diff --git a/.babelrc b/.babelrc new file mode 100644 index 000000000..fe5a185ee --- /dev/null +++ b/.babelrc @@ -0,0 +1,26 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "targets": { + "node": "current" + } + } + ], + "@babel/preset-typescript" + ], + "plugins": [ + "@babel/plugin-transform-runtime" + ], + "sourceType": "unambiguous", + "sourceMaps": "inline", + "retainLines": true, + "ignore": [ + "node_modules", + "build", + "browser_build", + "dist", + "configs" + ] +} \ No newline at end of file diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml new file mode 100644 index 000000000..55faa5b78 --- /dev/null +++ b/.github/workflows/label.yml @@ -0,0 +1,25 @@ +name: Comment to label + +on: + issues: + types: [labeled] + workflow_call: + +jobs: + issueLabeled: + runs-on: ubuntu-latest + steps: + - name: Bounty explanation + uses: peter-evans/create-or-update-comment@v2 + if: github.event.label.name == '💰bounty' + with: + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: > + There is a bounty on this issue. The amount is in the title. The reward will be awarded to the first person or group of people whose solution is accepted and merged. + + + In some cases, we may assign the issue to specific contributors. We expect contributors to provide a PR in a reasonable time frame or, in case of an extensive work, updates on their progress. We will unassign the issue if we feel the assignee is not responsive or has abandoned the task. + + + Read the [full conditions and details](https://github.com/woodser/monero-ts/blob/master/docs/bounties.md) of the bounty system. diff --git a/.gitignore b/.gitignore index 726d7af1d..96c156319 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ test_products /test_wallets/ /build /browser_build/ +/dist/src/test/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 267a67e0a..ba9fda2ac 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "external/monero-cpp"] path = external/monero-cpp - url = https://github.com/monero-ecosystem/monero-cpp.git + url = https://github.com/woodser/monero-cpp.git ignore = dirty \ No newline at end of file diff --git a/.project b/.project index 1bad55ed9..2f7eec801 100644 --- a/.project +++ b/.project @@ -1,6 +1,6 @@ - monero-javascript + monero-ts diff --git a/CMakeLists.txt b/CMakeLists.txt index 9442faf00..83df59280 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,16 +1,13 @@ -cmake_minimum_required(VERSION 3.4.1) +cmake_minimum_required(VERSION 3.5) -project(monero-javascript-wasm) +project(monero-ts-wasm) # build with exception whitelist from file file(STRINGS wasm_exception_whitelist.txt WASM_EXCEPTION_WHITELIST) string(REPLACE ";" "," WASM_EXCEPTION_WHITELIST "${WASM_EXCEPTION_WHITELIST}") -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Oz --bind -s DISABLE_EXCEPTION_CATCHING=2 -s EXCEPTION_CATCHING_WHITELIST='[${WASM_EXCEPTION_WHITELIST}]'") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Oz -s EXCEPTION_CATCHING_ALLOWED='[${WASM_EXCEPTION_WHITELIST}]' -D_REENTRANT") add_definitions(-DAUTO_INITIALIZE_EASYLOGGINGPP -DNO_AES) -set(BUILD_MONERO_CORE_WASM ON) -set(BUILD_MONERO_CORE_KEYS_WASM ON) - ############## # C++ bridge ############## @@ -33,36 +30,43 @@ include_directories("${MONERO_CPP}/external/libsodium/include/sodium") # monero-project ################## -set(MONERO_CORE "${MONERO_CPP}/external/monero-core") -set(MONERO_CORE_SRC "${MONERO_CORE}/src") +set(MONERO_PROJECT "${MONERO_CPP}/external/monero-project") +set(MONERO_PROJECT_SRC "${MONERO_PROJECT}/src") # headers include_directories("src/main/cpp") -include_directories("${MONERO_CORE_SRC}/") -include_directories("${MONERO_CORE_SRC}/checkpoints") -include_directories("${MONERO_CORE_SRC}/common") -#include_directories("${MONERO_CORE_SRC}/crypto") -#include_directories("${MONERO_CORE_SRC}/crypto/crypto_ops_builder/include/") # DISABLED? -#include_directories("${MONERO_CORE_SRC}/crypto/crypto_ops_builder/include/sodium") # DISABLED? -include_directories("${MONERO_CORE_SRC}/cryptonote_basic") -#include_directories("${MONERO_CORE_SRC}/multisig") -#include_directories("${MONERO_CORE_SRC}/cryptonote_core") -#include_directories("${MONERO_CORE_SRC}/cryptonote_protocol") -#include_directories("${MONERO_CORE_SRC}/wallet") -#include_directories("${MONERO_CORE_SRC}/rpc") -#include_directories("${MONERO_CORE_SRC}/mnemonics") -include_directories("${MONERO_CORE}/external/") -include_directories("${MONERO_CORE}/external/easylogging++") -include_directories("${MONERO_CORE}/external/rapidjson/include") -include_directories("${MONERO_CORE}/external/unbound/libunbound") -include_directories("${MONERO_CORE}/external/db_drivers/liblmdb") -include_directories("${MONERO_CORE}/contrib/epee/include") -include_directories("${MONERO_CORE}/contrib/epee/include/net") +include_directories("${MONERO_PROJECT_SRC}/") +include_directories("${MONERO_PROJECT_SRC}/checkpoints") +include_directories("${MONERO_PROJECT_SRC}/common") +#include_directories("${MONERO_PROJECT_SRC}/crypto") +#include_directories("${MONERO_PROJECT_SRC}/crypto/crypto_ops_builder/include/") # DISABLED? +#include_directories("${MONERO_PROJECT_SRC}/crypto/crypto_ops_builder/include/sodium") # DISABLED? +include_directories("${MONERO_PROJECT_SRC}/cryptonote_basic") +#include_directories("${MONERO_PROJECT_SRC}/multisig") +#include_directories("${MONERO_PROJECT_SRC}/cryptonote_core") +#include_directories("${MONERO_PROJECT_SRC}/cryptonote_protocol") +#include_directories("${MONERO_PROJECT_SRC}/wallet") +#include_directories("${MONERO_PROJECT_SRC}/rpc") +#include_directories("${MONERO_PROJECT_SRC}/mnemonics") +include_directories("${MONERO_PROJECT}/external/") +include_directories("${MONERO_PROJECT}/external/easylogging++") +include_directories("${MONERO_PROJECT}/external/rapidjson/include") +include_directories("${MONERO_PROJECT}/external/unbound/libunbound") +include_directories("${MONERO_PROJECT}/external/db_drivers/liblmdb") +include_directories("${MONERO_PROJECT}/contrib/epee/include") +include_directories("${MONERO_PROJECT}/contrib/epee/include/net") #include_directories("${CMAKE_CURRENT_BINARY_DIR}") -#include_directories("${MONERO_CORE_SRC}/wallet/api") +#include_directories("${MONERO_PROJECT_SRC}/wallet/api") -include_directories("${MONERO_CORE}/build/release/translations") +include_directories("${MONERO_PROJECT}/build/release/translations") +include_directories("${MONERO_PROJECT}/build/release/generated_include") + +############# +# Unbound +############# + +include_directories("~/unbound-1.22.0/libunbound") ############# # OpenSSL @@ -93,7 +97,7 @@ set_target_properties( set(BOOST ${CMAKE_SOURCE_DIR}/build/boost) include_directories("${BOOST}") -include_directories("${BOOST}/include") # must exist already - run bin/build-boost-emscripten.sh +include_directories("${BOOST}/include") # must exist already - run bin/build_boost_emscripten.sh add_library(boost_chrono STATIC IMPORTED) set_target_properties( @@ -142,9 +146,9 @@ set_target_properties( ################################ set( - MONERO_CORE_KEYS_SRC_FILES + MONERO_WALLET_KEYS_SRC_FILES - # monero-javascript WASM bridge + # monero-ts WASM bridge src/main/cpp/index.cpp src/main/cpp/monero_wasm_bridge.cpp @@ -156,85 +160,99 @@ set( ${MONERO_CPP}/external/libsodium/src/crypto_verify/verify.c # monero-project (modified for WASM) - ${MONERO_CORE_SRC}/cryptonote_basic/cryptonote_basic_impl.cpp - ${MONERO_CORE_SRC}/cryptonote_basic/account.cpp - ${MONERO_CORE_SRC}/cryptonote_basic/cryptonote_format_utils.cpp - ${MONERO_CORE_SRC}/crypto/crypto.cpp - ${MONERO_CORE_SRC}/crypto/hash.c - ${MONERO_CORE_SRC}/crypto/slow-hash.c - ${MONERO_CORE_SRC}/crypto/oaes_lib.c - ${MONERO_CORE_SRC}/crypto/crypto-ops.c - ${MONERO_CORE_SRC}/crypto/crypto-ops-data.c - ${MONERO_CORE_SRC}/crypto/keccak.c - ${MONERO_CORE_SRC}/crypto/chacha.c - ${MONERO_CORE_SRC}/crypto/random.c - ${MONERO_CORE_SRC}/crypto/aesb.c - ${MONERO_CORE_SRC}/crypto/tree-hash.c - ${MONERO_CORE_SRC}/crypto/hash-extra-blake.c - ${MONERO_CORE_SRC}/crypto/blake256.c - ${MONERO_CORE_SRC}/crypto/hash-extra-groestl.c - ${MONERO_CORE_SRC}/crypto/hash-extra-jh.c - ${MONERO_CORE_SRC}/crypto/hash-extra-skein.c - ${MONERO_CORE_SRC}/crypto/groestl.c - ${MONERO_CORE_SRC}/crypto/jh.c - ${MONERO_CORE_SRC}/crypto/skein.c - ${MONERO_CORE_SRC}/cryptonote_core/cryptonote_tx_utils.cpp - ${MONERO_CORE}/contrib/epee/src/hex.cpp - ${MONERO_CORE}/contrib/epee/src/string_tools.cpp - ${MONERO_CORE}/contrib/epee/src/memwipe.c - ${MONERO_CORE}/contrib/epee/src/mlocker.cpp - ${MONERO_CORE}/contrib/epee/src/wipeable_string.cpp - ${MONERO_CORE_SRC}/common/base58.cpp - ${MONERO_CORE_SRC}/device/device.cpp - ${MONERO_CORE_SRC}/device/device_default.cpp - ${MONERO_CORE_SRC}/multisig/multisig.cpp - ${MONERO_CORE_SRC}/ringct/rctOps.cpp - ${MONERO_CORE_SRC}/ringct/rctTypes.cpp - ${MONERO_CORE_SRC}/ringct/rctCryptoOps.c - ${MONERO_CORE_SRC}/ringct/rctSigs.cpp - ${MONERO_CORE_SRC}/ringct/bulletproofs.cc - ${MONERO_CORE_SRC}/ringct/multiexp.cc - ${MONERO_CORE_SRC}/mnemonics/electrum-words.cpp - ${MONERO_CORE}/external/easylogging++/easylogging++.cc + ${MONERO_PROJECT_SRC}/cryptonote_basic/cryptonote_basic_impl.cpp + ${MONERO_PROJECT_SRC}/cryptonote_basic/account.cpp + ${MONERO_PROJECT_SRC}/cryptonote_basic/cryptonote_format_utils.cpp + ${MONERO_PROJECT_SRC}/cryptonote_basic/cryptonote_format_utils_basic.cpp + ${MONERO_PROJECT_SRC}/crypto/crypto.cpp + ${MONERO_PROJECT_SRC}/crypto/hash.c + ${MONERO_PROJECT_SRC}/crypto/slow-hash.c + ${MONERO_PROJECT_SRC}/crypto/oaes_lib.c + ${MONERO_PROJECT_SRC}/crypto/crypto-ops.c + ${MONERO_PROJECT_SRC}/crypto/crypto-ops-data.c + ${MONERO_PROJECT_SRC}/crypto/keccak.c + ${MONERO_PROJECT_SRC}/crypto/chacha.c + ${MONERO_PROJECT_SRC}/crypto/random.c + ${MONERO_PROJECT_SRC}/crypto/aesb.c + ${MONERO_PROJECT_SRC}/crypto/tree-hash.c + ${MONERO_PROJECT_SRC}/crypto/hash-extra-blake.c + ${MONERO_PROJECT_SRC}/crypto/blake256.c + ${MONERO_PROJECT_SRC}/crypto/hash-extra-groestl.c + ${MONERO_PROJECT_SRC}/crypto/hash-extra-jh.c + ${MONERO_PROJECT_SRC}/crypto/hash-extra-skein.c + ${MONERO_PROJECT_SRC}/crypto/groestl.c + ${MONERO_PROJECT_SRC}/crypto/jh.c + ${MONERO_PROJECT_SRC}/crypto/skein.c + ${MONERO_PROJECT_SRC}/cryptonote_core/cryptonote_tx_utils.cpp + ${MONERO_PROJECT}/contrib/epee/src/byte_stream.cpp + ${MONERO_PROJECT}/contrib/epee/src/byte_slice.cpp + ${MONERO_PROJECT}/contrib/epee/src/hex.cpp + ${MONERO_PROJECT}/contrib/epee/src/string_tools.cpp + ${MONERO_PROJECT}/contrib/epee/src/memwipe.c + ${MONERO_PROJECT}/contrib/epee/src/mlocker.cpp + ${MONERO_PROJECT}/contrib/epee/src/mlog.cpp + ${MONERO_PROJECT}/contrib/epee/src/wipeable_string.cpp + ${MONERO_PROJECT}/contrib/epee/src/portable_storage.cpp + ${MONERO_PROJECT}/contrib/epee/src/net_parse_helpers.cpp + ${MONERO_PROJECT}/contrib/epee/src/parserse_base_utils.cpp + ${MONERO_PROJECT_SRC}/common/base58.cpp + ${MONERO_PROJECT_SRC}/device/device.cpp + ${MONERO_PROJECT_SRC}/device/device_default.cpp + ${MONERO_PROJECT_SRC}/hardforks/hardforks.cpp + ${MONERO_PROJECT_SRC}/multisig/multisig.cpp + ${MONERO_PROJECT_SRC}/multisig/multisig_account.cpp + ${MONERO_PROJECT_SRC}/multisig/multisig_account_kex_impl.cpp + ${MONERO_PROJECT_SRC}/multisig/multisig_clsag_context.cpp + ${MONERO_PROJECT_SRC}/multisig/multisig_kex_msg.cpp + ${MONERO_PROJECT_SRC}/multisig/multisig_tx_builder_ringct.cpp + ${MONERO_PROJECT_SRC}/ringct/rctOps.cpp + ${MONERO_PROJECT_SRC}/ringct/rctTypes.cpp + ${MONERO_PROJECT_SRC}/ringct/rctCryptoOps.c + ${MONERO_PROJECT_SRC}/ringct/rctSigs.cpp + ${MONERO_PROJECT_SRC}/ringct/bulletproofs.cc + ${MONERO_PROJECT_SRC}/ringct/bulletproofs_plus.cc + ${MONERO_PROJECT_SRC}/ringct/multiexp.cc + ${MONERO_PROJECT_SRC}/mnemonics/electrum-words.cpp + ${MONERO_PROJECT}/external/easylogging++/easylogging++.cc ) ################################ -# Core wallet source files +# Full wallet source files ################################ set( - MONERO_CORE_SRC_FILES + MONERO_WALLET_FULL_SRC_FILES - # monero-javascript WASM bridge + # monero-ts WASM bridge src/main/cpp/http_client_wasm.cpp # monero-cpp (modified for WASM) - ${MONERO_CPP_SRC}/wallet/monero_wallet_core.cpp + ${MONERO_CPP_SRC}/wallet/monero_wallet_full.cpp # monero-project (modified for WASM) - ${MONERO_CORE}/external/db_drivers/liblmdb/mdb.c - ${MONERO_CORE}/external/db_drivers/liblmdb/midl.c - ${MONERO_CORE}/contrib/epee/src/abstract_http_client.cpp - #${MONERO_CORE}/contrib/epee/src/http_auth.cpp - ${MONERO_CORE_SRC}/wallet/wallet2.cpp - ${MONERO_CORE_SRC}/wallet/message_store.cpp - ${MONERO_CORE_SRC}/wallet/message_transporter.cpp - ${MONERO_CORE_SRC}/wallet/node_rpc_proxy.cpp - ${MONERO_CORE_SRC}/wallet/wallet_rpc_payments.cpp - #${MONERO_CORE_SRC}/blockchain_db/lmdb/db_lmdb.cpp - ${MONERO_CORE_SRC}/cryptonote_core/cryptonote_tx_utils.cpp - ${MONERO_CORE_SRC}/checkpoints/checkpoints.cpp - ${MONERO_CORE_SRC}/common/perf_timer.cpp - ${MONERO_CORE_SRC}/common/threadpool.cpp - ${MONERO_CORE_SRC}/common/aligned.c - ${MONERO_CORE_SRC}/common/util.cpp - ${MONERO_CORE_SRC}/common/i18n.cpp - ${MONERO_CORE_SRC}/common/combinator.cpp - ${MONERO_CORE_SRC}/rpc/rpc_payment_signature.cpp - ${MONERO_CORE_SRC}/wallet/ringdb.cpp - ${MONERO_CORE_SRC}/cryptonote_basic/miner.cpp - ${MONERO_CORE_SRC}/cryptonote_basic/difficulty.cpp - ${MONERO_CORE_SRC}/cryptonote_core/tx_sanity_check.cpp + ${MONERO_PROJECT}/external/db_drivers/liblmdb/mdb.c + ${MONERO_PROJECT}/external/db_drivers/liblmdb/midl.c + ${MONERO_PROJECT}/contrib/epee/src/abstract_http_client.cpp + #${MONERO_PROJECT}/contrib/epee/src/http_auth.cpp + ${MONERO_PROJECT_SRC}/wallet/wallet2.cpp + ${MONERO_PROJECT_SRC}/wallet/message_store.cpp + ${MONERO_PROJECT_SRC}/wallet/message_transporter.cpp + ${MONERO_PROJECT_SRC}/wallet/node_rpc_proxy.cpp + ${MONERO_PROJECT_SRC}/wallet/wallet_rpc_payments.cpp + #${MONERO_PROJECT_SRC}/blockchain_db/lmdb/db_lmdb.cpp + ${MONERO_PROJECT_SRC}/cryptonote_core/cryptonote_tx_utils.cpp + ${MONERO_PROJECT_SRC}/checkpoints/checkpoints.cpp + ${MONERO_PROJECT_SRC}/common/perf_timer.cpp + ${MONERO_PROJECT_SRC}/common/threadpool.cpp + ${MONERO_PROJECT_SRC}/common/aligned.c + ${MONERO_PROJECT_SRC}/common/util.cpp + ${MONERO_PROJECT_SRC}/common/i18n.cpp + ${MONERO_PROJECT_SRC}/common/combinator.cpp + ${MONERO_PROJECT_SRC}/rpc/rpc_payment_signature.cpp + ${MONERO_PROJECT_SRC}/wallet/ringdb.cpp + ${MONERO_PROJECT_SRC}/cryptonote_basic/miner.cpp + ${MONERO_PROJECT_SRC}/cryptonote_basic/difficulty.cpp + ${MONERO_PROJECT_SRC}/cryptonote_core/tx_sanity_check.cpp ) #################### @@ -249,6 +267,9 @@ set( #-s 'ASYNCIFY_IMPORTS=[\"js_send_json_request\",\"js_send_binary_request\",\"emscripten_sleep\"]' \ #-s ALLOW_MEMORY_GROWTH=0 \ #-s INITIAL_MEMORY=1536MB \ +#-s MALLOC=emmalloc \ +#-s INITIAL_MEMORY=1024MB \ +#-s TOTAL_STACK=512MB \ set ( EMCC_LINKER_FLAGS_BASE @@ -256,21 +277,25 @@ EMCC_LINKER_FLAGS_BASE # unsure if the -I...boost..include is necessary here due to include above # TODO? does EXPORT_NAME need to be the same for both targets? (or should it be set per-target with …_WASM, …_ASMJS?) -"-Wall -Werror -std=c++11 -Oz \ ---bind -s MODULARIZE=1 \ --s 'EXPORT_NAME=\"monero_javascript\"' \ +"-Wall -Werror -Wno-js-compiler -Wl,--allow-undefined -std=c++14 -Oz -D_REENTRANT \ +--bind \ +-s MODULARIZE=1 \ +-s 'EXPORT_NAME=\"monero_ts\"' \ -s ERROR_ON_UNDEFINED_SYMBOLS=0 \ --s ASSERTIONS=2 \ +-s ASSERTIONS=0 \ -s EXIT_RUNTIME=0 \ -s PRECISE_F32=1 \ -s EXCEPTION_DEBUG=0 \ --s DEMANGLE_SUPPORT=0 \ -s NO_DYNAMIC_EXECUTION=1 \ -s NODEJS_CATCH_EXIT=0 \ -s RESERVED_FUNCTION_POINTERS=5 \ --s EXTRA_EXPORTED_RUNTIME_METHODS='[\"UTF8ToString\",\"stringToUTF8\",\"lengthBytesUTF8\",\"intArrayToString\",\"makeBigInt\",\"getTempRet0\",\"addFunction\"]' \ --s WASM=1 \ +-s EXPORTED_RUNTIME_METHODS='[\"UTF8ToString\",\"stringToUTF8\",\"lengthBytesUTF8\",\"intArrayToString\",\"getTempRet0\",\"addFunction\"]' \ +-s SINGLE_FILE=1 \ -s ALLOW_MEMORY_GROWTH=1 \ +-s WASM_BIGINT=1 \ +-s EXPORTED_FUNCTIONS='[_free, _malloc]' \ +-s STACK_SIZE=5MB \ +-s DEFAULT_PTHREAD_STACK_SIZE=2MB \ " # • Disabling exception catching does not introduce silent failures # • Probably don't need PRECISE_F32 but wouldn't want to not use it @@ -281,61 +306,38 @@ EMCC_LINKER_FLAGS_BASE ) set( -EMCC_LINKER_FLAGS_CORE_KEYS -"${EMCC_LINKER_FLAGS_BASE} \ -" -) - -set( -EMCC_LINKER_FLAGS_CORE +EMCC_LINKER_FLAGS_FULL "${EMCC_LINKER_FLAGS_BASE} \ -s ASYNCIFY=1 \ -s 'ASYNCIFY_IMPORTS=[\"js_send_json_request\",\"js_send_binary_request\",\"emscripten_sleep\"]' \ " ) -message(STATUS "EMCC_LINKER_FLAGS_CORE_KEYS ${EMCC_LINKER_FLAGS_CORE_KEYS}") -message(STATUS "EMCC_LINKER_FLAGS_CORE ${EMCC_LINKER_FLAGS_CORE}") +message(STATUS "EMCC_LINKER_FLAGS_FULL ${EMCC_LINKER_FLAGS_FULL}") #################### # Build targets #################### -if (BUILD_MONERO_CORE_KEYS_WASM) - add_executable(monero_core_keys ${MONERO_CORE_KEYS_SRC_FILES}) - set_target_properties(monero_core_keys PROPERTIES LINK_FLAGS "${EMCC_LINKER_FLAGS_CORE_KEYS}") - target_link_libraries( - monero_core_keys - # - boost_chrono - boost_system - boost_thread - # - ${log-lib} - ) -endif() - -if (BUILD_MONERO_CORE_WASM) - add_executable(monero_core ${MONERO_CORE_SRC_FILES} ${MONERO_CORE_KEYS_SRC_FILES}) - set_target_properties(monero_core PROPERTIES LINK_FLAGS "${EMCC_LINKER_FLAGS_CORE}") - target_compile_definitions(monero_core PRIVATE BUILD_CORE_WALLET=1) - target_link_libraries( - monero_core - # - #openssl_ssl - #openssl_crypto - # - boost_chrono - boost_system - boost_thread - boost_serialization - #boost_filesystem - boost_regex - #boost_atomic - # - ${log-lib} - ) -endif() +add_executable(monero ${MONERO_WALLET_FULL_SRC_FILES} ${MONERO_WALLET_KEYS_SRC_FILES}) +set_target_properties(monero PROPERTIES LINK_FLAGS "${EMCC_LINKER_FLAGS_FULL}") +target_compile_definitions(monero PRIVATE BUILD_WALLET_FULL=1) +target_link_libraries( + monero + # + #openssl_ssl + #openssl_crypto + # + boost_chrono + boost_system + boost_thread + boost_serialization + boost_filesystem + boost_regex + #boost_atomic + # + ${log-lib} +) # build to bitcode instead of wasm -#SET(CMAKE_EXECUTABLE_SUFFIX ".bc") \ No newline at end of file +#SET(CMAKE_EXECUTABLE_SUFFIX ".bc") \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt index 5bac955b5..09ce99c44 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018-2020 woodser +Copyright (c) woodser Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index ba39d3231..d95d91c99 100644 --- a/README.md +++ b/README.md @@ -1,174 +1,188 @@ -# Monero JavaScript Library +# Monero TypeScript Library -A Node.js library for creating Monero applications using RPC or WebAssembly bindings to [monero v0.16.0.3 'Nitrogen Nebula'](https://github.com/monero-project/monero/tree/v0.16.0.3). +A TypeScript library for creating Monero applications using RPC and WebAssembly bindings to [monero v0.18.4.3 'Fluorine Fermi'](https://github.com/monero-project/monero/tree/v0.18.4.3). +* Supports client-side wallets in Node.js and the browser using WebAssembly. * Supports wallet and daemon RPC clients. -* Supports client-side wallets in Node.js or the browser using WebAssembly. * Supports multisig, view-only, and offline wallets. -* Wallet types are interchangeable by conforming to a [common interface](https://moneroecosystem.org/monero-javascript/MoneroWallet.html). -* Uses a clearly defined [data model and API specification](https://moneroecosystem.org/monero-java/monero-spec.pdf) intended to be intuitive and robust. +* Wallet types are interchangeable by conforming to a [common interface](https://woodser.github.io/monero-ts/typedocs/classes/MoneroWallet.html). +* Uses a clearly defined [data model and API specification](https://woodser.github.io/monero-java/monero-spec.pdf) intended to be intuitive and robust. * [Query wallet transactions, transfers, and outputs](docs/developer_guide/query_data_model.md) by their properties. * Fetch and process binary data from the daemon (e.g. raw blocks). * Receive notifications when blocks are added to the chain or when wallets sync, send, or receive. -* Over 250 passing Mocha tests. - -## Table of contents - -* [Architecture](#architecture) -* [Sample code](#sample-code) -* [Using monero-javascript in your project](#using-monero-javascript-in-your-project) -* [Building WebAssembly binaries from source](#building-webassembly-binaries-from-source) -* [Developer guide](#developer-guide) -* [Running tests](#running-tests) -* [See also](#see-also) -* [License](#license) -* [Donations](#donations) +* Over 300 passing Mocha tests. ## Architecture

-
- Build Node.js or browser applications using RPC or WebAssembly bindings to monero-project/monero. Wallet implementations are interchangeable by conforming to a common interface, MoneroWallet.js. +
+ Build browser or Node.js applications using RPC or WebAssembly bindings to monero-project/monero. Wallet implementations are interchangeable by conforming to a common interface, MoneroWallet.ts.

## Sample code -This code introduces the API used in monero-javascript. See the [JSDocs](https://moneroecosystem.org/monero-javascript/MoneroWallet.html), [API specification](https://moneroecosystem.org/monero-java/monero-spec.pdf), or [Mocha tests](src/test) for more detail. - -```js -// import library -const monerojs = require("monero-javascript"); +```typescript +// import monero-ts (or import types individually) +import moneroTs from "monero-ts"; -// connect to a daemon -let daemon = monerojs.connectToDaemonRpc("http://localhost:38081", "superuser", "abctesting123"); -let height = await daemon.getHeight(); // 1523651 -let feeEstimate = await daemon.getFeeEstimate(); // 1014313512 -let txsInPool = await daemon.getTxPool(); // get transactions in the pool - -// open wallet on monero-wallet-rpc -let walletRpc = monerojs.connectToWalletRpc("http://localhost:38083", "rpc_user", "abc123"); -await walletRpc.openWallet("sample_wallet_rpc", "supersecretpassword123"); -let primaryAddress = await walletRpc.getPrimaryAddress(); // 555zgduFhmKd2o8rPUz... -let balance = await walletRpc.getBalance(); // 533648366742 -let txs = await walletRpc.getTxs(); // get transactions containing transfers to/from the wallet +// connect to daemon +let daemon = await moneroTs.connectToDaemonRpc("http://localhost:28081"); +let height = await daemon.getHeight(); // 1523651 +let txsInPool = await daemon.getTxPool(); // get transactions in the pool // create wallet from mnemonic phrase using WebAssembly bindings to monero-project -let walletWasm = await monerojs.createWalletWasm({ - path: "sample_wallet_wasm", +let walletFull = await moneroTs.createWalletFull({ + path: "sample_wallet_full", password: "supersecretpassword123", - networkType: "stagenet", - serverUri: "http://localhost:38081", - serverUsername: "superuser", - serverPassword: "abctesting123", - mnemonic: "hefty value scenic...", + networkType: moneroTs.MoneroNetworkType.TESTNET, + seed: "hefty value scenic...", restoreHeight: 573936, + server: { // provide url or MoneroRpcConnection + uri: "http://localhost:28081", + username: "superuser", + password: "abctesting123" + } }); // synchronize with progress notifications -await walletWasm.sync(new class extends monerojs.MoneroWalletListener { - onSyncProgress(height, startHeight, endHeight, percentDone, message) { +await walletFull.sync(new class extends moneroTs.MoneroWalletListener { + async onSyncProgress(height: number, startHeight: number, endHeight: number, percentDone: number, message: string) { // feed a progress bar? } }); -// synchronize in the background -await walletWasm.startSyncing(); +// synchronize in the background every 5 seconds +await walletFull.startSyncing(5000); -// listen for incoming transfers +// receive notifications when funds are received, confirmed, and unlocked let fundsReceived = false; -await walletWasm.addListener(new class extends monerojs.MoneroWalletListener { - onOutputReceived(output) { +await walletFull.addListener(new class extends moneroTs.MoneroWalletListener { + async onOutputReceived(output: moneroTs.MoneroOutputWallet) { let amount = output.getAmount(); let txHash = output.getTx().getHash(); + let isConfirmed = output.getTx().getIsConfirmed(); + let isLocked = output.getTx().getIsLocked(); fundsReceived = true; } }); +// connect to wallet RPC and open wallet +let walletRpc = await moneroTs.connectToWalletRpc("http://localhost:28084", "rpc_user", "abc123"); +await walletRpc.openWallet("sample_wallet_rpc", "supersecretpassword123"); +let primaryAddress = await walletRpc.getPrimaryAddress(); // 555zgduFhmKd2o8rPUz... +let balance = await walletRpc.getBalance(); // 533648366742 +let txs = await walletRpc.getTxs(); // get transactions containing transfers to/from the wallet + // send funds from RPC wallet to WebAssembly wallet let createdTx = await walletRpc.createTx({ accountIndex: 0, - address: await walletWasm.getAddress(1, 0), - amount: "250000000000", // send 0.25 XMR (denominated in atomic units) + address: await walletFull.getAddress(1, 0), + amount: 250000000000n, // send 0.25 XMR (denominated in atomic units) relay: false // create transaction and relay to the network if true }); let fee = createdTx.getFee(); // "Are you sure you want to send... ?" await walletRpc.relayTx(createdTx); // relay the transaction -// recipient receives unconfirmed funds within 10 seconds -await new Promise(function(resolve) { setTimeout(resolve, 10000); }); +// recipient receives unconfirmed funds within 5 seconds +await new Promise(function(resolve) { setTimeout(resolve, 5000); }); assert(fundsReceived); // save and close WebAssembly wallet -await walletWasm.close(true); +await walletFull.close(true); + +// terminate any running resources (e.g. workers) +await moneroTs.shutdown(); ``` -## Using monero-javascript in your project +## Documentation + +* [TypeDocs](https://woodser.github.io/monero-ts/typedocs/) +* [API and model overview with visual diagrams](https://woodser.github.io/monero-java/monero-spec.pdf) +* [Creating wallets](docs/developer_guide/creating_wallets.md) +* [The data model: blocks, transactions, transfers, and outputs](docs/developer_guide/data_model.md) +* [Getting transactions, transfers, and outputs](docs/developer_guide/query_data_model.md) +* [Sending funds](docs/developer_guide/sending_funds.md) +* [Multisig wallets](docs/developer_guide/multisig_wallets.md) +* [View-only and offline wallets](docs/developer_guide/view_only_offline.md) +* [Connection manager](docs/developer_guide/connection_manager.md) +* [HTTPS and self-signed certificates](./docs/developer_guide/https_and_self_signed_certificates.md) +* [Mocha tests](src/test) +* [Installing prerequisites](docs/developer_guide/installing_prerequisites.md) +* [Getting started part 1: creating a Node.js application](docs/developer_guide/getting_started_p1.md) +* [Getting started part 2: creating a web application](docs/developer_guide/getting_started_p2.md) + +## Sample projects + +* [Sample Node.js app](https://github.com/woodser/xmr-sample-node) +* [Sample React app](https://github.com/woodser/xmr-sample-react) +* [Sample Next.js app](https://github.com/woodser/xmr-sample-next) +* [Sample Vite app](https://github.com/woodser/xmr-sample-vite) +* [Sample Webpack app](https://github.com/woodser/xmr-sample-webpack) +* [Sample Deno app](https://github.com/woodser/xmr-sample-deno) + +## Related projects + +* [monero-cpp](https://github.com/woodser/monero-cpp) - C++ library counterpart +* [monero-java](https://github.com/woodser/monero-java) - Java library counterpart +* [haveno-ts](https://github.com/haveno-dex/haveno-ts) - used for testing Haveno and its TypeScript library + +## Using monero-ts in your project 1. `cd your_project` or `mkdir your_project && cd your_project && npm init` -2. `npm install monero-javascript` -3. Add `require("monero-javascript")` to your application code. +2. `npm install monero-ts` +3. Add `import moneroTs from "monero-ts"` in your application code (or import types individually). + +#### Running in Node.js -#### If using RPC servers: +Node 20 LTS is recommended. Alternatively, Node 16 and 18 LTS work using the `--experimental-wasm-threads` flag. + +#### Building a browser application +1. Bundle your application code for a browser. See [xmr-sample-webpack](https://github.com/woodser/xmr-sample-webpack) for an example project using Webpack. +2. Copy assets from ./dist to your web app's build directory. + +#### Using RPC servers: 1. Download and install [Monero CLI](https://web.getmonero.org/downloads/). -2. Start monero-daemon-rpc, e.g.: `./monerod --stagenet` (or use a remote daemon). -3. Start monero-wallet-rpc, e.g.: `./monero-wallet-rpc --daemon-address http://localhost:38081 --stagenet --rpc-bind-port 38083 --rpc-login rpc_user:abc123 --wallet-dir ./` +2. Start monerod, e.g.: `./monerod --stagenet` (or use a remote daemon). +3. Start monero-wallet-rpc, e.g.: `./monero-wallet-rpc --daemon-address http://localhost:38081 --stagenet --rpc-bind-port 38084 --rpc-login rpc_user:abc123 --wallet-dir ./` ## Building WebAssembly binaries from source -This project uses WebAssembly to package and execute Monero's source code for use in a browser or other WebAssembly-supported environments. +This project uses WebAssembly to package and execute Monero's source code for a browser or other WebAssembly-supported environment. Compiled WebAssembly binaries are committed to ./dist for convenience, but these files can be built independently from source code: -1. Install and activate emscripten +1. Install and activate emscripten. 1. Clone emscripten repository: `git clone https://github.com/emscripten-core/emsdk.git` 2. `cd emsdk` - 3. `git pull && ./emsdk install latest-upstream && ./emsdk activate latest-upstream && source ./emsdk_env.sh` + 3. `git pull && ./emsdk install 3.1.66 && ./emsdk activate 3.1.66 && source ./emsdk_env.sh` 4. `export EMSCRIPTEN=path/to/emsdk/upstream/emscripten` (change for your system) -2. Clone monero-javascript repository: `git clone https://github.com/monero-ecosystem/monero-javascript.git` -3. `cd monero-javascript` -4. `./bin/build_all.sh` - -## Developer guide - -* [Installing prerequisites](docs/developer_guide/installing_prerequisites.md) -* [Getting started part 1: creating a Node.js application](docs/developer_guide/getting_started_p1.md) -* [Getting started part 2: creating a web application](docs/developer_guide/getting_started_p2.md) -* [Creating wallets](docs/developer_guide/creating_wallets.md) -* [The data model: blocks, transactions, transfers, and outputs](docs/developer_guide/data_model.md) -* [Getting transactions, transfers, and outputs](docs/developer_guide/query_data_model.md) -* [Sending funds](docs/developer_guide/sending_funds.md) -* [Multisig wallets](docs/developer_guide/multisig_wallets.md) -* [View-only and offline wallets](docs/developer_guide/view_only_offline.md) -* [HTTPS and self-signed certificates](./docs/developer_guide/https_and_self_signed_certificates.md) +2. Clone monero-ts repository: `git clone --recursive https://github.com/woodser/monero-ts.git` +3. `cd monero-ts` +4. `./bin/update_submodules.sh` +5. Modify ./external/monero-cpp/external/monero-project/src/crypto/wallet/CMakeLists.txt from `set(MONERO_WALLET_CRYPTO_LIBRARY "auto" ...` to `set(MONERO_WALLET_CRYPTO_LIBRARY "cn" ...`. +6. Build the monero-cpp submodule (located at ./external/monero-cpp) by following [instructions](https://github.com/woodser/monero-cpp#using-monero-cpp-in-your-project) for your system. This will ensure all dependencies are installed. Be sure to install unbound 1.19.0 to your home directory (`~/unbound-1.19.0`). +7. `./bin/build_all.sh` (install [monero-project dependencies](https://github.com/monero-project/monero#dependencies) as needed for your system) ## Running tests -1. Clone the project repository: `git clone https://github.com/monero-ecosystem/monero-javascript.git` -2. `cd monero-javascript` +1. Clone the project repository: `git clone https://github.com/woodser/monero-ts.git` +2. `cd monero-ts` 3. Start RPC servers: 1. Download and install [Monero CLI](https://web.getmonero.org/downloads/). - 2. Start monero-daemon-rpc, e.g.: `./monerod --stagenet` (or use a remote daemon). - 3. Start monero-wallet-rpc, e.g.: `./monero-wallet-rpc --daemon-address http://localhost:38081 --stagenet --rpc-bind-port 38083 --rpc-login rpc_user:abc123 --wallet-dir ./` -4. Configure the appropriate RPC endpoints and authentication by modifying `WALLET_RPC_CONFIG` and `DAEMON_RPC_CONFIG` in [TestUtils.js](src/test/utils/TestUtils.js). + 2. Start monerod, e.g.: `./monerod --testnet` (or use a remote daemon). + 3. Start monero-wallet-rpc, e.g.: `./monero-wallet-rpc --daemon-address http://localhost:38081 --testnet --rpc-bind-port 28084 --rpc-login rpc_user:abc123 --wallet-dir ./` +4. Configure the appropriate RPC endpoints, authentication, and other settings in [TestUtils.ts](src/test/utils/TestUtils.ts) (e.g. `WALLET_RPC_CONFIG` and `DAEMON_RPC_CONFIG`). #### Running tests in Node.js * Run all tests: `npm test` -* Run tests by their description: `node_modules/mocha/bin/mocha src/test/TestAll --grep "Can get transactions" --timeout 2000000` - -#### Running tests in the browser - -1. `./bin/build_browser_tests.sh` -2. Access http://localhost:9100/tests.html in a browser +* Run tests by their description, e.g.: `npm run test -- --grep "Can get transactions"` -## See also +#### Running tests in a browser -* [API specification](http://moneroecosystem.org/monero-java/monero-spec.pdf) -* [monero-java](https://github.com/monero-ecosystem/monero-java) -* [monero-cpp](https://github.com/monero-ecosystem/monero-cpp) -* [xmr-sample-app](https://github.com/woodser/xmr-sample-app/) - sample web app template (under development) -* [monerostresstester.com](https://github.com/woodser/monerostresstester.com) - repeatedly sends txs to self to stress test the network (under development) -* [monerowebwallet.com](https://github.com/woodser/monerowebwallet.com) - open-source, client-side web wallet (under development) +1. Start monero-wallet-rpc servers used by tests: `./bin/start_wallet_rpc_test_servers.sh` +2. In another terminal, build browser tests: `./bin/build_browser_tests.sh` +3. Access http://localhost:8080/tests.html in a browser to run all tests ## License @@ -176,7 +190,7 @@ This project is licensed under MIT. ## Donations -If this library brings you value, please consider donating. +Please consider donating to support the development of this project. 🙏


diff --git a/bin/build_all.sh b/bin/build_all.sh index 191d04bbc..db61813fa 100755 --- a/bin/build_all.sh +++ b/bin/build_all.sh @@ -10,28 +10,25 @@ exit 1 } } - -# update submodules -./bin/update_submodules.sh || exit 1 -# build monero-core translations directory -cd ./external/monero-cpp/external/monero-core || exit 1 +# build monero-project translations directory +cd ./external/monero-cpp/external/monero-project || exit 1 +git submodule update --init --force || exit 1 HOST_NCORES=$(nproc 2>/dev/null || shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1) make release-static -j$HOST_NCORES # don't exit because this will build translations directory even if build fails cd ../../../../ || exit 1 +# install node modules +npm install || exit 1 + # build boost ./bin/build_boost_emscripten.sh || exit 1 # build openssl ./bin/build_openssl_emscripten.sh || exit 1 -# build webassembly for distribution -./bin/build_wasm_emscripten.sh || exit 1 - -# build web worker -npm install || exit 1 -./bin/build_web_worker.sh || exit 1 +# build dist (wasm, commonjs , web worker) +./bin/build_dist.sh || exit 1 # build browser tests ./bin/build_browser_tests.sh || exit 1 \ No newline at end of file diff --git a/bin/build_boost_emscripten.sh b/bin/build_boost_emscripten.sh index 4c182e097..1005bbd53 100755 --- a/bin/build_boost_emscripten.sh +++ b/bin/build_boost_emscripten.sh @@ -1,17 +1,14 @@ #!/bin/sh -#source "$(realpath $(dirname $0))/emsdk_inc.sh" -source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/emsdk_inc.sh" -[ -f $(dirname $0)/colors.sh ] && source $(dirname $0)/colors.sh - -PLATFORM="emscripten" +. $(dirname $0)/download_deps.sh +[ -f $(dirname $0)/colors.sh ] && . $(dirname $0)/colors.sh SRC_DIR="external/monero-cpp/external/boost-sdk" INSTALL_DIR="build/boost" SRC_PATH="$(pwd)/$SRC_DIR" INSTALL_PATH="$(pwd)/$INSTALL_DIR" -JAM_CONFIG_PATH="$(pwd)/configs/$PLATFORM.jam" +JAM_CONFIG_PATH="$(pwd)/configs/emscripten.jam" [ ! -d ${SRC_PATH} -o $# -ge 1 ] \ && { @@ -66,7 +63,7 @@ fi cd $EMSCRIPTEN -python ./embuilder.py build zlib \ +python3 ./embuilder.py build zlib \ || { echo "EMSDK build zlib failed.." exit 1 @@ -88,7 +85,7 @@ export NO_BZIP2=1 #bc it's supplied by emscripten but b2 will fail to find it ./bootstrap.sh \ - --with-libraries=system,thread,chrono,serialization,regex \ + --with-libraries=system,thread,chrono,serialization,regex,filesystem \ 2>&1 if [ $? != 0 ]; then @@ -106,14 +103,13 @@ mkdir "$INSTALL_PATH" HOST_NCORES=$(nproc 2>/dev/null|| shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1) - -# threading=single \ -./b2 -q -a -j$HOST_NCORES \ +./b2 -q -a -j $HOST_NCORES \ toolset=clang-emscripten \ - threading=single \ + threading=single \ link=static \ optimization=space \ variant=release \ + cxxflags=-no-pthread \ stage \ --stagedir="$INSTALL_PATH" \ 2>&1 diff --git a/bin/build_browser_tests.sh b/bin/build_browser_tests.sh index b6e5ec80e..1b2c1b87d 100755 --- a/bin/build_browser_tests.sh +++ b/bin/build_browser_tests.sh @@ -12,7 +12,8 @@ cp -R dist/* browser_build/ || exit 1 cp src/test/browser/tests.html browser_build/tests.html || exit 1 cp src/test/browser/favicon.ico browser_build/favicon.ico || exit 1 cp node_modules/mocha/mocha.js browser_build/mocha.js || exit 1 +cp node_modules/mocha/mocha.js.map browser_build/mocha.js.map || exit 1 cp node_modules/mocha/mocha.css browser_build/mocha.css || exit 1 # start server -./bin/start_dev_server.sh \ No newline at end of file +./bin/start_browser_test_server.sh \ No newline at end of file diff --git a/bin/build_dist.sh b/bin/build_dist.sh index 963ecc9db..b073bfed8 100755 --- a/bin/build_dist.sh +++ b/bin/build_dist.sh @@ -1,4 +1,5 @@ #!/bin/sh ./bin/build_wasm_emscripten.sh || exit 1 -./bin/build_web_worker.sh || exit 1 \ No newline at end of file +./bin/build_web_worker.sh || exit 1 +npm run build_commonjs || exit 1 \ No newline at end of file diff --git a/bin/build_openssl_emscripten.sh b/bin/build_openssl_emscripten.sh index 9c045aa18..c3cb0235a 100755 --- a/bin/build_openssl_emscripten.sh +++ b/bin/build_openssl_emscripten.sh @@ -1,8 +1,7 @@ #!/bin/sh -#source "$(realpath $(dirname $0))/emsdk_inc.sh" -source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )/emsdk_inc.sh" -[ -f $(dirname $0)/colors.sh ] && source $(dirname $0)/colors.sh +. $(dirname $0)/download_deps.sh +[ -f $(dirname $0)/colors.sh ] && . $(dirname $0)/colors.sh PLATFORM="emscripten" @@ -66,7 +65,7 @@ fi cd "$SRC_PATH" -emcmake perl ./Configure \ +perl ./Configure \ linux-generic32 \ -no-asm no-ssl2 no-ssl3 no-comp no-engine no-deprecated no-tests no-dso no-shared no-threads disable-shared \ --prefix="$INSTALL_PATH" \ diff --git a/bin/build_wasm_emscripten.sh b/bin/build_wasm_emscripten.sh index 1595e875b..e2dc1b848 100755 --- a/bin/build_wasm_emscripten.sh +++ b/bin/build_wasm_emscripten.sh @@ -17,26 +17,14 @@ HOST_NCORES=$(nproc 2>/dev/null || shell nproc 2>/dev/null || sysctl -n hw.ncpu cd build || exit 1 emcmake cmake .. || exit 1 emmake cmake --build . -j$HOST_NCORES || exit 1 - -# move available wasm files to ./dist cd .. -mkdir -p ./dist || exit 1 -[ -f ./build/monero_core_keys.js ] \ - && { - mv ./build/monero_core_keys.js ./dist/ - } -[ -f ./build/monero_core_keys.wasm ] \ - && { - mv ./build/monero_core_keys.wasm ./dist/ - } +# postprocess wasm files +./bin/postprocess_wasm.sh || exit 1 -[ -f ./build/monero_core.js ] \ +# move wasm files to ./dist +mkdir -p ./dist || exit 1 +[ -f ./build/monero.js ] \ && { - mv ./build/monero_core.js ./dist/ + mv ./build/monero.js ./dist/ } - -[ -f ./build/monero_core.wasm ] \ - && { - mv ./build/monero_core.wasm ./dist/ - } \ No newline at end of file diff --git a/bin/emsdk_inc.sh b/bin/download_deps.sh similarity index 91% rename from bin/emsdk_inc.sh rename to bin/download_deps.sh index 0bb778f24..80aab8a6d 100755 --- a/bin/emsdk_inc.sh +++ b/bin/download_deps.sh @@ -47,7 +47,7 @@ get_boost_github() { [ -d ${SDK_PATH} ] || { echo "get_boost_github: Missing directory: ${SDK_PATH}"; return 1; } echo "Downloading boost from GitHub..." - git clone --recursive https://github.com/boostorg/boost.git --branch "boost-1.72.0" "${SDK_PATH}/boost-sdk" \ + git clone --recursive https://github.com/boostorg/boost.git --branch "boost-1.83.0" "${SDK_PATH}/boost-sdk" \ || { echo "Download failed" return 1 @@ -117,7 +117,7 @@ download_source() { # url, destination [ -f "${SDK_PATH}/$(basename ${DL_URL})" ] \ || { - echo "Both wget and curl failed. Don't know how to proseed." + echo "Both wget and curl failed. Don't know how to proceed." return 1 } } @@ -147,9 +147,8 @@ get_boost_source() { [ -d ${SDK_PATH} ] || { echo "get_boost_source: Missing directory: ${SDK_PATH}"; return 1; } # Github source is missing stuff - #local DL_URL="https://github.com/boostorg/boost/archive/boost-1.72.0.tar.gz" - local DL_URL="https://dl.bintray.com/boostorg/release/1.72.0/source" - local DL_FILE="boost_1_72_0.tar.gz" + local DL_URL="https://archives.boost.io/release/1.83.0/source/" + local DL_FILE="boost_1_83_0.tar.gz" check_archive "${SDK_PATH}/${DL_FILE}" \ && { @@ -179,7 +178,7 @@ get_openssl_source() { [ -d ${SDK_PATH} ] || { echo "get_openssl_source: Missing directory: ${SDK_PATH}"; return 1; } local DL_URL="https://github.com/openssl/openssl/archive" - local DL_FILE="OpenSSL_1_1_1d.tar.gz" + local DL_FILE="OpenSSL_1_1_1q.tar.gz" check_archive "${SDK_PATH}/${DL_FILE}" \ && { @@ -191,7 +190,7 @@ get_openssl_source() { } mkdir ${SDK_PATH}/openssl-sdk - tar -C ${SDK_PATH}/openssl-sdk --strip-components=1 -xvf ${SDK_PATH}/OpenSSL_1_1_1d.tar.gz || return 1 + tar -C ${SDK_PATH}/openssl-sdk --strip-components=1 -xvf ${SDK_PATH}/OpenSSL_1_1_1q.tar.gz || return 1 return 0 } diff --git a/bin/postprocess_wasm.mjs b/bin/postprocess_wasm.mjs new file mode 100644 index 000000000..481a49c9f --- /dev/null +++ b/bin/postprocess_wasm.mjs @@ -0,0 +1,52 @@ +import fs from "fs"; +import { Buffer } from "buffer"; + +const fileNames = ["./build/monero.js"]; + +const postprocess = async (fileName) => { + // read input file + const source = await fs.promises.readFile(fileName, "utf8"); + + // do not recompress again + if (source.includes("DecompressionStream")) { + console.log(`Skipping already compressed file ${fileName}`); + return; + } + + // find wasmBinaryFile base64 string + const match = source.match(/f=\"data:application\/octet-stream;base64,(.+?(?=\"))/gm); + if (!match?.length) { + console.log(`Skipping ${fileName}. wasmBinaryFile not base64 encoded`); + return; + } + const b64 = match[0].split('f="data:application/octet-stream;base64,')[1]; + const buf = Buffer.from(b64, 'base64'); + + // compress wasmBinaryFile + const compression = new CompressionStream("gzip"); + const compressedStream = new ReadableStream({ + start(controller) { + controller.enqueue(new Uint8Array(buf)); + controller.close(); + }, + }).pipeThrough(compression); + const compressedData = await new Response(compressedStream).arrayBuffer(); + + // convert compressed wasmBinaryFile to base64 + const cb64 = Buffer.from(compressedData).toString("base64"); + + // replace wasmBinaryFile with compressed wasmBinaryFile and add extra code to decompress it + const replaced = source + .replace(b64, cb64) + .replace( + "return intArrayFromBase64(filename.slice(dataURIPrefix.length))", + 'const data=filename.slice(dataURIPrefix.length);if(data.startsWith("AGFzbQ"))return intArrayFromBase64(data);else{const bin=intArrayFromBase64(data);const ds = new DecompressionStream("gzip");const decompressedStream = new ReadableStream({start(controller){controller.enqueue(bin);controller.close();}}).pipeThrough(ds);return (new Response(decompressedStream)).arrayBuffer();}' + ); + + // write output file + await fs.promises.writeFile(fileName, replaced); +} + +for (const fileName of fileNames) { + await postprocess(fileName); +} \ No newline at end of file diff --git a/bin/postprocess_wasm.sh b/bin/postprocess_wasm.sh new file mode 100755 index 000000000..2fa63ae8b --- /dev/null +++ b/bin/postprocess_wasm.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +set -ex +node ./bin/postprocess_wasm.mjs \ No newline at end of file diff --git a/bin/run_server.py b/bin/run_server.py index 836870f2a..15c1430b2 100755 --- a/bin/run_server.py +++ b/bin/run_server.py @@ -2,7 +2,7 @@ import http.server #import ssl -port=9100 +port=8080 print("Running on port %d" % port) http.server.SimpleHTTPRequestHandler.extensions_map['.wasm'] = 'application/wasm' diff --git a/bin/start_dev_server.sh b/bin/start_browser_test_server.sh similarity index 100% rename from bin/start_dev_server.sh rename to bin/start_browser_test_server.sh diff --git a/bin/start_wallet_rpc_test_servers.sh b/bin/start_wallet_rpc_test_servers.sh new file mode 100755 index 000000000..868b66d5d --- /dev/null +++ b/bin/start_wallet_rpc_test_servers.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +# build commonjs +npm run build_commonjs || exit 1 + +# run monero-wallet-rpc servers until terminated +node ./dist/src/test/utils/RunWalletRpcTestServers.js \ No newline at end of file diff --git a/bin/update_submodules.sh b/bin/update_submodules.sh index f8edd72d8..683461f7a 100755 --- a/bin/update_submodules.sh +++ b/bin/update_submodules.sh @@ -1,15 +1,4 @@ #!/usr/bin/env bash # initialize submodules recursively -git submodule update --init --recursive - -# update monero-cpp -cd ./external/monero-cpp -git checkout tags/v0.3.5 -git pull --ff-only origin tags/v0.3.5 - -# update monero-core -cd ./external/monero-core -git checkout tags/v0.16.0.3 -git pull --ff-only origin tags/v0.16.0.3 -cd ../../../../ \ No newline at end of file +git submodule update --init --recursive \ No newline at end of file diff --git a/configs/emscripten.jam b/configs/emscripten.jam index b43e7a2c4..c11437af9 100644 --- a/configs/emscripten.jam +++ b/configs/emscripten.jam @@ -10,7 +10,7 @@ local EMSCRIPTEN = [ os.environ EMSCRIPTEN ] ; using clang : emscripten : - emcc -v -s USE_ZLIB=1 + emcc -v -s USE_ZLIB=1 -s USE_PTHREADS=0 -D_REENTRANT : $(EMSCRIPTEN) $(EMSCRIPTEN)/emar diff --git a/configs/jsdoc_config.js b/configs/jsdoc_config.js deleted file mode 100644 index 4dab0d782..000000000 --- a/configs/jsdoc_config.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -module.exports = { - "plugins": ['./configs/jsdoc_plugins'], - "recurseDepth": 100, - "source": { - "include": ["./index.js", "./src/main/js/"], - "includePattern": ".+\\.js(doc|x)?$", - "excludePattern": "(^|\\/|\\\\)_" - }, - "sourceType": "module", - "tags": { - "allowUnknownTags": true, - "dictionaries": ["jsdoc","closure"] - }, - "templates": { - "cleverLinks": false, - "monospaceLinks": false - } -}; \ No newline at end of file diff --git a/configs/jsdoc_plugins.js b/configs/jsdoc_plugins.js deleted file mode 100644 index 71eab344c..000000000 --- a/configs/jsdoc_plugins.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Plugin to generate jsdoc for undocumented methods. - */ -'use strict'; - -module.exports.handlers = { - newDoclet : function(e) { - if (e.doclet.name.startsWith("_")) e.doclet.undocumented = true; // hide private methods starting with "_" - else if (e.doclet.undocumented && e.doclet.kind === "function" && !e.doclet.comment && (e.doclet.scope === "instance" || e.doclet.scope === "static")) { - e.doclet.undocumented = false; // preserve doclet - } - }, - processingComplete: function(e) { - - // overwrite subclass comments and descriptions with superclass until no further changes - let changes; - do { - changes = false; - for (let doclet of e.doclets) { - if (!doclet.comment) { - let parentDoc = ""; - if (doclet.implements) parentDoc = doclet.implements[0]; - else if (doclet.overrides) parentDoc = doclet.overriddes; - if (parentDoc) { - for (let aDoclet of e.doclets) { - if (aDoclet.longname !== parentDoc) continue; - if (aDoclet.comment !== doclet.comment || aDoclet.description !== doclet.description) { - doclet.comment = aDoclet.comment; - doclet.description = aDoclet.description; - doclet.params = aDoclet.params; - doclet.returns = aDoclet.returns; - doclet.undocumented = false; - changes = true; - } - } - } - } - } - } while (changes); - -// for (let doclet of e.doclets) { -// console.log(doclet); -// } - } -}; \ No newline at end of file diff --git a/dist/MoneroWebWorker.dist.js b/dist/MoneroWebWorker.dist.js deleted file mode 100644 index 61fb6e4d0..000000000 --- a/dist/MoneroWebWorker.dist.js +++ /dev/null @@ -1,245 +0,0 @@ -!function(e){var t={};function r(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,r),n.l=!0,n.exports}r.m=e,r.c=t,r.d=function(e,t,i){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(r.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)r.d(i,n,function(t){return e[t]}.bind(null,n));return i},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=266)}([function(e,t){"function"==typeof Object.create?e.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}},function(e,t,r){var i=r(2),n=i.Buffer;function a(e,t){for(var r in e)t[r]=e[r]}function o(e,t,r){return n(e,t,r)}n.from&&n.alloc&&n.allocUnsafe&&n.allocUnsafeSlow?e.exports=i:(a(i,t),t.Buffer=o),a(n,o),o.from=function(e,t,r){if("number"==typeof e)throw new TypeError("Argument must not be a number");return n(e,t,r)},o.alloc=function(e,t,r){if("number"!=typeof e)throw new TypeError("Argument must be a number");var i=n(e);return void 0!==t?"string"==typeof r?i.fill(t,r):i.fill(t):i.fill(0),i},o.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return n(e)},o.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return i.SlowBuffer(e)}},function(e,t,r){"use strict";(function(e){ -/*! - * The buffer module from node.js, for the browser. - * - * @author Feross Aboukhadijeh - * @license MIT - */ -var i=r(271),n=r(272),a=r(104);function o(){return c.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function s(e,t){if(o()=o())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+o().toString(16)+" bytes");return 0|e}function f(e,t){if(c.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var r=e.length;if(0===r)return 0;for(var i=!1;;)switch(t){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":case void 0:return L(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return U(e).length;default:if(i)return L(e).length;t=(""+t).toLowerCase(),i=!0}}function m(e,t,r){var i=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return T(this,t,r);case"utf8":case"utf-8":return M(this,t,r);case"ascii":return N(this,t,r);case"latin1":case"binary":return j(this,t,r);case"base64":return x(this,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return R(this,t,r);default:if(i)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),i=!0}}function g(e,t,r){var i=e[t];e[t]=e[r],e[r]=i}function _(e,t,r,i,n){if(0===e.length)return-1;if("string"==typeof r?(i=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),r=+r,isNaN(r)&&(r=n?0:e.length-1),r<0&&(r=e.length+r),r>=e.length){if(n)return-1;r=e.length-1}else if(r<0){if(!n)return-1;r=0}if("string"==typeof t&&(t=c.from(t,i)),c.isBuffer(t))return 0===t.length?-1:v(e,t,r,i,n);if("number"==typeof t)return t&=255,c.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?n?Uint8Array.prototype.indexOf.call(e,t,r):Uint8Array.prototype.lastIndexOf.call(e,t,r):v(e,[t],r,i,n);throw new TypeError("val must be string, number or Buffer")}function v(e,t,r,i,n){var a,o=1,s=e.length,c=t.length;if(void 0!==i&&("ucs2"===(i=String(i).toLowerCase())||"ucs-2"===i||"utf16le"===i||"utf-16le"===i)){if(e.length<2||t.length<2)return-1;o=2,s/=2,c/=2,r/=2}function u(e,t){return 1===o?e[t]:e.readUInt16BE(t*o)}if(n){var l=-1;for(a=r;as&&(r=s-c),a=r;a>=0;a--){for(var h=!0,d=0;dn&&(i=n):i=n;var a=t.length;if(a%2!=0)throw new TypeError("Invalid hex string");i>a/2&&(i=a/2);for(var o=0;o>8,n=r%256,a.push(n),a.push(i);return a}(t,e.length-r),e,r,i)}function x(e,t,r){return 0===t&&r===e.length?i.fromByteArray(e):i.fromByteArray(e.slice(t,r))}function M(e,t,r){r=Math.min(e.length,r);for(var i=[],n=t;n239?4:u>223?3:u>191?2:1;if(n+h<=r)switch(h){case 1:u<128&&(l=u);break;case 2:128==(192&(a=e[n+1]))&&(c=(31&u)<<6|63&a)>127&&(l=c);break;case 3:a=e[n+1],o=e[n+2],128==(192&a)&&128==(192&o)&&(c=(15&u)<<12|(63&a)<<6|63&o)>2047&&(c<55296||c>57343)&&(l=c);break;case 4:a=e[n+1],o=e[n+2],s=e[n+3],128==(192&a)&&128==(192&o)&&128==(192&s)&&(c=(15&u)<<18|(63&a)<<12|(63&o)<<6|63&s)>65535&&c<1114112&&(l=c)}null===l?(l=65533,h=1):l>65535&&(l-=65536,i.push(l>>>10&1023|55296),l=56320|1023&l),i.push(l),n+=h}return function(e){var t=e.length;if(t<=4096)return String.fromCharCode.apply(String,e);var r="",i=0;for(;i0&&(e=this.toString("hex",0,r).match(/.{2}/g).join(" "),this.length>r&&(e+=" ... ")),""},c.prototype.compare=function(e,t,r,i,n){if(!c.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===r&&(r=e?e.length:0),void 0===i&&(i=0),void 0===n&&(n=this.length),t<0||r>e.length||i<0||n>this.length)throw new RangeError("out of range index");if(i>=n&&t>=r)return 0;if(i>=n)return-1;if(t>=r)return 1;if(this===e)return 0;for(var a=(n>>>=0)-(i>>>=0),o=(r>>>=0)-(t>>>=0),s=Math.min(a,o),u=this.slice(i,n),l=e.slice(t,r),h=0;hn)&&(r=n),e.length>0&&(r<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");i||(i="utf8");for(var a=!1;;)switch(i){case"hex":return y(this,e,t,r);case"utf8":case"utf-8":return b(this,e,t,r);case"ascii":return E(this,e,t,r);case"latin1":case"binary":return w(this,e,t,r);case"base64":return S(this,e,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return k(this,e,t,r);default:if(a)throw new TypeError("Unknown encoding: "+i);i=(""+i).toLowerCase(),a=!0}},c.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function N(e,t,r){var i="";r=Math.min(e.length,r);for(var n=t;ni)&&(r=i);for(var n="",a=t;ar)throw new RangeError("Trying to access beyond buffer length")}function O(e,t,r,i,n,a){if(!c.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>n||te.length)throw new RangeError("Index out of range")}function A(e,t,r,i){t<0&&(t=65535+t+1);for(var n=0,a=Math.min(e.length-r,2);n>>8*(i?n:1-n)}function P(e,t,r,i){t<0&&(t=4294967295+t+1);for(var n=0,a=Math.min(e.length-r,4);n>>8*(i?n:3-n)&255}function D(e,t,r,i,n,a){if(r+i>e.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function F(e,t,r,i,a){return a||D(e,0,r,4),n.write(e,t,r,i,23,4),r+4}function C(e,t,r,i,a){return a||D(e,0,r,8),n.write(e,t,r,i,52,8),r+8}c.prototype.slice=function(e,t){var r,i=this.length;if((e=~~e)<0?(e+=i)<0&&(e=0):e>i&&(e=i),(t=void 0===t?i:~~t)<0?(t+=i)<0&&(t=0):t>i&&(t=i),t0&&(n*=256);)i+=this[e+--t]*n;return i},c.prototype.readUInt8=function(e,t){return t||I(e,1,this.length),this[e]},c.prototype.readUInt16LE=function(e,t){return t||I(e,2,this.length),this[e]|this[e+1]<<8},c.prototype.readUInt16BE=function(e,t){return t||I(e,2,this.length),this[e]<<8|this[e+1]},c.prototype.readUInt32LE=function(e,t){return t||I(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},c.prototype.readUInt32BE=function(e,t){return t||I(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},c.prototype.readIntLE=function(e,t,r){e|=0,t|=0,r||I(e,t,this.length);for(var i=this[e],n=1,a=0;++a=(n*=128)&&(i-=Math.pow(2,8*t)),i},c.prototype.readIntBE=function(e,t,r){e|=0,t|=0,r||I(e,t,this.length);for(var i=t,n=1,a=this[e+--i];i>0&&(n*=256);)a+=this[e+--i]*n;return a>=(n*=128)&&(a-=Math.pow(2,8*t)),a},c.prototype.readInt8=function(e,t){return t||I(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},c.prototype.readInt16LE=function(e,t){t||I(e,2,this.length);var r=this[e]|this[e+1]<<8;return 32768&r?4294901760|r:r},c.prototype.readInt16BE=function(e,t){t||I(e,2,this.length);var r=this[e+1]|this[e]<<8;return 32768&r?4294901760|r:r},c.prototype.readInt32LE=function(e,t){return t||I(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},c.prototype.readInt32BE=function(e,t){return t||I(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},c.prototype.readFloatLE=function(e,t){return t||I(e,4,this.length),n.read(this,e,!0,23,4)},c.prototype.readFloatBE=function(e,t){return t||I(e,4,this.length),n.read(this,e,!1,23,4)},c.prototype.readDoubleLE=function(e,t){return t||I(e,8,this.length),n.read(this,e,!0,52,8)},c.prototype.readDoubleBE=function(e,t){return t||I(e,8,this.length),n.read(this,e,!1,52,8)},c.prototype.writeUIntLE=function(e,t,r,i){(e=+e,t|=0,r|=0,i)||O(this,e,t,r,Math.pow(2,8*r)-1,0);var n=1,a=0;for(this[t]=255&e;++a=0&&(a*=256);)this[t+n]=e/a&255;return t+r},c.prototype.writeUInt8=function(e,t,r){return e=+e,t|=0,r||O(this,e,t,1,255,0),c.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},c.prototype.writeUInt16LE=function(e,t,r){return e=+e,t|=0,r||O(this,e,t,2,65535,0),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):A(this,e,t,!0),t+2},c.prototype.writeUInt16BE=function(e,t,r){return e=+e,t|=0,r||O(this,e,t,2,65535,0),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):A(this,e,t,!1),t+2},c.prototype.writeUInt32LE=function(e,t,r){return e=+e,t|=0,r||O(this,e,t,4,4294967295,0),c.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):P(this,e,t,!0),t+4},c.prototype.writeUInt32BE=function(e,t,r){return e=+e,t|=0,r||O(this,e,t,4,4294967295,0),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):P(this,e,t,!1),t+4},c.prototype.writeIntLE=function(e,t,r,i){if(e=+e,t|=0,!i){var n=Math.pow(2,8*r-1);O(this,e,t,r,n-1,-n)}var a=0,o=1,s=0;for(this[t]=255&e;++a>0)-s&255;return t+r},c.prototype.writeIntBE=function(e,t,r,i){if(e=+e,t|=0,!i){var n=Math.pow(2,8*r-1);O(this,e,t,r,n-1,-n)}var a=r-1,o=1,s=0;for(this[t+a]=255&e;--a>=0&&(o*=256);)e<0&&0===s&&0!==this[t+a+1]&&(s=1),this[t+a]=(e/o>>0)-s&255;return t+r},c.prototype.writeInt8=function(e,t,r){return e=+e,t|=0,r||O(this,e,t,1,127,-128),c.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},c.prototype.writeInt16LE=function(e,t,r){return e=+e,t|=0,r||O(this,e,t,2,32767,-32768),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):A(this,e,t,!0),t+2},c.prototype.writeInt16BE=function(e,t,r){return e=+e,t|=0,r||O(this,e,t,2,32767,-32768),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):A(this,e,t,!1),t+2},c.prototype.writeInt32LE=function(e,t,r){return e=+e,t|=0,r||O(this,e,t,4,2147483647,-2147483648),c.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):P(this,e,t,!0),t+4},c.prototype.writeInt32BE=function(e,t,r){return e=+e,t|=0,r||O(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),c.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):P(this,e,t,!1),t+4},c.prototype.writeFloatLE=function(e,t,r){return F(this,e,t,!0,r)},c.prototype.writeFloatBE=function(e,t,r){return F(this,e,t,!1,r)},c.prototype.writeDoubleLE=function(e,t,r){return C(this,e,t,!0,r)},c.prototype.writeDoubleBE=function(e,t,r){return C(this,e,t,!1,r)},c.prototype.copy=function(e,t,r,i){if(r||(r=0),i||0===i||(i=this.length),t>=e.length&&(t=e.length),t||(t=0),i>0&&i=this.length)throw new RangeError("sourceStart out of bounds");if(i<0)throw new RangeError("sourceEnd out of bounds");i>this.length&&(i=this.length),e.length-t=0;--n)e[n+t]=this[n+r];else if(a<1e3||!c.TYPED_ARRAY_SUPPORT)for(n=0;n>>=0,r=void 0===r?this.length:r>>>0,e||(e=0),"number"==typeof e)for(a=t;a55295&&r<57344){if(!n){if(r>56319){(t-=3)>-1&&a.push(239,191,189);continue}if(o+1===i){(t-=3)>-1&&a.push(239,191,189);continue}n=r;continue}if(r<56320){(t-=3)>-1&&a.push(239,191,189),n=r;continue}r=65536+(n-55296<<10|r-56320)}else n&&(t-=3)>-1&&a.push(239,191,189);if(n=null,r<128){if((t-=1)<0)break;a.push(r)}else if(r<2048){if((t-=2)<0)break;a.push(r>>6|192,63&r|128)}else if(r<65536){if((t-=3)<0)break;a.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;a.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return a}function U(e){return i.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(B,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function H(e,t,r,i){for(var n=0;n=t.length||n>=e.length);++n)t[n+r]=e[n];return n}}).call(this,r(8))},function(e,t){var r,i,n=e.exports={};function a(){throw new Error("setTimeout has not been defined")}function o(){throw new Error("clearTimeout has not been defined")}function s(e){if(r===setTimeout)return setTimeout(e,0);if((r===a||!r)&&setTimeout)return r=setTimeout,setTimeout(e,0);try{return r(e,0)}catch(t){try{return r.call(null,e,0)}catch(t){return r.call(this,e,0)}}}!function(){try{r="function"==typeof setTimeout?setTimeout:a}catch(e){r=a}try{i="function"==typeof clearTimeout?clearTimeout:o}catch(e){i=o}}();var c,u=[],l=!1,h=-1;function d(){l&&c&&(l=!1,c.length?u=c.concat(u):h=-1,u.length&&p())}function p(){if(!l){var e=s(d);l=!0;for(var t=u.length;t;){for(c=u,u=[];++h1)for(var r=1;r - * @license MIT - */function n(e,t){if(e===t)return 0;for(var r=e.length,i=t.length,n=0,a=Math.min(r,i);n=0;u--)if(l[u]!==h[u])return!1;for(u=l.length-1;u>=0;u--)if(s=l[u],!y(e[s],t[s],r,i))return!1;return!0}(e,t,r,i))}return r?e===t:e==t}function b(e){return"[object Arguments]"==Object.prototype.toString.call(e)}function E(e,t){if(!e||!t)return!1;if("[object RegExp]"==Object.prototype.toString.call(t))return t.test(e);try{if(e instanceof t)return!0}catch(e){}return!Error.isPrototypeOf(t)&&!0===t.call({},e)}function w(e,t,r,i){var n;if("function"!=typeof t)throw new TypeError('"block" argument must be a function');"string"==typeof r&&(i=r,r=null),n=function(e){var t;try{e()}catch(e){t=e}return t}(t),i=(r&&r.name?" ("+r.name+").":".")+(i?" "+i:"."),e&&!n&&_(n,r,"Missing expected exception"+i);var a="string"==typeof i,s=!e&&n&&!r;if((!e&&o.isError(n)&&a&&E(n,r)||s)&&_(n,r,"Got unwanted exception"+i),e&&n&&r&&!E(n,r)||!e&&n)throw n}d.AssertionError=function(e){this.name="AssertionError",this.actual=e.actual,this.expected=e.expected,this.operator=e.operator,e.message?(this.message=e.message,this.generatedMessage=!1):(this.message=function(e){return m(g(e.actual),128)+" "+e.operator+" "+m(g(e.expected),128)}(this),this.generatedMessage=!0);var t=e.stackStartFunction||_;if(Error.captureStackTrace)Error.captureStackTrace(this,t);else{var r=new Error;if(r.stack){var i=r.stack,n=f(t),a=i.indexOf("\n"+n);if(a>=0){var o=i.indexOf("\n",a+1);i=i.substring(o+1)}this.stack=i}}},o.inherits(d.AssertionError,Error),d.fail=_,d.ok=v,d.equal=function(e,t,r){e!=t&&_(e,t,r,"==",d.equal)},d.notEqual=function(e,t,r){e==t&&_(e,t,r,"!=",d.notEqual)},d.deepEqual=function(e,t,r){y(e,t,!1)||_(e,t,r,"deepEqual",d.deepEqual)},d.deepStrictEqual=function(e,t,r){y(e,t,!0)||_(e,t,r,"deepStrictEqual",d.deepStrictEqual)},d.notDeepEqual=function(e,t,r){y(e,t,!1)&&_(e,t,r,"notDeepEqual",d.notDeepEqual)},d.notDeepStrictEqual=function e(t,r,i){y(t,r,!0)&&_(t,r,i,"notDeepStrictEqual",e)},d.strictEqual=function(e,t,r){e!==t&&_(e,t,r,"===",d.strictEqual)},d.notStrictEqual=function(e,t,r){e===t&&_(e,t,r,"!==",d.notStrictEqual)},d.throws=function(e,t,r){w(!0,e,t,r)},d.doesNotThrow=function(e,t,r){w(!1,e,t,r)},d.ifError=function(e){if(e)throw e},d.strict=i((function e(t,r){t||_(t,!0,r,"==",e)}),d,{equal:d.strictEqual,deepEqual:d.deepStrictEqual,notEqual:d.notStrictEqual,notDeepEqual:d.notDeepStrictEqual}),d.strict.strict=d.strict;var S=Object.keys||function(e){var t=[];for(var r in e)s.call(e,r)&&t.push(r);return t}}).call(this,r(8))},function(e,t,r){(function(t){var i;e.exports=(i=i||function(e,i){var n;if("undefined"!=typeof window&&window.crypto&&(n=window.crypto),!n&&"undefined"!=typeof window&&window.msCrypto&&(n=window.msCrypto),!n&&void 0!==t&&t.crypto&&(n=t.crypto),!n)try{n=r(10)}catch(e){}var a=function(){if(n){if("function"==typeof n.getRandomValues)try{return n.getRandomValues(new Uint32Array(1))[0]}catch(e){}if("function"==typeof n.randomBytes)try{return n.randomBytes(4).readInt32LE()}catch(e){}}throw new Error("Native crypto module could not be used to get secure random number.")},o=Object.create||function(){function e(){}return function(t){var r;return e.prototype=t,r=new e,e.prototype=null,r}}(),s={},c=s.lib={},u=c.Base={extend:function(e){var t=o(this);return e&&t.mixIn(e),t.hasOwnProperty("init")&&this.init!==t.init||(t.init=function(){t.$super.init.apply(this,arguments)}),t.init.prototype=t,t.$super=this,t},create:function(){var e=this.extend();return e.init.apply(e,arguments),e},init:function(){},mixIn:function(e){for(var t in e)e.hasOwnProperty(t)&&(this[t]=e[t]);e.hasOwnProperty("toString")&&(this.toString=e.toString)},clone:function(){return this.init.prototype.extend(this)}},l=c.WordArray=u.extend({init:function(e,t){e=this.words=e||[],this.sigBytes=null!=t?t:4*e.length},toString:function(e){return(e||d).stringify(this)},concat:function(e){var t=this.words,r=e.words,i=this.sigBytes,n=e.sigBytes;if(this.clamp(),i%4)for(var a=0;a>>2]>>>24-a%4*8&255;t[i+a>>>2]|=o<<24-(i+a)%4*8}else for(a=0;a>>2]=r[a>>>2];return this.sigBytes+=n,this},clamp:function(){var t=this.words,r=this.sigBytes;t[r>>>2]&=4294967295<<32-r%4*8,t.length=e.ceil(r/4)},clone:function(){var e=u.clone.call(this);return e.words=this.words.slice(0),e},random:function(e){for(var t=[],r=0;r>>2]>>>24-n%4*8&255;i.push((a>>>4).toString(16)),i.push((15&a).toString(16))}return i.join("")},parse:function(e){for(var t=e.length,r=[],i=0;i>>3]|=parseInt(e.substr(i,2),16)<<24-i%8*4;return new l.init(r,t/2)}},p=h.Latin1={stringify:function(e){for(var t=e.words,r=e.sigBytes,i=[],n=0;n>>2]>>>24-n%4*8&255;i.push(String.fromCharCode(a))}return i.join("")},parse:function(e){for(var t=e.length,r=[],i=0;i>>2]|=(255&e.charCodeAt(i))<<24-i%4*8;return new l.init(r,t)}},f=h.Utf8={stringify:function(e){try{return decodeURIComponent(escape(p.stringify(e)))}catch(e){throw new Error("Malformed UTF-8 data")}},parse:function(e){return p.parse(unescape(encodeURIComponent(e)))}},m=c.BufferedBlockAlgorithm=u.extend({reset:function(){this._data=new l.init,this._nDataBytes=0},_append:function(e){"string"==typeof e&&(e=f.parse(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes},_process:function(t){var r,i=this._data,n=i.words,a=i.sigBytes,o=this.blockSize,s=a/(4*o),c=(s=t?e.ceil(s):e.max((0|s)-this._minBufferSize,0))*o,u=e.min(4*c,a);if(c){for(var h=0;h36)throw new Error("illegal radix "+e+".");if(0===this._s)return"0";if(10===e){var t=this._s<0?"-":"";t+=this._d[this._d.length-1].toString();for(var i=this._d.length-2;i>=0;i--){for(var n=this._d[i].toString();n.length<7;)n="0"+n;t+=n}return t}var a=r.digits;e=r.small[e];for(var o,s=this._s,c=this.abs(),u=[];0!==c._s;){var l=c.divRem(e);c=l[0],o=l[1],u.push(a[o.valueOf()])}return(s<0?"-":"")+u.reverse().join("")},r.radixRegex=[/^$/,/^$/,/^[01]*$/,/^[012]*$/,/^[0-3]*$/,/^[0-4]*$/,/^[0-5]*$/,/^[0-6]*$/,/^[0-7]*$/,/^[0-8]*$/,/^[0-9]*$/,/^[0-9aA]*$/,/^[0-9abAB]*$/,/^[0-9abcABC]*$/,/^[0-9a-dA-D]*$/,/^[0-9a-eA-E]*$/,/^[0-9a-fA-F]*$/,/^[0-9a-gA-G]*$/,/^[0-9a-hA-H]*$/,/^[0-9a-iA-I]*$/,/^[0-9a-jA-J]*$/,/^[0-9a-kA-K]*$/,/^[0-9a-lA-L]*$/,/^[0-9a-mA-M]*$/,/^[0-9a-nA-N]*$/,/^[0-9a-oA-O]*$/,/^[0-9a-pA-P]*$/,/^[0-9a-qA-Q]*$/,/^[0-9a-rA-R]*$/,/^[0-9a-sA-S]*$/,/^[0-9a-tA-T]*$/,/^[0-9a-uA-U]*$/,/^[0-9a-vA-V]*$/,/^[0-9a-wA-W]*$/,/^[0-9a-xA-X]*$/,/^[0-9a-yA-Y]*$/,/^[0-9a-zA-Z]*$/],r.parse=function(e,n){var a;e=e.toString(),void 0!==n&&10!=+n||(e=e.replace(/\s*[*xX]\s*10\s*(\^|\*\*)\s*/,"e").replace(/^([+\-])?(\d+)\.?(\d*)[eE]([+\-]?\d+)$/,(function(e,t,r,i,n){var a=(n=+n)<0,o=r.length+n;e=(a?r:i).length,n=(n=Math.abs(n))>=e?n-e+a:0;var s=new Array(n+1).join("0"),c=r+i;return(t||"")+(a?c=s+c:c+=s).substr(0,o+=a?s.length:0)+(o36)throw new Error("Illegal radix "+n+".");if(n=+n,!r.radixRegex[n].test(u))throw new Error("Bad digit for radix "+n);if(0===(u=u.replace(/^0+/,"").split("")).length)return i;if(s="-"===s?-1:1,10==n){for(var l=[];u.length>=7;)l.push(parseInt(u.splice(u.length-r.base_log10,r.base_log10).join(""),10));return l.push(parseInt(u.join(""),10)),new r(l,s,t)}l=i;n=r.small[n];for(var h=r.small,d=0;do&&(n=a,o=s),h=u;l&&hi)return 1;for(var n=this._d,a=e._d,o=t-1;o>=0;o--)if(n[o]!==a[o])return n[o]=e._d.length,o=(a?this:e)._d,s=(a?e:this)._d,c=o.length,u=s.length,l=c+u,h=new Array(l);for(n=0;n=1e7?[n%1e7|0,n/1e7|0]:[n],1,t);if(2===e)return this.add(this);if(this.isUnit())return new r([e],1,t);for(var a=this._d,o=a.length,s=o+1,c=new Array(s),u=0;uc._d.length&&(m=1e7*(m+1)),o=Math.ceil(m/g)}do{var _=c.multiplySingleDigit(o);if(_.compareAbs(d)<=0)break;o--}while(o);if(h.push(o),o){var v=d.subtract(_);d._d=v._d.slice()}}return[new r(h.reverse(),s,t),new r(d._d,this._s,t)]},r.prototype.divRemSmall=function(e){var n;if(0===(e=+e))throw new Error("Divide by zero");var a=e<0?-1:1,o=this._s*a;if((e=Math.abs(e))<1||e>=1e7)throw new Error("Argument out of range");if(0===this._s)return[i,i];if(1===e||-1===e)return[1===o?this.abs():new r(this._d,o,t),i];if(1===this._d.length){var s=new r([this._d[0]/e|0],1,t);return n=new r([this._d[0]%e|0],1,t),o<0&&(s=s.negate()),this._s<0&&(n=n.negate()),[s,n]}for(var c,u=this._d.slice(),l=new Array(u.length),h=0,d=0,p=0;u.length;){if((h=1e7*h+u[u.length-1])0},r.prototype.isNegative=function(){return this._s<0},r.prototype.isZero=function(){return 0===this._s},r.prototype.exp10=function(e){if(0===(e=+e))return this;if(Math.abs(e)>Number(o))throw new Error("exponent too large in BigInteger.exp10");if(0===this._s)return i;if(e>0){for(var n=new r(this._d.slice(),this._s,t);e>=7;e-=7)n._d.unshift(0);return 0==e?n:(n._s=1,n=n.multiplySingleDigit(Math.pow(10,e)),this._s<0?n.negate():n)}if(-e>=7*this._d.length)return i;n=new r(this._d.slice(),this._s,t);for(e=-e;e>=7;e-=7)n._d.shift();return 0==e?n:n.divRemSmall(Math.pow(10,e))[0]},r.prototype.pow=function(e){if(this.isUnit())return this._s>0||r(e).isOdd()?this:this.negate();if(0===(e=r(e))._s)return n;if(e._s<0){if(0===this._s)throw new Error("Divide by zero");return i}if(0===this._s)return i;if(e.isUnit())return this;if(e.compareAbs(o)>0)throw new Error("exponent too large in BigInteger.pow");for(var t=this,a=n,s=r.small[2];e.isPositive();){if(e.isOdd()&&(a=a.multiply(t),e.isUnit()))return a;t=t.square(),e=e.quotient(s)}return a},r.prototype.modPow=function(e,t){for(var i=n,a=this;e.isPositive();)e.isOdd()&&(i=i.multiply(a).remainder(t)),(e=e.quotient(r.small[2])).isPositive()&&(a=a.square().remainder(t));return i},r.prototype.log=function(){switch(this._s){case 0:return-1/0;case-1:return NaN}var e=this._d.length;if(7*e<30)return Math.log(this.valueOf());var i=Math.ceil(30/7),n=this._d.slice(e-i);return Math.log(new r(n,1,t).valueOf())+(e-i)*Math.log(1e7)},r.prototype.valueOf=function(){return parseInt(this.toString(),10)},r.prototype.toJSValue=function(){return parseInt(this.toString(),10)},r.prototype.lowVal=function(){return this._d[0]||0};var o=r(2147483647);r.MAX_EXP=o,function(){function e(e){return function(t){return e.call(r(t))}}function t(e){return function(t,i){return e.call(r(t),r(i))}}function i(e){return function(t,i,n){return e.call(r(t),r(i),r(n))}}!function(){var n,a,o="toJSValue,isEven,isOdd,sign,isZero,isNegative,abs,isUnit,square,negate,isPositive,toString,next,prev,log".split(","),s="compare,remainder,divRem,subtract,add,quotient,divide,multiply,pow,compareAbs".split(","),c=["modPow"];for(n=0;n=2*(1<<30))throw new RangeError('The value "'+e+'" is invalid for option "size"');var i=a(e);return t&&0!==t.length?"string"==typeof r?i.fill(t,r):i.fill(t):i.fill(0),i}),!o.kStringMaxLength)try{o.kStringMaxLength=t.binding("buffer").kStringMaxLength}catch(e){}o.constants||(o.constants={MAX_LENGTH:o.kMaxLength},o.kStringMaxLength&&(o.constants.MAX_STRING_LENGTH=o.kStringMaxLength)),e.exports=o}).call(this,r(3))},function(e,t,r){"use strict";t.randomBytes=t.rng=t.pseudoRandomBytes=t.prng=r(44),t.createHash=t.Hash=r(61),t.createHmac=t.Hmac=r(167);var i=r(297),n=Object.keys(i),a=["sha1","sha224","sha256","sha384","sha512","md5","rmd160"].concat(n);t.getHashes=function(){return a};var o=r(170);t.pbkdf2=o.pbkdf2,t.pbkdf2Sync=o.pbkdf2Sync;var s=r(299);t.Cipher=s.Cipher,t.createCipher=s.createCipher,t.Cipheriv=s.Cipheriv,t.createCipheriv=s.createCipheriv,t.Decipher=s.Decipher,t.createDecipher=s.createDecipher,t.Decipheriv=s.Decipheriv,t.createDecipheriv=s.createDecipheriv,t.getCiphers=s.getCiphers,t.listCiphers=s.listCiphers;var c=r(314);t.DiffieHellmanGroup=c.DiffieHellmanGroup,t.createDiffieHellmanGroup=c.createDiffieHellmanGroup,t.getDiffieHellman=c.getDiffieHellman,t.createDiffieHellman=c.createDiffieHellman,t.DiffieHellman=c.DiffieHellman;var u=r(321);t.createSign=u.createSign,t.Sign=u.Sign,t.createVerify=u.createVerify,t.Verify=u.Verify,t.createECDH=r(369);var l=r(372);t.publicEncrypt=l.publicEncrypt,t.privateEncrypt=l.privateEncrypt,t.publicDecrypt=l.publicDecrypt,t.privateDecrypt=l.privateDecrypt;var h=r(376);t.randomFill=h.randomFill,t.randomFillSync=h.randomFillSync,t.createCredentials=function(){throw new Error(["sorry, createCredentials is not implemented yet","we accept pull requests","https://github.com/crypto-browserify/crypto-browserify"].join("\n"))},t.constants={DH_CHECK_P_NOT_SAFE_PRIME:2,DH_CHECK_P_NOT_PRIME:1,DH_UNABLE_TO_CHECK_GENERATOR:4,DH_NOT_SUITABLE_GENERATOR:8,NPN_ENABLED:1,ALPN_ENABLED:1,RSA_PKCS1_PADDING:1,RSA_SSLV23_PADDING:2,RSA_NO_PADDING:3,RSA_PKCS1_OAEP_PADDING:4,RSA_X931_PADDING:5,RSA_PKCS1_PSS_PADDING:6,POINT_CONVERSION_COMPRESSED:2,POINT_CONVERSION_UNCOMPRESSED:4,POINT_CONVERSION_HYBRID:6}},function(e,t,r){(function(e){var i=Object.getOwnPropertyDescriptors||function(e){for(var t=Object.keys(e),r={},i=0;i=a)return e;switch(e){case"%s":return String(i[r++]);case"%d":return Number(i[r++]);case"%j":try{return JSON.stringify(i[r++])}catch(e){return"[Circular]"}default:return e}})),c=i[r];r=3&&(i.depth=arguments[2]),arguments.length>=4&&(i.colors=arguments[3]),f(r)?i.showHidden=r:r&&t._extend(i,r),v(i.showHidden)&&(i.showHidden=!1),v(i.depth)&&(i.depth=2),v(i.colors)&&(i.colors=!1),v(i.customInspect)&&(i.customInspect=!0),i.colors&&(i.stylize=c),l(i,e,i.depth)}function c(e,t){var r=s.styles[t];return r?"["+s.colors[r][0]+"m"+e+"["+s.colors[r][1]+"m":e}function u(e,t){return e}function l(e,r,i){if(e.customInspect&&r&&S(r.inspect)&&r.inspect!==t.inspect&&(!r.constructor||r.constructor.prototype!==r)){var n=r.inspect(i,e);return _(n)||(n=l(e,n,i)),n}var a=function(e,t){if(v(t))return e.stylize("undefined","undefined");if(_(t)){var r="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(r,"string")}if(g(t))return e.stylize(""+t,"number");if(f(t))return e.stylize(""+t,"boolean");if(m(t))return e.stylize("null","null")}(e,r);if(a)return a;var o=Object.keys(r),s=function(e){var t={};return e.forEach((function(e,r){t[e]=!0})),t}(o);if(e.showHidden&&(o=Object.getOwnPropertyNames(r)),w(r)&&(o.indexOf("message")>=0||o.indexOf("description")>=0))return h(r);if(0===o.length){if(S(r)){var c=r.name?": "+r.name:"";return e.stylize("[Function"+c+"]","special")}if(y(r))return e.stylize(RegExp.prototype.toString.call(r),"regexp");if(E(r))return e.stylize(Date.prototype.toString.call(r),"date");if(w(r))return h(r)}var u,b="",k=!1,x=["{","}"];(p(r)&&(k=!0,x=["[","]"]),S(r))&&(b=" [Function"+(r.name?": "+r.name:"")+"]");return y(r)&&(b=" "+RegExp.prototype.toString.call(r)),E(r)&&(b=" "+Date.prototype.toUTCString.call(r)),w(r)&&(b=" "+h(r)),0!==o.length||k&&0!=r.length?i<0?y(r)?e.stylize(RegExp.prototype.toString.call(r),"regexp"):e.stylize("[Object]","special"):(e.seen.push(r),u=k?function(e,t,r,i,n){for(var a=[],o=0,s=t.length;o=0&&0,e+t.replace(/\u001b\[\d\d?m/g,"").length+1}),0)>60)return r[0]+(""===t?"":t+"\n ")+" "+e.join(",\n ")+" "+r[1];return r[0]+t+" "+e.join(", ")+" "+r[1]}(u,b,x)):x[0]+b+x[1]}function h(e){return"["+Error.prototype.toString.call(e)+"]"}function d(e,t,r,i,n,a){var o,s,c;if((c=Object.getOwnPropertyDescriptor(t,n)||{value:t[n]}).get?s=c.set?e.stylize("[Getter/Setter]","special"):e.stylize("[Getter]","special"):c.set&&(s=e.stylize("[Setter]","special")),j(i,n)||(o="["+n+"]"),s||(e.seen.indexOf(c.value)<0?(s=m(r)?l(e,c.value,null):l(e,c.value,r-1)).indexOf("\n")>-1&&(s=a?s.split("\n").map((function(e){return" "+e})).join("\n").substr(2):"\n"+s.split("\n").map((function(e){return" "+e})).join("\n")):s=e.stylize("[Circular]","special")),v(o)){if(a&&n.match(/^\d+$/))return s;(o=JSON.stringify(""+n)).match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(o=o.substr(1,o.length-2),o=e.stylize(o,"name")):(o=o.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),o=e.stylize(o,"string"))}return o+": "+s}function p(e){return Array.isArray(e)}function f(e){return"boolean"==typeof e}function m(e){return null===e}function g(e){return"number"==typeof e}function _(e){return"string"==typeof e}function v(e){return void 0===e}function y(e){return b(e)&&"[object RegExp]"===k(e)}function b(e){return"object"==typeof e&&null!==e}function E(e){return b(e)&&"[object Date]"===k(e)}function w(e){return b(e)&&("[object Error]"===k(e)||e instanceof Error)}function S(e){return"function"==typeof e}function k(e){return Object.prototype.toString.call(e)}function x(e){return e<10?"0"+e.toString(10):e.toString(10)}t.debuglog=function(r){if(v(a)&&(a=e.env.NODE_DEBUG||""),r=r.toUpperCase(),!o[r])if(new RegExp("\\b"+r+"\\b","i").test(a)){var i=e.pid;o[r]=function(){var e=t.format.apply(t,arguments);console.error("%s %d: %s",r,i,e)}}else o[r]=function(){};return o[r]},t.inspect=s,s.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},s.styles={special:"cyan",number:"yellow",boolean:"yellow",undefined:"grey",null:"bold",string:"green",date:"magenta",regexp:"red"},t.isArray=p,t.isBoolean=f,t.isNull=m,t.isNullOrUndefined=function(e){return null==e},t.isNumber=g,t.isString=_,t.isSymbol=function(e){return"symbol"==typeof e},t.isUndefined=v,t.isRegExp=y,t.isObject=b,t.isDate=E,t.isError=w,t.isFunction=S,t.isPrimitive=function(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e},t.isBuffer=r(268);var M=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];function N(){var e=new Date,t=[x(e.getHours()),x(e.getMinutes()),x(e.getSeconds())].join(":");return[e.getDate(),M[e.getMonth()],t].join(" ")}function j(e,t){return Object.prototype.hasOwnProperty.call(e,t)}t.log=function(){console.log("%s - %s",N(),t.format.apply(t,arguments))},t.inherits=r(0),t._extend=function(e,t){if(!t||!b(t))return e;for(var r=Object.keys(t),i=r.length;i--;)e[r[i]]=t[r[i]];return e};var T="undefined"!=typeof Symbol?Symbol("util.promisify.custom"):void 0;function R(e,t){if(!e){var r=new Error("Promise was rejected with a falsy value");r.reason=e,e=r}return t(e)}t.promisify=function(e){if("function"!=typeof e)throw new TypeError('The "original" argument must be of type Function');if(T&&e[T]){var t;if("function"!=typeof(t=e[T]))throw new TypeError('The "util.promisify.custom" argument must be of type Function');return Object.defineProperty(t,T,{value:t,enumerable:!1,writable:!1,configurable:!0}),t}function t(){for(var t,r,i=new Promise((function(e,i){t=e,r=i})),n=[],a=0;a0,"Cannot determine if empty string is base32"),/^[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]+$/.test(e))}static assertBase58(e,t){o.assertTrue(isBase58(e),t||"Argument asserted as base58 but is not base58")}static isBase58(e){return"string"==typeof e&&(o.assertTrue(e.length>0,"Cannot determine if empty string is base58"),/^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$/.test(e))}static assertBase64(e,t){o.assertTrue(isBase64(e),t||"Argument asserted as base64 but is not base64")}static isBase64(e){if("string"!=typeof e)return!1;o.assertTrue(e.length>0,"Cannot determine if empty string is base64");try{return btoa(atob(e))==e}catch(e){return!1}}static fail(e){throw new Error(e||"Failure (no message)")}static assertTrue(e,t){if("boolean"!=typeof e)throw new Error("Argument is not a boolean");if(!e)throw new Error(t||"Boolean asserted as true but was false")}static assertFalse(e,t){if("boolean"!=typeof e)throw new Error("Argument is not a boolean");if(e)throw new Error(t||"Boolean asserted as false but was true")}static assertNull(e,t){if(null!==e)throw new Error(t||"Argument asserted as null but was not null: "+e)}static assertNotNull(e,t){if(null===e)throw new Error(t||"Argument asserted as not null but was null")}static assertDefined(e,t){if(o.isUndefined(e))throw new Error(t||"Argument asserted as defined but was undefined")}static assertUndefined(e,t){if(o.isDefined(e))throw new Error(t||"Argument asserted as undefined but was defined: "+e)}static assertInitialized(e,t){if(o.isUninitialized(e))throw new Error(t||"Argument asserted as initialized but was "+e)}static assertUninitialized(e,t){if(o.isInitialized(e))throw new Error(t||"Argument asserted as uninitialized but was initialized")}static assertEquals(e,t,r){o.assertTrue(equals(e,t),r||"Arguments asserted as equal but are not equal: "+e+" vs "+t)}static assertNotEquals(e,t,r){if(e===t)throw new Error(r||"Arguments asserted as not equal but are equal: "+e+" vs "+t)}static assertInt(e,t){if(!o.isInt(e))throw new Error(t||"Argument asserted as an integer but is not an integer")}static assertNumber(e,t){if(!o.isNumber(e))throw new Error(t||"Argument asserted as a number but is not a number")}static assertBoolean(e,t){if(!o.isBoolean(e))throw new Error(t||"Argument asserted as a boolean but is not a boolean")}static assertString(e,t){if(!o.isString(e))throw new Error(t||"Argument asserted as a string but is not a string: "+e)}static assertArray(e,t){if(!o.isArray(e))throw new Error(t||"Argument asserted as an array but is not an array")}static assertFunction(e,t){if(!o.isFunction(e))throw new Error(t||"Argument asserted as a static but is not a static")}static assertObject(e,t,r){if(o.assertInitialized(e,r),t){if(!isObject(e,t))throw new Error(r||"Argument asserted as object '"+t.name+"' but was not")}else if(!isObject(e))throw new Error(r||"Argument asserted as object but was not")}static inheritsFrom(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e}static invoke(){let e=arguments[0],t=[];for(let e=1;e0&&(n[n.length]=i)},r=[];r.push([]);for(let i=0;i=1);let r=getPowerSet(e),i=[];for(let e=0;e=0;i--)e[i]===t&&(e.splice(i,1),r=!0,i--);return r}static toLowerCaseArray(e){let t=[];for(let r=0;r-1}static arraysEqual(e,t){if(e===t)return!0;if(null==e&&null==t)return!0;if(null==e||null==t)return!1;if(void 0===e&&void 0===t)return!0;if(void 0===e||void 0===t)return!1;if(!o.isArray(e))throw new Error("First argument is not an array");if(!o.isArray(t))throw new Error("Second argument is not an array");if(e.length!=t.length)return!1;for(let r=0;r=1);let r=getPowerSetOfLength(getIndices(e.length),t),i=[];for(let t=0;t").append($(e).clone()).html()}static copyProperties(e){return JSON.parse(JSON.stringify(e))}static deleteProperties(e){let t=[];for(let r in e)t.push(r);for(i=0;i"+e.title+"":"",t+=e.internalCss?"":"",e.dependencyPaths){let r=listify(e.dependencyPaths);for(let e=0;e<\/script>";else if(i.endsWith(".css"))t+="";else{if(!i.endsWith(".png")&&!i.endsWith(".img"))throw new Error("Unrecognized dependency path extension: "+i);t+=""}}}return t+="",e.div&&(t+=$("

").append(e.div.clone()).html()),t+="",t}static newWindow(e,t){let r=!1,i=window.open();function n(e,i){r||(r=!0,t&&t(e,i))}isInitialized(i)&&isInitialized(i.document)?(i.opener=null,i.document.write(buildHtmlDocument(e)),i.addEventListener("load",(function(){n(null,i)})),i.document.close()):n(new Error("Could not get window reference"))}static imgToDataUrl(e,t){let r=document.createElement("canvas");return r.height=e.naturalHeight,r.width=e.naturalWidth,r.getContext("2d").drawImage(e,0,0),r.toDataURL(t)}static isImageAccessible(e,r,i){let n=!1,a=new Image;function o(e){n||(n=!0,void 0===e||"error"===e.type?i(!1):i(!0))}a.onload=o,a.onerror=o,a.src=e+"?"+ +new Date,setTimeout((function(){t((function(){t((function(){t((function(){n||(n=!0,i(!1))}))}))}))}),r)}static isZipFile(e){return e.name.endsWith(".zip")||"application/zip"===e.type}static isJsonFile(e){return e.name.endsWith(".json")||"application/json"===e.type}static isCsvFile(e){return e.name.endsWith(".csv")||"text/csv"===e.type}static isTxtFile(e){return e.name.endsWith(".txt")||"text/plain"===e.type}static getImages(e,t){o.isArray(e)||(o.assertTrue(isString(e)),e=[e]);let r=[];for(let t=0;t0}static getIEVersion(){let e=window.navigator.userAgent,t=e.indexOf("MSIE ");if(t>0)return parseInt(e.substring(t+5,e.indexOf(".",t)),10);if(e.indexOf("Trident/")>0){let t=e.indexOf("rv:");return parseInt(e.substring(t+3,e.indexOf(".",t)),10)}let r=e.indexOf("Edge/");return r>0?parseInt(e.substring(r+5,e.indexOf(".",r)),10):null}static getParameterByName(e,t){t||(t=window.location.href),e=e.replace(/[\[\]]/g,"\\$&");let r=new RegExp("[?&]"+e+"(=([^&#]*)|&|#|$)").exec(t);return r?r[2]?decodeURIComponent(r[2].replace(/\+/g," ")):"":null}static getRandomInt(e,t){return e=Math.ceil(e),t=Math.floor(t),Math.floor(Math.random()*(t-e+1))+e}static getRandomInts(e,t,r){o.assertTrue("number"==typeof r);let i=[];for(let n=0;n=0),o.assertTrue(t-e+1>=r);i.length0;t--){var r=Math.floor(Math.random()*(t+1)),i=e[t];e[t]=e[r],e[r]=i}}static sort(e){e.sort((e,t)=>e===t?0:e>t?1:-1)}static safeSet(e,t,r,i,n,a){let s=t.call(e),c=o.reconcile(s,i,n,a);s!==c&&r.call(e,c)}static reconcile(e,t,r,i){if(e===t)return e;let o;if(e instanceof a&&t instanceof a&&(o=e.compare(t),0===o))return e;if(void 0===e||void 0===t)return r&&!1===r.resolveDefined?void 0:void 0===e?t:e;if(r&&void 0!==r.resolveTrue&&"boolean"==typeof e&&"boolean"==typeof t)return n.equal(typeof r.resolveTrue,"boolean"),r.resolveTrue;if(r&&void 0!==r.resolveMax){if(n.equal(typeof r.resolveMax,"boolean"),"number"==typeof e&&"number"==typeof t)return r.resolveMax?Math.max(e,t):Math.min(e,t);if(e instanceof a&&t instanceof a)return r.resolveMax?o<0?t:e:o<0?e:t}return n.deepEqual(e,t,i||"Cannot reconcile values "+e+" and "+t+" with config: "+JSON.stringify(r)),e}static kvLine(e,t,r=0,i=!0,n=!0){return void 0===t&&n?"":o.getIndent(r)+e+": "+t+(i?"\n":"")}static stringifyBIs(e){return e.replace(/("[^"]*"\s*:\s*)(\d{16,})/g,'$1"$2"')}}e.exports=o}).call(this,r(32).setImmediate)},function(e,t,r){e.exports={bufferSplit:function(e,t){i.buffer(e),i.string(t);for(var r=[],n=0,a=0,o=0;o=t.length){var s=o+1;r.push(e.slice(n,s-a)),n=s,a=0}n<=e.length&&r.push(e.slice(n,e.length));return r},addRSAMissing:function(e){i.object(e),p(e,a,[1,1]);var t,r=new h(e.part.d.data);if(!e.part.dmodp){var n=new h(e.part.p.data),o=r.mod(n.subtract(1));t=g(o),e.part.dmodp={name:"dmodp",data:t},e.parts.push(e.part.dmodp)}if(!e.part.dmodq){var s=new h(e.part.q.data),c=r.mod(s.subtract(1));t=g(c),e.part.dmodq={name:"dmodq",data:t},e.parts.push(e.part.dmodq)}},calculateDSAPublic:function(e,t,r){return i.buffer(e),i.buffer(t),i.buffer(r),e=new h(e),t=new h(t),r=new h(r),g(e.modPow(r,t))},calculateED25519Public:function(e){i.buffer(e);var t=d.sign.keyPair.fromSeed(new Uint8Array(e));return n.from(t.publicKey)},calculateX25519Public:function(e){i.buffer(e);var t=d.box.keyPair.fromSeed(new Uint8Array(e));return n.from(t.publicKey)},mpNormalize:m,mpDenormalize:function(e){i.buffer(e);for(;e.length>1&&0===e[0];)e=e.slice(1);return e},ecNormalize:function(e,t){if(i.buffer(e),0===e[0]&&4===e[1])return t?e:e.slice(1);if(4===e[0]){if(!t)return e}else{for(;0===e[0];)e=e.slice(1);if(2===e[0]||3===e[0])throw new Error("Compressed elliptic curve points are not supported");if(4!==e[0])throw new Error("Not a valid elliptic curve point");if(!t)return e}var r=n.alloc(e.length+1);return r[0]=0,e.copy(r,1),r},countZeros:function(e){var t=0,r=8;for(;t3)return!1;if(i.constructor.name!==t.name)return!1;var a=i._sshpkApiVersion;void 0===a&&(a=t._oldVersionDetect(e));return!(a[0]!=r[0]||a[1]t;)i.equal(e[0],0),e=e.slice(1);for(;e.length=r[1],n+" must be compatible with "+t.name+" klass version "+r[0]+"."+r[1])}}var f={"des-ede3-cbc":{key:7,iv:8},"aes-128-cbc":{key:16,iv:16},"aes-256-cbc":{key:32,iv:16}};function m(e){for(i.buffer(e);e.length>1&&0===e[0]&&0==(128&e[1]);)e=e.slice(1);if(128==(128&e[0])){var t=n.alloc(e.length+1);t[0]=0,e.copy(t,1),e=t}return e}function g(e){var t=n.from(e.toByteArray());return t=m(t)}},function(e,t,r){(function(t){e.exports=g;var i,n=r(6),a=r(16),o=r(10),s=r(66),c=r(30),u=r(126).DiffieHellman,l=r(29),h=r(13),d=r(17);try{i=r(226)}catch(e){}var p=l.InvalidAlgorithmError,f=l.KeyParseError,m={};function g(e){n.object(e,"options"),n.arrayOfObject(e.parts,"options.parts"),n.string(e.type,"options.type"),n.optionalString(e.comment,"options.comment");var t=a.info[e.type];if("object"!=typeof t)throw new p(e.type);for(var r,i={},o=0;o1024&&(e="sha256"),"ed25519"===this.type&&(e="sha512"),"ecdsa"===this.type&&(e=this.size<=256?"sha256":this.size<=384?"sha384":"sha512"),e},g.prototype.createVerify=function(e){if(void 0===e&&(e=this.defaultHashAlgorithm()),n.string(e,"hash algorithm"),"ed25519"===this.type&&void 0!==i)return new i.Verifier(this,e);if("curve25519"===this.type)throw new Error("Curve25519 keys are not suitable for signing or verification");var r,a,s;try{a=e.toUpperCase(),r=o.createVerify(a)}catch(e){s=e}(void 0===r||s instanceof Error&&s.message.match(/Unknown message digest/))&&(a="RSA-",a+=e.toUpperCase(),r=o.createVerify(a)),n.ok(r,"failed to create verifier");var u=r.verify.bind(r),l=this.toBuffer("pkcs8"),h=this.curve,d=this;return r.verify=function(r,i){if(c.isSignature(r,[2,0]))return r.type===d.type&&((!r.hashAlgorithm||r.hashAlgorithm===e)&&((!r.curve||"ecdsa"!==d.type||r.curve===h)&&u(l,r.toBuffer("asn1"))));if("string"==typeof r||t.isBuffer(r))return u(l,r,i);throw c.isSignature(r,[1,0])?new Error("signature was created by too old a version of sshpk and cannot be verified"):new TypeError("signature must be a string, Buffer, or Signature object")},r},g.prototype.createDiffieHellman=function(){if("rsa"===this.type)throw new Error("RSA keys do not support Diffie-Hellman");return new u(this)},g.prototype.createDH=g.prototype.createDiffieHellman,g.parse=function(e,t,r){"string"!=typeof e&&n.buffer(e,"data"),void 0===t&&(t="auto"),n.string(t,"format"),"string"==typeof r&&(r={filename:r}),n.optionalObject(r,"options"),void 0===r&&(r={}),n.optionalString(r.filename,"options.filename"),void 0===r.filename&&(r.filename="(unnamed)"),n.object(m[t],"formats[format]");try{var i=m[t].read(e,r);return i instanceof d&&(i=i.toPublic()),i.comment||(i.comment=r.filename),i}catch(e){if("KeyEncryptedError"===e.name)throw e;throw new f(r.filename,t,e)}},g.isKey=function(e,t){return h.isCompatible(e,g,t)},g.prototype._sshpkApiVersion=[1,6],g._oldVersionDetect=function(e){return n.func(e.toBuffer),n.func(e.fingerprint),e.createDH?[1,4]:e.defaultHashAlgorithm?[1,3]:e.formats.auto?[1,2]:e.formats.pkcs1?[1,1]:[1,0]}}).call(this,r(2).Buffer)},function(e,t,r){var i,n,a,o,s,c,u,l,h,d,p,f,m,g,_,v,y,b,E;e.exports=(i=r(5),r(41),void(i.lib.Cipher||(n=i,a=n.lib,o=a.Base,s=a.WordArray,c=a.BufferedBlockAlgorithm,u=n.enc,u.Utf8,l=u.Base64,h=n.algo.EvpKDF,d=a.Cipher=c.extend({cfg:o.extend(),createEncryptor:function(e,t){return this.create(this._ENC_XFORM_MODE,e,t)},createDecryptor:function(e,t){return this.create(this._DEC_XFORM_MODE,e,t)},init:function(e,t,r){this.cfg=this.cfg.extend(r),this._xformMode=e,this._key=t,this.reset()},reset:function(){c.reset.call(this),this._doReset()},process:function(e){return this._append(e),this._process()},finalize:function(e){return e&&this._append(e),this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(){function e(e){return"string"==typeof e?E:y}return function(t){return{encrypt:function(r,i,n){return e(i).encrypt(t,r,i,n)},decrypt:function(r,i,n){return e(i).decrypt(t,r,i,n)}}}}()}),a.StreamCipher=d.extend({_doFinalize:function(){return this._process(!0)},blockSize:1}),p=n.mode={},f=a.BlockCipherMode=o.extend({createEncryptor:function(e,t){return this.Encryptor.create(e,t)},createDecryptor:function(e,t){return this.Decryptor.create(e,t)},init:function(e,t){this._cipher=e,this._iv=t}}),m=p.CBC=function(){var e=f.extend();function t(e,t,r){var i,n=this._iv;n?(i=n,this._iv=void 0):i=this._prevBlock;for(var a=0;a>>2];e.sigBytes-=t}},a.BlockCipher=d.extend({cfg:d.cfg.extend({mode:m,padding:g}),reset:function(){var e;d.reset.call(this);var t=this.cfg,r=t.iv,i=t.mode;this._xformMode==this._ENC_XFORM_MODE?e=i.createEncryptor:(e=i.createDecryptor,this._minBufferSize=1),this._mode&&this._mode.__creator==e?this._mode.init(this,r&&r.words):(this._mode=e.call(i,this,r&&r.words),this._mode.__creator=e)},_doProcessBlock:function(e,t){this._mode.processBlock(e,t)},_doFinalize:function(){var e,t=this.cfg.padding;return this._xformMode==this._ENC_XFORM_MODE?(t.pad(this._data,this.blockSize),e=this._process(!0)):(e=this._process(!0),t.unpad(e)),e},blockSize:4}),_=a.CipherParams=o.extend({init:function(e){this.mixIn(e)},toString:function(e){return(e||this.formatter).stringify(this)}}),v=(n.format={}).OpenSSL={stringify:function(e){var t=e.ciphertext,r=e.salt;return(r?s.create([1398893684,1701076831]).concat(r).concat(t):t).toString(l)},parse:function(e){var t,r=l.parse(e),i=r.words;return 1398893684==i[0]&&1701076831==i[1]&&(t=s.create(i.slice(2,4)),i.splice(0,4),r.sigBytes-=16),_.create({ciphertext:r,salt:t})}},y=a.SerializableCipher=o.extend({cfg:o.extend({format:v}),encrypt:function(e,t,r,i){i=this.cfg.extend(i);var n=e.createEncryptor(r,i),a=n.finalize(t),o=n.cfg;return _.create({ciphertext:a,key:r,iv:o.iv,algorithm:e,mode:o.mode,padding:o.padding,blockSize:e.blockSize,formatter:i.format})},decrypt:function(e,t,r,i){return i=this.cfg.extend(i),t=this._parse(t,i.format),e.createDecryptor(r,i).finalize(t.ciphertext)},_parse:function(e,t){return"string"==typeof e?t.parse(e,this):e}}),b=(n.kdf={}).OpenSSL={execute:function(e,t,r,i){i||(i=s.random(8));var n=h.create({keySize:t+r}).compute(e,i),a=s.create(n.words.slice(t),4*r);return n.sigBytes=4*t,_.create({key:n,iv:a,salt:i})}},E=a.PasswordBasedCipher=y.extend({cfg:y.cfg.extend({kdf:b}),encrypt:function(e,t,r,i){var n=(i=this.cfg.extend(i)).kdf.execute(r,e.keySize,e.ivSize);i.iv=n.iv;var a=y.encrypt.call(this,e,t,n.key,i);return a.mixIn(n),a},decrypt:function(e,t,r,i){i=this.cfg.extend(i),t=this._parse(t,i.format);var n=i.kdf.execute(r,e.keySize,e.ivSize,t.salt);return i.iv=n.iv,y.decrypt.call(this,e,t,n.key,i)}}))))},function(e,t,r){var i=r(9).Buffer,n={dsa:{parts:["p","q","g","y"],sizePart:"p"},rsa:{parts:["e","n"],sizePart:"n"},ecdsa:{parts:["curve","Q"],sizePart:"Q"},ed25519:{parts:["A"],sizePart:"A"}};n.curve25519=n.ed25519;var a={dsa:{parts:["p","q","g","y","x"]},rsa:{parts:["n","e","d","iqmp","p","q"]},ecdsa:{parts:["curve","Q","d"]},ed25519:{parts:["A","k"]}};a.curve25519=a.ed25519;var o={nistp256:{size:256,pkcs8oid:"1.2.840.10045.3.1.7",p:i.from("00ffffffff 00000001 00000000 0000000000000000 ffffffff ffffffff ffffffff".replace(/ /g,""),"hex"),a:i.from("00FFFFFFFF 00000001 00000000 0000000000000000 FFFFFFFF FFFFFFFF FFFFFFFC".replace(/ /g,""),"hex"),b:i.from("5ac635d8 aa3a93e7 b3ebbd55 769886bc651d06b0 cc53b0f6 3bce3c3e 27d2604b".replace(/ /g,""),"hex"),s:i.from("00c49d3608 86e70493 6a6678e1 139d26b7819f7e90".replace(/ /g,""),"hex"),n:i.from("00ffffffff 00000000 ffffffff ffffffffbce6faad a7179e84 f3b9cac2 fc632551".replace(/ /g,""),"hex"),G:i.from("046b17d1f2 e12c4247 f8bce6e5 63a440f277037d81 2deb33a0 f4a13945 d898c2964fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e162bce3357 6b315ece cbb64068 37bf51f5".replace(/ /g,""),"hex")},nistp384:{size:384,pkcs8oid:"1.3.132.0.34",p:i.from("00ffffffff ffffffff ffffffff ffffffffffffffff ffffffff ffffffff fffffffeffffffff 00000000 00000000 ffffffff".replace(/ /g,""),"hex"),a:i.from("00FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFEFFFFFFFF 00000000 00000000 FFFFFFFC".replace(/ /g,""),"hex"),b:i.from("b3312fa7 e23ee7e4 988e056b e3f82d19181d9c6e fe814112 0314088f 5013875ac656398d 8a2ed19d 2a85c8ed d3ec2aef".replace(/ /g,""),"hex"),s:i.from("00a335926a a319a27a 1d00896a 6773a4827acdac73".replace(/ /g,""),"hex"),n:i.from("00ffffffff ffffffff ffffffff ffffffffffffffff ffffffff c7634d81 f4372ddf581a0db2 48b0a77a ecec196a ccc52973".replace(/ /g,""),"hex"),G:i.from("04aa87ca22 be8b0537 8eb1c71e f320ad746e1d3b62 8ba79b98 59f741e0 82542a385502f25d bf55296c 3a545e38 72760ab73617de4a 96262c6f 5d9e98bf 9292dc29f8f41dbd 289a147c e9da3113 b5f0b8c00a60b1ce 1d7e819d 7a431d7c 90ea0e5f".replace(/ /g,""),"hex")},nistp521:{size:521,pkcs8oid:"1.3.132.0.35",p:i.from("01ffffff ffffffff ffffffff ffffffffffffffff ffffffff ffffffff ffffffffffffffff ffffffff ffffffff ffffffffffffffff ffffffff ffffffff ffffffffffff".replace(/ /g,""),"hex"),a:i.from("01FFFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFFFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFC".replace(/ /g,""),"hex"),b:i.from("51953eb961 8e1c9a1f 929a21a0 b68540eea2da725b 99b315f3 b8b48991 8ef109e156193951 ec7e937b 1652c0bd 3bb1bf073573df88 3d2c34f1 ef451fd4 6b503f00".replace(/ /g,""),"hex"),s:i.from("00d09e8800 291cb853 96cc6717 393284aaa0da64ba".replace(/ /g,""),"hex"),n:i.from("01ffffffffff ffffffff ffffffff ffffffffffffffff ffffffff ffffffff fffffffa51868783 bf2f966b 7fcc0148 f709a5d03bb5c9b8 899c47ae bb6fb71e 91386409".replace(/ /g,""),"hex"),G:i.from("0400c6 858e06b7 0404e9cd 9e3ecb66 2395b4429c648139 053fb521 f828af60 6b4d3dbaa14b5e77 efe75928 fe1dc127 a2ffa8de3348b3c1 856a429b f97e7e31 c2e5bd660118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd998f54449 579b4468 17afbd17 273e662c97ee7299 5ef42640 c550b901 3fad0761353c7086 a272c240 88be9476 9fd16650".replace(/ /g,""),"hex")}};e.exports={info:n,privInfo:a,hashAlgs:{md5:!0,sha1:!0,sha256:!0,sha384:!0,sha512:!0},curves:o}},function(e,t,r){e.exports=y;var i=r(6),n=r(9).Buffer,a=r(16),o=r(10),s=(r(66),r(30)),c=r(29),u=r(11),l=r(13),h=r(126),d=h.generateECDSA,p=h.generateED25519,f=r(226),m=r(68),g=r(14),_=(c.InvalidAlgorithmError,c.KeyParseError),v=(c.KeyEncryptedError,{});function y(e){i.object(e,"options"),g.call(this,e),this._pubCache=void 0}v.auto=r(227),v.pem=r(36),v.pkcs1=r(129),v.pkcs8=r(70),v.rfc4253=r(40),v["ssh-private"]=r(89),v.openssh=v["ssh-private"],v.ssh=v["ssh-private"],v.dnssec=r(130),u.inherits(y,g),y.formats=v,y.prototype.toBuffer=function(e,t){return void 0===e&&(e="pkcs1"),i.string(e,"format"),i.object(v[e],"formats[format]"),i.optionalObject(t,"options"),v[e].write(this,t)},y.prototype.hash=function(e){return this.toPublic().hash(e)},y.prototype.toPublic=function(){if(this._pubCache)return this._pubCache;for(var e=a.info[this.type],t=[],r=0;r(n>>1)-1?(n>>1)-c:c,a.isubn(s)):s=0,i[o]=s,a.iushrn(1)}return i},i.getJSF=function(e,t){var r=[[],[]];e=e.clone(),t=t.clone();for(var i=0,n=0;e.cmpn(-i)>0||t.cmpn(-n)>0;){var a,o,s,c=e.andln(3)+i&3,u=t.andln(3)+n&3;if(3===c&&(c=-1),3===u&&(u=-1),0==(1&c))a=0;else a=3!==(s=e.andln(7)+i&7)&&5!==s||2!==u?c:-c;if(r[0].push(a),0==(1&u))o=0;else o=3!==(s=t.andln(7)+n&7)&&5!==s||2!==c?u:-u;r[1].push(o),2*i===a+1&&(i=1-i),2*n===o+1&&(n=1-n),e.iushrn(1),t.iushrn(1)}return r},i.cachedProperty=function(e,t,r){var i="_"+t;e.prototype[t]=function(){return void 0!==this[i]?this[i]:this[i]=r.call(this)}},i.parseBytes=function(e){return"string"==typeof e?i.toArray(e,"hex"):e},i.intFromLE=function(e){return new n(e,"hex","le")}},function(e,t,r){(function(e){function r(e){return Object.prototype.toString.call(e)}t.isArray=function(e){return Array.isArray?Array.isArray(e):"[object Array]"===r(e)},t.isBoolean=function(e){return"boolean"==typeof e},t.isNull=function(e){return null===e},t.isNullOrUndefined=function(e){return null==e},t.isNumber=function(e){return"number"==typeof e},t.isString=function(e){return"string"==typeof e},t.isSymbol=function(e){return"symbol"==typeof e},t.isUndefined=function(e){return void 0===e},t.isRegExp=function(e){return"[object RegExp]"===r(e)},t.isObject=function(e){return"object"==typeof e&&null!==e},t.isDate=function(e){return"[object Date]"===r(e)},t.isError=function(e){return"[object Error]"===r(e)||e instanceof Error},t.isFunction=function(e){return"function"==typeof e},t.isPrimitive=function(e){return null===e||"boolean"==typeof e||"number"==typeof e||"string"==typeof e||"symbol"==typeof e||void 0===e},t.isBuffer=e.isBuffer}).call(this,r(2).Buffer)},function(e,t){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}},function(e,t,r){"use strict";var i,n="object"==typeof Reflect?Reflect:null,a=n&&"function"==typeof n.apply?n.apply:function(e,t,r){return Function.prototype.apply.call(e,t,r)};i=n&&"function"==typeof n.ownKeys?n.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};var o=Number.isNaN||function(e){return e!=e};function s(){s.init.call(this)}e.exports=s,s.EventEmitter=s,s.prototype._events=void 0,s.prototype._eventsCount=0,s.prototype._maxListeners=void 0;var c=10;function u(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function l(e){return void 0===e._maxListeners?s.defaultMaxListeners:e._maxListeners}function h(e,t,r,i){var n,a,o,s;if(u(r),void 0===(a=e._events)?(a=e._events=Object.create(null),e._eventsCount=0):(void 0!==a.newListener&&(e.emit("newListener",t,r.listener?r.listener:r),a=e._events),o=a[t]),void 0===o)o=a[t]=r,++e._eventsCount;else if("function"==typeof o?o=a[t]=i?[r,o]:[o,r]:i?o.unshift(r):o.push(r),(n=l(e))>0&&o.length>n&&!o.warned){o.warned=!0;var c=new Error("Possible EventEmitter memory leak detected. "+o.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");c.name="MaxListenersExceededWarning",c.emitter=e,c.type=t,c.count=o.length,s=c,console&&console.warn&&console.warn(s)}return e}function d(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function p(e,t,r){var i={fired:!1,wrapFn:void 0,target:e,type:t,listener:r},n=d.bind(i);return n.listener=r,i.wrapFn=n,n}function f(e,t,r){var i=e._events;if(void 0===i)return[];var n=i[t];return void 0===n?[]:"function"==typeof n?r?[n.listener||n]:[n]:r?function(e){for(var t=new Array(e.length),r=0;r0&&(o=t[0]),o instanceof Error)throw o;var s=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw s.context=o,s}var c=n[e];if(void 0===c)return!1;if("function"==typeof c)a(c,this,t);else{var u=c.length,l=g(c,u);for(r=0;r=0;a--)if(r[a]===t||r[a].listener===t){o=r[a].listener,n=a;break}if(n<0)return this;0===n?r.shift():function(e,t){for(;t+1=0;i--)this.removeListener(e,t[i]);return this},s.prototype.listeners=function(e){return f(this,e,!0)},s.prototype.rawListeners=function(e){return f(this,e,!1)},s.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):m.call(e,t)},s.prototype.listenerCount=m,s.prototype.eventNames=function(){return this._eventsCount>0?i(this._events):[]}},function(e,t,r){"use strict";var i=r(19),n=r(0);function a(e,t){return 55296==(64512&e.charCodeAt(t))&&(!(t<0||t+1>=e.length)&&56320==(64512&e.charCodeAt(t+1)))}function o(e){return(e>>>24|e>>>8&65280|e<<8&16711680|(255&e)<<24)>>>0}function s(e){return 1===e.length?"0"+e:e}function c(e){return 7===e.length?"0"+e:6===e.length?"00"+e:5===e.length?"000"+e:4===e.length?"0000"+e:3===e.length?"00000"+e:2===e.length?"000000"+e:1===e.length?"0000000"+e:e}t.inherits=n,t.toArray=function(e,t){if(Array.isArray(e))return e.slice();if(!e)return[];var r=[];if("string"==typeof e)if(t){if("hex"===t)for((e=e.replace(/[^a-z0-9]+/gi,"")).length%2!=0&&(e="0"+e),n=0;n>6|192,r[i++]=63&o|128):a(e,n)?(o=65536+((1023&o)<<10)+(1023&e.charCodeAt(++n)),r[i++]=o>>18|240,r[i++]=o>>12&63|128,r[i++]=o>>6&63|128,r[i++]=63&o|128):(r[i++]=o>>12|224,r[i++]=o>>6&63|128,r[i++]=63&o|128)}else for(n=0;n>>0}return o},t.split32=function(e,t){for(var r=new Array(4*e.length),i=0,n=0;i>>24,r[n+1]=a>>>16&255,r[n+2]=a>>>8&255,r[n+3]=255&a):(r[n+3]=a>>>24,r[n+2]=a>>>16&255,r[n+1]=a>>>8&255,r[n]=255&a)}return r},t.rotr32=function(e,t){return e>>>t|e<<32-t},t.rotl32=function(e,t){return e<>>32-t},t.sum32=function(e,t){return e+t>>>0},t.sum32_3=function(e,t,r){return e+t+r>>>0},t.sum32_4=function(e,t,r,i){return e+t+r+i>>>0},t.sum32_5=function(e,t,r,i,n){return e+t+r+i+n>>>0},t.sum64=function(e,t,r,i){var n=e[t],a=i+e[t+1]>>>0,o=(a>>0,e[t+1]=a},t.sum64_hi=function(e,t,r,i){return(t+i>>>0>>0},t.sum64_lo=function(e,t,r,i){return t+i>>>0},t.sum64_4_hi=function(e,t,r,i,n,a,o,s){var c=0,u=t;return c+=(u=u+i>>>0)>>0)>>0)>>0},t.sum64_4_lo=function(e,t,r,i,n,a,o,s){return t+i+a+s>>>0},t.sum64_5_hi=function(e,t,r,i,n,a,o,s,c,u){var l=0,h=t;return l+=(h=h+i>>>0)>>0)>>0)>>0)>>0},t.sum64_5_lo=function(e,t,r,i,n,a,o,s,c,u){return t+i+a+s+u>>>0},t.rotr64_hi=function(e,t,r){return(t<<32-r|e>>>r)>>>0},t.rotr64_lo=function(e,t,r){return(e<<32-r|t>>>r)>>>0},t.shr64_hi=function(e,t,r){return e>>>r},t.shr64_lo=function(e,t,r){return(e<<32-r|t>>>r)>>>0}},function(e,t,r){"use strict";var i=r(123),n=r(394);function a(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}t.parse=y,t.resolve=function(e,t){return y(e,!1,!0).resolve(t)},t.resolveObject=function(e,t){return e?y(e,!1,!0).resolveObject(t):t},t.format=function(e){n.isString(e)&&(e=y(e));return e instanceof a?e.format():a.prototype.format.call(e)},t.Url=a;var o=/^([a-z0-9.+-]+:)/i,s=/:[0-9]*$/,c=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,u=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),l=["'"].concat(u),h=["%","/","?",";","#"].concat(l),d=["/","?","#"],p=/^[+a-z0-9A-Z_-]{0,63}$/,f=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,m={javascript:!0,"javascript:":!0},g={javascript:!0,"javascript:":!0},_={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},v=r(84);function y(e,t,r){if(e&&n.isObject(e)&&e instanceof a)return e;var i=new a;return i.parse(e,t,r),i}a.prototype.parse=function(e,t,r){if(!n.isString(e))throw new TypeError("Parameter 'url' must be a string, not "+typeof e);var a=e.indexOf("?"),s=-1!==a&&a127?A+="x":A+=O[P];if(!A.match(p)){var F=R.slice(0,N),C=R.slice(N+1),B=O.match(f);B&&(F.push(B[1]),C.unshift(B[2])),C.length&&(y="/"+C.join(".")+y),this.hostname=F.join(".");break}}}this.hostname.length>255?this.hostname="":this.hostname=this.hostname.toLowerCase(),T||(this.hostname=i.toASCII(this.hostname));var z=this.port?":"+this.port:"",L=this.hostname||"";this.host=L+z,this.href+=this.host,T&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==y[0]&&(y="/"+y))}if(!m[w])for(N=0,I=l.length;N0)&&r.host.split("@"))&&(r.auth=T.shift(),r.host=r.hostname=T.shift());return r.search=e.search,r.query=e.query,n.isNull(r.pathname)&&n.isNull(r.search)||(r.path=(r.pathname?r.pathname:"")+(r.search?r.search:"")),r.href=r.format(),r}if(!S.length)return r.pathname=null,r.search?r.path="/"+r.search:r.path=null,r.href=r.format(),r;for(var x=S.slice(-1)[0],M=(r.host||e.host||S.length>1)&&("."===x||".."===x)||""===x,N=0,j=S.length;j>=0;j--)"."===(x=S[j])?S.splice(j,1):".."===x?(S.splice(j,1),N++):N&&(S.splice(j,1),N--);if(!E&&!w)for(;N--;N)S.unshift("..");!E||""===S[0]||S[0]&&"/"===S[0].charAt(0)||S.unshift(""),M&&"/"!==S.join("/").substr(-1)&&S.push("");var T,R=""===S[0]||S[0]&&"/"===S[0].charAt(0);k&&(r.hostname=r.host=R?"":S.length?S.shift():"",(T=!!(r.host&&r.host.indexOf("@")>0)&&r.host.split("@"))&&(r.auth=T.shift(),r.host=r.hostname=T.shift()));return(E=E||r.host&&S.length)&&!R&&S.unshift(""),S.length?r.pathname=S.join("/"):(r.pathname=null,r.path=null),n.isNull(r.pathname)&&n.isNull(r.search)||(r.path=(r.pathname?r.pathname:"")+(r.search?r.search:"")),r.auth=e.auth||r.auth,r.slashes=r.slashes||e.slashes,r.href=r.format(),r},a.prototype.parseHost=function(){var e=this.host,t=s.exec(e);t&&(":"!==(t=t[0])&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)}},function(e,t,r){"use strict";var i=r(279).Buffer,n=i.isEncoding||function(e){switch((e=""+e)&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function a(e){var t;switch(this.encoding=function(e){var t=function(e){if(!e)return"utf8";for(var t;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(t)return;e=(""+e).toLowerCase(),t=!0}}(e);if("string"!=typeof t&&(i.isEncoding===n||!n(e)))throw new Error("Unknown encoding: "+e);return t||e}(e),this.encoding){case"utf16le":this.text=c,this.end=u,t=4;break;case"utf8":this.fillLast=s,t=4;break;case"base64":this.text=l,this.end=h,t=3;break;default:return this.write=d,void(this.end=p)}this.lastNeed=0,this.lastTotal=0,this.lastChar=i.allocUnsafe(t)}function o(e){return e<=127?0:e>>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function s(e){var t=this.lastTotal-this.lastNeed,r=function(e,t,r){if(128!=(192&t[0]))return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if(128!=(192&t[1]))return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&128!=(192&t[2]))return e.lastNeed=2,"�"}}(this,e);return void 0!==r?r:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(e.copy(this.lastChar,t,0,e.length),void(this.lastNeed-=e.length))}function c(e,t){if((e.length-t)%2==0){var r=e.toString("utf16le",t);if(r){var i=r.charCodeAt(r.length-1);if(i>=55296&&i<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],r.slice(0,-1)}return r}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function u(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var r=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,r)}return t}function l(e,t){var r=(e.length-t)%3;return 0===r?e.toString("base64",t):(this.lastNeed=3-r,this.lastTotal=3,1===r?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-r))}function h(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function d(e){return e.toString(this.encoding)}function p(e){return e&&e.length?this.write(e):""}t.StringDecoder=a,a.prototype.write=function(e){if(0===e.length)return"";var t,r;if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";r=this.lastNeed,this.lastNeed=0}else r=0;return r=0)return n>0&&(e.lastNeed=n-1),n;if(--i=0)return n>0&&(e.lastNeed=n-2),n;if(--i=0)return n>0&&(2===n?n=0:e.lastNeed=n-3),n;return 0}(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=r;var i=e.length-(r-this.lastNeed);return e.copy(this.lastChar,0,i),e.toString("utf8",t,i)},a.prototype.fillLast=function(e){if(this.lastNeed<=e.length)return e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,e.length),this.lastNeed-=e.length}},function(e,t,r){(function(e){!function(e,t){"use strict";function i(e,t){if(!e)throw new Error(t||"Assertion failed")}function n(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}function a(e,t,r){if(a.isBN(e))return e;this.negative=0,this.words=null,this.length=0,this.red=null,null!==e&&("le"!==t&&"be"!==t||(r=t,t=10),this._init(e||0,t||10,r||"be"))}var o;"object"==typeof e?e.exports=a:t.BN=a,a.BN=a,a.wordSize=26;try{o=r(334).Buffer}catch(e){}function s(e,t,r){for(var i=0,n=Math.min(e.length,r),a=t;a=49&&o<=54?o-49+10:o>=17&&o<=22?o-17+10:15&o}return i}function c(e,t,r,i){for(var n=0,a=Math.min(e.length,r),o=t;o=49?s-49+10:s>=17?s-17+10:s}return n}a.isBN=function(e){return e instanceof a||null!==e&&"object"==typeof e&&e.constructor.wordSize===a.wordSize&&Array.isArray(e.words)},a.max=function(e,t){return e.cmp(t)>0?e:t},a.min=function(e,t){return e.cmp(t)<0?e:t},a.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),i(t===(0|t)&&t>=2&&t<=36);var n=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&n++,16===t?this._parseHex(e,n):this._parseBase(e,t,n),"-"===e[0]&&(this.negative=1),this.strip(),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(i(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initArray=function(e,t,r){if(i("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var n=0;n=0;n-=3)o=e[n]|e[n-1]<<8|e[n-2]<<16,this.words[a]|=o<>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);else if("le"===r)for(n=0,a=0;n>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);return this.strip()},a.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)n=s(e,r,r+6),this.words[i]|=n<>>26-a&4194303,(a+=24)>=26&&(a-=26,i++);r+6!==t&&(n=s(e,t,r+6),this.words[i]|=n<>>26-a&4194303),this.strip()},a.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var i=0,n=1;n<=67108863;n*=t)i++;i--,n=n/t|0;for(var a=e.length-r,o=a%i,s=Math.min(a,a-o)+r,u=0,l=r;l1&&0===this.words[this.length-1];)this.length--;return this._normSign()},a.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},a.prototype.inspect=function(){return(this.red?""};var u=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],l=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],h=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];function d(e,t,r){r.negative=t.negative^e.negative;var i=e.length+t.length|0;r.length=i,i=i-1|0;var n=0|e.words[0],a=0|t.words[0],o=n*a,s=67108863&o,c=o/67108864|0;r.words[0]=s;for(var u=1;u>>26,h=67108863&c,d=Math.min(u,t.length-1),p=Math.max(0,u-e.length+1);p<=d;p++){var f=u-p|0;l+=(o=(n=0|e.words[f])*(a=0|t.words[p])+h)/67108864|0,h=67108863&o}r.words[u]=0|h,c=0|l}return 0!==c?r.words[u]=0|c:r.length--,r.strip()}a.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var n=0,a=0,o=0;o>>24-n&16777215)||o!==this.length-1?u[6-c.length]+c+r:c+r,(n+=2)>=26&&(n-=26,o--)}for(0!==a&&(r=a.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var d=l[e],p=h[e];r="";var f=this.clone();for(f.negative=0;!f.isZero();){var m=f.modn(p).toString(e);r=(f=f.idivn(p)).isZero()?m+r:u[d-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}i(!1,"Base should be between 2 and 36")},a.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&i(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},a.prototype.toJSON=function(){return this.toString(16)},a.prototype.toBuffer=function(e,t){return i(void 0!==o),this.toArrayLike(o,e,t)},a.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)},a.prototype.toArrayLike=function(e,t,r){var n=this.byteLength(),a=r||Math.max(1,n);i(n<=a,"byte array longer than desired length"),i(a>0,"Requested array length <= 0"),this.strip();var o,s,c="le"===t,u=new e(a),l=this.clone();if(c){for(s=0;!l.isZero();s++)o=l.andln(255),l.iushrn(8),u[s]=o;for(;s=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},a.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},a.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},a.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},a.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},a.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},a.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},a.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var i=0;ie.length?this.clone().ixor(e):e.clone().ixor(this)},a.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},a.prototype.inotn=function(e){i("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var n=0;n0&&(this.words[n]=~this.words[n]&67108863>>26-r),this.strip()},a.prototype.notn=function(e){return this.clone().inotn(e)},a.prototype.setn=function(e,t){i("number"==typeof e&&e>=0);var r=e/26|0,n=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,i=e):(r=e,i=this);for(var n=0,a=0;a>>26;for(;0!==n&&a>>26;if(this.length=r.length,0!==n)this.words[this.length]=n,this.length++;else if(r!==this)for(;ae.length?this.clone().iadd(e):e.clone().iadd(this)},a.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,i,n=this.cmp(e);if(0===n)return this.negative=0,this.length=1,this.words[0]=0,this;n>0?(r=this,i=e):(r=e,i=this);for(var a=0,o=0;o>26,this.words[o]=67108863&t;for(;0!==a&&o>26,this.words[o]=67108863&t;if(0===a&&o>>13,p=0|o[1],f=8191&p,m=p>>>13,g=0|o[2],_=8191&g,v=g>>>13,y=0|o[3],b=8191&y,E=y>>>13,w=0|o[4],S=8191&w,k=w>>>13,x=0|o[5],M=8191&x,N=x>>>13,j=0|o[6],T=8191&j,R=j>>>13,I=0|o[7],O=8191&I,A=I>>>13,P=0|o[8],D=8191&P,F=P>>>13,C=0|o[9],B=8191&C,z=C>>>13,L=0|s[0],U=8191&L,H=L>>>13,q=0|s[1],K=8191&q,Z=q>>>13,W=0|s[2],X=8191&W,Q=W>>>13,J=0|s[3],V=8191&J,G=J>>>13,Y=0|s[4],$=8191&Y,ee=Y>>>13,te=0|s[5],re=8191&te,ie=te>>>13,ne=0|s[6],ae=8191&ne,oe=ne>>>13,se=0|s[7],ce=8191&se,ue=se>>>13,le=0|s[8],he=8191&le,de=le>>>13,pe=0|s[9],fe=8191&pe,me=pe>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(u+(i=Math.imul(h,U))|0)+((8191&(n=(n=Math.imul(h,H))+Math.imul(d,U)|0))<<13)|0;u=((a=Math.imul(d,H))+(n>>>13)|0)+(ge>>>26)|0,ge&=67108863,i=Math.imul(f,U),n=(n=Math.imul(f,H))+Math.imul(m,U)|0,a=Math.imul(m,H);var _e=(u+(i=i+Math.imul(h,K)|0)|0)+((8191&(n=(n=n+Math.imul(h,Z)|0)+Math.imul(d,K)|0))<<13)|0;u=((a=a+Math.imul(d,Z)|0)+(n>>>13)|0)+(_e>>>26)|0,_e&=67108863,i=Math.imul(_,U),n=(n=Math.imul(_,H))+Math.imul(v,U)|0,a=Math.imul(v,H),i=i+Math.imul(f,K)|0,n=(n=n+Math.imul(f,Z)|0)+Math.imul(m,K)|0,a=a+Math.imul(m,Z)|0;var ve=(u+(i=i+Math.imul(h,X)|0)|0)+((8191&(n=(n=n+Math.imul(h,Q)|0)+Math.imul(d,X)|0))<<13)|0;u=((a=a+Math.imul(d,Q)|0)+(n>>>13)|0)+(ve>>>26)|0,ve&=67108863,i=Math.imul(b,U),n=(n=Math.imul(b,H))+Math.imul(E,U)|0,a=Math.imul(E,H),i=i+Math.imul(_,K)|0,n=(n=n+Math.imul(_,Z)|0)+Math.imul(v,K)|0,a=a+Math.imul(v,Z)|0,i=i+Math.imul(f,X)|0,n=(n=n+Math.imul(f,Q)|0)+Math.imul(m,X)|0,a=a+Math.imul(m,Q)|0;var ye=(u+(i=i+Math.imul(h,V)|0)|0)+((8191&(n=(n=n+Math.imul(h,G)|0)+Math.imul(d,V)|0))<<13)|0;u=((a=a+Math.imul(d,G)|0)+(n>>>13)|0)+(ye>>>26)|0,ye&=67108863,i=Math.imul(S,U),n=(n=Math.imul(S,H))+Math.imul(k,U)|0,a=Math.imul(k,H),i=i+Math.imul(b,K)|0,n=(n=n+Math.imul(b,Z)|0)+Math.imul(E,K)|0,a=a+Math.imul(E,Z)|0,i=i+Math.imul(_,X)|0,n=(n=n+Math.imul(_,Q)|0)+Math.imul(v,X)|0,a=a+Math.imul(v,Q)|0,i=i+Math.imul(f,V)|0,n=(n=n+Math.imul(f,G)|0)+Math.imul(m,V)|0,a=a+Math.imul(m,G)|0;var be=(u+(i=i+Math.imul(h,$)|0)|0)+((8191&(n=(n=n+Math.imul(h,ee)|0)+Math.imul(d,$)|0))<<13)|0;u=((a=a+Math.imul(d,ee)|0)+(n>>>13)|0)+(be>>>26)|0,be&=67108863,i=Math.imul(M,U),n=(n=Math.imul(M,H))+Math.imul(N,U)|0,a=Math.imul(N,H),i=i+Math.imul(S,K)|0,n=(n=n+Math.imul(S,Z)|0)+Math.imul(k,K)|0,a=a+Math.imul(k,Z)|0,i=i+Math.imul(b,X)|0,n=(n=n+Math.imul(b,Q)|0)+Math.imul(E,X)|0,a=a+Math.imul(E,Q)|0,i=i+Math.imul(_,V)|0,n=(n=n+Math.imul(_,G)|0)+Math.imul(v,V)|0,a=a+Math.imul(v,G)|0,i=i+Math.imul(f,$)|0,n=(n=n+Math.imul(f,ee)|0)+Math.imul(m,$)|0,a=a+Math.imul(m,ee)|0;var Ee=(u+(i=i+Math.imul(h,re)|0)|0)+((8191&(n=(n=n+Math.imul(h,ie)|0)+Math.imul(d,re)|0))<<13)|0;u=((a=a+Math.imul(d,ie)|0)+(n>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,i=Math.imul(T,U),n=(n=Math.imul(T,H))+Math.imul(R,U)|0,a=Math.imul(R,H),i=i+Math.imul(M,K)|0,n=(n=n+Math.imul(M,Z)|0)+Math.imul(N,K)|0,a=a+Math.imul(N,Z)|0,i=i+Math.imul(S,X)|0,n=(n=n+Math.imul(S,Q)|0)+Math.imul(k,X)|0,a=a+Math.imul(k,Q)|0,i=i+Math.imul(b,V)|0,n=(n=n+Math.imul(b,G)|0)+Math.imul(E,V)|0,a=a+Math.imul(E,G)|0,i=i+Math.imul(_,$)|0,n=(n=n+Math.imul(_,ee)|0)+Math.imul(v,$)|0,a=a+Math.imul(v,ee)|0,i=i+Math.imul(f,re)|0,n=(n=n+Math.imul(f,ie)|0)+Math.imul(m,re)|0,a=a+Math.imul(m,ie)|0;var we=(u+(i=i+Math.imul(h,ae)|0)|0)+((8191&(n=(n=n+Math.imul(h,oe)|0)+Math.imul(d,ae)|0))<<13)|0;u=((a=a+Math.imul(d,oe)|0)+(n>>>13)|0)+(we>>>26)|0,we&=67108863,i=Math.imul(O,U),n=(n=Math.imul(O,H))+Math.imul(A,U)|0,a=Math.imul(A,H),i=i+Math.imul(T,K)|0,n=(n=n+Math.imul(T,Z)|0)+Math.imul(R,K)|0,a=a+Math.imul(R,Z)|0,i=i+Math.imul(M,X)|0,n=(n=n+Math.imul(M,Q)|0)+Math.imul(N,X)|0,a=a+Math.imul(N,Q)|0,i=i+Math.imul(S,V)|0,n=(n=n+Math.imul(S,G)|0)+Math.imul(k,V)|0,a=a+Math.imul(k,G)|0,i=i+Math.imul(b,$)|0,n=(n=n+Math.imul(b,ee)|0)+Math.imul(E,$)|0,a=a+Math.imul(E,ee)|0,i=i+Math.imul(_,re)|0,n=(n=n+Math.imul(_,ie)|0)+Math.imul(v,re)|0,a=a+Math.imul(v,ie)|0,i=i+Math.imul(f,ae)|0,n=(n=n+Math.imul(f,oe)|0)+Math.imul(m,ae)|0,a=a+Math.imul(m,oe)|0;var Se=(u+(i=i+Math.imul(h,ce)|0)|0)+((8191&(n=(n=n+Math.imul(h,ue)|0)+Math.imul(d,ce)|0))<<13)|0;u=((a=a+Math.imul(d,ue)|0)+(n>>>13)|0)+(Se>>>26)|0,Se&=67108863,i=Math.imul(D,U),n=(n=Math.imul(D,H))+Math.imul(F,U)|0,a=Math.imul(F,H),i=i+Math.imul(O,K)|0,n=(n=n+Math.imul(O,Z)|0)+Math.imul(A,K)|0,a=a+Math.imul(A,Z)|0,i=i+Math.imul(T,X)|0,n=(n=n+Math.imul(T,Q)|0)+Math.imul(R,X)|0,a=a+Math.imul(R,Q)|0,i=i+Math.imul(M,V)|0,n=(n=n+Math.imul(M,G)|0)+Math.imul(N,V)|0,a=a+Math.imul(N,G)|0,i=i+Math.imul(S,$)|0,n=(n=n+Math.imul(S,ee)|0)+Math.imul(k,$)|0,a=a+Math.imul(k,ee)|0,i=i+Math.imul(b,re)|0,n=(n=n+Math.imul(b,ie)|0)+Math.imul(E,re)|0,a=a+Math.imul(E,ie)|0,i=i+Math.imul(_,ae)|0,n=(n=n+Math.imul(_,oe)|0)+Math.imul(v,ae)|0,a=a+Math.imul(v,oe)|0,i=i+Math.imul(f,ce)|0,n=(n=n+Math.imul(f,ue)|0)+Math.imul(m,ce)|0,a=a+Math.imul(m,ue)|0;var ke=(u+(i=i+Math.imul(h,he)|0)|0)+((8191&(n=(n=n+Math.imul(h,de)|0)+Math.imul(d,he)|0))<<13)|0;u=((a=a+Math.imul(d,de)|0)+(n>>>13)|0)+(ke>>>26)|0,ke&=67108863,i=Math.imul(B,U),n=(n=Math.imul(B,H))+Math.imul(z,U)|0,a=Math.imul(z,H),i=i+Math.imul(D,K)|0,n=(n=n+Math.imul(D,Z)|0)+Math.imul(F,K)|0,a=a+Math.imul(F,Z)|0,i=i+Math.imul(O,X)|0,n=(n=n+Math.imul(O,Q)|0)+Math.imul(A,X)|0,a=a+Math.imul(A,Q)|0,i=i+Math.imul(T,V)|0,n=(n=n+Math.imul(T,G)|0)+Math.imul(R,V)|0,a=a+Math.imul(R,G)|0,i=i+Math.imul(M,$)|0,n=(n=n+Math.imul(M,ee)|0)+Math.imul(N,$)|0,a=a+Math.imul(N,ee)|0,i=i+Math.imul(S,re)|0,n=(n=n+Math.imul(S,ie)|0)+Math.imul(k,re)|0,a=a+Math.imul(k,ie)|0,i=i+Math.imul(b,ae)|0,n=(n=n+Math.imul(b,oe)|0)+Math.imul(E,ae)|0,a=a+Math.imul(E,oe)|0,i=i+Math.imul(_,ce)|0,n=(n=n+Math.imul(_,ue)|0)+Math.imul(v,ce)|0,a=a+Math.imul(v,ue)|0,i=i+Math.imul(f,he)|0,n=(n=n+Math.imul(f,de)|0)+Math.imul(m,he)|0,a=a+Math.imul(m,de)|0;var xe=(u+(i=i+Math.imul(h,fe)|0)|0)+((8191&(n=(n=n+Math.imul(h,me)|0)+Math.imul(d,fe)|0))<<13)|0;u=((a=a+Math.imul(d,me)|0)+(n>>>13)|0)+(xe>>>26)|0,xe&=67108863,i=Math.imul(B,K),n=(n=Math.imul(B,Z))+Math.imul(z,K)|0,a=Math.imul(z,Z),i=i+Math.imul(D,X)|0,n=(n=n+Math.imul(D,Q)|0)+Math.imul(F,X)|0,a=a+Math.imul(F,Q)|0,i=i+Math.imul(O,V)|0,n=(n=n+Math.imul(O,G)|0)+Math.imul(A,V)|0,a=a+Math.imul(A,G)|0,i=i+Math.imul(T,$)|0,n=(n=n+Math.imul(T,ee)|0)+Math.imul(R,$)|0,a=a+Math.imul(R,ee)|0,i=i+Math.imul(M,re)|0,n=(n=n+Math.imul(M,ie)|0)+Math.imul(N,re)|0,a=a+Math.imul(N,ie)|0,i=i+Math.imul(S,ae)|0,n=(n=n+Math.imul(S,oe)|0)+Math.imul(k,ae)|0,a=a+Math.imul(k,oe)|0,i=i+Math.imul(b,ce)|0,n=(n=n+Math.imul(b,ue)|0)+Math.imul(E,ce)|0,a=a+Math.imul(E,ue)|0,i=i+Math.imul(_,he)|0,n=(n=n+Math.imul(_,de)|0)+Math.imul(v,he)|0,a=a+Math.imul(v,de)|0;var Me=(u+(i=i+Math.imul(f,fe)|0)|0)+((8191&(n=(n=n+Math.imul(f,me)|0)+Math.imul(m,fe)|0))<<13)|0;u=((a=a+Math.imul(m,me)|0)+(n>>>13)|0)+(Me>>>26)|0,Me&=67108863,i=Math.imul(B,X),n=(n=Math.imul(B,Q))+Math.imul(z,X)|0,a=Math.imul(z,Q),i=i+Math.imul(D,V)|0,n=(n=n+Math.imul(D,G)|0)+Math.imul(F,V)|0,a=a+Math.imul(F,G)|0,i=i+Math.imul(O,$)|0,n=(n=n+Math.imul(O,ee)|0)+Math.imul(A,$)|0,a=a+Math.imul(A,ee)|0,i=i+Math.imul(T,re)|0,n=(n=n+Math.imul(T,ie)|0)+Math.imul(R,re)|0,a=a+Math.imul(R,ie)|0,i=i+Math.imul(M,ae)|0,n=(n=n+Math.imul(M,oe)|0)+Math.imul(N,ae)|0,a=a+Math.imul(N,oe)|0,i=i+Math.imul(S,ce)|0,n=(n=n+Math.imul(S,ue)|0)+Math.imul(k,ce)|0,a=a+Math.imul(k,ue)|0,i=i+Math.imul(b,he)|0,n=(n=n+Math.imul(b,de)|0)+Math.imul(E,he)|0,a=a+Math.imul(E,de)|0;var Ne=(u+(i=i+Math.imul(_,fe)|0)|0)+((8191&(n=(n=n+Math.imul(_,me)|0)+Math.imul(v,fe)|0))<<13)|0;u=((a=a+Math.imul(v,me)|0)+(n>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,i=Math.imul(B,V),n=(n=Math.imul(B,G))+Math.imul(z,V)|0,a=Math.imul(z,G),i=i+Math.imul(D,$)|0,n=(n=n+Math.imul(D,ee)|0)+Math.imul(F,$)|0,a=a+Math.imul(F,ee)|0,i=i+Math.imul(O,re)|0,n=(n=n+Math.imul(O,ie)|0)+Math.imul(A,re)|0,a=a+Math.imul(A,ie)|0,i=i+Math.imul(T,ae)|0,n=(n=n+Math.imul(T,oe)|0)+Math.imul(R,ae)|0,a=a+Math.imul(R,oe)|0,i=i+Math.imul(M,ce)|0,n=(n=n+Math.imul(M,ue)|0)+Math.imul(N,ce)|0,a=a+Math.imul(N,ue)|0,i=i+Math.imul(S,he)|0,n=(n=n+Math.imul(S,de)|0)+Math.imul(k,he)|0,a=a+Math.imul(k,de)|0;var je=(u+(i=i+Math.imul(b,fe)|0)|0)+((8191&(n=(n=n+Math.imul(b,me)|0)+Math.imul(E,fe)|0))<<13)|0;u=((a=a+Math.imul(E,me)|0)+(n>>>13)|0)+(je>>>26)|0,je&=67108863,i=Math.imul(B,$),n=(n=Math.imul(B,ee))+Math.imul(z,$)|0,a=Math.imul(z,ee),i=i+Math.imul(D,re)|0,n=(n=n+Math.imul(D,ie)|0)+Math.imul(F,re)|0,a=a+Math.imul(F,ie)|0,i=i+Math.imul(O,ae)|0,n=(n=n+Math.imul(O,oe)|0)+Math.imul(A,ae)|0,a=a+Math.imul(A,oe)|0,i=i+Math.imul(T,ce)|0,n=(n=n+Math.imul(T,ue)|0)+Math.imul(R,ce)|0,a=a+Math.imul(R,ue)|0,i=i+Math.imul(M,he)|0,n=(n=n+Math.imul(M,de)|0)+Math.imul(N,he)|0,a=a+Math.imul(N,de)|0;var Te=(u+(i=i+Math.imul(S,fe)|0)|0)+((8191&(n=(n=n+Math.imul(S,me)|0)+Math.imul(k,fe)|0))<<13)|0;u=((a=a+Math.imul(k,me)|0)+(n>>>13)|0)+(Te>>>26)|0,Te&=67108863,i=Math.imul(B,re),n=(n=Math.imul(B,ie))+Math.imul(z,re)|0,a=Math.imul(z,ie),i=i+Math.imul(D,ae)|0,n=(n=n+Math.imul(D,oe)|0)+Math.imul(F,ae)|0,a=a+Math.imul(F,oe)|0,i=i+Math.imul(O,ce)|0,n=(n=n+Math.imul(O,ue)|0)+Math.imul(A,ce)|0,a=a+Math.imul(A,ue)|0,i=i+Math.imul(T,he)|0,n=(n=n+Math.imul(T,de)|0)+Math.imul(R,he)|0,a=a+Math.imul(R,de)|0;var Re=(u+(i=i+Math.imul(M,fe)|0)|0)+((8191&(n=(n=n+Math.imul(M,me)|0)+Math.imul(N,fe)|0))<<13)|0;u=((a=a+Math.imul(N,me)|0)+(n>>>13)|0)+(Re>>>26)|0,Re&=67108863,i=Math.imul(B,ae),n=(n=Math.imul(B,oe))+Math.imul(z,ae)|0,a=Math.imul(z,oe),i=i+Math.imul(D,ce)|0,n=(n=n+Math.imul(D,ue)|0)+Math.imul(F,ce)|0,a=a+Math.imul(F,ue)|0,i=i+Math.imul(O,he)|0,n=(n=n+Math.imul(O,de)|0)+Math.imul(A,he)|0,a=a+Math.imul(A,de)|0;var Ie=(u+(i=i+Math.imul(T,fe)|0)|0)+((8191&(n=(n=n+Math.imul(T,me)|0)+Math.imul(R,fe)|0))<<13)|0;u=((a=a+Math.imul(R,me)|0)+(n>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,i=Math.imul(B,ce),n=(n=Math.imul(B,ue))+Math.imul(z,ce)|0,a=Math.imul(z,ue),i=i+Math.imul(D,he)|0,n=(n=n+Math.imul(D,de)|0)+Math.imul(F,he)|0,a=a+Math.imul(F,de)|0;var Oe=(u+(i=i+Math.imul(O,fe)|0)|0)+((8191&(n=(n=n+Math.imul(O,me)|0)+Math.imul(A,fe)|0))<<13)|0;u=((a=a+Math.imul(A,me)|0)+(n>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,i=Math.imul(B,he),n=(n=Math.imul(B,de))+Math.imul(z,he)|0,a=Math.imul(z,de);var Ae=(u+(i=i+Math.imul(D,fe)|0)|0)+((8191&(n=(n=n+Math.imul(D,me)|0)+Math.imul(F,fe)|0))<<13)|0;u=((a=a+Math.imul(F,me)|0)+(n>>>13)|0)+(Ae>>>26)|0,Ae&=67108863;var Pe=(u+(i=Math.imul(B,fe))|0)+((8191&(n=(n=Math.imul(B,me))+Math.imul(z,fe)|0))<<13)|0;return u=((a=Math.imul(z,me))+(n>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,c[0]=ge,c[1]=_e,c[2]=ve,c[3]=ye,c[4]=be,c[5]=Ee,c[6]=we,c[7]=Se,c[8]=ke,c[9]=xe,c[10]=Me,c[11]=Ne,c[12]=je,c[13]=Te,c[14]=Re,c[15]=Ie,c[16]=Oe,c[17]=Ae,c[18]=Pe,0!==u&&(c[19]=u,r.length++),r};function f(e,t,r){return(new m).mulp(e,t,r)}function m(e,t){this.x=e,this.y=t}Math.imul||(p=d),a.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?p(this,e,t):r<63?d(this,e,t):r<1024?function(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var i=0,n=0,a=0;a>>26)|0)>>>26,o&=67108863}r.words[a]=s,i=o,o=n}return 0!==i?r.words[a]=i:r.length--,r.strip()}(this,e,t):f(this,e,t)},m.prototype.makeRBT=function(e){for(var t=new Array(e),r=a.prototype._countBits(e)-1,i=0;i>=1;return i},m.prototype.permute=function(e,t,r,i,n,a){for(var o=0;o>>=1)n++;return 1<>>=13,r[2*o+1]=8191&a,a>>>=13;for(o=2*t;o>=26,t+=n/67108864|0,t+=a>>>26,this.words[r]=67108863&a}return 0!==t&&(this.words[r]=t,this.length++),this},a.prototype.muln=function(e){return this.clone().imuln(e)},a.prototype.sqr=function(){return this.mul(this)},a.prototype.isqr=function(){return this.imul(this.clone())},a.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>n}return t}(e);if(0===t.length)return new a(1);for(var r=this,i=0;i=0);var t,r=e%26,n=(e-r)/26,a=67108863>>>26-r<<26-r;if(0!==r){var o=0;for(t=0;t>>26-r}o&&(this.words[t]=o,this.length++)}if(0!==n){for(t=this.length-1;t>=0;t--)this.words[t+n]=this.words[t];for(t=0;t=0),n=t?(t-t%26)/26:0;var a=e%26,o=Math.min((e-a)/26,this.length),s=67108863^67108863>>>a<o)for(this.length-=o,u=0;u=0&&(0!==l||u>=n);u--){var h=0|this.words[u];this.words[u]=l<<26-a|h>>>a,l=h&s}return c&&0!==l&&(c.words[c.length++]=l),0===this.length&&(this.words[0]=0,this.length=1),this.strip()},a.prototype.ishrn=function(e,t,r){return i(0===this.negative),this.iushrn(e,t,r)},a.prototype.shln=function(e){return this.clone().ishln(e)},a.prototype.ushln=function(e){return this.clone().iushln(e)},a.prototype.shrn=function(e){return this.clone().ishrn(e)},a.prototype.ushrn=function(e){return this.clone().iushrn(e)},a.prototype.testn=function(e){i("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,n=1<=0);var t=e%26,r=(e-t)/26;if(i(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var n=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},a.prototype.isubn=function(e){if(i("number"==typeof e),i(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(c/67108864|0),this.words[n+r]=67108863&a}for(;n>26,this.words[n+r]=67108863&a;if(0===s)return this.strip();for(i(-1===s),s=0,n=0;n>26,this.words[n]=67108863&a;return this.negative=1,this.strip()},a.prototype._wordDiv=function(e,t){var r=(this.length,e.length),i=this.clone(),n=e,o=0|n.words[n.length-1];0!==(r=26-this._countBits(o))&&(n=n.ushln(r),i.iushln(r),o=0|n.words[n.length-1]);var s,c=i.length-n.length;if("mod"!==t){(s=new a(null)).length=c+1,s.words=new Array(s.length);for(var u=0;u=0;h--){var d=67108864*(0|i.words[n.length+h])+(0|i.words[n.length+h-1]);for(d=Math.min(d/o|0,67108863),i._ishlnsubmul(n,d,h);0!==i.negative;)d--,i.negative=0,i._ishlnsubmul(n,1,h),i.isZero()||(i.negative^=1);s&&(s.words[h]=d)}return s&&s.strip(),i.strip(),"div"!==t&&0!==r&&i.iushrn(r),{div:s||null,mod:i}},a.prototype.divmod=function(e,t,r){return i(!e.isZero()),this.isZero()?{div:new a(0),mod:new a(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(n=s.div.neg()),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.iadd(e)),{div:n,mod:o}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(n=s.div.neg()),{div:n,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.isub(e)),{div:s.div,mod:o}):e.length>this.length||this.cmp(e)<0?{div:new a(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new a(this.modn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new a(this.modn(e.words[0]))}:this._wordDiv(e,t);var n,o,s},a.prototype.div=function(e){return this.divmod(e,"div",!1).div},a.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},a.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},a.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,i=e.ushrn(1),n=e.andln(1),a=r.cmp(i);return a<0||1===n&&0===a?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},a.prototype.modn=function(e){i(e<=67108863);for(var t=(1<<26)%e,r=0,n=this.length-1;n>=0;n--)r=(t*r+(0|this.words[n]))%e;return r},a.prototype.idivn=function(e){i(e<=67108863);for(var t=0,r=this.length-1;r>=0;r--){var n=(0|this.words[r])+67108864*t;this.words[r]=n/e|0,t=n%e}return this.strip()},a.prototype.divn=function(e){return this.clone().idivn(e)},a.prototype.egcd=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n=new a(1),o=new a(0),s=new a(0),c=new a(1),u=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++u;for(var l=r.clone(),h=t.clone();!t.isZero();){for(var d=0,p=1;0==(t.words[0]&p)&&d<26;++d,p<<=1);if(d>0)for(t.iushrn(d);d-- >0;)(n.isOdd()||o.isOdd())&&(n.iadd(l),o.isub(h)),n.iushrn(1),o.iushrn(1);for(var f=0,m=1;0==(r.words[0]&m)&&f<26;++f,m<<=1);if(f>0)for(r.iushrn(f);f-- >0;)(s.isOdd()||c.isOdd())&&(s.iadd(l),c.isub(h)),s.iushrn(1),c.iushrn(1);t.cmp(r)>=0?(t.isub(r),n.isub(s),o.isub(c)):(r.isub(t),s.isub(n),c.isub(o))}return{a:s,b:c,gcd:r.iushln(u)}},a.prototype._invmp=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n,o=new a(1),s=new a(0),c=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var u=0,l=1;0==(t.words[0]&l)&&u<26;++u,l<<=1);if(u>0)for(t.iushrn(u);u-- >0;)o.isOdd()&&o.iadd(c),o.iushrn(1);for(var h=0,d=1;0==(r.words[0]&d)&&h<26;++h,d<<=1);if(h>0)for(r.iushrn(h);h-- >0;)s.isOdd()&&s.iadd(c),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),o.isub(s)):(r.isub(t),s.isub(o))}return(n=0===t.cmpn(1)?o:s).cmpn(0)<0&&n.iadd(e),n},a.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var i=0;t.isEven()&&r.isEven();i++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var n=t.cmp(r);if(n<0){var a=t;t=r,r=a}else if(0===n||0===r.cmpn(1))break;t.isub(r)}return r.iushln(i)},a.prototype.invm=function(e){return this.egcd(e).a.umod(e)},a.prototype.isEven=function(){return 0==(1&this.words[0])},a.prototype.isOdd=function(){return 1==(1&this.words[0])},a.prototype.andln=function(e){return this.words[0]&e},a.prototype.bincn=function(e){i("number"==typeof e);var t=e%26,r=(e-t)/26,n=1<>>26,s&=67108863,this.words[o]=s}return 0!==a&&(this.words[o]=a,this.length++),this},a.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},a.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this.strip(),this.length>1)t=1;else{r&&(e=-e),i(e<=67108863,"Number is too big");var n=0|this.words[0];t=n===e?0:ne.length)return 1;if(this.length=0;r--){var i=0|this.words[r],n=0|e.words[r];if(i!==n){in&&(t=1);break}}return t},a.prototype.gtn=function(e){return 1===this.cmpn(e)},a.prototype.gt=function(e){return 1===this.cmp(e)},a.prototype.gten=function(e){return this.cmpn(e)>=0},a.prototype.gte=function(e){return this.cmp(e)>=0},a.prototype.ltn=function(e){return-1===this.cmpn(e)},a.prototype.lt=function(e){return-1===this.cmp(e)},a.prototype.lten=function(e){return this.cmpn(e)<=0},a.prototype.lte=function(e){return this.cmp(e)<=0},a.prototype.eqn=function(e){return 0===this.cmpn(e)},a.prototype.eq=function(e){return 0===this.cmp(e)},a.red=function(e){return new w(e)},a.prototype.toRed=function(e){return i(!this.red,"Already a number in reduction context"),i(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},a.prototype.fromRed=function(){return i(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},a.prototype._forceRed=function(e){return this.red=e,this},a.prototype.forceRed=function(e){return i(!this.red,"Already a number in reduction context"),this._forceRed(e)},a.prototype.redAdd=function(e){return i(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},a.prototype.redIAdd=function(e){return i(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},a.prototype.redSub=function(e){return i(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},a.prototype.redISub=function(e){return i(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},a.prototype.redShl=function(e){return i(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},a.prototype.redMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},a.prototype.redIMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},a.prototype.redSqr=function(){return i(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},a.prototype.redISqr=function(){return i(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},a.prototype.redSqrt=function(){return i(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},a.prototype.redInvm=function(){return i(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},a.prototype.redNeg=function(){return i(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},a.prototype.redPow=function(e){return i(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var g={k256:null,p224:null,p192:null,p25519:null};function _(e,t){this.name=e,this.p=new a(t,16),this.n=this.p.bitLength(),this.k=new a(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function v(){_.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function y(){_.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function b(){_.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function E(){_.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function w(e){if("string"==typeof e){var t=a._prime(e);this.m=t.p,this.prime=t}else i(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function S(e){w.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new a(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}_.prototype._tmp=function(){var e=new a(null);return e.words=new Array(Math.ceil(this.n/13)),e},_.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var i=t0?r.isub(this.p):void 0!==r.strip?r.strip():r._strip(),r},_.prototype.split=function(e,t){e.iushrn(this.n,0,t)},_.prototype.imulK=function(e){return e.imul(this.k)},n(v,_),v.prototype.split=function(e,t){for(var r=Math.min(e.length,9),i=0;i>>22,n=a}n>>>=22,e.words[i-10]=n,0===n&&e.length>10?e.length-=10:e.length-=9},v.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=n,t=i}return 0!==t&&(e.words[e.length++]=t),e},a._prime=function(e){if(g[e])return g[e];var t;if("k256"===e)t=new v;else if("p224"===e)t=new y;else if("p192"===e)t=new b;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new E}return g[e]=t,t},w.prototype._verify1=function(e){i(0===e.negative,"red works only with positives"),i(e.red,"red works only with red numbers")},w.prototype._verify2=function(e,t){i(0==(e.negative|t.negative),"red works only with positives"),i(e.red&&e.red===t.red,"red works only with red numbers")},w.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):e.umod(this.m)._forceRed(this)},w.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},w.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},w.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},w.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},w.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},w.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},w.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},w.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},w.prototype.isqr=function(e){return this.imul(e,e.clone())},w.prototype.sqr=function(e){return this.mul(e,e)},w.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(i(t%2==1),3===t){var r=this.m.add(new a(1)).iushrn(2);return this.pow(e,r)}for(var n=this.m.subn(1),o=0;!n.isZero()&&0===n.andln(1);)o++,n.iushrn(1);i(!n.isZero());var s=new a(1).toRed(this),c=s.redNeg(),u=this.m.subn(1).iushrn(1),l=this.m.bitLength();for(l=new a(2*l*l).toRed(this);0!==this.pow(l,u).cmp(c);)l.redIAdd(c);for(var h=this.pow(l,n),d=this.pow(e,n.addn(1).iushrn(1)),p=this.pow(e,n),f=o;0!==p.cmp(s);){for(var m=p,g=0;0!==m.cmp(s);g++)m=m.redSqr();i(g=0;i--){for(var u=t.words[i],l=c-1;l>=0;l--){var h=u>>l&1;n!==r[0]&&(n=this.sqr(n)),0!==h||0!==o?(o<<=1,o|=h,(4===++s||0===i&&0===l)&&(n=this.mul(n,r[o]),s=0,o=0)):s=0}c=26}return n},w.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},w.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},a.mont=function(e){return new S(e)},n(S,w),S.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},S.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},S.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),a=n;return n.cmp(this.m)>=0?a=n.isub(this.m):n.cmpn(0)<0&&(a=n.iadd(this.m)),a._forceRed(this)},S.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new a(0)._forceRed(this);var r=e.mul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),o=n;return n.cmp(this.m)>=0?o=n.isub(this.m):n.cmpn(0)<0&&(o=n.iadd(this.m)),o._forceRed(this)},S.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(22)(e))},function(e,t,r){(function(t){const i=r(4),n=r(12),a=r(37),o=r(18);class s{static validateMnemonic(e){i(e,"Mnemonic phrase is not initialized");let t=e.split(" ");if(t.length!==s.NUM_MNEMONIC_WORDS)throw new Error("Mnemonic phrase is "+t.length+" words but must be "+s.NUM_MNEMONIC_WORDS)}static validatePrivateViewKey(e){i("string"==typeof e),i(64===e.length)}static validatePrivateSpendKey(e){i("string"==typeof e),i(64===e.length)}static validatePublicViewKey(e){i("string"==typeof e),i(64===e.length)}static validatePublicSpendKey(e){i("string"==typeof e),i(64===e.length)}static isValidAddress(e){try{return s.validateAddress(e),!0}catch(e){return!1}}static validateAddress(e){i("string"==typeof e,"Address is not string"),i(e.length>0,"Address is empty"),i(n.isBase58(e),"Address is not base 58")}static isValidPaymentId(e){try{return s.validatePaymentId(e),!0}catch(e){return!1}}static validatePaymentId(e){i.equal(typeof e,"string"),i(16===e.length||64===e.length)}static getLastTxPubKey(e){let r;for(let t=0;t=e.length&&"0"!==t[i])return!1;if(i>=t.length&&"0"!==e[i])return!1}return!0}static mergeTx(e,t){for(let r of e)if(r.getHash()===t.getHash())return void r.merge(t);e.push(t)}static jsonToBinary(e){if(void 0===a.getWasmModule())throw o("WASM module is not loaded; call 'await LibraryUtils.loadKeysModule()' to load");let t=a.getWasmModule().malloc_binary_from_json(JSON.stringify(e)),r=JSON.parse(t);r.ptr=parseInt(r.ptr),r.length=parseInt(r.length);let i=new Uint8Array(r.length);for(let e=0;eJSON.parse(e)),s.txs=s.txs.map(e=>e?e.map(e=>JSON.parse(e.replace(",","{")+"}")):[]),s}}s.NUM_MNEMONIC_WORDS=25,s.WALLET_REFRESH_RATE=1e4,s.RING_SIZE=12,s.MAX_REQUESTS_PER_SECOND=50,e.exports=s}).call(this,r(2).Buffer)},function(e,t,r){r(6);var i=r(11);function n(e,t){Error.captureStackTrace&&Error.captureStackTrace(this,n),this.name="FingerprintFormatError",this.fingerprint=e,this.format=t,this.message="Fingerprint format is not supported, or is invalid: ",void 0!==e&&(this.message+=" fingerprint = "+e),void 0!==t&&(this.message+=" format = "+t)}function a(e){Error.captureStackTrace&&Error.captureStackTrace(this,a),this.name="InvalidAlgorithmError",this.algorithm=e,this.message='Algorithm "'+e+'" is not supported'}function o(e,t,r){Error.captureStackTrace&&Error.captureStackTrace(this,o),this.name="KeyParseError",this.format=t,this.keyName=e,this.innerErr=r,this.message="Failed to parse "+e+" as a valid "+t+" format key: "+r.message}function s(e,t,r){Error.captureStackTrace&&Error.captureStackTrace(this,s),this.name="SignatureParseError",this.type=e,this.format=t,this.innerErr=r,this.message="Failed to parse the given data as a "+e+" signature in "+t+" format: "+r.message}function c(e,t,r){Error.captureStackTrace&&Error.captureStackTrace(this,c),this.name="CertificateParseError",this.format=t,this.certName=e,this.innerErr=r,this.message="Failed to parse "+e+" as a valid "+t+" format certificate: "+r.message}function u(e,t){Error.captureStackTrace&&Error.captureStackTrace(this,u),this.name="KeyEncryptedError",this.format=t,this.keyName=e,this.message="The "+t+" format key "+e+" is encrypted (password-protected), and no passphrase was provided in `options`"}i.inherits(n,Error),i.inherits(a,Error),i.inherits(o,Error),i.inherits(s,Error),i.inherits(c,Error),i.inherits(u,Error),e.exports={FingerprintFormatError:n,InvalidAlgorithmError:a,KeyParseError:o,SignatureParseError:s,KeyEncryptedError:u,CertificateParseError:c}},function(e,t,r){e.exports=h;var i=r(6),n=r(9).Buffer,a=(r(16),r(10),r(29)),o=r(13),s=r(31),c=r(71),u=a.InvalidAlgorithmError,l=a.SignatureParseError;function h(e){i.object(e,"options"),i.arrayOfObject(e.parts,"options.parts"),i.string(e.type,"options.type");for(var t={},r=0;r20&&0===a[0]&&(a=a.slice(1)),(u=this.part.s.data).length>20&&0===u[0]&&(u=u.slice(1)),this.hashAlgorithm&&"sha1"!==this.hashAlgorithm||a.length+u.length!==40)throw new Error("OpenSSH only supports DSA signatures with SHA1 hash");return t.writeBuffer(n.concat([a,u])),t.toBuffer()}if("ssh"===e&&"ecdsa"===this.type){var h,d=new c({});a=this.part.r.data,d.writeBuffer(a),d.writePart(this.part.s),t=new c({}),0===a[0]&&(a=a.slice(1));var p=8*a.length;return 256===p?h="nistp256":384===p?h="nistp384":528===p&&(h="nistp521"),t.writeString("ecdsa-sha2-"+h),t.writeBuffer(d.toBuffer()),t.toBuffer()}throw new Error("Invalid signature format");default:throw new Error("Invalid signature data")}},h.prototype.toString=function(e){return i.optionalString(e,"format"),this.toBuffer(e).toString("base64")},h.parse=function(e,t,r){"string"==typeof e&&(e=n.from(e,"base64")),i.buffer(e,"data"),i.string(r,"format"),i.string(t,"type");var a={};a.type=t.toLowerCase(),a.parts=[];try{switch(i.ok(e.length>0,"signature must not be empty"),a.type){case"rsa":case"ed25519":return d(e,t,r,a);case"dsa":case"ecdsa":return"asn1"===r?function(e,t,r,i){var n=new s.BerReader(e);n.readSequence();var a=n.readString(s.Ber.Integer,!0),c=n.readString(s.Ber.Integer,!0);return i.parts.push({name:"r",data:o.mpNormalize(a)}),i.parts.push({name:"s",data:o.mpNormalize(c)}),new h(i)}(e,0,0,a):"dsa"===a.type?function(e,t,r,n){if(40!=e.length){var a=new c({buffer:e}),o=a.readBuffer();"ssh-dss"===o.toString("ascii")&&(o=a.readBuffer()),i.ok(a.atEnd(),"extra trailing bytes"),i.strictEqual(o.length,40,"invalid inner length"),e=o}return n.parts.push({name:"r",data:e.slice(0,20)}),n.parts.push({name:"s",data:e.slice(20,40)}),new h(n)}(e,0,0,a):function(e,t,r,n){var a,o,s=new c({buffer:e}),u=s.readBuffer(),l=u.toString("ascii");if("ecdsa-"===l.slice(0,6)){var d=l.split("-");switch(i.strictEqual(d[0],"ecdsa"),i.strictEqual(d[1],"sha2"),n.curve=d[2],n.curve){case"nistp256":n.hashAlgo="sha256";break;case"nistp384":n.hashAlgo="sha384";break;case"nistp521":n.hashAlgo="sha512";break;default:throw new Error("Unsupported ECDSA curve: "+n.curve)}u=s.readBuffer(),i.ok(s.atEnd(),"extra trailing bytes on outer"),s=new c({buffer:u}),a=s.readPart()}else a={data:u};return o=s.readPart(),i.ok(s.atEnd(),"extra trailing bytes"),a.name="r",o.name="s",n.parts.push(a),n.parts.push(o),new h(n)}(e,0,0,a);default:throw new u(t)}}catch(e){if(e instanceof u)throw e;throw new l(t,r,e)}},h.isSignature=function(e,t){return o.isCompatible(e,h,t)},h.prototype._sshpkApiVersion=[2,1],h._oldVersionDetect=function(e){return i.func(e.toBuffer),e.hasOwnProperty("hashAlgorithm")?[2,0]:[1,0]}},function(e,t,r){var i=r(429);e.exports={Ber:i,BerReader:i.Reader,BerWriter:i.Writer}},function(e,t,r){(function(e){var i=void 0!==e&&e||"undefined"!=typeof self&&self||window,n=Function.prototype.apply;function a(e,t){this._id=e,this._clearFn=t}t.setTimeout=function(){return new a(n.call(setTimeout,i,arguments),clearTimeout)},t.setInterval=function(){return new a(n.call(setInterval,i,arguments),clearInterval)},t.clearTimeout=t.clearInterval=function(e){e&&e.close()},a.prototype.unref=a.prototype.ref=function(){},a.prototype.close=function(){this._clearFn.call(i,this._id)},t.enroll=function(e,t){clearTimeout(e._idleTimeoutId),e._idleTimeout=t},t.unenroll=function(e){clearTimeout(e._idleTimeoutId),e._idleTimeout=-1},t._unrefActive=t.active=function(e){clearTimeout(e._idleTimeoutId);var t=e._idleTimeout;t>=0&&(e._idleTimeoutId=setTimeout((function(){e._onTimeout&&e._onTimeout()}),t))},r(269),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(this,r(8))},function(e,t,r){var i=r(1).Buffer,n=r(34).Transform,a=r(26).StringDecoder;function o(e){n.call(this),this.hashMode="string"==typeof e,this.hashMode?this[e]=this._finalOrDigest:this.final=this._finalOrDigest,this._final&&(this.__final=this._final,this._final=null),this._decoder=null,this._encoding=null}r(0)(o,n),o.prototype.update=function(e,t,r){"string"==typeof e&&(e=i.from(e,t));var n=this._update(e);return this.hashMode?this:(r&&(n=this._toString(n,r)),n)},o.prototype.setAutoPadding=function(){},o.prototype.getAuthTag=function(){throw new Error("trying to get auth tag in unsupported state")},o.prototype.setAuthTag=function(){throw new Error("trying to set auth tag in unsupported state")},o.prototype.setAAD=function(){throw new Error("trying to set aad in unsupported state")},o.prototype._transform=function(e,t,r){var i;try{this.hashMode?this._update(e):this.push(this._update(e))}catch(e){i=e}finally{r(i)}},o.prototype._flush=function(e){var t;try{this.push(this.__final())}catch(e){t=e}e(t)},o.prototype._finalOrDigest=function(e){var t=this.__final()||i.alloc(0);return e&&(t=this._toString(t,e,!0)),t},o.prototype._toString=function(e,t,r){if(this._decoder||(this._decoder=new a(t),this._encoding=t),this._encoding!==t)throw new Error("can't switch encodings");var i=this._decoder.write(e);return r&&(i+=this._decoder.end()),i},e.exports=o},function(e,t,r){e.exports=n;var i=r(23).EventEmitter;function n(){i.call(this)}r(0)(n,i),n.Readable=r(109),n.Writable=r(292),n.Duplex=r(293),n.Transform=r(294),n.PassThrough=r(295),n.Stream=n,n.prototype.pipe=function(e,t){var r=this;function n(t){e.writable&&!1===e.write(t)&&r.pause&&r.pause()}function a(){r.readable&&r.resume&&r.resume()}r.on("data",n),e.on("drain",a),e._isStdio||t&&!1===t.end||(r.on("end",s),r.on("close",c));var o=!1;function s(){o||(o=!0,e.end())}function c(){o||(o=!0,"function"==typeof e.destroy&&e.destroy())}function u(e){if(l(),0===i.listenerCount(this,"error"))throw e}function l(){r.removeListener("data",n),e.removeListener("drain",a),r.removeListener("end",s),r.removeListener("close",c),r.removeListener("error",u),e.removeListener("error",u),r.removeListener("end",l),r.removeListener("close",l),e.removeListener("close",l)}return r.on("error",u),e.on("error",u),r.on("end",l),r.on("close",l),e.on("close",l),e.emit("pipe",r),e}},function(e,t,r){"use strict";(function(t){!t.version||0===t.version.indexOf("v0.")||0===t.version.indexOf("v1.")&&0!==t.version.indexOf("v1.8.")?e.exports={nextTick:function(e,r,i,n){if("function"!=typeof e)throw new TypeError('"callback" argument must be a function');var a,o,s=arguments.length;switch(s){case 0:case 1:return t.nextTick(e);case 2:return t.nextTick((function(){e.call(null,r)}));case 3:return t.nextTick((function(){e.call(null,r,i)}));case 4:return t.nextTick((function(){e.call(null,r,i,n)}));default:for(a=new Array(s-1),o=0;op.length&&(v=p.length),g+=m.write(p.slice(_,v),g),m[g++]=10,_=v}return g+=m.write("-----END "+a+"-----\n",g),m.slice(0,g)}};var i=r(6),n=r(31),a=r(10),o=r(9).Buffer,s=(r(16),r(13)),c=r(14),u=r(17),l=r(129),h=r(70),d=r(89),p=r(40),f=r(29)},function(e,t,r){const i=r(4),n=r(12),a=r(18);class o{static async getWasmMemoryUsed(){let e=0;return o.WORKER&&(e+=await o.invokeWorker(n.getUUID(),"getWasmMemoryUsed",[])),o.getWasmModule()&&o.getWasmModule().HEAP8&&(e+=o.getWasmModule().HEAP8.length),e}static getWasmModule(){return o.WASM_MODULE}static async loadKeysModule(){return o.WASM_MODULE?o.WASM_MODULE:(delete o.WASM_MODULE,o.WASM_MODULE=r(270)(),new Promise((function(e,t){o.WASM_MODULE.then(t=>{o.WASM_MODULE=t,delete o.WASM_MODULE.then,o._initWasmModule(o.WASM_MODULE),e(o.WASM_MODULE)})})))}static async loadCoreModule(){return o.WASM_MODULE&&o.CORE_LOADED?o.WASM_MODULE:(delete o.WASM_MODULE,o.WASM_MODULE=r(377)(),new Promise((function(e,t){o.WASM_MODULE.then(t=>{o.WASM_MODULE=t,delete o.WASM_MODULE.then,o.CORE_LOADED=!0,o._initWasmModule(o.WASM_MODULE),e(o.WASM_MODULE)})})))}static _initWasmModule(e){const t=r(245);e.taskQueue=t.queue((function(e,t){e.then?e.then(e=>{t(e)}).catch(e=>{t(void 0,e)}):e().then(e=>{t(e)}).catch(e=>{t(void 0,e)})}),1),e.queueTask=async function(t){return new Promise((function(r,i){e.taskQueue.push(t,(function(e,t){void 0!==t?i(t):r(e)}))}))}}static setRejectUnauthorizedFn(e,t){o.REJECT_UNAUTHORIZED_FNS||(o.REJECT_UNAUTHORIZED_FNS=[]),void 0===t?delete o.REJECT_UNAUTHORIZED_FNS[e]:o.REJECT_UNAUTHORIZED_FNS[e]=t}static isRejectUnauthorized(e){if(!o.REJECT_UNAUTHORIZED_FNS[e])throw new Error("No function registered with id "+e+" to inform if unauthorized reqs should be rejected");return o.REJECT_UNAUTHORIZED_FNS[e]()}static getWorker(){return o.WORKER||(o.WORKER=new Worker("MoneroWebWorker.dist.js"),o.WORKER_OBJECTS={},o.WORKER.onmessage=function(e){let t=null,r=o.WORKER_OBJECTS[e.data[0]].callbacks[e.data[1]];if(void 0===r)throw new Error("No worker callback function defined for key '"+e.data[1]+"'");r instanceof Array&&(t=r[1],r=r[0]),r.apply(t,e.data.slice(2))}),o.WORKER}static async invokeWorker(e,t,r){i(t.length>=2);let s=o.getWorker();return o.WORKER_OBJECTS[e]||(o.WORKER_OBJECTS[e]={callbacks:{}}),new Promise((function(i,c){o.WORKER_OBJECTS[e].callbacks["on"+t.charAt(0).toUpperCase()+t.substring(1)]=function(e){e?e.error?c(new a(e.error)):i(e.result):i()},s.postMessage([e,t].concat(void 0===r?[]:n.listify(r)))}))}}e.exports=o},function(e,t,r){(function(e){function r(e,t){for(var r=0,i=e.length-1;i>=0;i--){var n=e[i];"."===n?e.splice(i,1):".."===n?(e.splice(i,1),r++):r&&(e.splice(i,1),r--)}if(t)for(;r--;r)e.unshift("..");return e}function i(e,t){if(e.filter)return e.filter(t);for(var r=[],i=0;i=-1&&!n;a--){var o=a>=0?arguments[a]:e.cwd();if("string"!=typeof o)throw new TypeError("Arguments to path.resolve must be strings");o&&(t=o+"/"+t,n="/"===o.charAt(0))}return(n?"/":"")+(t=r(i(t.split("/"),(function(e){return!!e})),!n).join("/"))||"."},t.normalize=function(e){var a=t.isAbsolute(e),o="/"===n(e,-1);return(e=r(i(e.split("/"),(function(e){return!!e})),!a).join("/"))||a||(e="."),e&&o&&(e+="/"),(a?"/":"")+e},t.isAbsolute=function(e){return"/"===e.charAt(0)},t.join=function(){var e=Array.prototype.slice.call(arguments,0);return t.normalize(i(e,(function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e})).join("/"))},t.relative=function(e,r){function i(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=t.resolve(e).substr(1),r=t.resolve(r).substr(1);for(var n=i(e.split("/")),a=i(r.split("/")),o=Math.min(n.length,a.length),s=o,c=0;c=1;--a)if(47===(t=e.charCodeAt(a))){if(!n){i=a;break}}else n=!1;return-1===i?r?"/":".":r&&1===i?"/":e.slice(0,i)},t.basename=function(e,t){var r=function(e){"string"!=typeof e&&(e+="");var t,r=0,i=-1,n=!0;for(t=e.length-1;t>=0;--t)if(47===e.charCodeAt(t)){if(!n){r=t+1;break}}else-1===i&&(n=!1,i=t+1);return-1===i?"":e.slice(r,i)}(e);return t&&r.substr(-1*t.length)===t&&(r=r.substr(0,r.length-t.length)),r},t.extname=function(e){"string"!=typeof e&&(e+="");for(var t=-1,r=0,i=-1,n=!0,a=0,o=e.length-1;o>=0;--o){var s=e.charCodeAt(o);if(47!==s)-1===i&&(n=!1,i=o+1),46===s?-1===t?t=o:1!==a&&(a=1):-1!==t&&(a=-1);else if(!n){r=o+1;break}}return-1===t||-1===i||0===a||1===a&&t===i-1&&t===r+1?"":e.slice(t,i)};var n="b"==="ab".substr(-1)?function(e,t,r){return e.substr(t,r)}:function(e,t,r){return t<0&&(t=e.length+t),e.substr(t,r)}}).call(this,r(3))},function(e,t,r){"use strict";var i=r(35),n=Object.keys||function(e){var t=[];for(var r in e)t.push(r);return t};e.exports=h;var a=Object.create(r(21));a.inherits=r(0);var o=r(163),s=r(110);a.inherits(h,o);for(var c=n(s.prototype),u=0;u=1,"key must have at least one part"),i.ok(e||f.atEnd(),"leftover bytes at end of key");var _=s,v=a.info[d.type];if("private"!==t&&v.parts.length===p.length||(v=a.privInfo[d.type],_=c),i.strictEqual(v.parts.length,p.length),"ecdsa"===d.type){var y=/^ecdsa-sha2-(.+)$/.exec(m);i.ok(null!==y),i.strictEqual(y[1],p[0].data.toString())}for(var b=!0,E=0;Ethis.getMaxHeight()))return!1;if(!t)return!0;if(this.getTransferQuery()){let t=!1;if(e.getOutgoingTransfer()&&this.getTransferQuery().meetsCriteria(e.getOutgoingTransfer(),!1))t=!0;else if(e.getIncomingTransfers())for(let r of e.getIncomingTransfers())if(this.getTransferQuery().meetsCriteria(r,!1)){t=!0;break}if(!t)return!1}if(void 0!==this.getOutputQuery()){if(void 0===e.getOutputs()||0===e.getOutputs().length)return!1;let t=!1;for(let r of e.getOutputs())if(this.getOutputQuery().meetsCriteria(r,!1)){t=!0;break}if(!t)return!1}return!0}}e.exports=s},function(e,t,r){"use strict";(function(t,i){var n=r(1).Buffer,a=t.crypto||t.msCrypto;a&&a.getRandomValues?e.exports=function(e,t){if(e>4294967295)throw new RangeError("requested too many random bytes");var r=n.allocUnsafe(e);if(e>0)if(e>65536)for(var o=0;o2?"one of ".concat(t," ").concat(e.slice(0,r-1).join(", "),", or ")+e[r-1]:2===r?"one of ".concat(t," ").concat(e[0]," or ").concat(e[1]):"of ".concat(t," ").concat(e[0])}return"of ".concat(t," ").concat(String(e))}n("ERR_INVALID_OPT_VALUE",(function(e,t){return'The value "'+t+'" is invalid for option "'+e+'"'}),TypeError),n("ERR_INVALID_ARG_TYPE",(function(e,t,r){var i,n,o,s;if("string"==typeof t&&(n="not ",t.substr(!o||o<0?0:+o,n.length)===n)?(i="must not be",t=t.replace(/^not /,"")):i="must be",function(e,t,r){return(void 0===r||r>e.length)&&(r=e.length),e.substring(r-t.length,r)===t}(e," argument"))s="The ".concat(e," ").concat(i," ").concat(a(t,"type"));else{var c=function(e,t,r){return"number"!=typeof r&&(r=0),!(r+t.length>e.length)&&-1!==e.indexOf(t,r)}(e,".")?"property":"argument";s='The "'.concat(e,'" ').concat(c," ").concat(i," ").concat(a(t,"type"))}return s+=". Received type ".concat(typeof r)}),TypeError),n("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF"),n("ERR_METHOD_NOT_IMPLEMENTED",(function(e){return"The "+e+" method is not implemented"})),n("ERR_STREAM_PREMATURE_CLOSE","Premature close"),n("ERR_STREAM_DESTROYED",(function(e){return"Cannot call "+e+" after a stream was destroyed"})),n("ERR_MULTIPLE_CALLBACK","Callback called multiple times"),n("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable"),n("ERR_STREAM_WRITE_AFTER_END","write after end"),n("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError),n("ERR_UNKNOWN_ENCODING",(function(e){return"Unknown encoding: "+e}),TypeError),n("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event"),e.exports.codes=i},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:e.exports=function(e,t){if(t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}}},function(e,t,r){"use strict";(function(t){var i=Object.keys||function(e){var t=[];for(var r in e)t.push(r);return t};e.exports=u;var n=r(155),a=r(159);r(46)(u,n);for(var o=i(a.prototype),s=0;s=this._finalSize&&(this._update(this._block),this._block.fill(0));var r=8*this._len;if(r<=4294967295)this._block.writeUInt32BE(r,this._blockSize-4);else{var i=(4294967295&r)>>>0,n=(r-i)/4294967296;this._block.writeUInt32BE(n,this._blockSize-8),this._block.writeUInt32BE(i,this._blockSize-4)}this._update(this._block);var a=this._hash();return e?a.toString(e):a},n.prototype._update=function(){throw new Error("_update must be implemented by subclass")},e.exports=n},function(e,t,r){"use strict";var i={};function n(e,t,r){r||(r=Error);var n=function(e){var r,i;function n(r,i,n){return e.call(this,function(e,r,i){return"string"==typeof t?t:t(e,r,i)}(r,i,n))||this}return i=e,(r=n).prototype=Object.create(i.prototype),r.prototype.constructor=r,r.__proto__=i,n}(r);n.prototype.name=r.name,n.prototype.code=e,i[e]=n}function a(e,t){if(Array.isArray(e)){var r=e.length;return e=e.map((function(e){return String(e)})),r>2?"one of ".concat(t," ").concat(e.slice(0,r-1).join(", "),", or ")+e[r-1]:2===r?"one of ".concat(t," ").concat(e[0]," or ").concat(e[1]):"of ".concat(t," ").concat(e[0])}return"of ".concat(t," ").concat(String(e))}n("ERR_INVALID_OPT_VALUE",(function(e,t){return'The value "'+t+'" is invalid for option "'+e+'"'}),TypeError),n("ERR_INVALID_ARG_TYPE",(function(e,t,r){var i,n,o,s;if("string"==typeof t&&(n="not ",t.substr(!o||o<0?0:+o,n.length)===n)?(i="must not be",t=t.replace(/^not /,"")):i="must be",function(e,t,r){return(void 0===r||r>e.length)&&(r=e.length),e.substring(r-t.length,r)===t}(e," argument"))s="The ".concat(e," ").concat(i," ").concat(a(t,"type"));else{var c=function(e,t,r){return"number"!=typeof r&&(r=0),!(r+t.length>e.length)&&-1!==e.indexOf(t,r)}(e,".")?"property":"argument";s='The "'.concat(e,'" ').concat(c," ").concat(i," ").concat(a(t,"type"))}return s+=". Received type ".concat(typeof r)}),TypeError),n("ERR_STREAM_PUSH_AFTER_EOF","stream.push() after EOF"),n("ERR_METHOD_NOT_IMPLEMENTED",(function(e){return"The "+e+" method is not implemented"})),n("ERR_STREAM_PREMATURE_CLOSE","Premature close"),n("ERR_STREAM_DESTROYED",(function(e){return"Cannot call "+e+" after a stream was destroyed"})),n("ERR_MULTIPLE_CALLBACK","Callback called multiple times"),n("ERR_STREAM_CANNOT_PIPE","Cannot pipe, not readable"),n("ERR_STREAM_WRITE_AFTER_END","write after end"),n("ERR_STREAM_NULL_VALUES","May not write null values to stream",TypeError),n("ERR_UNKNOWN_ENCODING",(function(e){return"Unknown encoding: "+e}),TypeError),n("ERR_STREAM_UNSHIFT_AFTER_END_EVENT","stream.unshift() after end event"),e.exports.codes=i},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){t&&(e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}))}:e.exports=function(e,t){if(t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}}},function(e,t,r){"use strict";(function(t){var i=Object.keys||function(e){var t=[];for(var r in e)t.push(r);return t};e.exports=u;var n=r(184),a=r(188);r(50)(u,n);for(var o=i(a.prototype),s=0;s=t)throw new Error("Cannot access property/index "+i+" levels up, current level is "+t);return r[t-i]}if(i>t)throw new Error("Cannot access data "+i+" levels up, current level is "+t);if(a="data"+(t-i||""),!n)return a}for(var s=a,u=n.split("/"),l=0;l>>2]>>>24-a%4*8&255)<<16|(t[a+1>>>2]>>>24-(a+1)%4*8&255)<<8|t[a+2>>>2]>>>24-(a+2)%4*8&255,s=0;s<4&&a+.75*s>>6*(3-s)&63));var c=i.charAt(64);if(c)for(;n.length%4;)n.push(c);return n.join("")},parse:function(e){var t=e.length,r=this._map,i=this._reverseMap;if(!i){i=this._reverseMap=[];for(var a=0;a>>6-o%4*2,u=s|c;i[a>>>2]|=u<<24-a%4*8,a++}return n.create(i,a)}(e,t,i)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="},a.enc.Base64)},function(e,t,r){var i;e.exports=(i=r(5),function(e){var t=i,r=t.lib,n=r.WordArray,a=r.Hasher,o=t.algo,s=[];!function(){for(var t=0;t<64;t++)s[t]=4294967296*e.abs(e.sin(t+1))|0}();var c=o.MD5=a.extend({_doReset:function(){this._hash=new n.init([1732584193,4023233417,2562383102,271733878])},_doProcessBlock:function(e,t){for(var r=0;r<16;r++){var i=t+r,n=e[i];e[i]=16711935&(n<<8|n>>>24)|4278255360&(n<<24|n>>>8)}var a=this._hash.words,o=e[t+0],c=e[t+1],p=e[t+2],f=e[t+3],m=e[t+4],g=e[t+5],_=e[t+6],v=e[t+7],y=e[t+8],b=e[t+9],E=e[t+10],w=e[t+11],S=e[t+12],k=e[t+13],x=e[t+14],M=e[t+15],N=a[0],j=a[1],T=a[2],R=a[3];N=u(N,j,T,R,o,7,s[0]),R=u(R,N,j,T,c,12,s[1]),T=u(T,R,N,j,p,17,s[2]),j=u(j,T,R,N,f,22,s[3]),N=u(N,j,T,R,m,7,s[4]),R=u(R,N,j,T,g,12,s[5]),T=u(T,R,N,j,_,17,s[6]),j=u(j,T,R,N,v,22,s[7]),N=u(N,j,T,R,y,7,s[8]),R=u(R,N,j,T,b,12,s[9]),T=u(T,R,N,j,E,17,s[10]),j=u(j,T,R,N,w,22,s[11]),N=u(N,j,T,R,S,7,s[12]),R=u(R,N,j,T,k,12,s[13]),T=u(T,R,N,j,x,17,s[14]),N=l(N,j=u(j,T,R,N,M,22,s[15]),T,R,c,5,s[16]),R=l(R,N,j,T,_,9,s[17]),T=l(T,R,N,j,w,14,s[18]),j=l(j,T,R,N,o,20,s[19]),N=l(N,j,T,R,g,5,s[20]),R=l(R,N,j,T,E,9,s[21]),T=l(T,R,N,j,M,14,s[22]),j=l(j,T,R,N,m,20,s[23]),N=l(N,j,T,R,b,5,s[24]),R=l(R,N,j,T,x,9,s[25]),T=l(T,R,N,j,f,14,s[26]),j=l(j,T,R,N,y,20,s[27]),N=l(N,j,T,R,k,5,s[28]),R=l(R,N,j,T,p,9,s[29]),T=l(T,R,N,j,v,14,s[30]),N=h(N,j=l(j,T,R,N,S,20,s[31]),T,R,g,4,s[32]),R=h(R,N,j,T,y,11,s[33]),T=h(T,R,N,j,w,16,s[34]),j=h(j,T,R,N,x,23,s[35]),N=h(N,j,T,R,c,4,s[36]),R=h(R,N,j,T,m,11,s[37]),T=h(T,R,N,j,v,16,s[38]),j=h(j,T,R,N,E,23,s[39]),N=h(N,j,T,R,k,4,s[40]),R=h(R,N,j,T,o,11,s[41]),T=h(T,R,N,j,f,16,s[42]),j=h(j,T,R,N,_,23,s[43]),N=h(N,j,T,R,b,4,s[44]),R=h(R,N,j,T,S,11,s[45]),T=h(T,R,N,j,M,16,s[46]),N=d(N,j=h(j,T,R,N,p,23,s[47]),T,R,o,6,s[48]),R=d(R,N,j,T,v,10,s[49]),T=d(T,R,N,j,x,15,s[50]),j=d(j,T,R,N,g,21,s[51]),N=d(N,j,T,R,S,6,s[52]),R=d(R,N,j,T,f,10,s[53]),T=d(T,R,N,j,E,15,s[54]),j=d(j,T,R,N,c,21,s[55]),N=d(N,j,T,R,y,6,s[56]),R=d(R,N,j,T,M,10,s[57]),T=d(T,R,N,j,_,15,s[58]),j=d(j,T,R,N,k,21,s[59]),N=d(N,j,T,R,m,6,s[60]),R=d(R,N,j,T,w,10,s[61]),T=d(T,R,N,j,p,15,s[62]),j=d(j,T,R,N,b,21,s[63]),a[0]=a[0]+N|0,a[1]=a[1]+j|0,a[2]=a[2]+T|0,a[3]=a[3]+R|0},_doFinalize:function(){var t=this._data,r=t.words,i=8*this._nDataBytes,n=8*t.sigBytes;r[n>>>5]|=128<<24-n%32;var a=e.floor(i/4294967296),o=i;r[15+(n+64>>>9<<4)]=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8),r[14+(n+64>>>9<<4)]=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),t.sigBytes=4*(r.length+1),this._process();for(var s=this._hash,c=s.words,u=0;u<4;u++){var l=c[u];c[u]=16711935&(l<<8|l>>>24)|4278255360&(l<<24|l>>>8)}return s},clone:function(){var e=a.clone.call(this);return e._hash=this._hash.clone(),e}});function u(e,t,r,i,n,a,o){var s=e+(t&r|~t&i)+n+o;return(s<>>32-a)+t}function l(e,t,r,i,n,a,o){var s=e+(t&i|r&~i)+n+o;return(s<>>32-a)+t}function h(e,t,r,i,n,a,o){var s=e+(t^r^i)+n+o;return(s<>>32-a)+t}function d(e,t,r,i,n,a,o){var s=e+(r^(t|~i))+n+o;return(s<>>32-a)+t}t.MD5=a._createHelper(c),t.HmacMD5=a._createHmacHelper(c)}(Math),i.MD5)},function(e,t,r){const i=r(12),n=r(205),a=r(37),o=r(18),s=r(138),c=r(28);class u{constructor(e,t,r,i){if("string"==typeof e)this.config={uri:e},void 0!==t&&(this.config.username=t),void 0!==r&&(this.config.password=r),void 0!==i&&(this.config.rejectUnauthorized=i);else if("object"==typeof e){if(void 0!==t||void 0!==r||void 0!==i)throw new o("Can provide config object or params but not both");this.config=e instanceof u?Object.assign({},e.getConfig()):Object.assign({},e)}else if(void 0!==e)throw new o("Invalid configuration to MoneroRpcConnection; must be string or MoneroRpcConnection or equivalent JS object");if(this.config=Object.assign({},u.DEFAULT_CONFIG,this.config),this.config.uri&&(this.config.uri=this.config.uri.replace(/\/$/,"")),this.config.user||this.config.pass)throw new o("Authentication fields 'user' and 'pass' have been renamed to 'username' and 'password'. Please update to the new api")}getUri(){return this.config.uri}getUsername(){return this.config.username}getPassword(){return this.config.password}getRejectUnauthorized(){return this.config.rejectUnauthorized}getConfig(){return this.config}async sendJsonRequest(e,t){try{let r=await n.request({method:"POST",uri:this.getUri()+"/json_rpc",username:this.getUsername(),password:this.getPassword(),body:JSON.stringify({id:"0",jsonrpc:"2.0",method:e,params:t}),rejectUnauthorized:this.config.rejectUnauthorized,requestApi:i.isFirefox()?"xhr":"fetch"});if(r=JSON.parse(r.body.replace(/("[^"]*"\s*:\s*)(\d{16,})/g,'$1"$2"')),r.error)throw new s(r.error.message,r.error.code,e,t);return r}catch(r){throw r instanceof s?r:new s(r,void 0,e,t)}}async sendPathRequest(e,t){try{let r=await n.request({method:"POST",uri:this.getUri()+"/"+e,username:this.getUsername(),password:this.getPassword(),body:JSON.stringify(t),rejectUnauthorized:this.config.rejectUnauthorized,requestApi:i.isFirefox()?"xhr":"fetch"});if(r=JSON.parse(r.body.replace(/("[^"]*"\s*:\s*)(\d{16,})/g,'$1"$2"')),"string"==typeof r&&(r=JSON.parse(r)),r.error)throw new s(r.error.message,r.error.code,e,t);return r}catch(r){throw r instanceof s?r:new s(r,void 0,e,t)}}async sendBinaryRequest(e,t){await a.loadKeysModule();let r=c.jsonToBinary(t);try{let a=await n.request({method:"POST",uri:this.getUri()+"/"+e,username:this.getUsername(),password:this.getPassword(),body:r,rejectUnauthorized:this.config.rejectUnauthorized,requestApi:i.isFirefox()?"xhr":"fetch"});if(a=a.body,a instanceof Uint8Array||(console.error("resp is not uint8array"),console.error(a)),a.error)throw new s(a.error.message,a.error.code,e,t);return a}catch(r){throw r instanceof s?r:new s(r,void 0,e,t)}}}u.DEFAULT_CONFIG={uri:void 0,username:void 0,password:void 0,rejectUnauthorized:!0},u.SUPPORTED_FIELDS=["uri","username","password","rejectUnauthorized"],e.exports=u},function(e,t,r){const i=r(4),n=r(12);class a{constructor(e,t){if(e)if(e instanceof a)this.state=e.toJson();else if("object"==typeof e)this.state=Object.assign({},e);else{if("string"!=typeof e)throw new MoneroError("stateOrHex must be a MoneroKeyImage, JavaScript object, or string");this.state={},this.setHex(e),this.setSignature(t)}else this.state={}}getHex(){return this.state.hex}setHex(e){return this.state.hex=e,this}getSignature(){return this.state.signature}setSignature(e){return this.state.signature=e,this}copy(){return new a(this)}toJson(){return Object.assign({},this.state)}merge(e){return i(e instanceof a),e===this||(this.setHex(n.reconcile(this.getHex(),e.getHex())),this.setSignature(n.reconcile(this.getSignature(),e.getSignature()))),this}toString(e=0){let t="";return t+=n.kvLine("Hex",this.getHex(),e),t+=n.kvLine("Signature",this.getSignature(),e),t.slice(0,t.length-1)}}e.exports=a},function(e,t,r){const i=r(4),n=r(7).BigInteger,a=r(12),o=r(96),s=r(98),c=r(73),u=r(92);class l extends u{constructor(e){if(super(e),e instanceof l&&e.getTxSet()&&this.setTxSet(e.getTxSet()),(e=this.state).incomingTransfers)for(let t=0;t=this._delta8){var r=(e=this.pending).length%this._delta8;this.pending=e.slice(e.length-r,e.length),0===this.pending.length&&(this.pending=null),e=i.join32(e,0,e.length-r,this.endian);for(var n=0;n>>24&255,i[n++]=e>>>16&255,i[n++]=e>>>8&255,i[n++]=255&e}else for(i[n++]=255&e,i[n++]=e>>>8&255,i[n++]=e>>>16&255,i[n++]=e>>>24&255,i[n++]=0,i[n++]=0,i[n++]=0,i[n++]=0,a=8;a2){r="md5","md5"===c[0].toLowerCase()&&(c=c.slice(1)),c=(c=c.map((function(t){for(;t.length<2;)t="0"+t;if(t.length>2)throw new h(e);return t}))).join("");if(!/^[a-fA-F0-9]+$/.test(c)||c.length%2!=0)throw new h(e);try{o=n.from(c,"hex")}catch(t){throw new h(e)}}if(void 0===r)throw new h(e);if(void 0===a.hashAlgs[r])throw new d(r);if(void 0!==s&&-1===(s=s.map((function(e){return e.toLowerCase()}))).indexOf(r))throw new d(r);return new p({algorithm:r,hash:o,type:t.type||"key"})},p.isFingerprint=function(e,t){return l.isCompatible(e,p,t)},p.prototype._sshpkApiVersion=[1,1],p._oldVersionDetect=function(e){return i.func(e.toString),i.func(e.matches),[1,0]}},function(e,t,r){e.exports=g;var i=r(6),n=r(9).Buffer,a=r(16),o=r(10),s=r(66),c=(r(30),r(29)),u=(r(11),r(13)),l=r(14),h=r(17),d=r(72),p={};p.openssh=r(432),p.x509=r(230),p.pem=r(433);var f=c.CertificateParseError,m=c.InvalidAlgorithmError;function g(e){i.object(e,"options"),i.arrayOfObject(e.subjects,"options.subjects"),u.assertCompatible(e.subjects[0],d,[1,0],"options.subjects"),u.assertCompatible(e.subjectKey,l,[1,0],"options.subjectKey"),u.assertCompatible(e.issuer,d,[1,0],"options.issuer"),void 0!==e.issuerKey&&u.assertCompatible(e.issuerKey,l,[1,0],"options.issuerKey"),i.object(e.signatures,"options.signatures"),i.buffer(e.serial,"options.serial"),i.date(e.validFrom,"options.validFrom"),i.date(e.validUntil,"optons.validUntil"),i.optionalArrayOfString(e.purposes,"options.purposes"),this._hashCache={},this.subjects=e.subjects,this.issuer=e.issuer,this.subjectKey=e.subjectKey,this.issuerKey=e.issuerKey,this.signatures=e.signatures,this.serial=e.serial,this.validFrom=e.validFrom,this.validUntil=e.validUntil,this.purposes=e.purposes}g.formats=p,g.prototype.toBuffer=function(e,t){return void 0===e&&(e="x509"),i.string(e,"format"),i.object(p[e],"formats[format]"),i.optionalObject(t,"options"),p[e].write(this,t)},g.prototype.toString=function(e,t){return void 0===e&&(e="pem"),this.toBuffer(e,t).toString()},g.prototype.fingerprint=function(e){void 0===e&&(e="sha256"),i.string(e,"algorithm");var t={type:"certificate",hash:this.hash(e),algorithm:e};return new s(t)},g.prototype.hash=function(e){if(i.string(e,"algorithm"),e=e.toLowerCase(),void 0===a.hashAlgs[e])throw new m(e);if(this._hashCache[e])return this._hashCache[e];var t=o.createHash(e).update(this.toBuffer("x509")).digest();return this._hashCache[e]=t,t},g.prototype.isExpired=function(e){return void 0===e&&(e=new Date),!(e.getTime()>=this.validFrom.getTime()&&e.getTime()0&&-1===this.issuer.purposes.indexOf("ca"))&&this.isSignedByKey(e.subjectKey))},g.prototype.getExtension=function(e){return i.string(e,"keyOrOid"),this.getExtensions().filter((function(t){return"x509"===t.format?t.oid===e:"openssh"===t.format&&t.name===e}))[0]},g.prototype.getExtensions=function(){var e=[],t=this.signatures.x509;t&&t.extras&&t.extras.exts&&t.extras.exts.forEach((function(t){t.format="x509",e.push(t)}));var r=this.signatures.openssh;return r&&r.exts&&r.exts.forEach((function(t){t.format="openssh",e.push(t)})),e},g.prototype.isSignedByKey=function(e){if(u.assertCompatible(e,l,[1,2],"issuerKey"),void 0!==this.issuerKey)return this.issuerKey.fingerprint("sha512").matches(e);var t=Object.keys(this.signatures)[0],r=p[t].verify(this,e);return r&&(this.issuerKey=e),r},g.prototype.signWith=function(e){u.assertCompatible(e,h,[1,2],"key");for(var t=Object.keys(p),r=!1,i=0;i0&&-1===p.indexOf("serverAuth")&&p.push("serverAuth"),m.length>0&&-1===p.indexOf("clientAuth")&&p.push("clientAuth"),(m.length>0||f.length>0)&&(-1===p.indexOf("keyAgreement")&&p.push("keyAgreement"),"rsa"===t.type&&-1===p.indexOf("encryption")&&p.push("encryption"))}var _=new g({subjects:a,issuer:a[0],subjectKey:t.toPublic(),issuerKey:t.toPublic(),signatures:{},serial:l,validFrom:o,validUntil:s,purposes:p});return _.signWith(t),_},g.create=function(e,t,r,a,o){var s;s=Array.isArray(e)?e:[e],i.arrayOfObject(s),s.forEach((function(e){u.assertCompatible(e,d,[1,0],"subject")})),u.assertCompatible(t,l,[1,0],"key"),h.isPrivateKey(t)&&(t=t.toPublic()),u.assertCompatible(r,d,[1,0],"issuer"),u.assertCompatible(a,h,[1,2],"issuer key"),i.optionalObject(o,"options"),void 0===o&&(o={}),i.optionalObject(o.validFrom,"options.validFrom"),i.optionalObject(o.validUntil,"options.validUntil");var c=o.validFrom,p=o.validUntil;if(void 0===c&&(c=new Date),void 0===p){i.optionalNumber(o.lifetime,"options.lifetime");var f=o.lifetime;void 0===f&&(f=31536e4),(p=new Date).setTime(p.getTime()+1e3*f)}i.optionalBuffer(o.serial,"options.serial");var m=o.serial;void 0===m&&(m=n.from("0000000000000001","hex"));var _=o.purposes;void 0===_&&(_=[]),-1===_.indexOf("signature")&&_.push("signature"),!0===o.ca&&(-1===_.indexOf("ca")&&_.push("ca"),-1===_.indexOf("crl")&&_.push("crl"));var v=s.filter((function(e){return"host"===e.type})),y=s.filter((function(e){return"user"===e.type}));v.length>0&&-1===_.indexOf("serverAuth")&&_.push("serverAuth"),y.length>0&&-1===_.indexOf("clientAuth")&&_.push("clientAuth"),(y.length>0||v.length>0)&&(-1===_.indexOf("keyAgreement")&&_.push("keyAgreement"),"rsa"===t.type&&-1===_.indexOf("encryption")&&_.push("encryption"));var b=new g({subjects:s,issuer:r,subjectKey:t,issuerKey:a.toPublic(),signatures:{},serial:m,validFrom:c,validUntil:p,purposes:_});return b.signWith(a),b},g.parse=function(e,t,r){"string"!=typeof e&&i.buffer(e,"data"),void 0===t&&(t="auto"),i.string(t,"format"),"string"==typeof r&&(r={filename:r}),i.optionalObject(r,"options"),void 0===r&&(r={}),i.optionalString(r.filename,"options.filename"),void 0===r.filename&&(r.filename="(unnamed)"),i.object(p[t],"formats[format]");try{return p[t].read(e,r)}catch(e){throw new f(r.filename,t,e)}},g.isCertificate=function(e,t){return u.isCompatible(e,g,t)},g.prototype._sshpkApiVersion=[1,1],g._oldVersionDetect=function(e){return[1,0]}},function(e,t,r){!function(e){"use strict";var t=function(e){var t,r=new Float64Array(16);if(e)for(t=0;t>24&255,e[t+1]=r>>16&255,e[t+2]=r>>8&255,e[t+3]=255&r,e[t+4]=i>>24&255,e[t+5]=i>>16&255,e[t+6]=i>>8&255,e[t+7]=255&i}function m(e,t,r,i,n){var a,o=0;for(a=0;a>>8)-1}function g(e,t,r,i){return m(e,t,r,i,16)}function _(e,t,r,i){return m(e,t,r,i,32)}function v(e,t,r,i){!function(e,t,r,i){for(var n,a=255&i[0]|(255&i[1])<<8|(255&i[2])<<16|(255&i[3])<<24,o=255&r[0]|(255&r[1])<<8|(255&r[2])<<16|(255&r[3])<<24,s=255&r[4]|(255&r[5])<<8|(255&r[6])<<16|(255&r[7])<<24,c=255&r[8]|(255&r[9])<<8|(255&r[10])<<16|(255&r[11])<<24,u=255&r[12]|(255&r[13])<<8|(255&r[14])<<16|(255&r[15])<<24,l=255&i[4]|(255&i[5])<<8|(255&i[6])<<16|(255&i[7])<<24,h=255&t[0]|(255&t[1])<<8|(255&t[2])<<16|(255&t[3])<<24,d=255&t[4]|(255&t[5])<<8|(255&t[6])<<16|(255&t[7])<<24,p=255&t[8]|(255&t[9])<<8|(255&t[10])<<16|(255&t[11])<<24,f=255&t[12]|(255&t[13])<<8|(255&t[14])<<16|(255&t[15])<<24,m=255&i[8]|(255&i[9])<<8|(255&i[10])<<16|(255&i[11])<<24,g=255&r[16]|(255&r[17])<<8|(255&r[18])<<16|(255&r[19])<<24,_=255&r[20]|(255&r[21])<<8|(255&r[22])<<16|(255&r[23])<<24,v=255&r[24]|(255&r[25])<<8|(255&r[26])<<16|(255&r[27])<<24,y=255&r[28]|(255&r[29])<<8|(255&r[30])<<16|(255&r[31])<<24,b=255&i[12]|(255&i[13])<<8|(255&i[14])<<16|(255&i[15])<<24,E=a,w=o,S=s,k=c,x=u,M=l,N=h,j=d,T=p,R=f,I=m,O=g,A=_,P=v,D=y,F=b,C=0;C<20;C+=2)E^=(n=(A^=(n=(T^=(n=(x^=(n=E+A|0)<<7|n>>>25)+E|0)<<9|n>>>23)+x|0)<<13|n>>>19)+T|0)<<18|n>>>14,M^=(n=(w^=(n=(P^=(n=(R^=(n=M+w|0)<<7|n>>>25)+M|0)<<9|n>>>23)+R|0)<<13|n>>>19)+P|0)<<18|n>>>14,I^=(n=(N^=(n=(S^=(n=(D^=(n=I+N|0)<<7|n>>>25)+I|0)<<9|n>>>23)+D|0)<<13|n>>>19)+S|0)<<18|n>>>14,F^=(n=(O^=(n=(j^=(n=(k^=(n=F+O|0)<<7|n>>>25)+F|0)<<9|n>>>23)+k|0)<<13|n>>>19)+j|0)<<18|n>>>14,E^=(n=(k^=(n=(S^=(n=(w^=(n=E+k|0)<<7|n>>>25)+E|0)<<9|n>>>23)+w|0)<<13|n>>>19)+S|0)<<18|n>>>14,M^=(n=(x^=(n=(j^=(n=(N^=(n=M+x|0)<<7|n>>>25)+M|0)<<9|n>>>23)+N|0)<<13|n>>>19)+j|0)<<18|n>>>14,I^=(n=(R^=(n=(T^=(n=(O^=(n=I+R|0)<<7|n>>>25)+I|0)<<9|n>>>23)+O|0)<<13|n>>>19)+T|0)<<18|n>>>14,F^=(n=(D^=(n=(P^=(n=(A^=(n=F+D|0)<<7|n>>>25)+F|0)<<9|n>>>23)+A|0)<<13|n>>>19)+P|0)<<18|n>>>14;E=E+a|0,w=w+o|0,S=S+s|0,k=k+c|0,x=x+u|0,M=M+l|0,N=N+h|0,j=j+d|0,T=T+p|0,R=R+f|0,I=I+m|0,O=O+g|0,A=A+_|0,P=P+v|0,D=D+y|0,F=F+b|0,e[0]=E>>>0&255,e[1]=E>>>8&255,e[2]=E>>>16&255,e[3]=E>>>24&255,e[4]=w>>>0&255,e[5]=w>>>8&255,e[6]=w>>>16&255,e[7]=w>>>24&255,e[8]=S>>>0&255,e[9]=S>>>8&255,e[10]=S>>>16&255,e[11]=S>>>24&255,e[12]=k>>>0&255,e[13]=k>>>8&255,e[14]=k>>>16&255,e[15]=k>>>24&255,e[16]=x>>>0&255,e[17]=x>>>8&255,e[18]=x>>>16&255,e[19]=x>>>24&255,e[20]=M>>>0&255,e[21]=M>>>8&255,e[22]=M>>>16&255,e[23]=M>>>24&255,e[24]=N>>>0&255,e[25]=N>>>8&255,e[26]=N>>>16&255,e[27]=N>>>24&255,e[28]=j>>>0&255,e[29]=j>>>8&255,e[30]=j>>>16&255,e[31]=j>>>24&255,e[32]=T>>>0&255,e[33]=T>>>8&255,e[34]=T>>>16&255,e[35]=T>>>24&255,e[36]=R>>>0&255,e[37]=R>>>8&255,e[38]=R>>>16&255,e[39]=R>>>24&255,e[40]=I>>>0&255,e[41]=I>>>8&255,e[42]=I>>>16&255,e[43]=I>>>24&255,e[44]=O>>>0&255,e[45]=O>>>8&255,e[46]=O>>>16&255,e[47]=O>>>24&255,e[48]=A>>>0&255,e[49]=A>>>8&255,e[50]=A>>>16&255,e[51]=A>>>24&255,e[52]=P>>>0&255,e[53]=P>>>8&255,e[54]=P>>>16&255,e[55]=P>>>24&255,e[56]=D>>>0&255,e[57]=D>>>8&255,e[58]=D>>>16&255,e[59]=D>>>24&255,e[60]=F>>>0&255,e[61]=F>>>8&255,e[62]=F>>>16&255,e[63]=F>>>24&255}(e,t,r,i)}function y(e,t,r,i){!function(e,t,r,i){for(var n,a=255&i[0]|(255&i[1])<<8|(255&i[2])<<16|(255&i[3])<<24,o=255&r[0]|(255&r[1])<<8|(255&r[2])<<16|(255&r[3])<<24,s=255&r[4]|(255&r[5])<<8|(255&r[6])<<16|(255&r[7])<<24,c=255&r[8]|(255&r[9])<<8|(255&r[10])<<16|(255&r[11])<<24,u=255&r[12]|(255&r[13])<<8|(255&r[14])<<16|(255&r[15])<<24,l=255&i[4]|(255&i[5])<<8|(255&i[6])<<16|(255&i[7])<<24,h=255&t[0]|(255&t[1])<<8|(255&t[2])<<16|(255&t[3])<<24,d=255&t[4]|(255&t[5])<<8|(255&t[6])<<16|(255&t[7])<<24,p=255&t[8]|(255&t[9])<<8|(255&t[10])<<16|(255&t[11])<<24,f=255&t[12]|(255&t[13])<<8|(255&t[14])<<16|(255&t[15])<<24,m=255&i[8]|(255&i[9])<<8|(255&i[10])<<16|(255&i[11])<<24,g=255&r[16]|(255&r[17])<<8|(255&r[18])<<16|(255&r[19])<<24,_=255&r[20]|(255&r[21])<<8|(255&r[22])<<16|(255&r[23])<<24,v=255&r[24]|(255&r[25])<<8|(255&r[26])<<16|(255&r[27])<<24,y=255&r[28]|(255&r[29])<<8|(255&r[30])<<16|(255&r[31])<<24,b=255&i[12]|(255&i[13])<<8|(255&i[14])<<16|(255&i[15])<<24,E=0;E<20;E+=2)a^=(n=(_^=(n=(p^=(n=(u^=(n=a+_|0)<<7|n>>>25)+a|0)<<9|n>>>23)+u|0)<<13|n>>>19)+p|0)<<18|n>>>14,l^=(n=(o^=(n=(v^=(n=(f^=(n=l+o|0)<<7|n>>>25)+l|0)<<9|n>>>23)+f|0)<<13|n>>>19)+v|0)<<18|n>>>14,m^=(n=(h^=(n=(s^=(n=(y^=(n=m+h|0)<<7|n>>>25)+m|0)<<9|n>>>23)+y|0)<<13|n>>>19)+s|0)<<18|n>>>14,b^=(n=(g^=(n=(d^=(n=(c^=(n=b+g|0)<<7|n>>>25)+b|0)<<9|n>>>23)+c|0)<<13|n>>>19)+d|0)<<18|n>>>14,a^=(n=(c^=(n=(s^=(n=(o^=(n=a+c|0)<<7|n>>>25)+a|0)<<9|n>>>23)+o|0)<<13|n>>>19)+s|0)<<18|n>>>14,l^=(n=(u^=(n=(d^=(n=(h^=(n=l+u|0)<<7|n>>>25)+l|0)<<9|n>>>23)+h|0)<<13|n>>>19)+d|0)<<18|n>>>14,m^=(n=(f^=(n=(p^=(n=(g^=(n=m+f|0)<<7|n>>>25)+m|0)<<9|n>>>23)+g|0)<<13|n>>>19)+p|0)<<18|n>>>14,b^=(n=(y^=(n=(v^=(n=(_^=(n=b+y|0)<<7|n>>>25)+b|0)<<9|n>>>23)+_|0)<<13|n>>>19)+v|0)<<18|n>>>14;e[0]=a>>>0&255,e[1]=a>>>8&255,e[2]=a>>>16&255,e[3]=a>>>24&255,e[4]=l>>>0&255,e[5]=l>>>8&255,e[6]=l>>>16&255,e[7]=l>>>24&255,e[8]=m>>>0&255,e[9]=m>>>8&255,e[10]=m>>>16&255,e[11]=m>>>24&255,e[12]=b>>>0&255,e[13]=b>>>8&255,e[14]=b>>>16&255,e[15]=b>>>24&255,e[16]=h>>>0&255,e[17]=h>>>8&255,e[18]=h>>>16&255,e[19]=h>>>24&255,e[20]=d>>>0&255,e[21]=d>>>8&255,e[22]=d>>>16&255,e[23]=d>>>24&255,e[24]=p>>>0&255,e[25]=p>>>8&255,e[26]=p>>>16&255,e[27]=p>>>24&255,e[28]=f>>>0&255,e[29]=f>>>8&255,e[30]=f>>>16&255,e[31]=f>>>24&255}(e,t,r,i)}var b=new Uint8Array([101,120,112,97,110,100,32,51,50,45,98,121,116,101,32,107]);function E(e,t,r,i,n,a,o){var s,c,u=new Uint8Array(16),l=new Uint8Array(64);for(c=0;c<16;c++)u[c]=0;for(c=0;c<8;c++)u[c]=a[c];for(;n>=64;){for(v(l,u,o,b),c=0;c<64;c++)e[t+c]=r[i+c]^l[c];for(s=1,c=8;c<16;c++)s=s+(255&u[c])|0,u[c]=255&s,s>>>=8;n-=64,t+=64,i+=64}if(n>0)for(v(l,u,o,b),c=0;c=64;){for(v(c,s,n,b),o=0;o<64;o++)e[t+o]=c[o];for(a=1,o=8;o<16;o++)a=a+(255&s[o])|0,s[o]=255&a,a>>>=8;r-=64,t+=64}if(r>0)for(v(c,s,n,b),o=0;o>>13|r<<3),i=255&e[4]|(255&e[5])<<8,this.r[2]=7939&(r>>>10|i<<6),n=255&e[6]|(255&e[7])<<8,this.r[3]=8191&(i>>>7|n<<9),a=255&e[8]|(255&e[9])<<8,this.r[4]=255&(n>>>4|a<<12),this.r[5]=a>>>1&8190,o=255&e[10]|(255&e[11])<<8,this.r[6]=8191&(a>>>14|o<<2),s=255&e[12]|(255&e[13])<<8,this.r[7]=8065&(o>>>11|s<<5),c=255&e[14]|(255&e[15])<<8,this.r[8]=8191&(s>>>8|c<<8),this.r[9]=c>>>5&127,this.pad[0]=255&e[16]|(255&e[17])<<8,this.pad[1]=255&e[18]|(255&e[19])<<8,this.pad[2]=255&e[20]|(255&e[21])<<8,this.pad[3]=255&e[22]|(255&e[23])<<8,this.pad[4]=255&e[24]|(255&e[25])<<8,this.pad[5]=255&e[26]|(255&e[27])<<8,this.pad[6]=255&e[28]|(255&e[29])<<8,this.pad[7]=255&e[30]|(255&e[31])<<8};function M(e,t,r,i,n,a){var o=new x(a);return o.update(r,i,n),o.finish(e,t),0}function N(e,t,r,i,n,a){var o=new Uint8Array(16);return M(o,0,r,i,n,a),g(e,t,o,0)}function j(e,t,r,i,n){var a;if(r<32)return-1;for(k(e,0,t,0,r,i,n),M(e,16,e,32,r-32,e),a=0;a<16;a++)e[a]=0;return 0}function T(e,t,r,i,n){var a,o=new Uint8Array(32);if(r<32)return-1;if(S(o,0,32,i,n),0!==N(t,16,t,32,r-32,o))return-1;for(k(e,0,t,0,r,i,n),a=0;a<32;a++)e[a]=0;return 0}function R(e,t){var r;for(r=0;r<16;r++)e[r]=0|t[r]}function I(e){var t,r,i=1;for(t=0;t<16;t++)r=e[t]+i+65535,i=Math.floor(r/65536),e[t]=r-65536*i;e[0]+=i-1+37*(i-1)}function O(e,t,r){for(var i,n=~(r-1),a=0;a<16;a++)i=n&(e[a]^t[a]),e[a]^=i,t[a]^=i}function A(e,r){var i,n,a,o=t(),s=t();for(i=0;i<16;i++)s[i]=r[i];for(I(s),I(s),I(s),n=0;n<2;n++){for(o[0]=s[0]-65517,i=1;i<15;i++)o[i]=s[i]-65535-(o[i-1]>>16&1),o[i-1]&=65535;o[15]=s[15]-32767-(o[14]>>16&1),a=o[15]>>16&1,o[14]&=65535,O(s,o,1-a)}for(i=0;i<16;i++)e[2*i]=255&s[i],e[2*i+1]=s[i]>>8}function P(e,t){var r=new Uint8Array(32),i=new Uint8Array(32);return A(r,e),A(i,t),_(r,0,i,0)}function D(e){var t=new Uint8Array(32);return A(t,e),1&t[0]}function F(e,t){var r;for(r=0;r<16;r++)e[r]=t[2*r]+(t[2*r+1]<<8);e[15]&=32767}function C(e,t,r){for(var i=0;i<16;i++)e[i]=t[i]+r[i]}function B(e,t,r){for(var i=0;i<16;i++)e[i]=t[i]-r[i]}function z(e,t,r){var i,n,a=0,o=0,s=0,c=0,u=0,l=0,h=0,d=0,p=0,f=0,m=0,g=0,_=0,v=0,y=0,b=0,E=0,w=0,S=0,k=0,x=0,M=0,N=0,j=0,T=0,R=0,I=0,O=0,A=0,P=0,D=0,F=r[0],C=r[1],B=r[2],z=r[3],L=r[4],U=r[5],H=r[6],q=r[7],K=r[8],Z=r[9],W=r[10],X=r[11],Q=r[12],J=r[13],V=r[14],G=r[15];a+=(i=t[0])*F,o+=i*C,s+=i*B,c+=i*z,u+=i*L,l+=i*U,h+=i*H,d+=i*q,p+=i*K,f+=i*Z,m+=i*W,g+=i*X,_+=i*Q,v+=i*J,y+=i*V,b+=i*G,o+=(i=t[1])*F,s+=i*C,c+=i*B,u+=i*z,l+=i*L,h+=i*U,d+=i*H,p+=i*q,f+=i*K,m+=i*Z,g+=i*W,_+=i*X,v+=i*Q,y+=i*J,b+=i*V,E+=i*G,s+=(i=t[2])*F,c+=i*C,u+=i*B,l+=i*z,h+=i*L,d+=i*U,p+=i*H,f+=i*q,m+=i*K,g+=i*Z,_+=i*W,v+=i*X,y+=i*Q,b+=i*J,E+=i*V,w+=i*G,c+=(i=t[3])*F,u+=i*C,l+=i*B,h+=i*z,d+=i*L,p+=i*U,f+=i*H,m+=i*q,g+=i*K,_+=i*Z,v+=i*W,y+=i*X,b+=i*Q,E+=i*J,w+=i*V,S+=i*G,u+=(i=t[4])*F,l+=i*C,h+=i*B,d+=i*z,p+=i*L,f+=i*U,m+=i*H,g+=i*q,_+=i*K,v+=i*Z,y+=i*W,b+=i*X,E+=i*Q,w+=i*J,S+=i*V,k+=i*G,l+=(i=t[5])*F,h+=i*C,d+=i*B,p+=i*z,f+=i*L,m+=i*U,g+=i*H,_+=i*q,v+=i*K,y+=i*Z,b+=i*W,E+=i*X,w+=i*Q,S+=i*J,k+=i*V,x+=i*G,h+=(i=t[6])*F,d+=i*C,p+=i*B,f+=i*z,m+=i*L,g+=i*U,_+=i*H,v+=i*q,y+=i*K,b+=i*Z,E+=i*W,w+=i*X,S+=i*Q,k+=i*J,x+=i*V,M+=i*G,d+=(i=t[7])*F,p+=i*C,f+=i*B,m+=i*z,g+=i*L,_+=i*U,v+=i*H,y+=i*q,b+=i*K,E+=i*Z,w+=i*W,S+=i*X,k+=i*Q,x+=i*J,M+=i*V,N+=i*G,p+=(i=t[8])*F,f+=i*C,m+=i*B,g+=i*z,_+=i*L,v+=i*U,y+=i*H,b+=i*q,E+=i*K,w+=i*Z,S+=i*W,k+=i*X,x+=i*Q,M+=i*J,N+=i*V,j+=i*G,f+=(i=t[9])*F,m+=i*C,g+=i*B,_+=i*z,v+=i*L,y+=i*U,b+=i*H,E+=i*q,w+=i*K,S+=i*Z,k+=i*W,x+=i*X,M+=i*Q,N+=i*J,j+=i*V,T+=i*G,m+=(i=t[10])*F,g+=i*C,_+=i*B,v+=i*z,y+=i*L,b+=i*U,E+=i*H,w+=i*q,S+=i*K,k+=i*Z,x+=i*W,M+=i*X,N+=i*Q,j+=i*J,T+=i*V,R+=i*G,g+=(i=t[11])*F,_+=i*C,v+=i*B,y+=i*z,b+=i*L,E+=i*U,w+=i*H,S+=i*q,k+=i*K,x+=i*Z,M+=i*W,N+=i*X,j+=i*Q,T+=i*J,R+=i*V,I+=i*G,_+=(i=t[12])*F,v+=i*C,y+=i*B,b+=i*z,E+=i*L,w+=i*U,S+=i*H,k+=i*q,x+=i*K,M+=i*Z,N+=i*W,j+=i*X,T+=i*Q,R+=i*J,I+=i*V,O+=i*G,v+=(i=t[13])*F,y+=i*C,b+=i*B,E+=i*z,w+=i*L,S+=i*U,k+=i*H,x+=i*q,M+=i*K,N+=i*Z,j+=i*W,T+=i*X,R+=i*Q,I+=i*J,O+=i*V,A+=i*G,y+=(i=t[14])*F,b+=i*C,E+=i*B,w+=i*z,S+=i*L,k+=i*U,x+=i*H,M+=i*q,N+=i*K,j+=i*Z,T+=i*W,R+=i*X,I+=i*Q,O+=i*J,A+=i*V,P+=i*G,b+=(i=t[15])*F,o+=38*(w+=i*B),s+=38*(S+=i*z),c+=38*(k+=i*L),u+=38*(x+=i*U),l+=38*(M+=i*H),h+=38*(N+=i*q),d+=38*(j+=i*K),p+=38*(T+=i*Z),f+=38*(R+=i*W),m+=38*(I+=i*X),g+=38*(O+=i*Q),_+=38*(A+=i*J),v+=38*(P+=i*V),y+=38*(D+=i*G),a=(i=(a+=38*(E+=i*C))+(n=1)+65535)-65536*(n=Math.floor(i/65536)),o=(i=o+n+65535)-65536*(n=Math.floor(i/65536)),s=(i=s+n+65535)-65536*(n=Math.floor(i/65536)),c=(i=c+n+65535)-65536*(n=Math.floor(i/65536)),u=(i=u+n+65535)-65536*(n=Math.floor(i/65536)),l=(i=l+n+65535)-65536*(n=Math.floor(i/65536)),h=(i=h+n+65535)-65536*(n=Math.floor(i/65536)),d=(i=d+n+65535)-65536*(n=Math.floor(i/65536)),p=(i=p+n+65535)-65536*(n=Math.floor(i/65536)),f=(i=f+n+65535)-65536*(n=Math.floor(i/65536)),m=(i=m+n+65535)-65536*(n=Math.floor(i/65536)),g=(i=g+n+65535)-65536*(n=Math.floor(i/65536)),_=(i=_+n+65535)-65536*(n=Math.floor(i/65536)),v=(i=v+n+65535)-65536*(n=Math.floor(i/65536)),y=(i=y+n+65535)-65536*(n=Math.floor(i/65536)),b=(i=b+n+65535)-65536*(n=Math.floor(i/65536)),a=(i=(a+=n-1+37*(n-1))+(n=1)+65535)-65536*(n=Math.floor(i/65536)),o=(i=o+n+65535)-65536*(n=Math.floor(i/65536)),s=(i=s+n+65535)-65536*(n=Math.floor(i/65536)),c=(i=c+n+65535)-65536*(n=Math.floor(i/65536)),u=(i=u+n+65535)-65536*(n=Math.floor(i/65536)),l=(i=l+n+65535)-65536*(n=Math.floor(i/65536)),h=(i=h+n+65535)-65536*(n=Math.floor(i/65536)),d=(i=d+n+65535)-65536*(n=Math.floor(i/65536)),p=(i=p+n+65535)-65536*(n=Math.floor(i/65536)),f=(i=f+n+65535)-65536*(n=Math.floor(i/65536)),m=(i=m+n+65535)-65536*(n=Math.floor(i/65536)),g=(i=g+n+65535)-65536*(n=Math.floor(i/65536)),_=(i=_+n+65535)-65536*(n=Math.floor(i/65536)),v=(i=v+n+65535)-65536*(n=Math.floor(i/65536)),y=(i=y+n+65535)-65536*(n=Math.floor(i/65536)),b=(i=b+n+65535)-65536*(n=Math.floor(i/65536)),a+=n-1+37*(n-1),e[0]=a,e[1]=o,e[2]=s,e[3]=c,e[4]=u,e[5]=l,e[6]=h,e[7]=d,e[8]=p,e[9]=f,e[10]=m,e[11]=g,e[12]=_,e[13]=v,e[14]=y,e[15]=b}function L(e,t){z(e,t,t)}function U(e,r){var i,n=t();for(i=0;i<16;i++)n[i]=r[i];for(i=253;i>=0;i--)L(n,n),2!==i&&4!==i&&z(n,n,r);for(i=0;i<16;i++)e[i]=n[i]}function H(e,r,i){var n,a,o=new Uint8Array(32),s=new Float64Array(80),u=t(),l=t(),h=t(),d=t(),p=t(),f=t();for(a=0;a<31;a++)o[a]=r[a];for(o[31]=127&r[31]|64,o[0]&=248,F(s,i),a=0;a<16;a++)l[a]=s[a],d[a]=u[a]=h[a]=0;for(u[0]=d[0]=1,a=254;a>=0;--a)O(u,l,n=o[a>>>3]>>>(7&a)&1),O(h,d,n),C(p,u,h),B(u,u,h),C(h,l,d),B(l,l,d),L(d,p),L(f,u),z(u,h,u),z(h,l,p),C(p,u,h),B(u,u,h),L(l,u),B(h,d,f),z(u,h,c),C(u,u,d),z(h,h,u),z(u,d,f),z(d,l,s),L(l,p),O(u,l,n),O(h,d,n);for(a=0;a<16;a++)s[a+16]=u[a],s[a+32]=h[a],s[a+48]=l[a],s[a+64]=d[a];var m=s.subarray(32),g=s.subarray(16);return U(m,m),z(g,g,m),A(e,g),0}function q(e,t){return H(e,t,a)}function K(e,t){return i(t,32),q(e,t)}function Z(e,t,r){var i=new Uint8Array(32);return H(i,r,t),y(e,n,i,b)}x.prototype.blocks=function(e,t,r){for(var i,n,a,o,s,c,u,l,h,d,p,f,m,g,_,v,y,b,E,w=this.fin?0:2048,S=this.h[0],k=this.h[1],x=this.h[2],M=this.h[3],N=this.h[4],j=this.h[5],T=this.h[6],R=this.h[7],I=this.h[8],O=this.h[9],A=this.r[0],P=this.r[1],D=this.r[2],F=this.r[3],C=this.r[4],B=this.r[5],z=this.r[6],L=this.r[7],U=this.r[8],H=this.r[9];r>=16;)d=h=0,d+=(S+=8191&(i=255&e[t+0]|(255&e[t+1])<<8))*A,d+=(k+=8191&(i>>>13|(n=255&e[t+2]|(255&e[t+3])<<8)<<3))*(5*H),d+=(x+=8191&(n>>>10|(a=255&e[t+4]|(255&e[t+5])<<8)<<6))*(5*U),d+=(M+=8191&(a>>>7|(o=255&e[t+6]|(255&e[t+7])<<8)<<9))*(5*L),h=(d+=(N+=8191&(o>>>4|(s=255&e[t+8]|(255&e[t+9])<<8)<<12))*(5*z))>>>13,d&=8191,d+=(j+=s>>>1&8191)*(5*B),d+=(T+=8191&(s>>>14|(c=255&e[t+10]|(255&e[t+11])<<8)<<2))*(5*C),d+=(R+=8191&(c>>>11|(u=255&e[t+12]|(255&e[t+13])<<8)<<5))*(5*F),d+=(I+=8191&(u>>>8|(l=255&e[t+14]|(255&e[t+15])<<8)<<8))*(5*D),p=h+=(d+=(O+=l>>>5|w)*(5*P))>>>13,p+=S*P,p+=k*A,p+=x*(5*H),p+=M*(5*U),h=(p+=N*(5*L))>>>13,p&=8191,p+=j*(5*z),p+=T*(5*B),p+=R*(5*C),p+=I*(5*F),h+=(p+=O*(5*D))>>>13,p&=8191,f=h,f+=S*D,f+=k*P,f+=x*A,f+=M*(5*H),h=(f+=N*(5*U))>>>13,f&=8191,f+=j*(5*L),f+=T*(5*z),f+=R*(5*B),f+=I*(5*C),m=h+=(f+=O*(5*F))>>>13,m+=S*F,m+=k*D,m+=x*P,m+=M*A,h=(m+=N*(5*H))>>>13,m&=8191,m+=j*(5*U),m+=T*(5*L),m+=R*(5*z),m+=I*(5*B),g=h+=(m+=O*(5*C))>>>13,g+=S*C,g+=k*F,g+=x*D,g+=M*P,h=(g+=N*A)>>>13,g&=8191,g+=j*(5*H),g+=T*(5*U),g+=R*(5*L),g+=I*(5*z),_=h+=(g+=O*(5*B))>>>13,_+=S*B,_+=k*C,_+=x*F,_+=M*D,h=(_+=N*P)>>>13,_&=8191,_+=j*A,_+=T*(5*H),_+=R*(5*U),_+=I*(5*L),v=h+=(_+=O*(5*z))>>>13,v+=S*z,v+=k*B,v+=x*C,v+=M*F,h=(v+=N*D)>>>13,v&=8191,v+=j*P,v+=T*A,v+=R*(5*H),v+=I*(5*U),y=h+=(v+=O*(5*L))>>>13,y+=S*L,y+=k*z,y+=x*B,y+=M*C,h=(y+=N*F)>>>13,y&=8191,y+=j*D,y+=T*P,y+=R*A,y+=I*(5*H),b=h+=(y+=O*(5*U))>>>13,b+=S*U,b+=k*L,b+=x*z,b+=M*B,h=(b+=N*C)>>>13,b&=8191,b+=j*F,b+=T*D,b+=R*P,b+=I*A,E=h+=(b+=O*(5*H))>>>13,E+=S*H,E+=k*U,E+=x*L,E+=M*z,h=(E+=N*B)>>>13,E&=8191,E+=j*C,E+=T*F,E+=R*D,E+=I*P,S=d=8191&(h=(h=((h+=(E+=O*A)>>>13)<<2)+h|0)+(d&=8191)|0),k=p+=h>>>=13,x=f&=8191,M=m&=8191,N=g&=8191,j=_&=8191,T=v&=8191,R=y&=8191,I=b&=8191,O=E&=8191,t+=16,r-=16;this.h[0]=S,this.h[1]=k,this.h[2]=x,this.h[3]=M,this.h[4]=N,this.h[5]=j,this.h[6]=T,this.h[7]=R,this.h[8]=I,this.h[9]=O},x.prototype.finish=function(e,t){var r,i,n,a,o=new Uint16Array(10);if(this.leftover){for(a=this.leftover,this.buffer[a++]=1;a<16;a++)this.buffer[a]=0;this.fin=1,this.blocks(this.buffer,0,16)}for(r=this.h[1]>>>13,this.h[1]&=8191,a=2;a<10;a++)this.h[a]+=r,r=this.h[a]>>>13,this.h[a]&=8191;for(this.h[0]+=5*r,r=this.h[0]>>>13,this.h[0]&=8191,this.h[1]+=r,r=this.h[1]>>>13,this.h[1]&=8191,this.h[2]+=r,o[0]=this.h[0]+5,r=o[0]>>>13,o[0]&=8191,a=1;a<10;a++)o[a]=this.h[a]+r,r=o[a]>>>13,o[a]&=8191;for(o[9]-=8192,i=(1^r)-1,a=0;a<10;a++)o[a]&=i;for(i=~i,a=0;a<10;a++)this.h[a]=this.h[a]&i|o[a];for(this.h[0]=65535&(this.h[0]|this.h[1]<<13),this.h[1]=65535&(this.h[1]>>>3|this.h[2]<<10),this.h[2]=65535&(this.h[2]>>>6|this.h[3]<<7),this.h[3]=65535&(this.h[3]>>>9|this.h[4]<<4),this.h[4]=65535&(this.h[4]>>>12|this.h[5]<<1|this.h[6]<<14),this.h[5]=65535&(this.h[6]>>>2|this.h[7]<<11),this.h[6]=65535&(this.h[7]>>>5|this.h[8]<<8),this.h[7]=65535&(this.h[8]>>>8|this.h[9]<<5),n=this.h[0]+this.pad[0],this.h[0]=65535&n,a=1;a<8;a++)n=(this.h[a]+this.pad[a]|0)+(n>>>16)|0,this.h[a]=65535&n;e[t+0]=this.h[0]>>>0&255,e[t+1]=this.h[0]>>>8&255,e[t+2]=this.h[1]>>>0&255,e[t+3]=this.h[1]>>>8&255,e[t+4]=this.h[2]>>>0&255,e[t+5]=this.h[2]>>>8&255,e[t+6]=this.h[3]>>>0&255,e[t+7]=this.h[3]>>>8&255,e[t+8]=this.h[4]>>>0&255,e[t+9]=this.h[4]>>>8&255,e[t+10]=this.h[5]>>>0&255,e[t+11]=this.h[5]>>>8&255,e[t+12]=this.h[6]>>>0&255,e[t+13]=this.h[6]>>>8&255,e[t+14]=this.h[7]>>>0&255,e[t+15]=this.h[7]>>>8&255},x.prototype.update=function(e,t,r){var i,n;if(this.leftover){for((n=16-this.leftover)>r&&(n=r),i=0;i=16&&(n=r-r%16,this.blocks(e,t,n),t+=n,r-=n),r){for(i=0;i=128;){for(w=0;w<16;w++)S=8*w+J,R[w]=r[S+0]<<24|r[S+1]<<16|r[S+2]<<8|r[S+3],I[w]=r[S+4]<<24|r[S+5]<<16|r[S+6]<<8|r[S+7];for(w=0;w<80;w++)if(n=O,a=A,o=P,s=D,c=F,u=C,l=B,z,d=L,p=U,f=H,m=q,g=K,_=Z,v=W,X,M=65535&(x=X),N=x>>>16,j=65535&(k=z),T=k>>>16,M+=65535&(x=(K>>>14|F<<18)^(K>>>18|F<<14)^(F>>>9|K<<23)),N+=x>>>16,j+=65535&(k=(F>>>14|K<<18)^(F>>>18|K<<14)^(K>>>9|F<<23)),T+=k>>>16,M+=65535&(x=K&Z^~K&W),N+=x>>>16,j+=65535&(k=F&C^~F&B),T+=k>>>16,M+=65535&(x=Q[2*w+1]),N+=x>>>16,j+=65535&(k=Q[2*w]),T+=k>>>16,k=R[w%16],N+=(x=I[w%16])>>>16,j+=65535&k,T+=k>>>16,j+=(N+=(M+=65535&x)>>>16)>>>16,M=65535&(x=E=65535&M|N<<16),N=x>>>16,j=65535&(k=b=65535&j|(T+=j>>>16)<<16),T=k>>>16,M+=65535&(x=(L>>>28|O<<4)^(O>>>2|L<<30)^(O>>>7|L<<25)),N+=x>>>16,j+=65535&(k=(O>>>28|L<<4)^(L>>>2|O<<30)^(L>>>7|O<<25)),T+=k>>>16,N+=(x=L&U^L&H^U&H)>>>16,j+=65535&(k=O&A^O&P^A&P),T+=k>>>16,h=65535&(j+=(N+=(M+=65535&x)>>>16)>>>16)|(T+=j>>>16)<<16,y=65535&M|N<<16,M=65535&(x=m),N=x>>>16,j=65535&(k=s),T=k>>>16,N+=(x=E)>>>16,j+=65535&(k=b),T+=k>>>16,A=n,P=a,D=o,F=s=65535&(j+=(N+=(M+=65535&x)>>>16)>>>16)|(T+=j>>>16)<<16,C=c,B=u,z=l,O=h,U=d,H=p,q=f,K=m=65535&M|N<<16,Z=g,W=_,X=v,L=y,w%16==15)for(S=0;S<16;S++)k=R[S],M=65535&(x=I[S]),N=x>>>16,j=65535&k,T=k>>>16,k=R[(S+9)%16],M+=65535&(x=I[(S+9)%16]),N+=x>>>16,j+=65535&k,T+=k>>>16,b=R[(S+1)%16],M+=65535&(x=((E=I[(S+1)%16])>>>1|b<<31)^(E>>>8|b<<24)^(E>>>7|b<<25)),N+=x>>>16,j+=65535&(k=(b>>>1|E<<31)^(b>>>8|E<<24)^b>>>7),T+=k>>>16,b=R[(S+14)%16],N+=(x=((E=I[(S+14)%16])>>>19|b<<13)^(b>>>29|E<<3)^(E>>>6|b<<26))>>>16,j+=65535&(k=(b>>>19|E<<13)^(E>>>29|b<<3)^b>>>6),T+=k>>>16,T+=(j+=(N+=(M+=65535&x)>>>16)>>>16)>>>16,R[S]=65535&j|T<<16,I[S]=65535&M|N<<16;M=65535&(x=L),N=x>>>16,j=65535&(k=O),T=k>>>16,k=e[0],N+=(x=t[0])>>>16,j+=65535&k,T+=k>>>16,T+=(j+=(N+=(M+=65535&x)>>>16)>>>16)>>>16,e[0]=O=65535&j|T<<16,t[0]=L=65535&M|N<<16,M=65535&(x=U),N=x>>>16,j=65535&(k=A),T=k>>>16,k=e[1],N+=(x=t[1])>>>16,j+=65535&k,T+=k>>>16,T+=(j+=(N+=(M+=65535&x)>>>16)>>>16)>>>16,e[1]=A=65535&j|T<<16,t[1]=U=65535&M|N<<16,M=65535&(x=H),N=x>>>16,j=65535&(k=P),T=k>>>16,k=e[2],N+=(x=t[2])>>>16,j+=65535&k,T+=k>>>16,T+=(j+=(N+=(M+=65535&x)>>>16)>>>16)>>>16,e[2]=P=65535&j|T<<16,t[2]=H=65535&M|N<<16,M=65535&(x=q),N=x>>>16,j=65535&(k=D),T=k>>>16,k=e[3],N+=(x=t[3])>>>16,j+=65535&k,T+=k>>>16,T+=(j+=(N+=(M+=65535&x)>>>16)>>>16)>>>16,e[3]=D=65535&j|T<<16,t[3]=q=65535&M|N<<16,M=65535&(x=K),N=x>>>16,j=65535&(k=F),T=k>>>16,k=e[4],N+=(x=t[4])>>>16,j+=65535&k,T+=k>>>16,T+=(j+=(N+=(M+=65535&x)>>>16)>>>16)>>>16,e[4]=F=65535&j|T<<16,t[4]=K=65535&M|N<<16,M=65535&(x=Z),N=x>>>16,j=65535&(k=C),T=k>>>16,k=e[5],N+=(x=t[5])>>>16,j+=65535&k,T+=k>>>16,T+=(j+=(N+=(M+=65535&x)>>>16)>>>16)>>>16,e[5]=C=65535&j|T<<16,t[5]=Z=65535&M|N<<16,M=65535&(x=W),N=x>>>16,j=65535&(k=B),T=k>>>16,k=e[6],N+=(x=t[6])>>>16,j+=65535&k,T+=k>>>16,T+=(j+=(N+=(M+=65535&x)>>>16)>>>16)>>>16,e[6]=B=65535&j|T<<16,t[6]=W=65535&M|N<<16,M=65535&(x=X),N=x>>>16,j=65535&(k=z),T=k>>>16,k=e[7],N+=(x=t[7])>>>16,j+=65535&k,T+=k>>>16,T+=(j+=(N+=(M+=65535&x)>>>16)>>>16)>>>16,e[7]=z=65535&j|T<<16,t[7]=X=65535&M|N<<16,J+=128,i-=128}return i}function V(e,t,r){var i,n=new Int32Array(8),a=new Int32Array(8),o=new Uint8Array(256),s=r;for(n[0]=1779033703,n[1]=3144134277,n[2]=1013904242,n[3]=2773480762,n[4]=1359893119,n[5]=2600822924,n[6]=528734635,n[7]=1541459225,a[0]=4089235720,a[1]=2227873595,a[2]=4271175723,a[3]=1595750129,a[4]=2917565137,a[5]=725511199,a[6]=4215389547,a[7]=327033209,J(n,a,t,r),r%=128,i=0;i=0;--n)Y(e,t,i=r[n/8|0]>>(7&n)&1),G(t,e),G(e,e),Y(e,t,i)}function te(e,r){var i=[t(),t(),t(),t()];R(i[0],h),R(i[1],d),R(i[2],s),z(i[3],h,d),ee(e,i,r)}function re(e,r,n){var a,o=new Uint8Array(64),s=[t(),t(),t(),t()];for(n||i(r,32),V(o,r,32),o[0]&=248,o[31]&=127,o[31]|=64,te(s,o),$(e,s),a=0;a<32;a++)r[a+32]=e[a];return 0}var ie=new Float64Array([237,211,245,92,26,99,18,88,214,156,247,162,222,249,222,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16]);function ne(e,t){var r,i,n,a;for(i=63;i>=32;--i){for(r=0,n=i-32,a=i-12;n>8,t[n]-=256*r;t[n]+=r,t[i]=0}for(r=0,n=0;n<32;n++)t[n]+=r-(t[31]>>4)*ie[n],r=t[n]>>8,t[n]&=255;for(n=0;n<32;n++)t[n]-=r*ie[n];for(i=0;i<32;i++)t[i+1]+=t[i]>>8,e[i]=255&t[i]}function ae(e){var t,r=new Float64Array(64);for(t=0;t<64;t++)r[t]=e[t];for(t=0;t<64;t++)e[t]=0;ne(e,r)}function oe(e,r,i,n){var a,o,s=new Uint8Array(64),c=new Uint8Array(64),u=new Uint8Array(64),l=new Float64Array(64),h=[t(),t(),t(),t()];V(s,n,32),s[0]&=248,s[31]&=127,s[31]|=64;var d=i+64;for(a=0;a=0;i--)L(n,n),1!==i&&z(n,n,r);for(i=0;i<16;i++)e[i]=n[i]}(i,i),z(i,i,a),z(i,i,c),z(i,i,c),z(e[0],i,c),L(n,e[0]),z(n,n,c),P(n,a)&&z(e[0],e[0],p),L(n,e[0]),z(n,n,c),P(n,a)?-1:(D(e[0])===r[31]>>7&&B(e[0],o,e[0]),z(e[3],e[0],e[1]),0)}function ce(e,r,i,n){var a,o=new Uint8Array(32),s=new Uint8Array(64),c=[t(),t(),t(),t()],u=[t(),t(),t(),t()];if(-1,i<64)return-1;if(se(u,n))return-1;for(a=0;a=0},e.sign.keyPair=function(){var e=new Uint8Array(32),t=new Uint8Array(64);return re(e,t),{publicKey:e,secretKey:t}},e.sign.keyPair.fromSecretKey=function(e){if(le(e),64!==e.length)throw new Error("bad secret key size");for(var t=new Uint8Array(32),r=0;r>15;--a>=0;){var c=32767&this[e],u=this[e++]>>15,l=s*c+u*o;n=((c=o*c+((32767&l)<<15)+r[i]+(1073741823&n))>>>30)+(l>>>15)+s*u+(n>>>30),r[i++]=1073741823&c}return n},t=30):n&&"Netscape"!=navigator.appName?(r.prototype.am=function(e,t,r,i,n,a){for(;--a>=0;){var o=t*this[e++]+r[i]+n;n=Math.floor(o/67108864),r[i++]=67108863&o}return n},t=26):(r.prototype.am=function(e,t,r,i,n,a){for(var o=16383&t,s=t>>14;--a>=0;){var c=16383&this[e],u=this[e++]>>14,l=s*c+u*o;n=((c=o*c+((16383&l)<<14)+r[i]+n)>>28)+(l>>14)+s*u,r[i++]=268435455&c}return n},t=28),r.prototype.DB=t,r.prototype.DM=(1<>>16)&&(e=t,r+=16),0!=(t=e>>8)&&(e=t,r+=8),0!=(t=e>>4)&&(e=t,r+=4),0!=(t=e>>2)&&(e=t,r+=2),0!=(t=e>>1)&&(e=t,r+=1),r}function d(e){this.m=e}function p(e){this.m=e,this.mp=e.invDigit(),this.mpl=32767&this.mp,this.mph=this.mp>>15,this.um=(1<>=16,t+=16),0==(255&e)&&(e>>=8,t+=8),0==(15&e)&&(e>>=4,t+=4),0==(3&e)&&(e>>=2,t+=2),0==(1&e)&&++t,t}function y(e){for(var t=0;0!=e;)e&=e-1,++t;return t}function b(){}function E(e){return e}function w(e){this.r2=i(),this.q3=i(),r.ONE.dlShiftTo(2*e.t,this.r2),this.mu=this.r2.divide(e),this.m=e}d.prototype.convert=function(e){return e.s<0||e.compareTo(this.m)>=0?e.mod(this.m):e},d.prototype.revert=function(e){return e},d.prototype.reduce=function(e){e.divRemTo(this.m,null,e)},d.prototype.mulTo=function(e,t,r){e.multiplyTo(t,r),this.reduce(r)},d.prototype.sqrTo=function(e,t){e.squareTo(t),this.reduce(t)},p.prototype.convert=function(e){var t=i();return e.abs().dlShiftTo(this.m.t,t),t.divRemTo(this.m,null,t),e.s<0&&t.compareTo(r.ZERO)>0&&this.m.subTo(t,t),t},p.prototype.revert=function(e){var t=i();return e.copyTo(t),this.reduce(t),t},p.prototype.reduce=function(e){for(;e.t<=this.mt2;)e[e.t++]=0;for(var t=0;t>15)*this.mpl&this.um)<<15)&e.DM;for(e[r=t+this.m.t]+=this.m.am(0,i,e,t,0,this.m.t);e[r]>=e.DV;)e[r]-=e.DV,e[++r]++}e.clamp(),e.drShiftTo(this.m.t,e),e.compareTo(this.m)>=0&&e.subTo(this.m,e)},p.prototype.mulTo=function(e,t,r){e.multiplyTo(t,r),this.reduce(r)},p.prototype.sqrTo=function(e,t){e.squareTo(t),this.reduce(t)},r.prototype.copyTo=function(e){for(var t=this.t-1;t>=0;--t)e[t]=this[t];e.t=this.t,e.s=this.s},r.prototype.fromInt=function(e){this.t=1,this.s=e<0?-1:0,e>0?this[0]=e:e<-1?this[0]=e+this.DV:this.t=0},r.prototype.fromString=function(e,t){var i;if(16==t)i=4;else if(8==t)i=3;else if(256==t)i=8;else if(2==t)i=1;else if(32==t)i=5;else{if(4!=t)return void this.fromRadix(e,t);i=2}this.t=0,this.s=0;for(var n=e.length,a=!1,o=0;--n>=0;){var s=8==i?255&e[n]:u(e,n);s<0?"-"==e.charAt(n)&&(a=!0):(a=!1,0==o?this[this.t++]=s:o+i>this.DB?(this[this.t-1]|=(s&(1<>this.DB-o):this[this.t-1]|=s<=this.DB&&(o-=this.DB))}8==i&&0!=(128&e[0])&&(this.s=-1,o>0&&(this[this.t-1]|=(1<0&&this[this.t-1]==e;)--this.t},r.prototype.dlShiftTo=function(e,t){var r;for(r=this.t-1;r>=0;--r)t[r+e]=this[r];for(r=e-1;r>=0;--r)t[r]=0;t.t=this.t+e,t.s=this.s},r.prototype.drShiftTo=function(e,t){for(var r=e;r=0;--r)t[r+o+1]=this[r]>>n|s,s=(this[r]&a)<=0;--r)t[r]=0;t[o]=s,t.t=this.t+o+1,t.s=this.s,t.clamp()},r.prototype.rShiftTo=function(e,t){t.s=this.s;var r=Math.floor(e/this.DB);if(r>=this.t)t.t=0;else{var i=e%this.DB,n=this.DB-i,a=(1<>i;for(var o=r+1;o>i;i>0&&(t[this.t-r-1]|=(this.s&a)<>=this.DB;if(e.t>=this.DB;i+=this.s}else{for(i+=this.s;r>=this.DB;i-=e.s}t.s=i<0?-1:0,i<-1?t[r++]=this.DV+i:i>0&&(t[r++]=i),t.t=r,t.clamp()},r.prototype.multiplyTo=function(e,t){var i=this.abs(),n=e.abs(),a=i.t;for(t.t=a+n.t;--a>=0;)t[a]=0;for(a=0;a=0;)e[r]=0;for(r=0;r=t.DV&&(e[r+t.t]-=t.DV,e[r+t.t+1]=1)}e.t>0&&(e[e.t-1]+=t.am(r,t[r],e,2*r,0,1)),e.s=0,e.clamp()},r.prototype.divRemTo=function(e,t,n){var a=e.abs();if(!(a.t<=0)){var o=this.abs();if(o.t0?(a.lShiftTo(l,s),o.lShiftTo(l,n)):(a.copyTo(s),o.copyTo(n));var d=s.t,p=s[d-1];if(0!=p){var f=p*(1<1?s[d-2]>>this.F2:0),m=this.FV/f,g=(1<=0&&(n[n.t++]=1,n.subTo(b,n)),r.ONE.dlShiftTo(d,b),b.subTo(s,s);s.t=0;){var E=n[--v]==p?this.DM:Math.floor(n[v]*m+(n[v-1]+_)*g);if((n[v]+=s.am(0,E,n,y,0,d))0&&n.rShiftTo(l,n),c<0&&r.ZERO.subTo(n,n)}}},r.prototype.invDigit=function(){if(this.t<1)return 0;var e=this[0];if(0==(1&e))return 0;var t=3&e;return(t=(t=(t=(t=t*(2-(15&e)*t)&15)*(2-(255&e)*t)&255)*(2-((65535&e)*t&65535))&65535)*(2-e*t%this.DV)%this.DV)>0?this.DV-t:-t},r.prototype.isEven=function(){return 0==(this.t>0?1&this[0]:this.s)},r.prototype.exp=function(e,t){if(e>4294967295||e<1)return r.ONE;var n=i(),a=i(),o=t.convert(this),s=h(e)-1;for(o.copyTo(n);--s>=0;)if(t.sqrTo(n,a),(e&1<0)t.mulTo(a,o,n);else{var c=n;n=a,a=c}return t.revert(n)},r.prototype.toString=function(e){if(this.s<0)return"-"+this.negate().toString(e);var t;if(16==e)t=4;else if(8==e)t=3;else if(2==e)t=1;else if(32==e)t=5;else{if(4!=e)return this.toRadix(e);t=2}var r,i=(1<0)for(s>s)>0&&(n=!0,a=c(r));o>=0;)s>(s+=this.DB-t)):(r=this[o]>>(s-=t)&i,s<=0&&(s+=this.DB,--o)),r>0&&(n=!0),n&&(a+=c(r));return n?a:"0"},r.prototype.negate=function(){var e=i();return r.ZERO.subTo(this,e),e},r.prototype.abs=function(){return this.s<0?this.negate():this},r.prototype.compareTo=function(e){var t=this.s-e.s;if(0!=t)return t;var r=this.t;if(0!=(t=r-e.t))return this.s<0?-t:t;for(;--r>=0;)if(0!=(t=this[r]-e[r]))return t;return 0},r.prototype.bitLength=function(){return this.t<=0?0:this.DB*(this.t-1)+h(this[this.t-1]^this.s&this.DM)},r.prototype.mod=function(e){var t=i();return this.abs().divRemTo(e,null,t),this.s<0&&t.compareTo(r.ZERO)>0&&e.subTo(t,t),t},r.prototype.modPowInt=function(e,t){var r;return r=e<256||t.isEven()?new d(t):new p(t),this.exp(e,r)},r.ZERO=l(0),r.ONE=l(1),b.prototype.convert=E,b.prototype.revert=E,b.prototype.mulTo=function(e,t,r){e.multiplyTo(t,r)},b.prototype.sqrTo=function(e,t){e.squareTo(t)},w.prototype.convert=function(e){if(e.s<0||e.t>2*this.m.t)return e.mod(this.m);if(e.compareTo(this.m)<0)return e;var t=i();return e.copyTo(t),this.reduce(t),t},w.prototype.revert=function(e){return e},w.prototype.reduce=function(e){for(e.drShiftTo(this.m.t-1,this.r2),e.t>this.m.t+1&&(e.t=this.m.t+1,e.clamp()),this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3),this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);e.compareTo(this.r2)<0;)e.dAddOffset(1,this.m.t+1);for(e.subTo(this.r2,e);e.compareTo(this.m)>=0;)e.subTo(this.m,e)},w.prototype.mulTo=function(e,t,r){e.multiplyTo(t,r),this.reduce(r)},w.prototype.sqrTo=function(e,t){e.squareTo(t),this.reduce(t)};var S,k,x,M=[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997],N=(1<<26)/M[M.length-1];function j(){var e;e=(new Date).getTime(),k[x++]^=255&e,k[x++]^=e>>8&255,k[x++]^=e>>16&255,k[x++]^=e>>24&255,x>=D&&(x-=D)}if(r.prototype.chunkSize=function(e){return Math.floor(Math.LN2*this.DB/Math.log(e))},r.prototype.toRadix=function(e){if(null==e&&(e=10),0==this.signum()||e<2||e>36)return"0";var t=this.chunkSize(e),r=Math.pow(e,t),n=l(r),a=i(),o=i(),s="";for(this.divRemTo(n,a,o);a.signum()>0;)s=(r+o.intValue()).toString(e).substr(1)+s,a.divRemTo(n,a,o);return o.intValue().toString(e)+s},r.prototype.fromRadix=function(e,t){this.fromInt(0),null==t&&(t=10);for(var i=this.chunkSize(t),n=Math.pow(t,i),a=!1,o=0,s=0,c=0;c=i&&(this.dMultiply(n),this.dAddOffset(s,0),o=0,s=0))}o>0&&(this.dMultiply(Math.pow(t,o)),this.dAddOffset(s,0)),a&&r.ZERO.subTo(this,this)},r.prototype.fromNumber=function(e,t,i){if("number"==typeof t)if(e<2)this.fromInt(1);else for(this.fromNumber(e,i),this.testBit(e-1)||this.bitwiseTo(r.ONE.shiftLeft(e-1),m,this),this.isEven()&&this.dAddOffset(1,0);!this.isProbablePrime(t);)this.dAddOffset(2,0),this.bitLength()>e&&this.subTo(r.ONE.shiftLeft(e-1),this);else{var n=new Array,a=7&e;n.length=1+(e>>3),t.nextBytes(n),a>0?n[0]&=(1<>=this.DB;if(e.t>=this.DB;i+=this.s}else{for(i+=this.s;r>=this.DB;i+=e.s}t.s=i<0?-1:0,i>0?t[r++]=i:i<-1&&(t[r++]=this.DV+i),t.t=r,t.clamp()},r.prototype.dMultiply=function(e){this[this.t]=this.am(0,e-1,this,0,0,this.t),++this.t,this.clamp()},r.prototype.dAddOffset=function(e,t){if(0!=e){for(;this.t<=t;)this[this.t++]=0;for(this[t]+=e;this[t]>=this.DV;)this[t]-=this.DV,++t>=this.t&&(this[this.t++]=0),++this[t]}},r.prototype.multiplyLowerTo=function(e,t,r){var i,n=Math.min(this.t+e.t,t);for(r.s=0,r.t=n;n>0;)r[--n]=0;for(i=r.t-this.t;n=0;)r[i]=0;for(i=Math.max(t-this.t,0);i0)if(0==t)r=this[0]%e;else for(var i=this.t-1;i>=0;--i)r=(t*r+this[i])%e;return r},r.prototype.millerRabin=function(e){var t=this.subtract(r.ONE),n=t.getLowestSetBit();if(n<=0)return!1;var a=t.shiftRight(n);(e=e+1>>1)>M.length&&(e=M.length);for(var o=i(),s=0;s>24},r.prototype.shortValue=function(){return 0==this.t?this.s:this[0]<<16>>16},r.prototype.signum=function(){return this.s<0?-1:this.t<=0||1==this.t&&this[0]<=0?0:1},r.prototype.toByteArray=function(){var e=this.t,t=new Array;t[0]=this.s;var r,i=this.DB-e*this.DB%8,n=0;if(e-- >0)for(i>i)!=(this.s&this.DM)>>i&&(t[n++]=r|this.s<=0;)i<8?(r=(this[e]&(1<>(i+=this.DB-8)):(r=this[e]>>(i-=8)&255,i<=0&&(i+=this.DB,--e)),0!=(128&r)&&(r|=-256),0==n&&(128&this.s)!=(128&r)&&++n,(n>0||r!=this.s)&&(t[n++]=r);return t},r.prototype.equals=function(e){return 0==this.compareTo(e)},r.prototype.min=function(e){return this.compareTo(e)<0?this:e},r.prototype.max=function(e){return this.compareTo(e)>0?this:e},r.prototype.and=function(e){var t=i();return this.bitwiseTo(e,f,t),t},r.prototype.or=function(e){var t=i();return this.bitwiseTo(e,m,t),t},r.prototype.xor=function(e){var t=i();return this.bitwiseTo(e,g,t),t},r.prototype.andNot=function(e){var t=i();return this.bitwiseTo(e,_,t),t},r.prototype.not=function(){for(var e=i(),t=0;t=this.t?0!=this.s:0!=(this[t]&1<1){var m=i();for(n.sqrTo(s[1],m);c<=f;)s[c]=i(),n.mulTo(m,s[c-2],s[c]),c+=2}var g,_,v=e.t-1,y=!0,b=i();for(a=h(e[v])-1;v>=0;){for(a>=u?g=e[v]>>a-u&f:(g=(e[v]&(1<0&&(g|=e[v-1]>>this.DB+a-u)),c=r;0==(1&g);)g>>=1,--c;if((a-=c)<0&&(a+=this.DB,--v),y)s[g].copyTo(o),y=!1;else{for(;c>1;)n.sqrTo(o,b),n.sqrTo(b,o),c-=2;c>0?n.sqrTo(o,b):(_=o,o=b,b=_),n.mulTo(b,s[g],o)}for(;v>=0&&0==(e[v]&1<=0?(i.subTo(n,i),t&&a.subTo(s,a),o.subTo(c,o)):(n.subTo(i,n),t&&s.subTo(a,s),c.subTo(o,c))}return 0!=n.compareTo(r.ONE)?r.ZERO:c.compareTo(e)>=0?c.subtract(e):c.signum()<0?(c.addTo(e,c),c.signum()<0?c.add(e):c):c},r.prototype.pow=function(e){return this.exp(e,new b)},r.prototype.gcd=function(e){var t=this.s<0?this.negate():this.clone(),r=e.s<0?e.negate():e.clone();if(t.compareTo(r)<0){var i=t;t=r,r=i}var n=t.getLowestSetBit(),a=r.getLowestSetBit();if(a<0)return t;for(n0&&(t.rShiftTo(a,t),r.rShiftTo(a,r));t.signum()>0;)(n=t.getLowestSetBit())>0&&t.rShiftTo(n,t),(n=r.getLowestSetBit())>0&&r.rShiftTo(n,r),t.compareTo(r)>=0?(t.subTo(r,t),t.rShiftTo(1,t)):(r.subTo(t,r),r.rShiftTo(1,r));return a>0&&r.lShiftTo(a,r),r},r.prototype.isProbablePrime=function(e){var t,r=this.abs();if(1==r.t&&r[0]<=M[M.length-1]){for(t=0;t>>8,k[x++]=255&T;x=0,j()}function O(){if(null==S){for(j(),(S=new P).init(k),x=0;x=this._buffer.length},a.prototype.remainder=function(){return this._buffer.slice(this._offset)},a.prototype.skip=function(e){this._offset+=e},a.prototype.expand=function(){this._size*=2;var e=n.alloc(this._size);this._buffer.copy(e,0),this._buffer=e},a.prototype.readPart=function(){return{data:this.readBuffer()}},a.prototype.readBuffer=function(){var e=this._buffer.readUInt32BE(this._offset);this._offset+=4,i.ok(this._offset+e<=this._buffer.length,"length out of bounds at +0x"+this._offset.toString(16)+" (data truncated?)");var t=this._buffer.slice(this._offset,this._offset+e);return this._offset+=e,t},a.prototype.readString=function(){return this.readBuffer().toString()},a.prototype.readCString=function(){for(var e=this._offset;ethis._size;)this.expand();this._buffer.writeUInt32BE(e.length,this._offset),this._offset+=4,e.copy(this._buffer,this._offset),this._offset+=e.length},a.prototype.writeString=function(e){this.writeBuffer(n.from(e,"utf8"))},a.prototype.writeCString=function(e){for(;this._offset+1+e.length>this._size;)this.expand();this._buffer.write(e,this._offset),this._offset+=e.length,this._buffer[this._offset++]=0},a.prototype.writeInt=function(e){for(;this._offset+4>this._size;)this.expand();this._buffer.writeUInt32BE(e,this._offset),this._offset+=4},a.prototype.writeInt64=function(e){if(i.buffer(e,"value"),e.length>8){for(var t=e.slice(0,e.length-8),r=0;rthis._size;)this.expand();e.copy(this._buffer,this._offset),this._offset+=8},a.prototype.writeChar=function(e){for(;this._offset+1>this._size;)this.expand();this._buffer[this._offset++]=e},a.prototype.writePart=function(e){this.writeBuffer(e.data)},a.prototype.write=function(e){for(;this._offset+e.length>this._size;)this.expand();e.copy(this._buffer,this._offset),this._offset+=e.length}},function(e,t,r){e.exports=l;var i=r(6),n=(r(16),r(10),r(66),r(30),r(29),r(11),r(13)),a=r(31),o=r(9).Buffer,s=/^([*]|[a-z0-9][a-z0-9\-]{0,62})(?:\.([*]|[a-z0-9][a-z0-9\-]{0,62}))*$/i,c={cn:"2.5.4.3",o:"2.5.4.10",ou:"2.5.4.11",l:"2.5.4.7",s:"2.5.4.8",c:"2.5.4.6",sn:"2.5.4.4",postalCode:"2.5.4.17",serialNumber:"2.5.4.5",street:"2.5.4.9",x500UniqueIdentifier:"2.5.4.45",role:"2.5.4.72",telephoneNumber:"2.5.4.20",description:"2.5.4.13",dc:"0.9.2342.19200300.100.1.25",uid:"0.9.2342.19200300.100.1.1",mail:"0.9.2342.19200300.100.1.3",title:"2.5.4.12",gn:"2.5.4.42",initials:"2.5.4.43",pseudonym:"2.5.4.65",emailAddress:"1.2.840.113549.1.9.1"},u={};function l(e){var t=this;if(i.object(e,"options"),i.arrayOfObject(e.components,"options.components"),this.components=e.components,this.componentLookup={},this.components.forEach((function(e){e.name&&!e.oid&&(e.oid=c[e.name]),e.oid&&!e.name&&(e.name=u[e.oid]),void 0===t.componentLookup[e.name]&&(t.componentLookup[e.name]=[]),t.componentLookup[e.name].push(e)})),this.componentLookup.cn&&this.componentLookup.cn.length>0&&(this.cn=this.componentLookup.cn[0].value),i.optionalString(e.type,"options.type"),void 0===e.type)1===this.components.length&&this.componentLookup.cn&&1===this.componentLookup.cn.length&&this.componentLookup.cn[0].value.match(s)?(this.type="host",this.hostname=this.componentLookup.cn[0].value):this.componentLookup.dc&&this.components.length===this.componentLookup.dc.length?(this.type="host",this.hostname=this.componentLookup.dc.map((function(e){return e.value})).join(".")):this.componentLookup.uid&&this.components.length===this.componentLookup.uid.length?(this.type="user",this.uid=this.componentLookup.uid[0].value):this.componentLookup.cn&&1===this.componentLookup.cn.length&&this.componentLookup.cn[0].value.match(s)?(this.type="host",this.hostname=this.componentLookup.cn[0].value):this.componentLookup.uid&&1===this.componentLookup.uid.length?(this.type="user",this.uid=this.componentLookup.uid[0].value):this.componentLookup.mail&&1===this.componentLookup.mail.length?(this.type="email",this.email=this.componentLookup.mail[0].value):this.componentLookup.cn&&1===this.componentLookup.cn.length?(this.type="user",this.uid=this.componentLookup.cn[0].value):this.type="unknown";else if(this.type=e.type,"host"===this.type)this.hostname=e.hostname;else if("user"===this.type)this.uid=e.uid;else{if("email"!==this.type)throw new Error("Unknown type "+this.type);this.email=e.email}}Object.keys(c).forEach((function(e){u[c[e]]=e})),l.prototype.toString=function(){return this.components.map((function(e){var t=e.name.toUpperCase();t=t.replace(/=/g,"\\=");var r=e.value;return t+"="+(r=r.replace(/,/g,"\\,"))})).join(", ")},l.prototype.get=function(e,t){i.string(e,"name");var r=this.componentLookup[e];if(void 0!==r&&0!==r.length){if(!t&&r.length>1)throw new Error("Multiple values for attribute "+e);return t?r.map((function(e){return e.value})):r[0].value}},l.prototype.toArray=function(e){return this.components.map((function(e){return{name:e.name,value:e.value}}))};var h=/[^a-zA-Z0-9 '(),+.\/:=?-]/,d=/[^\x00-\x7f]/;function p(e,t){if("**"===e||"**"===t)return!0;var r=e.split("."),i=t.split(".");if(r.length!==i.length)return!1;for(var n=0;n0;){var a;if(null!==(a=/^,/.exec(n)))t[++r]="",n=n.slice(a[0].length);else if(null!==(a=/^\\,/.exec(n)))t[r]+=",",n=n.slice(a[0].length);else if(null!==(a=/^\\./.exec(n)))t[r]+=a[0],n=n.slice(a[0].length);else{if(null===(a=/^[^\\,]+/.exec(n)))throw new Error("Failed to parse DN");t[r]+=a[0],n=n.slice(a[0].length)}}return new l({components:t.map((function(e){for(var t=(e=e.trim()).indexOf("=");t>0&&"\\"===e.charAt(t-1);)t=e.indexOf("=",t+1);if(-1===t)throw new Error("Failed to parse DN");return{name:e.slice(0,t).toLowerCase().replace(/\\=/g,"="),value:e.slice(t+1)}}))})},l.fromArray=function(e){return i.arrayOfObject(e,"components"),e.forEach((function(e){if(i.object(e,"component"),i.string(e.name,"component.name"),!o.isBuffer(e.value)&&"string"!=typeof e.value)throw new Error("Invalid component value")})),new l({components:e})},l.parseAsn1=function(e,t){var r=[];e.readSequence(t);for(var i=e.offset+e.length;e.offset1)throw new a("MoneroTxConfig can be constructed with only one parameter but was given "+arguments.length);if(e)if(e instanceof o)this.state=e.toJson();else{if("object"!=typeof e)throw new a("Invalid argument given to MoneroTxConfig: "+typeof e);this.state=Object.assign({},e)}else this.state={};this.state.destinations&&(i(void 0===this.state.address&&void 0===this.state.amount,"Tx configuration may specify destinations or an address/amount but not both"),this.setDestinations(this.state.destinations.map(e=>e instanceof n?e:new n(e)))),(this.state.address||this.state.amount)&&(i(!this.state.destinations,"Tx configuration may specify destinations or an address/amount but not both"),this.setDestinations([new n(this.state.address,this.state.amount)]),delete this.state.address,delete this.state.amount),void 0!==this.state.subaddressIndex&&(this.setSubaddressIndices([this.state.subaddressIndex]),delete this.state.subaddressIndex)}copy(){return new o(this)}toJson(){let e=Object.assign({},this.state);if(this.getDestinations()){e.destinations=[];for(let t of this.getDestinations())e.destinations.push(t.toJson())}return this.getFee()&&(e.fee=this.getFee().toString()),this.getBelowAmount()&&(e.belowAmount=this.getBelowAmount().toString()),e}setAddress(e){if(void 0!==this.state.destinations&&this.state.destinations.length>1)throw new a("Cannot set address because MoneroTxConfig already has multiple destinations");return void 0===this.state.destinations||0===this.state.destinations.length?this.addDestination(new n(e)):this.state.destinations[0].setAddress(e),this}getAddress(){if(void 0===this.state.destinations||1!==this.state.destinations.length)throw new a("Cannot get address because MoneroTxConfig does not have exactly one destination");return this.state.destinations[0].getAddress()}setAmount(e){if(void 0!==this.state.destinations&&this.state.destinations.length>1)throw new a("Cannot set amount because MoneroTxConfig already has multiple destinations");return void 0===this.state.destinations||0===this.state.destinations.length?this.addDestination(new n(void 0,e)):this.state.destinations[0].setAmount(e),this}getAmount(){if(void 0===this.state.destinations||1!==this.state.destinations.length)throw new a("Cannot get amount because MoneroTxConfig does not have exactly one destination");return this.state.destinations[0].getAmount()}addDestination(e){return i(e instanceof n),void 0===this.state.destinations&&(this.state.destinations=[]),this.state.destinations.push(e),this}getDestinations(){return this.state.destinations}setDestinations(e){return arguments.length>1&&(e=Array.from(arguments)),this.state.destinations=e,this}setDestination(e){return this.setDestinations(e?[e]:e)}getPaymentId(){return this.state.paymentId}setPaymentId(e){return this.state.paymentId=e,this}getPriority(){return this.state.priority}setPriority(e){return this.state.priority=e,this}getFee(){return this.state.fee}setFee(e){return this.state.fee=e,this}getAccountIndex(){return this.state.accountIndex}setAccountIndex(e){return this.state.accountIndex=e,this}setSubaddressIndex(e){return this.setSubaddressIndices([e]),this}getSubaddressIndices(){return this.state.subaddressIndices}setSubaddressIndices(e){return arguments.length>1&&(e=Array.from(arguments)),this.state.subaddressIndices=e,this}getUnlockHeight(){return this.state.unlockHeight}setUnlockHeight(e){return this.state.unlockHeight=e,this}getRelay(){return this.state.relay}setRelay(e){return this.state.relay=e,this}getCanSplit(){return this.state.canSplit}setCanSplit(e){return this.state.canSplit=e,this}getNote(){return this.state.note}setNote(e){return this.state.note=e,this}getRecipientName(){return this.state.recipientName}setRecipientName(e){return this.state.recipientName=e,this}getBelowAmount(){return this.state.belowAmount}setBelowAmount(e){return this.state.belowAmount=e,this}getSweepEachSubaddress(){return this.state.sweepEachSubaddress}setSweepEachSubaddress(e){return this.state.sweepEachSubaddress=e,this}getKeyImage(){return this.state.keyImage}setKeyImage(e){return this.state.keyImage=e,this}}e.exports=o},function(e,t,r){"use strict";var i=r(153),n=r(38),a=r(273),o=i.wrapSuccess,s=i.wrapFail;t.getFsInstance=a.getInstance,t.appendFile=function(e,t,r){a.writeFile(e,t,r,!0)},t.writeFile=function(e,t,r){a.writeFile(e,t,r,!1)},t.readFile=function(e,t,r){"function"==typeof t&&(r=t,t={encoding:"utf8"});var i=o(r),n=s(r);a.getFile(e,(function(e,r){r.file((function(e){var r=new FileReader;r.onloadend=function(e){i(e.target.result)},r.onerror=function(e){n(e)},"utf8"===t.encoding?r.readAsText(e):r.readAsDataURL(e)}),n)}))},t.unlink=function(e,t){var r=o(t),i=s(t);a.getFile(e,(function(e,t){e?i(e):t.remove(r,i)}))},t.readdir=function(e,t){var r=o(t),i=s(t);a.getDirectory(e,(function(e,t){e?i(e):t.createReader().readEntries(r,i)}))},t.mkdir=function(e,t){var r=n.basename(e),o=n.dirname(e),s=i.wrapSuccess(t),c=i.wrapFail(t),u={create:!0,exclusive:!0};"."===o?a.getDirectory(r,u,t):a.getDirectory(o,(function(e,i){e?t(e,null):i.getDirectory(r,u,s,c)}))},t.rmdir=function(e,t){var r=o(t),i=s(t);this.readdir(e,(function(t,n){t?i(t):n&&n.length>0?i("ENOTEMPTY: Directory must be empty"):a.getDirectory(e,(function(e,t){e?i(e):t.remove(r,i)}))}))},t.exists=function(e,t){var r=s(t);a.getFile(e,{create:!1},(function(e){e&&(window.FileError&&1===e.code||"NotFoundError"===e.name)?t(!1):e?r(e):t(!0)}))},t.stat=function(e,t){var r=o(t),n=s(t),c=a.getFile;i.isDirectory(e)&&(c=a.getDirectory),c(e,(function(e,t){e?n(e):t.getMetadata(r,n)}))},t.init=function(e,t){a.init(e,(function(e){e?t(e,null):a.getInstance((function(e){t(e,null)}))}))}},function(e,t,r){(function(t){function r(e){try{if(!t.localStorage)return!1}catch(e){return!1}var r=t.localStorage[e];return null!=r&&"true"===String(r).toLowerCase()}e.exports=function(e,t){if(r("noDeprecation"))return e;var i=!1;return function(){if(!i){if(r("throwDeprecation"))throw new Error(t);r("traceDeprecation")?console.trace(t):console.warn(t),i=!0}return e.apply(this,arguments)}}}).call(this,r(8))},function(e,t,r){var i=r(1).Buffer;function n(e){i.isBuffer(e)||(e=i.from(e));for(var t=e.length/4|0,r=new Array(t),n=0;n>>24]^l[f>>>16&255]^h[m>>>8&255]^d[255&g]^t[_++],o=u[f>>>24]^l[m>>>16&255]^h[g>>>8&255]^d[255&p]^t[_++],s=u[m>>>24]^l[g>>>16&255]^h[p>>>8&255]^d[255&f]^t[_++],c=u[g>>>24]^l[p>>>16&255]^h[f>>>8&255]^d[255&m]^t[_++],p=a,f=o,m=s,g=c;return a=(i[p>>>24]<<24|i[f>>>16&255]<<16|i[m>>>8&255]<<8|i[255&g])^t[_++],o=(i[f>>>24]<<24|i[m>>>16&255]<<16|i[g>>>8&255]<<8|i[255&p])^t[_++],s=(i[m>>>24]<<24|i[g>>>16&255]<<16|i[p>>>8&255]<<8|i[255&f])^t[_++],c=(i[g>>>24]<<24|i[p>>>16&255]<<16|i[f>>>8&255]<<8|i[255&m])^t[_++],[a>>>=0,o>>>=0,s>>>=0,c>>>=0]}var s=[0,1,2,4,8,16,32,64,128,27,54],c=function(){for(var e=new Array(256),t=0;t<256;t++)e[t]=t<128?t<<1:t<<1^283;for(var r=[],i=[],n=[[],[],[],[]],a=[[],[],[],[]],o=0,s=0,c=0;c<256;++c){var u=s^s<<1^s<<2^s<<3^s<<4;u=u>>>8^255&u^99,r[o]=u,i[u]=o;var l=e[o],h=e[l],d=e[h],p=257*e[u]^16843008*u;n[0][o]=p<<24|p>>>8,n[1][o]=p<<16|p>>>16,n[2][o]=p<<8|p>>>24,n[3][o]=p,p=16843009*d^65537*h^257*l^16843008*o,a[0][u]=p<<24|p>>>8,a[1][u]=p<<16|p>>>16,a[2][u]=p<<8|p>>>24,a[3][u]=p,0===o?o=s=1:(o=l^e[e[e[d^l]]],s^=e[e[s]])}return{SBOX:r,INV_SBOX:i,SUB_MIX:n,INV_SUB_MIX:a}}();function u(e){this._key=n(e),this._reset()}u.blockSize=16,u.keySize=32,u.prototype.blockSize=u.blockSize,u.prototype.keySize=u.keySize,u.prototype._reset=function(){for(var e=this._key,t=e.length,r=t+6,i=4*(r+1),n=[],a=0;a>>24,o=c.SBOX[o>>>24]<<24|c.SBOX[o>>>16&255]<<16|c.SBOX[o>>>8&255]<<8|c.SBOX[255&o],o^=s[a/t|0]<<24):t>6&&a%t==4&&(o=c.SBOX[o>>>24]<<24|c.SBOX[o>>>16&255]<<16|c.SBOX[o>>>8&255]<<8|c.SBOX[255&o]),n[a]=n[a-t]^o}for(var u=[],l=0;l>>24]]^c.INV_SUB_MIX[1][c.SBOX[d>>>16&255]]^c.INV_SUB_MIX[2][c.SBOX[d>>>8&255]]^c.INV_SUB_MIX[3][c.SBOX[255&d]]}this._nRounds=r,this._keySchedule=n,this._invKeySchedule=u},u.prototype.encryptBlockRaw=function(e){return o(e=n(e),this._keySchedule,c.SUB_MIX,c.SBOX,this._nRounds)},u.prototype.encryptBlock=function(e){var t=this.encryptBlockRaw(e),r=i.allocUnsafe(16);return r.writeUInt32BE(t[0],0),r.writeUInt32BE(t[1],4),r.writeUInt32BE(t[2],8),r.writeUInt32BE(t[3],12),r},u.prototype.decryptBlock=function(e){var t=(e=n(e))[1];e[1]=e[3],e[3]=t;var r=o(e,this._invKeySchedule,c.INV_SUB_MIX,c.INV_SBOX,this._nRounds),a=i.allocUnsafe(16);return a.writeUInt32BE(r[0],0),a.writeUInt32BE(r[3],4),a.writeUInt32BE(r[2],8),a.writeUInt32BE(r[1],12),a},u.prototype.scrub=function(){a(this._keySchedule),a(this._invKeySchedule),a(this._key)},e.exports.AES=u},function(e,t,r){var i=r(1).Buffer,n=r(105);e.exports=function(e,t,r,a){if(i.isBuffer(e)||(e=i.from(e,"binary")),t&&(i.isBuffer(t)||(t=i.from(t,"binary")),8!==t.length))throw new RangeError("salt should be Buffer with 8 byte length");for(var o=r/8,s=i.alloc(o),c=i.alloc(a||0),u=i.alloc(0);o>0||a>0;){var l=new n;l.update(u),l.update(e),t&&l.update(t),u=l.digest();var h=0;if(o>0){var d=s.length-o;h=Math.min(o,u.length),u.copy(s,d,0,h),o-=h}if(h0){var p=c.length-a,f=Math.min(a,u.length-h);u.copy(c,p,h,h+f),a-=f}}return u.fill(0),{key:s,iv:c}}},function(e,t,r){"use strict";var i=r(27),n=r(20),a=n.getNAF,o=n.getJSF,s=n.assert;function c(e,t){this.type=e,this.p=new i(t.p,16),this.red=t.prime?i.red(t.prime):i.mont(this.p),this.zero=new i(0).toRed(this.red),this.one=new i(1).toRed(this.red),this.two=new i(2).toRed(this.red),this.n=t.n&&new i(t.n,16),this.g=t.g&&this.pointFromJSON(t.g,t.gRed),this._wnafT1=new Array(4),this._wnafT2=new Array(4),this._wnafT3=new Array(4),this._wnafT4=new Array(4),this._bitLength=this.n?this.n.bitLength():0;var r=this.n&&this.p.div(this.n);!r||r.cmpn(100)>0?this.redN=null:(this._maxwellTrick=!0,this.redN=this.n.toRed(this.red))}function u(e,t){this.curve=e,this.type=t,this.precomputed=null}e.exports=c,c.prototype.point=function(){throw new Error("Not implemented")},c.prototype.validate=function(){throw new Error("Not implemented")},c.prototype._fixedNafMul=function(e,t){s(e.precomputed);var r=e._getDoubles(),i=a(t,1,this._bitLength),n=(1<=c;t--)u=(u<<1)+i[t];o.push(u)}for(var l=this.jpoint(null,null,null),h=this.jpoint(null,null,null),d=n;d>0;d--){for(c=0;c=0;u--){for(t=0;u>=0&&0===o[u];u--)t++;if(u>=0&&t++,c=c.dblp(t),u<0)break;var l=o[u];s(0!==l),c="affine"===e.type?l>0?c.mixedAdd(n[l-1>>1]):c.mixedAdd(n[-l-1>>1].neg()):l>0?c.add(n[l-1>>1]):c.add(n[-l-1>>1].neg())}return"affine"===e.type?c.toP():c},c.prototype._wnafMulAdd=function(e,t,r,i,n){for(var s=this._wnafT1,c=this._wnafT2,u=this._wnafT3,l=0,h=0;h=1;h-=2){var p=h-1,f=h;if(1===s[p]&&1===s[f]){var m=[t[p],null,null,t[f]];0===t[p].y.cmp(t[f].y)?(m[1]=t[p].add(t[f]),m[2]=t[p].toJ().mixedAdd(t[f].neg())):0===t[p].y.cmp(t[f].y.redNeg())?(m[1]=t[p].toJ().mixedAdd(t[f]),m[2]=t[p].add(t[f].neg())):(m[1]=t[p].toJ().mixedAdd(t[f]),m[2]=t[p].toJ().mixedAdd(t[f].neg()));var g=[-3,-1,-5,-7,0,7,5,1,3],_=o(r[p],r[f]);l=Math.max(_[0].length,l),u[p]=new Array(l),u[f]=new Array(l);for(var v=0;v=0;h--){for(var S=0;h>=0;){var k=!0;for(v=0;v=0&&S++,E=E.dblp(S),h<0)break;for(v=0;v0?x=c[v][M-1>>1]:M<0&&(x=c[v][-M-1>>1].neg()),E="affine"===x.type?E.mixedAdd(x):E.add(x))}}for(h=0;h=Math.ceil((e.bitLength()+1)/t.step)},u.prototype._getDoubles=function(e,t){if(this.precomputed&&this.precomputed.doubles)return this.precomputed.doubles;for(var r=[this],i=this,n=0;n0;--t){o=o.twice();var s=n.testBit(t);s!=r.testBit(t)&&(o=o.add(s?this:a))}return o},o.prototype.multiplyTwo=function(e,t,r){var i;i=e.bitLength()>r.bitLength()?e.bitLength()-1:r.bitLength()-1;for(var n=this.curve.getInfinity(),a=this.add(t);i>=0;)n=n.twice(),e.testBit(i)?n=r.testBit(i)?n.add(a):n.add(this):r.testBit(i)&&(n=n.add(t)),--i;return n},s.prototype.getQ=function(){return this.q},s.prototype.getA=function(){return this.a},s.prototype.getB=function(){return this.b},s.prototype.equals=function(e){return e==this||this.q.equals(e.q)&&this.a.equals(e.a)&&this.b.equals(e.b)},s.prototype.getInfinity=function(){return this.infinity},s.prototype.fromBigInteger=function(e){return new a(this.q,e)},s.prototype.reduce=function(e){this.reducer.reduce(e)},s.prototype.encodePointHex=function(e){if(e.isInfinity())return"00";var t=e.getX().toBigInteger().toString(16),r=e.getY().toBigInteger().toString(16),i=this.getQ().toString(16).length;for(i%2!=0&&i++;t.length128&&(-1==this.q.shiftRight(e-64).intValue()&&(this.r=i.ONE.shiftLeft(e).subtract(this.q)));return this.r},a.prototype.modMult=function(e,t){return this.modReduce(e.multiply(t))},a.prototype.modReduce=function(e){if(null!=this.getR()){for(var t=q.bitLength();e.bitLength()>t+1;){var r=e.shiftRight(t),n=e.subtract(r.shiftLeft(t));this.getR().equals(i.ONE)||(r=r.multiply(this.getR())),e=r.add(n)}for(;e.compareTo(q)>=0;)e=e.subtract(q)}else e=e.mod(q);return e},a.prototype.sqrt=function(){if(!this.q.testBit(0))throw"unsupported";if(this.q.testBit(1)){var e=new a(this.q,this.x.modPow(this.q.shiftRight(2).add(i.ONE),this.q));return e.square().equals(this)?e:null}var t=this.q.subtract(i.ONE),r=t.shiftRight(1);if(!this.x.modPow(r,this.q).equals(i.ONE))return null;var n,o,s=t.shiftRight(2).shiftLeft(1).add(i.ONE),c=this.x,u=modDouble(modDouble(c));do{var l;do{l=new i(this.q.bitLength(),new SecureRandom)}while(l.compareTo(this.q)>=0||!l.multiply(l).subtract(u).modPow(r,this.q).equals(t));var h=this.lucasSequence(l,c,s);if(n=h[0],o=h[1],this.modMult(o,o).equals(u))return o.testBit(0)&&(o=o.add(q)),o=o.shiftRight(1),new a(q,o)}while(n.equals(i.ONE)||n.equals(t));return null},a.prototype.lucasSequence=function(e,t,r){for(var n=r.bitLength(),a=r.getLowestSetBit(),o=i.ONE,s=i.TWO,c=e,u=i.ONE,l=i.ONE,h=n-1;h>=a+1;--h)u=this.modMult(u,l),r.testBit(h)?(l=this.modMult(u,t),o=this.modMult(o,c),s=this.modReduce(c.multiply(s).subtract(e.multiply(u))),c=this.modReduce(c.multiply(c).subtract(l.shiftLeft(1)))):(l=u,o=this.modReduce(o.multiply(s).subtract(u)),c=this.modReduce(c.multiply(s).subtract(e.multiply(u))),s=this.modReduce(s.multiply(s).subtract(u.shiftLeft(1))));u=this.modMult(u,l),l=this.modMult(u,t),o=this.modReduce(o.multiply(s).subtract(u)),s=this.modReduce(c.multiply(s).subtract(e.multiply(u))),u=this.modMult(u,l);for(h=1;h<=a;++h)o=this.modMult(o,s),s=this.modReduce(s.multiply(s).subtract(u.shiftLeft(1))),u=this.modMult(u,u);return[o,s]};t={ECCurveFp:s,ECPointFp:o,ECFieldElementFp:a};e.exports=t},function(e,t,r){e.exports={read:function(e,t){return u.read(e,t)},readSSHPrivate:function(e,t,c){var u=(t=new h({buffer:t})).readCString();n.strictEqual(u,"openssh-key-v1","bad magic string");var p=t.readString(),f=t.readString(),m=t.readBuffer();if(1!==t.readInt())throw new Error("OpenSSH-format key file contains multiple keys: this is unsupported.");var g=t.readBuffer();if("public"===e)return n.ok(t.atEnd(),"excess bytes left after key"),l.read(g);var _=t.readBuffer();n.ok(t.atEnd(),"excess bytes left after key");var v=new h({buffer:m});switch(f){case"none":if("none"!==p)throw new Error('OpenSSH-format key uses KDF "none" but specifies a cipher other than "none"');break;case"bcrypt":var y=v.readBuffer(),b=v.readInt(),E=o.opensshCipherInfo(p);if(void 0===i&&(i=r(228)),"string"==typeof c.passphrase&&(c.passphrase=a.from(c.passphrase,"utf-8")),!a.isBuffer(c.passphrase))throw new d.KeyEncryptedError(c.filename,"OpenSSH");var w=new Uint8Array(c.passphrase),S=new Uint8Array(y),k=new Uint8Array(E.keySize+E.blockSize);if(0!==i.pbkdf(w,w.length,S,S.length,k,k.length,b))throw new Error("bcrypt_pbkdf function returned failure, parameters invalid");var x=(k=a.from(k)).slice(0,E.keySize),M=k.slice(E.keySize,E.keySize+E.blockSize),N=s.createDecipheriv(E.opensslName,x,M);N.setAutoPadding(!1);var j,T=[];for(N.once("error",(function(e){if(-1!==e.toString().indexOf("bad decrypt"))throw new Error("Incorrect passphrase supplied, could not decrypt key");throw e})),N.write(_),N.end();null!==(j=N.read());)T.push(j);_=a.concat(T);break;default:throw new Error('OpenSSH-format key uses unknown KDF "'+f+'"')}var R=(t=new h({buffer:_})).readInt(),I=t.readInt();if(R!==I)throw new Error("Incorrect passphrase supplied, could not decrypt key");var O={},A=l.readInternal(O,"private",t.remainder());t.skip(O.consumed);var P=t.readString();return A.comment=P,A},write:function(e,t){var u;u=c.isPrivateKey(e)?e.toPublic():e;var l,d,p="none",f="none",m=a.alloc(0),g={blockSize:8};void 0!==t&&("string"==typeof(l=t.passphrase)&&(l=a.from(l,"utf-8")),void 0!==l&&(n.buffer(l,"options.passphrase"),n.optionalString(t.cipher,"options.cipher"),void 0===(p=t.cipher)&&(p="aes128-ctr"),g=o.opensshCipherInfo(p),f="bcrypt"));if(c.isPrivateKey(e)){d=new h({});var _=s.randomBytes(4).readUInt32BE(0);d.writeInt(_),d.writeInt(_),d.write(e.toBuffer("rfc4253")),d.writeString(e.comment||"");for(var v=1;d._offset%g.blockSize!=0;)d.writeChar(v++);d=d.toBuffer()}switch(f){case"none":break;case"bcrypt":var y=s.randomBytes(16),b=new h({});b.writeBuffer(y),b.writeInt(16),m=b.toBuffer(),void 0===i&&(i=r(228));var E=new Uint8Array(l),w=new Uint8Array(y),S=new Uint8Array(g.keySize+g.blockSize);if(0!==i.pbkdf(E,E.length,w,w.length,S,S.length,16))throw new Error("bcrypt_pbkdf function returned failure, parameters invalid");var k=(S=a.from(S)).slice(0,g.keySize),x=S.slice(g.keySize,g.keySize+g.blockSize),M=s.createCipheriv(g.opensslName,k,x);M.setAutoPadding(!1);var N,j=[];for(M.once("error",(function(e){throw e})),M.write(d),M.end();null!==(N=M.read());)j.push(N);d=a.concat(j);break;default:throw new Error("Unsupported kdf "+f)}var T,R=new h({});R.writeCString("openssh-key-v1"),R.writeString(p),R.writeString(f),R.writeBuffer(m),R.writeInt(1),R.writeBuffer(u.toBuffer("rfc4253")),d&&R.writeBuffer(d);R=R.toBuffer(),T=c.isPrivateKey(e)?"OPENSSH PRIVATE KEY":"OPENSSH PUBLIC KEY";var I=R.toString("base64"),O=I.length+I.length/70+18+16+2*T.length+10;R=a.alloc(O);var A=0;A+=R.write("-----BEGIN "+T+"-----\n",A);for(var P=0;PI.length&&(D=I.length),A+=R.write(I.slice(P,D),A),R[A++]=10,P=D}return A+=R.write("-----END "+T+"-----\n",A),R.slice(0,A)}};var i,n=r(6),a=(r(31),r(9).Buffer),o=(r(16),r(13)),s=r(10),c=(r(14),r(17)),u=r(36),l=r(40),h=r(71),d=r(29)},function(e,t,r){var i,n,a,o,s,c;e.exports=(c=r(5),n=(i=c).lib,a=n.Base,o=n.WordArray,(s=i.x64={}).Word=a.extend({init:function(e,t){this.high=e,this.low=t}}),s.WordArray=a.extend({init:function(e,t){e=this.words=e||[],this.sigBytes=null!=t?t:8*e.length},toX32:function(){for(var e=this.words,t=e.length,r=[],i=0;i0))))}}a._EMPTY_OUTPUT=new n,e.exports=a},function(e,t,r){const i=r(96),n=r(98),a=r(97),o=r(18);class s extends a{constructor(e){super(e);const t=r(43);!this.state.txQuery||this.state.txQuery instanceof t||(this.state.txQuery=new t(this.state.txQuery)),this.state.txQuery&&this.state.txQuery.setTransferQuery(this),void 0!==this.state.isOutgoing&&(this.state.isIncoming=!this.state.isOutgoing),this._validate()}copy(){return new s(this)}toJson(){let e=Object.assign({},this.state,super.toJson());return delete e.txQuery,e}getTxQuery(){return this.state.txQuery}setTxQuery(e){return this.state.txQuery=e,e&&(e.state.transferQuery=this),this}isIncoming(){return this.state.isIncoming}setIsIncoming(e){return this.state.isIncoming=e,this}isOutgoing(){return void 0===this.state.isIncoming?void 0:!this.state.isIncoming}setIsOutgoing(e){return this.state.isIncoming=void 0===e?void 0:!e,this}getAddress(){return this.state.address}setAddress(e){return this.state.address=e,this}getAddresses(){return this.state.addresses}setAddresses(e){return this.state.addresses=e,this}getSubaddressIndex(){return this.state.subaddressIndex}setSubaddressIndex(e){return this.state.subaddressIndex=e,this._validate(),this}getSubaddressIndices(){return this.state.subaddressIndices}setSubaddressIndices(e){return this.state.subaddressIndices=e,this._validate(),this}getDestinations(){return this.state.destinations}setDestinations(e){return this.state.destinations=e,this}hasDestinations(){return this.state.hasDestinations}setHasDestinations(e){return this.state.hasDestinations=e,this}setIsLocked(e){return void 0===this.state.txQuery&&(this.state.txQuery=new MoneroTxQuery),this.state.txQuery.setIsLocked(e),this}meetsCriteria(e,t){if(!(e instanceof a))throw new Error("Transfer not given to MoneroTransferQuery.meetsCriteria(transfer)");if(void 0===t&&(t=!0),void 0!==this.isIncoming()&&this.isIncoming()!==e.isIncoming())return!1;if(void 0!==this.isOutgoing()&&this.isOutgoing()!==e.isOutgoing())return!1;if(void 0!==this.getAmount()&&0!==this.getAmount().compare(e.getAmount()))return!1;if(void 0!==this.getAccountIndex()&&this.getAccountIndex()!==e.getAccountIndex())return!1;if(e instanceof i){if(this.hasDestinations())return!1;if(void 0!==this.getAddress()&&this.getAddress()!==e.getAddress())return!1;if(void 0!==this.getAddresses()&&!this.getAddresses().includes(e.getAddress()))return!1;if(void 0!==this.getSubaddressIndex()&&this.getSubaddressIndex()!==e.getSubaddressIndex())return!1;if(void 0!==this.getSubaddressIndices()&&!this.getSubaddressIndices().includes(e.getSubaddressIndex()))return!1}else{if(!(e instanceof n))throw new Error("Transfer must be MoneroIncomingTransfer or MoneroOutgoingTransfer");if(void 0!==this.getAddress()&&(void 0===e.getAddresses()||!e.getAddresses().includes(this.getAddress())))return!1;if(void 0!==this.getAddresses()){if(!e.getAddresses())return!1;if(!this.getAddresses().some(t=>e.getAddresses().includes(t)))return!1}if(void 0!==this.getSubaddressIndex()&&(void 0===e.getSubaddressIndices()||!e.getSubaddressIndices().includes(this.getSubaddressIndex())))return!1;if(void 0!==this.getSubaddressIndices()){if(!e.getSubaddressIndices())return!1;if(!this.getSubaddressIndices().some(t=>e.getSubaddressIndices().includes(t)))return!1}if(void 0!==this.hasDestinations()){if(this.hasDestinations()&&void 0===e.getDestinations())return!1;if(!this.hasDestinations()&&void 0!==e.getDestinations())return!1}}return!(t&&void 0!==this.getTxQuery()&&!this.getTxQuery().meetsCriteria(e.getTx()))}_validate(){if(void 0!==this.getSubaddressIndex()&&this.getSubaddressIndex()<0)throw new o("Subaddress index must be >= 0");if(void 0!==this.getSubaddressIndices())for(let e of this.getSubaddressIndices())if(e<0)throw new o("Subaddress indices must be >= 0")}}e.exports=s},function(e,t,r){const i=r(4),n=r(12),a=r(97);class o extends a{constructor(e){super(e)}isIncoming(){return!0}getSubaddressIndex(){return this.state.subaddressIndex}setSubaddressIndex(e){return this.state.subaddressIndex=e,this}getAddress(){return this.state.address}setAddress(e){return this.state.address=e,this}getNumSuggestedConfirmations(){return this.state.numSuggestedConfirmations}setNumSuggestedConfirmations(e){return this.state.numSuggestedConfirmations=e,this}copy(){return new o(this.toJson())}merge(e){return super.merge(e),i(e instanceof o),this===e||(this.setSubaddressIndex(n.reconcile(this.getSubaddressIndex(),e.getSubaddressIndex())),this.setAddress(n.reconcile(this.getAddress(),e.getAddress())),this.setNumSuggestedConfirmations(n.reconcile(this.getNumSuggestedConfirmations(),e.getNumSuggestedConfirmations(),{resolveMax:!1}))),this}toString(){return this.toString(0)}toString(e){let t=super.toString(e)+"\n";return t+=n.kvLine("Subaddress index",this.getSubaddressIndex(),e),t+=n.kvLine("Address",this.getAddress(),e),t+=n.kvLine("Num suggested confirmations",this.getNumSuggestedConfirmations(),e),t.slice(0,t.length-1)}}e.exports=o},function(e,t,r){const i=r(4),n=r(7).BigInteger,a=r(12);class o{constructor(e){if(e)if(e instanceof o)e=e.toJson();else{if("object"!=typeof e)throw new MoneroError("state must be a MoneroTransfer or JavaScript object");e=Object.assign({},e)}else e={};this.state=e,void 0===e.amount||e.amount instanceof n||(e.amount=n.parse(e.amount)),this._validate()}copy(){return new o(this)}toJson(){let e=Object.assign({},this.state);return this.getAmount()&&(e.amount=this.getAmount().toString()),delete e.tx,e}getTx(){return this.state.tx}setTx(e){return this.state.tx=e,this}isOutgoing(){let e=this.isIncoming();return i("boolean"==typeof e),!e}isIncoming(){throw new Error("Subclass must implement")}getAccountIndex(){return this.state.accountIndex}setAccountIndex(e){return this.state.accountIndex=e,this._validate(),this}getAmount(){return this.state.amount}setAmount(e){return this.state.amount=e,this}merge(e){return i(e instanceof o),this===e?this:this.getTx()!==e.getTx()?(this.getTx().merge(e.getTx()),this):(this.setAccountIndex(a.reconcile(this.getAccountIndex(),e.getAccountIndex())),(void 0===this.getAmount()||void 0===e.getAmount()||0===this.getAmount().compare(e.getAmount())||0!==this.getAmount().compare(n.parse("0"))&&0!==e.getAmount().compare(n.parse("0")))&&this.setAmount(a.reconcile(this.getAmount(),e.getAmount())),this)}toString(e=0){let t="";return t+=a.kvLine("Is incoming",this.isIncoming(),e),t+=a.kvLine("Account index",this.getAccountIndex(),e),t+=a.kvLine("Amount",this.getAmount()?this.getAmount().toString():void 0,e),""===t?t:t.slice(0,t.length-1)}_validate(){if(void 0!==this.getAccountIndex()&&this.getAccountIndex()<0)throw new MoneroError("Account index must be >= 0")}}e.exports=o},function(e,t,r){const i=r(4),n=r(12),a=r(99),o=r(97);class s extends o{constructor(e){if(super(e),(e=this.state).destinations)for(let t=0;t=0),i(t>=0),(await this.getSubaddresses(e,t))[0]}async createSubaddress(e,t){throw new a("Not supported")}async getTx(e){return(await this.getTxs([e]))[0]}async getTxs(e,t){throw new a("Not supported")}async getTransfers(e){throw new a("Not supported")}async getIncomingTransfers(e){let t;if(void 0===e)t=new s;else{if(!1===e.isIncoming())throw new a("Transfer query contradicts getting incoming transfers");t=e.copy()}t.setIsIncoming(!0);let r=[];for(let e of await this.getTransfers(t))r.push(e);return r}async getOutgoingTransfers(e){let t;if(void 0===e)t=new s;else{if(!1===e.isOutgoing())throw new a("Transfer query contradicts getting outgoing transfers");t=e.copy()}t.setIsOutgoing(!0);let r=[];for(let e of await this.getTransfers(t))r.push(e);return r}async getOutputs(e){throw new a("Not supported")}async getOutputsHex(){throw new a("Not supported")}async importOutputsHex(e){throw new a("Not supported")}async getKeyImages(){throw new a("Not supported")}async importKeyImages(e){throw new a("Not supported")}async getNewKeyImagesFromLastImport(){throw new a("Not supported")}async createTx(e){return void 0!==(e=l._normalizeCreateTxsConfig(e)).getCanSplit()&&i.equal(e.getCanSplit(),!1,"Cannot split transactions using createTx(); use createTxs()"),e.setCanSplit(!1),(await this.createTxs(e))[0]}async createTxs(e){throw new a("Not supported")}async sweepOutput(e){throw new a("Not supported")}async sweepUnlocked(e){throw new a("Not supported")}async sweepDust(e){throw new a("Not supported")}async relayTx(e){return(await this.relayTxs([e]))[0]}async relayTxs(e){throw new a("Not supported")}async parseTxSet(e){throw new a("Not supported")}async signTxs(e){throw new a("Not supported")}async submitTxs(e){throw new a("Not supported")}async signMessage(e){throw new a("Not supported")}async verifyMessage(e,t,r){throw new a("Not supported")}async getTxKey(e){throw new a("Not supported")}async checkTxKey(e,t,r){throw new a("Not supported")}async getTxProof(e,t,r){throw new a("Not supported")}async checkTxProof(e,t,r,i){throw new a("Not supported")}async getSpendProof(e,t){throw new a("Not supported")}async checkSpendProof(e,t,r){throw new a("Not supported")}async getReserveProofWallet(e){throw new a("Not supported")}async getReserveProofAccount(e,t,r){throw new a("Not supported")}async checkReserveProof(e,t,r){throw new a("Not supported")}async getTxNote(e){return(await this.getTxNotes([e]))[0]}async getTxNotes(e){throw new a("Not supported")}async setTxNote(e,t){await this.setTxNotes([e],[t])}async setTxNotes(e,t){throw new a("Not supported")}async getAddressBookEntries(e){throw new a("Not supported")}async addAddressBookEntry(e,t){throw new a("Not supported")}async editAddressBookEntry(e,t,r,i,n){throw new a("Not supported")}async deleteAddressBookEntry(e){throw new a("Not supported")}async tagAccounts(e,t){throw new a("Not supported")}async untagAccounts(e){throw new a("Not supported")}async getAccountTags(){throw new a("Not supported")}async setAccountTagLabel(e,t){throw new a("Not supported")}async createPaymentUri(e){throw new a("Not supported")}async parsePaymentUri(e){throw new a("Not supported")}async getAttribute(e){throw new a("Not supported")}async setAttribute(e,t){throw new a("Not supported")}async startMining(e,t,r){throw new a("Not supported")}async stopMining(){throw new a("Not supported")}async isMultisigImportNeeded(){throw new a("Not supported")}async isMultisig(){return(await this.getMultisigInfo()).isMultisig()}async getMultisigInfo(){throw new a("Not supported")}async prepareMultisig(){throw new a("Not supported")}async makeMultisig(e,t,r){throw new a("Not supported")}async exchangeMultisigKeys(e,t){throw new a("Not supported")}async getMultisigHex(){throw new a("Not supported")}async importMultisigHex(e){throw new a("Not supported")}async signMultisigTxHex(e){throw new a("Not supported")}async submitMultisigTxHex(e){throw new a("Not supported")}save(){throw new a("Not supported")}async close(e){throw new a("Not supported")}async isClosed(){throw new a("Not supported")}static _normalizeTxQuery(e){return e instanceof u?e=e.copy():Array.isArray(e)?e=(new u).setHashes(e):(e=Object.assign({},e),e=new u(e)),void 0===e.getBlock()&&e.setBlock((new n).setTxs([e])),e}static _normalizeTransferQuery(e){if(void 0===e)e=new s;else if(e instanceof s)if(void 0===e.getTxQuery())e=e.copy();else{let t=e.getTxQuery().copy();e.getTxQuery().getTransferQuery()===e?e=t.getTransferQuery():(i.equal(e.getTxQuery().getTransferQuery(),void 0,"Transfer query's tx query must be circular reference or null"),(e=e.copy()).setTxQuery(t))}else e=Object.assign({},e),e=new s(e);return void 0===e.getTxQuery()&&e.setTxQuery(new u),e.getTxQuery().setTransferQuery(e),void 0===e.getTxQuery().getBlock()&&e.getTxQuery().setBlock((new n).setTxs([e.getTxQuery()])),e}static _normalizeOutputQuery(e){if(void 0===e)e=new o;else if(e instanceof o)if(void 0===e.getTxQuery())e=e.copy();else{let t=e.getTxQuery().copy();e.getTxQuery().getOutputQuery()===e?e=t.getOutputQuery():(i.equal(e.getTxQuery().getOutputQuery(),void 0,"Output query's tx query must be circular reference or null"),(e=e.copy()).setTxQuery(t))}else e=Object.assign({},e),e=new o(e);return void 0===e.getTxQuery()&&e.setTxQuery(new u),e.getTxQuery().setOutputQuery(e),void 0===e.getTxQuery().getBlock()&&e.getTxQuery().setBlock((new n).setTxs([e.getTxQuery()])),e}static _normalizeCreateTxsConfig(e){if(void 0===e||!(e instanceof Object))throw new a("Must provide MoneroTxConfig or equivalent JS object");return e=new c(e),i(e.getDestinations()&&e.getDestinations().length>0,"Must provide destinations"),i.equal(e.getSweepEachSubaddress(),void 0),i.equal(e.getBelowAmount(),void 0),e}static _normalizeSweepOutputConfig(e){if(void 0===e||!(e instanceof Object))throw new a("Must provide MoneroTxConfig or equivalent JS object");if(e=new c(e),i.equal(e.getSweepEachSubaddress(),void 0),i.equal(e.getBelowAmount(),void 0),i.equal(e.getCanSplit(),void 0,"Cannot split transactions when sweeping an output"),!e.getDestinations()||1!==e.getDestinations().length||!e.getDestinations()[0].getAddress())throw new a("Must provide exactly one destination address to sweep output to");return e}static _normalizeSweepUnlockedConfig(e){if(void 0===e||!(e instanceof Object))throw new a("Must provide MoneroTxConfig or equivalent JS object");if(void 0===(e=new c(e)).getDestinations()||1!=e.getDestinations().length)throw new a("Must provide exactly one destination to sweep to");if(void 0===e.getDestinations()[0].getAddress())throw new a("Must provide destination address to sweep to");if(void 0!==e.getDestinations()[0].getAmount())throw new a("Cannot provide amount in sweep config");if(void 0!==e.getKeyImage())throw new a("Key image defined; use sweepOutput() to sweep an output by its key image");if(void 0!==e.getSubaddressIndices()&&0===e.getSubaddressIndices().length&&e.setSubaddressIndices(void 0),void 0===e.getAccountIndex()&&void 0!==e.getSubaddressIndices())throw new a("Must provide account index if subaddress indices are provided");return e}}l.DEFAULT_LANGUAGE="English",e.exports=l},function(e,t,r){const i=r(4),n=r(7).BigInteger,a=r(12),o=r(37),s=r(249),c=r(139),u=r(42),l=r(91),h=r(250),d=r(262),p=r(140),f=r(252),m=r(141),g=r(253),_=r(18),v=r(255),y=r(58),b=r(256),E=r(257),w=r(60),S=r(93),k=r(258),x=r(57),M=r(259),N=r(92),j=r(28),T=r(100);class R extends d{constructor(e,t,r,i,n,a){super(),this.config=R._normalizeConfig(e,t,r,i,n,a),this.config.proxyToWorker?this._proxyPromise=I.connect(this.config):(this.rpc=new x(this.config),this.listeners=[],this.cachedHeaders={})}async getRpcConnection(){return this.config.proxyToWorker?(await this._getDaemonProxy()).getRpcConnection():this.rpc}async isConnected(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).isConnected();try{return await this.getHeight(),!0}catch(e){return!1}}async getVersion(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getVersion();let e=await this.rpc.sendJsonRequest("get_version");return R._checkResponseStatus(e.result),new T(e.result.version,e.result.release)}async isTrusted(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).isTrusted();let e=await this.rpc.sendPathRequest("get_height");return R._checkResponseStatus(e),!e.untrusted}async getHeight(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getHeight();let e=await this.rpc.sendJsonRequest("get_block_count");return R._checkResponseStatus(e.result),e.result.count}async getBlockHash(e){return this.config.proxyToWorker?(await this._getDaemonProxy()).getBlockHash(e):(await this.rpc.sendJsonRequest("on_get_block_hash",[e])).result}async getBlockTemplate(e,t){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getBlockTemplate(e,t);i(e&&"string"==typeof e,"Must specify wallet address to be mined to");let r=await this.rpc.sendJsonRequest("get_block_template",{wallet_address:e,reserve_size:t});return R._checkResponseStatus(r.result),R._convertRpcBlockTemplate(r.result)}async getLastBlockHeader(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getLastBlockHeader();let e=await this.rpc.sendJsonRequest("get_last_block_header");return R._checkResponseStatus(e.result),R._convertRpcBlockHeader(e.result.block_header)}async getBlockHeaderByHash(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getBlockHeaderByHash(e);let t=await this.rpc.sendJsonRequest("get_block_header_by_hash",{hash:e});return R._checkResponseStatus(t.result),R._convertRpcBlockHeader(t.result.block_header)}async getBlockHeaderByHeight(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getBlockHeaderByHeight(e);let t=await this.rpc.sendJsonRequest("get_block_header_by_height",{height:e});return R._checkResponseStatus(t.result),R._convertRpcBlockHeader(t.result.block_header)}async getBlockHeadersByRange(e,t){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getBlockHeadersByRange(e,t);let r=await this.rpc.sendJsonRequest("get_block_headers_range",{start_height:e,end_height:t});R._checkResponseStatus(r.result);let i=[];for(let e of r.result.headers)i.push(R._convertRpcBlockHeader(e));return i}async getBlockByHash(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getBlockByHash(e);let t=await this.rpc.sendJsonRequest("get_block",{hash:e});return R._checkResponseStatus(t.result),R._convertRpcBlock(t.result)}async getBlockByHeight(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getBlockByHeight(e);let t=await this.rpc.sendJsonRequest("get_block",{height:e});return R._checkResponseStatus(t.result),R._convertRpcBlock(t.result)}async getBlocksByHeight(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getBlocksByHeight(e);let t=await this.rpc.sendBinaryRequest("get_blocks_by_height.bin",{heights:e});await o.loadKeysModule();let r=j.binaryBlocksToJson(t);R._checkResponseStatus(r),i.equal(r.txs.length,r.blocks.length);let n=[];for(let t=0;t0,"Must provide an array of transaction hashes"),i(void 0===t||"boolean"==typeof t,"Prune must be a boolean or undefined");let r=await this.rpc.sendPathRequest("get_transactions",{txs_hashes:e,decode_as_json:!0,prune:t});try{R._checkResponseStatus(r)}catch(e){if(e.message.indexOf("Failed to parse hex representation of transaction hash")>=0)throw new _("Invalid transaction hash");throw e}let n=[];if(r.txs)for(let e=0;e=0,"Height must be an integer >= 0"),void 0===t?t=await this.getHeight():i(t>=0,"Count must be an integer >= 0");let r=await this.rpc.sendJsonRequest("get_coinbase_tx_sum",{height:e,count:t});R._checkResponseStatus(r.result);let a=new b;return a.setEmissionSum(new n(r.result.emission_amount)),a.setFeeSum(new n(r.result.fee_amount)),a}async getFeeEstimate(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getFeeEstimate(e);let t=await this.rpc.sendJsonRequest("get_fee_estimate",{grace_blocks:e});return R._checkResponseStatus(t.result),new n(t.result.fee)}async submitTxHex(e,t){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).submitTxHex(e,t);let r=await this.rpc.sendPathRequest("send_raw_transaction",{tx_as_hex:e,do_not_relay:t}),i=R._convertRpcSubmitTxResult(r);try{R._checkResponseStatus(r),i.setIsGood(!0)}catch(e){i.setIsGood(!1)}return i}async relayTxsByHash(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).relayTxsByHash(e);let t=await this.rpc.sendJsonRequest("relay_tx",{txids:e});R._checkResponseStatus(t.result)}async getTxPool(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getTxPool();let e=await this.rpc.sendPathRequest("get_transaction_pool");R._checkResponseStatus(e);let t=[];if(e.transactions)for(let r of e.transactions){let e=new N;t.push(e),e.setIsConfirmed(!1),e.setIsMinerTx(!1),e.setInTxPool(!0),e.setNumConfirmations(0),R._convertRpcTx(r,e)}return t}async getTxPoolHashes(){throw new _("Not implemented")}async getTxPoolBacklog(){throw new _("Not implemented")}async getTxPoolStats(){throw new _("Response contains field 'histo' which is binary'")}async flushTxPool(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).flushTxPool(e);e&&(e=a.listify(e));let t=await this.rpc.sendJsonRequest("flush_txpool",{txids:e});R._checkResponseStatus(t.result)}async getKeyImageSpentStatuses(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getKeyImageSpentStatuses(e);if(void 0===e||0===e.length)throw new _("Must provide key images to check the status of");let t=await this.rpc.sendPathRequest("is_key_image_spent",{key_images:e});return R._checkResponseStatus(t),t.spent_status}async getOutputHistogram(e,t,r,i,n){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getOutputHistogram(e,t,r,i,n);let a=await this.rpc.sendJsonRequest("get_output_histogram",{amounts:e,min_count:t,max_count:r,unlocked:i,recent_cutoff:n});R._checkResponseStatus(a.result);let o=[];if(!a.result.histogram)return o;for(let e of a.result.histogram)o.push(R._convertRpcOutputHistogramEntry(e));return o}async getOutputDistribution(e,t,r,i){throw new _("Not implemented (response 'distribution' field is binary)")}async getInfo(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getInfo();let e=await this.rpc.sendJsonRequest("get_info");return R._checkResponseStatus(e.result),R._convertRpcInfo(e.result)}async getSyncInfo(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getSyncInfo();let e=await this.rpc.sendJsonRequest("sync_info");return R._checkResponseStatus(e.result),R._convertRpcSyncInfo(e.result)}async getHardForkInfo(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getHardForkInfo();let e=await this.rpc.sendJsonRequest("hard_fork_info");return R._checkResponseStatus(e.result),R._convertRpcHardForkInfo(e.result)}async getAltChains(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getAltChains();let e=await this.rpc.sendJsonRequest("get_alternate_chains");R._checkResponseStatus(e.result);let t=[];if(!e.result.chains)return t;for(let r of e.result.chains)t.push(R._convertRpcAltChain(r));return t}async getAltBlockHashes(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getAltBlockHashes();let e=await this.rpc.sendPathRequest("get_alt_blocks_hashes");return R._checkResponseStatus(e),e.blks_hashes?e.blks_hashes:[]}async getDownloadLimit(){return this.config.proxyToWorker?(await this._getDaemonProxy()).getDownloadLimit():(await this._getBandwidthLimits())[0]}async setDownloadLimit(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).setDownloadLimit(e);if(-1==e)return await this.resetDownloadLimit();if(!(a.isInt(e)&&e>0))throw new _("Download limit must be an integer greater than 0");return(await this._setBandwidthLimits(e,0))[0]}async resetDownloadLimit(){return this.config.proxyToWorker?(await this._getDaemonProxy()).resetDownloadLimit():(await this._setBandwidthLimits(-1,0))[0]}async getUploadLimit(){return this.config.proxyToWorker?(await this._getDaemonProxy()).getUploadLimit():(await this._getBandwidthLimits())[1]}async setUploadLimit(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).setUploadLimit(e);if(-1==e)return await this.resetUploadLimit();if(!(a.isInt(e)&&e>0))throw new _("Upload limit must be an integer greater than 0");return(await this._setBandwidthLimits(0,e))[1]}async resetUploadLimit(){return this.config.proxyToWorker?(await this._getDaemonProxy()).resetUploadLimit():(await this._setBandwidthLimits(0,-1))[1]}async getConnections(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getConnections();let e=await this.rpc.sendJsonRequest("get_connections");R._checkResponseStatus(e.result);let t=[];if(!e.result.connections)return t;for(let r of e.result.connections)t.push(R._convertRpcConnection(r));return t}async getKnownPeers(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getKnownPeers();let e=await this.rpc.sendPathRequest("get_peer_list");R._checkResponseStatus(e);let t=[];if(e.gray_list)for(let r of e.gray_list){let e=R._convertRpcPeer(r);e.setIsOnline(!1),t.push(e)}if(e.white_list)for(let r of e.white_list){let e=R._convertRpcPeer(r);e.setIsOnline(!0),t.push(e)}return t}async setOutgoingPeerLimit(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).setOutgoingPeerLimit(e);if(!(a.isInt(e)&&e>=0))throw new _("Outgoing peer limit must be >= 0");let t=await this.rpc.sendPathRequest("out_peers",{out_peers:e});R._checkResponseStatus(t)}async setIncomingPeerLimit(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).setIncomingPeerLimit(e);if(!(a.isInt(e)&&e>=0))throw new _("Incoming peer limit must be >= 0");let t=await this.rpc.sendPathRequest("in_peers",{in_peers:e});R._checkResponseStatus(t)}async getPeerBans(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getPeerBans();let e=await this.rpc.sendJsonRequest("get_bans");R._checkResponseStatus(e.result);let t=[];for(let r of e.result.bans){let e=new c;e.setHost(r.host),e.setIp(r.ip),e.setSeconds(r.seconds),t.push(e)}return t}async setPeerBans(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).setPeerBans(e);let t=[];for(let r of e)t.push(R._convertToRpcBan(r));let r=await this.rpc.sendJsonRequest("set_bans",{bans:t});R._checkResponseStatus(r.result)}async startMining(e,t,r,n){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).startMining(e,t,r,n);i(e,"Must provide address to mine to"),i(a.isInt(t)&&t>0,"Number of threads must be an integer greater than 0"),i(void 0===r||"boolean"==typeof r),i(void 0===n||"boolean"==typeof n);let o=await this.rpc.sendPathRequest("start_mining",{miner_address:e,threads_count:t,do_background_mining:r,ignore_battery:n});R._checkResponseStatus(o)}async stopMining(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).stopMining();let e=await this.rpc.sendPathRequest("stop_mining");R._checkResponseStatus(e)}async getMiningStatus(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getMiningStatus();let e=await this.rpc.sendPathRequest("mining_status");return R._checkResponseStatus(e),R._convertRpcMiningStatus(e)}async submitBlocks(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).submitBlocks(e);i(Array.isArray(e)&&e.length>0,"Must provide an array of mined block blobs to submit");let t=await this.rpc.sendJsonRequest("submit_block",e);R._checkResponseStatus(t.result)}async checkForUpdate(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).checkForUpdate();let e=await this.rpc.sendPathRequest("update",{command:"check"});return R._checkResponseStatus(e),R._convertRpcUpdateCheckResult(e)}async downloadUpdate(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).downloadUpdate();let t=await this.rpc.sendPathRequest("update",{command:"download",path:e});return R._checkResponseStatus(t),R._convertRpcUpdateDownloadResult(t)}async stop(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).stop();let e=await this.rpc.sendPathRequest("stop_daemon");R._checkResponseStatus(e)}async getNextBlockHeader(){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).getNextBlockHeader();let e=this;return new Promise((async function(t,r){let i=async function(r){t(r),await e.removeBlockListener(i)};await e.addBlockListener(i)}))}async addBlockListener(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).addBlockListener(e);this.listeners.push(e),this.isPollingHeaders||this._startPollingHeaders(this.config.pollInterval)}async removeBlockListener(e){if(this.config.proxyToWorker)return(await this._getDaemonProxy()).removeBlockListener(e);let t=a.remove(this.listeners,e);i(t,"Listener is not registered"),0===this.listeners.length&&this._stopPollingHeaders()}async getTx(){return super.getTx(...arguments)}async getTxHex(){return super.getTxHex(...arguments)}async getKeyImageSpentStatus(){return super.getKeyImageSpentStatus(...arguments)}async setPeerBan(){return super.setPeerBan(...arguments)}async submitBlock(){return super.submitBlock(...arguments)}async _getDaemonProxy(){return await this._proxyPromise}async _startPollingHeaders(e){i(!this.isPollingHeaders,"Daemon is already polling block headers");let t=await this.getLastBlockHeader();for(this.isPollingHeaders=!0;this.isPollingHeaders;){let r;await new Promise((function(t){setTimeout(t,e)}));try{r=await this.getLastBlockHeader()}catch(e){console.error("Failed to poll last block header, retrying...");continue}if(r.getHash()!==t.getHash()){t=r;for(let e of this.listeners)e(r)}}}_stopPollingHeaders(){this.isPollingHeaders=!1}async _getBandwidthLimits(){let e=await this.rpc.sendPathRequest("get_limit");return R._checkResponseStatus(e),[e.limit_down,e.limit_up]}async _setBandwidthLimits(e,t){void 0===e&&(e=0),void 0===t&&(t=0);let r=await this.rpc.sendPathRequest("set_limit",{limit_down:e,limit_up:t});return R._checkResponseStatus(r),[r.limit_down,r.limit_up]}async _getMaxBlocks(e,t,r){void 0===e&&(e=0),void 0===t&&(t=await this.getHeight()-1),void 0===r&&(r=R.MAX_REQ_SIZE);let n=0,a=e-1;for(;nr)break;n+=e.getSize(),a++}return a>=e?await this.getBlocksByRange(e,a):[]}async _getBlockHeaderByHeightCached(e,t){let r=this.cachedHeaders[e];if(r)return r;let i=Math.min(t,e+R.NUM_HEADERS_PER_REQ-1),n=await this.getBlockHeadersByRange(e,i);for(let e of n)this.cachedHeaders[e.getHeight()]=e;return this.cachedHeaders[e]}static _normalizeConfig(e,t,r,i,n,o){let s;if("string"==typeof e)s={uri:e,username:t,password:r,proxyToWorker:o,rejectUnauthorized:i,pollInterval:n};else{if("object"!=typeof e)throw new _("Invalid configuration to create daemon rpc client; must be string, object, or MoneroRpcConnection");if(t||r||i||n||o)throw new _("Can provide config object or params or new MoneroDaemonRpc(...) but not both");s=e instanceof x?Object.assign({},e.getConfig()):Object.assign({},e)}return void 0===s.pollInterval&&(s.pollInterval=5e3),s.server&&(s=Object.assign(s,new x(s.server).getConfig()),delete s.server),void 0===s.proxyToWorker&&(s.proxyToWorker=a.isBrowser()),s}static _checkResponseStatus(e){if("OK"!==e.status)throw new _(e.status)}static _convertRpcBlockHeader(e){if(!e)return;let t=new l;for(let r of Object.keys(e)){let i=e[r];"block_size"===r?a.safeSet(t,t.getSize,t.setSize,i):"depth"===r?a.safeSet(t,t.getDepth,t.setDepth,i):"difficulty"===r||"cumulative_difficulty"===r||"difficulty_top64"===r||"cumulative_difficulty_top64"===r||("wide_difficulty"===r?t.setDifficulty(a.reconcile(t.getDifficulty(),R._prefixedHexToBI(i))):"wide_cumulative_difficulty"===r?t.setCumulativeDifficulty(a.reconcile(t.getCumulativeDifficulty(),R._prefixedHexToBI(i))):"hash"===r?a.safeSet(t,t.getHash,t.setHash,i):"height"===r?a.safeSet(t,t.getHeight,t.setHeight,i):"major_version"===r?a.safeSet(t,t.getMajorVersion,t.setMajorVersion,i):"minor_version"===r?a.safeSet(t,t.getMinorVersion,t.setMinorVersion,i):"nonce"===r?a.safeSet(t,t.getNonce,t.setNonce,i):"num_txes"===r?a.safeSet(t,t.getNumTxs,t.setNumTxs,i):"orphan_status"===r?a.safeSet(t,t.getOrphanStatus,t.setOrphanStatus,i):"prev_hash"===r||"prev_id"===r?a.safeSet(t,t.getPrevHash,t.setPrevHash,i):"reward"===r?a.safeSet(t,t.getReward,t.setReward,n.parse(i)):"timestamp"===r?a.safeSet(t,t.getTimestamp,t.setTimestamp,i):"block_weight"===r?a.safeSet(t,t.getWeight,t.setWeight,i):"long_term_weight"===r?a.safeSet(t,t.getLongTermWeight,t.setLongTermWeight,i):"pow_hash"===r?a.safeSet(t,t.getPowHash,t.setPowHash,""===i?void 0:i):"tx_hashes"===r||"miner_tx"===r||("miner_tx_hash"===r?t.setMinerTxHash(i):console.log("WARNING: ignoring unexpected block header field: '"+r+"': "+i)))}return t}static _convertRpcBlock(e){let t=new u(R._convertRpcBlockHeader(e.block_header?e.block_header:e));t.setHex(e.blob),t.setTxHashes(void 0===e.tx_hashes?[]:e.tx_hashes);let r=e.json?JSON.parse(e.json).miner_tx:e.miner_tx,i=new N;return t.setMinerTx(i),i.setIsConfirmed(!0),i.setIsMinerTx(!0),R._convertRpcTx(r,i),t}static _convertRpcTx(e,t){if(void 0===e)return;let r;void 0===t&&(t=new N);for(let i of Object.keys(e)){let o=e[i];"tx_hash"===i||"id_hash"===i?a.safeSet(t,t.getHash,t.setHash,o):"block_timestamp"===i?(r||(r=new l),a.safeSet(r,r.getTimestamp,r.setTimestamp,o)):"block_height"===i?(r||(r=new l),a.safeSet(r,r.getHeight,r.setHeight,o)):"last_relayed_time"===i?a.safeSet(t,t.getLastRelayedTimestamp,t.setLastRelayedTimestamp,o):"receive_time"===i||"received_timestamp"===i?a.safeSet(t,t.getReceivedTimestamp,t.setReceivedTimestamp,o):"in_pool"===i?(a.safeSet(t,t.isConfirmed,t.setIsConfirmed,!o),a.safeSet(t,t.inTxPool,t.setInTxPool,o)):"double_spend_seen"===i?a.safeSet(t,t.isDoubleSpendSeen,t.setIsDoubleSpend,o):"version"===i?a.safeSet(t,t.getVersion,t.setVersion,o):"extra"===i?a.safeSet(t,t.getExtra,t.setExtra,o):"vin"===i?1===o.length&&o[0].gen||t.setInputs(o.map(e=>R._convertRpcOutput(e,t))):"vout"===i?t.setOutputs(o.map(e=>R._convertRpcOutput(e,t))):"rct_signatures"===i?a.safeSet(t,t.getRctSignatures,t.setRctSignatures,o):"rctsig_prunable"===i?a.safeSet(t,t.getRctSigPrunable,t.setRctSigPrunable,o):"unlock_time"===i?a.safeSet(t,t.getUnlockHeight,t.setUnlockHeight,o):"as_json"===i||"tx_json"===i||("as_hex"===i||"tx_blob"===i?a.safeSet(t,t.getFullHex,t.setFullHex,o||void 0):"blob_size"===i?a.safeSet(t,t.getSize,t.setSize,o):"weight"===i?a.safeSet(t,t.getWeight,t.setWeight,o):"fee"===i?a.safeSet(t,t.getFee,t.setFee,n.parse(o)):"relayed"===i?a.safeSet(t,t.isRelayed,t.setIsRelayed,o):"output_indices"===i?a.safeSet(t,t.getOutputIndices,t.setOutputIndices,o):"do_not_relay"===i?a.safeSet(t,t.getRelay,t.setRelay,!o):"kept_by_block"===i?a.safeSet(t,t.isKeptByBlock,t.setIsKeptByBlock,o):"signatures"===i?a.safeSet(t,t.getSignatures,t.setSignatures,o):"last_failed_height"===i?0===o?a.safeSet(t,t.isFailed,t.setIsFailed,!1):(a.safeSet(t,t.isFailed,t.setIsFailed,!0),a.safeSet(t,t.getLastFailedHeight,t.setLastFailedHeight,o)):"last_failed_id_hash"===i?o===R.DEFAULT_ID?a.safeSet(t,t.isFailed,t.setIsFailed,!1):(a.safeSet(t,t.isFailed,t.setIsFailed,!0),a.safeSet(t,t.getLastFailedHash,t.setLastFailedHash,o)):"max_used_block_height"===i?a.safeSet(t,t.getMaxUsedBlockHeight,t.setMaxUsedBlockHeight,o):"max_used_block_id_hash"===i?a.safeSet(t,t.getMaxUsedBlockHash,t.setMaxUsedBlockHash,o):"prunable_hash"===i?a.safeSet(t,t.getPrunableHash,t.setPrunableHash,o||void 0):"prunable_as_hex"===i?a.safeSet(t,t.getPrunableHex,t.setPrunableHex,o||void 0):"pruned_as_hex"===i?a.safeSet(t,t.getPrunedHex,t.setPrunedHex,o||void 0):console.log("WARNING: ignoring unexpected field in rpc tx: "+i+": "+o))}if(r&&t.setBlock(new u(r).setTxs([t])),t.getBlock()&&void 0!==t.getBlock().getHeight()&&t.getBlock().getHeight()===t.getBlock().getTimestamp()&&(t.setBlock(void 0),t.setIsConfirmed(!1)),t.isConfirmed()?(a.safeSet(t,t.isRelayed,t.setIsRelayed,!0),a.safeSet(t,t.getRelay,t.setRelay,!0),a.safeSet(t,t.isFailed,t.setIsFailed,!1)):t.setNumConfirmations(0),void 0===t.isFailed()&&t.setIsFailed(!1),t.getOutputIndices()&&t.getOutputs()){i.equal(t.getOutputs().length,t.getOutputIndices().length);for(let e=0;e0&&console.error("Ignoring non-empty 'overview' field (not implemented): "+e)}catch(t){console.error("Failed to parse 'overview' field: "+e+": "+t.message)}}else"credits"===r?t.setCredits(n.parse(i)):"top_hash"===r?t.setTopBlockHash(""===i?void 0:i):"untrusted"===r||console.log("WARNING: ignoring unexpected field in sync info: "+r+": "+i)}return t}static _convertRpcHardForkInfo(e){let t=new v;for(let r of Object.keys(e)){let i=e[r];"earliest_height"===r?t.setEarliestHeight(i):"enabled"===r?t.setIsEnabled(i):"state"===r?t.setState(i):"status"===r||"untrusted"===r||("threshold"===r?t.setThreshold(i):"version"===r?t.setVersion(i):"votes"===r?t.setNumVotes(i):"voting"===r?t.setVoting(i):"window"===r?t.setWindow(i):"credits"===r?t.setCredits(n.parse(i)):"top_hash"===r?t.setTopBlockHash(""===i?void 0:i):console.log("WARNING: ignoring unexpected field in hard fork info: "+r+": "+i))}return t}static _convertRpcConnectionSpan(e){let t=new MoneroDaemonConnectionSpan;for(let r of Object.keys(e)){let i=e[r];"connection_id"===r?t.setConnectionId(i):"nblocks"===r?t.setNumBlocks(i):"rate"===r?t.setRate(i):"remote_address"===r?""!==i&&t.setRemoteAddress(i):"size"===r?t.setSize(i):"speed"===r?t.setSpeed(i):"start_block_height"===r?t.setStartHeight(i):console.log("WARNING: ignoring unexpected field in daemon connection span: "+r+": "+i)}return t}static _convertRpcOutputHistogramEntry(e){let t=new k;for(let r of Object.keys(e)){let i=e[r];"amount"===r?t.setAmount(n.parse(i)):"total_instances"===r?t.setNumInstances(i):"unlocked_instances"===r?t.setNumUnlockedInstances(i):"recent_instances"===r?t.setNumRecentInstances(i):console.log("WARNING: ignoring unexpected field in output histogram: "+r+": "+i)}return t}static _convertRpcSubmitTxResult(e){i(e);let t=new M;for(let r of Object.keys(e)){let i=e[r];"double_spend"===r?t.setIsDoubleSpend(i):"fee_too_low"===r?t.setIsFeeTooLow(i):"invalid_input"===r?t.setHasInvalidInput(i):"invalid_output"===r?t.setHasInvalidOutput(i):"too_few_outputs"===r?t.setHasTooFewOutputs(i):"low_mixin"===r?t.setIsMixinTooLow(i):"not_relayed"===r?t.setIsRelayed(!i):"overspend"===r?t.setIsOverspend(i):"reason"===r?t.setReason(""===i?void 0:i):"too_big"===r?t.setIsTooBig(i):"sanity_check_failed"===r?t.setSanityCheckFailed(i):"credits"===r?t.setCredits(n.parse(i)):"status"===r||"untrusted"===r||("top_hash"===r?t.setTopBlockHash(""===i?void 0:i):console.log("WARNING: ignoring unexpected field in submit tx hex result: "+r+": "+i))}return t}static _convertRpcTxPoolStats(e){i(e);let t=new MoneroTxPoolStats;for(let r of Object.keys(e)){let i=e[r];if("bytes_max"===r)t.setBytesMax(i);else if("bytes_med"===r)t.setBytesMed(i);else if("bytes_min"===r)t.setBytesMin(i);else if("bytes_total"===r)t.setBytesTotal(i);else if("histo_98pc"===r)t.setHisto98pc(i);else if("num_10m"===r)t.setNum10m(i);else if("num_double_spends"===r)t.setNumDoubleSpends(i);else if("num_failing"===r)t.setNumFailing(i);else if("num_not_relayed"===r)t.setNumNotRelayed(i);else if("oldest"===r)t.setOldestTimestamp(i);else if("txs_total"===r)t.setNumTxs(i);else if("fee_total"===r)t.setFeeTotal(n.parse(i));else{if("histo"===r)throw new _("Not implemented");console.log("WARNING: ignoring unexpected field in tx pool stats: "+r+": "+i)}}return t}static _convertRpcAltChain(e){i(e);let t=new s;for(let r of Object.keys(e)){let i=e[r];"block_hash"===r||"difficulty"===r||"difficulty_top64"===r||("wide_difficulty"===r?t.setDifficulty(a.reconcile(t.getDifficulty(),R._prefixedHexToBI(i))):"height"===r?t.setHeight(i):"length"===r?t.setLength(i):"block_hashes"===r?t.setBlockHashes(i):"main_chain_parent_block"===r?t.setMainChainParentBlockHash(i):console.log("WARNING: ignoring unexpected field in alternative chain: "+r+": "+i))}return t}static _convertRpcPeer(e){i(e);let t=new m;for(let r of Object.keys(e)){let i=e[r];"host"===r?t.setHost(i):"id"===r?t.setId(""+i):"ip"===r||("last_seen"===r?t.setLastSeenTimestamp(i):"port"===r?t.setPort(i):"rpc_port"===r?t.setRpcPort(i):"pruning_seed"===r?t.setPruningSeed(i):"rpc_credits_per_hash"===r?t.setRpcCreditsPerHash(n.parse(i)):console.log("WARNING: ignoring unexpected field in rpc peer: "+r+": "+i))}return t}static _convertRpcConnection(e){let t=new p,r=new m;t.setPeer(r),r.setIsOnline(!0);for(let i of Object.keys(e)){let a=e[i];"address"===i?r.setAddress(a):"avg_download"===i?t.setAvgDownload(a):"avg_upload"===i?t.setAvgUpload(a):"connection_id"===i?t.setId(a):"current_download"===i?t.setCurrentDownload(a):"current_upload"===i?t.setCurrentUpload(a):"height"===i?t.setHeight(a):"host"===i?r.setHost(a):"ip"===i||("incoming"===i?t.setIsIncoming(a):"live_time"===i?t.setLiveTime(a):"local_ip"===i?t.setIsLocalIp(a):"localhost"===i?t.setIsLocalHost(a):"peer_id"===i?r.setId(a):"port"===i?r.setPort(parseInt(a)):"rpc_port"===i?r.setRpcPort(a):"recv_count"===i?t.setNumReceives(a):"recv_idle_time"===i?t.setReceiveIdleTime(a):"send_count"===i?t.setNumSends(a):"send_idle_time"===i?t.setSendIdleTime(a):"state"===i?t.setState(a):"support_flags"===i?t.setNumSupportFlags(a):"pruning_seed"===i?r.setPruningSeed(a):"rpc_credits_per_hash"===i?r.setRpcCreditsPerHash(n.parse(a)):"address_type"===i?t.setType(a):console.log("WARNING: ignoring unexpected field in connection: "+i+": "+a))}return t}static _convertToRpcBan(e){let t={};return t.host=e.getHost(),t.ip=e.getIp(),t.ban=e.isBanned(),t.seconds=e.getSeconds(),t}static _convertRpcMiningStatus(e){let t=new E;return t.setIsActive(e.active),t.setSpeed(e.speed),t.setNumThreads(e.threads_count),e.active&&(t.setAddress(e.address),t.setIsBackground(e.is_background_mining_enabled)),t}static _convertRpcUpdateCheckResult(e){i(e);let t=new MoneroDaemonUpdateCheckResult;for(let r of Object.keys(e)){let i=e[r];"auto_uri"===r?t.setAutoUri(i):"hash"===r?t.setHash(i):"path"===r||"status"===r||("update"===r?t.setIsUpdateAvailable(i):"user_uri"===r?t.setUserUri(i):"version"===r?t.setVersion(i):"untrusted"===r||console.log("WARNING: ignoring unexpected field in rpc check update result: "+r+": "+i))}return""===t.getAutoUri()&&t.setAutoUri(void 0),""===t.getUserUri()&&t.setUserUri(void 0),""===t.getVersion()&&t.setVersion(void 0),""===t.getHash()&&t.setHash(void 0),t}static _convertRpcUpdateDownloadResult(e){let t=new MoneroDaemonUpdateDownloadResult(R._convertRpcUpdateCheckResult(e));return t.setDownloadPath(e.path),""===t.getDownloadPath()&&t.setDownloadPath(void 0),t}static _prefixedHexToBI(e){return i("0x"===e.substring(0,2)),n.parse(e,16)}}R.DEFAULT_ID="0000000000000000000000000000000000000000000000000000000000000000",R.MAX_REQ_SIZE="3000000",R.NUM_HEADERS_PER_REQ="750";class I extends d{static async connect(e){let t=a.getUUID();return e=Object.assign({},e,{proxyToWorker:!1}),await o.invokeWorker(t,"connectDaemonRpc",[e]),new I(t,o.getWorker())}constructor(e,t){super(),this.daemonId=e,this.worker=t,this.wrappedListeners=[]}async getRpcConnection(){let e=await this._invokeWorker("daemonGetRpcConnection");return new x(e)}async isConnected(){return this._invokeWorker("daemonIsConnected")}async getVersion(){let e=await this._invokeWorker("daemonGetVersion");return new T(e.number,e.isRelease)}async isTrusted(){return this._invokeWorker("daemonIsTrusted")}async getHeight(){return this._invokeWorker("daemonGetHeight")}async getBlockHash(e){return this._invokeWorker("daemonGetBlockHash",Array.from(arguments))}async getBlockTemplate(e,t){return new h(await this._invokeWorker("daemonGetBlockTemplate",Array.from(arguments)))}async getLastBlockHeader(){return new l(await this._invokeWorker("daemonGetLastBlockHeader"))}async getBlockHeaderByHash(e){return new l(await this._invokeWorker("daemonGetBlockHeaderByHash",Array.from(arguments)))}async getBlockHeaderByHeight(e){return new l(await this._invokeWorker("daemonGetBlockHeaderByHeight",Array.from(arguments)))}async getBlockHeadersByRange(e,t){let r=await this._invokeWorker("daemonGetBlockHeadersByRange",Array.from(arguments)),i=[];for(let e of r)i.push(new l(e));return i}async getBlockByHash(e){return new u(await this._invokeWorker("daemonGetBlockByHash",Array.from(arguments)))}async getBlocksByHash(e,t,r){let i=await this._invokeWorker("daemonGetBlocksByHash",Array.from(arguments)),n=[];for(let e of i)n.push(new u(e));return n}async getBlockByHeight(e){return new u(await this._invokeWorker("daemonGetBlockByHeight",Array.from(arguments)))}async getBlocksByHeight(e){let t=await this._invokeWorker("daemonGetBlocksByHeight",Array.from(arguments)),r=[];for(let e of t)r.push(new u(e));return r}async getBlocksByRange(e,t){let r=await this._invokeWorker("daemonGetBlocksByRange",Array.from(arguments)),i=[];for(let e of r)i.push(new u(e));return i}async getBlocksByRangeChunked(e,t,r){let i=await this._invokeWorker("daemonGetBlocksByRangeChunked",Array.from(arguments)),n=[];for(let e of i)n.push(new u(e));return n}async getBlockHashes(e,t){return this._invokeWorker("daemonGetBlockHashes",Array.from(arguments))}async getTxs(e,t=!1){let r=[];for(let e of await this._invokeWorker("daemonGetTxs",Array.from(arguments)))r.push(new u(e));let i=[];for(let e of r)for(let t of e.getTxs())t.isConfirmed()||t.setBlock(void 0),i.push(t);return i}async getTxHexes(e,t=!1){return this._invokeWorker("daemonGetTxHexes",Array.from(arguments))}async getMinerTxSum(e,t){return new b(await this._invokeWorker("daemonGetMinerTxSum",Array.from(arguments)))}async getFeeEstimate(e){return n.parse(await this._invokeWorker("daemonGetFeeEstimate",Array.from(arguments)))}async submitTxHex(e,t){return new M(await this._invokeWorker("daemonSubmitTxHex",Array.from(arguments)))}async relayTxsByHash(e){return this._invokeWorker("daemonRelayTxsByHash",Array.from(arguments))}async getTxPool(){let e=await this._invokeWorker("daemonGetTxPool"),t=new u(e).getTxs();for(let e of t)e.setBlock(void 0);return t||[]}async getTxPoolHashes(){return this._invokeWorker("daemonGetTxPoolHashes",Array.from(arguments))}async getTxPoolBacklog(){throw new _("Not implemented")}async getTxPoolStats(){return new MoneroTxPoolStats(await this._invokeWorker("daemonGetTxPoolStats"))}async flushTxPool(e){return this._invokeWorker("daemonFlushTxPool",Array.from(arguments))}async getKeyImageSpentStatuses(e){return this._invokeWorker("daemonGetKeyImageSpentStatuses",Array.from(arguments))}async getOutputs(e){throw new _("Not implemented")}async getOutputHistogram(e,t,r,i,n){let a=[];for(let o of await this._invokeWorker("daemonGetOutputHistogram",[e,t,r,i,n]))a.push(new k(o));return a}async getOutputDistribution(e,t,r,i){throw new _("Not implemented")}async getInfo(){return new f(await this._invokeWorker("daemonGetInfo"))}async getSyncInfo(){return new g(await this._invokeWorker("daemonGetSyncInfo"))}async getHardForkInfo(){return new v(await this._invokeWorker("daemonGetHardForkInfo"))}async getAltChains(){let e=[];for(let t of await this._invokeWorker("daemonGetAltChains"))e.push(new s(t));return e}async getAltBlockHashes(){return this._invokeWorker("daemonGetAltBlockHashes")}async getDownloadLimit(){return this._invokeWorker("daemonGetDownloadLimit")}async setDownloadLimit(e){return this._invokeWorker("daemonSetDownloadLimit",Array.from(arguments))}async resetDownloadLimit(){return this._invokeWorker("daemonResetDownloadLimit")}async getUploadLimit(){return this._invokeWorker("daemonGetUploadLimit")}async setUploadLimit(e){return this._invokeWorker("daemonSetUploadLimit",Array.from(arguments))}async resetUploadLimit(){return this._invokeWorker("daemonResetUploadLimit")}async getKnownPeers(){let e=[];for(let t of await this._invokeWorker("daemonGetKnownPeers"))e.push(new m(t));return e}async getConnections(){let e=[];for(let t of await this._invokeWorker("daemonGetConnections"))e.push(new p(t));return e}async setOutgoingPeerLimit(e){return this._invokeWorker("daemonSetIncomingPeerLimit",Array.from(arguments))}async setIncomingPeerLimit(e){return this._invokeWorker("daemonSetIncomingPeerLimit",Array.from(arguments))}async getPeerBans(){let e=[];for(let t of await this._invokeWorker("daemonGetPeerBans"))e.push(new c(t));return e}async setPeerBans(e){let t=[];for(let r of e)t.push(r.toJson());return this._invokeWorker("daemonSetPeerBans",[t])}async startMining(e,t,r,i){return this._invokeWorker("daemonStartMining",Array.from(arguments))}async stopMining(){return this._invokeWorker("daemonStopMining")}async getMiningStatus(){return new E(await this._invokeWorker("daemonGetMiningStatus"))}async submitBlocks(e){throw new _("Not implemented")}async checkForUpdate(){throw new _("Not implemented")}async downloadUpdate(e){throw new _("Not implemented")}async stop(){for(;this.wrappedListeners.length;)await this.removeBlockListener(this.wrappedListeners[0].getListener());return this._invokeWorker("daemonStop")}async getNextBlockHeader(){return new l(await this._invokeWorker("daemonGetNextBlockHeader"))}async addBlockListener(e){let t=new O(e),r=t.getId();return o.WORKER_OBJECTS[this.daemonId].callbacks["onNewBlockHeader_"+r]=[t.onNewBlockHeader,t],this.wrappedListeners.push(t),this._invokeWorker("daemonAddBlockListener",[r])}async removeBlockListener(e){for(let t=0;t>>32-t}function u(e,t,r,i,n,a,o){return c(e+(t&r|~t&i)+n+a|0,o)+t|0}function l(e,t,r,i,n,a,o){return c(e+(t&i|r&~i)+n+a|0,o)+t|0}function h(e,t,r,i,n,a,o){return c(e+(t^r^i)+n+a|0,o)+t|0}function d(e,t,r,i,n,a,o){return c(e+(r^(t|~i))+n+a|0,o)+t|0}i(s,n),s.prototype._update=function(){for(var e=o,t=0;t<16;++t)e[t]=this._block.readInt32LE(4*t);var r=this._a,i=this._b,n=this._c,a=this._d;r=u(r,i,n,a,e[0],3614090360,7),a=u(a,r,i,n,e[1],3905402710,12),n=u(n,a,r,i,e[2],606105819,17),i=u(i,n,a,r,e[3],3250441966,22),r=u(r,i,n,a,e[4],4118548399,7),a=u(a,r,i,n,e[5],1200080426,12),n=u(n,a,r,i,e[6],2821735955,17),i=u(i,n,a,r,e[7],4249261313,22),r=u(r,i,n,a,e[8],1770035416,7),a=u(a,r,i,n,e[9],2336552879,12),n=u(n,a,r,i,e[10],4294925233,17),i=u(i,n,a,r,e[11],2304563134,22),r=u(r,i,n,a,e[12],1804603682,7),a=u(a,r,i,n,e[13],4254626195,12),n=u(n,a,r,i,e[14],2792965006,17),r=l(r,i=u(i,n,a,r,e[15],1236535329,22),n,a,e[1],4129170786,5),a=l(a,r,i,n,e[6],3225465664,9),n=l(n,a,r,i,e[11],643717713,14),i=l(i,n,a,r,e[0],3921069994,20),r=l(r,i,n,a,e[5],3593408605,5),a=l(a,r,i,n,e[10],38016083,9),n=l(n,a,r,i,e[15],3634488961,14),i=l(i,n,a,r,e[4],3889429448,20),r=l(r,i,n,a,e[9],568446438,5),a=l(a,r,i,n,e[14],3275163606,9),n=l(n,a,r,i,e[3],4107603335,14),i=l(i,n,a,r,e[8],1163531501,20),r=l(r,i,n,a,e[13],2850285829,5),a=l(a,r,i,n,e[2],4243563512,9),n=l(n,a,r,i,e[7],1735328473,14),r=h(r,i=l(i,n,a,r,e[12],2368359562,20),n,a,e[5],4294588738,4),a=h(a,r,i,n,e[8],2272392833,11),n=h(n,a,r,i,e[11],1839030562,16),i=h(i,n,a,r,e[14],4259657740,23),r=h(r,i,n,a,e[1],2763975236,4),a=h(a,r,i,n,e[4],1272893353,11),n=h(n,a,r,i,e[7],4139469664,16),i=h(i,n,a,r,e[10],3200236656,23),r=h(r,i,n,a,e[13],681279174,4),a=h(a,r,i,n,e[0],3936430074,11),n=h(n,a,r,i,e[3],3572445317,16),i=h(i,n,a,r,e[6],76029189,23),r=h(r,i,n,a,e[9],3654602809,4),a=h(a,r,i,n,e[12],3873151461,11),n=h(n,a,r,i,e[15],530742520,16),r=d(r,i=h(i,n,a,r,e[2],3299628645,23),n,a,e[0],4096336452,6),a=d(a,r,i,n,e[7],1126891415,10),n=d(n,a,r,i,e[14],2878612391,15),i=d(i,n,a,r,e[5],4237533241,21),r=d(r,i,n,a,e[12],1700485571,6),a=d(a,r,i,n,e[3],2399980690,10),n=d(n,a,r,i,e[10],4293915773,15),i=d(i,n,a,r,e[1],2240044497,21),r=d(r,i,n,a,e[8],1873313359,6),a=d(a,r,i,n,e[15],4264355552,10),n=d(n,a,r,i,e[6],2734768916,15),i=d(i,n,a,r,e[13],1309151649,21),r=d(r,i,n,a,e[4],4149444226,6),a=d(a,r,i,n,e[11],3174756917,10),n=d(n,a,r,i,e[2],718787259,15),i=d(i,n,a,r,e[9],3951481745,21),this._a=this._a+r|0,this._b=this._b+i|0,this._c=this._c+n|0,this._d=this._d+a|0},s.prototype._digest=function(){this._block[this._blockOffset++]=128,this._blockOffset>56&&(this._block.fill(0,this._blockOffset,64),this._update(),this._blockOffset=0),this._block.fill(0,this._blockOffset,56),this._block.writeUInt32LE(this._length[0],56),this._block.writeUInt32LE(this._length[1],60),this._update();var e=a.allocUnsafe(16);return e.writeInt32LE(this._a,0),e.writeInt32LE(this._b,4),e.writeInt32LE(this._c,8),e.writeInt32LE(this._d,12),e},e.exports=s},function(e,t,r){"use strict";var i=r(45).codes.ERR_STREAM_PREMATURE_CLOSE;function n(){}e.exports=function e(t,r,a){if("function"==typeof r)return e(t,null,r);r||(r={}),a=function(e){var t=!1;return function(){if(!t){t=!0;for(var r=arguments.length,i=new Array(r),n=0;n>>32-t}function m(e,t,r,i,n,a,o,s){return f(e+(t^r^i)+a+o|0,s)+n|0}function g(e,t,r,i,n,a,o,s){return f(e+(t&r|~t&i)+a+o|0,s)+n|0}function _(e,t,r,i,n,a,o,s){return f(e+((t|~r)^i)+a+o|0,s)+n|0}function v(e,t,r,i,n,a,o,s){return f(e+(t&i|r&~i)+a+o|0,s)+n|0}function y(e,t,r,i,n,a,o,s){return f(e+(t^(r|~i))+a+o|0,s)+n|0}n(p,a),p.prototype._update=function(){for(var e=o,t=0;t<16;++t)e[t]=this._block.readInt32LE(4*t);for(var r=0|this._a,i=0|this._b,n=0|this._c,a=0|this._d,p=0|this._e,b=0|this._a,E=0|this._b,w=0|this._c,S=0|this._d,k=0|this._e,x=0;x<80;x+=1){var M,N;x<16?(M=m(r,i,n,a,p,e[s[x]],h[0],u[x]),N=y(b,E,w,S,k,e[c[x]],d[0],l[x])):x<32?(M=g(r,i,n,a,p,e[s[x]],h[1],u[x]),N=v(b,E,w,S,k,e[c[x]],d[1],l[x])):x<48?(M=_(r,i,n,a,p,e[s[x]],h[2],u[x]),N=_(b,E,w,S,k,e[c[x]],d[2],l[x])):x<64?(M=v(r,i,n,a,p,e[s[x]],h[3],u[x]),N=g(b,E,w,S,k,e[c[x]],d[3],l[x])):(M=y(r,i,n,a,p,e[s[x]],h[4],u[x]),N=m(b,E,w,S,k,e[c[x]],d[4],l[x])),r=p,p=a,a=f(n,10),n=i,i=M,b=k,k=S,S=f(w,10),w=E,E=N}var j=this._b+n+S|0;this._b=this._c+a+k|0,this._c=this._d+p+b|0,this._d=this._e+r+E|0,this._e=this._a+i+w|0,this._a=j},p.prototype._digest=function(){this._block[this._blockOffset++]=128,this._blockOffset>56&&(this._block.fill(0,this._blockOffset,64),this._update(),this._blockOffset=0),this._block.fill(0,this._blockOffset,56),this._block.writeUInt32LE(this._length[0],56),this._block.writeUInt32LE(this._length[1],60),this._update();var e=i.alloc?i.alloc(20):new i(20);return e.writeInt32LE(this._a,0),e.writeInt32LE(this._b,4),e.writeInt32LE(this._c,8),e.writeInt32LE(this._d,12),e.writeInt32LE(this._e,16),e},e.exports=p},function(e,t,r){(t=e.exports=function(e){e=e.toLowerCase();var r=t[e];if(!r)throw new Error(e+" is not supported (we accept pull requests)");return new r}).sha=r(284),t.sha1=r(285),t.sha224=r(286),t.sha256=r(161),t.sha384=r(287),t.sha512=r(162)},function(e,t,r){(t=e.exports=r(163)).Stream=t,t.Readable=t,t.Writable=r(110),t.Duplex=r(39),t.Transform=r(166),t.PassThrough=r(291)},function(e,t,r){"use strict";(function(t,i,n){var a=r(35);function o(e){var t=this;this.next=null,this.entry=null,this.finish=function(){!function(e,t,r){var i=e.entry;e.entry=null;for(;i;){var n=i.callback;t.pendingcb--,n(r),i=i.next}t.corkedRequestsFree?t.corkedRequestsFree.next=e:t.corkedRequestsFree=e}(t,e)}}e.exports=v;var s,c=!t.browser&&["v0.10","v0.9."].indexOf(t.version.slice(0,5))>-1?i:a.nextTick;v.WritableState=_;var u=Object.create(r(21));u.inherits=r(0);var l={deprecate:r(78)},h=r(164),d=r(1).Buffer,p=n.Uint8Array||function(){};var f,m=r(165);function g(){}function _(e,t){s=s||r(39),e=e||{};var i=t instanceof s;this.objectMode=!!e.objectMode,i&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var n=e.highWaterMark,u=e.writableHighWaterMark,l=this.objectMode?16:16384;this.highWaterMark=n||0===n?n:i&&(u||0===u)?u:l,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var h=!1===e.decodeStrings;this.decodeStrings=!h,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){!function(e,t){var r=e._writableState,i=r.sync,n=r.writecb;if(function(e){e.writing=!1,e.writecb=null,e.length-=e.writelen,e.writelen=0}(r),t)!function(e,t,r,i,n){--t.pendingcb,r?(a.nextTick(n,i),a.nextTick(k,e,t),e._writableState.errorEmitted=!0,e.emit("error",i)):(n(i),e._writableState.errorEmitted=!0,e.emit("error",i),k(e,t))}(e,r,i,t,n);else{var o=w(r);o||r.corked||r.bufferProcessing||!r.bufferedRequest||E(e,r),i?c(b,e,r,o,n):b(e,r,o,n)}}(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new o(this)}function v(e){if(s=s||r(39),!(f.call(v,this)||this instanceof s))return new v(e);this._writableState=new _(e,this),this.writable=!0,e&&("function"==typeof e.write&&(this._write=e.write),"function"==typeof e.writev&&(this._writev=e.writev),"function"==typeof e.destroy&&(this._destroy=e.destroy),"function"==typeof e.final&&(this._final=e.final)),h.call(this)}function y(e,t,r,i,n,a,o){t.writelen=i,t.writecb=o,t.writing=!0,t.sync=!0,r?e._writev(n,t.onwrite):e._write(n,a,t.onwrite),t.sync=!1}function b(e,t,r,i){r||function(e,t){0===t.length&&t.needDrain&&(t.needDrain=!1,e.emit("drain"))}(e,t),t.pendingcb--,i(),k(e,t)}function E(e,t){t.bufferProcessing=!0;var r=t.bufferedRequest;if(e._writev&&r&&r.next){var i=t.bufferedRequestCount,n=new Array(i),a=t.corkedRequestsFree;a.entry=r;for(var s=0,c=!0;r;)n[s]=r,r.isBuf||(c=!1),r=r.next,s+=1;n.allBuffers=c,y(e,t,!0,t.length,n,"",a.finish),t.pendingcb++,t.lastBufferedRequest=null,a.next?(t.corkedRequestsFree=a.next,a.next=null):t.corkedRequestsFree=new o(t),t.bufferedRequestCount=0}else{for(;r;){var u=r.chunk,l=r.encoding,h=r.callback;if(y(e,t,!1,t.objectMode?1:u.length,u,l,h),r=r.next,t.bufferedRequestCount--,t.writing)break}null===r&&(t.lastBufferedRequest=null)}t.bufferedRequest=r,t.bufferProcessing=!1}function w(e){return e.ending&&0===e.length&&null===e.bufferedRequest&&!e.finished&&!e.writing}function S(e,t){e._final((function(r){t.pendingcb--,r&&e.emit("error",r),t.prefinished=!0,e.emit("prefinish"),k(e,t)}))}function k(e,t){var r=w(t);return r&&(!function(e,t){t.prefinished||t.finalCalled||("function"==typeof e._final?(t.pendingcb++,t.finalCalled=!0,a.nextTick(S,e,t)):(t.prefinished=!0,e.emit("prefinish")))}(e,t),0===t.pendingcb&&(t.finished=!0,e.emit("finish"))),r}u.inherits(v,h),_.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(_.prototype,"buffer",{get:l.deprecate((function(){return this.getBuffer()}),"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch(e){}}(),"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(f=Function.prototype[Symbol.hasInstance],Object.defineProperty(v,Symbol.hasInstance,{value:function(e){return!!f.call(this,e)||this===v&&(e&&e._writableState instanceof _)}})):f=function(e){return e instanceof this},v.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))},v.prototype.write=function(e,t,r){var i,n=this._writableState,o=!1,s=!n.objectMode&&(i=e,d.isBuffer(i)||i instanceof p);return s&&!d.isBuffer(e)&&(e=function(e){return d.from(e)}(e)),"function"==typeof t&&(r=t,t=null),s?t="buffer":t||(t=n.defaultEncoding),"function"!=typeof r&&(r=g),n.ended?function(e,t){var r=new Error("write after end");e.emit("error",r),a.nextTick(t,r)}(this,r):(s||function(e,t,r,i){var n=!0,o=!1;return null===r?o=new TypeError("May not write null values to stream"):"string"==typeof r||void 0===r||t.objectMode||(o=new TypeError("Invalid non-string/buffer chunk")),o&&(e.emit("error",o),a.nextTick(i,o),n=!1),n}(this,n,e,r))&&(n.pendingcb++,o=function(e,t,r,i,n,a){if(!r){var o=function(e,t,r){e.objectMode||!1===e.decodeStrings||"string"!=typeof t||(t=d.from(t,r));return t}(t,i,n);i!==o&&(r=!0,n="buffer",i=o)}var s=t.objectMode?1:i.length;t.length+=s;var c=t.length-1))throw new TypeError("Unknown encoding: "+e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(v.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),v.prototype._write=function(e,t,r){r(new Error("_write() is not implemented"))},v.prototype._writev=null,v.prototype.end=function(e,t,r){var i=this._writableState;"function"==typeof e?(r=e,e=null,t=null):"function"==typeof t&&(r=t,t=null),null!=e&&this.write(e,t),i.corked&&(i.corked=1,this.uncork()),i.ending||i.finished||function(e,t,r){t.ending=!0,k(e,t),r&&(t.finished?a.nextTick(r):e.once("finish",r));t.ended=!0,e.writable=!1}(this,i,r)},Object.defineProperty(v.prototype,"destroyed",{get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),v.prototype.destroy=m.destroy,v.prototype._undestroy=m.undestroy,v.prototype._destroy=function(e,t){this.end(),t(e)}}).call(this,r(3),r(32).setImmediate,r(8))},function(e,t,r){"use strict";var i=r(19);function n(e){this.options=e,this.type=this.options.type,this.blockSize=8,this._init(),this.buffer=new Array(this.blockSize),this.bufferOff=0}e.exports=n,n.prototype._init=function(){},n.prototype.update=function(e){return 0===e.length?[]:"decrypt"===this.type?this._updateDecrypt(e):this._updateEncrypt(e)},n.prototype._buffer=function(e,t){for(var r=Math.min(this.buffer.length-this.bufferOff,e.length-t),i=0;i0;i--)t+=this._buffer(e,t),r+=this._flushBuffer(n,r);return t+=this._buffer(e,t),n},n.prototype.final=function(e){var t,r;return e&&(t=this.update(e)),r="encrypt"===this.type?this._finalEncrypt():this._finalDecrypt(),t?t.concat(r):r},n.prototype._pad=function(e,t){if(0===t)return!1;for(;t=0||!r.umod(e.prime1)||!r.umod(e.prime2);)r=new i(n(t));return r}e.exports=a,a.getr=o}).call(this,r(2).Buffer)},function(e,t,r){"use strict";var i=t;i.version=r(333).version,i.utils=r(20),i.rand=r(114),i.curve=r(191),i.curves=r(118),i.ec=r(345),i.eddsa=r(349)},function(e,t,r){"use strict";var i,n=t,a=r(119),o=r(191),s=r(20).assert;function c(e){"short"===e.type?this.curve=new o.short(e):"edwards"===e.type?this.curve=new o.edwards(e):this.curve=new o.mont(e),this.g=this.curve.g,this.n=this.curve.n,this.hash=e.hash,s(this.g.validate(),"Invalid curve"),s(this.g.mul(this.n).isInfinity(),"Invalid curve, G*N != O")}function u(e,t){Object.defineProperty(n,e,{configurable:!0,enumerable:!0,get:function(){var r=new c(t);return Object.defineProperty(n,e,{configurable:!0,enumerable:!0,value:r}),r}})}n.PresetCurve=c,u("p192",{type:"short",prime:"p192",p:"ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff",a:"ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc",b:"64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1",n:"ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831",hash:a.sha256,gRed:!1,g:["188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012","07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811"]}),u("p224",{type:"short",prime:"p224",p:"ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001",a:"ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe",b:"b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4",n:"ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d",hash:a.sha256,gRed:!1,g:["b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21","bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34"]}),u("p256",{type:"short",prime:null,p:"ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff",a:"ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc",b:"5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b",n:"ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551",hash:a.sha256,gRed:!1,g:["6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296","4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5"]}),u("p384",{type:"short",prime:null,p:"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe ffffffff 00000000 00000000 ffffffff",a:"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe ffffffff 00000000 00000000 fffffffc",b:"b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 0314088f 5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef",n:"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff c7634d81 f4372ddf 581a0db2 48b0a77a ecec196a ccc52973",hash:a.sha384,gRed:!1,g:["aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 59f741e0 82542a38 5502f25d bf55296c 3a545e38 72760ab7","3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c e9da3113 b5f0b8c0 0a60b1ce 1d7e819d 7a431d7c 90ea0e5f"]}),u("p521",{type:"short",prime:null,p:"000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff",a:"000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffc",b:"00000051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b 99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd 3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00",n:"000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148 f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409",hash:a.sha512,gRed:!1,g:["000000c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66","00000118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901 3fad0761 353c7086 a272c240 88be9476 9fd16650"]}),u("curve25519",{type:"mont",prime:"p25519",p:"7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed",a:"76d06",b:"1",n:"1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed",hash:a.sha256,gRed:!1,g:["9"]}),u("ed25519",{type:"edwards",prime:"p25519",p:"7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed",a:"-1",c:"1",d:"52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3",n:"1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed",hash:a.sha256,gRed:!1,g:["216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a","6666666666666666666666666666666666666666666666666666666666666658"]});try{i=r(344)}catch(e){i=void 0}u("secp256k1",{type:"short",prime:"k256",p:"ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f",a:"0",b:"7",n:"ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141",h:"1",hash:a.sha256,beta:"7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee",lambda:"5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72",basis:[{a:"3086d221a7d46bcde86c90e49284eb15",b:"-e4437ed6010e88286f547fa90abfe4c3"},{a:"114ca50f7a8e2f3f657c1108d9d44cfd8",b:"3086d221a7d46bcde86c90e49284eb15"}],gRed:!1,g:["79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",i]})},function(e,t,r){var i=t;i.utils=r(24),i.common=r(63),i.sha=r(338),i.ripemd=r(342),i.hmac=r(343),i.sha1=i.sha.sha1,i.sha256=i.sha.sha256,i.sha224=i.sha.sha224,i.sha384=i.sha.sha384,i.sha512=i.sha.sha512,i.ripemd160=i.ripemd.ripemd160},function(e,t,r){(function(e){!function(e,t){"use strict";function i(e,t){if(!e)throw new Error(t||"Assertion failed")}function n(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}function a(e,t,r){if(a.isBN(e))return e;this.negative=0,this.words=null,this.length=0,this.red=null,null!==e&&("le"!==t&&"be"!==t||(r=t,t=10),this._init(e||0,t||10,r||"be"))}var o;"object"==typeof e?e.exports=a:t.BN=a,a.BN=a,a.wordSize=26;try{o=r(374).Buffer}catch(e){}function s(e,t,r){for(var i=0,n=Math.min(e.length,r),a=t;a=49&&o<=54?o-49+10:o>=17&&o<=22?o-17+10:15&o}return i}function c(e,t,r,i){for(var n=0,a=Math.min(e.length,r),o=t;o=49?s-49+10:s>=17?s-17+10:s}return n}a.isBN=function(e){return e instanceof a||null!==e&&"object"==typeof e&&e.constructor.wordSize===a.wordSize&&Array.isArray(e.words)},a.max=function(e,t){return e.cmp(t)>0?e:t},a.min=function(e,t){return e.cmp(t)<0?e:t},a.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),i(t===(0|t)&&t>=2&&t<=36);var n=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&n++,16===t?this._parseHex(e,n):this._parseBase(e,t,n),"-"===e[0]&&(this.negative=1),this.strip(),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(i(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initArray=function(e,t,r){if(i("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var n=0;n=0;n-=3)o=e[n]|e[n-1]<<8|e[n-2]<<16,this.words[a]|=o<>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);else if("le"===r)for(n=0,a=0;n>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);return this.strip()},a.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)n=s(e,r,r+6),this.words[i]|=n<>>26-a&4194303,(a+=24)>=26&&(a-=26,i++);r+6!==t&&(n=s(e,t,r+6),this.words[i]|=n<>>26-a&4194303),this.strip()},a.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var i=0,n=1;n<=67108863;n*=t)i++;i--,n=n/t|0;for(var a=e.length-r,o=a%i,s=Math.min(a,a-o)+r,u=0,l=r;l1&&0===this.words[this.length-1];)this.length--;return this._normSign()},a.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},a.prototype.inspect=function(){return(this.red?""};var u=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],l=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],h=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];function d(e,t,r){r.negative=t.negative^e.negative;var i=e.length+t.length|0;r.length=i,i=i-1|0;var n=0|e.words[0],a=0|t.words[0],o=n*a,s=67108863&o,c=o/67108864|0;r.words[0]=s;for(var u=1;u>>26,h=67108863&c,d=Math.min(u,t.length-1),p=Math.max(0,u-e.length+1);p<=d;p++){var f=u-p|0;l+=(o=(n=0|e.words[f])*(a=0|t.words[p])+h)/67108864|0,h=67108863&o}r.words[u]=0|h,c=0|l}return 0!==c?r.words[u]=0|c:r.length--,r.strip()}a.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var n=0,a=0,o=0;o>>24-n&16777215)||o!==this.length-1?u[6-c.length]+c+r:c+r,(n+=2)>=26&&(n-=26,o--)}for(0!==a&&(r=a.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var d=l[e],p=h[e];r="";var f=this.clone();for(f.negative=0;!f.isZero();){var m=f.modn(p).toString(e);r=(f=f.idivn(p)).isZero()?m+r:u[d-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}i(!1,"Base should be between 2 and 36")},a.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&i(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},a.prototype.toJSON=function(){return this.toString(16)},a.prototype.toBuffer=function(e,t){return i(void 0!==o),this.toArrayLike(o,e,t)},a.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)},a.prototype.toArrayLike=function(e,t,r){var n=this.byteLength(),a=r||Math.max(1,n);i(n<=a,"byte array longer than desired length"),i(a>0,"Requested array length <= 0"),this.strip();var o,s,c="le"===t,u=new e(a),l=this.clone();if(c){for(s=0;!l.isZero();s++)o=l.andln(255),l.iushrn(8),u[s]=o;for(;s=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},a.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},a.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},a.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},a.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},a.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},a.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},a.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var i=0;ie.length?this.clone().ixor(e):e.clone().ixor(this)},a.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},a.prototype.inotn=function(e){i("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var n=0;n0&&(this.words[n]=~this.words[n]&67108863>>26-r),this.strip()},a.prototype.notn=function(e){return this.clone().inotn(e)},a.prototype.setn=function(e,t){i("number"==typeof e&&e>=0);var r=e/26|0,n=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,i=e):(r=e,i=this);for(var n=0,a=0;a>>26;for(;0!==n&&a>>26;if(this.length=r.length,0!==n)this.words[this.length]=n,this.length++;else if(r!==this)for(;ae.length?this.clone().iadd(e):e.clone().iadd(this)},a.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,i,n=this.cmp(e);if(0===n)return this.negative=0,this.length=1,this.words[0]=0,this;n>0?(r=this,i=e):(r=e,i=this);for(var a=0,o=0;o>26,this.words[o]=67108863&t;for(;0!==a&&o>26,this.words[o]=67108863&t;if(0===a&&o>>13,p=0|o[1],f=8191&p,m=p>>>13,g=0|o[2],_=8191&g,v=g>>>13,y=0|o[3],b=8191&y,E=y>>>13,w=0|o[4],S=8191&w,k=w>>>13,x=0|o[5],M=8191&x,N=x>>>13,j=0|o[6],T=8191&j,R=j>>>13,I=0|o[7],O=8191&I,A=I>>>13,P=0|o[8],D=8191&P,F=P>>>13,C=0|o[9],B=8191&C,z=C>>>13,L=0|s[0],U=8191&L,H=L>>>13,q=0|s[1],K=8191&q,Z=q>>>13,W=0|s[2],X=8191&W,Q=W>>>13,J=0|s[3],V=8191&J,G=J>>>13,Y=0|s[4],$=8191&Y,ee=Y>>>13,te=0|s[5],re=8191&te,ie=te>>>13,ne=0|s[6],ae=8191&ne,oe=ne>>>13,se=0|s[7],ce=8191&se,ue=se>>>13,le=0|s[8],he=8191&le,de=le>>>13,pe=0|s[9],fe=8191&pe,me=pe>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(u+(i=Math.imul(h,U))|0)+((8191&(n=(n=Math.imul(h,H))+Math.imul(d,U)|0))<<13)|0;u=((a=Math.imul(d,H))+(n>>>13)|0)+(ge>>>26)|0,ge&=67108863,i=Math.imul(f,U),n=(n=Math.imul(f,H))+Math.imul(m,U)|0,a=Math.imul(m,H);var _e=(u+(i=i+Math.imul(h,K)|0)|0)+((8191&(n=(n=n+Math.imul(h,Z)|0)+Math.imul(d,K)|0))<<13)|0;u=((a=a+Math.imul(d,Z)|0)+(n>>>13)|0)+(_e>>>26)|0,_e&=67108863,i=Math.imul(_,U),n=(n=Math.imul(_,H))+Math.imul(v,U)|0,a=Math.imul(v,H),i=i+Math.imul(f,K)|0,n=(n=n+Math.imul(f,Z)|0)+Math.imul(m,K)|0,a=a+Math.imul(m,Z)|0;var ve=(u+(i=i+Math.imul(h,X)|0)|0)+((8191&(n=(n=n+Math.imul(h,Q)|0)+Math.imul(d,X)|0))<<13)|0;u=((a=a+Math.imul(d,Q)|0)+(n>>>13)|0)+(ve>>>26)|0,ve&=67108863,i=Math.imul(b,U),n=(n=Math.imul(b,H))+Math.imul(E,U)|0,a=Math.imul(E,H),i=i+Math.imul(_,K)|0,n=(n=n+Math.imul(_,Z)|0)+Math.imul(v,K)|0,a=a+Math.imul(v,Z)|0,i=i+Math.imul(f,X)|0,n=(n=n+Math.imul(f,Q)|0)+Math.imul(m,X)|0,a=a+Math.imul(m,Q)|0;var ye=(u+(i=i+Math.imul(h,V)|0)|0)+((8191&(n=(n=n+Math.imul(h,G)|0)+Math.imul(d,V)|0))<<13)|0;u=((a=a+Math.imul(d,G)|0)+(n>>>13)|0)+(ye>>>26)|0,ye&=67108863,i=Math.imul(S,U),n=(n=Math.imul(S,H))+Math.imul(k,U)|0,a=Math.imul(k,H),i=i+Math.imul(b,K)|0,n=(n=n+Math.imul(b,Z)|0)+Math.imul(E,K)|0,a=a+Math.imul(E,Z)|0,i=i+Math.imul(_,X)|0,n=(n=n+Math.imul(_,Q)|0)+Math.imul(v,X)|0,a=a+Math.imul(v,Q)|0,i=i+Math.imul(f,V)|0,n=(n=n+Math.imul(f,G)|0)+Math.imul(m,V)|0,a=a+Math.imul(m,G)|0;var be=(u+(i=i+Math.imul(h,$)|0)|0)+((8191&(n=(n=n+Math.imul(h,ee)|0)+Math.imul(d,$)|0))<<13)|0;u=((a=a+Math.imul(d,ee)|0)+(n>>>13)|0)+(be>>>26)|0,be&=67108863,i=Math.imul(M,U),n=(n=Math.imul(M,H))+Math.imul(N,U)|0,a=Math.imul(N,H),i=i+Math.imul(S,K)|0,n=(n=n+Math.imul(S,Z)|0)+Math.imul(k,K)|0,a=a+Math.imul(k,Z)|0,i=i+Math.imul(b,X)|0,n=(n=n+Math.imul(b,Q)|0)+Math.imul(E,X)|0,a=a+Math.imul(E,Q)|0,i=i+Math.imul(_,V)|0,n=(n=n+Math.imul(_,G)|0)+Math.imul(v,V)|0,a=a+Math.imul(v,G)|0,i=i+Math.imul(f,$)|0,n=(n=n+Math.imul(f,ee)|0)+Math.imul(m,$)|0,a=a+Math.imul(m,ee)|0;var Ee=(u+(i=i+Math.imul(h,re)|0)|0)+((8191&(n=(n=n+Math.imul(h,ie)|0)+Math.imul(d,re)|0))<<13)|0;u=((a=a+Math.imul(d,ie)|0)+(n>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,i=Math.imul(T,U),n=(n=Math.imul(T,H))+Math.imul(R,U)|0,a=Math.imul(R,H),i=i+Math.imul(M,K)|0,n=(n=n+Math.imul(M,Z)|0)+Math.imul(N,K)|0,a=a+Math.imul(N,Z)|0,i=i+Math.imul(S,X)|0,n=(n=n+Math.imul(S,Q)|0)+Math.imul(k,X)|0,a=a+Math.imul(k,Q)|0,i=i+Math.imul(b,V)|0,n=(n=n+Math.imul(b,G)|0)+Math.imul(E,V)|0,a=a+Math.imul(E,G)|0,i=i+Math.imul(_,$)|0,n=(n=n+Math.imul(_,ee)|0)+Math.imul(v,$)|0,a=a+Math.imul(v,ee)|0,i=i+Math.imul(f,re)|0,n=(n=n+Math.imul(f,ie)|0)+Math.imul(m,re)|0,a=a+Math.imul(m,ie)|0;var we=(u+(i=i+Math.imul(h,ae)|0)|0)+((8191&(n=(n=n+Math.imul(h,oe)|0)+Math.imul(d,ae)|0))<<13)|0;u=((a=a+Math.imul(d,oe)|0)+(n>>>13)|0)+(we>>>26)|0,we&=67108863,i=Math.imul(O,U),n=(n=Math.imul(O,H))+Math.imul(A,U)|0,a=Math.imul(A,H),i=i+Math.imul(T,K)|0,n=(n=n+Math.imul(T,Z)|0)+Math.imul(R,K)|0,a=a+Math.imul(R,Z)|0,i=i+Math.imul(M,X)|0,n=(n=n+Math.imul(M,Q)|0)+Math.imul(N,X)|0,a=a+Math.imul(N,Q)|0,i=i+Math.imul(S,V)|0,n=(n=n+Math.imul(S,G)|0)+Math.imul(k,V)|0,a=a+Math.imul(k,G)|0,i=i+Math.imul(b,$)|0,n=(n=n+Math.imul(b,ee)|0)+Math.imul(E,$)|0,a=a+Math.imul(E,ee)|0,i=i+Math.imul(_,re)|0,n=(n=n+Math.imul(_,ie)|0)+Math.imul(v,re)|0,a=a+Math.imul(v,ie)|0,i=i+Math.imul(f,ae)|0,n=(n=n+Math.imul(f,oe)|0)+Math.imul(m,ae)|0,a=a+Math.imul(m,oe)|0;var Se=(u+(i=i+Math.imul(h,ce)|0)|0)+((8191&(n=(n=n+Math.imul(h,ue)|0)+Math.imul(d,ce)|0))<<13)|0;u=((a=a+Math.imul(d,ue)|0)+(n>>>13)|0)+(Se>>>26)|0,Se&=67108863,i=Math.imul(D,U),n=(n=Math.imul(D,H))+Math.imul(F,U)|0,a=Math.imul(F,H),i=i+Math.imul(O,K)|0,n=(n=n+Math.imul(O,Z)|0)+Math.imul(A,K)|0,a=a+Math.imul(A,Z)|0,i=i+Math.imul(T,X)|0,n=(n=n+Math.imul(T,Q)|0)+Math.imul(R,X)|0,a=a+Math.imul(R,Q)|0,i=i+Math.imul(M,V)|0,n=(n=n+Math.imul(M,G)|0)+Math.imul(N,V)|0,a=a+Math.imul(N,G)|0,i=i+Math.imul(S,$)|0,n=(n=n+Math.imul(S,ee)|0)+Math.imul(k,$)|0,a=a+Math.imul(k,ee)|0,i=i+Math.imul(b,re)|0,n=(n=n+Math.imul(b,ie)|0)+Math.imul(E,re)|0,a=a+Math.imul(E,ie)|0,i=i+Math.imul(_,ae)|0,n=(n=n+Math.imul(_,oe)|0)+Math.imul(v,ae)|0,a=a+Math.imul(v,oe)|0,i=i+Math.imul(f,ce)|0,n=(n=n+Math.imul(f,ue)|0)+Math.imul(m,ce)|0,a=a+Math.imul(m,ue)|0;var ke=(u+(i=i+Math.imul(h,he)|0)|0)+((8191&(n=(n=n+Math.imul(h,de)|0)+Math.imul(d,he)|0))<<13)|0;u=((a=a+Math.imul(d,de)|0)+(n>>>13)|0)+(ke>>>26)|0,ke&=67108863,i=Math.imul(B,U),n=(n=Math.imul(B,H))+Math.imul(z,U)|0,a=Math.imul(z,H),i=i+Math.imul(D,K)|0,n=(n=n+Math.imul(D,Z)|0)+Math.imul(F,K)|0,a=a+Math.imul(F,Z)|0,i=i+Math.imul(O,X)|0,n=(n=n+Math.imul(O,Q)|0)+Math.imul(A,X)|0,a=a+Math.imul(A,Q)|0,i=i+Math.imul(T,V)|0,n=(n=n+Math.imul(T,G)|0)+Math.imul(R,V)|0,a=a+Math.imul(R,G)|0,i=i+Math.imul(M,$)|0,n=(n=n+Math.imul(M,ee)|0)+Math.imul(N,$)|0,a=a+Math.imul(N,ee)|0,i=i+Math.imul(S,re)|0,n=(n=n+Math.imul(S,ie)|0)+Math.imul(k,re)|0,a=a+Math.imul(k,ie)|0,i=i+Math.imul(b,ae)|0,n=(n=n+Math.imul(b,oe)|0)+Math.imul(E,ae)|0,a=a+Math.imul(E,oe)|0,i=i+Math.imul(_,ce)|0,n=(n=n+Math.imul(_,ue)|0)+Math.imul(v,ce)|0,a=a+Math.imul(v,ue)|0,i=i+Math.imul(f,he)|0,n=(n=n+Math.imul(f,de)|0)+Math.imul(m,he)|0,a=a+Math.imul(m,de)|0;var xe=(u+(i=i+Math.imul(h,fe)|0)|0)+((8191&(n=(n=n+Math.imul(h,me)|0)+Math.imul(d,fe)|0))<<13)|0;u=((a=a+Math.imul(d,me)|0)+(n>>>13)|0)+(xe>>>26)|0,xe&=67108863,i=Math.imul(B,K),n=(n=Math.imul(B,Z))+Math.imul(z,K)|0,a=Math.imul(z,Z),i=i+Math.imul(D,X)|0,n=(n=n+Math.imul(D,Q)|0)+Math.imul(F,X)|0,a=a+Math.imul(F,Q)|0,i=i+Math.imul(O,V)|0,n=(n=n+Math.imul(O,G)|0)+Math.imul(A,V)|0,a=a+Math.imul(A,G)|0,i=i+Math.imul(T,$)|0,n=(n=n+Math.imul(T,ee)|0)+Math.imul(R,$)|0,a=a+Math.imul(R,ee)|0,i=i+Math.imul(M,re)|0,n=(n=n+Math.imul(M,ie)|0)+Math.imul(N,re)|0,a=a+Math.imul(N,ie)|0,i=i+Math.imul(S,ae)|0,n=(n=n+Math.imul(S,oe)|0)+Math.imul(k,ae)|0,a=a+Math.imul(k,oe)|0,i=i+Math.imul(b,ce)|0,n=(n=n+Math.imul(b,ue)|0)+Math.imul(E,ce)|0,a=a+Math.imul(E,ue)|0,i=i+Math.imul(_,he)|0,n=(n=n+Math.imul(_,de)|0)+Math.imul(v,he)|0,a=a+Math.imul(v,de)|0;var Me=(u+(i=i+Math.imul(f,fe)|0)|0)+((8191&(n=(n=n+Math.imul(f,me)|0)+Math.imul(m,fe)|0))<<13)|0;u=((a=a+Math.imul(m,me)|0)+(n>>>13)|0)+(Me>>>26)|0,Me&=67108863,i=Math.imul(B,X),n=(n=Math.imul(B,Q))+Math.imul(z,X)|0,a=Math.imul(z,Q),i=i+Math.imul(D,V)|0,n=(n=n+Math.imul(D,G)|0)+Math.imul(F,V)|0,a=a+Math.imul(F,G)|0,i=i+Math.imul(O,$)|0,n=(n=n+Math.imul(O,ee)|0)+Math.imul(A,$)|0,a=a+Math.imul(A,ee)|0,i=i+Math.imul(T,re)|0,n=(n=n+Math.imul(T,ie)|0)+Math.imul(R,re)|0,a=a+Math.imul(R,ie)|0,i=i+Math.imul(M,ae)|0,n=(n=n+Math.imul(M,oe)|0)+Math.imul(N,ae)|0,a=a+Math.imul(N,oe)|0,i=i+Math.imul(S,ce)|0,n=(n=n+Math.imul(S,ue)|0)+Math.imul(k,ce)|0,a=a+Math.imul(k,ue)|0,i=i+Math.imul(b,he)|0,n=(n=n+Math.imul(b,de)|0)+Math.imul(E,he)|0,a=a+Math.imul(E,de)|0;var Ne=(u+(i=i+Math.imul(_,fe)|0)|0)+((8191&(n=(n=n+Math.imul(_,me)|0)+Math.imul(v,fe)|0))<<13)|0;u=((a=a+Math.imul(v,me)|0)+(n>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,i=Math.imul(B,V),n=(n=Math.imul(B,G))+Math.imul(z,V)|0,a=Math.imul(z,G),i=i+Math.imul(D,$)|0,n=(n=n+Math.imul(D,ee)|0)+Math.imul(F,$)|0,a=a+Math.imul(F,ee)|0,i=i+Math.imul(O,re)|0,n=(n=n+Math.imul(O,ie)|0)+Math.imul(A,re)|0,a=a+Math.imul(A,ie)|0,i=i+Math.imul(T,ae)|0,n=(n=n+Math.imul(T,oe)|0)+Math.imul(R,ae)|0,a=a+Math.imul(R,oe)|0,i=i+Math.imul(M,ce)|0,n=(n=n+Math.imul(M,ue)|0)+Math.imul(N,ce)|0,a=a+Math.imul(N,ue)|0,i=i+Math.imul(S,he)|0,n=(n=n+Math.imul(S,de)|0)+Math.imul(k,he)|0,a=a+Math.imul(k,de)|0;var je=(u+(i=i+Math.imul(b,fe)|0)|0)+((8191&(n=(n=n+Math.imul(b,me)|0)+Math.imul(E,fe)|0))<<13)|0;u=((a=a+Math.imul(E,me)|0)+(n>>>13)|0)+(je>>>26)|0,je&=67108863,i=Math.imul(B,$),n=(n=Math.imul(B,ee))+Math.imul(z,$)|0,a=Math.imul(z,ee),i=i+Math.imul(D,re)|0,n=(n=n+Math.imul(D,ie)|0)+Math.imul(F,re)|0,a=a+Math.imul(F,ie)|0,i=i+Math.imul(O,ae)|0,n=(n=n+Math.imul(O,oe)|0)+Math.imul(A,ae)|0,a=a+Math.imul(A,oe)|0,i=i+Math.imul(T,ce)|0,n=(n=n+Math.imul(T,ue)|0)+Math.imul(R,ce)|0,a=a+Math.imul(R,ue)|0,i=i+Math.imul(M,he)|0,n=(n=n+Math.imul(M,de)|0)+Math.imul(N,he)|0,a=a+Math.imul(N,de)|0;var Te=(u+(i=i+Math.imul(S,fe)|0)|0)+((8191&(n=(n=n+Math.imul(S,me)|0)+Math.imul(k,fe)|0))<<13)|0;u=((a=a+Math.imul(k,me)|0)+(n>>>13)|0)+(Te>>>26)|0,Te&=67108863,i=Math.imul(B,re),n=(n=Math.imul(B,ie))+Math.imul(z,re)|0,a=Math.imul(z,ie),i=i+Math.imul(D,ae)|0,n=(n=n+Math.imul(D,oe)|0)+Math.imul(F,ae)|0,a=a+Math.imul(F,oe)|0,i=i+Math.imul(O,ce)|0,n=(n=n+Math.imul(O,ue)|0)+Math.imul(A,ce)|0,a=a+Math.imul(A,ue)|0,i=i+Math.imul(T,he)|0,n=(n=n+Math.imul(T,de)|0)+Math.imul(R,he)|0,a=a+Math.imul(R,de)|0;var Re=(u+(i=i+Math.imul(M,fe)|0)|0)+((8191&(n=(n=n+Math.imul(M,me)|0)+Math.imul(N,fe)|0))<<13)|0;u=((a=a+Math.imul(N,me)|0)+(n>>>13)|0)+(Re>>>26)|0,Re&=67108863,i=Math.imul(B,ae),n=(n=Math.imul(B,oe))+Math.imul(z,ae)|0,a=Math.imul(z,oe),i=i+Math.imul(D,ce)|0,n=(n=n+Math.imul(D,ue)|0)+Math.imul(F,ce)|0,a=a+Math.imul(F,ue)|0,i=i+Math.imul(O,he)|0,n=(n=n+Math.imul(O,de)|0)+Math.imul(A,he)|0,a=a+Math.imul(A,de)|0;var Ie=(u+(i=i+Math.imul(T,fe)|0)|0)+((8191&(n=(n=n+Math.imul(T,me)|0)+Math.imul(R,fe)|0))<<13)|0;u=((a=a+Math.imul(R,me)|0)+(n>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,i=Math.imul(B,ce),n=(n=Math.imul(B,ue))+Math.imul(z,ce)|0,a=Math.imul(z,ue),i=i+Math.imul(D,he)|0,n=(n=n+Math.imul(D,de)|0)+Math.imul(F,he)|0,a=a+Math.imul(F,de)|0;var Oe=(u+(i=i+Math.imul(O,fe)|0)|0)+((8191&(n=(n=n+Math.imul(O,me)|0)+Math.imul(A,fe)|0))<<13)|0;u=((a=a+Math.imul(A,me)|0)+(n>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,i=Math.imul(B,he),n=(n=Math.imul(B,de))+Math.imul(z,he)|0,a=Math.imul(z,de);var Ae=(u+(i=i+Math.imul(D,fe)|0)|0)+((8191&(n=(n=n+Math.imul(D,me)|0)+Math.imul(F,fe)|0))<<13)|0;u=((a=a+Math.imul(F,me)|0)+(n>>>13)|0)+(Ae>>>26)|0,Ae&=67108863;var Pe=(u+(i=Math.imul(B,fe))|0)+((8191&(n=(n=Math.imul(B,me))+Math.imul(z,fe)|0))<<13)|0;return u=((a=Math.imul(z,me))+(n>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,c[0]=ge,c[1]=_e,c[2]=ve,c[3]=ye,c[4]=be,c[5]=Ee,c[6]=we,c[7]=Se,c[8]=ke,c[9]=xe,c[10]=Me,c[11]=Ne,c[12]=je,c[13]=Te,c[14]=Re,c[15]=Ie,c[16]=Oe,c[17]=Ae,c[18]=Pe,0!==u&&(c[19]=u,r.length++),r};function f(e,t,r){return(new m).mulp(e,t,r)}function m(e,t){this.x=e,this.y=t}Math.imul||(p=d),a.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?p(this,e,t):r<63?d(this,e,t):r<1024?function(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var i=0,n=0,a=0;a>>26)|0)>>>26,o&=67108863}r.words[a]=s,i=o,o=n}return 0!==i?r.words[a]=i:r.length--,r.strip()}(this,e,t):f(this,e,t)},m.prototype.makeRBT=function(e){for(var t=new Array(e),r=a.prototype._countBits(e)-1,i=0;i>=1;return i},m.prototype.permute=function(e,t,r,i,n,a){for(var o=0;o>>=1)n++;return 1<>>=13,r[2*o+1]=8191&a,a>>>=13;for(o=2*t;o>=26,t+=n/67108864|0,t+=a>>>26,this.words[r]=67108863&a}return 0!==t&&(this.words[r]=t,this.length++),this},a.prototype.muln=function(e){return this.clone().imuln(e)},a.prototype.sqr=function(){return this.mul(this)},a.prototype.isqr=function(){return this.imul(this.clone())},a.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>n}return t}(e);if(0===t.length)return new a(1);for(var r=this,i=0;i=0);var t,r=e%26,n=(e-r)/26,a=67108863>>>26-r<<26-r;if(0!==r){var o=0;for(t=0;t>>26-r}o&&(this.words[t]=o,this.length++)}if(0!==n){for(t=this.length-1;t>=0;t--)this.words[t+n]=this.words[t];for(t=0;t=0),n=t?(t-t%26)/26:0;var a=e%26,o=Math.min((e-a)/26,this.length),s=67108863^67108863>>>a<o)for(this.length-=o,u=0;u=0&&(0!==l||u>=n);u--){var h=0|this.words[u];this.words[u]=l<<26-a|h>>>a,l=h&s}return c&&0!==l&&(c.words[c.length++]=l),0===this.length&&(this.words[0]=0,this.length=1),this.strip()},a.prototype.ishrn=function(e,t,r){return i(0===this.negative),this.iushrn(e,t,r)},a.prototype.shln=function(e){return this.clone().ishln(e)},a.prototype.ushln=function(e){return this.clone().iushln(e)},a.prototype.shrn=function(e){return this.clone().ishrn(e)},a.prototype.ushrn=function(e){return this.clone().iushrn(e)},a.prototype.testn=function(e){i("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,n=1<=0);var t=e%26,r=(e-t)/26;if(i(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var n=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},a.prototype.isubn=function(e){if(i("number"==typeof e),i(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(c/67108864|0),this.words[n+r]=67108863&a}for(;n>26,this.words[n+r]=67108863&a;if(0===s)return this.strip();for(i(-1===s),s=0,n=0;n>26,this.words[n]=67108863&a;return this.negative=1,this.strip()},a.prototype._wordDiv=function(e,t){var r=(this.length,e.length),i=this.clone(),n=e,o=0|n.words[n.length-1];0!==(r=26-this._countBits(o))&&(n=n.ushln(r),i.iushln(r),o=0|n.words[n.length-1]);var s,c=i.length-n.length;if("mod"!==t){(s=new a(null)).length=c+1,s.words=new Array(s.length);for(var u=0;u=0;h--){var d=67108864*(0|i.words[n.length+h])+(0|i.words[n.length+h-1]);for(d=Math.min(d/o|0,67108863),i._ishlnsubmul(n,d,h);0!==i.negative;)d--,i.negative=0,i._ishlnsubmul(n,1,h),i.isZero()||(i.negative^=1);s&&(s.words[h]=d)}return s&&s.strip(),i.strip(),"div"!==t&&0!==r&&i.iushrn(r),{div:s||null,mod:i}},a.prototype.divmod=function(e,t,r){return i(!e.isZero()),this.isZero()?{div:new a(0),mod:new a(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(n=s.div.neg()),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.iadd(e)),{div:n,mod:o}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(n=s.div.neg()),{div:n,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.isub(e)),{div:s.div,mod:o}):e.length>this.length||this.cmp(e)<0?{div:new a(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new a(this.modn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new a(this.modn(e.words[0]))}:this._wordDiv(e,t);var n,o,s},a.prototype.div=function(e){return this.divmod(e,"div",!1).div},a.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},a.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},a.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,i=e.ushrn(1),n=e.andln(1),a=r.cmp(i);return a<0||1===n&&0===a?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},a.prototype.modn=function(e){i(e<=67108863);for(var t=(1<<26)%e,r=0,n=this.length-1;n>=0;n--)r=(t*r+(0|this.words[n]))%e;return r},a.prototype.idivn=function(e){i(e<=67108863);for(var t=0,r=this.length-1;r>=0;r--){var n=(0|this.words[r])+67108864*t;this.words[r]=n/e|0,t=n%e}return this.strip()},a.prototype.divn=function(e){return this.clone().idivn(e)},a.prototype.egcd=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n=new a(1),o=new a(0),s=new a(0),c=new a(1),u=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++u;for(var l=r.clone(),h=t.clone();!t.isZero();){for(var d=0,p=1;0==(t.words[0]&p)&&d<26;++d,p<<=1);if(d>0)for(t.iushrn(d);d-- >0;)(n.isOdd()||o.isOdd())&&(n.iadd(l),o.isub(h)),n.iushrn(1),o.iushrn(1);for(var f=0,m=1;0==(r.words[0]&m)&&f<26;++f,m<<=1);if(f>0)for(r.iushrn(f);f-- >0;)(s.isOdd()||c.isOdd())&&(s.iadd(l),c.isub(h)),s.iushrn(1),c.iushrn(1);t.cmp(r)>=0?(t.isub(r),n.isub(s),o.isub(c)):(r.isub(t),s.isub(n),c.isub(o))}return{a:s,b:c,gcd:r.iushln(u)}},a.prototype._invmp=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n,o=new a(1),s=new a(0),c=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var u=0,l=1;0==(t.words[0]&l)&&u<26;++u,l<<=1);if(u>0)for(t.iushrn(u);u-- >0;)o.isOdd()&&o.iadd(c),o.iushrn(1);for(var h=0,d=1;0==(r.words[0]&d)&&h<26;++h,d<<=1);if(h>0)for(r.iushrn(h);h-- >0;)s.isOdd()&&s.iadd(c),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),o.isub(s)):(r.isub(t),s.isub(o))}return(n=0===t.cmpn(1)?o:s).cmpn(0)<0&&n.iadd(e),n},a.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var i=0;t.isEven()&&r.isEven();i++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var n=t.cmp(r);if(n<0){var a=t;t=r,r=a}else if(0===n||0===r.cmpn(1))break;t.isub(r)}return r.iushln(i)},a.prototype.invm=function(e){return this.egcd(e).a.umod(e)},a.prototype.isEven=function(){return 0==(1&this.words[0])},a.prototype.isOdd=function(){return 1==(1&this.words[0])},a.prototype.andln=function(e){return this.words[0]&e},a.prototype.bincn=function(e){i("number"==typeof e);var t=e%26,r=(e-t)/26,n=1<>>26,s&=67108863,this.words[o]=s}return 0!==a&&(this.words[o]=a,this.length++),this},a.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},a.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this.strip(),this.length>1)t=1;else{r&&(e=-e),i(e<=67108863,"Number is too big");var n=0|this.words[0];t=n===e?0:ne.length)return 1;if(this.length=0;r--){var i=0|this.words[r],n=0|e.words[r];if(i!==n){in&&(t=1);break}}return t},a.prototype.gtn=function(e){return 1===this.cmpn(e)},a.prototype.gt=function(e){return 1===this.cmp(e)},a.prototype.gten=function(e){return this.cmpn(e)>=0},a.prototype.gte=function(e){return this.cmp(e)>=0},a.prototype.ltn=function(e){return-1===this.cmpn(e)},a.prototype.lt=function(e){return-1===this.cmp(e)},a.prototype.lten=function(e){return this.cmpn(e)<=0},a.prototype.lte=function(e){return this.cmp(e)<=0},a.prototype.eqn=function(e){return 0===this.cmpn(e)},a.prototype.eq=function(e){return 0===this.cmp(e)},a.red=function(e){return new w(e)},a.prototype.toRed=function(e){return i(!this.red,"Already a number in reduction context"),i(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},a.prototype.fromRed=function(){return i(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},a.prototype._forceRed=function(e){return this.red=e,this},a.prototype.forceRed=function(e){return i(!this.red,"Already a number in reduction context"),this._forceRed(e)},a.prototype.redAdd=function(e){return i(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},a.prototype.redIAdd=function(e){return i(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},a.prototype.redSub=function(e){return i(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},a.prototype.redISub=function(e){return i(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},a.prototype.redShl=function(e){return i(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},a.prototype.redMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},a.prototype.redIMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},a.prototype.redSqr=function(){return i(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},a.prototype.redISqr=function(){return i(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},a.prototype.redSqrt=function(){return i(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},a.prototype.redInvm=function(){return i(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},a.prototype.redNeg=function(){return i(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},a.prototype.redPow=function(e){return i(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var g={k256:null,p224:null,p192:null,p25519:null};function _(e,t){this.name=e,this.p=new a(t,16),this.n=this.p.bitLength(),this.k=new a(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function v(){_.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function y(){_.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function b(){_.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function E(){_.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function w(e){if("string"==typeof e){var t=a._prime(e);this.m=t.p,this.prime=t}else i(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function S(e){w.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new a(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}_.prototype._tmp=function(){var e=new a(null);return e.words=new Array(Math.ceil(this.n/13)),e},_.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var i=t0?r.isub(this.p):r.strip(),r},_.prototype.split=function(e,t){e.iushrn(this.n,0,t)},_.prototype.imulK=function(e){return e.imul(this.k)},n(v,_),v.prototype.split=function(e,t){for(var r=Math.min(e.length,9),i=0;i>>22,n=a}n>>>=22,e.words[i-10]=n,0===n&&e.length>10?e.length-=10:e.length-=9},v.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=n,t=i}return 0!==t&&(e.words[e.length++]=t),e},a._prime=function(e){if(g[e])return g[e];var t;if("k256"===e)t=new v;else if("p224"===e)t=new y;else if("p192"===e)t=new b;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new E}return g[e]=t,t},w.prototype._verify1=function(e){i(0===e.negative,"red works only with positives"),i(e.red,"red works only with red numbers")},w.prototype._verify2=function(e,t){i(0==(e.negative|t.negative),"red works only with positives"),i(e.red&&e.red===t.red,"red works only with red numbers")},w.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):e.umod(this.m)._forceRed(this)},w.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},w.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},w.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},w.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},w.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},w.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},w.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},w.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},w.prototype.isqr=function(e){return this.imul(e,e.clone())},w.prototype.sqr=function(e){return this.mul(e,e)},w.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(i(t%2==1),3===t){var r=this.m.add(new a(1)).iushrn(2);return this.pow(e,r)}for(var n=this.m.subn(1),o=0;!n.isZero()&&0===n.andln(1);)o++,n.iushrn(1);i(!n.isZero());var s=new a(1).toRed(this),c=s.redNeg(),u=this.m.subn(1).iushrn(1),l=this.m.bitLength();for(l=new a(2*l*l).toRed(this);0!==this.pow(l,u).cmp(c);)l.redIAdd(c);for(var h=this.pow(l,n),d=this.pow(e,n.addn(1).iushrn(1)),p=this.pow(e,n),f=o;0!==p.cmp(s);){for(var m=p,g=0;0!==m.cmp(s);g++)m=m.redSqr();i(g=0;i--){for(var u=t.words[i],l=c-1;l>=0;l--){var h=u>>l&1;n!==r[0]&&(n=this.sqr(n)),0!==h||0!==o?(o<<=1,o|=h,(4===++s||0===i&&0===l)&&(n=this.mul(n,r[o]),s=0,o=0)):s=0}c=26}return n},w.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},w.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},a.mont=function(e){return new S(e)},n(S,w),S.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},S.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},S.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),a=n;return n.cmp(this.m)>=0?a=n.isub(this.m):n.cmpn(0)<0&&(a=n.iadd(this.m)),a._forceRed(this)},S.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new a(0)._forceRed(this);var r=e.mul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),o=n;return n.cmp(this.m)>=0?o=n.isub(this.m):n.cmpn(0)<0&&(o=n.iadd(this.m)),o._forceRed(this)},S.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(22)(e))},function(e,t){e.exports=function(e){return null!=e&&"object"==typeof e}},function(e,t,r){"use strict";var i=Object.prototype.hasOwnProperty,n=Object.prototype.toString,a=Object.defineProperty,o=Object.getOwnPropertyDescriptor,s=function(e){return"function"==typeof Array.isArray?Array.isArray(e):"[object Array]"===n.call(e)},c=function(e){if(!e||"[object Object]"!==n.call(e))return!1;var t,r=i.call(e,"constructor"),a=e.constructor&&e.constructor.prototype&&i.call(e.constructor.prototype,"isPrototypeOf");if(e.constructor&&!r&&!a)return!1;for(t in e);return void 0===t||i.call(e,t)},u=function(e,t){a&&"__proto__"===t.name?a(e,t.name,{enumerable:!0,configurable:!0,value:t.newValue,writable:!0}):e[t.name]=t.newValue},l=function(e,t){if("__proto__"===t){if(!i.call(e,t))return;if(o)return o(e,t).value}return e[t]};e.exports=function e(){var t,r,i,n,a,o,h=arguments[0],d=1,p=arguments.length,f=!1;for("boolean"==typeof h&&(f=h,h=arguments[1]||{},d=2),(null==h||"object"!=typeof h&&"function"!=typeof h)&&(h={});d= 0x80 (not a basic code point)","invalid-input":"Invalid input"},p=Math.floor,f=String.fromCharCode;function m(e){throw new RangeError(d[e])}function g(e,t){for(var r=e.length,i=[];r--;)i[r]=t(e[r]);return i}function _(e,t){var r=e.split("@"),i="";return r.length>1&&(i=r[0]+"@",e=r[1]),i+g((e=e.replace(h,".")).split("."),t).join(".")}function v(e){for(var t,r,i=[],n=0,a=e.length;n=55296&&t<=56319&&n65535&&(t+=f((e-=65536)>>>10&1023|55296),e=56320|1023&e),t+=f(e)})).join("")}function b(e,t){return e+22+75*(e<26)-((0!=t)<<5)}function E(e,t,r){var i=0;for(e=r?p(e/700):e>>1,e+=p(e/t);e>455;i+=36)e=p(e/35);return p(i+36*e/(e+38))}function w(e){var t,r,i,n,a,o,s,u,l,h,d,f=[],g=e.length,_=0,v=128,b=72;for((r=e.lastIndexOf("-"))<0&&(r=0),i=0;i=128&&m("not-basic"),f.push(e.charCodeAt(i));for(n=r>0?r+1:0;n=g&&m("invalid-input"),((u=(d=e.charCodeAt(n++))-48<10?d-22:d-65<26?d-65:d-97<26?d-97:36)>=36||u>p((c-_)/o))&&m("overflow"),_+=u*o,!(u<(l=s<=b?1:s>=b+26?26:s-b));s+=36)o>p(c/(h=36-l))&&m("overflow"),o*=h;b=E(_-a,t=f.length+1,0==a),p(_/t)>c-v&&m("overflow"),v+=p(_/t),_%=t,f.splice(_++,0,v)}return y(f)}function S(e){var t,r,i,n,a,o,s,u,l,h,d,g,_,y,w,S=[];for(g=(e=v(e)).length,t=128,r=0,a=72,o=0;o=t&&dp((c-r)/(_=i+1))&&m("overflow"),r+=(s-t)*_,t=s,o=0;oc&&m("overflow"),d==t){for(u=r,l=36;!(u<(h=l<=a?1:l>=a+26?26:l-a));l+=36)w=u-h,y=36-h,S.push(f(b(h+w%y,0))),u=p(w/y);S.push(f(b(u,0))),a=E(r,_,i==n),r=0,++i}++r,++t}return S.join("")}s={version:"1.4.1",ucs2:{decode:v,encode:y},decode:w,encode:S,toASCII:function(e){return _(e,(function(e){return l.test(e)?"xn--"+S(e):e}))},toUnicode:function(e){return _(e,(function(e){return u.test(e)?w(e.slice(4).toLowerCase()):e}))}},void 0===(n=function(){return s}.call(t,r,t,e))||(e.exports=n)}()}).call(this,r(22)(e),r(8))},function(e,t,r){"use strict";(function(e,i){var n=r(401),a=r(10),o=r(1).Buffer,s=void 0===e?i.nextTick:e;t.paramsHaveRequestBody=function(e){return e.body||e.requestBodyStream||e.json&&"boolean"!=typeof e.json||e.multipart},t.safeStringify=function(e,t){var r;try{r=JSON.stringify(e,t)}catch(i){r=n(e,t)}return r},t.md5=function(e){return a.createHash("md5").update(e).digest("hex")},t.isReadStream=function(e){return e.readable&&e.path&&e.mode},t.toBase64=function(e){return o.from(e||"","utf8").toString("base64")},t.copy=function(e){var t={};return Object.keys(e).forEach((function(r){t[r]=e[r]})),t},t.version=function(){var e=i.version.replace("v","").split(".");return{major:parseInt(e[0],10),minor:parseInt(e[1],10),patch:parseInt(e[2],10)}},t.defer=s}).call(this,r(32).setImmediate,r(3))},function(e,t,r){var i=r(14),n=r(66),a=r(30),o=r(17),s=r(67),c=r(72),u=r(29);e.exports={Key:i,parseKey:i.parse,Fingerprint:n,parseFingerprint:n.parse,Signature:a,parseSignature:a.parse,PrivateKey:o,parsePrivateKey:o.parse,generatePrivateKey:o.generate,Certificate:s,parseCertificate:s.parse,createSelfSignedCertificate:s.createSelfSigned,createCertificate:s.create,Identity:c,identityFromDN:c.parseDN,identityForHost:c.forHost,identityForUser:c.forUser,identityForEmail:c.forEmail,identityFromArray:c.fromArray,FingerprintFormatError:u.FingerprintFormatError,InvalidAlgorithmError:u.InvalidAlgorithmError,KeyParseError:u.KeyParseError,SignatureParseError:u.SignatureParseError,KeyEncryptedError:u.KeyEncryptedError,CertificateParseError:u.CertificateParseError}},function(e,t,r){e.exports={DiffieHellman:f,generateECDSA:function(e){var t=[];if(h){var r={nistp256:"prime256v1",nistp384:"secp384r1",nistp521:"secp521r1"}[e],i=n.createECDH(r);return i.generateKeys(),t.push({name:"curve",data:a.from(e)}),t.push({name:"Q",data:i.getPublicKey()}),t.push({name:"d",data:i.getPrivateKey()}),new l({type:"ecdsa",curve:e,parts:t})}var o=new m(e),s=o.getN(),c=Math.ceil((s.bitLength()+64)/8),u=new p(n.randomBytes(c)),d=s.subtract(p.ONE),f=u.mod(d).add(p.ONE),g=o.getG().multiply(f);return f=a.from(f.toByteArray()),g=a.from(o.getCurve().encodePointHex(g),"hex"),t.push({name:"curve",data:a.from(e)}),t.push({name:"Q",data:g}),t.push({name:"d",data:f}),new l({type:"ecdsa",curve:e,parts:t})},generateED25519:function(){var e=c.sign.keyPair(),t=a.from(e.secretKey),r=a.from(e.publicKey);i.strictEqual(t.length,64),i.strictEqual(r.length,32);var n=[];return n.push({name:"A",data:r}),n.push({name:"k",data:t.slice(0,32)}),new l({type:"ed25519",parts:n})}};var i=r(6),n=r(10),a=r(9).Buffer,o=r(16),s=r(13),c=r(68),u=r(14),l=r(17),h=void 0!==n.createECDH,d=(r(427),r(88)),p=r(69).BigInteger;function f(e){if(s.assertCompatible(e,u,[1,4],"key"),this._isPriv=l.isPrivateKey(e,[1,3]),this._algo=e.type,this._curve=e.curve,this._key=e,"dsa"===e.type){if(!h)throw new Error("Due to bugs in the node 0.10 crypto API, node 0.12.x or later is required to use DH");this._dh=n.createDiffieHellman(e.part.p.data,void 0,e.part.g.data,void 0),this._p=e.part.p,this._g=e.part.g,this._isPriv&&this._dh.setPrivateKey(e.part.x.data),this._dh.setPublicKey(e.part.y.data)}else if("ecdsa"===e.type){if(!h)return this._ecParams=new m(this._curve),void(this._isPriv&&(this._priv=new _(this._ecParams,e.part.d.data)));var t={nistp256:"prime256v1",nistp384:"secp384r1",nistp521:"secp521r1"}[e.curve];if(this._dh=n.createECDH(t),"object"!=typeof this._dh||"function"!=typeof this._dh.setPrivateKey)return h=!1,void f.call(this,e);this._isPriv&&this._dh.setPrivateKey(e.part.d.data),this._dh.setPublicKey(e.part.Q.data)}else{if("curve25519"!==e.type)throw new Error("DH not supported for "+e.type+" keys");this._isPriv&&(s.assertCompatible(e,l,[1,5],"key"),this._priv=e.part.k.data)}}function m(e){var t=o.curves[e];i.object(t);var r=new p(t.p),n=new p(t.a),a=new p(t.b),s=new p(t.n),c=p.ONE,u=new d.ECCurveFp(r,n,a),l=u.decodePointHex(t.G.toString("hex"));this.curve=u,this.g=l,this.n=s,this.h=c}function g(e,t){this._params=e,0===t[0]&&(t=t.slice(1)),this._pub=e.getCurve().decodePointHex(t.toString("hex"))}function _(e,t){this._params=e,this._priv=new p(s.mpNormalize(t))}f.prototype.getPublicKey=function(){return this._isPriv?this._key.toPublic():this._key},f.prototype.getPrivateKey=function(){return this._isPriv?this._key:void 0},f.prototype.getKey=f.prototype.getPrivateKey,f.prototype._keyCheck=function(e,t){if(i.object(e,"key"),t||s.assertCompatible(e,l,[1,3],"key"),s.assertCompatible(e,u,[1,4],"key"),e.type!==this._algo)throw new Error("A "+e.type+" key cannot be used in "+this._algo+" Diffie-Hellman");if(e.curve!==this._curve)throw new Error("A key from the "+e.curve+" curve cannot be used with a "+this._curve+" Diffie-Hellman");"dsa"===e.type&&(i.deepEqual(e.part.p,this._p,"DSA key prime does not match"),i.deepEqual(e.part.g,this._g,"DSA key generator does not match"))},f.prototype.setKey=function(e){if(this._keyCheck(e),"dsa"===e.type)this._dh.setPrivateKey(e.part.x.data),this._dh.setPublicKey(e.part.y.data);else if("ecdsa"===e.type)h?(this._dh.setPrivateKey(e.part.d.data),this._dh.setPublicKey(e.part.Q.data)):this._priv=new _(this._ecParams,e.part.d.data);else if("curve25519"===e.type){var t=e.part.k;e.part.k||(t=e.part.r),this._priv=t.data,0===this._priv[0]&&(this._priv=this._priv.slice(1)),this._priv=this._priv.slice(0,32)}this._key=e,this._isPriv=!0},f.prototype.setPrivateKey=f.prototype.setKey,f.prototype.computeSecret=function(e){if(this._keyCheck(e,!0),!this._isPriv)throw new Error("DH exchange has not been initialized with a private key yet");var t;if("dsa"===this._algo)return this._dh.computeSecret(e.part.y.data);if("ecdsa"===this._algo)return h?this._dh.computeSecret(e.part.Q.data):(t=new g(this._ecParams,e.part.Q.data),this._priv.deriveSharedSecret(t));if("curve25519"===this._algo){for(t=e.part.A.data;0===t[0]&&t.length>32;)t=t.slice(1);var r=this._priv;i.strictEqual(t.length,32),i.strictEqual(r.length,32);var n=c.box.before(new Uint8Array(t),new Uint8Array(r));return a.from(n)}throw new Error("Invalid algorithm: "+this._algo)},f.prototype.generateKey=function(){var e,t,r=[];if("dsa"===this._algo)return this._dh.generateKeys(),r.push({name:"p",data:this._p.data}),r.push({name:"q",data:this._key.part.q.data}),r.push({name:"g",data:this._g.data}),r.push({name:"y",data:this._dh.getPublicKey()}),r.push({name:"x",data:this._dh.getPrivateKey()}),this._key=new l({type:"dsa",parts:r}),this._isPriv=!0,this._key;if("ecdsa"===this._algo){if(h)return this._dh.generateKeys(),r.push({name:"curve",data:a.from(this._curve)}),r.push({name:"Q",data:this._dh.getPublicKey()}),r.push({name:"d",data:this._dh.getPrivateKey()}),this._key=new l({type:"ecdsa",curve:this._curve,parts:r}),this._isPriv=!0,this._key;var o=this._ecParams.getN(),s=new p(n.randomBytes(o.bitLength())),u=o.subtract(p.ONE);return e=s.mod(u).add(p.ONE),t=this._ecParams.getG().multiply(e),e=a.from(e.toByteArray()),t=a.from(this._ecParams.getCurve().encodePointHex(t),"hex"),this._priv=new _(this._ecParams,e),r.push({name:"curve",data:a.from(this._curve)}),r.push({name:"Q",data:t}),r.push({name:"d",data:e}),this._key=new l({type:"ecdsa",curve:this._curve,parts:r}),this._isPriv=!0,this._key}if("curve25519"===this._algo){var d=c.box.keyPair();return e=a.from(d.secretKey),t=a.from(d.publicKey),e=a.concat([e,t]),i.strictEqual(e.length,64),i.strictEqual(t.length,32),r.push({name:"A",data:t}),r.push({name:"k",data:e}),this._key=new l({type:"curve25519",parts:r}),this._isPriv=!0,this._key}throw new Error("Invalid algorithm: "+this._algo)},f.prototype.generateKeys=f.prototype.generateKey,m.prototype.getCurve=function(){return this.curve},m.prototype.getG=function(){return this.g},m.prototype.getN=function(){return this.n},m.prototype.getH=function(){return this.h},_.prototype.deriveSharedSecret=function(e){i.ok(e instanceof g);var t=e._pub.multiply(this._priv);return a.from(t.getX().toBigInteger().toByteArray())}},function(e,t){e.exports={newInvalidAsn1Error:function(e){var t=new Error;return t.name="InvalidAsn1Error",t.message=e||"",t}}},function(e,t){e.exports={EOC:0,Boolean:1,Integer:2,BitString:3,OctetString:4,Null:5,OID:6,ObjectDescriptor:7,External:8,Real:9,Enumeration:10,PDV:11,Utf8String:12,RelativeOID:13,Sequence:16,Set:17,NumericString:18,PrintableString:19,T61String:20,VideotexString:21,IA5String:22,UTCTime:23,GeneralizedTime:24,GraphicString:25,VisibleString:26,GeneralString:28,UniversalString:29,CharacterString:30,BMPString:31,Constructor:32,Context:128}},function(e,t,r){e.exports={read:function(e,t){return l.read(e,t,"pkcs1")},readPkcs1:function(e,t,r){switch(e){case"RSA":if("public"===t)return function(e){var t=d(e,"modulus"),r=d(e,"exponent");return new c({type:"rsa",parts:[{name:"e",data:r},{name:"n",data:t}]})}(r);if("private"===t)return function(e){var t=d(e,"version");i.strictEqual(t[0],0);var r=d(e,"modulus"),n=d(e,"public exponent"),a=d(e,"private exponent"),o=d(e,"prime1"),s=d(e,"prime2"),c=d(e,"exponent1"),l=d(e,"exponent2"),h=d(e,"iqmp");return new u({type:"rsa",parts:[{name:"n",data:r},{name:"e",data:n},{name:"d",data:a},{name:"iqmp",data:h},{name:"p",data:o},{name:"q",data:s},{name:"dmodp",data:c},{name:"dmodq",data:l}]})}(r);throw new Error("Unknown key type: "+t);case"DSA":if("public"===t)return function(e){var t=d(e,"y"),r=d(e,"p"),i=d(e,"q"),n=d(e,"g");return new c({type:"dsa",parts:[{name:"y",data:t},{name:"p",data:r},{name:"q",data:i},{name:"g",data:n}]})}(r);if("private"===t)return function(e){var t=d(e,"version");i.strictEqual(t.readUInt8(0),0);var r=d(e,"p"),n=d(e,"q"),a=d(e,"g"),o=d(e,"y"),s=d(e,"x");return new u({type:"dsa",parts:[{name:"p",data:r},{name:"q",data:n},{name:"g",data:a},{name:"y",data:o},{name:"x",data:s}]})}(r);throw new Error("Unknown key type: "+t);case"EC":case"ECDSA":if("private"===t)return function(e){var t=d(e,"version");i.strictEqual(t.readUInt8(0),1);var r=e.readString(n.Ber.OctetString,!0);e.readSequence(160);var o=h(e);i.string(o,"a known elliptic curve"),e.readSequence(161);var c=e.readString(n.Ber.BitString,!0);c=s.ecNormalize(c);var l={type:"ecdsa",parts:[{name:"curve",data:a.from(o)},{name:"Q",data:c},{name:"d",data:r}]};return new u(l)}(r);if("public"===t)return function(e){e.readSequence();var t=e.readOID();i.strictEqual(t,"1.2.840.10045.2.1","must be ecPublicKey");for(var r,u=e.readOID(),l=Object.keys(o.curves),h=0;h>>31}var h=(i<<5|i>>>27)+s+c[u];h+=u<20?1518500249+(n&a|~n&o):u<40?1859775393+(n^a^o):u<60?(n&a|n&o|a&o)-1894007588:(n^a^o)-899497514,s=o,o=a,a=n<<30|n>>>2,n=i,i=h}r[0]=r[0]+i|0,r[1]=r[1]+n|0,r[2]=r[2]+a|0,r[3]=r[3]+o|0,r[4]=r[4]+s|0},_doFinalize:function(){var e=this._data,t=e.words,r=8*this._nDataBytes,i=8*e.sigBytes;return t[i>>>5]|=128<<24-i%32,t[14+(i+64>>>9<<4)]=Math.floor(r/4294967296),t[15+(i+64>>>9<<4)]=r,e.sigBytes=4*t.length,this._process(),this._hash},clone:function(){var e=o.clone.call(this);return e._hash=this._hash.clone(),e}}),i.SHA1=o._createHelper(u),i.HmacSHA1=o._createHmacHelper(u),l.SHA1)},function(e,t,r){var i,n,a,o;e.exports=(i=r(5),a=(n=i).lib.Base,o=n.enc.Utf8,void(n.algo.HMAC=a.extend({init:function(e,t){e=this._hasher=new e.init,"string"==typeof t&&(t=o.parse(t));var r=e.blockSize,i=4*r;t.sigBytes>i&&(t=e.finalize(t)),t.clamp();for(var n=this._oKey=t.clone(),a=this._iKey=t.clone(),s=n.words,c=a.words,u=0;u=this._blockSize;){for(var a=this._blockOffset;a0;++o)this._length[o]+=s,(s=this._length[o]/4294967296|0)>0&&(this._length[o]-=4294967296*s);return this},a.prototype._update=function(){throw new Error("_update is not implemented")},a.prototype.digest=function(e){if(this._finalized)throw new Error("Digest already called");this._finalized=!0;var t=this._digest();void 0!==e&&(t=t.toString(e)),this._block.fill(0),this._blockOffset=0;for(var r=0;r<4;++r)this._length[r]=0;return t},a.prototype._digest=function(){throw new Error("_digest is not implemented")},e.exports=a},function(e,t,r){"use strict";(function(t,i){var n;e.exports=x,x.ReadableState=k;r(23).EventEmitter;var a=function(e,t){return e.listeners(t).length},o=r(156),s=r(2).Buffer,c=t.Uint8Array||function(){};var u,l=r(276);u=l&&l.debuglog?l.debuglog("stream"):function(){};var h,d,p,f=r(277),m=r(157),g=r(158).getHighWaterMark,_=r(45).codes,v=_.ERR_INVALID_ARG_TYPE,y=_.ERR_STREAM_PUSH_AFTER_EOF,b=_.ERR_METHOD_NOT_IMPLEMENTED,E=_.ERR_STREAM_UNSHIFT_AFTER_END_EVENT;r(46)(x,o);var w=m.errorOrDestroy,S=["error","close","destroy","pause","resume"];function k(e,t,i){n=n||r(47),e=e||{},"boolean"!=typeof i&&(i=t instanceof n),this.objectMode=!!e.objectMode,i&&(this.objectMode=this.objectMode||!!e.readableObjectMode),this.highWaterMark=g(this,e,"readableHighWaterMark",i),this.buffer=new f,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.paused=!0,this.emitClose=!1!==e.emitClose,this.autoDestroy=!!e.autoDestroy,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(h||(h=r(26).StringDecoder),this.decoder=new h(e.encoding),this.encoding=e.encoding)}function x(e){if(n=n||r(47),!(this instanceof x))return new x(e);var t=this instanceof n;this._readableState=new k(e,this,t),this.readable=!0,e&&("function"==typeof e.read&&(this._read=e.read),"function"==typeof e.destroy&&(this._destroy=e.destroy)),o.call(this)}function M(e,t,r,i,n){u("readableAddChunk",t);var a,o=e._readableState;if(null===t)o.reading=!1,function(e,t){if(u("onEofChunk"),t.ended)return;if(t.decoder){var r=t.decoder.end();r&&r.length&&(t.buffer.push(r),t.length+=t.objectMode?1:r.length)}t.ended=!0,t.sync?T(e):(t.needReadable=!1,t.emittedReadable||(t.emittedReadable=!0,R(e)))}(e,o);else if(n||(a=function(e,t){var r;i=t,s.isBuffer(i)||i instanceof c||"string"==typeof t||void 0===t||e.objectMode||(r=new v("chunk",["string","Buffer","Uint8Array"],t));var i;return r}(o,t)),a)w(e,a);else if(o.objectMode||t&&t.length>0)if("string"==typeof t||o.objectMode||Object.getPrototypeOf(t)===s.prototype||(t=function(e){return s.from(e)}(t)),i)o.endEmitted?w(e,new E):N(e,o,t,!0);else if(o.ended)w(e,new y);else{if(o.destroyed)return!1;o.reading=!1,o.decoder&&!r?(t=o.decoder.write(t),o.objectMode||0!==t.length?N(e,o,t,!1):I(e,o)):N(e,o,t,!1)}else i||(o.reading=!1,I(e,o));return!o.ended&&(o.lengtht.highWaterMark&&(t.highWaterMark=function(e){return e>=1073741824?e=1073741824:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function T(e){var t=e._readableState;u("emitReadable",t.needReadable,t.emittedReadable),t.needReadable=!1,t.emittedReadable||(u("emitReadable",t.flowing),t.emittedReadable=!0,i.nextTick(R,e))}function R(e){var t=e._readableState;u("emitReadable_",t.destroyed,t.length,t.ended),t.destroyed||!t.length&&!t.ended||(e.emit("readable"),t.emittedReadable=!1),t.needReadable=!t.flowing&&!t.ended&&t.length<=t.highWaterMark,F(e)}function I(e,t){t.readingMore||(t.readingMore=!0,i.nextTick(O,e,t))}function O(e,t){for(;!t.reading&&!t.ended&&(t.length0,t.resumeScheduled&&!t.paused?t.flowing=!0:e.listenerCount("data")>0&&e.resume()}function P(e){u("readable nexttick read 0"),e.read(0)}function D(e,t){u("resume",t.reading),t.reading||e.read(0),t.resumeScheduled=!1,e.emit("resume"),F(e),t.flowing&&!t.reading&&e.read(0)}function F(e){var t=e._readableState;for(u("flow",t.flowing);t.flowing&&null!==e.read(););}function C(e,t){return 0===t.length?null:(t.objectMode?r=t.buffer.shift():!e||e>=t.length?(r=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.first():t.buffer.concat(t.length),t.buffer.clear()):r=t.buffer.consume(e,t.decoder),r);var r}function B(e){var t=e._readableState;u("endReadable",t.endEmitted),t.endEmitted||(t.ended=!0,i.nextTick(z,t,e))}function z(e,t){if(u("endReadableNT",e.endEmitted,e.length),!e.endEmitted&&0===e.length&&(e.endEmitted=!0,t.readable=!1,t.emit("end"),e.autoDestroy)){var r=t._writableState;(!r||r.autoDestroy&&r.finished)&&t.destroy()}}function L(e,t){for(var r=0,i=e.length;r=t.highWaterMark:t.length>0)||t.ended))return u("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?B(this):T(this),null;if(0===(e=j(e,t))&&t.ended)return 0===t.length&&B(this),null;var i,n=t.needReadable;return u("need readable",n),(0===t.length||t.length-e0?C(e,t):null)?(t.needReadable=t.length<=t.highWaterMark,e=0):(t.length-=e,t.awaitDrain=0),0===t.length&&(t.ended||(t.needReadable=!0),r!==e&&t.ended&&B(this)),null!==i&&this.emit("data",i),i},x.prototype._read=function(e){w(this,new b("_read()"))},x.prototype.pipe=function(e,t){var r=this,n=this._readableState;switch(n.pipesCount){case 0:n.pipes=e;break;case 1:n.pipes=[n.pipes,e];break;default:n.pipes.push(e)}n.pipesCount+=1,u("pipe count=%d opts=%j",n.pipesCount,t);var o=(!t||!1!==t.end)&&e!==i.stdout&&e!==i.stderr?c:g;function s(t,i){u("onunpipe"),t===r&&i&&!1===i.hasUnpiped&&(i.hasUnpiped=!0,u("cleanup"),e.removeListener("close",f),e.removeListener("finish",m),e.removeListener("drain",l),e.removeListener("error",p),e.removeListener("unpipe",s),r.removeListener("end",c),r.removeListener("end",g),r.removeListener("data",d),h=!0,!n.awaitDrain||e._writableState&&!e._writableState.needDrain||l())}function c(){u("onend"),e.end()}n.endEmitted?i.nextTick(o):r.once("end",o),e.on("unpipe",s);var l=function(e){return function(){var t=e._readableState;u("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&a(e,"data")&&(t.flowing=!0,F(e))}}(r);e.on("drain",l);var h=!1;function d(t){u("ondata");var i=e.write(t);u("dest.write",i),!1===i&&((1===n.pipesCount&&n.pipes===e||n.pipesCount>1&&-1!==L(n.pipes,e))&&!h&&(u("false write response, pause",n.awaitDrain),n.awaitDrain++),r.pause())}function p(t){u("onerror",t),g(),e.removeListener("error",p),0===a(e,"error")&&w(e,t)}function f(){e.removeListener("finish",m),g()}function m(){u("onfinish"),e.removeListener("close",f),g()}function g(){u("unpipe"),r.unpipe(e)}return r.on("data",d),function(e,t,r){if("function"==typeof e.prependListener)return e.prependListener(t,r);e._events&&e._events[t]?Array.isArray(e._events[t])?e._events[t].unshift(r):e._events[t]=[r,e._events[t]]:e.on(t,r)}(e,"error",p),e.once("close",f),e.once("finish",m),e.emit("pipe",r),n.flowing||(u("pipe resume"),r.resume()),e},x.prototype.unpipe=function(e){var t=this._readableState,r={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes||(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,r)),this;if(!e){var i=t.pipes,n=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var a=0;a0,!1!==n.flowing&&this.resume()):"readable"===e&&(n.endEmitted||n.readableListening||(n.readableListening=n.needReadable=!0,n.flowing=!1,n.emittedReadable=!1,u("on readable",n.length,n.reading),n.length?T(this):n.reading||i.nextTick(P,this))),r},x.prototype.addListener=x.prototype.on,x.prototype.removeListener=function(e,t){var r=o.prototype.removeListener.call(this,e,t);return"readable"===e&&i.nextTick(A,this),r},x.prototype.removeAllListeners=function(e){var t=o.prototype.removeAllListeners.apply(this,arguments);return"readable"!==e&&void 0!==e||i.nextTick(A,this),t},x.prototype.resume=function(){var e=this._readableState;return e.flowing||(u("resume"),e.flowing=!e.readableListening,function(e,t){t.resumeScheduled||(t.resumeScheduled=!0,i.nextTick(D,e,t))}(this,e)),e.paused=!1,this},x.prototype.pause=function(){return u("call pause flowing=%j",this._readableState.flowing),!1!==this._readableState.flowing&&(u("pause"),this._readableState.flowing=!1,this.emit("pause")),this._readableState.paused=!0,this},x.prototype.wrap=function(e){var t=this,r=this._readableState,i=!1;for(var n in e.on("end",(function(){if(u("wrapped end"),r.decoder&&!r.ended){var e=r.decoder.end();e&&e.length&&t.push(e)}t.push(null)})),e.on("data",(function(n){(u("wrapped data"),r.decoder&&(n=r.decoder.write(n)),r.objectMode&&null==n)||(r.objectMode||n&&n.length)&&(t.push(n)||(i=!0,e.pause()))})),e)void 0===this[n]&&"function"==typeof e[n]&&(this[n]=function(t){return function(){return e[t].apply(e,arguments)}}(n));for(var a=0;a-1))throw new E(e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(x.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}}),Object.defineProperty(x.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),x.prototype._write=function(e,t,r){r(new m("_write()"))},x.prototype._writev=null,x.prototype.end=function(e,t,r){var n=this._writableState;return"function"==typeof e?(r=e,e=null,t=null):"function"==typeof t&&(r=t,t=null),null!=e&&this.write(e,t),n.corked&&(n.corked=1,this.uncork()),n.ending||function(e,t,r){t.ending=!0,I(e,t),r&&(t.finished?i.nextTick(r):e.once("finish",r));t.ended=!0,e.writable=!1}(this,n,r),this},Object.defineProperty(x.prototype,"writableLength",{enumerable:!1,get:function(){return this._writableState.length}}),Object.defineProperty(x.prototype,"destroyed",{enumerable:!1,get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),x.prototype.destroy=h.destroy,x.prototype._undestroy=h.undestroy,x.prototype._destroy=function(e,t){t(e)}}).call(this,r(8),r(3))},function(e,t,r){"use strict";e.exports=l;var i=r(45).codes,n=i.ERR_METHOD_NOT_IMPLEMENTED,a=i.ERR_MULTIPLE_CALLBACK,o=i.ERR_TRANSFORM_ALREADY_TRANSFORMING,s=i.ERR_TRANSFORM_WITH_LENGTH_0,c=r(47);function u(e,t){var r=this._transformState;r.transforming=!1;var i=r.writecb;if(null===i)return this.emit("error",new a);r.writechunk=null,r.writecb=null,null!=t&&this.push(t),i(e);var n=this._readableState;n.reading=!1,(n.needReadable||n.length>>2|e<<30)^(e>>>13|e<<19)^(e>>>22|e<<10)}function d(e){return(e>>>6|e<<26)^(e>>>11|e<<21)^(e>>>25|e<<7)}function p(e){return(e>>>7|e<<25)^(e>>>18|e<<14)^e>>>3}i(c,n),c.prototype.init=function(){return this._a=1779033703,this._b=3144134277,this._c=1013904242,this._d=2773480762,this._e=1359893119,this._f=2600822924,this._g=528734635,this._h=1541459225,this},c.prototype._update=function(e){for(var t,r=this._w,i=0|this._a,n=0|this._b,a=0|this._c,s=0|this._d,c=0|this._e,f=0|this._f,m=0|this._g,g=0|this._h,_=0;_<16;++_)r[_]=e.readInt32BE(4*_);for(;_<64;++_)r[_]=0|(((t=r[_-2])>>>17|t<<15)^(t>>>19|t<<13)^t>>>10)+r[_-7]+p(r[_-15])+r[_-16];for(var v=0;v<64;++v){var y=g+d(c)+u(c,f,m)+o[v]+r[v]|0,b=h(i)+l(i,n,a)|0;g=m,m=f,f=c,c=s+y|0,s=a,a=n,n=i,i=y+b|0}this._a=i+this._a|0,this._b=n+this._b|0,this._c=a+this._c|0,this._d=s+this._d|0,this._e=c+this._e|0,this._f=f+this._f|0,this._g=m+this._g|0,this._h=g+this._h|0},c.prototype._hash=function(){var e=a.allocUnsafe(32);return e.writeInt32BE(this._a,0),e.writeInt32BE(this._b,4),e.writeInt32BE(this._c,8),e.writeInt32BE(this._d,12),e.writeInt32BE(this._e,16),e.writeInt32BE(this._f,20),e.writeInt32BE(this._g,24),e.writeInt32BE(this._h,28),e},e.exports=c},function(e,t,r){var i=r(0),n=r(48),a=r(1).Buffer,o=[1116352408,3609767458,1899447441,602891725,3049323471,3964484399,3921009573,2173295548,961987163,4081628472,1508970993,3053834265,2453635748,2937671579,2870763221,3664609560,3624381080,2734883394,310598401,1164996542,607225278,1323610764,1426881987,3590304994,1925078388,4068182383,2162078206,991336113,2614888103,633803317,3248222580,3479774868,3835390401,2666613458,4022224774,944711139,264347078,2341262773,604807628,2007800933,770255983,1495990901,1249150122,1856431235,1555081692,3175218132,1996064986,2198950837,2554220882,3999719339,2821834349,766784016,2952996808,2566594879,3210313671,3203337956,3336571891,1034457026,3584528711,2466948901,113926993,3758326383,338241895,168717936,666307205,1188179964,773529912,1546045734,1294757372,1522805485,1396182291,2643833823,1695183700,2343527390,1986661051,1014477480,2177026350,1206759142,2456956037,344077627,2730485921,1290863460,2820302411,3158454273,3259730800,3505952657,3345764771,106217008,3516065817,3606008344,3600352804,1432725776,4094571909,1467031594,275423344,851169720,430227734,3100823752,506948616,1363258195,659060556,3750685593,883997877,3785050280,958139571,3318307427,1322822218,3812723403,1537002063,2003034995,1747873779,3602036899,1955562222,1575990012,2024104815,1125592928,2227730452,2716904306,2361852424,442776044,2428436474,593698344,2756734187,3733110249,3204031479,2999351573,3329325298,3815920427,3391569614,3928383900,3515267271,566280711,3940187606,3454069534,4118630271,4000239992,116418474,1914138554,174292421,2731055270,289380356,3203993006,460393269,320620315,685471733,587496836,852142971,1086792851,1017036298,365543100,1126000580,2618297676,1288033470,3409855158,1501505948,4234509866,1607167915,987167468,1816402316,1246189591],s=new Array(160);function c(){this.init(),this._w=s,n.call(this,128,112)}function u(e,t,r){return r^e&(t^r)}function l(e,t,r){return e&t|r&(e|t)}function h(e,t){return(e>>>28|t<<4)^(t>>>2|e<<30)^(t>>>7|e<<25)}function d(e,t){return(e>>>14|t<<18)^(e>>>18|t<<14)^(t>>>9|e<<23)}function p(e,t){return(e>>>1|t<<31)^(e>>>8|t<<24)^e>>>7}function f(e,t){return(e>>>1|t<<31)^(e>>>8|t<<24)^(e>>>7|t<<25)}function m(e,t){return(e>>>19|t<<13)^(t>>>29|e<<3)^e>>>6}function g(e,t){return(e>>>19|t<<13)^(t>>>29|e<<3)^(e>>>6|t<<26)}function _(e,t){return e>>>0>>0?1:0}i(c,n),c.prototype.init=function(){return this._ah=1779033703,this._bh=3144134277,this._ch=1013904242,this._dh=2773480762,this._eh=1359893119,this._fh=2600822924,this._gh=528734635,this._hh=1541459225,this._al=4089235720,this._bl=2227873595,this._cl=4271175723,this._dl=1595750129,this._el=2917565137,this._fl=725511199,this._gl=4215389547,this._hl=327033209,this},c.prototype._update=function(e){for(var t=this._w,r=0|this._ah,i=0|this._bh,n=0|this._ch,a=0|this._dh,s=0|this._eh,c=0|this._fh,v=0|this._gh,y=0|this._hh,b=0|this._al,E=0|this._bl,w=0|this._cl,S=0|this._dl,k=0|this._el,x=0|this._fl,M=0|this._gl,N=0|this._hl,j=0;j<32;j+=2)t[j]=e.readInt32BE(4*j),t[j+1]=e.readInt32BE(4*j+4);for(;j<160;j+=2){var T=t[j-30],R=t[j-30+1],I=p(T,R),O=f(R,T),A=m(T=t[j-4],R=t[j-4+1]),P=g(R,T),D=t[j-14],F=t[j-14+1],C=t[j-32],B=t[j-32+1],z=O+F|0,L=I+D+_(z,O)|0;L=(L=L+A+_(z=z+P|0,P)|0)+C+_(z=z+B|0,B)|0,t[j]=L,t[j+1]=z}for(var U=0;U<160;U+=2){L=t[U],z=t[U+1];var H=l(r,i,n),q=l(b,E,w),K=h(r,b),Z=h(b,r),W=d(s,k),X=d(k,s),Q=o[U],J=o[U+1],V=u(s,c,v),G=u(k,x,M),Y=N+X|0,$=y+W+_(Y,N)|0;$=($=($=$+V+_(Y=Y+G|0,G)|0)+Q+_(Y=Y+J|0,J)|0)+L+_(Y=Y+z|0,z)|0;var ee=Z+q|0,te=K+H+_(ee,Z)|0;y=v,N=M,v=c,M=x,c=s,x=k,s=a+$+_(k=S+Y|0,S)|0,a=n,S=w,n=i,w=E,i=r,E=b,r=$+te+_(b=Y+ee|0,Y)|0}this._al=this._al+b|0,this._bl=this._bl+E|0,this._cl=this._cl+w|0,this._dl=this._dl+S|0,this._el=this._el+k|0,this._fl=this._fl+x|0,this._gl=this._gl+M|0,this._hl=this._hl+N|0,this._ah=this._ah+r+_(this._al,b)|0,this._bh=this._bh+i+_(this._bl,E)|0,this._ch=this._ch+n+_(this._cl,w)|0,this._dh=this._dh+a+_(this._dl,S)|0,this._eh=this._eh+s+_(this._el,k)|0,this._fh=this._fh+c+_(this._fl,x)|0,this._gh=this._gh+v+_(this._gl,M)|0,this._hh=this._hh+y+_(this._hl,N)|0},c.prototype._hash=function(){var e=a.allocUnsafe(64);function t(t,r,i){e.writeInt32BE(t,i),e.writeInt32BE(r,i+4)}return t(this._ah,this._al,0),t(this._bh,this._bl,8),t(this._ch,this._cl,16),t(this._dh,this._dl,24),t(this._eh,this._el,32),t(this._fh,this._fl,40),t(this._gh,this._gl,48),t(this._hh,this._hl,56),e},e.exports=c},function(e,t,r){"use strict";(function(t,i){var n=r(35);e.exports=y;var a,o=r(104);y.ReadableState=v;r(23).EventEmitter;var s=function(e,t){return e.listeners(t).length},c=r(164),u=r(1).Buffer,l=t.Uint8Array||function(){};var h=Object.create(r(21));h.inherits=r(0);var d=r(288),p=void 0;p=d&&d.debuglog?d.debuglog("stream"):function(){};var f,m=r(289),g=r(165);h.inherits(y,c);var _=["error","close","destroy","pause","resume"];function v(e,t){e=e||{};var i=t instanceof(a=a||r(39));this.objectMode=!!e.objectMode,i&&(this.objectMode=this.objectMode||!!e.readableObjectMode);var n=e.highWaterMark,o=e.readableHighWaterMark,s=this.objectMode?16:16384;this.highWaterMark=n||0===n?n:i&&(o||0===o)?o:s,this.highWaterMark=Math.floor(this.highWaterMark),this.buffer=new m,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(f||(f=r(26).StringDecoder),this.decoder=new f(e.encoding),this.encoding=e.encoding)}function y(e){if(a=a||r(39),!(this instanceof y))return new y(e);this._readableState=new v(e,this),this.readable=!0,e&&("function"==typeof e.read&&(this._read=e.read),"function"==typeof e.destroy&&(this._destroy=e.destroy)),c.call(this)}function b(e,t,r,i,n){var a,o=e._readableState;null===t?(o.reading=!1,function(e,t){if(t.ended)return;if(t.decoder){var r=t.decoder.end();r&&r.length&&(t.buffer.push(r),t.length+=t.objectMode?1:r.length)}t.ended=!0,S(e)}(e,o)):(n||(a=function(e,t){var r;i=t,u.isBuffer(i)||i instanceof l||"string"==typeof t||void 0===t||e.objectMode||(r=new TypeError("Invalid non-string/buffer chunk"));var i;return r}(o,t)),a?e.emit("error",a):o.objectMode||t&&t.length>0?("string"==typeof t||o.objectMode||Object.getPrototypeOf(t)===u.prototype||(t=function(e){return u.from(e)}(t)),i?o.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):E(e,o,t,!0):o.ended?e.emit("error",new Error("stream.push() after EOF")):(o.reading=!1,o.decoder&&!r?(t=o.decoder.write(t),o.objectMode||0!==t.length?E(e,o,t,!1):x(e,o)):E(e,o,t,!1))):i||(o.reading=!1));return function(e){return!e.ended&&(e.needReadable||e.lengtht.highWaterMark&&(t.highWaterMark=function(e){return e>=8388608?e=8388608:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function S(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(p("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?n.nextTick(k,e):k(e))}function k(e){p("emit readable"),e.emit("readable"),T(e)}function x(e,t){t.readingMore||(t.readingMore=!0,n.nextTick(M,e,t))}function M(e,t){for(var r=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=t.length?(r=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.head.data:t.buffer.concat(t.length),t.buffer.clear()):r=function(e,t,r){var i;ea.length?a.length:e;if(o===a.length?n+=a:n+=a.slice(0,e),0===(e-=o)){o===a.length?(++i,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=a.slice(o));break}++i}return t.length-=i,n}(e,t):function(e,t){var r=u.allocUnsafe(e),i=t.head,n=1;i.data.copy(r),e-=i.data.length;for(;i=i.next;){var a=i.data,o=e>a.length?a.length:e;if(a.copy(r,r.length-e,0,o),0===(e-=o)){o===a.length?(++n,i.next?t.head=i.next:t.head=t.tail=null):(t.head=i,i.data=a.slice(o));break}++n}return t.length-=n,r}(e,t);return i}(e,t.buffer,t.decoder),r);var r}function I(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,n.nextTick(O,t,e))}function O(e,t){e.endEmitted||0!==e.length||(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function A(e,t){for(var r=0,i=e.length;r=t.highWaterMark||t.ended))return p("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?I(this):S(this),null;if(0===(e=w(e,t))&&t.ended)return 0===t.length&&I(this),null;var i,n=t.needReadable;return p("need readable",n),(0===t.length||t.length-e0?R(e,t):null)?(t.needReadable=!0,e=0):t.length-=e,0===t.length&&(t.ended||(t.needReadable=!0),r!==e&&t.ended&&I(this)),null!==i&&this.emit("data",i),i},y.prototype._read=function(e){this.emit("error",new Error("_read() is not implemented"))},y.prototype.pipe=function(e,t){var r=this,a=this._readableState;switch(a.pipesCount){case 0:a.pipes=e;break;case 1:a.pipes=[a.pipes,e];break;default:a.pipes.push(e)}a.pipesCount+=1,p("pipe count=%d opts=%j",a.pipesCount,t);var c=(!t||!1!==t.end)&&e!==i.stdout&&e!==i.stderr?l:y;function u(t,i){p("onunpipe"),t===r&&i&&!1===i.hasUnpiped&&(i.hasUnpiped=!0,p("cleanup"),e.removeListener("close",_),e.removeListener("finish",v),e.removeListener("drain",h),e.removeListener("error",g),e.removeListener("unpipe",u),r.removeListener("end",l),r.removeListener("end",y),r.removeListener("data",m),d=!0,!a.awaitDrain||e._writableState&&!e._writableState.needDrain||h())}function l(){p("onend"),e.end()}a.endEmitted?n.nextTick(c):r.once("end",c),e.on("unpipe",u);var h=function(e){return function(){var t=e._readableState;p("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&s(e,"data")&&(t.flowing=!0,T(e))}}(r);e.on("drain",h);var d=!1;var f=!1;function m(t){p("ondata"),f=!1,!1!==e.write(t)||f||((1===a.pipesCount&&a.pipes===e||a.pipesCount>1&&-1!==A(a.pipes,e))&&!d&&(p("false write response, pause",r._readableState.awaitDrain),r._readableState.awaitDrain++,f=!0),r.pause())}function g(t){p("onerror",t),y(),e.removeListener("error",g),0===s(e,"error")&&e.emit("error",t)}function _(){e.removeListener("finish",v),y()}function v(){p("onfinish"),e.removeListener("close",_),y()}function y(){p("unpipe"),r.unpipe(e)}return r.on("data",m),function(e,t,r){if("function"==typeof e.prependListener)return e.prependListener(t,r);e._events&&e._events[t]?o(e._events[t])?e._events[t].unshift(r):e._events[t]=[r,e._events[t]]:e.on(t,r)}(e,"error",g),e.once("close",_),e.once("finish",v),e.emit("pipe",r),a.flowing||(p("pipe resume"),r.resume()),e},y.prototype.unpipe=function(e){var t=this._readableState,r={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes||(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,r)),this;if(!e){var i=t.pipes,n=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var a=0;ar)?t=("rmd160"===e?new c:u(e)).update(t).digest():t.lengthr||a!=a)throw new TypeError("Bad key length")}}).call(this,r(2).Buffer)},function(e,t,r){(function(t){var r;t.browser?r="utf-8":r=parseInt(t.version.split(".")[0].slice(1),10)>=6?"utf-8":"binary";e.exports=r}).call(this,r(3))},function(e,t,r){var i=r(168),n=r(107),a=r(108),o=r(171),s=r(172),c=r(1).Buffer,u=c.alloc(128),l={md5:16,sha1:20,sha224:28,sha256:32,sha384:48,sha512:64,rmd160:20,ripemd160:20};function h(e,t,r){var o=function(e){function t(t){return a(e).update(t).digest()}return"rmd160"===e||"ripemd160"===e?function(e){return(new n).update(e).digest()}:"md5"===e?i:t}(e),s="sha512"===e||"sha384"===e?128:64;t.length>s?t=o(t):t.length>>0},t.writeUInt32BE=function(e,t,r){e[0+r]=t>>>24,e[1+r]=t>>>16&255,e[2+r]=t>>>8&255,e[3+r]=255&t},t.ip=function(e,t,r,i){for(var n=0,a=0,o=6;o>=0;o-=2){for(var s=0;s<=24;s+=8)n<<=1,n|=t>>>s+o&1;for(s=0;s<=24;s+=8)n<<=1,n|=e>>>s+o&1}for(o=6;o>=0;o-=2){for(s=1;s<=25;s+=8)a<<=1,a|=t>>>s+o&1;for(s=1;s<=25;s+=8)a<<=1,a|=e>>>s+o&1}r[i+0]=n>>>0,r[i+1]=a>>>0},t.rip=function(e,t,r,i){for(var n=0,a=0,o=0;o<4;o++)for(var s=24;s>=0;s-=8)n<<=1,n|=t>>>s+o&1,n<<=1,n|=e>>>s+o&1;for(o=4;o<8;o++)for(s=24;s>=0;s-=8)a<<=1,a|=t>>>s+o&1,a<<=1,a|=e>>>s+o&1;r[i+0]=n>>>0,r[i+1]=a>>>0},t.pc1=function(e,t,r,i){for(var n=0,a=0,o=7;o>=5;o--){for(var s=0;s<=24;s+=8)n<<=1,n|=t>>s+o&1;for(s=0;s<=24;s+=8)n<<=1,n|=e>>s+o&1}for(s=0;s<=24;s+=8)n<<=1,n|=t>>s+o&1;for(o=1;o<=3;o++){for(s=0;s<=24;s+=8)a<<=1,a|=t>>s+o&1;for(s=0;s<=24;s+=8)a<<=1,a|=e>>s+o&1}for(s=0;s<=24;s+=8)a<<=1,a|=e>>s+o&1;r[i+0]=n>>>0,r[i+1]=a>>>0},t.r28shl=function(e,t){return e<>>28-t};var i=[14,11,17,4,27,23,25,0,13,22,7,18,5,9,16,24,2,20,12,21,1,8,15,26,15,4,25,19,9,1,26,16,5,11,23,8,12,7,17,0,22,3,10,14,6,20,27,24];t.pc2=function(e,t,r,n){for(var a=0,o=0,s=i.length>>>1,c=0;c>>i[c]&1;for(c=s;c>>i[c]&1;r[n+0]=a>>>0,r[n+1]=o>>>0},t.expand=function(e,t,r){var i=0,n=0;i=(1&e)<<5|e>>>27;for(var a=23;a>=15;a-=4)i<<=6,i|=e>>>a&63;for(a=11;a>=3;a-=4)n|=e>>>a&63,n<<=6;n|=(31&e)<<1|e>>>31,t[r+0]=i>>>0,t[r+1]=n>>>0};var n=[14,0,4,15,13,7,1,4,2,14,15,2,11,13,8,1,3,10,10,6,6,12,12,11,5,9,9,5,0,3,7,8,4,15,1,12,14,8,8,2,13,4,6,9,2,1,11,7,15,5,12,11,9,3,7,14,3,10,10,0,5,6,0,13,15,3,1,13,8,4,14,7,6,15,11,2,3,8,4,14,9,12,7,0,2,1,13,10,12,6,0,9,5,11,10,5,0,13,14,8,7,10,11,1,10,3,4,15,13,4,1,2,5,11,8,6,12,7,6,12,9,0,3,5,2,14,15,9,10,13,0,7,9,0,14,9,6,3,3,4,15,6,5,10,1,2,13,8,12,5,7,14,11,12,4,11,2,15,8,1,13,1,6,10,4,13,9,0,8,6,15,9,3,8,0,7,11,4,1,15,2,14,12,3,5,11,10,5,14,2,7,12,7,13,13,8,14,11,3,5,0,6,6,15,9,0,10,3,1,4,2,7,8,2,5,12,11,1,12,10,4,14,15,9,10,3,6,15,9,0,0,6,12,10,11,1,7,13,13,8,15,9,1,4,3,5,14,11,5,12,2,7,8,2,4,14,2,14,12,11,4,2,1,12,7,4,10,7,11,13,6,1,8,5,5,0,3,15,15,10,13,3,0,9,14,8,9,6,4,11,2,8,1,12,11,7,10,1,13,14,7,2,8,13,15,6,9,15,12,0,5,9,6,10,3,4,0,5,14,3,12,10,1,15,10,4,15,2,9,7,2,12,6,9,8,5,0,6,13,1,3,13,4,14,14,0,7,11,5,3,11,8,9,4,14,3,15,2,5,12,2,9,8,5,12,15,3,10,7,11,0,14,4,1,10,7,1,6,13,0,11,8,6,13,4,13,11,0,2,11,14,7,15,4,0,9,8,1,13,10,3,14,12,3,9,5,7,12,5,2,10,15,6,8,1,6,1,6,4,11,11,13,13,8,12,1,3,4,7,10,14,7,10,9,15,5,6,0,8,15,0,14,5,2,9,3,2,12,13,1,2,15,8,13,4,8,6,10,15,3,11,7,1,4,10,12,9,5,3,6,14,11,5,0,0,14,12,9,7,2,7,2,11,1,4,14,1,7,9,4,12,10,14,8,2,13,0,15,6,12,10,9,13,0,15,3,3,5,5,6,8,11];t.substitute=function(e,t){for(var r=0,i=0;i<4;i++){r<<=4,r|=n[64*i+(e>>>18-6*i&63)]}for(i=0;i<4;i++){r<<=4,r|=n[256+64*i+(t>>>18-6*i&63)]}return r>>>0};var a=[16,25,12,11,3,20,4,15,31,17,9,6,27,14,1,22,30,24,8,18,0,5,29,23,13,19,2,26,10,21,28,7];t.permute=function(e){for(var t=0,r=0;r>>a[r]&1;return t>>>0},t.padSplit=function(e,t,r){for(var i=e.toString(2);i.length>>1];r=a.r28shl(r,s),n=a.r28shl(n,s),a.pc2(r,n,e.keys,o)}},c.prototype._update=function(e,t,r,i){var n=this._desState,o=a.readUInt32BE(e,t),s=a.readUInt32BE(e,t+4);a.ip(o,s,n.tmp,0),o=n.tmp[0],s=n.tmp[1],"encrypt"===this.type?this._encrypt(n,o,s,n.tmp,0):this._decrypt(n,o,s,n.tmp,0),o=n.tmp[0],s=n.tmp[1],a.writeUInt32BE(r,o,i),a.writeUInt32BE(r,s,i+4)},c.prototype._pad=function(e,t){for(var r=e.length-t,i=t;i>>0,o=d}a.rip(s,o,i,n)},c.prototype._decrypt=function(e,t,r,i,n){for(var o=r,s=t,c=e.keys.length-2;c>=0;c-=2){var u=e.keys[c],l=e.keys[c+1];a.expand(o,e.tmp,0),u^=e.tmp[0],l^=e.tmp[1];var h=a.substitute(u,l),d=o;o=(s^a.permute(h))>>>0,s=d}a.rip(o,s,i,n)}},function(e,t,r){var i=r(62),n=r(1).Buffer,a=r(177);function o(e){var t=e._cipher.encryptBlockRaw(e._prev);return a(e._prev),t}t.encrypt=function(e,t){var r=Math.ceil(t.length/16),a=e._cache.length;e._cache=n.concat([e._cache,n.allocUnsafe(16*r)]);for(var s=0;se;)r.ishrn(1);if(r.isEven()&&r.iadd(s),r.testn(1)||r.iadd(c),t.cmp(c)){if(!t.cmp(u))for(;r.mod(l).cmp(h);)r.iadd(p)}else for(;r.mod(a).cmp(d);)r.iadd(p);if(g(f=r.shrn(1))&&g(r)&&_(f)&&_(r)&&o.test(f)&&o.test(r))return r}}},function(e,t,r){(function(e){!function(e,t){"use strict";function i(e,t){if(!e)throw new Error(t||"Assertion failed")}function n(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}function a(e,t,r){if(a.isBN(e))return e;this.negative=0,this.words=null,this.length=0,this.red=null,null!==e&&("le"!==t&&"be"!==t||(r=t,t=10),this._init(e||0,t||10,r||"be"))}var o;"object"==typeof e?e.exports=a:t.BN=a,a.BN=a,a.wordSize=26;try{o=r(315).Buffer}catch(e){}function s(e,t,r){for(var i=0,n=Math.min(e.length,r),a=t;a=49&&o<=54?o-49+10:o>=17&&o<=22?o-17+10:15&o}return i}function c(e,t,r,i){for(var n=0,a=Math.min(e.length,r),o=t;o=49?s-49+10:s>=17?s-17+10:s}return n}a.isBN=function(e){return e instanceof a||null!==e&&"object"==typeof e&&e.constructor.wordSize===a.wordSize&&Array.isArray(e.words)},a.max=function(e,t){return e.cmp(t)>0?e:t},a.min=function(e,t){return e.cmp(t)<0?e:t},a.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),i(t===(0|t)&&t>=2&&t<=36);var n=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&n++,16===t?this._parseHex(e,n):this._parseBase(e,t,n),"-"===e[0]&&(this.negative=1),this.strip(),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(i(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initArray=function(e,t,r){if(i("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var n=0;n=0;n-=3)o=e[n]|e[n-1]<<8|e[n-2]<<16,this.words[a]|=o<>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);else if("le"===r)for(n=0,a=0;n>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);return this.strip()},a.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)n=s(e,r,r+6),this.words[i]|=n<>>26-a&4194303,(a+=24)>=26&&(a-=26,i++);r+6!==t&&(n=s(e,t,r+6),this.words[i]|=n<>>26-a&4194303),this.strip()},a.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var i=0,n=1;n<=67108863;n*=t)i++;i--,n=n/t|0;for(var a=e.length-r,o=a%i,s=Math.min(a,a-o)+r,u=0,l=r;l1&&0===this.words[this.length-1];)this.length--;return this._normSign()},a.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},a.prototype.inspect=function(){return(this.red?""};var u=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],l=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],h=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];function d(e,t,r){r.negative=t.negative^e.negative;var i=e.length+t.length|0;r.length=i,i=i-1|0;var n=0|e.words[0],a=0|t.words[0],o=n*a,s=67108863&o,c=o/67108864|0;r.words[0]=s;for(var u=1;u>>26,h=67108863&c,d=Math.min(u,t.length-1),p=Math.max(0,u-e.length+1);p<=d;p++){var f=u-p|0;l+=(o=(n=0|e.words[f])*(a=0|t.words[p])+h)/67108864|0,h=67108863&o}r.words[u]=0|h,c=0|l}return 0!==c?r.words[u]=0|c:r.length--,r.strip()}a.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var n=0,a=0,o=0;o>>24-n&16777215)||o!==this.length-1?u[6-c.length]+c+r:c+r,(n+=2)>=26&&(n-=26,o--)}for(0!==a&&(r=a.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var d=l[e],p=h[e];r="";var f=this.clone();for(f.negative=0;!f.isZero();){var m=f.modn(p).toString(e);r=(f=f.idivn(p)).isZero()?m+r:u[d-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}i(!1,"Base should be between 2 and 36")},a.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&i(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},a.prototype.toJSON=function(){return this.toString(16)},a.prototype.toBuffer=function(e,t){return i(void 0!==o),this.toArrayLike(o,e,t)},a.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)},a.prototype.toArrayLike=function(e,t,r){var n=this.byteLength(),a=r||Math.max(1,n);i(n<=a,"byte array longer than desired length"),i(a>0,"Requested array length <= 0"),this.strip();var o,s,c="le"===t,u=new e(a),l=this.clone();if(c){for(s=0;!l.isZero();s++)o=l.andln(255),l.iushrn(8),u[s]=o;for(;s=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},a.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},a.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},a.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},a.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},a.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},a.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},a.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var i=0;ie.length?this.clone().ixor(e):e.clone().ixor(this)},a.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},a.prototype.inotn=function(e){i("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var n=0;n0&&(this.words[n]=~this.words[n]&67108863>>26-r),this.strip()},a.prototype.notn=function(e){return this.clone().inotn(e)},a.prototype.setn=function(e,t){i("number"==typeof e&&e>=0);var r=e/26|0,n=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,i=e):(r=e,i=this);for(var n=0,a=0;a>>26;for(;0!==n&&a>>26;if(this.length=r.length,0!==n)this.words[this.length]=n,this.length++;else if(r!==this)for(;ae.length?this.clone().iadd(e):e.clone().iadd(this)},a.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,i,n=this.cmp(e);if(0===n)return this.negative=0,this.length=1,this.words[0]=0,this;n>0?(r=this,i=e):(r=e,i=this);for(var a=0,o=0;o>26,this.words[o]=67108863&t;for(;0!==a&&o>26,this.words[o]=67108863&t;if(0===a&&o>>13,p=0|o[1],f=8191&p,m=p>>>13,g=0|o[2],_=8191&g,v=g>>>13,y=0|o[3],b=8191&y,E=y>>>13,w=0|o[4],S=8191&w,k=w>>>13,x=0|o[5],M=8191&x,N=x>>>13,j=0|o[6],T=8191&j,R=j>>>13,I=0|o[7],O=8191&I,A=I>>>13,P=0|o[8],D=8191&P,F=P>>>13,C=0|o[9],B=8191&C,z=C>>>13,L=0|s[0],U=8191&L,H=L>>>13,q=0|s[1],K=8191&q,Z=q>>>13,W=0|s[2],X=8191&W,Q=W>>>13,J=0|s[3],V=8191&J,G=J>>>13,Y=0|s[4],$=8191&Y,ee=Y>>>13,te=0|s[5],re=8191&te,ie=te>>>13,ne=0|s[6],ae=8191&ne,oe=ne>>>13,se=0|s[7],ce=8191&se,ue=se>>>13,le=0|s[8],he=8191&le,de=le>>>13,pe=0|s[9],fe=8191&pe,me=pe>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(u+(i=Math.imul(h,U))|0)+((8191&(n=(n=Math.imul(h,H))+Math.imul(d,U)|0))<<13)|0;u=((a=Math.imul(d,H))+(n>>>13)|0)+(ge>>>26)|0,ge&=67108863,i=Math.imul(f,U),n=(n=Math.imul(f,H))+Math.imul(m,U)|0,a=Math.imul(m,H);var _e=(u+(i=i+Math.imul(h,K)|0)|0)+((8191&(n=(n=n+Math.imul(h,Z)|0)+Math.imul(d,K)|0))<<13)|0;u=((a=a+Math.imul(d,Z)|0)+(n>>>13)|0)+(_e>>>26)|0,_e&=67108863,i=Math.imul(_,U),n=(n=Math.imul(_,H))+Math.imul(v,U)|0,a=Math.imul(v,H),i=i+Math.imul(f,K)|0,n=(n=n+Math.imul(f,Z)|0)+Math.imul(m,K)|0,a=a+Math.imul(m,Z)|0;var ve=(u+(i=i+Math.imul(h,X)|0)|0)+((8191&(n=(n=n+Math.imul(h,Q)|0)+Math.imul(d,X)|0))<<13)|0;u=((a=a+Math.imul(d,Q)|0)+(n>>>13)|0)+(ve>>>26)|0,ve&=67108863,i=Math.imul(b,U),n=(n=Math.imul(b,H))+Math.imul(E,U)|0,a=Math.imul(E,H),i=i+Math.imul(_,K)|0,n=(n=n+Math.imul(_,Z)|0)+Math.imul(v,K)|0,a=a+Math.imul(v,Z)|0,i=i+Math.imul(f,X)|0,n=(n=n+Math.imul(f,Q)|0)+Math.imul(m,X)|0,a=a+Math.imul(m,Q)|0;var ye=(u+(i=i+Math.imul(h,V)|0)|0)+((8191&(n=(n=n+Math.imul(h,G)|0)+Math.imul(d,V)|0))<<13)|0;u=((a=a+Math.imul(d,G)|0)+(n>>>13)|0)+(ye>>>26)|0,ye&=67108863,i=Math.imul(S,U),n=(n=Math.imul(S,H))+Math.imul(k,U)|0,a=Math.imul(k,H),i=i+Math.imul(b,K)|0,n=(n=n+Math.imul(b,Z)|0)+Math.imul(E,K)|0,a=a+Math.imul(E,Z)|0,i=i+Math.imul(_,X)|0,n=(n=n+Math.imul(_,Q)|0)+Math.imul(v,X)|0,a=a+Math.imul(v,Q)|0,i=i+Math.imul(f,V)|0,n=(n=n+Math.imul(f,G)|0)+Math.imul(m,V)|0,a=a+Math.imul(m,G)|0;var be=(u+(i=i+Math.imul(h,$)|0)|0)+((8191&(n=(n=n+Math.imul(h,ee)|0)+Math.imul(d,$)|0))<<13)|0;u=((a=a+Math.imul(d,ee)|0)+(n>>>13)|0)+(be>>>26)|0,be&=67108863,i=Math.imul(M,U),n=(n=Math.imul(M,H))+Math.imul(N,U)|0,a=Math.imul(N,H),i=i+Math.imul(S,K)|0,n=(n=n+Math.imul(S,Z)|0)+Math.imul(k,K)|0,a=a+Math.imul(k,Z)|0,i=i+Math.imul(b,X)|0,n=(n=n+Math.imul(b,Q)|0)+Math.imul(E,X)|0,a=a+Math.imul(E,Q)|0,i=i+Math.imul(_,V)|0,n=(n=n+Math.imul(_,G)|0)+Math.imul(v,V)|0,a=a+Math.imul(v,G)|0,i=i+Math.imul(f,$)|0,n=(n=n+Math.imul(f,ee)|0)+Math.imul(m,$)|0,a=a+Math.imul(m,ee)|0;var Ee=(u+(i=i+Math.imul(h,re)|0)|0)+((8191&(n=(n=n+Math.imul(h,ie)|0)+Math.imul(d,re)|0))<<13)|0;u=((a=a+Math.imul(d,ie)|0)+(n>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,i=Math.imul(T,U),n=(n=Math.imul(T,H))+Math.imul(R,U)|0,a=Math.imul(R,H),i=i+Math.imul(M,K)|0,n=(n=n+Math.imul(M,Z)|0)+Math.imul(N,K)|0,a=a+Math.imul(N,Z)|0,i=i+Math.imul(S,X)|0,n=(n=n+Math.imul(S,Q)|0)+Math.imul(k,X)|0,a=a+Math.imul(k,Q)|0,i=i+Math.imul(b,V)|0,n=(n=n+Math.imul(b,G)|0)+Math.imul(E,V)|0,a=a+Math.imul(E,G)|0,i=i+Math.imul(_,$)|0,n=(n=n+Math.imul(_,ee)|0)+Math.imul(v,$)|0,a=a+Math.imul(v,ee)|0,i=i+Math.imul(f,re)|0,n=(n=n+Math.imul(f,ie)|0)+Math.imul(m,re)|0,a=a+Math.imul(m,ie)|0;var we=(u+(i=i+Math.imul(h,ae)|0)|0)+((8191&(n=(n=n+Math.imul(h,oe)|0)+Math.imul(d,ae)|0))<<13)|0;u=((a=a+Math.imul(d,oe)|0)+(n>>>13)|0)+(we>>>26)|0,we&=67108863,i=Math.imul(O,U),n=(n=Math.imul(O,H))+Math.imul(A,U)|0,a=Math.imul(A,H),i=i+Math.imul(T,K)|0,n=(n=n+Math.imul(T,Z)|0)+Math.imul(R,K)|0,a=a+Math.imul(R,Z)|0,i=i+Math.imul(M,X)|0,n=(n=n+Math.imul(M,Q)|0)+Math.imul(N,X)|0,a=a+Math.imul(N,Q)|0,i=i+Math.imul(S,V)|0,n=(n=n+Math.imul(S,G)|0)+Math.imul(k,V)|0,a=a+Math.imul(k,G)|0,i=i+Math.imul(b,$)|0,n=(n=n+Math.imul(b,ee)|0)+Math.imul(E,$)|0,a=a+Math.imul(E,ee)|0,i=i+Math.imul(_,re)|0,n=(n=n+Math.imul(_,ie)|0)+Math.imul(v,re)|0,a=a+Math.imul(v,ie)|0,i=i+Math.imul(f,ae)|0,n=(n=n+Math.imul(f,oe)|0)+Math.imul(m,ae)|0,a=a+Math.imul(m,oe)|0;var Se=(u+(i=i+Math.imul(h,ce)|0)|0)+((8191&(n=(n=n+Math.imul(h,ue)|0)+Math.imul(d,ce)|0))<<13)|0;u=((a=a+Math.imul(d,ue)|0)+(n>>>13)|0)+(Se>>>26)|0,Se&=67108863,i=Math.imul(D,U),n=(n=Math.imul(D,H))+Math.imul(F,U)|0,a=Math.imul(F,H),i=i+Math.imul(O,K)|0,n=(n=n+Math.imul(O,Z)|0)+Math.imul(A,K)|0,a=a+Math.imul(A,Z)|0,i=i+Math.imul(T,X)|0,n=(n=n+Math.imul(T,Q)|0)+Math.imul(R,X)|0,a=a+Math.imul(R,Q)|0,i=i+Math.imul(M,V)|0,n=(n=n+Math.imul(M,G)|0)+Math.imul(N,V)|0,a=a+Math.imul(N,G)|0,i=i+Math.imul(S,$)|0,n=(n=n+Math.imul(S,ee)|0)+Math.imul(k,$)|0,a=a+Math.imul(k,ee)|0,i=i+Math.imul(b,re)|0,n=(n=n+Math.imul(b,ie)|0)+Math.imul(E,re)|0,a=a+Math.imul(E,ie)|0,i=i+Math.imul(_,ae)|0,n=(n=n+Math.imul(_,oe)|0)+Math.imul(v,ae)|0,a=a+Math.imul(v,oe)|0,i=i+Math.imul(f,ce)|0,n=(n=n+Math.imul(f,ue)|0)+Math.imul(m,ce)|0,a=a+Math.imul(m,ue)|0;var ke=(u+(i=i+Math.imul(h,he)|0)|0)+((8191&(n=(n=n+Math.imul(h,de)|0)+Math.imul(d,he)|0))<<13)|0;u=((a=a+Math.imul(d,de)|0)+(n>>>13)|0)+(ke>>>26)|0,ke&=67108863,i=Math.imul(B,U),n=(n=Math.imul(B,H))+Math.imul(z,U)|0,a=Math.imul(z,H),i=i+Math.imul(D,K)|0,n=(n=n+Math.imul(D,Z)|0)+Math.imul(F,K)|0,a=a+Math.imul(F,Z)|0,i=i+Math.imul(O,X)|0,n=(n=n+Math.imul(O,Q)|0)+Math.imul(A,X)|0,a=a+Math.imul(A,Q)|0,i=i+Math.imul(T,V)|0,n=(n=n+Math.imul(T,G)|0)+Math.imul(R,V)|0,a=a+Math.imul(R,G)|0,i=i+Math.imul(M,$)|0,n=(n=n+Math.imul(M,ee)|0)+Math.imul(N,$)|0,a=a+Math.imul(N,ee)|0,i=i+Math.imul(S,re)|0,n=(n=n+Math.imul(S,ie)|0)+Math.imul(k,re)|0,a=a+Math.imul(k,ie)|0,i=i+Math.imul(b,ae)|0,n=(n=n+Math.imul(b,oe)|0)+Math.imul(E,ae)|0,a=a+Math.imul(E,oe)|0,i=i+Math.imul(_,ce)|0,n=(n=n+Math.imul(_,ue)|0)+Math.imul(v,ce)|0,a=a+Math.imul(v,ue)|0,i=i+Math.imul(f,he)|0,n=(n=n+Math.imul(f,de)|0)+Math.imul(m,he)|0,a=a+Math.imul(m,de)|0;var xe=(u+(i=i+Math.imul(h,fe)|0)|0)+((8191&(n=(n=n+Math.imul(h,me)|0)+Math.imul(d,fe)|0))<<13)|0;u=((a=a+Math.imul(d,me)|0)+(n>>>13)|0)+(xe>>>26)|0,xe&=67108863,i=Math.imul(B,K),n=(n=Math.imul(B,Z))+Math.imul(z,K)|0,a=Math.imul(z,Z),i=i+Math.imul(D,X)|0,n=(n=n+Math.imul(D,Q)|0)+Math.imul(F,X)|0,a=a+Math.imul(F,Q)|0,i=i+Math.imul(O,V)|0,n=(n=n+Math.imul(O,G)|0)+Math.imul(A,V)|0,a=a+Math.imul(A,G)|0,i=i+Math.imul(T,$)|0,n=(n=n+Math.imul(T,ee)|0)+Math.imul(R,$)|0,a=a+Math.imul(R,ee)|0,i=i+Math.imul(M,re)|0,n=(n=n+Math.imul(M,ie)|0)+Math.imul(N,re)|0,a=a+Math.imul(N,ie)|0,i=i+Math.imul(S,ae)|0,n=(n=n+Math.imul(S,oe)|0)+Math.imul(k,ae)|0,a=a+Math.imul(k,oe)|0,i=i+Math.imul(b,ce)|0,n=(n=n+Math.imul(b,ue)|0)+Math.imul(E,ce)|0,a=a+Math.imul(E,ue)|0,i=i+Math.imul(_,he)|0,n=(n=n+Math.imul(_,de)|0)+Math.imul(v,he)|0,a=a+Math.imul(v,de)|0;var Me=(u+(i=i+Math.imul(f,fe)|0)|0)+((8191&(n=(n=n+Math.imul(f,me)|0)+Math.imul(m,fe)|0))<<13)|0;u=((a=a+Math.imul(m,me)|0)+(n>>>13)|0)+(Me>>>26)|0,Me&=67108863,i=Math.imul(B,X),n=(n=Math.imul(B,Q))+Math.imul(z,X)|0,a=Math.imul(z,Q),i=i+Math.imul(D,V)|0,n=(n=n+Math.imul(D,G)|0)+Math.imul(F,V)|0,a=a+Math.imul(F,G)|0,i=i+Math.imul(O,$)|0,n=(n=n+Math.imul(O,ee)|0)+Math.imul(A,$)|0,a=a+Math.imul(A,ee)|0,i=i+Math.imul(T,re)|0,n=(n=n+Math.imul(T,ie)|0)+Math.imul(R,re)|0,a=a+Math.imul(R,ie)|0,i=i+Math.imul(M,ae)|0,n=(n=n+Math.imul(M,oe)|0)+Math.imul(N,ae)|0,a=a+Math.imul(N,oe)|0,i=i+Math.imul(S,ce)|0,n=(n=n+Math.imul(S,ue)|0)+Math.imul(k,ce)|0,a=a+Math.imul(k,ue)|0,i=i+Math.imul(b,he)|0,n=(n=n+Math.imul(b,de)|0)+Math.imul(E,he)|0,a=a+Math.imul(E,de)|0;var Ne=(u+(i=i+Math.imul(_,fe)|0)|0)+((8191&(n=(n=n+Math.imul(_,me)|0)+Math.imul(v,fe)|0))<<13)|0;u=((a=a+Math.imul(v,me)|0)+(n>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,i=Math.imul(B,V),n=(n=Math.imul(B,G))+Math.imul(z,V)|0,a=Math.imul(z,G),i=i+Math.imul(D,$)|0,n=(n=n+Math.imul(D,ee)|0)+Math.imul(F,$)|0,a=a+Math.imul(F,ee)|0,i=i+Math.imul(O,re)|0,n=(n=n+Math.imul(O,ie)|0)+Math.imul(A,re)|0,a=a+Math.imul(A,ie)|0,i=i+Math.imul(T,ae)|0,n=(n=n+Math.imul(T,oe)|0)+Math.imul(R,ae)|0,a=a+Math.imul(R,oe)|0,i=i+Math.imul(M,ce)|0,n=(n=n+Math.imul(M,ue)|0)+Math.imul(N,ce)|0,a=a+Math.imul(N,ue)|0,i=i+Math.imul(S,he)|0,n=(n=n+Math.imul(S,de)|0)+Math.imul(k,he)|0,a=a+Math.imul(k,de)|0;var je=(u+(i=i+Math.imul(b,fe)|0)|0)+((8191&(n=(n=n+Math.imul(b,me)|0)+Math.imul(E,fe)|0))<<13)|0;u=((a=a+Math.imul(E,me)|0)+(n>>>13)|0)+(je>>>26)|0,je&=67108863,i=Math.imul(B,$),n=(n=Math.imul(B,ee))+Math.imul(z,$)|0,a=Math.imul(z,ee),i=i+Math.imul(D,re)|0,n=(n=n+Math.imul(D,ie)|0)+Math.imul(F,re)|0,a=a+Math.imul(F,ie)|0,i=i+Math.imul(O,ae)|0,n=(n=n+Math.imul(O,oe)|0)+Math.imul(A,ae)|0,a=a+Math.imul(A,oe)|0,i=i+Math.imul(T,ce)|0,n=(n=n+Math.imul(T,ue)|0)+Math.imul(R,ce)|0,a=a+Math.imul(R,ue)|0,i=i+Math.imul(M,he)|0,n=(n=n+Math.imul(M,de)|0)+Math.imul(N,he)|0,a=a+Math.imul(N,de)|0;var Te=(u+(i=i+Math.imul(S,fe)|0)|0)+((8191&(n=(n=n+Math.imul(S,me)|0)+Math.imul(k,fe)|0))<<13)|0;u=((a=a+Math.imul(k,me)|0)+(n>>>13)|0)+(Te>>>26)|0,Te&=67108863,i=Math.imul(B,re),n=(n=Math.imul(B,ie))+Math.imul(z,re)|0,a=Math.imul(z,ie),i=i+Math.imul(D,ae)|0,n=(n=n+Math.imul(D,oe)|0)+Math.imul(F,ae)|0,a=a+Math.imul(F,oe)|0,i=i+Math.imul(O,ce)|0,n=(n=n+Math.imul(O,ue)|0)+Math.imul(A,ce)|0,a=a+Math.imul(A,ue)|0,i=i+Math.imul(T,he)|0,n=(n=n+Math.imul(T,de)|0)+Math.imul(R,he)|0,a=a+Math.imul(R,de)|0;var Re=(u+(i=i+Math.imul(M,fe)|0)|0)+((8191&(n=(n=n+Math.imul(M,me)|0)+Math.imul(N,fe)|0))<<13)|0;u=((a=a+Math.imul(N,me)|0)+(n>>>13)|0)+(Re>>>26)|0,Re&=67108863,i=Math.imul(B,ae),n=(n=Math.imul(B,oe))+Math.imul(z,ae)|0,a=Math.imul(z,oe),i=i+Math.imul(D,ce)|0,n=(n=n+Math.imul(D,ue)|0)+Math.imul(F,ce)|0,a=a+Math.imul(F,ue)|0,i=i+Math.imul(O,he)|0,n=(n=n+Math.imul(O,de)|0)+Math.imul(A,he)|0,a=a+Math.imul(A,de)|0;var Ie=(u+(i=i+Math.imul(T,fe)|0)|0)+((8191&(n=(n=n+Math.imul(T,me)|0)+Math.imul(R,fe)|0))<<13)|0;u=((a=a+Math.imul(R,me)|0)+(n>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,i=Math.imul(B,ce),n=(n=Math.imul(B,ue))+Math.imul(z,ce)|0,a=Math.imul(z,ue),i=i+Math.imul(D,he)|0,n=(n=n+Math.imul(D,de)|0)+Math.imul(F,he)|0,a=a+Math.imul(F,de)|0;var Oe=(u+(i=i+Math.imul(O,fe)|0)|0)+((8191&(n=(n=n+Math.imul(O,me)|0)+Math.imul(A,fe)|0))<<13)|0;u=((a=a+Math.imul(A,me)|0)+(n>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,i=Math.imul(B,he),n=(n=Math.imul(B,de))+Math.imul(z,he)|0,a=Math.imul(z,de);var Ae=(u+(i=i+Math.imul(D,fe)|0)|0)+((8191&(n=(n=n+Math.imul(D,me)|0)+Math.imul(F,fe)|0))<<13)|0;u=((a=a+Math.imul(F,me)|0)+(n>>>13)|0)+(Ae>>>26)|0,Ae&=67108863;var Pe=(u+(i=Math.imul(B,fe))|0)+((8191&(n=(n=Math.imul(B,me))+Math.imul(z,fe)|0))<<13)|0;return u=((a=Math.imul(z,me))+(n>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,c[0]=ge,c[1]=_e,c[2]=ve,c[3]=ye,c[4]=be,c[5]=Ee,c[6]=we,c[7]=Se,c[8]=ke,c[9]=xe,c[10]=Me,c[11]=Ne,c[12]=je,c[13]=Te,c[14]=Re,c[15]=Ie,c[16]=Oe,c[17]=Ae,c[18]=Pe,0!==u&&(c[19]=u,r.length++),r};function f(e,t,r){return(new m).mulp(e,t,r)}function m(e,t){this.x=e,this.y=t}Math.imul||(p=d),a.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?p(this,e,t):r<63?d(this,e,t):r<1024?function(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var i=0,n=0,a=0;a>>26)|0)>>>26,o&=67108863}r.words[a]=s,i=o,o=n}return 0!==i?r.words[a]=i:r.length--,r.strip()}(this,e,t):f(this,e,t)},m.prototype.makeRBT=function(e){for(var t=new Array(e),r=a.prototype._countBits(e)-1,i=0;i>=1;return i},m.prototype.permute=function(e,t,r,i,n,a){for(var o=0;o>>=1)n++;return 1<>>=13,r[2*o+1]=8191&a,a>>>=13;for(o=2*t;o>=26,t+=n/67108864|0,t+=a>>>26,this.words[r]=67108863&a}return 0!==t&&(this.words[r]=t,this.length++),this},a.prototype.muln=function(e){return this.clone().imuln(e)},a.prototype.sqr=function(){return this.mul(this)},a.prototype.isqr=function(){return this.imul(this.clone())},a.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>n}return t}(e);if(0===t.length)return new a(1);for(var r=this,i=0;i=0);var t,r=e%26,n=(e-r)/26,a=67108863>>>26-r<<26-r;if(0!==r){var o=0;for(t=0;t>>26-r}o&&(this.words[t]=o,this.length++)}if(0!==n){for(t=this.length-1;t>=0;t--)this.words[t+n]=this.words[t];for(t=0;t=0),n=t?(t-t%26)/26:0;var a=e%26,o=Math.min((e-a)/26,this.length),s=67108863^67108863>>>a<o)for(this.length-=o,u=0;u=0&&(0!==l||u>=n);u--){var h=0|this.words[u];this.words[u]=l<<26-a|h>>>a,l=h&s}return c&&0!==l&&(c.words[c.length++]=l),0===this.length&&(this.words[0]=0,this.length=1),this.strip()},a.prototype.ishrn=function(e,t,r){return i(0===this.negative),this.iushrn(e,t,r)},a.prototype.shln=function(e){return this.clone().ishln(e)},a.prototype.ushln=function(e){return this.clone().iushln(e)},a.prototype.shrn=function(e){return this.clone().ishrn(e)},a.prototype.ushrn=function(e){return this.clone().iushrn(e)},a.prototype.testn=function(e){i("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,n=1<=0);var t=e%26,r=(e-t)/26;if(i(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var n=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},a.prototype.isubn=function(e){if(i("number"==typeof e),i(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(c/67108864|0),this.words[n+r]=67108863&a}for(;n>26,this.words[n+r]=67108863&a;if(0===s)return this.strip();for(i(-1===s),s=0,n=0;n>26,this.words[n]=67108863&a;return this.negative=1,this.strip()},a.prototype._wordDiv=function(e,t){var r=(this.length,e.length),i=this.clone(),n=e,o=0|n.words[n.length-1];0!==(r=26-this._countBits(o))&&(n=n.ushln(r),i.iushln(r),o=0|n.words[n.length-1]);var s,c=i.length-n.length;if("mod"!==t){(s=new a(null)).length=c+1,s.words=new Array(s.length);for(var u=0;u=0;h--){var d=67108864*(0|i.words[n.length+h])+(0|i.words[n.length+h-1]);for(d=Math.min(d/o|0,67108863),i._ishlnsubmul(n,d,h);0!==i.negative;)d--,i.negative=0,i._ishlnsubmul(n,1,h),i.isZero()||(i.negative^=1);s&&(s.words[h]=d)}return s&&s.strip(),i.strip(),"div"!==t&&0!==r&&i.iushrn(r),{div:s||null,mod:i}},a.prototype.divmod=function(e,t,r){return i(!e.isZero()),this.isZero()?{div:new a(0),mod:new a(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(n=s.div.neg()),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.iadd(e)),{div:n,mod:o}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(n=s.div.neg()),{div:n,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.isub(e)),{div:s.div,mod:o}):e.length>this.length||this.cmp(e)<0?{div:new a(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new a(this.modn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new a(this.modn(e.words[0]))}:this._wordDiv(e,t);var n,o,s},a.prototype.div=function(e){return this.divmod(e,"div",!1).div},a.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},a.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},a.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,i=e.ushrn(1),n=e.andln(1),a=r.cmp(i);return a<0||1===n&&0===a?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},a.prototype.modn=function(e){i(e<=67108863);for(var t=(1<<26)%e,r=0,n=this.length-1;n>=0;n--)r=(t*r+(0|this.words[n]))%e;return r},a.prototype.idivn=function(e){i(e<=67108863);for(var t=0,r=this.length-1;r>=0;r--){var n=(0|this.words[r])+67108864*t;this.words[r]=n/e|0,t=n%e}return this.strip()},a.prototype.divn=function(e){return this.clone().idivn(e)},a.prototype.egcd=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n=new a(1),o=new a(0),s=new a(0),c=new a(1),u=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++u;for(var l=r.clone(),h=t.clone();!t.isZero();){for(var d=0,p=1;0==(t.words[0]&p)&&d<26;++d,p<<=1);if(d>0)for(t.iushrn(d);d-- >0;)(n.isOdd()||o.isOdd())&&(n.iadd(l),o.isub(h)),n.iushrn(1),o.iushrn(1);for(var f=0,m=1;0==(r.words[0]&m)&&f<26;++f,m<<=1);if(f>0)for(r.iushrn(f);f-- >0;)(s.isOdd()||c.isOdd())&&(s.iadd(l),c.isub(h)),s.iushrn(1),c.iushrn(1);t.cmp(r)>=0?(t.isub(r),n.isub(s),o.isub(c)):(r.isub(t),s.isub(n),c.isub(o))}return{a:s,b:c,gcd:r.iushln(u)}},a.prototype._invmp=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n,o=new a(1),s=new a(0),c=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var u=0,l=1;0==(t.words[0]&l)&&u<26;++u,l<<=1);if(u>0)for(t.iushrn(u);u-- >0;)o.isOdd()&&o.iadd(c),o.iushrn(1);for(var h=0,d=1;0==(r.words[0]&d)&&h<26;++h,d<<=1);if(h>0)for(r.iushrn(h);h-- >0;)s.isOdd()&&s.iadd(c),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),o.isub(s)):(r.isub(t),s.isub(o))}return(n=0===t.cmpn(1)?o:s).cmpn(0)<0&&n.iadd(e),n},a.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var i=0;t.isEven()&&r.isEven();i++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var n=t.cmp(r);if(n<0){var a=t;t=r,r=a}else if(0===n||0===r.cmpn(1))break;t.isub(r)}return r.iushln(i)},a.prototype.invm=function(e){return this.egcd(e).a.umod(e)},a.prototype.isEven=function(){return 0==(1&this.words[0])},a.prototype.isOdd=function(){return 1==(1&this.words[0])},a.prototype.andln=function(e){return this.words[0]&e},a.prototype.bincn=function(e){i("number"==typeof e);var t=e%26,r=(e-t)/26,n=1<>>26,s&=67108863,this.words[o]=s}return 0!==a&&(this.words[o]=a,this.length++),this},a.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},a.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this.strip(),this.length>1)t=1;else{r&&(e=-e),i(e<=67108863,"Number is too big");var n=0|this.words[0];t=n===e?0:ne.length)return 1;if(this.length=0;r--){var i=0|this.words[r],n=0|e.words[r];if(i!==n){in&&(t=1);break}}return t},a.prototype.gtn=function(e){return 1===this.cmpn(e)},a.prototype.gt=function(e){return 1===this.cmp(e)},a.prototype.gten=function(e){return this.cmpn(e)>=0},a.prototype.gte=function(e){return this.cmp(e)>=0},a.prototype.ltn=function(e){return-1===this.cmpn(e)},a.prototype.lt=function(e){return-1===this.cmp(e)},a.prototype.lten=function(e){return this.cmpn(e)<=0},a.prototype.lte=function(e){return this.cmp(e)<=0},a.prototype.eqn=function(e){return 0===this.cmpn(e)},a.prototype.eq=function(e){return 0===this.cmp(e)},a.red=function(e){return new w(e)},a.prototype.toRed=function(e){return i(!this.red,"Already a number in reduction context"),i(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},a.prototype.fromRed=function(){return i(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},a.prototype._forceRed=function(e){return this.red=e,this},a.prototype.forceRed=function(e){return i(!this.red,"Already a number in reduction context"),this._forceRed(e)},a.prototype.redAdd=function(e){return i(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},a.prototype.redIAdd=function(e){return i(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},a.prototype.redSub=function(e){return i(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},a.prototype.redISub=function(e){return i(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},a.prototype.redShl=function(e){return i(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},a.prototype.redMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},a.prototype.redIMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},a.prototype.redSqr=function(){return i(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},a.prototype.redISqr=function(){return i(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},a.prototype.redSqrt=function(){return i(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},a.prototype.redInvm=function(){return i(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},a.prototype.redNeg=function(){return i(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},a.prototype.redPow=function(e){return i(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var g={k256:null,p224:null,p192:null,p25519:null};function _(e,t){this.name=e,this.p=new a(t,16),this.n=this.p.bitLength(),this.k=new a(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function v(){_.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function y(){_.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function b(){_.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function E(){_.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function w(e){if("string"==typeof e){var t=a._prime(e);this.m=t.p,this.prime=t}else i(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function S(e){w.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new a(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}_.prototype._tmp=function(){var e=new a(null);return e.words=new Array(Math.ceil(this.n/13)),e},_.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var i=t0?r.isub(this.p):r.strip(),r},_.prototype.split=function(e,t){e.iushrn(this.n,0,t)},_.prototype.imulK=function(e){return e.imul(this.k)},n(v,_),v.prototype.split=function(e,t){for(var r=Math.min(e.length,9),i=0;i>>22,n=a}n>>>=22,e.words[i-10]=n,0===n&&e.length>10?e.length-=10:e.length-=9},v.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=n,t=i}return 0!==t&&(e.words[e.length++]=t),e},a._prime=function(e){if(g[e])return g[e];var t;if("k256"===e)t=new v;else if("p224"===e)t=new y;else if("p192"===e)t=new b;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new E}return g[e]=t,t},w.prototype._verify1=function(e){i(0===e.negative,"red works only with positives"),i(e.red,"red works only with red numbers")},w.prototype._verify2=function(e,t){i(0==(e.negative|t.negative),"red works only with positives"),i(e.red&&e.red===t.red,"red works only with red numbers")},w.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):e.umod(this.m)._forceRed(this)},w.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},w.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},w.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},w.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},w.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},w.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},w.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},w.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},w.prototype.isqr=function(e){return this.imul(e,e.clone())},w.prototype.sqr=function(e){return this.mul(e,e)},w.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(i(t%2==1),3===t){var r=this.m.add(new a(1)).iushrn(2);return this.pow(e,r)}for(var n=this.m.subn(1),o=0;!n.isZero()&&0===n.andln(1);)o++,n.iushrn(1);i(!n.isZero());var s=new a(1).toRed(this),c=s.redNeg(),u=this.m.subn(1).iushrn(1),l=this.m.bitLength();for(l=new a(2*l*l).toRed(this);0!==this.pow(l,u).cmp(c);)l.redIAdd(c);for(var h=this.pow(l,n),d=this.pow(e,n.addn(1).iushrn(1)),p=this.pow(e,n),f=o;0!==p.cmp(s);){for(var m=p,g=0;0!==m.cmp(s);g++)m=m.redSqr();i(g=0;i--){for(var u=t.words[i],l=c-1;l>=0;l--){var h=u>>l&1;n!==r[0]&&(n=this.sqr(n)),0!==h||0!==o?(o<<=1,o|=h,(4===++s||0===i&&0===l)&&(n=this.mul(n,r[o]),s=0,o=0)):s=0}c=26}return n},w.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},w.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},a.mont=function(e){return new S(e)},n(S,w),S.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},S.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},S.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),a=n;return n.cmp(this.m)>=0?a=n.isub(this.m):n.cmpn(0)<0&&(a=n.iadd(this.m)),a._forceRed(this)},S.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new a(0)._forceRed(this);var r=e.mul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),o=n;return n.cmp(this.m)>=0?o=n.isub(this.m):n.cmpn(0)<0&&(o=n.iadd(this.m)),o._forceRed(this)},S.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(22)(e))},function(e,t,r){var i=r(316),n=r(114);function a(e){this.rand=e||new n.Rand}e.exports=a,a.create=function(e){return new a(e)},a.prototype._randbelow=function(e){var t=e.bitLength(),r=Math.ceil(t/8);do{var n=new i(this.rand.generate(r))}while(n.cmp(e)>=0);return n},a.prototype._randrange=function(e,t){var r=t.sub(e);return e.add(this._randbelow(r))},a.prototype.test=function(e,t,r){var n=e.bitLength(),a=i.mont(e),o=new i(1).toRed(a);t||(t=Math.max(1,n/48|0));for(var s=e.subn(1),c=0;!s.testn(c);c++);for(var u=e.shrn(c),l=s.toRed(a);t>0;t--){var h=this._randrange(new i(2),s);r&&r(h);var d=h.toRed(a).redPow(u);if(0!==d.cmp(o)&&0!==d.cmp(l)){for(var p=1;p0;t--){var l=this._randrange(new i(2),o),h=e.gcd(l);if(0!==h.cmpn(1))return h;var d=l.toRed(n).redPow(c);if(0!==d.cmp(a)&&0!==d.cmp(u)){for(var p=1;p0)if("string"==typeof t||o.objectMode||Object.getPrototypeOf(t)===s.prototype||(t=function(e){return s.from(e)}(t)),i)o.endEmitted?w(e,new E):N(e,o,t,!0);else if(o.ended)w(e,new y);else{if(o.destroyed)return!1;o.reading=!1,o.decoder&&!r?(t=o.decoder.write(t),o.objectMode||0!==t.length?N(e,o,t,!1):I(e,o)):N(e,o,t,!1)}else i||(o.reading=!1,I(e,o));return!o.ended&&(o.lengtht.highWaterMark&&(t.highWaterMark=function(e){return e>=1073741824?e=1073741824:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function T(e){var t=e._readableState;u("emitReadable",t.needReadable,t.emittedReadable),t.needReadable=!1,t.emittedReadable||(u("emitReadable",t.flowing),t.emittedReadable=!0,i.nextTick(R,e))}function R(e){var t=e._readableState;u("emitReadable_",t.destroyed,t.length,t.ended),t.destroyed||!t.length&&!t.ended||(e.emit("readable"),t.emittedReadable=!1),t.needReadable=!t.flowing&&!t.ended&&t.length<=t.highWaterMark,F(e)}function I(e,t){t.readingMore||(t.readingMore=!0,i.nextTick(O,e,t))}function O(e,t){for(;!t.reading&&!t.ended&&(t.length0,t.resumeScheduled&&!t.paused?t.flowing=!0:e.listenerCount("data")>0&&e.resume()}function P(e){u("readable nexttick read 0"),e.read(0)}function D(e,t){u("resume",t.reading),t.reading||e.read(0),t.resumeScheduled=!1,e.emit("resume"),F(e),t.flowing&&!t.reading&&e.read(0)}function F(e){var t=e._readableState;for(u("flow",t.flowing);t.flowing&&null!==e.read(););}function C(e,t){return 0===t.length?null:(t.objectMode?r=t.buffer.shift():!e||e>=t.length?(r=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.first():t.buffer.concat(t.length),t.buffer.clear()):r=t.buffer.consume(e,t.decoder),r);var r}function B(e){var t=e._readableState;u("endReadable",t.endEmitted),t.endEmitted||(t.ended=!0,i.nextTick(z,t,e))}function z(e,t){if(u("endReadableNT",e.endEmitted,e.length),!e.endEmitted&&0===e.length&&(e.endEmitted=!0,t.readable=!1,t.emit("end"),e.autoDestroy)){var r=t._writableState;(!r||r.autoDestroy&&r.finished)&&t.destroy()}}function L(e,t){for(var r=0,i=e.length;r=t.highWaterMark:t.length>0)||t.ended))return u("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?B(this):T(this),null;if(0===(e=j(e,t))&&t.ended)return 0===t.length&&B(this),null;var i,n=t.needReadable;return u("need readable",n),(0===t.length||t.length-e0?C(e,t):null)?(t.needReadable=t.length<=t.highWaterMark,e=0):(t.length-=e,t.awaitDrain=0),0===t.length&&(t.ended||(t.needReadable=!0),r!==e&&t.ended&&B(this)),null!==i&&this.emit("data",i),i},x.prototype._read=function(e){w(this,new b("_read()"))},x.prototype.pipe=function(e,t){var r=this,n=this._readableState;switch(n.pipesCount){case 0:n.pipes=e;break;case 1:n.pipes=[n.pipes,e];break;default:n.pipes.push(e)}n.pipesCount+=1,u("pipe count=%d opts=%j",n.pipesCount,t);var o=(!t||!1!==t.end)&&e!==i.stdout&&e!==i.stderr?c:g;function s(t,i){u("onunpipe"),t===r&&i&&!1===i.hasUnpiped&&(i.hasUnpiped=!0,u("cleanup"),e.removeListener("close",f),e.removeListener("finish",m),e.removeListener("drain",l),e.removeListener("error",p),e.removeListener("unpipe",s),r.removeListener("end",c),r.removeListener("end",g),r.removeListener("data",d),h=!0,!n.awaitDrain||e._writableState&&!e._writableState.needDrain||l())}function c(){u("onend"),e.end()}n.endEmitted?i.nextTick(o):r.once("end",o),e.on("unpipe",s);var l=function(e){return function(){var t=e._readableState;u("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&a(e,"data")&&(t.flowing=!0,F(e))}}(r);e.on("drain",l);var h=!1;function d(t){u("ondata");var i=e.write(t);u("dest.write",i),!1===i&&((1===n.pipesCount&&n.pipes===e||n.pipesCount>1&&-1!==L(n.pipes,e))&&!h&&(u("false write response, pause",n.awaitDrain),n.awaitDrain++),r.pause())}function p(t){u("onerror",t),g(),e.removeListener("error",p),0===a(e,"error")&&w(e,t)}function f(){e.removeListener("finish",m),g()}function m(){u("onfinish"),e.removeListener("close",f),g()}function g(){u("unpipe"),r.unpipe(e)}return r.on("data",d),function(e,t,r){if("function"==typeof e.prependListener)return e.prependListener(t,r);e._events&&e._events[t]?Array.isArray(e._events[t])?e._events[t].unshift(r):e._events[t]=[r,e._events[t]]:e.on(t,r)}(e,"error",p),e.once("close",f),e.once("finish",m),e.emit("pipe",r),n.flowing||(u("pipe resume"),r.resume()),e},x.prototype.unpipe=function(e){var t=this._readableState,r={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes||(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,r)),this;if(!e){var i=t.pipes,n=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var a=0;a0,!1!==n.flowing&&this.resume()):"readable"===e&&(n.endEmitted||n.readableListening||(n.readableListening=n.needReadable=!0,n.flowing=!1,n.emittedReadable=!1,u("on readable",n.length,n.reading),n.length?T(this):n.reading||i.nextTick(P,this))),r},x.prototype.addListener=x.prototype.on,x.prototype.removeListener=function(e,t){var r=o.prototype.removeListener.call(this,e,t);return"readable"===e&&i.nextTick(A,this),r},x.prototype.removeAllListeners=function(e){var t=o.prototype.removeAllListeners.apply(this,arguments);return"readable"!==e&&void 0!==e||i.nextTick(A,this),t},x.prototype.resume=function(){var e=this._readableState;return e.flowing||(u("resume"),e.flowing=!e.readableListening,function(e,t){t.resumeScheduled||(t.resumeScheduled=!0,i.nextTick(D,e,t))}(this,e)),e.paused=!1,this},x.prototype.pause=function(){return u("call pause flowing=%j",this._readableState.flowing),!1!==this._readableState.flowing&&(u("pause"),this._readableState.flowing=!1,this.emit("pause")),this._readableState.paused=!0,this},x.prototype.wrap=function(e){var t=this,r=this._readableState,i=!1;for(var n in e.on("end",(function(){if(u("wrapped end"),r.decoder&&!r.ended){var e=r.decoder.end();e&&e.length&&t.push(e)}t.push(null)})),e.on("data",(function(n){(u("wrapped data"),r.decoder&&(n=r.decoder.write(n)),r.objectMode&&null==n)||(r.objectMode||n&&n.length)&&(t.push(n)||(i=!0,e.pause()))})),e)void 0===this[n]&&"function"==typeof e[n]&&(this[n]=function(t){return function(){return e[t].apply(e,arguments)}}(n));for(var a=0;a-1))throw new E(e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(x.prototype,"writableBuffer",{enumerable:!1,get:function(){return this._writableState&&this._writableState.getBuffer()}}),Object.defineProperty(x.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),x.prototype._write=function(e,t,r){r(new m("_write()"))},x.prototype._writev=null,x.prototype.end=function(e,t,r){var n=this._writableState;return"function"==typeof e?(r=e,e=null,t=null):"function"==typeof t&&(r=t,t=null),null!=e&&this.write(e,t),n.corked&&(n.corked=1,this.uncork()),n.ending||function(e,t,r){t.ending=!0,I(e,t),r&&(t.finished?i.nextTick(r):e.once("finish",r));t.ended=!0,e.writable=!1}(this,n,r),this},Object.defineProperty(x.prototype,"writableLength",{enumerable:!1,get:function(){return this._writableState.length}}),Object.defineProperty(x.prototype,"destroyed",{enumerable:!1,get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),x.prototype.destroy=h.destroy,x.prototype._undestroy=h.undestroy,x.prototype._destroy=function(e,t){t(e)}}).call(this,r(8),r(3))},function(e,t,r){"use strict";e.exports=l;var i=r(49).codes,n=i.ERR_METHOD_NOT_IMPLEMENTED,a=i.ERR_MULTIPLE_CALLBACK,o=i.ERR_TRANSFORM_ALREADY_TRANSFORMING,s=i.ERR_TRANSFORM_WITH_LENGTH_0,c=r(51);function u(e,t){var r=this._transformState;r.transforming=!1;var i=r.writecb;if(null===i)return this.emit("error",new a);r.writechunk=null,r.writecb=null,null!=t&&this.push(t),i(e);var n=this._readableState;n.reading=!1,(n.needReadable||n.length>8,o=255&n;a?r.push(a,o):r.push(o)}return r},i.zero2=n,i.toHex=a,i.encode=function(e,t){return"hex"===t?a(e):e}},function(e,t,r){"use strict";var i=t;i.base=r(81),i.short=r(335),i.mont=r(336),i.edwards=r(337)},function(e,t,r){"use strict";var i=r(24).rotr32;function n(e,t,r){return e&t^~e&r}function a(e,t,r){return e&t^e&r^t&r}function o(e,t,r){return e^t^r}t.ft_1=function(e,t,r,i){return 0===e?n(t,r,i):1===e||3===e?o(t,r,i):2===e?a(t,r,i):void 0},t.ch32=n,t.maj32=a,t.p32=o,t.s0_256=function(e){return i(e,2)^i(e,13)^i(e,22)},t.s1_256=function(e){return i(e,6)^i(e,11)^i(e,25)},t.g0_256=function(e){return i(e,7)^i(e,18)^e>>>3},t.g1_256=function(e){return i(e,17)^i(e,19)^e>>>10}},function(e,t,r){"use strict";var i=r(24),n=r(63),a=r(192),o=r(19),s=i.sum32,c=i.sum32_4,u=i.sum32_5,l=a.ch32,h=a.maj32,d=a.s0_256,p=a.s1_256,f=a.g0_256,m=a.g1_256,g=n.BlockHash,_=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];function v(){if(!(this instanceof v))return new v;g.call(this),this.h=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225],this.k=_,this.W=new Array(64)}i.inherits(v,g),e.exports=v,v.blockSize=512,v.outSize=256,v.hmacStrength=192,v.padLength=64,v.prototype._update=function(e,t){for(var r=this.W,i=0;i<16;i++)r[i]=e[t+i];for(;i=49&&u<=54?u-49+10:u>=17&&u<=22?u-17+10:u,o|=c}return i(!(240&o),"Invalid character in "+e),n}function c(e,t,r,n){for(var a=0,o=0,s=Math.min(e.length,r),c=t;c=49?u-49+10:u>=17?u-17+10:u,i(u>=0&&o"}a.isBN=function(e){return e instanceof a||null!==e&&"object"==typeof e&&e.constructor.wordSize===a.wordSize&&Array.isArray(e.words)},a.max=function(e,t){return e.cmp(t)>0?e:t},a.min=function(e,t){return e.cmp(t)<0?e:t},a.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),i(t===(0|t)&&t>=2&&t<=36);var n=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&n++,16===t?this._parseHex(e,n):this._parseBase(e,t,n),"-"===e[0]&&(this.negative=1),this._strip(),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(i(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initArray=function(e,t,r){if(i("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var n=0;n=0;n-=3)o=e[n]|e[n-1]<<8|e[n-2]<<16,this.words[a]|=o<>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);else if("le"===r)for(n=0,a=0;n>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);return this._strip()},a.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)n=s(e,r,r+6),this.words[i]|=n<>>26-a&4194303,(a+=24)>=26&&(a-=26,i++);r+6!==t&&(n=s(e,t,r+6),this.words[i]|=n<>>26-a&4194303),this._strip()},a.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var i=0,n=1;n<=67108863;n*=t)i++;i--,n=n/t|0;for(var a=e.length-r,o=a%i,s=Math.min(a,a-o)+r,u=0,l=r;l1&&0===this.words[this.length-1];)this.length--;return this._normSign()},a.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},"undefined"!=typeof Symbol&&"function"==typeof Symbol.for?a.prototype[Symbol.for("nodejs.util.inspect.custom")]=l:a.prototype.inspect=l;var h=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],d=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],p=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];a.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var n=0,a=0,o=0;o>>24-n&16777215)||o!==this.length-1?h[6-c.length]+c+r:c+r,(n+=2)>=26&&(n-=26,o--)}for(0!==a&&(r=a.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var u=d[e],l=p[e];r="";var f=this.clone();for(f.negative=0;!f.isZero();){var m=f.modrn(l).toString(e);r=(f=f.idivn(l)).isZero()?m+r:h[u-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}i(!1,"Base should be between 2 and 36")},a.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&i(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},a.prototype.toJSON=function(){return this.toString(16,2)},o&&(a.prototype.toBuffer=function(e,t){return this.toArrayLike(o,e,t)}),a.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)};function f(e,t,r){r.negative=t.negative^e.negative;var i=e.length+t.length|0;r.length=i,i=i-1|0;var n=0|e.words[0],a=0|t.words[0],o=n*a,s=67108863&o,c=o/67108864|0;r.words[0]=s;for(var u=1;u>>26,h=67108863&c,d=Math.min(u,t.length-1),p=Math.max(0,u-e.length+1);p<=d;p++){var f=u-p|0;l+=(o=(n=0|e.words[f])*(a=0|t.words[p])+h)/67108864|0,h=67108863&o}r.words[u]=0|h,c=0|l}return 0!==c?r.words[u]=0|c:r.length--,r._strip()}a.prototype.toArrayLike=function(e,t,r){this._strip();var n=this.byteLength(),a=r||Math.max(1,n);i(n<=a,"byte array longer than desired length"),i(a>0,"Requested array length <= 0");var o=function(e,t){return e.allocUnsafe?e.allocUnsafe(t):new e(t)}(e,a);return this["_toArrayLike"+("le"===t?"LE":"BE")](o,n),o},a.prototype._toArrayLikeLE=function(e,t){for(var r=0,i=0,n=0,a=0;n>8&255),r>16&255),6===a?(r>24&255),i=0,a=0):(i=o>>>24,a+=2)}if(r=0&&(e[r--]=o>>8&255),r>=0&&(e[r--]=o>>16&255),6===a?(r>=0&&(e[r--]=o>>24&255),i=0,a=0):(i=o>>>24,a+=2)}if(r>=0)for(e[r--]=i;r>=0;)e[r--]=0},Math.clz32?a.prototype._countBits=function(e){return 32-Math.clz32(e)}:a.prototype._countBits=function(e){var t=e,r=0;return t>=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},a.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},a.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},a.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},a.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},a.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},a.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},a.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var i=0;ie.length?this.clone().ixor(e):e.clone().ixor(this)},a.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},a.prototype.inotn=function(e){i("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var n=0;n0&&(this.words[n]=~this.words[n]&67108863>>26-r),this._strip()},a.prototype.notn=function(e){return this.clone().inotn(e)},a.prototype.setn=function(e,t){i("number"==typeof e&&e>=0);var r=e/26|0,n=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,i=e):(r=e,i=this);for(var n=0,a=0;a>>26;for(;0!==n&&a>>26;if(this.length=r.length,0!==n)this.words[this.length]=n,this.length++;else if(r!==this)for(;ae.length?this.clone().iadd(e):e.clone().iadd(this)},a.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,i,n=this.cmp(e);if(0===n)return this.negative=0,this.length=1,this.words[0]=0,this;n>0?(r=this,i=e):(r=e,i=this);for(var a=0,o=0;o>26,this.words[o]=67108863&t;for(;0!==a&&o>26,this.words[o]=67108863&t;if(0===a&&o>>13,p=0|o[1],f=8191&p,m=p>>>13,g=0|o[2],_=8191&g,v=g>>>13,y=0|o[3],b=8191&y,E=y>>>13,w=0|o[4],S=8191&w,k=w>>>13,x=0|o[5],M=8191&x,N=x>>>13,j=0|o[6],T=8191&j,R=j>>>13,I=0|o[7],O=8191&I,A=I>>>13,P=0|o[8],D=8191&P,F=P>>>13,C=0|o[9],B=8191&C,z=C>>>13,L=0|s[0],U=8191&L,H=L>>>13,q=0|s[1],K=8191&q,Z=q>>>13,W=0|s[2],X=8191&W,Q=W>>>13,J=0|s[3],V=8191&J,G=J>>>13,Y=0|s[4],$=8191&Y,ee=Y>>>13,te=0|s[5],re=8191&te,ie=te>>>13,ne=0|s[6],ae=8191&ne,oe=ne>>>13,se=0|s[7],ce=8191&se,ue=se>>>13,le=0|s[8],he=8191&le,de=le>>>13,pe=0|s[9],fe=8191&pe,me=pe>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(u+(i=Math.imul(h,U))|0)+((8191&(n=(n=Math.imul(h,H))+Math.imul(d,U)|0))<<13)|0;u=((a=Math.imul(d,H))+(n>>>13)|0)+(ge>>>26)|0,ge&=67108863,i=Math.imul(f,U),n=(n=Math.imul(f,H))+Math.imul(m,U)|0,a=Math.imul(m,H);var _e=(u+(i=i+Math.imul(h,K)|0)|0)+((8191&(n=(n=n+Math.imul(h,Z)|0)+Math.imul(d,K)|0))<<13)|0;u=((a=a+Math.imul(d,Z)|0)+(n>>>13)|0)+(_e>>>26)|0,_e&=67108863,i=Math.imul(_,U),n=(n=Math.imul(_,H))+Math.imul(v,U)|0,a=Math.imul(v,H),i=i+Math.imul(f,K)|0,n=(n=n+Math.imul(f,Z)|0)+Math.imul(m,K)|0,a=a+Math.imul(m,Z)|0;var ve=(u+(i=i+Math.imul(h,X)|0)|0)+((8191&(n=(n=n+Math.imul(h,Q)|0)+Math.imul(d,X)|0))<<13)|0;u=((a=a+Math.imul(d,Q)|0)+(n>>>13)|0)+(ve>>>26)|0,ve&=67108863,i=Math.imul(b,U),n=(n=Math.imul(b,H))+Math.imul(E,U)|0,a=Math.imul(E,H),i=i+Math.imul(_,K)|0,n=(n=n+Math.imul(_,Z)|0)+Math.imul(v,K)|0,a=a+Math.imul(v,Z)|0,i=i+Math.imul(f,X)|0,n=(n=n+Math.imul(f,Q)|0)+Math.imul(m,X)|0,a=a+Math.imul(m,Q)|0;var ye=(u+(i=i+Math.imul(h,V)|0)|0)+((8191&(n=(n=n+Math.imul(h,G)|0)+Math.imul(d,V)|0))<<13)|0;u=((a=a+Math.imul(d,G)|0)+(n>>>13)|0)+(ye>>>26)|0,ye&=67108863,i=Math.imul(S,U),n=(n=Math.imul(S,H))+Math.imul(k,U)|0,a=Math.imul(k,H),i=i+Math.imul(b,K)|0,n=(n=n+Math.imul(b,Z)|0)+Math.imul(E,K)|0,a=a+Math.imul(E,Z)|0,i=i+Math.imul(_,X)|0,n=(n=n+Math.imul(_,Q)|0)+Math.imul(v,X)|0,a=a+Math.imul(v,Q)|0,i=i+Math.imul(f,V)|0,n=(n=n+Math.imul(f,G)|0)+Math.imul(m,V)|0,a=a+Math.imul(m,G)|0;var be=(u+(i=i+Math.imul(h,$)|0)|0)+((8191&(n=(n=n+Math.imul(h,ee)|0)+Math.imul(d,$)|0))<<13)|0;u=((a=a+Math.imul(d,ee)|0)+(n>>>13)|0)+(be>>>26)|0,be&=67108863,i=Math.imul(M,U),n=(n=Math.imul(M,H))+Math.imul(N,U)|0,a=Math.imul(N,H),i=i+Math.imul(S,K)|0,n=(n=n+Math.imul(S,Z)|0)+Math.imul(k,K)|0,a=a+Math.imul(k,Z)|0,i=i+Math.imul(b,X)|0,n=(n=n+Math.imul(b,Q)|0)+Math.imul(E,X)|0,a=a+Math.imul(E,Q)|0,i=i+Math.imul(_,V)|0,n=(n=n+Math.imul(_,G)|0)+Math.imul(v,V)|0,a=a+Math.imul(v,G)|0,i=i+Math.imul(f,$)|0,n=(n=n+Math.imul(f,ee)|0)+Math.imul(m,$)|0,a=a+Math.imul(m,ee)|0;var Ee=(u+(i=i+Math.imul(h,re)|0)|0)+((8191&(n=(n=n+Math.imul(h,ie)|0)+Math.imul(d,re)|0))<<13)|0;u=((a=a+Math.imul(d,ie)|0)+(n>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,i=Math.imul(T,U),n=(n=Math.imul(T,H))+Math.imul(R,U)|0,a=Math.imul(R,H),i=i+Math.imul(M,K)|0,n=(n=n+Math.imul(M,Z)|0)+Math.imul(N,K)|0,a=a+Math.imul(N,Z)|0,i=i+Math.imul(S,X)|0,n=(n=n+Math.imul(S,Q)|0)+Math.imul(k,X)|0,a=a+Math.imul(k,Q)|0,i=i+Math.imul(b,V)|0,n=(n=n+Math.imul(b,G)|0)+Math.imul(E,V)|0,a=a+Math.imul(E,G)|0,i=i+Math.imul(_,$)|0,n=(n=n+Math.imul(_,ee)|0)+Math.imul(v,$)|0,a=a+Math.imul(v,ee)|0,i=i+Math.imul(f,re)|0,n=(n=n+Math.imul(f,ie)|0)+Math.imul(m,re)|0,a=a+Math.imul(m,ie)|0;var we=(u+(i=i+Math.imul(h,ae)|0)|0)+((8191&(n=(n=n+Math.imul(h,oe)|0)+Math.imul(d,ae)|0))<<13)|0;u=((a=a+Math.imul(d,oe)|0)+(n>>>13)|0)+(we>>>26)|0,we&=67108863,i=Math.imul(O,U),n=(n=Math.imul(O,H))+Math.imul(A,U)|0,a=Math.imul(A,H),i=i+Math.imul(T,K)|0,n=(n=n+Math.imul(T,Z)|0)+Math.imul(R,K)|0,a=a+Math.imul(R,Z)|0,i=i+Math.imul(M,X)|0,n=(n=n+Math.imul(M,Q)|0)+Math.imul(N,X)|0,a=a+Math.imul(N,Q)|0,i=i+Math.imul(S,V)|0,n=(n=n+Math.imul(S,G)|0)+Math.imul(k,V)|0,a=a+Math.imul(k,G)|0,i=i+Math.imul(b,$)|0,n=(n=n+Math.imul(b,ee)|0)+Math.imul(E,$)|0,a=a+Math.imul(E,ee)|0,i=i+Math.imul(_,re)|0,n=(n=n+Math.imul(_,ie)|0)+Math.imul(v,re)|0,a=a+Math.imul(v,ie)|0,i=i+Math.imul(f,ae)|0,n=(n=n+Math.imul(f,oe)|0)+Math.imul(m,ae)|0,a=a+Math.imul(m,oe)|0;var Se=(u+(i=i+Math.imul(h,ce)|0)|0)+((8191&(n=(n=n+Math.imul(h,ue)|0)+Math.imul(d,ce)|0))<<13)|0;u=((a=a+Math.imul(d,ue)|0)+(n>>>13)|0)+(Se>>>26)|0,Se&=67108863,i=Math.imul(D,U),n=(n=Math.imul(D,H))+Math.imul(F,U)|0,a=Math.imul(F,H),i=i+Math.imul(O,K)|0,n=(n=n+Math.imul(O,Z)|0)+Math.imul(A,K)|0,a=a+Math.imul(A,Z)|0,i=i+Math.imul(T,X)|0,n=(n=n+Math.imul(T,Q)|0)+Math.imul(R,X)|0,a=a+Math.imul(R,Q)|0,i=i+Math.imul(M,V)|0,n=(n=n+Math.imul(M,G)|0)+Math.imul(N,V)|0,a=a+Math.imul(N,G)|0,i=i+Math.imul(S,$)|0,n=(n=n+Math.imul(S,ee)|0)+Math.imul(k,$)|0,a=a+Math.imul(k,ee)|0,i=i+Math.imul(b,re)|0,n=(n=n+Math.imul(b,ie)|0)+Math.imul(E,re)|0,a=a+Math.imul(E,ie)|0,i=i+Math.imul(_,ae)|0,n=(n=n+Math.imul(_,oe)|0)+Math.imul(v,ae)|0,a=a+Math.imul(v,oe)|0,i=i+Math.imul(f,ce)|0,n=(n=n+Math.imul(f,ue)|0)+Math.imul(m,ce)|0,a=a+Math.imul(m,ue)|0;var ke=(u+(i=i+Math.imul(h,he)|0)|0)+((8191&(n=(n=n+Math.imul(h,de)|0)+Math.imul(d,he)|0))<<13)|0;u=((a=a+Math.imul(d,de)|0)+(n>>>13)|0)+(ke>>>26)|0,ke&=67108863,i=Math.imul(B,U),n=(n=Math.imul(B,H))+Math.imul(z,U)|0,a=Math.imul(z,H),i=i+Math.imul(D,K)|0,n=(n=n+Math.imul(D,Z)|0)+Math.imul(F,K)|0,a=a+Math.imul(F,Z)|0,i=i+Math.imul(O,X)|0,n=(n=n+Math.imul(O,Q)|0)+Math.imul(A,X)|0,a=a+Math.imul(A,Q)|0,i=i+Math.imul(T,V)|0,n=(n=n+Math.imul(T,G)|0)+Math.imul(R,V)|0,a=a+Math.imul(R,G)|0,i=i+Math.imul(M,$)|0,n=(n=n+Math.imul(M,ee)|0)+Math.imul(N,$)|0,a=a+Math.imul(N,ee)|0,i=i+Math.imul(S,re)|0,n=(n=n+Math.imul(S,ie)|0)+Math.imul(k,re)|0,a=a+Math.imul(k,ie)|0,i=i+Math.imul(b,ae)|0,n=(n=n+Math.imul(b,oe)|0)+Math.imul(E,ae)|0,a=a+Math.imul(E,oe)|0,i=i+Math.imul(_,ce)|0,n=(n=n+Math.imul(_,ue)|0)+Math.imul(v,ce)|0,a=a+Math.imul(v,ue)|0,i=i+Math.imul(f,he)|0,n=(n=n+Math.imul(f,de)|0)+Math.imul(m,he)|0,a=a+Math.imul(m,de)|0;var xe=(u+(i=i+Math.imul(h,fe)|0)|0)+((8191&(n=(n=n+Math.imul(h,me)|0)+Math.imul(d,fe)|0))<<13)|0;u=((a=a+Math.imul(d,me)|0)+(n>>>13)|0)+(xe>>>26)|0,xe&=67108863,i=Math.imul(B,K),n=(n=Math.imul(B,Z))+Math.imul(z,K)|0,a=Math.imul(z,Z),i=i+Math.imul(D,X)|0,n=(n=n+Math.imul(D,Q)|0)+Math.imul(F,X)|0,a=a+Math.imul(F,Q)|0,i=i+Math.imul(O,V)|0,n=(n=n+Math.imul(O,G)|0)+Math.imul(A,V)|0,a=a+Math.imul(A,G)|0,i=i+Math.imul(T,$)|0,n=(n=n+Math.imul(T,ee)|0)+Math.imul(R,$)|0,a=a+Math.imul(R,ee)|0,i=i+Math.imul(M,re)|0,n=(n=n+Math.imul(M,ie)|0)+Math.imul(N,re)|0,a=a+Math.imul(N,ie)|0,i=i+Math.imul(S,ae)|0,n=(n=n+Math.imul(S,oe)|0)+Math.imul(k,ae)|0,a=a+Math.imul(k,oe)|0,i=i+Math.imul(b,ce)|0,n=(n=n+Math.imul(b,ue)|0)+Math.imul(E,ce)|0,a=a+Math.imul(E,ue)|0,i=i+Math.imul(_,he)|0,n=(n=n+Math.imul(_,de)|0)+Math.imul(v,he)|0,a=a+Math.imul(v,de)|0;var Me=(u+(i=i+Math.imul(f,fe)|0)|0)+((8191&(n=(n=n+Math.imul(f,me)|0)+Math.imul(m,fe)|0))<<13)|0;u=((a=a+Math.imul(m,me)|0)+(n>>>13)|0)+(Me>>>26)|0,Me&=67108863,i=Math.imul(B,X),n=(n=Math.imul(B,Q))+Math.imul(z,X)|0,a=Math.imul(z,Q),i=i+Math.imul(D,V)|0,n=(n=n+Math.imul(D,G)|0)+Math.imul(F,V)|0,a=a+Math.imul(F,G)|0,i=i+Math.imul(O,$)|0,n=(n=n+Math.imul(O,ee)|0)+Math.imul(A,$)|0,a=a+Math.imul(A,ee)|0,i=i+Math.imul(T,re)|0,n=(n=n+Math.imul(T,ie)|0)+Math.imul(R,re)|0,a=a+Math.imul(R,ie)|0,i=i+Math.imul(M,ae)|0,n=(n=n+Math.imul(M,oe)|0)+Math.imul(N,ae)|0,a=a+Math.imul(N,oe)|0,i=i+Math.imul(S,ce)|0,n=(n=n+Math.imul(S,ue)|0)+Math.imul(k,ce)|0,a=a+Math.imul(k,ue)|0,i=i+Math.imul(b,he)|0,n=(n=n+Math.imul(b,de)|0)+Math.imul(E,he)|0,a=a+Math.imul(E,de)|0;var Ne=(u+(i=i+Math.imul(_,fe)|0)|0)+((8191&(n=(n=n+Math.imul(_,me)|0)+Math.imul(v,fe)|0))<<13)|0;u=((a=a+Math.imul(v,me)|0)+(n>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,i=Math.imul(B,V),n=(n=Math.imul(B,G))+Math.imul(z,V)|0,a=Math.imul(z,G),i=i+Math.imul(D,$)|0,n=(n=n+Math.imul(D,ee)|0)+Math.imul(F,$)|0,a=a+Math.imul(F,ee)|0,i=i+Math.imul(O,re)|0,n=(n=n+Math.imul(O,ie)|0)+Math.imul(A,re)|0,a=a+Math.imul(A,ie)|0,i=i+Math.imul(T,ae)|0,n=(n=n+Math.imul(T,oe)|0)+Math.imul(R,ae)|0,a=a+Math.imul(R,oe)|0,i=i+Math.imul(M,ce)|0,n=(n=n+Math.imul(M,ue)|0)+Math.imul(N,ce)|0,a=a+Math.imul(N,ue)|0,i=i+Math.imul(S,he)|0,n=(n=n+Math.imul(S,de)|0)+Math.imul(k,he)|0,a=a+Math.imul(k,de)|0;var je=(u+(i=i+Math.imul(b,fe)|0)|0)+((8191&(n=(n=n+Math.imul(b,me)|0)+Math.imul(E,fe)|0))<<13)|0;u=((a=a+Math.imul(E,me)|0)+(n>>>13)|0)+(je>>>26)|0,je&=67108863,i=Math.imul(B,$),n=(n=Math.imul(B,ee))+Math.imul(z,$)|0,a=Math.imul(z,ee),i=i+Math.imul(D,re)|0,n=(n=n+Math.imul(D,ie)|0)+Math.imul(F,re)|0,a=a+Math.imul(F,ie)|0,i=i+Math.imul(O,ae)|0,n=(n=n+Math.imul(O,oe)|0)+Math.imul(A,ae)|0,a=a+Math.imul(A,oe)|0,i=i+Math.imul(T,ce)|0,n=(n=n+Math.imul(T,ue)|0)+Math.imul(R,ce)|0,a=a+Math.imul(R,ue)|0,i=i+Math.imul(M,he)|0,n=(n=n+Math.imul(M,de)|0)+Math.imul(N,he)|0,a=a+Math.imul(N,de)|0;var Te=(u+(i=i+Math.imul(S,fe)|0)|0)+((8191&(n=(n=n+Math.imul(S,me)|0)+Math.imul(k,fe)|0))<<13)|0;u=((a=a+Math.imul(k,me)|0)+(n>>>13)|0)+(Te>>>26)|0,Te&=67108863,i=Math.imul(B,re),n=(n=Math.imul(B,ie))+Math.imul(z,re)|0,a=Math.imul(z,ie),i=i+Math.imul(D,ae)|0,n=(n=n+Math.imul(D,oe)|0)+Math.imul(F,ae)|0,a=a+Math.imul(F,oe)|0,i=i+Math.imul(O,ce)|0,n=(n=n+Math.imul(O,ue)|0)+Math.imul(A,ce)|0,a=a+Math.imul(A,ue)|0,i=i+Math.imul(T,he)|0,n=(n=n+Math.imul(T,de)|0)+Math.imul(R,he)|0,a=a+Math.imul(R,de)|0;var Re=(u+(i=i+Math.imul(M,fe)|0)|0)+((8191&(n=(n=n+Math.imul(M,me)|0)+Math.imul(N,fe)|0))<<13)|0;u=((a=a+Math.imul(N,me)|0)+(n>>>13)|0)+(Re>>>26)|0,Re&=67108863,i=Math.imul(B,ae),n=(n=Math.imul(B,oe))+Math.imul(z,ae)|0,a=Math.imul(z,oe),i=i+Math.imul(D,ce)|0,n=(n=n+Math.imul(D,ue)|0)+Math.imul(F,ce)|0,a=a+Math.imul(F,ue)|0,i=i+Math.imul(O,he)|0,n=(n=n+Math.imul(O,de)|0)+Math.imul(A,he)|0,a=a+Math.imul(A,de)|0;var Ie=(u+(i=i+Math.imul(T,fe)|0)|0)+((8191&(n=(n=n+Math.imul(T,me)|0)+Math.imul(R,fe)|0))<<13)|0;u=((a=a+Math.imul(R,me)|0)+(n>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,i=Math.imul(B,ce),n=(n=Math.imul(B,ue))+Math.imul(z,ce)|0,a=Math.imul(z,ue),i=i+Math.imul(D,he)|0,n=(n=n+Math.imul(D,de)|0)+Math.imul(F,he)|0,a=a+Math.imul(F,de)|0;var Oe=(u+(i=i+Math.imul(O,fe)|0)|0)+((8191&(n=(n=n+Math.imul(O,me)|0)+Math.imul(A,fe)|0))<<13)|0;u=((a=a+Math.imul(A,me)|0)+(n>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,i=Math.imul(B,he),n=(n=Math.imul(B,de))+Math.imul(z,he)|0,a=Math.imul(z,de);var Ae=(u+(i=i+Math.imul(D,fe)|0)|0)+((8191&(n=(n=n+Math.imul(D,me)|0)+Math.imul(F,fe)|0))<<13)|0;u=((a=a+Math.imul(F,me)|0)+(n>>>13)|0)+(Ae>>>26)|0,Ae&=67108863;var Pe=(u+(i=Math.imul(B,fe))|0)+((8191&(n=(n=Math.imul(B,me))+Math.imul(z,fe)|0))<<13)|0;return u=((a=Math.imul(z,me))+(n>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,c[0]=ge,c[1]=_e,c[2]=ve,c[3]=ye,c[4]=be,c[5]=Ee,c[6]=we,c[7]=Se,c[8]=ke,c[9]=xe,c[10]=Me,c[11]=Ne,c[12]=je,c[13]=Te,c[14]=Re,c[15]=Ie,c[16]=Oe,c[17]=Ae,c[18]=Pe,0!==u&&(c[19]=u,r.length++),r};function g(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var i=0,n=0,a=0;a>>26)|0)>>>26,o&=67108863}r.words[a]=s,i=o,o=n}return 0!==i?r.words[a]=i:r.length--,r._strip()}function _(e,t,r){return g(e,t,r)}function v(e,t){this.x=e,this.y=t}Math.imul||(m=f),a.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?m(this,e,t):r<63?f(this,e,t):r<1024?g(this,e,t):_(this,e,t)},v.prototype.makeRBT=function(e){for(var t=new Array(e),r=a.prototype._countBits(e)-1,i=0;i>=1;return i},v.prototype.permute=function(e,t,r,i,n,a){for(var o=0;o>>=1)n++;return 1<>>=13,r[2*o+1]=8191&a,a>>>=13;for(o=2*t;o>=26,r+=a/67108864|0,r+=o>>>26,this.words[n]=67108863&o}return 0!==r&&(this.words[n]=r,this.length++),t?this.ineg():this},a.prototype.muln=function(e){return this.clone().imuln(e)},a.prototype.sqr=function(){return this.mul(this)},a.prototype.isqr=function(){return this.imul(this.clone())},a.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>n&1}return t}(e);if(0===t.length)return new a(1);for(var r=this,i=0;i=0);var t,r=e%26,n=(e-r)/26,a=67108863>>>26-r<<26-r;if(0!==r){var o=0;for(t=0;t>>26-r}o&&(this.words[t]=o,this.length++)}if(0!==n){for(t=this.length-1;t>=0;t--)this.words[t+n]=this.words[t];for(t=0;t=0),n=t?(t-t%26)/26:0;var a=e%26,o=Math.min((e-a)/26,this.length),s=67108863^67108863>>>a<o)for(this.length-=o,u=0;u=0&&(0!==l||u>=n);u--){var h=0|this.words[u];this.words[u]=l<<26-a|h>>>a,l=h&s}return c&&0!==l&&(c.words[c.length++]=l),0===this.length&&(this.words[0]=0,this.length=1),this._strip()},a.prototype.ishrn=function(e,t,r){return i(0===this.negative),this.iushrn(e,t,r)},a.prototype.shln=function(e){return this.clone().ishln(e)},a.prototype.ushln=function(e){return this.clone().iushln(e)},a.prototype.shrn=function(e){return this.clone().ishrn(e)},a.prototype.ushrn=function(e){return this.clone().iushrn(e)},a.prototype.testn=function(e){i("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,n=1<=0);var t=e%26,r=(e-t)/26;if(i(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var n=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},a.prototype.isubn=function(e){if(i("number"==typeof e),i(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(c/67108864|0),this.words[n+r]=67108863&a}for(;n>26,this.words[n+r]=67108863&a;if(0===s)return this._strip();for(i(-1===s),s=0,n=0;n>26,this.words[n]=67108863&a;return this.negative=1,this._strip()},a.prototype._wordDiv=function(e,t){var r=(this.length,e.length),i=this.clone(),n=e,o=0|n.words[n.length-1];0!==(r=26-this._countBits(o))&&(n=n.ushln(r),i.iushln(r),o=0|n.words[n.length-1]);var s,c=i.length-n.length;if("mod"!==t){(s=new a(null)).length=c+1,s.words=new Array(s.length);for(var u=0;u=0;h--){var d=67108864*(0|i.words[n.length+h])+(0|i.words[n.length+h-1]);for(d=Math.min(d/o|0,67108863),i._ishlnsubmul(n,d,h);0!==i.negative;)d--,i.negative=0,i._ishlnsubmul(n,1,h),i.isZero()||(i.negative^=1);s&&(s.words[h]=d)}return s&&s._strip(),i._strip(),"div"!==t&&0!==r&&i.iushrn(r),{div:s||null,mod:i}},a.prototype.divmod=function(e,t,r){return i(!e.isZero()),this.isZero()?{div:new a(0),mod:new a(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(n=s.div.neg()),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.iadd(e)),{div:n,mod:o}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(n=s.div.neg()),{div:n,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.isub(e)),{div:s.div,mod:o}):e.length>this.length||this.cmp(e)<0?{div:new a(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new a(this.modrn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new a(this.modrn(e.words[0]))}:this._wordDiv(e,t);var n,o,s},a.prototype.div=function(e){return this.divmod(e,"div",!1).div},a.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},a.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},a.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,i=e.ushrn(1),n=e.andln(1),a=r.cmp(i);return a<0||1===n&&0===a?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},a.prototype.modrn=function(e){var t=e<0;t&&(e=-e),i(e<=67108863);for(var r=(1<<26)%e,n=0,a=this.length-1;a>=0;a--)n=(r*n+(0|this.words[a]))%e;return t?-n:n},a.prototype.modn=function(e){return this.modrn(e)},a.prototype.idivn=function(e){var t=e<0;t&&(e=-e),i(e<=67108863);for(var r=0,n=this.length-1;n>=0;n--){var a=(0|this.words[n])+67108864*r;this.words[n]=a/e|0,r=a%e}return this._strip(),t?this.ineg():this},a.prototype.divn=function(e){return this.clone().idivn(e)},a.prototype.egcd=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n=new a(1),o=new a(0),s=new a(0),c=new a(1),u=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++u;for(var l=r.clone(),h=t.clone();!t.isZero();){for(var d=0,p=1;0==(t.words[0]&p)&&d<26;++d,p<<=1);if(d>0)for(t.iushrn(d);d-- >0;)(n.isOdd()||o.isOdd())&&(n.iadd(l),o.isub(h)),n.iushrn(1),o.iushrn(1);for(var f=0,m=1;0==(r.words[0]&m)&&f<26;++f,m<<=1);if(f>0)for(r.iushrn(f);f-- >0;)(s.isOdd()||c.isOdd())&&(s.iadd(l),c.isub(h)),s.iushrn(1),c.iushrn(1);t.cmp(r)>=0?(t.isub(r),n.isub(s),o.isub(c)):(r.isub(t),s.isub(n),c.isub(o))}return{a:s,b:c,gcd:r.iushln(u)}},a.prototype._invmp=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n,o=new a(1),s=new a(0),c=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var u=0,l=1;0==(t.words[0]&l)&&u<26;++u,l<<=1);if(u>0)for(t.iushrn(u);u-- >0;)o.isOdd()&&o.iadd(c),o.iushrn(1);for(var h=0,d=1;0==(r.words[0]&d)&&h<26;++h,d<<=1);if(h>0)for(r.iushrn(h);h-- >0;)s.isOdd()&&s.iadd(c),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),o.isub(s)):(r.isub(t),s.isub(o))}return(n=0===t.cmpn(1)?o:s).cmpn(0)<0&&n.iadd(e),n},a.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var i=0;t.isEven()&&r.isEven();i++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var n=t.cmp(r);if(n<0){var a=t;t=r,r=a}else if(0===n||0===r.cmpn(1))break;t.isub(r)}return r.iushln(i)},a.prototype.invm=function(e){return this.egcd(e).a.umod(e)},a.prototype.isEven=function(){return 0==(1&this.words[0])},a.prototype.isOdd=function(){return 1==(1&this.words[0])},a.prototype.andln=function(e){return this.words[0]&e},a.prototype.bincn=function(e){i("number"==typeof e);var t=e%26,r=(e-t)/26,n=1<>>26,s&=67108863,this.words[o]=s}return 0!==a&&(this.words[o]=a,this.length++),this},a.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},a.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this._strip(),this.length>1)t=1;else{r&&(e=-e),i(e<=67108863,"Number is too big");var n=0|this.words[0];t=n===e?0:ne.length)return 1;if(this.length=0;r--){var i=0|this.words[r],n=0|e.words[r];if(i!==n){in&&(t=1);break}}return t},a.prototype.gtn=function(e){return 1===this.cmpn(e)},a.prototype.gt=function(e){return 1===this.cmp(e)},a.prototype.gten=function(e){return this.cmpn(e)>=0},a.prototype.gte=function(e){return this.cmp(e)>=0},a.prototype.ltn=function(e){return-1===this.cmpn(e)},a.prototype.lt=function(e){return-1===this.cmp(e)},a.prototype.lten=function(e){return this.cmpn(e)<=0},a.prototype.lte=function(e){return this.cmp(e)<=0},a.prototype.eqn=function(e){return 0===this.cmpn(e)},a.prototype.eq=function(e){return 0===this.cmp(e)},a.red=function(e){return new x(e)},a.prototype.toRed=function(e){return i(!this.red,"Already a number in reduction context"),i(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},a.prototype.fromRed=function(){return i(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},a.prototype._forceRed=function(e){return this.red=e,this},a.prototype.forceRed=function(e){return i(!this.red,"Already a number in reduction context"),this._forceRed(e)},a.prototype.redAdd=function(e){return i(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},a.prototype.redIAdd=function(e){return i(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},a.prototype.redSub=function(e){return i(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},a.prototype.redISub=function(e){return i(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},a.prototype.redShl=function(e){return i(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},a.prototype.redMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},a.prototype.redIMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},a.prototype.redSqr=function(){return i(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},a.prototype.redISqr=function(){return i(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},a.prototype.redSqrt=function(){return i(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},a.prototype.redInvm=function(){return i(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},a.prototype.redNeg=function(){return i(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},a.prototype.redPow=function(e){return i(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var y={k256:null,p224:null,p192:null,p25519:null};function b(e,t){this.name=e,this.p=new a(t,16),this.n=this.p.bitLength(),this.k=new a(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function E(){b.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function w(){b.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function S(){b.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function k(){b.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function x(e){if("string"==typeof e){var t=a._prime(e);this.m=t.p,this.prime=t}else i(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function M(e){x.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new a(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}b.prototype._tmp=function(){var e=new a(null);return e.words=new Array(Math.ceil(this.n/13)),e},b.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var i=t0?r.isub(this.p):r._strip(),r},b.prototype.split=function(e,t){e.iushrn(this.n,0,t)},b.prototype.imulK=function(e){return e.imul(this.k)},n(E,b),E.prototype.split=function(e,t){for(var r=Math.min(e.length,9),i=0;i>>22,n=a}n>>>=22,e.words[i-10]=n,0===n&&e.length>10?e.length-=10:e.length-=9},E.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=n,t=i}return 0!==t&&(e.words[e.length++]=t),e},a._prime=function(e){if(y[e])return y[e];var t;if("k256"===e)t=new E;else if("p224"===e)t=new w;else if("p192"===e)t=new S;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new k}return y[e]=t,t},x.prototype._verify1=function(e){i(0===e.negative,"red works only with positives"),i(e.red,"red works only with red numbers")},x.prototype._verify2=function(e,t){i(0==(e.negative|t.negative),"red works only with positives"),i(e.red&&e.red===t.red,"red works only with red numbers")},x.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):(u(e,e.umod(this.m)._forceRed(this)),e)},x.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},x.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},x.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},x.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},x.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},x.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},x.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},x.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},x.prototype.isqr=function(e){return this.imul(e,e.clone())},x.prototype.sqr=function(e){return this.mul(e,e)},x.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(i(t%2==1),3===t){var r=this.m.add(new a(1)).iushrn(2);return this.pow(e,r)}for(var n=this.m.subn(1),o=0;!n.isZero()&&0===n.andln(1);)o++,n.iushrn(1);i(!n.isZero());var s=new a(1).toRed(this),c=s.redNeg(),u=this.m.subn(1).iushrn(1),l=this.m.bitLength();for(l=new a(2*l*l).toRed(this);0!==this.pow(l,u).cmp(c);)l.redIAdd(c);for(var h=this.pow(l,n),d=this.pow(e,n.addn(1).iushrn(1)),p=this.pow(e,n),f=o;0!==p.cmp(s);){for(var m=p,g=0;0!==m.cmp(s);g++)m=m.redSqr();i(g=0;i--){for(var u=t.words[i],l=c-1;l>=0;l--){var h=u>>l&1;n!==r[0]&&(n=this.sqr(n)),0!==h||0!==o?(o<<=1,o|=h,(4===++s||0===i&&0===l)&&(n=this.mul(n,r[o]),s=0,o=0)):s=0}c=26}return n},x.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},x.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},a.mont=function(e){return new M(e)},n(M,x),M.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},M.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},M.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),a=n;return n.cmp(this.m)>=0?a=n.isub(this.m):n.cmpn(0)<0&&(a=n.iadd(this.m)),a._forceRed(this)},M.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new a(0)._forceRed(this);var r=e.mul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),o=n;return n.cmp(this.m)>=0?o=n.isub(this.m):n.cmpn(0)<0&&(o=n.iadd(this.m)),o._forceRed(this)},M.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(22)(e))},function(e,t,r){var i=r(0),n=r(65).Reporter,a=r(2).Buffer;function o(e,t){n.call(this,t),a.isBuffer(e)?(this.base=e,this.offset=0,this.length=e.length):this.error("Input not Buffer")}function s(e,t){if(Array.isArray(e))this.length=0,this.value=e.map((function(e){return e instanceof s||(e=new s(e,t)),this.length+=e.length,e}),this);else if("number"==typeof e){if(!(0<=e&&e<=255))return t.error("non-byte EncoderBuffer value");this.value=e,this.length=1}else if("string"==typeof e)this.value=e,this.length=a.byteLength(e);else{if(!a.isBuffer(e))return t.error("Unsupported type: "+typeof e);this.value=e,this.length=e.length}}i(o,n),t.DecoderBuffer=o,o.prototype.save=function(){return{offset:this.offset,reporter:n.prototype.save.call(this)}},o.prototype.restore=function(e){var t=new o(this.base);return t.offset=e.offset,t.length=this.offset,this.offset=e.offset,n.prototype.restore.call(this,e.reporter),t},o.prototype.isEmpty=function(){return this.offset===this.length},o.prototype.readUInt8=function(e){return this.offset+1<=this.length?this.base.readUInt8(this.offset++,!0):this.error(e||"DecoderBuffer overrun")},o.prototype.skip=function(e,t){if(!(this.offset+e<=this.length))return this.error(t||"DecoderBuffer overrun");var r=new o(this.base);return r._reporterState=this._reporterState,r.offset=this.offset,r.length=this.offset+e,this.offset+=e,r},o.prototype.raw=function(e){return this.base.slice(e?e.offset:this.offset,this.length)},t.EncoderBuffer=s,s.prototype.join=function(e,t){return e||(e=new a(this.length)),t||(t=0),0===this.length||(Array.isArray(this.value)?this.value.forEach((function(r){r.join(e,t),t+=r.length})):("number"==typeof this.value?e[t]=this.value:"string"==typeof this.value?e.write(this.value,t):a.isBuffer(this.value)&&this.value.copy(e,t),t+=this.length)),e}},function(e,t,r){var i=t;i._reverse=function(e){var t={};return Object.keys(e).forEach((function(r){(0|r)==r&&(r|=0);var i=e[r];t[i]=r})),t},i.der=r(360)},function(e,t,r){var i=r(0),n=r(64),a=n.base,o=n.bignum,s=n.constants.der;function c(e){this.enc="der",this.name=e.name,this.entity=e,this.tree=new u,this.tree._init(e.body)}function u(e){a.Node.call(this,"der",e)}function l(e,t){var r=e.readUInt8(t);if(e.isError(r))return r;var i=s.tagClass[r>>6],n=0==(32&r);if(31==(31&r)){var a=r;for(r=0;128==(128&a);){if(a=e.readUInt8(t),e.isError(a))return a;r<<=7,r|=127&a}}else r&=31;return{cls:i,primitive:n,tag:r,tagStr:s.tag[r]}}function h(e,t,r){var i=e.readUInt8(r);if(e.isError(i))return i;if(!t&&128===i)return null;if(0==(128&i))return i;var n=127&i;if(n>4)return e.error("length octect is too long");i=0;for(var a=0;a=31)return i.error("Multi-octet tag encoding unsupported");t||(n|=32);return n|=s.tagClassByName[r||"universal"]<<6}(e,t,r,this.reporter);if(i.length<128)return(a=new n(2))[0]=o,a[1]=i.length,this._createEncoderBuffer([a,i]);for(var c=1,u=i.length;u>=256;u>>=8)c++;(a=new n(2+c))[0]=o,a[1]=128|c;u=1+c;for(var l=i.length;l>0;u--,l>>=8)a[u]=255&l;return this._createEncoderBuffer([a,i])},u.prototype._encodeStr=function(e,t){if("bitstr"===t)return this._createEncoderBuffer([0|e.unused,e.data]);if("bmpstr"===t){for(var r=new n(2*e.length),i=0;i=40)return this.reporter.error("Second objid identifier OOB");e.splice(0,2,40*e[0]+e[1])}var a=0;for(i=0;i=128;o>>=7)a++}var s=new n(a),c=s.length-1;for(i=e.length-1;i>=0;i--){o=e[i];for(s[c--]=127&o;(o>>=7)>0;)s[c--]=128|127&o}return this._createEncoderBuffer(s)},u.prototype._encodeTime=function(e,t){var r,i=new Date(e);return"gentime"===t?r=[l(i.getFullYear()),l(i.getUTCMonth()+1),l(i.getUTCDate()),l(i.getUTCHours()),l(i.getUTCMinutes()),l(i.getUTCSeconds()),"Z"].join(""):"utctime"===t?r=[l(i.getFullYear()%100),l(i.getUTCMonth()+1),l(i.getUTCDate()),l(i.getUTCHours()),l(i.getUTCMinutes()),l(i.getUTCSeconds()),"Z"].join(""):this.reporter.error("Encoding "+t+" time is not supported yet"),this._encodeStr(r,"octstr")},u.prototype._encodeNull=function(){return this._createEncoderBuffer("")},u.prototype._encodeInt=function(e,t){if("string"==typeof e){if(!t)return this.reporter.error("String int or enum given, but no values map");if(!t.hasOwnProperty(e))return this.reporter.error("Values map doesn't contain: "+JSON.stringify(e));e=t[e]}if("number"!=typeof e&&!n.isBuffer(e)){var r=e.toArray();!e.sign&&128&r[0]&&r.unshift(0),e=new n(r)}if(n.isBuffer(e)){var i=e.length;0===e.length&&i++;var a=new n(i);return e.copy(a),0===e.length&&(a[0]=0),this._createEncoderBuffer(a)}if(e<128)return this._createEncoderBuffer(e);if(e<256)return this._createEncoderBuffer([0,e]);i=1;for(var o=e;o>=256;o>>=8)i++;for(o=(a=new Array(i)).length-1;o>=0;o--)a[o]=255&e,e>>=8;return 128&a[0]&&a.unshift(0),this._createEncoderBuffer(new n(a))},u.prototype._encodeBool=function(e){return this._createEncoderBuffer(e?255:0)},u.prototype._use=function(e,t){return"function"==typeof e&&(e=e(t)),e._getEncoder("der").tree},u.prototype._skipDefault=function(e,t,r){var i,n=this._baseState;if(null===n.default)return!1;var a=e.join();if(void 0===n.defaultBuffer&&(n.defaultBuffer=this._encodeValue(n.default,t,r).join()),a.length!==n.defaultBuffer.length)return!1;for(i=0;i{t(e)}).catch(e=>{t(void 0,e)}):e().then(e=>{t(e)}).catch(e=>{t(void 0,e)})}),1)}return new Promise((function(t,r){o.TASK_QUEUE.push(e,(function(e,i){void 0!==i?r(i):t(e)}))}))}static _getHttpAgent(){if(!o.HTTP_AGENT){let e=r(52);o.HTTP_AGENT=new e.Agent({keepAlive:!0})}return o.HTTP_AGENT}static _getHttpsAgent(){if(!o.HTTPS_AGENT){let e=r(85);o.HTTPS_AGENT=new e.Agent({keepAlive:!0})}return o.HTTPS_AGENT}static _parseXhrResponseHeaders(e){let t={},r=e.trim().split(/[\r\n]+/);for(let e of r){let r=e.split(": ");t[r[0]]=r[1]}return t}}o.DEFAULT_REQUEST={method:"GET",requestApi:"fetch",resolveWithFullResponse:!1,rejectUnauthorized:!0},o.digestAuthRequest=function(e,t,i,n){var a=this;if(void 0===o)var o=r(518);this.scheme=null,this.nonce=null,this.realm=null,this.qop=null,this.response=null,this.opaque=null,this.nc=1,this.cnonce=null,this.timeout=6e4,this.loggingOn=!1,this.post=!1,"post"!==e.toLowerCase()&&"put"!==e.toLowerCase()||(this.post=!0),this.request=function(e,t,r){if(r)try{a.data=r instanceof Uint8Array||"string"==typeof r?r:JSON.stringify(r)}catch(e){throw console.error(e),e}a.successFn=e,a.errorFn=t,a.nonce?a.makeAuthenticatedRequest():a.makeUnauthenticatedRequest(a.data)},this.makeUnauthenticatedRequest=function(r){a.firstRequest=new XMLHttpRequest,a.firstRequest.open(e,t,!0),a.firstRequest.timeout=a.timeout,a.post&&r&&("string"==typeof r?a.firstRequest.setRequestHeader("Content-type","text/plain"):a.firstRequest.responseType="arraybuffer"),a.firstRequest.onreadystatechange=function(){if(2===a.firstRequest.readyState){var e,i=a.firstRequest.getAllResponseHeaders();i=i.split("\n");for(var n=0;n0&&(a.isJson(a.firstRequest.responseText),a.successFn(a.firstRequest)):a.successFn())},a.post?a.firstRequest.send(a.data):a.firstRequest.send(),a.log("Unauthenticated request to "+t),a.firstRequest.onerror=function(){401!==a.firstRequest.status&&(a.log("Error ("+a.firstRequest.status+") on unauthenticated request to "+t),a.errorFn(a.firstRequest))}},this.makeAuthenticatedRequest=function(){a.response=a.formulateResponse(),a.authenticatedRequest=new XMLHttpRequest,a.authenticatedRequest.open(e,t,!0),a.authenticatedRequest.timeout=a.timeout;var r=a.scheme+' username="'+i+'", realm="'+a.realm+'", nonce="'+a.nonce+'", uri="'+t+'", response="'+a.response+'", opaque="'+a.opaque+'", qop='+a.qop+", nc="+("00000000"+a.nc).slice(-8)+', cnonce="'+a.cnonce+'"';a.authenticatedRequest.setRequestHeader("Authorization",r),a.log("digest auth header response to be sent:"),a.log(r),a.post&&a.data&&("string"==typeof a.data?a.authenticatedRequest.setRequestHeader("Content-type","text/plain"):a.authenticatedRequest.responseType="arraybuffer"),a.authenticatedRequest.onload=function(){a.authenticatedRequest.status>=200&&a.authenticatedRequest.status<400?(a.nc++,a.data instanceof Uint8Array?a.successFn(a.authenticatedRequest):"undefined"!==a.authenticatedRequest.responseText&&a.authenticatedRequest.responseText.length>0?(a.isJson(a.authenticatedRequest.responseText),a.successFn(a.authenticatedRequest)):a.successFn()):(a.nonce=null,a.errorFn(a.authenticatedRequest))},a.authenticatedRequest.onerror=function(){a.log("Error ("+a.authenticatedRequest.status+") on authenticated request to "+t),a.nonce=null,a.errorFn(a.authenticatedRequest)},a.post?a.authenticatedRequest.send(a.data):a.authenticatedRequest.send(),a.log("Authenticated request to "+t)},this.formulateResponse=function(){var r=o.MD5(i+":"+a.realm+":"+n).toString(),s=o.MD5(e+":"+t).toString();return o.MD5(r+":"+a.nonce+":"+("00000000"+a.nc).slice(-8)+":"+a.cnonce+":"+a.qop+":"+s).toString()},this.generateCnonce=function(){for(var e="",t=0;t<16;t++){var r=Math.round(Math.random()*"abcdef0123456789".length);e+="abcdef0123456789".substr(r,1)}return e},this.abort=function(){a.log("[digestAuthRequest] Aborted request to "+t),null!=a.firstRequest&&4!=a.firstRequest.readyState&&a.firstRequest.abort(),null!=a.authenticatedRequest&&4!=a.authenticatedRequest.readyState&&a.authenticatedRequest.abort()},this.isJson=function(e){try{JSON.parse(e)}catch(e){return!1}return!0},this.log=function(e){a.loggingOn&&console.log("[digestAuthRequest] "+e)},this.version=function(){return"0.8.0"}},e.exports=o},function(e,t,r){var i=r(207),n=r(389);e.exports=function(e){if(!n(e))return!1;var t=i(e);return"[object Function]"==t||"[object GeneratorFunction]"==t||"[object AsyncFunction]"==t||"[object Proxy]"==t}},function(e,t,r){var i=r(208),n=r(387),a=r(388),o=i?i.toStringTag:void 0;e.exports=function(e){return null==e?void 0===e?"[object Undefined]":"[object Null]":o&&o in Object(e)?n(e):a(e)}},function(e,t,r){var i=r(385).Symbol;e.exports=i},function(e,t){var r=Array.isArray;e.exports=r},function(e,t,r){"use strict";var i=r(211),n=i.Cookie,a=i.CookieJar;function o(e){this._jar=new a(e,{looseMode:!0})}t.parse=function(e){if(e&&e.uri&&(e=e.uri),"string"!=typeof e)throw new Error("The cookie function only accepts STRING as param");return n.parse(e,{loose:!0})},o.prototype.setCookie=function(e,t,r){return this._jar.setCookieSync(e,t,r||{})},o.prototype.getCookieString=function(e){return this._jar.getCookieStringSync(e)},o.prototype.getCookies=function(e){return this._jar.getCookiesSync(e)},t.jar=function(e){return new o(e)}},function(e,t,r){"use strict"; -/*! - * Copyright (c) 2015, Salesforce.com, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of Salesforce.com nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */var i,n=r(83),a=r(25).parse,o=r(11),s=r(212),c=r(213).Store,u=r(399).MemoryCookieStore,l=r(215).pathMatch,h=r(400).version;try{i=r(123)}catch(e){console.warn("tough-cookie: can't load punycode; won't use punycode for domain normalization")}var d=/^[\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]+$/,p=/[\x00-\x1F]/,f=["\n","\r","\0"],m=/[\x20-\x3A\x3C-\x7E]+/,g=/[\x09\x20-\x2F\x3B-\x40\x5B-\x60\x7B-\x7E]/,_={jan:0,feb:1,mar:2,apr:3,may:4,jun:5,jul:6,aug:7,sep:8,oct:9,nov:10,dec:11},v=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],y=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];function b(e,t,r,i){for(var n=0;n=58)break;n++}return nr?null:i||n==e.length?parseInt(e.substr(0,n),10):null}function E(e){var t=e.split(":"),r=[0,0,0];if(3!==t.length)return null;for(var i=0;i<3;i++){var n=2==i,a=b(t[i],1,2,n);if(null===a)return null;r[i]=a}return r}function w(e){e=String(e).substr(0,3).toLowerCase();var t=_[e];return t>=0?t:null}function S(e){if(e){var t=e.split(g);if(t){for(var r=null,i=null,n=null,a=null,o=null,s=null,c=0;c=70&&s<=99?s+=1900:s>=0&&s<=69&&(s+=2e3)):o=u:a=u}if(!(null===a||null===o||null===s||null===n||a<1||a>31||s<1601||r>23||i>59||n>59))return new Date(Date.UTC(s,o,a,r,i,n))}}}function k(e){var t=e.getUTCDate();t=t>=10?t:"0"+t;var r=e.getUTCHours();r=r>=10?r:"0"+r;var i=e.getUTCMinutes();i=i>=10?i:"0"+i;var n=e.getUTCSeconds();return n=n>=10?n:"0"+n,y[e.getUTCDay()]+", "+t+" "+v[e.getUTCMonth()]+" "+e.getUTCFullYear()+" "+r+":"+i+":"+n+" GMT"}function x(e){return null==e?null:(e=e.trim().replace(/^\./,""),i&&/[^\u0001-\u007f]/.test(e)&&(e=i.toASCII(e)),e.toLowerCase())}function M(e,t,r){if(null==e||null==t)return null;if(!1!==r&&(e=x(e),t=x(t)),e==t)return!0;if(n.isIP(e))return!1;var i=e.indexOf(t);return!(i<=0)&&(e.length===t.length+i&&"."===e.substr(i-1,1))}function N(e){if(!e||"/"!==e.substr(0,1))return"/";if("/"===e)return e;var t=e.lastIndexOf("/");return 0===t?"/":e.slice(0,t)}function j(e,t){var r,i,n=(e=function(e){for(var t=0;t1;){var r=e.lastIndexOf("/");if(0===r)break;e=e.substr(0,r),t.push(e)}return t.push("/"),t},t.canonicalDomain=x},function(e,t,r){"use strict"; -/*! - * Copyright (c) 2018, Salesforce.com, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of Salesforce.com nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */var i=r(397);t.getPublicSuffix=function(e){return i.get(e)}},function(e,t,r){"use strict"; -/*! - * Copyright (c) 2015, Salesforce.com, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of Salesforce.com nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */function i(){}t.Store=i,i.prototype.synchronous=!1,i.prototype.findCookie=function(e,t,r,i){throw new Error("findCookie is not implemented")},i.prototype.findCookies=function(e,t,r){throw new Error("findCookies is not implemented")},i.prototype.putCookie=function(e,t){throw new Error("putCookie is not implemented")},i.prototype.updateCookie=function(e,t,r){throw new Error("updateCookie is not implemented")},i.prototype.removeCookie=function(e,t,r,i){throw new Error("removeCookie is not implemented")},i.prototype.removeCookies=function(e,t,r){throw new Error("removeCookies is not implemented")},i.prototype.getAllCookies=function(e){throw new Error("getAllCookies is not implemented (therefore jar cannot be serialized)")}},function(e,t,r){"use strict"; -/*! - * Copyright (c) 2015, Salesforce.com, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of Salesforce.com nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */var i=r(212);t.permuteDomain=function(e){var t=i.getPublicSuffix(e);if(!t)return null;if(t==e)return[e];for(var r=e.slice(0,-(t.length+1)).split(".").reverse(),n=t,a=[n];r.length;)n=r.shift()+"."+n,a.push(n);return a}},function(e,t,r){"use strict"; -/*! - * Copyright (c) 2015, Salesforce.com, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of Salesforce.com nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */t.pathMatch=function(e,t){if(t===e)return!0;if(0===e.indexOf(t)){if("/"===t.substr(-1))return!0;if("/"===e.substr(t.length,1))return!0}return!1}},function(e,t,r){(function(e){t.fetch=s(e.fetch)&&s(e.ReadableStream),t.writableStream=s(e.WritableStream),t.abortController=s(e.AbortController),t.blobConstructor=!1;try{new Blob([new ArrayBuffer(1)]),t.blobConstructor=!0}catch(e){}var r;function i(){if(void 0!==r)return r;if(e.XMLHttpRequest){r=new e.XMLHttpRequest;try{r.open("GET",e.XDomainRequest?"/":"https://example.com")}catch(e){r=null}}else r=null;return r}function n(e){var t=i();if(!t)return!1;try{return t.responseType=e,t.responseType===e}catch(e){}return!1}var a=void 0!==e.ArrayBuffer,o=a&&s(e.ArrayBuffer.prototype.slice);function s(e){return"function"==typeof e}t.arraybuffer=t.fetch||a&&n("arraybuffer"),t.msstream=!t.fetch&&o&&n("ms-stream"),t.mozchunkedarraybuffer=!t.fetch&&a&&n("moz-chunked-arraybuffer"),t.overrideMimeType=t.fetch||!!i()&&s(i().overrideMimeType),t.vbArray=s(e.VBArray),r=null}).call(this,r(8))},function(e,t,r){(function(e,i,n){var a=r(216),o=r(0),s=r(218),c=t.readyStates={UNSENT:0,OPENED:1,HEADERS_RECEIVED:2,LOADING:3,DONE:4},u=t.IncomingMessage=function(t,r,o,c){var u=this;if(s.Readable.call(u),u._mode=o,u.headers={},u.rawHeaders=[],u.trailers={},u.rawTrailers=[],u.on("end",(function(){e.nextTick((function(){u.emit("close")}))})),"fetch"===o){if(u._fetchResponse=r,u.url=r.url,u.statusCode=r.status,u.statusMessage=r.statusText,r.headers.forEach((function(e,t){u.headers[t.toLowerCase()]=e,u.rawHeaders.push(t,e)})),a.writableStream){var l=new WritableStream({write:function(e){return new Promise((function(t,r){u._destroyed?r():u.push(new i(e))?t():u._resumeFetch=t}))},close:function(){n.clearTimeout(c),u._destroyed||u.push(null)},abort:function(e){u._destroyed||u.emit("error",e)}});try{return void r.body.pipeTo(l).catch((function(e){n.clearTimeout(c),u._destroyed||u.emit("error",e)}))}catch(e){}}var h=r.body.getReader();!function e(){h.read().then((function(t){if(!u._destroyed){if(t.done)return n.clearTimeout(c),void u.push(null);u.push(new i(t.value)),e()}})).catch((function(e){n.clearTimeout(c),u._destroyed||u.emit("error",e)}))}()}else{if(u._xhr=t,u._pos=0,u.url=t.responseURL,u.statusCode=t.status,u.statusMessage=t.statusText,t.getAllResponseHeaders().split(/\r?\n/).forEach((function(e){var t=e.match(/^([^:]+):\s*(.*)/);if(t){var r=t[1].toLowerCase();"set-cookie"===r?(void 0===u.headers[r]&&(u.headers[r]=[]),u.headers[r].push(t[2])):void 0!==u.headers[r]?u.headers[r]+=", "+t[2]:u.headers[r]=t[2],u.rawHeaders.push(t[1],t[2])}})),u._charset="x-user-defined",!a.overrideMimeType){var d=u.rawHeaders["mime-type"];if(d){var p=d.match(/;\s*charset=([^;])(;|$)/);p&&(u._charset=p[1].toLowerCase())}u._charset||(u._charset="utf-8")}}};o(u,s.Readable),u.prototype._read=function(){var e=this._resumeFetch;e&&(this._resumeFetch=null,e())},u.prototype._onXHRProgress=function(){var e=this,t=e._xhr,r=null;switch(e._mode){case"text:vbarray":if(t.readyState!==c.DONE)break;try{r=new n.VBArray(t.responseBody).toArray()}catch(e){}if(null!==r){e.push(new i(r));break}case"text":try{r=t.responseText}catch(t){e._mode="text:vbarray";break}if(r.length>e._pos){var a=r.substr(e._pos);if("x-user-defined"===e._charset){for(var o=new i(a.length),s=0;se._pos&&(e.push(new i(new Uint8Array(u.result.slice(e._pos)))),e._pos=u.result.byteLength)},u.onload=function(){e.push(null)},u.readAsArrayBuffer(r)}e._xhr.readyState===c.DONE&&"ms-stream"!==e._mode&&e.push(null)}}).call(this,r(3),r(2).Buffer,r(8))},function(e,t,r){(t=e.exports=r(219)).Stream=t,t.Readable=t,t.Writable=r(222),t.Duplex=r(53),t.Transform=r(223),t.PassThrough=r(407)},function(e,t,r){"use strict";(function(t,i){var n=r(35);e.exports=y;var a,o=r(104);y.ReadableState=v;r(23).EventEmitter;var s=function(e,t){return e.listeners(t).length},c=r(220),u=r(1).Buffer,l=t.Uint8Array||function(){};var h=Object.create(r(21));h.inherits=r(0);var d=r(404),p=void 0;p=d&&d.debuglog?d.debuglog("stream"):function(){};var f,m=r(405),g=r(221);h.inherits(y,c);var _=["error","close","destroy","pause","resume"];function v(e,t){e=e||{};var i=t instanceof(a=a||r(53));this.objectMode=!!e.objectMode,i&&(this.objectMode=this.objectMode||!!e.readableObjectMode);var n=e.highWaterMark,o=e.readableHighWaterMark,s=this.objectMode?16:16384;this.highWaterMark=n||0===n?n:i&&(o||0===o)?o:s,this.highWaterMark=Math.floor(this.highWaterMark),this.buffer=new m,this.length=0,this.pipes=null,this.pipesCount=0,this.flowing=null,this.ended=!1,this.endEmitted=!1,this.reading=!1,this.sync=!0,this.needReadable=!1,this.emittedReadable=!1,this.readableListening=!1,this.resumeScheduled=!1,this.destroyed=!1,this.defaultEncoding=e.defaultEncoding||"utf8",this.awaitDrain=0,this.readingMore=!1,this.decoder=null,this.encoding=null,e.encoding&&(f||(f=r(26).StringDecoder),this.decoder=new f(e.encoding),this.encoding=e.encoding)}function y(e){if(a=a||r(53),!(this instanceof y))return new y(e);this._readableState=new v(e,this),this.readable=!0,e&&("function"==typeof e.read&&(this._read=e.read),"function"==typeof e.destroy&&(this._destroy=e.destroy)),c.call(this)}function b(e,t,r,i,n){var a,o=e._readableState;null===t?(o.reading=!1,function(e,t){if(t.ended)return;if(t.decoder){var r=t.decoder.end();r&&r.length&&(t.buffer.push(r),t.length+=t.objectMode?1:r.length)}t.ended=!0,S(e)}(e,o)):(n||(a=function(e,t){var r;i=t,u.isBuffer(i)||i instanceof l||"string"==typeof t||void 0===t||e.objectMode||(r=new TypeError("Invalid non-string/buffer chunk"));var i;return r}(o,t)),a?e.emit("error",a):o.objectMode||t&&t.length>0?("string"==typeof t||o.objectMode||Object.getPrototypeOf(t)===u.prototype||(t=function(e){return u.from(e)}(t)),i?o.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):E(e,o,t,!0):o.ended?e.emit("error",new Error("stream.push() after EOF")):(o.reading=!1,o.decoder&&!r?(t=o.decoder.write(t),o.objectMode||0!==t.length?E(e,o,t,!1):x(e,o)):E(e,o,t,!1))):i||(o.reading=!1));return function(e){return!e.ended&&(e.needReadable||e.lengtht.highWaterMark&&(t.highWaterMark=function(e){return e>=8388608?e=8388608:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function S(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(p("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?n.nextTick(k,e):k(e))}function k(e){p("emit readable"),e.emit("readable"),T(e)}function x(e,t){t.readingMore||(t.readingMore=!0,n.nextTick(M,e,t))}function M(e,t){for(var r=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=t.length?(r=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.head.data:t.buffer.concat(t.length),t.buffer.clear()):r=function(e,t,r){var i;ea.length?a.length:e;if(o===a.length?n+=a:n+=a.slice(0,e),0===(e-=o)){o===a.length?(++i,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=a.slice(o));break}++i}return t.length-=i,n}(e,t):function(e,t){var r=u.allocUnsafe(e),i=t.head,n=1;i.data.copy(r),e-=i.data.length;for(;i=i.next;){var a=i.data,o=e>a.length?a.length:e;if(a.copy(r,r.length-e,0,o),0===(e-=o)){o===a.length?(++n,i.next?t.head=i.next:t.head=t.tail=null):(t.head=i,i.data=a.slice(o));break}++n}return t.length-=n,r}(e,t);return i}(e,t.buffer,t.decoder),r);var r}function I(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,n.nextTick(O,t,e))}function O(e,t){e.endEmitted||0!==e.length||(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function A(e,t){for(var r=0,i=e.length;r=t.highWaterMark||t.ended))return p("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?I(this):S(this),null;if(0===(e=w(e,t))&&t.ended)return 0===t.length&&I(this),null;var i,n=t.needReadable;return p("need readable",n),(0===t.length||t.length-e0?R(e,t):null)?(t.needReadable=!0,e=0):t.length-=e,0===t.length&&(t.ended||(t.needReadable=!0),r!==e&&t.ended&&I(this)),null!==i&&this.emit("data",i),i},y.prototype._read=function(e){this.emit("error",new Error("_read() is not implemented"))},y.prototype.pipe=function(e,t){var r=this,a=this._readableState;switch(a.pipesCount){case 0:a.pipes=e;break;case 1:a.pipes=[a.pipes,e];break;default:a.pipes.push(e)}a.pipesCount+=1,p("pipe count=%d opts=%j",a.pipesCount,t);var c=(!t||!1!==t.end)&&e!==i.stdout&&e!==i.stderr?l:y;function u(t,i){p("onunpipe"),t===r&&i&&!1===i.hasUnpiped&&(i.hasUnpiped=!0,p("cleanup"),e.removeListener("close",_),e.removeListener("finish",v),e.removeListener("drain",h),e.removeListener("error",g),e.removeListener("unpipe",u),r.removeListener("end",l),r.removeListener("end",y),r.removeListener("data",m),d=!0,!a.awaitDrain||e._writableState&&!e._writableState.needDrain||h())}function l(){p("onend"),e.end()}a.endEmitted?n.nextTick(c):r.once("end",c),e.on("unpipe",u);var h=function(e){return function(){var t=e._readableState;p("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&s(e,"data")&&(t.flowing=!0,T(e))}}(r);e.on("drain",h);var d=!1;var f=!1;function m(t){p("ondata"),f=!1,!1!==e.write(t)||f||((1===a.pipesCount&&a.pipes===e||a.pipesCount>1&&-1!==A(a.pipes,e))&&!d&&(p("false write response, pause",r._readableState.awaitDrain),r._readableState.awaitDrain++,f=!0),r.pause())}function g(t){p("onerror",t),y(),e.removeListener("error",g),0===s(e,"error")&&e.emit("error",t)}function _(){e.removeListener("finish",v),y()}function v(){p("onfinish"),e.removeListener("close",_),y()}function y(){p("unpipe"),r.unpipe(e)}return r.on("data",m),function(e,t,r){if("function"==typeof e.prependListener)return e.prependListener(t,r);e._events&&e._events[t]?o(e._events[t])?e._events[t].unshift(r):e._events[t]=[r,e._events[t]]:e.on(t,r)}(e,"error",g),e.once("close",_),e.once("finish",v),e.emit("pipe",r),a.flowing||(p("pipe resume"),r.resume()),e},y.prototype.unpipe=function(e){var t=this._readableState,r={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes||(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,r)),this;if(!e){var i=t.pipes,n=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var a=0;a-1?i:a.nextTick;v.WritableState=_;var u=Object.create(r(21));u.inherits=r(0);var l={deprecate:r(78)},h=r(220),d=r(1).Buffer,p=n.Uint8Array||function(){};var f,m=r(221);function g(){}function _(e,t){s=s||r(53),e=e||{};var i=t instanceof s;this.objectMode=!!e.objectMode,i&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var n=e.highWaterMark,u=e.writableHighWaterMark,l=this.objectMode?16:16384;this.highWaterMark=n||0===n?n:i&&(u||0===u)?u:l,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var h=!1===e.decodeStrings;this.decodeStrings=!h,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){!function(e,t){var r=e._writableState,i=r.sync,n=r.writecb;if(function(e){e.writing=!1,e.writecb=null,e.length-=e.writelen,e.writelen=0}(r),t)!function(e,t,r,i,n){--t.pendingcb,r?(a.nextTick(n,i),a.nextTick(k,e,t),e._writableState.errorEmitted=!0,e.emit("error",i)):(n(i),e._writableState.errorEmitted=!0,e.emit("error",i),k(e,t))}(e,r,i,t,n);else{var o=w(r);o||r.corked||r.bufferProcessing||!r.bufferedRequest||E(e,r),i?c(b,e,r,o,n):b(e,r,o,n)}}(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new o(this)}function v(e){if(s=s||r(53),!(f.call(v,this)||this instanceof s))return new v(e);this._writableState=new _(e,this),this.writable=!0,e&&("function"==typeof e.write&&(this._write=e.write),"function"==typeof e.writev&&(this._writev=e.writev),"function"==typeof e.destroy&&(this._destroy=e.destroy),"function"==typeof e.final&&(this._final=e.final)),h.call(this)}function y(e,t,r,i,n,a,o){t.writelen=i,t.writecb=o,t.writing=!0,t.sync=!0,r?e._writev(n,t.onwrite):e._write(n,a,t.onwrite),t.sync=!1}function b(e,t,r,i){r||function(e,t){0===t.length&&t.needDrain&&(t.needDrain=!1,e.emit("drain"))}(e,t),t.pendingcb--,i(),k(e,t)}function E(e,t){t.bufferProcessing=!0;var r=t.bufferedRequest;if(e._writev&&r&&r.next){var i=t.bufferedRequestCount,n=new Array(i),a=t.corkedRequestsFree;a.entry=r;for(var s=0,c=!0;r;)n[s]=r,r.isBuf||(c=!1),r=r.next,s+=1;n.allBuffers=c,y(e,t,!0,t.length,n,"",a.finish),t.pendingcb++,t.lastBufferedRequest=null,a.next?(t.corkedRequestsFree=a.next,a.next=null):t.corkedRequestsFree=new o(t),t.bufferedRequestCount=0}else{for(;r;){var u=r.chunk,l=r.encoding,h=r.callback;if(y(e,t,!1,t.objectMode?1:u.length,u,l,h),r=r.next,t.bufferedRequestCount--,t.writing)break}null===r&&(t.lastBufferedRequest=null)}t.bufferedRequest=r,t.bufferProcessing=!1}function w(e){return e.ending&&0===e.length&&null===e.bufferedRequest&&!e.finished&&!e.writing}function S(e,t){e._final((function(r){t.pendingcb--,r&&e.emit("error",r),t.prefinished=!0,e.emit("prefinish"),k(e,t)}))}function k(e,t){var r=w(t);return r&&(!function(e,t){t.prefinished||t.finalCalled||("function"==typeof e._final?(t.pendingcb++,t.finalCalled=!0,a.nextTick(S,e,t)):(t.prefinished=!0,e.emit("prefinish")))}(e,t),0===t.pendingcb&&(t.finished=!0,e.emit("finish"))),r}u.inherits(v,h),_.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(_.prototype,"buffer",{get:l.deprecate((function(){return this.getBuffer()}),"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch(e){}}(),"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(f=Function.prototype[Symbol.hasInstance],Object.defineProperty(v,Symbol.hasInstance,{value:function(e){return!!f.call(this,e)||this===v&&(e&&e._writableState instanceof _)}})):f=function(e){return e instanceof this},v.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))},v.prototype.write=function(e,t,r){var i,n=this._writableState,o=!1,s=!n.objectMode&&(i=e,d.isBuffer(i)||i instanceof p);return s&&!d.isBuffer(e)&&(e=function(e){return d.from(e)}(e)),"function"==typeof t&&(r=t,t=null),s?t="buffer":t||(t=n.defaultEncoding),"function"!=typeof r&&(r=g),n.ended?function(e,t){var r=new Error("write after end");e.emit("error",r),a.nextTick(t,r)}(this,r):(s||function(e,t,r,i){var n=!0,o=!1;return null===r?o=new TypeError("May not write null values to stream"):"string"==typeof r||void 0===r||t.objectMode||(o=new TypeError("Invalid non-string/buffer chunk")),o&&(e.emit("error",o),a.nextTick(i,o),n=!1),n}(this,n,e,r))&&(n.pendingcb++,o=function(e,t,r,i,n,a){if(!r){var o=function(e,t,r){e.objectMode||!1===e.decodeStrings||"string"!=typeof t||(t=d.from(t,r));return t}(t,i,n);i!==o&&(r=!0,n="buffer",i=o)}var s=t.objectMode?1:i.length;t.length+=s;var c=t.length-1))throw new TypeError("Unknown encoding: "+e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(v.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),v.prototype._write=function(e,t,r){r(new Error("_write() is not implemented"))},v.prototype._writev=null,v.prototype.end=function(e,t,r){var i=this._writableState;"function"==typeof e?(r=e,e=null,t=null):"function"==typeof t&&(r=t,t=null),null!=e&&this.write(e,t),i.corked&&(i.corked=1,this.uncork()),i.ending||i.finished||function(e,t,r){t.ending=!0,k(e,t),r&&(t.finished?a.nextTick(r):e.once("finish",r));t.ended=!0,e.writable=!1}(this,i,r)},Object.defineProperty(v.prototype,"destroyed",{get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),v.prototype.destroy=m.destroy,v.prototype._undestroy=m.undestroy,v.prototype._destroy=function(e,t){this.end(),t(e)}}).call(this,r(3),r(32).setImmediate,r(8))},function(e,t,r){"use strict";e.exports=o;var i=r(53),n=Object.create(r(21));function a(e,t){var r=this._transformState;r.transforming=!1;var i=r.writecb;if(!i)return this.emit("error",new Error("write callback called multiple times"));r.writechunk=null,r.writecb=null,null!=t&&this.push(t),i(e);var n=this._readableState;n.reading=!1,(n.needReadable||n.length>>16&65535|0,o=0;0!==r;){r-=o=r>2e3?2e3:r;do{a=a+(n=n+t[i++]|0)|0}while(--o);n%=65521,a%=65521}return n|a<<16|0}},function(e,t,r){"use strict";var i=function(){for(var e,t=[],r=0;r<256;r++){e=r;for(var i=0;i<8;i++)e=1&e?3988292384^e>>>1:e>>>1;t[r]=e}return t}();e.exports=function(e,t,r,n){var a=i,o=n+r;e^=-1;for(var s=n;s>>8^a[255&(e^t[s])];return-1^e}},function(e,t,r){e.exports={Verifier:u,Signer:l};var i=r(68),n=r(34),a=r(11),o=r(6),s=r(9).Buffer,c=r(30);function u(e,t){if("sha512"!==t.toLowerCase())throw new Error("ED25519 only supports the use of SHA-512 hashes");this.key=e,this.chunks=[],n.Writable.call(this,{})}function l(e,t){if("sha512"!==t.toLowerCase())throw new Error("ED25519 only supports the use of SHA-512 hashes");this.key=e,this.chunks=[],n.Writable.call(this,{})}a.inherits(u,n.Writable),u.prototype._write=function(e,t,r){this.chunks.push(e),r()},u.prototype.update=function(e){"string"==typeof e&&(e=s.from(e,"binary")),this.chunks.push(e)},u.prototype.verify=function(e,t){var r;if(c.isSignature(e,[2,0])){if("ed25519"!==e.type)return!1;r=e.toBuffer("raw")}else if("string"==typeof e)r=s.from(e,"base64");else if(c.isSignature(e,[1,0]))throw new Error("signature was created by too old a version of sshpk and cannot be verified");return o.buffer(r),i.sign.detached.verify(new Uint8Array(s.concat(this.chunks)),new Uint8Array(r),new Uint8Array(this.key.part.A.data))},a.inherits(l,n.Writable),l.prototype._write=function(e,t,r){this.chunks.push(e),r()},l.prototype.update=function(e){"string"==typeof e&&(e=s.from(e,"binary")),this.chunks.push(e)},l.prototype.sign=function(){var e=i.sign.detached(new Uint8Array(s.concat(this.chunks)),new Uint8Array(s.concat([this.key.part.k.data,this.key.part.A.data]))),t=s.from(e),r=c.parse(t,"ed25519","raw");return r.hashAlgorithm="sha512",r}},function(e,t,r){e.exports={read:function(e,t){if("string"==typeof e){if(e.trim().match(/^[-]+[ ]*BEGIN/))return a.read(e,t);if(e.match(/^\s*ssh-[a-z]/))return o.read(e,t);if(e.match(/^\s*ecdsa-/))return o.read(e,t);if(u(e))return c.read(e,t);e=n.from(e,"binary")}else{if(i.buffer(e),function(e){var t=0;for(;te.length||"BEGIN"!==e.slice(t,t+5).toString("ascii"))}(e))return a.read(e,t);if(function(e){var t=0;for(;t=t&&(n=0),i=i<<8|e[n];return i}a.prototype.encipher=function(e,t){void 0===t&&(t=new Uint8Array(e.buffer),0!==e.byteOffset&&(t=t.subarray(e.byteOffset))),e[0]^=this.P[0];for(var r=1;r<16;r+=2)e[1]^=o(this.S,t,0)^this.P[r],e[0]^=o(this.S,t,4)^this.P[r+1];var i=e[0];e[0]=e[1]^this.P[17],e[1]=i},a.prototype.decipher=function(e){var t=new Uint8Array(e.buffer);0!==e.byteOffset&&(t=t.subarray(e.byteOffset)),e[0]^=this.P[17];for(var r=16;r>0;r-=2)e[1]^=o(this.S,t,0)^this.P[r],e[0]^=o(this.S,t,4)^this.P[r-1];var i=e[0];e[0]=e[1]^this.P[0],e[1]=i},a.prototype.expand0state=function(e,t){var r,i,a=new Uint32Array(2),o=new Uint8Array(a.buffer);for(r=0,n=0;r<18;r++)this.P[r]^=s(e,t);for(n=0,r=0;r<18;r+=2)this.encipher(a,o),this.P[r]=a[0],this.P[r+1]=a[1];for(r=0;r<4;r++)for(i=0;i<256;i+=2)this.encipher(a,o),this.S[r][i]=a[0],this.S[r][i+1]=a[1]},a.prototype.expandstate=function(e,t,r,i){var a,o,c=new Uint32Array(2);for(a=0,n=0;a<18;a++)this.P[a]^=s(r,i);for(a=0,n=0;a<18;a+=2)c[0]^=s(e,t),c[1]^=s(e,t),this.encipher(c),this.P[a]=c[0],this.P[a+1]=c[1];for(a=0;a<4;a++)for(o=0;o<256;o+=2)c[0]^=s(e,t),c[1]^=s(e,t),this.encipher(c),this.S[a][o]=c[0],this.S[a][o+1]=c[1];n=0},a.prototype.enc=function(e,t){for(var r=0;r>>24,r[4*i+2]=o[i]>>>16,r[4*i+1]=o[i]>>>8,r[4*i+0]=o[i]}e.exports={BLOCKS:8,HASHSIZE:32,hash:c,pbkdf:function(e,t,r,n,a,o,s){var u,l,h,d,p,f,m=new Uint8Array(64),g=new Uint8Array(64),_=new Uint8Array(32),v=new Uint8Array(32),y=new Uint8Array(n+4),b=o;if(s<1)return-1;if(0===t||0===n||0===o||o>_.byteLength*_.byteLength||n>1<<20)return-1;for(d=Math.floor((o+_.byteLength-1)/_.byteLength),h=Math.floor((o+d-1)/d),u=0;u0;f++){for(y[n+0]=f>>>24,y[n+1]=f>>>16,y[n+2]=f>>>8,y[n+3]=f,i(g,y,n+4),c(m,g,v),u=_.byteLength;u--;)_[u]=v[u];for(u=1;u=b);u++)a[p]=_[u];o-=u}return 0}}},function(e,t,r){e.exports={read:function(e,t){"string"!=typeof e&&(i.buffer(e,"buf"),e=e.toString("ascii"));var r=e.trim().replace(/[\\\r]/g,""),o=r.match(s);o||(o=r.match(c));i.ok(o,"key must match regex");var u,l=a.algToKeyType(o[1]),h=n.from(o[2],"base64"),d={};if(o[4])try{u=a.read(h)}catch(e){o=r.match(c),i.ok(o,"key must match regex"),h=n.from(o[2],"base64"),u=a.readInternal(d,"public",h)}else u=a.readInternal(d,"public",h);if(i.strictEqual(l,u.type),o[4]&&o[4].length>0)u.comment=o[4];else if(d.consumed){var p=o[2]+(o[3]?o[3]:""),f=4*Math.ceil(d.consumed/3);for(p=p.slice(0,f-2).replace(/[^a-zA-Z0-9+\/=]/g,"")+p.slice(f-2),d.consumed%3>0&&"="!==p.slice(f-1,f)&&f--;"="===p.slice(f,f+1);)f++;var m=p.slice(f);(m=m.replace(/[\r\n]/g," ").replace(/^\s+/,"")).match(/^[a-zA-Z0-9]/)&&(u.comment=m)}return u},write:function(e,t){if(i.object(e),!o.isKey(e))throw new Error("Must be a public key");var r=[],s=a.keyTypeToAlg(e);r.push(s);var c=a.write(e);r.push(c.toString("base64")),e.comment&&r.push(e.comment);return n.from(r.join(" "))}};var i=r(6),n=r(9).Buffer,a=r(40),o=(r(13),r(14)),s=(r(17),r(89),/^([a-z0-9-]+)[ \t]+([a-zA-Z0-9+\/]+[=]*)([ \t]+([^ \t][^\n]*[\n]*)?)?$/),c=/^([a-z0-9-]+)[ \t\n]+([a-zA-Z0-9+\/][a-zA-Z0-9+\/ \t\n=]*)([^a-zA-Z0-9+\/ \t\n=].*)?$/},function(e,t,r){e.exports={read:function(e,t){"string"==typeof e&&(e=a.from(e,"binary"));i.buffer(e,"buf");var r=new n.BerReader(e);if(r.readSequence(),Math.abs(r.length-r.remain)>1)throw new Error("DER sequence does not contain whole byte stream");var d=r.offset;r.readSequence();var f=r.offset+r.length,m=f;if(r.peek()===h(0)){r.readSequence(h(0));var g=r.readInt();i.ok(g<=3,"only x.509 versions up to v3 supported")}var _={signatures:{}},y=_.signatures.x509={};y.extras={},_.serial=function(e,t){return i.strictEqual(e.peek(),n.Ber.Integer,t+" is not an Integer"),o.mpNormalize(e.readString(n.Ber.Integer,!0))}(r,"serial"),r.readSequence();var b=r.offset+r.length,E=r.readOID();if(void 0===p[E])throw new Error("unknown signature algorithm "+E);r._offset=b,_.issuer=s.parseAsn1(r),r.readSequence(),_.validFrom=v(r),_.validUntil=v(r),_.subjects=[s.parseAsn1(r)],r.readSequence(),b=r.offset+r.length,_.subjectKey=l.readPkcs8(void 0,"public",r),r._offset=b,r.peek()===h(1)&&(r.readSequence(h(1)),y.extras.issuerUniqueID=e.slice(r.offset,r.offset+r.length),r._offset+=r.length);r.peek()===h(2)&&(r.readSequence(h(2)),y.extras.subjectUniqueID=e.slice(r.offset,r.offset+r.length),r._offset+=r.length);if(r.peek()===h(3)){r.readSequence(h(3));var w=r.offset+r.length;for(r.readSequence();r.offset=60?a-1:a;r.setUTCFullYear(o,parseInt(t[2],10)-1,parseInt(t[3],10)),r.setUTCHours(parseInt(t[4],10),parseInt(t[5],10)),t[6]&&t[6].length>0&&r.setUTCSeconds(parseInt(t[6],10));return r}(e.readString(n.Ber.UTCTime));if(e.peek()===n.Ber.GeneralizedTime)return function(e){var t=e.match(x);i.ok(t);var r=new Date;r.setUTCFullYear(parseInt(t[1],10),parseInt(t[2],10)-1,parseInt(t[3],10)),r.setUTCHours(parseInt(t[4],10),parseInt(t[5],10)),t[6]&&t[6].length>0&&r.setUTCSeconds(parseInt(t[6],10));return r}(e.readString(n.Ber.GeneralizedTime));throw new Error("Unsupported date format")}var y={OtherName:h(0),RFC822Name:d(1),DNSName:d(2),X400Address:h(3),DirectoryName:h(4),EDIPartyName:h(5),URI:d(6),IPAddress:d(7),OID:d(8)},b={serverAuth:"1.3.6.1.5.5.7.3.1",clientAuth:"1.3.6.1.5.5.7.3.2",codeSigning:"1.3.6.1.5.5.7.3.3",joyentDocker:"1.3.6.1.4.1.38678.1.4.1",joyentCmon:"1.3.6.1.4.1.38678.1.4.2"},E={};Object.keys(b).forEach((function(e){E[b[e]]=e}));var w=["signature","identity","keyEncryption","encryption","keyAgreement","ca","crl"];function S(e,t,r){r.readSequence();var i,a,o=r.offset+r.length,c=r.readOID(),u=e.signatures.x509;switch(u.extras.exts||(u.extras.exts=[]),r.peek()===n.Ber.Boolean&&(a=r.readBoolean()),c){case m:r.readSequence(n.Ber.OctetString),r.readSequence();var l=r.offset+r.length,h=!1;r.peek()===n.Ber.Boolean&&(h=r.readBoolean()),void 0===e.purposes&&(e.purposes=[]),!0===h&&e.purposes.push("ca");var d={oid:c,critical:a};r.offset0||"host"===a.type||void 0!==e.purposes&&e.purposes.length>0||r.extras&&r.extras.exts){t.startSequence(h(3)),t.startSequence();var c=[];void 0!==e.purposes&&e.purposes.length>0&&(c.push({oid:m,critical:!0}),c.push({oid:g,critical:!0}),c.push({oid:_,critical:!0})),c.push({oid:f}),r.extras&&r.extras.exts&&(c=r.extras.exts);for(var u=0;u0)throw new Error("non-zero precision not supported");switch(t.match(/-/)&&(u=!0),t.match(/0/)&&(l="0"),t.match(/\+/)&&(h=!0),o){case"s":if(null==d)throw new Error("argument "+v+": attempted to print undefined or null as a string");_+=s(l,r,u,d.toString());break;case"d":d=Math.floor(d);case"f":_+=(h=h&&d>0?"+":"")+s(l,r,u,d.toString());break;case"x":_+=s(l,r,u,d.toString(16));break;case"j":0===r&&(r=10),_+=n.inspect(d,!1,r);break;case"r":_+=c(d);break;default:throw new Error("unsupported conversion: "+o)}}else _+="%";return _+=e}function o(e){var t=Array.prototype.slice.call(arguments,1);return e.write(a.apply(this,t))}function s(e,t,r,i){for(var n=i;n.length=0:t.isEnumerableObject(e))},t.isEnumerableObject=function(e){for(var t in e)return!0;return!1},t.isEmpty=function(e){return t.isObject(e)?!t.isEnumerableObject(e):!t.isEnumerable(e)},t.isFiniteNumber=function(e){return t.isNumber(e)&&isFinite(e)},t.isInteger=function(e){return t.isFiniteNumber(e)&&Math.floor(e)===e},t.isVague=function(e){return e&&"object"==typeof e},t.isList=function(e){return t.isVague(e)&&t.isInteger(e.length)&&e.length>=0},t.isNaN=isNaN,t.nativeTypeOf=function(e){var t=e.toString(e);return t.substring(8,t.length-1)},t.typeOf=function(e){return t.isObject(e)?e.constructor.name||"Object":t.nativeTypeOf(e)},t.safeApply=function(e,r,i){return t.isFunction(e)?e.apply(i||this,r):void 0},t.enumerate=function(e,r,i,n){if(!e)return e;if(i=i||this,!n&&t.isFunction(e.forEach))return e.forEach(r,i);var a=0,o=e.length;if(t.isString(e))for(;at||t>=i}))):void 0}},function(e,t,r){var i=r(34);function n(e){return e instanceof i.Stream}function a(e){return n(e)&&"function"==typeof e._read&&"object"==typeof e._readableState}function o(e){return n(e)&&"function"==typeof e._write&&"object"==typeof e._writableState}e.exports=n,e.exports.isReadable=a,e.exports.isWritable=o,e.exports.isDuplex=function(e){return a(e)&&o(e)}},function(e,t,r){"use strict";var i=r(447),n=r(448),a=r(236);e.exports={formats:a,parse:n,stringify:i}},function(e,t,r){"use strict";var i=Object.prototype.hasOwnProperty,n=function(){for(var e=[],t=0;t<256;++t)e.push("%"+((t<16?"0":"")+t.toString(16)).toUpperCase());return e}(),a=function(e,t){for(var r=t&&t.plainObjects?Object.create(null):{},i=0;i=48&&a<=57||a>=65&&a<=90||a>=97&&a<=122?r+=t.charAt(i):a<128?r+=n[a]:a<2048?r+=n[192|a>>6]+n[128|63&a]:a<55296||a>=57344?r+=n[224|a>>12]+n[128|a>>6&63]+n[128|63&a]:(i+=1,a=65536+((1023&a)<<10|1023&t.charCodeAt(i)),r+=n[240|a>>18]+n[128|a>>12&63]+n[128|a>>6&63]+n[128|63&a])}return r},isBuffer:function(e){return null!=e&&!!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e))},isRegExp:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},merge:function e(t,r,n){if(!r)return t;if("object"!=typeof r){if(Array.isArray(t))t.push(r);else{if("object"!=typeof t)return[t,r];(n.plainObjects||n.allowPrototypes||!i.call(Object.prototype,r))&&(t[r]=!0)}return t}if("object"!=typeof t)return[t].concat(r);var o=t;return Array.isArray(t)&&!Array.isArray(r)&&(o=a(t,n)),Array.isArray(t)&&Array.isArray(r)?(r.forEach((function(r,a){i.call(t,a)?t[a]&&"object"==typeof t[a]?t[a]=e(t[a],r,n):t.push(r):t[a]=r})),t):Object.keys(r).reduce((function(t,a){var o=r[a];return i.call(t,a)?t[a]=e(t[a],o,n):t[a]=o,t}),o)}}},function(e,t,r){"use strict";var i=String.prototype.replace,n=/%20/g;e.exports={default:"RFC3986",formatters:{RFC1738:function(e){return i.call(e,n,"+")},RFC3986:function(e){return e}},RFC1738:"RFC1738",RFC3986:"RFC3986"}},function(e,t,r){"use strict";var i=r(54);e.exports=function(e){i.copy(e,this)}},function(e,t,r){"use strict";e.exports=function(e,t){t||(t={}),"function"==typeof t&&(t={cmp:t});var r,i="boolean"==typeof t.cycles&&t.cycles,n=t.cmp&&(r=t.cmp,function(e){return function(t,i){var n={key:t,value:e[t]},a={key:i,value:e[i]};return r(n,a)}}),a=[];return function e(t){if(t&&t.toJSON&&"function"==typeof t.toJSON&&(t=t.toJSON()),void 0!==t){if("number"==typeof t)return isFinite(t)?""+t:"null";if("object"!=typeof t)return JSON.stringify(t);var r,o;if(Array.isArray(t)){for(o="[",r=0;r2&&(t=r.call(arguments,1)),i(t)}))}))}function o(e){return Promise.all(e.map(n,this))}function s(e){for(var t=new e.constructor,r=Object.keys(e),i=[],a=0;a",_=p?">":"<",v=void 0;if(e.opts.$data&&m&&m.$data){var y=e.util.getData(m.$data,o,e.dataPathArr),b="exclusive"+a,E="exclType"+a,w="exclIsNumber"+a,S="' + "+(M="op"+a)+" + '";n+=" var schemaExcl"+a+" = "+y+"; ",n+=" var "+b+"; var "+E+" = typeof "+(y="schemaExcl"+a)+"; if ("+E+" != 'boolean' && "+E+" != 'undefined' && "+E+" != 'number') { ";var k;v=f;(k=k||[]).push(n),n="",!1!==e.createErrors?(n+=" { keyword: '"+(v||"_exclusiveLimit")+"' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(u)+" , params: {} ",!1!==e.opts.messages&&(n+=" , message: '"+f+" should be boolean' "),e.opts.verbose&&(n+=" , schema: validate.schema"+c+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),n+=" } "):n+=" {} ";var x=n;n=k.pop(),!e.compositeRule&&l?e.async?n+=" throw new ValidationError(["+x+"]); ":n+=" validate.errors = ["+x+"]; return false; ":n+=" var err = "+x+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",n+=" } else if ( ",d&&(n+=" ("+i+" !== undefined && typeof "+i+" != 'number') || "),n+=" "+E+" == 'number' ? ( ("+b+" = "+i+" === undefined || "+y+" "+g+"= "+i+") ? "+h+" "+_+"= "+y+" : "+h+" "+_+" "+i+" ) : ( ("+b+" = "+y+" === true) ? "+h+" "+_+"= "+i+" : "+h+" "+_+" "+i+" ) || "+h+" !== "+h+") { var op"+a+" = "+b+" ? '"+g+"' : '"+g+"=';"}else{S=g;if((w="number"==typeof m)&&d){var M="'"+S+"'";n+=" if ( ",d&&(n+=" ("+i+" !== undefined && typeof "+i+" != 'number') || "),n+=" ( "+i+" === undefined || "+m+" "+g+"= "+i+" ? "+h+" "+_+"= "+m+" : "+h+" "+_+" "+i+" ) || "+h+" !== "+h+") { "}else{w&&void 0===s?(b=!0,v=f,u=e.errSchemaPath+"/"+f,i=m,_+="="):(w&&(i=Math[p?"min":"max"](m,s)),m===(!w||i)?(b=!0,v=f,u=e.errSchemaPath+"/"+f,_+="="):(b=!1,S+="="));M="'"+S+"'";n+=" if ( ",d&&(n+=" ("+i+" !== undefined && typeof "+i+" != 'number') || "),n+=" "+h+" "+_+" "+i+" || "+h+" !== "+h+") { "}}v=v||t,(k=k||[]).push(n),n="",!1!==e.createErrors?(n+=" { keyword: '"+(v||"_limit")+"' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(u)+" , params: { comparison: "+M+", limit: "+i+", exclusive: "+b+" } ",!1!==e.opts.messages&&(n+=" , message: 'should be "+S+" ",n+=d?"' + "+i:i+"'"),e.opts.verbose&&(n+=" , schema: ",n+=d?"validate.schema"+c:""+s,n+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),n+=" } "):n+=" {} ";x=n;return n=k.pop(),!e.compositeRule&&l?e.async?n+=" throw new ValidationError(["+x+"]); ":n+=" validate.errors = ["+x+"]; return false; ":n+=" var err = "+x+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",n+=" } ",l&&(n+=" else { "),n}},function(e,t,r){"use strict";e.exports=function(e,t,r){var i,n=" ",a=e.level,o=e.dataLevel,s=e.schema[t],c=e.schemaPath+e.util.getProperty(t),u=e.errSchemaPath+"/"+t,l=!e.opts.allErrors,h="data"+(o||""),d=e.opts.$data&&s&&s.$data;d?(n+=" var schema"+a+" = "+e.util.getData(s.$data,o,e.dataPathArr)+"; ",i="schema"+a):i=s,n+="if ( ",d&&(n+=" ("+i+" !== undefined && typeof "+i+" != 'number') || "),n+=" "+h+".length "+("maxItems"==t?">":"<")+" "+i+") { ";var p=t,f=f||[];f.push(n),n="",!1!==e.createErrors?(n+=" { keyword: '"+(p||"_limitItems")+"' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(u)+" , params: { limit: "+i+" } ",!1!==e.opts.messages&&(n+=" , message: 'should NOT have ",n+="maxItems"==t?"more":"less",n+=" than ",n+=d?"' + "+i+" + '":""+s,n+=" items' "),e.opts.verbose&&(n+=" , schema: ",n+=d?"validate.schema"+c:""+s,n+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),n+=" } "):n+=" {} ";var m=n;return n=f.pop(),!e.compositeRule&&l?e.async?n+=" throw new ValidationError(["+m+"]); ":n+=" validate.errors = ["+m+"]; return false; ":n+=" var err = "+m+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",n+="} ",l&&(n+=" else { "),n}},function(e,t,r){"use strict";e.exports=function(e,t,r){var i,n=" ",a=e.level,o=e.dataLevel,s=e.schema[t],c=e.schemaPath+e.util.getProperty(t),u=e.errSchemaPath+"/"+t,l=!e.opts.allErrors,h="data"+(o||""),d=e.opts.$data&&s&&s.$data;d?(n+=" var schema"+a+" = "+e.util.getData(s.$data,o,e.dataPathArr)+"; ",i="schema"+a):i=s;var p="maxLength"==t?">":"<";n+="if ( ",d&&(n+=" ("+i+" !== undefined && typeof "+i+" != 'number') || "),!1===e.opts.unicode?n+=" "+h+".length ":n+=" ucs2length("+h+") ",n+=" "+p+" "+i+") { ";var f=t,m=m||[];m.push(n),n="",!1!==e.createErrors?(n+=" { keyword: '"+(f||"_limitLength")+"' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(u)+" , params: { limit: "+i+" } ",!1!==e.opts.messages&&(n+=" , message: 'should NOT be ",n+="maxLength"==t?"longer":"shorter",n+=" than ",n+=d?"' + "+i+" + '":""+s,n+=" characters' "),e.opts.verbose&&(n+=" , schema: ",n+=d?"validate.schema"+c:""+s,n+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),n+=" } "):n+=" {} ";var g=n;return n=m.pop(),!e.compositeRule&&l?e.async?n+=" throw new ValidationError(["+g+"]); ":n+=" validate.errors = ["+g+"]; return false; ":n+=" var err = "+g+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",n+="} ",l&&(n+=" else { "),n}},function(e,t,r){"use strict";e.exports=function(e,t,r){var i,n=" ",a=e.level,o=e.dataLevel,s=e.schema[t],c=e.schemaPath+e.util.getProperty(t),u=e.errSchemaPath+"/"+t,l=!e.opts.allErrors,h="data"+(o||""),d=e.opts.$data&&s&&s.$data;d?(n+=" var schema"+a+" = "+e.util.getData(s.$data,o,e.dataPathArr)+"; ",i="schema"+a):i=s,n+="if ( ",d&&(n+=" ("+i+" !== undefined && typeof "+i+" != 'number') || "),n+=" Object.keys("+h+").length "+("maxProperties"==t?">":"<")+" "+i+") { ";var p=t,f=f||[];f.push(n),n="",!1!==e.createErrors?(n+=" { keyword: '"+(p||"_limitProperties")+"' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(u)+" , params: { limit: "+i+" } ",!1!==e.opts.messages&&(n+=" , message: 'should NOT have ",n+="maxProperties"==t?"more":"less",n+=" than ",n+=d?"' + "+i+" + '":""+s,n+=" properties' "),e.opts.verbose&&(n+=" , schema: ",n+=d?"validate.schema"+c:""+s,n+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),n+=" } "):n+=" {} ";var m=n;return n=f.pop(),!e.compositeRule&&l?e.async?n+=" throw new ValidationError(["+m+"]); ":n+=" validate.errors = ["+m+"]; return false; ":n+=" var err = "+m+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",n+="} ",l&&(n+=" else { "),n}},function(e,t,r){(function(e,r,i,n){(function(t){"use strict";function a(e,t){t|=0;for(var r=Math.max(e.length-t,0),i=Array(r),n=0;n-1&&e%1==0&&e<=9007199254740991}function A(e){return null!=e&&O(e.length)&&!function(e){if(!c(e))return!1;var t=I(e);return"[object Function]"==t||"[object GeneratorFunction]"==t||"[object AsyncFunction]"==t||"[object Proxy]"==t}(e)}var P={};function D(){}function F(e){return function(){if(null!==e){var t=e;e=null,t.apply(this,arguments)}}}var C="function"==typeof Symbol&&Symbol.iterator;function B(e){return null!=e&&"object"==typeof e}function z(e){return B(e)&&"[object Arguments]"==I(e)}var L=Object.prototype,U=L.hasOwnProperty,H=L.propertyIsEnumerable,q=z(function(){return arguments}())?z:function(e){return B(e)&&U.call(e,"callee")&&!H.call(e,"callee")},K=Array.isArray,Z="object"==typeof t&&t&&!t.nodeType&&t,W=Z&&"object"==typeof n&&n&&!n.nodeType&&n,X=W&&W.exports===Z?S.Buffer:void 0,Q=(X?X.isBuffer:void 0)||function(){return!1},J=/^(?:0|[1-9]\d*)$/;function V(e,t){var r=typeof e;return!!(t=null==t?9007199254740991:t)&&("number"==r||"symbol"!=r&&J.test(e))&&e>-1&&e%1==0&&e2&&(i=a(arguments,1)),t){var u={};Ie(n,(function(e,t){u[t]=e})),u[e]=i,s=!0,c=Object.create(null),r(t,u)}else n[e]=i,f(e)}));o++;var u=y(t[t.length-1]);t.length>1?u(n,i):u(i)}}(e,t)}))}function p(){if(0===u.length&&0===o)return r(null,n);for(;u.length&&o=0&&r.push(i)})),r}Ie(e,(function(t,r){if(!K(t))return d(r,[t]),void l.push(r);var i=t.slice(0,t.length-1),n=i.length;if(0===n)return d(r,t),void l.push(r);h[r]=n,je(i,(function(a){if(!e[a])throw new Error("async.auto task `"+r+"` has a non-existent dependency `"+a+"` in "+i.join(", "));var o,s,u;s=function(){0==--n&&d(r,t)},(u=c[o=a])||(u=c[o]=[]),u.push(s)}))})),function(){for(var e,t=0;l.length;)e=l.pop(),t++,je(m(e),(function(e){0==--h[e]&&l.push(e)}));if(t!==i)throw new Error("async.auto cannot execute tasks due to a recursive dependency")}(),p()};function De(e,t){for(var r=-1,i=null==e?0:e.length,n=Array(i);++r=i?e:function(e,t,r){var i=-1,n=e.length;t<0&&(t=-t>n?0:n+t),(r=r>n?n:r)<0&&(r+=n),n=t>r?0:r-t>>>0,t>>>=0;for(var a=Array(n);++i-1;);return r}(n,a),function(e,t){for(var r=e.length;r--&&Ae(t,e[r],0)>-1;);return r}(n,a)+1).join("")}var et=/^(?:async\s+)?(function)?\s*[^\(]*\(\s*([^\)]*)\)/m,tt=/,/,rt=/(=.+)?(\s*)$/,it=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;function nt(e,t){var r={};Ie(e,(function(e,t){var i,n=v(e),a=!n&&1===e.length||n&&0===e.length;if(K(e))i=e.slice(0,-1),e=e[e.length-1],r[t]=i.concat(i.length>0?o:e);else if(a)r[t]=e;else{if(i=function(e){return e=(e=(e=(e=e.toString().replace(it,"")).match(et)[2].replace(" ",""))?e.split(tt):[]).map((function(e){return $e(e.replace(rt,""))}))}(e),0===e.length&&!n&&0===i.length)throw new Error("autoInject task functions require explicit parameters.");n||i.pop(),r[t]=i.concat(o)}function o(t,r){var n=De(i,(function(e){return t[e]}));n.push(r),y(e).apply(null,n)}})),Pe(r,t)}function at(){this.head=this.tail=null,this.length=0}function ot(e,t){e.length=1,e.head=e.tail=t}function st(e,t,r){if(null==t)t=1;else if(0===t)throw new Error("Concurrency must not be zero");var i=y(e),n=0,a=[],o=!1;function s(e,t,r){if(null!=r&&"function"!=typeof r)throw new Error("task callback must be a function");if(l.started=!0,K(e)||(e=[e]),0===e.length&&l.idle())return p((function(){l.drain()}));for(var i=0,n=e.length;i0&&a.splice(s,1),o.callback.apply(o,arguments),null!=t&&l.error(t,o.data)}n<=l.concurrency-l.buffer&&l.unsaturated(),l.idle()&&l.drain(),l.process()}}var u=!1,l={_tasks:new at,concurrency:t,payload:r,saturated:D,unsaturated:D,buffer:t/4,empty:D,drain:D,error:D,started:!1,paused:!1,push:function(e,t){s(e,!1,t)},kill:function(){l.drain=D,l._tasks.empty()},unshift:function(e,t){s(e,!0,t)},remove:function(e){l._tasks.remove(e)},process:function(){if(!u){for(u=!0;!l.paused&&n2&&(n=a(arguments,1)),i[t]=n,r(e)}))}),(function(e){r(e,i)}))}function nr(e,t){ir(ye,e,t)}function ar(e,t,r){ir(fe(t),e,r)}var or=function(e,t){var r=y(e);return st((function(e,t){r(e[0],t)}),t,1)},sr=function(e,t){var r=or(e,t);return r.push=function(e,t,i){if(null==i&&(i=D),"function"!=typeof i)throw new Error("task callback must be a function");if(r.started=!0,K(e)||(e=[e]),0===e.length)return p((function(){r.drain()}));t=t||0;for(var n=r._tasks.head;n&&t>=n.priority;)n=n.next;for(var a=0,o=e.length;ai?1:0}we(e,(function(e,t){i(e,(function(r,i){if(r)return t(r);t(null,{value:e,criteria:i})}))}),(function(e,t){if(e)return r(e);r(null,De(t.sort(n),zt("value")))}))}function kr(e,t,r){var i=y(e);return s((function(n,a){var o,s=!1;n.push((function(){s||(a.apply(null,arguments),clearTimeout(o))})),o=setTimeout((function(){var t=e.name||"anonymous",i=new Error('Callback function "'+t+'" timed out.');i.code="ETIMEDOUT",r&&(i.info=r),s=!0,a(i)}),t),i.apply(null,n)}))}var xr=Math.ceil,Mr=Math.max;function Nr(e,t,r,i){var n=y(r);xe(function(e,t,r,i){for(var n=-1,a=Mr(xr((t-e)/(r||1)),0),o=Array(a);a--;)o[i?a:++n]=e,e+=r;return o}(0,e,1),t,n,i)}var jr=ge(Nr,1/0),Tr=ge(Nr,1);function Rr(e,t,r,i){arguments.length<=3&&(i=r,r=t,t=K(e)?[]:{}),i=F(i||D);var n=y(r);ye(e,(function(e,r,i){n(t,e,r,i)}),(function(e){i(e,t)}))}function Ir(e,t){var r,i=null;t=t||D,At(e,(function(e,t){y(e)((function(e,n){r=arguments.length>2?a(arguments,1):n,i=e,t(!e)}))}),(function(){t(i,r)}))}function Or(e){return function(){return(e.unmemoized||e).apply(null,arguments)}}function Ar(e,t,r){r=pe(r||D);var i=y(t);if(!e())return r(null);var n=function(t){if(t)return r(t);if(e())return i(n);var o=a(arguments,1);r.apply(null,[null].concat(o))};i(n)}function Pr(e,t,r){Ar((function(){return!e.apply(this,arguments)}),t,r)}var Dr=function(e,t){if(t=F(t||D),!K(e))return t(new Error("First argument to waterfall must be an array of functions"));if(!e.length)return t();var r=0;function i(t){var i=y(e[r++]);t.push(pe(n)),i.apply(null,t)}function n(n){if(n||r===e.length)return t.apply(null,arguments);i(a(arguments,1))}i([])},Fr={apply:o,applyEach:Se,applyEachSeries:Ne,asyncify:f,auto:Pe,autoInject:nt,cargo:ct,compose:dt,concat:mt,concatLimit:ft,concatSeries:gt,constant:_t,detect:Et,detectLimit:wt,detectSeries:St,dir:xt,doDuring:Mt,doUntil:jt,doWhilst:Nt,during:Tt,each:It,eachLimit:Ot,eachOf:ye,eachOfLimit:me,eachOfSeries:ut,eachSeries:At,ensureAsync:Pt,every:Ft,everyLimit:Ct,everySeries:Bt,filter:qt,filterLimit:Kt,filterSeries:Zt,forever:Wt,groupBy:Qt,groupByLimit:Xt,groupBySeries:Jt,log:Vt,map:we,mapLimit:xe,mapSeries:Me,mapValues:Yt,mapValuesLimit:Gt,mapValuesSeries:$t,memoize:tr,nextTick:rr,parallel:nr,parallelLimit:ar,priorityQueue:sr,queue:or,race:cr,reduce:lt,reduceRight:ur,reflect:lr,reflectAll:hr,reject:pr,rejectLimit:fr,rejectSeries:mr,retry:_r,retryable:vr,seq:ht,series:yr,setImmediate:p,some:br,someLimit:Er,someSeries:wr,sortBy:Sr,timeout:kr,times:jr,timesLimit:Nr,timesSeries:Tr,transform:Rr,tryEach:Ir,unmemoize:Or,until:Pr,waterfall:Dr,whilst:Ar,all:Ft,allLimit:Ct,allSeries:Bt,any:br,anyLimit:Er,anySeries:wr,find:Et,findLimit:wt,findSeries:St,forEach:It,forEachSeries:At,forEachLimit:Ot,forEachOf:ye,forEachOfSeries:ut,forEachOfLimit:me,inject:lt,foldl:lt,foldr:ur,select:qt,selectLimit:Kt,selectSeries:Zt,wrapSync:f};t.default=Fr,t.apply=o,t.applyEach=Se,t.applyEachSeries=Ne,t.asyncify=f,t.auto=Pe,t.autoInject=nt,t.cargo=ct,t.compose=dt,t.concat=mt,t.concatLimit=ft,t.concatSeries=gt,t.constant=_t,t.detect=Et,t.detectLimit=wt,t.detectSeries=St,t.dir=xt,t.doDuring=Mt,t.doUntil=jt,t.doWhilst=Nt,t.during=Tt,t.each=It,t.eachLimit=Ot,t.eachOf=ye,t.eachOfLimit=me,t.eachOfSeries=ut,t.eachSeries=At,t.ensureAsync=Pt,t.every=Ft,t.everyLimit=Ct,t.everySeries=Bt,t.filter=qt,t.filterLimit=Kt,t.filterSeries=Zt,t.forever=Wt,t.groupBy=Qt,t.groupByLimit=Xt,t.groupBySeries=Jt,t.log=Vt,t.map=we,t.mapLimit=xe,t.mapSeries=Me,t.mapValues=Yt,t.mapValuesLimit=Gt,t.mapValuesSeries=$t,t.memoize=tr,t.nextTick=rr,t.parallel=nr,t.parallelLimit=ar,t.priorityQueue=sr,t.queue=or,t.race=cr,t.reduce=lt,t.reduceRight=ur,t.reflect=lr,t.reflectAll=hr,t.reject=pr,t.rejectLimit=fr,t.rejectSeries=mr,t.retry=_r,t.retryable=vr,t.seq=ht,t.series=yr,t.setImmediate=p,t.some=br,t.someLimit=Er,t.someSeries=wr,t.sortBy=Sr,t.timeout=kr,t.times=jr,t.timesLimit=Nr,t.timesSeries=Tr,t.transform=Rr,t.tryEach=Ir,t.unmemoize=Or,t.until=Pr,t.waterfall=Dr,t.whilst=Ar,t.all=Ft,t.allLimit=Ct,t.allSeries=Bt,t.any=br,t.anyLimit=Er,t.anySeries=wr,t.find=Et,t.findLimit=wt,t.findSeries=St,t.forEach=It,t.forEachSeries=At,t.forEachLimit=Ot,t.forEachOf=ye,t.forEachOfSeries=ut,t.forEachOfLimit=me,t.inject=lt,t.foldl=lt,t.foldr=ur,t.select=qt,t.selectLimit=Kt,t.selectSeries=Zt,t.wrapSync=f,Object.defineProperty(t,"__esModule",{value:!0})})(t)}).call(this,r(32).setImmediate,r(3),r(8),r(22)(e))},function(e,t,r){var i;e.exports=(i=r(5),function(e){var t=i,r=t.lib,n=r.WordArray,a=r.Hasher,o=t.algo,s=[],c=[];!function(){function t(t){for(var r=e.sqrt(t),i=2;i<=r;i++)if(!(t%i))return!1;return!0}function r(e){return 4294967296*(e-(0|e))|0}for(var i=2,n=0;n<64;)t(i)&&(n<8&&(s[n]=r(e.pow(i,.5))),c[n]=r(e.pow(i,1/3)),n++),i++}();var u=[],l=o.SHA256=a.extend({_doReset:function(){this._hash=new n.init(s.slice(0))},_doProcessBlock:function(e,t){for(var r=this._hash.words,i=r[0],n=r[1],a=r[2],o=r[3],s=r[4],l=r[5],h=r[6],d=r[7],p=0;p<64;p++){if(p<16)u[p]=0|e[t+p];else{var f=u[p-15],m=(f<<25|f>>>7)^(f<<14|f>>>18)^f>>>3,g=u[p-2],_=(g<<15|g>>>17)^(g<<13|g>>>19)^g>>>10;u[p]=m+u[p-7]+_+u[p-16]}var v=i&n^i&a^n&a,y=(i<<30|i>>>2)^(i<<19|i>>>13)^(i<<10|i>>>22),b=d+((s<<26|s>>>6)^(s<<21|s>>>11)^(s<<7|s>>>25))+(s&l^~s&h)+c[p]+u[p];d=h,h=l,l=s,s=o+b|0,o=a,a=n,n=i,i=b+(y+v)|0}r[0]=r[0]+i|0,r[1]=r[1]+n|0,r[2]=r[2]+a|0,r[3]=r[3]+o|0,r[4]=r[4]+s|0,r[5]=r[5]+l|0,r[6]=r[6]+h|0,r[7]=r[7]+d|0},_doFinalize:function(){var t=this._data,r=t.words,i=8*this._nDataBytes,n=8*t.sigBytes;return r[n>>>5]|=128<<24-n%32,r[14+(n+64>>>9<<4)]=e.floor(i/4294967296),r[15+(n+64>>>9<<4)]=i,t.sigBytes=4*r.length,this._process(),this._hash},clone:function(){var e=a.clone.call(this);return e._hash=this._hash.clone(),e}});t.SHA256=a._createHelper(l),t.HmacSHA256=a._createHmacHelper(l)}(Math),i.SHA256)},function(e,t,r){var i;e.exports=(i=r(5),r(90),function(){var e=i,t=e.lib.Hasher,r=e.x64,n=r.Word,a=r.WordArray,o=e.algo;function s(){return n.create.apply(n,arguments)}var c=[s(1116352408,3609767458),s(1899447441,602891725),s(3049323471,3964484399),s(3921009573,2173295548),s(961987163,4081628472),s(1508970993,3053834265),s(2453635748,2937671579),s(2870763221,3664609560),s(3624381080,2734883394),s(310598401,1164996542),s(607225278,1323610764),s(1426881987,3590304994),s(1925078388,4068182383),s(2162078206,991336113),s(2614888103,633803317),s(3248222580,3479774868),s(3835390401,2666613458),s(4022224774,944711139),s(264347078,2341262773),s(604807628,2007800933),s(770255983,1495990901),s(1249150122,1856431235),s(1555081692,3175218132),s(1996064986,2198950837),s(2554220882,3999719339),s(2821834349,766784016),s(2952996808,2566594879),s(3210313671,3203337956),s(3336571891,1034457026),s(3584528711,2466948901),s(113926993,3758326383),s(338241895,168717936),s(666307205,1188179964),s(773529912,1546045734),s(1294757372,1522805485),s(1396182291,2643833823),s(1695183700,2343527390),s(1986661051,1014477480),s(2177026350,1206759142),s(2456956037,344077627),s(2730485921,1290863460),s(2820302411,3158454273),s(3259730800,3505952657),s(3345764771,106217008),s(3516065817,3606008344),s(3600352804,1432725776),s(4094571909,1467031594),s(275423344,851169720),s(430227734,3100823752),s(506948616,1363258195),s(659060556,3750685593),s(883997877,3785050280),s(958139571,3318307427),s(1322822218,3812723403),s(1537002063,2003034995),s(1747873779,3602036899),s(1955562222,1575990012),s(2024104815,1125592928),s(2227730452,2716904306),s(2361852424,442776044),s(2428436474,593698344),s(2756734187,3733110249),s(3204031479,2999351573),s(3329325298,3815920427),s(3391569614,3928383900),s(3515267271,566280711),s(3940187606,3454069534),s(4118630271,4000239992),s(116418474,1914138554),s(174292421,2731055270),s(289380356,3203993006),s(460393269,320620315),s(685471733,587496836),s(852142971,1086792851),s(1017036298,365543100),s(1126000580,2618297676),s(1288033470,3409855158),s(1501505948,4234509866),s(1607167915,987167468),s(1816402316,1246189591)],u=[];!function(){for(var e=0;e<80;e++)u[e]=s()}();var l=o.SHA512=t.extend({_doReset:function(){this._hash=new a.init([new n.init(1779033703,4089235720),new n.init(3144134277,2227873595),new n.init(1013904242,4271175723),new n.init(2773480762,1595750129),new n.init(1359893119,2917565137),new n.init(2600822924,725511199),new n.init(528734635,4215389547),new n.init(1541459225,327033209)])},_doProcessBlock:function(e,t){for(var r=this._hash.words,i=r[0],n=r[1],a=r[2],o=r[3],s=r[4],l=r[5],h=r[6],d=r[7],p=i.high,f=i.low,m=n.high,g=n.low,_=a.high,v=a.low,y=o.high,b=o.low,E=s.high,w=s.low,S=l.high,k=l.low,x=h.high,M=h.low,N=d.high,j=d.low,T=p,R=f,I=m,O=g,A=_,P=v,D=y,F=b,C=E,B=w,z=S,L=k,U=x,H=M,q=N,K=j,Z=0;Z<80;Z++){var W,X,Q=u[Z];if(Z<16)X=Q.high=0|e[t+2*Z],W=Q.low=0|e[t+2*Z+1];else{var J=u[Z-15],V=J.high,G=J.low,Y=(V>>>1|G<<31)^(V>>>8|G<<24)^V>>>7,$=(G>>>1|V<<31)^(G>>>8|V<<24)^(G>>>7|V<<25),ee=u[Z-2],te=ee.high,re=ee.low,ie=(te>>>19|re<<13)^(te<<3|re>>>29)^te>>>6,ne=(re>>>19|te<<13)^(re<<3|te>>>29)^(re>>>6|te<<26),ae=u[Z-7],oe=ae.high,se=ae.low,ce=u[Z-16],ue=ce.high,le=ce.low;X=(X=(X=Y+oe+((W=$+se)>>>0<$>>>0?1:0))+ie+((W+=ne)>>>0>>0?1:0))+ue+((W+=le)>>>0>>0?1:0),Q.high=X,Q.low=W}var he,de=C&z^~C&U,pe=B&L^~B&H,fe=T&I^T&A^I&A,me=R&O^R&P^O&P,ge=(T>>>28|R<<4)^(T<<30|R>>>2)^(T<<25|R>>>7),_e=(R>>>28|T<<4)^(R<<30|T>>>2)^(R<<25|T>>>7),ve=(C>>>14|B<<18)^(C>>>18|B<<14)^(C<<23|B>>>9),ye=(B>>>14|C<<18)^(B>>>18|C<<14)^(B<<23|C>>>9),be=c[Z],Ee=be.high,we=be.low,Se=q+ve+((he=K+ye)>>>0>>0?1:0),ke=_e+me;q=U,K=H,U=z,H=L,z=C,L=B,C=D+(Se=(Se=(Se=Se+de+((he+=pe)>>>0>>0?1:0))+Ee+((he+=we)>>>0>>0?1:0))+X+((he+=W)>>>0>>0?1:0))+((B=F+he|0)>>>0>>0?1:0)|0,D=A,F=P,A=I,P=O,I=T,O=R,T=Se+(ge+fe+(ke>>>0<_e>>>0?1:0))+((R=he+ke|0)>>>0>>0?1:0)|0}f=i.low=f+R,i.high=p+T+(f>>>0>>0?1:0),g=n.low=g+O,n.high=m+I+(g>>>0>>0?1:0),v=a.low=v+P,a.high=_+A+(v>>>0

>>0?1:0),b=o.low=b+F,o.high=y+D+(b>>>0>>0?1:0),w=s.low=w+B,s.high=E+C+(w>>>0>>0?1:0),k=l.low=k+L,l.high=S+z+(k>>>0>>0?1:0),M=h.low=M+H,h.high=x+U+(M>>>0>>0?1:0),j=d.low=j+K,d.high=N+q+(j>>>0>>0?1:0)},_doFinalize:function(){var e=this._data,t=e.words,r=8*this._nDataBytes,i=8*e.sigBytes;return t[i>>>5]|=128<<24-i%32,t[30+(i+128>>>10<<5)]=Math.floor(r/4294967296),t[31+(i+128>>>10<<5)]=r,e.sigBytes=4*t.length,this._process(),this._hash.toX32()},clone:function(){var e=t.clone.call(this);return e._hash=this._hash.clone(),e},blockSize:32});e.SHA512=t._createHelper(l),e.HmacSHA512=t._createHmacHelper(l)}(),i.SHA512)},function(e,t){e.exports=class{constructor(e){this.state=Object.assign({},e)}getPrivateKeyPath(){return this.state.privateKeyPath}setPrivateKeyPath(e){return this.state.privateKeyPath=e,this}getCertificatePath(){return this.state.certificatePath}setCertificatePath(e){return this.state.certificatePath=e,this}getCertificateAuthorityFile(){return this.state.certificateAuthorityFile}setCertificateAuthorityFile(e){return this.state.certificateAuthorityFile=e,this}getAllowedFingerprints(){return this.state.allowedFingerprints}setAllowedFingerprints(e){return this.state.allowedFingerprints=e,this}getAllowAnyCert(){return this.state.allowAnyCert}setAllowAnyCert(e){return this.state.allowAnyCert=e,this}}},function(e,t,r){const i=r(7).BigInteger;e.exports=class{constructor(e){void 0===(e=Object.assign({},e)).difficulty||e.difficulty instanceof i||(e.difficulty=i.parse(e.difficulty)),this.state=e}toJson(){let e=Object.assign({},this.state);return this.getDifficulty()&&(e.difficulty=this.getDifficulty().toString()),e}getBlockHashes(e){return this.state.blockHashes}setBlockHashes(e){return this.state.blockHashes=e,this}getDifficulty(){return this.state.difficulty}setDifficulty(e){return this.state.difficulty=e,this}getHeight(){return this.state.height}setHeight(e){return this.state.height=e,this}getLength(){return this.state.length}setLength(e){return this.state.length=e,this}getMainChainParentBlockHash(){return this.state.mainChainParentBlockHash}setMainChainParentBlockHash(e){return this.state.mainChainParentBlockHash=e,this}}},function(e,t,r){const i=r(7).BigInteger;e.exports=class{constructor(e){e=Object.assign({},e),this.state=e,void 0===e.expectedReward||e.expectedReward instanceof i||(e.expectedReward=i.parse(e.expectedReward)),void 0===e.difficulty||e.difficulty instanceof i||(e.difficulty=i.parse(e.difficulty))}toJson(){let e=Object.assign({},this.state);return this.getExpectedReward()&&(e.expectedReward=this.getExpectedReward().toString()),this.getDifficulty()&&(e.difficulty=this.getDifficulty().toString()),e}toJson(){let e=Object.assign({},this.state);return e.expectedReward&&(e.expectedReward=e.expectedReward.toString()),e.difficulty&&(e.difficulty=e.difficulty.toString()),e}getBlockTemplateBlob(){return this.state.blockTemplateBlob}setBlockTemplateBlob(e){return this.state.blockTemplateBlob=e,this}getBlockHashingBlob(){return this.state.blockHashingBlob}setBlockHashingBlob(e){return this.state.blockHashingBlob=e,this}getDifficulty(){return this.state.difficulty}setDifficulty(e){return this.state.difficulty=e,this}getExpectedReward(){return this.state.expectedReward}setExpectedReward(e){return this.state.expectedReward=e,this}getHeight(){return this.state.height}setHeight(e){return this.state.height=e,this}getPrevHash(){return this.state.prevId}setPrevHash(e){return this.state.prevId=e,this}getReservedOffset(){return this.state.reservedOffset}setReservedOffset(e){return this.state.reservedOffset=e,this}getSeedHeight(){return this.state.height}setSeedHeight(e){return this.state.seedHeight=e,this}getSeedHash(){return this.state.seedHash}setSeedHash(e){return this.state.seedHash=e,this}getNextSeedHash(){return this.state.nextSeedHash}setNextSeedHash(e){return this.state.nextSeedHash=e,this}}},function(e,t){e.exports=class{constructor(e){this.state=Object.assign({},e)}toJson(){return Object.assign({},this.state)}getConnectionId(){return this.state.connectionId}setConnectionId(e){return this.state.connectionId=e,this}getNumBlocks(){return this.state.numBlocks}setNumBlocks(e){return this.state.numBlocks=e,this}getRemoteAddress(){return this.state.remoteAddress}setRemoteAddress(e){return this.state.remoteAddress=e,this}getRate(){return this.state.rate}setRate(e){return this.state.rate=e,this}getSpeed(){return this.state.speed}setSpeed(e){return this.state.speed=e,this}getSize(){return this.state.size}setSize(e){return this.state.size=e,this}getStartHeight(){return this.state.startHeight}setStartHeight(e){return this.state.startHeight=e,this}}},function(e,t,r){const i=r(7).BigInteger;e.exports=class{constructor(e){e=Object.assign({},e),this.state=e,void 0===e.difficulty||e.difficulty instanceof i||(e.difficulty=i.parse(e.difficulty)),void 0===e.cumulativeDifficulty||e.cumulativeDifficulty instanceof i||(e.cumulativeDifficulty=i.parse(e.cumulativeDifficulty)),void 0===e.credits||e.credits instanceof i||(e.credits=i.parse(e.credits))}toJson(){let e=Object.assign([],this.state);return e.difficulty&&(e.difficulty=e.difficulty.toString()),e.cumulativeDifficulty&&(e.cumulativeDifficulty=e.cumulativeDifficulty.toString()),e.credits&&(e.credits=e.credits.toString()),e}getVersion(){return this.state.version}setVersion(e){return this.state.version=e,this}getNumAltBlocks(){return this.state.numAltBlocks}setNumAltBlocks(e){return this.state.numAltBlocks=e,this}getBlockSizeLimit(){return this.state.blockSizeLimit}setBlockSizeLimit(e){return this.state.blockSizeLimit=e,this}getBlockSizeMedian(){return this.state.blockSizeMedian}setBlockSizeMedian(e){return this.state.blockSizeMedian=e,this}getBlockWeightLimit(){return this.state.blockWeightLimit}setBlockWeightLimit(e){return this.state.blockWeightLimit=e,this}getBlockWeightMedian(){return this.state.blockWeightMedian}setBlockWeightMedian(e){return this.state.blockWeightMedian=e,this}getBootstrapDaemonAddress(){return this.state.bootstrapDaemonAddress}setBootstrapDaemonAddress(e){return this.state.bootstrapDaemonAddress=e,this}getDifficulty(){return this.state.difficulty}setDifficulty(e){return this.state.difficulty=e,this}getCumulativeDifficulty(){return this.state.cumulativeDifficulty}setCumulativeDifficulty(e){return this.state.cumulativeDifficulty=e,this}getFreeSpace(){return this.state.freeSpace}setFreeSpace(e){return this.state.freeSpace=e,this}getNumOfflinePeers(){return this.state.numOfflinePeers}setNumOfflinePeers(e){return this.state.numOfflinePeers=e,this}getNumOnlinePeers(){return this.state.numOnlinePeers}setNumOnlinePeers(e){return this.state.numOnlinePeers=e,this}getHeight(){return this.state.height}setHeight(e){return this.state.height=e,this}getHeightWithoutBootstrap(){return this.state.heightWithoutBootstrap}setHeightWithoutBootstrap(e){return this.state.heightWithoutBootstrap=e,this}getNetworkType(){return this.state.networkType}setNetworkType(e){return this.state.networkType=e,this}isOffline(){return this.state.isOffline}setIsOffline(e){return this.state.isOffline=e,this}getNumIncomingConnections(){return this.state.numIncomingConnections}setNumIncomingConnections(e){return this.state.numIncomingConnections=e,this}getNumOutgoingConnections(){return this.state.numOutgoingConnections}setNumOutgoingConnections(e){return this.state.numOutgoingConnections=e,this}getNumRpcConnections(){return this.state.numRpcConnections}setNumRpcConnections(e){return this.state.numRpcConnections=e,this}getStartTimestamp(){return this.state.startTimestamp}setStartTimestamp(e){return this.state.startTimestamp=e,this}getTarget(){return this.state.target}setTarget(e){return this.state.target=e,this}getTargetHeight(){return this.state.targetHeight}setTargetHeight(e){return this.state.targetHeight=e,this}getTopBlockHash(){return this.state.topBlockHash}setTopBlockHash(e){return this.state.topBlockHash=e,this}getNumTxs(){return this.state.numTxs}setNumTxs(e){return this.state.numTxs=e,this}getNumTxsPool(){return this.state.numTxsPool}setNumTxsPool(e){return this.state.numTxsPool=e,this}getWasBootstrapEverUsed(){return this.state.wasBootstrapEverUsed}setWasBootstrapEverUsed(e){return this.state.wasBootstrapEverUsed=e,this}getDatabaseSize(){return this.state.databaseSize}setDatabaseSize(e){return this.state.databaseSize=e,this}getUpdateAvailable(){return this.state.updateAvailable}setUpdateAvailable(e){return this.state.updateAvailable=e,this}getCredits(){return this.state.credits}setCredits(e){return this.state.credits=e,this}}},function(e,t,r){const i=r(7).BigInteger,n=r(140),a=r(251);e.exports=class{constructor(e){if((e=Object.assign({},e)).connections)for(let t=0;t-1))throw new d("Listener is not registered with wallet");this._listeners.splice(t,1),0===this._listeners.length&&await this._setIsListening(!1)}getListeners(){return this._assertNotClosed(),this._listeners}async moveTo(e,t){throw this._assertNotClosed(),new Error("Not implemented")}async setDaemonConnection(e,t,r,i){this._assertNotClosed();let n=new E(e,t,r,i),a=n.getUri();t=n.getUsername(),r=n.getPassword(),i=n.getRejectUnauthorized(),a||(a=""),t||(t=""),r||(r=""),this._rejectUnauthorized=i;let o=this;return o._module.queueTask((async function(){return o._assertNotClosed(),new Promise((function(e,i){o._module.set_daemon_connection(o._cppAddress,a,t,r,(function(t){e()}))}))}))}async getDaemonConnection(){let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),new Promise((function(t,r){let i=e._module.get_daemon_connection(e._cppAddress);if(i){let r=JSON.parse(i);t(new E(r.uri,r.username,r.password,e._rejectUnauthorized))}else t()}))}))}async isConnected(){let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),new Promise((function(t,r){e._module.is_connected(e._cppAddress,(function(e){t(e)}))}))}))}async getVersion(){throw this._assertNotClosed(),new Error("Not implemented")}async getPath(){return this._assertNotClosed(),this._path}async getIntegratedAddress(e){let t=this;return t._module.queueTask((async function(){t._assertNotClosed();try{return new p(JSON.parse(t._module.get_integrated_address(t._cppAddress,"",e||"")))}catch(t){throw new d("Invalid payment ID: "+e)}}))}async decodeIntegratedAddress(e){let t=this;return t._module.queueTask((async function(){t._assertNotClosed();try{return new p(JSON.parse(t._module.decode_integrated_address(t._cppAddress,e)))}catch(t){throw new d("Invalid integrated address: "+e)}}))}async getHeight(){let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),new Promise((function(t,r){e._module.get_height(e._cppAddress,(function(e){t(e)}))}))}))}async getDaemonHeight(){if(this._assertNotClosed(),!await this.isConnected())throw new d("Wallet is not connected to daemon");let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),new Promise((function(t,r){e._module.get_daemon_height(e._cppAddress,(function(e){t(e)}))}))}))}async getHeightByDate(e,t,r){if(this._assertNotClosed(),!await this.isConnected())throw new d("Wallet is not connected to daemon");let i=this;return i._module.queueTask((async function(){return i._assertNotClosed(),new Promise((function(n,a){i._module.get_height_by_date(i._cppAddress,e,t,r,(function(e){"string"==typeof e?a(new d(e)):n(e)}))}))}))}async sync(e,t){if(this._assertNotClosed(),!await this.isConnected())throw new d("Wallet is not connected to daemon");let r,i,n=e instanceof I?e:void 0;void 0===(t=e instanceof I?t:e)&&(t=Math.max(await this.getHeight(),await this.getSyncHeight())),n&&await this.addListener(n);try{let e=this;i=await e._module.queueTask((async function(){return e._assertNotClosed(),new Promise((function(r,i){e._module.sync(e._cppAddress,t,(async function(e){if("{"!==e.charAt(0))i(new d(e));else{let t=JSON.parse(e);r(new S(t.numBlocksFetched,t.receivedMoney))}}))}))}))}catch(e){r=e}if(n&&await this.removeListener(n),r)throw r;return i}async startSyncing(){if(this._assertNotClosed(),!await this.isConnected())throw new d("Wallet is not connected to daemon");this._syncingEnabled||(this._syncingEnabled=!0,this._runSyncLoop())}async stopSyncing(){this._assertNotClosed(),this._syncingEnabled=!1,this._module.stop_syncing(this._cppAddress)}async rescanSpent(){let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),new Promise((function(t,r){e._module.rescan_spent(e._cppAddress,(function(){t()}))}))}))}async rescanBlockchain(){let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),new Promise((function(t,r){e._module.rescan_blockchain(e._cppAddress,(function(){t()}))}))}))}async getBalance(e,t){let r=this;return r._module.queueTask((async function(){let o;return r._assertNotClosed(),void 0===e?(i(void 0===t,"Subaddress index must be undefined if account index is undefined"),o=r._module.get_balance_wallet(r._cppAddress)):o=void 0===t?r._module.get_balance_account(r._cppAddress,e):r._module.get_balance_subaddress(r._cppAddress,e,t),n.parse(JSON.parse(a.stringifyBIs(o)).balance)}))}async getUnlockedBalance(e,t){let r=this;return r._module.queueTask((async function(){let o;return r._assertNotClosed(),void 0===e?(i(void 0===t,"Subaddress index must be undefined if account index is undefined"),o=r._module.get_unlocked_balance_wallet(r._cppAddress)):o=void 0===t?r._module.get_unlocked_balance_account(r._cppAddress,e):r._module.get_unlocked_balance_subaddress(r._cppAddress,e,t),n.parse(JSON.parse(a.stringifyBIs(o)).unlockedBalance)}))}async getAccounts(e,t){let r=this;return r._module.queueTask((async function(){r._assertNotClosed();let i=r._module.get_accounts(r._cppAddress,!!e,t||""),n=[];for(let e of JSON.parse(a.stringifyBIs(i)).accounts)n.push(O._sanitizeAccount(new s(e)));return n}))}async getAccount(e,t){let r=this;return r._module.queueTask((async function(){r._assertNotClosed();let i=r._module.get_account(r._cppAddress,e,!!t),n=JSON.parse(a.stringifyBIs(i));return O._sanitizeAccount(new s(n))}))}async createAccount(e){void 0===e&&(e="");let t=this;return t._module.queueTask((async function(){t._assertNotClosed();let r=t._module.create_account(t._cppAddress,e),i=JSON.parse(a.stringifyBIs(r));return O._sanitizeAccount(new s(i))}))}async getSubaddresses(e,t){let r={accountIdx:e,subaddressIndices:void 0===t?[]:a.listify(t)},i=this;return i._module.queueTask((async function(){i._assertNotClosed();let e=JSON.parse(a.stringifyBIs(i._module.get_subaddresses(i._cppAddress,JSON.stringify(r)))).subaddresses,t=[];for(let r of e)t.push(O._sanitizeSubaddress(new w(r)));return t}))}async createSubaddress(e,t){void 0===t&&(t="");let r=this;return r._module.queueTask((async function(){r._assertNotClosed();let i=r._module.create_subaddress(r._cppAddress,e,t),n=JSON.parse(a.stringifyBIs(i));return O._sanitizeSubaddress(new w(n))}))}async getTxs(e,t){this._assertNotClosed(),e=j._normalizeTxQuery(e);let r=this;return r._module.queueTask((async function(){return r._assertNotClosed(),new Promise((function(i,n){r._module.get_txs(r._cppAddress,JSON.stringify(e.getBlock().toJson()),(function(r){if("{"===r.charAt(0))try{i(O._deserializeTxs(e,r,t))}catch(e){n(e)}else n(new d(r))}))}))}))}async getTransfers(e){this._assertNotClosed(),e=j._normalizeTransferQuery(e);let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new Promise((function(r,i){t._module.get_transfers(t._cppAddress,JSON.stringify(e.getTxQuery().getBlock().toJson()),(function(t){if("{"===t.charAt(0))try{r(O._deserializeTransfers(e,t))}catch(e){i(e)}else i(new d(t))}))}))}))}async getOutputs(e){this._assertNotClosed(),e=j._normalizeOutputQuery(e);let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new Promise((function(r,i){t._module.get_outputs(t._cppAddress,JSON.stringify(e.getTxQuery().getBlock().toJson()),(function(t){if("{"===t.charAt(0))try{r(O._deserializeOutputs(e,t))}catch(e){i(e)}else i(new d(t))}))}))}))}async getOutputsHex(){let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),new Promise((function(t,r){e._module.get_outputs_hex(e._cppAddress,(function(e){t(e)}))}))}))}async importOutputsHex(e){let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new Promise((function(r,i){t._module.import_outputs_hex(t._cppAddress,e,(function(e){r(e)}))}))}))}async getKeyImages(){let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),new Promise((function(t,r){e._module.get_key_images(e._cppAddress,(function(e){let r=[];for(let t of JSON.parse(a.stringifyBIs(e)).keyImages)r.push(new f(t));t(r)}))}))}))}async importKeyImages(e){let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new Promise((function(r,i){t._module.import_key_images(t._cppAddress,JSON.stringify({keyImages:e.map(e=>e.toJson())}),(function(e){r(new m(JSON.parse(a.stringifyBIs(e))))}))}))}))}async getNewKeyImagesFromLastImport(){throw this._assertNotClosed(),new d("Not implemented")}async createTxs(e){if(this._assertNotClosed(),void 0===(e=j._normalizeCreateTxsConfig(e)).getCanSplit()&&e.setCanSplit(!0),e.getPaymentId())throw new d("Standalone payment IDs are obsolete. Use subaddresses or integrated addresses instead");let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new Promise((function(r,i){t._module.create_txs(t._cppAddress,JSON.stringify(e.toJson()),(function(e){"{"!==e.charAt(0)?i(new d(e)):r(new x(JSON.parse(a.stringifyBIs(e))).getTxs())}))}))}))}async sweepOutput(e){this._assertNotClosed(),e=j._normalizeSweepOutputConfig(e);let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new Promise((function(r,i){t._module.sweep_output(t._cppAddress,JSON.stringify(e.toJson()),(function(e){"{"!==e.charAt(0)?i(new d(e)):r(new x(JSON.parse(a.stringifyBIs(e))).getTxs()[0])}))}))}))}async sweepUnlocked(e){this._assertNotClosed(),e=j._normalizeSweepUnlockedConfig(e);let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new Promise((function(r,i){t._module.sweep_unlocked(t._cppAddress,JSON.stringify(e.toJson()),(function(e){if("{"!==e.charAt(0))i(new d(e));else{let t=[];for(let r of JSON.parse(a.stringifyBIs(e)).txSets)t.push(new x(r));let i=[];for(let e of t)for(let t of e.getTxs())i.push(t);r(i)}}))}))}))}async sweepDust(e){let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new Promise((function(r,i){t._module.sweep_dust(t._cppAddress,e,(function(e){"{"!==e.charAt(0)?i(new d(e)):r(new x(JSON.parse(a.stringifyBIs(e))).getTxs())}))}))}))}async relayTxs(e){this._assertNotClosed(),i(Array.isArray(e),"Must provide an array of txs or their metadata to relay");let t=[];for(let r of e)t.push(r instanceof M?r.getMetadata():r);let r=this;return r._module.queueTask((async function(){return r._assertNotClosed(),new Promise((function(e,i){r._module.relay_txs(r._cppAddress,JSON.stringify({txMetadatas:t}),(function(t){"{"!==t.charAt(0)?i(new d(t)):e(JSON.parse(t).txHashes)}))}))}))}async parseTxSet(e){let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new x(JSON.parse(a.stringifyBIs(t._module.parse_tx_set(t._cppAddress,JSON.stringify(e.toJson())))))}))}async signTxs(e){let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),t._module.sign_txs(t._cppAddress,e)}))}async submitTxs(e){let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new Promise((function(r,i){t._module.submit_txs(t._cppAddress,e,(function(e){r(JSON.parse(e).txHashes)}))}))}))}async signMessage(e){let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),t._module.sign_message(t._cppAddress,e)}))}async verifyMessage(e,t,r){let i=this;return i._module.queueTask((async function(){return i._assertNotClosed(),i._module.verify_message(i._cppAddress,e,t,r)}))}async getTxKey(e){let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),t._module.get_tx_key(t._cppAddress,e)}))}async checkTxKey(e,t,r){throw new Error("MoneroWalletWasm.checkTxKey() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html")}async getTxProof(e,t,r){throw new Error("MoneroWalletWasm.checkTxKey() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html")}async checkTxProof(e,t,r,i){let n=this;return n._module.queueTask((async function(){return n._assertNotClosed(),new l(JSON.parse(a.stringifyBIs(n._module.check_tx_proof(n._cppAddress,e,t,r,i))))}))}async getSpendProof(e,t){throw new Error("MoneroWalletWasm.getSpendProof() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html")}async checkSpendProof(e,t,r){let i=this;return i._module.queueTask((async function(){return i._assertNotClosed(),i._module.check_spend_proof(i._cppAddress,e,t,r)}))}async getReserveProofWallet(e){throw new Error("MoneroWalletWasm.getReserveProofWallet() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html")}async getReserveProofAccount(e,t,r){throw new Error("MoneroWalletWasm.getReserveProofAccount() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html")}async checkReserveProof(e,t,r){let i=this;return i._module.queueTask((async function(){return i._assertNotClosed(),new MoneroCheckReserve(JSON.parse(a.stringifyBIs(i._module.check_reserve_proof(i._cppAddress,e,t,r))))}))}async getTxNotes(e){let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),JSON.parse(t._module.get_tx_notes(t._cppAddress,JSON.stringify({txHashes:e}))).txNotes}))}async setTxNotes(e,t){let r=this;return r._module.queueTask((async function(){r._assertNotClosed(),r._module.set_tx_notes(r._cppAddress,JSON.stringify({txHashes:e,txNotes:t}))}))}async getAddressBookEntries(e){e||(e=[]);let t=this;return t._module.queueTask((async function(){t._assertNotClosed();let r=[];for(let i of JSON.parse(t._module.get_address_book_entries(t._cppAddress,JSON.stringify({entryIndices:e}))).entries)r.push(new c(i));return r}))}async addAddressBookEntry(e,t){e||(e=""),t||(t="");let r=this;return r._module.queueTask((async function(){return r._assertNotClosed(),r._module.add_address_book_entry(r._cppAddress,e,t)}))}async editAddressBookEntry(e,t,r,i,n){t||(t=!1),r||(r=""),i||(i=!1),n||(n="");let a=this;return a._module.queueTask((async function(){a._assertNotClosed(),a._module.edit_address_book_entry(a._cppAddress,e,t,r,i,n)}))}async deleteAddressBookEntry(e){let t=this;return t._module.queueTask((async function(){t._assertNotClosed(),t._module.delete_address_book_entry(t._cppAddress,e)}))}async tagAccounts(e,t){e||(e=""),t||(t=[]);let r=this;return r._module.queueTask((async function(){r._assertNotClosed(),r._module.tag_accounts(r._cppAddress,JSON.stringify({tag:e,accountIndices:t}))}))}async untagAccounts(e){e||(e=[]);let t=this;return t._module.queueTask((async function(){t._assertNotClosed(),t._module.tag_accounts(t._cppAddress,JSON.stringify({accountIndices:e}))}))}async getAccountTags(){let e=this;return e._module.queueTask((async function(){e._assertNotClosed();let t=[];for(let r of JSON.parse(e._module.get_account_tags(e._cppAddress)).accountTags)t.push(new MoneroAccountTag(r));return t}))}async setAccountTagLabel(e,t){e||(e=""),llabel||(t="");let r=this;return r._module.queueTask((async function(){r._assertNotClosed(),r._module.set_account_tag_label(r._cppAddress,e,t)}))}async createPaymentUri(e){e=j._normalizeCreateTxsConfig(e);let t=this;return t._module.queueTask((async function(){t._assertNotClosed();try{return t._module.create_payment_uri(t._cppAddress,JSON.stringify(e.toJson()))}catch(e){throw new d("Cannot make URI from supplied parameters")}}))}async parsePaymentUri(e){let t=this;return t._module.queueTask((async function(){t._assertNotClosed();try{return new k(JSON.parse(a.stringifyBIs(t._module.parse_payment_uri(t._cppAddress,e))))}catch(e){throw new d(e.message)}}))}async getAttribute(e){this._assertNotClosed(),i("string"==typeof e,"Attribute key must be a string");let t=this;return t._module.queueTask((async function(){t._assertNotClosed();let r=t._module.get_attribute(t._cppAddress,e);return""===r?null:r}))}async setAttribute(e,t){this._assertNotClosed(),i("string"==typeof e,"Attribute key must be a string"),i("string"==typeof t,"Attribute value must be a string");let r=this;return r._module.queueTask((async function(){r._assertNotClosed(),r._module.set_attribute(r._cppAddress,e,t)}))}async startMining(e,t,r){this._assertNotClosed();let i=new h(await this.getDaemonConnection());await i.startMining(await this.getPrimaryAddress(),e,t,r)}async stopMining(){this._assertNotClosed();let e=new h(await this.getDaemonConnection());await e.stopMining()}async isMultisigImportNeeded(){let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),e._module.is_multisig_import_needed(e._cppAddress)}))}async isMultisig(){let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),e._module.is_multisig(e._cppAddress)}))}async getMultisigInfo(){let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),new g(JSON.parse(e._module.get_multisig_info(e._cppAddress)))}))}async prepareMultisig(){let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),e._module.prepare_multisig(e._cppAddress)}))}async makeMultisig(e,t,r){let i=this;return i._module.queueTask((async function(){return i._assertNotClosed(),new _(JSON.parse(i._module.make_multisig(i._cppAddress,JSON.stringify({multisigHexes:e,threshold:t,password:r}))))}))}async exchangeMultisigKeys(e,t){let r=this;return r._module.queueTask((async function(){return r._assertNotClosed(),new _(JSON.parse(r._module.exchange_multisig_keys(r._cppAddress,JSON.stringify({multisigHexes:e,password:t}))))}))}async getMultisigHex(){let e=this;return e._module.queueTask((async function(){return e._assertNotClosed(),e._module.get_multisig_hex(e._cppAddress)}))}async importMultisigHex(e){let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new Promise((function(r,i){t._module.import_multisig_hex(t._cppAddress,JSON.stringify({multisigHexes:e}),(function(e){"string"==typeof e?i(new d(e)):r(e)}))}))}))}async signMultisigTxHex(e){let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new v(JSON.parse(t._module.sign_multisig_tx_hex(t._cppAddress,e)))}))}async submitMultisigTxHex(e){let t=this;return t._module.queueTask((async function(){return t._assertNotClosed(),new Promise((function(r,i){t._module.submit_multisig_tx_hex(t._cppAddress,e,(function(e){r(JSON.parse(e).txHashes)}))}))}))}async getData(){this._assertNotClosed();let e=await this.isViewOnly(),r=this;return r._module.queueTask((async function(){r._assertNotClosed();let i=[],n=JSON.parse(r._module.get_cache_file_buffer(r._cppAddress,r._password)),a=new DataView(new ArrayBuffer(n.length));for(let e=0;e0)throw new d("Wallet missing requested tx hashes: "+i.missingTxHashes);for(let e of i.missingTxHashes)r.push(e);let n=i.blocks,a=[];for(let e of n){O._sanitizeBlock(e);for(let t of e.getTxs())void 0===e.getHeight()&&t.setBlock(void 0),a.push(t)}if(void 0!==e.getHashes()){let t=new Map;for(let e of a)t[e.getHash()]=e;let r=[];for(let i of e.getHashes())void 0!==t[i]&&r.push(t[i]);a=r}return a}static _deserializeTransfers(e,t){let r=O._deserializeBlocks(t);if(r.missingTxHashes.length>0)throw new d("Wallet missing requested tx hashes: "+r.missingTxHashes);let i=r.blocks,n=[];for(let e of i)for(let t of e.getTxs())if(void 0===e.getHeight()&&t.setBlock(void 0),void 0!==t.getOutgoingTransfer()&&n.push(t.getOutgoingTransfer()),void 0!==t.getIncomingTransfers())for(let e of t.getIncomingTransfers())n.push(e);return n}static _deserializeOutputs(e,t){let r=O._deserializeBlocks(t);if(r.missingTxHashes.length>0)throw new d("Wallet missing requested tx hashes: "+r.missingTxHashes);let i=r.blocks,n=[];for(let e of i)for(let t of e.getTxs())for(let e of t.getOutputs())n.push(e);return n}_setBrowserMainPath(e){this._browserMainPath=e}}class A{constructor(e){this._wallet=e}onSyncProgress(e,t,r,i,n){for(let a of this._wallet.getListeners())a.onSyncProgress(e,t,r,i,n)}onNewBlock(e){for(let t of this._wallet.getListeners())t.onNewBlock(e)}onBalancesChanged(e,t){for(let r of this._wallet.getListeners())r.onBalancesChanged(n.parse(e),n.parse(t))}onOutputReceived(e,t,r,i,a,o,s,c){let l=new b;l.setAmount(n.parse(r)),l.setAccountIndex(i),l.setSubaddressIndex(a);let h=new M;if(h.setHash(t),h.setVersion(o),h.setUnlockHeight(s),l.setTx(h),h.setOutputs([l]),h.setIsIncoming(!0),h.setIsLocked(c),e>0){let t=(new u).setHeight(e);t.setTxs([h]),h.setBlock(t),h.setIsConfirmed(!0),h.setInTxPool(!1),h.setIsFailed(!1)}else h.setIsConfirmed(!1),h.setInTxPool(!0);for(let e of this._wallet.getListeners())e.onOutputReceived(h.getOutputs()[0])}onOutputSpent(e,t,r,i,a,o){let s=new b;s.setAmount(n.parse(r)),s.setAccountIndex(i),s.setSubaddressIndex(a);let c=new M;if(c.setHash(t),c.setVersion(o),s.setTx(c),c.setInputs([s]),e>0){let t=(new u).setHeight(e);t.setTxs([c]),c.setBlock(t),c.setIsConfirmed(!0),c.setInTxPool(!1),c.setIsFailed(!1)}else c.setIsConfirmed(!1),c.setInTxPool(!0);for(let e of this._wallet.getListeners())e.onOutputSpent(c.getInputs()[0])}}class P extends j{static async openWalletData(e,t,r,i,n,s,c){let u=a.getUUID(),l=s instanceof E?s.getConfig():s;await o.invokeWorker(u,"openWalletData",[e,t,r,i,n,l]);let h=new P(u,o.getWorker(),e,c);return e&&await h.save(),h}static async _createWalletRandom(e,t,r,i,n,s){if(e&&await O.walletExists(e,s))throw new Error("Wallet already exists: "+e);let c=a.getUUID(),u=i instanceof E?i.getConfig():i;await o.invokeWorker(c,"_createWalletRandom",[e,t,r,u,n]);let l=new P(c,o.getWorker(),e,s);return e&&await l.save(),l}static async _createWalletFromMnemonic(e,t,r,i,n,s,c,u){if(e&&await O.walletExists(e,u))throw new Error("Wallet already exists: "+e);let l=a.getUUID(),h=n instanceof E?n.getConfig():n;await o.invokeWorker(l,"_createWalletFromMnemonic",[e,t,r,i,h,s,c]);let d=new P(l,o.getWorker(),e,u);return e&&await d.save(),d}static async _createWalletFromKeys(e,t,r,i,n,s,c,u,l,h){if(e&&await O.walletExists(e,h))throw new Error("Wallet already exists: "+e);let d=a.getUUID(),p=c instanceof E?c.getConfig():c;await o.invokeWorker(d,"_createWalletFromKeys",[e,t,r,i,n,s,p,u,l]);let f=new P(d,o.getWorker(),e,h);return e&&await f.save(),f}constructor(e,t,r,i){super(),this._walletId=e,this._worker=t,this._path=r,this._fs=i||(r?O._getFs():void 0),this._wrappedListeners=[]}async isViewOnly(){return this._invokeWorker("isViewOnly")}async getNetworkType(){return this._invokeWorker("getNetworkType")}async getVersion(){throw new Error("Not implemented")}getPath(){return this._path}async getMnemonic(){return this._invokeWorker("getMnemonic")}async getMnemonicLanguage(){return this._invokeWorker("getMnemonicLanguage")}async getMnemonicLanguages(){return this._invokeWorker("getMnemonicLanguages")}async getPrivateSpendKey(){return this._invokeWorker("getPrivateSpendKey")}async getPrivateViewKey(){return this._invokeWorker("getPrivateViewKey")}async getPublicViewKey(){return this._invokeWorker("getPublicViewKey")}async getPublicSpendKey(){return this._invokeWorker("getPublicSpendKey")}async getAddress(e,t){return this._invokeWorker("getAddress",Array.from(arguments))}async getAddressIndex(e){let t=await this._invokeWorker("getAddressIndex",Array.from(arguments));return O._sanitizeSubaddress(new w(t))}async getIntegratedAddress(e){return new p(await this._invokeWorker("getIntegratedAddress",Array.from(arguments)))}async decodeIntegratedAddress(e){return new p(await this._invokeWorker("decodeIntegratedAddress",Array.from(arguments)))}async setDaemonConnection(e,t,r){if(e){let i=e instanceof E?e:new E({uri:e,username:t,password:r});await this._invokeWorker("setDaemonConnection",i.getConfig())}else await this._invokeWorker("setDaemonConnection")}async getDaemonConnection(){let e=await this._invokeWorker("getDaemonConnection");return e?new E(e):void 0}async isConnected(){return this._invokeWorker("isConnected")}async getSyncHeight(){return this._invokeWorker("getSyncHeight")}async setSyncHeight(e){return this._invokeWorker("setSyncHeight",[e])}async getDaemonHeight(){return this._invokeWorker("getDaemonHeight")}async getDaemonMaxPeerHeight(){return this._invokeWorker("getDaemonMaxPeerHeight")}async getHeightByDate(e,t,r){return this._invokeWorker("getHeightByDate",[e,t,r])}async isDaemonSynced(){return this._invokeWorker("isDaemonSynced")}async getHeight(){return this._invokeWorker("getHeight")}async addListener(e){let t=new D(e),r=t.getId();return o.WORKER_OBJECTS[this._walletId].callbacks["onSyncProgress_"+r]=[t.onSyncProgress,t],o.WORKER_OBJECTS[this._walletId].callbacks["onNewBlock_"+r]=[t.onNewBlock,t],o.WORKER_OBJECTS[this._walletId].callbacks["onBalancesChanged_"+r]=[t.onBalancesChanged,t],o.WORKER_OBJECTS[this._walletId].callbacks["onOutputReceived_"+r]=[t.onOutputReceived,t],o.WORKER_OBJECTS[this._walletId].callbacks["onOutputSpent_"+r]=[t.onOutputSpent,t],this._wrappedListeners.push(t),this._invokeWorker("addListener",[r])}async removeListener(e){for(let t=0;t=2,"Must provide a function name with length >= 2"),!self[r])throw new Error("Method '"+r+"' is not registered with worker");e.data.splice(1,1);let n="on"+r.charAt(0).toUpperCase()+r.substring(1);try{postMessage([t,n,{result:await self[r].apply(null,e.data)}])}catch(e){postMessage([t,n,{error:e.message}])}},self.initOneTime=async function(){self.isInitialized||(self.WORKER_OBJECTS={},self.isInitialized=!0)},self.getWasmMemoryUsed=async function(e){return a.getWasmModule()&&a.getWasmModule().HEAP8?a.getWasmModule().HEAP8.length:void 0},self.connectDaemonRpc=async function(e,t){self.WORKER_OBJECTS[e]=new c(t)},self.daemonGetRpcConnection=async function(e){let t=await self.WORKER_OBJECTS[e].getRpcConnection();return t?t.getConfig():void 0},self.daemonIsConnected=async function(e){return self.WORKER_OBJECTS[e].isConnected()},self.daemonGetVersion=async function(e){return(await self.WORKER_OBJECTS[e].getVersion()).toJson()},self.daemonIsTrusted=async function(e){return self.WORKER_OBJECTS[e].isTrusted()},self.daemonGetHeight=async function(e){return self.WORKER_OBJECTS[e].getHeight()},self.daemonGetBlockHash=async function(e,t){return self.WORKER_OBJECTS[e].getBlockHash(t)},self.daemonGetBlockTemplate=async function(e,t,r){return(await self.WORKER_OBJECTS[e].getBlockTemplate(t,r)).toJson()},self.daemonGetLastBlockHeader=async function(e){return(await self.WORKER_OBJECTS[e].getLastBlockHeader()).toJson()},self.daemonGetBlockHeaderByHash=async function(e,t){return(await self.WORKER_OBJECTS[e].getBlockHeaderByHash(t)).toJson()},self.daemonGetBlockHeaderByHeight=async function(e,t){return(await self.WORKER_OBJECTS[e].getBlockHeaderByHeight(t)).toJson()},self.daemonGetBlockHeadersByRange=async function(e,t,r){let i=[];for(let n of await self.WORKER_OBJECTS[e].getBlockHeadersByRange(t,r))i.push(n.toJson());return i},self.daemonGetBlockByHash=async function(e,t){return(await self.WORKER_OBJECTS[e].getBlockByHash(t)).toJson()},self.daemonGetBlocksByHash=async function(e,t,r,i){let n=[];for(let a of await self.WORKER_OBJECTS[e].getBlocksByHash(t,r,i))n.push(a.toJson());return n},self.daemonGetBlockByHeight=async function(e,t){return(await self.WORKER_OBJECTS[e].getBlockByHeight(t)).toJson()},self.daemonGetBlocksByHeight=async function(e,t){let r=[];for(let i of await self.WORKER_OBJECTS[e].getBlocksByHeight(t))r.push(i.toJson());return r},self.daemonGetBlocksByRange=async function(e,t,r){let i=[];for(let n of await self.WORKER_OBJECTS[e].getBlocksByRange(t,r))i.push(n.toJson());return i},self.daemonGetBlocksByRangeChunked=async function(e,t,r,i){let n=[];for(let a of await self.WORKER_OBJECTS[e].getBlocksByRangeChunked(t,r,i))n.push(a.toJson());return n},self.daemonGetBlockHashes=async function(e,t,r){throw new Error("worker.getBlockHashes not implemented")},self.daemonGetTxs=async function(e,t,r){let i=await self.WORKER_OBJECTS[e].getTxs(t,r),n=[],a=void 0,o=new Set;for(let e of i)e.getBlock()||(a||(a=(new s).setTxs([])),e.setBlock(a),a.getTxs().push(e)),o.has(e.getBlock())||(o.add(e.getBlock()),n.push(e.getBlock()));for(let e=0;e1&&(d=i.argv[1].replace(/\\/g,"/")),h=i.argv.slice(2),i.on("unhandledRejection",Ge),p=function(e){i.exit(e)},c.inspect=function(){return"[Emscripten Module object]"};else if(_)"undefined"!=typeof read&&(v=function(e){return read(e)}),y=function(e){var t;return"function"==typeof readbuffer?new Uint8Array(readbuffer(e)):(q("object"==typeof(t=read(e,"binary"))),t)},"undefined"!=typeof scriptArgs?h=scriptArgs:void 0!==arguments&&(h=arguments),"function"==typeof quit&&(p=function(e){quit(e)}),"undefined"!=typeof print&&("undefined"==typeof console&&(console={}),console.log=print,console.warn=console.error="undefined"!=typeof printErr?printErr:print);else{if(!f&&!m)throw new Error("environment detection error");m?w=self.location.href:document.currentScript&&(w=document.currentScript.src),o&&(w=o),w=0!==w.indexOf("blob:")?w.substr(0,w.lastIndexOf("/")+1):"",v=function(e){var t=new XMLHttpRequest;return t.open("GET",e,!1),t.send(null),t.responseText},m&&(y=function(e){var t=new XMLHttpRequest;return t.open("GET",e,!1),t.responseType="arraybuffer",t.send(null),new Uint8Array(t.response)})}var k=c.print||console.log.bind(console),x=c.printErr||console.warn.bind(console);for(u in l)l.hasOwnProperty(u)&&(c[u]=l[u]);l=null,c.arguments&&(h=c.arguments),Object.getOwnPropertyDescriptor(c,"arguments")||Object.defineProperty(c,"arguments",{configurable:!0,get:function(){Ge("Module.arguments has been replaced with plain arguments_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),c.thisProgram&&(d=c.thisProgram),Object.getOwnPropertyDescriptor(c,"thisProgram")||Object.defineProperty(c,"thisProgram",{configurable:!0,get:function(){Ge("Module.thisProgram has been replaced with plain thisProgram (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),c.quit&&(p=c.quit),Object.getOwnPropertyDescriptor(c,"quit")||Object.defineProperty(c,"quit",{configurable:!0,get:function(){Ge("Module.quit has been replaced with plain quit_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),q(void 0===c.memoryInitializerPrefixURL,"Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead"),q(void 0===c.pthreadMainPrefixURL,"Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead"),q(void 0===c.cdInitializerPrefixURL,"Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead"),q(void 0===c.filePackagePrefixURL,"Module.filePackagePrefixURL option was removed, use Module.locateFile instead"),q(void 0===c.read,"Module.read option was removed (modify read_ in JS)"),q(void 0===c.readAsync,"Module.readAsync option was removed (modify readAsync in JS)"),q(void 0===c.readBinary,"Module.readBinary option was removed (modify readBinary in JS)"),q(void 0===c.setWindowTitle,"Module.setWindowTitle option was removed (modify setWindowTitle in JS)"),q(void 0===c.TOTAL_MEMORY,"Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY"),Object.getOwnPropertyDescriptor(c,"read")||Object.defineProperty(c,"read",{configurable:!0,get:function(){Ge("Module.read has been replaced with plain read_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),Object.getOwnPropertyDescriptor(c,"readAsync")||Object.defineProperty(c,"readAsync",{configurable:!0,get:function(){Ge("Module.readAsync has been replaced with plain readAsync (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),Object.getOwnPropertyDescriptor(c,"readBinary")||Object.defineProperty(c,"readBinary",{configurable:!0,get:function(){Ge("Module.readBinary has been replaced with plain readBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),Object.getOwnPropertyDescriptor(c,"setWindowTitle")||Object.defineProperty(c,"setWindowTitle",{configurable:!0,get:function(){Ge("Module.setWindowTitle has been replaced with plain setWindowTitle (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});var M=16;function N(e,t){return t||(t=M),Math.ceil(e/t)*t}function j(e){j.shown||(j.shown={}),j.shown[e]||(j.shown[e]=1,x(e))}function T(e,t){if("function"==typeof WebAssembly.Function){for(var r={i:"i32",j:"i64",f:"f32",d:"f64"},i={parameters:[],results:"v"==t[0]?[]:[r[t[0]]]},n=1;n>>0)+4294967296*+(t>>>0):+(e>>>0)+4294967296*+(0|t)}var D,F,C,B=0,z=function(e){B=e},L=function(){return B};c.wasmBinary&&(D=c.wasmBinary),Object.getOwnPropertyDescriptor(c,"wasmBinary")||Object.defineProperty(c,"wasmBinary",{configurable:!0,get:function(){Ge("Module.wasmBinary has been replaced with plain wasmBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),c.noExitRuntime&&(F=c.noExitRuntime),Object.getOwnPropertyDescriptor(c,"noExitRuntime")||Object.defineProperty(c,"noExitRuntime",{configurable:!0,get:function(){Ge("Module.noExitRuntime has been replaced with plain noExitRuntime (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),"object"!=typeof WebAssembly&&Ge("no native wasm support detected");var U=new WebAssembly.Table({initial:1906,maximum:1911,element:"anyfunc"}),H=!1;function q(e,t){e||Ge("Assertion failed: "+t)}var K="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0;function Z(e,t,r){for(var i=t+r,n=t;e[n]&&!(n>=i);)++n;if(n-t>16&&e.subarray&&K)return K.decode(e.subarray(t,n));for(var a="";t>10,56320|1023&u)}}else a+=String.fromCharCode((31&o)<<6|s)}else a+=String.fromCharCode(o)}return a}function W(e,t){return e?Z(ce,e,t):""}function X(e,t,r,i){if(!(i>0))return 0;for(var n=r,a=r+i-1,o=0;o=55296&&s<=57343&&(s=65536+((1023&s)<<10)|1023&e.charCodeAt(++o)),s<=127){if(r>=a)break;t[r++]=s}else if(s<=2047){if(r+1>=a)break;t[r++]=192|s>>6,t[r++]=128|63&s}else if(s<=65535){if(r+2>=a)break;t[r++]=224|s>>12,t[r++]=128|s>>6&63,t[r++]=128|63&s}else{if(r+3>=a)break;s>=2097152&&j("Invalid Unicode code point 0x"+s.toString(16)+" encountered when serializing a JS string to an UTF-8 string on the asm.js/wasm heap! (Valid unicode code points should be in range 0-0x1FFFFF)."),t[r++]=240|s>>18,t[r++]=128|s>>12&63,t[r++]=128|s>>6&63,t[r++]=128|63&s}}return t[r]=0,r-n}function Q(e,t,r){return q("number"==typeof r,"stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!"),X(e,ce,t,r)}function J(e){for(var t=0,r=0;r=55296&&i<=57343&&(i=65536+((1023&i)<<10)|1023&e.charCodeAt(++r)),i<=127?++t:t+=i<=2047?2:i<=65535?3:4}return t}var V="undefined"!=typeof TextDecoder?new TextDecoder("utf-16le"):void 0;function G(e,t){q(e%2==0,"Pointer passed to UTF16ToString must be aligned to two bytes!");for(var r=e,i=r>>1,n=i+t/2;!(i>=n)&&le[i];)++i;if((r=i<<1)-e>32&&V)return V.decode(ce.subarray(e,r));for(var a=0,o="";;){var s=ue[e+2*a>>1];if(0==s||a==t/2)return o;++a,o+=String.fromCharCode(s)}}function Y(e,t,r){if(q(t%2==0,"Pointer passed to stringToUTF16 must be aligned to two bytes!"),q("number"==typeof r,"stringToUTF16(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!"),void 0===r&&(r=2147483647),r<2)return 0;for(var i=t,n=(r-=2)<2*e.length?r/2:e.length,a=0;a>1]=o,t+=2}return ue[t>>1]=0,t-i}function $(e){return 2*e.length}function ee(e,t){q(e%4==0,"Pointer passed to UTF32ToString must be aligned to four bytes!");for(var r=0,i="";!(r>=t/4);){var n=he[e+4*r>>2];if(0==n)break;if(++r,n>=65536){var a=n-65536;i+=String.fromCharCode(55296|a>>10,56320|1023&a)}else i+=String.fromCharCode(n)}return i}function te(e,t,r){if(q(t%4==0,"Pointer passed to stringToUTF32 must be aligned to four bytes!"),q("number"==typeof r,"stringToUTF32(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!"),void 0===r&&(r=2147483647),r<4)return 0;for(var i=t,n=i+r-4,a=0;a=55296&&o<=57343&&(o=65536+((1023&o)<<10)|1023&e.charCodeAt(++a)),he[t>>2]=o,(t+=4)+4>n)break}return he[t>>2]=0,t-i}function re(e){for(var t=0,r=0;r=55296&&i<=57343&&++r,t+=4}return t}function ie(e){var t=J(e)+1,r=wn(t);return r&&X(e,se,r,t),r}function ne(e,t){q(e.length>=0,"writeArrayToMemory array must have a length (should be an array or typed array)"),se.set(e,t)}function ae(e,t,r){for(var i=0;i>0]=e.charCodeAt(i);r||(se[t>>0]=0)}var oe,se,ce,ue,le,he,de,pe,fe,me=65536;function ge(e,t){return e%t>0&&(e+=t-e%t),e}function _e(e){oe=e,c.HEAP8=se=new Int8Array(e),c.HEAP16=ue=new Int16Array(e),c.HEAP32=he=new Int32Array(e),c.HEAPU8=ce=new Uint8Array(e),c.HEAPU16=le=new Uint16Array(e),c.HEAPU32=de=new Uint32Array(e),c.HEAPF32=pe=new Float32Array(e),c.HEAPF64=fe=new Float64Array(e)}var ve=5660288,ye=417408,be=5660288,Ee=417232;q(ve%16==0,"stack must start aligned"),q(be%16==0,"heap must start aligned");var we=5242880;c.TOTAL_STACK&&q(we===c.TOTAL_STACK,"the stack size can no longer be determined at runtime");var Se=c.INITIAL_MEMORY||16777216;function ke(){q(0==(3&ye)),de[1+(ye>>2)]=34821223,de[2+(ye>>2)]=2310721022,he[0]=1668509029}function xe(){var e=de[1+(ye>>2)],t=de[2+(ye>>2)];34821223==e&&2310721022==t||Ge("Stack overflow! Stack cookie has been overwritten, expected hex dwords 0x89BACDFE and 0x2135467, but received 0x"+t.toString(16)+" "+e.toString(16)),1668509029!==he[0]&&Ge("Runtime error: The application has corrupted its heap memory area (address zero)!")}function Me(e){for(;e.length>0;){var t=e.shift();if("function"!=typeof t){var r=t.func;"number"==typeof r?void 0===t.arg?c.dynCall_v(r):c.dynCall_vi(r,t.arg):r(void 0===t.arg?null:t.arg)}else t(c)}}Object.getOwnPropertyDescriptor(c,"INITIAL_MEMORY")||Object.defineProperty(c,"INITIAL_MEMORY",{configurable:!0,get:function(){Ge("Module.INITIAL_MEMORY has been replaced with plain INITIAL_INITIAL_MEMORY (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),q(Se>=we,"INITIAL_MEMORY should be larger than TOTAL_STACK, was "+Se+"! (TOTAL_STACK="+we+")"),q("undefined"!=typeof Int32Array&&"undefined"!=typeof Float64Array&&void 0!==Int32Array.prototype.subarray&&void 0!==Int32Array.prototype.set,"JS engine does not provide full typed array support"),(C=c.wasmMemory?c.wasmMemory:new WebAssembly.Memory({initial:Se/me,maximum:2147483648/me}))&&(oe=C.buffer),q((Se=oe.byteLength)%me==0),q(65536%me==0),_e(oe),he[Ee>>2]=be,function(){var e=new Int16Array(1),t=new Int8Array(e.buffer);if(e[0]=25459,115!==t[0]||99!==t[1])throw"Runtime error: expected the system to be little-endian!"}();var Ne=[],je=[],Te=[],Re=[],Ie=!1,Oe=!1;function Ae(){if(c.preRun)for("function"==typeof c.preRun&&(c.preRun=[c.preRun]);c.preRun.length;)Be(c.preRun.shift());Me(Ne)}function Pe(){xe(),q(!Ie),Ie=!0,c.noFSInit||ar.init.initialized||ar.init(),tr.init(),Me(je)}function De(){xe(),ar.ignorePermissions=!1,Me(Te)}function Fe(){xe(),Oe=!0}function Ce(){if(xe(),c.postRun)for("function"==typeof c.postRun&&(c.postRun=[c.postRun]);c.postRun.length;)ze(c.postRun.shift());Me(Re)}function Be(e){Ne.unshift(e)}function ze(e){Re.unshift(e)}q(Math.imul,"This browser does not support Math.imul(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill"),q(Math.fround,"This browser does not support Math.fround(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill"),q(Math.clz32,"This browser does not support Math.clz32(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill"),q(Math.trunc,"This browser does not support Math.trunc(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");var Le=Math.abs,Ue=Math.ceil,He=Math.floor,qe=Math.min,Ke=0,Ze=null,We=null,Xe={};function Qe(e){for(var t=e;;){if(!Xe[e])return e;e=t+Math.random()}}function Je(e){Ke++,c.monitorRunDependencies&&c.monitorRunDependencies(Ke),e?(q(!Xe[e]),Xe[e]=1,null===Ze&&"undefined"!=typeof setInterval&&(Ze=setInterval((function(){if(H)return clearInterval(Ze),void(Ze=null);var e=!1;for(var t in Xe)e||(e=!0,x("still waiting on run dependencies:")),x("dependency: "+t);e&&x("(end of list)")}),1e4))):x("warning: run dependency added without ID")}function Ve(e){if(Ke--,c.monitorRunDependencies&&c.monitorRunDependencies(Ke),e?(q(Xe[e]),delete Xe[e]):x("warning: run dependency removed without ID"),0==Ke&&(null!==Ze&&(clearInterval(Ze),Ze=null),We)){var t=We;We=null,t()}}function Ge(e){c.onAbort&&c.onAbort(e),x(e+=""),H=!0,e="abort("+e+") at "+pt();var t=new WebAssembly.RuntimeError(e);throw s(t),t}function Ye(e,t){return String.prototype.startsWith?e.startsWith(t):0===e.indexOf(t)}c.preloadedImages={},c.preloadedAudios={};var $e="data:application/octet-stream;base64,";function et(e){return Ye(e,$e)}var tt="file://";function rt(e){return Ye(e,tt)}function it(e,t){return function(){var r=e,i=t;return t||(i=c.asm),q(Ie,"native function `"+r+"` called before runtime initialization"),q(!Oe,"native function `"+r+"` called after runtime exit (use NO_EXIT_RUNTIME to keep it alive after main() exits)"),i[e]||q(i[e],"exported native function `"+r+"` not found"),i[e].apply(null,arguments)}}var nt,at,ot="monero_core_keys.wasm";function st(){try{if(D)return new Uint8Array(D);if(y)return y(ot);throw"both async and sync fetching of the wasm failed"}catch(e){Ge(e)}}function ct(){return D||!f&&!m||"function"!=typeof fetch||rt(ot)?new Promise((function(e,t){e(st())})):fetch(ot,{credentials:"same-origin"}).then((function(e){if(!e.ok)throw"failed to load wasm binary file at '"+ot+"'";return e.arrayBuffer()})).catch((function(){return st()}))}function ut(){var e={env:bn,wasi_snapshot_preview1:bn};function t(e,t){var r=e.exports;c.asm=r,Ve("wasm-instantiate")}Je("wasm-instantiate");var r=c;function i(e){q(c===r,"the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?"),r=null,t(e.instance)}function n(t){return ct().then((function(t){return WebAssembly.instantiate(t,e)})).then(t,(function(e){x("failed to asynchronously prepare wasm: "+e),Ge(e)}))}if(c.instantiateWasm)try{return c.instantiateWasm(e,t)}catch(e){return x("Module.instantiateWasm callback failed with error: "+e),!1}return function(){if(D||"function"!=typeof WebAssembly.instantiateStreaming||et(ot)||rt(ot)||"function"!=typeof fetch)return n(i);fetch(ot,{credentials:"same-origin"}).then((function(t){return WebAssembly.instantiateStreaming(t,e).then(i,(function(e){return x("wasm streaming compile failed: "+e),x("falling back to ArrayBuffer instantiation"),n(i)}))}))}(),{}}function lt(e){return j("warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling"),e}function ht(e){return e.replace(/\b_Z[\w\d_]+/g,(function(e){var t=lt(e);return e===t?e:t+" ["+e+"]"}))}function dt(){var e=new Error;if(!e.stack){try{throw new Error}catch(t){e=t}if(!e.stack)return"(no stack trace available)"}return e.stack.toString()}function pt(){var e=dt();return c.extraStackTrace&&(e+="\n"+c.extraStackTrace()),ht(e)}function ft(){x("missing function: CONF_modules_unload"),Ge(-1)}function mt(){x("missing function: ERR_reason_error_string"),Ge(-1)}function gt(){x("missing function: _ZN5boost11regex_errorC1ERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_15regex_constants10error_typeEl"),Ge(-1)}function _t(){x("missing function: _ZN5boost11regex_errorD1Ev"),Ge(-1)}function vt(){x("missing function: _ZN5boost16re_detail_10720011raw_storage6insertEmm"),Ge(-1)}function yt(){x("missing function: _ZN5boost16re_detail_10720011raw_storage6resizeEm"),Ge(-1)}function bt(){x("missing function: _ZN5boost16re_detail_10720013get_mem_blockEv"),Ge(-1)}function Et(){x("missing function: _ZN5boost16re_detail_10720013put_mem_blockEPv"),Ge(-1)}function wt(){x("missing function: _ZN5boost16re_detail_10720014verify_optionsEjNS_15regex_constants12_match_flagsE"),Ge(-1)}function St(){x("missing function: _ZN5boost16re_detail_10720019raise_runtime_errorERKSt13runtime_error"),Ge(-1)}function kt(){x("missing function: _ZN5boost16re_detail_10720024get_default_error_stringENS_15regex_constants10error_typeE"),Ge(-1)}function xt(){x("missing function: _ZN5boost16re_detail_10720027cpp_regex_traits_char_layerIcE4initEv"),Ge(-1)}function Mt(){x("missing function: _ZN5boost16re_detail_10720027lookup_default_collate_nameERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE"),Ge(-1)}function Nt(){x("missing function: _ZN5boost24scoped_static_mutex_lockC1ERNS_12static_mutexEb"),Ge(-1)}function jt(){x("missing function: _ZN5boost24scoped_static_mutex_lockD1Ev"),Ge(-1)}function Tt(){x("missing function: _ZNK5boost11regex_error5raiseEv"),Ge(-1)}function Rt(e,t,r,i){Ge("Assertion failed: "+W(e)+", at: "+[t?W(t):"unknown filename",r,i?W(i):"unknown function"])}et(ot)||(ot=S(ot)),je.push({func:function(){En()}});var It={DESTRUCTOR_OFFSET:0,REFCOUNT_OFFSET:4,TYPE_OFFSET:8,CAUGHT_OFFSET:12,RETHROWN_OFFSET:13,SIZE:16};function Ot(e){return wn(e+It.SIZE)+It.SIZE}function At(e,t){j("atexit() called, but EXIT_RUNTIME is not set, so atexits() will not be called. set EXIT_RUNTIME to 1 (see the FAQ)")}function Pt(e,t){return At()}function Dt(e){this.excPtr=e,this.ptr=e-It.SIZE,this.set_type=function(e){he[this.ptr+It.TYPE_OFFSET>>2]=e},this.get_type=function(){return he[this.ptr+It.TYPE_OFFSET>>2]},this.set_destructor=function(e){he[this.ptr+It.DESTRUCTOR_OFFSET>>2]=e},this.get_destructor=function(){return he[this.ptr+It.DESTRUCTOR_OFFSET>>2]},this.set_refcount=function(e){he[this.ptr+It.REFCOUNT_OFFSET>>2]=e},this.set_caught=function(e){e=e?1:0,se[this.ptr+It.CAUGHT_OFFSET>>0]=e},this.get_caught=function(){return 0!=se[this.ptr+It.CAUGHT_OFFSET>>0]},this.set_rethrown=function(e){e=e?1:0,se[this.ptr+It.RETHROWN_OFFSET>>0]=e},this.get_rethrown=function(){return 0!=se[this.ptr+It.RETHROWN_OFFSET>>0]},this.init=function(e,t){this.set_type(e),this.set_destructor(t),this.set_refcount(0),this.set_caught(!1),this.set_rethrown(!1)},this.add_ref=function(){var e=he[this.ptr+It.REFCOUNT_OFFSET>>2];he[this.ptr+It.REFCOUNT_OFFSET>>2]=e+1},this.release_ref=function(){var e=he[this.ptr+It.REFCOUNT_OFFSET>>2];return he[this.ptr+It.REFCOUNT_OFFSET>>2]=e-1,q(e>0),1===e}}function Ft(e){this.free=function(){Sn(this.ptr),this.ptr=0},this.set_base_ptr=function(e){he[this.ptr>>2]=e},this.get_base_ptr=function(){return he[this.ptr>>2]},this.set_adjusted_ptr=function(e){he[this.ptr+4>>2]=e},this.get_adjusted_ptr=function(){return he[this.ptr+4>>2]},this.get_exception_ptr=function(){if(Pn(this.get_exception_info().get_type()))return he[this.get_base_ptr()>>2];var e=this.get_adjusted_ptr();return 0!==e?e:this.get_base_ptr()},this.get_exception_info=function(){return new Dt(this.get_base_ptr())},void 0===e?(this.ptr=wn(8),this.set_adjusted_ptr(0)):this.ptr=e}var Ct=[];function Bt(e){e.add_ref()}function zt(e){var t=new Ft(e),r=t.get_exception_info();return r.get_caught()||(r.set_caught(!0),On.uncaught_exceptions--),r.set_rethrown(!1),Ct.push(t),Bt(r),t.get_exception_ptr()}var Lt=0;function Ut(e){try{return Sn(new Dt(e).ptr)}catch(e){x("exception during cxa_free_exception: "+e)}}function Ht(e){if(e.release_ref()&&!e.get_rethrown()){var t=e.get_destructor();t&&c.dynCall_ii(t,e.excPtr),Ut(e.excPtr)}}function qt(){Tn(0),q(Ct.length>0);var e=Ct.pop();Ht(e.get_exception_info()),e.free(),Lt=0}function Kt(e){var t=new Ft(e),r=t.get_base_ptr();throw Lt||(Lt=r),t.free(),r}function Zt(){var e=Lt;if(!e)return 0|(z(0),0);var t=new Dt(e),r=t.get_type(),i=new Ft;if(i.set_base_ptr(e),!r)return 0|(z(0),i.ptr);var n=Array.prototype.slice.call(arguments),a=417392;he[a>>2]=e;for(var o=0;o>2];return e!==c&&i.set_adjusted_ptr(c),0|(z(s),i.ptr)}}return 0|(z(r),i.ptr)}function Wt(){var e=Lt;if(!e)return 0|(z(0),0);var t=new Dt(e),r=t.get_type(),i=new Ft;if(i.set_base_ptr(e),!r)return 0|(z(0),i.ptr);var n=Array.prototype.slice.call(arguments),a=417392;he[a>>2]=e;for(var o=0;o>2];return e!==c&&i.set_adjusted_ptr(c),0|(z(s),i.ptr)}}return 0|(z(r),i.ptr)}function Xt(){var e=Ct.pop(),t=e.get_exception_info(),r=e.get_base_ptr();throw t.get_rethrown()?e.free():(Ct.push(e),t.set_rethrown(!0)),Lt=r,r}function Qt(e,t,r){throw new Dt(e).init(t,r),Lt=e,"uncaught_exception"in On?On.uncaught_exceptions++:On.uncaught_exceptions=1,e}function Jt(){return On.uncaught_exceptions}function Vt(){Ge("stack overflow")}function Gt(e){return he[kn()>>2]=e,e}function Yt(e,t){return Gt(63),-1}var $t={splitPath:function(e){return/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(e).slice(1)},normalizeArray:function(e,t){for(var r=0,i=e.length-1;i>=0;i--){var n=e[i];"."===n?e.splice(i,1):".."===n?(e.splice(i,1),r++):r&&(e.splice(i,1),r--)}if(t)for(;r;r--)e.unshift("..");return e},normalize:function(e){var t="/"===e.charAt(0),r="/"===e.substr(-1);return(e=$t.normalizeArray(e.split("/").filter((function(e){return!!e})),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e},dirname:function(e){var t=$t.splitPath(e),r=t[0],i=t[1];return r||i?(i&&(i=i.substr(0,i.length-1)),r+i):"."},basename:function(e){if("/"===e)return"/";var t=e.lastIndexOf("/");return-1===t?e:e.substr(t+1)},extname:function(e){return $t.splitPath(e)[3]},join:function(){var e=Array.prototype.slice.call(arguments,0);return $t.normalize(e.join("/"))},join2:function(e,t){return $t.normalize(e+"/"+t)}},er={resolve:function(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var i=r>=0?arguments[r]:ar.cwd();if("string"!=typeof i)throw new TypeError("Arguments to path.resolve must be strings");if(!i)return"";e=i+"/"+e,t="/"===i.charAt(0)}return(t?"/":"")+(e=$t.normalizeArray(e.split("/").filter((function(e){return!!e})),!t).join("/"))||"."},relative:function(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=er.resolve(e).substr(1),t=er.resolve(t).substr(1);for(var i=r(e.split("/")),n=r(t.split("/")),a=Math.min(i.length,n.length),o=a,s=0;s0?r.slice(0,n).toString("utf-8"):null}else"undefined"!=typeof window&&"function"==typeof window.prompt?null!==(t=window.prompt("Input: "))&&(t+="\n"):"function"==typeof readline&&null!==(t=readline())&&(t+="\n");if(!t)return null;e.input=_n(t,!0)}return e.input.shift()},put_char:function(e,t){null===t||10===t?(k(Z(e.output,0)),e.output=[]):0!=t&&e.output.push(t)},flush:function(e){e.output&&e.output.length>0&&(k(Z(e.output,0)),e.output=[])}},default_tty1_ops:{put_char:function(e,t){null===t||10===t?(x(Z(e.output,0)),e.output=[]):0!=t&&e.output.push(t)},flush:function(e){e.output&&e.output.length>0&&(x(Z(e.output,0)),e.output=[])}}},rr={ops_table:null,mount:function(e){return rr.createNode(null,"/",16895,0)},createNode:function(e,t,r,i){if(ar.isBlkdev(r)||ar.isFIFO(r))throw new ar.ErrnoError(63);rr.ops_table||(rr.ops_table={dir:{node:{getattr:rr.node_ops.getattr,setattr:rr.node_ops.setattr,lookup:rr.node_ops.lookup,mknod:rr.node_ops.mknod,rename:rr.node_ops.rename,unlink:rr.node_ops.unlink,rmdir:rr.node_ops.rmdir,readdir:rr.node_ops.readdir,symlink:rr.node_ops.symlink},stream:{llseek:rr.stream_ops.llseek}},file:{node:{getattr:rr.node_ops.getattr,setattr:rr.node_ops.setattr},stream:{llseek:rr.stream_ops.llseek,read:rr.stream_ops.read,write:rr.stream_ops.write,allocate:rr.stream_ops.allocate,mmap:rr.stream_ops.mmap,msync:rr.stream_ops.msync}},link:{node:{getattr:rr.node_ops.getattr,setattr:rr.node_ops.setattr,readlink:rr.node_ops.readlink},stream:{}},chrdev:{node:{getattr:rr.node_ops.getattr,setattr:rr.node_ops.setattr},stream:ar.chrdev_stream_ops}});var n=ar.createNode(e,t,r,i);return ar.isDir(n.mode)?(n.node_ops=rr.ops_table.dir.node,n.stream_ops=rr.ops_table.dir.stream,n.contents={}):ar.isFile(n.mode)?(n.node_ops=rr.ops_table.file.node,n.stream_ops=rr.ops_table.file.stream,n.usedBytes=0,n.contents=null):ar.isLink(n.mode)?(n.node_ops=rr.ops_table.link.node,n.stream_ops=rr.ops_table.link.stream):ar.isChrdev(n.mode)&&(n.node_ops=rr.ops_table.chrdev.node,n.stream_ops=rr.ops_table.chrdev.stream),n.timestamp=Date.now(),e&&(e.contents[t]=n),n},getFileDataAsRegularArray:function(e){if(e.contents&&e.contents.subarray){for(var t=[],r=0;r=t)){t=Math.max(t,r*(r<1048576?2:1.125)>>>0),0!=r&&(t=Math.max(t,256));var i=e.contents;e.contents=new Uint8Array(t),e.usedBytes>0&&e.contents.set(i.subarray(0,e.usedBytes),0)}},resizeFileStorage:function(e,t){if(e.usedBytes!=t){if(0==t)return e.contents=null,void(e.usedBytes=0);if(!e.contents||e.contents.subarray){var r=e.contents;return e.contents=new Uint8Array(t),r&&e.contents.set(r.subarray(0,Math.min(t,e.usedBytes))),void(e.usedBytes=t)}if(e.contents||(e.contents=[]),e.contents.length>t)e.contents.length=t;else for(;e.contents.length=e.node.usedBytes)return 0;var o=Math.min(e.node.usedBytes-n,i);if(q(o>=0),o>8&&a.subarray)t.set(a.subarray(n,n+o),r);else for(var s=0;s0||i+r8)throw new ar.ErrnoError(32);for(var n=$t.normalizeArray(e.split("/").filter((function(e){return!!e})),!1),a=ar.root,o="/",s=0;s40)throw new ar.ErrnoError(32)}}return{path:o,node:a}},getPath:function(e){for(var t;;){if(ar.isRoot(e)){var r=e.mount.mountpoint;return t?"/"!==r[r.length-1]?r+"/"+t:r+t:r}t=t?e.name+"/"+t:e.name,e=e.parent}},hashName:function(e,t){for(var r=0,i=0;i>>0)%ar.nameTable.length},hashAddNode:function(e){var t=ar.hashName(e.parent.id,e.name);e.name_next=ar.nameTable[t],ar.nameTable[t]=e},hashRemoveNode:function(e){var t=ar.hashName(e.parent.id,e.name);if(ar.nameTable[t]===e)ar.nameTable[t]=e.name_next;else for(var r=ar.nameTable[t];r;){if(r.name_next===e){r.name_next=e.name_next;break}r=r.name_next}},lookupNode:function(e,t){var r=ar.mayLookup(e);if(r)throw new ar.ErrnoError(r,e);for(var i=ar.hashName(e.id,t),n=ar.nameTable[i];n;n=n.name_next){var a=n.name;if(n.parent.id===e.id&&a===t)return n}return ar.lookup(e,t)},createNode:function(e,t,r,i){var n=new ar.FSNode(e,t,r,i);return ar.hashAddNode(n),n},destroyNode:function(e){ar.hashRemoveNode(e)},isRoot:function(e){return e===e.parent},isMountpoint:function(e){return!!e.mounted},isFile:function(e){return 32768==(61440&e)},isDir:function(e){return 16384==(61440&e)},isLink:function(e){return 40960==(61440&e)},isChrdev:function(e){return 8192==(61440&e)},isBlkdev:function(e){return 24576==(61440&e)},isFIFO:function(e){return 4096==(61440&e)},isSocket:function(e){return 49152==(49152&e)},flagModes:{r:0,rs:1052672,"r+":2,w:577,wx:705,xw:705,"w+":578,"wx+":706,"xw+":706,a:1089,ax:1217,xa:1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function(e){var t=ar.flagModes[e];if(void 0===t)throw new Error("Unknown file open mode: "+e);return t},flagsToPermissionString:function(e){var t=["r","w","rw"][3&e];return 512&e&&(t+="w"),t},nodePermissions:function(e,t){return ar.ignorePermissions||(-1===t.indexOf("r")||292&e.mode)&&(-1===t.indexOf("w")||146&e.mode)&&(-1===t.indexOf("x")||73&e.mode)?0:2},mayLookup:function(e){var t=ar.nodePermissions(e,"x");return t||(e.node_ops.lookup?0:2)},mayCreate:function(e,t){try{return ar.lookupNode(e,t),20}catch(e){}return ar.nodePermissions(e,"wx")},mayDelete:function(e,t,r){var i;try{i=ar.lookupNode(e,t)}catch(e){return e.errno}var n=ar.nodePermissions(e,"wx");if(n)return n;if(r){if(!ar.isDir(i.mode))return 54;if(ar.isRoot(i)||ar.getPath(i)===ar.cwd())return 10}else if(ar.isDir(i.mode))return 31;return 0},mayOpen:function(e,t){return e?ar.isLink(e.mode)?32:ar.isDir(e.mode)&&("r"!==ar.flagsToPermissionString(t)||512&t)?31:ar.nodePermissions(e,ar.flagsToPermissionString(t)):44},MAX_OPEN_FDS:4096,nextfd:function(e,t){e=e||0,t=t||ar.MAX_OPEN_FDS;for(var r=e;r<=t;r++)if(!ar.streams[r])return r;throw new ar.ErrnoError(33)},getStream:function(e){return ar.streams[e]},createStream:function(e,t,r){ar.FSStream||(ar.FSStream=function(){},ar.FSStream.prototype={object:{get:function(){return this.node},set:function(e){this.node=e}},isRead:{get:function(){return 1!=(2097155&this.flags)}},isWrite:{get:function(){return 0!=(2097155&this.flags)}},isAppend:{get:function(){return 1024&this.flags}}});var i=new ar.FSStream;for(var n in e)i[n]=e[n];e=i;var a=ar.nextfd(t,r);return e.fd=a,ar.streams[a]=e,e},closeStream:function(e){ar.streams[e]=null},chrdev_stream_ops:{open:function(e){var t=ar.getDevice(e.node.rdev);e.stream_ops=t.stream_ops,e.stream_ops.open&&e.stream_ops.open(e)},llseek:function(){throw new ar.ErrnoError(70)}},major:function(e){return e>>8},minor:function(e){return 255&e},makedev:function(e,t){return e<<8|t},registerDevice:function(e,t){ar.devices[e]={stream_ops:t}},getDevice:function(e){return ar.devices[e]},getMounts:function(e){for(var t=[],r=[e];r.length;){var i=r.pop();t.push(i),r.push.apply(r,i.mounts)}return t},syncfs:function(e,t){"function"==typeof e&&(t=e,e=!1),ar.syncFSRequests++,ar.syncFSRequests>1&&x("warning: "+ar.syncFSRequests+" FS.syncfs operations in flight at once, probably just doing extra work");var r=ar.getMounts(ar.root.mount),i=0;function n(e){return q(ar.syncFSRequests>0),ar.syncFSRequests--,t(e)}function a(e){if(e)return a.errored?void 0:(a.errored=!0,n(e));++i>=r.length&&n(null)}r.forEach((function(t){if(!t.type.syncfs)return a(null);t.type.syncfs(t,e,a)}))},mount:function(e,t,r){if("string"==typeof e)throw e;var i,n="/"===r,a=!r;if(n&&ar.root)throw new ar.ErrnoError(10);if(!n&&!a){var o=ar.lookupPath(r,{follow_mount:!1});if(r=o.path,i=o.node,ar.isMountpoint(i))throw new ar.ErrnoError(10);if(!ar.isDir(i.mode))throw new ar.ErrnoError(54)}var s={type:e,opts:t,mountpoint:r,mounts:[]},c=e.mount(s);return c.mount=s,s.root=c,n?ar.root=c:i&&(i.mounted=s,i.mount&&i.mount.mounts.push(s)),c},unmount:function(e){var t=ar.lookupPath(e,{follow_mount:!1});if(!ar.isMountpoint(t.node))throw new ar.ErrnoError(28);var r=t.node,i=r.mounted,n=ar.getMounts(i);Object.keys(ar.nameTable).forEach((function(e){for(var t=ar.nameTable[e];t;){var r=t.name_next;-1!==n.indexOf(t.mount)&&ar.destroyNode(t),t=r}})),r.mounted=null;var a=r.mount.mounts.indexOf(i);q(-1!==a),r.mount.mounts.splice(a,1)},lookup:function(e,t){return e.node_ops.lookup(e,t)},mknod:function(e,t,r){var i=ar.lookupPath(e,{parent:!0}).node,n=$t.basename(e);if(!n||"."===n||".."===n)throw new ar.ErrnoError(28);var a=ar.mayCreate(i,n);if(a)throw new ar.ErrnoError(a);if(!i.node_ops.mknod)throw new ar.ErrnoError(63);return i.node_ops.mknod(i,n,t,r)},create:function(e,t){return t=void 0!==t?t:438,t&=4095,t|=32768,ar.mknod(e,t,0)},mkdir:function(e,t){return t=void 0!==t?t:511,t&=1023,t|=16384,ar.mknod(e,t,0)},mkdirTree:function(e,t){for(var r=e.split("/"),i="",n=0;nthis.length-1||e<0)){var t=e%this.chunkSize,r=e/this.chunkSize|0;return this.getter(r)[t]}},a.prototype.setDataGetter=function(e){this.getter=e},a.prototype.cacheLength=function(){var e=new XMLHttpRequest;if(e.open("HEAD",r,!1),e.send(null),!(e.status>=200&&e.status<300||304===e.status))throw new Error("Couldn't load "+r+". Status: "+e.status);var t,i=Number(e.getResponseHeader("Content-length")),n=(t=e.getResponseHeader("Accept-Ranges"))&&"bytes"===t,a=(t=e.getResponseHeader("Content-Encoding"))&&"gzip"===t,o=1048576;n||(o=i);var s=this;s.setDataGetter((function(e){var t=e*o,n=(e+1)*o-1;if(n=Math.min(n,i-1),void 0===s.chunks[e]&&(s.chunks[e]=function(e,t){if(e>t)throw new Error("invalid range ("+e+", "+t+") or no bytes requested!");if(t>i-1)throw new Error("only "+i+" bytes available! programmer error!");var n=new XMLHttpRequest;if(n.open("GET",r,!1),i!==o&&n.setRequestHeader("Range","bytes="+e+"-"+t),"undefined"!=typeof Uint8Array&&(n.responseType="arraybuffer"),n.overrideMimeType&&n.overrideMimeType("text/plain; charset=x-user-defined"),n.send(null),!(n.status>=200&&n.status<300||304===n.status))throw new Error("Couldn't load "+r+". Status: "+n.status);return void 0!==n.response?new Uint8Array(n.response||[]):_n(n.responseText||"",!0)}(t,n)),void 0===s.chunks[e])throw new Error("doXHR failed!");return s.chunks[e]})),!a&&i||(o=i=1,i=this.getter(0).length,o=i,k("LazyFiles on gzip forces download of the whole file when length is accessed")),this._length=i,this._chunkSize=o,this.lengthKnown=!0},"undefined"!=typeof XMLHttpRequest){if(!m)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var o=new a;Object.defineProperties(o,{length:{get:function(){return this.lengthKnown||this.cacheLength(),this._length}},chunkSize:{get:function(){return this.lengthKnown||this.cacheLength(),this._chunkSize}}});var s={isDevice:!1,contents:o}}else s={isDevice:!1,url:r};var c=ar.createFile(e,t,s,i,n);s.contents?c.contents=s.contents:s.url&&(c.contents=null,c.url=s.url),Object.defineProperties(c,{usedBytes:{get:function(){return this.contents.length}}});var u={};return Object.keys(c.stream_ops).forEach((function(e){var t=c.stream_ops[e];u[e]=function(){if(!ar.forceLoadFile(c))throw new ar.ErrnoError(29);return t.apply(null,arguments)}})),u.read=function(e,t,r,i,n){if(!ar.forceLoadFile(c))throw new ar.ErrnoError(29);var a=e.node.contents;if(n>=a.length)return 0;var o=Math.min(a.length-n,i);if(q(o>=0),a.slice)for(var s=0;s>2]=i.dev,he[r+4>>2]=0,he[r+8>>2]=i.ino,he[r+12>>2]=i.mode,he[r+16>>2]=i.nlink,he[r+20>>2]=i.uid,he[r+24>>2]=i.gid,he[r+28>>2]=i.rdev,he[r+32>>2]=0,at=[i.size>>>0,(nt=i.size,+Le(nt)>=1?nt>0?(0|qe(+He(nt/4294967296),4294967295))>>>0:~~+Ue((nt-+(~~nt>>>0))/4294967296)>>>0:0)],he[r+40>>2]=at[0],he[r+44>>2]=at[1],he[r+48>>2]=4096,he[r+52>>2]=i.blocks,he[r+56>>2]=i.atime.getTime()/1e3|0,he[r+60>>2]=0,he[r+64>>2]=i.mtime.getTime()/1e3|0,he[r+68>>2]=0,he[r+72>>2]=i.ctime.getTime()/1e3|0,he[r+76>>2]=0,at=[i.ino>>>0,(nt=i.ino,+Le(nt)>=1?nt>0?(0|qe(+He(nt/4294967296),4294967295))>>>0:~~+Ue((nt-+(~~nt>>>0))/4294967296)>>>0:0)],he[r+80>>2]=at[0],he[r+84>>2]=at[1],0},doMsync:function(e,t,r,i,n){var a=ce.slice(e,e+r);ar.msync(t,a,n,r,i)},doMkdir:function(e,t){return"/"===(e=$t.normalize(e))[e.length-1]&&(e=e.substr(0,e.length-1)),ar.mkdir(e,t,0),0},doMknod:function(e,t,r){switch(61440&t){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}return ar.mknod(e,t,r),0},doReadlink:function(e,t,r){if(r<=0)return-28;var i=ar.readlink(e),n=Math.min(r,J(i)),a=se[t+n];return Q(i,t,r+1),se[t+n]=a,n},doAccess:function(e,t){if(-8&t)return-28;var r;if(!(r=ar.lookupPath(e,{follow:!0}).node))return-44;var i="";return 4&t&&(i+="r"),2&t&&(i+="w"),1&t&&(i+="x"),i&&ar.nodePermissions(r,i)?-2:0},doDup:function(e,t,r){var i=ar.getStream(r);return i&&ar.close(i),ar.open(e,t,0,r,r).fd},doReadv:function(e,t,r,i){for(var n=0,a=0;a>2],s=he[t+(8*a+4)>>2],c=ar.read(e,se,o,s,i);if(c<0)return-1;if(n+=c,c>2],s=he[t+(8*a+4)>>2],c=ar.write(e,se,o,s,i);if(c<0)return-1;n+=c}return n},varargs:void 0,get:function(){return q(null!=or.varargs),or.varargs+=4,he[or.varargs-4>>2]},getStr:function(e){return W(e)},getStreamFromFD:function(e){var t=ar.getStream(e);if(!t)throw new ar.ErrnoError(8);return t},get64:function(e,t){return q(e>=0?0===t:-1===t),e}};function sr(e,t,r){or.varargs=r;try{var i=or.getStreamFromFD(e);switch(t){case 0:return(n=or.get())<0?-28:ar.open(i.path,i.flags,0,n).fd;case 1:case 2:return 0;case 3:return i.flags;case 4:var n=or.get();return i.flags|=n,0;case 12:return n=or.get(),ue[n+0>>1]=2,0;case 13:case 14:return 0;case 16:case 8:return-28;case 9:return Gt(28),-1;default:return-28}}catch(e){return void 0!==ar&&e instanceof ar.ErrnoError||Ge(e),-e.errno}}function cr(){return 42}function ur(e,t,r){or.varargs=r;try{var i=or.getStreamFromFD(e);switch(t){case 21509:case 21505:return i.tty?0:-59;case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:return i.tty?0:-59;case 21519:if(!i.tty)return-59;var n=or.get();return he[n>>2]=0,0;case 21520:return i.tty?-28:-59;case 21531:return n=or.get(),ar.ioctl(i,t,n);case 21523:case 21524:return i.tty?0:-59;default:Ge("bad ioctl syscall "+t)}}catch(e){return void 0!==ar&&e instanceof ar.ErrnoError||Ge(e),-e.errno}}function lr(e,t){try{return e=or.getStr(e),or.doMkdir(e,t)}catch(e){return void 0!==ar&&e instanceof ar.ErrnoError||Ge(e),-e.errno}}function hr(e,t){return 0}function dr(e,t){return 0}function pr(e,t){if(-1==(0|e)||0===t)return-28;var r=or.mappings[e];if(!r)return 0;if(t===r.len){var i=ar.getStream(r.fd);2&r.prot&&or.doMsync(e,i,t,r.flags,r.offset),ar.munmap(i),or.mappings[e]=null,r.allocated&&Sn(r.malloc)}return 0}function fr(e,t){try{return pr(e,t)}catch(e){return void 0!==ar&&e instanceof ar.ErrnoError||Ge(e),-e.errno}}function mr(e,t,r){or.varargs=r;try{var i=or.getStr(e),n=or.get();return ar.open(i,t,n).fd}catch(e){return void 0!==ar&&e instanceof ar.ErrnoError||Ge(e),-e.errno}}function gr(e,t,r){try{var i=or.getStreamFromFD(e);return ar.read(i,se,t,r)}catch(e){return void 0!==ar&&e instanceof ar.ErrnoError||Ge(e),-e.errno}}function _r(e,t){try{return e=or.getStr(e),or.doStat(ar.stat,e,t)}catch(e){return void 0!==ar&&e instanceof ar.ErrnoError||Ge(e),-e.errno}}function vr(e){switch(e){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+e)}}function yr(){for(var e=new Array(256),t=0;t<256;++t)e[t]=String.fromCharCode(t);br=e}var br=void 0;function Er(e){for(var t="",r=e;ce[r];)t+=br[ce[r++]];return t}var wr={},Sr={},kr={},xr=48,Mr=57;function Nr(e){if(void 0===e)return"_unknown";var t=(e=e.replace(/[^a-zA-Z0-9_]/g,"$")).charCodeAt(0);return t>=xr&&t<=Mr?"_"+e:e}function jr(e,t){return e=Nr(e),function(){"use strict";return t.apply(this,arguments)}}function Tr(e,t){var r=jr(t,(function(e){this.name=t,this.message=e;var r=new Error(e).stack;void 0!==r&&(this.stack=this.toString()+"\n"+r.replace(/^Error(:[^\n]*)?\n/,""))}));return r.prototype=Object.create(e.prototype),r.prototype.constructor=r,r.prototype.toString=function(){return void 0===this.message?this.name:this.name+": "+this.message},r}var Rr=void 0;function Ir(e){throw new Rr(e)}var Or=void 0;function Ar(e){throw new Or(e)}function Pr(e,t,r){function i(t){var i=r(t);i.length!==e.length&&Ar("Mismatched type converter count");for(var n=0;n>a])},destructorFunction:null})}var Cr=[],Br=[{},{value:void 0},{value:null},{value:!0},{value:!1}];function zr(e){e>4&&0==--Br[e].refcount&&(Br[e]=void 0,Cr.push(e))}function Lr(){for(var e=0,t=5;t>2])}function Zr(e,t){Dr(e,{name:t=Er(t),fromWireType:function(e){var t=Br[e].value;return zr(e),t},toWireType:function(e,t){return qr(t)},argPackAdvance:8,readValueFromPointer:Kr,destructorFunction:null})}function Wr(e){if(null===e)return"null";var t=typeof e;return"object"===t||"array"===t||"function"===t?e.toString():""+e}function Xr(e,t){switch(t){case 2:return function(e){return this.fromWireType(pe[e>>2])};case 3:return function(e){return this.fromWireType(fe[e>>3])};default:throw new TypeError("Unknown float type: "+e)}}function Qr(e,t,r){var i=vr(r);Dr(e,{name:t=Er(t),fromWireType:function(e){return e},toWireType:function(e,t){if("number"!=typeof t&&"boolean"!=typeof t)throw new TypeError('Cannot convert "'+Wr(t)+'" to '+this.name);return t},argPackAdvance:8,readValueFromPointer:Xr(t,i),destructorFunction:null})}function Jr(e){for(;e.length;){var t=e.pop();e.pop()(t)}}function Vr(e,t,r,i,n){var a=t.length;a<2&&Ir("argTypes array size mismatch! Must at least get return value and 'this' types!");for(var o=null!==t[1]&&null!==r,s=!1,c=1;c>2)+i]);return r}function ei(e,t,r){c.hasOwnProperty(e)||Ar("Replacing nonexistant public symbol"),void 0!==c[e].overloadTable&&void 0!==r?c[e].overloadTable[r]=t:(c[e]=t,c[e].argCount=r)}function ti(e,t){e=Er(e);var r=function(e){var r=[t];return function(){r.length=arguments.length+1;for(var t=0;t>1]}:function(e){return le[e>>1]};case 2:return r?function(e){return he[e>>2]}:function(e){return de[e>>2]};default:throw new TypeError("Unknown integer type: "+e)}}function ci(e,t,r,i,n){t=Er(t),-1===n&&(n=4294967295);var a=vr(r),o=function(e){return e};if(0===i){var s=32-8*r;o=function(e){return e<>>s}}var c=-1!=t.indexOf("unsigned");Dr(e,{name:t,fromWireType:o,toWireType:function(e,r){if("number"!=typeof r&&"boolean"!=typeof r)throw new TypeError('Cannot convert "'+Wr(r)+'" to '+this.name);if(rn)throw new TypeError('Passing a number "'+Wr(r)+'" from JS side to C/C++ side to an argument of type "'+t+'", which is outside the valid range ['+i+", "+n+"]!");return c?r>>>0:0|r},argPackAdvance:8,readValueFromPointer:si(t,a,0!==i),destructorFunction:null})}function ui(e,t,r){var i=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][t];function n(e){var t=de,r=t[e>>=2],n=t[e+1];return new i(oe,n,r)}Dr(e,{name:r=Er(r),fromWireType:n,argPackAdvance:8,readValueFromPointer:n},{ignoreDuplicateRegistrations:!0})}function li(e,t){var r="std::string"===(t=Er(t));Dr(e,{name:t,fromWireType:function(e){var t,i=de[e>>2];if(r)for(var n=e+4,a=0;a<=i;++a){var o=e+4+a;if(a==i||0==ce[o]){var s=W(n,o-n);void 0===t?t=s:(t+=String.fromCharCode(0),t+=s),n=o+1}}else{var c=new Array(i);for(a=0;a>2]=n,r&&i)Q(t,a+4,n+1);else if(i)for(var o=0;o255&&(Sn(a),Ir("String has UTF-16 code units that do not fit in 8 bits")),ce[a+4+o]=s}else for(o=0;o>2],o=a(),c=e+4,u=0;u<=n;++u){var l=e+4+u*t;if(u==n||0==o[l>>s]){var h=i(c,l-c);void 0===r?r=h:(r+=String.fromCharCode(0),r+=h),c=l+t}}return Sn(e),r},toWireType:function(e,i){"string"!=typeof i&&Ir("Cannot pass non-string to C++ string type "+r);var a=o(i),c=wn(4+a+t);return de[c>>2]=a>>s,n(i,c+4,a+t),null!==e&&e.push(Sn,c),c},argPackAdvance:8,readValueFromPointer:Kr,destructorFunction:function(e){Sn(e)}})}function di(e,t){Dr(e,{isVoid:!0,name:t=Er(t),argPackAdvance:0,fromWireType:function(){},toWireType:function(e,t){}})}function pi(e,t){var r=Sr[e];return void 0===r&&Ir(t+" has unknown type "+ni(e)),r}function fi(e,t){for(var r=new Array(e),i=0;i>2)+i],"parameter "+i);return r}function mi(e){return e||Ir("Cannot use deleted val. handle = "+e),Br[e].value}function gi(e,t,r,i){e=mi(e);for(var n=fi(t,r),a=new Array(t),o=0;o4&&(Br[e].refcount+=1)}function yi(e,t){return qr((e=pi(e,"_emval_take_value")).readValueFromPointer(t))}function bi(e){Wa(e)}function Ei(e){return bi(e)}function wi(){Ge()}function Si(){return 417232}function ki(e,t,r){ce.copyWithin(e,t,t+r)}function xi(){return ce.length}function Mi(e){try{return C.grow(e-oe.byteLength+65535>>>16),_e(C.buffer),1}catch(t){console.error("emscripten_realloc_buffer: Attempted to grow heap from "+oe.byteLength+" bytes to "+e+" bytes, but got error: "+t)}}function Ni(e){e>>>=0;var t=xi();if(q(e>t),e>2147483648)return x("Cannot enlarge memory, asked to go up to "+e+" bytes, but the limit is 2147483648 bytes!"),!1;for(var r=1;r<=4;r*=2){var i=t*(1+.2/r);i=Math.min(i,e+100663296);var n=Math.min(2147483648,ge(Math.max(16777216,e,i),65536)),a=ri(),o=Mi(n),s=ri();if(console.log("Heap resize call from "+t+" to "+n+" took "+(s-a)+" msecs. Success: "+!!o),o)return!0}return x("Failed to grow the heap from "+t+" bytes to "+n+" bytes, not enough memory!"),!1}ri=g?function(){var e=i.hrtime();return 1e3*e[0]+e[1]/1e6}:"undefined"!=typeof dateNow?dateNow:function(){return performance.now()};var ji={};function Ti(){return d||"./this.program"}function Ri(){if(!Ri.strings){var e={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:Ti()};for(var t in ji)e[t]=ji[t];var r=[];for(var t in e)r.push(t+"="+e[t]);Ri.strings=r}return Ri.strings}function Ii(e,t){var r=0;return Ri().forEach((function(i,n){var a=t+r;he[e+4*n>>2]=a,ae(i,a),r+=i.length+1})),0}function Oi(e,t){var r=Ri();he[e>>2]=r.length;var i=0;return r.forEach((function(e){i+=e.length+1})),he[t>>2]=i,0}function Ai(e){try{var t=or.getStreamFromFD(e);return ar.close(t),0}catch(e){return void 0!==ar&&e instanceof ar.ErrnoError||Ge(e),e.errno}}function Pi(e,t,r,i){try{var n=or.getStreamFromFD(e),a=or.doReadv(n,t,r);return he[i>>2]=a,0}catch(e){return void 0!==ar&&e instanceof ar.ErrnoError||Ge(e),e.errno}}function Di(e,t,r,i,n){try{var a=or.getStreamFromFD(e),o=4294967296*r+(t>>>0);return o<=-9007199254740992||o>=9007199254740992?-61:(ar.llseek(a,o,i),at=[a.position>>>0,(nt=a.position,+Le(nt)>=1?nt>0?(0|qe(+He(nt/4294967296),4294967295))>>>0:~~+Ue((nt-+(~~nt>>>0))/4294967296)>>>0:0)],he[n>>2]=at[0],he[n+4>>2]=at[1],a.getdents&&0===o&&0===i&&(a.getdents=null),0)}catch(e){return void 0!==ar&&e instanceof ar.ErrnoError||Ge(e),e.errno}}function Fi(e,t,r,i){try{var n=or.getStreamFromFD(e),a=or.doWritev(n,t,r);return he[i>>2]=a,0}catch(e){return void 0!==ar&&e instanceof ar.ErrnoError||Ge(e),e.errno}}function Ci(e){var t=Date.now();return he[e>>2]=t/1e3|0,ue[e+4>>1]=t%1e3,ue[e+6>>1]=0,ue[e+8>>1]=0,0}function Bi(){return 0|L()}function zi(e){var t=Date.now();return he[e>>2]=t/1e3|0,he[e+4>>2]=t%1e3*1e3|0,0}var Li=417248,Ui=(Q("GMT",417296,4),417296);function Hi(e,t){var r=new Date(1e3*he[e>>2]);he[t>>2]=r.getUTCSeconds(),he[t+4>>2]=r.getUTCMinutes(),he[t+8>>2]=r.getUTCHours(),he[t+12>>2]=r.getUTCDate(),he[t+16>>2]=r.getUTCMonth(),he[t+20>>2]=r.getUTCFullYear()-1900,he[t+24>>2]=r.getUTCDay(),he[t+36>>2]=0,he[t+32>>2]=0;var i=Date.UTC(r.getUTCFullYear(),0,1,0,0,0,0),n=(r.getTime()-i)/864e5|0;return he[t+28>>2]=n,he[t+40>>2]=Ui,t}function qi(e){return Hi(e,Li)}function Ki(e){return e}function Zi(){if(!Zi.called){Zi.called=!0,he[jn()>>2]=60*(new Date).getTimezoneOffset();var e=(new Date).getFullYear(),t=new Date(e,0,1),r=new Date(e,6,1);he[Nn()>>2]=Number(t.getTimezoneOffset()!=r.getTimezoneOffset());var i=s(t),n=s(r),a=ie(i),o=ie(n);r.getTimezoneOffset()>2]=a,he[Mn()+4>>2]=o):(he[Mn()>>2]=o,he[Mn()+4>>2]=a)}function s(e){var t=e.toTimeString().match(/\(([A-Za-z ]+)\)$/);return t?t[1]:"GMT"}}function Wi(e){Zi();var t=new Date(he[e+20>>2]+1900,he[e+16>>2],he[e+12>>2],he[e+8>>2],he[e+4>>2],he[e>>2],0),r=he[e+32>>2],i=t.getTimezoneOffset(),n=new Date(t.getFullYear(),0,1),a=new Date(t.getFullYear(),6,1).getTimezoneOffset(),o=n.getTimezoneOffset(),s=Math.min(o,a);if(r<0)he[e+32>>2]=Number(a!=o&&s==i);else if(r>0!=(s==i)){var c=Math.max(o,a),u=r>0?s:c;t.setTime(t.getTime()+6e4*(u-i))}he[e+24>>2]=t.getDay();var l=(t.getTime()-n.getTime())/864e5|0;return he[e+28>>2]=l,t.getTime()/1e3|0}function Xi(){return 0}function Qi(){return 0}function Ji(){return 0}function Vi(){}function Gi(){}function Yi(){}function $i(){}function en(){}function tn(e){z(0|e)}function rn(e){return e%4==0&&(e%100!=0||e%400==0)}function nn(e,t){for(var r=0,i=0;i<=t;r+=e[i++]);return r}var an=[31,29,31,30,31,30,31,31,30,31,30,31],on=[31,28,31,30,31,30,31,31,30,31,30,31];function sn(e,t){for(var r=new Date(e.getTime());t>0;){var i=rn(r.getFullYear()),n=r.getMonth(),a=(i?an:on)[n];if(!(t>a-r.getDate()))return r.setDate(r.getDate()+t),r;t-=a-r.getDate()+1,r.setDate(1),n<11?r.setMonth(n+1):(r.setMonth(0),r.setFullYear(r.getFullYear()+1))}return r}function cn(e,t,r,i){var n=he[i+40>>2],a={tm_sec:he[i>>2],tm_min:he[i+4>>2],tm_hour:he[i+8>>2],tm_mday:he[i+12>>2],tm_mon:he[i+16>>2],tm_year:he[i+20>>2],tm_wday:he[i+24>>2],tm_yday:he[i+28>>2],tm_isdst:he[i+32>>2],tm_gmtoff:he[i+36>>2],tm_zone:n?W(n):""},o=W(r),s={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var c in s)o=o.replace(new RegExp(c,"g"),s[c]);var u=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],l=["January","February","March","April","May","June","July","August","September","October","November","December"];function h(e,t,r){for(var i="number"==typeof e?e.toString():e||"";i.length0?1:0}var i;return 0===(i=r(e.getFullYear()-t.getFullYear()))&&0===(i=r(e.getMonth()-t.getMonth()))&&(i=r(e.getDate()-t.getDate())),i}function f(e){switch(e.getDay()){case 0:return new Date(e.getFullYear()-1,11,29);case 1:return e;case 2:return new Date(e.getFullYear(),0,3);case 3:return new Date(e.getFullYear(),0,2);case 4:return new Date(e.getFullYear(),0,1);case 5:return new Date(e.getFullYear()-1,11,31);case 6:return new Date(e.getFullYear()-1,11,30)}}function m(e){var t=sn(new Date(e.tm_year+1900,0,1),e.tm_yday),r=new Date(t.getFullYear(),0,4),i=new Date(t.getFullYear()+1,0,4),n=f(r),a=f(i);return p(n,t)<=0?p(a,t)<=0?t.getFullYear()+1:t.getFullYear():t.getFullYear()-1}var g={"%a":function(e){return u[e.tm_wday].substring(0,3)},"%A":function(e){return u[e.tm_wday]},"%b":function(e){return l[e.tm_mon].substring(0,3)},"%B":function(e){return l[e.tm_mon]},"%C":function(e){return d((e.tm_year+1900)/100|0,2)},"%d":function(e){return d(e.tm_mday,2)},"%e":function(e){return h(e.tm_mday,2," ")},"%g":function(e){return m(e).toString().substring(2)},"%G":function(e){return m(e)},"%H":function(e){return d(e.tm_hour,2)},"%I":function(e){var t=e.tm_hour;return 0==t?t=12:t>12&&(t-=12),d(t,2)},"%j":function(e){return d(e.tm_mday+nn(rn(e.tm_year+1900)?an:on,e.tm_mon-1),3)},"%m":function(e){return d(e.tm_mon+1,2)},"%M":function(e){return d(e.tm_min,2)},"%n":function(){return"\n"},"%p":function(e){return e.tm_hour>=0&&e.tm_hour<12?"AM":"PM"},"%S":function(e){return d(e.tm_sec,2)},"%t":function(){return"\t"},"%u":function(e){return e.tm_wday||7},"%U":function(e){var t=new Date(e.tm_year+1900,0,1),r=0===t.getDay()?t:sn(t,7-t.getDay()),i=new Date(e.tm_year+1900,e.tm_mon,e.tm_mday);if(p(r,i)<0){var n=nn(rn(i.getFullYear())?an:on,i.getMonth()-1)-31,a=31-r.getDate()+n+i.getDate();return d(Math.ceil(a/7),2)}return 0===p(r,t)?"01":"00"},"%V":function(e){var t,r=new Date(e.tm_year+1900,0,4),i=new Date(e.tm_year+1901,0,4),n=f(r),a=f(i),o=sn(new Date(e.tm_year+1900,0,1),e.tm_yday);return p(o,n)<0?"53":p(a,o)<=0?"01":(t=n.getFullYear()=0;return t=(t=Math.abs(t)/60)/60*100+t%60,(r?"+":"-")+String("0000"+t).slice(-4)},"%Z":function(e){return e.tm_zone},"%%":function(){return"%"}};for(var c in g)o.indexOf(c)>=0&&(o=o.replace(new RegExp(c,"g"),g[c](a)));var _=_n(o,!1);return _.length>t?0:(ne(_,e),_.length-1)}function un(e,t,r,i){return cn(e,t,r,i)}function ln(e){switch(e){case 30:return 16384;case 85:return 131072;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:case 79:return 200809;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1;case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32;case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1e3;case 89:return 700;case 71:return 256;case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:return"object"==typeof navigator&&navigator.hardwareConcurrency||1}return Gt(28),-1}function hn(e){var t=Date.now()/1e3|0;return e&&(he[e>>2]=t),t}function dn(){x("missing function: v4_generate_JIT_code"),Ge(-1)}var pn=function(e,t,r,i){e||(e=this),this.parent=e,this.mount=e.mount,this.mounted=null,this.id=ar.nextInode++,this.name=t,this.mode=r,this.node_ops={},this.stream_ops={},this.rdev=i},fn=365,mn=146;Object.defineProperties(pn.prototype,{read:{get:function(){return(this.mode&fn)===fn},set:function(e){e?this.mode|=fn:this.mode&=~fn}},write:{get:function(){return(this.mode&mn)===mn},set:function(e){e?this.mode|=mn:this.mode&=~mn}},isFolder:{get:function(){return ar.isDir(this.mode)}},isDevice:{get:function(){return ar.isChrdev(this.mode)}}}),ar.FSNode=pn,ar.staticInit(),yr(),Rr=c.BindingError=Tr(Error,"BindingError"),Or=c.InternalError=Tr(Error,"InternalError"),Hr(),ii=c.UnboundTypeError=Tr(Error,"UnboundTypeError");var gn=!0;function _n(e,t,r){var i=r>0?r:J(e)+1,n=new Array(i),a=X(e,n,0,n.length);return t&&(n.length=a),n}function vn(e){for(var t=[],r=0;r255&&(gn&&q(!1,"Character code "+i+" ("+String.fromCharCode(i)+") at offset "+r+" not in 0x00-0xFF."),i&=255),t.push(String.fromCharCode(i))}return t.join("")}var yn,bn={CONF_modules_unload:ft,ERR_reason_error_string:mt,_ZN5boost11regex_errorC1ERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_15regex_constants10error_typeEl:gt,_ZN5boost11regex_errorD1Ev:_t,_ZN5boost16re_detail_10720011raw_storage6insertEmm:vt,_ZN5boost16re_detail_10720011raw_storage6resizeEm:yt,_ZN5boost16re_detail_10720013get_mem_blockEv:bt,_ZN5boost16re_detail_10720013put_mem_blockEPv:Et,_ZN5boost16re_detail_10720014verify_optionsEjNS_15regex_constants12_match_flagsE:wt,_ZN5boost16re_detail_10720019raise_runtime_errorERKSt13runtime_error:St,_ZN5boost16re_detail_10720024get_default_error_stringENS_15regex_constants10error_typeE:kt,_ZN5boost16re_detail_10720027cpp_regex_traits_char_layerIcE4initEv:xt,_ZN5boost16re_detail_10720027lookup_default_collate_nameERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:Mt,_ZN5boost24scoped_static_mutex_lockC1ERNS_12static_mutexEb:Nt,_ZN5boost24scoped_static_mutex_lockD1Ev:jt,_ZNK5boost11regex_error5raiseEv:Tt,__assert_fail:Rt,__cxa_allocate_exception:Ot,__cxa_atexit:Pt,__cxa_begin_catch:zt,__cxa_end_catch:qt,__cxa_find_matching_catch_2:Zt,__cxa_find_matching_catch_3:Wt,__cxa_free_exception:Ut,__cxa_rethrow:Xt,__cxa_throw:Qt,__cxa_uncaught_exceptions:Jt,__handle_stack_overflow:Vt,__map_file:Yt,__resumeException:Kt,__sys_fcntl64:sr,__sys_getpid:cr,__sys_ioctl:ur,__sys_mkdir:lr,__sys_mlock:hr,__sys_munlock:dr,__sys_munmap:fr,__sys_open:mr,__sys_read:gr,__sys_stat64:_r,_embind_register_bool:Fr,_embind_register_emval:Zr,_embind_register_float:Qr,_embind_register_function:oi,_embind_register_integer:ci,_embind_register_memory_view:ui,_embind_register_std_string:li,_embind_register_std_wstring:hi,_embind_register_void:di,_emval_call:gi,_emval_decref:zr,_emval_equals:_i,_emval_incref:vi,_emval_take_value:yi,_exit:Ei,abort:wi,atexit:At,emscripten_get_sbrk_ptr:Si,emscripten_memcpy_big:ki,emscripten_resize_heap:Ni,environ_get:Ii,environ_sizes_get:Oi,exit:bi,fd_close:Ai,fd_read:Pi,fd_seek:Di,fd_write:Fi,ftime:Ci,getTempRet0:Bi,gettimeofday:zi,gmtime:qi,gmtime_r:Hi,invoke_diii:Ta,invoke_fiii:ja,invoke_i:Ra,invoke_ii:pa,invoke_iii:ma,invoke_iiii:fa,invoke_iiiii:ba,invoke_iiiiid:ka,invoke_iiiiii:va,invoke_iiiiiii:Ea,invoke_iiiiiiii:xa,invoke_iiiiiiiiiii:Ma,invoke_iiiiiiiiiiii:Oa,invoke_iiiiiiiiiiiii:Na,invoke_iiiiij:Ha,invoke_ji:Ca,invoke_jii:Ba,invoke_jiii:za,invoke_jiiii:Da,invoke_v:_a,invoke_vi:ya,invoke_vii:da,invoke_viii:ga,invoke_viiii:wa,invoke_viiiii:Sa,invoke_viiiiiii:Ia,invoke_viiiiiiiiii:Aa,invoke_viiiiiiiiiiiiiii:Pa,invoke_viiiji:La,invoke_viij:Fa,invoke_viijii:Ua,llvm_eh_typeid_for:Ki,memory:C,mktime:Wi,pthread_condattr_destroy:Xi,pthread_condattr_init:Qi,pthread_condattr_setclock:Ji,pthread_detach:Vi,pthread_join:Gi,pthread_mutexattr_destroy:Yi,pthread_mutexattr_init:$i,pthread_mutexattr_settype:en,setTempRet0:tn,strftime_l:un,sysconf:ln,table:U,time:hn,v4_generate_JIT_code:dn},En=(ut(),c.___wasm_call_ctors=it("__wasm_call_ctors")),wn=c._malloc=it("malloc"),Sn=(c.__ZN5boost13serialization16singleton_module8get_lockEv=it("_ZN5boost13serialization16singleton_module8get_lockEv"),c._free=it("free")),kn=(c._memset=it("memset"),c.___errno_location=it("__errno_location")),xn=(c._fflush=it("fflush"),c.___getTypeName=it("__getTypeName")),Mn=(c.___embind_register_native_and_builtin_types=it("__embind_register_native_and_builtin_types"),c.__get_tzname=it("_get_tzname")),Nn=c.__get_daylight=it("_get_daylight"),jn=c.__get_timezone=it("_get_timezone"),Tn=c._setThrew=it("setThrew"),Rn=c.stackSave=it("stackSave"),In=c.stackRestore=it("stackRestore"),On=(c.stackAlloc=it("stackAlloc"),c.__ZSt18uncaught_exceptionv=it("_ZSt18uncaught_exceptionv")),An=c.___cxa_can_catch=it("__cxa_can_catch"),Pn=c.___cxa_is_pointer_type=it("__cxa_is_pointer_type"),Dn=(c._emscripten_main_thread_process_queued_calls=it("emscripten_main_thread_process_queued_calls"),c.dynCall_v=it("dynCall_v")),Fn=c.dynCall_vi=it("dynCall_vi"),Cn=c.dynCall_vii=it("dynCall_vii"),Bn=c.dynCall_viii=it("dynCall_viii"),zn=c.dynCall_viiii=it("dynCall_viiii"),Ln=c.dynCall_viiiii=it("dynCall_viiiii"),Un=c.dynCall_viiiiiii=it("dynCall_viiiiiii"),Hn=c.dynCall_viiiiiiiiii=it("dynCall_viiiiiiiiii"),qn=c.dynCall_viiiiiiiiiiiiiii=it("dynCall_viiiiiiiiiiiiiii"),Kn=c.dynCall_viiiji=it("dynCall_viiiji"),Zn=c.dynCall_viij=it("dynCall_viij"),Wn=c.dynCall_viijii=it("dynCall_viijii"),Xn=c.dynCall_i=it("dynCall_i"),Qn=c.dynCall_ii=it("dynCall_ii"),Jn=c.dynCall_iii=it("dynCall_iii"),Vn=c.dynCall_iiii=it("dynCall_iiii"),Gn=c.dynCall_iiiii=it("dynCall_iiiii"),Yn=c.dynCall_iiiiii=it("dynCall_iiiiii"),$n=c.dynCall_iiiiiii=it("dynCall_iiiiiii"),ea=c.dynCall_iiiiiiii=it("dynCall_iiiiiiii"),ta=c.dynCall_iiiiiiiiiii=it("dynCall_iiiiiiiiiii"),ra=c.dynCall_iiiiiiiiiiii=it("dynCall_iiiiiiiiiiii"),ia=c.dynCall_iiiiiiiiiiiii=it("dynCall_iiiiiiiiiiiii"),na=c.dynCall_iiiiij=it("dynCall_iiiiij"),aa=c.dynCall_iiiiid=it("dynCall_iiiiid"),oa=c.dynCall_ji=it("dynCall_ji"),sa=c.dynCall_jii=it("dynCall_jii"),ca=c.dynCall_jiii=it("dynCall_jiii"),ua=c.dynCall_jiiii=it("dynCall_jiiii"),la=c.dynCall_fiii=it("dynCall_fiii"),ha=c.dynCall_diii=it("dynCall_diii");function da(e,t,r){var i=Rn();try{Cn(e,t,r)}catch(e){if(In(i),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function pa(e,t){var r=Rn();try{return Qn(e,t)}catch(e){if(In(r),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function fa(e,t,r,i){var n=Rn();try{return Vn(e,t,r,i)}catch(e){if(In(n),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function ma(e,t,r){var i=Rn();try{return Jn(e,t,r)}catch(e){if(In(i),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function ga(e,t,r,i){var n=Rn();try{Bn(e,t,r,i)}catch(e){if(In(n),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function _a(e){var t=Rn();try{Dn(e)}catch(e){if(In(t),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function va(e,t,r,i,n,a){var o=Rn();try{return Yn(e,t,r,i,n,a)}catch(e){if(In(o),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function ya(e,t){var r=Rn();try{Fn(e,t)}catch(e){if(In(r),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function ba(e,t,r,i,n){var a=Rn();try{return Gn(e,t,r,i,n)}catch(e){if(In(a),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Ea(e,t,r,i,n,a,o){var s=Rn();try{return $n(e,t,r,i,n,a,o)}catch(e){if(In(s),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function wa(e,t,r,i,n){var a=Rn();try{zn(e,t,r,i,n)}catch(e){if(In(a),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Sa(e,t,r,i,n,a){var o=Rn();try{Ln(e,t,r,i,n,a)}catch(e){if(In(o),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function ka(e,t,r,i,n,a){var o=Rn();try{return aa(e,t,r,i,n,a)}catch(e){if(In(o),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function xa(e,t,r,i,n,a,o,s){var c=Rn();try{return ea(e,t,r,i,n,a,o,s)}catch(e){if(In(c),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Ma(e,t,r,i,n,a,o,s,c,u,l){var h=Rn();try{return ta(e,t,r,i,n,a,o,s,c,u,l)}catch(e){if(In(h),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Na(e,t,r,i,n,a,o,s,c,u,l,h,d){var p=Rn();try{return ia(e,t,r,i,n,a,o,s,c,u,l,h,d)}catch(e){if(In(p),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function ja(e,t,r,i){var n=Rn();try{return la(e,t,r,i)}catch(e){if(In(n),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Ta(e,t,r,i){var n=Rn();try{return ha(e,t,r,i)}catch(e){if(In(n),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Ra(e){var t=Rn();try{return Xn(e)}catch(e){if(In(t),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Ia(e,t,r,i,n,a,o,s){var c=Rn();try{Un(e,t,r,i,n,a,o,s)}catch(e){if(In(c),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Oa(e,t,r,i,n,a,o,s,c,u,l,h){var d=Rn();try{return ra(e,t,r,i,n,a,o,s,c,u,l,h)}catch(e){if(In(d),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Aa(e,t,r,i,n,a,o,s,c,u,l){var h=Rn();try{Hn(e,t,r,i,n,a,o,s,c,u,l)}catch(e){if(In(h),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Pa(e,t,r,i,n,a,o,s,c,u,l,h,d,p,f,m){var g=Rn();try{qn(e,t,r,i,n,a,o,s,c,u,l,h,d,p,f,m)}catch(e){if(In(g),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Da(e,t,r,i,n){var a=Rn();try{return ua(e,t,r,i,n)}catch(e){if(In(a),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Fa(e,t,r,i,n){var a=Rn();try{Zn(e,t,r,i,n)}catch(e){if(In(a),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Ca(e,t){var r=Rn();try{return oa(e,t)}catch(e){if(In(r),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Ba(e,t,r){var i=Rn();try{return sa(e,t,r)}catch(e){if(In(i),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function za(e,t,r,i){var n=Rn();try{return ca(e,t,r,i)}catch(e){if(In(n),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function La(e,t,r,i,n,a,o){var s=Rn();try{Kn(e,t,r,i,n,a,o)}catch(e){if(In(s),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Ua(e,t,r,i,n,a,o){var s=Rn();try{Wn(e,t,r,i,n,a,o)}catch(e){if(In(s),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function Ha(e,t,r,i,n,a,o){var s=Rn();try{return na(e,t,r,i,n,a,o)}catch(e){if(In(s),e!==e+0&&"longjmp"!==e)throw e;Tn(1,0)}}function qa(e){this.name="ExitStatus",this.message="Program terminated with exit("+e+")",this.status=e}function Ka(e){function r(){yn||(yn=!0,c.calledRun=!0,H||(Pe(),De(),t(c),c.onRuntimeInitialized&&c.onRuntimeInitialized(),q(!c._main,'compiled without a main, but one is present. if you added it from JS, use Module["onRuntimeInitialized"]'),Ce()))}e=e||h,Ke>0||(ke(),Ae(),Ke>0||(c.setStatus?(c.setStatus("Running..."),setTimeout((function(){setTimeout((function(){c.setStatus("")}),1),r()}),1)):r(),xe()))}function Za(){var e=k,t=x,r=!1;k=x=function(e){r=!0};try{var i=c._fflush;i&&i(0),["stdout","stderr"].forEach((function(e){var t=ar.analyzePath("/dev/"+e);if(t){var i=t.object.rdev,n=tr.ttys[i];n&&n.output&&n.output.length&&(r=!0)}}))}catch(e){}k=e,x=t,r&&j("stdio streams had content in them that was not flushed. you should set EXIT_RUNTIME to 1 (see the FAQ), or make sure to emit a newline when you printf etc.")}function Wa(e,t){if(Za(),!t||!F||0!==e){if(F){if(!t){var r="program exited (with status: "+e+"), but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)";s(r),x(r)}}else H=!0,Fe(),c.onExit&&c.onExit(e);p(e,new qa(e))}}if(c.___set_stack_limit=it("__set_stack_limit"),c.dynCall_viiiiiiiii=it("dynCall_viiiiiiiii"),c.dynCall_viiiiiiii=it("dynCall_viiiiiiii"),c.dynCall_viiiiiiiiiiii=it("dynCall_viiiiiiiiiiii"),c.dynCall_viiiiii=it("dynCall_viiiiii"),c.dynCall_viiiiiiiiiii=it("dynCall_viiiiiiiiiii"),c.dynCall_viiiiiiiiiiiii=it("dynCall_viiiiiiiiiiiii"),c.dynCall_iiiiiiiii=it("dynCall_iiiiiiiii"),c.dynCall_vijjjdi=it("dynCall_vijjjdi"),c.dynCall_vij=it("dynCall_vij"),c.dynCall_vijj=it("dynCall_vijj"),c.dynCall_viiji=it("dynCall_viiji"),c.dynCall_vijiiii=it("dynCall_vijiiii"),c.dynCall_iiiij=it("dynCall_iiiij"),c.dynCall_iiiiiiiiiiiiii=it("dynCall_iiiiiiiiiiiiii"),c.dynCall_jiji=it("dynCall_jiji"),c.dynCall_iidiiii=it("dynCall_iidiiii"),c.dynCall_iiiiijj=it("dynCall_iiiiijj"),c.dynCall_iiiiiijj=it("dynCall_iiiiiijj"),c.__growWasmMemory=it("__growWasmMemory"),Object.getOwnPropertyDescriptor(c,"intArrayFromString")||(c.intArrayFromString=function(){Ge("'intArrayFromString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),c.intArrayToString=vn,Object.getOwnPropertyDescriptor(c,"ccall")||(c.ccall=function(){Ge("'ccall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"cwrap")||(c.cwrap=function(){Ge("'cwrap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"setValue")||(c.setValue=function(){Ge("'setValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getValue")||(c.getValue=function(){Ge("'getValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"allocate")||(c.allocate=function(){Ge("'allocate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getMemory")||(c.getMemory=function(){Ge("'getMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(c,"UTF8ArrayToString")||(c.UTF8ArrayToString=function(){Ge("'UTF8ArrayToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),c.UTF8ToString=W,Object.getOwnPropertyDescriptor(c,"stringToUTF8Array")||(c.stringToUTF8Array=function(){Ge("'stringToUTF8Array' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),c.stringToUTF8=Q,c.lengthBytesUTF8=J,Object.getOwnPropertyDescriptor(c,"stackTrace")||(c.stackTrace=function(){Ge("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"addOnPreRun")||(c.addOnPreRun=function(){Ge("'addOnPreRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"addOnInit")||(c.addOnInit=function(){Ge("'addOnInit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"addOnPreMain")||(c.addOnPreMain=function(){Ge("'addOnPreMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"addOnExit")||(c.addOnExit=function(){Ge("'addOnExit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"addOnPostRun")||(c.addOnPostRun=function(){Ge("'addOnPostRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"writeStringToMemory")||(c.writeStringToMemory=function(){Ge("'writeStringToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"writeArrayToMemory")||(c.writeArrayToMemory=function(){Ge("'writeArrayToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"writeAsciiToMemory")||(c.writeAsciiToMemory=function(){Ge("'writeAsciiToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"addRunDependency")||(c.addRunDependency=function(){Ge("'addRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(c,"removeRunDependency")||(c.removeRunDependency=function(){Ge("'removeRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(c,"FS_createFolder")||(c.FS_createFolder=function(){Ge("'FS_createFolder' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(c,"FS_createPath")||(c.FS_createPath=function(){Ge("'FS_createPath' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(c,"FS_createDataFile")||(c.FS_createDataFile=function(){Ge("'FS_createDataFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(c,"FS_createPreloadedFile")||(c.FS_createPreloadedFile=function(){Ge("'FS_createPreloadedFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(c,"FS_createLazyFile")||(c.FS_createLazyFile=function(){Ge("'FS_createLazyFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(c,"FS_createLink")||(c.FS_createLink=function(){Ge("'FS_createLink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(c,"FS_createDevice")||(c.FS_createDevice=function(){Ge("'FS_createDevice' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(c,"FS_unlink")||(c.FS_unlink=function(){Ge("'FS_unlink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(c,"dynamicAlloc")||(c.dynamicAlloc=function(){Ge("'dynamicAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"loadDynamicLibrary")||(c.loadDynamicLibrary=function(){Ge("'loadDynamicLibrary' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"loadWebAssemblyModule")||(c.loadWebAssemblyModule=function(){Ge("'loadWebAssemblyModule' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getLEB")||(c.getLEB=function(){Ge("'getLEB' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getFunctionTables")||(c.getFunctionTables=function(){Ge("'getFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"alignFunctionTables")||(c.alignFunctionTables=function(){Ge("'alignFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"registerFunctions")||(c.registerFunctions=function(){Ge("'registerFunctions' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),c.addFunction=A,Object.getOwnPropertyDescriptor(c,"removeFunction")||(c.removeFunction=function(){Ge("'removeFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getFuncWrapper")||(c.getFuncWrapper=function(){Ge("'getFuncWrapper' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"prettyPrint")||(c.prettyPrint=function(){Ge("'prettyPrint' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),c.makeBigInt=P,Object.getOwnPropertyDescriptor(c,"dynCall")||(c.dynCall=function(){Ge("'dynCall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getCompilerSetting")||(c.getCompilerSetting=function(){Ge("'getCompilerSetting' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"print")||(c.print=function(){Ge("'print' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"printErr")||(c.printErr=function(){Ge("'printErr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),c.getTempRet0=L,Object.getOwnPropertyDescriptor(c,"setTempRet0")||(c.setTempRet0=function(){Ge("'setTempRet0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"callMain")||(c.callMain=function(){Ge("'callMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"abort")||(c.abort=function(){Ge("'abort' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"stringToNewUTF8")||(c.stringToNewUTF8=function(){Ge("'stringToNewUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"emscripten_realloc_buffer")||(c.emscripten_realloc_buffer=function(){Ge("'emscripten_realloc_buffer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"ENV")||(c.ENV=function(){Ge("'ENV' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"ERRNO_CODES")||(c.ERRNO_CODES=function(){Ge("'ERRNO_CODES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"ERRNO_MESSAGES")||(c.ERRNO_MESSAGES=function(){Ge("'ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"setErrNo")||(c.setErrNo=function(){Ge("'setErrNo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"DNS")||(c.DNS=function(){Ge("'DNS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"GAI_ERRNO_MESSAGES")||(c.GAI_ERRNO_MESSAGES=function(){Ge("'GAI_ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"Protocols")||(c.Protocols=function(){Ge("'Protocols' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"Sockets")||(c.Sockets=function(){Ge("'Sockets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"traverseStack")||(c.traverseStack=function(){Ge("'traverseStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"UNWIND_CACHE")||(c.UNWIND_CACHE=function(){Ge("'UNWIND_CACHE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"withBuiltinMalloc")||(c.withBuiltinMalloc=function(){Ge("'withBuiltinMalloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"readAsmConstArgsArray")||(c.readAsmConstArgsArray=function(){Ge("'readAsmConstArgsArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"readAsmConstArgs")||(c.readAsmConstArgs=function(){Ge("'readAsmConstArgs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"jstoi_q")||(c.jstoi_q=function(){Ge("'jstoi_q' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"jstoi_s")||(c.jstoi_s=function(){Ge("'jstoi_s' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getExecutableName")||(c.getExecutableName=function(){Ge("'getExecutableName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"listenOnce")||(c.listenOnce=function(){Ge("'listenOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"autoResumeAudioContext")||(c.autoResumeAudioContext=function(){Ge("'autoResumeAudioContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"abortStackOverflow")||(c.abortStackOverflow=function(){Ge("'abortStackOverflow' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"reallyNegative")||(c.reallyNegative=function(){Ge("'reallyNegative' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"formatString")||(c.formatString=function(){Ge("'formatString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"PATH")||(c.PATH=function(){Ge("'PATH' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"PATH_FS")||(c.PATH_FS=function(){Ge("'PATH_FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"SYSCALLS")||(c.SYSCALLS=function(){Ge("'SYSCALLS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"syscallMmap2")||(c.syscallMmap2=function(){Ge("'syscallMmap2' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"syscallMunmap")||(c.syscallMunmap=function(){Ge("'syscallMunmap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"JSEvents")||(c.JSEvents=function(){Ge("'JSEvents' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"specialHTMLTargets")||(c.specialHTMLTargets=function(){Ge("'specialHTMLTargets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"maybeCStringToJsString")||(c.maybeCStringToJsString=function(){Ge("'maybeCStringToJsString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"findEventTarget")||(c.findEventTarget=function(){Ge("'findEventTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"findCanvasEventTarget")||(c.findCanvasEventTarget=function(){Ge("'findCanvasEventTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"polyfillSetImmediate")||(c.polyfillSetImmediate=function(){Ge("'polyfillSetImmediate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"demangle")||(c.demangle=function(){Ge("'demangle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"demangleAll")||(c.demangleAll=function(){Ge("'demangleAll' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"jsStackTrace")||(c.jsStackTrace=function(){Ge("'jsStackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"stackTrace")||(c.stackTrace=function(){Ge("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getEnvStrings")||(c.getEnvStrings=function(){Ge("'getEnvStrings' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"checkWasiClock")||(c.checkWasiClock=function(){Ge("'checkWasiClock' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"writeI53ToI64")||(c.writeI53ToI64=function(){Ge("'writeI53ToI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"writeI53ToI64Clamped")||(c.writeI53ToI64Clamped=function(){Ge("'writeI53ToI64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"writeI53ToI64Signaling")||(c.writeI53ToI64Signaling=function(){Ge("'writeI53ToI64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"writeI53ToU64Clamped")||(c.writeI53ToU64Clamped=function(){Ge("'writeI53ToU64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"writeI53ToU64Signaling")||(c.writeI53ToU64Signaling=function(){Ge("'writeI53ToU64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"readI53FromI64")||(c.readI53FromI64=function(){Ge("'readI53FromI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"readI53FromU64")||(c.readI53FromU64=function(){Ge("'readI53FromU64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"convertI32PairToI53")||(c.convertI32PairToI53=function(){Ge("'convertI32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"convertU32PairToI53")||(c.convertU32PairToI53=function(){Ge("'convertU32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"exceptionLast")||(c.exceptionLast=function(){Ge("'exceptionLast' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"exceptionCaught")||(c.exceptionCaught=function(){Ge("'exceptionCaught' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"ExceptionInfoAttrs")||(c.ExceptionInfoAttrs=function(){Ge("'ExceptionInfoAttrs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"ExceptionInfo")||(c.ExceptionInfo=function(){Ge("'ExceptionInfo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"CatchInfo")||(c.CatchInfo=function(){Ge("'CatchInfo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"exception_addRef")||(c.exception_addRef=function(){Ge("'exception_addRef' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"exception_decRef")||(c.exception_decRef=function(){Ge("'exception_decRef' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"Browser")||(c.Browser=function(){Ge("'Browser' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"FS")||(c.FS=function(){Ge("'FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"MEMFS")||(c.MEMFS=function(){Ge("'MEMFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"TTY")||(c.TTY=function(){Ge("'TTY' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"PIPEFS")||(c.PIPEFS=function(){Ge("'PIPEFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"SOCKFS")||(c.SOCKFS=function(){Ge("'SOCKFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"tempFixedLengthArray")||(c.tempFixedLengthArray=function(){Ge("'tempFixedLengthArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"miniTempWebGLFloatBuffers")||(c.miniTempWebGLFloatBuffers=function(){Ge("'miniTempWebGLFloatBuffers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"heapObjectForWebGLType")||(c.heapObjectForWebGLType=function(){Ge("'heapObjectForWebGLType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"heapAccessShiftForWebGLHeap")||(c.heapAccessShiftForWebGLHeap=function(){Ge("'heapAccessShiftForWebGLHeap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"GL")||(c.GL=function(){Ge("'GL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"emscriptenWebGLGet")||(c.emscriptenWebGLGet=function(){Ge("'emscriptenWebGLGet' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"computeUnpackAlignedImageSize")||(c.computeUnpackAlignedImageSize=function(){Ge("'computeUnpackAlignedImageSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"emscriptenWebGLGetTexPixelData")||(c.emscriptenWebGLGetTexPixelData=function(){Ge("'emscriptenWebGLGetTexPixelData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"emscriptenWebGLGetUniform")||(c.emscriptenWebGLGetUniform=function(){Ge("'emscriptenWebGLGetUniform' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"emscriptenWebGLGetVertexAttrib")||(c.emscriptenWebGLGetVertexAttrib=function(){Ge("'emscriptenWebGLGetVertexAttrib' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"writeGLArray")||(c.writeGLArray=function(){Ge("'writeGLArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"AL")||(c.AL=function(){Ge("'AL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"SDL_unicode")||(c.SDL_unicode=function(){Ge("'SDL_unicode' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"SDL_ttfContext")||(c.SDL_ttfContext=function(){Ge("'SDL_ttfContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"SDL_audio")||(c.SDL_audio=function(){Ge("'SDL_audio' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"SDL")||(c.SDL=function(){Ge("'SDL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"SDL_gfx")||(c.SDL_gfx=function(){Ge("'SDL_gfx' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"GLUT")||(c.GLUT=function(){Ge("'GLUT' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"EGL")||(c.EGL=function(){Ge("'EGL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"GLFW_Window")||(c.GLFW_Window=function(){Ge("'GLFW_Window' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"GLFW")||(c.GLFW=function(){Ge("'GLFW' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"GLEW")||(c.GLEW=function(){Ge("'GLEW' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"IDBStore")||(c.IDBStore=function(){Ge("'IDBStore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"runAndAbortIfError")||(c.runAndAbortIfError=function(){Ge("'runAndAbortIfError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"emval_handle_array")||(c.emval_handle_array=function(){Ge("'emval_handle_array' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"emval_free_list")||(c.emval_free_list=function(){Ge("'emval_free_list' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"emval_symbols")||(c.emval_symbols=function(){Ge("'emval_symbols' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"init_emval")||(c.init_emval=function(){Ge("'init_emval' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"count_emval_handles")||(c.count_emval_handles=function(){Ge("'count_emval_handles' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"get_first_emval")||(c.get_first_emval=function(){Ge("'get_first_emval' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getStringOrSymbol")||(c.getStringOrSymbol=function(){Ge("'getStringOrSymbol' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"requireHandle")||(c.requireHandle=function(){Ge("'requireHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"emval_newers")||(c.emval_newers=function(){Ge("'emval_newers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"craftEmvalAllocator")||(c.craftEmvalAllocator=function(){Ge("'craftEmvalAllocator' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"emval_get_global")||(c.emval_get_global=function(){Ge("'emval_get_global' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"emval_methodCallers")||(c.emval_methodCallers=function(){Ge("'emval_methodCallers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"InternalError")||(c.InternalError=function(){Ge("'InternalError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"BindingError")||(c.BindingError=function(){Ge("'BindingError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"UnboundTypeError")||(c.UnboundTypeError=function(){Ge("'UnboundTypeError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"PureVirtualError")||(c.PureVirtualError=function(){Ge("'PureVirtualError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"init_embind")||(c.init_embind=function(){Ge("'init_embind' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"throwInternalError")||(c.throwInternalError=function(){Ge("'throwInternalError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"throwBindingError")||(c.throwBindingError=function(){Ge("'throwBindingError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"throwUnboundTypeError")||(c.throwUnboundTypeError=function(){Ge("'throwUnboundTypeError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"ensureOverloadTable")||(c.ensureOverloadTable=function(){Ge("'ensureOverloadTable' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"exposePublicSymbol")||(c.exposePublicSymbol=function(){Ge("'exposePublicSymbol' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"replacePublicSymbol")||(c.replacePublicSymbol=function(){Ge("'replacePublicSymbol' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"extendError")||(c.extendError=function(){Ge("'extendError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"createNamedFunction")||(c.createNamedFunction=function(){Ge("'createNamedFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"registeredInstances")||(c.registeredInstances=function(){Ge("'registeredInstances' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getBasestPointer")||(c.getBasestPointer=function(){Ge("'getBasestPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"registerInheritedInstance")||(c.registerInheritedInstance=function(){Ge("'registerInheritedInstance' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"unregisterInheritedInstance")||(c.unregisterInheritedInstance=function(){Ge("'unregisterInheritedInstance' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getInheritedInstance")||(c.getInheritedInstance=function(){Ge("'getInheritedInstance' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getInheritedInstanceCount")||(c.getInheritedInstanceCount=function(){Ge("'getInheritedInstanceCount' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getLiveInheritedInstances")||(c.getLiveInheritedInstances=function(){Ge("'getLiveInheritedInstances' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"registeredTypes")||(c.registeredTypes=function(){Ge("'registeredTypes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"awaitingDependencies")||(c.awaitingDependencies=function(){Ge("'awaitingDependencies' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"typeDependencies")||(c.typeDependencies=function(){Ge("'typeDependencies' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"registeredPointers")||(c.registeredPointers=function(){Ge("'registeredPointers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"registerType")||(c.registerType=function(){Ge("'registerType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"whenDependentTypesAreResolved")||(c.whenDependentTypesAreResolved=function(){Ge("'whenDependentTypesAreResolved' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"embind_charCodes")||(c.embind_charCodes=function(){Ge("'embind_charCodes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"embind_init_charCodes")||(c.embind_init_charCodes=function(){Ge("'embind_init_charCodes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"readLatin1String")||(c.readLatin1String=function(){Ge("'readLatin1String' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getTypeName")||(c.getTypeName=function(){Ge("'getTypeName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"heap32VectorToArray")||(c.heap32VectorToArray=function(){Ge("'heap32VectorToArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"requireRegisteredType")||(c.requireRegisteredType=function(){Ge("'requireRegisteredType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"getShiftFromSize")||(c.getShiftFromSize=function(){Ge("'getShiftFromSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"integerReadValueFromPointer")||(c.integerReadValueFromPointer=function(){Ge("'integerReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"enumReadValueFromPointer")||(c.enumReadValueFromPointer=function(){Ge("'enumReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"floatReadValueFromPointer")||(c.floatReadValueFromPointer=function(){Ge("'floatReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"simpleReadValueFromPointer")||(c.simpleReadValueFromPointer=function(){Ge("'simpleReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"runDestructors")||(c.runDestructors=function(){Ge("'runDestructors' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"new_")||(c.new_=function(){Ge("'new_' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"craftInvokerFunction")||(c.craftInvokerFunction=function(){Ge("'craftInvokerFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"embind__requireFunction")||(c.embind__requireFunction=function(){Ge("'embind__requireFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"tupleRegistrations")||(c.tupleRegistrations=function(){Ge("'tupleRegistrations' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"structRegistrations")||(c.structRegistrations=function(){Ge("'structRegistrations' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"genericPointerToWireType")||(c.genericPointerToWireType=function(){Ge("'genericPointerToWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"constNoSmartPtrRawPointerToWireType")||(c.constNoSmartPtrRawPointerToWireType=function(){Ge("'constNoSmartPtrRawPointerToWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"nonConstNoSmartPtrRawPointerToWireType")||(c.nonConstNoSmartPtrRawPointerToWireType=function(){Ge("'nonConstNoSmartPtrRawPointerToWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"init_RegisteredPointer")||(c.init_RegisteredPointer=function(){Ge("'init_RegisteredPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"RegisteredPointer")||(c.RegisteredPointer=function(){Ge("'RegisteredPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"RegisteredPointer_getPointee")||(c.RegisteredPointer_getPointee=function(){Ge("'RegisteredPointer_getPointee' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"RegisteredPointer_destructor")||(c.RegisteredPointer_destructor=function(){Ge("'RegisteredPointer_destructor' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"RegisteredPointer_deleteObject")||(c.RegisteredPointer_deleteObject=function(){Ge("'RegisteredPointer_deleteObject' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"RegisteredPointer_fromWireType")||(c.RegisteredPointer_fromWireType=function(){Ge("'RegisteredPointer_fromWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"runDestructor")||(c.runDestructor=function(){Ge("'runDestructor' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"releaseClassHandle")||(c.releaseClassHandle=function(){Ge("'releaseClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"finalizationGroup")||(c.finalizationGroup=function(){Ge("'finalizationGroup' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"detachFinalizer_deps")||(c.detachFinalizer_deps=function(){Ge("'detachFinalizer_deps' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"detachFinalizer")||(c.detachFinalizer=function(){Ge("'detachFinalizer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"attachFinalizer")||(c.attachFinalizer=function(){Ge("'attachFinalizer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"makeClassHandle")||(c.makeClassHandle=function(){Ge("'makeClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"init_ClassHandle")||(c.init_ClassHandle=function(){Ge("'init_ClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"ClassHandle")||(c.ClassHandle=function(){Ge("'ClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"ClassHandle_isAliasOf")||(c.ClassHandle_isAliasOf=function(){Ge("'ClassHandle_isAliasOf' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"throwInstanceAlreadyDeleted")||(c.throwInstanceAlreadyDeleted=function(){Ge("'throwInstanceAlreadyDeleted' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"ClassHandle_clone")||(c.ClassHandle_clone=function(){Ge("'ClassHandle_clone' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"ClassHandle_delete")||(c.ClassHandle_delete=function(){Ge("'ClassHandle_delete' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"deletionQueue")||(c.deletionQueue=function(){Ge("'deletionQueue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"ClassHandle_isDeleted")||(c.ClassHandle_isDeleted=function(){Ge("'ClassHandle_isDeleted' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"ClassHandle_deleteLater")||(c.ClassHandle_deleteLater=function(){Ge("'ClassHandle_deleteLater' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"flushPendingDeletes")||(c.flushPendingDeletes=function(){Ge("'flushPendingDeletes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"delayFunction")||(c.delayFunction=function(){Ge("'delayFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"setDelayFunction")||(c.setDelayFunction=function(){Ge("'setDelayFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"RegisteredClass")||(c.RegisteredClass=function(){Ge("'RegisteredClass' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"shallowCopyInternalPointer")||(c.shallowCopyInternalPointer=function(){Ge("'shallowCopyInternalPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"downcastPointer")||(c.downcastPointer=function(){Ge("'downcastPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"upcastPointer")||(c.upcastPointer=function(){Ge("'upcastPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"validateThis")||(c.validateThis=function(){Ge("'validateThis' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"char_0")||(c.char_0=function(){Ge("'char_0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"char_9")||(c.char_9=function(){Ge("'char_9' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"makeLegalFunctionName")||(c.makeLegalFunctionName=function(){Ge("'makeLegalFunctionName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"warnOnce")||(c.warnOnce=function(){Ge("'warnOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"stackSave")||(c.stackSave=function(){Ge("'stackSave' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"stackRestore")||(c.stackRestore=function(){Ge("'stackRestore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"stackAlloc")||(c.stackAlloc=function(){Ge("'stackAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"AsciiToString")||(c.AsciiToString=function(){Ge("'AsciiToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"stringToAscii")||(c.stringToAscii=function(){Ge("'stringToAscii' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"UTF16ToString")||(c.UTF16ToString=function(){Ge("'UTF16ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"stringToUTF16")||(c.stringToUTF16=function(){Ge("'stringToUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"lengthBytesUTF16")||(c.lengthBytesUTF16=function(){Ge("'lengthBytesUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"UTF32ToString")||(c.UTF32ToString=function(){Ge("'UTF32ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"stringToUTF32")||(c.stringToUTF32=function(){Ge("'stringToUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"lengthBytesUTF32")||(c.lengthBytesUTF32=function(){Ge("'lengthBytesUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"allocateUTF8")||(c.allocateUTF8=function(){Ge("'allocateUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(c,"allocateUTF8OnStack")||(c.allocateUTF8OnStack=function(){Ge("'allocateUTF8OnStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),c.writeStackCookie=ke,c.checkStackCookie=xe,Object.getOwnPropertyDescriptor(c,"ALLOC_NORMAL")||Object.defineProperty(c,"ALLOC_NORMAL",{configurable:!0,get:function(){Ge("'ALLOC_NORMAL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}}),Object.getOwnPropertyDescriptor(c,"ALLOC_STACK")||Object.defineProperty(c,"ALLOC_STACK",{configurable:!0,get:function(){Ge("'ALLOC_STACK' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}}),Object.getOwnPropertyDescriptor(c,"ALLOC_DYNAMIC")||Object.defineProperty(c,"ALLOC_DYNAMIC",{configurable:!0,get:function(){Ge("'ALLOC_DYNAMIC' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}}),Object.getOwnPropertyDescriptor(c,"ALLOC_NONE")||Object.defineProperty(c,"ALLOC_NONE",{configurable:!0,get:function(){Ge("'ALLOC_NONE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}}),We=function e(){yn||Ka(),yn||(We=e)},c.run=Ka,c.preInit)for("function"==typeof c.preInit&&(c.preInit=[c.preInit]);c.preInit.length>0;)c.preInit.pop()();return F=!0,Ka(),e.ready});e.exports=s}).call(this,"/index.js",r(3),"/",r(2).Buffer)},function(e,t,r){"use strict";t.byteLength=function(e){var t=u(e),r=t[0],i=t[1];return 3*(r+i)/4-i},t.toByteArray=function(e){var t,r,i=u(e),o=i[0],s=i[1],c=new a(function(e,t,r){return 3*(t+r)/4-r}(0,o,s)),l=0,h=s>0?o-4:o;for(r=0;r>16&255,c[l++]=t>>8&255,c[l++]=255&t;2===s&&(t=n[e.charCodeAt(r)]<<2|n[e.charCodeAt(r+1)]>>4,c[l++]=255&t);1===s&&(t=n[e.charCodeAt(r)]<<10|n[e.charCodeAt(r+1)]<<4|n[e.charCodeAt(r+2)]>>2,c[l++]=t>>8&255,c[l++]=255&t);return c},t.fromByteArray=function(e){for(var t,r=e.length,n=r%3,a=[],o=0,s=r-n;os?s:o+16383));1===n?(t=e[r-1],a.push(i[t>>2]+i[t<<4&63]+"==")):2===n&&(t=(e[r-2]<<8)+e[r-1],a.push(i[t>>10]+i[t>>4&63]+i[t<<2&63]+"="));return a.join("")};for(var i=[],n=[],a="undefined"!=typeof Uint8Array?Uint8Array:Array,o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",s=0,c=o.length;s0)throw new Error("Invalid string. Length must be a multiple of 4");var r=e.indexOf("=");return-1===r&&(r=t),[r,r===t?0:4-r%4]}function l(e,t,r){for(var n,a,o=[],s=t;s>18&63]+i[a>>12&63]+i[a>>6&63]+i[63&a]);return o.join("")}n["-".charCodeAt(0)]=62,n["_".charCodeAt(0)]=63},function(e,t){t.read=function(e,t,r,i,n){var a,o,s=8*n-i-1,c=(1<>1,l=-7,h=r?n-1:0,d=r?-1:1,p=e[t+h];for(h+=d,a=p&(1<<-l)-1,p>>=-l,l+=s;l>0;a=256*a+e[t+h],h+=d,l-=8);for(o=a&(1<<-l)-1,a>>=-l,l+=i;l>0;o=256*o+e[t+h],h+=d,l-=8);if(0===a)a=1-u;else{if(a===c)return o?NaN:1/0*(p?-1:1);o+=Math.pow(2,i),a-=u}return(p?-1:1)*o*Math.pow(2,a-i)},t.write=function(e,t,r,i,n,a){var o,s,c,u=8*a-n-1,l=(1<>1,d=23===n?Math.pow(2,-24)-Math.pow(2,-77):0,p=i?0:a-1,f=i?1:-1,m=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(s=isNaN(t)?1:0,o=l):(o=Math.floor(Math.log(t)/Math.LN2),t*(c=Math.pow(2,-o))<1&&(o--,c*=2),(t+=o+h>=1?d/c:d*Math.pow(2,1-h))*c>=2&&(o++,c/=2),o+h>=l?(s=0,o=l):o+h>=1?(s=(t*c-1)*Math.pow(2,n),o+=h):(s=t*Math.pow(2,h-1)*Math.pow(2,n),o=0));n>=8;e[r+p]=255&s,p+=f,s/=256,n-=8);for(o=o<0;e[r+p]=255&o,p+=f,o/=256,u-=8);e[r+p-f]|=128*m}},function(e,t,r){"use strict";var i=r(153),n=r(38),a=null;t.getInstance=function(e){a?e(null,a):o(null,e)};var o=t.init=function(e,t){!function(e,t){function r(e){t(null,e)}function n(e){t(e,null)}e=e||10485760,navigator.webkitPersistentStorage&&navigator.webkitPersistentStorage.requestQuota?navigator.webkitPersistentStorage.requestQuota(e,r,n):window.webkitStorageInfo&&window.webkitStorageInfo.requestQuota?window.webkitStorageInfo.requestQuota(window.PERSISTENT,e,r,n):window.requestFileSystem?(!0===i.isPhoneGap()&&(e=0),r(e)):n("NO_SUPPORT")}(e,(function(e,r){if(e)return t(e,null);!function(e,t,r){window.navigator.webkitRequestFileSystem?window.navigator.webkitRequestFileSystem(e,t,r):window.requestFileSystem?window.requestFileSystem(window.LocalFileSystem.PERSISTENT,e,t,r):window.webkitRequestFileSystem?window.webkitRequestFileSystem(window.PERSISTENT,e,t,r):r("NO_SUPPORT")}(r,(function(e){a=e,t(null,r)}),(function(e){t(e,null)}))}))};t.writeFile=function(e,t,r,n){var a=i.wrapFail(r),o=i.wrapSuccess(r);this.getFile(e,{create:!0,exclusive:!1},(function(e,s){if(e)return r(e,null);s.createWriter((function(e){e.onwrite=function(){o(s.toURL())},e.onerror=function(e){a(e.target.error)},!0===n&&e.seek(e.length),i.isMobile()?e.write(t):e.write(new Blob([t]))}),a)}))},t.getDirectory=function(e,t,r){r||(r=t,t={create:!1});var n=i.wrapSuccess(r),o=i.wrapFail(r);a.root.getDirectory(e,t,n,o)},t.getFile=function(e,t,r){r||(r=t,t={create:!1});var o=n.basename(e),s=n.dirname(e),c=i.wrapSuccess(r),u=i.wrapFail(r);function l(e){e.getFile(o,t,c,u)}"."===s?l(a.root):this.getDirectory(s,t,(function(e,t){e?r(e,null):l(t)}))}},function(e,t,r){var i=r(2),n=i.Buffer;function a(e,t){for(var r in e)t[r]=e[r]}function o(e,t,r){return n(e,t,r)}n.from&&n.alloc&&n.allocUnsafe&&n.allocUnsafeSlow?e.exports=i:(a(i,t),t.Buffer=o),o.prototype=Object.create(n.prototype),a(n,o),o.from=function(e,t,r){if("number"==typeof e)throw new TypeError("Argument must not be a number");return n(e,t,r)},o.alloc=function(e,t,r){if("number"!=typeof e)throw new TypeError("Argument must be a number");var i=n(e);return void 0!==t?"string"==typeof r?i.fill(t,r):i.fill(t):i.fill(0),i},o.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return n(e)},o.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return i.SlowBuffer(e)}},function(e,t,r){(t=e.exports=r(155)).Stream=t,t.Readable=t,t.Writable=r(159),t.Duplex=r(47),t.Transform=r(160),t.PassThrough=r(282),t.finished=r(106),t.pipeline=r(283)},function(e,t){},function(e,t,r){"use strict";function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,i)}return r}function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){for(var r=0;r0?this.tail.next=t:this.head=t,this.tail=t,++this.length}},{key:"unshift",value:function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length}},{key:"shift",value:function(){if(0!==this.length){var e=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,e}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(e){if(0===this.length)return"";for(var t=this.head,r=""+t.data;t=t.next;)r+=e+t.data;return r}},{key:"concat",value:function(e){if(0===this.length)return o.alloc(0);for(var t,r,i,n=o.allocUnsafe(e>>>0),a=this.head,s=0;a;)t=a.data,r=n,i=s,o.prototype.copy.call(t,r,i),s+=a.data.length,a=a.next;return n}},{key:"consume",value:function(e,t){var r;return en.length?n.length:e;if(a===n.length?i+=n:i+=n.slice(0,e),0==(e-=a)){a===n.length?(++r,t.next?this.head=t.next:this.head=this.tail=null):(this.head=t,t.data=n.slice(a));break}++r}return this.length-=r,i}},{key:"_getBuffer",value:function(e){var t=o.allocUnsafe(e),r=this.head,i=1;for(r.data.copy(t),e-=r.data.length;r=r.next;){var n=r.data,a=e>n.length?n.length:e;if(n.copy(t,t.length-e,0,a),0==(e-=a)){a===n.length?(++i,r.next?this.head=r.next:this.head=this.tail=null):(this.head=r,r.data=n.slice(a));break}++i}return this.length-=i,t}},{key:c,value:function(e,t){return s(this,function(e){for(var t=1;t0,(function(e){i||(i=e),e&&o.forEach(u),a||(o.forEach(u),n(i))}))}));return t.reduce(l)}},function(e,t,r){var i=r(0),n=r(48),a=r(1).Buffer,o=[1518500249,1859775393,-1894007588,-899497514],s=new Array(80);function c(){this.init(),this._w=s,n.call(this,64,56)}function u(e){return e<<30|e>>>2}function l(e,t,r,i){return 0===e?t&r|~t&i:2===e?t&r|t&i|r&i:t^r^i}i(c,n),c.prototype.init=function(){return this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878,this._e=3285377520,this},c.prototype._update=function(e){for(var t,r=this._w,i=0|this._a,n=0|this._b,a=0|this._c,s=0|this._d,c=0|this._e,h=0;h<16;++h)r[h]=e.readInt32BE(4*h);for(;h<80;++h)r[h]=r[h-3]^r[h-8]^r[h-14]^r[h-16];for(var d=0;d<80;++d){var p=~~(d/20),f=0|((t=i)<<5|t>>>27)+l(p,n,a,s)+c+r[d]+o[p];c=s,s=a,a=u(n),n=i,i=f}this._a=i+this._a|0,this._b=n+this._b|0,this._c=a+this._c|0,this._d=s+this._d|0,this._e=c+this._e|0},c.prototype._hash=function(){var e=a.allocUnsafe(20);return e.writeInt32BE(0|this._a,0),e.writeInt32BE(0|this._b,4),e.writeInt32BE(0|this._c,8),e.writeInt32BE(0|this._d,12),e.writeInt32BE(0|this._e,16),e},e.exports=c},function(e,t,r){var i=r(0),n=r(48),a=r(1).Buffer,o=[1518500249,1859775393,-1894007588,-899497514],s=new Array(80);function c(){this.init(),this._w=s,n.call(this,64,56)}function u(e){return e<<5|e>>>27}function l(e){return e<<30|e>>>2}function h(e,t,r,i){return 0===e?t&r|~t&i:2===e?t&r|t&i|r&i:t^r^i}i(c,n),c.prototype.init=function(){return this._a=1732584193,this._b=4023233417,this._c=2562383102,this._d=271733878,this._e=3285377520,this},c.prototype._update=function(e){for(var t,r=this._w,i=0|this._a,n=0|this._b,a=0|this._c,s=0|this._d,c=0|this._e,d=0;d<16;++d)r[d]=e.readInt32BE(4*d);for(;d<80;++d)r[d]=(t=r[d-3]^r[d-8]^r[d-14]^r[d-16])<<1|t>>>31;for(var p=0;p<80;++p){var f=~~(p/20),m=u(i)+h(f,n,a,s)+c+r[p]+o[f]|0;c=s,s=a,a=l(n),n=i,i=m}this._a=i+this._a|0,this._b=n+this._b|0,this._c=a+this._c|0,this._d=s+this._d|0,this._e=c+this._e|0},c.prototype._hash=function(){var e=a.allocUnsafe(20);return e.writeInt32BE(0|this._a,0),e.writeInt32BE(0|this._b,4),e.writeInt32BE(0|this._c,8),e.writeInt32BE(0|this._d,12),e.writeInt32BE(0|this._e,16),e},e.exports=c},function(e,t,r){var i=r(0),n=r(161),a=r(48),o=r(1).Buffer,s=new Array(64);function c(){this.init(),this._w=s,a.call(this,64,56)}i(c,n),c.prototype.init=function(){return this._a=3238371032,this._b=914150663,this._c=812702999,this._d=4144912697,this._e=4290775857,this._f=1750603025,this._g=1694076839,this._h=3204075428,this},c.prototype._hash=function(){var e=o.allocUnsafe(28);return e.writeInt32BE(this._a,0),e.writeInt32BE(this._b,4),e.writeInt32BE(this._c,8),e.writeInt32BE(this._d,12),e.writeInt32BE(this._e,16),e.writeInt32BE(this._f,20),e.writeInt32BE(this._g,24),e},e.exports=c},function(e,t,r){var i=r(0),n=r(162),a=r(48),o=r(1).Buffer,s=new Array(160);function c(){this.init(),this._w=s,a.call(this,128,112)}i(c,n),c.prototype.init=function(){return this._ah=3418070365,this._bh=1654270250,this._ch=2438529370,this._dh=355462360,this._eh=1731405415,this._fh=2394180231,this._gh=3675008525,this._hh=1203062813,this._al=3238371032,this._bl=914150663,this._cl=812702999,this._dl=4144912697,this._el=4290775857,this._fl=1750603025,this._gl=1694076839,this._hl=3204075428,this},c.prototype._hash=function(){var e=o.allocUnsafe(48);function t(t,r,i){e.writeInt32BE(t,i),e.writeInt32BE(r,i+4)}return t(this._ah,this._al,0),t(this._bh,this._bl,8),t(this._ch,this._cl,16),t(this._dh,this._dl,24),t(this._eh,this._el,32),t(this._fh,this._fl,40),e},e.exports=c},function(e,t){},function(e,t,r){"use strict";var i=r(1).Buffer,n=r(290);e.exports=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.head=null,this.tail=null,this.length=0}return e.prototype.push=function(e){var t={data:e,next:null};this.length>0?this.tail.next=t:this.head=t,this.tail=t,++this.length},e.prototype.unshift=function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length},e.prototype.shift=function(){if(0!==this.length){var e=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,e}},e.prototype.clear=function(){this.head=this.tail=null,this.length=0},e.prototype.join=function(e){if(0===this.length)return"";for(var t=this.head,r=""+t.data;t=t.next;)r+=e+t.data;return r},e.prototype.concat=function(e){if(0===this.length)return i.alloc(0);if(1===this.length)return this.head.data;for(var t,r,n,a=i.allocUnsafe(e>>>0),o=this.head,s=0;o;)t=o.data,r=a,n=s,t.copy(r,n),s+=o.data.length,o=o.next;return a},e}(),n&&n.inspect&&n.inspect.custom&&(e.exports.prototype[n.inspect.custom]=function(){var e=n.inspect({length:this.length});return this.constructor.name+" "+e})},function(e,t){},function(e,t,r){"use strict";e.exports=a;var i=r(166),n=Object.create(r(21));function a(e){if(!(this instanceof a))return new a(e);i.call(this,e)}n.inherits=r(0),n.inherits(a,i),a.prototype._transform=function(e,t,r){r(null,e)}},function(e,t,r){e.exports=r(110)},function(e,t,r){e.exports=r(39)},function(e,t,r){e.exports=r(109).Transform},function(e,t,r){e.exports=r(109).PassThrough},function(e,t,r){"use strict";var i=r(0),n=r(1).Buffer,a=r(33),o=n.alloc(128);function s(e,t){a.call(this,"digest"),"string"==typeof t&&(t=n.from(t)),this._alg=e,this._key=t,t.length>64?t=e(t):t.length<64&&(t=n.concat([t,o],64));for(var r=this._ipad=n.allocUnsafe(64),i=this._opad=n.allocUnsafe(64),s=0;s<64;s++)r[s]=54^t[s],i[s]=92^t[s];this._hash=[r]}i(s,a),s.prototype._update=function(e){this._hash.push(e)},s.prototype._final=function(){var e=this._alg(n.concat(this._hash));return this._alg(n.concat([this._opad,e]))},e.exports=s},function(e,t,r){e.exports=r(169)},function(e,t,r){(function(t,i){var n,a=r(171),o=r(172),s=r(173),c=r(1).Buffer,u=t.crypto&&t.crypto.subtle,l={sha:"SHA-1","sha-1":"SHA-1",sha1:"SHA-1",sha256:"SHA-256","sha-256":"SHA-256",sha384:"SHA-384","sha-384":"SHA-384","sha-512":"SHA-512",sha512:"SHA-512"},h=[];function d(e,t,r,i,n){return u.importKey("raw",e,{name:"PBKDF2"},!1,["deriveBits"]).then((function(e){return u.deriveBits({name:"PBKDF2",salt:t,iterations:r,hash:{name:n}},e,i<<3)})).then((function(e){return c.from(e)}))}e.exports=function(e,r,p,f,m,g){"function"==typeof m&&(g=m,m=void 0);var _=l[(m=m||"sha1").toLowerCase()];if(!_||"function"!=typeof t.Promise)return i.nextTick((function(){var t;try{t=s(e,r,p,f,m)}catch(e){return g(e)}g(null,t)}));if(a(e,r,p,f),"function"!=typeof g)throw new Error("No callback provided to pbkdf2");c.isBuffer(e)||(e=c.from(e,o)),c.isBuffer(r)||(r=c.from(r,o)),function(e,t){e.then((function(e){i.nextTick((function(){t(null,e)}))}),(function(e){i.nextTick((function(){t(e)}))}))}(function(e){if(t.process&&!t.process.browser)return Promise.resolve(!1);if(!u||!u.importKey||!u.deriveBits)return Promise.resolve(!1);if(void 0!==h[e])return h[e];var r=d(n=n||c.alloc(8),n,10,128,e).then((function(){return!0})).catch((function(){return!1}));return h[e]=r,r}(_).then((function(t){return t?d(e,r,p,f,_):s(e,r,p,f,m)})),g)}}).call(this,r(8),r(3))},function(e,t,r){var i=r(300),n=r(112),a=r(113),o=r(313),s=r(80);function c(e,t,r){if(e=e.toLowerCase(),a[e])return n.createCipheriv(e,t,r);if(o[e])return new i({key:t,iv:r,mode:e});throw new TypeError("invalid suite type")}function u(e,t,r){if(e=e.toLowerCase(),a[e])return n.createDecipheriv(e,t,r);if(o[e])return new i({key:t,iv:r,mode:e,decrypt:!0});throw new TypeError("invalid suite type")}t.createCipher=t.Cipher=function(e,t){var r,i;if(e=e.toLowerCase(),a[e])r=a[e].key,i=a[e].iv;else{if(!o[e])throw new TypeError("invalid suite type");r=8*o[e].key,i=o[e].iv}var n=s(t,!1,r,i);return c(e,n.key,n.iv)},t.createCipheriv=t.Cipheriv=c,t.createDecipher=t.Decipher=function(e,t){var r,i;if(e=e.toLowerCase(),a[e])r=a[e].key,i=a[e].iv;else{if(!o[e])throw new TypeError("invalid suite type");r=8*o[e].key,i=o[e].iv}var n=s(t,!1,r,i);return u(e,n.key,n.iv)},t.createDecipheriv=t.Decipheriv=u,t.listCiphers=t.getCiphers=function(){return Object.keys(o).concat(n.getCiphers())}},function(e,t,r){var i=r(33),n=r(301),a=r(0),o=r(1).Buffer,s={"des-ede3-cbc":n.CBC.instantiate(n.EDE),"des-ede3":n.EDE,"des-ede-cbc":n.CBC.instantiate(n.EDE),"des-ede":n.EDE,"des-cbc":n.CBC.instantiate(n.DES),"des-ecb":n.DES};function c(e){i.call(this);var t,r=e.mode.toLowerCase(),n=s[r];t=e.decrypt?"decrypt":"encrypt";var a=e.key;o.isBuffer(a)||(a=o.from(a)),"des-ede"!==r&&"des-ede-cbc"!==r||(a=o.concat([a,a.slice(0,8)]));var c=e.iv;o.isBuffer(c)||(c=o.from(c)),this._des=n.create({key:a,iv:c,type:t})}s.des=s["des-cbc"],s.des3=s["des-ede3-cbc"],e.exports=c,a(c,i),c.prototype._update=function(e){return o.from(this._des.update(e))},c.prototype._final=function(){return o.from(this._des.final())}},function(e,t,r){"use strict";t.utils=r(174),t.Cipher=r(111),t.DES=r(175),t.CBC=r(302),t.EDE=r(303)},function(e,t,r){"use strict";var i=r(19),n=r(0),a={};function o(e){i.equal(e.length,8,"Invalid IV length"),this.iv=new Array(8);for(var t=0;t15){var e=this.cache.slice(0,16);return this.cache=this.cache.slice(16),e}return null},d.prototype.flush=function(){for(var e=16-this.cache.length,t=a.allocUnsafe(e),r=-1;++r>o%8,e._prev=a(e._prev,r?i:n);return s}function a(e,t){var r=e.length,n=-1,a=i.allocUnsafe(e.length);for(e=i.concat([e,i.from([t])]);++n>7;return a}t.encrypt=function(e,t,r){for(var a=t.length,o=i.allocUnsafe(a),s=-1;++s>>0,0),t.writeUInt32BE(e[1]>>>0,4),t.writeUInt32BE(e[2]>>>0,8),t.writeUInt32BE(e[3]>>>0,12),t}function o(e){this.h=e,this.state=i.alloc(16,0),this.cache=i.allocUnsafe(0)}o.prototype.ghash=function(e){for(var t=-1;++t0;t--)i[t]=i[t]>>>1|(1&i[t-1])<<31;i[0]=i[0]>>>1,r&&(i[0]=i[0]^225<<24)}this.state=a(n)},o.prototype.update=function(e){var t;for(this.cache=i.concat([this.cache,e]);this.cache.length>=16;)t=this.cache.slice(0,16),this.cache=this.cache.slice(16),this.ghash(t)},o.prototype.final=function(e,t){return this.cache.length&&this.ghash(i.concat([this.cache,n],16)),this.ghash(a([0,e,0,t])),this.state},e.exports=o},function(e,t,r){var i=r(179),n=r(1).Buffer,a=r(113),o=r(180),s=r(33),c=r(79),u=r(80);function l(e,t,r){s.call(this),this._cache=new h,this._last=void 0,this._cipher=new c.AES(t),this._prev=n.from(r),this._mode=e,this._autopadding=!0}function h(){this.cache=n.allocUnsafe(0)}function d(e,t,r){var s=a[e.toLowerCase()];if(!s)throw new TypeError("invalid suite type");if("string"==typeof r&&(r=n.from(r)),"GCM"!==s.mode&&r.length!==s.iv)throw new TypeError("invalid iv length "+r.length);if("string"==typeof t&&(t=n.from(t)),t.length!==s.key/8)throw new TypeError("invalid key length "+t.length);return"stream"===s.type?new o(s.module,t,r,!0):"auth"===s.type?new i(s.module,t,r,!0):new l(s.module,t,r)}r(0)(l,s),l.prototype._update=function(e){var t,r;this._cache.add(e);for(var i=[];t=this._cache.get(this._autopadding);)r=this._mode.decrypt(this,t),i.push(r);return n.concat(i)},l.prototype._final=function(){var e=this._cache.flush();if(this._autopadding)return function(e){var t=e[15];if(t<1||t>16)throw new Error("unable to decrypt data");var r=-1;for(;++r16)return t=this.cache.slice(0,16),this.cache=this.cache.slice(16),t}else if(this.cache.length>=16)return t=this.cache.slice(0,16),this.cache=this.cache.slice(16),t;return null},h.prototype.flush=function(){if(this.cache.length)return this.cache},t.createDecipher=function(e,t){var r=a[e.toLowerCase()];if(!r)throw new TypeError("invalid suite type");var i=u(t,!1,r.key,r.iv);return d(e,i.key,i.iv)},t.createDecipheriv=d},function(e,t){t["des-ecb"]={key:8,iv:0},t["des-cbc"]=t.des={key:8,iv:8},t["des-ede3-cbc"]=t.des3={key:24,iv:8},t["des-ede3"]={key:24,iv:0},t["des-ede-cbc"]={key:16,iv:8},t["des-ede"]={key:16,iv:0}},function(e,t,r){(function(e){var i=r(181),n=r(319),a=r(320);var o={binary:!0,hex:!0,base64:!0};t.DiffieHellmanGroup=t.createDiffieHellmanGroup=t.getDiffieHellman=function(t){var r=new e(n[t].prime,"hex"),i=new e(n[t].gen,"hex");return new a(r,i)},t.createDiffieHellman=t.DiffieHellman=function t(r,n,s,c){return e.isBuffer(n)||void 0===o[n]?t(r,"binary",n,s):(n=n||"binary",c=c||"binary",s=s||new e([2]),e.isBuffer(s)||(s=new e(s,c)),"number"==typeof r?new a(i(r,s),s,!0):(e.isBuffer(r)||(r=new e(r,n)),new a(r,s,!0)))}}).call(this,r(2).Buffer)},function(e,t){},function(e,t,r){(function(e){!function(e,t){"use strict";function i(e,t){if(!e)throw new Error(t||"Assertion failed")}function n(e,t){e.super_=t;var r=function(){};r.prototype=t.prototype,e.prototype=new r,e.prototype.constructor=e}function a(e,t,r){if(a.isBN(e))return e;this.negative=0,this.words=null,this.length=0,this.red=null,null!==e&&("le"!==t&&"be"!==t||(r=t,t=10),this._init(e||0,t||10,r||"be"))}var o;"object"==typeof e?e.exports=a:t.BN=a,a.BN=a,a.wordSize=26;try{o=r(317).Buffer}catch(e){}function s(e,t,r){for(var i=0,n=Math.min(e.length,r),a=t;a=49&&o<=54?o-49+10:o>=17&&o<=22?o-17+10:15&o}return i}function c(e,t,r,i){for(var n=0,a=Math.min(e.length,r),o=t;o=49?s-49+10:s>=17?s-17+10:s}return n}a.isBN=function(e){return e instanceof a||null!==e&&"object"==typeof e&&e.constructor.wordSize===a.wordSize&&Array.isArray(e.words)},a.max=function(e,t){return e.cmp(t)>0?e:t},a.min=function(e,t){return e.cmp(t)<0?e:t},a.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),i(t===(0|t)&&t>=2&&t<=36);var n=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&n++,16===t?this._parseHex(e,n):this._parseBase(e,t,n),"-"===e[0]&&(this.negative=1),this.strip(),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(i(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initArray=function(e,t,r){if(i("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var n=0;n=0;n-=3)o=e[n]|e[n-1]<<8|e[n-2]<<16,this.words[a]|=o<>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);else if("le"===r)for(n=0,a=0;n>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);return this.strip()},a.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)n=s(e,r,r+6),this.words[i]|=n<>>26-a&4194303,(a+=24)>=26&&(a-=26,i++);r+6!==t&&(n=s(e,t,r+6),this.words[i]|=n<>>26-a&4194303),this.strip()},a.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var i=0,n=1;n<=67108863;n*=t)i++;i--,n=n/t|0;for(var a=e.length-r,o=a%i,s=Math.min(a,a-o)+r,u=0,l=r;l1&&0===this.words[this.length-1];)this.length--;return this._normSign()},a.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},a.prototype.inspect=function(){return(this.red?""};var u=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],l=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],h=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];function d(e,t,r){r.negative=t.negative^e.negative;var i=e.length+t.length|0;r.length=i,i=i-1|0;var n=0|e.words[0],a=0|t.words[0],o=n*a,s=67108863&o,c=o/67108864|0;r.words[0]=s;for(var u=1;u>>26,h=67108863&c,d=Math.min(u,t.length-1),p=Math.max(0,u-e.length+1);p<=d;p++){var f=u-p|0;l+=(o=(n=0|e.words[f])*(a=0|t.words[p])+h)/67108864|0,h=67108863&o}r.words[u]=0|h,c=0|l}return 0!==c?r.words[u]=0|c:r.length--,r.strip()}a.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var n=0,a=0,o=0;o>>24-n&16777215)||o!==this.length-1?u[6-c.length]+c+r:c+r,(n+=2)>=26&&(n-=26,o--)}for(0!==a&&(r=a.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var d=l[e],p=h[e];r="";var f=this.clone();for(f.negative=0;!f.isZero();){var m=f.modn(p).toString(e);r=(f=f.idivn(p)).isZero()?m+r:u[d-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}i(!1,"Base should be between 2 and 36")},a.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&i(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},a.prototype.toJSON=function(){return this.toString(16)},a.prototype.toBuffer=function(e,t){return i(void 0!==o),this.toArrayLike(o,e,t)},a.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)},a.prototype.toArrayLike=function(e,t,r){var n=this.byteLength(),a=r||Math.max(1,n);i(n<=a,"byte array longer than desired length"),i(a>0,"Requested array length <= 0"),this.strip();var o,s,c="le"===t,u=new e(a),l=this.clone();if(c){for(s=0;!l.isZero();s++)o=l.andln(255),l.iushrn(8),u[s]=o;for(;s=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},a.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},a.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},a.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},a.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},a.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},a.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},a.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var i=0;ie.length?this.clone().ixor(e):e.clone().ixor(this)},a.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},a.prototype.inotn=function(e){i("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var n=0;n0&&(this.words[n]=~this.words[n]&67108863>>26-r),this.strip()},a.prototype.notn=function(e){return this.clone().inotn(e)},a.prototype.setn=function(e,t){i("number"==typeof e&&e>=0);var r=e/26|0,n=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,i=e):(r=e,i=this);for(var n=0,a=0;a>>26;for(;0!==n&&a>>26;if(this.length=r.length,0!==n)this.words[this.length]=n,this.length++;else if(r!==this)for(;ae.length?this.clone().iadd(e):e.clone().iadd(this)},a.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,i,n=this.cmp(e);if(0===n)return this.negative=0,this.length=1,this.words[0]=0,this;n>0?(r=this,i=e):(r=e,i=this);for(var a=0,o=0;o>26,this.words[o]=67108863&t;for(;0!==a&&o>26,this.words[o]=67108863&t;if(0===a&&o>>13,p=0|o[1],f=8191&p,m=p>>>13,g=0|o[2],_=8191&g,v=g>>>13,y=0|o[3],b=8191&y,E=y>>>13,w=0|o[4],S=8191&w,k=w>>>13,x=0|o[5],M=8191&x,N=x>>>13,j=0|o[6],T=8191&j,R=j>>>13,I=0|o[7],O=8191&I,A=I>>>13,P=0|o[8],D=8191&P,F=P>>>13,C=0|o[9],B=8191&C,z=C>>>13,L=0|s[0],U=8191&L,H=L>>>13,q=0|s[1],K=8191&q,Z=q>>>13,W=0|s[2],X=8191&W,Q=W>>>13,J=0|s[3],V=8191&J,G=J>>>13,Y=0|s[4],$=8191&Y,ee=Y>>>13,te=0|s[5],re=8191&te,ie=te>>>13,ne=0|s[6],ae=8191&ne,oe=ne>>>13,se=0|s[7],ce=8191&se,ue=se>>>13,le=0|s[8],he=8191&le,de=le>>>13,pe=0|s[9],fe=8191&pe,me=pe>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(u+(i=Math.imul(h,U))|0)+((8191&(n=(n=Math.imul(h,H))+Math.imul(d,U)|0))<<13)|0;u=((a=Math.imul(d,H))+(n>>>13)|0)+(ge>>>26)|0,ge&=67108863,i=Math.imul(f,U),n=(n=Math.imul(f,H))+Math.imul(m,U)|0,a=Math.imul(m,H);var _e=(u+(i=i+Math.imul(h,K)|0)|0)+((8191&(n=(n=n+Math.imul(h,Z)|0)+Math.imul(d,K)|0))<<13)|0;u=((a=a+Math.imul(d,Z)|0)+(n>>>13)|0)+(_e>>>26)|0,_e&=67108863,i=Math.imul(_,U),n=(n=Math.imul(_,H))+Math.imul(v,U)|0,a=Math.imul(v,H),i=i+Math.imul(f,K)|0,n=(n=n+Math.imul(f,Z)|0)+Math.imul(m,K)|0,a=a+Math.imul(m,Z)|0;var ve=(u+(i=i+Math.imul(h,X)|0)|0)+((8191&(n=(n=n+Math.imul(h,Q)|0)+Math.imul(d,X)|0))<<13)|0;u=((a=a+Math.imul(d,Q)|0)+(n>>>13)|0)+(ve>>>26)|0,ve&=67108863,i=Math.imul(b,U),n=(n=Math.imul(b,H))+Math.imul(E,U)|0,a=Math.imul(E,H),i=i+Math.imul(_,K)|0,n=(n=n+Math.imul(_,Z)|0)+Math.imul(v,K)|0,a=a+Math.imul(v,Z)|0,i=i+Math.imul(f,X)|0,n=(n=n+Math.imul(f,Q)|0)+Math.imul(m,X)|0,a=a+Math.imul(m,Q)|0;var ye=(u+(i=i+Math.imul(h,V)|0)|0)+((8191&(n=(n=n+Math.imul(h,G)|0)+Math.imul(d,V)|0))<<13)|0;u=((a=a+Math.imul(d,G)|0)+(n>>>13)|0)+(ye>>>26)|0,ye&=67108863,i=Math.imul(S,U),n=(n=Math.imul(S,H))+Math.imul(k,U)|0,a=Math.imul(k,H),i=i+Math.imul(b,K)|0,n=(n=n+Math.imul(b,Z)|0)+Math.imul(E,K)|0,a=a+Math.imul(E,Z)|0,i=i+Math.imul(_,X)|0,n=(n=n+Math.imul(_,Q)|0)+Math.imul(v,X)|0,a=a+Math.imul(v,Q)|0,i=i+Math.imul(f,V)|0,n=(n=n+Math.imul(f,G)|0)+Math.imul(m,V)|0,a=a+Math.imul(m,G)|0;var be=(u+(i=i+Math.imul(h,$)|0)|0)+((8191&(n=(n=n+Math.imul(h,ee)|0)+Math.imul(d,$)|0))<<13)|0;u=((a=a+Math.imul(d,ee)|0)+(n>>>13)|0)+(be>>>26)|0,be&=67108863,i=Math.imul(M,U),n=(n=Math.imul(M,H))+Math.imul(N,U)|0,a=Math.imul(N,H),i=i+Math.imul(S,K)|0,n=(n=n+Math.imul(S,Z)|0)+Math.imul(k,K)|0,a=a+Math.imul(k,Z)|0,i=i+Math.imul(b,X)|0,n=(n=n+Math.imul(b,Q)|0)+Math.imul(E,X)|0,a=a+Math.imul(E,Q)|0,i=i+Math.imul(_,V)|0,n=(n=n+Math.imul(_,G)|0)+Math.imul(v,V)|0,a=a+Math.imul(v,G)|0,i=i+Math.imul(f,$)|0,n=(n=n+Math.imul(f,ee)|0)+Math.imul(m,$)|0,a=a+Math.imul(m,ee)|0;var Ee=(u+(i=i+Math.imul(h,re)|0)|0)+((8191&(n=(n=n+Math.imul(h,ie)|0)+Math.imul(d,re)|0))<<13)|0;u=((a=a+Math.imul(d,ie)|0)+(n>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,i=Math.imul(T,U),n=(n=Math.imul(T,H))+Math.imul(R,U)|0,a=Math.imul(R,H),i=i+Math.imul(M,K)|0,n=(n=n+Math.imul(M,Z)|0)+Math.imul(N,K)|0,a=a+Math.imul(N,Z)|0,i=i+Math.imul(S,X)|0,n=(n=n+Math.imul(S,Q)|0)+Math.imul(k,X)|0,a=a+Math.imul(k,Q)|0,i=i+Math.imul(b,V)|0,n=(n=n+Math.imul(b,G)|0)+Math.imul(E,V)|0,a=a+Math.imul(E,G)|0,i=i+Math.imul(_,$)|0,n=(n=n+Math.imul(_,ee)|0)+Math.imul(v,$)|0,a=a+Math.imul(v,ee)|0,i=i+Math.imul(f,re)|0,n=(n=n+Math.imul(f,ie)|0)+Math.imul(m,re)|0,a=a+Math.imul(m,ie)|0;var we=(u+(i=i+Math.imul(h,ae)|0)|0)+((8191&(n=(n=n+Math.imul(h,oe)|0)+Math.imul(d,ae)|0))<<13)|0;u=((a=a+Math.imul(d,oe)|0)+(n>>>13)|0)+(we>>>26)|0,we&=67108863,i=Math.imul(O,U),n=(n=Math.imul(O,H))+Math.imul(A,U)|0,a=Math.imul(A,H),i=i+Math.imul(T,K)|0,n=(n=n+Math.imul(T,Z)|0)+Math.imul(R,K)|0,a=a+Math.imul(R,Z)|0,i=i+Math.imul(M,X)|0,n=(n=n+Math.imul(M,Q)|0)+Math.imul(N,X)|0,a=a+Math.imul(N,Q)|0,i=i+Math.imul(S,V)|0,n=(n=n+Math.imul(S,G)|0)+Math.imul(k,V)|0,a=a+Math.imul(k,G)|0,i=i+Math.imul(b,$)|0,n=(n=n+Math.imul(b,ee)|0)+Math.imul(E,$)|0,a=a+Math.imul(E,ee)|0,i=i+Math.imul(_,re)|0,n=(n=n+Math.imul(_,ie)|0)+Math.imul(v,re)|0,a=a+Math.imul(v,ie)|0,i=i+Math.imul(f,ae)|0,n=(n=n+Math.imul(f,oe)|0)+Math.imul(m,ae)|0,a=a+Math.imul(m,oe)|0;var Se=(u+(i=i+Math.imul(h,ce)|0)|0)+((8191&(n=(n=n+Math.imul(h,ue)|0)+Math.imul(d,ce)|0))<<13)|0;u=((a=a+Math.imul(d,ue)|0)+(n>>>13)|0)+(Se>>>26)|0,Se&=67108863,i=Math.imul(D,U),n=(n=Math.imul(D,H))+Math.imul(F,U)|0,a=Math.imul(F,H),i=i+Math.imul(O,K)|0,n=(n=n+Math.imul(O,Z)|0)+Math.imul(A,K)|0,a=a+Math.imul(A,Z)|0,i=i+Math.imul(T,X)|0,n=(n=n+Math.imul(T,Q)|0)+Math.imul(R,X)|0,a=a+Math.imul(R,Q)|0,i=i+Math.imul(M,V)|0,n=(n=n+Math.imul(M,G)|0)+Math.imul(N,V)|0,a=a+Math.imul(N,G)|0,i=i+Math.imul(S,$)|0,n=(n=n+Math.imul(S,ee)|0)+Math.imul(k,$)|0,a=a+Math.imul(k,ee)|0,i=i+Math.imul(b,re)|0,n=(n=n+Math.imul(b,ie)|0)+Math.imul(E,re)|0,a=a+Math.imul(E,ie)|0,i=i+Math.imul(_,ae)|0,n=(n=n+Math.imul(_,oe)|0)+Math.imul(v,ae)|0,a=a+Math.imul(v,oe)|0,i=i+Math.imul(f,ce)|0,n=(n=n+Math.imul(f,ue)|0)+Math.imul(m,ce)|0,a=a+Math.imul(m,ue)|0;var ke=(u+(i=i+Math.imul(h,he)|0)|0)+((8191&(n=(n=n+Math.imul(h,de)|0)+Math.imul(d,he)|0))<<13)|0;u=((a=a+Math.imul(d,de)|0)+(n>>>13)|0)+(ke>>>26)|0,ke&=67108863,i=Math.imul(B,U),n=(n=Math.imul(B,H))+Math.imul(z,U)|0,a=Math.imul(z,H),i=i+Math.imul(D,K)|0,n=(n=n+Math.imul(D,Z)|0)+Math.imul(F,K)|0,a=a+Math.imul(F,Z)|0,i=i+Math.imul(O,X)|0,n=(n=n+Math.imul(O,Q)|0)+Math.imul(A,X)|0,a=a+Math.imul(A,Q)|0,i=i+Math.imul(T,V)|0,n=(n=n+Math.imul(T,G)|0)+Math.imul(R,V)|0,a=a+Math.imul(R,G)|0,i=i+Math.imul(M,$)|0,n=(n=n+Math.imul(M,ee)|0)+Math.imul(N,$)|0,a=a+Math.imul(N,ee)|0,i=i+Math.imul(S,re)|0,n=(n=n+Math.imul(S,ie)|0)+Math.imul(k,re)|0,a=a+Math.imul(k,ie)|0,i=i+Math.imul(b,ae)|0,n=(n=n+Math.imul(b,oe)|0)+Math.imul(E,ae)|0,a=a+Math.imul(E,oe)|0,i=i+Math.imul(_,ce)|0,n=(n=n+Math.imul(_,ue)|0)+Math.imul(v,ce)|0,a=a+Math.imul(v,ue)|0,i=i+Math.imul(f,he)|0,n=(n=n+Math.imul(f,de)|0)+Math.imul(m,he)|0,a=a+Math.imul(m,de)|0;var xe=(u+(i=i+Math.imul(h,fe)|0)|0)+((8191&(n=(n=n+Math.imul(h,me)|0)+Math.imul(d,fe)|0))<<13)|0;u=((a=a+Math.imul(d,me)|0)+(n>>>13)|0)+(xe>>>26)|0,xe&=67108863,i=Math.imul(B,K),n=(n=Math.imul(B,Z))+Math.imul(z,K)|0,a=Math.imul(z,Z),i=i+Math.imul(D,X)|0,n=(n=n+Math.imul(D,Q)|0)+Math.imul(F,X)|0,a=a+Math.imul(F,Q)|0,i=i+Math.imul(O,V)|0,n=(n=n+Math.imul(O,G)|0)+Math.imul(A,V)|0,a=a+Math.imul(A,G)|0,i=i+Math.imul(T,$)|0,n=(n=n+Math.imul(T,ee)|0)+Math.imul(R,$)|0,a=a+Math.imul(R,ee)|0,i=i+Math.imul(M,re)|0,n=(n=n+Math.imul(M,ie)|0)+Math.imul(N,re)|0,a=a+Math.imul(N,ie)|0,i=i+Math.imul(S,ae)|0,n=(n=n+Math.imul(S,oe)|0)+Math.imul(k,ae)|0,a=a+Math.imul(k,oe)|0,i=i+Math.imul(b,ce)|0,n=(n=n+Math.imul(b,ue)|0)+Math.imul(E,ce)|0,a=a+Math.imul(E,ue)|0,i=i+Math.imul(_,he)|0,n=(n=n+Math.imul(_,de)|0)+Math.imul(v,he)|0,a=a+Math.imul(v,de)|0;var Me=(u+(i=i+Math.imul(f,fe)|0)|0)+((8191&(n=(n=n+Math.imul(f,me)|0)+Math.imul(m,fe)|0))<<13)|0;u=((a=a+Math.imul(m,me)|0)+(n>>>13)|0)+(Me>>>26)|0,Me&=67108863,i=Math.imul(B,X),n=(n=Math.imul(B,Q))+Math.imul(z,X)|0,a=Math.imul(z,Q),i=i+Math.imul(D,V)|0,n=(n=n+Math.imul(D,G)|0)+Math.imul(F,V)|0,a=a+Math.imul(F,G)|0,i=i+Math.imul(O,$)|0,n=(n=n+Math.imul(O,ee)|0)+Math.imul(A,$)|0,a=a+Math.imul(A,ee)|0,i=i+Math.imul(T,re)|0,n=(n=n+Math.imul(T,ie)|0)+Math.imul(R,re)|0,a=a+Math.imul(R,ie)|0,i=i+Math.imul(M,ae)|0,n=(n=n+Math.imul(M,oe)|0)+Math.imul(N,ae)|0,a=a+Math.imul(N,oe)|0,i=i+Math.imul(S,ce)|0,n=(n=n+Math.imul(S,ue)|0)+Math.imul(k,ce)|0,a=a+Math.imul(k,ue)|0,i=i+Math.imul(b,he)|0,n=(n=n+Math.imul(b,de)|0)+Math.imul(E,he)|0,a=a+Math.imul(E,de)|0;var Ne=(u+(i=i+Math.imul(_,fe)|0)|0)+((8191&(n=(n=n+Math.imul(_,me)|0)+Math.imul(v,fe)|0))<<13)|0;u=((a=a+Math.imul(v,me)|0)+(n>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,i=Math.imul(B,V),n=(n=Math.imul(B,G))+Math.imul(z,V)|0,a=Math.imul(z,G),i=i+Math.imul(D,$)|0,n=(n=n+Math.imul(D,ee)|0)+Math.imul(F,$)|0,a=a+Math.imul(F,ee)|0,i=i+Math.imul(O,re)|0,n=(n=n+Math.imul(O,ie)|0)+Math.imul(A,re)|0,a=a+Math.imul(A,ie)|0,i=i+Math.imul(T,ae)|0,n=(n=n+Math.imul(T,oe)|0)+Math.imul(R,ae)|0,a=a+Math.imul(R,oe)|0,i=i+Math.imul(M,ce)|0,n=(n=n+Math.imul(M,ue)|0)+Math.imul(N,ce)|0,a=a+Math.imul(N,ue)|0,i=i+Math.imul(S,he)|0,n=(n=n+Math.imul(S,de)|0)+Math.imul(k,he)|0,a=a+Math.imul(k,de)|0;var je=(u+(i=i+Math.imul(b,fe)|0)|0)+((8191&(n=(n=n+Math.imul(b,me)|0)+Math.imul(E,fe)|0))<<13)|0;u=((a=a+Math.imul(E,me)|0)+(n>>>13)|0)+(je>>>26)|0,je&=67108863,i=Math.imul(B,$),n=(n=Math.imul(B,ee))+Math.imul(z,$)|0,a=Math.imul(z,ee),i=i+Math.imul(D,re)|0,n=(n=n+Math.imul(D,ie)|0)+Math.imul(F,re)|0,a=a+Math.imul(F,ie)|0,i=i+Math.imul(O,ae)|0,n=(n=n+Math.imul(O,oe)|0)+Math.imul(A,ae)|0,a=a+Math.imul(A,oe)|0,i=i+Math.imul(T,ce)|0,n=(n=n+Math.imul(T,ue)|0)+Math.imul(R,ce)|0,a=a+Math.imul(R,ue)|0,i=i+Math.imul(M,he)|0,n=(n=n+Math.imul(M,de)|0)+Math.imul(N,he)|0,a=a+Math.imul(N,de)|0;var Te=(u+(i=i+Math.imul(S,fe)|0)|0)+((8191&(n=(n=n+Math.imul(S,me)|0)+Math.imul(k,fe)|0))<<13)|0;u=((a=a+Math.imul(k,me)|0)+(n>>>13)|0)+(Te>>>26)|0,Te&=67108863,i=Math.imul(B,re),n=(n=Math.imul(B,ie))+Math.imul(z,re)|0,a=Math.imul(z,ie),i=i+Math.imul(D,ae)|0,n=(n=n+Math.imul(D,oe)|0)+Math.imul(F,ae)|0,a=a+Math.imul(F,oe)|0,i=i+Math.imul(O,ce)|0,n=(n=n+Math.imul(O,ue)|0)+Math.imul(A,ce)|0,a=a+Math.imul(A,ue)|0,i=i+Math.imul(T,he)|0,n=(n=n+Math.imul(T,de)|0)+Math.imul(R,he)|0,a=a+Math.imul(R,de)|0;var Re=(u+(i=i+Math.imul(M,fe)|0)|0)+((8191&(n=(n=n+Math.imul(M,me)|0)+Math.imul(N,fe)|0))<<13)|0;u=((a=a+Math.imul(N,me)|0)+(n>>>13)|0)+(Re>>>26)|0,Re&=67108863,i=Math.imul(B,ae),n=(n=Math.imul(B,oe))+Math.imul(z,ae)|0,a=Math.imul(z,oe),i=i+Math.imul(D,ce)|0,n=(n=n+Math.imul(D,ue)|0)+Math.imul(F,ce)|0,a=a+Math.imul(F,ue)|0,i=i+Math.imul(O,he)|0,n=(n=n+Math.imul(O,de)|0)+Math.imul(A,he)|0,a=a+Math.imul(A,de)|0;var Ie=(u+(i=i+Math.imul(T,fe)|0)|0)+((8191&(n=(n=n+Math.imul(T,me)|0)+Math.imul(R,fe)|0))<<13)|0;u=((a=a+Math.imul(R,me)|0)+(n>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,i=Math.imul(B,ce),n=(n=Math.imul(B,ue))+Math.imul(z,ce)|0,a=Math.imul(z,ue),i=i+Math.imul(D,he)|0,n=(n=n+Math.imul(D,de)|0)+Math.imul(F,he)|0,a=a+Math.imul(F,de)|0;var Oe=(u+(i=i+Math.imul(O,fe)|0)|0)+((8191&(n=(n=n+Math.imul(O,me)|0)+Math.imul(A,fe)|0))<<13)|0;u=((a=a+Math.imul(A,me)|0)+(n>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,i=Math.imul(B,he),n=(n=Math.imul(B,de))+Math.imul(z,he)|0,a=Math.imul(z,de);var Ae=(u+(i=i+Math.imul(D,fe)|0)|0)+((8191&(n=(n=n+Math.imul(D,me)|0)+Math.imul(F,fe)|0))<<13)|0;u=((a=a+Math.imul(F,me)|0)+(n>>>13)|0)+(Ae>>>26)|0,Ae&=67108863;var Pe=(u+(i=Math.imul(B,fe))|0)+((8191&(n=(n=Math.imul(B,me))+Math.imul(z,fe)|0))<<13)|0;return u=((a=Math.imul(z,me))+(n>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,c[0]=ge,c[1]=_e,c[2]=ve,c[3]=ye,c[4]=be,c[5]=Ee,c[6]=we,c[7]=Se,c[8]=ke,c[9]=xe,c[10]=Me,c[11]=Ne,c[12]=je,c[13]=Te,c[14]=Re,c[15]=Ie,c[16]=Oe,c[17]=Ae,c[18]=Pe,0!==u&&(c[19]=u,r.length++),r};function f(e,t,r){return(new m).mulp(e,t,r)}function m(e,t){this.x=e,this.y=t}Math.imul||(p=d),a.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?p(this,e,t):r<63?d(this,e,t):r<1024?function(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var i=0,n=0,a=0;a>>26)|0)>>>26,o&=67108863}r.words[a]=s,i=o,o=n}return 0!==i?r.words[a]=i:r.length--,r.strip()}(this,e,t):f(this,e,t)},m.prototype.makeRBT=function(e){for(var t=new Array(e),r=a.prototype._countBits(e)-1,i=0;i>=1;return i},m.prototype.permute=function(e,t,r,i,n,a){for(var o=0;o>>=1)n++;return 1<>>=13,r[2*o+1]=8191&a,a>>>=13;for(o=2*t;o>=26,t+=n/67108864|0,t+=a>>>26,this.words[r]=67108863&a}return 0!==t&&(this.words[r]=t,this.length++),this},a.prototype.muln=function(e){return this.clone().imuln(e)},a.prototype.sqr=function(){return this.mul(this)},a.prototype.isqr=function(){return this.imul(this.clone())},a.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>n}return t}(e);if(0===t.length)return new a(1);for(var r=this,i=0;i=0);var t,r=e%26,n=(e-r)/26,a=67108863>>>26-r<<26-r;if(0!==r){var o=0;for(t=0;t>>26-r}o&&(this.words[t]=o,this.length++)}if(0!==n){for(t=this.length-1;t>=0;t--)this.words[t+n]=this.words[t];for(t=0;t=0),n=t?(t-t%26)/26:0;var a=e%26,o=Math.min((e-a)/26,this.length),s=67108863^67108863>>>a<o)for(this.length-=o,u=0;u=0&&(0!==l||u>=n);u--){var h=0|this.words[u];this.words[u]=l<<26-a|h>>>a,l=h&s}return c&&0!==l&&(c.words[c.length++]=l),0===this.length&&(this.words[0]=0,this.length=1),this.strip()},a.prototype.ishrn=function(e,t,r){return i(0===this.negative),this.iushrn(e,t,r)},a.prototype.shln=function(e){return this.clone().ishln(e)},a.prototype.ushln=function(e){return this.clone().iushln(e)},a.prototype.shrn=function(e){return this.clone().ishrn(e)},a.prototype.ushrn=function(e){return this.clone().iushrn(e)},a.prototype.testn=function(e){i("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,n=1<=0);var t=e%26,r=(e-t)/26;if(i(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var n=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},a.prototype.isubn=function(e){if(i("number"==typeof e),i(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(c/67108864|0),this.words[n+r]=67108863&a}for(;n>26,this.words[n+r]=67108863&a;if(0===s)return this.strip();for(i(-1===s),s=0,n=0;n>26,this.words[n]=67108863&a;return this.negative=1,this.strip()},a.prototype._wordDiv=function(e,t){var r=(this.length,e.length),i=this.clone(),n=e,o=0|n.words[n.length-1];0!==(r=26-this._countBits(o))&&(n=n.ushln(r),i.iushln(r),o=0|n.words[n.length-1]);var s,c=i.length-n.length;if("mod"!==t){(s=new a(null)).length=c+1,s.words=new Array(s.length);for(var u=0;u=0;h--){var d=67108864*(0|i.words[n.length+h])+(0|i.words[n.length+h-1]);for(d=Math.min(d/o|0,67108863),i._ishlnsubmul(n,d,h);0!==i.negative;)d--,i.negative=0,i._ishlnsubmul(n,1,h),i.isZero()||(i.negative^=1);s&&(s.words[h]=d)}return s&&s.strip(),i.strip(),"div"!==t&&0!==r&&i.iushrn(r),{div:s||null,mod:i}},a.prototype.divmod=function(e,t,r){return i(!e.isZero()),this.isZero()?{div:new a(0),mod:new a(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(n=s.div.neg()),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.iadd(e)),{div:n,mod:o}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(n=s.div.neg()),{div:n,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.isub(e)),{div:s.div,mod:o}):e.length>this.length||this.cmp(e)<0?{div:new a(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new a(this.modn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new a(this.modn(e.words[0]))}:this._wordDiv(e,t);var n,o,s},a.prototype.div=function(e){return this.divmod(e,"div",!1).div},a.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},a.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},a.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,i=e.ushrn(1),n=e.andln(1),a=r.cmp(i);return a<0||1===n&&0===a?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},a.prototype.modn=function(e){i(e<=67108863);for(var t=(1<<26)%e,r=0,n=this.length-1;n>=0;n--)r=(t*r+(0|this.words[n]))%e;return r},a.prototype.idivn=function(e){i(e<=67108863);for(var t=0,r=this.length-1;r>=0;r--){var n=(0|this.words[r])+67108864*t;this.words[r]=n/e|0,t=n%e}return this.strip()},a.prototype.divn=function(e){return this.clone().idivn(e)},a.prototype.egcd=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n=new a(1),o=new a(0),s=new a(0),c=new a(1),u=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++u;for(var l=r.clone(),h=t.clone();!t.isZero();){for(var d=0,p=1;0==(t.words[0]&p)&&d<26;++d,p<<=1);if(d>0)for(t.iushrn(d);d-- >0;)(n.isOdd()||o.isOdd())&&(n.iadd(l),o.isub(h)),n.iushrn(1),o.iushrn(1);for(var f=0,m=1;0==(r.words[0]&m)&&f<26;++f,m<<=1);if(f>0)for(r.iushrn(f);f-- >0;)(s.isOdd()||c.isOdd())&&(s.iadd(l),c.isub(h)),s.iushrn(1),c.iushrn(1);t.cmp(r)>=0?(t.isub(r),n.isub(s),o.isub(c)):(r.isub(t),s.isub(n),c.isub(o))}return{a:s,b:c,gcd:r.iushln(u)}},a.prototype._invmp=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n,o=new a(1),s=new a(0),c=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var u=0,l=1;0==(t.words[0]&l)&&u<26;++u,l<<=1);if(u>0)for(t.iushrn(u);u-- >0;)o.isOdd()&&o.iadd(c),o.iushrn(1);for(var h=0,d=1;0==(r.words[0]&d)&&h<26;++h,d<<=1);if(h>0)for(r.iushrn(h);h-- >0;)s.isOdd()&&s.iadd(c),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),o.isub(s)):(r.isub(t),s.isub(o))}return(n=0===t.cmpn(1)?o:s).cmpn(0)<0&&n.iadd(e),n},a.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var i=0;t.isEven()&&r.isEven();i++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var n=t.cmp(r);if(n<0){var a=t;t=r,r=a}else if(0===n||0===r.cmpn(1))break;t.isub(r)}return r.iushln(i)},a.prototype.invm=function(e){return this.egcd(e).a.umod(e)},a.prototype.isEven=function(){return 0==(1&this.words[0])},a.prototype.isOdd=function(){return 1==(1&this.words[0])},a.prototype.andln=function(e){return this.words[0]&e},a.prototype.bincn=function(e){i("number"==typeof e);var t=e%26,r=(e-t)/26,n=1<>>26,s&=67108863,this.words[o]=s}return 0!==a&&(this.words[o]=a,this.length++),this},a.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},a.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this.strip(),this.length>1)t=1;else{r&&(e=-e),i(e<=67108863,"Number is too big");var n=0|this.words[0];t=n===e?0:ne.length)return 1;if(this.length=0;r--){var i=0|this.words[r],n=0|e.words[r];if(i!==n){in&&(t=1);break}}return t},a.prototype.gtn=function(e){return 1===this.cmpn(e)},a.prototype.gt=function(e){return 1===this.cmp(e)},a.prototype.gten=function(e){return this.cmpn(e)>=0},a.prototype.gte=function(e){return this.cmp(e)>=0},a.prototype.ltn=function(e){return-1===this.cmpn(e)},a.prototype.lt=function(e){return-1===this.cmp(e)},a.prototype.lten=function(e){return this.cmpn(e)<=0},a.prototype.lte=function(e){return this.cmp(e)<=0},a.prototype.eqn=function(e){return 0===this.cmpn(e)},a.prototype.eq=function(e){return 0===this.cmp(e)},a.red=function(e){return new w(e)},a.prototype.toRed=function(e){return i(!this.red,"Already a number in reduction context"),i(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},a.prototype.fromRed=function(){return i(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},a.prototype._forceRed=function(e){return this.red=e,this},a.prototype.forceRed=function(e){return i(!this.red,"Already a number in reduction context"),this._forceRed(e)},a.prototype.redAdd=function(e){return i(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},a.prototype.redIAdd=function(e){return i(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},a.prototype.redSub=function(e){return i(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},a.prototype.redISub=function(e){return i(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},a.prototype.redShl=function(e){return i(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},a.prototype.redMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},a.prototype.redIMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},a.prototype.redSqr=function(){return i(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},a.prototype.redISqr=function(){return i(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},a.prototype.redSqrt=function(){return i(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},a.prototype.redInvm=function(){return i(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},a.prototype.redNeg=function(){return i(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},a.prototype.redPow=function(e){return i(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var g={k256:null,p224:null,p192:null,p25519:null};function _(e,t){this.name=e,this.p=new a(t,16),this.n=this.p.bitLength(),this.k=new a(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function v(){_.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function y(){_.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function b(){_.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function E(){_.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function w(e){if("string"==typeof e){var t=a._prime(e);this.m=t.p,this.prime=t}else i(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function S(e){w.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new a(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}_.prototype._tmp=function(){var e=new a(null);return e.words=new Array(Math.ceil(this.n/13)),e},_.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var i=t0?r.isub(this.p):r.strip(),r},_.prototype.split=function(e,t){e.iushrn(this.n,0,t)},_.prototype.imulK=function(e){return e.imul(this.k)},n(v,_),v.prototype.split=function(e,t){for(var r=Math.min(e.length,9),i=0;i>>22,n=a}n>>>=22,e.words[i-10]=n,0===n&&e.length>10?e.length-=10:e.length-=9},v.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=n,t=i}return 0!==t&&(e.words[e.length++]=t),e},a._prime=function(e){if(g[e])return g[e];var t;if("k256"===e)t=new v;else if("p224"===e)t=new y;else if("p192"===e)t=new b;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new E}return g[e]=t,t},w.prototype._verify1=function(e){i(0===e.negative,"red works only with positives"),i(e.red,"red works only with red numbers")},w.prototype._verify2=function(e,t){i(0==(e.negative|t.negative),"red works only with positives"),i(e.red&&e.red===t.red,"red works only with red numbers")},w.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):e.umod(this.m)._forceRed(this)},w.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},w.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},w.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},w.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},w.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},w.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},w.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},w.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},w.prototype.isqr=function(e){return this.imul(e,e.clone())},w.prototype.sqr=function(e){return this.mul(e,e)},w.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(i(t%2==1),3===t){var r=this.m.add(new a(1)).iushrn(2);return this.pow(e,r)}for(var n=this.m.subn(1),o=0;!n.isZero()&&0===n.andln(1);)o++,n.iushrn(1);i(!n.isZero());var s=new a(1).toRed(this),c=s.redNeg(),u=this.m.subn(1).iushrn(1),l=this.m.bitLength();for(l=new a(2*l*l).toRed(this);0!==this.pow(l,u).cmp(c);)l.redIAdd(c);for(var h=this.pow(l,n),d=this.pow(e,n.addn(1).iushrn(1)),p=this.pow(e,n),f=o;0!==p.cmp(s);){for(var m=p,g=0;0!==m.cmp(s);g++)m=m.redSqr();i(g=0;i--){for(var u=t.words[i],l=c-1;l>=0;l--){var h=u>>l&1;n!==r[0]&&(n=this.sqr(n)),0!==h||0!==o?(o<<=1,o|=h,(4===++s||0===i&&0===l)&&(n=this.mul(n,r[o]),s=0,o=0)):s=0}c=26}return n},w.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},w.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},a.mont=function(e){return new S(e)},n(S,w),S.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},S.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},S.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),a=n;return n.cmp(this.m)>=0?a=n.isub(this.m):n.cmpn(0)<0&&(a=n.iadd(this.m)),a._forceRed(this)},S.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new a(0)._forceRed(this);var r=e.mul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),o=n;return n.cmp(this.m)>=0?o=n.isub(this.m):n.cmpn(0)<0&&(o=n.iadd(this.m)),o._forceRed(this)},S.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(22)(e))},function(e,t){},function(e,t){},function(e){e.exports=JSON.parse('{"modp1":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a63a3620ffffffffffffffff"},"modp2":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece65381ffffffffffffffff"},"modp5":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca237327ffffffffffffffff"},"modp14":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff"},"modp15":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a93ad2caffffffffffffffff"},"modp16":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c934063199ffffffffffffffff"},"modp17":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dcc4024ffffffffffffffff"},"modp18":{"gen":"02","prime":"ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa051015728e5a8aaac42dad33170d04507a33a85521abdf1cba64ecfb850458dbef0a8aea71575d060c7db3970f85a6e1e4c7abf5ae8cdb0933d71e8c94e04a25619dcee3d2261ad2ee6bf12ffa06d98a0864d87602733ec86a64521f2b18177b200cbbe117577a615d6c770988c0bad946e208e24fa074e5ab3143db5bfce0fd108e4b82d120a92108011a723c12a787e6d788719a10bdba5b2699c327186af4e23c1a946834b6150bda2583e9ca2ad44ce8dbbbc2db04de8ef92e8efc141fbecaa6287c59474e6bc05d99b2964fa090c3a2233ba186515be7ed1f612970cee2d7afb81bdd762170481cd0069127d5b05aa993b4ea988d8fddc186ffb7dc90a6c08f4df435c93402849236c3fab4d27c7026c1d4dcb2602646dec9751e763dba37bdf8ff9406ad9e530ee5db382f413001aeb06a53ed9027d831179727b0865a8918da3edbebcf9b14ed44ce6cbaced4bb1bdb7f1447e6cc254b332051512bd7af426fb8f401378cd2bf5983ca01c64b92ecf032ea15d1721d03f482d7ce6e74fef6d55e702f46980c82b5a84031900b1c9e59e7c97fbec7e8f323a97a7e36cc88be0f1d45b7ff585ac54bd407b22b4154aacc8f6d7ebf48e1d814cc5ed20f8037e0a79715eef29be32806a1d58bb7c5da76f550aa3d8a1fbff0eb19ccb1a313d55cda56c9ec2ef29632387fe8d76e3c0468043e8f663f4860ee12bf2d5b0b7474d6e694f91e6dbe115974a3926f12fee5e438777cb6a932df8cd8bec4d073b931ba3bc832b68d9dd300741fa7bf8afc47ed2576f6936ba424663aab639c5ae4f5683423b4742bf1c978238f16cbe39d652de3fdb8befc848ad922222e04a4037c0713eb57a81a23f0c73473fc646cea306b4bcbc8862f8385ddfa9d4b7fa2c087e879683303ed5bdd3a062b3cf5b3a278a66d2a13f83f44f82ddf310ee074ab6a364597e899a0255dc164f31cc50846851df9ab48195ded7ea1b1d510bd7ee74d73faf36bc31ecfa268359046f4eb879f924009438b481c6cd7889a002ed5ee382bc9190da6fc026e479558e4475677e9aa9e3050e2765694dfc81f56e880b96e7160c980dd98edd3dfffffffffffffffff"}}')},function(e,t,r){(function(t){var i=r(182),n=new(r(183)),a=new i(24),o=new i(11),s=new i(10),c=new i(3),u=new i(7),l=r(181),h=r(44);function d(e,r){return r=r||"utf8",t.isBuffer(e)||(e=new t(e,r)),this._pub=new i(e),this}function p(e,r){return r=r||"utf8",t.isBuffer(e)||(e=new t(e,r)),this._priv=new i(e),this}e.exports=m;var f={};function m(e,t,r){this.setGenerator(t),this.__prime=new i(e),this._prime=i.mont(this.__prime),this._primeLen=e.length,this._pub=void 0,this._priv=void 0,this._primeCode=void 0,r?(this.setPublicKey=d,this.setPrivateKey=p):this._primeCode=8}function g(e,r){var i=new t(e.toArray());return r?i.toString(r):i}Object.defineProperty(m.prototype,"verifyError",{enumerable:!0,get:function(){return"number"!=typeof this._primeCode&&(this._primeCode=function(e,t){var r=t.toString("hex"),i=[r,e.toString(16)].join("_");if(i in f)return f[i];var h,d=0;if(e.isEven()||!l.simpleSieve||!l.fermatTest(e)||!n.test(e))return d+=1,d+="02"===r||"05"===r?8:4,f[i]=d,d;switch(n.test(e.shrn(1))||(d+=2),r){case"02":e.mod(a).cmp(o)&&(d+=8);break;case"05":(h=e.mod(s)).cmp(c)&&h.cmp(u)&&(d+=8);break;default:d+=4}return f[i]=d,d}(this.__prime,this.__gen)),this._primeCode}}),m.prototype.generateKeys=function(){return this._priv||(this._priv=new i(h(this._primeLen))),this._pub=this._gen.toRed(this._prime).redPow(this._priv).fromRed(),this.getPublicKey()},m.prototype.computeSecret=function(e){var r=(e=(e=new i(e)).toRed(this._prime)).redPow(this._priv).fromRed(),n=new t(r.toArray()),a=this.getPrime();if(n.length0?this.tail.next=t:this.head=t,this.tail=t,++this.length}},{key:"unshift",value:function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length}},{key:"shift",value:function(){if(0!==this.length){var e=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,e}}},{key:"clear",value:function(){this.head=this.tail=null,this.length=0}},{key:"join",value:function(e){if(0===this.length)return"";for(var t=this.head,r=""+t.data;t=t.next;)r+=e+t.data;return r}},{key:"concat",value:function(e){if(0===this.length)return o.alloc(0);for(var t,r,i,n=o.allocUnsafe(e>>>0),a=this.head,s=0;a;)t=a.data,r=n,i=s,o.prototype.copy.call(t,r,i),s+=a.data.length,a=a.next;return n}},{key:"consume",value:function(e,t){var r;return en.length?n.length:e;if(a===n.length?i+=n:i+=n.slice(0,e),0==(e-=a)){a===n.length?(++r,t.next?this.head=t.next:this.head=this.tail=null):(this.head=t,t.data=n.slice(a));break}++r}return this.length-=r,i}},{key:"_getBuffer",value:function(e){var t=o.allocUnsafe(e),r=this.head,i=1;for(r.data.copy(t),e-=r.data.length;r=r.next;){var n=r.data,a=e>n.length?n.length:e;if(n.copy(t,t.length-e,0,a),0==(e-=a)){a===n.length?(++i,r.next?this.head=r.next:this.head=this.tail=null):(this.head=r,r.data=n.slice(a));break}++i}return this.length-=i,t}},{key:c,value:function(e,t){return s(this,function(e){for(var t=1;t0,(function(e){i||(i=e),e&&o.forEach(u),a||(o.forEach(u),n(i))}))}));return t.reduce(l)}},function(e,t,r){var i=r(2).Buffer,n=r(167),a=r(116),o=r(117).ec,s=r(195),c=r(82),u=r(200);function l(e,t,r,a){if((e=i.from(e.toArray())).length0&&r.ishrn(i),r}function d(e,t,r){var a,o;do{for(a=i.alloc(0);8*a.length=49&&o<=54?o-49+10:o>=17&&o<=22?o-17+10:15&o}return i}function c(e,t,r,i){for(var n=0,a=Math.min(e.length,r),o=t;o=49?s-49+10:s>=17?s-17+10:s}return n}a.isBN=function(e){return e instanceof a||null!==e&&"object"==typeof e&&e.constructor.wordSize===a.wordSize&&Array.isArray(e.words)},a.max=function(e,t){return e.cmp(t)>0?e:t},a.min=function(e,t){return e.cmp(t)<0?e:t},a.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),i(t===(0|t)&&t>=2&&t<=36);var n=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&n++,16===t?this._parseHex(e,n):this._parseBase(e,t,n),"-"===e[0]&&(this.negative=1),this.strip(),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(i(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initArray=function(e,t,r){if(i("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var n=0;n=0;n-=3)o=e[n]|e[n-1]<<8|e[n-2]<<16,this.words[a]|=o<>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);else if("le"===r)for(n=0,a=0;n>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);return this.strip()},a.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)n=s(e,r,r+6),this.words[i]|=n<>>26-a&4194303,(a+=24)>=26&&(a-=26,i++);r+6!==t&&(n=s(e,t,r+6),this.words[i]|=n<>>26-a&4194303),this.strip()},a.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var i=0,n=1;n<=67108863;n*=t)i++;i--,n=n/t|0;for(var a=e.length-r,o=a%i,s=Math.min(a,a-o)+r,u=0,l=r;l1&&0===this.words[this.length-1];)this.length--;return this._normSign()},a.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},a.prototype.inspect=function(){return(this.red?""};var u=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],l=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],h=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];function d(e,t,r){r.negative=t.negative^e.negative;var i=e.length+t.length|0;r.length=i,i=i-1|0;var n=0|e.words[0],a=0|t.words[0],o=n*a,s=67108863&o,c=o/67108864|0;r.words[0]=s;for(var u=1;u>>26,h=67108863&c,d=Math.min(u,t.length-1),p=Math.max(0,u-e.length+1);p<=d;p++){var f=u-p|0;l+=(o=(n=0|e.words[f])*(a=0|t.words[p])+h)/67108864|0,h=67108863&o}r.words[u]=0|h,c=0|l}return 0!==c?r.words[u]=0|c:r.length--,r.strip()}a.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var n=0,a=0,o=0;o>>24-n&16777215)||o!==this.length-1?u[6-c.length]+c+r:c+r,(n+=2)>=26&&(n-=26,o--)}for(0!==a&&(r=a.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var d=l[e],p=h[e];r="";var f=this.clone();for(f.negative=0;!f.isZero();){var m=f.modn(p).toString(e);r=(f=f.idivn(p)).isZero()?m+r:u[d-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}i(!1,"Base should be between 2 and 36")},a.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&i(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},a.prototype.toJSON=function(){return this.toString(16)},a.prototype.toBuffer=function(e,t){return i(void 0!==o),this.toArrayLike(o,e,t)},a.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)},a.prototype.toArrayLike=function(e,t,r){var n=this.byteLength(),a=r||Math.max(1,n);i(n<=a,"byte array longer than desired length"),i(a>0,"Requested array length <= 0"),this.strip();var o,s,c="le"===t,u=new e(a),l=this.clone();if(c){for(s=0;!l.isZero();s++)o=l.andln(255),l.iushrn(8),u[s]=o;for(;s=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},a.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},a.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},a.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},a.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},a.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},a.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},a.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var i=0;ie.length?this.clone().ixor(e):e.clone().ixor(this)},a.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},a.prototype.inotn=function(e){i("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var n=0;n0&&(this.words[n]=~this.words[n]&67108863>>26-r),this.strip()},a.prototype.notn=function(e){return this.clone().inotn(e)},a.prototype.setn=function(e,t){i("number"==typeof e&&e>=0);var r=e/26|0,n=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,i=e):(r=e,i=this);for(var n=0,a=0;a>>26;for(;0!==n&&a>>26;if(this.length=r.length,0!==n)this.words[this.length]=n,this.length++;else if(r!==this)for(;ae.length?this.clone().iadd(e):e.clone().iadd(this)},a.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,i,n=this.cmp(e);if(0===n)return this.negative=0,this.length=1,this.words[0]=0,this;n>0?(r=this,i=e):(r=e,i=this);for(var a=0,o=0;o>26,this.words[o]=67108863&t;for(;0!==a&&o>26,this.words[o]=67108863&t;if(0===a&&o>>13,p=0|o[1],f=8191&p,m=p>>>13,g=0|o[2],_=8191&g,v=g>>>13,y=0|o[3],b=8191&y,E=y>>>13,w=0|o[4],S=8191&w,k=w>>>13,x=0|o[5],M=8191&x,N=x>>>13,j=0|o[6],T=8191&j,R=j>>>13,I=0|o[7],O=8191&I,A=I>>>13,P=0|o[8],D=8191&P,F=P>>>13,C=0|o[9],B=8191&C,z=C>>>13,L=0|s[0],U=8191&L,H=L>>>13,q=0|s[1],K=8191&q,Z=q>>>13,W=0|s[2],X=8191&W,Q=W>>>13,J=0|s[3],V=8191&J,G=J>>>13,Y=0|s[4],$=8191&Y,ee=Y>>>13,te=0|s[5],re=8191&te,ie=te>>>13,ne=0|s[6],ae=8191&ne,oe=ne>>>13,se=0|s[7],ce=8191&se,ue=se>>>13,le=0|s[8],he=8191&le,de=le>>>13,pe=0|s[9],fe=8191&pe,me=pe>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(u+(i=Math.imul(h,U))|0)+((8191&(n=(n=Math.imul(h,H))+Math.imul(d,U)|0))<<13)|0;u=((a=Math.imul(d,H))+(n>>>13)|0)+(ge>>>26)|0,ge&=67108863,i=Math.imul(f,U),n=(n=Math.imul(f,H))+Math.imul(m,U)|0,a=Math.imul(m,H);var _e=(u+(i=i+Math.imul(h,K)|0)|0)+((8191&(n=(n=n+Math.imul(h,Z)|0)+Math.imul(d,K)|0))<<13)|0;u=((a=a+Math.imul(d,Z)|0)+(n>>>13)|0)+(_e>>>26)|0,_e&=67108863,i=Math.imul(_,U),n=(n=Math.imul(_,H))+Math.imul(v,U)|0,a=Math.imul(v,H),i=i+Math.imul(f,K)|0,n=(n=n+Math.imul(f,Z)|0)+Math.imul(m,K)|0,a=a+Math.imul(m,Z)|0;var ve=(u+(i=i+Math.imul(h,X)|0)|0)+((8191&(n=(n=n+Math.imul(h,Q)|0)+Math.imul(d,X)|0))<<13)|0;u=((a=a+Math.imul(d,Q)|0)+(n>>>13)|0)+(ve>>>26)|0,ve&=67108863,i=Math.imul(b,U),n=(n=Math.imul(b,H))+Math.imul(E,U)|0,a=Math.imul(E,H),i=i+Math.imul(_,K)|0,n=(n=n+Math.imul(_,Z)|0)+Math.imul(v,K)|0,a=a+Math.imul(v,Z)|0,i=i+Math.imul(f,X)|0,n=(n=n+Math.imul(f,Q)|0)+Math.imul(m,X)|0,a=a+Math.imul(m,Q)|0;var ye=(u+(i=i+Math.imul(h,V)|0)|0)+((8191&(n=(n=n+Math.imul(h,G)|0)+Math.imul(d,V)|0))<<13)|0;u=((a=a+Math.imul(d,G)|0)+(n>>>13)|0)+(ye>>>26)|0,ye&=67108863,i=Math.imul(S,U),n=(n=Math.imul(S,H))+Math.imul(k,U)|0,a=Math.imul(k,H),i=i+Math.imul(b,K)|0,n=(n=n+Math.imul(b,Z)|0)+Math.imul(E,K)|0,a=a+Math.imul(E,Z)|0,i=i+Math.imul(_,X)|0,n=(n=n+Math.imul(_,Q)|0)+Math.imul(v,X)|0,a=a+Math.imul(v,Q)|0,i=i+Math.imul(f,V)|0,n=(n=n+Math.imul(f,G)|0)+Math.imul(m,V)|0,a=a+Math.imul(m,G)|0;var be=(u+(i=i+Math.imul(h,$)|0)|0)+((8191&(n=(n=n+Math.imul(h,ee)|0)+Math.imul(d,$)|0))<<13)|0;u=((a=a+Math.imul(d,ee)|0)+(n>>>13)|0)+(be>>>26)|0,be&=67108863,i=Math.imul(M,U),n=(n=Math.imul(M,H))+Math.imul(N,U)|0,a=Math.imul(N,H),i=i+Math.imul(S,K)|0,n=(n=n+Math.imul(S,Z)|0)+Math.imul(k,K)|0,a=a+Math.imul(k,Z)|0,i=i+Math.imul(b,X)|0,n=(n=n+Math.imul(b,Q)|0)+Math.imul(E,X)|0,a=a+Math.imul(E,Q)|0,i=i+Math.imul(_,V)|0,n=(n=n+Math.imul(_,G)|0)+Math.imul(v,V)|0,a=a+Math.imul(v,G)|0,i=i+Math.imul(f,$)|0,n=(n=n+Math.imul(f,ee)|0)+Math.imul(m,$)|0,a=a+Math.imul(m,ee)|0;var Ee=(u+(i=i+Math.imul(h,re)|0)|0)+((8191&(n=(n=n+Math.imul(h,ie)|0)+Math.imul(d,re)|0))<<13)|0;u=((a=a+Math.imul(d,ie)|0)+(n>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,i=Math.imul(T,U),n=(n=Math.imul(T,H))+Math.imul(R,U)|0,a=Math.imul(R,H),i=i+Math.imul(M,K)|0,n=(n=n+Math.imul(M,Z)|0)+Math.imul(N,K)|0,a=a+Math.imul(N,Z)|0,i=i+Math.imul(S,X)|0,n=(n=n+Math.imul(S,Q)|0)+Math.imul(k,X)|0,a=a+Math.imul(k,Q)|0,i=i+Math.imul(b,V)|0,n=(n=n+Math.imul(b,G)|0)+Math.imul(E,V)|0,a=a+Math.imul(E,G)|0,i=i+Math.imul(_,$)|0,n=(n=n+Math.imul(_,ee)|0)+Math.imul(v,$)|0,a=a+Math.imul(v,ee)|0,i=i+Math.imul(f,re)|0,n=(n=n+Math.imul(f,ie)|0)+Math.imul(m,re)|0,a=a+Math.imul(m,ie)|0;var we=(u+(i=i+Math.imul(h,ae)|0)|0)+((8191&(n=(n=n+Math.imul(h,oe)|0)+Math.imul(d,ae)|0))<<13)|0;u=((a=a+Math.imul(d,oe)|0)+(n>>>13)|0)+(we>>>26)|0,we&=67108863,i=Math.imul(O,U),n=(n=Math.imul(O,H))+Math.imul(A,U)|0,a=Math.imul(A,H),i=i+Math.imul(T,K)|0,n=(n=n+Math.imul(T,Z)|0)+Math.imul(R,K)|0,a=a+Math.imul(R,Z)|0,i=i+Math.imul(M,X)|0,n=(n=n+Math.imul(M,Q)|0)+Math.imul(N,X)|0,a=a+Math.imul(N,Q)|0,i=i+Math.imul(S,V)|0,n=(n=n+Math.imul(S,G)|0)+Math.imul(k,V)|0,a=a+Math.imul(k,G)|0,i=i+Math.imul(b,$)|0,n=(n=n+Math.imul(b,ee)|0)+Math.imul(E,$)|0,a=a+Math.imul(E,ee)|0,i=i+Math.imul(_,re)|0,n=(n=n+Math.imul(_,ie)|0)+Math.imul(v,re)|0,a=a+Math.imul(v,ie)|0,i=i+Math.imul(f,ae)|0,n=(n=n+Math.imul(f,oe)|0)+Math.imul(m,ae)|0,a=a+Math.imul(m,oe)|0;var Se=(u+(i=i+Math.imul(h,ce)|0)|0)+((8191&(n=(n=n+Math.imul(h,ue)|0)+Math.imul(d,ce)|0))<<13)|0;u=((a=a+Math.imul(d,ue)|0)+(n>>>13)|0)+(Se>>>26)|0,Se&=67108863,i=Math.imul(D,U),n=(n=Math.imul(D,H))+Math.imul(F,U)|0,a=Math.imul(F,H),i=i+Math.imul(O,K)|0,n=(n=n+Math.imul(O,Z)|0)+Math.imul(A,K)|0,a=a+Math.imul(A,Z)|0,i=i+Math.imul(T,X)|0,n=(n=n+Math.imul(T,Q)|0)+Math.imul(R,X)|0,a=a+Math.imul(R,Q)|0,i=i+Math.imul(M,V)|0,n=(n=n+Math.imul(M,G)|0)+Math.imul(N,V)|0,a=a+Math.imul(N,G)|0,i=i+Math.imul(S,$)|0,n=(n=n+Math.imul(S,ee)|0)+Math.imul(k,$)|0,a=a+Math.imul(k,ee)|0,i=i+Math.imul(b,re)|0,n=(n=n+Math.imul(b,ie)|0)+Math.imul(E,re)|0,a=a+Math.imul(E,ie)|0,i=i+Math.imul(_,ae)|0,n=(n=n+Math.imul(_,oe)|0)+Math.imul(v,ae)|0,a=a+Math.imul(v,oe)|0,i=i+Math.imul(f,ce)|0,n=(n=n+Math.imul(f,ue)|0)+Math.imul(m,ce)|0,a=a+Math.imul(m,ue)|0;var ke=(u+(i=i+Math.imul(h,he)|0)|0)+((8191&(n=(n=n+Math.imul(h,de)|0)+Math.imul(d,he)|0))<<13)|0;u=((a=a+Math.imul(d,de)|0)+(n>>>13)|0)+(ke>>>26)|0,ke&=67108863,i=Math.imul(B,U),n=(n=Math.imul(B,H))+Math.imul(z,U)|0,a=Math.imul(z,H),i=i+Math.imul(D,K)|0,n=(n=n+Math.imul(D,Z)|0)+Math.imul(F,K)|0,a=a+Math.imul(F,Z)|0,i=i+Math.imul(O,X)|0,n=(n=n+Math.imul(O,Q)|0)+Math.imul(A,X)|0,a=a+Math.imul(A,Q)|0,i=i+Math.imul(T,V)|0,n=(n=n+Math.imul(T,G)|0)+Math.imul(R,V)|0,a=a+Math.imul(R,G)|0,i=i+Math.imul(M,$)|0,n=(n=n+Math.imul(M,ee)|0)+Math.imul(N,$)|0,a=a+Math.imul(N,ee)|0,i=i+Math.imul(S,re)|0,n=(n=n+Math.imul(S,ie)|0)+Math.imul(k,re)|0,a=a+Math.imul(k,ie)|0,i=i+Math.imul(b,ae)|0,n=(n=n+Math.imul(b,oe)|0)+Math.imul(E,ae)|0,a=a+Math.imul(E,oe)|0,i=i+Math.imul(_,ce)|0,n=(n=n+Math.imul(_,ue)|0)+Math.imul(v,ce)|0,a=a+Math.imul(v,ue)|0,i=i+Math.imul(f,he)|0,n=(n=n+Math.imul(f,de)|0)+Math.imul(m,he)|0,a=a+Math.imul(m,de)|0;var xe=(u+(i=i+Math.imul(h,fe)|0)|0)+((8191&(n=(n=n+Math.imul(h,me)|0)+Math.imul(d,fe)|0))<<13)|0;u=((a=a+Math.imul(d,me)|0)+(n>>>13)|0)+(xe>>>26)|0,xe&=67108863,i=Math.imul(B,K),n=(n=Math.imul(B,Z))+Math.imul(z,K)|0,a=Math.imul(z,Z),i=i+Math.imul(D,X)|0,n=(n=n+Math.imul(D,Q)|0)+Math.imul(F,X)|0,a=a+Math.imul(F,Q)|0,i=i+Math.imul(O,V)|0,n=(n=n+Math.imul(O,G)|0)+Math.imul(A,V)|0,a=a+Math.imul(A,G)|0,i=i+Math.imul(T,$)|0,n=(n=n+Math.imul(T,ee)|0)+Math.imul(R,$)|0,a=a+Math.imul(R,ee)|0,i=i+Math.imul(M,re)|0,n=(n=n+Math.imul(M,ie)|0)+Math.imul(N,re)|0,a=a+Math.imul(N,ie)|0,i=i+Math.imul(S,ae)|0,n=(n=n+Math.imul(S,oe)|0)+Math.imul(k,ae)|0,a=a+Math.imul(k,oe)|0,i=i+Math.imul(b,ce)|0,n=(n=n+Math.imul(b,ue)|0)+Math.imul(E,ce)|0,a=a+Math.imul(E,ue)|0,i=i+Math.imul(_,he)|0,n=(n=n+Math.imul(_,de)|0)+Math.imul(v,he)|0,a=a+Math.imul(v,de)|0;var Me=(u+(i=i+Math.imul(f,fe)|0)|0)+((8191&(n=(n=n+Math.imul(f,me)|0)+Math.imul(m,fe)|0))<<13)|0;u=((a=a+Math.imul(m,me)|0)+(n>>>13)|0)+(Me>>>26)|0,Me&=67108863,i=Math.imul(B,X),n=(n=Math.imul(B,Q))+Math.imul(z,X)|0,a=Math.imul(z,Q),i=i+Math.imul(D,V)|0,n=(n=n+Math.imul(D,G)|0)+Math.imul(F,V)|0,a=a+Math.imul(F,G)|0,i=i+Math.imul(O,$)|0,n=(n=n+Math.imul(O,ee)|0)+Math.imul(A,$)|0,a=a+Math.imul(A,ee)|0,i=i+Math.imul(T,re)|0,n=(n=n+Math.imul(T,ie)|0)+Math.imul(R,re)|0,a=a+Math.imul(R,ie)|0,i=i+Math.imul(M,ae)|0,n=(n=n+Math.imul(M,oe)|0)+Math.imul(N,ae)|0,a=a+Math.imul(N,oe)|0,i=i+Math.imul(S,ce)|0,n=(n=n+Math.imul(S,ue)|0)+Math.imul(k,ce)|0,a=a+Math.imul(k,ue)|0,i=i+Math.imul(b,he)|0,n=(n=n+Math.imul(b,de)|0)+Math.imul(E,he)|0,a=a+Math.imul(E,de)|0;var Ne=(u+(i=i+Math.imul(_,fe)|0)|0)+((8191&(n=(n=n+Math.imul(_,me)|0)+Math.imul(v,fe)|0))<<13)|0;u=((a=a+Math.imul(v,me)|0)+(n>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,i=Math.imul(B,V),n=(n=Math.imul(B,G))+Math.imul(z,V)|0,a=Math.imul(z,G),i=i+Math.imul(D,$)|0,n=(n=n+Math.imul(D,ee)|0)+Math.imul(F,$)|0,a=a+Math.imul(F,ee)|0,i=i+Math.imul(O,re)|0,n=(n=n+Math.imul(O,ie)|0)+Math.imul(A,re)|0,a=a+Math.imul(A,ie)|0,i=i+Math.imul(T,ae)|0,n=(n=n+Math.imul(T,oe)|0)+Math.imul(R,ae)|0,a=a+Math.imul(R,oe)|0,i=i+Math.imul(M,ce)|0,n=(n=n+Math.imul(M,ue)|0)+Math.imul(N,ce)|0,a=a+Math.imul(N,ue)|0,i=i+Math.imul(S,he)|0,n=(n=n+Math.imul(S,de)|0)+Math.imul(k,he)|0,a=a+Math.imul(k,de)|0;var je=(u+(i=i+Math.imul(b,fe)|0)|0)+((8191&(n=(n=n+Math.imul(b,me)|0)+Math.imul(E,fe)|0))<<13)|0;u=((a=a+Math.imul(E,me)|0)+(n>>>13)|0)+(je>>>26)|0,je&=67108863,i=Math.imul(B,$),n=(n=Math.imul(B,ee))+Math.imul(z,$)|0,a=Math.imul(z,ee),i=i+Math.imul(D,re)|0,n=(n=n+Math.imul(D,ie)|0)+Math.imul(F,re)|0,a=a+Math.imul(F,ie)|0,i=i+Math.imul(O,ae)|0,n=(n=n+Math.imul(O,oe)|0)+Math.imul(A,ae)|0,a=a+Math.imul(A,oe)|0,i=i+Math.imul(T,ce)|0,n=(n=n+Math.imul(T,ue)|0)+Math.imul(R,ce)|0,a=a+Math.imul(R,ue)|0,i=i+Math.imul(M,he)|0,n=(n=n+Math.imul(M,de)|0)+Math.imul(N,he)|0,a=a+Math.imul(N,de)|0;var Te=(u+(i=i+Math.imul(S,fe)|0)|0)+((8191&(n=(n=n+Math.imul(S,me)|0)+Math.imul(k,fe)|0))<<13)|0;u=((a=a+Math.imul(k,me)|0)+(n>>>13)|0)+(Te>>>26)|0,Te&=67108863,i=Math.imul(B,re),n=(n=Math.imul(B,ie))+Math.imul(z,re)|0,a=Math.imul(z,ie),i=i+Math.imul(D,ae)|0,n=(n=n+Math.imul(D,oe)|0)+Math.imul(F,ae)|0,a=a+Math.imul(F,oe)|0,i=i+Math.imul(O,ce)|0,n=(n=n+Math.imul(O,ue)|0)+Math.imul(A,ce)|0,a=a+Math.imul(A,ue)|0,i=i+Math.imul(T,he)|0,n=(n=n+Math.imul(T,de)|0)+Math.imul(R,he)|0,a=a+Math.imul(R,de)|0;var Re=(u+(i=i+Math.imul(M,fe)|0)|0)+((8191&(n=(n=n+Math.imul(M,me)|0)+Math.imul(N,fe)|0))<<13)|0;u=((a=a+Math.imul(N,me)|0)+(n>>>13)|0)+(Re>>>26)|0,Re&=67108863,i=Math.imul(B,ae),n=(n=Math.imul(B,oe))+Math.imul(z,ae)|0,a=Math.imul(z,oe),i=i+Math.imul(D,ce)|0,n=(n=n+Math.imul(D,ue)|0)+Math.imul(F,ce)|0,a=a+Math.imul(F,ue)|0,i=i+Math.imul(O,he)|0,n=(n=n+Math.imul(O,de)|0)+Math.imul(A,he)|0,a=a+Math.imul(A,de)|0;var Ie=(u+(i=i+Math.imul(T,fe)|0)|0)+((8191&(n=(n=n+Math.imul(T,me)|0)+Math.imul(R,fe)|0))<<13)|0;u=((a=a+Math.imul(R,me)|0)+(n>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,i=Math.imul(B,ce),n=(n=Math.imul(B,ue))+Math.imul(z,ce)|0,a=Math.imul(z,ue),i=i+Math.imul(D,he)|0,n=(n=n+Math.imul(D,de)|0)+Math.imul(F,he)|0,a=a+Math.imul(F,de)|0;var Oe=(u+(i=i+Math.imul(O,fe)|0)|0)+((8191&(n=(n=n+Math.imul(O,me)|0)+Math.imul(A,fe)|0))<<13)|0;u=((a=a+Math.imul(A,me)|0)+(n>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,i=Math.imul(B,he),n=(n=Math.imul(B,de))+Math.imul(z,he)|0,a=Math.imul(z,de);var Ae=(u+(i=i+Math.imul(D,fe)|0)|0)+((8191&(n=(n=n+Math.imul(D,me)|0)+Math.imul(F,fe)|0))<<13)|0;u=((a=a+Math.imul(F,me)|0)+(n>>>13)|0)+(Ae>>>26)|0,Ae&=67108863;var Pe=(u+(i=Math.imul(B,fe))|0)+((8191&(n=(n=Math.imul(B,me))+Math.imul(z,fe)|0))<<13)|0;return u=((a=Math.imul(z,me))+(n>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,c[0]=ge,c[1]=_e,c[2]=ve,c[3]=ye,c[4]=be,c[5]=Ee,c[6]=we,c[7]=Se,c[8]=ke,c[9]=xe,c[10]=Me,c[11]=Ne,c[12]=je,c[13]=Te,c[14]=Re,c[15]=Ie,c[16]=Oe,c[17]=Ae,c[18]=Pe,0!==u&&(c[19]=u,r.length++),r};function f(e,t,r){return(new m).mulp(e,t,r)}function m(e,t){this.x=e,this.y=t}Math.imul||(p=d),a.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?p(this,e,t):r<63?d(this,e,t):r<1024?function(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var i=0,n=0,a=0;a>>26)|0)>>>26,o&=67108863}r.words[a]=s,i=o,o=n}return 0!==i?r.words[a]=i:r.length--,r.strip()}(this,e,t):f(this,e,t)},m.prototype.makeRBT=function(e){for(var t=new Array(e),r=a.prototype._countBits(e)-1,i=0;i>=1;return i},m.prototype.permute=function(e,t,r,i,n,a){for(var o=0;o>>=1)n++;return 1<>>=13,r[2*o+1]=8191&a,a>>>=13;for(o=2*t;o>=26,t+=n/67108864|0,t+=a>>>26,this.words[r]=67108863&a}return 0!==t&&(this.words[r]=t,this.length++),this},a.prototype.muln=function(e){return this.clone().imuln(e)},a.prototype.sqr=function(){return this.mul(this)},a.prototype.isqr=function(){return this.imul(this.clone())},a.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>n}return t}(e);if(0===t.length)return new a(1);for(var r=this,i=0;i=0);var t,r=e%26,n=(e-r)/26,a=67108863>>>26-r<<26-r;if(0!==r){var o=0;for(t=0;t>>26-r}o&&(this.words[t]=o,this.length++)}if(0!==n){for(t=this.length-1;t>=0;t--)this.words[t+n]=this.words[t];for(t=0;t=0),n=t?(t-t%26)/26:0;var a=e%26,o=Math.min((e-a)/26,this.length),s=67108863^67108863>>>a<o)for(this.length-=o,u=0;u=0&&(0!==l||u>=n);u--){var h=0|this.words[u];this.words[u]=l<<26-a|h>>>a,l=h&s}return c&&0!==l&&(c.words[c.length++]=l),0===this.length&&(this.words[0]=0,this.length=1),this.strip()},a.prototype.ishrn=function(e,t,r){return i(0===this.negative),this.iushrn(e,t,r)},a.prototype.shln=function(e){return this.clone().ishln(e)},a.prototype.ushln=function(e){return this.clone().iushln(e)},a.prototype.shrn=function(e){return this.clone().ishrn(e)},a.prototype.ushrn=function(e){return this.clone().iushrn(e)},a.prototype.testn=function(e){i("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,n=1<=0);var t=e%26,r=(e-t)/26;if(i(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var n=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},a.prototype.isubn=function(e){if(i("number"==typeof e),i(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(c/67108864|0),this.words[n+r]=67108863&a}for(;n>26,this.words[n+r]=67108863&a;if(0===s)return this.strip();for(i(-1===s),s=0,n=0;n>26,this.words[n]=67108863&a;return this.negative=1,this.strip()},a.prototype._wordDiv=function(e,t){var r=(this.length,e.length),i=this.clone(),n=e,o=0|n.words[n.length-1];0!==(r=26-this._countBits(o))&&(n=n.ushln(r),i.iushln(r),o=0|n.words[n.length-1]);var s,c=i.length-n.length;if("mod"!==t){(s=new a(null)).length=c+1,s.words=new Array(s.length);for(var u=0;u=0;h--){var d=67108864*(0|i.words[n.length+h])+(0|i.words[n.length+h-1]);for(d=Math.min(d/o|0,67108863),i._ishlnsubmul(n,d,h);0!==i.negative;)d--,i.negative=0,i._ishlnsubmul(n,1,h),i.isZero()||(i.negative^=1);s&&(s.words[h]=d)}return s&&s.strip(),i.strip(),"div"!==t&&0!==r&&i.iushrn(r),{div:s||null,mod:i}},a.prototype.divmod=function(e,t,r){return i(!e.isZero()),this.isZero()?{div:new a(0),mod:new a(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(n=s.div.neg()),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.iadd(e)),{div:n,mod:o}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(n=s.div.neg()),{div:n,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.isub(e)),{div:s.div,mod:o}):e.length>this.length||this.cmp(e)<0?{div:new a(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new a(this.modn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new a(this.modn(e.words[0]))}:this._wordDiv(e,t);var n,o,s},a.prototype.div=function(e){return this.divmod(e,"div",!1).div},a.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},a.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},a.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,i=e.ushrn(1),n=e.andln(1),a=r.cmp(i);return a<0||1===n&&0===a?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},a.prototype.modn=function(e){i(e<=67108863);for(var t=(1<<26)%e,r=0,n=this.length-1;n>=0;n--)r=(t*r+(0|this.words[n]))%e;return r},a.prototype.idivn=function(e){i(e<=67108863);for(var t=0,r=this.length-1;r>=0;r--){var n=(0|this.words[r])+67108864*t;this.words[r]=n/e|0,t=n%e}return this.strip()},a.prototype.divn=function(e){return this.clone().idivn(e)},a.prototype.egcd=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n=new a(1),o=new a(0),s=new a(0),c=new a(1),u=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++u;for(var l=r.clone(),h=t.clone();!t.isZero();){for(var d=0,p=1;0==(t.words[0]&p)&&d<26;++d,p<<=1);if(d>0)for(t.iushrn(d);d-- >0;)(n.isOdd()||o.isOdd())&&(n.iadd(l),o.isub(h)),n.iushrn(1),o.iushrn(1);for(var f=0,m=1;0==(r.words[0]&m)&&f<26;++f,m<<=1);if(f>0)for(r.iushrn(f);f-- >0;)(s.isOdd()||c.isOdd())&&(s.iadd(l),c.isub(h)),s.iushrn(1),c.iushrn(1);t.cmp(r)>=0?(t.isub(r),n.isub(s),o.isub(c)):(r.isub(t),s.isub(n),c.isub(o))}return{a:s,b:c,gcd:r.iushln(u)}},a.prototype._invmp=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n,o=new a(1),s=new a(0),c=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var u=0,l=1;0==(t.words[0]&l)&&u<26;++u,l<<=1);if(u>0)for(t.iushrn(u);u-- >0;)o.isOdd()&&o.iadd(c),o.iushrn(1);for(var h=0,d=1;0==(r.words[0]&d)&&h<26;++h,d<<=1);if(h>0)for(r.iushrn(h);h-- >0;)s.isOdd()&&s.iadd(c),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),o.isub(s)):(r.isub(t),s.isub(o))}return(n=0===t.cmpn(1)?o:s).cmpn(0)<0&&n.iadd(e),n},a.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var i=0;t.isEven()&&r.isEven();i++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var n=t.cmp(r);if(n<0){var a=t;t=r,r=a}else if(0===n||0===r.cmpn(1))break;t.isub(r)}return r.iushln(i)},a.prototype.invm=function(e){return this.egcd(e).a.umod(e)},a.prototype.isEven=function(){return 0==(1&this.words[0])},a.prototype.isOdd=function(){return 1==(1&this.words[0])},a.prototype.andln=function(e){return this.words[0]&e},a.prototype.bincn=function(e){i("number"==typeof e);var t=e%26,r=(e-t)/26,n=1<>>26,s&=67108863,this.words[o]=s}return 0!==a&&(this.words[o]=a,this.length++),this},a.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},a.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this.strip(),this.length>1)t=1;else{r&&(e=-e),i(e<=67108863,"Number is too big");var n=0|this.words[0];t=n===e?0:ne.length)return 1;if(this.length=0;r--){var i=0|this.words[r],n=0|e.words[r];if(i!==n){in&&(t=1);break}}return t},a.prototype.gtn=function(e){return 1===this.cmpn(e)},a.prototype.gt=function(e){return 1===this.cmp(e)},a.prototype.gten=function(e){return this.cmpn(e)>=0},a.prototype.gte=function(e){return this.cmp(e)>=0},a.prototype.ltn=function(e){return-1===this.cmpn(e)},a.prototype.lt=function(e){return-1===this.cmp(e)},a.prototype.lten=function(e){return this.cmpn(e)<=0},a.prototype.lte=function(e){return this.cmp(e)<=0},a.prototype.eqn=function(e){return 0===this.cmpn(e)},a.prototype.eq=function(e){return 0===this.cmp(e)},a.red=function(e){return new w(e)},a.prototype.toRed=function(e){return i(!this.red,"Already a number in reduction context"),i(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},a.prototype.fromRed=function(){return i(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},a.prototype._forceRed=function(e){return this.red=e,this},a.prototype.forceRed=function(e){return i(!this.red,"Already a number in reduction context"),this._forceRed(e)},a.prototype.redAdd=function(e){return i(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},a.prototype.redIAdd=function(e){return i(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},a.prototype.redSub=function(e){return i(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},a.prototype.redISub=function(e){return i(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},a.prototype.redShl=function(e){return i(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},a.prototype.redMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},a.prototype.redIMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},a.prototype.redSqr=function(){return i(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},a.prototype.redISqr=function(){return i(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},a.prototype.redSqrt=function(){return i(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},a.prototype.redInvm=function(){return i(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},a.prototype.redNeg=function(){return i(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},a.prototype.redPow=function(e){return i(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var g={k256:null,p224:null,p192:null,p25519:null};function _(e,t){this.name=e,this.p=new a(t,16),this.n=this.p.bitLength(),this.k=new a(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function v(){_.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function y(){_.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function b(){_.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function E(){_.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function w(e){if("string"==typeof e){var t=a._prime(e);this.m=t.p,this.prime=t}else i(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function S(e){w.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new a(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}_.prototype._tmp=function(){var e=new a(null);return e.words=new Array(Math.ceil(this.n/13)),e},_.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var i=t0?r.isub(this.p):r.strip(),r},_.prototype.split=function(e,t){e.iushrn(this.n,0,t)},_.prototype.imulK=function(e){return e.imul(this.k)},n(v,_),v.prototype.split=function(e,t){for(var r=Math.min(e.length,9),i=0;i>>22,n=a}n>>>=22,e.words[i-10]=n,0===n&&e.length>10?e.length-=10:e.length-=9},v.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=n,t=i}return 0!==t&&(e.words[e.length++]=t),e},a._prime=function(e){if(g[e])return g[e];var t;if("k256"===e)t=new v;else if("p224"===e)t=new y;else if("p192"===e)t=new b;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new E}return g[e]=t,t},w.prototype._verify1=function(e){i(0===e.negative,"red works only with positives"),i(e.red,"red works only with red numbers")},w.prototype._verify2=function(e,t){i(0==(e.negative|t.negative),"red works only with positives"),i(e.red&&e.red===t.red,"red works only with red numbers")},w.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):e.umod(this.m)._forceRed(this)},w.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},w.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},w.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},w.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},w.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},w.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},w.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},w.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},w.prototype.isqr=function(e){return this.imul(e,e.clone())},w.prototype.sqr=function(e){return this.mul(e,e)},w.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(i(t%2==1),3===t){var r=this.m.add(new a(1)).iushrn(2);return this.pow(e,r)}for(var n=this.m.subn(1),o=0;!n.isZero()&&0===n.andln(1);)o++,n.iushrn(1);i(!n.isZero());var s=new a(1).toRed(this),c=s.redNeg(),u=this.m.subn(1).iushrn(1),l=this.m.bitLength();for(l=new a(2*l*l).toRed(this);0!==this.pow(l,u).cmp(c);)l.redIAdd(c);for(var h=this.pow(l,n),d=this.pow(e,n.addn(1).iushrn(1)),p=this.pow(e,n),f=o;0!==p.cmp(s);){for(var m=p,g=0;0!==m.cmp(s);g++)m=m.redSqr();i(g=0;i--){for(var u=t.words[i],l=c-1;l>=0;l--){var h=u>>l&1;n!==r[0]&&(n=this.sqr(n)),0!==h||0!==o?(o<<=1,o|=h,(4===++s||0===i&&0===l)&&(n=this.mul(n,r[o]),s=0,o=0)):s=0}c=26}return n},w.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},w.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},a.mont=function(e){return new S(e)},n(S,w),S.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},S.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},S.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),a=n;return n.cmp(this.m)>=0?a=n.isub(this.m):n.cmpn(0)<0&&(a=n.iadd(this.m)),a._forceRed(this)},S.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new a(0)._forceRed(this);var r=e.mul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),o=n;return n.cmp(this.m)>=0?o=n.isub(this.m):n.cmpn(0)<0&&(o=n.iadd(this.m)),o._forceRed(this)},S.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(22)(e))},function(e,t){},function(e){e.exports=JSON.parse('{"_args":[["elliptic@6.5.3","/Users/woodser/git/monero-javascript"]],"_development":true,"_from":"elliptic@6.5.3","_id":"elliptic@6.5.3","_inBundle":false,"_integrity":"sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==","_location":"/elliptic","_phantomChildren":{},"_requested":{"type":"version","registry":true,"raw":"elliptic@6.5.3","name":"elliptic","escapedName":"elliptic","rawSpec":"6.5.3","saveSpec":null,"fetchSpec":"6.5.3"},"_requiredBy":["/browserify-sign","/create-ecdh"],"_resolved":"https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz","_spec":"6.5.3","_where":"/Users/woodser/git/monero-javascript","author":{"name":"Fedor Indutny","email":"fedor@indutny.com"},"bugs":{"url":"https://github.com/indutny/elliptic/issues"},"dependencies":{"bn.js":"^4.4.0","brorand":"^1.0.1","hash.js":"^1.0.0","hmac-drbg":"^1.0.0","inherits":"^2.0.1","minimalistic-assert":"^1.0.0","minimalistic-crypto-utils":"^1.0.0"},"description":"EC cryptography","devDependencies":{"brfs":"^1.4.3","coveralls":"^3.0.8","grunt":"^1.0.4","grunt-browserify":"^5.0.0","grunt-cli":"^1.2.0","grunt-contrib-connect":"^1.0.0","grunt-contrib-copy":"^1.0.0","grunt-contrib-uglify":"^1.0.1","grunt-mocha-istanbul":"^3.0.1","grunt-saucelabs":"^9.0.1","istanbul":"^0.4.2","jscs":"^3.0.7","jshint":"^2.10.3","mocha":"^6.2.2"},"files":["lib"],"homepage":"https://github.com/indutny/elliptic","keywords":["EC","Elliptic","curve","Cryptography"],"license":"MIT","main":"lib/elliptic.js","name":"elliptic","repository":{"type":"git","url":"git+ssh://git@github.com/indutny/elliptic.git"},"scripts":{"jscs":"jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js","jshint":"jscs benchmarks/*.js lib/*.js lib/**/*.js lib/**/**/*.js test/index.js","lint":"npm run jscs && npm run jshint","test":"npm run lint && npm run unit","unit":"istanbul test _mocha --reporter=spec test/index.js","version":"grunt dist && git add dist/"},"version":"6.5.3"}')},function(e,t){},function(e,t,r){"use strict";var i=r(20),n=r(27),a=r(0),o=r(81),s=i.assert;function c(e){o.call(this,"short",e),this.a=new n(e.a,16).toRed(this.red),this.b=new n(e.b,16).toRed(this.red),this.tinv=this.two.redInvm(),this.zeroA=0===this.a.fromRed().cmpn(0),this.threeA=0===this.a.fromRed().sub(this.p).cmpn(-3),this.endo=this._getEndomorphism(e),this._endoWnafT1=new Array(4),this._endoWnafT2=new Array(4)}function u(e,t,r,i){o.BasePoint.call(this,e,"affine"),null===t&&null===r?(this.x=null,this.y=null,this.inf=!0):(this.x=new n(t,16),this.y=new n(r,16),i&&(this.x.forceRed(this.curve.red),this.y.forceRed(this.curve.red)),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.y.red||(this.y=this.y.toRed(this.curve.red)),this.inf=!1)}function l(e,t,r,i){o.BasePoint.call(this,e,"jacobian"),null===t&&null===r&&null===i?(this.x=this.curve.one,this.y=this.curve.one,this.z=new n(0)):(this.x=new n(t,16),this.y=new n(r,16),this.z=new n(i,16)),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.y.red||(this.y=this.y.toRed(this.curve.red)),this.z.red||(this.z=this.z.toRed(this.curve.red)),this.zOne=this.z===this.curve.one}a(c,o),e.exports=c,c.prototype._getEndomorphism=function(e){if(this.zeroA&&this.g&&this.n&&1===this.p.modn(3)){var t,r;if(e.beta)t=new n(e.beta,16).toRed(this.red);else{var i=this._getEndoRoots(this.p);t=(t=i[0].cmp(i[1])<0?i[0]:i[1]).toRed(this.red)}if(e.lambda)r=new n(e.lambda,16);else{var a=this._getEndoRoots(this.n);0===this.g.mul(a[0]).x.cmp(this.g.x.redMul(t))?r=a[0]:(r=a[1],s(0===this.g.mul(r).x.cmp(this.g.x.redMul(t))))}return{beta:t,lambda:r,basis:e.basis?e.basis.map((function(e){return{a:new n(e.a,16),b:new n(e.b,16)}})):this._getEndoBasis(r)}}},c.prototype._getEndoRoots=function(e){var t=e===this.p?this.red:n.mont(e),r=new n(2).toRed(t).redInvm(),i=r.redNeg(),a=new n(3).toRed(t).redNeg().redSqrt().redMul(r);return[i.redAdd(a).fromRed(),i.redSub(a).fromRed()]},c.prototype._getEndoBasis=function(e){for(var t,r,i,a,o,s,c,u,l,h=this.n.ushrn(Math.floor(this.n.bitLength()/2)),d=e,p=this.n.clone(),f=new n(1),m=new n(0),g=new n(0),_=new n(1),v=0;0!==d.cmpn(0);){var y=p.div(d);u=p.sub(y.mul(d)),l=g.sub(y.mul(f));var b=_.sub(y.mul(m));if(!i&&u.cmp(h)<0)t=c.neg(),r=f,i=u.neg(),a=l;else if(i&&2==++v)break;c=u,p=d,d=u,g=f,f=l,_=m,m=b}o=u.neg(),s=l;var E=i.sqr().add(a.sqr());return o.sqr().add(s.sqr()).cmp(E)>=0&&(o=t,s=r),i.negative&&(i=i.neg(),a=a.neg()),o.negative&&(o=o.neg(),s=s.neg()),[{a:i,b:a},{a:o,b:s}]},c.prototype._endoSplit=function(e){var t=this.endo.basis,r=t[0],i=t[1],n=i.b.mul(e).divRound(this.n),a=r.b.neg().mul(e).divRound(this.n),o=n.mul(r.a),s=a.mul(i.a),c=n.mul(r.b),u=a.mul(i.b);return{k1:e.sub(o).sub(s),k2:c.add(u).neg()}},c.prototype.pointFromX=function(e,t){(e=new n(e,16)).red||(e=e.toRed(this.red));var r=e.redSqr().redMul(e).redIAdd(e.redMul(this.a)).redIAdd(this.b),i=r.redSqrt();if(0!==i.redSqr().redSub(r).cmp(this.zero))throw new Error("invalid point");var a=i.fromRed().isOdd();return(t&&!a||!t&&a)&&(i=i.redNeg()),this.point(e,i)},c.prototype.validate=function(e){if(e.inf)return!0;var t=e.x,r=e.y,i=this.a.redMul(t),n=t.redSqr().redMul(t).redIAdd(i).redIAdd(this.b);return 0===r.redSqr().redISub(n).cmpn(0)},c.prototype._endoWnafMulAdd=function(e,t,r){for(var i=this._endoWnafT1,n=this._endoWnafT2,a=0;a":""},u.prototype.isInfinity=function(){return this.inf},u.prototype.add=function(e){if(this.inf)return e;if(e.inf)return this;if(this.eq(e))return this.dbl();if(this.neg().eq(e))return this.curve.point(null,null);if(0===this.x.cmp(e.x))return this.curve.point(null,null);var t=this.y.redSub(e.y);0!==t.cmpn(0)&&(t=t.redMul(this.x.redSub(e.x).redInvm()));var r=t.redSqr().redISub(this.x).redISub(e.x),i=t.redMul(this.x.redSub(r)).redISub(this.y);return this.curve.point(r,i)},u.prototype.dbl=function(){if(this.inf)return this;var e=this.y.redAdd(this.y);if(0===e.cmpn(0))return this.curve.point(null,null);var t=this.curve.a,r=this.x.redSqr(),i=e.redInvm(),n=r.redAdd(r).redIAdd(r).redIAdd(t).redMul(i),a=n.redSqr().redISub(this.x.redAdd(this.x)),o=n.redMul(this.x.redSub(a)).redISub(this.y);return this.curve.point(a,o)},u.prototype.getX=function(){return this.x.fromRed()},u.prototype.getY=function(){return this.y.fromRed()},u.prototype.mul=function(e){return e=new n(e,16),this.isInfinity()?this:this._hasDoubles(e)?this.curve._fixedNafMul(this,e):this.curve.endo?this.curve._endoWnafMulAdd([this],[e]):this.curve._wnafMul(this,e)},u.prototype.mulAdd=function(e,t,r){var i=[this,t],n=[e,r];return this.curve.endo?this.curve._endoWnafMulAdd(i,n):this.curve._wnafMulAdd(1,i,n,2)},u.prototype.jmulAdd=function(e,t,r){var i=[this,t],n=[e,r];return this.curve.endo?this.curve._endoWnafMulAdd(i,n,!0):this.curve._wnafMulAdd(1,i,n,2,!0)},u.prototype.eq=function(e){return this===e||this.inf===e.inf&&(this.inf||0===this.x.cmp(e.x)&&0===this.y.cmp(e.y))},u.prototype.neg=function(e){if(this.inf)return this;var t=this.curve.point(this.x,this.y.redNeg());if(e&&this.precomputed){var r=this.precomputed,i=function(e){return e.neg()};t.precomputed={naf:r.naf&&{wnd:r.naf.wnd,points:r.naf.points.map(i)},doubles:r.doubles&&{step:r.doubles.step,points:r.doubles.points.map(i)}}}return t},u.prototype.toJ=function(){return this.inf?this.curve.jpoint(null,null,null):this.curve.jpoint(this.x,this.y,this.curve.one)},a(l,o.BasePoint),c.prototype.jpoint=function(e,t,r){return new l(this,e,t,r)},l.prototype.toP=function(){if(this.isInfinity())return this.curve.point(null,null);var e=this.z.redInvm(),t=e.redSqr(),r=this.x.redMul(t),i=this.y.redMul(t).redMul(e);return this.curve.point(r,i)},l.prototype.neg=function(){return this.curve.jpoint(this.x,this.y.redNeg(),this.z)},l.prototype.add=function(e){if(this.isInfinity())return e;if(e.isInfinity())return this;var t=e.z.redSqr(),r=this.z.redSqr(),i=this.x.redMul(t),n=e.x.redMul(r),a=this.y.redMul(t.redMul(e.z)),o=e.y.redMul(r.redMul(this.z)),s=i.redSub(n),c=a.redSub(o);if(0===s.cmpn(0))return 0!==c.cmpn(0)?this.curve.jpoint(null,null,null):this.dbl();var u=s.redSqr(),l=u.redMul(s),h=i.redMul(u),d=c.redSqr().redIAdd(l).redISub(h).redISub(h),p=c.redMul(h.redISub(d)).redISub(a.redMul(l)),f=this.z.redMul(e.z).redMul(s);return this.curve.jpoint(d,p,f)},l.prototype.mixedAdd=function(e){if(this.isInfinity())return e.toJ();if(e.isInfinity())return this;var t=this.z.redSqr(),r=this.x,i=e.x.redMul(t),n=this.y,a=e.y.redMul(t).redMul(this.z),o=r.redSub(i),s=n.redSub(a);if(0===o.cmpn(0))return 0!==s.cmpn(0)?this.curve.jpoint(null,null,null):this.dbl();var c=o.redSqr(),u=c.redMul(o),l=r.redMul(c),h=s.redSqr().redIAdd(u).redISub(l).redISub(l),d=s.redMul(l.redISub(h)).redISub(n.redMul(u)),p=this.z.redMul(o);return this.curve.jpoint(h,d,p)},l.prototype.dblp=function(e){if(0===e)return this;if(this.isInfinity())return this;if(!e)return this.dbl();if(this.curve.zeroA||this.curve.threeA){for(var t=this,r=0;r=0)return!1;if(r.redIAdd(n),0===this.x.cmp(r))return!0}},l.prototype.inspect=function(){return this.isInfinity()?"":""},l.prototype.isInfinity=function(){return 0===this.z.cmpn(0)}},function(e,t,r){"use strict";var i=r(27),n=r(0),a=r(81),o=r(20);function s(e){a.call(this,"mont",e),this.a=new i(e.a,16).toRed(this.red),this.b=new i(e.b,16).toRed(this.red),this.i4=new i(4).toRed(this.red).redInvm(),this.two=new i(2).toRed(this.red),this.a24=this.i4.redMul(this.a.redAdd(this.two))}function c(e,t,r){a.BasePoint.call(this,e,"projective"),null===t&&null===r?(this.x=this.curve.one,this.z=this.curve.zero):(this.x=new i(t,16),this.z=new i(r,16),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.z.red||(this.z=this.z.toRed(this.curve.red)))}n(s,a),e.exports=s,s.prototype.validate=function(e){var t=e.normalize().x,r=t.redSqr(),i=r.redMul(t).redAdd(r.redMul(this.a)).redAdd(t);return 0===i.redSqrt().redSqr().cmp(i)},n(c,a.BasePoint),s.prototype.decodePoint=function(e,t){return this.point(o.toArray(e,t),1)},s.prototype.point=function(e,t){return new c(this,e,t)},s.prototype.pointFromJSON=function(e){return c.fromJSON(this,e)},c.prototype.precompute=function(){},c.prototype._encode=function(){return this.getX().toArray("be",this.curve.p.byteLength())},c.fromJSON=function(e,t){return new c(e,t[0],t[1]||e.one)},c.prototype.inspect=function(){return this.isInfinity()?"":""},c.prototype.isInfinity=function(){return 0===this.z.cmpn(0)},c.prototype.dbl=function(){var e=this.x.redAdd(this.z).redSqr(),t=this.x.redSub(this.z).redSqr(),r=e.redSub(t),i=e.redMul(t),n=r.redMul(t.redAdd(this.curve.a24.redMul(r)));return this.curve.point(i,n)},c.prototype.add=function(){throw new Error("Not supported on Montgomery curve")},c.prototype.diffAdd=function(e,t){var r=this.x.redAdd(this.z),i=this.x.redSub(this.z),n=e.x.redAdd(e.z),a=e.x.redSub(e.z).redMul(r),o=n.redMul(i),s=t.z.redMul(a.redAdd(o).redSqr()),c=t.x.redMul(a.redISub(o).redSqr());return this.curve.point(s,c)},c.prototype.mul=function(e){for(var t=e.clone(),r=this,i=this.curve.point(null,null),n=[];0!==t.cmpn(0);t.iushrn(1))n.push(t.andln(1));for(var a=n.length-1;a>=0;a--)0===n[a]?(r=r.diffAdd(i,this),i=i.dbl()):(i=r.diffAdd(i,this),r=r.dbl());return i},c.prototype.mulAdd=function(){throw new Error("Not supported on Montgomery curve")},c.prototype.jumlAdd=function(){throw new Error("Not supported on Montgomery curve")},c.prototype.eq=function(e){return 0===this.getX().cmp(e.getX())},c.prototype.normalize=function(){return this.x=this.x.redMul(this.z.redInvm()),this.z=this.curve.one,this},c.prototype.getX=function(){return this.normalize(),this.x.fromRed()}},function(e,t,r){"use strict";var i=r(20),n=r(27),a=r(0),o=r(81),s=i.assert;function c(e){this.twisted=1!=(0|e.a),this.mOneA=this.twisted&&-1==(0|e.a),this.extended=this.mOneA,o.call(this,"edwards",e),this.a=new n(e.a,16).umod(this.red.m),this.a=this.a.toRed(this.red),this.c=new n(e.c,16).toRed(this.red),this.c2=this.c.redSqr(),this.d=new n(e.d,16).toRed(this.red),this.dd=this.d.redAdd(this.d),s(!this.twisted||0===this.c.fromRed().cmpn(1)),this.oneC=1==(0|e.c)}function u(e,t,r,i,a){o.BasePoint.call(this,e,"projective"),null===t&&null===r&&null===i?(this.x=this.curve.zero,this.y=this.curve.one,this.z=this.curve.one,this.t=this.curve.zero,this.zOne=!0):(this.x=new n(t,16),this.y=new n(r,16),this.z=i?new n(i,16):this.curve.one,this.t=a&&new n(a,16),this.x.red||(this.x=this.x.toRed(this.curve.red)),this.y.red||(this.y=this.y.toRed(this.curve.red)),this.z.red||(this.z=this.z.toRed(this.curve.red)),this.t&&!this.t.red&&(this.t=this.t.toRed(this.curve.red)),this.zOne=this.z===this.curve.one,this.curve.extended&&!this.t&&(this.t=this.x.redMul(this.y),this.zOne||(this.t=this.t.redMul(this.z.redInvm()))))}a(c,o),e.exports=c,c.prototype._mulA=function(e){return this.mOneA?e.redNeg():this.a.redMul(e)},c.prototype._mulC=function(e){return this.oneC?e:this.c.redMul(e)},c.prototype.jpoint=function(e,t,r,i){return this.point(e,t,r,i)},c.prototype.pointFromX=function(e,t){(e=new n(e,16)).red||(e=e.toRed(this.red));var r=e.redSqr(),i=this.c2.redSub(this.a.redMul(r)),a=this.one.redSub(this.c2.redMul(this.d).redMul(r)),o=i.redMul(a.redInvm()),s=o.redSqrt();if(0!==s.redSqr().redSub(o).cmp(this.zero))throw new Error("invalid point");var c=s.fromRed().isOdd();return(t&&!c||!t&&c)&&(s=s.redNeg()),this.point(e,s)},c.prototype.pointFromY=function(e,t){(e=new n(e,16)).red||(e=e.toRed(this.red));var r=e.redSqr(),i=r.redSub(this.c2),a=r.redMul(this.d).redMul(this.c2).redSub(this.a),o=i.redMul(a.redInvm());if(0===o.cmp(this.zero)){if(t)throw new Error("invalid point");return this.point(this.zero,e)}var s=o.redSqrt();if(0!==s.redSqr().redSub(o).cmp(this.zero))throw new Error("invalid point");return s.fromRed().isOdd()!==t&&(s=s.redNeg()),this.point(s,e)},c.prototype.validate=function(e){if(e.isInfinity())return!0;e.normalize();var t=e.x.redSqr(),r=e.y.redSqr(),i=t.redMul(this.a).redAdd(r),n=this.c2.redMul(this.one.redAdd(this.d.redMul(t).redMul(r)));return 0===i.cmp(n)},a(u,o.BasePoint),c.prototype.pointFromJSON=function(e){return u.fromJSON(this,e)},c.prototype.point=function(e,t,r,i){return new u(this,e,t,r,i)},u.fromJSON=function(e,t){return new u(e,t[0],t[1],t[2])},u.prototype.inspect=function(){return this.isInfinity()?"":""},u.prototype.isInfinity=function(){return 0===this.x.cmpn(0)&&(0===this.y.cmp(this.z)||this.zOne&&0===this.y.cmp(this.curve.c))},u.prototype._extDbl=function(){var e=this.x.redSqr(),t=this.y.redSqr(),r=this.z.redSqr();r=r.redIAdd(r);var i=this.curve._mulA(e),n=this.x.redAdd(this.y).redSqr().redISub(e).redISub(t),a=i.redAdd(t),o=a.redSub(r),s=i.redSub(t),c=n.redMul(o),u=a.redMul(s),l=n.redMul(s),h=o.redMul(a);return this.curve.point(c,u,h,l)},u.prototype._projDbl=function(){var e,t,r,i=this.x.redAdd(this.y).redSqr(),n=this.x.redSqr(),a=this.y.redSqr();if(this.curve.twisted){var o=(u=this.curve._mulA(n)).redAdd(a);if(this.zOne)e=i.redSub(n).redSub(a).redMul(o.redSub(this.curve.two)),t=o.redMul(u.redSub(a)),r=o.redSqr().redSub(o).redSub(o);else{var s=this.z.redSqr(),c=o.redSub(s).redISub(s);e=i.redSub(n).redISub(a).redMul(c),t=o.redMul(u.redSub(a)),r=o.redMul(c)}}else{var u=n.redAdd(a);s=this.curve._mulC(this.z).redSqr(),c=u.redSub(s).redSub(s);e=this.curve._mulC(i.redISub(u)).redMul(c),t=this.curve._mulC(u).redMul(n.redISub(a)),r=u.redMul(c)}return this.curve.point(e,t,r)},u.prototype.dbl=function(){return this.isInfinity()?this:this.curve.extended?this._extDbl():this._projDbl()},u.prototype._extAdd=function(e){var t=this.y.redSub(this.x).redMul(e.y.redSub(e.x)),r=this.y.redAdd(this.x).redMul(e.y.redAdd(e.x)),i=this.t.redMul(this.curve.dd).redMul(e.t),n=this.z.redMul(e.z.redAdd(e.z)),a=r.redSub(t),o=n.redSub(i),s=n.redAdd(i),c=r.redAdd(t),u=a.redMul(o),l=s.redMul(c),h=a.redMul(c),d=o.redMul(s);return this.curve.point(u,l,d,h)},u.prototype._projAdd=function(e){var t,r,i=this.z.redMul(e.z),n=i.redSqr(),a=this.x.redMul(e.x),o=this.y.redMul(e.y),s=this.curve.d.redMul(a).redMul(o),c=n.redSub(s),u=n.redAdd(s),l=this.x.redAdd(this.y).redMul(e.x.redAdd(e.y)).redISub(a).redISub(o),h=i.redMul(c).redMul(l);return this.curve.twisted?(t=i.redMul(u).redMul(o.redSub(this.curve._mulA(a))),r=c.redMul(u)):(t=i.redMul(u).redMul(o.redSub(a)),r=this.curve._mulC(c).redMul(u)),this.curve.point(h,t,r)},u.prototype.add=function(e){return this.isInfinity()?e:e.isInfinity()?this:this.curve.extended?this._extAdd(e):this._projAdd(e)},u.prototype.mul=function(e){return this._hasDoubles(e)?this.curve._fixedNafMul(this,e):this.curve._wnafMul(this,e)},u.prototype.mulAdd=function(e,t,r){return this.curve._wnafMulAdd(1,[this,t],[e,r],2,!1)},u.prototype.jmulAdd=function(e,t,r){return this.curve._wnafMulAdd(1,[this,t],[e,r],2,!0)},u.prototype.normalize=function(){if(this.zOne)return this;var e=this.z.redInvm();return this.x=this.x.redMul(e),this.y=this.y.redMul(e),this.t&&(this.t=this.t.redMul(e)),this.z=this.curve.one,this.zOne=!0,this},u.prototype.neg=function(){return this.curve.point(this.x.redNeg(),this.y,this.z,this.t&&this.t.redNeg())},u.prototype.getX=function(){return this.normalize(),this.x.fromRed()},u.prototype.getY=function(){return this.normalize(),this.y.fromRed()},u.prototype.eq=function(e){return this===e||0===this.getX().cmp(e.getX())&&0===this.getY().cmp(e.getY())},u.prototype.eqXToP=function(e){var t=e.toRed(this.curve.red).redMul(this.z);if(0===this.x.cmp(t))return!0;for(var r=e.clone(),i=this.curve.redN.redMul(this.z);;){if(r.iadd(this.curve.n),r.cmp(this.curve.p)>=0)return!1;if(t.redIAdd(i),0===this.x.cmp(t))return!0}},u.prototype.toP=u.prototype.normalize,u.prototype.mixedAdd=u.prototype.add},function(e,t,r){"use strict";t.sha1=r(339),t.sha224=r(340),t.sha256=r(193),t.sha384=r(341),t.sha512=r(194)},function(e,t,r){"use strict";var i=r(24),n=r(63),a=r(192),o=i.rotl32,s=i.sum32,c=i.sum32_5,u=a.ft_1,l=n.BlockHash,h=[1518500249,1859775393,2400959708,3395469782];function d(){if(!(this instanceof d))return new d;l.call(this),this.h=[1732584193,4023233417,2562383102,271733878,3285377520],this.W=new Array(80)}i.inherits(d,l),e.exports=d,d.blockSize=512,d.outSize=160,d.hmacStrength=80,d.padLength=64,d.prototype._update=function(e,t){for(var r=this.W,i=0;i<16;i++)r[i]=e[t+i];for(;ithis.blockSize&&(e=(new this.Hash).update(e).digest()),n(e.length<=this.blockSize);for(var t=e.length;t0))return o.iaddn(1),this.keyFromPrivate(o)}},h.prototype._truncateToN=function(e,t){var r=8*e.byteLength()-this.n.bitLength();return r>0&&(e=e.ushrn(r)),!t&&e.cmp(this.n)>=0?e.sub(this.n):e},h.prototype.sign=function(e,t,r,a){"object"==typeof r&&(a=r,r=null),a||(a={}),t=this.keyFromPrivate(t,r),e=this._truncateToN(new i(e,16));for(var o=this.n.byteLength(),s=t.getPrivate().toArray("be",o),c=e.toArray("be",o),u=new n({hash:this.hash,entropy:s,nonce:c,pers:a.pers,persEnc:a.persEnc||"utf8"}),h=this.n.sub(new i(1)),d=0;;d++){var p=a.k?a.k(d):new i(u.generate(this.n.byteLength()));if(!((p=this._truncateToN(p,!0)).cmpn(1)<=0||p.cmp(h)>=0)){var f=this.g.mul(p);if(!f.isInfinity()){var m=f.getX(),g=m.umod(this.n);if(0!==g.cmpn(0)){var _=p.invm(this.n).mul(g.mul(t.getPrivate()).iadd(e));if(0!==(_=_.umod(this.n)).cmpn(0)){var v=(f.getY().isOdd()?1:0)|(0!==m.cmp(g)?2:0);return a.canonical&&_.cmp(this.nh)>0&&(_=this.n.sub(_),v^=1),new l({r:g,s:_,recoveryParam:v})}}}}}},h.prototype.verify=function(e,t,r,n){e=this._truncateToN(new i(e,16)),r=this.keyFromPublic(r,n);var a=(t=new l(t,"hex")).r,o=t.s;if(a.cmpn(1)<0||a.cmp(this.n)>=0)return!1;if(o.cmpn(1)<0||o.cmp(this.n)>=0)return!1;var s,c=o.invm(this.n),u=c.mul(e).umod(this.n),h=c.mul(a).umod(this.n);return this.curve._maxwellTrick?!(s=this.g.jmulAdd(u,r.getPublic(),h)).isInfinity()&&s.eqXToP(a):!(s=this.g.mulAdd(u,r.getPublic(),h)).isInfinity()&&0===s.getX().umod(this.n).cmp(a)},h.prototype.recoverPubKey=function(e,t,r,n){c((3&r)===r,"The recovery param is more than two bits"),t=new l(t,n);var a=this.n,o=new i(e),s=t.r,u=t.s,h=1&r,d=r>>1;if(s.cmp(this.curve.p.umod(this.curve.n))>=0&&d)throw new Error("Unable to find sencond key candinate");s=d?this.curve.pointFromX(s.add(this.curve.n),h):this.curve.pointFromX(s,h);var p=t.r.invm(a),f=a.sub(o).mul(p).umod(a),m=u.mul(p).umod(a);return this.g.mulAdd(f,s,m)},h.prototype.getKeyRecoveryParam=function(e,t,r,i){if(null!==(t=new l(t,i)).recoveryParam)return t.recoveryParam;for(var n=0;n<4;n++){var a;try{a=this.recoverPubKey(e,t,n)}catch(e){continue}if(a.eq(r))return n}throw new Error("Unable to find valid recovery factor")}},function(e,t,r){"use strict";var i=r(119),n=r(190),a=r(19);function o(e){if(!(this instanceof o))return new o(e);this.hash=e.hash,this.predResist=!!e.predResist,this.outLen=this.hash.outSize,this.minEntropy=e.minEntropy||this.hash.hmacStrength,this._reseed=null,this.reseedInterval=null,this.K=null,this.V=null;var t=n.toArray(e.entropy,e.entropyEnc||"hex"),r=n.toArray(e.nonce,e.nonceEnc||"hex"),i=n.toArray(e.pers,e.persEnc||"hex");a(t.length>=this.minEntropy/8,"Not enough entropy. Minimum is: "+this.minEntropy+" bits"),this._init(t,r,i)}e.exports=o,o.prototype._init=function(e,t,r){var i=e.concat(t).concat(r);this.K=new Array(this.outLen/8),this.V=new Array(this.outLen/8);for(var n=0;n=this.minEntropy/8,"Not enough entropy. Minimum is: "+this.minEntropy+" bits"),this._update(e.concat(r||[])),this._reseed=1},o.prototype.generate=function(e,t,r,i){if(this._reseed>this.reseedInterval)throw new Error("Reseed is required");"string"!=typeof t&&(i=r,r=t,t=null),r&&(r=n.toArray(r,i||"hex"),this._update(r));for(var a=[];a.length"}},function(e,t,r){"use strict";var i=r(27),n=r(20),a=n.assert;function o(e,t){if(e instanceof o)return e;this._importDER(e,t)||(a(e.r&&e.s,"Signature without r or s"),this.r=new i(e.r,16),this.s=new i(e.s,16),void 0===e.recoveryParam?this.recoveryParam=null:this.recoveryParam=e.recoveryParam)}function s(){this.place=0}function c(e,t){var r=e[t.place++];if(!(128&r))return r;var i=15&r;if(0===i||i>4)return!1;for(var n=0,a=0,o=t.place;a>>=0;return!(n<=127)&&(t.place=o,n)}function u(e){for(var t=0,r=e.length-1;!e[t]&&!(128&e[t+1])&&t>>3);for(e.push(128|r);--r;)e.push(t>>>(r<<3)&255);e.push(t)}}e.exports=o,o.prototype._importDER=function(e,t){e=n.toArray(e,t);var r=new s;if(48!==e[r.place++])return!1;var a=c(e,r);if(!1===a)return!1;if(a+r.place!==e.length)return!1;if(2!==e[r.place++])return!1;var o=c(e,r);if(!1===o)return!1;var u=e.slice(r.place,o+r.place);if(r.place+=o,2!==e[r.place++])return!1;var l=c(e,r);if(!1===l)return!1;if(e.length!==l+r.place)return!1;var h=e.slice(r.place,l+r.place);if(0===u[0]){if(!(128&u[1]))return!1;u=u.slice(1)}if(0===h[0]){if(!(128&h[1]))return!1;h=h.slice(1)}return this.r=new i(u),this.s=new i(h),this.recoveryParam=null,!0},o.prototype.toDER=function(e){var t=this.r.toArray(),r=this.s.toArray();for(128&t[0]&&(t=[0].concat(t)),128&r[0]&&(r=[0].concat(r)),t=u(t),r=u(r);!(r[0]||128&r[1]);)r=r.slice(1);var i=[2];l(i,t.length),(i=i.concat(t)).push(2),l(i,r.length);var a=i.concat(r),o=[48];return l(o,a.length),o=o.concat(a),n.encode(o,e)}},function(e,t,r){"use strict";var i=r(119),n=r(118),a=r(20),o=a.assert,s=a.parseBytes,c=r(350),u=r(351);function l(e){if(o("ed25519"===e,"only tested with ed25519 so far"),!(this instanceof l))return new l(e);e=n[e].curve;this.curve=e,this.g=e.g,this.g.precompute(e.n.bitLength()+1),this.pointClass=e.point().constructor,this.encodingLength=Math.ceil(e.n.bitLength()/8),this.hash=i.sha512}e.exports=l,l.prototype.sign=function(e,t){e=s(e);var r=this.keyFromSecret(t),i=this.hashInt(r.messagePrefix(),e),n=this.g.mul(i),a=this.encodePoint(n),o=this.hashInt(a,r.pubBytes(),e).mul(r.priv()),c=i.add(o).umod(this.curve.n);return this.makeSignature({R:n,S:c,Rencoded:a})},l.prototype.verify=function(e,t,r){e=s(e),t=this.makeSignature(t);var i=this.keyFromPublic(r),n=this.hashInt(t.Rencoded(),i.pubBytes(),e),a=this.g.mul(t.S());return t.R().add(i.pub().mul(n)).eq(a)},l.prototype.hashInt=function(){for(var e=this.hash(),t=0;t=49&&o<=54?o-49+10:o>=17&&o<=22?o-17+10:15&o}return i}function c(e,t,r,i){for(var n=0,a=Math.min(e.length,r),o=t;o=49?s-49+10:s>=17?s-17+10:s}return n}a.isBN=function(e){return e instanceof a||null!==e&&"object"==typeof e&&e.constructor.wordSize===a.wordSize&&Array.isArray(e.words)},a.max=function(e,t){return e.cmp(t)>0?e:t},a.min=function(e,t){return e.cmp(t)<0?e:t},a.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),i(t===(0|t)&&t>=2&&t<=36);var n=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&n++,16===t?this._parseHex(e,n):this._parseBase(e,t,n),"-"===e[0]&&(this.negative=1),this.strip(),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(i(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initArray=function(e,t,r){if(i("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var n=0;n=0;n-=3)o=e[n]|e[n-1]<<8|e[n-2]<<16,this.words[a]|=o<>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);else if("le"===r)for(n=0,a=0;n>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);return this.strip()},a.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)n=s(e,r,r+6),this.words[i]|=n<>>26-a&4194303,(a+=24)>=26&&(a-=26,i++);r+6!==t&&(n=s(e,t,r+6),this.words[i]|=n<>>26-a&4194303),this.strip()},a.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var i=0,n=1;n<=67108863;n*=t)i++;i--,n=n/t|0;for(var a=e.length-r,o=a%i,s=Math.min(a,a-o)+r,u=0,l=r;l1&&0===this.words[this.length-1];)this.length--;return this._normSign()},a.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},a.prototype.inspect=function(){return(this.red?""};var u=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],l=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],h=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];function d(e,t,r){r.negative=t.negative^e.negative;var i=e.length+t.length|0;r.length=i,i=i-1|0;var n=0|e.words[0],a=0|t.words[0],o=n*a,s=67108863&o,c=o/67108864|0;r.words[0]=s;for(var u=1;u>>26,h=67108863&c,d=Math.min(u,t.length-1),p=Math.max(0,u-e.length+1);p<=d;p++){var f=u-p|0;l+=(o=(n=0|e.words[f])*(a=0|t.words[p])+h)/67108864|0,h=67108863&o}r.words[u]=0|h,c=0|l}return 0!==c?r.words[u]=0|c:r.length--,r.strip()}a.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var n=0,a=0,o=0;o>>24-n&16777215)||o!==this.length-1?u[6-c.length]+c+r:c+r,(n+=2)>=26&&(n-=26,o--)}for(0!==a&&(r=a.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var d=l[e],p=h[e];r="";var f=this.clone();for(f.negative=0;!f.isZero();){var m=f.modn(p).toString(e);r=(f=f.idivn(p)).isZero()?m+r:u[d-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}i(!1,"Base should be between 2 and 36")},a.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&i(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},a.prototype.toJSON=function(){return this.toString(16)},a.prototype.toBuffer=function(e,t){return i(void 0!==o),this.toArrayLike(o,e,t)},a.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)},a.prototype.toArrayLike=function(e,t,r){var n=this.byteLength(),a=r||Math.max(1,n);i(n<=a,"byte array longer than desired length"),i(a>0,"Requested array length <= 0"),this.strip();var o,s,c="le"===t,u=new e(a),l=this.clone();if(c){for(s=0;!l.isZero();s++)o=l.andln(255),l.iushrn(8),u[s]=o;for(;s=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},a.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},a.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},a.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},a.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},a.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},a.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},a.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var i=0;ie.length?this.clone().ixor(e):e.clone().ixor(this)},a.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},a.prototype.inotn=function(e){i("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var n=0;n0&&(this.words[n]=~this.words[n]&67108863>>26-r),this.strip()},a.prototype.notn=function(e){return this.clone().inotn(e)},a.prototype.setn=function(e,t){i("number"==typeof e&&e>=0);var r=e/26|0,n=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,i=e):(r=e,i=this);for(var n=0,a=0;a>>26;for(;0!==n&&a>>26;if(this.length=r.length,0!==n)this.words[this.length]=n,this.length++;else if(r!==this)for(;ae.length?this.clone().iadd(e):e.clone().iadd(this)},a.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,i,n=this.cmp(e);if(0===n)return this.negative=0,this.length=1,this.words[0]=0,this;n>0?(r=this,i=e):(r=e,i=this);for(var a=0,o=0;o>26,this.words[o]=67108863&t;for(;0!==a&&o>26,this.words[o]=67108863&t;if(0===a&&o>>13,p=0|o[1],f=8191&p,m=p>>>13,g=0|o[2],_=8191&g,v=g>>>13,y=0|o[3],b=8191&y,E=y>>>13,w=0|o[4],S=8191&w,k=w>>>13,x=0|o[5],M=8191&x,N=x>>>13,j=0|o[6],T=8191&j,R=j>>>13,I=0|o[7],O=8191&I,A=I>>>13,P=0|o[8],D=8191&P,F=P>>>13,C=0|o[9],B=8191&C,z=C>>>13,L=0|s[0],U=8191&L,H=L>>>13,q=0|s[1],K=8191&q,Z=q>>>13,W=0|s[2],X=8191&W,Q=W>>>13,J=0|s[3],V=8191&J,G=J>>>13,Y=0|s[4],$=8191&Y,ee=Y>>>13,te=0|s[5],re=8191&te,ie=te>>>13,ne=0|s[6],ae=8191&ne,oe=ne>>>13,se=0|s[7],ce=8191&se,ue=se>>>13,le=0|s[8],he=8191&le,de=le>>>13,pe=0|s[9],fe=8191&pe,me=pe>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(u+(i=Math.imul(h,U))|0)+((8191&(n=(n=Math.imul(h,H))+Math.imul(d,U)|0))<<13)|0;u=((a=Math.imul(d,H))+(n>>>13)|0)+(ge>>>26)|0,ge&=67108863,i=Math.imul(f,U),n=(n=Math.imul(f,H))+Math.imul(m,U)|0,a=Math.imul(m,H);var _e=(u+(i=i+Math.imul(h,K)|0)|0)+((8191&(n=(n=n+Math.imul(h,Z)|0)+Math.imul(d,K)|0))<<13)|0;u=((a=a+Math.imul(d,Z)|0)+(n>>>13)|0)+(_e>>>26)|0,_e&=67108863,i=Math.imul(_,U),n=(n=Math.imul(_,H))+Math.imul(v,U)|0,a=Math.imul(v,H),i=i+Math.imul(f,K)|0,n=(n=n+Math.imul(f,Z)|0)+Math.imul(m,K)|0,a=a+Math.imul(m,Z)|0;var ve=(u+(i=i+Math.imul(h,X)|0)|0)+((8191&(n=(n=n+Math.imul(h,Q)|0)+Math.imul(d,X)|0))<<13)|0;u=((a=a+Math.imul(d,Q)|0)+(n>>>13)|0)+(ve>>>26)|0,ve&=67108863,i=Math.imul(b,U),n=(n=Math.imul(b,H))+Math.imul(E,U)|0,a=Math.imul(E,H),i=i+Math.imul(_,K)|0,n=(n=n+Math.imul(_,Z)|0)+Math.imul(v,K)|0,a=a+Math.imul(v,Z)|0,i=i+Math.imul(f,X)|0,n=(n=n+Math.imul(f,Q)|0)+Math.imul(m,X)|0,a=a+Math.imul(m,Q)|0;var ye=(u+(i=i+Math.imul(h,V)|0)|0)+((8191&(n=(n=n+Math.imul(h,G)|0)+Math.imul(d,V)|0))<<13)|0;u=((a=a+Math.imul(d,G)|0)+(n>>>13)|0)+(ye>>>26)|0,ye&=67108863,i=Math.imul(S,U),n=(n=Math.imul(S,H))+Math.imul(k,U)|0,a=Math.imul(k,H),i=i+Math.imul(b,K)|0,n=(n=n+Math.imul(b,Z)|0)+Math.imul(E,K)|0,a=a+Math.imul(E,Z)|0,i=i+Math.imul(_,X)|0,n=(n=n+Math.imul(_,Q)|0)+Math.imul(v,X)|0,a=a+Math.imul(v,Q)|0,i=i+Math.imul(f,V)|0,n=(n=n+Math.imul(f,G)|0)+Math.imul(m,V)|0,a=a+Math.imul(m,G)|0;var be=(u+(i=i+Math.imul(h,$)|0)|0)+((8191&(n=(n=n+Math.imul(h,ee)|0)+Math.imul(d,$)|0))<<13)|0;u=((a=a+Math.imul(d,ee)|0)+(n>>>13)|0)+(be>>>26)|0,be&=67108863,i=Math.imul(M,U),n=(n=Math.imul(M,H))+Math.imul(N,U)|0,a=Math.imul(N,H),i=i+Math.imul(S,K)|0,n=(n=n+Math.imul(S,Z)|0)+Math.imul(k,K)|0,a=a+Math.imul(k,Z)|0,i=i+Math.imul(b,X)|0,n=(n=n+Math.imul(b,Q)|0)+Math.imul(E,X)|0,a=a+Math.imul(E,Q)|0,i=i+Math.imul(_,V)|0,n=(n=n+Math.imul(_,G)|0)+Math.imul(v,V)|0,a=a+Math.imul(v,G)|0,i=i+Math.imul(f,$)|0,n=(n=n+Math.imul(f,ee)|0)+Math.imul(m,$)|0,a=a+Math.imul(m,ee)|0;var Ee=(u+(i=i+Math.imul(h,re)|0)|0)+((8191&(n=(n=n+Math.imul(h,ie)|0)+Math.imul(d,re)|0))<<13)|0;u=((a=a+Math.imul(d,ie)|0)+(n>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,i=Math.imul(T,U),n=(n=Math.imul(T,H))+Math.imul(R,U)|0,a=Math.imul(R,H),i=i+Math.imul(M,K)|0,n=(n=n+Math.imul(M,Z)|0)+Math.imul(N,K)|0,a=a+Math.imul(N,Z)|0,i=i+Math.imul(S,X)|0,n=(n=n+Math.imul(S,Q)|0)+Math.imul(k,X)|0,a=a+Math.imul(k,Q)|0,i=i+Math.imul(b,V)|0,n=(n=n+Math.imul(b,G)|0)+Math.imul(E,V)|0,a=a+Math.imul(E,G)|0,i=i+Math.imul(_,$)|0,n=(n=n+Math.imul(_,ee)|0)+Math.imul(v,$)|0,a=a+Math.imul(v,ee)|0,i=i+Math.imul(f,re)|0,n=(n=n+Math.imul(f,ie)|0)+Math.imul(m,re)|0,a=a+Math.imul(m,ie)|0;var we=(u+(i=i+Math.imul(h,ae)|0)|0)+((8191&(n=(n=n+Math.imul(h,oe)|0)+Math.imul(d,ae)|0))<<13)|0;u=((a=a+Math.imul(d,oe)|0)+(n>>>13)|0)+(we>>>26)|0,we&=67108863,i=Math.imul(O,U),n=(n=Math.imul(O,H))+Math.imul(A,U)|0,a=Math.imul(A,H),i=i+Math.imul(T,K)|0,n=(n=n+Math.imul(T,Z)|0)+Math.imul(R,K)|0,a=a+Math.imul(R,Z)|0,i=i+Math.imul(M,X)|0,n=(n=n+Math.imul(M,Q)|0)+Math.imul(N,X)|0,a=a+Math.imul(N,Q)|0,i=i+Math.imul(S,V)|0,n=(n=n+Math.imul(S,G)|0)+Math.imul(k,V)|0,a=a+Math.imul(k,G)|0,i=i+Math.imul(b,$)|0,n=(n=n+Math.imul(b,ee)|0)+Math.imul(E,$)|0,a=a+Math.imul(E,ee)|0,i=i+Math.imul(_,re)|0,n=(n=n+Math.imul(_,ie)|0)+Math.imul(v,re)|0,a=a+Math.imul(v,ie)|0,i=i+Math.imul(f,ae)|0,n=(n=n+Math.imul(f,oe)|0)+Math.imul(m,ae)|0,a=a+Math.imul(m,oe)|0;var Se=(u+(i=i+Math.imul(h,ce)|0)|0)+((8191&(n=(n=n+Math.imul(h,ue)|0)+Math.imul(d,ce)|0))<<13)|0;u=((a=a+Math.imul(d,ue)|0)+(n>>>13)|0)+(Se>>>26)|0,Se&=67108863,i=Math.imul(D,U),n=(n=Math.imul(D,H))+Math.imul(F,U)|0,a=Math.imul(F,H),i=i+Math.imul(O,K)|0,n=(n=n+Math.imul(O,Z)|0)+Math.imul(A,K)|0,a=a+Math.imul(A,Z)|0,i=i+Math.imul(T,X)|0,n=(n=n+Math.imul(T,Q)|0)+Math.imul(R,X)|0,a=a+Math.imul(R,Q)|0,i=i+Math.imul(M,V)|0,n=(n=n+Math.imul(M,G)|0)+Math.imul(N,V)|0,a=a+Math.imul(N,G)|0,i=i+Math.imul(S,$)|0,n=(n=n+Math.imul(S,ee)|0)+Math.imul(k,$)|0,a=a+Math.imul(k,ee)|0,i=i+Math.imul(b,re)|0,n=(n=n+Math.imul(b,ie)|0)+Math.imul(E,re)|0,a=a+Math.imul(E,ie)|0,i=i+Math.imul(_,ae)|0,n=(n=n+Math.imul(_,oe)|0)+Math.imul(v,ae)|0,a=a+Math.imul(v,oe)|0,i=i+Math.imul(f,ce)|0,n=(n=n+Math.imul(f,ue)|0)+Math.imul(m,ce)|0,a=a+Math.imul(m,ue)|0;var ke=(u+(i=i+Math.imul(h,he)|0)|0)+((8191&(n=(n=n+Math.imul(h,de)|0)+Math.imul(d,he)|0))<<13)|0;u=((a=a+Math.imul(d,de)|0)+(n>>>13)|0)+(ke>>>26)|0,ke&=67108863,i=Math.imul(B,U),n=(n=Math.imul(B,H))+Math.imul(z,U)|0,a=Math.imul(z,H),i=i+Math.imul(D,K)|0,n=(n=n+Math.imul(D,Z)|0)+Math.imul(F,K)|0,a=a+Math.imul(F,Z)|0,i=i+Math.imul(O,X)|0,n=(n=n+Math.imul(O,Q)|0)+Math.imul(A,X)|0,a=a+Math.imul(A,Q)|0,i=i+Math.imul(T,V)|0,n=(n=n+Math.imul(T,G)|0)+Math.imul(R,V)|0,a=a+Math.imul(R,G)|0,i=i+Math.imul(M,$)|0,n=(n=n+Math.imul(M,ee)|0)+Math.imul(N,$)|0,a=a+Math.imul(N,ee)|0,i=i+Math.imul(S,re)|0,n=(n=n+Math.imul(S,ie)|0)+Math.imul(k,re)|0,a=a+Math.imul(k,ie)|0,i=i+Math.imul(b,ae)|0,n=(n=n+Math.imul(b,oe)|0)+Math.imul(E,ae)|0,a=a+Math.imul(E,oe)|0,i=i+Math.imul(_,ce)|0,n=(n=n+Math.imul(_,ue)|0)+Math.imul(v,ce)|0,a=a+Math.imul(v,ue)|0,i=i+Math.imul(f,he)|0,n=(n=n+Math.imul(f,de)|0)+Math.imul(m,he)|0,a=a+Math.imul(m,de)|0;var xe=(u+(i=i+Math.imul(h,fe)|0)|0)+((8191&(n=(n=n+Math.imul(h,me)|0)+Math.imul(d,fe)|0))<<13)|0;u=((a=a+Math.imul(d,me)|0)+(n>>>13)|0)+(xe>>>26)|0,xe&=67108863,i=Math.imul(B,K),n=(n=Math.imul(B,Z))+Math.imul(z,K)|0,a=Math.imul(z,Z),i=i+Math.imul(D,X)|0,n=(n=n+Math.imul(D,Q)|0)+Math.imul(F,X)|0,a=a+Math.imul(F,Q)|0,i=i+Math.imul(O,V)|0,n=(n=n+Math.imul(O,G)|0)+Math.imul(A,V)|0,a=a+Math.imul(A,G)|0,i=i+Math.imul(T,$)|0,n=(n=n+Math.imul(T,ee)|0)+Math.imul(R,$)|0,a=a+Math.imul(R,ee)|0,i=i+Math.imul(M,re)|0,n=(n=n+Math.imul(M,ie)|0)+Math.imul(N,re)|0,a=a+Math.imul(N,ie)|0,i=i+Math.imul(S,ae)|0,n=(n=n+Math.imul(S,oe)|0)+Math.imul(k,ae)|0,a=a+Math.imul(k,oe)|0,i=i+Math.imul(b,ce)|0,n=(n=n+Math.imul(b,ue)|0)+Math.imul(E,ce)|0,a=a+Math.imul(E,ue)|0,i=i+Math.imul(_,he)|0,n=(n=n+Math.imul(_,de)|0)+Math.imul(v,he)|0,a=a+Math.imul(v,de)|0;var Me=(u+(i=i+Math.imul(f,fe)|0)|0)+((8191&(n=(n=n+Math.imul(f,me)|0)+Math.imul(m,fe)|0))<<13)|0;u=((a=a+Math.imul(m,me)|0)+(n>>>13)|0)+(Me>>>26)|0,Me&=67108863,i=Math.imul(B,X),n=(n=Math.imul(B,Q))+Math.imul(z,X)|0,a=Math.imul(z,Q),i=i+Math.imul(D,V)|0,n=(n=n+Math.imul(D,G)|0)+Math.imul(F,V)|0,a=a+Math.imul(F,G)|0,i=i+Math.imul(O,$)|0,n=(n=n+Math.imul(O,ee)|0)+Math.imul(A,$)|0,a=a+Math.imul(A,ee)|0,i=i+Math.imul(T,re)|0,n=(n=n+Math.imul(T,ie)|0)+Math.imul(R,re)|0,a=a+Math.imul(R,ie)|0,i=i+Math.imul(M,ae)|0,n=(n=n+Math.imul(M,oe)|0)+Math.imul(N,ae)|0,a=a+Math.imul(N,oe)|0,i=i+Math.imul(S,ce)|0,n=(n=n+Math.imul(S,ue)|0)+Math.imul(k,ce)|0,a=a+Math.imul(k,ue)|0,i=i+Math.imul(b,he)|0,n=(n=n+Math.imul(b,de)|0)+Math.imul(E,he)|0,a=a+Math.imul(E,de)|0;var Ne=(u+(i=i+Math.imul(_,fe)|0)|0)+((8191&(n=(n=n+Math.imul(_,me)|0)+Math.imul(v,fe)|0))<<13)|0;u=((a=a+Math.imul(v,me)|0)+(n>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,i=Math.imul(B,V),n=(n=Math.imul(B,G))+Math.imul(z,V)|0,a=Math.imul(z,G),i=i+Math.imul(D,$)|0,n=(n=n+Math.imul(D,ee)|0)+Math.imul(F,$)|0,a=a+Math.imul(F,ee)|0,i=i+Math.imul(O,re)|0,n=(n=n+Math.imul(O,ie)|0)+Math.imul(A,re)|0,a=a+Math.imul(A,ie)|0,i=i+Math.imul(T,ae)|0,n=(n=n+Math.imul(T,oe)|0)+Math.imul(R,ae)|0,a=a+Math.imul(R,oe)|0,i=i+Math.imul(M,ce)|0,n=(n=n+Math.imul(M,ue)|0)+Math.imul(N,ce)|0,a=a+Math.imul(N,ue)|0,i=i+Math.imul(S,he)|0,n=(n=n+Math.imul(S,de)|0)+Math.imul(k,he)|0,a=a+Math.imul(k,de)|0;var je=(u+(i=i+Math.imul(b,fe)|0)|0)+((8191&(n=(n=n+Math.imul(b,me)|0)+Math.imul(E,fe)|0))<<13)|0;u=((a=a+Math.imul(E,me)|0)+(n>>>13)|0)+(je>>>26)|0,je&=67108863,i=Math.imul(B,$),n=(n=Math.imul(B,ee))+Math.imul(z,$)|0,a=Math.imul(z,ee),i=i+Math.imul(D,re)|0,n=(n=n+Math.imul(D,ie)|0)+Math.imul(F,re)|0,a=a+Math.imul(F,ie)|0,i=i+Math.imul(O,ae)|0,n=(n=n+Math.imul(O,oe)|0)+Math.imul(A,ae)|0,a=a+Math.imul(A,oe)|0,i=i+Math.imul(T,ce)|0,n=(n=n+Math.imul(T,ue)|0)+Math.imul(R,ce)|0,a=a+Math.imul(R,ue)|0,i=i+Math.imul(M,he)|0,n=(n=n+Math.imul(M,de)|0)+Math.imul(N,he)|0,a=a+Math.imul(N,de)|0;var Te=(u+(i=i+Math.imul(S,fe)|0)|0)+((8191&(n=(n=n+Math.imul(S,me)|0)+Math.imul(k,fe)|0))<<13)|0;u=((a=a+Math.imul(k,me)|0)+(n>>>13)|0)+(Te>>>26)|0,Te&=67108863,i=Math.imul(B,re),n=(n=Math.imul(B,ie))+Math.imul(z,re)|0,a=Math.imul(z,ie),i=i+Math.imul(D,ae)|0,n=(n=n+Math.imul(D,oe)|0)+Math.imul(F,ae)|0,a=a+Math.imul(F,oe)|0,i=i+Math.imul(O,ce)|0,n=(n=n+Math.imul(O,ue)|0)+Math.imul(A,ce)|0,a=a+Math.imul(A,ue)|0,i=i+Math.imul(T,he)|0,n=(n=n+Math.imul(T,de)|0)+Math.imul(R,he)|0,a=a+Math.imul(R,de)|0;var Re=(u+(i=i+Math.imul(M,fe)|0)|0)+((8191&(n=(n=n+Math.imul(M,me)|0)+Math.imul(N,fe)|0))<<13)|0;u=((a=a+Math.imul(N,me)|0)+(n>>>13)|0)+(Re>>>26)|0,Re&=67108863,i=Math.imul(B,ae),n=(n=Math.imul(B,oe))+Math.imul(z,ae)|0,a=Math.imul(z,oe),i=i+Math.imul(D,ce)|0,n=(n=n+Math.imul(D,ue)|0)+Math.imul(F,ce)|0,a=a+Math.imul(F,ue)|0,i=i+Math.imul(O,he)|0,n=(n=n+Math.imul(O,de)|0)+Math.imul(A,he)|0,a=a+Math.imul(A,de)|0;var Ie=(u+(i=i+Math.imul(T,fe)|0)|0)+((8191&(n=(n=n+Math.imul(T,me)|0)+Math.imul(R,fe)|0))<<13)|0;u=((a=a+Math.imul(R,me)|0)+(n>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,i=Math.imul(B,ce),n=(n=Math.imul(B,ue))+Math.imul(z,ce)|0,a=Math.imul(z,ue),i=i+Math.imul(D,he)|0,n=(n=n+Math.imul(D,de)|0)+Math.imul(F,he)|0,a=a+Math.imul(F,de)|0;var Oe=(u+(i=i+Math.imul(O,fe)|0)|0)+((8191&(n=(n=n+Math.imul(O,me)|0)+Math.imul(A,fe)|0))<<13)|0;u=((a=a+Math.imul(A,me)|0)+(n>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,i=Math.imul(B,he),n=(n=Math.imul(B,de))+Math.imul(z,he)|0,a=Math.imul(z,de);var Ae=(u+(i=i+Math.imul(D,fe)|0)|0)+((8191&(n=(n=n+Math.imul(D,me)|0)+Math.imul(F,fe)|0))<<13)|0;u=((a=a+Math.imul(F,me)|0)+(n>>>13)|0)+(Ae>>>26)|0,Ae&=67108863;var Pe=(u+(i=Math.imul(B,fe))|0)+((8191&(n=(n=Math.imul(B,me))+Math.imul(z,fe)|0))<<13)|0;return u=((a=Math.imul(z,me))+(n>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,c[0]=ge,c[1]=_e,c[2]=ve,c[3]=ye,c[4]=be,c[5]=Ee,c[6]=we,c[7]=Se,c[8]=ke,c[9]=xe,c[10]=Me,c[11]=Ne,c[12]=je,c[13]=Te,c[14]=Re,c[15]=Ie,c[16]=Oe,c[17]=Ae,c[18]=Pe,0!==u&&(c[19]=u,r.length++),r};function f(e,t,r){return(new m).mulp(e,t,r)}function m(e,t){this.x=e,this.y=t}Math.imul||(p=d),a.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?p(this,e,t):r<63?d(this,e,t):r<1024?function(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var i=0,n=0,a=0;a>>26)|0)>>>26,o&=67108863}r.words[a]=s,i=o,o=n}return 0!==i?r.words[a]=i:r.length--,r.strip()}(this,e,t):f(this,e,t)},m.prototype.makeRBT=function(e){for(var t=new Array(e),r=a.prototype._countBits(e)-1,i=0;i>=1;return i},m.prototype.permute=function(e,t,r,i,n,a){for(var o=0;o>>=1)n++;return 1<>>=13,r[2*o+1]=8191&a,a>>>=13;for(o=2*t;o>=26,t+=n/67108864|0,t+=a>>>26,this.words[r]=67108863&a}return 0!==t&&(this.words[r]=t,this.length++),this},a.prototype.muln=function(e){return this.clone().imuln(e)},a.prototype.sqr=function(){return this.mul(this)},a.prototype.isqr=function(){return this.imul(this.clone())},a.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>n}return t}(e);if(0===t.length)return new a(1);for(var r=this,i=0;i=0);var t,r=e%26,n=(e-r)/26,a=67108863>>>26-r<<26-r;if(0!==r){var o=0;for(t=0;t>>26-r}o&&(this.words[t]=o,this.length++)}if(0!==n){for(t=this.length-1;t>=0;t--)this.words[t+n]=this.words[t];for(t=0;t=0),n=t?(t-t%26)/26:0;var a=e%26,o=Math.min((e-a)/26,this.length),s=67108863^67108863>>>a<o)for(this.length-=o,u=0;u=0&&(0!==l||u>=n);u--){var h=0|this.words[u];this.words[u]=l<<26-a|h>>>a,l=h&s}return c&&0!==l&&(c.words[c.length++]=l),0===this.length&&(this.words[0]=0,this.length=1),this.strip()},a.prototype.ishrn=function(e,t,r){return i(0===this.negative),this.iushrn(e,t,r)},a.prototype.shln=function(e){return this.clone().ishln(e)},a.prototype.ushln=function(e){return this.clone().iushln(e)},a.prototype.shrn=function(e){return this.clone().ishrn(e)},a.prototype.ushrn=function(e){return this.clone().iushrn(e)},a.prototype.testn=function(e){i("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,n=1<=0);var t=e%26,r=(e-t)/26;if(i(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var n=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},a.prototype.isubn=function(e){if(i("number"==typeof e),i(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(c/67108864|0),this.words[n+r]=67108863&a}for(;n>26,this.words[n+r]=67108863&a;if(0===s)return this.strip();for(i(-1===s),s=0,n=0;n>26,this.words[n]=67108863&a;return this.negative=1,this.strip()},a.prototype._wordDiv=function(e,t){var r=(this.length,e.length),i=this.clone(),n=e,o=0|n.words[n.length-1];0!==(r=26-this._countBits(o))&&(n=n.ushln(r),i.iushln(r),o=0|n.words[n.length-1]);var s,c=i.length-n.length;if("mod"!==t){(s=new a(null)).length=c+1,s.words=new Array(s.length);for(var u=0;u=0;h--){var d=67108864*(0|i.words[n.length+h])+(0|i.words[n.length+h-1]);for(d=Math.min(d/o|0,67108863),i._ishlnsubmul(n,d,h);0!==i.negative;)d--,i.negative=0,i._ishlnsubmul(n,1,h),i.isZero()||(i.negative^=1);s&&(s.words[h]=d)}return s&&s.strip(),i.strip(),"div"!==t&&0!==r&&i.iushrn(r),{div:s||null,mod:i}},a.prototype.divmod=function(e,t,r){return i(!e.isZero()),this.isZero()?{div:new a(0),mod:new a(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(n=s.div.neg()),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.iadd(e)),{div:n,mod:o}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(n=s.div.neg()),{div:n,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.isub(e)),{div:s.div,mod:o}):e.length>this.length||this.cmp(e)<0?{div:new a(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new a(this.modn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new a(this.modn(e.words[0]))}:this._wordDiv(e,t);var n,o,s},a.prototype.div=function(e){return this.divmod(e,"div",!1).div},a.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},a.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},a.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,i=e.ushrn(1),n=e.andln(1),a=r.cmp(i);return a<0||1===n&&0===a?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},a.prototype.modn=function(e){i(e<=67108863);for(var t=(1<<26)%e,r=0,n=this.length-1;n>=0;n--)r=(t*r+(0|this.words[n]))%e;return r},a.prototype.idivn=function(e){i(e<=67108863);for(var t=0,r=this.length-1;r>=0;r--){var n=(0|this.words[r])+67108864*t;this.words[r]=n/e|0,t=n%e}return this.strip()},a.prototype.divn=function(e){return this.clone().idivn(e)},a.prototype.egcd=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n=new a(1),o=new a(0),s=new a(0),c=new a(1),u=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++u;for(var l=r.clone(),h=t.clone();!t.isZero();){for(var d=0,p=1;0==(t.words[0]&p)&&d<26;++d,p<<=1);if(d>0)for(t.iushrn(d);d-- >0;)(n.isOdd()||o.isOdd())&&(n.iadd(l),o.isub(h)),n.iushrn(1),o.iushrn(1);for(var f=0,m=1;0==(r.words[0]&m)&&f<26;++f,m<<=1);if(f>0)for(r.iushrn(f);f-- >0;)(s.isOdd()||c.isOdd())&&(s.iadd(l),c.isub(h)),s.iushrn(1),c.iushrn(1);t.cmp(r)>=0?(t.isub(r),n.isub(s),o.isub(c)):(r.isub(t),s.isub(n),c.isub(o))}return{a:s,b:c,gcd:r.iushln(u)}},a.prototype._invmp=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n,o=new a(1),s=new a(0),c=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var u=0,l=1;0==(t.words[0]&l)&&u<26;++u,l<<=1);if(u>0)for(t.iushrn(u);u-- >0;)o.isOdd()&&o.iadd(c),o.iushrn(1);for(var h=0,d=1;0==(r.words[0]&d)&&h<26;++h,d<<=1);if(h>0)for(r.iushrn(h);h-- >0;)s.isOdd()&&s.iadd(c),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),o.isub(s)):(r.isub(t),s.isub(o))}return(n=0===t.cmpn(1)?o:s).cmpn(0)<0&&n.iadd(e),n},a.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var i=0;t.isEven()&&r.isEven();i++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var n=t.cmp(r);if(n<0){var a=t;t=r,r=a}else if(0===n||0===r.cmpn(1))break;t.isub(r)}return r.iushln(i)},a.prototype.invm=function(e){return this.egcd(e).a.umod(e)},a.prototype.isEven=function(){return 0==(1&this.words[0])},a.prototype.isOdd=function(){return 1==(1&this.words[0])},a.prototype.andln=function(e){return this.words[0]&e},a.prototype.bincn=function(e){i("number"==typeof e);var t=e%26,r=(e-t)/26,n=1<>>26,s&=67108863,this.words[o]=s}return 0!==a&&(this.words[o]=a,this.length++),this},a.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},a.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this.strip(),this.length>1)t=1;else{r&&(e=-e),i(e<=67108863,"Number is too big");var n=0|this.words[0];t=n===e?0:ne.length)return 1;if(this.length=0;r--){var i=0|this.words[r],n=0|e.words[r];if(i!==n){in&&(t=1);break}}return t},a.prototype.gtn=function(e){return 1===this.cmpn(e)},a.prototype.gt=function(e){return 1===this.cmp(e)},a.prototype.gten=function(e){return this.cmpn(e)>=0},a.prototype.gte=function(e){return this.cmp(e)>=0},a.prototype.ltn=function(e){return-1===this.cmpn(e)},a.prototype.lt=function(e){return-1===this.cmp(e)},a.prototype.lten=function(e){return this.cmpn(e)<=0},a.prototype.lte=function(e){return this.cmp(e)<=0},a.prototype.eqn=function(e){return 0===this.cmpn(e)},a.prototype.eq=function(e){return 0===this.cmp(e)},a.red=function(e){return new w(e)},a.prototype.toRed=function(e){return i(!this.red,"Already a number in reduction context"),i(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},a.prototype.fromRed=function(){return i(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},a.prototype._forceRed=function(e){return this.red=e,this},a.prototype.forceRed=function(e){return i(!this.red,"Already a number in reduction context"),this._forceRed(e)},a.prototype.redAdd=function(e){return i(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},a.prototype.redIAdd=function(e){return i(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},a.prototype.redSub=function(e){return i(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},a.prototype.redISub=function(e){return i(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},a.prototype.redShl=function(e){return i(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},a.prototype.redMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},a.prototype.redIMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},a.prototype.redSqr=function(){return i(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},a.prototype.redISqr=function(){return i(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},a.prototype.redSqrt=function(){return i(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},a.prototype.redInvm=function(){return i(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},a.prototype.redNeg=function(){return i(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},a.prototype.redPow=function(e){return i(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var g={k256:null,p224:null,p192:null,p25519:null};function _(e,t){this.name=e,this.p=new a(t,16),this.n=this.p.bitLength(),this.k=new a(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function v(){_.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function y(){_.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function b(){_.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function E(){_.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function w(e){if("string"==typeof e){var t=a._prime(e);this.m=t.p,this.prime=t}else i(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function S(e){w.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new a(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}_.prototype._tmp=function(){var e=new a(null);return e.words=new Array(Math.ceil(this.n/13)),e},_.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var i=t0?r.isub(this.p):r.strip(),r},_.prototype.split=function(e,t){e.iushrn(this.n,0,t)},_.prototype.imulK=function(e){return e.imul(this.k)},n(v,_),v.prototype.split=function(e,t){for(var r=Math.min(e.length,9),i=0;i>>22,n=a}n>>>=22,e.words[i-10]=n,0===n&&e.length>10?e.length-=10:e.length-=9},v.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=n,t=i}return 0!==t&&(e.words[e.length++]=t),e},a._prime=function(e){if(g[e])return g[e];var t;if("k256"===e)t=new v;else if("p224"===e)t=new y;else if("p192"===e)t=new b;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new E}return g[e]=t,t},w.prototype._verify1=function(e){i(0===e.negative,"red works only with positives"),i(e.red,"red works only with red numbers")},w.prototype._verify2=function(e,t){i(0==(e.negative|t.negative),"red works only with positives"),i(e.red&&e.red===t.red,"red works only with red numbers")},w.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):e.umod(this.m)._forceRed(this)},w.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},w.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},w.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},w.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},w.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},w.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},w.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},w.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},w.prototype.isqr=function(e){return this.imul(e,e.clone())},w.prototype.sqr=function(e){return this.mul(e,e)},w.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(i(t%2==1),3===t){var r=this.m.add(new a(1)).iushrn(2);return this.pow(e,r)}for(var n=this.m.subn(1),o=0;!n.isZero()&&0===n.andln(1);)o++,n.iushrn(1);i(!n.isZero());var s=new a(1).toRed(this),c=s.redNeg(),u=this.m.subn(1).iushrn(1),l=this.m.bitLength();for(l=new a(2*l*l).toRed(this);0!==this.pow(l,u).cmp(c);)l.redIAdd(c);for(var h=this.pow(l,n),d=this.pow(e,n.addn(1).iushrn(1)),p=this.pow(e,n),f=o;0!==p.cmp(s);){for(var m=p,g=0;0!==m.cmp(s);g++)m=m.redSqr();i(g=0;i--){for(var u=t.words[i],l=c-1;l>=0;l--){var h=u>>l&1;n!==r[0]&&(n=this.sqr(n)),0!==h||0!==o?(o<<=1,o|=h,(4===++s||0===i&&0===l)&&(n=this.mul(n,r[o]),s=0,o=0)):s=0}c=26}return n},w.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},w.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},a.mont=function(e){return new S(e)},n(S,w),S.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},S.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},S.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),a=n;return n.cmp(this.m)>=0?a=n.isub(this.m):n.cmpn(0)<0&&(a=n.iadd(this.m)),a._forceRed(this)},S.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new a(0)._forceRed(this);var r=e.mul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),o=n;return n.cmp(this.m)>=0?o=n.isub(this.m):n.cmpn(0)<0&&(o=n.iadd(this.m)),o._forceRed(this)},S.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(22)(e))},function(e,t){},function(e,t,r){var i=r(64),n=r(0);function a(e,t){this.name=e,this.body=t,this.decoders={},this.encoders={}}t.define=function(e,t){return new a(e,t)},a.prototype._createNamed=function(e){var t;try{t=r(357).runInThisContext("(function "+this.name+"(entity) {\n this._initNamed(entity);\n})")}catch(e){t=function(e){this._initNamed(e)}}return n(t,e),t.prototype._initNamed=function(t){e.call(this,t)},new t(this)},a.prototype._getDecoder=function(e){return e=e||"der",this.decoders.hasOwnProperty(e)||(this.decoders[e]=this._createNamed(i.decoders[e])),this.decoders[e]},a.prototype.decode=function(e,t,r){return this._getDecoder(t).decode(e,r)},a.prototype._getEncoder=function(e){return e=e||"der",this.encoders.hasOwnProperty(e)||(this.encoders[e]=this._createNamed(i.encoders[e])),this.encoders[e]},a.prototype.encode=function(e,t,r){return this._getEncoder(t).encode(e,r)}},function(module,exports){var indexOf=function(e,t){if(e.indexOf)return e.indexOf(t);for(var r=0;r=t)throw new Error("invalid sig")}e.exports=function(e,t,r,u,l){var h=o(r);if("ec"===h.type){if("ecdsa"!==u&&"ecdsa/rsa"!==u)throw new Error("wrong public key type");return function(e,t,r){var i=s[r.data.algorithm.curve.join(".")];if(!i)throw new Error("unknown curve "+r.data.algorithm.curve.join("."));var n=new a(i),o=r.data.subjectPrivateKey.data;return n.verify(t,e,o)}(e,t,h)}if("dsa"===h.type){if("dsa"!==u)throw new Error("wrong public key type");return function(e,t,r){var i=r.data.p,a=r.data.q,s=r.data.g,u=r.data.pub_key,l=o.signature.decode(e,"der"),h=l.s,d=l.r;c(h,a),c(d,a);var p=n.mont(i),f=h.invm(a);return 0===s.toRed(p).redPow(new n(t).mul(f).mod(a)).fromRed().mul(u.toRed(p).redPow(d.mul(f).mod(a)).fromRed()).mod(i).mod(a).cmp(d)}(e,t,h)}if("rsa"!==u&&"ecdsa/rsa"!==u)throw new Error("wrong public key type");t=i.concat([l,t]);for(var d=h.modulus.byteLength(),p=[1],f=0;t.length+p.length+2=49&&o<=54?o-49+10:o>=17&&o<=22?o-17+10:15&o}return i}function c(e,t,r,i){for(var n=0,a=Math.min(e.length,r),o=t;o=49?s-49+10:s>=17?s-17+10:s}return n}a.isBN=function(e){return e instanceof a||null!==e&&"object"==typeof e&&e.constructor.wordSize===a.wordSize&&Array.isArray(e.words)},a.max=function(e,t){return e.cmp(t)>0?e:t},a.min=function(e,t){return e.cmp(t)<0?e:t},a.prototype._init=function(e,t,r){if("number"==typeof e)return this._initNumber(e,t,r);if("object"==typeof e)return this._initArray(e,t,r);"hex"===t&&(t=16),i(t===(0|t)&&t>=2&&t<=36);var n=0;"-"===(e=e.toString().replace(/\s+/g,""))[0]&&n++,16===t?this._parseHex(e,n):this._parseBase(e,t,n),"-"===e[0]&&(this.negative=1),this.strip(),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initNumber=function(e,t,r){e<0&&(this.negative=1,e=-e),e<67108864?(this.words=[67108863&e],this.length=1):e<4503599627370496?(this.words=[67108863&e,e/67108864&67108863],this.length=2):(i(e<9007199254740992),this.words=[67108863&e,e/67108864&67108863,1],this.length=3),"le"===r&&this._initArray(this.toArray(),t,r)},a.prototype._initArray=function(e,t,r){if(i("number"==typeof e.length),e.length<=0)return this.words=[0],this.length=1,this;this.length=Math.ceil(e.length/3),this.words=new Array(this.length);for(var n=0;n=0;n-=3)o=e[n]|e[n-1]<<8|e[n-2]<<16,this.words[a]|=o<>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);else if("le"===r)for(n=0,a=0;n>>26-s&67108863,(s+=24)>=26&&(s-=26,a++);return this.strip()},a.prototype._parseHex=function(e,t){this.length=Math.ceil((e.length-t)/6),this.words=new Array(this.length);for(var r=0;r=t;r-=6)n=s(e,r,r+6),this.words[i]|=n<>>26-a&4194303,(a+=24)>=26&&(a-=26,i++);r+6!==t&&(n=s(e,t,r+6),this.words[i]|=n<>>26-a&4194303),this.strip()},a.prototype._parseBase=function(e,t,r){this.words=[0],this.length=1;for(var i=0,n=1;n<=67108863;n*=t)i++;i--,n=n/t|0;for(var a=e.length-r,o=a%i,s=Math.min(a,a-o)+r,u=0,l=r;l1&&0===this.words[this.length-1];)this.length--;return this._normSign()},a.prototype._normSign=function(){return 1===this.length&&0===this.words[0]&&(this.negative=0),this},a.prototype.inspect=function(){return(this.red?""};var u=["","0","00","000","0000","00000","000000","0000000","00000000","000000000","0000000000","00000000000","000000000000","0000000000000","00000000000000","000000000000000","0000000000000000","00000000000000000","000000000000000000","0000000000000000000","00000000000000000000","000000000000000000000","0000000000000000000000","00000000000000000000000","000000000000000000000000","0000000000000000000000000"],l=[0,0,25,16,12,11,10,9,8,8,7,7,7,7,6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5],h=[0,0,33554432,43046721,16777216,48828125,60466176,40353607,16777216,43046721,1e7,19487171,35831808,62748517,7529536,11390625,16777216,24137569,34012224,47045881,64e6,4084101,5153632,6436343,7962624,9765625,11881376,14348907,17210368,20511149,243e5,28629151,33554432,39135393,45435424,52521875,60466176];function d(e,t,r){r.negative=t.negative^e.negative;var i=e.length+t.length|0;r.length=i,i=i-1|0;var n=0|e.words[0],a=0|t.words[0],o=n*a,s=67108863&o,c=o/67108864|0;r.words[0]=s;for(var u=1;u>>26,h=67108863&c,d=Math.min(u,t.length-1),p=Math.max(0,u-e.length+1);p<=d;p++){var f=u-p|0;l+=(o=(n=0|e.words[f])*(a=0|t.words[p])+h)/67108864|0,h=67108863&o}r.words[u]=0|h,c=0|l}return 0!==c?r.words[u]=0|c:r.length--,r.strip()}a.prototype.toString=function(e,t){var r;if(t=0|t||1,16===(e=e||10)||"hex"===e){r="";for(var n=0,a=0,o=0;o>>24-n&16777215)||o!==this.length-1?u[6-c.length]+c+r:c+r,(n+=2)>=26&&(n-=26,o--)}for(0!==a&&(r=a.toString(16)+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}if(e===(0|e)&&e>=2&&e<=36){var d=l[e],p=h[e];r="";var f=this.clone();for(f.negative=0;!f.isZero();){var m=f.modn(p).toString(e);r=(f=f.idivn(p)).isZero()?m+r:u[d-m.length]+m+r}for(this.isZero()&&(r="0"+r);r.length%t!=0;)r="0"+r;return 0!==this.negative&&(r="-"+r),r}i(!1,"Base should be between 2 and 36")},a.prototype.toNumber=function(){var e=this.words[0];return 2===this.length?e+=67108864*this.words[1]:3===this.length&&1===this.words[2]?e+=4503599627370496+67108864*this.words[1]:this.length>2&&i(!1,"Number can only safely store up to 53 bits"),0!==this.negative?-e:e},a.prototype.toJSON=function(){return this.toString(16)},a.prototype.toBuffer=function(e,t){return i(void 0!==o),this.toArrayLike(o,e,t)},a.prototype.toArray=function(e,t){return this.toArrayLike(Array,e,t)},a.prototype.toArrayLike=function(e,t,r){var n=this.byteLength(),a=r||Math.max(1,n);i(n<=a,"byte array longer than desired length"),i(a>0,"Requested array length <= 0"),this.strip();var o,s,c="le"===t,u=new e(a),l=this.clone();if(c){for(s=0;!l.isZero();s++)o=l.andln(255),l.iushrn(8),u[s]=o;for(;s=4096&&(r+=13,t>>>=13),t>=64&&(r+=7,t>>>=7),t>=8&&(r+=4,t>>>=4),t>=2&&(r+=2,t>>>=2),r+t},a.prototype._zeroBits=function(e){if(0===e)return 26;var t=e,r=0;return 0==(8191&t)&&(r+=13,t>>>=13),0==(127&t)&&(r+=7,t>>>=7),0==(15&t)&&(r+=4,t>>>=4),0==(3&t)&&(r+=2,t>>>=2),0==(1&t)&&r++,r},a.prototype.bitLength=function(){var e=this.words[this.length-1],t=this._countBits(e);return 26*(this.length-1)+t},a.prototype.zeroBits=function(){if(this.isZero())return 0;for(var e=0,t=0;te.length?this.clone().ior(e):e.clone().ior(this)},a.prototype.uor=function(e){return this.length>e.length?this.clone().iuor(e):e.clone().iuor(this)},a.prototype.iuand=function(e){var t;t=this.length>e.length?e:this;for(var r=0;re.length?this.clone().iand(e):e.clone().iand(this)},a.prototype.uand=function(e){return this.length>e.length?this.clone().iuand(e):e.clone().iuand(this)},a.prototype.iuxor=function(e){var t,r;this.length>e.length?(t=this,r=e):(t=e,r=this);for(var i=0;ie.length?this.clone().ixor(e):e.clone().ixor(this)},a.prototype.uxor=function(e){return this.length>e.length?this.clone().iuxor(e):e.clone().iuxor(this)},a.prototype.inotn=function(e){i("number"==typeof e&&e>=0);var t=0|Math.ceil(e/26),r=e%26;this._expand(t),r>0&&t--;for(var n=0;n0&&(this.words[n]=~this.words[n]&67108863>>26-r),this.strip()},a.prototype.notn=function(e){return this.clone().inotn(e)},a.prototype.setn=function(e,t){i("number"==typeof e&&e>=0);var r=e/26|0,n=e%26;return this._expand(r+1),this.words[r]=t?this.words[r]|1<e.length?(r=this,i=e):(r=e,i=this);for(var n=0,a=0;a>>26;for(;0!==n&&a>>26;if(this.length=r.length,0!==n)this.words[this.length]=n,this.length++;else if(r!==this)for(;ae.length?this.clone().iadd(e):e.clone().iadd(this)},a.prototype.isub=function(e){if(0!==e.negative){e.negative=0;var t=this.iadd(e);return e.negative=1,t._normSign()}if(0!==this.negative)return this.negative=0,this.iadd(e),this.negative=1,this._normSign();var r,i,n=this.cmp(e);if(0===n)return this.negative=0,this.length=1,this.words[0]=0,this;n>0?(r=this,i=e):(r=e,i=this);for(var a=0,o=0;o>26,this.words[o]=67108863&t;for(;0!==a&&o>26,this.words[o]=67108863&t;if(0===a&&o>>13,p=0|o[1],f=8191&p,m=p>>>13,g=0|o[2],_=8191&g,v=g>>>13,y=0|o[3],b=8191&y,E=y>>>13,w=0|o[4],S=8191&w,k=w>>>13,x=0|o[5],M=8191&x,N=x>>>13,j=0|o[6],T=8191&j,R=j>>>13,I=0|o[7],O=8191&I,A=I>>>13,P=0|o[8],D=8191&P,F=P>>>13,C=0|o[9],B=8191&C,z=C>>>13,L=0|s[0],U=8191&L,H=L>>>13,q=0|s[1],K=8191&q,Z=q>>>13,W=0|s[2],X=8191&W,Q=W>>>13,J=0|s[3],V=8191&J,G=J>>>13,Y=0|s[4],$=8191&Y,ee=Y>>>13,te=0|s[5],re=8191&te,ie=te>>>13,ne=0|s[6],ae=8191&ne,oe=ne>>>13,se=0|s[7],ce=8191&se,ue=se>>>13,le=0|s[8],he=8191&le,de=le>>>13,pe=0|s[9],fe=8191&pe,me=pe>>>13;r.negative=e.negative^t.negative,r.length=19;var ge=(u+(i=Math.imul(h,U))|0)+((8191&(n=(n=Math.imul(h,H))+Math.imul(d,U)|0))<<13)|0;u=((a=Math.imul(d,H))+(n>>>13)|0)+(ge>>>26)|0,ge&=67108863,i=Math.imul(f,U),n=(n=Math.imul(f,H))+Math.imul(m,U)|0,a=Math.imul(m,H);var _e=(u+(i=i+Math.imul(h,K)|0)|0)+((8191&(n=(n=n+Math.imul(h,Z)|0)+Math.imul(d,K)|0))<<13)|0;u=((a=a+Math.imul(d,Z)|0)+(n>>>13)|0)+(_e>>>26)|0,_e&=67108863,i=Math.imul(_,U),n=(n=Math.imul(_,H))+Math.imul(v,U)|0,a=Math.imul(v,H),i=i+Math.imul(f,K)|0,n=(n=n+Math.imul(f,Z)|0)+Math.imul(m,K)|0,a=a+Math.imul(m,Z)|0;var ve=(u+(i=i+Math.imul(h,X)|0)|0)+((8191&(n=(n=n+Math.imul(h,Q)|0)+Math.imul(d,X)|0))<<13)|0;u=((a=a+Math.imul(d,Q)|0)+(n>>>13)|0)+(ve>>>26)|0,ve&=67108863,i=Math.imul(b,U),n=(n=Math.imul(b,H))+Math.imul(E,U)|0,a=Math.imul(E,H),i=i+Math.imul(_,K)|0,n=(n=n+Math.imul(_,Z)|0)+Math.imul(v,K)|0,a=a+Math.imul(v,Z)|0,i=i+Math.imul(f,X)|0,n=(n=n+Math.imul(f,Q)|0)+Math.imul(m,X)|0,a=a+Math.imul(m,Q)|0;var ye=(u+(i=i+Math.imul(h,V)|0)|0)+((8191&(n=(n=n+Math.imul(h,G)|0)+Math.imul(d,V)|0))<<13)|0;u=((a=a+Math.imul(d,G)|0)+(n>>>13)|0)+(ye>>>26)|0,ye&=67108863,i=Math.imul(S,U),n=(n=Math.imul(S,H))+Math.imul(k,U)|0,a=Math.imul(k,H),i=i+Math.imul(b,K)|0,n=(n=n+Math.imul(b,Z)|0)+Math.imul(E,K)|0,a=a+Math.imul(E,Z)|0,i=i+Math.imul(_,X)|0,n=(n=n+Math.imul(_,Q)|0)+Math.imul(v,X)|0,a=a+Math.imul(v,Q)|0,i=i+Math.imul(f,V)|0,n=(n=n+Math.imul(f,G)|0)+Math.imul(m,V)|0,a=a+Math.imul(m,G)|0;var be=(u+(i=i+Math.imul(h,$)|0)|0)+((8191&(n=(n=n+Math.imul(h,ee)|0)+Math.imul(d,$)|0))<<13)|0;u=((a=a+Math.imul(d,ee)|0)+(n>>>13)|0)+(be>>>26)|0,be&=67108863,i=Math.imul(M,U),n=(n=Math.imul(M,H))+Math.imul(N,U)|0,a=Math.imul(N,H),i=i+Math.imul(S,K)|0,n=(n=n+Math.imul(S,Z)|0)+Math.imul(k,K)|0,a=a+Math.imul(k,Z)|0,i=i+Math.imul(b,X)|0,n=(n=n+Math.imul(b,Q)|0)+Math.imul(E,X)|0,a=a+Math.imul(E,Q)|0,i=i+Math.imul(_,V)|0,n=(n=n+Math.imul(_,G)|0)+Math.imul(v,V)|0,a=a+Math.imul(v,G)|0,i=i+Math.imul(f,$)|0,n=(n=n+Math.imul(f,ee)|0)+Math.imul(m,$)|0,a=a+Math.imul(m,ee)|0;var Ee=(u+(i=i+Math.imul(h,re)|0)|0)+((8191&(n=(n=n+Math.imul(h,ie)|0)+Math.imul(d,re)|0))<<13)|0;u=((a=a+Math.imul(d,ie)|0)+(n>>>13)|0)+(Ee>>>26)|0,Ee&=67108863,i=Math.imul(T,U),n=(n=Math.imul(T,H))+Math.imul(R,U)|0,a=Math.imul(R,H),i=i+Math.imul(M,K)|0,n=(n=n+Math.imul(M,Z)|0)+Math.imul(N,K)|0,a=a+Math.imul(N,Z)|0,i=i+Math.imul(S,X)|0,n=(n=n+Math.imul(S,Q)|0)+Math.imul(k,X)|0,a=a+Math.imul(k,Q)|0,i=i+Math.imul(b,V)|0,n=(n=n+Math.imul(b,G)|0)+Math.imul(E,V)|0,a=a+Math.imul(E,G)|0,i=i+Math.imul(_,$)|0,n=(n=n+Math.imul(_,ee)|0)+Math.imul(v,$)|0,a=a+Math.imul(v,ee)|0,i=i+Math.imul(f,re)|0,n=(n=n+Math.imul(f,ie)|0)+Math.imul(m,re)|0,a=a+Math.imul(m,ie)|0;var we=(u+(i=i+Math.imul(h,ae)|0)|0)+((8191&(n=(n=n+Math.imul(h,oe)|0)+Math.imul(d,ae)|0))<<13)|0;u=((a=a+Math.imul(d,oe)|0)+(n>>>13)|0)+(we>>>26)|0,we&=67108863,i=Math.imul(O,U),n=(n=Math.imul(O,H))+Math.imul(A,U)|0,a=Math.imul(A,H),i=i+Math.imul(T,K)|0,n=(n=n+Math.imul(T,Z)|0)+Math.imul(R,K)|0,a=a+Math.imul(R,Z)|0,i=i+Math.imul(M,X)|0,n=(n=n+Math.imul(M,Q)|0)+Math.imul(N,X)|0,a=a+Math.imul(N,Q)|0,i=i+Math.imul(S,V)|0,n=(n=n+Math.imul(S,G)|0)+Math.imul(k,V)|0,a=a+Math.imul(k,G)|0,i=i+Math.imul(b,$)|0,n=(n=n+Math.imul(b,ee)|0)+Math.imul(E,$)|0,a=a+Math.imul(E,ee)|0,i=i+Math.imul(_,re)|0,n=(n=n+Math.imul(_,ie)|0)+Math.imul(v,re)|0,a=a+Math.imul(v,ie)|0,i=i+Math.imul(f,ae)|0,n=(n=n+Math.imul(f,oe)|0)+Math.imul(m,ae)|0,a=a+Math.imul(m,oe)|0;var Se=(u+(i=i+Math.imul(h,ce)|0)|0)+((8191&(n=(n=n+Math.imul(h,ue)|0)+Math.imul(d,ce)|0))<<13)|0;u=((a=a+Math.imul(d,ue)|0)+(n>>>13)|0)+(Se>>>26)|0,Se&=67108863,i=Math.imul(D,U),n=(n=Math.imul(D,H))+Math.imul(F,U)|0,a=Math.imul(F,H),i=i+Math.imul(O,K)|0,n=(n=n+Math.imul(O,Z)|0)+Math.imul(A,K)|0,a=a+Math.imul(A,Z)|0,i=i+Math.imul(T,X)|0,n=(n=n+Math.imul(T,Q)|0)+Math.imul(R,X)|0,a=a+Math.imul(R,Q)|0,i=i+Math.imul(M,V)|0,n=(n=n+Math.imul(M,G)|0)+Math.imul(N,V)|0,a=a+Math.imul(N,G)|0,i=i+Math.imul(S,$)|0,n=(n=n+Math.imul(S,ee)|0)+Math.imul(k,$)|0,a=a+Math.imul(k,ee)|0,i=i+Math.imul(b,re)|0,n=(n=n+Math.imul(b,ie)|0)+Math.imul(E,re)|0,a=a+Math.imul(E,ie)|0,i=i+Math.imul(_,ae)|0,n=(n=n+Math.imul(_,oe)|0)+Math.imul(v,ae)|0,a=a+Math.imul(v,oe)|0,i=i+Math.imul(f,ce)|0,n=(n=n+Math.imul(f,ue)|0)+Math.imul(m,ce)|0,a=a+Math.imul(m,ue)|0;var ke=(u+(i=i+Math.imul(h,he)|0)|0)+((8191&(n=(n=n+Math.imul(h,de)|0)+Math.imul(d,he)|0))<<13)|0;u=((a=a+Math.imul(d,de)|0)+(n>>>13)|0)+(ke>>>26)|0,ke&=67108863,i=Math.imul(B,U),n=(n=Math.imul(B,H))+Math.imul(z,U)|0,a=Math.imul(z,H),i=i+Math.imul(D,K)|0,n=(n=n+Math.imul(D,Z)|0)+Math.imul(F,K)|0,a=a+Math.imul(F,Z)|0,i=i+Math.imul(O,X)|0,n=(n=n+Math.imul(O,Q)|0)+Math.imul(A,X)|0,a=a+Math.imul(A,Q)|0,i=i+Math.imul(T,V)|0,n=(n=n+Math.imul(T,G)|0)+Math.imul(R,V)|0,a=a+Math.imul(R,G)|0,i=i+Math.imul(M,$)|0,n=(n=n+Math.imul(M,ee)|0)+Math.imul(N,$)|0,a=a+Math.imul(N,ee)|0,i=i+Math.imul(S,re)|0,n=(n=n+Math.imul(S,ie)|0)+Math.imul(k,re)|0,a=a+Math.imul(k,ie)|0,i=i+Math.imul(b,ae)|0,n=(n=n+Math.imul(b,oe)|0)+Math.imul(E,ae)|0,a=a+Math.imul(E,oe)|0,i=i+Math.imul(_,ce)|0,n=(n=n+Math.imul(_,ue)|0)+Math.imul(v,ce)|0,a=a+Math.imul(v,ue)|0,i=i+Math.imul(f,he)|0,n=(n=n+Math.imul(f,de)|0)+Math.imul(m,he)|0,a=a+Math.imul(m,de)|0;var xe=(u+(i=i+Math.imul(h,fe)|0)|0)+((8191&(n=(n=n+Math.imul(h,me)|0)+Math.imul(d,fe)|0))<<13)|0;u=((a=a+Math.imul(d,me)|0)+(n>>>13)|0)+(xe>>>26)|0,xe&=67108863,i=Math.imul(B,K),n=(n=Math.imul(B,Z))+Math.imul(z,K)|0,a=Math.imul(z,Z),i=i+Math.imul(D,X)|0,n=(n=n+Math.imul(D,Q)|0)+Math.imul(F,X)|0,a=a+Math.imul(F,Q)|0,i=i+Math.imul(O,V)|0,n=(n=n+Math.imul(O,G)|0)+Math.imul(A,V)|0,a=a+Math.imul(A,G)|0,i=i+Math.imul(T,$)|0,n=(n=n+Math.imul(T,ee)|0)+Math.imul(R,$)|0,a=a+Math.imul(R,ee)|0,i=i+Math.imul(M,re)|0,n=(n=n+Math.imul(M,ie)|0)+Math.imul(N,re)|0,a=a+Math.imul(N,ie)|0,i=i+Math.imul(S,ae)|0,n=(n=n+Math.imul(S,oe)|0)+Math.imul(k,ae)|0,a=a+Math.imul(k,oe)|0,i=i+Math.imul(b,ce)|0,n=(n=n+Math.imul(b,ue)|0)+Math.imul(E,ce)|0,a=a+Math.imul(E,ue)|0,i=i+Math.imul(_,he)|0,n=(n=n+Math.imul(_,de)|0)+Math.imul(v,he)|0,a=a+Math.imul(v,de)|0;var Me=(u+(i=i+Math.imul(f,fe)|0)|0)+((8191&(n=(n=n+Math.imul(f,me)|0)+Math.imul(m,fe)|0))<<13)|0;u=((a=a+Math.imul(m,me)|0)+(n>>>13)|0)+(Me>>>26)|0,Me&=67108863,i=Math.imul(B,X),n=(n=Math.imul(B,Q))+Math.imul(z,X)|0,a=Math.imul(z,Q),i=i+Math.imul(D,V)|0,n=(n=n+Math.imul(D,G)|0)+Math.imul(F,V)|0,a=a+Math.imul(F,G)|0,i=i+Math.imul(O,$)|0,n=(n=n+Math.imul(O,ee)|0)+Math.imul(A,$)|0,a=a+Math.imul(A,ee)|0,i=i+Math.imul(T,re)|0,n=(n=n+Math.imul(T,ie)|0)+Math.imul(R,re)|0,a=a+Math.imul(R,ie)|0,i=i+Math.imul(M,ae)|0,n=(n=n+Math.imul(M,oe)|0)+Math.imul(N,ae)|0,a=a+Math.imul(N,oe)|0,i=i+Math.imul(S,ce)|0,n=(n=n+Math.imul(S,ue)|0)+Math.imul(k,ce)|0,a=a+Math.imul(k,ue)|0,i=i+Math.imul(b,he)|0,n=(n=n+Math.imul(b,de)|0)+Math.imul(E,he)|0,a=a+Math.imul(E,de)|0;var Ne=(u+(i=i+Math.imul(_,fe)|0)|0)+((8191&(n=(n=n+Math.imul(_,me)|0)+Math.imul(v,fe)|0))<<13)|0;u=((a=a+Math.imul(v,me)|0)+(n>>>13)|0)+(Ne>>>26)|0,Ne&=67108863,i=Math.imul(B,V),n=(n=Math.imul(B,G))+Math.imul(z,V)|0,a=Math.imul(z,G),i=i+Math.imul(D,$)|0,n=(n=n+Math.imul(D,ee)|0)+Math.imul(F,$)|0,a=a+Math.imul(F,ee)|0,i=i+Math.imul(O,re)|0,n=(n=n+Math.imul(O,ie)|0)+Math.imul(A,re)|0,a=a+Math.imul(A,ie)|0,i=i+Math.imul(T,ae)|0,n=(n=n+Math.imul(T,oe)|0)+Math.imul(R,ae)|0,a=a+Math.imul(R,oe)|0,i=i+Math.imul(M,ce)|0,n=(n=n+Math.imul(M,ue)|0)+Math.imul(N,ce)|0,a=a+Math.imul(N,ue)|0,i=i+Math.imul(S,he)|0,n=(n=n+Math.imul(S,de)|0)+Math.imul(k,he)|0,a=a+Math.imul(k,de)|0;var je=(u+(i=i+Math.imul(b,fe)|0)|0)+((8191&(n=(n=n+Math.imul(b,me)|0)+Math.imul(E,fe)|0))<<13)|0;u=((a=a+Math.imul(E,me)|0)+(n>>>13)|0)+(je>>>26)|0,je&=67108863,i=Math.imul(B,$),n=(n=Math.imul(B,ee))+Math.imul(z,$)|0,a=Math.imul(z,ee),i=i+Math.imul(D,re)|0,n=(n=n+Math.imul(D,ie)|0)+Math.imul(F,re)|0,a=a+Math.imul(F,ie)|0,i=i+Math.imul(O,ae)|0,n=(n=n+Math.imul(O,oe)|0)+Math.imul(A,ae)|0,a=a+Math.imul(A,oe)|0,i=i+Math.imul(T,ce)|0,n=(n=n+Math.imul(T,ue)|0)+Math.imul(R,ce)|0,a=a+Math.imul(R,ue)|0,i=i+Math.imul(M,he)|0,n=(n=n+Math.imul(M,de)|0)+Math.imul(N,he)|0,a=a+Math.imul(N,de)|0;var Te=(u+(i=i+Math.imul(S,fe)|0)|0)+((8191&(n=(n=n+Math.imul(S,me)|0)+Math.imul(k,fe)|0))<<13)|0;u=((a=a+Math.imul(k,me)|0)+(n>>>13)|0)+(Te>>>26)|0,Te&=67108863,i=Math.imul(B,re),n=(n=Math.imul(B,ie))+Math.imul(z,re)|0,a=Math.imul(z,ie),i=i+Math.imul(D,ae)|0,n=(n=n+Math.imul(D,oe)|0)+Math.imul(F,ae)|0,a=a+Math.imul(F,oe)|0,i=i+Math.imul(O,ce)|0,n=(n=n+Math.imul(O,ue)|0)+Math.imul(A,ce)|0,a=a+Math.imul(A,ue)|0,i=i+Math.imul(T,he)|0,n=(n=n+Math.imul(T,de)|0)+Math.imul(R,he)|0,a=a+Math.imul(R,de)|0;var Re=(u+(i=i+Math.imul(M,fe)|0)|0)+((8191&(n=(n=n+Math.imul(M,me)|0)+Math.imul(N,fe)|0))<<13)|0;u=((a=a+Math.imul(N,me)|0)+(n>>>13)|0)+(Re>>>26)|0,Re&=67108863,i=Math.imul(B,ae),n=(n=Math.imul(B,oe))+Math.imul(z,ae)|0,a=Math.imul(z,oe),i=i+Math.imul(D,ce)|0,n=(n=n+Math.imul(D,ue)|0)+Math.imul(F,ce)|0,a=a+Math.imul(F,ue)|0,i=i+Math.imul(O,he)|0,n=(n=n+Math.imul(O,de)|0)+Math.imul(A,he)|0,a=a+Math.imul(A,de)|0;var Ie=(u+(i=i+Math.imul(T,fe)|0)|0)+((8191&(n=(n=n+Math.imul(T,me)|0)+Math.imul(R,fe)|0))<<13)|0;u=((a=a+Math.imul(R,me)|0)+(n>>>13)|0)+(Ie>>>26)|0,Ie&=67108863,i=Math.imul(B,ce),n=(n=Math.imul(B,ue))+Math.imul(z,ce)|0,a=Math.imul(z,ue),i=i+Math.imul(D,he)|0,n=(n=n+Math.imul(D,de)|0)+Math.imul(F,he)|0,a=a+Math.imul(F,de)|0;var Oe=(u+(i=i+Math.imul(O,fe)|0)|0)+((8191&(n=(n=n+Math.imul(O,me)|0)+Math.imul(A,fe)|0))<<13)|0;u=((a=a+Math.imul(A,me)|0)+(n>>>13)|0)+(Oe>>>26)|0,Oe&=67108863,i=Math.imul(B,he),n=(n=Math.imul(B,de))+Math.imul(z,he)|0,a=Math.imul(z,de);var Ae=(u+(i=i+Math.imul(D,fe)|0)|0)+((8191&(n=(n=n+Math.imul(D,me)|0)+Math.imul(F,fe)|0))<<13)|0;u=((a=a+Math.imul(F,me)|0)+(n>>>13)|0)+(Ae>>>26)|0,Ae&=67108863;var Pe=(u+(i=Math.imul(B,fe))|0)+((8191&(n=(n=Math.imul(B,me))+Math.imul(z,fe)|0))<<13)|0;return u=((a=Math.imul(z,me))+(n>>>13)|0)+(Pe>>>26)|0,Pe&=67108863,c[0]=ge,c[1]=_e,c[2]=ve,c[3]=ye,c[4]=be,c[5]=Ee,c[6]=we,c[7]=Se,c[8]=ke,c[9]=xe,c[10]=Me,c[11]=Ne,c[12]=je,c[13]=Te,c[14]=Re,c[15]=Ie,c[16]=Oe,c[17]=Ae,c[18]=Pe,0!==u&&(c[19]=u,r.length++),r};function f(e,t,r){return(new m).mulp(e,t,r)}function m(e,t){this.x=e,this.y=t}Math.imul||(p=d),a.prototype.mulTo=function(e,t){var r=this.length+e.length;return 10===this.length&&10===e.length?p(this,e,t):r<63?d(this,e,t):r<1024?function(e,t,r){r.negative=t.negative^e.negative,r.length=e.length+t.length;for(var i=0,n=0,a=0;a>>26)|0)>>>26,o&=67108863}r.words[a]=s,i=o,o=n}return 0!==i?r.words[a]=i:r.length--,r.strip()}(this,e,t):f(this,e,t)},m.prototype.makeRBT=function(e){for(var t=new Array(e),r=a.prototype._countBits(e)-1,i=0;i>=1;return i},m.prototype.permute=function(e,t,r,i,n,a){for(var o=0;o>>=1)n++;return 1<>>=13,r[2*o+1]=8191&a,a>>>=13;for(o=2*t;o>=26,t+=n/67108864|0,t+=a>>>26,this.words[r]=67108863&a}return 0!==t&&(this.words[r]=t,this.length++),this},a.prototype.muln=function(e){return this.clone().imuln(e)},a.prototype.sqr=function(){return this.mul(this)},a.prototype.isqr=function(){return this.imul(this.clone())},a.prototype.pow=function(e){var t=function(e){for(var t=new Array(e.bitLength()),r=0;r>>n}return t}(e);if(0===t.length)return new a(1);for(var r=this,i=0;i=0);var t,r=e%26,n=(e-r)/26,a=67108863>>>26-r<<26-r;if(0!==r){var o=0;for(t=0;t>>26-r}o&&(this.words[t]=o,this.length++)}if(0!==n){for(t=this.length-1;t>=0;t--)this.words[t+n]=this.words[t];for(t=0;t=0),n=t?(t-t%26)/26:0;var a=e%26,o=Math.min((e-a)/26,this.length),s=67108863^67108863>>>a<o)for(this.length-=o,u=0;u=0&&(0!==l||u>=n);u--){var h=0|this.words[u];this.words[u]=l<<26-a|h>>>a,l=h&s}return c&&0!==l&&(c.words[c.length++]=l),0===this.length&&(this.words[0]=0,this.length=1),this.strip()},a.prototype.ishrn=function(e,t,r){return i(0===this.negative),this.iushrn(e,t,r)},a.prototype.shln=function(e){return this.clone().ishln(e)},a.prototype.ushln=function(e){return this.clone().iushln(e)},a.prototype.shrn=function(e){return this.clone().ishrn(e)},a.prototype.ushrn=function(e){return this.clone().iushrn(e)},a.prototype.testn=function(e){i("number"==typeof e&&e>=0);var t=e%26,r=(e-t)/26,n=1<=0);var t=e%26,r=(e-t)/26;if(i(0===this.negative,"imaskn works only with positive numbers"),this.length<=r)return this;if(0!==t&&r++,this.length=Math.min(r,this.length),0!==t){var n=67108863^67108863>>>t<=67108864;t++)this.words[t]-=67108864,t===this.length-1?this.words[t+1]=1:this.words[t+1]++;return this.length=Math.max(this.length,t+1),this},a.prototype.isubn=function(e){if(i("number"==typeof e),i(e<67108864),e<0)return this.iaddn(-e);if(0!==this.negative)return this.negative=0,this.iaddn(e),this.negative=1,this;if(this.words[0]-=e,1===this.length&&this.words[0]<0)this.words[0]=-this.words[0],this.negative=1;else for(var t=0;t>26)-(c/67108864|0),this.words[n+r]=67108863&a}for(;n>26,this.words[n+r]=67108863&a;if(0===s)return this.strip();for(i(-1===s),s=0,n=0;n>26,this.words[n]=67108863&a;return this.negative=1,this.strip()},a.prototype._wordDiv=function(e,t){var r=(this.length,e.length),i=this.clone(),n=e,o=0|n.words[n.length-1];0!==(r=26-this._countBits(o))&&(n=n.ushln(r),i.iushln(r),o=0|n.words[n.length-1]);var s,c=i.length-n.length;if("mod"!==t){(s=new a(null)).length=c+1,s.words=new Array(s.length);for(var u=0;u=0;h--){var d=67108864*(0|i.words[n.length+h])+(0|i.words[n.length+h-1]);for(d=Math.min(d/o|0,67108863),i._ishlnsubmul(n,d,h);0!==i.negative;)d--,i.negative=0,i._ishlnsubmul(n,1,h),i.isZero()||(i.negative^=1);s&&(s.words[h]=d)}return s&&s.strip(),i.strip(),"div"!==t&&0!==r&&i.iushrn(r),{div:s||null,mod:i}},a.prototype.divmod=function(e,t,r){return i(!e.isZero()),this.isZero()?{div:new a(0),mod:new a(0)}:0!==this.negative&&0===e.negative?(s=this.neg().divmod(e,t),"mod"!==t&&(n=s.div.neg()),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.iadd(e)),{div:n,mod:o}):0===this.negative&&0!==e.negative?(s=this.divmod(e.neg(),t),"mod"!==t&&(n=s.div.neg()),{div:n,mod:s.mod}):0!=(this.negative&e.negative)?(s=this.neg().divmod(e.neg(),t),"div"!==t&&(o=s.mod.neg(),r&&0!==o.negative&&o.isub(e)),{div:s.div,mod:o}):e.length>this.length||this.cmp(e)<0?{div:new a(0),mod:this}:1===e.length?"div"===t?{div:this.divn(e.words[0]),mod:null}:"mod"===t?{div:null,mod:new a(this.modn(e.words[0]))}:{div:this.divn(e.words[0]),mod:new a(this.modn(e.words[0]))}:this._wordDiv(e,t);var n,o,s},a.prototype.div=function(e){return this.divmod(e,"div",!1).div},a.prototype.mod=function(e){return this.divmod(e,"mod",!1).mod},a.prototype.umod=function(e){return this.divmod(e,"mod",!0).mod},a.prototype.divRound=function(e){var t=this.divmod(e);if(t.mod.isZero())return t.div;var r=0!==t.div.negative?t.mod.isub(e):t.mod,i=e.ushrn(1),n=e.andln(1),a=r.cmp(i);return a<0||1===n&&0===a?t.div:0!==t.div.negative?t.div.isubn(1):t.div.iaddn(1)},a.prototype.modn=function(e){i(e<=67108863);for(var t=(1<<26)%e,r=0,n=this.length-1;n>=0;n--)r=(t*r+(0|this.words[n]))%e;return r},a.prototype.idivn=function(e){i(e<=67108863);for(var t=0,r=this.length-1;r>=0;r--){var n=(0|this.words[r])+67108864*t;this.words[r]=n/e|0,t=n%e}return this.strip()},a.prototype.divn=function(e){return this.clone().idivn(e)},a.prototype.egcd=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n=new a(1),o=new a(0),s=new a(0),c=new a(1),u=0;t.isEven()&&r.isEven();)t.iushrn(1),r.iushrn(1),++u;for(var l=r.clone(),h=t.clone();!t.isZero();){for(var d=0,p=1;0==(t.words[0]&p)&&d<26;++d,p<<=1);if(d>0)for(t.iushrn(d);d-- >0;)(n.isOdd()||o.isOdd())&&(n.iadd(l),o.isub(h)),n.iushrn(1),o.iushrn(1);for(var f=0,m=1;0==(r.words[0]&m)&&f<26;++f,m<<=1);if(f>0)for(r.iushrn(f);f-- >0;)(s.isOdd()||c.isOdd())&&(s.iadd(l),c.isub(h)),s.iushrn(1),c.iushrn(1);t.cmp(r)>=0?(t.isub(r),n.isub(s),o.isub(c)):(r.isub(t),s.isub(n),c.isub(o))}return{a:s,b:c,gcd:r.iushln(u)}},a.prototype._invmp=function(e){i(0===e.negative),i(!e.isZero());var t=this,r=e.clone();t=0!==t.negative?t.umod(e):t.clone();for(var n,o=new a(1),s=new a(0),c=r.clone();t.cmpn(1)>0&&r.cmpn(1)>0;){for(var u=0,l=1;0==(t.words[0]&l)&&u<26;++u,l<<=1);if(u>0)for(t.iushrn(u);u-- >0;)o.isOdd()&&o.iadd(c),o.iushrn(1);for(var h=0,d=1;0==(r.words[0]&d)&&h<26;++h,d<<=1);if(h>0)for(r.iushrn(h);h-- >0;)s.isOdd()&&s.iadd(c),s.iushrn(1);t.cmp(r)>=0?(t.isub(r),o.isub(s)):(r.isub(t),s.isub(o))}return(n=0===t.cmpn(1)?o:s).cmpn(0)<0&&n.iadd(e),n},a.prototype.gcd=function(e){if(this.isZero())return e.abs();if(e.isZero())return this.abs();var t=this.clone(),r=e.clone();t.negative=0,r.negative=0;for(var i=0;t.isEven()&&r.isEven();i++)t.iushrn(1),r.iushrn(1);for(;;){for(;t.isEven();)t.iushrn(1);for(;r.isEven();)r.iushrn(1);var n=t.cmp(r);if(n<0){var a=t;t=r,r=a}else if(0===n||0===r.cmpn(1))break;t.isub(r)}return r.iushln(i)},a.prototype.invm=function(e){return this.egcd(e).a.umod(e)},a.prototype.isEven=function(){return 0==(1&this.words[0])},a.prototype.isOdd=function(){return 1==(1&this.words[0])},a.prototype.andln=function(e){return this.words[0]&e},a.prototype.bincn=function(e){i("number"==typeof e);var t=e%26,r=(e-t)/26,n=1<>>26,s&=67108863,this.words[o]=s}return 0!==a&&(this.words[o]=a,this.length++),this},a.prototype.isZero=function(){return 1===this.length&&0===this.words[0]},a.prototype.cmpn=function(e){var t,r=e<0;if(0!==this.negative&&!r)return-1;if(0===this.negative&&r)return 1;if(this.strip(),this.length>1)t=1;else{r&&(e=-e),i(e<=67108863,"Number is too big");var n=0|this.words[0];t=n===e?0:ne.length)return 1;if(this.length=0;r--){var i=0|this.words[r],n=0|e.words[r];if(i!==n){in&&(t=1);break}}return t},a.prototype.gtn=function(e){return 1===this.cmpn(e)},a.prototype.gt=function(e){return 1===this.cmp(e)},a.prototype.gten=function(e){return this.cmpn(e)>=0},a.prototype.gte=function(e){return this.cmp(e)>=0},a.prototype.ltn=function(e){return-1===this.cmpn(e)},a.prototype.lt=function(e){return-1===this.cmp(e)},a.prototype.lten=function(e){return this.cmpn(e)<=0},a.prototype.lte=function(e){return this.cmp(e)<=0},a.prototype.eqn=function(e){return 0===this.cmpn(e)},a.prototype.eq=function(e){return 0===this.cmp(e)},a.red=function(e){return new w(e)},a.prototype.toRed=function(e){return i(!this.red,"Already a number in reduction context"),i(0===this.negative,"red works only with positives"),e.convertTo(this)._forceRed(e)},a.prototype.fromRed=function(){return i(this.red,"fromRed works only with numbers in reduction context"),this.red.convertFrom(this)},a.prototype._forceRed=function(e){return this.red=e,this},a.prototype.forceRed=function(e){return i(!this.red,"Already a number in reduction context"),this._forceRed(e)},a.prototype.redAdd=function(e){return i(this.red,"redAdd works only with red numbers"),this.red.add(this,e)},a.prototype.redIAdd=function(e){return i(this.red,"redIAdd works only with red numbers"),this.red.iadd(this,e)},a.prototype.redSub=function(e){return i(this.red,"redSub works only with red numbers"),this.red.sub(this,e)},a.prototype.redISub=function(e){return i(this.red,"redISub works only with red numbers"),this.red.isub(this,e)},a.prototype.redShl=function(e){return i(this.red,"redShl works only with red numbers"),this.red.shl(this,e)},a.prototype.redMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.mul(this,e)},a.prototype.redIMul=function(e){return i(this.red,"redMul works only with red numbers"),this.red._verify2(this,e),this.red.imul(this,e)},a.prototype.redSqr=function(){return i(this.red,"redSqr works only with red numbers"),this.red._verify1(this),this.red.sqr(this)},a.prototype.redISqr=function(){return i(this.red,"redISqr works only with red numbers"),this.red._verify1(this),this.red.isqr(this)},a.prototype.redSqrt=function(){return i(this.red,"redSqrt works only with red numbers"),this.red._verify1(this),this.red.sqrt(this)},a.prototype.redInvm=function(){return i(this.red,"redInvm works only with red numbers"),this.red._verify1(this),this.red.invm(this)},a.prototype.redNeg=function(){return i(this.red,"redNeg works only with red numbers"),this.red._verify1(this),this.red.neg(this)},a.prototype.redPow=function(e){return i(this.red&&!e.red,"redPow(normalNum)"),this.red._verify1(this),this.red.pow(this,e)};var g={k256:null,p224:null,p192:null,p25519:null};function _(e,t){this.name=e,this.p=new a(t,16),this.n=this.p.bitLength(),this.k=new a(1).iushln(this.n).isub(this.p),this.tmp=this._tmp()}function v(){_.call(this,"k256","ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f")}function y(){_.call(this,"p224","ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001")}function b(){_.call(this,"p192","ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff")}function E(){_.call(this,"25519","7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed")}function w(e){if("string"==typeof e){var t=a._prime(e);this.m=t.p,this.prime=t}else i(e.gtn(1),"modulus must be greater than 1"),this.m=e,this.prime=null}function S(e){w.call(this,e),this.shift=this.m.bitLength(),this.shift%26!=0&&(this.shift+=26-this.shift%26),this.r=new a(1).iushln(this.shift),this.r2=this.imod(this.r.sqr()),this.rinv=this.r._invmp(this.m),this.minv=this.rinv.mul(this.r).isubn(1).div(this.m),this.minv=this.minv.umod(this.r),this.minv=this.r.sub(this.minv)}_.prototype._tmp=function(){var e=new a(null);return e.words=new Array(Math.ceil(this.n/13)),e},_.prototype.ireduce=function(e){var t,r=e;do{this.split(r,this.tmp),t=(r=(r=this.imulK(r)).iadd(this.tmp)).bitLength()}while(t>this.n);var i=t0?r.isub(this.p):r.strip(),r},_.prototype.split=function(e,t){e.iushrn(this.n,0,t)},_.prototype.imulK=function(e){return e.imul(this.k)},n(v,_),v.prototype.split=function(e,t){for(var r=Math.min(e.length,9),i=0;i>>22,n=a}n>>>=22,e.words[i-10]=n,0===n&&e.length>10?e.length-=10:e.length-=9},v.prototype.imulK=function(e){e.words[e.length]=0,e.words[e.length+1]=0,e.length+=2;for(var t=0,r=0;r>>=26,e.words[r]=n,t=i}return 0!==t&&(e.words[e.length++]=t),e},a._prime=function(e){if(g[e])return g[e];var t;if("k256"===e)t=new v;else if("p224"===e)t=new y;else if("p192"===e)t=new b;else{if("p25519"!==e)throw new Error("Unknown prime "+e);t=new E}return g[e]=t,t},w.prototype._verify1=function(e){i(0===e.negative,"red works only with positives"),i(e.red,"red works only with red numbers")},w.prototype._verify2=function(e,t){i(0==(e.negative|t.negative),"red works only with positives"),i(e.red&&e.red===t.red,"red works only with red numbers")},w.prototype.imod=function(e){return this.prime?this.prime.ireduce(e)._forceRed(this):e.umod(this.m)._forceRed(this)},w.prototype.neg=function(e){return e.isZero()?e.clone():this.m.sub(e)._forceRed(this)},w.prototype.add=function(e,t){this._verify2(e,t);var r=e.add(t);return r.cmp(this.m)>=0&&r.isub(this.m),r._forceRed(this)},w.prototype.iadd=function(e,t){this._verify2(e,t);var r=e.iadd(t);return r.cmp(this.m)>=0&&r.isub(this.m),r},w.prototype.sub=function(e,t){this._verify2(e,t);var r=e.sub(t);return r.cmpn(0)<0&&r.iadd(this.m),r._forceRed(this)},w.prototype.isub=function(e,t){this._verify2(e,t);var r=e.isub(t);return r.cmpn(0)<0&&r.iadd(this.m),r},w.prototype.shl=function(e,t){return this._verify1(e),this.imod(e.ushln(t))},w.prototype.imul=function(e,t){return this._verify2(e,t),this.imod(e.imul(t))},w.prototype.mul=function(e,t){return this._verify2(e,t),this.imod(e.mul(t))},w.prototype.isqr=function(e){return this.imul(e,e.clone())},w.prototype.sqr=function(e){return this.mul(e,e)},w.prototype.sqrt=function(e){if(e.isZero())return e.clone();var t=this.m.andln(3);if(i(t%2==1),3===t){var r=this.m.add(new a(1)).iushrn(2);return this.pow(e,r)}for(var n=this.m.subn(1),o=0;!n.isZero()&&0===n.andln(1);)o++,n.iushrn(1);i(!n.isZero());var s=new a(1).toRed(this),c=s.redNeg(),u=this.m.subn(1).iushrn(1),l=this.m.bitLength();for(l=new a(2*l*l).toRed(this);0!==this.pow(l,u).cmp(c);)l.redIAdd(c);for(var h=this.pow(l,n),d=this.pow(e,n.addn(1).iushrn(1)),p=this.pow(e,n),f=o;0!==p.cmp(s);){for(var m=p,g=0;0!==m.cmp(s);g++)m=m.redSqr();i(g=0;i--){for(var u=t.words[i],l=c-1;l>=0;l--){var h=u>>l&1;n!==r[0]&&(n=this.sqr(n)),0!==h||0!==o?(o<<=1,o|=h,(4===++s||0===i&&0===l)&&(n=this.mul(n,r[o]),s=0,o=0)):s=0}c=26}return n},w.prototype.convertTo=function(e){var t=e.umod(this.m);return t===e?t.clone():t},w.prototype.convertFrom=function(e){var t=e.clone();return t.red=null,t},a.mont=function(e){return new S(e)},n(S,w),S.prototype.convertTo=function(e){return this.imod(e.ushln(this.shift))},S.prototype.convertFrom=function(e){var t=this.imod(e.mul(this.rinv));return t.red=null,t},S.prototype.imul=function(e,t){if(e.isZero()||t.isZero())return e.words[0]=0,e.length=1,e;var r=e.imul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),a=n;return n.cmp(this.m)>=0?a=n.isub(this.m):n.cmpn(0)<0&&(a=n.iadd(this.m)),a._forceRed(this)},S.prototype.mul=function(e,t){if(e.isZero()||t.isZero())return new a(0)._forceRed(this);var r=e.mul(t),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),o=n;return n.cmp(this.m)>=0?o=n.isub(this.m):n.cmpn(0)<0&&(o=n.iadd(this.m)),o._forceRed(this)},S.prototype.invm=function(e){return this.imod(e._invmp(this.m).mul(this.r2))._forceRed(this)}}(e,this)}).call(this,r(22)(e))},function(e,t){},function(e,t,r){t.publicEncrypt=r(373),t.privateDecrypt=r(375),t.privateEncrypt=function(e,r){return t.publicEncrypt(e,r,!0)},t.publicDecrypt=function(e,r){return t.privateDecrypt(e,r,!0)}},function(e,t,r){var i=r(82),n=r(44),a=r(61),o=r(201),s=r(202),c=r(120),u=r(203),l=r(116),h=r(1).Buffer;e.exports=function(e,t,r){var d;d=e.padding?e.padding:r?1:4;var p,f=i(e);if(4===d)p=function(e,t){var r=e.modulus.byteLength(),i=t.length,u=a("sha1").update(h.alloc(0)).digest(),l=u.length,d=2*l;if(i>r-d-2)throw new Error("message too long");var p=h.alloc(r-i-d-2),f=r-l-1,m=n(l),g=s(h.concat([u,p,h.alloc(1,1),t],f),o(m,f)),_=s(m,o(g,l));return new c(h.concat([h.alloc(1),_,g],r))}(f,t);else if(1===d)p=function(e,t,r){var i,a=t.length,o=e.modulus.byteLength();if(a>o-11)throw new Error("message too long");i=r?h.alloc(o-a-3,255):function(e){var t,r=h.allocUnsafe(e),i=0,a=n(2*e),o=0;for(;i=0)throw new Error("data too long for modulus")}return r?l(p,f):u(p,f)}},function(e,t){},function(e,t,r){var i=r(82),n=r(201),a=r(202),o=r(120),s=r(116),c=r(61),u=r(203),l=r(1).Buffer;e.exports=function(e,t,r){var h;h=e.padding?e.padding:r?1:4;var d,p=i(e),f=p.modulus.byteLength();if(t.length>f||new o(t).cmp(p.modulus)>=0)throw new Error("decryption error");d=r?u(new o(t),p):s(t,p);var m=l.alloc(f-d.length);if(d=l.concat([m,d],f),4===h)return function(e,t){var r=e.modulus.byteLength(),i=c("sha1").update(l.alloc(0)).digest(),o=i.length;if(0!==t[0])throw new Error("decryption error");var s=t.slice(1,o+1),u=t.slice(o+1),h=a(s,n(u,o)),d=a(u,n(h,r-o-1));if(function(e,t){e=l.from(e),t=l.from(t);var r=0,i=e.length;e.length!==t.length&&(r++,i=Math.min(e.length,t.length));var n=-1;for(;++n=t.length){a++;break}var o=t.slice(2,n-1);("0002"!==i.toString("hex")&&!r||"0001"!==i.toString("hex")&&r)&&a++;o.length<8&&a++;if(a)throw new Error("decryption error");return t.slice(n)}(0,d,r);if(3===h)return d;throw new Error("unknown padding")}},function(e,t,r){"use strict";(function(e,i){function n(){throw new Error("secure random number generation not supported by this browser\nuse chrome, FireFox or Internet Explorer 11")}var a=r(1),o=r(44),s=a.Buffer,c=a.kMaxLength,u=e.crypto||e.msCrypto,l=Math.pow(2,32)-1;function h(e,t){if("number"!=typeof e||e!=e)throw new TypeError("offset must be a number");if(e>l||e<0)throw new TypeError("offset must be a uint32");if(e>c||e>t)throw new RangeError("offset out of range")}function d(e,t,r){if("number"!=typeof e||e!=e)throw new TypeError("size must be a number");if(e>l||e<0)throw new TypeError("size must be a uint32");if(e+t>r||e>c)throw new RangeError("buffer too small")}function p(e,t,r,n){if(i.browser){var a=e.buffer,s=new Uint8Array(a,t,r);return u.getRandomValues(s),n?void i.nextTick((function(){n(null,e)})):e}if(!n)return o(r).copy(e,t),e;o(r,(function(r,i){if(r)return n(r);i.copy(e,t),n(null,e)}))}u&&u.getRandomValues||!i.browser?(t.randomFill=function(t,r,i,n){if(!(s.isBuffer(t)||t instanceof e.Uint8Array))throw new TypeError('"buf" argument must be a Buffer or Uint8Array');if("function"==typeof r)n=r,r=0,i=t.length;else if("function"==typeof i)n=i,i=t.length-r;else if("function"!=typeof n)throw new TypeError('"cb" argument must be a function');return h(r,t.length),d(i,r,t.length),p(t,r,i,n)},t.randomFillSync=function(t,r,i){void 0===r&&(r=0);if(!(s.isBuffer(t)||t instanceof e.Uint8Array))throw new TypeError('"buf" argument must be a Buffer or Uint8Array');h(r,t.length),void 0===i&&(i=t.length-r);return d(i,r,t.length),p(t,r,i)}):(t.randomFill=n,t.randomFillSync=n)}).call(this,r(8),r(3))},function(e,t,r){(function(t,i,n,a,o){var s,c=(s=(s="undefined"!=typeof document&&document.currentScript?document.currentScript.src:void 0)||t,function(e){var t,c,u=void 0!==(e=e||{})?e:{};u.ready=new Promise((function(e,r){t=e,c=r})),Object.getOwnPropertyDescriptor(u.ready,"_main")||(Object.defineProperty(u.ready,"_main",{configurable:!0,get:function(){$e("You are getting _main on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_main",{configurable:!0,set:function(){$e("You are setting _main on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_malloc")||(Object.defineProperty(u.ready,"_malloc",{configurable:!0,get:function(){$e("You are getting _malloc on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_malloc",{configurable:!0,set:function(){$e("You are setting _malloc on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_free")||(Object.defineProperty(u.ready,"_free",{configurable:!0,get:function(){$e("You are getting _free on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_free",{configurable:!0,set:function(){$e("You are setting _free on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_stackSave")||(Object.defineProperty(u.ready,"_stackSave",{configurable:!0,get:function(){$e("You are getting _stackSave on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_stackSave",{configurable:!0,set:function(){$e("You are setting _stackSave on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_stackRestore")||(Object.defineProperty(u.ready,"_stackRestore",{configurable:!0,get:function(){$e("You are getting _stackRestore on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_stackRestore",{configurable:!0,set:function(){$e("You are setting _stackRestore on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_stackAlloc")||(Object.defineProperty(u.ready,"_stackAlloc",{configurable:!0,get:function(){$e("You are getting _stackAlloc on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_stackAlloc",{configurable:!0,set:function(){$e("You are setting _stackAlloc on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"___data_end")||(Object.defineProperty(u.ready,"___data_end",{configurable:!0,get:function(){$e("You are getting ___data_end on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"___data_end",{configurable:!0,set:function(){$e("You are setting ___data_end on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"___wasm_call_ctors")||(Object.defineProperty(u.ready,"___wasm_call_ctors",{configurable:!0,get:function(){$e("You are getting ___wasm_call_ctors on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"___wasm_call_ctors",{configurable:!0,set:function(){$e("You are setting ___wasm_call_ctors on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_fflush")||(Object.defineProperty(u.ready,"_fflush",{configurable:!0,get:function(){$e("You are getting _fflush on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_fflush",{configurable:!0,set:function(){$e("You are setting _fflush on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"___errno_location")||(Object.defineProperty(u.ready,"___errno_location",{configurable:!0,get:function(){$e("You are getting ___errno_location on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"___errno_location",{configurable:!0,set:function(){$e("You are setting ___errno_location on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"__ZSt18uncaught_exceptionv")||(Object.defineProperty(u.ready,"__ZSt18uncaught_exceptionv",{configurable:!0,get:function(){$e("You are getting __ZSt18uncaught_exceptionv on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"__ZSt18uncaught_exceptionv",{configurable:!0,set:function(){$e("You are setting __ZSt18uncaught_exceptionv on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_setThrew")||(Object.defineProperty(u.ready,"_setThrew",{configurable:!0,get:function(){$e("You are getting _setThrew on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_setThrew",{configurable:!0,set:function(){$e("You are setting _setThrew on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"___cxa_is_pointer_type")||(Object.defineProperty(u.ready,"___cxa_is_pointer_type",{configurable:!0,get:function(){$e("You are getting ___cxa_is_pointer_type on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"___cxa_is_pointer_type",{configurable:!0,set:function(){$e("You are setting ___cxa_is_pointer_type on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"___cxa_can_catch")||(Object.defineProperty(u.ready,"___cxa_can_catch",{configurable:!0,get:function(){$e("You are getting ___cxa_can_catch on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"___cxa_can_catch",{configurable:!0,set:function(){$e("You are setting ___cxa_can_catch on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_emscripten_main_thread_process_queued_calls")||(Object.defineProperty(u.ready,"_emscripten_main_thread_process_queued_calls",{configurable:!0,get:function(){$e("You are getting _emscripten_main_thread_process_queued_calls on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_emscripten_main_thread_process_queued_calls",{configurable:!0,set:function(){$e("You are setting _emscripten_main_thread_process_queued_calls on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_memalign")||(Object.defineProperty(u.ready,"_memalign",{configurable:!0,get:function(){$e("You are getting _memalign on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_memalign",{configurable:!0,set:function(){$e("You are setting _memalign on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_memset")||(Object.defineProperty(u.ready,"_memset",{configurable:!0,get:function(){$e("You are getting _memset on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_memset",{configurable:!0,set:function(){$e("You are setting _memset on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"__get_tzname")||(Object.defineProperty(u.ready,"__get_tzname",{configurable:!0,get:function(){$e("You are getting __get_tzname on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"__get_tzname",{configurable:!0,set:function(){$e("You are setting __get_tzname on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"__get_daylight")||(Object.defineProperty(u.ready,"__get_daylight",{configurable:!0,get:function(){$e("You are getting __get_daylight on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"__get_daylight",{configurable:!0,set:function(){$e("You are setting __get_daylight on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"__get_timezone")||(Object.defineProperty(u.ready,"__get_timezone",{configurable:!0,get:function(){$e("You are getting __get_timezone on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"__get_timezone",{configurable:!0,set:function(){$e("You are setting __get_timezone on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_htonl")||(Object.defineProperty(u.ready,"_htonl",{configurable:!0,get:function(){$e("You are getting _htonl on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_htonl",{configurable:!0,set:function(){$e("You are setting _htonl on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_htons")||(Object.defineProperty(u.ready,"_htons",{configurable:!0,get:function(){$e("You are getting _htons on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_htons",{configurable:!0,set:function(){$e("You are setting _htons on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"_ntohs")||(Object.defineProperty(u.ready,"_ntohs",{configurable:!0,get:function(){$e("You are getting _ntohs on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"_ntohs",{configurable:!0,set:function(){$e("You are setting _ntohs on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})),Object.getOwnPropertyDescriptor(u.ready,"onRuntimeInitialized")||(Object.defineProperty(u.ready,"onRuntimeInitialized",{configurable:!0,get:function(){$e("You are getting onRuntimeInitialized on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}),Object.defineProperty(u.ready,"onRuntimeInitialized",{configurable:!0,set:function(){$e("You are setting onRuntimeInitialized on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}}));var l,h={};for(l in u)u.hasOwnProperty(l)&&(h[l]=u[l]);var d=[],p="./this.program",f=function(e,t){throw t},m=!1,g=!1,_=!1,v=!1;if(m="object"==typeof window,g="function"==typeof importScripts,_="object"==typeof i&&"object"==typeof i.versions&&"string"==typeof i.versions.node,v=!m&&!_&&!g,u.ENVIRONMENT)throw new Error("Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -s ENVIRONMENT=web or -s ENVIRONMENT=node)");var y,b,E,w,S,k="";function x(e){return u.locateFile?u.locateFile(e,k):k+e}if(_)k=g?r(38).dirname(k)+"/":n+"/",y=function(e,t){return w||(w=r(77)),S||(S=r(38)),e=S.normalize(e),w.readFileSync(e,t?null:"utf8")},E=function(e){var t=y(e,!0);return t.buffer||(t=new Uint8Array(t)),Z(t.buffer),t},i.argv.length>1&&(p=i.argv[1].replace(/\\/g,"/")),d=i.argv.slice(2),i.on("unhandledRejection",$e),f=function(e){i.exit(e)},u.inspect=function(){return"[Emscripten Module object]"};else if(v)"undefined"!=typeof read&&(y=function(e){return read(e)}),E=function(e){var t;return"function"==typeof readbuffer?new Uint8Array(readbuffer(e)):(Z("object"==typeof(t=read(e,"binary"))),t)},"undefined"!=typeof scriptArgs?d=scriptArgs:void 0!==arguments&&(d=arguments),"function"==typeof quit&&(f=function(e){quit(e)}),"undefined"!=typeof print&&("undefined"==typeof console&&(console={}),console.log=print,console.warn=console.error="undefined"!=typeof printErr?printErr:print);else{if(!m&&!g)throw new Error("environment detection error");g?k=self.location.href:document.currentScript&&(k=document.currentScript.src),s&&(k=s),k=0!==k.indexOf("blob:")?k.substr(0,k.lastIndexOf("/")+1):"",y=function(e){var t=new XMLHttpRequest;return t.open("GET",e,!1),t.send(null),t.responseText},g&&(E=function(e){var t=new XMLHttpRequest;return t.open("GET",e,!1),t.responseType="arraybuffer",t.send(null),new Uint8Array(t.response)}),b=function(e,t,r){var i=new XMLHttpRequest;i.open("GET",e,!0),i.responseType="arraybuffer",i.onload=function(){200==i.status||0==i.status&&i.response?t(i.response):r()},i.onerror=r,i.send(null)}}var M=u.print||console.log.bind(console),N=u.printErr||console.warn.bind(console);for(l in h)h.hasOwnProperty(l)&&(u[l]=h[l]);h=null,u.arguments&&(d=u.arguments),Object.getOwnPropertyDescriptor(u,"arguments")||Object.defineProperty(u,"arguments",{configurable:!0,get:function(){$e("Module.arguments has been replaced with plain arguments_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),u.thisProgram&&(p=u.thisProgram),Object.getOwnPropertyDescriptor(u,"thisProgram")||Object.defineProperty(u,"thisProgram",{configurable:!0,get:function(){$e("Module.thisProgram has been replaced with plain thisProgram (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),u.quit&&(f=u.quit),Object.getOwnPropertyDescriptor(u,"quit")||Object.defineProperty(u,"quit",{configurable:!0,get:function(){$e("Module.quit has been replaced with plain quit_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),Z(void 0===u.memoryInitializerPrefixURL,"Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead"),Z(void 0===u.pthreadMainPrefixURL,"Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead"),Z(void 0===u.cdInitializerPrefixURL,"Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead"),Z(void 0===u.filePackagePrefixURL,"Module.filePackagePrefixURL option was removed, use Module.locateFile instead"),Z(void 0===u.read,"Module.read option was removed (modify read_ in JS)"),Z(void 0===u.readAsync,"Module.readAsync option was removed (modify readAsync in JS)"),Z(void 0===u.readBinary,"Module.readBinary option was removed (modify readBinary in JS)"),Z(void 0===u.setWindowTitle,"Module.setWindowTitle option was removed (modify setWindowTitle in JS)"),Z(void 0===u.TOTAL_MEMORY,"Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY"),Object.getOwnPropertyDescriptor(u,"read")||Object.defineProperty(u,"read",{configurable:!0,get:function(){$e("Module.read has been replaced with plain read_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),Object.getOwnPropertyDescriptor(u,"readAsync")||Object.defineProperty(u,"readAsync",{configurable:!0,get:function(){$e("Module.readAsync has been replaced with plain readAsync (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),Object.getOwnPropertyDescriptor(u,"readBinary")||Object.defineProperty(u,"readBinary",{configurable:!0,get:function(){$e("Module.readBinary has been replaced with plain readBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),Object.getOwnPropertyDescriptor(u,"setWindowTitle")||Object.defineProperty(u,"setWindowTitle",{configurable:!0,get:function(){$e("Module.setWindowTitle has been replaced with plain setWindowTitle (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});var j=16;function T(e,t){return t||(t=j),Math.ceil(e/t)*t}function R(e){R.shown||(R.shown={}),R.shown[e]||(R.shown[e]=1,N(e))}function I(e,t){if("function"==typeof WebAssembly.Function){for(var r={i:"i32",j:"i64",f:"f32",d:"f64"},i={parameters:[],results:"v"==t[0]?[]:[r[t[0]]]},n=1;n>>0)+4294967296*+(t>>>0):+(e>>>0)+4294967296*+(0|t)}var C,B,z,L=0,U=function(e){L=e},H=function(){return L};u.wasmBinary&&(C=u.wasmBinary),Object.getOwnPropertyDescriptor(u,"wasmBinary")||Object.defineProperty(u,"wasmBinary",{configurable:!0,get:function(){$e("Module.wasmBinary has been replaced with plain wasmBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),u.noExitRuntime&&(B=u.noExitRuntime),Object.getOwnPropertyDescriptor(u,"noExitRuntime")||Object.defineProperty(u,"noExitRuntime",{configurable:!0,get:function(){$e("Module.noExitRuntime has been replaced with plain noExitRuntime (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),"object"!=typeof WebAssembly&&$e("no native wasm support detected");var q=new WebAssembly.Table({initial:7145,maximum:7150,element:"anyfunc"}),K=!1;function Z(e,t){e||$e("Assertion failed: "+t)}var W="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0;function X(e,t,r){for(var i=t+r,n=t;e[n]&&!(n>=i);)++n;if(n-t>16&&e.subarray&&W)return W.decode(e.subarray(t,n));for(var a="";t>10,56320|1023&u)}}else a+=String.fromCharCode((31&o)<<6|s)}else a+=String.fromCharCode(o)}return a}function Q(e,t){return e?X(le,e,t):""}function J(e,t,r,i){if(!(i>0))return 0;for(var n=r,a=r+i-1,o=0;o=55296&&s<=57343&&(s=65536+((1023&s)<<10)|1023&e.charCodeAt(++o)),s<=127){if(r>=a)break;t[r++]=s}else if(s<=2047){if(r+1>=a)break;t[r++]=192|s>>6,t[r++]=128|63&s}else if(s<=65535){if(r+2>=a)break;t[r++]=224|s>>12,t[r++]=128|s>>6&63,t[r++]=128|63&s}else{if(r+3>=a)break;s>=2097152&&R("Invalid Unicode code point 0x"+s.toString(16)+" encountered when serializing a JS string to an UTF-8 string on the asm.js/wasm heap! (Valid unicode code points should be in range 0-0x1FFFFF)."),t[r++]=240|s>>18,t[r++]=128|s>>12&63,t[r++]=128|s>>6&63,t[r++]=128|63&s}}return t[r]=0,r-n}function V(e,t,r){return Z("number"==typeof r,"stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!"),J(e,le,t,r)}function G(e){for(var t=0,r=0;r=55296&&i<=57343&&(i=65536+((1023&i)<<10)|1023&e.charCodeAt(++r)),i<=127?++t:t+=i<=2047?2:i<=65535?3:4}return t}var Y="undefined"!=typeof TextDecoder?new TextDecoder("utf-16le"):void 0;function $(e,t){Z(e%2==0,"Pointer passed to UTF16ToString must be aligned to two bytes!");for(var r=e,i=r>>1,n=i+t/2;!(i>=n)&&de[i];)++i;if((r=i<<1)-e>32&&Y)return Y.decode(le.subarray(e,r));for(var a=0,o="";;){var s=he[e+2*a>>1];if(0==s||a==t/2)return o;++a,o+=String.fromCharCode(s)}}function ee(e,t,r){if(Z(t%2==0,"Pointer passed to stringToUTF16 must be aligned to two bytes!"),Z("number"==typeof r,"stringToUTF16(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!"),void 0===r&&(r=2147483647),r<2)return 0;for(var i=t,n=(r-=2)<2*e.length?r/2:e.length,a=0;a>1]=o,t+=2}return he[t>>1]=0,t-i}function te(e){return 2*e.length}function re(e,t){Z(e%4==0,"Pointer passed to UTF32ToString must be aligned to four bytes!");for(var r=0,i="";!(r>=t/4);){var n=pe[e+4*r>>2];if(0==n)break;if(++r,n>=65536){var a=n-65536;i+=String.fromCharCode(55296|a>>10,56320|1023&a)}else i+=String.fromCharCode(n)}return i}function ie(e,t,r){if(Z(t%4==0,"Pointer passed to stringToUTF32 must be aligned to four bytes!"),Z("number"==typeof r,"stringToUTF32(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!"),void 0===r&&(r=2147483647),r<4)return 0;for(var i=t,n=i+r-4,a=0;a=55296&&o<=57343&&(o=65536+((1023&o)<<10)|1023&e.charCodeAt(++a)),pe[t>>2]=o,(t+=4)+4>n)break}return pe[t>>2]=0,t-i}function ne(e){for(var t=0,r=0;r=55296&&i<=57343&&++r,t+=4}return t}function ae(e){var t=G(e)+1,r=no(t);return r&&J(e,ue,r,t),r}function oe(e,t){Z(e.length>=0,"writeArrayToMemory array must have a length (should be an array or typed array)"),ue.set(e,t)}function se(e,t,r){for(var i=0;i>0]=e.charCodeAt(i);r||(ue[t>>0]=0)}var ce,ue,le,he,de,pe,fe,me,ge,_e=65536;function ve(e,t){return e%t>0&&(e+=t-e%t),e}function ye(e){ce=e,u.HEAP8=ue=new Int8Array(e),u.HEAP16=he=new Int16Array(e),u.HEAP32=pe=new Int32Array(e),u.HEAPU8=le=new Uint8Array(e),u.HEAPU16=de=new Uint16Array(e),u.HEAPU32=fe=new Uint32Array(e),u.HEAPF32=me=new Float32Array(e),u.HEAPF64=ge=new Float64Array(e)}var be=6561440,Ee=1318560,we=6561440,Se=1318384;Z(be%16==0,"stack must start aligned"),Z(we%16==0,"heap must start aligned");var ke=5242880;u.TOTAL_STACK&&Z(ke===u.TOTAL_STACK,"the stack size can no longer be determined at runtime");var xe=u.INITIAL_MEMORY||16777216;function Me(){Z(0==(3&Ee)),fe[1+(Ee>>2)]=34821223,fe[2+(Ee>>2)]=2310721022,pe[0]=1668509029}function Ne(){var e=fe[1+(Ee>>2)],t=fe[2+(Ee>>2)];34821223==e&&2310721022==t||$e("Stack overflow! Stack cookie has been overwritten, expected hex dwords 0x89BACDFE and 0x2135467, but received 0x"+t.toString(16)+" "+e.toString(16)),1668509029!==pe[0]&&$e("Runtime error: The application has corrupted its heap memory area (address zero)!")}function je(e){for(;e.length>0;){var t=e.shift();if("function"!=typeof t){var r=t.func;"number"==typeof r?void 0===t.arg?u.dynCall_v(r):u.dynCall_vi(r,t.arg):r(void 0===t.arg?null:t.arg)}else t(u)}}Object.getOwnPropertyDescriptor(u,"INITIAL_MEMORY")||Object.defineProperty(u,"INITIAL_MEMORY",{configurable:!0,get:function(){$e("Module.INITIAL_MEMORY has been replaced with plain INITIAL_INITIAL_MEMORY (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}}),Z(xe>=ke,"INITIAL_MEMORY should be larger than TOTAL_STACK, was "+xe+"! (TOTAL_STACK="+ke+")"),Z("undefined"!=typeof Int32Array&&"undefined"!=typeof Float64Array&&void 0!==Int32Array.prototype.subarray&&void 0!==Int32Array.prototype.set,"JS engine does not provide full typed array support"),(z=u.wasmMemory?u.wasmMemory:new WebAssembly.Memory({initial:xe/_e,maximum:2147483648/_e}))&&(ce=z.buffer),Z((xe=ce.byteLength)%_e==0),Z(65536%_e==0),ye(ce),pe[Se>>2]=we,function(){var e=new Int16Array(1),t=new Int8Array(e.buffer);if(e[0]=25459,115!==t[0]||99!==t[1])throw"Runtime error: expected the system to be little-endian!"}();var Te=[],Re=[],Ie=[],Oe=[],Ae=!1,Pe=!1;function De(){if(u.preRun)for("function"==typeof u.preRun&&(u.preRun=[u.preRun]);u.preRun.length;)Le(u.preRun.shift());je(Te)}function Fe(){Ne(),Z(!Ae),Ae=!0,u.noFSInit||Yr.init.initialized||Yr.init(),Qr.init(),_i.root=Yr.mount(_i,{},null),wi.root=Yr.mount(wi,{},null),je(Re)}function Ce(){Ne(),Yr.ignorePermissions=!1,je(Ie)}function Be(){Ne(),Pe=!0}function ze(){if(Ne(),u.postRun)for("function"==typeof u.postRun&&(u.postRun=[u.postRun]);u.postRun.length;)Ue(u.postRun.shift());je(Oe)}function Le(e){Te.unshift(e)}function Ue(e){Oe.unshift(e)}Z(Math.imul,"This browser does not support Math.imul(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill"),Z(Math.fround,"This browser does not support Math.fround(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill"),Z(Math.clz32,"This browser does not support Math.clz32(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill"),Z(Math.trunc,"This browser does not support Math.trunc(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");var He=Math.abs,qe=Math.ceil,Ke=Math.floor,Ze=Math.min,We=0,Xe=null,Qe=null,Je={};function Ve(e){for(var t=e;;){if(!Je[e])return e;e=t+Math.random()}}function Ge(e){We++,u.monitorRunDependencies&&u.monitorRunDependencies(We),e?(Z(!Je[e]),Je[e]=1,null===Xe&&"undefined"!=typeof setInterval&&(Xe=setInterval((function(){if(K)return clearInterval(Xe),void(Xe=null);var e=!1;for(var t in Je)e||(e=!0,N("still waiting on run dependencies:")),N("dependency: "+t);e&&N("(end of list)")}),1e4))):N("warning: run dependency added without ID")}function Ye(e){if(We--,u.monitorRunDependencies&&u.monitorRunDependencies(We),e?(Z(Je[e]),delete Je[e]):N("warning: run dependency removed without ID"),0==We&&(null!==Xe&&(clearInterval(Xe),Xe=null),Qe)){var t=Qe;Qe=null,t()}}function $e(e){u.onAbort&&u.onAbort(e),N(e+=""),K=!0,e="abort("+e+") at "+_t();var t=new WebAssembly.RuntimeError(e);throw c(t),t}function et(e,t){return String.prototype.startsWith?e.startsWith(t):0===e.indexOf(t)}u.preloadedImages={},u.preloadedAudios={};var tt="data:application/octet-stream;base64,";function rt(e){return et(e,tt)}var it="file://";function nt(e){return et(e,it)}function at(e,t){return function(){var r=e,i=t;return t||(i=u.asm),Z(Ae,"native function `"+r+"` called before runtime initialization"),Z(!Pe,"native function `"+r+"` called after runtime exit (use NO_EXIT_RUNTIME to keep it alive after main() exits)"),i[e]||Z(i[e],"exported native function `"+r+"` not found"),i[e].apply(null,arguments)}}var ot,st,ct="monero_core.wasm";function ut(){try{if(C)return new Uint8Array(C);if(E)return E(ct);throw"both async and sync fetching of the wasm failed"}catch(e){$e(e)}}function lt(){return C||!m&&!g||"function"!=typeof fetch||nt(ct)?new Promise((function(e,t){e(ut())})):fetch(ct,{credentials:"same-origin"}).then((function(e){if(!e.ok)throw"failed to load wasm binary file at '"+ct+"'";return e.arrayBuffer()})).catch((function(){return ut()}))}function ht(){var e={env:Ya,wasi_snapshot_preview1:Ya};function t(e,t){var r=e.exports;r=Za.instrumentWasmExports(r),u.asm=r,Ye("wasm-instantiate")}Ge("wasm-instantiate");var r=u;function i(e){Z(u===r,"the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?"),r=null,t(e.instance)}function n(t){return lt().then((function(t){return WebAssembly.instantiate(t,e)})).then(t,(function(e){N("failed to asynchronously prepare wasm: "+e),$e(e)}))}if(u.instantiateWasm)try{var a=u.instantiateWasm(e,t);return a=Za.instrumentWasmExports(a)}catch(e){return N("Module.instantiateWasm callback failed with error: "+e),!1}return function(){if(C||"function"!=typeof WebAssembly.instantiateStreaming||rt(ct)||nt(ct)||"function"!=typeof fetch)return n(i);fetch(ct,{credentials:"same-origin"}).then((function(t){return WebAssembly.instantiateStreaming(t,e).then(i,(function(e){return N("wasm streaming compile failed: "+e),N("falling back to ArrayBuffer instantiation"),n(i)}))}))}(),{}}function dt(e,t,i,n,a,o,s,c){const l=r(204),h=l.HttpClient,d=l.LibraryUtils,p=l.GenUtils;return Za.handleSleep((function(r){d.loadCoreModule().then(c=>{let l=o,f=s,m=new Uint8Array(f);for(let e=0;e{let t=e.body;t instanceof Uint8Array||(console.error("resp is not uint8array"),console.error(t));let i=t.length*t.BYTES_PER_ELEMENT,n=u._malloc(i);new Uint8Array(u.HEAPU8.buffer,n,i).set(new Uint8Array(t.buffer,t.byteOffset,i));let a={code:e.statusCode,message:e.statusText,headers:e.headers,bodyPtr:n,bodyLength:t.length},o=JSON.stringify(a),s=u.lengthBytesUTF8(o)+1,c=u._malloc(s);u.stringToUTF8(o,c,s),g=!0,r(c)}).catch(e=>{if(g)throw console.error("Error caught in JS after previously calling wakeUp(): "+e),new Error("Error caught in JS after previously calling wakeUp(): "+e);let t=e.message?e.message:""+e;t=JSON.stringify({error:t});let i=u.lengthBytesUTF8(t)+1,n=u._malloc(i);u.stringToUTF8(t,n,i),g=!0,r(n)})}).catch(e=>{throw new Error("Could not load core wasm module")})}))}function pt(e,t,i,n,a,o,s){const c=r(204),l=c.HttpClient,h=c.LibraryUtils,d=c.GenUtils;return Za.handleSleep((function(r){let s=!1;l.request({method:Q(a),uri:Q(e),username:Q(t),password:Q(i),body:Q(o),resolveWithFullResponse:!0,rejectUnauthorized:h.isRejectUnauthorized(Q(n)),requestApi:d.isFirefox()?"xhr":"fetch"}).then(e=>{let t={code:e.statusCode,message:e.statusText,body:e.body,headers:e.headers},i=JSON.stringify(t),n=u.lengthBytesUTF8(i)+1,a=u._malloc(n);u.stringToUTF8(i,a,n),s=!0,r(a)}).catch(e=>{if(s)throw console.error("Error caught in JS after previously calling wakeUp(): "+e),new Error("Error caught in JS after previously calling wakeUp(): "+e);let t=e.message?e.message:""+e;t=JSON.stringify({error:t});let i=u.lengthBytesUTF8(t)+1,n=u._malloc(i);u.stringToUTF8(t,n,i),s=!0,r(n)})}))}function ft(e){return R("warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling"),e}function mt(e){return e.replace(/\b_Z[\w\d_]+/g,(function(e){var t=ft(e);return e===t?e:t+" ["+e+"]"}))}function gt(){var e=new Error;if(!e.stack){try{throw new Error}catch(t){e=t}if(!e.stack)return"(no stack trace available)"}return e.stack.toString()}function _t(){var e=gt();return u.extraStackTrace&&(e+="\n"+u.extraStackTrace()),mt(e)}function vt(){N("missing function: BIO_ctrl"),$e(-1)}function yt(){N("missing function: BIO_ctrl_pending"),$e(-1)}function bt(){N("missing function: BIO_free"),$e(-1)}function Et(){N("missing function: BIO_new_bio_pair"),$e(-1)}function wt(){N("missing function: BIO_new_mem_buf"),$e(-1)}function St(){N("missing function: BIO_read"),$e(-1)}function kt(){N("missing function: BIO_write"),$e(-1)}function xt(){N("missing function: CONF_modules_unload"),$e(-1)}function Mt(){N("missing function: CRYPTO_free"),$e(-1)}function Nt(){N("missing function: ERR_clear_error"),$e(-1)}function jt(){N("missing function: ERR_get_error"),$e(-1)}function Tt(){N("missing function: ERR_reason_error_string"),$e(-1)}function Rt(){N("missing function: PEM_read_bio"),$e(-1)}function It(){N("missing function: PEM_write"),$e(-1)}function Ot(){N("missing function: SSL_CTX_ctrl"),$e(-1)}function At(){N("missing function: SSL_CTX_free"),$e(-1)}function Pt(){N("missing function: SSL_CTX_get_default_passwd_cb_userdata"),$e(-1)}function Dt(){N("missing function: SSL_CTX_get_ex_data"),$e(-1)}function Ft(){N("missing function: SSL_CTX_new"),$e(-1)}function Ct(){N("missing function: SSL_CTX_set_default_passwd_cb_userdata"),$e(-1)}function Bt(){N("missing function: SSL_CTX_set_ex_data"),$e(-1)}function zt(){N("missing function: SSL_CTX_set_options"),$e(-1)}function Lt(){N("missing function: SSL_ctrl"),$e(-1)}function Ut(){N("missing function: SSL_free"),$e(-1)}function Ht(){N("missing function: SSL_get_error"),$e(-1)}function qt(){N("missing function: SSL_get_ex_data"),$e(-1)}function Kt(){N("missing function: SSL_get_shutdown"),$e(-1)}function Zt(){N("missing function: SSL_new"),$e(-1)}function Wt(){N("missing function: SSL_read"),$e(-1)}function Xt(){N("missing function: SSL_set_bio"),$e(-1)}function Qt(){N("missing function: SSL_set_ex_data"),$e(-1)}function Jt(){N("missing function: SSL_shutdown"),$e(-1)}function Vt(){N("missing function: SSL_write"),$e(-1)}function Gt(){N("missing function: TLS_client_method"),$e(-1)}function Yt(){N("missing function: TLS_method"),$e(-1)}function $t(){N("missing function: TLS_server_method"),$e(-1)}function er(){N("missing function: _ZN2hw6trezor12register_allEv"),$e(-1)}function tr(){N("missing function: _ZN4epee9net_utils4http16http_client_auth13do_handle_401ERKNS1_18http_response_infoE"),$e(-1)}function rr(){N("missing function: _ZN4epee9net_utils4http16http_client_auth17do_get_auth_fieldEN5boost16basic_string_refIcNSt3__211char_traitsIcEEEES8_"),$e(-1)}function ir(){N("missing function: _ZN4epee9net_utils4http16http_client_authC1ENS1_5loginE"),$e(-1)}function nr(){N("missing function: _ZN5boost10filesystem6detail12current_pathEPNS_6system10error_codeE"),$e(-1)}function ar(){N("missing function: _ZN5boost10filesystem6detail18create_directoriesERKNS0_4pathEPNS_6system10error_codeE"),$e(-1)}function or(){N("missing function: _ZN5boost10filesystem6detail5spaceERKNS0_4pathEPNS_6system10error_codeE"),$e(-1)}function sr(){N("missing function: _ZN5boost10filesystem6detail6removeERKNS0_4pathEPNS_6system10error_codeE"),$e(-1)}function cr(){N("missing function: _ZN5boost10filesystem6detail6statusERKNS0_4pathEPNS_6system10error_codeE"),$e(-1)}function ur(){N("missing function: _ZN5boost10filesystem6detail9canonicalERKNS0_4pathES4_PNS_6system10error_codeE"),$e(-1)}function lr(){N("missing function: _ZN5tools6Notify6notifyEPKcS2_z"),$e(-1)}function hr(){N("missing function: _ZN5tools9dns_utils25load_txt_records_from_dnsERNSt3__26vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEERKSA_"),$e(-1)}function dr(){N("missing function: _ZN5tools9dns_utils35get_account_address_as_str_from_urlERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERbNS1_8functionIFS7_S9_RKNS1_6vectorIS7_NS5_IS7_EEEEbEEE"),$e(-1)}function pr(){N("missing function: _ZNK10cryptonote10Blockchain29get_current_blockchain_heightEv"),$e(-1)}function fr(){N("missing function: _ZNK10cryptonote10Blockchain30get_pending_block_id_by_heightEy"),$e(-1)}function mr(){N("missing function: _ZNK3net5socks9connectorclERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RN5boost4asio20basic_waitable_timerINS2_6chrono12steady_clockENSC_11wait_traitsISF_EENSC_8executorEEE"),$e(-1)}function gr(){N("missing function: _ZNK4epee9net_utils13ssl_options_t14create_contextEv"),$e(-1)}function _r(){N("missing function: _ZNK4epee9net_utils13ssl_options_t9handshakeERN5boost4asio3ssl6streamINS3_19basic_stream_socketINS3_2ip3tcpENS3_8executorEEEEENS4_11stream_base14handshake_typeERKNSt3__212basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEENSF_6chrono8durationIxNSF_5ratioILx1ELx1000EEEEE"),$e(-1)}function vr(){N("missing function: _ZNK4epee9net_utils14direct_connectclERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RN5boost4asio20basic_waitable_timerINS2_6chrono12steady_clockENSC_11wait_traitsISF_EENSC_8executorEEE"),$e(-1)}function yr(){N("missing function: _ZNK5boost10filesystem4path11parent_pathEv"),$e(-1)}function br(e,t,r,i){$e("Assertion failed: "+Q(e)+", at: "+[t?Q(t):"unknown filename",r,i?Q(i):"unknown function"])}rt(ct)||(ct=x(ct)),Re.push({func:function(){eo()}});var Er={DESTRUCTOR_OFFSET:0,REFCOUNT_OFFSET:4,TYPE_OFFSET:8,CAUGHT_OFFSET:12,RETHROWN_OFFSET:13,SIZE:16};function wr(e){return no(e+Er.SIZE)+Er.SIZE}function Sr(e,t){R("atexit() called, but EXIT_RUNTIME is not set, so atexits() will not be called. set EXIT_RUNTIME to 1 (see the FAQ)")}function kr(e,t){return Sr()}function xr(e){this.excPtr=e,this.ptr=e-Er.SIZE,this.set_type=function(e){pe[this.ptr+Er.TYPE_OFFSET>>2]=e},this.get_type=function(){return pe[this.ptr+Er.TYPE_OFFSET>>2]},this.set_destructor=function(e){pe[this.ptr+Er.DESTRUCTOR_OFFSET>>2]=e},this.get_destructor=function(){return pe[this.ptr+Er.DESTRUCTOR_OFFSET>>2]},this.set_refcount=function(e){pe[this.ptr+Er.REFCOUNT_OFFSET>>2]=e},this.set_caught=function(e){e=e?1:0,ue[this.ptr+Er.CAUGHT_OFFSET>>0]=e},this.get_caught=function(){return 0!=ue[this.ptr+Er.CAUGHT_OFFSET>>0]},this.set_rethrown=function(e){e=e?1:0,ue[this.ptr+Er.RETHROWN_OFFSET>>0]=e},this.get_rethrown=function(){return 0!=ue[this.ptr+Er.RETHROWN_OFFSET>>0]},this.init=function(e,t){this.set_type(e),this.set_destructor(t),this.set_refcount(0),this.set_caught(!1),this.set_rethrown(!1)},this.add_ref=function(){var e=pe[this.ptr+Er.REFCOUNT_OFFSET>>2];pe[this.ptr+Er.REFCOUNT_OFFSET>>2]=e+1},this.release_ref=function(){var e=pe[this.ptr+Er.REFCOUNT_OFFSET>>2];return pe[this.ptr+Er.REFCOUNT_OFFSET>>2]=e-1,Z(e>0),1===e}}function Mr(e){this.free=function(){to(this.ptr),this.ptr=0},this.set_base_ptr=function(e){pe[this.ptr>>2]=e},this.get_base_ptr=function(){return pe[this.ptr>>2]},this.set_adjusted_ptr=function(e){pe[this.ptr+4>>2]=e},this.get_adjusted_ptr=function(){return pe[this.ptr+4>>2]},this.get_exception_ptr=function(){if(_o(this.get_exception_info().get_type()))return pe[this.get_base_ptr()>>2];var e=this.get_adjusted_ptr();return 0!==e?e:this.get_base_ptr()},this.get_exception_info=function(){return new xr(this.get_base_ptr())},void 0===e?(this.ptr=no(8),this.set_adjusted_ptr(0)):this.ptr=e}var Nr=[];function jr(e){e.add_ref()}function Tr(e){var t=new Mr(e),r=t.get_exception_info();return r.get_caught()||(r.set_caught(!0),mo.uncaught_exceptions--),r.set_rethrown(!1),Nr.push(t),jr(r),t.get_exception_ptr()}function Rr(e){try{return to(new xr(e).ptr)}catch(e){N("exception during cxa_free_exception: "+e)}}function Ir(e){if(e.release_ref()&&!e.get_rethrown()){var t=e.get_destructor();t&&u.dynCall_ii(t,e.excPtr),Rr(e.excPtr)}}function Or(e){e&&Ir(new xr(e))}var Ar=0;function Pr(){ho(0),Z(Nr.length>0);var e=Nr.pop();Ir(e.get_exception_info()),e.free(),Ar=0}function Dr(e){var t=new Mr(e),r=t.get_base_ptr();throw Ar||(Ar=r),t.free(),r}function Fr(){var e=Ar;if(!e)return 0|(U(0),0);var t=new xr(e),r=t.get_type(),i=new Mr;if(i.set_base_ptr(e),!r)return 0|(U(0),i.ptr);var n=Array.prototype.slice.call(arguments),a=1318544;pe[a>>2]=e;for(var o=0;o>2];return e!==c&&i.set_adjusted_ptr(c),0|(U(s),i.ptr)}}return 0|(U(r),i.ptr)}function Cr(){var e=Ar;if(!e)return 0|(U(0),0);var t=new xr(e),r=t.get_type(),i=new Mr;if(i.set_base_ptr(e),!r)return 0|(U(0),i.ptr);var n=Array.prototype.slice.call(arguments),a=1318544;pe[a>>2]=e;for(var o=0;o>2];return e!==c&&i.set_adjusted_ptr(c),0|(U(s),i.ptr)}}return 0|(U(r),i.ptr)}function Br(e){e&&jr(new xr(e))}function zr(){var e=Nr.pop(),t=e.get_exception_info(),r=e.get_base_ptr();throw t.get_rethrown()?e.free():(Nr.push(e),t.set_rethrown(!0)),Ar=r,r}function Lr(e){if(e){var t=new Mr;t.set_base_ptr(e);var r=t.get_exception_info();Nr.push(t),r.set_rethrown(!0),zr()}}function Ur(e,t,r){throw new xr(e).init(t,r),Ar=e,"uncaught_exception"in mo?mo.uncaught_exceptions++:mo.uncaught_exceptions=1,e}function Hr(){return mo.uncaught_exceptions}function qr(){$e("stack overflow")}function Kr(e){return pe[io()>>2]=e,e}function Zr(e,t){return Kr(63),-1}var Wr={splitPath:function(e){return/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/.exec(e).slice(1)},normalizeArray:function(e,t){for(var r=0,i=e.length-1;i>=0;i--){var n=e[i];"."===n?e.splice(i,1):".."===n?(e.splice(i,1),r++):r&&(e.splice(i,1),r--)}if(t)for(;r;r--)e.unshift("..");return e},normalize:function(e){var t="/"===e.charAt(0),r="/"===e.substr(-1);return(e=Wr.normalizeArray(e.split("/").filter((function(e){return!!e})),!t).join("/"))||t||(e="."),e&&r&&(e+="/"),(t?"/":"")+e},dirname:function(e){var t=Wr.splitPath(e),r=t[0],i=t[1];return r||i?(i&&(i=i.substr(0,i.length-1)),r+i):"."},basename:function(e){if("/"===e)return"/";var t=e.lastIndexOf("/");return-1===t?e:e.substr(t+1)},extname:function(e){return Wr.splitPath(e)[3]},join:function(){var e=Array.prototype.slice.call(arguments,0);return Wr.normalize(e.join("/"))},join2:function(e,t){return Wr.normalize(e+"/"+t)}},Xr={resolve:function(){for(var e="",t=!1,r=arguments.length-1;r>=-1&&!t;r--){var i=r>=0?arguments[r]:Yr.cwd();if("string"!=typeof i)throw new TypeError("Arguments to path.resolve must be strings");if(!i)return"";e=i+"/"+e,t="/"===i.charAt(0)}return(t?"/":"")+(e=Wr.normalizeArray(e.split("/").filter((function(e){return!!e})),!t).join("/"))||"."},relative:function(e,t){function r(e){for(var t=0;t=0&&""===e[r];r--);return t>r?[]:e.slice(t,r-t+1)}e=Xr.resolve(e).substr(1),t=Xr.resolve(t).substr(1);for(var i=r(e.split("/")),n=r(t.split("/")),a=Math.min(i.length,n.length),o=a,s=0;s0?r.slice(0,n).toString("utf-8"):null}else"undefined"!=typeof window&&"function"==typeof window.prompt?null!==(t=window.prompt("Input: "))&&(t+="\n"):"function"==typeof readline&&null!==(t=readline())&&(t+="\n");if(!t)return null;e.input=Va(t,!0)}return e.input.shift()},put_char:function(e,t){null===t||10===t?(M(X(e.output,0)),e.output=[]):0!=t&&e.output.push(t)},flush:function(e){e.output&&e.output.length>0&&(M(X(e.output,0)),e.output=[])}},default_tty1_ops:{put_char:function(e,t){null===t||10===t?(N(X(e.output,0)),e.output=[]):0!=t&&e.output.push(t)},flush:function(e){e.output&&e.output.length>0&&(N(X(e.output,0)),e.output=[])}}},Jr={ops_table:null,mount:function(e){return Jr.createNode(null,"/",16895,0)},createNode:function(e,t,r,i){if(Yr.isBlkdev(r)||Yr.isFIFO(r))throw new Yr.ErrnoError(63);Jr.ops_table||(Jr.ops_table={dir:{node:{getattr:Jr.node_ops.getattr,setattr:Jr.node_ops.setattr,lookup:Jr.node_ops.lookup,mknod:Jr.node_ops.mknod,rename:Jr.node_ops.rename,unlink:Jr.node_ops.unlink,rmdir:Jr.node_ops.rmdir,readdir:Jr.node_ops.readdir,symlink:Jr.node_ops.symlink},stream:{llseek:Jr.stream_ops.llseek}},file:{node:{getattr:Jr.node_ops.getattr,setattr:Jr.node_ops.setattr},stream:{llseek:Jr.stream_ops.llseek,read:Jr.stream_ops.read,write:Jr.stream_ops.write,allocate:Jr.stream_ops.allocate,mmap:Jr.stream_ops.mmap,msync:Jr.stream_ops.msync}},link:{node:{getattr:Jr.node_ops.getattr,setattr:Jr.node_ops.setattr,readlink:Jr.node_ops.readlink},stream:{}},chrdev:{node:{getattr:Jr.node_ops.getattr,setattr:Jr.node_ops.setattr},stream:Yr.chrdev_stream_ops}});var n=Yr.createNode(e,t,r,i);return Yr.isDir(n.mode)?(n.node_ops=Jr.ops_table.dir.node,n.stream_ops=Jr.ops_table.dir.stream,n.contents={}):Yr.isFile(n.mode)?(n.node_ops=Jr.ops_table.file.node,n.stream_ops=Jr.ops_table.file.stream,n.usedBytes=0,n.contents=null):Yr.isLink(n.mode)?(n.node_ops=Jr.ops_table.link.node,n.stream_ops=Jr.ops_table.link.stream):Yr.isChrdev(n.mode)&&(n.node_ops=Jr.ops_table.chrdev.node,n.stream_ops=Jr.ops_table.chrdev.stream),n.timestamp=Date.now(),e&&(e.contents[t]=n),n},getFileDataAsRegularArray:function(e){if(e.contents&&e.contents.subarray){for(var t=[],r=0;r=t)){t=Math.max(t,r*(r<1048576?2:1.125)>>>0),0!=r&&(t=Math.max(t,256));var i=e.contents;e.contents=new Uint8Array(t),e.usedBytes>0&&e.contents.set(i.subarray(0,e.usedBytes),0)}},resizeFileStorage:function(e,t){if(e.usedBytes!=t){if(0==t)return e.contents=null,void(e.usedBytes=0);if(!e.contents||e.contents.subarray){var r=e.contents;return e.contents=new Uint8Array(t),r&&e.contents.set(r.subarray(0,Math.min(t,e.usedBytes))),void(e.usedBytes=t)}if(e.contents||(e.contents=[]),e.contents.length>t)e.contents.length=t;else for(;e.contents.length=e.node.usedBytes)return 0;var o=Math.min(e.node.usedBytes-n,i);if(Z(o>=0),o>8&&a.subarray)t.set(a.subarray(n,n+o),r);else for(var s=0;s0||i+r8)throw new Yr.ErrnoError(32);for(var n=Wr.normalizeArray(e.split("/").filter((function(e){return!!e})),!1),a=Yr.root,o="/",s=0;s40)throw new Yr.ErrnoError(32)}}return{path:o,node:a}},getPath:function(e){for(var t;;){if(Yr.isRoot(e)){var r=e.mount.mountpoint;return t?"/"!==r[r.length-1]?r+"/"+t:r+t:r}t=t?e.name+"/"+t:e.name,e=e.parent}},hashName:function(e,t){for(var r=0,i=0;i>>0)%Yr.nameTable.length},hashAddNode:function(e){var t=Yr.hashName(e.parent.id,e.name);e.name_next=Yr.nameTable[t],Yr.nameTable[t]=e},hashRemoveNode:function(e){var t=Yr.hashName(e.parent.id,e.name);if(Yr.nameTable[t]===e)Yr.nameTable[t]=e.name_next;else for(var r=Yr.nameTable[t];r;){if(r.name_next===e){r.name_next=e.name_next;break}r=r.name_next}},lookupNode:function(e,t){var r=Yr.mayLookup(e);if(r)throw new Yr.ErrnoError(r,e);for(var i=Yr.hashName(e.id,t),n=Yr.nameTable[i];n;n=n.name_next){var a=n.name;if(n.parent.id===e.id&&a===t)return n}return Yr.lookup(e,t)},createNode:function(e,t,r,i){var n=new Yr.FSNode(e,t,r,i);return Yr.hashAddNode(n),n},destroyNode:function(e){Yr.hashRemoveNode(e)},isRoot:function(e){return e===e.parent},isMountpoint:function(e){return!!e.mounted},isFile:function(e){return 32768==(61440&e)},isDir:function(e){return 16384==(61440&e)},isLink:function(e){return 40960==(61440&e)},isChrdev:function(e){return 8192==(61440&e)},isBlkdev:function(e){return 24576==(61440&e)},isFIFO:function(e){return 4096==(61440&e)},isSocket:function(e){return 49152==(49152&e)},flagModes:{r:0,rs:1052672,"r+":2,w:577,wx:705,xw:705,"w+":578,"wx+":706,"xw+":706,a:1089,ax:1217,xa:1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function(e){var t=Yr.flagModes[e];if(void 0===t)throw new Error("Unknown file open mode: "+e);return t},flagsToPermissionString:function(e){var t=["r","w","rw"][3&e];return 512&e&&(t+="w"),t},nodePermissions:function(e,t){return Yr.ignorePermissions||(-1===t.indexOf("r")||292&e.mode)&&(-1===t.indexOf("w")||146&e.mode)&&(-1===t.indexOf("x")||73&e.mode)?0:2},mayLookup:function(e){var t=Yr.nodePermissions(e,"x");return t||(e.node_ops.lookup?0:2)},mayCreate:function(e,t){try{return Yr.lookupNode(e,t),20}catch(e){}return Yr.nodePermissions(e,"wx")},mayDelete:function(e,t,r){var i;try{i=Yr.lookupNode(e,t)}catch(e){return e.errno}var n=Yr.nodePermissions(e,"wx");if(n)return n;if(r){if(!Yr.isDir(i.mode))return 54;if(Yr.isRoot(i)||Yr.getPath(i)===Yr.cwd())return 10}else if(Yr.isDir(i.mode))return 31;return 0},mayOpen:function(e,t){return e?Yr.isLink(e.mode)?32:Yr.isDir(e.mode)&&("r"!==Yr.flagsToPermissionString(t)||512&t)?31:Yr.nodePermissions(e,Yr.flagsToPermissionString(t)):44},MAX_OPEN_FDS:4096,nextfd:function(e,t){e=e||0,t=t||Yr.MAX_OPEN_FDS;for(var r=e;r<=t;r++)if(!Yr.streams[r])return r;throw new Yr.ErrnoError(33)},getStream:function(e){return Yr.streams[e]},createStream:function(e,t,r){Yr.FSStream||(Yr.FSStream=function(){},Yr.FSStream.prototype={object:{get:function(){return this.node},set:function(e){this.node=e}},isRead:{get:function(){return 1!=(2097155&this.flags)}},isWrite:{get:function(){return 0!=(2097155&this.flags)}},isAppend:{get:function(){return 1024&this.flags}}});var i=new Yr.FSStream;for(var n in e)i[n]=e[n];e=i;var a=Yr.nextfd(t,r);return e.fd=a,Yr.streams[a]=e,e},closeStream:function(e){Yr.streams[e]=null},chrdev_stream_ops:{open:function(e){var t=Yr.getDevice(e.node.rdev);e.stream_ops=t.stream_ops,e.stream_ops.open&&e.stream_ops.open(e)},llseek:function(){throw new Yr.ErrnoError(70)}},major:function(e){return e>>8},minor:function(e){return 255&e},makedev:function(e,t){return e<<8|t},registerDevice:function(e,t){Yr.devices[e]={stream_ops:t}},getDevice:function(e){return Yr.devices[e]},getMounts:function(e){for(var t=[],r=[e];r.length;){var i=r.pop();t.push(i),r.push.apply(r,i.mounts)}return t},syncfs:function(e,t){"function"==typeof e&&(t=e,e=!1),Yr.syncFSRequests++,Yr.syncFSRequests>1&&N("warning: "+Yr.syncFSRequests+" FS.syncfs operations in flight at once, probably just doing extra work");var r=Yr.getMounts(Yr.root.mount),i=0;function n(e){return Z(Yr.syncFSRequests>0),Yr.syncFSRequests--,t(e)}function a(e){if(e)return a.errored?void 0:(a.errored=!0,n(e));++i>=r.length&&n(null)}r.forEach((function(t){if(!t.type.syncfs)return a(null);t.type.syncfs(t,e,a)}))},mount:function(e,t,r){if("string"==typeof e)throw e;var i,n="/"===r,a=!r;if(n&&Yr.root)throw new Yr.ErrnoError(10);if(!n&&!a){var o=Yr.lookupPath(r,{follow_mount:!1});if(r=o.path,i=o.node,Yr.isMountpoint(i))throw new Yr.ErrnoError(10);if(!Yr.isDir(i.mode))throw new Yr.ErrnoError(54)}var s={type:e,opts:t,mountpoint:r,mounts:[]},c=e.mount(s);return c.mount=s,s.root=c,n?Yr.root=c:i&&(i.mounted=s,i.mount&&i.mount.mounts.push(s)),c},unmount:function(e){var t=Yr.lookupPath(e,{follow_mount:!1});if(!Yr.isMountpoint(t.node))throw new Yr.ErrnoError(28);var r=t.node,i=r.mounted,n=Yr.getMounts(i);Object.keys(Yr.nameTable).forEach((function(e){for(var t=Yr.nameTable[e];t;){var r=t.name_next;-1!==n.indexOf(t.mount)&&Yr.destroyNode(t),t=r}})),r.mounted=null;var a=r.mount.mounts.indexOf(i);Z(-1!==a),r.mount.mounts.splice(a,1)},lookup:function(e,t){return e.node_ops.lookup(e,t)},mknod:function(e,t,r){var i=Yr.lookupPath(e,{parent:!0}).node,n=Wr.basename(e);if(!n||"."===n||".."===n)throw new Yr.ErrnoError(28);var a=Yr.mayCreate(i,n);if(a)throw new Yr.ErrnoError(a);if(!i.node_ops.mknod)throw new Yr.ErrnoError(63);return i.node_ops.mknod(i,n,t,r)},create:function(e,t){return t=void 0!==t?t:438,t&=4095,t|=32768,Yr.mknod(e,t,0)},mkdir:function(e,t){return t=void 0!==t?t:511,t&=1023,t|=16384,Yr.mknod(e,t,0)},mkdirTree:function(e,t){for(var r=e.split("/"),i="",n=0;nthis.length-1||e<0)){var t=e%this.chunkSize,r=e/this.chunkSize|0;return this.getter(r)[t]}},a.prototype.setDataGetter=function(e){this.getter=e},a.prototype.cacheLength=function(){var e=new XMLHttpRequest;if(e.open("HEAD",r,!1),e.send(null),!(e.status>=200&&e.status<300||304===e.status))throw new Error("Couldn't load "+r+". Status: "+e.status);var t,i=Number(e.getResponseHeader("Content-length")),n=(t=e.getResponseHeader("Accept-Ranges"))&&"bytes"===t,a=(t=e.getResponseHeader("Content-Encoding"))&&"gzip"===t,o=1048576;n||(o=i);var s=this;s.setDataGetter((function(e){var t=e*o,n=(e+1)*o-1;if(n=Math.min(n,i-1),void 0===s.chunks[e]&&(s.chunks[e]=function(e,t){if(e>t)throw new Error("invalid range ("+e+", "+t+") or no bytes requested!");if(t>i-1)throw new Error("only "+i+" bytes available! programmer error!");var n=new XMLHttpRequest;if(n.open("GET",r,!1),i!==o&&n.setRequestHeader("Range","bytes="+e+"-"+t),"undefined"!=typeof Uint8Array&&(n.responseType="arraybuffer"),n.overrideMimeType&&n.overrideMimeType("text/plain; charset=x-user-defined"),n.send(null),!(n.status>=200&&n.status<300||304===n.status))throw new Error("Couldn't load "+r+". Status: "+n.status);return void 0!==n.response?new Uint8Array(n.response||[]):Va(n.responseText||"",!0)}(t,n)),void 0===s.chunks[e])throw new Error("doXHR failed!");return s.chunks[e]})),!a&&i||(o=i=1,i=this.getter(0).length,o=i,M("LazyFiles on gzip forces download of the whole file when length is accessed")),this._length=i,this._chunkSize=o,this.lengthKnown=!0},"undefined"!=typeof XMLHttpRequest){if(!g)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var o=new a;Object.defineProperties(o,{length:{get:function(){return this.lengthKnown||this.cacheLength(),this._length}},chunkSize:{get:function(){return this.lengthKnown||this.cacheLength(),this._chunkSize}}});var s={isDevice:!1,contents:o}}else s={isDevice:!1,url:r};var c=Yr.createFile(e,t,s,i,n);s.contents?c.contents=s.contents:s.url&&(c.contents=null,c.url=s.url),Object.defineProperties(c,{usedBytes:{get:function(){return this.contents.length}}});var u={};return Object.keys(c.stream_ops).forEach((function(e){var t=c.stream_ops[e];u[e]=function(){if(!Yr.forceLoadFile(c))throw new Yr.ErrnoError(29);return t.apply(null,arguments)}})),u.read=function(e,t,r,i,n){if(!Yr.forceLoadFile(c))throw new Yr.ErrnoError(29);var a=e.node.contents;if(n>=a.length)return 0;var o=Math.min(a.length-n,i);if(Z(o>=0),a.slice)for(var s=0;s>2]=i.dev,pe[r+4>>2]=0,pe[r+8>>2]=i.ino,pe[r+12>>2]=i.mode,pe[r+16>>2]=i.nlink,pe[r+20>>2]=i.uid,pe[r+24>>2]=i.gid,pe[r+28>>2]=i.rdev,pe[r+32>>2]=0,st=[i.size>>>0,(ot=i.size,+He(ot)>=1?ot>0?(0|Ze(+Ke(ot/4294967296),4294967295))>>>0:~~+qe((ot-+(~~ot>>>0))/4294967296)>>>0:0)],pe[r+40>>2]=st[0],pe[r+44>>2]=st[1],pe[r+48>>2]=4096,pe[r+52>>2]=i.blocks,pe[r+56>>2]=i.atime.getTime()/1e3|0,pe[r+60>>2]=0,pe[r+64>>2]=i.mtime.getTime()/1e3|0,pe[r+68>>2]=0,pe[r+72>>2]=i.ctime.getTime()/1e3|0,pe[r+76>>2]=0,st=[i.ino>>>0,(ot=i.ino,+He(ot)>=1?ot>0?(0|Ze(+Ke(ot/4294967296),4294967295))>>>0:~~+qe((ot-+(~~ot>>>0))/4294967296)>>>0:0)],pe[r+80>>2]=st[0],pe[r+84>>2]=st[1],0},doMsync:function(e,t,r,i,n){var a=le.slice(e,e+r);Yr.msync(t,a,n,r,i)},doMkdir:function(e,t){return"/"===(e=Wr.normalize(e))[e.length-1]&&(e=e.substr(0,e.length-1)),Yr.mkdir(e,t,0),0},doMknod:function(e,t,r){switch(61440&t){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}return Yr.mknod(e,t,r),0},doReadlink:function(e,t,r){if(r<=0)return-28;var i=Yr.readlink(e),n=Math.min(r,G(i)),a=ue[t+n];return V(i,t,r+1),ue[t+n]=a,n},doAccess:function(e,t){if(-8&t)return-28;var r;if(!(r=Yr.lookupPath(e,{follow:!0}).node))return-44;var i="";return 4&t&&(i+="r"),2&t&&(i+="w"),1&t&&(i+="x"),i&&Yr.nodePermissions(r,i)?-2:0},doDup:function(e,t,r){var i=Yr.getStream(r);return i&&Yr.close(i),Yr.open(e,t,0,r,r).fd},doReadv:function(e,t,r,i){for(var n=0,a=0;a>2],s=pe[t+(8*a+4)>>2],c=Yr.read(e,ue,o,s,i);if(c<0)return-1;if(n+=c,c>2],s=pe[t+(8*a+4)>>2],c=Yr.write(e,ue,o,s,i);if(c<0)return-1;n+=c}return n},varargs:void 0,get:function(){return Z(null!=$r.varargs),$r.varargs+=4,pe[$r.varargs-4>>2]},getStr:function(e){return Q(e)},getStreamFromFD:function(e){var t=Yr.getStream(e);if(!t)throw new Yr.ErrnoError(8);return t},get64:function(e,t){return Z(e>=0?0===t:-1===t),e}};function ei(e,t,r,i,n){try{Z(e<=64,"nfds must be less than or equal to 64"),Z(!i,"exceptfds not supported");for(var a=0,o=t?pe[t>>2]:0,s=t?pe[t+4>>2]:0,c=r?pe[r>>2]:0,u=r?pe[r+4>>2]:0,l=i?pe[i>>2]:0,h=i?pe[i+4>>2]:0,d=0,p=0,f=0,m=0,g=0,_=0,v=(t?pe[t>>2]:0)|(r?pe[r>>2]:0)|(i?pe[i>>2]:0),y=(t?pe[t+4>>2]:0)|(r?pe[r+4>>2]:0)|(i?pe[i+4>>2]:0),b=function(e,t,r,i){return e<32?t&i:r&i},E=0;E>2]=d,pe[t+4>>2]=p),r&&(pe[r>>2]=f,pe[r+4>>2]=m),i&&(pe[i>>2]=g,pe[i+4>>2]=_),a}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function ti(e,t,r){$r.varargs=r;try{var i=$r.getStreamFromFD(e);switch(t){case 0:return(n=$r.get())<0?-28:Yr.open(i.path,i.flags,0,n).fd;case 1:case 2:return 0;case 3:return i.flags;case 4:var n=$r.get();return i.flags|=n,0;case 12:return n=$r.get(),he[n+0>>1]=2,0;case 13:case 14:return 0;case 16:case 8:return-28;case 9:return Kr(28),-1;default:return-28}}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function ri(e){try{return $r.getStreamFromFD(e),0}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function ii(e,t,r,i){try{var n=$r.get64(r,i);return Yr.ftruncate(e,n),0}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function ni(){return 42}function ai(e,t,r){$r.varargs=r;try{var i=$r.getStreamFromFD(e);switch(t){case 21509:case 21505:return i.tty?0:-59;case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:return i.tty?0:-59;case 21519:if(!i.tty)return-59;var n=$r.get();return pe[n>>2]=0,0;case 21520:return i.tty?-28:-59;case 21531:return n=$r.get(),Yr.ioctl(i,t,n);case 21523:case 21524:return i.tty?0:-59;default:$e("bad ioctl syscall "+t)}}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function oi(e,t,r){return 0}function si(e,t){try{return e=$r.getStr(e),$r.doMkdir(e,t)}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function ci(e,t){return 0}function ui(e,t,r,i,n,a){var o;a<<=12;var s=!1;if(0!=(16&i)&&e%16384!=0)return-28;if(0!=(32&i)){if(!(o=vo(16384,t)))return-48;ro(o,0,t),s=!0}else{var c=Yr.getStream(n);if(!c)return-8;var u=Yr.mmap(c,e,t,a,r,i);o=u.ptr,s=u.allocated}return $r.mappings[o]={malloc:o,len:t,allocated:s,fd:n,prot:r,flags:i,offset:a},o}function li(e,t,r,i,n,a){try{return ui(e,t,r,i,n,a)}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function hi(e,t,r){try{var i=$r.mappings[e];return i?($r.doMsync(e,Yr.getStream(i.fd),t,i.flags,0),0):0}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function di(e,t){return 0}function pi(e,t){if(-1==(0|e)||0===t)return-28;var r=$r.mappings[e];if(!r)return 0;if(t===r.len){var i=Yr.getStream(r.fd);2&r.prot&&$r.doMsync(e,i,t,r.flags,r.offset),Yr.munmap(i),$r.mappings[e]=null,r.allocated&&to(r.malloc)}return 0}function fi(e,t){try{return pi(e,t)}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function mi(e,t,r){$r.varargs=r;try{var i=$r.getStr(e),n=$r.get();return Yr.open(i,t,n).fd}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function gi(){return-27}var _i={BUCKET_BUFFER_SIZE:8192,mount:function(e){return Yr.createNode(null,"/",16895,0)},createPipe:function(){var e={buckets:[]};e.buckets.push({buffer:new Uint8Array(_i.BUCKET_BUFFER_SIZE),offset:0,roffset:0});var t=_i.nextname(),r=_i.nextname(),i=Yr.createNode(_i.root,t,4096,0),n=Yr.createNode(_i.root,r,4096,0);i.pipe=e,n.pipe=e;var a=Yr.createStream({path:t,node:i,flags:Yr.modeStringToFlags("r"),seekable:!1,stream_ops:_i.stream_ops});i.stream=a;var o=Yr.createStream({path:r,node:n,flags:Yr.modeStringToFlags("w"),seekable:!1,stream_ops:_i.stream_ops});return n.stream=o,{readable_fd:a.fd,writable_fd:o.fd}},stream_ops:{poll:function(e){var t=e.node.pipe;if(1==(2097155&e.flags))return 260;if(t.buckets.length>0)for(var r=0;r0)return 65}return 0},ioctl:function(e,t,r){return Gr.EINVAL},fsync:function(e){return Gr.EINVAL},read:function(e,t,r,i,n){for(var a=e.node.pipe,o=0,s=0;s=s)return c.buffer.set(o,c.offset),c.offset+=s,s;u>0&&(c.buffer.set(o.subarray(0,u),c.offset),c.offset+=u,o=o.subarray(u,o.byteLength));for(var l=o.byteLength/_i.BUCKET_BUFFER_SIZE|0,h=o.byteLength%_i.BUCKET_BUFFER_SIZE,d=0;d0&&(p={buffer:new Uint8Array(_i.BUCKET_BUFFER_SIZE),offset:o.byteLength,roffset:0},a.buckets.push(p),p.buffer.set(o)),s},close:function(e){e.node.pipe.buckets=null}},nextname:function(){return _i.nextname.current||(_i.nextname.current=0),"pipe["+_i.nextname.current+++"]"}};function vi(e){try{if(0==e)throw new Yr.ErrnoError(21);var t=_i.createPipe();return pe[e>>2]=t.readable_fd,pe[e+4>>2]=t.writable_fd,0}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function yi(e,t,r,i,n,a){try{var o=$r.getStreamFromFD(e),s=$r.get64(n,a);return Yr.write(o,ue,t,r,s)}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function bi(e,t,r){try{var i=$r.getStreamFromFD(e);return Yr.read(i,ue,t,r)}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function Ei(e,t){try{return e=$r.getStr(e),t=$r.getStr(t),Yr.rename(e,t),0}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}var wi={mount:function(e){return u.websocket=u.websocket&&"object"==typeof u.websocket?u.websocket:{},u.websocket._callbacks={},u.websocket.on=function(e,t){return"function"==typeof t&&(this._callbacks[e]=t),this},u.websocket.emit=function(e,t){"function"==typeof this._callbacks[e]&&this._callbacks[e].call(this,t)},Yr.createNode(null,"/",16895,0)},createSocket:function(e,t,r){t&=-526337,r&&Z(1==t==(6==r));var i={family:e,type:t,protocol:r,server:null,error:null,peers:{},pending:[],recv_queue:[],sock_ops:wi.websocket_sock_ops},n=wi.nextname(),a=Yr.createNode(wi.root,n,49152,0);a.sock=i;var o=Yr.createStream({path:n,node:a,flags:Yr.modeStringToFlags("r+"),seekable:!1,stream_ops:wi.stream_ops});return i.stream=o,i},getSocket:function(e){var t=Yr.getStream(e);return t&&Yr.isSocket(t.node.mode)?t.node.sock:null},stream_ops:{poll:function(e){var t=e.node.sock;return t.sock_ops.poll(t)},ioctl:function(e,t,r){var i=e.node.sock;return i.sock_ops.ioctl(i,t,r)},read:function(e,t,r,i,n){var a=e.node.sock,o=a.sock_ops.recvmsg(a,i);return o?(t.set(o.buffer,r),o.buffer.length):0},write:function(e,t,r,i,n){var a=e.node.sock;return a.sock_ops.sendmsg(a,t,r,i)},close:function(e){var t=e.node.sock;t.sock_ops.close(t)}},nextname:function(){return wi.nextname.current||(wi.nextname.current=0),"socket["+wi.nextname.current+++"]"},websocket_sock_ops:{createPeer:function(e,t,i){var n;if("object"==typeof t&&(n=t,t=null,i=null),n)if(n._socket)t=n._socket.remoteAddress,i=n._socket.remotePort;else{var a=/ws[s]?:\/\/([^:]+):(\d+)/.exec(n.url);if(!a)throw new Error("WebSocket URL must be in the format ws(s)://address:port");t=a[1],i=parseInt(a[2],10)}else try{var o=u.websocket&&"object"==typeof u.websocket,s="ws:#".replace("#","//");if(o&&"string"==typeof u.websocket.url&&(s=u.websocket.url),"ws://"===s||"wss://"===s){var c=t.split("/");s=s+c[0]+":"+i+"/"+c.slice(1).join("/")}var l="binary";o&&"string"==typeof u.websocket.subprotocol&&(l=u.websocket.subprotocol);var h=void 0;"null"!==l&&(l=l.replace(/^ +| +$/g,"").split(/ *, */),h=_?{protocol:l.toString()}:l),o&&null===u.websocket.subprotocol&&(l="null",h=void 0),(n=new(_?r(265):WebSocket)(s,h)).binaryType="arraybuffer"}catch(e){throw new Yr.ErrnoError(Gr.EHOSTUNREACH)}var d={addr:t,port:i,socket:n,dgram_send_queue:[]};return wi.websocket_sock_ops.addPeer(e,d),wi.websocket_sock_ops.handlePeerEvents(e,d),2===e.type&&void 0!==e.sport&&d.dgram_send_queue.push(new Uint8Array([255,255,255,255,"p".charCodeAt(0),"o".charCodeAt(0),"r".charCodeAt(0),"t".charCodeAt(0),(65280&e.sport)>>8,255&e.sport])),d},getPeer:function(e,t,r){return e.peers[t+":"+r]},addPeer:function(e,t){e.peers[t.addr+":"+t.port]=t},removePeer:function(e,t){delete e.peers[t.addr+":"+t.port]},handlePeerEvents:function(e,t){var r=!0,i=function(){u.websocket.emit("open",e.stream.fd);try{for(var r=t.dgram_send_queue.shift();r;)t.socket.send(r),r=t.dgram_send_queue.shift()}catch(e){t.socket.close()}};function n(i){if("string"==typeof i)i=(new TextEncoder).encode(i);else{if(Z(void 0!==i.byteLength),0==i.byteLength)return;i=new Uint8Array(i)}var n=r;if(r=!1,n&&10===i.length&&255===i[0]&&255===i[1]&&255===i[2]&&255===i[3]&&i[4]==="p".charCodeAt(0)&&i[5]==="o".charCodeAt(0)&&i[6]==="r".charCodeAt(0)&&i[7]==="t".charCodeAt(0)){var a=i[8]<<8|i[9];return wi.websocket_sock_ops.removePeer(e,t),t.port=a,void wi.websocket_sock_ops.addPeer(e,t)}e.recv_queue.push({addr:t.addr,port:t.port,data:i}),u.websocket.emit("message",e.stream.fd)}_?(t.socket.on("open",i),t.socket.on("message",(function(e,t){t.binary&&n(new Uint8Array(e).buffer)})),t.socket.on("close",(function(){u.websocket.emit("close",e.stream.fd)})),t.socket.on("error",(function(t){e.error=Gr.ECONNREFUSED,u.websocket.emit("error",[e.stream.fd,e.error,"ECONNREFUSED: Connection refused"])}))):(t.socket.onopen=i,t.socket.onclose=function(){u.websocket.emit("close",e.stream.fd)},t.socket.onmessage=function(e){n(e.data)},t.socket.onerror=function(t){e.error=Gr.ECONNREFUSED,u.websocket.emit("error",[e.stream.fd,e.error,"ECONNREFUSED: Connection refused"])})},poll:function(e){if(1===e.type&&e.server)return e.pending.length?65:0;var t=0,r=1===e.type?wi.websocket_sock_ops.getPeer(e,e.daddr,e.dport):null;return(e.recv_queue.length||!r||r&&r.socket.readyState===r.socket.CLOSING||r&&r.socket.readyState===r.socket.CLOSED)&&(t|=65),(!r||r&&r.socket.readyState===r.socket.OPEN)&&(t|=4),(r&&r.socket.readyState===r.socket.CLOSING||r&&r.socket.readyState===r.socket.CLOSED)&&(t|=16),t},ioctl:function(e,t,r){switch(t){case 21531:var i=0;return e.recv_queue.length&&(i=e.recv_queue[0].data.length),pe[r>>2]=i,0;default:return Gr.EINVAL}},close:function(e){if(e.server){try{e.server.close()}catch(e){}e.server=null}for(var t=Object.keys(e.peers),r=0;r>>0}function ki(e){return parseInt(e)}function xi(e){var t,r,i,n,a=[];if(!/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i.test(e))return null;if("::"===e)return[0,0,0,0,0,0,0,0];for((e=0===e.indexOf("::")?e.replace("::","Z:"):e.replace("::",":Z:")).indexOf(".")>0?((t=(e=e.replace(new RegExp("[.]","g"),":")).split(":"))[t.length-4]=ki(t[t.length-4])+256*ki(t[t.length-3]),t[t.length-3]=ki(t[t.length-2])+256*ki(t[t.length-1]),t=t.slice(0,t.length-2)):t=e.split(":"),i=0,n=0,r=0;r>8&255)+"."+(e>>16&255)+"."+(e>>24&255)}function ji(e){var t="",r=0,i=0,n=0,a=0,o=0,s=0,c=[65535&e[0],e[0]>>16,65535&e[1],e[1]>>16,65535&e[2],e[2]>>16,65535&e[3],e[3]>>16],u=!0,l="";for(s=0;s<5;s++)if(0!==c[s]){u=!1;break}if(u){if(l=Ni(c[6]|c[7]<<16),-1===c[5])return t="::ffff:",t+=l;if(0===c[5])return t="::","0.0.0.0"===l&&(l=""),"0.0.0.1"===l&&(l="1"),t+=l}for(r=0;r<8;r++)0===c[r]&&(r-n>1&&(o=0),n=r,o++),o>i&&(a=r-(i=o)+1);for(r=0;r<8;r++)i>1&&0===c[r]&&r>=a&&r>1],n=oo(de[e+2>>1]);switch(i){case 2:if(16!==t)return{errno:28};r=Ni(r=pe[e+4>>2]);break;case 10:if(28!==t)return{errno:28};r=ji(r=[pe[e+8>>2],pe[e+12>>2],pe[e+16>>2],pe[e+20>>2]]);break;default:return{errno:5}}return{family:i,addr:r,port:n}}function Ri(e,t,r,i){switch(t){case 2:r=Si(r),he[e>>1]=t,pe[e+4>>2]=r,he[e+2>>1]=ao(i);break;case 10:r=xi(r),pe[e>>2]=t,pe[e+8>>2]=r[0],pe[e+12>>2]=r[1],pe[e+16>>2]=r[2],pe[e+20>>2]=r[3],he[e+2>>1]=ao(i),pe[e+4>>2]=0,pe[e+24>>2]=0;break;default:return{errno:5}}return{}}function Ii(e,t){try{$r.varargs=t;var r=function(){var e=wi.getSocket($r.get());if(!e)throw new Yr.ErrnoError(8);return e},i=function(e){var t=$r.get(),r=$r.get();if(e&&0===t)return null;var i=Ti(t,r);if(i.errno)throw new Yr.ErrnoError(i.errno);return i.addr=Mi.lookup_addr(i.addr)||i.addr,i};switch(e){case 1:var n=$r.get(),a=$r.get(),o=$r.get();return Z((s=wi.createSocket(n,a,o)).stream.fd<64),s.stream.fd;case 2:var s=r(),c=i();return s.sock_ops.bind(s,c.addr,c.port),0;case 3:return s=r(),c=i(),s.sock_ops.connect(s,c.addr,c.port),0;case 4:s=r();var u=$r.get();return s.sock_ops.listen(s,u),0;case 5:s=r();var l=$r.get(),h=($r.get(),s.sock_ops.accept(s));return l&&Z(!Ri(l,h.family,Mi.lookup_name(h.daddr),h.dport).errno),h.stream.fd;case 6:return s=r(),l=$r.get(),$r.get(),Z(!Ri(l,s.family,Mi.lookup_name(s.saddr||"0.0.0.0"),s.sport).errno),0;case 7:return s=r(),l=$r.get(),$r.get(),s.daddr?(Z(!Ri(l,s.family,Mi.lookup_name(s.daddr),s.dport).errno),0):-53;case 11:s=r();var d=$r.get(),p=$r.get(),f=($r.get(),i(!0));return f?s.sock_ops.sendmsg(s,ue,d,p,f.addr,f.port):Yr.write(s.stream,ue,d,p);case 12:s=r();var m=$r.get(),g=$r.get();return $r.get(),l=$r.get(),$r.get(),(A=s.sock_ops.recvmsg(s,g))?(l&&Z(!Ri(l,s.family,Mi.lookup_name(A.addr),A.port).errno),le.set(A.buffer,m),A.buffer.byteLength):0;case 14:return-50;case 15:s=r();var _=$r.get(),v=$r.get(),y=$r.get(),b=$r.get();return 1===_&&4===v?(pe[y>>2]=s.error,pe[b>>2]=4,s.error=null,0):-50;case 16:s=r(),d=$r.get(),$r.get();var E,w=pe[d+8>>2],S=pe[d+12>>2],k=pe[d>>2],x=pe[d+4>>2];if(k){if((c=Ti(k,x)).errno)return-c.errno;E=c.port,l=Mi.lookup_addr(c.addr)||c.addr}for(var M=0,N=0;N>2];var j=new Uint8Array(M),T=0;for(N=0;N>2],I=pe[w+(8*N+4)>>2],O=0;O>0];return s.sock_ops.sendmsg(s,j,0,M,l,E);case 17:for(s=r(),d=$r.get(),$r.get(),w=pe[d+8>>2],S=pe[d+12>>2],M=0,N=0;N>2];var A;if(!(A=s.sock_ops.recvmsg(s,M)))return 0;(k=pe[d>>2])&&Z(!Ri(k,s.family,Mi.lookup_name(A.addr),A.port).errno);var P=0,D=A.buffer.byteLength;for(N=0;D>0&&N>2],(I=pe[w+(8*N+4)>>2])&&(p=Math.min(I,D),m=A.buffer.subarray(P,P+p),le.set(m,R+P),P+=p,D-=p);return P;default:return-52}}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function Oi(e,t){try{return e=$r.getStr(e),$r.doStat(Yr.stat,e,t)}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),-e.errno}}function Ai(e){switch(e){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+e)}}function Pi(){for(var e=new Array(256),t=0;t<256;++t)e[t]=String.fromCharCode(t);Di=e}var Di=void 0;function Fi(e){for(var t="",r=e;le[r];)t+=Di[le[r++]];return t}var Ci={},Bi={},zi={},Li=48,Ui=57;function Hi(e){if(void 0===e)return"_unknown";var t=(e=e.replace(/[^a-zA-Z0-9_]/g,"$")).charCodeAt(0);return t>=Li&&t<=Ui?"_"+e:e}function qi(e,t){return e=Hi(e),function(){"use strict";return t.apply(this,arguments)}}function Ki(e,t){var r=qi(t,(function(e){this.name=t,this.message=e;var r=new Error(e).stack;void 0!==r&&(this.stack=this.toString()+"\n"+r.replace(/^Error(:[^\n]*)?\n/,""))}));return r.prototype=Object.create(e.prototype),r.prototype.constructor=r,r.prototype.toString=function(){return void 0===this.message?this.name:this.name+": "+this.message},r}var Zi=void 0;function Wi(e){throw new Zi(e)}var Xi=void 0;function Qi(e){throw new Xi(e)}function Ji(e,t,r){function i(t){var i=r(t);i.length!==e.length&&Qi("Mismatched type converter count");for(var n=0;n>a])},destructorFunction:null})}var Yi=[],$i=[{},{value:void 0},{value:null},{value:!0},{value:!1}];function en(e){e>4&&0==--$i[e].refcount&&($i[e]=void 0,Yi.push(e))}function tn(){for(var e=0,t=5;t<$i.length;++t)void 0!==$i[t]&&++e;return e}function rn(){for(var e=5;e<$i.length;++e)if(void 0!==$i[e])return $i[e];return null}function nn(){u.count_emval_handles=tn,u.get_first_emval=rn}function an(e){switch(e){case void 0:return 1;case null:return 2;case!0:return 3;case!1:return 4;default:var t=Yi.length?Yi.pop():$i.length;return $i[t]={refcount:1,value:e},t}}function on(e){return this.fromWireType(fe[e>>2])}function sn(e,t){Vi(e,{name:t=Fi(t),fromWireType:function(e){var t=$i[e].value;return en(e),t},toWireType:function(e,t){return an(t)},argPackAdvance:8,readValueFromPointer:on,destructorFunction:null})}function cn(e){if(null===e)return"null";var t=typeof e;return"object"===t||"array"===t||"function"===t?e.toString():""+e}function un(e,t){switch(t){case 2:return function(e){return this.fromWireType(me[e>>2])};case 3:return function(e){return this.fromWireType(ge[e>>3])};default:throw new TypeError("Unknown float type: "+e)}}function ln(e,t,r){var i=Ai(r);Vi(e,{name:t=Fi(t),fromWireType:function(e){return e},toWireType:function(e,t){if("number"!=typeof t&&"boolean"!=typeof t)throw new TypeError('Cannot convert "'+cn(t)+'" to '+this.name);return t},argPackAdvance:8,readValueFromPointer:un(t,i),destructorFunction:null})}function hn(e){for(;e.length;){var t=e.pop();e.pop()(t)}}function dn(e,t,r,i,n){var a=t.length;a<2&&Wi("argTypes array size mismatch! Must at least get return value and 'this' types!");for(var o=null!==t[1]&&null!==r,s=!1,c=1;c>2)+i]);return r}function gn(e,t,r){u.hasOwnProperty(e)||Qi("Replacing nonexistant public symbol"),void 0!==u[e].overloadTable&&void 0!==r?u[e].overloadTable[r]=t:(u[e]=t,u[e].argCount=r)}function _n(e,t){e=Fi(e);var r=function(e){var r=[t];return function(){r.length=arguments.length+1;for(var t=0;t>1]}:function(e){return de[e>>1]};case 2:return r?function(e){return pe[e>>2]}:function(e){return fe[e>>2]};default:throw new TypeError("Unknown integer type: "+e)}}function kn(e,t,r,i,n){t=Fi(t),-1===n&&(n=4294967295);var a=Ai(r),o=function(e){return e};if(0===i){var s=32-8*r;o=function(e){return e<>>s}}var c=-1!=t.indexOf("unsigned");Vi(e,{name:t,fromWireType:o,toWireType:function(e,r){if("number"!=typeof r&&"boolean"!=typeof r)throw new TypeError('Cannot convert "'+cn(r)+'" to '+this.name);if(rn)throw new TypeError('Passing a number "'+cn(r)+'" from JS side to C/C++ side to an argument of type "'+t+'", which is outside the valid range ['+i+", "+n+"]!");return c?r>>>0:0|r},argPackAdvance:8,readValueFromPointer:Sn(t,a,0!==i),destructorFunction:null})}function xn(e,t,r){var i=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array][t];function n(e){var t=fe,r=t[e>>=2],n=t[e+1];return new i(ce,n,r)}Vi(e,{name:r=Fi(r),fromWireType:n,argPackAdvance:8,readValueFromPointer:n},{ignoreDuplicateRegistrations:!0})}function Mn(e,t){var r="std::string"===(t=Fi(t));Vi(e,{name:t,fromWireType:function(e){var t,i=fe[e>>2];if(r)for(var n=e+4,a=0;a<=i;++a){var o=e+4+a;if(a==i||0==le[o]){var s=Q(n,o-n);void 0===t?t=s:(t+=String.fromCharCode(0),t+=s),n=o+1}}else{var c=new Array(i);for(a=0;a>2]=n,r&&i)V(t,a+4,n+1);else if(i)for(var o=0;o255&&(to(a),Wi("String has UTF-16 code units that do not fit in 8 bits")),le[a+4+o]=s}else for(o=0;o>2],o=a(),c=e+4,u=0;u<=n;++u){var l=e+4+u*t;if(u==n||0==o[l>>s]){var h=i(c,l-c);void 0===r?r=h:(r+=String.fromCharCode(0),r+=h),c=l+t}}return to(e),r},toWireType:function(e,i){"string"!=typeof i&&Wi("Cannot pass non-string to C++ string type "+r);var a=o(i),c=no(4+a+t);return fe[c>>2]=a>>s,n(i,c+4,a+t),null!==e&&e.push(to,c),c},argPackAdvance:8,readValueFromPointer:on,destructorFunction:function(e){to(e)}})}function jn(e,t){Vi(e,{isVoid:!0,name:t=Fi(t),argPackAdvance:0,fromWireType:function(){},toWireType:function(e,t){}})}function Tn(e,t){var r=Bi[e];return void 0===r&&Wi(t+" has unknown type "+bn(e)),r}function Rn(e,t){for(var r=new Array(e),i=0;i>2)+i],"parameter "+i);return r}function In(e){return e||Wi("Cannot use deleted val. handle = "+e),$i[e].value}function On(e,t,r,i){e=In(e);for(var n=Rn(t,r),a=new Array(t),o=0;o4&&($i[e].refcount+=1)}function Dn(e,t){return an((e=Tn(e,"_emval_take_value")).readValueFromPointer(t))}function Fn(e){Fs(e)}function Cn(e){return Fn(e)}function Bn(){$e()}vn=_?function(){var e=i.hrtime();return 1e3*e[0]+e[1]/1e6}:"undefined"!=typeof dateNow?dateNow:function(){return performance.now()};var zn=!0;function Ln(e,t){var r;if(0===e)r=Date.now();else{if(1!==e&&4!==e||!zn)return Kr(28),-1;r=vn()}return pe[t>>2]=r/1e3|0,pe[t+4>>2]=r%1e3*1e3*1e3|0,0}function Un(){return 1318384}function Hn(e,t,r){le.copyWithin(e,t,t+r)}function qn(){return le.length}function Kn(e){try{return z.grow(e-ce.byteLength+65535>>>16),ye(z.buffer),1}catch(t){console.error("emscripten_realloc_buffer: Attempted to grow heap from "+ce.byteLength+" bytes to "+e+" bytes, but got error: "+t)}}function Zn(e){e>>>=0;var t=qn();if(Z(e>t),e>2147483648)return N("Cannot enlarge memory, asked to go up to "+e+" bytes, but the limit is 2147483648 bytes!"),!1;for(var r=1;r<=4;r*=2){var i=t*(1+.2/r);i=Math.min(i,e+100663296);var n=Math.min(2147483648,ve(Math.max(16777216,e,i),65536)),a=vn(),o=Kn(n),s=vn();if(console.log("Heap resize call from "+t+" to "+n+" took "+(s-a)+" msecs. Success: "+!!o),o)return!0}return N("Failed to grow the heap from "+t+" bytes to "+n+" bytes, not enough memory!"),!1}var Wn={};function Xn(){return p||"./this.program"}function Qn(){if(!Qn.strings){var e={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:Xn()};for(var t in Wn)e[t]=Wn[t];var r=[];for(var t in e)r.push(t+"="+e[t]);Qn.strings=r}return Qn.strings}function Jn(e,t){var r=0;return Qn().forEach((function(i,n){var a=t+r;pe[e+4*n>>2]=a,se(i,a),r+=i.length+1})),0}function Vn(e,t){var r=Qn();pe[e>>2]=r.length;var i=0;return r.forEach((function(e){i+=e.length+1})),pe[t>>2]=i,0}function Gn(e){try{var t=$r.getStreamFromFD(e);return Yr.close(t),0}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),e.errno}}function Yn(e,t,r,i){try{var n=$r.getStreamFromFD(e),a=$r.doReadv(n,t,r);return pe[i>>2]=a,0}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),e.errno}}function $n(e,t,r,i,n){try{var a=$r.getStreamFromFD(e),o=4294967296*r+(t>>>0);return o<=-9007199254740992||o>=9007199254740992?-61:(Yr.llseek(a,o,i),st=[a.position>>>0,(ot=a.position,+He(ot)>=1?ot>0?(0|Ze(+Ke(ot/4294967296),4294967295))>>>0:~~+qe((ot-+(~~ot>>>0))/4294967296)>>>0:0)],pe[n>>2]=st[0],pe[n+4>>2]=st[1],a.getdents&&0===o&&0===i&&(a.getdents=null),0)}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),e.errno}}function ea(e,t,r,i){try{var n=$r.getStreamFromFD(e),a=$r.doWritev(n,t,r);return pe[i>>2]=a,0}catch(e){return void 0!==Yr&&e instanceof Yr.ErrnoError||$e(e),e.errno}}function ta(e){var t=Date.now();return pe[e>>2]=t/1e3|0,he[e+4>>1]=t%1e3,he[e+6>>1]=0,he[e+8>>1]=0,0}function ra(){return 0|H()}function ia(e){var t=Date.now();return pe[e>>2]=t/1e3|0,pe[e+4>>2]=t%1e3*1e3|0,0}var na=1318400,aa=(V("GMT",1318448,4),1318448);function oa(e,t){var r=new Date(1e3*pe[e>>2]);pe[t>>2]=r.getUTCSeconds(),pe[t+4>>2]=r.getUTCMinutes(),pe[t+8>>2]=r.getUTCHours(),pe[t+12>>2]=r.getUTCDate(),pe[t+16>>2]=r.getUTCMonth(),pe[t+20>>2]=r.getUTCFullYear()-1900,pe[t+24>>2]=r.getUTCDay(),pe[t+36>>2]=0,pe[t+32>>2]=0;var i=Date.UTC(r.getUTCFullYear(),0,1,0,0,0,0),n=(r.getTime()-i)/864e5|0;return pe[t+28>>2]=n,pe[t+40>>2]=aa,t}function sa(e){return oa(e,na)}function ca(e){return e}function ua(){if(!ua.called){ua.called=!0,pe[lo()>>2]=60*(new Date).getTimezoneOffset();var e=(new Date).getFullYear(),t=new Date(e,0,1),r=new Date(e,6,1);pe[uo()>>2]=Number(t.getTimezoneOffset()!=r.getTimezoneOffset());var i=s(t),n=s(r),a=ae(i),o=ae(n);r.getTimezoneOffset()>2]=a,pe[co()+4>>2]=o):(pe[co()>>2]=o,pe[co()+4>>2]=a)}function s(e){var t=e.toTimeString().match(/\(([A-Za-z ]+)\)$/);return t?t[1]:"GMT"}}function la(e){ua();var t=new Date(pe[e+20>>2]+1900,pe[e+16>>2],pe[e+12>>2],pe[e+8>>2],pe[e+4>>2],pe[e>>2],0),r=pe[e+32>>2],i=t.getTimezoneOffset(),n=new Date(t.getFullYear(),0,1),a=new Date(t.getFullYear(),6,1).getTimezoneOffset(),o=n.getTimezoneOffset(),s=Math.min(o,a);if(r<0)pe[e+32>>2]=Number(a!=o&&s==i);else if(r>0!=(s==i)){var c=Math.max(o,a),u=r>0?s:c;t.setTime(t.getTime()+6e4*(u-i))}pe[e+24>>2]=t.getDay();var l=(t.getTime()-n.getTime())/864e5|0;return pe[e+28>>2]=l,t.getTime()/1e3|0}function ha(e){for(var t=vn();vn()-t>2],i=pe[e+4>>2];return i<0||i>999999999||r<0?(Kr(28),-1):(0!==t&&(pe[t>>2]=0,pe[t+4>>2]=0),ha(1e6*r+i/1e3))}function pa(e){return 0}function fa(e,t){return 0}function ma(e){return 0}function ga(){}function _a(){return 0}function va(){return 0}function ya(){return 0}function ba(){return 6}function Ea(){}function wa(){}function Sa(){}function ka(){}function xa(){}function Ma(e,t,r){return N("pthread_sigmask() is not supported: this is a no-op."),0}function Na(){N("missing function: rx_seedheight"),$e(-1)}function ja(){N("missing function: rx_slow_hash"),$e(-1)}function Ta(e){U(0|e)}function Ra(e){return pe[e>>2]=-1>>>0,0}function Ia(e){return e%4==0&&(e%100!=0||e%400==0)}function Oa(e,t){for(var r=0,i=0;i<=t;r+=e[i++]);return r}var Aa=[31,29,31,30,31,30,31,31,30,31,30,31],Pa=[31,28,31,30,31,30,31,31,30,31,30,31];function Da(e,t){for(var r=new Date(e.getTime());t>0;){var i=Ia(r.getFullYear()),n=r.getMonth(),a=(i?Aa:Pa)[n];if(!(t>a-r.getDate()))return r.setDate(r.getDate()+t),r;t-=a-r.getDate()+1,r.setDate(1),n<11?r.setMonth(n+1):(r.setMonth(0),r.setFullYear(r.getFullYear()+1))}return r}function Fa(e,t,r,i){var n=pe[i+40>>2],a={tm_sec:pe[i>>2],tm_min:pe[i+4>>2],tm_hour:pe[i+8>>2],tm_mday:pe[i+12>>2],tm_mon:pe[i+16>>2],tm_year:pe[i+20>>2],tm_wday:pe[i+24>>2],tm_yday:pe[i+28>>2],tm_isdst:pe[i+32>>2],tm_gmtoff:pe[i+36>>2],tm_zone:n?Q(n):""},o=Q(r),s={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var c in s)o=o.replace(new RegExp(c,"g"),s[c]);var u=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],l=["January","February","March","April","May","June","July","August","September","October","November","December"];function h(e,t,r){for(var i="number"==typeof e?e.toString():e||"";i.length0?1:0}var i;return 0===(i=r(e.getFullYear()-t.getFullYear()))&&0===(i=r(e.getMonth()-t.getMonth()))&&(i=r(e.getDate()-t.getDate())),i}function f(e){switch(e.getDay()){case 0:return new Date(e.getFullYear()-1,11,29);case 1:return e;case 2:return new Date(e.getFullYear(),0,3);case 3:return new Date(e.getFullYear(),0,2);case 4:return new Date(e.getFullYear(),0,1);case 5:return new Date(e.getFullYear()-1,11,31);case 6:return new Date(e.getFullYear()-1,11,30)}}function m(e){var t=Da(new Date(e.tm_year+1900,0,1),e.tm_yday),r=new Date(t.getFullYear(),0,4),i=new Date(t.getFullYear()+1,0,4),n=f(r),a=f(i);return p(n,t)<=0?p(a,t)<=0?t.getFullYear()+1:t.getFullYear():t.getFullYear()-1}var g={"%a":function(e){return u[e.tm_wday].substring(0,3)},"%A":function(e){return u[e.tm_wday]},"%b":function(e){return l[e.tm_mon].substring(0,3)},"%B":function(e){return l[e.tm_mon]},"%C":function(e){return d((e.tm_year+1900)/100|0,2)},"%d":function(e){return d(e.tm_mday,2)},"%e":function(e){return h(e.tm_mday,2," ")},"%g":function(e){return m(e).toString().substring(2)},"%G":function(e){return m(e)},"%H":function(e){return d(e.tm_hour,2)},"%I":function(e){var t=e.tm_hour;return 0==t?t=12:t>12&&(t-=12),d(t,2)},"%j":function(e){return d(e.tm_mday+Oa(Ia(e.tm_year+1900)?Aa:Pa,e.tm_mon-1),3)},"%m":function(e){return d(e.tm_mon+1,2)},"%M":function(e){return d(e.tm_min,2)},"%n":function(){return"\n"},"%p":function(e){return e.tm_hour>=0&&e.tm_hour<12?"AM":"PM"},"%S":function(e){return d(e.tm_sec,2)},"%t":function(){return"\t"},"%u":function(e){return e.tm_wday||7},"%U":function(e){var t=new Date(e.tm_year+1900,0,1),r=0===t.getDay()?t:Da(t,7-t.getDay()),i=new Date(e.tm_year+1900,e.tm_mon,e.tm_mday);if(p(r,i)<0){var n=Oa(Ia(i.getFullYear())?Aa:Pa,i.getMonth()-1)-31,a=31-r.getDate()+n+i.getDate();return d(Math.ceil(a/7),2)}return 0===p(r,t)?"01":"00"},"%V":function(e){var t,r=new Date(e.tm_year+1900,0,4),i=new Date(e.tm_year+1901,0,4),n=f(r),a=f(i),o=Da(new Date(e.tm_year+1900,0,1),e.tm_yday);return p(o,n)<0?"53":p(a,o)<=0?"01":(t=n.getFullYear()=0;return t=(t=Math.abs(t)/60)/60*100+t%60,(r?"+":"-")+String("0000"+t).slice(-4)},"%Z":function(e){return e.tm_zone},"%%":function(){return"%"}};for(var c in g)o.indexOf(c)>=0&&(o=o.replace(new RegExp(c,"g"),g[c](a)));var _=Va(o,!1);return _.length>t?0:(oe(_,e),_.length-1)}function Ca(e,t,r,i){return Fa(e,t,r,i)}function Ba(e){switch(e){case 30:return 16384;case 85:return 131072;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:case 79:return 200809;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1;case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32;case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1e3;case 89:return 700;case 71:return 256;case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:return"object"==typeof navigator&&navigator.hardwareConcurrency||1}return Kr(28),-1}function za(e){var t=Date.now()/1e3|0;return e&&(pe[e>>2]=t),t}function La(){N("missing function: v4_generate_JIT_code"),$e(-1)}function Ua(e,t){if(qa.mainLoop.timingMode=e,qa.mainLoop.timingValue=t,!qa.mainLoop.func)return console.error("emscripten_set_main_loop_timing: Cannot set timing mode for main loop since a main loop does not exist! Call emscripten_set_main_loop first to set one up."),1;if(0==e)qa.mainLoop.scheduler=function(){var e=0|Math.max(0,qa.mainLoop.tickStartTime+t-vn());setTimeout(qa.mainLoop.runner,e)},qa.mainLoop.method="timeout";else if(1==e)qa.mainLoop.scheduler=function(){qa.requestAnimationFrame(qa.mainLoop.runner)},qa.mainLoop.method="rAF";else if(2==e){if(void 0===o){var r=[];addEventListener("message",(function(e){"setimmediate"!==e.data&&"setimmediate"!==e.data.target||(e.stopPropagation(),r.shift()())}),!0),o=function(e){r.push(e),g?(void 0===u.setImmediates&&(u.setImmediates=[]),u.setImmediates.push(e),postMessage({target:"setimmediate"})):postMessage("setimmediate","*")}}qa.mainLoop.scheduler=function(){o(qa.mainLoop.runner)},qa.mainLoop.method="immediate"}return 0}function Ha(e,t,r,i,n){var a;B=!0,Z(!qa.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters."),qa.mainLoop.func=e,qa.mainLoop.arg=i,a=void 0!==i?function(){u.dynCall_vi(e,i)}:function(){u.dynCall_v(e)};var o=qa.mainLoop.currentlyRunningMainloop;if(qa.mainLoop.runner=function(){if(!K)if(qa.mainLoop.queue.length>0){var e=Date.now(),t=qa.mainLoop.queue.shift();if(t.func(t.arg),qa.mainLoop.remainingBlockers){var r=qa.mainLoop.remainingBlockers,i=r%1==0?r-1:Math.floor(r);t.counted?qa.mainLoop.remainingBlockers=i:(i+=.5,qa.mainLoop.remainingBlockers=(8*r+i)/9)}if(console.log('main loop blocker "'+t.name+'" took '+(Date.now()-e)+" ms"),qa.mainLoop.updateStatus(),o1&&qa.mainLoop.currentFrameNumber%qa.mainLoop.timingValue!=0?qa.mainLoop.scheduler():(0==qa.mainLoop.timingMode&&(qa.mainLoop.tickStartTime=vn()),"timeout"===qa.mainLoop.method&&u.ctx&&(R("Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!"),qa.mainLoop.method=""),qa.mainLoop.runIter(a),Ne(),o0?Ua(0,1e3/t):Ua(1,1),qa.mainLoop.scheduler()),r)throw"unwind"}var qa={mainLoop:{scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){qa.mainLoop.scheduler=null,qa.mainLoop.currentlyRunningMainloop++},resume:function(){qa.mainLoop.currentlyRunningMainloop++;var e=qa.mainLoop.timingMode,t=qa.mainLoop.timingValue,r=qa.mainLoop.func;qa.mainLoop.func=null,Ha(r,0,!1,qa.mainLoop.arg,!0),Ua(e,t),qa.mainLoop.scheduler()},updateStatus:function(){if(u.setStatus){var e=u.statusMessage||"Please wait...",t=qa.mainLoop.remainingBlockers,r=qa.mainLoop.expectedBlockers;t?t=6;){var o=i>>n-6&63;n-=6,r+=t[o]}return 2==n?(r+=t[(3&i)<<4],r+="=="):4==n&&(r+=t[(15&i)<<2],r+="="),r}(e),a(l))},l.src=c,qa.safeSetTimeout((function(){a(l)}),1e4)}};u.preloadPlugins.push(t);var r=u.canvas;r&&(r.requestPointerLock=r.requestPointerLock||r.mozRequestPointerLock||r.webkitRequestPointerLock||r.msRequestPointerLock||function(){},r.exitPointerLock=document.exitPointerLock||document.mozExitPointerLock||document.webkitExitPointerLock||document.msExitPointerLock||function(){},r.exitPointerLock=r.exitPointerLock.bind(document),document.addEventListener("pointerlockchange",i,!1),document.addEventListener("mozpointerlockchange",i,!1),document.addEventListener("webkitpointerlockchange",i,!1),document.addEventListener("mspointerlockchange",i,!1),u.elementPointerLock&&r.addEventListener("click",(function(e){!qa.pointerLock&&u.canvas.requestPointerLock&&(u.canvas.requestPointerLock(),e.preventDefault())}),!1))}function i(){qa.pointerLock=document.pointerLockElement===u.canvas||document.mozPointerLockElement===u.canvas||document.webkitPointerLockElement===u.canvas||document.msPointerLockElement===u.canvas}},createContext:function(e,t,r,i){if(t&&u.ctx&&e==u.canvas)return u.ctx;var n,a;if(t){var o={antialias:!1,alpha:!1,majorVersion:1};if(i)for(var s in i)o[s]=i[s];"undefined"!=typeof GL&&(a=GL.createContext(e,o))&&(n=GL.getContext(a).GLctx)}else n=e.getContext("2d");return n?(r&&(t||Z("undefined"==typeof GLctx,"cannot set in module if GLctx is used, but we are a non-GL context that would replace it"),u.ctx=n,t&&GL.makeContextCurrent(a),u.useWebGL=t,qa.moduleContextCreatedCallbacks.forEach((function(e){e()})),qa.init()),n):null},destroyContext:function(e,t,r){},fullscreenHandlersInstalled:!1,lockPointer:void 0,resizeCanvas:void 0,requestFullscreen:function(e,t){qa.lockPointer=e,qa.resizeCanvas=t,void 0===qa.lockPointer&&(qa.lockPointer=!0),void 0===qa.resizeCanvas&&(qa.resizeCanvas=!1);var r=u.canvas;function i(){qa.isFullscreen=!1;var e=r.parentNode;(document.fullscreenElement||document.mozFullScreenElement||document.msFullscreenElement||document.webkitFullscreenElement||document.webkitCurrentFullScreenElement)===e?(r.exitFullscreen=qa.exitFullscreen,qa.lockPointer&&r.requestPointerLock(),qa.isFullscreen=!0,qa.resizeCanvas?qa.setFullscreenCanvasSize():qa.updateCanvasDimensions(r)):(e.parentNode.insertBefore(r,e),e.parentNode.removeChild(e),qa.resizeCanvas?qa.setWindowedCanvasSize():qa.updateCanvasDimensions(r)),u.onFullScreen&&u.onFullScreen(qa.isFullscreen),u.onFullscreen&&u.onFullscreen(qa.isFullscreen)}qa.fullscreenHandlersInstalled||(qa.fullscreenHandlersInstalled=!0,document.addEventListener("fullscreenchange",i,!1),document.addEventListener("mozfullscreenchange",i,!1),document.addEventListener("webkitfullscreenchange",i,!1),document.addEventListener("MSFullscreenChange",i,!1));var n=document.createElement("div");r.parentNode.insertBefore(n,r),n.appendChild(r),n.requestFullscreen=n.requestFullscreen||n.mozRequestFullScreen||n.msRequestFullscreen||(n.webkitRequestFullscreen?function(){n.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}:null)||(n.webkitRequestFullScreen?function(){n.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT)}:null),n.requestFullscreen()},requestFullScreen:function(){$e("Module.requestFullScreen has been replaced by Module.requestFullscreen (without a capital S)")},exitFullscreen:function(){return!!qa.isFullscreen&&((document.exitFullscreen||document.cancelFullScreen||document.mozCancelFullScreen||document.msExitFullscreen||document.webkitCancelFullScreen||function(){}).apply(document,[]),!0)},nextRAF:0,fakeRequestAnimationFrame:function(e){var t=Date.now();if(0===qa.nextRAF)qa.nextRAF=t+1e3/60;else for(;t+2>=qa.nextRAF;)qa.nextRAF+=1e3/60;var r=Math.max(qa.nextRAF-t,0);setTimeout(e,r)},requestAnimationFrame:function(e){"function"!=typeof requestAnimationFrame?(0,qa.fakeRequestAnimationFrame)(e):requestAnimationFrame(e)},safeCallback:function(e){return function(){if(!K)return e.apply(null,arguments)}},allowAsyncCallbacks:!0,queuedAsyncCallbacks:[],pauseAsyncCallbacks:function(){qa.allowAsyncCallbacks=!1},resumeAsyncCallbacks:function(){if(qa.allowAsyncCallbacks=!0,qa.queuedAsyncCallbacks.length>0){var e=qa.queuedAsyncCallbacks;qa.queuedAsyncCallbacks=[],e.forEach((function(e){e()}))}},safeRequestAnimationFrame:function(e){return qa.requestAnimationFrame((function(){K||(qa.allowAsyncCallbacks?e():qa.queuedAsyncCallbacks.push(e))}))},safeSetTimeout:function(e,t){return B=!0,setTimeout((function(){K||(qa.allowAsyncCallbacks?e():qa.queuedAsyncCallbacks.push(e))}),t)},safeSetInterval:function(e,t){return B=!0,setInterval((function(){K||qa.allowAsyncCallbacks&&e()}),t)},getMimetype:function(e){return{jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",bmp:"image/bmp",ogg:"audio/ogg",wav:"audio/wav",mp3:"audio/mpeg"}[e.substr(e.lastIndexOf(".")+1)]},getUserMedia:function(e){window.getUserMedia||(window.getUserMedia=navigator.getUserMedia||navigator.mozGetUserMedia),window.getUserMedia(e)},getMovementX:function(e){return e.movementX||e.mozMovementX||e.webkitMovementX||0},getMovementY:function(e){return e.movementY||e.mozMovementY||e.webkitMovementY||0},getMouseWheelDelta:function(e){var t=0;switch(e.type){case"DOMMouseScroll":t=e.detail/3;break;case"mousewheel":t=e.wheelDelta/120;break;case"wheel":switch(t=e.deltaY,e.deltaMode){case 0:t/=100;break;case 1:t/=3;break;case 2:t*=80;break;default:throw"unrecognized mouse wheel delta mode: "+e.deltaMode}break;default:throw"unrecognized mouse wheel event: "+e.type}return t},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(e){if(qa.pointerLock)"mousemove"!=e.type&&"mozMovementX"in e?qa.mouseMovementX=qa.mouseMovementY=0:(qa.mouseMovementX=qa.getMovementX(e),qa.mouseMovementY=qa.getMovementY(e)),"undefined"!=typeof SDL?(qa.mouseX=SDL.mouseX+qa.mouseMovementX,qa.mouseY=SDL.mouseY+qa.mouseMovementY):(qa.mouseX+=qa.mouseMovementX,qa.mouseY+=qa.mouseMovementY);else{var t=u.canvas.getBoundingClientRect(),r=u.canvas.width,i=u.canvas.height,n=void 0!==window.scrollX?window.scrollX:window.pageXOffset,a=void 0!==window.scrollY?window.scrollY:window.pageYOffset;if(Z(void 0!==n&&void 0!==a,"Unable to retrieve scroll position, mouse positions likely broken."),"touchstart"===e.type||"touchend"===e.type||"touchmove"===e.type){var o=e.touch;if(void 0===o)return;var s=o.pageX-(n+t.left),c=o.pageY-(a+t.top),l={x:s*=r/t.width,y:c*=i/t.height};if("touchstart"===e.type)qa.lastTouches[o.identifier]=l,qa.touches[o.identifier]=l;else if("touchend"===e.type||"touchmove"===e.type){var h=qa.touches[o.identifier];h||(h=l),qa.lastTouches[o.identifier]=h,qa.touches[o.identifier]=l}return}var d=e.pageX-(n+t.left),p=e.pageY-(a+t.top);d*=r/t.width,p*=i/t.height,qa.mouseMovementX=d-qa.mouseX,qa.mouseMovementY=p-qa.mouseY,qa.mouseX=d,qa.mouseY=p}},asyncLoad:function(e,t,r,i){var n=i?"":Ve("al "+e);b(e,(function(r){Z(r,'Loading data file "'+e+'" failed (no arrayBuffer).'),t(new Uint8Array(r)),n&&Ye(n)}),(function(t){if(!r)throw'Loading data file "'+e+'" failed.';r()})),n&&Ge(n)},resizeListeners:[],updateResizeListeners:function(){var e=u.canvas;qa.resizeListeners.forEach((function(t){t(e.width,e.height)}))},setCanvasSize:function(e,t,r){var i=u.canvas;qa.updateCanvasDimensions(i,e,t),r||qa.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if("undefined"!=typeof SDL){var e=fe[SDL.screen>>2];e|=8388608,pe[SDL.screen>>2]=e}qa.updateCanvasDimensions(u.canvas),qa.updateResizeListeners()},setWindowedCanvasSize:function(){if("undefined"!=typeof SDL){var e=fe[SDL.screen>>2];e&=-8388609,pe[SDL.screen>>2]=e}qa.updateCanvasDimensions(u.canvas),qa.updateResizeListeners()},updateCanvasDimensions:function(e,t,r){t&&r?(e.widthNative=t,e.heightNative=r):(t=e.widthNative,r=e.heightNative);var i=t,n=r;if(u.forcedAspectRatio&&u.forcedAspectRatio>0&&(i/n>2]=t,pe[e+4>>2]=t+r},setDataRewindFunc:function(e){var t=Za.exportCallStack[0],r=Za.getCallStackId(t);pe[e+8>>2]=r},getDataRewindFunc:function(e){var t=pe[e+8>>2];return Za.callStackIdToFunc[t]},handleSleep:function(e){if(!K){if(B=!0,Za.state===Za.State.Normal){var t=!1,r=!1;e((function(e){if(Z(!e||"number"==typeof e),!K&&(Za.handleSleepReturnValue=e||0,t=!0,r)){Z(!Za.exportCallStack.length,"Waking up (starting to rewind) must be done from JS, without compiled code on the stack."),Za.state=Za.State.Rewinding,Ka((function(){u._asyncify_start_rewind(Za.currData)})),qa.mainLoop.func&&qa.mainLoop.resume();var i=Za.getDataRewindFunc(Za.currData)();if(!Za.currData){var n=Za.asyncFinalizers;Za.asyncFinalizers=[],n.forEach((function(e){e(i)}))}}})),r=!0,t||(Za.state=Za.State.Unwinding,Za.currData=Za.allocateData(),Ka((function(){u._asyncify_start_unwind(Za.currData)})),qa.mainLoop.func&&qa.mainLoop.pause())}else Za.state===Za.State.Rewinding?(Za.state=Za.State.Normal,Ka(u._asyncify_stop_rewind),to(Za.currData),Za.currData=null,Za.sleepCallbacks.forEach((function(e){e()}))):$e("invalid state: "+Za.state);return Za.handleSleepReturnValue}},handleAsync:function(e){return Za.handleSleep((function(t){e().then(t)}))}},Wa=function(e,t,r,i){e||(e=this),this.parent=e,this.mount=e.mount,this.mounted=null,this.id=Yr.nextInode++,this.name=t,this.mode=r,this.node_ops={},this.stream_ops={},this.rdev=i},Xa=365,Qa=146;Object.defineProperties(Wa.prototype,{read:{get:function(){return(this.mode&Xa)===Xa},set:function(e){e?this.mode|=Xa:this.mode&=~Xa}},write:{get:function(){return(this.mode&Qa)===Qa},set:function(e){e?this.mode|=Qa:this.mode&=~Qa}},isFolder:{get:function(){return Yr.isDir(this.mode)}},isDevice:{get:function(){return Yr.isChrdev(this.mode)}}}),Yr.FSNode=Wa,Yr.staticInit(),Pi(),Zi=u.BindingError=Ki(Error,"BindingError"),Xi=u.InternalError=Ki(Error,"InternalError"),nn(),yn=u.UnboundTypeError=Ki(Error,"UnboundTypeError"),u.requestFullscreen=function(e,t){qa.requestFullscreen(e,t)},u.requestFullScreen=function(){qa.requestFullScreen()},u.requestAnimationFrame=function(e){qa.requestAnimationFrame(e)},u.setCanvasSize=function(e,t,r){qa.setCanvasSize(e,t,r)},u.pauseMainLoop=function(){qa.mainLoop.pause()},u.resumeMainLoop=function(){qa.mainLoop.resume()},u.getUserMedia=function(){qa.getUserMedia()},u.createContext=function(e,t,r,i){return qa.createContext(e,t,r,i)};var Ja=!0;function Va(e,t,r){var i=r>0?r:G(e)+1,n=new Array(i),a=J(e,n,0,n.length);return t&&(n.length=a),n}function Ga(e){for(var t=[],r=0;r255&&(Ja&&Z(!1,"Character code "+i+" ("+String.fromCharCode(i)+") at offset "+r+" not in 0x00-0xFF."),i&=255),t.push(String.fromCharCode(i))}return t.join("")}var Ya={BIO_ctrl:vt,BIO_ctrl_pending:yt,BIO_free:bt,BIO_new_bio_pair:Et,BIO_new_mem_buf:wt,BIO_read:St,BIO_write:kt,CONF_modules_unload:xt,CRYPTO_free:Mt,ERR_clear_error:Nt,ERR_get_error:jt,ERR_reason_error_string:Tt,PEM_read_bio:Rt,PEM_write:It,SSL_CTX_ctrl:Ot,SSL_CTX_free:At,SSL_CTX_get_default_passwd_cb_userdata:Pt,SSL_CTX_get_ex_data:Dt,SSL_CTX_new:Ft,SSL_CTX_set_default_passwd_cb_userdata:Ct,SSL_CTX_set_ex_data:Bt,SSL_CTX_set_options:zt,SSL_ctrl:Lt,SSL_free:Ut,SSL_get_error:Ht,SSL_get_ex_data:qt,SSL_get_shutdown:Kt,SSL_new:Zt,SSL_read:Wt,SSL_set_bio:Xt,SSL_set_ex_data:Qt,SSL_shutdown:Jt,SSL_write:Vt,TLS_client_method:Gt,TLS_method:Yt,TLS_server_method:$t,_ZN2hw6trezor12register_allEv:er,_ZN4epee9net_utils4http16http_client_auth13do_handle_401ERKNS1_18http_response_infoE:tr,_ZN4epee9net_utils4http16http_client_auth17do_get_auth_fieldEN5boost16basic_string_refIcNSt3__211char_traitsIcEEEES8_:rr,_ZN4epee9net_utils4http16http_client_authC1ENS1_5loginE:ir,_ZN5boost10filesystem6detail12current_pathEPNS_6system10error_codeE:nr,_ZN5boost10filesystem6detail18create_directoriesERKNS0_4pathEPNS_6system10error_codeE:ar,_ZN5boost10filesystem6detail5spaceERKNS0_4pathEPNS_6system10error_codeE:or,_ZN5boost10filesystem6detail6removeERKNS0_4pathEPNS_6system10error_codeE:sr,_ZN5boost10filesystem6detail6statusERKNS0_4pathEPNS_6system10error_codeE:cr,_ZN5boost10filesystem6detail9canonicalERKNS0_4pathES4_PNS_6system10error_codeE:ur,_ZN5tools6Notify6notifyEPKcS2_z:lr,_ZN5tools9dns_utils25load_txt_records_from_dnsERNSt3__26vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEERKSA_:hr,_ZN5tools9dns_utils35get_account_address_as_str_from_urlERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERbNS1_8functionIFS7_S9_RKNS1_6vectorIS7_NS5_IS7_EEEEbEEE:dr,_ZNK10cryptonote10Blockchain29get_current_blockchain_heightEv:pr,_ZNK10cryptonote10Blockchain30get_pending_block_id_by_heightEy:fr,_ZNK3net5socks9connectorclERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RN5boost4asio20basic_waitable_timerINS2_6chrono12steady_clockENSC_11wait_traitsISF_EENSC_8executorEEE:mr,_ZNK4epee9net_utils13ssl_options_t14create_contextEv:gr,_ZNK4epee9net_utils13ssl_options_t9handshakeERN5boost4asio3ssl6streamINS3_19basic_stream_socketINS3_2ip3tcpENS3_8executorEEEEENS4_11stream_base14handshake_typeERKNSt3__212basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEENSF_6chrono8durationIxNSF_5ratioILx1ELx1000EEEEE:_r,_ZNK4epee9net_utils14direct_connectclERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RN5boost4asio20basic_waitable_timerINS2_6chrono12steady_clockENSC_11wait_traitsISF_EENSC_8executorEEE:vr,_ZNK5boost10filesystem4path11parent_pathEv:yr,__assert_fail:br,__cxa_allocate_exception:wr,__cxa_atexit:kr,__cxa_begin_catch:Tr,__cxa_decrement_exception_refcount:Or,__cxa_end_catch:Pr,__cxa_find_matching_catch_2:Fr,__cxa_find_matching_catch_3:Cr,__cxa_free_exception:Rr,__cxa_increment_exception_refcount:Br,__cxa_rethrow:zr,__cxa_rethrow_primary_exception:Lr,__cxa_throw:Ur,__cxa_uncaught_exceptions:Hr,__handle_stack_overflow:qr,__map_file:Zr,__resumeException:Dr,__sys__newselect:ei,__sys_fcntl64:ti,__sys_fdatasync:ri,__sys_ftruncate64:ii,__sys_getpid:ni,__sys_ioctl:ai,__sys_madvise1:oi,__sys_mkdir:si,__sys_mlock:ci,__sys_mmap2:li,__sys_msync:hi,__sys_munlock:di,__sys_munmap:fi,__sys_open:mi,__sys_pause:gi,__sys_pipe:vi,__sys_pwrite64:yi,__sys_read:bi,__sys_rename:Ei,__sys_socketcall:Ii,__sys_stat64:Oi,_embind_register_bool:Gi,_embind_register_emval:sn,_embind_register_float:ln,_embind_register_function:wn,_embind_register_integer:kn,_embind_register_memory_view:xn,_embind_register_std_string:Mn,_embind_register_std_wstring:Nn,_embind_register_void:jn,_emval_call:On,_emval_decref:en,_emval_equals:An,_emval_incref:Pn,_emval_take_value:Dn,_exit:Cn,abort:Bn,atexit:Sr,clock_gettime:Ln,emscripten_get_sbrk_ptr:Un,emscripten_memcpy_big:Hn,emscripten_resize_heap:Zn,environ_get:Jn,environ_sizes_get:Vn,exit:Fn,fd_close:Gn,fd_read:Yn,fd_seek:$n,fd_write:ea,ftime:ta,getTempRet0:ra,gettimeofday:ia,gmtime:sa,gmtime_r:oa,invoke_diii:_s,invoke_fiii:gs,invoke_i:hs,invoke_ii:ns,invoke_iii:es,invoke_iiii:$o,invoke_iiiii:as,invoke_iiiiid:ds,invoke_iiiiii:cs,invoke_iiiiiii:os,invoke_iiiiiiii:ps,invoke_iiiiiiiiiii:fs,invoke_iiiiiiiiiiii:ys,invoke_iiiiiiiiiiiii:ms,invoke_iiiiiiiijii:ks,invoke_iiiiiijii:Ss,invoke_iiiiij:Os,invoke_ji:Ns,invoke_jii:js,invoke_jiii:Ts,invoke_jiiii:xs,invoke_v:rs,invoke_vi:ts,invoke_vii:is,invoke_viii:ss,invoke_viiii:us,invoke_viiiii:ls,invoke_viiiiiii:vs,invoke_viiiiiiiiii:bs,invoke_viiiiiiiiiiiiiii:Es,invoke_viiiji:Rs,invoke_viij:Ms,invoke_viijii:Is,invoke_viijiii:ws,js_send_binary_request:dt,js_send_json_request:pt,llvm_eh_typeid_for:ca,memory:z,mktime:la,nanosleep:da,pthread_attr_destroy:pa,pthread_attr_getdetachstate:fa,pthread_attr_init:ma,pthread_attr_setstacksize:ga,pthread_condattr_destroy:_a,pthread_condattr_init:va,pthread_condattr_setclock:ya,pthread_create:ba,pthread_detach:Ea,pthread_join:wa,pthread_mutexattr_destroy:Sa,pthread_mutexattr_init:ka,pthread_mutexattr_settype:xa,pthread_sigmask:Ma,rx_seedheight:Na,rx_slow_hash:ja,setTempRet0:Ta,sigfillset:Ra,strftime_l:Ca,sysconf:Ba,table:q,time:za,v4_generate_JIT_code:La};Za.instrumentWasmImports(Ya),ht();var $a,eo=u.___wasm_call_ctors=at("__wasm_call_ctors"),to=u._free=at("free"),ro=u._memset=at("memset"),io=(u.__ZN5boost13serialization16singleton_module8get_lockEv=at("_ZN5boost13serialization16singleton_module8get_lockEv"),u.___errno_location=at("__errno_location")),no=(u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet210pending_txEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet210pending_txEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote11transactionEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote11transactionEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote8txin_genEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote8txin_genEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote14txin_to_scriptEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote14txin_to_scriptEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto4hashEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto4hashEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote18txin_to_scripthashEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote18txin_to_scripthashEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote15txout_to_scriptEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote15txout_to_scriptEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto10public_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto10public_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote11txin_to_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote11txin_to_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9key_imageEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9key_imageEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote6tx_outEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote6tx_outEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote19txout_to_scripthashEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote19txout_to_scripthashEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote12txout_to_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote12txout_to_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9signatureEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9signatureEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct10rctSigBaseEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct10rctSigBaseEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct3keyEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct3keyEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct9ecdhTupleEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct9ecdhTupleEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct14rctSigPrunableEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct14rctSigPrunableEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct8rangeSigEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct8rangeSigEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct7boroSigEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct7boroSigEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct11BulletproofEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct11BulletproofEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct5mgSigEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct5mgSigEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote20tx_destination_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote20tx_destination_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote22account_public_addressEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote22account_public_addressEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24listImNS4_9allocatorImEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24listImNS4_9allocatorImEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet220tx_construction_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet220tx_construction_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote15tx_source_entryENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote15tx_source_entryENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote15tx_source_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote15tx_source_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIyN3rct5ctkeyEEENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIyN3rct5ctkeyEEENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIyN3rct5ctkeyEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIyN3rct5ctkeyEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct5ctkeyEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct5ctkeyEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct14multisig_kLRkiEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct14multisig_kLRkiEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct9RCTConfigEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct9RCTConfigEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorImNS4_9allocatorImEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorImNS4_9allocatorImEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet212multisig_sigENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet212multisig_sigENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet212multisig_sigEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet212multisig_sigEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct6rctSigEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct6rctSigEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN3rct3keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN3rct3keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct12multisig_outEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct12multisig_outEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet210pending_txEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet210pending_txEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote11transactionEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote11transactionEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote8txin_genEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote8txin_genEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote14txin_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote14txin_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto4hashEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto4hashEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote18txin_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote18txin_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote15txout_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote15txout_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto10public_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto10public_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote11txin_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote11txin_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9key_imageEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9key_imageEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote6tx_outEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote6tx_outEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote19txout_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote19txout_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote12txout_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote12txout_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9signatureEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9signatureEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct10rctSigBaseEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct10rctSigBaseEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct3keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct3keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct9ecdhTupleEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct9ecdhTupleEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct14rctSigPrunableEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct14rctSigPrunableEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct8rangeSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct8rangeSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct7boroSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct7boroSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct11BulletproofEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct11BulletproofEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct5mgSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct5mgSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote20tx_destination_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote20tx_destination_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote22account_public_addressEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote22account_public_addressEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24listImNS4_9allocatorImEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24listImNS4_9allocatorImEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet220tx_construction_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet220tx_construction_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote15tx_source_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote15tx_source_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote15tx_source_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote15tx_source_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIyN3rct5ctkeyEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIyN3rct5ctkeyEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIyN3rct5ctkeyEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIyN3rct5ctkeyEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct5ctkeyEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct5ctkeyEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct14multisig_kLRkiEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct14multisig_kLRkiEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct9RCTConfigEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct9RCTConfigEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorImNS4_9allocatorImEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorImNS4_9allocatorImEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet212multisig_sigENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet212multisig_sigENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet212multisig_sigEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet212multisig_sigEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct6rctSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct6rctSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN3rct3keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN3rct3keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct12multisig_outEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct12multisig_outEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u._malloc=at("malloc")),ao=u._htons=at("htons"),oo=(u._htonl=at("htonl"),u._fflush=at("fflush"),u._ntohs=at("ntohs")),so=(u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet2EE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet2EE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools9hashchainEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools9hashchainEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet216transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet216transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote18transaction_prefixEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote18transaction_prefixEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote16subaddress_indexEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote16subaddress_indexEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIyN6crypto4hashEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIyN6crypto4hashEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet226confirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet226confirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet216address_book_rowEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet216address_book_rowEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto5hash8EE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto5hash8EE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet220pool_payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet220pool_payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet2EE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet2EE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto4hashEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto4hashEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools9hashchainEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools9hashchainEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet216transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet216transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote11transactionEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote11transactionEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote8txin_genEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote8txin_genEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote14txin_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote14txin_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote18txin_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote18txin_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote15txout_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote15txout_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto10public_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto10public_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote11txin_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote11txin_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote6tx_outEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote6tx_outEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote19txout_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote19txout_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote12txout_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote12txout_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto9signatureEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto9signatureEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct10rctSigBaseEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct10rctSigBaseEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct9ecdhTupleEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct9ecdhTupleEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct14rctSigPrunableEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct14rctSigPrunableEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct8rangeSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct8rangeSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct7boroSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct7boroSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct3keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct3keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct11BulletproofEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct11BulletproofEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct5mgSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct5mgSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote18transaction_prefixEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote18transaction_prefixEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto9key_imageEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto9key_imageEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote16subaddress_indexEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote16subaddress_indexEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet213multisig_infoEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet213multisig_infoEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet213multisig_info2LREE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet213multisig_info2LREE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIyN6crypto4hashEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIyN6crypto4hashEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote22account_public_addressEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote22account_public_addressEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote20tx_destination_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote20tx_destination_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet215payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet215payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet226confirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet226confirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet216address_book_rowEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet216address_book_rowEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto5hash8EE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto5hash8EE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet220pool_payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet220pool_payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet2EE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet2EE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools9hashchainEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools9hashchainEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet216transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet216transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote18transaction_prefixEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote18transaction_prefixEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote16subaddress_indexEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote16subaddress_indexEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIyN6crypto4hashEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIyN6crypto4hashEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215payment_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215payment_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet226confirmed_transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet226confirmed_transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet216address_book_rowEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet216address_book_rowEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto5hash8EE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto5hash8EE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet220pool_payment_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet220pool_payment_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215unsigned_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215unsigned_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet220tx_construction_dataENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet220tx_construction_dataENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215unsigned_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215unsigned_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet220tx_construction_dataENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet220tx_construction_dataENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213signed_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213signed_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet210pending_txENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet210pending_txENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213signed_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213signed_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet210pending_txENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet210pending_txENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215multisig_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215multisig_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215multisig_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215multisig_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet219reserve_proof_entryENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet219reserve_proof_entryENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet219reserve_proof_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet219reserve_proof_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9signatureENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9signatureENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet219reserve_proof_entryENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet219reserve_proof_entryENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet219reserve_proof_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet219reserve_proof_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9signatureENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9signatureENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213multisig_infoEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213multisig_infoEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213multisig_info2LREE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213multisig_info2LREE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213multisig_infoEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213multisig_infoEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213multisig_info2LREE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213multisig_info2LREE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3mms17authorized_signerENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3mms17authorized_signerENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms17authorized_signerEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms17authorized_signerEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3mms17authorized_signerENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3mms17authorized_signerENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms17authorized_signerEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms17authorized_signerEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms16auto_config_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms16auto_config_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms16auto_config_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms16auto_config_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms13message_storeEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms13message_storeEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3mms7messageENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3mms7messageENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms7messageEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms7messageEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms9file_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms9file_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9chacha_ivEE16save_object_dataERNS1_14basic_oarchiveEPKv=at("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9chacha_ivEE16save_object_dataERNS1_14basic_oarchiveEPKv"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms9file_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms9file_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9chacha_ivEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9chacha_ivEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms13message_storeEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms13message_storeEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3mms7messageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3mms7messageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms7messageEE16load_object_dataERNS1_14basic_iarchiveEPvj=at("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms7messageEE16load_object_dataERNS1_14basic_iarchiveEPvj"),u.___getTypeName=at("__getTypeName")),co=(u.___embind_register_native_and_builtin_types=at("__embind_register_native_and_builtin_types"),u.__get_tzname=at("_get_tzname")),uo=u.__get_daylight=at("_get_daylight"),lo=u.__get_timezone=at("_get_timezone"),ho=u._setThrew=at("setThrew"),po=u.stackSave=at("stackSave"),fo=u.stackRestore=at("stackRestore"),mo=(u.stackAlloc=at("stackAlloc"),u.__ZSt18uncaught_exceptionv=at("_ZSt18uncaught_exceptionv")),go=u.___cxa_can_catch=at("__cxa_can_catch"),_o=u.___cxa_is_pointer_type=at("__cxa_is_pointer_type"),vo=u._memalign=at("memalign"),yo=(u._emscripten_main_thread_process_queued_calls=at("emscripten_main_thread_process_queued_calls"),u.dynCall_v=at("dynCall_v")),bo=u.dynCall_vi=at("dynCall_vi"),Eo=u.dynCall_vii=at("dynCall_vii"),wo=u.dynCall_viii=at("dynCall_viii"),So=u.dynCall_viiii=at("dynCall_viiii"),ko=u.dynCall_viiiii=at("dynCall_viiiii"),xo=u.dynCall_viiiiiii=at("dynCall_viiiiiii"),Mo=u.dynCall_viiiiiiiiii=at("dynCall_viiiiiiiiii"),No=u.dynCall_viiiiiiiiiiiiiii=at("dynCall_viiiiiiiiiiiiiii"),jo=u.dynCall_viiiji=at("dynCall_viiiji"),To=u.dynCall_viij=at("dynCall_viij"),Ro=u.dynCall_viijii=at("dynCall_viijii"),Io=u.dynCall_viijiii=at("dynCall_viijiii"),Oo=u.dynCall_i=at("dynCall_i"),Ao=u.dynCall_ii=at("dynCall_ii"),Po=u.dynCall_iii=at("dynCall_iii"),Do=u.dynCall_iiii=at("dynCall_iiii"),Fo=u.dynCall_iiiii=at("dynCall_iiiii"),Co=u.dynCall_iiiiii=at("dynCall_iiiiii"),Bo=u.dynCall_iiiiiii=at("dynCall_iiiiiii"),zo=u.dynCall_iiiiiiii=at("dynCall_iiiiiiii"),Lo=u.dynCall_iiiiiiiiiii=at("dynCall_iiiiiiiiiii"),Uo=u.dynCall_iiiiiiiiiiii=at("dynCall_iiiiiiiiiiii"),Ho=u.dynCall_iiiiiiiiiiiii=at("dynCall_iiiiiiiiiiiii"),qo=u.dynCall_iiiiiiiijii=at("dynCall_iiiiiiiijii"),Ko=u.dynCall_iiiiiijii=at("dynCall_iiiiiijii"),Zo=u.dynCall_iiiiij=at("dynCall_iiiiij"),Wo=u.dynCall_iiiiid=at("dynCall_iiiiid"),Xo=u.dynCall_ji=at("dynCall_ji"),Qo=u.dynCall_jii=at("dynCall_jii"),Jo=u.dynCall_jiii=at("dynCall_jiii"),Vo=u.dynCall_jiiii=at("dynCall_jiiii"),Go=u.dynCall_fiii=at("dynCall_fiii"),Yo=u.dynCall_diii=at("dynCall_diii");function $o(e,t,r,i){var n=po();try{return Do(e,t,r,i)}catch(e){if(fo(n),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function es(e,t,r){var i=po();try{return Po(e,t,r)}catch(e){if(fo(i),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function ts(e,t){var r=po();try{bo(e,t)}catch(e){if(fo(r),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function rs(e){var t=po();try{yo(e)}catch(e){if(fo(t),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function is(e,t,r){var i=po();try{Eo(e,t,r)}catch(e){if(fo(i),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function ns(e,t){var r=po();try{return Ao(e,t)}catch(e){if(fo(r),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function as(e,t,r,i,n){var a=po();try{return Fo(e,t,r,i,n)}catch(e){if(fo(a),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function os(e,t,r,i,n,a,o){var s=po();try{return Bo(e,t,r,i,n,a,o)}catch(e){if(fo(s),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function ss(e,t,r,i){var n=po();try{wo(e,t,r,i)}catch(e){if(fo(n),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function cs(e,t,r,i,n,a){var o=po();try{return Co(e,t,r,i,n,a)}catch(e){if(fo(o),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function us(e,t,r,i,n){var a=po();try{So(e,t,r,i,n)}catch(e){if(fo(a),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function ls(e,t,r,i,n,a){var o=po();try{ko(e,t,r,i,n,a)}catch(e){if(fo(o),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function hs(e){var t=po();try{return Oo(e)}catch(e){if(fo(t),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function ds(e,t,r,i,n,a){var o=po();try{return Wo(e,t,r,i,n,a)}catch(e){if(fo(o),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function ps(e,t,r,i,n,a,o,s){var c=po();try{return zo(e,t,r,i,n,a,o,s)}catch(e){if(fo(c),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function fs(e,t,r,i,n,a,o,s,c,u,l){var h=po();try{return Lo(e,t,r,i,n,a,o,s,c,u,l)}catch(e){if(fo(h),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function ms(e,t,r,i,n,a,o,s,c,u,l,h,d){var p=po();try{return Ho(e,t,r,i,n,a,o,s,c,u,l,h,d)}catch(e){if(fo(p),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function gs(e,t,r,i){var n=po();try{return Go(e,t,r,i)}catch(e){if(fo(n),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function _s(e,t,r,i){var n=po();try{return Yo(e,t,r,i)}catch(e){if(fo(n),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function vs(e,t,r,i,n,a,o,s){var c=po();try{xo(e,t,r,i,n,a,o,s)}catch(e){if(fo(c),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function ys(e,t,r,i,n,a,o,s,c,u,l,h){var d=po();try{return Uo(e,t,r,i,n,a,o,s,c,u,l,h)}catch(e){if(fo(d),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function bs(e,t,r,i,n,a,o,s,c,u,l){var h=po();try{Mo(e,t,r,i,n,a,o,s,c,u,l)}catch(e){if(fo(h),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function Es(e,t,r,i,n,a,o,s,c,u,l,h,d,p,f,m){var g=po();try{No(e,t,r,i,n,a,o,s,c,u,l,h,d,p,f,m)}catch(e){if(fo(g),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function ws(e,t,r,i,n,a,o,s){var c=po();try{Io(e,t,r,i,n,a,o,s)}catch(e){if(fo(c),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function Ss(e,t,r,i,n,a,o,s,c,u){var l=po();try{return Ko(e,t,r,i,n,a,o,s,c,u)}catch(e){if(fo(l),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function ks(e,t,r,i,n,a,o,s,c,u,l,h){var d=po();try{return qo(e,t,r,i,n,a,o,s,c,u,l,h)}catch(e){if(fo(d),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function xs(e,t,r,i,n){var a=po();try{return Vo(e,t,r,i,n)}catch(e){if(fo(a),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function Ms(e,t,r,i,n){var a=po();try{To(e,t,r,i,n)}catch(e){if(fo(a),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function Ns(e,t){var r=po();try{return Xo(e,t)}catch(e){if(fo(r),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function js(e,t,r){var i=po();try{return Qo(e,t,r)}catch(e){if(fo(i),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function Ts(e,t,r,i){var n=po();try{return Jo(e,t,r,i)}catch(e){if(fo(n),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function Rs(e,t,r,i,n,a,o){var s=po();try{jo(e,t,r,i,n,a,o)}catch(e){if(fo(s),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function Is(e,t,r,i,n,a,o){var s=po();try{Ro(e,t,r,i,n,a,o)}catch(e){if(fo(s),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function Os(e,t,r,i,n,a,o){var s=po();try{return Zo(e,t,r,i,n,a,o)}catch(e){if(fo(s),e!==e+0&&"longjmp"!==e)throw e;ho(1,0)}}function As(e){this.name="ExitStatus",this.message="Program terminated with exit("+e+")",this.status=e}function Ps(e){function r(){$a||($a=!0,u.calledRun=!0,K||(Fe(),Ce(),t(u),u.onRuntimeInitialized&&u.onRuntimeInitialized(),Z(!u._main,'compiled without a main, but one is present. if you added it from JS, use Module["onRuntimeInitialized"]'),ze()))}e=e||d,We>0||(Me(),De(),We>0||(u.setStatus?(u.setStatus("Running..."),setTimeout((function(){setTimeout((function(){u.setStatus("")}),1),r()}),1)):r(),Ne()))}function Ds(){var e=M,t=N,r=!1;M=N=function(e){r=!0};try{var i=u._fflush;i&&i(0),["stdout","stderr"].forEach((function(e){var t=Yr.analyzePath("/dev/"+e);if(t){var i=t.object.rdev,n=Qr.ttys[i];n&&n.output&&n.output.length&&(r=!0)}}))}catch(e){}M=e,N=t,r&&R("stdio streams had content in them that was not flushed. you should set EXIT_RUNTIME to 1 (see the FAQ), or make sure to emit a newline when you printf etc.")}function Fs(e,t){if(Ds(),!t||!B||0!==e){if(B){if(!t){var r="program exited (with status: "+e+"), but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)";c(r),N(r)}}else K=!0,Be(),u.onExit&&u.onExit(e);f(e,new As(e))}}if(u.___set_stack_limit=at("__set_stack_limit"),u.dynCall_iij=at("dynCall_iij"),u.dynCall_iiiiijii=at("dynCall_iiiiijii"),u.dynCall_iiijiii=at("dynCall_iiijiii"),u.dynCall_iiiijii=at("dynCall_iiiijii"),u.dynCall_vij=at("dynCall_vij"),u.dynCall_viiji=at("dynCall_viiji"),u.dynCall_viiiiii=at("dynCall_viiiiii"),u.dynCall_vijiiii=at("dynCall_vijiiii"),u.dynCall_iiiiiiiii=at("dynCall_iiiiiiiii"),u.dynCall_vijjjdi=at("dynCall_vijjjdi"),u.dynCall_vijj=at("dynCall_vijj"),u.dynCall_viji=at("dynCall_viji"),u.dynCall_vijiijiij=at("dynCall_vijiijiij"),u.dynCall_vijiiji=at("dynCall_vijiiji"),u.dynCall_vijiijii=at("dynCall_vijiijii"),u.dynCall_vijii=at("dynCall_vijii"),u.dynCall_vijij=at("dynCall_vijij"),u.dynCall_viiiiiiii=at("dynCall_viiiiiiii"),u.dynCall_viiiiiiiii=at("dynCall_viiiiiiiii"),u.dynCall_viiiiiiiiiiii=at("dynCall_viiiiiiiiiiii"),u.dynCall_viiiiiiiiiii=at("dynCall_viiiiiiiiiii"),u.dynCall_viiiiiiiiiiiii=at("dynCall_viiiiiiiiiiiii"),u.dynCall_iiiij=at("dynCall_iiiij"),u.dynCall_iiiiiiiiiiiiii=at("dynCall_iiiiiiiiiiiiii"),u.dynCall_jiji=at("dynCall_jiji"),u.dynCall_iidiiii=at("dynCall_iidiiii"),u.dynCall_iiiiijj=at("dynCall_iiiiijj"),u.dynCall_iiiiiijj=at("dynCall_iiiiiijj"),u.__growWasmMemory=at("__growWasmMemory"),u._asyncify_start_unwind=at("asyncify_start_unwind"),u._asyncify_stop_unwind=at("asyncify_stop_unwind"),u._asyncify_start_rewind=at("asyncify_start_rewind"),u._asyncify_stop_rewind=at("asyncify_stop_rewind"),Object.getOwnPropertyDescriptor(u,"intArrayFromString")||(u.intArrayFromString=function(){$e("'intArrayFromString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),u.intArrayToString=Ga,Object.getOwnPropertyDescriptor(u,"ccall")||(u.ccall=function(){$e("'ccall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"cwrap")||(u.cwrap=function(){$e("'cwrap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"setValue")||(u.setValue=function(){$e("'setValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getValue")||(u.getValue=function(){$e("'getValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"allocate")||(u.allocate=function(){$e("'allocate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getMemory")||(u.getMemory=function(){$e("'getMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(u,"UTF8ArrayToString")||(u.UTF8ArrayToString=function(){$e("'UTF8ArrayToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),u.UTF8ToString=Q,Object.getOwnPropertyDescriptor(u,"stringToUTF8Array")||(u.stringToUTF8Array=function(){$e("'stringToUTF8Array' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),u.stringToUTF8=V,u.lengthBytesUTF8=G,Object.getOwnPropertyDescriptor(u,"stackTrace")||(u.stackTrace=function(){$e("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"addOnPreRun")||(u.addOnPreRun=function(){$e("'addOnPreRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"addOnInit")||(u.addOnInit=function(){$e("'addOnInit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"addOnPreMain")||(u.addOnPreMain=function(){$e("'addOnPreMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"addOnExit")||(u.addOnExit=function(){$e("'addOnExit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"addOnPostRun")||(u.addOnPostRun=function(){$e("'addOnPostRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"writeStringToMemory")||(u.writeStringToMemory=function(){$e("'writeStringToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"writeArrayToMemory")||(u.writeArrayToMemory=function(){$e("'writeArrayToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"writeAsciiToMemory")||(u.writeAsciiToMemory=function(){$e("'writeAsciiToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"addRunDependency")||(u.addRunDependency=function(){$e("'addRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(u,"removeRunDependency")||(u.removeRunDependency=function(){$e("'removeRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(u,"FS_createFolder")||(u.FS_createFolder=function(){$e("'FS_createFolder' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(u,"FS_createPath")||(u.FS_createPath=function(){$e("'FS_createPath' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(u,"FS_createDataFile")||(u.FS_createDataFile=function(){$e("'FS_createDataFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(u,"FS_createPreloadedFile")||(u.FS_createPreloadedFile=function(){$e("'FS_createPreloadedFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(u,"FS_createLazyFile")||(u.FS_createLazyFile=function(){$e("'FS_createLazyFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(u,"FS_createLink")||(u.FS_createLink=function(){$e("'FS_createLink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(u,"FS_createDevice")||(u.FS_createDevice=function(){$e("'FS_createDevice' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(u,"FS_unlink")||(u.FS_unlink=function(){$e("'FS_unlink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")}),Object.getOwnPropertyDescriptor(u,"dynamicAlloc")||(u.dynamicAlloc=function(){$e("'dynamicAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"loadDynamicLibrary")||(u.loadDynamicLibrary=function(){$e("'loadDynamicLibrary' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"loadWebAssemblyModule")||(u.loadWebAssemblyModule=function(){$e("'loadWebAssemblyModule' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getLEB")||(u.getLEB=function(){$e("'getLEB' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getFunctionTables")||(u.getFunctionTables=function(){$e("'getFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"alignFunctionTables")||(u.alignFunctionTables=function(){$e("'alignFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"registerFunctions")||(u.registerFunctions=function(){$e("'registerFunctions' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),u.addFunction=D,Object.getOwnPropertyDescriptor(u,"removeFunction")||(u.removeFunction=function(){$e("'removeFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getFuncWrapper")||(u.getFuncWrapper=function(){$e("'getFuncWrapper' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"prettyPrint")||(u.prettyPrint=function(){$e("'prettyPrint' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),u.makeBigInt=F,Object.getOwnPropertyDescriptor(u,"dynCall")||(u.dynCall=function(){$e("'dynCall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getCompilerSetting")||(u.getCompilerSetting=function(){$e("'getCompilerSetting' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"print")||(u.print=function(){$e("'print' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"printErr")||(u.printErr=function(){$e("'printErr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),u.getTempRet0=H,Object.getOwnPropertyDescriptor(u,"setTempRet0")||(u.setTempRet0=function(){$e("'setTempRet0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"callMain")||(u.callMain=function(){$e("'callMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"abort")||(u.abort=function(){$e("'abort' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"stringToNewUTF8")||(u.stringToNewUTF8=function(){$e("'stringToNewUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"emscripten_realloc_buffer")||(u.emscripten_realloc_buffer=function(){$e("'emscripten_realloc_buffer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"ENV")||(u.ENV=function(){$e("'ENV' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"ERRNO_CODES")||(u.ERRNO_CODES=function(){$e("'ERRNO_CODES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"ERRNO_MESSAGES")||(u.ERRNO_MESSAGES=function(){$e("'ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"setErrNo")||(u.setErrNo=function(){$e("'setErrNo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"DNS")||(u.DNS=function(){$e("'DNS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"GAI_ERRNO_MESSAGES")||(u.GAI_ERRNO_MESSAGES=function(){$e("'GAI_ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"Protocols")||(u.Protocols=function(){$e("'Protocols' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"Sockets")||(u.Sockets=function(){$e("'Sockets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"traverseStack")||(u.traverseStack=function(){$e("'traverseStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"UNWIND_CACHE")||(u.UNWIND_CACHE=function(){$e("'UNWIND_CACHE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"withBuiltinMalloc")||(u.withBuiltinMalloc=function(){$e("'withBuiltinMalloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"readAsmConstArgsArray")||(u.readAsmConstArgsArray=function(){$e("'readAsmConstArgsArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"readAsmConstArgs")||(u.readAsmConstArgs=function(){$e("'readAsmConstArgs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"jstoi_q")||(u.jstoi_q=function(){$e("'jstoi_q' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"jstoi_s")||(u.jstoi_s=function(){$e("'jstoi_s' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getExecutableName")||(u.getExecutableName=function(){$e("'getExecutableName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"listenOnce")||(u.listenOnce=function(){$e("'listenOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"autoResumeAudioContext")||(u.autoResumeAudioContext=function(){$e("'autoResumeAudioContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"abortStackOverflow")||(u.abortStackOverflow=function(){$e("'abortStackOverflow' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"reallyNegative")||(u.reallyNegative=function(){$e("'reallyNegative' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"formatString")||(u.formatString=function(){$e("'formatString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"PATH")||(u.PATH=function(){$e("'PATH' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"PATH_FS")||(u.PATH_FS=function(){$e("'PATH_FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"SYSCALLS")||(u.SYSCALLS=function(){$e("'SYSCALLS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"syscallMmap2")||(u.syscallMmap2=function(){$e("'syscallMmap2' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"syscallMunmap")||(u.syscallMunmap=function(){$e("'syscallMunmap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"JSEvents")||(u.JSEvents=function(){$e("'JSEvents' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"specialHTMLTargets")||(u.specialHTMLTargets=function(){$e("'specialHTMLTargets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"maybeCStringToJsString")||(u.maybeCStringToJsString=function(){$e("'maybeCStringToJsString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"findEventTarget")||(u.findEventTarget=function(){$e("'findEventTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"findCanvasEventTarget")||(u.findCanvasEventTarget=function(){$e("'findCanvasEventTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"polyfillSetImmediate")||(u.polyfillSetImmediate=function(){$e("'polyfillSetImmediate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"demangle")||(u.demangle=function(){$e("'demangle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"demangleAll")||(u.demangleAll=function(){$e("'demangleAll' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"jsStackTrace")||(u.jsStackTrace=function(){$e("'jsStackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"stackTrace")||(u.stackTrace=function(){$e("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getEnvStrings")||(u.getEnvStrings=function(){$e("'getEnvStrings' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"checkWasiClock")||(u.checkWasiClock=function(){$e("'checkWasiClock' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"writeI53ToI64")||(u.writeI53ToI64=function(){$e("'writeI53ToI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"writeI53ToI64Clamped")||(u.writeI53ToI64Clamped=function(){$e("'writeI53ToI64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"writeI53ToI64Signaling")||(u.writeI53ToI64Signaling=function(){$e("'writeI53ToI64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"writeI53ToU64Clamped")||(u.writeI53ToU64Clamped=function(){$e("'writeI53ToU64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"writeI53ToU64Signaling")||(u.writeI53ToU64Signaling=function(){$e("'writeI53ToU64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"readI53FromI64")||(u.readI53FromI64=function(){$e("'readI53FromI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"readI53FromU64")||(u.readI53FromU64=function(){$e("'readI53FromU64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"convertI32PairToI53")||(u.convertI32PairToI53=function(){$e("'convertI32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"convertU32PairToI53")||(u.convertU32PairToI53=function(){$e("'convertU32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"exceptionLast")||(u.exceptionLast=function(){$e("'exceptionLast' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"exceptionCaught")||(u.exceptionCaught=function(){$e("'exceptionCaught' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"ExceptionInfoAttrs")||(u.ExceptionInfoAttrs=function(){$e("'ExceptionInfoAttrs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"ExceptionInfo")||(u.ExceptionInfo=function(){$e("'ExceptionInfo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"CatchInfo")||(u.CatchInfo=function(){$e("'CatchInfo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"exception_addRef")||(u.exception_addRef=function(){$e("'exception_addRef' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"exception_decRef")||(u.exception_decRef=function(){$e("'exception_decRef' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"Browser")||(u.Browser=function(){$e("'Browser' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"FS")||(u.FS=function(){$e("'FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"MEMFS")||(u.MEMFS=function(){$e("'MEMFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"TTY")||(u.TTY=function(){$e("'TTY' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"PIPEFS")||(u.PIPEFS=function(){$e("'PIPEFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"SOCKFS")||(u.SOCKFS=function(){$e("'SOCKFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"tempFixedLengthArray")||(u.tempFixedLengthArray=function(){$e("'tempFixedLengthArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"miniTempWebGLFloatBuffers")||(u.miniTempWebGLFloatBuffers=function(){$e("'miniTempWebGLFloatBuffers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"heapObjectForWebGLType")||(u.heapObjectForWebGLType=function(){$e("'heapObjectForWebGLType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"heapAccessShiftForWebGLHeap")||(u.heapAccessShiftForWebGLHeap=function(){$e("'heapAccessShiftForWebGLHeap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"GL")||(u.GL=function(){$e("'GL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"emscriptenWebGLGet")||(u.emscriptenWebGLGet=function(){$e("'emscriptenWebGLGet' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"computeUnpackAlignedImageSize")||(u.computeUnpackAlignedImageSize=function(){$e("'computeUnpackAlignedImageSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"emscriptenWebGLGetTexPixelData")||(u.emscriptenWebGLGetTexPixelData=function(){$e("'emscriptenWebGLGetTexPixelData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"emscriptenWebGLGetUniform")||(u.emscriptenWebGLGetUniform=function(){$e("'emscriptenWebGLGetUniform' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"emscriptenWebGLGetVertexAttrib")||(u.emscriptenWebGLGetVertexAttrib=function(){$e("'emscriptenWebGLGetVertexAttrib' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"writeGLArray")||(u.writeGLArray=function(){$e("'writeGLArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"AL")||(u.AL=function(){$e("'AL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"SDL_unicode")||(u.SDL_unicode=function(){$e("'SDL_unicode' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"SDL_ttfContext")||(u.SDL_ttfContext=function(){$e("'SDL_ttfContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"SDL_audio")||(u.SDL_audio=function(){$e("'SDL_audio' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"SDL")||(u.SDL=function(){$e("'SDL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"SDL_gfx")||(u.SDL_gfx=function(){$e("'SDL_gfx' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"GLUT")||(u.GLUT=function(){$e("'GLUT' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"EGL")||(u.EGL=function(){$e("'EGL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"GLFW_Window")||(u.GLFW_Window=function(){$e("'GLFW_Window' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"GLFW")||(u.GLFW=function(){$e("'GLFW' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"GLEW")||(u.GLEW=function(){$e("'GLEW' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"IDBStore")||(u.IDBStore=function(){$e("'IDBStore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"runAndAbortIfError")||(u.runAndAbortIfError=function(){$e("'runAndAbortIfError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"Asyncify")||(u.Asyncify=function(){$e("'Asyncify' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"Fibers")||(u.Fibers=function(){$e("'Fibers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"emval_handle_array")||(u.emval_handle_array=function(){$e("'emval_handle_array' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"emval_free_list")||(u.emval_free_list=function(){$e("'emval_free_list' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"emval_symbols")||(u.emval_symbols=function(){$e("'emval_symbols' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"init_emval")||(u.init_emval=function(){$e("'init_emval' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"count_emval_handles")||(u.count_emval_handles=function(){$e("'count_emval_handles' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"get_first_emval")||(u.get_first_emval=function(){$e("'get_first_emval' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getStringOrSymbol")||(u.getStringOrSymbol=function(){$e("'getStringOrSymbol' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"requireHandle")||(u.requireHandle=function(){$e("'requireHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"emval_newers")||(u.emval_newers=function(){$e("'emval_newers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"craftEmvalAllocator")||(u.craftEmvalAllocator=function(){$e("'craftEmvalAllocator' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"emval_get_global")||(u.emval_get_global=function(){$e("'emval_get_global' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"emval_methodCallers")||(u.emval_methodCallers=function(){$e("'emval_methodCallers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"InternalError")||(u.InternalError=function(){$e("'InternalError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"BindingError")||(u.BindingError=function(){$e("'BindingError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"UnboundTypeError")||(u.UnboundTypeError=function(){$e("'UnboundTypeError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"PureVirtualError")||(u.PureVirtualError=function(){$e("'PureVirtualError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"init_embind")||(u.init_embind=function(){$e("'init_embind' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"throwInternalError")||(u.throwInternalError=function(){$e("'throwInternalError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"throwBindingError")||(u.throwBindingError=function(){$e("'throwBindingError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"throwUnboundTypeError")||(u.throwUnboundTypeError=function(){$e("'throwUnboundTypeError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"ensureOverloadTable")||(u.ensureOverloadTable=function(){$e("'ensureOverloadTable' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"exposePublicSymbol")||(u.exposePublicSymbol=function(){$e("'exposePublicSymbol' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"replacePublicSymbol")||(u.replacePublicSymbol=function(){$e("'replacePublicSymbol' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"extendError")||(u.extendError=function(){$e("'extendError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"createNamedFunction")||(u.createNamedFunction=function(){$e("'createNamedFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"registeredInstances")||(u.registeredInstances=function(){$e("'registeredInstances' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getBasestPointer")||(u.getBasestPointer=function(){$e("'getBasestPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"registerInheritedInstance")||(u.registerInheritedInstance=function(){$e("'registerInheritedInstance' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"unregisterInheritedInstance")||(u.unregisterInheritedInstance=function(){$e("'unregisterInheritedInstance' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getInheritedInstance")||(u.getInheritedInstance=function(){$e("'getInheritedInstance' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getInheritedInstanceCount")||(u.getInheritedInstanceCount=function(){$e("'getInheritedInstanceCount' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getLiveInheritedInstances")||(u.getLiveInheritedInstances=function(){$e("'getLiveInheritedInstances' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"registeredTypes")||(u.registeredTypes=function(){$e("'registeredTypes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"awaitingDependencies")||(u.awaitingDependencies=function(){$e("'awaitingDependencies' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"typeDependencies")||(u.typeDependencies=function(){$e("'typeDependencies' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"registeredPointers")||(u.registeredPointers=function(){$e("'registeredPointers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"registerType")||(u.registerType=function(){$e("'registerType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"whenDependentTypesAreResolved")||(u.whenDependentTypesAreResolved=function(){$e("'whenDependentTypesAreResolved' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"embind_charCodes")||(u.embind_charCodes=function(){$e("'embind_charCodes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"embind_init_charCodes")||(u.embind_init_charCodes=function(){$e("'embind_init_charCodes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"readLatin1String")||(u.readLatin1String=function(){$e("'readLatin1String' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getTypeName")||(u.getTypeName=function(){$e("'getTypeName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"heap32VectorToArray")||(u.heap32VectorToArray=function(){$e("'heap32VectorToArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"requireRegisteredType")||(u.requireRegisteredType=function(){$e("'requireRegisteredType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"getShiftFromSize")||(u.getShiftFromSize=function(){$e("'getShiftFromSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"integerReadValueFromPointer")||(u.integerReadValueFromPointer=function(){$e("'integerReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"enumReadValueFromPointer")||(u.enumReadValueFromPointer=function(){$e("'enumReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"floatReadValueFromPointer")||(u.floatReadValueFromPointer=function(){$e("'floatReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"simpleReadValueFromPointer")||(u.simpleReadValueFromPointer=function(){$e("'simpleReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"runDestructors")||(u.runDestructors=function(){$e("'runDestructors' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"new_")||(u.new_=function(){$e("'new_' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"craftInvokerFunction")||(u.craftInvokerFunction=function(){$e("'craftInvokerFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"embind__requireFunction")||(u.embind__requireFunction=function(){$e("'embind__requireFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"tupleRegistrations")||(u.tupleRegistrations=function(){$e("'tupleRegistrations' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"structRegistrations")||(u.structRegistrations=function(){$e("'structRegistrations' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"genericPointerToWireType")||(u.genericPointerToWireType=function(){$e("'genericPointerToWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"constNoSmartPtrRawPointerToWireType")||(u.constNoSmartPtrRawPointerToWireType=function(){$e("'constNoSmartPtrRawPointerToWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"nonConstNoSmartPtrRawPointerToWireType")||(u.nonConstNoSmartPtrRawPointerToWireType=function(){$e("'nonConstNoSmartPtrRawPointerToWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"init_RegisteredPointer")||(u.init_RegisteredPointer=function(){$e("'init_RegisteredPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"RegisteredPointer")||(u.RegisteredPointer=function(){$e("'RegisteredPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"RegisteredPointer_getPointee")||(u.RegisteredPointer_getPointee=function(){$e("'RegisteredPointer_getPointee' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"RegisteredPointer_destructor")||(u.RegisteredPointer_destructor=function(){$e("'RegisteredPointer_destructor' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"RegisteredPointer_deleteObject")||(u.RegisteredPointer_deleteObject=function(){$e("'RegisteredPointer_deleteObject' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"RegisteredPointer_fromWireType")||(u.RegisteredPointer_fromWireType=function(){$e("'RegisteredPointer_fromWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"runDestructor")||(u.runDestructor=function(){$e("'runDestructor' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"releaseClassHandle")||(u.releaseClassHandle=function(){$e("'releaseClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"finalizationGroup")||(u.finalizationGroup=function(){$e("'finalizationGroup' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"detachFinalizer_deps")||(u.detachFinalizer_deps=function(){$e("'detachFinalizer_deps' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"detachFinalizer")||(u.detachFinalizer=function(){$e("'detachFinalizer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"attachFinalizer")||(u.attachFinalizer=function(){$e("'attachFinalizer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"makeClassHandle")||(u.makeClassHandle=function(){$e("'makeClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"init_ClassHandle")||(u.init_ClassHandle=function(){$e("'init_ClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"ClassHandle")||(u.ClassHandle=function(){$e("'ClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"ClassHandle_isAliasOf")||(u.ClassHandle_isAliasOf=function(){$e("'ClassHandle_isAliasOf' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"throwInstanceAlreadyDeleted")||(u.throwInstanceAlreadyDeleted=function(){$e("'throwInstanceAlreadyDeleted' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"ClassHandle_clone")||(u.ClassHandle_clone=function(){$e("'ClassHandle_clone' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"ClassHandle_delete")||(u.ClassHandle_delete=function(){$e("'ClassHandle_delete' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"deletionQueue")||(u.deletionQueue=function(){$e("'deletionQueue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"ClassHandle_isDeleted")||(u.ClassHandle_isDeleted=function(){$e("'ClassHandle_isDeleted' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"ClassHandle_deleteLater")||(u.ClassHandle_deleteLater=function(){$e("'ClassHandle_deleteLater' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"flushPendingDeletes")||(u.flushPendingDeletes=function(){$e("'flushPendingDeletes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"delayFunction")||(u.delayFunction=function(){$e("'delayFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"setDelayFunction")||(u.setDelayFunction=function(){$e("'setDelayFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"RegisteredClass")||(u.RegisteredClass=function(){$e("'RegisteredClass' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"shallowCopyInternalPointer")||(u.shallowCopyInternalPointer=function(){$e("'shallowCopyInternalPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"downcastPointer")||(u.downcastPointer=function(){$e("'downcastPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"upcastPointer")||(u.upcastPointer=function(){$e("'upcastPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"validateThis")||(u.validateThis=function(){$e("'validateThis' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"char_0")||(u.char_0=function(){$e("'char_0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"char_9")||(u.char_9=function(){$e("'char_9' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"makeLegalFunctionName")||(u.makeLegalFunctionName=function(){$e("'makeLegalFunctionName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"warnOnce")||(u.warnOnce=function(){$e("'warnOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"stackSave")||(u.stackSave=function(){$e("'stackSave' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"stackRestore")||(u.stackRestore=function(){$e("'stackRestore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"stackAlloc")||(u.stackAlloc=function(){$e("'stackAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"AsciiToString")||(u.AsciiToString=function(){$e("'AsciiToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"stringToAscii")||(u.stringToAscii=function(){$e("'stringToAscii' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"UTF16ToString")||(u.UTF16ToString=function(){$e("'UTF16ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"stringToUTF16")||(u.stringToUTF16=function(){$e("'stringToUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"lengthBytesUTF16")||(u.lengthBytesUTF16=function(){$e("'lengthBytesUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"UTF32ToString")||(u.UTF32ToString=function(){$e("'UTF32ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"stringToUTF32")||(u.stringToUTF32=function(){$e("'stringToUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"lengthBytesUTF32")||(u.lengthBytesUTF32=function(){$e("'lengthBytesUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"allocateUTF8")||(u.allocateUTF8=function(){$e("'allocateUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),Object.getOwnPropertyDescriptor(u,"allocateUTF8OnStack")||(u.allocateUTF8OnStack=function(){$e("'allocateUTF8OnStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}),u.writeStackCookie=Me,u.checkStackCookie=Ne,Object.getOwnPropertyDescriptor(u,"ALLOC_NORMAL")||Object.defineProperty(u,"ALLOC_NORMAL",{configurable:!0,get:function(){$e("'ALLOC_NORMAL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}}),Object.getOwnPropertyDescriptor(u,"ALLOC_STACK")||Object.defineProperty(u,"ALLOC_STACK",{configurable:!0,get:function(){$e("'ALLOC_STACK' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}}),Object.getOwnPropertyDescriptor(u,"ALLOC_DYNAMIC")||Object.defineProperty(u,"ALLOC_DYNAMIC",{configurable:!0,get:function(){$e("'ALLOC_DYNAMIC' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}}),Object.getOwnPropertyDescriptor(u,"ALLOC_NONE")||Object.defineProperty(u,"ALLOC_NONE",{configurable:!0,get:function(){$e("'ALLOC_NONE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}}),Qe=function e(){$a||Ps(),$a||(Qe=e)},u.run=Ps,u.preInit)for("function"==typeof u.preInit&&(u.preInit=[u.preInit]);u.preInit.length>0;)u.preInit.pop()();return B=!0,Ps(),e.ready});e.exports=c}).call(this,"/index.js",r(3),"/",r(2).Buffer,r(32).setImmediate)},function(e,t){e.exports=class{meetsCriteria(e){throw new Error("Subclass must implement")}static apply(e,t){return t.filter(t=>e.meetsCriteria(t))}}},function(e,t,r){"use strict";function i(e){this.requestsPerSecond=e.requestsPerSecond,this.promiseImplementation=e.promiseImplementation||Promise,this.lastStartTime=0,this.queued=[]}i.prototype.add=function(e,t){var r=this,i=t||{};return new r.promiseImplementation((function(t,n){r.queued.push({resolve:t,reject:n,promise:e,weight:i.weight||1,signal:i.signal}),r.dequeue()}))},i.prototype.addAll=function(e,t){var r=e.map(function(e){return this.add(e,t)}.bind(this));return Promise.all(r)},i.prototype.dequeue=function(){if(this.queued.length>0){var e=new Date,t=this.queued[0].weight,r=1e3/this.requestsPerSecond*t,i=e-this.lastStartTime;i>=r?this._execute():setTimeout(function(){this.dequeue()}.bind(this),r-i)}},i.prototype._execute=function(){this.lastStartTime=new Date;var e=this.queued.shift();e.signal&&e.signal.aborted?e.reject(new DOMException("","AbortError")):e.promise().then((function(t){e.resolve(t)})).catch((function(t){e.reject(t)}))},e.exports=i},function(e,t,r){"use strict";(function(e){var t=r(381).getNewLibraryCopy(),i=r(382),n=r(392);try{var a=n(r.c,(function(){return r(393)}),(function(){r(211)}),e)}catch(e){var o=r(517).EOL;throw console.error(o+"###"+o+'### The "request" library is not installed automatically anymore.'+o+'### But is a dependency of "request-promise".'+o+"### Please install it with:"+o+"### npm install request --save"+o+"###"+o),e}t.config({cancellation:!0}),i({request:a,PromiseImpl:t,expose:["then","catch","finally","cancel","promise"],constructorMixin:function(e,t,r){var i=this;r((function(){i.abort()}))}}),a.bindCLS=function(){throw new Error("CLS support was dropped. To get it back read: https://github.com/request/request-promise/wiki/Getting-Back-Support-for-Continuation-Local-Storage")},e.exports=a}).call(this,r(22)(e))},function(e,t,r){(function(t,r,i){var n;n=function(){var e,n,a;return function e(t,r,i){function n(o,s){if(!r[o]){if(!t[o]){var c="function"==typeof _dereq_&&_dereq_;if(!s&&c)return c(o,!0);if(a)return a(o,!0);var u=new Error("Cannot find module '"+o+"'");throw u.code="MODULE_NOT_FOUND",u}var l=r[o]={exports:{}};t[o][0].call(l.exports,(function(e){var r=t[o][1][e];return n(r||e)}),l,l.exports,e,t,r,i)}return r[o].exports}for(var a="function"==typeof _dereq_&&_dereq_,o=0;o0;)p(e)}function p(e){var t=e.shift();if("function"!=typeof t)t._settlePromises();else{var r=e.shift(),i=e.shift();t.call(r,i)}}c.prototype.setScheduler=function(e){var t=this._schedule;return this._schedule=e,this._customScheduler=!0,t},c.prototype.hasCustomScheduler=function(){return this._customScheduler},c.prototype.enableTrampoline=function(){this._trampolineEnabled=!0},c.prototype.disableTrampolineIfNecessary=function(){s.hasDevTools&&(this._trampolineEnabled=!1)},c.prototype.haveItemsQueued=function(){return this._isTickUsed||this._haveDrainedQueues},c.prototype.fatalError=function(e,r){r?(t.stderr.write("Fatal "+(e instanceof Error?e.stack:e)+"\n"),t.exit(2)):this.throwLater(e)},c.prototype.throwLater=function(e,t){if(1===arguments.length&&(t=e,e=function(){throw t}),"undefined"!=typeof setTimeout)setTimeout((function(){e(t)}),0);else try{this._schedule((function(){e(t)}))}catch(e){throw new Error("No async scheduler available\n\n See http://goo.gl/MqrFmX\n")}},s.hasDevTools?(c.prototype.invokeLater=function(e,t,r){this._trampolineEnabled?u.call(this,e,t,r):this._schedule((function(){setTimeout((function(){e.call(t,r)}),100)}))},c.prototype.invoke=function(e,t,r){this._trampolineEnabled?l.call(this,e,t,r):this._schedule((function(){e.call(t,r)}))},c.prototype.settlePromises=function(e){this._trampolineEnabled?h.call(this,e):this._schedule((function(){e._settlePromises()}))}):(c.prototype.invokeLater=u,c.prototype.invoke=l,c.prototype.settlePromises=h),c.prototype._drainQueues=function(){d(this._normalQueue),this._reset(),this._haveDrainedQueues=!0,d(this._lateQueue)},c.prototype._queueTick=function(){this._isTickUsed||(this._isTickUsed=!0,this._schedule(this.drainQueues))},c.prototype._reset=function(){this._isTickUsed=!1},r.exports=c,r.exports.firstLineError=n},{"./queue":26,"./schedule":29,"./util":36}],3:[function(e,t,r){"use strict";t.exports=function(e,t,r,i){var n=!1,a=function(e,t){this._reject(t)},o=function(e,t){t.promiseRejectionQueued=!0,t.bindingPromise._then(a,a,null,this,e)},s=function(e,t){0==(50397184&this._bitField)&&this._resolveCallback(t.target)},c=function(e,t){t.promiseRejectionQueued||this._reject(e)};e.prototype.bind=function(a){n||(n=!0,e.prototype._propagateFrom=i.propagateFromFunction(),e.prototype._boundValue=i.boundValueFunction());var u=r(a),l=new e(t);l._propagateFrom(this,1);var h=this._target();if(l._setBoundTo(u),u instanceof e){var d={promiseRejectionQueued:!1,promise:l,target:h,bindingPromise:u};h._then(t,o,void 0,l,d),u._then(s,c,void 0,l,d),l._setOnCancel(u)}else l._resolveCallback(h);return l},e.prototype._setBoundTo=function(e){void 0!==e?(this._bitField=2097152|this._bitField,this._boundTo=e):this._bitField=-2097153&this._bitField},e.prototype._isBound=function(){return 2097152==(2097152&this._bitField)},e.bind=function(t,r){return e.resolve(r).bind(t)}}},{}],4:[function(e,t,r){"use strict";var i;"undefined"!=typeof Promise&&(i=Promise);var n=e("./promise")();n.noConflict=function(){try{Promise===n&&(Promise=i)}catch(e){}return n},t.exports=n},{"./promise":22}],5:[function(e,t,r){"use strict";var i=Object.create;if(i){var n=i(null),a=i(null);n[" size"]=a[" size"]=0}t.exports=function(t){var r=e("./util"),i=r.canEvaluate;function n(e){return function(e,i){var n;if(null!=e&&(n=e[i]),"function"!=typeof n){var a="Object "+r.classString(e)+" has no method '"+r.toString(i)+"'";throw new t.TypeError(a)}return n}(e,this.pop()).apply(e,this)}function a(e){return e[this]}function o(e){var t=+this;return t<0&&(t=Math.max(0,t+e.length)),e[t]}r.isIdentifier,t.prototype.call=function(e){var t=[].slice.call(arguments,1);return t.push(e),this._then(n,void 0,void 0,t,void 0)},t.prototype.get=function(e){var t;if("number"==typeof e)t=o;else if(i){var r=(void 0)(e);t=null!==r?r:a}else t=a;return this._then(t,void 0,void 0,e,void 0)}}},{"./util":36}],6:[function(e,t,r){"use strict";t.exports=function(t,r,i,n){var a=e("./util"),o=a.tryCatch,s=a.errorObj,c=t._async;t.prototype.break=t.prototype.cancel=function(){if(!n.cancellation())return this._warn("cancellation is disabled");for(var e=this,t=e;e._isCancellable();){if(!e._cancelBy(t)){t._isFollowing()?t._followee().cancel():t._cancelBranched();break}var r=e._cancellationParent;if(null==r||!r._isCancellable()){e._isFollowing()?e._followee().cancel():e._cancelBranched();break}e._isFollowing()&&e._followee().cancel(),e._setWillBeCancelled(),t=e,e=r}},t.prototype._branchHasCancelled=function(){this._branchesRemainingToCancel--},t.prototype._enoughBranchesHaveCancelled=function(){return void 0===this._branchesRemainingToCancel||this._branchesRemainingToCancel<=0},t.prototype._cancelBy=function(e){return e===this?(this._branchesRemainingToCancel=0,this._invokeOnCancel(),!0):(this._branchHasCancelled(),!!this._enoughBranchesHaveCancelled()&&(this._invokeOnCancel(),!0))},t.prototype._cancelBranched=function(){this._enoughBranchesHaveCancelled()&&this._cancel()},t.prototype._cancel=function(){this._isCancellable()&&(this._setCancelled(),c.invoke(this._cancelPromises,this,void 0))},t.prototype._cancelPromises=function(){this._length()>0&&this._settlePromises()},t.prototype._unsetOnCancel=function(){this._onCancelField=void 0},t.prototype._isCancellable=function(){return this.isPending()&&!this._isCancelled()},t.prototype.isCancellable=function(){return this.isPending()&&!this.isCancelled()},t.prototype._doInvokeOnCancel=function(e,t){if(a.isArray(e))for(var r=0;r=0)return r[e]}return e.prototype._promiseCreated=function(){},e.prototype._pushContext=function(){},e.prototype._popContext=function(){return null},e._peekContext=e.prototype._peekContext=function(){},i.prototype._pushContext=function(){void 0!==this._trace&&(this._trace._promiseCreated=null,r.push(this._trace))},i.prototype._popContext=function(){if(void 0!==this._trace){var e=r.pop(),t=e._promiseCreated;return e._promiseCreated=null,t}return null},i.CapturedTrace=null,i.create=function(){if(t)return new i},i.deactivateLongStackTraces=function(){},i.activateLongStackTraces=function(){var r=e.prototype._pushContext,a=e.prototype._popContext,o=e._peekContext,s=e.prototype._peekContext,c=e.prototype._promiseCreated;i.deactivateLongStackTraces=function(){e.prototype._pushContext=r,e.prototype._popContext=a,e._peekContext=o,e.prototype._peekContext=s,e.prototype._promiseCreated=c,t=!1},t=!0,e.prototype._pushContext=i.prototype._pushContext,e.prototype._popContext=i.prototype._popContext,e._peekContext=e.prototype._peekContext=n,e.prototype._promiseCreated=function(){var e=this._peekContext();e&&null==e._promiseCreated&&(e._promiseCreated=this)}},i}},{}],9:[function(e,r,i){"use strict";r.exports=function(r,i){var n,a,o,s=r._getDomain,c=r._async,u=e("./errors").Warning,l=e("./util"),h=e("./es5"),d=l.canAttachTrace,p=/[\\\/]bluebird[\\\/]js[\\\/](release|debug|instrumented)/,f=/\((?:timers\.js):\d+:\d+\)/,m=/[\/<\(](.+?):(\d+):(\d+)\)?\s*$/,g=null,_=null,v=!1,y=!(0==l.env("BLUEBIRD_DEBUG")),b=!(0==l.env("BLUEBIRD_WARNINGS")||!y&&!l.env("BLUEBIRD_WARNINGS")),E=!(0==l.env("BLUEBIRD_LONG_STACK_TRACES")||!y&&!l.env("BLUEBIRD_LONG_STACK_TRACES")),w=0!=l.env("BLUEBIRD_W_FORGOTTEN_RETURN")&&(b||!!l.env("BLUEBIRD_W_FORGOTTEN_RETURN"));r.prototype.suppressUnhandledRejections=function(){var e=this._target();e._bitField=-1048577&e._bitField|524288},r.prototype._ensurePossibleRejectionHandled=function(){if(0==(524288&this._bitField)){this._setRejectionIsUnhandled();var e=this;setTimeout((function(){e._notifyUnhandledRejection()}),1)}},r.prototype._notifyUnhandledRejectionIsHandled=function(){Z("rejectionHandled",n,void 0,this)},r.prototype._setReturnedNonUndefined=function(){this._bitField=268435456|this._bitField},r.prototype._returnedNonUndefined=function(){return 0!=(268435456&this._bitField)},r.prototype._notifyUnhandledRejection=function(){if(this._isRejectionUnhandled()){var e=this._settledValue();this._setUnhandledRejectionIsNotified(),Z("unhandledRejection",a,e,this)}},r.prototype._setUnhandledRejectionIsNotified=function(){this._bitField=262144|this._bitField},r.prototype._unsetUnhandledRejectionIsNotified=function(){this._bitField=-262145&this._bitField},r.prototype._isUnhandledRejectionNotified=function(){return(262144&this._bitField)>0},r.prototype._setRejectionIsUnhandled=function(){this._bitField=1048576|this._bitField},r.prototype._unsetRejectionIsUnhandled=function(){this._bitField=-1048577&this._bitField,this._isUnhandledRejectionNotified()&&(this._unsetUnhandledRejectionIsNotified(),this._notifyUnhandledRejectionIsHandled())},r.prototype._isRejectionUnhandled=function(){return(1048576&this._bitField)>0},r.prototype._warn=function(e,t,r){return U(e,t,r||this)},r.onPossiblyUnhandledRejection=function(e){var t=s();a="function"==typeof e?null===t?e:l.domainBind(t,e):void 0},r.onUnhandledRejectionHandled=function(e){var t=s();n="function"==typeof e?null===t?e:l.domainBind(t,e):void 0};var S=function(){};r.longStackTraces=function(){if(c.haveItemsQueued()&&!$.longStackTraces)throw new Error("cannot enable long stack traces after promises have been created\n\n See http://goo.gl/MqrFmX\n");if(!$.longStackTraces&&X()){var e=r.prototype._captureStackTrace,t=r.prototype._attachExtraTrace,n=r.prototype._dereferenceTrace;$.longStackTraces=!0,S=function(){if(c.haveItemsQueued()&&!$.longStackTraces)throw new Error("cannot enable long stack traces after promises have been created\n\n See http://goo.gl/MqrFmX\n");r.prototype._captureStackTrace=e,r.prototype._attachExtraTrace=t,r.prototype._dereferenceTrace=n,i.deactivateLongStackTraces(),c.enableTrampoline(),$.longStackTraces=!1},r.prototype._captureStackTrace=B,r.prototype._attachExtraTrace=z,r.prototype._dereferenceTrace=L,i.activateLongStackTraces(),c.disableTrampolineIfNecessary()}},r.hasLongStackTraces=function(){return $.longStackTraces&&X()};var k=function(){try{if("function"==typeof CustomEvent){var e=new CustomEvent("CustomEvent");return l.global.dispatchEvent(e),function(e,t){var r={detail:t,cancelable:!0};h.defineProperty(r,"promise",{value:t.promise}),h.defineProperty(r,"reason",{value:t.reason});var i=new CustomEvent(e.toLowerCase(),r);return!l.global.dispatchEvent(i)}}return"function"==typeof Event?(e=new Event("CustomEvent"),l.global.dispatchEvent(e),function(e,t){var r=new Event(e.toLowerCase(),{cancelable:!0});return r.detail=t,h.defineProperty(r,"promise",{value:t.promise}),h.defineProperty(r,"reason",{value:t.reason}),!l.global.dispatchEvent(r)}):((e=document.createEvent("CustomEvent")).initCustomEvent("testingtheevent",!1,!0,{}),l.global.dispatchEvent(e),function(e,t){var r=document.createEvent("CustomEvent");return r.initCustomEvent(e.toLowerCase(),!1,!0,t),!l.global.dispatchEvent(r)})}catch(e){}return function(){return!1}}(),x=l.isNode?function(){return t.emit.apply(t,arguments)}:l.global?function(e){var t="on"+e.toLowerCase(),r=l.global[t];return!!r&&(r.apply(l.global,[].slice.call(arguments,1)),!0)}:function(){return!1};function M(e,t){return{promise:t}}var N={promiseCreated:M,promiseFulfilled:M,promiseRejected:M,promiseResolved:M,promiseCancelled:M,promiseChained:function(e,t,r){return{promise:t,child:r}},warning:function(e,t){return{warning:t}},unhandledRejection:function(e,t,r){return{reason:t,promise:r}},rejectionHandled:M},j=function(e){var t=!1;try{t=x.apply(null,arguments)}catch(e){c.throwLater(e),t=!0}var r=!1;try{r=k(e,N[e].apply(null,arguments))}catch(e){c.throwLater(e),r=!0}return r||t};function T(){return!1}function R(e,t,r){var i=this;try{e(t,r,(function(e){if("function"!=typeof e)throw new TypeError("onCancel must be a function, got: "+l.toString(e));i._attachCancellationCallback(e)}))}catch(e){return e}}function I(e){if(!this._isCancellable())return this;var t=this._onCancel();void 0!==t?l.isArray(t)?t.push(e):this._setOnCancel([t,e]):this._setOnCancel(e)}function O(){return this._onCancelField}function A(e){this._onCancelField=e}function P(){this._cancellationParent=void 0,this._onCancelField=void 0}function D(e,t){if(0!=(1&t)){this._cancellationParent=e;var r=e._branchesRemainingToCancel;void 0===r&&(r=0),e._branchesRemainingToCancel=r+1}0!=(2&t)&&e._isBound()&&this._setBoundTo(e._boundTo)}r.config=function(e){if("longStackTraces"in(e=Object(e))&&(e.longStackTraces?r.longStackTraces():!e.longStackTraces&&r.hasLongStackTraces()&&S()),"warnings"in e){var t=e.warnings;$.warnings=!!t,w=$.warnings,l.isObject(t)&&"wForgottenReturn"in t&&(w=!!t.wForgottenReturn)}if("cancellation"in e&&e.cancellation&&!$.cancellation){if(c.haveItemsQueued())throw new Error("cannot enable cancellation after promises are in use");r.prototype._clearCancellationData=P,r.prototype._propagateFrom=D,r.prototype._onCancel=O,r.prototype._setOnCancel=A,r.prototype._attachCancellationCallback=I,r.prototype._execute=R,F=D,$.cancellation=!0}return"monitoring"in e&&(e.monitoring&&!$.monitoring?($.monitoring=!0,r.prototype._fireEvent=j):!e.monitoring&&$.monitoring&&($.monitoring=!1,r.prototype._fireEvent=T)),r},r.prototype._fireEvent=T,r.prototype._execute=function(e,t,r){try{e(t,r)}catch(e){return e}},r.prototype._onCancel=function(){},r.prototype._setOnCancel=function(e){},r.prototype._attachCancellationCallback=function(e){},r.prototype._captureStackTrace=function(){},r.prototype._attachExtraTrace=function(){},r.prototype._dereferenceTrace=function(){},r.prototype._clearCancellationData=function(){},r.prototype._propagateFrom=function(e,t){};var F=function(e,t){0!=(2&t)&&e._isBound()&&this._setBoundTo(e._boundTo)};function C(){var e=this._boundTo;return void 0!==e&&e instanceof r?e.isFulfilled()?e.value():void 0:e}function B(){this._trace=new G(this._peekContext())}function z(e,t){if(d(e)){var r=this._trace;if(void 0!==r&&t&&(r=r._parent),void 0!==r)r.attachExtraTrace(e);else if(!e.__stackCleaned__){var i=q(e);l.notEnumerableProp(e,"stack",i.message+"\n"+i.stack.join("\n")),l.notEnumerableProp(e,"__stackCleaned__",!0)}}}function L(){this._trace=void 0}function U(e,t,i){if($.warnings){var n,a=new u(e);if(t)i._attachExtraTrace(a);else if($.longStackTraces&&(n=r._peekContext()))n.attachExtraTrace(a);else{var o=q(a);a.stack=o.message+"\n"+o.stack.join("\n")}j("warning",a)||K(a,"",!0)}}function H(e){for(var t=[],r=0;r0?function(e){for(var t=e.stack.replace(/\s+$/g,"").split("\n"),r=0;r0&&"SyntaxError"!=e.name&&(t=t.slice(r)),t}(e):[" (No stack trace)"],{message:r,stack:"SyntaxError"==e.name?t:H(t)}}function K(e,t,r){if("undefined"!=typeof console){var i;if(l.isObject(e)){var n=e.stack;i=t+_(n,e)}else i=t+String(e);"function"==typeof o?o(i,r):"function"!=typeof console.log&&"object"!=typeof console.log||console.log(i)}}function Z(e,t,r,i){var n=!1;try{"function"==typeof t&&(n=!0,"rejectionHandled"===e?t(i):t(r,i))}catch(e){c.throwLater(e)}"unhandledRejection"===e?j(e,r,i)||n||K(r,"Unhandled rejection "):j(e,i)}function W(e){var t;if("function"==typeof e)t="[function "+(e.name||"anonymous")+"]";else{if(t=e&&"function"==typeof e.toString?e.toString():l.toString(e),/\[object [a-zA-Z0-9$_]+\]/.test(t))try{t=JSON.stringify(e)}catch(e){}0===t.length&&(t="(empty array)")}return"(<"+function(e){return e.length<41?e:e.substr(0,38)+"..."}(t)+">, no stack trace)"}function X(){return"function"==typeof Y}var Q=function(){return!1},J=/[\/<\(]([^:\/]+):(\d+):(?:\d+)\)?\s*$/;function V(e){var t=e.match(J);if(t)return{fileName:t[1],line:parseInt(t[2],10)}}function G(e){this._parent=e,this._promisesCreated=0;var t=this._length=1+(void 0===e?0:e._length);Y(this,G),t>32&&this.uncycle()}l.inherits(G,Error),i.CapturedTrace=G,G.prototype.uncycle=function(){var e=this._length;if(!(e<2)){for(var t=[],r={},i=0,n=this;void 0!==n;++i)t.push(n),n=n._parent;for(i=(e=this._length=i)-1;i>=0;--i){var a=t[i].stack;void 0===r[a]&&(r[a]=i)}for(i=0;i0&&(t[o-1]._parent=void 0,t[o-1]._length=1),t[i]._parent=void 0,t[i]._length=1;var s=i>0?t[i-1]:this;o=0;--u)t[u]._length=c,c++;return}}}},G.prototype.attachExtraTrace=function(e){if(!e.__stackCleaned__){this.uncycle();for(var t=q(e),r=t.message,i=[t.stack],n=this;void 0!==n;)i.push(H(n.stack.split("\n"))),n=n._parent;!function(e){for(var t=e[0],r=1;r=0;--s)if(i[s]===a){o=s;break}for(s=o;s>=0;--s){var c=i[s];if(t[n]!==c)break;t.pop(),n--}t=i}}(i),function(e){for(var t=0;t=0)return g=/@/,_=t,v=!0,function(e){e.stack=(new Error).stack};try{throw new Error}catch(e){i="stack"in e}return!("stack"in n)&&i&&"number"==typeof Error.stackTraceLimit?(g=e,_=t,function(e){Error.stackTraceLimit+=6;try{throw new Error}catch(t){e.stack=t.stack}Error.stackTraceLimit-=6}):(_=function(e,t){return"string"==typeof e?e:"object"!=typeof t&&"function"!=typeof t||void 0===t.name||void 0===t.message?W(t):t.toString()},null)}();"undefined"!=typeof console&&void 0!==console.warn&&(o=function(e){console.warn(e)},l.isNode&&t.stderr.isTTY?o=function(e,t){var r=t?"":"";console.warn(r+e+"\n")}:l.isNode||"string"!=typeof(new Error).stack||(o=function(e,t){console.warn("%c"+e,t?"color: darkorange":"color: red")}));var $={warnings:b,longStackTraces:!1,cancellation:!1,monitoring:!1};return E&&r.longStackTraces(),{longStackTraces:function(){return $.longStackTraces},warnings:function(){return $.warnings},cancellation:function(){return $.cancellation},monitoring:function(){return $.monitoring},propagateFromFunction:function(){return F},boundValueFunction:function(){return C},checkForgottenReturns:function(e,t,r,i,n){if(void 0===e&&null!==t&&w){if(void 0!==n&&n._returnedNonUndefined())return;if(0==(65535&i._bitField))return;r&&(r+=" ");var a="",o="";if(t._trace){for(var s=t._trace.stack.split("\n"),c=H(s),u=c.length-1;u>=0;--u){var l=c[u];if(!f.test(l)){var h=l.match(m);h&&(a="at "+h[1]+":"+h[2]+":"+h[3]+" ");break}}if(c.length>0){var d=c[0];for(u=0;u0&&(o="\n"+s[u-1]);break}}}var p="a promise was created in a "+r+"handler "+a+"but was not returned from it, see http://goo.gl/rRqMUw"+o;i._warn(p,!0,t)}},setBounds:function(e,t){if(X()){for(var r,i,n=e.stack.split("\n"),a=t.stack.split("\n"),o=-1,s=-1,c=0;c=s||(Q=function(e){if(p.test(e))return!0;var t=V(e);return!!(t&&t.fileName===r&&o<=t.line&&t.line<=s)})}},warn:U,deprecated:function(e,t){var r=e+" is deprecated and will be removed in a future version.";return t&&(r+=" Use "+t+" instead."),U(r)},CapturedTrace:G,fireDomEvent:k,fireGlobalEvent:x}}},{"./errors":12,"./es5":13,"./util":36}],10:[function(e,t,r){"use strict";t.exports=function(e){function t(){return this.value}function r(){throw this.reason}e.prototype.return=e.prototype.thenReturn=function(r){return r instanceof e&&r.suppressUnhandledRejections(),this._then(t,void 0,void 0,{value:r},void 0)},e.prototype.throw=e.prototype.thenThrow=function(e){return this._then(r,void 0,void 0,{reason:e},void 0)},e.prototype.catchThrow=function(e){if(arguments.length<=1)return this._then(void 0,r,void 0,{reason:e},void 0);var t=arguments[1],i=function(){throw t};return this.caught(e,i)},e.prototype.catchReturn=function(r){if(arguments.length<=1)return r instanceof e&&r.suppressUnhandledRejections(),this._then(void 0,t,void 0,{value:r},void 0);var i=arguments[1];i instanceof e&&i.suppressUnhandledRejections();var n=function(){return i};return this.caught(r,n)}}},{}],11:[function(e,t,r){"use strict";t.exports=function(e,t){var r=e.reduce,i=e.all;function n(){return i(this)}e.prototype.each=function(e){return r(this,e,t,0)._then(n,void 0,void 0,this,void 0)},e.prototype.mapSeries=function(e){return r(this,e,t,t)},e.each=function(e,i){return r(e,i,t,0)._then(n,void 0,void 0,e,void 0)},e.mapSeries=function(e,i){return r(e,i,t,t)}}},{}],12:[function(e,t,r){"use strict";var i,n,a=e("./es5"),o=a.freeze,s=e("./util"),c=s.inherits,u=s.notEnumerableProp;function l(e,t){function r(i){if(!(this instanceof r))return new r(i);u(this,"message","string"==typeof i?i:t),u(this,"name",e),Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):Error.call(this)}return c(r,Error),r}var h=l("Warning","warning"),d=l("CancellationError","cancellation error"),p=l("TimeoutError","timeout error"),f=l("AggregateError","aggregate error");try{i=TypeError,n=RangeError}catch(e){i=l("TypeError","type error"),n=l("RangeError","range error")}for(var m="join pop push shift unshift slice filter forEach some every map indexOf lastIndexOf reduce reduceRight sort reverse".split(" "),g=0;g1?e.cancelPromise._reject(t):e.cancelPromise._cancel(),e.cancelPromise=null,!0)}function h(){return p.call(this,this.promise._target()._settledValue())}function d(e){if(!l(this,e))return o.e=e,o}function p(e){var n=this.promise,s=this.handler;if(!this.called){this.called=!0;var c=this.isFinallyHandler()?s.call(n._boundValue()):s.call(n._boundValue(),e);if(c===i)return c;if(void 0!==c){n._setReturnedNonUndefined();var p=r(c,n);if(p instanceof t){if(null!=this.cancelPromise){if(p._isCancelled()){var f=new a("late cancellation observer");return n._attachExtraTrace(f),o.e=f,o}p.isPending()&&p._attachCancellationCallback(new u(this))}return p._then(h,d,void 0,this,void 0)}}}return n.isRejected()?(l(this),o.e=e,o):(l(this),e)}return c.prototype.isFinallyHandler=function(){return 0===this.type},u.prototype._resultCancelled=function(){l(this.finallyHandler)},t.prototype._passThrough=function(e,t,r,i){return"function"!=typeof e?this.then():this._then(r,i,void 0,new c(this,t,e),void 0)},t.prototype.lastly=t.prototype.finally=function(e){return this._passThrough(e,0,p,p)},t.prototype.tap=function(e){return this._passThrough(e,1,p)},t.prototype.tapCatch=function(e){var r=arguments.length;if(1===r)return this._passThrough(e,1,void 0,p);var i,a=new Array(r-1),o=0;for(i=0;i0&&"function"==typeof arguments[t]&&(e=arguments[t]);var i=[].slice.call(arguments);e&&i.pop();var n=new r(i).promise();return void 0!==e?n.spread(e):n}}},{"./util":36}],18:[function(e,t,r){"use strict";t.exports=function(t,r,i,n,a,o){var s=t._getDomain,c=e("./util"),u=c.tryCatch,l=c.errorObj,h=t._async;function d(e,t,r,i){this.constructor$(e),this._promise._captureStackTrace();var n=s();this._callback=null===n?t:c.domainBind(n,t),this._preservedValues=i===a?new Array(this.length()):null,this._limit=r,this._inFlight=0,this._queue=[],h.invoke(this._asyncInit,this,void 0)}function p(e,r,n,a){if("function"!=typeof r)return i("expecting a function but got "+c.classString(r));var o=0;if(void 0!==n){if("object"!=typeof n||null===n)return t.reject(new TypeError("options argument must be an object but it is "+c.classString(n)));if("number"!=typeof n.concurrency)return t.reject(new TypeError("'concurrency' must be a number but it is "+c.classString(n.concurrency)));o=n.concurrency}return new d(e,r,o="number"==typeof o&&isFinite(o)&&o>=1?o:0,a).promise()}c.inherits(d,r),d.prototype._asyncInit=function(){this._init$(void 0,-2)},d.prototype._init=function(){},d.prototype._promiseFulfilled=function(e,r){var i=this._values,a=this.length(),s=this._preservedValues,c=this._limit;if(r<0){if(i[r=-1*r-1]=e,c>=1&&(this._inFlight--,this._drainQueue(),this._isResolved()))return!0}else{if(c>=1&&this._inFlight>=c)return i[r]=e,this._queue.push(r),!1;null!==s&&(s[r]=e);var h=this._promise,d=this._callback,p=h._boundValue();h._pushContext();var f=u(d).call(p,e,r,a),m=h._popContext();if(o.checkForgottenReturns(f,m,null!==s?"Promise.filter":"Promise.map",h),f===l)return this._reject(f.e),!0;var g=n(f,this._promise);if(g instanceof t){var _=(g=g._target())._bitField;if(0==(50397184&_))return c>=1&&this._inFlight++,i[r]=g,g._proxy(this,-1*(r+1)),!1;if(0==(33554432&_))return 0!=(16777216&_)?(this._reject(g._reason()),!0):(this._cancel(),!0);f=g._value()}i[r]=f}return++this._totalResolved>=a&&(null!==s?this._filter(i,s):this._resolve(i),!0)},d.prototype._drainQueue=function(){for(var e=this._queue,t=this._limit,r=this._values;e.length>0&&this._inFlight1){a.deprecated("calling Promise.try with more than 1 argument");var u=arguments[1],l=arguments[2];i=o.isArray(u)?s(e).apply(l,u):s(e).call(l,u)}else i=s(e)();var h=c._popContext();return a.checkForgottenReturns(i,h,"Promise.try",c),c._resolveFromSyncValue(i),c},t.prototype._resolveFromSyncValue=function(e){e===o.errorObj?this._rejectCallback(e.e,!1):this._resolveCallback(e,!0)}}},{"./util":36}],20:[function(e,t,r){"use strict";var i=e("./util"),n=i.maybeWrapAsError,a=e("./errors").OperationalError,o=e("./es5"),s=/^(?:name|message|stack|cause)$/;function c(e){var t;if(function(e){return e instanceof Error&&o.getPrototypeOf(e)===Error.prototype}(e)){(t=new a(e)).name=e.name,t.message=e.message,t.stack=e.stack;for(var r=o.keys(e),n=0;n1){var r,i=new Array(t-1),n=0;for(r=0;r0&&"function"!=typeof e&&"function"!=typeof t){var r=".then() only accepts functions but was passed: "+u.classString(e);arguments.length>1&&(r+=", "+u.classString(t)),this._warn(r)}return this._then(e,t,void 0,void 0,void 0)},T.prototype.done=function(e,t){this._then(e,t,void 0,void 0,void 0)._setIsFinal()},T.prototype.spread=function(e){return"function"!=typeof e?a("expecting a function but got "+u.classString(e)):this.all()._then(e,void 0,void 0,_,void 0)},T.prototype.toJSON=function(){var e={isFulfilled:!1,isRejected:!1,fulfillmentValue:void 0,rejectionReason:void 0};return this.isFulfilled()?(e.fulfillmentValue=this.value(),e.isFulfilled=!0):this.isRejected()&&(e.rejectionReason=this.reason(),e.isRejected=!0),e},T.prototype.all=function(){return arguments.length>0&&this._warn(".all() was passed arguments but it does not take any"),new b(this).promise()},T.prototype.error=function(e){return this.caught(u.originatesFromRejection,e)},T.getNewLibraryCopy=r.exports,T.is=function(e){return e instanceof T},T.fromNode=T.fromCallback=function(e){var t=new T(g);t._captureStackTrace();var r=arguments.length>1&&!!Object(arguments[1]).multiArgs,i=j(e)(M(t,r));return i===N&&t._rejectCallback(i.e,!0),t._isFateSealed()||t._setAsyncGuaranteed(),t},T.all=function(e){return new b(e).promise()},T.cast=function(e){var t=y(e);return t instanceof T||((t=new T(g))._captureStackTrace(),t._setFulfilled(),t._rejectionHandler0=e),t},T.resolve=T.fulfilled=T.cast,T.reject=T.rejected=function(e){var t=new T(g);return t._captureStackTrace(),t._rejectCallback(e,!0),t},T.setScheduler=function(e){if("function"!=typeof e)throw new f("expecting a function but got "+u.classString(e));return d.setScheduler(e)},T.prototype._then=function(e,t,r,i,n){var a=void 0!==n,o=a?n:new T(g),c=this._target(),l=c._bitField;a||(o._propagateFrom(this,3),o._captureStackTrace(),void 0===i&&0!=(2097152&this._bitField)&&(i=0!=(50397184&l)?this._boundValue():c===this?void 0:this._boundTo),this._fireEvent("promiseChained",this,o));var h=s();if(0!=(50397184&l)){var p,f,_=c._settlePromiseCtx;0!=(33554432&l)?(f=c._rejectionHandler0,p=e):0!=(16777216&l)?(f=c._fulfillmentHandler0,p=t,c._unsetRejectionIsUnhandled()):(_=c._settlePromiseLateCancellationObserver,f=new m("late cancellation observer"),c._attachExtraTrace(f),p=t),d.invoke(_,c,{handler:null===h?p:"function"==typeof p&&u.domainBind(h,p),promise:o,receiver:i,value:f})}else c._addCallbacks(e,t,o,i,h);return o},T.prototype._length=function(){return 65535&this._bitField},T.prototype._isFateSealed=function(){return 0!=(117506048&this._bitField)},T.prototype._isFollowing=function(){return 67108864==(67108864&this._bitField)},T.prototype._setLength=function(e){this._bitField=-65536&this._bitField|65535&e},T.prototype._setFulfilled=function(){this._bitField=33554432|this._bitField,this._fireEvent("promiseFulfilled",this)},T.prototype._setRejected=function(){this._bitField=16777216|this._bitField,this._fireEvent("promiseRejected",this)},T.prototype._setFollowing=function(){this._bitField=67108864|this._bitField,this._fireEvent("promiseResolved",this)},T.prototype._setIsFinal=function(){this._bitField=4194304|this._bitField},T.prototype._isFinal=function(){return(4194304&this._bitField)>0},T.prototype._unsetCancelled=function(){this._bitField=-65537&this._bitField},T.prototype._setCancelled=function(){this._bitField=65536|this._bitField,this._fireEvent("promiseCancelled",this)},T.prototype._setWillBeCancelled=function(){this._bitField=8388608|this._bitField},T.prototype._setAsyncGuaranteed=function(){d.hasCustomScheduler()||(this._bitField=134217728|this._bitField)},T.prototype._receiverAt=function(e){var t=0===e?this._receiver0:this[4*e-4+3];if(t!==c)return void 0===t&&this._isBound()?this._boundValue():t},T.prototype._promiseAt=function(e){return this[4*e-4+2]},T.prototype._fulfillmentHandlerAt=function(e){return this[4*e-4+0]},T.prototype._rejectionHandlerAt=function(e){return this[4*e-4+1]},T.prototype._boundValue=function(){},T.prototype._migrateCallback0=function(e){e._bitField;var t=e._fulfillmentHandler0,r=e._rejectionHandler0,i=e._promise0,n=e._receiverAt(0);void 0===n&&(n=c),this._addCallbacks(t,r,i,n,null)},T.prototype._migrateCallbackAt=function(e,t){var r=e._fulfillmentHandlerAt(t),i=e._rejectionHandlerAt(t),n=e._promiseAt(t),a=e._receiverAt(t);void 0===a&&(a=c),this._addCallbacks(r,i,n,a,null)},T.prototype._addCallbacks=function(e,t,r,i,n){var a=this._length();if(a>=65531&&(a=0,this._setLength(0)),0===a)this._promise0=r,this._receiver0=i,"function"==typeof e&&(this._fulfillmentHandler0=null===n?e:u.domainBind(n,e)),"function"==typeof t&&(this._rejectionHandler0=null===n?t:u.domainBind(n,t));else{var o=4*a-4;this[o+2]=r,this[o+3]=i,"function"==typeof e&&(this[o+0]=null===n?e:u.domainBind(n,e)),"function"==typeof t&&(this[o+1]=null===n?t:u.domainBind(n,t))}return this._setLength(a+1),a},T.prototype._proxy=function(e,t){this._addCallbacks(void 0,void 0,t,e,null)},T.prototype._resolveCallback=function(e,t){if(0==(117506048&this._bitField)){if(e===this)return this._rejectCallback(i(),!1);var r=y(e,this);if(!(r instanceof T))return this._fulfill(e);t&&this._propagateFrom(r,2);var n=r._target();if(n!==this){var a=n._bitField;if(0==(50397184&a)){var o=this._length();o>0&&n._migrateCallback0(this);for(var s=1;s>>16)){if(e===this){var r=i();return this._attachExtraTrace(r),this._reject(r)}this._setFulfilled(),this._rejectionHandler0=e,(65535&t)>0&&(0!=(134217728&t)?this._settlePromises():d.settlePromises(this),this._dereferenceTrace())}},T.prototype._reject=function(e){var t=this._bitField;if(!((117506048&t)>>>16)){if(this._setRejected(),this._fulfillmentHandler0=e,this._isFinal())return d.fatalError(e,u.isNode);(65535&t)>0?d.settlePromises(this):this._ensurePossibleRejectionHandled()}},T.prototype._fulfillPromises=function(e,t){for(var r=1;r0){if(0!=(16842752&e)){var r=this._fulfillmentHandler0;this._settlePromise0(this._rejectionHandler0,r,e),this._rejectPromises(t,r)}else{var i=this._rejectionHandler0;this._settlePromise0(this._fulfillmentHandler0,i,e),this._fulfillPromises(t,i)}this._setLength(0)}this._clearCancellationData()},T.prototype._settledValue=function(){var e=this._bitField;return 0!=(33554432&e)?this._rejectionHandler0:0!=(16777216&e)?this._fulfillmentHandler0:void 0},T.defer=T.pending=function(){return S.deprecated("Promise.defer","new Promise"),{promise:new T(g),resolve:R,reject:I}},u.notEnumerableProp(T,"_makeSelfResolutionError",i),e("./method")(T,g,y,a,S),e("./bind")(T,g,y,S),e("./cancel")(T,b,a,S),e("./direct_resolve")(T),e("./synchronous_inspection")(T),e("./join")(T,b,y,g,d,s),T.Promise=T,T.version="3.5.2",e("./map.js")(T,b,a,y,g,S),e("./call_get.js")(T),e("./using.js")(T,a,y,w,g,S),e("./timers.js")(T,g,S),e("./generators.js")(T,a,g,y,o,S),e("./nodeify.js")(T),e("./promisify.js")(T,g),e("./props.js")(T,b,y,a),e("./race.js")(T,g,y,a),e("./reduce.js")(T,b,a,y,g,S),e("./settle.js")(T,b,S),e("./some.js")(T,b,a),e("./filter.js")(T,g),e("./each.js")(T,g),e("./any.js")(T),u.toFastProperties(T),u.toFastProperties(T.prototype),O({a:1}),O({b:2}),O({c:3}),O(1),O((function(){})),O(void 0),O(!1),O(new T(g)),S.setBounds(h.firstLineError,u.lastLineError),T}},{"./any.js":1,"./async":2,"./bind":3,"./call_get.js":5,"./cancel":6,"./catch_filter":7,"./context":8,"./debuggability":9,"./direct_resolve":10,"./each.js":11,"./errors":12,"./es5":13,"./filter.js":14,"./finally":15,"./generators.js":16,"./join":17,"./map.js":18,"./method":19,"./nodeback":20,"./nodeify.js":21,"./promise_array":23,"./promisify.js":24,"./props.js":25,"./race.js":27,"./reduce.js":28,"./settle.js":30,"./some.js":31,"./synchronous_inspection":32,"./thenables":33,"./timers.js":34,"./using.js":35,"./util":36}],23:[function(e,t,r){"use strict";t.exports=function(t,r,i,n,a){var o=e("./util");function s(e){var i=this._promise=new t(r);e instanceof t&&i._propagateFrom(e,3),i._setOnCancel(this),this._values=e,this._length=0,this._totalResolved=0,this._init(void 0,-2)}return o.isArray,o.inherits(s,a),s.prototype.length=function(){return this._length},s.prototype.promise=function(){return this._promise},s.prototype._init=function e(r,a){var s=i(this._values,this._promise);if(s instanceof t){var c=(s=s._target())._bitField;if(this._values=s,0==(50397184&c))return this._promise._setAsyncGuaranteed(),s._then(e,this._reject,void 0,this,a);if(0==(33554432&c))return 0!=(16777216&c)?this._reject(s._reason()):this._cancel();s=s._value()}if(null!==(s=o.asArray(s)))0!==s.length?this._iterate(s):-5===a?this._resolveEmptyArray():this._resolve(function(e){switch(e){case-2:return[];case-3:return{};case-6:return new Map}}(a));else{var u=n("expecting an array or an iterable object but got "+o.classString(s)).reason();this._promise._rejectCallback(u,!1)}},s.prototype._iterate=function(e){var r=this.getActualLength(e.length);this._length=r,this._values=this.shouldCopyValues()?new Array(r):this._values;for(var n=this._promise,a=!1,o=null,s=0;s=this._length&&(this._resolve(this._values),!0)},s.prototype._promiseCancelled=function(){return this._cancel(),!0},s.prototype._promiseRejected=function(e){return this._totalResolved++,this._reject(e),!0},s.prototype._resultCancelled=function(){if(!this._isResolved()){var e=this._values;if(this._cancel(),e instanceof t)e.cancel();else for(var r=0;r=this._length){var r;if(this._isMap)r=function(e){for(var t=new a,r=e.length/2|0,i=0;i>1},t.prototype.props=function(){return h(this)},t.props=function(e){return h(e)}}},{"./es5":13,"./util":36}],26:[function(e,t,r){"use strict";function i(e){this._capacity=e,this._length=0,this._front=0}i.prototype._willBeOverCapacity=function(e){return this._capacity=this._length&&(this._resolve(this._values),!0)},a.prototype._promiseFulfilled=function(e,t){var r=new n;return r._bitField=33554432,r._settledValueField=e,this._promiseResolved(t,r)},a.prototype._promiseRejected=function(e,t){var r=new n;return r._bitField=16777216,r._settledValueField=e,this._promiseResolved(t,r)},t.settle=function(e){return i.deprecated(".settle()",".reflect()"),new a(e).promise()},t.prototype.settle=function(){return t.settle(this)}}},{"./util":36}],31:[function(e,t,r){"use strict";t.exports=function(t,r,i){var n=e("./util"),a=e("./errors").RangeError,o=e("./errors").AggregateError,s=n.isArray,c={};function u(e){this.constructor$(e),this._howMany=0,this._unwrap=!1,this._initialized=!1}function l(e,t){if((0|t)!==t||t<0)return i("expecting a positive integer\n\n See http://goo.gl/MqrFmX\n");var r=new u(e),n=r.promise();return r.setHowMany(t),r.init(),n}n.inherits(u,r),u.prototype._init=function(){if(this._initialized)if(0!==this._howMany){this._init$(void 0,-5);var e=s(this._values);!this._isResolved()&&e&&this._howMany>this._canPossiblyFulfill()&&this._reject(this._getRangeError(this.length()))}else this._resolve([])},u.prototype.init=function(){this._initialized=!0,this._init()},u.prototype.setUnwrap=function(){this._unwrap=!0},u.prototype.howMany=function(){return this._howMany},u.prototype.setHowMany=function(e){this._howMany=e},u.prototype._promiseFulfilled=function(e){return this._addFulfilled(e),this._fulfilled()===this.howMany()&&(this._values.length=this.howMany(),1===this.howMany()&&this._unwrap?this._resolve(this._values[0]):this._resolve(this._values),!0)},u.prototype._promiseRejected=function(e){return this._addRejected(e),this._checkOutcome()},u.prototype._promiseCancelled=function(){return this._values instanceof t||null==this._values?this._cancel():(this._addRejected(c),this._checkOutcome())},u.prototype._checkOutcome=function(){if(this.howMany()>this._canPossiblyFulfill()){for(var e=new o,t=this.length();t0?this._reject(e):this._cancel(),!0}return!1},u.prototype._fulfilled=function(){return this._totalResolved},u.prototype._rejected=function(){return this._values.length-this.length()},u.prototype._addRejected=function(e){this._values.push(e)},u.prototype._addFulfilled=function(e){this._values[this._totalResolved++]=e},u.prototype._canPossiblyFulfill=function(){return this.length()-this._rejected()},u.prototype._getRangeError=function(e){var t="Input array must contain at least "+this._howMany+" items but contains only "+e+" items";return new a(t)},u.prototype._resolveEmptyArray=function(){this._reject(this._getRangeError(0))},t.some=function(e,t){return l(e,t)},t.prototype.some=function(e){return l(this,e)},t._SomePromiseArray=u}},{"./errors":12,"./util":36}],32:[function(e,t,r){"use strict";t.exports=function(e){function t(e){void 0!==e?(e=e._target(),this._bitField=e._bitField,this._settledValueField=e._isFateSealed()?e._settledValue():void 0):(this._bitField=0,this._settledValueField=void 0)}t.prototype._settledValue=function(){return this._settledValueField};var r=t.prototype.value=function(){if(!this.isFulfilled())throw new TypeError("cannot get fulfillment value of a non-fulfilled promise\n\n See http://goo.gl/MqrFmX\n");return this._settledValue()},i=t.prototype.error=t.prototype.reason=function(){if(!this.isRejected())throw new TypeError("cannot get rejection reason of a non-rejected promise\n\n See http://goo.gl/MqrFmX\n");return this._settledValue()},n=t.prototype.isFulfilled=function(){return 0!=(33554432&this._bitField)},a=t.prototype.isRejected=function(){return 0!=(16777216&this._bitField)},o=t.prototype.isPending=function(){return 0==(50397184&this._bitField)},s=t.prototype.isResolved=function(){return 0!=(50331648&this._bitField)};t.prototype.isCancelled=function(){return 0!=(8454144&this._bitField)},e.prototype.__isCancelled=function(){return 65536==(65536&this._bitField)},e.prototype._isCancelled=function(){return this._target().__isCancelled()},e.prototype.isCancelled=function(){return 0!=(8454144&this._target()._bitField)},e.prototype.isPending=function(){return o.call(this._target())},e.prototype.isRejected=function(){return a.call(this._target())},e.prototype.isFulfilled=function(){return n.call(this._target())},e.prototype.isResolved=function(){return s.call(this._target())},e.prototype.value=function(){return r.call(this._target())},e.prototype.reason=function(){var e=this._target();return e._unsetRejectionIsUnhandled(),i.call(e)},e.prototype._value=function(){return this._settledValue()},e.prototype._reason=function(){return this._unsetRejectionIsUnhandled(),this._settledValue()},e.PromiseInspection=t}},{}],33:[function(e,t,r){"use strict";t.exports=function(t,r){var i=e("./util"),n=i.errorObj,a=i.isObject,o={}.hasOwnProperty;return function(e,s){if(a(e)){if(e instanceof t)return e;var c=function(e){try{return function(e){return e.then}(e)}catch(e){return n.e=e,n}}(e);if(c===n){s&&s._pushContext();var u=t.reject(c.e);return s&&s._popContext(),u}if("function"==typeof c)return function(e){try{return o.call(e,"_promise0")}catch(e){return!1}}(e)?(u=new t(r),e._then(u._fulfill,u._reject,void 0,u,null),u):function(e,a,o){var s=new t(r),c=s;o&&o._pushContext(),s._captureStackTrace(),o&&o._popContext();var u=i.tryCatch(a).call(e,(function(e){s&&(s._resolveCallback(e),s=null)}),(function(e){s&&(s._rejectCallback(e,!1,!0),s=null)}));return s&&u===n&&(s._rejectCallback(u.e,!0,!0),s=null),c}(e,c,s)}return e}}},{"./util":36}],34:[function(e,t,r){"use strict";t.exports=function(t,r,i){var n=e("./util"),a=t.TimeoutError;function o(e){this.handle=e}o.prototype._resultCancelled=function(){clearTimeout(this.handle)};var s=function(e){return c(+this).thenReturn(e)},c=t.delay=function(e,n){var a,c;return void 0!==n?(a=t.resolve(n)._then(s,null,null,e,void 0),i.cancellation()&&n instanceof t&&a._setOnCancel(n)):(a=new t(r),c=setTimeout((function(){a._fulfill()}),+e),i.cancellation()&&a._setOnCancel(new o(c)),a._captureStackTrace()),a._setAsyncGuaranteed(),a};function u(e){return clearTimeout(this.handle),e}function l(e){throw clearTimeout(this.handle),e}t.prototype.delay=function(e){return c(e,this)},t.prototype.timeout=function(e,t){var r,s;e=+e;var c=new o(setTimeout((function(){r.isPending()&&function(e,t,r){var i;i="string"!=typeof t?t instanceof Error?t:new a("operation timed out"):new a(t),n.markAsOriginatingFromRejection(i),e._attachExtraTrace(i),e._reject(i),null!=r&&r.cancel()}(r,t,s)}),e));return i.cancellation()?(s=this.then(),(r=s._then(u,l,void 0,c,void 0))._setOnCancel(c)):r=this._then(u,l,void 0,c,void 0),r}}},{"./util":36}],35:[function(e,t,r){"use strict";t.exports=function(t,r,i,n,a,o){var s=e("./util"),c=e("./errors").TypeError,u=e("./util").inherits,l=s.errorObj,h=s.tryCatch,d={};function p(e){setTimeout((function(){throw e}),0)}function f(e,r){var n=0,o=e.length,s=new t(a);return function a(){if(n>=o)return s._fulfill();var c=function(e){var t=i(e);return t!==e&&"function"==typeof e._isDisposable&&"function"==typeof e._getDisposer&&e._isDisposable()&&t._setDisposable(e._getDisposer()),t}(e[n++]);if(c instanceof t&&c._isDisposable()){try{c=i(c._getDisposer().tryDispose(r),e.promise)}catch(e){return p(e)}if(c instanceof t)return c._then(a,p,null,null,null)}a()}(),s}function m(e,t,r){this._data=e,this._promise=t,this._context=r}function g(e,t,r){this.constructor$(e,t,r)}function _(e){return m.isDisposer(e)?(this.resources[this.index]._setDisposable(e),e.promise()):e}function v(e){this.length=e,this.promise=null,this[e-1]=null}m.prototype.data=function(){return this._data},m.prototype.promise=function(){return this._promise},m.prototype.resource=function(){return this.promise().isFulfilled()?this.promise().value():d},m.prototype.tryDispose=function(e){var t=this.resource(),r=this._context;void 0!==r&&r._pushContext();var i=t!==d?this.doDispose(t,e):null;return void 0!==r&&r._popContext(),this._promise._unsetDisposable(),this._data=null,i},m.isDisposer=function(e){return null!=e&&"function"==typeof e.resource&&"function"==typeof e.tryDispose},u(g,m),g.prototype.doDispose=function(e,t){return this.data().call(e,e,t)},v.prototype._resultCancelled=function(){for(var e=this.length,r=0;r0},t.prototype._getDisposer=function(){return this._disposer},t.prototype._unsetDisposable=function(){this._bitField=-131073&this._bitField,this._disposer=void 0},t.prototype.disposer=function(e){if("function"==typeof e)return new g(e,this,n());throw new c}}},{"./errors":12,"./util":36}],36:[function(e,i,n){"use strict";var a=e("./es5"),o="undefined"==typeof navigator,s={e:{}},c,u="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==r?r:void 0!==this?this:null;function l(){try{var e=c;return c=null,e.apply(this,arguments)}catch(e){return s.e=e,s}}function h(e){return c=e,l}var d=function(e,t){var r={}.hasOwnProperty;function i(){for(var i in this.constructor=e,this.constructor$=t,t.prototype)r.call(t.prototype,i)&&"$"!==i.charAt(i.length-1)&&(this[i+"$"]=t.prototype[i])}return i.prototype=t.prototype,e.prototype=new i,e.prototype};function p(e){return null==e||!0===e||!1===e||"string"==typeof e||"number"==typeof e}function f(e){return"function"==typeof e||"object"==typeof e&&null!==e}function m(e){return p(e)?new Error(N(e)):e}function g(e,t){var r,i=e.length,n=new Array(i+1);for(r=0;r1,i=t.length>0&&!(1===t.length&&"constructor"===t[0]),n=E.test(e+"")&&a.names(e).length>0;if(r||i||n)return!0}return!1}catch(e){return!1}}function S(e){function t(){}t.prototype=e;var r=new t;function i(){return typeof r.foo}return i(),i(),e}var k=/^[a-z$_][a-z$_0-9]*$/i;function x(e){return k.test(e)}function M(e,t,r){for(var i=new Array(e),n=0;n10||q[0]>0),H.isNode&&H.toFastProperties(t);try{throw new Error}catch(e){H.lastLineError=e}i.exports=H},{"./es5":13}]},{},[4])(4)},e.exports=n(),"undefined"!=typeof window&&null!==window?window.P=window.Promise:"undefined"!=typeof self&&null!==self&&(self.P=self.Promise)}).call(this,r(3),r(8),r(32).setImmediate)},function(e,t,r){"use strict";var i=r(383),n=r(209),a=r(206),o=r(121);e.exports=function(e){var t="Please verify options";if(!o(e))throw new TypeError(t);if(!a(e.request))throw new TypeError(t+".request");if(!n(e.expose)||0===e.expose.length)throw new TypeError(t+".expose");var r=i({PromiseImpl:e.PromiseImpl,constructorMixin:e.constructorMixin}),s=e.request.Request.prototype.init;e.request.Request.prototype.init=function(e){return!o(e)||this._callback||this._rp_promise||r.init.call(this,e),s.apply(this,arguments)};for(var c=!1,u=0;u0&&u>c&&(u=c);for(var l=0;l=0?(h=m.substr(0,g),d=m.substr(g+1)):(h=m,d=""),p=decodeURIComponent(h),f=decodeURIComponent(d),i(o,p)?n(o[p])?o[p].push(f):o[p]=[o[p],f]:o[p]=f}return o};var n=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)}},function(e,t,r){"use strict";var i=function(e){switch(typeof e){case"string":return e;case"boolean":return e?"true":"false";case"number":return isFinite(e)?e:"";default:return""}};e.exports=function(e,t,r,s){return t=t||"&",r=r||"=",null===e&&(e=void 0),"object"==typeof e?a(o(e),(function(o){var s=encodeURIComponent(i(o))+r;return n(e[o])?a(e[o],(function(e){return s+encodeURIComponent(i(e))})).join(t):s+encodeURIComponent(i(e[o]))})).join(t):s?encodeURIComponent(i(s))+r+encodeURIComponent(i(e)):""};var n=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)};function a(e,t){if(e.map)return e.map(t);for(var r=[],i=0;i255)return"DOMAIN_TOO_LONG";for(var r,n=t.split("."),a=0;a63)return"LABEL_TOO_LONG";if("-"===r.charAt(0))return"LABEL_STARTS_WITH_DASH";if("-"===r.charAt(r.length-1))return"LABEL_ENDS_WITH_DASH";if(!/^[a-z0-9\-]+$/.test(r))return"LABEL_INVALID_CHARS"}},t.parse=function(e){if("string"!=typeof e)throw new TypeError("Domain name must be a string.");var r=e.slice(0).toLowerCase();"."===r.charAt(r.length-1)&&(r=r.slice(0,r.length-1));var a=n.validate(r);if(a)return{input:e,error:{message:t.errorCodes[a],code:a}};var o={input:e,tld:null,sld:null,domain:null,subdomain:null,listed:!1},s=r.split(".");if("local"===s[s.length-1])return o;var c=function(){return/xn--/.test(r)?(o.domain&&(o.domain=i.toASCII(o.domain)),o.subdomain&&(o.subdomain=i.toASCII(o.subdomain)),o):o},u=n.findRule(r);if(!u)return s.length<2?o:(o.tld=s.pop(),o.sld=s.pop(),o.domain=[o.sld,o.tld].join("."),s.length&&(o.subdomain=s.pop()),c());o.listed=!0;var l=u.suffix.split("."),h=s.slice(0,s.length-l.length);return u.exception&&h.push(l.shift()),o.tld=l.join("."),h.length?(u.wildcard&&(l.unshift(h.pop()),o.tld=l.join(".")),h.length?(o.sld=h.pop(),o.domain=[o.sld,o.tld].join("."),h.length&&(o.subdomain=h.join(".")),c()):c()):c()},t.get=function(e){return e&&t.parse(e).domain||null},t.isValid=function(e){var r=t.parse(e);return Boolean(r.domain&&r.listed)}},function(e){e.exports=JSON.parse('["ac","com.ac","edu.ac","gov.ac","net.ac","mil.ac","org.ac","ad","nom.ad","ae","co.ae","net.ae","org.ae","sch.ae","ac.ae","gov.ae","mil.ae","aero","accident-investigation.aero","accident-prevention.aero","aerobatic.aero","aeroclub.aero","aerodrome.aero","agents.aero","aircraft.aero","airline.aero","airport.aero","air-surveillance.aero","airtraffic.aero","air-traffic-control.aero","ambulance.aero","amusement.aero","association.aero","author.aero","ballooning.aero","broker.aero","caa.aero","cargo.aero","catering.aero","certification.aero","championship.aero","charter.aero","civilaviation.aero","club.aero","conference.aero","consultant.aero","consulting.aero","control.aero","council.aero","crew.aero","design.aero","dgca.aero","educator.aero","emergency.aero","engine.aero","engineer.aero","entertainment.aero","equipment.aero","exchange.aero","express.aero","federation.aero","flight.aero","freight.aero","fuel.aero","gliding.aero","government.aero","groundhandling.aero","group.aero","hanggliding.aero","homebuilt.aero","insurance.aero","journal.aero","journalist.aero","leasing.aero","logistics.aero","magazine.aero","maintenance.aero","media.aero","microlight.aero","modelling.aero","navigation.aero","parachuting.aero","paragliding.aero","passenger-association.aero","pilot.aero","press.aero","production.aero","recreation.aero","repbody.aero","res.aero","research.aero","rotorcraft.aero","safety.aero","scientist.aero","services.aero","show.aero","skydiving.aero","software.aero","student.aero","trader.aero","trading.aero","trainer.aero","union.aero","workinggroup.aero","works.aero","af","gov.af","com.af","org.af","net.af","edu.af","ag","com.ag","org.ag","net.ag","co.ag","nom.ag","ai","off.ai","com.ai","net.ai","org.ai","al","com.al","edu.al","gov.al","mil.al","net.al","org.al","am","ao","ed.ao","gv.ao","og.ao","co.ao","pb.ao","it.ao","aq","ar","com.ar","edu.ar","gob.ar","gov.ar","int.ar","mil.ar","musica.ar","net.ar","org.ar","tur.ar","arpa","e164.arpa","in-addr.arpa","ip6.arpa","iris.arpa","uri.arpa","urn.arpa","as","gov.as","asia","at","ac.at","co.at","gv.at","or.at","au","com.au","net.au","org.au","edu.au","gov.au","asn.au","id.au","info.au","conf.au","oz.au","act.au","nsw.au","nt.au","qld.au","sa.au","tas.au","vic.au","wa.au","act.edu.au","nsw.edu.au","nt.edu.au","qld.edu.au","sa.edu.au","tas.edu.au","vic.edu.au","wa.edu.au","qld.gov.au","sa.gov.au","tas.gov.au","vic.gov.au","wa.gov.au","aw","com.aw","ax","az","com.az","net.az","int.az","gov.az","org.az","edu.az","info.az","pp.az","mil.az","name.az","pro.az","biz.az","ba","com.ba","edu.ba","gov.ba","mil.ba","net.ba","org.ba","bb","biz.bb","co.bb","com.bb","edu.bb","gov.bb","info.bb","net.bb","org.bb","store.bb","tv.bb","*.bd","be","ac.be","bf","gov.bf","bg","a.bg","b.bg","c.bg","d.bg","e.bg","f.bg","g.bg","h.bg","i.bg","j.bg","k.bg","l.bg","m.bg","n.bg","o.bg","p.bg","q.bg","r.bg","s.bg","t.bg","u.bg","v.bg","w.bg","x.bg","y.bg","z.bg","0.bg","1.bg","2.bg","3.bg","4.bg","5.bg","6.bg","7.bg","8.bg","9.bg","bh","com.bh","edu.bh","net.bh","org.bh","gov.bh","bi","co.bi","com.bi","edu.bi","or.bi","org.bi","biz","bj","asso.bj","barreau.bj","gouv.bj","bm","com.bm","edu.bm","gov.bm","net.bm","org.bm","*.bn","bo","com.bo","edu.bo","gob.bo","int.bo","org.bo","net.bo","mil.bo","tv.bo","web.bo","academia.bo","agro.bo","arte.bo","blog.bo","bolivia.bo","ciencia.bo","cooperativa.bo","democracia.bo","deporte.bo","ecologia.bo","economia.bo","empresa.bo","indigena.bo","industria.bo","info.bo","medicina.bo","movimiento.bo","musica.bo","natural.bo","nombre.bo","noticias.bo","patria.bo","politica.bo","profesional.bo","plurinacional.bo","pueblo.bo","revista.bo","salud.bo","tecnologia.bo","tksat.bo","transporte.bo","wiki.bo","br","9guacu.br","abc.br","adm.br","adv.br","agr.br","aju.br","am.br","anani.br","aparecida.br","arq.br","art.br","ato.br","b.br","barueri.br","belem.br","bhz.br","bio.br","blog.br","bmd.br","boavista.br","bsb.br","campinagrande.br","campinas.br","caxias.br","cim.br","cng.br","cnt.br","com.br","contagem.br","coop.br","cri.br","cuiaba.br","curitiba.br","def.br","ecn.br","eco.br","edu.br","emp.br","eng.br","esp.br","etc.br","eti.br","far.br","feira.br","flog.br","floripa.br","fm.br","fnd.br","fortal.br","fot.br","foz.br","fst.br","g12.br","ggf.br","goiania.br","gov.br","ac.gov.br","al.gov.br","am.gov.br","ap.gov.br","ba.gov.br","ce.gov.br","df.gov.br","es.gov.br","go.gov.br","ma.gov.br","mg.gov.br","ms.gov.br","mt.gov.br","pa.gov.br","pb.gov.br","pe.gov.br","pi.gov.br","pr.gov.br","rj.gov.br","rn.gov.br","ro.gov.br","rr.gov.br","rs.gov.br","sc.gov.br","se.gov.br","sp.gov.br","to.gov.br","gru.br","imb.br","ind.br","inf.br","jab.br","jampa.br","jdf.br","joinville.br","jor.br","jus.br","leg.br","lel.br","londrina.br","macapa.br","maceio.br","manaus.br","maringa.br","mat.br","med.br","mil.br","morena.br","mp.br","mus.br","natal.br","net.br","niteroi.br","*.nom.br","not.br","ntr.br","odo.br","org.br","osasco.br","palmas.br","poa.br","ppg.br","pro.br","psc.br","psi.br","pvh.br","qsl.br","radio.br","rec.br","recife.br","ribeirao.br","rio.br","riobranco.br","riopreto.br","salvador.br","sampa.br","santamaria.br","santoandre.br","saobernardo.br","saogonca.br","sjc.br","slg.br","slz.br","sorocaba.br","srv.br","taxi.br","teo.br","the.br","tmp.br","trd.br","tur.br","tv.br","udi.br","vet.br","vix.br","vlog.br","wiki.br","zlg.br","bs","com.bs","net.bs","org.bs","edu.bs","gov.bs","bt","com.bt","edu.bt","gov.bt","net.bt","org.bt","bv","bw","co.bw","org.bw","by","gov.by","mil.by","com.by","of.by","bz","com.bz","net.bz","org.bz","edu.bz","gov.bz","ca","ab.ca","bc.ca","mb.ca","nb.ca","nf.ca","nl.ca","ns.ca","nt.ca","nu.ca","on.ca","pe.ca","qc.ca","sk.ca","yk.ca","gc.ca","cat","cc","cd","gov.cd","cf","cg","ch","ci","org.ci","or.ci","com.ci","co.ci","edu.ci","ed.ci","ac.ci","net.ci","go.ci","asso.ci","aéroport.ci","int.ci","presse.ci","md.ci","gouv.ci","*.ck","!www.ck","cl","gov.cl","gob.cl","co.cl","mil.cl","cm","co.cm","com.cm","gov.cm","net.cm","cn","ac.cn","com.cn","edu.cn","gov.cn","net.cn","org.cn","mil.cn","公司.cn","网络.cn","網絡.cn","ah.cn","bj.cn","cq.cn","fj.cn","gd.cn","gs.cn","gz.cn","gx.cn","ha.cn","hb.cn","he.cn","hi.cn","hl.cn","hn.cn","jl.cn","js.cn","jx.cn","ln.cn","nm.cn","nx.cn","qh.cn","sc.cn","sd.cn","sh.cn","sn.cn","sx.cn","tj.cn","xj.cn","xz.cn","yn.cn","zj.cn","hk.cn","mo.cn","tw.cn","co","arts.co","com.co","edu.co","firm.co","gov.co","info.co","int.co","mil.co","net.co","nom.co","org.co","rec.co","web.co","com","coop","cr","ac.cr","co.cr","ed.cr","fi.cr","go.cr","or.cr","sa.cr","cu","com.cu","edu.cu","org.cu","net.cu","gov.cu","inf.cu","cv","cw","com.cw","edu.cw","net.cw","org.cw","cx","gov.cx","cy","ac.cy","biz.cy","com.cy","ekloges.cy","gov.cy","ltd.cy","name.cy","net.cy","org.cy","parliament.cy","press.cy","pro.cy","tm.cy","cz","de","dj","dk","dm","com.dm","net.dm","org.dm","edu.dm","gov.dm","do","art.do","com.do","edu.do","gob.do","gov.do","mil.do","net.do","org.do","sld.do","web.do","dz","com.dz","org.dz","net.dz","gov.dz","edu.dz","asso.dz","pol.dz","art.dz","ec","com.ec","info.ec","net.ec","fin.ec","k12.ec","med.ec","pro.ec","org.ec","edu.ec","gov.ec","gob.ec","mil.ec","edu","ee","edu.ee","gov.ee","riik.ee","lib.ee","med.ee","com.ee","pri.ee","aip.ee","org.ee","fie.ee","eg","com.eg","edu.eg","eun.eg","gov.eg","mil.eg","name.eg","net.eg","org.eg","sci.eg","*.er","es","com.es","nom.es","org.es","gob.es","edu.es","et","com.et","gov.et","org.et","edu.et","biz.et","name.et","info.et","net.et","eu","fi","aland.fi","*.fj","*.fk","fm","fo","fr","com.fr","asso.fr","nom.fr","prd.fr","presse.fr","tm.fr","aeroport.fr","assedic.fr","avocat.fr","avoues.fr","cci.fr","chambagri.fr","chirurgiens-dentistes.fr","experts-comptables.fr","geometre-expert.fr","gouv.fr","greta.fr","huissier-justice.fr","medecin.fr","notaires.fr","pharmacien.fr","port.fr","veterinaire.fr","ga","gb","gd","ge","com.ge","edu.ge","gov.ge","org.ge","mil.ge","net.ge","pvt.ge","gf","gg","co.gg","net.gg","org.gg","gh","com.gh","edu.gh","gov.gh","org.gh","mil.gh","gi","com.gi","ltd.gi","gov.gi","mod.gi","edu.gi","org.gi","gl","co.gl","com.gl","edu.gl","net.gl","org.gl","gm","gn","ac.gn","com.gn","edu.gn","gov.gn","org.gn","net.gn","gov","gp","com.gp","net.gp","mobi.gp","edu.gp","org.gp","asso.gp","gq","gr","com.gr","edu.gr","net.gr","org.gr","gov.gr","gs","gt","com.gt","edu.gt","gob.gt","ind.gt","mil.gt","net.gt","org.gt","gu","com.gu","edu.gu","gov.gu","guam.gu","info.gu","net.gu","org.gu","web.gu","gw","gy","co.gy","com.gy","edu.gy","gov.gy","net.gy","org.gy","hk","com.hk","edu.hk","gov.hk","idv.hk","net.hk","org.hk","公司.hk","教育.hk","敎育.hk","政府.hk","個人.hk","个人.hk","箇人.hk","網络.hk","网络.hk","组織.hk","網絡.hk","网絡.hk","组织.hk","組織.hk","組织.hk","hm","hn","com.hn","edu.hn","org.hn","net.hn","mil.hn","gob.hn","hr","iz.hr","from.hr","name.hr","com.hr","ht","com.ht","shop.ht","firm.ht","info.ht","adult.ht","net.ht","pro.ht","org.ht","med.ht","art.ht","coop.ht","pol.ht","asso.ht","edu.ht","rel.ht","gouv.ht","perso.ht","hu","co.hu","info.hu","org.hu","priv.hu","sport.hu","tm.hu","2000.hu","agrar.hu","bolt.hu","casino.hu","city.hu","erotica.hu","erotika.hu","film.hu","forum.hu","games.hu","hotel.hu","ingatlan.hu","jogasz.hu","konyvelo.hu","lakas.hu","media.hu","news.hu","reklam.hu","sex.hu","shop.hu","suli.hu","szex.hu","tozsde.hu","utazas.hu","video.hu","id","ac.id","biz.id","co.id","desa.id","go.id","mil.id","my.id","net.id","or.id","sch.id","web.id","ie","gov.ie","il","ac.il","co.il","gov.il","idf.il","k12.il","muni.il","net.il","org.il","im","ac.im","co.im","com.im","ltd.co.im","net.im","org.im","plc.co.im","tt.im","tv.im","in","co.in","firm.in","net.in","org.in","gen.in","ind.in","nic.in","ac.in","edu.in","res.in","gov.in","mil.in","info","int","eu.int","io","com.io","iq","gov.iq","edu.iq","mil.iq","com.iq","org.iq","net.iq","ir","ac.ir","co.ir","gov.ir","id.ir","net.ir","org.ir","sch.ir","ایران.ir","ايران.ir","is","net.is","com.is","edu.is","gov.is","org.is","int.is","it","gov.it","edu.it","abr.it","abruzzo.it","aosta-valley.it","aostavalley.it","bas.it","basilicata.it","cal.it","calabria.it","cam.it","campania.it","emilia-romagna.it","emiliaromagna.it","emr.it","friuli-v-giulia.it","friuli-ve-giulia.it","friuli-vegiulia.it","friuli-venezia-giulia.it","friuli-veneziagiulia.it","friuli-vgiulia.it","friuliv-giulia.it","friulive-giulia.it","friulivegiulia.it","friulivenezia-giulia.it","friuliveneziagiulia.it","friulivgiulia.it","fvg.it","laz.it","lazio.it","lig.it","liguria.it","lom.it","lombardia.it","lombardy.it","lucania.it","mar.it","marche.it","mol.it","molise.it","piedmont.it","piemonte.it","pmn.it","pug.it","puglia.it","sar.it","sardegna.it","sardinia.it","sic.it","sicilia.it","sicily.it","taa.it","tos.it","toscana.it","trentin-sud-tirol.it","trentin-süd-tirol.it","trentin-sudtirol.it","trentin-südtirol.it","trentin-sued-tirol.it","trentin-suedtirol.it","trentino-a-adige.it","trentino-aadige.it","trentino-alto-adige.it","trentino-altoadige.it","trentino-s-tirol.it","trentino-stirol.it","trentino-sud-tirol.it","trentino-süd-tirol.it","trentino-sudtirol.it","trentino-südtirol.it","trentino-sued-tirol.it","trentino-suedtirol.it","trentino.it","trentinoa-adige.it","trentinoaadige.it","trentinoalto-adige.it","trentinoaltoadige.it","trentinos-tirol.it","trentinostirol.it","trentinosud-tirol.it","trentinosüd-tirol.it","trentinosudtirol.it","trentinosüdtirol.it","trentinosued-tirol.it","trentinosuedtirol.it","trentinsud-tirol.it","trentinsüd-tirol.it","trentinsudtirol.it","trentinsüdtirol.it","trentinsued-tirol.it","trentinsuedtirol.it","tuscany.it","umb.it","umbria.it","val-d-aosta.it","val-daosta.it","vald-aosta.it","valdaosta.it","valle-aosta.it","valle-d-aosta.it","valle-daosta.it","valleaosta.it","valled-aosta.it","valledaosta.it","vallee-aoste.it","vallée-aoste.it","vallee-d-aoste.it","vallée-d-aoste.it","valleeaoste.it","valléeaoste.it","valleedaoste.it","valléedaoste.it","vao.it","vda.it","ven.it","veneto.it","ag.it","agrigento.it","al.it","alessandria.it","alto-adige.it","altoadige.it","an.it","ancona.it","andria-barletta-trani.it","andria-trani-barletta.it","andriabarlettatrani.it","andriatranibarletta.it","ao.it","aosta.it","aoste.it","ap.it","aq.it","aquila.it","ar.it","arezzo.it","ascoli-piceno.it","ascolipiceno.it","asti.it","at.it","av.it","avellino.it","ba.it","balsan-sudtirol.it","balsan-südtirol.it","balsan-suedtirol.it","balsan.it","bari.it","barletta-trani-andria.it","barlettatraniandria.it","belluno.it","benevento.it","bergamo.it","bg.it","bi.it","biella.it","bl.it","bn.it","bo.it","bologna.it","bolzano-altoadige.it","bolzano.it","bozen-sudtirol.it","bozen-südtirol.it","bozen-suedtirol.it","bozen.it","br.it","brescia.it","brindisi.it","bs.it","bt.it","bulsan-sudtirol.it","bulsan-südtirol.it","bulsan-suedtirol.it","bulsan.it","bz.it","ca.it","cagliari.it","caltanissetta.it","campidano-medio.it","campidanomedio.it","campobasso.it","carbonia-iglesias.it","carboniaiglesias.it","carrara-massa.it","carraramassa.it","caserta.it","catania.it","catanzaro.it","cb.it","ce.it","cesena-forli.it","cesena-forlì.it","cesenaforli.it","cesenaforlì.it","ch.it","chieti.it","ci.it","cl.it","cn.it","co.it","como.it","cosenza.it","cr.it","cremona.it","crotone.it","cs.it","ct.it","cuneo.it","cz.it","dell-ogliastra.it","dellogliastra.it","en.it","enna.it","fc.it","fe.it","fermo.it","ferrara.it","fg.it","fi.it","firenze.it","florence.it","fm.it","foggia.it","forli-cesena.it","forlì-cesena.it","forlicesena.it","forlìcesena.it","fr.it","frosinone.it","ge.it","genoa.it","genova.it","go.it","gorizia.it","gr.it","grosseto.it","iglesias-carbonia.it","iglesiascarbonia.it","im.it","imperia.it","is.it","isernia.it","kr.it","la-spezia.it","laquila.it","laspezia.it","latina.it","lc.it","le.it","lecce.it","lecco.it","li.it","livorno.it","lo.it","lodi.it","lt.it","lu.it","lucca.it","macerata.it","mantova.it","massa-carrara.it","massacarrara.it","matera.it","mb.it","mc.it","me.it","medio-campidano.it","mediocampidano.it","messina.it","mi.it","milan.it","milano.it","mn.it","mo.it","modena.it","monza-brianza.it","monza-e-della-brianza.it","monza.it","monzabrianza.it","monzaebrianza.it","monzaedellabrianza.it","ms.it","mt.it","na.it","naples.it","napoli.it","no.it","novara.it","nu.it","nuoro.it","og.it","ogliastra.it","olbia-tempio.it","olbiatempio.it","or.it","oristano.it","ot.it","pa.it","padova.it","padua.it","palermo.it","parma.it","pavia.it","pc.it","pd.it","pe.it","perugia.it","pesaro-urbino.it","pesarourbino.it","pescara.it","pg.it","pi.it","piacenza.it","pisa.it","pistoia.it","pn.it","po.it","pordenone.it","potenza.it","pr.it","prato.it","pt.it","pu.it","pv.it","pz.it","ra.it","ragusa.it","ravenna.it","rc.it","re.it","reggio-calabria.it","reggio-emilia.it","reggiocalabria.it","reggioemilia.it","rg.it","ri.it","rieti.it","rimini.it","rm.it","rn.it","ro.it","roma.it","rome.it","rovigo.it","sa.it","salerno.it","sassari.it","savona.it","si.it","siena.it","siracusa.it","so.it","sondrio.it","sp.it","sr.it","ss.it","suedtirol.it","südtirol.it","sv.it","ta.it","taranto.it","te.it","tempio-olbia.it","tempioolbia.it","teramo.it","terni.it","tn.it","to.it","torino.it","tp.it","tr.it","trani-andria-barletta.it","trani-barletta-andria.it","traniandriabarletta.it","tranibarlettaandria.it","trapani.it","trento.it","treviso.it","trieste.it","ts.it","turin.it","tv.it","ud.it","udine.it","urbino-pesaro.it","urbinopesaro.it","va.it","varese.it","vb.it","vc.it","ve.it","venezia.it","venice.it","verbania.it","vercelli.it","verona.it","vi.it","vibo-valentia.it","vibovalentia.it","vicenza.it","viterbo.it","vr.it","vs.it","vt.it","vv.it","je","co.je","net.je","org.je","*.jm","jo","com.jo","org.jo","net.jo","edu.jo","sch.jo","gov.jo","mil.jo","name.jo","jobs","jp","ac.jp","ad.jp","co.jp","ed.jp","go.jp","gr.jp","lg.jp","ne.jp","or.jp","aichi.jp","akita.jp","aomori.jp","chiba.jp","ehime.jp","fukui.jp","fukuoka.jp","fukushima.jp","gifu.jp","gunma.jp","hiroshima.jp","hokkaido.jp","hyogo.jp","ibaraki.jp","ishikawa.jp","iwate.jp","kagawa.jp","kagoshima.jp","kanagawa.jp","kochi.jp","kumamoto.jp","kyoto.jp","mie.jp","miyagi.jp","miyazaki.jp","nagano.jp","nagasaki.jp","nara.jp","niigata.jp","oita.jp","okayama.jp","okinawa.jp","osaka.jp","saga.jp","saitama.jp","shiga.jp","shimane.jp","shizuoka.jp","tochigi.jp","tokushima.jp","tokyo.jp","tottori.jp","toyama.jp","wakayama.jp","yamagata.jp","yamaguchi.jp","yamanashi.jp","栃木.jp","愛知.jp","愛媛.jp","兵庫.jp","熊本.jp","茨城.jp","北海道.jp","千葉.jp","和歌山.jp","長崎.jp","長野.jp","新潟.jp","青森.jp","静岡.jp","東京.jp","石川.jp","埼玉.jp","三重.jp","京都.jp","佐賀.jp","大分.jp","大阪.jp","奈良.jp","宮城.jp","宮崎.jp","富山.jp","山口.jp","山形.jp","山梨.jp","岩手.jp","岐阜.jp","岡山.jp","島根.jp","広島.jp","徳島.jp","沖縄.jp","滋賀.jp","神奈川.jp","福井.jp","福岡.jp","福島.jp","秋田.jp","群馬.jp","香川.jp","高知.jp","鳥取.jp","鹿児島.jp","*.kawasaki.jp","*.kitakyushu.jp","*.kobe.jp","*.nagoya.jp","*.sapporo.jp","*.sendai.jp","*.yokohama.jp","!city.kawasaki.jp","!city.kitakyushu.jp","!city.kobe.jp","!city.nagoya.jp","!city.sapporo.jp","!city.sendai.jp","!city.yokohama.jp","aisai.aichi.jp","ama.aichi.jp","anjo.aichi.jp","asuke.aichi.jp","chiryu.aichi.jp","chita.aichi.jp","fuso.aichi.jp","gamagori.aichi.jp","handa.aichi.jp","hazu.aichi.jp","hekinan.aichi.jp","higashiura.aichi.jp","ichinomiya.aichi.jp","inazawa.aichi.jp","inuyama.aichi.jp","isshiki.aichi.jp","iwakura.aichi.jp","kanie.aichi.jp","kariya.aichi.jp","kasugai.aichi.jp","kira.aichi.jp","kiyosu.aichi.jp","komaki.aichi.jp","konan.aichi.jp","kota.aichi.jp","mihama.aichi.jp","miyoshi.aichi.jp","nishio.aichi.jp","nisshin.aichi.jp","obu.aichi.jp","oguchi.aichi.jp","oharu.aichi.jp","okazaki.aichi.jp","owariasahi.aichi.jp","seto.aichi.jp","shikatsu.aichi.jp","shinshiro.aichi.jp","shitara.aichi.jp","tahara.aichi.jp","takahama.aichi.jp","tobishima.aichi.jp","toei.aichi.jp","togo.aichi.jp","tokai.aichi.jp","tokoname.aichi.jp","toyoake.aichi.jp","toyohashi.aichi.jp","toyokawa.aichi.jp","toyone.aichi.jp","toyota.aichi.jp","tsushima.aichi.jp","yatomi.aichi.jp","akita.akita.jp","daisen.akita.jp","fujisato.akita.jp","gojome.akita.jp","hachirogata.akita.jp","happou.akita.jp","higashinaruse.akita.jp","honjo.akita.jp","honjyo.akita.jp","ikawa.akita.jp","kamikoani.akita.jp","kamioka.akita.jp","katagami.akita.jp","kazuno.akita.jp","kitaakita.akita.jp","kosaka.akita.jp","kyowa.akita.jp","misato.akita.jp","mitane.akita.jp","moriyoshi.akita.jp","nikaho.akita.jp","noshiro.akita.jp","odate.akita.jp","oga.akita.jp","ogata.akita.jp","semboku.akita.jp","yokote.akita.jp","yurihonjo.akita.jp","aomori.aomori.jp","gonohe.aomori.jp","hachinohe.aomori.jp","hashikami.aomori.jp","hiranai.aomori.jp","hirosaki.aomori.jp","itayanagi.aomori.jp","kuroishi.aomori.jp","misawa.aomori.jp","mutsu.aomori.jp","nakadomari.aomori.jp","noheji.aomori.jp","oirase.aomori.jp","owani.aomori.jp","rokunohe.aomori.jp","sannohe.aomori.jp","shichinohe.aomori.jp","shingo.aomori.jp","takko.aomori.jp","towada.aomori.jp","tsugaru.aomori.jp","tsuruta.aomori.jp","abiko.chiba.jp","asahi.chiba.jp","chonan.chiba.jp","chosei.chiba.jp","choshi.chiba.jp","chuo.chiba.jp","funabashi.chiba.jp","futtsu.chiba.jp","hanamigawa.chiba.jp","ichihara.chiba.jp","ichikawa.chiba.jp","ichinomiya.chiba.jp","inzai.chiba.jp","isumi.chiba.jp","kamagaya.chiba.jp","kamogawa.chiba.jp","kashiwa.chiba.jp","katori.chiba.jp","katsuura.chiba.jp","kimitsu.chiba.jp","kisarazu.chiba.jp","kozaki.chiba.jp","kujukuri.chiba.jp","kyonan.chiba.jp","matsudo.chiba.jp","midori.chiba.jp","mihama.chiba.jp","minamiboso.chiba.jp","mobara.chiba.jp","mutsuzawa.chiba.jp","nagara.chiba.jp","nagareyama.chiba.jp","narashino.chiba.jp","narita.chiba.jp","noda.chiba.jp","oamishirasato.chiba.jp","omigawa.chiba.jp","onjuku.chiba.jp","otaki.chiba.jp","sakae.chiba.jp","sakura.chiba.jp","shimofusa.chiba.jp","shirako.chiba.jp","shiroi.chiba.jp","shisui.chiba.jp","sodegaura.chiba.jp","sosa.chiba.jp","tako.chiba.jp","tateyama.chiba.jp","togane.chiba.jp","tohnosho.chiba.jp","tomisato.chiba.jp","urayasu.chiba.jp","yachimata.chiba.jp","yachiyo.chiba.jp","yokaichiba.chiba.jp","yokoshibahikari.chiba.jp","yotsukaido.chiba.jp","ainan.ehime.jp","honai.ehime.jp","ikata.ehime.jp","imabari.ehime.jp","iyo.ehime.jp","kamijima.ehime.jp","kihoku.ehime.jp","kumakogen.ehime.jp","masaki.ehime.jp","matsuno.ehime.jp","matsuyama.ehime.jp","namikata.ehime.jp","niihama.ehime.jp","ozu.ehime.jp","saijo.ehime.jp","seiyo.ehime.jp","shikokuchuo.ehime.jp","tobe.ehime.jp","toon.ehime.jp","uchiko.ehime.jp","uwajima.ehime.jp","yawatahama.ehime.jp","echizen.fukui.jp","eiheiji.fukui.jp","fukui.fukui.jp","ikeda.fukui.jp","katsuyama.fukui.jp","mihama.fukui.jp","minamiechizen.fukui.jp","obama.fukui.jp","ohi.fukui.jp","ono.fukui.jp","sabae.fukui.jp","sakai.fukui.jp","takahama.fukui.jp","tsuruga.fukui.jp","wakasa.fukui.jp","ashiya.fukuoka.jp","buzen.fukuoka.jp","chikugo.fukuoka.jp","chikuho.fukuoka.jp","chikujo.fukuoka.jp","chikushino.fukuoka.jp","chikuzen.fukuoka.jp","chuo.fukuoka.jp","dazaifu.fukuoka.jp","fukuchi.fukuoka.jp","hakata.fukuoka.jp","higashi.fukuoka.jp","hirokawa.fukuoka.jp","hisayama.fukuoka.jp","iizuka.fukuoka.jp","inatsuki.fukuoka.jp","kaho.fukuoka.jp","kasuga.fukuoka.jp","kasuya.fukuoka.jp","kawara.fukuoka.jp","keisen.fukuoka.jp","koga.fukuoka.jp","kurate.fukuoka.jp","kurogi.fukuoka.jp","kurume.fukuoka.jp","minami.fukuoka.jp","miyako.fukuoka.jp","miyama.fukuoka.jp","miyawaka.fukuoka.jp","mizumaki.fukuoka.jp","munakata.fukuoka.jp","nakagawa.fukuoka.jp","nakama.fukuoka.jp","nishi.fukuoka.jp","nogata.fukuoka.jp","ogori.fukuoka.jp","okagaki.fukuoka.jp","okawa.fukuoka.jp","oki.fukuoka.jp","omuta.fukuoka.jp","onga.fukuoka.jp","onojo.fukuoka.jp","oto.fukuoka.jp","saigawa.fukuoka.jp","sasaguri.fukuoka.jp","shingu.fukuoka.jp","shinyoshitomi.fukuoka.jp","shonai.fukuoka.jp","soeda.fukuoka.jp","sue.fukuoka.jp","tachiarai.fukuoka.jp","tagawa.fukuoka.jp","takata.fukuoka.jp","toho.fukuoka.jp","toyotsu.fukuoka.jp","tsuiki.fukuoka.jp","ukiha.fukuoka.jp","umi.fukuoka.jp","usui.fukuoka.jp","yamada.fukuoka.jp","yame.fukuoka.jp","yanagawa.fukuoka.jp","yukuhashi.fukuoka.jp","aizubange.fukushima.jp","aizumisato.fukushima.jp","aizuwakamatsu.fukushima.jp","asakawa.fukushima.jp","bandai.fukushima.jp","date.fukushima.jp","fukushima.fukushima.jp","furudono.fukushima.jp","futaba.fukushima.jp","hanawa.fukushima.jp","higashi.fukushima.jp","hirata.fukushima.jp","hirono.fukushima.jp","iitate.fukushima.jp","inawashiro.fukushima.jp","ishikawa.fukushima.jp","iwaki.fukushima.jp","izumizaki.fukushima.jp","kagamiishi.fukushima.jp","kaneyama.fukushima.jp","kawamata.fukushima.jp","kitakata.fukushima.jp","kitashiobara.fukushima.jp","koori.fukushima.jp","koriyama.fukushima.jp","kunimi.fukushima.jp","miharu.fukushima.jp","mishima.fukushima.jp","namie.fukushima.jp","nango.fukushima.jp","nishiaizu.fukushima.jp","nishigo.fukushima.jp","okuma.fukushima.jp","omotego.fukushima.jp","ono.fukushima.jp","otama.fukushima.jp","samegawa.fukushima.jp","shimogo.fukushima.jp","shirakawa.fukushima.jp","showa.fukushima.jp","soma.fukushima.jp","sukagawa.fukushima.jp","taishin.fukushima.jp","tamakawa.fukushima.jp","tanagura.fukushima.jp","tenei.fukushima.jp","yabuki.fukushima.jp","yamato.fukushima.jp","yamatsuri.fukushima.jp","yanaizu.fukushima.jp","yugawa.fukushima.jp","anpachi.gifu.jp","ena.gifu.jp","gifu.gifu.jp","ginan.gifu.jp","godo.gifu.jp","gujo.gifu.jp","hashima.gifu.jp","hichiso.gifu.jp","hida.gifu.jp","higashishirakawa.gifu.jp","ibigawa.gifu.jp","ikeda.gifu.jp","kakamigahara.gifu.jp","kani.gifu.jp","kasahara.gifu.jp","kasamatsu.gifu.jp","kawaue.gifu.jp","kitagata.gifu.jp","mino.gifu.jp","minokamo.gifu.jp","mitake.gifu.jp","mizunami.gifu.jp","motosu.gifu.jp","nakatsugawa.gifu.jp","ogaki.gifu.jp","sakahogi.gifu.jp","seki.gifu.jp","sekigahara.gifu.jp","shirakawa.gifu.jp","tajimi.gifu.jp","takayama.gifu.jp","tarui.gifu.jp","toki.gifu.jp","tomika.gifu.jp","wanouchi.gifu.jp","yamagata.gifu.jp","yaotsu.gifu.jp","yoro.gifu.jp","annaka.gunma.jp","chiyoda.gunma.jp","fujioka.gunma.jp","higashiagatsuma.gunma.jp","isesaki.gunma.jp","itakura.gunma.jp","kanna.gunma.jp","kanra.gunma.jp","katashina.gunma.jp","kawaba.gunma.jp","kiryu.gunma.jp","kusatsu.gunma.jp","maebashi.gunma.jp","meiwa.gunma.jp","midori.gunma.jp","minakami.gunma.jp","naganohara.gunma.jp","nakanojo.gunma.jp","nanmoku.gunma.jp","numata.gunma.jp","oizumi.gunma.jp","ora.gunma.jp","ota.gunma.jp","shibukawa.gunma.jp","shimonita.gunma.jp","shinto.gunma.jp","showa.gunma.jp","takasaki.gunma.jp","takayama.gunma.jp","tamamura.gunma.jp","tatebayashi.gunma.jp","tomioka.gunma.jp","tsukiyono.gunma.jp","tsumagoi.gunma.jp","ueno.gunma.jp","yoshioka.gunma.jp","asaminami.hiroshima.jp","daiwa.hiroshima.jp","etajima.hiroshima.jp","fuchu.hiroshima.jp","fukuyama.hiroshima.jp","hatsukaichi.hiroshima.jp","higashihiroshima.hiroshima.jp","hongo.hiroshima.jp","jinsekikogen.hiroshima.jp","kaita.hiroshima.jp","kui.hiroshima.jp","kumano.hiroshima.jp","kure.hiroshima.jp","mihara.hiroshima.jp","miyoshi.hiroshima.jp","naka.hiroshima.jp","onomichi.hiroshima.jp","osakikamijima.hiroshima.jp","otake.hiroshima.jp","saka.hiroshima.jp","sera.hiroshima.jp","seranishi.hiroshima.jp","shinichi.hiroshima.jp","shobara.hiroshima.jp","takehara.hiroshima.jp","abashiri.hokkaido.jp","abira.hokkaido.jp","aibetsu.hokkaido.jp","akabira.hokkaido.jp","akkeshi.hokkaido.jp","asahikawa.hokkaido.jp","ashibetsu.hokkaido.jp","ashoro.hokkaido.jp","assabu.hokkaido.jp","atsuma.hokkaido.jp","bibai.hokkaido.jp","biei.hokkaido.jp","bifuka.hokkaido.jp","bihoro.hokkaido.jp","biratori.hokkaido.jp","chippubetsu.hokkaido.jp","chitose.hokkaido.jp","date.hokkaido.jp","ebetsu.hokkaido.jp","embetsu.hokkaido.jp","eniwa.hokkaido.jp","erimo.hokkaido.jp","esan.hokkaido.jp","esashi.hokkaido.jp","fukagawa.hokkaido.jp","fukushima.hokkaido.jp","furano.hokkaido.jp","furubira.hokkaido.jp","haboro.hokkaido.jp","hakodate.hokkaido.jp","hamatonbetsu.hokkaido.jp","hidaka.hokkaido.jp","higashikagura.hokkaido.jp","higashikawa.hokkaido.jp","hiroo.hokkaido.jp","hokuryu.hokkaido.jp","hokuto.hokkaido.jp","honbetsu.hokkaido.jp","horokanai.hokkaido.jp","horonobe.hokkaido.jp","ikeda.hokkaido.jp","imakane.hokkaido.jp","ishikari.hokkaido.jp","iwamizawa.hokkaido.jp","iwanai.hokkaido.jp","kamifurano.hokkaido.jp","kamikawa.hokkaido.jp","kamishihoro.hokkaido.jp","kamisunagawa.hokkaido.jp","kamoenai.hokkaido.jp","kayabe.hokkaido.jp","kembuchi.hokkaido.jp","kikonai.hokkaido.jp","kimobetsu.hokkaido.jp","kitahiroshima.hokkaido.jp","kitami.hokkaido.jp","kiyosato.hokkaido.jp","koshimizu.hokkaido.jp","kunneppu.hokkaido.jp","kuriyama.hokkaido.jp","kuromatsunai.hokkaido.jp","kushiro.hokkaido.jp","kutchan.hokkaido.jp","kyowa.hokkaido.jp","mashike.hokkaido.jp","matsumae.hokkaido.jp","mikasa.hokkaido.jp","minamifurano.hokkaido.jp","mombetsu.hokkaido.jp","moseushi.hokkaido.jp","mukawa.hokkaido.jp","muroran.hokkaido.jp","naie.hokkaido.jp","nakagawa.hokkaido.jp","nakasatsunai.hokkaido.jp","nakatombetsu.hokkaido.jp","nanae.hokkaido.jp","nanporo.hokkaido.jp","nayoro.hokkaido.jp","nemuro.hokkaido.jp","niikappu.hokkaido.jp","niki.hokkaido.jp","nishiokoppe.hokkaido.jp","noboribetsu.hokkaido.jp","numata.hokkaido.jp","obihiro.hokkaido.jp","obira.hokkaido.jp","oketo.hokkaido.jp","okoppe.hokkaido.jp","otaru.hokkaido.jp","otobe.hokkaido.jp","otofuke.hokkaido.jp","otoineppu.hokkaido.jp","oumu.hokkaido.jp","ozora.hokkaido.jp","pippu.hokkaido.jp","rankoshi.hokkaido.jp","rebun.hokkaido.jp","rikubetsu.hokkaido.jp","rishiri.hokkaido.jp","rishirifuji.hokkaido.jp","saroma.hokkaido.jp","sarufutsu.hokkaido.jp","shakotan.hokkaido.jp","shari.hokkaido.jp","shibecha.hokkaido.jp","shibetsu.hokkaido.jp","shikabe.hokkaido.jp","shikaoi.hokkaido.jp","shimamaki.hokkaido.jp","shimizu.hokkaido.jp","shimokawa.hokkaido.jp","shinshinotsu.hokkaido.jp","shintoku.hokkaido.jp","shiranuka.hokkaido.jp","shiraoi.hokkaido.jp","shiriuchi.hokkaido.jp","sobetsu.hokkaido.jp","sunagawa.hokkaido.jp","taiki.hokkaido.jp","takasu.hokkaido.jp","takikawa.hokkaido.jp","takinoue.hokkaido.jp","teshikaga.hokkaido.jp","tobetsu.hokkaido.jp","tohma.hokkaido.jp","tomakomai.hokkaido.jp","tomari.hokkaido.jp","toya.hokkaido.jp","toyako.hokkaido.jp","toyotomi.hokkaido.jp","toyoura.hokkaido.jp","tsubetsu.hokkaido.jp","tsukigata.hokkaido.jp","urakawa.hokkaido.jp","urausu.hokkaido.jp","uryu.hokkaido.jp","utashinai.hokkaido.jp","wakkanai.hokkaido.jp","wassamu.hokkaido.jp","yakumo.hokkaido.jp","yoichi.hokkaido.jp","aioi.hyogo.jp","akashi.hyogo.jp","ako.hyogo.jp","amagasaki.hyogo.jp","aogaki.hyogo.jp","asago.hyogo.jp","ashiya.hyogo.jp","awaji.hyogo.jp","fukusaki.hyogo.jp","goshiki.hyogo.jp","harima.hyogo.jp","himeji.hyogo.jp","ichikawa.hyogo.jp","inagawa.hyogo.jp","itami.hyogo.jp","kakogawa.hyogo.jp","kamigori.hyogo.jp","kamikawa.hyogo.jp","kasai.hyogo.jp","kasuga.hyogo.jp","kawanishi.hyogo.jp","miki.hyogo.jp","minamiawaji.hyogo.jp","nishinomiya.hyogo.jp","nishiwaki.hyogo.jp","ono.hyogo.jp","sanda.hyogo.jp","sannan.hyogo.jp","sasayama.hyogo.jp","sayo.hyogo.jp","shingu.hyogo.jp","shinonsen.hyogo.jp","shiso.hyogo.jp","sumoto.hyogo.jp","taishi.hyogo.jp","taka.hyogo.jp","takarazuka.hyogo.jp","takasago.hyogo.jp","takino.hyogo.jp","tamba.hyogo.jp","tatsuno.hyogo.jp","toyooka.hyogo.jp","yabu.hyogo.jp","yashiro.hyogo.jp","yoka.hyogo.jp","yokawa.hyogo.jp","ami.ibaraki.jp","asahi.ibaraki.jp","bando.ibaraki.jp","chikusei.ibaraki.jp","daigo.ibaraki.jp","fujishiro.ibaraki.jp","hitachi.ibaraki.jp","hitachinaka.ibaraki.jp","hitachiomiya.ibaraki.jp","hitachiota.ibaraki.jp","ibaraki.ibaraki.jp","ina.ibaraki.jp","inashiki.ibaraki.jp","itako.ibaraki.jp","iwama.ibaraki.jp","joso.ibaraki.jp","kamisu.ibaraki.jp","kasama.ibaraki.jp","kashima.ibaraki.jp","kasumigaura.ibaraki.jp","koga.ibaraki.jp","miho.ibaraki.jp","mito.ibaraki.jp","moriya.ibaraki.jp","naka.ibaraki.jp","namegata.ibaraki.jp","oarai.ibaraki.jp","ogawa.ibaraki.jp","omitama.ibaraki.jp","ryugasaki.ibaraki.jp","sakai.ibaraki.jp","sakuragawa.ibaraki.jp","shimodate.ibaraki.jp","shimotsuma.ibaraki.jp","shirosato.ibaraki.jp","sowa.ibaraki.jp","suifu.ibaraki.jp","takahagi.ibaraki.jp","tamatsukuri.ibaraki.jp","tokai.ibaraki.jp","tomobe.ibaraki.jp","tone.ibaraki.jp","toride.ibaraki.jp","tsuchiura.ibaraki.jp","tsukuba.ibaraki.jp","uchihara.ibaraki.jp","ushiku.ibaraki.jp","yachiyo.ibaraki.jp","yamagata.ibaraki.jp","yawara.ibaraki.jp","yuki.ibaraki.jp","anamizu.ishikawa.jp","hakui.ishikawa.jp","hakusan.ishikawa.jp","kaga.ishikawa.jp","kahoku.ishikawa.jp","kanazawa.ishikawa.jp","kawakita.ishikawa.jp","komatsu.ishikawa.jp","nakanoto.ishikawa.jp","nanao.ishikawa.jp","nomi.ishikawa.jp","nonoichi.ishikawa.jp","noto.ishikawa.jp","shika.ishikawa.jp","suzu.ishikawa.jp","tsubata.ishikawa.jp","tsurugi.ishikawa.jp","uchinada.ishikawa.jp","wajima.ishikawa.jp","fudai.iwate.jp","fujisawa.iwate.jp","hanamaki.iwate.jp","hiraizumi.iwate.jp","hirono.iwate.jp","ichinohe.iwate.jp","ichinoseki.iwate.jp","iwaizumi.iwate.jp","iwate.iwate.jp","joboji.iwate.jp","kamaishi.iwate.jp","kanegasaki.iwate.jp","karumai.iwate.jp","kawai.iwate.jp","kitakami.iwate.jp","kuji.iwate.jp","kunohe.iwate.jp","kuzumaki.iwate.jp","miyako.iwate.jp","mizusawa.iwate.jp","morioka.iwate.jp","ninohe.iwate.jp","noda.iwate.jp","ofunato.iwate.jp","oshu.iwate.jp","otsuchi.iwate.jp","rikuzentakata.iwate.jp","shiwa.iwate.jp","shizukuishi.iwate.jp","sumita.iwate.jp","tanohata.iwate.jp","tono.iwate.jp","yahaba.iwate.jp","yamada.iwate.jp","ayagawa.kagawa.jp","higashikagawa.kagawa.jp","kanonji.kagawa.jp","kotohira.kagawa.jp","manno.kagawa.jp","marugame.kagawa.jp","mitoyo.kagawa.jp","naoshima.kagawa.jp","sanuki.kagawa.jp","tadotsu.kagawa.jp","takamatsu.kagawa.jp","tonosho.kagawa.jp","uchinomi.kagawa.jp","utazu.kagawa.jp","zentsuji.kagawa.jp","akune.kagoshima.jp","amami.kagoshima.jp","hioki.kagoshima.jp","isa.kagoshima.jp","isen.kagoshima.jp","izumi.kagoshima.jp","kagoshima.kagoshima.jp","kanoya.kagoshima.jp","kawanabe.kagoshima.jp","kinko.kagoshima.jp","kouyama.kagoshima.jp","makurazaki.kagoshima.jp","matsumoto.kagoshima.jp","minamitane.kagoshima.jp","nakatane.kagoshima.jp","nishinoomote.kagoshima.jp","satsumasendai.kagoshima.jp","soo.kagoshima.jp","tarumizu.kagoshima.jp","yusui.kagoshima.jp","aikawa.kanagawa.jp","atsugi.kanagawa.jp","ayase.kanagawa.jp","chigasaki.kanagawa.jp","ebina.kanagawa.jp","fujisawa.kanagawa.jp","hadano.kanagawa.jp","hakone.kanagawa.jp","hiratsuka.kanagawa.jp","isehara.kanagawa.jp","kaisei.kanagawa.jp","kamakura.kanagawa.jp","kiyokawa.kanagawa.jp","matsuda.kanagawa.jp","minamiashigara.kanagawa.jp","miura.kanagawa.jp","nakai.kanagawa.jp","ninomiya.kanagawa.jp","odawara.kanagawa.jp","oi.kanagawa.jp","oiso.kanagawa.jp","sagamihara.kanagawa.jp","samukawa.kanagawa.jp","tsukui.kanagawa.jp","yamakita.kanagawa.jp","yamato.kanagawa.jp","yokosuka.kanagawa.jp","yugawara.kanagawa.jp","zama.kanagawa.jp","zushi.kanagawa.jp","aki.kochi.jp","geisei.kochi.jp","hidaka.kochi.jp","higashitsuno.kochi.jp","ino.kochi.jp","kagami.kochi.jp","kami.kochi.jp","kitagawa.kochi.jp","kochi.kochi.jp","mihara.kochi.jp","motoyama.kochi.jp","muroto.kochi.jp","nahari.kochi.jp","nakamura.kochi.jp","nankoku.kochi.jp","nishitosa.kochi.jp","niyodogawa.kochi.jp","ochi.kochi.jp","okawa.kochi.jp","otoyo.kochi.jp","otsuki.kochi.jp","sakawa.kochi.jp","sukumo.kochi.jp","susaki.kochi.jp","tosa.kochi.jp","tosashimizu.kochi.jp","toyo.kochi.jp","tsuno.kochi.jp","umaji.kochi.jp","yasuda.kochi.jp","yusuhara.kochi.jp","amakusa.kumamoto.jp","arao.kumamoto.jp","aso.kumamoto.jp","choyo.kumamoto.jp","gyokuto.kumamoto.jp","kamiamakusa.kumamoto.jp","kikuchi.kumamoto.jp","kumamoto.kumamoto.jp","mashiki.kumamoto.jp","mifune.kumamoto.jp","minamata.kumamoto.jp","minamioguni.kumamoto.jp","nagasu.kumamoto.jp","nishihara.kumamoto.jp","oguni.kumamoto.jp","ozu.kumamoto.jp","sumoto.kumamoto.jp","takamori.kumamoto.jp","uki.kumamoto.jp","uto.kumamoto.jp","yamaga.kumamoto.jp","yamato.kumamoto.jp","yatsushiro.kumamoto.jp","ayabe.kyoto.jp","fukuchiyama.kyoto.jp","higashiyama.kyoto.jp","ide.kyoto.jp","ine.kyoto.jp","joyo.kyoto.jp","kameoka.kyoto.jp","kamo.kyoto.jp","kita.kyoto.jp","kizu.kyoto.jp","kumiyama.kyoto.jp","kyotamba.kyoto.jp","kyotanabe.kyoto.jp","kyotango.kyoto.jp","maizuru.kyoto.jp","minami.kyoto.jp","minamiyamashiro.kyoto.jp","miyazu.kyoto.jp","muko.kyoto.jp","nagaokakyo.kyoto.jp","nakagyo.kyoto.jp","nantan.kyoto.jp","oyamazaki.kyoto.jp","sakyo.kyoto.jp","seika.kyoto.jp","tanabe.kyoto.jp","uji.kyoto.jp","ujitawara.kyoto.jp","wazuka.kyoto.jp","yamashina.kyoto.jp","yawata.kyoto.jp","asahi.mie.jp","inabe.mie.jp","ise.mie.jp","kameyama.mie.jp","kawagoe.mie.jp","kiho.mie.jp","kisosaki.mie.jp","kiwa.mie.jp","komono.mie.jp","kumano.mie.jp","kuwana.mie.jp","matsusaka.mie.jp","meiwa.mie.jp","mihama.mie.jp","minamiise.mie.jp","misugi.mie.jp","miyama.mie.jp","nabari.mie.jp","shima.mie.jp","suzuka.mie.jp","tado.mie.jp","taiki.mie.jp","taki.mie.jp","tamaki.mie.jp","toba.mie.jp","tsu.mie.jp","udono.mie.jp","ureshino.mie.jp","watarai.mie.jp","yokkaichi.mie.jp","furukawa.miyagi.jp","higashimatsushima.miyagi.jp","ishinomaki.miyagi.jp","iwanuma.miyagi.jp","kakuda.miyagi.jp","kami.miyagi.jp","kawasaki.miyagi.jp","marumori.miyagi.jp","matsushima.miyagi.jp","minamisanriku.miyagi.jp","misato.miyagi.jp","murata.miyagi.jp","natori.miyagi.jp","ogawara.miyagi.jp","ohira.miyagi.jp","onagawa.miyagi.jp","osaki.miyagi.jp","rifu.miyagi.jp","semine.miyagi.jp","shibata.miyagi.jp","shichikashuku.miyagi.jp","shikama.miyagi.jp","shiogama.miyagi.jp","shiroishi.miyagi.jp","tagajo.miyagi.jp","taiwa.miyagi.jp","tome.miyagi.jp","tomiya.miyagi.jp","wakuya.miyagi.jp","watari.miyagi.jp","yamamoto.miyagi.jp","zao.miyagi.jp","aya.miyazaki.jp","ebino.miyazaki.jp","gokase.miyazaki.jp","hyuga.miyazaki.jp","kadogawa.miyazaki.jp","kawaminami.miyazaki.jp","kijo.miyazaki.jp","kitagawa.miyazaki.jp","kitakata.miyazaki.jp","kitaura.miyazaki.jp","kobayashi.miyazaki.jp","kunitomi.miyazaki.jp","kushima.miyazaki.jp","mimata.miyazaki.jp","miyakonojo.miyazaki.jp","miyazaki.miyazaki.jp","morotsuka.miyazaki.jp","nichinan.miyazaki.jp","nishimera.miyazaki.jp","nobeoka.miyazaki.jp","saito.miyazaki.jp","shiiba.miyazaki.jp","shintomi.miyazaki.jp","takaharu.miyazaki.jp","takanabe.miyazaki.jp","takazaki.miyazaki.jp","tsuno.miyazaki.jp","achi.nagano.jp","agematsu.nagano.jp","anan.nagano.jp","aoki.nagano.jp","asahi.nagano.jp","azumino.nagano.jp","chikuhoku.nagano.jp","chikuma.nagano.jp","chino.nagano.jp","fujimi.nagano.jp","hakuba.nagano.jp","hara.nagano.jp","hiraya.nagano.jp","iida.nagano.jp","iijima.nagano.jp","iiyama.nagano.jp","iizuna.nagano.jp","ikeda.nagano.jp","ikusaka.nagano.jp","ina.nagano.jp","karuizawa.nagano.jp","kawakami.nagano.jp","kiso.nagano.jp","kisofukushima.nagano.jp","kitaaiki.nagano.jp","komagane.nagano.jp","komoro.nagano.jp","matsukawa.nagano.jp","matsumoto.nagano.jp","miasa.nagano.jp","minamiaiki.nagano.jp","minamimaki.nagano.jp","minamiminowa.nagano.jp","minowa.nagano.jp","miyada.nagano.jp","miyota.nagano.jp","mochizuki.nagano.jp","nagano.nagano.jp","nagawa.nagano.jp","nagiso.nagano.jp","nakagawa.nagano.jp","nakano.nagano.jp","nozawaonsen.nagano.jp","obuse.nagano.jp","ogawa.nagano.jp","okaya.nagano.jp","omachi.nagano.jp","omi.nagano.jp","ookuwa.nagano.jp","ooshika.nagano.jp","otaki.nagano.jp","otari.nagano.jp","sakae.nagano.jp","sakaki.nagano.jp","saku.nagano.jp","sakuho.nagano.jp","shimosuwa.nagano.jp","shinanomachi.nagano.jp","shiojiri.nagano.jp","suwa.nagano.jp","suzaka.nagano.jp","takagi.nagano.jp","takamori.nagano.jp","takayama.nagano.jp","tateshina.nagano.jp","tatsuno.nagano.jp","togakushi.nagano.jp","togura.nagano.jp","tomi.nagano.jp","ueda.nagano.jp","wada.nagano.jp","yamagata.nagano.jp","yamanouchi.nagano.jp","yasaka.nagano.jp","yasuoka.nagano.jp","chijiwa.nagasaki.jp","futsu.nagasaki.jp","goto.nagasaki.jp","hasami.nagasaki.jp","hirado.nagasaki.jp","iki.nagasaki.jp","isahaya.nagasaki.jp","kawatana.nagasaki.jp","kuchinotsu.nagasaki.jp","matsuura.nagasaki.jp","nagasaki.nagasaki.jp","obama.nagasaki.jp","omura.nagasaki.jp","oseto.nagasaki.jp","saikai.nagasaki.jp","sasebo.nagasaki.jp","seihi.nagasaki.jp","shimabara.nagasaki.jp","shinkamigoto.nagasaki.jp","togitsu.nagasaki.jp","tsushima.nagasaki.jp","unzen.nagasaki.jp","ando.nara.jp","gose.nara.jp","heguri.nara.jp","higashiyoshino.nara.jp","ikaruga.nara.jp","ikoma.nara.jp","kamikitayama.nara.jp","kanmaki.nara.jp","kashiba.nara.jp","kashihara.nara.jp","katsuragi.nara.jp","kawai.nara.jp","kawakami.nara.jp","kawanishi.nara.jp","koryo.nara.jp","kurotaki.nara.jp","mitsue.nara.jp","miyake.nara.jp","nara.nara.jp","nosegawa.nara.jp","oji.nara.jp","ouda.nara.jp","oyodo.nara.jp","sakurai.nara.jp","sango.nara.jp","shimoichi.nara.jp","shimokitayama.nara.jp","shinjo.nara.jp","soni.nara.jp","takatori.nara.jp","tawaramoto.nara.jp","tenkawa.nara.jp","tenri.nara.jp","uda.nara.jp","yamatokoriyama.nara.jp","yamatotakada.nara.jp","yamazoe.nara.jp","yoshino.nara.jp","aga.niigata.jp","agano.niigata.jp","gosen.niigata.jp","itoigawa.niigata.jp","izumozaki.niigata.jp","joetsu.niigata.jp","kamo.niigata.jp","kariwa.niigata.jp","kashiwazaki.niigata.jp","minamiuonuma.niigata.jp","mitsuke.niigata.jp","muika.niigata.jp","murakami.niigata.jp","myoko.niigata.jp","nagaoka.niigata.jp","niigata.niigata.jp","ojiya.niigata.jp","omi.niigata.jp","sado.niigata.jp","sanjo.niigata.jp","seiro.niigata.jp","seirou.niigata.jp","sekikawa.niigata.jp","shibata.niigata.jp","tagami.niigata.jp","tainai.niigata.jp","tochio.niigata.jp","tokamachi.niigata.jp","tsubame.niigata.jp","tsunan.niigata.jp","uonuma.niigata.jp","yahiko.niigata.jp","yoita.niigata.jp","yuzawa.niigata.jp","beppu.oita.jp","bungoono.oita.jp","bungotakada.oita.jp","hasama.oita.jp","hiji.oita.jp","himeshima.oita.jp","hita.oita.jp","kamitsue.oita.jp","kokonoe.oita.jp","kuju.oita.jp","kunisaki.oita.jp","kusu.oita.jp","oita.oita.jp","saiki.oita.jp","taketa.oita.jp","tsukumi.oita.jp","usa.oita.jp","usuki.oita.jp","yufu.oita.jp","akaiwa.okayama.jp","asakuchi.okayama.jp","bizen.okayama.jp","hayashima.okayama.jp","ibara.okayama.jp","kagamino.okayama.jp","kasaoka.okayama.jp","kibichuo.okayama.jp","kumenan.okayama.jp","kurashiki.okayama.jp","maniwa.okayama.jp","misaki.okayama.jp","nagi.okayama.jp","niimi.okayama.jp","nishiawakura.okayama.jp","okayama.okayama.jp","satosho.okayama.jp","setouchi.okayama.jp","shinjo.okayama.jp","shoo.okayama.jp","soja.okayama.jp","takahashi.okayama.jp","tamano.okayama.jp","tsuyama.okayama.jp","wake.okayama.jp","yakage.okayama.jp","aguni.okinawa.jp","ginowan.okinawa.jp","ginoza.okinawa.jp","gushikami.okinawa.jp","haebaru.okinawa.jp","higashi.okinawa.jp","hirara.okinawa.jp","iheya.okinawa.jp","ishigaki.okinawa.jp","ishikawa.okinawa.jp","itoman.okinawa.jp","izena.okinawa.jp","kadena.okinawa.jp","kin.okinawa.jp","kitadaito.okinawa.jp","kitanakagusuku.okinawa.jp","kumejima.okinawa.jp","kunigami.okinawa.jp","minamidaito.okinawa.jp","motobu.okinawa.jp","nago.okinawa.jp","naha.okinawa.jp","nakagusuku.okinawa.jp","nakijin.okinawa.jp","nanjo.okinawa.jp","nishihara.okinawa.jp","ogimi.okinawa.jp","okinawa.okinawa.jp","onna.okinawa.jp","shimoji.okinawa.jp","taketomi.okinawa.jp","tarama.okinawa.jp","tokashiki.okinawa.jp","tomigusuku.okinawa.jp","tonaki.okinawa.jp","urasoe.okinawa.jp","uruma.okinawa.jp","yaese.okinawa.jp","yomitan.okinawa.jp","yonabaru.okinawa.jp","yonaguni.okinawa.jp","zamami.okinawa.jp","abeno.osaka.jp","chihayaakasaka.osaka.jp","chuo.osaka.jp","daito.osaka.jp","fujiidera.osaka.jp","habikino.osaka.jp","hannan.osaka.jp","higashiosaka.osaka.jp","higashisumiyoshi.osaka.jp","higashiyodogawa.osaka.jp","hirakata.osaka.jp","ibaraki.osaka.jp","ikeda.osaka.jp","izumi.osaka.jp","izumiotsu.osaka.jp","izumisano.osaka.jp","kadoma.osaka.jp","kaizuka.osaka.jp","kanan.osaka.jp","kashiwara.osaka.jp","katano.osaka.jp","kawachinagano.osaka.jp","kishiwada.osaka.jp","kita.osaka.jp","kumatori.osaka.jp","matsubara.osaka.jp","minato.osaka.jp","minoh.osaka.jp","misaki.osaka.jp","moriguchi.osaka.jp","neyagawa.osaka.jp","nishi.osaka.jp","nose.osaka.jp","osakasayama.osaka.jp","sakai.osaka.jp","sayama.osaka.jp","sennan.osaka.jp","settsu.osaka.jp","shijonawate.osaka.jp","shimamoto.osaka.jp","suita.osaka.jp","tadaoka.osaka.jp","taishi.osaka.jp","tajiri.osaka.jp","takaishi.osaka.jp","takatsuki.osaka.jp","tondabayashi.osaka.jp","toyonaka.osaka.jp","toyono.osaka.jp","yao.osaka.jp","ariake.saga.jp","arita.saga.jp","fukudomi.saga.jp","genkai.saga.jp","hamatama.saga.jp","hizen.saga.jp","imari.saga.jp","kamimine.saga.jp","kanzaki.saga.jp","karatsu.saga.jp","kashima.saga.jp","kitagata.saga.jp","kitahata.saga.jp","kiyama.saga.jp","kouhoku.saga.jp","kyuragi.saga.jp","nishiarita.saga.jp","ogi.saga.jp","omachi.saga.jp","ouchi.saga.jp","saga.saga.jp","shiroishi.saga.jp","taku.saga.jp","tara.saga.jp","tosu.saga.jp","yoshinogari.saga.jp","arakawa.saitama.jp","asaka.saitama.jp","chichibu.saitama.jp","fujimi.saitama.jp","fujimino.saitama.jp","fukaya.saitama.jp","hanno.saitama.jp","hanyu.saitama.jp","hasuda.saitama.jp","hatogaya.saitama.jp","hatoyama.saitama.jp","hidaka.saitama.jp","higashichichibu.saitama.jp","higashimatsuyama.saitama.jp","honjo.saitama.jp","ina.saitama.jp","iruma.saitama.jp","iwatsuki.saitama.jp","kamiizumi.saitama.jp","kamikawa.saitama.jp","kamisato.saitama.jp","kasukabe.saitama.jp","kawagoe.saitama.jp","kawaguchi.saitama.jp","kawajima.saitama.jp","kazo.saitama.jp","kitamoto.saitama.jp","koshigaya.saitama.jp","kounosu.saitama.jp","kuki.saitama.jp","kumagaya.saitama.jp","matsubushi.saitama.jp","minano.saitama.jp","misato.saitama.jp","miyashiro.saitama.jp","miyoshi.saitama.jp","moroyama.saitama.jp","nagatoro.saitama.jp","namegawa.saitama.jp","niiza.saitama.jp","ogano.saitama.jp","ogawa.saitama.jp","ogose.saitama.jp","okegawa.saitama.jp","omiya.saitama.jp","otaki.saitama.jp","ranzan.saitama.jp","ryokami.saitama.jp","saitama.saitama.jp","sakado.saitama.jp","satte.saitama.jp","sayama.saitama.jp","shiki.saitama.jp","shiraoka.saitama.jp","soka.saitama.jp","sugito.saitama.jp","toda.saitama.jp","tokigawa.saitama.jp","tokorozawa.saitama.jp","tsurugashima.saitama.jp","urawa.saitama.jp","warabi.saitama.jp","yashio.saitama.jp","yokoze.saitama.jp","yono.saitama.jp","yorii.saitama.jp","yoshida.saitama.jp","yoshikawa.saitama.jp","yoshimi.saitama.jp","aisho.shiga.jp","gamo.shiga.jp","higashiomi.shiga.jp","hikone.shiga.jp","koka.shiga.jp","konan.shiga.jp","kosei.shiga.jp","koto.shiga.jp","kusatsu.shiga.jp","maibara.shiga.jp","moriyama.shiga.jp","nagahama.shiga.jp","nishiazai.shiga.jp","notogawa.shiga.jp","omihachiman.shiga.jp","otsu.shiga.jp","ritto.shiga.jp","ryuoh.shiga.jp","takashima.shiga.jp","takatsuki.shiga.jp","torahime.shiga.jp","toyosato.shiga.jp","yasu.shiga.jp","akagi.shimane.jp","ama.shimane.jp","gotsu.shimane.jp","hamada.shimane.jp","higashiizumo.shimane.jp","hikawa.shimane.jp","hikimi.shimane.jp","izumo.shimane.jp","kakinoki.shimane.jp","masuda.shimane.jp","matsue.shimane.jp","misato.shimane.jp","nishinoshima.shimane.jp","ohda.shimane.jp","okinoshima.shimane.jp","okuizumo.shimane.jp","shimane.shimane.jp","tamayu.shimane.jp","tsuwano.shimane.jp","unnan.shimane.jp","yakumo.shimane.jp","yasugi.shimane.jp","yatsuka.shimane.jp","arai.shizuoka.jp","atami.shizuoka.jp","fuji.shizuoka.jp","fujieda.shizuoka.jp","fujikawa.shizuoka.jp","fujinomiya.shizuoka.jp","fukuroi.shizuoka.jp","gotemba.shizuoka.jp","haibara.shizuoka.jp","hamamatsu.shizuoka.jp","higashiizu.shizuoka.jp","ito.shizuoka.jp","iwata.shizuoka.jp","izu.shizuoka.jp","izunokuni.shizuoka.jp","kakegawa.shizuoka.jp","kannami.shizuoka.jp","kawanehon.shizuoka.jp","kawazu.shizuoka.jp","kikugawa.shizuoka.jp","kosai.shizuoka.jp","makinohara.shizuoka.jp","matsuzaki.shizuoka.jp","minamiizu.shizuoka.jp","mishima.shizuoka.jp","morimachi.shizuoka.jp","nishiizu.shizuoka.jp","numazu.shizuoka.jp","omaezaki.shizuoka.jp","shimada.shizuoka.jp","shimizu.shizuoka.jp","shimoda.shizuoka.jp","shizuoka.shizuoka.jp","susono.shizuoka.jp","yaizu.shizuoka.jp","yoshida.shizuoka.jp","ashikaga.tochigi.jp","bato.tochigi.jp","haga.tochigi.jp","ichikai.tochigi.jp","iwafune.tochigi.jp","kaminokawa.tochigi.jp","kanuma.tochigi.jp","karasuyama.tochigi.jp","kuroiso.tochigi.jp","mashiko.tochigi.jp","mibu.tochigi.jp","moka.tochigi.jp","motegi.tochigi.jp","nasu.tochigi.jp","nasushiobara.tochigi.jp","nikko.tochigi.jp","nishikata.tochigi.jp","nogi.tochigi.jp","ohira.tochigi.jp","ohtawara.tochigi.jp","oyama.tochigi.jp","sakura.tochigi.jp","sano.tochigi.jp","shimotsuke.tochigi.jp","shioya.tochigi.jp","takanezawa.tochigi.jp","tochigi.tochigi.jp","tsuga.tochigi.jp","ujiie.tochigi.jp","utsunomiya.tochigi.jp","yaita.tochigi.jp","aizumi.tokushima.jp","anan.tokushima.jp","ichiba.tokushima.jp","itano.tokushima.jp","kainan.tokushima.jp","komatsushima.tokushima.jp","matsushige.tokushima.jp","mima.tokushima.jp","minami.tokushima.jp","miyoshi.tokushima.jp","mugi.tokushima.jp","nakagawa.tokushima.jp","naruto.tokushima.jp","sanagochi.tokushima.jp","shishikui.tokushima.jp","tokushima.tokushima.jp","wajiki.tokushima.jp","adachi.tokyo.jp","akiruno.tokyo.jp","akishima.tokyo.jp","aogashima.tokyo.jp","arakawa.tokyo.jp","bunkyo.tokyo.jp","chiyoda.tokyo.jp","chofu.tokyo.jp","chuo.tokyo.jp","edogawa.tokyo.jp","fuchu.tokyo.jp","fussa.tokyo.jp","hachijo.tokyo.jp","hachioji.tokyo.jp","hamura.tokyo.jp","higashikurume.tokyo.jp","higashimurayama.tokyo.jp","higashiyamato.tokyo.jp","hino.tokyo.jp","hinode.tokyo.jp","hinohara.tokyo.jp","inagi.tokyo.jp","itabashi.tokyo.jp","katsushika.tokyo.jp","kita.tokyo.jp","kiyose.tokyo.jp","kodaira.tokyo.jp","koganei.tokyo.jp","kokubunji.tokyo.jp","komae.tokyo.jp","koto.tokyo.jp","kouzushima.tokyo.jp","kunitachi.tokyo.jp","machida.tokyo.jp","meguro.tokyo.jp","minato.tokyo.jp","mitaka.tokyo.jp","mizuho.tokyo.jp","musashimurayama.tokyo.jp","musashino.tokyo.jp","nakano.tokyo.jp","nerima.tokyo.jp","ogasawara.tokyo.jp","okutama.tokyo.jp","ome.tokyo.jp","oshima.tokyo.jp","ota.tokyo.jp","setagaya.tokyo.jp","shibuya.tokyo.jp","shinagawa.tokyo.jp","shinjuku.tokyo.jp","suginami.tokyo.jp","sumida.tokyo.jp","tachikawa.tokyo.jp","taito.tokyo.jp","tama.tokyo.jp","toshima.tokyo.jp","chizu.tottori.jp","hino.tottori.jp","kawahara.tottori.jp","koge.tottori.jp","kotoura.tottori.jp","misasa.tottori.jp","nanbu.tottori.jp","nichinan.tottori.jp","sakaiminato.tottori.jp","tottori.tottori.jp","wakasa.tottori.jp","yazu.tottori.jp","yonago.tottori.jp","asahi.toyama.jp","fuchu.toyama.jp","fukumitsu.toyama.jp","funahashi.toyama.jp","himi.toyama.jp","imizu.toyama.jp","inami.toyama.jp","johana.toyama.jp","kamiichi.toyama.jp","kurobe.toyama.jp","nakaniikawa.toyama.jp","namerikawa.toyama.jp","nanto.toyama.jp","nyuzen.toyama.jp","oyabe.toyama.jp","taira.toyama.jp","takaoka.toyama.jp","tateyama.toyama.jp","toga.toyama.jp","tonami.toyama.jp","toyama.toyama.jp","unazuki.toyama.jp","uozu.toyama.jp","yamada.toyama.jp","arida.wakayama.jp","aridagawa.wakayama.jp","gobo.wakayama.jp","hashimoto.wakayama.jp","hidaka.wakayama.jp","hirogawa.wakayama.jp","inami.wakayama.jp","iwade.wakayama.jp","kainan.wakayama.jp","kamitonda.wakayama.jp","katsuragi.wakayama.jp","kimino.wakayama.jp","kinokawa.wakayama.jp","kitayama.wakayama.jp","koya.wakayama.jp","koza.wakayama.jp","kozagawa.wakayama.jp","kudoyama.wakayama.jp","kushimoto.wakayama.jp","mihama.wakayama.jp","misato.wakayama.jp","nachikatsuura.wakayama.jp","shingu.wakayama.jp","shirahama.wakayama.jp","taiji.wakayama.jp","tanabe.wakayama.jp","wakayama.wakayama.jp","yuasa.wakayama.jp","yura.wakayama.jp","asahi.yamagata.jp","funagata.yamagata.jp","higashine.yamagata.jp","iide.yamagata.jp","kahoku.yamagata.jp","kaminoyama.yamagata.jp","kaneyama.yamagata.jp","kawanishi.yamagata.jp","mamurogawa.yamagata.jp","mikawa.yamagata.jp","murayama.yamagata.jp","nagai.yamagata.jp","nakayama.yamagata.jp","nanyo.yamagata.jp","nishikawa.yamagata.jp","obanazawa.yamagata.jp","oe.yamagata.jp","oguni.yamagata.jp","ohkura.yamagata.jp","oishida.yamagata.jp","sagae.yamagata.jp","sakata.yamagata.jp","sakegawa.yamagata.jp","shinjo.yamagata.jp","shirataka.yamagata.jp","shonai.yamagata.jp","takahata.yamagata.jp","tendo.yamagata.jp","tozawa.yamagata.jp","tsuruoka.yamagata.jp","yamagata.yamagata.jp","yamanobe.yamagata.jp","yonezawa.yamagata.jp","yuza.yamagata.jp","abu.yamaguchi.jp","hagi.yamaguchi.jp","hikari.yamaguchi.jp","hofu.yamaguchi.jp","iwakuni.yamaguchi.jp","kudamatsu.yamaguchi.jp","mitou.yamaguchi.jp","nagato.yamaguchi.jp","oshima.yamaguchi.jp","shimonoseki.yamaguchi.jp","shunan.yamaguchi.jp","tabuse.yamaguchi.jp","tokuyama.yamaguchi.jp","toyota.yamaguchi.jp","ube.yamaguchi.jp","yuu.yamaguchi.jp","chuo.yamanashi.jp","doshi.yamanashi.jp","fuefuki.yamanashi.jp","fujikawa.yamanashi.jp","fujikawaguchiko.yamanashi.jp","fujiyoshida.yamanashi.jp","hayakawa.yamanashi.jp","hokuto.yamanashi.jp","ichikawamisato.yamanashi.jp","kai.yamanashi.jp","kofu.yamanashi.jp","koshu.yamanashi.jp","kosuge.yamanashi.jp","minami-alps.yamanashi.jp","minobu.yamanashi.jp","nakamichi.yamanashi.jp","nanbu.yamanashi.jp","narusawa.yamanashi.jp","nirasaki.yamanashi.jp","nishikatsura.yamanashi.jp","oshino.yamanashi.jp","otsuki.yamanashi.jp","showa.yamanashi.jp","tabayama.yamanashi.jp","tsuru.yamanashi.jp","uenohara.yamanashi.jp","yamanakako.yamanashi.jp","yamanashi.yamanashi.jp","ke","ac.ke","co.ke","go.ke","info.ke","me.ke","mobi.ke","ne.ke","or.ke","sc.ke","kg","org.kg","net.kg","com.kg","edu.kg","gov.kg","mil.kg","*.kh","ki","edu.ki","biz.ki","net.ki","org.ki","gov.ki","info.ki","com.ki","km","org.km","nom.km","gov.km","prd.km","tm.km","edu.km","mil.km","ass.km","com.km","coop.km","asso.km","presse.km","medecin.km","notaires.km","pharmaciens.km","veterinaire.km","gouv.km","kn","net.kn","org.kn","edu.kn","gov.kn","kp","com.kp","edu.kp","gov.kp","org.kp","rep.kp","tra.kp","kr","ac.kr","co.kr","es.kr","go.kr","hs.kr","kg.kr","mil.kr","ms.kr","ne.kr","or.kr","pe.kr","re.kr","sc.kr","busan.kr","chungbuk.kr","chungnam.kr","daegu.kr","daejeon.kr","gangwon.kr","gwangju.kr","gyeongbuk.kr","gyeonggi.kr","gyeongnam.kr","incheon.kr","jeju.kr","jeonbuk.kr","jeonnam.kr","seoul.kr","ulsan.kr","kw","com.kw","edu.kw","emb.kw","gov.kw","ind.kw","net.kw","org.kw","ky","edu.ky","gov.ky","com.ky","org.ky","net.ky","kz","org.kz","edu.kz","net.kz","gov.kz","mil.kz","com.kz","la","int.la","net.la","info.la","edu.la","gov.la","per.la","com.la","org.la","lb","com.lb","edu.lb","gov.lb","net.lb","org.lb","lc","com.lc","net.lc","co.lc","org.lc","edu.lc","gov.lc","li","lk","gov.lk","sch.lk","net.lk","int.lk","com.lk","org.lk","edu.lk","ngo.lk","soc.lk","web.lk","ltd.lk","assn.lk","grp.lk","hotel.lk","ac.lk","lr","com.lr","edu.lr","gov.lr","org.lr","net.lr","ls","co.ls","org.ls","lt","gov.lt","lu","lv","com.lv","edu.lv","gov.lv","org.lv","mil.lv","id.lv","net.lv","asn.lv","conf.lv","ly","com.ly","net.ly","gov.ly","plc.ly","edu.ly","sch.ly","med.ly","org.ly","id.ly","ma","co.ma","net.ma","gov.ma","org.ma","ac.ma","press.ma","mc","tm.mc","asso.mc","md","me","co.me","net.me","org.me","edu.me","ac.me","gov.me","its.me","priv.me","mg","org.mg","nom.mg","gov.mg","prd.mg","tm.mg","edu.mg","mil.mg","com.mg","co.mg","mh","mil","mk","com.mk","org.mk","net.mk","edu.mk","gov.mk","inf.mk","name.mk","ml","com.ml","edu.ml","gouv.ml","gov.ml","net.ml","org.ml","presse.ml","*.mm","mn","gov.mn","edu.mn","org.mn","mo","com.mo","net.mo","org.mo","edu.mo","gov.mo","mobi","mp","mq","mr","gov.mr","ms","com.ms","edu.ms","gov.ms","net.ms","org.ms","mt","com.mt","edu.mt","net.mt","org.mt","mu","com.mu","net.mu","org.mu","gov.mu","ac.mu","co.mu","or.mu","museum","academy.museum","agriculture.museum","air.museum","airguard.museum","alabama.museum","alaska.museum","amber.museum","ambulance.museum","american.museum","americana.museum","americanantiques.museum","americanart.museum","amsterdam.museum","and.museum","annefrank.museum","anthro.museum","anthropology.museum","antiques.museum","aquarium.museum","arboretum.museum","archaeological.museum","archaeology.museum","architecture.museum","art.museum","artanddesign.museum","artcenter.museum","artdeco.museum","arteducation.museum","artgallery.museum","arts.museum","artsandcrafts.museum","asmatart.museum","assassination.museum","assisi.museum","association.museum","astronomy.museum","atlanta.museum","austin.museum","australia.museum","automotive.museum","aviation.museum","axis.museum","badajoz.museum","baghdad.museum","bahn.museum","bale.museum","baltimore.museum","barcelona.museum","baseball.museum","basel.museum","baths.museum","bauern.museum","beauxarts.museum","beeldengeluid.museum","bellevue.museum","bergbau.museum","berkeley.museum","berlin.museum","bern.museum","bible.museum","bilbao.museum","bill.museum","birdart.museum","birthplace.museum","bonn.museum","boston.museum","botanical.museum","botanicalgarden.museum","botanicgarden.museum","botany.museum","brandywinevalley.museum","brasil.museum","bristol.museum","british.museum","britishcolumbia.museum","broadcast.museum","brunel.museum","brussel.museum","brussels.museum","bruxelles.museum","building.museum","burghof.museum","bus.museum","bushey.museum","cadaques.museum","california.museum","cambridge.museum","can.museum","canada.museum","capebreton.museum","carrier.museum","cartoonart.museum","casadelamoneda.museum","castle.museum","castres.museum","celtic.museum","center.museum","chattanooga.museum","cheltenham.museum","chesapeakebay.museum","chicago.museum","children.museum","childrens.museum","childrensgarden.museum","chiropractic.museum","chocolate.museum","christiansburg.museum","cincinnati.museum","cinema.museum","circus.museum","civilisation.museum","civilization.museum","civilwar.museum","clinton.museum","clock.museum","coal.museum","coastaldefence.museum","cody.museum","coldwar.museum","collection.museum","colonialwilliamsburg.museum","coloradoplateau.museum","columbia.museum","columbus.museum","communication.museum","communications.museum","community.museum","computer.museum","computerhistory.museum","comunicações.museum","contemporary.museum","contemporaryart.museum","convent.museum","copenhagen.museum","corporation.museum","correios-e-telecomunicações.museum","corvette.museum","costume.museum","countryestate.museum","county.museum","crafts.museum","cranbrook.museum","creation.museum","cultural.museum","culturalcenter.museum","culture.museum","cyber.museum","cymru.museum","dali.museum","dallas.museum","database.museum","ddr.museum","decorativearts.museum","delaware.museum","delmenhorst.museum","denmark.museum","depot.museum","design.museum","detroit.museum","dinosaur.museum","discovery.museum","dolls.museum","donostia.museum","durham.museum","eastafrica.museum","eastcoast.museum","education.museum","educational.museum","egyptian.museum","eisenbahn.museum","elburg.museum","elvendrell.museum","embroidery.museum","encyclopedic.museum","england.museum","entomology.museum","environment.museum","environmentalconservation.museum","epilepsy.museum","essex.museum","estate.museum","ethnology.museum","exeter.museum","exhibition.museum","family.museum","farm.museum","farmequipment.museum","farmers.museum","farmstead.museum","field.museum","figueres.museum","filatelia.museum","film.museum","fineart.museum","finearts.museum","finland.museum","flanders.museum","florida.museum","force.museum","fortmissoula.museum","fortworth.museum","foundation.museum","francaise.museum","frankfurt.museum","franziskaner.museum","freemasonry.museum","freiburg.museum","fribourg.museum","frog.museum","fundacio.museum","furniture.museum","gallery.museum","garden.museum","gateway.museum","geelvinck.museum","gemological.museum","geology.museum","georgia.museum","giessen.museum","glas.museum","glass.museum","gorge.museum","grandrapids.museum","graz.museum","guernsey.museum","halloffame.museum","hamburg.museum","handson.museum","harvestcelebration.museum","hawaii.museum","health.museum","heimatunduhren.museum","hellas.museum","helsinki.museum","hembygdsforbund.museum","heritage.museum","histoire.museum","historical.museum","historicalsociety.museum","historichouses.museum","historisch.museum","historisches.museum","history.museum","historyofscience.museum","horology.museum","house.museum","humanities.museum","illustration.museum","imageandsound.museum","indian.museum","indiana.museum","indianapolis.museum","indianmarket.museum","intelligence.museum","interactive.museum","iraq.museum","iron.museum","isleofman.museum","jamison.museum","jefferson.museum","jerusalem.museum","jewelry.museum","jewish.museum","jewishart.museum","jfk.museum","journalism.museum","judaica.museum","judygarland.museum","juedisches.museum","juif.museum","karate.museum","karikatur.museum","kids.museum","koebenhavn.museum","koeln.museum","kunst.museum","kunstsammlung.museum","kunstunddesign.museum","labor.museum","labour.museum","lajolla.museum","lancashire.museum","landes.museum","lans.museum","läns.museum","larsson.museum","lewismiller.museum","lincoln.museum","linz.museum","living.museum","livinghistory.museum","localhistory.museum","london.museum","losangeles.museum","louvre.museum","loyalist.museum","lucerne.museum","luxembourg.museum","luzern.museum","mad.museum","madrid.museum","mallorca.museum","manchester.museum","mansion.museum","mansions.museum","manx.museum","marburg.museum","maritime.museum","maritimo.museum","maryland.museum","marylhurst.museum","media.museum","medical.museum","medizinhistorisches.museum","meeres.museum","memorial.museum","mesaverde.museum","michigan.museum","midatlantic.museum","military.museum","mill.museum","miners.museum","mining.museum","minnesota.museum","missile.museum","missoula.museum","modern.museum","moma.museum","money.museum","monmouth.museum","monticello.museum","montreal.museum","moscow.museum","motorcycle.museum","muenchen.museum","muenster.museum","mulhouse.museum","muncie.museum","museet.museum","museumcenter.museum","museumvereniging.museum","music.museum","national.museum","nationalfirearms.museum","nationalheritage.museum","nativeamerican.museum","naturalhistory.museum","naturalhistorymuseum.museum","naturalsciences.museum","nature.museum","naturhistorisches.museum","natuurwetenschappen.museum","naumburg.museum","naval.museum","nebraska.museum","neues.museum","newhampshire.museum","newjersey.museum","newmexico.museum","newport.museum","newspaper.museum","newyork.museum","niepce.museum","norfolk.museum","north.museum","nrw.museum","nuernberg.museum","nuremberg.museum","nyc.museum","nyny.museum","oceanographic.museum","oceanographique.museum","omaha.museum","online.museum","ontario.museum","openair.museum","oregon.museum","oregontrail.museum","otago.museum","oxford.museum","pacific.museum","paderborn.museum","palace.museum","paleo.museum","palmsprings.museum","panama.museum","paris.museum","pasadena.museum","pharmacy.museum","philadelphia.museum","philadelphiaarea.museum","philately.museum","phoenix.museum","photography.museum","pilots.museum","pittsburgh.museum","planetarium.museum","plantation.museum","plants.museum","plaza.museum","portal.museum","portland.museum","portlligat.museum","posts-and-telecommunications.museum","preservation.museum","presidio.museum","press.museum","project.museum","public.museum","pubol.museum","quebec.museum","railroad.museum","railway.museum","research.museum","resistance.museum","riodejaneiro.museum","rochester.museum","rockart.museum","roma.museum","russia.museum","saintlouis.museum","salem.museum","salvadordali.museum","salzburg.museum","sandiego.museum","sanfrancisco.museum","santabarbara.museum","santacruz.museum","santafe.museum","saskatchewan.museum","satx.museum","savannahga.museum","schlesisches.museum","schoenbrunn.museum","schokoladen.museum","school.museum","schweiz.museum","science.museum","scienceandhistory.museum","scienceandindustry.museum","sciencecenter.museum","sciencecenters.museum","science-fiction.museum","sciencehistory.museum","sciences.museum","sciencesnaturelles.museum","scotland.museum","seaport.museum","settlement.museum","settlers.museum","shell.museum","sherbrooke.museum","sibenik.museum","silk.museum","ski.museum","skole.museum","society.museum","sologne.museum","soundandvision.museum","southcarolina.museum","southwest.museum","space.museum","spy.museum","square.museum","stadt.museum","stalbans.museum","starnberg.museum","state.museum","stateofdelaware.museum","station.museum","steam.museum","steiermark.museum","stjohn.museum","stockholm.museum","stpetersburg.museum","stuttgart.museum","suisse.museum","surgeonshall.museum","surrey.museum","svizzera.museum","sweden.museum","sydney.museum","tank.museum","tcm.museum","technology.museum","telekommunikation.museum","television.museum","texas.museum","textile.museum","theater.museum","time.museum","timekeeping.museum","topology.museum","torino.museum","touch.museum","town.museum","transport.museum","tree.museum","trolley.museum","trust.museum","trustee.museum","uhren.museum","ulm.museum","undersea.museum","university.museum","usa.museum","usantiques.museum","usarts.museum","uscountryestate.museum","usculture.museum","usdecorativearts.museum","usgarden.museum","ushistory.museum","ushuaia.museum","uslivinghistory.museum","utah.museum","uvic.museum","valley.museum","vantaa.museum","versailles.museum","viking.museum","village.museum","virginia.museum","virtual.museum","virtuel.museum","vlaanderen.museum","volkenkunde.museum","wales.museum","wallonie.museum","war.museum","washingtondc.museum","watchandclock.museum","watch-and-clock.museum","western.museum","westfalen.museum","whaling.museum","wildlife.museum","williamsburg.museum","windmill.museum","workshop.museum","york.museum","yorkshire.museum","yosemite.museum","youth.museum","zoological.museum","zoology.museum","ירושלים.museum","иком.museum","mv","aero.mv","biz.mv","com.mv","coop.mv","edu.mv","gov.mv","info.mv","int.mv","mil.mv","museum.mv","name.mv","net.mv","org.mv","pro.mv","mw","ac.mw","biz.mw","co.mw","com.mw","coop.mw","edu.mw","gov.mw","int.mw","museum.mw","net.mw","org.mw","mx","com.mx","org.mx","gob.mx","edu.mx","net.mx","my","com.my","net.my","org.my","gov.my","edu.my","mil.my","name.my","mz","ac.mz","adv.mz","co.mz","edu.mz","gov.mz","mil.mz","net.mz","org.mz","na","info.na","pro.na","name.na","school.na","or.na","dr.na","us.na","mx.na","ca.na","in.na","cc.na","tv.na","ws.na","mobi.na","co.na","com.na","org.na","name","nc","asso.nc","nom.nc","ne","net","nf","com.nf","net.nf","per.nf","rec.nf","web.nf","arts.nf","firm.nf","info.nf","other.nf","store.nf","ng","com.ng","edu.ng","gov.ng","i.ng","mil.ng","mobi.ng","name.ng","net.ng","org.ng","sch.ng","ni","ac.ni","biz.ni","co.ni","com.ni","edu.ni","gob.ni","in.ni","info.ni","int.ni","mil.ni","net.ni","nom.ni","org.ni","web.ni","nl","bv.nl","no","fhs.no","vgs.no","fylkesbibl.no","folkebibl.no","museum.no","idrett.no","priv.no","mil.no","stat.no","dep.no","kommune.no","herad.no","aa.no","ah.no","bu.no","fm.no","hl.no","hm.no","jan-mayen.no","mr.no","nl.no","nt.no","of.no","ol.no","oslo.no","rl.no","sf.no","st.no","svalbard.no","tm.no","tr.no","va.no","vf.no","gs.aa.no","gs.ah.no","gs.bu.no","gs.fm.no","gs.hl.no","gs.hm.no","gs.jan-mayen.no","gs.mr.no","gs.nl.no","gs.nt.no","gs.of.no","gs.ol.no","gs.oslo.no","gs.rl.no","gs.sf.no","gs.st.no","gs.svalbard.no","gs.tm.no","gs.tr.no","gs.va.no","gs.vf.no","akrehamn.no","åkrehamn.no","algard.no","ålgård.no","arna.no","brumunddal.no","bryne.no","bronnoysund.no","brønnøysund.no","drobak.no","drøbak.no","egersund.no","fetsund.no","floro.no","florø.no","fredrikstad.no","hokksund.no","honefoss.no","hønefoss.no","jessheim.no","jorpeland.no","jørpeland.no","kirkenes.no","kopervik.no","krokstadelva.no","langevag.no","langevåg.no","leirvik.no","mjondalen.no","mjøndalen.no","mo-i-rana.no","mosjoen.no","mosjøen.no","nesoddtangen.no","orkanger.no","osoyro.no","osøyro.no","raholt.no","råholt.no","sandnessjoen.no","sandnessjøen.no","skedsmokorset.no","slattum.no","spjelkavik.no","stathelle.no","stavern.no","stjordalshalsen.no","stjørdalshalsen.no","tananger.no","tranby.no","vossevangen.no","afjord.no","åfjord.no","agdenes.no","al.no","ål.no","alesund.no","ålesund.no","alstahaug.no","alta.no","áltá.no","alaheadju.no","álaheadju.no","alvdal.no","amli.no","åmli.no","amot.no","åmot.no","andebu.no","andoy.no","andøy.no","andasuolo.no","ardal.no","årdal.no","aremark.no","arendal.no","ås.no","aseral.no","åseral.no","asker.no","askim.no","askvoll.no","askoy.no","askøy.no","asnes.no","åsnes.no","audnedaln.no","aukra.no","aure.no","aurland.no","aurskog-holand.no","aurskog-høland.no","austevoll.no","austrheim.no","averoy.no","averøy.no","balestrand.no","ballangen.no","balat.no","bálát.no","balsfjord.no","bahccavuotna.no","báhccavuotna.no","bamble.no","bardu.no","beardu.no","beiarn.no","bajddar.no","bájddar.no","baidar.no","báidár.no","berg.no","bergen.no","berlevag.no","berlevåg.no","bearalvahki.no","bearalváhki.no","bindal.no","birkenes.no","bjarkoy.no","bjarkøy.no","bjerkreim.no","bjugn.no","bodo.no","bodø.no","badaddja.no","bådåddjå.no","budejju.no","bokn.no","bremanger.no","bronnoy.no","brønnøy.no","bygland.no","bykle.no","barum.no","bærum.no","bo.telemark.no","bø.telemark.no","bo.nordland.no","bø.nordland.no","bievat.no","bievát.no","bomlo.no","bømlo.no","batsfjord.no","båtsfjord.no","bahcavuotna.no","báhcavuotna.no","dovre.no","drammen.no","drangedal.no","dyroy.no","dyrøy.no","donna.no","dønna.no","eid.no","eidfjord.no","eidsberg.no","eidskog.no","eidsvoll.no","eigersund.no","elverum.no","enebakk.no","engerdal.no","etne.no","etnedal.no","evenes.no","evenassi.no","evenášši.no","evje-og-hornnes.no","farsund.no","fauske.no","fuossko.no","fuoisku.no","fedje.no","fet.no","finnoy.no","finnøy.no","fitjar.no","fjaler.no","fjell.no","flakstad.no","flatanger.no","flekkefjord.no","flesberg.no","flora.no","fla.no","flå.no","folldal.no","forsand.no","fosnes.no","frei.no","frogn.no","froland.no","frosta.no","frana.no","fræna.no","froya.no","frøya.no","fusa.no","fyresdal.no","forde.no","førde.no","gamvik.no","gangaviika.no","gáŋgaviika.no","gaular.no","gausdal.no","gildeskal.no","gildeskål.no","giske.no","gjemnes.no","gjerdrum.no","gjerstad.no","gjesdal.no","gjovik.no","gjøvik.no","gloppen.no","gol.no","gran.no","grane.no","granvin.no","gratangen.no","grimstad.no","grong.no","kraanghke.no","kråanghke.no","grue.no","gulen.no","hadsel.no","halden.no","halsa.no","hamar.no","hamaroy.no","habmer.no","hábmer.no","hapmir.no","hápmir.no","hammerfest.no","hammarfeasta.no","hámmárfeasta.no","haram.no","hareid.no","harstad.no","hasvik.no","aknoluokta.no","ákŋoluokta.no","hattfjelldal.no","aarborte.no","haugesund.no","hemne.no","hemnes.no","hemsedal.no","heroy.more-og-romsdal.no","herøy.møre-og-romsdal.no","heroy.nordland.no","herøy.nordland.no","hitra.no","hjartdal.no","hjelmeland.no","hobol.no","hobøl.no","hof.no","hol.no","hole.no","holmestrand.no","holtalen.no","holtålen.no","hornindal.no","horten.no","hurdal.no","hurum.no","hvaler.no","hyllestad.no","hagebostad.no","hægebostad.no","hoyanger.no","høyanger.no","hoylandet.no","høylandet.no","ha.no","hå.no","ibestad.no","inderoy.no","inderøy.no","iveland.no","jevnaker.no","jondal.no","jolster.no","jølster.no","karasjok.no","karasjohka.no","kárášjohka.no","karlsoy.no","galsa.no","gálsá.no","karmoy.no","karmøy.no","kautokeino.no","guovdageaidnu.no","klepp.no","klabu.no","klæbu.no","kongsberg.no","kongsvinger.no","kragero.no","kragerø.no","kristiansand.no","kristiansund.no","krodsherad.no","krødsherad.no","kvalsund.no","rahkkeravju.no","ráhkkerávju.no","kvam.no","kvinesdal.no","kvinnherad.no","kviteseid.no","kvitsoy.no","kvitsøy.no","kvafjord.no","kvæfjord.no","giehtavuoatna.no","kvanangen.no","kvænangen.no","navuotna.no","návuotna.no","kafjord.no","kåfjord.no","gaivuotna.no","gáivuotna.no","larvik.no","lavangen.no","lavagis.no","loabat.no","loabát.no","lebesby.no","davvesiida.no","leikanger.no","leirfjord.no","leka.no","leksvik.no","lenvik.no","leangaviika.no","leaŋgaviika.no","lesja.no","levanger.no","lier.no","lierne.no","lillehammer.no","lillesand.no","lindesnes.no","lindas.no","lindås.no","lom.no","loppa.no","lahppi.no","láhppi.no","lund.no","lunner.no","luroy.no","lurøy.no","luster.no","lyngdal.no","lyngen.no","ivgu.no","lardal.no","lerdal.no","lærdal.no","lodingen.no","lødingen.no","lorenskog.no","lørenskog.no","loten.no","løten.no","malvik.no","masoy.no","måsøy.no","muosat.no","muosát.no","mandal.no","marker.no","marnardal.no","masfjorden.no","meland.no","meldal.no","melhus.no","meloy.no","meløy.no","meraker.no","meråker.no","moareke.no","moåreke.no","midsund.no","midtre-gauldal.no","modalen.no","modum.no","molde.no","moskenes.no","moss.no","mosvik.no","malselv.no","målselv.no","malatvuopmi.no","málatvuopmi.no","namdalseid.no","aejrie.no","namsos.no","namsskogan.no","naamesjevuemie.no","nååmesjevuemie.no","laakesvuemie.no","nannestad.no","narvik.no","narviika.no","naustdal.no","nedre-eiker.no","nes.akershus.no","nes.buskerud.no","nesna.no","nesodden.no","nesseby.no","unjarga.no","unjárga.no","nesset.no","nissedal.no","nittedal.no","nord-aurdal.no","nord-fron.no","nord-odal.no","norddal.no","nordkapp.no","davvenjarga.no","davvenjárga.no","nordre-land.no","nordreisa.no","raisa.no","ráisa.no","nore-og-uvdal.no","notodden.no","naroy.no","nærøy.no","notteroy.no","nøtterøy.no","odda.no","oksnes.no","øksnes.no","oppdal.no","oppegard.no","oppegård.no","orkdal.no","orland.no","ørland.no","orskog.no","ørskog.no","orsta.no","ørsta.no","os.hedmark.no","os.hordaland.no","osen.no","osteroy.no","osterøy.no","ostre-toten.no","østre-toten.no","overhalla.no","ovre-eiker.no","øvre-eiker.no","oyer.no","øyer.no","oygarden.no","øygarden.no","oystre-slidre.no","øystre-slidre.no","porsanger.no","porsangu.no","porsáŋgu.no","porsgrunn.no","radoy.no","radøy.no","rakkestad.no","rana.no","ruovat.no","randaberg.no","rauma.no","rendalen.no","rennebu.no","rennesoy.no","rennesøy.no","rindal.no","ringebu.no","ringerike.no","ringsaker.no","rissa.no","risor.no","risør.no","roan.no","rollag.no","rygge.no","ralingen.no","rælingen.no","rodoy.no","rødøy.no","romskog.no","rømskog.no","roros.no","røros.no","rost.no","røst.no","royken.no","røyken.no","royrvik.no","røyrvik.no","rade.no","råde.no","salangen.no","siellak.no","saltdal.no","salat.no","sálát.no","sálat.no","samnanger.no","sande.more-og-romsdal.no","sande.møre-og-romsdal.no","sande.vestfold.no","sandefjord.no","sandnes.no","sandoy.no","sandøy.no","sarpsborg.no","sauda.no","sauherad.no","sel.no","selbu.no","selje.no","seljord.no","sigdal.no","siljan.no","sirdal.no","skaun.no","skedsmo.no","ski.no","skien.no","skiptvet.no","skjervoy.no","skjervøy.no","skierva.no","skiervá.no","skjak.no","skjåk.no","skodje.no","skanland.no","skånland.no","skanit.no","skánit.no","smola.no","smøla.no","snillfjord.no","snasa.no","snåsa.no","snoasa.no","snaase.no","snåase.no","sogndal.no","sokndal.no","sola.no","solund.no","songdalen.no","sortland.no","spydeberg.no","stange.no","stavanger.no","steigen.no","steinkjer.no","stjordal.no","stjørdal.no","stokke.no","stor-elvdal.no","stord.no","stordal.no","storfjord.no","omasvuotna.no","strand.no","stranda.no","stryn.no","sula.no","suldal.no","sund.no","sunndal.no","surnadal.no","sveio.no","svelvik.no","sykkylven.no","sogne.no","søgne.no","somna.no","sømna.no","sondre-land.no","søndre-land.no","sor-aurdal.no","sør-aurdal.no","sor-fron.no","sør-fron.no","sor-odal.no","sør-odal.no","sor-varanger.no","sør-varanger.no","matta-varjjat.no","mátta-várjjat.no","sorfold.no","sørfold.no","sorreisa.no","sørreisa.no","sorum.no","sørum.no","tana.no","deatnu.no","time.no","tingvoll.no","tinn.no","tjeldsund.no","dielddanuorri.no","tjome.no","tjøme.no","tokke.no","tolga.no","torsken.no","tranoy.no","tranøy.no","tromso.no","tromsø.no","tromsa.no","romsa.no","trondheim.no","troandin.no","trysil.no","trana.no","træna.no","trogstad.no","trøgstad.no","tvedestrand.no","tydal.no","tynset.no","tysfjord.no","divtasvuodna.no","divttasvuotna.no","tysnes.no","tysvar.no","tysvær.no","tonsberg.no","tønsberg.no","ullensaker.no","ullensvang.no","ulvik.no","utsira.no","vadso.no","vadsø.no","cahcesuolo.no","čáhcesuolo.no","vaksdal.no","valle.no","vang.no","vanylven.no","vardo.no","vardø.no","varggat.no","várggát.no","vefsn.no","vaapste.no","vega.no","vegarshei.no","vegårshei.no","vennesla.no","verdal.no","verran.no","vestby.no","vestnes.no","vestre-slidre.no","vestre-toten.no","vestvagoy.no","vestvågøy.no","vevelstad.no","vik.no","vikna.no","vindafjord.no","volda.no","voss.no","varoy.no","værøy.no","vagan.no","vågan.no","voagat.no","vagsoy.no","vågsøy.no","vaga.no","vågå.no","valer.ostfold.no","våler.østfold.no","valer.hedmark.no","våler.hedmark.no","*.np","nr","biz.nr","info.nr","gov.nr","edu.nr","org.nr","net.nr","com.nr","nu","nz","ac.nz","co.nz","cri.nz","geek.nz","gen.nz","govt.nz","health.nz","iwi.nz","kiwi.nz","maori.nz","mil.nz","māori.nz","net.nz","org.nz","parliament.nz","school.nz","om","co.om","com.om","edu.om","gov.om","med.om","museum.om","net.om","org.om","pro.om","onion","org","pa","ac.pa","gob.pa","com.pa","org.pa","sld.pa","edu.pa","net.pa","ing.pa","abo.pa","med.pa","nom.pa","pe","edu.pe","gob.pe","nom.pe","mil.pe","org.pe","com.pe","net.pe","pf","com.pf","org.pf","edu.pf","*.pg","ph","com.ph","net.ph","org.ph","gov.ph","edu.ph","ngo.ph","mil.ph","i.ph","pk","com.pk","net.pk","edu.pk","org.pk","fam.pk","biz.pk","web.pk","gov.pk","gob.pk","gok.pk","gon.pk","gop.pk","gos.pk","info.pk","pl","com.pl","net.pl","org.pl","aid.pl","agro.pl","atm.pl","auto.pl","biz.pl","edu.pl","gmina.pl","gsm.pl","info.pl","mail.pl","miasta.pl","media.pl","mil.pl","nieruchomosci.pl","nom.pl","pc.pl","powiat.pl","priv.pl","realestate.pl","rel.pl","sex.pl","shop.pl","sklep.pl","sos.pl","szkola.pl","targi.pl","tm.pl","tourism.pl","travel.pl","turystyka.pl","gov.pl","ap.gov.pl","ic.gov.pl","is.gov.pl","us.gov.pl","kmpsp.gov.pl","kppsp.gov.pl","kwpsp.gov.pl","psp.gov.pl","wskr.gov.pl","kwp.gov.pl","mw.gov.pl","ug.gov.pl","um.gov.pl","umig.gov.pl","ugim.gov.pl","upow.gov.pl","uw.gov.pl","starostwo.gov.pl","pa.gov.pl","po.gov.pl","psse.gov.pl","pup.gov.pl","rzgw.gov.pl","sa.gov.pl","so.gov.pl","sr.gov.pl","wsa.gov.pl","sko.gov.pl","uzs.gov.pl","wiih.gov.pl","winb.gov.pl","pinb.gov.pl","wios.gov.pl","witd.gov.pl","wzmiuw.gov.pl","piw.gov.pl","wiw.gov.pl","griw.gov.pl","wif.gov.pl","oum.gov.pl","sdn.gov.pl","zp.gov.pl","uppo.gov.pl","mup.gov.pl","wuoz.gov.pl","konsulat.gov.pl","oirm.gov.pl","augustow.pl","babia-gora.pl","bedzin.pl","beskidy.pl","bialowieza.pl","bialystok.pl","bielawa.pl","bieszczady.pl","boleslawiec.pl","bydgoszcz.pl","bytom.pl","cieszyn.pl","czeladz.pl","czest.pl","dlugoleka.pl","elblag.pl","elk.pl","glogow.pl","gniezno.pl","gorlice.pl","grajewo.pl","ilawa.pl","jaworzno.pl","jelenia-gora.pl","jgora.pl","kalisz.pl","kazimierz-dolny.pl","karpacz.pl","kartuzy.pl","kaszuby.pl","katowice.pl","kepno.pl","ketrzyn.pl","klodzko.pl","kobierzyce.pl","kolobrzeg.pl","konin.pl","konskowola.pl","kutno.pl","lapy.pl","lebork.pl","legnica.pl","lezajsk.pl","limanowa.pl","lomza.pl","lowicz.pl","lubin.pl","lukow.pl","malbork.pl","malopolska.pl","mazowsze.pl","mazury.pl","mielec.pl","mielno.pl","mragowo.pl","naklo.pl","nowaruda.pl","nysa.pl","olawa.pl","olecko.pl","olkusz.pl","olsztyn.pl","opoczno.pl","opole.pl","ostroda.pl","ostroleka.pl","ostrowiec.pl","ostrowwlkp.pl","pila.pl","pisz.pl","podhale.pl","podlasie.pl","polkowice.pl","pomorze.pl","pomorskie.pl","prochowice.pl","pruszkow.pl","przeworsk.pl","pulawy.pl","radom.pl","rawa-maz.pl","rybnik.pl","rzeszow.pl","sanok.pl","sejny.pl","slask.pl","slupsk.pl","sosnowiec.pl","stalowa-wola.pl","skoczow.pl","starachowice.pl","stargard.pl","suwalki.pl","swidnica.pl","swiebodzin.pl","swinoujscie.pl","szczecin.pl","szczytno.pl","tarnobrzeg.pl","tgory.pl","turek.pl","tychy.pl","ustka.pl","walbrzych.pl","warmia.pl","warszawa.pl","waw.pl","wegrow.pl","wielun.pl","wlocl.pl","wloclawek.pl","wodzislaw.pl","wolomin.pl","wroclaw.pl","zachpomor.pl","zagan.pl","zarow.pl","zgora.pl","zgorzelec.pl","pm","pn","gov.pn","co.pn","org.pn","edu.pn","net.pn","post","pr","com.pr","net.pr","org.pr","gov.pr","edu.pr","isla.pr","pro.pr","biz.pr","info.pr","name.pr","est.pr","prof.pr","ac.pr","pro","aaa.pro","aca.pro","acct.pro","avocat.pro","bar.pro","cpa.pro","eng.pro","jur.pro","law.pro","med.pro","recht.pro","ps","edu.ps","gov.ps","sec.ps","plo.ps","com.ps","org.ps","net.ps","pt","net.pt","gov.pt","org.pt","edu.pt","int.pt","publ.pt","com.pt","nome.pt","pw","co.pw","ne.pw","or.pw","ed.pw","go.pw","belau.pw","py","com.py","coop.py","edu.py","gov.py","mil.py","net.py","org.py","qa","com.qa","edu.qa","gov.qa","mil.qa","name.qa","net.qa","org.qa","sch.qa","re","asso.re","com.re","nom.re","ro","arts.ro","com.ro","firm.ro","info.ro","nom.ro","nt.ro","org.ro","rec.ro","store.ro","tm.ro","www.ro","rs","ac.rs","co.rs","edu.rs","gov.rs","in.rs","org.rs","ru","ac.ru","edu.ru","gov.ru","int.ru","mil.ru","test.ru","rw","gov.rw","net.rw","edu.rw","ac.rw","com.rw","co.rw","int.rw","mil.rw","gouv.rw","sa","com.sa","net.sa","org.sa","gov.sa","med.sa","pub.sa","edu.sa","sch.sa","sb","com.sb","edu.sb","gov.sb","net.sb","org.sb","sc","com.sc","gov.sc","net.sc","org.sc","edu.sc","sd","com.sd","net.sd","org.sd","edu.sd","med.sd","tv.sd","gov.sd","info.sd","se","a.se","ac.se","b.se","bd.se","brand.se","c.se","d.se","e.se","f.se","fh.se","fhsk.se","fhv.se","g.se","h.se","i.se","k.se","komforb.se","kommunalforbund.se","komvux.se","l.se","lanbib.se","m.se","n.se","naturbruksgymn.se","o.se","org.se","p.se","parti.se","pp.se","press.se","r.se","s.se","t.se","tm.se","u.se","w.se","x.se","y.se","z.se","sg","com.sg","net.sg","org.sg","gov.sg","edu.sg","per.sg","sh","com.sh","net.sh","gov.sh","org.sh","mil.sh","si","sj","sk","sl","com.sl","net.sl","edu.sl","gov.sl","org.sl","sm","sn","art.sn","com.sn","edu.sn","gouv.sn","org.sn","perso.sn","univ.sn","so","com.so","net.so","org.so","sr","st","co.st","com.st","consulado.st","edu.st","embaixada.st","gov.st","mil.st","net.st","org.st","principe.st","saotome.st","store.st","su","sv","com.sv","edu.sv","gob.sv","org.sv","red.sv","sx","gov.sx","sy","edu.sy","gov.sy","net.sy","mil.sy","com.sy","org.sy","sz","co.sz","ac.sz","org.sz","tc","td","tel","tf","tg","th","ac.th","co.th","go.th","in.th","mi.th","net.th","or.th","tj","ac.tj","biz.tj","co.tj","com.tj","edu.tj","go.tj","gov.tj","int.tj","mil.tj","name.tj","net.tj","nic.tj","org.tj","test.tj","web.tj","tk","tl","gov.tl","tm","com.tm","co.tm","org.tm","net.tm","nom.tm","gov.tm","mil.tm","edu.tm","tn","com.tn","ens.tn","fin.tn","gov.tn","ind.tn","intl.tn","nat.tn","net.tn","org.tn","info.tn","perso.tn","tourism.tn","edunet.tn","rnrt.tn","rns.tn","rnu.tn","mincom.tn","agrinet.tn","defense.tn","turen.tn","to","com.to","gov.to","net.to","org.to","edu.to","mil.to","tr","com.tr","info.tr","biz.tr","net.tr","org.tr","web.tr","gen.tr","tv.tr","av.tr","dr.tr","bbs.tr","name.tr","tel.tr","gov.tr","bel.tr","pol.tr","mil.tr","k12.tr","edu.tr","kep.tr","nc.tr","gov.nc.tr","tt","co.tt","com.tt","org.tt","net.tt","biz.tt","info.tt","pro.tt","int.tt","coop.tt","jobs.tt","mobi.tt","travel.tt","museum.tt","aero.tt","name.tt","gov.tt","edu.tt","tv","tw","edu.tw","gov.tw","mil.tw","com.tw","net.tw","org.tw","idv.tw","game.tw","ebiz.tw","club.tw","網路.tw","組織.tw","商業.tw","tz","ac.tz","co.tz","go.tz","hotel.tz","info.tz","me.tz","mil.tz","mobi.tz","ne.tz","or.tz","sc.tz","tv.tz","ua","com.ua","edu.ua","gov.ua","in.ua","net.ua","org.ua","cherkassy.ua","cherkasy.ua","chernigov.ua","chernihiv.ua","chernivtsi.ua","chernovtsy.ua","ck.ua","cn.ua","cr.ua","crimea.ua","cv.ua","dn.ua","dnepropetrovsk.ua","dnipropetrovsk.ua","dominic.ua","donetsk.ua","dp.ua","if.ua","ivano-frankivsk.ua","kh.ua","kharkiv.ua","kharkov.ua","kherson.ua","khmelnitskiy.ua","khmelnytskyi.ua","kiev.ua","kirovograd.ua","km.ua","kr.ua","krym.ua","ks.ua","kv.ua","kyiv.ua","lg.ua","lt.ua","lugansk.ua","lutsk.ua","lv.ua","lviv.ua","mk.ua","mykolaiv.ua","nikolaev.ua","od.ua","odesa.ua","odessa.ua","pl.ua","poltava.ua","rivne.ua","rovno.ua","rv.ua","sb.ua","sebastopol.ua","sevastopol.ua","sm.ua","sumy.ua","te.ua","ternopil.ua","uz.ua","uzhgorod.ua","vinnica.ua","vinnytsia.ua","vn.ua","volyn.ua","yalta.ua","zaporizhzhe.ua","zaporizhzhia.ua","zhitomir.ua","zhytomyr.ua","zp.ua","zt.ua","ug","co.ug","or.ug","ac.ug","sc.ug","go.ug","ne.ug","com.ug","org.ug","uk","ac.uk","co.uk","gov.uk","ltd.uk","me.uk","net.uk","nhs.uk","org.uk","plc.uk","police.uk","*.sch.uk","us","dni.us","fed.us","isa.us","kids.us","nsn.us","ak.us","al.us","ar.us","as.us","az.us","ca.us","co.us","ct.us","dc.us","de.us","fl.us","ga.us","gu.us","hi.us","ia.us","id.us","il.us","in.us","ks.us","ky.us","la.us","ma.us","md.us","me.us","mi.us","mn.us","mo.us","ms.us","mt.us","nc.us","nd.us","ne.us","nh.us","nj.us","nm.us","nv.us","ny.us","oh.us","ok.us","or.us","pa.us","pr.us","ri.us","sc.us","sd.us","tn.us","tx.us","ut.us","vi.us","vt.us","va.us","wa.us","wi.us","wv.us","wy.us","k12.ak.us","k12.al.us","k12.ar.us","k12.as.us","k12.az.us","k12.ca.us","k12.co.us","k12.ct.us","k12.dc.us","k12.de.us","k12.fl.us","k12.ga.us","k12.gu.us","k12.ia.us","k12.id.us","k12.il.us","k12.in.us","k12.ks.us","k12.ky.us","k12.la.us","k12.ma.us","k12.md.us","k12.me.us","k12.mi.us","k12.mn.us","k12.mo.us","k12.ms.us","k12.mt.us","k12.nc.us","k12.ne.us","k12.nh.us","k12.nj.us","k12.nm.us","k12.nv.us","k12.ny.us","k12.oh.us","k12.ok.us","k12.or.us","k12.pa.us","k12.pr.us","k12.ri.us","k12.sc.us","k12.tn.us","k12.tx.us","k12.ut.us","k12.vi.us","k12.vt.us","k12.va.us","k12.wa.us","k12.wi.us","k12.wy.us","cc.ak.us","cc.al.us","cc.ar.us","cc.as.us","cc.az.us","cc.ca.us","cc.co.us","cc.ct.us","cc.dc.us","cc.de.us","cc.fl.us","cc.ga.us","cc.gu.us","cc.hi.us","cc.ia.us","cc.id.us","cc.il.us","cc.in.us","cc.ks.us","cc.ky.us","cc.la.us","cc.ma.us","cc.md.us","cc.me.us","cc.mi.us","cc.mn.us","cc.mo.us","cc.ms.us","cc.mt.us","cc.nc.us","cc.nd.us","cc.ne.us","cc.nh.us","cc.nj.us","cc.nm.us","cc.nv.us","cc.ny.us","cc.oh.us","cc.ok.us","cc.or.us","cc.pa.us","cc.pr.us","cc.ri.us","cc.sc.us","cc.sd.us","cc.tn.us","cc.tx.us","cc.ut.us","cc.vi.us","cc.vt.us","cc.va.us","cc.wa.us","cc.wi.us","cc.wv.us","cc.wy.us","lib.ak.us","lib.al.us","lib.ar.us","lib.as.us","lib.az.us","lib.ca.us","lib.co.us","lib.ct.us","lib.dc.us","lib.fl.us","lib.ga.us","lib.gu.us","lib.hi.us","lib.ia.us","lib.id.us","lib.il.us","lib.in.us","lib.ks.us","lib.ky.us","lib.la.us","lib.ma.us","lib.md.us","lib.me.us","lib.mi.us","lib.mn.us","lib.mo.us","lib.ms.us","lib.mt.us","lib.nc.us","lib.nd.us","lib.ne.us","lib.nh.us","lib.nj.us","lib.nm.us","lib.nv.us","lib.ny.us","lib.oh.us","lib.ok.us","lib.or.us","lib.pa.us","lib.pr.us","lib.ri.us","lib.sc.us","lib.sd.us","lib.tn.us","lib.tx.us","lib.ut.us","lib.vi.us","lib.vt.us","lib.va.us","lib.wa.us","lib.wi.us","lib.wy.us","pvt.k12.ma.us","chtr.k12.ma.us","paroch.k12.ma.us","ann-arbor.mi.us","cog.mi.us","dst.mi.us","eaton.mi.us","gen.mi.us","mus.mi.us","tec.mi.us","washtenaw.mi.us","uy","com.uy","edu.uy","gub.uy","mil.uy","net.uy","org.uy","uz","co.uz","com.uz","net.uz","org.uz","va","vc","com.vc","net.vc","org.vc","gov.vc","mil.vc","edu.vc","ve","arts.ve","co.ve","com.ve","e12.ve","edu.ve","firm.ve","gob.ve","gov.ve","info.ve","int.ve","mil.ve","net.ve","org.ve","rec.ve","store.ve","tec.ve","web.ve","vg","vi","co.vi","com.vi","k12.vi","net.vi","org.vi","vn","com.vn","net.vn","org.vn","edu.vn","gov.vn","int.vn","ac.vn","biz.vn","info.vn","name.vn","pro.vn","health.vn","vu","com.vu","edu.vu","net.vu","org.vu","wf","ws","com.ws","net.ws","org.ws","gov.ws","edu.ws","yt","امارات","հայ","বাংলা","бг","бел","中国","中國","الجزائر","مصر","ею","გე","ελ","香港","公司.香港","教育.香港","政府.香港","個人.香港","網絡.香港","組織.香港","ಭಾರತ","ଭାରତ","ভাৰত","भारतम्","भारोत","ڀارت","ഭാരതം","भारत","بارت","بھارت","భారత్","ભારત","ਭਾਰਤ","ভারত","இந்தியா","ایران","ايران","عراق","الاردن","한국","қаз","ලංකා","இலங்கை","المغرب","мкд","мон","澳門","澳门","مليسيا","عمان","پاکستان","پاكستان","فلسطين","срб","пр.срб","орг.срб","обр.срб","од.срб","упр.срб","ак.срб","рф","قطر","السعودية","السعودیة","السعودیۃ","السعوديه","سودان","新加坡","சிங்கப்பூர்","سورية","سوريا","ไทย","ศึกษา.ไทย","ธุรกิจ.ไทย","รัฐบาล.ไทย","ทหาร.ไทย","เน็ต.ไทย","องค์กร.ไทย","تونس","台灣","台湾","臺灣","укр","اليمن","xxx","*.ye","ac.za","agric.za","alt.za","co.za","edu.za","gov.za","grondar.za","law.za","mil.za","net.za","ngo.za","nis.za","nom.za","org.za","school.za","tm.za","web.za","zm","ac.zm","biz.zm","co.zm","com.zm","edu.zm","gov.zm","info.zm","mil.zm","net.zm","org.zm","sch.zm","zw","ac.zw","co.zw","gov.zw","mil.zw","org.zw","aaa","aarp","abarth","abb","abbott","abbvie","abc","able","abogado","abudhabi","academy","accenture","accountant","accountants","aco","active","actor","adac","ads","adult","aeg","aetna","afamilycompany","afl","africa","agakhan","agency","aig","aigo","airbus","airforce","airtel","akdn","alfaromeo","alibaba","alipay","allfinanz","allstate","ally","alsace","alstom","americanexpress","americanfamily","amex","amfam","amica","amsterdam","analytics","android","anquan","anz","aol","apartments","app","apple","aquarelle","arab","aramco","archi","army","art","arte","asda","associates","athleta","attorney","auction","audi","audible","audio","auspost","author","auto","autos","avianca","aws","axa","azure","baby","baidu","banamex","bananarepublic","band","bank","bar","barcelona","barclaycard","barclays","barefoot","bargains","baseball","basketball","bauhaus","bayern","bbc","bbt","bbva","bcg","bcn","beats","beauty","beer","bentley","berlin","best","bestbuy","bet","bharti","bible","bid","bike","bing","bingo","bio","black","blackfriday","blanco","blockbuster","blog","bloomberg","blue","bms","bmw","bnl","bnpparibas","boats","boehringer","bofa","bom","bond","boo","book","booking","bosch","bostik","boston","bot","boutique","box","bradesco","bridgestone","broadway","broker","brother","brussels","budapest","bugatti","build","builders","business","buy","buzz","bzh","cab","cafe","cal","call","calvinklein","cam","camera","camp","cancerresearch","canon","capetown","capital","capitalone","car","caravan","cards","care","career","careers","cars","cartier","casa","case","caseih","cash","casino","catering","catholic","cba","cbn","cbre","cbs","ceb","center","ceo","cern","cfa","cfd","chanel","channel","charity","chase","chat","cheap","chintai","christmas","chrome","chrysler","church","cipriani","circle","cisco","citadel","citi","citic","city","cityeats","claims","cleaning","click","clinic","clinique","clothing","cloud","club","clubmed","coach","codes","coffee","college","cologne","comcast","commbank","community","company","compare","computer","comsec","condos","construction","consulting","contact","contractors","cooking","cookingchannel","cool","corsica","country","coupon","coupons","courses","credit","creditcard","creditunion","cricket","crown","crs","cruise","cruises","csc","cuisinella","cymru","cyou","dabur","dad","dance","data","date","dating","datsun","day","dclk","dds","deal","dealer","deals","degree","delivery","dell","deloitte","delta","democrat","dental","dentist","desi","design","dev","dhl","diamonds","diet","digital","direct","directory","discount","discover","dish","diy","dnp","docs","doctor","dodge","dog","doha","domains","dot","download","drive","dtv","dubai","duck","dunlop","duns","dupont","durban","dvag","dvr","earth","eat","eco","edeka","education","email","emerck","energy","engineer","engineering","enterprises","epost","epson","equipment","ericsson","erni","esq","estate","esurance","etisalat","eurovision","eus","events","everbank","exchange","expert","exposed","express","extraspace","fage","fail","fairwinds","faith","family","fan","fans","farm","farmers","fashion","fast","fedex","feedback","ferrari","ferrero","fiat","fidelity","fido","film","final","finance","financial","fire","firestone","firmdale","fish","fishing","fit","fitness","flickr","flights","flir","florist","flowers","fly","foo","food","foodnetwork","football","ford","forex","forsale","forum","foundation","fox","free","fresenius","frl","frogans","frontdoor","frontier","ftr","fujitsu","fujixerox","fun","fund","furniture","futbol","fyi","gal","gallery","gallo","gallup","game","games","gap","garden","gbiz","gdn","gea","gent","genting","george","ggee","gift","gifts","gives","giving","glade","glass","gle","global","globo","gmail","gmbh","gmo","gmx","godaddy","gold","goldpoint","golf","goo","goodhands","goodyear","goog","google","gop","got","grainger","graphics","gratis","green","gripe","grocery","group","guardian","gucci","guge","guide","guitars","guru","hair","hamburg","hangout","haus","hbo","hdfc","hdfcbank","health","healthcare","help","helsinki","here","hermes","hgtv","hiphop","hisamitsu","hitachi","hiv","hkt","hockey","holdings","holiday","homedepot","homegoods","homes","homesense","honda","honeywell","horse","hospital","host","hosting","hot","hoteles","hotels","hotmail","house","how","hsbc","hughes","hyatt","hyundai","ibm","icbc","ice","icu","ieee","ifm","ikano","imamat","imdb","immo","immobilien","inc","industries","infiniti","ing","ink","institute","insurance","insure","intel","international","intuit","investments","ipiranga","irish","iselect","ismaili","ist","istanbul","itau","itv","iveco","jaguar","java","jcb","jcp","jeep","jetzt","jewelry","jio","jlc","jll","jmp","jnj","joburg","jot","joy","jpmorgan","jprs","juegos","juniper","kaufen","kddi","kerryhotels","kerrylogistics","kerryproperties","kfh","kia","kim","kinder","kindle","kitchen","kiwi","koeln","komatsu","kosher","kpmg","kpn","krd","kred","kuokgroup","kyoto","lacaixa","ladbrokes","lamborghini","lamer","lancaster","lancia","lancome","land","landrover","lanxess","lasalle","lat","latino","latrobe","law","lawyer","lds","lease","leclerc","lefrak","legal","lego","lexus","lgbt","liaison","lidl","life","lifeinsurance","lifestyle","lighting","like","lilly","limited","limo","lincoln","linde","link","lipsy","live","living","lixil","llc","loan","loans","locker","locus","loft","lol","london","lotte","lotto","love","lpl","lplfinancial","ltd","ltda","lundbeck","lupin","luxe","luxury","macys","madrid","maif","maison","makeup","man","management","mango","map","market","marketing","markets","marriott","marshalls","maserati","mattel","mba","mckinsey","med","media","meet","melbourne","meme","memorial","men","menu","merckmsd","metlife","miami","microsoft","mini","mint","mit","mitsubishi","mlb","mls","mma","mobile","mobily","moda","moe","moi","mom","monash","money","monster","mopar","mormon","mortgage","moscow","moto","motorcycles","mov","movie","movistar","msd","mtn","mtr","mutual","nab","nadex","nagoya","nationwide","natura","navy","nba","nec","netbank","netflix","network","neustar","new","newholland","news","next","nextdirect","nexus","nfl","ngo","nhk","nico","nike","nikon","ninja","nissan","nissay","nokia","northwesternmutual","norton","now","nowruz","nowtv","nra","nrw","ntt","nyc","obi","observer","off","office","okinawa","olayan","olayangroup","oldnavy","ollo","omega","one","ong","onl","online","onyourside","ooo","open","oracle","orange","organic","origins","osaka","otsuka","ott","ovh","page","panasonic","panerai","paris","pars","partners","parts","party","passagens","pay","pccw","pet","pfizer","pharmacy","phd","philips","phone","photo","photography","photos","physio","piaget","pics","pictet","pictures","pid","pin","ping","pink","pioneer","pizza","place","play","playstation","plumbing","plus","pnc","pohl","poker","politie","porn","pramerica","praxi","press","prime","prod","productions","prof","progressive","promo","properties","property","protection","pru","prudential","pub","pwc","qpon","quebec","quest","qvc","racing","radio","raid","read","realestate","realtor","realty","recipes","red","redstone","redumbrella","rehab","reise","reisen","reit","reliance","ren","rent","rentals","repair","report","republican","rest","restaurant","review","reviews","rexroth","rich","richardli","ricoh","rightathome","ril","rio","rip","rmit","rocher","rocks","rodeo","rogers","room","rsvp","rugby","ruhr","run","rwe","ryukyu","saarland","safe","safety","sakura","sale","salon","samsclub","samsung","sandvik","sandvikcoromant","sanofi","sap","sarl","sas","save","saxo","sbi","sbs","sca","scb","schaeffler","schmidt","scholarships","school","schule","schwarz","science","scjohnson","scor","scot","search","seat","secure","security","seek","select","sener","services","ses","seven","sew","sex","sexy","sfr","shangrila","sharp","shaw","shell","shia","shiksha","shoes","shop","shopping","shouji","show","showtime","shriram","silk","sina","singles","site","ski","skin","sky","skype","sling","smart","smile","sncf","soccer","social","softbank","software","sohu","solar","solutions","song","sony","soy","space","spiegel","sport","spot","spreadbetting","srl","srt","stada","staples","star","starhub","statebank","statefarm","statoil","stc","stcgroup","stockholm","storage","store","stream","studio","study","style","sucks","supplies","supply","support","surf","surgery","suzuki","swatch","swiftcover","swiss","sydney","symantec","systems","tab","taipei","talk","taobao","target","tatamotors","tatar","tattoo","tax","taxi","tci","tdk","team","tech","technology","telecity","telefonica","temasek","tennis","teva","thd","theater","theatre","tiaa","tickets","tienda","tiffany","tips","tires","tirol","tjmaxx","tjx","tkmaxx","tmall","today","tokyo","tools","top","toray","toshiba","total","tours","town","toyota","toys","trade","trading","training","travel","travelchannel","travelers","travelersinsurance","trust","trv","tube","tui","tunes","tushu","tvs","ubank","ubs","uconnect","unicom","university","uno","uol","ups","vacations","vana","vanguard","vegas","ventures","verisign","versicherung","vet","viajes","video","vig","viking","villas","vin","vip","virgin","visa","vision","vista","vistaprint","viva","vivo","vlaanderen","vodka","volkswagen","volvo","vote","voting","voto","voyage","vuelos","wales","walmart","walter","wang","wanggou","warman","watch","watches","weather","weatherchannel","webcam","weber","website","wed","wedding","weibo","weir","whoswho","wien","wiki","williamhill","win","windows","wine","winners","wme","wolterskluwer","woodside","work","works","world","wow","wtc","wtf","xbox","xerox","xfinity","xihuan","xin","कॉम","セール","佛山","慈善","集团","在线","大众汽车","点看","คอม","八卦","موقع","公益","公司","香格里拉","网站","移动","我爱你","москва","католик","онлайн","сайт","联通","קום","时尚","微博","淡马锡","ファッション","орг","नेट","ストア","삼성","商标","商店","商城","дети","ポイント","新闻","工行","家電","كوم","中文网","中信","娱乐","谷歌","電訊盈科","购物","クラウド","通販","网店","संगठन","餐厅","网络","ком","诺基亚","食品","飞利浦","手表","手机","ارامكو","العليان","اتصالات","بازار","موبايلي","ابوظبي","كاثوليك","همراه","닷컴","政府","شبكة","بيتك","عرب","机构","组织机构","健康","招聘","рус","珠宝","大拿","みんな","グーグル","世界","書籍","网址","닷넷","コム","天主教","游戏","vermögensberater","vermögensberatung","企业","信息","嘉里大酒店","嘉里","广东","政务","xyz","yachts","yahoo","yamaxun","yandex","yodobashi","yoga","yokohama","you","youtube","yun","zappos","zara","zero","zip","zippo","zone","zuerich","cc.ua","inf.ua","ltd.ua","beep.pl","*.compute.estate","*.alces.network","alwaysdata.net","cloudfront.net","*.compute.amazonaws.com","*.compute-1.amazonaws.com","*.compute.amazonaws.com.cn","us-east-1.amazonaws.com","cn-north-1.eb.amazonaws.com.cn","elasticbeanstalk.com","ap-northeast-1.elasticbeanstalk.com","ap-northeast-2.elasticbeanstalk.com","ap-northeast-3.elasticbeanstalk.com","ap-south-1.elasticbeanstalk.com","ap-southeast-1.elasticbeanstalk.com","ap-southeast-2.elasticbeanstalk.com","ca-central-1.elasticbeanstalk.com","eu-central-1.elasticbeanstalk.com","eu-west-1.elasticbeanstalk.com","eu-west-2.elasticbeanstalk.com","eu-west-3.elasticbeanstalk.com","sa-east-1.elasticbeanstalk.com","us-east-1.elasticbeanstalk.com","us-east-2.elasticbeanstalk.com","us-gov-west-1.elasticbeanstalk.com","us-west-1.elasticbeanstalk.com","us-west-2.elasticbeanstalk.com","*.elb.amazonaws.com","*.elb.amazonaws.com.cn","s3.amazonaws.com","s3-ap-northeast-1.amazonaws.com","s3-ap-northeast-2.amazonaws.com","s3-ap-south-1.amazonaws.com","s3-ap-southeast-1.amazonaws.com","s3-ap-southeast-2.amazonaws.com","s3-ca-central-1.amazonaws.com","s3-eu-central-1.amazonaws.com","s3-eu-west-1.amazonaws.com","s3-eu-west-2.amazonaws.com","s3-eu-west-3.amazonaws.com","s3-external-1.amazonaws.com","s3-fips-us-gov-west-1.amazonaws.com","s3-sa-east-1.amazonaws.com","s3-us-gov-west-1.amazonaws.com","s3-us-east-2.amazonaws.com","s3-us-west-1.amazonaws.com","s3-us-west-2.amazonaws.com","s3.ap-northeast-2.amazonaws.com","s3.ap-south-1.amazonaws.com","s3.cn-north-1.amazonaws.com.cn","s3.ca-central-1.amazonaws.com","s3.eu-central-1.amazonaws.com","s3.eu-west-2.amazonaws.com","s3.eu-west-3.amazonaws.com","s3.us-east-2.amazonaws.com","s3.dualstack.ap-northeast-1.amazonaws.com","s3.dualstack.ap-northeast-2.amazonaws.com","s3.dualstack.ap-south-1.amazonaws.com","s3.dualstack.ap-southeast-1.amazonaws.com","s3.dualstack.ap-southeast-2.amazonaws.com","s3.dualstack.ca-central-1.amazonaws.com","s3.dualstack.eu-central-1.amazonaws.com","s3.dualstack.eu-west-1.amazonaws.com","s3.dualstack.eu-west-2.amazonaws.com","s3.dualstack.eu-west-3.amazonaws.com","s3.dualstack.sa-east-1.amazonaws.com","s3.dualstack.us-east-1.amazonaws.com","s3.dualstack.us-east-2.amazonaws.com","s3-website-us-east-1.amazonaws.com","s3-website-us-west-1.amazonaws.com","s3-website-us-west-2.amazonaws.com","s3-website-ap-northeast-1.amazonaws.com","s3-website-ap-southeast-1.amazonaws.com","s3-website-ap-southeast-2.amazonaws.com","s3-website-eu-west-1.amazonaws.com","s3-website-sa-east-1.amazonaws.com","s3-website.ap-northeast-2.amazonaws.com","s3-website.ap-south-1.amazonaws.com","s3-website.ca-central-1.amazonaws.com","s3-website.eu-central-1.amazonaws.com","s3-website.eu-west-2.amazonaws.com","s3-website.eu-west-3.amazonaws.com","s3-website.us-east-2.amazonaws.com","t3l3p0rt.net","tele.amune.org","on-aptible.com","user.party.eus","pimienta.org","poivron.org","potager.org","sweetpepper.org","myasustor.com","myfritz.net","*.awdev.ca","*.advisor.ws","backplaneapp.io","betainabox.com","bnr.la","blackbaudcdn.net","boomla.net","boxfuse.io","square7.ch","bplaced.com","bplaced.de","square7.de","bplaced.net","square7.net","browsersafetymark.io","mycd.eu","ae.org","ar.com","br.com","cn.com","com.de","com.se","de.com","eu.com","gb.com","gb.net","hu.com","hu.net","jp.net","jpn.com","kr.com","mex.com","no.com","qc.com","ru.com","sa.com","se.net","uk.com","uk.net","us.com","uy.com","za.bz","za.com","africa.com","gr.com","in.net","us.org","co.com","c.la","certmgr.org","xenapponazure.com","virtueeldomein.nl","cleverapps.io","c66.me","cloud66.ws","jdevcloud.com","wpdevcloud.com","cloudaccess.host","freesite.host","cloudaccess.net","cloudcontrolled.com","cloudcontrolapp.com","co.ca","*.otap.co","co.cz","c.cdn77.org","cdn77-ssl.net","r.cdn77.net","rsc.cdn77.org","ssl.origin.cdn77-secure.org","cloudns.asia","cloudns.biz","cloudns.club","cloudns.cc","cloudns.eu","cloudns.in","cloudns.info","cloudns.org","cloudns.pro","cloudns.pw","cloudns.us","cloudeity.net","cnpy.gdn","co.nl","co.no","webhosting.be","hosting-cluster.nl","dyn.cosidns.de","dynamisches-dns.de","dnsupdater.de","internet-dns.de","l-o-g-i-n.de","dynamic-dns.info","feste-ip.net","knx-server.net","static-access.net","realm.cz","*.cryptonomic.net","cupcake.is","cyon.link","cyon.site","daplie.me","localhost.daplie.me","dattolocal.com","dattorelay.com","dattoweb.com","mydatto.com","dattolocal.net","mydatto.net","biz.dk","co.dk","firm.dk","reg.dk","store.dk","debian.net","dedyn.io","dnshome.de","drayddns.com","dreamhosters.com","mydrobo.com","drud.io","drud.us","duckdns.org","dy.fi","tunk.org","dyndns-at-home.com","dyndns-at-work.com","dyndns-blog.com","dyndns-free.com","dyndns-home.com","dyndns-ip.com","dyndns-mail.com","dyndns-office.com","dyndns-pics.com","dyndns-remote.com","dyndns-server.com","dyndns-web.com","dyndns-wiki.com","dyndns-work.com","dyndns.biz","dyndns.info","dyndns.org","dyndns.tv","at-band-camp.net","ath.cx","barrel-of-knowledge.info","barrell-of-knowledge.info","better-than.tv","blogdns.com","blogdns.net","blogdns.org","blogsite.org","boldlygoingnowhere.org","broke-it.net","buyshouses.net","cechire.com","dnsalias.com","dnsalias.net","dnsalias.org","dnsdojo.com","dnsdojo.net","dnsdojo.org","does-it.net","doesntexist.com","doesntexist.org","dontexist.com","dontexist.net","dontexist.org","doomdns.com","doomdns.org","dvrdns.org","dyn-o-saur.com","dynalias.com","dynalias.net","dynalias.org","dynathome.net","dyndns.ws","endofinternet.net","endofinternet.org","endoftheinternet.org","est-a-la-maison.com","est-a-la-masion.com","est-le-patron.com","est-mon-blogueur.com","for-better.biz","for-more.biz","for-our.info","for-some.biz","for-the.biz","forgot.her.name","forgot.his.name","from-ak.com","from-al.com","from-ar.com","from-az.net","from-ca.com","from-co.net","from-ct.com","from-dc.com","from-de.com","from-fl.com","from-ga.com","from-hi.com","from-ia.com","from-id.com","from-il.com","from-in.com","from-ks.com","from-ky.com","from-la.net","from-ma.com","from-md.com","from-me.org","from-mi.com","from-mn.com","from-mo.com","from-ms.com","from-mt.com","from-nc.com","from-nd.com","from-ne.com","from-nh.com","from-nj.com","from-nm.com","from-nv.com","from-ny.net","from-oh.com","from-ok.com","from-or.com","from-pa.com","from-pr.com","from-ri.com","from-sc.com","from-sd.com","from-tn.com","from-tx.com","from-ut.com","from-va.com","from-vt.com","from-wa.com","from-wi.com","from-wv.com","from-wy.com","ftpaccess.cc","fuettertdasnetz.de","game-host.org","game-server.cc","getmyip.com","gets-it.net","go.dyndns.org","gotdns.com","gotdns.org","groks-the.info","groks-this.info","ham-radio-op.net","here-for-more.info","hobby-site.com","hobby-site.org","home.dyndns.org","homedns.org","homeftp.net","homeftp.org","homeip.net","homelinux.com","homelinux.net","homelinux.org","homeunix.com","homeunix.net","homeunix.org","iamallama.com","in-the-band.net","is-a-anarchist.com","is-a-blogger.com","is-a-bookkeeper.com","is-a-bruinsfan.org","is-a-bulls-fan.com","is-a-candidate.org","is-a-caterer.com","is-a-celticsfan.org","is-a-chef.com","is-a-chef.net","is-a-chef.org","is-a-conservative.com","is-a-cpa.com","is-a-cubicle-slave.com","is-a-democrat.com","is-a-designer.com","is-a-doctor.com","is-a-financialadvisor.com","is-a-geek.com","is-a-geek.net","is-a-geek.org","is-a-green.com","is-a-guru.com","is-a-hard-worker.com","is-a-hunter.com","is-a-knight.org","is-a-landscaper.com","is-a-lawyer.com","is-a-liberal.com","is-a-libertarian.com","is-a-linux-user.org","is-a-llama.com","is-a-musician.com","is-a-nascarfan.com","is-a-nurse.com","is-a-painter.com","is-a-patsfan.org","is-a-personaltrainer.com","is-a-photographer.com","is-a-player.com","is-a-republican.com","is-a-rockstar.com","is-a-socialist.com","is-a-soxfan.org","is-a-student.com","is-a-teacher.com","is-a-techie.com","is-a-therapist.com","is-an-accountant.com","is-an-actor.com","is-an-actress.com","is-an-anarchist.com","is-an-artist.com","is-an-engineer.com","is-an-entertainer.com","is-by.us","is-certified.com","is-found.org","is-gone.com","is-into-anime.com","is-into-cars.com","is-into-cartoons.com","is-into-games.com","is-leet.com","is-lost.org","is-not-certified.com","is-saved.org","is-slick.com","is-uberleet.com","is-very-bad.org","is-very-evil.org","is-very-good.org","is-very-nice.org","is-very-sweet.org","is-with-theband.com","isa-geek.com","isa-geek.net","isa-geek.org","isa-hockeynut.com","issmarterthanyou.com","isteingeek.de","istmein.de","kicks-ass.net","kicks-ass.org","knowsitall.info","land-4-sale.us","lebtimnetz.de","leitungsen.de","likes-pie.com","likescandy.com","merseine.nu","mine.nu","misconfused.org","mypets.ws","myphotos.cc","neat-url.com","office-on-the.net","on-the-web.tv","podzone.net","podzone.org","readmyblog.org","saves-the-whales.com","scrapper-site.net","scrapping.cc","selfip.biz","selfip.com","selfip.info","selfip.net","selfip.org","sells-for-less.com","sells-for-u.com","sells-it.net","sellsyourhome.org","servebbs.com","servebbs.net","servebbs.org","serveftp.net","serveftp.org","servegame.org","shacknet.nu","simple-url.com","space-to-rent.com","stuff-4-sale.org","stuff-4-sale.us","teaches-yoga.com","thruhere.net","traeumtgerade.de","webhop.biz","webhop.info","webhop.net","webhop.org","worse-than.tv","writesthisblog.com","ddnss.de","dyn.ddnss.de","dyndns.ddnss.de","dyndns1.de","dyn-ip24.de","home-webserver.de","dyn.home-webserver.de","myhome-server.de","ddnss.org","definima.net","definima.io","bci.dnstrace.pro","ddnsfree.com","ddnsgeek.com","giize.com","gleeze.com","kozow.com","loseyourip.com","ooguy.com","theworkpc.com","casacam.net","dynu.net","accesscam.org","camdvr.org","freeddns.org","mywire.org","webredirect.org","myddns.rocks","blogsite.xyz","dynv6.net","e4.cz","mytuleap.com","enonic.io","customer.enonic.io","eu.org","al.eu.org","asso.eu.org","at.eu.org","au.eu.org","be.eu.org","bg.eu.org","ca.eu.org","cd.eu.org","ch.eu.org","cn.eu.org","cy.eu.org","cz.eu.org","de.eu.org","dk.eu.org","edu.eu.org","ee.eu.org","es.eu.org","fi.eu.org","fr.eu.org","gr.eu.org","hr.eu.org","hu.eu.org","ie.eu.org","il.eu.org","in.eu.org","int.eu.org","is.eu.org","it.eu.org","jp.eu.org","kr.eu.org","lt.eu.org","lu.eu.org","lv.eu.org","mc.eu.org","me.eu.org","mk.eu.org","mt.eu.org","my.eu.org","net.eu.org","ng.eu.org","nl.eu.org","no.eu.org","nz.eu.org","paris.eu.org","pl.eu.org","pt.eu.org","q-a.eu.org","ro.eu.org","ru.eu.org","se.eu.org","si.eu.org","sk.eu.org","tr.eu.org","uk.eu.org","us.eu.org","eu-1.evennode.com","eu-2.evennode.com","eu-3.evennode.com","eu-4.evennode.com","us-1.evennode.com","us-2.evennode.com","us-3.evennode.com","us-4.evennode.com","twmail.cc","twmail.net","twmail.org","mymailer.com.tw","url.tw","apps.fbsbx.com","ru.net","adygeya.ru","bashkiria.ru","bir.ru","cbg.ru","com.ru","dagestan.ru","grozny.ru","kalmykia.ru","kustanai.ru","marine.ru","mordovia.ru","msk.ru","mytis.ru","nalchik.ru","nov.ru","pyatigorsk.ru","spb.ru","vladikavkaz.ru","vladimir.ru","abkhazia.su","adygeya.su","aktyubinsk.su","arkhangelsk.su","armenia.su","ashgabad.su","azerbaijan.su","balashov.su","bashkiria.su","bryansk.su","bukhara.su","chimkent.su","dagestan.su","east-kazakhstan.su","exnet.su","georgia.su","grozny.su","ivanovo.su","jambyl.su","kalmykia.su","kaluga.su","karacol.su","karaganda.su","karelia.su","khakassia.su","krasnodar.su","kurgan.su","kustanai.su","lenug.su","mangyshlak.su","mordovia.su","msk.su","murmansk.su","nalchik.su","navoi.su","north-kazakhstan.su","nov.su","obninsk.su","penza.su","pokrovsk.su","sochi.su","spb.su","tashkent.su","termez.su","togliatti.su","troitsk.su","tselinograd.su","tula.su","tuva.su","vladikavkaz.su","vladimir.su","vologda.su","channelsdvr.net","fastlylb.net","map.fastlylb.net","freetls.fastly.net","map.fastly.net","a.prod.fastly.net","global.prod.fastly.net","a.ssl.fastly.net","b.ssl.fastly.net","global.ssl.fastly.net","fastpanel.direct","fastvps-server.com","fhapp.xyz","fedorainfracloud.org","fedorapeople.org","cloud.fedoraproject.org","app.os.fedoraproject.org","app.os.stg.fedoraproject.org","filegear.me","firebaseapp.com","flynnhub.com","flynnhosting.net","freebox-os.com","freeboxos.com","fbx-os.fr","fbxos.fr","freebox-os.fr","freeboxos.fr","freedesktop.org","*.futurecms.at","*.ex.futurecms.at","*.in.futurecms.at","futurehosting.at","futuremailing.at","*.ex.ortsinfo.at","*.kunden.ortsinfo.at","*.statics.cloud","service.gov.uk","github.io","githubusercontent.com","gitlab.io","homeoffice.gov.uk","ro.im","shop.ro","goip.de","*.0emm.com","appspot.com","blogspot.ae","blogspot.al","blogspot.am","blogspot.ba","blogspot.be","blogspot.bg","blogspot.bj","blogspot.ca","blogspot.cf","blogspot.ch","blogspot.cl","blogspot.co.at","blogspot.co.id","blogspot.co.il","blogspot.co.ke","blogspot.co.nz","blogspot.co.uk","blogspot.co.za","blogspot.com","blogspot.com.ar","blogspot.com.au","blogspot.com.br","blogspot.com.by","blogspot.com.co","blogspot.com.cy","blogspot.com.ee","blogspot.com.eg","blogspot.com.es","blogspot.com.mt","blogspot.com.ng","blogspot.com.tr","blogspot.com.uy","blogspot.cv","blogspot.cz","blogspot.de","blogspot.dk","blogspot.fi","blogspot.fr","blogspot.gr","blogspot.hk","blogspot.hr","blogspot.hu","blogspot.ie","blogspot.in","blogspot.is","blogspot.it","blogspot.jp","blogspot.kr","blogspot.li","blogspot.lt","blogspot.lu","blogspot.md","blogspot.mk","blogspot.mr","blogspot.mx","blogspot.my","blogspot.nl","blogspot.no","blogspot.pe","blogspot.pt","blogspot.qa","blogspot.re","blogspot.ro","blogspot.rs","blogspot.ru","blogspot.se","blogspot.sg","blogspot.si","blogspot.sk","blogspot.sn","blogspot.td","blogspot.tw","blogspot.ug","blogspot.vn","cloudfunctions.net","cloud.goog","codespot.com","googleapis.com","googlecode.com","pagespeedmobilizer.com","publishproxy.com","withgoogle.com","withyoutube.com","hashbang.sh","hasura.app","hasura-app.io","hepforge.org","herokuapp.com","herokussl.com","myravendb.com","ravendb.community","ravendb.me","development.run","ravendb.run","moonscale.net","iki.fi","biz.at","info.at","info.cx","ac.leg.br","al.leg.br","am.leg.br","ap.leg.br","ba.leg.br","ce.leg.br","df.leg.br","es.leg.br","go.leg.br","ma.leg.br","mg.leg.br","ms.leg.br","mt.leg.br","pa.leg.br","pb.leg.br","pe.leg.br","pi.leg.br","pr.leg.br","rj.leg.br","rn.leg.br","ro.leg.br","rr.leg.br","rs.leg.br","sc.leg.br","se.leg.br","sp.leg.br","to.leg.br","pixolino.com","ipifony.net","mein-iserv.de","test-iserv.de","myjino.ru","*.hosting.myjino.ru","*.landing.myjino.ru","*.spectrum.myjino.ru","*.vps.myjino.ru","*.triton.zone","*.cns.joyent.com","js.org","keymachine.de","knightpoint.systems","co.krd","edu.krd","git-repos.de","lcube-server.de","svn-repos.de","app.lmpm.com","linkitools.space","linkyard.cloud","linkyard-cloud.ch","we.bs","uklugs.org","glug.org.uk","lug.org.uk","lugs.org.uk","barsy.bg","barsy.co.uk","barsyonline.co.uk","barsycenter.com","barsyonline.com","barsy.club","barsy.de","barsy.eu","barsy.in","barsy.info","barsy.io","barsy.me","barsy.menu","barsy.mobi","barsy.net","barsy.online","barsy.org","barsy.pro","barsy.pub","barsy.shop","barsy.site","barsy.support","barsy.uk","*.magentosite.cloud","mayfirst.info","mayfirst.org","hb.cldmail.ru","miniserver.com","memset.net","cloud.metacentrum.cz","custom.metacentrum.cz","flt.cloud.muni.cz","usr.cloud.muni.cz","meteorapp.com","eu.meteorapp.com","co.pl","azurecontainer.io","azurewebsites.net","azure-mobile.net","cloudapp.net","mozilla-iot.org","bmoattachments.org","net.ru","org.ru","pp.ru","bitballoon.com","netlify.com","4u.com","ngrok.io","nh-serv.co.uk","nfshost.com","dnsking.ch","mypi.co","n4t.co","001www.com","ddnslive.com","myiphost.com","forumz.info","16-b.it","32-b.it","64-b.it","soundcast.me","tcp4.me","dnsup.net","hicam.net","now-dns.net","ownip.net","vpndns.net","dynserv.org","now-dns.org","x443.pw","now-dns.top","ntdll.top","freeddns.us","crafting.xyz","zapto.xyz","nsupdate.info","nerdpol.ovh","blogsyte.com","brasilia.me","cable-modem.org","ciscofreak.com","collegefan.org","couchpotatofries.org","damnserver.com","ddns.me","ditchyourip.com","dnsfor.me","dnsiskinky.com","dvrcam.info","dynns.com","eating-organic.net","fantasyleague.cc","geekgalaxy.com","golffan.us","health-carereform.com","homesecuritymac.com","homesecuritypc.com","hopto.me","ilovecollege.info","loginto.me","mlbfan.org","mmafan.biz","myactivedirectory.com","mydissent.net","myeffect.net","mymediapc.net","mypsx.net","mysecuritycamera.com","mysecuritycamera.net","mysecuritycamera.org","net-freaks.com","nflfan.org","nhlfan.net","no-ip.ca","no-ip.co.uk","no-ip.net","noip.us","onthewifi.com","pgafan.net","point2this.com","pointto.us","privatizehealthinsurance.net","quicksytes.com","read-books.org","securitytactics.com","serveexchange.com","servehumour.com","servep2p.com","servesarcasm.com","stufftoread.com","ufcfan.org","unusualperson.com","workisboring.com","3utilities.com","bounceme.net","ddns.net","ddnsking.com","gotdns.ch","hopto.org","myftp.biz","myftp.org","myvnc.com","no-ip.biz","no-ip.info","no-ip.org","noip.me","redirectme.net","servebeer.com","serveblog.net","servecounterstrike.com","serveftp.com","servegame.com","servehalflife.com","servehttp.com","serveirc.com","serveminecraft.net","servemp3.com","servepics.com","servequake.com","sytes.net","webhop.me","zapto.org","stage.nodeart.io","nodum.co","nodum.io","pcloud.host","nyc.mn","nom.ae","nom.af","nom.ai","nom.al","nym.by","nym.bz","nom.cl","nom.gd","nom.ge","nom.gl","nym.gr","nom.gt","nym.gy","nom.hn","nym.ie","nom.im","nom.ke","nym.kz","nym.la","nym.lc","nom.li","nym.li","nym.lt","nym.lu","nym.me","nom.mk","nym.mn","nym.mx","nom.nu","nym.nz","nym.pe","nym.pt","nom.pw","nom.qa","nym.ro","nom.rs","nom.si","nym.sk","nom.st","nym.su","nym.sx","nom.tj","nym.tw","nom.ug","nom.uy","nom.vc","nom.vg","cya.gg","cloudycluster.net","nid.io","opencraft.hosting","operaunite.com","outsystemscloud.com","ownprovider.com","own.pm","ox.rs","oy.lc","pgfog.com","pagefrontapp.com","art.pl","gliwice.pl","krakow.pl","poznan.pl","wroc.pl","zakopane.pl","pantheonsite.io","gotpantheon.com","mypep.link","on-web.fr","*.platform.sh","*.platformsh.site","xen.prgmr.com","priv.at","protonet.io","chirurgiens-dentistes-en-france.fr","byen.site","ras.ru","qa2.com","dev-myqnapcloud.com","alpha-myqnapcloud.com","myqnapcloud.com","*.quipelements.com","vapor.cloud","vaporcloud.io","rackmaze.com","rackmaze.net","rhcloud.com","resindevice.io","devices.resinstaging.io","hzc.io","wellbeingzone.eu","ptplus.fit","wellbeingzone.co.uk","sandcats.io","logoip.de","logoip.com","schokokeks.net","scrysec.com","firewall-gateway.com","firewall-gateway.de","my-gateway.de","my-router.de","spdns.de","spdns.eu","firewall-gateway.net","my-firewall.org","myfirewall.org","spdns.org","*.s5y.io","*.sensiosite.cloud","biz.ua","co.ua","pp.ua","shiftedit.io","myshopblocks.com","1kapp.com","appchizi.com","applinzi.com","sinaapp.com","vipsinaapp.com","bounty-full.com","alpha.bounty-full.com","beta.bounty-full.com","static.land","dev.static.land","sites.static.land","apps.lair.io","*.stolos.io","spacekit.io","customer.speedpartner.de","storj.farm","utwente.io","temp-dns.com","diskstation.me","dscloud.biz","dscloud.me","dscloud.mobi","dsmynas.com","dsmynas.net","dsmynas.org","familyds.com","familyds.net","familyds.org","i234.me","myds.me","synology.me","vpnplus.to","taifun-dns.de","gda.pl","gdansk.pl","gdynia.pl","med.pl","sopot.pl","gwiddle.co.uk","cust.dev.thingdust.io","cust.disrec.thingdust.io","cust.prod.thingdust.io","cust.testing.thingdust.io","bloxcms.com","townnews-staging.com","12hp.at","2ix.at","4lima.at","lima-city.at","12hp.ch","2ix.ch","4lima.ch","lima-city.ch","trafficplex.cloud","de.cool","12hp.de","2ix.de","4lima.de","lima-city.de","1337.pictures","clan.rip","lima-city.rocks","webspace.rocks","lima.zone","*.transurl.be","*.transurl.eu","*.transurl.nl","tuxfamily.org","dd-dns.de","diskstation.eu","diskstation.org","dray-dns.de","draydns.de","dyn-vpn.de","dynvpn.de","mein-vigor.de","my-vigor.de","my-wan.de","syno-ds.de","synology-diskstation.de","synology-ds.de","uber.space","*.uberspace.de","hk.com","hk.org","ltd.hk","inc.hk","virtualuser.de","virtual-user.de","lib.de.us","2038.io","router.management","v-info.info","wedeploy.io","wedeploy.me","wedeploy.sh","remotewd.com","wmflabs.org","half.host","xnbay.com","u2.xnbay.com","u2-local.xnbay.com","cistron.nl","demon.nl","xs4all.space","official.academy","yolasite.com","ybo.faith","yombo.me","homelink.one","ybo.party","ybo.review","ybo.science","ybo.trade","nohost.me","noho.st","za.net","za.org","now.sh","zone.id"]')},function(e,t,r){"use strict"; -/*! - * Copyright (c) 2015, Salesforce.com, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of Salesforce.com nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */var i=r(213).Store,n=r(214).permuteDomain,a=r(215).pathMatch,o=r(11);function s(){i.call(this),this.idx={}}o.inherits(s,i),t.MemoryCookieStore=s,s.prototype.idx=null,s.prototype.synchronous=!0,s.prototype.inspect=function(){return"{ idx: "+o.inspect(this.idx,!1,2)+" }"},o.inspect.custom&&(s.prototype[o.inspect.custom]=s.prototype.inspect),s.prototype.findCookie=function(e,t,r,i){return this.idx[e]&&this.idx[e][t]?i(null,this.idx[e][t][r]||null):i(null,void 0)},s.prototype.findCookies=function(e,t,r){var i,o=[];if(!e)return r(null,[]);i=t?function(e){Object.keys(e).forEach((function(r){if(a(t,r)){var i=e[r];for(var n in i)o.push(i[n])}}))}:function(e){for(var t in e){var r=e[t];for(var i in r)o.push(r[i])}};var s=n(e)||[e],c=this.idx;s.forEach((function(e){var t=c[e];t&&i(t)})),r(null,o)},s.prototype.putCookie=function(e,t){this.idx[e.domain]||(this.idx[e.domain]={}),this.idx[e.domain][e.path]||(this.idx[e.domain][e.path]={}),this.idx[e.domain][e.path][e.key]=e,t(null)},s.prototype.updateCookie=function(e,t,r){this.putCookie(t,r)},s.prototype.removeCookie=function(e,t,r,i){this.idx[e]&&this.idx[e][t]&&this.idx[e][t][r]&&delete this.idx[e][t][r],i(null)},s.prototype.removeCookies=function(e,t,r){return this.idx[e]&&(t?delete this.idx[e][t]:delete this.idx[e]),r(null)},s.prototype.getAllCookies=function(e){var t=[],r=this.idx;Object.keys(r).forEach((function(e){Object.keys(r[e]).forEach((function(i){Object.keys(r[e][i]).forEach((function(n){null!==n&&t.push(r[e][i][n])}))}))})),t.sort((function(e,t){return(e.creationIndex||0)-(t.creationIndex||0)})),e(null,t)}},function(e){e.exports=JSON.parse('{"author":{"name":"Jeremy Stashewsky","email":"jstash@gmail.com","website":"https://github.com/stash"},"contributors":[{"name":"Alexander Savin","website":"https://github.com/apsavin"},{"name":"Ian Livingstone","website":"https://github.com/ianlivingstone"},{"name":"Ivan Nikulin","website":"https://github.com/inikulin"},{"name":"Lalit Kapoor","website":"https://github.com/lalitkapoor"},{"name":"Sam Thompson","website":"https://github.com/sambthompson"},{"name":"Sebastian Mayr","website":"https://github.com/Sebmaster"}],"license":"BSD-3-Clause","name":"tough-cookie","description":"RFC6265 Cookies and Cookie Jar for node.js","keywords":["HTTP","cookie","cookies","set-cookie","cookiejar","jar","RFC6265","RFC2965"],"version":"2.4.3","homepage":"https://github.com/salesforce/tough-cookie","repository":{"type":"git","url":"git://github.com/salesforce/tough-cookie.git"},"bugs":{"url":"https://github.com/salesforce/tough-cookie/issues"},"main":"./lib/cookie","files":["lib"],"scripts":{"test":"vows test/*_test.js","cover":"nyc --reporter=lcov --reporter=html vows test/*_test.js"},"engines":{"node":">=0.8"},"devDependencies":{"async":"^1.4.2","nyc":"^11.6.0","string.prototype.repeat":"^0.2.0","vows":"^0.8.1"},"dependencies":{"psl":"^1.1.24","punycode":"^1.4.1"},"_resolved":"https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz","_integrity":"sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==","_from":"tough-cookie@2.4.3"}')},function(e,t){function r(e,t){var r=[],i=[];return null==t&&(t=function(e,t){return r[0]===t?"[Circular ~]":"[Circular ~."+i.slice(0,r.indexOf(t)).join(".")+"]"}),function(n,a){if(r.length>0){var o=r.indexOf(this);~o?r.splice(o+1):r.push(this),~o?i.splice(o,1/0,n):i.push(n),~r.indexOf(a)&&(a=t.call(this,n,a))}else r.push(a);return null==e?a:e.call(this,n,a)}}(e.exports=function(e,t,i,n){return JSON.stringify(e,r(t,n),i)}).getSerialize=r},function(e,t,r){"use strict";(function(t){var i=r(52),n=r(85),a=r(25),o=r(11),s=r(34),c=r(411),u=r(421),l=r(422),h=r(424),d=r(439),p=r(131),f=r(442),m=r(443),g=r(122),_=r(233),v=r(444).strict,y=r(124),b=r(210),E=r(445),w=r(446).Querystring,S=r(449).Har,k=r(503).Auth,x=r(506).OAuth,M=r(508),N=r(509).Multipart,j=r(513).Redirect,T=r(514).Tunnel,R=r(516),I=r(1).Buffer,O=y.safeStringify,A=y.isReadStream,P=y.toBase64,D=y.defer,F=y.copy,C=y.version,B=b.jar(),z={};function L(){return{uri:this.uri,method:this.method,headers:this.headers}}function U(){return{statusCode:this.statusCode,body:this.body,headers:this.headers,request:L.call(this.request)}}function H(e){e.har&&(this._har=new S(this),e=this._har.options(e)),s.Stream.call(this);var t=Object.keys(H.prototype),r=function(e,t){var r={};for(var i in t){-1===e.indexOf(i)&&(r[i]=t[i])}return r}(t,e);g(this,r),e=function(e,t){var r={};for(var i in t){var n=!(-1===e.indexOf(i)),a="function"==typeof t[i];n&&a||(r[i]=t[i])}return r}(t,e),this.readable=!0,this.writable=!0,e.method&&(this.explicitMethod=!0),this._qs=new w(this),this._auth=new k(this),this._oauth=new x(this),this._multipart=new N(this),this._redirect=new j(this),this._tunnel=new T(this),this.init(e)}function q(){H.debug&&console.error("REQUEST %s",o.format.apply(o,arguments))}o.inherits(H,s.Stream),H.debug=t.env.NODE_DEBUG&&/\brequest\b/.test(t.env.NODE_DEBUG),H.prototype.debug=q,H.prototype.init=function(e){var t=this;for(var r in e||(e={}),t.headers=t.headers?F(t.headers):{},t.headers)void 0===t.headers[r]&&delete t.headers[r];if(p.httpify(t,t.headers),t.method||(t.method=e.method||"GET"),t.localAddress||(t.localAddress=e.localAddress),t._qs.init(e),q(e),t.pool||!1===t.pool||(t.pool=z),t.dests=t.dests||[],t.__isRequestRequest=!0,!t._callback&&t.callback&&(t._callback=t.callback,t.callback=function(){t._callbackCalled||(t._callbackCalled=!0,t._callback.apply(t,arguments))},t.on("error",t.callback.bind()),t.on("complete",t.callback.bind(t,null))),!t.uri&&t.url&&(t.uri=t.url,delete t.url),t.baseUrl){if("string"!=typeof t.baseUrl)return t.emit("error",new Error("options.baseUrl must be a string"));if("string"!=typeof t.uri)return t.emit("error",new Error("options.uri must be a string when using options.baseUrl"));if(0===t.uri.indexOf("//")||-1!==t.uri.indexOf("://"))return t.emit("error",new Error("options.uri must be a path when using options.baseUrl"));var o=t.baseUrl.lastIndexOf("/")===t.baseUrl.length-1,s=0===t.uri.indexOf("/");o&&s?t.uri=t.baseUrl+t.uri.slice(1):o||s?t.uri=t.baseUrl+t.uri:""===t.uri?t.uri=t.baseUrl:t.uri=t.baseUrl+"/"+t.uri,delete t.baseUrl}if(!t.uri)return t.emit("error",new Error("options.uri is a required argument"));if("string"==typeof t.uri&&(t.uri=a.parse(t.uri)),t.uri.href||(t.uri.href=a.format(t.uri)),"unix:"===t.uri.protocol)return t.emit("error",new Error("`unix://` URL scheme is no longer supported. Please use the format `http://unix:SOCKET:PATH`"));if("unix"===t.uri.host&&t.enableUnixSocket(),!1===t.strictSSL&&(t.rejectUnauthorized=!1),t.uri.pathname||(t.uri.pathname="/"),!(t.uri.host||t.uri.hostname&&t.uri.port||t.uri.isUnix)){var c='Invalid URI "'+a.format(t.uri)+'"';return 0===Object.keys(e).length&&(c+=". This can be caused by a crappy redirection."),t.abort(),t.emit("error",new Error(c))}if(t.hasOwnProperty("proxy")||(t.proxy=E(t.uri)),t.tunnel=t._tunnel.isEnabled(),t.proxy&&t._tunnel.setup(e),t._redirect.onRequest(e),t.setHost=!1,!t.hasHeader("host")){var u=t.originalHostHeaderName||"host";t.setHeader(u,t.uri.host),t.uri.port&&("80"===t.uri.port&&"http:"===t.uri.protocol||"443"===t.uri.port&&"https:"===t.uri.protocol)&&t.setHeader(u,t.uri.hostname),t.setHost=!0}if(t.jar(t._jar||e.jar),t.uri.port||("http:"===t.uri.protocol?t.uri.port=80:"https:"===t.uri.protocol&&(t.uri.port=443)),t.proxy&&!t.tunnel?(t.port=t.proxy.port,t.host=t.proxy.hostname):(t.port=t.uri.port,t.host=t.uri.hostname),e.form&&t.form(e.form),e.formData){var l=e.formData,h=t.form(),m=function(e,t){t&&t.hasOwnProperty("value")&&t.hasOwnProperty("options")?h.append(e,t.value,t.options):h.append(e,t)};for(var g in l)if(l.hasOwnProperty(g)){var y=l[g];if(y instanceof Array)for(var b=0;b=100&&s<200||204===s||304===s))o=e;else{var u=e.headers["content-encoding"]||"identity";u=u.trim().toLowerCase();var l={flush:c.Z_SYNC_FLUSH,finishFlush:c.Z_SYNC_FLUSH};"gzip"===u?(o=c.createGunzip(l),e.pipe(o)):"deflate"===u?(o=c.createInflate(l),e.pipe(o)):("identity"!==u&&q("ignoring unrecognized Content-Encoding "+u),o=e)}t.encoding&&(0!==t.dests.length?console.error("Ignoring encoding parameter as this stream is being piped to another stream which makes the encoding option invalid."):o.setEncoding(t.encoding)),t._paused&&o.pause(),t.responseContent=o,t.emit("response",e),t.dests.forEach((function(e){t.pipeDest(e)})),o.on("data",(function(r){t.timing&&!t.responseStarted&&(t.responseStartTime=(new Date).getTime(),e.responseStartTime=t.responseStartTime),t._destdata=!0,t.emit("data",r)})),o.once("end",(function(e){t.emit("end",e)})),o.on("error",(function(e){t.emit("error",e)})),o.on("close",(function(){t.emit("close")})),t.callback?t.readResponseBody(e):t.on("end",(function(){t._aborted?q("aborted",t.uri.href):t.emit("complete",e)})),q("finish init function",t.uri.href)}}else{q("strict ssl error",t.uri.href);var h=e.hasOwnProperty("socket")?e.socket.authorizationError:t.uri.href+" does not support SSL";t.emit("error",new Error("SSL Error: "+h))}},H.prototype.readResponseBody=function(e){var t=this;q("reading response's body");var r=[],i=0,n=[];t.on("data",(function(e){I.isBuffer(e)?e.length&&(i+=e.length,r.push(e)):n.push(e)})),t.on("end",(function(){if(q("end event",t.uri.href),t._aborted)return q("aborted",t.uri.href),r=[],void(i=0);if(i?(q("has body",t.uri.href,i),e.body=I.concat(r,i),null!==t.encoding&&(e.body=e.body.toString(t.encoding)),r=[],i=0):n.length&&("utf8"===t.encoding&&n[0].length>0&&"\ufeff"===n[0][0]&&(n[0]=n[0].substring(1)),e.body=n.join("")),t._json)try{e.body=JSON.parse(e.body,t._jsonReviver)}catch(e){q("invalid JSON received",t.uri.href)}q("emitting complete",t.uri.href),void 0!==e.body||t._json||(e.body=null===t.encoding?I.alloc(0):""),t.emit("complete",e,e.body)}))},H.prototype.abort=function(){this._aborted=!0,this.req?this.req.abort():this.response&&this.response.destroy(),this.emit("abort")},H.prototype.pipeDest=function(e){var t=this.response;if(e.headers&&!e.headersSent){if(t.caseless.has("content-type")){var r=t.caseless.has("content-type");e.setHeader?e.setHeader(r,t.headers[r]):e.headers[r]=t.headers[r]}if(t.caseless.has("content-length")){var i=t.caseless.has("content-length");e.setHeader?e.setHeader(i,t.headers[i]):e.headers[i]=t.headers[i]}}if(e.setHeader&&!e.headersSent){for(var n in t.headers)this.gzip&&"content-encoding"===n||e.setHeader(n,t.headers[n]);e.statusCode=t.statusCode}this.pipefilter&&this.pipefilter(t,e)},H.prototype.qs=function(e,t){var r;for(var i in r=!t&&this.uri.query?this._qs.parse(this.uri.query):{},e)r[i]=e[i];var n=this._qs.stringify(r);return""===n||(this.uri=a.parse(this.uri.href.split("?")[0]+"?"+n),this.url=this.uri,this.path=this.uri.path,"unix"===this.uri.host&&this.enableUnixSocket()),this},H.prototype.form=function(e){var t=this;return e?(/^application\/x-www-form-urlencoded\b/.test(t.getHeader("content-type"))||t.setHeader("content-type","application/x-www-form-urlencoded"),t.body="string"==typeof e?t._qs.rfc3986(e.toString("utf8")):t._qs.stringify(e).toString("utf8"),t):(t._form=new m,t._form.on("error",(function(e){e.message="form-data: "+e.message,t.emit("error",e),t.abort()})),t._form)},H.prototype.multipart=function(e){return this._multipart.onRequest(e),this._multipart.chunked||(this.body=this._multipart.body),this},H.prototype.json=function(e){return this.hasHeader("accept")||this.setHeader("accept","application/json"),"function"==typeof this.jsonReplacer&&(this._jsonReplacer=this.jsonReplacer),this._json=!0,"boolean"==typeof e?void 0!==this.body&&(/^application\/x-www-form-urlencoded\b/.test(this.getHeader("content-type"))?this.body=this._qs.rfc3986(this.body):this.body=O(this.body,this._jsonReplacer),this.hasHeader("content-type")||this.setHeader("content-type","application/json")):(this.body=O(e,this._jsonReplacer),this.hasHeader("content-type")||this.setHeader("content-type","application/json")),"function"==typeof this.jsonReviver&&(this._jsonReviver=this.jsonReviver),this},H.prototype.getHeader=function(e,t){var r,i;return t||(t=this.headers),Object.keys(t).forEach((function(n){n.length===e.length&&(i=new RegExp(e,"i"),n.match(i)&&(r=t[n]))})),r},H.prototype.enableUnixSocket=function(){var e=this.uri.path.split(":"),t=e[0],r=e[1];this.socketPath=t,this.uri.pathname=r,this.uri.path=r,this.uri.host=t,this.uri.hostname=t,this.uri.isUnix=!0},H.prototype.auth=function(e,t,r,i){return this._auth.onRequest(e,t,r,i),this},H.prototype.aws=function(e,t){if(!t)return this._aws=e,this;if(4===e.sign_version||"4"===e.sign_version){var r={host:this.uri.host,path:this.uri.path,method:this.method,headers:this.headers,body:this.body};e.service&&(r.service=e.service);var i=l.sign(r,{accessKeyId:e.key,secretAccessKey:e.secret,sessionToken:e.session});this.setHeader("authorization",i.headers.Authorization),this.setHeader("x-amz-date",i.headers["X-Amz-Date"]),i.headers["X-Amz-Security-Token"]&&this.setHeader("x-amz-security-token",i.headers["X-Amz-Security-Token"])}else{var n=new Date;this.setHeader("date",n.toUTCString());var a={key:e.key,secret:e.secret,verb:this.method.toUpperCase(),date:n,contentType:this.getHeader("content-type")||"",md5:this.getHeader("content-md5")||"",amazonHeaders:u.canonicalizeHeaders(this.headers)},o=this.uri.path;e.bucket&&o?a.resource="/"+e.bucket+o:e.bucket&&!o?a.resource="/"+e.bucket:!e.bucket&&o?a.resource=o:e.bucket||o||(a.resource="/"),a.resource=u.canonicalizeResource(a.resource),this.setHeader("authorization",u.authorization(a))}return this},H.prototype.httpSignature=function(e){var t=this;return h.signRequest({getHeader:function(e){return t.getHeader(e,t.headers)},setHeader:function(e,r){t.setHeader(e,r)},method:t.method,path:t.path},e),q("httpSignature authorization",t.getHeader("authorization")),t},H.prototype.hawk=function(e){this.setHeader("Authorization",M.header(this.uri,this.method,e))},H.prototype.oauth=function(e){return this._oauth.onRequest(e),this},H.prototype.jar=function(e){var t;if(0===this._redirect.redirectsFollowed&&(this.originalCookieHeader=this.getHeader("cookie")),e){var r=e&&e.getCookieString?e:B,i=this.uri.href;r&&(t=r.getCookieString(i))}else t=!1,this._disableCookies=!0;return t&&t.length&&(this.originalCookieHeader?this.setHeader("cookie",this.originalCookieHeader+"; "+t):this.setHeader("cookie",t)),this._jar=e,this},H.prototype.pipe=function(e,t){if(!this.response)return this.dests.push(e),s.Stream.prototype.pipe.call(this,e,t),e;if(this._destdata)this.emit("error",new Error("You cannot pipe after data has been emitted from the response."));else{if(!this._ended)return s.Stream.prototype.pipe.call(this,e,t),this.pipeDest(e),e;this.emit("error",new Error("You cannot pipe after the response has been ended."))}},H.prototype.write=function(){var e=this;if(!e._aborted)return e._started||e.start(),e.req?e.req.write.apply(e.req,arguments):void 0},H.prototype.end=function(e){this._aborted||(e&&this.write(e),this._started||this.start(),this.req&&this.req.end())},H.prototype.pause=function(){var e=this;e.responseContent?e.responseContent.pause.apply(e.responseContent,arguments):e._paused=!0},H.prototype.resume=function(){var e=this;e.responseContent?e.responseContent.resume.apply(e.responseContent,arguments):e._paused=!1},H.prototype.destroy=function(){this._ended?this.response&&this.response.destroy():this.end()},H.defaultProxyHeaderWhiteList=T.defaultProxyHeaderWhiteList.slice(),H.defaultProxyHeaderExclusiveList=T.defaultProxyHeaderExclusiveList.slice(),H.prototype.toJSON=L,e.exports=H}).call(this,r(3))},function(e,t,r){(function(t,i,n){var a=r(216),o=r(0),s=r(217),c=r(218),u=r(408),l=s.IncomingMessage,h=s.readyStates;var d=e.exports=function(e){var r,i=this;c.Writable.call(i),i._opts=e,i._body=[],i._headers={},e.auth&&i.setHeader("Authorization","Basic "+new t(e.auth).toString("base64")),Object.keys(e.headers).forEach((function(t){i.setHeader(t,e.headers[t])}));var n=!0;if("disable-fetch"===e.mode||"requestTimeout"in e&&!a.abortController)n=!1,r=!0;else if("prefer-streaming"===e.mode)r=!1;else if("allow-wrong-content-type"===e.mode)r=!a.overrideMimeType;else{if(e.mode&&"default"!==e.mode&&"prefer-fast"!==e.mode)throw new Error("Invalid value for opts.mode");r=!0}i._mode=function(e,t){return a.fetch&&t?"fetch":a.mozchunkedarraybuffer?"moz-chunked-arraybuffer":a.msstream?"ms-stream":a.arraybuffer&&e?"arraybuffer":a.vbArray&&e?"text:vbarray":"text"}(r,n),i._fetchTimer=null,i.on("finish",(function(){i._onFinish()}))};o(d,c.Writable),d.prototype.setHeader=function(e,t){var r=e.toLowerCase();-1===p.indexOf(r)&&(this._headers[r]={name:e,value:t})},d.prototype.getHeader=function(e){var t=this._headers[e.toLowerCase()];return t?t.value:null},d.prototype.removeHeader=function(e){delete this._headers[e.toLowerCase()]},d.prototype._onFinish=function(){var e=this;if(!e._destroyed){var r=e._opts,o=e._headers,s=null;"GET"!==r.method&&"HEAD"!==r.method&&(s=a.arraybuffer?u(t.concat(e._body)):a.blobConstructor?new i.Blob(e._body.map((function(e){return u(e)})),{type:(o["content-type"]||{}).value||""}):t.concat(e._body).toString());var c=[];if(Object.keys(o).forEach((function(e){var t=o[e].name,r=o[e].value;Array.isArray(r)?r.forEach((function(e){c.push([t,e])})):c.push([t,r])})),"fetch"===e._mode){var l=null;if(a.abortController){var d=new AbortController;l=d.signal,e._fetchAbortController=d,"requestTimeout"in r&&0!==r.requestTimeout&&(e._fetchTimer=i.setTimeout((function(){e.emit("requestTimeout"),e._fetchAbortController&&e._fetchAbortController.abort()}),r.requestTimeout))}i.fetch(e._opts.url,{method:e._opts.method,headers:c,body:s||void 0,mode:"cors",credentials:r.withCredentials?"include":"same-origin",signal:l}).then((function(t){e._fetchResponse=t,e._connect()}),(function(t){i.clearTimeout(e._fetchTimer),e._destroyed||e.emit("error",t)}))}else{var p=e._xhr=new i.XMLHttpRequest;try{p.open(e._opts.method,e._opts.url,!0)}catch(t){return void n.nextTick((function(){e.emit("error",t)}))}"responseType"in p&&(p.responseType=e._mode.split(":")[0]),"withCredentials"in p&&(p.withCredentials=!!r.withCredentials),"text"===e._mode&&"overrideMimeType"in p&&p.overrideMimeType("text/plain; charset=x-user-defined"),"requestTimeout"in r&&(p.timeout=r.requestTimeout,p.ontimeout=function(){e.emit("requestTimeout")}),c.forEach((function(e){p.setRequestHeader(e[0],e[1])})),e._response=null,p.onreadystatechange=function(){switch(p.readyState){case h.LOADING:case h.DONE:e._onXHRProgress()}},"moz-chunked-arraybuffer"===e._mode&&(p.onprogress=function(){e._onXHRProgress()}),p.onerror=function(){e._destroyed||e.emit("error",new Error("XHR error"))};try{p.send(s)}catch(t){return void n.nextTick((function(){e.emit("error",t)}))}}}},d.prototype._onXHRProgress=function(){(function(e){try{var t=e.status;return null!==t&&0!==t}catch(e){return!1}})(this._xhr)&&!this._destroyed&&(this._response||this._connect(),this._response._onXHRProgress())},d.prototype._connect=function(){var e=this;e._destroyed||(e._response=new l(e._xhr,e._fetchResponse,e._mode,e._fetchTimer),e._response.on("error",(function(t){e.emit("error",t)})),e.emit("response",e._response))},d.prototype._write=function(e,t,r){this._body.push(e),r()},d.prototype.abort=d.prototype.destroy=function(){this._destroyed=!0,i.clearTimeout(this._fetchTimer),this._response&&(this._response._destroyed=!0),this._xhr?this._xhr.abort():this._fetchAbortController&&this._fetchAbortController.abort()},d.prototype.end=function(e,t,r){"function"==typeof e&&(r=e,e=void 0),c.Writable.prototype.end.call(this,e,t,r)},d.prototype.flushHeaders=function(){},d.prototype.setTimeout=function(){},d.prototype.setNoDelay=function(){},d.prototype.setSocketKeepAlive=function(){};var p=["accept-charset","accept-encoding","access-control-request-headers","access-control-request-method","connection","content-length","cookie","cookie2","date","dnt","expect","host","keep-alive","origin","referer","te","trailer","transfer-encoding","upgrade","via"]}).call(this,r(2).Buffer,r(8),r(3))},function(e,t){},function(e,t,r){"use strict";var i=r(1).Buffer,n=r(406);e.exports=function(){function e(){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.head=null,this.tail=null,this.length=0}return e.prototype.push=function(e){var t={data:e,next:null};this.length>0?this.tail.next=t:this.head=t,this.tail=t,++this.length},e.prototype.unshift=function(e){var t={data:e,next:this.head};0===this.length&&(this.tail=t),this.head=t,++this.length},e.prototype.shift=function(){if(0!==this.length){var e=this.head.data;return 1===this.length?this.head=this.tail=null:this.head=this.head.next,--this.length,e}},e.prototype.clear=function(){this.head=this.tail=null,this.length=0},e.prototype.join=function(e){if(0===this.length)return"";for(var t=this.head,r=""+t.data;t=t.next;)r+=e+t.data;return r},e.prototype.concat=function(e){if(0===this.length)return i.alloc(0);if(1===this.length)return this.head.data;for(var t,r,n,a=i.allocUnsafe(e>>>0),o=this.head,s=0;o;)t=o.data,r=a,n=s,t.copy(r,n),s+=o.data.length,o=o.next;return a},e}(),n&&n.inspect&&n.inspect.custom&&(e.exports.prototype[n.inspect.custom]=function(){var e=n.inspect({length:this.length});return this.constructor.name+" "+e})},function(e,t){},function(e,t,r){"use strict";e.exports=a;var i=r(223),n=Object.create(r(21));function a(e){if(!(this instanceof a))return new a(e);i.call(this,e)}n.inherits=r(0),n.inherits(a,i),a.prototype._transform=function(e,t,r){r(null,e)}},function(e,t,r){var i=r(2).Buffer;e.exports=function(e){if(e instanceof Uint8Array){if(0===e.byteOffset&&e.byteLength===e.buffer.byteLength)return e.buffer;if("function"==typeof e.buffer.slice)return e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}if(i.isBuffer(e)){for(var t=new Uint8Array(e.length),r=e.length,n=0;n=c?o=new RangeError(u):t=i.concat(n,a),n=[],e.close(),r(o,t)}e.on("error",(function(t){e.removeListener("end",s),e.removeListener("readable",o),r(t)})),e.on("end",s),e.end(t),o()}function v(e,t){if("string"==typeof t&&(t=i.from(t)),!i.isBuffer(t))throw new TypeError("Not a string or buffer");var r=e._finishFlushFlag;return e._processChunk(t,r)}function y(e){if(!(this instanceof y))return new y(e);N.call(this,e,a.DEFLATE)}function b(e){if(!(this instanceof b))return new b(e);N.call(this,e,a.INFLATE)}function E(e){if(!(this instanceof E))return new E(e);N.call(this,e,a.GZIP)}function w(e){if(!(this instanceof w))return new w(e);N.call(this,e,a.GUNZIP)}function S(e){if(!(this instanceof S))return new S(e);N.call(this,e,a.DEFLATERAW)}function k(e){if(!(this instanceof k))return new k(e);N.call(this,e,a.INFLATERAW)}function x(e){if(!(this instanceof x))return new x(e);N.call(this,e,a.UNZIP)}function M(e){return e===a.Z_NO_FLUSH||e===a.Z_PARTIAL_FLUSH||e===a.Z_SYNC_FLUSH||e===a.Z_FULL_FLUSH||e===a.Z_FINISH||e===a.Z_BLOCK}function N(e,r){var o=this;if(this._opts=e=e||{},this._chunkSize=e.chunkSize||t.Z_DEFAULT_CHUNK,n.call(this,e),e.flush&&!M(e.flush))throw new Error("Invalid flush flag: "+e.flush);if(e.finishFlush&&!M(e.finishFlush))throw new Error("Invalid flush flag: "+e.finishFlush);if(this._flushFlag=e.flush||a.Z_NO_FLUSH,this._finishFlushFlag=void 0!==e.finishFlush?e.finishFlush:a.Z_FINISH,e.chunkSize&&(e.chunkSizet.Z_MAX_CHUNK))throw new Error("Invalid chunk size: "+e.chunkSize);if(e.windowBits&&(e.windowBitst.Z_MAX_WINDOWBITS))throw new Error("Invalid windowBits: "+e.windowBits);if(e.level&&(e.levelt.Z_MAX_LEVEL))throw new Error("Invalid compression level: "+e.level);if(e.memLevel&&(e.memLevelt.Z_MAX_MEMLEVEL))throw new Error("Invalid memLevel: "+e.memLevel);if(e.strategy&&e.strategy!=t.Z_FILTERED&&e.strategy!=t.Z_HUFFMAN_ONLY&&e.strategy!=t.Z_RLE&&e.strategy!=t.Z_FIXED&&e.strategy!=t.Z_DEFAULT_STRATEGY)throw new Error("Invalid strategy: "+e.strategy);if(e.dictionary&&!i.isBuffer(e.dictionary))throw new Error("Invalid dictionary: it should be a Buffer instance");this._handle=new a.Zlib(r);var s=this;this._hadError=!1,this._handle.onerror=function(e,r){j(s),s._hadError=!0;var i=new Error(e);i.errno=r,i.code=t.codes[r],s.emit("error",i)};var c=t.Z_DEFAULT_COMPRESSION;"number"==typeof e.level&&(c=e.level);var u=t.Z_DEFAULT_STRATEGY;"number"==typeof e.strategy&&(u=e.strategy),this._handle.init(e.windowBits||t.Z_DEFAULT_WINDOWBITS,c,e.memLevel||t.Z_DEFAULT_MEMLEVEL,u,e.dictionary),this._buffer=i.allocUnsafe(this._chunkSize),this._offset=0,this._level=c,this._strategy=u,this.once("end",this.close),Object.defineProperty(this,"_closed",{get:function(){return!o._handle},configurable:!0,enumerable:!0})}function j(t,r){r&&e.nextTick(r),t._handle&&(t._handle.close(),t._handle=null)}function T(e){e.emit("close")}Object.defineProperty(t,"codes",{enumerable:!0,value:Object.freeze(p),writable:!1}),t.Deflate=y,t.Inflate=b,t.Gzip=E,t.Gunzip=w,t.DeflateRaw=S,t.InflateRaw=k,t.Unzip=x,t.createDeflate=function(e){return new y(e)},t.createInflate=function(e){return new b(e)},t.createDeflateRaw=function(e){return new S(e)},t.createInflateRaw=function(e){return new k(e)},t.createGzip=function(e){return new E(e)},t.createGunzip=function(e){return new w(e)},t.createUnzip=function(e){return new x(e)},t.deflate=function(e,t,r){return"function"==typeof t&&(r=t,t={}),_(new y(t),e,r)},t.deflateSync=function(e,t){return v(new y(t),e)},t.gzip=function(e,t,r){return"function"==typeof t&&(r=t,t={}),_(new E(t),e,r)},t.gzipSync=function(e,t){return v(new E(t),e)},t.deflateRaw=function(e,t,r){return"function"==typeof t&&(r=t,t={}),_(new S(t),e,r)},t.deflateRawSync=function(e,t){return v(new S(t),e)},t.unzip=function(e,t,r){return"function"==typeof t&&(r=t,t={}),_(new x(t),e,r)},t.unzipSync=function(e,t){return v(new x(t),e)},t.inflate=function(e,t,r){return"function"==typeof t&&(r=t,t={}),_(new b(t),e,r)},t.inflateSync=function(e,t){return v(new b(t),e)},t.gunzip=function(e,t,r){return"function"==typeof t&&(r=t,t={}),_(new w(t),e,r)},t.gunzipSync=function(e,t){return v(new w(t),e)},t.inflateRaw=function(e,t,r){return"function"==typeof t&&(r=t,t={}),_(new k(t),e,r)},t.inflateRawSync=function(e,t){return v(new k(t),e)},o.inherits(N,n),N.prototype.params=function(r,i,n){if(rt.Z_MAX_LEVEL)throw new RangeError("Invalid compression level: "+r);if(i!=t.Z_FILTERED&&i!=t.Z_HUFFMAN_ONLY&&i!=t.Z_RLE&&i!=t.Z_FIXED&&i!=t.Z_DEFAULT_STRATEGY)throw new TypeError("Invalid strategy: "+i);if(this._level!==r||this._strategy!==i){var o=this;this.flush(a.Z_SYNC_FLUSH,(function(){s(o._handle,"zlib binding closed"),o._handle.params(r,i),o._hadError||(o._level=r,o._strategy=i,n&&n())}))}else e.nextTick(n)},N.prototype.reset=function(){return s(this._handle,"zlib binding closed"),this._handle.reset()},N.prototype._flush=function(e){this._transform(i.alloc(0),"",e)},N.prototype.flush=function(t,r){var n=this,o=this._writableState;("function"==typeof t||void 0===t&&!r)&&(r=t,t=a.Z_FULL_FLUSH),o.ended?r&&e.nextTick(r):o.ending?r&&this.once("end",r):o.needDrain?r&&this.once("drain",(function(){return n.flush(t,r)})):(this._flushFlag=t,this.write(i.alloc(0),"",r))},N.prototype.close=function(t){j(this,t),e.nextTick(T,this)},N.prototype._transform=function(e,t,r){var n,o=this._writableState,s=(o.ending||o.ended)&&(!e||o.length===e.length);return null===e||i.isBuffer(e)?this._handle?(s?n=this._finishFlushFlag:(n=this._flushFlag,e.length>=o.length&&(this._flushFlag=this._opts.flush||a.Z_NO_FLUSH)),void this._processChunk(e,n,r)):r(new Error("zlib binding closed")):r(new Error("invalid input"))},N.prototype._processChunk=function(e,t,r){var n=e&&e.length,a=this._chunkSize-this._offset,o=0,l=this,h="function"==typeof r;if(!h){var d,p=[],f=0;this.on("error",(function(e){d=e})),s(this._handle,"zlib binding closed");do{var m=this._handle.writeSync(t,e,o,n,this._buffer,this._offset,a)}while(!this._hadError&&v(m[0],m[1]));if(this._hadError)throw d;if(f>=c)throw j(this),new RangeError(u);var g=i.concat(p,f);return j(this),g}s(this._handle,"zlib binding closed");var _=this._handle.write(t,e,o,n,this._buffer,this._offset,a);function v(c,u){if(this&&(this.buffer=null,this.callback=null),!l._hadError){var d=a-u;if(s(d>=0,"have should not go down"),d>0){var m=l._buffer.slice(l._offset,l._offset+d);l._offset+=d,h?l.push(m):(p.push(m),f+=m.length)}if((0===u||l._offset>=l._chunkSize)&&(a=l._chunkSize,l._offset=0,l._buffer=i.allocUnsafe(l._chunkSize)),0===u){if(o+=n-c,n=c,!h)return!0;var g=l._handle.write(t,e,o,n,l._buffer,l._offset,l._chunkSize);return g.callback=v,void(g.buffer=e)}if(!h)return!1;r()}}_.buffer=e,_.callback=v},o.inherits(y,N),o.inherits(b,N),o.inherits(E,N),o.inherits(w,N),o.inherits(S,N),o.inherits(k,N),o.inherits(x,N)}).call(this,r(3))},function(e,t,r){"use strict";(function(e,i){var n=r(4),a=r(413),o=r(414),s=r(417),c=r(420);for(var u in c)t[u]=c[u];t.NONE=0,t.DEFLATE=1,t.INFLATE=2,t.GZIP=3,t.GUNZIP=4,t.DEFLATERAW=5,t.INFLATERAW=6,t.UNZIP=7;function l(e){if("number"!=typeof e||et.UNZIP)throw new TypeError("Bad argument");this.dictionary=null,this.err=0,this.flush=0,this.init_done=!1,this.level=0,this.memLevel=0,this.mode=e,this.strategy=0,this.windowBits=0,this.write_in_progress=!1,this.pending_close=!1,this.gzip_id_bytes_read=0}l.prototype.close=function(){this.write_in_progress?this.pending_close=!0:(this.pending_close=!1,n(this.init_done,"close before init"),n(this.mode<=t.UNZIP),this.mode===t.DEFLATE||this.mode===t.GZIP||this.mode===t.DEFLATERAW?o.deflateEnd(this.strm):this.mode!==t.INFLATE&&this.mode!==t.GUNZIP&&this.mode!==t.INFLATERAW&&this.mode!==t.UNZIP||s.inflateEnd(this.strm),this.mode=t.NONE,this.dictionary=null)},l.prototype.write=function(e,t,r,i,n,a,o){return this._write(!0,e,t,r,i,n,a,o)},l.prototype.writeSync=function(e,t,r,i,n,a,o){return this._write(!1,e,t,r,i,n,a,o)},l.prototype._write=function(r,a,o,s,c,u,l,h){if(n.equal(arguments.length,8),n(this.init_done,"write before init"),n(this.mode!==t.NONE,"already finalized"),n.equal(!1,this.write_in_progress,"write already in progress"),n.equal(!1,this.pending_close,"close is pending"),this.write_in_progress=!0,n.equal(!1,void 0===a,"must provide flush value"),this.write_in_progress=!0,a!==t.Z_NO_FLUSH&&a!==t.Z_PARTIAL_FLUSH&&a!==t.Z_SYNC_FLUSH&&a!==t.Z_FULL_FLUSH&&a!==t.Z_FINISH&&a!==t.Z_BLOCK)throw new Error("Invalid flush value");if(null==o&&(o=e.alloc(0),c=0,s=0),this.strm.avail_in=c,this.strm.input=o,this.strm.next_in=s,this.strm.avail_out=h,this.strm.output=u,this.strm.next_out=l,this.flush=a,!r)return this._process(),this._checkError()?this._afterSync():void 0;var d=this;return i.nextTick((function(){d._process(),d._after()})),this},l.prototype._afterSync=function(){var e=this.strm.avail_out,t=this.strm.avail_in;return this.write_in_progress=!1,[t,e]},l.prototype._process=function(){var e=null;switch(this.mode){case t.DEFLATE:case t.GZIP:case t.DEFLATERAW:this.err=o.deflate(this.strm,this.flush);break;case t.UNZIP:switch(this.strm.avail_in>0&&(e=this.strm.next_in),this.gzip_id_bytes_read){case 0:if(null===e)break;if(31!==this.strm.input[e]){this.mode=t.INFLATE;break}if(this.gzip_id_bytes_read=1,e++,1===this.strm.avail_in)break;case 1:if(null===e)break;139===this.strm.input[e]?(this.gzip_id_bytes_read=2,this.mode=t.GUNZIP):this.mode=t.INFLATE;break;default:throw new Error("invalid number of gzip magic number bytes read")}case t.INFLATE:case t.GUNZIP:case t.INFLATERAW:for(this.err=s.inflate(this.strm,this.flush),this.err===t.Z_NEED_DICT&&this.dictionary&&(this.err=s.inflateSetDictionary(this.strm,this.dictionary),this.err===t.Z_OK?this.err=s.inflate(this.strm,this.flush):this.err===t.Z_DATA_ERROR&&(this.err=t.Z_NEED_DICT));this.strm.avail_in>0&&this.mode===t.GUNZIP&&this.err===t.Z_STREAM_END&&0!==this.strm.next_in[0];)this.reset(),this.err=s.inflate(this.strm,this.flush);break;default:throw new Error("Unknown mode "+this.mode)}},l.prototype._checkError=function(){switch(this.err){case t.Z_OK:case t.Z_BUF_ERROR:if(0!==this.strm.avail_out&&this.flush===t.Z_FINISH)return this._error("unexpected end of file"),!1;break;case t.Z_STREAM_END:break;case t.Z_NEED_DICT:return null==this.dictionary?this._error("Missing dictionary"):this._error("Bad dictionary"),!1;default:return this._error("Zlib error"),!1}return!0},l.prototype._after=function(){if(this._checkError()){var e=this.strm.avail_out,t=this.strm.avail_in;this.write_in_progress=!1,this.callback(t,e),this.pending_close&&this.close()}},l.prototype._error=function(e){this.strm.msg&&(e=this.strm.msg),this.onerror(e,this.err),this.write_in_progress=!1,this.pending_close&&this.close()},l.prototype.init=function(e,r,i,a,o){n(4===arguments.length||5===arguments.length,"init(windowBits, level, memLevel, strategy, [dictionary])"),n(e>=8&&e<=15,"invalid windowBits"),n(r>=-1&&r<=9,"invalid compression level"),n(i>=1&&i<=9,"invalid memlevel"),n(a===t.Z_FILTERED||a===t.Z_HUFFMAN_ONLY||a===t.Z_RLE||a===t.Z_FIXED||a===t.Z_DEFAULT_STRATEGY,"invalid strategy"),this._init(r,e,i,a,o),this._setDictionary()},l.prototype.params=function(){throw new Error("deflateParams Not supported")},l.prototype.reset=function(){this._reset(),this._setDictionary()},l.prototype._init=function(e,r,i,n,c){switch(this.level=e,this.windowBits=r,this.memLevel=i,this.strategy=n,this.flush=t.Z_NO_FLUSH,this.err=t.Z_OK,this.mode!==t.GZIP&&this.mode!==t.GUNZIP||(this.windowBits+=16),this.mode===t.UNZIP&&(this.windowBits+=32),this.mode!==t.DEFLATERAW&&this.mode!==t.INFLATERAW||(this.windowBits=-1*this.windowBits),this.strm=new a,this.mode){case t.DEFLATE:case t.GZIP:case t.DEFLATERAW:this.err=o.deflateInit2(this.strm,this.level,t.Z_DEFLATED,this.windowBits,this.memLevel,this.strategy);break;case t.INFLATE:case t.GUNZIP:case t.INFLATERAW:case t.UNZIP:this.err=s.inflateInit2(this.strm,this.windowBits);break;default:throw new Error("Unknown mode "+this.mode)}this.err!==t.Z_OK&&this._error("Init error"),this.dictionary=c,this.write_in_progress=!1,this.init_done=!0},l.prototype._setDictionary=function(){if(null!=this.dictionary){switch(this.err=t.Z_OK,this.mode){case t.DEFLATE:case t.DEFLATERAW:this.err=o.deflateSetDictionary(this.strm,this.dictionary)}this.err!==t.Z_OK&&this._error("Failed to set dictionary")}},l.prototype._reset=function(){switch(this.err=t.Z_OK,this.mode){case t.DEFLATE:case t.DEFLATERAW:case t.GZIP:this.err=o.deflateReset(this.strm);break;case t.INFLATE:case t.INFLATERAW:case t.GUNZIP:this.err=s.inflateReset(this.strm)}this.err!==t.Z_OK&&this._error("Failed to reset stream")},t.Zlib=l}).call(this,r(2).Buffer,r(3))},function(e,t,r){"use strict";e.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}},function(e,t,r){"use strict";var i,n=r(86),a=r(415),o=r(224),s=r(225),c=r(416);function u(e,t){return e.msg=c[t],t}function l(e){return(e<<1)-(e>4?9:0)}function h(e){for(var t=e.length;--t>=0;)e[t]=0}function d(e){var t=e.state,r=t.pending;r>e.avail_out&&(r=e.avail_out),0!==r&&(n.arraySet(e.output,t.pending_buf,t.pending_out,r,e.next_out),e.next_out+=r,t.pending_out+=r,e.total_out+=r,e.avail_out-=r,t.pending-=r,0===t.pending&&(t.pending_out=0))}function p(e,t){a._tr_flush_block(e,e.block_start>=0?e.block_start:-1,e.strstart-e.block_start,t),e.block_start=e.strstart,d(e.strm)}function f(e,t){e.pending_buf[e.pending++]=t}function m(e,t){e.pending_buf[e.pending++]=t>>>8&255,e.pending_buf[e.pending++]=255&t}function g(e,t){var r,i,n=e.max_chain_length,a=e.strstart,o=e.prev_length,s=e.nice_match,c=e.strstart>e.w_size-262?e.strstart-(e.w_size-262):0,u=e.window,l=e.w_mask,h=e.prev,d=e.strstart+258,p=u[a+o-1],f=u[a+o];e.prev_length>=e.good_match&&(n>>=2),s>e.lookahead&&(s=e.lookahead);do{if(u[(r=t)+o]===f&&u[r+o-1]===p&&u[r]===u[a]&&u[++r]===u[a+1]){a+=2,r++;do{}while(u[++a]===u[++r]&&u[++a]===u[++r]&&u[++a]===u[++r]&&u[++a]===u[++r]&&u[++a]===u[++r]&&u[++a]===u[++r]&&u[++a]===u[++r]&&u[++a]===u[++r]&&ao){if(e.match_start=t,o=i,i>=s)break;p=u[a+o-1],f=u[a+o]}}}while((t=h[t&l])>c&&0!=--n);return o<=e.lookahead?o:e.lookahead}function _(e){var t,r,i,a,c,u,l,h,d,p,f=e.w_size;do{if(a=e.window_size-e.lookahead-e.strstart,e.strstart>=f+(f-262)){n.arraySet(e.window,e.window,f,f,0),e.match_start-=f,e.strstart-=f,e.block_start-=f,t=r=e.hash_size;do{i=e.head[--t],e.head[t]=i>=f?i-f:0}while(--r);t=r=f;do{i=e.prev[--t],e.prev[t]=i>=f?i-f:0}while(--r);a+=f}if(0===e.strm.avail_in)break;if(u=e.strm,l=e.window,h=e.strstart+e.lookahead,d=a,p=void 0,(p=u.avail_in)>d&&(p=d),r=0===p?0:(u.avail_in-=p,n.arraySet(l,u.input,u.next_in,p,h),1===u.state.wrap?u.adler=o(u.adler,l,p,h):2===u.state.wrap&&(u.adler=s(u.adler,l,p,h)),u.next_in+=p,u.total_in+=p,p),e.lookahead+=r,e.lookahead+e.insert>=3)for(c=e.strstart-e.insert,e.ins_h=e.window[c],e.ins_h=(e.ins_h<=3&&(e.ins_h=(e.ins_h<=3)if(i=a._tr_tally(e,e.strstart-e.match_start,e.match_length-3),e.lookahead-=e.match_length,e.match_length<=e.max_lazy_match&&e.lookahead>=3){e.match_length--;do{e.strstart++,e.ins_h=(e.ins_h<=3&&(e.ins_h=(e.ins_h<4096)&&(e.match_length=2)),e.prev_length>=3&&e.match_length<=e.prev_length){n=e.strstart+e.lookahead-3,i=a._tr_tally(e,e.strstart-1-e.prev_match,e.prev_length-3),e.lookahead-=e.prev_length-1,e.prev_length-=2;do{++e.strstart<=n&&(e.ins_h=(e.ins_h<15&&(s=2,i-=16),a<1||a>9||8!==r||i<8||i>15||t<0||t>9||o<0||o>4)return u(e,-2);8===i&&(i=9);var c=new E;return e.state=c,c.strm=e,c.wrap=s,c.gzhead=null,c.w_bits=i,c.w_size=1<e.pending_buf_size-5&&(r=e.pending_buf_size-5);;){if(e.lookahead<=1){if(_(e),0===e.lookahead&&0===t)return 1;if(0===e.lookahead)break}e.strstart+=e.lookahead,e.lookahead=0;var i=e.block_start+r;if((0===e.strstart||e.strstart>=i)&&(e.lookahead=e.strstart-i,e.strstart=i,p(e,!1),0===e.strm.avail_out))return 1;if(e.strstart-e.block_start>=e.w_size-262&&(p(e,!1),0===e.strm.avail_out))return 1}return e.insert=0,4===t?(p(e,!0),0===e.strm.avail_out?3:4):(e.strstart>e.block_start&&(p(e,!1),e.strm.avail_out),1)})),new b(4,4,8,4,v),new b(4,5,16,8,v),new b(4,6,32,32,v),new b(4,4,16,16,y),new b(8,16,32,32,y),new b(8,16,128,128,y),new b(8,32,128,256,y),new b(32,128,258,1024,y),new b(32,258,258,4096,y)],t.deflateInit=function(e,t){return k(e,t,8,15,8,0)},t.deflateInit2=k,t.deflateReset=S,t.deflateResetKeep=w,t.deflateSetHeader=function(e,t){return e&&e.state?2!==e.state.wrap?-2:(e.state.gzhead=t,0):-2},t.deflate=function(e,t){var r,n,o,c;if(!e||!e.state||t>5||t<0)return e?u(e,-2):-2;if(n=e.state,!e.output||!e.input&&0!==e.avail_in||666===n.status&&4!==t)return u(e,0===e.avail_out?-5:-2);if(n.strm=e,r=n.last_flush,n.last_flush=t,42===n.status)if(2===n.wrap)e.adler=0,f(n,31),f(n,139),f(n,8),n.gzhead?(f(n,(n.gzhead.text?1:0)+(n.gzhead.hcrc?2:0)+(n.gzhead.extra?4:0)+(n.gzhead.name?8:0)+(n.gzhead.comment?16:0)),f(n,255&n.gzhead.time),f(n,n.gzhead.time>>8&255),f(n,n.gzhead.time>>16&255),f(n,n.gzhead.time>>24&255),f(n,9===n.level?2:n.strategy>=2||n.level<2?4:0),f(n,255&n.gzhead.os),n.gzhead.extra&&n.gzhead.extra.length&&(f(n,255&n.gzhead.extra.length),f(n,n.gzhead.extra.length>>8&255)),n.gzhead.hcrc&&(e.adler=s(e.adler,n.pending_buf,n.pending,0)),n.gzindex=0,n.status=69):(f(n,0),f(n,0),f(n,0),f(n,0),f(n,0),f(n,9===n.level?2:n.strategy>=2||n.level<2?4:0),f(n,3),n.status=113);else{var g=8+(n.w_bits-8<<4)<<8;g|=(n.strategy>=2||n.level<2?0:n.level<6?1:6===n.level?2:3)<<6,0!==n.strstart&&(g|=32),g+=31-g%31,n.status=113,m(n,g),0!==n.strstart&&(m(n,e.adler>>>16),m(n,65535&e.adler)),e.adler=1}if(69===n.status)if(n.gzhead.extra){for(o=n.pending;n.gzindex<(65535&n.gzhead.extra.length)&&(n.pending!==n.pending_buf_size||(n.gzhead.hcrc&&n.pending>o&&(e.adler=s(e.adler,n.pending_buf,n.pending-o,o)),d(e),o=n.pending,n.pending!==n.pending_buf_size));)f(n,255&n.gzhead.extra[n.gzindex]),n.gzindex++;n.gzhead.hcrc&&n.pending>o&&(e.adler=s(e.adler,n.pending_buf,n.pending-o,o)),n.gzindex===n.gzhead.extra.length&&(n.gzindex=0,n.status=73)}else n.status=73;if(73===n.status)if(n.gzhead.name){o=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>o&&(e.adler=s(e.adler,n.pending_buf,n.pending-o,o)),d(e),o=n.pending,n.pending===n.pending_buf_size)){c=1;break}c=n.gzindexo&&(e.adler=s(e.adler,n.pending_buf,n.pending-o,o)),0===c&&(n.gzindex=0,n.status=91)}else n.status=91;if(91===n.status)if(n.gzhead.comment){o=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>o&&(e.adler=s(e.adler,n.pending_buf,n.pending-o,o)),d(e),o=n.pending,n.pending===n.pending_buf_size)){c=1;break}c=n.gzindexo&&(e.adler=s(e.adler,n.pending_buf,n.pending-o,o)),0===c&&(n.status=103)}else n.status=103;if(103===n.status&&(n.gzhead.hcrc?(n.pending+2>n.pending_buf_size&&d(e),n.pending+2<=n.pending_buf_size&&(f(n,255&e.adler),f(n,e.adler>>8&255),e.adler=0,n.status=113)):n.status=113),0!==n.pending){if(d(e),0===e.avail_out)return n.last_flush=-1,0}else if(0===e.avail_in&&l(t)<=l(r)&&4!==t)return u(e,-5);if(666===n.status&&0!==e.avail_in)return u(e,-5);if(0!==e.avail_in||0!==n.lookahead||0!==t&&666!==n.status){var v=2===n.strategy?function(e,t){for(var r;;){if(0===e.lookahead&&(_(e),0===e.lookahead)){if(0===t)return 1;break}if(e.match_length=0,r=a._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++,r&&(p(e,!1),0===e.strm.avail_out))return 1}return e.insert=0,4===t?(p(e,!0),0===e.strm.avail_out?3:4):e.last_lit&&(p(e,!1),0===e.strm.avail_out)?1:2}(n,t):3===n.strategy?function(e,t){for(var r,i,n,o,s=e.window;;){if(e.lookahead<=258){if(_(e),e.lookahead<=258&&0===t)return 1;if(0===e.lookahead)break}if(e.match_length=0,e.lookahead>=3&&e.strstart>0&&(i=s[n=e.strstart-1])===s[++n]&&i===s[++n]&&i===s[++n]){o=e.strstart+258;do{}while(i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&i===s[++n]&&ne.lookahead&&(e.match_length=e.lookahead)}if(e.match_length>=3?(r=a._tr_tally(e,1,e.match_length-3),e.lookahead-=e.match_length,e.strstart+=e.match_length,e.match_length=0):(r=a._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++),r&&(p(e,!1),0===e.strm.avail_out))return 1}return e.insert=0,4===t?(p(e,!0),0===e.strm.avail_out?3:4):e.last_lit&&(p(e,!1),0===e.strm.avail_out)?1:2}(n,t):i[n.level].func(n,t);if(3!==v&&4!==v||(n.status=666),1===v||3===v)return 0===e.avail_out&&(n.last_flush=-1),0;if(2===v&&(1===t?a._tr_align(n):5!==t&&(a._tr_stored_block(n,0,0,!1),3===t&&(h(n.head),0===n.lookahead&&(n.strstart=0,n.block_start=0,n.insert=0))),d(e),0===e.avail_out))return n.last_flush=-1,0}return 4!==t?0:n.wrap<=0?1:(2===n.wrap?(f(n,255&e.adler),f(n,e.adler>>8&255),f(n,e.adler>>16&255),f(n,e.adler>>24&255),f(n,255&e.total_in),f(n,e.total_in>>8&255),f(n,e.total_in>>16&255),f(n,e.total_in>>24&255)):(m(n,e.adler>>>16),m(n,65535&e.adler)),d(e),n.wrap>0&&(n.wrap=-n.wrap),0!==n.pending?0:1)},t.deflateEnd=function(e){var t;return e&&e.state?42!==(t=e.state.status)&&69!==t&&73!==t&&91!==t&&103!==t&&113!==t&&666!==t?u(e,-2):(e.state=null,113===t?u(e,-3):0):-2},t.deflateSetDictionary=function(e,t){var r,i,a,s,c,u,l,d,p=t.length;if(!e||!e.state)return-2;if(2===(s=(r=e.state).wrap)||1===s&&42!==r.status||r.lookahead)return-2;for(1===s&&(e.adler=o(e.adler,t,p,0)),r.wrap=0,p>=r.w_size&&(0===s&&(h(r.head),r.strstart=0,r.block_start=0,r.insert=0),d=new n.Buf8(r.w_size),n.arraySet(d,t,p-r.w_size,r.w_size,0),t=d,p=r.w_size),c=e.avail_in,u=e.next_in,l=e.input,e.avail_in=p,e.next_in=0,e.input=t,_(r);r.lookahead>=3;){i=r.strstart,a=r.lookahead-2;do{r.ins_h=(r.ins_h<=0;)e[t]=0}var a=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],o=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],s=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],c=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],u=new Array(576);n(u);var l=new Array(60);n(l);var h=new Array(512);n(h);var d=new Array(256);n(d);var p=new Array(29);n(p);var f,m,g,_=new Array(30);function v(e,t,r,i,n){this.static_tree=e,this.extra_bits=t,this.extra_base=r,this.elems=i,this.max_length=n,this.has_stree=e&&e.length}function y(e,t){this.dyn_tree=e,this.max_code=0,this.stat_desc=t}function b(e){return e<256?h[e]:h[256+(e>>>7)]}function E(e,t){e.pending_buf[e.pending++]=255&t,e.pending_buf[e.pending++]=t>>>8&255}function w(e,t,r){e.bi_valid>16-r?(e.bi_buf|=t<>16-e.bi_valid,e.bi_valid+=r-16):(e.bi_buf|=t<>>=1,r<<=1}while(--t>0);return r>>>1}function x(e,t,r){var i,n,a=new Array(16),o=0;for(i=1;i<=15;i++)a[i]=o=o+r[i-1]<<1;for(n=0;n<=t;n++){var s=e[2*n+1];0!==s&&(e[2*n]=k(a[s]++,s))}}function M(e){var t;for(t=0;t<286;t++)e.dyn_ltree[2*t]=0;for(t=0;t<30;t++)e.dyn_dtree[2*t]=0;for(t=0;t<19;t++)e.bl_tree[2*t]=0;e.dyn_ltree[512]=1,e.opt_len=e.static_len=0,e.last_lit=e.matches=0}function N(e){e.bi_valid>8?E(e,e.bi_buf):e.bi_valid>0&&(e.pending_buf[e.pending++]=e.bi_buf),e.bi_buf=0,e.bi_valid=0}function j(e,t,r,i){var n=2*t,a=2*r;return e[n]>1;r>=1;r--)T(e,a,r);n=c;do{r=e.heap[1],e.heap[1]=e.heap[e.heap_len--],T(e,a,1),i=e.heap[1],e.heap[--e.heap_max]=r,e.heap[--e.heap_max]=i,a[2*n]=a[2*r]+a[2*i],e.depth[n]=(e.depth[r]>=e.depth[i]?e.depth[r]:e.depth[i])+1,a[2*r+1]=a[2*i+1]=n,e.heap[1]=n++,T(e,a,1)}while(e.heap_len>=2);e.heap[--e.heap_max]=e.heap[1],function(e,t){var r,i,n,a,o,s,c=t.dyn_tree,u=t.max_code,l=t.stat_desc.static_tree,h=t.stat_desc.has_stree,d=t.stat_desc.extra_bits,p=t.stat_desc.extra_base,f=t.stat_desc.max_length,m=0;for(a=0;a<=15;a++)e.bl_count[a]=0;for(c[2*e.heap[e.heap_max]+1]=0,r=e.heap_max+1;r<573;r++)(a=c[2*c[2*(i=e.heap[r])+1]+1]+1)>f&&(a=f,m++),c[2*i+1]=a,i>u||(e.bl_count[a]++,o=0,i>=p&&(o=d[i-p]),s=c[2*i],e.opt_len+=s*(a+o),h&&(e.static_len+=s*(l[2*i+1]+o)));if(0!==m){do{for(a=f-1;0===e.bl_count[a];)a--;e.bl_count[a]--,e.bl_count[a+1]+=2,e.bl_count[f]--,m-=2}while(m>0);for(a=f;0!==a;a--)for(i=e.bl_count[a];0!==i;)(n=e.heap[--r])>u||(c[2*n+1]!==a&&(e.opt_len+=(a-c[2*n+1])*c[2*n],c[2*n+1]=a),i--)}}(e,t),x(a,u,e.bl_count)}function O(e,t,r){var i,n,a=-1,o=t[1],s=0,c=7,u=4;for(0===o&&(c=138,u=3),t[2*(r+1)+1]=65535,i=0;i<=r;i++)n=o,o=t[2*(i+1)+1],++s>=7;i<30;i++)for(_[i]=n<<7,e=0;e<1<0?(2===e.strm.data_type&&(e.strm.data_type=function(e){var t,r=4093624447;for(t=0;t<=31;t++,r>>>=1)if(1&r&&0!==e.dyn_ltree[2*t])return 0;if(0!==e.dyn_ltree[18]||0!==e.dyn_ltree[20]||0!==e.dyn_ltree[26])return 1;for(t=32;t<256;t++)if(0!==e.dyn_ltree[2*t])return 1;return 0}(e)),I(e,e.l_desc),I(e,e.d_desc),o=function(e){var t;for(O(e,e.dyn_ltree,e.l_desc.max_code),O(e,e.dyn_dtree,e.d_desc.max_code),I(e,e.bl_desc),t=18;t>=3&&0===e.bl_tree[2*c[t]+1];t--);return e.opt_len+=3*(t+1)+5+5+4,t}(e),n=e.opt_len+3+7>>>3,(a=e.static_len+3+7>>>3)<=n&&(n=a)):n=a=r+5,r+4<=n&&-1!==t?D(e,t,r,i):4===e.strategy||a===n?(w(e,2+(i?1:0),3),R(e,u,l)):(w(e,4+(i?1:0),3),function(e,t,r,i){var n;for(w(e,t-257,5),w(e,r-1,5),w(e,i-4,4),n=0;n>>8&255,e.pending_buf[e.d_buf+2*e.last_lit+1]=255&t,e.pending_buf[e.l_buf+e.last_lit]=255&r,e.last_lit++,0===t?e.dyn_ltree[2*r]++:(e.matches++,t--,e.dyn_ltree[2*(d[r]+256+1)]++,e.dyn_dtree[2*b(t)]++),e.last_lit===e.lit_bufsize-1},t._tr_align=function(e){w(e,2,3),S(e,256,u),function(e){16===e.bi_valid?(E(e,e.bi_buf),e.bi_buf=0,e.bi_valid=0):e.bi_valid>=8&&(e.pending_buf[e.pending++]=255&e.bi_buf,e.bi_buf>>=8,e.bi_valid-=8)}(e)}},function(e,t,r){"use strict";e.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},function(e,t,r){"use strict";var i=r(86),n=r(224),a=r(225),o=r(418),s=r(419);function c(e){return(e>>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function u(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new i.Buf16(320),this.work=new i.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function l(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=1,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new i.Buf32(852),t.distcode=t.distdyn=new i.Buf32(592),t.sane=1,t.back=-1,0):-2}function h(e){var t;return e&&e.state?((t=e.state).wsize=0,t.whave=0,t.wnext=0,l(e)):-2}function d(e,t){var r,i;return e&&e.state?(i=e.state,t<0?(r=0,t=-t):(r=1+(t>>4),t<48&&(t&=15)),t&&(t<8||t>15)?-2:(null!==i.window&&i.wbits!==t&&(i.window=null),i.wrap=r,i.wbits=t,h(e))):-2}function p(e,t){var r,i;return e?(i=new u,e.state=i,i.window=null,0!==(r=d(e,t))&&(e.state=null),r):-2}var f,m,g=!0;function _(e){if(g){var t;for(f=new i.Buf32(512),m=new i.Buf32(32),t=0;t<144;)e.lens[t++]=8;for(;t<256;)e.lens[t++]=9;for(;t<280;)e.lens[t++]=7;for(;t<288;)e.lens[t++]=8;for(s(1,e.lens,0,288,f,0,e.work,{bits:9}),t=0;t<32;)e.lens[t++]=5;s(2,e.lens,0,32,m,0,e.work,{bits:5}),g=!1}e.lencode=f,e.lenbits=9,e.distcode=m,e.distbits=5}function v(e,t,r,n){var a,o=e.state;return null===o.window&&(o.wsize=1<=o.wsize?(i.arraySet(o.window,t,r-o.wsize,o.wsize,0),o.wnext=0,o.whave=o.wsize):((a=o.wsize-o.wnext)>n&&(a=n),i.arraySet(o.window,t,r-n,a,o.wnext),(n-=a)?(i.arraySet(o.window,t,r-n,n,0),o.wnext=n,o.whave=o.wsize):(o.wnext+=a,o.wnext===o.wsize&&(o.wnext=0),o.whave>>8&255,r.check=a(r.check,D,2,0),m=0,g=0,r.mode=2;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&m)<<8)+(m>>8))%31){e.msg="incorrect header check",r.mode=30;break}if(8!=(15&m)){e.msg="unknown compression method",r.mode=30;break}if(g-=4,R=8+(15&(m>>>=4)),0===r.wbits)r.wbits=R;else if(R>r.wbits){e.msg="invalid window size",r.mode=30;break}r.dmax=1<>8&1),512&r.flags&&(D[0]=255&m,D[1]=m>>>8&255,r.check=a(r.check,D,2,0)),m=0,g=0,r.mode=3;case 3:for(;g<32;){if(0===p)break e;p--,m+=u[h++]<>>8&255,D[2]=m>>>16&255,D[3]=m>>>24&255,r.check=a(r.check,D,4,0)),m=0,g=0,r.mode=4;case 4:for(;g<16;){if(0===p)break e;p--,m+=u[h++]<>8),512&r.flags&&(D[0]=255&m,D[1]=m>>>8&255,r.check=a(r.check,D,2,0)),m=0,g=0,r.mode=5;case 5:if(1024&r.flags){for(;g<16;){if(0===p)break e;p--,m+=u[h++]<>>8&255,r.check=a(r.check,D,2,0)),m=0,g=0}else r.head&&(r.head.extra=null);r.mode=6;case 6:if(1024&r.flags&&((E=r.length)>p&&(E=p),E&&(r.head&&(R=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),i.arraySet(r.head.extra,u,h,E,R)),512&r.flags&&(r.check=a(r.check,u,E,h)),p-=E,h+=E,r.length-=E),r.length))break e;r.length=0,r.mode=7;case 7:if(2048&r.flags){if(0===p)break e;E=0;do{R=u[h+E++],r.head&&R&&r.length<65536&&(r.head.name+=String.fromCharCode(R))}while(R&&E>9&1,r.head.done=!0),e.adler=r.check=0,r.mode=12;break;case 10:for(;g<32;){if(0===p)break e;p--,m+=u[h++]<>>=7&g,g-=7&g,r.mode=27;break}for(;g<3;){if(0===p)break e;p--,m+=u[h++]<>>=1)){case 0:r.mode=14;break;case 1:if(_(r),r.mode=20,6===t){m>>>=2,g-=2;break e}break;case 2:r.mode=17;break;case 3:e.msg="invalid block type",r.mode=30}m>>>=2,g-=2;break;case 14:for(m>>>=7&g,g-=7&g;g<32;){if(0===p)break e;p--,m+=u[h++]<>>16^65535)){e.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&m,m=0,g=0,r.mode=15,6===t)break e;case 15:r.mode=16;case 16:if(E=r.length){if(E>p&&(E=p),E>f&&(E=f),0===E)break e;i.arraySet(l,u,h,E,d),p-=E,h+=E,f-=E,d+=E,r.length-=E;break}r.mode=12;break;case 17:for(;g<14;){if(0===p)break e;p--,m+=u[h++]<>>=5,g-=5,r.ndist=1+(31&m),m>>>=5,g-=5,r.ncode=4+(15&m),m>>>=4,g-=4,r.nlen>286||r.ndist>30){e.msg="too many length or distance symbols",r.mode=30;break}r.have=0,r.mode=18;case 18:for(;r.have>>=3,g-=3}for(;r.have<19;)r.lens[F[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,O={bits:r.lenbits},I=s(0,r.lens,0,19,r.lencode,0,r.work,O),r.lenbits=O.bits,I){e.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have>>16&255,M=65535&P,!((k=P>>>24)<=g);){if(0===p)break e;p--,m+=u[h++]<>>=k,g-=k,r.lens[r.have++]=M;else{if(16===M){for(A=k+2;g>>=k,g-=k,0===r.have){e.msg="invalid bit length repeat",r.mode=30;break}R=r.lens[r.have-1],E=3+(3&m),m>>>=2,g-=2}else if(17===M){for(A=k+3;g>>=k)),m>>>=3,g-=3}else{for(A=k+7;g>>=k)),m>>>=7,g-=7}if(r.have+E>r.nlen+r.ndist){e.msg="invalid bit length repeat",r.mode=30;break}for(;E--;)r.lens[r.have++]=R}}if(30===r.mode)break;if(0===r.lens[256]){e.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,O={bits:r.lenbits},I=s(1,r.lens,0,r.nlen,r.lencode,0,r.work,O),r.lenbits=O.bits,I){e.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,O={bits:r.distbits},I=s(2,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,O),r.distbits=O.bits,I){e.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===t)break e;case 20:r.mode=21;case 21:if(p>=6&&f>=258){e.next_out=d,e.avail_out=f,e.next_in=h,e.avail_in=p,r.hold=m,r.bits=g,o(e,b),d=e.next_out,l=e.output,f=e.avail_out,h=e.next_in,u=e.input,p=e.avail_in,m=r.hold,g=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;x=(P=r.lencode[m&(1<>>16&255,M=65535&P,!((k=P>>>24)<=g);){if(0===p)break e;p--,m+=u[h++]<>N)])>>>16&255,M=65535&P,!(N+(k=P>>>24)<=g);){if(0===p)break e;p--,m+=u[h++]<>>=N,g-=N,r.back+=N}if(m>>>=k,g-=k,r.back+=k,r.length=M,0===x){r.mode=26;break}if(32&x){r.back=-1,r.mode=12;break}if(64&x){e.msg="invalid literal/length code",r.mode=30;break}r.extra=15&x,r.mode=22;case 22:if(r.extra){for(A=r.extra;g>>=r.extra,g-=r.extra,r.back+=r.extra}r.was=r.length,r.mode=23;case 23:for(;x=(P=r.distcode[m&(1<>>16&255,M=65535&P,!((k=P>>>24)<=g);){if(0===p)break e;p--,m+=u[h++]<>N)])>>>16&255,M=65535&P,!(N+(k=P>>>24)<=g);){if(0===p)break e;p--,m+=u[h++]<>>=N,g-=N,r.back+=N}if(m>>>=k,g-=k,r.back+=k,64&x){e.msg="invalid distance code",r.mode=30;break}r.offset=M,r.extra=15&x,r.mode=24;case 24:if(r.extra){for(A=r.extra;g>>=r.extra,g-=r.extra,r.back+=r.extra}if(r.offset>r.dmax){e.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===f)break e;if(E=b-f,r.offset>E){if((E=r.offset-E)>r.whave&&r.sane){e.msg="invalid distance too far back",r.mode=30;break}E>r.wnext?(E-=r.wnext,w=r.wsize-E):w=r.wnext-E,E>r.length&&(E=r.length),S=r.window}else S=l,w=d-r.offset,E=r.length;E>f&&(E=f),f-=E,r.length-=E;do{l[d++]=S[w++]}while(--E);0===r.length&&(r.mode=21);break;case 26:if(0===f)break e;l[d++]=r.length,f--,r.mode=21;break;case 27:if(r.wrap){for(;g<32;){if(0===p)break e;p--,m|=u[h++]<>>=b=y>>>24,f-=b,0===(b=y>>>16&255))M[a++]=65535&y;else{if(!(16&b)){if(0==(64&b)){y=m[(65535&y)+(p&(1<>>=b,f-=b),f<15&&(p+=x[i++]<>>=b=y>>>24,f-=b,!(16&(b=y>>>16&255))){if(0==(64&b)){y=g[(65535&y)+(p&(1<c){e.msg="invalid distance too far back",r.mode=30;break e}if(p>>>=b,f-=b,w>(b=a-o)){if((b=w-b)>l&&r.sane){e.msg="invalid distance too far back",r.mode=30;break e}if(S=0,k=d,0===h){if(S+=u-b,b2;)M[a++]=k[S++],M[a++]=k[S++],M[a++]=k[S++],E-=3;E&&(M[a++]=k[S++],E>1&&(M[a++]=k[S++]))}else{S=a-w;do{M[a++]=M[S++],M[a++]=M[S++],M[a++]=M[S++],E-=3}while(E>2);E&&(M[a++]=M[S++],E>1&&(M[a++]=M[S++]))}break}}break}}while(i>3,p&=(1<<(f-=E<<3))-1,e.next_in=i,e.next_out=a,e.avail_in=i=1&&0===D[M];M--);if(N>M&&(N=M),0===M)return u[l++]=20971520,u[l++]=20971520,d.bits=1,0;for(x=1;x0&&(0===e||1!==M))return-1;for(F[1]=0,S=1;S<15;S++)F[S+1]=F[S]+D[S];for(k=0;k852||2===e&&I>592)return 1;for(;;){y=S-T,h[k]v?(b=C[B+h[k]],E=A[P+h[k]]):(b=96,E=0),p=1<>T)+(f-=p)]=y<<24|b<<16|E|0}while(0!==f);for(p=1<>=1;if(0!==p?(O&=p-1,O+=p):O=0,k++,0==--D[S]){if(S===M)break;S=t[r+h[k]]}if(S>N&&(O&g)!==m){for(0===T&&(T=N),_+=x,R=1<<(j=S-T);j+T852||2===e&&I>592)return 1;u[m=O&g]=N<<24|j<<16|_-l|0}}return 0!==O&&(u[_+O]=S-T<<24|64<<16|0),d.bits=N,0}},function(e,t,r){"use strict";e.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},function(e,t,r){ -/*! - * Copyright 2010 LearnBoost - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -var i=r(10),n=r(25).parse,a=["acl","location","logging","notification","partNumber","policy","requestPayment","torrent","uploadId","uploads","versionId","versioning","versions","website"];function o(e){return"AWS "+e.key+":"+c(e)}function s(e){return i.createHmac("sha1",e.secret).update(e.message).digest("base64")}function c(e){return e.message=u(e),s(e)}function u(e){var t=e.amazonHeaders||"";return t&&(t+="\n"),[e.verb,e.md5,e.contentType,e.date?e.date.toUTCString():"",t+e.resource].join("\n")}function l(e){return"GET\n\n\n"+e.date+"\n"+e.resource}e.exports=o,e.exports.authorization=o,e.exports.hmacSha1=s,e.exports.sign=c,e.exports.signQuery=function(e){return e.message=l(e),s(e)},e.exports.stringToSign=u,e.exports.queryStringToSign=l,e.exports.canonicalizeHeaders=function(e){for(var t=[],r=Object.keys(e),i=0,n=r.length;i=0&&"us-east-1"===this.region||["cloudfront","ls","route53","iam","importexport","sts"].indexOf(this.service)>=0},h.prototype.createHost=function(){var e=this.isSingleRegion()?"":("s3"===this.service&&"us-east-1"!==this.region?"-":".")+this.region;return("ses"===this.service?"email":this.service)+e+".amazonaws.com"},h.prototype.prepareRequest=function(){this.parsePath();var t,r=this.request,i=r.headers;r.signQuery?(this.parsedPath.query=t=this.parsedPath.query||{},this.credentials.sessionToken&&(t["X-Amz-Security-Token"]=this.credentials.sessionToken),"s3"!==this.service||t["X-Amz-Expires"]||(t["X-Amz-Expires"]=86400),t["X-Amz-Date"]?this.datetime=t["X-Amz-Date"]:t["X-Amz-Date"]=this.getDateTime(),t["X-Amz-Algorithm"]="AWS4-HMAC-SHA256",t["X-Amz-Credential"]=this.credentials.accessKeyId+"/"+this.credentialString(),t["X-Amz-SignedHeaders"]=this.signedHeaders()):(r.doNotModifyHeaders||this.isCodeCommitGit||(!r.body||i["Content-Type"]||i["content-type"]||(i["Content-Type"]="application/x-www-form-urlencoded; charset=utf-8"),!r.body||i["Content-Length"]||i["content-length"]||(i["Content-Length"]=e.byteLength(r.body)),!this.credentials.sessionToken||i["X-Amz-Security-Token"]||i["x-amz-security-token"]||(i["X-Amz-Security-Token"]=this.credentials.sessionToken),"s3"!==this.service||i["X-Amz-Content-Sha256"]||i["x-amz-content-sha256"]||(i["X-Amz-Content-Sha256"]=u(this.request.body||"","hex")),i["X-Amz-Date"]||i["x-amz-date"]?this.datetime=i["X-Amz-Date"]||i["x-amz-date"]:i["X-Amz-Date"]=this.getDateTime()),delete i.Authorization,delete i.authorization)},h.prototype.sign=function(){return this.parsedPath||this.prepareRequest(),this.request.signQuery?this.parsedPath.query["X-Amz-Signature"]=this.signature():this.request.headers.Authorization=this.authHeader(),this.request.path=this.formatPath(),this.request},h.prototype.getDateTime=function(){if(!this.datetime){var e=this.request.headers,t=new Date(e.Date||e.date||new Date);this.datetime=t.toISOString().replace(/[:\-]|\.\d{3}/g,""),this.isCodeCommitGit&&(this.datetime=this.datetime.slice(0,-1))}return this.datetime},h.prototype.getDate=function(){return this.getDateTime().substr(0,8)},h.prototype.authHeader=function(){return["AWS4-HMAC-SHA256 Credential="+this.credentials.accessKeyId+"/"+this.credentialString(),"SignedHeaders="+this.signedHeaders(),"Signature="+this.signature()].join(", ")},h.prototype.signature=function(){var e,t,r,i=this.getDate(),n=[this.credentials.secretAccessKey,i,this.region,this.service].join(),a=s.get(n);return a||(e=c("AWS4"+this.credentials.secretAccessKey,i),t=c(e,this.region),r=c(t,this.service),a=c(r,"aws4_request"),s.set(n,a)),c(a,this.stringToSign(),"hex")},h.prototype.stringToSign=function(){return["AWS4-HMAC-SHA256",this.getDateTime(),this.credentialString(),u(this.canonicalString(),"hex")].join("\n")},h.prototype.canonicalString=function(){this.parsedPath||this.prepareRequest();var e,t=this.parsedPath.path,r=this.parsedPath.query,i=this.request.headers,n="",o="s3"!==this.service,s="s3"===this.service||this.request.doNotEncodePath,c="s3"===this.service,h="s3"===this.service;return e="s3"===this.service&&this.request.signQuery?"UNSIGNED-PAYLOAD":this.isCodeCommitGit?"":i["X-Amz-Content-Sha256"]||i["x-amz-content-sha256"]||u(this.request.body||"","hex"),r&&(n=l(a.stringify(Object.keys(r).sort().reduce((function(e,t){return t?(e[t]=Array.isArray(r[t])?h?r[t][0]:r[t].slice().sort():r[t],e):e}),{})))),"/"!==t&&(o&&(t=t.replace(/\/{2,}/g,"/")),"/"!==(t=t.split("/").reduce((function(e,t){return o&&".."===t?e.pop():o&&"."===t||(s&&(t=decodeURIComponent(t)),e.push(l(encodeURIComponent(t)))),e}),[]).join("/"))[0]&&(t="/"+t),c&&(t=t.replace(/%2F/g,"/"))),[this.request.method||"GET",t,n,this.canonicalHeaders()+"\n",this.signedHeaders(),e].join("\n")},h.prototype.canonicalHeaders=function(){var e=this.request.headers;return Object.keys(e).sort((function(e,t){return e.toLowerCase()=0&&(r=a.parse(e.slice(t+1)),e=e.slice(0,t)),/[^0-9A-Za-z!'()*\-._~%/]/.test(e)&&(e=e.split("/").map((function(e){return encodeURIComponent(decodeURIComponent(e))})).join("/")),this.parsedPath={path:e,query:r}},h.prototype.formatPath=function(){var e=this.parsedPath.path,t=this.parsedPath.query;return t?(null!=t[""]&&delete t[""],e+"?"+l(a.stringify(t))):e},i.RequestSigner=h,i.sign=function(e,t){return new h(e,t).sign()}}).call(this,r(2).Buffer)},function(e,t){function r(e){this.capacity=0|e,this.map=Object.create(null),this.list=new i}function i(){this.firstNode=null,this.lastNode=null}function n(e,t){this.key=e,this.val=t,this.prev=null,this.next=null}e.exports=function(e){return new r(e)},r.prototype.get=function(e){var t=this.map[e];if(null!=t)return this.used(t),t.val},r.prototype.set=function(e,t){var r=this.map[e];if(null!=r)r.val=t;else{if(this.capacity||this.prune(),!this.capacity)return!1;r=new n(e,t),this.map[e]=r,this.capacity--}return this.used(r),!0},r.prototype.used=function(e){this.list.moveToFront(e)},r.prototype.prune=function(){var e=this.list.pop();null!=e&&(delete this.map[e.key],this.capacity++)},i.prototype.moveToFront=function(e){this.firstNode!=e&&(this.remove(e),null==this.firstNode?(this.firstNode=e,this.lastNode=e,e.prev=null,e.next=null):(e.prev=null,e.next=this.firstNode,e.next.prev=e,this.firstNode=e))},i.prototype.pop=function(){var e=this.lastNode;return null!=e&&this.remove(e),e},i.prototype.remove=function(e){this.firstNode==e?this.firstNode=e.next:null!=e.prev&&(e.prev.next=e.next),this.lastNode==e?this.lastNode=e.prev:null!=e.next&&(e.next.prev=e.prev)}},function(e,t,r){var i=r(425),n=r(434),a=r(438),o=r(87);e.exports={parse:i.parseRequest,parseRequest:i.parseRequest,sign:n.signRequest,signRequest:n.signRequest,createSigner:n.createSigner,isSigner:n.isSigner,sshKeyToPEM:o.sshKeyToPEM,sshKeyFingerprint:o.fingerprint,pemToRsaSSHKey:o.pemToRsaSSHKey,verify:a.verifySignature,verifySignature:a.verifySignature,verifyHMAC:a.verifyHMAC}},function(e,t,r){var i=r(6),n=r(11),a=r(87),o=(a.HASH_ALGOS,a.PK_ALGOS,a.HttpSignatureError),s=a.InvalidAlgorithmError,c=a.validateAlgorithm,u=0,l=1,h=0,d=1,p=2,f=3;function m(e){o.call(this,e,m)}function g(e){o.call(this,e,g)}function _(e){o.call(this,e,_)}function v(e){o.call(this,e,v)}function y(e){o.call(this,e,y)}n.inherits(m,o),n.inherits(g,o),n.inherits(_,o),n.inherits(v,o),n.inherits(y,o),e.exports={parseRequest:function(e,t){i.object(e,"request"),i.object(e.headers,"request.headers"),void 0===t&&(t={}),void 0===t.headers&&(t.headers=[e.headers["x-date"]?"x-date":"date"]),i.object(t,"options"),i.arrayOfString(t.headers,"options.headers"),i.optionalFinite(t.clockSkew,"options.clockSkew");var r=t.authorizationHeaderName||"authorization";if(!e.headers[r])throw new v("no "+r+" header present in the request");t.clockSkew=t.clockSkew||300;var n,a=0,o=u,b=h,E="",w="",S={scheme:"",params:{},signingString:""},k=e.headers[r];for(a=0;a=65&&M<=90||M>=97&&M<=122)E+=x;else{if("="!==x)throw new g("bad param format");if(0===E.length)throw new g("bad param format");b=d}break;case d:if('"'!==x)throw new g("bad param format");w="",b=p;break;case p:'"'===x?(S.params[E]=w,b=f):w+=x;break;case f:if(","!==x)throw new g("bad param format");E="",b=h;break;default:throw new Error("Invalid substate")}break;default:throw new Error("Invalid substate")}}if(S.params.headers&&""!==S.params.headers?S.params.headers=S.params.headers.split(" "):e.headers["x-date"]?S.params.headers=["x-date"]:S.params.headers=["date"],!S.scheme||"Signature"!==S.scheme)throw new g('scheme was not "Signature"');if(!S.params.keyId)throw new g("keyId was not specified");if(!S.params.algorithm)throw new g("algorithm was not specified");if(!S.params.signature)throw new g("signature was not specified");S.params.algorithm=S.params.algorithm.toLowerCase();try{c(S.params.algorithm)}catch(e){throw e instanceof s?new _(S.params.algorithm+" is not supported"):e}for(a=0;a1e3*t.clockSkew)throw new m("clock skew of "+R/1e3+"s was greater than "+t.clockSkew+"s")}if(t.headers.forEach((function(e){if(S.params.headers.indexOf(e.toLowerCase())<0)throw new v(e+" was not a signed header")})),t.algorithms&&-1===t.algorithms.indexOf(S.params.algorithm))throw new _(S.params.algorithm+" is not a supported algorithm");return S.algorithm=S.params.algorithm.toUpperCase(),S.keyId=S.params.keyId,S}}},function(e,t){},function(e,t,r){var i=r(10),n=r(69).BigInteger,a=(r(88).ECPointFp,r(9).Buffer);function o(e,t){return e.length>=t?e:o("0"+e,t)}t.ECCurves=r(428),t.ECKey=function(e,t,r){var s,c=e(),u=c.getN(),l=Math.floor(u.bitLength()/8);if(t)if(r){e=c.getCurve();this.P=e.decodePointHex(t.toString("hex"))}else{if(t.length!=l)return!1;s=new n(t.toString("hex"),16)}else{var h=u.subtract(n.ONE),d=new n(i.randomBytes(u.bitLength()));s=d.mod(h).add(n.ONE),this.P=c.getG().multiply(s)}this.P&&(this.PublicKey=a.from(c.getCurve().encodeCompressedPointHex(this.P),"hex")),s&&(this.PrivateKey=a.from(o(s.toString(16),2*l),"hex"),this.deriveSharedSecret=function(e){if(!e||!e.P)return!1;var t=e.P.multiply(s);return a.from(o(t.getX().toBigInteger().toString(16),2*l),"hex")})}},function(e,t,r){var i=r(69).BigInteger,n=r(88).ECCurveFp;function a(e,t,r,i){this.curve=e,this.g=t,this.n=r,this.h=i}function o(e){return new i(e,16)}function s(){var e=o("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"),t=o("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC"),r=o("E87579C11079F43DD824993C2CEE5ED3"),s=o("FFFFFFFE0000000075A30D1B9038A115"),c=i.ONE,u=new n(e,t,r),l=u.decodePointHex("04161FF7528B899B2D0C28607CA52C5B86CF5AC8395BAFEB13C02DA292DDED7A83");return new a(u,l,s,c)}function c(){var e=o("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73"),t=i.ZERO,r=o("7"),s=o("0100000000000000000001B8FA16DFAB9ACA16B6B3"),c=i.ONE,u=new n(e,t,r),l=u.decodePointHex("043B4C382CE37AA192A4019E763036F4F5DD4D7EBB938CF935318FDCED6BC28286531733C3F03C4FEE");return new a(u,l,s,c)}function u(){var e=o("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF"),t=o("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC"),r=o("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45"),s=o("0100000000000000000001F4C8F927AED3CA752257"),c=i.ONE,u=new n(e,t,r),l=u.decodePointHex("044A96B5688EF573284664698968C38BB913CBFC8223A628553168947D59DCC912042351377AC5FB32");return new a(u,l,s,c)}function l(){var e=o("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37"),t=i.ZERO,r=o("3"),s=o("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D"),c=i.ONE,u=new n(e,t,r),l=u.decodePointHex("04DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D");return new a(u,l,s,c)}function h(){var e=o("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"),t=o("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC"),r=o("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"),s=o("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"),c=i.ONE,u=new n(e,t,r),l=u.decodePointHex("04188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E794811");return new a(u,l,s,c)}function d(){var e=o("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"),t=o("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE"),r=o("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"),s=o("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"),c=i.ONE,u=new n(e,t,r),l=u.decodePointHex("04B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34");return new a(u,l,s,c)}function p(){var e=o("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"),t=o("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"),r=o("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"),s=o("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"),c=i.ONE,u=new n(e,t,r),l=u.decodePointHex("046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5");return new a(u,l,s,c)}a.prototype.getCurve=function(){return this.curve},a.prototype.getG=function(){return this.g},a.prototype.getN=function(){return this.n},a.prototype.getH=function(){return this.h},e.exports={secp128r1:s,secp160k1:c,secp160r1:u,secp192k1:l,secp192r1:h,secp224r1:d,secp256r1:p}},function(e,t,r){var i=r(127),n=r(128),a=r(430),o=r(431);for(var s in e.exports={Reader:a,Writer:o},n)n.hasOwnProperty(s)&&(e.exports[s]=n[s]);for(var c in i)i.hasOwnProperty(c)&&(e.exports[c]=i[c])},function(e,t,r){var i=r(4),n=r(9).Buffer,a=r(128),o=r(127).newInvalidAsn1Error;function s(e){if(!e||!n.isBuffer(e))throw new TypeError("data must be a node Buffer");this._buf=e,this._size=e.length,this._len=0,this._offset=0}Object.defineProperty(s.prototype,"length",{enumerable:!0,get:function(){return this._len}}),Object.defineProperty(s.prototype,"offset",{enumerable:!0,get:function(){return this._offset}}),Object.defineProperty(s.prototype,"remain",{get:function(){return this._size-this._offset}}),Object.defineProperty(s.prototype,"buffer",{get:function(){return this._buf.slice(this._offset)}}),s.prototype.readByte=function(e){if(this._size-this._offset<1)return null;var t=255&this._buf[this._offset];return e||(this._offset+=1),t},s.prototype.peek=function(){return this.readByte(!0)},s.prototype.readLength=function(e){if(void 0===e&&(e=this._offset),e>=this._size)return null;var t=255&this._buf[e++];if(null===t)return null;if(128==(128&t)){if(0===(t&=127))throw o("Indefinite length not supported");if(t>4)throw o("encoding too long");if(this._size-ethis._size-i)return null;if(this._offset=i,0===this.length)return t?n.alloc(0):"";var s=this._buf.slice(this._offset,this._offset+this.length);return this._offset+=this.length,t?s:s.toString("utf8")},s.prototype.readOID=function(e){e||(e=a.OID);var t=this.readString(e,!0);if(null===t)return null;for(var r=[],i=0,n=0;n>0),r.join(".")},s.prototype._readTag=function(e){i.ok(void 0!==e);var t=this.peek();if(null===t)return null;if(t!==e)throw o("Expected 0x"+e.toString(16)+": got 0x"+t.toString(16));var r=this.readLength(this._offset+1);if(null===r)return null;if(this.length>4)throw o("Integer too long: "+this.length);if(this.length>this._size-r)return null;this._offset=r;for(var n=this._buf[this._offset],a=0,s=0;s>0},e.exports=s},function(e,t,r){var i=r(4),n=r(9).Buffer,a=r(128),o=r(127).newInvalidAsn1Error,s={size:1024,growthFactor:8};function c(e){var t,r;t=s,r=e||{},i.ok(t),i.equal(typeof t,"object"),i.ok(r),i.equal(typeof r,"object"),Object.getOwnPropertyNames(t).forEach((function(e){if(!r[e]){var i=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(r,e,i)}})),e=r,this._buf=n.alloc(e.size||1024),this._size=this._buf.length,this._offset=0,this._options=e,this._seq=[]}Object.defineProperty(c.prototype,"buffer",{get:function(){if(this._seq.length)throw o(this._seq.length+" unended sequence(s)");return this._buf.slice(0,this._offset)}}),c.prototype.writeByte=function(e){if("number"!=typeof e)throw new TypeError("argument must be a Number");this._ensure(1),this._buf[this._offset++]=e},c.prototype.writeInt=function(e,t){if("number"!=typeof e)throw new TypeError("argument must be a Number");"number"!=typeof t&&(t=a.Integer);for(var r=4;(0==(4286578688&e)||-8388608==(4286578688&e))&&r>1;)r--,e<<=8;if(r>4)throw o("BER ints cannot be > 0xffffffff");for(this._ensure(2+r),this._buf[this._offset++]=t,this._buf[this._offset++]=r;r-- >0;)this._buf[this._offset++]=(4278190080&e)>>>24,e<<=8},c.prototype.writeNull=function(){this.writeByte(a.Null),this.writeByte(0)},c.prototype.writeEnumeration=function(e,t){if("number"!=typeof e)throw new TypeError("argument must be a Number");return"number"!=typeof t&&(t=a.Enumeration),this.writeInt(e,t)},c.prototype.writeBoolean=function(e,t){if("boolean"!=typeof e)throw new TypeError("argument must be a Boolean");"number"!=typeof t&&(t=a.Boolean),this._ensure(3),this._buf[this._offset++]=t,this._buf[this._offset++]=1,this._buf[this._offset++]=e?255:0},c.prototype.writeString=function(e,t){if("string"!=typeof e)throw new TypeError("argument must be a string (was: "+typeof e+")");"number"!=typeof t&&(t=a.OctetString);var r=n.byteLength(e);this.writeByte(t),this.writeLength(r),r&&(this._ensure(r),this._buf.write(e,this._offset),this._offset+=r)},c.prototype.writeBuffer=function(e,t){if("number"!=typeof t)throw new TypeError("tag must be a number");if(!n.isBuffer(e))throw new TypeError("argument must be a buffer");this.writeByte(t),this.writeLength(e.length),this._ensure(e.length),e.copy(this._buf,this._offset,0,e.length),this._offset+=e.length},c.prototype.writeStringArray=function(e){if(!e instanceof Array)throw new TypeError("argument must be an Array[String]");var t=this;e.forEach((function(e){t.writeString(e)}))},c.prototype.writeOID=function(e,t){if("string"!=typeof e)throw new TypeError("argument must be a string");if("number"!=typeof t&&(t=a.OID),!/^([0-9]+\.){3,}[0-9]+$/.test(e))throw new Error("argument is not a valid OID string");var r=e.split("."),i=[];i.push(40*parseInt(r[0],10)+parseInt(r[1],10)),r.slice(2).forEach((function(e){!function(e,t){t<128?e.push(t):t<16384?(e.push(t>>>7|128),e.push(127&t)):t<2097152?(e.push(t>>>14|128),e.push(255&(t>>>7|128)),e.push(127&t)):t<268435456?(e.push(t>>>21|128),e.push(255&(t>>>14|128)),e.push(255&(t>>>7|128)),e.push(127&t)):(e.push(255&(t>>>28|128)),e.push(255&(t>>>21|128)),e.push(255&(t>>>14|128)),e.push(255&(t>>>7|128)),e.push(127&t))}(i,parseInt(e,10))}));var n=this;this._ensure(2+i.length),this.writeByte(t),this.writeLength(i.length),i.forEach((function(e){n.writeByte(e)}))},c.prototype.writeLength=function(e){if("number"!=typeof e)throw new TypeError("argument must be a Number");if(this._ensure(4),e<=127)this._buf[this._offset++]=e;else if(e<=255)this._buf[this._offset++]=129,this._buf[this._offset++]=e;else if(e<=65535)this._buf[this._offset++]=130,this._buf[this._offset++]=e>>8,this._buf[this._offset++]=e;else{if(!(e<=16777215))throw o("Length too long (> 4 bytes)");this._buf[this._offset++]=131,this._buf[this._offset++]=e>>16,this._buf[this._offset++]=e>>8,this._buf[this._offset++]=e}},c.prototype.startSequence=function(e){"number"!=typeof e&&(e=a.Sequence|a.Constructor),this.writeByte(e),this._seq.push(this._offset),this._ensure(3),this._offset+=3},c.prototype.endSequence=function(){var e=this._seq.pop(),t=e+3,r=this._offset-t;if(r<=127)this._shift(t,r,-2),this._buf[e]=r;else if(r<=255)this._shift(t,r,-1),this._buf[e]=129,this._buf[e+1]=r;else if(r<=65535)this._buf[e]=130,this._buf[e+1]=r>>8,this._buf[e+2]=r;else{if(!(r<=16777215))throw o("Sequence too long");this._shift(t,r,1),this._buf[e]=131,this._buf[e+1]=r>>16,this._buf[e+2]=r>>8,this._buf[e+3]=r}},c.prototype._shift=function(e,t,r){i.ok(void 0!==e),i.ok(void 0!==t),i.ok(r),this._buf.copy(this._buf,e+r,e,e+t),this._offset+=r},c.prototype._ensure=function(e){if(i.ok(e),this._size-this._offset3)throw new Error("Not a valid SSH certificate line");var i=r[0],n=r[1];return g(n=o.from(n,"base64"),i)},verify:function(e,t){return!1},sign:function(e,t){void 0===e.signatures.openssh&&(e.signatures.openssh={});try{var r=y(e,!0)}catch(t){return delete e.signatures.openssh,!1}var i=e.signatures.openssh,n=void 0;"rsa"!==t.type&&"dsa"!==t.type||(n="sha1");var a=t.createSign(n);return a.write(r),i.signature=a.sign(),!0},signAsync:function(e,t,r){void 0===e.signatures.openssh&&(e.signatures.openssh={});try{var i=y(e,!0)}catch(t){return delete e.signatures.openssh,void r(t)}var n=e.signatures.openssh;t(i,(function(e,t){if(e)r(e);else{try{t.toBuffer("ssh")}catch(e){return void r(e)}n.signature=t,r()}}))},write:function(e,t){void 0===t&&(t={});var r=y(e),i=b(e.subjectKey)+" "+r.toString("base64");t.comment&&(i=i+" "+t.comment);return i},fromBuffer:g,toBuffer:y};var i=r(6),n=r(71),a=r(10),o=r(9).Buffer,s=r(16),c=r(14),u=(r(17),r(72)),l=r(40),h=r(30),d=r(13),p=r(67);var f={user:1,host:2};Object.keys(f).forEach((function(e){f[f[e]]=e}));var m=/^ecdsa-sha2-([^@-]+)-cert-v01@openssh.com$/;function g(e,t,r){var a=new n({buffer:e}),o=a.readString();if(void 0!==t&&o!==t)throw new Error("SSH certificate algorithm mismatch");void 0===t&&(t=o);var g={signatures:{}};g.signatures.openssh={},g.signatures.openssh.nonce=a.readBuffer();var v={},y=v.parts=[];v.type=function(e){if("ssh-rsa-cert-v01@openssh.com"===e)return"rsa";if("ssh-dss-cert-v01@openssh.com"===e)return"dsa";if(e.match(m))return"ecdsa";if("ssh-ed25519-cert-v01@openssh.com"===e)return"ed25519";throw new Error("Unsupported cert type "+e)}(t);for(var b=s.info[v.type].parts.length;y.length=1,"key must have at least one part");var E=s.info[v.type];if("ecdsa"===v.type){var w=m.exec(t);i.ok(null!==w),i.strictEqual(w[1],y[0].data.toString())}for(var S=0;Sn.length&&(l=n.length),c+=s.write(n.slice(u,l),c),s[c++]=10,u=l}return c+=s.write("-----END CERTIFICATE-----\n",c),s.slice(0,c)}};var n=r(6),a=(r(31),r(9).Buffer);r(16),r(13),r(14),r(17),r(36),r(72),r(30),r(67)},function(e,t,r){(function(t){var i=r(6),n=r(10),a=(r(52),r(11)),o=r(125),s=r(435),c=r(87),u=r(11).format,l=c.HASH_ALGOS,h=c.PK_ALGOS,d=c.InvalidAlgorithmError,p=c.HttpSignatureError,f=c.validateAlgorithm,m='Signature keyId="%s",algorithm="%s",headers="%s",signature="%s"';function g(e){p.call(this,e,g)}function _(e){p.call(this,e,_)}function v(e){i.object(e,"options");var r=[];if(void 0!==e.algorithm&&(i.string(e.algorithm,"options.algorithm"),r=f(e.algorithm)),this.rs_alg=r,void 0!==e.sign)i.func(e.sign,"options.sign"),this.rs_signFunc=e.sign;else if("hmac"===r[0]&&void 0!==e.key){if(i.string(e.keyId,"options.keyId"),this.rs_keyId=e.keyId,"string"!=typeof e.key&&!t.isBuffer(e.key))throw new TypeError("options.key for HMAC must be a string or Buffer");this.rs_signer=n.createHmac(r[1].toUpperCase(),e.key),this.rs_signer.sign=function(){var e=this.digest("base64");return{hashAlgorithm:r[1],toString:function(){return e}}}}else{if(void 0===e.key)throw new TypeError("options.sign (func) or options.key is required");var a=e.key;if(("string"==typeof a||t.isBuffer(a))&&(a=o.parsePrivateKey(a)),i.ok(o.PrivateKey.isPrivateKey(a,[1,2]),"options.key must be a sshpk.PrivateKey"),this.rs_key=a,i.string(e.keyId,"options.keyId"),this.rs_keyId=e.keyId,!h[a.type])throw new d(a.type.toUpperCase()+" type keys are not supported");if(void 0!==r[0]&&a.type!==r[0])throw new d("options.key must be a "+r[0].toUpperCase()+" key, was given a "+a.type.toUpperCase()+" key instead");this.rs_signer=a.createSign(r[1])}this.rs_headers=[],this.rs_lines=[]}a.inherits(g,p),a.inherits(_,p),v.prototype.writeHeader=function(e,t){if(i.string(e,"header"),e=e.toLowerCase(),i.string(t,"value"),this.rs_headers.push(e),this.rs_signFunc)this.rs_lines.push(e+": "+t);else{var r=e+": "+t;this.rs_headers.length>0&&(r="\n"+r),this.rs_signer.update(r)}return t},v.prototype.writeDateHeader=function(){return this.writeHeader("date",s.rfc1123(new Date))},v.prototype.writeTarget=function(e,t){i.string(e,"method"),i.string(t,"path"),e=e.toLowerCase(),this.writeHeader("(request-target)",e+" "+t)},v.prototype.sign=function(e){if(i.func(e,"callback"),this.rs_headers.length<1)throw new Error("At least one header must be signed");var t,r;if(this.rs_signFunc){var n=this.rs_lines.join("\n"),a=this;this.rs_signFunc(n,(function(n,o){if(n)e(n);else{try{i.object(o,"signature"),i.string(o.keyId,"signature.keyId"),i.string(o.algorithm,"signature.algorithm"),i.string(o.signature,"signature.signature"),t=f(o.algorithm),r=u(m,o.keyId,o.algorithm,a.rs_headers.join(" "),o.signature)}catch(t){return void e(t)}e(null,r)}}))}else{try{var o=this.rs_signer.sign()}catch(t){return void e(t)}t=(this.rs_alg[0]||this.rs_key.type)+"-"+o.hashAlgorithm;var s=o.toString();r=u(m,this.rs_keyId,t,this.rs_headers.join(" "),s),e(null,r)}},e.exports={isSigner:function(e){return"object"==typeof e&&e instanceof v},createSigner:function(e){return new v(e)},signRequest:function(e,r){i.object(e,"request"),i.object(r,"options"),i.optionalString(r.algorithm,"options.algorithm"),i.string(r.keyId,"options.keyId"),i.optionalArrayOfString(r.headers,"options.headers"),i.optionalString(r.httpVersion,"options.httpVersion"),e.getHeader("Date")||e.setHeader("Date",s.rfc1123(new Date)),r.headers||(r.headers=["date"]),r.httpVersion||(r.httpVersion="1.1");var a,c=[];r.algorithm&&(r.algorithm=r.algorithm.toLowerCase(),c=f(r.algorithm));var p,v="";for(a=0;a=0);var n,a=[];for(n in t)e(t[n],r-1).forEach((function(e){a.push([n].concat(e))}));return a},t.flattenIter=function(e,t,r){!function e(t,r,n,a){var o,s;if(0===r)return(o=n.slice(0)).push(t),void a(o);for(s in i.ok(null!==t),i.equal(typeof t,"object"),i.equal(typeof r,"number"),i.ok(r>=0),t)(o=n.slice(0)).push(s),e(t[s],r-1,o,a)}(e,t,[],r)},t.validateJsonObject=m,t.validateJsonObjectJS=m,t.randElt=function(e){return i.ok(Array.isArray(e)&&e.length>0,"randElt argument must be a non-empty array"),e[Math.floor(Math.random()*e.length)]},t.extraProperties=function(e,t){i.ok("object"==typeof e&&null!==e,"obj argument must be a non-null object"),i.ok(Array.isArray(t),"allowed argument must be an array of strings");for(var r=0;r=2,"options.base >= 2"),i.ok(a.base<=36,"options.base <= 36"),i.bool(a.allowSign,"options.allowSign"),i.bool(a.allowPrefix,"options.allowPrefix"),i.bool(a.allowTrailing,"options.allowTrailing"),i.bool(a.allowImprecise,"options.allowImprecise"),i.bool(a.trimWhitespace,"options.trimWhitespace"),i.bool(a.leadingZeroIsOctal,"options.leadingZeroIsOctal"),a.leadingZeroIsOctal&&i.ok(!n,'"base" and "leadingZeroIsOctal" are mutually exclusive'));var o,c=-1,u=a.base,m=1,g=0,_=0,v=e.length;if(a.trimWhitespace)for(;_l||b=48&&e<=57?e-48:e>=65&&e<=90?e-55:e>=97&&e<=122?e-87:-1}function f(e){return 32===e||e>=9&&e<=13||160===e||5760===e||6158===e||e>=8192&&e<=8202||8232===e||8233===e||8239===e||8287===e||12288===e||65279===e}function m(e,t){var r=o.validate(t,e);if(0===r.errors.length)return null;var i,n,s=r.errors[0],c=s.property,u=s.message.toLowerCase();-1!=(i=u.indexOf("the property "))&&-1!=(n=u.indexOf(" is not defined in the schema and the schema does not allow additional properties"))&&(i+="the property ".length,c=""===c?u.substr(i,n-i):c+"."+u.substr(i,n-i),u="unsupported property");var l=new a.VError('property "%s": %s',c,u);return l.jsv_details=s,l}function g(e){i.ok(e[0]>=0&&e[1]>=0,"negative numbers not allowed in hrtimes"),i.ok(e[1]<1e9,"nanoseconds column overflow")}function _(e,t){g(e),g(t),i.ok(e[0]>t[0]||e[0]==t[0]&&e[1]>=t[1],"negative differences not allowed");var r=[e[0]-t[0],0];return e[1]>=t[1]?r[1]=e[1]-t[1]:(r[0]--,r[1]=1e9-(t[1]-e[1])),r}function v(e,t){return g(e),g(t),e[1]+=t[1],e[1]>=1e9&&(e[0]++,e[1]-=1e9),e[0]+=t[0],e}function y(e,t,r){var i,n;if(i={},r)for(n in r)i[n]=r[n];if(e)for(n in e)i[n]=e[n];if(t)for(n in t)i[n]=t[n];return i}},function(e,t,r){var i=r(6),n=r(11),a=r(231),o=r(21).isError,s=a.sprintf;function c(e){var t,r,n,a;if(i.object(e,"args"),i.bool(e.strict,"args.strict"),i.array(e.argv,"args.argv"),0===(t=e.argv).length)r={},n=[];else if(o(t[0]))r={cause:t[0]},n=t.slice(1);else if("object"==typeof t[0]){for(a in r={},t[0])r[a]=t[0][a];n=t.slice(1)}else i.string(t[0],"first argument to VError, SError, or WError constructor must be a string, object, or Error"),r={},n=t;return i.object(r),r.strict||e.strict||(n=n.map((function(e){return null===e?"null":void 0===e?"undefined":e}))),{options:r,shortmessage:0===n.length?"":s.apply(null,n)}}function u(){var e,t,r,n,a,s,l;if(e=Array.prototype.slice.call(arguments,0),!(this instanceof u))return t=Object.create(u.prototype),u.apply(t,arguments),t;if((r=c({argv:e,strict:!1})).options.name&&(i.string(r.options.name,'error\'s "name" must be a string'),this.name=r.options.name),this.jse_shortmsg=r.shortmessage,s=r.shortmessage,(n=r.options.cause)&&(i.ok(o(n),"cause is not an Error"),this.jse_cause=n,r.options.skipCauseMessage||(s+=": "+n.message)),this.jse_info={},r.options.info)for(l in r.options.info)this.jse_info[l]=r.options.info[l];return this.message=s,Error.call(this,s),Error.captureStackTrace&&(a=r.options.constructorOpt||this.constructor,Error.captureStackTrace(this,a)),this}function l(){var e,t,r,i;return e=Array.prototype.slice.call(arguments,0),this instanceof l?(i=(r=c({argv:e,strict:!0})).options,u.call(this,i,"%s",r.shortmessage),this):(t=Object.create(l.prototype),l.apply(t,arguments),t)}function h(e){i.array(e,"list of errors"),i.ok(e.length>0,"must be at least one error"),this.ase_errors=e,u.call(this,{cause:e[0]},"first of %d error%s",e.length,1==e.length?"":"s")}function d(){var e,t,r,i;return e=Array.prototype.slice.call(arguments,0),this instanceof d?((i=(r=c({argv:e,strict:!1})).options).skipCauseMessage=!0,u.call(this,i,"%s",r.shortmessage),this):(t=Object.create(d.prototype),d.apply(t,e),t)}e.exports=u,u.VError=u,u.SError=l,u.WError=d,u.MultiError=h,n.inherits(u,Error),u.prototype.name="VError",u.prototype.toString=function(){var e=this.hasOwnProperty("name")&&this.name||this.constructor.name||this.constructor.prototype.name;return this.message&&(e+=": "+this.message),e},u.prototype.cause=function(){var e=u.cause(this);return null===e?void 0:e},u.cause=function(e){return i.ok(o(e),"err must be an Error"),o(e.jse_cause)?e.jse_cause:null},u.info=function(e){var t,r,n;if(i.ok(o(e),"err must be an Error"),t=null!==(r=u.cause(e))?u.info(r):{},"object"==typeof e.jse_info&&null!==e.jse_info)for(n in e.jse_info)t[n]=e.jse_info[n];return t},u.findCauseByName=function(e,t){var r;for(i.ok(o(e),"err must be an Error"),i.string(t,"name"),i.ok(t.length>0,"name cannot be empty"),r=e;null!==r;r=u.cause(r))if(i.ok(o(r)),r.name==t)return r;return null},u.hasCauseWithName=function(e,t){return null!==u.findCauseByName(e,t)},u.fullStack=function(e){i.ok(o(e),"err must be an Error");var t=u.cause(e);return t?e.stack+"\ncaused by: "+u.fullStack(t):e.stack},u.errorFromList=function(e){return i.arrayOfObject(e,"errors"),0===e.length?null:(e.forEach((function(e){i.ok(o(e))})),1==e.length?e[0]:new h(e))},u.errorForEach=function(e,t){i.ok(o(e),"err must be an Error"),i.func(t,"func"),e instanceof h?e.errors().forEach((function(e){t(e)})):t(e)},n.inherits(l,u),n.inherits(h,u),h.prototype.name="MultiError",h.prototype.errors=function(){return this.ase_errors.slice(0)},n.inherits(d,u),d.prototype.name="WError",d.prototype.toString=function(){var e=this.hasOwnProperty("name")&&this.name||this.constructor.name||this.constructor.prototype.name;return this.message&&(e+=": "+this.message),this.jse_cause&&this.jse_cause.message&&(e+="; caused by "+this.jse_cause.toString()),e},d.prototype.cause=function(e){return o(e)&&(this.jse_cause=e),this.jse_cause}},function(e,t,r){var i;void 0===(i=function(){return function(){var e=r;e.Integer={type:"integer"};var t={String:String,Boolean:Boolean,Number:Number,Object:Object,Array:Array,Date:Date};function r(e,t){return r(e,t,{changing:!1})}e.validate=r,e.checkPropertyChange=function(e,t,i){return r(e,t,{changing:i||"property"})};var r=e._validate=function(e,r,i){i||(i={});var n=i.changing;function a(e){return e.type||t[e.name]==e&&e.name.toLowerCase()}var o=[];function s(e,t,r,c){var u;function l(e){o.push({property:r,message:e})}if(r+=r?"number"==typeof c?"["+c+"]":void 0===c?"":"."+c:c,("object"!=typeof t||t instanceof Array)&&(r||"function"!=typeof t)&&(!t||!a(t)))return"function"==typeof t?e instanceof t||l("is not an instance of the class/constructor "+t.name):t&&l("Invalid schema/property definition "+t),null;function h(e,t){if(e){if(!("string"!=typeof e||"any"==e||("null"==e?null===t:typeof t==e)||t instanceof Array&&"array"==e||t instanceof Date&&"date"==e||"integer"==e&&t%1==0))return[{property:r,message:typeof t+" value found, but a "+e+" is required"}];if(e instanceof Array){for(var i=[],n=0;nt.maxItems&&l("There must be a maximum of "+t.maxItems+" in the array")}else(t.properties||t.additionalProperties)&&o.concat(function(e,t,r,a){if("object"==typeof t)for(var c in("object"!=typeof e||e instanceof Array)&&o.push({property:r,message:"an object is required"}),t)if(t.hasOwnProperty(c)){var u=e[c];if(void 0===u&&i.existingOnly)continue;var l=t[c];void 0===u&&l.default&&(u=e[c]=l.default),i.coerce&&c in e&&(u=e[c]=i.coerce(u,l)),s(u,l,r,c)}for(c in e){if(e.hasOwnProperty(c)&&("_"!=c.charAt(0)||"_"!=c.charAt(1))&&t&&!t[c]&&!1===a){if(i.filter){delete e[c];continue}o.push({property:r,message:typeof u+"The property "+c+" is not defined in the schema and the schema does not allow additional properties"})}var h=t&&t[c]&&t[c].requires;h&&!(h in e)&&o.push({property:r,message:"the presence of the property "+c+" requires that "+h+" also be present"}),u=e[c],!a||t&&"object"==typeof t&&c in t||(i.coerce&&(u=e[c]=i.coerce(u,a)),s(u,a,r,c)),!n&&u&&u.$schema&&(o=o.concat(s(u,u.$schema,r,c)))}return o}(e,t.properties,r,t.additionalProperties));if(t.pattern&&"string"==typeof e&&!e.match(t.pattern)&&l("does not match the regex pattern "+t.pattern),t.maxLength&&"string"==typeof e&&e.length>t.maxLength&&l("may only be "+t.maxLength+" characters long"),t.minLength&&"string"==typeof e&&e.lengthe&&l("must have a minimum value of "+t.minimum),void 0!==typeof t.maximum&&typeof e==typeof t.maximum&&t.maximuml||u===l&&"application/"===n[c].substr(0,12)))continue}n[c]=e}}}))},function(e,t,r){ -/*! - * mime-db - * Copyright(c) 2014 Jonathan Ong - * MIT Licensed - */ -e.exports=r(441)},function(e){e.exports=JSON.parse('{"application/1d-interleaved-parityfec":{"source":"iana"},"application/3gpdash-qoe-report+xml":{"source":"iana","compressible":true},"application/3gpp-ims+xml":{"source":"iana","compressible":true},"application/a2l":{"source":"iana"},"application/activemessage":{"source":"iana"},"application/activity+json":{"source":"iana","compressible":true},"application/alto-costmap+json":{"source":"iana","compressible":true},"application/alto-costmapfilter+json":{"source":"iana","compressible":true},"application/alto-directory+json":{"source":"iana","compressible":true},"application/alto-endpointcost+json":{"source":"iana","compressible":true},"application/alto-endpointcostparams+json":{"source":"iana","compressible":true},"application/alto-endpointprop+json":{"source":"iana","compressible":true},"application/alto-endpointpropparams+json":{"source":"iana","compressible":true},"application/alto-error+json":{"source":"iana","compressible":true},"application/alto-networkmap+json":{"source":"iana","compressible":true},"application/alto-networkmapfilter+json":{"source":"iana","compressible":true},"application/aml":{"source":"iana"},"application/andrew-inset":{"source":"iana","extensions":["ez"]},"application/applefile":{"source":"iana"},"application/applixware":{"source":"apache","extensions":["aw"]},"application/atf":{"source":"iana"},"application/atfx":{"source":"iana"},"application/atom+xml":{"source":"iana","compressible":true,"extensions":["atom"]},"application/atomcat+xml":{"source":"iana","compressible":true,"extensions":["atomcat"]},"application/atomdeleted+xml":{"source":"iana","compressible":true},"application/atomicmail":{"source":"iana"},"application/atomsvc+xml":{"source":"iana","compressible":true,"extensions":["atomsvc"]},"application/atxml":{"source":"iana"},"application/auth-policy+xml":{"source":"iana","compressible":true},"application/bacnet-xdd+zip":{"source":"iana","compressible":false},"application/batch-smtp":{"source":"iana"},"application/bdoc":{"compressible":false,"extensions":["bdoc"]},"application/beep+xml":{"source":"iana","compressible":true},"application/calendar+json":{"source":"iana","compressible":true},"application/calendar+xml":{"source":"iana","compressible":true},"application/call-completion":{"source":"iana"},"application/cals-1840":{"source":"iana"},"application/cbor":{"source":"iana"},"application/cccex":{"source":"iana"},"application/ccmp+xml":{"source":"iana","compressible":true},"application/ccxml+xml":{"source":"iana","compressible":true,"extensions":["ccxml"]},"application/cdfx+xml":{"source":"iana","compressible":true},"application/cdmi-capability":{"source":"iana","extensions":["cdmia"]},"application/cdmi-container":{"source":"iana","extensions":["cdmic"]},"application/cdmi-domain":{"source":"iana","extensions":["cdmid"]},"application/cdmi-object":{"source":"iana","extensions":["cdmio"]},"application/cdmi-queue":{"source":"iana","extensions":["cdmiq"]},"application/cdni":{"source":"iana"},"application/cea":{"source":"iana"},"application/cea-2018+xml":{"source":"iana","compressible":true},"application/cellml+xml":{"source":"iana","compressible":true},"application/cfw":{"source":"iana"},"application/clue_info+xml":{"source":"iana","compressible":true},"application/cms":{"source":"iana"},"application/cnrp+xml":{"source":"iana","compressible":true},"application/coap-group+json":{"source":"iana","compressible":true},"application/coap-payload":{"source":"iana"},"application/commonground":{"source":"iana"},"application/conference-info+xml":{"source":"iana","compressible":true},"application/cose":{"source":"iana"},"application/cose-key":{"source":"iana"},"application/cose-key-set":{"source":"iana"},"application/cpl+xml":{"source":"iana","compressible":true},"application/csrattrs":{"source":"iana"},"application/csta+xml":{"source":"iana","compressible":true},"application/cstadata+xml":{"source":"iana","compressible":true},"application/csvm+json":{"source":"iana","compressible":true},"application/cu-seeme":{"source":"apache","extensions":["cu"]},"application/cwt":{"source":"iana"},"application/cybercash":{"source":"iana"},"application/dart":{"compressible":true},"application/dash+xml":{"source":"iana","compressible":true,"extensions":["mpd"]},"application/dashdelta":{"source":"iana"},"application/davmount+xml":{"source":"iana","compressible":true,"extensions":["davmount"]},"application/dca-rft":{"source":"iana"},"application/dcd":{"source":"iana"},"application/dec-dx":{"source":"iana"},"application/dialog-info+xml":{"source":"iana","compressible":true},"application/dicom":{"source":"iana"},"application/dicom+json":{"source":"iana","compressible":true},"application/dicom+xml":{"source":"iana","compressible":true},"application/dii":{"source":"iana"},"application/dit":{"source":"iana"},"application/dns":{"source":"iana"},"application/dns+json":{"source":"iana","compressible":true},"application/dns-message":{"source":"iana"},"application/docbook+xml":{"source":"apache","compressible":true,"extensions":["dbk"]},"application/dskpp+xml":{"source":"iana","compressible":true},"application/dssc+der":{"source":"iana","extensions":["dssc"]},"application/dssc+xml":{"source":"iana","compressible":true,"extensions":["xdssc"]},"application/dvcs":{"source":"iana"},"application/ecmascript":{"source":"iana","compressible":true,"extensions":["ecma","es"]},"application/edi-consent":{"source":"iana"},"application/edi-x12":{"source":"iana","compressible":false},"application/edifact":{"source":"iana","compressible":false},"application/efi":{"source":"iana"},"application/emergencycalldata.comment+xml":{"source":"iana","compressible":true},"application/emergencycalldata.control+xml":{"source":"iana","compressible":true},"application/emergencycalldata.deviceinfo+xml":{"source":"iana","compressible":true},"application/emergencycalldata.ecall.msd":{"source":"iana"},"application/emergencycalldata.providerinfo+xml":{"source":"iana","compressible":true},"application/emergencycalldata.serviceinfo+xml":{"source":"iana","compressible":true},"application/emergencycalldata.subscriberinfo+xml":{"source":"iana","compressible":true},"application/emergencycalldata.veds+xml":{"source":"iana","compressible":true},"application/emma+xml":{"source":"iana","compressible":true,"extensions":["emma"]},"application/emotionml+xml":{"source":"iana","compressible":true},"application/encaprtp":{"source":"iana"},"application/epp+xml":{"source":"iana","compressible":true},"application/epub+zip":{"source":"iana","compressible":false,"extensions":["epub"]},"application/eshop":{"source":"iana"},"application/exi":{"source":"iana","extensions":["exi"]},"application/fastinfoset":{"source":"iana"},"application/fastsoap":{"source":"iana"},"application/fdt+xml":{"source":"iana","compressible":true},"application/fhir+json":{"source":"iana","compressible":true},"application/fhir+xml":{"source":"iana","compressible":true},"application/fido.trusted-apps+json":{"compressible":true},"application/fits":{"source":"iana"},"application/font-sfnt":{"source":"iana"},"application/font-tdpfr":{"source":"iana","extensions":["pfr"]},"application/font-woff":{"source":"iana","compressible":false},"application/framework-attributes+xml":{"source":"iana","compressible":true},"application/geo+json":{"source":"iana","compressible":true,"extensions":["geojson"]},"application/geo+json-seq":{"source":"iana"},"application/geopackage+sqlite3":{"source":"iana"},"application/geoxacml+xml":{"source":"iana","compressible":true},"application/gltf-buffer":{"source":"iana"},"application/gml+xml":{"source":"iana","compressible":true,"extensions":["gml"]},"application/gpx+xml":{"source":"apache","compressible":true,"extensions":["gpx"]},"application/gxf":{"source":"apache","extensions":["gxf"]},"application/gzip":{"source":"iana","compressible":false,"extensions":["gz"]},"application/h224":{"source":"iana"},"application/held+xml":{"source":"iana","compressible":true},"application/hjson":{"extensions":["hjson"]},"application/http":{"source":"iana"},"application/hyperstudio":{"source":"iana","extensions":["stk"]},"application/ibe-key-request+xml":{"source":"iana","compressible":true},"application/ibe-pkg-reply+xml":{"source":"iana","compressible":true},"application/ibe-pp-data":{"source":"iana"},"application/iges":{"source":"iana"},"application/im-iscomposing+xml":{"source":"iana","compressible":true},"application/index":{"source":"iana"},"application/index.cmd":{"source":"iana"},"application/index.obj":{"source":"iana"},"application/index.response":{"source":"iana"},"application/index.vnd":{"source":"iana"},"application/inkml+xml":{"source":"iana","compressible":true,"extensions":["ink","inkml"]},"application/iotp":{"source":"iana"},"application/ipfix":{"source":"iana","extensions":["ipfix"]},"application/ipp":{"source":"iana"},"application/isup":{"source":"iana"},"application/its+xml":{"source":"iana","compressible":true},"application/java-archive":{"source":"apache","compressible":false,"extensions":["jar","war","ear"]},"application/java-serialized-object":{"source":"apache","compressible":false,"extensions":["ser"]},"application/java-vm":{"source":"apache","compressible":false,"extensions":["class"]},"application/javascript":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["js","mjs"]},"application/jf2feed+json":{"source":"iana","compressible":true},"application/jose":{"source":"iana"},"application/jose+json":{"source":"iana","compressible":true},"application/jrd+json":{"source":"iana","compressible":true},"application/json":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["json","map"]},"application/json-patch+json":{"source":"iana","compressible":true},"application/json-seq":{"source":"iana"},"application/json5":{"extensions":["json5"]},"application/jsonml+json":{"source":"apache","compressible":true,"extensions":["jsonml"]},"application/jwk+json":{"source":"iana","compressible":true},"application/jwk-set+json":{"source":"iana","compressible":true},"application/jwt":{"source":"iana"},"application/kpml-request+xml":{"source":"iana","compressible":true},"application/kpml-response+xml":{"source":"iana","compressible":true},"application/ld+json":{"source":"iana","compressible":true,"extensions":["jsonld"]},"application/lgr+xml":{"source":"iana","compressible":true},"application/link-format":{"source":"iana"},"application/load-control+xml":{"source":"iana","compressible":true},"application/lost+xml":{"source":"iana","compressible":true,"extensions":["lostxml"]},"application/lostsync+xml":{"source":"iana","compressible":true},"application/lxf":{"source":"iana"},"application/mac-binhex40":{"source":"iana","extensions":["hqx"]},"application/mac-compactpro":{"source":"apache","extensions":["cpt"]},"application/macwriteii":{"source":"iana"},"application/mads+xml":{"source":"iana","compressible":true,"extensions":["mads"]},"application/manifest+json":{"charset":"UTF-8","compressible":true,"extensions":["webmanifest"]},"application/marc":{"source":"iana","extensions":["mrc"]},"application/marcxml+xml":{"source":"iana","compressible":true,"extensions":["mrcx"]},"application/mathematica":{"source":"iana","extensions":["ma","nb","mb"]},"application/mathml+xml":{"source":"iana","compressible":true,"extensions":["mathml"]},"application/mathml-content+xml":{"source":"iana","compressible":true},"application/mathml-presentation+xml":{"source":"iana","compressible":true},"application/mbms-associated-procedure-description+xml":{"source":"iana","compressible":true},"application/mbms-deregister+xml":{"source":"iana","compressible":true},"application/mbms-envelope+xml":{"source":"iana","compressible":true},"application/mbms-msk+xml":{"source":"iana","compressible":true},"application/mbms-msk-response+xml":{"source":"iana","compressible":true},"application/mbms-protection-description+xml":{"source":"iana","compressible":true},"application/mbms-reception-report+xml":{"source":"iana","compressible":true},"application/mbms-register+xml":{"source":"iana","compressible":true},"application/mbms-register-response+xml":{"source":"iana","compressible":true},"application/mbms-schedule+xml":{"source":"iana","compressible":true},"application/mbms-user-service-description+xml":{"source":"iana","compressible":true},"application/mbox":{"source":"iana","extensions":["mbox"]},"application/media-policy-dataset+xml":{"source":"iana","compressible":true},"application/media_control+xml":{"source":"iana","compressible":true},"application/mediaservercontrol+xml":{"source":"iana","compressible":true,"extensions":["mscml"]},"application/merge-patch+json":{"source":"iana","compressible":true},"application/metalink+xml":{"source":"apache","compressible":true,"extensions":["metalink"]},"application/metalink4+xml":{"source":"iana","compressible":true,"extensions":["meta4"]},"application/mets+xml":{"source":"iana","compressible":true,"extensions":["mets"]},"application/mf4":{"source":"iana"},"application/mikey":{"source":"iana"},"application/mmt-usd+xml":{"source":"iana","compressible":true},"application/mods+xml":{"source":"iana","compressible":true,"extensions":["mods"]},"application/moss-keys":{"source":"iana"},"application/moss-signature":{"source":"iana"},"application/mosskey-data":{"source":"iana"},"application/mosskey-request":{"source":"iana"},"application/mp21":{"source":"iana","extensions":["m21","mp21"]},"application/mp4":{"source":"iana","extensions":["mp4s","m4p"]},"application/mpeg4-generic":{"source":"iana"},"application/mpeg4-iod":{"source":"iana"},"application/mpeg4-iod-xmt":{"source":"iana"},"application/mrb-consumer+xml":{"source":"iana","compressible":true},"application/mrb-publish+xml":{"source":"iana","compressible":true},"application/msc-ivr+xml":{"source":"iana","compressible":true},"application/msc-mixer+xml":{"source":"iana","compressible":true},"application/msword":{"source":"iana","compressible":false,"extensions":["doc","dot"]},"application/mud+json":{"source":"iana","compressible":true},"application/mxf":{"source":"iana","extensions":["mxf"]},"application/n-quads":{"source":"iana"},"application/n-triples":{"source":"iana"},"application/nasdata":{"source":"iana"},"application/news-checkgroups":{"source":"iana"},"application/news-groupinfo":{"source":"iana"},"application/news-transmission":{"source":"iana"},"application/nlsml+xml":{"source":"iana","compressible":true},"application/node":{"source":"iana"},"application/nss":{"source":"iana"},"application/ocsp-request":{"source":"iana"},"application/ocsp-response":{"source":"iana"},"application/octet-stream":{"source":"iana","compressible":false,"extensions":["bin","dms","lrf","mar","so","dist","distz","pkg","bpk","dump","elc","deploy","exe","dll","deb","dmg","iso","img","msi","msp","msm","buffer"]},"application/oda":{"source":"iana","extensions":["oda"]},"application/odx":{"source":"iana"},"application/oebps-package+xml":{"source":"iana","compressible":true,"extensions":["opf"]},"application/ogg":{"source":"iana","compressible":false,"extensions":["ogx"]},"application/omdoc+xml":{"source":"apache","compressible":true,"extensions":["omdoc"]},"application/onenote":{"source":"apache","extensions":["onetoc","onetoc2","onetmp","onepkg"]},"application/oxps":{"source":"iana","extensions":["oxps"]},"application/p2p-overlay+xml":{"source":"iana","compressible":true},"application/parityfec":{"source":"iana"},"application/passport":{"source":"iana"},"application/patch-ops-error+xml":{"source":"iana","compressible":true,"extensions":["xer"]},"application/pdf":{"source":"iana","compressible":false,"extensions":["pdf"]},"application/pdx":{"source":"iana"},"application/pgp-encrypted":{"source":"iana","compressible":false,"extensions":["pgp"]},"application/pgp-keys":{"source":"iana"},"application/pgp-signature":{"source":"iana","extensions":["asc","sig"]},"application/pics-rules":{"source":"apache","extensions":["prf"]},"application/pidf+xml":{"source":"iana","compressible":true},"application/pidf-diff+xml":{"source":"iana","compressible":true},"application/pkcs10":{"source":"iana","extensions":["p10"]},"application/pkcs12":{"source":"iana"},"application/pkcs7-mime":{"source":"iana","extensions":["p7m","p7c"]},"application/pkcs7-signature":{"source":"iana","extensions":["p7s"]},"application/pkcs8":{"source":"iana","extensions":["p8"]},"application/pkcs8-encrypted":{"source":"iana"},"application/pkix-attr-cert":{"source":"iana","extensions":["ac"]},"application/pkix-cert":{"source":"iana","extensions":["cer"]},"application/pkix-crl":{"source":"iana","extensions":["crl"]},"application/pkix-pkipath":{"source":"iana","extensions":["pkipath"]},"application/pkixcmp":{"source":"iana","extensions":["pki"]},"application/pls+xml":{"source":"iana","compressible":true,"extensions":["pls"]},"application/poc-settings+xml":{"source":"iana","compressible":true},"application/postscript":{"source":"iana","compressible":true,"extensions":["ai","eps","ps"]},"application/ppsp-tracker+json":{"source":"iana","compressible":true},"application/problem+json":{"source":"iana","compressible":true},"application/problem+xml":{"source":"iana","compressible":true},"application/provenance+xml":{"source":"iana","compressible":true},"application/prs.alvestrand.titrax-sheet":{"source":"iana"},"application/prs.cww":{"source":"iana","extensions":["cww"]},"application/prs.hpub+zip":{"source":"iana","compressible":false},"application/prs.nprend":{"source":"iana"},"application/prs.plucker":{"source":"iana"},"application/prs.rdf-xml-crypt":{"source":"iana"},"application/prs.xsf+xml":{"source":"iana","compressible":true},"application/pskc+xml":{"source":"iana","compressible":true,"extensions":["pskcxml"]},"application/qsig":{"source":"iana"},"application/raml+yaml":{"compressible":true,"extensions":["raml"]},"application/raptorfec":{"source":"iana"},"application/rdap+json":{"source":"iana","compressible":true},"application/rdf+xml":{"source":"iana","compressible":true,"extensions":["rdf","owl"]},"application/reginfo+xml":{"source":"iana","compressible":true,"extensions":["rif"]},"application/relax-ng-compact-syntax":{"source":"iana","extensions":["rnc"]},"application/remote-printing":{"source":"iana"},"application/reputon+json":{"source":"iana","compressible":true},"application/resource-lists+xml":{"source":"iana","compressible":true,"extensions":["rl"]},"application/resource-lists-diff+xml":{"source":"iana","compressible":true,"extensions":["rld"]},"application/rfc+xml":{"source":"iana","compressible":true},"application/riscos":{"source":"iana"},"application/rlmi+xml":{"source":"iana","compressible":true},"application/rls-services+xml":{"source":"iana","compressible":true,"extensions":["rs"]},"application/route-apd+xml":{"source":"iana","compressible":true},"application/route-s-tsid+xml":{"source":"iana","compressible":true},"application/route-usd+xml":{"source":"iana","compressible":true},"application/rpki-ghostbusters":{"source":"iana","extensions":["gbr"]},"application/rpki-manifest":{"source":"iana","extensions":["mft"]},"application/rpki-publication":{"source":"iana"},"application/rpki-roa":{"source":"iana","extensions":["roa"]},"application/rpki-updown":{"source":"iana"},"application/rsd+xml":{"source":"apache","compressible":true,"extensions":["rsd"]},"application/rss+xml":{"source":"apache","compressible":true,"extensions":["rss"]},"application/rtf":{"source":"iana","compressible":true,"extensions":["rtf"]},"application/rtploopback":{"source":"iana"},"application/rtx":{"source":"iana"},"application/samlassertion+xml":{"source":"iana","compressible":true},"application/samlmetadata+xml":{"source":"iana","compressible":true},"application/sbml+xml":{"source":"iana","compressible":true,"extensions":["sbml"]},"application/scaip+xml":{"source":"iana","compressible":true},"application/scim+json":{"source":"iana","compressible":true},"application/scvp-cv-request":{"source":"iana","extensions":["scq"]},"application/scvp-cv-response":{"source":"iana","extensions":["scs"]},"application/scvp-vp-request":{"source":"iana","extensions":["spq"]},"application/scvp-vp-response":{"source":"iana","extensions":["spp"]},"application/sdp":{"source":"iana","extensions":["sdp"]},"application/secevent+jwt":{"source":"iana"},"application/senml+cbor":{"source":"iana"},"application/senml+json":{"source":"iana","compressible":true},"application/senml+xml":{"source":"iana","compressible":true},"application/senml-exi":{"source":"iana"},"application/sensml+cbor":{"source":"iana"},"application/sensml+json":{"source":"iana","compressible":true},"application/sensml+xml":{"source":"iana","compressible":true},"application/sensml-exi":{"source":"iana"},"application/sep+xml":{"source":"iana","compressible":true},"application/sep-exi":{"source":"iana"},"application/session-info":{"source":"iana"},"application/set-payment":{"source":"iana"},"application/set-payment-initiation":{"source":"iana","extensions":["setpay"]},"application/set-registration":{"source":"iana"},"application/set-registration-initiation":{"source":"iana","extensions":["setreg"]},"application/sgml":{"source":"iana"},"application/sgml-open-catalog":{"source":"iana"},"application/shf+xml":{"source":"iana","compressible":true,"extensions":["shf"]},"application/sieve":{"source":"iana"},"application/simple-filter+xml":{"source":"iana","compressible":true},"application/simple-message-summary":{"source":"iana"},"application/simplesymbolcontainer":{"source":"iana"},"application/slate":{"source":"iana"},"application/smil":{"source":"iana"},"application/smil+xml":{"source":"iana","compressible":true,"extensions":["smi","smil"]},"application/smpte336m":{"source":"iana"},"application/soap+fastinfoset":{"source":"iana"},"application/soap+xml":{"source":"iana","compressible":true},"application/sparql-query":{"source":"iana","extensions":["rq"]},"application/sparql-results+xml":{"source":"iana","compressible":true,"extensions":["srx"]},"application/spirits-event+xml":{"source":"iana","compressible":true},"application/sql":{"source":"iana"},"application/srgs":{"source":"iana","extensions":["gram"]},"application/srgs+xml":{"source":"iana","compressible":true,"extensions":["grxml"]},"application/sru+xml":{"source":"iana","compressible":true,"extensions":["sru"]},"application/ssdl+xml":{"source":"apache","compressible":true,"extensions":["ssdl"]},"application/ssml+xml":{"source":"iana","compressible":true,"extensions":["ssml"]},"application/stix+json":{"source":"iana","compressible":true},"application/tamp-apex-update":{"source":"iana"},"application/tamp-apex-update-confirm":{"source":"iana"},"application/tamp-community-update":{"source":"iana"},"application/tamp-community-update-confirm":{"source":"iana"},"application/tamp-error":{"source":"iana"},"application/tamp-sequence-adjust":{"source":"iana"},"application/tamp-sequence-adjust-confirm":{"source":"iana"},"application/tamp-status-query":{"source":"iana"},"application/tamp-status-response":{"source":"iana"},"application/tamp-update":{"source":"iana"},"application/tamp-update-confirm":{"source":"iana"},"application/tar":{"compressible":true},"application/taxii+json":{"source":"iana","compressible":true},"application/tei+xml":{"source":"iana","compressible":true,"extensions":["tei","teicorpus"]},"application/thraud+xml":{"source":"iana","compressible":true,"extensions":["tfi"]},"application/timestamp-query":{"source":"iana"},"application/timestamp-reply":{"source":"iana"},"application/timestamped-data":{"source":"iana","extensions":["tsd"]},"application/tlsrpt+gzip":{"source":"iana"},"application/tlsrpt+json":{"source":"iana","compressible":true},"application/tnauthlist":{"source":"iana"},"application/trickle-ice-sdpfrag":{"source":"iana"},"application/trig":{"source":"iana"},"application/ttml+xml":{"source":"iana","compressible":true},"application/tve-trigger":{"source":"iana"},"application/ulpfec":{"source":"iana"},"application/urc-grpsheet+xml":{"source":"iana","compressible":true},"application/urc-ressheet+xml":{"source":"iana","compressible":true},"application/urc-targetdesc+xml":{"source":"iana","compressible":true},"application/urc-uisocketdesc+xml":{"source":"iana","compressible":true},"application/vcard+json":{"source":"iana","compressible":true},"application/vcard+xml":{"source":"iana","compressible":true},"application/vemmi":{"source":"iana"},"application/vividence.scriptfile":{"source":"apache"},"application/vnd.1000minds.decision-model+xml":{"source":"iana","compressible":true},"application/vnd.3gpp-prose+xml":{"source":"iana","compressible":true},"application/vnd.3gpp-prose-pc3ch+xml":{"source":"iana","compressible":true},"application/vnd.3gpp-v2x-local-service-information":{"source":"iana"},"application/vnd.3gpp.access-transfer-events+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.bsf+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.gmop+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mc-signalling-ear":{"source":"iana"},"application/vnd.3gpp.mcdata-payload":{"source":"iana"},"application/vnd.3gpp.mcdata-signalling":{"source":"iana"},"application/vnd.3gpp.mcptt-affiliation-command+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-floor-request+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-location-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-mbms-usage-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mcptt-signed+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.mid-call+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.pic-bw-large":{"source":"iana","extensions":["plb"]},"application/vnd.3gpp.pic-bw-small":{"source":"iana","extensions":["psb"]},"application/vnd.3gpp.pic-bw-var":{"source":"iana","extensions":["pvb"]},"application/vnd.3gpp.sms":{"source":"iana"},"application/vnd.3gpp.sms+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.srvcc-ext+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.srvcc-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.state-and-event-info+xml":{"source":"iana","compressible":true},"application/vnd.3gpp.ussd+xml":{"source":"iana","compressible":true},"application/vnd.3gpp2.bcmcsinfo+xml":{"source":"iana","compressible":true},"application/vnd.3gpp2.sms":{"source":"iana"},"application/vnd.3gpp2.tcap":{"source":"iana","extensions":["tcap"]},"application/vnd.3lightssoftware.imagescal":{"source":"iana"},"application/vnd.3m.post-it-notes":{"source":"iana","extensions":["pwn"]},"application/vnd.accpac.simply.aso":{"source":"iana","extensions":["aso"]},"application/vnd.accpac.simply.imp":{"source":"iana","extensions":["imp"]},"application/vnd.acucobol":{"source":"iana","extensions":["acu"]},"application/vnd.acucorp":{"source":"iana","extensions":["atc","acutc"]},"application/vnd.adobe.air-application-installer-package+zip":{"source":"apache","compressible":false,"extensions":["air"]},"application/vnd.adobe.flash.movie":{"source":"iana"},"application/vnd.adobe.formscentral.fcdt":{"source":"iana","extensions":["fcdt"]},"application/vnd.adobe.fxp":{"source":"iana","extensions":["fxp","fxpl"]},"application/vnd.adobe.partial-upload":{"source":"iana"},"application/vnd.adobe.xdp+xml":{"source":"iana","compressible":true,"extensions":["xdp"]},"application/vnd.adobe.xfdf":{"source":"iana","extensions":["xfdf"]},"application/vnd.aether.imp":{"source":"iana"},"application/vnd.afpc.afplinedata":{"source":"iana"},"application/vnd.afpc.modca":{"source":"iana"},"application/vnd.ah-barcode":{"source":"iana"},"application/vnd.ahead.space":{"source":"iana","extensions":["ahead"]},"application/vnd.airzip.filesecure.azf":{"source":"iana","extensions":["azf"]},"application/vnd.airzip.filesecure.azs":{"source":"iana","extensions":["azs"]},"application/vnd.amadeus+json":{"source":"iana","compressible":true},"application/vnd.amazon.ebook":{"source":"apache","extensions":["azw"]},"application/vnd.amazon.mobi8-ebook":{"source":"iana"},"application/vnd.americandynamics.acc":{"source":"iana","extensions":["acc"]},"application/vnd.amiga.ami":{"source":"iana","extensions":["ami"]},"application/vnd.amundsen.maze+xml":{"source":"iana","compressible":true},"application/vnd.android.package-archive":{"source":"apache","compressible":false,"extensions":["apk"]},"application/vnd.anki":{"source":"iana"},"application/vnd.anser-web-certificate-issue-initiation":{"source":"iana","extensions":["cii"]},"application/vnd.anser-web-funds-transfer-initiation":{"source":"apache","extensions":["fti"]},"application/vnd.antix.game-component":{"source":"iana","extensions":["atx"]},"application/vnd.apache.thrift.binary":{"source":"iana"},"application/vnd.apache.thrift.compact":{"source":"iana"},"application/vnd.apache.thrift.json":{"source":"iana"},"application/vnd.api+json":{"source":"iana","compressible":true},"application/vnd.apothekende.reservation+json":{"source":"iana","compressible":true},"application/vnd.apple.installer+xml":{"source":"iana","compressible":true,"extensions":["mpkg"]},"application/vnd.apple.keynote":{"source":"iana","extensions":["keynote"]},"application/vnd.apple.mpegurl":{"source":"iana","extensions":["m3u8"]},"application/vnd.apple.numbers":{"source":"iana","extensions":["numbers"]},"application/vnd.apple.pages":{"source":"iana","extensions":["pages"]},"application/vnd.apple.pkpass":{"compressible":false,"extensions":["pkpass"]},"application/vnd.arastra.swi":{"source":"iana"},"application/vnd.aristanetworks.swi":{"source":"iana","extensions":["swi"]},"application/vnd.artisan+json":{"source":"iana","compressible":true},"application/vnd.artsquare":{"source":"iana"},"application/vnd.astraea-software.iota":{"source":"iana","extensions":["iota"]},"application/vnd.audiograph":{"source":"iana","extensions":["aep"]},"application/vnd.autopackage":{"source":"iana"},"application/vnd.avalon+json":{"source":"iana","compressible":true},"application/vnd.avistar+xml":{"source":"iana","compressible":true},"application/vnd.balsamiq.bmml+xml":{"source":"iana","compressible":true},"application/vnd.balsamiq.bmpr":{"source":"iana"},"application/vnd.banana-accounting":{"source":"iana"},"application/vnd.bbf.usp.msg":{"source":"iana"},"application/vnd.bbf.usp.msg+json":{"source":"iana","compressible":true},"application/vnd.bekitzur-stech+json":{"source":"iana","compressible":true},"application/vnd.bint.med-content":{"source":"iana"},"application/vnd.biopax.rdf+xml":{"source":"iana","compressible":true},"application/vnd.blink-idb-value-wrapper":{"source":"iana"},"application/vnd.blueice.multipass":{"source":"iana","extensions":["mpm"]},"application/vnd.bluetooth.ep.oob":{"source":"iana"},"application/vnd.bluetooth.le.oob":{"source":"iana"},"application/vnd.bmi":{"source":"iana","extensions":["bmi"]},"application/vnd.businessobjects":{"source":"iana","extensions":["rep"]},"application/vnd.byu.uapi+json":{"source":"iana","compressible":true},"application/vnd.cab-jscript":{"source":"iana"},"application/vnd.canon-cpdl":{"source":"iana"},"application/vnd.canon-lips":{"source":"iana"},"application/vnd.capasystems-pg+json":{"source":"iana","compressible":true},"application/vnd.cendio.thinlinc.clientconf":{"source":"iana"},"application/vnd.century-systems.tcp_stream":{"source":"iana"},"application/vnd.chemdraw+xml":{"source":"iana","compressible":true,"extensions":["cdxml"]},"application/vnd.chess-pgn":{"source":"iana"},"application/vnd.chipnuts.karaoke-mmd":{"source":"iana","extensions":["mmd"]},"application/vnd.cinderella":{"source":"iana","extensions":["cdy"]},"application/vnd.cirpack.isdn-ext":{"source":"iana"},"application/vnd.citationstyles.style+xml":{"source":"iana","compressible":true,"extensions":["csl"]},"application/vnd.claymore":{"source":"iana","extensions":["cla"]},"application/vnd.cloanto.rp9":{"source":"iana","extensions":["rp9"]},"application/vnd.clonk.c4group":{"source":"iana","extensions":["c4g","c4d","c4f","c4p","c4u"]},"application/vnd.cluetrust.cartomobile-config":{"source":"iana","extensions":["c11amc"]},"application/vnd.cluetrust.cartomobile-config-pkg":{"source":"iana","extensions":["c11amz"]},"application/vnd.coffeescript":{"source":"iana"},"application/vnd.collabio.xodocuments.document":{"source":"iana"},"application/vnd.collabio.xodocuments.document-template":{"source":"iana"},"application/vnd.collabio.xodocuments.presentation":{"source":"iana"},"application/vnd.collabio.xodocuments.presentation-template":{"source":"iana"},"application/vnd.collabio.xodocuments.spreadsheet":{"source":"iana"},"application/vnd.collabio.xodocuments.spreadsheet-template":{"source":"iana"},"application/vnd.collection+json":{"source":"iana","compressible":true},"application/vnd.collection.doc+json":{"source":"iana","compressible":true},"application/vnd.collection.next+json":{"source":"iana","compressible":true},"application/vnd.comicbook+zip":{"source":"iana","compressible":false},"application/vnd.comicbook-rar":{"source":"iana"},"application/vnd.commerce-battelle":{"source":"iana"},"application/vnd.commonspace":{"source":"iana","extensions":["csp"]},"application/vnd.contact.cmsg":{"source":"iana","extensions":["cdbcmsg"]},"application/vnd.coreos.ignition+json":{"source":"iana","compressible":true},"application/vnd.cosmocaller":{"source":"iana","extensions":["cmc"]},"application/vnd.crick.clicker":{"source":"iana","extensions":["clkx"]},"application/vnd.crick.clicker.keyboard":{"source":"iana","extensions":["clkk"]},"application/vnd.crick.clicker.palette":{"source":"iana","extensions":["clkp"]},"application/vnd.crick.clicker.template":{"source":"iana","extensions":["clkt"]},"application/vnd.crick.clicker.wordbank":{"source":"iana","extensions":["clkw"]},"application/vnd.criticaltools.wbs+xml":{"source":"iana","compressible":true,"extensions":["wbs"]},"application/vnd.ctc-posml":{"source":"iana","extensions":["pml"]},"application/vnd.ctct.ws+xml":{"source":"iana","compressible":true},"application/vnd.cups-pdf":{"source":"iana"},"application/vnd.cups-postscript":{"source":"iana"},"application/vnd.cups-ppd":{"source":"iana","extensions":["ppd"]},"application/vnd.cups-raster":{"source":"iana"},"application/vnd.cups-raw":{"source":"iana"},"application/vnd.curl":{"source":"iana"},"application/vnd.curl.car":{"source":"apache","extensions":["car"]},"application/vnd.curl.pcurl":{"source":"apache","extensions":["pcurl"]},"application/vnd.cyan.dean.root+xml":{"source":"iana","compressible":true},"application/vnd.cybank":{"source":"iana"},"application/vnd.d2l.coursepackage1p0+zip":{"source":"iana","compressible":false},"application/vnd.dart":{"source":"iana","compressible":true,"extensions":["dart"]},"application/vnd.data-vision.rdz":{"source":"iana","extensions":["rdz"]},"application/vnd.datapackage+json":{"source":"iana","compressible":true},"application/vnd.dataresource+json":{"source":"iana","compressible":true},"application/vnd.debian.binary-package":{"source":"iana"},"application/vnd.dece.data":{"source":"iana","extensions":["uvf","uvvf","uvd","uvvd"]},"application/vnd.dece.ttml+xml":{"source":"iana","compressible":true,"extensions":["uvt","uvvt"]},"application/vnd.dece.unspecified":{"source":"iana","extensions":["uvx","uvvx"]},"application/vnd.dece.zip":{"source":"iana","extensions":["uvz","uvvz"]},"application/vnd.denovo.fcselayout-link":{"source":"iana","extensions":["fe_launch"]},"application/vnd.desmume.movie":{"source":"iana"},"application/vnd.dir-bi.plate-dl-nosuffix":{"source":"iana"},"application/vnd.dm.delegation+xml":{"source":"iana","compressible":true},"application/vnd.dna":{"source":"iana","extensions":["dna"]},"application/vnd.document+json":{"source":"iana","compressible":true},"application/vnd.dolby.mlp":{"source":"apache","extensions":["mlp"]},"application/vnd.dolby.mobile.1":{"source":"iana"},"application/vnd.dolby.mobile.2":{"source":"iana"},"application/vnd.doremir.scorecloud-binary-document":{"source":"iana"},"application/vnd.dpgraph":{"source":"iana","extensions":["dpg"]},"application/vnd.dreamfactory":{"source":"iana","extensions":["dfac"]},"application/vnd.drive+json":{"source":"iana","compressible":true},"application/vnd.ds-keypoint":{"source":"apache","extensions":["kpxx"]},"application/vnd.dtg.local":{"source":"iana"},"application/vnd.dtg.local.flash":{"source":"iana"},"application/vnd.dtg.local.html":{"source":"iana"},"application/vnd.dvb.ait":{"source":"iana","extensions":["ait"]},"application/vnd.dvb.dvbj":{"source":"iana"},"application/vnd.dvb.esgcontainer":{"source":"iana"},"application/vnd.dvb.ipdcdftnotifaccess":{"source":"iana"},"application/vnd.dvb.ipdcesgaccess":{"source":"iana"},"application/vnd.dvb.ipdcesgaccess2":{"source":"iana"},"application/vnd.dvb.ipdcesgpdd":{"source":"iana"},"application/vnd.dvb.ipdcroaming":{"source":"iana"},"application/vnd.dvb.iptv.alfec-base":{"source":"iana"},"application/vnd.dvb.iptv.alfec-enhancement":{"source":"iana"},"application/vnd.dvb.notif-aggregate-root+xml":{"source":"iana","compressible":true},"application/vnd.dvb.notif-container+xml":{"source":"iana","compressible":true},"application/vnd.dvb.notif-generic+xml":{"source":"iana","compressible":true},"application/vnd.dvb.notif-ia-msglist+xml":{"source":"iana","compressible":true},"application/vnd.dvb.notif-ia-registration-request+xml":{"source":"iana","compressible":true},"application/vnd.dvb.notif-ia-registration-response+xml":{"source":"iana","compressible":true},"application/vnd.dvb.notif-init+xml":{"source":"iana","compressible":true},"application/vnd.dvb.pfr":{"source":"iana"},"application/vnd.dvb.service":{"source":"iana","extensions":["svc"]},"application/vnd.dxr":{"source":"iana"},"application/vnd.dynageo":{"source":"iana","extensions":["geo"]},"application/vnd.dzr":{"source":"iana"},"application/vnd.easykaraoke.cdgdownload":{"source":"iana"},"application/vnd.ecdis-update":{"source":"iana"},"application/vnd.ecip.rlp":{"source":"iana"},"application/vnd.ecowin.chart":{"source":"iana","extensions":["mag"]},"application/vnd.ecowin.filerequest":{"source":"iana"},"application/vnd.ecowin.fileupdate":{"source":"iana"},"application/vnd.ecowin.series":{"source":"iana"},"application/vnd.ecowin.seriesrequest":{"source":"iana"},"application/vnd.ecowin.seriesupdate":{"source":"iana"},"application/vnd.efi.img":{"source":"iana"},"application/vnd.efi.iso":{"source":"iana"},"application/vnd.emclient.accessrequest+xml":{"source":"iana","compressible":true},"application/vnd.enliven":{"source":"iana","extensions":["nml"]},"application/vnd.enphase.envoy":{"source":"iana"},"application/vnd.eprints.data+xml":{"source":"iana","compressible":true},"application/vnd.epson.esf":{"source":"iana","extensions":["esf"]},"application/vnd.epson.msf":{"source":"iana","extensions":["msf"]},"application/vnd.epson.quickanime":{"source":"iana","extensions":["qam"]},"application/vnd.epson.salt":{"source":"iana","extensions":["slt"]},"application/vnd.epson.ssf":{"source":"iana","extensions":["ssf"]},"application/vnd.ericsson.quickcall":{"source":"iana"},"application/vnd.espass-espass+zip":{"source":"iana","compressible":false},"application/vnd.eszigno3+xml":{"source":"iana","compressible":true,"extensions":["es3","et3"]},"application/vnd.etsi.aoc+xml":{"source":"iana","compressible":true},"application/vnd.etsi.asic-e+zip":{"source":"iana","compressible":false},"application/vnd.etsi.asic-s+zip":{"source":"iana","compressible":false},"application/vnd.etsi.cug+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvcommand+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvdiscovery+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvprofile+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvsad-bc+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvsad-cod+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvsad-npvr+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvservice+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvsync+xml":{"source":"iana","compressible":true},"application/vnd.etsi.iptvueprofile+xml":{"source":"iana","compressible":true},"application/vnd.etsi.mcid+xml":{"source":"iana","compressible":true},"application/vnd.etsi.mheg5":{"source":"iana"},"application/vnd.etsi.overload-control-policy-dataset+xml":{"source":"iana","compressible":true},"application/vnd.etsi.pstn+xml":{"source":"iana","compressible":true},"application/vnd.etsi.sci+xml":{"source":"iana","compressible":true},"application/vnd.etsi.simservs+xml":{"source":"iana","compressible":true},"application/vnd.etsi.timestamp-token":{"source":"iana"},"application/vnd.etsi.tsl+xml":{"source":"iana","compressible":true},"application/vnd.etsi.tsl.der":{"source":"iana"},"application/vnd.eudora.data":{"source":"iana"},"application/vnd.evolv.ecig.profile":{"source":"iana"},"application/vnd.evolv.ecig.settings":{"source":"iana"},"application/vnd.evolv.ecig.theme":{"source":"iana"},"application/vnd.exstream-empower+zip":{"source":"iana","compressible":false},"application/vnd.ezpix-album":{"source":"iana","extensions":["ez2"]},"application/vnd.ezpix-package":{"source":"iana","extensions":["ez3"]},"application/vnd.f-secure.mobile":{"source":"iana"},"application/vnd.fastcopy-disk-image":{"source":"iana"},"application/vnd.fdf":{"source":"iana","extensions":["fdf"]},"application/vnd.fdsn.mseed":{"source":"iana","extensions":["mseed"]},"application/vnd.fdsn.seed":{"source":"iana","extensions":["seed","dataless"]},"application/vnd.ffsns":{"source":"iana"},"application/vnd.filmit.zfc":{"source":"iana"},"application/vnd.fints":{"source":"iana"},"application/vnd.firemonkeys.cloudcell":{"source":"iana"},"application/vnd.flographit":{"source":"iana","extensions":["gph"]},"application/vnd.fluxtime.clip":{"source":"iana","extensions":["ftc"]},"application/vnd.font-fontforge-sfd":{"source":"iana"},"application/vnd.framemaker":{"source":"iana","extensions":["fm","frame","maker","book"]},"application/vnd.frogans.fnc":{"source":"iana","extensions":["fnc"]},"application/vnd.frogans.ltf":{"source":"iana","extensions":["ltf"]},"application/vnd.fsc.weblaunch":{"source":"iana","extensions":["fsc"]},"application/vnd.fujitsu.oasys":{"source":"iana","extensions":["oas"]},"application/vnd.fujitsu.oasys2":{"source":"iana","extensions":["oa2"]},"application/vnd.fujitsu.oasys3":{"source":"iana","extensions":["oa3"]},"application/vnd.fujitsu.oasysgp":{"source":"iana","extensions":["fg5"]},"application/vnd.fujitsu.oasysprs":{"source":"iana","extensions":["bh2"]},"application/vnd.fujixerox.art-ex":{"source":"iana"},"application/vnd.fujixerox.art4":{"source":"iana"},"application/vnd.fujixerox.ddd":{"source":"iana","extensions":["ddd"]},"application/vnd.fujixerox.docuworks":{"source":"iana","extensions":["xdw"]},"application/vnd.fujixerox.docuworks.binder":{"source":"iana","extensions":["xbd"]},"application/vnd.fujixerox.docuworks.container":{"source":"iana"},"application/vnd.fujixerox.hbpl":{"source":"iana"},"application/vnd.fut-misnet":{"source":"iana"},"application/vnd.futoin+cbor":{"source":"iana"},"application/vnd.futoin+json":{"source":"iana","compressible":true},"application/vnd.fuzzysheet":{"source":"iana","extensions":["fzs"]},"application/vnd.genomatix.tuxedo":{"source":"iana","extensions":["txd"]},"application/vnd.geo+json":{"source":"iana","compressible":true},"application/vnd.geocube+xml":{"source":"iana","compressible":true},"application/vnd.geogebra.file":{"source":"iana","extensions":["ggb"]},"application/vnd.geogebra.tool":{"source":"iana","extensions":["ggt"]},"application/vnd.geometry-explorer":{"source":"iana","extensions":["gex","gre"]},"application/vnd.geonext":{"source":"iana","extensions":["gxt"]},"application/vnd.geoplan":{"source":"iana","extensions":["g2w"]},"application/vnd.geospace":{"source":"iana","extensions":["g3w"]},"application/vnd.gerber":{"source":"iana"},"application/vnd.globalplatform.card-content-mgt":{"source":"iana"},"application/vnd.globalplatform.card-content-mgt-response":{"source":"iana"},"application/vnd.gmx":{"source":"iana","extensions":["gmx"]},"application/vnd.google-apps.document":{"compressible":false,"extensions":["gdoc"]},"application/vnd.google-apps.presentation":{"compressible":false,"extensions":["gslides"]},"application/vnd.google-apps.spreadsheet":{"compressible":false,"extensions":["gsheet"]},"application/vnd.google-earth.kml+xml":{"source":"iana","compressible":true,"extensions":["kml"]},"application/vnd.google-earth.kmz":{"source":"iana","compressible":false,"extensions":["kmz"]},"application/vnd.gov.sk.e-form+xml":{"source":"iana","compressible":true},"application/vnd.gov.sk.e-form+zip":{"source":"iana","compressible":false},"application/vnd.gov.sk.xmldatacontainer+xml":{"source":"iana","compressible":true},"application/vnd.grafeq":{"source":"iana","extensions":["gqf","gqs"]},"application/vnd.gridmp":{"source":"iana"},"application/vnd.groove-account":{"source":"iana","extensions":["gac"]},"application/vnd.groove-help":{"source":"iana","extensions":["ghf"]},"application/vnd.groove-identity-message":{"source":"iana","extensions":["gim"]},"application/vnd.groove-injector":{"source":"iana","extensions":["grv"]},"application/vnd.groove-tool-message":{"source":"iana","extensions":["gtm"]},"application/vnd.groove-tool-template":{"source":"iana","extensions":["tpl"]},"application/vnd.groove-vcard":{"source":"iana","extensions":["vcg"]},"application/vnd.hal+json":{"source":"iana","compressible":true},"application/vnd.hal+xml":{"source":"iana","compressible":true,"extensions":["hal"]},"application/vnd.handheld-entertainment+xml":{"source":"iana","compressible":true,"extensions":["zmm"]},"application/vnd.hbci":{"source":"iana","extensions":["hbci"]},"application/vnd.hc+json":{"source":"iana","compressible":true},"application/vnd.hcl-bireports":{"source":"iana"},"application/vnd.hdt":{"source":"iana"},"application/vnd.heroku+json":{"source":"iana","compressible":true},"application/vnd.hhe.lesson-player":{"source":"iana","extensions":["les"]},"application/vnd.hp-hpgl":{"source":"iana","extensions":["hpgl"]},"application/vnd.hp-hpid":{"source":"iana","extensions":["hpid"]},"application/vnd.hp-hps":{"source":"iana","extensions":["hps"]},"application/vnd.hp-jlyt":{"source":"iana","extensions":["jlt"]},"application/vnd.hp-pcl":{"source":"iana","extensions":["pcl"]},"application/vnd.hp-pclxl":{"source":"iana","extensions":["pclxl"]},"application/vnd.httphone":{"source":"iana"},"application/vnd.hydrostatix.sof-data":{"source":"iana","extensions":["sfd-hdstx"]},"application/vnd.hyper+json":{"source":"iana","compressible":true},"application/vnd.hyper-item+json":{"source":"iana","compressible":true},"application/vnd.hyperdrive+json":{"source":"iana","compressible":true},"application/vnd.hzn-3d-crossword":{"source":"iana"},"application/vnd.ibm.afplinedata":{"source":"iana"},"application/vnd.ibm.electronic-media":{"source":"iana"},"application/vnd.ibm.minipay":{"source":"iana","extensions":["mpy"]},"application/vnd.ibm.modcap":{"source":"iana","extensions":["afp","listafp","list3820"]},"application/vnd.ibm.rights-management":{"source":"iana","extensions":["irm"]},"application/vnd.ibm.secure-container":{"source":"iana","extensions":["sc"]},"application/vnd.iccprofile":{"source":"iana","extensions":["icc","icm"]},"application/vnd.ieee.1905":{"source":"iana"},"application/vnd.igloader":{"source":"iana","extensions":["igl"]},"application/vnd.imagemeter.folder+zip":{"source":"iana","compressible":false},"application/vnd.imagemeter.image+zip":{"source":"iana","compressible":false},"application/vnd.immervision-ivp":{"source":"iana","extensions":["ivp"]},"application/vnd.immervision-ivu":{"source":"iana","extensions":["ivu"]},"application/vnd.ims.imsccv1p1":{"source":"iana"},"application/vnd.ims.imsccv1p2":{"source":"iana"},"application/vnd.ims.imsccv1p3":{"source":"iana"},"application/vnd.ims.lis.v2.result+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolconsumerprofile+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolproxy+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolproxy.id+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolsettings+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolsettings.simple+json":{"source":"iana","compressible":true},"application/vnd.informedcontrol.rms+xml":{"source":"iana","compressible":true},"application/vnd.informix-visionary":{"source":"iana"},"application/vnd.infotech.project":{"source":"iana"},"application/vnd.infotech.project+xml":{"source":"iana","compressible":true},"application/vnd.innopath.wamp.notification":{"source":"iana"},"application/vnd.insors.igm":{"source":"iana","extensions":["igm"]},"application/vnd.intercon.formnet":{"source":"iana","extensions":["xpw","xpx"]},"application/vnd.intergeo":{"source":"iana","extensions":["i2g"]},"application/vnd.intertrust.digibox":{"source":"iana"},"application/vnd.intertrust.nncp":{"source":"iana"},"application/vnd.intu.qbo":{"source":"iana","extensions":["qbo"]},"application/vnd.intu.qfx":{"source":"iana","extensions":["qfx"]},"application/vnd.iptc.g2.catalogitem+xml":{"source":"iana","compressible":true},"application/vnd.iptc.g2.conceptitem+xml":{"source":"iana","compressible":true},"application/vnd.iptc.g2.knowledgeitem+xml":{"source":"iana","compressible":true},"application/vnd.iptc.g2.newsitem+xml":{"source":"iana","compressible":true},"application/vnd.iptc.g2.newsmessage+xml":{"source":"iana","compressible":true},"application/vnd.iptc.g2.packageitem+xml":{"source":"iana","compressible":true},"application/vnd.iptc.g2.planningitem+xml":{"source":"iana","compressible":true},"application/vnd.ipunplugged.rcprofile":{"source":"iana","extensions":["rcprofile"]},"application/vnd.irepository.package+xml":{"source":"iana","compressible":true,"extensions":["irp"]},"application/vnd.is-xpr":{"source":"iana","extensions":["xpr"]},"application/vnd.isac.fcs":{"source":"iana","extensions":["fcs"]},"application/vnd.jam":{"source":"iana","extensions":["jam"]},"application/vnd.japannet-directory-service":{"source":"iana"},"application/vnd.japannet-jpnstore-wakeup":{"source":"iana"},"application/vnd.japannet-payment-wakeup":{"source":"iana"},"application/vnd.japannet-registration":{"source":"iana"},"application/vnd.japannet-registration-wakeup":{"source":"iana"},"application/vnd.japannet-setstore-wakeup":{"source":"iana"},"application/vnd.japannet-verification":{"source":"iana"},"application/vnd.japannet-verification-wakeup":{"source":"iana"},"application/vnd.jcp.javame.midlet-rms":{"source":"iana","extensions":["rms"]},"application/vnd.jisp":{"source":"iana","extensions":["jisp"]},"application/vnd.joost.joda-archive":{"source":"iana","extensions":["joda"]},"application/vnd.jsk.isdn-ngn":{"source":"iana"},"application/vnd.kahootz":{"source":"iana","extensions":["ktz","ktr"]},"application/vnd.kde.karbon":{"source":"iana","extensions":["karbon"]},"application/vnd.kde.kchart":{"source":"iana","extensions":["chrt"]},"application/vnd.kde.kformula":{"source":"iana","extensions":["kfo"]},"application/vnd.kde.kivio":{"source":"iana","extensions":["flw"]},"application/vnd.kde.kontour":{"source":"iana","extensions":["kon"]},"application/vnd.kde.kpresenter":{"source":"iana","extensions":["kpr","kpt"]},"application/vnd.kde.kspread":{"source":"iana","extensions":["ksp"]},"application/vnd.kde.kword":{"source":"iana","extensions":["kwd","kwt"]},"application/vnd.kenameaapp":{"source":"iana","extensions":["htke"]},"application/vnd.kidspiration":{"source":"iana","extensions":["kia"]},"application/vnd.kinar":{"source":"iana","extensions":["kne","knp"]},"application/vnd.koan":{"source":"iana","extensions":["skp","skd","skt","skm"]},"application/vnd.kodak-descriptor":{"source":"iana","extensions":["sse"]},"application/vnd.las.las+json":{"source":"iana","compressible":true},"application/vnd.las.las+xml":{"source":"iana","compressible":true,"extensions":["lasxml"]},"application/vnd.leap+json":{"source":"iana","compressible":true},"application/vnd.liberty-request+xml":{"source":"iana","compressible":true},"application/vnd.llamagraphics.life-balance.desktop":{"source":"iana","extensions":["lbd"]},"application/vnd.llamagraphics.life-balance.exchange+xml":{"source":"iana","compressible":true,"extensions":["lbe"]},"application/vnd.lotus-1-2-3":{"source":"iana","extensions":["123"]},"application/vnd.lotus-approach":{"source":"iana","extensions":["apr"]},"application/vnd.lotus-freelance":{"source":"iana","extensions":["pre"]},"application/vnd.lotus-notes":{"source":"iana","extensions":["nsf"]},"application/vnd.lotus-organizer":{"source":"iana","extensions":["org"]},"application/vnd.lotus-screencam":{"source":"iana","extensions":["scm"]},"application/vnd.lotus-wordpro":{"source":"iana","extensions":["lwp"]},"application/vnd.macports.portpkg":{"source":"iana","extensions":["portpkg"]},"application/vnd.mapbox-vector-tile":{"source":"iana"},"application/vnd.marlin.drm.actiontoken+xml":{"source":"iana","compressible":true},"application/vnd.marlin.drm.conftoken+xml":{"source":"iana","compressible":true},"application/vnd.marlin.drm.license+xml":{"source":"iana","compressible":true},"application/vnd.marlin.drm.mdcf":{"source":"iana"},"application/vnd.mason+json":{"source":"iana","compressible":true},"application/vnd.maxmind.maxmind-db":{"source":"iana"},"application/vnd.mcd":{"source":"iana","extensions":["mcd"]},"application/vnd.medcalcdata":{"source":"iana","extensions":["mc1"]},"application/vnd.mediastation.cdkey":{"source":"iana","extensions":["cdkey"]},"application/vnd.meridian-slingshot":{"source":"iana"},"application/vnd.mfer":{"source":"iana","extensions":["mwf"]},"application/vnd.mfmp":{"source":"iana","extensions":["mfm"]},"application/vnd.micro+json":{"source":"iana","compressible":true},"application/vnd.micrografx.flo":{"source":"iana","extensions":["flo"]},"application/vnd.micrografx.igx":{"source":"iana","extensions":["igx"]},"application/vnd.microsoft.portable-executable":{"source":"iana"},"application/vnd.microsoft.windows.thumbnail-cache":{"source":"iana"},"application/vnd.miele+json":{"source":"iana","compressible":true},"application/vnd.mif":{"source":"iana","extensions":["mif"]},"application/vnd.minisoft-hp3000-save":{"source":"iana"},"application/vnd.mitsubishi.misty-guard.trustweb":{"source":"iana"},"application/vnd.mobius.daf":{"source":"iana","extensions":["daf"]},"application/vnd.mobius.dis":{"source":"iana","extensions":["dis"]},"application/vnd.mobius.mbk":{"source":"iana","extensions":["mbk"]},"application/vnd.mobius.mqy":{"source":"iana","extensions":["mqy"]},"application/vnd.mobius.msl":{"source":"iana","extensions":["msl"]},"application/vnd.mobius.plc":{"source":"iana","extensions":["plc"]},"application/vnd.mobius.txf":{"source":"iana","extensions":["txf"]},"application/vnd.mophun.application":{"source":"iana","extensions":["mpn"]},"application/vnd.mophun.certificate":{"source":"iana","extensions":["mpc"]},"application/vnd.motorola.flexsuite":{"source":"iana"},"application/vnd.motorola.flexsuite.adsi":{"source":"iana"},"application/vnd.motorola.flexsuite.fis":{"source":"iana"},"application/vnd.motorola.flexsuite.gotap":{"source":"iana"},"application/vnd.motorola.flexsuite.kmr":{"source":"iana"},"application/vnd.motorola.flexsuite.ttc":{"source":"iana"},"application/vnd.motorola.flexsuite.wem":{"source":"iana"},"application/vnd.motorola.iprm":{"source":"iana"},"application/vnd.mozilla.xul+xml":{"source":"iana","compressible":true,"extensions":["xul"]},"application/vnd.ms-3mfdocument":{"source":"iana"},"application/vnd.ms-artgalry":{"source":"iana","extensions":["cil"]},"application/vnd.ms-asf":{"source":"iana"},"application/vnd.ms-cab-compressed":{"source":"iana","extensions":["cab"]},"application/vnd.ms-color.iccprofile":{"source":"apache"},"application/vnd.ms-excel":{"source":"iana","compressible":false,"extensions":["xls","xlm","xla","xlc","xlt","xlw"]},"application/vnd.ms-excel.addin.macroenabled.12":{"source":"iana","extensions":["xlam"]},"application/vnd.ms-excel.sheet.binary.macroenabled.12":{"source":"iana","extensions":["xlsb"]},"application/vnd.ms-excel.sheet.macroenabled.12":{"source":"iana","extensions":["xlsm"]},"application/vnd.ms-excel.template.macroenabled.12":{"source":"iana","extensions":["xltm"]},"application/vnd.ms-fontobject":{"source":"iana","compressible":true,"extensions":["eot"]},"application/vnd.ms-htmlhelp":{"source":"iana","extensions":["chm"]},"application/vnd.ms-ims":{"source":"iana","extensions":["ims"]},"application/vnd.ms-lrm":{"source":"iana","extensions":["lrm"]},"application/vnd.ms-office.activex+xml":{"source":"iana","compressible":true},"application/vnd.ms-officetheme":{"source":"iana","extensions":["thmx"]},"application/vnd.ms-opentype":{"source":"apache","compressible":true},"application/vnd.ms-outlook":{"compressible":false,"extensions":["msg"]},"application/vnd.ms-package.obfuscated-opentype":{"source":"apache"},"application/vnd.ms-pki.seccat":{"source":"apache","extensions":["cat"]},"application/vnd.ms-pki.stl":{"source":"apache","extensions":["stl"]},"application/vnd.ms-playready.initiator+xml":{"source":"iana","compressible":true},"application/vnd.ms-powerpoint":{"source":"iana","compressible":false,"extensions":["ppt","pps","pot"]},"application/vnd.ms-powerpoint.addin.macroenabled.12":{"source":"iana","extensions":["ppam"]},"application/vnd.ms-powerpoint.presentation.macroenabled.12":{"source":"iana","extensions":["pptm"]},"application/vnd.ms-powerpoint.slide.macroenabled.12":{"source":"iana","extensions":["sldm"]},"application/vnd.ms-powerpoint.slideshow.macroenabled.12":{"source":"iana","extensions":["ppsm"]},"application/vnd.ms-powerpoint.template.macroenabled.12":{"source":"iana","extensions":["potm"]},"application/vnd.ms-printdevicecapabilities+xml":{"source":"iana","compressible":true},"application/vnd.ms-printing.printticket+xml":{"source":"apache","compressible":true},"application/vnd.ms-printschematicket+xml":{"source":"iana","compressible":true},"application/vnd.ms-project":{"source":"iana","extensions":["mpp","mpt"]},"application/vnd.ms-tnef":{"source":"iana"},"application/vnd.ms-windows.devicepairing":{"source":"iana"},"application/vnd.ms-windows.nwprinting.oob":{"source":"iana"},"application/vnd.ms-windows.printerpairing":{"source":"iana"},"application/vnd.ms-windows.wsd.oob":{"source":"iana"},"application/vnd.ms-wmdrm.lic-chlg-req":{"source":"iana"},"application/vnd.ms-wmdrm.lic-resp":{"source":"iana"},"application/vnd.ms-wmdrm.meter-chlg-req":{"source":"iana"},"application/vnd.ms-wmdrm.meter-resp":{"source":"iana"},"application/vnd.ms-word.document.macroenabled.12":{"source":"iana","extensions":["docm"]},"application/vnd.ms-word.template.macroenabled.12":{"source":"iana","extensions":["dotm"]},"application/vnd.ms-works":{"source":"iana","extensions":["wps","wks","wcm","wdb"]},"application/vnd.ms-wpl":{"source":"iana","extensions":["wpl"]},"application/vnd.ms-xpsdocument":{"source":"iana","compressible":false,"extensions":["xps"]},"application/vnd.msa-disk-image":{"source":"iana"},"application/vnd.mseq":{"source":"iana","extensions":["mseq"]},"application/vnd.msign":{"source":"iana"},"application/vnd.multiad.creator":{"source":"iana"},"application/vnd.multiad.creator.cif":{"source":"iana"},"application/vnd.music-niff":{"source":"iana"},"application/vnd.musician":{"source":"iana","extensions":["mus"]},"application/vnd.muvee.style":{"source":"iana","extensions":["msty"]},"application/vnd.mynfc":{"source":"iana","extensions":["taglet"]},"application/vnd.ncd.control":{"source":"iana"},"application/vnd.ncd.reference":{"source":"iana"},"application/vnd.nearst.inv+json":{"source":"iana","compressible":true},"application/vnd.nervana":{"source":"iana"},"application/vnd.netfpx":{"source":"iana"},"application/vnd.neurolanguage.nlu":{"source":"iana","extensions":["nlu"]},"application/vnd.nimn":{"source":"iana"},"application/vnd.nintendo.nitro.rom":{"source":"iana"},"application/vnd.nintendo.snes.rom":{"source":"iana"},"application/vnd.nitf":{"source":"iana","extensions":["ntf","nitf"]},"application/vnd.noblenet-directory":{"source":"iana","extensions":["nnd"]},"application/vnd.noblenet-sealer":{"source":"iana","extensions":["nns"]},"application/vnd.noblenet-web":{"source":"iana","extensions":["nnw"]},"application/vnd.nokia.catalogs":{"source":"iana"},"application/vnd.nokia.conml+wbxml":{"source":"iana"},"application/vnd.nokia.conml+xml":{"source":"iana","compressible":true},"application/vnd.nokia.iptv.config+xml":{"source":"iana","compressible":true},"application/vnd.nokia.isds-radio-presets":{"source":"iana"},"application/vnd.nokia.landmark+wbxml":{"source":"iana"},"application/vnd.nokia.landmark+xml":{"source":"iana","compressible":true},"application/vnd.nokia.landmarkcollection+xml":{"source":"iana","compressible":true},"application/vnd.nokia.n-gage.ac+xml":{"source":"iana","compressible":true},"application/vnd.nokia.n-gage.data":{"source":"iana","extensions":["ngdat"]},"application/vnd.nokia.n-gage.symbian.install":{"source":"iana","extensions":["n-gage"]},"application/vnd.nokia.ncd":{"source":"iana"},"application/vnd.nokia.pcd+wbxml":{"source":"iana"},"application/vnd.nokia.pcd+xml":{"source":"iana","compressible":true},"application/vnd.nokia.radio-preset":{"source":"iana","extensions":["rpst"]},"application/vnd.nokia.radio-presets":{"source":"iana","extensions":["rpss"]},"application/vnd.novadigm.edm":{"source":"iana","extensions":["edm"]},"application/vnd.novadigm.edx":{"source":"iana","extensions":["edx"]},"application/vnd.novadigm.ext":{"source":"iana","extensions":["ext"]},"application/vnd.ntt-local.content-share":{"source":"iana"},"application/vnd.ntt-local.file-transfer":{"source":"iana"},"application/vnd.ntt-local.ogw_remote-access":{"source":"iana"},"application/vnd.ntt-local.sip-ta_remote":{"source":"iana"},"application/vnd.ntt-local.sip-ta_tcp_stream":{"source":"iana"},"application/vnd.oasis.opendocument.chart":{"source":"iana","extensions":["odc"]},"application/vnd.oasis.opendocument.chart-template":{"source":"iana","extensions":["otc"]},"application/vnd.oasis.opendocument.database":{"source":"iana","extensions":["odb"]},"application/vnd.oasis.opendocument.formula":{"source":"iana","extensions":["odf"]},"application/vnd.oasis.opendocument.formula-template":{"source":"iana","extensions":["odft"]},"application/vnd.oasis.opendocument.graphics":{"source":"iana","compressible":false,"extensions":["odg"]},"application/vnd.oasis.opendocument.graphics-template":{"source":"iana","extensions":["otg"]},"application/vnd.oasis.opendocument.image":{"source":"iana","extensions":["odi"]},"application/vnd.oasis.opendocument.image-template":{"source":"iana","extensions":["oti"]},"application/vnd.oasis.opendocument.presentation":{"source":"iana","compressible":false,"extensions":["odp"]},"application/vnd.oasis.opendocument.presentation-template":{"source":"iana","extensions":["otp"]},"application/vnd.oasis.opendocument.spreadsheet":{"source":"iana","compressible":false,"extensions":["ods"]},"application/vnd.oasis.opendocument.spreadsheet-template":{"source":"iana","extensions":["ots"]},"application/vnd.oasis.opendocument.text":{"source":"iana","compressible":false,"extensions":["odt"]},"application/vnd.oasis.opendocument.text-master":{"source":"iana","extensions":["odm"]},"application/vnd.oasis.opendocument.text-template":{"source":"iana","extensions":["ott"]},"application/vnd.oasis.opendocument.text-web":{"source":"iana","extensions":["oth"]},"application/vnd.obn":{"source":"iana"},"application/vnd.ocf+cbor":{"source":"iana"},"application/vnd.oftn.l10n+json":{"source":"iana","compressible":true},"application/vnd.oipf.contentaccessdownload+xml":{"source":"iana","compressible":true},"application/vnd.oipf.contentaccessstreaming+xml":{"source":"iana","compressible":true},"application/vnd.oipf.cspg-hexbinary":{"source":"iana"},"application/vnd.oipf.dae.svg+xml":{"source":"iana","compressible":true},"application/vnd.oipf.dae.xhtml+xml":{"source":"iana","compressible":true},"application/vnd.oipf.mippvcontrolmessage+xml":{"source":"iana","compressible":true},"application/vnd.oipf.pae.gem":{"source":"iana"},"application/vnd.oipf.spdiscovery+xml":{"source":"iana","compressible":true},"application/vnd.oipf.spdlist+xml":{"source":"iana","compressible":true},"application/vnd.oipf.ueprofile+xml":{"source":"iana","compressible":true},"application/vnd.oipf.userprofile+xml":{"source":"iana","compressible":true},"application/vnd.olpc-sugar":{"source":"iana","extensions":["xo"]},"application/vnd.oma-scws-config":{"source":"iana"},"application/vnd.oma-scws-http-request":{"source":"iana"},"application/vnd.oma-scws-http-response":{"source":"iana"},"application/vnd.oma.bcast.associated-procedure-parameter+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.drm-trigger+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.imd+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.ltkm":{"source":"iana"},"application/vnd.oma.bcast.notification+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.provisioningtrigger":{"source":"iana"},"application/vnd.oma.bcast.sgboot":{"source":"iana"},"application/vnd.oma.bcast.sgdd+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.sgdu":{"source":"iana"},"application/vnd.oma.bcast.simple-symbol-container":{"source":"iana"},"application/vnd.oma.bcast.smartcard-trigger+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.sprov+xml":{"source":"iana","compressible":true},"application/vnd.oma.bcast.stkm":{"source":"iana"},"application/vnd.oma.cab-address-book+xml":{"source":"iana","compressible":true},"application/vnd.oma.cab-feature-handler+xml":{"source":"iana","compressible":true},"application/vnd.oma.cab-pcc+xml":{"source":"iana","compressible":true},"application/vnd.oma.cab-subs-invite+xml":{"source":"iana","compressible":true},"application/vnd.oma.cab-user-prefs+xml":{"source":"iana","compressible":true},"application/vnd.oma.dcd":{"source":"iana"},"application/vnd.oma.dcdc":{"source":"iana"},"application/vnd.oma.dd2+xml":{"source":"iana","compressible":true,"extensions":["dd2"]},"application/vnd.oma.drm.risd+xml":{"source":"iana","compressible":true},"application/vnd.oma.group-usage-list+xml":{"source":"iana","compressible":true},"application/vnd.oma.lwm2m+json":{"source":"iana","compressible":true},"application/vnd.oma.lwm2m+tlv":{"source":"iana"},"application/vnd.oma.pal+xml":{"source":"iana","compressible":true},"application/vnd.oma.poc.detailed-progress-report+xml":{"source":"iana","compressible":true},"application/vnd.oma.poc.final-report+xml":{"source":"iana","compressible":true},"application/vnd.oma.poc.groups+xml":{"source":"iana","compressible":true},"application/vnd.oma.poc.invocation-descriptor+xml":{"source":"iana","compressible":true},"application/vnd.oma.poc.optimized-progress-report+xml":{"source":"iana","compressible":true},"application/vnd.oma.push":{"source":"iana"},"application/vnd.oma.scidm.messages+xml":{"source":"iana","compressible":true},"application/vnd.oma.xcap-directory+xml":{"source":"iana","compressible":true},"application/vnd.omads-email+xml":{"source":"iana","compressible":true},"application/vnd.omads-file+xml":{"source":"iana","compressible":true},"application/vnd.omads-folder+xml":{"source":"iana","compressible":true},"application/vnd.omaloc-supl-init":{"source":"iana"},"application/vnd.onepager":{"source":"iana"},"application/vnd.onepagertamp":{"source":"iana"},"application/vnd.onepagertamx":{"source":"iana"},"application/vnd.onepagertat":{"source":"iana"},"application/vnd.onepagertatp":{"source":"iana"},"application/vnd.onepagertatx":{"source":"iana"},"application/vnd.openblox.game+xml":{"source":"iana","compressible":true},"application/vnd.openblox.game-binary":{"source":"iana"},"application/vnd.openeye.oeb":{"source":"iana"},"application/vnd.openofficeorg.extension":{"source":"apache","extensions":["oxt"]},"application/vnd.openstreetmap.data+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.custom-properties+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.customxmlproperties+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawing+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawingml.chart+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.extended-properties+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.comments+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.presentation":{"source":"iana","compressible":false,"extensions":["pptx"]},"application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.presprops+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.slide":{"source":"iana","extensions":["sldx"]},"application/vnd.openxmlformats-officedocument.presentationml.slide+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.slideshow":{"source":"iana","extensions":["ppsx"]},"application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.tags+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.template":{"source":"iana","extensions":["potx"]},"application/vnd.openxmlformats-officedocument.presentationml.template.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"source":"iana","compressible":false,"extensions":["xlsx"]},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.template":{"source":"iana","extensions":["xltx"]},"application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.theme+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.themeoverride+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.vmldrawing":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{"source":"iana","compressible":false,"extensions":["docx"]},"application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.template":{"source":"iana","extensions":["dotx"]},"application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-package.core-properties+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml":{"source":"iana","compressible":true},"application/vnd.openxmlformats-package.relationships+xml":{"source":"iana","compressible":true},"application/vnd.oracle.resource+json":{"source":"iana","compressible":true},"application/vnd.orange.indata":{"source":"iana"},"application/vnd.osa.netdeploy":{"source":"iana"},"application/vnd.osgeo.mapguide.package":{"source":"iana","extensions":["mgp"]},"application/vnd.osgi.bundle":{"source":"iana"},"application/vnd.osgi.dp":{"source":"iana","extensions":["dp"]},"application/vnd.osgi.subsystem":{"source":"iana","extensions":["esa"]},"application/vnd.otps.ct-kip+xml":{"source":"iana","compressible":true},"application/vnd.oxli.countgraph":{"source":"iana"},"application/vnd.pagerduty+json":{"source":"iana","compressible":true},"application/vnd.palm":{"source":"iana","extensions":["pdb","pqa","oprc"]},"application/vnd.panoply":{"source":"iana"},"application/vnd.paos.xml":{"source":"iana"},"application/vnd.patentdive":{"source":"iana"},"application/vnd.pawaafile":{"source":"iana","extensions":["paw"]},"application/vnd.pcos":{"source":"iana"},"application/vnd.pg.format":{"source":"iana","extensions":["str"]},"application/vnd.pg.osasli":{"source":"iana","extensions":["ei6"]},"application/vnd.piaccess.application-licence":{"source":"iana"},"application/vnd.picsel":{"source":"iana","extensions":["efif"]},"application/vnd.pmi.widget":{"source":"iana","extensions":["wg"]},"application/vnd.poc.group-advertisement+xml":{"source":"iana","compressible":true},"application/vnd.pocketlearn":{"source":"iana","extensions":["plf"]},"application/vnd.powerbuilder6":{"source":"iana","extensions":["pbd"]},"application/vnd.powerbuilder6-s":{"source":"iana"},"application/vnd.powerbuilder7":{"source":"iana"},"application/vnd.powerbuilder7-s":{"source":"iana"},"application/vnd.powerbuilder75":{"source":"iana"},"application/vnd.powerbuilder75-s":{"source":"iana"},"application/vnd.preminet":{"source":"iana"},"application/vnd.previewsystems.box":{"source":"iana","extensions":["box"]},"application/vnd.proteus.magazine":{"source":"iana","extensions":["mgz"]},"application/vnd.psfs":{"source":"iana"},"application/vnd.publishare-delta-tree":{"source":"iana","extensions":["qps"]},"application/vnd.pvi.ptid1":{"source":"iana","extensions":["ptid"]},"application/vnd.pwg-multiplexed":{"source":"iana"},"application/vnd.pwg-xhtml-print+xml":{"source":"iana","compressible":true},"application/vnd.qualcomm.brew-app-res":{"source":"iana"},"application/vnd.quarantainenet":{"source":"iana"},"application/vnd.quark.quarkxpress":{"source":"iana","extensions":["qxd","qxt","qwd","qwt","qxl","qxb"]},"application/vnd.quobject-quoxdocument":{"source":"iana"},"application/vnd.radisys.moml+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-audit+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-audit-conf+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-audit-conn+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-audit-dialog+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-audit-stream+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-conf+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog-base+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog-fax-detect+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog-fax-sendrecv+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog-group+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog-speech+xml":{"source":"iana","compressible":true},"application/vnd.radisys.msml-dialog-transform+xml":{"source":"iana","compressible":true},"application/vnd.rainstor.data":{"source":"iana"},"application/vnd.rapid":{"source":"iana"},"application/vnd.rar":{"source":"iana"},"application/vnd.realvnc.bed":{"source":"iana","extensions":["bed"]},"application/vnd.recordare.musicxml":{"source":"iana","extensions":["mxl"]},"application/vnd.recordare.musicxml+xml":{"source":"iana","compressible":true,"extensions":["musicxml"]},"application/vnd.renlearn.rlprint":{"source":"iana"},"application/vnd.restful+json":{"source":"iana","compressible":true},"application/vnd.rig.cryptonote":{"source":"iana","extensions":["cryptonote"]},"application/vnd.rim.cod":{"source":"apache","extensions":["cod"]},"application/vnd.rn-realmedia":{"source":"apache","extensions":["rm"]},"application/vnd.rn-realmedia-vbr":{"source":"apache","extensions":["rmvb"]},"application/vnd.route66.link66+xml":{"source":"iana","compressible":true,"extensions":["link66"]},"application/vnd.rs-274x":{"source":"iana"},"application/vnd.ruckus.download":{"source":"iana"},"application/vnd.s3sms":{"source":"iana"},"application/vnd.sailingtracker.track":{"source":"iana","extensions":["st"]},"application/vnd.sbm.cid":{"source":"iana"},"application/vnd.sbm.mid2":{"source":"iana"},"application/vnd.scribus":{"source":"iana"},"application/vnd.sealed.3df":{"source":"iana"},"application/vnd.sealed.csf":{"source":"iana"},"application/vnd.sealed.doc":{"source":"iana"},"application/vnd.sealed.eml":{"source":"iana"},"application/vnd.sealed.mht":{"source":"iana"},"application/vnd.sealed.net":{"source":"iana"},"application/vnd.sealed.ppt":{"source":"iana"},"application/vnd.sealed.tiff":{"source":"iana"},"application/vnd.sealed.xls":{"source":"iana"},"application/vnd.sealedmedia.softseal.html":{"source":"iana"},"application/vnd.sealedmedia.softseal.pdf":{"source":"iana"},"application/vnd.seemail":{"source":"iana","extensions":["see"]},"application/vnd.sema":{"source":"iana","extensions":["sema"]},"application/vnd.semd":{"source":"iana","extensions":["semd"]},"application/vnd.semf":{"source":"iana","extensions":["semf"]},"application/vnd.shana.informed.formdata":{"source":"iana","extensions":["ifm"]},"application/vnd.shana.informed.formtemplate":{"source":"iana","extensions":["itp"]},"application/vnd.shana.informed.interchange":{"source":"iana","extensions":["iif"]},"application/vnd.shana.informed.package":{"source":"iana","extensions":["ipk"]},"application/vnd.shootproof+json":{"source":"iana","compressible":true},"application/vnd.sigrok.session":{"source":"iana"},"application/vnd.simtech-mindmapper":{"source":"iana","extensions":["twd","twds"]},"application/vnd.siren+json":{"source":"iana","compressible":true},"application/vnd.smaf":{"source":"iana","extensions":["mmf"]},"application/vnd.smart.notebook":{"source":"iana"},"application/vnd.smart.teacher":{"source":"iana","extensions":["teacher"]},"application/vnd.software602.filler.form+xml":{"source":"iana","compressible":true},"application/vnd.software602.filler.form-xml-zip":{"source":"iana"},"application/vnd.solent.sdkm+xml":{"source":"iana","compressible":true,"extensions":["sdkm","sdkd"]},"application/vnd.spotfire.dxp":{"source":"iana","extensions":["dxp"]},"application/vnd.spotfire.sfs":{"source":"iana","extensions":["sfs"]},"application/vnd.sqlite3":{"source":"iana"},"application/vnd.sss-cod":{"source":"iana"},"application/vnd.sss-dtf":{"source":"iana"},"application/vnd.sss-ntf":{"source":"iana"},"application/vnd.stardivision.calc":{"source":"apache","extensions":["sdc"]},"application/vnd.stardivision.draw":{"source":"apache","extensions":["sda"]},"application/vnd.stardivision.impress":{"source":"apache","extensions":["sdd"]},"application/vnd.stardivision.math":{"source":"apache","extensions":["smf"]},"application/vnd.stardivision.writer":{"source":"apache","extensions":["sdw","vor"]},"application/vnd.stardivision.writer-global":{"source":"apache","extensions":["sgl"]},"application/vnd.stepmania.package":{"source":"iana","extensions":["smzip"]},"application/vnd.stepmania.stepchart":{"source":"iana","extensions":["sm"]},"application/vnd.street-stream":{"source":"iana"},"application/vnd.sun.wadl+xml":{"source":"iana","compressible":true,"extensions":["wadl"]},"application/vnd.sun.xml.calc":{"source":"apache","extensions":["sxc"]},"application/vnd.sun.xml.calc.template":{"source":"apache","extensions":["stc"]},"application/vnd.sun.xml.draw":{"source":"apache","extensions":["sxd"]},"application/vnd.sun.xml.draw.template":{"source":"apache","extensions":["std"]},"application/vnd.sun.xml.impress":{"source":"apache","extensions":["sxi"]},"application/vnd.sun.xml.impress.template":{"source":"apache","extensions":["sti"]},"application/vnd.sun.xml.math":{"source":"apache","extensions":["sxm"]},"application/vnd.sun.xml.writer":{"source":"apache","extensions":["sxw"]},"application/vnd.sun.xml.writer.global":{"source":"apache","extensions":["sxg"]},"application/vnd.sun.xml.writer.template":{"source":"apache","extensions":["stw"]},"application/vnd.sus-calendar":{"source":"iana","extensions":["sus","susp"]},"application/vnd.svd":{"source":"iana","extensions":["svd"]},"application/vnd.swiftview-ics":{"source":"iana"},"application/vnd.symbian.install":{"source":"apache","extensions":["sis","sisx"]},"application/vnd.syncml+xml":{"source":"iana","compressible":true,"extensions":["xsm"]},"application/vnd.syncml.dm+wbxml":{"source":"iana","extensions":["bdm"]},"application/vnd.syncml.dm+xml":{"source":"iana","compressible":true,"extensions":["xdm"]},"application/vnd.syncml.dm.notification":{"source":"iana"},"application/vnd.syncml.dmddf+wbxml":{"source":"iana"},"application/vnd.syncml.dmddf+xml":{"source":"iana","compressible":true},"application/vnd.syncml.dmtnds+wbxml":{"source":"iana"},"application/vnd.syncml.dmtnds+xml":{"source":"iana","compressible":true},"application/vnd.syncml.ds.notification":{"source":"iana"},"application/vnd.tableschema+json":{"source":"iana","compressible":true},"application/vnd.tao.intent-module-archive":{"source":"iana","extensions":["tao"]},"application/vnd.tcpdump.pcap":{"source":"iana","extensions":["pcap","cap","dmp"]},"application/vnd.think-cell.ppttc+json":{"source":"iana","compressible":true},"application/vnd.tmd.mediaflex.api+xml":{"source":"iana","compressible":true},"application/vnd.tml":{"source":"iana"},"application/vnd.tmobile-livetv":{"source":"iana","extensions":["tmo"]},"application/vnd.tri.onesource":{"source":"iana"},"application/vnd.trid.tpt":{"source":"iana","extensions":["tpt"]},"application/vnd.triscape.mxs":{"source":"iana","extensions":["mxs"]},"application/vnd.trueapp":{"source":"iana","extensions":["tra"]},"application/vnd.truedoc":{"source":"iana"},"application/vnd.ubisoft.webplayer":{"source":"iana"},"application/vnd.ufdl":{"source":"iana","extensions":["ufd","ufdl"]},"application/vnd.uiq.theme":{"source":"iana","extensions":["utz"]},"application/vnd.umajin":{"source":"iana","extensions":["umj"]},"application/vnd.unity":{"source":"iana","extensions":["unityweb"]},"application/vnd.uoml+xml":{"source":"iana","compressible":true,"extensions":["uoml"]},"application/vnd.uplanet.alert":{"source":"iana"},"application/vnd.uplanet.alert-wbxml":{"source":"iana"},"application/vnd.uplanet.bearer-choice":{"source":"iana"},"application/vnd.uplanet.bearer-choice-wbxml":{"source":"iana"},"application/vnd.uplanet.cacheop":{"source":"iana"},"application/vnd.uplanet.cacheop-wbxml":{"source":"iana"},"application/vnd.uplanet.channel":{"source":"iana"},"application/vnd.uplanet.channel-wbxml":{"source":"iana"},"application/vnd.uplanet.list":{"source":"iana"},"application/vnd.uplanet.list-wbxml":{"source":"iana"},"application/vnd.uplanet.listcmd":{"source":"iana"},"application/vnd.uplanet.listcmd-wbxml":{"source":"iana"},"application/vnd.uplanet.signal":{"source":"iana"},"application/vnd.uri-map":{"source":"iana"},"application/vnd.valve.source.material":{"source":"iana"},"application/vnd.vcx":{"source":"iana","extensions":["vcx"]},"application/vnd.vd-study":{"source":"iana"},"application/vnd.vectorworks":{"source":"iana"},"application/vnd.vel+json":{"source":"iana","compressible":true},"application/vnd.verimatrix.vcas":{"source":"iana"},"application/vnd.vidsoft.vidconference":{"source":"iana"},"application/vnd.visio":{"source":"iana","extensions":["vsd","vst","vss","vsw"]},"application/vnd.visionary":{"source":"iana","extensions":["vis"]},"application/vnd.vividence.scriptfile":{"source":"iana"},"application/vnd.vsf":{"source":"iana","extensions":["vsf"]},"application/vnd.wap.sic":{"source":"iana"},"application/vnd.wap.slc":{"source":"iana"},"application/vnd.wap.wbxml":{"source":"iana","extensions":["wbxml"]},"application/vnd.wap.wmlc":{"source":"iana","extensions":["wmlc"]},"application/vnd.wap.wmlscriptc":{"source":"iana","extensions":["wmlsc"]},"application/vnd.webturbo":{"source":"iana","extensions":["wtb"]},"application/vnd.wfa.p2p":{"source":"iana"},"application/vnd.wfa.wsc":{"source":"iana"},"application/vnd.windows.devicepairing":{"source":"iana"},"application/vnd.wmc":{"source":"iana"},"application/vnd.wmf.bootstrap":{"source":"iana"},"application/vnd.wolfram.mathematica":{"source":"iana"},"application/vnd.wolfram.mathematica.package":{"source":"iana"},"application/vnd.wolfram.player":{"source":"iana","extensions":["nbp"]},"application/vnd.wordperfect":{"source":"iana","extensions":["wpd"]},"application/vnd.wqd":{"source":"iana","extensions":["wqd"]},"application/vnd.wrq-hp3000-labelled":{"source":"iana"},"application/vnd.wt.stf":{"source":"iana","extensions":["stf"]},"application/vnd.wv.csp+wbxml":{"source":"iana"},"application/vnd.wv.csp+xml":{"source":"iana","compressible":true},"application/vnd.wv.ssp+xml":{"source":"iana","compressible":true},"application/vnd.xacml+json":{"source":"iana","compressible":true},"application/vnd.xara":{"source":"iana","extensions":["xar"]},"application/vnd.xfdl":{"source":"iana","extensions":["xfdl"]},"application/vnd.xfdl.webform":{"source":"iana"},"application/vnd.xmi+xml":{"source":"iana","compressible":true},"application/vnd.xmpie.cpkg":{"source":"iana"},"application/vnd.xmpie.dpkg":{"source":"iana"},"application/vnd.xmpie.plan":{"source":"iana"},"application/vnd.xmpie.ppkg":{"source":"iana"},"application/vnd.xmpie.xlim":{"source":"iana"},"application/vnd.yamaha.hv-dic":{"source":"iana","extensions":["hvd"]},"application/vnd.yamaha.hv-script":{"source":"iana","extensions":["hvs"]},"application/vnd.yamaha.hv-voice":{"source":"iana","extensions":["hvp"]},"application/vnd.yamaha.openscoreformat":{"source":"iana","extensions":["osf"]},"application/vnd.yamaha.openscoreformat.osfpvg+xml":{"source":"iana","compressible":true,"extensions":["osfpvg"]},"application/vnd.yamaha.remote-setup":{"source":"iana"},"application/vnd.yamaha.smaf-audio":{"source":"iana","extensions":["saf"]},"application/vnd.yamaha.smaf-phrase":{"source":"iana","extensions":["spf"]},"application/vnd.yamaha.through-ngn":{"source":"iana"},"application/vnd.yamaha.tunnel-udpencap":{"source":"iana"},"application/vnd.yaoweme":{"source":"iana"},"application/vnd.yellowriver-custom-menu":{"source":"iana","extensions":["cmp"]},"application/vnd.youtube.yt":{"source":"iana"},"application/vnd.zul":{"source":"iana","extensions":["zir","zirz"]},"application/vnd.zzazz.deck+xml":{"source":"iana","compressible":true,"extensions":["zaz"]},"application/voicexml+xml":{"source":"iana","compressible":true,"extensions":["vxml"]},"application/voucher-cms+json":{"source":"iana","compressible":true},"application/vq-rtcpxr":{"source":"iana"},"application/wasm":{"compressible":true,"extensions":["wasm"]},"application/watcherinfo+xml":{"source":"iana","compressible":true},"application/webpush-options+json":{"source":"iana","compressible":true},"application/whoispp-query":{"source":"iana"},"application/whoispp-response":{"source":"iana"},"application/widget":{"source":"iana","extensions":["wgt"]},"application/winhlp":{"source":"apache","extensions":["hlp"]},"application/wita":{"source":"iana"},"application/wordperfect5.1":{"source":"iana"},"application/wsdl+xml":{"source":"iana","compressible":true,"extensions":["wsdl"]},"application/wspolicy+xml":{"source":"iana","compressible":true,"extensions":["wspolicy"]},"application/x-7z-compressed":{"source":"apache","compressible":false,"extensions":["7z"]},"application/x-abiword":{"source":"apache","extensions":["abw"]},"application/x-ace-compressed":{"source":"apache","extensions":["ace"]},"application/x-amf":{"source":"apache"},"application/x-apple-diskimage":{"source":"apache","extensions":["dmg"]},"application/x-arj":{"compressible":false,"extensions":["arj"]},"application/x-authorware-bin":{"source":"apache","extensions":["aab","x32","u32","vox"]},"application/x-authorware-map":{"source":"apache","extensions":["aam"]},"application/x-authorware-seg":{"source":"apache","extensions":["aas"]},"application/x-bcpio":{"source":"apache","extensions":["bcpio"]},"application/x-bdoc":{"compressible":false,"extensions":["bdoc"]},"application/x-bittorrent":{"source":"apache","extensions":["torrent"]},"application/x-blorb":{"source":"apache","extensions":["blb","blorb"]},"application/x-bzip":{"source":"apache","compressible":false,"extensions":["bz"]},"application/x-bzip2":{"source":"apache","compressible":false,"extensions":["bz2","boz"]},"application/x-cbr":{"source":"apache","extensions":["cbr","cba","cbt","cbz","cb7"]},"application/x-cdlink":{"source":"apache","extensions":["vcd"]},"application/x-cfs-compressed":{"source":"apache","extensions":["cfs"]},"application/x-chat":{"source":"apache","extensions":["chat"]},"application/x-chess-pgn":{"source":"apache","extensions":["pgn"]},"application/x-chrome-extension":{"extensions":["crx"]},"application/x-cocoa":{"source":"nginx","extensions":["cco"]},"application/x-compress":{"source":"apache"},"application/x-conference":{"source":"apache","extensions":["nsc"]},"application/x-cpio":{"source":"apache","extensions":["cpio"]},"application/x-csh":{"source":"apache","extensions":["csh"]},"application/x-deb":{"compressible":false},"application/x-debian-package":{"source":"apache","extensions":["deb","udeb"]},"application/x-dgc-compressed":{"source":"apache","extensions":["dgc"]},"application/x-director":{"source":"apache","extensions":["dir","dcr","dxr","cst","cct","cxt","w3d","fgd","swa"]},"application/x-doom":{"source":"apache","extensions":["wad"]},"application/x-dtbncx+xml":{"source":"apache","compressible":true,"extensions":["ncx"]},"application/x-dtbook+xml":{"source":"apache","compressible":true,"extensions":["dtb"]},"application/x-dtbresource+xml":{"source":"apache","compressible":true,"extensions":["res"]},"application/x-dvi":{"source":"apache","compressible":false,"extensions":["dvi"]},"application/x-envoy":{"source":"apache","extensions":["evy"]},"application/x-eva":{"source":"apache","extensions":["eva"]},"application/x-font-bdf":{"source":"apache","extensions":["bdf"]},"application/x-font-dos":{"source":"apache"},"application/x-font-framemaker":{"source":"apache"},"application/x-font-ghostscript":{"source":"apache","extensions":["gsf"]},"application/x-font-libgrx":{"source":"apache"},"application/x-font-linux-psf":{"source":"apache","extensions":["psf"]},"application/x-font-pcf":{"source":"apache","extensions":["pcf"]},"application/x-font-snf":{"source":"apache","extensions":["snf"]},"application/x-font-speedo":{"source":"apache"},"application/x-font-sunos-news":{"source":"apache"},"application/x-font-type1":{"source":"apache","extensions":["pfa","pfb","pfm","afm"]},"application/x-font-vfont":{"source":"apache"},"application/x-freearc":{"source":"apache","extensions":["arc"]},"application/x-futuresplash":{"source":"apache","extensions":["spl"]},"application/x-gca-compressed":{"source":"apache","extensions":["gca"]},"application/x-glulx":{"source":"apache","extensions":["ulx"]},"application/x-gnumeric":{"source":"apache","extensions":["gnumeric"]},"application/x-gramps-xml":{"source":"apache","extensions":["gramps"]},"application/x-gtar":{"source":"apache","extensions":["gtar"]},"application/x-gzip":{"source":"apache"},"application/x-hdf":{"source":"apache","extensions":["hdf"]},"application/x-httpd-php":{"compressible":true,"extensions":["php"]},"application/x-install-instructions":{"source":"apache","extensions":["install"]},"application/x-iso9660-image":{"source":"apache","extensions":["iso"]},"application/x-java-archive-diff":{"source":"nginx","extensions":["jardiff"]},"application/x-java-jnlp-file":{"source":"apache","compressible":false,"extensions":["jnlp"]},"application/x-javascript":{"compressible":true},"application/x-latex":{"source":"apache","compressible":false,"extensions":["latex"]},"application/x-lua-bytecode":{"extensions":["luac"]},"application/x-lzh-compressed":{"source":"apache","extensions":["lzh","lha"]},"application/x-makeself":{"source":"nginx","extensions":["run"]},"application/x-mie":{"source":"apache","extensions":["mie"]},"application/x-mobipocket-ebook":{"source":"apache","extensions":["prc","mobi"]},"application/x-mpegurl":{"compressible":false},"application/x-ms-application":{"source":"apache","extensions":["application"]},"application/x-ms-shortcut":{"source":"apache","extensions":["lnk"]},"application/x-ms-wmd":{"source":"apache","extensions":["wmd"]},"application/x-ms-wmz":{"source":"apache","extensions":["wmz"]},"application/x-ms-xbap":{"source":"apache","extensions":["xbap"]},"application/x-msaccess":{"source":"apache","extensions":["mdb"]},"application/x-msbinder":{"source":"apache","extensions":["obd"]},"application/x-mscardfile":{"source":"apache","extensions":["crd"]},"application/x-msclip":{"source":"apache","extensions":["clp"]},"application/x-msdos-program":{"extensions":["exe"]},"application/x-msdownload":{"source":"apache","extensions":["exe","dll","com","bat","msi"]},"application/x-msmediaview":{"source":"apache","extensions":["mvb","m13","m14"]},"application/x-msmetafile":{"source":"apache","extensions":["wmf","wmz","emf","emz"]},"application/x-msmoney":{"source":"apache","extensions":["mny"]},"application/x-mspublisher":{"source":"apache","extensions":["pub"]},"application/x-msschedule":{"source":"apache","extensions":["scd"]},"application/x-msterminal":{"source":"apache","extensions":["trm"]},"application/x-mswrite":{"source":"apache","extensions":["wri"]},"application/x-netcdf":{"source":"apache","extensions":["nc","cdf"]},"application/x-ns-proxy-autoconfig":{"compressible":true,"extensions":["pac"]},"application/x-nzb":{"source":"apache","extensions":["nzb"]},"application/x-perl":{"source":"nginx","extensions":["pl","pm"]},"application/x-pilot":{"source":"nginx","extensions":["prc","pdb"]},"application/x-pkcs12":{"source":"apache","compressible":false,"extensions":["p12","pfx"]},"application/x-pkcs7-certificates":{"source":"apache","extensions":["p7b","spc"]},"application/x-pkcs7-certreqresp":{"source":"apache","extensions":["p7r"]},"application/x-rar-compressed":{"source":"apache","compressible":false,"extensions":["rar"]},"application/x-redhat-package-manager":{"source":"nginx","extensions":["rpm"]},"application/x-research-info-systems":{"source":"apache","extensions":["ris"]},"application/x-sea":{"source":"nginx","extensions":["sea"]},"application/x-sh":{"source":"apache","compressible":true,"extensions":["sh"]},"application/x-shar":{"source":"apache","extensions":["shar"]},"application/x-shockwave-flash":{"source":"apache","compressible":false,"extensions":["swf"]},"application/x-silverlight-app":{"source":"apache","extensions":["xap"]},"application/x-sql":{"source":"apache","extensions":["sql"]},"application/x-stuffit":{"source":"apache","compressible":false,"extensions":["sit"]},"application/x-stuffitx":{"source":"apache","extensions":["sitx"]},"application/x-subrip":{"source":"apache","extensions":["srt"]},"application/x-sv4cpio":{"source":"apache","extensions":["sv4cpio"]},"application/x-sv4crc":{"source":"apache","extensions":["sv4crc"]},"application/x-t3vm-image":{"source":"apache","extensions":["t3"]},"application/x-tads":{"source":"apache","extensions":["gam"]},"application/x-tar":{"source":"apache","compressible":true,"extensions":["tar"]},"application/x-tcl":{"source":"apache","extensions":["tcl","tk"]},"application/x-tex":{"source":"apache","extensions":["tex"]},"application/x-tex-tfm":{"source":"apache","extensions":["tfm"]},"application/x-texinfo":{"source":"apache","extensions":["texinfo","texi"]},"application/x-tgif":{"source":"apache","extensions":["obj"]},"application/x-ustar":{"source":"apache","extensions":["ustar"]},"application/x-virtualbox-hdd":{"compressible":true,"extensions":["hdd"]},"application/x-virtualbox-ova":{"compressible":true,"extensions":["ova"]},"application/x-virtualbox-ovf":{"compressible":true,"extensions":["ovf"]},"application/x-virtualbox-vbox":{"compressible":true,"extensions":["vbox"]},"application/x-virtualbox-vbox-extpack":{"compressible":false,"extensions":["vbox-extpack"]},"application/x-virtualbox-vdi":{"compressible":true,"extensions":["vdi"]},"application/x-virtualbox-vhd":{"compressible":true,"extensions":["vhd"]},"application/x-virtualbox-vmdk":{"compressible":true,"extensions":["vmdk"]},"application/x-wais-source":{"source":"apache","extensions":["src"]},"application/x-web-app-manifest+json":{"compressible":true,"extensions":["webapp"]},"application/x-www-form-urlencoded":{"source":"iana","compressible":true},"application/x-x509-ca-cert":{"source":"apache","extensions":["der","crt","pem"]},"application/x-xfig":{"source":"apache","extensions":["fig"]},"application/x-xliff+xml":{"source":"apache","compressible":true,"extensions":["xlf"]},"application/x-xpinstall":{"source":"apache","compressible":false,"extensions":["xpi"]},"application/x-xz":{"source":"apache","extensions":["xz"]},"application/x-zmachine":{"source":"apache","extensions":["z1","z2","z3","z4","z5","z6","z7","z8"]},"application/x400-bp":{"source":"iana"},"application/xacml+xml":{"source":"iana","compressible":true},"application/xaml+xml":{"source":"apache","compressible":true,"extensions":["xaml"]},"application/xcap-att+xml":{"source":"iana","compressible":true},"application/xcap-caps+xml":{"source":"iana","compressible":true},"application/xcap-diff+xml":{"source":"iana","compressible":true,"extensions":["xdf"]},"application/xcap-el+xml":{"source":"iana","compressible":true},"application/xcap-error+xml":{"source":"iana","compressible":true},"application/xcap-ns+xml":{"source":"iana","compressible":true},"application/xcon-conference-info+xml":{"source":"iana","compressible":true},"application/xcon-conference-info-diff+xml":{"source":"iana","compressible":true},"application/xenc+xml":{"source":"iana","compressible":true,"extensions":["xenc"]},"application/xhtml+xml":{"source":"iana","compressible":true,"extensions":["xhtml","xht"]},"application/xhtml-voice+xml":{"source":"apache","compressible":true},"application/xliff+xml":{"source":"iana","compressible":true},"application/xml":{"source":"iana","compressible":true,"extensions":["xml","xsl","xsd","rng"]},"application/xml-dtd":{"source":"iana","compressible":true,"extensions":["dtd"]},"application/xml-external-parsed-entity":{"source":"iana"},"application/xml-patch+xml":{"source":"iana","compressible":true},"application/xmpp+xml":{"source":"iana","compressible":true},"application/xop+xml":{"source":"iana","compressible":true,"extensions":["xop"]},"application/xproc+xml":{"source":"apache","compressible":true,"extensions":["xpl"]},"application/xslt+xml":{"source":"iana","compressible":true,"extensions":["xslt"]},"application/xspf+xml":{"source":"apache","compressible":true,"extensions":["xspf"]},"application/xv+xml":{"source":"iana","compressible":true,"extensions":["mxml","xhvml","xvml","xvm"]},"application/yang":{"source":"iana","extensions":["yang"]},"application/yang-data+json":{"source":"iana","compressible":true},"application/yang-data+xml":{"source":"iana","compressible":true},"application/yang-patch+json":{"source":"iana","compressible":true},"application/yang-patch+xml":{"source":"iana","compressible":true},"application/yin+xml":{"source":"iana","compressible":true,"extensions":["yin"]},"application/zip":{"source":"iana","compressible":false,"extensions":["zip"]},"application/zlib":{"source":"iana"},"application/zstd":{"source":"iana"},"audio/1d-interleaved-parityfec":{"source":"iana"},"audio/32kadpcm":{"source":"iana"},"audio/3gpp":{"source":"iana","compressible":false,"extensions":["3gpp"]},"audio/3gpp2":{"source":"iana"},"audio/aac":{"source":"iana"},"audio/ac3":{"source":"iana"},"audio/adpcm":{"source":"apache","extensions":["adp"]},"audio/amr":{"source":"iana"},"audio/amr-wb":{"source":"iana"},"audio/amr-wb+":{"source":"iana"},"audio/aptx":{"source":"iana"},"audio/asc":{"source":"iana"},"audio/atrac-advanced-lossless":{"source":"iana"},"audio/atrac-x":{"source":"iana"},"audio/atrac3":{"source":"iana"},"audio/basic":{"source":"iana","compressible":false,"extensions":["au","snd"]},"audio/bv16":{"source":"iana"},"audio/bv32":{"source":"iana"},"audio/clearmode":{"source":"iana"},"audio/cn":{"source":"iana"},"audio/dat12":{"source":"iana"},"audio/dls":{"source":"iana"},"audio/dsr-es201108":{"source":"iana"},"audio/dsr-es202050":{"source":"iana"},"audio/dsr-es202211":{"source":"iana"},"audio/dsr-es202212":{"source":"iana"},"audio/dv":{"source":"iana"},"audio/dvi4":{"source":"iana"},"audio/eac3":{"source":"iana"},"audio/encaprtp":{"source":"iana"},"audio/evrc":{"source":"iana"},"audio/evrc-qcp":{"source":"iana"},"audio/evrc0":{"source":"iana"},"audio/evrc1":{"source":"iana"},"audio/evrcb":{"source":"iana"},"audio/evrcb0":{"source":"iana"},"audio/evrcb1":{"source":"iana"},"audio/evrcnw":{"source":"iana"},"audio/evrcnw0":{"source":"iana"},"audio/evrcnw1":{"source":"iana"},"audio/evrcwb":{"source":"iana"},"audio/evrcwb0":{"source":"iana"},"audio/evrcwb1":{"source":"iana"},"audio/evs":{"source":"iana"},"audio/fwdred":{"source":"iana"},"audio/g711-0":{"source":"iana"},"audio/g719":{"source":"iana"},"audio/g722":{"source":"iana"},"audio/g7221":{"source":"iana"},"audio/g723":{"source":"iana"},"audio/g726-16":{"source":"iana"},"audio/g726-24":{"source":"iana"},"audio/g726-32":{"source":"iana"},"audio/g726-40":{"source":"iana"},"audio/g728":{"source":"iana"},"audio/g729":{"source":"iana"},"audio/g7291":{"source":"iana"},"audio/g729d":{"source":"iana"},"audio/g729e":{"source":"iana"},"audio/gsm":{"source":"iana"},"audio/gsm-efr":{"source":"iana"},"audio/gsm-hr-08":{"source":"iana"},"audio/ilbc":{"source":"iana"},"audio/ip-mr_v2.5":{"source":"iana"},"audio/isac":{"source":"apache"},"audio/l16":{"source":"iana"},"audio/l20":{"source":"iana"},"audio/l24":{"source":"iana","compressible":false},"audio/l8":{"source":"iana"},"audio/lpc":{"source":"iana"},"audio/melp":{"source":"iana"},"audio/melp1200":{"source":"iana"},"audio/melp2400":{"source":"iana"},"audio/melp600":{"source":"iana"},"audio/midi":{"source":"apache","extensions":["mid","midi","kar","rmi"]},"audio/mobile-xmf":{"source":"iana"},"audio/mp3":{"compressible":false,"extensions":["mp3"]},"audio/mp4":{"source":"iana","compressible":false,"extensions":["m4a","mp4a"]},"audio/mp4a-latm":{"source":"iana"},"audio/mpa":{"source":"iana"},"audio/mpa-robust":{"source":"iana"},"audio/mpeg":{"source":"iana","compressible":false,"extensions":["mpga","mp2","mp2a","mp3","m2a","m3a"]},"audio/mpeg4-generic":{"source":"iana"},"audio/musepack":{"source":"apache"},"audio/ogg":{"source":"iana","compressible":false,"extensions":["oga","ogg","spx"]},"audio/opus":{"source":"iana"},"audio/parityfec":{"source":"iana"},"audio/pcma":{"source":"iana"},"audio/pcma-wb":{"source":"iana"},"audio/pcmu":{"source":"iana"},"audio/pcmu-wb":{"source":"iana"},"audio/prs.sid":{"source":"iana"},"audio/qcelp":{"source":"iana"},"audio/raptorfec":{"source":"iana"},"audio/red":{"source":"iana"},"audio/rtp-enc-aescm128":{"source":"iana"},"audio/rtp-midi":{"source":"iana"},"audio/rtploopback":{"source":"iana"},"audio/rtx":{"source":"iana"},"audio/s3m":{"source":"apache","extensions":["s3m"]},"audio/silk":{"source":"apache","extensions":["sil"]},"audio/smv":{"source":"iana"},"audio/smv-qcp":{"source":"iana"},"audio/smv0":{"source":"iana"},"audio/sp-midi":{"source":"iana"},"audio/speex":{"source":"iana"},"audio/t140c":{"source":"iana"},"audio/t38":{"source":"iana"},"audio/telephone-event":{"source":"iana"},"audio/tone":{"source":"iana"},"audio/uemclip":{"source":"iana"},"audio/ulpfec":{"source":"iana"},"audio/usac":{"source":"iana"},"audio/vdvi":{"source":"iana"},"audio/vmr-wb":{"source":"iana"},"audio/vnd.3gpp.iufp":{"source":"iana"},"audio/vnd.4sb":{"source":"iana"},"audio/vnd.audiokoz":{"source":"iana"},"audio/vnd.celp":{"source":"iana"},"audio/vnd.cisco.nse":{"source":"iana"},"audio/vnd.cmles.radio-events":{"source":"iana"},"audio/vnd.cns.anp1":{"source":"iana"},"audio/vnd.cns.inf1":{"source":"iana"},"audio/vnd.dece.audio":{"source":"iana","extensions":["uva","uvva"]},"audio/vnd.digital-winds":{"source":"iana","extensions":["eol"]},"audio/vnd.dlna.adts":{"source":"iana"},"audio/vnd.dolby.heaac.1":{"source":"iana"},"audio/vnd.dolby.heaac.2":{"source":"iana"},"audio/vnd.dolby.mlp":{"source":"iana"},"audio/vnd.dolby.mps":{"source":"iana"},"audio/vnd.dolby.pl2":{"source":"iana"},"audio/vnd.dolby.pl2x":{"source":"iana"},"audio/vnd.dolby.pl2z":{"source":"iana"},"audio/vnd.dolby.pulse.1":{"source":"iana"},"audio/vnd.dra":{"source":"iana","extensions":["dra"]},"audio/vnd.dts":{"source":"iana","extensions":["dts"]},"audio/vnd.dts.hd":{"source":"iana","extensions":["dtshd"]},"audio/vnd.dvb.file":{"source":"iana"},"audio/vnd.everad.plj":{"source":"iana"},"audio/vnd.hns.audio":{"source":"iana"},"audio/vnd.lucent.voice":{"source":"iana","extensions":["lvp"]},"audio/vnd.ms-playready.media.pya":{"source":"iana","extensions":["pya"]},"audio/vnd.nokia.mobile-xmf":{"source":"iana"},"audio/vnd.nortel.vbk":{"source":"iana"},"audio/vnd.nuera.ecelp4800":{"source":"iana","extensions":["ecelp4800"]},"audio/vnd.nuera.ecelp7470":{"source":"iana","extensions":["ecelp7470"]},"audio/vnd.nuera.ecelp9600":{"source":"iana","extensions":["ecelp9600"]},"audio/vnd.octel.sbc":{"source":"iana"},"audio/vnd.presonus.multitrack":{"source":"iana"},"audio/vnd.qcelp":{"source":"iana"},"audio/vnd.rhetorex.32kadpcm":{"source":"iana"},"audio/vnd.rip":{"source":"iana","extensions":["rip"]},"audio/vnd.rn-realaudio":{"compressible":false},"audio/vnd.sealedmedia.softseal.mpeg":{"source":"iana"},"audio/vnd.vmx.cvsd":{"source":"iana"},"audio/vnd.wave":{"compressible":false},"audio/vorbis":{"source":"iana","compressible":false},"audio/vorbis-config":{"source":"iana"},"audio/wav":{"compressible":false,"extensions":["wav"]},"audio/wave":{"compressible":false,"extensions":["wav"]},"audio/webm":{"source":"apache","compressible":false,"extensions":["weba"]},"audio/x-aac":{"source":"apache","compressible":false,"extensions":["aac"]},"audio/x-aiff":{"source":"apache","extensions":["aif","aiff","aifc"]},"audio/x-caf":{"source":"apache","compressible":false,"extensions":["caf"]},"audio/x-flac":{"source":"apache","extensions":["flac"]},"audio/x-m4a":{"source":"nginx","extensions":["m4a"]},"audio/x-matroska":{"source":"apache","extensions":["mka"]},"audio/x-mpegurl":{"source":"apache","extensions":["m3u"]},"audio/x-ms-wax":{"source":"apache","extensions":["wax"]},"audio/x-ms-wma":{"source":"apache","extensions":["wma"]},"audio/x-pn-realaudio":{"source":"apache","extensions":["ram","ra"]},"audio/x-pn-realaudio-plugin":{"source":"apache","extensions":["rmp"]},"audio/x-realaudio":{"source":"nginx","extensions":["ra"]},"audio/x-tta":{"source":"apache"},"audio/x-wav":{"source":"apache","extensions":["wav"]},"audio/xm":{"source":"apache","extensions":["xm"]},"chemical/x-cdx":{"source":"apache","extensions":["cdx"]},"chemical/x-cif":{"source":"apache","extensions":["cif"]},"chemical/x-cmdf":{"source":"apache","extensions":["cmdf"]},"chemical/x-cml":{"source":"apache","extensions":["cml"]},"chemical/x-csml":{"source":"apache","extensions":["csml"]},"chemical/x-pdb":{"source":"apache"},"chemical/x-xyz":{"source":"apache","extensions":["xyz"]},"font/collection":{"source":"iana","extensions":["ttc"]},"font/otf":{"source":"iana","compressible":true,"extensions":["otf"]},"font/sfnt":{"source":"iana"},"font/ttf":{"source":"iana","extensions":["ttf"]},"font/woff":{"source":"iana","extensions":["woff"]},"font/woff2":{"source":"iana","extensions":["woff2"]},"image/aces":{"source":"iana","extensions":["exr"]},"image/apng":{"compressible":false,"extensions":["apng"]},"image/avci":{"source":"iana"},"image/avcs":{"source":"iana"},"image/bmp":{"source":"iana","compressible":true,"extensions":["bmp"]},"image/cgm":{"source":"iana","extensions":["cgm"]},"image/dicom-rle":{"source":"iana","extensions":["drle"]},"image/emf":{"source":"iana","extensions":["emf"]},"image/fits":{"source":"iana","extensions":["fits"]},"image/g3fax":{"source":"iana","extensions":["g3"]},"image/gif":{"source":"iana","compressible":false,"extensions":["gif"]},"image/heic":{"source":"iana","extensions":["heic"]},"image/heic-sequence":{"source":"iana","extensions":["heics"]},"image/heif":{"source":"iana","extensions":["heif"]},"image/heif-sequence":{"source":"iana","extensions":["heifs"]},"image/ief":{"source":"iana","extensions":["ief"]},"image/jls":{"source":"iana","extensions":["jls"]},"image/jp2":{"source":"iana","compressible":false,"extensions":["jp2","jpg2"]},"image/jpeg":{"source":"iana","compressible":false,"extensions":["jpeg","jpg","jpe"]},"image/jpm":{"source":"iana","compressible":false,"extensions":["jpm"]},"image/jpx":{"source":"iana","compressible":false,"extensions":["jpx","jpf"]},"image/ktx":{"source":"iana","extensions":["ktx"]},"image/naplps":{"source":"iana"},"image/pjpeg":{"compressible":false},"image/png":{"source":"iana","compressible":false,"extensions":["png"]},"image/prs.btif":{"source":"iana","extensions":["btif"]},"image/prs.pti":{"source":"iana","extensions":["pti"]},"image/pwg-raster":{"source":"iana"},"image/sgi":{"source":"apache","extensions":["sgi"]},"image/svg+xml":{"source":"iana","compressible":true,"extensions":["svg","svgz"]},"image/t38":{"source":"iana","extensions":["t38"]},"image/tiff":{"source":"iana","compressible":false,"extensions":["tif","tiff"]},"image/tiff-fx":{"source":"iana","extensions":["tfx"]},"image/vnd.adobe.photoshop":{"source":"iana","compressible":true,"extensions":["psd"]},"image/vnd.airzip.accelerator.azv":{"source":"iana","extensions":["azv"]},"image/vnd.cns.inf2":{"source":"iana"},"image/vnd.dece.graphic":{"source":"iana","extensions":["uvi","uvvi","uvg","uvvg"]},"image/vnd.djvu":{"source":"iana","extensions":["djvu","djv"]},"image/vnd.dvb.subtitle":{"source":"iana","extensions":["sub"]},"image/vnd.dwg":{"source":"iana","extensions":["dwg"]},"image/vnd.dxf":{"source":"iana","extensions":["dxf"]},"image/vnd.fastbidsheet":{"source":"iana","extensions":["fbs"]},"image/vnd.fpx":{"source":"iana","extensions":["fpx"]},"image/vnd.fst":{"source":"iana","extensions":["fst"]},"image/vnd.fujixerox.edmics-mmr":{"source":"iana","extensions":["mmr"]},"image/vnd.fujixerox.edmics-rlc":{"source":"iana","extensions":["rlc"]},"image/vnd.globalgraphics.pgb":{"source":"iana"},"image/vnd.microsoft.icon":{"source":"iana","extensions":["ico"]},"image/vnd.mix":{"source":"iana"},"image/vnd.mozilla.apng":{"source":"iana"},"image/vnd.ms-modi":{"source":"iana","extensions":["mdi"]},"image/vnd.ms-photo":{"source":"apache","extensions":["wdp"]},"image/vnd.net-fpx":{"source":"iana","extensions":["npx"]},"image/vnd.radiance":{"source":"iana"},"image/vnd.sealed.png":{"source":"iana"},"image/vnd.sealedmedia.softseal.gif":{"source":"iana"},"image/vnd.sealedmedia.softseal.jpg":{"source":"iana"},"image/vnd.svf":{"source":"iana"},"image/vnd.tencent.tap":{"source":"iana","extensions":["tap"]},"image/vnd.valve.source.texture":{"source":"iana","extensions":["vtf"]},"image/vnd.wap.wbmp":{"source":"iana","extensions":["wbmp"]},"image/vnd.xiff":{"source":"iana","extensions":["xif"]},"image/vnd.zbrush.pcx":{"source":"iana","extensions":["pcx"]},"image/webp":{"source":"apache","extensions":["webp"]},"image/wmf":{"source":"iana","extensions":["wmf"]},"image/x-3ds":{"source":"apache","extensions":["3ds"]},"image/x-cmu-raster":{"source":"apache","extensions":["ras"]},"image/x-cmx":{"source":"apache","extensions":["cmx"]},"image/x-freehand":{"source":"apache","extensions":["fh","fhc","fh4","fh5","fh7"]},"image/x-icon":{"source":"apache","compressible":true,"extensions":["ico"]},"image/x-jng":{"source":"nginx","extensions":["jng"]},"image/x-mrsid-image":{"source":"apache","extensions":["sid"]},"image/x-ms-bmp":{"source":"nginx","compressible":true,"extensions":["bmp"]},"image/x-pcx":{"source":"apache","extensions":["pcx"]},"image/x-pict":{"source":"apache","extensions":["pic","pct"]},"image/x-portable-anymap":{"source":"apache","extensions":["pnm"]},"image/x-portable-bitmap":{"source":"apache","extensions":["pbm"]},"image/x-portable-graymap":{"source":"apache","extensions":["pgm"]},"image/x-portable-pixmap":{"source":"apache","extensions":["ppm"]},"image/x-rgb":{"source":"apache","extensions":["rgb"]},"image/x-tga":{"source":"apache","extensions":["tga"]},"image/x-xbitmap":{"source":"apache","extensions":["xbm"]},"image/x-xcf":{"compressible":false},"image/x-xpixmap":{"source":"apache","extensions":["xpm"]},"image/x-xwindowdump":{"source":"apache","extensions":["xwd"]},"message/cpim":{"source":"iana"},"message/delivery-status":{"source":"iana"},"message/disposition-notification":{"source":"iana","extensions":["disposition-notification"]},"message/external-body":{"source":"iana"},"message/feedback-report":{"source":"iana"},"message/global":{"source":"iana","extensions":["u8msg"]},"message/global-delivery-status":{"source":"iana","extensions":["u8dsn"]},"message/global-disposition-notification":{"source":"iana","extensions":["u8mdn"]},"message/global-headers":{"source":"iana","extensions":["u8hdr"]},"message/http":{"source":"iana","compressible":false},"message/imdn+xml":{"source":"iana","compressible":true},"message/news":{"source":"iana"},"message/partial":{"source":"iana","compressible":false},"message/rfc822":{"source":"iana","compressible":true,"extensions":["eml","mime"]},"message/s-http":{"source":"iana"},"message/sip":{"source":"iana"},"message/sipfrag":{"source":"iana"},"message/tracking-status":{"source":"iana"},"message/vnd.si.simp":{"source":"iana"},"message/vnd.wfa.wsc":{"source":"iana","extensions":["wsc"]},"model/3mf":{"source":"iana"},"model/gltf+json":{"source":"iana","compressible":true,"extensions":["gltf"]},"model/gltf-binary":{"source":"iana","compressible":true,"extensions":["glb"]},"model/iges":{"source":"iana","compressible":false,"extensions":["igs","iges"]},"model/mesh":{"source":"iana","compressible":false,"extensions":["msh","mesh","silo"]},"model/stl":{"source":"iana"},"model/vnd.collada+xml":{"source":"iana","compressible":true,"extensions":["dae"]},"model/vnd.dwf":{"source":"iana","extensions":["dwf"]},"model/vnd.flatland.3dml":{"source":"iana"},"model/vnd.gdl":{"source":"iana","extensions":["gdl"]},"model/vnd.gs-gdl":{"source":"apache"},"model/vnd.gs.gdl":{"source":"iana"},"model/vnd.gtw":{"source":"iana","extensions":["gtw"]},"model/vnd.moml+xml":{"source":"iana","compressible":true},"model/vnd.mts":{"source":"iana","extensions":["mts"]},"model/vnd.opengex":{"source":"iana"},"model/vnd.parasolid.transmit.binary":{"source":"iana"},"model/vnd.parasolid.transmit.text":{"source":"iana"},"model/vnd.rosette.annotated-data-model":{"source":"iana"},"model/vnd.usdz+zip":{"source":"iana","compressible":false},"model/vnd.valve.source.compiled-map":{"source":"iana"},"model/vnd.vtu":{"source":"iana","extensions":["vtu"]},"model/vrml":{"source":"iana","compressible":false,"extensions":["wrl","vrml"]},"model/x3d+binary":{"source":"apache","compressible":false,"extensions":["x3db","x3dbz"]},"model/x3d+fastinfoset":{"source":"iana"},"model/x3d+vrml":{"source":"apache","compressible":false,"extensions":["x3dv","x3dvz"]},"model/x3d+xml":{"source":"iana","compressible":true,"extensions":["x3d","x3dz"]},"model/x3d-vrml":{"source":"iana"},"multipart/alternative":{"source":"iana","compressible":false},"multipart/appledouble":{"source":"iana"},"multipart/byteranges":{"source":"iana"},"multipart/digest":{"source":"iana"},"multipart/encrypted":{"source":"iana","compressible":false},"multipart/form-data":{"source":"iana","compressible":false},"multipart/header-set":{"source":"iana"},"multipart/mixed":{"source":"iana","compressible":false},"multipart/multilingual":{"source":"iana"},"multipart/parallel":{"source":"iana"},"multipart/related":{"source":"iana","compressible":false},"multipart/report":{"source":"iana"},"multipart/signed":{"source":"iana","compressible":false},"multipart/vnd.bint.med-plus":{"source":"iana"},"multipart/voice-message":{"source":"iana"},"multipart/x-mixed-replace":{"source":"iana"},"text/1d-interleaved-parityfec":{"source":"iana"},"text/cache-manifest":{"source":"iana","compressible":true,"extensions":["appcache","manifest"]},"text/calendar":{"source":"iana","extensions":["ics","ifb"]},"text/calender":{"compressible":true},"text/cmd":{"compressible":true},"text/coffeescript":{"extensions":["coffee","litcoffee"]},"text/css":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["css"]},"text/csv":{"source":"iana","compressible":true,"extensions":["csv"]},"text/csv-schema":{"source":"iana"},"text/directory":{"source":"iana"},"text/dns":{"source":"iana"},"text/ecmascript":{"source":"iana"},"text/encaprtp":{"source":"iana"},"text/enriched":{"source":"iana"},"text/fwdred":{"source":"iana"},"text/grammar-ref-list":{"source":"iana"},"text/html":{"source":"iana","compressible":true,"extensions":["html","htm","shtml"]},"text/jade":{"extensions":["jade"]},"text/javascript":{"source":"iana","compressible":true},"text/jcr-cnd":{"source":"iana"},"text/jsx":{"compressible":true,"extensions":["jsx"]},"text/less":{"extensions":["less"]},"text/markdown":{"source":"iana","compressible":true,"extensions":["markdown","md"]},"text/mathml":{"source":"nginx","extensions":["mml"]},"text/mizar":{"source":"iana"},"text/n3":{"source":"iana","compressible":true,"extensions":["n3"]},"text/parameters":{"source":"iana"},"text/parityfec":{"source":"iana"},"text/plain":{"source":"iana","compressible":true,"extensions":["txt","text","conf","def","list","log","in","ini"]},"text/provenance-notation":{"source":"iana"},"text/prs.fallenstein.rst":{"source":"iana"},"text/prs.lines.tag":{"source":"iana","extensions":["dsc"]},"text/prs.prop.logic":{"source":"iana"},"text/raptorfec":{"source":"iana"},"text/red":{"source":"iana"},"text/rfc822-headers":{"source":"iana"},"text/richtext":{"source":"iana","compressible":true,"extensions":["rtx"]},"text/rtf":{"source":"iana","compressible":true,"extensions":["rtf"]},"text/rtp-enc-aescm128":{"source":"iana"},"text/rtploopback":{"source":"iana"},"text/rtx":{"source":"iana"},"text/sgml":{"source":"iana","extensions":["sgml","sgm"]},"text/shex":{"extensions":["shex"]},"text/slim":{"extensions":["slim","slm"]},"text/strings":{"source":"iana"},"text/stylus":{"extensions":["stylus","styl"]},"text/t140":{"source":"iana"},"text/tab-separated-values":{"source":"iana","compressible":true,"extensions":["tsv"]},"text/troff":{"source":"iana","extensions":["t","tr","roff","man","me","ms"]},"text/turtle":{"source":"iana","charset":"UTF-8","extensions":["ttl"]},"text/ulpfec":{"source":"iana"},"text/uri-list":{"source":"iana","compressible":true,"extensions":["uri","uris","urls"]},"text/vcard":{"source":"iana","compressible":true,"extensions":["vcard"]},"text/vnd.a":{"source":"iana"},"text/vnd.abc":{"source":"iana"},"text/vnd.ascii-art":{"source":"iana"},"text/vnd.curl":{"source":"iana","extensions":["curl"]},"text/vnd.curl.dcurl":{"source":"apache","extensions":["dcurl"]},"text/vnd.curl.mcurl":{"source":"apache","extensions":["mcurl"]},"text/vnd.curl.scurl":{"source":"apache","extensions":["scurl"]},"text/vnd.debian.copyright":{"source":"iana"},"text/vnd.dmclientscript":{"source":"iana"},"text/vnd.dvb.subtitle":{"source":"iana","extensions":["sub"]},"text/vnd.esmertec.theme-descriptor":{"source":"iana"},"text/vnd.fly":{"source":"iana","extensions":["fly"]},"text/vnd.fmi.flexstor":{"source":"iana","extensions":["flx"]},"text/vnd.gml":{"source":"iana"},"text/vnd.graphviz":{"source":"iana","extensions":["gv"]},"text/vnd.hgl":{"source":"iana"},"text/vnd.in3d.3dml":{"source":"iana","extensions":["3dml"]},"text/vnd.in3d.spot":{"source":"iana","extensions":["spot"]},"text/vnd.iptc.newsml":{"source":"iana"},"text/vnd.iptc.nitf":{"source":"iana"},"text/vnd.latex-z":{"source":"iana"},"text/vnd.motorola.reflex":{"source":"iana"},"text/vnd.ms-mediapackage":{"source":"iana"},"text/vnd.net2phone.commcenter.command":{"source":"iana"},"text/vnd.radisys.msml-basic-layout":{"source":"iana"},"text/vnd.si.uricatalogue":{"source":"iana"},"text/vnd.sun.j2me.app-descriptor":{"source":"iana","extensions":["jad"]},"text/vnd.trolltech.linguist":{"source":"iana"},"text/vnd.wap.si":{"source":"iana"},"text/vnd.wap.sl":{"source":"iana"},"text/vnd.wap.wml":{"source":"iana","extensions":["wml"]},"text/vnd.wap.wmlscript":{"source":"iana","extensions":["wmls"]},"text/vtt":{"charset":"UTF-8","compressible":true,"extensions":["vtt"]},"text/x-asm":{"source":"apache","extensions":["s","asm"]},"text/x-c":{"source":"apache","extensions":["c","cc","cxx","cpp","h","hh","dic"]},"text/x-component":{"source":"nginx","extensions":["htc"]},"text/x-fortran":{"source":"apache","extensions":["f","for","f77","f90"]},"text/x-gwt-rpc":{"compressible":true},"text/x-handlebars-template":{"extensions":["hbs"]},"text/x-java-source":{"source":"apache","extensions":["java"]},"text/x-jquery-tmpl":{"compressible":true},"text/x-lua":{"extensions":["lua"]},"text/x-markdown":{"compressible":true,"extensions":["mkd"]},"text/x-nfo":{"source":"apache","extensions":["nfo"]},"text/x-opml":{"source":"apache","extensions":["opml"]},"text/x-org":{"compressible":true,"extensions":["org"]},"text/x-pascal":{"source":"apache","extensions":["p","pas"]},"text/x-processing":{"compressible":true,"extensions":["pde"]},"text/x-sass":{"extensions":["sass"]},"text/x-scss":{"extensions":["scss"]},"text/x-setext":{"source":"apache","extensions":["etx"]},"text/x-sfv":{"source":"apache","extensions":["sfv"]},"text/x-suse-ymp":{"compressible":true,"extensions":["ymp"]},"text/x-uuencode":{"source":"apache","extensions":["uu"]},"text/x-vcalendar":{"source":"apache","extensions":["vcs"]},"text/x-vcard":{"source":"apache","extensions":["vcf"]},"text/xml":{"source":"iana","compressible":true,"extensions":["xml"]},"text/xml-external-parsed-entity":{"source":"iana"},"text/yaml":{"extensions":["yaml","yml"]},"video/1d-interleaved-parityfec":{"source":"iana"},"video/3gpp":{"source":"iana","extensions":["3gp","3gpp"]},"video/3gpp-tt":{"source":"iana"},"video/3gpp2":{"source":"iana","extensions":["3g2"]},"video/bmpeg":{"source":"iana"},"video/bt656":{"source":"iana"},"video/celb":{"source":"iana"},"video/dv":{"source":"iana"},"video/encaprtp":{"source":"iana"},"video/h261":{"source":"iana","extensions":["h261"]},"video/h263":{"source":"iana","extensions":["h263"]},"video/h263-1998":{"source":"iana"},"video/h263-2000":{"source":"iana"},"video/h264":{"source":"iana","extensions":["h264"]},"video/h264-rcdo":{"source":"iana"},"video/h264-svc":{"source":"iana"},"video/h265":{"source":"iana"},"video/iso.segment":{"source":"iana"},"video/jpeg":{"source":"iana","extensions":["jpgv"]},"video/jpeg2000":{"source":"iana"},"video/jpm":{"source":"apache","extensions":["jpm","jpgm"]},"video/mj2":{"source":"iana","extensions":["mj2","mjp2"]},"video/mp1s":{"source":"iana"},"video/mp2p":{"source":"iana"},"video/mp2t":{"source":"iana","extensions":["ts"]},"video/mp4":{"source":"iana","compressible":false,"extensions":["mp4","mp4v","mpg4"]},"video/mp4v-es":{"source":"iana"},"video/mpeg":{"source":"iana","compressible":false,"extensions":["mpeg","mpg","mpe","m1v","m2v"]},"video/mpeg4-generic":{"source":"iana"},"video/mpv":{"source":"iana"},"video/nv":{"source":"iana"},"video/ogg":{"source":"iana","compressible":false,"extensions":["ogv"]},"video/parityfec":{"source":"iana"},"video/pointer":{"source":"iana"},"video/quicktime":{"source":"iana","compressible":false,"extensions":["qt","mov"]},"video/raptorfec":{"source":"iana"},"video/raw":{"source":"iana"},"video/rtp-enc-aescm128":{"source":"iana"},"video/rtploopback":{"source":"iana"},"video/rtx":{"source":"iana"},"video/smpte291":{"source":"iana"},"video/smpte292m":{"source":"iana"},"video/ulpfec":{"source":"iana"},"video/vc1":{"source":"iana"},"video/vc2":{"source":"iana"},"video/vnd.cctv":{"source":"iana"},"video/vnd.dece.hd":{"source":"iana","extensions":["uvh","uvvh"]},"video/vnd.dece.mobile":{"source":"iana","extensions":["uvm","uvvm"]},"video/vnd.dece.mp4":{"source":"iana"},"video/vnd.dece.pd":{"source":"iana","extensions":["uvp","uvvp"]},"video/vnd.dece.sd":{"source":"iana","extensions":["uvs","uvvs"]},"video/vnd.dece.video":{"source":"iana","extensions":["uvv","uvvv"]},"video/vnd.directv.mpeg":{"source":"iana"},"video/vnd.directv.mpeg-tts":{"source":"iana"},"video/vnd.dlna.mpeg-tts":{"source":"iana"},"video/vnd.dvb.file":{"source":"iana","extensions":["dvb"]},"video/vnd.fvt":{"source":"iana","extensions":["fvt"]},"video/vnd.hns.video":{"source":"iana"},"video/vnd.iptvforum.1dparityfec-1010":{"source":"iana"},"video/vnd.iptvforum.1dparityfec-2005":{"source":"iana"},"video/vnd.iptvforum.2dparityfec-1010":{"source":"iana"},"video/vnd.iptvforum.2dparityfec-2005":{"source":"iana"},"video/vnd.iptvforum.ttsavc":{"source":"iana"},"video/vnd.iptvforum.ttsmpeg2":{"source":"iana"},"video/vnd.motorola.video":{"source":"iana"},"video/vnd.motorola.videop":{"source":"iana"},"video/vnd.mpegurl":{"source":"iana","extensions":["mxu","m4u"]},"video/vnd.ms-playready.media.pyv":{"source":"iana","extensions":["pyv"]},"video/vnd.nokia.interleaved-multimedia":{"source":"iana"},"video/vnd.nokia.mp4vr":{"source":"iana"},"video/vnd.nokia.videovoip":{"source":"iana"},"video/vnd.objectvideo":{"source":"iana"},"video/vnd.radgamettools.bink":{"source":"iana"},"video/vnd.radgamettools.smacker":{"source":"iana"},"video/vnd.sealed.mpeg1":{"source":"iana"},"video/vnd.sealed.mpeg4":{"source":"iana"},"video/vnd.sealed.swf":{"source":"iana"},"video/vnd.sealedmedia.softseal.mov":{"source":"iana"},"video/vnd.uvvu.mp4":{"source":"iana","extensions":["uvu","uvvu"]},"video/vnd.vivo":{"source":"iana","extensions":["viv"]},"video/vp8":{"source":"iana"},"video/webm":{"source":"apache","compressible":false,"extensions":["webm"]},"video/x-f4v":{"source":"apache","extensions":["f4v"]},"video/x-fli":{"source":"apache","extensions":["fli"]},"video/x-flv":{"source":"apache","compressible":false,"extensions":["flv"]},"video/x-m4v":{"source":"apache","extensions":["m4v"]},"video/x-matroska":{"source":"apache","compressible":false,"extensions":["mkv","mk3d","mks"]},"video/x-mng":{"source":"apache","extensions":["mng"]},"video/x-ms-asf":{"source":"apache","extensions":["asf","asx"]},"video/x-ms-vob":{"source":"apache","extensions":["vob"]},"video/x-ms-wm":{"source":"apache","extensions":["wm"]},"video/x-ms-wmv":{"source":"apache","compressible":false,"extensions":["wmv"]},"video/x-ms-wmx":{"source":"apache","extensions":["wmx"]},"video/x-ms-wvx":{"source":"apache","extensions":["wvx"]},"video/x-msvideo":{"source":"apache","extensions":["avi"]},"video/x-sgi-movie":{"source":"apache","extensions":["movie"]},"video/x-smv":{"source":"apache","extensions":["smv"]},"x-conference/x-cooltalk":{"source":"apache","extensions":["ice"]},"x-shader/x-fragment":{"compressible":true},"x-shader/x-vertex":{"compressible":true}}')},function(e,t,r){e.exports=u,u.SSL=l;var i=r(11),n=r(52).Agent,a=r(83),o=r(232),s=r(85).Agent;function c(e,t){return"string"==typeof e?e+":"+t:e.host+":"+e.port+":"+(e.localAddress?e.localAddress+":":":")}function u(e){var t=this;t.options=e||{},t.requests={},t.sockets={},t.freeSockets={},t.maxSockets=t.options.maxSockets||n.defaultMaxSockets,t.minSockets=t.options.minSockets||u.defaultMinSockets,t.on("free",(function(e,r,i){var n=c(r,i);if(t.requests[n]&&t.requests[n].length)t.requests[n].shift().onSocket(e);else if(t.sockets[n].length0&&!e.useChunkedEncodingByDefault){var a=this.freeSockets[i].pop();a.removeListener("error",a._onIdleError),delete a._onIdleError,e._reusedSocket=!0,e.onSocket(a)}else this.addRequestNoreuse(e,t,r)},u.prototype.removeSocket=function(e,t,r,i){var n;this.sockets[t]?-1!==(n=this.sockets[t].indexOf(e))&&this.sockets[t].splice(n,1):this.sockets[t]&&0===this.sockets[t].length&&(delete this.sockets[t],delete this.requests[t]);this.freeSockets[t]&&(-1!==(n=this.freeSockets[t].indexOf(e))&&(this.freeSockets[t].splice(n,1),0===this.freeSockets[t].length&&delete this.freeSockets[t]));this.requests[t]&&this.requests[t].length&&this.createSocket(t,r,i).emit("free")},i.inherits(l,u),l.prototype.createConnection=function(e,t,r){r="object"==typeof e?e:"object"==typeof t?t:"object"==typeof r?r:{};"number"==typeof e&&(r.port=e);"string"==typeof t&&(r.host=t);return o.connect(r)},l.prototype.addRequestNoreuse=s.prototype.addRequest},function(e,t){e.exports="object"==typeof self?self.FormData:window.FormData},function(e,t){e.exports=n,n.strict=a,n.loose=o;var r=Object.prototype.toString,i={"[object Int8Array]":!0,"[object Int16Array]":!0,"[object Int32Array]":!0,"[object Uint8Array]":!0,"[object Uint8ClampedArray]":!0,"[object Uint16Array]":!0,"[object Uint32Array]":!0,"[object Float32Array]":!0,"[object Float64Array]":!0};function n(e){return a(e)||o(e)}function a(e){return e instanceof Int8Array||e instanceof Int16Array||e instanceof Int32Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray||e instanceof Uint16Array||e instanceof Uint32Array||e instanceof Float32Array||e instanceof Float64Array}function o(e){return i[r.call(e)]}},function(e,t,r){"use strict";(function(t){function r(e){return e.replace(/^\.*/,".").toLowerCase()}function i(e){var t=(e=e.trim().toLowerCase()).split(":",2);return{hostname:r(t[0]),port:t[1],hasPort:e.indexOf(":")>-1}}e.exports=function(e){var n=t.env.NO_PROXY||t.env.no_proxy||"";return"*"===n||""!==n&&function(e,t){var n=e.port||("https:"===e.protocol?"443":"80"),a=r(e.hostname);return t.split(",").map(i).some((function(e){var t=a.indexOf(e.hostname),r=t>-1&&t===a.length-e.hostname.length;return e.hasPort?n===e.port&&r:r}))}(e,n)?null:"http:"===e.protocol?t.env.HTTP_PROXY||t.env.http_proxy||null:"https:"===e.protocol&&(t.env.HTTPS_PROXY||t.env.https_proxy||t.env.HTTP_PROXY||t.env.http_proxy)||null}}).call(this,r(3))},function(e,t,r){"use strict";var i=r(234),n=r(84);function a(e){this.request=e,this.lib=null,this.useQuerystring=null,this.parseOptions=null,this.stringifyOptions=null}a.prototype.init=function(e){this.lib||(this.useQuerystring=e.useQuerystring,this.lib=this.useQuerystring?n:i,this.parseOptions=e.qsParseOptions||{},this.stringifyOptions=e.qsStringifyOptions||{})},a.prototype.stringify=function(e){return this.useQuerystring?this.rfc3986(this.lib.stringify(e,this.stringifyOptions.sep||null,this.stringifyOptions.eq||null,this.stringifyOptions)):this.lib.stringify(e,this.stringifyOptions)},a.prototype.parse=function(e){return this.useQuerystring?this.lib.parse(e,this.parseOptions.sep||null,this.parseOptions.eq||null,this.parseOptions):this.lib.parse(e,this.parseOptions)},a.prototype.rfc3986=function(e){return e.replace(/[!'()*]/g,(function(e){return"%"+e.charCodeAt(0).toString(16).toUpperCase()}))},a.prototype.unescape=n.unescape,t.Querystring=a},function(e,t,r){"use strict";var i=r(235),n=r(236),a={brackets:function(e){return e+"[]"},indices:function(e,t){return e+"["+t+"]"},repeat:function(e){return e}},o=Date.prototype.toISOString,s={delimiter:"&",encode:!0,encoder:i.encode,encodeValuesOnly:!1,serializeDate:function(e){return o.call(e)},skipNulls:!1,strictNullHandling:!1},c=function e(t,r,n,a,o,c,u,l,h,d,p,f){var m=t;if("function"==typeof u)m=u(r,m);else if(m instanceof Date)m=d(m);else if(null===m){if(a)return c&&!f?c(r,s.encoder):r;m=""}if("string"==typeof m||"number"==typeof m||"boolean"==typeof m||i.isBuffer(m))return c?[p(f?r:c(r,s.encoder))+"="+p(c(m,s.encoder))]:[p(r)+"="+p(String(m))];var g,_=[];if(void 0===m)return _;if(Array.isArray(u))g=u;else{var v=Object.keys(m);g=l?v.sort(l):v}for(var y=0;y0?N+M:""}},function(e,t,r){"use strict";var i=r(235),n=Object.prototype.hasOwnProperty,a={allowDots:!1,allowPrototypes:!1,arrayLimit:20,decoder:i.decode,delimiter:"&",depth:5,parameterLimit:1e3,plainObjects:!1,strictNullHandling:!1},o=function(e,t,r){if(e){var i=r.allowDots?e.replace(/\.([^.[]+)/g,"[$1]"):e,a=/(\[[^[\]]*])/g,o=/(\[[^[\]]*])/.exec(i),s=o?i.slice(0,o.index):i,c=[];if(s){if(!r.plainObjects&&n.call(Object.prototype,s)&&!r.allowPrototypes)return;c.push(s)}for(var u=0;null!==(o=a.exec(i))&&u=0;--n){var a,o=e[n];if("[]"===o)a=(a=[]).concat(i);else{a=r.plainObjects?Object.create(null):{};var s="["===o.charAt(0)&&"]"===o.charAt(o.length-1)?o.slice(1,-1):o,c=parseInt(s,10);!isNaN(c)&&o!==s&&String(c)===s&&c>=0&&r.parseArrays&&c<=r.arrayLimit?(a=[])[c]=i:a[s]=i}i=a}return i}(c,t,r)}};e.exports=function(e,t){var r=t?i.assign({},t):{};if(null!==r.decoder&&void 0!==r.decoder&&"function"!=typeof r.decoder)throw new TypeError("Decoder has to be a function.");if(r.ignoreQueryPrefix=!0===r.ignoreQueryPrefix,r.delimiter="string"==typeof r.delimiter||i.isRegExp(r.delimiter)?r.delimiter:a.delimiter,r.depth="number"==typeof r.depth?r.depth:a.depth,r.arrayLimit="number"==typeof r.arrayLimit?r.arrayLimit:a.arrayLimit,r.parseArrays=!1!==r.parseArrays,r.decoder="function"==typeof r.decoder?r.decoder:a.decoder,r.allowDots="boolean"==typeof r.allowDots?r.allowDots:a.allowDots,r.plainObjects="boolean"==typeof r.plainObjects?r.plainObjects:a.plainObjects,r.allowPrototypes="boolean"==typeof r.allowPrototypes?r.allowPrototypes:a.allowPrototypes,r.parameterLimit="number"==typeof r.parameterLimit?r.parameterLimit:a.parameterLimit,r.strictNullHandling="boolean"==typeof r.strictNullHandling?r.strictNullHandling:a.strictNullHandling,""===e||null==e)return r.plainObjects?Object.create(null):{};for(var s="string"==typeof e?function(e,t){for(var r={},i=t.ignoreQueryPrefix?e.replace(/^\?/,""):e,o=t.parameterLimit===1/0?void 0:t.parameterLimit,s=i.split(t.delimiter,o),c=0;c=0?{index:i,compiling:!0}:(i=this._compilations.length,this._compilations[i]={schema:e,root:t,baseId:r},{index:i,compiling:!1})}function p(e,t,r){var i=f.call(this,e,t,r);i>=0&&this._compilations.splice(i,1)}function f(e,t,r){for(var i=0;i=55296&&t<=56319&&n%\\^`{|}]|%[0-9a-f]{2})|\{[+#./;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?::[1-9][0-9]{0,3}|\*)?)*\})*$/i,l=/^(?:(?:http[s\u017F]?|ftp):\/\/)(?:(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+(?::(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?@)?(?:(?!10(?:\.[0-9]{1,3}){3})(?!127(?:\.[0-9]{1,3}){3})(?!169\.254(?:\.[0-9]{1,3}){2})(?!192\.168(?:\.[0-9]{1,3}){2})(?!172\.(?:1[6-9]|2[0-9]|3[01])(?:\.[0-9]{1,3}){2})(?:[1-9][0-9]?|1[0-9][0-9]|2[01][0-9]|22[0-3])(?:\.(?:1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])){2}(?:\.(?:[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-4]))|(?:(?:(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-?)*(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)(?:\.(?:(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+-?)*(?:[0-9KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])+)*(?:\.(?:(?:[KSa-z\xA1-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]){2,})))(?::[0-9]{2,5})?(?:\/(?:[\0-\x08\x0E-\x1F!-\x9F\xA1-\u167F\u1681-\u1FFF\u200B-\u2027\u202A-\u202E\u2030-\u205E\u2060-\u2FFF\u3001-\uD7FF\uE000-\uFEFE\uFF00-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])*)?$/i,h=/^(?:urn:uuid:)?[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}$/i,d=/^(?:\/(?:[^~/]|~0|~1)*)*$|^#(?:\/(?:[a-z0-9_\-.!$&'()*+,;:=@]|%[0-9a-f]{2}|~0|~1)*)*$/i,p=/^(?:0|[1-9][0-9]*)(?:#|(?:\/(?:[^~/]|~0|~1)*)*)$/;function f(e){return e="full"==e?"full":"fast",i.copy(f[e])}function m(e){var t=e.match(n);if(!t)return!1;var r=+t[1],i=+t[2];return r>=1&&r<=12&&i>=1&&i<=a[r]}function g(e,t){var r=e.match(o);if(!r)return!1;var i=r[1],n=r[2],a=r[3],s=r[5];return i<=23&&n<=59&&a<=59&&(!t||s)}e.exports=f,f.fast={date:/^\d\d\d\d-[0-1]\d-[0-3]\d$/,time:/^[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:z|[+-]\d\d:\d\d)?$/i,"date-time":/^\d\d\d\d-[0-1]\d-[0-3]\d[t\s][0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:z|[+-]\d\d:\d\d)$/i,uri:/^(?:[a-z][a-z0-9+-.]*)(?::|\/)\/?[^\s]*$/i,"uri-reference":/^(?:(?:[a-z][a-z0-9+-.]*:)?\/\/)?[^\s]*$/i,"uri-template":u,url:l,email:/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i,hostname:s,ipv4:/^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,ipv6:/^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i,regex:b,uuid:h,"json-pointer":d,"relative-json-pointer":p},f.full={date:m,time:g,"date-time":function(e){var t=e.split(_);return 2==t.length&&m(t[0])&&g(t[1],!0)},uri:function(e){return v.test(e)&&c.test(e)},"uri-reference":/^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i,"uri-template":u,url:l,email:/^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&''*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i,hostname:function(e){return e.length<=255&&s.test(e)},ipv4:/^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/,ipv6:/^\s*(?:(?:(?:[0-9a-f]{1,4}:){7}(?:[0-9a-f]{1,4}|:))|(?:(?:[0-9a-f]{1,4}:){6}(?::[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){5}(?:(?:(?::[0-9a-f]{1,4}){1,2})|:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(?:(?:[0-9a-f]{1,4}:){4}(?:(?:(?::[0-9a-f]{1,4}){1,3})|(?:(?::[0-9a-f]{1,4})?:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){3}(?:(?:(?::[0-9a-f]{1,4}){1,4})|(?:(?::[0-9a-f]{1,4}){0,2}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){2}(?:(?:(?::[0-9a-f]{1,4}){1,5})|(?:(?::[0-9a-f]{1,4}){0,3}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?:(?:[0-9a-f]{1,4}:){1}(?:(?:(?::[0-9a-f]{1,4}){1,6})|(?:(?::[0-9a-f]{1,4}){0,4}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(?::(?:(?:(?::[0-9a-f]{1,4}){1,7})|(?:(?::[0-9a-f]{1,4}){0,5}:(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(?:%.+)?\s*$/i,regex:b,uuid:h,"json-pointer":d,"relative-json-pointer":p};var _=/t|\s/i;var v=/\/|:/;var y=/[^\\]\\Z/;function b(e){if(y.test(e))return!1;try{return new RegExp(e),!0}catch(e){return!1}}},function(e,t,r){"use strict";var i=r(458),n=r(54).toHash;e.exports=function(){var e=[{type:"number",rules:[{maximum:["exclusiveMaximum"]},{minimum:["exclusiveMinimum"]},"multipleOf","format"]},{type:"string",rules:["maxLength","minLength","pattern","format"]},{type:"array",rules:["maxItems","minItems","uniqueItems","contains","items"]},{type:"object",rules:["maxProperties","minProperties","required","dependencies","propertyNames",{properties:["additionalProperties","patternProperties"]}]},{rules:["$ref","const","enum","not","anyOf","oneOf","allOf"]}],t=["type"];return e.all=n(t),e.types=n(["number","integer","string","array","object","boolean","null"]),e.forEach((function(r){r.rules=r.rules.map((function(r){var n;if("object"==typeof r){var a=Object.keys(r)[0];n=r[a],r=a,n.forEach((function(r){t.push(r),e.all[r]=!0}))}return t.push(r),e.all[r]={keyword:r,code:i[r],implements:n}})),r.type&&(e.types[r.type]=r)})),e.keywords=n(t.concat(["additionalItems","$schema","$id","id","title","description","default","definitions"])),e.custom={},e}},function(e,t,r){"use strict";e.exports={$ref:r(459),allOf:r(460),anyOf:r(461),const:r(462),contains:r(463),dependencies:r(464),enum:r(465),format:r(466),items:r(467),maximum:r(241),minimum:r(241),maxItems:r(242),minItems:r(242),maxLength:r(243),minLength:r(243),maxProperties:r(244),minProperties:r(244),multipleOf:r(468),not:r(469),oneOf:r(470),pattern:r(471),properties:r(472),propertyNames:r(473),required:r(474),uniqueItems:r(475),validate:r(239)}},function(e,t,r){"use strict";e.exports=function(e,t,r){var i,n,a=" ",o=e.level,s=e.dataLevel,c=e.schema[t],u=e.errSchemaPath+"/"+t,l=!e.opts.allErrors,h="data"+(s||""),d="valid"+o;if("#"==c||"#/"==c)e.isRoot?(i=e.async,n="validate"):(i=!0===e.root.schema.$async,n="root.refVal[0]");else{var p=e.resolveRef(e.baseId,c,e.isRoot);if(void 0===p){var f=e.MissingRefError.message(e.baseId,c);if("fail"==e.opts.missingRefs){e.logger.error(f),(v=v||[]).push(a),a="",!1!==e.createErrors?(a+=" { keyword: '$ref' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(u)+" , params: { ref: '"+e.util.escapeQuotes(c)+"' } ",!1!==e.opts.messages&&(a+=" , message: 'can\\'t resolve reference "+e.util.escapeQuotes(c)+"' "),e.opts.verbose&&(a+=" , schema: "+e.util.toQuotedString(c)+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),a+=" } "):a+=" {} ";var m=a;a=v.pop(),!e.compositeRule&&l?e.async?a+=" throw new ValidationError(["+m+"]); ":a+=" validate.errors = ["+m+"]; return false; ":a+=" var err = "+m+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",l&&(a+=" if (false) { ")}else{if("ignore"!=e.opts.missingRefs)throw new e.MissingRefError(e.baseId,c,f);e.logger.warn(f),l&&(a+=" if (true) { ")}}else if(p.inline){var g=e.util.copy(e);g.level++;var _="valid"+g.level;g.schema=p.schema,g.schemaPath="",g.errSchemaPath=c,a+=" "+e.validate(g).replace(/validate\.schema/g,p.code)+" ",l&&(a+=" if ("+_+") { ")}else i=!0===p.$async,n=p.code}if(n){var v;(v=v||[]).push(a),a="",e.opts.passContext?a+=" "+n+".call(this, ":a+=" "+n+"( ",a+=" "+h+", (dataPath || '')",'""'!=e.errorPath&&(a+=" + "+e.errorPath);var y=a+=" , "+(s?"data"+(s-1||""):"parentData")+" , "+(s?e.dataPathArr[s]:"parentDataProperty")+", rootData) ";if(a=v.pop(),i){if(!e.async)throw new Error("async schema referenced by sync schema");l&&(a+=" var "+d+"; "),a+=" try { "+e.yieldAwait+" "+y+"; ",l&&(a+=" "+d+" = true; "),a+=" } catch (e) { if (!(e instanceof ValidationError)) throw e; if (vErrors === null) vErrors = e.errors; else vErrors = vErrors.concat(e.errors); errors = vErrors.length; ",l&&(a+=" "+d+" = false; "),a+=" } ",l&&(a+=" if ("+d+") { ")}else a+=" if (!"+y+") { if (vErrors === null) vErrors = "+n+".errors; else vErrors = vErrors.concat("+n+".errors); errors = vErrors.length; } ",l&&(a+=" else { ")}return a}},function(e,t,r){"use strict";e.exports=function(e,t,r){var i=" ",n=e.schema[t],a=e.schemaPath+e.util.getProperty(t),o=e.errSchemaPath+"/"+t,s=!e.opts.allErrors,c=e.util.copy(e),u="";c.level++;var l="valid"+c.level,h=c.baseId,d=!0,p=n;if(p)for(var f,m=-1,g=p.length-1;m=0)return u&&(i+=" if (true) { "),i;throw new Error('unknown format "'+o+'" is used in schema at path "'+e.errSchemaPath+'"')}var g,_=(g="object"==typeof m&&!(m instanceof RegExp)&&m.validate)&&m.type||"string";if(g){var v=!0===m.async;m=m.validate}if(_!=r)return u&&(i+=" if (true) { "),i;if(v){if(!e.async)throw new Error("async format in sync schema");var y="formats"+e.util.getProperty(o)+".validate";i+=" if (!("+e.yieldAwait+" "+y+"("+l+"))) { "}else{i+=" if (! ";y="formats"+e.util.getProperty(o);g&&(y+=".validate"),i+="function"==typeof m?" "+y+"("+l+") ":" "+y+".test("+l+") ",i+=") { "}}var b=b||[];b.push(i),i="",!1!==e.createErrors?(i+=" { keyword: 'format' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: { format: ",i+=d?""+h:""+e.util.toQuotedString(o),i+=" } ",!1!==e.opts.messages&&(i+=" , message: 'should match format \"",i+=d?"' + "+h+" + '":""+e.util.escapeQuotes(o),i+="\"' "),e.opts.verbose&&(i+=" , schema: ",i+=d?"validate.schema"+s:""+e.util.toQuotedString(o),i+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+l+" "),i+=" } "):i+=" {} ";var E=i;return i=b.pop(),!e.compositeRule&&u?e.async?i+=" throw new ValidationError(["+E+"]); ":i+=" validate.errors = ["+E+"]; return false; ":i+=" var err = "+E+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",i+=" } ",u&&(i+=" else { "),i}},function(e,t,r){"use strict";e.exports=function(e,t,r){var i=" ",n=e.level,a=e.dataLevel,o=e.schema[t],s=e.schemaPath+e.util.getProperty(t),c=e.errSchemaPath+"/"+t,u=!e.opts.allErrors,l="data"+(a||""),h="valid"+n,d="errs__"+n,p=e.util.copy(e),f="";p.level++;var m="valid"+p.level,g="i"+n,_=p.dataLevel=e.dataLevel+1,v="data"+_,y=e.baseId;if(i+="var "+d+" = errors;var "+h+";",Array.isArray(o)){var b=e.schema.additionalItems;if(!1===b){i+=" "+h+" = "+l+".length <= "+o.length+"; ";var E=c;c=e.errSchemaPath+"/additionalItems",i+=" if (!"+h+") { ";var w=w||[];w.push(i),i="",!1!==e.createErrors?(i+=" { keyword: 'additionalItems' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: { limit: "+o.length+" } ",!1!==e.opts.messages&&(i+=" , message: 'should NOT have more than "+o.length+" items' "),e.opts.verbose&&(i+=" , schema: false , parentSchema: validate.schema"+e.schemaPath+" , data: "+l+" "),i+=" } "):i+=" {} ";var S=i;i=w.pop(),!e.compositeRule&&u?e.async?i+=" throw new ValidationError(["+S+"]); ":i+=" validate.errors = ["+S+"]; return false; ":i+=" var err = "+S+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",i+=" } ",c=E,u&&(f+="}",i+=" else { ")}var k=o;if(k)for(var x,M=-1,N=k.length-1;M "+M+") { ";var j=l+"["+M+"]";p.schema=x,p.schemaPath=s+"["+M+"]",p.errSchemaPath=c+"/"+M,p.errorPath=e.util.getPathExpr(e.errorPath,M,e.opts.jsonPointers,!0),p.dataPathArr[_]=M;var T=e.validate(p);p.baseId=y,e.util.varOccurences(T,v)<2?i+=" "+e.util.varReplace(T,v,j)+" ":i+=" var "+v+" = "+j+"; "+T+" ",i+=" } ",u&&(i+=" if ("+m+") { ",f+="}")}if("object"==typeof b&&e.util.schemaHasRules(b,e.RULES.all)){p.schema=b,p.schemaPath=e.schemaPath+".additionalItems",p.errSchemaPath=e.errSchemaPath+"/additionalItems",i+=" "+m+" = true; if ("+l+".length > "+o.length+") { for (var "+g+" = "+o.length+"; "+g+" < "+l+".length; "+g+"++) { ",p.errorPath=e.util.getPathExpr(e.errorPath,g,e.opts.jsonPointers,!0);j=l+"["+g+"]";p.dataPathArr[_]=g;T=e.validate(p);p.baseId=y,e.util.varOccurences(T,v)<2?i+=" "+e.util.varReplace(T,v,j)+" ":i+=" var "+v+" = "+j+"; "+T+" ",u&&(i+=" if (!"+m+") break; "),i+=" } } ",u&&(i+=" if ("+m+") { ",f+="}")}}else if(e.util.schemaHasRules(o,e.RULES.all)){p.schema=o,p.schemaPath=s,p.errSchemaPath=c,i+=" for (var "+g+" = 0; "+g+" < "+l+".length; "+g+"++) { ",p.errorPath=e.util.getPathExpr(e.errorPath,g,e.opts.jsonPointers,!0);j=l+"["+g+"]";p.dataPathArr[_]=g;T=e.validate(p);p.baseId=y,e.util.varOccurences(T,v)<2?i+=" "+e.util.varReplace(T,v,j)+" ":i+=" var "+v+" = "+j+"; "+T+" ",u&&(i+=" if (!"+m+") break; "),i+=" }"}return u&&(i+=" "+f+" if ("+d+" == errors) {"),i=e.util.cleanUpCode(i)}},function(e,t,r){"use strict";e.exports=function(e,t,r){var i,n=" ",a=e.level,o=e.dataLevel,s=e.schema[t],c=e.schemaPath+e.util.getProperty(t),u=e.errSchemaPath+"/"+t,l=!e.opts.allErrors,h="data"+(o||""),d=e.opts.$data&&s&&s.$data;d?(n+=" var schema"+a+" = "+e.util.getData(s.$data,o,e.dataPathArr)+"; ",i="schema"+a):i=s,n+="var division"+a+";if (",d&&(n+=" "+i+" !== undefined && ( typeof "+i+" != 'number' || "),n+=" (division"+a+" = "+h+" / "+i+", ",e.opts.multipleOfPrecision?n+=" Math.abs(Math.round(division"+a+") - division"+a+") > 1e-"+e.opts.multipleOfPrecision+" ":n+=" division"+a+" !== parseInt(division"+a+") ",n+=" ) ",d&&(n+=" ) "),n+=" ) { ";var p=p||[];p.push(n),n="",!1!==e.createErrors?(n+=" { keyword: 'multipleOf' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(u)+" , params: { multipleOf: "+i+" } ",!1!==e.opts.messages&&(n+=" , message: 'should be multiple of ",n+=d?"' + "+i:i+"'"),e.opts.verbose&&(n+=" , schema: ",n+=d?"validate.schema"+c:""+s,n+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),n+=" } "):n+=" {} ";var f=n;return n=p.pop(),!e.compositeRule&&l?e.async?n+=" throw new ValidationError(["+f+"]); ":n+=" validate.errors = ["+f+"]; return false; ":n+=" var err = "+f+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",n+="} ",l&&(n+=" else { "),n}},function(e,t,r){"use strict";e.exports=function(e,t,r){var i=" ",n=e.level,a=e.dataLevel,o=e.schema[t],s=e.schemaPath+e.util.getProperty(t),c=e.errSchemaPath+"/"+t,u=!e.opts.allErrors,l="data"+(a||""),h="errs__"+n,d=e.util.copy(e);d.level++;var p="valid"+d.level;if(e.util.schemaHasRules(o,e.RULES.all)){d.schema=o,d.schemaPath=s,d.errSchemaPath=c,i+=" var "+h+" = errors; ";var f,m=e.compositeRule;e.compositeRule=d.compositeRule=!0,d.createErrors=!1,d.opts.allErrors&&(f=d.opts.allErrors,d.opts.allErrors=!1),i+=" "+e.validate(d)+" ",d.createErrors=!0,f&&(d.opts.allErrors=f),e.compositeRule=d.compositeRule=m,i+=" if ("+p+") { ";var g=g||[];g.push(i),i="",!1!==e.createErrors?(i+=" { keyword: 'not' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: {} ",!1!==e.opts.messages&&(i+=" , message: 'should NOT be valid' "),e.opts.verbose&&(i+=" , schema: validate.schema"+s+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+l+" "),i+=" } "):i+=" {} ";var _=i;i=g.pop(),!e.compositeRule&&u?e.async?i+=" throw new ValidationError(["+_+"]); ":i+=" validate.errors = ["+_+"]; return false; ":i+=" var err = "+_+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",i+=" } else { errors = "+h+"; if (vErrors !== null) { if ("+h+") vErrors.length = "+h+"; else vErrors = null; } ",e.opts.allErrors&&(i+=" } ")}else i+=" var err = ",!1!==e.createErrors?(i+=" { keyword: 'not' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: {} ",!1!==e.opts.messages&&(i+=" , message: 'should NOT be valid' "),e.opts.verbose&&(i+=" , schema: validate.schema"+s+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+l+" "),i+=" } "):i+=" {} ",i+="; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",u&&(i+=" if (false) { ");return i}},function(e,t,r){"use strict";e.exports=function(e,t,r){var i=" ",n=e.level,a=e.dataLevel,o=e.schema[t],s=e.schemaPath+e.util.getProperty(t),c=e.errSchemaPath+"/"+t,u=!e.opts.allErrors,l="data"+(a||""),h="valid"+n,d="errs__"+n,p=e.util.copy(e),f="";p.level++;var m="valid"+p.level;i+="var "+d+" = errors;var prevValid"+n+" = false;var "+h+" = false;";var g=p.baseId,_=e.compositeRule;e.compositeRule=p.compositeRule=!0;var v=o;if(v)for(var y,b=-1,E=v.length-1;b5)i+=" || validate.schema"+s+"["+g+"] ";else{var F=E;if(F)for(var C=-1,B=F.length-1;C= "+ge+"; ",c=e.errSchemaPath+"/patternGroups/minimum",i+=" if (!"+h+") { ",(Ee=Ee||[]).push(i),i="",!1!==e.createErrors?(i+=" { keyword: 'patternGroups' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: { reason: '"+ye+"', limit: "+ve+", pattern: '"+e.util.escapeQuotes(de)+"' } ",!1!==e.opts.messages&&(i+=" , message: 'should NOT have "+be+" than "+ve+' properties matching pattern "'+e.util.escapeQuotes(de)+"\"' "),e.opts.verbose&&(i+=" , schema: validate.schema"+s+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+l+" "),i+=" } "):i+=" {} ";X=i;i=Ee.pop(),!e.compositeRule&&u?e.async?i+=" throw new ValidationError(["+X+"]); ":i+=" validate.errors = ["+X+"]; return false; ":i+=" var err = "+X+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",i+=" } ",void 0!==_e&&(i+=" else ")}if(void 0!==_e){var Ee;ve=_e,ye="maximum",be="more";i+=" "+h+" = pgPropCount"+n+" <= "+_e+"; ",c=e.errSchemaPath+"/patternGroups/maximum",i+=" if (!"+h+") { ",(Ee=Ee||[]).push(i),i="",!1!==e.createErrors?(i+=" { keyword: 'patternGroups' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: { reason: '"+ye+"', limit: "+ve+", pattern: '"+e.util.escapeQuotes(de)+"' } ",!1!==e.opts.messages&&(i+=" , message: 'should NOT have "+be+" than "+ve+' properties matching pattern "'+e.util.escapeQuotes(de)+"\"' "),e.opts.verbose&&(i+=" , schema: validate.schema"+s+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+l+" "),i+=" } "):i+=" {} ";X=i;i=Ee.pop(),!e.compositeRule&&u?e.async?i+=" throw new ValidationError(["+X+"]); ":i+=" validate.errors = ["+X+"]; return false; ":i+=" var err = "+X+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",i+=" } "}c=W,u&&(i+=" if ("+h+") { ",f+="}")}}}}return u&&(i+=" "+f+" if ("+d+" == errors) {"),i=e.util.cleanUpCode(i)}},function(e,t,r){"use strict";e.exports=function(e,t,r){var i=" ",n=e.level,a=e.dataLevel,o=e.schema[t],s=e.schemaPath+e.util.getProperty(t),c=e.errSchemaPath+"/"+t,u=!e.opts.allErrors,l="data"+(a||""),h="errs__"+n,d=e.util.copy(e);d.level++;var p="valid"+d.level;if(e.util.schemaHasRules(o,e.RULES.all)){d.schema=o,d.schemaPath=s,d.errSchemaPath=c;var f="key"+n,m="idx"+n,g="i"+n,_="' + "+f+" + '",v="data"+(d.dataLevel=e.dataLevel+1),y="dataProperties"+n,b=e.opts.ownProperties,E=e.baseId;i+=" var "+h+" = errors; ",b&&(i+=" var "+y+" = undefined; "),i+=b?" "+y+" = "+y+" || Object.keys("+l+"); for (var "+m+"=0; "+m+"<"+y+".length; "+m+"++) { var "+f+" = "+y+"["+m+"]; ":" for (var "+f+" in "+l+") { ",i+=" var startErrs"+n+" = errors; ";var w=f,S=e.compositeRule;e.compositeRule=d.compositeRule=!0;var k=e.validate(d);d.baseId=E,e.util.varOccurences(k,v)<2?i+=" "+e.util.varReplace(k,v,w)+" ":i+=" var "+v+" = "+w+"; "+k+" ",e.compositeRule=d.compositeRule=S,i+=" if (!"+p+") { for (var "+g+"=startErrs"+n+"; "+g+"=e.opts.loopRequired,w=e.opts.ownProperties;if(u)if(i+=" var missing"+n+"; ",E){d||(i+=" var "+p+" = validate.schema"+s+"; ");var S="' + "+(T="schema"+n+"["+(M="i"+n)+"]")+" + '";e.opts._errorDataPathProperty&&(e.errorPath=e.util.getPathExpr(b,T,e.opts.jsonPointers)),i+=" var "+h+" = true; ",d&&(i+=" if (schema"+n+" === undefined) "+h+" = true; else if (!Array.isArray(schema"+n+")) "+h+" = false; else {"),i+=" for (var "+M+" = 0; "+M+" < "+p+".length; "+M+"++) { "+h+" = "+l+"["+p+"["+M+"]] !== undefined ",w&&(i+=" && Object.prototype.hasOwnProperty.call("+l+", "+p+"["+M+"]) "),i+="; if (!"+h+") break; } ",d&&(i+=" } "),i+=" if (!"+h+") { ",(j=j||[]).push(i),i="",!1!==e.createErrors?(i+=" { keyword: 'required' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(c)+" , params: { missingProperty: '"+S+"' } ",!1!==e.opts.messages&&(i+=" , message: '",e.opts._errorDataPathProperty?i+="is a required property":i+="should have required property \\'"+S+"\\'",i+="' "),e.opts.verbose&&(i+=" , schema: validate.schema"+s+" , parentSchema: validate.schema"+e.schemaPath+" , data: "+l+" "),i+=" } "):i+=" {} ";var k=i;i=j.pop(),!e.compositeRule&&u?e.async?i+=" throw new ValidationError(["+k+"]); ":i+=" validate.errors = ["+k+"]; return false; ":i+=" var err = "+k+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",i+=" } else { "}else{i+=" if ( ";var x=f;if(x)for(var M=-1,N=x.length-1;M 1) { var i = "+h+".length, j; outer: for (;i--;) { for (j = i; j--;) { if (equal("+h+"[i], "+h+"[j])) { "+d+" = false; break outer; } } } } ",p&&(n+=" } "),n+=" if (!"+d+") { ";var f=f||[];f.push(n),n="",!1!==e.createErrors?(n+=" { keyword: 'uniqueItems' , dataPath: (dataPath || '') + "+e.errorPath+" , schemaPath: "+e.util.toQuotedString(u)+" , params: { i: i, j: j } ",!1!==e.opts.messages&&(n+=" , message: 'should NOT have duplicate items (items ## ' + j + ' and ' + i + ' are identical)' "),e.opts.verbose&&(n+=" , schema: ",n+=p?"validate.schema"+c:""+s,n+=" , parentSchema: validate.schema"+e.schemaPath+" , data: "+h+" "),n+=" } "):n+=" {} ";var m=n;n=f.pop(),!e.compositeRule&&l?e.async?n+=" throw new ValidationError(["+m+"]); ":n+=" validate.errors = ["+m+"]; return false; ":n+=" var err = "+m+"; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ",n+=" } ",l&&(n+=" else { ")}else l&&(n+=" if (true) { ");return n}},function(e,t,r){"use strict";var i=["multipleOf","maximum","exclusiveMaximum","minimum","exclusiveMinimum","maxLength","minLength","pattern","additionalItems","maxItems","minItems","uniqueItems","maxProperties","minProperties","required","additionalProperties","enum","format","const"];e.exports=function(e,t){for(var r=0;r>>((3&t)<<3)&255;return n}}},function(e,t){for(var r=[],i=0;i<256;++i)r[i]=(i+256).toString(16).substr(1);e.exports=function(e,t){var i=t||0,n=r;return[n[e[i++]],n[e[i++]],n[e[i++]],n[e[i++]],"-",n[e[i++]],n[e[i++]],"-",n[e[i++]],n[e[i++]],"-",n[e[i++]],n[e[i++]],"-",n[e[i++]],n[e[i++]],n[e[i++]],n[e[i++]],n[e[i++]],n[e[i++]]].join("")}},function(e,t,r){"use strict";var i=r(25),n=r(234),a=r(131),o=r(135),s=r(507),c=r(10),u=r(1).Buffer;function l(e){this.request=e,this.params=null}l.prototype.buildParams=function(e,t,r,i,n,a){var c={};for(var u in e)c["oauth_"+u]=e[u];c.oauth_version||(c.oauth_version="1.0"),c.oauth_timestamp||(c.oauth_timestamp=Math.floor(Date.now()/1e3).toString()),c.oauth_nonce||(c.oauth_nonce=o().replace(/-/g,"")),c.oauth_signature_method||(c.oauth_signature_method="HMAC-SHA1");var l=c.oauth_consumer_secret||c.oauth_private_key;delete c.oauth_consumer_secret,delete c.oauth_private_key;var h=c.oauth_token_secret;delete c.oauth_token_secret;var d=c.oauth_realm;delete c.oauth_realm,delete c.oauth_transport_method;var p=t.protocol+"//"+t.host+t.pathname,f=a.parse([].concat(i,n,a.stringify(c)).join("&"));return c.oauth_signature=s.sign(c.oauth_signature_method,r,p,f,l,h),d&&(c.realm=d),c},l.prototype.buildBodyHash=function(e,t){["HMAC-SHA1","RSA-SHA1"].indexOf(e.signature_method||"HMAC-SHA1")<0&&this.request.emit("error",new Error("oauth: "+e.signature_method+" signature_method not supported with body_hash signing."));var r=c.createHash("sha1");r.update(t||"");var i=r.digest("hex");return u.from(i,"hex").toString("base64")},l.prototype.concatParams=function(e,t,r){r=r||"";var i=Object.keys(e).filter((function(e){return"realm"!==e&&"oauth_signature"!==e})).sort();return e.realm&&i.splice(0,0,"realm"),i.push("oauth_signature"),i.map((function(t){return t+"="+r+s.rfc3986(e[t])+r})).join(t)},l.prototype.onRequest=function(e){this.params=e;var t,r,o=this.request.uri||{},s=this.request.method||"",c=a(this.request.headers),u=this.request.body||"",l=this.request.qsLib||n,h=c.get("content-type")||"",d="application/x-www-form-urlencoded",p=e.transport_method||"header";h.slice(0,d.length)===d&&(h=d,t=u),o.query&&(r=o.query),"body"!==p||"POST"===s&&h===d||this.request.emit("error",new Error("oauth: transport_method of body requires POST and content-type "+d)),t||"boolean"!=typeof e.body_hash||(e.body_hash=this.buildBodyHash(e,this.request.body.toString()));var f=this.buildParams(e,o,s,r,t,l);switch(p){case"header":this.request.setHeader("Authorization","OAuth "+this.concatParams(f,",",'"'));break;case"query":var m=this.request.uri.href+=(r?"&":"?")+this.concatParams(f,"&");this.request.uri=i.parse(m),this.request.path=this.request.uri.path;break;case"body":this.request.body=(t?t+"&":"")+this.concatParams(f,"&");break;default:this.request.emit("error",new Error("oauth: transport_method invalid"))}},t.OAuth=l},function(e,t,r){var i=r(10);function n(e,t,r){return i.createHmac(r,e).update(t).digest("base64")}function a(e){return encodeURIComponent(e).replace(/!/g,"%21").replace(/\*/g,"%2A").replace(/\(/g,"%28").replace(/\)/g,"%29").replace(/'/g,"%27")}function o(e,t){return e>t?1:e=300&&e.statusCode<400&&e.caseless.has("location")){var i=e.caseless.get("location");if(t.debug("redirect",i),this.followAllRedirects)r=i;else if(this.followRedirects)switch(t.method){case"PATCH":case"PUT":case"POST":case"DELETE":break;default:r=i}}else if(401===e.statusCode){var n=t._auth.onResponse(e);n&&(t.setHeader("authorization",n),r=t.uri)}return r},a.prototype.onResponse=function(e){var t=this.request,r=this.redirectTo(e);if(!r||!this.allowRedirect.call(t,e))return!1;if(t.debug("redirect to",r),e.resume&&e.resume(),this.redirectsFollowed>=this.maxRedirects)return t.emit("error",new Error("Exceeded maxRedirects. Probably stuck in a redirect loop "+t.uri.href)),!1;this.redirectsFollowed+=1,n.test(r)||(r=i.resolve(t.uri.href,r));var a=t.uri;return t.uri=i.parse(r),t.uri.protocol!==a.protocol&&delete t.agent,this.redirects.push({statusCode:e.statusCode,redirectUri:r}),this.followAllRedirects&&"HEAD"!==t.method&&401!==e.statusCode&&307!==e.statusCode&&(t.method=this.followOriginalHttpMethod?t.method:"GET"),delete t.src,delete t.req,delete t._started,401!==e.statusCode&&307!==e.statusCode&&(delete t.body,delete t._form,t.headers&&(t.removeHeader("host"),t.removeHeader("content-type"),t.removeHeader("content-length"),t.uri.hostname!==t.originalHost.split(":")[0]&&t.removeHeader("authorization"))),this.removeRefererHeader||t.setHeader("referer",a.href),t.emit("redirect"),t.init(),!0},t.Redirect=a},function(e,t,r){"use strict";var i=r(25),n=r(515),a=["accept","accept-charset","accept-encoding","accept-language","accept-ranges","cache-control","content-encoding","content-language","content-location","content-md5","content-range","content-type","connection","date","expect","max-forwards","pragma","referer","te","user-agent","via"],o=["proxy-authorization"];function s(e){this.request=e,this.proxyHeaderWhiteList=a,this.proxyHeaderExclusiveList=[],void 0!==e.tunnel&&(this.tunnelOverride=e.tunnel)}s.prototype.isEnabled=function(){var e=this.request;return void 0!==this.tunnelOverride?this.tunnelOverride:"https:"===e.uri.protocol},s.prototype.setup=function(e){var t=this.request;if(e=e||{},"string"==typeof t.proxy&&(t.proxy=i.parse(t.proxy)),!t.proxy||!t.tunnel)return!1;e.proxyHeaderWhiteList&&(this.proxyHeaderWhiteList=e.proxyHeaderWhiteList),e.proxyHeaderExclusiveList&&(this.proxyHeaderExclusiveList=e.proxyHeaderExclusiveList);var r,a,s,c,u=this.proxyHeaderExclusiveList.concat(o),l=this.proxyHeaderWhiteList.concat(u),h=function(e,t){var r=t.reduce((function(e,t){return e[t.toLowerCase()]=!0,e}),{});return Object.keys(e).filter((function(e){return r[e.toLowerCase()]})).reduce((function(t,r){return t[r]=e[r],t}),{})}(t.headers,l);h.host=(r=t.uri,a=r.port,s=r.protocol,c=r.hostname+":",c+=a||("https:"===s?"443":"80")),u.forEach(t.removeHeader,t);var d=function(e){var t=function(e,t){return["https:"===e.protocol?"https":"http","https:"===t.protocol?"Https":"Http"].join("Over")}(e.uri,e.proxy);return n[t]}(t),p=function(e,t){var r=e.proxy;return{proxy:{host:r.hostname,port:+r.port,proxyAuth:r.auth,headers:t},headers:e.headers,ca:e.ca,cert:e.cert,key:e.key,passphrase:e.passphrase,pfx:e.pfx,ciphers:e.ciphers,rejectUnauthorized:e.rejectUnauthorized,secureOptions:e.secureOptions,secureProtocol:e.secureProtocol}}(t,h);return t.agent=d(p),!0},s.defaultProxyHeaderWhiteList=a,s.defaultProxyHeaderExclusiveList=o,t.Tunnel=s},function(e,t,r){"use strict";(function(e){r(83);var i,n=r(232),a=r(52),o=r(85),s=r(23),c=r(4),u=r(11),l=r(1).Buffer;function h(e){var t=this;t.options=e||{},t.proxyOptions=t.options.proxy||{},t.maxSockets=t.options.maxSockets||a.Agent.defaultMaxSockets,t.requests=[],t.sockets=[],t.on("free",(function(e,r,i){for(var n=0,a=t.requests.length;n=this.maxSockets?r.requests.push({host:t.host,port:t.port,request:e}):r.createConnection({host:t.host,port:t.port,request:e})},h.prototype.createConnection=function(e){var t=this;t.createSocket(e,(function(r){function i(){t.emit("free",r,e.host,e.port)}function n(e){t.removeSocket(r),r.removeListener("free",i),r.removeListener("close",n),r.removeListener("agentRemove",n)}r.on("free",i),r.on("close",n),r.on("agentRemove",n),e.request.onSocket(r)}))},h.prototype.createSocket=function(t,r){var n=this,a={};n.sockets.push(a);var o=p({},n.proxyOptions,{method:"CONNECT",path:t.host+":"+t.port,agent:!1});o.proxyAuth&&(o.headers=o.headers||{},o.headers["Proxy-Authorization"]="Basic "+l.from(o.proxyAuth).toString("base64")),i("making CONNECT request");var s=n.request(o);function u(e,o,u){if(s.removeAllListeners(),o.removeAllListeners(),200===e.statusCode)c.equal(u.length,0),i("tunneling connection has established"),n.sockets[n.sockets.indexOf(a)]=o,r(o);else{i("tunneling socket could not be established, statusCode=%d",e.statusCode);var l=new Error("tunneling socket could not be established, statusCode="+e.statusCode);l.code="ECONNRESET",t.request.emit("error",l),n.removeSocket(a)}}s.useChunkedEncodingByDefault=!1,s.once("response",(function(e){e.upgrade=!0})),s.once("upgrade",(function(t,r,i){e.nextTick((function(){u(t,r,i)}))})),s.once("connect",u),s.once("error",(function(e){s.removeAllListeners(),i("tunneling socket could not be established, cause=%s\n",e.message,e.stack);var r=new Error("tunneling socket could not be established, cause="+e.message);r.code="ECONNRESET",t.request.emit("error",r),n.removeSocket(a)})),s.end()},h.prototype.removeSocket=function(e){var t=this.sockets.indexOf(e);if(-1!==t){this.sockets.splice(t,1);var r=this.requests.shift();r&&this.createConnection(r)}},i=e.env.NODE_DEBUG&&/\btunnel\b/.test(e.env.NODE_DEBUG)?function(){var e=Array.prototype.slice.call(arguments);"string"==typeof e[0]?e[0]="TUNNEL: "+e[0]:e.unshift("TUNNEL:"),console.error.apply(console,e)}:function(){},t.debug=i}).call(this,r(3))},function(e,t,r){(function(t){(function(){var r,i,n,a,o,s;"undefined"!=typeof performance&&null!==performance&&performance.now?e.exports=function(){return performance.now()}:null!=t&&t.hrtime?(e.exports=function(){return(r()-o)/1e6},i=t.hrtime,a=(r=function(){var e;return 1e9*(e=i())[0]+e[1]})(),s=1e9*t.uptime(),o=a-s):Date.now?(e.exports=function(){return Date.now()-n},n=Date.now()):(e.exports=function(){return(new Date).getTime()-n},n=(new Date).getTime())}).call(this)}).call(this,r(3))},function(e,t){t.endianness=function(){return"LE"},t.hostname=function(){return"undefined"!=typeof location?location.hostname:""},t.loadavg=function(){return[]},t.uptime=function(){return 0},t.freemem=function(){return Number.MAX_VALUE},t.totalmem=function(){return Number.MAX_VALUE},t.cpus=function(){return[]},t.type=function(){return"Browser"},t.release=function(){return"undefined"!=typeof navigator?navigator.appVersion:""},t.networkInterfaces=t.getNetworkInterfaces=function(){return{}},t.arch=function(){return"javascript"},t.platform=function(){return"browser"},t.tmpdir=t.tmpDir=function(){return"/tmp"},t.EOL="\n",t.homedir=function(){return"/"}},function(e,t,r){var i;e.exports=(i=r(5),r(90),r(519),r(520),r(55),r(56),r(136),r(246),r(521),r(247),r(522),r(523),r(524),r(137),r(525),r(41),r(15),r(526),r(527),r(528),r(529),r(530),r(531),r(532),r(533),r(534),r(535),r(536),r(537),r(538),r(539),r(540),r(541),i)},function(e,t,r){var i;e.exports=(i=r(5),function(){if("function"==typeof ArrayBuffer){var e=i.lib.WordArray,t=e.init;(e.init=function(e){if(e instanceof ArrayBuffer&&(e=new Uint8Array(e)),(e instanceof Int8Array||"undefined"!=typeof Uint8ClampedArray&&e instanceof Uint8ClampedArray||e instanceof Int16Array||e instanceof Uint16Array||e instanceof Int32Array||e instanceof Uint32Array||e instanceof Float32Array||e instanceof Float64Array)&&(e=new Uint8Array(e.buffer,e.byteOffset,e.byteLength)),e instanceof Uint8Array){for(var r=e.byteLength,i=[],n=0;n>>2]|=e[n]<<24-n%4*8;t.call(this,i,r)}else t.apply(this,arguments)}).prototype=e}}(),i.lib.WordArray)},function(e,t,r){var i;e.exports=(i=r(5),function(){var e=i,t=e.lib.WordArray,r=e.enc;function n(e){return e<<8&4278255360|e>>>8&16711935}r.Utf16=r.Utf16BE={stringify:function(e){for(var t=e.words,r=e.sigBytes,i=[],n=0;n>>2]>>>16-n%4*8&65535;i.push(String.fromCharCode(a))}return i.join("")},parse:function(e){for(var r=e.length,i=[],n=0;n>>1]|=e.charCodeAt(n)<<16-n%2*16;return t.create(i,2*r)}},r.Utf16LE={stringify:function(e){for(var t=e.words,r=e.sigBytes,i=[],a=0;a>>2]>>>16-a%4*8&65535);i.push(String.fromCharCode(o))}return i.join("")},parse:function(e){for(var r=e.length,i=[],a=0;a>>1]|=n(e.charCodeAt(a)<<16-a%2*16);return t.create(i,2*r)}}}(),i.enc.Utf16)},function(e,t,r){var i,n,a,o,s,c;e.exports=(c=r(5),r(246),n=(i=c).lib.WordArray,a=i.algo,o=a.SHA256,s=a.SHA224=o.extend({_doReset:function(){this._hash=new n.init([3238371032,914150663,812702999,4144912697,4290775857,1750603025,1694076839,3204075428])},_doFinalize:function(){var e=o._doFinalize.call(this);return e.sigBytes-=4,e}}),i.SHA224=o._createHelper(s),i.HmacSHA224=o._createHmacHelper(s),c.SHA224)},function(e,t,r){var i,n,a,o,s,c,u,l;e.exports=(l=r(5),r(90),r(247),n=(i=l).x64,a=n.Word,o=n.WordArray,s=i.algo,c=s.SHA512,u=s.SHA384=c.extend({_doReset:function(){this._hash=new o.init([new a.init(3418070365,3238371032),new a.init(1654270250,914150663),new a.init(2438529370,812702999),new a.init(355462360,4144912697),new a.init(1731405415,4290775857),new a.init(2394180231,1750603025),new a.init(3675008525,1694076839),new a.init(1203062813,3204075428)])},_doFinalize:function(){var e=c._doFinalize.call(this);return e.sigBytes-=16,e}}),i.SHA384=c._createHelper(u),i.HmacSHA384=c._createHmacHelper(u),l.SHA384)},function(e,t,r){var i;e.exports=(i=r(5),r(90),function(e){var t=i,r=t.lib,n=r.WordArray,a=r.Hasher,o=t.x64.Word,s=t.algo,c=[],u=[],l=[];!function(){for(var e=1,t=0,r=0;r<24;r++){c[e+5*t]=(r+1)*(r+2)/2%64;var i=(2*e+3*t)%5;e=t%5,t=i}for(e=0;e<5;e++)for(t=0;t<5;t++)u[e+5*t]=t+(2*e+3*t)%5*5;for(var n=1,a=0;a<24;a++){for(var s=0,h=0,d=0;d<7;d++){if(1&n){var p=(1<>>24)|4278255360&(a<<24|a>>>8),o=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),(j=r[n]).high^=o,j.low^=a}for(var s=0;s<24;s++){for(var d=0;d<5;d++){for(var p=0,f=0,m=0;m<5;m++)p^=(j=r[d+5*m]).high,f^=j.low;var g=h[d];g.high=p,g.low=f}for(d=0;d<5;d++){var _=h[(d+4)%5],v=h[(d+1)%5],y=v.high,b=v.low;for(p=_.high^(y<<1|b>>>31),f=_.low^(b<<1|y>>>31),m=0;m<5;m++)(j=r[d+5*m]).high^=p,j.low^=f}for(var E=1;E<25;E++){var w=(j=r[E]).high,S=j.low,k=c[E];k<32?(p=w<>>32-k,f=S<>>32-k):(p=S<>>64-k,f=w<>>64-k);var x=h[u[E]];x.high=p,x.low=f}var M=h[0],N=r[0];for(M.high=N.high,M.low=N.low,d=0;d<5;d++)for(m=0;m<5;m++){var j=r[E=d+5*m],T=h[E],R=h[(d+1)%5+5*m],I=h[(d+2)%5+5*m];j.high=T.high^~R.high&I.high,j.low=T.low^~R.low&I.low}j=r[0];var O=l[s];j.high^=O.high,j.low^=O.low}},_doFinalize:function(){var t=this._data,r=t.words,i=(this._nDataBytes,8*t.sigBytes),a=32*this.blockSize;r[i>>>5]|=1<<24-i%32,r[(e.ceil((i+1)/a)*a>>>5)-1]|=128,t.sigBytes=4*r.length,this._process();for(var o=this._state,s=this.cfg.outputLength/8,c=s/8,u=[],l=0;l>>24)|4278255360&(d<<24|d>>>8),p=16711935&(p<<8|p>>>24)|4278255360&(p<<24|p>>>8),u.push(p),u.push(d)}return new n.init(u,s)},clone:function(){for(var e=a.clone.call(this),t=e._state=this._state.slice(0),r=0;r<25;r++)t[r]=t[r].clone();return e}});t.SHA3=a._createHelper(d),t.HmacSHA3=a._createHmacHelper(d)}(Math),i.SHA3)},function(e,t,r){var i;e.exports=(i=r(5), -/** @preserve - (c) 2012 by Cédric Mesnil. All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -function(e){var t=i,r=t.lib,n=r.WordArray,a=r.Hasher,o=t.algo,s=n.create([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13]),c=n.create([5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11]),u=n.create([11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6]),l=n.create([8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]),h=n.create([0,1518500249,1859775393,2400959708,2840853838]),d=n.create([1352829926,1548603684,1836072691,2053994217,0]),p=o.RIPEMD160=a.extend({_doReset:function(){this._hash=n.create([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(e,t){for(var r=0;r<16;r++){var i=t+r,n=e[i];e[i]=16711935&(n<<8|n>>>24)|4278255360&(n<<24|n>>>8)}var a,o,p,b,E,w,S,k,x,M,N,j=this._hash.words,T=h.words,R=d.words,I=s.words,O=c.words,A=u.words,P=l.words;for(w=a=j[0],S=o=j[1],k=p=j[2],x=b=j[3],M=E=j[4],r=0;r<80;r+=1)N=a+e[t+I[r]]|0,N+=r<16?f(o,p,b)+T[0]:r<32?m(o,p,b)+T[1]:r<48?g(o,p,b)+T[2]:r<64?_(o,p,b)+T[3]:v(o,p,b)+T[4],N=(N=y(N|=0,A[r]))+E|0,a=E,E=b,b=y(p,10),p=o,o=N,N=w+e[t+O[r]]|0,N+=r<16?v(S,k,x)+R[0]:r<32?_(S,k,x)+R[1]:r<48?g(S,k,x)+R[2]:r<64?m(S,k,x)+R[3]:f(S,k,x)+R[4],N=(N=y(N|=0,P[r]))+M|0,w=M,M=x,x=y(k,10),k=S,S=N;N=j[1]+p+x|0,j[1]=j[2]+b+M|0,j[2]=j[3]+E+w|0,j[3]=j[4]+a+S|0,j[4]=j[0]+o+k|0,j[0]=N},_doFinalize:function(){var e=this._data,t=e.words,r=8*this._nDataBytes,i=8*e.sigBytes;t[i>>>5]|=128<<24-i%32,t[14+(i+64>>>9<<4)]=16711935&(r<<8|r>>>24)|4278255360&(r<<24|r>>>8),e.sigBytes=4*(t.length+1),this._process();for(var n=this._hash,a=n.words,o=0;o<5;o++){var s=a[o];a[o]=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8)}return n},clone:function(){var e=a.clone.call(this);return e._hash=this._hash.clone(),e}});function f(e,t,r){return e^t^r}function m(e,t,r){return e&t|~e&r}function g(e,t,r){return(e|~t)^r}function _(e,t,r){return e&r|t&~r}function v(e,t,r){return e^(t|~r)}function y(e,t){return e<>>32-t}t.RIPEMD160=a._createHelper(p),t.HmacRIPEMD160=a._createHmacHelper(p)}(Math),i.RIPEMD160)},function(e,t,r){var i,n,a,o,s,c,u,l,h;e.exports=(h=r(5),r(136),r(137),n=(i=h).lib,a=n.Base,o=n.WordArray,s=i.algo,c=s.SHA1,u=s.HMAC,l=s.PBKDF2=a.extend({cfg:a.extend({keySize:4,hasher:c,iterations:1}),init:function(e){this.cfg=this.cfg.extend(e)},compute:function(e,t){for(var r=this.cfg,i=u.create(r.hasher,e),n=o.create(),a=o.create([1]),s=n.words,c=a.words,l=r.keySize,h=r.iterations;s.length>24&255)){var t=e>>16&255,r=e>>8&255,i=255&e;255===t?(t=0,255===r?(r=0,255===i?i=0:++i):++r):++t,e=0,e+=t<<16,e+=r<<8,e+=i}else e+=1<<24;return e}var r=e.Encryptor=e.extend({processBlock:function(e,r){var i=this._cipher,n=i.blockSize,a=this._iv,o=this._counter;a&&(o=this._counter=a.slice(0),this._iv=void 0),function(e){0===(e[0]=t(e[0]))&&(e[1]=t(e[1]))}(o);var s=o.slice(0);i.encryptBlock(s,0);for(var c=0;c>>2]|=n<<24-a%4*8,e.sigBytes+=n},unpad:function(e){var t=255&e.words[e.sigBytes-1>>>2];e.sigBytes-=t}},i.pad.Ansix923)},function(e,t,r){var i;e.exports=(i=r(5),r(15),i.pad.Iso10126={pad:function(e,t){var r=4*t,n=r-e.sigBytes%r;e.concat(i.lib.WordArray.random(n-1)).concat(i.lib.WordArray.create([n<<24],1))},unpad:function(e){var t=255&e.words[e.sigBytes-1>>>2];e.sigBytes-=t}},i.pad.Iso10126)},function(e,t,r){var i;e.exports=(i=r(5),r(15),i.pad.Iso97971={pad:function(e,t){e.concat(i.lib.WordArray.create([2147483648],1)),i.pad.ZeroPadding.pad(e,t)},unpad:function(e){i.pad.ZeroPadding.unpad(e),e.sigBytes--}},i.pad.Iso97971)},function(e,t,r){var i;e.exports=(i=r(5),r(15),i.pad.ZeroPadding={pad:function(e,t){var r=4*t;e.clamp(),e.sigBytes+=r-(e.sigBytes%r||r)},unpad:function(e){var t=e.words,r=e.sigBytes-1;for(r=e.sigBytes-1;r>=0;r--)if(t[r>>>2]>>>24-r%4*8&255){e.sigBytes=r+1;break}}},i.pad.ZeroPadding)},function(e,t,r){var i;e.exports=(i=r(5),r(15),i.pad.NoPadding={pad:function(){},unpad:function(){}},i.pad.NoPadding)},function(e,t,r){var i,n,a,o;e.exports=(o=r(5),r(15),n=(i=o).lib.CipherParams,a=i.enc.Hex,i.format.Hex={stringify:function(e){return e.ciphertext.toString(a)},parse:function(e){var t=a.parse(e);return n.create({ciphertext:t})}},o.format.Hex)},function(e,t,r){var i;e.exports=(i=r(5),r(55),r(56),r(41),r(15),function(){var e=i,t=e.lib.BlockCipher,r=e.algo,n=[],a=[],o=[],s=[],c=[],u=[],l=[],h=[],d=[],p=[];!function(){for(var e=[],t=0;t<256;t++)e[t]=t<128?t<<1:t<<1^283;var r=0,i=0;for(t=0;t<256;t++){var f=i^i<<1^i<<2^i<<3^i<<4;f=f>>>8^255&f^99,n[r]=f,a[f]=r;var m=e[r],g=e[m],_=e[g],v=257*e[f]^16843008*f;o[r]=v<<24|v>>>8,s[r]=v<<16|v>>>16,c[r]=v<<8|v>>>24,u[r]=v,v=16843009*_^65537*g^257*m^16843008*r,l[f]=v<<24|v>>>8,h[f]=v<<16|v>>>16,d[f]=v<<8|v>>>24,p[f]=v,r?(r=m^e[e[e[_^m]]],i^=e[e[i]]):r=i=1}}();var f=[0,1,2,4,8,16,32,64,128,27,54],m=r.AES=t.extend({_doReset:function(){if(!this._nRounds||this._keyPriorReset!==this._key){for(var e=this._keyPriorReset=this._key,t=e.words,r=e.sigBytes/4,i=4*((this._nRounds=r+6)+1),a=this._keySchedule=[],o=0;o6&&o%r==4&&(u=n[u>>>24]<<24|n[u>>>16&255]<<16|n[u>>>8&255]<<8|n[255&u]):(u=n[(u=u<<8|u>>>24)>>>24]<<24|n[u>>>16&255]<<16|n[u>>>8&255]<<8|n[255&u],u^=f[o/r|0]<<24),a[o]=a[o-r]^u);for(var s=this._invKeySchedule=[],c=0;c>>24]]^h[n[u>>>16&255]]^d[n[u>>>8&255]]^p[n[255&u]]}}},encryptBlock:function(e,t){this._doCryptBlock(e,t,this._keySchedule,o,s,c,u,n)},decryptBlock:function(e,t){var r=e[t+1];e[t+1]=e[t+3],e[t+3]=r,this._doCryptBlock(e,t,this._invKeySchedule,l,h,d,p,a),r=e[t+1],e[t+1]=e[t+3],e[t+3]=r},_doCryptBlock:function(e,t,r,i,n,a,o,s){for(var c=this._nRounds,u=e[t]^r[0],l=e[t+1]^r[1],h=e[t+2]^r[2],d=e[t+3]^r[3],p=4,f=1;f>>24]^n[l>>>16&255]^a[h>>>8&255]^o[255&d]^r[p++],g=i[l>>>24]^n[h>>>16&255]^a[d>>>8&255]^o[255&u]^r[p++],_=i[h>>>24]^n[d>>>16&255]^a[u>>>8&255]^o[255&l]^r[p++],v=i[d>>>24]^n[u>>>16&255]^a[l>>>8&255]^o[255&h]^r[p++];u=m,l=g,h=_,d=v}m=(s[u>>>24]<<24|s[l>>>16&255]<<16|s[h>>>8&255]<<8|s[255&d])^r[p++],g=(s[l>>>24]<<24|s[h>>>16&255]<<16|s[d>>>8&255]<<8|s[255&u])^r[p++],_=(s[h>>>24]<<24|s[d>>>16&255]<<16|s[u>>>8&255]<<8|s[255&l])^r[p++],v=(s[d>>>24]<<24|s[u>>>16&255]<<16|s[l>>>8&255]<<8|s[255&h])^r[p++],e[t]=m,e[t+1]=g,e[t+2]=_,e[t+3]=v},keySize:8});e.AES=t._createHelper(m)}(),i.AES)},function(e,t,r){var i;e.exports=(i=r(5),r(55),r(56),r(41),r(15),function(){var e=i,t=e.lib,r=t.WordArray,n=t.BlockCipher,a=e.algo,o=[57,49,41,33,25,17,9,1,58,50,42,34,26,18,10,2,59,51,43,35,27,19,11,3,60,52,44,36,63,55,47,39,31,23,15,7,62,54,46,38,30,22,14,6,61,53,45,37,29,21,13,5,28,20,12,4],s=[14,17,11,24,1,5,3,28,15,6,21,10,23,19,12,4,26,8,16,7,27,20,13,2,41,52,31,37,47,55,30,40,51,45,33,48,44,49,39,56,34,53,46,42,50,36,29,32],c=[1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28],u=[{0:8421888,268435456:32768,536870912:8421378,805306368:2,1073741824:512,1342177280:8421890,1610612736:8389122,1879048192:8388608,2147483648:514,2415919104:8389120,2684354560:33280,2952790016:8421376,3221225472:32770,3489660928:8388610,3758096384:0,4026531840:33282,134217728:0,402653184:8421890,671088640:33282,939524096:32768,1207959552:8421888,1476395008:512,1744830464:8421378,2013265920:2,2281701376:8389120,2550136832:33280,2818572288:8421376,3087007744:8389122,3355443200:8388610,3623878656:32770,3892314112:514,4160749568:8388608,1:32768,268435457:2,536870913:8421888,805306369:8388608,1073741825:8421378,1342177281:33280,1610612737:512,1879048193:8389122,2147483649:8421890,2415919105:8421376,2684354561:8388610,2952790017:33282,3221225473:514,3489660929:8389120,3758096385:32770,4026531841:0,134217729:8421890,402653185:8421376,671088641:8388608,939524097:512,1207959553:32768,1476395009:8388610,1744830465:2,2013265921:33282,2281701377:32770,2550136833:8389122,2818572289:514,3087007745:8421888,3355443201:8389120,3623878657:0,3892314113:33280,4160749569:8421378},{0:1074282512,16777216:16384,33554432:524288,50331648:1074266128,67108864:1073741840,83886080:1074282496,100663296:1073758208,117440512:16,134217728:540672,150994944:1073758224,167772160:1073741824,184549376:540688,201326592:524304,218103808:0,234881024:16400,251658240:1074266112,8388608:1073758208,25165824:540688,41943040:16,58720256:1073758224,75497472:1074282512,92274688:1073741824,109051904:524288,125829120:1074266128,142606336:524304,159383552:0,176160768:16384,192937984:1074266112,209715200:1073741840,226492416:540672,243269632:1074282496,260046848:16400,268435456:0,285212672:1074266128,301989888:1073758224,318767104:1074282496,335544320:1074266112,352321536:16,369098752:540688,385875968:16384,402653184:16400,419430400:524288,436207616:524304,452984832:1073741840,469762048:540672,486539264:1073758208,503316480:1073741824,520093696:1074282512,276824064:540688,293601280:524288,310378496:1074266112,327155712:16384,343932928:1073758208,360710144:1074282512,377487360:16,394264576:1073741824,411041792:1074282496,427819008:1073741840,444596224:1073758224,461373440:524304,478150656:0,494927872:16400,511705088:1074266128,528482304:540672},{0:260,1048576:0,2097152:67109120,3145728:65796,4194304:65540,5242880:67108868,6291456:67174660,7340032:67174400,8388608:67108864,9437184:67174656,10485760:65792,11534336:67174404,12582912:67109124,13631488:65536,14680064:4,15728640:256,524288:67174656,1572864:67174404,2621440:0,3670016:67109120,4718592:67108868,5767168:65536,6815744:65540,7864320:260,8912896:4,9961472:256,11010048:67174400,12058624:65796,13107200:65792,14155776:67109124,15204352:67174660,16252928:67108864,16777216:67174656,17825792:65540,18874368:65536,19922944:67109120,20971520:256,22020096:67174660,23068672:67108868,24117248:0,25165824:67109124,26214400:67108864,27262976:4,28311552:65792,29360128:67174400,30408704:260,31457280:65796,32505856:67174404,17301504:67108864,18350080:260,19398656:67174656,20447232:0,21495808:65540,22544384:67109120,23592960:256,24641536:67174404,25690112:65536,26738688:67174660,27787264:65796,28835840:67108868,29884416:67109124,30932992:67174400,31981568:4,33030144:65792},{0:2151682048,65536:2147487808,131072:4198464,196608:2151677952,262144:0,327680:4198400,393216:2147483712,458752:4194368,524288:2147483648,589824:4194304,655360:64,720896:2147487744,786432:2151678016,851968:4160,917504:4096,983040:2151682112,32768:2147487808,98304:64,163840:2151678016,229376:2147487744,294912:4198400,360448:2151682112,425984:0,491520:2151677952,557056:4096,622592:2151682048,688128:4194304,753664:4160,819200:2147483648,884736:4194368,950272:4198464,1015808:2147483712,1048576:4194368,1114112:4198400,1179648:2147483712,1245184:0,1310720:4160,1376256:2151678016,1441792:2151682048,1507328:2147487808,1572864:2151682112,1638400:2147483648,1703936:2151677952,1769472:4198464,1835008:2147487744,1900544:4194304,1966080:64,2031616:4096,1081344:2151677952,1146880:2151682112,1212416:0,1277952:4198400,1343488:4194368,1409024:2147483648,1474560:2147487808,1540096:64,1605632:2147483712,1671168:4096,1736704:2147487744,1802240:2151678016,1867776:4160,1933312:2151682048,1998848:4194304,2064384:4198464},{0:128,4096:17039360,8192:262144,12288:536870912,16384:537133184,20480:16777344,24576:553648256,28672:262272,32768:16777216,36864:537133056,40960:536871040,45056:553910400,49152:553910272,53248:0,57344:17039488,61440:553648128,2048:17039488,6144:553648256,10240:128,14336:17039360,18432:262144,22528:537133184,26624:553910272,30720:536870912,34816:537133056,38912:0,43008:553910400,47104:16777344,51200:536871040,55296:553648128,59392:16777216,63488:262272,65536:262144,69632:128,73728:536870912,77824:553648256,81920:16777344,86016:553910272,90112:537133184,94208:16777216,98304:553910400,102400:553648128,106496:17039360,110592:537133056,114688:262272,118784:536871040,122880:0,126976:17039488,67584:553648256,71680:16777216,75776:17039360,79872:537133184,83968:536870912,88064:17039488,92160:128,96256:553910272,100352:262272,104448:553910400,108544:0,112640:553648128,116736:16777344,120832:262144,124928:537133056,129024:536871040},{0:268435464,256:8192,512:270532608,768:270540808,1024:268443648,1280:2097152,1536:2097160,1792:268435456,2048:0,2304:268443656,2560:2105344,2816:8,3072:270532616,3328:2105352,3584:8200,3840:270540800,128:270532608,384:270540808,640:8,896:2097152,1152:2105352,1408:268435464,1664:268443648,1920:8200,2176:2097160,2432:8192,2688:268443656,2944:270532616,3200:0,3456:270540800,3712:2105344,3968:268435456,4096:268443648,4352:270532616,4608:270540808,4864:8200,5120:2097152,5376:268435456,5632:268435464,5888:2105344,6144:2105352,6400:0,6656:8,6912:270532608,7168:8192,7424:268443656,7680:270540800,7936:2097160,4224:8,4480:2105344,4736:2097152,4992:268435464,5248:268443648,5504:8200,5760:270540808,6016:270532608,6272:270540800,6528:270532616,6784:8192,7040:2105352,7296:2097160,7552:0,7808:268435456,8064:268443656},{0:1048576,16:33555457,32:1024,48:1049601,64:34604033,80:0,96:1,112:34603009,128:33555456,144:1048577,160:33554433,176:34604032,192:34603008,208:1025,224:1049600,240:33554432,8:34603009,24:0,40:33555457,56:34604032,72:1048576,88:33554433,104:33554432,120:1025,136:1049601,152:33555456,168:34603008,184:1048577,200:1024,216:34604033,232:1,248:1049600,256:33554432,272:1048576,288:33555457,304:34603009,320:1048577,336:33555456,352:34604032,368:1049601,384:1025,400:34604033,416:1049600,432:1,448:0,464:34603008,480:33554433,496:1024,264:1049600,280:33555457,296:34603009,312:1,328:33554432,344:1048576,360:1025,376:34604032,392:33554433,408:34603008,424:0,440:34604033,456:1049601,472:1024,488:33555456,504:1048577},{0:134219808,1:131072,2:134217728,3:32,4:131104,5:134350880,6:134350848,7:2048,8:134348800,9:134219776,10:133120,11:134348832,12:2080,13:0,14:134217760,15:133152,2147483648:2048,2147483649:134350880,2147483650:134219808,2147483651:134217728,2147483652:134348800,2147483653:133120,2147483654:133152,2147483655:32,2147483656:134217760,2147483657:2080,2147483658:131104,2147483659:134350848,2147483660:0,2147483661:134348832,2147483662:134219776,2147483663:131072,16:133152,17:134350848,18:32,19:2048,20:134219776,21:134217760,22:134348832,23:131072,24:0,25:131104,26:134348800,27:134219808,28:134350880,29:133120,30:2080,31:134217728,2147483664:131072,2147483665:2048,2147483666:134348832,2147483667:133152,2147483668:32,2147483669:134348800,2147483670:134217728,2147483671:134219808,2147483672:134350880,2147483673:134217760,2147483674:134219776,2147483675:0,2147483676:133120,2147483677:2080,2147483678:131104,2147483679:134350848}],l=[4160749569,528482304,33030144,2064384,129024,8064,504,2147483679],h=a.DES=n.extend({_doReset:function(){for(var e=this._key.words,t=[],r=0;r<56;r++){var i=o[r]-1;t[r]=e[i>>>5]>>>31-i%32&1}for(var n=this._subKeys=[],a=0;a<16;a++){var u=n[a]=[],l=c[a];for(r=0;r<24;r++)u[r/6|0]|=t[(s[r]-1+l)%28]<<31-r%6,u[4+(r/6|0)]|=t[28+(s[r+24]-1+l)%28]<<31-r%6;for(u[0]=u[0]<<1|u[0]>>>31,r=1;r<7;r++)u[r]=u[r]>>>4*(r-1)+3;u[7]=u[7]<<5|u[7]>>>27}var h=this._invSubKeys=[];for(r=0;r<16;r++)h[r]=n[15-r]},encryptBlock:function(e,t){this._doCryptBlock(e,t,this._subKeys)},decryptBlock:function(e,t){this._doCryptBlock(e,t,this._invSubKeys)},_doCryptBlock:function(e,t,r){this._lBlock=e[t],this._rBlock=e[t+1],d.call(this,4,252645135),d.call(this,16,65535),p.call(this,2,858993459),p.call(this,8,16711935),d.call(this,1,1431655765);for(var i=0;i<16;i++){for(var n=r[i],a=this._lBlock,o=this._rBlock,s=0,c=0;c<8;c++)s|=u[c][((o^n[c])&l[c])>>>0];this._lBlock=o,this._rBlock=a^s}var h=this._lBlock;this._lBlock=this._rBlock,this._rBlock=h,d.call(this,1,1431655765),p.call(this,8,16711935),p.call(this,2,858993459),d.call(this,16,65535),d.call(this,4,252645135),e[t]=this._lBlock,e[t+1]=this._rBlock},keySize:2,ivSize:2,blockSize:2});function d(e,t){var r=(this._lBlock>>>e^this._rBlock)&t;this._rBlock^=r,this._lBlock^=r<>>e^this._lBlock)&t;this._lBlock^=r,this._rBlock^=r<192.");var t=e.slice(0,2),i=e.length<4?e.slice(0,2):e.slice(2,4),n=e.length<6?e.slice(0,2):e.slice(4,6);this._des1=h.createEncryptor(r.create(t)),this._des2=h.createEncryptor(r.create(i)),this._des3=h.createEncryptor(r.create(n))},encryptBlock:function(e,t){this._des1.encryptBlock(e,t),this._des2.decryptBlock(e,t),this._des3.encryptBlock(e,t)},decryptBlock:function(e,t){this._des3.decryptBlock(e,t),this._des2.encryptBlock(e,t),this._des1.decryptBlock(e,t)},keySize:6,ivSize:2,blockSize:2});e.TripleDES=n._createHelper(f)}(),i.TripleDES)},function(e,t,r){var i;e.exports=(i=r(5),r(55),r(56),r(41),r(15),function(){var e=i,t=e.lib.StreamCipher,r=e.algo,n=r.RC4=t.extend({_doReset:function(){for(var e=this._key,t=e.words,r=e.sigBytes,i=this._S=[],n=0;n<256;n++)i[n]=n;n=0;for(var a=0;n<256;n++){var o=n%r,s=t[o>>>2]>>>24-o%4*8&255;a=(a+i[n]+s)%256;var c=i[n];i[n]=i[a],i[a]=c}this._i=this._j=0},_doProcessBlock:function(e,t){e[t]^=a.call(this)},keySize:8,ivSize:0});function a(){for(var e=this._S,t=this._i,r=this._j,i=0,n=0;n<4;n++){r=(r+e[t=(t+1)%256])%256;var a=e[t];e[t]=e[r],e[r]=a,i|=e[(e[t]+e[r])%256]<<24-8*n}return this._i=t,this._j=r,i}e.RC4=t._createHelper(n);var o=r.RC4Drop=n.extend({cfg:n.cfg.extend({drop:192}),_doReset:function(){n._doReset.call(this);for(var e=this.cfg.drop;e>0;e--)a.call(this)}});e.RC4Drop=t._createHelper(o)}(),i.RC4)},function(e,t,r){var i;e.exports=(i=r(5),r(55),r(56),r(41),r(15),function(){var e=i,t=e.lib.StreamCipher,r=e.algo,n=[],a=[],o=[],s=r.Rabbit=t.extend({_doReset:function(){for(var e=this._key.words,t=this.cfg.iv,r=0;r<4;r++)e[r]=16711935&(e[r]<<8|e[r]>>>24)|4278255360&(e[r]<<24|e[r]>>>8);var i=this._X=[e[0],e[3]<<16|e[2]>>>16,e[1],e[0]<<16|e[3]>>>16,e[2],e[1]<<16|e[0]>>>16,e[3],e[2]<<16|e[1]>>>16],n=this._C=[e[2]<<16|e[2]>>>16,4294901760&e[0]|65535&e[1],e[3]<<16|e[3]>>>16,4294901760&e[1]|65535&e[2],e[0]<<16|e[0]>>>16,4294901760&e[2]|65535&e[3],e[1]<<16|e[1]>>>16,4294901760&e[3]|65535&e[0]];for(this._b=0,r=0;r<4;r++)c.call(this);for(r=0;r<8;r++)n[r]^=i[r+4&7];if(t){var a=t.words,o=a[0],s=a[1],u=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),l=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),h=u>>>16|4294901760&l,d=l<<16|65535&u;for(n[0]^=u,n[1]^=h,n[2]^=l,n[3]^=d,n[4]^=u,n[5]^=h,n[6]^=l,n[7]^=d,r=0;r<4;r++)c.call(this)}},_doProcessBlock:function(e,t){var r=this._X;c.call(this),n[0]=r[0]^r[5]>>>16^r[3]<<16,n[1]=r[2]^r[7]>>>16^r[5]<<16,n[2]=r[4]^r[1]>>>16^r[7]<<16,n[3]=r[6]^r[3]>>>16^r[1]<<16;for(var i=0;i<4;i++)n[i]=16711935&(n[i]<<8|n[i]>>>24)|4278255360&(n[i]<<24|n[i]>>>8),e[t+i]^=n[i]},blockSize:4,ivSize:2});function c(){for(var e=this._X,t=this._C,r=0;r<8;r++)a[r]=t[r];for(t[0]=t[0]+1295307597+this._b|0,t[1]=t[1]+3545052371+(t[0]>>>0>>0?1:0)|0,t[2]=t[2]+886263092+(t[1]>>>0>>0?1:0)|0,t[3]=t[3]+1295307597+(t[2]>>>0>>0?1:0)|0,t[4]=t[4]+3545052371+(t[3]>>>0>>0?1:0)|0,t[5]=t[5]+886263092+(t[4]>>>0>>0?1:0)|0,t[6]=t[6]+1295307597+(t[5]>>>0>>0?1:0)|0,t[7]=t[7]+3545052371+(t[6]>>>0>>0?1:0)|0,this._b=t[7]>>>0>>0?1:0,r=0;r<8;r++){var i=e[r]+t[r],n=65535&i,s=i>>>16,c=((n*n>>>17)+n*s>>>15)+s*s,u=((4294901760&i)*i|0)+((65535&i)*i|0);o[r]=c^u}e[0]=o[0]+(o[7]<<16|o[7]>>>16)+(o[6]<<16|o[6]>>>16)|0,e[1]=o[1]+(o[0]<<8|o[0]>>>24)+o[7]|0,e[2]=o[2]+(o[1]<<16|o[1]>>>16)+(o[0]<<16|o[0]>>>16)|0,e[3]=o[3]+(o[2]<<8|o[2]>>>24)+o[1]|0,e[4]=o[4]+(o[3]<<16|o[3]>>>16)+(o[2]<<16|o[2]>>>16)|0,e[5]=o[5]+(o[4]<<8|o[4]>>>24)+o[3]|0,e[6]=o[6]+(o[5]<<16|o[5]>>>16)+(o[4]<<16|o[4]>>>16)|0,e[7]=o[7]+(o[6]<<8|o[6]>>>24)+o[5]|0}e.Rabbit=t._createHelper(s)}(),i.Rabbit)},function(e,t,r){var i;e.exports=(i=r(5),r(55),r(56),r(41),r(15),function(){var e=i,t=e.lib.StreamCipher,r=e.algo,n=[],a=[],o=[],s=r.RabbitLegacy=t.extend({_doReset:function(){var e=this._key.words,t=this.cfg.iv,r=this._X=[e[0],e[3]<<16|e[2]>>>16,e[1],e[0]<<16|e[3]>>>16,e[2],e[1]<<16|e[0]>>>16,e[3],e[2]<<16|e[1]>>>16],i=this._C=[e[2]<<16|e[2]>>>16,4294901760&e[0]|65535&e[1],e[3]<<16|e[3]>>>16,4294901760&e[1]|65535&e[2],e[0]<<16|e[0]>>>16,4294901760&e[2]|65535&e[3],e[1]<<16|e[1]>>>16,4294901760&e[3]|65535&e[0]];this._b=0;for(var n=0;n<4;n++)c.call(this);for(n=0;n<8;n++)i[n]^=r[n+4&7];if(t){var a=t.words,o=a[0],s=a[1],u=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),l=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),h=u>>>16|4294901760&l,d=l<<16|65535&u;for(i[0]^=u,i[1]^=h,i[2]^=l,i[3]^=d,i[4]^=u,i[5]^=h,i[6]^=l,i[7]^=d,n=0;n<4;n++)c.call(this)}},_doProcessBlock:function(e,t){var r=this._X;c.call(this),n[0]=r[0]^r[5]>>>16^r[3]<<16,n[1]=r[2]^r[7]>>>16^r[5]<<16,n[2]=r[4]^r[1]>>>16^r[7]<<16,n[3]=r[6]^r[3]>>>16^r[1]<<16;for(var i=0;i<4;i++)n[i]=16711935&(n[i]<<8|n[i]>>>24)|4278255360&(n[i]<<24|n[i]>>>8),e[t+i]^=n[i]},blockSize:4,ivSize:2});function c(){for(var e=this._X,t=this._C,r=0;r<8;r++)a[r]=t[r];for(t[0]=t[0]+1295307597+this._b|0,t[1]=t[1]+3545052371+(t[0]>>>0>>0?1:0)|0,t[2]=t[2]+886263092+(t[1]>>>0>>0?1:0)|0,t[3]=t[3]+1295307597+(t[2]>>>0>>0?1:0)|0,t[4]=t[4]+3545052371+(t[3]>>>0>>0?1:0)|0,t[5]=t[5]+886263092+(t[4]>>>0>>0?1:0)|0,t[6]=t[6]+1295307597+(t[5]>>>0>>0?1:0)|0,t[7]=t[7]+3545052371+(t[6]>>>0>>0?1:0)|0,this._b=t[7]>>>0>>0?1:0,r=0;r<8;r++){var i=e[r]+t[r],n=65535&i,s=i>>>16,c=((n*n>>>17)+n*s>>>15)+s*s,u=((4294901760&i)*i|0)+((65535&i)*i|0);o[r]=c^u}e[0]=o[0]+(o[7]<<16|o[7]>>>16)+(o[6]<<16|o[6]>>>16)|0,e[1]=o[1]+(o[0]<<8|o[0]>>>24)+o[7]|0,e[2]=o[2]+(o[1]<<16|o[1]>>>16)+(o[0]<<16|o[0]>>>16)|0,e[3]=o[3]+(o[2]<<8|o[2]>>>24)+o[1]|0,e[4]=o[4]+(o[3]<<16|o[3]>>>16)+(o[2]<<16|o[2]>>>16)|0,e[5]=o[5]+(o[4]<<8|o[4]>>>24)+o[3]|0,e[6]=o[6]+(o[5]<<16|o[5]>>>16)+(o[4]<<16|o[4]>>>16)|0,e[7]=o[7]+(o[6]<<8|o[6]>>>24)+o[5]|0}e.RabbitLegacy=t._createHelper(s)}(),i.RabbitLegacy)},function(e,t,r){const i=r(4);class n{static validate(e){i(0===e||1===e||2===e||3===e,"Connection type is invalid: "+e)}static isValid(e){return 0===e||1===e||2===e||3}}n.INVALID=0,n.IPV4=1,n.IPV6=2,n.TOR=3,n.I2P=4,e.exports=n},function(e,t,r){const i=r(254);e.exports=class extends i{constructor(e){super(e)}getDownloadPath(){return this.state.downloadPath}setDownloadPath(e){return this.state.downloadPath=e,this}}},function(e,t){class r{}r.NOT_SPENT=0,r.CONFIRMED=1,r.TX_POOL=2,e.exports=r},function(e,t,r){const i=r(7).BigInteger;e.exports=class{constructor(e){this.state=Object.assign({},e),void 0===this.state.feeTotal||this.state.feeTotal instanceof i||(this.state.feeTotal=i.parse(this.state.feeTotal))}toJson(){let e=Object.assign({},this.state);return e.feeTotal&&(e.feeTotal=e.feeTotal.toString()),e}getNumTxs(){return this.state.numTxs}setNumTxs(e){return this.state.numTxs=e,this}getNumNotRelayed(){return this.state.numNotRelayed}setNumNotRelayed(e){return this.state.numNotRelayed=e,this}getNumFailing(){return this.state.numFailing}setNumFailing(e){return this.state.numFailing=e,this}getNumDoubleSpends(){return this.state.numDoubleSpends}setNumDoubleSpends(e){return this.state.numDoubleSpends=e,this}getNum10m(){return this.state.num10m}setNum10m(e){return this.state.num10m=e,this}getFeeTotal(){return this.state.feeTotal}setFeeTotal(e){return this.state.feeTotal=e,this}getBytesMax(){return this.state.bytesMax}setBytesMax(e){return this.state.bytesMax=e,this}getBytesMed(){return this.state.bytesMed}setBytesMed(e){return this.state.bytesMed=e,this}getBytesMin(){return this.state.bytesMin}setBytesMin(e){return this.state.bytesMin=e,this}getBytesTotal(){return this.state.bytesTotal}setBytesTotal(e){return this.state.bytesTotal=e,this}getHisto(){return this.state.histo}setHisto(e){return this.state.histo=e,this}getHisto98pc(){return this.state.histo98pc}setHisto98pc(e){return this.state.histo98pc=e,this}getOldestTimestamp(){return this.state.oldestTimestamp}setOldestTimestamp(e){return this.state.oldestTimestamp=e,this}}},function(e,t){class r{}r.DEFAULT=0,r.UNIMPORTANT=1,r.NORMAL=2,r.ELEVATED=3,e.exports=r},function(e,t,r){const i=r(4),n=r(7).BigInteger,a=r(12),o=r(142),s=r(260),c=r(143),u=r(42),l=r(91),h=r(261),d=r(145),p=r(103),f=r(99),m=r(18),g=r(96),_=r(146),v=r(58),y=r(147),b=r(148),E=r(149),w=r(150),S=r(98),k=r(94),x=r(73),M=r(57),N=r(138),j=r(75),T=r(151),R=r(95),I=r(76),O=(r(43),r(74)),A=r(59),P=r(28),D=r(100),F=r(102),C=r(101),B=r(248);class z extends F{constructor(e,t,r,i){super(),this.config=p._normalizeConfig(e,t,r,i),this.rpc=new M(this.config),this.addressCache={}}async getRpcConnection(){return this.rpc}async openWallet(e,t){let r=new C("string"==typeof e?{path:e,password:t}:e);if(!r.getPath())throw new m("Must provide name of wallet to open");if(!r.getPassword())throw new m("Must provide password of wallet to open");if(await this.rpc.sendJsonRequest("open_wallet",{filename:r.getPath(),password:r.getPassword()}),this._clear(),this.path=r.getPath(),r.getServer())return this.setDaemonConnection(r.getServer())}async createWallet(e){if(void 0===e)throw new m("Must provide config to create wallet");if(void 0!==(e=e instanceof C?e:new C(e)).getMnemonic()&&(void 0!==e.getPrimaryAddress()||void 0!==e.getPrivateViewKey()||void 0!==e.getPrivateSpendKey()))throw new m("Wallet may be initialized with a mnemonic or keys but not both");if(void 0!==e.getNetworkType())throw new m("Cannot provide networkType when creating RPC wallet because server's network type is already set");if(void 0!==e.getMnemonic())await this._createWalletFromMnemonic(e.getPath(),e.getPassword(),e.getMnemonic(),e.getRestoreHeight(),e.getLanguage(),e.getSeedOffset(),e.getSaveCurrent());else if(void 0!==e.getPrimaryAddress()){if(void 0!==e.getSeedOffset())throw new m("Cannot provide seedOffset when creating wallet from keys");await this._createWalletFromKeys(e.getPath(),e.getPassword(),e.getPrimaryAddress(),e.getPrivateViewKey(),e.getPrivateSpendKey(),e.getRestoreHeight(),e.getLanguage(),e.getSaveCurrent())}else{if(void 0!==e.getSeedOffset())throw new m("Cannot provide seedOffset when creating random wallet");if(void 0!==e.getRestoreHeight())throw new m("Cannot provide restoreHeight when creating random wallet");if(!1===e.getSaveCurrent())throw new m("Current wallet is saved automatically when creating random wallet");await this._createWalletRandom(e.getPath(),e.getPassword(),e.getLanguage())}if(e.getServer())return this.setDaemonConnection(e.getServer())}async _createWalletRandom(e,t,r){if(!e)throw new m("Name is not initialized");if(!t)throw new m("Password is not initialized");r||(r=F.DEFAULT_LANGUAGE);let i={filename:e,password:t,language:r};try{await this.rpc.sendJsonRequest("create_wallet",i)}catch(t){if("Cannot create wallet. Already exists."===t.message)throw new m("Wallet already exists: "+e);throw t}this._clear(),this.path=e}async _createWalletFromMnemonic(e,t,r,i,n,a,o){try{await this.rpc.sendJsonRequest("restore_deterministic_wallet",{filename:e,password:t,seed:r,seed_offset:a,restore_height:i,language:n,autosave_current:o})}catch(t){if("Cannot create wallet. Already exists."===t.message)throw new m("Wallet already exists: "+e);throw t}this._clear(),this.path=e}async _createWalletFromKeys(e,t,r,i,n,a,o,s){void 0===a&&(a=0),void 0===o&&(o=F.DEFAULT_LANGUAGE);try{await this.rpc.sendJsonRequest("generate_from_keys",{filename:e,password:t,address:r,viewkey:i,spendkey:n,restore_height:a,autosave_current:s})}catch(t){if("Cannot create wallet. Already exists."===t.message)throw new m("Wallet already exists: "+e);throw t}this._clear(),this.path=e}async isViewOnly(){try{return await this.rpc.sendJsonRequest("query_key",{key_type:"mnemonic"}),!1}catch(e){if(-29===e.getCode())return!0;if(-1===e.getCode())return!1;throw e}}async setDaemonConnection(e,t,r){let i=e instanceof M?e:new M(e);if(i.getUsername())throw new m("monero-wallet-rpc does not support setting daemon connection with authentication");r||(r=new B);let n={};n.address=i?i.getUri():"bad_uri",n.trusted=t,n.ssl_support="autodetect",n.ssl_private_key_path=r.getPrivateKeyPath(),n.ssl_certificate_path=r.getCertificatePath(),n.ssl_ca_file=r.getCertificateAuthorityFile(),n.ssl_allowed_fingerprints=r.getAllowedFingerprints(),n.ssl_allow_any_cert=r.getAllowAnyCert(),await this.rpc.sendJsonRequest("set_daemon",n)}async getDaemonConnection(){throw new m("Not implemented")}async isConnected(){try{return await this.sync(),!0}catch(e){return!1}}async getVersion(){let e=await this.rpc.sendJsonRequest("get_version");return new D(e.result.version,e.result.release)}async getPath(){return this.path}async getMnemonic(){try{return(await this.rpc.sendJsonRequest("query_key",{key_type:"mnemonic"})).result.key}catch(e){if(-29===e.getCode())return;throw e}}async getMnemonicLanguage(){if(void 0!==await this.getMnemonic())throw new m("MoneroWalletRpc.getMnemonicLanguage() not supported")}async getMnemonicLanguages(){return(await this.rpc.sendJsonRequest("get_languages")).result.languages}async getPrivateViewKey(){return(await this.rpc.sendJsonRequest("query_key",{key_type:"view_key"})).result.key}async getPrivateSpendKey(){try{return(await this.rpc.sendJsonRequest("query_key",{key_type:"spend_key"})).result.key}catch(e){if(-29===e.getCode()&&-1!==e.message.indexOf("watch-only"))return;throw e}}async getAddress(e,t){let r=this.addressCache[e];if(!r)return await this.getSubaddresses(e,void 0,!0),this.getAddress(e,t);let i=r[t];return i||(await this.getSubaddresses(e,void 0,!0),this.addressCache[e][t])}async getAddressIndex(e){let t;try{t=await this.rpc.sendJsonRequest("get_address_index",{address:e})}catch(e){if(-2===e.getCode())throw new m(e.message);throw e}let r=new j(e);return r.setAccountIndex(t.result.index.major),r.setIndex(t.result.index.minor),r}async getIntegratedAddress(e){try{let t=(await this.rpc.sendJsonRequest("make_integrated_address",{payment_id:e})).result.integrated_address;return await this.decodeIntegratedAddress(t)}catch(t){if(t.message.includes("Invalid payment ID"))throw new m("Invalid payment ID: "+e);throw t}}async decodeIntegratedAddress(e){let t=await this.rpc.sendJsonRequest("split_integrated_address",{integrated_address:e});return(new _).setStandardAddress(t.result.standard_address).setPaymentId(t.result.payment_id).setIntegratedAddress(e)}async getHeight(){return(await this.rpc.sendJsonRequest("get_height")).result.height}async getDaemonHeight(){throw new m("monero-wallet-rpc does not support getting the chain height")}async getHeightByDate(e,t,r){throw new m("monero-wallet-rpc does not support getting a height by date")}async sync(e,t){i(void 0===t,"Monero Wallet RPC does not support reporting sync progress");let r=await this.rpc.sendJsonRequest("refresh",{start_height:e});return new T(r.result.blocks_fetched,r.result.received_money)}async startSyncing(){}async rescanSpent(){await this.rpc.sendJsonRequest("rescan_spent")}async rescanBlockchain(){await this.rpc.sendJsonRequest("rescan_blockchain")}async getBalance(e,t){return(await this._getBalances(e,t))[0]}async getUnlockedBalance(e,t){return(await this._getBalances(e,t))[1]}async getAccounts(e,t,r){let a=await this.rpc.sendJsonRequest("get_accounts",{tag:t}),o=[];for(let t of a.result.subaddress_accounts){let r=z._convertRpcAccount(t);e&&r.setSubaddresses(await this.getSubaddresses(r.getIndex(),void 0,!0)),o.push(r)}if(e&&!r){for(let e of o)for(let t of e.getSubaddresses())t.setBalance(new n(0)),t.setUnlockedBalance(new n(0)),t.setNumUnspentOutputs(0),t.setNumBlocksToUnlock(0);if(a=await this.rpc.sendJsonRequest("get_balance",{all_accounts:!0}),a.result.per_subaddress)for(let e of a.result.per_subaddress){let t=z._convertRpcSubaddress(e),r=o[t.getAccountIndex()];i.equal(t.getAccountIndex(),r.getIndex(),"RPC accounts are out of order");let n=r.getSubaddresses()[t.getIndex()];i.equal(t.getIndex(),n.getIndex(),"RPC subaddresses are out of order"),void 0!==t.getBalance()&&n.setBalance(t.getBalance()),void 0!==t.getUnlockedBalance()&&n.setUnlockedBalance(t.getUnlockedBalance()),void 0!==t.getNumUnspentOutputs()&&n.setNumUnspentOutputs(t.getNumUnspentOutputs())}}return o}async getAccount(e,t,r){i(e>=0);for(let i of await this.getAccounts())if(i.getIndex()===e)return t&&i.setSubaddresses(await this.getSubaddresses(e,void 0,r)),i;throw new Exception("Account with index "+e+" does not exist")}async createAccount(e){e=e||void 0;let t=await this.rpc.sendJsonRequest("create_account",{label:e});return new o(t.result.account_index,t.result.address,new n(0),new n(0))}async getSubaddresses(e,t,r){let i={};i.account_index=e,t&&(i.address_index=a.listify(t));let o=await this.rpc.sendJsonRequest("get_address",i),s=[];for(let t of o.result.addresses){let r=z._convertRpcSubaddress(t);r.setAccountIndex(e),s.push(r)}if(!r){for(let e of s)e.setBalance(new n(0)),e.setUnlockedBalance(new n(0)),e.setNumUnspentOutputs(0),e.setNumBlocksToUnlock(0);if(o=await this.rpc.sendJsonRequest("get_balance",i),o.result.per_subaddress)for(let e of o.result.per_subaddress){let t=z._convertRpcSubaddress(e);for(let e of s)e.getIndex()===t.getIndex()&&(void 0!==t.getBalance()&&e.setBalance(t.getBalance()),void 0!==t.getUnlockedBalance()&&e.setUnlockedBalance(t.getUnlockedBalance()),void 0!==t.getNumUnspentOutputs()&&e.setNumUnspentOutputs(t.getNumUnspentOutputs()),void 0!==t.getNumBlocksToUnlock()&&e.setNumBlocksToUnlock(t.getNumBlocksToUnlock()))}}let c=this.addressCache[e];c||(c={},this.addressCache[e]=c);for(let e of s)c[e.getIndex()]=e.getAddress();return s}async getSubaddress(e,t,r){return i(e>=0),i(t>=0),(await this.getSubaddresses(e,t,r))[0]}async createSubaddress(e,t){let r=await this.rpc.sendJsonRequest("create_address",{account_index:e,label:t}),i=new j;return i.setAccountIndex(e),i.setIndex(r.result.address_index),i.setAddress(r.result.address),i.setLabel(t||void 0),i.setBalance(new n(0)),i.setUnlockedBalance(new n(0)),i.setNumUnspentOutputs(0),i.setIsUsed(!1),i.setNumBlocksToUnlock(0),i}async getTxs(e,t){let r=(e=F._normalizeTxQuery(e)).getTransferQuery(),i=e.getOutputQuery();e.setTransferQuery(void 0),e.setOutputQuery(void 0);let n=await this._getTransfersAux((new R).setTxQuery(z._decontextualize(e.copy()))),a=[],o=new Set;for(let e of n)o.has(e.getTx())||(a.push(e.getTx()),o.add(e.getTx()));let s=new Map,c=new Map;for(let e of a)z._mergeTx(e,s,c,!1);if(e.getIncludeOutputs()||i){let t=await this._getOutputsAux((new k).setTxQuery(z._decontextualize(e.copy()))),r=[];for(let e of t)r.includes(e.getTx())||(z._mergeTx(e.getTx(),s,c,!0),r.push(e.getTx()))}e.setTransferQuery(r),e.setOutputQuery(i);let u=[];for(let t of a)e.meetsCriteria(t)?u.push(t):void 0!==t.getBlock()&&t.getBlock().getTxs().splice(t.getBlock().getTxs().indexOf(t),1);if(a=u,e.getHashes()){let r=[];for(let t of e.getHashes()){let e=!1;for(let r of a)if(t===r.getHash()){e=!0;break}e||r.push(t)}if(t)for(let e of r)t.push(e);else if(r.length>0)throw new m("Wallet missing requested tx hashes: "+r)}for(let t of a)if(t.isConfirmed()&&void 0===t.getBlock())return this.getTxs(e);if(e.getHashes()&&e.getHashes().length>0){let t=new Map;for(let e of a)t.set(e.getHash(),e);let r=[];for(let i of e.getHashes())t.get(i)&&r.push(t.get(i));a=r}return a}async getTransfers(e){if(e=F._normalizeTransferQuery(e),!z._isContextual(e))return this._getTransfersAux(e);let t=[];for(let r of await this.getTxs(e.getTxQuery()))for(let i of r.filterTransfers(e))t.push(i);return t}async getOutputs(e){if(e=F._normalizeOutputQuery(e),!z._isContextual(e))return this._getOutputsAux(e);let t=[];for(let r of await this.getTxs(e.getTxQuery()))for(let i of r.filterOutputs(e))t.push(i);return t}async getOutputsHex(){return(await this.rpc.sendJsonRequest("export_outputs")).result.outputs_data_hex}async importOutputsHex(e){return(await this.rpc.sendJsonRequest("import_outputs",{outputs_data_hex:e})).result.num_imported}async getKeyImages(){return await this._rpcExportKeyImages(!0)}async importKeyImages(e){let t=e.map(e=>({key_image:e.getHex(),signature:e.getSignature()})),r=await this.rpc.sendJsonRequest("import_key_images",{signed_key_images:t}),i=new y;return i.setHeight(r.result.height),i.setSpentAmount(new n(r.result.spent)),i.setUnspentAmount(new n(r.result.unspent)),i}async getNewKeyImagesFromLastImport(){return await this._rpcExportKeyImages(!1)}async relayTxs(e){i(Array.isArray(e),"Must provide an array of txs or their metadata to relay");let t=[];for(let r of e){let e=r instanceof A?r.getMetadata():r,i=await this.rpc.sendJsonRequest("relay_tx",{hex:e});t.push(i.result.tx_hash)}return t}async createTxs(e){if(void 0===(e=F._normalizeCreateTxsConfig(e)).getCanSplit()&&e.setCanSplit(!0),!0===e.getRelay()&&await this.isMultisig())throw new m("Cannot relay multisig transaction until co-signed");let t=e.getAccountIndex();if(void 0===t)throw new m("Must provide the account index to send from");let r=void 0===e.getSubaddressIndices()?void 0:e.getSubaddressIndices().slice(0),n={destinations:[]};for(let t of e.getDestinations())i(t.getAddress(),"Destination address is not defined"),i(t.getAmount(),"Destination amount is not defined"),n.destinations.push({address:t.getAddress(),amount:t.getAmount().toString()});n.account_index=t,n.subaddr_indices=r,n.payment_id=e.getPaymentId(),n.unlock_time=e.getUnlockHeight(),n.do_not_relay=!0!==e.getRelay(),i(void 0===e.getPriority()||e.getPriority()>=0&&e.getPriority()<=3),n.priority=e.getPriority(),n.get_tx_hex=!0,n.get_tx_metadata=!0,e.getCanSplit()?n.get_tx_keys=!0:n.get_tx_key=!0;let a,o=(await this.rpc.sendJsonRequest(e.getCanSplit()?"transfer_split":"transfer",n)).result,s=e.getCanSplit()?void 0!==o.fee_list?o.fee_list.length:0:void 0!==o.fee?1:0;s>0&&(a=[]);for(let i=0;i=0&&e.getPriority()<=3),t.priority=e.getPriority(),t.payment_id=e.getPaymentId(),t.get_tx_key=!0,t.get_tx_hex=!0,t.get_tx_metadata=!0;let r=(await this.rpc.sendJsonRequest("sweep_single",t)).result,n=z._initSentTxWallet(e,null);z._convertRpcTxToTxSet(r,n,!0);return n.getOutgoingTransfer().getDestinations()[0].setAmount(n.getOutgoingTransfer().getAmount()),n}async sweepUnlocked(e){e=F._normalizeSweepUnlockedConfig(e);let t=new Map;if(void 0!==e.getAccountIndex())if(void 0!==e.getSubaddressIndices())t.set(e.getAccountIndex(),e.getSubaddressIndices());else{let r=[];t.set(e.getAccountIndex(),r);for(let t of await this.getSubaddresses(e.getAccountIndex()))t.getUnlockedBalance().compare(new n(0))>0&&r.push(t.getIndex())}else{let e=await this.getAccounts(!0);for(let r of e)if(r.getUnlockedBalance().compare(new n(0))>0){let e=[];t.set(r.getIndex(),e);for(let t of r.getSubaddresses())t.getUnlockedBalance().compare(new n(0))>0&&e.push(t.getIndex())}}let r=[];for(let i of t.keys()){let n=e.copy();if(n.setAccountIndex(i),n.setSweepEachSubaddress(!1),!0!==n.getSweepEachSubaddress()){n.setSubaddressIndices(t.get(i));for(let e of await this._rpcSweepAccount(n))r.push(e)}else for(let e of t.get(i)){n.setSubaddressIndices([e]);for(let e of await this._rpcSweepAccount(n))r.push(e)}}return r}async sweepDust(e){void 0===e&&(e=!1);let t=(await this.rpc.sendJsonRequest("sweep_dust",{do_not_relay:!e})).result,r=z._convertRpcSentTxsToTxSet(t);if(void 0!==r.getTxs())for(let t of r.getTxs())t.setIsRelayed(!e),t.setInTxPool(t.isRelayed());else if(void 0===r.getMultisigTxHex()&&void 0===r.getSignedTxHex()&&void 0===r.getUnsignedTxHex())throw new m("No dust to sweep");return r.getTxs()}async parseTxSet(e){let t=await this.rpc.sendJsonRequest("describe_transfer",{unsigned_txset:e.getUnsignedTxHex(),multisig_txset:e.getMultisigTxHex()});return z._convertRpcDescribeTransfer(t.result)}async signTxs(e){return(await this.rpc.sendJsonRequest("sign_transfer",{unsigned_txset:e,export_raw:!1})).result.signed_txset}async submitTxs(e){return(await this.rpc.sendJsonRequest("submit_transfer",{tx_data_hex:e})).result.tx_hash_list}async signMessage(e){return(await this.rpc.sendJsonRequest("sign",{data:e})).result.signature}async verifyMessage(e,t,r){return(await this.rpc.sendJsonRequest("verify",{data:e,address:t,signature:r})).result.good}async getTxKey(e){try{return(await this.rpc.sendJsonRequest("get_tx_key",{txid:e})).result.tx_key}catch(e){throw e instanceof N&&-8===e.getCode()&&e.message.includes("TX ID has invalid format")&&(e=new N("TX hash has invalid format",e.getCode(),e.getRpcMethod(),e.getRpcParams())),e}}async checkTxKey(e,t,r){try{let i=await this.rpc.sendJsonRequest("check_tx_key",{txid:e,tx_key:t,address:r}),a=new d;return a.setIsGood(!0),a.setNumConfirmations(i.result.confirmations),a.setInTxPool(i.result.in_pool),a.setReceivedAmount(new n(i.result.received)),a}catch(e){throw e instanceof N&&-8===e.getCode()&&e.message.includes("TX ID has invalid format")&&(e=new N("TX hash has invalid format",e.getCode(),e.getRpcMethod(),e.getRpcParams())),e}}async getTxProof(e,t,r){try{return(await this.rpc.sendJsonRequest("get_tx_proof",{txid:e,address:t,message:r})).result.signature}catch(e){throw e instanceof N&&-8===e.getCode()&&e.message.includes("TX ID has invalid format")&&(e=new N("TX hash has invalid format",e.getCode(),e.getRpcMethod(),e.getRpcParams())),e}}async checkTxProof(e,t,r,i){try{let a=await this.rpc.sendJsonRequest("check_tx_proof",{txid:e,address:t,message:r,signature:i}),o=a.result.good,s=new d;return s.setIsGood(o),o&&(s.setNumConfirmations(a.result.confirmations),s.setInTxPool(a.result.in_pool),s.setReceivedAmount(new n(a.result.received))),s}catch(e){throw e instanceof N&&-8===e.getCode()&&e.message.includes("TX ID has invalid format")&&(e=new N("TX hash has invalid format",e.getCode(),e.getRpcMethod(),e.getRpcParams())),e}}async getSpendProof(e,t){try{return(await this.rpc.sendJsonRequest("get_spend_proof",{txid:e,message:t})).result.signature}catch(e){throw e instanceof N&&-8===e.getCode()&&e.message.includes("TX ID has invalid format")&&(e=new N("TX hash has invalid format",e.getCode(),e.getRpcMethod(),e.getRpcParams())),e}}async checkSpendProof(e,t,r){try{return(await this.rpc.sendJsonRequest("check_spend_proof",{txid:e,message:t,signature:r})).result.good}catch(e){throw e instanceof N&&-8===e.getCode()&&e.message.includes("TX ID has invalid format")&&(e=new N("TX hash has invalid format",e.getCode(),e.getRpcMethod(),e.getRpcParams())),e}}async getReserveProofWallet(e){return(await this.rpc.sendJsonRequest("get_reserve_proof",{all:!0,message:e})).result.signature}async getReserveProofAccount(e,t,r){return(await this.rpc.sendJsonRequest("get_reserve_proof",{account_index:e,amount:t.toString(),message:r})).result.signature}async checkReserveProof(e,t,r){let i=await this.rpc.sendJsonRequest("check_reserve_proof",{address:e,message:t,signature:r}),a=i.result.good,o=new h;return o.setIsGood(a),a&&(o.setUnconfirmedSpentAmount(new n(i.result.spent)),o.setTotalAmount(new n(i.result.total))),o}async getTxNotes(e){return(await this.rpc.sendJsonRequest("get_tx_notes",{txids:e})).result.notes}async setTxNotes(e,t){await this.rpc.sendJsonRequest("set_tx_notes",{txids:e,notes:t})}async getAddressBookEntries(e){let t=await this.rpc.sendJsonRequest("get_address_book",{entries:e});if(!t.result.entries)return[];let r=[];for(let e of t.result.entries)r.push((new c).setIndex(e.index).setAddress(e.address).setDescription(e.description).setPaymentId(e.payment_id));return r}async addAddressBookEntry(e,t){return(await this.rpc.sendJsonRequest("add_address_book",{address:e,description:t})).result.index}async editAddressBookEntry(e,t,r,i,n){await this.rpc.sendJsonRequest("edit_address_book",{index:e,set_address:t,address:r,set_description:i,description:n})}async deleteAddressBookEntry(e){await this.rpc.sendJsonRequest("delete_address_book",{index:e})}async tagAccounts(e,t){await this.rpc.sendJsonRequest("tag_accounts",{tag:e,accounts:t})}async untagAccounts(e){await this.rpc.sendJsonRequest("untag_accounts",{accounts:e})}async getAccountTags(){let e=[],t=await this.rpc.sendJsonRequest("get_account_tags");if(t.result.account_tags)for(let r of t.result.account_tags)e.push(new s(r.tag?r.tag:void 0,r.label?r.label:void 0,r.accounts));return e}async setAccountTagLabel(e,t){await this.rpc.sendJsonRequest("set_account_tag_description",{tag:e,description:t})}async createPaymentUri(e){return e=F._normalizeCreateTxsConfig(e),(await this.rpc.sendJsonRequest("make_uri",{address:e.getDestinations()[0].getAddress(),amount:e.getDestinations()[0].getAmount()?e.getDestinations()[0].getAmount().toString():void 0,payment_id:e.getPaymentId(),recipient_name:e.getRecipientName(),tx_description:e.getNote()})).result.uri}async parsePaymentUri(e){i(e,"Must provide URI to parse");let t=await this.rpc.sendJsonRequest("parse_uri",{uri:e}),r=new I({address:t.result.uri.address,amount:new n(t.result.uri.amount)});return r.setPaymentId(t.result.uri.payment_id),r.setRecipientName(t.result.uri.recipient_name),r.setNote(t.result.uri.tx_description),""===r.getDestinations()[0].getAddress()&&r.getDestinations()[0].setAddress(void 0),""===r.getPaymentId()&&r.setPaymentId(void 0),""===r.getRecipientName()&&r.setRecipientName(void 0),""===r.getNote()&&r.setNote(void 0),r}async getAttribute(e){try{let t=await this.rpc.sendJsonRequest("get_attribute",{key:e});return""===t.result.value?void 0:t.result.value}catch(e){if(e instanceof N&&-45===e.getCode())return;throw e}}async setAttribute(e,t){await this.rpc.sendJsonRequest("set_attribute",{key:e,value:t})}async startMining(e,t,r){await this.rpc.sendJsonRequest("start_mining",{threads_count:e,do_background_mining:t,ignore_battery:r})}async stopMining(){await this.rpc.sendJsonRequest("stop_mining")}async isMultisigImportNeeded(){return!0===(await this.rpc.sendJsonRequest("get_balance")).result.multisig_import_needed}async getMultisigInfo(){let e=(await this.rpc.sendJsonRequest("is_multisig")).result,t=new b;return t.setIsMultisig(e.multisig),t.setIsReady(e.ready),t.setThreshold(e.threshold),t.setNumParticipants(e.total),t}async prepareMultisig(){return(await this.rpc.sendJsonRequest("prepare_multisig")).result.multisig_info}async makeMultisig(e,t,r){let i=(await this.rpc.sendJsonRequest("make_multisig",{multisig_info:e,threshold:t,password:r})).result,n=new E;return n.setAddress(i.address),n.setMultisigHex(i.multisig_info),0===n.getAddress().length&&n.setAddress(void 0),0===n.getMultisigHex().length&&n.setMultisigHex(void 0),n}async exchangeMultisigKeys(e,t){let r=await this.rpc.sendJsonRequest("exchange_multisig_keys",{multisig_info:e,password:t}),i=new E;return i.setAddress(r.result.address),i.setMultisigHex(r.result.multisig_info),0===i.getAddress().length&&i.setAddress(void 0),0===i.getMultisigHex().length&&i.setMultisigHex(void 0),i}async getMultisigHex(){return(await this.rpc.sendJsonRequest("export_multisig_info")).result.info}async importMultisigHex(e){return(await this.rpc.sendJsonRequest("import_multisig_info",{info:e})).result.n_outputs}async signMultisigTxHex(e){let t=(await this.rpc.sendJsonRequest("sign_multisig",{tx_data_hex:e})).result,r=new w;return r.setSignedMultisigTxHex(t.tx_data_hex),r.setTxHashes(t.tx_hash_list),r}async submitMultisigTxHex(e){return(await this.rpc.sendJsonRequest("submit_multisig",{tx_data_hex:e})).result.tx_hash_list}async save(){await this.rpc.sendJsonRequest("store")}async close(e){void 0===e&&(e=!1),this._clear(),await this.rpc.sendJsonRequest("close_wallet",{autosave_current:e})}async isClosed(){try{await this.getPrimaryAddress()}catch(e){return e instanceof N&&-13===e.getCode()&&e.message.indexOf("No wallet file")>-1}return!1}async stop(){this._clear(),await this.rpc.sendJsonRequest("stop_wallet")}async getTx(){return super.getTx(...arguments)}async getIncomingTransfers(){return super.getIncomingTransfers(...arguments)}async getOutgoingTransfers(){return super.getOutgoingTransfers(...arguments)}async createTx(){return super.createTx(...arguments)}async relayTx(){return super.relayTx(...arguments)}async getTxNote(){return super.getTxNote(...arguments)}async setTxNote(){return super.setTxNote(...arguments)}async _clear(){delete this.addressCache,this.addressCache={},this.path=void 0}async _getBalances(e,t){if(void 0===e){i.equal(t,void 0,"Must provide account index with subaddress index");let e=new n(0),r=new n(0);for(let t of await this.getAccounts())e=e.add(t.getBalance()),r=r.add(t.getUnlockedBalance());return[e,r]}{let r={account_index:e,address_indices:void 0===t?void 0:[t]},i=await this.rpc.sendJsonRequest("get_balance",r);return void 0===t?[new n(i.result.balance),new n(i.result.unlocked_balance)]:[new n(i.result.per_subaddress[0].balance),new n(i.result.per_subaddress[0].unlocked_balance)]}}async _getAccountIndices(e){let t=new Map;for(let r of await this.getAccounts())t.set(r.getIndex(),e?await this._getSubaddressIndices(r.getIndex()):void 0);return t}async _getSubaddressIndices(e){let t=[],r=await this.rpc.sendJsonRequest("get_address",{account_index:e});for(let e of r.result.addresses)t.push(e.address_index);return t}async _getTransfersAux(e){let t=e.getTxQuery();if(void 0!==t.inTxPool()&&t.inTxPool()&&!await this.isConnected())throw new m("Cannot fetch pool transactions because wallet has no daemon connection");let r={},a=!1!==t.isConfirmed()&&!0!==t.inTxPool()&&!0!==t.isFailed()&&!1!==t.isRelayed(),o=await this.isConnected()&&!0!==t.isConfirmed()&&!1!==t.inTxPool()&&!0!==t.isFailed()&&!1!==t.isRelayed()&&void 0===t.getHeight()&&void 0===t.getMinHeight()&&void 0===t.getMaxHeight(),s=!1!==e.isIncoming()&&!0!==e.isOutgoing()&&!0!==e.hasDestinations(),c=!1!==e.isOutgoing()&&!0!==e.isIncoming();if(r.in=s&&a,r.out=c&&a,r.pool=s&&o,r.pending=c&&o,r.failed=!1!==t.isFailed()&&!0!==t.isConfirmed()&&1!=t.inTxPool(),void 0!==t.getMinHeight()&&(t.getMinHeight()>0?r.min_height=t.getMinHeight()-1:r.min_height=t.getMinHeight()),void 0!==t.getMaxHeight()&&(r.max_height=t.getMaxHeight()),r.filter_by_height=void 0!==t.getMinHeight()||void 0!==t.getMaxHeight(),void 0===e.getAccountIndex())i(void 0===e.getSubaddressIndex()&&void 0===e.getSubaddressIndices(),"Query specifies a subaddress index but not an account index"),r.all_accounts=!0;else{r.account_index=e.getAccountIndex();let t=new Set;void 0!==e.getSubaddressIndex()&&t.add(e.getSubaddressIndex()),void 0!==e.getSubaddressIndices()&&e.getSubaddressIndices().map(e=>t.add(e)),t.size&&(r.subaddr_indices=Array.from(t))}let u={},l={},h=await this.rpc.sendJsonRequest("get_transfers",r);for(let e of Object.keys(h.result))for(let t of h.result[e]){let e=z._convertRpcTxWithTransfer(t);if(e.isConfirmed()&&i(e.getBlock().getTxs().indexOf(e)>-1),void 0!==e.getOutgoingTransfer()&&e.isRelayed()&&!e.isFailed()&&e.getOutgoingTransfer().getDestinations()&&0===e.getOutgoingAmount().compare(new n(0))){let t=e.getOutgoingTransfer(),r=new n(0);for(let e of t.getDestinations())r=r.add(e.getAmount());e.getOutgoingTransfer().setAmount(r)}z._mergeTx(e,u,l,!1)}let d=Object.values(u);d.sort(z._compareTxsByHeight);let p=[];for(let t of d){void 0===t.isIncoming()&&t.setIsIncoming(!1),void 0===t.isOutgoing()&&t.setIsOutgoing(!1),void 0!==t.getIncomingTransfers()&&t.getIncomingTransfers().sort(z._compareIncomingTransfers);for(let r of t.filterTransfers(e))p.push(r);void 0!==t.getBlock()&&void 0===t.getOutgoingTransfer()&&void 0===t.getIncomingTransfers()&&t.getBlock().getTxs().splice(t.getBlock().getTxs().indexOf(t),1)}return p}async _getOutputsAux(e){let t=new Map;if(void 0!==e.getAccountIndex()){let r=new Set;void 0!==e.getSubaddressIndex()&&r.add(e.getSubaddressIndex()),void 0!==e.getSubaddressIndices()&&e.getSubaddressIndices().map(e=>r.add(e)),t.set(e.getAccountIndex(),r.size?Array.from(r):void 0)}else i.equal(e.getSubaddressIndex(),void 0,"Query specifies a subaddress index but not an account index"),i(void 0===e.getSubaddressIndices()||0===e.getSubaddressIndices().length,"Query specifies subaddress indices but not an account index"),t=await this._getAccountIndices();let r={},n={},a={};a.transfer_type=!0===e.isSpent()?"unavailable":!1===e.isSpent()?"available":"all",a.verbose=!0;for(let e of t.keys()){a.account_index=e,a.subaddr_indices=t.get(e);let i=await this.rpc.sendJsonRequest("incoming_transfers",a);if(void 0!==i.result.transfers)for(let e of i.result.transfers){let t=z._convertRpcTxWalletWithOutput(e);z._mergeTx(t,r,n,!1)}}let o=Object.values(r);o.sort(z._compareTxsByHeight);let s=[];for(let t of o){void 0!==t.getOutputs()&&t.getOutputs().sort(z._compareOutputs);for(let r of t.filterOutputs(e))s.push(r);void 0===t.getOutputs()&&void 0!==t.getBlock()&&t.getBlock().getTxs().splice(t.getBlock().getTxs().indexOf(t),1)}return s}async _rpcExportKeyImages(e){let t=await this.rpc.sendJsonRequest("export_key_images",{all:e});return t.result.signed_key_images?t.result.signed_key_images.map(e=>new v(e.key_image,e.signature)):[]}async _rpcSweepAccount(e){if(void 0===e)throw new m("Must provide sweep config");if(void 0===e.getAccountIndex())throw new m("Must provide an account index to sweep from");if(void 0===e.getDestinations()||1!=e.getDestinations().length)throw new m("Must provide exactly one destination to sweep to");if(void 0===e.getDestinations()[0].getAddress())throw new m("Must provide destination address to sweep to");if(void 0!==e.getDestinations()[0].getAmount())throw new m("Cannot specify amount in sweep config");if(void 0!==e.getKeyImage())throw new m("Key image defined; use sweepOutput() to sweep an output by its key image");if(void 0!==e.getSubaddressIndices()&&0===e.getSubaddressIndices().length)throw new m("Empty list given for subaddresses indices to sweep");if(e.getSweepEachSubaddress())throw new m("Cannot sweep each subaddress with RPC `sweep_all`");if(void 0===e.getSubaddressIndices()){e.setSubaddressIndices([]);for(let t of await this.getSubaddresses(e.getAccountIndex()))e.getSubaddressIndices().push(t.getIndex())}if(0===e.getSubaddressIndices().length)throw new m("No subaddresses to sweep from");let t={},r=!0===e.getRelay();t.account_index=e.getAccountIndex(),t.subaddr_indices=e.getSubaddressIndices(),t.address=e.getDestinations()[0].getAddress(),i(void 0===e.getPriority()||e.getPriority()>=0&&e.getPriority()<=3),t.priority=e.getPriority(),t.unlock_time=e.getUnlockHeight(),t.payment_id=e.getPaymentId(),t.do_not_relay=!r,t.below_amount=e.getBelowAmount(),t.get_tx_keys=!0,t.get_tx_hex=!0,t.get_tx_metadata=!0;let a=(await this.rpc.sendJsonRequest("sweep_all",t)).result,o=z._convertRpcSentTxsToTxSet(a);for(let t of o.getTxs()){t.setIsLocked(!0),t.setIsConfirmed(!1),t.setNumConfirmations(0),t.setRelay(r),t.setInTxPool(r),t.setIsRelayed(r),t.setIsMinerTx(!1),t.setIsFailed(!1),t.setRingSize(P.RING_SIZE);let i=t.getOutgoingTransfer();i.setAccountIndex(e.getAccountIndex()),1===e.getSubaddressIndices().length&&i.setSubaddressIndices(e.getSubaddressIndices());let a=new f(e.getDestinations()[0].getAddress(),new n(i.getAmount()));i.setDestinations([a]),t.setOutgoingTransfer(i),t.setPaymentId(e.getPaymentId()),void 0===t.getUnlockHeight()&&t.setUnlockHeight(void 0===e.getUnlockHeight()?0:e.getUnlockHeight()),t.getRelay()&&(void 0===t.getLastRelayedTimestamp()&&t.setLastRelayedTimestamp(+(new Date).getTime()),void 0===t.isDoubleSpendSeen()&&t.setIsDoubleSpend(!1))}return o.getTxs()}static _decontextualize(e){return e.setIsIncoming(void 0),e.setIsOutgoing(void 0),e.setTransferQuery(void 0),e.setOutputQuery(void 0),e}static _isContextual(e){if(!e)return!1;if(!e.getTxQuery())return!1;if(void 0!==e.getTxQuery().isIncoming())return!0;if(void 0!==e.getTxQuery().isOutgoing())return!0;if(e instanceof R){if(void 0!==e.getTxQuery().getOutputQuery())return!0}else{if(!(e instanceof k))throw new m("query must be tx or transfer query");if(void 0!==e.getTxQuery().getTransferQuery())return!0}return!1}static _convertRpcAccount(e){let t=new o;for(let r of Object.keys(e)){let i=e[r];"account_index"===r?t.setIndex(i):"balance"===r?t.setBalance(new n(i)):"unlocked_balance"===r?t.setUnlockedBalance(new n(i)):"base_address"===r?t.setPrimaryAddress(i):"tag"===r?t.setTag(i):"label"===r||console.log("WARNING: ignoring unexpected account field: "+r+": "+i)}return""===t.getTag()&&t.setTag(void 0),t}static _convertRpcSubaddress(e){let t=new j;for(let r of Object.keys(e)){let i=e[r];"account_index"===r?t.setAccountIndex(i):"address_index"===r?t.setIndex(i):"address"===r?t.setAddress(i):"balance"===r?t.setBalance(new n(i)):"unlocked_balance"===r?t.setUnlockedBalance(new n(i)):"num_unspent_outputs"===r?t.setNumUnspentOutputs(i):"label"===r?i&&t.setLabel(i):"used"===r?t.setIsUsed(i):"blocks_to_unlock"===r?t.setNumBlocksToUnlock(i):"time_to_unlock"==r||console.log("WARNING: ignoring unexpected subaddress field: "+r+": "+i)}return t}static _initSentTxWallet(e,t){t||(t=new A);let r=!0===e.getRelay();t.setIsOutgoing(!0),t.setIsConfirmed(!1),t.setNumConfirmations(0),t.setInTxPool(r),t.setRelay(r),t.setIsRelayed(r),t.setIsMinerTx(!1),t.setIsFailed(!1),t.setIsLocked(!0),t.setRingSize(P.RING_SIZE);let i=(new S).setTx(t);e.getSubaddressIndices()&&1===e.getSubaddressIndices().length&&i.setSubaddressIndices(e.getSubaddressIndices().slice(0));let n=[];for(let t of e.getDestinations())n.push(t.copy());return i.setDestinations(n),t.setOutgoingTransfer(i),t.setPaymentId(e.getPaymentId()),void 0===t.getUnlockHeight()&&t.setUnlockHeight(void 0===e.getUnlockHeight()?0:e.getUnlockHeight()),e.getRelay()&&(void 0===t.getLastRelayedTimestamp()&&t.setLastRelayedTimestamp(+(new Date).getTime()),void 0===t.isDoubleSpendSeen()&&t.setIsDoubleSpend(!1)),t}static _convertRpcTxSet(e){let t=new O;return t.setMultisigTxHex(e.multisig_txset),t.setUnsignedTxHex(e.unsigned_txset),t.setSignedTxHex(e.signed_txset),void 0!==t.getMultisigTxHex()&&0===t.getMultisigTxHex().length&&t.setMultisigTxHex(void 0),void 0!==t.getUnsignedTxHex()&&0===t.getUnsignedTxHex().length&&t.setUnsignedTxHex(void 0),void 0!==t.getSignedTxHex()&&0===t.getSignedTxHex().length&&t.setSignedTxHex(void 0),t}static _convertRpcSentTxsToTxSet(e,t){let r=z._convertRpcTxSet(e),a=e.fee_list?e.fee_list.length:0;if(0===a)return i.equal(t,void 0),r;if(t)r.setTxs(t);else{t=[];for(let e=0;e\n * @license MIT\n */\n/* eslint-disable no-proto */\n\n'use strict'\n\nvar base64 = require('base64-js')\nvar ieee754 = require('ieee754')\nvar isArray = require('isarray')\n\nexports.Buffer = Buffer\nexports.SlowBuffer = SlowBuffer\nexports.INSPECT_MAX_BYTES = 50\n\n/**\n * If `Buffer.TYPED_ARRAY_SUPPORT`:\n * === true Use Uint8Array implementation (fastest)\n * === false Use Object implementation (most compatible, even IE6)\n *\n * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,\n * Opera 11.6+, iOS 4.2+.\n *\n * Due to various browser bugs, sometimes the Object implementation will be used even\n * when the browser supports typed arrays.\n *\n * Note:\n *\n * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,\n * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.\n *\n * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.\n *\n * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of\n * incorrect length in some situations.\n\n * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they\n * get the Object implementation, which is slower but behaves correctly.\n */\nBuffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined\n ? global.TYPED_ARRAY_SUPPORT\n : typedArraySupport()\n\n/*\n * Export kMaxLength after typed array support is determined.\n */\nexports.kMaxLength = kMaxLength()\n\nfunction typedArraySupport () {\n try {\n var arr = new Uint8Array(1)\n arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}\n return arr.foo() === 42 && // typed array instances can be augmented\n typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`\n arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`\n } catch (e) {\n return false\n }\n}\n\nfunction kMaxLength () {\n return Buffer.TYPED_ARRAY_SUPPORT\n ? 0x7fffffff\n : 0x3fffffff\n}\n\nfunction createBuffer (that, length) {\n if (kMaxLength() < length) {\n throw new RangeError('Invalid typed array length')\n }\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = new Uint8Array(length)\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n if (that === null) {\n that = new Buffer(length)\n }\n that.length = length\n }\n\n return that\n}\n\n/**\n * The Buffer constructor returns instances of `Uint8Array` that have their\n * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of\n * `Uint8Array`, so the returned instances will have all the node `Buffer` methods\n * and the `Uint8Array` methods. Square bracket notation works as expected -- it\n * returns a single octet.\n *\n * The `Uint8Array` prototype remains unmodified.\n */\n\nfunction Buffer (arg, encodingOrOffset, length) {\n if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {\n return new Buffer(arg, encodingOrOffset, length)\n }\n\n // Common case.\n if (typeof arg === 'number') {\n if (typeof encodingOrOffset === 'string') {\n throw new Error(\n 'If encoding is specified then the first argument must be a string'\n )\n }\n return allocUnsafe(this, arg)\n }\n return from(this, arg, encodingOrOffset, length)\n}\n\nBuffer.poolSize = 8192 // not used by this implementation\n\n// TODO: Legacy, not needed anymore. Remove in next major version.\nBuffer._augment = function (arr) {\n arr.__proto__ = Buffer.prototype\n return arr\n}\n\nfunction from (that, value, encodingOrOffset, length) {\n if (typeof value === 'number') {\n throw new TypeError('\"value\" argument must not be a number')\n }\n\n if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {\n return fromArrayBuffer(that, value, encodingOrOffset, length)\n }\n\n if (typeof value === 'string') {\n return fromString(that, value, encodingOrOffset)\n }\n\n return fromObject(that, value)\n}\n\n/**\n * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError\n * if value is a number.\n * Buffer.from(str[, encoding])\n * Buffer.from(array)\n * Buffer.from(buffer)\n * Buffer.from(arrayBuffer[, byteOffset[, length]])\n **/\nBuffer.from = function (value, encodingOrOffset, length) {\n return from(null, value, encodingOrOffset, length)\n}\n\nif (Buffer.TYPED_ARRAY_SUPPORT) {\n Buffer.prototype.__proto__ = Uint8Array.prototype\n Buffer.__proto__ = Uint8Array\n if (typeof Symbol !== 'undefined' && Symbol.species &&\n Buffer[Symbol.species] === Buffer) {\n // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97\n Object.defineProperty(Buffer, Symbol.species, {\n value: null,\n configurable: true\n })\n }\n}\n\nfunction assertSize (size) {\n if (typeof size !== 'number') {\n throw new TypeError('\"size\" argument must be a number')\n } else if (size < 0) {\n throw new RangeError('\"size\" argument must not be negative')\n }\n}\n\nfunction alloc (that, size, fill, encoding) {\n assertSize(size)\n if (size <= 0) {\n return createBuffer(that, size)\n }\n if (fill !== undefined) {\n // Only pay attention to encoding if it's a string. This\n // prevents accidentally sending in a number that would\n // be interpretted as a start offset.\n return typeof encoding === 'string'\n ? createBuffer(that, size).fill(fill, encoding)\n : createBuffer(that, size).fill(fill)\n }\n return createBuffer(that, size)\n}\n\n/**\n * Creates a new filled Buffer instance.\n * alloc(size[, fill[, encoding]])\n **/\nBuffer.alloc = function (size, fill, encoding) {\n return alloc(null, size, fill, encoding)\n}\n\nfunction allocUnsafe (that, size) {\n assertSize(size)\n that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) {\n for (var i = 0; i < size; ++i) {\n that[i] = 0\n }\n }\n return that\n}\n\n/**\n * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.\n * */\nBuffer.allocUnsafe = function (size) {\n return allocUnsafe(null, size)\n}\n/**\n * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.\n */\nBuffer.allocUnsafeSlow = function (size) {\n return allocUnsafe(null, size)\n}\n\nfunction fromString (that, string, encoding) {\n if (typeof encoding !== 'string' || encoding === '') {\n encoding = 'utf8'\n }\n\n if (!Buffer.isEncoding(encoding)) {\n throw new TypeError('\"encoding\" must be a valid string encoding')\n }\n\n var length = byteLength(string, encoding) | 0\n that = createBuffer(that, length)\n\n var actual = that.write(string, encoding)\n\n if (actual !== length) {\n // Writing a hex string, for example, that contains invalid characters will\n // cause everything after the first invalid character to be ignored. (e.g.\n // 'abxxcd' will be treated as 'ab')\n that = that.slice(0, actual)\n }\n\n return that\n}\n\nfunction fromArrayLike (that, array) {\n var length = array.length < 0 ? 0 : checked(array.length) | 0\n that = createBuffer(that, length)\n for (var i = 0; i < length; i += 1) {\n that[i] = array[i] & 255\n }\n return that\n}\n\nfunction fromArrayBuffer (that, array, byteOffset, length) {\n array.byteLength // this throws if `array` is not a valid ArrayBuffer\n\n if (byteOffset < 0 || array.byteLength < byteOffset) {\n throw new RangeError('\\'offset\\' is out of bounds')\n }\n\n if (array.byteLength < byteOffset + (length || 0)) {\n throw new RangeError('\\'length\\' is out of bounds')\n }\n\n if (byteOffset === undefined && length === undefined) {\n array = new Uint8Array(array)\n } else if (length === undefined) {\n array = new Uint8Array(array, byteOffset)\n } else {\n array = new Uint8Array(array, byteOffset, length)\n }\n\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n // Return an augmented `Uint8Array` instance, for best performance\n that = array\n that.__proto__ = Buffer.prototype\n } else {\n // Fallback: Return an object instance of the Buffer class\n that = fromArrayLike(that, array)\n }\n return that\n}\n\nfunction fromObject (that, obj) {\n if (Buffer.isBuffer(obj)) {\n var len = checked(obj.length) | 0\n that = createBuffer(that, len)\n\n if (that.length === 0) {\n return that\n }\n\n obj.copy(that, 0, 0, len)\n return that\n }\n\n if (obj) {\n if ((typeof ArrayBuffer !== 'undefined' &&\n obj.buffer instanceof ArrayBuffer) || 'length' in obj) {\n if (typeof obj.length !== 'number' || isnan(obj.length)) {\n return createBuffer(that, 0)\n }\n return fromArrayLike(that, obj)\n }\n\n if (obj.type === 'Buffer' && isArray(obj.data)) {\n return fromArrayLike(that, obj.data)\n }\n }\n\n throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')\n}\n\nfunction checked (length) {\n // Note: cannot use `length < kMaxLength()` here because that fails when\n // length is NaN (which is otherwise coerced to zero.)\n if (length >= kMaxLength()) {\n throw new RangeError('Attempt to allocate Buffer larger than maximum ' +\n 'size: 0x' + kMaxLength().toString(16) + ' bytes')\n }\n return length | 0\n}\n\nfunction SlowBuffer (length) {\n if (+length != length) { // eslint-disable-line eqeqeq\n length = 0\n }\n return Buffer.alloc(+length)\n}\n\nBuffer.isBuffer = function isBuffer (b) {\n return !!(b != null && b._isBuffer)\n}\n\nBuffer.compare = function compare (a, b) {\n if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {\n throw new TypeError('Arguments must be Buffers')\n }\n\n if (a === b) return 0\n\n var x = a.length\n var y = b.length\n\n for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i]\n y = b[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\nBuffer.isEncoding = function isEncoding (encoding) {\n switch (String(encoding).toLowerCase()) {\n case 'hex':\n case 'utf8':\n case 'utf-8':\n case 'ascii':\n case 'latin1':\n case 'binary':\n case 'base64':\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return true\n default:\n return false\n }\n}\n\nBuffer.concat = function concat (list, length) {\n if (!isArray(list)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n\n if (list.length === 0) {\n return Buffer.alloc(0)\n }\n\n var i\n if (length === undefined) {\n length = 0\n for (i = 0; i < list.length; ++i) {\n length += list[i].length\n }\n }\n\n var buffer = Buffer.allocUnsafe(length)\n var pos = 0\n for (i = 0; i < list.length; ++i) {\n var buf = list[i]\n if (!Buffer.isBuffer(buf)) {\n throw new TypeError('\"list\" argument must be an Array of Buffers')\n }\n buf.copy(buffer, pos)\n pos += buf.length\n }\n return buffer\n}\n\nfunction byteLength (string, encoding) {\n if (Buffer.isBuffer(string)) {\n return string.length\n }\n if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&\n (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {\n return string.byteLength\n }\n if (typeof string !== 'string') {\n string = '' + string\n }\n\n var len = string.length\n if (len === 0) return 0\n\n // Use a for loop to avoid recursion\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'ascii':\n case 'latin1':\n case 'binary':\n return len\n case 'utf8':\n case 'utf-8':\n case undefined:\n return utf8ToBytes(string).length\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return len * 2\n case 'hex':\n return len >>> 1\n case 'base64':\n return base64ToBytes(string).length\n default:\n if (loweredCase) return utf8ToBytes(string).length // assume utf8\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\nBuffer.byteLength = byteLength\n\nfunction slowToString (encoding, start, end) {\n var loweredCase = false\n\n // No need to verify that \"this.length <= MAX_UINT32\" since it's a read-only\n // property of a typed array.\n\n // This behaves neither like String nor Uint8Array in that we set start/end\n // to their upper/lower bounds if the value passed is out of range.\n // undefined is handled specially as per ECMA-262 6th Edition,\n // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.\n if (start === undefined || start < 0) {\n start = 0\n }\n // Return early if start > this.length. Done here to prevent potential uint32\n // coercion fail below.\n if (start > this.length) {\n return ''\n }\n\n if (end === undefined || end > this.length) {\n end = this.length\n }\n\n if (end <= 0) {\n return ''\n }\n\n // Force coersion to uint32. This will also coerce falsey/NaN values to 0.\n end >>>= 0\n start >>>= 0\n\n if (end <= start) {\n return ''\n }\n\n if (!encoding) encoding = 'utf8'\n\n while (true) {\n switch (encoding) {\n case 'hex':\n return hexSlice(this, start, end)\n\n case 'utf8':\n case 'utf-8':\n return utf8Slice(this, start, end)\n\n case 'ascii':\n return asciiSlice(this, start, end)\n\n case 'latin1':\n case 'binary':\n return latin1Slice(this, start, end)\n\n case 'base64':\n return base64Slice(this, start, end)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return utf16leSlice(this, start, end)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = (encoding + '').toLowerCase()\n loweredCase = true\n }\n }\n}\n\n// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect\n// Buffer instances.\nBuffer.prototype._isBuffer = true\n\nfunction swap (b, n, m) {\n var i = b[n]\n b[n] = b[m]\n b[m] = i\n}\n\nBuffer.prototype.swap16 = function swap16 () {\n var len = this.length\n if (len % 2 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 16-bits')\n }\n for (var i = 0; i < len; i += 2) {\n swap(this, i, i + 1)\n }\n return this\n}\n\nBuffer.prototype.swap32 = function swap32 () {\n var len = this.length\n if (len % 4 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 32-bits')\n }\n for (var i = 0; i < len; i += 4) {\n swap(this, i, i + 3)\n swap(this, i + 1, i + 2)\n }\n return this\n}\n\nBuffer.prototype.swap64 = function swap64 () {\n var len = this.length\n if (len % 8 !== 0) {\n throw new RangeError('Buffer size must be a multiple of 64-bits')\n }\n for (var i = 0; i < len; i += 8) {\n swap(this, i, i + 7)\n swap(this, i + 1, i + 6)\n swap(this, i + 2, i + 5)\n swap(this, i + 3, i + 4)\n }\n return this\n}\n\nBuffer.prototype.toString = function toString () {\n var length = this.length | 0\n if (length === 0) return ''\n if (arguments.length === 0) return utf8Slice(this, 0, length)\n return slowToString.apply(this, arguments)\n}\n\nBuffer.prototype.equals = function equals (b) {\n if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')\n if (this === b) return true\n return Buffer.compare(this, b) === 0\n}\n\nBuffer.prototype.inspect = function inspect () {\n var str = ''\n var max = exports.INSPECT_MAX_BYTES\n if (this.length > 0) {\n str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')\n if (this.length > max) str += ' ... '\n }\n return ''\n}\n\nBuffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {\n if (!Buffer.isBuffer(target)) {\n throw new TypeError('Argument must be a Buffer')\n }\n\n if (start === undefined) {\n start = 0\n }\n if (end === undefined) {\n end = target ? target.length : 0\n }\n if (thisStart === undefined) {\n thisStart = 0\n }\n if (thisEnd === undefined) {\n thisEnd = this.length\n }\n\n if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {\n throw new RangeError('out of range index')\n }\n\n if (thisStart >= thisEnd && start >= end) {\n return 0\n }\n if (thisStart >= thisEnd) {\n return -1\n }\n if (start >= end) {\n return 1\n }\n\n start >>>= 0\n end >>>= 0\n thisStart >>>= 0\n thisEnd >>>= 0\n\n if (this === target) return 0\n\n var x = thisEnd - thisStart\n var y = end - start\n var len = Math.min(x, y)\n\n var thisCopy = this.slice(thisStart, thisEnd)\n var targetCopy = target.slice(start, end)\n\n for (var i = 0; i < len; ++i) {\n if (thisCopy[i] !== targetCopy[i]) {\n x = thisCopy[i]\n y = targetCopy[i]\n break\n }\n }\n\n if (x < y) return -1\n if (y < x) return 1\n return 0\n}\n\n// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,\n// OR the last index of `val` in `buffer` at offset <= `byteOffset`.\n//\n// Arguments:\n// - buffer - a Buffer to search\n// - val - a string, Buffer, or number\n// - byteOffset - an index into `buffer`; will be clamped to an int32\n// - encoding - an optional encoding, relevant is val is a string\n// - dir - true for indexOf, false for lastIndexOf\nfunction bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {\n // Empty buffer means no match\n if (buffer.length === 0) return -1\n\n // Normalize byteOffset\n if (typeof byteOffset === 'string') {\n encoding = byteOffset\n byteOffset = 0\n } else if (byteOffset > 0x7fffffff) {\n byteOffset = 0x7fffffff\n } else if (byteOffset < -0x80000000) {\n byteOffset = -0x80000000\n }\n byteOffset = +byteOffset // Coerce to Number.\n if (isNaN(byteOffset)) {\n // byteOffset: it it's undefined, null, NaN, \"foo\", etc, search whole buffer\n byteOffset = dir ? 0 : (buffer.length - 1)\n }\n\n // Normalize byteOffset: negative offsets start from the end of the buffer\n if (byteOffset < 0) byteOffset = buffer.length + byteOffset\n if (byteOffset >= buffer.length) {\n if (dir) return -1\n else byteOffset = buffer.length - 1\n } else if (byteOffset < 0) {\n if (dir) byteOffset = 0\n else return -1\n }\n\n // Normalize val\n if (typeof val === 'string') {\n val = Buffer.from(val, encoding)\n }\n\n // Finally, search either indexOf (if dir is true) or lastIndexOf\n if (Buffer.isBuffer(val)) {\n // Special case: looking for empty string/buffer always fails\n if (val.length === 0) {\n return -1\n }\n return arrayIndexOf(buffer, val, byteOffset, encoding, dir)\n } else if (typeof val === 'number') {\n val = val & 0xFF // Search for a byte value [0-255]\n if (Buffer.TYPED_ARRAY_SUPPORT &&\n typeof Uint8Array.prototype.indexOf === 'function') {\n if (dir) {\n return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)\n } else {\n return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)\n }\n }\n return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)\n }\n\n throw new TypeError('val must be string, number or Buffer')\n}\n\nfunction arrayIndexOf (arr, val, byteOffset, encoding, dir) {\n var indexSize = 1\n var arrLength = arr.length\n var valLength = val.length\n\n if (encoding !== undefined) {\n encoding = String(encoding).toLowerCase()\n if (encoding === 'ucs2' || encoding === 'ucs-2' ||\n encoding === 'utf16le' || encoding === 'utf-16le') {\n if (arr.length < 2 || val.length < 2) {\n return -1\n }\n indexSize = 2\n arrLength /= 2\n valLength /= 2\n byteOffset /= 2\n }\n }\n\n function read (buf, i) {\n if (indexSize === 1) {\n return buf[i]\n } else {\n return buf.readUInt16BE(i * indexSize)\n }\n }\n\n var i\n if (dir) {\n var foundIndex = -1\n for (i = byteOffset; i < arrLength; i++) {\n if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {\n if (foundIndex === -1) foundIndex = i\n if (i - foundIndex + 1 === valLength) return foundIndex * indexSize\n } else {\n if (foundIndex !== -1) i -= i - foundIndex\n foundIndex = -1\n }\n }\n } else {\n if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength\n for (i = byteOffset; i >= 0; i--) {\n var found = true\n for (var j = 0; j < valLength; j++) {\n if (read(arr, i + j) !== read(val, j)) {\n found = false\n break\n }\n }\n if (found) return i\n }\n }\n\n return -1\n}\n\nBuffer.prototype.includes = function includes (val, byteOffset, encoding) {\n return this.indexOf(val, byteOffset, encoding) !== -1\n}\n\nBuffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {\n return bidirectionalIndexOf(this, val, byteOffset, encoding, true)\n}\n\nBuffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {\n return bidirectionalIndexOf(this, val, byteOffset, encoding, false)\n}\n\nfunction hexWrite (buf, string, offset, length) {\n offset = Number(offset) || 0\n var remaining = buf.length - offset\n if (!length) {\n length = remaining\n } else {\n length = Number(length)\n if (length > remaining) {\n length = remaining\n }\n }\n\n // must be an even number of digits\n var strLen = string.length\n if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')\n\n if (length > strLen / 2) {\n length = strLen / 2\n }\n for (var i = 0; i < length; ++i) {\n var parsed = parseInt(string.substr(i * 2, 2), 16)\n if (isNaN(parsed)) return i\n buf[offset + i] = parsed\n }\n return i\n}\n\nfunction utf8Write (buf, string, offset, length) {\n return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nfunction asciiWrite (buf, string, offset, length) {\n return blitBuffer(asciiToBytes(string), buf, offset, length)\n}\n\nfunction latin1Write (buf, string, offset, length) {\n return asciiWrite(buf, string, offset, length)\n}\n\nfunction base64Write (buf, string, offset, length) {\n return blitBuffer(base64ToBytes(string), buf, offset, length)\n}\n\nfunction ucs2Write (buf, string, offset, length) {\n return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)\n}\n\nBuffer.prototype.write = function write (string, offset, length, encoding) {\n // Buffer#write(string)\n if (offset === undefined) {\n encoding = 'utf8'\n length = this.length\n offset = 0\n // Buffer#write(string, encoding)\n } else if (length === undefined && typeof offset === 'string') {\n encoding = offset\n length = this.length\n offset = 0\n // Buffer#write(string, offset[, length][, encoding])\n } else if (isFinite(offset)) {\n offset = offset | 0\n if (isFinite(length)) {\n length = length | 0\n if (encoding === undefined) encoding = 'utf8'\n } else {\n encoding = length\n length = undefined\n }\n // legacy write(string, encoding, offset, length) - remove in v0.13\n } else {\n throw new Error(\n 'Buffer.write(string, encoding, offset[, length]) is no longer supported'\n )\n }\n\n var remaining = this.length - offset\n if (length === undefined || length > remaining) length = remaining\n\n if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {\n throw new RangeError('Attempt to write outside buffer bounds')\n }\n\n if (!encoding) encoding = 'utf8'\n\n var loweredCase = false\n for (;;) {\n switch (encoding) {\n case 'hex':\n return hexWrite(this, string, offset, length)\n\n case 'utf8':\n case 'utf-8':\n return utf8Write(this, string, offset, length)\n\n case 'ascii':\n return asciiWrite(this, string, offset, length)\n\n case 'latin1':\n case 'binary':\n return latin1Write(this, string, offset, length)\n\n case 'base64':\n // Warning: maxLength not taken into account in base64Write\n return base64Write(this, string, offset, length)\n\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return ucs2Write(this, string, offset, length)\n\n default:\n if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)\n encoding = ('' + encoding).toLowerCase()\n loweredCase = true\n }\n }\n}\n\nBuffer.prototype.toJSON = function toJSON () {\n return {\n type: 'Buffer',\n data: Array.prototype.slice.call(this._arr || this, 0)\n }\n}\n\nfunction base64Slice (buf, start, end) {\n if (start === 0 && end === buf.length) {\n return base64.fromByteArray(buf)\n } else {\n return base64.fromByteArray(buf.slice(start, end))\n }\n}\n\nfunction utf8Slice (buf, start, end) {\n end = Math.min(buf.length, end)\n var res = []\n\n var i = start\n while (i < end) {\n var firstByte = buf[i]\n var codePoint = null\n var bytesPerSequence = (firstByte > 0xEF) ? 4\n : (firstByte > 0xDF) ? 3\n : (firstByte > 0xBF) ? 2\n : 1\n\n if (i + bytesPerSequence <= end) {\n var secondByte, thirdByte, fourthByte, tempCodePoint\n\n switch (bytesPerSequence) {\n case 1:\n if (firstByte < 0x80) {\n codePoint = firstByte\n }\n break\n case 2:\n secondByte = buf[i + 1]\n if ((secondByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)\n if (tempCodePoint > 0x7F) {\n codePoint = tempCodePoint\n }\n }\n break\n case 3:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)\n if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {\n codePoint = tempCodePoint\n }\n }\n break\n case 4:\n secondByte = buf[i + 1]\n thirdByte = buf[i + 2]\n fourthByte = buf[i + 3]\n if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {\n tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)\n if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {\n codePoint = tempCodePoint\n }\n }\n }\n }\n\n if (codePoint === null) {\n // we did not generate a valid codePoint so insert a\n // replacement char (U+FFFD) and advance only 1 byte\n codePoint = 0xFFFD\n bytesPerSequence = 1\n } else if (codePoint > 0xFFFF) {\n // encode to utf16 (surrogate pair dance)\n codePoint -= 0x10000\n res.push(codePoint >>> 10 & 0x3FF | 0xD800)\n codePoint = 0xDC00 | codePoint & 0x3FF\n }\n\n res.push(codePoint)\n i += bytesPerSequence\n }\n\n return decodeCodePointsArray(res)\n}\n\n// Based on http://stackoverflow.com/a/22747272/680742, the browser with\n// the lowest limit is Chrome, with 0x10000 args.\n// We go 1 magnitude less, for safety\nvar MAX_ARGUMENTS_LENGTH = 0x1000\n\nfunction decodeCodePointsArray (codePoints) {\n var len = codePoints.length\n if (len <= MAX_ARGUMENTS_LENGTH) {\n return String.fromCharCode.apply(String, codePoints) // avoid extra slice()\n }\n\n // Decode in chunks to avoid \"call stack size exceeded\".\n var res = ''\n var i = 0\n while (i < len) {\n res += String.fromCharCode.apply(\n String,\n codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)\n )\n }\n return res\n}\n\nfunction asciiSlice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i] & 0x7F)\n }\n return ret\n}\n\nfunction latin1Slice (buf, start, end) {\n var ret = ''\n end = Math.min(buf.length, end)\n\n for (var i = start; i < end; ++i) {\n ret += String.fromCharCode(buf[i])\n }\n return ret\n}\n\nfunction hexSlice (buf, start, end) {\n var len = buf.length\n\n if (!start || start < 0) start = 0\n if (!end || end < 0 || end > len) end = len\n\n var out = ''\n for (var i = start; i < end; ++i) {\n out += toHex(buf[i])\n }\n return out\n}\n\nfunction utf16leSlice (buf, start, end) {\n var bytes = buf.slice(start, end)\n var res = ''\n for (var i = 0; i < bytes.length; i += 2) {\n res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)\n }\n return res\n}\n\nBuffer.prototype.slice = function slice (start, end) {\n var len = this.length\n start = ~~start\n end = end === undefined ? len : ~~end\n\n if (start < 0) {\n start += len\n if (start < 0) start = 0\n } else if (start > len) {\n start = len\n }\n\n if (end < 0) {\n end += len\n if (end < 0) end = 0\n } else if (end > len) {\n end = len\n }\n\n if (end < start) end = start\n\n var newBuf\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n newBuf = this.subarray(start, end)\n newBuf.__proto__ = Buffer.prototype\n } else {\n var sliceLen = end - start\n newBuf = new Buffer(sliceLen, undefined)\n for (var i = 0; i < sliceLen; ++i) {\n newBuf[i] = this[i + start]\n }\n }\n\n return newBuf\n}\n\n/*\n * Need to make sure that buffer isn't trying to write out of bounds.\n */\nfunction checkOffset (offset, ext, length) {\n if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')\n if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')\n}\n\nBuffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n checkOffset(offset, byteLength, this.length)\n }\n\n var val = this[offset + --byteLength]\n var mul = 1\n while (byteLength > 0 && (mul *= 0x100)) {\n val += this[offset + --byteLength] * mul\n }\n\n return val\n}\n\nBuffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n return this[offset]\n}\n\nBuffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return this[offset] | (this[offset + 1] << 8)\n}\n\nBuffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n return (this[offset] << 8) | this[offset + 1]\n}\n\nBuffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return ((this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16)) +\n (this[offset + 3] * 0x1000000)\n}\n\nBuffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] * 0x1000000) +\n ((this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n this[offset + 3])\n}\n\nBuffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var val = this[offset]\n var mul = 1\n var i = 0\n while (++i < byteLength && (mul *= 0x100)) {\n val += this[offset + i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) checkOffset(offset, byteLength, this.length)\n\n var i = byteLength\n var mul = 1\n var val = this[offset + --i]\n while (i > 0 && (mul *= 0x100)) {\n val += this[offset + --i] * mul\n }\n mul *= 0x80\n\n if (val >= mul) val -= Math.pow(2, 8 * byteLength)\n\n return val\n}\n\nBuffer.prototype.readInt8 = function readInt8 (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 1, this.length)\n if (!(this[offset] & 0x80)) return (this[offset])\n return ((0xff - this[offset] + 1) * -1)\n}\n\nBuffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset] | (this[offset + 1] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 2, this.length)\n var val = this[offset + 1] | (this[offset] << 8)\n return (val & 0x8000) ? val | 0xFFFF0000 : val\n}\n\nBuffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset]) |\n (this[offset + 1] << 8) |\n (this[offset + 2] << 16) |\n (this[offset + 3] << 24)\n}\n\nBuffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n\n return (this[offset] << 24) |\n (this[offset + 1] << 16) |\n (this[offset + 2] << 8) |\n (this[offset + 3])\n}\n\nBuffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, true, 23, 4)\n}\n\nBuffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 4, this.length)\n return ieee754.read(this, offset, false, 23, 4)\n}\n\nBuffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, true, 52, 8)\n}\n\nBuffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {\n if (!noAssert) checkOffset(offset, 8, this.length)\n return ieee754.read(this, offset, false, 52, 8)\n}\n\nfunction checkInt (buf, value, offset, ext, max, min) {\n if (!Buffer.isBuffer(buf)) throw new TypeError('\"buffer\" argument must be a Buffer instance')\n if (value > max || value < min) throw new RangeError('\"value\" argument is out of bounds')\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n}\n\nBuffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var mul = 1\n var i = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n byteLength = byteLength | 0\n if (!noAssert) {\n var maxBytes = Math.pow(2, 8 * byteLength) - 1\n checkInt(this, value, offset, byteLength, maxBytes, 0)\n }\n\n var i = byteLength - 1\n var mul = 1\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n this[offset + i] = (value / mul) & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nfunction objectWriteUInt16 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {\n buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>\n (littleEndian ? i : 1 - i) * 8\n }\n}\n\nBuffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nfunction objectWriteUInt32 (buf, value, offset, littleEndian) {\n if (value < 0) value = 0xffffffff + value + 1\n for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {\n buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff\n }\n}\n\nBuffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset + 3] = (value >>> 24)\n this[offset + 2] = (value >>> 16)\n this[offset + 1] = (value >>> 8)\n this[offset] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = 0\n var mul = 1\n var sub = 0\n this[offset] = value & 0xFF\n while (++i < byteLength && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) {\n var limit = Math.pow(2, 8 * byteLength - 1)\n\n checkInt(this, value, offset, byteLength, limit - 1, -limit)\n }\n\n var i = byteLength - 1\n var mul = 1\n var sub = 0\n this[offset + i] = value & 0xFF\n while (--i >= 0 && (mul *= 0x100)) {\n if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {\n sub = 1\n }\n this[offset + i] = ((value / mul) >> 0) - sub & 0xFF\n }\n\n return offset + byteLength\n}\n\nBuffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)\n if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)\n if (value < 0) value = 0xff + value + 1\n this[offset] = (value & 0xff)\n return offset + 1\n}\n\nBuffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n } else {\n objectWriteUInt16(this, value, offset, true)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 8)\n this[offset + 1] = (value & 0xff)\n } else {\n objectWriteUInt16(this, value, offset, false)\n }\n return offset + 2\n}\n\nBuffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value & 0xff)\n this[offset + 1] = (value >>> 8)\n this[offset + 2] = (value >>> 16)\n this[offset + 3] = (value >>> 24)\n } else {\n objectWriteUInt32(this, value, offset, true)\n }\n return offset + 4\n}\n\nBuffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {\n value = +value\n offset = offset | 0\n if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)\n if (value < 0) value = 0xffffffff + value + 1\n if (Buffer.TYPED_ARRAY_SUPPORT) {\n this[offset] = (value >>> 24)\n this[offset + 1] = (value >>> 16)\n this[offset + 2] = (value >>> 8)\n this[offset + 3] = (value & 0xff)\n } else {\n objectWriteUInt32(this, value, offset, false)\n }\n return offset + 4\n}\n\nfunction checkIEEE754 (buf, value, offset, ext, max, min) {\n if (offset + ext > buf.length) throw new RangeError('Index out of range')\n if (offset < 0) throw new RangeError('Index out of range')\n}\n\nfunction writeFloat (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)\n }\n ieee754.write(buf, value, offset, littleEndian, 23, 4)\n return offset + 4\n}\n\nBuffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {\n return writeFloat(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {\n return writeFloat(this, value, offset, false, noAssert)\n}\n\nfunction writeDouble (buf, value, offset, littleEndian, noAssert) {\n if (!noAssert) {\n checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)\n }\n ieee754.write(buf, value, offset, littleEndian, 52, 8)\n return offset + 8\n}\n\nBuffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {\n return writeDouble(this, value, offset, true, noAssert)\n}\n\nBuffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {\n return writeDouble(this, value, offset, false, noAssert)\n}\n\n// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)\nBuffer.prototype.copy = function copy (target, targetStart, start, end) {\n if (!start) start = 0\n if (!end && end !== 0) end = this.length\n if (targetStart >= target.length) targetStart = target.length\n if (!targetStart) targetStart = 0\n if (end > 0 && end < start) end = start\n\n // Copy 0 bytes; we're done\n if (end === start) return 0\n if (target.length === 0 || this.length === 0) return 0\n\n // Fatal error conditions\n if (targetStart < 0) {\n throw new RangeError('targetStart out of bounds')\n }\n if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')\n if (end < 0) throw new RangeError('sourceEnd out of bounds')\n\n // Are we oob?\n if (end > this.length) end = this.length\n if (target.length - targetStart < end - start) {\n end = target.length - targetStart + start\n }\n\n var len = end - start\n var i\n\n if (this === target && start < targetStart && targetStart < end) {\n // descending copy from end\n for (i = len - 1; i >= 0; --i) {\n target[i + targetStart] = this[i + start]\n }\n } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {\n // ascending copy from start\n for (i = 0; i < len; ++i) {\n target[i + targetStart] = this[i + start]\n }\n } else {\n Uint8Array.prototype.set.call(\n target,\n this.subarray(start, start + len),\n targetStart\n )\n }\n\n return len\n}\n\n// Usage:\n// buffer.fill(number[, offset[, end]])\n// buffer.fill(buffer[, offset[, end]])\n// buffer.fill(string[, offset[, end]][, encoding])\nBuffer.prototype.fill = function fill (val, start, end, encoding) {\n // Handle string cases:\n if (typeof val === 'string') {\n if (typeof start === 'string') {\n encoding = start\n start = 0\n end = this.length\n } else if (typeof end === 'string') {\n encoding = end\n end = this.length\n }\n if (val.length === 1) {\n var code = val.charCodeAt(0)\n if (code < 256) {\n val = code\n }\n }\n if (encoding !== undefined && typeof encoding !== 'string') {\n throw new TypeError('encoding must be a string')\n }\n if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {\n throw new TypeError('Unknown encoding: ' + encoding)\n }\n } else if (typeof val === 'number') {\n val = val & 255\n }\n\n // Invalid ranges are not set to a default, so can range check early.\n if (start < 0 || this.length < start || this.length < end) {\n throw new RangeError('Out of range index')\n }\n\n if (end <= start) {\n return this\n }\n\n start = start >>> 0\n end = end === undefined ? this.length : end >>> 0\n\n if (!val) val = 0\n\n var i\n if (typeof val === 'number') {\n for (i = start; i < end; ++i) {\n this[i] = val\n }\n } else {\n var bytes = Buffer.isBuffer(val)\n ? val\n : utf8ToBytes(new Buffer(val, encoding).toString())\n var len = bytes.length\n for (i = 0; i < end - start; ++i) {\n this[i + start] = bytes[i % len]\n }\n }\n\n return this\n}\n\n// HELPER FUNCTIONS\n// ================\n\nvar INVALID_BASE64_RE = /[^+\\/0-9A-Za-z-_]/g\n\nfunction base64clean (str) {\n // Node strips out invalid characters like \\n and \\t from the string, base64-js does not\n str = stringtrim(str).replace(INVALID_BASE64_RE, '')\n // Node converts strings with length < 2 to ''\n if (str.length < 2) return ''\n // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not\n while (str.length % 4 !== 0) {\n str = str + '='\n }\n return str\n}\n\nfunction stringtrim (str) {\n if (str.trim) return str.trim()\n return str.replace(/^\\s+|\\s+$/g, '')\n}\n\nfunction toHex (n) {\n if (n < 16) return '0' + n.toString(16)\n return n.toString(16)\n}\n\nfunction utf8ToBytes (string, units) {\n units = units || Infinity\n var codePoint\n var length = string.length\n var leadSurrogate = null\n var bytes = []\n\n for (var i = 0; i < length; ++i) {\n codePoint = string.charCodeAt(i)\n\n // is surrogate component\n if (codePoint > 0xD7FF && codePoint < 0xE000) {\n // last char was a lead\n if (!leadSurrogate) {\n // no lead yet\n if (codePoint > 0xDBFF) {\n // unexpected trail\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n } else if (i + 1 === length) {\n // unpaired lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n continue\n }\n\n // valid lead\n leadSurrogate = codePoint\n\n continue\n }\n\n // 2 leads in a row\n if (codePoint < 0xDC00) {\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n leadSurrogate = codePoint\n continue\n }\n\n // valid surrogate pair\n codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000\n } else if (leadSurrogate) {\n // valid bmp char, but last char was a lead\n if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)\n }\n\n leadSurrogate = null\n\n // encode utf8\n if (codePoint < 0x80) {\n if ((units -= 1) < 0) break\n bytes.push(codePoint)\n } else if (codePoint < 0x800) {\n if ((units -= 2) < 0) break\n bytes.push(\n codePoint >> 0x6 | 0xC0,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x10000) {\n if ((units -= 3) < 0) break\n bytes.push(\n codePoint >> 0xC | 0xE0,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else if (codePoint < 0x110000) {\n if ((units -= 4) < 0) break\n bytes.push(\n codePoint >> 0x12 | 0xF0,\n codePoint >> 0xC & 0x3F | 0x80,\n codePoint >> 0x6 & 0x3F | 0x80,\n codePoint & 0x3F | 0x80\n )\n } else {\n throw new Error('Invalid code point')\n }\n }\n\n return bytes\n}\n\nfunction asciiToBytes (str) {\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n // Node's code seems to be doing this and not & 0x7F..\n byteArray.push(str.charCodeAt(i) & 0xFF)\n }\n return byteArray\n}\n\nfunction utf16leToBytes (str, units) {\n var c, hi, lo\n var byteArray = []\n for (var i = 0; i < str.length; ++i) {\n if ((units -= 2) < 0) break\n\n c = str.charCodeAt(i)\n hi = c >> 8\n lo = c % 256\n byteArray.push(lo)\n byteArray.push(hi)\n }\n\n return byteArray\n}\n\nfunction base64ToBytes (str) {\n return base64.toByteArray(base64clean(str))\n}\n\nfunction blitBuffer (src, dst, offset, length) {\n for (var i = 0; i < length; ++i) {\n if ((i + offset >= dst.length) || (i >= src.length)) break\n dst[i + offset] = src[i]\n }\n return i\n}\n\nfunction isnan (val) {\n return val !== val // eslint-disable-line no-self-compare\n}\n","// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things. But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals. It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n throw new Error('clearTimeout has not been defined');\n}\n(function () {\n try {\n if (typeof setTimeout === 'function') {\n cachedSetTimeout = setTimeout;\n } else {\n cachedSetTimeout = defaultSetTimout;\n }\n } catch (e) {\n cachedSetTimeout = defaultSetTimout;\n }\n try {\n if (typeof clearTimeout === 'function') {\n cachedClearTimeout = clearTimeout;\n } else {\n cachedClearTimeout = defaultClearTimeout;\n }\n } catch (e) {\n cachedClearTimeout = defaultClearTimeout;\n }\n} ())\nfunction runTimeout(fun) {\n if (cachedSetTimeout === setTimeout) {\n //normal enviroments in sane situations\n return setTimeout(fun, 0);\n }\n // if setTimeout wasn't available but was latter defined\n if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n cachedSetTimeout = setTimeout;\n return setTimeout(fun, 0);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedSetTimeout(fun, 0);\n } catch(e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedSetTimeout.call(null, fun, 0);\n } catch(e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n return cachedSetTimeout.call(this, fun, 0);\n }\n }\n\n\n}\nfunction runClearTimeout(marker) {\n if (cachedClearTimeout === clearTimeout) {\n //normal enviroments in sane situations\n return clearTimeout(marker);\n }\n // if clearTimeout wasn't available but was latter defined\n if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n cachedClearTimeout = clearTimeout;\n return clearTimeout(marker);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedClearTimeout(marker);\n } catch (e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedClearTimeout.call(null, marker);\n } catch (e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n return cachedClearTimeout.call(this, marker);\n }\n }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n if (!draining || !currentQueue) {\n return;\n }\n draining = false;\n if (currentQueue.length) {\n queue = currentQueue.concat(queue);\n } else {\n queueIndex = -1;\n }\n if (queue.length) {\n drainQueue();\n }\n}\n\nfunction drainQueue() {\n if (draining) {\n return;\n }\n var timeout = runTimeout(cleanUpNextTick);\n draining = true;\n\n var len = queue.length;\n while(len) {\n currentQueue = queue;\n queue = [];\n while (++queueIndex < len) {\n if (currentQueue) {\n currentQueue[queueIndex].run();\n }\n }\n queueIndex = -1;\n len = queue.length;\n }\n currentQueue = null;\n draining = false;\n runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n var args = new Array(arguments.length - 1);\n if (arguments.length > 1) {\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n }\n queue.push(new Item(fun, args));\n if (queue.length === 1 && !draining) {\n runTimeout(drainQueue);\n }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n this.fun = fun;\n this.array = array;\n}\nItem.prototype.run = function () {\n this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\nprocess.prependListener = noop;\nprocess.prependOnceListener = noop;\n\nprocess.listeners = function (name) { return [] }\n\nprocess.binding = function (name) {\n throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n","'use strict';\n\nvar objectAssign = require('object-assign');\n\n// compare and isBuffer taken from https://github.com/feross/buffer/blob/680e9e5e488f22aac27599a57dc844a6315928dd/index.js\n// original notice:\n\n/*!\n * The buffer module from node.js, for the browser.\n *\n * @author Feross Aboukhadijeh \n * @license MIT\n */\nfunction compare(a, b) {\n if (a === b) {\n return 0;\n }\n\n var x = a.length;\n var y = b.length;\n\n for (var i = 0, len = Math.min(x, y); i < len; ++i) {\n if (a[i] !== b[i]) {\n x = a[i];\n y = b[i];\n break;\n }\n }\n\n if (x < y) {\n return -1;\n }\n if (y < x) {\n return 1;\n }\n return 0;\n}\nfunction isBuffer(b) {\n if (global.Buffer && typeof global.Buffer.isBuffer === 'function') {\n return global.Buffer.isBuffer(b);\n }\n return !!(b != null && b._isBuffer);\n}\n\n// based on node assert, original notice:\n// NB: The URL to the CommonJS spec is kept just for tradition.\n// node-assert has evolved a lot since then, both in API and behavior.\n\n// http://wiki.commonjs.org/wiki/Unit_Testing/1.0\n//\n// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!\n//\n// Originally from narwhal.js (http://narwhaljs.org)\n// Copyright (c) 2009 Thomas Robinson <280north.com>\n//\n// Permission is hereby granted, free of charge, to any person obtaining a copy\n// of this software and associated documentation files (the 'Software'), to\n// deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n// sell copies of the Software, and to permit persons to whom the Software is\n// furnished to do so, subject to the following conditions:\n//\n// The above copyright notice and this permission notice shall be included in\n// all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nvar util = require('util/');\nvar hasOwn = Object.prototype.hasOwnProperty;\nvar pSlice = Array.prototype.slice;\nvar functionsHaveNames = (function () {\n return function foo() {}.name === 'foo';\n}());\nfunction pToString (obj) {\n return Object.prototype.toString.call(obj);\n}\nfunction isView(arrbuf) {\n if (isBuffer(arrbuf)) {\n return false;\n }\n if (typeof global.ArrayBuffer !== 'function') {\n return false;\n }\n if (typeof ArrayBuffer.isView === 'function') {\n return ArrayBuffer.isView(arrbuf);\n }\n if (!arrbuf) {\n return false;\n }\n if (arrbuf instanceof DataView) {\n return true;\n }\n if (arrbuf.buffer && arrbuf.buffer instanceof ArrayBuffer) {\n return true;\n }\n return false;\n}\n// 1. The assert module provides functions that throw\n// AssertionError's when particular conditions are not met. The\n// assert module must conform to the following interface.\n\nvar assert = module.exports = ok;\n\n// 2. The AssertionError is defined in assert.\n// new assert.AssertionError({ message: message,\n// actual: actual,\n// expected: expected })\n\nvar regex = /\\s*function\\s+([^\\(\\s]*)\\s*/;\n// based on https://github.com/ljharb/function.prototype.name/blob/adeeeec8bfcc6068b187d7d9fb3d5bb1d3a30899/implementation.js\nfunction getName(func) {\n if (!util.isFunction(func)) {\n return;\n }\n if (functionsHaveNames) {\n return func.name;\n }\n var str = func.toString();\n var match = str.match(regex);\n return match && match[1];\n}\nassert.AssertionError = function AssertionError(options) {\n this.name = 'AssertionError';\n this.actual = options.actual;\n this.expected = options.expected;\n this.operator = options.operator;\n if (options.message) {\n this.message = options.message;\n this.generatedMessage = false;\n } else {\n this.message = getMessage(this);\n this.generatedMessage = true;\n }\n var stackStartFunction = options.stackStartFunction || fail;\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, stackStartFunction);\n } else {\n // non v8 browsers so we can have a stacktrace\n var err = new Error();\n if (err.stack) {\n var out = err.stack;\n\n // try to strip useless frames\n var fn_name = getName(stackStartFunction);\n var idx = out.indexOf('\\n' + fn_name);\n if (idx >= 0) {\n // once we have located the function frame\n // we need to strip out everything before it (and its line)\n var next_line = out.indexOf('\\n', idx + 1);\n out = out.substring(next_line + 1);\n }\n\n this.stack = out;\n }\n }\n};\n\n// assert.AssertionError instanceof Error\nutil.inherits(assert.AssertionError, Error);\n\nfunction truncate(s, n) {\n if (typeof s === 'string') {\n return s.length < n ? s : s.slice(0, n);\n } else {\n return s;\n }\n}\nfunction inspect(something) {\n if (functionsHaveNames || !util.isFunction(something)) {\n return util.inspect(something);\n }\n var rawname = getName(something);\n var name = rawname ? ': ' + rawname : '';\n return '[Function' + name + ']';\n}\nfunction getMessage(self) {\n return truncate(inspect(self.actual), 128) + ' ' +\n self.operator + ' ' +\n truncate(inspect(self.expected), 128);\n}\n\n// At present only the three keys mentioned above are used and\n// understood by the spec. Implementations or sub modules can pass\n// other keys to the AssertionError's constructor - they will be\n// ignored.\n\n// 3. All of the following functions must throw an AssertionError\n// when a corresponding condition is not met, with a message that\n// may be undefined if not provided. All assertion methods provide\n// both the actual and expected values to the assertion error for\n// display purposes.\n\nfunction fail(actual, expected, message, operator, stackStartFunction) {\n throw new assert.AssertionError({\n message: message,\n actual: actual,\n expected: expected,\n operator: operator,\n stackStartFunction: stackStartFunction\n });\n}\n\n// EXTENSION! allows for well behaved errors defined elsewhere.\nassert.fail = fail;\n\n// 4. Pure assertion tests whether a value is truthy, as determined\n// by !!guard.\n// assert.ok(guard, message_opt);\n// This statement is equivalent to assert.equal(true, !!guard,\n// message_opt);. To test strictly for the value true, use\n// assert.strictEqual(true, guard, message_opt);.\n\nfunction ok(value, message) {\n if (!value) fail(value, true, message, '==', assert.ok);\n}\nassert.ok = ok;\n\n// 5. The equality assertion tests shallow, coercive equality with\n// ==.\n// assert.equal(actual, expected, message_opt);\n\nassert.equal = function equal(actual, expected, message) {\n if (actual != expected) fail(actual, expected, message, '==', assert.equal);\n};\n\n// 6. The non-equality assertion tests for whether two objects are not equal\n// with != assert.notEqual(actual, expected, message_opt);\n\nassert.notEqual = function notEqual(actual, expected, message) {\n if (actual == expected) {\n fail(actual, expected, message, '!=', assert.notEqual);\n }\n};\n\n// 7. The equivalence assertion tests a deep equality relation.\n// assert.deepEqual(actual, expected, message_opt);\n\nassert.deepEqual = function deepEqual(actual, expected, message) {\n if (!_deepEqual(actual, expected, false)) {\n fail(actual, expected, message, 'deepEqual', assert.deepEqual);\n }\n};\n\nassert.deepStrictEqual = function deepStrictEqual(actual, expected, message) {\n if (!_deepEqual(actual, expected, true)) {\n fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual);\n }\n};\n\nfunction _deepEqual(actual, expected, strict, memos) {\n // 7.1. All identical values are equivalent, as determined by ===.\n if (actual === expected) {\n return true;\n } else if (isBuffer(actual) && isBuffer(expected)) {\n return compare(actual, expected) === 0;\n\n // 7.2. If the expected value is a Date object, the actual value is\n // equivalent if it is also a Date object that refers to the same time.\n } else if (util.isDate(actual) && util.isDate(expected)) {\n return actual.getTime() === expected.getTime();\n\n // 7.3 If the expected value is a RegExp object, the actual value is\n // equivalent if it is also a RegExp object with the same source and\n // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).\n } else if (util.isRegExp(actual) && util.isRegExp(expected)) {\n return actual.source === expected.source &&\n actual.global === expected.global &&\n actual.multiline === expected.multiline &&\n actual.lastIndex === expected.lastIndex &&\n actual.ignoreCase === expected.ignoreCase;\n\n // 7.4. Other pairs that do not both pass typeof value == 'object',\n // equivalence is determined by ==.\n } else if ((actual === null || typeof actual !== 'object') &&\n (expected === null || typeof expected !== 'object')) {\n return strict ? actual === expected : actual == expected;\n\n // If both values are instances of typed arrays, wrap their underlying\n // ArrayBuffers in a Buffer each to increase performance\n // This optimization requires the arrays to have the same type as checked by\n // Object.prototype.toString (aka pToString). Never perform binary\n // comparisons for Float*Arrays, though, since e.g. +0 === -0 but their\n // bit patterns are not identical.\n } else if (isView(actual) && isView(expected) &&\n pToString(actual) === pToString(expected) &&\n !(actual instanceof Float32Array ||\n actual instanceof Float64Array)) {\n return compare(new Uint8Array(actual.buffer),\n new Uint8Array(expected.buffer)) === 0;\n\n // 7.5 For all other Object pairs, including Array objects, equivalence is\n // determined by having the same number of owned properties (as verified\n // with Object.prototype.hasOwnProperty.call), the same set of keys\n // (although not necessarily the same order), equivalent values for every\n // corresponding key, and an identical 'prototype' property. Note: this\n // accounts for both named and indexed properties on Arrays.\n } else if (isBuffer(actual) !== isBuffer(expected)) {\n return false;\n } else {\n memos = memos || {actual: [], expected: []};\n\n var actualIndex = memos.actual.indexOf(actual);\n if (actualIndex !== -1) {\n if (actualIndex === memos.expected.indexOf(expected)) {\n return true;\n }\n }\n\n memos.actual.push(actual);\n memos.expected.push(expected);\n\n return objEquiv(actual, expected, strict, memos);\n }\n}\n\nfunction isArguments(object) {\n return Object.prototype.toString.call(object) == '[object Arguments]';\n}\n\nfunction objEquiv(a, b, strict, actualVisitedObjects) {\n if (a === null || a === undefined || b === null || b === undefined)\n return false;\n // if one is a primitive, the other must be same\n if (util.isPrimitive(a) || util.isPrimitive(b))\n return a === b;\n if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))\n return false;\n var aIsArgs = isArguments(a);\n var bIsArgs = isArguments(b);\n if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))\n return false;\n if (aIsArgs) {\n a = pSlice.call(a);\n b = pSlice.call(b);\n return _deepEqual(a, b, strict);\n }\n var ka = objectKeys(a);\n var kb = objectKeys(b);\n var key, i;\n // having the same number of owned properties (keys incorporates\n // hasOwnProperty)\n if (ka.length !== kb.length)\n return false;\n //the same set of keys (although not necessarily the same order),\n ka.sort();\n kb.sort();\n //~~~cheap key test\n for (i = ka.length - 1; i >= 0; i--) {\n if (ka[i] !== kb[i])\n return false;\n }\n //equivalent values for every corresponding key, and\n //~~~possibly expensive deep test\n for (i = ka.length - 1; i >= 0; i--) {\n key = ka[i];\n if (!_deepEqual(a[key], b[key], strict, actualVisitedObjects))\n return false;\n }\n return true;\n}\n\n// 8. The non-equivalence assertion tests for any deep inequality.\n// assert.notDeepEqual(actual, expected, message_opt);\n\nassert.notDeepEqual = function notDeepEqual(actual, expected, message) {\n if (_deepEqual(actual, expected, false)) {\n fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);\n }\n};\n\nassert.notDeepStrictEqual = notDeepStrictEqual;\nfunction notDeepStrictEqual(actual, expected, message) {\n if (_deepEqual(actual, expected, true)) {\n fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual);\n }\n}\n\n\n// 9. The strict equality assertion tests strict equality, as determined by ===.\n// assert.strictEqual(actual, expected, message_opt);\n\nassert.strictEqual = function strictEqual(actual, expected, message) {\n if (actual !== expected) {\n fail(actual, expected, message, '===', assert.strictEqual);\n }\n};\n\n// 10. The strict non-equality assertion tests for strict inequality, as\n// determined by !==. assert.notStrictEqual(actual, expected, message_opt);\n\nassert.notStrictEqual = function notStrictEqual(actual, expected, message) {\n if (actual === expected) {\n fail(actual, expected, message, '!==', assert.notStrictEqual);\n }\n};\n\nfunction expectedException(actual, expected) {\n if (!actual || !expected) {\n return false;\n }\n\n if (Object.prototype.toString.call(expected) == '[object RegExp]') {\n return expected.test(actual);\n }\n\n try {\n if (actual instanceof expected) {\n return true;\n }\n } catch (e) {\n // Ignore. The instanceof check doesn't work for arrow functions.\n }\n\n if (Error.isPrototypeOf(expected)) {\n return false;\n }\n\n return expected.call({}, actual) === true;\n}\n\nfunction _tryBlock(block) {\n var error;\n try {\n block();\n } catch (e) {\n error = e;\n }\n return error;\n}\n\nfunction _throws(shouldThrow, block, expected, message) {\n var actual;\n\n if (typeof block !== 'function') {\n throw new TypeError('\"block\" argument must be a function');\n }\n\n if (typeof expected === 'string') {\n message = expected;\n expected = null;\n }\n\n actual = _tryBlock(block);\n\n message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +\n (message ? ' ' + message : '.');\n\n if (shouldThrow && !actual) {\n fail(actual, expected, 'Missing expected exception' + message);\n }\n\n var userProvidedMessage = typeof message === 'string';\n var isUnwantedException = !shouldThrow && util.isError(actual);\n var isUnexpectedException = !shouldThrow && actual && !expected;\n\n if ((isUnwantedException &&\n userProvidedMessage &&\n expectedException(actual, expected)) ||\n isUnexpectedException) {\n fail(actual, expected, 'Got unwanted exception' + message);\n }\n\n if ((shouldThrow && actual && expected &&\n !expectedException(actual, expected)) || (!shouldThrow && actual)) {\n throw actual;\n }\n}\n\n// 11. Expected to throw an error:\n// assert.throws(block, Error_opt, message_opt);\n\nassert.throws = function(block, /*optional*/error, /*optional*/message) {\n _throws(true, block, error, message);\n};\n\n// EXTENSION! This is annoying to write outside this module.\nassert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) {\n _throws(false, block, error, message);\n};\n\nassert.ifError = function(err) { if (err) throw err; };\n\n// Expose a strict only variant of assert\nfunction strict(value, message) {\n if (!value) fail(value, true, message, '==', strict);\n}\nassert.strict = objectAssign(strict, assert, {\n equal: assert.strictEqual,\n deepEqual: assert.deepStrictEqual,\n notEqual: assert.notStrictEqual,\n notDeepEqual: assert.notDeepStrictEqual\n});\nassert.strict.strict = assert.strict;\n\nvar objectKeys = Object.keys || function (obj) {\n var keys = [];\n for (var key in obj) {\n if (hasOwn.call(obj, key)) keys.push(key);\n }\n return keys;\n};\n",";(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/*globals window, global, require*/\n\n\t/**\n\t * CryptoJS core components.\n\t */\n\tvar CryptoJS = CryptoJS || (function (Math, undefined) {\n\n\t var crypto;\n\n\t // Native crypto from window (Browser)\n\t if (typeof window !== 'undefined' && window.crypto) {\n\t crypto = window.crypto;\n\t }\n\n\t // Native (experimental IE 11) crypto from window (Browser)\n\t if (!crypto && typeof window !== 'undefined' && window.msCrypto) {\n\t crypto = window.msCrypto;\n\t }\n\n\t // Native crypto from global (NodeJS)\n\t if (!crypto && typeof global !== 'undefined' && global.crypto) {\n\t crypto = global.crypto;\n\t }\n\n\t // Native crypto import via require (NodeJS)\n\t if (!crypto && typeof require === 'function') {\n\t try {\n\t crypto = require('crypto');\n\t } catch (err) {}\n\t }\n\n\t /*\n\t * Cryptographically secure pseudorandom number generator\n\t *\n\t * As Math.random() is cryptographically not safe to use\n\t */\n\t var cryptoSecureRandomInt = function () {\n\t if (crypto) {\n\t // Use getRandomValues method (Browser)\n\t if (typeof crypto.getRandomValues === 'function') {\n\t try {\n\t return crypto.getRandomValues(new Uint32Array(1))[0];\n\t } catch (err) {}\n\t }\n\n\t // Use randomBytes method (NodeJS)\n\t if (typeof crypto.randomBytes === 'function') {\n\t try {\n\t return crypto.randomBytes(4).readInt32LE();\n\t } catch (err) {}\n\t }\n\t }\n\n\t throw new Error('Native crypto module could not be used to get secure random number.');\n\t };\n\n\t /*\n\t * Local polyfill of Object.create\n\n\t */\n\t var create = Object.create || (function () {\n\t function F() {}\n\n\t return function (obj) {\n\t var subtype;\n\n\t F.prototype = obj;\n\n\t subtype = new F();\n\n\t F.prototype = null;\n\n\t return subtype;\n\t };\n\t }())\n\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\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 var subtype = create(this);\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') || this.init === subtype.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 for (var i = 0; i < nBytes; i += 4) {\n\t words.push(cryptoSecureRandomInt());\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 var processedWords;\n\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 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}));","// Copyright (c) 2012, Mark Cavage. All rights reserved.\n// Copyright 2015 Joyent, Inc.\n\nvar assert = require('assert');\nvar Stream = require('stream').Stream;\nvar util = require('util');\n\n\n///--- Globals\n\n/* JSSTYLED */\nvar UUID_REGEXP = /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/;\n\n\n///--- Internal\n\nfunction _capitalize(str) {\n return (str.charAt(0).toUpperCase() + str.slice(1));\n}\n\nfunction _toss(name, expected, oper, arg, actual) {\n throw new assert.AssertionError({\n message: util.format('%s (%s) is required', name, expected),\n actual: (actual === undefined) ? typeof (arg) : actual(arg),\n expected: expected,\n operator: oper || '===',\n stackStartFunction: _toss.caller\n });\n}\n\nfunction _getClass(arg) {\n return (Object.prototype.toString.call(arg).slice(8, -1));\n}\n\nfunction noop() {\n // Why even bother with asserts?\n}\n\n\n///--- Exports\n\nvar types = {\n bool: {\n check: function (arg) { return typeof (arg) === 'boolean'; }\n },\n func: {\n check: function (arg) { return typeof (arg) === 'function'; }\n },\n string: {\n check: function (arg) { return typeof (arg) === 'string'; }\n },\n object: {\n check: function (arg) {\n return typeof (arg) === 'object' && arg !== null;\n }\n },\n number: {\n check: function (arg) {\n return typeof (arg) === 'number' && !isNaN(arg);\n }\n },\n finite: {\n check: function (arg) {\n return typeof (arg) === 'number' && !isNaN(arg) && isFinite(arg);\n }\n },\n buffer: {\n check: function (arg) { return Buffer.isBuffer(arg); },\n operator: 'Buffer.isBuffer'\n },\n array: {\n check: function (arg) { return Array.isArray(arg); },\n operator: 'Array.isArray'\n },\n stream: {\n check: function (arg) { return arg instanceof Stream; },\n operator: 'instanceof',\n actual: _getClass\n },\n date: {\n check: function (arg) { return arg instanceof Date; },\n operator: 'instanceof',\n actual: _getClass\n },\n regexp: {\n check: function (arg) { return arg instanceof RegExp; },\n operator: 'instanceof',\n actual: _getClass\n },\n uuid: {\n check: function (arg) {\n return typeof (arg) === 'string' && UUID_REGEXP.test(arg);\n },\n operator: 'isUUID'\n }\n};\n\nfunction _setExports(ndebug) {\n var keys = Object.keys(types);\n var out;\n\n /* re-export standard assert */\n if (process.env.NODE_NDEBUG) {\n out = noop;\n } else {\n out = function (arg, msg) {\n if (!arg) {\n _toss(msg, 'true', arg);\n }\n };\n }\n\n /* standard checks */\n keys.forEach(function (k) {\n if (ndebug) {\n out[k] = noop;\n return;\n }\n var type = types[k];\n out[k] = function (arg, msg) {\n if (!type.check(arg)) {\n _toss(msg, k, type.operator, arg, type.actual);\n }\n };\n });\n\n /* optional checks */\n keys.forEach(function (k) {\n var name = 'optional' + _capitalize(k);\n if (ndebug) {\n out[name] = noop;\n return;\n }\n var type = types[k];\n out[name] = function (arg, msg) {\n if (arg === undefined || arg === null) {\n return;\n }\n if (!type.check(arg)) {\n _toss(msg, k, type.operator, arg, type.actual);\n }\n };\n });\n\n /* arrayOf checks */\n keys.forEach(function (k) {\n var name = 'arrayOf' + _capitalize(k);\n if (ndebug) {\n out[name] = noop;\n return;\n }\n var type = types[k];\n var expected = '[' + k + ']';\n out[name] = function (arg, msg) {\n if (!Array.isArray(arg)) {\n _toss(msg, expected, type.operator, arg, type.actual);\n }\n var i;\n for (i = 0; i < arg.length; i++) {\n if (!type.check(arg[i])) {\n _toss(msg, expected, type.operator, arg, type.actual);\n }\n }\n };\n });\n\n /* optionalArrayOf checks */\n keys.forEach(function (k) {\n var name = 'optionalArrayOf' + _capitalize(k);\n if (ndebug) {\n out[name] = noop;\n return;\n }\n var type = types[k];\n var expected = '[' + k + ']';\n out[name] = function (arg, msg) {\n if (arg === undefined || arg === null) {\n return;\n }\n if (!Array.isArray(arg)) {\n _toss(msg, expected, type.operator, arg, type.actual);\n }\n var i;\n for (i = 0; i < arg.length; i++) {\n if (!type.check(arg[i])) {\n _toss(msg, expected, type.operator, arg, type.actual);\n }\n }\n };\n });\n\n /* re-export built-in assertions */\n Object.keys(assert).forEach(function (k) {\n if (k === 'AssertionError') {\n out[k] = assert[k];\n return;\n }\n if (ndebug) {\n out[k] = noop;\n return;\n }\n out[k] = assert[k];\n });\n\n /* export ourselves (for unit tests _only_) */\n out._setExports = _setExports;\n\n return out;\n}\n\nmodule.exports = _setExports(process.env.NODE_NDEBUG);\n","/*\n\tJavaScript BigInteger library version 0.9.1\n\thttp://silentmatt.com/biginteger/\n\n\tCopyright (c) 2009 Matthew Crumley \n\tCopyright (c) 2010,2011 by John Tobey \n\tLicensed under the MIT license.\n\n\tSupport for arbitrary internal representation base was added by\n\tVitaly Magerya.\n*/\n/*\n\nThis file has been modified by Paul Shapiro:\n\n1. to bring in the function lowVal which was written by Lucas Jones\n2. to expose CONSTRUCT\n\n*/\n/*\n\tFile: biginteger.js\n\n\tExports:\n\n\t\t\n*/\n(function(exports) {\n\"use strict\";\n/*\n\tClass: BigInteger\n\tAn arbitrarily-large integer.\n\n\t objects should be considered immutable. None of the \"built-in\"\n\tmethods modify *this* or their arguments. All properties should be\n\tconsidered private.\n\n\tAll the methods of instances can be called \"statically\". The\n\tstatic versions are convenient if you don't already have a \n\tobject.\n\n\tAs an example, these calls are equivalent.\n\n\t> BigInteger(4).multiply(5); // returns BigInteger(20);\n\t> BigInteger.multiply(4, 5); // returns BigInteger(20);\n\n\t> var a = 42;\n\t> var a = BigInteger.toJSValue(\"0b101010\"); // Not completely useless...\n*/\n\nvar CONSTRUCT = {}; // Unique token to call \"private\" version of constructor\n\n/*\n\tConstructor: BigInteger()\n\tConvert a value to a .\n\n\tAlthough is the constructor for objects, it is\n\tbest not to call it as a constructor. If *n* is a object, it is\n\tsimply returned as-is. Otherwise, is equivalent to \n\twithout a radix argument.\n\n\t> var n0 = BigInteger();\t // Same as \n\t> var n1 = BigInteger(\"123\"); // Create a new with value 123\n\t> var n2 = BigInteger(123); // Create a new with value 123\n\t> var n3 = BigInteger(n2);\t// Return n2, unchanged\n\n\tThe constructor form only takes an array and a sign. *n* must be an\n\tarray of numbers in little-endian order, where each digit is between 0\n\tand BigInteger.base. The second parameter sets the sign: -1 for\n\tnegative, +1 for positive, or 0 for zero. The array is *not copied and\n\tmay be modified*. If the array contains only zeros, the sign parameter\n\tis ignored and is forced to zero.\n\n\t> new BigInteger([5], -1): create a new BigInteger with value -5\n\n\tParameters:\n\n\t\tn - Value to convert to a .\n\n\tReturns:\n\n\t\tA value.\n\n\tSee Also:\n\n\t\t, \n*/\nfunction BigInteger(n, s, token) {\n\tif (token !== CONSTRUCT) {\n\t\tif (n instanceof BigInteger) {\n\t\t\treturn n;\n\t\t}\n\t\telse if (typeof n === \"undefined\") {\n\t\t\treturn ZERO;\n\t\t}\n\t\treturn BigInteger.parse(n);\n\t}\n\n\tn = n || []; // Provide the nullary constructor for subclasses.\n\twhile (n.length && !n[n.length - 1]) {\n\t\t--n.length;\n\t}\n\tthis._d = n;\n\tthis._s = n.length ? (s || 1) : 0;\n}\nBigInteger.CONSTRUCT = CONSTRUCT; // added by PS to actually use the constructor\n\nBigInteger._construct = function(n, s) {\n\treturn new BigInteger(n, s, CONSTRUCT);\n};\n\n// Base-10 speedup hacks in parse, toString, exp10 and log functions\n// require base to be a power of 10. 10^7 is the largest such power\n// that won't cause a precision loss when digits are multiplied.\nvar BigInteger_base = 10000000;\nvar BigInteger_base_log10 = 7;\n\nBigInteger.base = BigInteger_base;\nBigInteger.base_log10 = BigInteger_base_log10;\n\nvar ZERO = new BigInteger([], 0, CONSTRUCT);\n// Constant: ZERO\n// 0.\nBigInteger.ZERO = ZERO;\n\nvar ONE = new BigInteger([1], 1, CONSTRUCT);\n// Constant: ONE\n// 1.\nBigInteger.ONE = ONE;\n\nvar M_ONE = new BigInteger(ONE._d, -1, CONSTRUCT);\n// Constant: M_ONE\n// -1.\nBigInteger.M_ONE = M_ONE;\n\n// Constant: _0\n// Shortcut for .\nBigInteger._0 = ZERO;\n\n// Constant: _1\n// Shortcut for .\nBigInteger._1 = ONE;\n\n/*\n\tConstant: small\n\tArray of from 0 to 36.\n\n\tThese are used internally for parsing, but useful when you need a \"small\"\n\t.\n\n\tSee Also:\n\n\t\t, , <_0>, <_1>\n*/\nBigInteger.small = [\n\tZERO,\n\tONE,\n\t/* Assuming BigInteger_base > 36 */\n\tnew BigInteger( [2], 1, CONSTRUCT),\n\tnew BigInteger( [3], 1, CONSTRUCT),\n\tnew BigInteger( [4], 1, CONSTRUCT),\n\tnew BigInteger( [5], 1, CONSTRUCT),\n\tnew BigInteger( [6], 1, CONSTRUCT),\n\tnew BigInteger( [7], 1, CONSTRUCT),\n\tnew BigInteger( [8], 1, CONSTRUCT),\n\tnew BigInteger( [9], 1, CONSTRUCT),\n\tnew BigInteger([10], 1, CONSTRUCT),\n\tnew BigInteger([11], 1, CONSTRUCT),\n\tnew BigInteger([12], 1, CONSTRUCT),\n\tnew BigInteger([13], 1, CONSTRUCT),\n\tnew BigInteger([14], 1, CONSTRUCT),\n\tnew BigInteger([15], 1, CONSTRUCT),\n\tnew BigInteger([16], 1, CONSTRUCT),\n\tnew BigInteger([17], 1, CONSTRUCT),\n\tnew BigInteger([18], 1, CONSTRUCT),\n\tnew BigInteger([19], 1, CONSTRUCT),\n\tnew BigInteger([20], 1, CONSTRUCT),\n\tnew BigInteger([21], 1, CONSTRUCT),\n\tnew BigInteger([22], 1, CONSTRUCT),\n\tnew BigInteger([23], 1, CONSTRUCT),\n\tnew BigInteger([24], 1, CONSTRUCT),\n\tnew BigInteger([25], 1, CONSTRUCT),\n\tnew BigInteger([26], 1, CONSTRUCT),\n\tnew BigInteger([27], 1, CONSTRUCT),\n\tnew BigInteger([28], 1, CONSTRUCT),\n\tnew BigInteger([29], 1, CONSTRUCT),\n\tnew BigInteger([30], 1, CONSTRUCT),\n\tnew BigInteger([31], 1, CONSTRUCT),\n\tnew BigInteger([32], 1, CONSTRUCT),\n\tnew BigInteger([33], 1, CONSTRUCT),\n\tnew BigInteger([34], 1, CONSTRUCT),\n\tnew BigInteger([35], 1, CONSTRUCT),\n\tnew BigInteger([36], 1, CONSTRUCT)\n];\n\n// Used for parsing/radix conversion\nBigInteger.digits = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\".split(\"\");\n\n/*\n\tMethod: toString\n\tConvert a to a string.\n\n\tWhen *base* is greater than 10, letters are upper case.\n\n\tParameters:\n\n\t\tbase - Optional base to represent the number in (default is base 10).\n\t\t\t Must be between 2 and 36 inclusive, or an Error will be thrown.\n\n\tReturns:\n\n\t\tThe string representation of the .\n*/\nBigInteger.prototype.toString = function(base) {\n\tbase = +base || 10;\n\tif (base < 2 || base > 36) {\n\t\tthrow new Error(\"illegal radix \" + base + \".\");\n\t}\n\tif (this._s === 0) {\n\t\treturn \"0\";\n\t}\n\tif (base === 10) {\n\t\tvar str = this._s < 0 ? \"-\" : \"\";\n\t\tstr += this._d[this._d.length - 1].toString();\n\t\tfor (var i = this._d.length - 2; i >= 0; i--) {\n\t\t\tvar group = this._d[i].toString();\n\t\t\twhile (group.length < BigInteger_base_log10) group = '0' + group;\n\t\t\tstr += group;\n\t\t}\n\t\treturn str;\n\t}\n\telse {\n\t\tvar numerals = BigInteger.digits;\n\t\tbase = BigInteger.small[base];\n\t\tvar sign = this._s;\n\n\t\tvar n = this.abs();\n\t\tvar digits = [];\n\t\tvar digit;\n\n\t\twhile (n._s !== 0) {\n\t\t\tvar divmod = n.divRem(base);\n\t\t\tn = divmod[0];\n\t\t\tdigit = divmod[1];\n\t\t\t// TODO: This could be changed to unshift instead of reversing at the end.\n\t\t\t// Benchmark both to compare speeds.\n\t\t\tdigits.push(numerals[digit.valueOf()]);\n\t\t}\n\t\treturn (sign < 0 ? \"-\" : \"\") + digits.reverse().join(\"\");\n\t}\n};\n\n// Verify strings for parsing\nBigInteger.radixRegex = [\n\t/^$/,\n\t/^$/,\n\t/^[01]*$/,\n\t/^[012]*$/,\n\t/^[0-3]*$/,\n\t/^[0-4]*$/,\n\t/^[0-5]*$/,\n\t/^[0-6]*$/,\n\t/^[0-7]*$/,\n\t/^[0-8]*$/,\n\t/^[0-9]*$/,\n\t/^[0-9aA]*$/,\n\t/^[0-9abAB]*$/,\n\t/^[0-9abcABC]*$/,\n\t/^[0-9a-dA-D]*$/,\n\t/^[0-9a-eA-E]*$/,\n\t/^[0-9a-fA-F]*$/,\n\t/^[0-9a-gA-G]*$/,\n\t/^[0-9a-hA-H]*$/,\n\t/^[0-9a-iA-I]*$/,\n\t/^[0-9a-jA-J]*$/,\n\t/^[0-9a-kA-K]*$/,\n\t/^[0-9a-lA-L]*$/,\n\t/^[0-9a-mA-M]*$/,\n\t/^[0-9a-nA-N]*$/,\n\t/^[0-9a-oA-O]*$/,\n\t/^[0-9a-pA-P]*$/,\n\t/^[0-9a-qA-Q]*$/,\n\t/^[0-9a-rA-R]*$/,\n\t/^[0-9a-sA-S]*$/,\n\t/^[0-9a-tA-T]*$/,\n\t/^[0-9a-uA-U]*$/,\n\t/^[0-9a-vA-V]*$/,\n\t/^[0-9a-wA-W]*$/,\n\t/^[0-9a-xA-X]*$/,\n\t/^[0-9a-yA-Y]*$/,\n\t/^[0-9a-zA-Z]*$/\n];\n\n/*\n\tFunction: parse\n\tParse a string into a .\n\n\t*base* is optional but, if provided, must be from 2 to 36 inclusive. If\n\t*base* is not provided, it will be guessed based on the leading characters\n\tof *s* as follows:\n\n\t- \"0x\" or \"0X\": *base* = 16\n\t- \"0c\" or \"0C\": *base* = 8\n\t- \"0b\" or \"0B\": *base* = 2\n\t- else: *base* = 10\n\n\tIf no base is provided, or *base* is 10, the number can be in exponential\n\tform. For example, these are all valid:\n\n\t> BigInteger.parse(\"1e9\");\t\t\t // Same as \"1000000000\"\n\t> BigInteger.parse(\"1.234*10^3\");\t // Same as 1234\n\t> BigInteger.parse(\"56789 * 10 ** -2\"); // Same as 567\n\n\tIf any characters fall outside the range defined by the radix, an exception\n\twill be thrown.\n\n\tParameters:\n\n\t\ts - The string to parse.\n\t\tbase - Optional radix (default is to guess based on *s*).\n\n\tReturns:\n\n\t\ta instance.\n*/\nBigInteger.parse = function(s, base) {\n\t// Expands a number in exponential form to decimal form.\n\t// expandExponential(\"-13.441*10^5\") === \"1344100\";\n\t// expandExponential(\"1.12300e-1\") === \"0.112300\";\n\t// expandExponential(1000000000000000000000000000000) === \"1000000000000000000000000000000\";\n\tfunction expandExponential(str) {\n\t\tstr = str.replace(/\\s*[*xX]\\s*10\\s*(\\^|\\*\\*)\\s*/, \"e\");\n\n\t\treturn str.replace(/^([+\\-])?(\\d+)\\.?(\\d*)[eE]([+\\-]?\\d+)$/, function(x, s, n, f, c) {\n\t\t\tc = +c;\n\t\t\tvar l = c < 0;\n\t\t\tvar i = n.length + c;\n\t\t\tx = (l ? n : f).length;\n\t\t\tc = ((c = Math.abs(c)) >= x ? c - x + l : 0);\n\t\t\tvar z = (new Array(c + 1)).join(\"0\");\n\t\t\tvar r = n + f;\n\t\t\treturn (s || \"\") + (l ? r = z + r : r += z).substr(0, i += l ? z.length : 0) + (i < r.length ? \".\" + r.substr(i) : \"\");\n\t\t});\n\t}\n\n\ts = s.toString();\n\tif (typeof base === \"undefined\" || +base === 10) {\n\t\ts = expandExponential(s);\n\t}\n\n\tvar prefixRE;\n\tif (typeof base === \"undefined\") {\n\t\tprefixRE = '0[xcb]';\n\t}\n\telse if (base == 16) {\n\t\tprefixRE = '0x';\n\t}\n\telse if (base == 8) {\n\t\tprefixRE = '0c';\n\t}\n\telse if (base == 2) {\n\t\tprefixRE = '0b';\n\t}\n\telse {\n\t\tprefixRE = '';\n\t}\n\tvar parts = new RegExp('^([+\\\\-]?)(' + prefixRE + ')?([0-9a-z]*)(?:\\\\.\\\\d*)?$', 'i').exec(s);\n\tif (parts) {\n\t\tvar sign = parts[1] || \"+\";\n\t\tvar baseSection = parts[2] || \"\";\n\t\tvar digits = parts[3] || \"\";\n\n\t\tif (typeof base === \"undefined\") {\n\t\t\t// Guess base\n\t\t\tif (baseSection === \"0x\" || baseSection === \"0X\") { // Hex\n\t\t\t\tbase = 16;\n\t\t\t}\n\t\t\telse if (baseSection === \"0c\" || baseSection === \"0C\") { // Octal\n\t\t\t\tbase = 8;\n\t\t\t}\n\t\t\telse if (baseSection === \"0b\" || baseSection === \"0B\") { // Binary\n\t\t\t\tbase = 2;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbase = 10;\n\t\t\t}\n\t\t}\n\t\telse if (base < 2 || base > 36) {\n\t\t\tthrow new Error(\"Illegal radix \" + base + \".\");\n\t\t}\n\n\t\tbase = +base;\n\n\t\t// Check for digits outside the range\n\t\tif (!(BigInteger.radixRegex[base].test(digits))) {\n\t\t\tthrow new Error(\"Bad digit for radix \" + base);\n\t\t}\n\n\t\t// Strip leading zeros, and convert to array\n\t\tdigits = digits.replace(/^0+/, \"\").split(\"\");\n\t\tif (digits.length === 0) {\n\t\t\treturn ZERO;\n\t\t}\n\n\t\t// Get the sign (we know it's not zero)\n\t\tsign = (sign === \"-\") ? -1 : 1;\n\n\t\t// Optimize 10\n\t\tif (base == 10) {\n\t\t\tvar d = [];\n\t\t\twhile (digits.length >= BigInteger_base_log10) {\n\t\t\t\td.push(parseInt(digits.splice(digits.length-BigInteger.base_log10, BigInteger.base_log10).join(''), 10));\n\t\t\t}\n\t\t\td.push(parseInt(digits.join(''), 10));\n\t\t\treturn new BigInteger(d, sign, CONSTRUCT);\n\t\t}\n\n\t\t// Do the conversion\n\t\tvar d = ZERO;\n\t\tbase = BigInteger.small[base];\n\t\tvar small = BigInteger.small;\n\t\tfor (var i = 0; i < digits.length; i++) {\n\t\t\td = d.multiply(base).add(small[parseInt(digits[i], 36)]);\n\t\t}\n\t\treturn new BigInteger(d._d, sign, CONSTRUCT);\n\t}\n\telse {\n\t\tthrow new Error(\"Invalid BigInteger format: \" + s);\n\t}\n};\n\n/*\n\tFunction: add\n\tAdd two .\n\n\tParameters:\n\n\t\tn - The number to add to *this*. Will be converted to a .\n\n\tReturns:\n\n\t\tThe numbers added together.\n\n\tSee Also:\n\n\t\t, , , \n*/\nBigInteger.prototype.add = function(n) {\n\tif (this._s === 0) {\n\t\treturn BigInteger(n);\n\t}\n\n\tn = BigInteger(n);\n\tif (n._s === 0) {\n\t\treturn this;\n\t}\n\tif (this._s !== n._s) {\n\t\tn = n.negate();\n\t\treturn this.subtract(n);\n\t}\n\n\tvar a = this._d;\n\tvar b = n._d;\n\tvar al = a.length;\n\tvar bl = b.length;\n\tvar sum = new Array(Math.max(al, bl) + 1);\n\tvar size = Math.min(al, bl);\n\tvar carry = 0;\n\tvar digit;\n\n\tfor (var i = 0; i < size; i++) {\n\t\tdigit = a[i] + b[i] + carry;\n\t\tsum[i] = digit % BigInteger_base;\n\t\tcarry = (digit / BigInteger_base) | 0;\n\t}\n\tif (bl > al) {\n\t\ta = b;\n\t\tal = bl;\n\t}\n\tfor (i = size; carry && i < al; i++) {\n\t\tdigit = a[i] + carry;\n\t\tsum[i] = digit % BigInteger_base;\n\t\tcarry = (digit / BigInteger_base) | 0;\n\t}\n\tif (carry) {\n\t\tsum[i] = carry;\n\t}\n\n\tfor ( ; i < al; i++) {\n\t\tsum[i] = a[i];\n\t}\n\n\treturn new BigInteger(sum, this._s, CONSTRUCT);\n};\n\n/*\n\tFunction: negate\n\tGet the additive inverse of a .\n\n\tReturns:\n\n\t\tA with the same magnatude, but with the opposite sign.\n\n\tSee Also:\n\n\t\t\n*/\nBigInteger.prototype.negate = function() {\n\treturn new BigInteger(this._d, (-this._s) | 0, CONSTRUCT);\n};\n\n/*\n\tFunction: abs\n\tGet the absolute value of a .\n\n\tReturns:\n\n\t\tA with the same magnatude, but always positive (or zero).\n\n\tSee Also:\n\n\t\t\n*/\nBigInteger.prototype.abs = function() {\n\treturn (this._s < 0) ? this.negate() : this;\n};\n\n/*\n\tFunction: subtract\n\tSubtract two .\n\n\tParameters:\n\n\t\tn - The number to subtract from *this*. Will be converted to a .\n\n\tReturns:\n\n\t\tThe *n* subtracted from *this*.\n\n\tSee Also:\n\n\t\t, , , \n*/\nBigInteger.prototype.subtract = function(n) {\n\tif (this._s === 0) {\n\t\treturn BigInteger(n).negate();\n\t}\n\n\tn = BigInteger(n);\n\tif (n._s === 0) {\n\t\treturn this;\n\t}\n\tif (this._s !== n._s) {\n\t\tn = n.negate();\n\t\treturn this.add(n);\n\t}\n\n\tvar m = this;\n\t// negative - negative => -|a| - -|b| => -|a| + |b| => |b| - |a|\n\tif (this._s < 0) {\n\t\tm = new BigInteger(n._d, 1, CONSTRUCT);\n\t\tn = new BigInteger(this._d, 1, CONSTRUCT);\n\t}\n\n\t// Both are positive => a - b\n\tvar sign = m.compareAbs(n);\n\tif (sign === 0) {\n\t\treturn ZERO;\n\t}\n\telse if (sign < 0) {\n\t\t// swap m and n\n\t\tvar t = n;\n\t\tn = m;\n\t\tm = t;\n\t}\n\n\t// a > b\n\tvar a = m._d;\n\tvar b = n._d;\n\tvar al = a.length;\n\tvar bl = b.length;\n\tvar diff = new Array(al); // al >= bl since a > b\n\tvar borrow = 0;\n\tvar i;\n\tvar digit;\n\n\tfor (i = 0; i < bl; i++) {\n\t\tdigit = a[i] - borrow - b[i];\n\t\tif (digit < 0) {\n\t\t\tdigit += BigInteger_base;\n\t\t\tborrow = 1;\n\t\t}\n\t\telse {\n\t\t\tborrow = 0;\n\t\t}\n\t\tdiff[i] = digit;\n\t}\n\tfor (i = bl; i < al; i++) {\n\t\tdigit = a[i] - borrow;\n\t\tif (digit < 0) {\n\t\t\tdigit += BigInteger_base;\n\t\t}\n\t\telse {\n\t\t\tdiff[i++] = digit;\n\t\t\tbreak;\n\t\t}\n\t\tdiff[i] = digit;\n\t}\n\tfor ( ; i < al; i++) {\n\t\tdiff[i] = a[i];\n\t}\n\n\treturn new BigInteger(diff, sign, CONSTRUCT);\n};\n\n(function() {\n\tfunction addOne(n, sign) {\n\t\tvar a = n._d;\n\t\tvar sum = a.slice();\n\t\tvar carry = true;\n\t\tvar i = 0;\n\n\t\twhile (true) {\n\t\t\tvar digit = (a[i] || 0) + 1;\n\t\t\tsum[i] = digit % BigInteger_base;\n\t\t\tif (digit <= BigInteger_base - 1) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t++i;\n\t\t}\n\n\t\treturn new BigInteger(sum, sign, CONSTRUCT);\n\t}\n\n\tfunction subtractOne(n, sign) {\n\t\tvar a = n._d;\n\t\tvar sum = a.slice();\n\t\tvar borrow = true;\n\t\tvar i = 0;\n\n\t\twhile (true) {\n\t\t\tvar digit = (a[i] || 0) - 1;\n\t\t\tif (digit < 0) {\n\t\t\t\tsum[i] = digit + BigInteger_base;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsum[i] = digit;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t++i;\n\t\t}\n\n\t\treturn new BigInteger(sum, sign, CONSTRUCT);\n\t}\n\n\t/*\n\t\tFunction: next\n\t\tGet the next (add one).\n\n\t\tReturns:\n\n\t\t\t*this* + 1.\n\n\t\tSee Also:\n\n\t\t\t, \n\t*/\n\tBigInteger.prototype.next = function() {\n\t\tswitch (this._s) {\n\t\tcase 0:\n\t\t\treturn ONE;\n\t\tcase -1:\n\t\t\treturn subtractOne(this, -1);\n\t\t// case 1:\n\t\tdefault:\n\t\t\treturn addOne(this, 1);\n\t\t}\n\t};\n\n\t/*\n\t\tFunction: prev\n\t\tGet the previous (subtract one).\n\n\t\tReturns:\n\n\t\t\t*this* - 1.\n\n\t\tSee Also:\n\n\t\t\t, \n\t*/\n\tBigInteger.prototype.prev = function() {\n\t\tswitch (this._s) {\n\t\tcase 0:\n\t\t\treturn M_ONE;\n\t\tcase -1:\n\t\t\treturn addOne(this, -1);\n\t\t// case 1:\n\t\tdefault:\n\t\t\treturn subtractOne(this, 1);\n\t\t}\n\t};\n})();\n\n/*\n\tFunction: compareAbs\n\tCompare the absolute value of two .\n\n\tCalling is faster than calling twice, then .\n\n\tParameters:\n\n\t\tn - The number to compare to *this*. Will be converted to a .\n\n\tReturns:\n\n\t\t-1, 0, or +1 if *|this|* is less than, equal to, or greater than *|n|*.\n\n\tSee Also:\n\n\t\t, \n*/\nBigInteger.prototype.compareAbs = function(n) {\n\tif (this === n) {\n\t\treturn 0;\n\t}\n\n\tif (!(n instanceof BigInteger)) {\n\t\tif (!isFinite(n)) {\n\t\t\treturn(isNaN(n) ? n : -1);\n\t\t}\n\t\tn = BigInteger(n);\n\t}\n\n\tif (this._s === 0) {\n\t\treturn (n._s !== 0) ? -1 : 0;\n\t}\n\tif (n._s === 0) {\n\t\treturn 1;\n\t}\n\n\tvar l = this._d.length;\n\tvar nl = n._d.length;\n\tif (l < nl) {\n\t\treturn -1;\n\t}\n\telse if (l > nl) {\n\t\treturn 1;\n\t}\n\n\tvar a = this._d;\n\tvar b = n._d;\n\tfor (var i = l-1; i >= 0; i--) {\n\t\tif (a[i] !== b[i]) {\n\t\t\treturn a[i] < b[i] ? -1 : 1;\n\t\t}\n\t}\n\n\treturn 0;\n};\n\n/*\n\tFunction: compare\n\tCompare two .\n\n\tParameters:\n\n\t\tn - The number to compare to *this*. Will be converted to a .\n\n\tReturns:\n\n\t\t-1, 0, or +1 if *this* is less than, equal to, or greater than *n*.\n\n\tSee Also:\n\n\t\t, , , \n*/\nBigInteger.prototype.compare = function(n) {\n\tif (this === n) {\n\t\treturn 0;\n\t}\n\n\tn = BigInteger(n);\n\n\tif (this._s === 0) {\n\t\treturn -n._s;\n\t}\n\n\tif (this._s === n._s) { // both positive or both negative\n\t\tvar cmp = this.compareAbs(n);\n\t\treturn cmp * this._s;\n\t}\n\telse {\n\t\treturn this._s;\n\t}\n};\n\n/*\n\tFunction: isUnit\n\tReturn true iff *this* is either 1 or -1.\n\n\tReturns:\n\n\t\ttrue if *this* compares equal to or .\n\n\tSee Also:\n\n\t\t, , , , ,\n\t\t, \n*/\nBigInteger.prototype.isUnit = function() {\n\treturn this === ONE ||\n\t\tthis === M_ONE ||\n\t\t(this._d.length === 1 && this._d[0] === 1);\n};\n\n/*\n\tFunction: multiply\n\tMultiply two .\n\n\tParameters:\n\n\t\tn - The number to multiply *this* by. Will be converted to a\n\t\t.\n\n\tReturns:\n\n\t\tThe numbers multiplied together.\n\n\tSee Also:\n\n\t\t, , , \n*/\nBigInteger.prototype.multiply = function(n) {\n\t// TODO: Consider adding Karatsuba multiplication for large numbers\n\tif (this._s === 0) {\n\t\treturn ZERO;\n\t}\n\n\tn = BigInteger(n);\n\tif (n._s === 0) {\n\t\treturn ZERO;\n\t}\n\tif (this.isUnit()) {\n\t\tif (this._s < 0) {\n\t\t\treturn n.negate();\n\t\t}\n\t\treturn n;\n\t}\n\tif (n.isUnit()) {\n\t\tif (n._s < 0) {\n\t\t\treturn this.negate();\n\t\t}\n\t\treturn this;\n\t}\n\tif (this === n) {\n\t\treturn this.square();\n\t}\n\n\tvar r = (this._d.length >= n._d.length);\n\tvar a = (r ? this : n)._d; // a will be longer than b\n\tvar b = (r ? n : this)._d;\n\tvar al = a.length;\n\tvar bl = b.length;\n\n\tvar pl = al + bl;\n\tvar partial = new Array(pl);\n\tvar i;\n\tfor (i = 0; i < pl; i++) {\n\t\tpartial[i] = 0;\n\t}\n\n\tfor (i = 0; i < bl; i++) {\n\t\tvar carry = 0;\n\t\tvar bi = b[i];\n\t\tvar jlimit = al + i;\n\t\tvar digit;\n\t\tfor (var j = i; j < jlimit; j++) {\n\t\t\tdigit = partial[j] + bi * a[j - i] + carry;\n\t\t\tcarry = (digit / BigInteger_base) | 0;\n\t\t\tpartial[j] = (digit % BigInteger_base) | 0;\n\t\t}\n\t\tif (carry) {\n\t\t\tdigit = partial[j] + carry;\n\t\t\tcarry = (digit / BigInteger_base) | 0;\n\t\t\tpartial[j] = digit % BigInteger_base;\n\t\t}\n\t}\n\treturn new BigInteger(partial, this._s * n._s, CONSTRUCT);\n};\n\n// Multiply a BigInteger by a single-digit native number\n// Assumes that this and n are >= 0\n// This is not really intended to be used outside the library itself\nBigInteger.prototype.multiplySingleDigit = function(n) {\n\tif (n === 0 || this._s === 0) {\n\t\treturn ZERO;\n\t}\n\tif (n === 1) {\n\t\treturn this;\n\t}\n\n\tvar digit;\n\tif (this._d.length === 1) {\n\t\tdigit = this._d[0] * n;\n\t\tif (digit >= BigInteger_base) {\n\t\t\treturn new BigInteger([(digit % BigInteger_base)|0,\n\t\t\t\t\t(digit / BigInteger_base)|0], 1, CONSTRUCT);\n\t\t}\n\t\treturn new BigInteger([digit], 1, CONSTRUCT);\n\t}\n\n\tif (n === 2) {\n\t\treturn this.add(this);\n\t}\n\tif (this.isUnit()) {\n\t\treturn new BigInteger([n], 1, CONSTRUCT);\n\t}\n\n\tvar a = this._d;\n\tvar al = a.length;\n\n\tvar pl = al + 1;\n\tvar partial = new Array(pl);\n\tfor (var i = 0; i < pl; i++) {\n\t\tpartial[i] = 0;\n\t}\n\n\tvar carry = 0;\n\tfor (var j = 0; j < al; j++) {\n\t\tdigit = n * a[j] + carry;\n\t\tcarry = (digit / BigInteger_base) | 0;\n\t\tpartial[j] = (digit % BigInteger_base) | 0;\n\t}\n\tif (carry) {\n\t\tpartial[j] = carry;\n\t}\n\n\treturn new BigInteger(partial, 1, CONSTRUCT);\n};\n\n/*\n\tFunction: square\n\tMultiply a by itself.\n\n\tThis is slightly faster than regular multiplication, since it removes the\n\tduplicated multiplcations.\n\n\tReturns:\n\n\t\t> this.multiply(this)\n\n\tSee Also:\n\t\t\n*/\nBigInteger.prototype.square = function() {\n\t// Normally, squaring a 10-digit number would take 100 multiplications.\n\t// Of these 10 are unique diagonals, of the remaining 90 (100-10), 45 are repeated.\n\t// This procedure saves (N*(N-1))/2 multiplications, (e.g., 45 of 100 multiplies).\n\t// Based on code by Gary Darby, Intellitech Systems Inc., www.DelphiForFun.org\n\n\tif (this._s === 0) {\n\t\treturn ZERO;\n\t}\n\tif (this.isUnit()) {\n\t\treturn ONE;\n\t}\n\n\tvar digits = this._d;\n\tvar length = digits.length;\n\tvar imult1 = new Array(length + length + 1);\n\tvar product, carry, k;\n\tvar i;\n\n\t// Calculate diagonal\n\tfor (i = 0; i < length; i++) {\n\t\tk = i * 2;\n\t\tproduct = digits[i] * digits[i];\n\t\tcarry = (product / BigInteger_base) | 0;\n\t\timult1[k] = product % BigInteger_base;\n\t\timult1[k + 1] = carry;\n\t}\n\n\t// Calculate repeating part\n\tfor (i = 0; i < length; i++) {\n\t\tcarry = 0;\n\t\tk = i * 2 + 1;\n\t\tfor (var j = i + 1; j < length; j++, k++) {\n\t\t\tproduct = digits[j] * digits[i] * 2 + imult1[k] + carry;\n\t\t\tcarry = (product / BigInteger_base) | 0;\n\t\t\timult1[k] = product % BigInteger_base;\n\t\t}\n\t\tk = length + i;\n\t\tvar digit = carry + imult1[k];\n\t\tcarry = (digit / BigInteger_base) | 0;\n\t\timult1[k] = digit % BigInteger_base;\n\t\timult1[k + 1] += carry;\n\t}\n\n\treturn new BigInteger(imult1, 1, CONSTRUCT);\n};\n\n/*\n\tFunction: quotient\n\tDivide two and truncate towards zero.\n\n\t throws an exception if *n* is zero.\n\n\tParameters:\n\n\t\tn - The number to divide *this* by. Will be converted to a .\n\n\tReturns:\n\n\t\tThe *this* / *n*, truncated to an integer.\n\n\tSee Also:\n\n\t\t, , , , \n*/\nBigInteger.prototype.quotient = function(n) {\n\treturn this.divRem(n)[0];\n};\n\n/*\n\tFunction: divide\n\tDeprecated synonym for .\n*/\nBigInteger.prototype.divide = BigInteger.prototype.quotient;\n\n/*\n\tFunction: remainder\n\tCalculate the remainder of two .\n\n\t throws an exception if *n* is zero.\n\n\tParameters:\n\n\t\tn - The remainder after *this* is divided *this* by *n*. Will be\n\t\t\tconverted to a .\n\n\tReturns:\n\n\t\t*this* % *n*.\n\n\tSee Also:\n\n\t\t, \n*/\nBigInteger.prototype.remainder = function(n) {\n\treturn this.divRem(n)[1];\n};\n\n/*\n\tFunction: divRem\n\tCalculate the integer quotient and remainder of two .\n\n\t throws an exception if *n* is zero.\n\n\tParameters:\n\n\t\tn - The number to divide *this* by. Will be converted to a .\n\n\tReturns:\n\n\t\tA two-element array containing the quotient and the remainder.\n\n\t\t> a.divRem(b)\n\n\t\tis exactly equivalent to\n\n\t\t> [a.quotient(b), a.remainder(b)]\n\n\t\texcept it is faster, because they are calculated at the same time.\n\n\tSee Also:\n\n\t\t, \n*/\nBigInteger.prototype.divRem = function(n) {\n\tn = BigInteger(n);\n\tif (n._s === 0) {\n\t\tthrow new Error(\"Divide by zero\");\n\t}\n\tif (this._s === 0) {\n\t\treturn [ZERO, ZERO];\n\t}\n\tif (n._d.length === 1) {\n\t\treturn this.divRemSmall(n._s * n._d[0]);\n\t}\n\n\t// Test for easy cases -- |n1| <= |n2|\n\tswitch (this.compareAbs(n)) {\n\tcase 0: // n1 == n2\n\t\treturn [this._s === n._s ? ONE : M_ONE, ZERO];\n\tcase -1: // |n1| < |n2|\n\t\treturn [ZERO, this];\n\t}\n\n\tvar sign = this._s * n._s;\n\tvar a = n.abs();\n\tvar b_digits = this._d;\n\tvar b_index = b_digits.length;\n\tvar digits = n._d.length;\n\tvar quot = [];\n\tvar guess;\n\n\tvar part = new BigInteger([], 0, CONSTRUCT);\n\n\twhile (b_index) {\n\t\tpart._d.unshift(b_digits[--b_index]);\n\t\tpart = new BigInteger(part._d, 1, CONSTRUCT);\n\n\t\tif (part.compareAbs(n) < 0) {\n\t\t\tquot.push(0);\n\t\t\tcontinue;\n\t\t}\n\t\tif (part._s === 0) {\n\t\t\tguess = 0;\n\t\t}\n\t\telse {\n\t\t\tvar xlen = part._d.length, ylen = a._d.length;\n\t\t\tvar highx = part._d[xlen-1]*BigInteger_base + part._d[xlen-2];\n\t\t\tvar highy = a._d[ylen-1]*BigInteger_base + a._d[ylen-2];\n\t\t\tif (part._d.length > a._d.length) {\n\t\t\t\t// The length of part._d can either match a._d length,\n\t\t\t\t// or exceed it by one.\n\t\t\t\thighx = (highx+1)*BigInteger_base;\n\t\t\t}\n\t\t\tguess = Math.ceil(highx/highy);\n\t\t}\n\t\tdo {\n\t\t\tvar check = a.multiplySingleDigit(guess);\n\t\t\tif (check.compareAbs(part) <= 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tguess--;\n\t\t} while (guess);\n\n\t\tquot.push(guess);\n\t\tif (!guess) {\n\t\t\tcontinue;\n\t\t}\n\t\tvar diff = part.subtract(check);\n\t\tpart._d = diff._d.slice();\n\t}\n\n\treturn [new BigInteger(quot.reverse(), sign, CONSTRUCT),\n\t\t new BigInteger(part._d, this._s, CONSTRUCT)];\n};\n\n// Throws an exception if n is outside of (-BigInteger.base, -1] or\n// [1, BigInteger.base). It's not necessary to call this, since the\n// other division functions will call it if they are able to.\nBigInteger.prototype.divRemSmall = function(n) {\n\tvar r;\n\tn = +n;\n\tif (n === 0) {\n\t\tthrow new Error(\"Divide by zero\");\n\t}\n\n\tvar n_s = n < 0 ? -1 : 1;\n\tvar sign = this._s * n_s;\n\tn = Math.abs(n);\n\n\tif (n < 1 || n >= BigInteger_base) {\n\t\tthrow new Error(\"Argument out of range\");\n\t}\n\n\tif (this._s === 0) {\n\t\treturn [ZERO, ZERO];\n\t}\n\n\tif (n === 1 || n === -1) {\n\t\treturn [(sign === 1) ? this.abs() : new BigInteger(this._d, sign, CONSTRUCT), ZERO];\n\t}\n\n\t// 2 <= n < BigInteger_base\n\n\t// divide a single digit by a single digit\n\tif (this._d.length === 1) {\n\t\tvar q = new BigInteger([(this._d[0] / n) | 0], 1, CONSTRUCT);\n\t\tr = new BigInteger([(this._d[0] % n) | 0], 1, CONSTRUCT);\n\t\tif (sign < 0) {\n\t\t\tq = q.negate();\n\t\t}\n\t\tif (this._s < 0) {\n\t\t\tr = r.negate();\n\t\t}\n\t\treturn [q, r];\n\t}\n\n\tvar digits = this._d.slice();\n\tvar quot = new Array(digits.length);\n\tvar part = 0;\n\tvar diff = 0;\n\tvar i = 0;\n\tvar guess;\n\n\twhile (digits.length) {\n\t\tpart = part * BigInteger_base + digits[digits.length - 1];\n\t\tif (part < n) {\n\t\t\tquot[i++] = 0;\n\t\t\tdigits.pop();\n\t\t\tdiff = BigInteger_base * diff + part;\n\t\t\tcontinue;\n\t\t}\n\t\tif (part === 0) {\n\t\t\tguess = 0;\n\t\t}\n\t\telse {\n\t\t\tguess = (part / n) | 0;\n\t\t}\n\n\t\tvar check = n * guess;\n\t\tdiff = part - check;\n\t\tquot[i++] = guess;\n\t\tif (!guess) {\n\t\t\tdigits.pop();\n\t\t\tcontinue;\n\t\t}\n\n\t\tdigits.pop();\n\t\tpart = diff;\n\t}\n\n\tr = new BigInteger([diff], 1, CONSTRUCT);\n\tif (this._s < 0) {\n\t\tr = r.negate();\n\t}\n\treturn [new BigInteger(quot.reverse(), sign, CONSTRUCT), r];\n};\n\n/*\n\tFunction: isEven\n\tReturn true iff *this* is divisible by two.\n\n\tNote that is even.\n\n\tReturns:\n\n\t\ttrue if *this* is even, false otherwise.\n\n\tSee Also:\n\n\t\t\n*/\nBigInteger.prototype.isEven = function() {\n\tvar digits = this._d;\n\treturn this._s === 0 || digits.length === 0 || (digits[0] % 2) === 0;\n};\n\n/*\n\tFunction: isOdd\n\tReturn true iff *this* is not divisible by two.\n\n\tReturns:\n\n\t\ttrue if *this* is odd, false otherwise.\n\n\tSee Also:\n\n\t\t\n*/\nBigInteger.prototype.isOdd = function() {\n\treturn !this.isEven();\n};\n\n/*\n\tFunction: sign\n\tGet the sign of a .\n\n\tReturns:\n\n\t\t* -1 if *this* < 0\n\t\t* 0 if *this* == 0\n\t\t* +1 if *this* > 0\n\n\tSee Also:\n\n\t\t, , , , \n*/\nBigInteger.prototype.sign = function() {\n\treturn this._s;\n};\n\n/*\n\tFunction: isPositive\n\tReturn true iff *this* > 0.\n\n\tReturns:\n\n\t\ttrue if *this*.compare() == 1.\n\n\tSee Also:\n\n\t\t, , , , , \n*/\nBigInteger.prototype.isPositive = function() {\n\treturn this._s > 0;\n};\n\n/*\n\tFunction: isNegative\n\tReturn true iff *this* < 0.\n\n\tReturns:\n\n\t\ttrue if *this*.compare() == -1.\n\n\tSee Also:\n\n\t\t, , , , , \n*/\nBigInteger.prototype.isNegative = function() {\n\treturn this._s < 0;\n};\n\n/*\n\tFunction: isZero\n\tReturn true iff *this* == 0.\n\n\tReturns:\n\n\t\ttrue if *this*.compare() == 0.\n\n\tSee Also:\n\n\t\t, , , , \n*/\nBigInteger.prototype.isZero = function() {\n\treturn this._s === 0;\n};\n\n/*\n\tFunction: exp10\n\tMultiply a by a power of 10.\n\n\tThis is equivalent to, but faster than\n\n\t> if (n >= 0) {\n\t>\t return this.multiply(BigInteger(\"1e\" + n));\n\t> }\n\t> else { // n <= 0\n\t>\t return this.quotient(BigInteger(\"1e\" + -n));\n\t> }\n\n\tParameters:\n\n\t\tn - The power of 10 to multiply *this* by. *n* is converted to a\n\t\tjavascipt number and must be no greater than \n\t\t(0x7FFFFFFF), or an exception will be thrown.\n\n\tReturns:\n\n\t\t*this* * (10 ** *n*), truncated to an integer if necessary.\n\n\tSee Also:\n\n\t\t, \n*/\nBigInteger.prototype.exp10 = function(n) {\n\tn = +n;\n\tif (n === 0) {\n\t\treturn this;\n\t}\n\tif (Math.abs(n) > Number(MAX_EXP)) {\n\t\tthrow new Error(\"exponent too large in BigInteger.exp10\");\n\t}\n\t// Optimization for this == 0. This also keeps us from having to trim zeros in the positive n case\n\tif (this._s === 0) {\n\t\treturn ZERO;\n\t}\n\tif (n > 0) {\n\t\tvar k = new BigInteger(this._d.slice(), this._s, CONSTRUCT);\n\n\t\tfor (; n >= BigInteger_base_log10; n -= BigInteger_base_log10) {\n\t\t\tk._d.unshift(0);\n\t\t}\n\t\tif (n == 0)\n\t\t\treturn k;\n\t\tk._s = 1;\n\t\tk = k.multiplySingleDigit(Math.pow(10, n));\n\t\treturn (this._s < 0 ? k.negate() : k);\n\t} else if (-n >= this._d.length*BigInteger_base_log10) {\n\t\treturn ZERO;\n\t} else {\n\t\tvar k = new BigInteger(this._d.slice(), this._s, CONSTRUCT);\n\n\t\tfor (n = -n; n >= BigInteger_base_log10; n -= BigInteger_base_log10) {\n\t\t\tk._d.shift();\n\t\t}\n\t\treturn (n == 0) ? k : k.divRemSmall(Math.pow(10, n))[0];\n\t}\n};\n\n/*\n\tFunction: pow\n\tRaise a to a power.\n\n\tIn this implementation, 0**0 is 1.\n\n\tParameters:\n\n\t\tn - The exponent to raise *this* by. *n* must be no greater than\n\t\t (0x7FFFFFFF), or an exception will be thrown.\n\n\tReturns:\n\n\t\t*this* raised to the *nth* power.\n\n\tSee Also:\n\n\t\t\n*/\nBigInteger.prototype.pow = function(n) {\n\tif (this.isUnit()) {\n\t\tif (this._s > 0) {\n\t\t\treturn this;\n\t\t}\n\t\telse {\n\t\t\treturn BigInteger(n).isOdd() ? this : this.negate();\n\t\t}\n\t}\n\n\tn = BigInteger(n);\n\tif (n._s === 0) {\n\t\treturn ONE;\n\t}\n\telse if (n._s < 0) {\n\t\tif (this._s === 0) {\n\t\t\tthrow new Error(\"Divide by zero\");\n\t\t}\n\t\telse {\n\t\t\treturn ZERO;\n\t\t}\n\t}\n\tif (this._s === 0) {\n\t\treturn ZERO;\n\t}\n\tif (n.isUnit()) {\n\t\treturn this;\n\t}\n\n\tif (n.compareAbs(MAX_EXP) > 0) {\n\t\tthrow new Error(\"exponent too large in BigInteger.pow\");\n\t}\n\tvar x = this;\n\tvar aux = ONE;\n\tvar two = BigInteger.small[2];\n\n\twhile (n.isPositive()) {\n\t\tif (n.isOdd()) {\n\t\t\taux = aux.multiply(x);\n\t\t\tif (n.isUnit()) {\n\t\t\t\treturn aux;\n\t\t\t}\n\t\t}\n\t\tx = x.square();\n\t\tn = n.quotient(two);\n\t}\n\n\treturn aux;\n};\n\n/*\n\tFunction: modPow\n\tRaise a to a power (mod m).\n\n\tBecause it is reduced by a modulus, is not limited by\n\t like .\n\n\tParameters:\n\n\t\texponent - The exponent to raise *this* by. Must be positive.\n\t\tmodulus - The modulus.\n\n\tReturns:\n\n\t\t*this* ^ *exponent* (mod *modulus*).\n\n\tSee Also:\n\n\t\t, \n*/\nBigInteger.prototype.modPow = function(exponent, modulus) {\n\tvar result = ONE;\n\tvar base = this;\n\n\twhile (exponent.isPositive()) {\n\t\tif (exponent.isOdd()) {\n\t\t\tresult = result.multiply(base).remainder(modulus);\n\t\t}\n\n\t\texponent = exponent.quotient(BigInteger.small[2]);\n\t\tif (exponent.isPositive()) {\n\t\t\tbase = base.square().remainder(modulus);\n\t\t}\n\t}\n\n\treturn result;\n};\n\n/*\n\tFunction: log\n\tGet the natural logarithm of a as a native JavaScript number.\n\n\tThis is equivalent to\n\n\t> Math.log(this.toJSValue())\n\n\tbut handles values outside of the native number range.\n\n\tReturns:\n\n\t\tlog( *this* )\n\n\tSee Also:\n\n\t\t\n*/\nBigInteger.prototype.log = function() {\n\tswitch (this._s) {\n\tcase 0:\t return -Infinity;\n\tcase -1: return NaN;\n\tdefault: // Fall through.\n\t}\n\n\tvar l = this._d.length;\n\n\tif (l*BigInteger_base_log10 < 30) {\n\t\treturn Math.log(this.valueOf());\n\t}\n\n\tvar N = Math.ceil(30/BigInteger_base_log10);\n\tvar firstNdigits = this._d.slice(l - N);\n\treturn Math.log((new BigInteger(firstNdigits, 1, CONSTRUCT)).valueOf()) + (l - N) * Math.log(BigInteger_base);\n};\n\n/*\n\tFunction: valueOf\n\tConvert a to a native JavaScript integer.\n\n\tThis is called automatically by JavaScipt to convert a to a\n\tnative value.\n\n\tReturns:\n\n\t\t> parseInt(this.toString(), 10)\n\n\tSee Also:\n\n\t\t, \n*/\nBigInteger.prototype.valueOf = function() {\n\treturn parseInt(this.toString(), 10);\n};\n\n/*\n\tFunction: toJSValue\n\tConvert a to a native JavaScript integer.\n\n\tThis is the same as valueOf, but more explicitly named.\n\n\tReturns:\n\n\t\t> parseInt(this.toString(), 10)\n\n\tSee Also:\n\n\t\t, \n*/\nBigInteger.prototype.toJSValue = function() {\n\treturn parseInt(this.toString(), 10);\n};\n\n/*\n\tFunction: lowVal\n\tAuthor: Lucas Jones\n*/\nBigInteger.prototype.lowVal = function () {\n\treturn this._d[0] || 0;\n};\n\nvar MAX_EXP = BigInteger(0x7FFFFFFF);\n// Constant: MAX_EXP\n// The largest exponent allowed in and (0x7FFFFFFF or 2147483647).\nBigInteger.MAX_EXP = MAX_EXP;\n\n(function() {\n\tfunction makeUnary(fn) {\n\t\treturn function(a) {\n\t\t\treturn fn.call(BigInteger(a));\n\t\t};\n\t}\n\n\tfunction makeBinary(fn) {\n\t\treturn function(a, b) {\n\t\t\treturn fn.call(BigInteger(a), BigInteger(b));\n\t\t};\n\t}\n\n\tfunction makeTrinary(fn) {\n\t\treturn function(a, b, c) {\n\t\t\treturn fn.call(BigInteger(a), BigInteger(b), BigInteger(c));\n\t\t};\n\t}\n\n\t(function() {\n\t\tvar i, fn;\n\t\tvar unary = \"toJSValue,isEven,isOdd,sign,isZero,isNegative,abs,isUnit,square,negate,isPositive,toString,next,prev,log\".split(\",\");\n\t\tvar binary = \"compare,remainder,divRem,subtract,add,quotient,divide,multiply,pow,compareAbs\".split(\",\");\n\t\tvar trinary = [\"modPow\"];\n\n\t\tfor (i = 0; i < unary.length; i++) {\n\t\t\tfn = unary[i];\n\t\t\tBigInteger[fn] = makeUnary(BigInteger.prototype[fn]);\n\t\t}\n\n\t\tfor (i = 0; i < binary.length; i++) {\n\t\t\tfn = binary[i];\n\t\t\tBigInteger[fn] = makeBinary(BigInteger.prototype[fn]);\n\t\t}\n\n\t\tfor (i = 0; i < trinary.length; i++) {\n\t\t\tfn = trinary[i];\n\t\t\tBigInteger[fn] = makeTrinary(BigInteger.prototype[fn]);\n\t\t}\n\n\t\tBigInteger.exp10 = function(x, n) {\n\t\t\treturn BigInteger(x).exp10(n);\n\t\t};\n\t})();\n})();\n\nexports.BigInteger = BigInteger;\n})(typeof exports !== 'undefined' ? exports : this);","var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || new Function(\"return this\")();\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n","/* eslint-disable node/no-deprecated-api */\n\n'use strict'\n\nvar buffer = require('buffer')\nvar Buffer = buffer.Buffer\n\nvar safer = {}\n\nvar key\n\nfor (key in buffer) {\n if (!buffer.hasOwnProperty(key)) continue\n if (key === 'SlowBuffer' || key === 'Buffer') continue\n safer[key] = buffer[key]\n}\n\nvar Safer = safer.Buffer = {}\nfor (key in Buffer) {\n if (!Buffer.hasOwnProperty(key)) continue\n if (key === 'allocUnsafe' || key === 'allocUnsafeSlow') continue\n Safer[key] = Buffer[key]\n}\n\nsafer.Buffer.prototype = Buffer.prototype\n\nif (!Safer.from || Safer.from === Uint8Array.from) {\n Safer.from = function (value, encodingOrOffset, length) {\n if (typeof value === 'number') {\n throw new TypeError('The \"value\" argument must not be of type number. Received type ' + typeof value)\n }\n if (value && typeof value.length === 'undefined') {\n throw new TypeError('The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type ' + typeof value)\n }\n return Buffer(value, encodingOrOffset, length)\n }\n}\n\nif (!Safer.alloc) {\n Safer.alloc = function (size, fill, encoding) {\n if (typeof size !== 'number') {\n throw new TypeError('The \"size\" argument must be of type number. Received type ' + typeof size)\n }\n if (size < 0 || size >= 2 * (1 << 30)) {\n throw new RangeError('The value \"' + size + '\" is invalid for option \"size\"')\n }\n var buf = Buffer(size)\n if (!fill || fill.length === 0) {\n buf.fill(0)\n } else if (typeof encoding === 'string') {\n buf.fill(fill, encoding)\n } else {\n buf.fill(fill)\n }\n return buf\n }\n}\n\nif (!safer.kStringMaxLength) {\n try {\n safer.kStringMaxLength = process.binding('buffer').kStringMaxLength\n } catch (e) {\n // we can't determine kStringMaxLength in environments where process.binding\n // is unsupported, so let's not set it\n }\n}\n\nif (!safer.constants) {\n safer.constants = {\n MAX_LENGTH: safer.kMaxLength\n }\n if (safer.kStringMaxLength) {\n safer.constants.MAX_STRING_LENGTH = safer.kStringMaxLength\n }\n}\n\nmodule.exports = safer\n","'use strict'\n\nexports.randomBytes = exports.rng = exports.pseudoRandomBytes = exports.prng = require('randombytes')\nexports.createHash = exports.Hash = require('create-hash')\nexports.createHmac = exports.Hmac = require('create-hmac')\n\nvar algos = require('browserify-sign/algos')\nvar algoKeys = Object.keys(algos)\nvar hashes = ['sha1', 'sha224', 'sha256', 'sha384', 'sha512', 'md5', 'rmd160'].concat(algoKeys)\nexports.getHashes = function () {\n return hashes\n}\n\nvar p = require('pbkdf2')\nexports.pbkdf2 = p.pbkdf2\nexports.pbkdf2Sync = p.pbkdf2Sync\n\nvar aes = require('browserify-cipher')\n\nexports.Cipher = aes.Cipher\nexports.createCipher = aes.createCipher\nexports.Cipheriv = aes.Cipheriv\nexports.createCipheriv = aes.createCipheriv\nexports.Decipher = aes.Decipher\nexports.createDecipher = aes.createDecipher\nexports.Decipheriv = aes.Decipheriv\nexports.createDecipheriv = aes.createDecipheriv\nexports.getCiphers = aes.getCiphers\nexports.listCiphers = aes.listCiphers\n\nvar dh = require('diffie-hellman')\n\nexports.DiffieHellmanGroup = dh.DiffieHellmanGroup\nexports.createDiffieHellmanGroup = dh.createDiffieHellmanGroup\nexports.getDiffieHellman = dh.getDiffieHellman\nexports.createDiffieHellman = dh.createDiffieHellman\nexports.DiffieHellman = dh.DiffieHellman\n\nvar sign = require('browserify-sign')\n\nexports.createSign = sign.createSign\nexports.Sign = sign.Sign\nexports.createVerify = sign.createVerify\nexports.Verify = sign.Verify\n\nexports.createECDH = require('create-ecdh')\n\nvar publicEncrypt = require('public-encrypt')\n\nexports.publicEncrypt = publicEncrypt.publicEncrypt\nexports.privateEncrypt = publicEncrypt.privateEncrypt\nexports.publicDecrypt = publicEncrypt.publicDecrypt\nexports.privateDecrypt = publicEncrypt.privateDecrypt\n\n// the least I can do is make error messages for the rest of the node.js/crypto api.\n// ;[\n// 'createCredentials'\n// ].forEach(function (name) {\n// exports[name] = function () {\n// throw new Error([\n// 'sorry, ' + name + ' is not implemented yet',\n// 'we accept pull requests',\n// 'https://github.com/crypto-browserify/crypto-browserify'\n// ].join('\\n'))\n// }\n// })\n\nvar rf = require('randomfill')\n\nexports.randomFill = rf.randomFill\nexports.randomFillSync = rf.randomFillSync\n\nexports.createCredentials = function () {\n throw new Error([\n 'sorry, createCredentials is not implemented yet',\n 'we accept pull requests',\n 'https://github.com/crypto-browserify/crypto-browserify'\n ].join('\\n'))\n}\n\nexports.constants = {\n 'DH_CHECK_P_NOT_SAFE_PRIME': 2,\n 'DH_CHECK_P_NOT_PRIME': 1,\n 'DH_UNABLE_TO_CHECK_GENERATOR': 4,\n 'DH_NOT_SUITABLE_GENERATOR': 8,\n 'NPN_ENABLED': 1,\n 'ALPN_ENABLED': 1,\n 'RSA_PKCS1_PADDING': 1,\n 'RSA_SSLV23_PADDING': 2,\n 'RSA_NO_PADDING': 3,\n 'RSA_PKCS1_OAEP_PADDING': 4,\n 'RSA_X931_PADDING': 5,\n 'RSA_PKCS1_PSS_PADDING': 6,\n 'POINT_CONVERSION_COMPRESSED': 2,\n 'POINT_CONVERSION_UNCOMPRESSED': 4,\n 'POINT_CONVERSION_HYBRID': 6\n}\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nvar getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors ||\n function getOwnPropertyDescriptors(obj) {\n var keys = Object.keys(obj);\n var descriptors = {};\n for (var i = 0; i < keys.length; i++) {\n descriptors[keys[i]] = Object.getOwnPropertyDescriptor(obj, keys[i]);\n }\n return descriptors;\n };\n\nvar formatRegExp = /%[sdj%]/g;\nexports.format = function(f) {\n if (!isString(f)) {\n var objects = [];\n for (var i = 0; i < arguments.length; i++) {\n objects.push(inspect(arguments[i]));\n }\n return objects.join(' ');\n }\n\n var i = 1;\n var args = arguments;\n var len = args.length;\n var str = String(f).replace(formatRegExp, function(x) {\n if (x === '%%') return '%';\n if (i >= len) return x;\n switch (x) {\n case '%s': return String(args[i++]);\n case '%d': return Number(args[i++]);\n case '%j':\n try {\n return JSON.stringify(args[i++]);\n } catch (_) {\n return '[Circular]';\n }\n default:\n return x;\n }\n });\n for (var x = args[i]; i < len; x = args[++i]) {\n if (isNull(x) || !isObject(x)) {\n str += ' ' + x;\n } else {\n str += ' ' + inspect(x);\n }\n }\n return str;\n};\n\n\n// Mark that a method should not be used.\n// Returns a modified function which warns once by default.\n// If --no-deprecation is set, then it is a no-op.\nexports.deprecate = function(fn, msg) {\n if (typeof process !== 'undefined' && process.noDeprecation === true) {\n return fn;\n }\n\n // Allow for deprecating things in the process of starting up.\n if (typeof process === 'undefined') {\n return function() {\n return exports.deprecate(fn, msg).apply(this, arguments);\n };\n }\n\n var warned = false;\n function deprecated() {\n if (!warned) {\n if (process.throwDeprecation) {\n throw new Error(msg);\n } else if (process.traceDeprecation) {\n console.trace(msg);\n } else {\n console.error(msg);\n }\n warned = true;\n }\n return fn.apply(this, arguments);\n }\n\n return deprecated;\n};\n\n\nvar debugs = {};\nvar debugEnviron;\nexports.debuglog = function(set) {\n if (isUndefined(debugEnviron))\n debugEnviron = process.env.NODE_DEBUG || '';\n set = set.toUpperCase();\n if (!debugs[set]) {\n if (new RegExp('\\\\b' + set + '\\\\b', 'i').test(debugEnviron)) {\n var pid = process.pid;\n debugs[set] = function() {\n var msg = exports.format.apply(exports, arguments);\n console.error('%s %d: %s', set, pid, msg);\n };\n } else {\n debugs[set] = function() {};\n }\n }\n return debugs[set];\n};\n\n\n/**\n * Echos the value of a value. Trys to print the value out\n * in the best way possible given the different types.\n *\n * @param {Object} obj The object to print out.\n * @param {Object} opts Optional options object that alters the output.\n */\n/* legacy: obj, showHidden, depth, colors*/\nfunction inspect(obj, opts) {\n // default options\n var ctx = {\n seen: [],\n stylize: stylizeNoColor\n };\n // legacy...\n if (arguments.length >= 3) ctx.depth = arguments[2];\n if (arguments.length >= 4) ctx.colors = arguments[3];\n if (isBoolean(opts)) {\n // legacy...\n ctx.showHidden = opts;\n } else if (opts) {\n // got an \"options\" object\n exports._extend(ctx, opts);\n }\n // set default options\n if (isUndefined(ctx.showHidden)) ctx.showHidden = false;\n if (isUndefined(ctx.depth)) ctx.depth = 2;\n if (isUndefined(ctx.colors)) ctx.colors = false;\n if (isUndefined(ctx.customInspect)) ctx.customInspect = true;\n if (ctx.colors) ctx.stylize = stylizeWithColor;\n return formatValue(ctx, obj, ctx.depth);\n}\nexports.inspect = inspect;\n\n\n// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics\ninspect.colors = {\n 'bold' : [1, 22],\n 'italic' : [3, 23],\n 'underline' : [4, 24],\n 'inverse' : [7, 27],\n 'white' : [37, 39],\n 'grey' : [90, 39],\n 'black' : [30, 39],\n 'blue' : [34, 39],\n 'cyan' : [36, 39],\n 'green' : [32, 39],\n 'magenta' : [35, 39],\n 'red' : [31, 39],\n 'yellow' : [33, 39]\n};\n\n// Don't use 'blue' not visible on cmd.exe\ninspect.styles = {\n 'special': 'cyan',\n 'number': 'yellow',\n 'boolean': 'yellow',\n 'undefined': 'grey',\n 'null': 'bold',\n 'string': 'green',\n 'date': 'magenta',\n // \"name\": intentionally not styling\n 'regexp': 'red'\n};\n\n\nfunction stylizeWithColor(str, styleType) {\n var style = inspect.styles[styleType];\n\n if (style) {\n return '\\u001b[' + inspect.colors[style][0] + 'm' + str +\n '\\u001b[' + inspect.colors[style][1] + 'm';\n } else {\n return str;\n }\n}\n\n\nfunction stylizeNoColor(str, styleType) {\n return str;\n}\n\n\nfunction arrayToHash(array) {\n var hash = {};\n\n array.forEach(function(val, idx) {\n hash[val] = true;\n });\n\n return hash;\n}\n\n\nfunction formatValue(ctx, value, recurseTimes) {\n // Provide a hook for user-specified inspect functions.\n // Check that value is an object with an inspect function on it\n if (ctx.customInspect &&\n value &&\n isFunction(value.inspect) &&\n // Filter out the util module, it's inspect function is special\n value.inspect !== exports.inspect &&\n // Also filter out any prototype objects using the circular check.\n !(value.constructor && value.constructor.prototype === value)) {\n var ret = value.inspect(recurseTimes, ctx);\n if (!isString(ret)) {\n ret = formatValue(ctx, ret, recurseTimes);\n }\n return ret;\n }\n\n // Primitive types cannot have properties\n var primitive = formatPrimitive(ctx, value);\n if (primitive) {\n return primitive;\n }\n\n // Look up the keys of the object.\n var keys = Object.keys(value);\n var visibleKeys = arrayToHash(keys);\n\n if (ctx.showHidden) {\n keys = Object.getOwnPropertyNames(value);\n }\n\n // IE doesn't make error fields non-enumerable\n // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx\n if (isError(value)\n && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {\n return formatError(value);\n }\n\n // Some type of object without properties can be shortcutted.\n if (keys.length === 0) {\n if (isFunction(value)) {\n var name = value.name ? ': ' + value.name : '';\n return ctx.stylize('[Function' + name + ']', 'special');\n }\n if (isRegExp(value)) {\n return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');\n }\n if (isDate(value)) {\n return ctx.stylize(Date.prototype.toString.call(value), 'date');\n }\n if (isError(value)) {\n return formatError(value);\n }\n }\n\n var base = '', array = false, braces = ['{', '}'];\n\n // Make Array say that they are Array\n if (isArray(value)) {\n array = true;\n braces = ['[', ']'];\n }\n\n // Make functions say that they are functions\n if (isFunction(value)) {\n var n = value.name ? ': ' + value.name : '';\n base = ' [Function' + n + ']';\n }\n\n // Make RegExps say that they are RegExps\n if (isRegExp(value)) {\n base = ' ' + RegExp.prototype.toString.call(value);\n }\n\n // Make dates with properties first say the date\n if (isDate(value)) {\n base = ' ' + Date.prototype.toUTCString.call(value);\n }\n\n // Make error with message first say the error\n if (isError(value)) {\n base = ' ' + formatError(value);\n }\n\n if (keys.length === 0 && (!array || value.length == 0)) {\n return braces[0] + base + braces[1];\n }\n\n if (recurseTimes < 0) {\n if (isRegExp(value)) {\n return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');\n } else {\n return ctx.stylize('[Object]', 'special');\n }\n }\n\n ctx.seen.push(value);\n\n var output;\n if (array) {\n output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);\n } else {\n output = keys.map(function(key) {\n return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);\n });\n }\n\n ctx.seen.pop();\n\n return reduceToSingleString(output, base, braces);\n}\n\n\nfunction formatPrimitive(ctx, value) {\n if (isUndefined(value))\n return ctx.stylize('undefined', 'undefined');\n if (isString(value)) {\n var simple = '\\'' + JSON.stringify(value).replace(/^\"|\"$/g, '')\n .replace(/'/g, \"\\\\'\")\n .replace(/\\\\\"/g, '\"') + '\\'';\n return ctx.stylize(simple, 'string');\n }\n if (isNumber(value))\n return ctx.stylize('' + value, 'number');\n if (isBoolean(value))\n return ctx.stylize('' + value, 'boolean');\n // For some reason typeof null is \"object\", so special case here.\n if (isNull(value))\n return ctx.stylize('null', 'null');\n}\n\n\nfunction formatError(value) {\n return '[' + Error.prototype.toString.call(value) + ']';\n}\n\n\nfunction formatArray(ctx, value, recurseTimes, visibleKeys, keys) {\n var output = [];\n for (var i = 0, l = value.length; i < l; ++i) {\n if (hasOwnProperty(value, String(i))) {\n output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,\n String(i), true));\n } else {\n output.push('');\n }\n }\n keys.forEach(function(key) {\n if (!key.match(/^\\d+$/)) {\n output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,\n key, true));\n }\n });\n return output;\n}\n\n\nfunction formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {\n var name, str, desc;\n desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };\n if (desc.get) {\n if (desc.set) {\n str = ctx.stylize('[Getter/Setter]', 'special');\n } else {\n str = ctx.stylize('[Getter]', 'special');\n }\n } else {\n if (desc.set) {\n str = ctx.stylize('[Setter]', 'special');\n }\n }\n if (!hasOwnProperty(visibleKeys, key)) {\n name = '[' + key + ']';\n }\n if (!str) {\n if (ctx.seen.indexOf(desc.value) < 0) {\n if (isNull(recurseTimes)) {\n str = formatValue(ctx, desc.value, null);\n } else {\n str = formatValue(ctx, desc.value, recurseTimes - 1);\n }\n if (str.indexOf('\\n') > -1) {\n if (array) {\n str = str.split('\\n').map(function(line) {\n return ' ' + line;\n }).join('\\n').substr(2);\n } else {\n str = '\\n' + str.split('\\n').map(function(line) {\n return ' ' + line;\n }).join('\\n');\n }\n }\n } else {\n str = ctx.stylize('[Circular]', 'special');\n }\n }\n if (isUndefined(name)) {\n if (array && key.match(/^\\d+$/)) {\n return str;\n }\n name = JSON.stringify('' + key);\n if (name.match(/^\"([a-zA-Z_][a-zA-Z_0-9]*)\"$/)) {\n name = name.substr(1, name.length - 2);\n name = ctx.stylize(name, 'name');\n } else {\n name = name.replace(/'/g, \"\\\\'\")\n .replace(/\\\\\"/g, '\"')\n .replace(/(^\"|\"$)/g, \"'\");\n name = ctx.stylize(name, 'string');\n }\n }\n\n return name + ': ' + str;\n}\n\n\nfunction reduceToSingleString(output, base, braces) {\n var numLinesEst = 0;\n var length = output.reduce(function(prev, cur) {\n numLinesEst++;\n if (cur.indexOf('\\n') >= 0) numLinesEst++;\n return prev + cur.replace(/\\u001b\\[\\d\\d?m/g, '').length + 1;\n }, 0);\n\n if (length > 60) {\n return braces[0] +\n (base === '' ? '' : base + '\\n ') +\n ' ' +\n output.join(',\\n ') +\n ' ' +\n braces[1];\n }\n\n return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];\n}\n\n\n// NOTE: These type checking functions intentionally don't use `instanceof`\n// because it is fragile and can be easily faked with `Object.create()`.\nfunction isArray(ar) {\n return Array.isArray(ar);\n}\nexports.isArray = isArray;\n\nfunction isBoolean(arg) {\n return typeof arg === 'boolean';\n}\nexports.isBoolean = isBoolean;\n\nfunction isNull(arg) {\n return arg === null;\n}\nexports.isNull = isNull;\n\nfunction isNullOrUndefined(arg) {\n return arg == null;\n}\nexports.isNullOrUndefined = isNullOrUndefined;\n\nfunction isNumber(arg) {\n return typeof arg === 'number';\n}\nexports.isNumber = isNumber;\n\nfunction isString(arg) {\n return typeof arg === 'string';\n}\nexports.isString = isString;\n\nfunction isSymbol(arg) {\n return typeof arg === 'symbol';\n}\nexports.isSymbol = isSymbol;\n\nfunction isUndefined(arg) {\n return arg === void 0;\n}\nexports.isUndefined = isUndefined;\n\nfunction isRegExp(re) {\n return isObject(re) && objectToString(re) === '[object RegExp]';\n}\nexports.isRegExp = isRegExp;\n\nfunction isObject(arg) {\n return typeof arg === 'object' && arg !== null;\n}\nexports.isObject = isObject;\n\nfunction isDate(d) {\n return isObject(d) && objectToString(d) === '[object Date]';\n}\nexports.isDate = isDate;\n\nfunction isError(e) {\n return isObject(e) &&\n (objectToString(e) === '[object Error]' || e instanceof Error);\n}\nexports.isError = isError;\n\nfunction isFunction(arg) {\n return typeof arg === 'function';\n}\nexports.isFunction = isFunction;\n\nfunction isPrimitive(arg) {\n return arg === null ||\n typeof arg === 'boolean' ||\n typeof arg === 'number' ||\n typeof arg === 'string' ||\n typeof arg === 'symbol' || // ES6 symbol\n typeof arg === 'undefined';\n}\nexports.isPrimitive = isPrimitive;\n\nexports.isBuffer = require('./support/isBuffer');\n\nfunction objectToString(o) {\n return Object.prototype.toString.call(o);\n}\n\n\nfunction pad(n) {\n return n < 10 ? '0' + n.toString(10) : n.toString(10);\n}\n\n\nvar months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',\n 'Oct', 'Nov', 'Dec'];\n\n// 26 Feb 16:19:34\nfunction timestamp() {\n var d = new Date();\n var time = [pad(d.getHours()),\n pad(d.getMinutes()),\n pad(d.getSeconds())].join(':');\n return [d.getDate(), months[d.getMonth()], time].join(' ');\n}\n\n\n// log is just a thin wrapper to console.log that prepends a timestamp\nexports.log = function() {\n console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));\n};\n\n\n/**\n * Inherit the prototype methods from one constructor into another.\n *\n * The Function.prototype.inherits from lang.js rewritten as a standalone\n * function (not on Function.prototype). NOTE: If this file is to be loaded\n * during bootstrapping this function needs to be rewritten using some native\n * functions as prototype setup using normal JavaScript does not work as\n * expected during bootstrapping (see mirror.js in r114903).\n *\n * @param {function} ctor Constructor function which needs to inherit the\n * prototype.\n * @param {function} superCtor Constructor function to inherit prototype from.\n */\nexports.inherits = require('inherits');\n\nexports._extend = function(origin, add) {\n // Don't do anything if add isn't an object\n if (!add || !isObject(add)) return origin;\n\n var keys = Object.keys(add);\n var i = keys.length;\n while (i--) {\n origin[keys[i]] = add[keys[i]];\n }\n return origin;\n};\n\nfunction hasOwnProperty(obj, prop) {\n return Object.prototype.hasOwnProperty.call(obj, prop);\n}\n\nvar kCustomPromisifiedSymbol = typeof Symbol !== 'undefined' ? Symbol('util.promisify.custom') : undefined;\n\nexports.promisify = function promisify(original) {\n if (typeof original !== 'function')\n throw new TypeError('The \"original\" argument must be of type Function');\n\n if (kCustomPromisifiedSymbol && original[kCustomPromisifiedSymbol]) {\n var fn = original[kCustomPromisifiedSymbol];\n if (typeof fn !== 'function') {\n throw new TypeError('The \"util.promisify.custom\" argument must be of type Function');\n }\n Object.defineProperty(fn, kCustomPromisifiedSymbol, {\n value: fn, enumerable: false, writable: false, configurable: true\n });\n return fn;\n }\n\n function fn() {\n var promiseResolve, promiseReject;\n var promise = new Promise(function (resolve, reject) {\n promiseResolve = resolve;\n promiseReject = reject;\n });\n\n var args = [];\n for (var i = 0; i < arguments.length; i++) {\n args.push(arguments[i]);\n }\n args.push(function (err, value) {\n if (err) {\n promiseReject(err);\n } else {\n promiseResolve(value);\n }\n });\n\n try {\n original.apply(this, args);\n } catch (err) {\n promiseReject(err);\n }\n\n return promise;\n }\n\n Object.setPrototypeOf(fn, Object.getPrototypeOf(original));\n\n if (kCustomPromisifiedSymbol) Object.defineProperty(fn, kCustomPromisifiedSymbol, {\n value: fn, enumerable: false, writable: false, configurable: true\n });\n return Object.defineProperties(\n fn,\n getOwnPropertyDescriptors(original)\n );\n}\n\nexports.promisify.custom = kCustomPromisifiedSymbol\n\nfunction callbackifyOnRejected(reason, cb) {\n // `!reason` guard inspired by bluebird (Ref: https://goo.gl/t5IS6M).\n // Because `null` is a special error value in callbacks which means \"no error\n // occurred\", we error-wrap so the callback consumer can distinguish between\n // \"the promise rejected with null\" or \"the promise fulfilled with undefined\".\n if (!reason) {\n var newReason = new Error('Promise was rejected with a falsy value');\n newReason.reason = reason;\n reason = newReason;\n }\n return cb(reason);\n}\n\nfunction callbackify(original) {\n if (typeof original !== 'function') {\n throw new TypeError('The \"original\" argument must be of type Function');\n }\n\n // We DO NOT return the promise as it gives the user a false sense that\n // the promise is actually somehow related to the callback's execution\n // and that the callback throwing will reject the promise.\n function callbackified() {\n var args = [];\n for (var i = 0; i < arguments.length; i++) {\n args.push(arguments[i]);\n }\n\n var maybeCb = args.pop();\n if (typeof maybeCb !== 'function') {\n throw new TypeError('The last argument must be of type Function');\n }\n var self = this;\n var cb = function() {\n return maybeCb.apply(self, arguments);\n };\n // In true node style we process the callback on `nextTick` with all the\n // implications (stack, `uncaughtException`, `async_hooks`)\n original.apply(this, args)\n .then(function(ret) { process.nextTick(cb, null, ret) },\n function(rej) { process.nextTick(callbackifyOnRejected, rej, cb) });\n }\n\n Object.setPrototypeOf(callbackified, Object.getPrototypeOf(original));\n Object.defineProperties(callbackified,\n getOwnPropertyDescriptors(original));\n return callbackified;\n}\nexports.callbackify = callbackify;\n","const assert = require(\"assert\");\nconst BigInteger = require(\"./biginteger\").BigInteger;\n\n/**\n * MIT License\n * \n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n * \n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n * \n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Collection of general purpose utilities.\n * \n * TODO: could pull in assert and remove these asserts\n * TODO: needs cleanup as ES6+ utility class\n */\nclass GenUtils {\n \n /**\n * Indicates if the given argument is defined.\n * \n * @param arg is the arg to test\n * @returns true if the given arg is defined, false otherwise\n */\n static isDefined(arg) {\n return typeof arg !== 'undefined';\n }\n\n /**\n * Indicates if the given argument is undefined.\n * \n * @param arg is the arg to test\n * @returns true if the given arg is undefined, false otherwise\n */\n static isUndefined(arg) {\n return typeof arg === 'undefined';\n }\n\n /**\n * Indicates if the given arg is initialized.\n * \n * @param arg is the arg to test\n * @returns true if the given arg is initialized, false otherwise\n */\n static isInitialized(arg) {\n return arg !== undefined && arg !== null;\n }\n\n /**\n * Indicates if the given arg is uninitialized.\n * \n * @param arg is the arg to test\n * @returns true if the given arg is uninitialized, false otherwise\n */\n static isUninitialized(arg) {\n if (!arg) return true;\n return false;\n }\n\n /**\n * Indicates if the given argument is a number.\n * \n * @param arg is the argument to test\n * @returns true if the argument is a number, false otherwise\n */\n static isNumber(arg) {\n return !isNaN(parseFloat(arg)) && isFinite(arg);\n }\n\n /**\n * Indicates if the given argument is an integer.\n * \n * @param arg is the argument to test\n * @returns true if the given argument is an integer, false otherwise\n */\n static isInt(arg) {\n return arg === parseInt(Number(arg)) && !isNaN(arg) && !isNaN(parseInt(arg, 10));\n }\n\n /**\n * Indicates if the given argument is an array.\n * \n * TODO: remove this entirely since just a direct wrapper?\n * TODO: this method returns true for object\n * \n * @param arg is the argument to test as being an array\n * @returns true if the argument is an array, false otherwise\n */\n static isArray(arg) {\n return Array.isArray(arg);\n }\n\n /**\n * Indicates if the given argument is a string.\n * \n * @param arg is the argument to test as being a string\n * @returns true if the argument is a string, false otherwise\n */\n static isString(arg) {\n return typeof arg === 'string';\n }\n\n /**\n * Determines if the given argument is a boolean.\n * \n * @param arg is the argument to test as being a boolean\n * @returns true if the argument is a boolean, false otherwise\n */\n static isBoolean(arg) {\n return typeof(arg) == typeof(true);\n }\n\n /**\n * Determines if the given argument is a static.\n * \n * @param arg is the argument to test as being a static\n * @returns true if the argument is a static, false otherwise\n */\n static isFunction(arg) {\n return typeof arg === \"static\";\n }\n\n /**\n * Indicates if the given argument is an object and optionally if it has the given constructor name.\n * \n * @param arg is the argument to test\n * @param obj is an object to test arg instanceof obj (optional)\n * @returns true if the given argument is an object and optionally has the given constructor name\n */\n static isObject(arg, obj) {\n if (!arg) return false;\n if (typeof arg !== 'object') return false;\n if (obj && !(arg instanceof obj)) return false;\n return true;\n }\n\n /**\n * Determines if all alphabet characters in the given string are upper case.\n * \n * @param str is the string to test\n * @returns true if the string is upper case, false otherwise\n */\n static isUpperCase(str) {\n return str.toUpperCase() === str;\n }\n\n /**\n * Determines if all alphabet characters in the given string are lower case.\n * \n * @param str is the string to test\n * @param true if the string is lower case, false otherwise\n */\n static isLowerCase(str) {\n return str.toLowerCase() === str;\n }\n\n /**\n * Asserts that the given argument is hex.\n * \n * @param arg is the argument to assert as hex\n * @param msg is the message to throw if the argument is not hex\n */\n static assertHex(str, msg) {\n GenUtils.assertTrue(isHex(str), msg ? msg : \"Argument asserted as hex but is not hex\");\n }\n\n /**\n * Indicates if the given argument is a hexidemal string.\n * \n * Credit: https://github.com/roryrjb/is-hex/blob/master/is-hex.js.\n * \n * @param str is the string to test\n * @returns true if the given string is hexidecimal, false otherwise\n */\n static isHex(arg) {\n if (typeof arg !== 'string') return false;\n if (arg.length === 0) return false;\n return (arg.match(/([0-9]|[a-f])/gim) || []).length === arg.length;\n }\n\n /**\n * Determines if the given string is base32.\n */\n static isBase32(str) {\n if (typeof str !== 'string') return false;\n GenUtils.assertTrue(str.length > 0, \"Cannot determine if empty string is base32\");\n return /^[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]+$/.test(str);\n }\n\n /**\n * Asserts that the given argument is base58.\n * \n * @param arg is the argument to assert as base58\n * @param msg is the message to throw if the argument is not base58\n */\n static assertBase58(str, msg) {\n GenUtils.assertTrue(isBase58(str), msg ? msg : \"Argument asserted as base58 but is not base58\");\n }\n\n /**\n * Determines if the given string is base58.\n */\n static isBase58(str) {\n if (typeof str !== 'string') return false;\n GenUtils.assertTrue(str.length > 0, \"Cannot determine if empty string is base58\");\n return /^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$/.test(str);\n }\n\n /**\n * Asserts that the given argument is base64.\n * \n * @param arg is the argument to assert as base64\n * @param msg is the message to throw if the argument is not base64\n */\n static assertBase64(str, msg) {\n GenUtils.assertTrue(isBase64(str), msg ? msg : \"Argument asserted as base64 but is not base64\");\n }\n\n /**\n * Determines if the given string is base64.\n */\n static isBase64(str) {\n if (typeof str !== 'string') return false;\n GenUtils.assertTrue(str.length > 0, \"Cannot determine if empty string is base64\");\n try {\n return btoa(atob(str)) == str;\n } catch (err) {\n return false;\n }\n }\n\n /**\n * Throws an exception with the given message.\n * \n * @param msg defines the message to throw the exception with (optional)\n */\n static fail(msg) {\n throw new Error(msg ? msg : \"Failure (no message)\");\n }\n\n /**\n * Asserts that the given boolean is true. Throws an exception if not a boolean or false.\n * \n * @param bool is the boolean to assert true\n * @param msg is the message to throw if bool is false (optional)\n */\n static assertTrue(bool, msg) {\n if (typeof bool !== 'boolean') throw new Error(\"Argument is not a boolean\");\n if (!bool) throw new Error(msg ? msg : \"Boolean asserted as true but was false\");\n }\n\n /**\n * Asserts that the given boolean is false. Throws an exception if not a boolean or true.\n * \n * @param bool is the boolean to assert false\n * @param msg is the message to throw if bool is true (optional)\n */\n static assertFalse(bool, msg) {\n if (typeof bool !== 'boolean') throw new Error(\"Argument is not a boolean\");\n if (bool) throw new Error(msg ? msg : \"Boolean asserted as false but was true\");\n }\n\n /**\n * Asserts that the given argument is null. Throws an exception if not null.\n * \n * @param arg is the argument to assert null\n * @param msg is the message to throw if arg is not null (optional)\n */\n static assertNull(arg, msg) {\n if (arg !== null) throw new Error(msg ? msg : \"Argument asserted as null but was not null: \" + arg);\n }\n\n /**\n * Asserts that the given argument is not null. Throws an exception if null.\n * \n * @param arg is the argument to assert not null\n * @param msg is the message to throw if arg is null (optional)\n */\n static assertNotNull(arg, msg) {\n if (arg === null) throw new Error(msg ? msg : \"Argument asserted as not null but was null\");\n }\n\n /**\n * Asserts that the given argument is defined. Throws an exception if undefined.\n * \n * @param arg is the argument to assert defined\n * @param msg is the message to throw if arg is undefined (optional)\n */\n static assertDefined(arg, msg) {\n if (GenUtils.isUndefined(arg)) throw new Error(msg ? msg : \"Argument asserted as defined but was undefined\");\n }\n\n /**\n * Asserts that the given argument is undefined. Throws an exception if defined.\n * \n * @param arg is the argument to assert undefined\n * @param msg is the message to throw if arg is defined (optional)\n */\n static assertUndefined(arg, msg) {\n if (GenUtils.isDefined(arg)) throw new Error(msg ? msg : \"Argument asserted as undefined but was defined: \" + arg);\n }\n\n /**\n * Asserts that the given argument is initialized. Throws an exception if not initialized.\n * \n * @param arg is the argument to assert as initialized\n * @param msg is the message to throw if arg is not initialized (optional)\n */\n static assertInitialized(arg, msg) {\n if (GenUtils.isUninitialized(arg)) {\n throw new Error(msg ? msg : \"Argument asserted as initialized but was \" + arg);\n }\n }\n\n /**\n * Asserts that the given argument is uninitialized. Throws an exception if initialized.\n * \n * @param arg is the argument to assert as uninitialized\n * @param msg is the message to throw if arg is initialized (optional)\n */\n static assertUninitialized(arg, msg) {\n if (GenUtils.isInitialized(arg)) throw new Error(msg ? msg : \"Argument asserted as uninitialized but was initialized\");\n }\n\n /**\n * Asserts that the given arguments are equal. Throws an exception if not equal.\n * \n * @param arg1 is an argument to assert as equal\n * @param arg2 is an argument to assert as equal\n * @param msg is the message to throw if the arguments are not equal\n */\n static assertEquals(arg1, arg2, msg) {\n GenUtils.assertTrue(equals(arg1, arg2), msg ? msg : \"Arguments asserted as equal but are not equal: \" + arg1 + \" vs \" + arg2);\n }\n\n /**\n * Asserts that the given arguments are not equal. Throws an exception if equal.\n * \n * @param arg1 is an argument to assert as not equal\n * @param arg2 is an argument to assert as not equal\n * @param msg is the message to throw if the arguments are equal\n */\n static assertNotEquals(arg1, arg2, msg) {\n if (arg1 === arg2) throw new Error(msg ? msg : \"Arguments asserted as not equal but are equal: \" + arg1 + \" vs \" + arg2);\n }\n\n /**\n * Asserts that the given argument is an integer.\n * \n * @param arg is the argument to assert as an integer\n * @param msg is the message to throw if the argument is not an integer\n */\n static assertInt(arg, msg) {\n if (!GenUtils.isInt(arg)) throw new Error(msg ? msg : \"Argument asserted as an integer but is not an integer\");\n }\n\n /**\n * Asserts that the given argument is a number.\n * \n * @param arg is the argument to assert as a number\n * @param msg is the message to throw if the argument is not a number\n */\n static assertNumber(arg, msg) {\n if (!GenUtils.isNumber(arg)) throw new Error(msg ? msg : \"Argument asserted as a number but is not a number\");\n }\n\n /**\n * Asserts that the given argument is a boolean.\n * \n * @param arg is the argument to assert as a boolean\n * @param msg is the message to throw if the argument is not a boolean\n */\n static assertBoolean(arg, msg) {\n if (!GenUtils.isBoolean(arg)) throw new Error(msg ? msg : \"Argument asserted as a boolean but is not a boolean\");\n }\n\n /**\n * Asserts that the given argument is a string.\n * \n * @param arg is the argument to assert as a string\n * @param msg is the message to throw if the argument is not a string\n */\n static assertString(arg, msg) {\n if (!GenUtils.isString(arg)) throw new Error(msg ? msg : \"Argument asserted as a string but is not a string: \" + arg);\n }\n\n /**\n * Asserts that the given argument is an array.\n * \n * @param arg is the argument to assert as an array\n * @param msg is the message to throw if the argument is not an array\n */\n static assertArray(arg, msg) {\n if (!GenUtils.isArray(arg)) throw new Error(msg ? msg : \"Argument asserted as an array but is not an array\");\n }\n\n /**\n * Asserts that the given argument is a static.\n * \n * @param arg is the argument to assert as a static\n * @param msg is the message to throw if the argument is not a static\n */\n static assertFunction(arg, msg) {\n if (!GenUtils.isFunction(arg)) throw new Error(msg ? msg : \"Argument asserted as a static but is not a static\");\n }\n\n /**\n * Asserts that the given argument is an object with the given name.\n * \n * @param arg is the argument to test\n * @param obj is an object to assert arg instanceof obj (optional)\n * @param msg is the message to throw if the argument is not the specified object\n */\n static assertObject(arg, obj, msg) {\n GenUtils.assertInitialized(arg, msg);\n if (obj) {\n if (!isObject(arg, obj)) throw new Error(msg ? msg : \"Argument asserted as object '\" + obj.name + \"' but was not\");\n } else {\n if (!isObject(arg)) throw new Error(msg ? msg : \"Argument asserted as object but was not\");\n }\n }\n\n /**\n * Sets the child's prototype to the parent's prototype.\n * \n * @param child is the child class\n * @param parent is the parent class\n */\n static inheritsFrom(child, parent) {\n child.prototype = Object.create(parent.prototype);\n child.prototype.constructor = child;\n }\n\n /**\n * Invokes functions with arguments.\n * \n * arguments[0] is assumed to be an array of functions to invoke\n * arguments[1...n] are args to invoke the functions with\n */\n static invoke() {\n let fns = arguments[0];\n let args = [];\n for (let i = 1; i < arguments.length; i++) args.push(arguments[i]);\n for (let i = 0; i < fns.length; i++) {\n assertFunction(fns[i], \"Functions[\" + i + \"] is not a static\");\n fns[i].apply(null, args);\n }\n }\n\n /**\n * Returns the power set of the given array.\n * \n * @param arr is the array to get the power set of\n * @returns [][] is the power set of the given array\n */\n static getPowerSet(arr) {\n let fn = function(n, src, got, all) {\n if (n == 0) {\n if (got.length > 0) {\n all[all.length] = got;\n }\n return;\n }\n for (let j = 0; j < src.length; j++) {\n fn(n - 1, src.slice(j + 1), got.concat([ src[j] ]), all);\n }\n return;\n }\n let all = [];\n all.push([]);\n for (let i = 0; i < arr.length; i++) {\n fn(i, arr, [], all);\n }\n all.push(arr);\n return all;\n }\n\n /**\n * Returns the power set of the given array whose elements are the given size.\n * \n * @param arr is the array to get the power set of\n * @param size is the required size of the elements within the power set\n * returns [][] is the power set of the given array whose elements are the given size \n */\n static getPowerSetOfLength(arr, size) {\n assertInitialized(arr);\n assertInitialized(size);\n GenUtils.assertTrue(size >= 1);\n let powerSet = getPowerSet(arr);\n let powerSetOfLength = [];\n for (let i = 0; i < powerSet.length; i++) {\n if (powerSet[i].length === size) {\n powerSetOfLength.push(powerSet[i]);\n }\n }\n return powerSetOfLength;\n }\n\n /**\n * Returns an array of indices of the given size.\n * \n * @param size specifies the size to get indices for\n * @returns array of the given size with indices starting at 0\n */\n static getIndices(size) {\n let indices = [];\n for (let i = 0; i < size; i++) {\n indices.push(i);\n }\n return indices;\n }\n\n /**\n * Returns a new array containing unique elements of the given array.\n * \n * @param arr is the array to return unique elements from\n * @returns a new array with the given array's unique elements\n */\n static toUniqueArray(arr) {\n return arr.filter(function(value, index, self) {\n return self.indexOf(value) === index;\n });\n }\n\n /**\n * Copies the given array.\n * \n * @param arr is the array to copy\n * @returns a copy of the given array\n */\n static copyArray(arr) {\n GenUtils.assertArray(arr);\n let copy = [];\n for (let i = 0; i < arr.length; i++) copy.push(arr[i]);\n return copy;\n }\n \n /**\n * Removes every instance of the given value from the given array.\n * \n * @param arr is the array to remove the value from\n * @param val is the value to remove from the array\n * @returns true if the value is found and removed, false otherwise\n */\n static remove(arr, val) {\n let found = false;\n for (let i = arr.length - 1; i >= 0; i--) {\n if (arr[i] === val) {\n arr.splice(i, 1);\n found = true;\n i--;\n }\n }\n return found;\n }\n\n /**\n * Returns a copy of the given array where each element is lowercase.\n * \n * @param arr is the array to convert to lowercase\n * @returns a copy of the given array where each element is lowercase\n */\n static toLowerCaseArray(arr) {\n let arr2 = [];\n for (let i = 0; i < arr.length; i++) {\n arr2.push(arr[i].toLowerCase());\n }\n return arr2;\n }\n\n /**\n * Listifies the given argument.\n * \n * @param arrOrElem is an array or an element in the array\n * @returns an array which is the given arg if it's an array or an array with the given arg as an element\n */\n static listify(arrOrElem) {\n return GenUtils.isArray(arrOrElem) ? arrOrElem : [arrOrElem];\n }\n\n /**\n * Indicates if the given array contains the given object.\n * \n * @param {object[]} arr - array that may or may not contain the object\n * @param {object} obj - object to check for inclusion in the array\n * @param {boolean} compareByReference - compare strictly by reference, forgoing deep equality check\n * @returns true if the array contains the object, false otherwise\n */\n static arrayContains(arr, obj, compareByReference) {\n GenUtils.assertTrue(GenUtils.isArray(arr));\n for (let i = 0; i < arr.length; i++) {\n if (arr[i] === obj) return true;\n if (!compareByReference && GenUtils.equals(arr[i], obj)) return true;\n }\n return false;\n }\n\n /**\n * Indicates if the given string contains the given substring.\n * \n * @param str is the string to search for a substring\n * @param substring is the substring to searchin within the string\n * @returns true if the substring is within the string, false otherwise\n */\n static strContains(str, substring) {\n return str.indexOf(substring) > -1;\n }\n\n /**\n * Determines if two arrays are equal.\n * \n * @param arr1 is an array to compare\n * @param arr2 is an array to compare\n * @returns true if the arrays are equal, false otherwise\n */\n static arraysEqual(arr1, arr2) {\n if (arr1 === arr2) return true;\n if (arr1 == null && arr2 == null) return true;\n if (arr1 == null || arr2 == null) return false;\n if (typeof arr1 === 'undefined' && typeof arr2 === 'undefined') return true;\n if (typeof arr1 === 'undefined' || typeof arr2 === 'undefined') return false;\n if (!GenUtils.isArray(arr1)) throw new Error(\"First argument is not an array\");\n if (!GenUtils.isArray(arr2)) throw new Error(\"Second argument is not an array\");\n if (arr1.length != arr2.length) return false;\n for (let i = 0; i < arr1.length; ++i) {\n if (!GenUtils.equals(arr1[i], arr2[i])) return false;\n }\n return true;\n }\n\n /**\n * Determines if two arguments are deep equal.\n * \n * @param arg1 is an argument to compare\n * @param arg2 is an argument to compare\n * @returns true if the arguments are deep equals, false otherwise\n */\n static equals(arg1, arg2) {\n if (GenUtils.isArray(arg1) && GenUtils.isArray(arg2)) return GenUtils.arraysEqual(arg1, arg2);\n if (GenUtils.isObject(arg1) && GenUtils.isObject(arg2)) return GenUtils.objectsEqual(arg1, arg2);\n return arg1 === arg2;\n }\n \n /**\n * Determines if two objects are deep equal.\n * \n * Undefined values are considered equal to non-existent keys.\n * \n * @param map1 is a map to compare\n * @param map2 is a map to compare\n * @returns true if the maps have identical keys and values, false otherwise\n */\n static objectsEqual(map1, map2) {\n let keys1 = Object.keys(map1);\n let keys2 = Object.keys(map2);\n \n // compare each key1 to keys2\n for (let key1 of keys1) {\n let found = false;\n for (let key2 of keys2) {\n if (key1 === key2) {\n if (!GenUtils.equals(map1[key1], map2[key2])) return false;\n found = true;\n break;\n }\n }\n if (!found && map1[key1] !== undefined) return false; // allows undefined values to equal non-existent keys\n }\n \n // compare each key2 to keys1\n for (let key2 of keys2) {\n let found = false;\n for (let key1 of keys1) {\n if (key1 === key2) {\n found = true; // no need to re-compare which was done earlier\n break;\n }\n }\n if (!found && map2[key2] !== undefined) return false; // allows undefined values to equal non-existent keys\n }\n return true;\n \n // TODO: support strict option?\n// if (strict) {\n// let keys1 = Object.keys(map1);\n// if (keys1.length !== Object.keys(map2).length) return false;\n// for (let i = 0; i < keys1.length; i++) {\n// let key = Object.keys(map1)[i];\n// if (!GenUtils.equals(map1[key], map2[key])) return false;\n// }\n// }\n }\n \n /**\n * Deletes properties from the object that are undefined.\n * \n * @param obj is the object to delete undefined keys from\n */\n static deleteUndefinedKeys(obj) {\n for (let key of Object.keys(obj)) {\n if (obj[key] === undefined) delete obj[key];\n }\n }\n\n /**\n * Returns combinations of the given array of the given size.\n * \n * @param arr is the array to get combinations from\n * @param combinationSize specifies the size of each combination\n */\n static getCombinations(arr, combinationSize) {\n \n // validate input\n assertInitialized(arr);\n assertInitialized(combinationSize);\n GenUtils.assertTrue(combinationSize >= 1);\n \n // get combinations of array indices of the given size\n let indexCombinations = getPowerSetOfLength(getIndices(arr.length), combinationSize);\n \n // collect combinations from each combination of array indices\n let combinations = [];\n for (let indexCombinationsIdx = 0; indexCombinationsIdx < indexCombinations.length; indexCombinationsIdx++) {\n \n // get combination of array indices\n let indexCombination = indexCombinations[indexCombinationsIdx];\n \n // build combination from array\n let combination = [];\n for (let indexCombinationIdx = 0; indexCombinationIdx < indexCombination.length; indexCombinationIdx++) {\n combination.push(arr[indexCombination[indexCombinationIdx]]);\n }\n \n // add to combinations\n combinations.push(combination);\n }\n \n return combinations;\n }\n\n /**\n * Gets an 'a' element that is downloadable when clicked.\n * \n * @param name is the name of the file to download\n * @param contents are the string contents of the file to download\n * @returns 'a' dom element with downloadable file\n */\n static getDownloadableA(name, contents) {\n let a = window.document.createElement('a');\n a.href = window.URL.createObjectURL(new Blob([contents], {type: 'text/plain'}));\n a.download = name;\n a.target=\"_blank\";\n a.innerHTML = name;\n return a;\n }\n\n /**\n * Returns the given node's outer HTML.\n * \n * @param node is the node to get outer HTML for\n * @returns the outer HTML of the given node\n */\n static getOuterHtml(node) {\n return $('

').append($(node).clone()).html();\n }\n\n /**\n * Copies properties in the given object to a new object.\n * \n * @param obj is object to copy properties for\n * @returns a new object with properties copied from the given object\n */\n static copyProperties(obj) {\n return JSON.parse(JSON.stringify(obj))\n }\n\n /**\n * Deletes all properties in the given object.\n * \n * @param obj is the object to delete properties from\n */\n static deleteProperties(obj) {\n let props = [];\n for (let prop in obj) props.push(prop); // TODO: if (obj.hasOwnProperty(prop)) { ...\n for (i = 0; i < props.length; i++) delete obj[props[i].toString()];\n }\n\n /**\n * Converts a CSV string to a 2-dimensional array of strings.\n * \n * @param csv is the CSV string to convert\n * @returns a 2-dimensional array of strings\n */\n static csvToArr(csv) {\n return $.csv.toArrays(csv);\n }\n\n /**\n * Converts the given array to a CSV string.\n * \n * @param arr is a 2-dimensional array of strings\n * @returns the CSV string\n */\n static arrToCsv(arr) {\n return $.csv.fromObjects(arr, {headers: false});\n }\n\n /**\n * Indicates if the given string contains whitespace.\n * \n * @param str is the string to test\n * @returns true if the string contains whitespace, false otherwise\n */\n static hasWhitespace(str) {\n return /\\s/g.test(str);\n }\n\n /**\n * Indicates if the given character is whitespace.\n * \n * @param char is the character to test\n * @returns true if the given character is whitespace, false otherwise\n */\n static isWhitespace(char) {\n return /\\s/.test(char);\n }\n\n /**\n * Indicates if the given character is a newline.\n * \n * @param char is the character to test\n * @returns true if the given character is a newline, false otherwise\n */\n static isNewline(char) {\n return char === '\\n' || char === '\\r';\n }\n\n /**\n * Counts the number of non-whitespace characters in the given string.\n * \n * @param str is the string to count the number of non-whitespace characters in\n * @returns int is the number of non-whitespace characters in the given string\n */\n static countNonWhitespaceCharacters(str) {\n let count = 0;\n for (let i = 0; i < str.length; i++) {\n if (!isWhitespace(str.charAt(i))) count++;\n }\n return count;\n }\n\n /**\n * Returns tokens separated by whitespace from the given string.\n * \n * @param str is the string to get tokens from\n * @returns string[] are the tokens separated by whitespace within the string\n */\n static getWhitespaceTokens(str) {\n return str.match(/\\S+/g);\n }\n\n /**\n * Returns lines separated by newlines from the given string.\n * \n * @param str is the string to get lines from\n * @param string[] are the lines separated by newlines within the string\n */\n static getLines(str) {\n return str.match(/[^\\r\\n]+/g);\n }\n\n /**\n * Returns the document's first stylesheet which has no href.\n * \n * @returns StyleSheet is the internal stylesheet\n */\n static getInternalStyleSheet() {\n for (let i = 0; i < document.styleSheets.length; i++) {\n let styleSheet = document.styleSheets[i];\n if (!styleSheet.href) return styleSheet;\n }\n return null;\n }\n\n /**\n * Returns the document's internal stylesheet as text.\n * \n * @returns str is the document's internal stylesheet\n */\n static getInternalStyleSheetText() {\n let internalCss = \"\";\n let internalStyleSheet = getInternalStyleSheet();\n if (!internalStyleSheet) return null;\n for (let i = 0; i < internalStyleSheet.cssRules.length; i++) {\n internalCss += internalStyleSheet.cssRules[i].cssText + \"\\n\";\n }\n return internalCss;\n }\n\n /**\n * Manually builds an HTML document string.\n * \n * @param content specifies optional document content\n * content.div is a pre-existing div to stringify and add to the body\n * content.title is the title of the new tab\n * content.dependencyPaths specifies paths to js, css, or img paths\n * content.internalCss is css to embed in the html document\n * content.metas are meta elements with keys/values to include\n * @returns str is the document string\n */\n static buildHtmlDocument(content) {\n let str = \"\";\n str += \"\";\n \n // add metas\n if (content.metas) {\n let metas = listify(content.metas);\n for (let i = 0; i < metas.length; i++) {\n let meta = metas[i];\n let elem = document.createElement(\"meta\");\n for (let prop in meta) {\n if (meta.hasOwnProperty(prop)) {\n elem.setAttribute(prop.toString(), meta[prop.toString()]);\n }\n }\n str += elem.outerHTML;\n }\n }\n \n // add title and internal css\n str += content.title ? \"\" + content.title + \"\" : \"\";\n str += content.internalCss ? \"\" : \"\";\n \n // add dependency paths\n if (content.dependencyPaths) {\n let dependencyPaths = listify(content.dependencyPaths);\n for (let i = 0; i < dependencyPaths.length; i++) {\n let dependencyPath = dependencyPaths[i];\n if (dependencyPath.endsWith(\".js\")) str += \"\";\n else if (dependencyPath.endsWith(\".css\")) str += \"\";\n else if (dependencyPath.endsWith(\".png\") || dependencyPath.endsWith(\".img\")) str += \"\";\n else throw new Error(\"Unrecognized dependency path extension: \" + dependencyPath); \n }\n }\n str += \"\";\n if (content.div) str += $(\"
\").append(content.div.clone()).html(); // add cloned div as string\n str += \"\";\n return str;\n }\n\n /**\n * Opens the given div in a new window.\n * \n * @param content specifies optional window content\n * content.div is a pre-existing div to stringify and add to the body\n * content.title is the title of the new tab\n * content.dependencyPaths specifies paths to js, css, or img paths\n * content.internalCss is css to embed in the html document\n * content.metas are meta elements with keys/values to include\n * @param onLoad(err, window) is invoked with a reference to the window when available\n */\n static newWindow(content, onLoad) {\n let onLoadCalled = false;\n let w = window.open();\n if (!isInitialized(w) || !isInitialized(w.document)) {\n onLoadOnce(new Error(\"Could not get window reference\"));\n return;\n }\n w.opener = null;\n w.document.write(buildHtmlDocument(content));\n w.addEventListener('load', function() {\n onLoadOnce(null, w);\n });\n w.document.close();\n \n // prevents onLoad() from being called multiple times\n function onLoadOnce(err, window) {\n if (onLoadCalled) return;\n onLoadCalled = true;\n if (onLoad) onLoad(err, window);\n }\n }\n\n /**\n * Converts the given image to a base64 encoded data url.\n * \n * @param img is the image to convert\n * @param quality is a number between 0 and 1 specifying the image quality\n */\n static imgToDataUrl(img, quality) {\n let canvas = document.createElement('canvas');\n canvas.height = img.naturalHeight;\n canvas.width = img.naturalWidth;\n let context = canvas.getContext('2d');\n context.drawImage(img, 0, 0);\n return canvas.toDataURL(quality);\n }\n\n /**\n * Determines if the image at the given URL is accessible.\n * \n * @param url is the url to an image\n * @param timeout is the maximum time to wait\n * @param onDone(bool) when the image is determined to be accessible or not\n */\n static isImageAccessible(url, timeout, onDone) {\n \n // track return so it only executes once\n let returned = false;\n \n // attempt to load favicon\n let img = new Image();\n img.onload = onResponse;\n img.onerror = onResponse;\n img.src = url + \"?\" + (+new Date()); // trigger image load with cache buster\n \n // nest failure timeouts to give response a chance when browser is under load\n setTimeout(function() {\n setImmediate(function() {\n setImmediate(function() {\n setImmediate(function() {\n if (!returned) {\n returned = true;\n onDone(false);\n }\n });\n });\n });\n }, timeout);\n \n function onResponse(e) {\n if (returned) return;\n returned = true;\n if (typeof e === 'undefined' || e.type === \"error\") onDone(false);\n else onDone(true);\n }\n }\n\n /**\n * Determines if the given file is a zip file.\n * \n * @param file is a file\n * @returns true if the given file is a zip file, false otherwise\n */\n static isZipFile(file) {\n return file.name.endsWith(\".zip\") || file.type === 'application/zip';\n }\n\n /**\n * Determines if the given file is a json file.\n * \n * @param file is a file\n * @returns true if the given file is a json file, false otherwise\n */\n static isJsonFile(file) {\n return file.name.endsWith(\".json\") || file.type === 'application/json';\n }\n\n /**\n * Determines if the given file is a csv file.\n * \n * @param file is a file\n * @returns true if the given file is a csv file, false otherwise\n */\n static isCsvFile(file) {\n return file.name.endsWith(\".csv\") || file.type === 'text/csv';\n }\n\n /**\n * Determines if the given file is a txt file.\n * \n * @param file is a file\n * @returns true if the given file is a txt file, false otherwise\n */\n static isTxtFile(file) {\n return file.name.endsWith(\".txt\") || file.type === 'text/plain';\n }\n\n /**\n * Fetches the given list of images.\n * \n * Prerequisite: async.js.\n * \n * @param paths are the paths to the images to fetch\n * @param onDone(err, images) is called when done\n */\n static getImages(paths, onDone) {\n \n // listify paths\n if (!GenUtils.isArray(paths)) {\n GenUtils.assertTrue(isString(paths));\n paths = [paths];\n }\n \n // collect functions to fetch images\n let funcs = [];\n for (let i = 0; i < paths.length; i++) {\n funcs.push(loadFunc(paths[i]));\n }\n \n // fetch in parallel\n async.parallel(funcs, onDone);\n \n // callback static to fetch a single image\n function loadFunc(path) {\n return function(onDone) {\n let img = new Image();\n img.onload = function() { onDone(null, img); }\n img.onerror = function() { onDone(new Error(\"Cannot load image: \" + path)); }\n img.src = path;\n }\n }\n }\n \n /**\n * Returns a string indentation of the given length;\n * \n * @param length is the length of the indentation\n * @returns {string} is an indentation string of the given length\n */\n static getIndent(length) {\n let str = \"\";\n for (let i = 0; i < length; i++) str += ' '; // two spaces\n return str;\n }\n \n static initPolyfills() {\n \n // Polyfill Object.assign()\n // Credit: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign\n if (typeof Object.assign != 'static') {\n // Must be writable: true, enumerable: false, configurable: true\n Object.defineProperty(Object, \"assign\", {\n value: function assign(target, varArgs) { // .length of static is 2\n 'use strict';\n if (target == null) { // TypeError if undefined or null\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n let to = Object(target);\n\n for (let index = 1; index < arguments.length; index++) {\n let nextSource = arguments[index];\n\n if (nextSource != null) { // Skip over if undefined or null\n for (let nextKey in nextSource) {\n // Avoid bugs when hasOwnProperty is shadowed\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n return to;\n },\n writable: true,\n configurable: true\n });\n }\n \n /**\n * Polyfill str.replaceAt(idx, replacement).\n */\n String.prototype.replaceAt=function(idx, replacement) {\n return this.substr(0, idx) + replacement + this.substr(idx + replacement.length);\n }\n\n /**\n * Polyfill str.startsWith(searchString, position).\n * \n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith#Polyfill\n */\n String.prototype.startsWith = function(searchString, position) {\n return this.substr(position || 0, searchString.length) === searchString;\n };\n\n /**\n * Polyfill str.endsWith(searchString, position).\n * \n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith#Polyfill\n */\n String.prototype.endsWith = function(searchString, position) {\n if (!(position < this.length)) position = this.length; // works better than >= because it compensates for NaN\n else position |= 0; // round position\n return this.substr(position - searchString.length, searchString.length) === searchString;\n }\n\n /**\n * Removes the given value from the array.\n * \n * @returns true if the value was found and removed, false otherwise\n */\n Array.prototype.removeVal = function(val) {\n var found = false;\n for (var i = 0; i < this.length; i++) {\n if (this[i] == val) { \n found = true;\n this.splice(i, 1);\n i--;\n }\n }\n return found;;\n };\n }\n\n /**\n * Generates a v4 UUID.\n * \n * Source: https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript\n */\n static getUUID() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n }\n \n /**\n * Indicates if the current environment is a browser.\n * \n * @return {boolean} true if the environment is a browser, false otherwise\n */\n static isBrowser() {\n let isWorker = typeof importScripts === 'function';\n let isBrowserMain = new Function(\"try {return this===window;}catch(e){return false;}\")();\n return isWorker || isBrowserMain;\n }\n \n /**\n * Indicates if the current environment is a firefox-based browser.\n * \n * @return {boolean} true if the environment is a firefox-based browser, false otherwise\n */\n static isFirefox() {\n return this.isBrowser() && navigator.userAgent.indexOf(\"Firefox\") > 0;\n }\n\n /**\n * Gets the IE version number.\n * \n * Credit: https://stackoverflow.com/questions/19999388/check-if-user-is-using-ie-with-jquery/21712356#21712356\n * \n * @returns the IE version number of null if not IE\n */\n static getIEVersion() {\n let ua = window.navigator.userAgent;\n\n let msie = ua.indexOf('MSIE ');\n if (msie > 0) {\n // IE 10 or older => return version number\n return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);\n }\n\n let trident = ua.indexOf('Trident/');\n if (trident > 0) {\n // IE 11 => return version number\n let rv = ua.indexOf('rv:');\n return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);\n }\n\n let edge = ua.indexOf('Edge/');\n if (edge > 0) {\n // Edge (IE 12+) => return version number\n return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);\n }\n\n // other browser\n return null;\n }\n\n /**\n * Gets a parameter value.\n * \n * Credit: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript\n * \n * @param name is the name of the parameter to get the value of\n * @param url is a URL to get the parameter from, uses the window's current href if not given\n * @returns the parameter's value\n */\n static getParameterByName(name, url) {\n if (!url) url = window.location.href;\n name = name.replace(/[\\[\\]]/g, \"\\\\$&\");\n let regex = new RegExp(\"[?&]\" + name + \"(=([^&#]*)|&|#|$)\"), results = regex.exec(url);\n if (!results) return null;\n if (!results[2]) return '';\n return decodeURIComponent(results[2].replace(/\\+/g, \" \"));\n }\n \n /**\n * Gets a non-cryptographically secure random number within a given range.\n * \n * @param min is the minimum range of the int to generate, inclusive\n * @param max is the maximum range of the int to generate, inclusive\n * \n * Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random\n */\n static getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return Math.floor(Math.random() * (max - min + 1)) + min;\n }\n \n /**\n * Gets random ints.\n * \n * @param min is the minimum range of the ints to generate, inclusive\n * @param max is the maximum range of the ints to generate, inclusive\n * @param count is the number of random ints to get\n */\n static getRandomInts(min, max, count) {\n GenUtils.assertTrue(typeof count === \"number\");\n let ints = [];\n for (let i = 0; i < count; i++) ints.push(GenUtils.getRandomInt(min, max));\n return ints;\n }\n \n /**\n * Gets a given number of unique random ints within a range.\n * \n * @param min is the minimum range of the ints to generate, inclusive\n * @param max is the maximum range of the ints to generate, inclusive\n * @param count is the number of unique random ints to get\n */\n static getUniqueRandomInts(min, max, count) {\n let ints = [];\n GenUtils.assertTrue(count >= 0);\n GenUtils.assertTrue(max - min + 1 >= count);\n while (ints.length < count) {\n let randomInt = GenUtils.getRandomInt(min, max);\n if (!ints.includes(randomInt)) ints.push(randomInt);\n }\n return ints;\n }\n \n /**\n * Randomize array element order in-place using Durstenfeld shuffle algorithm.\n * \n * Credit: https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array\n */\n static shuffle(array) {\n for (var i = array.length - 1; i > 0; i--) {\n var j = Math.floor(Math.random() * (i + 1));\n var temp = array[i];\n array[i] = array[j];\n array[j] = temp;\n }\n }\n \n /**\n * Sorts an array by natural ordering.\n * \n * @param the array to sort\n */\n static sort(array) {\n array.sort((a, b) => a === b ? 0 : a > b ? 1 : -1);\n }\n \n /**\n * Sets the given value ensuring a previous value is not overwritten.\n * \n * TODO: remove for portability because function passing not supported in other languages, use reconcile only\n * \n * @param obj is the object to invoke the getter and setter on\n * @param getFn gets the current value\n * @param setFn sets the current value\n * @param val is the value to set iff it does not overwrite a previous value\n * @param config specifies reconciliation configuration\n * config.resolveDefined uses defined value if true or undefined, undefined if false\n * config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined\n * config.resolveMax uses max over min if true, min over max if false, must be equal if undefined\n * @param errMsg is the error message to throw if the values cannot be reconciled (optional)\n */\n static safeSet(obj, getFn, setFn, val, config, errMsg) {\n let curVal = getFn.call(obj);\n let reconciledVal = GenUtils.reconcile(curVal, val, config, errMsg);\n if (curVal !== reconciledVal) setFn.call(obj, reconciledVal);\n }\n \n /**\n * Reconciles two values.\n * \n * TODO: remove custom error message\n * \n * @param val1 is a value to reconcile\n * @param val2 is a value to reconcile\n * @param config specifies reconciliation configuration\n * config.resolveDefined uses defined value if true or undefined, undefined if false\n * config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined\n * config.resolveMax uses max over min if true, min over max if false, must be equal if undefined\n * @param errMsg is the error message to throw if the values cannot be reconciled (optional)\n * @returns the reconciled value if reconcilable, throws error otherwise\n */\n static reconcile(val1, val2, config, errMsg) {\n \n // check for equality\n if (val1 === val2) return val1;\n \n // check for BigInteger equality\n let comparison; // save comparison for later if applicable\n if (val1 instanceof BigInteger && val2 instanceof BigInteger) {\n comparison = val1.compare(val2); \n if (comparison === 0) return val1;\n }\n \n // resolve one value defined\n if (val1 === undefined || val2 === undefined) {\n if (config && config.resolveDefined === false) return undefined; // use undefined\n else return val1 === undefined ? val2 : val1; // use defined value\n }\n \n // resolve different booleans\n if (config && config.resolveTrue !== undefined && typeof val1 === \"boolean\" && typeof val2 === \"boolean\") {\n assert.equal(typeof config.resolveTrue, \"boolean\");\n return config.resolveTrue;\n }\n \n // resolve different numbers\n if (config && config.resolveMax !== undefined) {\n assert.equal(typeof config.resolveMax, \"boolean\");\n \n // resolve js numbers\n if (typeof val1 === \"number\" && typeof val2 === \"number\") {\n return config.resolveMax ? Math.max(val1, val2) : Math.min(val1, val2);\n }\n \n // resolve BigIntegers\n if (val1 instanceof BigInteger && val2 instanceof BigInteger) {\n return config.resolveMax ? (comparison < 0 ? val2 : val1) : (comparison < 0 ? val1 : val2);\n }\n }\n \n // assert deep equality\n assert.deepEqual(val1, val2, errMsg ? errMsg : \"Cannot reconcile values \" + val1 + \" and \" + val2 + \" with config: \" + JSON.stringify(config));\n return val1;\n }\n \n /**\n * Returns a human-friendly key value line.\n * \n * @param key is the key\n * @param value is the value\n * @param indent indents the line\n * @param newline specifies if the string should be terminated with a newline or not\n * @param ignoreUndefined specifies if undefined values should return an empty string\n * @returns {string} is the human-friendly key value line\n */\n static kvLine(key, value, indent = 0, newline = true, ignoreUndefined = true) {\n if (value === undefined && ignoreUndefined) return \"\";\n return GenUtils.getIndent(indent) + key + \": \" + value + (newline ? '\\n' : \"\");\n }\n \n /**\n * Replace big integers (16 or more consecutive digits) with strings in order\n * to preserve numeric precision.\n * \n * @param {string} str is the string to be modified\n * @return {string} the modified string with big numbers converted to strings\n */\n static stringifyBIs(str) {\n return str.replace(/(\"[^\"]*\"\\s*:\\s*)(\\d{16,})/g, '$1\"$2\"');\n }\n}\n\nmodule.exports = GenUtils;","// Copyright 2015 Joyent, Inc.\n\nmodule.exports = {\n\tbufferSplit: bufferSplit,\n\taddRSAMissing: addRSAMissing,\n\tcalculateDSAPublic: calculateDSAPublic,\n\tcalculateED25519Public: calculateED25519Public,\n\tcalculateX25519Public: calculateX25519Public,\n\tmpNormalize: mpNormalize,\n\tmpDenormalize: mpDenormalize,\n\tecNormalize: ecNormalize,\n\tcountZeros: countZeros,\n\tassertCompatible: assertCompatible,\n\tisCompatible: isCompatible,\n\topensslKeyDeriv: opensslKeyDeriv,\n\topensshCipherInfo: opensshCipherInfo,\n\tpublicFromPrivateECDSA: publicFromPrivateECDSA,\n\tzeroPadToLength: zeroPadToLength,\n\twriteBitString: writeBitString,\n\treadBitString: readBitString\n};\n\nvar assert = require('assert-plus');\nvar Buffer = require('safer-buffer').Buffer;\nvar PrivateKey = require('./private-key');\nvar Key = require('./key');\nvar crypto = require('crypto');\nvar algs = require('./algs');\nvar asn1 = require('asn1');\n\nvar ec = require('ecc-jsbn/lib/ec');\nvar jsbn = require('jsbn').BigInteger;\nvar nacl = require('tweetnacl');\n\nvar MAX_CLASS_DEPTH = 3;\n\nfunction isCompatible(obj, klass, needVer) {\n\tif (obj === null || typeof (obj) !== 'object')\n\t\treturn (false);\n\tif (needVer === undefined)\n\t\tneedVer = klass.prototype._sshpkApiVersion;\n\tif (obj instanceof klass &&\n\t klass.prototype._sshpkApiVersion[0] == needVer[0])\n\t\treturn (true);\n\tvar proto = Object.getPrototypeOf(obj);\n\tvar depth = 0;\n\twhile (proto.constructor.name !== klass.name) {\n\t\tproto = Object.getPrototypeOf(proto);\n\t\tif (!proto || ++depth > MAX_CLASS_DEPTH)\n\t\t\treturn (false);\n\t}\n\tif (proto.constructor.name !== klass.name)\n\t\treturn (false);\n\tvar ver = proto._sshpkApiVersion;\n\tif (ver === undefined)\n\t\tver = klass._oldVersionDetect(obj);\n\tif (ver[0] != needVer[0] || ver[1] < needVer[1])\n\t\treturn (false);\n\treturn (true);\n}\n\nfunction assertCompatible(obj, klass, needVer, name) {\n\tif (name === undefined)\n\t\tname = 'object';\n\tassert.ok(obj, name + ' must not be null');\n\tassert.object(obj, name + ' must be an object');\n\tif (needVer === undefined)\n\t\tneedVer = klass.prototype._sshpkApiVersion;\n\tif (obj instanceof klass &&\n\t klass.prototype._sshpkApiVersion[0] == needVer[0])\n\t\treturn;\n\tvar proto = Object.getPrototypeOf(obj);\n\tvar depth = 0;\n\twhile (proto.constructor.name !== klass.name) {\n\t\tproto = Object.getPrototypeOf(proto);\n\t\tassert.ok(proto && ++depth <= MAX_CLASS_DEPTH,\n\t\t name + ' must be a ' + klass.name + ' instance');\n\t}\n\tassert.strictEqual(proto.constructor.name, klass.name,\n\t name + ' must be a ' + klass.name + ' instance');\n\tvar ver = proto._sshpkApiVersion;\n\tif (ver === undefined)\n\t\tver = klass._oldVersionDetect(obj);\n\tassert.ok(ver[0] == needVer[0] && ver[1] >= needVer[1],\n\t name + ' must be compatible with ' + klass.name + ' klass ' +\n\t 'version ' + needVer[0] + '.' + needVer[1]);\n}\n\nvar CIPHER_LEN = {\n\t'des-ede3-cbc': { key: 7, iv: 8 },\n\t'aes-128-cbc': { key: 16, iv: 16 },\n\t'aes-256-cbc': { key: 32, iv: 16 }\n};\nvar PKCS5_SALT_LEN = 8;\n\nfunction opensslKeyDeriv(cipher, salt, passphrase, count) {\n\tassert.buffer(salt, 'salt');\n\tassert.buffer(passphrase, 'passphrase');\n\tassert.number(count, 'iteration count');\n\n\tvar clen = CIPHER_LEN[cipher];\n\tassert.object(clen, 'supported cipher');\n\n\tsalt = salt.slice(0, PKCS5_SALT_LEN);\n\n\tvar D, D_prev, bufs;\n\tvar material = Buffer.alloc(0);\n\twhile (material.length < clen.key + clen.iv) {\n\t\tbufs = [];\n\t\tif (D_prev)\n\t\t\tbufs.push(D_prev);\n\t\tbufs.push(passphrase);\n\t\tbufs.push(salt);\n\t\tD = Buffer.concat(bufs);\n\t\tfor (var j = 0; j < count; ++j)\n\t\t\tD = crypto.createHash('md5').update(D).digest();\n\t\tmaterial = Buffer.concat([material, D]);\n\t\tD_prev = D;\n\t}\n\n\treturn ({\n\t key: material.slice(0, clen.key),\n\t iv: material.slice(clen.key, clen.key + clen.iv)\n\t});\n}\n\n/* Count leading zero bits on a buffer */\nfunction countZeros(buf) {\n\tvar o = 0, obit = 8;\n\twhile (o < buf.length) {\n\t\tvar mask = (1 << obit);\n\t\tif ((buf[o] & mask) === mask)\n\t\t\tbreak;\n\t\tobit--;\n\t\tif (obit < 0) {\n\t\t\to++;\n\t\t\tobit = 8;\n\t\t}\n\t}\n\treturn (o*8 + (8 - obit) - 1);\n}\n\nfunction bufferSplit(buf, chr) {\n\tassert.buffer(buf);\n\tassert.string(chr);\n\n\tvar parts = [];\n\tvar lastPart = 0;\n\tvar matches = 0;\n\tfor (var i = 0; i < buf.length; ++i) {\n\t\tif (buf[i] === chr.charCodeAt(matches))\n\t\t\t++matches;\n\t\telse if (buf[i] === chr.charCodeAt(0))\n\t\t\tmatches = 1;\n\t\telse\n\t\t\tmatches = 0;\n\n\t\tif (matches >= chr.length) {\n\t\t\tvar newPart = i + 1;\n\t\t\tparts.push(buf.slice(lastPart, newPart - matches));\n\t\t\tlastPart = newPart;\n\t\t\tmatches = 0;\n\t\t}\n\t}\n\tif (lastPart <= buf.length)\n\t\tparts.push(buf.slice(lastPart, buf.length));\n\n\treturn (parts);\n}\n\nfunction ecNormalize(buf, addZero) {\n\tassert.buffer(buf);\n\tif (buf[0] === 0x00 && buf[1] === 0x04) {\n\t\tif (addZero)\n\t\t\treturn (buf);\n\t\treturn (buf.slice(1));\n\t} else if (buf[0] === 0x04) {\n\t\tif (!addZero)\n\t\t\treturn (buf);\n\t} else {\n\t\twhile (buf[0] === 0x00)\n\t\t\tbuf = buf.slice(1);\n\t\tif (buf[0] === 0x02 || buf[0] === 0x03)\n\t\t\tthrow (new Error('Compressed elliptic curve points ' +\n\t\t\t 'are not supported'));\n\t\tif (buf[0] !== 0x04)\n\t\t\tthrow (new Error('Not a valid elliptic curve point'));\n\t\tif (!addZero)\n\t\t\treturn (buf);\n\t}\n\tvar b = Buffer.alloc(buf.length + 1);\n\tb[0] = 0x0;\n\tbuf.copy(b, 1);\n\treturn (b);\n}\n\nfunction readBitString(der, tag) {\n\tif (tag === undefined)\n\t\ttag = asn1.Ber.BitString;\n\tvar buf = der.readString(tag, true);\n\tassert.strictEqual(buf[0], 0x00, 'bit strings with unused bits are ' +\n\t 'not supported (0x' + buf[0].toString(16) + ')');\n\treturn (buf.slice(1));\n}\n\nfunction writeBitString(der, buf, tag) {\n\tif (tag === undefined)\n\t\ttag = asn1.Ber.BitString;\n\tvar b = Buffer.alloc(buf.length + 1);\n\tb[0] = 0x00;\n\tbuf.copy(b, 1);\n\tder.writeBuffer(b, tag);\n}\n\nfunction mpNormalize(buf) {\n\tassert.buffer(buf);\n\twhile (buf.length > 1 && buf[0] === 0x00 && (buf[1] & 0x80) === 0x00)\n\t\tbuf = buf.slice(1);\n\tif ((buf[0] & 0x80) === 0x80) {\n\t\tvar b = Buffer.alloc(buf.length + 1);\n\t\tb[0] = 0x00;\n\t\tbuf.copy(b, 1);\n\t\tbuf = b;\n\t}\n\treturn (buf);\n}\n\nfunction mpDenormalize(buf) {\n\tassert.buffer(buf);\n\twhile (buf.length > 1 && buf[0] === 0x00)\n\t\tbuf = buf.slice(1);\n\treturn (buf);\n}\n\nfunction zeroPadToLength(buf, len) {\n\tassert.buffer(buf);\n\tassert.number(len);\n\twhile (buf.length > len) {\n\t\tassert.equal(buf[0], 0x00);\n\t\tbuf = buf.slice(1);\n\t}\n\twhile (buf.length < len) {\n\t\tvar b = Buffer.alloc(buf.length + 1);\n\t\tb[0] = 0x00;\n\t\tbuf.copy(b, 1);\n\t\tbuf = b;\n\t}\n\treturn (buf);\n}\n\nfunction bigintToMpBuf(bigint) {\n\tvar buf = Buffer.from(bigint.toByteArray());\n\tbuf = mpNormalize(buf);\n\treturn (buf);\n}\n\nfunction calculateDSAPublic(g, p, x) {\n\tassert.buffer(g);\n\tassert.buffer(p);\n\tassert.buffer(x);\n\tg = new jsbn(g);\n\tp = new jsbn(p);\n\tx = new jsbn(x);\n\tvar y = g.modPow(x, p);\n\tvar ybuf = bigintToMpBuf(y);\n\treturn (ybuf);\n}\n\nfunction calculateED25519Public(k) {\n\tassert.buffer(k);\n\n\tvar kp = nacl.sign.keyPair.fromSeed(new Uint8Array(k));\n\treturn (Buffer.from(kp.publicKey));\n}\n\nfunction calculateX25519Public(k) {\n\tassert.buffer(k);\n\n\tvar kp = nacl.box.keyPair.fromSeed(new Uint8Array(k));\n\treturn (Buffer.from(kp.publicKey));\n}\n\nfunction addRSAMissing(key) {\n\tassert.object(key);\n\tassertCompatible(key, PrivateKey, [1, 1]);\n\n\tvar d = new jsbn(key.part.d.data);\n\tvar buf;\n\n\tif (!key.part.dmodp) {\n\t\tvar p = new jsbn(key.part.p.data);\n\t\tvar dmodp = d.mod(p.subtract(1));\n\n\t\tbuf = bigintToMpBuf(dmodp);\n\t\tkey.part.dmodp = {name: 'dmodp', data: buf};\n\t\tkey.parts.push(key.part.dmodp);\n\t}\n\tif (!key.part.dmodq) {\n\t\tvar q = new jsbn(key.part.q.data);\n\t\tvar dmodq = d.mod(q.subtract(1));\n\n\t\tbuf = bigintToMpBuf(dmodq);\n\t\tkey.part.dmodq = {name: 'dmodq', data: buf};\n\t\tkey.parts.push(key.part.dmodq);\n\t}\n}\n\nfunction publicFromPrivateECDSA(curveName, priv) {\n\tassert.string(curveName, 'curveName');\n\tassert.buffer(priv);\n\tvar params = algs.curves[curveName];\n\tvar p = new jsbn(params.p);\n\tvar a = new jsbn(params.a);\n\tvar b = new jsbn(params.b);\n\tvar curve = new ec.ECCurveFp(p, a, b);\n\tvar G = curve.decodePointHex(params.G.toString('hex'));\n\n\tvar d = new jsbn(mpNormalize(priv));\n\tvar pub = G.multiply(d);\n\tpub = Buffer.from(curve.encodePointHex(pub), 'hex');\n\n\tvar parts = [];\n\tparts.push({name: 'curve', data: Buffer.from(curveName)});\n\tparts.push({name: 'Q', data: pub});\n\n\tvar key = new Key({type: 'ecdsa', curve: curve, parts: parts});\n\treturn (key);\n}\n\nfunction opensshCipherInfo(cipher) {\n\tvar inf = {};\n\tswitch (cipher) {\n\tcase '3des-cbc':\n\t\tinf.keySize = 24;\n\t\tinf.blockSize = 8;\n\t\tinf.opensslName = 'des-ede3-cbc';\n\t\tbreak;\n\tcase 'blowfish-cbc':\n\t\tinf.keySize = 16;\n\t\tinf.blockSize = 8;\n\t\tinf.opensslName = 'bf-cbc';\n\t\tbreak;\n\tcase 'aes128-cbc':\n\tcase 'aes128-ctr':\n\tcase 'aes128-gcm@openssh.com':\n\t\tinf.keySize = 16;\n\t\tinf.blockSize = 16;\n\t\tinf.opensslName = 'aes-128-' + cipher.slice(7, 10);\n\t\tbreak;\n\tcase 'aes192-cbc':\n\tcase 'aes192-ctr':\n\tcase 'aes192-gcm@openssh.com':\n\t\tinf.keySize = 24;\n\t\tinf.blockSize = 16;\n\t\tinf.opensslName = 'aes-192-' + cipher.slice(7, 10);\n\t\tbreak;\n\tcase 'aes256-cbc':\n\tcase 'aes256-ctr':\n\tcase 'aes256-gcm@openssh.com':\n\t\tinf.keySize = 32;\n\t\tinf.blockSize = 16;\n\t\tinf.opensslName = 'aes-256-' + cipher.slice(7, 10);\n\t\tbreak;\n\tdefault:\n\t\tthrow (new Error(\n\t\t 'Unsupported openssl cipher \"' + cipher + '\"'));\n\t}\n\treturn (inf);\n}\n","// Copyright 2017 Joyent, Inc.\n\nmodule.exports = Key;\n\nvar assert = require('assert-plus');\nvar algs = require('./algs');\nvar crypto = require('crypto');\nvar Fingerprint = require('./fingerprint');\nvar Signature = require('./signature');\nvar DiffieHellman = require('./dhe').DiffieHellman;\nvar errs = require('./errors');\nvar utils = require('./utils');\nvar PrivateKey = require('./private-key');\nvar edCompat;\n\ntry {\n\tedCompat = require('./ed-compat');\n} catch (e) {\n\t/* Just continue through, and bail out if we try to use it. */\n}\n\nvar InvalidAlgorithmError = errs.InvalidAlgorithmError;\nvar KeyParseError = errs.KeyParseError;\n\nvar formats = {};\nformats['auto'] = require('./formats/auto');\nformats['pem'] = require('./formats/pem');\nformats['pkcs1'] = require('./formats/pkcs1');\nformats['pkcs8'] = require('./formats/pkcs8');\nformats['rfc4253'] = require('./formats/rfc4253');\nformats['ssh'] = require('./formats/ssh');\nformats['ssh-private'] = require('./formats/ssh-private');\nformats['openssh'] = formats['ssh-private'];\nformats['dnssec'] = require('./formats/dnssec');\n\nfunction Key(opts) {\n\tassert.object(opts, 'options');\n\tassert.arrayOfObject(opts.parts, 'options.parts');\n\tassert.string(opts.type, 'options.type');\n\tassert.optionalString(opts.comment, 'options.comment');\n\n\tvar algInfo = algs.info[opts.type];\n\tif (typeof (algInfo) !== 'object')\n\t\tthrow (new InvalidAlgorithmError(opts.type));\n\n\tvar partLookup = {};\n\tfor (var i = 0; i < opts.parts.length; ++i) {\n\t\tvar part = opts.parts[i];\n\t\tpartLookup[part.name] = part;\n\t}\n\n\tthis.type = opts.type;\n\tthis.parts = opts.parts;\n\tthis.part = partLookup;\n\tthis.comment = undefined;\n\tthis.source = opts.source;\n\n\t/* for speeding up hashing/fingerprint operations */\n\tthis._rfc4253Cache = opts._rfc4253Cache;\n\tthis._hashCache = {};\n\n\tvar sz;\n\tthis.curve = undefined;\n\tif (this.type === 'ecdsa') {\n\t\tvar curve = this.part.curve.data.toString();\n\t\tthis.curve = curve;\n\t\tsz = algs.curves[curve].size;\n\t} else if (this.type === 'ed25519' || this.type === 'curve25519') {\n\t\tsz = 256;\n\t\tthis.curve = 'curve25519';\n\t} else {\n\t\tvar szPart = this.part[algInfo.sizePart];\n\t\tsz = szPart.data.length;\n\t\tsz = sz * 8 - utils.countZeros(szPart.data);\n\t}\n\tthis.size = sz;\n}\n\nKey.formats = formats;\n\nKey.prototype.toBuffer = function (format, options) {\n\tif (format === undefined)\n\t\tformat = 'ssh';\n\tassert.string(format, 'format');\n\tassert.object(formats[format], 'formats[format]');\n\tassert.optionalObject(options, 'options');\n\n\tif (format === 'rfc4253') {\n\t\tif (this._rfc4253Cache === undefined)\n\t\t\tthis._rfc4253Cache = formats['rfc4253'].write(this);\n\t\treturn (this._rfc4253Cache);\n\t}\n\n\treturn (formats[format].write(this, options));\n};\n\nKey.prototype.toString = function (format, options) {\n\treturn (this.toBuffer(format, options).toString());\n};\n\nKey.prototype.hash = function (algo) {\n\tassert.string(algo, 'algorithm');\n\talgo = algo.toLowerCase();\n\tif (algs.hashAlgs[algo] === undefined)\n\t\tthrow (new InvalidAlgorithmError(algo));\n\n\tif (this._hashCache[algo])\n\t\treturn (this._hashCache[algo]);\n\tvar hash = crypto.createHash(algo).\n\t update(this.toBuffer('rfc4253')).digest();\n\tthis._hashCache[algo] = hash;\n\treturn (hash);\n};\n\nKey.prototype.fingerprint = function (algo) {\n\tif (algo === undefined)\n\t\talgo = 'sha256';\n\tassert.string(algo, 'algorithm');\n\tvar opts = {\n\t\ttype: 'key',\n\t\thash: this.hash(algo),\n\t\talgorithm: algo\n\t};\n\treturn (new Fingerprint(opts));\n};\n\nKey.prototype.defaultHashAlgorithm = function () {\n\tvar hashAlgo = 'sha1';\n\tif (this.type === 'rsa')\n\t\thashAlgo = 'sha256';\n\tif (this.type === 'dsa' && this.size > 1024)\n\t\thashAlgo = 'sha256';\n\tif (this.type === 'ed25519')\n\t\thashAlgo = 'sha512';\n\tif (this.type === 'ecdsa') {\n\t\tif (this.size <= 256)\n\t\t\thashAlgo = 'sha256';\n\t\telse if (this.size <= 384)\n\t\t\thashAlgo = 'sha384';\n\t\telse\n\t\t\thashAlgo = 'sha512';\n\t}\n\treturn (hashAlgo);\n};\n\nKey.prototype.createVerify = function (hashAlgo) {\n\tif (hashAlgo === undefined)\n\t\thashAlgo = this.defaultHashAlgorithm();\n\tassert.string(hashAlgo, 'hash algorithm');\n\n\t/* ED25519 is not supported by OpenSSL, use a javascript impl. */\n\tif (this.type === 'ed25519' && edCompat !== undefined)\n\t\treturn (new edCompat.Verifier(this, hashAlgo));\n\tif (this.type === 'curve25519')\n\t\tthrow (new Error('Curve25519 keys are not suitable for ' +\n\t\t 'signing or verification'));\n\n\tvar v, nm, err;\n\ttry {\n\t\tnm = hashAlgo.toUpperCase();\n\t\tv = crypto.createVerify(nm);\n\t} catch (e) {\n\t\terr = e;\n\t}\n\tif (v === undefined || (err instanceof Error &&\n\t err.message.match(/Unknown message digest/))) {\n\t\tnm = 'RSA-';\n\t\tnm += hashAlgo.toUpperCase();\n\t\tv = crypto.createVerify(nm);\n\t}\n\tassert.ok(v, 'failed to create verifier');\n\tvar oldVerify = v.verify.bind(v);\n\tvar key = this.toBuffer('pkcs8');\n\tvar curve = this.curve;\n\tvar self = this;\n\tv.verify = function (signature, fmt) {\n\t\tif (Signature.isSignature(signature, [2, 0])) {\n\t\t\tif (signature.type !== self.type)\n\t\t\t\treturn (false);\n\t\t\tif (signature.hashAlgorithm &&\n\t\t\t signature.hashAlgorithm !== hashAlgo)\n\t\t\t\treturn (false);\n\t\t\tif (signature.curve && self.type === 'ecdsa' &&\n\t\t\t signature.curve !== curve)\n\t\t\t\treturn (false);\n\t\t\treturn (oldVerify(key, signature.toBuffer('asn1')));\n\n\t\t} else if (typeof (signature) === 'string' ||\n\t\t Buffer.isBuffer(signature)) {\n\t\t\treturn (oldVerify(key, signature, fmt));\n\n\t\t/*\n\t\t * Avoid doing this on valid arguments, walking the prototype\n\t\t * chain can be quite slow.\n\t\t */\n\t\t} else if (Signature.isSignature(signature, [1, 0])) {\n\t\t\tthrow (new Error('signature was created by too old ' +\n\t\t\t 'a version of sshpk and cannot be verified'));\n\n\t\t} else {\n\t\t\tthrow (new TypeError('signature must be a string, ' +\n\t\t\t 'Buffer, or Signature object'));\n\t\t}\n\t};\n\treturn (v);\n};\n\nKey.prototype.createDiffieHellman = function () {\n\tif (this.type === 'rsa')\n\t\tthrow (new Error('RSA keys do not support Diffie-Hellman'));\n\n\treturn (new DiffieHellman(this));\n};\nKey.prototype.createDH = Key.prototype.createDiffieHellman;\n\nKey.parse = function (data, format, options) {\n\tif (typeof (data) !== 'string')\n\t\tassert.buffer(data, 'data');\n\tif (format === undefined)\n\t\tformat = 'auto';\n\tassert.string(format, 'format');\n\tif (typeof (options) === 'string')\n\t\toptions = { filename: options };\n\tassert.optionalObject(options, 'options');\n\tif (options === undefined)\n\t\toptions = {};\n\tassert.optionalString(options.filename, 'options.filename');\n\tif (options.filename === undefined)\n\t\toptions.filename = '(unnamed)';\n\n\tassert.object(formats[format], 'formats[format]');\n\n\ttry {\n\t\tvar k = formats[format].read(data, options);\n\t\tif (k instanceof PrivateKey)\n\t\t\tk = k.toPublic();\n\t\tif (!k.comment)\n\t\t\tk.comment = options.filename;\n\t\treturn (k);\n\t} catch (e) {\n\t\tif (e.name === 'KeyEncryptedError')\n\t\t\tthrow (e);\n\t\tthrow (new KeyParseError(options.filename, format, e));\n\t}\n};\n\nKey.isKey = function (obj, ver) {\n\treturn (utils.isCompatible(obj, Key, ver));\n};\n\n/*\n * API versions for Key:\n * [1,0] -- initial ver, may take Signature for createVerify or may not\n * [1,1] -- added pkcs1, pkcs8 formats\n * [1,2] -- added auto, ssh-private, openssh formats\n * [1,3] -- added defaultHashAlgorithm\n * [1,4] -- added ed support, createDH\n * [1,5] -- first explicitly tagged version\n * [1,6] -- changed ed25519 part names\n */\nKey.prototype._sshpkApiVersion = [1, 6];\n\nKey._oldVersionDetect = function (obj) {\n\tassert.func(obj.toBuffer);\n\tassert.func(obj.fingerprint);\n\tif (obj.createDH)\n\t\treturn ([1, 4]);\n\tif (obj.defaultHashAlgorithm)\n\t\treturn ([1, 3]);\n\tif (obj.formats['auto'])\n\t\treturn ([1, 2]);\n\tif (obj.formats['pkcs1'])\n\t\treturn ([1, 1]);\n\treturn ([1, 0]);\n};\n",";(function (root, factory, undef) {\n\tif (typeof exports === \"object\") {\n\t\t// CommonJS\n\t\tmodule.exports = exports = factory(require(\"./core\"), require(\"./evpkdf\"));\n\t}\n\telse if (typeof define === \"function\" && define.amd) {\n\t\t// AMD\n\t\tdefine([\"./core\", \"./evpkdf\"], factory);\n\t}\n\telse {\n\t\t// Global (browser)\n\t\tfactory(root.CryptoJS);\n\t}\n}(this, function (CryptoJS) {\n\n\t/**\n\t * Cipher core components.\n\t */\n\tCryptoJS.lib.Cipher || (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 WordArray = C_lib.WordArray;\n\t var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm;\n\t var C_enc = C.enc;\n\t var Utf8 = C_enc.Utf8;\n\t var Base64 = C_enc.Base64;\n\t var C_algo = C.algo;\n\t var EvpKDF = C_algo.EvpKDF;\n\n\t /**\n\t * Abstract base cipher template.\n\t *\n\t * @property {number} keySize This cipher's key size. Default: 4 (128 bits)\n\t * @property {number} ivSize This cipher's IV size. Default: 4 (128 bits)\n\t * @property {number} _ENC_XFORM_MODE A constant representing encryption mode.\n\t * @property {number} _DEC_XFORM_MODE A constant representing decryption mode.\n\t */\n\t var Cipher = C_lib.Cipher = BufferedBlockAlgorithm.extend({\n\t /**\n\t * Configuration options.\n\t *\n\t * @property {WordArray} iv The IV to use for this operation.\n\t */\n\t cfg: Base.extend(),\n\n\t /**\n\t * Creates this cipher in encryption mode.\n\t *\n\t * @param {WordArray} key The key.\n\t * @param {Object} cfg (Optional) The configuration options to use for this operation.\n\t *\n\t * @return {Cipher} A cipher instance.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var cipher = CryptoJS.algo.AES.createEncryptor(keyWordArray, { iv: ivWordArray });\n\t */\n\t createEncryptor: function (key, cfg) {\n\t return this.create(this._ENC_XFORM_MODE, key, cfg);\n\t },\n\n\t /**\n\t * Creates this cipher in decryption mode.\n\t *\n\t * @param {WordArray} key The key.\n\t * @param {Object} cfg (Optional) The configuration options to use for this operation.\n\t *\n\t * @return {Cipher} A cipher instance.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var cipher = CryptoJS.algo.AES.createDecryptor(keyWordArray, { iv: ivWordArray });\n\t */\n\t createDecryptor: function (key, cfg) {\n\t return this.create(this._DEC_XFORM_MODE, key, cfg);\n\t },\n\n\t /**\n\t * Initializes a newly created cipher.\n\t *\n\t * @param {number} xformMode Either the encryption or decryption transormation mode constant.\n\t * @param {WordArray} key The key.\n\t * @param {Object} cfg (Optional) The configuration options to use for this operation.\n\t *\n\t * @example\n\t *\n\t * var cipher = CryptoJS.algo.AES.create(CryptoJS.algo.AES._ENC_XFORM_MODE, keyWordArray, { iv: ivWordArray });\n\t */\n\t init: function (xformMode, key, cfg) {\n\t // Apply config defaults\n\t this.cfg = this.cfg.extend(cfg);\n\n\t // Store transform mode and key\n\t this._xformMode = xformMode;\n\t this._key = key;\n\n\t // Set initial values\n\t this.reset();\n\t },\n\n\t /**\n\t * Resets this cipher to its initial state.\n\t *\n\t * @example\n\t *\n\t * cipher.reset();\n\t */\n\t reset: function () {\n\t // Reset data buffer\n\t BufferedBlockAlgorithm.reset.call(this);\n\n\t // Perform concrete-cipher logic\n\t this._doReset();\n\t },\n\n\t /**\n\t * Adds data to be encrypted or decrypted.\n\t *\n\t * @param {WordArray|string} dataUpdate The data to encrypt or decrypt.\n\t *\n\t * @return {WordArray} The data after processing.\n\t *\n\t * @example\n\t *\n\t * var encrypted = cipher.process('data');\n\t * var encrypted = cipher.process(wordArray);\n\t */\n\t process: function (dataUpdate) {\n\t // Append\n\t this._append(dataUpdate);\n\n\t // Process available blocks\n\t return this._process();\n\t },\n\n\t /**\n\t * Finalizes the encryption or decryption process.\n\t * Note that the finalize operation is effectively a destructive, read-once operation.\n\t *\n\t * @param {WordArray|string} dataUpdate The final data to encrypt or decrypt.\n\t *\n\t * @return {WordArray} The data after final processing.\n\t *\n\t * @example\n\t *\n\t * var encrypted = cipher.finalize();\n\t * var encrypted = cipher.finalize('data');\n\t * var encrypted = cipher.finalize(wordArray);\n\t */\n\t finalize: function (dataUpdate) {\n\t // Final data update\n\t if (dataUpdate) {\n\t this._append(dataUpdate);\n\t }\n\n\t // Perform concrete-cipher logic\n\t var finalProcessedData = this._doFinalize();\n\n\t return finalProcessedData;\n\t },\n\n\t keySize: 128/32,\n\n\t ivSize: 128/32,\n\n\t _ENC_XFORM_MODE: 1,\n\n\t _DEC_XFORM_MODE: 2,\n\n\t /**\n\t * Creates shortcut functions to a cipher's object interface.\n\t *\n\t * @param {Cipher} cipher The cipher to create a helper for.\n\t *\n\t * @return {Object} An object with encrypt and decrypt shortcut functions.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var AES = CryptoJS.lib.Cipher._createHelper(CryptoJS.algo.AES);\n\t */\n\t _createHelper: (function () {\n\t function selectCipherStrategy(key) {\n\t if (typeof key == 'string') {\n\t return PasswordBasedCipher;\n\t } else {\n\t return SerializableCipher;\n\t }\n\t }\n\n\t return function (cipher) {\n\t return {\n\t encrypt: function (message, key, cfg) {\n\t return selectCipherStrategy(key).encrypt(cipher, message, key, cfg);\n\t },\n\n\t decrypt: function (ciphertext, key, cfg) {\n\t return selectCipherStrategy(key).decrypt(cipher, ciphertext, key, cfg);\n\t }\n\t };\n\t };\n\t }())\n\t });\n\n\t /**\n\t * Abstract base stream cipher template.\n\t *\n\t * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 1 (32 bits)\n\t */\n\t var StreamCipher = C_lib.StreamCipher = Cipher.extend({\n\t _doFinalize: function () {\n\t // Process partial blocks\n\t var finalProcessedBlocks = this._process(!!'flush');\n\n\t return finalProcessedBlocks;\n\t },\n\n\t blockSize: 1\n\t });\n\n\t /**\n\t * Mode namespace.\n\t */\n\t var C_mode = C.mode = {};\n\n\t /**\n\t * Abstract base block cipher mode template.\n\t */\n\t var BlockCipherMode = C_lib.BlockCipherMode = Base.extend({\n\t /**\n\t * Creates this mode for encryption.\n\t *\n\t * @param {Cipher} cipher A block cipher instance.\n\t * @param {Array} iv The IV words.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var mode = CryptoJS.mode.CBC.createEncryptor(cipher, iv.words);\n\t */\n\t createEncryptor: function (cipher, iv) {\n\t return this.Encryptor.create(cipher, iv);\n\t },\n\n\t /**\n\t * Creates this mode for decryption.\n\t *\n\t * @param {Cipher} cipher A block cipher instance.\n\t * @param {Array} iv The IV words.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var mode = CryptoJS.mode.CBC.createDecryptor(cipher, iv.words);\n\t */\n\t createDecryptor: function (cipher, iv) {\n\t return this.Decryptor.create(cipher, iv);\n\t },\n\n\t /**\n\t * Initializes a newly created mode.\n\t *\n\t * @param {Cipher} cipher A block cipher instance.\n\t * @param {Array} iv The IV words.\n\t *\n\t * @example\n\t *\n\t * var mode = CryptoJS.mode.CBC.Encryptor.create(cipher, iv.words);\n\t */\n\t init: function (cipher, iv) {\n\t this._cipher = cipher;\n\t this._iv = iv;\n\t }\n\t });\n\n\t /**\n\t * Cipher Block Chaining mode.\n\t */\n\t var CBC = C_mode.CBC = (function () {\n\t /**\n\t * Abstract base CBC mode.\n\t */\n\t var CBC = BlockCipherMode.extend();\n\n\t /**\n\t * CBC encryptor.\n\t */\n\t CBC.Encryptor = CBC.extend({\n\t /**\n\t * Processes the data block at offset.\n\t *\n\t * @param {Array} words The data words to operate on.\n\t * @param {number} offset The offset where the block starts.\n\t *\n\t * @example\n\t *\n\t * mode.processBlock(data.words, offset);\n\t */\n\t processBlock: function (words, offset) {\n\t // Shortcuts\n\t var cipher = this._cipher;\n\t var blockSize = cipher.blockSize;\n\n\t // XOR and encrypt\n\t xorBlock.call(this, words, offset, blockSize);\n\t cipher.encryptBlock(words, offset);\n\n\t // Remember this block to use with next block\n\t this._prevBlock = words.slice(offset, offset + blockSize);\n\t }\n\t });\n\n\t /**\n\t * CBC decryptor.\n\t */\n\t CBC.Decryptor = CBC.extend({\n\t /**\n\t * Processes the data block at offset.\n\t *\n\t * @param {Array} words The data words to operate on.\n\t * @param {number} offset The offset where the block starts.\n\t *\n\t * @example\n\t *\n\t * mode.processBlock(data.words, offset);\n\t */\n\t processBlock: function (words, offset) {\n\t // Shortcuts\n\t var cipher = this._cipher;\n\t var blockSize = cipher.blockSize;\n\n\t // Remember this block to use with next block\n\t var thisBlock = words.slice(offset, offset + blockSize);\n\n\t // Decrypt and XOR\n\t cipher.decryptBlock(words, offset);\n\t xorBlock.call(this, words, offset, blockSize);\n\n\t // This block becomes the previous block\n\t this._prevBlock = thisBlock;\n\t }\n\t });\n\n\t function xorBlock(words, offset, blockSize) {\n\t var block;\n\n\t // Shortcut\n\t var iv = this._iv;\n\n\t // Choose mixing block\n\t if (iv) {\n\t block = iv;\n\n\t // Remove IV for subsequent blocks\n\t this._iv = undefined;\n\t } else {\n\t block = this._prevBlock;\n\t }\n\n\t // XOR blocks\n\t for (var i = 0; i < blockSize; i++) {\n\t words[offset + i] ^= block[i];\n\t }\n\t }\n\n\t return CBC;\n\t }());\n\n\t /**\n\t * Padding namespace.\n\t */\n\t var C_pad = C.pad = {};\n\n\t /**\n\t * PKCS #5/7 padding strategy.\n\t */\n\t var Pkcs7 = C_pad.Pkcs7 = {\n\t /**\n\t * Pads data using the algorithm defined in PKCS #5/7.\n\t *\n\t * @param {WordArray} data The data to pad.\n\t * @param {number} blockSize The multiple that the data should be padded to.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * CryptoJS.pad.Pkcs7.pad(wordArray, 4);\n\t */\n\t pad: function (data, blockSize) {\n\t // Shortcut\n\t var blockSizeBytes = blockSize * 4;\n\n\t // Count padding bytes\n\t var nPaddingBytes = blockSizeBytes - data.sigBytes % blockSizeBytes;\n\n\t // Create padding word\n\t var paddingWord = (nPaddingBytes << 24) | (nPaddingBytes << 16) | (nPaddingBytes << 8) | nPaddingBytes;\n\n\t // Create padding\n\t var paddingWords = [];\n\t for (var i = 0; i < nPaddingBytes; i += 4) {\n\t paddingWords.push(paddingWord);\n\t }\n\t var padding = WordArray.create(paddingWords, nPaddingBytes);\n\n\t // Add padding\n\t data.concat(padding);\n\t },\n\n\t /**\n\t * Unpads data that had been padded using the algorithm defined in PKCS #5/7.\n\t *\n\t * @param {WordArray} data The data to unpad.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * CryptoJS.pad.Pkcs7.unpad(wordArray);\n\t */\n\t unpad: function (data) {\n\t // Get number of padding bytes from last byte\n\t var nPaddingBytes = data.words[(data.sigBytes - 1) >>> 2] & 0xff;\n\n\t // Remove padding\n\t data.sigBytes -= nPaddingBytes;\n\t }\n\t };\n\n\t /**\n\t * Abstract base block cipher template.\n\t *\n\t * @property {number} blockSize The number of 32-bit words this cipher operates on. Default: 4 (128 bits)\n\t */\n\t var BlockCipher = C_lib.BlockCipher = Cipher.extend({\n\t /**\n\t * Configuration options.\n\t *\n\t * @property {Mode} mode The block mode to use. Default: CBC\n\t * @property {Padding} padding The padding strategy to use. Default: Pkcs7\n\t */\n\t cfg: Cipher.cfg.extend({\n\t mode: CBC,\n\t padding: Pkcs7\n\t }),\n\n\t reset: function () {\n\t var modeCreator;\n\n\t // Reset cipher\n\t Cipher.reset.call(this);\n\n\t // Shortcuts\n\t var cfg = this.cfg;\n\t var iv = cfg.iv;\n\t var mode = cfg.mode;\n\n\t // Reset block mode\n\t if (this._xformMode == this._ENC_XFORM_MODE) {\n\t modeCreator = mode.createEncryptor;\n\t } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {\n\t modeCreator = mode.createDecryptor;\n\t // Keep at least one block in the buffer for unpadding\n\t this._minBufferSize = 1;\n\t }\n\n\t if (this._mode && this._mode.__creator == modeCreator) {\n\t this._mode.init(this, iv && iv.words);\n\t } else {\n\t this._mode = modeCreator.call(mode, this, iv && iv.words);\n\t this._mode.__creator = modeCreator;\n\t }\n\t },\n\n\t _doProcessBlock: function (words, offset) {\n\t this._mode.processBlock(words, offset);\n\t },\n\n\t _doFinalize: function () {\n\t var finalProcessedBlocks;\n\n\t // Shortcut\n\t var padding = this.cfg.padding;\n\n\t // Finalize\n\t if (this._xformMode == this._ENC_XFORM_MODE) {\n\t // Pad data\n\t padding.pad(this._data, this.blockSize);\n\n\t // Process final blocks\n\t finalProcessedBlocks = this._process(!!'flush');\n\t } else /* if (this._xformMode == this._DEC_XFORM_MODE) */ {\n\t // Process final blocks\n\t finalProcessedBlocks = this._process(!!'flush');\n\n\t // Unpad data\n\t padding.unpad(finalProcessedBlocks);\n\t }\n\n\t return finalProcessedBlocks;\n\t },\n\n\t blockSize: 128/32\n\t });\n\n\t /**\n\t * A collection of cipher parameters.\n\t *\n\t * @property {WordArray} ciphertext The raw ciphertext.\n\t * @property {WordArray} key The key to this ciphertext.\n\t * @property {WordArray} iv The IV used in the ciphering operation.\n\t * @property {WordArray} salt The salt used with a key derivation function.\n\t * @property {Cipher} algorithm The cipher algorithm.\n\t * @property {Mode} mode The block mode used in the ciphering operation.\n\t * @property {Padding} padding The padding scheme used in the ciphering operation.\n\t * @property {number} blockSize The block size of the cipher.\n\t * @property {Format} formatter The default formatting strategy to convert this cipher params object to a string.\n\t */\n\t var CipherParams = C_lib.CipherParams = Base.extend({\n\t /**\n\t * Initializes a newly created cipher params object.\n\t *\n\t * @param {Object} cipherParams An object with any of the possible cipher parameters.\n\t *\n\t * @example\n\t *\n\t * var cipherParams = CryptoJS.lib.CipherParams.create({\n\t * ciphertext: ciphertextWordArray,\n\t * key: keyWordArray,\n\t * iv: ivWordArray,\n\t * salt: saltWordArray,\n\t * algorithm: CryptoJS.algo.AES,\n\t * mode: CryptoJS.mode.CBC,\n\t * padding: CryptoJS.pad.PKCS7,\n\t * blockSize: 4,\n\t * formatter: CryptoJS.format.OpenSSL\n\t * });\n\t */\n\t init: function (cipherParams) {\n\t this.mixIn(cipherParams);\n\t },\n\n\t /**\n\t * Converts this cipher params object to a string.\n\t *\n\t * @param {Format} formatter (Optional) The formatting strategy to use.\n\t *\n\t * @return {string} The stringified cipher params.\n\t *\n\t * @throws Error If neither the formatter nor the default formatter is set.\n\t *\n\t * @example\n\t *\n\t * var string = cipherParams + '';\n\t * var string = cipherParams.toString();\n\t * var string = cipherParams.toString(CryptoJS.format.OpenSSL);\n\t */\n\t toString: function (formatter) {\n\t return (formatter || this.formatter).stringify(this);\n\t }\n\t });\n\n\t /**\n\t * Format namespace.\n\t */\n\t var C_format = C.format = {};\n\n\t /**\n\t * OpenSSL formatting strategy.\n\t */\n\t var OpenSSLFormatter = C_format.OpenSSL = {\n\t /**\n\t * Converts a cipher params object to an OpenSSL-compatible string.\n\t *\n\t * @param {CipherParams} cipherParams The cipher params object.\n\t *\n\t * @return {string} The OpenSSL-compatible string.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var openSSLString = CryptoJS.format.OpenSSL.stringify(cipherParams);\n\t */\n\t stringify: function (cipherParams) {\n\t var wordArray;\n\n\t // Shortcuts\n\t var ciphertext = cipherParams.ciphertext;\n\t var salt = cipherParams.salt;\n\n\t // Format\n\t if (salt) {\n\t wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);\n\t } else {\n\t wordArray = ciphertext;\n\t }\n\n\t return wordArray.toString(Base64);\n\t },\n\n\t /**\n\t * Converts an OpenSSL-compatible string to a cipher params object.\n\t *\n\t * @param {string} openSSLStr The OpenSSL-compatible string.\n\t *\n\t * @return {CipherParams} The cipher params object.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var cipherParams = CryptoJS.format.OpenSSL.parse(openSSLString);\n\t */\n\t parse: function (openSSLStr) {\n\t var salt;\n\n\t // Parse base64\n\t var ciphertext = Base64.parse(openSSLStr);\n\n\t // Shortcut\n\t var ciphertextWords = ciphertext.words;\n\n\t // Test for salt\n\t if (ciphertextWords[0] == 0x53616c74 && ciphertextWords[1] == 0x65645f5f) {\n\t // Extract salt\n\t salt = WordArray.create(ciphertextWords.slice(2, 4));\n\n\t // Remove salt from ciphertext\n\t ciphertextWords.splice(0, 4);\n\t ciphertext.sigBytes -= 16;\n\t }\n\n\t return CipherParams.create({ ciphertext: ciphertext, salt: salt });\n\t }\n\t };\n\n\t /**\n\t * A cipher wrapper that returns ciphertext as a serializable cipher params object.\n\t */\n\t var SerializableCipher = C_lib.SerializableCipher = Base.extend({\n\t /**\n\t * Configuration options.\n\t *\n\t * @property {Formatter} format The formatting strategy to convert cipher param objects to and from a string. Default: OpenSSL\n\t */\n\t cfg: Base.extend({\n\t format: OpenSSLFormatter\n\t }),\n\n\t /**\n\t * Encrypts a message.\n\t *\n\t * @param {Cipher} cipher The cipher algorithm to use.\n\t * @param {WordArray|string} message The message to encrypt.\n\t * @param {WordArray} key The key.\n\t * @param {Object} cfg (Optional) The configuration options to use for this operation.\n\t *\n\t * @return {CipherParams} A cipher params object.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key);\n\t * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv });\n\t * var ciphertextParams = CryptoJS.lib.SerializableCipher.encrypt(CryptoJS.algo.AES, message, key, { iv: iv, format: CryptoJS.format.OpenSSL });\n\t */\n\t encrypt: function (cipher, message, key, cfg) {\n\t // Apply config defaults\n\t cfg = this.cfg.extend(cfg);\n\n\t // Encrypt\n\t var encryptor = cipher.createEncryptor(key, cfg);\n\t var ciphertext = encryptor.finalize(message);\n\n\t // Shortcut\n\t var cipherCfg = encryptor.cfg;\n\n\t // Create and return serializable cipher params\n\t return CipherParams.create({\n\t ciphertext: ciphertext,\n\t key: key,\n\t iv: cipherCfg.iv,\n\t algorithm: cipher,\n\t mode: cipherCfg.mode,\n\t padding: cipherCfg.padding,\n\t blockSize: cipher.blockSize,\n\t formatter: cfg.format\n\t });\n\t },\n\n\t /**\n\t * Decrypts serialized ciphertext.\n\t *\n\t * @param {Cipher} cipher The cipher algorithm to use.\n\t * @param {CipherParams|string} ciphertext The ciphertext to decrypt.\n\t * @param {WordArray} key The key.\n\t * @param {Object} cfg (Optional) The configuration options to use for this operation.\n\t *\n\t * @return {WordArray} The plaintext.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, key, { iv: iv, format: CryptoJS.format.OpenSSL });\n\t * var plaintext = CryptoJS.lib.SerializableCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, key, { iv: iv, format: CryptoJS.format.OpenSSL });\n\t */\n\t decrypt: function (cipher, ciphertext, key, cfg) {\n\t // Apply config defaults\n\t cfg = this.cfg.extend(cfg);\n\n\t // Convert string to CipherParams\n\t ciphertext = this._parse(ciphertext, cfg.format);\n\n\t // Decrypt\n\t var plaintext = cipher.createDecryptor(key, cfg).finalize(ciphertext.ciphertext);\n\n\t return plaintext;\n\t },\n\n\t /**\n\t * Converts serialized ciphertext to CipherParams,\n\t * else assumed CipherParams already and returns ciphertext unchanged.\n\t *\n\t * @param {CipherParams|string} ciphertext The ciphertext.\n\t * @param {Formatter} format The formatting strategy to use to parse serialized ciphertext.\n\t *\n\t * @return {CipherParams} The unserialized ciphertext.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var ciphertextParams = CryptoJS.lib.SerializableCipher._parse(ciphertextStringOrParams, format);\n\t */\n\t _parse: function (ciphertext, format) {\n\t if (typeof ciphertext == 'string') {\n\t return format.parse(ciphertext, this);\n\t } else {\n\t return ciphertext;\n\t }\n\t }\n\t });\n\n\t /**\n\t * Key derivation function namespace.\n\t */\n\t var C_kdf = C.kdf = {};\n\n\t /**\n\t * OpenSSL key derivation function.\n\t */\n\t var OpenSSLKdf = C_kdf.OpenSSL = {\n\t /**\n\t * Derives a key and IV from a password.\n\t *\n\t * @param {string} password The password to derive from.\n\t * @param {number} keySize The size in words of the key to generate.\n\t * @param {number} ivSize The size in words of the IV to generate.\n\t * @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be generated randomly.\n\t *\n\t * @return {CipherParams} A cipher params object with the key, IV, and salt.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);\n\t * var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');\n\t */\n\t execute: function (password, keySize, ivSize, salt) {\n\t // Generate random salt\n\t if (!salt) {\n\t salt = WordArray.random(64/8);\n\t }\n\n\t // Derive key and IV\n\t var key = EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt);\n\n\t // Separate key and IV\n\t var iv = WordArray.create(key.words.slice(keySize), ivSize * 4);\n\t key.sigBytes = keySize * 4;\n\n\t // Return params\n\t return CipherParams.create({ key: key, iv: iv, salt: salt });\n\t }\n\t };\n\n\t /**\n\t * A serializable cipher wrapper that derives the key from a password,\n\t * and returns ciphertext as a serializable cipher params object.\n\t */\n\t var PasswordBasedCipher = C_lib.PasswordBasedCipher = SerializableCipher.extend({\n\t /**\n\t * Configuration options.\n\t *\n\t * @property {KDF} kdf The key derivation function to use to generate a key and IV from a password. Default: OpenSSL\n\t */\n\t cfg: SerializableCipher.cfg.extend({\n\t kdf: OpenSSLKdf\n\t }),\n\n\t /**\n\t * Encrypts a message using a password.\n\t *\n\t * @param {Cipher} cipher The cipher algorithm to use.\n\t * @param {WordArray|string} message The message to encrypt.\n\t * @param {string} password The password.\n\t * @param {Object} cfg (Optional) The configuration options to use for this operation.\n\t *\n\t * @return {CipherParams} A cipher params object.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password');\n\t * var ciphertextParams = CryptoJS.lib.PasswordBasedCipher.encrypt(CryptoJS.algo.AES, message, 'password', { format: CryptoJS.format.OpenSSL });\n\t */\n\t encrypt: function (cipher, message, password, cfg) {\n\t // Apply config defaults\n\t cfg = this.cfg.extend(cfg);\n\n\t // Derive key and other params\n\t var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize);\n\n\t // Add IV to config\n\t cfg.iv = derivedParams.iv;\n\n\t // Encrypt\n\t var ciphertext = SerializableCipher.encrypt.call(this, cipher, message, derivedParams.key, cfg);\n\n\t // Mix in derived params\n\t ciphertext.mixIn(derivedParams);\n\n\t return ciphertext;\n\t },\n\n\t /**\n\t * Decrypts serialized ciphertext using a password.\n\t *\n\t * @param {Cipher} cipher The cipher algorithm to use.\n\t * @param {CipherParams|string} ciphertext The ciphertext to decrypt.\n\t * @param {string} password The password.\n\t * @param {Object} cfg (Optional) The configuration options to use for this operation.\n\t *\n\t * @return {WordArray} The plaintext.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, formattedCiphertext, 'password', { format: CryptoJS.format.OpenSSL });\n\t * var plaintext = CryptoJS.lib.PasswordBasedCipher.decrypt(CryptoJS.algo.AES, ciphertextParams, 'password', { format: CryptoJS.format.OpenSSL });\n\t */\n\t decrypt: function (cipher, ciphertext, password, cfg) {\n\t // Apply config defaults\n\t cfg = this.cfg.extend(cfg);\n\n\t // Convert string to CipherParams\n\t ciphertext = this._parse(ciphertext, cfg.format);\n\n\t // Derive key and other params\n\t var derivedParams = cfg.kdf.execute(password, cipher.keySize, cipher.ivSize, ciphertext.salt);\n\n\t // Add IV to config\n\t cfg.iv = derivedParams.iv;\n\n\t // Decrypt\n\t var plaintext = SerializableCipher.decrypt.call(this, cipher, ciphertext, derivedParams.key, cfg);\n\n\t return plaintext;\n\t }\n\t });\n\t}());\n\n\n}));","// Copyright 2015 Joyent, Inc.\n\nvar Buffer = require('safer-buffer').Buffer;\n\nvar algInfo = {\n\t'dsa': {\n\t\tparts: ['p', 'q', 'g', 'y'],\n\t\tsizePart: 'p'\n\t},\n\t'rsa': {\n\t\tparts: ['e', 'n'],\n\t\tsizePart: 'n'\n\t},\n\t'ecdsa': {\n\t\tparts: ['curve', 'Q'],\n\t\tsizePart: 'Q'\n\t},\n\t'ed25519': {\n\t\tparts: ['A'],\n\t\tsizePart: 'A'\n\t}\n};\nalgInfo['curve25519'] = algInfo['ed25519'];\n\nvar algPrivInfo = {\n\t'dsa': {\n\t\tparts: ['p', 'q', 'g', 'y', 'x']\n\t},\n\t'rsa': {\n\t\tparts: ['n', 'e', 'd', 'iqmp', 'p', 'q']\n\t},\n\t'ecdsa': {\n\t\tparts: ['curve', 'Q', 'd']\n\t},\n\t'ed25519': {\n\t\tparts: ['A', 'k']\n\t}\n};\nalgPrivInfo['curve25519'] = algPrivInfo['ed25519'];\n\nvar hashAlgs = {\n\t'md5': true,\n\t'sha1': true,\n\t'sha256': true,\n\t'sha384': true,\n\t'sha512': true\n};\n\n/*\n * Taken from\n * http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf\n */\nvar curves = {\n\t'nistp256': {\n\t\tsize: 256,\n\t\tpkcs8oid: '1.2.840.10045.3.1.7',\n\t\tp: Buffer.from(('00' +\n\t\t 'ffffffff 00000001 00000000 00000000' +\n\t\t '00000000 ffffffff ffffffff ffffffff').\n\t\t replace(/ /g, ''), 'hex'),\n\t\ta: Buffer.from(('00' +\n\t\t 'FFFFFFFF 00000001 00000000 00000000' +\n\t\t '00000000 FFFFFFFF FFFFFFFF FFFFFFFC').\n\t\t replace(/ /g, ''), 'hex'),\n\t\tb: Buffer.from((\n\t\t '5ac635d8 aa3a93e7 b3ebbd55 769886bc' +\n\t\t '651d06b0 cc53b0f6 3bce3c3e 27d2604b').\n\t\t replace(/ /g, ''), 'hex'),\n\t\ts: Buffer.from(('00' +\n\t\t 'c49d3608 86e70493 6a6678e1 139d26b7' +\n\t\t '819f7e90').\n\t\t replace(/ /g, ''), 'hex'),\n\t\tn: Buffer.from(('00' +\n\t\t 'ffffffff 00000000 ffffffff ffffffff' +\n\t\t 'bce6faad a7179e84 f3b9cac2 fc632551').\n\t\t replace(/ /g, ''), 'hex'),\n\t\tG: Buffer.from(('04' +\n\t\t '6b17d1f2 e12c4247 f8bce6e5 63a440f2' +\n\t\t '77037d81 2deb33a0 f4a13945 d898c296' +\n\t\t '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16' +\n\t\t '2bce3357 6b315ece cbb64068 37bf51f5').\n\t\t replace(/ /g, ''), 'hex')\n\t},\n\t'nistp384': {\n\t\tsize: 384,\n\t\tpkcs8oid: '1.3.132.0.34',\n\t\tp: Buffer.from(('00' +\n\t\t 'ffffffff ffffffff ffffffff ffffffff' +\n\t\t 'ffffffff ffffffff ffffffff fffffffe' +\n\t\t 'ffffffff 00000000 00000000 ffffffff').\n\t\t replace(/ /g, ''), 'hex'),\n\t\ta: Buffer.from(('00' +\n\t\t 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' +\n\t\t 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE' +\n\t\t 'FFFFFFFF 00000000 00000000 FFFFFFFC').\n\t\t replace(/ /g, ''), 'hex'),\n\t\tb: Buffer.from((\n\t\t 'b3312fa7 e23ee7e4 988e056b e3f82d19' +\n\t\t '181d9c6e fe814112 0314088f 5013875a' +\n\t\t 'c656398d 8a2ed19d 2a85c8ed d3ec2aef').\n\t\t replace(/ /g, ''), 'hex'),\n\t\ts: Buffer.from(('00' +\n\t\t 'a335926a a319a27a 1d00896a 6773a482' +\n\t\t '7acdac73').\n\t\t replace(/ /g, ''), 'hex'),\n\t\tn: Buffer.from(('00' +\n\t\t 'ffffffff ffffffff ffffffff ffffffff' +\n\t\t 'ffffffff ffffffff c7634d81 f4372ddf' +\n\t\t '581a0db2 48b0a77a ecec196a ccc52973').\n\t\t replace(/ /g, ''), 'hex'),\n\t\tG: Buffer.from(('04' +\n\t\t 'aa87ca22 be8b0537 8eb1c71e f320ad74' +\n\t\t '6e1d3b62 8ba79b98 59f741e0 82542a38' +\n\t\t '5502f25d bf55296c 3a545e38 72760ab7' +\n\t\t '3617de4a 96262c6f 5d9e98bf 9292dc29' +\n\t\t 'f8f41dbd 289a147c e9da3113 b5f0b8c0' +\n\t\t '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f').\n\t\t replace(/ /g, ''), 'hex')\n\t},\n\t'nistp521': {\n\t\tsize: 521,\n\t\tpkcs8oid: '1.3.132.0.35',\n\t\tp: Buffer.from((\n\t\t '01ffffff ffffffff ffffffff ffffffff' +\n\t\t 'ffffffff ffffffff ffffffff ffffffff' +\n\t\t 'ffffffff ffffffff ffffffff ffffffff' +\n\t\t 'ffffffff ffffffff ffffffff ffffffff' +\n\t\t 'ffff').replace(/ /g, ''), 'hex'),\n\t\ta: Buffer.from(('01FF' +\n\t\t 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' +\n\t\t 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' +\n\t\t 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF' +\n\t\t 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFC').\n\t\t replace(/ /g, ''), 'hex'),\n\t\tb: Buffer.from(('51' +\n\t\t '953eb961 8e1c9a1f 929a21a0 b68540ee' +\n\t\t 'a2da725b 99b315f3 b8b48991 8ef109e1' +\n\t\t '56193951 ec7e937b 1652c0bd 3bb1bf07' +\n\t\t '3573df88 3d2c34f1 ef451fd4 6b503f00').\n\t\t replace(/ /g, ''), 'hex'),\n\t\ts: Buffer.from(('00' +\n\t\t 'd09e8800 291cb853 96cc6717 393284aa' +\n\t\t 'a0da64ba').replace(/ /g, ''), 'hex'),\n\t\tn: Buffer.from(('01ff' +\n\t\t 'ffffffff ffffffff ffffffff ffffffff' +\n\t\t 'ffffffff ffffffff ffffffff fffffffa' +\n\t\t '51868783 bf2f966b 7fcc0148 f709a5d0' +\n\t\t '3bb5c9b8 899c47ae bb6fb71e 91386409').\n\t\t replace(/ /g, ''), 'hex'),\n\t\tG: Buffer.from(('04' +\n\t\t '00c6 858e06b7 0404e9cd 9e3ecb66 2395b442' +\n\t\t '9c648139 053fb521 f828af60 6b4d3dba' +\n\t\t 'a14b5e77 efe75928 fe1dc127 a2ffa8de' +\n\t\t '3348b3c1 856a429b f97e7e31 c2e5bd66' +\n\t\t '0118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9' +\n\t\t '98f54449 579b4468 17afbd17 273e662c' +\n\t\t '97ee7299 5ef42640 c550b901 3fad0761' +\n\t\t '353c7086 a272c240 88be9476 9fd16650').\n\t\t replace(/ /g, ''), 'hex')\n\t}\n};\n\nmodule.exports = {\n\tinfo: algInfo,\n\tprivInfo: algPrivInfo,\n\thashAlgs: hashAlgs,\n\tcurves: curves\n};\n","// Copyright 2017 Joyent, Inc.\n\nmodule.exports = PrivateKey;\n\nvar assert = require('assert-plus');\nvar Buffer = require('safer-buffer').Buffer;\nvar algs = require('./algs');\nvar crypto = require('crypto');\nvar Fingerprint = require('./fingerprint');\nvar Signature = require('./signature');\nvar errs = require('./errors');\nvar util = require('util');\nvar utils = require('./utils');\nvar dhe = require('./dhe');\nvar generateECDSA = dhe.generateECDSA;\nvar generateED25519 = dhe.generateED25519;\nvar edCompat = require('./ed-compat');\nvar nacl = require('tweetnacl');\n\nvar Key = require('./key');\n\nvar InvalidAlgorithmError = errs.InvalidAlgorithmError;\nvar KeyParseError = errs.KeyParseError;\nvar KeyEncryptedError = errs.KeyEncryptedError;\n\nvar formats = {};\nformats['auto'] = require('./formats/auto');\nformats['pem'] = require('./formats/pem');\nformats['pkcs1'] = require('./formats/pkcs1');\nformats['pkcs8'] = require('./formats/pkcs8');\nformats['rfc4253'] = require('./formats/rfc4253');\nformats['ssh-private'] = require('./formats/ssh-private');\nformats['openssh'] = formats['ssh-private'];\nformats['ssh'] = formats['ssh-private'];\nformats['dnssec'] = require('./formats/dnssec');\n\nfunction PrivateKey(opts) {\n\tassert.object(opts, 'options');\n\tKey.call(this, opts);\n\n\tthis._pubCache = undefined;\n}\nutil.inherits(PrivateKey, Key);\n\nPrivateKey.formats = formats;\n\nPrivateKey.prototype.toBuffer = function (format, options) {\n\tif (format === undefined)\n\t\tformat = 'pkcs1';\n\tassert.string(format, 'format');\n\tassert.object(formats[format], 'formats[format]');\n\tassert.optionalObject(options, 'options');\n\n\treturn (formats[format].write(this, options));\n};\n\nPrivateKey.prototype.hash = function (algo) {\n\treturn (this.toPublic().hash(algo));\n};\n\nPrivateKey.prototype.toPublic = function () {\n\tif (this._pubCache)\n\t\treturn (this._pubCache);\n\n\tvar algInfo = algs.info[this.type];\n\tvar pubParts = [];\n\tfor (var i = 0; i < algInfo.parts.length; ++i) {\n\t\tvar p = algInfo.parts[i];\n\t\tpubParts.push(this.part[p]);\n\t}\n\n\tthis._pubCache = new Key({\n\t\ttype: this.type,\n\t\tsource: this,\n\t\tparts: pubParts\n\t});\n\tif (this.comment)\n\t\tthis._pubCache.comment = this.comment;\n\treturn (this._pubCache);\n};\n\nPrivateKey.prototype.derive = function (newType) {\n\tassert.string(newType, 'type');\n\tvar priv, pub, pair;\n\n\tif (this.type === 'ed25519' && newType === 'curve25519') {\n\t\tpriv = this.part.k.data;\n\t\tif (priv[0] === 0x00)\n\t\t\tpriv = priv.slice(1);\n\n\t\tpair = nacl.box.keyPair.fromSecretKey(new Uint8Array(priv));\n\t\tpub = Buffer.from(pair.publicKey);\n\n\t\treturn (new PrivateKey({\n\t\t\ttype: 'curve25519',\n\t\t\tparts: [\n\t\t\t\t{ name: 'A', data: utils.mpNormalize(pub) },\n\t\t\t\t{ name: 'k', data: utils.mpNormalize(priv) }\n\t\t\t]\n\t\t}));\n\t} else if (this.type === 'curve25519' && newType === 'ed25519') {\n\t\tpriv = this.part.k.data;\n\t\tif (priv[0] === 0x00)\n\t\t\tpriv = priv.slice(1);\n\n\t\tpair = nacl.sign.keyPair.fromSeed(new Uint8Array(priv));\n\t\tpub = Buffer.from(pair.publicKey);\n\n\t\treturn (new PrivateKey({\n\t\t\ttype: 'ed25519',\n\t\t\tparts: [\n\t\t\t\t{ name: 'A', data: utils.mpNormalize(pub) },\n\t\t\t\t{ name: 'k', data: utils.mpNormalize(priv) }\n\t\t\t]\n\t\t}));\n\t}\n\tthrow (new Error('Key derivation not supported from ' + this.type +\n\t ' to ' + newType));\n};\n\nPrivateKey.prototype.createVerify = function (hashAlgo) {\n\treturn (this.toPublic().createVerify(hashAlgo));\n};\n\nPrivateKey.prototype.createSign = function (hashAlgo) {\n\tif (hashAlgo === undefined)\n\t\thashAlgo = this.defaultHashAlgorithm();\n\tassert.string(hashAlgo, 'hash algorithm');\n\n\t/* ED25519 is not supported by OpenSSL, use a javascript impl. */\n\tif (this.type === 'ed25519' && edCompat !== undefined)\n\t\treturn (new edCompat.Signer(this, hashAlgo));\n\tif (this.type === 'curve25519')\n\t\tthrow (new Error('Curve25519 keys are not suitable for ' +\n\t\t 'signing or verification'));\n\n\tvar v, nm, err;\n\ttry {\n\t\tnm = hashAlgo.toUpperCase();\n\t\tv = crypto.createSign(nm);\n\t} catch (e) {\n\t\terr = e;\n\t}\n\tif (v === undefined || (err instanceof Error &&\n\t err.message.match(/Unknown message digest/))) {\n\t\tnm = 'RSA-';\n\t\tnm += hashAlgo.toUpperCase();\n\t\tv = crypto.createSign(nm);\n\t}\n\tassert.ok(v, 'failed to create verifier');\n\tvar oldSign = v.sign.bind(v);\n\tvar key = this.toBuffer('pkcs1');\n\tvar type = this.type;\n\tvar curve = this.curve;\n\tv.sign = function () {\n\t\tvar sig = oldSign(key);\n\t\tif (typeof (sig) === 'string')\n\t\t\tsig = Buffer.from(sig, 'binary');\n\t\tsig = Signature.parse(sig, type, 'asn1');\n\t\tsig.hashAlgorithm = hashAlgo;\n\t\tsig.curve = curve;\n\t\treturn (sig);\n\t};\n\treturn (v);\n};\n\nPrivateKey.parse = function (data, format, options) {\n\tif (typeof (data) !== 'string')\n\t\tassert.buffer(data, 'data');\n\tif (format === undefined)\n\t\tformat = 'auto';\n\tassert.string(format, 'format');\n\tif (typeof (options) === 'string')\n\t\toptions = { filename: options };\n\tassert.optionalObject(options, 'options');\n\tif (options === undefined)\n\t\toptions = {};\n\tassert.optionalString(options.filename, 'options.filename');\n\tif (options.filename === undefined)\n\t\toptions.filename = '(unnamed)';\n\n\tassert.object(formats[format], 'formats[format]');\n\n\ttry {\n\t\tvar k = formats[format].read(data, options);\n\t\tassert.ok(k instanceof PrivateKey, 'key is not a private key');\n\t\tif (!k.comment)\n\t\t\tk.comment = options.filename;\n\t\treturn (k);\n\t} catch (e) {\n\t\tif (e.name === 'KeyEncryptedError')\n\t\t\tthrow (e);\n\t\tthrow (new KeyParseError(options.filename, format, e));\n\t}\n};\n\nPrivateKey.isPrivateKey = function (obj, ver) {\n\treturn (utils.isCompatible(obj, PrivateKey, ver));\n};\n\nPrivateKey.generate = function (type, options) {\n\tif (options === undefined)\n\t\toptions = {};\n\tassert.object(options, 'options');\n\n\tswitch (type) {\n\tcase 'ecdsa':\n\t\tif (options.curve === undefined)\n\t\t\toptions.curve = 'nistp256';\n\t\tassert.string(options.curve, 'options.curve');\n\t\treturn (generateECDSA(options.curve));\n\tcase 'ed25519':\n\t\treturn (generateED25519());\n\tdefault:\n\t\tthrow (new Error('Key generation not supported with key ' +\n\t\t 'type \"' + type + '\"'));\n\t}\n};\n\n/*\n * API versions for PrivateKey:\n * [1,0] -- initial ver\n * [1,1] -- added auto, pkcs[18], openssh/ssh-private formats\n * [1,2] -- added defaultHashAlgorithm\n * [1,3] -- added derive, ed, createDH\n * [1,4] -- first tagged version\n * [1,5] -- changed ed25519 part names and format\n */\nPrivateKey.prototype._sshpkApiVersion = [1, 5];\n\nPrivateKey._oldVersionDetect = function (obj) {\n\tassert.func(obj.toPublic);\n\tassert.func(obj.createSign);\n\tif (obj.derive)\n\t\treturn ([1, 3]);\n\tif (obj.defaultHashAlgorithm)\n\t\treturn ([1, 2]);\n\tif (obj.formats['auto'])\n\t\treturn ([1, 1]);\n\treturn ([1, 0]);\n};\n","/**\n * Exception when interacting with a Monero wallet or daemon.\n */\nclass MoneroError extends Error {\n \n /**\n * Constructs the error.\n * \n * @param {string} message is a human-readable message of the error\n * @param {int} code is the error code (optional)\n */\n constructor(message, code) {\n super(message);\n this.code = code;\n }\n \n getCode() {\n return this.code;\n }\n \n toString() {\n if (this.message === undefined && this.getCode() === undefined) return super.message;\n let str = \"\";\n if (this.getCode() !== undefined) str += this.getCode() + \": \";\n str += this.message;\n return str;\n }\n}\n\nmodule.exports = MoneroError;","module.exports = assert;\n\nfunction assert(val, msg) {\n if (!val)\n throw new Error(msg || 'Assertion failed');\n}\n\nassert.equal = function assertEqual(l, r, msg) {\n if (l != r)\n throw new Error(msg || ('Assertion failed: ' + l + ' != ' + r));\n};\n","'use strict';\n\nvar utils = exports;\nvar BN = require('bn.js');\nvar minAssert = require('minimalistic-assert');\nvar minUtils = require('minimalistic-crypto-utils');\n\nutils.assert = minAssert;\nutils.toArray = minUtils.toArray;\nutils.zero2 = minUtils.zero2;\nutils.toHex = minUtils.toHex;\nutils.encode = minUtils.encode;\n\n// Represent num in a w-NAF form\nfunction getNAF(num, w, bits) {\n var naf = new Array(Math.max(num.bitLength(), bits) + 1);\n naf.fill(0);\n\n var ws = 1 << (w + 1);\n var k = num.clone();\n\n for (var i = 0; i < naf.length; i++) {\n var z;\n var mod = k.andln(ws - 1);\n if (k.isOdd()) {\n if (mod > (ws >> 1) - 1)\n z = (ws >> 1) - mod;\n else\n z = mod;\n k.isubn(z);\n } else {\n z = 0;\n }\n\n naf[i] = z;\n k.iushrn(1);\n }\n\n return naf;\n}\nutils.getNAF = getNAF;\n\n// Represent k1, k2 in a Joint Sparse Form\nfunction getJSF(k1, k2) {\n var jsf = [\n [],\n []\n ];\n\n k1 = k1.clone();\n k2 = k2.clone();\n var d1 = 0;\n var d2 = 0;\n while (k1.cmpn(-d1) > 0 || k2.cmpn(-d2) > 0) {\n\n // First phase\n var m14 = (k1.andln(3) + d1) & 3;\n var m24 = (k2.andln(3) + d2) & 3;\n if (m14 === 3)\n m14 = -1;\n if (m24 === 3)\n m24 = -1;\n var u1;\n if ((m14 & 1) === 0) {\n u1 = 0;\n } else {\n var m8 = (k1.andln(7) + d1) & 7;\n if ((m8 === 3 || m8 === 5) && m24 === 2)\n u1 = -m14;\n else\n u1 = m14;\n }\n jsf[0].push(u1);\n\n var u2;\n if ((m24 & 1) === 0) {\n u2 = 0;\n } else {\n var m8 = (k2.andln(7) + d2) & 7;\n if ((m8 === 3 || m8 === 5) && m14 === 2)\n u2 = -m24;\n else\n u2 = m24;\n }\n jsf[1].push(u2);\n\n // Second phase\n if (2 * d1 === u1 + 1)\n d1 = 1 - d1;\n if (2 * d2 === u2 + 1)\n d2 = 1 - d2;\n k1.iushrn(1);\n k2.iushrn(1);\n }\n\n return jsf;\n}\nutils.getJSF = getJSF;\n\nfunction cachedProperty(obj, name, computer) {\n var key = '_' + name;\n obj.prototype[name] = function cachedProperty() {\n return this[key] !== undefined ? this[key] :\n this[key] = computer.call(this);\n };\n}\nutils.cachedProperty = cachedProperty;\n\nfunction parseBytes(bytes) {\n return typeof bytes === 'string' ? utils.toArray(bytes, 'hex') :\n bytes;\n}\nutils.parseBytes = parseBytes;\n\nfunction intFromLE(bytes) {\n return new BN(bytes, 'hex', 'le');\n}\nutils.intFromLE = intFromLE;\n\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// NOTE: These type checking functions intentionally don't use `instanceof`\n// because it is fragile and can be easily faked with `Object.create()`.\n\nfunction isArray(arg) {\n if (Array.isArray) {\n return Array.isArray(arg);\n }\n return objectToString(arg) === '[object Array]';\n}\nexports.isArray = isArray;\n\nfunction isBoolean(arg) {\n return typeof arg === 'boolean';\n}\nexports.isBoolean = isBoolean;\n\nfunction isNull(arg) {\n return arg === null;\n}\nexports.isNull = isNull;\n\nfunction isNullOrUndefined(arg) {\n return arg == null;\n}\nexports.isNullOrUndefined = isNullOrUndefined;\n\nfunction isNumber(arg) {\n return typeof arg === 'number';\n}\nexports.isNumber = isNumber;\n\nfunction isString(arg) {\n return typeof arg === 'string';\n}\nexports.isString = isString;\n\nfunction isSymbol(arg) {\n return typeof arg === 'symbol';\n}\nexports.isSymbol = isSymbol;\n\nfunction isUndefined(arg) {\n return arg === void 0;\n}\nexports.isUndefined = isUndefined;\n\nfunction isRegExp(re) {\n return objectToString(re) === '[object RegExp]';\n}\nexports.isRegExp = isRegExp;\n\nfunction isObject(arg) {\n return typeof arg === 'object' && arg !== null;\n}\nexports.isObject = isObject;\n\nfunction isDate(d) {\n return objectToString(d) === '[object Date]';\n}\nexports.isDate = isDate;\n\nfunction isError(e) {\n return (objectToString(e) === '[object Error]' || e instanceof Error);\n}\nexports.isError = isError;\n\nfunction isFunction(arg) {\n return typeof arg === 'function';\n}\nexports.isFunction = isFunction;\n\nfunction isPrimitive(arg) {\n return arg === null ||\n typeof arg === 'boolean' ||\n typeof arg === 'number' ||\n typeof arg === 'string' ||\n typeof arg === 'symbol' || // ES6 symbol\n typeof arg === 'undefined';\n}\nexports.isPrimitive = isPrimitive;\n\nexports.isBuffer = Buffer.isBuffer;\n\nfunction objectToString(o) {\n return Object.prototype.toString.call(o);\n}\n","module.exports = function(module) {\n\tif (!module.webpackPolyfill) {\n\t\tmodule.deprecate = function() {};\n\t\tmodule.paths = [];\n\t\t// module.parent = undefined by default\n\t\tif (!module.children) module.children = [];\n\t\tObject.defineProperty(module, \"loaded\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.l;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"id\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.i;\n\t\t\t}\n\t\t});\n\t\tmodule.webpackPolyfill = 1;\n\t}\n\treturn module;\n};\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\nvar R = typeof Reflect === 'object' ? Reflect : null\nvar ReflectApply = R && typeof R.apply === 'function'\n ? R.apply\n : function ReflectApply(target, receiver, args) {\n return Function.prototype.apply.call(target, receiver, args);\n }\n\nvar ReflectOwnKeys\nif (R && typeof R.ownKeys === 'function') {\n ReflectOwnKeys = R.ownKeys\n} else if (Object.getOwnPropertySymbols) {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target)\n .concat(Object.getOwnPropertySymbols(target));\n };\n} else {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target);\n };\n}\n\nfunction ProcessEmitWarning(warning) {\n if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n return value !== value;\n}\n\nfunction EventEmitter() {\n EventEmitter.init.call(this);\n}\nmodule.exports = EventEmitter;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nfunction checkListener(listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n}\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n enumerable: true,\n get: function() {\n return defaultMaxListeners;\n },\n set: function(arg) {\n if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n }\n defaultMaxListeners = arg;\n }\n});\n\nEventEmitter.init = function() {\n\n if (this._events === undefined ||\n this._events === Object.getPrototypeOf(this)._events) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n }\n\n this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n }\n this._maxListeners = n;\n return this;\n};\n\nfunction _getMaxListeners(that) {\n if (that._maxListeners === undefined)\n return EventEmitter.defaultMaxListeners;\n return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n return _getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n var args = [];\n for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n var doError = (type === 'error');\n\n var events = this._events;\n if (events !== undefined)\n doError = (doError && events.error === undefined);\n else if (!doError)\n return false;\n\n // If there is no 'error' event listener then throw.\n if (doError) {\n var er;\n if (args.length > 0)\n er = args[0];\n if (er instanceof Error) {\n // Note: The comments on the `throw` lines are intentional, they show\n // up in Node's output if this results in an unhandled exception.\n throw er; // Unhandled 'error' event\n }\n // At least give some kind of context to the user\n var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n err.context = er;\n throw err; // Unhandled 'error' event\n }\n\n var handler = events[type];\n\n if (handler === undefined)\n return false;\n\n if (typeof handler === 'function') {\n ReflectApply(handler, this, args);\n } else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n ReflectApply(listeners[i], this, args);\n }\n\n return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n var m;\n var events;\n var existing;\n\n checkListener(listener);\n\n events = target._events;\n if (events === undefined) {\n events = target._events = Object.create(null);\n target._eventsCount = 0;\n } else {\n // To avoid recursion in the case that type === \"newListener\"! Before\n // adding it to the listeners, first emit \"newListener\".\n if (events.newListener !== undefined) {\n target.emit('newListener', type,\n listener.listener ? listener.listener : listener);\n\n // Re-assign `events` because a newListener handler could have caused the\n // this._events to be assigned to a new object\n events = target._events;\n }\n existing = events[type];\n }\n\n if (existing === undefined) {\n // Optimize the case of one listener. Don't need the extra array object.\n existing = events[type] = listener;\n ++target._eventsCount;\n } else {\n if (typeof existing === 'function') {\n // Adding the second element, need to change to array.\n existing = events[type] =\n prepend ? [listener, existing] : [existing, listener];\n // If we've already got an array, just append.\n } else if (prepend) {\n existing.unshift(listener);\n } else {\n existing.push(listener);\n }\n\n // Check for listener leak\n m = _getMaxListeners(target);\n if (m > 0 && existing.length > m && !existing.warned) {\n existing.warned = true;\n // No error code for this since it is a Warning\n // eslint-disable-next-line no-restricted-syntax\n var w = new Error('Possible EventEmitter memory leak detected. ' +\n existing.length + ' ' + String(type) + ' listeners ' +\n 'added. Use emitter.setMaxListeners() to ' +\n 'increase limit');\n w.name = 'MaxListenersExceededWarning';\n w.emitter = target;\n w.type = type;\n w.count = existing.length;\n ProcessEmitWarning(w);\n }\n }\n\n return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n function prependListener(type, listener) {\n return _addListener(this, type, listener, true);\n };\n\nfunction onceWrapper() {\n if (!this.fired) {\n this.target.removeListener(this.type, this.wrapFn);\n this.fired = true;\n if (arguments.length === 0)\n return this.listener.call(this.target);\n return this.listener.apply(this.target, arguments);\n }\n}\n\nfunction _onceWrap(target, type, listener) {\n var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n var wrapped = onceWrapper.bind(state);\n wrapped.listener = listener;\n state.wrapFn = wrapped;\n return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n checkListener(listener);\n this.on(type, _onceWrap(this, type, listener));\n return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n function prependOnceListener(type, listener) {\n checkListener(listener);\n this.prependListener(type, _onceWrap(this, type, listener));\n return this;\n };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n function removeListener(type, listener) {\n var list, events, position, i, originalListener;\n\n checkListener(listener);\n\n events = this._events;\n if (events === undefined)\n return this;\n\n list = events[type];\n if (list === undefined)\n return this;\n\n if (list === listener || list.listener === listener) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else {\n delete events[type];\n if (events.removeListener)\n this.emit('removeListener', type, list.listener || listener);\n }\n } else if (typeof list !== 'function') {\n position = -1;\n\n for (i = list.length - 1; i >= 0; i--) {\n if (list[i] === listener || list[i].listener === listener) {\n originalListener = list[i].listener;\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (position === 0)\n list.shift();\n else {\n spliceOne(list, position);\n }\n\n if (list.length === 1)\n events[type] = list[0];\n\n if (events.removeListener !== undefined)\n this.emit('removeListener', type, originalListener || listener);\n }\n\n return this;\n };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n function removeAllListeners(type) {\n var listeners, events, i;\n\n events = this._events;\n if (events === undefined)\n return this;\n\n // not listening for removeListener, no need to emit\n if (events.removeListener === undefined) {\n if (arguments.length === 0) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (events[type] !== undefined) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else\n delete events[type];\n }\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n var keys = Object.keys(events);\n var key;\n for (i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = Object.create(null);\n this._eventsCount = 0;\n return this;\n }\n\n listeners = events[type];\n\n if (typeof listeners === 'function') {\n this.removeListener(type, listeners);\n } else if (listeners !== undefined) {\n // LIFO order\n for (i = listeners.length - 1; i >= 0; i--) {\n this.removeListener(type, listeners[i]);\n }\n }\n\n return this;\n };\n\nfunction _listeners(target, type, unwrap) {\n var events = target._events;\n\n if (events === undefined)\n return [];\n\n var evlistener = events[type];\n if (evlistener === undefined)\n return [];\n\n if (typeof evlistener === 'function')\n return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n return unwrap ?\n unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n if (typeof emitter.listenerCount === 'function') {\n return emitter.listenerCount(type);\n } else {\n return listenerCount.call(emitter, type);\n }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n var events = this._events;\n\n if (events !== undefined) {\n var evlistener = events[type];\n\n if (typeof evlistener === 'function') {\n return 1;\n } else if (evlistener !== undefined) {\n return evlistener.length;\n }\n }\n\n return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n var copy = new Array(n);\n for (var i = 0; i < n; ++i)\n copy[i] = arr[i];\n return copy;\n}\n\nfunction spliceOne(list, index) {\n for (; index + 1 < list.length; index++)\n list[index] = list[index + 1];\n list.pop();\n}\n\nfunction unwrapListeners(arr) {\n var ret = new Array(arr.length);\n for (var i = 0; i < ret.length; ++i) {\n ret[i] = arr[i].listener || arr[i];\n }\n return ret;\n}\n","'use strict';\n\nvar assert = require('minimalistic-assert');\nvar inherits = require('inherits');\n\nexports.inherits = inherits;\n\nfunction isSurrogatePair(msg, i) {\n if ((msg.charCodeAt(i) & 0xFC00) !== 0xD800) {\n return false;\n }\n if (i < 0 || i + 1 >= msg.length) {\n return false;\n }\n return (msg.charCodeAt(i + 1) & 0xFC00) === 0xDC00;\n}\n\nfunction toArray(msg, enc) {\n if (Array.isArray(msg))\n return msg.slice();\n if (!msg)\n return [];\n var res = [];\n if (typeof msg === 'string') {\n if (!enc) {\n // Inspired by stringToUtf8ByteArray() in closure-library by Google\n // https://github.com/google/closure-library/blob/8598d87242af59aac233270742c8984e2b2bdbe0/closure/goog/crypt/crypt.js#L117-L143\n // Apache License 2.0\n // https://github.com/google/closure-library/blob/master/LICENSE\n var p = 0;\n for (var i = 0; i < msg.length; i++) {\n var c = msg.charCodeAt(i);\n if (c < 128) {\n res[p++] = c;\n } else if (c < 2048) {\n res[p++] = (c >> 6) | 192;\n res[p++] = (c & 63) | 128;\n } else if (isSurrogatePair(msg, i)) {\n c = 0x10000 + ((c & 0x03FF) << 10) + (msg.charCodeAt(++i) & 0x03FF);\n res[p++] = (c >> 18) | 240;\n res[p++] = ((c >> 12) & 63) | 128;\n res[p++] = ((c >> 6) & 63) | 128;\n res[p++] = (c & 63) | 128;\n } else {\n res[p++] = (c >> 12) | 224;\n res[p++] = ((c >> 6) & 63) | 128;\n res[p++] = (c & 63) | 128;\n }\n }\n } else if (enc === 'hex') {\n msg = msg.replace(/[^a-z0-9]+/ig, '');\n if (msg.length % 2 !== 0)\n msg = '0' + msg;\n for (i = 0; i < msg.length; i += 2)\n res.push(parseInt(msg[i] + msg[i + 1], 16));\n }\n } else {\n for (i = 0; i < msg.length; i++)\n res[i] = msg[i] | 0;\n }\n return res;\n}\nexports.toArray = toArray;\n\nfunction toHex(msg) {\n var res = '';\n for (var i = 0; i < msg.length; i++)\n res += zero2(msg[i].toString(16));\n return res;\n}\nexports.toHex = toHex;\n\nfunction htonl(w) {\n var res = (w >>> 24) |\n ((w >>> 8) & 0xff00) |\n ((w << 8) & 0xff0000) |\n ((w & 0xff) << 24);\n return res >>> 0;\n}\nexports.htonl = htonl;\n\nfunction toHex32(msg, endian) {\n var res = '';\n for (var i = 0; i < msg.length; i++) {\n var w = msg[i];\n if (endian === 'little')\n w = htonl(w);\n res += zero8(w.toString(16));\n }\n return res;\n}\nexports.toHex32 = toHex32;\n\nfunction zero2(word) {\n if (word.length === 1)\n return '0' + word;\n else\n return word;\n}\nexports.zero2 = zero2;\n\nfunction zero8(word) {\n if (word.length === 7)\n return '0' + word;\n else if (word.length === 6)\n return '00' + word;\n else if (word.length === 5)\n return '000' + word;\n else if (word.length === 4)\n return '0000' + word;\n else if (word.length === 3)\n return '00000' + word;\n else if (word.length === 2)\n return '000000' + word;\n else if (word.length === 1)\n return '0000000' + word;\n else\n return word;\n}\nexports.zero8 = zero8;\n\nfunction join32(msg, start, end, endian) {\n var len = end - start;\n assert(len % 4 === 0);\n var res = new Array(len / 4);\n for (var i = 0, k = start; i < res.length; i++, k += 4) {\n var w;\n if (endian === 'big')\n w = (msg[k] << 24) | (msg[k + 1] << 16) | (msg[k + 2] << 8) | msg[k + 3];\n else\n w = (msg[k + 3] << 24) | (msg[k + 2] << 16) | (msg[k + 1] << 8) | msg[k];\n res[i] = w >>> 0;\n }\n return res;\n}\nexports.join32 = join32;\n\nfunction split32(msg, endian) {\n var res = new Array(msg.length * 4);\n for (var i = 0, k = 0; i < msg.length; i++, k += 4) {\n var m = msg[i];\n if (endian === 'big') {\n res[k] = m >>> 24;\n res[k + 1] = (m >>> 16) & 0xff;\n res[k + 2] = (m >>> 8) & 0xff;\n res[k + 3] = m & 0xff;\n } else {\n res[k + 3] = m >>> 24;\n res[k + 2] = (m >>> 16) & 0xff;\n res[k + 1] = (m >>> 8) & 0xff;\n res[k] = m & 0xff;\n }\n }\n return res;\n}\nexports.split32 = split32;\n\nfunction rotr32(w, b) {\n return (w >>> b) | (w << (32 - b));\n}\nexports.rotr32 = rotr32;\n\nfunction rotl32(w, b) {\n return (w << b) | (w >>> (32 - b));\n}\nexports.rotl32 = rotl32;\n\nfunction sum32(a, b) {\n return (a + b) >>> 0;\n}\nexports.sum32 = sum32;\n\nfunction sum32_3(a, b, c) {\n return (a + b + c) >>> 0;\n}\nexports.sum32_3 = sum32_3;\n\nfunction sum32_4(a, b, c, d) {\n return (a + b + c + d) >>> 0;\n}\nexports.sum32_4 = sum32_4;\n\nfunction sum32_5(a, b, c, d, e) {\n return (a + b + c + d + e) >>> 0;\n}\nexports.sum32_5 = sum32_5;\n\nfunction sum64(buf, pos, ah, al) {\n var bh = buf[pos];\n var bl = buf[pos + 1];\n\n var lo = (al + bl) >>> 0;\n var hi = (lo < al ? 1 : 0) + ah + bh;\n buf[pos] = hi >>> 0;\n buf[pos + 1] = lo;\n}\nexports.sum64 = sum64;\n\nfunction sum64_hi(ah, al, bh, bl) {\n var lo = (al + bl) >>> 0;\n var hi = (lo < al ? 1 : 0) + ah + bh;\n return hi >>> 0;\n}\nexports.sum64_hi = sum64_hi;\n\nfunction sum64_lo(ah, al, bh, bl) {\n var lo = al + bl;\n return lo >>> 0;\n}\nexports.sum64_lo = sum64_lo;\n\nfunction sum64_4_hi(ah, al, bh, bl, ch, cl, dh, dl) {\n var carry = 0;\n var lo = al;\n lo = (lo + bl) >>> 0;\n carry += lo < al ? 1 : 0;\n lo = (lo + cl) >>> 0;\n carry += lo < cl ? 1 : 0;\n lo = (lo + dl) >>> 0;\n carry += lo < dl ? 1 : 0;\n\n var hi = ah + bh + ch + dh + carry;\n return hi >>> 0;\n}\nexports.sum64_4_hi = sum64_4_hi;\n\nfunction sum64_4_lo(ah, al, bh, bl, ch, cl, dh, dl) {\n var lo = al + bl + cl + dl;\n return lo >>> 0;\n}\nexports.sum64_4_lo = sum64_4_lo;\n\nfunction sum64_5_hi(ah, al, bh, bl, ch, cl, dh, dl, eh, el) {\n var carry = 0;\n var lo = al;\n lo = (lo + bl) >>> 0;\n carry += lo < al ? 1 : 0;\n lo = (lo + cl) >>> 0;\n carry += lo < cl ? 1 : 0;\n lo = (lo + dl) >>> 0;\n carry += lo < dl ? 1 : 0;\n lo = (lo + el) >>> 0;\n carry += lo < el ? 1 : 0;\n\n var hi = ah + bh + ch + dh + eh + carry;\n return hi >>> 0;\n}\nexports.sum64_5_hi = sum64_5_hi;\n\nfunction sum64_5_lo(ah, al, bh, bl, ch, cl, dh, dl, eh, el) {\n var lo = al + bl + cl + dl + el;\n\n return lo >>> 0;\n}\nexports.sum64_5_lo = sum64_5_lo;\n\nfunction rotr64_hi(ah, al, num) {\n var r = (al << (32 - num)) | (ah >>> num);\n return r >>> 0;\n}\nexports.rotr64_hi = rotr64_hi;\n\nfunction rotr64_lo(ah, al, num) {\n var r = (ah << (32 - num)) | (al >>> num);\n return r >>> 0;\n}\nexports.rotr64_lo = rotr64_lo;\n\nfunction shr64_hi(ah, al, num) {\n return ah >>> num;\n}\nexports.shr64_hi = shr64_hi;\n\nfunction shr64_lo(ah, al, num) {\n var r = (ah << (32 - num)) | (al >>> num);\n return r >>> 0;\n}\nexports.shr64_lo = shr64_lo;\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\nvar punycode = require('punycode');\nvar util = require('./util');\n\nexports.parse = urlParse;\nexports.resolve = urlResolve;\nexports.resolveObject = urlResolveObject;\nexports.format = urlFormat;\n\nexports.Url = Url;\n\nfunction Url() {\n this.protocol = null;\n this.slashes = null;\n this.auth = null;\n this.host = null;\n this.port = null;\n this.hostname = null;\n this.hash = null;\n this.search = null;\n this.query = null;\n this.pathname = null;\n this.path = null;\n this.href = null;\n}\n\n// Reference: RFC 3986, RFC 1808, RFC 2396\n\n// define these here so at least they only have to be\n// compiled once on the first module load.\nvar protocolPattern = /^([a-z0-9.+-]+:)/i,\n portPattern = /:[0-9]*$/,\n\n // Special case for a simple path URL\n simplePathPattern = /^(\\/\\/?(?!\\/)[^\\?\\s]*)(\\?[^\\s]*)?$/,\n\n // RFC 2396: characters reserved for delimiting URLs.\n // We actually just auto-escape these.\n delims = ['<', '>', '\"', '`', ' ', '\\r', '\\n', '\\t'],\n\n // RFC 2396: characters not allowed for various reasons.\n unwise = ['{', '}', '|', '\\\\', '^', '`'].concat(delims),\n\n // Allowed by RFCs, but cause of XSS attacks. Always escape these.\n autoEscape = ['\\''].concat(unwise),\n // Characters that are never ever allowed in a hostname.\n // Note that any invalid chars are also handled, but these\n // are the ones that are *expected* to be seen, so we fast-path\n // them.\n nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape),\n hostEndingChars = ['/', '?', '#'],\n hostnameMaxLen = 255,\n hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/,\n hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/,\n // protocols that can allow \"unsafe\" and \"unwise\" chars.\n unsafeProtocol = {\n 'javascript': true,\n 'javascript:': true\n },\n // protocols that never have a hostname.\n hostlessProtocol = {\n 'javascript': true,\n 'javascript:': true\n },\n // protocols that always contain a // bit.\n slashedProtocol = {\n 'http': true,\n 'https': true,\n 'ftp': true,\n 'gopher': true,\n 'file': true,\n 'http:': true,\n 'https:': true,\n 'ftp:': true,\n 'gopher:': true,\n 'file:': true\n },\n querystring = require('querystring');\n\nfunction urlParse(url, parseQueryString, slashesDenoteHost) {\n if (url && util.isObject(url) && url instanceof Url) return url;\n\n var u = new Url;\n u.parse(url, parseQueryString, slashesDenoteHost);\n return u;\n}\n\nUrl.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {\n if (!util.isString(url)) {\n throw new TypeError(\"Parameter 'url' must be a string, not \" + typeof url);\n }\n\n // Copy chrome, IE, opera backslash-handling behavior.\n // Back slashes before the query string get converted to forward slashes\n // See: https://code.google.com/p/chromium/issues/detail?id=25916\n var queryIndex = url.indexOf('?'),\n splitter =\n (queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#',\n uSplit = url.split(splitter),\n slashRegex = /\\\\/g;\n uSplit[0] = uSplit[0].replace(slashRegex, '/');\n url = uSplit.join(splitter);\n\n var rest = url;\n\n // trim before proceeding.\n // This is to support parse stuff like \" http://foo.com \\n\"\n rest = rest.trim();\n\n if (!slashesDenoteHost && url.split('#').length === 1) {\n // Try fast path regexp\n var simplePath = simplePathPattern.exec(rest);\n if (simplePath) {\n this.path = rest;\n this.href = rest;\n this.pathname = simplePath[1];\n if (simplePath[2]) {\n this.search = simplePath[2];\n if (parseQueryString) {\n this.query = querystring.parse(this.search.substr(1));\n } else {\n this.query = this.search.substr(1);\n }\n } else if (parseQueryString) {\n this.search = '';\n this.query = {};\n }\n return this;\n }\n }\n\n var proto = protocolPattern.exec(rest);\n if (proto) {\n proto = proto[0];\n var lowerProto = proto.toLowerCase();\n this.protocol = lowerProto;\n rest = rest.substr(proto.length);\n }\n\n // figure out if it's got a host\n // user@server is *always* interpreted as a hostname, and url\n // resolution will treat //foo/bar as host=foo,path=bar because that's\n // how the browser resolves relative URLs.\n if (slashesDenoteHost || proto || rest.match(/^\\/\\/[^@\\/]+@[^@\\/]+/)) {\n var slashes = rest.substr(0, 2) === '//';\n if (slashes && !(proto && hostlessProtocol[proto])) {\n rest = rest.substr(2);\n this.slashes = true;\n }\n }\n\n if (!hostlessProtocol[proto] &&\n (slashes || (proto && !slashedProtocol[proto]))) {\n\n // there's a hostname.\n // the first instance of /, ?, ;, or # ends the host.\n //\n // If there is an @ in the hostname, then non-host chars *are* allowed\n // to the left of the last @ sign, unless some host-ending character\n // comes *before* the @-sign.\n // URLs are obnoxious.\n //\n // ex:\n // http://a@b@c/ => user:a@b host:c\n // http://a@b?@c => user:a host:c path:/?@c\n\n // v0.12 TODO(isaacs): This is not quite how Chrome does things.\n // Review our test case against browsers more comprehensively.\n\n // find the first instance of any hostEndingChars\n var hostEnd = -1;\n for (var i = 0; i < hostEndingChars.length; i++) {\n var hec = rest.indexOf(hostEndingChars[i]);\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))\n hostEnd = hec;\n }\n\n // at this point, either we have an explicit point where the\n // auth portion cannot go past, or the last @ char is the decider.\n var auth, atSign;\n if (hostEnd === -1) {\n // atSign can be anywhere.\n atSign = rest.lastIndexOf('@');\n } else {\n // atSign must be in auth portion.\n // http://a@b/c@d => host:b auth:a path:/c@d\n atSign = rest.lastIndexOf('@', hostEnd);\n }\n\n // Now we have a portion which is definitely the auth.\n // Pull that off.\n if (atSign !== -1) {\n auth = rest.slice(0, atSign);\n rest = rest.slice(atSign + 1);\n this.auth = decodeURIComponent(auth);\n }\n\n // the host is the remaining to the left of the first non-host char\n hostEnd = -1;\n for (var i = 0; i < nonHostChars.length; i++) {\n var hec = rest.indexOf(nonHostChars[i]);\n if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))\n hostEnd = hec;\n }\n // if we still have not hit it, then the entire thing is a host.\n if (hostEnd === -1)\n hostEnd = rest.length;\n\n this.host = rest.slice(0, hostEnd);\n rest = rest.slice(hostEnd);\n\n // pull out port.\n this.parseHost();\n\n // we've indicated that there is a hostname,\n // so even if it's empty, it has to be present.\n this.hostname = this.hostname || '';\n\n // if hostname begins with [ and ends with ]\n // assume that it's an IPv6 address.\n var ipv6Hostname = this.hostname[0] === '[' &&\n this.hostname[this.hostname.length - 1] === ']';\n\n // validate a little.\n if (!ipv6Hostname) {\n var hostparts = this.hostname.split(/\\./);\n for (var i = 0, l = hostparts.length; i < l; i++) {\n var part = hostparts[i];\n if (!part) continue;\n if (!part.match(hostnamePartPattern)) {\n var newpart = '';\n for (var j = 0, k = part.length; j < k; j++) {\n if (part.charCodeAt(j) > 127) {\n // we replace non-ASCII char with a temporary placeholder\n // we need this to make sure size of hostname is not\n // broken by replacing non-ASCII by nothing\n newpart += 'x';\n } else {\n newpart += part[j];\n }\n }\n // we test again with ASCII char only\n if (!newpart.match(hostnamePartPattern)) {\n var validParts = hostparts.slice(0, i);\n var notHost = hostparts.slice(i + 1);\n var bit = part.match(hostnamePartStart);\n if (bit) {\n validParts.push(bit[1]);\n notHost.unshift(bit[2]);\n }\n if (notHost.length) {\n rest = '/' + notHost.join('.') + rest;\n }\n this.hostname = validParts.join('.');\n break;\n }\n }\n }\n }\n\n if (this.hostname.length > hostnameMaxLen) {\n this.hostname = '';\n } else {\n // hostnames are always lower case.\n this.hostname = this.hostname.toLowerCase();\n }\n\n if (!ipv6Hostname) {\n // IDNA Support: Returns a punycoded representation of \"domain\".\n // It only converts parts of the domain name that\n // have non-ASCII characters, i.e. it doesn't matter if\n // you call it with a domain that already is ASCII-only.\n this.hostname = punycode.toASCII(this.hostname);\n }\n\n var p = this.port ? ':' + this.port : '';\n var h = this.hostname || '';\n this.host = h + p;\n this.href += this.host;\n\n // strip [ and ] from the hostname\n // the host field still retains them, though\n if (ipv6Hostname) {\n this.hostname = this.hostname.substr(1, this.hostname.length - 2);\n if (rest[0] !== '/') {\n rest = '/' + rest;\n }\n }\n }\n\n // now rest is set to the post-host stuff.\n // chop off any delim chars.\n if (!unsafeProtocol[lowerProto]) {\n\n // First, make 100% sure that any \"autoEscape\" chars get\n // escaped, even if encodeURIComponent doesn't think they\n // need to be.\n for (var i = 0, l = autoEscape.length; i < l; i++) {\n var ae = autoEscape[i];\n if (rest.indexOf(ae) === -1)\n continue;\n var esc = encodeURIComponent(ae);\n if (esc === ae) {\n esc = escape(ae);\n }\n rest = rest.split(ae).join(esc);\n }\n }\n\n\n // chop off from the tail first.\n var hash = rest.indexOf('#');\n if (hash !== -1) {\n // got a fragment string.\n this.hash = rest.substr(hash);\n rest = rest.slice(0, hash);\n }\n var qm = rest.indexOf('?');\n if (qm !== -1) {\n this.search = rest.substr(qm);\n this.query = rest.substr(qm + 1);\n if (parseQueryString) {\n this.query = querystring.parse(this.query);\n }\n rest = rest.slice(0, qm);\n } else if (parseQueryString) {\n // no query string, but parseQueryString still requested\n this.search = '';\n this.query = {};\n }\n if (rest) this.pathname = rest;\n if (slashedProtocol[lowerProto] &&\n this.hostname && !this.pathname) {\n this.pathname = '/';\n }\n\n //to support http.request\n if (this.pathname || this.search) {\n var p = this.pathname || '';\n var s = this.search || '';\n this.path = p + s;\n }\n\n // finally, reconstruct the href based on what has been validated.\n this.href = this.format();\n return this;\n};\n\n// format a parsed object into a url string\nfunction urlFormat(obj) {\n // ensure it's an object, and not a string url.\n // If it's an obj, this is a no-op.\n // this way, you can call url_format() on strings\n // to clean up potentially wonky urls.\n if (util.isString(obj)) obj = urlParse(obj);\n if (!(obj instanceof Url)) return Url.prototype.format.call(obj);\n return obj.format();\n}\n\nUrl.prototype.format = function() {\n var auth = this.auth || '';\n if (auth) {\n auth = encodeURIComponent(auth);\n auth = auth.replace(/%3A/i, ':');\n auth += '@';\n }\n\n var protocol = this.protocol || '',\n pathname = this.pathname || '',\n hash = this.hash || '',\n host = false,\n query = '';\n\n if (this.host) {\n host = auth + this.host;\n } else if (this.hostname) {\n host = auth + (this.hostname.indexOf(':') === -1 ?\n this.hostname :\n '[' + this.hostname + ']');\n if (this.port) {\n host += ':' + this.port;\n }\n }\n\n if (this.query &&\n util.isObject(this.query) &&\n Object.keys(this.query).length) {\n query = querystring.stringify(this.query);\n }\n\n var search = this.search || (query && ('?' + query)) || '';\n\n if (protocol && protocol.substr(-1) !== ':') protocol += ':';\n\n // only the slashedProtocols get the //. Not mailto:, xmpp:, etc.\n // unless they had them to begin with.\n if (this.slashes ||\n (!protocol || slashedProtocol[protocol]) && host !== false) {\n host = '//' + (host || '');\n if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname;\n } else if (!host) {\n host = '';\n }\n\n if (hash && hash.charAt(0) !== '#') hash = '#' + hash;\n if (search && search.charAt(0) !== '?') search = '?' + search;\n\n pathname = pathname.replace(/[?#]/g, function(match) {\n return encodeURIComponent(match);\n });\n search = search.replace('#', '%23');\n\n return protocol + host + pathname + search + hash;\n};\n\nfunction urlResolve(source, relative) {\n return urlParse(source, false, true).resolve(relative);\n}\n\nUrl.prototype.resolve = function(relative) {\n return this.resolveObject(urlParse(relative, false, true)).format();\n};\n\nfunction urlResolveObject(source, relative) {\n if (!source) return relative;\n return urlParse(source, false, true).resolveObject(relative);\n}\n\nUrl.prototype.resolveObject = function(relative) {\n if (util.isString(relative)) {\n var rel = new Url();\n rel.parse(relative, false, true);\n relative = rel;\n }\n\n var result = new Url();\n var tkeys = Object.keys(this);\n for (var tk = 0; tk < tkeys.length; tk++) {\n var tkey = tkeys[tk];\n result[tkey] = this[tkey];\n }\n\n // hash is always overridden, no matter what.\n // even href=\"\" will remove it.\n result.hash = relative.hash;\n\n // if the relative url is empty, then there's nothing left to do here.\n if (relative.href === '') {\n result.href = result.format();\n return result;\n }\n\n // hrefs like //foo/bar always cut to the protocol.\n if (relative.slashes && !relative.protocol) {\n // take everything except the protocol from relative\n var rkeys = Object.keys(relative);\n for (var rk = 0; rk < rkeys.length; rk++) {\n var rkey = rkeys[rk];\n if (rkey !== 'protocol')\n result[rkey] = relative[rkey];\n }\n\n //urlParse appends trailing / to urls like http://www.example.com\n if (slashedProtocol[result.protocol] &&\n result.hostname && !result.pathname) {\n result.path = result.pathname = '/';\n }\n\n result.href = result.format();\n return result;\n }\n\n if (relative.protocol && relative.protocol !== result.protocol) {\n // if it's a known url protocol, then changing\n // the protocol does weird things\n // first, if it's not file:, then we MUST have a host,\n // and if there was a path\n // to begin with, then we MUST have a path.\n // if it is file:, then the host is dropped,\n // because that's known to be hostless.\n // anything else is assumed to be absolute.\n if (!slashedProtocol[relative.protocol]) {\n var keys = Object.keys(relative);\n for (var v = 0; v < keys.length; v++) {\n var k = keys[v];\n result[k] = relative[k];\n }\n result.href = result.format();\n return result;\n }\n\n result.protocol = relative.protocol;\n if (!relative.host && !hostlessProtocol[relative.protocol]) {\n var relPath = (relative.pathname || '').split('/');\n while (relPath.length && !(relative.host = relPath.shift()));\n if (!relative.host) relative.host = '';\n if (!relative.hostname) relative.hostname = '';\n if (relPath[0] !== '') relPath.unshift('');\n if (relPath.length < 2) relPath.unshift('');\n result.pathname = relPath.join('/');\n } else {\n result.pathname = relative.pathname;\n }\n result.search = relative.search;\n result.query = relative.query;\n result.host = relative.host || '';\n result.auth = relative.auth;\n result.hostname = relative.hostname || relative.host;\n result.port = relative.port;\n // to support http.request\n if (result.pathname || result.search) {\n var p = result.pathname || '';\n var s = result.search || '';\n result.path = p + s;\n }\n result.slashes = result.slashes || relative.slashes;\n result.href = result.format();\n return result;\n }\n\n var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'),\n isRelAbs = (\n relative.host ||\n relative.pathname && relative.pathname.charAt(0) === '/'\n ),\n mustEndAbs = (isRelAbs || isSourceAbs ||\n (result.host && relative.pathname)),\n removeAllDots = mustEndAbs,\n srcPath = result.pathname && result.pathname.split('/') || [],\n relPath = relative.pathname && relative.pathname.split('/') || [],\n psychotic = result.protocol && !slashedProtocol[result.protocol];\n\n // if the url is a non-slashed url, then relative\n // links like ../.. should be able\n // to crawl up to the hostname, as well. This is strange.\n // result.protocol has already been set by now.\n // Later on, put the first path part into the host field.\n if (psychotic) {\n result.hostname = '';\n result.port = null;\n if (result.host) {\n if (srcPath[0] === '') srcPath[0] = result.host;\n else srcPath.unshift(result.host);\n }\n result.host = '';\n if (relative.protocol) {\n relative.hostname = null;\n relative.port = null;\n if (relative.host) {\n if (relPath[0] === '') relPath[0] = relative.host;\n else relPath.unshift(relative.host);\n }\n relative.host = null;\n }\n mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');\n }\n\n if (isRelAbs) {\n // it's absolute.\n result.host = (relative.host || relative.host === '') ?\n relative.host : result.host;\n result.hostname = (relative.hostname || relative.hostname === '') ?\n relative.hostname : result.hostname;\n result.search = relative.search;\n result.query = relative.query;\n srcPath = relPath;\n // fall through to the dot-handling below.\n } else if (relPath.length) {\n // it's relative\n // throw away the existing file, and take the new path instead.\n if (!srcPath) srcPath = [];\n srcPath.pop();\n srcPath = srcPath.concat(relPath);\n result.search = relative.search;\n result.query = relative.query;\n } else if (!util.isNullOrUndefined(relative.search)) {\n // just pull out the search.\n // like href='?foo'.\n // Put this after the other two cases because it simplifies the booleans\n if (psychotic) {\n result.hostname = result.host = srcPath.shift();\n //occationaly the auth can get stuck only in host\n //this especially happens in cases like\n //url.resolveObject('mailto:local1@domain1', 'local2@domain2')\n var authInHost = result.host && result.host.indexOf('@') > 0 ?\n result.host.split('@') : false;\n if (authInHost) {\n result.auth = authInHost.shift();\n result.host = result.hostname = authInHost.shift();\n }\n }\n result.search = relative.search;\n result.query = relative.query;\n //to support http.request\n if (!util.isNull(result.pathname) || !util.isNull(result.search)) {\n result.path = (result.pathname ? result.pathname : '') +\n (result.search ? result.search : '');\n }\n result.href = result.format();\n return result;\n }\n\n if (!srcPath.length) {\n // no path at all. easy.\n // we've already handled the other stuff above.\n result.pathname = null;\n //to support http.request\n if (result.search) {\n result.path = '/' + result.search;\n } else {\n result.path = null;\n }\n result.href = result.format();\n return result;\n }\n\n // if a url ENDs in . or .., then it must get a trailing slash.\n // however, if it ends in anything else non-slashy,\n // then it must NOT get a trailing slash.\n var last = srcPath.slice(-1)[0];\n var hasTrailingSlash = (\n (result.host || relative.host || srcPath.length > 1) &&\n (last === '.' || last === '..') || last === '');\n\n // strip single dots, resolve double dots to parent dir\n // if the path tries to go above the root, `up` ends up > 0\n var up = 0;\n for (var i = srcPath.length; i >= 0; i--) {\n last = srcPath[i];\n if (last === '.') {\n srcPath.splice(i, 1);\n } else if (last === '..') {\n srcPath.splice(i, 1);\n up++;\n } else if (up) {\n srcPath.splice(i, 1);\n up--;\n }\n }\n\n // if the path is allowed to go above the root, restore leading ..s\n if (!mustEndAbs && !removeAllDots) {\n for (; up--; up) {\n srcPath.unshift('..');\n }\n }\n\n if (mustEndAbs && srcPath[0] !== '' &&\n (!srcPath[0] || srcPath[0].charAt(0) !== '/')) {\n srcPath.unshift('');\n }\n\n if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) {\n srcPath.push('');\n }\n\n var isAbsolute = srcPath[0] === '' ||\n (srcPath[0] && srcPath[0].charAt(0) === '/');\n\n // put the host back\n if (psychotic) {\n result.hostname = result.host = isAbsolute ? '' :\n srcPath.length ? srcPath.shift() : '';\n //occationaly the auth can get stuck only in host\n //this especially happens in cases like\n //url.resolveObject('mailto:local1@domain1', 'local2@domain2')\n var authInHost = result.host && result.host.indexOf('@') > 0 ?\n result.host.split('@') : false;\n if (authInHost) {\n result.auth = authInHost.shift();\n result.host = result.hostname = authInHost.shift();\n }\n }\n\n mustEndAbs = mustEndAbs || (result.host && srcPath.length);\n\n if (mustEndAbs && !isAbsolute) {\n srcPath.unshift('');\n }\n\n if (!srcPath.length) {\n result.pathname = null;\n result.path = null;\n } else {\n result.pathname = srcPath.join('/');\n }\n\n //to support request.http\n if (!util.isNull(result.pathname) || !util.isNull(result.search)) {\n result.path = (result.pathname ? result.pathname : '') +\n (result.search ? result.search : '');\n }\n result.auth = relative.auth || result.auth;\n result.slashes = result.slashes || relative.slashes;\n result.href = result.format();\n return result;\n};\n\nUrl.prototype.parseHost = function() {\n var host = this.host;\n var port = portPattern.exec(host);\n if (port) {\n port = port[0];\n if (port !== ':') {\n this.port = port.substr(1);\n }\n host = host.substr(0, host.length - port.length);\n }\n if (host) this.hostname = host;\n};\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\n/**/\n\nvar Buffer = require('safe-buffer').Buffer;\n/**/\n\nvar isEncoding = Buffer.isEncoding || function (encoding) {\n encoding = '' + encoding;\n switch (encoding && encoding.toLowerCase()) {\n case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw':\n return true;\n default:\n return false;\n }\n};\n\nfunction _normalizeEncoding(enc) {\n if (!enc) return 'utf8';\n var retried;\n while (true) {\n switch (enc) {\n case 'utf8':\n case 'utf-8':\n return 'utf8';\n case 'ucs2':\n case 'ucs-2':\n case 'utf16le':\n case 'utf-16le':\n return 'utf16le';\n case 'latin1':\n case 'binary':\n return 'latin1';\n case 'base64':\n case 'ascii':\n case 'hex':\n return enc;\n default:\n if (retried) return; // undefined\n enc = ('' + enc).toLowerCase();\n retried = true;\n }\n }\n};\n\n// Do not cache `Buffer.isEncoding` when checking encoding names as some\n// modules monkey-patch it to support additional encodings\nfunction normalizeEncoding(enc) {\n var nenc = _normalizeEncoding(enc);\n if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc);\n return nenc || enc;\n}\n\n// StringDecoder provides an interface for efficiently splitting a series of\n// buffers into a series of JS strings without breaking apart multi-byte\n// characters.\nexports.StringDecoder = StringDecoder;\nfunction StringDecoder(encoding) {\n this.encoding = normalizeEncoding(encoding);\n var nb;\n switch (this.encoding) {\n case 'utf16le':\n this.text = utf16Text;\n this.end = utf16End;\n nb = 4;\n break;\n case 'utf8':\n this.fillLast = utf8FillLast;\n nb = 4;\n break;\n case 'base64':\n this.text = base64Text;\n this.end = base64End;\n nb = 3;\n break;\n default:\n this.write = simpleWrite;\n this.end = simpleEnd;\n return;\n }\n this.lastNeed = 0;\n this.lastTotal = 0;\n this.lastChar = Buffer.allocUnsafe(nb);\n}\n\nStringDecoder.prototype.write = function (buf) {\n if (buf.length === 0) return '';\n var r;\n var i;\n if (this.lastNeed) {\n r = this.fillLast(buf);\n if (r === undefined) return '';\n i = this.lastNeed;\n this.lastNeed = 0;\n } else {\n i = 0;\n }\n if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i);\n return r || '';\n};\n\nStringDecoder.prototype.end = utf8End;\n\n// Returns only complete characters in a Buffer\nStringDecoder.prototype.text = utf8Text;\n\n// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer\nStringDecoder.prototype.fillLast = function (buf) {\n if (this.lastNeed <= buf.length) {\n buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed);\n return this.lastChar.toString(this.encoding, 0, this.lastTotal);\n }\n buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length);\n this.lastNeed -= buf.length;\n};\n\n// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a\n// continuation byte. If an invalid byte is detected, -2 is returned.\nfunction utf8CheckByte(byte) {\n if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4;\n return byte >> 6 === 0x02 ? -1 : -2;\n}\n\n// Checks at most 3 bytes at the end of a Buffer in order to detect an\n// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4)\n// needed to complete the UTF-8 character (if applicable) are returned.\nfunction utf8CheckIncomplete(self, buf, i) {\n var j = buf.length - 1;\n if (j < i) return 0;\n var nb = utf8CheckByte(buf[j]);\n if (nb >= 0) {\n if (nb > 0) self.lastNeed = nb - 1;\n return nb;\n }\n if (--j < i || nb === -2) return 0;\n nb = utf8CheckByte(buf[j]);\n if (nb >= 0) {\n if (nb > 0) self.lastNeed = nb - 2;\n return nb;\n }\n if (--j < i || nb === -2) return 0;\n nb = utf8CheckByte(buf[j]);\n if (nb >= 0) {\n if (nb > 0) {\n if (nb === 2) nb = 0;else self.lastNeed = nb - 3;\n }\n return nb;\n }\n return 0;\n}\n\n// Validates as many continuation bytes for a multi-byte UTF-8 character as\n// needed or are available. If we see a non-continuation byte where we expect\n// one, we \"replace\" the validated continuation bytes we've seen so far with\n// a single UTF-8 replacement character ('\\ufffd'), to match v8's UTF-8 decoding\n// behavior. The continuation byte check is included three times in the case\n// where all of the continuation bytes for a character exist in the same buffer.\n// It is also done this way as a slight performance increase instead of using a\n// loop.\nfunction utf8CheckExtraBytes(self, buf, p) {\n if ((buf[0] & 0xC0) !== 0x80) {\n self.lastNeed = 0;\n return '\\ufffd';\n }\n if (self.lastNeed > 1 && buf.length > 1) {\n if ((buf[1] & 0xC0) !== 0x80) {\n self.lastNeed = 1;\n return '\\ufffd';\n }\n if (self.lastNeed > 2 && buf.length > 2) {\n if ((buf[2] & 0xC0) !== 0x80) {\n self.lastNeed = 2;\n return '\\ufffd';\n }\n }\n }\n}\n\n// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer.\nfunction utf8FillLast(buf) {\n var p = this.lastTotal - this.lastNeed;\n var r = utf8CheckExtraBytes(this, buf, p);\n if (r !== undefined) return r;\n if (this.lastNeed <= buf.length) {\n buf.copy(this.lastChar, p, 0, this.lastNeed);\n return this.lastChar.toString(this.encoding, 0, this.lastTotal);\n }\n buf.copy(this.lastChar, p, 0, buf.length);\n this.lastNeed -= buf.length;\n}\n\n// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a\n// partial character, the character's bytes are buffered until the required\n// number of bytes are available.\nfunction utf8Text(buf, i) {\n var total = utf8CheckIncomplete(this, buf, i);\n if (!this.lastNeed) return buf.toString('utf8', i);\n this.lastTotal = total;\n var end = buf.length - (total - this.lastNeed);\n buf.copy(this.lastChar, 0, end);\n return buf.toString('utf8', i, end);\n}\n\n// For UTF-8, a replacement character is added when ending on a partial\n// character.\nfunction utf8End(buf) {\n var r = buf && buf.length ? this.write(buf) : '';\n if (this.lastNeed) return r + '\\ufffd';\n return r;\n}\n\n// UTF-16LE typically needs two bytes per character, but even if we have an even\n// number of bytes available, we need to check if we end on a leading/high\n// surrogate. In that case, we need to wait for the next two bytes in order to\n// decode the last character properly.\nfunction utf16Text(buf, i) {\n if ((buf.length - i) % 2 === 0) {\n var r = buf.toString('utf16le', i);\n if (r) {\n var c = r.charCodeAt(r.length - 1);\n if (c >= 0xD800 && c <= 0xDBFF) {\n this.lastNeed = 2;\n this.lastTotal = 4;\n this.lastChar[0] = buf[buf.length - 2];\n this.lastChar[1] = buf[buf.length - 1];\n return r.slice(0, -1);\n }\n }\n return r;\n }\n this.lastNeed = 1;\n this.lastTotal = 2;\n this.lastChar[0] = buf[buf.length - 1];\n return buf.toString('utf16le', i, buf.length - 1);\n}\n\n// For UTF-16LE we do not explicitly append special replacement characters if we\n// end on a partial character, we simply let v8 handle that.\nfunction utf16End(buf) {\n var r = buf && buf.length ? this.write(buf) : '';\n if (this.lastNeed) {\n var end = this.lastTotal - this.lastNeed;\n return r + this.lastChar.toString('utf16le', 0, end);\n }\n return r;\n}\n\nfunction base64Text(buf, i) {\n var n = (buf.length - i) % 3;\n if (n === 0) return buf.toString('base64', i);\n this.lastNeed = 3 - n;\n this.lastTotal = 3;\n if (n === 1) {\n this.lastChar[0] = buf[buf.length - 1];\n } else {\n this.lastChar[0] = buf[buf.length - 2];\n this.lastChar[1] = buf[buf.length - 1];\n }\n return buf.toString('base64', i, buf.length - n);\n}\n\nfunction base64End(buf) {\n var r = buf && buf.length ? this.write(buf) : '';\n if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed);\n return r;\n}\n\n// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex)\nfunction simpleWrite(buf) {\n return buf.toString(this.encoding);\n}\n\nfunction simpleEnd(buf) {\n return buf && buf.length ? this.write(buf) : '';\n}","(function (module, exports) {\n 'use strict';\n\n // Utils\n function assert (val, msg) {\n if (!val) throw new Error(msg || 'Assertion failed');\n }\n\n // Could use `inherits` module, but don't want to move from single file\n // architecture yet.\n function inherits (ctor, superCtor) {\n ctor.super_ = superCtor;\n var TempCtor = function () {};\n TempCtor.prototype = superCtor.prototype;\n ctor.prototype = new TempCtor();\n ctor.prototype.constructor = ctor;\n }\n\n // BN\n\n function BN (number, base, endian) {\n if (BN.isBN(number)) {\n return number;\n }\n\n this.negative = 0;\n this.words = null;\n this.length = 0;\n\n // Reduction context\n this.red = null;\n\n if (number !== null) {\n if (base === 'le' || base === 'be') {\n endian = base;\n base = 10;\n }\n\n this._init(number || 0, base || 10, endian || 'be');\n }\n }\n if (typeof module === 'object') {\n module.exports = BN;\n } else {\n exports.BN = BN;\n }\n\n BN.BN = BN;\n BN.wordSize = 26;\n\n var Buffer;\n try {\n Buffer = require('buffer').Buffer;\n } catch (e) {\n }\n\n BN.isBN = function isBN (num) {\n if (num instanceof BN) {\n return true;\n }\n\n return num !== null && typeof num === 'object' &&\n num.constructor.wordSize === BN.wordSize && Array.isArray(num.words);\n };\n\n BN.max = function max (left, right) {\n if (left.cmp(right) > 0) return left;\n return right;\n };\n\n BN.min = function min (left, right) {\n if (left.cmp(right) < 0) return left;\n return right;\n };\n\n BN.prototype._init = function init (number, base, endian) {\n if (typeof number === 'number') {\n return this._initNumber(number, base, endian);\n }\n\n if (typeof number === 'object') {\n return this._initArray(number, base, endian);\n }\n\n if (base === 'hex') {\n base = 16;\n }\n assert(base === (base | 0) && base >= 2 && base <= 36);\n\n number = number.toString().replace(/\\s+/g, '');\n var start = 0;\n if (number[0] === '-') {\n start++;\n }\n\n if (base === 16) {\n this._parseHex(number, start);\n } else {\n this._parseBase(number, base, start);\n }\n\n if (number[0] === '-') {\n this.negative = 1;\n }\n\n this.strip();\n\n if (endian !== 'le') return;\n\n this._initArray(this.toArray(), base, endian);\n };\n\n BN.prototype._initNumber = function _initNumber (number, base, endian) {\n if (number < 0) {\n this.negative = 1;\n number = -number;\n }\n if (number < 0x4000000) {\n this.words = [ number & 0x3ffffff ];\n this.length = 1;\n } else if (number < 0x10000000000000) {\n this.words = [\n number & 0x3ffffff,\n (number / 0x4000000) & 0x3ffffff\n ];\n this.length = 2;\n } else {\n assert(number < 0x20000000000000); // 2 ^ 53 (unsafe)\n this.words = [\n number & 0x3ffffff,\n (number / 0x4000000) & 0x3ffffff,\n 1\n ];\n this.length = 3;\n }\n\n if (endian !== 'le') return;\n\n // Reverse the bytes\n this._initArray(this.toArray(), base, endian);\n };\n\n BN.prototype._initArray = function _initArray (number, base, endian) {\n // Perhaps a Uint8Array\n assert(typeof number.length === 'number');\n if (number.length <= 0) {\n this.words = [ 0 ];\n this.length = 1;\n return this;\n }\n\n this.length = Math.ceil(number.length / 3);\n this.words = new Array(this.length);\n for (var i = 0; i < this.length; i++) {\n this.words[i] = 0;\n }\n\n var j, w;\n var off = 0;\n if (endian === 'be') {\n for (i = number.length - 1, j = 0; i >= 0; i -= 3) {\n w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16);\n this.words[j] |= (w << off) & 0x3ffffff;\n this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;\n off += 24;\n if (off >= 26) {\n off -= 26;\n j++;\n }\n }\n } else if (endian === 'le') {\n for (i = 0, j = 0; i < number.length; i += 3) {\n w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16);\n this.words[j] |= (w << off) & 0x3ffffff;\n this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;\n off += 24;\n if (off >= 26) {\n off -= 26;\n j++;\n }\n }\n }\n return this.strip();\n };\n\n function parseHex (str, start, end) {\n var r = 0;\n var len = Math.min(str.length, end);\n for (var i = start; i < len; i++) {\n var c = str.charCodeAt(i) - 48;\n\n r <<= 4;\n\n // 'a' - 'f'\n if (c >= 49 && c <= 54) {\n r |= c - 49 + 0xa;\n\n // 'A' - 'F'\n } else if (c >= 17 && c <= 22) {\n r |= c - 17 + 0xa;\n\n // '0' - '9'\n } else {\n r |= c & 0xf;\n }\n }\n return r;\n }\n\n BN.prototype._parseHex = function _parseHex (number, start) {\n // Create possibly bigger array to ensure that it fits the number\n this.length = Math.ceil((number.length - start) / 6);\n this.words = new Array(this.length);\n for (var i = 0; i < this.length; i++) {\n this.words[i] = 0;\n }\n\n var j, w;\n // Scan 24-bit chunks and add them to the number\n var off = 0;\n for (i = number.length - 6, j = 0; i >= start; i -= 6) {\n w = parseHex(number, i, i + 6);\n this.words[j] |= (w << off) & 0x3ffffff;\n // NOTE: `0x3fffff` is intentional here, 26bits max shift + 24bit hex limb\n this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;\n off += 24;\n if (off >= 26) {\n off -= 26;\n j++;\n }\n }\n if (i + 6 !== start) {\n w = parseHex(number, start, i + 6);\n this.words[j] |= (w << off) & 0x3ffffff;\n this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;\n }\n this.strip();\n };\n\n function parseBase (str, start, end, mul) {\n var r = 0;\n var len = Math.min(str.length, end);\n for (var i = start; i < len; i++) {\n var c = str.charCodeAt(i) - 48;\n\n r *= mul;\n\n // 'a'\n if (c >= 49) {\n r += c - 49 + 0xa;\n\n // 'A'\n } else if (c >= 17) {\n r += c - 17 + 0xa;\n\n // '0' - '9'\n } else {\n r += c;\n }\n }\n return r;\n }\n\n BN.prototype._parseBase = function _parseBase (number, base, start) {\n // Initialize as zero\n this.words = [ 0 ];\n this.length = 1;\n\n // Find length of limb in base\n for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) {\n limbLen++;\n }\n limbLen--;\n limbPow = (limbPow / base) | 0;\n\n var total = number.length - start;\n var mod = total % limbLen;\n var end = Math.min(total, total - mod) + start;\n\n var word = 0;\n for (var i = start; i < end; i += limbLen) {\n word = parseBase(number, i, i + limbLen, base);\n\n this.imuln(limbPow);\n if (this.words[0] + word < 0x4000000) {\n this.words[0] += word;\n } else {\n this._iaddn(word);\n }\n }\n\n if (mod !== 0) {\n var pow = 1;\n word = parseBase(number, i, number.length, base);\n\n for (i = 0; i < mod; i++) {\n pow *= base;\n }\n\n this.imuln(pow);\n if (this.words[0] + word < 0x4000000) {\n this.words[0] += word;\n } else {\n this._iaddn(word);\n }\n }\n };\n\n BN.prototype.copy = function copy (dest) {\n dest.words = new Array(this.length);\n for (var i = 0; i < this.length; i++) {\n dest.words[i] = this.words[i];\n }\n dest.length = this.length;\n dest.negative = this.negative;\n dest.red = this.red;\n };\n\n BN.prototype.clone = function clone () {\n var r = new BN(null);\n this.copy(r);\n return r;\n };\n\n BN.prototype._expand = function _expand (size) {\n while (this.length < size) {\n this.words[this.length++] = 0;\n }\n return this;\n };\n\n // Remove leading `0` from `this`\n BN.prototype.strip = function strip () {\n while (this.length > 1 && this.words[this.length - 1] === 0) {\n this.length--;\n }\n return this._normSign();\n };\n\n BN.prototype._normSign = function _normSign () {\n // -0 = 0\n if (this.length === 1 && this.words[0] === 0) {\n this.negative = 0;\n }\n return this;\n };\n\n BN.prototype.inspect = function inspect () {\n return (this.red ? '';\n };\n\n /*\n\n var zeros = [];\n var groupSizes = [];\n var groupBases = [];\n\n var s = '';\n var i = -1;\n while (++i < BN.wordSize) {\n zeros[i] = s;\n s += '0';\n }\n groupSizes[0] = 0;\n groupSizes[1] = 0;\n groupBases[0] = 0;\n groupBases[1] = 0;\n var base = 2 - 1;\n while (++base < 36 + 1) {\n var groupSize = 0;\n var groupBase = 1;\n while (groupBase < (1 << BN.wordSize) / base) {\n groupBase *= base;\n groupSize += 1;\n }\n groupSizes[base] = groupSize;\n groupBases[base] = groupBase;\n }\n\n */\n\n var zeros = [\n '',\n '0',\n '00',\n '000',\n '0000',\n '00000',\n '000000',\n '0000000',\n '00000000',\n '000000000',\n '0000000000',\n '00000000000',\n '000000000000',\n '0000000000000',\n '00000000000000',\n '000000000000000',\n '0000000000000000',\n '00000000000000000',\n '000000000000000000',\n '0000000000000000000',\n '00000000000000000000',\n '000000000000000000000',\n '0000000000000000000000',\n '00000000000000000000000',\n '000000000000000000000000',\n '0000000000000000000000000'\n ];\n\n var groupSizes = [\n 0, 0,\n 25, 16, 12, 11, 10, 9, 8,\n 8, 7, 7, 7, 7, 6, 6,\n 6, 6, 6, 6, 6, 5, 5,\n 5, 5, 5, 5, 5, 5, 5,\n 5, 5, 5, 5, 5, 5, 5\n ];\n\n var groupBases = [\n 0, 0,\n 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216,\n 43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625,\n 16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632,\n 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149,\n 24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176\n ];\n\n BN.prototype.toString = function toString (base, padding) {\n base = base || 10;\n padding = padding | 0 || 1;\n\n var out;\n if (base === 16 || base === 'hex') {\n out = '';\n var off = 0;\n var carry = 0;\n for (var i = 0; i < this.length; i++) {\n var w = this.words[i];\n var word = (((w << off) | carry) & 0xffffff).toString(16);\n carry = (w >>> (24 - off)) & 0xffffff;\n if (carry !== 0 || i !== this.length - 1) {\n out = zeros[6 - word.length] + word + out;\n } else {\n out = word + out;\n }\n off += 2;\n if (off >= 26) {\n off -= 26;\n i--;\n }\n }\n if (carry !== 0) {\n out = carry.toString(16) + out;\n }\n while (out.length % padding !== 0) {\n out = '0' + out;\n }\n if (this.negative !== 0) {\n out = '-' + out;\n }\n return out;\n }\n\n if (base === (base | 0) && base >= 2 && base <= 36) {\n // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base));\n var groupSize = groupSizes[base];\n // var groupBase = Math.pow(base, groupSize);\n var groupBase = groupBases[base];\n out = '';\n var c = this.clone();\n c.negative = 0;\n while (!c.isZero()) {\n var r = c.modn(groupBase).toString(base);\n c = c.idivn(groupBase);\n\n if (!c.isZero()) {\n out = zeros[groupSize - r.length] + r + out;\n } else {\n out = r + out;\n }\n }\n if (this.isZero()) {\n out = '0' + out;\n }\n while (out.length % padding !== 0) {\n out = '0' + out;\n }\n if (this.negative !== 0) {\n out = '-' + out;\n }\n return out;\n }\n\n assert(false, 'Base should be between 2 and 36');\n };\n\n BN.prototype.toNumber = function toNumber () {\n var ret = this.words[0];\n if (this.length === 2) {\n ret += this.words[1] * 0x4000000;\n } else if (this.length === 3 && this.words[2] === 0x01) {\n // NOTE: at this stage it is known that the top bit is set\n ret += 0x10000000000000 + (this.words[1] * 0x4000000);\n } else if (this.length > 2) {\n assert(false, 'Number can only safely store up to 53 bits');\n }\n return (this.negative !== 0) ? -ret : ret;\n };\n\n BN.prototype.toJSON = function toJSON () {\n return this.toString(16);\n };\n\n BN.prototype.toBuffer = function toBuffer (endian, length) {\n assert(typeof Buffer !== 'undefined');\n return this.toArrayLike(Buffer, endian, length);\n };\n\n BN.prototype.toArray = function toArray (endian, length) {\n return this.toArrayLike(Array, endian, length);\n };\n\n BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) {\n var byteLength = this.byteLength();\n var reqLength = length || Math.max(1, byteLength);\n assert(byteLength <= reqLength, 'byte array longer than desired length');\n assert(reqLength > 0, 'Requested array length <= 0');\n\n this.strip();\n var littleEndian = endian === 'le';\n var res = new ArrayType(reqLength);\n\n var b, i;\n var q = this.clone();\n if (!littleEndian) {\n // Assume big-endian\n for (i = 0; i < reqLength - byteLength; i++) {\n res[i] = 0;\n }\n\n for (i = 0; !q.isZero(); i++) {\n b = q.andln(0xff);\n q.iushrn(8);\n\n res[reqLength - i - 1] = b;\n }\n } else {\n for (i = 0; !q.isZero(); i++) {\n b = q.andln(0xff);\n q.iushrn(8);\n\n res[i] = b;\n }\n\n for (; i < reqLength; i++) {\n res[i] = 0;\n }\n }\n\n return res;\n };\n\n if (Math.clz32) {\n BN.prototype._countBits = function _countBits (w) {\n return 32 - Math.clz32(w);\n };\n } else {\n BN.prototype._countBits = function _countBits (w) {\n var t = w;\n var r = 0;\n if (t >= 0x1000) {\n r += 13;\n t >>>= 13;\n }\n if (t >= 0x40) {\n r += 7;\n t >>>= 7;\n }\n if (t >= 0x8) {\n r += 4;\n t >>>= 4;\n }\n if (t >= 0x02) {\n r += 2;\n t >>>= 2;\n }\n return r + t;\n };\n }\n\n BN.prototype._zeroBits = function _zeroBits (w) {\n // Short-cut\n if (w === 0) return 26;\n\n var t = w;\n var r = 0;\n if ((t & 0x1fff) === 0) {\n r += 13;\n t >>>= 13;\n }\n if ((t & 0x7f) === 0) {\n r += 7;\n t >>>= 7;\n }\n if ((t & 0xf) === 0) {\n r += 4;\n t >>>= 4;\n }\n if ((t & 0x3) === 0) {\n r += 2;\n t >>>= 2;\n }\n if ((t & 0x1) === 0) {\n r++;\n }\n return r;\n };\n\n // Return number of used bits in a BN\n BN.prototype.bitLength = function bitLength () {\n var w = this.words[this.length - 1];\n var hi = this._countBits(w);\n return (this.length - 1) * 26 + hi;\n };\n\n function toBitArray (num) {\n var w = new Array(num.bitLength());\n\n for (var bit = 0; bit < w.length; bit++) {\n var off = (bit / 26) | 0;\n var wbit = bit % 26;\n\n w[bit] = (num.words[off] & (1 << wbit)) >>> wbit;\n }\n\n return w;\n }\n\n // Number of trailing zero bits\n BN.prototype.zeroBits = function zeroBits () {\n if (this.isZero()) return 0;\n\n var r = 0;\n for (var i = 0; i < this.length; i++) {\n var b = this._zeroBits(this.words[i]);\n r += b;\n if (b !== 26) break;\n }\n return r;\n };\n\n BN.prototype.byteLength = function byteLength () {\n return Math.ceil(this.bitLength() / 8);\n };\n\n BN.prototype.toTwos = function toTwos (width) {\n if (this.negative !== 0) {\n return this.abs().inotn(width).iaddn(1);\n }\n return this.clone();\n };\n\n BN.prototype.fromTwos = function fromTwos (width) {\n if (this.testn(width - 1)) {\n return this.notn(width).iaddn(1).ineg();\n }\n return this.clone();\n };\n\n BN.prototype.isNeg = function isNeg () {\n return this.negative !== 0;\n };\n\n // Return negative clone of `this`\n BN.prototype.neg = function neg () {\n return this.clone().ineg();\n };\n\n BN.prototype.ineg = function ineg () {\n if (!this.isZero()) {\n this.negative ^= 1;\n }\n\n return this;\n };\n\n // Or `num` with `this` in-place\n BN.prototype.iuor = function iuor (num) {\n while (this.length < num.length) {\n this.words[this.length++] = 0;\n }\n\n for (var i = 0; i < num.length; i++) {\n this.words[i] = this.words[i] | num.words[i];\n }\n\n return this.strip();\n };\n\n BN.prototype.ior = function ior (num) {\n assert((this.negative | num.negative) === 0);\n return this.iuor(num);\n };\n\n // Or `num` with `this`\n BN.prototype.or = function or (num) {\n if (this.length > num.length) return this.clone().ior(num);\n return num.clone().ior(this);\n };\n\n BN.prototype.uor = function uor (num) {\n if (this.length > num.length) return this.clone().iuor(num);\n return num.clone().iuor(this);\n };\n\n // And `num` with `this` in-place\n BN.prototype.iuand = function iuand (num) {\n // b = min-length(num, this)\n var b;\n if (this.length > num.length) {\n b = num;\n } else {\n b = this;\n }\n\n for (var i = 0; i < b.length; i++) {\n this.words[i] = this.words[i] & num.words[i];\n }\n\n this.length = b.length;\n\n return this.strip();\n };\n\n BN.prototype.iand = function iand (num) {\n assert((this.negative | num.negative) === 0);\n return this.iuand(num);\n };\n\n // And `num` with `this`\n BN.prototype.and = function and (num) {\n if (this.length > num.length) return this.clone().iand(num);\n return num.clone().iand(this);\n };\n\n BN.prototype.uand = function uand (num) {\n if (this.length > num.length) return this.clone().iuand(num);\n return num.clone().iuand(this);\n };\n\n // Xor `num` with `this` in-place\n BN.prototype.iuxor = function iuxor (num) {\n // a.length > b.length\n var a;\n var b;\n if (this.length > num.length) {\n a = this;\n b = num;\n } else {\n a = num;\n b = this;\n }\n\n for (var i = 0; i < b.length; i++) {\n this.words[i] = a.words[i] ^ b.words[i];\n }\n\n if (this !== a) {\n for (; i < a.length; i++) {\n this.words[i] = a.words[i];\n }\n }\n\n this.length = a.length;\n\n return this.strip();\n };\n\n BN.prototype.ixor = function ixor (num) {\n assert((this.negative | num.negative) === 0);\n return this.iuxor(num);\n };\n\n // Xor `num` with `this`\n BN.prototype.xor = function xor (num) {\n if (this.length > num.length) return this.clone().ixor(num);\n return num.clone().ixor(this);\n };\n\n BN.prototype.uxor = function uxor (num) {\n if (this.length > num.length) return this.clone().iuxor(num);\n return num.clone().iuxor(this);\n };\n\n // Not ``this`` with ``width`` bitwidth\n BN.prototype.inotn = function inotn (width) {\n assert(typeof width === 'number' && width >= 0);\n\n var bytesNeeded = Math.ceil(width / 26) | 0;\n var bitsLeft = width % 26;\n\n // Extend the buffer with leading zeroes\n this._expand(bytesNeeded);\n\n if (bitsLeft > 0) {\n bytesNeeded--;\n }\n\n // Handle complete words\n for (var i = 0; i < bytesNeeded; i++) {\n this.words[i] = ~this.words[i] & 0x3ffffff;\n }\n\n // Handle the residue\n if (bitsLeft > 0) {\n this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft));\n }\n\n // And remove leading zeroes\n return this.strip();\n };\n\n BN.prototype.notn = function notn (width) {\n return this.clone().inotn(width);\n };\n\n // Set `bit` of `this`\n BN.prototype.setn = function setn (bit, val) {\n assert(typeof bit === 'number' && bit >= 0);\n\n var off = (bit / 26) | 0;\n var wbit = bit % 26;\n\n this._expand(off + 1);\n\n if (val) {\n this.words[off] = this.words[off] | (1 << wbit);\n } else {\n this.words[off] = this.words[off] & ~(1 << wbit);\n }\n\n return this.strip();\n };\n\n // Add `num` to `this` in-place\n BN.prototype.iadd = function iadd (num) {\n var r;\n\n // negative + positive\n if (this.negative !== 0 && num.negative === 0) {\n this.negative = 0;\n r = this.isub(num);\n this.negative ^= 1;\n return this._normSign();\n\n // positive + negative\n } else if (this.negative === 0 && num.negative !== 0) {\n num.negative = 0;\n r = this.isub(num);\n num.negative = 1;\n return r._normSign();\n }\n\n // a.length > b.length\n var a, b;\n if (this.length > num.length) {\n a = this;\n b = num;\n } else {\n a = num;\n b = this;\n }\n\n var carry = 0;\n for (var i = 0; i < b.length; i++) {\n r = (a.words[i] | 0) + (b.words[i] | 0) + carry;\n this.words[i] = r & 0x3ffffff;\n carry = r >>> 26;\n }\n for (; carry !== 0 && i < a.length; i++) {\n r = (a.words[i] | 0) + carry;\n this.words[i] = r & 0x3ffffff;\n carry = r >>> 26;\n }\n\n this.length = a.length;\n if (carry !== 0) {\n this.words[this.length] = carry;\n this.length++;\n // Copy the rest of the words\n } else if (a !== this) {\n for (; i < a.length; i++) {\n this.words[i] = a.words[i];\n }\n }\n\n return this;\n };\n\n // Add `num` to `this`\n BN.prototype.add = function add (num) {\n var res;\n if (num.negative !== 0 && this.negative === 0) {\n num.negative = 0;\n res = this.sub(num);\n num.negative ^= 1;\n return res;\n } else if (num.negative === 0 && this.negative !== 0) {\n this.negative = 0;\n res = num.sub(this);\n this.negative = 1;\n return res;\n }\n\n if (this.length > num.length) return this.clone().iadd(num);\n\n return num.clone().iadd(this);\n };\n\n // Subtract `num` from `this` in-place\n BN.prototype.isub = function isub (num) {\n // this - (-num) = this + num\n if (num.negative !== 0) {\n num.negative = 0;\n var r = this.iadd(num);\n num.negative = 1;\n return r._normSign();\n\n // -this - num = -(this + num)\n } else if (this.negative !== 0) {\n this.negative = 0;\n this.iadd(num);\n this.negative = 1;\n return this._normSign();\n }\n\n // At this point both numbers are positive\n var cmp = this.cmp(num);\n\n // Optimization - zeroify\n if (cmp === 0) {\n this.negative = 0;\n this.length = 1;\n this.words[0] = 0;\n return this;\n }\n\n // a > b\n var a, b;\n if (cmp > 0) {\n a = this;\n b = num;\n } else {\n a = num;\n b = this;\n }\n\n var carry = 0;\n for (var i = 0; i < b.length; i++) {\n r = (a.words[i] | 0) - (b.words[i] | 0) + carry;\n carry = r >> 26;\n this.words[i] = r & 0x3ffffff;\n }\n for (; carry !== 0 && i < a.length; i++) {\n r = (a.words[i] | 0) + carry;\n carry = r >> 26;\n this.words[i] = r & 0x3ffffff;\n }\n\n // Copy rest of the words\n if (carry === 0 && i < a.length && a !== this) {\n for (; i < a.length; i++) {\n this.words[i] = a.words[i];\n }\n }\n\n this.length = Math.max(this.length, i);\n\n if (a !== this) {\n this.negative = 1;\n }\n\n return this.strip();\n };\n\n // Subtract `num` from `this`\n BN.prototype.sub = function sub (num) {\n return this.clone().isub(num);\n };\n\n function smallMulTo (self, num, out) {\n out.negative = num.negative ^ self.negative;\n var len = (self.length + num.length) | 0;\n out.length = len;\n len = (len - 1) | 0;\n\n // Peel one iteration (compiler can't do it, because of code complexity)\n var a = self.words[0] | 0;\n var b = num.words[0] | 0;\n var r = a * b;\n\n var lo = r & 0x3ffffff;\n var carry = (r / 0x4000000) | 0;\n out.words[0] = lo;\n\n for (var k = 1; k < len; k++) {\n // Sum all words with the same `i + j = k` and accumulate `ncarry`,\n // note that ncarry could be >= 0x3ffffff\n var ncarry = carry >>> 26;\n var rword = carry & 0x3ffffff;\n var maxJ = Math.min(k, num.length - 1);\n for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {\n var i = (k - j) | 0;\n a = self.words[i] | 0;\n b = num.words[j] | 0;\n r = a * b + rword;\n ncarry += (r / 0x4000000) | 0;\n rword = r & 0x3ffffff;\n }\n out.words[k] = rword | 0;\n carry = ncarry | 0;\n }\n if (carry !== 0) {\n out.words[k] = carry | 0;\n } else {\n out.length--;\n }\n\n return out.strip();\n }\n\n // TODO(indutny): it may be reasonable to omit it for users who don't need\n // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit\n // multiplication (like elliptic secp256k1).\n var comb10MulTo = function comb10MulTo (self, num, out) {\n var a = self.words;\n var b = num.words;\n var o = out.words;\n var c = 0;\n var lo;\n var mid;\n var hi;\n var a0 = a[0] | 0;\n var al0 = a0 & 0x1fff;\n var ah0 = a0 >>> 13;\n var a1 = a[1] | 0;\n var al1 = a1 & 0x1fff;\n var ah1 = a1 >>> 13;\n var a2 = a[2] | 0;\n var al2 = a2 & 0x1fff;\n var ah2 = a2 >>> 13;\n var a3 = a[3] | 0;\n var al3 = a3 & 0x1fff;\n var ah3 = a3 >>> 13;\n var a4 = a[4] | 0;\n var al4 = a4 & 0x1fff;\n var ah4 = a4 >>> 13;\n var a5 = a[5] | 0;\n var al5 = a5 & 0x1fff;\n var ah5 = a5 >>> 13;\n var a6 = a[6] | 0;\n var al6 = a6 & 0x1fff;\n var ah6 = a6 >>> 13;\n var a7 = a[7] | 0;\n var al7 = a7 & 0x1fff;\n var ah7 = a7 >>> 13;\n var a8 = a[8] | 0;\n var al8 = a8 & 0x1fff;\n var ah8 = a8 >>> 13;\n var a9 = a[9] | 0;\n var al9 = a9 & 0x1fff;\n var ah9 = a9 >>> 13;\n var b0 = b[0] | 0;\n var bl0 = b0 & 0x1fff;\n var bh0 = b0 >>> 13;\n var b1 = b[1] | 0;\n var bl1 = b1 & 0x1fff;\n var bh1 = b1 >>> 13;\n var b2 = b[2] | 0;\n var bl2 = b2 & 0x1fff;\n var bh2 = b2 >>> 13;\n var b3 = b[3] | 0;\n var bl3 = b3 & 0x1fff;\n var bh3 = b3 >>> 13;\n var b4 = b[4] | 0;\n var bl4 = b4 & 0x1fff;\n var bh4 = b4 >>> 13;\n var b5 = b[5] | 0;\n var bl5 = b5 & 0x1fff;\n var bh5 = b5 >>> 13;\n var b6 = b[6] | 0;\n var bl6 = b6 & 0x1fff;\n var bh6 = b6 >>> 13;\n var b7 = b[7] | 0;\n var bl7 = b7 & 0x1fff;\n var bh7 = b7 >>> 13;\n var b8 = b[8] | 0;\n var bl8 = b8 & 0x1fff;\n var bh8 = b8 >>> 13;\n var b9 = b[9] | 0;\n var bl9 = b9 & 0x1fff;\n var bh9 = b9 >>> 13;\n\n out.negative = self.negative ^ num.negative;\n out.length = 19;\n /* k = 0 */\n lo = Math.imul(al0, bl0);\n mid = Math.imul(al0, bh0);\n mid = (mid + Math.imul(ah0, bl0)) | 0;\n hi = Math.imul(ah0, bh0);\n var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0;\n w0 &= 0x3ffffff;\n /* k = 1 */\n lo = Math.imul(al1, bl0);\n mid = Math.imul(al1, bh0);\n mid = (mid + Math.imul(ah1, bl0)) | 0;\n hi = Math.imul(ah1, bh0);\n lo = (lo + Math.imul(al0, bl1)) | 0;\n mid = (mid + Math.imul(al0, bh1)) | 0;\n mid = (mid + Math.imul(ah0, bl1)) | 0;\n hi = (hi + Math.imul(ah0, bh1)) | 0;\n var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0;\n w1 &= 0x3ffffff;\n /* k = 2 */\n lo = Math.imul(al2, bl0);\n mid = Math.imul(al2, bh0);\n mid = (mid + Math.imul(ah2, bl0)) | 0;\n hi = Math.imul(ah2, bh0);\n lo = (lo + Math.imul(al1, bl1)) | 0;\n mid = (mid + Math.imul(al1, bh1)) | 0;\n mid = (mid + Math.imul(ah1, bl1)) | 0;\n hi = (hi + Math.imul(ah1, bh1)) | 0;\n lo = (lo + Math.imul(al0, bl2)) | 0;\n mid = (mid + Math.imul(al0, bh2)) | 0;\n mid = (mid + Math.imul(ah0, bl2)) | 0;\n hi = (hi + Math.imul(ah0, bh2)) | 0;\n var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0;\n w2 &= 0x3ffffff;\n /* k = 3 */\n lo = Math.imul(al3, bl0);\n mid = Math.imul(al3, bh0);\n mid = (mid + Math.imul(ah3, bl0)) | 0;\n hi = Math.imul(ah3, bh0);\n lo = (lo + Math.imul(al2, bl1)) | 0;\n mid = (mid + Math.imul(al2, bh1)) | 0;\n mid = (mid + Math.imul(ah2, bl1)) | 0;\n hi = (hi + Math.imul(ah2, bh1)) | 0;\n lo = (lo + Math.imul(al1, bl2)) | 0;\n mid = (mid + Math.imul(al1, bh2)) | 0;\n mid = (mid + Math.imul(ah1, bl2)) | 0;\n hi = (hi + Math.imul(ah1, bh2)) | 0;\n lo = (lo + Math.imul(al0, bl3)) | 0;\n mid = (mid + Math.imul(al0, bh3)) | 0;\n mid = (mid + Math.imul(ah0, bl3)) | 0;\n hi = (hi + Math.imul(ah0, bh3)) | 0;\n var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0;\n w3 &= 0x3ffffff;\n /* k = 4 */\n lo = Math.imul(al4, bl0);\n mid = Math.imul(al4, bh0);\n mid = (mid + Math.imul(ah4, bl0)) | 0;\n hi = Math.imul(ah4, bh0);\n lo = (lo + Math.imul(al3, bl1)) | 0;\n mid = (mid + Math.imul(al3, bh1)) | 0;\n mid = (mid + Math.imul(ah3, bl1)) | 0;\n hi = (hi + Math.imul(ah3, bh1)) | 0;\n lo = (lo + Math.imul(al2, bl2)) | 0;\n mid = (mid + Math.imul(al2, bh2)) | 0;\n mid = (mid + Math.imul(ah2, bl2)) | 0;\n hi = (hi + Math.imul(ah2, bh2)) | 0;\n lo = (lo + Math.imul(al1, bl3)) | 0;\n mid = (mid + Math.imul(al1, bh3)) | 0;\n mid = (mid + Math.imul(ah1, bl3)) | 0;\n hi = (hi + Math.imul(ah1, bh3)) | 0;\n lo = (lo + Math.imul(al0, bl4)) | 0;\n mid = (mid + Math.imul(al0, bh4)) | 0;\n mid = (mid + Math.imul(ah0, bl4)) | 0;\n hi = (hi + Math.imul(ah0, bh4)) | 0;\n var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0;\n w4 &= 0x3ffffff;\n /* k = 5 */\n lo = Math.imul(al5, bl0);\n mid = Math.imul(al5, bh0);\n mid = (mid + Math.imul(ah5, bl0)) | 0;\n hi = Math.imul(ah5, bh0);\n lo = (lo + Math.imul(al4, bl1)) | 0;\n mid = (mid + Math.imul(al4, bh1)) | 0;\n mid = (mid + Math.imul(ah4, bl1)) | 0;\n hi = (hi + Math.imul(ah4, bh1)) | 0;\n lo = (lo + Math.imul(al3, bl2)) | 0;\n mid = (mid + Math.imul(al3, bh2)) | 0;\n mid = (mid + Math.imul(ah3, bl2)) | 0;\n hi = (hi + Math.imul(ah3, bh2)) | 0;\n lo = (lo + Math.imul(al2, bl3)) | 0;\n mid = (mid + Math.imul(al2, bh3)) | 0;\n mid = (mid + Math.imul(ah2, bl3)) | 0;\n hi = (hi + Math.imul(ah2, bh3)) | 0;\n lo = (lo + Math.imul(al1, bl4)) | 0;\n mid = (mid + Math.imul(al1, bh4)) | 0;\n mid = (mid + Math.imul(ah1, bl4)) | 0;\n hi = (hi + Math.imul(ah1, bh4)) | 0;\n lo = (lo + Math.imul(al0, bl5)) | 0;\n mid = (mid + Math.imul(al0, bh5)) | 0;\n mid = (mid + Math.imul(ah0, bl5)) | 0;\n hi = (hi + Math.imul(ah0, bh5)) | 0;\n var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0;\n w5 &= 0x3ffffff;\n /* k = 6 */\n lo = Math.imul(al6, bl0);\n mid = Math.imul(al6, bh0);\n mid = (mid + Math.imul(ah6, bl0)) | 0;\n hi = Math.imul(ah6, bh0);\n lo = (lo + Math.imul(al5, bl1)) | 0;\n mid = (mid + Math.imul(al5, bh1)) | 0;\n mid = (mid + Math.imul(ah5, bl1)) | 0;\n hi = (hi + Math.imul(ah5, bh1)) | 0;\n lo = (lo + Math.imul(al4, bl2)) | 0;\n mid = (mid + Math.imul(al4, bh2)) | 0;\n mid = (mid + Math.imul(ah4, bl2)) | 0;\n hi = (hi + Math.imul(ah4, bh2)) | 0;\n lo = (lo + Math.imul(al3, bl3)) | 0;\n mid = (mid + Math.imul(al3, bh3)) | 0;\n mid = (mid + Math.imul(ah3, bl3)) | 0;\n hi = (hi + Math.imul(ah3, bh3)) | 0;\n lo = (lo + Math.imul(al2, bl4)) | 0;\n mid = (mid + Math.imul(al2, bh4)) | 0;\n mid = (mid + Math.imul(ah2, bl4)) | 0;\n hi = (hi + Math.imul(ah2, bh4)) | 0;\n lo = (lo + Math.imul(al1, bl5)) | 0;\n mid = (mid + Math.imul(al1, bh5)) | 0;\n mid = (mid + Math.imul(ah1, bl5)) | 0;\n hi = (hi + Math.imul(ah1, bh5)) | 0;\n lo = (lo + Math.imul(al0, bl6)) | 0;\n mid = (mid + Math.imul(al0, bh6)) | 0;\n mid = (mid + Math.imul(ah0, bl6)) | 0;\n hi = (hi + Math.imul(ah0, bh6)) | 0;\n var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0;\n w6 &= 0x3ffffff;\n /* k = 7 */\n lo = Math.imul(al7, bl0);\n mid = Math.imul(al7, bh0);\n mid = (mid + Math.imul(ah7, bl0)) | 0;\n hi = Math.imul(ah7, bh0);\n lo = (lo + Math.imul(al6, bl1)) | 0;\n mid = (mid + Math.imul(al6, bh1)) | 0;\n mid = (mid + Math.imul(ah6, bl1)) | 0;\n hi = (hi + Math.imul(ah6, bh1)) | 0;\n lo = (lo + Math.imul(al5, bl2)) | 0;\n mid = (mid + Math.imul(al5, bh2)) | 0;\n mid = (mid + Math.imul(ah5, bl2)) | 0;\n hi = (hi + Math.imul(ah5, bh2)) | 0;\n lo = (lo + Math.imul(al4, bl3)) | 0;\n mid = (mid + Math.imul(al4, bh3)) | 0;\n mid = (mid + Math.imul(ah4, bl3)) | 0;\n hi = (hi + Math.imul(ah4, bh3)) | 0;\n lo = (lo + Math.imul(al3, bl4)) | 0;\n mid = (mid + Math.imul(al3, bh4)) | 0;\n mid = (mid + Math.imul(ah3, bl4)) | 0;\n hi = (hi + Math.imul(ah3, bh4)) | 0;\n lo = (lo + Math.imul(al2, bl5)) | 0;\n mid = (mid + Math.imul(al2, bh5)) | 0;\n mid = (mid + Math.imul(ah2, bl5)) | 0;\n hi = (hi + Math.imul(ah2, bh5)) | 0;\n lo = (lo + Math.imul(al1, bl6)) | 0;\n mid = (mid + Math.imul(al1, bh6)) | 0;\n mid = (mid + Math.imul(ah1, bl6)) | 0;\n hi = (hi + Math.imul(ah1, bh6)) | 0;\n lo = (lo + Math.imul(al0, bl7)) | 0;\n mid = (mid + Math.imul(al0, bh7)) | 0;\n mid = (mid + Math.imul(ah0, bl7)) | 0;\n hi = (hi + Math.imul(ah0, bh7)) | 0;\n var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0;\n w7 &= 0x3ffffff;\n /* k = 8 */\n lo = Math.imul(al8, bl0);\n mid = Math.imul(al8, bh0);\n mid = (mid + Math.imul(ah8, bl0)) | 0;\n hi = Math.imul(ah8, bh0);\n lo = (lo + Math.imul(al7, bl1)) | 0;\n mid = (mid + Math.imul(al7, bh1)) | 0;\n mid = (mid + Math.imul(ah7, bl1)) | 0;\n hi = (hi + Math.imul(ah7, bh1)) | 0;\n lo = (lo + Math.imul(al6, bl2)) | 0;\n mid = (mid + Math.imul(al6, bh2)) | 0;\n mid = (mid + Math.imul(ah6, bl2)) | 0;\n hi = (hi + Math.imul(ah6, bh2)) | 0;\n lo = (lo + Math.imul(al5, bl3)) | 0;\n mid = (mid + Math.imul(al5, bh3)) | 0;\n mid = (mid + Math.imul(ah5, bl3)) | 0;\n hi = (hi + Math.imul(ah5, bh3)) | 0;\n lo = (lo + Math.imul(al4, bl4)) | 0;\n mid = (mid + Math.imul(al4, bh4)) | 0;\n mid = (mid + Math.imul(ah4, bl4)) | 0;\n hi = (hi + Math.imul(ah4, bh4)) | 0;\n lo = (lo + Math.imul(al3, bl5)) | 0;\n mid = (mid + Math.imul(al3, bh5)) | 0;\n mid = (mid + Math.imul(ah3, bl5)) | 0;\n hi = (hi + Math.imul(ah3, bh5)) | 0;\n lo = (lo + Math.imul(al2, bl6)) | 0;\n mid = (mid + Math.imul(al2, bh6)) | 0;\n mid = (mid + Math.imul(ah2, bl6)) | 0;\n hi = (hi + Math.imul(ah2, bh6)) | 0;\n lo = (lo + Math.imul(al1, bl7)) | 0;\n mid = (mid + Math.imul(al1, bh7)) | 0;\n mid = (mid + Math.imul(ah1, bl7)) | 0;\n hi = (hi + Math.imul(ah1, bh7)) | 0;\n lo = (lo + Math.imul(al0, bl8)) | 0;\n mid = (mid + Math.imul(al0, bh8)) | 0;\n mid = (mid + Math.imul(ah0, bl8)) | 0;\n hi = (hi + Math.imul(ah0, bh8)) | 0;\n var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0;\n w8 &= 0x3ffffff;\n /* k = 9 */\n lo = Math.imul(al9, bl0);\n mid = Math.imul(al9, bh0);\n mid = (mid + Math.imul(ah9, bl0)) | 0;\n hi = Math.imul(ah9, bh0);\n lo = (lo + Math.imul(al8, bl1)) | 0;\n mid = (mid + Math.imul(al8, bh1)) | 0;\n mid = (mid + Math.imul(ah8, bl1)) | 0;\n hi = (hi + Math.imul(ah8, bh1)) | 0;\n lo = (lo + Math.imul(al7, bl2)) | 0;\n mid = (mid + Math.imul(al7, bh2)) | 0;\n mid = (mid + Math.imul(ah7, bl2)) | 0;\n hi = (hi + Math.imul(ah7, bh2)) | 0;\n lo = (lo + Math.imul(al6, bl3)) | 0;\n mid = (mid + Math.imul(al6, bh3)) | 0;\n mid = (mid + Math.imul(ah6, bl3)) | 0;\n hi = (hi + Math.imul(ah6, bh3)) | 0;\n lo = (lo + Math.imul(al5, bl4)) | 0;\n mid = (mid + Math.imul(al5, bh4)) | 0;\n mid = (mid + Math.imul(ah5, bl4)) | 0;\n hi = (hi + Math.imul(ah5, bh4)) | 0;\n lo = (lo + Math.imul(al4, bl5)) | 0;\n mid = (mid + Math.imul(al4, bh5)) | 0;\n mid = (mid + Math.imul(ah4, bl5)) | 0;\n hi = (hi + Math.imul(ah4, bh5)) | 0;\n lo = (lo + Math.imul(al3, bl6)) | 0;\n mid = (mid + Math.imul(al3, bh6)) | 0;\n mid = (mid + Math.imul(ah3, bl6)) | 0;\n hi = (hi + Math.imul(ah3, bh6)) | 0;\n lo = (lo + Math.imul(al2, bl7)) | 0;\n mid = (mid + Math.imul(al2, bh7)) | 0;\n mid = (mid + Math.imul(ah2, bl7)) | 0;\n hi = (hi + Math.imul(ah2, bh7)) | 0;\n lo = (lo + Math.imul(al1, bl8)) | 0;\n mid = (mid + Math.imul(al1, bh8)) | 0;\n mid = (mid + Math.imul(ah1, bl8)) | 0;\n hi = (hi + Math.imul(ah1, bh8)) | 0;\n lo = (lo + Math.imul(al0, bl9)) | 0;\n mid = (mid + Math.imul(al0, bh9)) | 0;\n mid = (mid + Math.imul(ah0, bl9)) | 0;\n hi = (hi + Math.imul(ah0, bh9)) | 0;\n var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0;\n w9 &= 0x3ffffff;\n /* k = 10 */\n lo = Math.imul(al9, bl1);\n mid = Math.imul(al9, bh1);\n mid = (mid + Math.imul(ah9, bl1)) | 0;\n hi = Math.imul(ah9, bh1);\n lo = (lo + Math.imul(al8, bl2)) | 0;\n mid = (mid + Math.imul(al8, bh2)) | 0;\n mid = (mid + Math.imul(ah8, bl2)) | 0;\n hi = (hi + Math.imul(ah8, bh2)) | 0;\n lo = (lo + Math.imul(al7, bl3)) | 0;\n mid = (mid + Math.imul(al7, bh3)) | 0;\n mid = (mid + Math.imul(ah7, bl3)) | 0;\n hi = (hi + Math.imul(ah7, bh3)) | 0;\n lo = (lo + Math.imul(al6, bl4)) | 0;\n mid = (mid + Math.imul(al6, bh4)) | 0;\n mid = (mid + Math.imul(ah6, bl4)) | 0;\n hi = (hi + Math.imul(ah6, bh4)) | 0;\n lo = (lo + Math.imul(al5, bl5)) | 0;\n mid = (mid + Math.imul(al5, bh5)) | 0;\n mid = (mid + Math.imul(ah5, bl5)) | 0;\n hi = (hi + Math.imul(ah5, bh5)) | 0;\n lo = (lo + Math.imul(al4, bl6)) | 0;\n mid = (mid + Math.imul(al4, bh6)) | 0;\n mid = (mid + Math.imul(ah4, bl6)) | 0;\n hi = (hi + Math.imul(ah4, bh6)) | 0;\n lo = (lo + Math.imul(al3, bl7)) | 0;\n mid = (mid + Math.imul(al3, bh7)) | 0;\n mid = (mid + Math.imul(ah3, bl7)) | 0;\n hi = (hi + Math.imul(ah3, bh7)) | 0;\n lo = (lo + Math.imul(al2, bl8)) | 0;\n mid = (mid + Math.imul(al2, bh8)) | 0;\n mid = (mid + Math.imul(ah2, bl8)) | 0;\n hi = (hi + Math.imul(ah2, bh8)) | 0;\n lo = (lo + Math.imul(al1, bl9)) | 0;\n mid = (mid + Math.imul(al1, bh9)) | 0;\n mid = (mid + Math.imul(ah1, bl9)) | 0;\n hi = (hi + Math.imul(ah1, bh9)) | 0;\n var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0;\n w10 &= 0x3ffffff;\n /* k = 11 */\n lo = Math.imul(al9, bl2);\n mid = Math.imul(al9, bh2);\n mid = (mid + Math.imul(ah9, bl2)) | 0;\n hi = Math.imul(ah9, bh2);\n lo = (lo + Math.imul(al8, bl3)) | 0;\n mid = (mid + Math.imul(al8, bh3)) | 0;\n mid = (mid + Math.imul(ah8, bl3)) | 0;\n hi = (hi + Math.imul(ah8, bh3)) | 0;\n lo = (lo + Math.imul(al7, bl4)) | 0;\n mid = (mid + Math.imul(al7, bh4)) | 0;\n mid = (mid + Math.imul(ah7, bl4)) | 0;\n hi = (hi + Math.imul(ah7, bh4)) | 0;\n lo = (lo + Math.imul(al6, bl5)) | 0;\n mid = (mid + Math.imul(al6, bh5)) | 0;\n mid = (mid + Math.imul(ah6, bl5)) | 0;\n hi = (hi + Math.imul(ah6, bh5)) | 0;\n lo = (lo + Math.imul(al5, bl6)) | 0;\n mid = (mid + Math.imul(al5, bh6)) | 0;\n mid = (mid + Math.imul(ah5, bl6)) | 0;\n hi = (hi + Math.imul(ah5, bh6)) | 0;\n lo = (lo + Math.imul(al4, bl7)) | 0;\n mid = (mid + Math.imul(al4, bh7)) | 0;\n mid = (mid + Math.imul(ah4, bl7)) | 0;\n hi = (hi + Math.imul(ah4, bh7)) | 0;\n lo = (lo + Math.imul(al3, bl8)) | 0;\n mid = (mid + Math.imul(al3, bh8)) | 0;\n mid = (mid + Math.imul(ah3, bl8)) | 0;\n hi = (hi + Math.imul(ah3, bh8)) | 0;\n lo = (lo + Math.imul(al2, bl9)) | 0;\n mid = (mid + Math.imul(al2, bh9)) | 0;\n mid = (mid + Math.imul(ah2, bl9)) | 0;\n hi = (hi + Math.imul(ah2, bh9)) | 0;\n var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0;\n w11 &= 0x3ffffff;\n /* k = 12 */\n lo = Math.imul(al9, bl3);\n mid = Math.imul(al9, bh3);\n mid = (mid + Math.imul(ah9, bl3)) | 0;\n hi = Math.imul(ah9, bh3);\n lo = (lo + Math.imul(al8, bl4)) | 0;\n mid = (mid + Math.imul(al8, bh4)) | 0;\n mid = (mid + Math.imul(ah8, bl4)) | 0;\n hi = (hi + Math.imul(ah8, bh4)) | 0;\n lo = (lo + Math.imul(al7, bl5)) | 0;\n mid = (mid + Math.imul(al7, bh5)) | 0;\n mid = (mid + Math.imul(ah7, bl5)) | 0;\n hi = (hi + Math.imul(ah7, bh5)) | 0;\n lo = (lo + Math.imul(al6, bl6)) | 0;\n mid = (mid + Math.imul(al6, bh6)) | 0;\n mid = (mid + Math.imul(ah6, bl6)) | 0;\n hi = (hi + Math.imul(ah6, bh6)) | 0;\n lo = (lo + Math.imul(al5, bl7)) | 0;\n mid = (mid + Math.imul(al5, bh7)) | 0;\n mid = (mid + Math.imul(ah5, bl7)) | 0;\n hi = (hi + Math.imul(ah5, bh7)) | 0;\n lo = (lo + Math.imul(al4, bl8)) | 0;\n mid = (mid + Math.imul(al4, bh8)) | 0;\n mid = (mid + Math.imul(ah4, bl8)) | 0;\n hi = (hi + Math.imul(ah4, bh8)) | 0;\n lo = (lo + Math.imul(al3, bl9)) | 0;\n mid = (mid + Math.imul(al3, bh9)) | 0;\n mid = (mid + Math.imul(ah3, bl9)) | 0;\n hi = (hi + Math.imul(ah3, bh9)) | 0;\n var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0;\n w12 &= 0x3ffffff;\n /* k = 13 */\n lo = Math.imul(al9, bl4);\n mid = Math.imul(al9, bh4);\n mid = (mid + Math.imul(ah9, bl4)) | 0;\n hi = Math.imul(ah9, bh4);\n lo = (lo + Math.imul(al8, bl5)) | 0;\n mid = (mid + Math.imul(al8, bh5)) | 0;\n mid = (mid + Math.imul(ah8, bl5)) | 0;\n hi = (hi + Math.imul(ah8, bh5)) | 0;\n lo = (lo + Math.imul(al7, bl6)) | 0;\n mid = (mid + Math.imul(al7, bh6)) | 0;\n mid = (mid + Math.imul(ah7, bl6)) | 0;\n hi = (hi + Math.imul(ah7, bh6)) | 0;\n lo = (lo + Math.imul(al6, bl7)) | 0;\n mid = (mid + Math.imul(al6, bh7)) | 0;\n mid = (mid + Math.imul(ah6, bl7)) | 0;\n hi = (hi + Math.imul(ah6, bh7)) | 0;\n lo = (lo + Math.imul(al5, bl8)) | 0;\n mid = (mid + Math.imul(al5, bh8)) | 0;\n mid = (mid + Math.imul(ah5, bl8)) | 0;\n hi = (hi + Math.imul(ah5, bh8)) | 0;\n lo = (lo + Math.imul(al4, bl9)) | 0;\n mid = (mid + Math.imul(al4, bh9)) | 0;\n mid = (mid + Math.imul(ah4, bl9)) | 0;\n hi = (hi + Math.imul(ah4, bh9)) | 0;\n var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0;\n w13 &= 0x3ffffff;\n /* k = 14 */\n lo = Math.imul(al9, bl5);\n mid = Math.imul(al9, bh5);\n mid = (mid + Math.imul(ah9, bl5)) | 0;\n hi = Math.imul(ah9, bh5);\n lo = (lo + Math.imul(al8, bl6)) | 0;\n mid = (mid + Math.imul(al8, bh6)) | 0;\n mid = (mid + Math.imul(ah8, bl6)) | 0;\n hi = (hi + Math.imul(ah8, bh6)) | 0;\n lo = (lo + Math.imul(al7, bl7)) | 0;\n mid = (mid + Math.imul(al7, bh7)) | 0;\n mid = (mid + Math.imul(ah7, bl7)) | 0;\n hi = (hi + Math.imul(ah7, bh7)) | 0;\n lo = (lo + Math.imul(al6, bl8)) | 0;\n mid = (mid + Math.imul(al6, bh8)) | 0;\n mid = (mid + Math.imul(ah6, bl8)) | 0;\n hi = (hi + Math.imul(ah6, bh8)) | 0;\n lo = (lo + Math.imul(al5, bl9)) | 0;\n mid = (mid + Math.imul(al5, bh9)) | 0;\n mid = (mid + Math.imul(ah5, bl9)) | 0;\n hi = (hi + Math.imul(ah5, bh9)) | 0;\n var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0;\n w14 &= 0x3ffffff;\n /* k = 15 */\n lo = Math.imul(al9, bl6);\n mid = Math.imul(al9, bh6);\n mid = (mid + Math.imul(ah9, bl6)) | 0;\n hi = Math.imul(ah9, bh6);\n lo = (lo + Math.imul(al8, bl7)) | 0;\n mid = (mid + Math.imul(al8, bh7)) | 0;\n mid = (mid + Math.imul(ah8, bl7)) | 0;\n hi = (hi + Math.imul(ah8, bh7)) | 0;\n lo = (lo + Math.imul(al7, bl8)) | 0;\n mid = (mid + Math.imul(al7, bh8)) | 0;\n mid = (mid + Math.imul(ah7, bl8)) | 0;\n hi = (hi + Math.imul(ah7, bh8)) | 0;\n lo = (lo + Math.imul(al6, bl9)) | 0;\n mid = (mid + Math.imul(al6, bh9)) | 0;\n mid = (mid + Math.imul(ah6, bl9)) | 0;\n hi = (hi + Math.imul(ah6, bh9)) | 0;\n var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0;\n w15 &= 0x3ffffff;\n /* k = 16 */\n lo = Math.imul(al9, bl7);\n mid = Math.imul(al9, bh7);\n mid = (mid + Math.imul(ah9, bl7)) | 0;\n hi = Math.imul(ah9, bh7);\n lo = (lo + Math.imul(al8, bl8)) | 0;\n mid = (mid + Math.imul(al8, bh8)) | 0;\n mid = (mid + Math.imul(ah8, bl8)) | 0;\n hi = (hi + Math.imul(ah8, bh8)) | 0;\n lo = (lo + Math.imul(al7, bl9)) | 0;\n mid = (mid + Math.imul(al7, bh9)) | 0;\n mid = (mid + Math.imul(ah7, bl9)) | 0;\n hi = (hi + Math.imul(ah7, bh9)) | 0;\n var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0;\n w16 &= 0x3ffffff;\n /* k = 17 */\n lo = Math.imul(al9, bl8);\n mid = Math.imul(al9, bh8);\n mid = (mid + Math.imul(ah9, bl8)) | 0;\n hi = Math.imul(ah9, bh8);\n lo = (lo + Math.imul(al8, bl9)) | 0;\n mid = (mid + Math.imul(al8, bh9)) | 0;\n mid = (mid + Math.imul(ah8, bl9)) | 0;\n hi = (hi + Math.imul(ah8, bh9)) | 0;\n var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0;\n w17 &= 0x3ffffff;\n /* k = 18 */\n lo = Math.imul(al9, bl9);\n mid = Math.imul(al9, bh9);\n mid = (mid + Math.imul(ah9, bl9)) | 0;\n hi = Math.imul(ah9, bh9);\n var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0;\n w18 &= 0x3ffffff;\n o[0] = w0;\n o[1] = w1;\n o[2] = w2;\n o[3] = w3;\n o[4] = w4;\n o[5] = w5;\n o[6] = w6;\n o[7] = w7;\n o[8] = w8;\n o[9] = w9;\n o[10] = w10;\n o[11] = w11;\n o[12] = w12;\n o[13] = w13;\n o[14] = w14;\n o[15] = w15;\n o[16] = w16;\n o[17] = w17;\n o[18] = w18;\n if (c !== 0) {\n o[19] = c;\n out.length++;\n }\n return out;\n };\n\n // Polyfill comb\n if (!Math.imul) {\n comb10MulTo = smallMulTo;\n }\n\n function bigMulTo (self, num, out) {\n out.negative = num.negative ^ self.negative;\n out.length = self.length + num.length;\n\n var carry = 0;\n var hncarry = 0;\n for (var k = 0; k < out.length - 1; k++) {\n // Sum all words with the same `i + j = k` and accumulate `ncarry`,\n // note that ncarry could be >= 0x3ffffff\n var ncarry = hncarry;\n hncarry = 0;\n var rword = carry & 0x3ffffff;\n var maxJ = Math.min(k, num.length - 1);\n for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {\n var i = k - j;\n var a = self.words[i] | 0;\n var b = num.words[j] | 0;\n var r = a * b;\n\n var lo = r & 0x3ffffff;\n ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0;\n lo = (lo + rword) | 0;\n rword = lo & 0x3ffffff;\n ncarry = (ncarry + (lo >>> 26)) | 0;\n\n hncarry += ncarry >>> 26;\n ncarry &= 0x3ffffff;\n }\n out.words[k] = rword;\n carry = ncarry;\n ncarry = hncarry;\n }\n if (carry !== 0) {\n out.words[k] = carry;\n } else {\n out.length--;\n }\n\n return out.strip();\n }\n\n function jumboMulTo (self, num, out) {\n var fftm = new FFTM();\n return fftm.mulp(self, num, out);\n }\n\n BN.prototype.mulTo = function mulTo (num, out) {\n var res;\n var len = this.length + num.length;\n if (this.length === 10 && num.length === 10) {\n res = comb10MulTo(this, num, out);\n } else if (len < 63) {\n res = smallMulTo(this, num, out);\n } else if (len < 1024) {\n res = bigMulTo(this, num, out);\n } else {\n res = jumboMulTo(this, num, out);\n }\n\n return res;\n };\n\n // Cooley-Tukey algorithm for FFT\n // slightly revisited to rely on looping instead of recursion\n\n function FFTM (x, y) {\n this.x = x;\n this.y = y;\n }\n\n FFTM.prototype.makeRBT = function makeRBT (N) {\n var t = new Array(N);\n var l = BN.prototype._countBits(N) - 1;\n for (var i = 0; i < N; i++) {\n t[i] = this.revBin(i, l, N);\n }\n\n return t;\n };\n\n // Returns binary-reversed representation of `x`\n FFTM.prototype.revBin = function revBin (x, l, N) {\n if (x === 0 || x === N - 1) return x;\n\n var rb = 0;\n for (var i = 0; i < l; i++) {\n rb |= (x & 1) << (l - i - 1);\n x >>= 1;\n }\n\n return rb;\n };\n\n // Performs \"tweedling\" phase, therefore 'emulating'\n // behaviour of the recursive algorithm\n FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) {\n for (var i = 0; i < N; i++) {\n rtws[i] = rws[rbt[i]];\n itws[i] = iws[rbt[i]];\n }\n };\n\n FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) {\n this.permute(rbt, rws, iws, rtws, itws, N);\n\n for (var s = 1; s < N; s <<= 1) {\n var l = s << 1;\n\n var rtwdf = Math.cos(2 * Math.PI / l);\n var itwdf = Math.sin(2 * Math.PI / l);\n\n for (var p = 0; p < N; p += l) {\n var rtwdf_ = rtwdf;\n var itwdf_ = itwdf;\n\n for (var j = 0; j < s; j++) {\n var re = rtws[p + j];\n var ie = itws[p + j];\n\n var ro = rtws[p + j + s];\n var io = itws[p + j + s];\n\n var rx = rtwdf_ * ro - itwdf_ * io;\n\n io = rtwdf_ * io + itwdf_ * ro;\n ro = rx;\n\n rtws[p + j] = re + ro;\n itws[p + j] = ie + io;\n\n rtws[p + j + s] = re - ro;\n itws[p + j + s] = ie - io;\n\n /* jshint maxdepth : false */\n if (j !== l) {\n rx = rtwdf * rtwdf_ - itwdf * itwdf_;\n\n itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_;\n rtwdf_ = rx;\n }\n }\n }\n }\n };\n\n FFTM.prototype.guessLen13b = function guessLen13b (n, m) {\n var N = Math.max(m, n) | 1;\n var odd = N & 1;\n var i = 0;\n for (N = N / 2 | 0; N; N = N >>> 1) {\n i++;\n }\n\n return 1 << i + 1 + odd;\n };\n\n FFTM.prototype.conjugate = function conjugate (rws, iws, N) {\n if (N <= 1) return;\n\n for (var i = 0; i < N / 2; i++) {\n var t = rws[i];\n\n rws[i] = rws[N - i - 1];\n rws[N - i - 1] = t;\n\n t = iws[i];\n\n iws[i] = -iws[N - i - 1];\n iws[N - i - 1] = -t;\n }\n };\n\n FFTM.prototype.normalize13b = function normalize13b (ws, N) {\n var carry = 0;\n for (var i = 0; i < N / 2; i++) {\n var w = Math.round(ws[2 * i + 1] / N) * 0x2000 +\n Math.round(ws[2 * i] / N) +\n carry;\n\n ws[i] = w & 0x3ffffff;\n\n if (w < 0x4000000) {\n carry = 0;\n } else {\n carry = w / 0x4000000 | 0;\n }\n }\n\n return ws;\n };\n\n FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) {\n var carry = 0;\n for (var i = 0; i < len; i++) {\n carry = carry + (ws[i] | 0);\n\n rws[2 * i] = carry & 0x1fff; carry = carry >>> 13;\n rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13;\n }\n\n // Pad with zeroes\n for (i = 2 * len; i < N; ++i) {\n rws[i] = 0;\n }\n\n assert(carry === 0);\n assert((carry & ~0x1fff) === 0);\n };\n\n FFTM.prototype.stub = function stub (N) {\n var ph = new Array(N);\n for (var i = 0; i < N; i++) {\n ph[i] = 0;\n }\n\n return ph;\n };\n\n FFTM.prototype.mulp = function mulp (x, y, out) {\n var N = 2 * this.guessLen13b(x.length, y.length);\n\n var rbt = this.makeRBT(N);\n\n var _ = this.stub(N);\n\n var rws = new Array(N);\n var rwst = new Array(N);\n var iwst = new Array(N);\n\n var nrws = new Array(N);\n var nrwst = new Array(N);\n var niwst = new Array(N);\n\n var rmws = out.words;\n rmws.length = N;\n\n this.convert13b(x.words, x.length, rws, N);\n this.convert13b(y.words, y.length, nrws, N);\n\n this.transform(rws, _, rwst, iwst, N, rbt);\n this.transform(nrws, _, nrwst, niwst, N, rbt);\n\n for (var i = 0; i < N; i++) {\n var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i];\n iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i];\n rwst[i] = rx;\n }\n\n this.conjugate(rwst, iwst, N);\n this.transform(rwst, iwst, rmws, _, N, rbt);\n this.conjugate(rmws, _, N);\n this.normalize13b(rmws, N);\n\n out.negative = x.negative ^ y.negative;\n out.length = x.length + y.length;\n return out.strip();\n };\n\n // Multiply `this` by `num`\n BN.prototype.mul = function mul (num) {\n var out = new BN(null);\n out.words = new Array(this.length + num.length);\n return this.mulTo(num, out);\n };\n\n // Multiply employing FFT\n BN.prototype.mulf = function mulf (num) {\n var out = new BN(null);\n out.words = new Array(this.length + num.length);\n return jumboMulTo(this, num, out);\n };\n\n // In-place Multiplication\n BN.prototype.imul = function imul (num) {\n return this.clone().mulTo(num, this);\n };\n\n BN.prototype.imuln = function imuln (num) {\n assert(typeof num === 'number');\n assert(num < 0x4000000);\n\n // Carry\n var carry = 0;\n for (var i = 0; i < this.length; i++) {\n var w = (this.words[i] | 0) * num;\n var lo = (w & 0x3ffffff) + (carry & 0x3ffffff);\n carry >>= 26;\n carry += (w / 0x4000000) | 0;\n // NOTE: lo is 27bit maximum\n carry += lo >>> 26;\n this.words[i] = lo & 0x3ffffff;\n }\n\n if (carry !== 0) {\n this.words[i] = carry;\n this.length++;\n }\n\n return this;\n };\n\n BN.prototype.muln = function muln (num) {\n return this.clone().imuln(num);\n };\n\n // `this` * `this`\n BN.prototype.sqr = function sqr () {\n return this.mul(this);\n };\n\n // `this` * `this` in-place\n BN.prototype.isqr = function isqr () {\n return this.imul(this.clone());\n };\n\n // Math.pow(`this`, `num`)\n BN.prototype.pow = function pow (num) {\n var w = toBitArray(num);\n if (w.length === 0) return new BN(1);\n\n // Skip leading zeroes\n var res = this;\n for (var i = 0; i < w.length; i++, res = res.sqr()) {\n if (w[i] !== 0) break;\n }\n\n if (++i < w.length) {\n for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) {\n if (w[i] === 0) continue;\n\n res = res.mul(q);\n }\n }\n\n return res;\n };\n\n // Shift-left in-place\n BN.prototype.iushln = function iushln (bits) {\n assert(typeof bits === 'number' && bits >= 0);\n var r = bits % 26;\n var s = (bits - r) / 26;\n var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r);\n var i;\n\n if (r !== 0) {\n var carry = 0;\n\n for (i = 0; i < this.length; i++) {\n var newCarry = this.words[i] & carryMask;\n var c = ((this.words[i] | 0) - newCarry) << r;\n this.words[i] = c | carry;\n carry = newCarry >>> (26 - r);\n }\n\n if (carry) {\n this.words[i] = carry;\n this.length++;\n }\n }\n\n if (s !== 0) {\n for (i = this.length - 1; i >= 0; i--) {\n this.words[i + s] = this.words[i];\n }\n\n for (i = 0; i < s; i++) {\n this.words[i] = 0;\n }\n\n this.length += s;\n }\n\n return this.strip();\n };\n\n BN.prototype.ishln = function ishln (bits) {\n // TODO(indutny): implement me\n assert(this.negative === 0);\n return this.iushln(bits);\n };\n\n // Shift-right in-place\n // NOTE: `hint` is a lowest bit before trailing zeroes\n // NOTE: if `extended` is present - it will be filled with destroyed bits\n BN.prototype.iushrn = function iushrn (bits, hint, extended) {\n assert(typeof bits === 'number' && bits >= 0);\n var h;\n if (hint) {\n h = (hint - (hint % 26)) / 26;\n } else {\n h = 0;\n }\n\n var r = bits % 26;\n var s = Math.min((bits - r) / 26, this.length);\n var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);\n var maskedWords = extended;\n\n h -= s;\n h = Math.max(0, h);\n\n // Extended mode, copy masked part\n if (maskedWords) {\n for (var i = 0; i < s; i++) {\n maskedWords.words[i] = this.words[i];\n }\n maskedWords.length = s;\n }\n\n if (s === 0) {\n // No-op, we should not move anything at all\n } else if (this.length > s) {\n this.length -= s;\n for (i = 0; i < this.length; i++) {\n this.words[i] = this.words[i + s];\n }\n } else {\n this.words[0] = 0;\n this.length = 1;\n }\n\n var carry = 0;\n for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) {\n var word = this.words[i] | 0;\n this.words[i] = (carry << (26 - r)) | (word >>> r);\n carry = word & mask;\n }\n\n // Push carried bits as a mask\n if (maskedWords && carry !== 0) {\n maskedWords.words[maskedWords.length++] = carry;\n }\n\n if (this.length === 0) {\n this.words[0] = 0;\n this.length = 1;\n }\n\n return this.strip();\n };\n\n BN.prototype.ishrn = function ishrn (bits, hint, extended) {\n // TODO(indutny): implement me\n assert(this.negative === 0);\n return this.iushrn(bits, hint, extended);\n };\n\n // Shift-left\n BN.prototype.shln = function shln (bits) {\n return this.clone().ishln(bits);\n };\n\n BN.prototype.ushln = function ushln (bits) {\n return this.clone().iushln(bits);\n };\n\n // Shift-right\n BN.prototype.shrn = function shrn (bits) {\n return this.clone().ishrn(bits);\n };\n\n BN.prototype.ushrn = function ushrn (bits) {\n return this.clone().iushrn(bits);\n };\n\n // Test if n bit is set\n BN.prototype.testn = function testn (bit) {\n assert(typeof bit === 'number' && bit >= 0);\n var r = bit % 26;\n var s = (bit - r) / 26;\n var q = 1 << r;\n\n // Fast case: bit is much higher than all existing words\n if (this.length <= s) return false;\n\n // Check bit and return\n var w = this.words[s];\n\n return !!(w & q);\n };\n\n // Return only lowers bits of number (in-place)\n BN.prototype.imaskn = function imaskn (bits) {\n assert(typeof bits === 'number' && bits >= 0);\n var r = bits % 26;\n var s = (bits - r) / 26;\n\n assert(this.negative === 0, 'imaskn works only with positive numbers');\n\n if (this.length <= s) {\n return this;\n }\n\n if (r !== 0) {\n s++;\n }\n this.length = Math.min(s, this.length);\n\n if (r !== 0) {\n var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);\n this.words[this.length - 1] &= mask;\n }\n\n return this.strip();\n };\n\n // Return only lowers bits of number\n BN.prototype.maskn = function maskn (bits) {\n return this.clone().imaskn(bits);\n };\n\n // Add plain number `num` to `this`\n BN.prototype.iaddn = function iaddn (num) {\n assert(typeof num === 'number');\n assert(num < 0x4000000);\n if (num < 0) return this.isubn(-num);\n\n // Possible sign change\n if (this.negative !== 0) {\n if (this.length === 1 && (this.words[0] | 0) < num) {\n this.words[0] = num - (this.words[0] | 0);\n this.negative = 0;\n return this;\n }\n\n this.negative = 0;\n this.isubn(num);\n this.negative = 1;\n return this;\n }\n\n // Add without checks\n return this._iaddn(num);\n };\n\n BN.prototype._iaddn = function _iaddn (num) {\n this.words[0] += num;\n\n // Carry\n for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) {\n this.words[i] -= 0x4000000;\n if (i === this.length - 1) {\n this.words[i + 1] = 1;\n } else {\n this.words[i + 1]++;\n }\n }\n this.length = Math.max(this.length, i + 1);\n\n return this;\n };\n\n // Subtract plain number `num` from `this`\n BN.prototype.isubn = function isubn (num) {\n assert(typeof num === 'number');\n assert(num < 0x4000000);\n if (num < 0) return this.iaddn(-num);\n\n if (this.negative !== 0) {\n this.negative = 0;\n this.iaddn(num);\n this.negative = 1;\n return this;\n }\n\n this.words[0] -= num;\n\n if (this.length === 1 && this.words[0] < 0) {\n this.words[0] = -this.words[0];\n this.negative = 1;\n } else {\n // Carry\n for (var i = 0; i < this.length && this.words[i] < 0; i++) {\n this.words[i] += 0x4000000;\n this.words[i + 1] -= 1;\n }\n }\n\n return this.strip();\n };\n\n BN.prototype.addn = function addn (num) {\n return this.clone().iaddn(num);\n };\n\n BN.prototype.subn = function subn (num) {\n return this.clone().isubn(num);\n };\n\n BN.prototype.iabs = function iabs () {\n this.negative = 0;\n\n return this;\n };\n\n BN.prototype.abs = function abs () {\n return this.clone().iabs();\n };\n\n BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) {\n var len = num.length + shift;\n var i;\n\n this._expand(len);\n\n var w;\n var carry = 0;\n for (i = 0; i < num.length; i++) {\n w = (this.words[i + shift] | 0) + carry;\n var right = (num.words[i] | 0) * mul;\n w -= right & 0x3ffffff;\n carry = (w >> 26) - ((right / 0x4000000) | 0);\n this.words[i + shift] = w & 0x3ffffff;\n }\n for (; i < this.length - shift; i++) {\n w = (this.words[i + shift] | 0) + carry;\n carry = w >> 26;\n this.words[i + shift] = w & 0x3ffffff;\n }\n\n if (carry === 0) return this.strip();\n\n // Subtraction overflow\n assert(carry === -1);\n carry = 0;\n for (i = 0; i < this.length; i++) {\n w = -(this.words[i] | 0) + carry;\n carry = w >> 26;\n this.words[i] = w & 0x3ffffff;\n }\n this.negative = 1;\n\n return this.strip();\n };\n\n BN.prototype._wordDiv = function _wordDiv (num, mode) {\n var shift = this.length - num.length;\n\n var a = this.clone();\n var b = num;\n\n // Normalize\n var bhi = b.words[b.length - 1] | 0;\n var bhiBits = this._countBits(bhi);\n shift = 26 - bhiBits;\n if (shift !== 0) {\n b = b.ushln(shift);\n a.iushln(shift);\n bhi = b.words[b.length - 1] | 0;\n }\n\n // Initialize quotient\n var m = a.length - b.length;\n var q;\n\n if (mode !== 'mod') {\n q = new BN(null);\n q.length = m + 1;\n q.words = new Array(q.length);\n for (var i = 0; i < q.length; i++) {\n q.words[i] = 0;\n }\n }\n\n var diff = a.clone()._ishlnsubmul(b, 1, m);\n if (diff.negative === 0) {\n a = diff;\n if (q) {\n q.words[m] = 1;\n }\n }\n\n for (var j = m - 1; j >= 0; j--) {\n var qj = (a.words[b.length + j] | 0) * 0x4000000 +\n (a.words[b.length + j - 1] | 0);\n\n // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max\n // (0x7ffffff)\n qj = Math.min((qj / bhi) | 0, 0x3ffffff);\n\n a._ishlnsubmul(b, qj, j);\n while (a.negative !== 0) {\n qj--;\n a.negative = 0;\n a._ishlnsubmul(b, 1, j);\n if (!a.isZero()) {\n a.negative ^= 1;\n }\n }\n if (q) {\n q.words[j] = qj;\n }\n }\n if (q) {\n q.strip();\n }\n a.strip();\n\n // Denormalize\n if (mode !== 'div' && shift !== 0) {\n a.iushrn(shift);\n }\n\n return {\n div: q || null,\n mod: a\n };\n };\n\n // NOTE: 1) `mode` can be set to `mod` to request mod only,\n // to `div` to request div only, or be absent to\n // request both div & mod\n // 2) `positive` is true if unsigned mod is requested\n BN.prototype.divmod = function divmod (num, mode, positive) {\n assert(!num.isZero());\n\n if (this.isZero()) {\n return {\n div: new BN(0),\n mod: new BN(0)\n };\n }\n\n var div, mod, res;\n if (this.negative !== 0 && num.negative === 0) {\n res = this.neg().divmod(num, mode);\n\n if (mode !== 'mod') {\n div = res.div.neg();\n }\n\n if (mode !== 'div') {\n mod = res.mod.neg();\n if (positive && mod.negative !== 0) {\n mod.iadd(num);\n }\n }\n\n return {\n div: div,\n mod: mod\n };\n }\n\n if (this.negative === 0 && num.negative !== 0) {\n res = this.divmod(num.neg(), mode);\n\n if (mode !== 'mod') {\n div = res.div.neg();\n }\n\n return {\n div: div,\n mod: res.mod\n };\n }\n\n if ((this.negative & num.negative) !== 0) {\n res = this.neg().divmod(num.neg(), mode);\n\n if (mode !== 'div') {\n mod = res.mod.neg();\n if (positive && mod.negative !== 0) {\n mod.isub(num);\n }\n }\n\n return {\n div: res.div,\n mod: mod\n };\n }\n\n // Both numbers are positive at this point\n\n // Strip both numbers to approximate shift value\n if (num.length > this.length || this.cmp(num) < 0) {\n return {\n div: new BN(0),\n mod: this\n };\n }\n\n // Very short reduction\n if (num.length === 1) {\n if (mode === 'div') {\n return {\n div: this.divn(num.words[0]),\n mod: null\n };\n }\n\n if (mode === 'mod') {\n return {\n div: null,\n mod: new BN(this.modn(num.words[0]))\n };\n }\n\n return {\n div: this.divn(num.words[0]),\n mod: new BN(this.modn(num.words[0]))\n };\n }\n\n return this._wordDiv(num, mode);\n };\n\n // Find `this` / `num`\n BN.prototype.div = function div (num) {\n return this.divmod(num, 'div', false).div;\n };\n\n // Find `this` % `num`\n BN.prototype.mod = function mod (num) {\n return this.divmod(num, 'mod', false).mod;\n };\n\n BN.prototype.umod = function umod (num) {\n return this.divmod(num, 'mod', true).mod;\n };\n\n // Find Round(`this` / `num`)\n BN.prototype.divRound = function divRound (num) {\n var dm = this.divmod(num);\n\n // Fast case - exact division\n if (dm.mod.isZero()) return dm.div;\n\n var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod;\n\n var half = num.ushrn(1);\n var r2 = num.andln(1);\n var cmp = mod.cmp(half);\n\n // Round down\n if (cmp < 0 || r2 === 1 && cmp === 0) return dm.div;\n\n // Round up\n return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1);\n };\n\n BN.prototype.modn = function modn (num) {\n assert(num <= 0x3ffffff);\n var p = (1 << 26) % num;\n\n var acc = 0;\n for (var i = this.length - 1; i >= 0; i--) {\n acc = (p * acc + (this.words[i] | 0)) % num;\n }\n\n return acc;\n };\n\n // In-place division by number\n BN.prototype.idivn = function idivn (num) {\n assert(num <= 0x3ffffff);\n\n var carry = 0;\n for (var i = this.length - 1; i >= 0; i--) {\n var w = (this.words[i] | 0) + carry * 0x4000000;\n this.words[i] = (w / num) | 0;\n carry = w % num;\n }\n\n return this.strip();\n };\n\n BN.prototype.divn = function divn (num) {\n return this.clone().idivn(num);\n };\n\n BN.prototype.egcd = function egcd (p) {\n assert(p.negative === 0);\n assert(!p.isZero());\n\n var x = this;\n var y = p.clone();\n\n if (x.negative !== 0) {\n x = x.umod(p);\n } else {\n x = x.clone();\n }\n\n // A * x + B * y = x\n var A = new BN(1);\n var B = new BN(0);\n\n // C * x + D * y = y\n var C = new BN(0);\n var D = new BN(1);\n\n var g = 0;\n\n while (x.isEven() && y.isEven()) {\n x.iushrn(1);\n y.iushrn(1);\n ++g;\n }\n\n var yp = y.clone();\n var xp = x.clone();\n\n while (!x.isZero()) {\n for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1);\n if (i > 0) {\n x.iushrn(i);\n while (i-- > 0) {\n if (A.isOdd() || B.isOdd()) {\n A.iadd(yp);\n B.isub(xp);\n }\n\n A.iushrn(1);\n B.iushrn(1);\n }\n }\n\n for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);\n if (j > 0) {\n y.iushrn(j);\n while (j-- > 0) {\n if (C.isOdd() || D.isOdd()) {\n C.iadd(yp);\n D.isub(xp);\n }\n\n C.iushrn(1);\n D.iushrn(1);\n }\n }\n\n if (x.cmp(y) >= 0) {\n x.isub(y);\n A.isub(C);\n B.isub(D);\n } else {\n y.isub(x);\n C.isub(A);\n D.isub(B);\n }\n }\n\n return {\n a: C,\n b: D,\n gcd: y.iushln(g)\n };\n };\n\n // This is reduced incarnation of the binary EEA\n // above, designated to invert members of the\n // _prime_ fields F(p) at a maximal speed\n BN.prototype._invmp = function _invmp (p) {\n assert(p.negative === 0);\n assert(!p.isZero());\n\n var a = this;\n var b = p.clone();\n\n if (a.negative !== 0) {\n a = a.umod(p);\n } else {\n a = a.clone();\n }\n\n var x1 = new BN(1);\n var x2 = new BN(0);\n\n var delta = b.clone();\n\n while (a.cmpn(1) > 0 && b.cmpn(1) > 0) {\n for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1);\n if (i > 0) {\n a.iushrn(i);\n while (i-- > 0) {\n if (x1.isOdd()) {\n x1.iadd(delta);\n }\n\n x1.iushrn(1);\n }\n }\n\n for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);\n if (j > 0) {\n b.iushrn(j);\n while (j-- > 0) {\n if (x2.isOdd()) {\n x2.iadd(delta);\n }\n\n x2.iushrn(1);\n }\n }\n\n if (a.cmp(b) >= 0) {\n a.isub(b);\n x1.isub(x2);\n } else {\n b.isub(a);\n x2.isub(x1);\n }\n }\n\n var res;\n if (a.cmpn(1) === 0) {\n res = x1;\n } else {\n res = x2;\n }\n\n if (res.cmpn(0) < 0) {\n res.iadd(p);\n }\n\n return res;\n };\n\n BN.prototype.gcd = function gcd (num) {\n if (this.isZero()) return num.abs();\n if (num.isZero()) return this.abs();\n\n var a = this.clone();\n var b = num.clone();\n a.negative = 0;\n b.negative = 0;\n\n // Remove common factor of two\n for (var shift = 0; a.isEven() && b.isEven(); shift++) {\n a.iushrn(1);\n b.iushrn(1);\n }\n\n do {\n while (a.isEven()) {\n a.iushrn(1);\n }\n while (b.isEven()) {\n b.iushrn(1);\n }\n\n var r = a.cmp(b);\n if (r < 0) {\n // Swap `a` and `b` to make `a` always bigger than `b`\n var t = a;\n a = b;\n b = t;\n } else if (r === 0 || b.cmpn(1) === 0) {\n break;\n }\n\n a.isub(b);\n } while (true);\n\n return b.iushln(shift);\n };\n\n // Invert number in the field F(num)\n BN.prototype.invm = function invm (num) {\n return this.egcd(num).a.umod(num);\n };\n\n BN.prototype.isEven = function isEven () {\n return (this.words[0] & 1) === 0;\n };\n\n BN.prototype.isOdd = function isOdd () {\n return (this.words[0] & 1) === 1;\n };\n\n // And first word and num\n BN.prototype.andln = function andln (num) {\n return this.words[0] & num;\n };\n\n // Increment at the bit position in-line\n BN.prototype.bincn = function bincn (bit) {\n assert(typeof bit === 'number');\n var r = bit % 26;\n var s = (bit - r) / 26;\n var q = 1 << r;\n\n // Fast case: bit is much higher than all existing words\n if (this.length <= s) {\n this._expand(s + 1);\n this.words[s] |= q;\n return this;\n }\n\n // Add bit and propagate, if needed\n var carry = q;\n for (var i = s; carry !== 0 && i < this.length; i++) {\n var w = this.words[i] | 0;\n w += carry;\n carry = w >>> 26;\n w &= 0x3ffffff;\n this.words[i] = w;\n }\n if (carry !== 0) {\n this.words[i] = carry;\n this.length++;\n }\n return this;\n };\n\n BN.prototype.isZero = function isZero () {\n return this.length === 1 && this.words[0] === 0;\n };\n\n BN.prototype.cmpn = function cmpn (num) {\n var negative = num < 0;\n\n if (this.negative !== 0 && !negative) return -1;\n if (this.negative === 0 && negative) return 1;\n\n this.strip();\n\n var res;\n if (this.length > 1) {\n res = 1;\n } else {\n if (negative) {\n num = -num;\n }\n\n assert(num <= 0x3ffffff, 'Number is too big');\n\n var w = this.words[0] | 0;\n res = w === num ? 0 : w < num ? -1 : 1;\n }\n if (this.negative !== 0) return -res | 0;\n return res;\n };\n\n // Compare two numbers and return:\n // 1 - if `this` > `num`\n // 0 - if `this` == `num`\n // -1 - if `this` < `num`\n BN.prototype.cmp = function cmp (num) {\n if (this.negative !== 0 && num.negative === 0) return -1;\n if (this.negative === 0 && num.negative !== 0) return 1;\n\n var res = this.ucmp(num);\n if (this.negative !== 0) return -res | 0;\n return res;\n };\n\n // Unsigned comparison\n BN.prototype.ucmp = function ucmp (num) {\n // At this point both numbers have the same sign\n if (this.length > num.length) return 1;\n if (this.length < num.length) return -1;\n\n var res = 0;\n for (var i = this.length - 1; i >= 0; i--) {\n var a = this.words[i] | 0;\n var b = num.words[i] | 0;\n\n if (a === b) continue;\n if (a < b) {\n res = -1;\n } else if (a > b) {\n res = 1;\n }\n break;\n }\n return res;\n };\n\n BN.prototype.gtn = function gtn (num) {\n return this.cmpn(num) === 1;\n };\n\n BN.prototype.gt = function gt (num) {\n return this.cmp(num) === 1;\n };\n\n BN.prototype.gten = function gten (num) {\n return this.cmpn(num) >= 0;\n };\n\n BN.prototype.gte = function gte (num) {\n return this.cmp(num) >= 0;\n };\n\n BN.prototype.ltn = function ltn (num) {\n return this.cmpn(num) === -1;\n };\n\n BN.prototype.lt = function lt (num) {\n return this.cmp(num) === -1;\n };\n\n BN.prototype.lten = function lten (num) {\n return this.cmpn(num) <= 0;\n };\n\n BN.prototype.lte = function lte (num) {\n return this.cmp(num) <= 0;\n };\n\n BN.prototype.eqn = function eqn (num) {\n return this.cmpn(num) === 0;\n };\n\n BN.prototype.eq = function eq (num) {\n return this.cmp(num) === 0;\n };\n\n //\n // A reduce context, could be using montgomery or something better, depending\n // on the `m` itself.\n //\n BN.red = function red (num) {\n return new Red(num);\n };\n\n BN.prototype.toRed = function toRed (ctx) {\n assert(!this.red, 'Already a number in reduction context');\n assert(this.negative === 0, 'red works only with positives');\n return ctx.convertTo(this)._forceRed(ctx);\n };\n\n BN.prototype.fromRed = function fromRed () {\n assert(this.red, 'fromRed works only with numbers in reduction context');\n return this.red.convertFrom(this);\n };\n\n BN.prototype._forceRed = function _forceRed (ctx) {\n this.red = ctx;\n return this;\n };\n\n BN.prototype.forceRed = function forceRed (ctx) {\n assert(!this.red, 'Already a number in reduction context');\n return this._forceRed(ctx);\n };\n\n BN.prototype.redAdd = function redAdd (num) {\n assert(this.red, 'redAdd works only with red numbers');\n return this.red.add(this, num);\n };\n\n BN.prototype.redIAdd = function redIAdd (num) {\n assert(this.red, 'redIAdd works only with red numbers');\n return this.red.iadd(this, num);\n };\n\n BN.prototype.redSub = function redSub (num) {\n assert(this.red, 'redSub works only with red numbers');\n return this.red.sub(this, num);\n };\n\n BN.prototype.redISub = function redISub (num) {\n assert(this.red, 'redISub works only with red numbers');\n return this.red.isub(this, num);\n };\n\n BN.prototype.redShl = function redShl (num) {\n assert(this.red, 'redShl works only with red numbers');\n return this.red.shl(this, num);\n };\n\n BN.prototype.redMul = function redMul (num) {\n assert(this.red, 'redMul works only with red numbers');\n this.red._verify2(this, num);\n return this.red.mul(this, num);\n };\n\n BN.prototype.redIMul = function redIMul (num) {\n assert(this.red, 'redMul works only with red numbers');\n this.red._verify2(this, num);\n return this.red.imul(this, num);\n };\n\n BN.prototype.redSqr = function redSqr () {\n assert(this.red, 'redSqr works only with red numbers');\n this.red._verify1(this);\n return this.red.sqr(this);\n };\n\n BN.prototype.redISqr = function redISqr () {\n assert(this.red, 'redISqr works only with red numbers');\n this.red._verify1(this);\n return this.red.isqr(this);\n };\n\n // Square root over p\n BN.prototype.redSqrt = function redSqrt () {\n assert(this.red, 'redSqrt works only with red numbers');\n this.red._verify1(this);\n return this.red.sqrt(this);\n };\n\n BN.prototype.redInvm = function redInvm () {\n assert(this.red, 'redInvm works only with red numbers');\n this.red._verify1(this);\n return this.red.invm(this);\n };\n\n // Return negative clone of `this` % `red modulo`\n BN.prototype.redNeg = function redNeg () {\n assert(this.red, 'redNeg works only with red numbers');\n this.red._verify1(this);\n return this.red.neg(this);\n };\n\n BN.prototype.redPow = function redPow (num) {\n assert(this.red && !num.red, 'redPow(normalNum)');\n this.red._verify1(this);\n return this.red.pow(this, num);\n };\n\n // Prime numbers with efficient reduction\n var primes = {\n k256: null,\n p224: null,\n p192: null,\n p25519: null\n };\n\n // Pseudo-Mersenne prime\n function MPrime (name, p) {\n // P = 2 ^ N - K\n this.name = name;\n this.p = new BN(p, 16);\n this.n = this.p.bitLength();\n this.k = new BN(1).iushln(this.n).isub(this.p);\n\n this.tmp = this._tmp();\n }\n\n MPrime.prototype._tmp = function _tmp () {\n var tmp = new BN(null);\n tmp.words = new Array(Math.ceil(this.n / 13));\n return tmp;\n };\n\n MPrime.prototype.ireduce = function ireduce (num) {\n // Assumes that `num` is less than `P^2`\n // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P)\n var r = num;\n var rlen;\n\n do {\n this.split(r, this.tmp);\n r = this.imulK(r);\n r = r.iadd(this.tmp);\n rlen = r.bitLength();\n } while (rlen > this.n);\n\n var cmp = rlen < this.n ? -1 : r.ucmp(this.p);\n if (cmp === 0) {\n r.words[0] = 0;\n r.length = 1;\n } else if (cmp > 0) {\n r.isub(this.p);\n } else {\n if (r.strip !== undefined) {\n // r is BN v4 instance\n r.strip();\n } else {\n // r is BN v5 instance\n r._strip();\n }\n }\n\n return r;\n };\n\n MPrime.prototype.split = function split (input, out) {\n input.iushrn(this.n, 0, out);\n };\n\n MPrime.prototype.imulK = function imulK (num) {\n return num.imul(this.k);\n };\n\n function K256 () {\n MPrime.call(\n this,\n 'k256',\n 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f');\n }\n inherits(K256, MPrime);\n\n K256.prototype.split = function split (input, output) {\n // 256 = 9 * 26 + 22\n var mask = 0x3fffff;\n\n var outLen = Math.min(input.length, 9);\n for (var i = 0; i < outLen; i++) {\n output.words[i] = input.words[i];\n }\n output.length = outLen;\n\n if (input.length <= 9) {\n input.words[0] = 0;\n input.length = 1;\n return;\n }\n\n // Shift by 9 limbs\n var prev = input.words[9];\n output.words[output.length++] = prev & mask;\n\n for (i = 10; i < input.length; i++) {\n var next = input.words[i] | 0;\n input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22);\n prev = next;\n }\n prev >>>= 22;\n input.words[i - 10] = prev;\n if (prev === 0 && input.length > 10) {\n input.length -= 10;\n } else {\n input.length -= 9;\n }\n };\n\n K256.prototype.imulK = function imulK (num) {\n // K = 0x1000003d1 = [ 0x40, 0x3d1 ]\n num.words[num.length] = 0;\n num.words[num.length + 1] = 0;\n num.length += 2;\n\n // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390\n var lo = 0;\n for (var i = 0; i < num.length; i++) {\n var w = num.words[i] | 0;\n lo += w * 0x3d1;\n num.words[i] = lo & 0x3ffffff;\n lo = w * 0x40 + ((lo / 0x4000000) | 0);\n }\n\n // Fast length reduction\n if (num.words[num.length - 1] === 0) {\n num.length--;\n if (num.words[num.length - 1] === 0) {\n num.length--;\n }\n }\n return num;\n };\n\n function P224 () {\n MPrime.call(\n this,\n 'p224',\n 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001');\n }\n inherits(P224, MPrime);\n\n function P192 () {\n MPrime.call(\n this,\n 'p192',\n 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff');\n }\n inherits(P192, MPrime);\n\n function P25519 () {\n // 2 ^ 255 - 19\n MPrime.call(\n this,\n '25519',\n '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed');\n }\n inherits(P25519, MPrime);\n\n P25519.prototype.imulK = function imulK (num) {\n // K = 0x13\n var carry = 0;\n for (var i = 0; i < num.length; i++) {\n var hi = (num.words[i] | 0) * 0x13 + carry;\n var lo = hi & 0x3ffffff;\n hi >>>= 26;\n\n num.words[i] = lo;\n carry = hi;\n }\n if (carry !== 0) {\n num.words[num.length++] = carry;\n }\n return num;\n };\n\n // Exported mostly for testing purposes, use plain name instead\n BN._prime = function prime (name) {\n // Cached version of prime\n if (primes[name]) return primes[name];\n\n var prime;\n if (name === 'k256') {\n prime = new K256();\n } else if (name === 'p224') {\n prime = new P224();\n } else if (name === 'p192') {\n prime = new P192();\n } else if (name === 'p25519') {\n prime = new P25519();\n } else {\n throw new Error('Unknown prime ' + name);\n }\n primes[name] = prime;\n\n return prime;\n };\n\n //\n // Base reduction engine\n //\n function Red (m) {\n if (typeof m === 'string') {\n var prime = BN._prime(m);\n this.m = prime.p;\n this.prime = prime;\n } else {\n assert(m.gtn(1), 'modulus must be greater than 1');\n this.m = m;\n this.prime = null;\n }\n }\n\n Red.prototype._verify1 = function _verify1 (a) {\n assert(a.negative === 0, 'red works only with positives');\n assert(a.red, 'red works only with red numbers');\n };\n\n Red.prototype._verify2 = function _verify2 (a, b) {\n assert((a.negative | b.negative) === 0, 'red works only with positives');\n assert(a.red && a.red === b.red,\n 'red works only with red numbers');\n };\n\n Red.prototype.imod = function imod (a) {\n if (this.prime) return this.prime.ireduce(a)._forceRed(this);\n return a.umod(this.m)._forceRed(this);\n };\n\n Red.prototype.neg = function neg (a) {\n if (a.isZero()) {\n return a.clone();\n }\n\n return this.m.sub(a)._forceRed(this);\n };\n\n Red.prototype.add = function add (a, b) {\n this._verify2(a, b);\n\n var res = a.add(b);\n if (res.cmp(this.m) >= 0) {\n res.isub(this.m);\n }\n return res._forceRed(this);\n };\n\n Red.prototype.iadd = function iadd (a, b) {\n this._verify2(a, b);\n\n var res = a.iadd(b);\n if (res.cmp(this.m) >= 0) {\n res.isub(this.m);\n }\n return res;\n };\n\n Red.prototype.sub = function sub (a, b) {\n this._verify2(a, b);\n\n var res = a.sub(b);\n if (res.cmpn(0) < 0) {\n res.iadd(this.m);\n }\n return res._forceRed(this);\n };\n\n Red.prototype.isub = function isub (a, b) {\n this._verify2(a, b);\n\n var res = a.isub(b);\n if (res.cmpn(0) < 0) {\n res.iadd(this.m);\n }\n return res;\n };\n\n Red.prototype.shl = function shl (a, num) {\n this._verify1(a);\n return this.imod(a.ushln(num));\n };\n\n Red.prototype.imul = function imul (a, b) {\n this._verify2(a, b);\n return this.imod(a.imul(b));\n };\n\n Red.prototype.mul = function mul (a, b) {\n this._verify2(a, b);\n return this.imod(a.mul(b));\n };\n\n Red.prototype.isqr = function isqr (a) {\n return this.imul(a, a.clone());\n };\n\n Red.prototype.sqr = function sqr (a) {\n return this.mul(a, a);\n };\n\n Red.prototype.sqrt = function sqrt (a) {\n if (a.isZero()) return a.clone();\n\n var mod3 = this.m.andln(3);\n assert(mod3 % 2 === 1);\n\n // Fast case\n if (mod3 === 3) {\n var pow = this.m.add(new BN(1)).iushrn(2);\n return this.pow(a, pow);\n }\n\n // Tonelli-Shanks algorithm (Totally unoptimized and slow)\n //\n // Find Q and S, that Q * 2 ^ S = (P - 1)\n var q = this.m.subn(1);\n var s = 0;\n while (!q.isZero() && q.andln(1) === 0) {\n s++;\n q.iushrn(1);\n }\n assert(!q.isZero());\n\n var one = new BN(1).toRed(this);\n var nOne = one.redNeg();\n\n // Find quadratic non-residue\n // NOTE: Max is such because of generalized Riemann hypothesis.\n var lpow = this.m.subn(1).iushrn(1);\n var z = this.m.bitLength();\n z = new BN(2 * z * z).toRed(this);\n\n while (this.pow(z, lpow).cmp(nOne) !== 0) {\n z.redIAdd(nOne);\n }\n\n var c = this.pow(z, q);\n var r = this.pow(a, q.addn(1).iushrn(1));\n var t = this.pow(a, q);\n var m = s;\n while (t.cmp(one) !== 0) {\n var tmp = t;\n for (var i = 0; tmp.cmp(one) !== 0; i++) {\n tmp = tmp.redSqr();\n }\n assert(i < m);\n var b = this.pow(c, new BN(1).iushln(m - i - 1));\n\n r = r.redMul(b);\n c = b.redSqr();\n t = t.redMul(c);\n m = i;\n }\n\n return r;\n };\n\n Red.prototype.invm = function invm (a) {\n var inv = a._invmp(this.m);\n if (inv.negative !== 0) {\n inv.negative = 0;\n return this.imod(inv).redNeg();\n } else {\n return this.imod(inv);\n }\n };\n\n Red.prototype.pow = function pow (a, num) {\n if (num.isZero()) return new BN(1).toRed(this);\n if (num.cmpn(1) === 0) return a.clone();\n\n var windowSize = 4;\n var wnd = new Array(1 << windowSize);\n wnd[0] = new BN(1).toRed(this);\n wnd[1] = a;\n for (var i = 2; i < wnd.length; i++) {\n wnd[i] = this.mul(wnd[i - 1], a);\n }\n\n var res = wnd[0];\n var current = 0;\n var currentLen = 0;\n var start = num.bitLength() % 26;\n if (start === 0) {\n start = 26;\n }\n\n for (i = num.length - 1; i >= 0; i--) {\n var word = num.words[i];\n for (var j = start - 1; j >= 0; j--) {\n var bit = (word >> j) & 1;\n if (res !== wnd[0]) {\n res = this.sqr(res);\n }\n\n if (bit === 0 && current === 0) {\n currentLen = 0;\n continue;\n }\n\n current <<= 1;\n current |= bit;\n currentLen++;\n if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue;\n\n res = this.mul(res, wnd[current]);\n currentLen = 0;\n current = 0;\n }\n start = 26;\n }\n\n return res;\n };\n\n Red.prototype.convertTo = function convertTo (num) {\n var r = num.umod(this.m);\n\n return r === num ? r.clone() : r;\n };\n\n Red.prototype.convertFrom = function convertFrom (num) {\n var res = num.clone();\n res.red = null;\n return res;\n };\n\n //\n // Montgomery method engine\n //\n\n BN.mont = function mont (num) {\n return new Mont(num);\n };\n\n function Mont (m) {\n Red.call(this, m);\n\n this.shift = this.m.bitLength();\n if (this.shift % 26 !== 0) {\n this.shift += 26 - (this.shift % 26);\n }\n\n this.r = new BN(1).iushln(this.shift);\n this.r2 = this.imod(this.r.sqr());\n this.rinv = this.r._invmp(this.m);\n\n this.minv = this.rinv.mul(this.r).isubn(1).div(this.m);\n this.minv = this.minv.umod(this.r);\n this.minv = this.r.sub(this.minv);\n }\n inherits(Mont, Red);\n\n Mont.prototype.convertTo = function convertTo (num) {\n return this.imod(num.ushln(this.shift));\n };\n\n Mont.prototype.convertFrom = function convertFrom (num) {\n var r = this.imod(num.mul(this.rinv));\n r.red = null;\n return r;\n };\n\n Mont.prototype.imul = function imul (a, b) {\n if (a.isZero() || b.isZero()) {\n a.words[0] = 0;\n a.length = 1;\n return a;\n }\n\n var t = a.imul(b);\n var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);\n var u = t.isub(c).iushrn(this.shift);\n var res = u;\n\n if (u.cmp(this.m) >= 0) {\n res = u.isub(this.m);\n } else if (u.cmpn(0) < 0) {\n res = u.iadd(this.m);\n }\n\n return res._forceRed(this);\n };\n\n Mont.prototype.mul = function mul (a, b) {\n if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this);\n\n var t = a.mul(b);\n var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);\n var u = t.isub(c).iushrn(this.shift);\n var res = u;\n if (u.cmp(this.m) >= 0) {\n res = u.isub(this.m);\n } else if (u.cmpn(0) < 0) {\n res = u.iadd(this.m);\n }\n\n return res._forceRed(this);\n };\n\n Mont.prototype.invm = function invm (a) {\n // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R\n var res = this.imod(a._invmp(this.m).mul(this.r2));\n return res._forceRed(this);\n };\n})(typeof module === 'undefined' || module, this);\n","const assert = require(\"assert\");\nconst GenUtils = require(\"./GenUtils\");\nconst LibraryUtils = require(\"./LibraryUtils\");\nconst MoneroError = require(\"./MoneroError\");\n\n/**\n * Collection of Monero utilities.\n * \n * @hideconstructor\n */\nclass MoneroUtils {\n \n // TODO: improve validation\n static validateMnemonic(mnemonic) {\n assert(mnemonic, \"Mnemonic phrase is not initialized\");\n let words = mnemonic.split(\" \");\n if (words.length !== MoneroUtils.NUM_MNEMONIC_WORDS) throw new Error(\"Mnemonic phrase is \" + words.length + \" words but must be \" + MoneroUtils.NUM_MNEMONIC_WORDS);\n }\n \n // TODO: improve validation\n static validatePrivateViewKey(privateViewKey) {\n assert(typeof privateViewKey === \"string\");\n assert(privateViewKey.length === 64);\n }\n \n // TODO: improve validation\n static validatePrivateSpendKey(privateSpendKey) {\n assert(typeof privateSpendKey === \"string\");\n assert(privateSpendKey.length === 64);\n }\n \n // TODO: improve validation\n static validatePublicViewKey(publicViewKey) {\n assert(typeof publicViewKey === \"string\");\n assert(publicViewKey.length === 64);\n }\n \n // TODO: improve validation\n static validatePublicSpendKey(publicSpendKey) {\n assert(typeof publicSpendKey === \"string\");\n assert(publicSpendKey.length === 64);\n }\n \n // TODO: improve validation, will require knowing network type\n static isValidAddress(address) {\n try {\n MoneroUtils.validateAddress(address);\n return true;\n } catch (e) {\n return false;\n }\n }\n \n static validateAddress(address) {\n assert(typeof address === \"string\", \"Address is not string\");\n assert(address.length > 0, \"Address is empty\");\n assert(GenUtils.isBase58(address), \"Address is not base 58\");\n }\n \n static isValidPaymentId(paymentId) {\n try {\n MoneroUtils.validatePaymentId(paymentId);\n return true;\n } catch (e) {\n return false;\n }\n }\n \n // TODO: beef this up\n static validatePaymentId(paymentId) {\n assert.equal(typeof paymentId, \"string\");\n assert(paymentId.length === 16 || paymentId.length === 64);\n }\n \n /**\n * Decodes tx extra according to https://cryptonote.org/cns/cns005.txt and\n * returns the last tx pub key.\n * \n * TODO: use c++ bridge for this\n * \n * @param txExtra is an array of tx extra bytes\n * @return the last pub key as a hexidecimal string\n */\n static getLastTxPubKey(txExtra) {\n let lastPubKeyIdx;\n for (let i = 0; i < txExtra.length; i++) {\n let tag = txExtra[i];\n if (tag === 0 || tag === 2) {\n i += 1 + txExtra[i + 1]; // advance to next tag\n } else if (tag === 1) {\n lastPubKeyIdx = i + 1;\n i += 1 + 32; // advance to next tag\n } else throw new Error(\"Invalid sub-field tag: \" + tag);\n }\n return Buffer.from(new Uint8Array(txExtra.slice(lastPubKeyIdx, lastPubKeyIdx + 32))).toString(\"hex\");\n }\n \n /**\n * Determines if two payment ids are functionally equal.\n * \n * For example, 03284e41c342f032 and 03284e41c342f032000000000000000000000000000000000000000000000000 are considered equal.\n * \n * @param paymentId1 is a payment id to compare\n * @param paymentId2 is a payment id to compare\n * @return true if the payment ids are equal, false otherwise\n */\n static paymentIdsEqual(paymentId1, paymentId2) {\n let maxLength = Math.max(paymentId1.length, paymentId2.length);\n for (let i = 0; i < maxLength; i++) {\n if (i < paymentId1.length && i < paymentId2.length && paymentId1[i] !== paymentId2[i]) return false;\n if (i >= paymentId1.length && paymentId2[i] !== '0') return false;\n if (i >= paymentId2.length && paymentId1[i] !== '0') return false;\n }\n return true;\n }\n \n /**\n * Merges a transaction into a list of existing transactions.\n * \n * @param txs are existing transactions to merge into\n * @param tx is the transaction to merge into the list\n */\n static mergeTx(txs, tx) {\n for (let aTx of txs) {\n if (aTx.getHash() === tx.getHash()) {\n aTx.merge(tx);\n return;\n }\n }\n txs.push(tx);\n }\n \n /**\n * Converts the given JSON to a binary Uint8Array using Monero's portable storage format.\n * \n * @param json is the json to convert to binary\n * @returns Uint8Array is the json converted to portable storage binary\n */\n static jsonToBinary(json) {\n \n // wasm module must be pre-loaded\n if (LibraryUtils.getWasmModule() === undefined) throw MoneroError(\"WASM module is not loaded; call 'await LibraryUtils.loadKeysModule()' to load\");\n \n // serialize json to binary which is stored in c++ heap\n let binMemInfoStr = LibraryUtils.getWasmModule().malloc_binary_from_json(JSON.stringify(json));\n \n // sanitize binary memory address info\n let binMemInfo = JSON.parse(binMemInfoStr);\n binMemInfo.ptr = parseInt(binMemInfo.ptr);\n binMemInfo.length = parseInt(binMemInfo.length);\n \n // read binary data from heap to Uint8Array\n let view = new Uint8Array(binMemInfo.length);\n for (let i = 0; i < binMemInfo.length; i++) {\n view[i] = LibraryUtils.getWasmModule().HEAPU8[binMemInfo.ptr / Uint8Array.BYTES_PER_ELEMENT + i];\n }\n \n // free binary on heap\n LibraryUtils.getWasmModule()._free(binMemInfo.ptr);\n \n // return json from binary data\n return view;\n }\n \n /**\n * Converts the given portable storage binary to JSON.\n * \n * @param uint8arr is a Uint8Array with binary data in Monero's portable storage format\n * @returns a JSON object converted from the binary data\n */\n static binaryToJson(uint8arr) {\n \n // wasm module must be pre-loaded\n if (LibraryUtils.getWasmModule() === undefined) throw MoneroError(\"WASM module is not loaded; call 'await LibraryUtils.loadKeysModule()' to load\");\n \n // allocate space in c++ heap for binary\n let ptr = LibraryUtils.getWasmModule()._malloc(uint8arr.length * uint8arr.BYTES_PER_ELEMENT);\n let heap = new Uint8Array(LibraryUtils.getWasmModule().HEAPU8.buffer, ptr, uint8arr.length * uint8arr.BYTES_PER_ELEMENT);\n if (ptr !== heap.byteOffset) throw new Error(\"Memory ptr !== heap.byteOffset\"); // should be equal\n \n // write binary to heap\n heap.set(new Uint8Array(uint8arr.buffer));\n \n // create object with binary memory address info\n let binMemInfo = { ptr: ptr, length: uint8arr.length }\n\n // convert binary to json str\n const ret_string = LibraryUtils.getWasmModule().binary_to_json(JSON.stringify(binMemInfo));\n \n // free binary on heap\n LibraryUtils.getWasmModule()._free(ptr);\n \n // parse and return json\n return JSON.parse(ret_string);\n }\n \n /**\n * Converts the binary response from daemon RPC block retrieval to JSON.\n * \n * @param uint8arr is the binary response from daemon RPC when getting blocks\n * @returns a JSON object with the blocks data\n */\n static binaryBlocksToJson(uint8arr) {\n \n // wasm module must be pre-loaded\n if (LibraryUtils.getWasmModule() === undefined) throw MoneroError(\"WASM module is not loaded; call 'await LibraryUtils.loadKeysModule()' to load\");\n \n // allocate space in c++ heap for binary\n let ptr = LibraryUtils.getWasmModule()._malloc(uint8arr.length * uint8arr.BYTES_PER_ELEMENT);\n let heap = new Uint8Array(LibraryUtils.getWasmModule().HEAPU8.buffer, ptr, uint8arr.length * uint8arr.BYTES_PER_ELEMENT);\n if (ptr !== heap.byteOffset) throw new Error(\"Memory ptr !== heap.byteOffset\"); // should be equal\n \n // write binary to heap\n heap.set(new Uint8Array(uint8arr.buffer));\n \n // create object with binary memory address info\n let binMemInfo = { ptr: ptr, length: uint8arr.length }\n\n // convert binary to json str\n const json_str = LibraryUtils.getWasmModule().binary_blocks_to_json(JSON.stringify(binMemInfo));\n \n // free memory\n LibraryUtils.getWasmModule()._free(ptr);\n \n // parse result to json\n let json = JSON.parse(json_str); // parsing json gives arrays of block and tx strings\n json.blocks = json.blocks.map(blockStr => JSON.parse(blockStr)); // replace block strings with parsed blocks\n json.txs = json.txs.map(txs => txs ? txs.map(tx => JSON.parse(tx.replace(\",\", \"{\") + \"}\")) : []); // modify tx string to proper json and parse // TODO: more efficient way than this json manipulation?\n return json;\n }\n}\n\nMoneroUtils.NUM_MNEMONIC_WORDS = 25;\nMoneroUtils.WALLET_REFRESH_RATE = 10000; // 10 seconds\nMoneroUtils.RING_SIZE = 12;\nMoneroUtils.MAX_REQUESTS_PER_SECOND = 50;\n\nmodule.exports = MoneroUtils;","// Copyright 2015 Joyent, Inc.\n\nvar assert = require('assert-plus');\nvar util = require('util');\n\nfunction FingerprintFormatError(fp, format) {\n\tif (Error.captureStackTrace)\n\t\tError.captureStackTrace(this, FingerprintFormatError);\n\tthis.name = 'FingerprintFormatError';\n\tthis.fingerprint = fp;\n\tthis.format = format;\n\tthis.message = 'Fingerprint format is not supported, or is invalid: ';\n\tif (fp !== undefined)\n\t\tthis.message += ' fingerprint = ' + fp;\n\tif (format !== undefined)\n\t\tthis.message += ' format = ' + format;\n}\nutil.inherits(FingerprintFormatError, Error);\n\nfunction InvalidAlgorithmError(alg) {\n\tif (Error.captureStackTrace)\n\t\tError.captureStackTrace(this, InvalidAlgorithmError);\n\tthis.name = 'InvalidAlgorithmError';\n\tthis.algorithm = alg;\n\tthis.message = 'Algorithm \"' + alg + '\" is not supported';\n}\nutil.inherits(InvalidAlgorithmError, Error);\n\nfunction KeyParseError(name, format, innerErr) {\n\tif (Error.captureStackTrace)\n\t\tError.captureStackTrace(this, KeyParseError);\n\tthis.name = 'KeyParseError';\n\tthis.format = format;\n\tthis.keyName = name;\n\tthis.innerErr = innerErr;\n\tthis.message = 'Failed to parse ' + name + ' as a valid ' + format +\n\t ' format key: ' + innerErr.message;\n}\nutil.inherits(KeyParseError, Error);\n\nfunction SignatureParseError(type, format, innerErr) {\n\tif (Error.captureStackTrace)\n\t\tError.captureStackTrace(this, SignatureParseError);\n\tthis.name = 'SignatureParseError';\n\tthis.type = type;\n\tthis.format = format;\n\tthis.innerErr = innerErr;\n\tthis.message = 'Failed to parse the given data as a ' + type +\n\t ' signature in ' + format + ' format: ' + innerErr.message;\n}\nutil.inherits(SignatureParseError, Error);\n\nfunction CertificateParseError(name, format, innerErr) {\n\tif (Error.captureStackTrace)\n\t\tError.captureStackTrace(this, CertificateParseError);\n\tthis.name = 'CertificateParseError';\n\tthis.format = format;\n\tthis.certName = name;\n\tthis.innerErr = innerErr;\n\tthis.message = 'Failed to parse ' + name + ' as a valid ' + format +\n\t ' format certificate: ' + innerErr.message;\n}\nutil.inherits(CertificateParseError, Error);\n\nfunction KeyEncryptedError(name, format) {\n\tif (Error.captureStackTrace)\n\t\tError.captureStackTrace(this, KeyEncryptedError);\n\tthis.name = 'KeyEncryptedError';\n\tthis.format = format;\n\tthis.keyName = name;\n\tthis.message = 'The ' + format + ' format key ' + name + ' is ' +\n\t 'encrypted (password-protected), and no passphrase was ' +\n\t 'provided in `options`';\n}\nutil.inherits(KeyEncryptedError, Error);\n\nmodule.exports = {\n\tFingerprintFormatError: FingerprintFormatError,\n\tInvalidAlgorithmError: InvalidAlgorithmError,\n\tKeyParseError: KeyParseError,\n\tSignatureParseError: SignatureParseError,\n\tKeyEncryptedError: KeyEncryptedError,\n\tCertificateParseError: CertificateParseError\n};\n","// Copyright 2015 Joyent, Inc.\n\nmodule.exports = Signature;\n\nvar assert = require('assert-plus');\nvar Buffer = require('safer-buffer').Buffer;\nvar algs = require('./algs');\nvar crypto = require('crypto');\nvar errs = require('./errors');\nvar utils = require('./utils');\nvar asn1 = require('asn1');\nvar SSHBuffer = require('./ssh-buffer');\n\nvar InvalidAlgorithmError = errs.InvalidAlgorithmError;\nvar SignatureParseError = errs.SignatureParseError;\n\nfunction Signature(opts) {\n\tassert.object(opts, 'options');\n\tassert.arrayOfObject(opts.parts, 'options.parts');\n\tassert.string(opts.type, 'options.type');\n\n\tvar partLookup = {};\n\tfor (var i = 0; i < opts.parts.length; ++i) {\n\t\tvar part = opts.parts[i];\n\t\tpartLookup[part.name] = part;\n\t}\n\n\tthis.type = opts.type;\n\tthis.hashAlgorithm = opts.hashAlgo;\n\tthis.curve = opts.curve;\n\tthis.parts = opts.parts;\n\tthis.part = partLookup;\n}\n\nSignature.prototype.toBuffer = function (format) {\n\tif (format === undefined)\n\t\tformat = 'asn1';\n\tassert.string(format, 'format');\n\n\tvar buf;\n\tvar stype = 'ssh-' + this.type;\n\n\tswitch (this.type) {\n\tcase 'rsa':\n\t\tswitch (this.hashAlgorithm) {\n\t\tcase 'sha256':\n\t\t\tstype = 'rsa-sha2-256';\n\t\t\tbreak;\n\t\tcase 'sha512':\n\t\t\tstype = 'rsa-sha2-512';\n\t\t\tbreak;\n\t\tcase 'sha1':\n\t\tcase undefined:\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthrow (new Error('SSH signature ' +\n\t\t\t 'format does not support hash ' +\n\t\t\t 'algorithm ' + this.hashAlgorithm));\n\t\t}\n\t\tif (format === 'ssh') {\n\t\t\tbuf = new SSHBuffer({});\n\t\t\tbuf.writeString(stype);\n\t\t\tbuf.writePart(this.part.sig);\n\t\t\treturn (buf.toBuffer());\n\t\t} else {\n\t\t\treturn (this.part.sig.data);\n\t\t}\n\t\tbreak;\n\n\tcase 'ed25519':\n\t\tif (format === 'ssh') {\n\t\t\tbuf = new SSHBuffer({});\n\t\t\tbuf.writeString(stype);\n\t\t\tbuf.writePart(this.part.sig);\n\t\t\treturn (buf.toBuffer());\n\t\t} else {\n\t\t\treturn (this.part.sig.data);\n\t\t}\n\t\tbreak;\n\n\tcase 'dsa':\n\tcase 'ecdsa':\n\t\tvar r, s;\n\t\tif (format === 'asn1') {\n\t\t\tvar der = new asn1.BerWriter();\n\t\t\tder.startSequence();\n\t\t\tr = utils.mpNormalize(this.part.r.data);\n\t\t\ts = utils.mpNormalize(this.part.s.data);\n\t\t\tder.writeBuffer(r, asn1.Ber.Integer);\n\t\t\tder.writeBuffer(s, asn1.Ber.Integer);\n\t\t\tder.endSequence();\n\t\t\treturn (der.buffer);\n\t\t} else if (format === 'ssh' && this.type === 'dsa') {\n\t\t\tbuf = new SSHBuffer({});\n\t\t\tbuf.writeString('ssh-dss');\n\t\t\tr = this.part.r.data;\n\t\t\tif (r.length > 20 && r[0] === 0x00)\n\t\t\t\tr = r.slice(1);\n\t\t\ts = this.part.s.data;\n\t\t\tif (s.length > 20 && s[0] === 0x00)\n\t\t\t\ts = s.slice(1);\n\t\t\tif ((this.hashAlgorithm &&\n\t\t\t this.hashAlgorithm !== 'sha1') ||\n\t\t\t r.length + s.length !== 40) {\n\t\t\t\tthrow (new Error('OpenSSH only supports ' +\n\t\t\t\t 'DSA signatures with SHA1 hash'));\n\t\t\t}\n\t\t\tbuf.writeBuffer(Buffer.concat([r, s]));\n\t\t\treturn (buf.toBuffer());\n\t\t} else if (format === 'ssh' && this.type === 'ecdsa') {\n\t\t\tvar inner = new SSHBuffer({});\n\t\t\tr = this.part.r.data;\n\t\t\tinner.writeBuffer(r);\n\t\t\tinner.writePart(this.part.s);\n\n\t\t\tbuf = new SSHBuffer({});\n\t\t\t/* XXX: find a more proper way to do this? */\n\t\t\tvar curve;\n\t\t\tif (r[0] === 0x00)\n\t\t\t\tr = r.slice(1);\n\t\t\tvar sz = r.length * 8;\n\t\t\tif (sz === 256)\n\t\t\t\tcurve = 'nistp256';\n\t\t\telse if (sz === 384)\n\t\t\t\tcurve = 'nistp384';\n\t\t\telse if (sz === 528)\n\t\t\t\tcurve = 'nistp521';\n\t\t\tbuf.writeString('ecdsa-sha2-' + curve);\n\t\t\tbuf.writeBuffer(inner.toBuffer());\n\t\t\treturn (buf.toBuffer());\n\t\t}\n\t\tthrow (new Error('Invalid signature format'));\n\tdefault:\n\t\tthrow (new Error('Invalid signature data'));\n\t}\n};\n\nSignature.prototype.toString = function (format) {\n\tassert.optionalString(format, 'format');\n\treturn (this.toBuffer(format).toString('base64'));\n};\n\nSignature.parse = function (data, type, format) {\n\tif (typeof (data) === 'string')\n\t\tdata = Buffer.from(data, 'base64');\n\tassert.buffer(data, 'data');\n\tassert.string(format, 'format');\n\tassert.string(type, 'type');\n\n\tvar opts = {};\n\topts.type = type.toLowerCase();\n\topts.parts = [];\n\n\ttry {\n\t\tassert.ok(data.length > 0, 'signature must not be empty');\n\t\tswitch (opts.type) {\n\t\tcase 'rsa':\n\t\t\treturn (parseOneNum(data, type, format, opts));\n\t\tcase 'ed25519':\n\t\t\treturn (parseOneNum(data, type, format, opts));\n\n\t\tcase 'dsa':\n\t\tcase 'ecdsa':\n\t\t\tif (format === 'asn1')\n\t\t\t\treturn (parseDSAasn1(data, type, format, opts));\n\t\t\telse if (opts.type === 'dsa')\n\t\t\t\treturn (parseDSA(data, type, format, opts));\n\t\t\telse\n\t\t\t\treturn (parseECDSA(data, type, format, opts));\n\n\t\tdefault:\n\t\t\tthrow (new InvalidAlgorithmError(type));\n\t\t}\n\n\t} catch (e) {\n\t\tif (e instanceof InvalidAlgorithmError)\n\t\t\tthrow (e);\n\t\tthrow (new SignatureParseError(type, format, e));\n\t}\n};\n\nfunction parseOneNum(data, type, format, opts) {\n\tif (format === 'ssh') {\n\t\ttry {\n\t\t\tvar buf = new SSHBuffer({buffer: data});\n\t\t\tvar head = buf.readString();\n\t\t} catch (e) {\n\t\t\t/* fall through */\n\t\t}\n\t\tif (buf !== undefined) {\n\t\t\tvar msg = 'SSH signature does not match expected ' +\n\t\t\t 'type (expected ' + type + ', got ' + head + ')';\n\t\t\tswitch (head) {\n\t\t\tcase 'ssh-rsa':\n\t\t\t\tassert.strictEqual(type, 'rsa', msg);\n\t\t\t\topts.hashAlgo = 'sha1';\n\t\t\t\tbreak;\n\t\t\tcase 'rsa-sha2-256':\n\t\t\t\tassert.strictEqual(type, 'rsa', msg);\n\t\t\t\topts.hashAlgo = 'sha256';\n\t\t\t\tbreak;\n\t\t\tcase 'rsa-sha2-512':\n\t\t\t\tassert.strictEqual(type, 'rsa', msg);\n\t\t\t\topts.hashAlgo = 'sha512';\n\t\t\t\tbreak;\n\t\t\tcase 'ssh-ed25519':\n\t\t\t\tassert.strictEqual(type, 'ed25519', msg);\n\t\t\t\topts.hashAlgo = 'sha512';\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tthrow (new Error('Unknown SSH signature ' +\n\t\t\t\t 'type: ' + head));\n\t\t\t}\n\t\t\tvar sig = buf.readPart();\n\t\t\tassert.ok(buf.atEnd(), 'extra trailing bytes');\n\t\t\tsig.name = 'sig';\n\t\t\topts.parts.push(sig);\n\t\t\treturn (new Signature(opts));\n\t\t}\n\t}\n\topts.parts.push({name: 'sig', data: data});\n\treturn (new Signature(opts));\n}\n\nfunction parseDSAasn1(data, type, format, opts) {\n\tvar der = new asn1.BerReader(data);\n\tder.readSequence();\n\tvar r = der.readString(asn1.Ber.Integer, true);\n\tvar s = der.readString(asn1.Ber.Integer, true);\n\n\topts.parts.push({name: 'r', data: utils.mpNormalize(r)});\n\topts.parts.push({name: 's', data: utils.mpNormalize(s)});\n\n\treturn (new Signature(opts));\n}\n\nfunction parseDSA(data, type, format, opts) {\n\tif (data.length != 40) {\n\t\tvar buf = new SSHBuffer({buffer: data});\n\t\tvar d = buf.readBuffer();\n\t\tif (d.toString('ascii') === 'ssh-dss')\n\t\t\td = buf.readBuffer();\n\t\tassert.ok(buf.atEnd(), 'extra trailing bytes');\n\t\tassert.strictEqual(d.length, 40, 'invalid inner length');\n\t\tdata = d;\n\t}\n\topts.parts.push({name: 'r', data: data.slice(0, 20)});\n\topts.parts.push({name: 's', data: data.slice(20, 40)});\n\treturn (new Signature(opts));\n}\n\nfunction parseECDSA(data, type, format, opts) {\n\tvar buf = new SSHBuffer({buffer: data});\n\n\tvar r, s;\n\tvar inner = buf.readBuffer();\n\tvar stype = inner.toString('ascii');\n\tif (stype.slice(0, 6) === 'ecdsa-') {\n\t\tvar parts = stype.split('-');\n\t\tassert.strictEqual(parts[0], 'ecdsa');\n\t\tassert.strictEqual(parts[1], 'sha2');\n\t\topts.curve = parts[2];\n\t\tswitch (opts.curve) {\n\t\tcase 'nistp256':\n\t\t\topts.hashAlgo = 'sha256';\n\t\t\tbreak;\n\t\tcase 'nistp384':\n\t\t\topts.hashAlgo = 'sha384';\n\t\t\tbreak;\n\t\tcase 'nistp521':\n\t\t\topts.hashAlgo = 'sha512';\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthrow (new Error('Unsupported ECDSA curve: ' +\n\t\t\t opts.curve));\n\t\t}\n\t\tinner = buf.readBuffer();\n\t\tassert.ok(buf.atEnd(), 'extra trailing bytes on outer');\n\t\tbuf = new SSHBuffer({buffer: inner});\n\t\tr = buf.readPart();\n\t} else {\n\t\tr = {data: inner};\n\t}\n\n\ts = buf.readPart();\n\tassert.ok(buf.atEnd(), 'extra trailing bytes');\n\n\tr.name = 'r';\n\ts.name = 's';\n\n\topts.parts.push(r);\n\topts.parts.push(s);\n\treturn (new Signature(opts));\n}\n\nSignature.isSignature = function (obj, ver) {\n\treturn (utils.isCompatible(obj, Signature, ver));\n};\n\n/*\n * API versions for Signature:\n * [1,0] -- initial ver\n * [2,0] -- support for rsa in full ssh format, compat with sshpk-agent\n * hashAlgorithm property\n * [2,1] -- first tagged version\n */\nSignature.prototype._sshpkApiVersion = [2, 1];\n\nSignature._oldVersionDetect = function (obj) {\n\tassert.func(obj.toBuffer);\n\tif (obj.hasOwnProperty('hashAlgorithm'))\n\t\treturn ([2, 0]);\n\treturn ([1, 0]);\n};\n","// Copyright 2011 Mark Cavage All rights reserved.\n\n// If you have no idea what ASN.1 or BER is, see this:\n// ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc\n\nvar Ber = require('./ber/index');\n\n\n\n// --- Exported API\n\nmodule.exports = {\n\n Ber: Ber,\n\n BerReader: Ber.Reader,\n\n BerWriter: Ber.Writer\n\n};\n","var scope = (typeof global !== \"undefined\" && global) ||\n (typeof self !== \"undefined\" && self) ||\n window;\nvar apply = Function.prototype.apply;\n\n// DOM APIs, for completeness\n\nexports.setTimeout = function() {\n return new Timeout(apply.call(setTimeout, scope, arguments), clearTimeout);\n};\nexports.setInterval = function() {\n return new Timeout(apply.call(setInterval, scope, arguments), clearInterval);\n};\nexports.clearTimeout =\nexports.clearInterval = function(timeout) {\n if (timeout) {\n timeout.close();\n }\n};\n\nfunction Timeout(id, clearFn) {\n this._id = id;\n this._clearFn = clearFn;\n}\nTimeout.prototype.unref = Timeout.prototype.ref = function() {};\nTimeout.prototype.close = function() {\n this._clearFn.call(scope, this._id);\n};\n\n// Does not start the time, just sets up the members needed.\nexports.enroll = function(item, msecs) {\n clearTimeout(item._idleTimeoutId);\n item._idleTimeout = msecs;\n};\n\nexports.unenroll = function(item) {\n clearTimeout(item._idleTimeoutId);\n item._idleTimeout = -1;\n};\n\nexports._unrefActive = exports.active = function(item) {\n clearTimeout(item._idleTimeoutId);\n\n var msecs = item._idleTimeout;\n if (msecs >= 0) {\n item._idleTimeoutId = setTimeout(function onTimeout() {\n if (item._onTimeout)\n item._onTimeout();\n }, msecs);\n }\n};\n\n// setimmediate attaches itself to the global object\nrequire(\"setimmediate\");\n// On some exotic environments, it's not clear which object `setimmediate` was\n// able to install onto. Search each possibility in the same order as the\n// `setimmediate` library.\nexports.setImmediate = (typeof self !== \"undefined\" && self.setImmediate) ||\n (typeof global !== \"undefined\" && global.setImmediate) ||\n (this && this.setImmediate);\nexports.clearImmediate = (typeof self !== \"undefined\" && self.clearImmediate) ||\n (typeof global !== \"undefined\" && global.clearImmediate) ||\n (this && this.clearImmediate);\n","var Buffer = require('safe-buffer').Buffer\nvar Transform = require('stream').Transform\nvar StringDecoder = require('string_decoder').StringDecoder\nvar inherits = require('inherits')\n\nfunction CipherBase (hashMode) {\n Transform.call(this)\n this.hashMode = typeof hashMode === 'string'\n if (this.hashMode) {\n this[hashMode] = this._finalOrDigest\n } else {\n this.final = this._finalOrDigest\n }\n if (this._final) {\n this.__final = this._final\n this._final = null\n }\n this._decoder = null\n this._encoding = null\n}\ninherits(CipherBase, Transform)\n\nCipherBase.prototype.update = function (data, inputEnc, outputEnc) {\n if (typeof data === 'string') {\n data = Buffer.from(data, inputEnc)\n }\n\n var outData = this._update(data)\n if (this.hashMode) return this\n\n if (outputEnc) {\n outData = this._toString(outData, outputEnc)\n }\n\n return outData\n}\n\nCipherBase.prototype.setAutoPadding = function () {}\nCipherBase.prototype.getAuthTag = function () {\n throw new Error('trying to get auth tag in unsupported state')\n}\n\nCipherBase.prototype.setAuthTag = function () {\n throw new Error('trying to set auth tag in unsupported state')\n}\n\nCipherBase.prototype.setAAD = function () {\n throw new Error('trying to set aad in unsupported state')\n}\n\nCipherBase.prototype._transform = function (data, _, next) {\n var err\n try {\n if (this.hashMode) {\n this._update(data)\n } else {\n this.push(this._update(data))\n }\n } catch (e) {\n err = e\n } finally {\n next(err)\n }\n}\nCipherBase.prototype._flush = function (done) {\n var err\n try {\n this.push(this.__final())\n } catch (e) {\n err = e\n }\n\n done(err)\n}\nCipherBase.prototype._finalOrDigest = function (outputEnc) {\n var outData = this.__final() || Buffer.alloc(0)\n if (outputEnc) {\n outData = this._toString(outData, outputEnc, true)\n }\n return outData\n}\n\nCipherBase.prototype._toString = function (value, enc, fin) {\n if (!this._decoder) {\n this._decoder = new StringDecoder(enc)\n this._encoding = enc\n }\n\n if (this._encoding !== enc) throw new Error('can\\'t switch encodings')\n\n var out = this._decoder.write(value)\n if (fin) {\n out += this._decoder.end()\n }\n\n return out\n}\n\nmodule.exports = CipherBase\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\nmodule.exports = Stream;\n\nvar EE = require('events').EventEmitter;\nvar inherits = require('inherits');\n\ninherits(Stream, EE);\nStream.Readable = require('readable-stream/readable.js');\nStream.Writable = require('readable-stream/writable.js');\nStream.Duplex = require('readable-stream/duplex.js');\nStream.Transform = require('readable-stream/transform.js');\nStream.PassThrough = require('readable-stream/passthrough.js');\n\n// Backwards-compat with node 0.4.x\nStream.Stream = Stream;\n\n\n\n// old-style streams. Note that the pipe method (the only relevant\n// part of this class) is overridden in the Readable class.\n\nfunction Stream() {\n EE.call(this);\n}\n\nStream.prototype.pipe = function(dest, options) {\n var source = this;\n\n function ondata(chunk) {\n if (dest.writable) {\n if (false === dest.write(chunk) && source.pause) {\n source.pause();\n }\n }\n }\n\n source.on('data', ondata);\n\n function ondrain() {\n if (source.readable && source.resume) {\n source.resume();\n }\n }\n\n dest.on('drain', ondrain);\n\n // If the 'end' option is not supplied, dest.end() will be called when\n // source gets the 'end' or 'close' events. Only dest.end() once.\n if (!dest._isStdio && (!options || options.end !== false)) {\n source.on('end', onend);\n source.on('close', onclose);\n }\n\n var didOnEnd = false;\n function onend() {\n if (didOnEnd) return;\n didOnEnd = true;\n\n dest.end();\n }\n\n\n function onclose() {\n if (didOnEnd) return;\n didOnEnd = true;\n\n if (typeof dest.destroy === 'function') dest.destroy();\n }\n\n // don't leave dangling pipes when there are errors.\n function onerror(er) {\n cleanup();\n if (EE.listenerCount(this, 'error') === 0) {\n throw er; // Unhandled stream error in pipe.\n }\n }\n\n source.on('error', onerror);\n dest.on('error', onerror);\n\n // remove all the event listeners that were added.\n function cleanup() {\n source.removeListener('data', ondata);\n dest.removeListener('drain', ondrain);\n\n source.removeListener('end', onend);\n source.removeListener('close', onclose);\n\n source.removeListener('error', onerror);\n dest.removeListener('error', onerror);\n\n source.removeListener('end', cleanup);\n source.removeListener('close', cleanup);\n\n dest.removeListener('close', cleanup);\n }\n\n source.on('end', cleanup);\n source.on('close', cleanup);\n\n dest.on('close', cleanup);\n\n dest.emit('pipe', source);\n\n // Allow for unix-like usage: A.pipe(B).pipe(C)\n return dest;\n};\n","'use strict';\n\nif (!process.version ||\n process.version.indexOf('v0.') === 0 ||\n process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) {\n module.exports = { nextTick: nextTick };\n} else {\n module.exports = process\n}\n\nfunction nextTick(fn, arg1, arg2, arg3) {\n if (typeof fn !== 'function') {\n throw new TypeError('\"callback\" argument must be a function');\n }\n var len = arguments.length;\n var args, i;\n switch (len) {\n case 0:\n case 1:\n return process.nextTick(fn);\n case 2:\n return process.nextTick(function afterTickOne() {\n fn.call(null, arg1);\n });\n case 3:\n return process.nextTick(function afterTickTwo() {\n fn.call(null, arg1, arg2);\n });\n case 4:\n return process.nextTick(function afterTickThree() {\n fn.call(null, arg1, arg2, arg3);\n });\n default:\n args = new Array(len - 1);\n i = 0;\n while (i < args.length) {\n args[i++] = arguments[i];\n }\n return process.nextTick(function afterTick() {\n fn.apply(null, args);\n });\n }\n}\n\n","// Copyright 2015 Joyent, Inc.\n\nmodule.exports = {\n\tread: read,\n\twrite: write\n};\n\nvar assert = require('assert-plus');\nvar asn1 = require('asn1');\nvar crypto = require('crypto');\nvar Buffer = require('safer-buffer').Buffer;\nvar algs = require('../algs');\nvar utils = require('../utils');\nvar Key = require('../key');\nvar PrivateKey = require('../private-key');\n\nvar pkcs1 = require('./pkcs1');\nvar pkcs8 = require('./pkcs8');\nvar sshpriv = require('./ssh-private');\nvar rfc4253 = require('./rfc4253');\n\nvar errors = require('../errors');\n\n/*\n * For reading we support both PKCS#1 and PKCS#8. If we find a private key,\n * we just take the public component of it and use that.\n */\nfunction read(buf, options, forceType) {\n\tvar input = buf;\n\tif (typeof (buf) !== 'string') {\n\t\tassert.buffer(buf, 'buf');\n\t\tbuf = buf.toString('ascii');\n\t}\n\n\tvar lines = buf.trim().split('\\n');\n\n\tvar m = lines[0].match(/*JSSTYLED*/\n\t /[-]+[ ]*BEGIN ([A-Z0-9][A-Za-z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/);\n\tassert.ok(m, 'invalid PEM header');\n\n\tvar m2 = lines[lines.length - 1].match(/*JSSTYLED*/\n\t /[-]+[ ]*END ([A-Z0-9][A-Za-z0-9]+ )?(PUBLIC|PRIVATE) KEY[ ]*[-]+/);\n\tassert.ok(m2, 'invalid PEM footer');\n\n\t/* Begin and end banners must match key type */\n\tassert.equal(m[2], m2[2]);\n\tvar type = m[2].toLowerCase();\n\n\tvar alg;\n\tif (m[1]) {\n\t\t/* They also must match algorithms, if given */\n\t\tassert.equal(m[1], m2[1], 'PEM header and footer mismatch');\n\t\talg = m[1].trim();\n\t}\n\n\tvar headers = {};\n\twhile (true) {\n\t\tlines = lines.slice(1);\n\t\tm = lines[0].match(/*JSSTYLED*/\n\t\t /^([A-Za-z0-9-]+): (.+)$/);\n\t\tif (!m)\n\t\t\tbreak;\n\t\theaders[m[1].toLowerCase()] = m[2];\n\t}\n\n\tvar cipher, key, iv;\n\tif (headers['proc-type']) {\n\t\tvar parts = headers['proc-type'].split(',');\n\t\tif (parts[0] === '4' && parts[1] === 'ENCRYPTED') {\n\t\t\tif (typeof (options.passphrase) === 'string') {\n\t\t\t\toptions.passphrase = Buffer.from(\n\t\t\t\t options.passphrase, 'utf-8');\n\t\t\t}\n\t\t\tif (!Buffer.isBuffer(options.passphrase)) {\n\t\t\t\tthrow (new errors.KeyEncryptedError(\n\t\t\t\t options.filename, 'PEM'));\n\t\t\t} else {\n\t\t\t\tparts = headers['dek-info'].split(',');\n\t\t\t\tassert.ok(parts.length === 2);\n\t\t\t\tcipher = parts[0].toLowerCase();\n\t\t\t\tiv = Buffer.from(parts[1], 'hex');\n\t\t\t\tkey = utils.opensslKeyDeriv(cipher, iv,\n\t\t\t\t options.passphrase, 1).key;\n\t\t\t}\n\t\t}\n\t}\n\n\t/* Chop off the first and last lines */\n\tlines = lines.slice(0, -1).join('');\n\tbuf = Buffer.from(lines, 'base64');\n\n\tif (cipher && key && iv) {\n\t\tvar cipherStream = crypto.createDecipheriv(cipher, key, iv);\n\t\tvar chunk, chunks = [];\n\t\tcipherStream.once('error', function (e) {\n\t\t\tif (e.toString().indexOf('bad decrypt') !== -1) {\n\t\t\t\tthrow (new Error('Incorrect passphrase ' +\n\t\t\t\t 'supplied, could not decrypt key'));\n\t\t\t}\n\t\t\tthrow (e);\n\t\t});\n\t\tcipherStream.write(buf);\n\t\tcipherStream.end();\n\t\twhile ((chunk = cipherStream.read()) !== null)\n\t\t\tchunks.push(chunk);\n\t\tbuf = Buffer.concat(chunks);\n\t}\n\n\t/* The new OpenSSH internal format abuses PEM headers */\n\tif (alg && alg.toLowerCase() === 'openssh')\n\t\treturn (sshpriv.readSSHPrivate(type, buf, options));\n\tif (alg && alg.toLowerCase() === 'ssh2')\n\t\treturn (rfc4253.readType(type, buf, options));\n\n\tvar der = new asn1.BerReader(buf);\n\tder.originalInput = input;\n\n\t/*\n\t * All of the PEM file types start with a sequence tag, so chop it\n\t * off here\n\t */\n\tder.readSequence();\n\n\t/* PKCS#1 type keys name an algorithm in the banner explicitly */\n\tif (alg) {\n\t\tif (forceType)\n\t\t\tassert.strictEqual(forceType, 'pkcs1');\n\t\treturn (pkcs1.readPkcs1(alg, type, der));\n\t} else {\n\t\tif (forceType)\n\t\t\tassert.strictEqual(forceType, 'pkcs8');\n\t\treturn (pkcs8.readPkcs8(alg, type, der));\n\t}\n}\n\nfunction write(key, options, type) {\n\tassert.object(key);\n\n\tvar alg = {\n\t 'ecdsa': 'EC',\n\t 'rsa': 'RSA',\n\t 'dsa': 'DSA',\n\t 'ed25519': 'EdDSA'\n\t}[key.type];\n\tvar header;\n\n\tvar der = new asn1.BerWriter();\n\n\tif (PrivateKey.isPrivateKey(key)) {\n\t\tif (type && type === 'pkcs8') {\n\t\t\theader = 'PRIVATE KEY';\n\t\t\tpkcs8.writePkcs8(der, key);\n\t\t} else {\n\t\t\tif (type)\n\t\t\t\tassert.strictEqual(type, 'pkcs1');\n\t\t\theader = alg + ' PRIVATE KEY';\n\t\t\tpkcs1.writePkcs1(der, key);\n\t\t}\n\n\t} else if (Key.isKey(key)) {\n\t\tif (type && type === 'pkcs1') {\n\t\t\theader = alg + ' PUBLIC KEY';\n\t\t\tpkcs1.writePkcs1(der, key);\n\t\t} else {\n\t\t\tif (type)\n\t\t\t\tassert.strictEqual(type, 'pkcs8');\n\t\t\theader = 'PUBLIC KEY';\n\t\t\tpkcs8.writePkcs8(der, key);\n\t\t}\n\n\t} else {\n\t\tthrow (new Error('key is not a Key or PrivateKey'));\n\t}\n\n\tvar tmp = der.buffer.toString('base64');\n\tvar len = tmp.length + (tmp.length / 64) +\n\t 18 + 16 + header.length*2 + 10;\n\tvar buf = Buffer.alloc(len);\n\tvar o = 0;\n\to += buf.write('-----BEGIN ' + header + '-----\\n', o);\n\tfor (var i = 0; i < tmp.length; ) {\n\t\tvar limit = i + 64;\n\t\tif (limit > tmp.length)\n\t\t\tlimit = tmp.length;\n\t\to += buf.write(tmp.slice(i, limit), o);\n\t\tbuf[o++] = 10;\n\t\ti = limit;\n\t}\n\to += buf.write('-----END ' + header + '-----\\n', o);\n\n\treturn (buf.slice(0, o));\n}\n","const assert = require(\"assert\");\nconst GenUtils = require(\"./GenUtils\");\nconst MoneroError = require(\"./MoneroError\");\n\n/**\n * Collection of helper utilities for the library.\n * \n * @hideconstructor\n */\nclass LibraryUtils {\n \n /**\n * Get the total memory used by WebAssembly.\n * \n * @return {int} the total memory used by WebAssembly\n */\n static async getWasmMemoryUsed() {\n let total = 0;\n if (LibraryUtils.WORKER) total += await LibraryUtils.invokeWorker(GenUtils.getUUID(), \"getWasmMemoryUsed\", []);\n if (LibraryUtils.getWasmModule() && LibraryUtils.getWasmModule().HEAP8) total += LibraryUtils.getWasmModule().HEAP8.length;\n return total;\n }\n \n /**\n * Get the WebAssembly module in the current context (nodejs, browser main thread or worker).\n */\n static getWasmModule() {\n return LibraryUtils.WASM_MODULE;\n }\n \n /**\n * Load the WebAssembly keys module with caching.\n */\n static async loadKeysModule() {\n \n // use cache if suitable, core module supersedes keys module because it is superset\n if (LibraryUtils.WASM_MODULE) return LibraryUtils.WASM_MODULE;\n \n // load module\n delete LibraryUtils.WASM_MODULE;\n LibraryUtils.WASM_MODULE = require(\"../../../../dist/monero_core_keys\")();\n return new Promise(function(resolve, reject) {\n LibraryUtils.WASM_MODULE.then(module => {\n LibraryUtils.WASM_MODULE = module\n delete LibraryUtils.WASM_MODULE.then;\n LibraryUtils._initWasmModule(LibraryUtils.WASM_MODULE);\n resolve(LibraryUtils.WASM_MODULE);\n });\n });\n }\n \n /**\n * Load the WebAssembly core module with caching.\n * \n * The core module is a superset of the keys module and overrides it.\n * \n * TODO: this is separate static function from loadKeysModule() because webpack cannot bundle WebWorker using runtime param for conditional import\n */\n static async loadCoreModule() {\n \n // use cache if suitable, core module supersedes keys module because it is superset\n if (LibraryUtils.WASM_MODULE && LibraryUtils.CORE_LOADED) return LibraryUtils.WASM_MODULE;\n \n // load module\n delete LibraryUtils.WASM_MODULE;\n LibraryUtils.WASM_MODULE = require(\"../../../../dist/monero_core\")();\n return new Promise(function(resolve, reject) {\n LibraryUtils.WASM_MODULE.then(module => {\n LibraryUtils.WASM_MODULE = module\n delete LibraryUtils.WASM_MODULE.then;\n LibraryUtils.CORE_LOADED = true;\n LibraryUtils._initWasmModule(LibraryUtils.WASM_MODULE);\n resolve(LibraryUtils.WASM_MODULE);\n });\n });\n }\n \n /**\n * Private helper to initialize the wasm module with data structures to synchronize access.\n */\n static _initWasmModule(wasmModule) {\n \n // initialize data structure to synchronize access to wasm module\n const async = require(\"async\");\n wasmModule.taskQueue = async.queue(function(asyncFn, callback) {\n if (asyncFn.then) asyncFn.then(resp => { callback(resp); }).catch(err => { callback(undefined, err); });\n else asyncFn().then(resp => { callback(resp); }).catch(err => { callback(undefined, err); });\n }, 1);\n \n // initialize method to synchronize access to wasm module\n wasmModule.queueTask = async function(asyncFn) {\n return new Promise(function(resolve, reject) {\n wasmModule.taskQueue.push(asyncFn, function(resp, err) {\n if (err !== undefined) reject(err);\n else resolve(resp);\n });\n });\n }\n }\n \n /**\n * Register a function by id which informs if unauthorized requests (e.g.\n * self-signed certificates) should be rejected.\n * \n * @param {string} fnId - unique identifier for the function\n * @param {function} fn - function to inform if unauthorized requests should be rejected\n */\n static setRejectUnauthorizedFn(fnId, fn) {\n if (!LibraryUtils.REJECT_UNAUTHORIZED_FNS) LibraryUtils.REJECT_UNAUTHORIZED_FNS = [];\n if (fn === undefined) delete LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId];\n else LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId] = fn;\n }\n \n /**\n * Indicate if unauthorized requests should be rejected.\n * \n * @param {string} fnId - uniquely identifies the function\n */\n static isRejectUnauthorized(fnId) {\n if (!LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId]) throw new Error(\"No function registered with id \" + fnId + \" to inform if unauthorized reqs should be rejected\");\n return LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId]();\n }\n \n /**\n * Get a singleton instance of a web worker to share.\n * \n * @return {Worker} a worker to share among wallet instances\n */\n static getWorker() {\n \n // one time initialization\n if (!LibraryUtils.WORKER) {\n LibraryUtils.WORKER = new Worker(\"MoneroWebWorker.dist.js\");\n LibraryUtils.WORKER_OBJECTS = {}; // store per object running in the worker\n \n // catch worker messages\n LibraryUtils.WORKER.onmessage = function(e) {\n \n // lookup object id, callback function, and this arg\n let thisArg = null;\n let callbackFn = LibraryUtils.WORKER_OBJECTS[e.data[0]].callbacks[e.data[1]]; // look up by object id then by function name\n if (callbackFn === undefined) throw new Error(\"No worker callback function defined for key '\" + e.data[1] + \"'\");\n if (callbackFn instanceof Array) { // this arg may be stored with callback function\n thisArg = callbackFn[1];\n callbackFn = callbackFn[0];\n }\n \n // invoke callback function with this arg and arguments\n callbackFn.apply(thisArg, e.data.slice(2));\n }\n }\n return LibraryUtils.WORKER;\n }\n \n /**\n * Invoke a web worker function and get the result with error handling.\n * \n * @param {objectId} identifies the worker object to invoke\n * @param {string} fnName is the name of the function to invoke\n * @param {Object[]} args are function arguments to invoke with\n * @return {Promise} resolves with response payload from the worker or an error\n */\n static async invokeWorker(objectId, fnName, args) {\n assert(fnName.length >= 2);\n let worker = LibraryUtils.getWorker();\n if (!LibraryUtils.WORKER_OBJECTS[objectId]) LibraryUtils.WORKER_OBJECTS[objectId] = {callbacks: {}};\n return new Promise(function(resolve, reject) {\n LibraryUtils.WORKER_OBJECTS[objectId].callbacks[\"on\" + fnName.charAt(0).toUpperCase() + fnName.substring(1)] = function(resp) { // TODO: this defines function once per callback\n resp ? (resp.error ? reject(new MoneroError(resp.error)) : resolve(resp.result)) : resolve();\n };\n worker.postMessage([objectId, fnName].concat(args === undefined ? [] : GenUtils.listify(args)));\n });\n }\n}\n\nmodule.exports = LibraryUtils;","// .dirname, .basename, and .extname methods are extracted from Node.js v8.11.1,\n// backported and transplited with Babel, with backwards-compat fixes\n\n// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// resolves . and .. elements in a path array with directory names there\n// must be no slashes, empty elements, or device names (c:\\) in the array\n// (so also no leading and trailing slashes - it does not distinguish\n// relative and absolute paths)\nfunction normalizeArray(parts, allowAboveRoot) {\n // if the path tries to go above the root, `up` ends up > 0\n var up = 0;\n for (var i = parts.length - 1; i >= 0; i--) {\n var last = parts[i];\n if (last === '.') {\n parts.splice(i, 1);\n } else if (last === '..') {\n parts.splice(i, 1);\n up++;\n } else if (up) {\n parts.splice(i, 1);\n up--;\n }\n }\n\n // if the path is allowed to go above the root, restore leading ..s\n if (allowAboveRoot) {\n for (; up--; up) {\n parts.unshift('..');\n }\n }\n\n return parts;\n}\n\n// path.resolve([from ...], to)\n// posix version\nexports.resolve = function() {\n var resolvedPath = '',\n resolvedAbsolute = false;\n\n for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n var path = (i >= 0) ? arguments[i] : process.cwd();\n\n // Skip empty and invalid entries\n if (typeof path !== 'string') {\n throw new TypeError('Arguments to path.resolve must be strings');\n } else if (!path) {\n continue;\n }\n\n resolvedPath = path + '/' + resolvedPath;\n resolvedAbsolute = path.charAt(0) === '/';\n }\n\n // At this point the path should be resolved to a full absolute path, but\n // handle relative paths to be safe (might happen when process.cwd() fails)\n\n // Normalize the path\n resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {\n return !!p;\n }), !resolvedAbsolute).join('/');\n\n return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';\n};\n\n// path.normalize(path)\n// posix version\nexports.normalize = function(path) {\n var isAbsolute = exports.isAbsolute(path),\n trailingSlash = substr(path, -1) === '/';\n\n // Normalize the path\n path = normalizeArray(filter(path.split('/'), function(p) {\n return !!p;\n }), !isAbsolute).join('/');\n\n if (!path && !isAbsolute) {\n path = '.';\n }\n if (path && trailingSlash) {\n path += '/';\n }\n\n return (isAbsolute ? '/' : '') + path;\n};\n\n// posix version\nexports.isAbsolute = function(path) {\n return path.charAt(0) === '/';\n};\n\n// posix version\nexports.join = function() {\n var paths = Array.prototype.slice.call(arguments, 0);\n return exports.normalize(filter(paths, function(p, index) {\n if (typeof p !== 'string') {\n throw new TypeError('Arguments to path.join must be strings');\n }\n return p;\n }).join('/'));\n};\n\n\n// path.relative(from, to)\n// posix version\nexports.relative = function(from, to) {\n from = exports.resolve(from).substr(1);\n to = exports.resolve(to).substr(1);\n\n function trim(arr) {\n var start = 0;\n for (; start < arr.length; start++) {\n if (arr[start] !== '') break;\n }\n\n var end = arr.length - 1;\n for (; end >= 0; end--) {\n if (arr[end] !== '') break;\n }\n\n if (start > end) return [];\n return arr.slice(start, end - start + 1);\n }\n\n var fromParts = trim(from.split('/'));\n var toParts = trim(to.split('/'));\n\n var length = Math.min(fromParts.length, toParts.length);\n var samePartsLength = length;\n for (var i = 0; i < length; i++) {\n if (fromParts[i] !== toParts[i]) {\n samePartsLength = i;\n break;\n }\n }\n\n var outputParts = [];\n for (var i = samePartsLength; i < fromParts.length; i++) {\n outputParts.push('..');\n }\n\n outputParts = outputParts.concat(toParts.slice(samePartsLength));\n\n return outputParts.join('/');\n};\n\nexports.sep = '/';\nexports.delimiter = ':';\n\nexports.dirname = function (path) {\n if (typeof path !== 'string') path = path + '';\n if (path.length === 0) return '.';\n var code = path.charCodeAt(0);\n var hasRoot = code === 47 /*/*/;\n var end = -1;\n var matchedSlash = true;\n for (var i = path.length - 1; i >= 1; --i) {\n code = path.charCodeAt(i);\n if (code === 47 /*/*/) {\n if (!matchedSlash) {\n end = i;\n break;\n }\n } else {\n // We saw the first non-path separator\n matchedSlash = false;\n }\n }\n\n if (end === -1) return hasRoot ? '/' : '.';\n if (hasRoot && end === 1) {\n // return '//';\n // Backwards-compat fix:\n return '/';\n }\n return path.slice(0, end);\n};\n\nfunction basename(path) {\n if (typeof path !== 'string') path = path + '';\n\n var start = 0;\n var end = -1;\n var matchedSlash = true;\n var i;\n\n for (i = path.length - 1; i >= 0; --i) {\n if (path.charCodeAt(i) === 47 /*/*/) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n start = i + 1;\n break;\n }\n } else if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // path component\n matchedSlash = false;\n end = i + 1;\n }\n }\n\n if (end === -1) return '';\n return path.slice(start, end);\n}\n\n// Uses a mixed approach for backwards-compatibility, as ext behavior changed\n// in new Node.js versions, so only basename() above is backported here\nexports.basename = function (path, ext) {\n var f = basename(path);\n if (ext && f.substr(-1 * ext.length) === ext) {\n f = f.substr(0, f.length - ext.length);\n }\n return f;\n};\n\nexports.extname = function (path) {\n if (typeof path !== 'string') path = path + '';\n var startDot = -1;\n var startPart = 0;\n var end = -1;\n var matchedSlash = true;\n // Track the state of characters (if any) we see before our first dot and\n // after any path separator we find\n var preDotState = 0;\n for (var i = path.length - 1; i >= 0; --i) {\n var code = path.charCodeAt(i);\n if (code === 47 /*/*/) {\n // If we reached a path separator that was not part of a set of path\n // separators at the end of the string, stop now\n if (!matchedSlash) {\n startPart = i + 1;\n break;\n }\n continue;\n }\n if (end === -1) {\n // We saw the first non-path separator, mark this as the end of our\n // extension\n matchedSlash = false;\n end = i + 1;\n }\n if (code === 46 /*.*/) {\n // If this is our first dot, mark it as the start of our extension\n if (startDot === -1)\n startDot = i;\n else if (preDotState !== 1)\n preDotState = 1;\n } else if (startDot !== -1) {\n // We saw a non-dot and non-path separator before our dot, so we should\n // have a good chance at having a non-empty extension\n preDotState = -1;\n }\n }\n\n if (startDot === -1 || end === -1 ||\n // We saw a non-dot character immediately before the dot\n preDotState === 0 ||\n // The (right-most) trimmed path component is exactly '..'\n preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {\n return '';\n }\n return path.slice(startDot, end);\n};\n\nfunction filter (xs, f) {\n if (xs.filter) return xs.filter(f);\n var res = [];\n for (var i = 0; i < xs.length; i++) {\n if (f(xs[i], i, xs)) res.push(xs[i]);\n }\n return res;\n}\n\n// String.prototype.substr - negative index don't work in IE8\nvar substr = 'ab'.substr(-1) === 'b'\n ? function (str, start, len) { return str.substr(start, len) }\n : function (str, start, len) {\n if (start < 0) start = str.length + start;\n return str.substr(start, len);\n }\n;\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// a duplex stream is just a stream that is both readable and writable.\n// Since JS doesn't have multiple prototypal inheritance, this class\n// prototypally inherits from Readable, and then parasitically from\n// Writable.\n\n'use strict';\n\n/**/\n\nvar pna = require('process-nextick-args');\n/**/\n\n/**/\nvar objectKeys = Object.keys || function (obj) {\n var keys = [];\n for (var key in obj) {\n keys.push(key);\n }return keys;\n};\n/**/\n\nmodule.exports = Duplex;\n\n/**/\nvar util = Object.create(require('core-util-is'));\nutil.inherits = require('inherits');\n/**/\n\nvar Readable = require('./_stream_readable');\nvar Writable = require('./_stream_writable');\n\nutil.inherits(Duplex, Readable);\n\n{\n // avoid scope creep, the keys array can then be collected\n var keys = objectKeys(Writable.prototype);\n for (var v = 0; v < keys.length; v++) {\n var method = keys[v];\n if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];\n }\n}\n\nfunction Duplex(options) {\n if (!(this instanceof Duplex)) return new Duplex(options);\n\n Readable.call(this, options);\n Writable.call(this, options);\n\n if (options && options.readable === false) this.readable = false;\n\n if (options && options.writable === false) this.writable = false;\n\n this.allowHalfOpen = true;\n if (options && options.allowHalfOpen === false) this.allowHalfOpen = false;\n\n this.once('end', onend);\n}\n\nObject.defineProperty(Duplex.prototype, 'writableHighWaterMark', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function () {\n return this._writableState.highWaterMark;\n }\n});\n\n// the no-half-open enforcer\nfunction onend() {\n // if we allow half-open state, or if the writable side ended,\n // then we're ok.\n if (this.allowHalfOpen || this._writableState.ended) return;\n\n // no more data can be written.\n // But allow more writes to happen in this tick.\n pna.nextTick(onEndNT, this);\n}\n\nfunction onEndNT(self) {\n self.end();\n}\n\nObject.defineProperty(Duplex.prototype, 'destroyed', {\n get: function () {\n if (this._readableState === undefined || this._writableState === undefined) {\n return false;\n }\n return this._readableState.destroyed && this._writableState.destroyed;\n },\n set: function (value) {\n // we ignore the value if the stream\n // has not been initialized yet\n if (this._readableState === undefined || this._writableState === undefined) {\n return;\n }\n\n // backward compatibility, the user is explicitly\n // managing destroyed\n this._readableState.destroyed = value;\n this._writableState.destroyed = value;\n }\n});\n\nDuplex.prototype._destroy = function (err, cb) {\n this.push(null);\n this.end();\n\n pna.nextTick(cb, err);\n};","// Copyright 2015 Joyent, Inc.\n\nmodule.exports = {\n\tread: read.bind(undefined, false, undefined),\n\treadType: read.bind(undefined, false),\n\twrite: write,\n\t/* semi-private api, used by sshpk-agent */\n\treadPartial: read.bind(undefined, true),\n\n\t/* shared with ssh format */\n\treadInternal: read,\n\tkeyTypeToAlg: keyTypeToAlg,\n\talgToKeyType: algToKeyType\n};\n\nvar assert = require('assert-plus');\nvar Buffer = require('safer-buffer').Buffer;\nvar algs = require('../algs');\nvar utils = require('../utils');\nvar Key = require('../key');\nvar PrivateKey = require('../private-key');\nvar SSHBuffer = require('../ssh-buffer');\n\nfunction algToKeyType(alg) {\n\tassert.string(alg);\n\tif (alg === 'ssh-dss')\n\t\treturn ('dsa');\n\telse if (alg === 'ssh-rsa')\n\t\treturn ('rsa');\n\telse if (alg === 'ssh-ed25519')\n\t\treturn ('ed25519');\n\telse if (alg === 'ssh-curve25519')\n\t\treturn ('curve25519');\n\telse if (alg.match(/^ecdsa-sha2-/))\n\t\treturn ('ecdsa');\n\telse\n\t\tthrow (new Error('Unknown algorithm ' + alg));\n}\n\nfunction keyTypeToAlg(key) {\n\tassert.object(key);\n\tif (key.type === 'dsa')\n\t\treturn ('ssh-dss');\n\telse if (key.type === 'rsa')\n\t\treturn ('ssh-rsa');\n\telse if (key.type === 'ed25519')\n\t\treturn ('ssh-ed25519');\n\telse if (key.type === 'curve25519')\n\t\treturn ('ssh-curve25519');\n\telse if (key.type === 'ecdsa')\n\t\treturn ('ecdsa-sha2-' + key.part.curve.data.toString());\n\telse\n\t\tthrow (new Error('Unknown key type ' + key.type));\n}\n\nfunction read(partial, type, buf, options) {\n\tif (typeof (buf) === 'string')\n\t\tbuf = Buffer.from(buf);\n\tassert.buffer(buf, 'buf');\n\n\tvar key = {};\n\n\tvar parts = key.parts = [];\n\tvar sshbuf = new SSHBuffer({buffer: buf});\n\n\tvar alg = sshbuf.readString();\n\tassert.ok(!sshbuf.atEnd(), 'key must have at least one part');\n\n\tkey.type = algToKeyType(alg);\n\n\tvar partCount = algs.info[key.type].parts.length;\n\tif (type && type === 'private')\n\t\tpartCount = algs.privInfo[key.type].parts.length;\n\n\twhile (!sshbuf.atEnd() && parts.length < partCount)\n\t\tparts.push(sshbuf.readPart());\n\twhile (!partial && !sshbuf.atEnd())\n\t\tparts.push(sshbuf.readPart());\n\n\tassert.ok(parts.length >= 1,\n\t 'key must have at least one part');\n\tassert.ok(partial || sshbuf.atEnd(),\n\t 'leftover bytes at end of key');\n\n\tvar Constructor = Key;\n\tvar algInfo = algs.info[key.type];\n\tif (type === 'private' || algInfo.parts.length !== parts.length) {\n\t\talgInfo = algs.privInfo[key.type];\n\t\tConstructor = PrivateKey;\n\t}\n\tassert.strictEqual(algInfo.parts.length, parts.length);\n\n\tif (key.type === 'ecdsa') {\n\t\tvar res = /^ecdsa-sha2-(.+)$/.exec(alg);\n\t\tassert.ok(res !== null);\n\t\tassert.strictEqual(res[1], parts[0].data.toString());\n\t}\n\n\tvar normalized = true;\n\tfor (var i = 0; i < algInfo.parts.length; ++i) {\n\t\tvar p = parts[i];\n\t\tp.name = algInfo.parts[i];\n\t\t/*\n\t\t * OpenSSH stores ed25519 \"private\" keys as seed + public key\n\t\t * concat'd together (k followed by A). We want to keep them\n\t\t * separate for other formats that don't do this.\n\t\t */\n\t\tif (key.type === 'ed25519' && p.name === 'k')\n\t\t\tp.data = p.data.slice(0, 32);\n\n\t\tif (p.name !== 'curve' && algInfo.normalize !== false) {\n\t\t\tvar nd;\n\t\t\tif (key.type === 'ed25519') {\n\t\t\t\tnd = utils.zeroPadToLength(p.data, 32);\n\t\t\t} else {\n\t\t\t\tnd = utils.mpNormalize(p.data);\n\t\t\t}\n\t\t\tif (nd.toString('binary') !==\n\t\t\t p.data.toString('binary')) {\n\t\t\t\tp.data = nd;\n\t\t\t\tnormalized = false;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (normalized)\n\t\tkey._rfc4253Cache = sshbuf.toBuffer();\n\n\tif (partial && typeof (partial) === 'object') {\n\t\tpartial.remainder = sshbuf.remainder();\n\t\tpartial.consumed = sshbuf._offset;\n\t}\n\n\treturn (new Constructor(key));\n}\n\nfunction write(key, options) {\n\tassert.object(key);\n\n\tvar alg = keyTypeToAlg(key);\n\tvar i;\n\n\tvar algInfo = algs.info[key.type];\n\tif (PrivateKey.isPrivateKey(key))\n\t\talgInfo = algs.privInfo[key.type];\n\tvar parts = algInfo.parts;\n\n\tvar buf = new SSHBuffer({});\n\n\tbuf.writeString(alg);\n\n\tfor (i = 0; i < parts.length; ++i) {\n\t\tvar data = key.part[parts[i]].data;\n\t\tif (algInfo.normalize !== false) {\n\t\t\tif (key.type === 'ed25519')\n\t\t\t\tdata = utils.zeroPadToLength(data, 32);\n\t\t\telse\n\t\t\t\tdata = utils.mpNormalize(data);\n\t\t}\n\t\tif (key.type === 'ed25519' && parts[i] === 'k')\n\t\t\tdata = Buffer.concat([data, key.part.A.data]);\n\t\tbuf.writeBuffer(data);\n\t}\n\n\treturn (buf.toBuffer());\n}\n",";(function (root, factory, undef) {\n\tif (typeof exports === \"object\") {\n\t\t// CommonJS\n\t\tmodule.exports = exports = factory(require(\"./core\"), require(\"./sha1\"), require(\"./hmac\"));\n\t}\n\telse if (typeof define === \"function\" && define.amd) {\n\t\t// AMD\n\t\tdefine([\"./core\", \"./sha1\", \"./hmac\"], 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 () {\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 WordArray = C_lib.WordArray;\n\t var C_algo = C.algo;\n\t var MD5 = C_algo.MD5;\n\n\t /**\n\t * This key derivation function is meant to conform with EVP_BytesToKey.\n\t * www.openssl.org/docs/crypto/EVP_BytesToKey.html\n\t */\n\t var EvpKDF = C_algo.EvpKDF = Base.extend({\n\t /**\n\t * Configuration options.\n\t *\n\t * @property {number} keySize The key size in words to generate. Default: 4 (128 bits)\n\t * @property {Hasher} hasher The hash algorithm to use. Default: MD5\n\t * @property {number} iterations The number of iterations to perform. Default: 1\n\t */\n\t cfg: Base.extend({\n\t keySize: 128/32,\n\t hasher: MD5,\n\t iterations: 1\n\t }),\n\n\t /**\n\t * Initializes a newly created key derivation function.\n\t *\n\t * @param {Object} cfg (Optional) The configuration options to use for the derivation.\n\t *\n\t * @example\n\t *\n\t * var kdf = CryptoJS.algo.EvpKDF.create();\n\t * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8 });\n\t * var kdf = CryptoJS.algo.EvpKDF.create({ keySize: 8, iterations: 1000 });\n\t */\n\t init: function (cfg) {\n\t this.cfg = this.cfg.extend(cfg);\n\t },\n\n\t /**\n\t * Derives a key from a password.\n\t *\n\t * @param {WordArray|string} password The password.\n\t * @param {WordArray|string} salt A salt.\n\t *\n\t * @return {WordArray} The derived key.\n\t *\n\t * @example\n\t *\n\t * var key = kdf.compute(password, salt);\n\t */\n\t compute: function (password, salt) {\n\t var block;\n\n\t // Shortcut\n\t var cfg = this.cfg;\n\n\t // Init hasher\n\t var hasher = cfg.hasher.create();\n\n\t // Initial values\n\t var derivedKey = WordArray.create();\n\n\t // Shortcuts\n\t var derivedKeyWords = derivedKey.words;\n\t var keySize = cfg.keySize;\n\t var iterations = cfg.iterations;\n\n\t // Generate key\n\t while (derivedKeyWords.length < keySize) {\n\t if (block) {\n\t hasher.update(block);\n\t }\n\t block = hasher.update(password).finalize(salt);\n\t hasher.reset();\n\n\t // Iterations\n\t for (var i = 1; i < iterations; i++) {\n\t block = hasher.finalize(block);\n\t hasher.reset();\n\t }\n\n\t derivedKey.concat(block);\n\t }\n\t derivedKey.sigBytes = keySize * 4;\n\n\t return derivedKey;\n\t }\n\t });\n\n\t /**\n\t * Derives a key from a password.\n\t *\n\t * @param {WordArray|string} password The password.\n\t * @param {WordArray|string} salt A salt.\n\t * @param {Object} cfg (Optional) The configuration options to use for this computation.\n\t *\n\t * @return {WordArray} The derived key.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var key = CryptoJS.EvpKDF(password, salt);\n\t * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8 });\n\t * var key = CryptoJS.EvpKDF(password, salt, { keySize: 8, iterations: 1000 });\n\t */\n\t C.EvpKDF = function (password, salt, cfg) {\n\t return EvpKDF.create(cfg).compute(password, salt);\n\t };\n\t}());\n\n\n\treturn CryptoJS.EvpKDF;\n\n}));","const assert = require(\"assert\");\nconst GenUtils = require(\"../../common/GenUtils\");\nconst MoneroBlockHeader = require(\"./MoneroBlockHeader\");\nconst MoneroTx = require(\"./MoneroTx\");\nconst MoneroTxQuery = require(\"../../wallet/model/MoneroTxQuery\");\nconst MoneroTxWallet = require(\"../../wallet/model/MoneroTxWallet\");\n\n/**\n * Models a Monero block in the blockchain.\n * \n * @extends {MoneroBlockHeader}\n */\nclass MoneroBlock extends MoneroBlockHeader {\n \n /**\n * Construct the model.\n * \n * @param {MoneroBlock|MoneroBlockHeader|object} state is existing state to initialize from (optional)\n * @param {MoneroBlock.DeserializationType} txType informs the tx deserialization type (MoneroTx, MoneroTxWallet, MoneroTxQuery)\n */\n constructor(state, txType) {\n super(state);\n state = this.state;\n \n // deserialize miner tx\n if (state.minerTx && !(state.minerTx instanceof MoneroTx)) state.minerTx = new MoneroTx(state.minerTx).setBlock(this);\n \n // deserialize non-miner txs\n if (state.txs) {\n for (let i = 0; i < state.txs.length; i++) {\n if (txType === MoneroBlock.DeserializationType.TX || txType === undefined) {\n if (!(state.txs[i] instanceof MoneroTx)) state.txs[i] = new MoneroTx(state.txs[i]).setBlock(this);\n } else if (txType === MoneroBlock.DeserializationType.TX_WALLET) {\n if (!(state.txs[i] instanceof MoneroTxWallet)) state.txs[i] = new MoneroTxWallet(state.txs[i]).setBlock(this);\n } else if (txType === MoneroBlock.DeserializationType.TX_QUERY) {\n if (!(state.txs[i] instanceof MoneroTxQuery)) state.txs[i] = new MoneroTxQuery(state.txs[i]).setBlock(this);\n } else {\n throw new Error(\"Unrecognized tx deserialization type: \" + txType);\n }\n }\n }\n }\n \n getHex() {\n return this.state.hex;\n }\n \n setHex(hex) {\n this.state.hex = hex;\n return this;\n }\n \n getMinerTx() {\n return this.state.minerTx;\n }\n \n setMinerTx(minerTx) {\n this.state.minerTx = minerTx;\n return this;\n }\n \n getTxs() {\n return this.state.txs;\n }\n \n setTxs(txs) {\n this.state.txs = txs;\n return this;\n }\n \n getTxHashes() {\n return this.state.txHashes;\n }\n \n setTxHashes(txHashes) {\n this.state.txHashes = txHashes;\n return this;\n }\n \n copy() {\n return new MoneroBlock(this);\n }\n \n toJson() {\n let json = super.toJson();\n if (this.getMinerTx()) json.minerTx = this.getMinerTx().toJson();\n if (this.getTxs()) {\n json.txs = [];\n for (let tx of this.getTxs()) json.txs.push(tx.toJson());\n }\n return json;\n }\n \n merge(block) {\n assert(block instanceof MoneroBlock);\n if (this === block) return this;\n \n // merge header fields\n super.merge(block);\n \n // merge reconcilable block extensions\n this.setHex(GenUtils.reconcile(this.getHex(), block.getHex()));\n this.setTxHashes(GenUtils.reconcile(this.getTxHashes(), block.getTxHashes()));\n \n // merge miner tx\n if (this.getMinerTx() === undefined) this.setMinerTx(block.getMinerTx());\n if (block.getMinerTx() !== undefined) {\n block.getMinerTx().setBlock(this);\n minerTx.merge(block.getMinerTx());\n }\n \n // merge non-miner txs\n if (block.getTxs() !== undefined) {\n for (let tx of block.getTxs()) {\n tx.setBlock(this);\n MoneroBlock._mergeTx(this.getTxs(), tx);\n }\n }\n\n return this;\n }\n \n toString(indent = 0) {\n let str = super.toString(indent) + \"\\n\";\n str += GenUtils.kvLine(\"Hex\", this.getHex(), indent);\n if (this.getTxs()) {\n str += GenUtils.kvLine(\"Txs\", \"\", indent);\n for (let tx of this.getTxs()) {\n str += tx.toString(indent + 1) + \"\\n\";\n }\n }\n if (this.getMinerTx()) {\n str += GenUtils.kvLine(\"Miner tx\", \"\", indent);\n str += this.getMinerTx().toString(indent + 1) + \"\\n\";\n }\n str += GenUtils.kvLine(\"Txs hashes\", this.getTxHashes(), indent);\n return str[str.length - 1] === \"\\n\" ? str.slice(0, str.length - 1) : str // strip last newline\n }\n \n // private helper to merge txs\n static _mergeTx(txs, tx) {\n for (let aTx of txs) {\n if (aTx.getHash() === tx.getHash()) {\n aTx.merge(tx);\n return;\n }\n }\n txs.push(tx);\n }\n}\n\nMoneroBlock.DeserializationType = {\n TX: 0,\n TX_WALLET: 1,\n TX_QUERY: 2\n}\n\nmodule.exports = MoneroBlock;","const assert = require(\"assert\");\nconst MoneroOutputQuery = require(\"./MoneroOutputQuery\");\nconst MoneroTransferQuery = require(\"./MoneroTransferQuery\");\nconst MoneroTxWallet = require(\"./MoneroTxWallet\");\n\n/**\n *

Configuration to query transactions.

\n * \n * @class\n * @extends {MoneroTxWallet}\n */\nclass MoneroTxQuery extends MoneroTxWallet {\n \n /**\n *

Construct the transaction query.

\n * \n *

Example:

\n * \n * \n * // get transactions with unlocked incoming transfers to account 0
\n * let txs = await wallet.getTxs({
\n *    isLocked: false,
\n *    transferQuery: {
\n *      isIncoming: true,
\n *      accountIndex: 0
\n *    }
\n * });\n *
\n * \n *

All configuration is optional. All transactions are returned except those that don't meet criteria defined in this query.

\n * \n * @param {object} config - tx query configuration\n * @param {string} config.hash - get a tx with this hash\n * @param {string[]} config.txHashes - get txs with these hashes\n * @param {int} config.height - get txs with this height\n * @param {int} config.minHeight - get txs with height greater than or equal to this height\n * @param {int} config.maxHeight - get txs with height less than or equal to this height\n * @param {boolean} config.isConfirmed - get confirmed or unconfirmed txs\n * @param {boolean} config.inTxPool - get txs in or out of the tx pool\n * @param {boolean} config.relay - get txs with the same relay status\n * @param {boolean} config.isRelayed - get relayed or non-relayed txs\n * @param {boolean} config.isFailed - get failed or non-failed txs\n * @param {boolean} config.isMinerTx - get miner or non-miner txs\n * @param {boolean} config.isLocked - get locked or unlocked txs\n * @param {boolean} config.isIncoming - get txs with or without incoming transfers\n * @param {boolean} config.isOutgoing - get txs with or without outgoing transfers\n * @param {string} config.paymentId - get txs with this payment ID\n * @param {string} config.paymentIds - get txs with a payment ID among these payment IDs\n * @param {boolean} config.hasPaymentId - get txs with or without payment IDs\n * @param {object|MoneroTransferQuery} config.transferQuery - get txs with transfers matching this transfer query\n * @param {object|MoneroOutputQuery} config.outputQuery - get txs with outputs matching this output query\n */\n constructor(config) {\n super(config);\n \n // deserialize if necessary\n if (this.state.transferQuery && !(this.state.transferQuery instanceof MoneroTransferQuery)) this.state.transferQuery = new MoneroTransferQuery(this.state.transferQuery);\n if (this.state.outputQuery && !(this.state.outputQuery instanceof MoneroOutputQuery)) this.state.outputQuery = new MoneroOutputQuery(this.state.outputQuery);\n \n // link cycles\n if (this.state.transferQuery) this.state.transferQuery.setTxQuery(this);\n if (this.state.outputQuery) this.state.outputQuery.setTxQuery(this);\n \n // alias 'hash' to hashes\n if (this.state.hash) {\n this.setHashes([this.state.hash]);\n delete this.state.hash;\n }\n }\n \n copy() {\n return new MoneroTxQuery(this);\n }\n \n toJson() {\n let json = Object.assign({}, this.state, super.toJson()); // merge json onto inherited state\n if (this.getTransferQuery()) json.transferQuery = this.getTransferQuery().toJson();\n if (this.getOutputQuery()) json.outputQuery = this.getOutputQuery().toJson();\n delete json.block; // do not serialize parent block\n return json;\n }\n \n isIncoming() {\n return this.state.isIncoming;\n }\n \n setIsIncoming(isIncoming) {\n this.state.isIncoming = isIncoming;\n return this;\n }\n \n isOutgoing() {\n return this.state.isOutgoing;\n }\n \n setIsOutgoing(isOutgoing) {\n this.state.isOutgoing = isOutgoing;\n return this;\n }\n\n getHashes() {\n return this.state.hashes;\n }\n\n setHashes(hashes) {\n this.state.hashes = hashes;\n return this;\n }\n \n setHash(hash) {\n if (hash === undefined) return this.setHashes(undefined);\n assert(typeof hash === \"string\");\n return this.setHashes([hash]);\n }\n \n hasPaymentId() {\n return this.state.hasPaymentId;\n }\n \n setHasPaymentId() {\n this.state.hasPaymentId = hasPaymentId;\n return this;\n }\n \n getPaymentIds() {\n return this.state.paymentIds;\n }\n\n setPaymentIds(paymentIds) {\n this.state.paymentIds = paymentIds;\n return this;\n }\n \n setPaymentId(paymentId) {\n if (paymentId === undefined) return this.setPaymentIds(undefined);\n assert(typeof paymentId === \"string\");\n return this.setPaymentIds([paymentId]);\n }\n \n getHeight() {\n return this.state.height;\n }\n \n setHeight(height) {\n this.state.height = height;\n return this;\n }\n \n getMinHeight() {\n return this.state.minHeight;\n }\n\n setMinHeight(minHeight) {\n this.state.minHeight = minHeight;\n return this;\n }\n\n getMaxHeight() {\n return this.state.maxHeight;\n }\n\n setMaxHeight(maxHeight) {\n this.state.maxHeight = maxHeight;\n return this;\n }\n \n getIncludeOutputs() {\n return this.state.includeOutputs;\n }\n\n setIncludeOutputs(includeOutputs) {\n this.state.includeOutputs = includeOutputs;\n return this;\n }\n \n getTransferQuery() {\n return this.state.transferQuery;\n }\n \n setTransferQuery(transferQuery) {\n this.state.transferQuery = transferQuery;\n if (transferQuery) transferQuery.state.txQuery = this;\n return this;\n }\n \n getOutputQuery() {\n return this.state.outputQuery;\n }\n \n setOutputQuery(outputQuery) {\n this.state.outputQuery = outputQuery;\n if (outputQuery) outputQuery.state.txQuery = this;\n return this;\n }\n \n meetsCriteria(tx, queryChildren) {\n if (!(tx instanceof MoneroTxWallet)) throw new Error(\"Tx not given to MoneroTxQuery.meetsCriteria(tx)\");\n if (queryChildren === undefined) queryChildren = true;\n \n // filter on tx\n if (this.getHash() !== undefined && this.getHash() !== tx.getHash()) return false;\n if (this.getPaymentId() !== undefined && this.getPaymentId() !== tx.getPaymentId()) return false;\n if (this.isConfirmed() !== undefined && this.isConfirmed() !== tx.isConfirmed()) return false;\n if (this.inTxPool() !== undefined && this.inTxPool() !== tx.inTxPool()) return false;\n if (this.getRelay() !== undefined && this.getRelay() !== tx.getRelay()) return false;\n if (this.isRelayed() !== undefined && this.isRelayed() !== tx.isRelayed()) return false;\n if (this.isFailed() !== undefined && this.isFailed() !== tx.isFailed()) return false;\n if (this.isMinerTx() !== undefined && this.isMinerTx() !== tx.isMinerTx()) return false;\n if (this.isLocked() !== undefined && this.isLocked() !== tx.isLocked()) return false;\n \n // filter on having a payment id\n if (this.hasPaymentId() !== undefined) {\n if (this.hasPaymentId() && tx.getPaymentId() === undefined) return false;\n if (!this.hasPaymentId() && tx.getPaymentId() !== undefined) return false;\n }\n \n // filter on incoming\n if (this.isIncoming() !== undefined) {\n if (this.isIncoming() && !tx.isIncoming()) return false;\n if (!this.isIncoming() && tx.isIncoming()) return false;\n }\n \n // filter on outgoing\n if (this.isOutgoing() !== undefined) {\n if (this.isOutgoing() && !tx.isOutgoing()) return false;\n if (!this.isOutgoing() && tx.isOutgoing()) return false;\n }\n \n // filter on remaining fields\n let txHeight = tx.getBlock() === undefined ? undefined : tx.getBlock().getHeight();\n if (this.getHashes() !== undefined && !this.getHashes().includes(tx.getHash())) return false;\n if (this.getPaymentIds() !== undefined && !this.getPaymentIds().includes(tx.getPaymentId())) return false;\n if (this.getHeight() !== undefined && (txHeight === undefined || txHeight !== this.getHeight())) return false;\n if (this.getMinHeight() !== undefined && (txHeight === undefined || txHeight < this.getMinHeight())) return false;\n if (this.getMaxHeight() !== undefined && (txHeight === undefined || txHeight > this.getMaxHeight())) return false;\n // TODO: filtering not complete\n \n // done if not querying transfers or outputs\n if (!queryChildren) return true;\n \n // at least one transfer must meet transfer filter if defined\n if (this.getTransferQuery()) {\n let matchFound = false;\n if (tx.getOutgoingTransfer() && this.getTransferQuery().meetsCriteria(tx.getOutgoingTransfer(), false)) matchFound = true;\n else if (tx.getIncomingTransfers()) {\n for (let incomingTransfer of tx.getIncomingTransfers()) {\n if (this.getTransferQuery().meetsCriteria(incomingTransfer, false)) {\n matchFound = true;\n break;\n }\n }\n }\n if (!matchFound) return false;\n }\n \n // at least one output must meet output query if defined\n if (this.getOutputQuery() !== undefined) {\n if (tx.getOutputs() === undefined || tx.getOutputs().length === 0) return false;\n let matchFound = false;\n for (let output of tx.getOutputs()) {\n if (this.getOutputQuery().meetsCriteria(output, false)) {\n matchFound = true;\n break;\n }\n }\n if (!matchFound) return false;\n }\n \n return true; // transaction meets filter criteria\n }\n}\n\nmodule.exports = MoneroTxQuery;","'use strict'\n\n// limit of Crypto.getRandomValues()\n// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues\nvar MAX_BYTES = 65536\n\n// Node supports requesting up to this number of bytes\n// https://github.com/nodejs/node/blob/master/lib/internal/crypto/random.js#L48\nvar MAX_UINT32 = 4294967295\n\nfunction oldBrowser () {\n throw new Error('Secure random number generation is not supported by this browser.\\nUse Chrome, Firefox or Internet Explorer 11')\n}\n\nvar Buffer = require('safe-buffer').Buffer\nvar crypto = global.crypto || global.msCrypto\n\nif (crypto && crypto.getRandomValues) {\n module.exports = randomBytes\n} else {\n module.exports = oldBrowser\n}\n\nfunction randomBytes (size, cb) {\n // phantomjs needs to throw\n if (size > MAX_UINT32) throw new RangeError('requested too many random bytes')\n\n var bytes = Buffer.allocUnsafe(size)\n\n if (size > 0) { // getRandomValues fails on IE if size == 0\n if (size > MAX_BYTES) { // this is the max bytes crypto.getRandomValues\n // can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues\n for (var generated = 0; generated < size; generated += MAX_BYTES) {\n // buffer.slice automatically checks if the end is past the end of\n // the buffer so we don't have to here\n crypto.getRandomValues(bytes.slice(generated, generated + MAX_BYTES))\n }\n } else {\n crypto.getRandomValues(bytes)\n }\n }\n\n if (typeof cb === 'function') {\n return process.nextTick(function () {\n cb(null, bytes)\n })\n }\n\n return bytes\n}\n","'use strict';\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }\n\nvar codes = {};\n\nfunction createErrorType(code, message, Base) {\n if (!Base) {\n Base = Error;\n }\n\n function getMessage(arg1, arg2, arg3) {\n if (typeof message === 'string') {\n return message;\n } else {\n return message(arg1, arg2, arg3);\n }\n }\n\n var NodeError =\n /*#__PURE__*/\n function (_Base) {\n _inheritsLoose(NodeError, _Base);\n\n function NodeError(arg1, arg2, arg3) {\n return _Base.call(this, getMessage(arg1, arg2, arg3)) || this;\n }\n\n return NodeError;\n }(Base);\n\n NodeError.prototype.name = Base.name;\n NodeError.prototype.code = code;\n codes[code] = NodeError;\n} // https://github.com/nodejs/node/blob/v10.8.0/lib/internal/errors.js\n\n\nfunction oneOf(expected, thing) {\n if (Array.isArray(expected)) {\n var len = expected.length;\n expected = expected.map(function (i) {\n return String(i);\n });\n\n if (len > 2) {\n return \"one of \".concat(thing, \" \").concat(expected.slice(0, len - 1).join(', '), \", or \") + expected[len - 1];\n } else if (len === 2) {\n return \"one of \".concat(thing, \" \").concat(expected[0], \" or \").concat(expected[1]);\n } else {\n return \"of \".concat(thing, \" \").concat(expected[0]);\n }\n } else {\n return \"of \".concat(thing, \" \").concat(String(expected));\n }\n} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith\n\n\nfunction startsWith(str, search, pos) {\n return str.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;\n} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith\n\n\nfunction endsWith(str, search, this_len) {\n if (this_len === undefined || this_len > str.length) {\n this_len = str.length;\n }\n\n return str.substring(this_len - search.length, this_len) === search;\n} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes\n\n\nfunction includes(str, search, start) {\n if (typeof start !== 'number') {\n start = 0;\n }\n\n if (start + search.length > str.length) {\n return false;\n } else {\n return str.indexOf(search, start) !== -1;\n }\n}\n\ncreateErrorType('ERR_INVALID_OPT_VALUE', function (name, value) {\n return 'The value \"' + value + '\" is invalid for option \"' + name + '\"';\n}, TypeError);\ncreateErrorType('ERR_INVALID_ARG_TYPE', function (name, expected, actual) {\n // determiner: 'must be' or 'must not be'\n var determiner;\n\n if (typeof expected === 'string' && startsWith(expected, 'not ')) {\n determiner = 'must not be';\n expected = expected.replace(/^not /, '');\n } else {\n determiner = 'must be';\n }\n\n var msg;\n\n if (endsWith(name, ' argument')) {\n // For cases like 'first argument'\n msg = \"The \".concat(name, \" \").concat(determiner, \" \").concat(oneOf(expected, 'type'));\n } else {\n var type = includes(name, '.') ? 'property' : 'argument';\n msg = \"The \\\"\".concat(name, \"\\\" \").concat(type, \" \").concat(determiner, \" \").concat(oneOf(expected, 'type'));\n }\n\n msg += \". Received type \".concat(typeof actual);\n return msg;\n}, TypeError);\ncreateErrorType('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF');\ncreateErrorType('ERR_METHOD_NOT_IMPLEMENTED', function (name) {\n return 'The ' + name + ' method is not implemented';\n});\ncreateErrorType('ERR_STREAM_PREMATURE_CLOSE', 'Premature close');\ncreateErrorType('ERR_STREAM_DESTROYED', function (name) {\n return 'Cannot call ' + name + ' after a stream was destroyed';\n});\ncreateErrorType('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times');\ncreateErrorType('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable');\ncreateErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end');\ncreateErrorType('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError);\ncreateErrorType('ERR_UNKNOWN_ENCODING', function (arg) {\n return 'Unknown encoding: ' + arg;\n}, TypeError);\ncreateErrorType('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event');\nmodule.exports.codes = codes;\n","if (typeof Object.create === 'function') {\n // implementation from standard node.js 'util' module\n module.exports = function inherits(ctor, superCtor) {\n if (superCtor) {\n ctor.super_ = superCtor\n ctor.prototype = Object.create(superCtor.prototype, {\n constructor: {\n value: ctor,\n enumerable: false,\n writable: true,\n configurable: true\n }\n })\n }\n };\n} else {\n // old school shim for old browsers\n module.exports = function inherits(ctor, superCtor) {\n if (superCtor) {\n ctor.super_ = superCtor\n var TempCtor = function () {}\n TempCtor.prototype = superCtor.prototype\n ctor.prototype = new TempCtor()\n ctor.prototype.constructor = ctor\n }\n }\n}\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n// a duplex stream is just a stream that is both readable and writable.\n// Since JS doesn't have multiple prototypal inheritance, this class\n// prototypally inherits from Readable, and then parasitically from\n// Writable.\n'use strict';\n/**/\n\nvar objectKeys = Object.keys || function (obj) {\n var keys = [];\n\n for (var key in obj) {\n keys.push(key);\n }\n\n return keys;\n};\n/**/\n\n\nmodule.exports = Duplex;\n\nvar Readable = require('./_stream_readable');\n\nvar Writable = require('./_stream_writable');\n\nrequire('inherits')(Duplex, Readable);\n\n{\n // Allow the keys array to be GC'ed.\n var keys = objectKeys(Writable.prototype);\n\n for (var v = 0; v < keys.length; v++) {\n var method = keys[v];\n if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];\n }\n}\n\nfunction Duplex(options) {\n if (!(this instanceof Duplex)) return new Duplex(options);\n Readable.call(this, options);\n Writable.call(this, options);\n this.allowHalfOpen = true;\n\n if (options) {\n if (options.readable === false) this.readable = false;\n if (options.writable === false) this.writable = false;\n\n if (options.allowHalfOpen === false) {\n this.allowHalfOpen = false;\n this.once('end', onend);\n }\n }\n}\n\nObject.defineProperty(Duplex.prototype, 'writableHighWaterMark', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._writableState.highWaterMark;\n }\n});\nObject.defineProperty(Duplex.prototype, 'writableBuffer', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._writableState && this._writableState.getBuffer();\n }\n});\nObject.defineProperty(Duplex.prototype, 'writableLength', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._writableState.length;\n }\n}); // the no-half-open enforcer\n\nfunction onend() {\n // If the writable side ended, then we're ok.\n if (this._writableState.ended) return; // no more data can be written.\n // But allow more writes to happen in this tick.\n\n process.nextTick(onEndNT, this);\n}\n\nfunction onEndNT(self) {\n self.end();\n}\n\nObject.defineProperty(Duplex.prototype, 'destroyed', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n if (this._readableState === undefined || this._writableState === undefined) {\n return false;\n }\n\n return this._readableState.destroyed && this._writableState.destroyed;\n },\n set: function set(value) {\n // we ignore the value if the stream\n // has not been initialized yet\n if (this._readableState === undefined || this._writableState === undefined) {\n return;\n } // backward compatibility, the user is explicitly\n // managing destroyed\n\n\n this._readableState.destroyed = value;\n this._writableState.destroyed = value;\n }\n});","var Buffer = require('safe-buffer').Buffer\n\n// prototype class for hash functions\nfunction Hash (blockSize, finalSize) {\n this._block = Buffer.alloc(blockSize)\n this._finalSize = finalSize\n this._blockSize = blockSize\n this._len = 0\n}\n\nHash.prototype.update = function (data, enc) {\n if (typeof data === 'string') {\n enc = enc || 'utf8'\n data = Buffer.from(data, enc)\n }\n\n var block = this._block\n var blockSize = this._blockSize\n var length = data.length\n var accum = this._len\n\n for (var offset = 0; offset < length;) {\n var assigned = accum % blockSize\n var remainder = Math.min(length - offset, blockSize - assigned)\n\n for (var i = 0; i < remainder; i++) {\n block[assigned + i] = data[offset + i]\n }\n\n accum += remainder\n offset += remainder\n\n if ((accum % blockSize) === 0) {\n this._update(block)\n }\n }\n\n this._len += length\n return this\n}\n\nHash.prototype.digest = function (enc) {\n var rem = this._len % this._blockSize\n\n this._block[rem] = 0x80\n\n // zero (rem + 1) trailing bits, where (rem + 1) is the smallest\n // non-negative solution to the equation (length + 1 + (rem + 1)) === finalSize mod blockSize\n this._block.fill(0, rem + 1)\n\n if (rem >= this._finalSize) {\n this._update(this._block)\n this._block.fill(0)\n }\n\n var bits = this._len * 8\n\n // uint32\n if (bits <= 0xffffffff) {\n this._block.writeUInt32BE(bits, this._blockSize - 4)\n\n // uint64\n } else {\n var lowBits = (bits & 0xffffffff) >>> 0\n var highBits = (bits - lowBits) / 0x100000000\n\n this._block.writeUInt32BE(highBits, this._blockSize - 8)\n this._block.writeUInt32BE(lowBits, this._blockSize - 4)\n }\n\n this._update(this._block)\n var hash = this._hash()\n\n return enc ? hash.toString(enc) : hash\n}\n\nHash.prototype._update = function () {\n throw new Error('_update must be implemented by subclass')\n}\n\nmodule.exports = Hash\n","'use strict';\n\nfunction _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; }\n\nvar codes = {};\n\nfunction createErrorType(code, message, Base) {\n if (!Base) {\n Base = Error;\n }\n\n function getMessage(arg1, arg2, arg3) {\n if (typeof message === 'string') {\n return message;\n } else {\n return message(arg1, arg2, arg3);\n }\n }\n\n var NodeError =\n /*#__PURE__*/\n function (_Base) {\n _inheritsLoose(NodeError, _Base);\n\n function NodeError(arg1, arg2, arg3) {\n return _Base.call(this, getMessage(arg1, arg2, arg3)) || this;\n }\n\n return NodeError;\n }(Base);\n\n NodeError.prototype.name = Base.name;\n NodeError.prototype.code = code;\n codes[code] = NodeError;\n} // https://github.com/nodejs/node/blob/v10.8.0/lib/internal/errors.js\n\n\nfunction oneOf(expected, thing) {\n if (Array.isArray(expected)) {\n var len = expected.length;\n expected = expected.map(function (i) {\n return String(i);\n });\n\n if (len > 2) {\n return \"one of \".concat(thing, \" \").concat(expected.slice(0, len - 1).join(', '), \", or \") + expected[len - 1];\n } else if (len === 2) {\n return \"one of \".concat(thing, \" \").concat(expected[0], \" or \").concat(expected[1]);\n } else {\n return \"of \".concat(thing, \" \").concat(expected[0]);\n }\n } else {\n return \"of \".concat(thing, \" \").concat(String(expected));\n }\n} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith\n\n\nfunction startsWith(str, search, pos) {\n return str.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;\n} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith\n\n\nfunction endsWith(str, search, this_len) {\n if (this_len === undefined || this_len > str.length) {\n this_len = str.length;\n }\n\n return str.substring(this_len - search.length, this_len) === search;\n} // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes\n\n\nfunction includes(str, search, start) {\n if (typeof start !== 'number') {\n start = 0;\n }\n\n if (start + search.length > str.length) {\n return false;\n } else {\n return str.indexOf(search, start) !== -1;\n }\n}\n\ncreateErrorType('ERR_INVALID_OPT_VALUE', function (name, value) {\n return 'The value \"' + value + '\" is invalid for option \"' + name + '\"';\n}, TypeError);\ncreateErrorType('ERR_INVALID_ARG_TYPE', function (name, expected, actual) {\n // determiner: 'must be' or 'must not be'\n var determiner;\n\n if (typeof expected === 'string' && startsWith(expected, 'not ')) {\n determiner = 'must not be';\n expected = expected.replace(/^not /, '');\n } else {\n determiner = 'must be';\n }\n\n var msg;\n\n if (endsWith(name, ' argument')) {\n // For cases like 'first argument'\n msg = \"The \".concat(name, \" \").concat(determiner, \" \").concat(oneOf(expected, 'type'));\n } else {\n var type = includes(name, '.') ? 'property' : 'argument';\n msg = \"The \\\"\".concat(name, \"\\\" \").concat(type, \" \").concat(determiner, \" \").concat(oneOf(expected, 'type'));\n }\n\n msg += \". Received type \".concat(typeof actual);\n return msg;\n}, TypeError);\ncreateErrorType('ERR_STREAM_PUSH_AFTER_EOF', 'stream.push() after EOF');\ncreateErrorType('ERR_METHOD_NOT_IMPLEMENTED', function (name) {\n return 'The ' + name + ' method is not implemented';\n});\ncreateErrorType('ERR_STREAM_PREMATURE_CLOSE', 'Premature close');\ncreateErrorType('ERR_STREAM_DESTROYED', function (name) {\n return 'Cannot call ' + name + ' after a stream was destroyed';\n});\ncreateErrorType('ERR_MULTIPLE_CALLBACK', 'Callback called multiple times');\ncreateErrorType('ERR_STREAM_CANNOT_PIPE', 'Cannot pipe, not readable');\ncreateErrorType('ERR_STREAM_WRITE_AFTER_END', 'write after end');\ncreateErrorType('ERR_STREAM_NULL_VALUES', 'May not write null values to stream', TypeError);\ncreateErrorType('ERR_UNKNOWN_ENCODING', function (arg) {\n return 'Unknown encoding: ' + arg;\n}, TypeError);\ncreateErrorType('ERR_STREAM_UNSHIFT_AFTER_END_EVENT', 'stream.unshift() after end event');\nmodule.exports.codes = codes;\n","if (typeof Object.create === 'function') {\n // implementation from standard node.js 'util' module\n module.exports = function inherits(ctor, superCtor) {\n if (superCtor) {\n ctor.super_ = superCtor\n ctor.prototype = Object.create(superCtor.prototype, {\n constructor: {\n value: ctor,\n enumerable: false,\n writable: true,\n configurable: true\n }\n })\n }\n };\n} else {\n // old school shim for old browsers\n module.exports = function inherits(ctor, superCtor) {\n if (superCtor) {\n ctor.super_ = superCtor\n var TempCtor = function () {}\n TempCtor.prototype = superCtor.prototype\n ctor.prototype = new TempCtor()\n ctor.prototype.constructor = ctor\n }\n }\n}\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n// a duplex stream is just a stream that is both readable and writable.\n// Since JS doesn't have multiple prototypal inheritance, this class\n// prototypally inherits from Readable, and then parasitically from\n// Writable.\n'use strict';\n/**/\n\nvar objectKeys = Object.keys || function (obj) {\n var keys = [];\n\n for (var key in obj) {\n keys.push(key);\n }\n\n return keys;\n};\n/**/\n\n\nmodule.exports = Duplex;\n\nvar Readable = require('./_stream_readable');\n\nvar Writable = require('./_stream_writable');\n\nrequire('inherits')(Duplex, Readable);\n\n{\n // Allow the keys array to be GC'ed.\n var keys = objectKeys(Writable.prototype);\n\n for (var v = 0; v < keys.length; v++) {\n var method = keys[v];\n if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];\n }\n}\n\nfunction Duplex(options) {\n if (!(this instanceof Duplex)) return new Duplex(options);\n Readable.call(this, options);\n Writable.call(this, options);\n this.allowHalfOpen = true;\n\n if (options) {\n if (options.readable === false) this.readable = false;\n if (options.writable === false) this.writable = false;\n\n if (options.allowHalfOpen === false) {\n this.allowHalfOpen = false;\n this.once('end', onend);\n }\n }\n}\n\nObject.defineProperty(Duplex.prototype, 'writableHighWaterMark', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._writableState.highWaterMark;\n }\n});\nObject.defineProperty(Duplex.prototype, 'writableBuffer', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._writableState && this._writableState.getBuffer();\n }\n});\nObject.defineProperty(Duplex.prototype, 'writableLength', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._writableState.length;\n }\n}); // the no-half-open enforcer\n\nfunction onend() {\n // If the writable side ended, then we're ok.\n if (this._writableState.ended) return; // no more data can be written.\n // But allow more writes to happen in this tick.\n\n process.nextTick(onEndNT, this);\n}\n\nfunction onEndNT(self) {\n self.end();\n}\n\nObject.defineProperty(Duplex.prototype, 'destroyed', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n if (this._readableState === undefined || this._writableState === undefined) {\n return false;\n }\n\n return this._readableState.destroyed && this._writableState.destroyed;\n },\n set: function set(value) {\n // we ignore the value if the stream\n // has not been initialized yet\n if (this._readableState === undefined || this._writableState === undefined) {\n return;\n } // backward compatibility, the user is explicitly\n // managing destroyed\n\n\n this._readableState.destroyed = value;\n this._writableState.destroyed = value;\n }\n});","var ClientRequest = require('./lib/request')\nvar response = require('./lib/response')\nvar extend = require('xtend')\nvar statusCodes = require('builtin-status-codes')\nvar url = require('url')\n\nvar http = exports\n\nhttp.request = function (opts, cb) {\n\tif (typeof opts === 'string')\n\t\topts = url.parse(opts)\n\telse\n\t\topts = extend(opts)\n\n\t// Normally, the page is loaded from http or https, so not specifying a protocol\n\t// will result in a (valid) protocol-relative url. However, this won't work if\n\t// the protocol is something else, like 'file:'\n\tvar defaultProtocol = global.location.protocol.search(/^https?:$/) === -1 ? 'http:' : ''\n\n\tvar protocol = opts.protocol || defaultProtocol\n\tvar host = opts.hostname || opts.host\n\tvar port = opts.port\n\tvar path = opts.path || '/'\n\n\t// Necessary for IPv6 addresses\n\tif (host && host.indexOf(':') !== -1)\n\t\thost = '[' + host + ']'\n\n\t// This may be a relative url. The browser should always be able to interpret it correctly.\n\topts.url = (host ? (protocol + '//' + host) : '') + (port ? ':' + port : '') + path\n\topts.method = (opts.method || 'GET').toUpperCase()\n\topts.headers = opts.headers || {}\n\n\t// Also valid opts.auth, opts.mode\n\n\tvar req = new ClientRequest(opts)\n\tif (cb)\n\t\treq.on('response', cb)\n\treturn req\n}\n\nhttp.get = function get (opts, cb) {\n\tvar req = http.request(opts, cb)\n\treq.end()\n\treturn req\n}\n\nhttp.ClientRequest = ClientRequest\nhttp.IncomingMessage = response.IncomingMessage\n\nhttp.Agent = function () {}\nhttp.Agent.defaultMaxSockets = 4\n\nhttp.globalAgent = new http.Agent()\n\nhttp.STATUS_CODES = statusCodes\n\nhttp.METHODS = [\n\t'CHECKOUT',\n\t'CONNECT',\n\t'COPY',\n\t'DELETE',\n\t'GET',\n\t'HEAD',\n\t'LOCK',\n\t'M-SEARCH',\n\t'MERGE',\n\t'MKACTIVITY',\n\t'MKCOL',\n\t'MOVE',\n\t'NOTIFY',\n\t'OPTIONS',\n\t'PATCH',\n\t'POST',\n\t'PROPFIND',\n\t'PROPPATCH',\n\t'PURGE',\n\t'PUT',\n\t'REPORT',\n\t'SEARCH',\n\t'SUBSCRIBE',\n\t'TRACE',\n\t'UNLOCK',\n\t'UNSUBSCRIBE'\n]","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// a duplex stream is just a stream that is both readable and writable.\n// Since JS doesn't have multiple prototypal inheritance, this class\n// prototypally inherits from Readable, and then parasitically from\n// Writable.\n\n'use strict';\n\n/**/\n\nvar pna = require('process-nextick-args');\n/**/\n\n/**/\nvar objectKeys = Object.keys || function (obj) {\n var keys = [];\n for (var key in obj) {\n keys.push(key);\n }return keys;\n};\n/**/\n\nmodule.exports = Duplex;\n\n/**/\nvar util = Object.create(require('core-util-is'));\nutil.inherits = require('inherits');\n/**/\n\nvar Readable = require('./_stream_readable');\nvar Writable = require('./_stream_writable');\n\nutil.inherits(Duplex, Readable);\n\n{\n // avoid scope creep, the keys array can then be collected\n var keys = objectKeys(Writable.prototype);\n for (var v = 0; v < keys.length; v++) {\n var method = keys[v];\n if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method];\n }\n}\n\nfunction Duplex(options) {\n if (!(this instanceof Duplex)) return new Duplex(options);\n\n Readable.call(this, options);\n Writable.call(this, options);\n\n if (options && options.readable === false) this.readable = false;\n\n if (options && options.writable === false) this.writable = false;\n\n this.allowHalfOpen = true;\n if (options && options.allowHalfOpen === false) this.allowHalfOpen = false;\n\n this.once('end', onend);\n}\n\nObject.defineProperty(Duplex.prototype, 'writableHighWaterMark', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function () {\n return this._writableState.highWaterMark;\n }\n});\n\n// the no-half-open enforcer\nfunction onend() {\n // if we allow half-open state, or if the writable side ended,\n // then we're ok.\n if (this.allowHalfOpen || this._writableState.ended) return;\n\n // no more data can be written.\n // But allow more writes to happen in this tick.\n pna.nextTick(onEndNT, this);\n}\n\nfunction onEndNT(self) {\n self.end();\n}\n\nObject.defineProperty(Duplex.prototype, 'destroyed', {\n get: function () {\n if (this._readableState === undefined || this._writableState === undefined) {\n return false;\n }\n return this._readableState.destroyed && this._writableState.destroyed;\n },\n set: function (value) {\n // we ignore the value if the stream\n // has not been initialized yet\n if (this._readableState === undefined || this._writableState === undefined) {\n return;\n }\n\n // backward compatibility, the user is explicitly\n // managing destroyed\n this._readableState.destroyed = value;\n this._writableState.destroyed = value;\n }\n});\n\nDuplex.prototype._destroy = function (err, cb) {\n this.push(null);\n this.end();\n\n pna.nextTick(cb, err);\n};","'use strict';\n\n\nmodule.exports = {\n copy: copy,\n checkDataType: checkDataType,\n checkDataTypes: checkDataTypes,\n coerceToTypes: coerceToTypes,\n toHash: toHash,\n getProperty: getProperty,\n escapeQuotes: escapeQuotes,\n equal: require('fast-deep-equal'),\n ucs2length: require('./ucs2length'),\n varOccurences: varOccurences,\n varReplace: varReplace,\n cleanUpCode: cleanUpCode,\n finalCleanUpCode: finalCleanUpCode,\n schemaHasRules: schemaHasRules,\n schemaHasRulesExcept: schemaHasRulesExcept,\n toQuotedString: toQuotedString,\n getPathExpr: getPathExpr,\n getPath: getPath,\n getData: getData,\n unescapeFragment: unescapeFragment,\n unescapeJsonPointer: unescapeJsonPointer,\n escapeFragment: escapeFragment,\n escapeJsonPointer: escapeJsonPointer\n};\n\n\nfunction copy(o, to) {\n to = to || {};\n for (var key in o) to[key] = o[key];\n return to;\n}\n\n\nfunction checkDataType(dataType, data, negate) {\n var EQUAL = negate ? ' !== ' : ' === '\n , AND = negate ? ' || ' : ' && '\n , OK = negate ? '!' : ''\n , NOT = negate ? '' : '!';\n switch (dataType) {\n case 'null': return data + EQUAL + 'null';\n case 'array': return OK + 'Array.isArray(' + data + ')';\n case 'object': return '(' + OK + data + AND +\n 'typeof ' + data + EQUAL + '\"object\"' + AND +\n NOT + 'Array.isArray(' + data + '))';\n case 'integer': return '(typeof ' + data + EQUAL + '\"number\"' + AND +\n NOT + '(' + data + ' % 1)' +\n AND + data + EQUAL + data + ')';\n default: return 'typeof ' + data + EQUAL + '\"' + dataType + '\"';\n }\n}\n\n\nfunction checkDataTypes(dataTypes, data) {\n switch (dataTypes.length) {\n case 1: return checkDataType(dataTypes[0], data, true);\n default:\n var code = '';\n var types = toHash(dataTypes);\n if (types.array && types.object) {\n code = types.null ? '(': '(!' + data + ' || ';\n code += 'typeof ' + data + ' !== \"object\")';\n delete types.null;\n delete types.array;\n delete types.object;\n }\n if (types.number) delete types.integer;\n for (var t in types)\n code += (code ? ' && ' : '' ) + checkDataType(t, data, true);\n\n return code;\n }\n}\n\n\nvar COERCE_TO_TYPES = toHash([ 'string', 'number', 'integer', 'boolean', 'null' ]);\nfunction coerceToTypes(optionCoerceTypes, dataTypes) {\n if (Array.isArray(dataTypes)) {\n var types = [];\n for (var i=0; i= lvl) throw new Error('Cannot access property/index ' + up + ' levels up, current level is ' + lvl);\n return paths[lvl - up];\n }\n\n if (up > lvl) throw new Error('Cannot access data ' + up + ' levels up, current level is ' + lvl);\n data = 'data' + ((lvl - up) || '');\n if (!jsonPointer) return data;\n }\n\n var expr = data;\n var segments = jsonPointer.split('/');\n for (var i=0; i>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n\t var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff;\n\t var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff;\n\n\t var triplet = (byte1 << 16) | (byte2 << 8) | byte3;\n\n\t for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) {\n\t base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f));\n\t }\n\t }\n\n\t // Add padding\n\t var paddingChar = map.charAt(64);\n\t if (paddingChar) {\n\t while (base64Chars.length % 4) {\n\t base64Chars.push(paddingChar);\n\t }\n\t }\n\n\t return base64Chars.join('');\n\t },\n\n\t /**\n\t * Converts a Base64 string to a word array.\n\t *\n\t * @param {string} base64Str The Base64 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.Base64.parse(base64String);\n\t */\n\t parse: function (base64Str) {\n\t // Shortcuts\n\t var base64StrLength = base64Str.length;\n\t var map = this._map;\n\t var reverseMap = this._reverseMap;\n\n\t if (!reverseMap) {\n\t reverseMap = this._reverseMap = [];\n\t for (var j = 0; j < map.length; j++) {\n\t reverseMap[map.charCodeAt(j)] = j;\n\t }\n\t }\n\n\t // Ignore padding\n\t var paddingChar = map.charAt(64);\n\t if (paddingChar) {\n\t var paddingIndex = base64Str.indexOf(paddingChar);\n\t if (paddingIndex !== -1) {\n\t base64StrLength = paddingIndex;\n\t }\n\t }\n\n\t // Convert\n\t return parseLoop(base64Str, base64StrLength, reverseMap);\n\n\t },\n\n\t _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='\n\t };\n\n\t function parseLoop(base64Str, base64StrLength, reverseMap) {\n\t var words = [];\n\t var nBytes = 0;\n\t for (var i = 0; i < base64StrLength; i++) {\n\t if (i % 4) {\n\t var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2);\n\t var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2);\n\t var bitsCombined = bits1 | bits2;\n\t words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8);\n\t nBytes++;\n\t }\n\t }\n\t return WordArray.create(words, nBytes);\n\t }\n\t}());\n\n\n\treturn CryptoJS.enc.Base64;\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 (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_algo = C.algo;\n\n\t // Constants table\n\t var T = [];\n\n\t // Compute constants\n\t (function () {\n\t for (var i = 0; i < 64; i++) {\n\t T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;\n\t }\n\t }());\n\n\t /**\n\t * MD5 hash algorithm.\n\t */\n\t var MD5 = C_algo.MD5 = Hasher.extend({\n\t _doReset: function () {\n\t this._hash = new WordArray.init([\n\t 0x67452301, 0xefcdab89,\n\t 0x98badcfe, 0x10325476\n\t ]);\n\t },\n\n\t _doProcessBlock: function (M, offset) {\n\t // Swap endian\n\t for (var i = 0; i < 16; i++) {\n\t // Shortcuts\n\t var offset_i = offset + i;\n\t var M_offset_i = M[offset_i];\n\n\t M[offset_i] = (\n\t (((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) |\n\t (((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00)\n\t );\n\t }\n\n\t // Shortcuts\n\t var H = this._hash.words;\n\n\t var M_offset_0 = M[offset + 0];\n\t var M_offset_1 = M[offset + 1];\n\t var M_offset_2 = M[offset + 2];\n\t var M_offset_3 = M[offset + 3];\n\t var M_offset_4 = M[offset + 4];\n\t var M_offset_5 = M[offset + 5];\n\t var M_offset_6 = M[offset + 6];\n\t var M_offset_7 = M[offset + 7];\n\t var M_offset_8 = M[offset + 8];\n\t var M_offset_9 = M[offset + 9];\n\t var M_offset_10 = M[offset + 10];\n\t var M_offset_11 = M[offset + 11];\n\t var M_offset_12 = M[offset + 12];\n\t var M_offset_13 = M[offset + 13];\n\t var M_offset_14 = M[offset + 14];\n\t var M_offset_15 = M[offset + 15];\n\n\t // Working varialbes\n\t var a = H[0];\n\t var b = H[1];\n\t var c = H[2];\n\t var d = H[3];\n\n\t // Computation\n\t a = FF(a, b, c, d, M_offset_0, 7, T[0]);\n\t d = FF(d, a, b, c, M_offset_1, 12, T[1]);\n\t c = FF(c, d, a, b, M_offset_2, 17, T[2]);\n\t b = FF(b, c, d, a, M_offset_3, 22, T[3]);\n\t a = FF(a, b, c, d, M_offset_4, 7, T[4]);\n\t d = FF(d, a, b, c, M_offset_5, 12, T[5]);\n\t c = FF(c, d, a, b, M_offset_6, 17, T[6]);\n\t b = FF(b, c, d, a, M_offset_7, 22, T[7]);\n\t a = FF(a, b, c, d, M_offset_8, 7, T[8]);\n\t d = FF(d, a, b, c, M_offset_9, 12, T[9]);\n\t c = FF(c, d, a, b, M_offset_10, 17, T[10]);\n\t b = FF(b, c, d, a, M_offset_11, 22, T[11]);\n\t a = FF(a, b, c, d, M_offset_12, 7, T[12]);\n\t d = FF(d, a, b, c, M_offset_13, 12, T[13]);\n\t c = FF(c, d, a, b, M_offset_14, 17, T[14]);\n\t b = FF(b, c, d, a, M_offset_15, 22, T[15]);\n\n\t a = GG(a, b, c, d, M_offset_1, 5, T[16]);\n\t d = GG(d, a, b, c, M_offset_6, 9, T[17]);\n\t c = GG(c, d, a, b, M_offset_11, 14, T[18]);\n\t b = GG(b, c, d, a, M_offset_0, 20, T[19]);\n\t a = GG(a, b, c, d, M_offset_5, 5, T[20]);\n\t d = GG(d, a, b, c, M_offset_10, 9, T[21]);\n\t c = GG(c, d, a, b, M_offset_15, 14, T[22]);\n\t b = GG(b, c, d, a, M_offset_4, 20, T[23]);\n\t a = GG(a, b, c, d, M_offset_9, 5, T[24]);\n\t d = GG(d, a, b, c, M_offset_14, 9, T[25]);\n\t c = GG(c, d, a, b, M_offset_3, 14, T[26]);\n\t b = GG(b, c, d, a, M_offset_8, 20, T[27]);\n\t a = GG(a, b, c, d, M_offset_13, 5, T[28]);\n\t d = GG(d, a, b, c, M_offset_2, 9, T[29]);\n\t c = GG(c, d, a, b, M_offset_7, 14, T[30]);\n\t b = GG(b, c, d, a, M_offset_12, 20, T[31]);\n\n\t a = HH(a, b, c, d, M_offset_5, 4, T[32]);\n\t d = HH(d, a, b, c, M_offset_8, 11, T[33]);\n\t c = HH(c, d, a, b, M_offset_11, 16, T[34]);\n\t b = HH(b, c, d, a, M_offset_14, 23, T[35]);\n\t a = HH(a, b, c, d, M_offset_1, 4, T[36]);\n\t d = HH(d, a, b, c, M_offset_4, 11, T[37]);\n\t c = HH(c, d, a, b, M_offset_7, 16, T[38]);\n\t b = HH(b, c, d, a, M_offset_10, 23, T[39]);\n\t a = HH(a, b, c, d, M_offset_13, 4, T[40]);\n\t d = HH(d, a, b, c, M_offset_0, 11, T[41]);\n\t c = HH(c, d, a, b, M_offset_3, 16, T[42]);\n\t b = HH(b, c, d, a, M_offset_6, 23, T[43]);\n\t a = HH(a, b, c, d, M_offset_9, 4, T[44]);\n\t d = HH(d, a, b, c, M_offset_12, 11, T[45]);\n\t c = HH(c, d, a, b, M_offset_15, 16, T[46]);\n\t b = HH(b, c, d, a, M_offset_2, 23, T[47]);\n\n\t a = II(a, b, c, d, M_offset_0, 6, T[48]);\n\t d = II(d, a, b, c, M_offset_7, 10, T[49]);\n\t c = II(c, d, a, b, M_offset_14, 15, T[50]);\n\t b = II(b, c, d, a, M_offset_5, 21, T[51]);\n\t a = II(a, b, c, d, M_offset_12, 6, T[52]);\n\t d = II(d, a, b, c, M_offset_3, 10, T[53]);\n\t c = II(c, d, a, b, M_offset_10, 15, T[54]);\n\t b = II(b, c, d, a, M_offset_1, 21, T[55]);\n\t a = II(a, b, c, d, M_offset_8, 6, T[56]);\n\t d = II(d, a, b, c, M_offset_15, 10, T[57]);\n\t c = II(c, d, a, b, M_offset_6, 15, T[58]);\n\t b = II(b, c, d, a, M_offset_13, 21, T[59]);\n\t a = II(a, b, c, d, M_offset_4, 6, T[60]);\n\t d = II(d, a, b, c, M_offset_11, 10, T[61]);\n\t c = II(c, d, a, b, M_offset_2, 15, T[62]);\n\t b = II(b, c, d, a, M_offset_9, 21, T[63]);\n\n\t // Intermediate hash value\n\t H[0] = (H[0] + a) | 0;\n\t H[1] = (H[1] + b) | 0;\n\t H[2] = (H[2] + c) | 0;\n\t H[3] = (H[3] + d) | 0;\n\t },\n\n\t _doFinalize: function () {\n\t // Shortcuts\n\t var data = this._data;\n\t var dataWords = data.words;\n\n\t var nBitsTotal = this._nDataBytes * 8;\n\t var nBitsLeft = data.sigBytes * 8;\n\n\t // Add padding\n\t dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);\n\n\t var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000);\n\t var nBitsTotalL = nBitsTotal;\n\t dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = (\n\t (((nBitsTotalH << 8) | (nBitsTotalH >>> 24)) & 0x00ff00ff) |\n\t (((nBitsTotalH << 24) | (nBitsTotalH >>> 8)) & 0xff00ff00)\n\t );\n\t dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (\n\t (((nBitsTotalL << 8) | (nBitsTotalL >>> 24)) & 0x00ff00ff) |\n\t (((nBitsTotalL << 24) | (nBitsTotalL >>> 8)) & 0xff00ff00)\n\t );\n\n\t data.sigBytes = (dataWords.length + 1) * 4;\n\n\t // Hash final blocks\n\t this._process();\n\n\t // Shortcuts\n\t var hash = this._hash;\n\t var H = hash.words;\n\n\t // Swap endian\n\t for (var i = 0; i < 4; i++) {\n\t // Shortcut\n\t var H_i = H[i];\n\n\t H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) |\n\t (((H_i << 24) | (H_i >>> 8)) & 0xff00ff00);\n\t }\n\n\t // Return final computed hash\n\t return hash;\n\t },\n\n\t clone: function () {\n\t var clone = Hasher.clone.call(this);\n\t clone._hash = this._hash.clone();\n\n\t return clone;\n\t }\n\t });\n\n\t function FF(a, b, c, d, x, s, t) {\n\t var n = a + ((b & c) | (~b & d)) + x + t;\n\t return ((n << s) | (n >>> (32 - s))) + b;\n\t }\n\n\t function GG(a, b, c, d, x, s, t) {\n\t var n = a + ((b & d) | (c & ~d)) + x + t;\n\t return ((n << s) | (n >>> (32 - s))) + b;\n\t }\n\n\t function HH(a, b, c, d, x, s, t) {\n\t var n = a + (b ^ c ^ d) + x + t;\n\t return ((n << s) | (n >>> (32 - s))) + b;\n\t }\n\n\t function II(a, b, c, d, x, s, t) {\n\t var n = a + (c ^ (b | ~d)) + x + t;\n\t return ((n << s) | (n >>> (32 - s))) + b;\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.MD5('message');\n\t * var hash = CryptoJS.MD5(wordArray);\n\t */\n\t C.MD5 = Hasher._createHelper(MD5);\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.HmacMD5(message, key);\n\t */\n\t C.HmacMD5 = Hasher._createHmacHelper(MD5);\n\t}(Math));\n\n\n\treturn CryptoJS.MD5;\n\n}));","const GenUtils = require(\"./GenUtils\");\nconst HttpClient = require(\"./HttpClient\");\nconst LibraryUtils = require(\"./LibraryUtils\");\nconst MoneroError = require(\"../common/MoneroError\");\nconst MoneroRpcError = require(\"../common/MoneroRpcError\");\nconst MoneroUtils = require(\"./MoneroUtils\");\n\n/**\n * Maintains a connection and sends requests to a Monero RPC API.\n */\nclass MoneroRpcConnection {\n \n /**\n *

Construct a RPC connection.

\n * \n *

Examples:

\n * \n * \n * let connection1 = new MoneroRpcConnection(\"http://localhost:38081\", \"daemon_user\", \"daemon_password_123\")

\n * \n * let connection2 = new MoneroRpcConnection({
\n *    uri: http://localhost:38081,
\n *    username: \"daemon_user\",
\n *    password: \"daemon_password_123\",
\n *    rejectUnauthorized: false // accept self-signed certificates e.g. for local development
\n * });\n *
\n * \n * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - RPC endpoint URI, MoneroRpcConnection, or equivalent JS object\n * @param {string} uriOrConfigOrConnection.uri - URI of the RPC endpoint\n * @param {string} uriOrConfigOrConnection.username - username to authenticate with the RPC endpoint (optional)\n * @param {string} uriOrConfigOrConnection.password - password to authenticate with the RPC endpoint (optional)\n * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true)\n * @param {string} username - username to authenticate with the RPC endpoint (optional)\n * @param {string} password - password to authenticate with the RPC endpoint (optional)\n * @param {boolean} rejectUnauthorized - reject self-signed certificates if true (default true)\n */\n constructor(uriOrConfigOrConnection, username, password, rejectUnauthorized) {\n \n // validate and normalize config\n if (typeof uriOrConfigOrConnection === \"string\") {\n this.config = {uri: uriOrConfigOrConnection};\n if (username !== undefined) this.config.username = username;\n if (password !== undefined) this.config.password = password;\n if (rejectUnauthorized !== undefined) this.config.rejectUnauthorized = rejectUnauthorized;\n } else if (typeof uriOrConfigOrConnection === \"object\") {\n if (username !== undefined || password !== undefined || rejectUnauthorized !== undefined) throw new MoneroError(\"Can provide config object or params but not both\");\n if (uriOrConfigOrConnection instanceof MoneroRpcConnection) this.config = Object.assign({}, uriOrConfigOrConnection.getConfig());\n else this.config = Object.assign({}, uriOrConfigOrConnection);\n } else if (uriOrConfigOrConnection !== undefined) {\n throw new MoneroError(\"Invalid configuration to MoneroRpcConnection; must be string or MoneroRpcConnection or equivalent JS object\");\n }\n \n // merge default config\n this.config = Object.assign({}, MoneroRpcConnection.DEFAULT_CONFIG, this.config);\n \n // standardize uri\n if (this.config.uri) this.config.uri = this.config.uri.replace(/\\/$/, \"\"); // strip trailing slash\n \n // fail with friendly message if using old api\n if (this.config.user || this.config.pass) throw new MoneroError(\"Authentication fields 'user' and 'pass' have been renamed to 'username' and 'password'. Please update to the new api\");\n }\n \n getUri() {\n return this.config.uri;\n }\n \n getUsername() {\n return this.config.username;\n }\n \n getPassword() {\n return this.config.password;\n }\n \n getRejectUnauthorized() {\n return this.config.rejectUnauthorized;\n }\n \n getConfig() {\n return this.config;\n }\n \n /**\n * Sends a JSON RPC request.\n * \n * @param method is the JSON RPC method to invoke\n * @param params are request parameters\n * @return {object} is the response map\n */\n async sendJsonRequest(method, params) {\n //console.log(\"sendJsonRequest(\" + method + \", \" + JSON.stringify(params) + \")\");\n \n try {\n // tx config\n let resp = await HttpClient.request({\n method: \"POST\",\n uri: this.getUri() + '/json_rpc',\n username: this.getUsername(),\n password: this.getPassword(),\n body: JSON.stringify({ // body is stringified so text/plain is returned so BigIntegers are preserved\n id: \"0\",\n jsonrpc: \"2.0\",\n method: method,\n params: params\n }),\n rejectUnauthorized: this.config.rejectUnauthorized,\n requestApi: GenUtils.isFirefox() ? \"xhr\" : \"fetch\" // firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1491010\n });\n \n // process response\n resp = JSON.parse(resp.body.replace(/(\"[^\"]*\"\\s*:\\s*)(\\d{16,})/g, '$1\"$2\"')); // replace 16 or more digits with strings and parse\n if (resp.error) throw new MoneroRpcError(resp.error.message, resp.error.code, method, params);\n return resp;\n } catch (e) {\n if (e instanceof MoneroRpcError) throw e;\n else throw new MoneroRpcError(e, undefined, method, params);\n }\n }\n \n /**\n * Sends a RPC request to the given path and with the given paramters.\n * \n * E.g. \"/get_transactions\" with params\n */\n async sendPathRequest(path, params) {\n //console.log(\"sendPathRequest(\" + path + \", \" + JSON.stringify(params) + \")\");\n \n try {\n // tx config\n let resp = await HttpClient.request({\n method: \"POST\",\n uri: this.getUri() + '/' + path,\n username: this.getUsername(),\n password: this.getPassword(),\n body: JSON.stringify(params), // body is stringified so text/plain is returned so BigIntegers are preserved\n rejectUnauthorized: this.config.rejectUnauthorized,\n requestApi: GenUtils.isFirefox() ? \"xhr\" : \"fetch\"\n });\n \n // process response\n resp = JSON.parse(resp.body.replace(/(\"[^\"]*\"\\s*:\\s*)(\\d{16,})/g, '$1\"$2\"')); // replace 16 or more digits with strings and parse\n if (typeof resp === \"string\") resp = JSON.parse(resp); // TODO: some responses returned as strings?\n if (resp.error) throw new MoneroRpcError(resp.error.message, resp.error.code, path, params);\n return resp;\n } catch (e) {\n if (e instanceof MoneroRpcError) throw e;\n else throw new MoneroRpcError(e, undefined, path, params);\n }\n }\n \n /**\n * Sends a binary RPC request.\n * \n * @param path is the path of the binary RPC method to invoke\n * @paramm params are the request parameters\n * @return a Uint8Array with the binary response\n */\n async sendBinaryRequest(path, params) {\n //console.log(\"sendBinaryRequest(\" + path + \", \" + JSON.stringify(params) + \")\");\n \n // load wasm module\n await LibraryUtils.loadKeysModule();\n \n // serialize params\n let paramsBin = MoneroUtils.jsonToBinary(params);\n \n try {\n // tx config\n let resp = await HttpClient.request({\n method: \"POST\",\n uri: this.getUri() + '/' + path,\n username: this.getUsername(),\n password: this.getPassword(),\n body: paramsBin,\n rejectUnauthorized: this.config.rejectUnauthorized,\n requestApi: GenUtils.isFirefox() ? \"xhr\" : \"fetch\"\n });\n \n // process response\n resp = resp.body;\n if (!(resp instanceof Uint8Array)) {\n console.error(\"resp is not uint8array\");\n console.error(resp);\n }\n if (resp.error) throw new MoneroRpcError(resp.error.message, resp.error.code, path, params);\n return resp;\n } catch (e) {\n if (e instanceof MoneroRpcError) throw e;\n else throw new MoneroRpcError(e, undefined, path, params);\n }\n }\n}\n\n\n/**\n * Default RPC configuration.\n */\nMoneroRpcConnection.DEFAULT_CONFIG = {\n uri: undefined,\n username: undefined,\n password: undefined,\n rejectUnauthorized: true // reject self-signed certificates if true\n}\n\nMoneroRpcConnection.SUPPORTED_FIELDS = [\"uri\", \"username\", \"password\", \"rejectUnauthorized\"];\n\nmodule.exports = MoneroRpcConnection;","const assert = require(\"assert\");\nconst GenUtils = require(\"../../common/GenUtils\");\n\n/**\n * Models a Monero key image.\n */\nclass MoneroKeyImage {\n \n /**\n * Construct the model.\n * \n * @param {MoneroKeyImage|object|string} stateOrHex is a MoneroKeyImage, JS object, or hex string to initialize from (optional)\n * @param {string} signature is the key image's signature\n */\n constructor(stateOrHex, signature) {\n if (!stateOrHex) this.state = {};\n else if (stateOrHex instanceof MoneroKeyImage) this.state = stateOrHex.toJson();\n else if (typeof stateOrHex === \"object\") this.state = Object.assign({}, stateOrHex);\n else if (typeof stateOrHex === \"string\") {\n this.state = {};\n this.setHex(stateOrHex);\n this.setSignature(signature);\n } else {\n throw new MoneroError(\"stateOrHex must be a MoneroKeyImage, JavaScript object, or string\");\n }\n }\n\n getHex() {\n return this.state.hex;\n }\n\n setHex(hex) {\n this.state.hex = hex;\n return this;\n }\n\n getSignature() {\n return this.state.signature;\n }\n\n setSignature(signature) {\n this.state.signature = signature;\n return this;\n }\n \n copy() {\n return new MoneroKeyImage(this);\n }\n \n toJson() {\n return Object.assign({}, this.state);\n }\n \n merge(keyImage) {\n assert(keyImage instanceof MoneroKeyImage);\n if (keyImage === this) return this;\n this.setHex(GenUtils.reconcile(this.getHex(), keyImage.getHex()));\n this.setSignature(GenUtils.reconcile(this.getSignature(), keyImage.getSignature()));\n return this;\n }\n \n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.kvLine(\"Hex\", this.getHex(), indent);\n str += GenUtils.kvLine(\"Signature\", this.getSignature(), indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n\nmodule.exports = MoneroKeyImage;","const assert = require(\"assert\");\nconst BigInteger = require(\"../../common/biginteger\").BigInteger;\nconst GenUtils = require(\"../../common/GenUtils\");\nconst MoneroIncomingTransfer = require(\"./MoneroIncomingTransfer\");\nconst MoneroOutgoingTransfer = require(\"./MoneroOutgoingTransfer\");\nconst MoneroOutputWallet = require(\"./MoneroOutputWallet\");\nconst MoneroTx = require(\"../../daemon/model/MoneroTx\");\n\n/**\n * Models a Monero transaction with wallet extensions.\n * \n * @class\n * @extends {MoneroTx}\n */\nclass MoneroTxWallet extends MoneroTx {\n \n /**\n * Construct the model.\n * \n * @param {MoneroTxWallet|object} state is existing state to initialize from (optional)\n */\n constructor(state) {\n super(state);\n if (state instanceof MoneroTxWallet && state.getTxSet()) this.setTxSet(state.getTxSet()); // preserve reference to tx set\n state = this.state;\n \n // deserialize incoming transfers\n if (state.incomingTransfers) {\n for (let i = 0; i < state.incomingTransfers.length; i++) {\n if (!(state.incomingTransfers[i] instanceof MoneroIncomingTransfer)) {\n state.incomingTransfers[i] = new MoneroIncomingTransfer(Object.assign(state.incomingTransfers[i], {tx: this}));\n }\n }\n }\n \n // deserialize outgoing transfer\n if (state.outgoingTransfer && !(state.outgoingTransfer instanceof MoneroOutgoingTransfer)) {\n this.setOutgoingTransfer(new MoneroOutgoingTransfer(Object.assign(state.outgoingTransfer, {tx: this})));\n }\n \n // deserialize inputs\n if (state.inputs) {\n for (let i = 0; i < state.inputs.length; i++) {\n if (!(state.inputs[i] instanceof MoneroOutputWallet)) {\n state.inputs[i] = new MoneroOutputWallet(Object.assign(state.inputs[i].toJson(), {tx: this}));\n }\n }\n }\n \n // deserialize outputs\n if (state.outputs) {\n for (let i = 0; i < state.outputs.length; i++) {\n if (!(state.outputs[i] instanceof MoneroOutputWallet)) {\n state.outputs[i] = new MoneroOutputWallet(Object.assign(state.outputs[i].toJson(), {tx: this}));\n }\n }\n }\n \n // deserialize BigIntegers\n if (state.inputSum !== undefined && !(state.inputSum instanceof BigInteger)) state.inputSum = BigInteger.parse(state.inputSum);\n if (state.outputSum !== undefined && !(state.outputSum instanceof BigInteger)) state.outputSum = BigInteger.parse(state.outputSum);\n if (state.changeAmount !== undefined && !(state.changeAmount instanceof BigInteger)) state.changeAmount = BigInteger.parse(state.changeAmount);\n }\n \n toJson() {\n let json = Object.assign({}, this.state, super.toJson()); // merge json onto inherited state\n if (this.getIncomingTransfers()) {\n json.incomingTransfers = [];\n for (let incomingTransfer of this.getIncomingTransfers()) json.incomingTransfers.push(incomingTransfer.toJson());\n }\n if (this.getOutgoingTransfer()) json.outgoingTransfer = this.getOutgoingTransfer().toJson();\n if (this.getInputSum()) json.inputSum = this.getInputSum().toString();\n if (this.getOutputSum()) json.outputSum = this.getOutputSum().toString();\n if (this.getChangeAmount()) json.changeAmount = this.getChangeAmount().toString();\n delete json.block; // do not serialize parent block\n delete json.txSet; // do not serialize parent tx set\n return json;\n }\n \n getTxSet() {\n return this.state.txSet;\n }\n \n setTxSet(txSet) {\n this.state.txSet = txSet;\n return this;\n }\n \n isIncoming() {\n return this.state.isIncoming;\n }\n \n setIsIncoming(isIncoming) {\n this.state.isIncoming = isIncoming;\n return this;\n }\n \n isOutgoing() {\n return this.state.isOutgoing;\n }\n \n setIsOutgoing(isOutgoing) {\n this.state.isOutgoing = isOutgoing;\n return this;\n }\n \n getIncomingAmount() {\n if (this.getIncomingTransfers() === undefined) return undefined;\n let incomingAmt = BigInteger.parse(\"0\");\n for (let transfer of this.getIncomingTransfers()) incomingAmt = incomingAmt.add(transfer.getAmount());\n return incomingAmt;\n }\n \n getOutgoingAmount() {\n return this.getOutgoingTransfer() ? this.getOutgoingTransfer().getAmount() : undefined;\n }\n \n getTransfers(transferQuery) {\n let transfers = [];\n if (this.getOutgoingTransfer() && (!transferQuery || transferQuery.meetsCriteria(this.getOutgoingTransfer()))) transfers.push(this.getOutgoingTransfer());\n if (this.getIncomingTransfers()) {\n for (let transfer of this.getIncomingTransfers()) {\n if (!transferQuery || transferQuery.meetsCriteria(transfer)) transfers.push(transfer);\n }\n }\n return transfers;\n }\n \n filterTransfers(transferQuery) {\n let transfers = [];\n \n // collect outgoing transfer or erase if filtered\n if (this.getOutgoingTransfer() && (!transferQuery || transferQuery.meetsCriteria(this.getOutgoingTransfer()))) transfers.push(this.getOutgoingTransfer());\n else this.setOutgoingTransfer(undefined);\n \n // collect incoming transfers or erase if filtered\n if (this.getIncomingTransfers()) {\n let toRemoves = [];\n for (let transfer of this.getIncomingTransfers()) {\n if (transferQuery.meetsCriteria(transfer)) transfers.push(transfer);\n else toRemoves.push(transfer);\n }\n this.setIncomingTransfers(this.getIncomingTransfers().filter(function(transfer) {\n return !toRemoves.includes(transfer);\n }));\n if (this.getIncomingTransfers().length === 0) this.setIncomingTransfers(undefined);\n }\n \n return transfers;\n }\n \n getIncomingTransfers() {\n return this.state.incomingTransfers;\n }\n \n setIncomingTransfers(incomingTransfers) {\n this.state.incomingTransfers = incomingTransfers;\n return this;\n }\n \n getOutgoingTransfer() {\n return this.state.outgoingTransfer;\n }\n \n setOutgoingTransfer(outgoingTransfer) {\n this.state.outgoingTransfer = outgoingTransfer;\n return this;\n }\n \n getOutputs(outputQuery) {\n if (!outputQuery || !super.getOutputs()) return super.getOutputs();\n let outputs = [];\n for (let output of super.getOutputs()) if (!outputQuery || outputQuery.meetsCriteria(output)) outputs.push(output);\n return outputs;\n }\n \n setOutputs(outputs) {\n \n // validate that all outputs are wallet outputs\n if (outputs) {\n for (let output of outputs) {\n if (!(output instanceof MoneroOutputWallet)) throw new MoneroError(\"Wallet transaction outputs must be of type MoneroOutputWallet\");\n }\n }\n super.setOutputs(outputs);\n return this;\n }\n \n filterOutputs(outputQuery) {\n let outputs = [];\n if (super.getOutputs()) {\n let toRemoves = [];\n for (let output of super.getOutputs()) {\n if (!outputQuery || outputQuery.meetsCriteria(output)) outputs.push(output);\n else toRemoves.push(output);\n }\n this.setOutputs(super.getOutputs().filter(function(output) {\n return !toRemoves.includes(output);\n }));\n if (this.getOutputs().length === 0) this.setOutputs(undefined);\n }\n return outputs;\n }\n \n getNote() {\n return this.state.note;\n }\n \n setNote(note) {\n this.state.note = note;\n return this;\n }\n \n isLocked() {\n return this.state.isLocked;\n }\n \n setIsLocked(isLocked) {\n this.state.isLocked = isLocked;\n return this;\n }\n \n getInputSum() {\n return this.state.inputSum;\n }\n \n setInputSum(inputSum) {\n this.state.inputSum = inputSum;\n return this;\n }\n \n getOutputSum() {\n return this.state.outputSum;\n }\n \n setOutputSum(outputSum) {\n this.state.outputSum = outputSum;\n return this;\n }\n \n getChangeAddress() {\n return this.state.changeAddress;\n }\n \n setChangeAddress(changeAddress) {\n this.state.changeAddress = changeAddress;\n return this;\n }\n \n getChangeAmount() {\n return this.state.changeAmount;\n }\n \n setChangeAmount(changeAmount) {\n this.state.changeAmount = changeAmount;\n return this;\n }\n \n getNumDummyOutputs() {\n return this.state.numDummyOutputs;\n }\n \n setNumDummyOutputs(numDummyOutputs) {\n this.state.numDummyOutputs = numDummyOutputs;\n return this;\n }\n \n getExtraHex() {\n return this.state.extraHex;\n }\n \n setExtraHex(extraHex) {\n this.state.extraHex = extraHex;\n return this;\n }\n \n copy() {\n return new MoneroTxWallet(this);\n }\n \n /**\n * Updates this transaction by merging the latest information from the given\n * transaction.\n * \n * Merging can modify or build references to the transaction given so it\n * should not be re-used or it should be copied before calling this method.\n * \n * @param tx is the transaction to merge into this transaction\n */\n merge(tx) {\n assert(tx instanceof MoneroTxWallet);\n if (this === tx) return this;\n \n // merge base classes\n super.merge(tx);\n \n // merge tx set if they're different which comes back to merging txs\n const MoneroTxSet = require(\"./MoneroTxSet\");\n if (this.getTxSet() !== tx.getTxSet()) {\n if (this.getTxSet() == undefined) {\n this.setTxSet(new MoneroTxSet().setTxs([this]));\n }\n if (tx.getTxSet() === undefined) {\n tx.setTxSet(new MoneroTxSet().setTxs([tx]));\n }\n this.getTxSet().merge(tx.getTxSet());\n return this;\n }\n \n // merge incoming transfers\n if (tx.getIncomingTransfers()) {\n if (this.getIncomingTransfers() === undefined) this.setIncomingTransfers([]);\n for (let transfer of tx.getIncomingTransfers()) {\n transfer.setTx(this);\n MoneroTxWallet._mergeIncomingTransfer(this.getIncomingTransfers(), transfer);\n }\n }\n \n // merge outgoing transfer\n if (tx.getOutgoingTransfer()) {\n tx.getOutgoingTransfer().setTx(this);\n if (this.getOutgoingTransfer() === undefined) this.setOutgoingTransfer(tx.getOutgoingTransfer());\n else this.getOutgoingTransfer().merge(tx.getOutgoingTransfer());\n }\n \n // merge simple extensions\n this.setIsIncoming(GenUtils.reconcile(this.isIncoming(), tx.isIncoming()));\n this.setIsOutgoing(GenUtils.reconcile(this.isOutgoing(), tx.isOutgoing()));\n this.setNote(GenUtils.reconcile(this.getNote(), tx.getNote()));\n this.setIsLocked(GenUtils.reconcile(this.isLocked(), tx.isLocked()));\n this.setInputSum(GenUtils.reconcile(this.getInputSum(), tx.getInputSum()));\n this.setOutputSum(GenUtils.reconcile(this.getOutputSum(), tx.getOutputSum()));\n this.setChangeAddress(GenUtils.reconcile(this.getChangeAddress(), tx.getChangeAddress()));\n this.setChangeAmount(GenUtils.reconcile(this.getChangeAmount(), tx.getChangeAmount()));\n this.setNumDummyOutputs(GenUtils.reconcile(this.getNumDummyOutputs(), tx.getNumDummyOutputs()));\n this.setExtraHex(GenUtils.reconcile(this.getExtraHex(), tx.getExtraHex()));\n \n return this; // for chaining\n }\n \n toString(indent = 0, oneLine) {\n let str = \"\";\n \n // represent tx with one line string\n // TODO: proper csv export\n if (oneLine) {\n str += this.getHash() + \", \";\n str += (this.isConfirmed() ? this.getBlock().getTimestamp() : this.getReceivedTimestamp()) + \", \";\n str += this.isConfirmed() + \", \";\n str += (this.getOutgoingAmount() ? this.getOutgoingAmount().toString() : \"\") + \", \";\n str += this.getIncomingAmount() ? this.getIncomingAmount().toString() : \"\";\n return str;\n }\n \n // otherwise stringify all fields\n str += super.toString(indent) + \"\\n\";\n str += GenUtils.kvLine(\"Is incoming\", this.isIncoming(), indent);\n str += GenUtils.kvLine(\"Incoming amount\", this.getIncomingAmount(), indent);\n if (this.getIncomingTransfers()) {\n str += GenUtils.kvLine(\"Incoming transfers\", \"\", indent);\n for (let i = 0; i < this.getIncomingTransfers().length; i++) {\n str += GenUtils.kvLine(i + 1, \"\", indent + 1);\n str += this.getIncomingTransfers()[i].toString(indent + 2) + \"\\n\";\n }\n }\n str += GenUtils.kvLine(\"Is outgoing\", this.isOutgoing(), indent);\n str += GenUtils.kvLine(\"Outgoing amount\", this.getOutgoingAmount(), indent);\n if (this.getOutgoingTransfer()) {\n str += GenUtils.kvLine(\"Outgoing transfer\", \"\", indent);\n str += this.getOutgoingTransfer().toString(indent + 1) + \"\\n\";\n }\n str += GenUtils.kvLine(\"Note\", this.getNote(), indent);\n str += GenUtils.kvLine(\"Is locked\", this.isLocked(), indent);\n str += GenUtils.kvLine(\"Input sum\", this.getInputSum(), indent);\n str += GenUtils.kvLine(\"Output sum\", this.getOutputSum(), indent);\n str += GenUtils.kvLine(\"Change address\", this.getChangeAddress(), indent);\n str += GenUtils.kvLine(\"Change amount\", this.getChangeAmount(), indent);\n str += GenUtils.kvLine(\"Num dummy outputs\", this.getNumDummyOutputs(), indent);\n str += GenUtils.kvLine(\"Extra hex\", this.getExtraHex(), indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n \n // private helper to merge transfers\n static _mergeIncomingTransfer(transfers, transfer) {\n for (let aTransfer of transfers) {\n if (aTransfer.getAccountIndex() === transfer.getAccountIndex() && aTransfer.getSubaddressIndex() === transfer.getSubaddressIndex()) {\n aTransfer.merge(transfer);\n return;\n }\n }\n transfers.push(transfer);\n }\n}\n\nmodule.exports = MoneroTxWallet;","const assert = require(\"assert\");\n\n/**\n * Defines the Monero network types (mainnet, testnet, and stagenet).\n * \n * @hideconstructor\n */\nclass MoneroNetworkType {\n \n /**\n * Asserts that the given network type is valid.\n * \n * @param {int} networkType - the network type to validate as a numeric\n */\n static validate(networkType) {\n assert(networkType === 0 || networkType === 1 || networkType === 2, \"Network type is invalid: \" + networkType);\n }\n \n /**\n * Indicates if the given network type is valid or not.\n * \n * @param {int} networkType - the network type to validate as a numeric\n * @return {boolean} true if the network type is valid, false otherwise\n */\n static isValid(networkType) {\n return networkType === 0 || networkType === 1 || networkType === 2;\n }\n \n /**\n * Parse the given string as a network type.\n * \n * @param {string} networkTypeStr - \"mainnet\", \"testnet\", or \"stagenet\" (case insensitive)\n * @return {int} the network type as a numeric\n */\n static parse(networkTypeStr) {\n let str = (\"\" + networkTypeStr).toLowerCase();\n switch (str) {\n case \"mainnet\": return MoneroNetworkType.MAINNET;\n case \"testnet\": return MoneroNetworkType.TESTNET;\n case \"stagenet\": return MoneroNetworkType.STAGENET;\n default: throw new MoneroError(\"Invalid network type to parse: '\" + networkTypeStr + \"'\");\n }\n }\n}\n\n/**\n * Mainnet (value=0).\n */\nMoneroNetworkType.MAINNET = 0;\n\n/**\n * Testnet (value=1).\n */\nMoneroNetworkType.TESTNET = 1;\n\n/**\n * Stagnet (value=2).\n */\nMoneroNetworkType.STAGENET = 2;\n\nmodule.exports = MoneroNetworkType;","'use strict'\nvar inherits = require('inherits')\nvar MD5 = require('md5.js')\nvar RIPEMD160 = require('ripemd160')\nvar sha = require('sha.js')\nvar Base = require('cipher-base')\n\nfunction Hash (hash) {\n Base.call(this, 'digest')\n\n this._hash = hash\n}\n\ninherits(Hash, Base)\n\nHash.prototype._update = function (data) {\n this._hash.update(data)\n}\n\nHash.prototype._final = function () {\n return this._hash.digest()\n}\n\nmodule.exports = function createHash (alg) {\n alg = alg.toLowerCase()\n if (alg === 'md5') return new MD5()\n if (alg === 'rmd160' || alg === 'ripemd160') return new RIPEMD160()\n\n return new Hash(sha(alg))\n}\n","module.exports = function xor (a, b) {\n var length = Math.min(a.length, b.length)\n var buffer = new Buffer(length)\n\n for (var i = 0; i < length; ++i) {\n buffer[i] = a[i] ^ b[i]\n }\n\n return buffer\n}\n","'use strict';\n\nvar utils = require('./utils');\nvar assert = require('minimalistic-assert');\n\nfunction BlockHash() {\n this.pending = null;\n this.pendingTotal = 0;\n this.blockSize = this.constructor.blockSize;\n this.outSize = this.constructor.outSize;\n this.hmacStrength = this.constructor.hmacStrength;\n this.padLength = this.constructor.padLength / 8;\n this.endian = 'big';\n\n this._delta8 = this.blockSize / 8;\n this._delta32 = this.blockSize / 32;\n}\nexports.BlockHash = BlockHash;\n\nBlockHash.prototype.update = function update(msg, enc) {\n // Convert message to array, pad it, and join into 32bit blocks\n msg = utils.toArray(msg, enc);\n if (!this.pending)\n this.pending = msg;\n else\n this.pending = this.pending.concat(msg);\n this.pendingTotal += msg.length;\n\n // Enough data, try updating\n if (this.pending.length >= this._delta8) {\n msg = this.pending;\n\n // Process pending data in blocks\n var r = msg.length % this._delta8;\n this.pending = msg.slice(msg.length - r, msg.length);\n if (this.pending.length === 0)\n this.pending = null;\n\n msg = utils.join32(msg, 0, msg.length - r, this.endian);\n for (var i = 0; i < msg.length; i += this._delta32)\n this._update(msg, i, i + this._delta32);\n }\n\n return this;\n};\n\nBlockHash.prototype.digest = function digest(enc) {\n this.update(this._pad());\n assert(this.pending === null);\n\n return this._digest(enc);\n};\n\nBlockHash.prototype._pad = function pad() {\n var len = this.pendingTotal;\n var bytes = this._delta8;\n var k = bytes - ((len + this.padLength) % bytes);\n var res = new Array(k + this.padLength);\n res[0] = 0x80;\n for (var i = 1; i < k; i++)\n res[i] = 0;\n\n // Append length\n len <<= 3;\n if (this.endian === 'big') {\n for (var t = 8; t < this.padLength; t++)\n res[i++] = 0;\n\n res[i++] = 0;\n res[i++] = 0;\n res[i++] = 0;\n res[i++] = 0;\n res[i++] = (len >>> 24) & 0xff;\n res[i++] = (len >>> 16) & 0xff;\n res[i++] = (len >>> 8) & 0xff;\n res[i++] = len & 0xff;\n } else {\n res[i++] = len & 0xff;\n res[i++] = (len >>> 8) & 0xff;\n res[i++] = (len >>> 16) & 0xff;\n res[i++] = (len >>> 24) & 0xff;\n res[i++] = 0;\n res[i++] = 0;\n res[i++] = 0;\n res[i++] = 0;\n\n for (t = 8; t < this.padLength; t++)\n res[i++] = 0;\n }\n\n return res;\n};\n","var asn1 = exports;\n\nasn1.bignum = require('bn.js');\n\nasn1.define = require('./asn1/api').define;\nasn1.base = require('./asn1/base');\nasn1.constants = require('./asn1/constants');\nasn1.decoders = require('./asn1/decoders');\nasn1.encoders = require('./asn1/encoders');\n","var base = exports;\n\nbase.Reporter = require('./reporter').Reporter;\nbase.DecoderBuffer = require('./buffer').DecoderBuffer;\nbase.EncoderBuffer = require('./buffer').EncoderBuffer;\nbase.Node = require('./node');\n","// Copyright 2015 Joyent, Inc.\n\nmodule.exports = Fingerprint;\n\nvar assert = require('assert-plus');\nvar Buffer = require('safer-buffer').Buffer;\nvar algs = require('./algs');\nvar crypto = require('crypto');\nvar errs = require('./errors');\nvar Key = require('./key');\nvar Certificate = require('./certificate');\nvar utils = require('./utils');\n\nvar FingerprintFormatError = errs.FingerprintFormatError;\nvar InvalidAlgorithmError = errs.InvalidAlgorithmError;\n\nfunction Fingerprint(opts) {\n\tassert.object(opts, 'options');\n\tassert.string(opts.type, 'options.type');\n\tassert.buffer(opts.hash, 'options.hash');\n\tassert.string(opts.algorithm, 'options.algorithm');\n\n\tthis.algorithm = opts.algorithm.toLowerCase();\n\tif (algs.hashAlgs[this.algorithm] !== true)\n\t\tthrow (new InvalidAlgorithmError(this.algorithm));\n\n\tthis.hash = opts.hash;\n\tthis.type = opts.type;\n}\n\nFingerprint.prototype.toString = function (format) {\n\tif (format === undefined) {\n\t\tif (this.algorithm === 'md5')\n\t\t\tformat = 'hex';\n\t\telse\n\t\t\tformat = 'base64';\n\t}\n\tassert.string(format);\n\n\tswitch (format) {\n\tcase 'hex':\n\t\treturn (addColons(this.hash.toString('hex')));\n\tcase 'base64':\n\t\treturn (sshBase64Format(this.algorithm,\n\t\t this.hash.toString('base64')));\n\tdefault:\n\t\tthrow (new FingerprintFormatError(undefined, format));\n\t}\n};\n\nFingerprint.prototype.matches = function (other) {\n\tassert.object(other, 'key or certificate');\n\tif (this.type === 'key') {\n\t\tutils.assertCompatible(other, Key, [1, 0], 'key');\n\t} else {\n\t\tutils.assertCompatible(other, Certificate, [1, 0],\n\t\t 'certificate');\n\t}\n\n\tvar theirHash = other.hash(this.algorithm);\n\tvar theirHash2 = crypto.createHash(this.algorithm).\n\t update(theirHash).digest('base64');\n\n\tif (this.hash2 === undefined)\n\t\tthis.hash2 = crypto.createHash(this.algorithm).\n\t\t update(this.hash).digest('base64');\n\n\treturn (this.hash2 === theirHash2);\n};\n\nFingerprint.parse = function (fp, options) {\n\tassert.string(fp, 'fingerprint');\n\n\tvar alg, hash, enAlgs;\n\tif (Array.isArray(options)) {\n\t\tenAlgs = options;\n\t\toptions = {};\n\t}\n\tassert.optionalObject(options, 'options');\n\tif (options === undefined)\n\t\toptions = {};\n\tif (options.enAlgs !== undefined)\n\t\tenAlgs = options.enAlgs;\n\tassert.optionalArrayOfString(enAlgs, 'algorithms');\n\n\tvar parts = fp.split(':');\n\tif (parts.length == 2) {\n\t\talg = parts[0].toLowerCase();\n\t\t/*JSSTYLED*/\n\t\tvar base64RE = /^[A-Za-z0-9+\\/=]+$/;\n\t\tif (!base64RE.test(parts[1]))\n\t\t\tthrow (new FingerprintFormatError(fp));\n\t\ttry {\n\t\t\thash = Buffer.from(parts[1], 'base64');\n\t\t} catch (e) {\n\t\t\tthrow (new FingerprintFormatError(fp));\n\t\t}\n\t} else if (parts.length > 2) {\n\t\talg = 'md5';\n\t\tif (parts[0].toLowerCase() === 'md5')\n\t\t\tparts = parts.slice(1);\n\t\tparts = parts.map(function (p) {\n\t\t\twhile (p.length < 2)\n\t\t\t\tp = '0' + p;\n\t\t\tif (p.length > 2)\n\t\t\t\tthrow (new FingerprintFormatError(fp));\n\t\t\treturn (p);\n\t\t});\n\t\tparts = parts.join('');\n\t\t/*JSSTYLED*/\n\t\tvar md5RE = /^[a-fA-F0-9]+$/;\n\t\tif (!md5RE.test(parts) || parts.length % 2 !== 0)\n\t\t\tthrow (new FingerprintFormatError(fp));\n\t\ttry {\n\t\t\thash = Buffer.from(parts, 'hex');\n\t\t} catch (e) {\n\t\t\tthrow (new FingerprintFormatError(fp));\n\t\t}\n\t}\n\n\tif (alg === undefined)\n\t\tthrow (new FingerprintFormatError(fp));\n\n\tif (algs.hashAlgs[alg] === undefined)\n\t\tthrow (new InvalidAlgorithmError(alg));\n\n\tif (enAlgs !== undefined) {\n\t\tenAlgs = enAlgs.map(function (a) { return a.toLowerCase(); });\n\t\tif (enAlgs.indexOf(alg) === -1)\n\t\t\tthrow (new InvalidAlgorithmError(alg));\n\t}\n\n\treturn (new Fingerprint({\n\t\talgorithm: alg,\n\t\thash: hash,\n\t\ttype: options.type || 'key'\n\t}));\n};\n\nfunction addColons(s) {\n\t/*JSSTYLED*/\n\treturn (s.replace(/(.{2})(?=.)/g, '$1:'));\n}\n\nfunction base64Strip(s) {\n\t/*JSSTYLED*/\n\treturn (s.replace(/=*$/, ''));\n}\n\nfunction sshBase64Format(alg, h) {\n\treturn (alg.toUpperCase() + ':' + base64Strip(h));\n}\n\nFingerprint.isFingerprint = function (obj, ver) {\n\treturn (utils.isCompatible(obj, Fingerprint, ver));\n};\n\n/*\n * API versions for Fingerprint:\n * [1,0] -- initial ver\n * [1,1] -- first tagged ver\n */\nFingerprint.prototype._sshpkApiVersion = [1, 1];\n\nFingerprint._oldVersionDetect = function (obj) {\n\tassert.func(obj.toString);\n\tassert.func(obj.matches);\n\treturn ([1, 0]);\n};\n","// Copyright 2016 Joyent, Inc.\n\nmodule.exports = Certificate;\n\nvar assert = require('assert-plus');\nvar Buffer = require('safer-buffer').Buffer;\nvar algs = require('./algs');\nvar crypto = require('crypto');\nvar Fingerprint = require('./fingerprint');\nvar Signature = require('./signature');\nvar errs = require('./errors');\nvar util = require('util');\nvar utils = require('./utils');\nvar Key = require('./key');\nvar PrivateKey = require('./private-key');\nvar Identity = require('./identity');\n\nvar formats = {};\nformats['openssh'] = require('./formats/openssh-cert');\nformats['x509'] = require('./formats/x509');\nformats['pem'] = require('./formats/x509-pem');\n\nvar CertificateParseError = errs.CertificateParseError;\nvar InvalidAlgorithmError = errs.InvalidAlgorithmError;\n\nfunction Certificate(opts) {\n\tassert.object(opts, 'options');\n\tassert.arrayOfObject(opts.subjects, 'options.subjects');\n\tutils.assertCompatible(opts.subjects[0], Identity, [1, 0],\n\t 'options.subjects');\n\tutils.assertCompatible(opts.subjectKey, Key, [1, 0],\n\t 'options.subjectKey');\n\tutils.assertCompatible(opts.issuer, Identity, [1, 0], 'options.issuer');\n\tif (opts.issuerKey !== undefined) {\n\t\tutils.assertCompatible(opts.issuerKey, Key, [1, 0],\n\t\t 'options.issuerKey');\n\t}\n\tassert.object(opts.signatures, 'options.signatures');\n\tassert.buffer(opts.serial, 'options.serial');\n\tassert.date(opts.validFrom, 'options.validFrom');\n\tassert.date(opts.validUntil, 'optons.validUntil');\n\n\tassert.optionalArrayOfString(opts.purposes, 'options.purposes');\n\n\tthis._hashCache = {};\n\n\tthis.subjects = opts.subjects;\n\tthis.issuer = opts.issuer;\n\tthis.subjectKey = opts.subjectKey;\n\tthis.issuerKey = opts.issuerKey;\n\tthis.signatures = opts.signatures;\n\tthis.serial = opts.serial;\n\tthis.validFrom = opts.validFrom;\n\tthis.validUntil = opts.validUntil;\n\tthis.purposes = opts.purposes;\n}\n\nCertificate.formats = formats;\n\nCertificate.prototype.toBuffer = function (format, options) {\n\tif (format === undefined)\n\t\tformat = 'x509';\n\tassert.string(format, 'format');\n\tassert.object(formats[format], 'formats[format]');\n\tassert.optionalObject(options, 'options');\n\n\treturn (formats[format].write(this, options));\n};\n\nCertificate.prototype.toString = function (format, options) {\n\tif (format === undefined)\n\t\tformat = 'pem';\n\treturn (this.toBuffer(format, options).toString());\n};\n\nCertificate.prototype.fingerprint = function (algo) {\n\tif (algo === undefined)\n\t\talgo = 'sha256';\n\tassert.string(algo, 'algorithm');\n\tvar opts = {\n\t\ttype: 'certificate',\n\t\thash: this.hash(algo),\n\t\talgorithm: algo\n\t};\n\treturn (new Fingerprint(opts));\n};\n\nCertificate.prototype.hash = function (algo) {\n\tassert.string(algo, 'algorithm');\n\talgo = algo.toLowerCase();\n\tif (algs.hashAlgs[algo] === undefined)\n\t\tthrow (new InvalidAlgorithmError(algo));\n\n\tif (this._hashCache[algo])\n\t\treturn (this._hashCache[algo]);\n\n\tvar hash = crypto.createHash(algo).\n\t update(this.toBuffer('x509')).digest();\n\tthis._hashCache[algo] = hash;\n\treturn (hash);\n};\n\nCertificate.prototype.isExpired = function (when) {\n\tif (when === undefined)\n\t\twhen = new Date();\n\treturn (!((when.getTime() >= this.validFrom.getTime()) &&\n\t\t(when.getTime() < this.validUntil.getTime())));\n};\n\nCertificate.prototype.isSignedBy = function (issuerCert) {\n\tutils.assertCompatible(issuerCert, Certificate, [1, 0], 'issuer');\n\n\tif (!this.issuer.equals(issuerCert.subjects[0]))\n\t\treturn (false);\n\tif (this.issuer.purposes && this.issuer.purposes.length > 0 &&\n\t this.issuer.purposes.indexOf('ca') === -1) {\n\t\treturn (false);\n\t}\n\n\treturn (this.isSignedByKey(issuerCert.subjectKey));\n};\n\nCertificate.prototype.getExtension = function (keyOrOid) {\n\tassert.string(keyOrOid, 'keyOrOid');\n\tvar ext = this.getExtensions().filter(function (maybeExt) {\n\t\tif (maybeExt.format === 'x509')\n\t\t\treturn (maybeExt.oid === keyOrOid);\n\t\tif (maybeExt.format === 'openssh')\n\t\t\treturn (maybeExt.name === keyOrOid);\n\t\treturn (false);\n\t})[0];\n\treturn (ext);\n};\n\nCertificate.prototype.getExtensions = function () {\n\tvar exts = [];\n\tvar x509 = this.signatures.x509;\n\tif (x509 && x509.extras && x509.extras.exts) {\n\t\tx509.extras.exts.forEach(function (ext) {\n\t\t\text.format = 'x509';\n\t\t\texts.push(ext);\n\t\t});\n\t}\n\tvar openssh = this.signatures.openssh;\n\tif (openssh && openssh.exts) {\n\t\topenssh.exts.forEach(function (ext) {\n\t\t\text.format = 'openssh';\n\t\t\texts.push(ext);\n\t\t});\n\t}\n\treturn (exts);\n};\n\nCertificate.prototype.isSignedByKey = function (issuerKey) {\n\tutils.assertCompatible(issuerKey, Key, [1, 2], 'issuerKey');\n\n\tif (this.issuerKey !== undefined) {\n\t\treturn (this.issuerKey.\n\t\t fingerprint('sha512').matches(issuerKey));\n\t}\n\n\tvar fmt = Object.keys(this.signatures)[0];\n\tvar valid = formats[fmt].verify(this, issuerKey);\n\tif (valid)\n\t\tthis.issuerKey = issuerKey;\n\treturn (valid);\n};\n\nCertificate.prototype.signWith = function (key) {\n\tutils.assertCompatible(key, PrivateKey, [1, 2], 'key');\n\tvar fmts = Object.keys(formats);\n\tvar didOne = false;\n\tfor (var i = 0; i < fmts.length; ++i) {\n\t\tif (fmts[i] !== 'pem') {\n\t\t\tvar ret = formats[fmts[i]].sign(this, key);\n\t\t\tif (ret === true)\n\t\t\t\tdidOne = true;\n\t\t}\n\t}\n\tif (!didOne) {\n\t\tthrow (new Error('Failed to sign the certificate for any ' +\n\t\t 'available certificate formats'));\n\t}\n};\n\nCertificate.createSelfSigned = function (subjectOrSubjects, key, options) {\n\tvar subjects;\n\tif (Array.isArray(subjectOrSubjects))\n\t\tsubjects = subjectOrSubjects;\n\telse\n\t\tsubjects = [subjectOrSubjects];\n\n\tassert.arrayOfObject(subjects);\n\tsubjects.forEach(function (subject) {\n\t\tutils.assertCompatible(subject, Identity, [1, 0], 'subject');\n\t});\n\n\tutils.assertCompatible(key, PrivateKey, [1, 2], 'private key');\n\n\tassert.optionalObject(options, 'options');\n\tif (options === undefined)\n\t\toptions = {};\n\tassert.optionalObject(options.validFrom, 'options.validFrom');\n\tassert.optionalObject(options.validUntil, 'options.validUntil');\n\tvar validFrom = options.validFrom;\n\tvar validUntil = options.validUntil;\n\tif (validFrom === undefined)\n\t\tvalidFrom = new Date();\n\tif (validUntil === undefined) {\n\t\tassert.optionalNumber(options.lifetime, 'options.lifetime');\n\t\tvar lifetime = options.lifetime;\n\t\tif (lifetime === undefined)\n\t\t\tlifetime = 10*365*24*3600;\n\t\tvalidUntil = new Date();\n\t\tvalidUntil.setTime(validUntil.getTime() + lifetime*1000);\n\t}\n\tassert.optionalBuffer(options.serial, 'options.serial');\n\tvar serial = options.serial;\n\tif (serial === undefined)\n\t\tserial = Buffer.from('0000000000000001', 'hex');\n\n\tvar purposes = options.purposes;\n\tif (purposes === undefined)\n\t\tpurposes = [];\n\n\tif (purposes.indexOf('signature') === -1)\n\t\tpurposes.push('signature');\n\n\t/* Self-signed certs are always CAs. */\n\tif (purposes.indexOf('ca') === -1)\n\t\tpurposes.push('ca');\n\tif (purposes.indexOf('crl') === -1)\n\t\tpurposes.push('crl');\n\n\t/*\n\t * If we weren't explicitly given any other purposes, do the sensible\n\t * thing and add some basic ones depending on the subject type.\n\t */\n\tif (purposes.length <= 3) {\n\t\tvar hostSubjects = subjects.filter(function (subject) {\n\t\t\treturn (subject.type === 'host');\n\t\t});\n\t\tvar userSubjects = subjects.filter(function (subject) {\n\t\t\treturn (subject.type === 'user');\n\t\t});\n\t\tif (hostSubjects.length > 0) {\n\t\t\tif (purposes.indexOf('serverAuth') === -1)\n\t\t\t\tpurposes.push('serverAuth');\n\t\t}\n\t\tif (userSubjects.length > 0) {\n\t\t\tif (purposes.indexOf('clientAuth') === -1)\n\t\t\t\tpurposes.push('clientAuth');\n\t\t}\n\t\tif (userSubjects.length > 0 || hostSubjects.length > 0) {\n\t\t\tif (purposes.indexOf('keyAgreement') === -1)\n\t\t\t\tpurposes.push('keyAgreement');\n\t\t\tif (key.type === 'rsa' &&\n\t\t\t purposes.indexOf('encryption') === -1)\n\t\t\t\tpurposes.push('encryption');\n\t\t}\n\t}\n\n\tvar cert = new Certificate({\n\t\tsubjects: subjects,\n\t\tissuer: subjects[0],\n\t\tsubjectKey: key.toPublic(),\n\t\tissuerKey: key.toPublic(),\n\t\tsignatures: {},\n\t\tserial: serial,\n\t\tvalidFrom: validFrom,\n\t\tvalidUntil: validUntil,\n\t\tpurposes: purposes\n\t});\n\tcert.signWith(key);\n\n\treturn (cert);\n};\n\nCertificate.create =\n function (subjectOrSubjects, key, issuer, issuerKey, options) {\n\tvar subjects;\n\tif (Array.isArray(subjectOrSubjects))\n\t\tsubjects = subjectOrSubjects;\n\telse\n\t\tsubjects = [subjectOrSubjects];\n\n\tassert.arrayOfObject(subjects);\n\tsubjects.forEach(function (subject) {\n\t\tutils.assertCompatible(subject, Identity, [1, 0], 'subject');\n\t});\n\n\tutils.assertCompatible(key, Key, [1, 0], 'key');\n\tif (PrivateKey.isPrivateKey(key))\n\t\tkey = key.toPublic();\n\tutils.assertCompatible(issuer, Identity, [1, 0], 'issuer');\n\tutils.assertCompatible(issuerKey, PrivateKey, [1, 2], 'issuer key');\n\n\tassert.optionalObject(options, 'options');\n\tif (options === undefined)\n\t\toptions = {};\n\tassert.optionalObject(options.validFrom, 'options.validFrom');\n\tassert.optionalObject(options.validUntil, 'options.validUntil');\n\tvar validFrom = options.validFrom;\n\tvar validUntil = options.validUntil;\n\tif (validFrom === undefined)\n\t\tvalidFrom = new Date();\n\tif (validUntil === undefined) {\n\t\tassert.optionalNumber(options.lifetime, 'options.lifetime');\n\t\tvar lifetime = options.lifetime;\n\t\tif (lifetime === undefined)\n\t\t\tlifetime = 10*365*24*3600;\n\t\tvalidUntil = new Date();\n\t\tvalidUntil.setTime(validUntil.getTime() + lifetime*1000);\n\t}\n\tassert.optionalBuffer(options.serial, 'options.serial');\n\tvar serial = options.serial;\n\tif (serial === undefined)\n\t\tserial = Buffer.from('0000000000000001', 'hex');\n\n\tvar purposes = options.purposes;\n\tif (purposes === undefined)\n\t\tpurposes = [];\n\n\tif (purposes.indexOf('signature') === -1)\n\t\tpurposes.push('signature');\n\n\tif (options.ca === true) {\n\t\tif (purposes.indexOf('ca') === -1)\n\t\t\tpurposes.push('ca');\n\t\tif (purposes.indexOf('crl') === -1)\n\t\t\tpurposes.push('crl');\n\t}\n\n\tvar hostSubjects = subjects.filter(function (subject) {\n\t\treturn (subject.type === 'host');\n\t});\n\tvar userSubjects = subjects.filter(function (subject) {\n\t\treturn (subject.type === 'user');\n\t});\n\tif (hostSubjects.length > 0) {\n\t\tif (purposes.indexOf('serverAuth') === -1)\n\t\t\tpurposes.push('serverAuth');\n\t}\n\tif (userSubjects.length > 0) {\n\t\tif (purposes.indexOf('clientAuth') === -1)\n\t\t\tpurposes.push('clientAuth');\n\t}\n\tif (userSubjects.length > 0 || hostSubjects.length > 0) {\n\t\tif (purposes.indexOf('keyAgreement') === -1)\n\t\t\tpurposes.push('keyAgreement');\n\t\tif (key.type === 'rsa' &&\n\t\t purposes.indexOf('encryption') === -1)\n\t\t\tpurposes.push('encryption');\n\t}\n\n\tvar cert = new Certificate({\n\t\tsubjects: subjects,\n\t\tissuer: issuer,\n\t\tsubjectKey: key,\n\t\tissuerKey: issuerKey.toPublic(),\n\t\tsignatures: {},\n\t\tserial: serial,\n\t\tvalidFrom: validFrom,\n\t\tvalidUntil: validUntil,\n\t\tpurposes: purposes\n\t});\n\tcert.signWith(issuerKey);\n\n\treturn (cert);\n};\n\nCertificate.parse = function (data, format, options) {\n\tif (typeof (data) !== 'string')\n\t\tassert.buffer(data, 'data');\n\tif (format === undefined)\n\t\tformat = 'auto';\n\tassert.string(format, 'format');\n\tif (typeof (options) === 'string')\n\t\toptions = { filename: options };\n\tassert.optionalObject(options, 'options');\n\tif (options === undefined)\n\t\toptions = {};\n\tassert.optionalString(options.filename, 'options.filename');\n\tif (options.filename === undefined)\n\t\toptions.filename = '(unnamed)';\n\n\tassert.object(formats[format], 'formats[format]');\n\n\ttry {\n\t\tvar k = formats[format].read(data, options);\n\t\treturn (k);\n\t} catch (e) {\n\t\tthrow (new CertificateParseError(options.filename, format, e));\n\t}\n};\n\nCertificate.isCertificate = function (obj, ver) {\n\treturn (utils.isCompatible(obj, Certificate, ver));\n};\n\n/*\n * API versions for Certificate:\n * [1,0] -- initial ver\n * [1,1] -- openssh format now unpacks extensions\n */\nCertificate.prototype._sshpkApiVersion = [1, 1];\n\nCertificate._oldVersionDetect = function (obj) {\n\treturn ([1, 0]);\n};\n","(function(nacl) {\n'use strict';\n\n// Ported in 2014 by Dmitry Chestnykh and Devi Mandiri.\n// Public domain.\n//\n// Implementation derived from TweetNaCl version 20140427.\n// See for details: http://tweetnacl.cr.yp.to/\n\nvar gf = function(init) {\n var i, r = new Float64Array(16);\n if (init) for (i = 0; i < init.length; i++) r[i] = init[i];\n return r;\n};\n\n// Pluggable, initialized in high-level API below.\nvar randombytes = function(/* x, n */) { throw new Error('no PRNG'); };\n\nvar _0 = new Uint8Array(16);\nvar _9 = new Uint8Array(32); _9[0] = 9;\n\nvar gf0 = gf(),\n gf1 = gf([1]),\n _121665 = gf([0xdb41, 1]),\n D = gf([0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]),\n D2 = gf([0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]),\n X = gf([0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]),\n Y = gf([0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]),\n I = gf([0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]);\n\nfunction ts64(x, i, h, l) {\n x[i] = (h >> 24) & 0xff;\n x[i+1] = (h >> 16) & 0xff;\n x[i+2] = (h >> 8) & 0xff;\n x[i+3] = h & 0xff;\n x[i+4] = (l >> 24) & 0xff;\n x[i+5] = (l >> 16) & 0xff;\n x[i+6] = (l >> 8) & 0xff;\n x[i+7] = l & 0xff;\n}\n\nfunction vn(x, xi, y, yi, n) {\n var i,d = 0;\n for (i = 0; i < n; i++) d |= x[xi+i]^y[yi+i];\n return (1 & ((d - 1) >>> 8)) - 1;\n}\n\nfunction crypto_verify_16(x, xi, y, yi) {\n return vn(x,xi,y,yi,16);\n}\n\nfunction crypto_verify_32(x, xi, y, yi) {\n return vn(x,xi,y,yi,32);\n}\n\nfunction core_salsa20(o, p, k, c) {\n var j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24,\n j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24,\n j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24,\n j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24,\n j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24,\n j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24,\n j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24,\n j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24,\n j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24,\n j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24,\n j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24,\n j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24,\n j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24,\n j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24,\n j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24,\n j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24;\n\n var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7,\n x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14,\n x15 = j15, u;\n\n for (var i = 0; i < 20; i += 2) {\n u = x0 + x12 | 0;\n x4 ^= u<<7 | u>>>(32-7);\n u = x4 + x0 | 0;\n x8 ^= u<<9 | u>>>(32-9);\n u = x8 + x4 | 0;\n x12 ^= u<<13 | u>>>(32-13);\n u = x12 + x8 | 0;\n x0 ^= u<<18 | u>>>(32-18);\n\n u = x5 + x1 | 0;\n x9 ^= u<<7 | u>>>(32-7);\n u = x9 + x5 | 0;\n x13 ^= u<<9 | u>>>(32-9);\n u = x13 + x9 | 0;\n x1 ^= u<<13 | u>>>(32-13);\n u = x1 + x13 | 0;\n x5 ^= u<<18 | u>>>(32-18);\n\n u = x10 + x6 | 0;\n x14 ^= u<<7 | u>>>(32-7);\n u = x14 + x10 | 0;\n x2 ^= u<<9 | u>>>(32-9);\n u = x2 + x14 | 0;\n x6 ^= u<<13 | u>>>(32-13);\n u = x6 + x2 | 0;\n x10 ^= u<<18 | u>>>(32-18);\n\n u = x15 + x11 | 0;\n x3 ^= u<<7 | u>>>(32-7);\n u = x3 + x15 | 0;\n x7 ^= u<<9 | u>>>(32-9);\n u = x7 + x3 | 0;\n x11 ^= u<<13 | u>>>(32-13);\n u = x11 + x7 | 0;\n x15 ^= u<<18 | u>>>(32-18);\n\n u = x0 + x3 | 0;\n x1 ^= u<<7 | u>>>(32-7);\n u = x1 + x0 | 0;\n x2 ^= u<<9 | u>>>(32-9);\n u = x2 + x1 | 0;\n x3 ^= u<<13 | u>>>(32-13);\n u = x3 + x2 | 0;\n x0 ^= u<<18 | u>>>(32-18);\n\n u = x5 + x4 | 0;\n x6 ^= u<<7 | u>>>(32-7);\n u = x6 + x5 | 0;\n x7 ^= u<<9 | u>>>(32-9);\n u = x7 + x6 | 0;\n x4 ^= u<<13 | u>>>(32-13);\n u = x4 + x7 | 0;\n x5 ^= u<<18 | u>>>(32-18);\n\n u = x10 + x9 | 0;\n x11 ^= u<<7 | u>>>(32-7);\n u = x11 + x10 | 0;\n x8 ^= u<<9 | u>>>(32-9);\n u = x8 + x11 | 0;\n x9 ^= u<<13 | u>>>(32-13);\n u = x9 + x8 | 0;\n x10 ^= u<<18 | u>>>(32-18);\n\n u = x15 + x14 | 0;\n x12 ^= u<<7 | u>>>(32-7);\n u = x12 + x15 | 0;\n x13 ^= u<<9 | u>>>(32-9);\n u = x13 + x12 | 0;\n x14 ^= u<<13 | u>>>(32-13);\n u = x14 + x13 | 0;\n x15 ^= u<<18 | u>>>(32-18);\n }\n x0 = x0 + j0 | 0;\n x1 = x1 + j1 | 0;\n x2 = x2 + j2 | 0;\n x3 = x3 + j3 | 0;\n x4 = x4 + j4 | 0;\n x5 = x5 + j5 | 0;\n x6 = x6 + j6 | 0;\n x7 = x7 + j7 | 0;\n x8 = x8 + j8 | 0;\n x9 = x9 + j9 | 0;\n x10 = x10 + j10 | 0;\n x11 = x11 + j11 | 0;\n x12 = x12 + j12 | 0;\n x13 = x13 + j13 | 0;\n x14 = x14 + j14 | 0;\n x15 = x15 + j15 | 0;\n\n o[ 0] = x0 >>> 0 & 0xff;\n o[ 1] = x0 >>> 8 & 0xff;\n o[ 2] = x0 >>> 16 & 0xff;\n o[ 3] = x0 >>> 24 & 0xff;\n\n o[ 4] = x1 >>> 0 & 0xff;\n o[ 5] = x1 >>> 8 & 0xff;\n o[ 6] = x1 >>> 16 & 0xff;\n o[ 7] = x1 >>> 24 & 0xff;\n\n o[ 8] = x2 >>> 0 & 0xff;\n o[ 9] = x2 >>> 8 & 0xff;\n o[10] = x2 >>> 16 & 0xff;\n o[11] = x2 >>> 24 & 0xff;\n\n o[12] = x3 >>> 0 & 0xff;\n o[13] = x3 >>> 8 & 0xff;\n o[14] = x3 >>> 16 & 0xff;\n o[15] = x3 >>> 24 & 0xff;\n\n o[16] = x4 >>> 0 & 0xff;\n o[17] = x4 >>> 8 & 0xff;\n o[18] = x4 >>> 16 & 0xff;\n o[19] = x4 >>> 24 & 0xff;\n\n o[20] = x5 >>> 0 & 0xff;\n o[21] = x5 >>> 8 & 0xff;\n o[22] = x5 >>> 16 & 0xff;\n o[23] = x5 >>> 24 & 0xff;\n\n o[24] = x6 >>> 0 & 0xff;\n o[25] = x6 >>> 8 & 0xff;\n o[26] = x6 >>> 16 & 0xff;\n o[27] = x6 >>> 24 & 0xff;\n\n o[28] = x7 >>> 0 & 0xff;\n o[29] = x7 >>> 8 & 0xff;\n o[30] = x7 >>> 16 & 0xff;\n o[31] = x7 >>> 24 & 0xff;\n\n o[32] = x8 >>> 0 & 0xff;\n o[33] = x8 >>> 8 & 0xff;\n o[34] = x8 >>> 16 & 0xff;\n o[35] = x8 >>> 24 & 0xff;\n\n o[36] = x9 >>> 0 & 0xff;\n o[37] = x9 >>> 8 & 0xff;\n o[38] = x9 >>> 16 & 0xff;\n o[39] = x9 >>> 24 & 0xff;\n\n o[40] = x10 >>> 0 & 0xff;\n o[41] = x10 >>> 8 & 0xff;\n o[42] = x10 >>> 16 & 0xff;\n o[43] = x10 >>> 24 & 0xff;\n\n o[44] = x11 >>> 0 & 0xff;\n o[45] = x11 >>> 8 & 0xff;\n o[46] = x11 >>> 16 & 0xff;\n o[47] = x11 >>> 24 & 0xff;\n\n o[48] = x12 >>> 0 & 0xff;\n o[49] = x12 >>> 8 & 0xff;\n o[50] = x12 >>> 16 & 0xff;\n o[51] = x12 >>> 24 & 0xff;\n\n o[52] = x13 >>> 0 & 0xff;\n o[53] = x13 >>> 8 & 0xff;\n o[54] = x13 >>> 16 & 0xff;\n o[55] = x13 >>> 24 & 0xff;\n\n o[56] = x14 >>> 0 & 0xff;\n o[57] = x14 >>> 8 & 0xff;\n o[58] = x14 >>> 16 & 0xff;\n o[59] = x14 >>> 24 & 0xff;\n\n o[60] = x15 >>> 0 & 0xff;\n o[61] = x15 >>> 8 & 0xff;\n o[62] = x15 >>> 16 & 0xff;\n o[63] = x15 >>> 24 & 0xff;\n}\n\nfunction core_hsalsa20(o,p,k,c) {\n var j0 = c[ 0] & 0xff | (c[ 1] & 0xff)<<8 | (c[ 2] & 0xff)<<16 | (c[ 3] & 0xff)<<24,\n j1 = k[ 0] & 0xff | (k[ 1] & 0xff)<<8 | (k[ 2] & 0xff)<<16 | (k[ 3] & 0xff)<<24,\n j2 = k[ 4] & 0xff | (k[ 5] & 0xff)<<8 | (k[ 6] & 0xff)<<16 | (k[ 7] & 0xff)<<24,\n j3 = k[ 8] & 0xff | (k[ 9] & 0xff)<<8 | (k[10] & 0xff)<<16 | (k[11] & 0xff)<<24,\n j4 = k[12] & 0xff | (k[13] & 0xff)<<8 | (k[14] & 0xff)<<16 | (k[15] & 0xff)<<24,\n j5 = c[ 4] & 0xff | (c[ 5] & 0xff)<<8 | (c[ 6] & 0xff)<<16 | (c[ 7] & 0xff)<<24,\n j6 = p[ 0] & 0xff | (p[ 1] & 0xff)<<8 | (p[ 2] & 0xff)<<16 | (p[ 3] & 0xff)<<24,\n j7 = p[ 4] & 0xff | (p[ 5] & 0xff)<<8 | (p[ 6] & 0xff)<<16 | (p[ 7] & 0xff)<<24,\n j8 = p[ 8] & 0xff | (p[ 9] & 0xff)<<8 | (p[10] & 0xff)<<16 | (p[11] & 0xff)<<24,\n j9 = p[12] & 0xff | (p[13] & 0xff)<<8 | (p[14] & 0xff)<<16 | (p[15] & 0xff)<<24,\n j10 = c[ 8] & 0xff | (c[ 9] & 0xff)<<8 | (c[10] & 0xff)<<16 | (c[11] & 0xff)<<24,\n j11 = k[16] & 0xff | (k[17] & 0xff)<<8 | (k[18] & 0xff)<<16 | (k[19] & 0xff)<<24,\n j12 = k[20] & 0xff | (k[21] & 0xff)<<8 | (k[22] & 0xff)<<16 | (k[23] & 0xff)<<24,\n j13 = k[24] & 0xff | (k[25] & 0xff)<<8 | (k[26] & 0xff)<<16 | (k[27] & 0xff)<<24,\n j14 = k[28] & 0xff | (k[29] & 0xff)<<8 | (k[30] & 0xff)<<16 | (k[31] & 0xff)<<24,\n j15 = c[12] & 0xff | (c[13] & 0xff)<<8 | (c[14] & 0xff)<<16 | (c[15] & 0xff)<<24;\n\n var x0 = j0, x1 = j1, x2 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7,\n x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14,\n x15 = j15, u;\n\n for (var i = 0; i < 20; i += 2) {\n u = x0 + x12 | 0;\n x4 ^= u<<7 | u>>>(32-7);\n u = x4 + x0 | 0;\n x8 ^= u<<9 | u>>>(32-9);\n u = x8 + x4 | 0;\n x12 ^= u<<13 | u>>>(32-13);\n u = x12 + x8 | 0;\n x0 ^= u<<18 | u>>>(32-18);\n\n u = x5 + x1 | 0;\n x9 ^= u<<7 | u>>>(32-7);\n u = x9 + x5 | 0;\n x13 ^= u<<9 | u>>>(32-9);\n u = x13 + x9 | 0;\n x1 ^= u<<13 | u>>>(32-13);\n u = x1 + x13 | 0;\n x5 ^= u<<18 | u>>>(32-18);\n\n u = x10 + x6 | 0;\n x14 ^= u<<7 | u>>>(32-7);\n u = x14 + x10 | 0;\n x2 ^= u<<9 | u>>>(32-9);\n u = x2 + x14 | 0;\n x6 ^= u<<13 | u>>>(32-13);\n u = x6 + x2 | 0;\n x10 ^= u<<18 | u>>>(32-18);\n\n u = x15 + x11 | 0;\n x3 ^= u<<7 | u>>>(32-7);\n u = x3 + x15 | 0;\n x7 ^= u<<9 | u>>>(32-9);\n u = x7 + x3 | 0;\n x11 ^= u<<13 | u>>>(32-13);\n u = x11 + x7 | 0;\n x15 ^= u<<18 | u>>>(32-18);\n\n u = x0 + x3 | 0;\n x1 ^= u<<7 | u>>>(32-7);\n u = x1 + x0 | 0;\n x2 ^= u<<9 | u>>>(32-9);\n u = x2 + x1 | 0;\n x3 ^= u<<13 | u>>>(32-13);\n u = x3 + x2 | 0;\n x0 ^= u<<18 | u>>>(32-18);\n\n u = x5 + x4 | 0;\n x6 ^= u<<7 | u>>>(32-7);\n u = x6 + x5 | 0;\n x7 ^= u<<9 | u>>>(32-9);\n u = x7 + x6 | 0;\n x4 ^= u<<13 | u>>>(32-13);\n u = x4 + x7 | 0;\n x5 ^= u<<18 | u>>>(32-18);\n\n u = x10 + x9 | 0;\n x11 ^= u<<7 | u>>>(32-7);\n u = x11 + x10 | 0;\n x8 ^= u<<9 | u>>>(32-9);\n u = x8 + x11 | 0;\n x9 ^= u<<13 | u>>>(32-13);\n u = x9 + x8 | 0;\n x10 ^= u<<18 | u>>>(32-18);\n\n u = x15 + x14 | 0;\n x12 ^= u<<7 | u>>>(32-7);\n u = x12 + x15 | 0;\n x13 ^= u<<9 | u>>>(32-9);\n u = x13 + x12 | 0;\n x14 ^= u<<13 | u>>>(32-13);\n u = x14 + x13 | 0;\n x15 ^= u<<18 | u>>>(32-18);\n }\n\n o[ 0] = x0 >>> 0 & 0xff;\n o[ 1] = x0 >>> 8 & 0xff;\n o[ 2] = x0 >>> 16 & 0xff;\n o[ 3] = x0 >>> 24 & 0xff;\n\n o[ 4] = x5 >>> 0 & 0xff;\n o[ 5] = x5 >>> 8 & 0xff;\n o[ 6] = x5 >>> 16 & 0xff;\n o[ 7] = x5 >>> 24 & 0xff;\n\n o[ 8] = x10 >>> 0 & 0xff;\n o[ 9] = x10 >>> 8 & 0xff;\n o[10] = x10 >>> 16 & 0xff;\n o[11] = x10 >>> 24 & 0xff;\n\n o[12] = x15 >>> 0 & 0xff;\n o[13] = x15 >>> 8 & 0xff;\n o[14] = x15 >>> 16 & 0xff;\n o[15] = x15 >>> 24 & 0xff;\n\n o[16] = x6 >>> 0 & 0xff;\n o[17] = x6 >>> 8 & 0xff;\n o[18] = x6 >>> 16 & 0xff;\n o[19] = x6 >>> 24 & 0xff;\n\n o[20] = x7 >>> 0 & 0xff;\n o[21] = x7 >>> 8 & 0xff;\n o[22] = x7 >>> 16 & 0xff;\n o[23] = x7 >>> 24 & 0xff;\n\n o[24] = x8 >>> 0 & 0xff;\n o[25] = x8 >>> 8 & 0xff;\n o[26] = x8 >>> 16 & 0xff;\n o[27] = x8 >>> 24 & 0xff;\n\n o[28] = x9 >>> 0 & 0xff;\n o[29] = x9 >>> 8 & 0xff;\n o[30] = x9 >>> 16 & 0xff;\n o[31] = x9 >>> 24 & 0xff;\n}\n\nfunction crypto_core_salsa20(out,inp,k,c) {\n core_salsa20(out,inp,k,c);\n}\n\nfunction crypto_core_hsalsa20(out,inp,k,c) {\n core_hsalsa20(out,inp,k,c);\n}\n\nvar sigma = new Uint8Array([101, 120, 112, 97, 110, 100, 32, 51, 50, 45, 98, 121, 116, 101, 32, 107]);\n // \"expand 32-byte k\"\n\nfunction crypto_stream_salsa20_xor(c,cpos,m,mpos,b,n,k) {\n var z = new Uint8Array(16), x = new Uint8Array(64);\n var u, i;\n for (i = 0; i < 16; i++) z[i] = 0;\n for (i = 0; i < 8; i++) z[i] = n[i];\n while (b >= 64) {\n crypto_core_salsa20(x,z,k,sigma);\n for (i = 0; i < 64; i++) c[cpos+i] = m[mpos+i] ^ x[i];\n u = 1;\n for (i = 8; i < 16; i++) {\n u = u + (z[i] & 0xff) | 0;\n z[i] = u & 0xff;\n u >>>= 8;\n }\n b -= 64;\n cpos += 64;\n mpos += 64;\n }\n if (b > 0) {\n crypto_core_salsa20(x,z,k,sigma);\n for (i = 0; i < b; i++) c[cpos+i] = m[mpos+i] ^ x[i];\n }\n return 0;\n}\n\nfunction crypto_stream_salsa20(c,cpos,b,n,k) {\n var z = new Uint8Array(16), x = new Uint8Array(64);\n var u, i;\n for (i = 0; i < 16; i++) z[i] = 0;\n for (i = 0; i < 8; i++) z[i] = n[i];\n while (b >= 64) {\n crypto_core_salsa20(x,z,k,sigma);\n for (i = 0; i < 64; i++) c[cpos+i] = x[i];\n u = 1;\n for (i = 8; i < 16; i++) {\n u = u + (z[i] & 0xff) | 0;\n z[i] = u & 0xff;\n u >>>= 8;\n }\n b -= 64;\n cpos += 64;\n }\n if (b > 0) {\n crypto_core_salsa20(x,z,k,sigma);\n for (i = 0; i < b; i++) c[cpos+i] = x[i];\n }\n return 0;\n}\n\nfunction crypto_stream(c,cpos,d,n,k) {\n var s = new Uint8Array(32);\n crypto_core_hsalsa20(s,n,k,sigma);\n var sn = new Uint8Array(8);\n for (var i = 0; i < 8; i++) sn[i] = n[i+16];\n return crypto_stream_salsa20(c,cpos,d,sn,s);\n}\n\nfunction crypto_stream_xor(c,cpos,m,mpos,d,n,k) {\n var s = new Uint8Array(32);\n crypto_core_hsalsa20(s,n,k,sigma);\n var sn = new Uint8Array(8);\n for (var i = 0; i < 8; i++) sn[i] = n[i+16];\n return crypto_stream_salsa20_xor(c,cpos,m,mpos,d,sn,s);\n}\n\n/*\n* Port of Andrew Moon's Poly1305-donna-16. Public domain.\n* https://github.com/floodyberry/poly1305-donna\n*/\n\nvar poly1305 = function(key) {\n this.buffer = new Uint8Array(16);\n this.r = new Uint16Array(10);\n this.h = new Uint16Array(10);\n this.pad = new Uint16Array(8);\n this.leftover = 0;\n this.fin = 0;\n\n var t0, t1, t2, t3, t4, t5, t6, t7;\n\n t0 = key[ 0] & 0xff | (key[ 1] & 0xff) << 8; this.r[0] = ( t0 ) & 0x1fff;\n t1 = key[ 2] & 0xff | (key[ 3] & 0xff) << 8; this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff;\n t2 = key[ 4] & 0xff | (key[ 5] & 0xff) << 8; this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03;\n t3 = key[ 6] & 0xff | (key[ 7] & 0xff) << 8; this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff;\n t4 = key[ 8] & 0xff | (key[ 9] & 0xff) << 8; this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff;\n this.r[5] = ((t4 >>> 1)) & 0x1ffe;\n t5 = key[10] & 0xff | (key[11] & 0xff) << 8; this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff;\n t6 = key[12] & 0xff | (key[13] & 0xff) << 8; this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81;\n t7 = key[14] & 0xff | (key[15] & 0xff) << 8; this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff;\n this.r[9] = ((t7 >>> 5)) & 0x007f;\n\n this.pad[0] = key[16] & 0xff | (key[17] & 0xff) << 8;\n this.pad[1] = key[18] & 0xff | (key[19] & 0xff) << 8;\n this.pad[2] = key[20] & 0xff | (key[21] & 0xff) << 8;\n this.pad[3] = key[22] & 0xff | (key[23] & 0xff) << 8;\n this.pad[4] = key[24] & 0xff | (key[25] & 0xff) << 8;\n this.pad[5] = key[26] & 0xff | (key[27] & 0xff) << 8;\n this.pad[6] = key[28] & 0xff | (key[29] & 0xff) << 8;\n this.pad[7] = key[30] & 0xff | (key[31] & 0xff) << 8;\n};\n\npoly1305.prototype.blocks = function(m, mpos, bytes) {\n var hibit = this.fin ? 0 : (1 << 11);\n var t0, t1, t2, t3, t4, t5, t6, t7, c;\n var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9;\n\n var h0 = this.h[0],\n h1 = this.h[1],\n h2 = this.h[2],\n h3 = this.h[3],\n h4 = this.h[4],\n h5 = this.h[5],\n h6 = this.h[6],\n h7 = this.h[7],\n h8 = this.h[8],\n h9 = this.h[9];\n\n var r0 = this.r[0],\n r1 = this.r[1],\n r2 = this.r[2],\n r3 = this.r[3],\n r4 = this.r[4],\n r5 = this.r[5],\n r6 = this.r[6],\n r7 = this.r[7],\n r8 = this.r[8],\n r9 = this.r[9];\n\n while (bytes >= 16) {\n t0 = m[mpos+ 0] & 0xff | (m[mpos+ 1] & 0xff) << 8; h0 += ( t0 ) & 0x1fff;\n t1 = m[mpos+ 2] & 0xff | (m[mpos+ 3] & 0xff) << 8; h1 += ((t0 >>> 13) | (t1 << 3)) & 0x1fff;\n t2 = m[mpos+ 4] & 0xff | (m[mpos+ 5] & 0xff) << 8; h2 += ((t1 >>> 10) | (t2 << 6)) & 0x1fff;\n t3 = m[mpos+ 6] & 0xff | (m[mpos+ 7] & 0xff) << 8; h3 += ((t2 >>> 7) | (t3 << 9)) & 0x1fff;\n t4 = m[mpos+ 8] & 0xff | (m[mpos+ 9] & 0xff) << 8; h4 += ((t3 >>> 4) | (t4 << 12)) & 0x1fff;\n h5 += ((t4 >>> 1)) & 0x1fff;\n t5 = m[mpos+10] & 0xff | (m[mpos+11] & 0xff) << 8; h6 += ((t4 >>> 14) | (t5 << 2)) & 0x1fff;\n t6 = m[mpos+12] & 0xff | (m[mpos+13] & 0xff) << 8; h7 += ((t5 >>> 11) | (t6 << 5)) & 0x1fff;\n t7 = m[mpos+14] & 0xff | (m[mpos+15] & 0xff) << 8; h8 += ((t6 >>> 8) | (t7 << 8)) & 0x1fff;\n h9 += ((t7 >>> 5)) | hibit;\n\n c = 0;\n\n d0 = c;\n d0 += h0 * r0;\n d0 += h1 * (5 * r9);\n d0 += h2 * (5 * r8);\n d0 += h3 * (5 * r7);\n d0 += h4 * (5 * r6);\n c = (d0 >>> 13); d0 &= 0x1fff;\n d0 += h5 * (5 * r5);\n d0 += h6 * (5 * r4);\n d0 += h7 * (5 * r3);\n d0 += h8 * (5 * r2);\n d0 += h9 * (5 * r1);\n c += (d0 >>> 13); d0 &= 0x1fff;\n\n d1 = c;\n d1 += h0 * r1;\n d1 += h1 * r0;\n d1 += h2 * (5 * r9);\n d1 += h3 * (5 * r8);\n d1 += h4 * (5 * r7);\n c = (d1 >>> 13); d1 &= 0x1fff;\n d1 += h5 * (5 * r6);\n d1 += h6 * (5 * r5);\n d1 += h7 * (5 * r4);\n d1 += h8 * (5 * r3);\n d1 += h9 * (5 * r2);\n c += (d1 >>> 13); d1 &= 0x1fff;\n\n d2 = c;\n d2 += h0 * r2;\n d2 += h1 * r1;\n d2 += h2 * r0;\n d2 += h3 * (5 * r9);\n d2 += h4 * (5 * r8);\n c = (d2 >>> 13); d2 &= 0x1fff;\n d2 += h5 * (5 * r7);\n d2 += h6 * (5 * r6);\n d2 += h7 * (5 * r5);\n d2 += h8 * (5 * r4);\n d2 += h9 * (5 * r3);\n c += (d2 >>> 13); d2 &= 0x1fff;\n\n d3 = c;\n d3 += h0 * r3;\n d3 += h1 * r2;\n d3 += h2 * r1;\n d3 += h3 * r0;\n d3 += h4 * (5 * r9);\n c = (d3 >>> 13); d3 &= 0x1fff;\n d3 += h5 * (5 * r8);\n d3 += h6 * (5 * r7);\n d3 += h7 * (5 * r6);\n d3 += h8 * (5 * r5);\n d3 += h9 * (5 * r4);\n c += (d3 >>> 13); d3 &= 0x1fff;\n\n d4 = c;\n d4 += h0 * r4;\n d4 += h1 * r3;\n d4 += h2 * r2;\n d4 += h3 * r1;\n d4 += h4 * r0;\n c = (d4 >>> 13); d4 &= 0x1fff;\n d4 += h5 * (5 * r9);\n d4 += h6 * (5 * r8);\n d4 += h7 * (5 * r7);\n d4 += h8 * (5 * r6);\n d4 += h9 * (5 * r5);\n c += (d4 >>> 13); d4 &= 0x1fff;\n\n d5 = c;\n d5 += h0 * r5;\n d5 += h1 * r4;\n d5 += h2 * r3;\n d5 += h3 * r2;\n d5 += h4 * r1;\n c = (d5 >>> 13); d5 &= 0x1fff;\n d5 += h5 * r0;\n d5 += h6 * (5 * r9);\n d5 += h7 * (5 * r8);\n d5 += h8 * (5 * r7);\n d5 += h9 * (5 * r6);\n c += (d5 >>> 13); d5 &= 0x1fff;\n\n d6 = c;\n d6 += h0 * r6;\n d6 += h1 * r5;\n d6 += h2 * r4;\n d6 += h3 * r3;\n d6 += h4 * r2;\n c = (d6 >>> 13); d6 &= 0x1fff;\n d6 += h5 * r1;\n d6 += h6 * r0;\n d6 += h7 * (5 * r9);\n d6 += h8 * (5 * r8);\n d6 += h9 * (5 * r7);\n c += (d6 >>> 13); d6 &= 0x1fff;\n\n d7 = c;\n d7 += h0 * r7;\n d7 += h1 * r6;\n d7 += h2 * r5;\n d7 += h3 * r4;\n d7 += h4 * r3;\n c = (d7 >>> 13); d7 &= 0x1fff;\n d7 += h5 * r2;\n d7 += h6 * r1;\n d7 += h7 * r0;\n d7 += h8 * (5 * r9);\n d7 += h9 * (5 * r8);\n c += (d7 >>> 13); d7 &= 0x1fff;\n\n d8 = c;\n d8 += h0 * r8;\n d8 += h1 * r7;\n d8 += h2 * r6;\n d8 += h3 * r5;\n d8 += h4 * r4;\n c = (d8 >>> 13); d8 &= 0x1fff;\n d8 += h5 * r3;\n d8 += h6 * r2;\n d8 += h7 * r1;\n d8 += h8 * r0;\n d8 += h9 * (5 * r9);\n c += (d8 >>> 13); d8 &= 0x1fff;\n\n d9 = c;\n d9 += h0 * r9;\n d9 += h1 * r8;\n d9 += h2 * r7;\n d9 += h3 * r6;\n d9 += h4 * r5;\n c = (d9 >>> 13); d9 &= 0x1fff;\n d9 += h5 * r4;\n d9 += h6 * r3;\n d9 += h7 * r2;\n d9 += h8 * r1;\n d9 += h9 * r0;\n c += (d9 >>> 13); d9 &= 0x1fff;\n\n c = (((c << 2) + c)) | 0;\n c = (c + d0) | 0;\n d0 = c & 0x1fff;\n c = (c >>> 13);\n d1 += c;\n\n h0 = d0;\n h1 = d1;\n h2 = d2;\n h3 = d3;\n h4 = d4;\n h5 = d5;\n h6 = d6;\n h7 = d7;\n h8 = d8;\n h9 = d9;\n\n mpos += 16;\n bytes -= 16;\n }\n this.h[0] = h0;\n this.h[1] = h1;\n this.h[2] = h2;\n this.h[3] = h3;\n this.h[4] = h4;\n this.h[5] = h5;\n this.h[6] = h6;\n this.h[7] = h7;\n this.h[8] = h8;\n this.h[9] = h9;\n};\n\npoly1305.prototype.finish = function(mac, macpos) {\n var g = new Uint16Array(10);\n var c, mask, f, i;\n\n if (this.leftover) {\n i = this.leftover;\n this.buffer[i++] = 1;\n for (; i < 16; i++) this.buffer[i] = 0;\n this.fin = 1;\n this.blocks(this.buffer, 0, 16);\n }\n\n c = this.h[1] >>> 13;\n this.h[1] &= 0x1fff;\n for (i = 2; i < 10; i++) {\n this.h[i] += c;\n c = this.h[i] >>> 13;\n this.h[i] &= 0x1fff;\n }\n this.h[0] += (c * 5);\n c = this.h[0] >>> 13;\n this.h[0] &= 0x1fff;\n this.h[1] += c;\n c = this.h[1] >>> 13;\n this.h[1] &= 0x1fff;\n this.h[2] += c;\n\n g[0] = this.h[0] + 5;\n c = g[0] >>> 13;\n g[0] &= 0x1fff;\n for (i = 1; i < 10; i++) {\n g[i] = this.h[i] + c;\n c = g[i] >>> 13;\n g[i] &= 0x1fff;\n }\n g[9] -= (1 << 13);\n\n mask = (c ^ 1) - 1;\n for (i = 0; i < 10; i++) g[i] &= mask;\n mask = ~mask;\n for (i = 0; i < 10; i++) this.h[i] = (this.h[i] & mask) | g[i];\n\n this.h[0] = ((this.h[0] ) | (this.h[1] << 13) ) & 0xffff;\n this.h[1] = ((this.h[1] >>> 3) | (this.h[2] << 10) ) & 0xffff;\n this.h[2] = ((this.h[2] >>> 6) | (this.h[3] << 7) ) & 0xffff;\n this.h[3] = ((this.h[3] >>> 9) | (this.h[4] << 4) ) & 0xffff;\n this.h[4] = ((this.h[4] >>> 12) | (this.h[5] << 1) | (this.h[6] << 14)) & 0xffff;\n this.h[5] = ((this.h[6] >>> 2) | (this.h[7] << 11) ) & 0xffff;\n this.h[6] = ((this.h[7] >>> 5) | (this.h[8] << 8) ) & 0xffff;\n this.h[7] = ((this.h[8] >>> 8) | (this.h[9] << 5) ) & 0xffff;\n\n f = this.h[0] + this.pad[0];\n this.h[0] = f & 0xffff;\n for (i = 1; i < 8; i++) {\n f = (((this.h[i] + this.pad[i]) | 0) + (f >>> 16)) | 0;\n this.h[i] = f & 0xffff;\n }\n\n mac[macpos+ 0] = (this.h[0] >>> 0) & 0xff;\n mac[macpos+ 1] = (this.h[0] >>> 8) & 0xff;\n mac[macpos+ 2] = (this.h[1] >>> 0) & 0xff;\n mac[macpos+ 3] = (this.h[1] >>> 8) & 0xff;\n mac[macpos+ 4] = (this.h[2] >>> 0) & 0xff;\n mac[macpos+ 5] = (this.h[2] >>> 8) & 0xff;\n mac[macpos+ 6] = (this.h[3] >>> 0) & 0xff;\n mac[macpos+ 7] = (this.h[3] >>> 8) & 0xff;\n mac[macpos+ 8] = (this.h[4] >>> 0) & 0xff;\n mac[macpos+ 9] = (this.h[4] >>> 8) & 0xff;\n mac[macpos+10] = (this.h[5] >>> 0) & 0xff;\n mac[macpos+11] = (this.h[5] >>> 8) & 0xff;\n mac[macpos+12] = (this.h[6] >>> 0) & 0xff;\n mac[macpos+13] = (this.h[6] >>> 8) & 0xff;\n mac[macpos+14] = (this.h[7] >>> 0) & 0xff;\n mac[macpos+15] = (this.h[7] >>> 8) & 0xff;\n};\n\npoly1305.prototype.update = function(m, mpos, bytes) {\n var i, want;\n\n if (this.leftover) {\n want = (16 - this.leftover);\n if (want > bytes)\n want = bytes;\n for (i = 0; i < want; i++)\n this.buffer[this.leftover + i] = m[mpos+i];\n bytes -= want;\n mpos += want;\n this.leftover += want;\n if (this.leftover < 16)\n return;\n this.blocks(this.buffer, 0, 16);\n this.leftover = 0;\n }\n\n if (bytes >= 16) {\n want = bytes - (bytes % 16);\n this.blocks(m, mpos, want);\n mpos += want;\n bytes -= want;\n }\n\n if (bytes) {\n for (i = 0; i < bytes; i++)\n this.buffer[this.leftover + i] = m[mpos+i];\n this.leftover += bytes;\n }\n};\n\nfunction crypto_onetimeauth(out, outpos, m, mpos, n, k) {\n var s = new poly1305(k);\n s.update(m, mpos, n);\n s.finish(out, outpos);\n return 0;\n}\n\nfunction crypto_onetimeauth_verify(h, hpos, m, mpos, n, k) {\n var x = new Uint8Array(16);\n crypto_onetimeauth(x,0,m,mpos,n,k);\n return crypto_verify_16(h,hpos,x,0);\n}\n\nfunction crypto_secretbox(c,m,d,n,k) {\n var i;\n if (d < 32) return -1;\n crypto_stream_xor(c,0,m,0,d,n,k);\n crypto_onetimeauth(c, 16, c, 32, d - 32, c);\n for (i = 0; i < 16; i++) c[i] = 0;\n return 0;\n}\n\nfunction crypto_secretbox_open(m,c,d,n,k) {\n var i;\n var x = new Uint8Array(32);\n if (d < 32) return -1;\n crypto_stream(x,0,32,n,k);\n if (crypto_onetimeauth_verify(c, 16,c, 32,d - 32,x) !== 0) return -1;\n crypto_stream_xor(m,0,c,0,d,n,k);\n for (i = 0; i < 32; i++) m[i] = 0;\n return 0;\n}\n\nfunction set25519(r, a) {\n var i;\n for (i = 0; i < 16; i++) r[i] = a[i]|0;\n}\n\nfunction car25519(o) {\n var i, v, c = 1;\n for (i = 0; i < 16; i++) {\n v = o[i] + c + 65535;\n c = Math.floor(v / 65536);\n o[i] = v - c * 65536;\n }\n o[0] += c-1 + 37 * (c-1);\n}\n\nfunction sel25519(p, q, b) {\n var t, c = ~(b-1);\n for (var i = 0; i < 16; i++) {\n t = c & (p[i] ^ q[i]);\n p[i] ^= t;\n q[i] ^= t;\n }\n}\n\nfunction pack25519(o, n) {\n var i, j, b;\n var m = gf(), t = gf();\n for (i = 0; i < 16; i++) t[i] = n[i];\n car25519(t);\n car25519(t);\n car25519(t);\n for (j = 0; j < 2; j++) {\n m[0] = t[0] - 0xffed;\n for (i = 1; i < 15; i++) {\n m[i] = t[i] - 0xffff - ((m[i-1]>>16) & 1);\n m[i-1] &= 0xffff;\n }\n m[15] = t[15] - 0x7fff - ((m[14]>>16) & 1);\n b = (m[15]>>16) & 1;\n m[14] &= 0xffff;\n sel25519(t, m, 1-b);\n }\n for (i = 0; i < 16; i++) {\n o[2*i] = t[i] & 0xff;\n o[2*i+1] = t[i]>>8;\n }\n}\n\nfunction neq25519(a, b) {\n var c = new Uint8Array(32), d = new Uint8Array(32);\n pack25519(c, a);\n pack25519(d, b);\n return crypto_verify_32(c, 0, d, 0);\n}\n\nfunction par25519(a) {\n var d = new Uint8Array(32);\n pack25519(d, a);\n return d[0] & 1;\n}\n\nfunction unpack25519(o, n) {\n var i;\n for (i = 0; i < 16; i++) o[i] = n[2*i] + (n[2*i+1] << 8);\n o[15] &= 0x7fff;\n}\n\nfunction A(o, a, b) {\n for (var i = 0; i < 16; i++) o[i] = a[i] + b[i];\n}\n\nfunction Z(o, a, b) {\n for (var i = 0; i < 16; i++) o[i] = a[i] - b[i];\n}\n\nfunction M(o, a, b) {\n var v, c,\n t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0,\n t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0,\n t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0,\n t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0,\n b0 = b[0],\n b1 = b[1],\n b2 = b[2],\n b3 = b[3],\n b4 = b[4],\n b5 = b[5],\n b6 = b[6],\n b7 = b[7],\n b8 = b[8],\n b9 = b[9],\n b10 = b[10],\n b11 = b[11],\n b12 = b[12],\n b13 = b[13],\n b14 = b[14],\n b15 = b[15];\n\n v = a[0];\n t0 += v * b0;\n t1 += v * b1;\n t2 += v * b2;\n t3 += v * b3;\n t4 += v * b4;\n t5 += v * b5;\n t6 += v * b6;\n t7 += v * b7;\n t8 += v * b8;\n t9 += v * b9;\n t10 += v * b10;\n t11 += v * b11;\n t12 += v * b12;\n t13 += v * b13;\n t14 += v * b14;\n t15 += v * b15;\n v = a[1];\n t1 += v * b0;\n t2 += v * b1;\n t3 += v * b2;\n t4 += v * b3;\n t5 += v * b4;\n t6 += v * b5;\n t7 += v * b6;\n t8 += v * b7;\n t9 += v * b8;\n t10 += v * b9;\n t11 += v * b10;\n t12 += v * b11;\n t13 += v * b12;\n t14 += v * b13;\n t15 += v * b14;\n t16 += v * b15;\n v = a[2];\n t2 += v * b0;\n t3 += v * b1;\n t4 += v * b2;\n t5 += v * b3;\n t6 += v * b4;\n t7 += v * b5;\n t8 += v * b6;\n t9 += v * b7;\n t10 += v * b8;\n t11 += v * b9;\n t12 += v * b10;\n t13 += v * b11;\n t14 += v * b12;\n t15 += v * b13;\n t16 += v * b14;\n t17 += v * b15;\n v = a[3];\n t3 += v * b0;\n t4 += v * b1;\n t5 += v * b2;\n t6 += v * b3;\n t7 += v * b4;\n t8 += v * b5;\n t9 += v * b6;\n t10 += v * b7;\n t11 += v * b8;\n t12 += v * b9;\n t13 += v * b10;\n t14 += v * b11;\n t15 += v * b12;\n t16 += v * b13;\n t17 += v * b14;\n t18 += v * b15;\n v = a[4];\n t4 += v * b0;\n t5 += v * b1;\n t6 += v * b2;\n t7 += v * b3;\n t8 += v * b4;\n t9 += v * b5;\n t10 += v * b6;\n t11 += v * b7;\n t12 += v * b8;\n t13 += v * b9;\n t14 += v * b10;\n t15 += v * b11;\n t16 += v * b12;\n t17 += v * b13;\n t18 += v * b14;\n t19 += v * b15;\n v = a[5];\n t5 += v * b0;\n t6 += v * b1;\n t7 += v * b2;\n t8 += v * b3;\n t9 += v * b4;\n t10 += v * b5;\n t11 += v * b6;\n t12 += v * b7;\n t13 += v * b8;\n t14 += v * b9;\n t15 += v * b10;\n t16 += v * b11;\n t17 += v * b12;\n t18 += v * b13;\n t19 += v * b14;\n t20 += v * b15;\n v = a[6];\n t6 += v * b0;\n t7 += v * b1;\n t8 += v * b2;\n t9 += v * b3;\n t10 += v * b4;\n t11 += v * b5;\n t12 += v * b6;\n t13 += v * b7;\n t14 += v * b8;\n t15 += v * b9;\n t16 += v * b10;\n t17 += v * b11;\n t18 += v * b12;\n t19 += v * b13;\n t20 += v * b14;\n t21 += v * b15;\n v = a[7];\n t7 += v * b0;\n t8 += v * b1;\n t9 += v * b2;\n t10 += v * b3;\n t11 += v * b4;\n t12 += v * b5;\n t13 += v * b6;\n t14 += v * b7;\n t15 += v * b8;\n t16 += v * b9;\n t17 += v * b10;\n t18 += v * b11;\n t19 += v * b12;\n t20 += v * b13;\n t21 += v * b14;\n t22 += v * b15;\n v = a[8];\n t8 += v * b0;\n t9 += v * b1;\n t10 += v * b2;\n t11 += v * b3;\n t12 += v * b4;\n t13 += v * b5;\n t14 += v * b6;\n t15 += v * b7;\n t16 += v * b8;\n t17 += v * b9;\n t18 += v * b10;\n t19 += v * b11;\n t20 += v * b12;\n t21 += v * b13;\n t22 += v * b14;\n t23 += v * b15;\n v = a[9];\n t9 += v * b0;\n t10 += v * b1;\n t11 += v * b2;\n t12 += v * b3;\n t13 += v * b4;\n t14 += v * b5;\n t15 += v * b6;\n t16 += v * b7;\n t17 += v * b8;\n t18 += v * b9;\n t19 += v * b10;\n t20 += v * b11;\n t21 += v * b12;\n t22 += v * b13;\n t23 += v * b14;\n t24 += v * b15;\n v = a[10];\n t10 += v * b0;\n t11 += v * b1;\n t12 += v * b2;\n t13 += v * b3;\n t14 += v * b4;\n t15 += v * b5;\n t16 += v * b6;\n t17 += v * b7;\n t18 += v * b8;\n t19 += v * b9;\n t20 += v * b10;\n t21 += v * b11;\n t22 += v * b12;\n t23 += v * b13;\n t24 += v * b14;\n t25 += v * b15;\n v = a[11];\n t11 += v * b0;\n t12 += v * b1;\n t13 += v * b2;\n t14 += v * b3;\n t15 += v * b4;\n t16 += v * b5;\n t17 += v * b6;\n t18 += v * b7;\n t19 += v * b8;\n t20 += v * b9;\n t21 += v * b10;\n t22 += v * b11;\n t23 += v * b12;\n t24 += v * b13;\n t25 += v * b14;\n t26 += v * b15;\n v = a[12];\n t12 += v * b0;\n t13 += v * b1;\n t14 += v * b2;\n t15 += v * b3;\n t16 += v * b4;\n t17 += v * b5;\n t18 += v * b6;\n t19 += v * b7;\n t20 += v * b8;\n t21 += v * b9;\n t22 += v * b10;\n t23 += v * b11;\n t24 += v * b12;\n t25 += v * b13;\n t26 += v * b14;\n t27 += v * b15;\n v = a[13];\n t13 += v * b0;\n t14 += v * b1;\n t15 += v * b2;\n t16 += v * b3;\n t17 += v * b4;\n t18 += v * b5;\n t19 += v * b6;\n t20 += v * b7;\n t21 += v * b8;\n t22 += v * b9;\n t23 += v * b10;\n t24 += v * b11;\n t25 += v * b12;\n t26 += v * b13;\n t27 += v * b14;\n t28 += v * b15;\n v = a[14];\n t14 += v * b0;\n t15 += v * b1;\n t16 += v * b2;\n t17 += v * b3;\n t18 += v * b4;\n t19 += v * b5;\n t20 += v * b6;\n t21 += v * b7;\n t22 += v * b8;\n t23 += v * b9;\n t24 += v * b10;\n t25 += v * b11;\n t26 += v * b12;\n t27 += v * b13;\n t28 += v * b14;\n t29 += v * b15;\n v = a[15];\n t15 += v * b0;\n t16 += v * b1;\n t17 += v * b2;\n t18 += v * b3;\n t19 += v * b4;\n t20 += v * b5;\n t21 += v * b6;\n t22 += v * b7;\n t23 += v * b8;\n t24 += v * b9;\n t25 += v * b10;\n t26 += v * b11;\n t27 += v * b12;\n t28 += v * b13;\n t29 += v * b14;\n t30 += v * b15;\n\n t0 += 38 * t16;\n t1 += 38 * t17;\n t2 += 38 * t18;\n t3 += 38 * t19;\n t4 += 38 * t20;\n t5 += 38 * t21;\n t6 += 38 * t22;\n t7 += 38 * t23;\n t8 += 38 * t24;\n t9 += 38 * t25;\n t10 += 38 * t26;\n t11 += 38 * t27;\n t12 += 38 * t28;\n t13 += 38 * t29;\n t14 += 38 * t30;\n // t15 left as is\n\n // first car\n c = 1;\n v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536;\n v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536;\n v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536;\n v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536;\n v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536;\n v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536;\n v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536;\n v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536;\n v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536;\n v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536;\n v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536;\n v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536;\n v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536;\n v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536;\n v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536;\n v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536;\n t0 += c-1 + 37 * (c-1);\n\n // second car\n c = 1;\n v = t0 + c + 65535; c = Math.floor(v / 65536); t0 = v - c * 65536;\n v = t1 + c + 65535; c = Math.floor(v / 65536); t1 = v - c * 65536;\n v = t2 + c + 65535; c = Math.floor(v / 65536); t2 = v - c * 65536;\n v = t3 + c + 65535; c = Math.floor(v / 65536); t3 = v - c * 65536;\n v = t4 + c + 65535; c = Math.floor(v / 65536); t4 = v - c * 65536;\n v = t5 + c + 65535; c = Math.floor(v / 65536); t5 = v - c * 65536;\n v = t6 + c + 65535; c = Math.floor(v / 65536); t6 = v - c * 65536;\n v = t7 + c + 65535; c = Math.floor(v / 65536); t7 = v - c * 65536;\n v = t8 + c + 65535; c = Math.floor(v / 65536); t8 = v - c * 65536;\n v = t9 + c + 65535; c = Math.floor(v / 65536); t9 = v - c * 65536;\n v = t10 + c + 65535; c = Math.floor(v / 65536); t10 = v - c * 65536;\n v = t11 + c + 65535; c = Math.floor(v / 65536); t11 = v - c * 65536;\n v = t12 + c + 65535; c = Math.floor(v / 65536); t12 = v - c * 65536;\n v = t13 + c + 65535; c = Math.floor(v / 65536); t13 = v - c * 65536;\n v = t14 + c + 65535; c = Math.floor(v / 65536); t14 = v - c * 65536;\n v = t15 + c + 65535; c = Math.floor(v / 65536); t15 = v - c * 65536;\n t0 += c-1 + 37 * (c-1);\n\n o[ 0] = t0;\n o[ 1] = t1;\n o[ 2] = t2;\n o[ 3] = t3;\n o[ 4] = t4;\n o[ 5] = t5;\n o[ 6] = t6;\n o[ 7] = t7;\n o[ 8] = t8;\n o[ 9] = t9;\n o[10] = t10;\n o[11] = t11;\n o[12] = t12;\n o[13] = t13;\n o[14] = t14;\n o[15] = t15;\n}\n\nfunction S(o, a) {\n M(o, a, a);\n}\n\nfunction inv25519(o, i) {\n var c = gf();\n var a;\n for (a = 0; a < 16; a++) c[a] = i[a];\n for (a = 253; a >= 0; a--) {\n S(c, c);\n if(a !== 2 && a !== 4) M(c, c, i);\n }\n for (a = 0; a < 16; a++) o[a] = c[a];\n}\n\nfunction pow2523(o, i) {\n var c = gf();\n var a;\n for (a = 0; a < 16; a++) c[a] = i[a];\n for (a = 250; a >= 0; a--) {\n S(c, c);\n if(a !== 1) M(c, c, i);\n }\n for (a = 0; a < 16; a++) o[a] = c[a];\n}\n\nfunction crypto_scalarmult(q, n, p) {\n var z = new Uint8Array(32);\n var x = new Float64Array(80), r, i;\n var a = gf(), b = gf(), c = gf(),\n d = gf(), e = gf(), f = gf();\n for (i = 0; i < 31; i++) z[i] = n[i];\n z[31]=(n[31]&127)|64;\n z[0]&=248;\n unpack25519(x,p);\n for (i = 0; i < 16; i++) {\n b[i]=x[i];\n d[i]=a[i]=c[i]=0;\n }\n a[0]=d[0]=1;\n for (i=254; i>=0; --i) {\n r=(z[i>>>3]>>>(i&7))&1;\n sel25519(a,b,r);\n sel25519(c,d,r);\n A(e,a,c);\n Z(a,a,c);\n A(c,b,d);\n Z(b,b,d);\n S(d,e);\n S(f,a);\n M(a,c,a);\n M(c,b,e);\n A(e,a,c);\n Z(a,a,c);\n S(b,a);\n Z(c,d,f);\n M(a,c,_121665);\n A(a,a,d);\n M(c,c,a);\n M(a,d,f);\n M(d,b,x);\n S(b,e);\n sel25519(a,b,r);\n sel25519(c,d,r);\n }\n for (i = 0; i < 16; i++) {\n x[i+16]=a[i];\n x[i+32]=c[i];\n x[i+48]=b[i];\n x[i+64]=d[i];\n }\n var x32 = x.subarray(32);\n var x16 = x.subarray(16);\n inv25519(x32,x32);\n M(x16,x16,x32);\n pack25519(q,x16);\n return 0;\n}\n\nfunction crypto_scalarmult_base(q, n) {\n return crypto_scalarmult(q, n, _9);\n}\n\nfunction crypto_box_keypair(y, x) {\n randombytes(x, 32);\n return crypto_scalarmult_base(y, x);\n}\n\nfunction crypto_box_beforenm(k, y, x) {\n var s = new Uint8Array(32);\n crypto_scalarmult(s, x, y);\n return crypto_core_hsalsa20(k, _0, s, sigma);\n}\n\nvar crypto_box_afternm = crypto_secretbox;\nvar crypto_box_open_afternm = crypto_secretbox_open;\n\nfunction crypto_box(c, m, d, n, y, x) {\n var k = new Uint8Array(32);\n crypto_box_beforenm(k, y, x);\n return crypto_box_afternm(c, m, d, n, k);\n}\n\nfunction crypto_box_open(m, c, d, n, y, x) {\n var k = new Uint8Array(32);\n crypto_box_beforenm(k, y, x);\n return crypto_box_open_afternm(m, c, d, n, k);\n}\n\nvar K = [\n 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,\n 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,\n 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,\n 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,\n 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,\n 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,\n 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,\n 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,\n 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,\n 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,\n 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,\n 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,\n 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,\n 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,\n 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,\n 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,\n 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,\n 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,\n 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,\n 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,\n 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,\n 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,\n 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,\n 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,\n 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,\n 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,\n 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,\n 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,\n 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,\n 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,\n 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,\n 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,\n 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,\n 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,\n 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,\n 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,\n 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,\n 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,\n 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,\n 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817\n];\n\nfunction crypto_hashblocks_hl(hh, hl, m, n) {\n var wh = new Int32Array(16), wl = new Int32Array(16),\n bh0, bh1, bh2, bh3, bh4, bh5, bh6, bh7,\n bl0, bl1, bl2, bl3, bl4, bl5, bl6, bl7,\n th, tl, i, j, h, l, a, b, c, d;\n\n var ah0 = hh[0],\n ah1 = hh[1],\n ah2 = hh[2],\n ah3 = hh[3],\n ah4 = hh[4],\n ah5 = hh[5],\n ah6 = hh[6],\n ah7 = hh[7],\n\n al0 = hl[0],\n al1 = hl[1],\n al2 = hl[2],\n al3 = hl[3],\n al4 = hl[4],\n al5 = hl[5],\n al6 = hl[6],\n al7 = hl[7];\n\n var pos = 0;\n while (n >= 128) {\n for (i = 0; i < 16; i++) {\n j = 8 * i + pos;\n wh[i] = (m[j+0] << 24) | (m[j+1] << 16) | (m[j+2] << 8) | m[j+3];\n wl[i] = (m[j+4] << 24) | (m[j+5] << 16) | (m[j+6] << 8) | m[j+7];\n }\n for (i = 0; i < 80; i++) {\n bh0 = ah0;\n bh1 = ah1;\n bh2 = ah2;\n bh3 = ah3;\n bh4 = ah4;\n bh5 = ah5;\n bh6 = ah6;\n bh7 = ah7;\n\n bl0 = al0;\n bl1 = al1;\n bl2 = al2;\n bl3 = al3;\n bl4 = al4;\n bl5 = al5;\n bl6 = al6;\n bl7 = al7;\n\n // add\n h = ah7;\n l = al7;\n\n a = l & 0xffff; b = l >>> 16;\n c = h & 0xffff; d = h >>> 16;\n\n // Sigma1\n h = ((ah4 >>> 14) | (al4 << (32-14))) ^ ((ah4 >>> 18) | (al4 << (32-18))) ^ ((al4 >>> (41-32)) | (ah4 << (32-(41-32))));\n l = ((al4 >>> 14) | (ah4 << (32-14))) ^ ((al4 >>> 18) | (ah4 << (32-18))) ^ ((ah4 >>> (41-32)) | (al4 << (32-(41-32))));\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n // Ch\n h = (ah4 & ah5) ^ (~ah4 & ah6);\n l = (al4 & al5) ^ (~al4 & al6);\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n // K\n h = K[i*2];\n l = K[i*2+1];\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n // w\n h = wh[i%16];\n l = wl[i%16];\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n b += a >>> 16;\n c += b >>> 16;\n d += c >>> 16;\n\n th = c & 0xffff | d << 16;\n tl = a & 0xffff | b << 16;\n\n // add\n h = th;\n l = tl;\n\n a = l & 0xffff; b = l >>> 16;\n c = h & 0xffff; d = h >>> 16;\n\n // Sigma0\n h = ((ah0 >>> 28) | (al0 << (32-28))) ^ ((al0 >>> (34-32)) | (ah0 << (32-(34-32)))) ^ ((al0 >>> (39-32)) | (ah0 << (32-(39-32))));\n l = ((al0 >>> 28) | (ah0 << (32-28))) ^ ((ah0 >>> (34-32)) | (al0 << (32-(34-32)))) ^ ((ah0 >>> (39-32)) | (al0 << (32-(39-32))));\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n // Maj\n h = (ah0 & ah1) ^ (ah0 & ah2) ^ (ah1 & ah2);\n l = (al0 & al1) ^ (al0 & al2) ^ (al1 & al2);\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n b += a >>> 16;\n c += b >>> 16;\n d += c >>> 16;\n\n bh7 = (c & 0xffff) | (d << 16);\n bl7 = (a & 0xffff) | (b << 16);\n\n // add\n h = bh3;\n l = bl3;\n\n a = l & 0xffff; b = l >>> 16;\n c = h & 0xffff; d = h >>> 16;\n\n h = th;\n l = tl;\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n b += a >>> 16;\n c += b >>> 16;\n d += c >>> 16;\n\n bh3 = (c & 0xffff) | (d << 16);\n bl3 = (a & 0xffff) | (b << 16);\n\n ah1 = bh0;\n ah2 = bh1;\n ah3 = bh2;\n ah4 = bh3;\n ah5 = bh4;\n ah6 = bh5;\n ah7 = bh6;\n ah0 = bh7;\n\n al1 = bl0;\n al2 = bl1;\n al3 = bl2;\n al4 = bl3;\n al5 = bl4;\n al6 = bl5;\n al7 = bl6;\n al0 = bl7;\n\n if (i%16 === 15) {\n for (j = 0; j < 16; j++) {\n // add\n h = wh[j];\n l = wl[j];\n\n a = l & 0xffff; b = l >>> 16;\n c = h & 0xffff; d = h >>> 16;\n\n h = wh[(j+9)%16];\n l = wl[(j+9)%16];\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n // sigma0\n th = wh[(j+1)%16];\n tl = wl[(j+1)%16];\n h = ((th >>> 1) | (tl << (32-1))) ^ ((th >>> 8) | (tl << (32-8))) ^ (th >>> 7);\n l = ((tl >>> 1) | (th << (32-1))) ^ ((tl >>> 8) | (th << (32-8))) ^ ((tl >>> 7) | (th << (32-7)));\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n // sigma1\n th = wh[(j+14)%16];\n tl = wl[(j+14)%16];\n h = ((th >>> 19) | (tl << (32-19))) ^ ((tl >>> (61-32)) | (th << (32-(61-32)))) ^ (th >>> 6);\n l = ((tl >>> 19) | (th << (32-19))) ^ ((th >>> (61-32)) | (tl << (32-(61-32)))) ^ ((tl >>> 6) | (th << (32-6)));\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n b += a >>> 16;\n c += b >>> 16;\n d += c >>> 16;\n\n wh[j] = (c & 0xffff) | (d << 16);\n wl[j] = (a & 0xffff) | (b << 16);\n }\n }\n }\n\n // add\n h = ah0;\n l = al0;\n\n a = l & 0xffff; b = l >>> 16;\n c = h & 0xffff; d = h >>> 16;\n\n h = hh[0];\n l = hl[0];\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n b += a >>> 16;\n c += b >>> 16;\n d += c >>> 16;\n\n hh[0] = ah0 = (c & 0xffff) | (d << 16);\n hl[0] = al0 = (a & 0xffff) | (b << 16);\n\n h = ah1;\n l = al1;\n\n a = l & 0xffff; b = l >>> 16;\n c = h & 0xffff; d = h >>> 16;\n\n h = hh[1];\n l = hl[1];\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n b += a >>> 16;\n c += b >>> 16;\n d += c >>> 16;\n\n hh[1] = ah1 = (c & 0xffff) | (d << 16);\n hl[1] = al1 = (a & 0xffff) | (b << 16);\n\n h = ah2;\n l = al2;\n\n a = l & 0xffff; b = l >>> 16;\n c = h & 0xffff; d = h >>> 16;\n\n h = hh[2];\n l = hl[2];\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n b += a >>> 16;\n c += b >>> 16;\n d += c >>> 16;\n\n hh[2] = ah2 = (c & 0xffff) | (d << 16);\n hl[2] = al2 = (a & 0xffff) | (b << 16);\n\n h = ah3;\n l = al3;\n\n a = l & 0xffff; b = l >>> 16;\n c = h & 0xffff; d = h >>> 16;\n\n h = hh[3];\n l = hl[3];\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n b += a >>> 16;\n c += b >>> 16;\n d += c >>> 16;\n\n hh[3] = ah3 = (c & 0xffff) | (d << 16);\n hl[3] = al3 = (a & 0xffff) | (b << 16);\n\n h = ah4;\n l = al4;\n\n a = l & 0xffff; b = l >>> 16;\n c = h & 0xffff; d = h >>> 16;\n\n h = hh[4];\n l = hl[4];\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n b += a >>> 16;\n c += b >>> 16;\n d += c >>> 16;\n\n hh[4] = ah4 = (c & 0xffff) | (d << 16);\n hl[4] = al4 = (a & 0xffff) | (b << 16);\n\n h = ah5;\n l = al5;\n\n a = l & 0xffff; b = l >>> 16;\n c = h & 0xffff; d = h >>> 16;\n\n h = hh[5];\n l = hl[5];\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n b += a >>> 16;\n c += b >>> 16;\n d += c >>> 16;\n\n hh[5] = ah5 = (c & 0xffff) | (d << 16);\n hl[5] = al5 = (a & 0xffff) | (b << 16);\n\n h = ah6;\n l = al6;\n\n a = l & 0xffff; b = l >>> 16;\n c = h & 0xffff; d = h >>> 16;\n\n h = hh[6];\n l = hl[6];\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n b += a >>> 16;\n c += b >>> 16;\n d += c >>> 16;\n\n hh[6] = ah6 = (c & 0xffff) | (d << 16);\n hl[6] = al6 = (a & 0xffff) | (b << 16);\n\n h = ah7;\n l = al7;\n\n a = l & 0xffff; b = l >>> 16;\n c = h & 0xffff; d = h >>> 16;\n\n h = hh[7];\n l = hl[7];\n\n a += l & 0xffff; b += l >>> 16;\n c += h & 0xffff; d += h >>> 16;\n\n b += a >>> 16;\n c += b >>> 16;\n d += c >>> 16;\n\n hh[7] = ah7 = (c & 0xffff) | (d << 16);\n hl[7] = al7 = (a & 0xffff) | (b << 16);\n\n pos += 128;\n n -= 128;\n }\n\n return n;\n}\n\nfunction crypto_hash(out, m, n) {\n var hh = new Int32Array(8),\n hl = new Int32Array(8),\n x = new Uint8Array(256),\n i, b = n;\n\n hh[0] = 0x6a09e667;\n hh[1] = 0xbb67ae85;\n hh[2] = 0x3c6ef372;\n hh[3] = 0xa54ff53a;\n hh[4] = 0x510e527f;\n hh[5] = 0x9b05688c;\n hh[6] = 0x1f83d9ab;\n hh[7] = 0x5be0cd19;\n\n hl[0] = 0xf3bcc908;\n hl[1] = 0x84caa73b;\n hl[2] = 0xfe94f82b;\n hl[3] = 0x5f1d36f1;\n hl[4] = 0xade682d1;\n hl[5] = 0x2b3e6c1f;\n hl[6] = 0xfb41bd6b;\n hl[7] = 0x137e2179;\n\n crypto_hashblocks_hl(hh, hl, m, n);\n n %= 128;\n\n for (i = 0; i < n; i++) x[i] = m[b-n+i];\n x[n] = 128;\n\n n = 256-128*(n<112?1:0);\n x[n-9] = 0;\n ts64(x, n-8, (b / 0x20000000) | 0, b << 3);\n crypto_hashblocks_hl(hh, hl, x, n);\n\n for (i = 0; i < 8; i++) ts64(out, 8*i, hh[i], hl[i]);\n\n return 0;\n}\n\nfunction add(p, q) {\n var a = gf(), b = gf(), c = gf(),\n d = gf(), e = gf(), f = gf(),\n g = gf(), h = gf(), t = gf();\n\n Z(a, p[1], p[0]);\n Z(t, q[1], q[0]);\n M(a, a, t);\n A(b, p[0], p[1]);\n A(t, q[0], q[1]);\n M(b, b, t);\n M(c, p[3], q[3]);\n M(c, c, D2);\n M(d, p[2], q[2]);\n A(d, d, d);\n Z(e, b, a);\n Z(f, d, c);\n A(g, d, c);\n A(h, b, a);\n\n M(p[0], e, f);\n M(p[1], h, g);\n M(p[2], g, f);\n M(p[3], e, h);\n}\n\nfunction cswap(p, q, b) {\n var i;\n for (i = 0; i < 4; i++) {\n sel25519(p[i], q[i], b);\n }\n}\n\nfunction pack(r, p) {\n var tx = gf(), ty = gf(), zi = gf();\n inv25519(zi, p[2]);\n M(tx, p[0], zi);\n M(ty, p[1], zi);\n pack25519(r, ty);\n r[31] ^= par25519(tx) << 7;\n}\n\nfunction scalarmult(p, q, s) {\n var b, i;\n set25519(p[0], gf0);\n set25519(p[1], gf1);\n set25519(p[2], gf1);\n set25519(p[3], gf0);\n for (i = 255; i >= 0; --i) {\n b = (s[(i/8)|0] >> (i&7)) & 1;\n cswap(p, q, b);\n add(q, p);\n add(p, p);\n cswap(p, q, b);\n }\n}\n\nfunction scalarbase(p, s) {\n var q = [gf(), gf(), gf(), gf()];\n set25519(q[0], X);\n set25519(q[1], Y);\n set25519(q[2], gf1);\n M(q[3], X, Y);\n scalarmult(p, q, s);\n}\n\nfunction crypto_sign_keypair(pk, sk, seeded) {\n var d = new Uint8Array(64);\n var p = [gf(), gf(), gf(), gf()];\n var i;\n\n if (!seeded) randombytes(sk, 32);\n crypto_hash(d, sk, 32);\n d[0] &= 248;\n d[31] &= 127;\n d[31] |= 64;\n\n scalarbase(p, d);\n pack(pk, p);\n\n for (i = 0; i < 32; i++) sk[i+32] = pk[i];\n return 0;\n}\n\nvar L = new Float64Array([0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10]);\n\nfunction modL(r, x) {\n var carry, i, j, k;\n for (i = 63; i >= 32; --i) {\n carry = 0;\n for (j = i - 32, k = i - 12; j < k; ++j) {\n x[j] += carry - 16 * x[i] * L[j - (i - 32)];\n carry = (x[j] + 128) >> 8;\n x[j] -= carry * 256;\n }\n x[j] += carry;\n x[i] = 0;\n }\n carry = 0;\n for (j = 0; j < 32; j++) {\n x[j] += carry - (x[31] >> 4) * L[j];\n carry = x[j] >> 8;\n x[j] &= 255;\n }\n for (j = 0; j < 32; j++) x[j] -= carry * L[j];\n for (i = 0; i < 32; i++) {\n x[i+1] += x[i] >> 8;\n r[i] = x[i] & 255;\n }\n}\n\nfunction reduce(r) {\n var x = new Float64Array(64), i;\n for (i = 0; i < 64; i++) x[i] = r[i];\n for (i = 0; i < 64; i++) r[i] = 0;\n modL(r, x);\n}\n\n// Note: difference from C - smlen returned, not passed as argument.\nfunction crypto_sign(sm, m, n, sk) {\n var d = new Uint8Array(64), h = new Uint8Array(64), r = new Uint8Array(64);\n var i, j, x = new Float64Array(64);\n var p = [gf(), gf(), gf(), gf()];\n\n crypto_hash(d, sk, 32);\n d[0] &= 248;\n d[31] &= 127;\n d[31] |= 64;\n\n var smlen = n + 64;\n for (i = 0; i < n; i++) sm[64 + i] = m[i];\n for (i = 0; i < 32; i++) sm[32 + i] = d[32 + i];\n\n crypto_hash(r, sm.subarray(32), n+32);\n reduce(r);\n scalarbase(p, r);\n pack(sm, p);\n\n for (i = 32; i < 64; i++) sm[i] = sk[i];\n crypto_hash(h, sm, n + 64);\n reduce(h);\n\n for (i = 0; i < 64; i++) x[i] = 0;\n for (i = 0; i < 32; i++) x[i] = r[i];\n for (i = 0; i < 32; i++) {\n for (j = 0; j < 32; j++) {\n x[i+j] += h[i] * d[j];\n }\n }\n\n modL(sm.subarray(32), x);\n return smlen;\n}\n\nfunction unpackneg(r, p) {\n var t = gf(), chk = gf(), num = gf(),\n den = gf(), den2 = gf(), den4 = gf(),\n den6 = gf();\n\n set25519(r[2], gf1);\n unpack25519(r[1], p);\n S(num, r[1]);\n M(den, num, D);\n Z(num, num, r[2]);\n A(den, r[2], den);\n\n S(den2, den);\n S(den4, den2);\n M(den6, den4, den2);\n M(t, den6, num);\n M(t, t, den);\n\n pow2523(t, t);\n M(t, t, num);\n M(t, t, den);\n M(t, t, den);\n M(r[0], t, den);\n\n S(chk, r[0]);\n M(chk, chk, den);\n if (neq25519(chk, num)) M(r[0], r[0], I);\n\n S(chk, r[0]);\n M(chk, chk, den);\n if (neq25519(chk, num)) return -1;\n\n if (par25519(r[0]) === (p[31]>>7)) Z(r[0], gf0, r[0]);\n\n M(r[3], r[0], r[1]);\n return 0;\n}\n\nfunction crypto_sign_open(m, sm, n, pk) {\n var i, mlen;\n var t = new Uint8Array(32), h = new Uint8Array(64);\n var p = [gf(), gf(), gf(), gf()],\n q = [gf(), gf(), gf(), gf()];\n\n mlen = -1;\n if (n < 64) return -1;\n\n if (unpackneg(q, pk)) return -1;\n\n for (i = 0; i < n; i++) m[i] = sm[i];\n for (i = 0; i < 32; i++) m[i+32] = pk[i];\n crypto_hash(h, m, n);\n reduce(h);\n scalarmult(p, q, h);\n\n scalarbase(q, sm.subarray(32));\n add(p, q);\n pack(t, p);\n\n n -= 64;\n if (crypto_verify_32(sm, 0, t, 0)) {\n for (i = 0; i < n; i++) m[i] = 0;\n return -1;\n }\n\n for (i = 0; i < n; i++) m[i] = sm[i + 64];\n mlen = n;\n return mlen;\n}\n\nvar crypto_secretbox_KEYBYTES = 32,\n crypto_secretbox_NONCEBYTES = 24,\n crypto_secretbox_ZEROBYTES = 32,\n crypto_secretbox_BOXZEROBYTES = 16,\n crypto_scalarmult_BYTES = 32,\n crypto_scalarmult_SCALARBYTES = 32,\n crypto_box_PUBLICKEYBYTES = 32,\n crypto_box_SECRETKEYBYTES = 32,\n crypto_box_BEFORENMBYTES = 32,\n crypto_box_NONCEBYTES = crypto_secretbox_NONCEBYTES,\n crypto_box_ZEROBYTES = crypto_secretbox_ZEROBYTES,\n crypto_box_BOXZEROBYTES = crypto_secretbox_BOXZEROBYTES,\n crypto_sign_BYTES = 64,\n crypto_sign_PUBLICKEYBYTES = 32,\n crypto_sign_SECRETKEYBYTES = 64,\n crypto_sign_SEEDBYTES = 32,\n crypto_hash_BYTES = 64;\n\nnacl.lowlevel = {\n crypto_core_hsalsa20: crypto_core_hsalsa20,\n crypto_stream_xor: crypto_stream_xor,\n crypto_stream: crypto_stream,\n crypto_stream_salsa20_xor: crypto_stream_salsa20_xor,\n crypto_stream_salsa20: crypto_stream_salsa20,\n crypto_onetimeauth: crypto_onetimeauth,\n crypto_onetimeauth_verify: crypto_onetimeauth_verify,\n crypto_verify_16: crypto_verify_16,\n crypto_verify_32: crypto_verify_32,\n crypto_secretbox: crypto_secretbox,\n crypto_secretbox_open: crypto_secretbox_open,\n crypto_scalarmult: crypto_scalarmult,\n crypto_scalarmult_base: crypto_scalarmult_base,\n crypto_box_beforenm: crypto_box_beforenm,\n crypto_box_afternm: crypto_box_afternm,\n crypto_box: crypto_box,\n crypto_box_open: crypto_box_open,\n crypto_box_keypair: crypto_box_keypair,\n crypto_hash: crypto_hash,\n crypto_sign: crypto_sign,\n crypto_sign_keypair: crypto_sign_keypair,\n crypto_sign_open: crypto_sign_open,\n\n crypto_secretbox_KEYBYTES: crypto_secretbox_KEYBYTES,\n crypto_secretbox_NONCEBYTES: crypto_secretbox_NONCEBYTES,\n crypto_secretbox_ZEROBYTES: crypto_secretbox_ZEROBYTES,\n crypto_secretbox_BOXZEROBYTES: crypto_secretbox_BOXZEROBYTES,\n crypto_scalarmult_BYTES: crypto_scalarmult_BYTES,\n crypto_scalarmult_SCALARBYTES: crypto_scalarmult_SCALARBYTES,\n crypto_box_PUBLICKEYBYTES: crypto_box_PUBLICKEYBYTES,\n crypto_box_SECRETKEYBYTES: crypto_box_SECRETKEYBYTES,\n crypto_box_BEFORENMBYTES: crypto_box_BEFORENMBYTES,\n crypto_box_NONCEBYTES: crypto_box_NONCEBYTES,\n crypto_box_ZEROBYTES: crypto_box_ZEROBYTES,\n crypto_box_BOXZEROBYTES: crypto_box_BOXZEROBYTES,\n crypto_sign_BYTES: crypto_sign_BYTES,\n crypto_sign_PUBLICKEYBYTES: crypto_sign_PUBLICKEYBYTES,\n crypto_sign_SECRETKEYBYTES: crypto_sign_SECRETKEYBYTES,\n crypto_sign_SEEDBYTES: crypto_sign_SEEDBYTES,\n crypto_hash_BYTES: crypto_hash_BYTES\n};\n\n/* High-level API */\n\nfunction checkLengths(k, n) {\n if (k.length !== crypto_secretbox_KEYBYTES) throw new Error('bad key size');\n if (n.length !== crypto_secretbox_NONCEBYTES) throw new Error('bad nonce size');\n}\n\nfunction checkBoxLengths(pk, sk) {\n if (pk.length !== crypto_box_PUBLICKEYBYTES) throw new Error('bad public key size');\n if (sk.length !== crypto_box_SECRETKEYBYTES) throw new Error('bad secret key size');\n}\n\nfunction checkArrayTypes() {\n var t, i;\n for (i = 0; i < arguments.length; i++) {\n if ((t = Object.prototype.toString.call(arguments[i])) !== '[object Uint8Array]')\n throw new TypeError('unexpected type ' + t + ', use Uint8Array');\n }\n}\n\nfunction cleanup(arr) {\n for (var i = 0; i < arr.length; i++) arr[i] = 0;\n}\n\n// TODO: Completely remove this in v0.15.\nif (!nacl.util) {\n nacl.util = {};\n nacl.util.decodeUTF8 = nacl.util.encodeUTF8 = nacl.util.encodeBase64 = nacl.util.decodeBase64 = function() {\n throw new Error('nacl.util moved into separate package: https://github.com/dchest/tweetnacl-util-js');\n };\n}\n\nnacl.randomBytes = function(n) {\n var b = new Uint8Array(n);\n randombytes(b, n);\n return b;\n};\n\nnacl.secretbox = function(msg, nonce, key) {\n checkArrayTypes(msg, nonce, key);\n checkLengths(key, nonce);\n var m = new Uint8Array(crypto_secretbox_ZEROBYTES + msg.length);\n var c = new Uint8Array(m.length);\n for (var i = 0; i < msg.length; i++) m[i+crypto_secretbox_ZEROBYTES] = msg[i];\n crypto_secretbox(c, m, m.length, nonce, key);\n return c.subarray(crypto_secretbox_BOXZEROBYTES);\n};\n\nnacl.secretbox.open = function(box, nonce, key) {\n checkArrayTypes(box, nonce, key);\n checkLengths(key, nonce);\n var c = new Uint8Array(crypto_secretbox_BOXZEROBYTES + box.length);\n var m = new Uint8Array(c.length);\n for (var i = 0; i < box.length; i++) c[i+crypto_secretbox_BOXZEROBYTES] = box[i];\n if (c.length < 32) return false;\n if (crypto_secretbox_open(m, c, c.length, nonce, key) !== 0) return false;\n return m.subarray(crypto_secretbox_ZEROBYTES);\n};\n\nnacl.secretbox.keyLength = crypto_secretbox_KEYBYTES;\nnacl.secretbox.nonceLength = crypto_secretbox_NONCEBYTES;\nnacl.secretbox.overheadLength = crypto_secretbox_BOXZEROBYTES;\n\nnacl.scalarMult = function(n, p) {\n checkArrayTypes(n, p);\n if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size');\n if (p.length !== crypto_scalarmult_BYTES) throw new Error('bad p size');\n var q = new Uint8Array(crypto_scalarmult_BYTES);\n crypto_scalarmult(q, n, p);\n return q;\n};\n\nnacl.scalarMult.base = function(n) {\n checkArrayTypes(n);\n if (n.length !== crypto_scalarmult_SCALARBYTES) throw new Error('bad n size');\n var q = new Uint8Array(crypto_scalarmult_BYTES);\n crypto_scalarmult_base(q, n);\n return q;\n};\n\nnacl.scalarMult.scalarLength = crypto_scalarmult_SCALARBYTES;\nnacl.scalarMult.groupElementLength = crypto_scalarmult_BYTES;\n\nnacl.box = function(msg, nonce, publicKey, secretKey) {\n var k = nacl.box.before(publicKey, secretKey);\n return nacl.secretbox(msg, nonce, k);\n};\n\nnacl.box.before = function(publicKey, secretKey) {\n checkArrayTypes(publicKey, secretKey);\n checkBoxLengths(publicKey, secretKey);\n var k = new Uint8Array(crypto_box_BEFORENMBYTES);\n crypto_box_beforenm(k, publicKey, secretKey);\n return k;\n};\n\nnacl.box.after = nacl.secretbox;\n\nnacl.box.open = function(msg, nonce, publicKey, secretKey) {\n var k = nacl.box.before(publicKey, secretKey);\n return nacl.secretbox.open(msg, nonce, k);\n};\n\nnacl.box.open.after = nacl.secretbox.open;\n\nnacl.box.keyPair = function() {\n var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES);\n var sk = new Uint8Array(crypto_box_SECRETKEYBYTES);\n crypto_box_keypair(pk, sk);\n return {publicKey: pk, secretKey: sk};\n};\n\nnacl.box.keyPair.fromSecretKey = function(secretKey) {\n checkArrayTypes(secretKey);\n if (secretKey.length !== crypto_box_SECRETKEYBYTES)\n throw new Error('bad secret key size');\n var pk = new Uint8Array(crypto_box_PUBLICKEYBYTES);\n crypto_scalarmult_base(pk, secretKey);\n return {publicKey: pk, secretKey: new Uint8Array(secretKey)};\n};\n\nnacl.box.publicKeyLength = crypto_box_PUBLICKEYBYTES;\nnacl.box.secretKeyLength = crypto_box_SECRETKEYBYTES;\nnacl.box.sharedKeyLength = crypto_box_BEFORENMBYTES;\nnacl.box.nonceLength = crypto_box_NONCEBYTES;\nnacl.box.overheadLength = nacl.secretbox.overheadLength;\n\nnacl.sign = function(msg, secretKey) {\n checkArrayTypes(msg, secretKey);\n if (secretKey.length !== crypto_sign_SECRETKEYBYTES)\n throw new Error('bad secret key size');\n var signedMsg = new Uint8Array(crypto_sign_BYTES+msg.length);\n crypto_sign(signedMsg, msg, msg.length, secretKey);\n return signedMsg;\n};\n\nnacl.sign.open = function(signedMsg, publicKey) {\n if (arguments.length !== 2)\n throw new Error('nacl.sign.open accepts 2 arguments; did you mean to use nacl.sign.detached.verify?');\n checkArrayTypes(signedMsg, publicKey);\n if (publicKey.length !== crypto_sign_PUBLICKEYBYTES)\n throw new Error('bad public key size');\n var tmp = new Uint8Array(signedMsg.length);\n var mlen = crypto_sign_open(tmp, signedMsg, signedMsg.length, publicKey);\n if (mlen < 0) return null;\n var m = new Uint8Array(mlen);\n for (var i = 0; i < m.length; i++) m[i] = tmp[i];\n return m;\n};\n\nnacl.sign.detached = function(msg, secretKey) {\n var signedMsg = nacl.sign(msg, secretKey);\n var sig = new Uint8Array(crypto_sign_BYTES);\n for (var i = 0; i < sig.length; i++) sig[i] = signedMsg[i];\n return sig;\n};\n\nnacl.sign.detached.verify = function(msg, sig, publicKey) {\n checkArrayTypes(msg, sig, publicKey);\n if (sig.length !== crypto_sign_BYTES)\n throw new Error('bad signature size');\n if (publicKey.length !== crypto_sign_PUBLICKEYBYTES)\n throw new Error('bad public key size');\n var sm = new Uint8Array(crypto_sign_BYTES + msg.length);\n var m = new Uint8Array(crypto_sign_BYTES + msg.length);\n var i;\n for (i = 0; i < crypto_sign_BYTES; i++) sm[i] = sig[i];\n for (i = 0; i < msg.length; i++) sm[i+crypto_sign_BYTES] = msg[i];\n return (crypto_sign_open(m, sm, sm.length, publicKey) >= 0);\n};\n\nnacl.sign.keyPair = function() {\n var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES);\n var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES);\n crypto_sign_keypair(pk, sk);\n return {publicKey: pk, secretKey: sk};\n};\n\nnacl.sign.keyPair.fromSecretKey = function(secretKey) {\n checkArrayTypes(secretKey);\n if (secretKey.length !== crypto_sign_SECRETKEYBYTES)\n throw new Error('bad secret key size');\n var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES);\n for (var i = 0; i < pk.length; i++) pk[i] = secretKey[32+i];\n return {publicKey: pk, secretKey: new Uint8Array(secretKey)};\n};\n\nnacl.sign.keyPair.fromSeed = function(seed) {\n checkArrayTypes(seed);\n if (seed.length !== crypto_sign_SEEDBYTES)\n throw new Error('bad seed size');\n var pk = new Uint8Array(crypto_sign_PUBLICKEYBYTES);\n var sk = new Uint8Array(crypto_sign_SECRETKEYBYTES);\n for (var i = 0; i < 32; i++) sk[i] = seed[i];\n crypto_sign_keypair(pk, sk, true);\n return {publicKey: pk, secretKey: sk};\n};\n\nnacl.sign.publicKeyLength = crypto_sign_PUBLICKEYBYTES;\nnacl.sign.secretKeyLength = crypto_sign_SECRETKEYBYTES;\nnacl.sign.seedLength = crypto_sign_SEEDBYTES;\nnacl.sign.signatureLength = crypto_sign_BYTES;\n\nnacl.hash = function(msg) {\n checkArrayTypes(msg);\n var h = new Uint8Array(crypto_hash_BYTES);\n crypto_hash(h, msg, msg.length);\n return h;\n};\n\nnacl.hash.hashLength = crypto_hash_BYTES;\n\nnacl.verify = function(x, y) {\n checkArrayTypes(x, y);\n // Zero length arguments are considered not equal.\n if (x.length === 0 || y.length === 0) return false;\n if (x.length !== y.length) return false;\n return (vn(x, 0, y, 0, x.length) === 0) ? true : false;\n};\n\nnacl.setPRNG = function(fn) {\n randombytes = fn;\n};\n\n(function() {\n // Initialize PRNG if environment provides CSPRNG.\n // If not, methods calling randombytes will throw.\n var crypto = typeof self !== 'undefined' ? (self.crypto || self.msCrypto) : null;\n if (crypto && crypto.getRandomValues) {\n // Browsers.\n var QUOTA = 65536;\n nacl.setPRNG(function(x, n) {\n var i, v = new Uint8Array(n);\n for (i = 0; i < n; i += QUOTA) {\n crypto.getRandomValues(v.subarray(i, i + Math.min(n - i, QUOTA)));\n }\n for (i = 0; i < n; i++) x[i] = v[i];\n cleanup(v);\n });\n } else if (typeof require !== 'undefined') {\n // Node.js.\n crypto = require('crypto');\n if (crypto && crypto.randomBytes) {\n nacl.setPRNG(function(x, n) {\n var i, v = crypto.randomBytes(n);\n for (i = 0; i < n; i++) x[i] = v[i];\n cleanup(v);\n });\n }\n }\n})();\n\n})(typeof module !== 'undefined' && module.exports ? module.exports : (self.nacl = self.nacl || {}));\n","(function(){\n\n // Copyright (c) 2005 Tom Wu\n // All Rights Reserved.\n // See \"LICENSE\" for details.\n\n // Basic JavaScript BN library - subset useful for RSA encryption.\n\n // Bits per digit\n var dbits;\n\n // JavaScript engine analysis\n var canary = 0xdeadbeefcafe;\n var j_lm = ((canary&0xffffff)==0xefcafe);\n\n // (public) Constructor\n function BigInteger(a,b,c) {\n if(a != null)\n if(\"number\" == typeof a) this.fromNumber(a,b,c);\n else if(b == null && \"string\" != typeof a) this.fromString(a,256);\n else this.fromString(a,b);\n }\n\n // return new, unset BigInteger\n function nbi() { return new BigInteger(null); }\n\n // am: Compute w_j += (x*this_i), propagate carries,\n // c is initial carry, returns final carry.\n // c < 3*dvalue, x < 2*dvalue, this_i < dvalue\n // We need to select the fastest one that works in this environment.\n\n // am1: use a single mult and divide to get the high bits,\n // max digit bits should be 26 because\n // max internal value = 2*dvalue^2-2*dvalue (< 2^53)\n function am1(i,x,w,j,c,n) {\n while(--n >= 0) {\n var v = x*this[i++]+w[j]+c;\n c = Math.floor(v/0x4000000);\n w[j++] = v&0x3ffffff;\n }\n return c;\n }\n // am2 avoids a big mult-and-extract completely.\n // Max digit bits should be <= 30 because we do bitwise ops\n // on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)\n function am2(i,x,w,j,c,n) {\n var xl = x&0x7fff, xh = x>>15;\n while(--n >= 0) {\n var l = this[i]&0x7fff;\n var h = this[i++]>>15;\n var m = xh*l+h*xl;\n l = xl*l+((m&0x7fff)<<15)+w[j]+(c&0x3fffffff);\n c = (l>>>30)+(m>>>15)+xh*h+(c>>>30);\n w[j++] = l&0x3fffffff;\n }\n return c;\n }\n // Alternately, set max digit bits to 28 since some\n // browsers slow down when dealing with 32-bit numbers.\n function am3(i,x,w,j,c,n) {\n var xl = x&0x3fff, xh = x>>14;\n while(--n >= 0) {\n var l = this[i]&0x3fff;\n var h = this[i++]>>14;\n var m = xh*l+h*xl;\n l = xl*l+((m&0x3fff)<<14)+w[j]+c;\n c = (l>>28)+(m>>14)+xh*h;\n w[j++] = l&0xfffffff;\n }\n return c;\n }\n var inBrowser = typeof navigator !== \"undefined\";\n if(inBrowser && j_lm && (navigator.appName == \"Microsoft Internet Explorer\")) {\n BigInteger.prototype.am = am2;\n dbits = 30;\n }\n else if(inBrowser && j_lm && (navigator.appName != \"Netscape\")) {\n BigInteger.prototype.am = am1;\n dbits = 26;\n }\n else { // Mozilla/Netscape seems to prefer am3\n BigInteger.prototype.am = am3;\n dbits = 28;\n }\n\n BigInteger.prototype.DB = dbits;\n BigInteger.prototype.DM = ((1<= 0; --i) r[i] = this[i];\n r.t = this.t;\n r.s = this.s;\n }\n\n // (protected) set from integer value x, -DV <= x < DV\n function bnpFromInt(x) {\n this.t = 1;\n this.s = (x<0)?-1:0;\n if(x > 0) this[0] = x;\n else if(x < -1) this[0] = x+this.DV;\n else this.t = 0;\n }\n\n // return bigint initialized to value\n function nbv(i) { var r = nbi(); r.fromInt(i); return r; }\n\n // (protected) set from string and radix\n function bnpFromString(s,b) {\n var k;\n if(b == 16) k = 4;\n else if(b == 8) k = 3;\n else if(b == 256) k = 8; // byte array\n else if(b == 2) k = 1;\n else if(b == 32) k = 5;\n else if(b == 4) k = 2;\n else { this.fromRadix(s,b); return; }\n this.t = 0;\n this.s = 0;\n var i = s.length, mi = false, sh = 0;\n while(--i >= 0) {\n var x = (k==8)?s[i]&0xff:intAt(s,i);\n if(x < 0) {\n if(s.charAt(i) == \"-\") mi = true;\n continue;\n }\n mi = false;\n if(sh == 0)\n this[this.t++] = x;\n else if(sh+k > this.DB) {\n this[this.t-1] |= (x&((1<<(this.DB-sh))-1))<>(this.DB-sh));\n }\n else\n this[this.t-1] |= x<= this.DB) sh -= this.DB;\n }\n if(k == 8 && (s[0]&0x80) != 0) {\n this.s = -1;\n if(sh > 0) this[this.t-1] |= ((1<<(this.DB-sh))-1)< 0 && this[this.t-1] == c) --this.t;\n }\n\n // (public) return string representation in given radix\n function bnToString(b) {\n if(this.s < 0) return \"-\"+this.negate().toString(b);\n var k;\n if(b == 16) k = 4;\n else if(b == 8) k = 3;\n else if(b == 2) k = 1;\n else if(b == 32) k = 5;\n else if(b == 4) k = 2;\n else return this.toRadix(b);\n var km = (1< 0) {\n if(p < this.DB && (d = this[i]>>p) > 0) { m = true; r = int2char(d); }\n while(i >= 0) {\n if(p < k) {\n d = (this[i]&((1<>(p+=this.DB-k);\n }\n else {\n d = (this[i]>>(p-=k))&km;\n if(p <= 0) { p += this.DB; --i; }\n }\n if(d > 0) m = true;\n if(m) r += int2char(d);\n }\n }\n return m?r:\"0\";\n }\n\n // (public) -this\n function bnNegate() { var r = nbi(); BigInteger.ZERO.subTo(this,r); return r; }\n\n // (public) |this|\n function bnAbs() { return (this.s<0)?this.negate():this; }\n\n // (public) return + if this > a, - if this < a, 0 if equal\n function bnCompareTo(a) {\n var r = this.s-a.s;\n if(r != 0) return r;\n var i = this.t;\n r = i-a.t;\n if(r != 0) return (this.s<0)?-r:r;\n while(--i >= 0) if((r=this[i]-a[i]) != 0) return r;\n return 0;\n }\n\n // returns bit length of the integer x\n function nbits(x) {\n var r = 1, t;\n if((t=x>>>16) != 0) { x = t; r += 16; }\n if((t=x>>8) != 0) { x = t; r += 8; }\n if((t=x>>4) != 0) { x = t; r += 4; }\n if((t=x>>2) != 0) { x = t; r += 2; }\n if((t=x>>1) != 0) { x = t; r += 1; }\n return r;\n }\n\n // (public) return the number of bits in \"this\"\n function bnBitLength() {\n if(this.t <= 0) return 0;\n return this.DB*(this.t-1)+nbits(this[this.t-1]^(this.s&this.DM));\n }\n\n // (protected) r = this << n*DB\n function bnpDLShiftTo(n,r) {\n var i;\n for(i = this.t-1; i >= 0; --i) r[i+n] = this[i];\n for(i = n-1; i >= 0; --i) r[i] = 0;\n r.t = this.t+n;\n r.s = this.s;\n }\n\n // (protected) r = this >> n*DB\n function bnpDRShiftTo(n,r) {\n for(var i = n; i < this.t; ++i) r[i-n] = this[i];\n r.t = Math.max(this.t-n,0);\n r.s = this.s;\n }\n\n // (protected) r = this << n\n function bnpLShiftTo(n,r) {\n var bs = n%this.DB;\n var cbs = this.DB-bs;\n var bm = (1<= 0; --i) {\n r[i+ds+1] = (this[i]>>cbs)|c;\n c = (this[i]&bm)<= 0; --i) r[i] = 0;\n r[ds] = c;\n r.t = this.t+ds+1;\n r.s = this.s;\n r.clamp();\n }\n\n // (protected) r = this >> n\n function bnpRShiftTo(n,r) {\n r.s = this.s;\n var ds = Math.floor(n/this.DB);\n if(ds >= this.t) { r.t = 0; return; }\n var bs = n%this.DB;\n var cbs = this.DB-bs;\n var bm = (1<>bs;\n for(var i = ds+1; i < this.t; ++i) {\n r[i-ds-1] |= (this[i]&bm)<>bs;\n }\n if(bs > 0) r[this.t-ds-1] |= (this.s&bm)<>= this.DB;\n }\n if(a.t < this.t) {\n c -= a.s;\n while(i < this.t) {\n c += this[i];\n r[i++] = c&this.DM;\n c >>= this.DB;\n }\n c += this.s;\n }\n else {\n c += this.s;\n while(i < a.t) {\n c -= a[i];\n r[i++] = c&this.DM;\n c >>= this.DB;\n }\n c -= a.s;\n }\n r.s = (c<0)?-1:0;\n if(c < -1) r[i++] = this.DV+c;\n else if(c > 0) r[i++] = c;\n r.t = i;\n r.clamp();\n }\n\n // (protected) r = this * a, r != this,a (HAC 14.12)\n // \"this\" should be the larger one if appropriate.\n function bnpMultiplyTo(a,r) {\n var x = this.abs(), y = a.abs();\n var i = x.t;\n r.t = i+y.t;\n while(--i >= 0) r[i] = 0;\n for(i = 0; i < y.t; ++i) r[i+x.t] = x.am(0,y[i],r,i,0,x.t);\n r.s = 0;\n r.clamp();\n if(this.s != a.s) BigInteger.ZERO.subTo(r,r);\n }\n\n // (protected) r = this^2, r != this (HAC 14.16)\n function bnpSquareTo(r) {\n var x = this.abs();\n var i = r.t = 2*x.t;\n while(--i >= 0) r[i] = 0;\n for(i = 0; i < x.t-1; ++i) {\n var c = x.am(i,x[i],r,2*i,0,1);\n if((r[i+x.t]+=x.am(i+1,2*x[i],r,2*i+1,c,x.t-i-1)) >= x.DV) {\n r[i+x.t] -= x.DV;\n r[i+x.t+1] = 1;\n }\n }\n if(r.t > 0) r[r.t-1] += x.am(i,x[i],r,2*i,0,1);\n r.s = 0;\n r.clamp();\n }\n\n // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)\n // r != q, this != m. q or r may be null.\n function bnpDivRemTo(m,q,r) {\n var pm = m.abs();\n if(pm.t <= 0) return;\n var pt = this.abs();\n if(pt.t < pm.t) {\n if(q != null) q.fromInt(0);\n if(r != null) this.copyTo(r);\n return;\n }\n if(r == null) r = nbi();\n var y = nbi(), ts = this.s, ms = m.s;\n var nsh = this.DB-nbits(pm[pm.t-1]); // normalize modulus\n if(nsh > 0) { pm.lShiftTo(nsh,y); pt.lShiftTo(nsh,r); }\n else { pm.copyTo(y); pt.copyTo(r); }\n var ys = y.t;\n var y0 = y[ys-1];\n if(y0 == 0) return;\n var yt = y0*(1<1)?y[ys-2]>>this.F2:0);\n var d1 = this.FV/yt, d2 = (1<= 0) {\n r[r.t++] = 1;\n r.subTo(t,r);\n }\n BigInteger.ONE.dlShiftTo(ys,t);\n t.subTo(y,y); // \"negative\" y so we can replace sub with am later\n while(y.t < ys) y[y.t++] = 0;\n while(--j >= 0) {\n // Estimate quotient digit\n var qd = (r[--i]==y0)?this.DM:Math.floor(r[i]*d1+(r[i-1]+e)*d2);\n if((r[i]+=y.am(0,qd,r,j,0,ys)) < qd) { // Try it out\n y.dlShiftTo(j,t);\n r.subTo(t,r);\n while(r[i] < --qd) r.subTo(t,r);\n }\n }\n if(q != null) {\n r.drShiftTo(ys,q);\n if(ts != ms) BigInteger.ZERO.subTo(q,q);\n }\n r.t = ys;\n r.clamp();\n if(nsh > 0) r.rShiftTo(nsh,r); // Denormalize remainder\n if(ts < 0) BigInteger.ZERO.subTo(r,r);\n }\n\n // (public) this mod a\n function bnMod(a) {\n var r = nbi();\n this.abs().divRemTo(a,null,r);\n if(this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r,r);\n return r;\n }\n\n // Modular reduction using \"classic\" algorithm\n function Classic(m) { this.m = m; }\n function cConvert(x) {\n if(x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);\n else return x;\n }\n function cRevert(x) { return x; }\n function cReduce(x) { x.divRemTo(this.m,null,x); }\n function cMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }\n function cSqrTo(x,r) { x.squareTo(r); this.reduce(r); }\n\n Classic.prototype.convert = cConvert;\n Classic.prototype.revert = cRevert;\n Classic.prototype.reduce = cReduce;\n Classic.prototype.mulTo = cMulTo;\n Classic.prototype.sqrTo = cSqrTo;\n\n // (protected) return \"-1/this % 2^DB\"; useful for Mont. reduction\n // justification:\n // xy == 1 (mod m)\n // xy = 1+km\n // xy(2-xy) = (1+km)(1-km)\n // x[y(2-xy)] = 1-k^2m^2\n // x[y(2-xy)] == 1 (mod m^2)\n // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2\n // should reduce x and y(2-xy) by m^2 at each step to keep size bounded.\n // JS multiply \"overflows\" differently from C/C++, so care is needed here.\n function bnpInvDigit() {\n if(this.t < 1) return 0;\n var x = this[0];\n if((x&1) == 0) return 0;\n var y = x&3; // y == 1/x mod 2^2\n y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4\n y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8\n y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16\n // last step - calculate inverse mod DV directly;\n // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints\n y = (y*(2-x*y%this.DV))%this.DV; // y == 1/x mod 2^dbits\n // we really want the negative inverse, and -DV < y < DV\n return (y>0)?this.DV-y:-y;\n }\n\n // Montgomery reduction\n function Montgomery(m) {\n this.m = m;\n this.mp = m.invDigit();\n this.mpl = this.mp&0x7fff;\n this.mph = this.mp>>15;\n this.um = (1<<(m.DB-15))-1;\n this.mt2 = 2*m.t;\n }\n\n // xR mod m\n function montConvert(x) {\n var r = nbi();\n x.abs().dlShiftTo(this.m.t,r);\n r.divRemTo(this.m,null,r);\n if(x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r,r);\n return r;\n }\n\n // x/R mod m\n function montRevert(x) {\n var r = nbi();\n x.copyTo(r);\n this.reduce(r);\n return r;\n }\n\n // x = x/R mod m (HAC 14.32)\n function montReduce(x) {\n while(x.t <= this.mt2) // pad x so am has enough room later\n x[x.t++] = 0;\n for(var i = 0; i < this.m.t; ++i) {\n // faster way of calculating u0 = x[i]*mp mod DV\n var j = x[i]&0x7fff;\n var u0 = (j*this.mpl+(((j*this.mph+(x[i]>>15)*this.mpl)&this.um)<<15))&x.DM;\n // use am to combine the multiply-shift-add into one call\n j = i+this.m.t;\n x[j] += this.m.am(0,u0,x,i,0,this.m.t);\n // propagate carry\n while(x[j] >= x.DV) { x[j] -= x.DV; x[++j]++; }\n }\n x.clamp();\n x.drShiftTo(this.m.t,x);\n if(x.compareTo(this.m) >= 0) x.subTo(this.m,x);\n }\n\n // r = \"x^2/R mod m\"; x != r\n function montSqrTo(x,r) { x.squareTo(r); this.reduce(r); }\n\n // r = \"xy/R mod m\"; x,y != r\n function montMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }\n\n Montgomery.prototype.convert = montConvert;\n Montgomery.prototype.revert = montRevert;\n Montgomery.prototype.reduce = montReduce;\n Montgomery.prototype.mulTo = montMulTo;\n Montgomery.prototype.sqrTo = montSqrTo;\n\n // (protected) true iff this is even\n function bnpIsEven() { return ((this.t>0)?(this[0]&1):this.s) == 0; }\n\n // (protected) this^e, e < 2^32, doing sqr and mul with \"r\" (HAC 14.79)\n function bnpExp(e,z) {\n if(e > 0xffffffff || e < 1) return BigInteger.ONE;\n var r = nbi(), r2 = nbi(), g = z.convert(this), i = nbits(e)-1;\n g.copyTo(r);\n while(--i >= 0) {\n z.sqrTo(r,r2);\n if((e&(1< 0) z.mulTo(r2,g,r);\n else { var t = r; r = r2; r2 = t; }\n }\n return z.revert(r);\n }\n\n // (public) this^e % m, 0 <= e < 2^32\n function bnModPowInt(e,m) {\n var z;\n if(e < 256 || m.isEven()) z = new Classic(m); else z = new Montgomery(m);\n return this.exp(e,z);\n }\n\n // protected\n BigInteger.prototype.copyTo = bnpCopyTo;\n BigInteger.prototype.fromInt = bnpFromInt;\n BigInteger.prototype.fromString = bnpFromString;\n BigInteger.prototype.clamp = bnpClamp;\n BigInteger.prototype.dlShiftTo = bnpDLShiftTo;\n BigInteger.prototype.drShiftTo = bnpDRShiftTo;\n BigInteger.prototype.lShiftTo = bnpLShiftTo;\n BigInteger.prototype.rShiftTo = bnpRShiftTo;\n BigInteger.prototype.subTo = bnpSubTo;\n BigInteger.prototype.multiplyTo = bnpMultiplyTo;\n BigInteger.prototype.squareTo = bnpSquareTo;\n BigInteger.prototype.divRemTo = bnpDivRemTo;\n BigInteger.prototype.invDigit = bnpInvDigit;\n BigInteger.prototype.isEven = bnpIsEven;\n BigInteger.prototype.exp = bnpExp;\n\n // public\n BigInteger.prototype.toString = bnToString;\n BigInteger.prototype.negate = bnNegate;\n BigInteger.prototype.abs = bnAbs;\n BigInteger.prototype.compareTo = bnCompareTo;\n BigInteger.prototype.bitLength = bnBitLength;\n BigInteger.prototype.mod = bnMod;\n BigInteger.prototype.modPowInt = bnModPowInt;\n\n // \"constants\"\n BigInteger.ZERO = nbv(0);\n BigInteger.ONE = nbv(1);\n\n // Copyright (c) 2005-2009 Tom Wu\n // All Rights Reserved.\n // See \"LICENSE\" for details.\n\n // Extended JavaScript BN functions, required for RSA private ops.\n\n // Version 1.1: new BigInteger(\"0\", 10) returns \"proper\" zero\n // Version 1.2: square() API, isProbablePrime fix\n\n // (public)\n function bnClone() { var r = nbi(); this.copyTo(r); return r; }\n\n // (public) return value as integer\n function bnIntValue() {\n if(this.s < 0) {\n if(this.t == 1) return this[0]-this.DV;\n else if(this.t == 0) return -1;\n }\n else if(this.t == 1) return this[0];\n else if(this.t == 0) return 0;\n // assumes 16 < DB < 32\n return ((this[1]&((1<<(32-this.DB))-1))<>24; }\n\n // (public) return value as short (assumes DB>=16)\n function bnShortValue() { return (this.t==0)?this.s:(this[0]<<16)>>16; }\n\n // (protected) return x s.t. r^x < DV\n function bnpChunkSize(r) { return Math.floor(Math.LN2*this.DB/Math.log(r)); }\n\n // (public) 0 if this == 0, 1 if this > 0\n function bnSigNum() {\n if(this.s < 0) return -1;\n else if(this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;\n else return 1;\n }\n\n // (protected) convert to radix string\n function bnpToRadix(b) {\n if(b == null) b = 10;\n if(this.signum() == 0 || b < 2 || b > 36) return \"0\";\n var cs = this.chunkSize(b);\n var a = Math.pow(b,cs);\n var d = nbv(a), y = nbi(), z = nbi(), r = \"\";\n this.divRemTo(d,y,z);\n while(y.signum() > 0) {\n r = (a+z.intValue()).toString(b).substr(1) + r;\n y.divRemTo(d,y,z);\n }\n return z.intValue().toString(b) + r;\n }\n\n // (protected) convert from radix string\n function bnpFromRadix(s,b) {\n this.fromInt(0);\n if(b == null) b = 10;\n var cs = this.chunkSize(b);\n var d = Math.pow(b,cs), mi = false, j = 0, w = 0;\n for(var i = 0; i < s.length; ++i) {\n var x = intAt(s,i);\n if(x < 0) {\n if(s.charAt(i) == \"-\" && this.signum() == 0) mi = true;\n continue;\n }\n w = b*w+x;\n if(++j >= cs) {\n this.dMultiply(d);\n this.dAddOffset(w,0);\n j = 0;\n w = 0;\n }\n }\n if(j > 0) {\n this.dMultiply(Math.pow(b,j));\n this.dAddOffset(w,0);\n }\n if(mi) BigInteger.ZERO.subTo(this,this);\n }\n\n // (protected) alternate constructor\n function bnpFromNumber(a,b,c) {\n if(\"number\" == typeof b) {\n // new BigInteger(int,int,RNG)\n if(a < 2) this.fromInt(1);\n else {\n this.fromNumber(a,c);\n if(!this.testBit(a-1))\t// force MSB set\n this.bitwiseTo(BigInteger.ONE.shiftLeft(a-1),op_or,this);\n if(this.isEven()) this.dAddOffset(1,0); // force odd\n while(!this.isProbablePrime(b)) {\n this.dAddOffset(2,0);\n if(this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a-1),this);\n }\n }\n }\n else {\n // new BigInteger(int,RNG)\n var x = new Array(), t = a&7;\n x.length = (a>>3)+1;\n b.nextBytes(x);\n if(t > 0) x[0] &= ((1< 0) {\n if(p < this.DB && (d = this[i]>>p) != (this.s&this.DM)>>p)\n r[k++] = d|(this.s<<(this.DB-p));\n while(i >= 0) {\n if(p < 8) {\n d = (this[i]&((1<>(p+=this.DB-8);\n }\n else {\n d = (this[i]>>(p-=8))&0xff;\n if(p <= 0) { p += this.DB; --i; }\n }\n if((d&0x80) != 0) d |= -256;\n if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;\n if(k > 0 || d != this.s) r[k++] = d;\n }\n }\n return r;\n }\n\n function bnEquals(a) { return(this.compareTo(a)==0); }\n function bnMin(a) { return(this.compareTo(a)<0)?this:a; }\n function bnMax(a) { return(this.compareTo(a)>0)?this:a; }\n\n // (protected) r = this op a (bitwise)\n function bnpBitwiseTo(a,op,r) {\n var i, f, m = Math.min(a.t,this.t);\n for(i = 0; i < m; ++i) r[i] = op(this[i],a[i]);\n if(a.t < this.t) {\n f = a.s&this.DM;\n for(i = m; i < this.t; ++i) r[i] = op(this[i],f);\n r.t = this.t;\n }\n else {\n f = this.s&this.DM;\n for(i = m; i < a.t; ++i) r[i] = op(f,a[i]);\n r.t = a.t;\n }\n r.s = op(this.s,a.s);\n r.clamp();\n }\n\n // (public) this & a\n function op_and(x,y) { return x&y; }\n function bnAnd(a) { var r = nbi(); this.bitwiseTo(a,op_and,r); return r; }\n\n // (public) this | a\n function op_or(x,y) { return x|y; }\n function bnOr(a) { var r = nbi(); this.bitwiseTo(a,op_or,r); return r; }\n\n // (public) this ^ a\n function op_xor(x,y) { return x^y; }\n function bnXor(a) { var r = nbi(); this.bitwiseTo(a,op_xor,r); return r; }\n\n // (public) this & ~a\n function op_andnot(x,y) { return x&~y; }\n function bnAndNot(a) { var r = nbi(); this.bitwiseTo(a,op_andnot,r); return r; }\n\n // (public) ~this\n function bnNot() {\n var r = nbi();\n for(var i = 0; i < this.t; ++i) r[i] = this.DM&~this[i];\n r.t = this.t;\n r.s = ~this.s;\n return r;\n }\n\n // (public) this << n\n function bnShiftLeft(n) {\n var r = nbi();\n if(n < 0) this.rShiftTo(-n,r); else this.lShiftTo(n,r);\n return r;\n }\n\n // (public) this >> n\n function bnShiftRight(n) {\n var r = nbi();\n if(n < 0) this.lShiftTo(-n,r); else this.rShiftTo(n,r);\n return r;\n }\n\n // return index of lowest 1-bit in x, x < 2^31\n function lbit(x) {\n if(x == 0) return -1;\n var r = 0;\n if((x&0xffff) == 0) { x >>= 16; r += 16; }\n if((x&0xff) == 0) { x >>= 8; r += 8; }\n if((x&0xf) == 0) { x >>= 4; r += 4; }\n if((x&3) == 0) { x >>= 2; r += 2; }\n if((x&1) == 0) ++r;\n return r;\n }\n\n // (public) returns index of lowest 1-bit (or -1 if none)\n function bnGetLowestSetBit() {\n for(var i = 0; i < this.t; ++i)\n if(this[i] != 0) return i*this.DB+lbit(this[i]);\n if(this.s < 0) return this.t*this.DB;\n return -1;\n }\n\n // return number of 1 bits in x\n function cbit(x) {\n var r = 0;\n while(x != 0) { x &= x-1; ++r; }\n return r;\n }\n\n // (public) return number of set bits\n function bnBitCount() {\n var r = 0, x = this.s&this.DM;\n for(var i = 0; i < this.t; ++i) r += cbit(this[i]^x);\n return r;\n }\n\n // (public) true iff nth bit is set\n function bnTestBit(n) {\n var j = Math.floor(n/this.DB);\n if(j >= this.t) return(this.s!=0);\n return((this[j]&(1<<(n%this.DB)))!=0);\n }\n\n // (protected) this op (1<>= this.DB;\n }\n if(a.t < this.t) {\n c += a.s;\n while(i < this.t) {\n c += this[i];\n r[i++] = c&this.DM;\n c >>= this.DB;\n }\n c += this.s;\n }\n else {\n c += this.s;\n while(i < a.t) {\n c += a[i];\n r[i++] = c&this.DM;\n c >>= this.DB;\n }\n c += a.s;\n }\n r.s = (c<0)?-1:0;\n if(c > 0) r[i++] = c;\n else if(c < -1) r[i++] = this.DV+c;\n r.t = i;\n r.clamp();\n }\n\n // (public) this + a\n function bnAdd(a) { var r = nbi(); this.addTo(a,r); return r; }\n\n // (public) this - a\n function bnSubtract(a) { var r = nbi(); this.subTo(a,r); return r; }\n\n // (public) this * a\n function bnMultiply(a) { var r = nbi(); this.multiplyTo(a,r); return r; }\n\n // (public) this^2\n function bnSquare() { var r = nbi(); this.squareTo(r); return r; }\n\n // (public) this / a\n function bnDivide(a) { var r = nbi(); this.divRemTo(a,r,null); return r; }\n\n // (public) this % a\n function bnRemainder(a) { var r = nbi(); this.divRemTo(a,null,r); return r; }\n\n // (public) [this/a,this%a]\n function bnDivideAndRemainder(a) {\n var q = nbi(), r = nbi();\n this.divRemTo(a,q,r);\n return new Array(q,r);\n }\n\n // (protected) this *= n, this >= 0, 1 < n < DV\n function bnpDMultiply(n) {\n this[this.t] = this.am(0,n-1,this,0,0,this.t);\n ++this.t;\n this.clamp();\n }\n\n // (protected) this += n << w words, this >= 0\n function bnpDAddOffset(n,w) {\n if(n == 0) return;\n while(this.t <= w) this[this.t++] = 0;\n this[w] += n;\n while(this[w] >= this.DV) {\n this[w] -= this.DV;\n if(++w >= this.t) this[this.t++] = 0;\n ++this[w];\n }\n }\n\n // A \"null\" reducer\n function NullExp() {}\n function nNop(x) { return x; }\n function nMulTo(x,y,r) { x.multiplyTo(y,r); }\n function nSqrTo(x,r) { x.squareTo(r); }\n\n NullExp.prototype.convert = nNop;\n NullExp.prototype.revert = nNop;\n NullExp.prototype.mulTo = nMulTo;\n NullExp.prototype.sqrTo = nSqrTo;\n\n // (public) this^e\n function bnPow(e) { return this.exp(e,new NullExp()); }\n\n // (protected) r = lower n words of \"this * a\", a.t <= n\n // \"this\" should be the larger one if appropriate.\n function bnpMultiplyLowerTo(a,n,r) {\n var i = Math.min(this.t+a.t,n);\n r.s = 0; // assumes a,this >= 0\n r.t = i;\n while(i > 0) r[--i] = 0;\n var j;\n for(j = r.t-this.t; i < j; ++i) r[i+this.t] = this.am(0,a[i],r,i,0,this.t);\n for(j = Math.min(a.t,n); i < j; ++i) this.am(0,a[i],r,i,0,n-i);\n r.clamp();\n }\n\n // (protected) r = \"this * a\" without lower n words, n > 0\n // \"this\" should be the larger one if appropriate.\n function bnpMultiplyUpperTo(a,n,r) {\n --n;\n var i = r.t = this.t+a.t-n;\n r.s = 0; // assumes a,this >= 0\n while(--i >= 0) r[i] = 0;\n for(i = Math.max(n-this.t,0); i < a.t; ++i)\n r[this.t+i-n] = this.am(n-i,a[i],r,0,0,this.t+i-n);\n r.clamp();\n r.drShiftTo(1,r);\n }\n\n // Barrett modular reduction\n function Barrett(m) {\n // setup Barrett\n this.r2 = nbi();\n this.q3 = nbi();\n BigInteger.ONE.dlShiftTo(2*m.t,this.r2);\n this.mu = this.r2.divide(m);\n this.m = m;\n }\n\n function barrettConvert(x) {\n if(x.s < 0 || x.t > 2*this.m.t) return x.mod(this.m);\n else if(x.compareTo(this.m) < 0) return x;\n else { var r = nbi(); x.copyTo(r); this.reduce(r); return r; }\n }\n\n function barrettRevert(x) { return x; }\n\n // x = x mod m (HAC 14.42)\n function barrettReduce(x) {\n x.drShiftTo(this.m.t-1,this.r2);\n if(x.t > this.m.t+1) { x.t = this.m.t+1; x.clamp(); }\n this.mu.multiplyUpperTo(this.r2,this.m.t+1,this.q3);\n this.m.multiplyLowerTo(this.q3,this.m.t+1,this.r2);\n while(x.compareTo(this.r2) < 0) x.dAddOffset(1,this.m.t+1);\n x.subTo(this.r2,x);\n while(x.compareTo(this.m) >= 0) x.subTo(this.m,x);\n }\n\n // r = x^2 mod m; x != r\n function barrettSqrTo(x,r) { x.squareTo(r); this.reduce(r); }\n\n // r = x*y mod m; x,y != r\n function barrettMulTo(x,y,r) { x.multiplyTo(y,r); this.reduce(r); }\n\n Barrett.prototype.convert = barrettConvert;\n Barrett.prototype.revert = barrettRevert;\n Barrett.prototype.reduce = barrettReduce;\n Barrett.prototype.mulTo = barrettMulTo;\n Barrett.prototype.sqrTo = barrettSqrTo;\n\n // (public) this^e % m (HAC 14.85)\n function bnModPow(e,m) {\n var i = e.bitLength(), k, r = nbv(1), z;\n if(i <= 0) return r;\n else if(i < 18) k = 1;\n else if(i < 48) k = 3;\n else if(i < 144) k = 4;\n else if(i < 768) k = 5;\n else k = 6;\n if(i < 8)\n z = new Classic(m);\n else if(m.isEven())\n z = new Barrett(m);\n else\n z = new Montgomery(m);\n\n // precomputation\n var g = new Array(), n = 3, k1 = k-1, km = (1< 1) {\n var g2 = nbi();\n z.sqrTo(g[1],g2);\n while(n <= km) {\n g[n] = nbi();\n z.mulTo(g2,g[n-2],g[n]);\n n += 2;\n }\n }\n\n var j = e.t-1, w, is1 = true, r2 = nbi(), t;\n i = nbits(e[j])-1;\n while(j >= 0) {\n if(i >= k1) w = (e[j]>>(i-k1))&km;\n else {\n w = (e[j]&((1<<(i+1))-1))<<(k1-i);\n if(j > 0) w |= e[j-1]>>(this.DB+i-k1);\n }\n\n n = k;\n while((w&1) == 0) { w >>= 1; --n; }\n if((i -= n) < 0) { i += this.DB; --j; }\n if(is1) {\t// ret == 1, don't bother squaring or multiplying it\n g[w].copyTo(r);\n is1 = false;\n }\n else {\n while(n > 1) { z.sqrTo(r,r2); z.sqrTo(r2,r); n -= 2; }\n if(n > 0) z.sqrTo(r,r2); else { t = r; r = r2; r2 = t; }\n z.mulTo(r2,g[w],r);\n }\n\n while(j >= 0 && (e[j]&(1< 0) {\n x.rShiftTo(g,x);\n y.rShiftTo(g,y);\n }\n while(x.signum() > 0) {\n if((i = x.getLowestSetBit()) > 0) x.rShiftTo(i,x);\n if((i = y.getLowestSetBit()) > 0) y.rShiftTo(i,y);\n if(x.compareTo(y) >= 0) {\n x.subTo(y,x);\n x.rShiftTo(1,x);\n }\n else {\n y.subTo(x,y);\n y.rShiftTo(1,y);\n }\n }\n if(g > 0) y.lShiftTo(g,y);\n return y;\n }\n\n // (protected) this % n, n < 2^26\n function bnpModInt(n) {\n if(n <= 0) return 0;\n var d = this.DV%n, r = (this.s<0)?n-1:0;\n if(this.t > 0)\n if(d == 0) r = this[0]%n;\n else for(var i = this.t-1; i >= 0; --i) r = (d*r+this[i])%n;\n return r;\n }\n\n // (public) 1/this % m (HAC 14.61)\n function bnModInverse(m) {\n var ac = m.isEven();\n if((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;\n var u = m.clone(), v = this.clone();\n var a = nbv(1), b = nbv(0), c = nbv(0), d = nbv(1);\n while(u.signum() != 0) {\n while(u.isEven()) {\n u.rShiftTo(1,u);\n if(ac) {\n if(!a.isEven() || !b.isEven()) { a.addTo(this,a); b.subTo(m,b); }\n a.rShiftTo(1,a);\n }\n else if(!b.isEven()) b.subTo(m,b);\n b.rShiftTo(1,b);\n }\n while(v.isEven()) {\n v.rShiftTo(1,v);\n if(ac) {\n if(!c.isEven() || !d.isEven()) { c.addTo(this,c); d.subTo(m,d); }\n c.rShiftTo(1,c);\n }\n else if(!d.isEven()) d.subTo(m,d);\n d.rShiftTo(1,d);\n }\n if(u.compareTo(v) >= 0) {\n u.subTo(v,u);\n if(ac) a.subTo(c,a);\n b.subTo(d,b);\n }\n else {\n v.subTo(u,v);\n if(ac) c.subTo(a,c);\n d.subTo(b,d);\n }\n }\n if(v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;\n if(d.compareTo(m) >= 0) return d.subtract(m);\n if(d.signum() < 0) d.addTo(m,d); else return d;\n if(d.signum() < 0) return d.add(m); else return d;\n }\n\n var lowprimes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997];\n var lplim = (1<<26)/lowprimes[lowprimes.length-1];\n\n // (public) test primality with certainty >= 1-.5^t\n function bnIsProbablePrime(t) {\n var i, x = this.abs();\n if(x.t == 1 && x[0] <= lowprimes[lowprimes.length-1]) {\n for(i = 0; i < lowprimes.length; ++i)\n if(x[0] == lowprimes[i]) return true;\n return false;\n }\n if(x.isEven()) return false;\n i = 1;\n while(i < lowprimes.length) {\n var m = lowprimes[i], j = i+1;\n while(j < lowprimes.length && m < lplim) m *= lowprimes[j++];\n m = x.modInt(m);\n while(i < j) if(m%lowprimes[i++] == 0) return false;\n }\n return x.millerRabin(t);\n }\n\n // (protected) true if probably prime (HAC 4.24, Miller-Rabin)\n function bnpMillerRabin(t) {\n var n1 = this.subtract(BigInteger.ONE);\n var k = n1.getLowestSetBit();\n if(k <= 0) return false;\n var r = n1.shiftRight(k);\n t = (t+1)>>1;\n if(t > lowprimes.length) t = lowprimes.length;\n var a = nbi();\n for(var i = 0; i < t; ++i) {\n //Pick bases at random, instead of starting at 2\n a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]);\n var y = a.modPow(r,this);\n if(y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {\n var j = 1;\n while(j++ < k && y.compareTo(n1) != 0) {\n y = y.modPowInt(2,this);\n if(y.compareTo(BigInteger.ONE) == 0) return false;\n }\n if(y.compareTo(n1) != 0) return false;\n }\n }\n return true;\n }\n\n // protected\n BigInteger.prototype.chunkSize = bnpChunkSize;\n BigInteger.prototype.toRadix = bnpToRadix;\n BigInteger.prototype.fromRadix = bnpFromRadix;\n BigInteger.prototype.fromNumber = bnpFromNumber;\n BigInteger.prototype.bitwiseTo = bnpBitwiseTo;\n BigInteger.prototype.changeBit = bnpChangeBit;\n BigInteger.prototype.addTo = bnpAddTo;\n BigInteger.prototype.dMultiply = bnpDMultiply;\n BigInteger.prototype.dAddOffset = bnpDAddOffset;\n BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;\n BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;\n BigInteger.prototype.modInt = bnpModInt;\n BigInteger.prototype.millerRabin = bnpMillerRabin;\n\n // public\n BigInteger.prototype.clone = bnClone;\n BigInteger.prototype.intValue = bnIntValue;\n BigInteger.prototype.byteValue = bnByteValue;\n BigInteger.prototype.shortValue = bnShortValue;\n BigInteger.prototype.signum = bnSigNum;\n BigInteger.prototype.toByteArray = bnToByteArray;\n BigInteger.prototype.equals = bnEquals;\n BigInteger.prototype.min = bnMin;\n BigInteger.prototype.max = bnMax;\n BigInteger.prototype.and = bnAnd;\n BigInteger.prototype.or = bnOr;\n BigInteger.prototype.xor = bnXor;\n BigInteger.prototype.andNot = bnAndNot;\n BigInteger.prototype.not = bnNot;\n BigInteger.prototype.shiftLeft = bnShiftLeft;\n BigInteger.prototype.shiftRight = bnShiftRight;\n BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;\n BigInteger.prototype.bitCount = bnBitCount;\n BigInteger.prototype.testBit = bnTestBit;\n BigInteger.prototype.setBit = bnSetBit;\n BigInteger.prototype.clearBit = bnClearBit;\n BigInteger.prototype.flipBit = bnFlipBit;\n BigInteger.prototype.add = bnAdd;\n BigInteger.prototype.subtract = bnSubtract;\n BigInteger.prototype.multiply = bnMultiply;\n BigInteger.prototype.divide = bnDivide;\n BigInteger.prototype.remainder = bnRemainder;\n BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;\n BigInteger.prototype.modPow = bnModPow;\n BigInteger.prototype.modInverse = bnModInverse;\n BigInteger.prototype.pow = bnPow;\n BigInteger.prototype.gcd = bnGCD;\n BigInteger.prototype.isProbablePrime = bnIsProbablePrime;\n\n // JSBN-specific extension\n BigInteger.prototype.square = bnSquare;\n\n // Expose the Barrett function\n BigInteger.prototype.Barrett = Barrett\n\n // BigInteger interfaces not implemented in jsbn:\n\n // BigInteger(int signum, byte[] magnitude)\n // double doubleValue()\n // float floatValue()\n // int hashCode()\n // long longValue()\n // static BigInteger valueOf(long val)\n\n\t// Random number generator - requires a PRNG backend, e.g. prng4.js\n\n\t// For best results, put code like\n\t// \n\t// in your main HTML document.\n\n\tvar rng_state;\n\tvar rng_pool;\n\tvar rng_pptr;\n\n\t// Mix in a 32-bit integer into the pool\n\tfunction rng_seed_int(x) {\n\t rng_pool[rng_pptr++] ^= x & 255;\n\t rng_pool[rng_pptr++] ^= (x >> 8) & 255;\n\t rng_pool[rng_pptr++] ^= (x >> 16) & 255;\n\t rng_pool[rng_pptr++] ^= (x >> 24) & 255;\n\t if(rng_pptr >= rng_psize) rng_pptr -= rng_psize;\n\t}\n\n\t// Mix in the current time (w/milliseconds) into the pool\n\tfunction rng_seed_time() {\n\t rng_seed_int(new Date().getTime());\n\t}\n\n\t// Initialize the pool with junk if needed.\n\tif(rng_pool == null) {\n\t rng_pool = new Array();\n\t rng_pptr = 0;\n\t var t;\n\t if(typeof window !== \"undefined\" && window.crypto) {\n\t\tif (window.crypto.getRandomValues) {\n\t\t // Use webcrypto if available\n\t\t var ua = new Uint8Array(32);\n\t\t window.crypto.getRandomValues(ua);\n\t\t for(t = 0; t < 32; ++t)\n\t\t\trng_pool[rng_pptr++] = ua[t];\n\t\t}\n\t\telse if(navigator.appName == \"Netscape\" && navigator.appVersion < \"5\") {\n\t\t // Extract entropy (256 bits) from NS4 RNG if available\n\t\t var z = window.crypto.random(32);\n\t\t for(t = 0; t < z.length; ++t)\n\t\t\trng_pool[rng_pptr++] = z.charCodeAt(t) & 255;\n\t\t}\n\t }\n\t while(rng_pptr < rng_psize) { // extract some randomness from Math.random()\n\t\tt = Math.floor(65536 * Math.random());\n\t\trng_pool[rng_pptr++] = t >>> 8;\n\t\trng_pool[rng_pptr++] = t & 255;\n\t }\n\t rng_pptr = 0;\n\t rng_seed_time();\n\t //rng_seed_int(window.screenX);\n\t //rng_seed_int(window.screenY);\n\t}\n\n\tfunction rng_get_byte() {\n\t if(rng_state == null) {\n\t\trng_seed_time();\n\t\trng_state = prng_newstate();\n\t\trng_state.init(rng_pool);\n\t\tfor(rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr)\n\t\t rng_pool[rng_pptr] = 0;\n\t\trng_pptr = 0;\n\t\t//rng_pool = null;\n\t }\n\t // TODO: allow reseeding after first request\n\t return rng_state.next();\n\t}\n\n\tfunction rng_get_bytes(ba) {\n\t var i;\n\t for(i = 0; i < ba.length; ++i) ba[i] = rng_get_byte();\n\t}\n\n\tfunction SecureRandom() {}\n\n\tSecureRandom.prototype.nextBytes = rng_get_bytes;\n\n\t// prng4.js - uses Arcfour as a PRNG\n\n\tfunction Arcfour() {\n\t this.i = 0;\n\t this.j = 0;\n\t this.S = new Array();\n\t}\n\n\t// Initialize arcfour context from key, an array of ints, each from [0..255]\n\tfunction ARC4init(key) {\n\t var i, j, t;\n\t for(i = 0; i < 256; ++i)\n\t\tthis.S[i] = i;\n\t j = 0;\n\t for(i = 0; i < 256; ++i) {\n\t\tj = (j + this.S[i] + key[i % key.length]) & 255;\n\t\tt = this.S[i];\n\t\tthis.S[i] = this.S[j];\n\t\tthis.S[j] = t;\n\t }\n\t this.i = 0;\n\t this.j = 0;\n\t}\n\n\tfunction ARC4next() {\n\t var t;\n\t this.i = (this.i + 1) & 255;\n\t this.j = (this.j + this.S[this.i]) & 255;\n\t t = this.S[this.i];\n\t this.S[this.i] = this.S[this.j];\n\t this.S[this.j] = t;\n\t return this.S[(t + this.S[this.i]) & 255];\n\t}\n\n\tArcfour.prototype.init = ARC4init;\n\tArcfour.prototype.next = ARC4next;\n\n\t// Plug in your RNG constructor here\n\tfunction prng_newstate() {\n\t return new Arcfour();\n\t}\n\n\t// Pool size must be a multiple of 4 and greater than 32.\n\t// An array of bytes the size of the pool will be passed to init()\n\tvar rng_psize = 256;\n\n BigInteger.SecureRandom = SecureRandom;\n BigInteger.BigInteger = BigInteger;\n if (typeof exports !== 'undefined') {\n exports = module.exports = BigInteger;\n } else {\n this.BigInteger = BigInteger;\n this.SecureRandom = SecureRandom;\n }\n\n}).call(this);\n","// Copyright 2015 Joyent, Inc.\n\nmodule.exports = {\n\tread: read,\n\treadPkcs8: readPkcs8,\n\twrite: write,\n\twritePkcs8: writePkcs8,\n\n\treadECDSACurve: readECDSACurve,\n\twriteECDSACurve: writeECDSACurve\n};\n\nvar assert = require('assert-plus');\nvar asn1 = require('asn1');\nvar Buffer = require('safer-buffer').Buffer;\nvar algs = require('../algs');\nvar utils = require('../utils');\nvar Key = require('../key');\nvar PrivateKey = require('../private-key');\nvar pem = require('./pem');\n\nfunction read(buf, options) {\n\treturn (pem.read(buf, options, 'pkcs8'));\n}\n\nfunction write(key, options) {\n\treturn (pem.write(key, options, 'pkcs8'));\n}\n\n/* Helper to read in a single mpint */\nfunction readMPInt(der, nm) {\n\tassert.strictEqual(der.peek(), asn1.Ber.Integer,\n\t nm + ' is not an Integer');\n\treturn (utils.mpNormalize(der.readString(asn1.Ber.Integer, true)));\n}\n\nfunction readPkcs8(alg, type, der) {\n\t/* Private keys in pkcs#8 format have a weird extra int */\n\tif (der.peek() === asn1.Ber.Integer) {\n\t\tassert.strictEqual(type, 'private',\n\t\t 'unexpected Integer at start of public key');\n\t\tder.readString(asn1.Ber.Integer, true);\n\t}\n\n\tder.readSequence();\n\tvar next = der.offset + der.length;\n\n\tvar oid = der.readOID();\n\tswitch (oid) {\n\tcase '1.2.840.113549.1.1.1':\n\t\tder._offset = next;\n\t\tif (type === 'public')\n\t\t\treturn (readPkcs8RSAPublic(der));\n\t\telse\n\t\t\treturn (readPkcs8RSAPrivate(der));\n\tcase '1.2.840.10040.4.1':\n\t\tif (type === 'public')\n\t\t\treturn (readPkcs8DSAPublic(der));\n\t\telse\n\t\t\treturn (readPkcs8DSAPrivate(der));\n\tcase '1.2.840.10045.2.1':\n\t\tif (type === 'public')\n\t\t\treturn (readPkcs8ECDSAPublic(der));\n\t\telse\n\t\t\treturn (readPkcs8ECDSAPrivate(der));\n\tcase '1.3.101.112':\n\t\tif (type === 'public') {\n\t\t\treturn (readPkcs8EdDSAPublic(der));\n\t\t} else {\n\t\t\treturn (readPkcs8EdDSAPrivate(der));\n\t\t}\n\tcase '1.3.101.110':\n\t\tif (type === 'public') {\n\t\t\treturn (readPkcs8X25519Public(der));\n\t\t} else {\n\t\t\treturn (readPkcs8X25519Private(der));\n\t\t}\n\tdefault:\n\t\tthrow (new Error('Unknown key type OID ' + oid));\n\t}\n}\n\nfunction readPkcs8RSAPublic(der) {\n\t// bit string sequence\n\tder.readSequence(asn1.Ber.BitString);\n\tder.readByte();\n\tder.readSequence();\n\n\t// modulus\n\tvar n = readMPInt(der, 'modulus');\n\tvar e = readMPInt(der, 'exponent');\n\n\t// now, make the key\n\tvar key = {\n\t\ttype: 'rsa',\n\t\tsource: der.originalInput,\n\t\tparts: [\n\t\t\t{ name: 'e', data: e },\n\t\t\t{ name: 'n', data: n }\n\t\t]\n\t};\n\n\treturn (new Key(key));\n}\n\nfunction readPkcs8RSAPrivate(der) {\n\tder.readSequence(asn1.Ber.OctetString);\n\tder.readSequence();\n\n\tvar ver = readMPInt(der, 'version');\n\tassert.equal(ver[0], 0x0, 'unknown RSA private key version');\n\n\t// modulus then public exponent\n\tvar n = readMPInt(der, 'modulus');\n\tvar e = readMPInt(der, 'public exponent');\n\tvar d = readMPInt(der, 'private exponent');\n\tvar p = readMPInt(der, 'prime1');\n\tvar q = readMPInt(der, 'prime2');\n\tvar dmodp = readMPInt(der, 'exponent1');\n\tvar dmodq = readMPInt(der, 'exponent2');\n\tvar iqmp = readMPInt(der, 'iqmp');\n\n\t// now, make the key\n\tvar key = {\n\t\ttype: 'rsa',\n\t\tparts: [\n\t\t\t{ name: 'n', data: n },\n\t\t\t{ name: 'e', data: e },\n\t\t\t{ name: 'd', data: d },\n\t\t\t{ name: 'iqmp', data: iqmp },\n\t\t\t{ name: 'p', data: p },\n\t\t\t{ name: 'q', data: q },\n\t\t\t{ name: 'dmodp', data: dmodp },\n\t\t\t{ name: 'dmodq', data: dmodq }\n\t\t]\n\t};\n\n\treturn (new PrivateKey(key));\n}\n\nfunction readPkcs8DSAPublic(der) {\n\tder.readSequence();\n\n\tvar p = readMPInt(der, 'p');\n\tvar q = readMPInt(der, 'q');\n\tvar g = readMPInt(der, 'g');\n\n\t// bit string sequence\n\tder.readSequence(asn1.Ber.BitString);\n\tder.readByte();\n\n\tvar y = readMPInt(der, 'y');\n\n\t// now, make the key\n\tvar key = {\n\t\ttype: 'dsa',\n\t\tparts: [\n\t\t\t{ name: 'p', data: p },\n\t\t\t{ name: 'q', data: q },\n\t\t\t{ name: 'g', data: g },\n\t\t\t{ name: 'y', data: y }\n\t\t]\n\t};\n\n\treturn (new Key(key));\n}\n\nfunction readPkcs8DSAPrivate(der) {\n\tder.readSequence();\n\n\tvar p = readMPInt(der, 'p');\n\tvar q = readMPInt(der, 'q');\n\tvar g = readMPInt(der, 'g');\n\n\tder.readSequence(asn1.Ber.OctetString);\n\tvar x = readMPInt(der, 'x');\n\n\t/* The pkcs#8 format does not include the public key */\n\tvar y = utils.calculateDSAPublic(g, p, x);\n\n\tvar key = {\n\t\ttype: 'dsa',\n\t\tparts: [\n\t\t\t{ name: 'p', data: p },\n\t\t\t{ name: 'q', data: q },\n\t\t\t{ name: 'g', data: g },\n\t\t\t{ name: 'y', data: y },\n\t\t\t{ name: 'x', data: x }\n\t\t]\n\t};\n\n\treturn (new PrivateKey(key));\n}\n\nfunction readECDSACurve(der) {\n\tvar curveName, curveNames;\n\tvar j, c, cd;\n\n\tif (der.peek() === asn1.Ber.OID) {\n\t\tvar oid = der.readOID();\n\n\t\tcurveNames = Object.keys(algs.curves);\n\t\tfor (j = 0; j < curveNames.length; ++j) {\n\t\t\tc = curveNames[j];\n\t\t\tcd = algs.curves[c];\n\t\t\tif (cd.pkcs8oid === oid) {\n\t\t\t\tcurveName = c;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t} else {\n\t\t// ECParameters sequence\n\t\tder.readSequence();\n\t\tvar version = der.readString(asn1.Ber.Integer, true);\n\t\tassert.strictEqual(version[0], 1, 'ECDSA key not version 1');\n\n\t\tvar curve = {};\n\n\t\t// FieldID sequence\n\t\tder.readSequence();\n\t\tvar fieldTypeOid = der.readOID();\n\t\tassert.strictEqual(fieldTypeOid, '1.2.840.10045.1.1',\n\t\t 'ECDSA key is not from a prime-field');\n\t\tvar p = curve.p = utils.mpNormalize(\n\t\t der.readString(asn1.Ber.Integer, true));\n\t\t/*\n\t\t * p always starts with a 1 bit, so count the zeros to get its\n\t\t * real size.\n\t\t */\n\t\tcurve.size = p.length * 8 - utils.countZeros(p);\n\n\t\t// Curve sequence\n\t\tder.readSequence();\n\t\tcurve.a = utils.mpNormalize(\n\t\t der.readString(asn1.Ber.OctetString, true));\n\t\tcurve.b = utils.mpNormalize(\n\t\t der.readString(asn1.Ber.OctetString, true));\n\t\tif (der.peek() === asn1.Ber.BitString)\n\t\t\tcurve.s = der.readString(asn1.Ber.BitString, true);\n\n\t\t// Combined Gx and Gy\n\t\tcurve.G = der.readString(asn1.Ber.OctetString, true);\n\t\tassert.strictEqual(curve.G[0], 0x4,\n\t\t 'uncompressed G is required');\n\n\t\tcurve.n = utils.mpNormalize(\n\t\t der.readString(asn1.Ber.Integer, true));\n\t\tcurve.h = utils.mpNormalize(\n\t\t der.readString(asn1.Ber.Integer, true));\n\t\tassert.strictEqual(curve.h[0], 0x1, 'a cofactor=1 curve is ' +\n\t\t 'required');\n\n\t\tcurveNames = Object.keys(algs.curves);\n\t\tvar ks = Object.keys(curve);\n\t\tfor (j = 0; j < curveNames.length; ++j) {\n\t\t\tc = curveNames[j];\n\t\t\tcd = algs.curves[c];\n\t\t\tvar equal = true;\n\t\t\tfor (var i = 0; i < ks.length; ++i) {\n\t\t\t\tvar k = ks[i];\n\t\t\t\tif (cd[k] === undefined)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (typeof (cd[k]) === 'object' &&\n\t\t\t\t cd[k].equals !== undefined) {\n\t\t\t\t\tif (!cd[k].equals(curve[k])) {\n\t\t\t\t\t\tequal = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} else if (Buffer.isBuffer(cd[k])) {\n\t\t\t\t\tif (cd[k].toString('binary')\n\t\t\t\t\t !== curve[k].toString('binary')) {\n\t\t\t\t\t\tequal = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (cd[k] !== curve[k]) {\n\t\t\t\t\t\tequal = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (equal) {\n\t\t\t\tcurveName = c;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\treturn (curveName);\n}\n\nfunction readPkcs8ECDSAPrivate(der) {\n\tvar curveName = readECDSACurve(der);\n\tassert.string(curveName, 'a known elliptic curve');\n\n\tder.readSequence(asn1.Ber.OctetString);\n\tder.readSequence();\n\n\tvar version = readMPInt(der, 'version');\n\tassert.equal(version[0], 1, 'unknown version of ECDSA key');\n\n\tvar d = der.readString(asn1.Ber.OctetString, true);\n\tder.readSequence(0xa1);\n\n\tvar Q = der.readString(asn1.Ber.BitString, true);\n\tQ = utils.ecNormalize(Q);\n\n\tvar key = {\n\t\ttype: 'ecdsa',\n\t\tparts: [\n\t\t\t{ name: 'curve', data: Buffer.from(curveName) },\n\t\t\t{ name: 'Q', data: Q },\n\t\t\t{ name: 'd', data: d }\n\t\t]\n\t};\n\n\treturn (new PrivateKey(key));\n}\n\nfunction readPkcs8ECDSAPublic(der) {\n\tvar curveName = readECDSACurve(der);\n\tassert.string(curveName, 'a known elliptic curve');\n\n\tvar Q = der.readString(asn1.Ber.BitString, true);\n\tQ = utils.ecNormalize(Q);\n\n\tvar key = {\n\t\ttype: 'ecdsa',\n\t\tparts: [\n\t\t\t{ name: 'curve', data: Buffer.from(curveName) },\n\t\t\t{ name: 'Q', data: Q }\n\t\t]\n\t};\n\n\treturn (new Key(key));\n}\n\nfunction readPkcs8EdDSAPublic(der) {\n\tif (der.peek() === 0x00)\n\t\tder.readByte();\n\n\tvar A = utils.readBitString(der);\n\n\tvar key = {\n\t\ttype: 'ed25519',\n\t\tparts: [\n\t\t\t{ name: 'A', data: utils.zeroPadToLength(A, 32) }\n\t\t]\n\t};\n\n\treturn (new Key(key));\n}\n\nfunction readPkcs8X25519Public(der) {\n\tvar A = utils.readBitString(der);\n\n\tvar key = {\n\t\ttype: 'curve25519',\n\t\tparts: [\n\t\t\t{ name: 'A', data: utils.zeroPadToLength(A, 32) }\n\t\t]\n\t};\n\n\treturn (new Key(key));\n}\n\nfunction readPkcs8EdDSAPrivate(der) {\n\tif (der.peek() === 0x00)\n\t\tder.readByte();\n\n\tder.readSequence(asn1.Ber.OctetString);\n\tvar k = der.readString(asn1.Ber.OctetString, true);\n\tk = utils.zeroPadToLength(k, 32);\n\n\tvar A;\n\tif (der.peek() === asn1.Ber.BitString) {\n\t\tA = utils.readBitString(der);\n\t\tA = utils.zeroPadToLength(A, 32);\n\t} else {\n\t\tA = utils.calculateED25519Public(k);\n\t}\n\n\tvar key = {\n\t\ttype: 'ed25519',\n\t\tparts: [\n\t\t\t{ name: 'A', data: utils.zeroPadToLength(A, 32) },\n\t\t\t{ name: 'k', data: utils.zeroPadToLength(k, 32) }\n\t\t]\n\t};\n\n\treturn (new PrivateKey(key));\n}\n\nfunction readPkcs8X25519Private(der) {\n\tif (der.peek() === 0x00)\n\t\tder.readByte();\n\n\tder.readSequence(asn1.Ber.OctetString);\n\tvar k = der.readString(asn1.Ber.OctetString, true);\n\tk = utils.zeroPadToLength(k, 32);\n\n\tvar A = utils.calculateX25519Public(k);\n\n\tvar key = {\n\t\ttype: 'curve25519',\n\t\tparts: [\n\t\t\t{ name: 'A', data: utils.zeroPadToLength(A, 32) },\n\t\t\t{ name: 'k', data: utils.zeroPadToLength(k, 32) }\n\t\t]\n\t};\n\n\treturn (new PrivateKey(key));\n}\n\nfunction writePkcs8(der, key) {\n\tder.startSequence();\n\n\tif (PrivateKey.isPrivateKey(key)) {\n\t\tvar sillyInt = Buffer.from([0]);\n\t\tder.writeBuffer(sillyInt, asn1.Ber.Integer);\n\t}\n\n\tder.startSequence();\n\tswitch (key.type) {\n\tcase 'rsa':\n\t\tder.writeOID('1.2.840.113549.1.1.1');\n\t\tif (PrivateKey.isPrivateKey(key))\n\t\t\twritePkcs8RSAPrivate(key, der);\n\t\telse\n\t\t\twritePkcs8RSAPublic(key, der);\n\t\tbreak;\n\tcase 'dsa':\n\t\tder.writeOID('1.2.840.10040.4.1');\n\t\tif (PrivateKey.isPrivateKey(key))\n\t\t\twritePkcs8DSAPrivate(key, der);\n\t\telse\n\t\t\twritePkcs8DSAPublic(key, der);\n\t\tbreak;\n\tcase 'ecdsa':\n\t\tder.writeOID('1.2.840.10045.2.1');\n\t\tif (PrivateKey.isPrivateKey(key))\n\t\t\twritePkcs8ECDSAPrivate(key, der);\n\t\telse\n\t\t\twritePkcs8ECDSAPublic(key, der);\n\t\tbreak;\n\tcase 'ed25519':\n\t\tder.writeOID('1.3.101.112');\n\t\tif (PrivateKey.isPrivateKey(key))\n\t\t\tthrow (new Error('Ed25519 private keys in pkcs8 ' +\n\t\t\t 'format are not supported'));\n\t\twritePkcs8EdDSAPublic(key, der);\n\t\tbreak;\n\tdefault:\n\t\tthrow (new Error('Unsupported key type: ' + key.type));\n\t}\n\n\tder.endSequence();\n}\n\nfunction writePkcs8RSAPrivate(key, der) {\n\tder.writeNull();\n\tder.endSequence();\n\n\tder.startSequence(asn1.Ber.OctetString);\n\tder.startSequence();\n\n\tvar version = Buffer.from([0]);\n\tder.writeBuffer(version, asn1.Ber.Integer);\n\n\tder.writeBuffer(key.part.n.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.e.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.d.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.p.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.q.data, asn1.Ber.Integer);\n\tif (!key.part.dmodp || !key.part.dmodq)\n\t\tutils.addRSAMissing(key);\n\tder.writeBuffer(key.part.dmodp.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.dmodq.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.iqmp.data, asn1.Ber.Integer);\n\n\tder.endSequence();\n\tder.endSequence();\n}\n\nfunction writePkcs8RSAPublic(key, der) {\n\tder.writeNull();\n\tder.endSequence();\n\n\tder.startSequence(asn1.Ber.BitString);\n\tder.writeByte(0x00);\n\n\tder.startSequence();\n\tder.writeBuffer(key.part.n.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.e.data, asn1.Ber.Integer);\n\tder.endSequence();\n\n\tder.endSequence();\n}\n\nfunction writePkcs8DSAPrivate(key, der) {\n\tder.startSequence();\n\tder.writeBuffer(key.part.p.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.q.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.g.data, asn1.Ber.Integer);\n\tder.endSequence();\n\n\tder.endSequence();\n\n\tder.startSequence(asn1.Ber.OctetString);\n\tder.writeBuffer(key.part.x.data, asn1.Ber.Integer);\n\tder.endSequence();\n}\n\nfunction writePkcs8DSAPublic(key, der) {\n\tder.startSequence();\n\tder.writeBuffer(key.part.p.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.q.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.g.data, asn1.Ber.Integer);\n\tder.endSequence();\n\tder.endSequence();\n\n\tder.startSequence(asn1.Ber.BitString);\n\tder.writeByte(0x00);\n\tder.writeBuffer(key.part.y.data, asn1.Ber.Integer);\n\tder.endSequence();\n}\n\nfunction writeECDSACurve(key, der) {\n\tvar curve = algs.curves[key.curve];\n\tif (curve.pkcs8oid) {\n\t\t/* This one has a name in pkcs#8, so just write the oid */\n\t\tder.writeOID(curve.pkcs8oid);\n\n\t} else {\n\t\t// ECParameters sequence\n\t\tder.startSequence();\n\n\t\tvar version = Buffer.from([1]);\n\t\tder.writeBuffer(version, asn1.Ber.Integer);\n\n\t\t// FieldID sequence\n\t\tder.startSequence();\n\t\tder.writeOID('1.2.840.10045.1.1'); // prime-field\n\t\tder.writeBuffer(curve.p, asn1.Ber.Integer);\n\t\tder.endSequence();\n\n\t\t// Curve sequence\n\t\tder.startSequence();\n\t\tvar a = curve.p;\n\t\tif (a[0] === 0x0)\n\t\t\ta = a.slice(1);\n\t\tder.writeBuffer(a, asn1.Ber.OctetString);\n\t\tder.writeBuffer(curve.b, asn1.Ber.OctetString);\n\t\tder.writeBuffer(curve.s, asn1.Ber.BitString);\n\t\tder.endSequence();\n\n\t\tder.writeBuffer(curve.G, asn1.Ber.OctetString);\n\t\tder.writeBuffer(curve.n, asn1.Ber.Integer);\n\t\tvar h = curve.h;\n\t\tif (!h) {\n\t\t\th = Buffer.from([1]);\n\t\t}\n\t\tder.writeBuffer(h, asn1.Ber.Integer);\n\n\t\t// ECParameters\n\t\tder.endSequence();\n\t}\n}\n\nfunction writePkcs8ECDSAPublic(key, der) {\n\twriteECDSACurve(key, der);\n\tder.endSequence();\n\n\tvar Q = utils.ecNormalize(key.part.Q.data, true);\n\tder.writeBuffer(Q, asn1.Ber.BitString);\n}\n\nfunction writePkcs8ECDSAPrivate(key, der) {\n\twriteECDSACurve(key, der);\n\tder.endSequence();\n\n\tder.startSequence(asn1.Ber.OctetString);\n\tder.startSequence();\n\n\tvar version = Buffer.from([1]);\n\tder.writeBuffer(version, asn1.Ber.Integer);\n\n\tder.writeBuffer(key.part.d.data, asn1.Ber.OctetString);\n\n\tder.startSequence(0xa1);\n\tvar Q = utils.ecNormalize(key.part.Q.data, true);\n\tder.writeBuffer(Q, asn1.Ber.BitString);\n\tder.endSequence();\n\n\tder.endSequence();\n\tder.endSequence();\n}\n\nfunction writePkcs8EdDSAPublic(key, der) {\n\tder.endSequence();\n\n\tutils.writeBitString(der, key.part.A.data);\n}\n\nfunction writePkcs8EdDSAPrivate(key, der) {\n\tder.endSequence();\n\n\tvar k = utils.mpNormalize(key.part.k.data, true);\n\tder.startSequence(asn1.Ber.OctetString);\n\tder.writeBuffer(k, asn1.Ber.OctetString);\n\tder.endSequence();\n}\n","// Copyright 2015 Joyent, Inc.\n\nmodule.exports = SSHBuffer;\n\nvar assert = require('assert-plus');\nvar Buffer = require('safer-buffer').Buffer;\n\nfunction SSHBuffer(opts) {\n\tassert.object(opts, 'options');\n\tif (opts.buffer !== undefined)\n\t\tassert.buffer(opts.buffer, 'options.buffer');\n\n\tthis._size = opts.buffer ? opts.buffer.length : 1024;\n\tthis._buffer = opts.buffer || Buffer.alloc(this._size);\n\tthis._offset = 0;\n}\n\nSSHBuffer.prototype.toBuffer = function () {\n\treturn (this._buffer.slice(0, this._offset));\n};\n\nSSHBuffer.prototype.atEnd = function () {\n\treturn (this._offset >= this._buffer.length);\n};\n\nSSHBuffer.prototype.remainder = function () {\n\treturn (this._buffer.slice(this._offset));\n};\n\nSSHBuffer.prototype.skip = function (n) {\n\tthis._offset += n;\n};\n\nSSHBuffer.prototype.expand = function () {\n\tthis._size *= 2;\n\tvar buf = Buffer.alloc(this._size);\n\tthis._buffer.copy(buf, 0);\n\tthis._buffer = buf;\n};\n\nSSHBuffer.prototype.readPart = function () {\n\treturn ({data: this.readBuffer()});\n};\n\nSSHBuffer.prototype.readBuffer = function () {\n\tvar len = this._buffer.readUInt32BE(this._offset);\n\tthis._offset += 4;\n\tassert.ok(this._offset + len <= this._buffer.length,\n\t 'length out of bounds at +0x' + this._offset.toString(16) +\n\t ' (data truncated?)');\n\tvar buf = this._buffer.slice(this._offset, this._offset + len);\n\tthis._offset += len;\n\treturn (buf);\n};\n\nSSHBuffer.prototype.readString = function () {\n\treturn (this.readBuffer().toString());\n};\n\nSSHBuffer.prototype.readCString = function () {\n\tvar offset = this._offset;\n\twhile (offset < this._buffer.length &&\n\t this._buffer[offset] !== 0x00)\n\t\toffset++;\n\tassert.ok(offset < this._buffer.length, 'c string does not terminate');\n\tvar str = this._buffer.slice(this._offset, offset).toString();\n\tthis._offset = offset + 1;\n\treturn (str);\n};\n\nSSHBuffer.prototype.readInt = function () {\n\tvar v = this._buffer.readUInt32BE(this._offset);\n\tthis._offset += 4;\n\treturn (v);\n};\n\nSSHBuffer.prototype.readInt64 = function () {\n\tassert.ok(this._offset + 8 < this._buffer.length,\n\t 'buffer not long enough to read Int64');\n\tvar v = this._buffer.slice(this._offset, this._offset + 8);\n\tthis._offset += 8;\n\treturn (v);\n};\n\nSSHBuffer.prototype.readChar = function () {\n\tvar v = this._buffer[this._offset++];\n\treturn (v);\n};\n\nSSHBuffer.prototype.writeBuffer = function (buf) {\n\twhile (this._offset + 4 + buf.length > this._size)\n\t\tthis.expand();\n\tthis._buffer.writeUInt32BE(buf.length, this._offset);\n\tthis._offset += 4;\n\tbuf.copy(this._buffer, this._offset);\n\tthis._offset += buf.length;\n};\n\nSSHBuffer.prototype.writeString = function (str) {\n\tthis.writeBuffer(Buffer.from(str, 'utf8'));\n};\n\nSSHBuffer.prototype.writeCString = function (str) {\n\twhile (this._offset + 1 + str.length > this._size)\n\t\tthis.expand();\n\tthis._buffer.write(str, this._offset);\n\tthis._offset += str.length;\n\tthis._buffer[this._offset++] = 0;\n};\n\nSSHBuffer.prototype.writeInt = function (v) {\n\twhile (this._offset + 4 > this._size)\n\t\tthis.expand();\n\tthis._buffer.writeUInt32BE(v, this._offset);\n\tthis._offset += 4;\n};\n\nSSHBuffer.prototype.writeInt64 = function (v) {\n\tassert.buffer(v, 'value');\n\tif (v.length > 8) {\n\t\tvar lead = v.slice(0, v.length - 8);\n\t\tfor (var i = 0; i < lead.length; ++i) {\n\t\t\tassert.strictEqual(lead[i], 0,\n\t\t\t 'must fit in 64 bits of precision');\n\t\t}\n\t\tv = v.slice(v.length - 8, v.length);\n\t}\n\twhile (this._offset + 8 > this._size)\n\t\tthis.expand();\n\tv.copy(this._buffer, this._offset);\n\tthis._offset += 8;\n};\n\nSSHBuffer.prototype.writeChar = function (v) {\n\twhile (this._offset + 1 > this._size)\n\t\tthis.expand();\n\tthis._buffer[this._offset++] = v;\n};\n\nSSHBuffer.prototype.writePart = function (p) {\n\tthis.writeBuffer(p.data);\n};\n\nSSHBuffer.prototype.write = function (buf) {\n\twhile (this._offset + buf.length > this._size)\n\t\tthis.expand();\n\tbuf.copy(this._buffer, this._offset);\n\tthis._offset += buf.length;\n};\n","// Copyright 2017 Joyent, Inc.\n\nmodule.exports = Identity;\n\nvar assert = require('assert-plus');\nvar algs = require('./algs');\nvar crypto = require('crypto');\nvar Fingerprint = require('./fingerprint');\nvar Signature = require('./signature');\nvar errs = require('./errors');\nvar util = require('util');\nvar utils = require('./utils');\nvar asn1 = require('asn1');\nvar Buffer = require('safer-buffer').Buffer;\n\n/*JSSTYLED*/\nvar DNS_NAME_RE = /^([*]|[a-z0-9][a-z0-9\\-]{0,62})(?:\\.([*]|[a-z0-9][a-z0-9\\-]{0,62}))*$/i;\n\nvar oids = {};\noids.cn = '2.5.4.3';\noids.o = '2.5.4.10';\noids.ou = '2.5.4.11';\noids.l = '2.5.4.7';\noids.s = '2.5.4.8';\noids.c = '2.5.4.6';\noids.sn = '2.5.4.4';\noids.postalCode = '2.5.4.17';\noids.serialNumber = '2.5.4.5';\noids.street = '2.5.4.9';\noids.x500UniqueIdentifier = '2.5.4.45';\noids.role = '2.5.4.72';\noids.telephoneNumber = '2.5.4.20';\noids.description = '2.5.4.13';\noids.dc = '0.9.2342.19200300.100.1.25';\noids.uid = '0.9.2342.19200300.100.1.1';\noids.mail = '0.9.2342.19200300.100.1.3';\noids.title = '2.5.4.12';\noids.gn = '2.5.4.42';\noids.initials = '2.5.4.43';\noids.pseudonym = '2.5.4.65';\noids.emailAddress = '1.2.840.113549.1.9.1';\n\nvar unoids = {};\nObject.keys(oids).forEach(function (k) {\n\tunoids[oids[k]] = k;\n});\n\nfunction Identity(opts) {\n\tvar self = this;\n\tassert.object(opts, 'options');\n\tassert.arrayOfObject(opts.components, 'options.components');\n\tthis.components = opts.components;\n\tthis.componentLookup = {};\n\tthis.components.forEach(function (c) {\n\t\tif (c.name && !c.oid)\n\t\t\tc.oid = oids[c.name];\n\t\tif (c.oid && !c.name)\n\t\t\tc.name = unoids[c.oid];\n\t\tif (self.componentLookup[c.name] === undefined)\n\t\t\tself.componentLookup[c.name] = [];\n\t\tself.componentLookup[c.name].push(c);\n\t});\n\tif (this.componentLookup.cn && this.componentLookup.cn.length > 0) {\n\t\tthis.cn = this.componentLookup.cn[0].value;\n\t}\n\tassert.optionalString(opts.type, 'options.type');\n\tif (opts.type === undefined) {\n\t\tif (this.components.length === 1 &&\n\t\t this.componentLookup.cn &&\n\t\t this.componentLookup.cn.length === 1 &&\n\t\t this.componentLookup.cn[0].value.match(DNS_NAME_RE)) {\n\t\t\tthis.type = 'host';\n\t\t\tthis.hostname = this.componentLookup.cn[0].value;\n\n\t\t} else if (this.componentLookup.dc &&\n\t\t this.components.length === this.componentLookup.dc.length) {\n\t\t\tthis.type = 'host';\n\t\t\tthis.hostname = this.componentLookup.dc.map(\n\t\t\t function (c) {\n\t\t\t\treturn (c.value);\n\t\t\t}).join('.');\n\n\t\t} else if (this.componentLookup.uid &&\n\t\t this.components.length ===\n\t\t this.componentLookup.uid.length) {\n\t\t\tthis.type = 'user';\n\t\t\tthis.uid = this.componentLookup.uid[0].value;\n\n\t\t} else if (this.componentLookup.cn &&\n\t\t this.componentLookup.cn.length === 1 &&\n\t\t this.componentLookup.cn[0].value.match(DNS_NAME_RE)) {\n\t\t\tthis.type = 'host';\n\t\t\tthis.hostname = this.componentLookup.cn[0].value;\n\n\t\t} else if (this.componentLookup.uid &&\n\t\t this.componentLookup.uid.length === 1) {\n\t\t\tthis.type = 'user';\n\t\t\tthis.uid = this.componentLookup.uid[0].value;\n\n\t\t} else if (this.componentLookup.mail &&\n\t\t this.componentLookup.mail.length === 1) {\n\t\t\tthis.type = 'email';\n\t\t\tthis.email = this.componentLookup.mail[0].value;\n\n\t\t} else if (this.componentLookup.cn &&\n\t\t this.componentLookup.cn.length === 1) {\n\t\t\tthis.type = 'user';\n\t\t\tthis.uid = this.componentLookup.cn[0].value;\n\n\t\t} else {\n\t\t\tthis.type = 'unknown';\n\t\t}\n\t} else {\n\t\tthis.type = opts.type;\n\t\tif (this.type === 'host')\n\t\t\tthis.hostname = opts.hostname;\n\t\telse if (this.type === 'user')\n\t\t\tthis.uid = opts.uid;\n\t\telse if (this.type === 'email')\n\t\t\tthis.email = opts.email;\n\t\telse\n\t\t\tthrow (new Error('Unknown type ' + this.type));\n\t}\n}\n\nIdentity.prototype.toString = function () {\n\treturn (this.components.map(function (c) {\n\t\tvar n = c.name.toUpperCase();\n\t\t/*JSSTYLED*/\n\t\tn = n.replace(/=/g, '\\\\=');\n\t\tvar v = c.value;\n\t\t/*JSSTYLED*/\n\t\tv = v.replace(/,/g, '\\\\,');\n\t\treturn (n + '=' + v);\n\t}).join(', '));\n};\n\nIdentity.prototype.get = function (name, asArray) {\n\tassert.string(name, 'name');\n\tvar arr = this.componentLookup[name];\n\tif (arr === undefined || arr.length === 0)\n\t\treturn (undefined);\n\tif (!asArray && arr.length > 1)\n\t\tthrow (new Error('Multiple values for attribute ' + name));\n\tif (!asArray)\n\t\treturn (arr[0].value);\n\treturn (arr.map(function (c) {\n\t\treturn (c.value);\n\t}));\n};\n\nIdentity.prototype.toArray = function (idx) {\n\treturn (this.components.map(function (c) {\n\t\treturn ({\n\t\t\tname: c.name,\n\t\t\tvalue: c.value\n\t\t});\n\t}));\n};\n\n/*\n * These are from X.680 -- PrintableString allowed chars are in section 37.4\n * table 8. Spec for IA5Strings is \"1,6 + SPACE + DEL\" where 1 refers to\n * ISO IR #001 (standard ASCII control characters) and 6 refers to ISO IR #006\n * (the basic ASCII character set).\n */\n/* JSSTYLED */\nvar NOT_PRINTABLE = /[^a-zA-Z0-9 '(),+.\\/:=?-]/;\n/* JSSTYLED */\nvar NOT_IA5 = /[^\\x00-\\x7f]/;\n\nIdentity.prototype.toAsn1 = function (der, tag) {\n\tder.startSequence(tag);\n\tthis.components.forEach(function (c) {\n\t\tder.startSequence(asn1.Ber.Constructor | asn1.Ber.Set);\n\t\tder.startSequence();\n\t\tder.writeOID(c.oid);\n\t\t/*\n\t\t * If we fit in a PrintableString, use that. Otherwise use an\n\t\t * IA5String or UTF8String.\n\t\t *\n\t\t * If this identity was parsed from a DN, use the ASN.1 types\n\t\t * from the original representation (otherwise this might not\n\t\t * be a full match for the original in some validators).\n\t\t */\n\t\tif (c.asn1type === asn1.Ber.Utf8String ||\n\t\t c.value.match(NOT_IA5)) {\n\t\t\tvar v = Buffer.from(c.value, 'utf8');\n\t\t\tder.writeBuffer(v, asn1.Ber.Utf8String);\n\n\t\t} else if (c.asn1type === asn1.Ber.IA5String ||\n\t\t c.value.match(NOT_PRINTABLE)) {\n\t\t\tder.writeString(c.value, asn1.Ber.IA5String);\n\n\t\t} else {\n\t\t\tvar type = asn1.Ber.PrintableString;\n\t\t\tif (c.asn1type !== undefined)\n\t\t\t\ttype = c.asn1type;\n\t\t\tder.writeString(c.value, type);\n\t\t}\n\t\tder.endSequence();\n\t\tder.endSequence();\n\t});\n\tder.endSequence();\n};\n\nfunction globMatch(a, b) {\n\tif (a === '**' || b === '**')\n\t\treturn (true);\n\tvar aParts = a.split('.');\n\tvar bParts = b.split('.');\n\tif (aParts.length !== bParts.length)\n\t\treturn (false);\n\tfor (var i = 0; i < aParts.length; ++i) {\n\t\tif (aParts[i] === '*' || bParts[i] === '*')\n\t\t\tcontinue;\n\t\tif (aParts[i] !== bParts[i])\n\t\t\treturn (false);\n\t}\n\treturn (true);\n}\n\nIdentity.prototype.equals = function (other) {\n\tif (!Identity.isIdentity(other, [1, 0]))\n\t\treturn (false);\n\tif (other.components.length !== this.components.length)\n\t\treturn (false);\n\tfor (var i = 0; i < this.components.length; ++i) {\n\t\tif (this.components[i].oid !== other.components[i].oid)\n\t\t\treturn (false);\n\t\tif (!globMatch(this.components[i].value,\n\t\t other.components[i].value)) {\n\t\t\treturn (false);\n\t\t}\n\t}\n\treturn (true);\n};\n\nIdentity.forHost = function (hostname) {\n\tassert.string(hostname, 'hostname');\n\treturn (new Identity({\n\t\ttype: 'host',\n\t\thostname: hostname,\n\t\tcomponents: [ { name: 'cn', value: hostname } ]\n\t}));\n};\n\nIdentity.forUser = function (uid) {\n\tassert.string(uid, 'uid');\n\treturn (new Identity({\n\t\ttype: 'user',\n\t\tuid: uid,\n\t\tcomponents: [ { name: 'uid', value: uid } ]\n\t}));\n};\n\nIdentity.forEmail = function (email) {\n\tassert.string(email, 'email');\n\treturn (new Identity({\n\t\ttype: 'email',\n\t\temail: email,\n\t\tcomponents: [ { name: 'mail', value: email } ]\n\t}));\n};\n\nIdentity.parseDN = function (dn) {\n\tassert.string(dn, 'dn');\n\tvar parts = [''];\n\tvar idx = 0;\n\tvar rem = dn;\n\twhile (rem.length > 0) {\n\t\tvar m;\n\t\t/*JSSTYLED*/\n\t\tif ((m = /^,/.exec(rem)) !== null) {\n\t\t\tparts[++idx] = '';\n\t\t\trem = rem.slice(m[0].length);\n\t\t/*JSSTYLED*/\n\t\t} else if ((m = /^\\\\,/.exec(rem)) !== null) {\n\t\t\tparts[idx] += ',';\n\t\t\trem = rem.slice(m[0].length);\n\t\t/*JSSTYLED*/\n\t\t} else if ((m = /^\\\\./.exec(rem)) !== null) {\n\t\t\tparts[idx] += m[0];\n\t\t\trem = rem.slice(m[0].length);\n\t\t/*JSSTYLED*/\n\t\t} else if ((m = /^[^\\\\,]+/.exec(rem)) !== null) {\n\t\t\tparts[idx] += m[0];\n\t\t\trem = rem.slice(m[0].length);\n\t\t} else {\n\t\t\tthrow (new Error('Failed to parse DN'));\n\t\t}\n\t}\n\tvar cmps = parts.map(function (c) {\n\t\tc = c.trim();\n\t\tvar eqPos = c.indexOf('=');\n\t\twhile (eqPos > 0 && c.charAt(eqPos - 1) === '\\\\')\n\t\t\teqPos = c.indexOf('=', eqPos + 1);\n\t\tif (eqPos === -1) {\n\t\t\tthrow (new Error('Failed to parse DN'));\n\t\t}\n\t\t/*JSSTYLED*/\n\t\tvar name = c.slice(0, eqPos).toLowerCase().replace(/\\\\=/g, '=');\n\t\tvar value = c.slice(eqPos + 1);\n\t\treturn ({ name: name, value: value });\n\t});\n\treturn (new Identity({ components: cmps }));\n};\n\nIdentity.fromArray = function (components) {\n\tassert.arrayOfObject(components, 'components');\n\tcomponents.forEach(function (cmp) {\n\t\tassert.object(cmp, 'component');\n\t\tassert.string(cmp.name, 'component.name');\n\t\tif (!Buffer.isBuffer(cmp.value) &&\n\t\t !(typeof (cmp.value) === 'string')) {\n\t\t\tthrow (new Error('Invalid component value'));\n\t\t}\n\t});\n\treturn (new Identity({ components: components }));\n};\n\nIdentity.parseAsn1 = function (der, top) {\n\tvar components = [];\n\tder.readSequence(top);\n\tvar end = der.offset + der.length;\n\twhile (der.offset < end) {\n\t\tder.readSequence(asn1.Ber.Constructor | asn1.Ber.Set);\n\t\tvar after = der.offset + der.length;\n\t\tder.readSequence();\n\t\tvar oid = der.readOID();\n\t\tvar type = der.peek();\n\t\tvar value;\n\t\tswitch (type) {\n\t\tcase asn1.Ber.PrintableString:\n\t\tcase asn1.Ber.IA5String:\n\t\tcase asn1.Ber.OctetString:\n\t\tcase asn1.Ber.T61String:\n\t\t\tvalue = der.readString(type);\n\t\t\tbreak;\n\t\tcase asn1.Ber.Utf8String:\n\t\t\tvalue = der.readString(type, true);\n\t\t\tvalue = value.toString('utf8');\n\t\t\tbreak;\n\t\tcase asn1.Ber.CharacterString:\n\t\tcase asn1.Ber.BMPString:\n\t\t\tvalue = der.readString(type, true);\n\t\t\tvalue = value.toString('utf16le');\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthrow (new Error('Unknown asn1 type ' + type));\n\t\t}\n\t\tcomponents.push({ oid: oid, asn1type: type, value: value });\n\t\tder._offset = after;\n\t}\n\tder._offset = end;\n\treturn (new Identity({\n\t\tcomponents: components\n\t}));\n};\n\nIdentity.isIdentity = function (obj, ver) {\n\treturn (utils.isCompatible(obj, Identity, ver));\n};\n\n/*\n * API versions for Identity:\n * [1,0] -- initial ver\n */\nIdentity.prototype._sshpkApiVersion = [1, 0];\n\nIdentity._oldVersionDetect = function (obj) {\n\treturn ([1, 0]);\n};\n","const assert = require(\"assert\");\nconst GenUtils = require(\"../../common/GenUtils\");\nconst MoneroOutput = require(\"../../daemon/model/MoneroOutput\");\n\n/**\n * Models a Monero output with wallet extensions.\n * \n * @class\n * @extends {MoneroOutput}\n */\nclass MoneroOutputWallet extends MoneroOutput {\n \n /**\n * Construct the model.\n * \n * @param {MoneroOutputWallet|object} state is existing state to initialize from (optional)\n */\n constructor(state) {\n super(state);\n }\n \n getAccountIndex() {\n return this.state.accountIndex;\n }\n\n setAccountIndex(accountIndex) {\n this.state.accountIndex = accountIndex;\n return this;\n }\n\n getSubaddressIndex() {\n return this.state.subaddressIndex;\n }\n\n setSubaddressIndex(subaddressIndex) {\n this.state.subaddressIndex = subaddressIndex;\n return this;\n }\n \n isSpent() {\n return this.state.isSpent;\n }\n\n setIsSpent(isSpent) {\n this.state.isSpent = isSpent;\n return this;\n }\n \n /**\n * Indicates if this output has been deemed 'malicious' and will therefore\n * not be spent by the wallet.\n * \n * @return Boolean is whether or not this output is frozen\n */\n isFrozen() {\n return this.state.isFrozen;\n }\n\n setIsFrozen(isFrozen) {\n this.state.isFrozen = isFrozen;\n return this;\n }\n \n isLocked() {\n if (this.getTx() === undefined) return undefined;\n return this.getTx().isLocked();\n }\n \n copy() {\n return new MoneroOutputWallet(this.toJson());\n }\n \n toJson() {\n let json = Object.assign({}, this.state, super.toJson());\n delete json.tx;\n return json;\n }\n \n /**\n * Updates this output by merging the latest information from the given\n * output.\n * \n * Merging can modify or build references to the output given so it\n * should not be re-used or it should be copied before calling this method.\n * \n * @param output is the output to merge into this one\n */\n merge(output) {\n assert(output instanceof MoneroOutputWallet);\n if (this === output) return;\n super.merge(output);\n this.setAccountIndex(GenUtils.reconcile(this.getAccountIndex(), output.getAccountIndex()));\n this.setSubaddressIndex(GenUtils.reconcile(this.getSubaddressIndex(), output.getSubaddressIndex()));\n this.setIsSpent(GenUtils.reconcile(this.isSpent(), output.isSpent(), {resolveTrue: true})); // output can become spent\n this.setIsFrozen(GenUtils.reconcile(this.isFrozen(), output.isFrozen()));\n return this;\n }\n \n toString(indent) {\n let str = super.toString(indent) + \"\\n\"\n str += GenUtils.kvLine(\"Account index\", this.getAccountIndex(), indent);\n str += GenUtils.kvLine(\"Subaddress index\", this.getSubaddressIndex(), indent);\n str += GenUtils.kvLine(\"Is spent\", this.isSpent(), indent);\n str += GenUtils.kvLine(\"Is frozen\", this.isFrozen(), indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n\nmodule.exports = MoneroOutputWallet;","const assert = require(\"assert\");\nconst GenUtils = require(\"../../common/GenUtils\");\nconst MoneroTxWallet = require(\"./MoneroTxWallet\");\nconst MoneroUtils = require(\"../../common/MoneroUtils\");\n\n/**\n * Groups transactions who share common hex data which is needed in order to\n * sign and submit the transactions.\n * \n * For example, multisig transactions created from createTxs() share a common\n * hex string which is needed in order to sign and submit the multisig\n * transactions.\n */\nclass MoneroTxSet {\n \n constructor(state) {\n \n // initialize internal state\n if (!state) state = {};\n else if (typeof state === \"object\") state = Object.assign({}, state);\n else throw new MoneroError(\"state must be JavaScript object\");\n this.state = state;\n \n // deserialize txs\n if (state.txs) {\n for (let i = 0; i < state.txs.length; i++) {\n if (!(state.txs[i] instanceof MoneroTxWallet)) state.txs[i] = new MoneroTxWallet(state.txs[i]);\n state.txs[i].setTxSet(this);\n }\n }\n }\n \n toJson() {\n let json = Object.assign({}, this.state); // copy state\n if (this.getTxs()) {\n json.txs = [];\n for (let tx of this.getTxs()) json.txs.push(tx.toJson());\n }\n return json;\n }\n\n getTxs() {\n return this.state.txs;\n }\n\n setTxs(txs) {\n this.state.txs = txs;\n return this;\n }\n \n getMultisigTxHex() {\n return this.state.multisigTxHex;\n }\n \n setMultisigTxHex(multisigTxHex) {\n this.state.multisigTxHex = multisigTxHex;\n return this;\n }\n \n getUnsignedTxHex() {\n return this.state.unsignedTxHex;\n }\n \n setUnsignedTxHex(unsignedTxHex) {\n this.state.unsignedTxHex = unsignedTxHex;\n return this;\n }\n \n getSignedTxHex() {\n return this.state.signedTxHex;\n }\n \n setSignedTxHex(signedTxHex) {\n this.state.signedTxHex = signedTxHex;\n return this;\n }\n \n merge(txSet) {\n assert(txSet instanceof MoneroTxSet);\n if (this === txSet) return this;\n \n // merge sets\n this.setMultisigTxHex(GenUtils.reconcile(this.getMultisigTxHex(), txSet.getMultisigTxHex()));\n this.setUnsignedTxHex(GenUtils.reconcile(this.getUnsignedTxHex(), txSet.getUnsignedTxHex()));\n this.setSignedTxHex(GenUtils.reconcile(this.getSignedTxHex(), txSet.getSignedTxHex()));\n \n // merge txs\n if (txSet.getTxs() !== undefined) {\n for (let tx of txSet.getTxs()) {\n tx.setTxSet(this);\n MoneroUtils.mergeTx(this.getTxs(), tx);\n }\n }\n\n return this;\n }\n \n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.kvLine(\"Multisig tx hex: \", getMultisigTxHex(), indent);\n str += GenUtils.kvLine(\"Unsigned tx hex: \", getUnsignedTxHex(), indent);\n str += GenUtils.kvLine(\"Signed tx hex: \", getSignedTxHex(), indent);\n if (getTxs() !== undefined) {\n str += GenUtils.kvLine(\"Txs\", \"\", indent);\n for (let tx of getTxs()) {\n str += tx.toString(indent + 1) + \"\\n\";\n }\n }\n return str;\n }\n}\n\nmodule.exports = MoneroTxSet;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\nconst GenUtils = require(\"../../common/GenUtils\");\n\n/**\n * Monero subaddress model.\n */\nclass MoneroSubaddress {\n \n constructor(stateOrAddress) {\n if (stateOrAddress === undefined || typeof stateOrAddress === \"string\") {\n this.state = {};\n this.setAddress(stateOrAddress);\n } else {\n this.state = stateOrAddress;\n if (this.state.balance !== undefined && !(this.state.balance instanceof BigInteger)) this.state.balance = BigInteger.parse(this.state.balance);\n if (this.state.unlockedBalance !== undefined && !(this.state.unlockedBalance instanceof BigInteger)) this.state.unlockedBalance = BigInteger.parse(this.state.unlockedBalance);\n }\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (json.balance) json.balance = json.balance.toString();\n if (json.unlockedBalance) json.unlockedBalance = json.unlockedBalance.toString();\n return json;\n }\n \n getAccountIndex() {\n return this.state.accountIndex;\n }\n\n setAccountIndex(accountIndex) {\n this.state.accountIndex = accountIndex;\n return this;\n }\n\n getIndex() {\n return this.state.index;\n }\n\n setIndex(index) {\n this.state.index = index;\n return this;\n }\n \n getAddress() {\n return this.state.address;\n }\n\n setAddress(address) {\n this.state.address = address;\n return this;\n }\n\n getLabel() {\n return this.state.label;\n }\n\n setLabel(label) {\n this.state.label = label;\n return this;\n }\n\n getBalance() {\n return this.state.balance;\n }\n\n setBalance(balance) {\n this.state.balance = balance;\n return this;\n }\n\n getUnlockedBalance() {\n return this.state.unlockedBalance;\n }\n\n setUnlockedBalance(unlockedBalance) {\n this.state.unlockedBalance = unlockedBalance;\n return this;\n }\n\n getNumUnspentOutputs() {\n return this.state.numUnspentOutputs;\n }\n\n setNumUnspentOutputs(numUnspentOutputs) {\n this.state.numUnspentOutputs = numUnspentOutputs;\n return this;\n }\n\n isUsed() {\n return this.state.isUsed;\n }\n\n setIsUsed(isUsed) {\n this.state.isUsed = isUsed;\n return this;\n }\n\n getNumBlocksToUnlock() {\n return this.state.numBlocksToUnlock;\n }\n\n setNumBlocksToUnlock(numBlocksToUnlock) {\n this.state.numBlocksToUnlock = numBlocksToUnlock;\n return this;\n }\n \n toString(indent) {\n let str = \"\";\n str += GenUtils.kvLine(\"Account index\", this.getAccountIndex(), indent);\n str += GenUtils.kvLine(\"Subaddress index\", this.getIndex(), indent);\n str += GenUtils.kvLine(\"Address\", this.getAddress(), indent);\n str += GenUtils.kvLine(\"Label\", this.getLabel(), indent);\n str += GenUtils.kvLine(\"Balance\", this.getBalance(), indent);\n str += GenUtils.kvLine(\"Unlocked balance\", this.getUnlockedBalance(), indent);\n str += GenUtils.kvLine(\"Num unspent outputs\", this.getNumUnspentOutputs(), indent);\n str += GenUtils.kvLine(\"Is used\", this.isUsed(), indent);\n str += GenUtils.kvLine(\"Num blocks to unlock\", this.isUsed(), indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n\nmodule.exports = MoneroSubaddress;","const assert = require(\"assert\");\nconst MoneroDestination = require(\"./MoneroDestination\");\nconst MoneroError = require(\"../../common/MoneroError\");\n\n/**\n * Configures a transaction to send, sweep, or create a payment URI.\n */\nclass MoneroTxConfig {\n \n /**\n *

Generic request to transfer funds from a wallet.

\n * \n *

Examples:

\n * \n * \n * let config1 = new MoneroTxConfig({
\n *    accountIndex: 0,
\n *    address: \"59aZULsUF3YN...\",
\n *    amount: new BigInteger(\"500000\"),
\n *    priority: MoneroTxPriority.NORMAL,
\n *    relay: true
\n * });

\n *
\n * \n * @param {MoneroTxConfig|object} config - configures the transaction to create (optional)\n * @param {string} config.address - single destination address\n * @param {BigInteger} config.amount - single destination amount\n * @param {int} config.accountIndex - source account index to transfer funds from\n * @param {int} config.subaddressIndex - source subaddress index to transfer funds from\n * @param {int[]} config.subaddressIndices - source subaddress indices to transfer funds from\n * @param {boolean} config.relay - relay the transaction to peers to commit to the blockchain\n * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL)\n * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx\n * @param {string} config.paymentId - transaction payment ID\n * @param {int} config.unlockHeight - minimum height for the transaction to unlock (default 0)\n * @param {string} config.note - transaction note saved locally with the wallet\n * @param {string} config.recipientName - recipient name saved locally with the wallet\n * @param {boolean} config.canSplit - allow funds to be transferred using multiple transactions\n * @param {BigInteger} config.belowAmount - for sweep requests, include outputs below this amount when sweeping wallet, account, subaddress, or all unlocked funds \n * @param {boolean} config.sweepEachSubaddress - for sweep requests, sweep each subaddress individually instead of together if true\n * @param {string} config.keyImage - key image to sweep (ignored except in sweepOutput() requests)\n */\n constructor(config) {\n if (arguments.length > 1) throw new MoneroError(\"MoneroTxConfig can be constructed with only one parameter but was given \" + arguments.length)\n \n // initialize internal state\n if (!config) this.state = {};\n else if (config instanceof MoneroTxConfig) this.state = config.toJson();\n else if (typeof config === \"object\") this.state = Object.assign({}, config);\n else throw new MoneroError(\"Invalid argument given to MoneroTxConfig: \" + typeof config);\n \n // deserialize if necessary\n if (this.state.destinations) {\n assert(this.state.address === undefined && this.state.amount === undefined, \"Tx configuration may specify destinations or an address/amount but not both\");\n this.setDestinations(this.state.destinations.map(destination => destination instanceof MoneroDestination ? destination : new MoneroDestination(destination)));\n }\n \n // alias 'address' and 'amount' to single destination to support e.g. createTx({address: \"...\"})\n if (this.state.address || this.state.amount) {\n assert(!this.state.destinations, \"Tx configuration may specify destinations or an address/amount but not both\");\n this.setDestinations([new MoneroDestination(this.state.address, this.state.amount)]);\n delete this.state.address;\n delete this.state.amount;\n }\n \n // alias 'subaddressIndex' to subaddress indices\n if (this.state.subaddressIndex !== undefined) {\n this.setSubaddressIndices([this.state.subaddressIndex]);\n delete this.state.subaddressIndex;\n }\n }\n \n copy() {\n return new MoneroTxConfig(this);\n }\n \n toJson() {\n let json = Object.assign({}, this.state); // copy state\n if (this.getDestinations()) {\n json.destinations = [];\n for (let destination of this.getDestinations()) json.destinations.push(destination.toJson());\n }\n if (this.getFee()) json.fee = this.getFee().toString();\n if (this.getBelowAmount()) json.belowAmount = this.getBelowAmount().toString();\n return json;\n }\n \n /**\n * Set the address of a single-destination configuration.\n * \n * @param {string} address - the address to set for the single destination\n * @return {MoneroTxConfig} this configuration for chaining\n */\n setAddress(address) {\n if (this.state.destinations !== undefined && this.state.destinations.length > 1) throw new MoneroError(\"Cannot set address because MoneroTxConfig already has multiple destinations\");\n if (this.state.destinations === undefined || this.state.destinations.length === 0) this.addDestination(new MoneroDestination(address));\n else this.state.destinations[0].setAddress(address);\n return this;\n }\n \n /**\n * Get the address of a single-destination configuration.\n * \n * @return {string} the address of the single destination\n */\n getAddress() {\n if (this.state.destinations === undefined || this.state.destinations.length !== 1) throw new MoneroError(\"Cannot get address because MoneroTxConfig does not have exactly one destination\");\n return this.state.destinations[0].getAddress();\n }\n \n /**\n * Set the amount of a single-destination configuration.\n * \n * @param {BigInteger} amount - the amount to set for the single destination\n * @return {MoneroTxConfig} this configuration for chaining\n */\n setAmount(amount) {\n if (this.state.destinations !== undefined && this.state.destinations.length > 1) throw new MoneroError(\"Cannot set amount because MoneroTxConfig already has multiple destinations\");\n if (this.state.destinations === undefined || this.state.destinations.length === 0) this.addDestination(new MoneroDestination(undefined, amount));\n else this.state.destinations[0].setAmount(amount);\n return this;\n }\n \n /**\n * Get the amount of a single-destination configuration.\n * \n * @return {BigInteger} the amount of the single destination\n */\n getAmount() {\n if (this.state.destinations === undefined || this.state.destinations.length !== 1) throw new MoneroError(\"Cannot get amount because MoneroTxConfig does not have exactly one destination\");\n return this.state.destinations[0].getAmount();\n }\n \n addDestination(destination) {\n assert(destination instanceof MoneroDestination);\n if (this.state.destinations === undefined) this.state.destinations = [];\n this.state.destinations.push(destination);\n return this;\n }\n \n getDestinations() {\n return this.state.destinations;\n }\n \n setDestinations(destinations) {\n if (arguments.length > 1) destinations = Array.from(arguments);\n this.state.destinations = destinations;\n return this;\n }\n \n setDestination(destination) {\n return this.setDestinations(destination ? [destination] : destination);\n }\n \n getPaymentId() {\n return this.state.paymentId;\n }\n \n setPaymentId(paymentId) {\n this.state.paymentId = paymentId;\n return this;\n }\n \n getPriority() {\n return this.state.priority;\n }\n \n setPriority(priority) {\n this.state.priority = priority;\n return this;\n }\n \n getFee() {\n return this.state.fee;\n }\n \n setFee(fee) {\n this.state.fee = fee;\n return this;\n }\n \n getAccountIndex() {\n return this.state.accountIndex;\n }\n \n setAccountIndex(accountIndex) {\n this.state.accountIndex = accountIndex;\n return this;\n }\n \n setSubaddressIndex(subaddressIndex) {\n this.setSubaddressIndices([subaddressIndex]);\n return this;\n }\n \n getSubaddressIndices() {\n return this.state.subaddressIndices;\n }\n \n setSubaddressIndices(subaddressIndices) {\n if (arguments.length > 1) subaddressIndices = Array.from(arguments);\n this.state.subaddressIndices = subaddressIndices;\n return this;\n }\n \n getUnlockHeight() {\n return this.state.unlockHeight;\n }\n \n setUnlockHeight(unlockHeight) {\n this.state.unlockHeight = unlockHeight;\n return this;\n }\n \n getRelay() {\n return this.state.relay;\n }\n \n setRelay(relay) {\n this.state.relay = relay;\n return this;\n }\n \n getCanSplit() {\n return this.state.canSplit;\n }\n \n setCanSplit(canSplit) {\n this.state.canSplit = canSplit;\n return this;\n }\n \n getNote() {\n return this.state.note;\n }\n \n setNote(note) {\n this.state.note = note;\n return this;\n }\n \n getRecipientName() {\n return this.state.recipientName;\n }\n \n setRecipientName(recipientName) {\n this.state.recipientName = recipientName;\n return this;\n }\n \n // --------------------------- SPECIFIC TO SWEEP ----------------------------\n \n getBelowAmount() {\n return this.state.belowAmount;\n }\n \n setBelowAmount(belowAmount) {\n this.state.belowAmount = belowAmount;\n return this;\n }\n \n getSweepEachSubaddress() {\n return this.state.sweepEachSubaddress;\n }\n \n setSweepEachSubaddress(sweepEachSubaddress) {\n this.state.sweepEachSubaddress = sweepEachSubaddress;\n return this;\n }\n \n /**\n * Get the key image hex of the output to sweep.\n * \n * return {string} is the key image hex of the output to sweep\n */\n getKeyImage() {\n return this.state.keyImage;\n }\n \n /**\n * Set the key image hex of the output to sweep.\n * \n * @param {string} keyImage is the key image hex of the output to sweep\n */\n setKeyImage(keyImage) {\n this.state.keyImage = keyImage;\n return this;\n }\n}\n\nmodule.exports = MoneroTxConfig","'use strict';\n\nvar utils = require('./utils')\n , pathm = require('path')\n , fs = require('./fileSystem');\n\nvar wrapSuccess = utils.wrapSuccess\n , wrapFail = utils.wrapFail;\n\nexports.getFsInstance = fs.getInstance;\n\nexports.appendFile = function(path, data, callback) {\n fs.writeFile(path, data, callback, true);\n};\n\n\nexports.writeFile = function(path, data, callback) {\n fs.writeFile(path, data, callback, false);\n};\n\n\nexports.readFile = function(path, opts, callback) {\n if (typeof opts === 'function') {\n callback = opts;\n opts = {\n encoding: 'utf8'\n };\n }\n\n var success = wrapSuccess(callback)\n , fail = wrapFail(callback);\n\n fs.getFile(path, function(err, fileEntry) {\n fileEntry.file(function(file) {\n var reader = new FileReader();\n\n reader.onloadend = function(evt) {\n success(evt.target.result);\n };\n\n reader.onerror = function(err) {\n fail(err);\n };\n\n if (opts.encoding === 'utf8') {\n reader.readAsText(file);\n } else {\n reader.readAsDataURL(file);\n }\n }, fail);\n });\n};\n\n\nexports.unlink = function(path, callback) {\n var success = wrapSuccess(callback)\n , fail = wrapFail(callback);\n\n fs.getFile(path, function(err, file) {\n if (err) {\n fail(err);\n } else {\n file.remove(success, fail);\n }\n });\n};\n\n\nexports.readdir = function(path, callback) {\n var success = wrapSuccess(callback)\n , fail = wrapFail(callback);\n\n fs.getDirectory(path, function(err, dirEntry) {\n if (err) {\n fail(err);\n } else {\n var directoryReader = dirEntry.createReader();\n directoryReader.readEntries(success, fail);\n }\n });\n};\n\n\nexports.mkdir = function(path, callback) {\n var newFolderName = pathm.basename(path)\n , basePath = pathm.dirname(path)\n , success = utils.wrapSuccess(callback)\n , fail = utils.wrapFail(callback)\n , opts = {\n create: true,\n exclusive: true\n };\n\n if (basePath === '.') {\n fs.getDirectory(newFolderName, opts, callback);\n } else {\n fs.getDirectory(basePath, function (err, dir) {\n if (err) {\n callback(err, null);\n } else {\n dir.getDirectory(newFolderName, opts, success, fail);\n }\n });\n }\n};\n\n\n/**\n * Remove a directory.\n * The FileSystem API expects directories to be empty but returns a\n * non-informative error on Android and possibly iOS so we check here\n * to ensure users know why directory deletes might fail.\n * @param {String} path\n * @param {Function} callback\n */\nexports.rmdir = function(path, callback) {\n var success = wrapSuccess(callback)\n , fail = wrapFail(callback);\n\n this.readdir(path, function(err, list) {\n if (err) {\n fail(err);\n } else if (list && list.length > 0) {\n fail('ENOTEMPTY: Directory must be empty');\n } else {\n fs.getDirectory(path, function(err, dirEntry) {\n if (err) {\n fail(err);\n } else {\n dirEntry.remove(success, fail);\n }\n });\n }\n });\n};\n\n\nexports.exists = function(path, callback) {\n var fail = wrapFail(callback);\n\n fs.getFile(path, {\n // Don't create the file, just look for it\n create: false\n }, function(err) {\n // See https://www.chromestatus.com/features/6687420359639040.\n if (err &&\n ((window.FileError && err.code === 1) ||\n (err.name === 'NotFoundError'))) { // NOT FOUND\n // If the file isn't found we don't want an error, pass false!\n callback(false);\n } else if (err) {\n // An actual error occured, pass it along\n fail(err);\n } else {\n callback(true);\n }\n });\n};\n\n\nexports.stat = function(path, callback) {\n var success = wrapSuccess(callback)\n , fail = wrapFail(callback)\n , fn = fs.getFile;\n\n // TODO: Perhaps check for folder AND file instead, use whichever exists\n if (utils.isDirectory(path)) {\n fn = fs.getDirectory;\n }\n\n fn(path, function(err, res) {\n if (err) {\n fail(err);\n } else {\n res.getMetadata(success, fail);\n }\n });\n};\n\n\n/**\n * Initialise the file system component for use.\n * @param {Number} [quota]\n * @param {Function} callback\n */\nexports.init = function(bytes, callback) {\n fs.init(bytes, function(err) {\n if (err) {\n callback(err, null);\n } else {\n fs.getInstance(function(err /*, instance */) {\n callback(err, null);\n });\n }\n });\n};\n","\n/**\n * Module exports.\n */\n\nmodule.exports = deprecate;\n\n/**\n * Mark that a method should not be used.\n * Returns a modified function which warns once by default.\n *\n * If `localStorage.noDeprecation = true` is set, then it is a no-op.\n *\n * If `localStorage.throwDeprecation = true` is set, then deprecated functions\n * will throw an Error when invoked.\n *\n * If `localStorage.traceDeprecation = true` is set, then deprecated functions\n * will invoke `console.trace()` instead of `console.error()`.\n *\n * @param {Function} fn - the function to deprecate\n * @param {String} msg - the string to print to the console when `fn` is invoked\n * @returns {Function} a new \"deprecated\" version of `fn`\n * @api public\n */\n\nfunction deprecate (fn, msg) {\n if (config('noDeprecation')) {\n return fn;\n }\n\n var warned = false;\n function deprecated() {\n if (!warned) {\n if (config('throwDeprecation')) {\n throw new Error(msg);\n } else if (config('traceDeprecation')) {\n console.trace(msg);\n } else {\n console.warn(msg);\n }\n warned = true;\n }\n return fn.apply(this, arguments);\n }\n\n return deprecated;\n}\n\n/**\n * Checks `localStorage` for boolean values for the given `name`.\n *\n * @param {String} name\n * @returns {Boolean}\n * @api private\n */\n\nfunction config (name) {\n // accessing global.localStorage can trigger a DOMException in sandboxed iframes\n try {\n if (!global.localStorage) return false;\n } catch (_) {\n return false;\n }\n var val = global.localStorage[name];\n if (null == val) return false;\n return String(val).toLowerCase() === 'true';\n}\n","// based on the aes implimentation in triple sec\n// https://github.com/keybase/triplesec\n// which is in turn based on the one from crypto-js\n// https://code.google.com/p/crypto-js/\n\nvar Buffer = require('safe-buffer').Buffer\n\nfunction asUInt32Array (buf) {\n if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf)\n\n var len = (buf.length / 4) | 0\n var out = new Array(len)\n\n for (var i = 0; i < len; i++) {\n out[i] = buf.readUInt32BE(i * 4)\n }\n\n return out\n}\n\nfunction scrubVec (v) {\n for (var i = 0; i < v.length; v++) {\n v[i] = 0\n }\n}\n\nfunction cryptBlock (M, keySchedule, SUB_MIX, SBOX, nRounds) {\n var SUB_MIX0 = SUB_MIX[0]\n var SUB_MIX1 = SUB_MIX[1]\n var SUB_MIX2 = SUB_MIX[2]\n var SUB_MIX3 = SUB_MIX[3]\n\n var s0 = M[0] ^ keySchedule[0]\n var s1 = M[1] ^ keySchedule[1]\n var s2 = M[2] ^ keySchedule[2]\n var s3 = M[3] ^ keySchedule[3]\n var t0, t1, t2, t3\n var ksRow = 4\n\n for (var round = 1; round < nRounds; round++) {\n t0 = SUB_MIX0[s0 >>> 24] ^ SUB_MIX1[(s1 >>> 16) & 0xff] ^ SUB_MIX2[(s2 >>> 8) & 0xff] ^ SUB_MIX3[s3 & 0xff] ^ keySchedule[ksRow++]\n t1 = SUB_MIX0[s1 >>> 24] ^ SUB_MIX1[(s2 >>> 16) & 0xff] ^ SUB_MIX2[(s3 >>> 8) & 0xff] ^ SUB_MIX3[s0 & 0xff] ^ keySchedule[ksRow++]\n t2 = SUB_MIX0[s2 >>> 24] ^ SUB_MIX1[(s3 >>> 16) & 0xff] ^ SUB_MIX2[(s0 >>> 8) & 0xff] ^ SUB_MIX3[s1 & 0xff] ^ keySchedule[ksRow++]\n t3 = SUB_MIX0[s3 >>> 24] ^ SUB_MIX1[(s0 >>> 16) & 0xff] ^ SUB_MIX2[(s1 >>> 8) & 0xff] ^ SUB_MIX3[s2 & 0xff] ^ keySchedule[ksRow++]\n s0 = t0\n s1 = t1\n s2 = t2\n s3 = t3\n }\n\n t0 = ((SBOX[s0 >>> 24] << 24) | (SBOX[(s1 >>> 16) & 0xff] << 16) | (SBOX[(s2 >>> 8) & 0xff] << 8) | SBOX[s3 & 0xff]) ^ keySchedule[ksRow++]\n t1 = ((SBOX[s1 >>> 24] << 24) | (SBOX[(s2 >>> 16) & 0xff] << 16) | (SBOX[(s3 >>> 8) & 0xff] << 8) | SBOX[s0 & 0xff]) ^ keySchedule[ksRow++]\n t2 = ((SBOX[s2 >>> 24] << 24) | (SBOX[(s3 >>> 16) & 0xff] << 16) | (SBOX[(s0 >>> 8) & 0xff] << 8) | SBOX[s1 & 0xff]) ^ keySchedule[ksRow++]\n t3 = ((SBOX[s3 >>> 24] << 24) | (SBOX[(s0 >>> 16) & 0xff] << 16) | (SBOX[(s1 >>> 8) & 0xff] << 8) | SBOX[s2 & 0xff]) ^ keySchedule[ksRow++]\n t0 = t0 >>> 0\n t1 = t1 >>> 0\n t2 = t2 >>> 0\n t3 = t3 >>> 0\n\n return [t0, t1, t2, t3]\n}\n\n// AES constants\nvar RCON = [0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]\nvar G = (function () {\n // Compute double table\n var d = new Array(256)\n for (var j = 0; j < 256; j++) {\n if (j < 128) {\n d[j] = j << 1\n } else {\n d[j] = (j << 1) ^ 0x11b\n }\n }\n\n var SBOX = []\n var INV_SBOX = []\n var SUB_MIX = [[], [], [], []]\n var INV_SUB_MIX = [[], [], [], []]\n\n // Walk GF(2^8)\n var x = 0\n var xi = 0\n for (var i = 0; i < 256; ++i) {\n // Compute sbox\n var sx = xi ^ (xi << 1) ^ (xi << 2) ^ (xi << 3) ^ (xi << 4)\n sx = (sx >>> 8) ^ (sx & 0xff) ^ 0x63\n SBOX[x] = sx\n INV_SBOX[sx] = x\n\n // Compute multiplication\n var x2 = d[x]\n var x4 = d[x2]\n var x8 = d[x4]\n\n // Compute sub bytes, mix columns tables\n var t = (d[sx] * 0x101) ^ (sx * 0x1010100)\n SUB_MIX[0][x] = (t << 24) | (t >>> 8)\n SUB_MIX[1][x] = (t << 16) | (t >>> 16)\n SUB_MIX[2][x] = (t << 8) | (t >>> 24)\n SUB_MIX[3][x] = t\n\n // Compute inv sub bytes, inv mix columns tables\n t = (x8 * 0x1010101) ^ (x4 * 0x10001) ^ (x2 * 0x101) ^ (x * 0x1010100)\n INV_SUB_MIX[0][sx] = (t << 24) | (t >>> 8)\n INV_SUB_MIX[1][sx] = (t << 16) | (t >>> 16)\n INV_SUB_MIX[2][sx] = (t << 8) | (t >>> 24)\n INV_SUB_MIX[3][sx] = t\n\n if (x === 0) {\n x = xi = 1\n } else {\n x = x2 ^ d[d[d[x8 ^ x2]]]\n xi ^= d[d[xi]]\n }\n }\n\n return {\n SBOX: SBOX,\n INV_SBOX: INV_SBOX,\n SUB_MIX: SUB_MIX,\n INV_SUB_MIX: INV_SUB_MIX\n }\n})()\n\nfunction AES (key) {\n this._key = asUInt32Array(key)\n this._reset()\n}\n\nAES.blockSize = 4 * 4\nAES.keySize = 256 / 8\nAES.prototype.blockSize = AES.blockSize\nAES.prototype.keySize = AES.keySize\nAES.prototype._reset = function () {\n var keyWords = this._key\n var keySize = keyWords.length\n var nRounds = keySize + 6\n var ksRows = (nRounds + 1) * 4\n\n var keySchedule = []\n for (var k = 0; k < keySize; k++) {\n keySchedule[k] = keyWords[k]\n }\n\n for (k = keySize; k < ksRows; k++) {\n var t = keySchedule[k - 1]\n\n if (k % keySize === 0) {\n t = (t << 8) | (t >>> 24)\n t =\n (G.SBOX[t >>> 24] << 24) |\n (G.SBOX[(t >>> 16) & 0xff] << 16) |\n (G.SBOX[(t >>> 8) & 0xff] << 8) |\n (G.SBOX[t & 0xff])\n\n t ^= RCON[(k / keySize) | 0] << 24\n } else if (keySize > 6 && k % keySize === 4) {\n t =\n (G.SBOX[t >>> 24] << 24) |\n (G.SBOX[(t >>> 16) & 0xff] << 16) |\n (G.SBOX[(t >>> 8) & 0xff] << 8) |\n (G.SBOX[t & 0xff])\n }\n\n keySchedule[k] = keySchedule[k - keySize] ^ t\n }\n\n var invKeySchedule = []\n for (var ik = 0; ik < ksRows; ik++) {\n var ksR = ksRows - ik\n var tt = keySchedule[ksR - (ik % 4 ? 0 : 4)]\n\n if (ik < 4 || ksR <= 4) {\n invKeySchedule[ik] = tt\n } else {\n invKeySchedule[ik] =\n G.INV_SUB_MIX[0][G.SBOX[tt >>> 24]] ^\n G.INV_SUB_MIX[1][G.SBOX[(tt >>> 16) & 0xff]] ^\n G.INV_SUB_MIX[2][G.SBOX[(tt >>> 8) & 0xff]] ^\n G.INV_SUB_MIX[3][G.SBOX[tt & 0xff]]\n }\n }\n\n this._nRounds = nRounds\n this._keySchedule = keySchedule\n this._invKeySchedule = invKeySchedule\n}\n\nAES.prototype.encryptBlockRaw = function (M) {\n M = asUInt32Array(M)\n return cryptBlock(M, this._keySchedule, G.SUB_MIX, G.SBOX, this._nRounds)\n}\n\nAES.prototype.encryptBlock = function (M) {\n var out = this.encryptBlockRaw(M)\n var buf = Buffer.allocUnsafe(16)\n buf.writeUInt32BE(out[0], 0)\n buf.writeUInt32BE(out[1], 4)\n buf.writeUInt32BE(out[2], 8)\n buf.writeUInt32BE(out[3], 12)\n return buf\n}\n\nAES.prototype.decryptBlock = function (M) {\n M = asUInt32Array(M)\n\n // swap\n var m1 = M[1]\n M[1] = M[3]\n M[3] = m1\n\n var out = cryptBlock(M, this._invKeySchedule, G.INV_SUB_MIX, G.INV_SBOX, this._nRounds)\n var buf = Buffer.allocUnsafe(16)\n buf.writeUInt32BE(out[0], 0)\n buf.writeUInt32BE(out[3], 4)\n buf.writeUInt32BE(out[2], 8)\n buf.writeUInt32BE(out[1], 12)\n return buf\n}\n\nAES.prototype.scrub = function () {\n scrubVec(this._keySchedule)\n scrubVec(this._invKeySchedule)\n scrubVec(this._key)\n}\n\nmodule.exports.AES = AES\n","var Buffer = require('safe-buffer').Buffer\nvar MD5 = require('md5.js')\n\n/* eslint-disable camelcase */\nfunction EVP_BytesToKey (password, salt, keyBits, ivLen) {\n if (!Buffer.isBuffer(password)) password = Buffer.from(password, 'binary')\n if (salt) {\n if (!Buffer.isBuffer(salt)) salt = Buffer.from(salt, 'binary')\n if (salt.length !== 8) throw new RangeError('salt should be Buffer with 8 byte length')\n }\n\n var keyLen = keyBits / 8\n var key = Buffer.alloc(keyLen)\n var iv = Buffer.alloc(ivLen || 0)\n var tmp = Buffer.alloc(0)\n\n while (keyLen > 0 || ivLen > 0) {\n var hash = new MD5()\n hash.update(tmp)\n hash.update(password)\n if (salt) hash.update(salt)\n tmp = hash.digest()\n\n var used = 0\n\n if (keyLen > 0) {\n var keyStart = key.length - keyLen\n used = Math.min(keyLen, tmp.length)\n tmp.copy(key, keyStart, 0, used)\n keyLen -= used\n }\n\n if (used < tmp.length && ivLen > 0) {\n var ivStart = iv.length - ivLen\n var length = Math.min(ivLen, tmp.length - used)\n tmp.copy(iv, ivStart, used, used + length)\n ivLen -= length\n }\n }\n\n tmp.fill(0)\n return { key: key, iv: iv }\n}\n\nmodule.exports = EVP_BytesToKey\n","'use strict';\n\nvar BN = require('bn.js');\nvar utils = require('../utils');\nvar getNAF = utils.getNAF;\nvar getJSF = utils.getJSF;\nvar assert = utils.assert;\n\nfunction BaseCurve(type, conf) {\n this.type = type;\n this.p = new BN(conf.p, 16);\n\n // Use Montgomery, when there is no fast reduction for the prime\n this.red = conf.prime ? BN.red(conf.prime) : BN.mont(this.p);\n\n // Useful for many curves\n this.zero = new BN(0).toRed(this.red);\n this.one = new BN(1).toRed(this.red);\n this.two = new BN(2).toRed(this.red);\n\n // Curve configuration, optional\n this.n = conf.n && new BN(conf.n, 16);\n this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed);\n\n // Temporary arrays\n this._wnafT1 = new Array(4);\n this._wnafT2 = new Array(4);\n this._wnafT3 = new Array(4);\n this._wnafT4 = new Array(4);\n\n this._bitLength = this.n ? this.n.bitLength() : 0;\n\n // Generalized Greg Maxwell's trick\n var adjustCount = this.n && this.p.div(this.n);\n if (!adjustCount || adjustCount.cmpn(100) > 0) {\n this.redN = null;\n } else {\n this._maxwellTrick = true;\n this.redN = this.n.toRed(this.red);\n }\n}\nmodule.exports = BaseCurve;\n\nBaseCurve.prototype.point = function point() {\n throw new Error('Not implemented');\n};\n\nBaseCurve.prototype.validate = function validate() {\n throw new Error('Not implemented');\n};\n\nBaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) {\n assert(p.precomputed);\n var doubles = p._getDoubles();\n\n var naf = getNAF(k, 1, this._bitLength);\n var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1);\n I /= 3;\n\n // Translate into more windowed form\n var repr = [];\n for (var j = 0; j < naf.length; j += doubles.step) {\n var nafW = 0;\n for (var k = j + doubles.step - 1; k >= j; k--)\n nafW = (nafW << 1) + naf[k];\n repr.push(nafW);\n }\n\n var a = this.jpoint(null, null, null);\n var b = this.jpoint(null, null, null);\n for (var i = I; i > 0; i--) {\n for (var j = 0; j < repr.length; j++) {\n var nafW = repr[j];\n if (nafW === i)\n b = b.mixedAdd(doubles.points[j]);\n else if (nafW === -i)\n b = b.mixedAdd(doubles.points[j].neg());\n }\n a = a.add(b);\n }\n return a.toP();\n};\n\nBaseCurve.prototype._wnafMul = function _wnafMul(p, k) {\n var w = 4;\n\n // Precompute window\n var nafPoints = p._getNAFPoints(w);\n w = nafPoints.wnd;\n var wnd = nafPoints.points;\n\n // Get NAF form\n var naf = getNAF(k, w, this._bitLength);\n\n // Add `this`*(N+1) for every w-NAF index\n var acc = this.jpoint(null, null, null);\n for (var i = naf.length - 1; i >= 0; i--) {\n // Count zeroes\n for (var k = 0; i >= 0 && naf[i] === 0; i--)\n k++;\n if (i >= 0)\n k++;\n acc = acc.dblp(k);\n\n if (i < 0)\n break;\n var z = naf[i];\n assert(z !== 0);\n if (p.type === 'affine') {\n // J +- P\n if (z > 0)\n acc = acc.mixedAdd(wnd[(z - 1) >> 1]);\n else\n acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg());\n } else {\n // J +- J\n if (z > 0)\n acc = acc.add(wnd[(z - 1) >> 1]);\n else\n acc = acc.add(wnd[(-z - 1) >> 1].neg());\n }\n }\n return p.type === 'affine' ? acc.toP() : acc;\n};\n\nBaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW,\n points,\n coeffs,\n len,\n jacobianResult) {\n var wndWidth = this._wnafT1;\n var wnd = this._wnafT2;\n var naf = this._wnafT3;\n\n // Fill all arrays\n var max = 0;\n for (var i = 0; i < len; i++) {\n var p = points[i];\n var nafPoints = p._getNAFPoints(defW);\n wndWidth[i] = nafPoints.wnd;\n wnd[i] = nafPoints.points;\n }\n\n // Comb small window NAFs\n for (var i = len - 1; i >= 1; i -= 2) {\n var a = i - 1;\n var b = i;\n if (wndWidth[a] !== 1 || wndWidth[b] !== 1) {\n naf[a] = getNAF(coeffs[a], wndWidth[a], this._bitLength);\n naf[b] = getNAF(coeffs[b], wndWidth[b], this._bitLength);\n max = Math.max(naf[a].length, max);\n max = Math.max(naf[b].length, max);\n continue;\n }\n\n var comb = [\n points[a], /* 1 */\n null, /* 3 */\n null, /* 5 */\n points[b] /* 7 */\n ];\n\n // Try to avoid Projective points, if possible\n if (points[a].y.cmp(points[b].y) === 0) {\n comb[1] = points[a].add(points[b]);\n comb[2] = points[a].toJ().mixedAdd(points[b].neg());\n } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) {\n comb[1] = points[a].toJ().mixedAdd(points[b]);\n comb[2] = points[a].add(points[b].neg());\n } else {\n comb[1] = points[a].toJ().mixedAdd(points[b]);\n comb[2] = points[a].toJ().mixedAdd(points[b].neg());\n }\n\n var index = [\n -3, /* -1 -1 */\n -1, /* -1 0 */\n -5, /* -1 1 */\n -7, /* 0 -1 */\n 0, /* 0 0 */\n 7, /* 0 1 */\n 5, /* 1 -1 */\n 1, /* 1 0 */\n 3 /* 1 1 */\n ];\n\n var jsf = getJSF(coeffs[a], coeffs[b]);\n max = Math.max(jsf[0].length, max);\n naf[a] = new Array(max);\n naf[b] = new Array(max);\n for (var j = 0; j < max; j++) {\n var ja = jsf[0][j] | 0;\n var jb = jsf[1][j] | 0;\n\n naf[a][j] = index[(ja + 1) * 3 + (jb + 1)];\n naf[b][j] = 0;\n wnd[a] = comb;\n }\n }\n\n var acc = this.jpoint(null, null, null);\n var tmp = this._wnafT4;\n for (var i = max; i >= 0; i--) {\n var k = 0;\n\n while (i >= 0) {\n var zero = true;\n for (var j = 0; j < len; j++) {\n tmp[j] = naf[j][i] | 0;\n if (tmp[j] !== 0)\n zero = false;\n }\n if (!zero)\n break;\n k++;\n i--;\n }\n if (i >= 0)\n k++;\n acc = acc.dblp(k);\n if (i < 0)\n break;\n\n for (var j = 0; j < len; j++) {\n var z = tmp[j];\n var p;\n if (z === 0)\n continue;\n else if (z > 0)\n p = wnd[j][(z - 1) >> 1];\n else if (z < 0)\n p = wnd[j][(-z - 1) >> 1].neg();\n\n if (p.type === 'affine')\n acc = acc.mixedAdd(p);\n else\n acc = acc.add(p);\n }\n }\n // Zeroify references\n for (var i = 0; i < len; i++)\n wnd[i] = null;\n\n if (jacobianResult)\n return acc;\n else\n return acc.toP();\n};\n\nfunction BasePoint(curve, type) {\n this.curve = curve;\n this.type = type;\n this.precomputed = null;\n}\nBaseCurve.BasePoint = BasePoint;\n\nBasePoint.prototype.eq = function eq(/*other*/) {\n throw new Error('Not implemented');\n};\n\nBasePoint.prototype.validate = function validate() {\n return this.curve.validate(this);\n};\n\nBaseCurve.prototype.decodePoint = function decodePoint(bytes, enc) {\n bytes = utils.toArray(bytes, enc);\n\n var len = this.p.byteLength();\n\n // uncompressed, hybrid-odd, hybrid-even\n if ((bytes[0] === 0x04 || bytes[0] === 0x06 || bytes[0] === 0x07) &&\n bytes.length - 1 === 2 * len) {\n if (bytes[0] === 0x06)\n assert(bytes[bytes.length - 1] % 2 === 0);\n else if (bytes[0] === 0x07)\n assert(bytes[bytes.length - 1] % 2 === 1);\n\n var res = this.point(bytes.slice(1, 1 + len),\n bytes.slice(1 + len, 1 + 2 * len));\n\n return res;\n } else if ((bytes[0] === 0x02 || bytes[0] === 0x03) &&\n bytes.length - 1 === len) {\n return this.pointFromX(bytes.slice(1, 1 + len), bytes[0] === 0x03);\n }\n throw new Error('Unknown point format');\n};\n\nBasePoint.prototype.encodeCompressed = function encodeCompressed(enc) {\n return this.encode(enc, true);\n};\n\nBasePoint.prototype._encode = function _encode(compact) {\n var len = this.curve.p.byteLength();\n var x = this.getX().toArray('be', len);\n\n if (compact)\n return [ this.getY().isEven() ? 0x02 : 0x03 ].concat(x);\n\n return [ 0x04 ].concat(x, this.getY().toArray('be', len)) ;\n};\n\nBasePoint.prototype.encode = function encode(enc, compact) {\n return utils.encode(this._encode(compact), enc);\n};\n\nBasePoint.prototype.precompute = function precompute(power) {\n if (this.precomputed)\n return this;\n\n var precomputed = {\n doubles: null,\n naf: null,\n beta: null\n };\n precomputed.naf = this._getNAFPoints(8);\n precomputed.doubles = this._getDoubles(4, power);\n precomputed.beta = this._getBeta();\n this.precomputed = precomputed;\n\n return this;\n};\n\nBasePoint.prototype._hasDoubles = function _hasDoubles(k) {\n if (!this.precomputed)\n return false;\n\n var doubles = this.precomputed.doubles;\n if (!doubles)\n return false;\n\n return doubles.points.length >= Math.ceil((k.bitLength() + 1) / doubles.step);\n};\n\nBasePoint.prototype._getDoubles = function _getDoubles(step, power) {\n if (this.precomputed && this.precomputed.doubles)\n return this.precomputed.doubles;\n\n var doubles = [ this ];\n var acc = this;\n for (var i = 0; i < power; i += step) {\n for (var j = 0; j < step; j++)\n acc = acc.dbl();\n doubles.push(acc);\n }\n return {\n step: step,\n points: doubles\n };\n};\n\nBasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) {\n if (this.precomputed && this.precomputed.naf)\n return this.precomputed.naf;\n\n var res = [ this ];\n var max = (1 << wnd) - 1;\n var dbl = max === 1 ? null : this.dbl();\n for (var i = 1; i < max; i++)\n res[i] = res[i - 1].add(dbl);\n return {\n wnd: wnd,\n points: res\n };\n};\n\nBasePoint.prototype._getBeta = function _getBeta() {\n return null;\n};\n\nBasePoint.prototype.dblp = function dblp(k) {\n var r = this;\n for (var i = 0; i < k; i++)\n r = r.dbl();\n return r;\n};\n","var asn1 = require('./asn1')\nvar aesid = require('./aesid.json')\nvar fixProc = require('./fixProc')\nvar ciphers = require('browserify-aes')\nvar compat = require('pbkdf2')\nvar Buffer = require('safe-buffer').Buffer\nmodule.exports = parseKeys\n\nfunction parseKeys (buffer) {\n var password\n if (typeof buffer === 'object' && !Buffer.isBuffer(buffer)) {\n password = buffer.passphrase\n buffer = buffer.key\n }\n if (typeof buffer === 'string') {\n buffer = Buffer.from(buffer)\n }\n\n var stripped = fixProc(buffer, password)\n\n var type = stripped.tag\n var data = stripped.data\n var subtype, ndata\n switch (type) {\n case 'CERTIFICATE':\n ndata = asn1.certificate.decode(data, 'der').tbsCertificate.subjectPublicKeyInfo\n // falls through\n case 'PUBLIC KEY':\n if (!ndata) {\n ndata = asn1.PublicKey.decode(data, 'der')\n }\n subtype = ndata.algorithm.algorithm.join('.')\n switch (subtype) {\n case '1.2.840.113549.1.1.1':\n return asn1.RSAPublicKey.decode(ndata.subjectPublicKey.data, 'der')\n case '1.2.840.10045.2.1':\n ndata.subjectPrivateKey = ndata.subjectPublicKey\n return {\n type: 'ec',\n data: ndata\n }\n case '1.2.840.10040.4.1':\n ndata.algorithm.params.pub_key = asn1.DSAparam.decode(ndata.subjectPublicKey.data, 'der')\n return {\n type: 'dsa',\n data: ndata.algorithm.params\n }\n default: throw new Error('unknown key id ' + subtype)\n }\n throw new Error('unknown key type ' + type)\n case 'ENCRYPTED PRIVATE KEY':\n data = asn1.EncryptedPrivateKey.decode(data, 'der')\n data = decrypt(data, password)\n // falls through\n case 'PRIVATE KEY':\n ndata = asn1.PrivateKey.decode(data, 'der')\n subtype = ndata.algorithm.algorithm.join('.')\n switch (subtype) {\n case '1.2.840.113549.1.1.1':\n return asn1.RSAPrivateKey.decode(ndata.subjectPrivateKey, 'der')\n case '1.2.840.10045.2.1':\n return {\n curve: ndata.algorithm.curve,\n privateKey: asn1.ECPrivateKey.decode(ndata.subjectPrivateKey, 'der').privateKey\n }\n case '1.2.840.10040.4.1':\n ndata.algorithm.params.priv_key = asn1.DSAparam.decode(ndata.subjectPrivateKey, 'der')\n return {\n type: 'dsa',\n params: ndata.algorithm.params\n }\n default: throw new Error('unknown key id ' + subtype)\n }\n throw new Error('unknown key type ' + type)\n case 'RSA PUBLIC KEY':\n return asn1.RSAPublicKey.decode(data, 'der')\n case 'RSA PRIVATE KEY':\n return asn1.RSAPrivateKey.decode(data, 'der')\n case 'DSA PRIVATE KEY':\n return {\n type: 'dsa',\n params: asn1.DSAPrivateKey.decode(data, 'der')\n }\n case 'EC PRIVATE KEY':\n data = asn1.ECPrivateKey.decode(data, 'der')\n return {\n curve: data.parameters.value,\n privateKey: data.privateKey\n }\n default: throw new Error('unknown key type ' + type)\n }\n}\nparseKeys.signature = asn1.signature\nfunction decrypt (data, password) {\n var salt = data.algorithm.decrypt.kde.kdeparams.salt\n var iters = parseInt(data.algorithm.decrypt.kde.kdeparams.iters.toString(), 10)\n var algo = aesid[data.algorithm.decrypt.cipher.algo.join('.')]\n var iv = data.algorithm.decrypt.cipher.iv\n var cipherText = data.subjectPrivateKey\n var keylen = parseInt(algo.split('-')[1], 10) / 8\n var key = compat.pbkdf2Sync(password, salt, iters, keylen, 'sha1')\n var cipher = ciphers.createDecipheriv(algo, key, iv)\n var out = []\n out.push(cipher.update(cipherText))\n out.push(cipher.final())\n return Buffer.concat(out)\n}\n","/*\nCopyright 2013 Sleepless Software Inc. All rights reserved.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to\ndeal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or\nsell copies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\nIN THE SOFTWARE. \n*/\n\n// yes, I know this seems stupid, but I have my reasons.\n\nvar net = require(\"net\")\nfor(k in net)\n\tglobal[k] = net[k]\n\n","'use strict';\n\nexports.decode = exports.parse = require('./decode');\nexports.encode = exports.stringify = require('./encode');\n","var http = require('http')\nvar url = require('url')\n\nvar https = module.exports\n\nfor (var key in http) {\n if (http.hasOwnProperty(key)) https[key] = http[key]\n}\n\nhttps.request = function (params, cb) {\n params = validateParams(params)\n return http.request.call(this, params, cb)\n}\n\nhttps.get = function (params, cb) {\n params = validateParams(params)\n return http.get.call(this, params, cb)\n}\n\nfunction validateParams (params) {\n if (typeof params === 'string') {\n params = url.parse(params)\n }\n if (!params.protocol) {\n params.protocol = 'https:'\n }\n if (params.protocol !== 'https:') {\n throw new Error('Protocol \"' + params.protocol + '\" not supported. Expected \"https:\"')\n }\n return params\n}\n","'use strict';\n\n\nvar TYPED_OK = (typeof Uint8Array !== 'undefined') &&\n (typeof Uint16Array !== 'undefined') &&\n (typeof Int32Array !== 'undefined');\n\nfunction _has(obj, key) {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\nexports.assign = function (obj /*from1, from2, from3, ...*/) {\n var sources = Array.prototype.slice.call(arguments, 1);\n while (sources.length) {\n var source = sources.shift();\n if (!source) { continue; }\n\n if (typeof source !== 'object') {\n throw new TypeError(source + 'must be non-object');\n }\n\n for (var p in source) {\n if (_has(source, p)) {\n obj[p] = source[p];\n }\n }\n }\n\n return obj;\n};\n\n\n// reduce buffer size, avoiding mem copy\nexports.shrinkBuf = function (buf, size) {\n if (buf.length === size) { return buf; }\n if (buf.subarray) { return buf.subarray(0, size); }\n buf.length = size;\n return buf;\n};\n\n\nvar fnTyped = {\n arraySet: function (dest, src, src_offs, len, dest_offs) {\n if (src.subarray && dest.subarray) {\n dest.set(src.subarray(src_offs, src_offs + len), dest_offs);\n return;\n }\n // Fallback to ordinary array\n for (var i = 0; i < len; i++) {\n dest[dest_offs + i] = src[src_offs + i];\n }\n },\n // Join array of chunks to single array.\n flattenChunks: function (chunks) {\n var i, l, len, pos, chunk, result;\n\n // calculate data length\n len = 0;\n for (i = 0, l = chunks.length; i < l; i++) {\n len += chunks[i].length;\n }\n\n // join chunks\n result = new Uint8Array(len);\n pos = 0;\n for (i = 0, l = chunks.length; i < l; i++) {\n chunk = chunks[i];\n result.set(chunk, pos);\n pos += chunk.length;\n }\n\n return result;\n }\n};\n\nvar fnUntyped = {\n arraySet: function (dest, src, src_offs, len, dest_offs) {\n for (var i = 0; i < len; i++) {\n dest[dest_offs + i] = src[src_offs + i];\n }\n },\n // Join array of chunks to single array.\n flattenChunks: function (chunks) {\n return [].concat.apply([], chunks);\n }\n};\n\n\n// Enable/Disable typed arrays use, for testing\n//\nexports.setTyped = function (on) {\n if (on) {\n exports.Buf8 = Uint8Array;\n exports.Buf16 = Uint16Array;\n exports.Buf32 = Int32Array;\n exports.assign(exports, fnTyped);\n } else {\n exports.Buf8 = Array;\n exports.Buf16 = Array;\n exports.Buf32 = Array;\n exports.assign(exports, fnUntyped);\n }\n};\n\nexports.setTyped(TYPED_OK);\n","// Copyright 2012 Joyent, Inc. All rights reserved.\n\nvar assert = require('assert-plus');\nvar sshpk = require('sshpk');\nvar util = require('util');\n\nvar HASH_ALGOS = {\n 'sha1': true,\n 'sha256': true,\n 'sha512': true\n};\n\nvar PK_ALGOS = {\n 'rsa': true,\n 'dsa': true,\n 'ecdsa': true\n};\n\nfunction HttpSignatureError(message, caller) {\n if (Error.captureStackTrace)\n Error.captureStackTrace(this, caller || HttpSignatureError);\n\n this.message = message;\n this.name = caller.name;\n}\nutil.inherits(HttpSignatureError, Error);\n\nfunction InvalidAlgorithmError(message) {\n HttpSignatureError.call(this, message, InvalidAlgorithmError);\n}\nutil.inherits(InvalidAlgorithmError, HttpSignatureError);\n\nfunction validateAlgorithm(algorithm) {\n var alg = algorithm.toLowerCase().split('-');\n\n if (alg.length !== 2) {\n throw (new InvalidAlgorithmError(alg[0].toUpperCase() + ' is not a ' +\n 'valid algorithm'));\n }\n\n if (alg[0] !== 'hmac' && !PK_ALGOS[alg[0]]) {\n throw (new InvalidAlgorithmError(alg[0].toUpperCase() + ' type keys ' +\n 'are not supported'));\n }\n\n if (!HASH_ALGOS[alg[1]]) {\n throw (new InvalidAlgorithmError(alg[1].toUpperCase() + ' is not a ' +\n 'supported hash algorithm'));\n }\n\n return (alg);\n}\n\n///--- API\n\nmodule.exports = {\n\n HASH_ALGOS: HASH_ALGOS,\n PK_ALGOS: PK_ALGOS,\n\n HttpSignatureError: HttpSignatureError,\n InvalidAlgorithmError: InvalidAlgorithmError,\n\n validateAlgorithm: validateAlgorithm,\n\n /**\n * Converts an OpenSSH public key (rsa only) to a PKCS#8 PEM file.\n *\n * The intent of this module is to interoperate with OpenSSL only,\n * specifically the node crypto module's `verify` method.\n *\n * @param {String} key an OpenSSH public key.\n * @return {String} PEM encoded form of the RSA public key.\n * @throws {TypeError} on bad input.\n * @throws {Error} on invalid ssh key formatted data.\n */\n sshKeyToPEM: function sshKeyToPEM(key) {\n assert.string(key, 'ssh_key');\n\n var k = sshpk.parseKey(key, 'ssh');\n return (k.toString('pem'));\n },\n\n\n /**\n * Generates an OpenSSH fingerprint from an ssh public key.\n *\n * @param {String} key an OpenSSH public key.\n * @return {String} key fingerprint.\n * @throws {TypeError} on bad input.\n * @throws {Error} if what you passed doesn't look like an ssh public key.\n */\n fingerprint: function fingerprint(key) {\n assert.string(key, 'ssh_key');\n\n var k = sshpk.parseKey(key, 'ssh');\n return (k.fingerprint('md5').toString('hex'));\n },\n\n /**\n * Converts a PKGCS#8 PEM file to an OpenSSH public key (rsa)\n *\n * The reverse of the above function.\n */\n pemToRsaSSHKey: function pemToRsaSSHKey(pem, comment) {\n assert.equal('string', typeof (pem), 'typeof pem');\n\n var k = sshpk.parseKey(pem, 'pem');\n k.comment = comment;\n return (k.toString('ssh'));\n }\n};\n","// Basic Javascript Elliptic Curve implementation\n// Ported loosely from BouncyCastle's Java EC code\n// Only Fp curves implemented for now\n\n// Requires jsbn.js and jsbn2.js\nvar BigInteger = require('jsbn').BigInteger\nvar Barrett = BigInteger.prototype.Barrett\n\n// ----------------\n// ECFieldElementFp\n\n// constructor\nfunction ECFieldElementFp(q,x) {\n this.x = x;\n // TODO if(x.compareTo(q) >= 0) error\n this.q = q;\n}\n\nfunction feFpEquals(other) {\n if(other == this) return true;\n return (this.q.equals(other.q) && this.x.equals(other.x));\n}\n\nfunction feFpToBigInteger() {\n return this.x;\n}\n\nfunction feFpNegate() {\n return new ECFieldElementFp(this.q, this.x.negate().mod(this.q));\n}\n\nfunction feFpAdd(b) {\n return new ECFieldElementFp(this.q, this.x.add(b.toBigInteger()).mod(this.q));\n}\n\nfunction feFpSubtract(b) {\n return new ECFieldElementFp(this.q, this.x.subtract(b.toBigInteger()).mod(this.q));\n}\n\nfunction feFpMultiply(b) {\n return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger()).mod(this.q));\n}\n\nfunction feFpSquare() {\n return new ECFieldElementFp(this.q, this.x.square().mod(this.q));\n}\n\nfunction feFpDivide(b) {\n return new ECFieldElementFp(this.q, this.x.multiply(b.toBigInteger().modInverse(this.q)).mod(this.q));\n}\n\nECFieldElementFp.prototype.equals = feFpEquals;\nECFieldElementFp.prototype.toBigInteger = feFpToBigInteger;\nECFieldElementFp.prototype.negate = feFpNegate;\nECFieldElementFp.prototype.add = feFpAdd;\nECFieldElementFp.prototype.subtract = feFpSubtract;\nECFieldElementFp.prototype.multiply = feFpMultiply;\nECFieldElementFp.prototype.square = feFpSquare;\nECFieldElementFp.prototype.divide = feFpDivide;\n\n// ----------------\n// ECPointFp\n\n// constructor\nfunction ECPointFp(curve,x,y,z) {\n this.curve = curve;\n this.x = x;\n this.y = y;\n // Projective coordinates: either zinv == null or z * zinv == 1\n // z and zinv are just BigIntegers, not fieldElements\n if(z == null) {\n this.z = BigInteger.ONE;\n }\n else {\n this.z = z;\n }\n this.zinv = null;\n //TODO: compression flag\n}\n\nfunction pointFpGetX() {\n if(this.zinv == null) {\n this.zinv = this.z.modInverse(this.curve.q);\n }\n var r = this.x.toBigInteger().multiply(this.zinv);\n this.curve.reduce(r);\n return this.curve.fromBigInteger(r);\n}\n\nfunction pointFpGetY() {\n if(this.zinv == null) {\n this.zinv = this.z.modInverse(this.curve.q);\n }\n var r = this.y.toBigInteger().multiply(this.zinv);\n this.curve.reduce(r);\n return this.curve.fromBigInteger(r);\n}\n\nfunction pointFpEquals(other) {\n if(other == this) return true;\n if(this.isInfinity()) return other.isInfinity();\n if(other.isInfinity()) return this.isInfinity();\n var u, v;\n // u = Y2 * Z1 - Y1 * Z2\n u = other.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(other.z)).mod(this.curve.q);\n if(!u.equals(BigInteger.ZERO)) return false;\n // v = X2 * Z1 - X1 * Z2\n v = other.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(other.z)).mod(this.curve.q);\n return v.equals(BigInteger.ZERO);\n}\n\nfunction pointFpIsInfinity() {\n if((this.x == null) && (this.y == null)) return true;\n return this.z.equals(BigInteger.ZERO) && !this.y.toBigInteger().equals(BigInteger.ZERO);\n}\n\nfunction pointFpNegate() {\n return new ECPointFp(this.curve, this.x, this.y.negate(), this.z);\n}\n\nfunction pointFpAdd(b) {\n if(this.isInfinity()) return b;\n if(b.isInfinity()) return this;\n\n // u = Y2 * Z1 - Y1 * Z2\n var u = b.y.toBigInteger().multiply(this.z).subtract(this.y.toBigInteger().multiply(b.z)).mod(this.curve.q);\n // v = X2 * Z1 - X1 * Z2\n var v = b.x.toBigInteger().multiply(this.z).subtract(this.x.toBigInteger().multiply(b.z)).mod(this.curve.q);\n\n if(BigInteger.ZERO.equals(v)) {\n if(BigInteger.ZERO.equals(u)) {\n return this.twice(); // this == b, so double\n }\n\treturn this.curve.getInfinity(); // this = -b, so infinity\n }\n\n var THREE = new BigInteger(\"3\");\n var x1 = this.x.toBigInteger();\n var y1 = this.y.toBigInteger();\n var x2 = b.x.toBigInteger();\n var y2 = b.y.toBigInteger();\n\n var v2 = v.square();\n var v3 = v2.multiply(v);\n var x1v2 = x1.multiply(v2);\n var zu2 = u.square().multiply(this.z);\n\n // x3 = v * (z2 * (z1 * u^2 - 2 * x1 * v^2) - v^3)\n var x3 = zu2.subtract(x1v2.shiftLeft(1)).multiply(b.z).subtract(v3).multiply(v).mod(this.curve.q);\n // y3 = z2 * (3 * x1 * u * v^2 - y1 * v^3 - z1 * u^3) + u * v^3\n var y3 = x1v2.multiply(THREE).multiply(u).subtract(y1.multiply(v3)).subtract(zu2.multiply(u)).multiply(b.z).add(u.multiply(v3)).mod(this.curve.q);\n // z3 = v^3 * z1 * z2\n var z3 = v3.multiply(this.z).multiply(b.z).mod(this.curve.q);\n\n return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);\n}\n\nfunction pointFpTwice() {\n if(this.isInfinity()) return this;\n if(this.y.toBigInteger().signum() == 0) return this.curve.getInfinity();\n\n // TODO: optimized handling of constants\n var THREE = new BigInteger(\"3\");\n var x1 = this.x.toBigInteger();\n var y1 = this.y.toBigInteger();\n\n var y1z1 = y1.multiply(this.z);\n var y1sqz1 = y1z1.multiply(y1).mod(this.curve.q);\n var a = this.curve.a.toBigInteger();\n\n // w = 3 * x1^2 + a * z1^2\n var w = x1.square().multiply(THREE);\n if(!BigInteger.ZERO.equals(a)) {\n w = w.add(this.z.square().multiply(a));\n }\n w = w.mod(this.curve.q);\n //this.curve.reduce(w);\n // x3 = 2 * y1 * z1 * (w^2 - 8 * x1 * y1^2 * z1)\n var x3 = w.square().subtract(x1.shiftLeft(3).multiply(y1sqz1)).shiftLeft(1).multiply(y1z1).mod(this.curve.q);\n // y3 = 4 * y1^2 * z1 * (3 * w * x1 - 2 * y1^2 * z1) - w^3\n var y3 = w.multiply(THREE).multiply(x1).subtract(y1sqz1.shiftLeft(1)).shiftLeft(2).multiply(y1sqz1).subtract(w.square().multiply(w)).mod(this.curve.q);\n // z3 = 8 * (y1 * z1)^3\n var z3 = y1z1.square().multiply(y1z1).shiftLeft(3).mod(this.curve.q);\n\n return new ECPointFp(this.curve, this.curve.fromBigInteger(x3), this.curve.fromBigInteger(y3), z3);\n}\n\n// Simple NAF (Non-Adjacent Form) multiplication algorithm\n// TODO: modularize the multiplication algorithm\nfunction pointFpMultiply(k) {\n if(this.isInfinity()) return this;\n if(k.signum() == 0) return this.curve.getInfinity();\n\n var e = k;\n var h = e.multiply(new BigInteger(\"3\"));\n\n var neg = this.negate();\n var R = this;\n\n var i;\n for(i = h.bitLength() - 2; i > 0; --i) {\n\tR = R.twice();\n\n\tvar hBit = h.testBit(i);\n\tvar eBit = e.testBit(i);\n\n\tif (hBit != eBit) {\n\t R = R.add(hBit ? this : neg);\n\t}\n }\n\n return R;\n}\n\n// Compute this*j + x*k (simultaneous multiplication)\nfunction pointFpMultiplyTwo(j,x,k) {\n var i;\n if(j.bitLength() > k.bitLength())\n i = j.bitLength() - 1;\n else\n i = k.bitLength() - 1;\n\n var R = this.curve.getInfinity();\n var both = this.add(x);\n while(i >= 0) {\n R = R.twice();\n if(j.testBit(i)) {\n if(k.testBit(i)) {\n R = R.add(both);\n }\n else {\n R = R.add(this);\n }\n }\n else {\n if(k.testBit(i)) {\n R = R.add(x);\n }\n }\n --i;\n }\n\n return R;\n}\n\nECPointFp.prototype.getX = pointFpGetX;\nECPointFp.prototype.getY = pointFpGetY;\nECPointFp.prototype.equals = pointFpEquals;\nECPointFp.prototype.isInfinity = pointFpIsInfinity;\nECPointFp.prototype.negate = pointFpNegate;\nECPointFp.prototype.add = pointFpAdd;\nECPointFp.prototype.twice = pointFpTwice;\nECPointFp.prototype.multiply = pointFpMultiply;\nECPointFp.prototype.multiplyTwo = pointFpMultiplyTwo;\n\n// ----------------\n// ECCurveFp\n\n// constructor\nfunction ECCurveFp(q,a,b) {\n this.q = q;\n this.a = this.fromBigInteger(a);\n this.b = this.fromBigInteger(b);\n this.infinity = new ECPointFp(this, null, null);\n this.reducer = new Barrett(this.q);\n}\n\nfunction curveFpGetQ() {\n return this.q;\n}\n\nfunction curveFpGetA() {\n return this.a;\n}\n\nfunction curveFpGetB() {\n return this.b;\n}\n\nfunction curveFpEquals(other) {\n if(other == this) return true;\n return(this.q.equals(other.q) && this.a.equals(other.a) && this.b.equals(other.b));\n}\n\nfunction curveFpGetInfinity() {\n return this.infinity;\n}\n\nfunction curveFpFromBigInteger(x) {\n return new ECFieldElementFp(this.q, x);\n}\n\nfunction curveReduce(x) {\n this.reducer.reduce(x);\n}\n\n// for now, work with hex strings because they're easier in JS\nfunction curveFpDecodePointHex(s) {\n switch(parseInt(s.substr(0,2), 16)) { // first byte\n case 0:\n\treturn this.infinity;\n case 2:\n case 3:\n\t// point compression not supported yet\n\treturn null;\n case 4:\n case 6:\n case 7:\n\tvar len = (s.length - 2) / 2;\n\tvar xHex = s.substr(2, len);\n\tvar yHex = s.substr(len+2, len);\n\n\treturn new ECPointFp(this,\n\t\t\t this.fromBigInteger(new BigInteger(xHex, 16)),\n\t\t\t this.fromBigInteger(new BigInteger(yHex, 16)));\n\n default: // unsupported\n\treturn null;\n }\n}\n\nfunction curveFpEncodePointHex(p) {\n\tif (p.isInfinity()) return \"00\";\n\tvar xHex = p.getX().toBigInteger().toString(16);\n\tvar yHex = p.getY().toBigInteger().toString(16);\n\tvar oLen = this.getQ().toString(16).length;\n\tif ((oLen % 2) != 0) oLen++;\n\twhile (xHex.length < oLen) {\n\t\txHex = \"0\" + xHex;\n\t}\n\twhile (yHex.length < oLen) {\n\t\tyHex = \"0\" + yHex;\n\t}\n\treturn \"04\" + xHex + yHex;\n}\n\nECCurveFp.prototype.getQ = curveFpGetQ;\nECCurveFp.prototype.getA = curveFpGetA;\nECCurveFp.prototype.getB = curveFpGetB;\nECCurveFp.prototype.equals = curveFpEquals;\nECCurveFp.prototype.getInfinity = curveFpGetInfinity;\nECCurveFp.prototype.fromBigInteger = curveFpFromBigInteger;\nECCurveFp.prototype.reduce = curveReduce;\n//ECCurveFp.prototype.decodePointHex = curveFpDecodePointHex;\nECCurveFp.prototype.encodePointHex = curveFpEncodePointHex;\n\n// from: https://github.com/kaielvin/jsbn-ec-point-compression\nECCurveFp.prototype.decodePointHex = function(s)\n{\n\tvar yIsEven;\n switch(parseInt(s.substr(0,2), 16)) { // first byte\n case 0:\n\treturn this.infinity;\n case 2:\n\tyIsEven = false;\n case 3:\n\tif(yIsEven == undefined) yIsEven = true;\n\tvar len = s.length - 2;\n\tvar xHex = s.substr(2, len);\n\tvar x = this.fromBigInteger(new BigInteger(xHex,16));\n\tvar alpha = x.multiply(x.square().add(this.getA())).add(this.getB());\n\tvar beta = alpha.sqrt();\n\n if (beta == null) throw \"Invalid point compression\";\n\n var betaValue = beta.toBigInteger();\n if (betaValue.testBit(0) != yIsEven)\n {\n // Use the other root\n beta = this.fromBigInteger(this.getQ().subtract(betaValue));\n }\n return new ECPointFp(this,x,beta);\n case 4:\n case 6:\n case 7:\n\tvar len = (s.length - 2) / 2;\n\tvar xHex = s.substr(2, len);\n\tvar yHex = s.substr(len+2, len);\n\n\treturn new ECPointFp(this,\n\t\t\t this.fromBigInteger(new BigInteger(xHex, 16)),\n\t\t\t this.fromBigInteger(new BigInteger(yHex, 16)));\n\n default: // unsupported\n\treturn null;\n }\n}\nECCurveFp.prototype.encodeCompressedPointHex = function(p)\n{\n\tif (p.isInfinity()) return \"00\";\n\tvar xHex = p.getX().toBigInteger().toString(16);\n\tvar oLen = this.getQ().toString(16).length;\n\tif ((oLen % 2) != 0) oLen++;\n\twhile (xHex.length < oLen)\n\t\txHex = \"0\" + xHex;\n\tvar yPrefix;\n\tif(p.getY().toBigInteger().isEven()) yPrefix = \"02\";\n\telse yPrefix = \"03\";\n\n\treturn yPrefix + xHex;\n}\n\n\nECFieldElementFp.prototype.getR = function()\n{\n\tif(this.r != undefined) return this.r;\n\n this.r = null;\n var bitLength = this.q.bitLength();\n if (bitLength > 128)\n {\n var firstWord = this.q.shiftRight(bitLength - 64);\n if (firstWord.intValue() == -1)\n {\n this.r = BigInteger.ONE.shiftLeft(bitLength).subtract(this.q);\n }\n }\n return this.r;\n}\nECFieldElementFp.prototype.modMult = function(x1,x2)\n{\n return this.modReduce(x1.multiply(x2));\n}\nECFieldElementFp.prototype.modReduce = function(x)\n{\n if (this.getR() != null)\n {\n var qLen = q.bitLength();\n while (x.bitLength() > (qLen + 1))\n {\n var u = x.shiftRight(qLen);\n var v = x.subtract(u.shiftLeft(qLen));\n if (!this.getR().equals(BigInteger.ONE))\n {\n u = u.multiply(this.getR());\n }\n x = u.add(v); \n }\n while (x.compareTo(q) >= 0)\n {\n x = x.subtract(q);\n }\n }\n else\n {\n x = x.mod(q);\n }\n return x;\n}\nECFieldElementFp.prototype.sqrt = function()\n{\n if (!this.q.testBit(0)) throw \"unsupported\";\n\n // p mod 4 == 3\n if (this.q.testBit(1))\n {\n \tvar z = new ECFieldElementFp(this.q,this.x.modPow(this.q.shiftRight(2).add(BigInteger.ONE),this.q));\n \treturn z.square().equals(this) ? z : null;\n }\n\n // p mod 4 == 1\n var qMinusOne = this.q.subtract(BigInteger.ONE);\n\n var legendreExponent = qMinusOne.shiftRight(1);\n if (!(this.x.modPow(legendreExponent, this.q).equals(BigInteger.ONE)))\n {\n return null;\n }\n\n var u = qMinusOne.shiftRight(2);\n var k = u.shiftLeft(1).add(BigInteger.ONE);\n\n var Q = this.x;\n var fourQ = modDouble(modDouble(Q));\n\n var U, V;\n do\n {\n var P;\n do\n {\n P = new BigInteger(this.q.bitLength(), new SecureRandom());\n }\n while (P.compareTo(this.q) >= 0\n || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, this.q).equals(qMinusOne)));\n\n var result = this.lucasSequence(P, Q, k);\n U = result[0];\n V = result[1];\n\n if (this.modMult(V, V).equals(fourQ))\n {\n // Integer division by 2, mod q\n if (V.testBit(0))\n {\n V = V.add(q);\n }\n\n V = V.shiftRight(1);\n\n return new ECFieldElementFp(q,V);\n }\n }\n while (U.equals(BigInteger.ONE) || U.equals(qMinusOne));\n\n return null;\n}\nECFieldElementFp.prototype.lucasSequence = function(P,Q,k)\n{\n var n = k.bitLength();\n var s = k.getLowestSetBit();\n\n var Uh = BigInteger.ONE;\n var Vl = BigInteger.TWO;\n var Vh = P;\n var Ql = BigInteger.ONE;\n var Qh = BigInteger.ONE;\n\n for (var j = n - 1; j >= s + 1; --j)\n {\n Ql = this.modMult(Ql, Qh);\n\n if (k.testBit(j))\n {\n Qh = this.modMult(Ql, Q);\n Uh = this.modMult(Uh, Vh);\n Vl = this.modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));\n Vh = this.modReduce(Vh.multiply(Vh).subtract(Qh.shiftLeft(1)));\n }\n else\n {\n Qh = Ql;\n Uh = this.modReduce(Uh.multiply(Vl).subtract(Ql));\n Vh = this.modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));\n Vl = this.modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1)));\n }\n }\n\n Ql = this.modMult(Ql, Qh);\n Qh = this.modMult(Ql, Q);\n Uh = this.modReduce(Uh.multiply(Vl).subtract(Ql));\n Vl = this.modReduce(Vh.multiply(Vl).subtract(P.multiply(Ql)));\n Ql = this.modMult(Ql, Qh);\n\n for (var j = 1; j <= s; ++j)\n {\n Uh = this.modMult(Uh, Vl);\n Vl = this.modReduce(Vl.multiply(Vl).subtract(Ql.shiftLeft(1)));\n Ql = this.modMult(Ql, Ql);\n }\n\n return [ Uh, Vl ];\n}\n\nvar exports = {\n ECCurveFp: ECCurveFp,\n ECPointFp: ECPointFp,\n ECFieldElementFp: ECFieldElementFp\n}\n\nmodule.exports = exports\n","// Copyright 2015 Joyent, Inc.\n\nmodule.exports = {\n\tread: read,\n\treadSSHPrivate: readSSHPrivate,\n\twrite: write\n};\n\nvar assert = require('assert-plus');\nvar asn1 = require('asn1');\nvar Buffer = require('safer-buffer').Buffer;\nvar algs = require('../algs');\nvar utils = require('../utils');\nvar crypto = require('crypto');\n\nvar Key = require('../key');\nvar PrivateKey = require('../private-key');\nvar pem = require('./pem');\nvar rfc4253 = require('./rfc4253');\nvar SSHBuffer = require('../ssh-buffer');\nvar errors = require('../errors');\n\nvar bcrypt;\n\nfunction read(buf, options) {\n\treturn (pem.read(buf, options));\n}\n\nvar MAGIC = 'openssh-key-v1';\n\nfunction readSSHPrivate(type, buf, options) {\n\tbuf = new SSHBuffer({buffer: buf});\n\n\tvar magic = buf.readCString();\n\tassert.strictEqual(magic, MAGIC, 'bad magic string');\n\n\tvar cipher = buf.readString();\n\tvar kdf = buf.readString();\n\tvar kdfOpts = buf.readBuffer();\n\n\tvar nkeys = buf.readInt();\n\tif (nkeys !== 1) {\n\t\tthrow (new Error('OpenSSH-format key file contains ' +\n\t\t 'multiple keys: this is unsupported.'));\n\t}\n\n\tvar pubKey = buf.readBuffer();\n\n\tif (type === 'public') {\n\t\tassert.ok(buf.atEnd(), 'excess bytes left after key');\n\t\treturn (rfc4253.read(pubKey));\n\t}\n\n\tvar privKeyBlob = buf.readBuffer();\n\tassert.ok(buf.atEnd(), 'excess bytes left after key');\n\n\tvar kdfOptsBuf = new SSHBuffer({ buffer: kdfOpts });\n\tswitch (kdf) {\n\tcase 'none':\n\t\tif (cipher !== 'none') {\n\t\t\tthrow (new Error('OpenSSH-format key uses KDF \"none\" ' +\n\t\t\t 'but specifies a cipher other than \"none\"'));\n\t\t}\n\t\tbreak;\n\tcase 'bcrypt':\n\t\tvar salt = kdfOptsBuf.readBuffer();\n\t\tvar rounds = kdfOptsBuf.readInt();\n\t\tvar cinf = utils.opensshCipherInfo(cipher);\n\t\tif (bcrypt === undefined) {\n\t\t\tbcrypt = require('bcrypt-pbkdf');\n\t\t}\n\n\t\tif (typeof (options.passphrase) === 'string') {\n\t\t\toptions.passphrase = Buffer.from(options.passphrase,\n\t\t\t 'utf-8');\n\t\t}\n\t\tif (!Buffer.isBuffer(options.passphrase)) {\n\t\t\tthrow (new errors.KeyEncryptedError(\n\t\t\t options.filename, 'OpenSSH'));\n\t\t}\n\n\t\tvar pass = new Uint8Array(options.passphrase);\n\t\tvar salti = new Uint8Array(salt);\n\t\t/* Use the pbkdf to derive both the key and the IV. */\n\t\tvar out = new Uint8Array(cinf.keySize + cinf.blockSize);\n\t\tvar res = bcrypt.pbkdf(pass, pass.length, salti, salti.length,\n\t\t out, out.length, rounds);\n\t\tif (res !== 0) {\n\t\t\tthrow (new Error('bcrypt_pbkdf function returned ' +\n\t\t\t 'failure, parameters invalid'));\n\t\t}\n\t\tout = Buffer.from(out);\n\t\tvar ckey = out.slice(0, cinf.keySize);\n\t\tvar iv = out.slice(cinf.keySize, cinf.keySize + cinf.blockSize);\n\t\tvar cipherStream = crypto.createDecipheriv(cinf.opensslName,\n\t\t ckey, iv);\n\t\tcipherStream.setAutoPadding(false);\n\t\tvar chunk, chunks = [];\n\t\tcipherStream.once('error', function (e) {\n\t\t\tif (e.toString().indexOf('bad decrypt') !== -1) {\n\t\t\t\tthrow (new Error('Incorrect passphrase ' +\n\t\t\t\t 'supplied, could not decrypt key'));\n\t\t\t}\n\t\t\tthrow (e);\n\t\t});\n\t\tcipherStream.write(privKeyBlob);\n\t\tcipherStream.end();\n\t\twhile ((chunk = cipherStream.read()) !== null)\n\t\t\tchunks.push(chunk);\n\t\tprivKeyBlob = Buffer.concat(chunks);\n\t\tbreak;\n\tdefault:\n\t\tthrow (new Error(\n\t\t 'OpenSSH-format key uses unknown KDF \"' + kdf + '\"'));\n\t}\n\n\tbuf = new SSHBuffer({buffer: privKeyBlob});\n\n\tvar checkInt1 = buf.readInt();\n\tvar checkInt2 = buf.readInt();\n\tif (checkInt1 !== checkInt2) {\n\t\tthrow (new Error('Incorrect passphrase supplied, could not ' +\n\t\t 'decrypt key'));\n\t}\n\n\tvar ret = {};\n\tvar key = rfc4253.readInternal(ret, 'private', buf.remainder());\n\n\tbuf.skip(ret.consumed);\n\n\tvar comment = buf.readString();\n\tkey.comment = comment;\n\n\treturn (key);\n}\n\nfunction write(key, options) {\n\tvar pubKey;\n\tif (PrivateKey.isPrivateKey(key))\n\t\tpubKey = key.toPublic();\n\telse\n\t\tpubKey = key;\n\n\tvar cipher = 'none';\n\tvar kdf = 'none';\n\tvar kdfopts = Buffer.alloc(0);\n\tvar cinf = { blockSize: 8 };\n\tvar passphrase;\n\tif (options !== undefined) {\n\t\tpassphrase = options.passphrase;\n\t\tif (typeof (passphrase) === 'string')\n\t\t\tpassphrase = Buffer.from(passphrase, 'utf-8');\n\t\tif (passphrase !== undefined) {\n\t\t\tassert.buffer(passphrase, 'options.passphrase');\n\t\t\tassert.optionalString(options.cipher, 'options.cipher');\n\t\t\tcipher = options.cipher;\n\t\t\tif (cipher === undefined)\n\t\t\t\tcipher = 'aes128-ctr';\n\t\t\tcinf = utils.opensshCipherInfo(cipher);\n\t\t\tkdf = 'bcrypt';\n\t\t}\n\t}\n\n\tvar privBuf;\n\tif (PrivateKey.isPrivateKey(key)) {\n\t\tprivBuf = new SSHBuffer({});\n\t\tvar checkInt = crypto.randomBytes(4).readUInt32BE(0);\n\t\tprivBuf.writeInt(checkInt);\n\t\tprivBuf.writeInt(checkInt);\n\t\tprivBuf.write(key.toBuffer('rfc4253'));\n\t\tprivBuf.writeString(key.comment || '');\n\n\t\tvar n = 1;\n\t\twhile (privBuf._offset % cinf.blockSize !== 0)\n\t\t\tprivBuf.writeChar(n++);\n\t\tprivBuf = privBuf.toBuffer();\n\t}\n\n\tswitch (kdf) {\n\tcase 'none':\n\t\tbreak;\n\tcase 'bcrypt':\n\t\tvar salt = crypto.randomBytes(16);\n\t\tvar rounds = 16;\n\t\tvar kdfssh = new SSHBuffer({});\n\t\tkdfssh.writeBuffer(salt);\n\t\tkdfssh.writeInt(rounds);\n\t\tkdfopts = kdfssh.toBuffer();\n\n\t\tif (bcrypt === undefined) {\n\t\t\tbcrypt = require('bcrypt-pbkdf');\n\t\t}\n\t\tvar pass = new Uint8Array(passphrase);\n\t\tvar salti = new Uint8Array(salt);\n\t\t/* Use the pbkdf to derive both the key and the IV. */\n\t\tvar out = new Uint8Array(cinf.keySize + cinf.blockSize);\n\t\tvar res = bcrypt.pbkdf(pass, pass.length, salti, salti.length,\n\t\t out, out.length, rounds);\n\t\tif (res !== 0) {\n\t\t\tthrow (new Error('bcrypt_pbkdf function returned ' +\n\t\t\t 'failure, parameters invalid'));\n\t\t}\n\t\tout = Buffer.from(out);\n\t\tvar ckey = out.slice(0, cinf.keySize);\n\t\tvar iv = out.slice(cinf.keySize, cinf.keySize + cinf.blockSize);\n\n\t\tvar cipherStream = crypto.createCipheriv(cinf.opensslName,\n\t\t ckey, iv);\n\t\tcipherStream.setAutoPadding(false);\n\t\tvar chunk, chunks = [];\n\t\tcipherStream.once('error', function (e) {\n\t\t\tthrow (e);\n\t\t});\n\t\tcipherStream.write(privBuf);\n\t\tcipherStream.end();\n\t\twhile ((chunk = cipherStream.read()) !== null)\n\t\t\tchunks.push(chunk);\n\t\tprivBuf = Buffer.concat(chunks);\n\t\tbreak;\n\tdefault:\n\t\tthrow (new Error('Unsupported kdf ' + kdf));\n\t}\n\n\tvar buf = new SSHBuffer({});\n\n\tbuf.writeCString(MAGIC);\n\tbuf.writeString(cipher);\t/* cipher */\n\tbuf.writeString(kdf);\t\t/* kdf */\n\tbuf.writeBuffer(kdfopts);\t/* kdfoptions */\n\n\tbuf.writeInt(1);\t\t/* nkeys */\n\tbuf.writeBuffer(pubKey.toBuffer('rfc4253'));\n\n\tif (privBuf)\n\t\tbuf.writeBuffer(privBuf);\n\n\tbuf = buf.toBuffer();\n\n\tvar header;\n\tif (PrivateKey.isPrivateKey(key))\n\t\theader = 'OPENSSH PRIVATE KEY';\n\telse\n\t\theader = 'OPENSSH PUBLIC KEY';\n\n\tvar tmp = buf.toString('base64');\n\tvar len = tmp.length + (tmp.length / 70) +\n\t 18 + 16 + header.length*2 + 10;\n\tbuf = Buffer.alloc(len);\n\tvar o = 0;\n\to += buf.write('-----BEGIN ' + header + '-----\\n', o);\n\tfor (var i = 0; i < tmp.length; ) {\n\t\tvar limit = i + 70;\n\t\tif (limit > tmp.length)\n\t\t\tlimit = tmp.length;\n\t\to += buf.write(tmp.slice(i, limit), o);\n\t\tbuf[o++] = 10;\n\t\ti = limit;\n\t}\n\to += buf.write('-----END ' + header + '-----\\n', o);\n\n\treturn (buf.slice(0, o));\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}));","const assert = require(\"assert\");\nconst BigInteger = require(\"../../common/biginteger\").BigInteger;\nconst GenUtils = require(\"../../common/GenUtils\");\n\n/**\n * Models a Monero block header which contains information about the block.\n * \n * @class\n */\nclass MoneroBlockHeader {\n \n /**\n * Construct the model.\n * \n * @param {MoneroBlockHeader|object} state is existing state to initialize from (optional)\n */\n constructor(state) {\n \n // initialize internal state\n if (!state) state = {};\n else if (state instanceof MoneroBlockHeader) state = state.toJson();\n else if (typeof state === \"object\") state = Object.assign({}, state);\n else throw new MoneroError(\"state must be a MoneroBlockHeader or JavaScript object\");\n this.state = state;\n \n // deserialize BigIntegers\n if (state.difficulty !== undefined && !(state.difficulty instanceof BigInteger)) state.difficulty = BigInteger.parse(state.difficulty);\n if (state.cumulativeDifficulty !== undefined && !(state.cumulativeDifficulty instanceof BigInteger)) state.cumulativeDifficulty = BigInteger.parse(state.cumulativeDifficulty);\n if (state.reward !== undefined && !(state.reward instanceof BigInteger)) state.reward = BigInteger.parse(state.reward);\n }\n \n copy() {\n return new MoneroBlockHeader(this);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (this.getDifficulty()) json.difficulty = this.getDifficulty().toString();\n if (this.getCumulativeDifficulty()) json.cumulativeDifficulty = this.getCumulativeDifficulty().toString();\n if (this.getReward()) json.reward = this.getReward().toString();\n return json;\n }\n \n getHash() {\n return this.state.hash;\n }\n \n setHash(hash) {\n this.state.hash = hash;\n return this;\n }\n \n /**\n * Return the block's height which is the total number of blocks that have occurred before.\n * \n * @return {number} the block's height\n */\n getHeight() {\n return this.state.height;\n }\n \n /**\n * Set the block's height which is the total number of blocks that have occurred before.\n * \n * @param {number} height is the block's height to set\n * @return {MoneroBlockHeader} a reference to this header for chaining\n */\n setHeight(height) {\n this.state.height = height;\n return this;\n }\n \n getTimestamp() {\n return this.state.timestamp;\n }\n \n setTimestamp(timestamp) {\n this.state.timestamp = timestamp;\n return this;\n }\n \n getSize() {\n return this.state.size;\n }\n \n setSize(size) {\n this.state.size = size;\n return this;\n }\n \n getWeight() {\n return this.state.weight;\n }\n \n setWeight(weight) {\n this.state.weight = weight;\n return this;\n }\n \n getLongTermWeight() {\n return this.state.longTermWeight;\n }\n \n setLongTermWeight(longTermWeight) {\n this.state.longTermWeight = longTermWeight;\n return this;\n }\n \n getDepth() {\n return this.state.depth;\n }\n \n setDepth(depth) {\n this.state.depth = depth;\n return this;\n }\n \n getDifficulty() {\n return this.state.difficulty;\n }\n \n setDifficulty(difficulty) {\n this.state.difficulty = difficulty;\n return this;\n }\n \n getCumulativeDifficulty() {\n return this.state.cumulativeDifficulty;\n }\n \n setCumulativeDifficulty(cumulativeDifficulty) {\n this.state.cumulativeDifficulty = cumulativeDifficulty;\n return this;\n }\n \n getMajorVersion() {\n return this.state.majorVersion;\n }\n \n setMajorVersion(majorVersion) {\n this.state.majorVersion = majorVersion;\n return this;\n }\n \n getMinorVersion() {\n return this.state.minorVersion;\n }\n \n setMinorVersion(minorVersion) {\n this.state.minorVersion = minorVersion;\n return this;\n }\n \n getNonce() {\n return this.state.nonce;\n }\n \n setNonce(nonce) {\n this.state.nonce = nonce;\n return this;\n }\n \n getMinerTxHash() {\n return this.state.minerTxHash;\n }\n \n setMinerTxHash(minerTxHash) {\n this.state.minerTxHash = minerTxHash;\n return this;\n }\n \n getNumTxs() {\n return this.state.numTxs;\n }\n \n setNumTxs(numTxs) {\n this.state.numTxs = numTxs;\n return this;\n }\n \n getOrphanStatus() {\n return this.state.orphanStatus;\n }\n \n setOrphanStatus(orphanStatus) {\n this.state.orphanStatus = orphanStatus;\n return this;\n }\n \n getPrevHash() {\n return this.state.prevHash;\n }\n \n setPrevHash(prevHash) {\n this.state.prevHash = prevHash;\n return this;\n }\n \n getReward() {\n return this.state.reward;\n }\n \n setReward(reward) {\n this.state.reward = reward;\n return this;\n }\n \n getPowHash() {\n return this.state.powHash;\n }\n \n setPowHash(powHash) {\n this.state.powHash = powHash;\n return this;\n }\n \n merge(header) {\n assert(header instanceof MoneroBlockHeader);\n if (this === header) return this;\n this.setHash(GenUtils.reconcile(this.getHash(), header.getHash()));\n this.setHeight(GenUtils.reconcile(this.getHeight(), header.getHeight(), {resolveMax: true})); // height can increase\n this.setTimestamp(GenUtils.reconcile(this.getTimestamp(), header.getTimestamp(), {resolveMax: true})); // block timestamp can increase\n this.setSize(GenUtils.reconcile(this.getSize(), header.getSize()));\n this.setWeight(GenUtils.reconcile(this.getWeight(), header.getWeight()));\n this.setDepth(GenUtils.reconcile(this.getDepth(), header.getDepth()));\n this.setDifficulty(GenUtils.reconcile(this.getDifficulty(), header.getDifficulty()));\n this.setCumulativeDifficulty(GenUtils.reconcile(this.getCumulativeDifficulty(), header.getCumulativeDifficulty()));\n this.setMajorVersion(GenUtils.reconcile(this.getMajorVersion(), header.getMajorVersion()));\n this.setMinorVersion(GenUtils.reconcile(this.getMinorVersion(), header.getMinorVersion()));\n this.setNonce(GenUtils.reconcile(this.getNonce(), header.getNonce()));\n this.setMinerTxHash(GenUtils.reconcile(this.getMinerTxHash(), header.getMinerTxHash()));\n this.setNumTxs(GenUtils.reconcile(this.getNumTxs(), header.getNumTxs()));\n this.setOrphanStatus(GenUtils.reconcile(this.getOrphanStatus(), header.getOrphanStatus()));\n this.setPrevHash(GenUtils.reconcile(this.getPrevHash(), header.getPrevHash()));\n this.setReward(GenUtils.reconcile(this.getReward(), header.getReward()));\n this.setPowHash(GenUtils.reconcile(this.getPowHash(), header.getPowHash()));\n return this;\n }\n \n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.kvLine(\"Hash\", this.getHash(), indent);\n str += GenUtils.kvLine(\"Height\", this.getHeight(), indent);\n str += GenUtils.kvLine(\"Timestamp\", this.getTimestamp(), indent);\n str += GenUtils.kvLine(\"Size\", this.getSize(), indent);\n str += GenUtils.kvLine(\"Weight\", this.getWeight(), indent);\n str += GenUtils.kvLine(\"Depth\", this.getDepth(), indent);\n str += GenUtils.kvLine(\"Difficulty\", this.getDifficulty(), indent);\n str += GenUtils.kvLine(\"Cumulative difficulty\", this.getCumulativeDifficulty(), indent);\n str += GenUtils.kvLine(\"Major version\", this.getMajorVersion(), indent);\n str += GenUtils.kvLine(\"Minor version\", this.getMinorVersion(), indent);\n str += GenUtils.kvLine(\"Nonce\", this.getNonce(), indent);\n str += GenUtils.kvLine(\"Miner tx hash\", this.getMinerTxHash(), indent);\n str += GenUtils.kvLine(\"Num txs\", this.getNumTxs(), indent);\n str += GenUtils.kvLine(\"Orphan status\", this.getOrphanStatus(), indent);\n str += GenUtils.kvLine(\"Prev hash\", this.getPrevHash(), indent);\n str += GenUtils.kvLine(\"Reward\", this.getReward(), indent);\n str += GenUtils.kvLine(\"Pow hash\", this.getPowHash(), indent);\n return str[str.length - 1] === \"\\n\" ? str.slice(0, str.length - 1) : str // strip last newline\n }\n}\n\nmodule.exports = MoneroBlockHeader;","const assert = require(\"assert\");\nconst BigInteger = require(\"../../common/biginteger\").BigInteger;\nconst GenUtils = require(\"../../common/GenUtils\");\nconst MoneroOutput = require(\"./MoneroOutput\");\n\n/**\n * Represents a transaction on the Monero network.\n * \n * @class\n */\nclass MoneroTx {\n \n /**\n * Construct the model.\n * \n * @param {MoneroTx|object} state is existing state to initialize from (optional)\n */\n constructor(state) {\n \n // initialize internal state\n if (!state) state = {};\n else if (state instanceof MoneroTx) state = state.toJson();\n else if (typeof state === \"object\") state = Object.assign({}, state);\n else throw new MoneroError(\"state must be a MoneroTx or JavaScript object\");\n this.state = state;\n \n // deserialize fee\n if (state.fee !== undefined && !(state.fee instanceof BigInteger)) state.fee = BigInteger.parse(state.fee);\n \n // deserialize inputs\n if (state.inputs) {\n for (let i = 0; i < state.inputs.length; i++) {\n if (!(state.inputs[i] instanceof MoneroOutput)) {\n state.inputs[i] = new MoneroOutput(Object.assign(state.inputs[i], {tx: this}));\n }\n }\n }\n \n // deserialize outputs\n if (state.outputs) {\n for (let i = 0; i < state.outputs.length; i++) {\n if (!(state.outputs[i] instanceof MoneroOutput)) {\n state.outputs[i] = new MoneroOutput(Object.assign(state.outputs[i], {tx: this}));\n }\n }\n }\n }\n \n getBlock() {\n return this.state.block;\n }\n \n setBlock(block) {\n this.state.block = block;\n return this;\n }\n \n getHeight() {\n return this.getBlock() === undefined ? undefined : this.getBlock().getHeight();\n }\n \n getHash() {\n return this.state.hash;\n }\n \n setHash(hash) {\n this.state.hash = hash;\n return this;\n }\n \n getVersion() {\n return this.state.version;\n }\n \n setVersion(version) {\n this.state.version = version;\n return this;\n }\n \n isMinerTx() {\n return this.state.isMinerTx;\n }\n \n setIsMinerTx(miner) {\n this.state.isMinerTx = miner;\n return this;\n }\n \n getPaymentId() {\n return this.state.paymentId;\n }\n \n setPaymentId(paymentId) {\n this.state.paymentId = paymentId;\n return this;\n }\n \n getFee() {\n return this.state.fee;\n }\n \n setFee(fee) {\n this.state.fee = fee;\n return this;\n }\n \n getRingSize() {\n return this.state.ringSize;\n }\n \n setRingSize(ringSize) {\n this.state.ringSize = ringSize;\n return this;\n }\n \n getRelay() {\n return this.state.relay;\n }\n \n setRelay(relay) {\n this.state.relay = relay;\n return this;\n }\n \n isRelayed() {\n return this.state.isRelayed;\n }\n \n setIsRelayed(isRelayed) {\n this.state.isRelayed = isRelayed;\n return this;\n }\n \n isConfirmed() {\n return this.state.isConfirmed;\n }\n \n setIsConfirmed(isConfirmed) {\n this.state.isConfirmed = isConfirmed;\n return this;\n }\n \n inTxPool() {\n return this.state.inTxPool;\n }\n \n setInTxPool(inTxPool) {\n this.state.inTxPool = inTxPool;\n return this;\n }\n \n getNumConfirmations() {\n return this.state.numConfirmations;\n }\n \n setNumConfirmations(numConfirmations) {\n this.state.numConfirmations = numConfirmations;\n return this;\n }\n \n getUnlockHeight() {\n return this.state.unlockHeight;\n }\n \n setUnlockHeight(unlockHeight) {\n this.state.unlockHeight = unlockHeight;\n return this;\n }\n \n getLastRelayedTimestamp() {\n return this.state.lastRelayedTimestamp;\n }\n \n setLastRelayedTimestamp(lastRelayedTimestamp) {\n this.state.lastRelayedTimestamp = lastRelayedTimestamp;\n return this;\n }\n \n getReceivedTimestamp() {\n return this.state.receivedTimestamp;\n }\n \n setReceivedTimestamp(receivedTimestamp) {\n this.state.receivedTimestamp = receivedTimestamp;\n return this;\n }\n \n isDoubleSpendSeen() {\n return this.state.isDoubleSpendSeen;\n }\n \n setIsDoubleSpend(isDoubleSpendSeen) {\n this.state.isDoubleSpendSeen = isDoubleSpendSeen;\n return this;\n }\n \n getKey() {\n return this.state.key;\n }\n \n setKey(key) {\n this.state.key = key;\n return this;\n }\n \n /**\n * Get full transaction hex. Full hex = pruned hex + prunable hex.\n * \n * @return {string} is full transaction hex\n */\n getFullHex() {\n return this.state.fullHex;\n }\n \n setFullHex(fullHex) {\n this.state.fullHex = fullHex;\n return this;\n }\n \n /**\n * Get pruned transaction hex. Full hex = pruned hex + prunable hex.\n * \n * @return {string} is pruned transaction hex\n */\n getPrunedHex() {\n return this.state.prunedHex;\n }\n \n setPrunedHex(prunedHex) {\n this.state.prunedHex = prunedHex;\n return this;\n }\n \n /**\n * Get prunable transaction hex which is hex that is removed from a pruned\n * transaction. Full hex = pruned hex + prunable hex.\n * \n * @return {string} is the prunable transaction hex\n */\n getPrunableHex() {\n return this.state.prunableHex;\n }\n \n setPrunableHex(prunableHex) {\n this.state.prunableHex = prunableHex;\n return this;\n }\n \n getPrunableHash() {\n return this.state.prunableHash;\n }\n \n setPrunableHash(prunableHash) {\n this.state.prunableHash = prunableHash;\n return this;\n }\n \n getSize() {\n return this.state.size;\n }\n \n setSize(size) {\n this.state.size = size;\n return this;\n }\n \n getWeight() {\n return this.state.weight;\n }\n \n setWeight(weight) {\n this.state.weight = weight;\n return this;\n }\n \n getInputs() {\n return this.state.inputs;\n }\n \n setInputs(inputs) {\n this.state.inputs = inputs;\n return this;\n }\n \n getOutputs() {\n return this.state.outputs;\n }\n \n setOutputs(outputs) {\n this.state.outputs = outputs;\n return this;\n }\n \n getOutputIndices() {\n return this.state.outputIndices;\n }\n \n setOutputIndices(outputIndices) {\n this.state.outputIndices = outputIndices;\n return this;\n }\n \n getMetadata() {\n return this.state.metadata;\n }\n \n setMetadata(metadata) {\n this.state.metadata = metadata;\n return this;\n }\n \n getExtra() {\n return this.state.extra;\n }\n \n setExtra(extra) {\n this.state.extra = extra;\n return this;\n }\n\n getRctSignatures() {\n return this.state.rctSignatures;\n }\n \n setRctSignatures(rctSignatures) {\n this.state.rctSignatures = rctSignatures;\n return this;\n }\n \n getRctSigPrunable() {\n return this.state.rctSigPrunable;\n }\n \n setRctSigPrunable(rctSigPrunable) {\n this.state.rctSigPrunable = rctSigPrunable;\n return this;\n }\n \n isKeptByBlock() {\n return this.state.isKeptByBlock;\n }\n \n setIsKeptByBlock(isKeptByBlock) {\n this.state.isKeptByBlock = isKeptByBlock;\n return this;\n }\n \n isFailed() {\n return this.state.isFailed;\n }\n \n setIsFailed(isFailed) {\n this.state.isFailed = isFailed;\n return this;\n }\n \n getLastFailedHeight() {\n return this.state.lastFailedHeight;\n }\n \n setLastFailedHeight(lastFailedHeight) {\n this.state.lastFailedHeight = lastFailedHeight;\n return this;\n }\n \n getLastFailedHash() {\n return this.state.lastFailedHash;\n }\n \n setLastFailedHash(lastFailedHash) {\n this.state.lastFailedHash = lastFailedHash;\n return this;\n }\n \n getMaxUsedBlockHeight() {\n return this.state.maxUsedBlockHeight;\n }\n \n setMaxUsedBlockHeight(maxUsedBlockHeight) {\n this.state.maxUsedBlockHeight = maxUsedBlockHeight;\n return this;\n }\n \n getMaxUsedBlockHash() {\n return this.state.maxUsedBlockHash;\n }\n \n setMaxUsedBlockHash(maxUsedBlockHash) {\n this.state.maxUsedBlockHash = maxUsedBlockHash;\n return this;\n }\n \n getSignatures() {\n return this.state.signatures;\n }\n \n setSignatures(signatures) {\n this.state.signatures = signatures;\n return this;\n }\n \n copy() {\n return new MoneroTx(this);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (this.getFee()) json.fee = this.getFee().toString();\n if (this.getInputs()) {\n json.inputs = [];\n for (let input of this.getInputs()) json.inputs.push(input.toJson());\n }\n if (this.getOutputs()) {\n json.outputs = [];\n for (let output of this.getOutputs()) json.outputs.push(output.toJson());\n }\n if (this.getExtra()) json.extra = this.getExtra().slice();\n delete json.block; // do not serialize parent block\n return json;\n }\n \n /**\n * Updates this transaction by merging the latest information from the given\n * transaction.\n * \n * @param tx is the transaction to update this transaction with\n * @return {MoneroTx} this for method chaining\n */\n merge(tx) {\n assert(tx instanceof MoneroTx);\n if (this === tx) return this;\n \n // merge blocks if they're different which comes back to merging txs\n const MoneroBlock = require(\"./MoneroBlock\");\n if (this.getBlock() !== tx.getBlock()) {\n if (this.getBlock() === undefined) {\n this.setBlock(new MoneroBlock());\n this.getBlock().setTxs([this]);\n this.getBlock().setHeight(tx.getHeight());\n }\n if (tx.getBlock() === undefined) {\n tx.setBlock(new MoneroBlock());\n tx.getBlock().setTxs([tx]);\n tx.getBlock().setHeight(this.getHeight());\n }\n this.getBlock().merge(tx.getBlock());\n return this;\n }\n \n // otherwise merge tx fields\n this.setHash(GenUtils.reconcile(this.getHash(), tx.getHash()));\n this.setVersion(GenUtils.reconcile(this.getVersion(), tx.getVersion()));\n this.setPaymentId(GenUtils.reconcile(this.getPaymentId(), tx.getPaymentId()));\n this.setFee(GenUtils.reconcile(this.getFee(), tx.getFee()));\n this.setRingSize(GenUtils.reconcile(this.getRingSize(), tx.getRingSize()));\n this.setIsConfirmed(GenUtils.reconcile(this.isConfirmed(), tx.isConfirmed(), {resolveTrue: true}));\n this.setIsMinerTx(GenUtils.reconcile(this.isMinerTx(), tx.isMinerTx(), null, null, null));\n this.setRelay(GenUtils.reconcile(this.getRelay(), tx.getRelay(), {resolveTrue: true})); // tx can become relayed\n this.setIsRelayed(GenUtils.reconcile(this.isRelayed(), tx.isRelayed(), {resolveTrue: true})); // tx can become relayed\n this.setIsDoubleSpend(GenUtils.reconcile(this.isDoubleSpendSeen(), tx.isDoubleSpendSeen()));\n this.setKey(GenUtils.reconcile(this.getKey(), tx.getKey()));\n this.setFullHex(GenUtils.reconcile(this.getFullHex(), tx.getFullHex()));\n this.setPrunedHex(GenUtils.reconcile(this.getPrunedHex(), tx.getPrunedHex()));\n this.setPrunableHex(GenUtils.reconcile(this.getPrunableHex(), tx.getPrunableHex()));\n this.setPrunableHash(GenUtils.reconcile(this.getPrunableHash(), tx.getPrunableHash()));\n this.setSize(GenUtils.reconcile(this.getSize(), tx.getSize()));\n this.setWeight(GenUtils.reconcile(this.getWeight(), tx.getWeight()));\n this.setOutputIndices(GenUtils.reconcile(this.getOutputIndices(), tx.getOutputIndices()));\n this.setMetadata(GenUtils.reconcile(this.getMetadata(), tx.getMetadata()));\n this.setExtra(GenUtils.reconcile(this.getExtra(), tx.getExtra()));\n this.setRctSignatures(GenUtils.reconcile(this.getRctSignatures(), tx.getRctSignatures()));\n this.setRctSigPrunable(GenUtils.reconcile(this.getRctSigPrunable(), tx.getRctSigPrunable()));\n this.setIsKeptByBlock(GenUtils.reconcile(this.isKeptByBlock(), tx.isKeptByBlock()));\n this.setIsFailed(GenUtils.reconcile(this.isFailed(), tx.isFailed()));\n this.setLastFailedHeight(GenUtils.reconcile(this.getLastFailedHeight(), tx.getLastFailedHeight()));\n this.setLastFailedHash(GenUtils.reconcile(this.getLastFailedHash(), tx.getLastFailedHash()));\n this.setMaxUsedBlockHeight(GenUtils.reconcile(this.getMaxUsedBlockHeight(), tx.getMaxUsedBlockHeight()));\n this.setMaxUsedBlockHash(GenUtils.reconcile(this.getMaxUsedBlockHash(), tx.getMaxUsedBlockHash()));\n this.setSignatures(GenUtils.reconcile(this.getSignatures(), tx.getSignatures()));\n this.setUnlockHeight(GenUtils.reconcile(this.getUnlockHeight(), tx.getUnlockHeight()));\n this.setNumConfirmations(GenUtils.reconcile(this.getNumConfirmations(), tx.getNumConfirmations(), {resolveMax: true})); // num confirmations can increase\n \n // merge inputs\n if (tx.getInputs()) {\n for (let merger of tx.getInputs()) {\n let merged = false;\n merger.setTx(this);\n if (!this.getInputs()) this.setInputs([]);\n for (let mergee of this.getInputs()) {\n if (mergee.getKeyImage().getHex() === merger.getKeyImage().getHex()) {\n mergee.merge(merger);\n merged = true;\n break;\n }\n }\n if (!merged) this.getInputs().push(merger);\n }\n }\n \n // merge outputs\n if (tx.getOutputs()) {\n for (let output of tx.getOutputs()) output.setTx(this);\n if (!this.getOutputs()) this.setOutputs(tx.getOutputs());\n else {\n \n // merge outputs if key image or stealth public key present, otherwise append\n for (let merger of tx.getOutputs()) {\n let merged = false;\n merger.setTx(this);\n for (let mergee of this.getOutputs()) {\n if ((merger.getKeyImage() && mergee.getKeyImage().getHex() === merger.getKeyImage().getHex()) ||\n (merger.getStealthPublicKey() && mergee.getStealthPublicKey() === merger.getStealthPublicKey())) {\n mergee.merge(merger);\n merged = true;\n break;\n }\n }\n if (!merged) this.getOutputs().push(merger); // append output\n }\n }\n }\n \n // handle unrelayed -> relayed -> confirmed\n if (this.isConfirmed()) {\n this.setInTxPool(false);\n this.setReceivedTimestamp(undefined);\n this.setLastRelayedTimestamp(undefined);\n } else {\n this.setInTxPool(GenUtils.reconcile(this.inTxPool(), tx.inTxPool(), {resolveTrue: true})); // unrelayed -> tx pool\n this.setReceivedTimestamp(GenUtils.reconcile(this.getReceivedTimestamp(), tx.getReceivedTimestamp(), {resolveMax: false})); // take earliest receive time\n this.setLastRelayedTimestamp(GenUtils.reconcile(this.getLastRelayedTimestamp(), tx.getLastRelayedTimestamp(), {resolveMax: true})); // take latest relay time\n }\n \n return this; // for chaining\n }\n \n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.getIndent(indent) + \"=== TX ===\\n\";\n str += GenUtils.kvLine(\"Tx hash\", this.getHash(), indent);\n str += GenUtils.kvLine(\"Height\", this.getHeight(), indent);\n str += GenUtils.kvLine(\"Version\", this.getVersion(), indent);\n str += GenUtils.kvLine(\"Is miner tx\", this.isMinerTx(), indent);\n str += GenUtils.kvLine(\"Payment ID\", this.getPaymentId(), indent);\n str += GenUtils.kvLine(\"Fee\", this.getFee(), indent);\n str += GenUtils.kvLine(\"Ring size\", this.getRingSize(), indent);\n str += GenUtils.kvLine(\"Relay\", this.getRelay(), indent);\n str += GenUtils.kvLine(\"Is relayed\", this.isRelayed(), indent);\n str += GenUtils.kvLine(\"Is confirmed\", this.isConfirmed(), indent);\n str += GenUtils.kvLine(\"In tx pool\", this.inTxPool(), indent);\n str += GenUtils.kvLine(\"Num confirmations\", this.getNumConfirmations(), indent);\n str += GenUtils.kvLine(\"Unlock height\", this.getUnlockHeight(), indent);\n str += GenUtils.kvLine(\"Last relayed time\", this.getLastRelayedTimestamp(), indent);\n str += GenUtils.kvLine(\"Received time\", this.getReceivedTimestamp(), indent);\n str += GenUtils.kvLine(\"Is double spend\", this.isDoubleSpendSeen(), indent);\n str += GenUtils.kvLine(\"Key\", this.getKey(), indent);\n str += GenUtils.kvLine(\"Full hex\", this.getFullHex(), indent);\n str += GenUtils.kvLine(\"Pruned hex\", this.getPrunedHex(), indent);\n str += GenUtils.kvLine(\"Prunable hex\", this.getPrunableHex(), indent);\n str += GenUtils.kvLine(\"Prunable hash\", this.getPrunableHash(), indent);\n str += GenUtils.kvLine(\"Size\", this.getSize(), indent);\n str += GenUtils.kvLine(\"Weight\", this.getWeight(), indent);\n str += GenUtils.kvLine(\"Output indices\", this.getOutputIndices(), indent);\n str += GenUtils.kvLine(\"Metadata\", this.getMetadata(), indent);\n str += GenUtils.kvLine(\"Extra\", this.getExtra(), indent);\n str += GenUtils.kvLine(\"RCT signatures\", this.getRctSignatures(), indent);\n str += GenUtils.kvLine(\"RCT sig prunable\", this.getRctSigPrunable(), indent);\n str += GenUtils.kvLine(\"Kept by block\", this.isKeptByBlock(), indent);\n str += GenUtils.kvLine(\"Is failed\", this.isFailed(), indent);\n str += GenUtils.kvLine(\"Last failed height\", this.getLastFailedHeight(), indent);\n str += GenUtils.kvLine(\"Last failed hash\", this.getLastFailedHash(), indent);\n str += GenUtils.kvLine(\"Max used block height\", this.getMaxUsedBlockHeight(), indent);\n str += GenUtils.kvLine(\"Max used block hash\", this.getMaxUsedBlockHash(), indent);\n str += GenUtils.kvLine(\"Signatures\", this.getSignatures(), indent);\n if (this.getInputs()) {\n str += GenUtils.kvLine(\"Inputs\", \"\", indent);\n for (let i = 0; i < this.getInputs().length; i++) {\n str += GenUtils.kvLine(i + 1, \"\", indent + 1);\n str += this.getInputs()[i].toString(indent + 2);\n str += '\\n'\n }\n }\n if (this.getOutputs()) {\n str += GenUtils.kvLine(\"Outputs\", \"\", indent);\n for (let i = 0; i < this.getOutputs().length; i++) {\n str += GenUtils.kvLine(i + 1, \"\", indent + 1);\n str += this.getOutputs()[i].toString(indent + 2);\n str += '\\n'\n }\n }\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n\n// default payment id\nMoneroTx.DEFAULT_PAYMENT_ID = \"0000000000000000\";\n\nmodule.exports = MoneroTx;","const assert = require(\"assert\");\nconst BigInteger = require(\"../../common/biginteger\").BigInteger;\nconst GenUtils = require(\"../../common/GenUtils\");\nconst MoneroKeyImage = require(\"./MoneroKeyImage\");\n\n/**\n * Models a Monero transaction output.\n * \n * @class\n */\nclass MoneroOutput {\n \n /**\n * Construct the model.\n * \n * @param {MoneroOutput|object} state is existing state to initialize from (optional)\n */\n constructor(state) {\n \n // initialize internal state\n if (!state) state = {};\n else if (state instanceof MoneroOutput) state = state.toJson();\n else if (typeof state === \"object\") state = Object.assign({}, state);\n else throw new MoneroError(\"state must be a MoneroOutput or JavaScript object\");\n this.state = state;\n \n // deserialize fields if necessary\n if (state.amount !== undefined && !(state.amount instanceof BigInteger)) state.amount = BigInteger.parse(state.amount);\n if (state.keyImage && !(state.keyImage instanceof MoneroKeyImage)) state.keyImage = new MoneroKeyImage(state.keyImage);\n }\n \n getTx() {\n return this.state.tx;\n }\n \n setTx(tx) {\n this.state.tx = tx;\n return this;\n }\n \n getKeyImage() {\n return this.state.keyImage;\n }\n\n setKeyImage(keyImage) {\n assert(keyImage === undefined || keyImage instanceof MoneroKeyImage);\n this.state.keyImage = keyImage;\n return this;\n }\n \n getAmount() {\n return this.state.amount;\n }\n\n setAmount(amount) {\n this.state.amount = amount;\n return this;\n }\n \n getIndex() {\n return this.state.index;\n }\n \n setIndex(index) {\n this.state.index = index;\n return this;\n }\n \n getRingOutputIndices() {\n return this.state.ringOutputIndices;\n }\n \n setRingOutputIndices(ringOutputIndices) {\n this.state.ringOutputIndices = ringOutputIndices;\n return this;\n }\n \n getStealthPublicKey() {\n return this.state.stealthPublicKey;\n }\n \n setStealthPublicKey(stealthPublicKey) {\n this.state.stealthPublicKey = stealthPublicKey;\n return this;\n }\n \n copy() {\n return new MoneroOutput(this);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (this.getAmount()) json.amount = this.getAmount() ? this.getAmount().toString() : undefined;\n if (this.getKeyImage()) json.keyImage = this.getKeyImage() ? this.getKeyImage().toJson() : undefined;\n delete json.tx;\n return json;\n }\n \n merge(output) {\n assert(output instanceof MoneroOutput);\n if (this === output) return this;\n \n // merge txs if they're different which comes back to merging outputs\n if (this.getTx() !== output.getTx()) this.getTx().merge(output.getTx());\n \n // otherwise merge output fields\n else {\n if (this.getKeyImage() === undefined) this.setKeyImage(output.getKeyImage());\n else if (output.getKeyImage() !== undefined) this.getKeyImage().merge(output.getKeyImage());\n this.setAmount(GenUtils.reconcile(this.getAmount(), output.getAmount()));\n this.setIndex(GenUtils.reconcile(this.getIndex(), output.getIndex()));\n }\n\n return this;\n }\n \n toString(indent = 0) {\n let str = \"\";\n if (this.getKeyImage()) {\n str += GenUtils.kvLine(\"Key image\", \"\", indent);\n str += this.getKeyImage().toString(indent + 1) + \"\\n\";\n }\n str += GenUtils.kvLine(\"Amount\", this.getAmount(), indent);\n str += GenUtils.kvLine(\"Index\", this.getIndex(), indent);\n str += GenUtils.kvLine(\"Ring output indices\", this.getRingOutputIndices(), indent);\n str += GenUtils.kvLine(\"Stealth public key\", this.getStealthPublicKey(), indent);\n return str === \"\" ? str : str.slice(0, str.length - 1); // strip last newline\n }\n}\n\nmodule.exports = MoneroOutput;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\nconst MoneroOutputWallet = require(\"./MoneroOutputWallet\");\n\n/**\n * Configuration to query wallet outputs.\n * \n * @extends {MoneroOutputWallet}\n */\nclass MoneroOutputQuery extends MoneroOutputWallet {\n \n /**\n *

Construct the output query.

\n * \n *

Example:

\n * \n * \n * // get available outputs in account 0 with a minimum amount
\n * let outputs = await wallet.getOutputs({
\n *    isSpent: false,
\n *    isLocked: false,
\n *    accountIndex: 0,
\n *    minAmount: new BigInteger(\"750000\")
\n * });\n *
\n * \n *

All configuration is optional. All outputs are returned except those that don't meet criteria defined in this query.

\n * \n * @param {object} config - output query configuration (optional)\n * @param {int} config.accountIndex - get outputs in this account index\n * @param {int} config.subaddressIndex - get outputs in this subaddress index\n * @param {int[]} config.subaddressIndices - get outputs in these subaddress indices\n * @param {BigInteger} config.amount - get outputs with this amount\n * @param {BigInteger} config.minAmount - get outputs with amount greater than or equal to this amount\n * @param {BigInteger} config.maxAmount - get outputs with amount less than or equal to this amount\n * @param {boolean} config.isLocked - get locked xor unlocked outputs\n * @param {boolean} config.isSpent - get spent xor unspent outputs\n * @param {object|MoneroKeyImage} config.keyImage - get outputs with a key image matching fields defined in this key image\n * @param {string} config.keyImage.hex - get outputs with this key image hex\n * @param {string} config.keyImage.signature - get outputs with this key image signature\n * @param {object|MoneroTxQuery} config.txQuery - get outputs whose tx match this tx query\n */\n constructor(config) {\n super(config);\n \n // deserialize if necessary\n const MoneroTxQuery = require(\"./MoneroTxQuery\");\n if (this.state.minAmount !== undefined && !(this.state.minAmount instanceof BigInteger)) this.state.minAmount = BigInteger.parse(this.state.minAmount);\n if (this.state.maxAmount !== undefined && !(this.state.maxAmount instanceof BigInteger)) this.state.maxAmount = BigInteger.parse(this.state.maxAmount);\n if (this.state.txQuery && !(this.state.txQuery instanceof MoneroTxQuery)) this.state.txQuery = new MoneroTxQuery(this.state.txQuery);\n if (this.state.txQuery) this.state.txQuery.setOutputQuery(this);\n }\n \n copy() {\n return new MoneroOutputQuery(this);\n }\n \n toJson() {\n let json = Object.assign({}, this.state, super.toJson());\n if (this.getMinAmount()) json.minAmount = this.getMinAmount().toString();\n if (this.getMaxAmount()) json.maxAmount = this.getMaxAmount().toString();\n delete json.txQuery;\n return json;\n }\n \n getMinAmount() {\n return this.state.minAmount;\n }\n\n setMinAmount(minAmount) {\n this.state.minAmount = minAmount;\n return this;\n }\n\n getMaxAmount() {\n return this.state.maxAmount;\n }\n\n setMaxAmount(maxAmount) {\n this.state.maxAmount = maxAmount;\n return this;\n }\n \n getTxQuery() {\n return this.state.txQuery;\n }\n \n setTxQuery(txQuery) {\n this.state.txQuery = txQuery;\n if (txQuery) txQuery.state.outputQuery = this;\n return this;\n }\n \n getSubaddressIndices() {\n return this.state.subaddressIndices;\n }\n \n setSubaddressIndices(subaddressIndices) {\n this.state.subaddressIndices = subaddressIndices;\n return this;\n }\n \n /**\n * Indicates if the this query will fetch locked outputs, unlocked outputs, or both (null).\n * \n * @return true if locked outputs queried, false of unlocked outputs queried, undefined if both\n */\n isLocked() {\n if (this.state.txQuery === undefined) return undefined;\n return txQuery.isLocked();\n }\n \n /**\n * Convenience method to query outputs by the locked state of their tx.\n * \n * @param isLocked specifies if the output's tx must be locked or unlocked (optional)\n * @return {MoneroOutputQuery} this query for chaining\n */\n setIsLocked(isLocked) {\n const MoneroTxQuery = require(\"./MoneroTxQuery\");\n if (this.state.txQuery === undefined) this.state.txQuery = new MoneroTxQuery();\n this.state.txQuery.setIsLocked(isLocked);\n return this;\n }\n \n meetsCriteria(output, queryParent) {\n if (!(output instanceof MoneroOutputWallet)) throw new Error(\"Output not given to MoneroOutputQuery.meetsCriteria(output)\");\n if (queryParent === undefined) queryParent = true;\n \n // filter on output\n if (this.getAccountIndex() !== undefined && this.getAccountIndex() !== output.getAccountIndex()) return false;\n if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() !== output.getSubaddressIndex()) return false;\n if (this.getAmount() !== undefined && this.getAmount().compare(output.getAmount()) !== 0) return false;\n if (this.isSpent() !== undefined && this.isSpent() !== output.isSpent()) return false;\n \n // filter on output's key image\n if (this.getKeyImage() !== undefined) {\n if (output.getKeyImage() === undefined) return false;\n if (this.getKeyImage().getHex() !== undefined && this.getKeyImage().getHex() !== output.getKeyImage().getHex()) return false;\n if (this.getKeyImage().getSignature() !== undefined && this.getKeyImage().getSignature() !== output.getKeyImage().getSignature()) return false;\n }\n \n // filter on extensions\n if (this.getSubaddressIndices() !== undefined && !this.getSubaddressIndices().includes(output.getSubaddressIndex())) return false;\n \n // filter with tx query\n if (this.getTxQuery() && !this.getTxQuery().meetsCriteria(output.getTx(), false)) return false;\n \n // filter on remaining fields\n if (this.getMinAmount() !== undefined && (output.getAmount() === undefined || output.getAmount().compare(this.getMinAmount()) < 0)) return false;\n if (this.getMaxAmount() !== undefined && (output.getAmount() === undefined || output.getAmount().compare(this.getMaxAmount()) > 0)) return false;\n \n // output meets query\n return true;\n }\n}\n\nMoneroOutputQuery._EMPTY_OUTPUT = new MoneroOutputWallet();\n\nmodule.exports = MoneroOutputQuery;","const MoneroIncomingTransfer = require(\"./MoneroIncomingTransfer\");\nconst MoneroOutgoingTransfer = require(\"./MoneroOutgoingTransfer\");\nconst MoneroTransfer = require(\"./MoneroTransfer\");\nconst MoneroError = require(\"../../common/MoneroError\")\n\n/**\n * Configuration to query wallet transfers.\n * \n * @extends {MoneroTransfer}\n */\nclass MoneroTransferQuery extends MoneroTransfer {\n \n /**\n *

Construct the transfer query.

\n * \n *

Example:

\n * \n * \n * // get incoming transfers to account 0, subaddress 1
\n * let transfers = await wallet.getTransfers({
\n *    accountIndex: 0,
\n *    subaddressIndex: 0
\n * });\n *
\n * \n *

All configuration is optional. All transfers are returned except those that don't meet criteria defined in this query.

\n * \n * @param {object} config - transfer query configuration (optional)\n * @param {BigInteger} config.amount - get transfers with this amount\n * @param {int} config.accountIndex - get transfers to/from this account index\n * @param {int} config.subaddressIndex - get transfers to/from this subaddress index\n * @param {int[]} config.subaddressIndices - get transfers to/from these subaddress indices\n * @param {string} config.address - get transfers to/from this wallet address\n * @param {string[]} config.addresses - get transfers to/from these wallet addresses\n * @param {boolean} config.isIncoming - get transfers which are incoming if true\n * @param {boolean} config.isOutgoing - get transfers which are outgoing if true\n * @param {boolean} config.hasDestinations - get transfers with known destinations if true (destinations are only stored locally with the wallet)\n * @param {object|MoneroTxQuery} config.txQuery - get transfers whose tx match this tx query\n */\n constructor(config) {\n super(config);\n \n // deserialize if necessary\n const MoneroTxQuery = require(\"./MoneroTxQuery\");\n if (this.state.txQuery && !(this.state.txQuery instanceof MoneroTxQuery)) this.state.txQuery = new MoneroTxQuery(this.state.txQuery);\n if (this.state.txQuery) this.state.txQuery.setTransferQuery(this);\n \n // alias isOutgoing to isIncoming\n if (this.state.isOutgoing !== undefined) this.state.isIncoming = !this.state.isOutgoing;\n \n // validate state\n this._validate();\n }\n \n copy() {\n return new MoneroTransferQuery(this);\n }\n \n toJson() {\n let json = Object.assign({}, this.state, super.toJson());\n delete json.txQuery;\n return json;\n }\n \n getTxQuery() {\n return this.state.txQuery;\n }\n \n setTxQuery(txQuery) {\n this.state.txQuery = txQuery;\n if (txQuery) txQuery.state.transferQuery = this;\n return this;\n }\n \n isIncoming() {\n return this.state.isIncoming;\n }\n\n setIsIncoming(isIncoming) {\n this.state.isIncoming = isIncoming;\n return this;\n }\n \n isOutgoing() {\n return this.state.isIncoming === undefined ? undefined : !this.state.isIncoming;\n }\n \n setIsOutgoing(isOutgoing) {\n this.state.isIncoming = isOutgoing === undefined ? undefined : !isOutgoing;\n return this;\n }\n \n getAddress() {\n return this.state.address;\n }\n\n setAddress(address) {\n this.state.address = address;\n return this;\n }\n \n getAddresses() {\n return this.state.addresses;\n }\n\n setAddresses(addresses) {\n this.state.addresses = addresses;\n return this;\n }\n \n getSubaddressIndex() {\n return this.state.subaddressIndex;\n }\n \n setSubaddressIndex(subaddressIndex) {\n this.state.subaddressIndex = subaddressIndex;\n this._validate();\n return this;\n }\n \n getSubaddressIndices() {\n return this.state.subaddressIndices;\n }\n \n setSubaddressIndices(subaddressIndices) {\n this.state.subaddressIndices = subaddressIndices;\n this._validate();\n return this;\n }\n \n getDestinations() {\n return this.state.destinations;\n }\n \n setDestinations(destinations) {\n this.state.destinations = destinations;\n return this;\n }\n \n hasDestinations() {\n return this.state.hasDestinations;\n }\n \n setHasDestinations(hasDestinations) {\n this.state.hasDestinations = hasDestinations;\n return this;\n }\n \n /**\n * Convenience method to query outputs by the locked state of their tx.\n * \n * @param isLocked specifies if the output's tx must be locked or unlocked (optional)\n * @return {MoneroOutputQuery} this query for chaining\n */\n setIsLocked(isLocked) {\n if (this.state.txQuery === undefined) this.state.txQuery = new MoneroTxQuery();\n this.state.txQuery.setIsLocked(isLocked);\n return this;\n }\n \n meetsCriteria(transfer, queryParent) {\n if (!(transfer instanceof MoneroTransfer)) throw new Error(\"Transfer not given to MoneroTransferQuery.meetsCriteria(transfer)\");\n if (queryParent === undefined) queryParent = true;\n \n // filter on common fields\n if (this.isIncoming() !== undefined && this.isIncoming() !== transfer.isIncoming()) return false;\n if (this.isOutgoing() !== undefined && this.isOutgoing() !== transfer.isOutgoing()) return false;\n if (this.getAmount() !== undefined && this.getAmount().compare(transfer.getAmount()) !== 0) return false;\n if (this.getAccountIndex() !== undefined && this.getAccountIndex() !== transfer.getAccountIndex()) return false;\n \n // filter on incoming fields\n if (transfer instanceof MoneroIncomingTransfer) {\n if (this.hasDestinations()) return false;\n if (this.getAddress() !== undefined && this.getAddress() !== transfer.getAddress()) return false;\n if (this.getAddresses() !== undefined && !this.getAddresses().includes(transfer.getAddress())) return false;\n if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() !== transfer.getSubaddressIndex()) return false;\n if (this.getSubaddressIndices() !== undefined && !this.getSubaddressIndices().includes(transfer.getSubaddressIndex())) return false;\n }\n\n // filter on outgoing fields\n else if (transfer instanceof MoneroOutgoingTransfer) {\n \n // filter on addresses which must have overlap\n if (this.getAddress() !== undefined && (transfer.getAddresses() === undefined || !transfer.getAddresses().includes(this.getAddress()))) return false; // TODO: will filter all transfers that don't contain addresses (outgoing txs might not have this field initialized)\n if (this.getAddresses() !== undefined) {\n if (!transfer.getAddresses()) return false;\n if (!this.getAddresses().some(address => transfer.getAddresses().includes(address))) return false;\n }\n \n // filter on subaddress indices\n if (this.getSubaddressIndex() !== undefined && (transfer.getSubaddressIndices() === undefined || !transfer.getSubaddressIndices().includes(this.getSubaddressIndex()))) return false;\n if (this.getSubaddressIndices() !== undefined) {\n if (!transfer.getSubaddressIndices()) return false;\n if (!this.getSubaddressIndices().some(subaddressIdx => transfer.getSubaddressIndices().includes(subaddressIdx))) return false;\n }\n \n // filter on having destinations\n if (this.hasDestinations() !== undefined) {\n if (this.hasDestinations() && transfer.getDestinations() === undefined) return false;\n if (!this.hasDestinations() && transfer.getDestinations() !== undefined) return false;\n }\n \n // filter on destinations TODO: start with test for this\n// if (this.getDestionations() !== undefined && this.getDestionations() !== transfer.getDestionations()) return false;\n }\n \n // otherwise invalid type\n else throw new Error(\"Transfer must be MoneroIncomingTransfer or MoneroOutgoingTransfer\");\n \n // filter with tx filter\n if (queryParent && this.getTxQuery() !== undefined && !this.getTxQuery().meetsCriteria(transfer.getTx())) return false; \n return true;\n }\n \n _validate() {\n if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() < 0) throw new MoneroError(\"Subaddress index must be >= 0\");\n if (this.getSubaddressIndices() !== undefined) for (let subaddressIdx of this.getSubaddressIndices()) if (subaddressIdx < 0) throw new MoneroError(\"Subaddress indices must be >= 0\");\n }\n}\n\nmodule.exports = MoneroTransferQuery;","const assert = require(\"assert\");\nconst GenUtils = require(\"../../common/GenUtils\");\nconst MoneroTransfer = require(\"./MoneroTransfer\");\n\n/**\n * Models an incoming transfer of funds to the wallet.\n * \n * @extends {MoneroTransfer}\n */\nclass MoneroIncomingTransfer extends MoneroTransfer {\n \n /**\n * Construct the model.\n * \n * @param {MoneroTransfer|object} state is existing state to initialize from (optional)\n */\n constructor(state) {\n super(state);\n }\n \n isIncoming() {\n return true;\n }\n \n getSubaddressIndex() {\n return this.state.subaddressIndex;\n }\n \n setSubaddressIndex(subaddressIndex) {\n this.state.subaddressIndex = subaddressIndex;\n return this;\n }\n \n getAddress() {\n return this.state.address;\n }\n\n setAddress(address) {\n this.state.address = address;\n return this;\n }\n \n /**\n * Return how many confirmations till it's not economically worth re-writing the chain.\n * That is, the number of confirmations before the transaction is highly unlikely to be\n * double spent or overwritten and may be considered settled, e.g. for a merchant to trust\n * as finalized.\n * \n * @return {number} is the number of confirmations before it's not worth rewriting the chain\n */\n getNumSuggestedConfirmations() {\n return this.state.numSuggestedConfirmations;\n }\n \n setNumSuggestedConfirmations(numSuggestedConfirmations) {\n this.state.numSuggestedConfirmations = numSuggestedConfirmations;\n return this;\n }\n\n copy() {\n return new MoneroIncomingTransfer(this.toJson());\n }\n \n /**\n * Updates this transaction by merging the latest information from the given\n * transaction.\n * \n * Merging can modify or build references to the transfer given so it\n * should not be re-used or it should be copied before calling this method.\n * \n * @param {MoneroIncomingTransfer} transfer is the transfer to merge into this one\n */\n merge(transfer) {\n super.merge(transfer);\n assert(transfer instanceof MoneroIncomingTransfer);\n if (this === transfer) return this;\n this.setSubaddressIndex(GenUtils.reconcile(this.getSubaddressIndex(), transfer.getSubaddressIndex()));\n this.setAddress(GenUtils.reconcile(this.getAddress(), transfer.getAddress()));\n this.setNumSuggestedConfirmations(GenUtils.reconcile(this.getNumSuggestedConfirmations(), transfer.getNumSuggestedConfirmations(), {resolveMax: false}));\n return this;\n }\n \n toString() {\n return this.toString(0);\n }\n \n toString(indent) {\n let str = super.toString(indent) + \"\\n\";\n str += GenUtils.kvLine(\"Subaddress index\", this.getSubaddressIndex(), indent);\n str += GenUtils.kvLine(\"Address\", this.getAddress(), indent);\n str += GenUtils.kvLine(\"Num suggested confirmations\", this.getNumSuggestedConfirmations(), indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n\nmodule.exports = MoneroIncomingTransfer;","const assert = require(\"assert\");\nconst BigInteger = require(\"../../common/biginteger\").BigInteger;\nconst GenUtils = require(\"../../common/GenUtils\");\n\n/**\n * Models a base transfer of funds to or from the wallet.\n * \n * @class\n */\nclass MoneroTransfer {\n \n /**\n * Construct the model.\n * \n * @param {MoneroTransfer|object} state is existing state to initialize from (optional)\n */\n constructor(state) {\n \n // initialize internal state\n if (!state) state = {};\n else if (state instanceof MoneroTransfer) state = state.toJson();\n else if (typeof state === \"object\") state = Object.assign({}, state);\n else throw new MoneroError(\"state must be a MoneroTransfer or JavaScript object\");\n this.state = state;\n \n // deserialize fields if necessary\n if (state.amount !== undefined && !(state.amount instanceof BigInteger)) state.amount = BigInteger.parse(state.amount);\n \n // validate state\n this._validate();\n }\n \n copy() {\n return new MoneroTransfer(this);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (this.getAmount()) json.amount = this.getAmount().toString()\n delete json.tx; // parent tx is not serialized\n return json;\n }\n \n getTx() {\n return this.state.tx;\n }\n \n setTx(tx) {\n this.state.tx = tx;\n return this;\n }\n \n isOutgoing() {\n let isIncoming = this.isIncoming();\n assert(typeof isIncoming === \"boolean\");\n return !isIncoming;\n }\n \n isIncoming() {\n throw new Error(\"Subclass must implement\");\n }\n\n getAccountIndex() {\n return this.state.accountIndex;\n }\n\n setAccountIndex(accountIndex) {\n this.state.accountIndex = accountIndex;\n this._validate();\n return this;\n }\n\n getAmount() {\n return this.state.amount;\n }\n\n setAmount(amount) {\n this.state.amount = amount;\n return this;\n }\n \n /**\n * Updates this transaction by merging the latest information from the given\n * transaction.\n * \n * Merging can modify or build references to the transfer given so it\n * should not be re-used or it should be copied before calling this method.\n * \n * @param transfer is the transfer to merge into this one\n * @return {MoneroTransfer} the merged transfer\n */\n merge(transfer) {\n assert(transfer instanceof MoneroTransfer);\n if (this === transfer) return this;\n \n // merge transactions if they're different which comes back to merging transfers\n if (this.getTx() !== transfer.getTx()) {\n this.getTx().merge(transfer.getTx());\n return this;\n }\n \n // otherwise merge transfer fields\n this.setAccountIndex(GenUtils.reconcile(this.getAccountIndex(), transfer.getAccountIndex()));\n \n // TODO monero core: failed tx in pool (after testUpdateLockedDifferentAccounts()) causes non-originating saved wallets to return duplicate incoming transfers but one has amount of 0\n if (this.getAmount() !== undefined && transfer.getAmount() !== undefined && this.getAmount().compare(transfer.getAmount()) !== 0 && (this.getAmount().compare(BigInteger.parse(\"0\")) === 0 || transfer.getAmount().compare(BigInteger.parse(\"0\")) === 0)) {\n //throw new Error(\"WARNING: monero core returning transfers with 0 amount/numSuggestedConfirmations\");\n } else {\n this.setAmount(GenUtils.reconcile(this.getAmount(), transfer.getAmount()));\n }\n \n return this;\n }\n \n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.kvLine(\"Is incoming\", this.isIncoming(), indent);\n str += GenUtils.kvLine(\"Account index\", this.getAccountIndex(), indent);\n str += GenUtils.kvLine(\"Amount\", this.getAmount() ? this.getAmount().toString() : undefined, indent);\n return str === \"\" ? str : str.slice(0, str.length - 1); // strip last newline\n }\n \n _validate() {\n if (this.getAccountIndex() !== undefined && this.getAccountIndex() < 0) throw new MoneroError(\"Account index must be >= 0\");\n }\n}\n\nmodule.exports = MoneroTransfer;","const assert = require(\"assert\");\nconst GenUtils = require(\"../../common/GenUtils\");\nconst MoneroDestination = require(\"./MoneroDestination\");\nconst MoneroTransfer = require(\"./MoneroTransfer\");\n\n/**\n * Models an outgoing transfer of funds from the wallet.\n * \n * @extends {MoneroTransfer}\n */\nclass MoneroOutgoingTransfer extends MoneroTransfer {\n\n /**\n * Construct the model.\n * \n * @param {MoneroOutgoingTranser|object} state is existing state to initialize from (optional)\n */\n constructor(state) {\n super(state);\n state = this.state;\n \n // deserialize destinations\n if (state.destinations) {\n for (let i = 0; i < state.destinations.length; i++) {\n if (!(state.destinations[i] instanceof MoneroDestination)) state.destinations[i] = new MoneroDestination(state.destinations[i]);\n }\n }\n }\n \n isIncoming() {\n return false;\n }\n \n getSubaddressIndices() {\n return this.state.subaddressIndices;\n }\n\n setSubaddressIndices(subaddressIndices) {\n this.state.subaddressIndices = subaddressIndices;\n return this;\n }\n \n getAddresses() {\n return this.state.addresses;\n }\n\n setAddresses(addresses) {\n this.state.addresses = addresses;\n return this;\n }\n\n getDestinations() {\n return this.state.destinations;\n }\n \n setDestinations(destinations) {\n this.state.destinations = destinations;\n return this;\n }\n \n copy() {\n return new MoneroOutgoingTransfer(this);\n }\n \n toJson() {\n let json = Object.assign({}, this.state, super.toJson()); // merge json onto inherited state\n if (this.getDestinations()) {\n json.destinations = [];\n for (let destination of this.getDestinations()) json.destinations.push(destination.toJson());\n }\n delete json.tx; // parent tx is not serialized\n return json;\n }\n \n /**\n * Updates this transaction by merging the latest information from the given\n * transaction.\n * \n * Merging can modify or build references to the transfer given so it\n * should not be re-used or it should be copied before calling this method.\n * \n * @param transfer is the transfer to merge into this one\n */\n merge(transfer) {\n super.merge(transfer);\n assert(transfer instanceof MoneroOutgoingTransfer);\n if (this === transfer) return this;\n this.setSubaddressIndices(GenUtils.reconcile(this.getSubaddressIndices(), transfer.getSubaddressIndices()));\n this.setAddresses(GenUtils.reconcile(this.getAddresses(), transfer.getAddresses()));\n this.setDestinations(GenUtils.reconcile(this.getDestinations(), transfer.getDestinations()));\n return this;\n }\n\n toString(indent = 0) {\n let str = super.toString(indent) + \"\\n\";\n str += GenUtils.kvLine(\"Subaddress indices\", this.getSubaddressIndices(), indent);\n str += GenUtils.kvLine(\"Addresses\", this.getAddresses(), indent);\n if (this.getDestinations()) {\n str += GenUtils.kvLine(\"Destinations\", \"\", indent);\n for (let i = 0; i < this.getDestinations().length; i++) {\n str += GenUtils.kvLine(i + 1, \"\", indent + 1);\n str += this.getDestinations()[i].toString(indent + 2) + \"\\n\";\n }\n }\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n\nmodule.exports = MoneroOutgoingTransfer;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\nconst GenUtils = require(\"../../common/GenUtils\");\n\n/**\n * Models an outgoing transfer destination.\n */\nclass MoneroDestination {\n \n /**\n * Construct the model.\n * \n * @param {MoneroDestination|object|string} stateOrAddress is a MoneroDestination, JS object, or hex string to initialize from (optional)\n * @param {BigInteger|string} amount - the destination amount\n */\n constructor(stateOrAddress, amount) {\n \n // initialize internal state\n if (!stateOrAddress) this.state = {};\n else if (stateOrAddress instanceof MoneroDestination) this.state = stateOrAddress.toJson();\n else if (typeof stateOrAddress === \"object\") this.state = Object.assign({}, stateOrAddress);\n else if (typeof stateOrAddress === \"string\") {\n this.state = {};\n this.setAddress(stateOrAddress);\n this.setAmount(amount);\n } else {\n throw new MoneroError(\"stateOrAddress must be a MoneroDestination, JavaScript object, or hex string\");\n }\n \n // deserialize amount \n if (amount) this.state.amount = amount;\n if (this.state.amount !== undefined && !(this.state.amount instanceof BigInteger)) this.state.amount = BigInteger.parse(this.state.amount);\n }\n \n getAddress() {\n return this.state.address;\n }\n\n setAddress(address) {\n this.state.address = address;\n return this;\n }\n \n getAmount() {\n return this.state.amount;\n }\n\n setAmount(amount) {\n this.state.amount = amount;\n return this;\n }\n\n copy() {\n return new MoneroDestination(this);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (this.getAmount()) json.amount = this.getAmount().toString();\n return json;\n }\n \n toString(indent = 0) {\n let str = GenUtils.kvLine(\"Address\", this.getAddress(), indent);\n str += GenUtils.kvLine(\"Amount\", this.getAmount() ? this.getAmount().toString() : undefined, indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n\nmodule.exports = MoneroDestination;","/**\n * Models a Monero version.\n */\nclass MoneroVersion {\n \n /**\n * Construct the model.\n * \n * @param number is the version number\n * @param isRelease indicates if this version is a release\n */\n constructor(number, isRelease) {\n this.state = {};\n this.state.number = number;\n this.state.isRelease = isRelease;\n }\n\n getNumber() {\n return this.state.number;\n }\n\n setNumber(number) {\n this.state.number = number;\n return this;\n }\n\n isRelease() {\n return this.state.isRelease;\n }\n\n setIsRelease(isRelease) {\n this.state.isRelease = isRelease;\n return this;\n }\n \n copy() {\n return new MoneroKeyImage(this);\n }\n \n toJson() {\n return Object.assign({}, this.state);\n }\n}\n\nmodule.exports = MoneroVersion;","const GenUtils = require(\"../../common/GenUtils\");\nconst MoneroNetworkType = require(\"../../daemon/model/MoneroNetworkType\");\nconst MoneroRpcConnection = require(\"../../common/MoneroRpcConnection\");\n\n/**\n * Configuration to create a Monero wallet.\n */\nclass MoneroWalletConfig {\n \n /**\n * Construct a configuration to open or create a wallet.\n * \n * @param {object|MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object\n * @param {string} config.path - path of the wallet to open or create\n * @param {string} config.password - password of the wallet to open\n * @param {string|number} config.networkType - network type of the wallet to open (one of \"mainnet\", \"testnet\", \"stagenet\" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)\n * @param {string} config.serverUri - uri of the wallet's server (optional)\n * @param {string} config.serverUsername - username of the wallet's server (optional)\n * @param {string} config.serverPassword - password of the wallet's server (optional)\n * @param {boolean} config.rejectUnauthorized - reject self-signed server certificates if true (defaults to true)\n * @param {MoneroRpcConnection|object} config.server - MoneroRpcConnection or equivalent JS object configuring the server connection (optional)\n * @param {Uint8Array} config.keysData - wallet keys data to open (optional)\n * @param {Uint8Array} config.cacheData - wallet cache data to open (optional)\n * @param {boolean} config.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default: false)\n * @param {fs} config.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)\n * @param {boolean} config.saveCurrent - specifies if the current RPC wallet should be saved before being closed\n */\n constructor(config) {\n \n // initialize internal config\n if (!config) config = {};\n else if (config instanceof MoneroWalletConfig) config = config.toJson();\n else if (typeof config === \"object\") config = Object.assign({}, config);\n else throw new MoneroError(\"config must be a MoneroWalletConfig or JavaScript object\");\n this.config = config;\n \n // normalize config\n this.setNetworkType(config.networkType);\n if (config.server) this.setServer(config.server);\n delete this.config.server;\n \n // check for unsupported fields\n for (let key of Object.keys(this.config)) {\n if (!GenUtils.arrayContains(MoneroWalletConfig.SUPPORTED_FIELDS, key)) {\n throw new MoneroError(\"Wallet config includes unsupported field: '\" + key + \"'\");\n }\n }\n }\n \n toJson() {\n return Object.assign({}, this.config);\n }\n \n getPath() {\n return this.config.path;\n }\n \n setPath(path) {\n this.config.path = path;\n return this;\n }\n \n getPassword() {\n return this.config.password;\n }\n \n setPassword(password) {\n this.config.password = password;\n return this;\n }\n \n getNetworkType() {\n return this.config.networkType;\n }\n \n setNetworkType(networkTypeOrStr) {\n this.config.networkType = typeof networkTypeOrStr === \"string\" ? MoneroNetworkType.parse(networkTypeOrStr) : networkTypeOrStr;\n return this;\n }\n \n getServer() {\n return !this.config.serverUri ? undefined : new MoneroRpcConnection({uri: this.config.serverUri, username: this.config.serverUsername, password: this.config.serverPassword, rejectUnauthorized: this.config.rejectUnauthorized})\n }\n \n setServer(server) {\n if (server && !(server instanceof MoneroRpcConnection)) server = new MoneroRpcConnection(server);\n this.config.serverUri = server === undefined ? undefined : server.getUri();\n this.config.serverUsername = server === undefined ? undefined : server.getUsername();\n this.config.serverPassword = server === undefined ? undefined : server.getPassword();\n this.config.rejectUnauthorized = server === undefined ? undefined : server.getRejectUnauthorized();\n return this;\n }\n \n getServerUri() {\n return this.config.serverUri;\n }\n \n setServerUri(serverUri) {\n this.config.serverUri = serverUri;\n return this;\n }\n \n getServerUsername() {\n return this.config.serverUsername;\n }\n \n setServerUsername(serverUsername) {\n this.config.serverUsername = serverUsername;\n return this;\n }\n \n getServerPassword() {\n return this.config.serverPassword;\n }\n \n setServerPassword(serverPassword) {\n this.config.serverPassword = serverPassword;\n return this;\n }\n \n getRejectUnauthorized() {\n return this.config.rejectUnauthorized;\n }\n \n setRejectUnauthorized(rejectUnauthorized) {\n this.config.rejectUnauthorized = rejectUnauthorized;\n return this;\n }\n \n getMnemonic() {\n return this.config.mnemonic;\n }\n \n setMnemonic(mnemonic) {\n this.config.mnemonic = mnemonic;\n return this;\n }\n \n getSeedOffset() {\n return this.config.seedOffset;\n }\n \n setSeedOffset(seedOffset) {\n this.config.seedOffset = seedOffset;\n return this;\n }\n \n getPrimaryAddress() {\n return this.config.primaryAddress;\n }\n \n setPrimaryAddress(primaryAddress) {\n this.config.primaryAddress = primaryAddress;\n return this;\n }\n \n getPrivateViewKey() {\n return this.config.privateViewKey;\n }\n \n setPrivateViewKey(privateViewKey) {\n this.config.privateViewKey = privateViewKey;\n return this;\n }\n \n getPrivateSpendKey() {\n return this.config.privateSpendKey;\n }\n \n setPrivateSpendKey(privateSpendKey) {\n this.config.privateSpendKey = privateSpendKey;\n return this;\n }\n \n getRestoreHeight() {\n return this.config.restoreHeight;\n }\n \n setRestoreHeight(restoreHeight) {\n this.config.restoreHeight = restoreHeight;\n return this;\n }\n \n getLanguage() {\n return this.config.language;\n }\n \n setLanguage(language) {\n this.config.language = language;\n return this;\n }\n \n getSaveCurrent() {\n return this.config.saveCurrent;\n }\n \n setSaveCurrent(saveCurrent) {\n this.config.saveCurrent = saveCurrent;\n return this;\n }\n \n getProxyToWorker() {\n return this.config.proxyToWorker;\n }\n \n setProxyToWorker(proxyToWorker) {\n this.config.proxyToWorker = proxyToWorker;\n return this;\n }\n \n getFs() {\n return this.config.fs;\n }\n \n setFs(fs) {\n this.config.fs = fs;\n return this;\n }\n \n getKeysData() {\n return this.config.keysData;\n }\n \n setKeysData(keysData) {\n this.config.keysData = keysData;\n return this;\n }\n \n getCacheData() {\n return this.config.cacheData;\n }\n \n setCacheData(cacheData) {\n this.config.cacheData = cacheData;\n return this;\n }\n}\n\nMoneroWalletConfig.SUPPORTED_FIELDS = [\"path\", \"password\", \"networkType\", \"serverUri\", \"serverUsername\", \"serverPassword\", \"rejectUnauthorized\", \"mnemonic\", \"seedOffset\", \"primaryAddress\", \"privateViewKey\", \"privateSpendKey\", \"restoreHeight\", \"language\", \"saveCurrent\", \"proxyToWorker\", \"fs\", \"keysData\", \"cacheData\"];\n\nmodule.exports = MoneroWalletConfig;","const assert = require(\"assert\");\nconst MoneroBlock = require(\"../daemon/model/MoneroBlock\");\nconst MoneroError = require(\"../common/MoneroError\");\nconst MoneroOutputQuery = require(\"./model/MoneroOutputQuery\");\nconst MoneroTransferQuery = require(\"./model/MoneroTransferQuery\");\nconst MoneroTxConfig = require(\"./model/MoneroTxConfig\");\nconst MoneroTxQuery = require(\"./model/MoneroTxQuery\");\n\n/**\n * Copyright (c) woodser\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Monero wallet interface and default implementations.\n * \n * @interface\n */\nclass MoneroWallet {\n \n /**\n * Indicates if the wallet is view-only, meaning it does have the private\n * spend key and can therefore only observe incoming outputs.\n * \n * @return {bool} true if the wallet is view-only, false otherwise\n */\n async isViewOnly() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Set the wallet's daemon connection.\n * \n * @param {string|MoneroRpcConnection} uriOrConnection - daemon's URI or connection (defaults to offline)\n * @param {string} username - username to authenticate with the daemon (optional)\n * @param {string} password - password to authenticate with the daemon (optional)\n */\n async setDaemonConnection(uriOrConnection, username, password) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the wallet's daemon connection.\n * \n * @return {MoneroRpcConnection} the wallet's daemon connection\n */\n async getDaemonConnection() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Indicates if the wallet is connected to daemon.\n * \n * @return {boolean} true if the wallet is connected to a daemon, false otherwise\n */\n async isConnected() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Gets the version of the wallet.\n * \n * @return {MoneroVersion} the version of the wallet\n */\n async getVersion() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the wallet's path.\n * \n * @return {string} the path the wallet can be opened with\n */\n async getPath() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the wallet's mnemonic phrase derived from the seed.\n * \n * @return {string} the wallet's mnemonic phrase\n */\n async getMnemonic() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the language of the wallet's mnemonic phrase.\n * \n * @return {string} the language of the wallet's mnemonic phrase\n */\n async getMnemonicLanguage() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the wallet's private view key.\n * \n * @return {string} the wallet's private view key\n */\n async getPrivateViewKey() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the wallet's private spend key.\n * \n * @return {string} the wallet's private spend key\n */\n async getPrivateSpendKey() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the wallet's public view key.\n * \n * @return {string} the wallet's public view key\n */\n async getPublicViewKey() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the wallet's public spend key.\n * \n * @return {string} the wallet's public spend key\n */\n async getPublicSpendKey() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the wallet's primary address.\n * \n * @return {string} the wallet's primary address\n */\n async getPrimaryAddress() {\n return await this.getAddress(0, 0);\n }\n \n /**\n * Get the address of a specific subaddress.\n * \n * @param {int} accountIdx - the account index of the address's subaddress\n * @param {int} subaddressIdx - the subaddress index within the account\n * @return {string} the receive address of the specified subaddress\n */\n async getAddress(accountIdx, subaddressIdx) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the account and subaddress index of the given address.\n * \n * @param {string} address - address to get the account and subaddress index from\n * @return {MoneroSubaddress} the account and subaddress indices\n */\n async getAddressIndex(address) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get an integrated address based on this wallet's primary address and the\n * given payment ID. Generates a random payment ID if none is given.\n * \n * @param {string} paymentId - payment ID to generate an integrated address from (randomly generated if undefined)\n * @return {MoneroIntegratedAddress} the integrated address\n */\n async getIntegratedAddress(paymentId) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Decode an integrated address to get its standard address and payment id.\n * \n * @param {string} integratedAddress - integrated address to decode\n * @return {MoneroIntegratedAddress} the decoded integrated address including standard address and payment id\n */\n async decodeIntegratedAddress(integratedAddress) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the height of the last block processed by the wallet (its index + 1).\n * \n * @return {int} the height of the last block processed by the wallet\n */\n async getHeight() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the blockchain's height.\n * \n * @return {int} the blockchain's height\n */\n async getDaemonHeight() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the blockchain's height by date as a conservative estimate for scanning.\n * \n * @param {int} year - year of the height to get\n * @param {int} month - month of the height to get as a number between 1 and 12\n * @param {int} day - day of the height to get as a number between 1 and 31\n * @return the blockchain's approximate height at the given date\n */\n async getHeightByDate(year, month, day) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Synchronize the wallet with the daemon as a one-time synchronous process.\n * \n * @param {MoneroWalletListener|number} listenerOrStartHeight - listener xor start height (defaults to no sync listener, the last synced block)\n * @param {number} startHeight - startHeight if not given in first arg (defaults to last synced block)\n */\n async sync(listenerOrStartHeight, startHeight) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Start an asynchronous thread to continuously synchronize the wallet with the daemon.\n */\n async startSyncing() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Stop synchronizing the wallet with the daemon.\n */\n async stopSyncing() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n *

Rescan the blockchain for spent outputs.

\n * \n *

Note: this can only be called with a trusted daemon.

\n * \n *

Example use case: peer multisig hex is import when connected to an untrusted daemon,\n * so the wallet will not rescan spent outputs. Then the wallet connects to a trusted\n * daemon. This method should be manually invoked to rescan outputs.

\n */\n async rescanSpent() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n *

Rescan the blockchain from scratch, losing any information which cannot be recovered from\n * the blockchain itself.

\n * \n *

WARNING: This method discards local wallet data like destination addresses, tx secret keys,\n * tx notes, etc.

\n */\n async rescanBlockchain() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the balance of the wallet, account, or subaddress.\n * \n * @param {int} accountIdx - index of the account to get the balance of (optional)\n * @param {int} subaddressIdx - index of the subaddress to get the balance of (optional)\n * @return {BigInteger} the balance of the wallet, account, or subaddress\n */\n async getBalance(accountIdx, subaddressIdx) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get the unlocked balance of the wallet, account, or subaddress.\n * \n * @param {int} accountIdx - index of the account to get the unlocked balance of (optional)\n * @param {int} subaddressIdx - index of the subaddress to get the unlocked balance of (optional)\n * @return {BigInteger} the unlocked balance of the wallet, account, or subaddress\n */\n async getUnlockedBalance(accountIdx, subaddressIdx) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get accounts with a given tag.\n * \n * @param {boolean} includeSubaddresses - include subaddresses if true\n * @param {string} tag - tag for filtering accounts, all accounts if undefined\n * @return {MoneroAccount[]} all accounts with the given tag\n */\n async getAccounts(includeSubaddresses, tag) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get an account.\n * \n * @param {int} accountIdx - index of the account to get\n * @param {boolean} includeSubaddresses - include subaddresses if true\n * @return {MoneroAccount} the retrieved account\n */\n async getAccount(accountIdx, includeSubaddresses) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Create a new account with a label for the first subaddress.\n * \n * @param {string} label - label for account's first subaddress (optional)\n * @return {MoneroAccount} the created account\n */\n async createAccount(label) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get subaddresses in an account.\n * \n * @param {int} accountIdx - account to get subaddresses within\n * @param {int[]} subaddressIndices - indices of subaddresses to get (optional)\n * @return {MoneroSubaddress[]} the retrieved subaddresses\n */\n async getSubaddresses(accountIdx, subaddressIndices) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get a subaddress.\n * \n * @param {int} accountIdx - index of the subaddress's account\n * @param {int} subaddressIdx - index of the subaddress within the account\n * @return {MoneroSubaddress} the retrieved subaddress\n */\n async getSubaddress(accountIdx, subaddressIdx) {\n assert(accountIdx >= 0);\n assert(subaddressIdx >= 0);\n return (await this.getSubaddresses(accountIdx, subaddressIdx))[0];\n }\n \n /**\n * Create a subaddress within an account.\n * \n * @param {int} accountIdx - index of the account to create the subaddress within\n * @param {string} label - the label for the subaddress (optional)\n * @return {MoneroSubaddress} the created subaddress\n */\n async createSubaddress(accountIdx, label) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get a wallet transaction by hash.\n * \n * @param {string} txHash - hash of a transaction to get\n * @return {MoneroTxWallet} the identified transactions\n */\n async getTx(txHash) {\n return (await this.getTxs([txHash]))[0];\n }\n \n /**\n *

Get wallet transactions. Wallet transactions contain one or more\n * transfers that are either incoming or outgoing to the wallet.

\n * \n *

Results can be filtered by passing a query object. Transactions must\n * meet every criteria defined in the query in order to be returned. All\n * criteria are optional and no filtering is applied when not defined.

\n * \n * @param {(MoneroTxQuery|string[]|object)} query - configures the query (optional)\n * @param {boolean} query.isConfirmed - get txs that are confirmed or not (optional)\n * @param {boolean} query.inTxPool - get txs that are in the tx pool or not (optional)\n * @param {boolean} query.isRelayed - get txs that are relayed or not (optional)\n * @param {boolean} query.isFailed - get txs that are failed or not (optional)\n * @param {boolean} query.isMinerTx - get miner txs or not (optional)\n * @param {string} query.hash - get a tx with the hash (optional)\n * @param {string[]} query.hashes - get txs with the hashes (optional)\n * @param {string} query.paymentId - get transactions with the payment id (optional)\n * @param {string[]} query.paymentIds - get transactions with the payment ids (optional)\n * @param {boolean} query.hasPaymentId - get transactions with a payment id or not (optional)\n * @param {int} query.minHeight - get txs with height >= the given height (optional)\n * @param {int} query.maxHeight - get txs with height <= the given height (optional)\n * @param {boolean} query.isOutgoing - get txs with an outgoing transfer or not (optional)\n * @param {boolean} query.isIncoming - get txs with an incoming transfer or not (optional)\n * @param {MoneroTransferQuery} query.transferQuery - get txs that have a transfer that meets this query (optional)\n * @param {boolean} query.includeOutputs - specifies that tx outputs should be returned with tx results (optional)\n * @param {string[]} missingTxHashes - populated with hashes of unfound or unmet transactions that were queried by hash (throws error if undefined and queried transaction hashes are unfound or unmet) \n * @return {MoneroTxWallet[]} wallet transactions per the configuration\n */\n async getTxs(query, missingTxHashes) {\n throw new MoneroError(\"Not supported\");\n }\n\n /**\n *

Get incoming and outgoing transfers to and from this wallet. An outgoing\n * transfer represents a total amount sent from one or more subaddresses\n * within an account to individual destination addresses, each with their\n * own amount. An incoming transfer represents a total amount received into\n * a subaddress within an account. Transfers belong to transactions which\n * are stored on the blockchain.

\n * \n *

Results can be filtered by passing a query object. Transfers must\n * meet every criteria defined in the query in order to be returned. All\n * criteria are optional and no filtering is applied when not defined.

\n * \n * @param {(MoneroTransferQuery|object)} query - configures the query (optional)\n * @param {boolean} query.isOutgoing - get transfers that are outgoing or not (optional)\n * @param {boolean} query.isIncoming - get transfers that are incoming or not (optional)\n * @param {string} query.address - wallet's address that a transfer either originated from (if outgoing) or is destined for (if incoming) (optional)\n * @param {int} query.accountIndex - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific account index (optional)\n * @param {int} query.subaddressIndex - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific subaddress index (optional)\n * @param {int[]} query.subaddressIndices - get transfers that either originated from (if outgoing) or are destined for (if incoming) specific subaddress indices (optional)\n * @param {BigInteger} query.amount - amount being transferred (optional)\n * @param {MoneroDestination[]} query.destinations - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional)\n * @param {boolean} query.hasDestinations - get transfers that have destinations or not (optional)\n * @param {MoneroTxQuery} query.txQuery - get transfers whose transaction meets this query (optional)\n * @return {MoneroTransfer[]} are wallet transfers per the configuration\n */\n async getTransfers(query) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get all of the wallet's incoming transfers.\n * \n * @param query - passed to getTransfers() with isIncoming=true\n * @return {MoneroIncomingTransfer[]} the wallet's incoming transfers\n */\n async getIncomingTransfers(query) {\n \n // copy query and set direction\n let _query;\n if (query === undefined) _query = new MoneroTransferQuery();\n else {\n if (query.isIncoming() === false) throw new MoneroError(\"Transfer query contradicts getting incoming transfers\");\n _query = query.copy();\n }\n _query.setIsIncoming(true);\n \n // fetch and cast transfers\n let inTransfers = [];\n for (let transfer of await this.getTransfers(_query)) {\n inTransfers.push(transfer);\n }\n return inTransfers;\n }\n \n /**\n * Get all of the wallet's outgoing transfers.\n * \n * @param query - passed to getTransfers() with isOutgoing=true\n * @return {MoneroOutgoingTransfer[]} the wallet's outgoing transfers\n */\n async getOutgoingTransfers(query) {\n \n // copy query and set direction\n let _query;\n if (query === undefined) _query = new MoneroTransferQuery();\n else {\n if (query.isOutgoing() === false) throw new MoneroError(\"Transfer query contradicts getting outgoing transfers\");\n _query = query.copy();\n }\n _query.setIsOutgoing(true);\n \n // fetch and cast transfers\n let outTransfers = [];\n for (let transfer of await this.getTransfers(_query)) {\n outTransfers.push(transfer);\n }\n return outTransfers;\n }\n \n /**\n *

Get outputs created from previous transactions that belong to the wallet\n * (i.e. that the wallet can spend one time). Outputs are part of\n * transactions which are stored in blocks on the blockchain.

\n * \n *

Results can be filtered by passing a query object. Outputs must\n * meet every criteria defined in the query in order to be returned. All\n * filtering is optional and no filtering is applied when not defined.

\n * \n * @param {(MoneroOutputQuery|object)} query - configures the query (optional)\n * @param {int} query.accountIndex - get outputs associated with a specific account index (optional)\n * @param {int} query.subaddressIndex - get outputs associated with a specific subaddress index (optional)\n * @param {int[]} query.subaddressIndices - get outputs associated with specific subaddress indices (optional)\n * @param {BigInteger} query.amount - get outputs with a specific amount (optional)\n * @param {BigInteger} query.minAmount - get outputs greater than or equal to a minimum amount (optional)\n * @param {BigInteger} query.maxAmount - get outputs less than or equal to a maximum amount (optional)\n * @param {boolean} query.isSpent - get outputs that are spent or not (optional)\n * @param {string|MoneroKeyImage} query.keyImage - get output with a key image or which matches fields defined in a MoneroKeyImage (optional)\n * @param {MoneroTxQuery} query.txQuery - get outputs whose transaction meets this filter (optional)\n * @return {MoneroOutputWallet[]} are queried outputs\n */\n async getOutputs(query) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Export all outputs in hex format.\n * \n * @return {string} all outputs in hex format, undefined if no outputs\n */\n async getOutputsHex() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Import outputs in hex format.\n * \n * @param {string} outputsHex - outputs in hex format\n * @return {int} the number of outputs imported\n */\n async importOutputsHex(outputsHex) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get all signed key images.\n * \n * @return {MoneroKeyImage[]} the wallet's signed key images\n */\n async getKeyImages() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Import signed key images and verify their spent status.\n * \n * @param {MoneroKeyImage[]} keyImages - images to import and verify (requires hex and signature)\n * @return {MoneroKeyImageImportResult} results of the import\n */\n async importKeyImages(keyImages) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get new key images from the last imported outputs.\n * \n * @return {MoneroKeyImage[]} the key images from the last imported outputs\n */\n async getNewKeyImagesFromLastImport() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Create a transaction to transfer funds from this wallet.\n * \n * @param {MoneroTxConfig|object} config - configures the transaction to create (required)\n * @param {string} config.address - single destination address (required unless `destinations` provided)\n * @param {BigInteger|string} config.amount - single destination amount (required unless `destinations` provided)\n * @param {int} config.accountIndex - source account index to transfer funds from (required)\n * @param {int} config.subaddressIndex - source subaddress index to transfer funds from (optional)\n * @param {int[]} config.subaddressIndices - source subaddress indices to transfer funds from (optional)\n * @param {boolean} config.relay - relay the transaction to peers to commit to the blockchain (default false)\n * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL)\n * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided)\n * @param {string} config.paymentId - transaction payment ID (optional)\n * @param {int} config.unlockHeight - minimum height for the transaction to unlock (default 0)\n * @return {MoneroTxWallet} the created transaction\n */\n async createTx(config) {\n config = MoneroWallet._normalizeCreateTxsConfig(config);\n if (config.getCanSplit() !== undefined) assert.equal(config.getCanSplit(), false, \"Cannot split transactions using createTx(); use createTxs()\");\n config.setCanSplit(false);\n return (await this.createTxs(config))[0];\n }\n \n /**\n * Create one or more transactions to transfer funds from this wallet.\n * \n * @param {MoneroTxConfig|object} config - configures the transactions to create (required)\n * @param {string} config.address - single destination address (required unless `destinations` provided)\n * @param {BigInteger|string} config.amount - single destination amount (required unless `destinations` provided)\n * @param {int} config.accountIndex - source account index to transfer funds from (required)\n * @param {int} config.subaddressIndex - source subaddress index to transfer funds from (optional)\n * @param {int[]} config.subaddressIndices - source subaddress indices to transfer funds from (optional)\n * @param {boolean} config.relay - relay the transactions to peers to commit to the blockchain (default false)\n * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL)\n * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided)\n * @param {string} config.paymentId - transaction payment ID (optional)\n * @param {int} config.unlockHeight - minimum height for the transactions to unlock (default 0)\n * @param {boolean} config.canSplit - allow funds to be transferred using multiple transactions (default true)\n * @return {MoneroTxWallet[]} the created transactions\n */\n async createTxs(config) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Sweep an output by key image.\n * \n * @param {MoneroTxConfig} config - configures the transaction to create (required)\n * @param {string} config.address - single destination address (required)\n * @param {string} config.keyImage - key image to sweep (required)\n * @param {boolean} config.relay - relay the transaction to peers to commit to the blockchain (default false)\n * @param {int} config.unlockHeight - minimum height for the transaction to unlock (default 0)\n * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL)\n * @return {MoneroTxWallet} the created transaction\n */\n async sweepOutput(config) {\n throw new MoneroError(\"Not supported\");\n }\n\n /**\n * Sweep all unlocked funds according to the given configuration.\n * \n * @param {MoneroTxConfig|object} config - configures the transactions to create (required)\n * @param {string} config.address - single destination address (required)\n * @param {int} config.accountIndex - source account index to sweep from from (required)\n * @param {int} config.subaddressIndex - source subaddress index to sweep from (optional)\n * @param {int[]} config.subaddressIndices - source subaddress indices to sweep from (optional)\n * @param {boolean} config.relay - relay the transactions to peers to commit to the blockchain (default false)\n * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL)\n * @param {int} config.unlockHeight - minimum height for the transactions to unlock (default 0)\n * @return {MoneroTxWallet[]} the created transactions\n */\n async sweepUnlocked(config) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n *

Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

\n * \n *

NOTE: Dust only exists pre RCT, so this method will throw \"no dust to sweep\" on new wallets.

\n * \n * @param {boolean} relay - specifies if the resulting transaction should be relayed (default false)\n * @return {MoneroTxWallet[]} the created transactions\n */\n async sweepDust(relay) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Relay a previously created transaction.\n * \n * @param {(MoneroTxWallet|string)} txOrMetadata - transaction or its metadata to relay\n * @return {string} the hash of the relayed tx\n */\n async relayTx(txOrMetadata) {\n return (await this.relayTxs([txOrMetadata]))[0];\n }\n \n /**\n * Relay previously created transactions.\n * \n * @param {(MoneroTxWallet[]|string[])} txsOrMetadatas - transactions or their metadata to relay\n * @return {string[]} the hashes of the relayed txs\n */\n async relayTxs(txsOrMetadatas) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Parse a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions.\n * \n * @param {MoneroTxSet} txSet - a tx set containing unsigned or multisig tx hex\n * @return {MoneroTxSet} the parsed tx set containing structured transactions\n */\n async parseTxSet(txSet) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Sign unsigned transactions from a view-only wallet.\n * \n * @param {string} unsignedTxHex - unsigned transaction hex from when the transactions were created\n * @return {string} the signed transaction hex\n */\n async signTxs(unsignedTxHex) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Submit signed transactions from a view-only wallet.\n * \n * @param {string} signedTxHex - signed transaction hex from signTxs()\n * @return {string[]} the resulting transaction hashes\n */\n async submitTxs(signedTxHex) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Sign a message.\n * \n * @param {string} msg - message to sign\n * @return {string} the signature\n */\n async signMessage(message) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Verify a signature on a message.\n * \n * @param {string} msg - signed message\n * @param {string} address - signing address\n * @param {string} signature - signature\n * @return {boolean} true if the signature is good, false otherwise\n */\n async verifyMessage(message, address, signature) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get a transaction's secret key from its hash.\n * \n * @param {string} txHash - transaction's hash\n * @return {string} - transaction's secret key\n */\n async getTxKey(txHash) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Check a transaction in the blockchain with its secret key.\n * \n * @param {string} txHash - transaction to check\n * @param {string} txKey - transaction's secret key\n * @param {string} address - destination public address of the transaction\n * @return {MoneroCheckTx} the result of the check\n */\n async checkTxKey(txHash, txKey, address) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get a transaction signature to prove it.\n * \n * @param {string} txHash - transaction to prove\n * @param {string} address - destination public address of the transaction\n * @param {string} message - message to include with the signature to further authenticate the proof (optional)\n * @return {string} the transaction signature\n */\n async getTxProof(txHash, address, message) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Prove a transaction by checking its signature.\n * \n * @param {string} txHash - transaction to prove\n * @param {string} address - destination public address of the transaction\n * @param {string} message - message included with the signature to further authenticate the proof (optional)\n * @param {string} signature - transaction signature to confirm\n * @return {MoneroCheckTx} the result of the check\n */\n async checkTxProof(txHash, address, message, signature) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address.\n * \n * @param {string} txHash - transaction to prove\n * @param {string} message - message to include with the signature to further authenticate the proof (optional)\n * @return {string} the transaction signature\n */\n async getSpendProof(txHash, message) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address.\n * \n * @param {string} txHash - transaction to prove\n * @param {string} message - message included with the signature to further authenticate the proof (optional)\n * @param {string} signature - transaction signature to confirm\n * @return {boolean} true if the signature is good, false otherwise\n */\n async checkSpendProof(txHash, message, signature) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Generate a signature to prove the entire balance of the wallet.\n * \n * @param message - message included with the signature to further authenticate the proof (optional)\n * @return the reserve proof signature\n */\n async getReserveProofWallet(message) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Generate a signature to prove an available amount in an account.\n * \n * @param {int} accountIdx - account to prove ownership of the amount\n * @param {BigInteger} amount - minimum amount to prove as available in the account\n * @param {string} message - message to include with the signature to further authenticate the proof (optional)\n * @return {string} the reserve proof signature\n */\n async getReserveProofAccount(accountIdx, amount, message) {\n throw new MoneroError(\"Not supported\");\n }\n\n /**\n * Proves a wallet has a disposable reserve using a signature.\n * \n * @param {string} address - public wallet address\n * @param {string} message - message included with the signature to further authenticate the proof (optional)\n * @param {string} signature - reserve proof signature to check\n * @return {MoneroCheckReserve} the result of checking the signature proof\n */\n async checkReserveProof(address, message, signature) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get a transaction note.\n * \n * @param {string} txHash - transaction to get the note of\n * @return {string} the tx note\n */\n async getTxNote(txHash) {\n return (await this.getTxNotes([txHash]))[0];\n }\n \n /**\n * Get notes for multiple transactions.\n * \n * @param {string[]} txHashes - hashes of the transactions to get notes for\n * @return {string[]} notes for the transactions\n */\n async getTxNotes(txHashes) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Set a note for a specific transaction.\n * \n * @param {string} txHash - hash of the transaction to set a note for\n * @param {string} note - the transaction note\n */\n async setTxNote(txHash, note) {\n await this.setTxNotes([txHash], [note]);\n }\n \n /**\n * Set notes for multiple transactions.\n * \n * @param {string[]} txHashes - transactions to set notes for\n * @param {string[]} notes - notes to set for the transactions\n */\n async setTxNotes(txHashes, notes) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get address book entries.\n * \n * @param {int[]} entryIndices - indices of the entries to get\n * @return {MoneroAddressBookEntry[]} the address book entries\n */\n async getAddressBookEntries(entryIndices) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Add an address book entry.\n * \n * @param {string} address - entry address\n * @param {string} description - entry description (optional)\n * @return {int} the index of the added entry\n */\n async addAddressBookEntry(address, description) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Edit an address book entry.\n * \n * @param {number} index - index of the address book entry to edit\n * @param {boolean} setAddress - specifies if the address should be updated\n * @param {string} address - updated address\n * @param {boolean} setDescription - specifies if the description should be updated\n * @param {string} description - updated description\n */\n async editAddressBookEntry(index, setAddress, address, setDescription, description) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Delete an address book entry.\n * \n * @param {int} entryIdx - index of the entry to delete\n */\n async deleteAddressBookEntry(entryIdx) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Tag accounts.\n * \n * @param {string} tag - tag to apply to the specified accounts\n * @param {int[]} accountIndices - indices of the accounts to tag\n */\n async tagAccounts(tag, accountIndices) {\n throw new MoneroError(\"Not supported\");\n }\n\n /**\n * Untag accounts.\n * \n * @param {int[]} accountIndices - indices of the accounts to untag\n */\n async untagAccounts(accountIndices) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Return all account tags.\n * \n * @return {MoneroAccountTag[]} the wallet's account tags\n */\n async getAccountTags() {\n throw new MoneroError(\"Not supported\");\n }\n\n /**\n * Sets a human-readable description for a tag.\n * \n * @param {string} tag - tag to set a description for\n * @param {string} label - label to set for the tag\n */\n async setAccountTagLabel(tag, label) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Creates a payment URI from a send configuration.\n * \n * @param {MoneroTxConfig} config - specifies configuration for a potential tx\n * @return {string} the payment uri\n */\n async createPaymentUri(config) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Parses a payment URI to a tx config.\n * \n * @param {string} uri - payment uri to parse\n * @return {MoneroTxConfig} the send configuration parsed from the uri\n */\n async parsePaymentUri(uri) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get an attribute.\n * \n * @param {string} key - attribute to get the value of\n * @return {string} the attribute's value\n */\n async getAttribute(key) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Set an arbitrary attribute.\n * \n * @param {string} key - attribute key\n * @param {string} val - attribute value\n */\n async setAttribute(key, val) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Start mining.\n * \n * @param {int} numThreads - number of threads created for mining (optional)\n * @param {boolean} backgroundMining - specifies if mining should occur in the background (optional)\n * @param {boolean} ignoreBattery - specifies if the battery should be ignored for mining (optional)\n */\n async startMining(numThreads, backgroundMining, ignoreBattery) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Stop mining.\n */\n async stopMining() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Indicates if importing multisig data is needed for returning a correct balance.\n * \n * @return {boolean} true if importing multisig data is needed for returning a correct balance, false otherwise\n */\n async isMultisigImportNeeded() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Indicates if this wallet is a multisig wallet.\n * \n * @return {boolean} true if this is a multisig wallet, false otherwise\n */\n async isMultisig() {\n return (await this.getMultisigInfo()).isMultisig();\n }\n \n /**\n * Get multisig info about this wallet.\n * \n * @return {MoneroMultisigInfo} multisig info about this wallet\n */\n async getMultisigInfo() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Get multisig info as hex to share with participants to begin creating a\n * multisig wallet.\n * \n * @return {string} this wallet's multisig hex to share with participants\n */\n async prepareMultisig() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Make this wallet multisig by importing multisig hex from participants.\n * \n * @param {String[]} multisigHexes - multisig hex from each participant\n * @param {int} threshold - number of signatures needed to sign transfers\n * @param {string} password - wallet password\n * @return {MoneroMultisigInitResult} the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not N/N\n */\n async makeMultisig(multisigHexes, threshold, password) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Exchange multisig hex with participants in a M/N multisig wallet.\n * \n * This process must be repeated with participants exactly N-M times.\n * \n * @param {string[]} multisigHexes are multisig hex from each participant\n * @param {string} password - wallet's password // TODO monero core: redundant? wallet is created with password\n * @return {MoneroMultisigInitResult} the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done\n */\n async exchangeMultisigKeys(multisigHexes, password) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Export this wallet's multisig info as hex for other participants.\n * \n * @return {string} this wallet's multisig info as hex for other participants\n */\n async getMultisigHex() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Import multisig info as hex from other participants.\n * \n * @param {string[]} multisigHexes - multisig hex from each participant\n * @return {int} the number of outputs signed with the given multisig hex\n */\n async importMultisigHex(multisigHexes) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Sign multisig transactions from a multisig wallet.\n * \n * @param {string} multisigTxHex - unsigned multisig transactions as hex\n * @return {MoneroMultisigSignResult} the result of signing the multisig transactions\n */\n async signMultisigTxHex(multisigTxHex) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Submit signed multisig transactions from a multisig wallet.\n * \n * @param {string} signedMultisigTxHex - signed multisig hex returned from signMultisigTxHex()\n * @return {string[]} the resulting transaction hashes\n */\n async submitMultisigTxHex(signedMultisigTxHex) {\n throw new MoneroError(\"Not supported\");\n }\n\n /**\n * Save the wallet at its current path.\n */\n save() {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Optionally save then close the wallet.\n *\n * @param {boolean} save - specifies if the wallet should be saved before being closed (default false)\n */\n async close(save) {\n throw new MoneroError(\"Not supported\");\n }\n \n /**\n * Indicates if this wallet is closed or not.\n * \n * @return {boolean} true if the wallet is closed, false otherwise\n */\n async isClosed() {\n throw new MoneroError(\"Not supported\");\n }\n \n // -------------------------------- PRIVATE ---------------------------------\n \n static _normalizeTxQuery(query) {\n if (query instanceof MoneroTxQuery) query = query.copy();\n else if (Array.isArray(query)) query = new MoneroTxQuery().setHashes(query);\n else {\n query = Object.assign({}, query);\n query = new MoneroTxQuery(query);\n }\n if (query.getBlock() === undefined) query.setBlock(new MoneroBlock().setTxs([query]));\n return query;\n }\n \n static _normalizeTransferQuery(query) {\n if (query === undefined) query = new MoneroTransferQuery();\n else if (query instanceof MoneroTransferQuery) {\n if (query.getTxQuery() === undefined) query = query.copy();\n else {\n let txQuery = query.getTxQuery().copy();\n if (query.getTxQuery().getTransferQuery() === query) query = txQuery.getTransferQuery();\n else {\n assert.equal(query.getTxQuery().getTransferQuery(), undefined, \"Transfer query's tx query must be circular reference or null\");\n query = query.copy();\n query.setTxQuery(txQuery);\n }\n }\n } else {\n query = Object.assign({}, query);\n query = new MoneroTransferQuery(query);\n }\n if (query.getTxQuery() === undefined) query.setTxQuery(new MoneroTxQuery());\n query.getTxQuery().setTransferQuery(query);\n if (query.getTxQuery().getBlock() === undefined) query.getTxQuery().setBlock(new MoneroBlock().setTxs([query.getTxQuery()]));\n return query;\n }\n \n static _normalizeOutputQuery(query) {\n if (query === undefined) query = new MoneroOutputQuery();\n else if (query instanceof MoneroOutputQuery) {\n if (query.getTxQuery() === undefined) query = query.copy();\n else {\n let txQuery = query.getTxQuery().copy();\n if (query.getTxQuery().getOutputQuery() === query) query = txQuery.getOutputQuery();\n else {\n assert.equal(query.getTxQuery().getOutputQuery(), undefined, \"Output query's tx query must be circular reference or null\");\n query = query.copy();\n query.setTxQuery(txQuery);\n }\n }\n } else {\n query = Object.assign({}, query);\n query = new MoneroOutputQuery(query);\n }\n if (query.getTxQuery() === undefined) query.setTxQuery(new MoneroTxQuery());\n query.getTxQuery().setOutputQuery(query);\n if (query.getTxQuery().getBlock() === undefined) query.getTxQuery().setBlock(new MoneroBlock().setTxs([query.getTxQuery()]));\n return query;\n }\n \n static _normalizeCreateTxsConfig(config) {\n if (config === undefined || !(config instanceof Object)) throw new MoneroError(\"Must provide MoneroTxConfig or equivalent JS object\");\n config = new MoneroTxConfig(config);\n assert(config.getDestinations() && config.getDestinations().length > 0, \"Must provide destinations\");\n assert.equal(config.getSweepEachSubaddress(), undefined);\n assert.equal(config.getBelowAmount(), undefined);\n return config;\n }\n \n static _normalizeSweepOutputConfig(config) {\n if (config === undefined || !(config instanceof Object)) throw new MoneroError(\"Must provide MoneroTxConfig or equivalent JS object\");\n config = new MoneroTxConfig(config);\n assert.equal(config.getSweepEachSubaddress(), undefined);\n assert.equal(config.getBelowAmount(), undefined);\n assert.equal(config.getCanSplit(), undefined, \"Cannot split transactions when sweeping an output\");\n if (!config.getDestinations() || config.getDestinations().length !== 1 || !config.getDestinations()[0].getAddress()) throw new MoneroError(\"Must provide exactly one destination address to sweep output to\");\n return config;\n }\n \n static _normalizeSweepUnlockedConfig(config) {\n if (config === undefined || !(config instanceof Object)) throw new MoneroError(\"Must provide MoneroTxConfig or equivalent JS object\");\n config = new MoneroTxConfig(config);\n if (config.getDestinations() === undefined || config.getDestinations().length != 1) throw new MoneroError(\"Must provide exactly one destination to sweep to\");\n if (config.getDestinations()[0].getAddress() === undefined) throw new MoneroError(\"Must provide destination address to sweep to\");\n if (config.getDestinations()[0].getAmount() !== undefined) throw new MoneroError(\"Cannot provide amount in sweep config\");\n if (config.getKeyImage() !== undefined) throw new MoneroError(\"Key image defined; use sweepOutput() to sweep an output by its key image\");\n if (config.getSubaddressIndices() !== undefined && config.getSubaddressIndices().length === 0) config.setSubaddressIndices(undefined);\n if (config.getAccountIndex() === undefined && config.getSubaddressIndices() !== undefined) throw new MoneroError(\"Must provide account index if subaddress indices are provided\");\n return config;\n }\n}\n\nMoneroWallet.DEFAULT_LANGUAGE = \"English\";\n\nmodule.exports = MoneroWallet;","const assert = require(\"assert\");\nconst BigInteger = require(\"../common/biginteger\").BigInteger;\nconst GenUtils = require(\"../common/GenUtils\");\nconst LibraryUtils = require(\"../common/LibraryUtils\");\nconst MoneroAltChain = require(\"./model/MoneroAltChain\");\nconst MoneroBan = require(\"./model/MoneroBan\");\nconst MoneroBlock = require(\"./model/MoneroBlock\");\nconst MoneroBlockHeader = require(\"./model/MoneroBlockHeader\");\nconst MoneroBlockTemplate = require(\"./model/MoneroBlockTemplate\");\nconst MoneroDaemon = require(\"./MoneroDaemon\");\nconst MoneroDaemonConnection = require(\"./model/MoneroDaemonConnection\");\nconst MoneroDaemonInfo = require(\"./model/MoneroDaemonInfo\");\nconst MoneroDaemonPeer = require(\"./model/MoneroDaemonPeer\");\nconst MoneroDaemonSyncInfo = require(\"./model/MoneroDaemonSyncInfo\");\nconst MoneroError = require(\"../common/MoneroError\");\nconst MoneroHardForkInfo = require(\"./model/MoneroHardForkInfo\");\nconst MoneroKeyImage = require(\"./model/MoneroKeyImage\");\nconst MoneroMinerTxSum = require(\"./model/MoneroMinerTxSum\");\nconst MoneroMiningStatus = require(\"./model/MoneroMiningStatus\");\nconst MoneroNetworkType = require(\"./model/MoneroNetworkType\");\nconst MoneroOutput = require(\"./model/MoneroOutput\");\nconst MoneroOutputHistogramEntry = require(\"./model/MoneroOutputHistogramEntry\");\nconst MoneroRpcConnection = require(\"../common/MoneroRpcConnection\");\nconst MoneroSubmitTxResult = require(\"./model/MoneroSubmitTxResult\");\nconst MoneroTx = require(\"./model/MoneroTx\");\nconst MoneroUtils = require(\"../common/MoneroUtils\");\nconst MoneroVersion = require(\"./model/MoneroVersion\");\n\n/**\n * Copyright (c) woodser\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Implements a MoneroDaemon as a client of monero-daemon-rpc.\n * \n * @implements {MoneroDaemon}\n */\nclass MoneroDaemonRpc extends MoneroDaemon {\n \n /**\n *

Construct a daemon RPC client.

\n * \n *

Examples:

\n * \n * \n * let daemon = new MoneroDaemonRpc(\"http://localhost:38081\", \"superuser\", \"abctesting123\");

\n * \n * let daemon = new MoneroDaemonRpc({
\n *    uri: \"http://localhost:38081\",
\n *    username: \"superuser\",
\n *    password: \"abctesting123\"
\n * });\n *
\n * \n * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - uri of monero-daemon-rpc or JS config object or MoneroRpcConnection\n * @param {string} uriOrConfigOrConnection.uri - uri of monero-daemon-rpc\n * @param {string} uriOrConfigOrConnection.username - username to authenticate with monero-daemon-rpc (optional)\n * @param {string} uriOrConfigOrConnection.password - password to authenticate with monero-daemon-rpc (optional)\n * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true)\n * @param {number} uriOrConfigOrConnection.pollInterval - poll interval to query for updates in ms (default 5000)\n * @param {boolean} uriOrConfigOrConnection.proxyToWorker - run the daemon client in a web worker if true (default true if browser, false otherwise)\n * @param {string} username - username to authenticate with monero-daemon-rpc (optional)\n * @param {string} password - password to authenticate with monero-daemon-rpc (optional)\n * @param {boolean} rejectUnauthorized - rejects self-signed certificates if true (default true)\n * @param {number} pollInterval - poll interval to query for updates in ms (default 5000)\n * @param {boolean} proxyToWorker - runs the daemon client in a web worker if true (default true if browser, false otherwise)\n */\n constructor(uriOrConfigOrConnection, username, password, rejectUnauthorized, pollInterval, proxyToWorker) {\n super();\n \n // normalize configuration\n this.config = MoneroDaemonRpc._normalizeConfig(uriOrConfigOrConnection, username, password, rejectUnauthorized, pollInterval, proxyToWorker);\n \n // initialize proxy if proxying to worker\n if (this.config.proxyToWorker) this._proxyPromise = MoneroDaemonRpcProxy.connect(this.config);\n else {\n this.rpc = new MoneroRpcConnection(this.config);\n this.listeners = []; // block listeners\n this.cachedHeaders = {}; // cached headers for fetching blocks in bound chunks\n }\n }\n \n /**\n * Get the daemon's RPC connection.\n * \n * @return {MoneroRpcConnection} the daemon's rpc connection\n */\n async getRpcConnection() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getRpcConnection();\n return this.rpc;\n }\n \n async isConnected() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).isConnected();\n try {\n await this.getHeight();\n return true;\n } catch (e) {\n return false;\n }\n }\n \n async getVersion() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getVersion();\n let resp = await this.rpc.sendJsonRequest(\"get_version\");\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n return new MoneroVersion(resp.result.version, resp.result.release);\n }\n \n async isTrusted() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).isTrusted();\n let resp = await this.rpc.sendPathRequest(\"get_height\");\n MoneroDaemonRpc._checkResponseStatus(resp);\n return !resp.untrusted;\n }\n \n async getHeight() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getHeight();\n let resp = await this.rpc.sendJsonRequest(\"get_block_count\");\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n return resp.result.count;\n }\n \n async getBlockHash(height) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockHash(height);\n return (await this.rpc.sendJsonRequest(\"on_get_block_hash\", [height])).result; // TODO monero-wallet-rpc: no status returned\n }\n \n async getBlockTemplate(walletAddress, reserveSize) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockTemplate(walletAddress, reserveSize);\n assert(walletAddress && typeof walletAddress === \"string\", \"Must specify wallet address to be mined to\");\n let resp = await this.rpc.sendJsonRequest(\"get_block_template\", {wallet_address: walletAddress, reserve_size: reserveSize});\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n return MoneroDaemonRpc._convertRpcBlockTemplate(resp.result);\n }\n \n async getLastBlockHeader() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getLastBlockHeader();\n let resp = await this.rpc.sendJsonRequest(\"get_last_block_header\");\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n return MoneroDaemonRpc._convertRpcBlockHeader(resp.result.block_header);\n }\n \n async getBlockHeaderByHash(blockHash) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockHeaderByHash(blockHash);\n let resp = await this.rpc.sendJsonRequest(\"get_block_header_by_hash\", {hash: blockHash});\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n return MoneroDaemonRpc._convertRpcBlockHeader(resp.result.block_header);\n }\n \n async getBlockHeaderByHeight(height) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockHeaderByHeight(height);\n let resp = await this.rpc.sendJsonRequest(\"get_block_header_by_height\", {height: height});\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n return MoneroDaemonRpc._convertRpcBlockHeader(resp.result.block_header);\n }\n \n async getBlockHeadersByRange(startHeight, endHeight) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockHeadersByRange(startHeight, endHeight);\n \n // fetch block headers\n let resp = await this.rpc.sendJsonRequest(\"get_block_headers_range\", {\n start_height: startHeight,\n end_height: endHeight\n });\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n \n // build headers\n let headers = [];\n for (let rpcHeader of resp.result.headers) {\n headers.push(MoneroDaemonRpc._convertRpcBlockHeader(rpcHeader));\n }\n return headers;\n }\n \n async getBlockByHash(blockHash) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockByHash(blockHash);\n let resp = await this.rpc.sendJsonRequest(\"get_block\", {hash: blockHash});\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n return MoneroDaemonRpc._convertRpcBlock(resp.result);\n }\n \n async getBlockByHeight(height) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockByHeight(height);\n let resp = await this.rpc.sendJsonRequest(\"get_block\", {height: height});\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n return MoneroDaemonRpc._convertRpcBlock(resp.result);\n }\n \n async getBlocksByHeight(heights) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlocksByHeight(heights);\n \n // fetch blocks in binary\n let respBin = await this.rpc.sendBinaryRequest(\"get_blocks_by_height.bin\", {heights: heights});\n \n // load wasm module\n await LibraryUtils.loadKeysModule();\n \n // convert binary blocks to json\n let rpcBlocks = MoneroUtils.binaryBlocksToJson(respBin);\n MoneroDaemonRpc._checkResponseStatus(rpcBlocks);\n //console.log(JSON.stringify(rpcBlocks));\n \n // build blocks with transactions\n assert.equal(rpcBlocks.txs.length, rpcBlocks.blocks.length); \n let blocks = [];\n for (let blockIdx = 0; blockIdx < rpcBlocks.blocks.length; blockIdx++) {\n \n // build block\n let block = MoneroDaemonRpc._convertRpcBlock(rpcBlocks.blocks[blockIdx]);\n block.setHeight(heights[blockIdx]);\n blocks.push(block);\n \n // build transactions\n let txs = [];\n for (let txIdx = 0; txIdx < rpcBlocks.txs[blockIdx].length; txIdx++) {\n let tx = new MoneroTx();\n txs.push(tx);\n tx.setHash(rpcBlocks.blocks[blockIdx].tx_hashes[txIdx]);\n tx.setIsConfirmed(true);\n tx.setInTxPool(false);\n tx.setIsMinerTx(false);\n tx.setRelay(true);\n tx.setIsRelayed(true);\n tx.setIsFailed(false);\n tx.setIsDoubleSpend(false);\n MoneroDaemonRpc._convertRpcTx(rpcBlocks.txs[blockIdx][txIdx], tx);\n }\n \n // merge into one block\n block.setTxs([]);\n for (let tx of txs) {\n if (tx.getBlock()) block.merge(tx.getBlock());\n else block.getTxs().push(tx.setBlock(block));\n }\n }\n \n return blocks;\n }\n \n async getBlocksByRange(startHeight, endHeight) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlocksByRange(startHeight, endHeight);\n if (startHeight === undefined) startHeight = 0;\n if (endHeight === undefined) endHeight = await this.getHeight() - 1;\n let heights = [];\n for (let height = startHeight; height <= endHeight; height++) heights.push(height);\n return await this.getBlocksByHeight(heights);\n }\n \n async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize);\n if (startHeight === undefined) startHeight = 0;\n if (endHeight === undefined) endHeight = await this.getHeight() - 1;\n let lastHeight = startHeight - 1;\n let blocks = [];\n while (lastHeight < endHeight) {\n for (let block of await this._getMaxBlocks(lastHeight + 1, endHeight, maxChunkSize)) {\n blocks.push(block);\n }\n lastHeight = blocks[blocks.length - 1].getHeight();\n }\n return blocks;\n }\n \n async getTxs(txHashes, prune) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getTxs(txHashes, prune);\n \n // validate input\n assert(Array.isArray(txHashes) && txHashes.length > 0, \"Must provide an array of transaction hashes\");\n assert(prune === undefined || typeof prune === \"boolean\", \"Prune must be a boolean or undefined\");\n \n // fetch transactions\n let resp = await this.rpc.sendPathRequest(\"get_transactions\", {\n txs_hashes: txHashes,\n decode_as_json: true,\n prune: prune\n });\n try {\n MoneroDaemonRpc._checkResponseStatus(resp);\n } catch (e) {\n if (e.message.indexOf(\"Failed to parse hex representation of transaction hash\") >= 0) throw new MoneroError(\"Invalid transaction hash\");\n throw e;\n }\n \n // build transaction models\n let txs = [];\n if (resp.txs) {\n for (let txIdx = 0; txIdx < resp.txs.length; txIdx++) {\n let tx = new MoneroTx();\n tx.setIsMinerTx(false);\n txs.push(MoneroDaemonRpc._convertRpcTx(resp.txs[txIdx], tx));\n }\n }\n \n // fetch unconfirmed txs from pool and merge additional fields // TODO monero-daemon-rpc: merge rpc calls so this isn't necessary?\n let poolTxs = await this.getTxPool();\n for (let tx of txs) {\n for (let poolTx of poolTxs) {\n if (tx.getHash() === poolTx.getHash()) tx.merge(poolTx);\n }\n }\n \n return txs;\n }\n \n async getTxHexes(txHashes, prune) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getTxHexes(txHashes, prune);\n let hexes = [];\n for (let tx of await this.getTxs(txHashes, prune)) hexes.push(prune ? tx.getPrunedHex() : tx.getFullHex());\n return hexes;\n }\n \n async getMinerTxSum(height, numBlocks) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getMinerTxSum(height, numBlocks);\n if (height === undefined) height = 0;\n else assert(height >= 0, \"Height must be an integer >= 0\");\n if (numBlocks === undefined) numBlocks = await this.getHeight();\n else assert(numBlocks >= 0, \"Count must be an integer >= 0\");\n let resp = await this.rpc.sendJsonRequest(\"get_coinbase_tx_sum\", {height: height, count: numBlocks});\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n let txSum = new MoneroMinerTxSum();\n txSum.setEmissionSum(new BigInteger(resp.result.emission_amount));\n txSum.setFeeSum(new BigInteger(resp.result.fee_amount));\n return txSum;\n }\n \n async getFeeEstimate(graceBlocks) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getFeeEstimate(graceBlocks);\n let resp = await this.rpc.sendJsonRequest(\"get_fee_estimate\", {grace_blocks: graceBlocks});\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n return new BigInteger(resp.result.fee);\n }\n \n async submitTxHex(txHex, doNotRelay) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).submitTxHex(txHex, doNotRelay);\n let resp = await this.rpc.sendPathRequest(\"send_raw_transaction\", {tx_as_hex: txHex, do_not_relay: doNotRelay});\n let result = MoneroDaemonRpc._convertRpcSubmitTxResult(resp);\n \n // set isGood based on status\n try {\n MoneroDaemonRpc._checkResponseStatus(resp); \n result.setIsGood(true);\n } catch(e) {\n result.setIsGood(false);\n }\n return result;\n }\n \n async relayTxsByHash(txHashes) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).relayTxsByHash(txHashes);\n let resp = await this.rpc.sendJsonRequest(\"relay_tx\", {txids: txHashes});\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n }\n \n async getTxPool() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getTxPool();\n \n // send rpc request\n let resp = await this.rpc.sendPathRequest(\"get_transaction_pool\");\n MoneroDaemonRpc._checkResponseStatus(resp);\n \n // build txs\n let txs = [];\n if (resp.transactions) {\n for (let rpcTx of resp.transactions) {\n let tx = new MoneroTx();\n txs.push(tx);\n tx.setIsConfirmed(false);\n tx.setIsMinerTx(false);\n tx.setInTxPool(true);\n tx.setNumConfirmations(0);\n MoneroDaemonRpc._convertRpcTx(rpcTx, tx);\n }\n }\n \n return txs;\n }\n \n async getTxPoolHashes() {\n throw new MoneroError(\"Not implemented\");\n }\n \n async getTxPoolBacklog() {\n throw new MoneroError(\"Not implemented\");\n }\n\n async getTxPoolStats() {\n throw new MoneroError(\"Response contains field 'histo' which is binary'\");\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getTxPoolStats();\n let resp = await this.rpc.sendPathRequest(\"get_transaction_pool_stats\");\n MoneroDaemonRpc._checkResponseStatus(resp);\n let stats = MoneroDaemonRpc._convertRpcTxPoolStats(resp.pool_stats);\n \n // uninitialize some stats if not applicable\n if (stats.getHisto98pc() === 0) stats.setHisto98pc(undefined);\n if (stats.getNumTxs() === 0) {\n stats.setBytesMin(undefined);\n stats.setBytesMed(undefined);\n stats.setBytesMax(undefined);\n stats.setHisto98pc(undefined);\n stats.setOldestTimestamp(undefined);\n }\n \n return stats;\n }\n \n async flushTxPool(hashes) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).flushTxPool(hashes);\n if (hashes) hashes = GenUtils.listify(hashes);\n let resp = await this.rpc.sendJsonRequest(\"flush_txpool\", {txids: hashes});\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n }\n \n async getKeyImageSpentStatuses(keyImages) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getKeyImageSpentStatuses(keyImages);\n if (keyImages === undefined || keyImages.length === 0) throw new MoneroError(\"Must provide key images to check the status of\");\n let resp = await this.rpc.sendPathRequest(\"is_key_image_spent\", {key_images: keyImages});\n MoneroDaemonRpc._checkResponseStatus(resp);\n return resp.spent_status;\n }\n \n async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff);\n \n // send rpc request\n let resp = await this.rpc.sendJsonRequest(\"get_output_histogram\", {\n amounts: amounts,\n min_count: minCount,\n max_count: maxCount,\n unlocked: isUnlocked,\n recent_cutoff: recentCutoff\n });\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n \n // build histogram entries from response\n let entries = [];\n if (!resp.result.histogram) return entries;\n for (let rpcEntry of resp.result.histogram) {\n entries.push(MoneroDaemonRpc._convertRpcOutputHistogramEntry(rpcEntry));\n }\n return entries;\n }\n \n async getOutputDistribution(amounts, cumulative, startHeight, endHeight) {\n throw new MoneroError(\"Not implemented (response 'distribution' field is binary)\");\n \n// let amountStrs = [];\n// for (let amount of amounts) amountStrs.push(amount.toJSValue());\n// console.log(amountStrs);\n// console.log(cumulative);\n// console.log(startHeight);\n// console.log(endHeight);\n// \n// // send rpc request\n// console.log(\"*********** SENDING REQUEST *************\");\n// if (startHeight === undefined) startHeight = 0;\n// let resp = await this.rpc.sendJsonRequest(\"get_output_distribution\", {\n// amounts: amountStrs,\n// cumulative: cumulative,\n// from_height: startHeight,\n// to_height: endHeight\n// });\n// \n// console.log(\"RESPONSE\");\n// console.log(resp);\n// \n// // build distribution entries from response\n// let entries = [];\n// if (!resp.result.distributions) return entries; \n// for (let rpcEntry of resp.result.distributions) {\n// let entry = MoneroDaemonRpc._convertRpcOutputDistributionEntry(rpcEntry);\n// entries.push(entry);\n// }\n// return entries;\n }\n \n async getInfo() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getInfo();\n let resp = await this.rpc.sendJsonRequest(\"get_info\");\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n return MoneroDaemonRpc._convertRpcInfo(resp.result);\n }\n \n async getSyncInfo() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getSyncInfo();\n let resp = await this.rpc.sendJsonRequest(\"sync_info\");\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n return MoneroDaemonRpc._convertRpcSyncInfo(resp.result);\n }\n \n async getHardForkInfo() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getHardForkInfo();\n let resp = await this.rpc.sendJsonRequest(\"hard_fork_info\");\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n return MoneroDaemonRpc._convertRpcHardForkInfo(resp.result);\n }\n \n async getAltChains() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getAltChains();\n \n// // mocked response for test\n// let resp = {\n// status: \"OK\",\n// chains: [\n// {\n// block_hash: \"697cf03c89a9b118f7bdf11b1b3a6a028d7b3617d2d0ed91322c5709acf75625\",\n// difficulty: 14114729638300280,\n// height: 1562062,\n// length: 2\n// }\n// ]\n// }\n \n let resp = await this.rpc.sendJsonRequest(\"get_alternate_chains\");\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n let chains = [];\n if (!resp.result.chains) return chains;\n for (let rpcChain of resp.result.chains) chains.push(MoneroDaemonRpc._convertRpcAltChain(rpcChain));\n return chains;\n }\n \n async getAltBlockHashes() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getAltBlockHashes();\n \n// // mocked response for test\n// let resp = {\n// status: \"OK\",\n// untrusted: false,\n// blks_hashes: [\"9c2277c5470234be8b32382cdf8094a103aba4fcd5e875a6fc159dc2ec00e011\",\"637c0e0f0558e284493f38a5fcca3615db59458d90d3a5eff0a18ff59b83f46f\",\"6f3adc174a2e8082819ebb965c96a095e3e8b63929ad9be2d705ad9c086a6b1c\",\"697cf03c89a9b118f7bdf11b1b3a6a028d7b3617d2d0ed91322c5709acf75625\"]\n// }\n \n let resp = await this.rpc.sendPathRequest(\"get_alt_blocks_hashes\");\n MoneroDaemonRpc._checkResponseStatus(resp);\n if (!resp.blks_hashes) return [];\n return resp.blks_hashes;\n }\n \n async getDownloadLimit() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getDownloadLimit();\n return (await this._getBandwidthLimits())[0];\n }\n \n async setDownloadLimit(limit) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setDownloadLimit(limit);\n if (limit == -1) return await this.resetDownloadLimit();\n if (!(GenUtils.isInt(limit) && limit > 0)) throw new MoneroError(\"Download limit must be an integer greater than 0\");\n return (await this._setBandwidthLimits(limit, 0))[0];\n }\n \n async resetDownloadLimit() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).resetDownloadLimit();\n return (await this._setBandwidthLimits(-1, 0))[0];\n }\n\n async getUploadLimit() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getUploadLimit();\n return (await this._getBandwidthLimits())[1];\n }\n \n async setUploadLimit(limit) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setUploadLimit(limit);\n if (limit == -1) return await this.resetUploadLimit();\n if (!(GenUtils.isInt(limit) && limit > 0)) throw new MoneroError(\"Upload limit must be an integer greater than 0\");\n return (await this._setBandwidthLimits(0, limit))[1];\n }\n \n async resetUploadLimit() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).resetUploadLimit();\n return (await this._setBandwidthLimits(0, -1))[1];\n }\n \n async getConnections() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getConnections();\n let resp = await this.rpc.sendJsonRequest(\"get_connections\");\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n let connections = [];\n if (!resp.result.connections) return connections;\n for (let rpcConnection of resp.result.connections) {\n connections.push(MoneroDaemonRpc._convertRpcConnection(rpcConnection));\n }\n return connections;\n }\n \n async getKnownPeers() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getKnownPeers();\n \n // tx config\n let resp = await this.rpc.sendPathRequest(\"get_peer_list\");\n MoneroDaemonRpc._checkResponseStatus(resp);\n \n // build peers\n let peers = [];\n if (resp.gray_list) {\n for (let rpcPeer of resp.gray_list) {\n let peer = MoneroDaemonRpc._convertRpcPeer(rpcPeer);\n peer.setIsOnline(false); // gray list means offline last checked\n peers.push(peer);\n }\n }\n if (resp.white_list) {\n for (let rpcPeer of resp.white_list) {\n let peer = MoneroDaemonRpc._convertRpcPeer(rpcPeer);\n peer.setIsOnline(true); // white list means online last checked\n peers.push(peer);\n }\n }\n return peers;\n }\n \n async setOutgoingPeerLimit(limit) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setOutgoingPeerLimit(limit);\n if (!(GenUtils.isInt(limit) && limit >= 0)) throw new MoneroError(\"Outgoing peer limit must be >= 0\");\n let resp = await this.rpc.sendPathRequest(\"out_peers\", {out_peers: limit});\n MoneroDaemonRpc._checkResponseStatus(resp);\n }\n \n async setIncomingPeerLimit(limit) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setIncomingPeerLimit(limit);\n if (!(GenUtils.isInt(limit) && limit >= 0)) throw new MoneroError(\"Incoming peer limit must be >= 0\");\n let resp = await this.rpc.sendPathRequest(\"in_peers\", {in_peers: limit});\n MoneroDaemonRpc._checkResponseStatus(resp);\n }\n \n async getPeerBans() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getPeerBans();\n let resp = await this.rpc.sendJsonRequest(\"get_bans\");\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n let bans = [];\n for (let rpcBan of resp.result.bans) {\n let ban = new MoneroBan();\n ban.setHost(rpcBan.host);\n ban.setIp(rpcBan.ip);\n ban.setSeconds(rpcBan.seconds);\n bans.push(ban);\n }\n return bans;\n }\n \n async setPeerBans(bans) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setPeerBans(bans);\n let rpcBans = [];\n for (let ban of bans) rpcBans.push(MoneroDaemonRpc._convertToRpcBan(ban));\n let resp = await this.rpc.sendJsonRequest(\"set_bans\", {bans: rpcBans});\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n }\n \n async startMining(address, numThreads, isBackground, ignoreBattery) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).startMining(address, numThreads, isBackground, ignoreBattery);\n assert(address, \"Must provide address to mine to\");\n assert(GenUtils.isInt(numThreads) && numThreads > 0, \"Number of threads must be an integer greater than 0\");\n assert(isBackground === undefined || typeof isBackground === \"boolean\");\n assert(ignoreBattery === undefined || typeof ignoreBattery === \"boolean\");\n let resp = await this.rpc.sendPathRequest(\"start_mining\", {\n miner_address: address,\n threads_count: numThreads,\n do_background_mining: isBackground,\n ignore_battery: ignoreBattery,\n });\n MoneroDaemonRpc._checkResponseStatus(resp);\n }\n \n async stopMining() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).stopMining();\n let resp = await this.rpc.sendPathRequest(\"stop_mining\");\n MoneroDaemonRpc._checkResponseStatus(resp);\n }\n \n async getMiningStatus() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getMiningStatus();\n let resp = await this.rpc.sendPathRequest(\"mining_status\");\n MoneroDaemonRpc._checkResponseStatus(resp);\n return MoneroDaemonRpc._convertRpcMiningStatus(resp);\n }\n \n async submitBlocks(blockBlobs) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).submitBlocks(blockBlobs);\n assert(Array.isArray(blockBlobs) && blockBlobs.length > 0, \"Must provide an array of mined block blobs to submit\");\n let resp = await this.rpc.sendJsonRequest(\"submit_block\", blockBlobs);\n MoneroDaemonRpc._checkResponseStatus(resp.result);\n }\n \n async checkForUpdate() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).checkForUpdate();\n let resp = await this.rpc.sendPathRequest(\"update\", {command: \"check\"});\n MoneroDaemonRpc._checkResponseStatus(resp);\n return MoneroDaemonRpc._convertRpcUpdateCheckResult(resp);\n }\n \n async downloadUpdate(path) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).downloadUpdate();\n let resp = await this.rpc.sendPathRequest(\"update\", {command: \"download\", path: path});\n MoneroDaemonRpc._checkResponseStatus(resp);\n return MoneroDaemonRpc._convertRpcUpdateDownloadResult(resp);\n }\n \n async stop() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).stop();\n let resp = await this.rpc.sendPathRequest(\"stop_daemon\");\n MoneroDaemonRpc._checkResponseStatus(resp);\n }\n \n async getNextBlockHeader() {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getNextBlockHeader();\n let that = this;\n return new Promise(async function(resolve, reject) {\n let listener = async function(header) {\n resolve(header);\n await that.removeBlockListener(listener);\n }\n await that.addBlockListener(listener);\n });\n }\n \n async addBlockListener(listener) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).addBlockListener(listener);\n\n // register listener\n this.listeners.push(listener);\n \n // start polling for new blocks\n if (!this.isPollingHeaders) this._startPollingHeaders(this.config.pollInterval);\n }\n \n async removeBlockListener(listener) {\n if (this.config.proxyToWorker) return (await this._getDaemonProxy()).removeBlockListener(listener);\n let found = GenUtils.remove(this.listeners, listener);\n assert(found, \"Listener is not registered\");\n if (this.listeners.length === 0) this._stopPollingHeaders();\n }\n \n // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS --------------\n \n async getTx() { return super.getTx(...arguments); }\n async getTxHex() { return super.getTxHex(...arguments); }\n async getKeyImageSpentStatus() { return super.getKeyImageSpentStatus(...arguments); }\n async setPeerBan() { return super.setPeerBan(...arguments); }\n async submitBlock() { return super.submitBlock(...arguments); }\n \n // ------------------------------- PRIVATE ----------------------------------\n \n async _getDaemonProxy() {\n return await this._proxyPromise;\n }\n \n async _startPollingHeaders(interval) {\n assert(!this.isPollingHeaders, \"Daemon is already polling block headers\");\n \n // get header to detect changes while polling\n let lastHeader = await this.getLastBlockHeader(); // TODO: this should be passed in\n \n // poll until stopped\n let that = this;\n this.isPollingHeaders = true;\n while (this.isPollingHeaders) {\n await new Promise(function(resolve) { setTimeout(resolve, interval); });\n let header;\n try {\n header = await this.getLastBlockHeader();\n } catch (e) {\n console.error(\"Failed to poll last block header, retrying...\");\n continue;\n }\n if (header.getHash() !== lastHeader.getHash()) {\n lastHeader = header;\n for (let listener of this.listeners) {\n listener(header); // notify listener\n }\n }\n }\n }\n \n _stopPollingHeaders() {\n this.isPollingHeaders = false; // causes polling loop to exit\n }\n \n async _getBandwidthLimits() {\n let resp = await this.rpc.sendPathRequest(\"get_limit\");\n MoneroDaemonRpc._checkResponseStatus(resp);\n return [resp.limit_down, resp.limit_up];\n }\n \n async _setBandwidthLimits(downLimit, upLimit) {\n if (downLimit === undefined) downLimit = 0;\n if (upLimit === undefined) upLimit = 0;\n let resp = await this.rpc.sendPathRequest(\"set_limit\", {limit_down: downLimit, limit_up: upLimit});\n MoneroDaemonRpc._checkResponseStatus(resp);\n return [resp.limit_down, resp.limit_up];\n }\n \n /**\n * Get a contiguous chunk of blocks starting from a given height up to a maximum\n * height or amount of block data fetched from the blockchain, whichever comes first.\n * \n * @param {number} startHeight - start height to retrieve blocks (default 0)\n * @param {number} maxHeight - maximum end height to retrieve blocks (default blockchain height)\n * @param {number} maxReqSize - maximum amount of block data to fetch from the blockchain in bytes (default 3,000,000 bytes)\n * @return {MoneroBlock[]} are the resulting chunk of blocks\n */\n async _getMaxBlocks(startHeight, maxHeight, maxReqSize) {\n if (startHeight === undefined) startHeight = 0;\n if (maxHeight === undefined) maxHeight = await this.getHeight() - 1;\n if (maxReqSize === undefined) maxReqSize = MoneroDaemonRpc.MAX_REQ_SIZE;\n \n // determine end height to fetch\n let reqSize = 0;\n let endHeight = startHeight - 1;\n while (reqSize < maxReqSize && endHeight < maxHeight) {\n \n // get header of next block\n let header = await this._getBlockHeaderByHeightCached(endHeight + 1, maxHeight);\n \n // block cannot be bigger than max request size\n assert(header.getSize() <= maxReqSize, \"Block exceeds maximum request size: \" + header.getSize());\n \n // done iterating if fetching block would exceed max request size\n if (reqSize + header.getSize() > maxReqSize) break;\n \n // otherwise block is included\n reqSize += header.getSize();\n endHeight++;\n }\n return endHeight >= startHeight ? await this.getBlocksByRange(startHeight, endHeight) : [];\n }\n \n /**\n * Retrieves a header by height from the cache or fetches and caches a header\n * range if not already in the cache.\n * \n * @param {number} height - height of the header to retrieve from the cache\n * @param {number} maxHeight - maximum height of headers to cache\n */\n async _getBlockHeaderByHeightCached(height, maxHeight) {\n \n // get header from cache\n let cachedHeader = this.cachedHeaders[height];\n if (cachedHeader) return cachedHeader;\n \n // fetch and cache headers if not in cache\n let endHeight = Math.min(maxHeight, height + MoneroDaemonRpc.NUM_HEADERS_PER_REQ - 1); // TODO: could specify end height to cache to optimize small requests (would like to have time profiling in place though)\n let headers = await this.getBlockHeadersByRange(height, endHeight);\n for (let header of headers) {\n this.cachedHeaders[header.getHeight()] = header;\n }\n \n // return the cached header\n return this.cachedHeaders[height];\n }\n \n // --------------------------------- STATIC ---------------------------------\n \n static _normalizeConfig(uriOrConfigOrConnection, username, password, rejectUnauthorized, pollInterval, proxyToWorker) {\n let config;\n if (typeof uriOrConfigOrConnection === \"string\") config = {uri: uriOrConfigOrConnection, username: username, password: password, proxyToWorker: proxyToWorker, rejectUnauthorized: rejectUnauthorized, pollInterval: pollInterval};\n else {\n if (typeof uriOrConfigOrConnection !== \"object\") throw new MoneroError(\"Invalid configuration to create daemon rpc client; must be string, object, or MoneroRpcConnection\");\n if (username || password || rejectUnauthorized || pollInterval || proxyToWorker) throw new MoneroError(\"Can provide config object or params or new MoneroDaemonRpc(...) but not both\");\n if (uriOrConfigOrConnection instanceof MoneroRpcConnection) config = Object.assign({}, uriOrConfigOrConnection.getConfig());\n else config = Object.assign({}, uriOrConfigOrConnection);\n }\n if (config.pollInterval === undefined) config.pollInterval = 5000; // TODO: move to config\n if (config.server) {\n config = Object.assign(config, new MoneroRpcConnection(config.server).getConfig());\n delete config.server;\n }\n if (config.proxyToWorker === undefined) config.proxyToWorker = GenUtils.isBrowser();\n return config;\n }\n \n static _checkResponseStatus(resp) {\n if (resp.status !== \"OK\") throw new MoneroError(resp.status);\n }\n \n static _convertRpcBlockHeader(rpcHeader) {\n if (!rpcHeader) return undefined;\n let header = new MoneroBlockHeader();\n for (let key of Object.keys(rpcHeader)) {\n let val = rpcHeader[key];\n if (key === \"block_size\") GenUtils.safeSet(header, header.getSize, header.setSize, val);\n else if (key === \"depth\") GenUtils.safeSet(header, header.getDepth, header.setDepth, val);\n else if (key === \"difficulty\") { } // handled by wide_difficulty\n else if (key === \"cumulative_difficulty\") { } // handled by wide_cumulative_difficulty\n else if (key === \"difficulty_top64\") { } // handled by wide_difficulty\n else if (key === \"cumulative_difficulty_top64\") { } // handled by wide_cumulative_difficulty\n else if (key === \"wide_difficulty\") header.setDifficulty(GenUtils.reconcile(header.getDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val)));\n else if (key === \"wide_cumulative_difficulty\") header.setCumulativeDifficulty(GenUtils.reconcile(header.getCumulativeDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val)));\n else if (key === \"hash\") GenUtils.safeSet(header, header.getHash, header.setHash, val);\n else if (key === \"height\") GenUtils.safeSet(header, header.getHeight, header.setHeight, val);\n else if (key === \"major_version\") GenUtils.safeSet(header, header.getMajorVersion, header.setMajorVersion, val);\n else if (key === \"minor_version\") GenUtils.safeSet(header, header.getMinorVersion, header.setMinorVersion, val);\n else if (key === \"nonce\") GenUtils.safeSet(header, header.getNonce, header.setNonce, val);\n else if (key === \"num_txes\") GenUtils.safeSet(header, header.getNumTxs, header.setNumTxs, val);\n else if (key === \"orphan_status\") GenUtils.safeSet(header, header.getOrphanStatus, header.setOrphanStatus, val);\n else if (key === \"prev_hash\" || key === \"prev_id\") GenUtils.safeSet(header, header.getPrevHash, header.setPrevHash, val);\n else if (key === \"reward\") GenUtils.safeSet(header, header.getReward, header.setReward, BigInteger.parse(val));\n else if (key === \"timestamp\") GenUtils.safeSet(header, header.getTimestamp, header.setTimestamp, val);\n else if (key === \"block_weight\") GenUtils.safeSet(header, header.getWeight, header.setWeight, val);\n else if (key === \"long_term_weight\") GenUtils.safeSet(header, header.getLongTermWeight, header.setLongTermWeight, val);\n else if (key === \"pow_hash\") GenUtils.safeSet(header, header.getPowHash, header.setPowHash, val === \"\" ? undefined : val);\n else if (key === \"tx_hashes\") {} // used in block model, not header model\n else if (key === \"miner_tx\") {} // used in block model, not header model\n else if (key === \"miner_tx_hash\") header.setMinerTxHash(val);\n else console.log(\"WARNING: ignoring unexpected block header field: '\" + key + \"': \" + val);\n }\n return header;\n }\n \n static _convertRpcBlock(rpcBlock) {\n \n // build block\n let block = new MoneroBlock(MoneroDaemonRpc._convertRpcBlockHeader(rpcBlock.block_header ? rpcBlock.block_header : rpcBlock));\n block.setHex(rpcBlock.blob);\n block.setTxHashes(rpcBlock.tx_hashes === undefined ? [] : rpcBlock.tx_hashes);\n \n // build miner tx\n let rpcMinerTx = rpcBlock.json ? JSON.parse(rpcBlock.json).miner_tx : rpcBlock.miner_tx; // may need to be parsed from json\n let minerTx = new MoneroTx();\n block.setMinerTx(minerTx);\n minerTx.setIsConfirmed(true);\n minerTx.setIsMinerTx(true);\n MoneroDaemonRpc._convertRpcTx(rpcMinerTx, minerTx);\n \n return block;\n }\n \n /**\n * Transfers RPC tx fields to a given MoneroTx without overwriting previous values.\n * \n * TODO: switch from safe set\n * \n * @param rpcTx - RPC map containing transaction fields\n * @param tx - MoneroTx to populate with values (optional)\n * @returns tx - same tx that was passed in or a new one if none given\n */\n static _convertRpcTx(rpcTx, tx) {\n if (rpcTx === undefined) return undefined;\n if (tx === undefined) tx = new MoneroTx();\n \n// console.log(\"******** BUILDING TX ***********\");\n// console.log(rpcTx);\n// console.log(tx.toString());\n \n // initialize from rpc map\n let header;\n for (let key of Object.keys(rpcTx)) {\n let val = rpcTx[key];\n if (key === \"tx_hash\" || key === \"id_hash\") GenUtils.safeSet(tx, tx.getHash, tx.setHash, val);\n else if (key === \"block_timestamp\") {\n if (!header) header = new MoneroBlockHeader();\n GenUtils.safeSet(header, header.getTimestamp, header.setTimestamp, val);\n }\n else if (key === \"block_height\") {\n if (!header) header = new MoneroBlockHeader();\n GenUtils.safeSet(header, header.getHeight, header.setHeight, val);\n }\n else if (key === \"last_relayed_time\") GenUtils.safeSet(tx, tx.getLastRelayedTimestamp, tx.setLastRelayedTimestamp, val);\n else if (key === \"receive_time\" || key === \"received_timestamp\") GenUtils.safeSet(tx, tx.getReceivedTimestamp, tx.setReceivedTimestamp, val);\n else if (key === \"in_pool\") {\n GenUtils.safeSet(tx, tx.isConfirmed, tx.setIsConfirmed, !val);\n GenUtils.safeSet(tx, tx.inTxPool, tx.setInTxPool, val);\n }\n else if (key === \"double_spend_seen\") GenUtils.safeSet(tx, tx.isDoubleSpendSeen, tx.setIsDoubleSpend, val);\n else if (key === \"version\") GenUtils.safeSet(tx, tx.getVersion, tx.setVersion, val);\n else if (key === \"extra\") GenUtils.safeSet(tx, tx.getExtra, tx.setExtra, val);\n else if (key === \"vin\") {\n if (val.length !== 1 || !val[0].gen) { // ignore miner input TODO: why?\n tx.setInputs(val.map(rpcVin => MoneroDaemonRpc._convertRpcOutput(rpcVin, tx)));\n }\n }\n else if (key === \"vout\") tx.setOutputs(val.map(rpcOutput => MoneroDaemonRpc._convertRpcOutput(rpcOutput, tx)));\n else if (key === \"rct_signatures\") GenUtils.safeSet(tx, tx.getRctSignatures, tx.setRctSignatures, val);\n else if (key === \"rctsig_prunable\") GenUtils.safeSet(tx, tx.getRctSigPrunable, tx.setRctSigPrunable, val);\n else if (key === \"unlock_time\") GenUtils.safeSet(tx, tx.getUnlockHeight, tx.setUnlockHeight, val);\n else if (key === \"as_json\" || key === \"tx_json\") { } // handled last so tx is as initialized as possible\n else if (key === \"as_hex\" || key === \"tx_blob\") GenUtils.safeSet(tx, tx.getFullHex, tx.setFullHex, val ? val : undefined);\n else if (key === \"blob_size\") GenUtils.safeSet(tx, tx.getSize, tx.setSize, val);\n else if (key === \"weight\") GenUtils.safeSet(tx, tx.getWeight, tx.setWeight, val);\n else if (key === \"fee\") GenUtils.safeSet(tx, tx.getFee, tx.setFee, BigInteger.parse(val));\n else if (key === \"relayed\") GenUtils.safeSet(tx, tx.isRelayed, tx.setIsRelayed, val);\n else if (key === \"output_indices\") GenUtils.safeSet(tx, tx.getOutputIndices, tx.setOutputIndices, val);\n else if (key === \"do_not_relay\") GenUtils.safeSet(tx, tx.getRelay, tx.setRelay, !val);\n else if (key === \"kept_by_block\") GenUtils.safeSet(tx, tx.isKeptByBlock, tx.setIsKeptByBlock, val);\n else if (key === \"signatures\") GenUtils.safeSet(tx, tx.getSignatures, tx.setSignatures, val);\n else if (key === \"last_failed_height\") {\n if (val === 0) GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, false);\n else {\n GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, true);\n GenUtils.safeSet(tx, tx.getLastFailedHeight, tx.setLastFailedHeight, val);\n }\n }\n else if (key === \"last_failed_id_hash\") {\n if (val === MoneroDaemonRpc.DEFAULT_ID) GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, false);\n else {\n GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, true);\n GenUtils.safeSet(tx, tx.getLastFailedHash, tx.setLastFailedHash, val);\n }\n }\n else if (key === \"max_used_block_height\") GenUtils.safeSet(tx, tx.getMaxUsedBlockHeight, tx.setMaxUsedBlockHeight, val);\n else if (key === \"max_used_block_id_hash\") GenUtils.safeSet(tx, tx.getMaxUsedBlockHash, tx.setMaxUsedBlockHash, val);\n else if (key === \"prunable_hash\") GenUtils.safeSet(tx, tx.getPrunableHash, tx.setPrunableHash, val ? val : undefined);\n else if (key === \"prunable_as_hex\") GenUtils.safeSet(tx, tx.getPrunableHex, tx.setPrunableHex, val ? val : undefined);\n else if (key === \"pruned_as_hex\") GenUtils.safeSet(tx, tx.getPrunedHex, tx.setPrunedHex, val ? val : undefined);\n else console.log(\"WARNING: ignoring unexpected field in rpc tx: \" + key + \": \" + val);\n }\n \n // link block and tx\n if (header) tx.setBlock(new MoneroBlock(header).setTxs([tx]));\n \n // TODO monero-daemon-rpc: unconfirmed txs misreport block height and timestamp\n if (tx.getBlock() && tx.getBlock().getHeight() !== undefined && tx.getBlock().getHeight() === tx.getBlock().getTimestamp()) {\n tx.setBlock(undefined);\n tx.setIsConfirmed(false);\n }\n \n // initialize remaining known fields\n if (tx.isConfirmed()) {\n GenUtils.safeSet(tx, tx.isRelayed, tx.setIsRelayed, true);\n GenUtils.safeSet(tx, tx.getRelay, tx.setRelay, true);\n GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, false);\n } else {\n tx.setNumConfirmations(0);\n }\n if (tx.isFailed() === undefined) tx.setIsFailed(false);\n if (tx.getOutputIndices() && tx.getOutputs()) {\n assert.equal(tx.getOutputs().length, tx.getOutputIndices().length);\n for (let i = 0; i < tx.getOutputs().length; i++) {\n tx.getOutputs()[i].setIndex(tx.getOutputIndices()[i]); // transfer output indices to outputs\n }\n }\n if (rpcTx.as_json) MoneroDaemonRpc._convertRpcTx(JSON.parse(rpcTx.as_json), tx);\n if (rpcTx.tx_json) MoneroDaemonRpc._convertRpcTx(JSON.parse(rpcTx.tx_json), tx);\n if (!tx.isRelayed()) tx.setLastRelayedTimestamp(undefined); // TODO monero-daemon-rpc: returns last_relayed_timestamp despite relayed: false, self inconsistent\n \n // return built transaction\n return tx;\n }\n \n static _convertRpcOutput(rpcOutput, tx) {\n let output = new MoneroOutput();\n output.setTx(tx);\n for (let key of Object.keys(rpcOutput)) {\n let val = rpcOutput[key];\n if (key === \"gen\") throw new MoneroError(\"Output with 'gen' from daemon rpc is miner tx which we ignore (i.e. each miner input is undefined)\");\n else if (key === \"key\") {\n GenUtils.safeSet(output, output.getAmount, output.setAmount, new BigInteger(val.amount));\n GenUtils.safeSet(output, output.getKeyImage, output.setKeyImage, new MoneroKeyImage(val.k_image));\n GenUtils.safeSet(output, output.getRingOutputIndices, output.setRingOutputIndices, val.key_offsets);\n }\n else if (key === \"amount\") GenUtils.safeSet(output, output.getAmount, output.setAmount, BigInteger.parse(val));\n else if (key === \"target\") GenUtils.safeSet(output, output.getStealthPublicKey, output.setStealthPublicKey, val.key);\n else console.log(\"WARNING: ignoring unexpected field output: \" + key + \": \" + val);\n }\n return output;\n }\n \n static _convertRpcBlockTemplate(rpcTemplate) {\n let template = new MoneroBlockTemplate();\n for (let key of Object.keys(rpcTemplate)) {\n let val = rpcTemplate[key];\n if (key === \"blockhashing_blob\") template.setBlockTemplateBlob(val);\n else if (key === \"blocktemplate_blob\") template.setBlockHashingBlob(val);\n else if (key === \"difficulty\") template.setDifficulty(BigInteger.parse(val));\n else if (key === \"expected_reward\") template.setExpectedReward(val);\n else if (key === \"difficulty\") { } // handled by wide_difficulty\n else if (key === \"difficulty_top64\") { } // handled by wide_difficulty\n else if (key === \"wide_difficulty\") template.setDifficulty(GenUtils.reconcile(template.getDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val)));\n else if (key === \"height\") template.setHeight(val);\n else if (key === \"prev_hash\") template.setPrevHash(val);\n else if (key === \"reserved_offset\") template.setReservedOffset(val);\n else if (key === \"status\") {} // handled elsewhere\n else if (key === \"untrusted\") {} // handled elsewhere\n else if (key === \"seed_height\") template.setSeedHeight(val);\n else if (key === \"seed_hash\") template.setSeedHash(val);\n else if (key === \"next_seed_hash\") template.setNextSeedHash(val);\n else console.log(\"WARNING: ignoring unexpected field in block template: \" + key + \": \" + val);\n }\n if (\"\" === template.getNextSeedHash()) template.setNextSeedHash(undefined);\n return template;\n }\n \n static _convertRpcInfo(rpcInfo) {\n if (!rpcInfo) return undefined;\n let info = new MoneroDaemonInfo();\n for (let key of Object.keys(rpcInfo)) {\n let val = rpcInfo[key];\n if (key === \"version\") info.setVersion(val);\n else if (key === \"alt_blocks_count\") info.setNumAltBlocks(val);\n else if (key === \"block_size_limit\") info.setBlockSizeLimit(val);\n else if (key === \"block_size_median\") info.setBlockSizeMedian(val);\n else if (key === \"block_weight_limit\") info.setBlockWeightLimit(val);\n else if (key === \"block_weight_median\") info.setBlockWeightMedian(val);\n else if (key === \"bootstrap_daemon_address\") { if (val) info.setBootstrapDaemonAddress(val); }\n else if (key === \"difficulty\") { } // handled by wide_difficulty\n else if (key === \"cumulative_difficulty\") { } // handled by wide_cumulative_difficulty\n else if (key === \"difficulty_top64\") { } // handled by wide_difficulty\n else if (key === \"cumulative_difficulty_top64\") { } // handled by wide_cumulative_difficulty\n else if (key === \"wide_difficulty\") info.setDifficulty(GenUtils.reconcile(info.getDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val)));\n else if (key === \"wide_cumulative_difficulty\") info.setCumulativeDifficulty(GenUtils.reconcile(info.getCumulativeDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val)));\n else if (key === \"free_space\") info.setFreeSpace(BigInteger.parse(val));\n else if (key === \"database_size\") info.setDatabaseSize(val);\n else if (key === \"grey_peerlist_size\") info.setNumOfflinePeers(val);\n else if (key === \"height\") info.setHeight(val);\n else if (key === \"height_without_bootstrap\") info.setHeightWithoutBootstrap(val);\n else if (key === \"incoming_connections_count\") info.setNumIncomingConnections(val);\n else if (key === \"offline\") info.setIsOffline(val);\n else if (key === \"outgoing_connections_count\") info.setNumOutgoingConnections(val);\n else if (key === \"rpc_connections_count\") info.setNumRpcConnections(val);\n else if (key === \"start_time\") info.setStartTimestamp(val);\n else if (key === \"status\") {} // handled elsewhere\n else if (key === \"target\") info.setTarget(val);\n else if (key === \"target_height\") info.setTargetHeight(val);\n else if (key === \"top_block_hash\") info.setTopBlockHash(val);\n else if (key === \"tx_count\") info.setNumTxs(val);\n else if (key === \"tx_pool_size\") info.setNumTxsPool(val);\n else if (key === \"untrusted\") {} // handled elsewhere\n else if (key === \"was_bootstrap_ever_used\") info.setWasBootstrapEverUsed(val);\n else if (key === \"white_peerlist_size\") info.setNumOnlinePeers(val);\n else if (key === \"update_available\") info.setUpdateAvailable(val);\n else if (key === \"nettype\") GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroDaemon.parseNetworkType(val));\n else if (key === \"mainnet\") { if (val) GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.MAINNET); }\n else if (key === \"testnet\") { if (val) GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.TESTNET); }\n else if (key === \"stagenet\") { if (val) GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.STAGENET); }\n else if (key === \"credits\") info.setCredits(BigInteger.parse(val));\n else if (key === \"top_block_hash\" || key === \"top_hash\") info.setTopBlockHash(GenUtils.reconcile(info.getTopBlockHash(), \"\" === val ? undefined : val))\n else console.log(\"WARNING: Ignoring unexpected info field: \" + key + \": \" + val);\n }\n return info;\n }\n \n /**\n * Initializes sync info from RPC sync info.\n * \n * @param rpcSyncInfo - rpc map to initialize the sync info from\n * @return {MoneroDaemonSyncInfo} is sync info initialized from the map\n */\n static _convertRpcSyncInfo(rpcSyncInfo) {\n let syncInfo = new MoneroDaemonSyncInfo();\n for (let key of Object.keys(rpcSyncInfo)) {\n let val = rpcSyncInfo[key];\n if (key === \"height\") syncInfo.setHeight(val);\n else if (key === \"peers\") {\n syncInfo.setConnections([]);\n let rpcConnections = val;\n for (let rpcConnection of rpcConnections) {\n syncInfo.getConnections().push(MoneroDaemonRpc._convertRpcConnection(rpcConnection.info));\n }\n }\n else if (key === \"spans\") {\n syncInfo.setSpans([]);\n let rpcSpans = val;\n for (let rpcSpan of rpcSpans) {\n syncInfo.getSpans().push(MoneroDaemonRpc._convertRpcConnectionSpan(rpcSpan));\n }\n } else if (key === \"status\") {} // handled elsewhere\n else if (key === \"target_height\") syncInfo.setTargetHeight(BigInteger.parse(val));\n else if (key === \"next_needed_pruning_seed\") syncInfo.setNextNeededPruningSeed(val);\n else if (key === \"overview\") { // this returns [] without pruning\n let overview;\n try {\n overview = JSON.parse(val);\n if (overview !== undefined && overview.length > 0) console.error(\"Ignoring non-empty 'overview' field (not implemented): \" + overview); // TODO\n } catch (e) {\n console.error(\"Failed to parse 'overview' field: \" + overview + \": \" + e.message);\n }\n }\n else if (key === \"credits\") syncInfo.setCredits(BigInteger.parse(val));\n else if (key === \"top_hash\") syncInfo.setTopBlockHash(\"\" === val ? undefined : val);\n else if (key === \"untrusted\") {} // handled elsewhere\n else console.log(\"WARNING: ignoring unexpected field in sync info: \" + key + \": \" + val);\n }\n return syncInfo;\n }\n \n static _convertRpcHardForkInfo(rpcHardForkInfo) {\n let info = new MoneroHardForkInfo();\n for (let key of Object.keys(rpcHardForkInfo)) {\n let val = rpcHardForkInfo[key];\n if (key === \"earliest_height\") info.setEarliestHeight(val);\n else if (key === \"enabled\") info.setIsEnabled(val);\n else if (key === \"state\") info.setState(val);\n else if (key === \"status\") {} // handled elsewhere\n else if (key === \"untrusted\") {} // handled elsewhere\n else if (key === \"threshold\") info.setThreshold(val);\n else if (key === \"version\") info.setVersion(val);\n else if (key === \"votes\") info.setNumVotes(val);\n else if (key === \"voting\") info.setVoting(val);\n else if (key === \"window\") info.setWindow(val);\n else if (key === \"credits\") info.setCredits(BigInteger.parse(val));\n else if (key === \"top_hash\") info.setTopBlockHash(\"\" === val ? undefined : val);\n else console.log(\"WARNING: ignoring unexpected field in hard fork info: \" + key + \": \" + val);\n }\n return info;\n }\n \n static _convertRpcConnectionSpan(rpcConnectionSpan) {\n let span = new MoneroDaemonConnectionSpan();\n for (let key of Object.keys(rpcConnectionSpan)) {\n let val = rpcConnectionSpan[key];\n if (key === \"connection_id\") span.setConnectionId(val);\n else if (key === \"nblocks\") span.setNumBlocks(val);\n else if (key === \"rate\") span.setRate(val);\n else if (key === \"remote_address\") { if (val !== \"\") span.setRemoteAddress(val); }\n else if (key === \"size\") span.setSize(val);\n else if (key === \"speed\") span.setSpeed(val);\n else if (key === \"start_block_height\") span.setStartHeight(val);\n else console.log(\"WARNING: ignoring unexpected field in daemon connection span: \" + key + \": \" + val);\n }\n return span;\n }\n \n static _convertRpcOutputHistogramEntry(rpcEntry) {\n let entry = new MoneroOutputHistogramEntry();\n for (let key of Object.keys(rpcEntry)) {\n let val = rpcEntry[key];\n if (key === \"amount\") entry.setAmount(BigInteger.parse(val));\n else if (key === \"total_instances\") entry.setNumInstances(val);\n else if (key === \"unlocked_instances\") entry.setNumUnlockedInstances(val);\n else if (key === \"recent_instances\") entry.setNumRecentInstances(val);\n else console.log(\"WARNING: ignoring unexpected field in output histogram: \" + key + \": \" + val);\n }\n return entry;\n }\n \n static _convertRpcSubmitTxResult(rpcResult) {\n assert(rpcResult);\n let result = new MoneroSubmitTxResult();\n for (let key of Object.keys(rpcResult)) {\n let val = rpcResult[key];\n if (key === \"double_spend\") result.setIsDoubleSpend(val);\n else if (key === \"fee_too_low\") result.setIsFeeTooLow(val);\n else if (key === \"invalid_input\") result.setHasInvalidInput(val);\n else if (key === \"invalid_output\") result.setHasInvalidOutput(val);\n else if (key === \"too_few_outputs\") result.setHasTooFewOutputs(val);\n else if (key === \"low_mixin\") result.setIsMixinTooLow(val);\n else if (key === \"not_relayed\") result.setIsRelayed(!val);\n else if (key === \"overspend\") result.setIsOverspend(val);\n else if (key === \"reason\") result.setReason(val === \"\" ? undefined : val);\n else if (key === \"too_big\") result.setIsTooBig(val);\n else if (key === \"sanity_check_failed\") result.setSanityCheckFailed(val);\n else if (key === \"credits\") result.setCredits(BigInteger.parse(val))\n else if (key === \"status\" || key === \"untrusted\") {} // handled elsewhere\n else if (key === \"top_hash\") result.setTopBlockHash(\"\" === val ? undefined : val);\n else console.log(\"WARNING: ignoring unexpected field in submit tx hex result: \" + key + \": \" + val);\n }\n return result;\n }\n \n static _convertRpcTxPoolStats(rpcStats) {\n assert(rpcStats);\n let stats = new MoneroTxPoolStats();\n for (let key of Object.keys(rpcStats)) {\n let val = rpcStats[key];\n if (key === \"bytes_max\") stats.setBytesMax(val);\n else if (key === \"bytes_med\") stats.setBytesMed(val);\n else if (key === \"bytes_min\") stats.setBytesMin(val);\n else if (key === \"bytes_total\") stats.setBytesTotal(val);\n else if (key === \"histo_98pc\") stats.setHisto98pc(val);\n else if (key === \"num_10m\") stats.setNum10m(val);\n else if (key === \"num_double_spends\") stats.setNumDoubleSpends(val);\n else if (key === \"num_failing\") stats.setNumFailing(val);\n else if (key === \"num_not_relayed\") stats.setNumNotRelayed(val);\n else if (key === \"oldest\") stats.setOldestTimestamp(val);\n else if (key === \"txs_total\") stats.setNumTxs(val);\n else if (key === \"fee_total\") stats.setFeeTotal(BigInteger.parse(val));\n else if (key === \"histo\") throw new MoneroError(\"Not implemented\");\n else console.log(\"WARNING: ignoring unexpected field in tx pool stats: \" + key + \": \" + val);\n }\n return stats;\n }\n \n static _convertRpcAltChain(rpcChain) {\n assert(rpcChain);\n let chain = new MoneroAltChain();\n for (let key of Object.keys(rpcChain)) {\n let val = rpcChain[key];\n if (key === \"block_hash\") {} // using block_hashes instead\n else if (key === \"difficulty\") { } // handled by wide_difficulty\n else if (key === \"difficulty_top64\") { } // handled by wide_difficulty\n else if (key === \"wide_difficulty\") chain.setDifficulty(GenUtils.reconcile(chain.getDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val)));\n else if (key === \"height\") chain.setHeight(val);\n else if (key === \"length\") chain.setLength(val);\n else if (key === \"block_hashes\") chain.setBlockHashes(val);\n else if (key === \"main_chain_parent_block\") chain.setMainChainParentBlockHash(val);\n else console.log(\"WARNING: ignoring unexpected field in alternative chain: \" + key + \": \" + val);\n }\n return chain;\n }\n \n static _convertRpcPeer(rpcPeer) {\n assert(rpcPeer);\n let peer = new MoneroDaemonPeer();\n for (let key of Object.keys(rpcPeer)) {\n let val = rpcPeer[key];\n if (key === \"host\") peer.setHost(val);\n else if (key === \"id\") peer.setId(\"\" + val); // TODO monero-wallet-rpc: peer id is BigInteger but string in `get_connections`\n else if (key === \"ip\") {} // host used instead which is consistently a string\n else if (key === \"last_seen\") peer.setLastSeenTimestamp(val);\n else if (key === \"port\") peer.setPort(val);\n else if (key === \"rpc_port\") peer.setRpcPort(val);\n else if (key === \"pruning_seed\") peer.setPruningSeed(val);\n else if (key === \"rpc_credits_per_hash\") peer.setRpcCreditsPerHash(BigInteger.parse(val));\n else console.log(\"WARNING: ignoring unexpected field in rpc peer: \" + key + \": \" + val);\n }\n return peer;\n }\n \n static _convertRpcConnection(rpcConnection) {\n let connection = new MoneroDaemonConnection();\n let peer = new MoneroDaemonPeer();\n connection.setPeer(peer);\n peer.setIsOnline(true);\n for (let key of Object.keys(rpcConnection)) {\n let val = rpcConnection[key];\n if (key === \"address\") peer.setAddress(val);\n else if (key === \"avg_download\") connection.setAvgDownload(val);\n else if (key === \"avg_upload\") connection.setAvgUpload(val);\n else if (key === \"connection_id\") connection.setId(val);\n else if (key === \"current_download\") connection.setCurrentDownload(val);\n else if (key === \"current_upload\") connection.setCurrentUpload(val);\n else if (key === \"height\") connection.setHeight(val);\n else if (key === \"host\") peer.setHost(val);\n else if (key === \"ip\") {} // host used instead which is consistently a string\n else if (key === \"incoming\") connection.setIsIncoming(val);\n else if (key === \"live_time\") connection.setLiveTime(val);\n else if (key === \"local_ip\") connection.setIsLocalIp(val);\n else if (key === \"localhost\") connection.setIsLocalHost(val);\n else if (key === \"peer_id\") peer.setId(val);\n else if (key === \"port\") peer.setPort(parseInt(val));\n else if (key === \"rpc_port\") peer.setRpcPort(val);\n else if (key === \"recv_count\") connection.setNumReceives(val);\n else if (key === \"recv_idle_time\") connection.setReceiveIdleTime(val);\n else if (key === \"send_count\") connection.setNumSends(val);\n else if (key === \"send_idle_time\") connection.setSendIdleTime(val);\n else if (key === \"state\") connection.setState(val);\n else if (key === \"support_flags\") connection.setNumSupportFlags(val);\n else if (key === \"pruning_seed\") peer.setPruningSeed(val);\n else if (key === \"rpc_credits_per_hash\") peer.setRpcCreditsPerHash(BigInteger.parse(val));\n else if (key === \"address_type\") connection.setType(val);\n else console.log(\"WARNING: ignoring unexpected field in connection: \" + key + \": \" + val);\n }\n return connection;\n }\n \n static _convertToRpcBan(ban) {\n let rpcBan = {};\n rpcBan.host = ban.getHost();\n rpcBan.ip = ban.getIp();\n rpcBan.ban = ban.isBanned();\n rpcBan.seconds = ban.getSeconds();\n return rpcBan;\n }\n \n static _convertRpcMiningStatus(rpcStatus) {\n let status = new MoneroMiningStatus();\n status.setIsActive(rpcStatus.active);\n status.setSpeed(rpcStatus.speed);\n status.setNumThreads(rpcStatus.threads_count);\n if (rpcStatus.active) {\n status.setAddress(rpcStatus.address);\n status.setIsBackground(rpcStatus.is_background_mining_enabled);\n }\n return status;\n }\n \n static _convertRpcUpdateCheckResult(rpcResult) {\n assert(rpcResult);\n let result = new MoneroDaemonUpdateCheckResult();\n for (let key of Object.keys(rpcResult)) {\n let val = rpcResult[key];\n if (key === \"auto_uri\") result.setAutoUri(val);\n else if (key === \"hash\") result.setHash(val);\n else if (key === \"path\") {} // handled elsewhere\n else if (key === \"status\") {} // handled elsewhere\n else if (key === \"update\") result.setIsUpdateAvailable(val);\n else if (key === \"user_uri\") result.setUserUri(val);\n else if (key === \"version\") result.setVersion(val);\n else if (key === \"untrusted\") {} // handled elsewhere\n else console.log(\"WARNING: ignoring unexpected field in rpc check update result: \" + key + \": \" + val);\n }\n if (result.getAutoUri() === \"\") result.setAutoUri(undefined);\n if (result.getUserUri() === \"\") result.setUserUri(undefined);\n if (result.getVersion() === \"\") result.setVersion(undefined);\n if (result.getHash() === \"\") result.setHash(undefined);\n return result;\n }\n \n static _convertRpcUpdateDownloadResult(rpcResult) {\n let result = new MoneroDaemonUpdateDownloadResult(MoneroDaemonRpc._convertRpcUpdateCheckResult(rpcResult));\n result.setDownloadPath(rpcResult[\"path\"]);\n if (result.getDownloadPath() === \"\") result.setDownloadPath(undefined);\n return result;\n }\n\n /**\n * Converts a '0x' prefixed hexidecimal string to a BigInteger.\n * \n * @param hex is the '0x' prefixed hexidecimal string to convert\n * @return BigInteger is the hexicedimal converted to decimal\n */\n static _prefixedHexToBI(hex) {\n assert(hex.substring(0, 2) === \"0x\");\n return BigInteger.parse(hex, 16);\n }\n}\n\n// static variables\nMoneroDaemonRpc.DEFAULT_ID = \"0000000000000000000000000000000000000000000000000000000000000000\"; // uninitialized tx or block hash from daemon rpc\nMoneroDaemonRpc.MAX_REQ_SIZE = \"3000000\"; // max request size when fetching blocks from daemon\nMoneroDaemonRpc.NUM_HEADERS_PER_REQ = \"750\"; // number of headers to fetch and cache per request\n\n/**\n * Implements a MoneroDaemon by proxying requests to a web worker.\n * \n * @private\n */\nclass MoneroDaemonRpcProxy extends MoneroDaemon {\n \n // --------------------------- STATIC UTILITIES -----------------------------\n \n static async connect(config) {\n let daemonId = GenUtils.getUUID();\n config = Object.assign({}, config, {proxyToWorker: false});\n await LibraryUtils.invokeWorker(daemonId, \"connectDaemonRpc\", [config]);\n return new MoneroDaemonRpcProxy(daemonId, LibraryUtils.getWorker());\n }\n \n // ---------------------------- INSTANCE METHODS ----------------------------\n \n constructor(daemonId, worker) {\n super();\n this.daemonId = daemonId;\n this.worker = worker;\n this.wrappedListeners = [];\n }\n \n async getRpcConnection() {\n let config = await this._invokeWorker(\"daemonGetRpcConnection\");\n return new MoneroRpcConnection(config);\n }\n \n async isConnected() {\n return this._invokeWorker(\"daemonIsConnected\");\n }\n \n async getVersion() {\n let versionJson = await this._invokeWorker(\"daemonGetVersion\");\n return new MoneroVersion(versionJson.number, versionJson.isRelease);\n }\n \n async isTrusted() {\n return this._invokeWorker(\"daemonIsTrusted\");\n }\n \n async getHeight() {\n return this._invokeWorker(\"daemonGetHeight\");\n }\n \n async getBlockHash(height) {\n return this._invokeWorker(\"daemonGetBlockHash\", Array.from(arguments));\n }\n \n async getBlockTemplate(walletAddress, reserveSize) {\n return new MoneroBlockTemplate(await this._invokeWorker(\"daemonGetBlockTemplate\", Array.from(arguments)));\n }\n \n async getLastBlockHeader() {\n return new MoneroBlockHeader(await this._invokeWorker(\"daemonGetLastBlockHeader\"));\n }\n \n async getBlockHeaderByHash(blockHash) {\n return new MoneroBlockHeader(await this._invokeWorker(\"daemonGetBlockHeaderByHash\", Array.from(arguments)));\n }\n \n async getBlockHeaderByHeight(height) {\n return new MoneroBlockHeader(await this._invokeWorker(\"daemonGetBlockHeaderByHeight\", Array.from(arguments)));\n }\n \n async getBlockHeadersByRange(startHeight, endHeight) {\n let blockHeadersJson = await this._invokeWorker(\"daemonGetBlockHeadersByRange\", Array.from(arguments));\n let headers = [];\n for (let blockHeaderJson of blockHeadersJson) headers.push(new MoneroBlockHeader(blockHeaderJson));\n return headers;\n }\n \n async getBlockByHash(blockHash) {\n return new MoneroBlock(await this._invokeWorker(\"daemonGetBlockByHash\", Array.from(arguments)));\n }\n \n async getBlocksByHash(blockHashes, startHeight, prune) {\n let blocksJson = await this._invokeWorker(\"daemonGetBlocksByHash\", Array.from(arguments));\n let blocks = [];\n for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson));\n return blocks;\n }\n \n async getBlockByHeight(height) {\n return new MoneroBlock(await this._invokeWorker(\"daemonGetBlockByHeight\", Array.from(arguments)));\n }\n \n async getBlocksByHeight(heights) {\n let blocksJson = await this._invokeWorker(\"daemonGetBlocksByHeight\", Array.from(arguments));\n let blocks = [];\n for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson));\n return blocks;\n }\n \n async getBlocksByRange(startHeight, endHeight) {\n let blocksJson = await this._invokeWorker(\"daemonGetBlocksByRange\", Array.from(arguments));\n let blocks = [];\n for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson));\n return blocks;\n }\n \n async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) {\n let blocksJson = await this._invokeWorker(\"daemonGetBlocksByRangeChunked\", Array.from(arguments));\n let blocks = [];\n for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson));\n return blocks;\n }\n \n async getBlockHashes(blockHashes, startHeight) {\n return this._invokeWorker(\"daemonGetBlockHashes\", Array.from(arguments));\n }\n \n async getTxs(txHashes, prune = false) {\n \n // deserialize txs from blocks\n let blocks = [];\n for (let blockJson of await this._invokeWorker(\"daemonGetTxs\", Array.from(arguments))) {\n blocks.push(new MoneroBlock(blockJson));\n }\n \n // collect txs\n let txs = [];\n for (let block of blocks) {\n for (let tx of block.getTxs()) {\n if (!tx.isConfirmed()) tx.setBlock(undefined);\n txs.push(tx);\n }\n }\n return txs;\n }\n \n async getTxHexes(txHashes, prune = false) {\n return this._invokeWorker(\"daemonGetTxHexes\", Array.from(arguments));\n }\n \n async getMinerTxSum(height, numBlocks) {\n return new MoneroMinerTxSum(await this._invokeWorker(\"daemonGetMinerTxSum\", Array.from(arguments)));\n }\n \n async getFeeEstimate(graceBlocks) {\n return BigInteger.parse(await this._invokeWorker(\"daemonGetFeeEstimate\", Array.from(arguments)));\n }\n \n async submitTxHex(txHex, doNotRelay) {\n return new MoneroSubmitTxResult(await this._invokeWorker(\"daemonSubmitTxHex\", Array.from(arguments)));\n }\n \n async relayTxsByHash(txHashes) {\n return this._invokeWorker(\"daemonRelayTxsByHash\", Array.from(arguments));\n }\n \n async getTxPool() {\n let blockJson = await this._invokeWorker(\"daemonGetTxPool\");\n let txs = new MoneroBlock(blockJson).getTxs();\n for (let tx of txs) tx.setBlock(undefined);\n return txs ? txs : [];\n }\n \n async getTxPoolHashes() {\n return this._invokeWorker(\"daemonGetTxPoolHashes\", Array.from(arguments));\n }\n \n async getTxPoolBacklog() {\n throw new MoneroError(\"Not implemented\");\n }\n \n async getTxPoolStats() {\n return new MoneroTxPoolStats(await this._invokeWorker(\"daemonGetTxPoolStats\"));\n }\n \n async flushTxPool(hashes) {\n return this._invokeWorker(\"daemonFlushTxPool\", Array.from(arguments));\n }\n \n async getKeyImageSpentStatuses(keyImages) {\n return this._invokeWorker(\"daemonGetKeyImageSpentStatuses\", Array.from(arguments));\n }\n \n async getOutputs(outputs) {\n throw new MoneroError(\"Not implemented\");\n }\n \n async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) {\n let entries = [];\n for (let entryJson of await this._invokeWorker(\"daemonGetOutputHistogram\", [amounts, minCount, maxCount, isUnlocked, recentCutoff])) {\n entries.push(new MoneroOutputHistogramEntry(entryJson));\n }\n return entries;\n }\n \n async getOutputDistribution(amounts, cumulative, startHeight, endHeight) {\n throw new MoneroError(\"Not implemented\");\n }\n \n async getInfo() {\n return new MoneroDaemonInfo(await this._invokeWorker(\"daemonGetInfo\"));\n }\n \n async getSyncInfo() {\n return new MoneroDaemonSyncInfo(await this._invokeWorker(\"daemonGetSyncInfo\"));\n }\n \n async getHardForkInfo() {\n return new MoneroHardForkInfo(await this._invokeWorker(\"daemonGetHardForkInfo\"));\n }\n \n async getAltChains() {\n let altChains = [];\n for (let altChainJson of await this._invokeWorker(\"daemonGetAltChains\")) altChains.push(new MoneroAltChain(altChainJson));\n return altChains;\n }\n \n async getAltBlockHashes() {\n return this._invokeWorker(\"daemonGetAltBlockHashes\");\n }\n \n async getDownloadLimit() {\n return this._invokeWorker(\"daemonGetDownloadLimit\");\n }\n \n async setDownloadLimit(limit) {\n return this._invokeWorker(\"daemonSetDownloadLimit\", Array.from(arguments));\n }\n \n async resetDownloadLimit() {\n return this._invokeWorker(\"daemonResetDownloadLimit\");\n }\n \n async getUploadLimit() {\n return this._invokeWorker(\"daemonGetUploadLimit\");\n }\n \n async setUploadLimit(limit) {\n return this._invokeWorker(\"daemonSetUploadLimit\", Array.from(arguments));\n }\n \n async resetUploadLimit() {\n return this._invokeWorker(\"daemonResetUploadLimit\");\n }\n \n async getKnownPeers() {\n let peers = [];\n for (let peerJson of await this._invokeWorker(\"daemonGetKnownPeers\")) peers.push(new MoneroDaemonPeer(peerJson));\n return peers;\n }\n \n async getConnections() {\n let connections = [];\n for (let connectionJson of await this._invokeWorker(\"daemonGetConnections\")) connections.push(new MoneroDaemonConnection(connectionJson));\n return connections;\n }\n \n async setOutgoingPeerLimit(limit) {\n return this._invokeWorker(\"daemonSetIncomingPeerLimit\", Array.from(arguments));\n }\n \n async setIncomingPeerLimit(limit) {\n return this._invokeWorker(\"daemonSetIncomingPeerLimit\", Array.from(arguments));\n }\n \n async getPeerBans() {\n let bans = [];\n for (let banJson of await this._invokeWorker(\"daemonGetPeerBans\")) bans.push(new MoneroBan(banJson));\n return bans;\n }\n\n async setPeerBans(bans) {\n let bansJson = [];\n for (let ban of bans) bansJson.push(ban.toJson());\n return this._invokeWorker(\"daemonSetPeerBans\", [bansJson]);\n }\n \n async startMining(address, numThreads, isBackground, ignoreBattery) {\n return this._invokeWorker(\"daemonStartMining\", Array.from(arguments));\n }\n \n async stopMining() {\n return this._invokeWorker(\"daemonStopMining\")\n }\n \n async getMiningStatus() {\n return new MoneroMiningStatus(await this._invokeWorker(\"daemonGetMiningStatus\"));\n }\n \n async submitBlocks(blockBlobs) {\n throw new MoneroError(\"Not implemented\");\n }\n \n async checkForUpdate() {\n throw new MoneroError(\"Not implemented\");\n }\n \n async downloadUpdate(path) {\n throw new MoneroError(\"Not implemented\");\n }\n \n async stop() {\n while (this.wrappedListeners.length) await this.removeBlockListener(this.wrappedListeners[0].getListener());\n return this._invokeWorker(\"daemonStop\");\n }\n \n async getNextBlockHeader() {\n return new MoneroBlockHeader(await this._invokeWorker(\"daemonGetNextBlockHeader\"));\n }\n \n async addBlockListener(listener) {\n let wrappedListener = new DaemonWorkerListener(listener);\n let listenerId = wrappedListener.getId();\n LibraryUtils.WORKER_OBJECTS[this.daemonId].callbacks[\"onNewBlockHeader_\" + listenerId] = [wrappedListener.onNewBlockHeader, wrappedListener];\n this.wrappedListeners.push(wrappedListener);\n return this._invokeWorker(\"daemonAddBlockListener\", [listenerId]);\n }\n \n async removeBlockListener(listener) {\n for (let i = 0; i < this.wrappedListeners.length; i++) {\n if (this.wrappedListeners[i].getListener() === listener) {\n let listenerId = this.wrappedListeners[i].getId();\n await this._invokeWorker(\"daemonRemoveBlockListener\", [listenerId]);\n delete LibraryUtils.WORKER_OBJECTS[this.daemonId].callbacks[\"onNewBlockHeader_\" + listenerId];\n this.wrappedListeners.splice(i, 1);\n return;\n }\n }\n throw new MoneroError(\"Listener is not registered with wallet\");\n }\n \n // --------------------------- PRIVATE HELPERS ------------------------------\n \n // TODO: duplicated with MoneroWalletWasmProxy\n async _invokeWorker(fnName, args) {\n return LibraryUtils.invokeWorker(this.daemonId, fnName, args);\n }\n}\n\n/**\n * Internal listener to bridge notifications to external listeners.\n * \n * @private\n */\nclass DaemonWorkerListener {\n \n constructor(listener) {\n this._id = GenUtils.getUUID();\n this._listener = listener;\n }\n \n getId() {\n return this._id;\n }\n \n getListener() {\n return this._listener;\n }\n \n onNewBlockHeader(headerJson) {\n this._listener(new MoneroBlockHeader(headerJson));\n }\n}\n\nmodule.exports = MoneroDaemonRpc;","var toString = {}.toString;\n\nmodule.exports = Array.isArray || function (arr) {\n return toString.call(arr) == '[object Array]';\n};\n","'use strict'\nvar inherits = require('inherits')\nvar HashBase = require('hash-base')\nvar Buffer = require('safe-buffer').Buffer\n\nvar ARRAY16 = new Array(16)\n\nfunction MD5 () {\n HashBase.call(this, 64)\n\n // state\n this._a = 0x67452301\n this._b = 0xefcdab89\n this._c = 0x98badcfe\n this._d = 0x10325476\n}\n\ninherits(MD5, HashBase)\n\nMD5.prototype._update = function () {\n var M = ARRAY16\n for (var i = 0; i < 16; ++i) M[i] = this._block.readInt32LE(i * 4)\n\n var a = this._a\n var b = this._b\n var c = this._c\n var d = this._d\n\n a = fnF(a, b, c, d, M[0], 0xd76aa478, 7)\n d = fnF(d, a, b, c, M[1], 0xe8c7b756, 12)\n c = fnF(c, d, a, b, M[2], 0x242070db, 17)\n b = fnF(b, c, d, a, M[3], 0xc1bdceee, 22)\n a = fnF(a, b, c, d, M[4], 0xf57c0faf, 7)\n d = fnF(d, a, b, c, M[5], 0x4787c62a, 12)\n c = fnF(c, d, a, b, M[6], 0xa8304613, 17)\n b = fnF(b, c, d, a, M[7], 0xfd469501, 22)\n a = fnF(a, b, c, d, M[8], 0x698098d8, 7)\n d = fnF(d, a, b, c, M[9], 0x8b44f7af, 12)\n c = fnF(c, d, a, b, M[10], 0xffff5bb1, 17)\n b = fnF(b, c, d, a, M[11], 0x895cd7be, 22)\n a = fnF(a, b, c, d, M[12], 0x6b901122, 7)\n d = fnF(d, a, b, c, M[13], 0xfd987193, 12)\n c = fnF(c, d, a, b, M[14], 0xa679438e, 17)\n b = fnF(b, c, d, a, M[15], 0x49b40821, 22)\n\n a = fnG(a, b, c, d, M[1], 0xf61e2562, 5)\n d = fnG(d, a, b, c, M[6], 0xc040b340, 9)\n c = fnG(c, d, a, b, M[11], 0x265e5a51, 14)\n b = fnG(b, c, d, a, M[0], 0xe9b6c7aa, 20)\n a = fnG(a, b, c, d, M[5], 0xd62f105d, 5)\n d = fnG(d, a, b, c, M[10], 0x02441453, 9)\n c = fnG(c, d, a, b, M[15], 0xd8a1e681, 14)\n b = fnG(b, c, d, a, M[4], 0xe7d3fbc8, 20)\n a = fnG(a, b, c, d, M[9], 0x21e1cde6, 5)\n d = fnG(d, a, b, c, M[14], 0xc33707d6, 9)\n c = fnG(c, d, a, b, M[3], 0xf4d50d87, 14)\n b = fnG(b, c, d, a, M[8], 0x455a14ed, 20)\n a = fnG(a, b, c, d, M[13], 0xa9e3e905, 5)\n d = fnG(d, a, b, c, M[2], 0xfcefa3f8, 9)\n c = fnG(c, d, a, b, M[7], 0x676f02d9, 14)\n b = fnG(b, c, d, a, M[12], 0x8d2a4c8a, 20)\n\n a = fnH(a, b, c, d, M[5], 0xfffa3942, 4)\n d = fnH(d, a, b, c, M[8], 0x8771f681, 11)\n c = fnH(c, d, a, b, M[11], 0x6d9d6122, 16)\n b = fnH(b, c, d, a, M[14], 0xfde5380c, 23)\n a = fnH(a, b, c, d, M[1], 0xa4beea44, 4)\n d = fnH(d, a, b, c, M[4], 0x4bdecfa9, 11)\n c = fnH(c, d, a, b, M[7], 0xf6bb4b60, 16)\n b = fnH(b, c, d, a, M[10], 0xbebfbc70, 23)\n a = fnH(a, b, c, d, M[13], 0x289b7ec6, 4)\n d = fnH(d, a, b, c, M[0], 0xeaa127fa, 11)\n c = fnH(c, d, a, b, M[3], 0xd4ef3085, 16)\n b = fnH(b, c, d, a, M[6], 0x04881d05, 23)\n a = fnH(a, b, c, d, M[9], 0xd9d4d039, 4)\n d = fnH(d, a, b, c, M[12], 0xe6db99e5, 11)\n c = fnH(c, d, a, b, M[15], 0x1fa27cf8, 16)\n b = fnH(b, c, d, a, M[2], 0xc4ac5665, 23)\n\n a = fnI(a, b, c, d, M[0], 0xf4292244, 6)\n d = fnI(d, a, b, c, M[7], 0x432aff97, 10)\n c = fnI(c, d, a, b, M[14], 0xab9423a7, 15)\n b = fnI(b, c, d, a, M[5], 0xfc93a039, 21)\n a = fnI(a, b, c, d, M[12], 0x655b59c3, 6)\n d = fnI(d, a, b, c, M[3], 0x8f0ccc92, 10)\n c = fnI(c, d, a, b, M[10], 0xffeff47d, 15)\n b = fnI(b, c, d, a, M[1], 0x85845dd1, 21)\n a = fnI(a, b, c, d, M[8], 0x6fa87e4f, 6)\n d = fnI(d, a, b, c, M[15], 0xfe2ce6e0, 10)\n c = fnI(c, d, a, b, M[6], 0xa3014314, 15)\n b = fnI(b, c, d, a, M[13], 0x4e0811a1, 21)\n a = fnI(a, b, c, d, M[4], 0xf7537e82, 6)\n d = fnI(d, a, b, c, M[11], 0xbd3af235, 10)\n c = fnI(c, d, a, b, M[2], 0x2ad7d2bb, 15)\n b = fnI(b, c, d, a, M[9], 0xeb86d391, 21)\n\n this._a = (this._a + a) | 0\n this._b = (this._b + b) | 0\n this._c = (this._c + c) | 0\n this._d = (this._d + d) | 0\n}\n\nMD5.prototype._digest = function () {\n // create padding and handle blocks\n this._block[this._blockOffset++] = 0x80\n if (this._blockOffset > 56) {\n this._block.fill(0, this._blockOffset, 64)\n this._update()\n this._blockOffset = 0\n }\n\n this._block.fill(0, this._blockOffset, 56)\n this._block.writeUInt32LE(this._length[0], 56)\n this._block.writeUInt32LE(this._length[1], 60)\n this._update()\n\n // produce result\n var buffer = Buffer.allocUnsafe(16)\n buffer.writeInt32LE(this._a, 0)\n buffer.writeInt32LE(this._b, 4)\n buffer.writeInt32LE(this._c, 8)\n buffer.writeInt32LE(this._d, 12)\n return buffer\n}\n\nfunction rotl (x, n) {\n return (x << n) | (x >>> (32 - n))\n}\n\nfunction fnF (a, b, c, d, m, k, s) {\n return (rotl((a + ((b & c) | ((~b) & d)) + m + k) | 0, s) + b) | 0\n}\n\nfunction fnG (a, b, c, d, m, k, s) {\n return (rotl((a + ((b & d) | (c & (~d))) + m + k) | 0, s) + b) | 0\n}\n\nfunction fnH (a, b, c, d, m, k, s) {\n return (rotl((a + (b ^ c ^ d) + m + k) | 0, s) + b) | 0\n}\n\nfunction fnI (a, b, c, d, m, k, s) {\n return (rotl((a + ((c ^ (b | (~d)))) + m + k) | 0, s) + b) | 0\n}\n\nmodule.exports = MD5\n","// Ported from https://github.com/mafintosh/end-of-stream with\n// permission from the author, Mathias Buus (@mafintosh).\n'use strict';\n\nvar ERR_STREAM_PREMATURE_CLOSE = require('../../../errors').codes.ERR_STREAM_PREMATURE_CLOSE;\n\nfunction once(callback) {\n var called = false;\n return function () {\n if (called) return;\n called = true;\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n callback.apply(this, args);\n };\n}\n\nfunction noop() {}\n\nfunction isRequest(stream) {\n return stream.setHeader && typeof stream.abort === 'function';\n}\n\nfunction eos(stream, opts, callback) {\n if (typeof opts === 'function') return eos(stream, null, opts);\n if (!opts) opts = {};\n callback = once(callback || noop);\n var readable = opts.readable || opts.readable !== false && stream.readable;\n var writable = opts.writable || opts.writable !== false && stream.writable;\n\n var onlegacyfinish = function onlegacyfinish() {\n if (!stream.writable) onfinish();\n };\n\n var writableEnded = stream._writableState && stream._writableState.finished;\n\n var onfinish = function onfinish() {\n writable = false;\n writableEnded = true;\n if (!readable) callback.call(stream);\n };\n\n var readableEnded = stream._readableState && stream._readableState.endEmitted;\n\n var onend = function onend() {\n readable = false;\n readableEnded = true;\n if (!writable) callback.call(stream);\n };\n\n var onerror = function onerror(err) {\n callback.call(stream, err);\n };\n\n var onclose = function onclose() {\n var err;\n\n if (readable && !readableEnded) {\n if (!stream._readableState || !stream._readableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE();\n return callback.call(stream, err);\n }\n\n if (writable && !writableEnded) {\n if (!stream._writableState || !stream._writableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE();\n return callback.call(stream, err);\n }\n };\n\n var onrequest = function onrequest() {\n stream.req.on('finish', onfinish);\n };\n\n if (isRequest(stream)) {\n stream.on('complete', onfinish);\n stream.on('abort', onclose);\n if (stream.req) onrequest();else stream.on('request', onrequest);\n } else if (writable && !stream._writableState) {\n // legacy streams\n stream.on('end', onlegacyfinish);\n stream.on('close', onlegacyfinish);\n }\n\n stream.on('end', onend);\n stream.on('finish', onfinish);\n if (opts.error !== false) stream.on('error', onerror);\n stream.on('close', onclose);\n return function () {\n stream.removeListener('complete', onfinish);\n stream.removeListener('abort', onclose);\n stream.removeListener('request', onrequest);\n if (stream.req) stream.req.removeListener('finish', onfinish);\n stream.removeListener('end', onlegacyfinish);\n stream.removeListener('close', onlegacyfinish);\n stream.removeListener('finish', onfinish);\n stream.removeListener('end', onend);\n stream.removeListener('error', onerror);\n stream.removeListener('close', onclose);\n };\n}\n\nmodule.exports = eos;","'use strict'\nvar Buffer = require('buffer').Buffer\nvar inherits = require('inherits')\nvar HashBase = require('hash-base')\n\nvar ARRAY16 = new Array(16)\n\nvar zl = [\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,\n 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,\n 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,\n 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13\n]\n\nvar zr = [\n 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,\n 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,\n 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,\n 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,\n 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11\n]\n\nvar sl = [\n 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,\n 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,\n 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,\n 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,\n 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6\n]\n\nvar sr = [\n 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,\n 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,\n 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,\n 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,\n 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11\n]\n\nvar hl = [0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e]\nvar hr = [0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000]\n\nfunction RIPEMD160 () {\n HashBase.call(this, 64)\n\n // state\n this._a = 0x67452301\n this._b = 0xefcdab89\n this._c = 0x98badcfe\n this._d = 0x10325476\n this._e = 0xc3d2e1f0\n}\n\ninherits(RIPEMD160, HashBase)\n\nRIPEMD160.prototype._update = function () {\n var words = ARRAY16\n for (var j = 0; j < 16; ++j) words[j] = this._block.readInt32LE(j * 4)\n\n var al = this._a | 0\n var bl = this._b | 0\n var cl = this._c | 0\n var dl = this._d | 0\n var el = this._e | 0\n\n var ar = this._a | 0\n var br = this._b | 0\n var cr = this._c | 0\n var dr = this._d | 0\n var er = this._e | 0\n\n // computation\n for (var i = 0; i < 80; i += 1) {\n var tl\n var tr\n if (i < 16) {\n tl = fn1(al, bl, cl, dl, el, words[zl[i]], hl[0], sl[i])\n tr = fn5(ar, br, cr, dr, er, words[zr[i]], hr[0], sr[i])\n } else if (i < 32) {\n tl = fn2(al, bl, cl, dl, el, words[zl[i]], hl[1], sl[i])\n tr = fn4(ar, br, cr, dr, er, words[zr[i]], hr[1], sr[i])\n } else if (i < 48) {\n tl = fn3(al, bl, cl, dl, el, words[zl[i]], hl[2], sl[i])\n tr = fn3(ar, br, cr, dr, er, words[zr[i]], hr[2], sr[i])\n } else if (i < 64) {\n tl = fn4(al, bl, cl, dl, el, words[zl[i]], hl[3], sl[i])\n tr = fn2(ar, br, cr, dr, er, words[zr[i]], hr[3], sr[i])\n } else { // if (i<80) {\n tl = fn5(al, bl, cl, dl, el, words[zl[i]], hl[4], sl[i])\n tr = fn1(ar, br, cr, dr, er, words[zr[i]], hr[4], sr[i])\n }\n\n al = el\n el = dl\n dl = rotl(cl, 10)\n cl = bl\n bl = tl\n\n ar = er\n er = dr\n dr = rotl(cr, 10)\n cr = br\n br = tr\n }\n\n // update state\n var t = (this._b + cl + dr) | 0\n this._b = (this._c + dl + er) | 0\n this._c = (this._d + el + ar) | 0\n this._d = (this._e + al + br) | 0\n this._e = (this._a + bl + cr) | 0\n this._a = t\n}\n\nRIPEMD160.prototype._digest = function () {\n // create padding and handle blocks\n this._block[this._blockOffset++] = 0x80\n if (this._blockOffset > 56) {\n this._block.fill(0, this._blockOffset, 64)\n this._update()\n this._blockOffset = 0\n }\n\n this._block.fill(0, this._blockOffset, 56)\n this._block.writeUInt32LE(this._length[0], 56)\n this._block.writeUInt32LE(this._length[1], 60)\n this._update()\n\n // produce result\n var buffer = Buffer.alloc ? Buffer.alloc(20) : new Buffer(20)\n buffer.writeInt32LE(this._a, 0)\n buffer.writeInt32LE(this._b, 4)\n buffer.writeInt32LE(this._c, 8)\n buffer.writeInt32LE(this._d, 12)\n buffer.writeInt32LE(this._e, 16)\n return buffer\n}\n\nfunction rotl (x, n) {\n return (x << n) | (x >>> (32 - n))\n}\n\nfunction fn1 (a, b, c, d, e, m, k, s) {\n return (rotl((a + (b ^ c ^ d) + m + k) | 0, s) + e) | 0\n}\n\nfunction fn2 (a, b, c, d, e, m, k, s) {\n return (rotl((a + ((b & c) | ((~b) & d)) + m + k) | 0, s) + e) | 0\n}\n\nfunction fn3 (a, b, c, d, e, m, k, s) {\n return (rotl((a + ((b | (~c)) ^ d) + m + k) | 0, s) + e) | 0\n}\n\nfunction fn4 (a, b, c, d, e, m, k, s) {\n return (rotl((a + ((b & d) | (c & (~d))) + m + k) | 0, s) + e) | 0\n}\n\nfunction fn5 (a, b, c, d, e, m, k, s) {\n return (rotl((a + (b ^ (c | (~d))) + m + k) | 0, s) + e) | 0\n}\n\nmodule.exports = RIPEMD160\n","var exports = module.exports = function SHA (algorithm) {\n algorithm = algorithm.toLowerCase()\n\n var Algorithm = exports[algorithm]\n if (!Algorithm) throw new Error(algorithm + ' is not supported (we accept pull requests)')\n\n return new Algorithm()\n}\n\nexports.sha = require('./sha')\nexports.sha1 = require('./sha1')\nexports.sha224 = require('./sha224')\nexports.sha256 = require('./sha256')\nexports.sha384 = require('./sha384')\nexports.sha512 = require('./sha512')\n","exports = module.exports = require('./lib/_stream_readable.js');\nexports.Stream = exports;\nexports.Readable = exports;\nexports.Writable = require('./lib/_stream_writable.js');\nexports.Duplex = require('./lib/_stream_duplex.js');\nexports.Transform = require('./lib/_stream_transform.js');\nexports.PassThrough = require('./lib/_stream_passthrough.js');\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// A bit simpler than readable streams.\n// Implement an async ._write(chunk, encoding, cb), and it'll handle all\n// the drain event emission and buffering.\n\n'use strict';\n\n/**/\n\nvar pna = require('process-nextick-args');\n/**/\n\nmodule.exports = Writable;\n\n/* */\nfunction WriteReq(chunk, encoding, cb) {\n this.chunk = chunk;\n this.encoding = encoding;\n this.callback = cb;\n this.next = null;\n}\n\n// It seems a linked list but it is not\n// there will be only 2 of these for each stream\nfunction CorkedRequest(state) {\n var _this = this;\n\n this.next = null;\n this.entry = null;\n this.finish = function () {\n onCorkedFinish(_this, state);\n };\n}\n/* */\n\n/**/\nvar asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : pna.nextTick;\n/**/\n\n/**/\nvar Duplex;\n/**/\n\nWritable.WritableState = WritableState;\n\n/**/\nvar util = Object.create(require('core-util-is'));\nutil.inherits = require('inherits');\n/**/\n\n/**/\nvar internalUtil = {\n deprecate: require('util-deprecate')\n};\n/**/\n\n/**/\nvar Stream = require('./internal/streams/stream');\n/**/\n\n/**/\n\nvar Buffer = require('safe-buffer').Buffer;\nvar OurUint8Array = global.Uint8Array || function () {};\nfunction _uint8ArrayToBuffer(chunk) {\n return Buffer.from(chunk);\n}\nfunction _isUint8Array(obj) {\n return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;\n}\n\n/**/\n\nvar destroyImpl = require('./internal/streams/destroy');\n\nutil.inherits(Writable, Stream);\n\nfunction nop() {}\n\nfunction WritableState(options, stream) {\n Duplex = Duplex || require('./_stream_duplex');\n\n options = options || {};\n\n // Duplex streams are both readable and writable, but share\n // the same options object.\n // However, some cases require setting options to different\n // values for the readable and the writable sides of the duplex stream.\n // These options can be provided separately as readableXXX and writableXXX.\n var isDuplex = stream instanceof Duplex;\n\n // object stream flag to indicate whether or not this stream\n // contains buffers or objects.\n this.objectMode = !!options.objectMode;\n\n if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode;\n\n // the point at which write() starts returning false\n // Note: 0 is a valid value, means that we always return false if\n // the entire buffer is not flushed immediately on write()\n var hwm = options.highWaterMark;\n var writableHwm = options.writableHighWaterMark;\n var defaultHwm = this.objectMode ? 16 : 16 * 1024;\n\n if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (writableHwm || writableHwm === 0)) this.highWaterMark = writableHwm;else this.highWaterMark = defaultHwm;\n\n // cast to ints.\n this.highWaterMark = Math.floor(this.highWaterMark);\n\n // if _final has been called\n this.finalCalled = false;\n\n // drain event flag.\n this.needDrain = false;\n // at the start of calling end()\n this.ending = false;\n // when end() has been called, and returned\n this.ended = false;\n // when 'finish' is emitted\n this.finished = false;\n\n // has it been destroyed\n this.destroyed = false;\n\n // should we decode strings into buffers before passing to _write?\n // this is here so that some node-core streams can optimize string\n // handling at a lower level.\n var noDecode = options.decodeStrings === false;\n this.decodeStrings = !noDecode;\n\n // Crypto is kind of old and crusty. Historically, its default string\n // encoding is 'binary' so we have to make this configurable.\n // Everything else in the universe uses 'utf8', though.\n this.defaultEncoding = options.defaultEncoding || 'utf8';\n\n // not an actual buffer we keep track of, but a measurement\n // of how much we're waiting to get pushed to some underlying\n // socket or file.\n this.length = 0;\n\n // a flag to see when we're in the middle of a write.\n this.writing = false;\n\n // when true all writes will be buffered until .uncork() call\n this.corked = 0;\n\n // a flag to be able to tell if the onwrite cb is called immediately,\n // or on a later tick. We set this to true at first, because any\n // actions that shouldn't happen until \"later\" should generally also\n // not happen before the first write call.\n this.sync = true;\n\n // a flag to know if we're processing previously buffered items, which\n // may call the _write() callback in the same tick, so that we don't\n // end up in an overlapped onwrite situation.\n this.bufferProcessing = false;\n\n // the callback that's passed to _write(chunk,cb)\n this.onwrite = function (er) {\n onwrite(stream, er);\n };\n\n // the callback that the user supplies to write(chunk,encoding,cb)\n this.writecb = null;\n\n // the amount that is being written when _write is called.\n this.writelen = 0;\n\n this.bufferedRequest = null;\n this.lastBufferedRequest = null;\n\n // number of pending user-supplied write callbacks\n // this must be 0 before 'finish' can be emitted\n this.pendingcb = 0;\n\n // emit prefinish if the only thing we're waiting for is _write cbs\n // This is relevant for synchronous Transform streams\n this.prefinished = false;\n\n // True if the error was already emitted and should not be thrown again\n this.errorEmitted = false;\n\n // count buffered requests\n this.bufferedRequestCount = 0;\n\n // allocate the first CorkedRequest, there is always\n // one allocated and free to use, and we maintain at most two\n this.corkedRequestsFree = new CorkedRequest(this);\n}\n\nWritableState.prototype.getBuffer = function getBuffer() {\n var current = this.bufferedRequest;\n var out = [];\n while (current) {\n out.push(current);\n current = current.next;\n }\n return out;\n};\n\n(function () {\n try {\n Object.defineProperty(WritableState.prototype, 'buffer', {\n get: internalUtil.deprecate(function () {\n return this.getBuffer();\n }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003')\n });\n } catch (_) {}\n})();\n\n// Test _writableState for inheritance to account for Duplex streams,\n// whose prototype chain only points to Readable.\nvar realHasInstance;\nif (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') {\n realHasInstance = Function.prototype[Symbol.hasInstance];\n Object.defineProperty(Writable, Symbol.hasInstance, {\n value: function (object) {\n if (realHasInstance.call(this, object)) return true;\n if (this !== Writable) return false;\n\n return object && object._writableState instanceof WritableState;\n }\n });\n} else {\n realHasInstance = function (object) {\n return object instanceof this;\n };\n}\n\nfunction Writable(options) {\n Duplex = Duplex || require('./_stream_duplex');\n\n // Writable ctor is applied to Duplexes, too.\n // `realHasInstance` is necessary because using plain `instanceof`\n // would return false, as no `_writableState` property is attached.\n\n // Trying to use the custom `instanceof` for Writable here will also break the\n // Node.js LazyTransform implementation, which has a non-trivial getter for\n // `_writableState` that would lead to infinite recursion.\n if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) {\n return new Writable(options);\n }\n\n this._writableState = new WritableState(options, this);\n\n // legacy.\n this.writable = true;\n\n if (options) {\n if (typeof options.write === 'function') this._write = options.write;\n\n if (typeof options.writev === 'function') this._writev = options.writev;\n\n if (typeof options.destroy === 'function') this._destroy = options.destroy;\n\n if (typeof options.final === 'function') this._final = options.final;\n }\n\n Stream.call(this);\n}\n\n// Otherwise people can pipe Writable streams, which is just wrong.\nWritable.prototype.pipe = function () {\n this.emit('error', new Error('Cannot pipe, not readable'));\n};\n\nfunction writeAfterEnd(stream, cb) {\n var er = new Error('write after end');\n // TODO: defer error events consistently everywhere, not just the cb\n stream.emit('error', er);\n pna.nextTick(cb, er);\n}\n\n// Checks that a user-supplied chunk is valid, especially for the particular\n// mode the stream is in. Currently this means that `null` is never accepted\n// and undefined/non-string values are only allowed in object mode.\nfunction validChunk(stream, state, chunk, cb) {\n var valid = true;\n var er = false;\n\n if (chunk === null) {\n er = new TypeError('May not write null values to stream');\n } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {\n er = new TypeError('Invalid non-string/buffer chunk');\n }\n if (er) {\n stream.emit('error', er);\n pna.nextTick(cb, er);\n valid = false;\n }\n return valid;\n}\n\nWritable.prototype.write = function (chunk, encoding, cb) {\n var state = this._writableState;\n var ret = false;\n var isBuf = !state.objectMode && _isUint8Array(chunk);\n\n if (isBuf && !Buffer.isBuffer(chunk)) {\n chunk = _uint8ArrayToBuffer(chunk);\n }\n\n if (typeof encoding === 'function') {\n cb = encoding;\n encoding = null;\n }\n\n if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;\n\n if (typeof cb !== 'function') cb = nop;\n\n if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) {\n state.pendingcb++;\n ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);\n }\n\n return ret;\n};\n\nWritable.prototype.cork = function () {\n var state = this._writableState;\n\n state.corked++;\n};\n\nWritable.prototype.uncork = function () {\n var state = this._writableState;\n\n if (state.corked) {\n state.corked--;\n\n if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);\n }\n};\n\nWritable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {\n // node::ParseEncoding() requires lower case.\n if (typeof encoding === 'string') encoding = encoding.toLowerCase();\n if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding);\n this._writableState.defaultEncoding = encoding;\n return this;\n};\n\nfunction decodeChunk(state, chunk, encoding) {\n if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {\n chunk = Buffer.from(chunk, encoding);\n }\n return chunk;\n}\n\nObject.defineProperty(Writable.prototype, 'writableHighWaterMark', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function () {\n return this._writableState.highWaterMark;\n }\n});\n\n// if we're already writing something, then just put this\n// in the queue, and wait our turn. Otherwise, call _write\n// If we return false, then we need a drain event, so set that flag.\nfunction writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {\n if (!isBuf) {\n var newChunk = decodeChunk(state, chunk, encoding);\n if (chunk !== newChunk) {\n isBuf = true;\n encoding = 'buffer';\n chunk = newChunk;\n }\n }\n var len = state.objectMode ? 1 : chunk.length;\n\n state.length += len;\n\n var ret = state.length < state.highWaterMark;\n // we must ensure that previous needDrain will not be reset to false.\n if (!ret) state.needDrain = true;\n\n if (state.writing || state.corked) {\n var last = state.lastBufferedRequest;\n state.lastBufferedRequest = {\n chunk: chunk,\n encoding: encoding,\n isBuf: isBuf,\n callback: cb,\n next: null\n };\n if (last) {\n last.next = state.lastBufferedRequest;\n } else {\n state.bufferedRequest = state.lastBufferedRequest;\n }\n state.bufferedRequestCount += 1;\n } else {\n doWrite(stream, state, false, len, chunk, encoding, cb);\n }\n\n return ret;\n}\n\nfunction doWrite(stream, state, writev, len, chunk, encoding, cb) {\n state.writelen = len;\n state.writecb = cb;\n state.writing = true;\n state.sync = true;\n if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);\n state.sync = false;\n}\n\nfunction onwriteError(stream, state, sync, er, cb) {\n --state.pendingcb;\n\n if (sync) {\n // defer the callback if we are being called synchronously\n // to avoid piling up things on the stack\n pna.nextTick(cb, er);\n // this can emit finish, and it will always happen\n // after error\n pna.nextTick(finishMaybe, stream, state);\n stream._writableState.errorEmitted = true;\n stream.emit('error', er);\n } else {\n // the caller expect this to happen before if\n // it is async\n cb(er);\n stream._writableState.errorEmitted = true;\n stream.emit('error', er);\n // this can emit finish, but finish must\n // always follow error\n finishMaybe(stream, state);\n }\n}\n\nfunction onwriteStateUpdate(state) {\n state.writing = false;\n state.writecb = null;\n state.length -= state.writelen;\n state.writelen = 0;\n}\n\nfunction onwrite(stream, er) {\n var state = stream._writableState;\n var sync = state.sync;\n var cb = state.writecb;\n\n onwriteStateUpdate(state);\n\n if (er) onwriteError(stream, state, sync, er, cb);else {\n // Check if we're actually ready to finish, but don't emit yet\n var finished = needFinish(state);\n\n if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {\n clearBuffer(stream, state);\n }\n\n if (sync) {\n /**/\n asyncWrite(afterWrite, stream, state, finished, cb);\n /**/\n } else {\n afterWrite(stream, state, finished, cb);\n }\n }\n}\n\nfunction afterWrite(stream, state, finished, cb) {\n if (!finished) onwriteDrain(stream, state);\n state.pendingcb--;\n cb();\n finishMaybe(stream, state);\n}\n\n// Must force callback to be called on nextTick, so that we don't\n// emit 'drain' before the write() consumer gets the 'false' return\n// value, and has a chance to attach a 'drain' listener.\nfunction onwriteDrain(stream, state) {\n if (state.length === 0 && state.needDrain) {\n state.needDrain = false;\n stream.emit('drain');\n }\n}\n\n// if there's something in the buffer waiting, then process it\nfunction clearBuffer(stream, state) {\n state.bufferProcessing = true;\n var entry = state.bufferedRequest;\n\n if (stream._writev && entry && entry.next) {\n // Fast case, write everything using _writev()\n var l = state.bufferedRequestCount;\n var buffer = new Array(l);\n var holder = state.corkedRequestsFree;\n holder.entry = entry;\n\n var count = 0;\n var allBuffers = true;\n while (entry) {\n buffer[count] = entry;\n if (!entry.isBuf) allBuffers = false;\n entry = entry.next;\n count += 1;\n }\n buffer.allBuffers = allBuffers;\n\n doWrite(stream, state, true, state.length, buffer, '', holder.finish);\n\n // doWrite is almost always async, defer these to save a bit of time\n // as the hot path ends with doWrite\n state.pendingcb++;\n state.lastBufferedRequest = null;\n if (holder.next) {\n state.corkedRequestsFree = holder.next;\n holder.next = null;\n } else {\n state.corkedRequestsFree = new CorkedRequest(state);\n }\n state.bufferedRequestCount = 0;\n } else {\n // Slow case, write chunks one-by-one\n while (entry) {\n var chunk = entry.chunk;\n var encoding = entry.encoding;\n var cb = entry.callback;\n var len = state.objectMode ? 1 : chunk.length;\n\n doWrite(stream, state, false, len, chunk, encoding, cb);\n entry = entry.next;\n state.bufferedRequestCount--;\n // if we didn't call the onwrite immediately, then\n // it means that we need to wait until it does.\n // also, that means that the chunk and cb are currently\n // being processed, so move the buffer counter past them.\n if (state.writing) {\n break;\n }\n }\n\n if (entry === null) state.lastBufferedRequest = null;\n }\n\n state.bufferedRequest = entry;\n state.bufferProcessing = false;\n}\n\nWritable.prototype._write = function (chunk, encoding, cb) {\n cb(new Error('_write() is not implemented'));\n};\n\nWritable.prototype._writev = null;\n\nWritable.prototype.end = function (chunk, encoding, cb) {\n var state = this._writableState;\n\n if (typeof chunk === 'function') {\n cb = chunk;\n chunk = null;\n encoding = null;\n } else if (typeof encoding === 'function') {\n cb = encoding;\n encoding = null;\n }\n\n if (chunk !== null && chunk !== undefined) this.write(chunk, encoding);\n\n // .end() fully uncorks\n if (state.corked) {\n state.corked = 1;\n this.uncork();\n }\n\n // ignore unnecessary end() calls.\n if (!state.ending && !state.finished) endWritable(this, state, cb);\n};\n\nfunction needFinish(state) {\n return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;\n}\nfunction callFinal(stream, state) {\n stream._final(function (err) {\n state.pendingcb--;\n if (err) {\n stream.emit('error', err);\n }\n state.prefinished = true;\n stream.emit('prefinish');\n finishMaybe(stream, state);\n });\n}\nfunction prefinish(stream, state) {\n if (!state.prefinished && !state.finalCalled) {\n if (typeof stream._final === 'function') {\n state.pendingcb++;\n state.finalCalled = true;\n pna.nextTick(callFinal, stream, state);\n } else {\n state.prefinished = true;\n stream.emit('prefinish');\n }\n }\n}\n\nfunction finishMaybe(stream, state) {\n var need = needFinish(state);\n if (need) {\n prefinish(stream, state);\n if (state.pendingcb === 0) {\n state.finished = true;\n stream.emit('finish');\n }\n }\n return need;\n}\n\nfunction endWritable(stream, state, cb) {\n state.ending = true;\n finishMaybe(stream, state);\n if (cb) {\n if (state.finished) pna.nextTick(cb);else stream.once('finish', cb);\n }\n state.ended = true;\n stream.writable = false;\n}\n\nfunction onCorkedFinish(corkReq, state, err) {\n var entry = corkReq.entry;\n corkReq.entry = null;\n while (entry) {\n var cb = entry.callback;\n state.pendingcb--;\n cb(err);\n entry = entry.next;\n }\n if (state.corkedRequestsFree) {\n state.corkedRequestsFree.next = corkReq;\n } else {\n state.corkedRequestsFree = corkReq;\n }\n}\n\nObject.defineProperty(Writable.prototype, 'destroyed', {\n get: function () {\n if (this._writableState === undefined) {\n return false;\n }\n return this._writableState.destroyed;\n },\n set: function (value) {\n // we ignore the value if the stream\n // has not been initialized yet\n if (!this._writableState) {\n return;\n }\n\n // backward compatibility, the user is explicitly\n // managing destroyed\n this._writableState.destroyed = value;\n }\n});\n\nWritable.prototype.destroy = destroyImpl.destroy;\nWritable.prototype._undestroy = destroyImpl.undestroy;\nWritable.prototype._destroy = function (err, cb) {\n this.end();\n cb(err);\n};","'use strict';\n\nvar assert = require('minimalistic-assert');\n\nfunction Cipher(options) {\n this.options = options;\n\n this.type = this.options.type;\n this.blockSize = 8;\n this._init();\n\n this.buffer = new Array(this.blockSize);\n this.bufferOff = 0;\n}\nmodule.exports = Cipher;\n\nCipher.prototype._init = function _init() {\n // Might be overrided\n};\n\nCipher.prototype.update = function update(data) {\n if (data.length === 0)\n return [];\n\n if (this.type === 'decrypt')\n return this._updateDecrypt(data);\n else\n return this._updateEncrypt(data);\n};\n\nCipher.prototype._buffer = function _buffer(data, off) {\n // Append data to buffer\n var min = Math.min(this.buffer.length - this.bufferOff, data.length - off);\n for (var i = 0; i < min; i++)\n this.buffer[this.bufferOff + i] = data[off + i];\n this.bufferOff += min;\n\n // Shift next\n return min;\n};\n\nCipher.prototype._flushBuffer = function _flushBuffer(out, off) {\n this._update(this.buffer, 0, out, off);\n this.bufferOff = 0;\n return this.blockSize;\n};\n\nCipher.prototype._updateEncrypt = function _updateEncrypt(data) {\n var inputOff = 0;\n var outputOff = 0;\n\n var count = ((this.bufferOff + data.length) / this.blockSize) | 0;\n var out = new Array(count * this.blockSize);\n\n if (this.bufferOff !== 0) {\n inputOff += this._buffer(data, inputOff);\n\n if (this.bufferOff === this.buffer.length)\n outputOff += this._flushBuffer(out, outputOff);\n }\n\n // Write blocks\n var max = data.length - ((data.length - inputOff) % this.blockSize);\n for (; inputOff < max; inputOff += this.blockSize) {\n this._update(data, inputOff, out, outputOff);\n outputOff += this.blockSize;\n }\n\n // Queue rest\n for (; inputOff < data.length; inputOff++, this.bufferOff++)\n this.buffer[this.bufferOff] = data[inputOff];\n\n return out;\n};\n\nCipher.prototype._updateDecrypt = function _updateDecrypt(data) {\n var inputOff = 0;\n var outputOff = 0;\n\n var count = Math.ceil((this.bufferOff + data.length) / this.blockSize) - 1;\n var out = new Array(count * this.blockSize);\n\n // TODO(indutny): optimize it, this is far from optimal\n for (; count > 0; count--) {\n inputOff += this._buffer(data, inputOff);\n outputOff += this._flushBuffer(out, outputOff);\n }\n\n // Buffer rest of the input\n inputOff += this._buffer(data, inputOff);\n\n return out;\n};\n\nCipher.prototype.final = function final(buffer) {\n var first;\n if (buffer)\n first = this.update(buffer);\n\n var last;\n if (this.type === 'encrypt')\n last = this._finalEncrypt();\n else\n last = this._finalDecrypt();\n\n if (first)\n return first.concat(last);\n else\n return last;\n};\n\nCipher.prototype._pad = function _pad(buffer, off) {\n if (off === 0)\n return false;\n\n while (off < buffer.length)\n buffer[off++] = 0;\n\n return true;\n};\n\nCipher.prototype._finalEncrypt = function _finalEncrypt() {\n if (!this._pad(this.buffer, this.bufferOff))\n return [];\n\n var out = new Array(this.blockSize);\n this._update(this.buffer, 0, out, 0);\n return out;\n};\n\nCipher.prototype._unpad = function _unpad(buffer) {\n return buffer;\n};\n\nCipher.prototype._finalDecrypt = function _finalDecrypt() {\n assert.equal(this.bufferOff, this.blockSize, 'Not enough data to decrypt');\n var out = new Array(this.blockSize);\n this._flushBuffer(out, 0);\n\n return this._unpad(out);\n};\n","var ciphers = require('./encrypter')\nvar deciphers = require('./decrypter')\nvar modes = require('./modes/list.json')\n\nfunction getCiphers () {\n return Object.keys(modes)\n}\n\nexports.createCipher = exports.Cipher = ciphers.createCipher\nexports.createCipheriv = exports.Cipheriv = ciphers.createCipheriv\nexports.createDecipher = exports.Decipher = deciphers.createDecipher\nexports.createDecipheriv = exports.Decipheriv = deciphers.createDecipheriv\nexports.listCiphers = exports.getCiphers = getCiphers\n","var modeModules = {\n ECB: require('./ecb'),\n CBC: require('./cbc'),\n CFB: require('./cfb'),\n CFB8: require('./cfb8'),\n CFB1: require('./cfb1'),\n OFB: require('./ofb'),\n CTR: require('./ctr'),\n GCM: require('./ctr')\n}\n\nvar modes = require('./list.json')\n\nfor (var key in modes) {\n modes[key].module = modeModules[modes[key].mode]\n}\n\nmodule.exports = modes\n","var r;\n\nmodule.exports = function rand(len) {\n if (!r)\n r = new Rand(null);\n\n return r.generate(len);\n};\n\nfunction Rand(rand) {\n this.rand = rand;\n}\nmodule.exports.Rand = Rand;\n\nRand.prototype.generate = function generate(len) {\n return this._rand(len);\n};\n\n// Emulate crypto API using randy\nRand.prototype._rand = function _rand(n) {\n if (this.rand.getBytes)\n return this.rand.getBytes(n);\n\n var res = new Uint8Array(n);\n for (var i = 0; i < res.length; i++)\n res[i] = this.rand.getByte();\n return res;\n};\n\nif (typeof self === 'object') {\n if (self.crypto && self.crypto.getRandomValues) {\n // Modern browsers\n Rand.prototype._rand = function _rand(n) {\n var arr = new Uint8Array(n);\n self.crypto.getRandomValues(arr);\n return arr;\n };\n } else if (self.msCrypto && self.msCrypto.getRandomValues) {\n // IE\n Rand.prototype._rand = function _rand(n) {\n var arr = new Uint8Array(n);\n self.msCrypto.getRandomValues(arr);\n return arr;\n };\n\n // Safari's WebWorkers do not have `crypto`\n } else if (typeof window === 'object') {\n // Old junk\n Rand.prototype._rand = function() {\n throw new Error('Not implemented yet');\n };\n }\n} else {\n // Node.js or Web worker with no crypto support\n try {\n var crypto = require('crypto');\n if (typeof crypto.randomBytes !== 'function')\n throw new Error('Not supported');\n\n Rand.prototype._rand = function _rand(n) {\n return crypto.randomBytes(n);\n };\n } catch (e) {\n }\n}\n","// Ported from https://github.com/mafintosh/end-of-stream with\n// permission from the author, Mathias Buus (@mafintosh).\n'use strict';\n\nvar ERR_STREAM_PREMATURE_CLOSE = require('../../../errors').codes.ERR_STREAM_PREMATURE_CLOSE;\n\nfunction once(callback) {\n var called = false;\n return function () {\n if (called) return;\n called = true;\n\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n callback.apply(this, args);\n };\n}\n\nfunction noop() {}\n\nfunction isRequest(stream) {\n return stream.setHeader && typeof stream.abort === 'function';\n}\n\nfunction eos(stream, opts, callback) {\n if (typeof opts === 'function') return eos(stream, null, opts);\n if (!opts) opts = {};\n callback = once(callback || noop);\n var readable = opts.readable || opts.readable !== false && stream.readable;\n var writable = opts.writable || opts.writable !== false && stream.writable;\n\n var onlegacyfinish = function onlegacyfinish() {\n if (!stream.writable) onfinish();\n };\n\n var writableEnded = stream._writableState && stream._writableState.finished;\n\n var onfinish = function onfinish() {\n writable = false;\n writableEnded = true;\n if (!readable) callback.call(stream);\n };\n\n var readableEnded = stream._readableState && stream._readableState.endEmitted;\n\n var onend = function onend() {\n readable = false;\n readableEnded = true;\n if (!writable) callback.call(stream);\n };\n\n var onerror = function onerror(err) {\n callback.call(stream, err);\n };\n\n var onclose = function onclose() {\n var err;\n\n if (readable && !readableEnded) {\n if (!stream._readableState || !stream._readableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE();\n return callback.call(stream, err);\n }\n\n if (writable && !writableEnded) {\n if (!stream._writableState || !stream._writableState.ended) err = new ERR_STREAM_PREMATURE_CLOSE();\n return callback.call(stream, err);\n }\n };\n\n var onrequest = function onrequest() {\n stream.req.on('finish', onfinish);\n };\n\n if (isRequest(stream)) {\n stream.on('complete', onfinish);\n stream.on('abort', onclose);\n if (stream.req) onrequest();else stream.on('request', onrequest);\n } else if (writable && !stream._writableState) {\n // legacy streams\n stream.on('end', onlegacyfinish);\n stream.on('close', onlegacyfinish);\n }\n\n stream.on('end', onend);\n stream.on('finish', onfinish);\n if (opts.error !== false) stream.on('error', onerror);\n stream.on('close', onclose);\n return function () {\n stream.removeListener('complete', onfinish);\n stream.removeListener('abort', onclose);\n stream.removeListener('request', onrequest);\n if (stream.req) stream.req.removeListener('finish', onfinish);\n stream.removeListener('end', onlegacyfinish);\n stream.removeListener('close', onlegacyfinish);\n stream.removeListener('finish', onfinish);\n stream.removeListener('end', onend);\n stream.removeListener('error', onerror);\n stream.removeListener('close', onclose);\n };\n}\n\nmodule.exports = eos;","var bn = require('bn.js');\nvar randomBytes = require('randombytes');\nmodule.exports = crt;\nfunction blind(priv) {\n var r = getr(priv);\n var blinder = r.toRed(bn.mont(priv.modulus))\n .redPow(new bn(priv.publicExponent)).fromRed();\n return {\n blinder: blinder,\n unblinder:r.invm(priv.modulus)\n };\n}\nfunction crt(msg, priv) {\n var blinds = blind(priv);\n var len = priv.modulus.byteLength();\n var mod = bn.mont(priv.modulus);\n var blinded = new bn(msg).mul(blinds.blinder).umod(priv.modulus);\n var c1 = blinded.toRed(bn.mont(priv.prime1));\n var c2 = blinded.toRed(bn.mont(priv.prime2));\n var qinv = priv.coefficient;\n var p = priv.prime1;\n var q = priv.prime2;\n var m1 = c1.redPow(priv.exponent1);\n var m2 = c2.redPow(priv.exponent2);\n m1 = m1.fromRed();\n m2 = m2.fromRed();\n var h = m1.isub(m2).imul(qinv).umod(p);\n h.imul(q);\n m2.iadd(h);\n return new Buffer(m2.imul(blinds.unblinder).umod(priv.modulus).toArray(false, len));\n}\ncrt.getr = getr;\nfunction getr(priv) {\n var len = priv.modulus.byteLength();\n var r = new bn(randomBytes(len));\n while (r.cmp(priv.modulus) >= 0 || !r.umod(priv.prime1) || !r.umod(priv.prime2)) {\n r = new bn(randomBytes(len));\n }\n return r;\n}\n","'use strict';\n\nvar elliptic = exports;\n\nelliptic.version = require('../package.json').version;\nelliptic.utils = require('./elliptic/utils');\nelliptic.rand = require('brorand');\nelliptic.curve = require('./elliptic/curve');\nelliptic.curves = require('./elliptic/curves');\n\n// Protocols\nelliptic.ec = require('./elliptic/ec');\nelliptic.eddsa = require('./elliptic/eddsa');\n","'use strict';\n\nvar curves = exports;\n\nvar hash = require('hash.js');\nvar curve = require('./curve');\nvar utils = require('./utils');\n\nvar assert = utils.assert;\n\nfunction PresetCurve(options) {\n if (options.type === 'short')\n this.curve = new curve.short(options);\n else if (options.type === 'edwards')\n this.curve = new curve.edwards(options);\n else\n this.curve = new curve.mont(options);\n this.g = this.curve.g;\n this.n = this.curve.n;\n this.hash = options.hash;\n\n assert(this.g.validate(), 'Invalid curve');\n assert(this.g.mul(this.n).isInfinity(), 'Invalid curve, G*N != O');\n}\ncurves.PresetCurve = PresetCurve;\n\nfunction defineCurve(name, options) {\n Object.defineProperty(curves, name, {\n configurable: true,\n enumerable: true,\n get: function() {\n var curve = new PresetCurve(options);\n Object.defineProperty(curves, name, {\n configurable: true,\n enumerable: true,\n value: curve\n });\n return curve;\n }\n });\n}\n\ndefineCurve('p192', {\n type: 'short',\n prime: 'p192',\n p: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff',\n a: 'ffffffff ffffffff ffffffff fffffffe ffffffff fffffffc',\n b: '64210519 e59c80e7 0fa7e9ab 72243049 feb8deec c146b9b1',\n n: 'ffffffff ffffffff ffffffff 99def836 146bc9b1 b4d22831',\n hash: hash.sha256,\n gRed: false,\n g: [\n '188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012',\n '07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811'\n ]\n});\n\ndefineCurve('p224', {\n type: 'short',\n prime: 'p224',\n p: 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001',\n a: 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff fffffffe',\n b: 'b4050a85 0c04b3ab f5413256 5044b0b7 d7bfd8ba 270b3943 2355ffb4',\n n: 'ffffffff ffffffff ffffffff ffff16a2 e0b8f03e 13dd2945 5c5c2a3d',\n hash: hash.sha256,\n gRed: false,\n g: [\n 'b70e0cbd 6bb4bf7f 321390b9 4a03c1d3 56c21122 343280d6 115c1d21',\n 'bd376388 b5f723fb 4c22dfe6 cd4375a0 5a074764 44d58199 85007e34'\n ]\n});\n\ndefineCurve('p256', {\n type: 'short',\n prime: null,\n p: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff ffffffff',\n a: 'ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff fffffffc',\n b: '5ac635d8 aa3a93e7 b3ebbd55 769886bc 651d06b0 cc53b0f6 3bce3c3e 27d2604b',\n n: 'ffffffff 00000000 ffffffff ffffffff bce6faad a7179e84 f3b9cac2 fc632551',\n hash: hash.sha256,\n gRed: false,\n g: [\n '6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296',\n '4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5'\n ]\n});\n\ndefineCurve('p384', {\n type: 'short',\n prime: null,\n p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' +\n 'fffffffe ffffffff 00000000 00000000 ffffffff',\n a: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' +\n 'fffffffe ffffffff 00000000 00000000 fffffffc',\n b: 'b3312fa7 e23ee7e4 988e056b e3f82d19 181d9c6e fe814112 0314088f ' +\n '5013875a c656398d 8a2ed19d 2a85c8ed d3ec2aef',\n n: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff c7634d81 ' +\n 'f4372ddf 581a0db2 48b0a77a ecec196a ccc52973',\n hash: hash.sha384,\n gRed: false,\n g: [\n 'aa87ca22 be8b0537 8eb1c71e f320ad74 6e1d3b62 8ba79b98 59f741e0 82542a38 ' +\n '5502f25d bf55296c 3a545e38 72760ab7',\n '3617de4a 96262c6f 5d9e98bf 9292dc29 f8f41dbd 289a147c e9da3113 b5f0b8c0 ' +\n '0a60b1ce 1d7e819d 7a431d7c 90ea0e5f'\n ]\n});\n\ndefineCurve('p521', {\n type: 'short',\n prime: null,\n p: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' +\n 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' +\n 'ffffffff ffffffff ffffffff ffffffff ffffffff',\n a: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' +\n 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ' +\n 'ffffffff ffffffff ffffffff ffffffff fffffffc',\n b: '00000051 953eb961 8e1c9a1f 929a21a0 b68540ee a2da725b ' +\n '99b315f3 b8b48991 8ef109e1 56193951 ec7e937b 1652c0bd ' +\n '3bb1bf07 3573df88 3d2c34f1 ef451fd4 6b503f00',\n n: '000001ff ffffffff ffffffff ffffffff ffffffff ffffffff ' +\n 'ffffffff ffffffff fffffffa 51868783 bf2f966b 7fcc0148 ' +\n 'f709a5d0 3bb5c9b8 899c47ae bb6fb71e 91386409',\n hash: hash.sha512,\n gRed: false,\n g: [\n '000000c6 858e06b7 0404e9cd 9e3ecb66 2395b442 9c648139 ' +\n '053fb521 f828af60 6b4d3dba a14b5e77 efe75928 fe1dc127 ' +\n 'a2ffa8de 3348b3c1 856a429b f97e7e31 c2e5bd66',\n '00000118 39296a78 9a3bc004 5c8a5fb4 2c7d1bd9 98f54449 ' +\n '579b4468 17afbd17 273e662c 97ee7299 5ef42640 c550b901 ' +\n '3fad0761 353c7086 a272c240 88be9476 9fd16650'\n ]\n});\n\ndefineCurve('curve25519', {\n type: 'mont',\n prime: 'p25519',\n p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed',\n a: '76d06',\n b: '1',\n n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed',\n hash: hash.sha256,\n gRed: false,\n g: [\n '9'\n ]\n});\n\ndefineCurve('ed25519', {\n type: 'edwards',\n prime: 'p25519',\n p: '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed',\n a: '-1',\n c: '1',\n // -121665 * (121666^(-1)) (mod P)\n d: '52036cee2b6ffe73 8cc740797779e898 00700a4d4141d8ab 75eb4dca135978a3',\n n: '1000000000000000 0000000000000000 14def9dea2f79cd6 5812631a5cf5d3ed',\n hash: hash.sha256,\n gRed: false,\n g: [\n '216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a',\n\n // 4/5\n '6666666666666666666666666666666666666666666666666666666666666658'\n ]\n});\n\nvar pre;\ntry {\n pre = require('./precomputed/secp256k1');\n} catch (e) {\n pre = undefined;\n}\n\ndefineCurve('secp256k1', {\n type: 'short',\n prime: 'k256',\n p: 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f',\n a: '0',\n b: '7',\n n: 'ffffffff ffffffff ffffffff fffffffe baaedce6 af48a03b bfd25e8c d0364141',\n h: '1',\n hash: hash.sha256,\n\n // Precomputed endomorphism\n beta: '7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee',\n lambda: '5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72',\n basis: [\n {\n a: '3086d221a7d46bcde86c90e49284eb15',\n b: '-e4437ed6010e88286f547fa90abfe4c3'\n },\n {\n a: '114ca50f7a8e2f3f657c1108d9d44cfd8',\n b: '3086d221a7d46bcde86c90e49284eb15'\n }\n ],\n\n gRed: false,\n g: [\n '79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',\n '483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8',\n pre\n ]\n});\n","var hash = exports;\n\nhash.utils = require('./hash/utils');\nhash.common = require('./hash/common');\nhash.sha = require('./hash/sha');\nhash.ripemd = require('./hash/ripemd');\nhash.hmac = require('./hash/hmac');\n\n// Proxy hash functions to the main object\nhash.sha1 = hash.sha.sha1;\nhash.sha256 = hash.sha.sha256;\nhash.sha224 = hash.sha.sha224;\nhash.sha384 = hash.sha.sha384;\nhash.sha512 = hash.sha.sha512;\nhash.ripemd160 = hash.ripemd.ripemd160;\n","(function (module, exports) {\n 'use strict';\n\n // Utils\n function assert (val, msg) {\n if (!val) throw new Error(msg || 'Assertion failed');\n }\n\n // Could use `inherits` module, but don't want to move from single file\n // architecture yet.\n function inherits (ctor, superCtor) {\n ctor.super_ = superCtor;\n var TempCtor = function () {};\n TempCtor.prototype = superCtor.prototype;\n ctor.prototype = new TempCtor();\n ctor.prototype.constructor = ctor;\n }\n\n // BN\n\n function BN (number, base, endian) {\n if (BN.isBN(number)) {\n return number;\n }\n\n this.negative = 0;\n this.words = null;\n this.length = 0;\n\n // Reduction context\n this.red = null;\n\n if (number !== null) {\n if (base === 'le' || base === 'be') {\n endian = base;\n base = 10;\n }\n\n this._init(number || 0, base || 10, endian || 'be');\n }\n }\n if (typeof module === 'object') {\n module.exports = BN;\n } else {\n exports.BN = BN;\n }\n\n BN.BN = BN;\n BN.wordSize = 26;\n\n var Buffer;\n try {\n Buffer = require('buffer').Buffer;\n } catch (e) {\n }\n\n BN.isBN = function isBN (num) {\n if (num instanceof BN) {\n return true;\n }\n\n return num !== null && typeof num === 'object' &&\n num.constructor.wordSize === BN.wordSize && Array.isArray(num.words);\n };\n\n BN.max = function max (left, right) {\n if (left.cmp(right) > 0) return left;\n return right;\n };\n\n BN.min = function min (left, right) {\n if (left.cmp(right) < 0) return left;\n return right;\n };\n\n BN.prototype._init = function init (number, base, endian) {\n if (typeof number === 'number') {\n return this._initNumber(number, base, endian);\n }\n\n if (typeof number === 'object') {\n return this._initArray(number, base, endian);\n }\n\n if (base === 'hex') {\n base = 16;\n }\n assert(base === (base | 0) && base >= 2 && base <= 36);\n\n number = number.toString().replace(/\\s+/g, '');\n var start = 0;\n if (number[0] === '-') {\n start++;\n }\n\n if (base === 16) {\n this._parseHex(number, start);\n } else {\n this._parseBase(number, base, start);\n }\n\n if (number[0] === '-') {\n this.negative = 1;\n }\n\n this.strip();\n\n if (endian !== 'le') return;\n\n this._initArray(this.toArray(), base, endian);\n };\n\n BN.prototype._initNumber = function _initNumber (number, base, endian) {\n if (number < 0) {\n this.negative = 1;\n number = -number;\n }\n if (number < 0x4000000) {\n this.words = [ number & 0x3ffffff ];\n this.length = 1;\n } else if (number < 0x10000000000000) {\n this.words = [\n number & 0x3ffffff,\n (number / 0x4000000) & 0x3ffffff\n ];\n this.length = 2;\n } else {\n assert(number < 0x20000000000000); // 2 ^ 53 (unsafe)\n this.words = [\n number & 0x3ffffff,\n (number / 0x4000000) & 0x3ffffff,\n 1\n ];\n this.length = 3;\n }\n\n if (endian !== 'le') return;\n\n // Reverse the bytes\n this._initArray(this.toArray(), base, endian);\n };\n\n BN.prototype._initArray = function _initArray (number, base, endian) {\n // Perhaps a Uint8Array\n assert(typeof number.length === 'number');\n if (number.length <= 0) {\n this.words = [ 0 ];\n this.length = 1;\n return this;\n }\n\n this.length = Math.ceil(number.length / 3);\n this.words = new Array(this.length);\n for (var i = 0; i < this.length; i++) {\n this.words[i] = 0;\n }\n\n var j, w;\n var off = 0;\n if (endian === 'be') {\n for (i = number.length - 1, j = 0; i >= 0; i -= 3) {\n w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16);\n this.words[j] |= (w << off) & 0x3ffffff;\n this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;\n off += 24;\n if (off >= 26) {\n off -= 26;\n j++;\n }\n }\n } else if (endian === 'le') {\n for (i = 0, j = 0; i < number.length; i += 3) {\n w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16);\n this.words[j] |= (w << off) & 0x3ffffff;\n this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;\n off += 24;\n if (off >= 26) {\n off -= 26;\n j++;\n }\n }\n }\n return this.strip();\n };\n\n function parseHex (str, start, end) {\n var r = 0;\n var len = Math.min(str.length, end);\n for (var i = start; i < len; i++) {\n var c = str.charCodeAt(i) - 48;\n\n r <<= 4;\n\n // 'a' - 'f'\n if (c >= 49 && c <= 54) {\n r |= c - 49 + 0xa;\n\n // 'A' - 'F'\n } else if (c >= 17 && c <= 22) {\n r |= c - 17 + 0xa;\n\n // '0' - '9'\n } else {\n r |= c & 0xf;\n }\n }\n return r;\n }\n\n BN.prototype._parseHex = function _parseHex (number, start) {\n // Create possibly bigger array to ensure that it fits the number\n this.length = Math.ceil((number.length - start) / 6);\n this.words = new Array(this.length);\n for (var i = 0; i < this.length; i++) {\n this.words[i] = 0;\n }\n\n var j, w;\n // Scan 24-bit chunks and add them to the number\n var off = 0;\n for (i = number.length - 6, j = 0; i >= start; i -= 6) {\n w = parseHex(number, i, i + 6);\n this.words[j] |= (w << off) & 0x3ffffff;\n // NOTE: `0x3fffff` is intentional here, 26bits max shift + 24bit hex limb\n this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;\n off += 24;\n if (off >= 26) {\n off -= 26;\n j++;\n }\n }\n if (i + 6 !== start) {\n w = parseHex(number, start, i + 6);\n this.words[j] |= (w << off) & 0x3ffffff;\n this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;\n }\n this.strip();\n };\n\n function parseBase (str, start, end, mul) {\n var r = 0;\n var len = Math.min(str.length, end);\n for (var i = start; i < len; i++) {\n var c = str.charCodeAt(i) - 48;\n\n r *= mul;\n\n // 'a'\n if (c >= 49) {\n r += c - 49 + 0xa;\n\n // 'A'\n } else if (c >= 17) {\n r += c - 17 + 0xa;\n\n // '0' - '9'\n } else {\n r += c;\n }\n }\n return r;\n }\n\n BN.prototype._parseBase = function _parseBase (number, base, start) {\n // Initialize as zero\n this.words = [ 0 ];\n this.length = 1;\n\n // Find length of limb in base\n for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) {\n limbLen++;\n }\n limbLen--;\n limbPow = (limbPow / base) | 0;\n\n var total = number.length - start;\n var mod = total % limbLen;\n var end = Math.min(total, total - mod) + start;\n\n var word = 0;\n for (var i = start; i < end; i += limbLen) {\n word = parseBase(number, i, i + limbLen, base);\n\n this.imuln(limbPow);\n if (this.words[0] + word < 0x4000000) {\n this.words[0] += word;\n } else {\n this._iaddn(word);\n }\n }\n\n if (mod !== 0) {\n var pow = 1;\n word = parseBase(number, i, number.length, base);\n\n for (i = 0; i < mod; i++) {\n pow *= base;\n }\n\n this.imuln(pow);\n if (this.words[0] + word < 0x4000000) {\n this.words[0] += word;\n } else {\n this._iaddn(word);\n }\n }\n };\n\n BN.prototype.copy = function copy (dest) {\n dest.words = new Array(this.length);\n for (var i = 0; i < this.length; i++) {\n dest.words[i] = this.words[i];\n }\n dest.length = this.length;\n dest.negative = this.negative;\n dest.red = this.red;\n };\n\n BN.prototype.clone = function clone () {\n var r = new BN(null);\n this.copy(r);\n return r;\n };\n\n BN.prototype._expand = function _expand (size) {\n while (this.length < size) {\n this.words[this.length++] = 0;\n }\n return this;\n };\n\n // Remove leading `0` from `this`\n BN.prototype.strip = function strip () {\n while (this.length > 1 && this.words[this.length - 1] === 0) {\n this.length--;\n }\n return this._normSign();\n };\n\n BN.prototype._normSign = function _normSign () {\n // -0 = 0\n if (this.length === 1 && this.words[0] === 0) {\n this.negative = 0;\n }\n return this;\n };\n\n BN.prototype.inspect = function inspect () {\n return (this.red ? '';\n };\n\n /*\n\n var zeros = [];\n var groupSizes = [];\n var groupBases = [];\n\n var s = '';\n var i = -1;\n while (++i < BN.wordSize) {\n zeros[i] = s;\n s += '0';\n }\n groupSizes[0] = 0;\n groupSizes[1] = 0;\n groupBases[0] = 0;\n groupBases[1] = 0;\n var base = 2 - 1;\n while (++base < 36 + 1) {\n var groupSize = 0;\n var groupBase = 1;\n while (groupBase < (1 << BN.wordSize) / base) {\n groupBase *= base;\n groupSize += 1;\n }\n groupSizes[base] = groupSize;\n groupBases[base] = groupBase;\n }\n\n */\n\n var zeros = [\n '',\n '0',\n '00',\n '000',\n '0000',\n '00000',\n '000000',\n '0000000',\n '00000000',\n '000000000',\n '0000000000',\n '00000000000',\n '000000000000',\n '0000000000000',\n '00000000000000',\n '000000000000000',\n '0000000000000000',\n '00000000000000000',\n '000000000000000000',\n '0000000000000000000',\n '00000000000000000000',\n '000000000000000000000',\n '0000000000000000000000',\n '00000000000000000000000',\n '000000000000000000000000',\n '0000000000000000000000000'\n ];\n\n var groupSizes = [\n 0, 0,\n 25, 16, 12, 11, 10, 9, 8,\n 8, 7, 7, 7, 7, 6, 6,\n 6, 6, 6, 6, 6, 5, 5,\n 5, 5, 5, 5, 5, 5, 5,\n 5, 5, 5, 5, 5, 5, 5\n ];\n\n var groupBases = [\n 0, 0,\n 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216,\n 43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625,\n 16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632,\n 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149,\n 24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176\n ];\n\n BN.prototype.toString = function toString (base, padding) {\n base = base || 10;\n padding = padding | 0 || 1;\n\n var out;\n if (base === 16 || base === 'hex') {\n out = '';\n var off = 0;\n var carry = 0;\n for (var i = 0; i < this.length; i++) {\n var w = this.words[i];\n var word = (((w << off) | carry) & 0xffffff).toString(16);\n carry = (w >>> (24 - off)) & 0xffffff;\n if (carry !== 0 || i !== this.length - 1) {\n out = zeros[6 - word.length] + word + out;\n } else {\n out = word + out;\n }\n off += 2;\n if (off >= 26) {\n off -= 26;\n i--;\n }\n }\n if (carry !== 0) {\n out = carry.toString(16) + out;\n }\n while (out.length % padding !== 0) {\n out = '0' + out;\n }\n if (this.negative !== 0) {\n out = '-' + out;\n }\n return out;\n }\n\n if (base === (base | 0) && base >= 2 && base <= 36) {\n // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base));\n var groupSize = groupSizes[base];\n // var groupBase = Math.pow(base, groupSize);\n var groupBase = groupBases[base];\n out = '';\n var c = this.clone();\n c.negative = 0;\n while (!c.isZero()) {\n var r = c.modn(groupBase).toString(base);\n c = c.idivn(groupBase);\n\n if (!c.isZero()) {\n out = zeros[groupSize - r.length] + r + out;\n } else {\n out = r + out;\n }\n }\n if (this.isZero()) {\n out = '0' + out;\n }\n while (out.length % padding !== 0) {\n out = '0' + out;\n }\n if (this.negative !== 0) {\n out = '-' + out;\n }\n return out;\n }\n\n assert(false, 'Base should be between 2 and 36');\n };\n\n BN.prototype.toNumber = function toNumber () {\n var ret = this.words[0];\n if (this.length === 2) {\n ret += this.words[1] * 0x4000000;\n } else if (this.length === 3 && this.words[2] === 0x01) {\n // NOTE: at this stage it is known that the top bit is set\n ret += 0x10000000000000 + (this.words[1] * 0x4000000);\n } else if (this.length > 2) {\n assert(false, 'Number can only safely store up to 53 bits');\n }\n return (this.negative !== 0) ? -ret : ret;\n };\n\n BN.prototype.toJSON = function toJSON () {\n return this.toString(16);\n };\n\n BN.prototype.toBuffer = function toBuffer (endian, length) {\n assert(typeof Buffer !== 'undefined');\n return this.toArrayLike(Buffer, endian, length);\n };\n\n BN.prototype.toArray = function toArray (endian, length) {\n return this.toArrayLike(Array, endian, length);\n };\n\n BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) {\n var byteLength = this.byteLength();\n var reqLength = length || Math.max(1, byteLength);\n assert(byteLength <= reqLength, 'byte array longer than desired length');\n assert(reqLength > 0, 'Requested array length <= 0');\n\n this.strip();\n var littleEndian = endian === 'le';\n var res = new ArrayType(reqLength);\n\n var b, i;\n var q = this.clone();\n if (!littleEndian) {\n // Assume big-endian\n for (i = 0; i < reqLength - byteLength; i++) {\n res[i] = 0;\n }\n\n for (i = 0; !q.isZero(); i++) {\n b = q.andln(0xff);\n q.iushrn(8);\n\n res[reqLength - i - 1] = b;\n }\n } else {\n for (i = 0; !q.isZero(); i++) {\n b = q.andln(0xff);\n q.iushrn(8);\n\n res[i] = b;\n }\n\n for (; i < reqLength; i++) {\n res[i] = 0;\n }\n }\n\n return res;\n };\n\n if (Math.clz32) {\n BN.prototype._countBits = function _countBits (w) {\n return 32 - Math.clz32(w);\n };\n } else {\n BN.prototype._countBits = function _countBits (w) {\n var t = w;\n var r = 0;\n if (t >= 0x1000) {\n r += 13;\n t >>>= 13;\n }\n if (t >= 0x40) {\n r += 7;\n t >>>= 7;\n }\n if (t >= 0x8) {\n r += 4;\n t >>>= 4;\n }\n if (t >= 0x02) {\n r += 2;\n t >>>= 2;\n }\n return r + t;\n };\n }\n\n BN.prototype._zeroBits = function _zeroBits (w) {\n // Short-cut\n if (w === 0) return 26;\n\n var t = w;\n var r = 0;\n if ((t & 0x1fff) === 0) {\n r += 13;\n t >>>= 13;\n }\n if ((t & 0x7f) === 0) {\n r += 7;\n t >>>= 7;\n }\n if ((t & 0xf) === 0) {\n r += 4;\n t >>>= 4;\n }\n if ((t & 0x3) === 0) {\n r += 2;\n t >>>= 2;\n }\n if ((t & 0x1) === 0) {\n r++;\n }\n return r;\n };\n\n // Return number of used bits in a BN\n BN.prototype.bitLength = function bitLength () {\n var w = this.words[this.length - 1];\n var hi = this._countBits(w);\n return (this.length - 1) * 26 + hi;\n };\n\n function toBitArray (num) {\n var w = new Array(num.bitLength());\n\n for (var bit = 0; bit < w.length; bit++) {\n var off = (bit / 26) | 0;\n var wbit = bit % 26;\n\n w[bit] = (num.words[off] & (1 << wbit)) >>> wbit;\n }\n\n return w;\n }\n\n // Number of trailing zero bits\n BN.prototype.zeroBits = function zeroBits () {\n if (this.isZero()) return 0;\n\n var r = 0;\n for (var i = 0; i < this.length; i++) {\n var b = this._zeroBits(this.words[i]);\n r += b;\n if (b !== 26) break;\n }\n return r;\n };\n\n BN.prototype.byteLength = function byteLength () {\n return Math.ceil(this.bitLength() / 8);\n };\n\n BN.prototype.toTwos = function toTwos (width) {\n if (this.negative !== 0) {\n return this.abs().inotn(width).iaddn(1);\n }\n return this.clone();\n };\n\n BN.prototype.fromTwos = function fromTwos (width) {\n if (this.testn(width - 1)) {\n return this.notn(width).iaddn(1).ineg();\n }\n return this.clone();\n };\n\n BN.prototype.isNeg = function isNeg () {\n return this.negative !== 0;\n };\n\n // Return negative clone of `this`\n BN.prototype.neg = function neg () {\n return this.clone().ineg();\n };\n\n BN.prototype.ineg = function ineg () {\n if (!this.isZero()) {\n this.negative ^= 1;\n }\n\n return this;\n };\n\n // Or `num` with `this` in-place\n BN.prototype.iuor = function iuor (num) {\n while (this.length < num.length) {\n this.words[this.length++] = 0;\n }\n\n for (var i = 0; i < num.length; i++) {\n this.words[i] = this.words[i] | num.words[i];\n }\n\n return this.strip();\n };\n\n BN.prototype.ior = function ior (num) {\n assert((this.negative | num.negative) === 0);\n return this.iuor(num);\n };\n\n // Or `num` with `this`\n BN.prototype.or = function or (num) {\n if (this.length > num.length) return this.clone().ior(num);\n return num.clone().ior(this);\n };\n\n BN.prototype.uor = function uor (num) {\n if (this.length > num.length) return this.clone().iuor(num);\n return num.clone().iuor(this);\n };\n\n // And `num` with `this` in-place\n BN.prototype.iuand = function iuand (num) {\n // b = min-length(num, this)\n var b;\n if (this.length > num.length) {\n b = num;\n } else {\n b = this;\n }\n\n for (var i = 0; i < b.length; i++) {\n this.words[i] = this.words[i] & num.words[i];\n }\n\n this.length = b.length;\n\n return this.strip();\n };\n\n BN.prototype.iand = function iand (num) {\n assert((this.negative | num.negative) === 0);\n return this.iuand(num);\n };\n\n // And `num` with `this`\n BN.prototype.and = function and (num) {\n if (this.length > num.length) return this.clone().iand(num);\n return num.clone().iand(this);\n };\n\n BN.prototype.uand = function uand (num) {\n if (this.length > num.length) return this.clone().iuand(num);\n return num.clone().iuand(this);\n };\n\n // Xor `num` with `this` in-place\n BN.prototype.iuxor = function iuxor (num) {\n // a.length > b.length\n var a;\n var b;\n if (this.length > num.length) {\n a = this;\n b = num;\n } else {\n a = num;\n b = this;\n }\n\n for (var i = 0; i < b.length; i++) {\n this.words[i] = a.words[i] ^ b.words[i];\n }\n\n if (this !== a) {\n for (; i < a.length; i++) {\n this.words[i] = a.words[i];\n }\n }\n\n this.length = a.length;\n\n return this.strip();\n };\n\n BN.prototype.ixor = function ixor (num) {\n assert((this.negative | num.negative) === 0);\n return this.iuxor(num);\n };\n\n // Xor `num` with `this`\n BN.prototype.xor = function xor (num) {\n if (this.length > num.length) return this.clone().ixor(num);\n return num.clone().ixor(this);\n };\n\n BN.prototype.uxor = function uxor (num) {\n if (this.length > num.length) return this.clone().iuxor(num);\n return num.clone().iuxor(this);\n };\n\n // Not ``this`` with ``width`` bitwidth\n BN.prototype.inotn = function inotn (width) {\n assert(typeof width === 'number' && width >= 0);\n\n var bytesNeeded = Math.ceil(width / 26) | 0;\n var bitsLeft = width % 26;\n\n // Extend the buffer with leading zeroes\n this._expand(bytesNeeded);\n\n if (bitsLeft > 0) {\n bytesNeeded--;\n }\n\n // Handle complete words\n for (var i = 0; i < bytesNeeded; i++) {\n this.words[i] = ~this.words[i] & 0x3ffffff;\n }\n\n // Handle the residue\n if (bitsLeft > 0) {\n this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft));\n }\n\n // And remove leading zeroes\n return this.strip();\n };\n\n BN.prototype.notn = function notn (width) {\n return this.clone().inotn(width);\n };\n\n // Set `bit` of `this`\n BN.prototype.setn = function setn (bit, val) {\n assert(typeof bit === 'number' && bit >= 0);\n\n var off = (bit / 26) | 0;\n var wbit = bit % 26;\n\n this._expand(off + 1);\n\n if (val) {\n this.words[off] = this.words[off] | (1 << wbit);\n } else {\n this.words[off] = this.words[off] & ~(1 << wbit);\n }\n\n return this.strip();\n };\n\n // Add `num` to `this` in-place\n BN.prototype.iadd = function iadd (num) {\n var r;\n\n // negative + positive\n if (this.negative !== 0 && num.negative === 0) {\n this.negative = 0;\n r = this.isub(num);\n this.negative ^= 1;\n return this._normSign();\n\n // positive + negative\n } else if (this.negative === 0 && num.negative !== 0) {\n num.negative = 0;\n r = this.isub(num);\n num.negative = 1;\n return r._normSign();\n }\n\n // a.length > b.length\n var a, b;\n if (this.length > num.length) {\n a = this;\n b = num;\n } else {\n a = num;\n b = this;\n }\n\n var carry = 0;\n for (var i = 0; i < b.length; i++) {\n r = (a.words[i] | 0) + (b.words[i] | 0) + carry;\n this.words[i] = r & 0x3ffffff;\n carry = r >>> 26;\n }\n for (; carry !== 0 && i < a.length; i++) {\n r = (a.words[i] | 0) + carry;\n this.words[i] = r & 0x3ffffff;\n carry = r >>> 26;\n }\n\n this.length = a.length;\n if (carry !== 0) {\n this.words[this.length] = carry;\n this.length++;\n // Copy the rest of the words\n } else if (a !== this) {\n for (; i < a.length; i++) {\n this.words[i] = a.words[i];\n }\n }\n\n return this;\n };\n\n // Add `num` to `this`\n BN.prototype.add = function add (num) {\n var res;\n if (num.negative !== 0 && this.negative === 0) {\n num.negative = 0;\n res = this.sub(num);\n num.negative ^= 1;\n return res;\n } else if (num.negative === 0 && this.negative !== 0) {\n this.negative = 0;\n res = num.sub(this);\n this.negative = 1;\n return res;\n }\n\n if (this.length > num.length) return this.clone().iadd(num);\n\n return num.clone().iadd(this);\n };\n\n // Subtract `num` from `this` in-place\n BN.prototype.isub = function isub (num) {\n // this - (-num) = this + num\n if (num.negative !== 0) {\n num.negative = 0;\n var r = this.iadd(num);\n num.negative = 1;\n return r._normSign();\n\n // -this - num = -(this + num)\n } else if (this.negative !== 0) {\n this.negative = 0;\n this.iadd(num);\n this.negative = 1;\n return this._normSign();\n }\n\n // At this point both numbers are positive\n var cmp = this.cmp(num);\n\n // Optimization - zeroify\n if (cmp === 0) {\n this.negative = 0;\n this.length = 1;\n this.words[0] = 0;\n return this;\n }\n\n // a > b\n var a, b;\n if (cmp > 0) {\n a = this;\n b = num;\n } else {\n a = num;\n b = this;\n }\n\n var carry = 0;\n for (var i = 0; i < b.length; i++) {\n r = (a.words[i] | 0) - (b.words[i] | 0) + carry;\n carry = r >> 26;\n this.words[i] = r & 0x3ffffff;\n }\n for (; carry !== 0 && i < a.length; i++) {\n r = (a.words[i] | 0) + carry;\n carry = r >> 26;\n this.words[i] = r & 0x3ffffff;\n }\n\n // Copy rest of the words\n if (carry === 0 && i < a.length && a !== this) {\n for (; i < a.length; i++) {\n this.words[i] = a.words[i];\n }\n }\n\n this.length = Math.max(this.length, i);\n\n if (a !== this) {\n this.negative = 1;\n }\n\n return this.strip();\n };\n\n // Subtract `num` from `this`\n BN.prototype.sub = function sub (num) {\n return this.clone().isub(num);\n };\n\n function smallMulTo (self, num, out) {\n out.negative = num.negative ^ self.negative;\n var len = (self.length + num.length) | 0;\n out.length = len;\n len = (len - 1) | 0;\n\n // Peel one iteration (compiler can't do it, because of code complexity)\n var a = self.words[0] | 0;\n var b = num.words[0] | 0;\n var r = a * b;\n\n var lo = r & 0x3ffffff;\n var carry = (r / 0x4000000) | 0;\n out.words[0] = lo;\n\n for (var k = 1; k < len; k++) {\n // Sum all words with the same `i + j = k` and accumulate `ncarry`,\n // note that ncarry could be >= 0x3ffffff\n var ncarry = carry >>> 26;\n var rword = carry & 0x3ffffff;\n var maxJ = Math.min(k, num.length - 1);\n for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {\n var i = (k - j) | 0;\n a = self.words[i] | 0;\n b = num.words[j] | 0;\n r = a * b + rword;\n ncarry += (r / 0x4000000) | 0;\n rword = r & 0x3ffffff;\n }\n out.words[k] = rword | 0;\n carry = ncarry | 0;\n }\n if (carry !== 0) {\n out.words[k] = carry | 0;\n } else {\n out.length--;\n }\n\n return out.strip();\n }\n\n // TODO(indutny): it may be reasonable to omit it for users who don't need\n // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit\n // multiplication (like elliptic secp256k1).\n var comb10MulTo = function comb10MulTo (self, num, out) {\n var a = self.words;\n var b = num.words;\n var o = out.words;\n var c = 0;\n var lo;\n var mid;\n var hi;\n var a0 = a[0] | 0;\n var al0 = a0 & 0x1fff;\n var ah0 = a0 >>> 13;\n var a1 = a[1] | 0;\n var al1 = a1 & 0x1fff;\n var ah1 = a1 >>> 13;\n var a2 = a[2] | 0;\n var al2 = a2 & 0x1fff;\n var ah2 = a2 >>> 13;\n var a3 = a[3] | 0;\n var al3 = a3 & 0x1fff;\n var ah3 = a3 >>> 13;\n var a4 = a[4] | 0;\n var al4 = a4 & 0x1fff;\n var ah4 = a4 >>> 13;\n var a5 = a[5] | 0;\n var al5 = a5 & 0x1fff;\n var ah5 = a5 >>> 13;\n var a6 = a[6] | 0;\n var al6 = a6 & 0x1fff;\n var ah6 = a6 >>> 13;\n var a7 = a[7] | 0;\n var al7 = a7 & 0x1fff;\n var ah7 = a7 >>> 13;\n var a8 = a[8] | 0;\n var al8 = a8 & 0x1fff;\n var ah8 = a8 >>> 13;\n var a9 = a[9] | 0;\n var al9 = a9 & 0x1fff;\n var ah9 = a9 >>> 13;\n var b0 = b[0] | 0;\n var bl0 = b0 & 0x1fff;\n var bh0 = b0 >>> 13;\n var b1 = b[1] | 0;\n var bl1 = b1 & 0x1fff;\n var bh1 = b1 >>> 13;\n var b2 = b[2] | 0;\n var bl2 = b2 & 0x1fff;\n var bh2 = b2 >>> 13;\n var b3 = b[3] | 0;\n var bl3 = b3 & 0x1fff;\n var bh3 = b3 >>> 13;\n var b4 = b[4] | 0;\n var bl4 = b4 & 0x1fff;\n var bh4 = b4 >>> 13;\n var b5 = b[5] | 0;\n var bl5 = b5 & 0x1fff;\n var bh5 = b5 >>> 13;\n var b6 = b[6] | 0;\n var bl6 = b6 & 0x1fff;\n var bh6 = b6 >>> 13;\n var b7 = b[7] | 0;\n var bl7 = b7 & 0x1fff;\n var bh7 = b7 >>> 13;\n var b8 = b[8] | 0;\n var bl8 = b8 & 0x1fff;\n var bh8 = b8 >>> 13;\n var b9 = b[9] | 0;\n var bl9 = b9 & 0x1fff;\n var bh9 = b9 >>> 13;\n\n out.negative = self.negative ^ num.negative;\n out.length = 19;\n /* k = 0 */\n lo = Math.imul(al0, bl0);\n mid = Math.imul(al0, bh0);\n mid = (mid + Math.imul(ah0, bl0)) | 0;\n hi = Math.imul(ah0, bh0);\n var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0;\n w0 &= 0x3ffffff;\n /* k = 1 */\n lo = Math.imul(al1, bl0);\n mid = Math.imul(al1, bh0);\n mid = (mid + Math.imul(ah1, bl0)) | 0;\n hi = Math.imul(ah1, bh0);\n lo = (lo + Math.imul(al0, bl1)) | 0;\n mid = (mid + Math.imul(al0, bh1)) | 0;\n mid = (mid + Math.imul(ah0, bl1)) | 0;\n hi = (hi + Math.imul(ah0, bh1)) | 0;\n var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0;\n w1 &= 0x3ffffff;\n /* k = 2 */\n lo = Math.imul(al2, bl0);\n mid = Math.imul(al2, bh0);\n mid = (mid + Math.imul(ah2, bl0)) | 0;\n hi = Math.imul(ah2, bh0);\n lo = (lo + Math.imul(al1, bl1)) | 0;\n mid = (mid + Math.imul(al1, bh1)) | 0;\n mid = (mid + Math.imul(ah1, bl1)) | 0;\n hi = (hi + Math.imul(ah1, bh1)) | 0;\n lo = (lo + Math.imul(al0, bl2)) | 0;\n mid = (mid + Math.imul(al0, bh2)) | 0;\n mid = (mid + Math.imul(ah0, bl2)) | 0;\n hi = (hi + Math.imul(ah0, bh2)) | 0;\n var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0;\n w2 &= 0x3ffffff;\n /* k = 3 */\n lo = Math.imul(al3, bl0);\n mid = Math.imul(al3, bh0);\n mid = (mid + Math.imul(ah3, bl0)) | 0;\n hi = Math.imul(ah3, bh0);\n lo = (lo + Math.imul(al2, bl1)) | 0;\n mid = (mid + Math.imul(al2, bh1)) | 0;\n mid = (mid + Math.imul(ah2, bl1)) | 0;\n hi = (hi + Math.imul(ah2, bh1)) | 0;\n lo = (lo + Math.imul(al1, bl2)) | 0;\n mid = (mid + Math.imul(al1, bh2)) | 0;\n mid = (mid + Math.imul(ah1, bl2)) | 0;\n hi = (hi + Math.imul(ah1, bh2)) | 0;\n lo = (lo + Math.imul(al0, bl3)) | 0;\n mid = (mid + Math.imul(al0, bh3)) | 0;\n mid = (mid + Math.imul(ah0, bl3)) | 0;\n hi = (hi + Math.imul(ah0, bh3)) | 0;\n var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0;\n w3 &= 0x3ffffff;\n /* k = 4 */\n lo = Math.imul(al4, bl0);\n mid = Math.imul(al4, bh0);\n mid = (mid + Math.imul(ah4, bl0)) | 0;\n hi = Math.imul(ah4, bh0);\n lo = (lo + Math.imul(al3, bl1)) | 0;\n mid = (mid + Math.imul(al3, bh1)) | 0;\n mid = (mid + Math.imul(ah3, bl1)) | 0;\n hi = (hi + Math.imul(ah3, bh1)) | 0;\n lo = (lo + Math.imul(al2, bl2)) | 0;\n mid = (mid + Math.imul(al2, bh2)) | 0;\n mid = (mid + Math.imul(ah2, bl2)) | 0;\n hi = (hi + Math.imul(ah2, bh2)) | 0;\n lo = (lo + Math.imul(al1, bl3)) | 0;\n mid = (mid + Math.imul(al1, bh3)) | 0;\n mid = (mid + Math.imul(ah1, bl3)) | 0;\n hi = (hi + Math.imul(ah1, bh3)) | 0;\n lo = (lo + Math.imul(al0, bl4)) | 0;\n mid = (mid + Math.imul(al0, bh4)) | 0;\n mid = (mid + Math.imul(ah0, bl4)) | 0;\n hi = (hi + Math.imul(ah0, bh4)) | 0;\n var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0;\n w4 &= 0x3ffffff;\n /* k = 5 */\n lo = Math.imul(al5, bl0);\n mid = Math.imul(al5, bh0);\n mid = (mid + Math.imul(ah5, bl0)) | 0;\n hi = Math.imul(ah5, bh0);\n lo = (lo + Math.imul(al4, bl1)) | 0;\n mid = (mid + Math.imul(al4, bh1)) | 0;\n mid = (mid + Math.imul(ah4, bl1)) | 0;\n hi = (hi + Math.imul(ah4, bh1)) | 0;\n lo = (lo + Math.imul(al3, bl2)) | 0;\n mid = (mid + Math.imul(al3, bh2)) | 0;\n mid = (mid + Math.imul(ah3, bl2)) | 0;\n hi = (hi + Math.imul(ah3, bh2)) | 0;\n lo = (lo + Math.imul(al2, bl3)) | 0;\n mid = (mid + Math.imul(al2, bh3)) | 0;\n mid = (mid + Math.imul(ah2, bl3)) | 0;\n hi = (hi + Math.imul(ah2, bh3)) | 0;\n lo = (lo + Math.imul(al1, bl4)) | 0;\n mid = (mid + Math.imul(al1, bh4)) | 0;\n mid = (mid + Math.imul(ah1, bl4)) | 0;\n hi = (hi + Math.imul(ah1, bh4)) | 0;\n lo = (lo + Math.imul(al0, bl5)) | 0;\n mid = (mid + Math.imul(al0, bh5)) | 0;\n mid = (mid + Math.imul(ah0, bl5)) | 0;\n hi = (hi + Math.imul(ah0, bh5)) | 0;\n var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0;\n w5 &= 0x3ffffff;\n /* k = 6 */\n lo = Math.imul(al6, bl0);\n mid = Math.imul(al6, bh0);\n mid = (mid + Math.imul(ah6, bl0)) | 0;\n hi = Math.imul(ah6, bh0);\n lo = (lo + Math.imul(al5, bl1)) | 0;\n mid = (mid + Math.imul(al5, bh1)) | 0;\n mid = (mid + Math.imul(ah5, bl1)) | 0;\n hi = (hi + Math.imul(ah5, bh1)) | 0;\n lo = (lo + Math.imul(al4, bl2)) | 0;\n mid = (mid + Math.imul(al4, bh2)) | 0;\n mid = (mid + Math.imul(ah4, bl2)) | 0;\n hi = (hi + Math.imul(ah4, bh2)) | 0;\n lo = (lo + Math.imul(al3, bl3)) | 0;\n mid = (mid + Math.imul(al3, bh3)) | 0;\n mid = (mid + Math.imul(ah3, bl3)) | 0;\n hi = (hi + Math.imul(ah3, bh3)) | 0;\n lo = (lo + Math.imul(al2, bl4)) | 0;\n mid = (mid + Math.imul(al2, bh4)) | 0;\n mid = (mid + Math.imul(ah2, bl4)) | 0;\n hi = (hi + Math.imul(ah2, bh4)) | 0;\n lo = (lo + Math.imul(al1, bl5)) | 0;\n mid = (mid + Math.imul(al1, bh5)) | 0;\n mid = (mid + Math.imul(ah1, bl5)) | 0;\n hi = (hi + Math.imul(ah1, bh5)) | 0;\n lo = (lo + Math.imul(al0, bl6)) | 0;\n mid = (mid + Math.imul(al0, bh6)) | 0;\n mid = (mid + Math.imul(ah0, bl6)) | 0;\n hi = (hi + Math.imul(ah0, bh6)) | 0;\n var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0;\n w6 &= 0x3ffffff;\n /* k = 7 */\n lo = Math.imul(al7, bl0);\n mid = Math.imul(al7, bh0);\n mid = (mid + Math.imul(ah7, bl0)) | 0;\n hi = Math.imul(ah7, bh0);\n lo = (lo + Math.imul(al6, bl1)) | 0;\n mid = (mid + Math.imul(al6, bh1)) | 0;\n mid = (mid + Math.imul(ah6, bl1)) | 0;\n hi = (hi + Math.imul(ah6, bh1)) | 0;\n lo = (lo + Math.imul(al5, bl2)) | 0;\n mid = (mid + Math.imul(al5, bh2)) | 0;\n mid = (mid + Math.imul(ah5, bl2)) | 0;\n hi = (hi + Math.imul(ah5, bh2)) | 0;\n lo = (lo + Math.imul(al4, bl3)) | 0;\n mid = (mid + Math.imul(al4, bh3)) | 0;\n mid = (mid + Math.imul(ah4, bl3)) | 0;\n hi = (hi + Math.imul(ah4, bh3)) | 0;\n lo = (lo + Math.imul(al3, bl4)) | 0;\n mid = (mid + Math.imul(al3, bh4)) | 0;\n mid = (mid + Math.imul(ah3, bl4)) | 0;\n hi = (hi + Math.imul(ah3, bh4)) | 0;\n lo = (lo + Math.imul(al2, bl5)) | 0;\n mid = (mid + Math.imul(al2, bh5)) | 0;\n mid = (mid + Math.imul(ah2, bl5)) | 0;\n hi = (hi + Math.imul(ah2, bh5)) | 0;\n lo = (lo + Math.imul(al1, bl6)) | 0;\n mid = (mid + Math.imul(al1, bh6)) | 0;\n mid = (mid + Math.imul(ah1, bl6)) | 0;\n hi = (hi + Math.imul(ah1, bh6)) | 0;\n lo = (lo + Math.imul(al0, bl7)) | 0;\n mid = (mid + Math.imul(al0, bh7)) | 0;\n mid = (mid + Math.imul(ah0, bl7)) | 0;\n hi = (hi + Math.imul(ah0, bh7)) | 0;\n var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0;\n w7 &= 0x3ffffff;\n /* k = 8 */\n lo = Math.imul(al8, bl0);\n mid = Math.imul(al8, bh0);\n mid = (mid + Math.imul(ah8, bl0)) | 0;\n hi = Math.imul(ah8, bh0);\n lo = (lo + Math.imul(al7, bl1)) | 0;\n mid = (mid + Math.imul(al7, bh1)) | 0;\n mid = (mid + Math.imul(ah7, bl1)) | 0;\n hi = (hi + Math.imul(ah7, bh1)) | 0;\n lo = (lo + Math.imul(al6, bl2)) | 0;\n mid = (mid + Math.imul(al6, bh2)) | 0;\n mid = (mid + Math.imul(ah6, bl2)) | 0;\n hi = (hi + Math.imul(ah6, bh2)) | 0;\n lo = (lo + Math.imul(al5, bl3)) | 0;\n mid = (mid + Math.imul(al5, bh3)) | 0;\n mid = (mid + Math.imul(ah5, bl3)) | 0;\n hi = (hi + Math.imul(ah5, bh3)) | 0;\n lo = (lo + Math.imul(al4, bl4)) | 0;\n mid = (mid + Math.imul(al4, bh4)) | 0;\n mid = (mid + Math.imul(ah4, bl4)) | 0;\n hi = (hi + Math.imul(ah4, bh4)) | 0;\n lo = (lo + Math.imul(al3, bl5)) | 0;\n mid = (mid + Math.imul(al3, bh5)) | 0;\n mid = (mid + Math.imul(ah3, bl5)) | 0;\n hi = (hi + Math.imul(ah3, bh5)) | 0;\n lo = (lo + Math.imul(al2, bl6)) | 0;\n mid = (mid + Math.imul(al2, bh6)) | 0;\n mid = (mid + Math.imul(ah2, bl6)) | 0;\n hi = (hi + Math.imul(ah2, bh6)) | 0;\n lo = (lo + Math.imul(al1, bl7)) | 0;\n mid = (mid + Math.imul(al1, bh7)) | 0;\n mid = (mid + Math.imul(ah1, bl7)) | 0;\n hi = (hi + Math.imul(ah1, bh7)) | 0;\n lo = (lo + Math.imul(al0, bl8)) | 0;\n mid = (mid + Math.imul(al0, bh8)) | 0;\n mid = (mid + Math.imul(ah0, bl8)) | 0;\n hi = (hi + Math.imul(ah0, bh8)) | 0;\n var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0;\n w8 &= 0x3ffffff;\n /* k = 9 */\n lo = Math.imul(al9, bl0);\n mid = Math.imul(al9, bh0);\n mid = (mid + Math.imul(ah9, bl0)) | 0;\n hi = Math.imul(ah9, bh0);\n lo = (lo + Math.imul(al8, bl1)) | 0;\n mid = (mid + Math.imul(al8, bh1)) | 0;\n mid = (mid + Math.imul(ah8, bl1)) | 0;\n hi = (hi + Math.imul(ah8, bh1)) | 0;\n lo = (lo + Math.imul(al7, bl2)) | 0;\n mid = (mid + Math.imul(al7, bh2)) | 0;\n mid = (mid + Math.imul(ah7, bl2)) | 0;\n hi = (hi + Math.imul(ah7, bh2)) | 0;\n lo = (lo + Math.imul(al6, bl3)) | 0;\n mid = (mid + Math.imul(al6, bh3)) | 0;\n mid = (mid + Math.imul(ah6, bl3)) | 0;\n hi = (hi + Math.imul(ah6, bh3)) | 0;\n lo = (lo + Math.imul(al5, bl4)) | 0;\n mid = (mid + Math.imul(al5, bh4)) | 0;\n mid = (mid + Math.imul(ah5, bl4)) | 0;\n hi = (hi + Math.imul(ah5, bh4)) | 0;\n lo = (lo + Math.imul(al4, bl5)) | 0;\n mid = (mid + Math.imul(al4, bh5)) | 0;\n mid = (mid + Math.imul(ah4, bl5)) | 0;\n hi = (hi + Math.imul(ah4, bh5)) | 0;\n lo = (lo + Math.imul(al3, bl6)) | 0;\n mid = (mid + Math.imul(al3, bh6)) | 0;\n mid = (mid + Math.imul(ah3, bl6)) | 0;\n hi = (hi + Math.imul(ah3, bh6)) | 0;\n lo = (lo + Math.imul(al2, bl7)) | 0;\n mid = (mid + Math.imul(al2, bh7)) | 0;\n mid = (mid + Math.imul(ah2, bl7)) | 0;\n hi = (hi + Math.imul(ah2, bh7)) | 0;\n lo = (lo + Math.imul(al1, bl8)) | 0;\n mid = (mid + Math.imul(al1, bh8)) | 0;\n mid = (mid + Math.imul(ah1, bl8)) | 0;\n hi = (hi + Math.imul(ah1, bh8)) | 0;\n lo = (lo + Math.imul(al0, bl9)) | 0;\n mid = (mid + Math.imul(al0, bh9)) | 0;\n mid = (mid + Math.imul(ah0, bl9)) | 0;\n hi = (hi + Math.imul(ah0, bh9)) | 0;\n var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0;\n w9 &= 0x3ffffff;\n /* k = 10 */\n lo = Math.imul(al9, bl1);\n mid = Math.imul(al9, bh1);\n mid = (mid + Math.imul(ah9, bl1)) | 0;\n hi = Math.imul(ah9, bh1);\n lo = (lo + Math.imul(al8, bl2)) | 0;\n mid = (mid + Math.imul(al8, bh2)) | 0;\n mid = (mid + Math.imul(ah8, bl2)) | 0;\n hi = (hi + Math.imul(ah8, bh2)) | 0;\n lo = (lo + Math.imul(al7, bl3)) | 0;\n mid = (mid + Math.imul(al7, bh3)) | 0;\n mid = (mid + Math.imul(ah7, bl3)) | 0;\n hi = (hi + Math.imul(ah7, bh3)) | 0;\n lo = (lo + Math.imul(al6, bl4)) | 0;\n mid = (mid + Math.imul(al6, bh4)) | 0;\n mid = (mid + Math.imul(ah6, bl4)) | 0;\n hi = (hi + Math.imul(ah6, bh4)) | 0;\n lo = (lo + Math.imul(al5, bl5)) | 0;\n mid = (mid + Math.imul(al5, bh5)) | 0;\n mid = (mid + Math.imul(ah5, bl5)) | 0;\n hi = (hi + Math.imul(ah5, bh5)) | 0;\n lo = (lo + Math.imul(al4, bl6)) | 0;\n mid = (mid + Math.imul(al4, bh6)) | 0;\n mid = (mid + Math.imul(ah4, bl6)) | 0;\n hi = (hi + Math.imul(ah4, bh6)) | 0;\n lo = (lo + Math.imul(al3, bl7)) | 0;\n mid = (mid + Math.imul(al3, bh7)) | 0;\n mid = (mid + Math.imul(ah3, bl7)) | 0;\n hi = (hi + Math.imul(ah3, bh7)) | 0;\n lo = (lo + Math.imul(al2, bl8)) | 0;\n mid = (mid + Math.imul(al2, bh8)) | 0;\n mid = (mid + Math.imul(ah2, bl8)) | 0;\n hi = (hi + Math.imul(ah2, bh8)) | 0;\n lo = (lo + Math.imul(al1, bl9)) | 0;\n mid = (mid + Math.imul(al1, bh9)) | 0;\n mid = (mid + Math.imul(ah1, bl9)) | 0;\n hi = (hi + Math.imul(ah1, bh9)) | 0;\n var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0;\n w10 &= 0x3ffffff;\n /* k = 11 */\n lo = Math.imul(al9, bl2);\n mid = Math.imul(al9, bh2);\n mid = (mid + Math.imul(ah9, bl2)) | 0;\n hi = Math.imul(ah9, bh2);\n lo = (lo + Math.imul(al8, bl3)) | 0;\n mid = (mid + Math.imul(al8, bh3)) | 0;\n mid = (mid + Math.imul(ah8, bl3)) | 0;\n hi = (hi + Math.imul(ah8, bh3)) | 0;\n lo = (lo + Math.imul(al7, bl4)) | 0;\n mid = (mid + Math.imul(al7, bh4)) | 0;\n mid = (mid + Math.imul(ah7, bl4)) | 0;\n hi = (hi + Math.imul(ah7, bh4)) | 0;\n lo = (lo + Math.imul(al6, bl5)) | 0;\n mid = (mid + Math.imul(al6, bh5)) | 0;\n mid = (mid + Math.imul(ah6, bl5)) | 0;\n hi = (hi + Math.imul(ah6, bh5)) | 0;\n lo = (lo + Math.imul(al5, bl6)) | 0;\n mid = (mid + Math.imul(al5, bh6)) | 0;\n mid = (mid + Math.imul(ah5, bl6)) | 0;\n hi = (hi + Math.imul(ah5, bh6)) | 0;\n lo = (lo + Math.imul(al4, bl7)) | 0;\n mid = (mid + Math.imul(al4, bh7)) | 0;\n mid = (mid + Math.imul(ah4, bl7)) | 0;\n hi = (hi + Math.imul(ah4, bh7)) | 0;\n lo = (lo + Math.imul(al3, bl8)) | 0;\n mid = (mid + Math.imul(al3, bh8)) | 0;\n mid = (mid + Math.imul(ah3, bl8)) | 0;\n hi = (hi + Math.imul(ah3, bh8)) | 0;\n lo = (lo + Math.imul(al2, bl9)) | 0;\n mid = (mid + Math.imul(al2, bh9)) | 0;\n mid = (mid + Math.imul(ah2, bl9)) | 0;\n hi = (hi + Math.imul(ah2, bh9)) | 0;\n var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0;\n w11 &= 0x3ffffff;\n /* k = 12 */\n lo = Math.imul(al9, bl3);\n mid = Math.imul(al9, bh3);\n mid = (mid + Math.imul(ah9, bl3)) | 0;\n hi = Math.imul(ah9, bh3);\n lo = (lo + Math.imul(al8, bl4)) | 0;\n mid = (mid + Math.imul(al8, bh4)) | 0;\n mid = (mid + Math.imul(ah8, bl4)) | 0;\n hi = (hi + Math.imul(ah8, bh4)) | 0;\n lo = (lo + Math.imul(al7, bl5)) | 0;\n mid = (mid + Math.imul(al7, bh5)) | 0;\n mid = (mid + Math.imul(ah7, bl5)) | 0;\n hi = (hi + Math.imul(ah7, bh5)) | 0;\n lo = (lo + Math.imul(al6, bl6)) | 0;\n mid = (mid + Math.imul(al6, bh6)) | 0;\n mid = (mid + Math.imul(ah6, bl6)) | 0;\n hi = (hi + Math.imul(ah6, bh6)) | 0;\n lo = (lo + Math.imul(al5, bl7)) | 0;\n mid = (mid + Math.imul(al5, bh7)) | 0;\n mid = (mid + Math.imul(ah5, bl7)) | 0;\n hi = (hi + Math.imul(ah5, bh7)) | 0;\n lo = (lo + Math.imul(al4, bl8)) | 0;\n mid = (mid + Math.imul(al4, bh8)) | 0;\n mid = (mid + Math.imul(ah4, bl8)) | 0;\n hi = (hi + Math.imul(ah4, bh8)) | 0;\n lo = (lo + Math.imul(al3, bl9)) | 0;\n mid = (mid + Math.imul(al3, bh9)) | 0;\n mid = (mid + Math.imul(ah3, bl9)) | 0;\n hi = (hi + Math.imul(ah3, bh9)) | 0;\n var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0;\n w12 &= 0x3ffffff;\n /* k = 13 */\n lo = Math.imul(al9, bl4);\n mid = Math.imul(al9, bh4);\n mid = (mid + Math.imul(ah9, bl4)) | 0;\n hi = Math.imul(ah9, bh4);\n lo = (lo + Math.imul(al8, bl5)) | 0;\n mid = (mid + Math.imul(al8, bh5)) | 0;\n mid = (mid + Math.imul(ah8, bl5)) | 0;\n hi = (hi + Math.imul(ah8, bh5)) | 0;\n lo = (lo + Math.imul(al7, bl6)) | 0;\n mid = (mid + Math.imul(al7, bh6)) | 0;\n mid = (mid + Math.imul(ah7, bl6)) | 0;\n hi = (hi + Math.imul(ah7, bh6)) | 0;\n lo = (lo + Math.imul(al6, bl7)) | 0;\n mid = (mid + Math.imul(al6, bh7)) | 0;\n mid = (mid + Math.imul(ah6, bl7)) | 0;\n hi = (hi + Math.imul(ah6, bh7)) | 0;\n lo = (lo + Math.imul(al5, bl8)) | 0;\n mid = (mid + Math.imul(al5, bh8)) | 0;\n mid = (mid + Math.imul(ah5, bl8)) | 0;\n hi = (hi + Math.imul(ah5, bh8)) | 0;\n lo = (lo + Math.imul(al4, bl9)) | 0;\n mid = (mid + Math.imul(al4, bh9)) | 0;\n mid = (mid + Math.imul(ah4, bl9)) | 0;\n hi = (hi + Math.imul(ah4, bh9)) | 0;\n var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0;\n w13 &= 0x3ffffff;\n /* k = 14 */\n lo = Math.imul(al9, bl5);\n mid = Math.imul(al9, bh5);\n mid = (mid + Math.imul(ah9, bl5)) | 0;\n hi = Math.imul(ah9, bh5);\n lo = (lo + Math.imul(al8, bl6)) | 0;\n mid = (mid + Math.imul(al8, bh6)) | 0;\n mid = (mid + Math.imul(ah8, bl6)) | 0;\n hi = (hi + Math.imul(ah8, bh6)) | 0;\n lo = (lo + Math.imul(al7, bl7)) | 0;\n mid = (mid + Math.imul(al7, bh7)) | 0;\n mid = (mid + Math.imul(ah7, bl7)) | 0;\n hi = (hi + Math.imul(ah7, bh7)) | 0;\n lo = (lo + Math.imul(al6, bl8)) | 0;\n mid = (mid + Math.imul(al6, bh8)) | 0;\n mid = (mid + Math.imul(ah6, bl8)) | 0;\n hi = (hi + Math.imul(ah6, bh8)) | 0;\n lo = (lo + Math.imul(al5, bl9)) | 0;\n mid = (mid + Math.imul(al5, bh9)) | 0;\n mid = (mid + Math.imul(ah5, bl9)) | 0;\n hi = (hi + Math.imul(ah5, bh9)) | 0;\n var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0;\n w14 &= 0x3ffffff;\n /* k = 15 */\n lo = Math.imul(al9, bl6);\n mid = Math.imul(al9, bh6);\n mid = (mid + Math.imul(ah9, bl6)) | 0;\n hi = Math.imul(ah9, bh6);\n lo = (lo + Math.imul(al8, bl7)) | 0;\n mid = (mid + Math.imul(al8, bh7)) | 0;\n mid = (mid + Math.imul(ah8, bl7)) | 0;\n hi = (hi + Math.imul(ah8, bh7)) | 0;\n lo = (lo + Math.imul(al7, bl8)) | 0;\n mid = (mid + Math.imul(al7, bh8)) | 0;\n mid = (mid + Math.imul(ah7, bl8)) | 0;\n hi = (hi + Math.imul(ah7, bh8)) | 0;\n lo = (lo + Math.imul(al6, bl9)) | 0;\n mid = (mid + Math.imul(al6, bh9)) | 0;\n mid = (mid + Math.imul(ah6, bl9)) | 0;\n hi = (hi + Math.imul(ah6, bh9)) | 0;\n var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0;\n w15 &= 0x3ffffff;\n /* k = 16 */\n lo = Math.imul(al9, bl7);\n mid = Math.imul(al9, bh7);\n mid = (mid + Math.imul(ah9, bl7)) | 0;\n hi = Math.imul(ah9, bh7);\n lo = (lo + Math.imul(al8, bl8)) | 0;\n mid = (mid + Math.imul(al8, bh8)) | 0;\n mid = (mid + Math.imul(ah8, bl8)) | 0;\n hi = (hi + Math.imul(ah8, bh8)) | 0;\n lo = (lo + Math.imul(al7, bl9)) | 0;\n mid = (mid + Math.imul(al7, bh9)) | 0;\n mid = (mid + Math.imul(ah7, bl9)) | 0;\n hi = (hi + Math.imul(ah7, bh9)) | 0;\n var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0;\n w16 &= 0x3ffffff;\n /* k = 17 */\n lo = Math.imul(al9, bl8);\n mid = Math.imul(al9, bh8);\n mid = (mid + Math.imul(ah9, bl8)) | 0;\n hi = Math.imul(ah9, bh8);\n lo = (lo + Math.imul(al8, bl9)) | 0;\n mid = (mid + Math.imul(al8, bh9)) | 0;\n mid = (mid + Math.imul(ah8, bl9)) | 0;\n hi = (hi + Math.imul(ah8, bh9)) | 0;\n var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0;\n w17 &= 0x3ffffff;\n /* k = 18 */\n lo = Math.imul(al9, bl9);\n mid = Math.imul(al9, bh9);\n mid = (mid + Math.imul(ah9, bl9)) | 0;\n hi = Math.imul(ah9, bh9);\n var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0;\n w18 &= 0x3ffffff;\n o[0] = w0;\n o[1] = w1;\n o[2] = w2;\n o[3] = w3;\n o[4] = w4;\n o[5] = w5;\n o[6] = w6;\n o[7] = w7;\n o[8] = w8;\n o[9] = w9;\n o[10] = w10;\n o[11] = w11;\n o[12] = w12;\n o[13] = w13;\n o[14] = w14;\n o[15] = w15;\n o[16] = w16;\n o[17] = w17;\n o[18] = w18;\n if (c !== 0) {\n o[19] = c;\n out.length++;\n }\n return out;\n };\n\n // Polyfill comb\n if (!Math.imul) {\n comb10MulTo = smallMulTo;\n }\n\n function bigMulTo (self, num, out) {\n out.negative = num.negative ^ self.negative;\n out.length = self.length + num.length;\n\n var carry = 0;\n var hncarry = 0;\n for (var k = 0; k < out.length - 1; k++) {\n // Sum all words with the same `i + j = k` and accumulate `ncarry`,\n // note that ncarry could be >= 0x3ffffff\n var ncarry = hncarry;\n hncarry = 0;\n var rword = carry & 0x3ffffff;\n var maxJ = Math.min(k, num.length - 1);\n for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {\n var i = k - j;\n var a = self.words[i] | 0;\n var b = num.words[j] | 0;\n var r = a * b;\n\n var lo = r & 0x3ffffff;\n ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0;\n lo = (lo + rword) | 0;\n rword = lo & 0x3ffffff;\n ncarry = (ncarry + (lo >>> 26)) | 0;\n\n hncarry += ncarry >>> 26;\n ncarry &= 0x3ffffff;\n }\n out.words[k] = rword;\n carry = ncarry;\n ncarry = hncarry;\n }\n if (carry !== 0) {\n out.words[k] = carry;\n } else {\n out.length--;\n }\n\n return out.strip();\n }\n\n function jumboMulTo (self, num, out) {\n var fftm = new FFTM();\n return fftm.mulp(self, num, out);\n }\n\n BN.prototype.mulTo = function mulTo (num, out) {\n var res;\n var len = this.length + num.length;\n if (this.length === 10 && num.length === 10) {\n res = comb10MulTo(this, num, out);\n } else if (len < 63) {\n res = smallMulTo(this, num, out);\n } else if (len < 1024) {\n res = bigMulTo(this, num, out);\n } else {\n res = jumboMulTo(this, num, out);\n }\n\n return res;\n };\n\n // Cooley-Tukey algorithm for FFT\n // slightly revisited to rely on looping instead of recursion\n\n function FFTM (x, y) {\n this.x = x;\n this.y = y;\n }\n\n FFTM.prototype.makeRBT = function makeRBT (N) {\n var t = new Array(N);\n var l = BN.prototype._countBits(N) - 1;\n for (var i = 0; i < N; i++) {\n t[i] = this.revBin(i, l, N);\n }\n\n return t;\n };\n\n // Returns binary-reversed representation of `x`\n FFTM.prototype.revBin = function revBin (x, l, N) {\n if (x === 0 || x === N - 1) return x;\n\n var rb = 0;\n for (var i = 0; i < l; i++) {\n rb |= (x & 1) << (l - i - 1);\n x >>= 1;\n }\n\n return rb;\n };\n\n // Performs \"tweedling\" phase, therefore 'emulating'\n // behaviour of the recursive algorithm\n FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) {\n for (var i = 0; i < N; i++) {\n rtws[i] = rws[rbt[i]];\n itws[i] = iws[rbt[i]];\n }\n };\n\n FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) {\n this.permute(rbt, rws, iws, rtws, itws, N);\n\n for (var s = 1; s < N; s <<= 1) {\n var l = s << 1;\n\n var rtwdf = Math.cos(2 * Math.PI / l);\n var itwdf = Math.sin(2 * Math.PI / l);\n\n for (var p = 0; p < N; p += l) {\n var rtwdf_ = rtwdf;\n var itwdf_ = itwdf;\n\n for (var j = 0; j < s; j++) {\n var re = rtws[p + j];\n var ie = itws[p + j];\n\n var ro = rtws[p + j + s];\n var io = itws[p + j + s];\n\n var rx = rtwdf_ * ro - itwdf_ * io;\n\n io = rtwdf_ * io + itwdf_ * ro;\n ro = rx;\n\n rtws[p + j] = re + ro;\n itws[p + j] = ie + io;\n\n rtws[p + j + s] = re - ro;\n itws[p + j + s] = ie - io;\n\n /* jshint maxdepth : false */\n if (j !== l) {\n rx = rtwdf * rtwdf_ - itwdf * itwdf_;\n\n itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_;\n rtwdf_ = rx;\n }\n }\n }\n }\n };\n\n FFTM.prototype.guessLen13b = function guessLen13b (n, m) {\n var N = Math.max(m, n) | 1;\n var odd = N & 1;\n var i = 0;\n for (N = N / 2 | 0; N; N = N >>> 1) {\n i++;\n }\n\n return 1 << i + 1 + odd;\n };\n\n FFTM.prototype.conjugate = function conjugate (rws, iws, N) {\n if (N <= 1) return;\n\n for (var i = 0; i < N / 2; i++) {\n var t = rws[i];\n\n rws[i] = rws[N - i - 1];\n rws[N - i - 1] = t;\n\n t = iws[i];\n\n iws[i] = -iws[N - i - 1];\n iws[N - i - 1] = -t;\n }\n };\n\n FFTM.prototype.normalize13b = function normalize13b (ws, N) {\n var carry = 0;\n for (var i = 0; i < N / 2; i++) {\n var w = Math.round(ws[2 * i + 1] / N) * 0x2000 +\n Math.round(ws[2 * i] / N) +\n carry;\n\n ws[i] = w & 0x3ffffff;\n\n if (w < 0x4000000) {\n carry = 0;\n } else {\n carry = w / 0x4000000 | 0;\n }\n }\n\n return ws;\n };\n\n FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) {\n var carry = 0;\n for (var i = 0; i < len; i++) {\n carry = carry + (ws[i] | 0);\n\n rws[2 * i] = carry & 0x1fff; carry = carry >>> 13;\n rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13;\n }\n\n // Pad with zeroes\n for (i = 2 * len; i < N; ++i) {\n rws[i] = 0;\n }\n\n assert(carry === 0);\n assert((carry & ~0x1fff) === 0);\n };\n\n FFTM.prototype.stub = function stub (N) {\n var ph = new Array(N);\n for (var i = 0; i < N; i++) {\n ph[i] = 0;\n }\n\n return ph;\n };\n\n FFTM.prototype.mulp = function mulp (x, y, out) {\n var N = 2 * this.guessLen13b(x.length, y.length);\n\n var rbt = this.makeRBT(N);\n\n var _ = this.stub(N);\n\n var rws = new Array(N);\n var rwst = new Array(N);\n var iwst = new Array(N);\n\n var nrws = new Array(N);\n var nrwst = new Array(N);\n var niwst = new Array(N);\n\n var rmws = out.words;\n rmws.length = N;\n\n this.convert13b(x.words, x.length, rws, N);\n this.convert13b(y.words, y.length, nrws, N);\n\n this.transform(rws, _, rwst, iwst, N, rbt);\n this.transform(nrws, _, nrwst, niwst, N, rbt);\n\n for (var i = 0; i < N; i++) {\n var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i];\n iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i];\n rwst[i] = rx;\n }\n\n this.conjugate(rwst, iwst, N);\n this.transform(rwst, iwst, rmws, _, N, rbt);\n this.conjugate(rmws, _, N);\n this.normalize13b(rmws, N);\n\n out.negative = x.negative ^ y.negative;\n out.length = x.length + y.length;\n return out.strip();\n };\n\n // Multiply `this` by `num`\n BN.prototype.mul = function mul (num) {\n var out = new BN(null);\n out.words = new Array(this.length + num.length);\n return this.mulTo(num, out);\n };\n\n // Multiply employing FFT\n BN.prototype.mulf = function mulf (num) {\n var out = new BN(null);\n out.words = new Array(this.length + num.length);\n return jumboMulTo(this, num, out);\n };\n\n // In-place Multiplication\n BN.prototype.imul = function imul (num) {\n return this.clone().mulTo(num, this);\n };\n\n BN.prototype.imuln = function imuln (num) {\n assert(typeof num === 'number');\n assert(num < 0x4000000);\n\n // Carry\n var carry = 0;\n for (var i = 0; i < this.length; i++) {\n var w = (this.words[i] | 0) * num;\n var lo = (w & 0x3ffffff) + (carry & 0x3ffffff);\n carry >>= 26;\n carry += (w / 0x4000000) | 0;\n // NOTE: lo is 27bit maximum\n carry += lo >>> 26;\n this.words[i] = lo & 0x3ffffff;\n }\n\n if (carry !== 0) {\n this.words[i] = carry;\n this.length++;\n }\n\n return this;\n };\n\n BN.prototype.muln = function muln (num) {\n return this.clone().imuln(num);\n };\n\n // `this` * `this`\n BN.prototype.sqr = function sqr () {\n return this.mul(this);\n };\n\n // `this` * `this` in-place\n BN.prototype.isqr = function isqr () {\n return this.imul(this.clone());\n };\n\n // Math.pow(`this`, `num`)\n BN.prototype.pow = function pow (num) {\n var w = toBitArray(num);\n if (w.length === 0) return new BN(1);\n\n // Skip leading zeroes\n var res = this;\n for (var i = 0; i < w.length; i++, res = res.sqr()) {\n if (w[i] !== 0) break;\n }\n\n if (++i < w.length) {\n for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) {\n if (w[i] === 0) continue;\n\n res = res.mul(q);\n }\n }\n\n return res;\n };\n\n // Shift-left in-place\n BN.prototype.iushln = function iushln (bits) {\n assert(typeof bits === 'number' && bits >= 0);\n var r = bits % 26;\n var s = (bits - r) / 26;\n var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r);\n var i;\n\n if (r !== 0) {\n var carry = 0;\n\n for (i = 0; i < this.length; i++) {\n var newCarry = this.words[i] & carryMask;\n var c = ((this.words[i] | 0) - newCarry) << r;\n this.words[i] = c | carry;\n carry = newCarry >>> (26 - r);\n }\n\n if (carry) {\n this.words[i] = carry;\n this.length++;\n }\n }\n\n if (s !== 0) {\n for (i = this.length - 1; i >= 0; i--) {\n this.words[i + s] = this.words[i];\n }\n\n for (i = 0; i < s; i++) {\n this.words[i] = 0;\n }\n\n this.length += s;\n }\n\n return this.strip();\n };\n\n BN.prototype.ishln = function ishln (bits) {\n // TODO(indutny): implement me\n assert(this.negative === 0);\n return this.iushln(bits);\n };\n\n // Shift-right in-place\n // NOTE: `hint` is a lowest bit before trailing zeroes\n // NOTE: if `extended` is present - it will be filled with destroyed bits\n BN.prototype.iushrn = function iushrn (bits, hint, extended) {\n assert(typeof bits === 'number' && bits >= 0);\n var h;\n if (hint) {\n h = (hint - (hint % 26)) / 26;\n } else {\n h = 0;\n }\n\n var r = bits % 26;\n var s = Math.min((bits - r) / 26, this.length);\n var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);\n var maskedWords = extended;\n\n h -= s;\n h = Math.max(0, h);\n\n // Extended mode, copy masked part\n if (maskedWords) {\n for (var i = 0; i < s; i++) {\n maskedWords.words[i] = this.words[i];\n }\n maskedWords.length = s;\n }\n\n if (s === 0) {\n // No-op, we should not move anything at all\n } else if (this.length > s) {\n this.length -= s;\n for (i = 0; i < this.length; i++) {\n this.words[i] = this.words[i + s];\n }\n } else {\n this.words[0] = 0;\n this.length = 1;\n }\n\n var carry = 0;\n for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) {\n var word = this.words[i] | 0;\n this.words[i] = (carry << (26 - r)) | (word >>> r);\n carry = word & mask;\n }\n\n // Push carried bits as a mask\n if (maskedWords && carry !== 0) {\n maskedWords.words[maskedWords.length++] = carry;\n }\n\n if (this.length === 0) {\n this.words[0] = 0;\n this.length = 1;\n }\n\n return this.strip();\n };\n\n BN.prototype.ishrn = function ishrn (bits, hint, extended) {\n // TODO(indutny): implement me\n assert(this.negative === 0);\n return this.iushrn(bits, hint, extended);\n };\n\n // Shift-left\n BN.prototype.shln = function shln (bits) {\n return this.clone().ishln(bits);\n };\n\n BN.prototype.ushln = function ushln (bits) {\n return this.clone().iushln(bits);\n };\n\n // Shift-right\n BN.prototype.shrn = function shrn (bits) {\n return this.clone().ishrn(bits);\n };\n\n BN.prototype.ushrn = function ushrn (bits) {\n return this.clone().iushrn(bits);\n };\n\n // Test if n bit is set\n BN.prototype.testn = function testn (bit) {\n assert(typeof bit === 'number' && bit >= 0);\n var r = bit % 26;\n var s = (bit - r) / 26;\n var q = 1 << r;\n\n // Fast case: bit is much higher than all existing words\n if (this.length <= s) return false;\n\n // Check bit and return\n var w = this.words[s];\n\n return !!(w & q);\n };\n\n // Return only lowers bits of number (in-place)\n BN.prototype.imaskn = function imaskn (bits) {\n assert(typeof bits === 'number' && bits >= 0);\n var r = bits % 26;\n var s = (bits - r) / 26;\n\n assert(this.negative === 0, 'imaskn works only with positive numbers');\n\n if (this.length <= s) {\n return this;\n }\n\n if (r !== 0) {\n s++;\n }\n this.length = Math.min(s, this.length);\n\n if (r !== 0) {\n var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);\n this.words[this.length - 1] &= mask;\n }\n\n return this.strip();\n };\n\n // Return only lowers bits of number\n BN.prototype.maskn = function maskn (bits) {\n return this.clone().imaskn(bits);\n };\n\n // Add plain number `num` to `this`\n BN.prototype.iaddn = function iaddn (num) {\n assert(typeof num === 'number');\n assert(num < 0x4000000);\n if (num < 0) return this.isubn(-num);\n\n // Possible sign change\n if (this.negative !== 0) {\n if (this.length === 1 && (this.words[0] | 0) < num) {\n this.words[0] = num - (this.words[0] | 0);\n this.negative = 0;\n return this;\n }\n\n this.negative = 0;\n this.isubn(num);\n this.negative = 1;\n return this;\n }\n\n // Add without checks\n return this._iaddn(num);\n };\n\n BN.prototype._iaddn = function _iaddn (num) {\n this.words[0] += num;\n\n // Carry\n for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) {\n this.words[i] -= 0x4000000;\n if (i === this.length - 1) {\n this.words[i + 1] = 1;\n } else {\n this.words[i + 1]++;\n }\n }\n this.length = Math.max(this.length, i + 1);\n\n return this;\n };\n\n // Subtract plain number `num` from `this`\n BN.prototype.isubn = function isubn (num) {\n assert(typeof num === 'number');\n assert(num < 0x4000000);\n if (num < 0) return this.iaddn(-num);\n\n if (this.negative !== 0) {\n this.negative = 0;\n this.iaddn(num);\n this.negative = 1;\n return this;\n }\n\n this.words[0] -= num;\n\n if (this.length === 1 && this.words[0] < 0) {\n this.words[0] = -this.words[0];\n this.negative = 1;\n } else {\n // Carry\n for (var i = 0; i < this.length && this.words[i] < 0; i++) {\n this.words[i] += 0x4000000;\n this.words[i + 1] -= 1;\n }\n }\n\n return this.strip();\n };\n\n BN.prototype.addn = function addn (num) {\n return this.clone().iaddn(num);\n };\n\n BN.prototype.subn = function subn (num) {\n return this.clone().isubn(num);\n };\n\n BN.prototype.iabs = function iabs () {\n this.negative = 0;\n\n return this;\n };\n\n BN.prototype.abs = function abs () {\n return this.clone().iabs();\n };\n\n BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) {\n var len = num.length + shift;\n var i;\n\n this._expand(len);\n\n var w;\n var carry = 0;\n for (i = 0; i < num.length; i++) {\n w = (this.words[i + shift] | 0) + carry;\n var right = (num.words[i] | 0) * mul;\n w -= right & 0x3ffffff;\n carry = (w >> 26) - ((right / 0x4000000) | 0);\n this.words[i + shift] = w & 0x3ffffff;\n }\n for (; i < this.length - shift; i++) {\n w = (this.words[i + shift] | 0) + carry;\n carry = w >> 26;\n this.words[i + shift] = w & 0x3ffffff;\n }\n\n if (carry === 0) return this.strip();\n\n // Subtraction overflow\n assert(carry === -1);\n carry = 0;\n for (i = 0; i < this.length; i++) {\n w = -(this.words[i] | 0) + carry;\n carry = w >> 26;\n this.words[i] = w & 0x3ffffff;\n }\n this.negative = 1;\n\n return this.strip();\n };\n\n BN.prototype._wordDiv = function _wordDiv (num, mode) {\n var shift = this.length - num.length;\n\n var a = this.clone();\n var b = num;\n\n // Normalize\n var bhi = b.words[b.length - 1] | 0;\n var bhiBits = this._countBits(bhi);\n shift = 26 - bhiBits;\n if (shift !== 0) {\n b = b.ushln(shift);\n a.iushln(shift);\n bhi = b.words[b.length - 1] | 0;\n }\n\n // Initialize quotient\n var m = a.length - b.length;\n var q;\n\n if (mode !== 'mod') {\n q = new BN(null);\n q.length = m + 1;\n q.words = new Array(q.length);\n for (var i = 0; i < q.length; i++) {\n q.words[i] = 0;\n }\n }\n\n var diff = a.clone()._ishlnsubmul(b, 1, m);\n if (diff.negative === 0) {\n a = diff;\n if (q) {\n q.words[m] = 1;\n }\n }\n\n for (var j = m - 1; j >= 0; j--) {\n var qj = (a.words[b.length + j] | 0) * 0x4000000 +\n (a.words[b.length + j - 1] | 0);\n\n // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max\n // (0x7ffffff)\n qj = Math.min((qj / bhi) | 0, 0x3ffffff);\n\n a._ishlnsubmul(b, qj, j);\n while (a.negative !== 0) {\n qj--;\n a.negative = 0;\n a._ishlnsubmul(b, 1, j);\n if (!a.isZero()) {\n a.negative ^= 1;\n }\n }\n if (q) {\n q.words[j] = qj;\n }\n }\n if (q) {\n q.strip();\n }\n a.strip();\n\n // Denormalize\n if (mode !== 'div' && shift !== 0) {\n a.iushrn(shift);\n }\n\n return {\n div: q || null,\n mod: a\n };\n };\n\n // NOTE: 1) `mode` can be set to `mod` to request mod only,\n // to `div` to request div only, or be absent to\n // request both div & mod\n // 2) `positive` is true if unsigned mod is requested\n BN.prototype.divmod = function divmod (num, mode, positive) {\n assert(!num.isZero());\n\n if (this.isZero()) {\n return {\n div: new BN(0),\n mod: new BN(0)\n };\n }\n\n var div, mod, res;\n if (this.negative !== 0 && num.negative === 0) {\n res = this.neg().divmod(num, mode);\n\n if (mode !== 'mod') {\n div = res.div.neg();\n }\n\n if (mode !== 'div') {\n mod = res.mod.neg();\n if (positive && mod.negative !== 0) {\n mod.iadd(num);\n }\n }\n\n return {\n div: div,\n mod: mod\n };\n }\n\n if (this.negative === 0 && num.negative !== 0) {\n res = this.divmod(num.neg(), mode);\n\n if (mode !== 'mod') {\n div = res.div.neg();\n }\n\n return {\n div: div,\n mod: res.mod\n };\n }\n\n if ((this.negative & num.negative) !== 0) {\n res = this.neg().divmod(num.neg(), mode);\n\n if (mode !== 'div') {\n mod = res.mod.neg();\n if (positive && mod.negative !== 0) {\n mod.isub(num);\n }\n }\n\n return {\n div: res.div,\n mod: mod\n };\n }\n\n // Both numbers are positive at this point\n\n // Strip both numbers to approximate shift value\n if (num.length > this.length || this.cmp(num) < 0) {\n return {\n div: new BN(0),\n mod: this\n };\n }\n\n // Very short reduction\n if (num.length === 1) {\n if (mode === 'div') {\n return {\n div: this.divn(num.words[0]),\n mod: null\n };\n }\n\n if (mode === 'mod') {\n return {\n div: null,\n mod: new BN(this.modn(num.words[0]))\n };\n }\n\n return {\n div: this.divn(num.words[0]),\n mod: new BN(this.modn(num.words[0]))\n };\n }\n\n return this._wordDiv(num, mode);\n };\n\n // Find `this` / `num`\n BN.prototype.div = function div (num) {\n return this.divmod(num, 'div', false).div;\n };\n\n // Find `this` % `num`\n BN.prototype.mod = function mod (num) {\n return this.divmod(num, 'mod', false).mod;\n };\n\n BN.prototype.umod = function umod (num) {\n return this.divmod(num, 'mod', true).mod;\n };\n\n // Find Round(`this` / `num`)\n BN.prototype.divRound = function divRound (num) {\n var dm = this.divmod(num);\n\n // Fast case - exact division\n if (dm.mod.isZero()) return dm.div;\n\n var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod;\n\n var half = num.ushrn(1);\n var r2 = num.andln(1);\n var cmp = mod.cmp(half);\n\n // Round down\n if (cmp < 0 || r2 === 1 && cmp === 0) return dm.div;\n\n // Round up\n return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1);\n };\n\n BN.prototype.modn = function modn (num) {\n assert(num <= 0x3ffffff);\n var p = (1 << 26) % num;\n\n var acc = 0;\n for (var i = this.length - 1; i >= 0; i--) {\n acc = (p * acc + (this.words[i] | 0)) % num;\n }\n\n return acc;\n };\n\n // In-place division by number\n BN.prototype.idivn = function idivn (num) {\n assert(num <= 0x3ffffff);\n\n var carry = 0;\n for (var i = this.length - 1; i >= 0; i--) {\n var w = (this.words[i] | 0) + carry * 0x4000000;\n this.words[i] = (w / num) | 0;\n carry = w % num;\n }\n\n return this.strip();\n };\n\n BN.prototype.divn = function divn (num) {\n return this.clone().idivn(num);\n };\n\n BN.prototype.egcd = function egcd (p) {\n assert(p.negative === 0);\n assert(!p.isZero());\n\n var x = this;\n var y = p.clone();\n\n if (x.negative !== 0) {\n x = x.umod(p);\n } else {\n x = x.clone();\n }\n\n // A * x + B * y = x\n var A = new BN(1);\n var B = new BN(0);\n\n // C * x + D * y = y\n var C = new BN(0);\n var D = new BN(1);\n\n var g = 0;\n\n while (x.isEven() && y.isEven()) {\n x.iushrn(1);\n y.iushrn(1);\n ++g;\n }\n\n var yp = y.clone();\n var xp = x.clone();\n\n while (!x.isZero()) {\n for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1);\n if (i > 0) {\n x.iushrn(i);\n while (i-- > 0) {\n if (A.isOdd() || B.isOdd()) {\n A.iadd(yp);\n B.isub(xp);\n }\n\n A.iushrn(1);\n B.iushrn(1);\n }\n }\n\n for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);\n if (j > 0) {\n y.iushrn(j);\n while (j-- > 0) {\n if (C.isOdd() || D.isOdd()) {\n C.iadd(yp);\n D.isub(xp);\n }\n\n C.iushrn(1);\n D.iushrn(1);\n }\n }\n\n if (x.cmp(y) >= 0) {\n x.isub(y);\n A.isub(C);\n B.isub(D);\n } else {\n y.isub(x);\n C.isub(A);\n D.isub(B);\n }\n }\n\n return {\n a: C,\n b: D,\n gcd: y.iushln(g)\n };\n };\n\n // This is reduced incarnation of the binary EEA\n // above, designated to invert members of the\n // _prime_ fields F(p) at a maximal speed\n BN.prototype._invmp = function _invmp (p) {\n assert(p.negative === 0);\n assert(!p.isZero());\n\n var a = this;\n var b = p.clone();\n\n if (a.negative !== 0) {\n a = a.umod(p);\n } else {\n a = a.clone();\n }\n\n var x1 = new BN(1);\n var x2 = new BN(0);\n\n var delta = b.clone();\n\n while (a.cmpn(1) > 0 && b.cmpn(1) > 0) {\n for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1);\n if (i > 0) {\n a.iushrn(i);\n while (i-- > 0) {\n if (x1.isOdd()) {\n x1.iadd(delta);\n }\n\n x1.iushrn(1);\n }\n }\n\n for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);\n if (j > 0) {\n b.iushrn(j);\n while (j-- > 0) {\n if (x2.isOdd()) {\n x2.iadd(delta);\n }\n\n x2.iushrn(1);\n }\n }\n\n if (a.cmp(b) >= 0) {\n a.isub(b);\n x1.isub(x2);\n } else {\n b.isub(a);\n x2.isub(x1);\n }\n }\n\n var res;\n if (a.cmpn(1) === 0) {\n res = x1;\n } else {\n res = x2;\n }\n\n if (res.cmpn(0) < 0) {\n res.iadd(p);\n }\n\n return res;\n };\n\n BN.prototype.gcd = function gcd (num) {\n if (this.isZero()) return num.abs();\n if (num.isZero()) return this.abs();\n\n var a = this.clone();\n var b = num.clone();\n a.negative = 0;\n b.negative = 0;\n\n // Remove common factor of two\n for (var shift = 0; a.isEven() && b.isEven(); shift++) {\n a.iushrn(1);\n b.iushrn(1);\n }\n\n do {\n while (a.isEven()) {\n a.iushrn(1);\n }\n while (b.isEven()) {\n b.iushrn(1);\n }\n\n var r = a.cmp(b);\n if (r < 0) {\n // Swap `a` and `b` to make `a` always bigger than `b`\n var t = a;\n a = b;\n b = t;\n } else if (r === 0 || b.cmpn(1) === 0) {\n break;\n }\n\n a.isub(b);\n } while (true);\n\n return b.iushln(shift);\n };\n\n // Invert number in the field F(num)\n BN.prototype.invm = function invm (num) {\n return this.egcd(num).a.umod(num);\n };\n\n BN.prototype.isEven = function isEven () {\n return (this.words[0] & 1) === 0;\n };\n\n BN.prototype.isOdd = function isOdd () {\n return (this.words[0] & 1) === 1;\n };\n\n // And first word and num\n BN.prototype.andln = function andln (num) {\n return this.words[0] & num;\n };\n\n // Increment at the bit position in-line\n BN.prototype.bincn = function bincn (bit) {\n assert(typeof bit === 'number');\n var r = bit % 26;\n var s = (bit - r) / 26;\n var q = 1 << r;\n\n // Fast case: bit is much higher than all existing words\n if (this.length <= s) {\n this._expand(s + 1);\n this.words[s] |= q;\n return this;\n }\n\n // Add bit and propagate, if needed\n var carry = q;\n for (var i = s; carry !== 0 && i < this.length; i++) {\n var w = this.words[i] | 0;\n w += carry;\n carry = w >>> 26;\n w &= 0x3ffffff;\n this.words[i] = w;\n }\n if (carry !== 0) {\n this.words[i] = carry;\n this.length++;\n }\n return this;\n };\n\n BN.prototype.isZero = function isZero () {\n return this.length === 1 && this.words[0] === 0;\n };\n\n BN.prototype.cmpn = function cmpn (num) {\n var negative = num < 0;\n\n if (this.negative !== 0 && !negative) return -1;\n if (this.negative === 0 && negative) return 1;\n\n this.strip();\n\n var res;\n if (this.length > 1) {\n res = 1;\n } else {\n if (negative) {\n num = -num;\n }\n\n assert(num <= 0x3ffffff, 'Number is too big');\n\n var w = this.words[0] | 0;\n res = w === num ? 0 : w < num ? -1 : 1;\n }\n if (this.negative !== 0) return -res | 0;\n return res;\n };\n\n // Compare two numbers and return:\n // 1 - if `this` > `num`\n // 0 - if `this` == `num`\n // -1 - if `this` < `num`\n BN.prototype.cmp = function cmp (num) {\n if (this.negative !== 0 && num.negative === 0) return -1;\n if (this.negative === 0 && num.negative !== 0) return 1;\n\n var res = this.ucmp(num);\n if (this.negative !== 0) return -res | 0;\n return res;\n };\n\n // Unsigned comparison\n BN.prototype.ucmp = function ucmp (num) {\n // At this point both numbers have the same sign\n if (this.length > num.length) return 1;\n if (this.length < num.length) return -1;\n\n var res = 0;\n for (var i = this.length - 1; i >= 0; i--) {\n var a = this.words[i] | 0;\n var b = num.words[i] | 0;\n\n if (a === b) continue;\n if (a < b) {\n res = -1;\n } else if (a > b) {\n res = 1;\n }\n break;\n }\n return res;\n };\n\n BN.prototype.gtn = function gtn (num) {\n return this.cmpn(num) === 1;\n };\n\n BN.prototype.gt = function gt (num) {\n return this.cmp(num) === 1;\n };\n\n BN.prototype.gten = function gten (num) {\n return this.cmpn(num) >= 0;\n };\n\n BN.prototype.gte = function gte (num) {\n return this.cmp(num) >= 0;\n };\n\n BN.prototype.ltn = function ltn (num) {\n return this.cmpn(num) === -1;\n };\n\n BN.prototype.lt = function lt (num) {\n return this.cmp(num) === -1;\n };\n\n BN.prototype.lten = function lten (num) {\n return this.cmpn(num) <= 0;\n };\n\n BN.prototype.lte = function lte (num) {\n return this.cmp(num) <= 0;\n };\n\n BN.prototype.eqn = function eqn (num) {\n return this.cmpn(num) === 0;\n };\n\n BN.prototype.eq = function eq (num) {\n return this.cmp(num) === 0;\n };\n\n //\n // A reduce context, could be using montgomery or something better, depending\n // on the `m` itself.\n //\n BN.red = function red (num) {\n return new Red(num);\n };\n\n BN.prototype.toRed = function toRed (ctx) {\n assert(!this.red, 'Already a number in reduction context');\n assert(this.negative === 0, 'red works only with positives');\n return ctx.convertTo(this)._forceRed(ctx);\n };\n\n BN.prototype.fromRed = function fromRed () {\n assert(this.red, 'fromRed works only with numbers in reduction context');\n return this.red.convertFrom(this);\n };\n\n BN.prototype._forceRed = function _forceRed (ctx) {\n this.red = ctx;\n return this;\n };\n\n BN.prototype.forceRed = function forceRed (ctx) {\n assert(!this.red, 'Already a number in reduction context');\n return this._forceRed(ctx);\n };\n\n BN.prototype.redAdd = function redAdd (num) {\n assert(this.red, 'redAdd works only with red numbers');\n return this.red.add(this, num);\n };\n\n BN.prototype.redIAdd = function redIAdd (num) {\n assert(this.red, 'redIAdd works only with red numbers');\n return this.red.iadd(this, num);\n };\n\n BN.prototype.redSub = function redSub (num) {\n assert(this.red, 'redSub works only with red numbers');\n return this.red.sub(this, num);\n };\n\n BN.prototype.redISub = function redISub (num) {\n assert(this.red, 'redISub works only with red numbers');\n return this.red.isub(this, num);\n };\n\n BN.prototype.redShl = function redShl (num) {\n assert(this.red, 'redShl works only with red numbers');\n return this.red.shl(this, num);\n };\n\n BN.prototype.redMul = function redMul (num) {\n assert(this.red, 'redMul works only with red numbers');\n this.red._verify2(this, num);\n return this.red.mul(this, num);\n };\n\n BN.prototype.redIMul = function redIMul (num) {\n assert(this.red, 'redMul works only with red numbers');\n this.red._verify2(this, num);\n return this.red.imul(this, num);\n };\n\n BN.prototype.redSqr = function redSqr () {\n assert(this.red, 'redSqr works only with red numbers');\n this.red._verify1(this);\n return this.red.sqr(this);\n };\n\n BN.prototype.redISqr = function redISqr () {\n assert(this.red, 'redISqr works only with red numbers');\n this.red._verify1(this);\n return this.red.isqr(this);\n };\n\n // Square root over p\n BN.prototype.redSqrt = function redSqrt () {\n assert(this.red, 'redSqrt works only with red numbers');\n this.red._verify1(this);\n return this.red.sqrt(this);\n };\n\n BN.prototype.redInvm = function redInvm () {\n assert(this.red, 'redInvm works only with red numbers');\n this.red._verify1(this);\n return this.red.invm(this);\n };\n\n // Return negative clone of `this` % `red modulo`\n BN.prototype.redNeg = function redNeg () {\n assert(this.red, 'redNeg works only with red numbers');\n this.red._verify1(this);\n return this.red.neg(this);\n };\n\n BN.prototype.redPow = function redPow (num) {\n assert(this.red && !num.red, 'redPow(normalNum)');\n this.red._verify1(this);\n return this.red.pow(this, num);\n };\n\n // Prime numbers with efficient reduction\n var primes = {\n k256: null,\n p224: null,\n p192: null,\n p25519: null\n };\n\n // Pseudo-Mersenne prime\n function MPrime (name, p) {\n // P = 2 ^ N - K\n this.name = name;\n this.p = new BN(p, 16);\n this.n = this.p.bitLength();\n this.k = new BN(1).iushln(this.n).isub(this.p);\n\n this.tmp = this._tmp();\n }\n\n MPrime.prototype._tmp = function _tmp () {\n var tmp = new BN(null);\n tmp.words = new Array(Math.ceil(this.n / 13));\n return tmp;\n };\n\n MPrime.prototype.ireduce = function ireduce (num) {\n // Assumes that `num` is less than `P^2`\n // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P)\n var r = num;\n var rlen;\n\n do {\n this.split(r, this.tmp);\n r = this.imulK(r);\n r = r.iadd(this.tmp);\n rlen = r.bitLength();\n } while (rlen > this.n);\n\n var cmp = rlen < this.n ? -1 : r.ucmp(this.p);\n if (cmp === 0) {\n r.words[0] = 0;\n r.length = 1;\n } else if (cmp > 0) {\n r.isub(this.p);\n } else {\n r.strip();\n }\n\n return r;\n };\n\n MPrime.prototype.split = function split (input, out) {\n input.iushrn(this.n, 0, out);\n };\n\n MPrime.prototype.imulK = function imulK (num) {\n return num.imul(this.k);\n };\n\n function K256 () {\n MPrime.call(\n this,\n 'k256',\n 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f');\n }\n inherits(K256, MPrime);\n\n K256.prototype.split = function split (input, output) {\n // 256 = 9 * 26 + 22\n var mask = 0x3fffff;\n\n var outLen = Math.min(input.length, 9);\n for (var i = 0; i < outLen; i++) {\n output.words[i] = input.words[i];\n }\n output.length = outLen;\n\n if (input.length <= 9) {\n input.words[0] = 0;\n input.length = 1;\n return;\n }\n\n // Shift by 9 limbs\n var prev = input.words[9];\n output.words[output.length++] = prev & mask;\n\n for (i = 10; i < input.length; i++) {\n var next = input.words[i] | 0;\n input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22);\n prev = next;\n }\n prev >>>= 22;\n input.words[i - 10] = prev;\n if (prev === 0 && input.length > 10) {\n input.length -= 10;\n } else {\n input.length -= 9;\n }\n };\n\n K256.prototype.imulK = function imulK (num) {\n // K = 0x1000003d1 = [ 0x40, 0x3d1 ]\n num.words[num.length] = 0;\n num.words[num.length + 1] = 0;\n num.length += 2;\n\n // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390\n var lo = 0;\n for (var i = 0; i < num.length; i++) {\n var w = num.words[i] | 0;\n lo += w * 0x3d1;\n num.words[i] = lo & 0x3ffffff;\n lo = w * 0x40 + ((lo / 0x4000000) | 0);\n }\n\n // Fast length reduction\n if (num.words[num.length - 1] === 0) {\n num.length--;\n if (num.words[num.length - 1] === 0) {\n num.length--;\n }\n }\n return num;\n };\n\n function P224 () {\n MPrime.call(\n this,\n 'p224',\n 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001');\n }\n inherits(P224, MPrime);\n\n function P192 () {\n MPrime.call(\n this,\n 'p192',\n 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff');\n }\n inherits(P192, MPrime);\n\n function P25519 () {\n // 2 ^ 255 - 19\n MPrime.call(\n this,\n '25519',\n '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed');\n }\n inherits(P25519, MPrime);\n\n P25519.prototype.imulK = function imulK (num) {\n // K = 0x13\n var carry = 0;\n for (var i = 0; i < num.length; i++) {\n var hi = (num.words[i] | 0) * 0x13 + carry;\n var lo = hi & 0x3ffffff;\n hi >>>= 26;\n\n num.words[i] = lo;\n carry = hi;\n }\n if (carry !== 0) {\n num.words[num.length++] = carry;\n }\n return num;\n };\n\n // Exported mostly for testing purposes, use plain name instead\n BN._prime = function prime (name) {\n // Cached version of prime\n if (primes[name]) return primes[name];\n\n var prime;\n if (name === 'k256') {\n prime = new K256();\n } else if (name === 'p224') {\n prime = new P224();\n } else if (name === 'p192') {\n prime = new P192();\n } else if (name === 'p25519') {\n prime = new P25519();\n } else {\n throw new Error('Unknown prime ' + name);\n }\n primes[name] = prime;\n\n return prime;\n };\n\n //\n // Base reduction engine\n //\n function Red (m) {\n if (typeof m === 'string') {\n var prime = BN._prime(m);\n this.m = prime.p;\n this.prime = prime;\n } else {\n assert(m.gtn(1), 'modulus must be greater than 1');\n this.m = m;\n this.prime = null;\n }\n }\n\n Red.prototype._verify1 = function _verify1 (a) {\n assert(a.negative === 0, 'red works only with positives');\n assert(a.red, 'red works only with red numbers');\n };\n\n Red.prototype._verify2 = function _verify2 (a, b) {\n assert((a.negative | b.negative) === 0, 'red works only with positives');\n assert(a.red && a.red === b.red,\n 'red works only with red numbers');\n };\n\n Red.prototype.imod = function imod (a) {\n if (this.prime) return this.prime.ireduce(a)._forceRed(this);\n return a.umod(this.m)._forceRed(this);\n };\n\n Red.prototype.neg = function neg (a) {\n if (a.isZero()) {\n return a.clone();\n }\n\n return this.m.sub(a)._forceRed(this);\n };\n\n Red.prototype.add = function add (a, b) {\n this._verify2(a, b);\n\n var res = a.add(b);\n if (res.cmp(this.m) >= 0) {\n res.isub(this.m);\n }\n return res._forceRed(this);\n };\n\n Red.prototype.iadd = function iadd (a, b) {\n this._verify2(a, b);\n\n var res = a.iadd(b);\n if (res.cmp(this.m) >= 0) {\n res.isub(this.m);\n }\n return res;\n };\n\n Red.prototype.sub = function sub (a, b) {\n this._verify2(a, b);\n\n var res = a.sub(b);\n if (res.cmpn(0) < 0) {\n res.iadd(this.m);\n }\n return res._forceRed(this);\n };\n\n Red.prototype.isub = function isub (a, b) {\n this._verify2(a, b);\n\n var res = a.isub(b);\n if (res.cmpn(0) < 0) {\n res.iadd(this.m);\n }\n return res;\n };\n\n Red.prototype.shl = function shl (a, num) {\n this._verify1(a);\n return this.imod(a.ushln(num));\n };\n\n Red.prototype.imul = function imul (a, b) {\n this._verify2(a, b);\n return this.imod(a.imul(b));\n };\n\n Red.prototype.mul = function mul (a, b) {\n this._verify2(a, b);\n return this.imod(a.mul(b));\n };\n\n Red.prototype.isqr = function isqr (a) {\n return this.imul(a, a.clone());\n };\n\n Red.prototype.sqr = function sqr (a) {\n return this.mul(a, a);\n };\n\n Red.prototype.sqrt = function sqrt (a) {\n if (a.isZero()) return a.clone();\n\n var mod3 = this.m.andln(3);\n assert(mod3 % 2 === 1);\n\n // Fast case\n if (mod3 === 3) {\n var pow = this.m.add(new BN(1)).iushrn(2);\n return this.pow(a, pow);\n }\n\n // Tonelli-Shanks algorithm (Totally unoptimized and slow)\n //\n // Find Q and S, that Q * 2 ^ S = (P - 1)\n var q = this.m.subn(1);\n var s = 0;\n while (!q.isZero() && q.andln(1) === 0) {\n s++;\n q.iushrn(1);\n }\n assert(!q.isZero());\n\n var one = new BN(1).toRed(this);\n var nOne = one.redNeg();\n\n // Find quadratic non-residue\n // NOTE: Max is such because of generalized Riemann hypothesis.\n var lpow = this.m.subn(1).iushrn(1);\n var z = this.m.bitLength();\n z = new BN(2 * z * z).toRed(this);\n\n while (this.pow(z, lpow).cmp(nOne) !== 0) {\n z.redIAdd(nOne);\n }\n\n var c = this.pow(z, q);\n var r = this.pow(a, q.addn(1).iushrn(1));\n var t = this.pow(a, q);\n var m = s;\n while (t.cmp(one) !== 0) {\n var tmp = t;\n for (var i = 0; tmp.cmp(one) !== 0; i++) {\n tmp = tmp.redSqr();\n }\n assert(i < m);\n var b = this.pow(c, new BN(1).iushln(m - i - 1));\n\n r = r.redMul(b);\n c = b.redSqr();\n t = t.redMul(c);\n m = i;\n }\n\n return r;\n };\n\n Red.prototype.invm = function invm (a) {\n var inv = a._invmp(this.m);\n if (inv.negative !== 0) {\n inv.negative = 0;\n return this.imod(inv).redNeg();\n } else {\n return this.imod(inv);\n }\n };\n\n Red.prototype.pow = function pow (a, num) {\n if (num.isZero()) return new BN(1).toRed(this);\n if (num.cmpn(1) === 0) return a.clone();\n\n var windowSize = 4;\n var wnd = new Array(1 << windowSize);\n wnd[0] = new BN(1).toRed(this);\n wnd[1] = a;\n for (var i = 2; i < wnd.length; i++) {\n wnd[i] = this.mul(wnd[i - 1], a);\n }\n\n var res = wnd[0];\n var current = 0;\n var currentLen = 0;\n var start = num.bitLength() % 26;\n if (start === 0) {\n start = 26;\n }\n\n for (i = num.length - 1; i >= 0; i--) {\n var word = num.words[i];\n for (var j = start - 1; j >= 0; j--) {\n var bit = (word >> j) & 1;\n if (res !== wnd[0]) {\n res = this.sqr(res);\n }\n\n if (bit === 0 && current === 0) {\n currentLen = 0;\n continue;\n }\n\n current <<= 1;\n current |= bit;\n currentLen++;\n if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue;\n\n res = this.mul(res, wnd[current]);\n currentLen = 0;\n current = 0;\n }\n start = 26;\n }\n\n return res;\n };\n\n Red.prototype.convertTo = function convertTo (num) {\n var r = num.umod(this.m);\n\n return r === num ? r.clone() : r;\n };\n\n Red.prototype.convertFrom = function convertFrom (num) {\n var res = num.clone();\n res.red = null;\n return res;\n };\n\n //\n // Montgomery method engine\n //\n\n BN.mont = function mont (num) {\n return new Mont(num);\n };\n\n function Mont (m) {\n Red.call(this, m);\n\n this.shift = this.m.bitLength();\n if (this.shift % 26 !== 0) {\n this.shift += 26 - (this.shift % 26);\n }\n\n this.r = new BN(1).iushln(this.shift);\n this.r2 = this.imod(this.r.sqr());\n this.rinv = this.r._invmp(this.m);\n\n this.minv = this.rinv.mul(this.r).isubn(1).div(this.m);\n this.minv = this.minv.umod(this.r);\n this.minv = this.r.sub(this.minv);\n }\n inherits(Mont, Red);\n\n Mont.prototype.convertTo = function convertTo (num) {\n return this.imod(num.ushln(this.shift));\n };\n\n Mont.prototype.convertFrom = function convertFrom (num) {\n var r = this.imod(num.mul(this.rinv));\n r.red = null;\n return r;\n };\n\n Mont.prototype.imul = function imul (a, b) {\n if (a.isZero() || b.isZero()) {\n a.words[0] = 0;\n a.length = 1;\n return a;\n }\n\n var t = a.imul(b);\n var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);\n var u = t.isub(c).iushrn(this.shift);\n var res = u;\n\n if (u.cmp(this.m) >= 0) {\n res = u.isub(this.m);\n } else if (u.cmpn(0) < 0) {\n res = u.iadd(this.m);\n }\n\n return res._forceRed(this);\n };\n\n Mont.prototype.mul = function mul (a, b) {\n if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this);\n\n var t = a.mul(b);\n var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);\n var u = t.isub(c).iushrn(this.shift);\n var res = u;\n if (u.cmp(this.m) >= 0) {\n res = u.isub(this.m);\n } else if (u.cmpn(0) < 0) {\n res = u.iadd(this.m);\n }\n\n return res._forceRed(this);\n };\n\n Mont.prototype.invm = function invm (a) {\n // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R\n var res = this.imod(a._invmp(this.m).mul(this.r2));\n return res._forceRed(this);\n };\n})(typeof module === 'undefined' || module, this);\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nmodule.exports = isObjectLike;\n","'use strict';\n\nvar hasOwn = Object.prototype.hasOwnProperty;\nvar toStr = Object.prototype.toString;\nvar defineProperty = Object.defineProperty;\nvar gOPD = Object.getOwnPropertyDescriptor;\n\nvar isArray = function isArray(arr) {\n\tif (typeof Array.isArray === 'function') {\n\t\treturn Array.isArray(arr);\n\t}\n\n\treturn toStr.call(arr) === '[object Array]';\n};\n\nvar isPlainObject = function isPlainObject(obj) {\n\tif (!obj || toStr.call(obj) !== '[object Object]') {\n\t\treturn false;\n\t}\n\n\tvar hasOwnConstructor = hasOwn.call(obj, 'constructor');\n\tvar hasIsPrototypeOf = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf');\n\t// Not own constructor property must be Object\n\tif (obj.constructor && !hasOwnConstructor && !hasIsPrototypeOf) {\n\t\treturn false;\n\t}\n\n\t// Own properties are enumerated firstly, so to speed up,\n\t// if last one is own, then all properties are own.\n\tvar key;\n\tfor (key in obj) { /**/ }\n\n\treturn typeof key === 'undefined' || hasOwn.call(obj, key);\n};\n\n// If name is '__proto__', and Object.defineProperty is available, define __proto__ as an own property on target\nvar setProperty = function setProperty(target, options) {\n\tif (defineProperty && options.name === '__proto__') {\n\t\tdefineProperty(target, options.name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\t\t\tvalue: options.newValue,\n\t\t\twritable: true\n\t\t});\n\t} else {\n\t\ttarget[options.name] = options.newValue;\n\t}\n};\n\n// Return undefined instead of __proto__ if '__proto__' is not an own property\nvar getProperty = function getProperty(obj, name) {\n\tif (name === '__proto__') {\n\t\tif (!hasOwn.call(obj, name)) {\n\t\t\treturn void 0;\n\t\t} else if (gOPD) {\n\t\t\t// In early versions of node, obj['__proto__'] is buggy when obj has\n\t\t\t// __proto__ as an own property. Object.getOwnPropertyDescriptor() works.\n\t\t\treturn gOPD(obj, name).value;\n\t\t}\n\t}\n\n\treturn obj[name];\n};\n\nmodule.exports = function extend() {\n\tvar options, name, src, copy, copyIsArray, clone;\n\tvar target = arguments[0];\n\tvar i = 1;\n\tvar length = arguments.length;\n\tvar deep = false;\n\n\t// Handle a deep copy situation\n\tif (typeof target === 'boolean') {\n\t\tdeep = target;\n\t\ttarget = arguments[1] || {};\n\t\t// skip the boolean and the target\n\t\ti = 2;\n\t}\n\tif (target == null || (typeof target !== 'object' && typeof target !== 'function')) {\n\t\ttarget = {};\n\t}\n\n\tfor (; i < length; ++i) {\n\t\toptions = arguments[i];\n\t\t// Only deal with non-null/undefined values\n\t\tif (options != null) {\n\t\t\t// Extend the base object\n\t\t\tfor (name in options) {\n\t\t\t\tsrc = getProperty(target, name);\n\t\t\t\tcopy = getProperty(options, name);\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif (target !== copy) {\n\t\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\t\tif (deep && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {\n\t\t\t\t\t\tif (copyIsArray) {\n\t\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\t\tclone = src && isArray(src) ? src : [];\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tclone = src && isPlainObject(src) ? src : {};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\t\tsetProperty(target, { name: name, newValue: extend(deep, clone, copy) });\n\n\t\t\t\t\t// Don't bring in undefined values\n\t\t\t\t\t} else if (typeof copy !== 'undefined') {\n\t\t\t\t\t\tsetProperty(target, { name: name, newValue: copy });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n","/*! https://mths.be/punycode v1.4.1 by @mathias */\n;(function(root) {\n\n\t/** Detect free variables */\n\tvar freeExports = typeof exports == 'object' && exports &&\n\t\t!exports.nodeType && exports;\n\tvar freeModule = typeof module == 'object' && module &&\n\t\t!module.nodeType && module;\n\tvar freeGlobal = typeof global == 'object' && global;\n\tif (\n\t\tfreeGlobal.global === freeGlobal ||\n\t\tfreeGlobal.window === freeGlobal ||\n\t\tfreeGlobal.self === freeGlobal\n\t) {\n\t\troot = freeGlobal;\n\t}\n\n\t/**\n\t * The `punycode` object.\n\t * @name punycode\n\t * @type Object\n\t */\n\tvar punycode,\n\n\t/** Highest positive signed 32-bit float value */\n\tmaxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1\n\n\t/** Bootstring parameters */\n\tbase = 36,\n\ttMin = 1,\n\ttMax = 26,\n\tskew = 38,\n\tdamp = 700,\n\tinitialBias = 72,\n\tinitialN = 128, // 0x80\n\tdelimiter = '-', // '\\x2D'\n\n\t/** Regular expressions */\n\tregexPunycode = /^xn--/,\n\tregexNonASCII = /[^\\x20-\\x7E]/, // unprintable ASCII chars + non-ASCII chars\n\tregexSeparators = /[\\x2E\\u3002\\uFF0E\\uFF61]/g, // RFC 3490 separators\n\n\t/** Error messages */\n\terrors = {\n\t\t'overflow': 'Overflow: input needs wider integers to process',\n\t\t'not-basic': 'Illegal input >= 0x80 (not a basic code point)',\n\t\t'invalid-input': 'Invalid input'\n\t},\n\n\t/** Convenience shortcuts */\n\tbaseMinusTMin = base - tMin,\n\tfloor = Math.floor,\n\tstringFromCharCode = String.fromCharCode,\n\n\t/** Temporary variable */\n\tkey;\n\n\t/*--------------------------------------------------------------------------*/\n\n\t/**\n\t * A generic error utility function.\n\t * @private\n\t * @param {String} type The error type.\n\t * @returns {Error} Throws a `RangeError` with the applicable error message.\n\t */\n\tfunction error(type) {\n\t\tthrow new RangeError(errors[type]);\n\t}\n\n\t/**\n\t * A generic `Array#map` utility function.\n\t * @private\n\t * @param {Array} array The array to iterate over.\n\t * @param {Function} callback The function that gets called for every array\n\t * item.\n\t * @returns {Array} A new array of values returned by the callback function.\n\t */\n\tfunction map(array, fn) {\n\t\tvar length = array.length;\n\t\tvar result = [];\n\t\twhile (length--) {\n\t\t\tresult[length] = fn(array[length]);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * A simple `Array#map`-like wrapper to work with domain name strings or email\n\t * addresses.\n\t * @private\n\t * @param {String} domain The domain name or email address.\n\t * @param {Function} callback The function that gets called for every\n\t * character.\n\t * @returns {Array} A new string of characters returned by the callback\n\t * function.\n\t */\n\tfunction mapDomain(string, fn) {\n\t\tvar parts = string.split('@');\n\t\tvar result = '';\n\t\tif (parts.length > 1) {\n\t\t\t// In email addresses, only the domain name should be punycoded. Leave\n\t\t\t// the local part (i.e. everything up to `@`) intact.\n\t\t\tresult = parts[0] + '@';\n\t\t\tstring = parts[1];\n\t\t}\n\t\t// Avoid `split(regex)` for IE8 compatibility. See #17.\n\t\tstring = string.replace(regexSeparators, '\\x2E');\n\t\tvar labels = string.split('.');\n\t\tvar encoded = map(labels, fn).join('.');\n\t\treturn result + encoded;\n\t}\n\n\t/**\n\t * Creates an array containing the numeric code points of each Unicode\n\t * character in the string. While JavaScript uses UCS-2 internally,\n\t * this function will convert a pair of surrogate halves (each of which\n\t * UCS-2 exposes as separate characters) into a single code point,\n\t * matching UTF-16.\n\t * @see `punycode.ucs2.encode`\n\t * @see \n\t * @memberOf punycode.ucs2\n\t * @name decode\n\t * @param {String} string The Unicode input string (UCS-2).\n\t * @returns {Array} The new array of code points.\n\t */\n\tfunction ucs2decode(string) {\n\t\tvar output = [],\n\t\t counter = 0,\n\t\t length = string.length,\n\t\t value,\n\t\t extra;\n\t\twhile (counter < length) {\n\t\t\tvalue = string.charCodeAt(counter++);\n\t\t\tif (value >= 0xD800 && value <= 0xDBFF && counter < length) {\n\t\t\t\t// high surrogate, and there is a next character\n\t\t\t\textra = string.charCodeAt(counter++);\n\t\t\t\tif ((extra & 0xFC00) == 0xDC00) { // low surrogate\n\t\t\t\t\toutput.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);\n\t\t\t\t} else {\n\t\t\t\t\t// unmatched surrogate; only append this code unit, in case the next\n\t\t\t\t\t// code unit is the high surrogate of a surrogate pair\n\t\t\t\t\toutput.push(value);\n\t\t\t\t\tcounter--;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\toutput.push(value);\n\t\t\t}\n\t\t}\n\t\treturn output;\n\t}\n\n\t/**\n\t * Creates a string based on an array of numeric code points.\n\t * @see `punycode.ucs2.decode`\n\t * @memberOf punycode.ucs2\n\t * @name encode\n\t * @param {Array} codePoints The array of numeric code points.\n\t * @returns {String} The new Unicode string (UCS-2).\n\t */\n\tfunction ucs2encode(array) {\n\t\treturn map(array, function(value) {\n\t\t\tvar output = '';\n\t\t\tif (value > 0xFFFF) {\n\t\t\t\tvalue -= 0x10000;\n\t\t\t\toutput += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);\n\t\t\t\tvalue = 0xDC00 | value & 0x3FF;\n\t\t\t}\n\t\t\toutput += stringFromCharCode(value);\n\t\t\treturn output;\n\t\t}).join('');\n\t}\n\n\t/**\n\t * Converts a basic code point into a digit/integer.\n\t * @see `digitToBasic()`\n\t * @private\n\t * @param {Number} codePoint The basic numeric code point value.\n\t * @returns {Number} The numeric value of a basic code point (for use in\n\t * representing integers) in the range `0` to `base - 1`, or `base` if\n\t * the code point does not represent a value.\n\t */\n\tfunction basicToDigit(codePoint) {\n\t\tif (codePoint - 48 < 10) {\n\t\t\treturn codePoint - 22;\n\t\t}\n\t\tif (codePoint - 65 < 26) {\n\t\t\treturn codePoint - 65;\n\t\t}\n\t\tif (codePoint - 97 < 26) {\n\t\t\treturn codePoint - 97;\n\t\t}\n\t\treturn base;\n\t}\n\n\t/**\n\t * Converts a digit/integer into a basic code point.\n\t * @see `basicToDigit()`\n\t * @private\n\t * @param {Number} digit The numeric value of a basic code point.\n\t * @returns {Number} The basic code point whose value (when used for\n\t * representing integers) is `digit`, which needs to be in the range\n\t * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is\n\t * used; else, the lowercase form is used. The behavior is undefined\n\t * if `flag` is non-zero and `digit` has no uppercase form.\n\t */\n\tfunction digitToBasic(digit, flag) {\n\t\t// 0..25 map to ASCII a..z or A..Z\n\t\t// 26..35 map to ASCII 0..9\n\t\treturn digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);\n\t}\n\n\t/**\n\t * Bias adaptation function as per section 3.4 of RFC 3492.\n\t * https://tools.ietf.org/html/rfc3492#section-3.4\n\t * @private\n\t */\n\tfunction adapt(delta, numPoints, firstTime) {\n\t\tvar k = 0;\n\t\tdelta = firstTime ? floor(delta / damp) : delta >> 1;\n\t\tdelta += floor(delta / numPoints);\n\t\tfor (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {\n\t\t\tdelta = floor(delta / baseMinusTMin);\n\t\t}\n\t\treturn floor(k + (baseMinusTMin + 1) * delta / (delta + skew));\n\t}\n\n\t/**\n\t * Converts a Punycode string of ASCII-only symbols to a string of Unicode\n\t * symbols.\n\t * @memberOf punycode\n\t * @param {String} input The Punycode string of ASCII-only symbols.\n\t * @returns {String} The resulting string of Unicode symbols.\n\t */\n\tfunction decode(input) {\n\t\t// Don't use UCS-2\n\t\tvar output = [],\n\t\t inputLength = input.length,\n\t\t out,\n\t\t i = 0,\n\t\t n = initialN,\n\t\t bias = initialBias,\n\t\t basic,\n\t\t j,\n\t\t index,\n\t\t oldi,\n\t\t w,\n\t\t k,\n\t\t digit,\n\t\t t,\n\t\t /** Cached calculation results */\n\t\t baseMinusT;\n\n\t\t// Handle the basic code points: let `basic` be the number of input code\n\t\t// points before the last delimiter, or `0` if there is none, then copy\n\t\t// the first basic code points to the output.\n\n\t\tbasic = input.lastIndexOf(delimiter);\n\t\tif (basic < 0) {\n\t\t\tbasic = 0;\n\t\t}\n\n\t\tfor (j = 0; j < basic; ++j) {\n\t\t\t// if it's not a basic code point\n\t\t\tif (input.charCodeAt(j) >= 0x80) {\n\t\t\t\terror('not-basic');\n\t\t\t}\n\t\t\toutput.push(input.charCodeAt(j));\n\t\t}\n\n\t\t// Main decoding loop: start just after the last delimiter if any basic code\n\t\t// points were copied; start at the beginning otherwise.\n\n\t\tfor (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {\n\n\t\t\t// `index` is the index of the next character to be consumed.\n\t\t\t// Decode a generalized variable-length integer into `delta`,\n\t\t\t// which gets added to `i`. The overflow checking is easier\n\t\t\t// if we increase `i` as we go, then subtract off its starting\n\t\t\t// value at the end to obtain `delta`.\n\t\t\tfor (oldi = i, w = 1, k = base; /* no condition */; k += base) {\n\n\t\t\t\tif (index >= inputLength) {\n\t\t\t\t\terror('invalid-input');\n\t\t\t\t}\n\n\t\t\t\tdigit = basicToDigit(input.charCodeAt(index++));\n\n\t\t\t\tif (digit >= base || digit > floor((maxInt - i) / w)) {\n\t\t\t\t\terror('overflow');\n\t\t\t\t}\n\n\t\t\t\ti += digit * w;\n\t\t\t\tt = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);\n\n\t\t\t\tif (digit < t) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tbaseMinusT = base - t;\n\t\t\t\tif (w > floor(maxInt / baseMinusT)) {\n\t\t\t\t\terror('overflow');\n\t\t\t\t}\n\n\t\t\t\tw *= baseMinusT;\n\n\t\t\t}\n\n\t\t\tout = output.length + 1;\n\t\t\tbias = adapt(i - oldi, out, oldi == 0);\n\n\t\t\t// `i` was supposed to wrap around from `out` to `0`,\n\t\t\t// incrementing `n` each time, so we'll fix that now:\n\t\t\tif (floor(i / out) > maxInt - n) {\n\t\t\t\terror('overflow');\n\t\t\t}\n\n\t\t\tn += floor(i / out);\n\t\t\ti %= out;\n\n\t\t\t// Insert `n` at position `i` of the output\n\t\t\toutput.splice(i++, 0, n);\n\n\t\t}\n\n\t\treturn ucs2encode(output);\n\t}\n\n\t/**\n\t * Converts a string of Unicode symbols (e.g. a domain name label) to a\n\t * Punycode string of ASCII-only symbols.\n\t * @memberOf punycode\n\t * @param {String} input The string of Unicode symbols.\n\t * @returns {String} The resulting Punycode string of ASCII-only symbols.\n\t */\n\tfunction encode(input) {\n\t\tvar n,\n\t\t delta,\n\t\t handledCPCount,\n\t\t basicLength,\n\t\t bias,\n\t\t j,\n\t\t m,\n\t\t q,\n\t\t k,\n\t\t t,\n\t\t currentValue,\n\t\t output = [],\n\t\t /** `inputLength` will hold the number of code points in `input`. */\n\t\t inputLength,\n\t\t /** Cached calculation results */\n\t\t handledCPCountPlusOne,\n\t\t baseMinusT,\n\t\t qMinusT;\n\n\t\t// Convert the input in UCS-2 to Unicode\n\t\tinput = ucs2decode(input);\n\n\t\t// Cache the length\n\t\tinputLength = input.length;\n\n\t\t// Initialize the state\n\t\tn = initialN;\n\t\tdelta = 0;\n\t\tbias = initialBias;\n\n\t\t// Handle the basic code points\n\t\tfor (j = 0; j < inputLength; ++j) {\n\t\t\tcurrentValue = input[j];\n\t\t\tif (currentValue < 0x80) {\n\t\t\t\toutput.push(stringFromCharCode(currentValue));\n\t\t\t}\n\t\t}\n\n\t\thandledCPCount = basicLength = output.length;\n\n\t\t// `handledCPCount` is the number of code points that have been handled;\n\t\t// `basicLength` is the number of basic code points.\n\n\t\t// Finish the basic string - if it is not empty - with a delimiter\n\t\tif (basicLength) {\n\t\t\toutput.push(delimiter);\n\t\t}\n\n\t\t// Main encoding loop:\n\t\twhile (handledCPCount < inputLength) {\n\n\t\t\t// All non-basic code points < n have been handled already. Find the next\n\t\t\t// larger one:\n\t\t\tfor (m = maxInt, j = 0; j < inputLength; ++j) {\n\t\t\t\tcurrentValue = input[j];\n\t\t\t\tif (currentValue >= n && currentValue < m) {\n\t\t\t\t\tm = currentValue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Increase `delta` enough to advance the decoder's state to ,\n\t\t\t// but guard against overflow\n\t\t\thandledCPCountPlusOne = handledCPCount + 1;\n\t\t\tif (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {\n\t\t\t\terror('overflow');\n\t\t\t}\n\n\t\t\tdelta += (m - n) * handledCPCountPlusOne;\n\t\t\tn = m;\n\n\t\t\tfor (j = 0; j < inputLength; ++j) {\n\t\t\t\tcurrentValue = input[j];\n\n\t\t\t\tif (currentValue < n && ++delta > maxInt) {\n\t\t\t\t\terror('overflow');\n\t\t\t\t}\n\n\t\t\t\tif (currentValue == n) {\n\t\t\t\t\t// Represent delta as a generalized variable-length integer\n\t\t\t\t\tfor (q = delta, k = base; /* no condition */; k += base) {\n\t\t\t\t\t\tt = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);\n\t\t\t\t\t\tif (q < t) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tqMinusT = q - t;\n\t\t\t\t\t\tbaseMinusT = base - t;\n\t\t\t\t\t\toutput.push(\n\t\t\t\t\t\t\tstringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))\n\t\t\t\t\t\t);\n\t\t\t\t\t\tq = floor(qMinusT / baseMinusT);\n\t\t\t\t\t}\n\n\t\t\t\t\toutput.push(stringFromCharCode(digitToBasic(q, 0)));\n\t\t\t\t\tbias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);\n\t\t\t\t\tdelta = 0;\n\t\t\t\t\t++handledCPCount;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t++delta;\n\t\t\t++n;\n\n\t\t}\n\t\treturn output.join('');\n\t}\n\n\t/**\n\t * Converts a Punycode string representing a domain name or an email address\n\t * to Unicode. Only the Punycoded parts of the input will be converted, i.e.\n\t * it doesn't matter if you call it on a string that has already been\n\t * converted to Unicode.\n\t * @memberOf punycode\n\t * @param {String} input The Punycoded domain name or email address to\n\t * convert to Unicode.\n\t * @returns {String} The Unicode representation of the given Punycode\n\t * string.\n\t */\n\tfunction toUnicode(input) {\n\t\treturn mapDomain(input, function(string) {\n\t\t\treturn regexPunycode.test(string)\n\t\t\t\t? decode(string.slice(4).toLowerCase())\n\t\t\t\t: string;\n\t\t});\n\t}\n\n\t/**\n\t * Converts a Unicode string representing a domain name or an email address to\n\t * Punycode. Only the non-ASCII parts of the domain name will be converted,\n\t * i.e. it doesn't matter if you call it with a domain that's already in\n\t * ASCII.\n\t * @memberOf punycode\n\t * @param {String} input The domain name or email address to convert, as a\n\t * Unicode string.\n\t * @returns {String} The Punycode representation of the given domain name or\n\t * email address.\n\t */\n\tfunction toASCII(input) {\n\t\treturn mapDomain(input, function(string) {\n\t\t\treturn regexNonASCII.test(string)\n\t\t\t\t? 'xn--' + encode(string)\n\t\t\t\t: string;\n\t\t});\n\t}\n\n\t/*--------------------------------------------------------------------------*/\n\n\t/** Define the public API */\n\tpunycode = {\n\t\t/**\n\t\t * A string representing the current Punycode.js version number.\n\t\t * @memberOf punycode\n\t\t * @type String\n\t\t */\n\t\t'version': '1.4.1',\n\t\t/**\n\t\t * An object of methods to convert from JavaScript's internal character\n\t\t * representation (UCS-2) to Unicode code points, and back.\n\t\t * @see \n\t\t * @memberOf punycode\n\t\t * @type Object\n\t\t */\n\t\t'ucs2': {\n\t\t\t'decode': ucs2decode,\n\t\t\t'encode': ucs2encode\n\t\t},\n\t\t'decode': decode,\n\t\t'encode': encode,\n\t\t'toASCII': toASCII,\n\t\t'toUnicode': toUnicode\n\t};\n\n\t/** Expose `punycode` */\n\t// Some AMD build optimizers, like r.js, check for specific condition patterns\n\t// like the following:\n\tif (\n\t\ttypeof define == 'function' &&\n\t\ttypeof define.amd == 'object' &&\n\t\tdefine.amd\n\t) {\n\t\tdefine('punycode', function() {\n\t\t\treturn punycode;\n\t\t});\n\t} else if (freeExports && freeModule) {\n\t\tif (module.exports == freeExports) {\n\t\t\t// in Node.js, io.js, or RingoJS v0.8.0+\n\t\t\tfreeModule.exports = punycode;\n\t\t} else {\n\t\t\t// in Narwhal or RingoJS v0.7.0-\n\t\t\tfor (key in punycode) {\n\t\t\t\tpunycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// in Rhino or a web browser\n\t\troot.punycode = punycode;\n\t}\n\n}(this));\n","'use strict'\n\nvar jsonSafeStringify = require('json-stringify-safe')\nvar crypto = require('crypto')\nvar Buffer = require('safe-buffer').Buffer\n\nvar defer = typeof setImmediate === 'undefined'\n ? process.nextTick\n : setImmediate\n\nfunction paramsHaveRequestBody (params) {\n return (\n params.body ||\n params.requestBodyStream ||\n (params.json && typeof params.json !== 'boolean') ||\n params.multipart\n )\n}\n\nfunction safeStringify (obj, replacer) {\n var ret\n try {\n ret = JSON.stringify(obj, replacer)\n } catch (e) {\n ret = jsonSafeStringify(obj, replacer)\n }\n return ret\n}\n\nfunction md5 (str) {\n return crypto.createHash('md5').update(str).digest('hex')\n}\n\nfunction isReadStream (rs) {\n return rs.readable && rs.path && rs.mode\n}\n\nfunction toBase64 (str) {\n return Buffer.from(str || '', 'utf8').toString('base64')\n}\n\nfunction copy (obj) {\n var o = {}\n Object.keys(obj).forEach(function (i) {\n o[i] = obj[i]\n })\n return o\n}\n\nfunction version () {\n var numbers = process.version.replace('v', '').split('.')\n return {\n major: parseInt(numbers[0], 10),\n minor: parseInt(numbers[1], 10),\n patch: parseInt(numbers[2], 10)\n }\n}\n\nexports.paramsHaveRequestBody = paramsHaveRequestBody\nexports.safeStringify = safeStringify\nexports.md5 = md5\nexports.isReadStream = isReadStream\nexports.toBase64 = toBase64\nexports.copy = copy\nexports.version = version\nexports.defer = defer\n","// Copyright 2015 Joyent, Inc.\n\nvar Key = require('./key');\nvar Fingerprint = require('./fingerprint');\nvar Signature = require('./signature');\nvar PrivateKey = require('./private-key');\nvar Certificate = require('./certificate');\nvar Identity = require('./identity');\nvar errs = require('./errors');\n\nmodule.exports = {\n\t/* top-level classes */\n\tKey: Key,\n\tparseKey: Key.parse,\n\tFingerprint: Fingerprint,\n\tparseFingerprint: Fingerprint.parse,\n\tSignature: Signature,\n\tparseSignature: Signature.parse,\n\tPrivateKey: PrivateKey,\n\tparsePrivateKey: PrivateKey.parse,\n\tgeneratePrivateKey: PrivateKey.generate,\n\tCertificate: Certificate,\n\tparseCertificate: Certificate.parse,\n\tcreateSelfSignedCertificate: Certificate.createSelfSigned,\n\tcreateCertificate: Certificate.create,\n\tIdentity: Identity,\n\tidentityFromDN: Identity.parseDN,\n\tidentityForHost: Identity.forHost,\n\tidentityForUser: Identity.forUser,\n\tidentityForEmail: Identity.forEmail,\n\tidentityFromArray: Identity.fromArray,\n\n\t/* errors */\n\tFingerprintFormatError: errs.FingerprintFormatError,\n\tInvalidAlgorithmError: errs.InvalidAlgorithmError,\n\tKeyParseError: errs.KeyParseError,\n\tSignatureParseError: errs.SignatureParseError,\n\tKeyEncryptedError: errs.KeyEncryptedError,\n\tCertificateParseError: errs.CertificateParseError\n};\n","// Copyright 2017 Joyent, Inc.\n\nmodule.exports = {\n\tDiffieHellman: DiffieHellman,\n\tgenerateECDSA: generateECDSA,\n\tgenerateED25519: generateED25519\n};\n\nvar assert = require('assert-plus');\nvar crypto = require('crypto');\nvar Buffer = require('safer-buffer').Buffer;\nvar algs = require('./algs');\nvar utils = require('./utils');\nvar nacl = require('tweetnacl');\n\nvar Key = require('./key');\nvar PrivateKey = require('./private-key');\n\nvar CRYPTO_HAVE_ECDH = (crypto.createECDH !== undefined);\n\nvar ecdh = require('ecc-jsbn');\nvar ec = require('ecc-jsbn/lib/ec');\nvar jsbn = require('jsbn').BigInteger;\n\nfunction DiffieHellman(key) {\n\tutils.assertCompatible(key, Key, [1, 4], 'key');\n\tthis._isPriv = PrivateKey.isPrivateKey(key, [1, 3]);\n\tthis._algo = key.type;\n\tthis._curve = key.curve;\n\tthis._key = key;\n\tif (key.type === 'dsa') {\n\t\tif (!CRYPTO_HAVE_ECDH) {\n\t\t\tthrow (new Error('Due to bugs in the node 0.10 ' +\n\t\t\t 'crypto API, node 0.12.x or later is required ' +\n\t\t\t 'to use DH'));\n\t\t}\n\t\tthis._dh = crypto.createDiffieHellman(\n\t\t key.part.p.data, undefined,\n\t\t key.part.g.data, undefined);\n\t\tthis._p = key.part.p;\n\t\tthis._g = key.part.g;\n\t\tif (this._isPriv)\n\t\t\tthis._dh.setPrivateKey(key.part.x.data);\n\t\tthis._dh.setPublicKey(key.part.y.data);\n\n\t} else if (key.type === 'ecdsa') {\n\t\tif (!CRYPTO_HAVE_ECDH) {\n\t\t\tthis._ecParams = new X9ECParameters(this._curve);\n\n\t\t\tif (this._isPriv) {\n\t\t\t\tthis._priv = new ECPrivate(\n\t\t\t\t this._ecParams, key.part.d.data);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tvar curve = {\n\t\t\t'nistp256': 'prime256v1',\n\t\t\t'nistp384': 'secp384r1',\n\t\t\t'nistp521': 'secp521r1'\n\t\t}[key.curve];\n\t\tthis._dh = crypto.createECDH(curve);\n\t\tif (typeof (this._dh) !== 'object' ||\n\t\t typeof (this._dh.setPrivateKey) !== 'function') {\n\t\t\tCRYPTO_HAVE_ECDH = false;\n\t\t\tDiffieHellman.call(this, key);\n\t\t\treturn;\n\t\t}\n\t\tif (this._isPriv)\n\t\t\tthis._dh.setPrivateKey(key.part.d.data);\n\t\tthis._dh.setPublicKey(key.part.Q.data);\n\n\t} else if (key.type === 'curve25519') {\n\t\tif (this._isPriv) {\n\t\t\tutils.assertCompatible(key, PrivateKey, [1, 5], 'key');\n\t\t\tthis._priv = key.part.k.data;\n\t\t}\n\n\t} else {\n\t\tthrow (new Error('DH not supported for ' + key.type + ' keys'));\n\t}\n}\n\nDiffieHellman.prototype.getPublicKey = function () {\n\tif (this._isPriv)\n\t\treturn (this._key.toPublic());\n\treturn (this._key);\n};\n\nDiffieHellman.prototype.getPrivateKey = function () {\n\tif (this._isPriv)\n\t\treturn (this._key);\n\telse\n\t\treturn (undefined);\n};\nDiffieHellman.prototype.getKey = DiffieHellman.prototype.getPrivateKey;\n\nDiffieHellman.prototype._keyCheck = function (pk, isPub) {\n\tassert.object(pk, 'key');\n\tif (!isPub)\n\t\tutils.assertCompatible(pk, PrivateKey, [1, 3], 'key');\n\tutils.assertCompatible(pk, Key, [1, 4], 'key');\n\n\tif (pk.type !== this._algo) {\n\t\tthrow (new Error('A ' + pk.type + ' key cannot be used in ' +\n\t\t this._algo + ' Diffie-Hellman'));\n\t}\n\n\tif (pk.curve !== this._curve) {\n\t\tthrow (new Error('A key from the ' + pk.curve + ' curve ' +\n\t\t 'cannot be used with a ' + this._curve +\n\t\t ' Diffie-Hellman'));\n\t}\n\n\tif (pk.type === 'dsa') {\n\t\tassert.deepEqual(pk.part.p, this._p,\n\t\t 'DSA key prime does not match');\n\t\tassert.deepEqual(pk.part.g, this._g,\n\t\t 'DSA key generator does not match');\n\t}\n};\n\nDiffieHellman.prototype.setKey = function (pk) {\n\tthis._keyCheck(pk);\n\n\tif (pk.type === 'dsa') {\n\t\tthis._dh.setPrivateKey(pk.part.x.data);\n\t\tthis._dh.setPublicKey(pk.part.y.data);\n\n\t} else if (pk.type === 'ecdsa') {\n\t\tif (CRYPTO_HAVE_ECDH) {\n\t\t\tthis._dh.setPrivateKey(pk.part.d.data);\n\t\t\tthis._dh.setPublicKey(pk.part.Q.data);\n\t\t} else {\n\t\t\tthis._priv = new ECPrivate(\n\t\t\t this._ecParams, pk.part.d.data);\n\t\t}\n\n\t} else if (pk.type === 'curve25519') {\n\t\tvar k = pk.part.k;\n\t\tif (!pk.part.k)\n\t\t\tk = pk.part.r;\n\t\tthis._priv = k.data;\n\t\tif (this._priv[0] === 0x00)\n\t\t\tthis._priv = this._priv.slice(1);\n\t\tthis._priv = this._priv.slice(0, 32);\n\t}\n\tthis._key = pk;\n\tthis._isPriv = true;\n};\nDiffieHellman.prototype.setPrivateKey = DiffieHellman.prototype.setKey;\n\nDiffieHellman.prototype.computeSecret = function (otherpk) {\n\tthis._keyCheck(otherpk, true);\n\tif (!this._isPriv)\n\t\tthrow (new Error('DH exchange has not been initialized with ' +\n\t\t 'a private key yet'));\n\n\tvar pub;\n\tif (this._algo === 'dsa') {\n\t\treturn (this._dh.computeSecret(\n\t\t otherpk.part.y.data));\n\n\t} else if (this._algo === 'ecdsa') {\n\t\tif (CRYPTO_HAVE_ECDH) {\n\t\t\treturn (this._dh.computeSecret(\n\t\t\t otherpk.part.Q.data));\n\t\t} else {\n\t\t\tpub = new ECPublic(\n\t\t\t this._ecParams, otherpk.part.Q.data);\n\t\t\treturn (this._priv.deriveSharedSecret(pub));\n\t\t}\n\n\t} else if (this._algo === 'curve25519') {\n\t\tpub = otherpk.part.A.data;\n\t\twhile (pub[0] === 0x00 && pub.length > 32)\n\t\t\tpub = pub.slice(1);\n\t\tvar priv = this._priv;\n\t\tassert.strictEqual(pub.length, 32);\n\t\tassert.strictEqual(priv.length, 32);\n\n\t\tvar secret = nacl.box.before(new Uint8Array(pub),\n\t\t new Uint8Array(priv));\n\n\t\treturn (Buffer.from(secret));\n\t}\n\n\tthrow (new Error('Invalid algorithm: ' + this._algo));\n};\n\nDiffieHellman.prototype.generateKey = function () {\n\tvar parts = [];\n\tvar priv, pub;\n\tif (this._algo === 'dsa') {\n\t\tthis._dh.generateKeys();\n\n\t\tparts.push({name: 'p', data: this._p.data});\n\t\tparts.push({name: 'q', data: this._key.part.q.data});\n\t\tparts.push({name: 'g', data: this._g.data});\n\t\tparts.push({name: 'y', data: this._dh.getPublicKey()});\n\t\tparts.push({name: 'x', data: this._dh.getPrivateKey()});\n\t\tthis._key = new PrivateKey({\n\t\t\ttype: 'dsa',\n\t\t\tparts: parts\n\t\t});\n\t\tthis._isPriv = true;\n\t\treturn (this._key);\n\n\t} else if (this._algo === 'ecdsa') {\n\t\tif (CRYPTO_HAVE_ECDH) {\n\t\t\tthis._dh.generateKeys();\n\n\t\t\tparts.push({name: 'curve',\n\t\t\t data: Buffer.from(this._curve)});\n\t\t\tparts.push({name: 'Q', data: this._dh.getPublicKey()});\n\t\t\tparts.push({name: 'd', data: this._dh.getPrivateKey()});\n\t\t\tthis._key = new PrivateKey({\n\t\t\t\ttype: 'ecdsa',\n\t\t\t\tcurve: this._curve,\n\t\t\t\tparts: parts\n\t\t\t});\n\t\t\tthis._isPriv = true;\n\t\t\treturn (this._key);\n\n\t\t} else {\n\t\t\tvar n = this._ecParams.getN();\n\t\t\tvar r = new jsbn(crypto.randomBytes(n.bitLength()));\n\t\t\tvar n1 = n.subtract(jsbn.ONE);\n\t\t\tpriv = r.mod(n1).add(jsbn.ONE);\n\t\t\tpub = this._ecParams.getG().multiply(priv);\n\n\t\t\tpriv = Buffer.from(priv.toByteArray());\n\t\t\tpub = Buffer.from(this._ecParams.getCurve().\n\t\t\t encodePointHex(pub), 'hex');\n\n\t\t\tthis._priv = new ECPrivate(this._ecParams, priv);\n\n\t\t\tparts.push({name: 'curve',\n\t\t\t data: Buffer.from(this._curve)});\n\t\t\tparts.push({name: 'Q', data: pub});\n\t\t\tparts.push({name: 'd', data: priv});\n\n\t\t\tthis._key = new PrivateKey({\n\t\t\t\ttype: 'ecdsa',\n\t\t\t\tcurve: this._curve,\n\t\t\t\tparts: parts\n\t\t\t});\n\t\t\tthis._isPriv = true;\n\t\t\treturn (this._key);\n\t\t}\n\n\t} else if (this._algo === 'curve25519') {\n\t\tvar pair = nacl.box.keyPair();\n\t\tpriv = Buffer.from(pair.secretKey);\n\t\tpub = Buffer.from(pair.publicKey);\n\t\tpriv = Buffer.concat([priv, pub]);\n\t\tassert.strictEqual(priv.length, 64);\n\t\tassert.strictEqual(pub.length, 32);\n\n\t\tparts.push({name: 'A', data: pub});\n\t\tparts.push({name: 'k', data: priv});\n\t\tthis._key = new PrivateKey({\n\t\t\ttype: 'curve25519',\n\t\t\tparts: parts\n\t\t});\n\t\tthis._isPriv = true;\n\t\treturn (this._key);\n\t}\n\n\tthrow (new Error('Invalid algorithm: ' + this._algo));\n};\nDiffieHellman.prototype.generateKeys = DiffieHellman.prototype.generateKey;\n\n/* These are helpers for using ecc-jsbn (for node 0.10 compatibility). */\n\nfunction X9ECParameters(name) {\n\tvar params = algs.curves[name];\n\tassert.object(params);\n\n\tvar p = new jsbn(params.p);\n\tvar a = new jsbn(params.a);\n\tvar b = new jsbn(params.b);\n\tvar n = new jsbn(params.n);\n\tvar h = jsbn.ONE;\n\tvar curve = new ec.ECCurveFp(p, a, b);\n\tvar G = curve.decodePointHex(params.G.toString('hex'));\n\n\tthis.curve = curve;\n\tthis.g = G;\n\tthis.n = n;\n\tthis.h = h;\n}\nX9ECParameters.prototype.getCurve = function () { return (this.curve); };\nX9ECParameters.prototype.getG = function () { return (this.g); };\nX9ECParameters.prototype.getN = function () { return (this.n); };\nX9ECParameters.prototype.getH = function () { return (this.h); };\n\nfunction ECPublic(params, buffer) {\n\tthis._params = params;\n\tif (buffer[0] === 0x00)\n\t\tbuffer = buffer.slice(1);\n\tthis._pub = params.getCurve().decodePointHex(buffer.toString('hex'));\n}\n\nfunction ECPrivate(params, buffer) {\n\tthis._params = params;\n\tthis._priv = new jsbn(utils.mpNormalize(buffer));\n}\nECPrivate.prototype.deriveSharedSecret = function (pubKey) {\n\tassert.ok(pubKey instanceof ECPublic);\n\tvar S = pubKey._pub.multiply(this._priv);\n\treturn (Buffer.from(S.getX().toBigInteger().toByteArray()));\n};\n\nfunction generateED25519() {\n\tvar pair = nacl.sign.keyPair();\n\tvar priv = Buffer.from(pair.secretKey);\n\tvar pub = Buffer.from(pair.publicKey);\n\tassert.strictEqual(priv.length, 64);\n\tassert.strictEqual(pub.length, 32);\n\n\tvar parts = [];\n\tparts.push({name: 'A', data: pub});\n\tparts.push({name: 'k', data: priv.slice(0, 32)});\n\tvar key = new PrivateKey({\n\t\ttype: 'ed25519',\n\t\tparts: parts\n\t});\n\treturn (key);\n}\n\n/* Generates a new ECDSA private key on a given curve. */\nfunction generateECDSA(curve) {\n\tvar parts = [];\n\tvar key;\n\n\tif (CRYPTO_HAVE_ECDH) {\n\t\t/*\n\t\t * Node crypto doesn't expose key generation directly, but the\n\t\t * ECDH instances can generate keys. It turns out this just\n\t\t * calls into the OpenSSL generic key generator, and we can\n\t\t * read its output happily without doing an actual DH. So we\n\t\t * use that here.\n\t\t */\n\t\tvar osCurve = {\n\t\t\t'nistp256': 'prime256v1',\n\t\t\t'nistp384': 'secp384r1',\n\t\t\t'nistp521': 'secp521r1'\n\t\t}[curve];\n\n\t\tvar dh = crypto.createECDH(osCurve);\n\t\tdh.generateKeys();\n\n\t\tparts.push({name: 'curve',\n\t\t data: Buffer.from(curve)});\n\t\tparts.push({name: 'Q', data: dh.getPublicKey()});\n\t\tparts.push({name: 'd', data: dh.getPrivateKey()});\n\n\t\tkey = new PrivateKey({\n\t\t\ttype: 'ecdsa',\n\t\t\tcurve: curve,\n\t\t\tparts: parts\n\t\t});\n\t\treturn (key);\n\t} else {\n\n\t\tvar ecParams = new X9ECParameters(curve);\n\n\t\t/* This algorithm taken from FIPS PUB 186-4 (section B.4.1) */\n\t\tvar n = ecParams.getN();\n\t\t/*\n\t\t * The crypto.randomBytes() function can only give us whole\n\t\t * bytes, so taking a nod from X9.62, we round up.\n\t\t */\n\t\tvar cByteLen = Math.ceil((n.bitLength() + 64) / 8);\n\t\tvar c = new jsbn(crypto.randomBytes(cByteLen));\n\n\t\tvar n1 = n.subtract(jsbn.ONE);\n\t\tvar priv = c.mod(n1).add(jsbn.ONE);\n\t\tvar pub = ecParams.getG().multiply(priv);\n\n\t\tpriv = Buffer.from(priv.toByteArray());\n\t\tpub = Buffer.from(ecParams.getCurve().\n\t\t encodePointHex(pub), 'hex');\n\n\t\tparts.push({name: 'curve', data: Buffer.from(curve)});\n\t\tparts.push({name: 'Q', data: pub});\n\t\tparts.push({name: 'd', data: priv});\n\n\t\tkey = new PrivateKey({\n\t\t\ttype: 'ecdsa',\n\t\t\tcurve: curve,\n\t\t\tparts: parts\n\t\t});\n\t\treturn (key);\n\t}\n}\n","// Copyright 2011 Mark Cavage All rights reserved.\n\n\nmodule.exports = {\n\n newInvalidAsn1Error: function (msg) {\n var e = new Error();\n e.name = 'InvalidAsn1Error';\n e.message = msg || '';\n return e;\n }\n\n};\n","// Copyright 2011 Mark Cavage All rights reserved.\n\n\nmodule.exports = {\n EOC: 0,\n Boolean: 1,\n Integer: 2,\n BitString: 3,\n OctetString: 4,\n Null: 5,\n OID: 6,\n ObjectDescriptor: 7,\n External: 8,\n Real: 9, // float\n Enumeration: 10,\n PDV: 11,\n Utf8String: 12,\n RelativeOID: 13,\n Sequence: 16,\n Set: 17,\n NumericString: 18,\n PrintableString: 19,\n T61String: 20,\n VideotexString: 21,\n IA5String: 22,\n UTCTime: 23,\n GeneralizedTime: 24,\n GraphicString: 25,\n VisibleString: 26,\n GeneralString: 28,\n UniversalString: 29,\n CharacterString: 30,\n BMPString: 31,\n Constructor: 32,\n Context: 128\n};\n","// Copyright 2015 Joyent, Inc.\n\nmodule.exports = {\n\tread: read,\n\treadPkcs1: readPkcs1,\n\twrite: write,\n\twritePkcs1: writePkcs1\n};\n\nvar assert = require('assert-plus');\nvar asn1 = require('asn1');\nvar Buffer = require('safer-buffer').Buffer;\nvar algs = require('../algs');\nvar utils = require('../utils');\n\nvar Key = require('../key');\nvar PrivateKey = require('../private-key');\nvar pem = require('./pem');\n\nvar pkcs8 = require('./pkcs8');\nvar readECDSACurve = pkcs8.readECDSACurve;\n\nfunction read(buf, options) {\n\treturn (pem.read(buf, options, 'pkcs1'));\n}\n\nfunction write(key, options) {\n\treturn (pem.write(key, options, 'pkcs1'));\n}\n\n/* Helper to read in a single mpint */\nfunction readMPInt(der, nm) {\n\tassert.strictEqual(der.peek(), asn1.Ber.Integer,\n\t nm + ' is not an Integer');\n\treturn (utils.mpNormalize(der.readString(asn1.Ber.Integer, true)));\n}\n\nfunction readPkcs1(alg, type, der) {\n\tswitch (alg) {\n\tcase 'RSA':\n\t\tif (type === 'public')\n\t\t\treturn (readPkcs1RSAPublic(der));\n\t\telse if (type === 'private')\n\t\t\treturn (readPkcs1RSAPrivate(der));\n\t\tthrow (new Error('Unknown key type: ' + type));\n\tcase 'DSA':\n\t\tif (type === 'public')\n\t\t\treturn (readPkcs1DSAPublic(der));\n\t\telse if (type === 'private')\n\t\t\treturn (readPkcs1DSAPrivate(der));\n\t\tthrow (new Error('Unknown key type: ' + type));\n\tcase 'EC':\n\tcase 'ECDSA':\n\t\tif (type === 'private')\n\t\t\treturn (readPkcs1ECDSAPrivate(der));\n\t\telse if (type === 'public')\n\t\t\treturn (readPkcs1ECDSAPublic(der));\n\t\tthrow (new Error('Unknown key type: ' + type));\n\tcase 'EDDSA':\n\tcase 'EdDSA':\n\t\tif (type === 'private')\n\t\t\treturn (readPkcs1EdDSAPrivate(der));\n\t\tthrow (new Error(type + ' keys not supported with EdDSA'));\n\tdefault:\n\t\tthrow (new Error('Unknown key algo: ' + alg));\n\t}\n}\n\nfunction readPkcs1RSAPublic(der) {\n\t// modulus and exponent\n\tvar n = readMPInt(der, 'modulus');\n\tvar e = readMPInt(der, 'exponent');\n\n\t// now, make the key\n\tvar key = {\n\t\ttype: 'rsa',\n\t\tparts: [\n\t\t\t{ name: 'e', data: e },\n\t\t\t{ name: 'n', data: n }\n\t\t]\n\t};\n\n\treturn (new Key(key));\n}\n\nfunction readPkcs1RSAPrivate(der) {\n\tvar version = readMPInt(der, 'version');\n\tassert.strictEqual(version[0], 0);\n\n\t// modulus then public exponent\n\tvar n = readMPInt(der, 'modulus');\n\tvar e = readMPInt(der, 'public exponent');\n\tvar d = readMPInt(der, 'private exponent');\n\tvar p = readMPInt(der, 'prime1');\n\tvar q = readMPInt(der, 'prime2');\n\tvar dmodp = readMPInt(der, 'exponent1');\n\tvar dmodq = readMPInt(der, 'exponent2');\n\tvar iqmp = readMPInt(der, 'iqmp');\n\n\t// now, make the key\n\tvar key = {\n\t\ttype: 'rsa',\n\t\tparts: [\n\t\t\t{ name: 'n', data: n },\n\t\t\t{ name: 'e', data: e },\n\t\t\t{ name: 'd', data: d },\n\t\t\t{ name: 'iqmp', data: iqmp },\n\t\t\t{ name: 'p', data: p },\n\t\t\t{ name: 'q', data: q },\n\t\t\t{ name: 'dmodp', data: dmodp },\n\t\t\t{ name: 'dmodq', data: dmodq }\n\t\t]\n\t};\n\n\treturn (new PrivateKey(key));\n}\n\nfunction readPkcs1DSAPrivate(der) {\n\tvar version = readMPInt(der, 'version');\n\tassert.strictEqual(version.readUInt8(0), 0);\n\n\tvar p = readMPInt(der, 'p');\n\tvar q = readMPInt(der, 'q');\n\tvar g = readMPInt(der, 'g');\n\tvar y = readMPInt(der, 'y');\n\tvar x = readMPInt(der, 'x');\n\n\t// now, make the key\n\tvar key = {\n\t\ttype: 'dsa',\n\t\tparts: [\n\t\t\t{ name: 'p', data: p },\n\t\t\t{ name: 'q', data: q },\n\t\t\t{ name: 'g', data: g },\n\t\t\t{ name: 'y', data: y },\n\t\t\t{ name: 'x', data: x }\n\t\t]\n\t};\n\n\treturn (new PrivateKey(key));\n}\n\nfunction readPkcs1EdDSAPrivate(der) {\n\tvar version = readMPInt(der, 'version');\n\tassert.strictEqual(version.readUInt8(0), 1);\n\n\t// private key\n\tvar k = der.readString(asn1.Ber.OctetString, true);\n\n\tder.readSequence(0xa0);\n\tvar oid = der.readOID();\n\tassert.strictEqual(oid, '1.3.101.112', 'the ed25519 curve identifier');\n\n\tder.readSequence(0xa1);\n\tvar A = utils.readBitString(der);\n\n\tvar key = {\n\t\ttype: 'ed25519',\n\t\tparts: [\n\t\t\t{ name: 'A', data: utils.zeroPadToLength(A, 32) },\n\t\t\t{ name: 'k', data: k }\n\t\t]\n\t};\n\n\treturn (new PrivateKey(key));\n}\n\nfunction readPkcs1DSAPublic(der) {\n\tvar y = readMPInt(der, 'y');\n\tvar p = readMPInt(der, 'p');\n\tvar q = readMPInt(der, 'q');\n\tvar g = readMPInt(der, 'g');\n\n\tvar key = {\n\t\ttype: 'dsa',\n\t\tparts: [\n\t\t\t{ name: 'y', data: y },\n\t\t\t{ name: 'p', data: p },\n\t\t\t{ name: 'q', data: q },\n\t\t\t{ name: 'g', data: g }\n\t\t]\n\t};\n\n\treturn (new Key(key));\n}\n\nfunction readPkcs1ECDSAPublic(der) {\n\tder.readSequence();\n\n\tvar oid = der.readOID();\n\tassert.strictEqual(oid, '1.2.840.10045.2.1', 'must be ecPublicKey');\n\n\tvar curveOid = der.readOID();\n\n\tvar curve;\n\tvar curves = Object.keys(algs.curves);\n\tfor (var j = 0; j < curves.length; ++j) {\n\t\tvar c = curves[j];\n\t\tvar cd = algs.curves[c];\n\t\tif (cd.pkcs8oid === curveOid) {\n\t\t\tcurve = c;\n\t\t\tbreak;\n\t\t}\n\t}\n\tassert.string(curve, 'a known ECDSA named curve');\n\n\tvar Q = der.readString(asn1.Ber.BitString, true);\n\tQ = utils.ecNormalize(Q);\n\n\tvar key = {\n\t\ttype: 'ecdsa',\n\t\tparts: [\n\t\t\t{ name: 'curve', data: Buffer.from(curve) },\n\t\t\t{ name: 'Q', data: Q }\n\t\t]\n\t};\n\n\treturn (new Key(key));\n}\n\nfunction readPkcs1ECDSAPrivate(der) {\n\tvar version = readMPInt(der, 'version');\n\tassert.strictEqual(version.readUInt8(0), 1);\n\n\t// private key\n\tvar d = der.readString(asn1.Ber.OctetString, true);\n\n\tder.readSequence(0xa0);\n\tvar curve = readECDSACurve(der);\n\tassert.string(curve, 'a known elliptic curve');\n\n\tder.readSequence(0xa1);\n\tvar Q = der.readString(asn1.Ber.BitString, true);\n\tQ = utils.ecNormalize(Q);\n\n\tvar key = {\n\t\ttype: 'ecdsa',\n\t\tparts: [\n\t\t\t{ name: 'curve', data: Buffer.from(curve) },\n\t\t\t{ name: 'Q', data: Q },\n\t\t\t{ name: 'd', data: d }\n\t\t]\n\t};\n\n\treturn (new PrivateKey(key));\n}\n\nfunction writePkcs1(der, key) {\n\tder.startSequence();\n\n\tswitch (key.type) {\n\tcase 'rsa':\n\t\tif (PrivateKey.isPrivateKey(key))\n\t\t\twritePkcs1RSAPrivate(der, key);\n\t\telse\n\t\t\twritePkcs1RSAPublic(der, key);\n\t\tbreak;\n\tcase 'dsa':\n\t\tif (PrivateKey.isPrivateKey(key))\n\t\t\twritePkcs1DSAPrivate(der, key);\n\t\telse\n\t\t\twritePkcs1DSAPublic(der, key);\n\t\tbreak;\n\tcase 'ecdsa':\n\t\tif (PrivateKey.isPrivateKey(key))\n\t\t\twritePkcs1ECDSAPrivate(der, key);\n\t\telse\n\t\t\twritePkcs1ECDSAPublic(der, key);\n\t\tbreak;\n\tcase 'ed25519':\n\t\tif (PrivateKey.isPrivateKey(key))\n\t\t\twritePkcs1EdDSAPrivate(der, key);\n\t\telse\n\t\t\twritePkcs1EdDSAPublic(der, key);\n\t\tbreak;\n\tdefault:\n\t\tthrow (new Error('Unknown key algo: ' + key.type));\n\t}\n\n\tder.endSequence();\n}\n\nfunction writePkcs1RSAPublic(der, key) {\n\tder.writeBuffer(key.part.n.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.e.data, asn1.Ber.Integer);\n}\n\nfunction writePkcs1RSAPrivate(der, key) {\n\tvar ver = Buffer.from([0]);\n\tder.writeBuffer(ver, asn1.Ber.Integer);\n\n\tder.writeBuffer(key.part.n.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.e.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.d.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.p.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.q.data, asn1.Ber.Integer);\n\tif (!key.part.dmodp || !key.part.dmodq)\n\t\tutils.addRSAMissing(key);\n\tder.writeBuffer(key.part.dmodp.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.dmodq.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.iqmp.data, asn1.Ber.Integer);\n}\n\nfunction writePkcs1DSAPrivate(der, key) {\n\tvar ver = Buffer.from([0]);\n\tder.writeBuffer(ver, asn1.Ber.Integer);\n\n\tder.writeBuffer(key.part.p.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.q.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.g.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.y.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.x.data, asn1.Ber.Integer);\n}\n\nfunction writePkcs1DSAPublic(der, key) {\n\tder.writeBuffer(key.part.y.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.p.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.q.data, asn1.Ber.Integer);\n\tder.writeBuffer(key.part.g.data, asn1.Ber.Integer);\n}\n\nfunction writePkcs1ECDSAPublic(der, key) {\n\tder.startSequence();\n\n\tder.writeOID('1.2.840.10045.2.1'); /* ecPublicKey */\n\tvar curve = key.part.curve.data.toString();\n\tvar curveOid = algs.curves[curve].pkcs8oid;\n\tassert.string(curveOid, 'a known ECDSA named curve');\n\tder.writeOID(curveOid);\n\n\tder.endSequence();\n\n\tvar Q = utils.ecNormalize(key.part.Q.data, true);\n\tder.writeBuffer(Q, asn1.Ber.BitString);\n}\n\nfunction writePkcs1ECDSAPrivate(der, key) {\n\tvar ver = Buffer.from([1]);\n\tder.writeBuffer(ver, asn1.Ber.Integer);\n\n\tder.writeBuffer(key.part.d.data, asn1.Ber.OctetString);\n\n\tder.startSequence(0xa0);\n\tvar curve = key.part.curve.data.toString();\n\tvar curveOid = algs.curves[curve].pkcs8oid;\n\tassert.string(curveOid, 'a known ECDSA named curve');\n\tder.writeOID(curveOid);\n\tder.endSequence();\n\n\tder.startSequence(0xa1);\n\tvar Q = utils.ecNormalize(key.part.Q.data, true);\n\tder.writeBuffer(Q, asn1.Ber.BitString);\n\tder.endSequence();\n}\n\nfunction writePkcs1EdDSAPrivate(der, key) {\n\tvar ver = Buffer.from([1]);\n\tder.writeBuffer(ver, asn1.Ber.Integer);\n\n\tder.writeBuffer(key.part.k.data, asn1.Ber.OctetString);\n\n\tder.startSequence(0xa0);\n\tder.writeOID('1.3.101.112');\n\tder.endSequence();\n\n\tder.startSequence(0xa1);\n\tutils.writeBitString(der, key.part.A.data);\n\tder.endSequence();\n}\n\nfunction writePkcs1EdDSAPublic(der, key) {\n\tthrow (new Error('Public keys are not supported for EdDSA PKCS#1'));\n}\n","// Copyright 2017 Joyent, Inc.\n\nmodule.exports = {\n\tread: read,\n\twrite: write\n};\n\nvar assert = require('assert-plus');\nvar Buffer = require('safer-buffer').Buffer;\nvar Key = require('../key');\nvar PrivateKey = require('../private-key');\nvar utils = require('../utils');\nvar SSHBuffer = require('../ssh-buffer');\nvar Dhe = require('../dhe');\n\nvar supportedAlgos = {\n\t'rsa-sha1' : 5,\n\t'rsa-sha256' : 8,\n\t'rsa-sha512' : 10,\n\t'ecdsa-p256-sha256' : 13,\n\t'ecdsa-p384-sha384' : 14\n\t/*\n\t * ed25519 is hypothetically supported with id 15\n\t * but the common tools available don't appear to be\n\t * capable of generating/using ed25519 keys\n\t */\n};\n\nvar supportedAlgosById = {};\nObject.keys(supportedAlgos).forEach(function (k) {\n\tsupportedAlgosById[supportedAlgos[k]] = k.toUpperCase();\n});\n\nfunction read(buf, options) {\n\tif (typeof (buf) !== 'string') {\n\t\tassert.buffer(buf, 'buf');\n\t\tbuf = buf.toString('ascii');\n\t}\n\tvar lines = buf.split('\\n');\n\tif (lines[0].match(/^Private-key-format\\: v1/)) {\n\t\tvar algElems = lines[1].split(' ');\n\t\tvar algoNum = parseInt(algElems[1], 10);\n\t\tvar algoName = algElems[2];\n\t\tif (!supportedAlgosById[algoNum])\n\t\t\tthrow (new Error('Unsupported algorithm: ' + algoName));\n\t\treturn (readDNSSECPrivateKey(algoNum, lines.slice(2)));\n\t}\n\n\t// skip any comment-lines\n\tvar line = 0;\n\t/* JSSTYLED */\n\twhile (lines[line].match(/^\\;/))\n\t\tline++;\n\t// we should now have *one single* line left with our KEY on it.\n\tif ((lines[line].match(/\\. IN KEY /) ||\n\t lines[line].match(/\\. IN DNSKEY /)) && lines[line+1].length === 0) {\n\t\treturn (readRFC3110(lines[line]));\n\t}\n\tthrow (new Error('Cannot parse dnssec key'));\n}\n\nfunction readRFC3110(keyString) {\n\tvar elems = keyString.split(' ');\n\t//unused var flags = parseInt(elems[3], 10);\n\t//unused var protocol = parseInt(elems[4], 10);\n\tvar algorithm = parseInt(elems[5], 10);\n\tif (!supportedAlgosById[algorithm])\n\t\tthrow (new Error('Unsupported algorithm: ' + algorithm));\n\tvar base64key = elems.slice(6, elems.length).join();\n\tvar keyBuffer = Buffer.from(base64key, 'base64');\n\tif (supportedAlgosById[algorithm].match(/^RSA-/)) {\n\t\t// join the rest of the body into a single base64-blob\n\t\tvar publicExponentLen = keyBuffer.readUInt8(0);\n\t\tif (publicExponentLen != 3 && publicExponentLen != 1)\n\t\t\tthrow (new Error('Cannot parse dnssec key: ' +\n\t\t\t 'unsupported exponent length'));\n\n\t\tvar publicExponent = keyBuffer.slice(1, publicExponentLen+1);\n\t\tpublicExponent = utils.mpNormalize(publicExponent);\n\t\tvar modulus = keyBuffer.slice(1+publicExponentLen);\n\t\tmodulus = utils.mpNormalize(modulus);\n\t\t// now, make the key\n\t\tvar rsaKey = {\n\t\t\ttype: 'rsa',\n\t\t\tparts: []\n\t\t};\n\t\trsaKey.parts.push({ name: 'e', data: publicExponent});\n\t\trsaKey.parts.push({ name: 'n', data: modulus});\n\t\treturn (new Key(rsaKey));\n\t}\n\tif (supportedAlgosById[algorithm] === 'ECDSA-P384-SHA384' ||\n\t supportedAlgosById[algorithm] === 'ECDSA-P256-SHA256') {\n\t\tvar curve = 'nistp384';\n\t\tvar size = 384;\n\t\tif (supportedAlgosById[algorithm].match(/^ECDSA-P256-SHA256/)) {\n\t\t\tcurve = 'nistp256';\n\t\t\tsize = 256;\n\t\t}\n\n\t\tvar ecdsaKey = {\n\t\t\ttype: 'ecdsa',\n\t\t\tcurve: curve,\n\t\t\tsize: size,\n\t\t\tparts: [\n\t\t\t\t{name: 'curve', data: Buffer.from(curve) },\n\t\t\t\t{name: 'Q', data: utils.ecNormalize(keyBuffer) }\n\t\t\t]\n\t\t};\n\t\treturn (new Key(ecdsaKey));\n\t}\n\tthrow (new Error('Unsupported algorithm: ' +\n\t supportedAlgosById[algorithm]));\n}\n\nfunction elementToBuf(e) {\n\treturn (Buffer.from(e.split(' ')[1], 'base64'));\n}\n\nfunction readDNSSECRSAPrivateKey(elements) {\n\tvar rsaParams = {};\n\telements.forEach(function (element) {\n\t\tif (element.split(' ')[0] === 'Modulus:')\n\t\t\trsaParams['n'] = elementToBuf(element);\n\t\telse if (element.split(' ')[0] === 'PublicExponent:')\n\t\t\trsaParams['e'] = elementToBuf(element);\n\t\telse if (element.split(' ')[0] === 'PrivateExponent:')\n\t\t\trsaParams['d'] = elementToBuf(element);\n\t\telse if (element.split(' ')[0] === 'Prime1:')\n\t\t\trsaParams['p'] = elementToBuf(element);\n\t\telse if (element.split(' ')[0] === 'Prime2:')\n\t\t\trsaParams['q'] = elementToBuf(element);\n\t\telse if (element.split(' ')[0] === 'Exponent1:')\n\t\t\trsaParams['dmodp'] = elementToBuf(element);\n\t\telse if (element.split(' ')[0] === 'Exponent2:')\n\t\t\trsaParams['dmodq'] = elementToBuf(element);\n\t\telse if (element.split(' ')[0] === 'Coefficient:')\n\t\t\trsaParams['iqmp'] = elementToBuf(element);\n\t});\n\t// now, make the key\n\tvar key = {\n\t\ttype: 'rsa',\n\t\tparts: [\n\t\t\t{ name: 'e', data: utils.mpNormalize(rsaParams['e'])},\n\t\t\t{ name: 'n', data: utils.mpNormalize(rsaParams['n'])},\n\t\t\t{ name: 'd', data: utils.mpNormalize(rsaParams['d'])},\n\t\t\t{ name: 'p', data: utils.mpNormalize(rsaParams['p'])},\n\t\t\t{ name: 'q', data: utils.mpNormalize(rsaParams['q'])},\n\t\t\t{ name: 'dmodp',\n\t\t\t data: utils.mpNormalize(rsaParams['dmodp'])},\n\t\t\t{ name: 'dmodq',\n\t\t\t data: utils.mpNormalize(rsaParams['dmodq'])},\n\t\t\t{ name: 'iqmp',\n\t\t\t data: utils.mpNormalize(rsaParams['iqmp'])}\n\t\t]\n\t};\n\treturn (new PrivateKey(key));\n}\n\nfunction readDNSSECPrivateKey(alg, elements) {\n\tif (supportedAlgosById[alg].match(/^RSA-/)) {\n\t\treturn (readDNSSECRSAPrivateKey(elements));\n\t}\n\tif (supportedAlgosById[alg] === 'ECDSA-P384-SHA384' ||\n\t supportedAlgosById[alg] === 'ECDSA-P256-SHA256') {\n\t\tvar d = Buffer.from(elements[0].split(' ')[1], 'base64');\n\t\tvar curve = 'nistp384';\n\t\tvar size = 384;\n\t\tif (supportedAlgosById[alg] === 'ECDSA-P256-SHA256') {\n\t\t\tcurve = 'nistp256';\n\t\t\tsize = 256;\n\t\t}\n\t\t// DNSSEC generates the public-key on the fly (go calculate it)\n\t\tvar publicKey = utils.publicFromPrivateECDSA(curve, d);\n\t\tvar Q = publicKey.part['Q'].data;\n\t\tvar ecdsaKey = {\n\t\t\ttype: 'ecdsa',\n\t\t\tcurve: curve,\n\t\t\tsize: size,\n\t\t\tparts: [\n\t\t\t\t{name: 'curve', data: Buffer.from(curve) },\n\t\t\t\t{name: 'd', data: d },\n\t\t\t\t{name: 'Q', data: Q }\n\t\t\t]\n\t\t};\n\t\treturn (new PrivateKey(ecdsaKey));\n\t}\n\tthrow (new Error('Unsupported algorithm: ' + supportedAlgosById[alg]));\n}\n\nfunction dnssecTimestamp(date) {\n\tvar year = date.getFullYear() + ''; //stringify\n\tvar month = (date.getMonth() + 1);\n\tvar timestampStr = year + month + date.getUTCDate();\n\ttimestampStr += '' + date.getUTCHours() + date.getUTCMinutes();\n\ttimestampStr += date.getUTCSeconds();\n\treturn (timestampStr);\n}\n\nfunction rsaAlgFromOptions(opts) {\n\tif (!opts || !opts.hashAlgo || opts.hashAlgo === 'sha1')\n\t\treturn ('5 (RSASHA1)');\n\telse if (opts.hashAlgo === 'sha256')\n\t\treturn ('8 (RSASHA256)');\n\telse if (opts.hashAlgo === 'sha512')\n\t\treturn ('10 (RSASHA512)');\n\telse\n\t\tthrow (new Error('Unknown or unsupported hash: ' +\n\t\t opts.hashAlgo));\n}\n\nfunction writeRSA(key, options) {\n\t// if we're missing parts, add them.\n\tif (!key.part.dmodp || !key.part.dmodq) {\n\t\tutils.addRSAMissing(key);\n\t}\n\n\tvar out = '';\n\tout += 'Private-key-format: v1.3\\n';\n\tout += 'Algorithm: ' + rsaAlgFromOptions(options) + '\\n';\n\tvar n = utils.mpDenormalize(key.part['n'].data);\n\tout += 'Modulus: ' + n.toString('base64') + '\\n';\n\tvar e = utils.mpDenormalize(key.part['e'].data);\n\tout += 'PublicExponent: ' + e.toString('base64') + '\\n';\n\tvar d = utils.mpDenormalize(key.part['d'].data);\n\tout += 'PrivateExponent: ' + d.toString('base64') + '\\n';\n\tvar p = utils.mpDenormalize(key.part['p'].data);\n\tout += 'Prime1: ' + p.toString('base64') + '\\n';\n\tvar q = utils.mpDenormalize(key.part['q'].data);\n\tout += 'Prime2: ' + q.toString('base64') + '\\n';\n\tvar dmodp = utils.mpDenormalize(key.part['dmodp'].data);\n\tout += 'Exponent1: ' + dmodp.toString('base64') + '\\n';\n\tvar dmodq = utils.mpDenormalize(key.part['dmodq'].data);\n\tout += 'Exponent2: ' + dmodq.toString('base64') + '\\n';\n\tvar iqmp = utils.mpDenormalize(key.part['iqmp'].data);\n\tout += 'Coefficient: ' + iqmp.toString('base64') + '\\n';\n\t// Assume that we're valid as-of now\n\tvar timestamp = new Date();\n\tout += 'Created: ' + dnssecTimestamp(timestamp) + '\\n';\n\tout += 'Publish: ' + dnssecTimestamp(timestamp) + '\\n';\n\tout += 'Activate: ' + dnssecTimestamp(timestamp) + '\\n';\n\treturn (Buffer.from(out, 'ascii'));\n}\n\nfunction writeECDSA(key, options) {\n\tvar out = '';\n\tout += 'Private-key-format: v1.3\\n';\n\n\tif (key.curve === 'nistp256') {\n\t\tout += 'Algorithm: 13 (ECDSAP256SHA256)\\n';\n\t} else if (key.curve === 'nistp384') {\n\t\tout += 'Algorithm: 14 (ECDSAP384SHA384)\\n';\n\t} else {\n\t\tthrow (new Error('Unsupported curve'));\n\t}\n\tvar base64Key = key.part['d'].data.toString('base64');\n\tout += 'PrivateKey: ' + base64Key + '\\n';\n\n\t// Assume that we're valid as-of now\n\tvar timestamp = new Date();\n\tout += 'Created: ' + dnssecTimestamp(timestamp) + '\\n';\n\tout += 'Publish: ' + dnssecTimestamp(timestamp) + '\\n';\n\tout += 'Activate: ' + dnssecTimestamp(timestamp) + '\\n';\n\n\treturn (Buffer.from(out, 'ascii'));\n}\n\nfunction write(key, options) {\n\tif (PrivateKey.isPrivateKey(key)) {\n\t\tif (key.type === 'rsa') {\n\t\t\treturn (writeRSA(key, options));\n\t\t} else if (key.type === 'ecdsa') {\n\t\t\treturn (writeECDSA(key, options));\n\t\t} else {\n\t\t\tthrow (new Error('Unsupported algorithm: ' + key.type));\n\t\t}\n\t} else if (Key.isKey(key)) {\n\t\t/*\n\t\t * RFC3110 requires a keyname, and a keytype, which we\n\t\t * don't really have a mechanism for specifying such\n\t\t * additional metadata.\n\t\t */\n\t\tthrow (new Error('Format \"dnssec\" only supports ' +\n\t\t 'writing private keys'));\n\t} else {\n\t\tthrow (new Error('key is not a Key or PrivateKey'));\n\t}\n}\n","function Caseless (dict) {\n this.dict = dict || {}\n}\nCaseless.prototype.set = function (name, value, clobber) {\n if (typeof name === 'object') {\n for (var i in name) {\n this.set(i, name[i], value)\n }\n } else {\n if (typeof clobber === 'undefined') clobber = true\n var has = this.has(name)\n\n if (!clobber && has) this.dict[has] = this.dict[has] + ',' + value\n else this.dict[has || name] = value\n return has\n }\n}\nCaseless.prototype.has = function (name) {\n var keys = Object.keys(this.dict)\n , name = name.toLowerCase()\n ;\n for (var i=0;i>> 31);\n\t }\n\n\t var t = ((a << 5) | (a >>> 27)) + e + W[i];\n\t if (i < 20) {\n\t t += ((b & c) | (~b & d)) + 0x5a827999;\n\t } else if (i < 40) {\n\t t += (b ^ c ^ d) + 0x6ed9eba1;\n\t } else if (i < 60) {\n\t t += ((b & c) | (b & d) | (c & d)) - 0x70e44324;\n\t } else /* if (i < 80) */ {\n\t t += (b ^ c ^ d) - 0x359d3e2a;\n\t }\n\n\t e = d;\n\t d = c;\n\t c = (b << 30) | (b >>> 2);\n\t b = a;\n\t a = t;\n\t }\n\n\t // Intermediate hash value\n\t H[0] = (H[0] + a) | 0;\n\t H[1] = (H[1] + b) | 0;\n\t H[2] = (H[2] + c) | 0;\n\t H[3] = (H[3] + d) | 0;\n\t H[4] = (H[4] + e) | 0;\n\t },\n\n\t _doFinalize: function () {\n\t // Shortcuts\n\t var data = this._data;\n\t var dataWords = data.words;\n\n\t var nBitsTotal = this._nDataBytes * 8;\n\t var nBitsLeft = data.sigBytes * 8;\n\n\t // Add padding\n\t dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);\n\t dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);\n\t dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;\n\t data.sigBytes = dataWords.length * 4;\n\n\t // Hash final blocks\n\t this._process();\n\n\t // Return final computed hash\n\t return this._hash;\n\t },\n\n\t clone: function () {\n\t var clone = Hasher.clone.call(this);\n\t clone._hash = this._hash.clone();\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.SHA1('message');\n\t * var hash = CryptoJS.SHA1(wordArray);\n\t */\n\t C.SHA1 = Hasher._createHelper(SHA1);\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.HmacSHA1(message, key);\n\t */\n\t C.HmacSHA1 = Hasher._createHmacHelper(SHA1);\n\t}());\n\n\n\treturn CryptoJS.SHA1;\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 () {\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 C_enc = C.enc;\n\t var Utf8 = C_enc.Utf8;\n\t var C_algo = C.algo;\n\n\t /**\n\t * HMAC algorithm.\n\t */\n\t var HMAC = C_algo.HMAC = Base.extend({\n\t /**\n\t * Initializes a newly created HMAC.\n\t *\n\t * @param {Hasher} hasher The hash algorithm to use.\n\t * @param {WordArray|string} key The secret key.\n\t *\n\t * @example\n\t *\n\t * var hmacHasher = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key);\n\t */\n\t init: function (hasher, key) {\n\t // Init hasher\n\t hasher = this._hasher = new hasher.init();\n\n\t // Convert string to WordArray, else assume WordArray already\n\t if (typeof key == 'string') {\n\t key = Utf8.parse(key);\n\t }\n\n\t // Shortcuts\n\t var hasherBlockSize = hasher.blockSize;\n\t var hasherBlockSizeBytes = hasherBlockSize * 4;\n\n\t // Allow arbitrary length keys\n\t if (key.sigBytes > hasherBlockSizeBytes) {\n\t key = hasher.finalize(key);\n\t }\n\n\t // Clamp excess bits\n\t key.clamp();\n\n\t // Clone key for inner and outer pads\n\t var oKey = this._oKey = key.clone();\n\t var iKey = this._iKey = key.clone();\n\n\t // Shortcuts\n\t var oKeyWords = oKey.words;\n\t var iKeyWords = iKey.words;\n\n\t // XOR keys with pad constants\n\t for (var i = 0; i < hasherBlockSize; i++) {\n\t oKeyWords[i] ^= 0x5c5c5c5c;\n\t iKeyWords[i] ^= 0x36363636;\n\t }\n\t oKey.sigBytes = iKey.sigBytes = hasherBlockSizeBytes;\n\n\t // Set initial values\n\t this.reset();\n\t },\n\n\t /**\n\t * Resets this HMAC to its initial state.\n\t *\n\t * @example\n\t *\n\t * hmacHasher.reset();\n\t */\n\t reset: function () {\n\t // Shortcut\n\t var hasher = this._hasher;\n\n\t // Reset\n\t hasher.reset();\n\t hasher.update(this._iKey);\n\t },\n\n\t /**\n\t * Updates this HMAC with a message.\n\t *\n\t * @param {WordArray|string} messageUpdate The message to append.\n\t *\n\t * @return {HMAC} This HMAC instance.\n\t *\n\t * @example\n\t *\n\t * hmacHasher.update('message');\n\t * hmacHasher.update(wordArray);\n\t */\n\t update: function (messageUpdate) {\n\t this._hasher.update(messageUpdate);\n\n\t // Chainable\n\t return this;\n\t },\n\n\t /**\n\t * Finalizes the HMAC 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 HMAC.\n\t *\n\t * @example\n\t *\n\t * var hmac = hmacHasher.finalize();\n\t * var hmac = hmacHasher.finalize('message');\n\t * var hmac = hmacHasher.finalize(wordArray);\n\t */\n\t finalize: function (messageUpdate) {\n\t // Shortcut\n\t var hasher = this._hasher;\n\n\t // Compute HMAC\n\t var innerHash = hasher.finalize(messageUpdate);\n\t hasher.reset();\n\t var hmac = hasher.finalize(this._oKey.clone().concat(innerHash));\n\n\t return hmac;\n\t }\n\t });\n\t}());\n\n\n}));","const MoneroError = require(\"./MoneroError\");\n\n/**\n * Error when interacting with Monero RPC.\n */\nclass MoneroRpcError extends MoneroError {\n \n /**\n * Constructs the error.\n * \n * @param {string} rpcDescription is a description of the error from rpc\n * @param {int} rpcCode is the error code from rpc\n * @param {string} rpcMethod is the rpc method invoked\n * @param {object} rpcParams are parameters sent with the rpc request\n */\n constructor(rpcDescription, rpcCode, rpcMethod, rpcParams) {\n super(rpcDescription, rpcCode);\n this.rpcMethod = rpcMethod;\n this.rpcParams = rpcParams;\n }\n \n getRpcMethod() {\n return this.rpcMethod;\n }\n \n getRpcParams() {\n return this.rpcParams;\n }\n \n toString() {\n let str = super.toString();\n if (this.rpcMethod || this.rpcParams) str += \"\\nRequest: '\" + this.rpcMethod + \"' with params: \" + (typeof this.rpcParams === \"object\" ? JSON.stringify(this.rpcParams) : this.rpcParams);\n return str;\n }\n}\n\nmodule.exports = MoneroRpcError;","/**\n * Monero banhammer.\n */\nclass MoneroBan {\n \n constructor(state) {\n this.state = Object.assign({}, state);\n }\n \n toJson() {\n return Object.assign({}, this.state);\n }\n \n getHost() {\n return this.state.host;\n }\n \n setHost(host) {\n this.state.host = host;\n return this;\n }\n \n getIp() {\n return this.state.ip;\n }\n \n setIp(ip) {\n this.state.ip = ip;\n return this;\n }\n \n isBanned() {\n return this.state.isBanned;\n }\n \n setIsBanned(isBanned) {\n this.state.isBanned = isBanned;\n return this;\n }\n \n getSeconds() {\n return this.state.seconds;\n }\n \n setSeconds(seconds) {\n this.state.seconds = seconds;\n return this;\n }\n}\n\nmodule.exports = MoneroBan;","const MoneroDaemonPeer = require(\"./MoneroDaemonPeer\");\n\n/**\n * Monero daemon connection.\n */\nclass MoneroDaemonConnection {\n \n constructor(state) {\n this.state = Object.assign({}, state);\n if (this.state.peer !== undefined && !(this.state.peer instanceof MoneroDaemonPeer)) this.state.peer = new MoneroDaemonPeer(this.state.peer);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (json.peer) json.peer = json.peer.toJson();\n return json;\n }\n \n getPeer() {\n return this.state.peer;\n }\n\n setPeer(peer) {\n this.state.peer = peer;\n return this;\n }\n \n getId() {\n return this.state.id;\n }\n\n setId(id) {\n this.state.id = id;\n return this;\n }\n\n getAvgDownload() {\n return this.state.avgDownload;\n }\n\n setAvgDownload(avgDownload) {\n this.state.avgDownload = avgDownload;\n return this;\n }\n\n getAvgUpload() {\n return this.state.avgUpload;\n }\n\n setAvgUpload(avgUpload) {\n this.state.avgUpload = avgUpload;\n return this;\n }\n\n getCurrentDownload() {\n return this.state.currentDownload;\n }\n\n setCurrentDownload(currentDownload) {\n this.state.currentDownload = currentDownload;\n return this;\n }\n\n getCurrentUpload() {\n return this.state.currentUpload;\n }\n\n setCurrentUpload(currentUpload) {\n this.state.currentUpload = currentUpload;\n return this;\n }\n\n getHeight() {\n return this.state.height;\n }\n\n setHeight(height) {\n this.state.height = height;\n return this;\n }\n\n isIncoming() {\n return this.state.isIncoming;\n }\n\n setIsIncoming(isIncoming) {\n this.state.isIncoming = isIncoming;\n return this;\n }\n\n getLiveTime() {\n return this.state.liveTime;\n }\n\n setLiveTime(liveTime) {\n this.state.liveTime = liveTime;\n return this;\n }\n\n isLocalIp() {\n return this.state.isLocalIp;\n }\n\n setIsLocalIp(isLocalIp) {\n this.state.isLocalIp = isLocalIp;\n return this;\n }\n\n isLocalHost() {\n return this.state.isLocalHost;\n }\n\n setIsLocalHost(isLocalHost) {\n this.state.isLocalHost = isLocalHost;\n return this;\n }\n\n getNumReceives() {\n return this.state.numReceives;\n }\n\n setNumReceives(numReceives) {\n this.state.numReceives = numReceives;\n return this;\n }\n\n getNumSends() {\n return this.state.numSends;\n }\n\n setNumSends(numSends) {\n this.state.numSends = numSends;\n return this;\n }\n\n getReceiveIdleTime() {\n return this.state.receiveIdleTime;\n }\n\n setReceiveIdleTime(receiveIdleTime) {\n this.state.receiveIdleTime = receiveIdleTime;\n return this;\n }\n\n getSendIdleTime() {\n return this.state.sendIdleTime;\n }\n\n setSendIdleTime(sendIdleTime) {\n this.state.sendIdleTime = sendIdleTime;\n return this;\n }\n\n getState() {\n return this.state.state;\n }\n\n setState(state) {\n this.state.state = state;\n return this;\n }\n\n getNumSupportFlags() {\n return this.state.numSupportFlags;\n }\n\n setNumSupportFlags(numSupportFlags) {\n this.state.numSupportFlags = numSupportFlags;\n return this;\n }\n \n getType() {\n return this.state.type;\n }\n \n setType(type) {\n this.state.type = type;\n return this;\n }\n}\n\nmodule.exports = MoneroDaemonConnection;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\n\n/**\n * Models a peer to the daemon.\n */\nclass MoneroDaemonPeer {\n \n constructor(state) {\n this.state = Object.assign({}, state);\n if (this.state.rpcCreditsPerHash !== undefined && !(this.state.rpcCreditsPerHash instanceof BigInteger)) this.state.rpcCreditsPerHash = BigInteger.parse(this.state.rpcCreditsPerHash);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (json.rpcCreditsPerHash) json.rpcCreditsPerHash = json.rpcCreditsPerHash.toString();\n return json;\n }\n \n getId() {\n return this.state.id;\n }\n\n setId(id) {\n this.state.id = id;\n return this;\n }\n\n getAddress() {\n return this.state.address;\n }\n\n setAddress(address) {\n this.state.address = address;\n return this;\n }\n\n getHost() {\n return this.state.host;\n }\n\n setHost(host) {\n this.state.host = host;\n return this;\n }\n\n getPort() {\n return this.state.port;\n }\n\n setPort(port) {\n this.state.port = port;\n return this;\n }\n \n /**\n * Indicates if the peer was online when last checked (aka \"white listed\" as\n * opposed to \"gray listed\").\n * \n * @return {boolean} true if peer was online when last checked, false otherwise\n */\n isOnline() {\n return this.state.isOnline;\n }\n \n setIsOnline(isOnline) {\n this.state.isOnline = isOnline;\n return this;\n }\n \n getLastSeenTimestamp() {\n return this.state.lastSeenTimestamp;\n }\n \n setLastSeenTimestamp(lastSeenTimestamp) {\n this.state.lastSeenTimestamp = lastSeenTimestamp;\n return this;\n }\n \n getPruningSeed() {\n return this.state.pruningSeed;\n }\n \n setPruningSeed(pruningSeed) {\n this.state.pruningSeed = pruningSeed;\n return this;\n }\n \n getRpcPort() {\n return this.state.rpcPort;\n }\n\n setRpcPort(rpcPort) {\n this.state.rpcPort = rpcPort;\n return this;\n }\n \n getRpcCreditsPerHash() {\n return this.state.rpcCreditsPerHash;\n }\n \n setRpcCreditsPerHash(rpcCreditsPerHash) {\n this.state.rpcCreditsPerHash = rpcCreditsPerHash;\n return this;\n }\n}\n\nmodule.exports = MoneroDaemonPeer;","const assert = require(\"assert\");\nconst BigInteger = require(\"../../common/biginteger\").BigInteger;\nconst MoneroSubaddress = require(\"./MoneroSubaddress\");\n\n/**\n * Monero account model.\n */\nclass MoneroAccount {\n \n constructor(stateOrIndex, primaryAddress, balance, unlockedBalance, subaddresses) {\n \n // construct from json\n if (typeof stateOrIndex === \"object\") {\n this.state = stateOrIndex;\n \n // deserialize balances\n if (this.state.balance !== undefined && !(this.state.balance instanceof BigInteger)) this.state.balance = BigInteger.parse(this.state.balance);\n if (this.state.unlockedBalance !== undefined && !(this.state.unlockedBalance instanceof BigInteger)) this.state.unlockedBalance = BigInteger.parse(this.state.unlockedBalance);\n \n // deserialize subaddresses\n if (this.state.subaddresses) {\n for (let i = 0; i < this.state.subaddresses.length; i++) {\n if (!(this.state.subaddresses[i] instanceof MoneroSubaddress)) {\n this.state.subaddresses[i] = new MoneroSubaddress(this.state.subaddresses[i]);\n }\n }\n }\n }\n \n // construct from individual params\n else {\n this.state = {};\n this.setIndex(stateOrIndex);\n this.setPrimaryAddress(primaryAddress);\n this.setBalance(balance);\n this.setUnlockedBalance(unlockedBalance);\n this.setSubaddresses(subaddresses);\n }\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (json.balance) json.balance = json.balance.toString();\n if (json.unlockedBalance) json.unlockedBalance = json.unlockedBalance.toString();\n if (json.subaddresses) {\n for (let i = 0; i < json.subaddresses.length; i++) {\n json.subaddresses[i] = json.subaddresses[i].toJson();\n }\n }\n return json;\n }\n \n getIndex() {\n return this.state.index;\n }\n \n setIndex(index) {\n this.state.index = index;\n return this;\n }\n \n getPrimaryAddress() {\n return this.state.primaryAddress;\n }\n\n setPrimaryAddress(primaryAddress) {\n this.state.primaryAddress = primaryAddress;\n return this;\n }\n \n getBalance() {\n return this.state.balance;\n }\n \n setBalance(balance) {\n this.state.balance = balance;\n return this;\n }\n \n getUnlockedBalance() {\n return this.state.unlockedBalance;\n }\n \n setUnlockedBalance(unlockedBalance) {\n this.state.unlockedBalance = unlockedBalance;\n return this;\n }\n \n getTag() {\n return this.state.tag;\n }\n \n setTag(tag) {\n this.state.tag = tag;\n return this;\n }\n \n getSubaddresses() {\n return this.state.subaddresses;\n }\n \n setSubaddresses(subaddresses) {\n assert(subaddresses === undefined || Array.isArray(subaddresses), \"Given subaddresses must be undefined or an array of subaddresses\");\n this.state.subaddresses = subaddresses;\n if (subaddresses) {\n for (let subaddress of subaddresses) {\n subaddress.setAccountIndex(this.state.index);\n }\n }\n return this;\n }\n \n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.kvLine(\"Index\", this.getIndex(), indent);\n str += GenUtils.kvLine(\"Primary address\", this.getPrimaryAddress(), indent);\n str += GenUtils.kvLine(\"Balance\", this.getBalance(), indent);\n str += GenUtils.kvLine(\"Unlocked balance\", this.getUnlockedBalance(), indent);\n str += GenUtils.kvLine(\"Tag\", this.getTag(), indent);\n if (this.getSubaddresses() != null) {\n sb += GenUtils.kvLine(\"Subaddresses\", \"\", indent)\n for (let i = 0; i < this.getSubaddresses().size(); i++) {\n str += GenUtils.kvLine(i + 1, \"\", indent + 1);\n str += this.getSubaddresses()[i].toString(indent + 2) + \"\\n\";\n }\n }\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n\nmodule.exports = MoneroAccount;","/**\n * Monero address book entry model\n */\nclass MoneroAddressBookEntry {\n \n constructor(state) {\n this.state = Object.assign({}, state);\n }\n \n toJson() {\n return Object.assign({}, this.state);\n }\n \n getIndex() {\n return this.state.index;\n }\n \n setIndex(index) {\n this.state.index = index;\n return this;\n }\n \n getAddress() {\n return this.state.address;\n }\n \n setAddress(address) {\n this.state.address = address;\n return this;\n }\n \n getDescription() {\n return this.state.description;\n }\n \n setDescription(description) {\n this.state.description = description;\n return this;\n }\n \n getPaymentId() {\n return this.state.paymentId;\n }\n \n setPaymentId(paymentId) {\n this.state.paymentId = paymentId;\n return this;\n }\n}\n\nmodule.exports = MoneroAddressBookEntry;","/**\n * Base class for results from checking a transaction or reserve proof.\n * \n * @class\n */\nclass MoneroCheck {\n \n constructor(state) {\n this.state = Object.assign({}, state);\n }\n\n isGood() {\n return this.state.isGood;\n }\n\n setIsGood(isGood) {\n this.state.isGood = isGood;\n return this;\n }\n}\n\nmodule.exports = MoneroCheck;","const MoneroCheck = require(\"./MoneroCheck\");\nconst BigInteger = require(\"../../common/biginteger\").BigInteger;\n\n/**\n * Results from checking a transaction key.\n * \n * @extends {MoneroCheck}\n */\nclass MoneroCheckTx extends MoneroCheck {\n \n constructor(state) {\n super(state);\n if (this.state.receivedAmount !== undefined && !(this.state.receivedAmount instanceof BigInteger)) this.state.receivedAmount = BigInteger.parse(this.state.receivedAmount);\n }\n \n toJson() {\n let json = Object.assign({}, state);\n if (this.getReceivedAmount()) json.receivedAmount = this.getReceivedAmount().toString();\n return json;\n }\n\n inTxPool() {\n return this.state.inTxPool;\n }\n \n setInTxPool(inTxPool) {\n this.state.inTxPool = inTxPool;\n return this;\n }\n \n getNumConfirmations() {\n return this.state.numConfirmations;\n }\n \n setNumConfirmations(numConfirmations) {\n this.state.numConfirmations = numConfirmations;\n return this;\n }\n \n getReceivedAmount() {\n return this.state.receivedAmount;\n }\n \n setReceivedAmount(receivedAmount) {\n this.state.receivedAmount = receivedAmount;\n return this;\n }\n}\n\nmodule.exports = MoneroCheckTx;","/**\n * Monero integrated address model.\n */\nclass MoneroIntegratedAddress {\n \n constructor(state) {\n this.state = Object.assign({}, state);\n }\n \n toJson() {\n return Object.assign({}, this.state);\n }\n\n getStandardAddress() {\n return this.state.standardAddress;\n }\n \n setStandardAddress(standardAddress) {\n this.state.standardAddress = standardAddress;\n return this;\n }\n \n getPaymentId() {\n return this.state.paymentId;\n }\n \n setPaymentId(paymentId) {\n this.state.paymentId = paymentId;\n return this;\n }\n \n getIntegratedAddress() {\n return this.state.integratedAddress;\n }\n \n setIntegratedAddress(integratedAddress) {\n this.state.integratedAddress = integratedAddress;\n return this;\n }\n \n toString() {\n return this.state.integratedAddress;\n }\n}\n\nmodule.exports = MoneroIntegratedAddress;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\n\n/**\n * Models results from importing key images.\n */\nclass MoneroKeyImageImportResult {\n \n constructor(state) {\n state = Object.assign({}, state);\n if (state.spentAmount !== undefined && !(state.spentAmount instanceof BigInteger)) state.spentAmount = BigInteger.parse(state.spentAmount);\n if (state.unspentAmount !== undefined && !(state.unspentAmount instanceof BigInteger)) state.unspentAmount = BigInteger.parse(state.unspentAmount);\n this.state = state;\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (this.getSpentAmount()) json.spentAmount = this.getSpentAmount().toString();\n if (this.getUnspentAmount()) json.unspentAmount = this.getUnspentAmount().toString();\n return json;\n }\n \n getHeight() {\n return this.state.height;\n }\n \n setHeight(height) {\n this.state.height = height;\n return this;\n }\n \n getSpentAmount() {\n return this.state.spentAmount;\n }\n \n setSpentAmount(spentAmount) {\n this.state.spentAmount = spentAmount;\n return this;\n }\n \n getUnspentAmount() {\n return this.state.unspentAmount;\n }\n \n setUnspentAmount(unspentAmount) {\n this.state.unspentAmount = unspentAmount;\n return this;\n }\n}\n\nmodule.exports = MoneroKeyImageImportResult;","/**\n * Models information about a multisig wallet.\n */\nclass MoneroMultisigInfo {\n \n constructor(state) {\n this.state = Object.assign({}, state);\n }\n \n toJson() {\n return Object.assign({}, this.state);\n }\n \n isMultisig() {\n return this.state.isMultisig;\n }\n \n setIsMultisig(isMultisig) {\n this.state.isMultisig = isMultisig;\n return this;\n }\n \n isReady() {\n return this.state.isReady;\n }\n \n setIsReady(isReady) {\n this.state.isReady = isReady;\n }\n \n getThreshold() {\n return this.state.threshold;\n }\n \n setThreshold(threshold) {\n this.state.threshold = threshold;\n }\n \n getNumParticipants() {\n return this.state.numParticipants;\n }\n \n setNumParticipants(numParticipants) {\n this.state.numParticipants = numParticipants;\n }\n}\n\nmodule.exports = MoneroMultisigInfo;","/**\n * Models the result of initializing a multisig wallet which results in the\n * multisig wallet's address xor another multisig hex to share with\n * participants to create the wallet.\n */\nclass MoneroMultisigInitResult {\n\n constructor(state) {\n this.state = Object.assign({}, state);\n }\n \n toJson() {\n return Object.assign({}, this.state);\n }\n \n getAddress() {\n return this.state.address;\n }\n \n setAddress(address) {\n this.state.address = address;\n return this;\n }\n \n getMultisigHex() {\n return this.state.multisigHex;\n }\n \n setMultisigHex(multisigHex) {\n this.state.multisigHex = multisigHex;\n return this;\n }\n}\n\nmodule.exports = MoneroMultisigInitResult;","/**\n * Models the result of signing multisig tx hex.\n */\nclass MoneroMultisigSignResult {\n \n constructor(state) {\n this.state = Object.assign({}, state);\n }\n \n toJson() {\n return Object.assign({}, this.state);\n }\n \n getSignedMultisigTxHex() {\n return this.state.signedMultisigTxHex;\n }\n\n setSignedMultisigTxHex(signedTxMultisigHex) {\n this.state.signedMultisigTxHex = signedTxMultisigHex;\n }\n\n getTxHashes() {\n return this.state.txHashes;\n }\n\n setTxHashes(txHashes) {\n this.state.txHashes = txHashes;\n }\n}\n\nmodule.exports = MoneroMultisigSignResult;","/**\n * Result from syncing a Monero wallet.\n */\nclass MoneroSyncResult {\n \n constructor(numBlocksFetched, receivedMoney) {\n this.setNumBlocksFetched(numBlocksFetched);\n this.setReceivedMoney(receivedMoney);\n }\n \n getNumBlocksFetched() {\n return this.numBlocksFetched;\n }\n \n setNumBlocksFetched(numBlocksFetched) {\n this.numBlocksFetched = numBlocksFetched;\n return this;\n }\n \n getReceivedMoney() {\n return this.receivedMoney;\n }\n \n setReceivedMoney(receivedMoney) {\n this.receivedMoney = receivedMoney;\n return this;\n }\n}\n\nmodule.exports = MoneroSyncResult;","/**\n * Default wallet listener which takes no action on notifications.\n */\nclass MoneroWalletListener {\n \n /**\n * Invoked as the wallet is synchronized.\n * \n * @param {number} height - height of the synced block \n * @param {number} startHeight - starting height of the sync request\n * @param {number} endHeight - ending height of the sync request\n * @param {number} percentDone - sync progress as a percentage\n * @param {string} message - human-readable description of the current progress\n */\n onSyncProgress(height, startHeight, endHeight, percentDone, message) { }\n\n /**\n * Invoked when a new block is added to the chain.\n * \n * @param {int} height - the height of the block added to the chain\n */\n onNewBlock(height) { }\n \n /**\n * Invoked when the wallet's balances change.\n * \n * @param {BigInteger} newBalance - new wallet balance\n * @param {BigInteger} newUnlockedBalance - new unlocked wallet balance\n */\n onBalancesChanged(newBalance, newUnlockedBalance) { }\n\n /**\n * Invoked when the wallet receives an unconfirmed output, when the output is confirmed,\n * and when the output is unlocked.\n * \n * @param {MoneroOutputWallet} output - the received output\n */\n onOutputReceived(output) { }\n \n /**\n * Invoked when the wallet spends an output.\n * \n * @param {MoneroOutputWallet} output - the spent output\n */\n onOutputSpent(output) { }\n}\n\nmodule.exports = MoneroWalletListener;","'use strict';\n\n/**\n * Detect is the device a mobile device.\n * @return {Boolean}\n */\nexports.isMobile = function() {\n var ua = window.navigator.userAgent;\n return (ua.match(/Android|iPad|iPhone|iPod|Windows Phone/) !== null);\n};\n\n\n/**\n * Determine if this is a PhoneGap application.\n * @return {Boolean}\n */\nexports.isPhoneGap = function() {\n // TODO: Improve this...\n var proto = window.location.protocol;\n return (this.isMobile() && proto.indexOf('file') !== -1);\n};\n\n\n/**\n * Determine if FileSystem is supported.\n * @return {Boolean}\n */\nexports.supportsFileSystem = function() {\n if (this.isPhoneGap() === true) {\n return true;\n }\n\n // TODO: Test this works, Opera (WebKit) and Chrome\n return window.navigator.userAgent.match(/Chrome|Opera/);\n};\n\n\n/**\n * Wrap a callback for use as a success callback.\n * @param {Function} callback\n * @return {Function}\n */\nexports.wrapSuccess = function(callback) {\n return function() {\n var args = [null].concat(Array.prototype.slice.call(arguments));\n\n callback.apply(callback, args);\n };\n};\n\n\n/**\n * Wrap a callback for use as a failure callback.\n * @param {Function} callback\n * @return {Function}\n */\nexports.wrapFail = function(callback) {\n return function() {\n var args = Array.prototype.slice.call(arguments)\n , e = args[0];\n\n callback.apply(callback, [e, null]);\n };\n};\n\n\n/**\n * Check is provided path a directory.\n * @param {String} path\n * @return {Boolean}\n */\nexports.isDirectory = function(path) {\n return (path.lastIndexOf('/') === (path.length - 1));\n};\n","'use strict'\nvar Buffer = require('safe-buffer').Buffer\nvar Transform = require('readable-stream').Transform\nvar inherits = require('inherits')\n\nfunction throwIfNotStringOrBuffer (val, prefix) {\n if (!Buffer.isBuffer(val) && typeof val !== 'string') {\n throw new TypeError(prefix + ' must be a string or a buffer')\n }\n}\n\nfunction HashBase (blockSize) {\n Transform.call(this)\n\n this._block = Buffer.allocUnsafe(blockSize)\n this._blockSize = blockSize\n this._blockOffset = 0\n this._length = [0, 0, 0, 0]\n\n this._finalized = false\n}\n\ninherits(HashBase, Transform)\n\nHashBase.prototype._transform = function (chunk, encoding, callback) {\n var error = null\n try {\n this.update(chunk, encoding)\n } catch (err) {\n error = err\n }\n\n callback(error)\n}\n\nHashBase.prototype._flush = function (callback) {\n var error = null\n try {\n this.push(this.digest())\n } catch (err) {\n error = err\n }\n\n callback(error)\n}\n\nHashBase.prototype.update = function (data, encoding) {\n throwIfNotStringOrBuffer(data, 'Data')\n if (this._finalized) throw new Error('Digest already called')\n if (!Buffer.isBuffer(data)) data = Buffer.from(data, encoding)\n\n // consume data\n var block = this._block\n var offset = 0\n while (this._blockOffset + data.length - offset >= this._blockSize) {\n for (var i = this._blockOffset; i < this._blockSize;) block[i++] = data[offset++]\n this._update()\n this._blockOffset = 0\n }\n while (offset < data.length) block[this._blockOffset++] = data[offset++]\n\n // update length\n for (var j = 0, carry = data.length * 8; carry > 0; ++j) {\n this._length[j] += carry\n carry = (this._length[j] / 0x0100000000) | 0\n if (carry > 0) this._length[j] -= 0x0100000000 * carry\n }\n\n return this\n}\n\nHashBase.prototype._update = function () {\n throw new Error('_update is not implemented')\n}\n\nHashBase.prototype.digest = function (encoding) {\n if (this._finalized) throw new Error('Digest already called')\n this._finalized = true\n\n var digest = this._digest()\n if (encoding !== undefined) digest = digest.toString(encoding)\n\n // reset state\n this._block.fill(0)\n this._blockOffset = 0\n for (var i = 0; i < 4; ++i) this._length[i] = 0\n\n return digest\n}\n\nHashBase.prototype._digest = function () {\n throw new Error('_digest is not implemented')\n}\n\nmodule.exports = HashBase\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n'use strict';\n\nmodule.exports = Readable;\n/**/\n\nvar Duplex;\n/**/\n\nReadable.ReadableState = ReadableState;\n/**/\n\nvar EE = require('events').EventEmitter;\n\nvar EElistenerCount = function EElistenerCount(emitter, type) {\n return emitter.listeners(type).length;\n};\n/**/\n\n/**/\n\n\nvar Stream = require('./internal/streams/stream');\n/**/\n\n\nvar Buffer = require('buffer').Buffer;\n\nvar OurUint8Array = global.Uint8Array || function () {};\n\nfunction _uint8ArrayToBuffer(chunk) {\n return Buffer.from(chunk);\n}\n\nfunction _isUint8Array(obj) {\n return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;\n}\n/**/\n\n\nvar debugUtil = require('util');\n\nvar debug;\n\nif (debugUtil && debugUtil.debuglog) {\n debug = debugUtil.debuglog('stream');\n} else {\n debug = function debug() {};\n}\n/**/\n\n\nvar BufferList = require('./internal/streams/buffer_list');\n\nvar destroyImpl = require('./internal/streams/destroy');\n\nvar _require = require('./internal/streams/state'),\n getHighWaterMark = _require.getHighWaterMark;\n\nvar _require$codes = require('../errors').codes,\n ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE,\n ERR_STREAM_PUSH_AFTER_EOF = _require$codes.ERR_STREAM_PUSH_AFTER_EOF,\n ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,\n ERR_STREAM_UNSHIFT_AFTER_END_EVENT = _require$codes.ERR_STREAM_UNSHIFT_AFTER_END_EVENT; // Lazy loaded to improve the startup performance.\n\n\nvar StringDecoder;\nvar createReadableStreamAsyncIterator;\nvar from;\n\nrequire('inherits')(Readable, Stream);\n\nvar errorOrDestroy = destroyImpl.errorOrDestroy;\nvar kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume'];\n\nfunction prependListener(emitter, event, fn) {\n // Sadly this is not cacheable as some libraries bundle their own\n // event emitter implementation with them.\n if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn); // This is a hack to make sure that our error handler is attached before any\n // userland ones. NEVER DO THIS. This is here only because this code needs\n // to continue to work with older versions of Node.js that do not include\n // the prependListener() method. The goal is to eventually remove this hack.\n\n if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (Array.isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]];\n}\n\nfunction ReadableState(options, stream, isDuplex) {\n Duplex = Duplex || require('./_stream_duplex');\n options = options || {}; // Duplex streams are both readable and writable, but share\n // the same options object.\n // However, some cases require setting options to different\n // values for the readable and the writable sides of the duplex stream.\n // These options can be provided separately as readableXXX and writableXXX.\n\n if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag. Used to make read(n) ignore n and to\n // make all the buffer merging and length checks go away\n\n this.objectMode = !!options.objectMode;\n if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode; // the point at which it stops calling _read() to fill the buffer\n // Note: 0 is a valid value, means \"don't call _read preemptively ever\"\n\n this.highWaterMark = getHighWaterMark(this, options, 'readableHighWaterMark', isDuplex); // A linked list is used to store data chunks instead of an array because the\n // linked list can remove elements from the beginning faster than\n // array.shift()\n\n this.buffer = new BufferList();\n this.length = 0;\n this.pipes = null;\n this.pipesCount = 0;\n this.flowing = null;\n this.ended = false;\n this.endEmitted = false;\n this.reading = false; // a flag to be able to tell if the event 'readable'/'data' is emitted\n // immediately, or on a later tick. We set this to true at first, because\n // any actions that shouldn't happen until \"later\" should generally also\n // not happen before the first read call.\n\n this.sync = true; // whenever we return null, then we set a flag to say\n // that we're awaiting a 'readable' event emission.\n\n this.needReadable = false;\n this.emittedReadable = false;\n this.readableListening = false;\n this.resumeScheduled = false;\n this.paused = true; // Should close be emitted on destroy. Defaults to true.\n\n this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'end' (and potentially 'finish')\n\n this.autoDestroy = !!options.autoDestroy; // has it been destroyed\n\n this.destroyed = false; // Crypto is kind of old and crusty. Historically, its default string\n // encoding is 'binary' so we have to make this configurable.\n // Everything else in the universe uses 'utf8', though.\n\n this.defaultEncoding = options.defaultEncoding || 'utf8'; // the number of writers that are awaiting a drain event in .pipe()s\n\n this.awaitDrain = 0; // if true, a maybeReadMore has been scheduled\n\n this.readingMore = false;\n this.decoder = null;\n this.encoding = null;\n\n if (options.encoding) {\n if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;\n this.decoder = new StringDecoder(options.encoding);\n this.encoding = options.encoding;\n }\n}\n\nfunction Readable(options) {\n Duplex = Duplex || require('./_stream_duplex');\n if (!(this instanceof Readable)) return new Readable(options); // Checking for a Stream.Duplex instance is faster here instead of inside\n // the ReadableState constructor, at least with V8 6.5\n\n var isDuplex = this instanceof Duplex;\n this._readableState = new ReadableState(options, this, isDuplex); // legacy\n\n this.readable = true;\n\n if (options) {\n if (typeof options.read === 'function') this._read = options.read;\n if (typeof options.destroy === 'function') this._destroy = options.destroy;\n }\n\n Stream.call(this);\n}\n\nObject.defineProperty(Readable.prototype, 'destroyed', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n if (this._readableState === undefined) {\n return false;\n }\n\n return this._readableState.destroyed;\n },\n set: function set(value) {\n // we ignore the value if the stream\n // has not been initialized yet\n if (!this._readableState) {\n return;\n } // backward compatibility, the user is explicitly\n // managing destroyed\n\n\n this._readableState.destroyed = value;\n }\n});\nReadable.prototype.destroy = destroyImpl.destroy;\nReadable.prototype._undestroy = destroyImpl.undestroy;\n\nReadable.prototype._destroy = function (err, cb) {\n cb(err);\n}; // Manually shove something into the read() buffer.\n// This returns true if the highWaterMark has not been hit yet,\n// similar to how Writable.write() returns true if you should\n// write() some more.\n\n\nReadable.prototype.push = function (chunk, encoding) {\n var state = this._readableState;\n var skipChunkCheck;\n\n if (!state.objectMode) {\n if (typeof chunk === 'string') {\n encoding = encoding || state.defaultEncoding;\n\n if (encoding !== state.encoding) {\n chunk = Buffer.from(chunk, encoding);\n encoding = '';\n }\n\n skipChunkCheck = true;\n }\n } else {\n skipChunkCheck = true;\n }\n\n return readableAddChunk(this, chunk, encoding, false, skipChunkCheck);\n}; // Unshift should *always* be something directly out of read()\n\n\nReadable.prototype.unshift = function (chunk) {\n return readableAddChunk(this, chunk, null, true, false);\n};\n\nfunction readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) {\n debug('readableAddChunk', chunk);\n var state = stream._readableState;\n\n if (chunk === null) {\n state.reading = false;\n onEofChunk(stream, state);\n } else {\n var er;\n if (!skipChunkCheck) er = chunkInvalid(state, chunk);\n\n if (er) {\n errorOrDestroy(stream, er);\n } else if (state.objectMode || chunk && chunk.length > 0) {\n if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) {\n chunk = _uint8ArrayToBuffer(chunk);\n }\n\n if (addToFront) {\n if (state.endEmitted) errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT());else addChunk(stream, state, chunk, true);\n } else if (state.ended) {\n errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF());\n } else if (state.destroyed) {\n return false;\n } else {\n state.reading = false;\n\n if (state.decoder && !encoding) {\n chunk = state.decoder.write(chunk);\n if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state);\n } else {\n addChunk(stream, state, chunk, false);\n }\n }\n } else if (!addToFront) {\n state.reading = false;\n maybeReadMore(stream, state);\n }\n } // We can push more data if we are below the highWaterMark.\n // Also, if we have no data yet, we can stand some more bytes.\n // This is to work around cases where hwm=0, such as the repl.\n\n\n return !state.ended && (state.length < state.highWaterMark || state.length === 0);\n}\n\nfunction addChunk(stream, state, chunk, addToFront) {\n if (state.flowing && state.length === 0 && !state.sync) {\n state.awaitDrain = 0;\n stream.emit('data', chunk);\n } else {\n // update the buffer info.\n state.length += state.objectMode ? 1 : chunk.length;\n if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk);\n if (state.needReadable) emitReadable(stream);\n }\n\n maybeReadMore(stream, state);\n}\n\nfunction chunkInvalid(state, chunk) {\n var er;\n\n if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {\n er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer', 'Uint8Array'], chunk);\n }\n\n return er;\n}\n\nReadable.prototype.isPaused = function () {\n return this._readableState.flowing === false;\n}; // backwards compatibility.\n\n\nReadable.prototype.setEncoding = function (enc) {\n if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;\n var decoder = new StringDecoder(enc);\n this._readableState.decoder = decoder; // If setEncoding(null), decoder.encoding equals utf8\n\n this._readableState.encoding = this._readableState.decoder.encoding; // Iterate over current buffer to convert already stored Buffers:\n\n var p = this._readableState.buffer.head;\n var content = '';\n\n while (p !== null) {\n content += decoder.write(p.data);\n p = p.next;\n }\n\n this._readableState.buffer.clear();\n\n if (content !== '') this._readableState.buffer.push(content);\n this._readableState.length = content.length;\n return this;\n}; // Don't raise the hwm > 1GB\n\n\nvar MAX_HWM = 0x40000000;\n\nfunction computeNewHighWaterMark(n) {\n if (n >= MAX_HWM) {\n // TODO(ronag): Throw ERR_VALUE_OUT_OF_RANGE.\n n = MAX_HWM;\n } else {\n // Get the next highest power of 2 to prevent increasing hwm excessively in\n // tiny amounts\n n--;\n n |= n >>> 1;\n n |= n >>> 2;\n n |= n >>> 4;\n n |= n >>> 8;\n n |= n >>> 16;\n n++;\n }\n\n return n;\n} // This function is designed to be inlinable, so please take care when making\n// changes to the function body.\n\n\nfunction howMuchToRead(n, state) {\n if (n <= 0 || state.length === 0 && state.ended) return 0;\n if (state.objectMode) return 1;\n\n if (n !== n) {\n // Only flow one buffer at a time\n if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length;\n } // If we're asking for more than the current hwm, then raise the hwm.\n\n\n if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);\n if (n <= state.length) return n; // Don't have enough\n\n if (!state.ended) {\n state.needReadable = true;\n return 0;\n }\n\n return state.length;\n} // you can override either this method, or the async _read(n) below.\n\n\nReadable.prototype.read = function (n) {\n debug('read', n);\n n = parseInt(n, 10);\n var state = this._readableState;\n var nOrig = n;\n if (n !== 0) state.emittedReadable = false; // if we're doing read(0) to trigger a readable event, but we\n // already have a bunch of data in the buffer, then just trigger\n // the 'readable' event and move on.\n\n if (n === 0 && state.needReadable && ((state.highWaterMark !== 0 ? state.length >= state.highWaterMark : state.length > 0) || state.ended)) {\n debug('read: emitReadable', state.length, state.ended);\n if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this);\n return null;\n }\n\n n = howMuchToRead(n, state); // if we've ended, and we're now clear, then finish it up.\n\n if (n === 0 && state.ended) {\n if (state.length === 0) endReadable(this);\n return null;\n } // All the actual chunk generation logic needs to be\n // *below* the call to _read. The reason is that in certain\n // synthetic stream cases, such as passthrough streams, _read\n // may be a completely synchronous operation which may change\n // the state of the read buffer, providing enough data when\n // before there was *not* enough.\n //\n // So, the steps are:\n // 1. Figure out what the state of things will be after we do\n // a read from the buffer.\n //\n // 2. If that resulting state will trigger a _read, then call _read.\n // Note that this may be asynchronous, or synchronous. Yes, it is\n // deeply ugly to write APIs this way, but that still doesn't mean\n // that the Readable class should behave improperly, as streams are\n // designed to be sync/async agnostic.\n // Take note if the _read call is sync or async (ie, if the read call\n // has returned yet), so that we know whether or not it's safe to emit\n // 'readable' etc.\n //\n // 3. Actually pull the requested chunks out of the buffer and return.\n // if we need a readable event, then we need to do some reading.\n\n\n var doRead = state.needReadable;\n debug('need readable', doRead); // if we currently have less than the highWaterMark, then also read some\n\n if (state.length === 0 || state.length - n < state.highWaterMark) {\n doRead = true;\n debug('length less than watermark', doRead);\n } // however, if we've ended, then there's no point, and if we're already\n // reading, then it's unnecessary.\n\n\n if (state.ended || state.reading) {\n doRead = false;\n debug('reading or ended', doRead);\n } else if (doRead) {\n debug('do read');\n state.reading = true;\n state.sync = true; // if the length is currently zero, then we *need* a readable event.\n\n if (state.length === 0) state.needReadable = true; // call internal read method\n\n this._read(state.highWaterMark);\n\n state.sync = false; // If _read pushed data synchronously, then `reading` will be false,\n // and we need to re-evaluate how much data we can return to the user.\n\n if (!state.reading) n = howMuchToRead(nOrig, state);\n }\n\n var ret;\n if (n > 0) ret = fromList(n, state);else ret = null;\n\n if (ret === null) {\n state.needReadable = state.length <= state.highWaterMark;\n n = 0;\n } else {\n state.length -= n;\n state.awaitDrain = 0;\n }\n\n if (state.length === 0) {\n // If we have nothing in the buffer, then we want to know\n // as soon as we *do* get something into the buffer.\n if (!state.ended) state.needReadable = true; // If we tried to read() past the EOF, then emit end on the next tick.\n\n if (nOrig !== n && state.ended) endReadable(this);\n }\n\n if (ret !== null) this.emit('data', ret);\n return ret;\n};\n\nfunction onEofChunk(stream, state) {\n debug('onEofChunk');\n if (state.ended) return;\n\n if (state.decoder) {\n var chunk = state.decoder.end();\n\n if (chunk && chunk.length) {\n state.buffer.push(chunk);\n state.length += state.objectMode ? 1 : chunk.length;\n }\n }\n\n state.ended = true;\n\n if (state.sync) {\n // if we are sync, wait until next tick to emit the data.\n // Otherwise we risk emitting data in the flow()\n // the readable code triggers during a read() call\n emitReadable(stream);\n } else {\n // emit 'readable' now to make sure it gets picked up.\n state.needReadable = false;\n\n if (!state.emittedReadable) {\n state.emittedReadable = true;\n emitReadable_(stream);\n }\n }\n} // Don't emit readable right away in sync mode, because this can trigger\n// another read() call => stack overflow. This way, it might trigger\n// a nextTick recursion warning, but that's not so bad.\n\n\nfunction emitReadable(stream) {\n var state = stream._readableState;\n debug('emitReadable', state.needReadable, state.emittedReadable);\n state.needReadable = false;\n\n if (!state.emittedReadable) {\n debug('emitReadable', state.flowing);\n state.emittedReadable = true;\n process.nextTick(emitReadable_, stream);\n }\n}\n\nfunction emitReadable_(stream) {\n var state = stream._readableState;\n debug('emitReadable_', state.destroyed, state.length, state.ended);\n\n if (!state.destroyed && (state.length || state.ended)) {\n stream.emit('readable');\n state.emittedReadable = false;\n } // The stream needs another readable event if\n // 1. It is not flowing, as the flow mechanism will take\n // care of it.\n // 2. It is not ended.\n // 3. It is below the highWaterMark, so we can schedule\n // another readable later.\n\n\n state.needReadable = !state.flowing && !state.ended && state.length <= state.highWaterMark;\n flow(stream);\n} // at this point, the user has presumably seen the 'readable' event,\n// and called read() to consume some data. that may have triggered\n// in turn another _read(n) call, in which case reading = true if\n// it's in progress.\n// However, if we're not ended, or reading, and the length < hwm,\n// then go ahead and try to read some more preemptively.\n\n\nfunction maybeReadMore(stream, state) {\n if (!state.readingMore) {\n state.readingMore = true;\n process.nextTick(maybeReadMore_, stream, state);\n }\n}\n\nfunction maybeReadMore_(stream, state) {\n // Attempt to read more data if we should.\n //\n // The conditions for reading more data are (one of):\n // - Not enough data buffered (state.length < state.highWaterMark). The loop\n // is responsible for filling the buffer with enough data if such data\n // is available. If highWaterMark is 0 and we are not in the flowing mode\n // we should _not_ attempt to buffer any extra data. We'll get more data\n // when the stream consumer calls read() instead.\n // - No data in the buffer, and the stream is in flowing mode. In this mode\n // the loop below is responsible for ensuring read() is called. Failing to\n // call read here would abort the flow and there's no other mechanism for\n // continuing the flow if the stream consumer has just subscribed to the\n // 'data' event.\n //\n // In addition to the above conditions to keep reading data, the following\n // conditions prevent the data from being read:\n // - The stream has ended (state.ended).\n // - There is already a pending 'read' operation (state.reading). This is a\n // case where the the stream has called the implementation defined _read()\n // method, but they are processing the call asynchronously and have _not_\n // called push() with new data. In this case we skip performing more\n // read()s. The execution ends in this method again after the _read() ends\n // up calling push() with more data.\n while (!state.reading && !state.ended && (state.length < state.highWaterMark || state.flowing && state.length === 0)) {\n var len = state.length;\n debug('maybeReadMore read 0');\n stream.read(0);\n if (len === state.length) // didn't get any data, stop spinning.\n break;\n }\n\n state.readingMore = false;\n} // abstract method. to be overridden in specific implementation classes.\n// call cb(er, data) where data is <= n in length.\n// for virtual (non-string, non-buffer) streams, \"length\" is somewhat\n// arbitrary, and perhaps not very meaningful.\n\n\nReadable.prototype._read = function (n) {\n errorOrDestroy(this, new ERR_METHOD_NOT_IMPLEMENTED('_read()'));\n};\n\nReadable.prototype.pipe = function (dest, pipeOpts) {\n var src = this;\n var state = this._readableState;\n\n switch (state.pipesCount) {\n case 0:\n state.pipes = dest;\n break;\n\n case 1:\n state.pipes = [state.pipes, dest];\n break;\n\n default:\n state.pipes.push(dest);\n break;\n }\n\n state.pipesCount += 1;\n debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);\n var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr;\n var endFn = doEnd ? onend : unpipe;\n if (state.endEmitted) process.nextTick(endFn);else src.once('end', endFn);\n dest.on('unpipe', onunpipe);\n\n function onunpipe(readable, unpipeInfo) {\n debug('onunpipe');\n\n if (readable === src) {\n if (unpipeInfo && unpipeInfo.hasUnpiped === false) {\n unpipeInfo.hasUnpiped = true;\n cleanup();\n }\n }\n }\n\n function onend() {\n debug('onend');\n dest.end();\n } // when the dest drains, it reduces the awaitDrain counter\n // on the source. This would be more elegant with a .once()\n // handler in flow(), but adding and removing repeatedly is\n // too slow.\n\n\n var ondrain = pipeOnDrain(src);\n dest.on('drain', ondrain);\n var cleanedUp = false;\n\n function cleanup() {\n debug('cleanup'); // cleanup event handlers once the pipe is broken\n\n dest.removeListener('close', onclose);\n dest.removeListener('finish', onfinish);\n dest.removeListener('drain', ondrain);\n dest.removeListener('error', onerror);\n dest.removeListener('unpipe', onunpipe);\n src.removeListener('end', onend);\n src.removeListener('end', unpipe);\n src.removeListener('data', ondata);\n cleanedUp = true; // if the reader is waiting for a drain event from this\n // specific writer, then it would cause it to never start\n // flowing again.\n // So, if this is awaiting a drain, then we just call it now.\n // If we don't know, then assume that we are waiting for one.\n\n if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();\n }\n\n src.on('data', ondata);\n\n function ondata(chunk) {\n debug('ondata');\n var ret = dest.write(chunk);\n debug('dest.write', ret);\n\n if (ret === false) {\n // If the user unpiped during `dest.write()`, it is possible\n // to get stuck in a permanently paused state if that write\n // also returned false.\n // => Check whether `dest` is still a piping destination.\n if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {\n debug('false write response, pause', state.awaitDrain);\n state.awaitDrain++;\n }\n\n src.pause();\n }\n } // if the dest has an error, then stop piping into it.\n // however, don't suppress the throwing behavior for this.\n\n\n function onerror(er) {\n debug('onerror', er);\n unpipe();\n dest.removeListener('error', onerror);\n if (EElistenerCount(dest, 'error') === 0) errorOrDestroy(dest, er);\n } // Make sure our error handler is attached before userland ones.\n\n\n prependListener(dest, 'error', onerror); // Both close and finish should trigger unpipe, but only once.\n\n function onclose() {\n dest.removeListener('finish', onfinish);\n unpipe();\n }\n\n dest.once('close', onclose);\n\n function onfinish() {\n debug('onfinish');\n dest.removeListener('close', onclose);\n unpipe();\n }\n\n dest.once('finish', onfinish);\n\n function unpipe() {\n debug('unpipe');\n src.unpipe(dest);\n } // tell the dest that it's being piped to\n\n\n dest.emit('pipe', src); // start the flow if it hasn't been started already.\n\n if (!state.flowing) {\n debug('pipe resume');\n src.resume();\n }\n\n return dest;\n};\n\nfunction pipeOnDrain(src) {\n return function pipeOnDrainFunctionResult() {\n var state = src._readableState;\n debug('pipeOnDrain', state.awaitDrain);\n if (state.awaitDrain) state.awaitDrain--;\n\n if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) {\n state.flowing = true;\n flow(src);\n }\n };\n}\n\nReadable.prototype.unpipe = function (dest) {\n var state = this._readableState;\n var unpipeInfo = {\n hasUnpiped: false\n }; // if we're not piping anywhere, then do nothing.\n\n if (state.pipesCount === 0) return this; // just one destination. most common case.\n\n if (state.pipesCount === 1) {\n // passed in one, but it's not the right one.\n if (dest && dest !== state.pipes) return this;\n if (!dest) dest = state.pipes; // got a match.\n\n state.pipes = null;\n state.pipesCount = 0;\n state.flowing = false;\n if (dest) dest.emit('unpipe', this, unpipeInfo);\n return this;\n } // slow case. multiple pipe destinations.\n\n\n if (!dest) {\n // remove all.\n var dests = state.pipes;\n var len = state.pipesCount;\n state.pipes = null;\n state.pipesCount = 0;\n state.flowing = false;\n\n for (var i = 0; i < len; i++) {\n dests[i].emit('unpipe', this, {\n hasUnpiped: false\n });\n }\n\n return this;\n } // try to find the right one.\n\n\n var index = indexOf(state.pipes, dest);\n if (index === -1) return this;\n state.pipes.splice(index, 1);\n state.pipesCount -= 1;\n if (state.pipesCount === 1) state.pipes = state.pipes[0];\n dest.emit('unpipe', this, unpipeInfo);\n return this;\n}; // set up data events if they are asked for\n// Ensure readable listeners eventually get something\n\n\nReadable.prototype.on = function (ev, fn) {\n var res = Stream.prototype.on.call(this, ev, fn);\n var state = this._readableState;\n\n if (ev === 'data') {\n // update readableListening so that resume() may be a no-op\n // a few lines down. This is needed to support once('readable').\n state.readableListening = this.listenerCount('readable') > 0; // Try start flowing on next tick if stream isn't explicitly paused\n\n if (state.flowing !== false) this.resume();\n } else if (ev === 'readable') {\n if (!state.endEmitted && !state.readableListening) {\n state.readableListening = state.needReadable = true;\n state.flowing = false;\n state.emittedReadable = false;\n debug('on readable', state.length, state.reading);\n\n if (state.length) {\n emitReadable(this);\n } else if (!state.reading) {\n process.nextTick(nReadingNextTick, this);\n }\n }\n }\n\n return res;\n};\n\nReadable.prototype.addListener = Readable.prototype.on;\n\nReadable.prototype.removeListener = function (ev, fn) {\n var res = Stream.prototype.removeListener.call(this, ev, fn);\n\n if (ev === 'readable') {\n // We need to check if there is someone still listening to\n // readable and reset the state. However this needs to happen\n // after readable has been emitted but before I/O (nextTick) to\n // support once('readable', fn) cycles. This means that calling\n // resume within the same tick will have no\n // effect.\n process.nextTick(updateReadableListening, this);\n }\n\n return res;\n};\n\nReadable.prototype.removeAllListeners = function (ev) {\n var res = Stream.prototype.removeAllListeners.apply(this, arguments);\n\n if (ev === 'readable' || ev === undefined) {\n // We need to check if there is someone still listening to\n // readable and reset the state. However this needs to happen\n // after readable has been emitted but before I/O (nextTick) to\n // support once('readable', fn) cycles. This means that calling\n // resume within the same tick will have no\n // effect.\n process.nextTick(updateReadableListening, this);\n }\n\n return res;\n};\n\nfunction updateReadableListening(self) {\n var state = self._readableState;\n state.readableListening = self.listenerCount('readable') > 0;\n\n if (state.resumeScheduled && !state.paused) {\n // flowing needs to be set to true now, otherwise\n // the upcoming resume will not flow.\n state.flowing = true; // crude way to check if we should resume\n } else if (self.listenerCount('data') > 0) {\n self.resume();\n }\n}\n\nfunction nReadingNextTick(self) {\n debug('readable nexttick read 0');\n self.read(0);\n} // pause() and resume() are remnants of the legacy readable stream API\n// If the user uses them, then switch into old mode.\n\n\nReadable.prototype.resume = function () {\n var state = this._readableState;\n\n if (!state.flowing) {\n debug('resume'); // we flow only if there is no one listening\n // for readable, but we still have to call\n // resume()\n\n state.flowing = !state.readableListening;\n resume(this, state);\n }\n\n state.paused = false;\n return this;\n};\n\nfunction resume(stream, state) {\n if (!state.resumeScheduled) {\n state.resumeScheduled = true;\n process.nextTick(resume_, stream, state);\n }\n}\n\nfunction resume_(stream, state) {\n debug('resume', state.reading);\n\n if (!state.reading) {\n stream.read(0);\n }\n\n state.resumeScheduled = false;\n stream.emit('resume');\n flow(stream);\n if (state.flowing && !state.reading) stream.read(0);\n}\n\nReadable.prototype.pause = function () {\n debug('call pause flowing=%j', this._readableState.flowing);\n\n if (this._readableState.flowing !== false) {\n debug('pause');\n this._readableState.flowing = false;\n this.emit('pause');\n }\n\n this._readableState.paused = true;\n return this;\n};\n\nfunction flow(stream) {\n var state = stream._readableState;\n debug('flow', state.flowing);\n\n while (state.flowing && stream.read() !== null) {\n ;\n }\n} // wrap an old-style stream as the async data source.\n// This is *not* part of the readable stream interface.\n// It is an ugly unfortunate mess of history.\n\n\nReadable.prototype.wrap = function (stream) {\n var _this = this;\n\n var state = this._readableState;\n var paused = false;\n stream.on('end', function () {\n debug('wrapped end');\n\n if (state.decoder && !state.ended) {\n var chunk = state.decoder.end();\n if (chunk && chunk.length) _this.push(chunk);\n }\n\n _this.push(null);\n });\n stream.on('data', function (chunk) {\n debug('wrapped data');\n if (state.decoder) chunk = state.decoder.write(chunk); // don't skip over falsy values in objectMode\n\n if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return;\n\n var ret = _this.push(chunk);\n\n if (!ret) {\n paused = true;\n stream.pause();\n }\n }); // proxy all the other methods.\n // important when wrapping filters and duplexes.\n\n for (var i in stream) {\n if (this[i] === undefined && typeof stream[i] === 'function') {\n this[i] = function methodWrap(method) {\n return function methodWrapReturnFunction() {\n return stream[method].apply(stream, arguments);\n };\n }(i);\n }\n } // proxy certain important events.\n\n\n for (var n = 0; n < kProxyEvents.length; n++) {\n stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n]));\n } // when we try to consume some more bytes, simply unpause the\n // underlying stream.\n\n\n this._read = function (n) {\n debug('wrapped _read', n);\n\n if (paused) {\n paused = false;\n stream.resume();\n }\n };\n\n return this;\n};\n\nif (typeof Symbol === 'function') {\n Readable.prototype[Symbol.asyncIterator] = function () {\n if (createReadableStreamAsyncIterator === undefined) {\n createReadableStreamAsyncIterator = require('./internal/streams/async_iterator');\n }\n\n return createReadableStreamAsyncIterator(this);\n };\n}\n\nObject.defineProperty(Readable.prototype, 'readableHighWaterMark', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._readableState.highWaterMark;\n }\n});\nObject.defineProperty(Readable.prototype, 'readableBuffer', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._readableState && this._readableState.buffer;\n }\n});\nObject.defineProperty(Readable.prototype, 'readableFlowing', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._readableState.flowing;\n },\n set: function set(state) {\n if (this._readableState) {\n this._readableState.flowing = state;\n }\n }\n}); // exposed for testing purposes only.\n\nReadable._fromList = fromList;\nObject.defineProperty(Readable.prototype, 'readableLength', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._readableState.length;\n }\n}); // Pluck off n bytes from an array of buffers.\n// Length is the combined lengths of all the buffers in the list.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\n\nfunction fromList(n, state) {\n // nothing buffered\n if (state.length === 0) return null;\n var ret;\n if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) {\n // read it all, truncate the list\n if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.first();else ret = state.buffer.concat(state.length);\n state.buffer.clear();\n } else {\n // read part of list\n ret = state.buffer.consume(n, state.decoder);\n }\n return ret;\n}\n\nfunction endReadable(stream) {\n var state = stream._readableState;\n debug('endReadable', state.endEmitted);\n\n if (!state.endEmitted) {\n state.ended = true;\n process.nextTick(endReadableNT, state, stream);\n }\n}\n\nfunction endReadableNT(state, stream) {\n debug('endReadableNT', state.endEmitted, state.length); // Check that we didn't get one last unshift.\n\n if (!state.endEmitted && state.length === 0) {\n state.endEmitted = true;\n stream.readable = false;\n stream.emit('end');\n\n if (state.autoDestroy) {\n // In case of duplex streams we need a way to detect\n // if the writable side is ready for autoDestroy as well\n var wState = stream._writableState;\n\n if (!wState || wState.autoDestroy && wState.finished) {\n stream.destroy();\n }\n }\n }\n}\n\nif (typeof Symbol === 'function') {\n Readable.from = function (iterable, opts) {\n if (from === undefined) {\n from = require('./internal/streams/from');\n }\n\n return from(Readable, iterable, opts);\n };\n}\n\nfunction indexOf(xs, x) {\n for (var i = 0, l = xs.length; i < l; i++) {\n if (xs[i] === x) return i;\n }\n\n return -1;\n}","module.exports = require('events').EventEmitter;\n","'use strict'; // undocumented cb() API, needed for core, not for public API\n\nfunction destroy(err, cb) {\n var _this = this;\n\n var readableDestroyed = this._readableState && this._readableState.destroyed;\n var writableDestroyed = this._writableState && this._writableState.destroyed;\n\n if (readableDestroyed || writableDestroyed) {\n if (cb) {\n cb(err);\n } else if (err) {\n if (!this._writableState) {\n process.nextTick(emitErrorNT, this, err);\n } else if (!this._writableState.errorEmitted) {\n this._writableState.errorEmitted = true;\n process.nextTick(emitErrorNT, this, err);\n }\n }\n\n return this;\n } // we set destroyed to true before firing error callbacks in order\n // to make it re-entrance safe in case destroy() is called within callbacks\n\n\n if (this._readableState) {\n this._readableState.destroyed = true;\n } // if this is a duplex stream mark the writable part as destroyed as well\n\n\n if (this._writableState) {\n this._writableState.destroyed = true;\n }\n\n this._destroy(err || null, function (err) {\n if (!cb && err) {\n if (!_this._writableState) {\n process.nextTick(emitErrorAndCloseNT, _this, err);\n } else if (!_this._writableState.errorEmitted) {\n _this._writableState.errorEmitted = true;\n process.nextTick(emitErrorAndCloseNT, _this, err);\n } else {\n process.nextTick(emitCloseNT, _this);\n }\n } else if (cb) {\n process.nextTick(emitCloseNT, _this);\n cb(err);\n } else {\n process.nextTick(emitCloseNT, _this);\n }\n });\n\n return this;\n}\n\nfunction emitErrorAndCloseNT(self, err) {\n emitErrorNT(self, err);\n emitCloseNT(self);\n}\n\nfunction emitCloseNT(self) {\n if (self._writableState && !self._writableState.emitClose) return;\n if (self._readableState && !self._readableState.emitClose) return;\n self.emit('close');\n}\n\nfunction undestroy() {\n if (this._readableState) {\n this._readableState.destroyed = false;\n this._readableState.reading = false;\n this._readableState.ended = false;\n this._readableState.endEmitted = false;\n }\n\n if (this._writableState) {\n this._writableState.destroyed = false;\n this._writableState.ended = false;\n this._writableState.ending = false;\n this._writableState.finalCalled = false;\n this._writableState.prefinished = false;\n this._writableState.finished = false;\n this._writableState.errorEmitted = false;\n }\n}\n\nfunction emitErrorNT(self, err) {\n self.emit('error', err);\n}\n\nfunction errorOrDestroy(stream, err) {\n // We have tests that rely on errors being emitted\n // in the same tick, so changing this is semver major.\n // For now when you opt-in to autoDestroy we allow\n // the error to be emitted nextTick. In a future\n // semver major update we should change the default to this.\n var rState = stream._readableState;\n var wState = stream._writableState;\n if (rState && rState.autoDestroy || wState && wState.autoDestroy) stream.destroy(err);else stream.emit('error', err);\n}\n\nmodule.exports = {\n destroy: destroy,\n undestroy: undestroy,\n errorOrDestroy: errorOrDestroy\n};","'use strict';\n\nvar ERR_INVALID_OPT_VALUE = require('../../../errors').codes.ERR_INVALID_OPT_VALUE;\n\nfunction highWaterMarkFrom(options, isDuplex, duplexKey) {\n return options.highWaterMark != null ? options.highWaterMark : isDuplex ? options[duplexKey] : null;\n}\n\nfunction getHighWaterMark(state, options, duplexKey, isDuplex) {\n var hwm = highWaterMarkFrom(options, isDuplex, duplexKey);\n\n if (hwm != null) {\n if (!(isFinite(hwm) && Math.floor(hwm) === hwm) || hwm < 0) {\n var name = isDuplex ? duplexKey : 'highWaterMark';\n throw new ERR_INVALID_OPT_VALUE(name, hwm);\n }\n\n return Math.floor(hwm);\n } // Default value\n\n\n return state.objectMode ? 16 : 16 * 1024;\n}\n\nmodule.exports = {\n getHighWaterMark: getHighWaterMark\n};","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n// A bit simpler than readable streams.\n// Implement an async ._write(chunk, encoding, cb), and it'll handle all\n// the drain event emission and buffering.\n'use strict';\n\nmodule.exports = Writable;\n/* */\n\nfunction WriteReq(chunk, encoding, cb) {\n this.chunk = chunk;\n this.encoding = encoding;\n this.callback = cb;\n this.next = null;\n} // It seems a linked list but it is not\n// there will be only 2 of these for each stream\n\n\nfunction CorkedRequest(state) {\n var _this = this;\n\n this.next = null;\n this.entry = null;\n\n this.finish = function () {\n onCorkedFinish(_this, state);\n };\n}\n/* */\n\n/**/\n\n\nvar Duplex;\n/**/\n\nWritable.WritableState = WritableState;\n/**/\n\nvar internalUtil = {\n deprecate: require('util-deprecate')\n};\n/**/\n\n/**/\n\nvar Stream = require('./internal/streams/stream');\n/**/\n\n\nvar Buffer = require('buffer').Buffer;\n\nvar OurUint8Array = global.Uint8Array || function () {};\n\nfunction _uint8ArrayToBuffer(chunk) {\n return Buffer.from(chunk);\n}\n\nfunction _isUint8Array(obj) {\n return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;\n}\n\nvar destroyImpl = require('./internal/streams/destroy');\n\nvar _require = require('./internal/streams/state'),\n getHighWaterMark = _require.getHighWaterMark;\n\nvar _require$codes = require('../errors').codes,\n ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE,\n ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,\n ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK,\n ERR_STREAM_CANNOT_PIPE = _require$codes.ERR_STREAM_CANNOT_PIPE,\n ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED,\n ERR_STREAM_NULL_VALUES = _require$codes.ERR_STREAM_NULL_VALUES,\n ERR_STREAM_WRITE_AFTER_END = _require$codes.ERR_STREAM_WRITE_AFTER_END,\n ERR_UNKNOWN_ENCODING = _require$codes.ERR_UNKNOWN_ENCODING;\n\nvar errorOrDestroy = destroyImpl.errorOrDestroy;\n\nrequire('inherits')(Writable, Stream);\n\nfunction nop() {}\n\nfunction WritableState(options, stream, isDuplex) {\n Duplex = Duplex || require('./_stream_duplex');\n options = options || {}; // Duplex streams are both readable and writable, but share\n // the same options object.\n // However, some cases require setting options to different\n // values for the readable and the writable sides of the duplex stream,\n // e.g. options.readableObjectMode vs. options.writableObjectMode, etc.\n\n if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag to indicate whether or not this stream\n // contains buffers or objects.\n\n this.objectMode = !!options.objectMode;\n if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode; // the point at which write() starts returning false\n // Note: 0 is a valid value, means that we always return false if\n // the entire buffer is not flushed immediately on write()\n\n this.highWaterMark = getHighWaterMark(this, options, 'writableHighWaterMark', isDuplex); // if _final has been called\n\n this.finalCalled = false; // drain event flag.\n\n this.needDrain = false; // at the start of calling end()\n\n this.ending = false; // when end() has been called, and returned\n\n this.ended = false; // when 'finish' is emitted\n\n this.finished = false; // has it been destroyed\n\n this.destroyed = false; // should we decode strings into buffers before passing to _write?\n // this is here so that some node-core streams can optimize string\n // handling at a lower level.\n\n var noDecode = options.decodeStrings === false;\n this.decodeStrings = !noDecode; // Crypto is kind of old and crusty. Historically, its default string\n // encoding is 'binary' so we have to make this configurable.\n // Everything else in the universe uses 'utf8', though.\n\n this.defaultEncoding = options.defaultEncoding || 'utf8'; // not an actual buffer we keep track of, but a measurement\n // of how much we're waiting to get pushed to some underlying\n // socket or file.\n\n this.length = 0; // a flag to see when we're in the middle of a write.\n\n this.writing = false; // when true all writes will be buffered until .uncork() call\n\n this.corked = 0; // a flag to be able to tell if the onwrite cb is called immediately,\n // or on a later tick. We set this to true at first, because any\n // actions that shouldn't happen until \"later\" should generally also\n // not happen before the first write call.\n\n this.sync = true; // a flag to know if we're processing previously buffered items, which\n // may call the _write() callback in the same tick, so that we don't\n // end up in an overlapped onwrite situation.\n\n this.bufferProcessing = false; // the callback that's passed to _write(chunk,cb)\n\n this.onwrite = function (er) {\n onwrite(stream, er);\n }; // the callback that the user supplies to write(chunk,encoding,cb)\n\n\n this.writecb = null; // the amount that is being written when _write is called.\n\n this.writelen = 0;\n this.bufferedRequest = null;\n this.lastBufferedRequest = null; // number of pending user-supplied write callbacks\n // this must be 0 before 'finish' can be emitted\n\n this.pendingcb = 0; // emit prefinish if the only thing we're waiting for is _write cbs\n // This is relevant for synchronous Transform streams\n\n this.prefinished = false; // True if the error was already emitted and should not be thrown again\n\n this.errorEmitted = false; // Should close be emitted on destroy. Defaults to true.\n\n this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'finish' (and potentially 'end')\n\n this.autoDestroy = !!options.autoDestroy; // count buffered requests\n\n this.bufferedRequestCount = 0; // allocate the first CorkedRequest, there is always\n // one allocated and free to use, and we maintain at most two\n\n this.corkedRequestsFree = new CorkedRequest(this);\n}\n\nWritableState.prototype.getBuffer = function getBuffer() {\n var current = this.bufferedRequest;\n var out = [];\n\n while (current) {\n out.push(current);\n current = current.next;\n }\n\n return out;\n};\n\n(function () {\n try {\n Object.defineProperty(WritableState.prototype, 'buffer', {\n get: internalUtil.deprecate(function writableStateBufferGetter() {\n return this.getBuffer();\n }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003')\n });\n } catch (_) {}\n})(); // Test _writableState for inheritance to account for Duplex streams,\n// whose prototype chain only points to Readable.\n\n\nvar realHasInstance;\n\nif (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') {\n realHasInstance = Function.prototype[Symbol.hasInstance];\n Object.defineProperty(Writable, Symbol.hasInstance, {\n value: function value(object) {\n if (realHasInstance.call(this, object)) return true;\n if (this !== Writable) return false;\n return object && object._writableState instanceof WritableState;\n }\n });\n} else {\n realHasInstance = function realHasInstance(object) {\n return object instanceof this;\n };\n}\n\nfunction Writable(options) {\n Duplex = Duplex || require('./_stream_duplex'); // Writable ctor is applied to Duplexes, too.\n // `realHasInstance` is necessary because using plain `instanceof`\n // would return false, as no `_writableState` property is attached.\n // Trying to use the custom `instanceof` for Writable here will also break the\n // Node.js LazyTransform implementation, which has a non-trivial getter for\n // `_writableState` that would lead to infinite recursion.\n // Checking for a Stream.Duplex instance is faster here instead of inside\n // the WritableState constructor, at least with V8 6.5\n\n var isDuplex = this instanceof Duplex;\n if (!isDuplex && !realHasInstance.call(Writable, this)) return new Writable(options);\n this._writableState = new WritableState(options, this, isDuplex); // legacy.\n\n this.writable = true;\n\n if (options) {\n if (typeof options.write === 'function') this._write = options.write;\n if (typeof options.writev === 'function') this._writev = options.writev;\n if (typeof options.destroy === 'function') this._destroy = options.destroy;\n if (typeof options.final === 'function') this._final = options.final;\n }\n\n Stream.call(this);\n} // Otherwise people can pipe Writable streams, which is just wrong.\n\n\nWritable.prototype.pipe = function () {\n errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE());\n};\n\nfunction writeAfterEnd(stream, cb) {\n var er = new ERR_STREAM_WRITE_AFTER_END(); // TODO: defer error events consistently everywhere, not just the cb\n\n errorOrDestroy(stream, er);\n process.nextTick(cb, er);\n} // Checks that a user-supplied chunk is valid, especially for the particular\n// mode the stream is in. Currently this means that `null` is never accepted\n// and undefined/non-string values are only allowed in object mode.\n\n\nfunction validChunk(stream, state, chunk, cb) {\n var er;\n\n if (chunk === null) {\n er = new ERR_STREAM_NULL_VALUES();\n } else if (typeof chunk !== 'string' && !state.objectMode) {\n er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk);\n }\n\n if (er) {\n errorOrDestroy(stream, er);\n process.nextTick(cb, er);\n return false;\n }\n\n return true;\n}\n\nWritable.prototype.write = function (chunk, encoding, cb) {\n var state = this._writableState;\n var ret = false;\n\n var isBuf = !state.objectMode && _isUint8Array(chunk);\n\n if (isBuf && !Buffer.isBuffer(chunk)) {\n chunk = _uint8ArrayToBuffer(chunk);\n }\n\n if (typeof encoding === 'function') {\n cb = encoding;\n encoding = null;\n }\n\n if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;\n if (typeof cb !== 'function') cb = nop;\n if (state.ending) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) {\n state.pendingcb++;\n ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);\n }\n return ret;\n};\n\nWritable.prototype.cork = function () {\n this._writableState.corked++;\n};\n\nWritable.prototype.uncork = function () {\n var state = this._writableState;\n\n if (state.corked) {\n state.corked--;\n if (!state.writing && !state.corked && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);\n }\n};\n\nWritable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {\n // node::ParseEncoding() requires lower case.\n if (typeof encoding === 'string') encoding = encoding.toLowerCase();\n if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new ERR_UNKNOWN_ENCODING(encoding);\n this._writableState.defaultEncoding = encoding;\n return this;\n};\n\nObject.defineProperty(Writable.prototype, 'writableBuffer', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._writableState && this._writableState.getBuffer();\n }\n});\n\nfunction decodeChunk(state, chunk, encoding) {\n if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {\n chunk = Buffer.from(chunk, encoding);\n }\n\n return chunk;\n}\n\nObject.defineProperty(Writable.prototype, 'writableHighWaterMark', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._writableState.highWaterMark;\n }\n}); // if we're already writing something, then just put this\n// in the queue, and wait our turn. Otherwise, call _write\n// If we return false, then we need a drain event, so set that flag.\n\nfunction writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {\n if (!isBuf) {\n var newChunk = decodeChunk(state, chunk, encoding);\n\n if (chunk !== newChunk) {\n isBuf = true;\n encoding = 'buffer';\n chunk = newChunk;\n }\n }\n\n var len = state.objectMode ? 1 : chunk.length;\n state.length += len;\n var ret = state.length < state.highWaterMark; // we must ensure that previous needDrain will not be reset to false.\n\n if (!ret) state.needDrain = true;\n\n if (state.writing || state.corked) {\n var last = state.lastBufferedRequest;\n state.lastBufferedRequest = {\n chunk: chunk,\n encoding: encoding,\n isBuf: isBuf,\n callback: cb,\n next: null\n };\n\n if (last) {\n last.next = state.lastBufferedRequest;\n } else {\n state.bufferedRequest = state.lastBufferedRequest;\n }\n\n state.bufferedRequestCount += 1;\n } else {\n doWrite(stream, state, false, len, chunk, encoding, cb);\n }\n\n return ret;\n}\n\nfunction doWrite(stream, state, writev, len, chunk, encoding, cb) {\n state.writelen = len;\n state.writecb = cb;\n state.writing = true;\n state.sync = true;\n if (state.destroyed) state.onwrite(new ERR_STREAM_DESTROYED('write'));else if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);\n state.sync = false;\n}\n\nfunction onwriteError(stream, state, sync, er, cb) {\n --state.pendingcb;\n\n if (sync) {\n // defer the callback if we are being called synchronously\n // to avoid piling up things on the stack\n process.nextTick(cb, er); // this can emit finish, and it will always happen\n // after error\n\n process.nextTick(finishMaybe, stream, state);\n stream._writableState.errorEmitted = true;\n errorOrDestroy(stream, er);\n } else {\n // the caller expect this to happen before if\n // it is async\n cb(er);\n stream._writableState.errorEmitted = true;\n errorOrDestroy(stream, er); // this can emit finish, but finish must\n // always follow error\n\n finishMaybe(stream, state);\n }\n}\n\nfunction onwriteStateUpdate(state) {\n state.writing = false;\n state.writecb = null;\n state.length -= state.writelen;\n state.writelen = 0;\n}\n\nfunction onwrite(stream, er) {\n var state = stream._writableState;\n var sync = state.sync;\n var cb = state.writecb;\n if (typeof cb !== 'function') throw new ERR_MULTIPLE_CALLBACK();\n onwriteStateUpdate(state);\n if (er) onwriteError(stream, state, sync, er, cb);else {\n // Check if we're actually ready to finish, but don't emit yet\n var finished = needFinish(state) || stream.destroyed;\n\n if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {\n clearBuffer(stream, state);\n }\n\n if (sync) {\n process.nextTick(afterWrite, stream, state, finished, cb);\n } else {\n afterWrite(stream, state, finished, cb);\n }\n }\n}\n\nfunction afterWrite(stream, state, finished, cb) {\n if (!finished) onwriteDrain(stream, state);\n state.pendingcb--;\n cb();\n finishMaybe(stream, state);\n} // Must force callback to be called on nextTick, so that we don't\n// emit 'drain' before the write() consumer gets the 'false' return\n// value, and has a chance to attach a 'drain' listener.\n\n\nfunction onwriteDrain(stream, state) {\n if (state.length === 0 && state.needDrain) {\n state.needDrain = false;\n stream.emit('drain');\n }\n} // if there's something in the buffer waiting, then process it\n\n\nfunction clearBuffer(stream, state) {\n state.bufferProcessing = true;\n var entry = state.bufferedRequest;\n\n if (stream._writev && entry && entry.next) {\n // Fast case, write everything using _writev()\n var l = state.bufferedRequestCount;\n var buffer = new Array(l);\n var holder = state.corkedRequestsFree;\n holder.entry = entry;\n var count = 0;\n var allBuffers = true;\n\n while (entry) {\n buffer[count] = entry;\n if (!entry.isBuf) allBuffers = false;\n entry = entry.next;\n count += 1;\n }\n\n buffer.allBuffers = allBuffers;\n doWrite(stream, state, true, state.length, buffer, '', holder.finish); // doWrite is almost always async, defer these to save a bit of time\n // as the hot path ends with doWrite\n\n state.pendingcb++;\n state.lastBufferedRequest = null;\n\n if (holder.next) {\n state.corkedRequestsFree = holder.next;\n holder.next = null;\n } else {\n state.corkedRequestsFree = new CorkedRequest(state);\n }\n\n state.bufferedRequestCount = 0;\n } else {\n // Slow case, write chunks one-by-one\n while (entry) {\n var chunk = entry.chunk;\n var encoding = entry.encoding;\n var cb = entry.callback;\n var len = state.objectMode ? 1 : chunk.length;\n doWrite(stream, state, false, len, chunk, encoding, cb);\n entry = entry.next;\n state.bufferedRequestCount--; // if we didn't call the onwrite immediately, then\n // it means that we need to wait until it does.\n // also, that means that the chunk and cb are currently\n // being processed, so move the buffer counter past them.\n\n if (state.writing) {\n break;\n }\n }\n\n if (entry === null) state.lastBufferedRequest = null;\n }\n\n state.bufferedRequest = entry;\n state.bufferProcessing = false;\n}\n\nWritable.prototype._write = function (chunk, encoding, cb) {\n cb(new ERR_METHOD_NOT_IMPLEMENTED('_write()'));\n};\n\nWritable.prototype._writev = null;\n\nWritable.prototype.end = function (chunk, encoding, cb) {\n var state = this._writableState;\n\n if (typeof chunk === 'function') {\n cb = chunk;\n chunk = null;\n encoding = null;\n } else if (typeof encoding === 'function') {\n cb = encoding;\n encoding = null;\n }\n\n if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); // .end() fully uncorks\n\n if (state.corked) {\n state.corked = 1;\n this.uncork();\n } // ignore unnecessary end() calls.\n\n\n if (!state.ending) endWritable(this, state, cb);\n return this;\n};\n\nObject.defineProperty(Writable.prototype, 'writableLength', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._writableState.length;\n }\n});\n\nfunction needFinish(state) {\n return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;\n}\n\nfunction callFinal(stream, state) {\n stream._final(function (err) {\n state.pendingcb--;\n\n if (err) {\n errorOrDestroy(stream, err);\n }\n\n state.prefinished = true;\n stream.emit('prefinish');\n finishMaybe(stream, state);\n });\n}\n\nfunction prefinish(stream, state) {\n if (!state.prefinished && !state.finalCalled) {\n if (typeof stream._final === 'function' && !state.destroyed) {\n state.pendingcb++;\n state.finalCalled = true;\n process.nextTick(callFinal, stream, state);\n } else {\n state.prefinished = true;\n stream.emit('prefinish');\n }\n }\n}\n\nfunction finishMaybe(stream, state) {\n var need = needFinish(state);\n\n if (need) {\n prefinish(stream, state);\n\n if (state.pendingcb === 0) {\n state.finished = true;\n stream.emit('finish');\n\n if (state.autoDestroy) {\n // In case of duplex streams we need a way to detect\n // if the readable side is ready for autoDestroy as well\n var rState = stream._readableState;\n\n if (!rState || rState.autoDestroy && rState.endEmitted) {\n stream.destroy();\n }\n }\n }\n }\n\n return need;\n}\n\nfunction endWritable(stream, state, cb) {\n state.ending = true;\n finishMaybe(stream, state);\n\n if (cb) {\n if (state.finished) process.nextTick(cb);else stream.once('finish', cb);\n }\n\n state.ended = true;\n stream.writable = false;\n}\n\nfunction onCorkedFinish(corkReq, state, err) {\n var entry = corkReq.entry;\n corkReq.entry = null;\n\n while (entry) {\n var cb = entry.callback;\n state.pendingcb--;\n cb(err);\n entry = entry.next;\n } // reuse the free corkReq.\n\n\n state.corkedRequestsFree.next = corkReq;\n}\n\nObject.defineProperty(Writable.prototype, 'destroyed', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n if (this._writableState === undefined) {\n return false;\n }\n\n return this._writableState.destroyed;\n },\n set: function set(value) {\n // we ignore the value if the stream\n // has not been initialized yet\n if (!this._writableState) {\n return;\n } // backward compatibility, the user is explicitly\n // managing destroyed\n\n\n this._writableState.destroyed = value;\n }\n});\nWritable.prototype.destroy = destroyImpl.destroy;\nWritable.prototype._undestroy = destroyImpl.undestroy;\n\nWritable.prototype._destroy = function (err, cb) {\n cb(err);\n};","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n// a transform stream is a readable/writable stream where you do\n// something with the data. Sometimes it's called a \"filter\",\n// but that's not a great name for it, since that implies a thing where\n// some bits pass through, and others are simply ignored. (That would\n// be a valid example of a transform, of course.)\n//\n// While the output is causally related to the input, it's not a\n// necessarily symmetric or synchronous transformation. For example,\n// a zlib stream might take multiple plain-text writes(), and then\n// emit a single compressed chunk some time in the future.\n//\n// Here's how this works:\n//\n// The Transform stream has all the aspects of the readable and writable\n// stream classes. When you write(chunk), that calls _write(chunk,cb)\n// internally, and returns false if there's a lot of pending writes\n// buffered up. When you call read(), that calls _read(n) until\n// there's enough pending readable data buffered up.\n//\n// In a transform stream, the written data is placed in a buffer. When\n// _read(n) is called, it transforms the queued up data, calling the\n// buffered _write cb's as it consumes chunks. If consuming a single\n// written chunk would result in multiple output chunks, then the first\n// outputted bit calls the readcb, and subsequent chunks just go into\n// the read buffer, and will cause it to emit 'readable' if necessary.\n//\n// This way, back-pressure is actually determined by the reading side,\n// since _read has to be called to start processing a new chunk. However,\n// a pathological inflate type of transform can cause excessive buffering\n// here. For example, imagine a stream where every byte of input is\n// interpreted as an integer from 0-255, and then results in that many\n// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in\n// 1kb of data being output. In this case, you could write a very small\n// amount of input, and end up with a very large amount of output. In\n// such a pathological inflating mechanism, there'd be no way to tell\n// the system to stop doing the transform. A single 4MB write could\n// cause the system to run out of memory.\n//\n// However, even in such a pathological case, only a single written chunk\n// would be consumed, and then the rest would wait (un-transformed) until\n// the results of the previous transformed chunk were consumed.\n'use strict';\n\nmodule.exports = Transform;\n\nvar _require$codes = require('../errors').codes,\n ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,\n ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK,\n ERR_TRANSFORM_ALREADY_TRANSFORMING = _require$codes.ERR_TRANSFORM_ALREADY_TRANSFORMING,\n ERR_TRANSFORM_WITH_LENGTH_0 = _require$codes.ERR_TRANSFORM_WITH_LENGTH_0;\n\nvar Duplex = require('./_stream_duplex');\n\nrequire('inherits')(Transform, Duplex);\n\nfunction afterTransform(er, data) {\n var ts = this._transformState;\n ts.transforming = false;\n var cb = ts.writecb;\n\n if (cb === null) {\n return this.emit('error', new ERR_MULTIPLE_CALLBACK());\n }\n\n ts.writechunk = null;\n ts.writecb = null;\n if (data != null) // single equals check for both `null` and `undefined`\n this.push(data);\n cb(er);\n var rs = this._readableState;\n rs.reading = false;\n\n if (rs.needReadable || rs.length < rs.highWaterMark) {\n this._read(rs.highWaterMark);\n }\n}\n\nfunction Transform(options) {\n if (!(this instanceof Transform)) return new Transform(options);\n Duplex.call(this, options);\n this._transformState = {\n afterTransform: afterTransform.bind(this),\n needTransform: false,\n transforming: false,\n writecb: null,\n writechunk: null,\n writeencoding: null\n }; // start out asking for a readable event once data is transformed.\n\n this._readableState.needReadable = true; // we have implemented the _read method, and done the other things\n // that Readable wants before the first _read call, so unset the\n // sync guard flag.\n\n this._readableState.sync = false;\n\n if (options) {\n if (typeof options.transform === 'function') this._transform = options.transform;\n if (typeof options.flush === 'function') this._flush = options.flush;\n } // When the writable side finishes, then flush out anything remaining.\n\n\n this.on('prefinish', prefinish);\n}\n\nfunction prefinish() {\n var _this = this;\n\n if (typeof this._flush === 'function' && !this._readableState.destroyed) {\n this._flush(function (er, data) {\n done(_this, er, data);\n });\n } else {\n done(this, null, null);\n }\n}\n\nTransform.prototype.push = function (chunk, encoding) {\n this._transformState.needTransform = false;\n return Duplex.prototype.push.call(this, chunk, encoding);\n}; // This is the part where you do stuff!\n// override this function in implementation classes.\n// 'chunk' is an input chunk.\n//\n// Call `push(newChunk)` to pass along transformed output\n// to the readable side. You may call 'push' zero or more times.\n//\n// Call `cb(err)` when you are done with this chunk. If you pass\n// an error, then that'll put the hurt on the whole operation. If you\n// never call cb(), then you'll never get another chunk.\n\n\nTransform.prototype._transform = function (chunk, encoding, cb) {\n cb(new ERR_METHOD_NOT_IMPLEMENTED('_transform()'));\n};\n\nTransform.prototype._write = function (chunk, encoding, cb) {\n var ts = this._transformState;\n ts.writecb = cb;\n ts.writechunk = chunk;\n ts.writeencoding = encoding;\n\n if (!ts.transforming) {\n var rs = this._readableState;\n if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);\n }\n}; // Doesn't matter what the args are here.\n// _transform does all the work.\n// That we got here means that the readable side wants more data.\n\n\nTransform.prototype._read = function (n) {\n var ts = this._transformState;\n\n if (ts.writechunk !== null && !ts.transforming) {\n ts.transforming = true;\n\n this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);\n } else {\n // mark that we need a transform, so that any data that comes in\n // will get processed, now that we've asked for it.\n ts.needTransform = true;\n }\n};\n\nTransform.prototype._destroy = function (err, cb) {\n Duplex.prototype._destroy.call(this, err, function (err2) {\n cb(err2);\n });\n};\n\nfunction done(stream, er, data) {\n if (er) return stream.emit('error', er);\n if (data != null) // single equals check for both `null` and `undefined`\n stream.push(data); // TODO(BridgeAR): Write a test for these two error cases\n // if there's nothing in the write buffer, then that means\n // that nothing more will ever be provided\n\n if (stream._writableState.length) throw new ERR_TRANSFORM_WITH_LENGTH_0();\n if (stream._transformState.transforming) throw new ERR_TRANSFORM_ALREADY_TRANSFORMING();\n return stream.push(null);\n}","/**\n * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined\n * in FIPS 180-2\n * Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009.\n * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet\n *\n */\n\nvar inherits = require('inherits')\nvar Hash = require('./hash')\nvar Buffer = require('safe-buffer').Buffer\n\nvar K = [\n 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,\n 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,\n 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,\n 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,\n 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,\n 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,\n 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,\n 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,\n 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,\n 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,\n 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,\n 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,\n 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,\n 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,\n 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,\n 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2\n]\n\nvar W = new Array(64)\n\nfunction Sha256 () {\n this.init()\n\n this._w = W // new Array(64)\n\n Hash.call(this, 64, 56)\n}\n\ninherits(Sha256, Hash)\n\nSha256.prototype.init = function () {\n this._a = 0x6a09e667\n this._b = 0xbb67ae85\n this._c = 0x3c6ef372\n this._d = 0xa54ff53a\n this._e = 0x510e527f\n this._f = 0x9b05688c\n this._g = 0x1f83d9ab\n this._h = 0x5be0cd19\n\n return this\n}\n\nfunction ch (x, y, z) {\n return z ^ (x & (y ^ z))\n}\n\nfunction maj (x, y, z) {\n return (x & y) | (z & (x | y))\n}\n\nfunction sigma0 (x) {\n return (x >>> 2 | x << 30) ^ (x >>> 13 | x << 19) ^ (x >>> 22 | x << 10)\n}\n\nfunction sigma1 (x) {\n return (x >>> 6 | x << 26) ^ (x >>> 11 | x << 21) ^ (x >>> 25 | x << 7)\n}\n\nfunction gamma0 (x) {\n return (x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ (x >>> 3)\n}\n\nfunction gamma1 (x) {\n return (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ (x >>> 10)\n}\n\nSha256.prototype._update = function (M) {\n var W = this._w\n\n var a = this._a | 0\n var b = this._b | 0\n var c = this._c | 0\n var d = this._d | 0\n var e = this._e | 0\n var f = this._f | 0\n var g = this._g | 0\n var h = this._h | 0\n\n for (var i = 0; i < 16; ++i) W[i] = M.readInt32BE(i * 4)\n for (; i < 64; ++i) W[i] = (gamma1(W[i - 2]) + W[i - 7] + gamma0(W[i - 15]) + W[i - 16]) | 0\n\n for (var j = 0; j < 64; ++j) {\n var T1 = (h + sigma1(e) + ch(e, f, g) + K[j] + W[j]) | 0\n var T2 = (sigma0(a) + maj(a, b, c)) | 0\n\n h = g\n g = f\n f = e\n e = (d + T1) | 0\n d = c\n c = b\n b = a\n a = (T1 + T2) | 0\n }\n\n this._a = (a + this._a) | 0\n this._b = (b + this._b) | 0\n this._c = (c + this._c) | 0\n this._d = (d + this._d) | 0\n this._e = (e + this._e) | 0\n this._f = (f + this._f) | 0\n this._g = (g + this._g) | 0\n this._h = (h + this._h) | 0\n}\n\nSha256.prototype._hash = function () {\n var H = Buffer.allocUnsafe(32)\n\n H.writeInt32BE(this._a, 0)\n H.writeInt32BE(this._b, 4)\n H.writeInt32BE(this._c, 8)\n H.writeInt32BE(this._d, 12)\n H.writeInt32BE(this._e, 16)\n H.writeInt32BE(this._f, 20)\n H.writeInt32BE(this._g, 24)\n H.writeInt32BE(this._h, 28)\n\n return H\n}\n\nmodule.exports = Sha256\n","var inherits = require('inherits')\nvar Hash = require('./hash')\nvar Buffer = require('safe-buffer').Buffer\n\nvar K = [\n 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,\n 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,\n 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,\n 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,\n 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,\n 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,\n 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,\n 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,\n 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,\n 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,\n 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,\n 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,\n 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,\n 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,\n 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,\n 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,\n 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,\n 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,\n 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,\n 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,\n 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,\n 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,\n 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,\n 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,\n 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,\n 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,\n 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,\n 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,\n 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,\n 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,\n 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,\n 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,\n 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,\n 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,\n 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,\n 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,\n 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,\n 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,\n 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,\n 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817\n]\n\nvar W = new Array(160)\n\nfunction Sha512 () {\n this.init()\n this._w = W\n\n Hash.call(this, 128, 112)\n}\n\ninherits(Sha512, Hash)\n\nSha512.prototype.init = function () {\n this._ah = 0x6a09e667\n this._bh = 0xbb67ae85\n this._ch = 0x3c6ef372\n this._dh = 0xa54ff53a\n this._eh = 0x510e527f\n this._fh = 0x9b05688c\n this._gh = 0x1f83d9ab\n this._hh = 0x5be0cd19\n\n this._al = 0xf3bcc908\n this._bl = 0x84caa73b\n this._cl = 0xfe94f82b\n this._dl = 0x5f1d36f1\n this._el = 0xade682d1\n this._fl = 0x2b3e6c1f\n this._gl = 0xfb41bd6b\n this._hl = 0x137e2179\n\n return this\n}\n\nfunction Ch (x, y, z) {\n return z ^ (x & (y ^ z))\n}\n\nfunction maj (x, y, z) {\n return (x & y) | (z & (x | y))\n}\n\nfunction sigma0 (x, xl) {\n return (x >>> 28 | xl << 4) ^ (xl >>> 2 | x << 30) ^ (xl >>> 7 | x << 25)\n}\n\nfunction sigma1 (x, xl) {\n return (x >>> 14 | xl << 18) ^ (x >>> 18 | xl << 14) ^ (xl >>> 9 | x << 23)\n}\n\nfunction Gamma0 (x, xl) {\n return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7)\n}\n\nfunction Gamma0l (x, xl) {\n return (x >>> 1 | xl << 31) ^ (x >>> 8 | xl << 24) ^ (x >>> 7 | xl << 25)\n}\n\nfunction Gamma1 (x, xl) {\n return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6)\n}\n\nfunction Gamma1l (x, xl) {\n return (x >>> 19 | xl << 13) ^ (xl >>> 29 | x << 3) ^ (x >>> 6 | xl << 26)\n}\n\nfunction getCarry (a, b) {\n return (a >>> 0) < (b >>> 0) ? 1 : 0\n}\n\nSha512.prototype._update = function (M) {\n var W = this._w\n\n var ah = this._ah | 0\n var bh = this._bh | 0\n var ch = this._ch | 0\n var dh = this._dh | 0\n var eh = this._eh | 0\n var fh = this._fh | 0\n var gh = this._gh | 0\n var hh = this._hh | 0\n\n var al = this._al | 0\n var bl = this._bl | 0\n var cl = this._cl | 0\n var dl = this._dl | 0\n var el = this._el | 0\n var fl = this._fl | 0\n var gl = this._gl | 0\n var hl = this._hl | 0\n\n for (var i = 0; i < 32; i += 2) {\n W[i] = M.readInt32BE(i * 4)\n W[i + 1] = M.readInt32BE(i * 4 + 4)\n }\n for (; i < 160; i += 2) {\n var xh = W[i - 15 * 2]\n var xl = W[i - 15 * 2 + 1]\n var gamma0 = Gamma0(xh, xl)\n var gamma0l = Gamma0l(xl, xh)\n\n xh = W[i - 2 * 2]\n xl = W[i - 2 * 2 + 1]\n var gamma1 = Gamma1(xh, xl)\n var gamma1l = Gamma1l(xl, xh)\n\n // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]\n var Wi7h = W[i - 7 * 2]\n var Wi7l = W[i - 7 * 2 + 1]\n\n var Wi16h = W[i - 16 * 2]\n var Wi16l = W[i - 16 * 2 + 1]\n\n var Wil = (gamma0l + Wi7l) | 0\n var Wih = (gamma0 + Wi7h + getCarry(Wil, gamma0l)) | 0\n Wil = (Wil + gamma1l) | 0\n Wih = (Wih + gamma1 + getCarry(Wil, gamma1l)) | 0\n Wil = (Wil + Wi16l) | 0\n Wih = (Wih + Wi16h + getCarry(Wil, Wi16l)) | 0\n\n W[i] = Wih\n W[i + 1] = Wil\n }\n\n for (var j = 0; j < 160; j += 2) {\n Wih = W[j]\n Wil = W[j + 1]\n\n var majh = maj(ah, bh, ch)\n var majl = maj(al, bl, cl)\n\n var sigma0h = sigma0(ah, al)\n var sigma0l = sigma0(al, ah)\n var sigma1h = sigma1(eh, el)\n var sigma1l = sigma1(el, eh)\n\n // t1 = h + sigma1 + ch + K[j] + W[j]\n var Kih = K[j]\n var Kil = K[j + 1]\n\n var chh = Ch(eh, fh, gh)\n var chl = Ch(el, fl, gl)\n\n var t1l = (hl + sigma1l) | 0\n var t1h = (hh + sigma1h + getCarry(t1l, hl)) | 0\n t1l = (t1l + chl) | 0\n t1h = (t1h + chh + getCarry(t1l, chl)) | 0\n t1l = (t1l + Kil) | 0\n t1h = (t1h + Kih + getCarry(t1l, Kil)) | 0\n t1l = (t1l + Wil) | 0\n t1h = (t1h + Wih + getCarry(t1l, Wil)) | 0\n\n // t2 = sigma0 + maj\n var t2l = (sigma0l + majl) | 0\n var t2h = (sigma0h + majh + getCarry(t2l, sigma0l)) | 0\n\n hh = gh\n hl = gl\n gh = fh\n gl = fl\n fh = eh\n fl = el\n el = (dl + t1l) | 0\n eh = (dh + t1h + getCarry(el, dl)) | 0\n dh = ch\n dl = cl\n ch = bh\n cl = bl\n bh = ah\n bl = al\n al = (t1l + t2l) | 0\n ah = (t1h + t2h + getCarry(al, t1l)) | 0\n }\n\n this._al = (this._al + al) | 0\n this._bl = (this._bl + bl) | 0\n this._cl = (this._cl + cl) | 0\n this._dl = (this._dl + dl) | 0\n this._el = (this._el + el) | 0\n this._fl = (this._fl + fl) | 0\n this._gl = (this._gl + gl) | 0\n this._hl = (this._hl + hl) | 0\n\n this._ah = (this._ah + ah + getCarry(this._al, al)) | 0\n this._bh = (this._bh + bh + getCarry(this._bl, bl)) | 0\n this._ch = (this._ch + ch + getCarry(this._cl, cl)) | 0\n this._dh = (this._dh + dh + getCarry(this._dl, dl)) | 0\n this._eh = (this._eh + eh + getCarry(this._el, el)) | 0\n this._fh = (this._fh + fh + getCarry(this._fl, fl)) | 0\n this._gh = (this._gh + gh + getCarry(this._gl, gl)) | 0\n this._hh = (this._hh + hh + getCarry(this._hl, hl)) | 0\n}\n\nSha512.prototype._hash = function () {\n var H = Buffer.allocUnsafe(64)\n\n function writeInt64BE (h, l, offset) {\n H.writeInt32BE(h, offset)\n H.writeInt32BE(l, offset + 4)\n }\n\n writeInt64BE(this._ah, this._al, 0)\n writeInt64BE(this._bh, this._bl, 8)\n writeInt64BE(this._ch, this._cl, 16)\n writeInt64BE(this._dh, this._dl, 24)\n writeInt64BE(this._eh, this._el, 32)\n writeInt64BE(this._fh, this._fl, 40)\n writeInt64BE(this._gh, this._gl, 48)\n writeInt64BE(this._hh, this._hl, 56)\n\n return H\n}\n\nmodule.exports = Sha512\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\n/**/\n\nvar pna = require('process-nextick-args');\n/**/\n\nmodule.exports = Readable;\n\n/**/\nvar isArray = require('isarray');\n/**/\n\n/**/\nvar Duplex;\n/**/\n\nReadable.ReadableState = ReadableState;\n\n/**/\nvar EE = require('events').EventEmitter;\n\nvar EElistenerCount = function (emitter, type) {\n return emitter.listeners(type).length;\n};\n/**/\n\n/**/\nvar Stream = require('./internal/streams/stream');\n/**/\n\n/**/\n\nvar Buffer = require('safe-buffer').Buffer;\nvar OurUint8Array = global.Uint8Array || function () {};\nfunction _uint8ArrayToBuffer(chunk) {\n return Buffer.from(chunk);\n}\nfunction _isUint8Array(obj) {\n return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;\n}\n\n/**/\n\n/**/\nvar util = Object.create(require('core-util-is'));\nutil.inherits = require('inherits');\n/**/\n\n/**/\nvar debugUtil = require('util');\nvar debug = void 0;\nif (debugUtil && debugUtil.debuglog) {\n debug = debugUtil.debuglog('stream');\n} else {\n debug = function () {};\n}\n/**/\n\nvar BufferList = require('./internal/streams/BufferList');\nvar destroyImpl = require('./internal/streams/destroy');\nvar StringDecoder;\n\nutil.inherits(Readable, Stream);\n\nvar kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume'];\n\nfunction prependListener(emitter, event, fn) {\n // Sadly this is not cacheable as some libraries bundle their own\n // event emitter implementation with them.\n if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn);\n\n // This is a hack to make sure that our error handler is attached before any\n // userland ones. NEVER DO THIS. This is here only because this code needs\n // to continue to work with older versions of Node.js that do not include\n // the prependListener() method. The goal is to eventually remove this hack.\n if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]];\n}\n\nfunction ReadableState(options, stream) {\n Duplex = Duplex || require('./_stream_duplex');\n\n options = options || {};\n\n // Duplex streams are both readable and writable, but share\n // the same options object.\n // However, some cases require setting options to different\n // values for the readable and the writable sides of the duplex stream.\n // These options can be provided separately as readableXXX and writableXXX.\n var isDuplex = stream instanceof Duplex;\n\n // object stream flag. Used to make read(n) ignore n and to\n // make all the buffer merging and length checks go away\n this.objectMode = !!options.objectMode;\n\n if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode;\n\n // the point at which it stops calling _read() to fill the buffer\n // Note: 0 is a valid value, means \"don't call _read preemptively ever\"\n var hwm = options.highWaterMark;\n var readableHwm = options.readableHighWaterMark;\n var defaultHwm = this.objectMode ? 16 : 16 * 1024;\n\n if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (readableHwm || readableHwm === 0)) this.highWaterMark = readableHwm;else this.highWaterMark = defaultHwm;\n\n // cast to ints.\n this.highWaterMark = Math.floor(this.highWaterMark);\n\n // A linked list is used to store data chunks instead of an array because the\n // linked list can remove elements from the beginning faster than\n // array.shift()\n this.buffer = new BufferList();\n this.length = 0;\n this.pipes = null;\n this.pipesCount = 0;\n this.flowing = null;\n this.ended = false;\n this.endEmitted = false;\n this.reading = false;\n\n // a flag to be able to tell if the event 'readable'/'data' is emitted\n // immediately, or on a later tick. We set this to true at first, because\n // any actions that shouldn't happen until \"later\" should generally also\n // not happen before the first read call.\n this.sync = true;\n\n // whenever we return null, then we set a flag to say\n // that we're awaiting a 'readable' event emission.\n this.needReadable = false;\n this.emittedReadable = false;\n this.readableListening = false;\n this.resumeScheduled = false;\n\n // has it been destroyed\n this.destroyed = false;\n\n // Crypto is kind of old and crusty. Historically, its default string\n // encoding is 'binary' so we have to make this configurable.\n // Everything else in the universe uses 'utf8', though.\n this.defaultEncoding = options.defaultEncoding || 'utf8';\n\n // the number of writers that are awaiting a drain event in .pipe()s\n this.awaitDrain = 0;\n\n // if true, a maybeReadMore has been scheduled\n this.readingMore = false;\n\n this.decoder = null;\n this.encoding = null;\n if (options.encoding) {\n if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;\n this.decoder = new StringDecoder(options.encoding);\n this.encoding = options.encoding;\n }\n}\n\nfunction Readable(options) {\n Duplex = Duplex || require('./_stream_duplex');\n\n if (!(this instanceof Readable)) return new Readable(options);\n\n this._readableState = new ReadableState(options, this);\n\n // legacy\n this.readable = true;\n\n if (options) {\n if (typeof options.read === 'function') this._read = options.read;\n\n if (typeof options.destroy === 'function') this._destroy = options.destroy;\n }\n\n Stream.call(this);\n}\n\nObject.defineProperty(Readable.prototype, 'destroyed', {\n get: function () {\n if (this._readableState === undefined) {\n return false;\n }\n return this._readableState.destroyed;\n },\n set: function (value) {\n // we ignore the value if the stream\n // has not been initialized yet\n if (!this._readableState) {\n return;\n }\n\n // backward compatibility, the user is explicitly\n // managing destroyed\n this._readableState.destroyed = value;\n }\n});\n\nReadable.prototype.destroy = destroyImpl.destroy;\nReadable.prototype._undestroy = destroyImpl.undestroy;\nReadable.prototype._destroy = function (err, cb) {\n this.push(null);\n cb(err);\n};\n\n// Manually shove something into the read() buffer.\n// This returns true if the highWaterMark has not been hit yet,\n// similar to how Writable.write() returns true if you should\n// write() some more.\nReadable.prototype.push = function (chunk, encoding) {\n var state = this._readableState;\n var skipChunkCheck;\n\n if (!state.objectMode) {\n if (typeof chunk === 'string') {\n encoding = encoding || state.defaultEncoding;\n if (encoding !== state.encoding) {\n chunk = Buffer.from(chunk, encoding);\n encoding = '';\n }\n skipChunkCheck = true;\n }\n } else {\n skipChunkCheck = true;\n }\n\n return readableAddChunk(this, chunk, encoding, false, skipChunkCheck);\n};\n\n// Unshift should *always* be something directly out of read()\nReadable.prototype.unshift = function (chunk) {\n return readableAddChunk(this, chunk, null, true, false);\n};\n\nfunction readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) {\n var state = stream._readableState;\n if (chunk === null) {\n state.reading = false;\n onEofChunk(stream, state);\n } else {\n var er;\n if (!skipChunkCheck) er = chunkInvalid(state, chunk);\n if (er) {\n stream.emit('error', er);\n } else if (state.objectMode || chunk && chunk.length > 0) {\n if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) {\n chunk = _uint8ArrayToBuffer(chunk);\n }\n\n if (addToFront) {\n if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true);\n } else if (state.ended) {\n stream.emit('error', new Error('stream.push() after EOF'));\n } else {\n state.reading = false;\n if (state.decoder && !encoding) {\n chunk = state.decoder.write(chunk);\n if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state);\n } else {\n addChunk(stream, state, chunk, false);\n }\n }\n } else if (!addToFront) {\n state.reading = false;\n }\n }\n\n return needMoreData(state);\n}\n\nfunction addChunk(stream, state, chunk, addToFront) {\n if (state.flowing && state.length === 0 && !state.sync) {\n stream.emit('data', chunk);\n stream.read(0);\n } else {\n // update the buffer info.\n state.length += state.objectMode ? 1 : chunk.length;\n if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk);\n\n if (state.needReadable) emitReadable(stream);\n }\n maybeReadMore(stream, state);\n}\n\nfunction chunkInvalid(state, chunk) {\n var er;\n if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {\n er = new TypeError('Invalid non-string/buffer chunk');\n }\n return er;\n}\n\n// if it's past the high water mark, we can push in some more.\n// Also, if we have no data yet, we can stand some\n// more bytes. This is to work around cases where hwm=0,\n// such as the repl. Also, if the push() triggered a\n// readable event, and the user called read(largeNumber) such that\n// needReadable was set, then we ought to push more, so that another\n// 'readable' event will be triggered.\nfunction needMoreData(state) {\n return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0);\n}\n\nReadable.prototype.isPaused = function () {\n return this._readableState.flowing === false;\n};\n\n// backwards compatibility.\nReadable.prototype.setEncoding = function (enc) {\n if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;\n this._readableState.decoder = new StringDecoder(enc);\n this._readableState.encoding = enc;\n return this;\n};\n\n// Don't raise the hwm > 8MB\nvar MAX_HWM = 0x800000;\nfunction computeNewHighWaterMark(n) {\n if (n >= MAX_HWM) {\n n = MAX_HWM;\n } else {\n // Get the next highest power of 2 to prevent increasing hwm excessively in\n // tiny amounts\n n--;\n n |= n >>> 1;\n n |= n >>> 2;\n n |= n >>> 4;\n n |= n >>> 8;\n n |= n >>> 16;\n n++;\n }\n return n;\n}\n\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction howMuchToRead(n, state) {\n if (n <= 0 || state.length === 0 && state.ended) return 0;\n if (state.objectMode) return 1;\n if (n !== n) {\n // Only flow one buffer at a time\n if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length;\n }\n // If we're asking for more than the current hwm, then raise the hwm.\n if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);\n if (n <= state.length) return n;\n // Don't have enough\n if (!state.ended) {\n state.needReadable = true;\n return 0;\n }\n return state.length;\n}\n\n// you can override either this method, or the async _read(n) below.\nReadable.prototype.read = function (n) {\n debug('read', n);\n n = parseInt(n, 10);\n var state = this._readableState;\n var nOrig = n;\n\n if (n !== 0) state.emittedReadable = false;\n\n // if we're doing read(0) to trigger a readable event, but we\n // already have a bunch of data in the buffer, then just trigger\n // the 'readable' event and move on.\n if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) {\n debug('read: emitReadable', state.length, state.ended);\n if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this);\n return null;\n }\n\n n = howMuchToRead(n, state);\n\n // if we've ended, and we're now clear, then finish it up.\n if (n === 0 && state.ended) {\n if (state.length === 0) endReadable(this);\n return null;\n }\n\n // All the actual chunk generation logic needs to be\n // *below* the call to _read. The reason is that in certain\n // synthetic stream cases, such as passthrough streams, _read\n // may be a completely synchronous operation which may change\n // the state of the read buffer, providing enough data when\n // before there was *not* enough.\n //\n // So, the steps are:\n // 1. Figure out what the state of things will be after we do\n // a read from the buffer.\n //\n // 2. If that resulting state will trigger a _read, then call _read.\n // Note that this may be asynchronous, or synchronous. Yes, it is\n // deeply ugly to write APIs this way, but that still doesn't mean\n // that the Readable class should behave improperly, as streams are\n // designed to be sync/async agnostic.\n // Take note if the _read call is sync or async (ie, if the read call\n // has returned yet), so that we know whether or not it's safe to emit\n // 'readable' etc.\n //\n // 3. Actually pull the requested chunks out of the buffer and return.\n\n // if we need a readable event, then we need to do some reading.\n var doRead = state.needReadable;\n debug('need readable', doRead);\n\n // if we currently have less than the highWaterMark, then also read some\n if (state.length === 0 || state.length - n < state.highWaterMark) {\n doRead = true;\n debug('length less than watermark', doRead);\n }\n\n // however, if we've ended, then there's no point, and if we're already\n // reading, then it's unnecessary.\n if (state.ended || state.reading) {\n doRead = false;\n debug('reading or ended', doRead);\n } else if (doRead) {\n debug('do read');\n state.reading = true;\n state.sync = true;\n // if the length is currently zero, then we *need* a readable event.\n if (state.length === 0) state.needReadable = true;\n // call internal read method\n this._read(state.highWaterMark);\n state.sync = false;\n // If _read pushed data synchronously, then `reading` will be false,\n // and we need to re-evaluate how much data we can return to the user.\n if (!state.reading) n = howMuchToRead(nOrig, state);\n }\n\n var ret;\n if (n > 0) ret = fromList(n, state);else ret = null;\n\n if (ret === null) {\n state.needReadable = true;\n n = 0;\n } else {\n state.length -= n;\n }\n\n if (state.length === 0) {\n // If we have nothing in the buffer, then we want to know\n // as soon as we *do* get something into the buffer.\n if (!state.ended) state.needReadable = true;\n\n // If we tried to read() past the EOF, then emit end on the next tick.\n if (nOrig !== n && state.ended) endReadable(this);\n }\n\n if (ret !== null) this.emit('data', ret);\n\n return ret;\n};\n\nfunction onEofChunk(stream, state) {\n if (state.ended) return;\n if (state.decoder) {\n var chunk = state.decoder.end();\n if (chunk && chunk.length) {\n state.buffer.push(chunk);\n state.length += state.objectMode ? 1 : chunk.length;\n }\n }\n state.ended = true;\n\n // emit 'readable' now to make sure it gets picked up.\n emitReadable(stream);\n}\n\n// Don't emit readable right away in sync mode, because this can trigger\n// another read() call => stack overflow. This way, it might trigger\n// a nextTick recursion warning, but that's not so bad.\nfunction emitReadable(stream) {\n var state = stream._readableState;\n state.needReadable = false;\n if (!state.emittedReadable) {\n debug('emitReadable', state.flowing);\n state.emittedReadable = true;\n if (state.sync) pna.nextTick(emitReadable_, stream);else emitReadable_(stream);\n }\n}\n\nfunction emitReadable_(stream) {\n debug('emit readable');\n stream.emit('readable');\n flow(stream);\n}\n\n// at this point, the user has presumably seen the 'readable' event,\n// and called read() to consume some data. that may have triggered\n// in turn another _read(n) call, in which case reading = true if\n// it's in progress.\n// However, if we're not ended, or reading, and the length < hwm,\n// then go ahead and try to read some more preemptively.\nfunction maybeReadMore(stream, state) {\n if (!state.readingMore) {\n state.readingMore = true;\n pna.nextTick(maybeReadMore_, stream, state);\n }\n}\n\nfunction maybeReadMore_(stream, state) {\n var len = state.length;\n while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) {\n debug('maybeReadMore read 0');\n stream.read(0);\n if (len === state.length)\n // didn't get any data, stop spinning.\n break;else len = state.length;\n }\n state.readingMore = false;\n}\n\n// abstract method. to be overridden in specific implementation classes.\n// call cb(er, data) where data is <= n in length.\n// for virtual (non-string, non-buffer) streams, \"length\" is somewhat\n// arbitrary, and perhaps not very meaningful.\nReadable.prototype._read = function (n) {\n this.emit('error', new Error('_read() is not implemented'));\n};\n\nReadable.prototype.pipe = function (dest, pipeOpts) {\n var src = this;\n var state = this._readableState;\n\n switch (state.pipesCount) {\n case 0:\n state.pipes = dest;\n break;\n case 1:\n state.pipes = [state.pipes, dest];\n break;\n default:\n state.pipes.push(dest);\n break;\n }\n state.pipesCount += 1;\n debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);\n\n var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr;\n\n var endFn = doEnd ? onend : unpipe;\n if (state.endEmitted) pna.nextTick(endFn);else src.once('end', endFn);\n\n dest.on('unpipe', onunpipe);\n function onunpipe(readable, unpipeInfo) {\n debug('onunpipe');\n if (readable === src) {\n if (unpipeInfo && unpipeInfo.hasUnpiped === false) {\n unpipeInfo.hasUnpiped = true;\n cleanup();\n }\n }\n }\n\n function onend() {\n debug('onend');\n dest.end();\n }\n\n // when the dest drains, it reduces the awaitDrain counter\n // on the source. This would be more elegant with a .once()\n // handler in flow(), but adding and removing repeatedly is\n // too slow.\n var ondrain = pipeOnDrain(src);\n dest.on('drain', ondrain);\n\n var cleanedUp = false;\n function cleanup() {\n debug('cleanup');\n // cleanup event handlers once the pipe is broken\n dest.removeListener('close', onclose);\n dest.removeListener('finish', onfinish);\n dest.removeListener('drain', ondrain);\n dest.removeListener('error', onerror);\n dest.removeListener('unpipe', onunpipe);\n src.removeListener('end', onend);\n src.removeListener('end', unpipe);\n src.removeListener('data', ondata);\n\n cleanedUp = true;\n\n // if the reader is waiting for a drain event from this\n // specific writer, then it would cause it to never start\n // flowing again.\n // So, if this is awaiting a drain, then we just call it now.\n // If we don't know, then assume that we are waiting for one.\n if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();\n }\n\n // If the user pushes more data while we're writing to dest then we'll end up\n // in ondata again. However, we only want to increase awaitDrain once because\n // dest will only emit one 'drain' event for the multiple writes.\n // => Introduce a guard on increasing awaitDrain.\n var increasedAwaitDrain = false;\n src.on('data', ondata);\n function ondata(chunk) {\n debug('ondata');\n increasedAwaitDrain = false;\n var ret = dest.write(chunk);\n if (false === ret && !increasedAwaitDrain) {\n // If the user unpiped during `dest.write()`, it is possible\n // to get stuck in a permanently paused state if that write\n // also returned false.\n // => Check whether `dest` is still a piping destination.\n if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {\n debug('false write response, pause', src._readableState.awaitDrain);\n src._readableState.awaitDrain++;\n increasedAwaitDrain = true;\n }\n src.pause();\n }\n }\n\n // if the dest has an error, then stop piping into it.\n // however, don't suppress the throwing behavior for this.\n function onerror(er) {\n debug('onerror', er);\n unpipe();\n dest.removeListener('error', onerror);\n if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er);\n }\n\n // Make sure our error handler is attached before userland ones.\n prependListener(dest, 'error', onerror);\n\n // Both close and finish should trigger unpipe, but only once.\n function onclose() {\n dest.removeListener('finish', onfinish);\n unpipe();\n }\n dest.once('close', onclose);\n function onfinish() {\n debug('onfinish');\n dest.removeListener('close', onclose);\n unpipe();\n }\n dest.once('finish', onfinish);\n\n function unpipe() {\n debug('unpipe');\n src.unpipe(dest);\n }\n\n // tell the dest that it's being piped to\n dest.emit('pipe', src);\n\n // start the flow if it hasn't been started already.\n if (!state.flowing) {\n debug('pipe resume');\n src.resume();\n }\n\n return dest;\n};\n\nfunction pipeOnDrain(src) {\n return function () {\n var state = src._readableState;\n debug('pipeOnDrain', state.awaitDrain);\n if (state.awaitDrain) state.awaitDrain--;\n if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) {\n state.flowing = true;\n flow(src);\n }\n };\n}\n\nReadable.prototype.unpipe = function (dest) {\n var state = this._readableState;\n var unpipeInfo = { hasUnpiped: false };\n\n // if we're not piping anywhere, then do nothing.\n if (state.pipesCount === 0) return this;\n\n // just one destination. most common case.\n if (state.pipesCount === 1) {\n // passed in one, but it's not the right one.\n if (dest && dest !== state.pipes) return this;\n\n if (!dest) dest = state.pipes;\n\n // got a match.\n state.pipes = null;\n state.pipesCount = 0;\n state.flowing = false;\n if (dest) dest.emit('unpipe', this, unpipeInfo);\n return this;\n }\n\n // slow case. multiple pipe destinations.\n\n if (!dest) {\n // remove all.\n var dests = state.pipes;\n var len = state.pipesCount;\n state.pipes = null;\n state.pipesCount = 0;\n state.flowing = false;\n\n for (var i = 0; i < len; i++) {\n dests[i].emit('unpipe', this, unpipeInfo);\n }return this;\n }\n\n // try to find the right one.\n var index = indexOf(state.pipes, dest);\n if (index === -1) return this;\n\n state.pipes.splice(index, 1);\n state.pipesCount -= 1;\n if (state.pipesCount === 1) state.pipes = state.pipes[0];\n\n dest.emit('unpipe', this, unpipeInfo);\n\n return this;\n};\n\n// set up data events if they are asked for\n// Ensure readable listeners eventually get something\nReadable.prototype.on = function (ev, fn) {\n var res = Stream.prototype.on.call(this, ev, fn);\n\n if (ev === 'data') {\n // Start flowing on next tick if stream isn't explicitly paused\n if (this._readableState.flowing !== false) this.resume();\n } else if (ev === 'readable') {\n var state = this._readableState;\n if (!state.endEmitted && !state.readableListening) {\n state.readableListening = state.needReadable = true;\n state.emittedReadable = false;\n if (!state.reading) {\n pna.nextTick(nReadingNextTick, this);\n } else if (state.length) {\n emitReadable(this);\n }\n }\n }\n\n return res;\n};\nReadable.prototype.addListener = Readable.prototype.on;\n\nfunction nReadingNextTick(self) {\n debug('readable nexttick read 0');\n self.read(0);\n}\n\n// pause() and resume() are remnants of the legacy readable stream API\n// If the user uses them, then switch into old mode.\nReadable.prototype.resume = function () {\n var state = this._readableState;\n if (!state.flowing) {\n debug('resume');\n state.flowing = true;\n resume(this, state);\n }\n return this;\n};\n\nfunction resume(stream, state) {\n if (!state.resumeScheduled) {\n state.resumeScheduled = true;\n pna.nextTick(resume_, stream, state);\n }\n}\n\nfunction resume_(stream, state) {\n if (!state.reading) {\n debug('resume read 0');\n stream.read(0);\n }\n\n state.resumeScheduled = false;\n state.awaitDrain = 0;\n stream.emit('resume');\n flow(stream);\n if (state.flowing && !state.reading) stream.read(0);\n}\n\nReadable.prototype.pause = function () {\n debug('call pause flowing=%j', this._readableState.flowing);\n if (false !== this._readableState.flowing) {\n debug('pause');\n this._readableState.flowing = false;\n this.emit('pause');\n }\n return this;\n};\n\nfunction flow(stream) {\n var state = stream._readableState;\n debug('flow', state.flowing);\n while (state.flowing && stream.read() !== null) {}\n}\n\n// wrap an old-style stream as the async data source.\n// This is *not* part of the readable stream interface.\n// It is an ugly unfortunate mess of history.\nReadable.prototype.wrap = function (stream) {\n var _this = this;\n\n var state = this._readableState;\n var paused = false;\n\n stream.on('end', function () {\n debug('wrapped end');\n if (state.decoder && !state.ended) {\n var chunk = state.decoder.end();\n if (chunk && chunk.length) _this.push(chunk);\n }\n\n _this.push(null);\n });\n\n stream.on('data', function (chunk) {\n debug('wrapped data');\n if (state.decoder) chunk = state.decoder.write(chunk);\n\n // don't skip over falsy values in objectMode\n if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return;\n\n var ret = _this.push(chunk);\n if (!ret) {\n paused = true;\n stream.pause();\n }\n });\n\n // proxy all the other methods.\n // important when wrapping filters and duplexes.\n for (var i in stream) {\n if (this[i] === undefined && typeof stream[i] === 'function') {\n this[i] = function (method) {\n return function () {\n return stream[method].apply(stream, arguments);\n };\n }(i);\n }\n }\n\n // proxy certain important events.\n for (var n = 0; n < kProxyEvents.length; n++) {\n stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n]));\n }\n\n // when we try to consume some more bytes, simply unpause the\n // underlying stream.\n this._read = function (n) {\n debug('wrapped _read', n);\n if (paused) {\n paused = false;\n stream.resume();\n }\n };\n\n return this;\n};\n\nObject.defineProperty(Readable.prototype, 'readableHighWaterMark', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function () {\n return this._readableState.highWaterMark;\n }\n});\n\n// exposed for testing purposes only.\nReadable._fromList = fromList;\n\n// Pluck off n bytes from an array of buffers.\n// Length is the combined lengths of all the buffers in the list.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction fromList(n, state) {\n // nothing buffered\n if (state.length === 0) return null;\n\n var ret;\n if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) {\n // read it all, truncate the list\n if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length);\n state.buffer.clear();\n } else {\n // read part of list\n ret = fromListPartial(n, state.buffer, state.decoder);\n }\n\n return ret;\n}\n\n// Extracts only enough buffered data to satisfy the amount requested.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction fromListPartial(n, list, hasStrings) {\n var ret;\n if (n < list.head.data.length) {\n // slice is the same for buffers and strings\n ret = list.head.data.slice(0, n);\n list.head.data = list.head.data.slice(n);\n } else if (n === list.head.data.length) {\n // first chunk is a perfect match\n ret = list.shift();\n } else {\n // result spans more than one buffer\n ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list);\n }\n return ret;\n}\n\n// Copies a specified amount of characters from the list of buffered data\n// chunks.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction copyFromBufferString(n, list) {\n var p = list.head;\n var c = 1;\n var ret = p.data;\n n -= ret.length;\n while (p = p.next) {\n var str = p.data;\n var nb = n > str.length ? str.length : n;\n if (nb === str.length) ret += str;else ret += str.slice(0, n);\n n -= nb;\n if (n === 0) {\n if (nb === str.length) {\n ++c;\n if (p.next) list.head = p.next;else list.head = list.tail = null;\n } else {\n list.head = p;\n p.data = str.slice(nb);\n }\n break;\n }\n ++c;\n }\n list.length -= c;\n return ret;\n}\n\n// Copies a specified amount of bytes from the list of buffered data chunks.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction copyFromBuffer(n, list) {\n var ret = Buffer.allocUnsafe(n);\n var p = list.head;\n var c = 1;\n p.data.copy(ret);\n n -= p.data.length;\n while (p = p.next) {\n var buf = p.data;\n var nb = n > buf.length ? buf.length : n;\n buf.copy(ret, ret.length - n, 0, nb);\n n -= nb;\n if (n === 0) {\n if (nb === buf.length) {\n ++c;\n if (p.next) list.head = p.next;else list.head = list.tail = null;\n } else {\n list.head = p;\n p.data = buf.slice(nb);\n }\n break;\n }\n ++c;\n }\n list.length -= c;\n return ret;\n}\n\nfunction endReadable(stream) {\n var state = stream._readableState;\n\n // If we get here before consuming all the bytes, then that is a\n // bug in node. Should never happen.\n if (state.length > 0) throw new Error('\"endReadable()\" called on non-empty stream');\n\n if (!state.endEmitted) {\n state.ended = true;\n pna.nextTick(endReadableNT, state, stream);\n }\n}\n\nfunction endReadableNT(state, stream) {\n // Check that we didn't get one last unshift.\n if (!state.endEmitted && state.length === 0) {\n state.endEmitted = true;\n stream.readable = false;\n stream.emit('end');\n }\n}\n\nfunction indexOf(xs, x) {\n for (var i = 0, l = xs.length; i < l; i++) {\n if (xs[i] === x) return i;\n }\n return -1;\n}","module.exports = require('events').EventEmitter;\n","'use strict';\n\n/**/\n\nvar pna = require('process-nextick-args');\n/**/\n\n// undocumented cb() API, needed for core, not for public API\nfunction destroy(err, cb) {\n var _this = this;\n\n var readableDestroyed = this._readableState && this._readableState.destroyed;\n var writableDestroyed = this._writableState && this._writableState.destroyed;\n\n if (readableDestroyed || writableDestroyed) {\n if (cb) {\n cb(err);\n } else if (err && (!this._writableState || !this._writableState.errorEmitted)) {\n pna.nextTick(emitErrorNT, this, err);\n }\n return this;\n }\n\n // we set destroyed to true before firing error callbacks in order\n // to make it re-entrance safe in case destroy() is called within callbacks\n\n if (this._readableState) {\n this._readableState.destroyed = true;\n }\n\n // if this is a duplex stream mark the writable part as destroyed as well\n if (this._writableState) {\n this._writableState.destroyed = true;\n }\n\n this._destroy(err || null, function (err) {\n if (!cb && err) {\n pna.nextTick(emitErrorNT, _this, err);\n if (_this._writableState) {\n _this._writableState.errorEmitted = true;\n }\n } else if (cb) {\n cb(err);\n }\n });\n\n return this;\n}\n\nfunction undestroy() {\n if (this._readableState) {\n this._readableState.destroyed = false;\n this._readableState.reading = false;\n this._readableState.ended = false;\n this._readableState.endEmitted = false;\n }\n\n if (this._writableState) {\n this._writableState.destroyed = false;\n this._writableState.ended = false;\n this._writableState.ending = false;\n this._writableState.finished = false;\n this._writableState.errorEmitted = false;\n }\n}\n\nfunction emitErrorNT(self, err) {\n self.emit('error', err);\n}\n\nmodule.exports = {\n destroy: destroy,\n undestroy: undestroy\n};","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// a transform stream is a readable/writable stream where you do\n// something with the data. Sometimes it's called a \"filter\",\n// but that's not a great name for it, since that implies a thing where\n// some bits pass through, and others are simply ignored. (That would\n// be a valid example of a transform, of course.)\n//\n// While the output is causally related to the input, it's not a\n// necessarily symmetric or synchronous transformation. For example,\n// a zlib stream might take multiple plain-text writes(), and then\n// emit a single compressed chunk some time in the future.\n//\n// Here's how this works:\n//\n// The Transform stream has all the aspects of the readable and writable\n// stream classes. When you write(chunk), that calls _write(chunk,cb)\n// internally, and returns false if there's a lot of pending writes\n// buffered up. When you call read(), that calls _read(n) until\n// there's enough pending readable data buffered up.\n//\n// In a transform stream, the written data is placed in a buffer. When\n// _read(n) is called, it transforms the queued up data, calling the\n// buffered _write cb's as it consumes chunks. If consuming a single\n// written chunk would result in multiple output chunks, then the first\n// outputted bit calls the readcb, and subsequent chunks just go into\n// the read buffer, and will cause it to emit 'readable' if necessary.\n//\n// This way, back-pressure is actually determined by the reading side,\n// since _read has to be called to start processing a new chunk. However,\n// a pathological inflate type of transform can cause excessive buffering\n// here. For example, imagine a stream where every byte of input is\n// interpreted as an integer from 0-255, and then results in that many\n// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in\n// 1kb of data being output. In this case, you could write a very small\n// amount of input, and end up with a very large amount of output. In\n// such a pathological inflating mechanism, there'd be no way to tell\n// the system to stop doing the transform. A single 4MB write could\n// cause the system to run out of memory.\n//\n// However, even in such a pathological case, only a single written chunk\n// would be consumed, and then the rest would wait (un-transformed) until\n// the results of the previous transformed chunk were consumed.\n\n'use strict';\n\nmodule.exports = Transform;\n\nvar Duplex = require('./_stream_duplex');\n\n/**/\nvar util = Object.create(require('core-util-is'));\nutil.inherits = require('inherits');\n/**/\n\nutil.inherits(Transform, Duplex);\n\nfunction afterTransform(er, data) {\n var ts = this._transformState;\n ts.transforming = false;\n\n var cb = ts.writecb;\n\n if (!cb) {\n return this.emit('error', new Error('write callback called multiple times'));\n }\n\n ts.writechunk = null;\n ts.writecb = null;\n\n if (data != null) // single equals check for both `null` and `undefined`\n this.push(data);\n\n cb(er);\n\n var rs = this._readableState;\n rs.reading = false;\n if (rs.needReadable || rs.length < rs.highWaterMark) {\n this._read(rs.highWaterMark);\n }\n}\n\nfunction Transform(options) {\n if (!(this instanceof Transform)) return new Transform(options);\n\n Duplex.call(this, options);\n\n this._transformState = {\n afterTransform: afterTransform.bind(this),\n needTransform: false,\n transforming: false,\n writecb: null,\n writechunk: null,\n writeencoding: null\n };\n\n // start out asking for a readable event once data is transformed.\n this._readableState.needReadable = true;\n\n // we have implemented the _read method, and done the other things\n // that Readable wants before the first _read call, so unset the\n // sync guard flag.\n this._readableState.sync = false;\n\n if (options) {\n if (typeof options.transform === 'function') this._transform = options.transform;\n\n if (typeof options.flush === 'function') this._flush = options.flush;\n }\n\n // When the writable side finishes, then flush out anything remaining.\n this.on('prefinish', prefinish);\n}\n\nfunction prefinish() {\n var _this = this;\n\n if (typeof this._flush === 'function') {\n this._flush(function (er, data) {\n done(_this, er, data);\n });\n } else {\n done(this, null, null);\n }\n}\n\nTransform.prototype.push = function (chunk, encoding) {\n this._transformState.needTransform = false;\n return Duplex.prototype.push.call(this, chunk, encoding);\n};\n\n// This is the part where you do stuff!\n// override this function in implementation classes.\n// 'chunk' is an input chunk.\n//\n// Call `push(newChunk)` to pass along transformed output\n// to the readable side. You may call 'push' zero or more times.\n//\n// Call `cb(err)` when you are done with this chunk. If you pass\n// an error, then that'll put the hurt on the whole operation. If you\n// never call cb(), then you'll never get another chunk.\nTransform.prototype._transform = function (chunk, encoding, cb) {\n throw new Error('_transform() is not implemented');\n};\n\nTransform.prototype._write = function (chunk, encoding, cb) {\n var ts = this._transformState;\n ts.writecb = cb;\n ts.writechunk = chunk;\n ts.writeencoding = encoding;\n if (!ts.transforming) {\n var rs = this._readableState;\n if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);\n }\n};\n\n// Doesn't matter what the args are here.\n// _transform does all the work.\n// That we got here means that the readable side wants more data.\nTransform.prototype._read = function (n) {\n var ts = this._transformState;\n\n if (ts.writechunk !== null && ts.writecb && !ts.transforming) {\n ts.transforming = true;\n this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);\n } else {\n // mark that we need a transform, so that any data that comes in\n // will get processed, now that we've asked for it.\n ts.needTransform = true;\n }\n};\n\nTransform.prototype._destroy = function (err, cb) {\n var _this2 = this;\n\n Duplex.prototype._destroy.call(this, err, function (err2) {\n cb(err2);\n _this2.emit('close');\n });\n};\n\nfunction done(stream, er, data) {\n if (er) return stream.emit('error', er);\n\n if (data != null) // single equals check for both `null` and `undefined`\n stream.push(data);\n\n // if there's nothing in the write buffer, then that means\n // that nothing more will ever be provided\n if (stream._writableState.length) throw new Error('Calling transform done when ws.length != 0');\n\n if (stream._transformState.transforming) throw new Error('Calling transform done when still transforming');\n\n return stream.push(null);\n}","'use strict'\nvar inherits = require('inherits')\nvar Legacy = require('./legacy')\nvar Base = require('cipher-base')\nvar Buffer = require('safe-buffer').Buffer\nvar md5 = require('create-hash/md5')\nvar RIPEMD160 = require('ripemd160')\n\nvar sha = require('sha.js')\n\nvar ZEROS = Buffer.alloc(128)\n\nfunction Hmac (alg, key) {\n Base.call(this, 'digest')\n if (typeof key === 'string') {\n key = Buffer.from(key)\n }\n\n var blocksize = (alg === 'sha512' || alg === 'sha384') ? 128 : 64\n\n this._alg = alg\n this._key = key\n if (key.length > blocksize) {\n var hash = alg === 'rmd160' ? new RIPEMD160() : sha(alg)\n key = hash.update(key).digest()\n } else if (key.length < blocksize) {\n key = Buffer.concat([key, ZEROS], blocksize)\n }\n\n var ipad = this._ipad = Buffer.allocUnsafe(blocksize)\n var opad = this._opad = Buffer.allocUnsafe(blocksize)\n\n for (var i = 0; i < blocksize; i++) {\n ipad[i] = key[i] ^ 0x36\n opad[i] = key[i] ^ 0x5C\n }\n this._hash = alg === 'rmd160' ? new RIPEMD160() : sha(alg)\n this._hash.update(ipad)\n}\n\ninherits(Hmac, Base)\n\nHmac.prototype._update = function (data) {\n this._hash.update(data)\n}\n\nHmac.prototype._final = function () {\n var h = this._hash.digest()\n var hash = this._alg === 'rmd160' ? new RIPEMD160() : sha(this._alg)\n return hash.update(this._opad).update(h).digest()\n}\n\nmodule.exports = function createHmac (alg, key) {\n alg = alg.toLowerCase()\n if (alg === 'rmd160' || alg === 'ripemd160') {\n return new Hmac('rmd160', key)\n }\n if (alg === 'md5') {\n return new Legacy(md5, key)\n }\n return new Hmac(alg, key)\n}\n","var MD5 = require('md5.js')\n\nmodule.exports = function (buffer) {\n return new MD5().update(buffer).digest()\n}\n","exports.pbkdf2 = require('./lib/async')\nexports.pbkdf2Sync = require('./lib/sync')\n","var MAX_ALLOC = Math.pow(2, 30) - 1 // default in iojs\n\nfunction checkBuffer (buf, name) {\n if (typeof buf !== 'string' && !Buffer.isBuffer(buf)) {\n throw new TypeError(name + ' must be a buffer or string')\n }\n}\n\nmodule.exports = function (password, salt, iterations, keylen) {\n checkBuffer(password, 'Password')\n checkBuffer(salt, 'Salt')\n\n if (typeof iterations !== 'number') {\n throw new TypeError('Iterations not a number')\n }\n\n if (iterations < 0) {\n throw new TypeError('Bad iterations')\n }\n\n if (typeof keylen !== 'number') {\n throw new TypeError('Key length not a number')\n }\n\n if (keylen < 0 || keylen > MAX_ALLOC || keylen !== keylen) { /* eslint no-self-compare: 0 */\n throw new TypeError('Bad key length')\n }\n}\n","var defaultEncoding\n/* istanbul ignore next */\nif (process.browser) {\n defaultEncoding = 'utf-8'\n} else {\n var pVersionMajor = parseInt(process.version.split('.')[0].slice(1), 10)\n\n defaultEncoding = pVersionMajor >= 6 ? 'utf-8' : 'binary'\n}\nmodule.exports = defaultEncoding\n","var md5 = require('create-hash/md5')\nvar RIPEMD160 = require('ripemd160')\nvar sha = require('sha.js')\n\nvar checkParameters = require('./precondition')\nvar defaultEncoding = require('./default-encoding')\nvar Buffer = require('safe-buffer').Buffer\nvar ZEROS = Buffer.alloc(128)\nvar sizes = {\n md5: 16,\n sha1: 20,\n sha224: 28,\n sha256: 32,\n sha384: 48,\n sha512: 64,\n rmd160: 20,\n ripemd160: 20\n}\n\nfunction Hmac (alg, key, saltLen) {\n var hash = getDigest(alg)\n var blocksize = (alg === 'sha512' || alg === 'sha384') ? 128 : 64\n\n if (key.length > blocksize) {\n key = hash(key)\n } else if (key.length < blocksize) {\n key = Buffer.concat([key, ZEROS], blocksize)\n }\n\n var ipad = Buffer.allocUnsafe(blocksize + sizes[alg])\n var opad = Buffer.allocUnsafe(blocksize + sizes[alg])\n for (var i = 0; i < blocksize; i++) {\n ipad[i] = key[i] ^ 0x36\n opad[i] = key[i] ^ 0x5C\n }\n\n var ipad1 = Buffer.allocUnsafe(blocksize + saltLen + 4)\n ipad.copy(ipad1, 0, 0, blocksize)\n this.ipad1 = ipad1\n this.ipad2 = ipad\n this.opad = opad\n this.alg = alg\n this.blocksize = blocksize\n this.hash = hash\n this.size = sizes[alg]\n}\n\nHmac.prototype.run = function (data, ipad) {\n data.copy(ipad, this.blocksize)\n var h = this.hash(ipad)\n h.copy(this.opad, this.blocksize)\n return this.hash(this.opad)\n}\n\nfunction getDigest (alg) {\n function shaFunc (data) {\n return sha(alg).update(data).digest()\n }\n function rmd160Func (data) {\n return new RIPEMD160().update(data).digest()\n }\n\n if (alg === 'rmd160' || alg === 'ripemd160') return rmd160Func\n if (alg === 'md5') return md5\n return shaFunc\n}\n\nfunction pbkdf2 (password, salt, iterations, keylen, digest) {\n checkParameters(password, salt, iterations, keylen)\n\n if (!Buffer.isBuffer(password)) password = Buffer.from(password, defaultEncoding)\n if (!Buffer.isBuffer(salt)) salt = Buffer.from(salt, defaultEncoding)\n\n digest = digest || 'sha1'\n\n var hmac = new Hmac(digest, password, salt.length)\n\n var DK = Buffer.allocUnsafe(keylen)\n var block1 = Buffer.allocUnsafe(salt.length + 4)\n salt.copy(block1, 0, 0, salt.length)\n\n var destPos = 0\n var hLen = sizes[digest]\n var l = Math.ceil(keylen / hLen)\n\n for (var i = 1; i <= l; i++) {\n block1.writeUInt32BE(i, salt.length)\n\n var T = hmac.run(block1, hmac.ipad1)\n var U = T\n\n for (var j = 1; j < iterations; j++) {\n U = hmac.run(U, hmac.ipad2)\n for (var k = 0; k < hLen; k++) T[k] ^= U[k]\n }\n\n T.copy(DK, destPos)\n destPos += hLen\n }\n\n return DK\n}\n\nmodule.exports = pbkdf2\n","'use strict';\n\nexports.readUInt32BE = function readUInt32BE(bytes, off) {\n var res = (bytes[0 + off] << 24) |\n (bytes[1 + off] << 16) |\n (bytes[2 + off] << 8) |\n bytes[3 + off];\n return res >>> 0;\n};\n\nexports.writeUInt32BE = function writeUInt32BE(bytes, value, off) {\n bytes[0 + off] = value >>> 24;\n bytes[1 + off] = (value >>> 16) & 0xff;\n bytes[2 + off] = (value >>> 8) & 0xff;\n bytes[3 + off] = value & 0xff;\n};\n\nexports.ip = function ip(inL, inR, out, off) {\n var outL = 0;\n var outR = 0;\n\n for (var i = 6; i >= 0; i -= 2) {\n for (var j = 0; j <= 24; j += 8) {\n outL <<= 1;\n outL |= (inR >>> (j + i)) & 1;\n }\n for (var j = 0; j <= 24; j += 8) {\n outL <<= 1;\n outL |= (inL >>> (j + i)) & 1;\n }\n }\n\n for (var i = 6; i >= 0; i -= 2) {\n for (var j = 1; j <= 25; j += 8) {\n outR <<= 1;\n outR |= (inR >>> (j + i)) & 1;\n }\n for (var j = 1; j <= 25; j += 8) {\n outR <<= 1;\n outR |= (inL >>> (j + i)) & 1;\n }\n }\n\n out[off + 0] = outL >>> 0;\n out[off + 1] = outR >>> 0;\n};\n\nexports.rip = function rip(inL, inR, out, off) {\n var outL = 0;\n var outR = 0;\n\n for (var i = 0; i < 4; i++) {\n for (var j = 24; j >= 0; j -= 8) {\n outL <<= 1;\n outL |= (inR >>> (j + i)) & 1;\n outL <<= 1;\n outL |= (inL >>> (j + i)) & 1;\n }\n }\n for (var i = 4; i < 8; i++) {\n for (var j = 24; j >= 0; j -= 8) {\n outR <<= 1;\n outR |= (inR >>> (j + i)) & 1;\n outR <<= 1;\n outR |= (inL >>> (j + i)) & 1;\n }\n }\n\n out[off + 0] = outL >>> 0;\n out[off + 1] = outR >>> 0;\n};\n\nexports.pc1 = function pc1(inL, inR, out, off) {\n var outL = 0;\n var outR = 0;\n\n // 7, 15, 23, 31, 39, 47, 55, 63\n // 6, 14, 22, 30, 39, 47, 55, 63\n // 5, 13, 21, 29, 39, 47, 55, 63\n // 4, 12, 20, 28\n for (var i = 7; i >= 5; i--) {\n for (var j = 0; j <= 24; j += 8) {\n outL <<= 1;\n outL |= (inR >> (j + i)) & 1;\n }\n for (var j = 0; j <= 24; j += 8) {\n outL <<= 1;\n outL |= (inL >> (j + i)) & 1;\n }\n }\n for (var j = 0; j <= 24; j += 8) {\n outL <<= 1;\n outL |= (inR >> (j + i)) & 1;\n }\n\n // 1, 9, 17, 25, 33, 41, 49, 57\n // 2, 10, 18, 26, 34, 42, 50, 58\n // 3, 11, 19, 27, 35, 43, 51, 59\n // 36, 44, 52, 60\n for (var i = 1; i <= 3; i++) {\n for (var j = 0; j <= 24; j += 8) {\n outR <<= 1;\n outR |= (inR >> (j + i)) & 1;\n }\n for (var j = 0; j <= 24; j += 8) {\n outR <<= 1;\n outR |= (inL >> (j + i)) & 1;\n }\n }\n for (var j = 0; j <= 24; j += 8) {\n outR <<= 1;\n outR |= (inL >> (j + i)) & 1;\n }\n\n out[off + 0] = outL >>> 0;\n out[off + 1] = outR >>> 0;\n};\n\nexports.r28shl = function r28shl(num, shift) {\n return ((num << shift) & 0xfffffff) | (num >>> (28 - shift));\n};\n\nvar pc2table = [\n // inL => outL\n 14, 11, 17, 4, 27, 23, 25, 0,\n 13, 22, 7, 18, 5, 9, 16, 24,\n 2, 20, 12, 21, 1, 8, 15, 26,\n\n // inR => outR\n 15, 4, 25, 19, 9, 1, 26, 16,\n 5, 11, 23, 8, 12, 7, 17, 0,\n 22, 3, 10, 14, 6, 20, 27, 24\n];\n\nexports.pc2 = function pc2(inL, inR, out, off) {\n var outL = 0;\n var outR = 0;\n\n var len = pc2table.length >>> 1;\n for (var i = 0; i < len; i++) {\n outL <<= 1;\n outL |= (inL >>> pc2table[i]) & 0x1;\n }\n for (var i = len; i < pc2table.length; i++) {\n outR <<= 1;\n outR |= (inR >>> pc2table[i]) & 0x1;\n }\n\n out[off + 0] = outL >>> 0;\n out[off + 1] = outR >>> 0;\n};\n\nexports.expand = function expand(r, out, off) {\n var outL = 0;\n var outR = 0;\n\n outL = ((r & 1) << 5) | (r >>> 27);\n for (var i = 23; i >= 15; i -= 4) {\n outL <<= 6;\n outL |= (r >>> i) & 0x3f;\n }\n for (var i = 11; i >= 3; i -= 4) {\n outR |= (r >>> i) & 0x3f;\n outR <<= 6;\n }\n outR |= ((r & 0x1f) << 1) | (r >>> 31);\n\n out[off + 0] = outL >>> 0;\n out[off + 1] = outR >>> 0;\n};\n\nvar sTable = [\n 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1,\n 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8,\n 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7,\n 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13,\n\n 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14,\n 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5,\n 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2,\n 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9,\n\n 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10,\n 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1,\n 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7,\n 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12,\n\n 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3,\n 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9,\n 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8,\n 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14,\n\n 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1,\n 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6,\n 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13,\n 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3,\n\n 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5,\n 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8,\n 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10,\n 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13,\n\n 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10,\n 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6,\n 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,\n 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12,\n\n 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4,\n 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2,\n 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13,\n 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11\n];\n\nexports.substitute = function substitute(inL, inR) {\n var out = 0;\n for (var i = 0; i < 4; i++) {\n var b = (inL >>> (18 - i * 6)) & 0x3f;\n var sb = sTable[i * 0x40 + b];\n\n out <<= 4;\n out |= sb;\n }\n for (var i = 0; i < 4; i++) {\n var b = (inR >>> (18 - i * 6)) & 0x3f;\n var sb = sTable[4 * 0x40 + i * 0x40 + b];\n\n out <<= 4;\n out |= sb;\n }\n return out >>> 0;\n};\n\nvar permuteTable = [\n 16, 25, 12, 11, 3, 20, 4, 15, 31, 17, 9, 6, 27, 14, 1, 22,\n 30, 24, 8, 18, 0, 5, 29, 23, 13, 19, 2, 26, 10, 21, 28, 7\n];\n\nexports.permute = function permute(num) {\n var out = 0;\n for (var i = 0; i < permuteTable.length; i++) {\n out <<= 1;\n out |= (num >>> permuteTable[i]) & 0x1;\n }\n return out >>> 0;\n};\n\nexports.padSplit = function padSplit(num, size, group) {\n var str = num.toString(2);\n while (str.length < size)\n str = '0' + str;\n\n var out = [];\n for (var i = 0; i < size; i += group)\n out.push(str.slice(i, i + group));\n return out.join(' ');\n};\n","'use strict';\n\nvar assert = require('minimalistic-assert');\nvar inherits = require('inherits');\n\nvar utils = require('./utils');\nvar Cipher = require('./cipher');\n\nfunction DESState() {\n this.tmp = new Array(2);\n this.keys = null;\n}\n\nfunction DES(options) {\n Cipher.call(this, options);\n\n var state = new DESState();\n this._desState = state;\n\n this.deriveKeys(state, options.key);\n}\ninherits(DES, Cipher);\nmodule.exports = DES;\n\nDES.create = function create(options) {\n return new DES(options);\n};\n\nvar shiftTable = [\n 1, 1, 2, 2, 2, 2, 2, 2,\n 1, 2, 2, 2, 2, 2, 2, 1\n];\n\nDES.prototype.deriveKeys = function deriveKeys(state, key) {\n state.keys = new Array(16 * 2);\n\n assert.equal(key.length, this.blockSize, 'Invalid key length');\n\n var kL = utils.readUInt32BE(key, 0);\n var kR = utils.readUInt32BE(key, 4);\n\n utils.pc1(kL, kR, state.tmp, 0);\n kL = state.tmp[0];\n kR = state.tmp[1];\n for (var i = 0; i < state.keys.length; i += 2) {\n var shift = shiftTable[i >>> 1];\n kL = utils.r28shl(kL, shift);\n kR = utils.r28shl(kR, shift);\n utils.pc2(kL, kR, state.keys, i);\n }\n};\n\nDES.prototype._update = function _update(inp, inOff, out, outOff) {\n var state = this._desState;\n\n var l = utils.readUInt32BE(inp, inOff);\n var r = utils.readUInt32BE(inp, inOff + 4);\n\n // Initial Permutation\n utils.ip(l, r, state.tmp, 0);\n l = state.tmp[0];\n r = state.tmp[1];\n\n if (this.type === 'encrypt')\n this._encrypt(state, l, r, state.tmp, 0);\n else\n this._decrypt(state, l, r, state.tmp, 0);\n\n l = state.tmp[0];\n r = state.tmp[1];\n\n utils.writeUInt32BE(out, l, outOff);\n utils.writeUInt32BE(out, r, outOff + 4);\n};\n\nDES.prototype._pad = function _pad(buffer, off) {\n var value = buffer.length - off;\n for (var i = off; i < buffer.length; i++)\n buffer[i] = value;\n\n return true;\n};\n\nDES.prototype._unpad = function _unpad(buffer) {\n var pad = buffer[buffer.length - 1];\n for (var i = buffer.length - pad; i < buffer.length; i++)\n assert.equal(buffer[i], pad);\n\n return buffer.slice(0, buffer.length - pad);\n};\n\nDES.prototype._encrypt = function _encrypt(state, lStart, rStart, out, off) {\n var l = lStart;\n var r = rStart;\n\n // Apply f() x16 times\n for (var i = 0; i < state.keys.length; i += 2) {\n var keyL = state.keys[i];\n var keyR = state.keys[i + 1];\n\n // f(r, k)\n utils.expand(r, state.tmp, 0);\n\n keyL ^= state.tmp[0];\n keyR ^= state.tmp[1];\n var s = utils.substitute(keyL, keyR);\n var f = utils.permute(s);\n\n var t = r;\n r = (l ^ f) >>> 0;\n l = t;\n }\n\n // Reverse Initial Permutation\n utils.rip(r, l, out, off);\n};\n\nDES.prototype._decrypt = function _decrypt(state, lStart, rStart, out, off) {\n var l = rStart;\n var r = lStart;\n\n // Apply f() x16 times\n for (var i = state.keys.length - 2; i >= 0; i -= 2) {\n var keyL = state.keys[i];\n var keyR = state.keys[i + 1];\n\n // f(r, k)\n utils.expand(l, state.tmp, 0);\n\n keyL ^= state.tmp[0];\n keyR ^= state.tmp[1];\n var s = utils.substitute(keyL, keyR);\n var f = utils.permute(s);\n\n var t = l;\n l = (r ^ f) >>> 0;\n r = t;\n }\n\n // Reverse Initial Permutation\n utils.rip(l, r, out, off);\n};\n","var xor = require('buffer-xor')\nvar Buffer = require('safe-buffer').Buffer\nvar incr32 = require('../incr32')\n\nfunction getBlock (self) {\n var out = self._cipher.encryptBlockRaw(self._prev)\n incr32(self._prev)\n return out\n}\n\nvar blockSize = 16\nexports.encrypt = function (self, chunk) {\n var chunkNum = Math.ceil(chunk.length / blockSize)\n var start = self._cache.length\n self._cache = Buffer.concat([\n self._cache,\n Buffer.allocUnsafe(chunkNum * blockSize)\n ])\n for (var i = 0; i < chunkNum; i++) {\n var out = getBlock(self)\n var offset = start + i * blockSize\n self._cache.writeUInt32BE(out[0], offset + 0)\n self._cache.writeUInt32BE(out[1], offset + 4)\n self._cache.writeUInt32BE(out[2], offset + 8)\n self._cache.writeUInt32BE(out[3], offset + 12)\n }\n var pad = self._cache.slice(0, chunk.length)\n self._cache = self._cache.slice(chunk.length)\n return xor(chunk, pad)\n}\n","function incr32 (iv) {\n var len = iv.length\n var item\n while (len--) {\n item = iv.readUInt8(len)\n if (item === 255) {\n iv.writeUInt8(0, len)\n } else {\n item++\n iv.writeUInt8(item, len)\n break\n }\n }\n}\nmodule.exports = incr32\n","var aes = require('./aes')\nvar Buffer = require('safe-buffer').Buffer\nvar Transform = require('cipher-base')\nvar inherits = require('inherits')\nvar GHASH = require('./ghash')\nvar xor = require('buffer-xor')\nvar incr32 = require('./incr32')\n\nfunction xorTest (a, b) {\n var out = 0\n if (a.length !== b.length) out++\n\n var len = Math.min(a.length, b.length)\n for (var i = 0; i < len; ++i) {\n out += (a[i] ^ b[i])\n }\n\n return out\n}\n\nfunction calcIv (self, iv, ck) {\n if (iv.length === 12) {\n self._finID = Buffer.concat([iv, Buffer.from([0, 0, 0, 1])])\n return Buffer.concat([iv, Buffer.from([0, 0, 0, 2])])\n }\n var ghash = new GHASH(ck)\n var len = iv.length\n var toPad = len % 16\n ghash.update(iv)\n if (toPad) {\n toPad = 16 - toPad\n ghash.update(Buffer.alloc(toPad, 0))\n }\n ghash.update(Buffer.alloc(8, 0))\n var ivBits = len * 8\n var tail = Buffer.alloc(8)\n tail.writeUIntBE(ivBits, 0, 8)\n ghash.update(tail)\n self._finID = ghash.state\n var out = Buffer.from(self._finID)\n incr32(out)\n return out\n}\nfunction StreamCipher (mode, key, iv, decrypt) {\n Transform.call(this)\n\n var h = Buffer.alloc(4, 0)\n\n this._cipher = new aes.AES(key)\n var ck = this._cipher.encryptBlock(h)\n this._ghash = new GHASH(ck)\n iv = calcIv(this, iv, ck)\n\n this._prev = Buffer.from(iv)\n this._cache = Buffer.allocUnsafe(0)\n this._secCache = Buffer.allocUnsafe(0)\n this._decrypt = decrypt\n this._alen = 0\n this._len = 0\n this._mode = mode\n\n this._authTag = null\n this._called = false\n}\n\ninherits(StreamCipher, Transform)\n\nStreamCipher.prototype._update = function (chunk) {\n if (!this._called && this._alen) {\n var rump = 16 - (this._alen % 16)\n if (rump < 16) {\n rump = Buffer.alloc(rump, 0)\n this._ghash.update(rump)\n }\n }\n\n this._called = true\n var out = this._mode.encrypt(this, chunk)\n if (this._decrypt) {\n this._ghash.update(chunk)\n } else {\n this._ghash.update(out)\n }\n this._len += chunk.length\n return out\n}\n\nStreamCipher.prototype._final = function () {\n if (this._decrypt && !this._authTag) throw new Error('Unsupported state or unable to authenticate data')\n\n var tag = xor(this._ghash.final(this._alen * 8, this._len * 8), this._cipher.encryptBlock(this._finID))\n if (this._decrypt && xorTest(tag, this._authTag)) throw new Error('Unsupported state or unable to authenticate data')\n\n this._authTag = tag\n this._cipher.scrub()\n}\n\nStreamCipher.prototype.getAuthTag = function getAuthTag () {\n if (this._decrypt || !Buffer.isBuffer(this._authTag)) throw new Error('Attempting to get auth tag in unsupported state')\n\n return this._authTag\n}\n\nStreamCipher.prototype.setAuthTag = function setAuthTag (tag) {\n if (!this._decrypt) throw new Error('Attempting to set auth tag in unsupported state')\n\n this._authTag = tag\n}\n\nStreamCipher.prototype.setAAD = function setAAD (buf) {\n if (this._called) throw new Error('Attempting to set AAD in unsupported state')\n\n this._ghash.update(buf)\n this._alen += buf.length\n}\n\nmodule.exports = StreamCipher\n","var aes = require('./aes')\nvar Buffer = require('safe-buffer').Buffer\nvar Transform = require('cipher-base')\nvar inherits = require('inherits')\n\nfunction StreamCipher (mode, key, iv, decrypt) {\n Transform.call(this)\n\n this._cipher = new aes.AES(key)\n this._prev = Buffer.from(iv)\n this._cache = Buffer.allocUnsafe(0)\n this._secCache = Buffer.allocUnsafe(0)\n this._decrypt = decrypt\n this._mode = mode\n}\n\ninherits(StreamCipher, Transform)\n\nStreamCipher.prototype._update = function (chunk) {\n return this._mode.encrypt(this, chunk, this._decrypt)\n}\n\nStreamCipher.prototype._final = function () {\n this._cipher.scrub()\n}\n\nmodule.exports = StreamCipher\n","var randomBytes = require('randombytes');\nmodule.exports = findPrime;\nfindPrime.simpleSieve = simpleSieve;\nfindPrime.fermatTest = fermatTest;\nvar BN = require('bn.js');\nvar TWENTYFOUR = new BN(24);\nvar MillerRabin = require('miller-rabin');\nvar millerRabin = new MillerRabin();\nvar ONE = new BN(1);\nvar TWO = new BN(2);\nvar FIVE = new BN(5);\nvar SIXTEEN = new BN(16);\nvar EIGHT = new BN(8);\nvar TEN = new BN(10);\nvar THREE = new BN(3);\nvar SEVEN = new BN(7);\nvar ELEVEN = new BN(11);\nvar FOUR = new BN(4);\nvar TWELVE = new BN(12);\nvar primes = null;\n\nfunction _getPrimes() {\n if (primes !== null)\n return primes;\n\n var limit = 0x100000;\n var res = [];\n res[0] = 2;\n for (var i = 1, k = 3; k < limit; k += 2) {\n var sqrt = Math.ceil(Math.sqrt(k));\n for (var j = 0; j < i && res[j] <= sqrt; j++)\n if (k % res[j] === 0)\n break;\n\n if (i !== j && res[j] <= sqrt)\n continue;\n\n res[i++] = k;\n }\n primes = res;\n return res;\n}\n\nfunction simpleSieve(p) {\n var primes = _getPrimes();\n\n for (var i = 0; i < primes.length; i++)\n if (p.modn(primes[i]) === 0) {\n if (p.cmpn(primes[i]) === 0) {\n return true;\n } else {\n return false;\n }\n }\n\n return true;\n}\n\nfunction fermatTest(p) {\n var red = BN.mont(p);\n return TWO.toRed(red).redPow(p.subn(1)).fromRed().cmpn(1) === 0;\n}\n\nfunction findPrime(bits, gen) {\n if (bits < 16) {\n // this is what openssl does\n if (gen === 2 || gen === 5) {\n return new BN([0x8c, 0x7b]);\n } else {\n return new BN([0x8c, 0x27]);\n }\n }\n gen = new BN(gen);\n\n var num, n2;\n\n while (true) {\n num = new BN(randomBytes(Math.ceil(bits / 8)));\n while (num.bitLength() > bits) {\n num.ishrn(1);\n }\n if (num.isEven()) {\n num.iadd(ONE);\n }\n if (!num.testn(1)) {\n num.iadd(TWO);\n }\n if (!gen.cmp(TWO)) {\n while (num.mod(TWENTYFOUR).cmp(ELEVEN)) {\n num.iadd(FOUR);\n }\n } else if (!gen.cmp(FIVE)) {\n while (num.mod(TEN).cmp(THREE)) {\n num.iadd(FOUR);\n }\n }\n n2 = num.shrn(1);\n if (simpleSieve(n2) && simpleSieve(num) &&\n fermatTest(n2) && fermatTest(num) &&\n millerRabin.test(n2) && millerRabin.test(num)) {\n return num;\n }\n }\n\n}\n","(function (module, exports) {\n 'use strict';\n\n // Utils\n function assert (val, msg) {\n if (!val) throw new Error(msg || 'Assertion failed');\n }\n\n // Could use `inherits` module, but don't want to move from single file\n // architecture yet.\n function inherits (ctor, superCtor) {\n ctor.super_ = superCtor;\n var TempCtor = function () {};\n TempCtor.prototype = superCtor.prototype;\n ctor.prototype = new TempCtor();\n ctor.prototype.constructor = ctor;\n }\n\n // BN\n\n function BN (number, base, endian) {\n if (BN.isBN(number)) {\n return number;\n }\n\n this.negative = 0;\n this.words = null;\n this.length = 0;\n\n // Reduction context\n this.red = null;\n\n if (number !== null) {\n if (base === 'le' || base === 'be') {\n endian = base;\n base = 10;\n }\n\n this._init(number || 0, base || 10, endian || 'be');\n }\n }\n if (typeof module === 'object') {\n module.exports = BN;\n } else {\n exports.BN = BN;\n }\n\n BN.BN = BN;\n BN.wordSize = 26;\n\n var Buffer;\n try {\n Buffer = require('buffer').Buffer;\n } catch (e) {\n }\n\n BN.isBN = function isBN (num) {\n if (num instanceof BN) {\n return true;\n }\n\n return num !== null && typeof num === 'object' &&\n num.constructor.wordSize === BN.wordSize && Array.isArray(num.words);\n };\n\n BN.max = function max (left, right) {\n if (left.cmp(right) > 0) return left;\n return right;\n };\n\n BN.min = function min (left, right) {\n if (left.cmp(right) < 0) return left;\n return right;\n };\n\n BN.prototype._init = function init (number, base, endian) {\n if (typeof number === 'number') {\n return this._initNumber(number, base, endian);\n }\n\n if (typeof number === 'object') {\n return this._initArray(number, base, endian);\n }\n\n if (base === 'hex') {\n base = 16;\n }\n assert(base === (base | 0) && base >= 2 && base <= 36);\n\n number = number.toString().replace(/\\s+/g, '');\n var start = 0;\n if (number[0] === '-') {\n start++;\n }\n\n if (base === 16) {\n this._parseHex(number, start);\n } else {\n this._parseBase(number, base, start);\n }\n\n if (number[0] === '-') {\n this.negative = 1;\n }\n\n this.strip();\n\n if (endian !== 'le') return;\n\n this._initArray(this.toArray(), base, endian);\n };\n\n BN.prototype._initNumber = function _initNumber (number, base, endian) {\n if (number < 0) {\n this.negative = 1;\n number = -number;\n }\n if (number < 0x4000000) {\n this.words = [ number & 0x3ffffff ];\n this.length = 1;\n } else if (number < 0x10000000000000) {\n this.words = [\n number & 0x3ffffff,\n (number / 0x4000000) & 0x3ffffff\n ];\n this.length = 2;\n } else {\n assert(number < 0x20000000000000); // 2 ^ 53 (unsafe)\n this.words = [\n number & 0x3ffffff,\n (number / 0x4000000) & 0x3ffffff,\n 1\n ];\n this.length = 3;\n }\n\n if (endian !== 'le') return;\n\n // Reverse the bytes\n this._initArray(this.toArray(), base, endian);\n };\n\n BN.prototype._initArray = function _initArray (number, base, endian) {\n // Perhaps a Uint8Array\n assert(typeof number.length === 'number');\n if (number.length <= 0) {\n this.words = [ 0 ];\n this.length = 1;\n return this;\n }\n\n this.length = Math.ceil(number.length / 3);\n this.words = new Array(this.length);\n for (var i = 0; i < this.length; i++) {\n this.words[i] = 0;\n }\n\n var j, w;\n var off = 0;\n if (endian === 'be') {\n for (i = number.length - 1, j = 0; i >= 0; i -= 3) {\n w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16);\n this.words[j] |= (w << off) & 0x3ffffff;\n this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;\n off += 24;\n if (off >= 26) {\n off -= 26;\n j++;\n }\n }\n } else if (endian === 'le') {\n for (i = 0, j = 0; i < number.length; i += 3) {\n w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16);\n this.words[j] |= (w << off) & 0x3ffffff;\n this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;\n off += 24;\n if (off >= 26) {\n off -= 26;\n j++;\n }\n }\n }\n return this.strip();\n };\n\n function parseHex (str, start, end) {\n var r = 0;\n var len = Math.min(str.length, end);\n for (var i = start; i < len; i++) {\n var c = str.charCodeAt(i) - 48;\n\n r <<= 4;\n\n // 'a' - 'f'\n if (c >= 49 && c <= 54) {\n r |= c - 49 + 0xa;\n\n // 'A' - 'F'\n } else if (c >= 17 && c <= 22) {\n r |= c - 17 + 0xa;\n\n // '0' - '9'\n } else {\n r |= c & 0xf;\n }\n }\n return r;\n }\n\n BN.prototype._parseHex = function _parseHex (number, start) {\n // Create possibly bigger array to ensure that it fits the number\n this.length = Math.ceil((number.length - start) / 6);\n this.words = new Array(this.length);\n for (var i = 0; i < this.length; i++) {\n this.words[i] = 0;\n }\n\n var j, w;\n // Scan 24-bit chunks and add them to the number\n var off = 0;\n for (i = number.length - 6, j = 0; i >= start; i -= 6) {\n w = parseHex(number, i, i + 6);\n this.words[j] |= (w << off) & 0x3ffffff;\n // NOTE: `0x3fffff` is intentional here, 26bits max shift + 24bit hex limb\n this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;\n off += 24;\n if (off >= 26) {\n off -= 26;\n j++;\n }\n }\n if (i + 6 !== start) {\n w = parseHex(number, start, i + 6);\n this.words[j] |= (w << off) & 0x3ffffff;\n this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;\n }\n this.strip();\n };\n\n function parseBase (str, start, end, mul) {\n var r = 0;\n var len = Math.min(str.length, end);\n for (var i = start; i < len; i++) {\n var c = str.charCodeAt(i) - 48;\n\n r *= mul;\n\n // 'a'\n if (c >= 49) {\n r += c - 49 + 0xa;\n\n // 'A'\n } else if (c >= 17) {\n r += c - 17 + 0xa;\n\n // '0' - '9'\n } else {\n r += c;\n }\n }\n return r;\n }\n\n BN.prototype._parseBase = function _parseBase (number, base, start) {\n // Initialize as zero\n this.words = [ 0 ];\n this.length = 1;\n\n // Find length of limb in base\n for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) {\n limbLen++;\n }\n limbLen--;\n limbPow = (limbPow / base) | 0;\n\n var total = number.length - start;\n var mod = total % limbLen;\n var end = Math.min(total, total - mod) + start;\n\n var word = 0;\n for (var i = start; i < end; i += limbLen) {\n word = parseBase(number, i, i + limbLen, base);\n\n this.imuln(limbPow);\n if (this.words[0] + word < 0x4000000) {\n this.words[0] += word;\n } else {\n this._iaddn(word);\n }\n }\n\n if (mod !== 0) {\n var pow = 1;\n word = parseBase(number, i, number.length, base);\n\n for (i = 0; i < mod; i++) {\n pow *= base;\n }\n\n this.imuln(pow);\n if (this.words[0] + word < 0x4000000) {\n this.words[0] += word;\n } else {\n this._iaddn(word);\n }\n }\n };\n\n BN.prototype.copy = function copy (dest) {\n dest.words = new Array(this.length);\n for (var i = 0; i < this.length; i++) {\n dest.words[i] = this.words[i];\n }\n dest.length = this.length;\n dest.negative = this.negative;\n dest.red = this.red;\n };\n\n BN.prototype.clone = function clone () {\n var r = new BN(null);\n this.copy(r);\n return r;\n };\n\n BN.prototype._expand = function _expand (size) {\n while (this.length < size) {\n this.words[this.length++] = 0;\n }\n return this;\n };\n\n // Remove leading `0` from `this`\n BN.prototype.strip = function strip () {\n while (this.length > 1 && this.words[this.length - 1] === 0) {\n this.length--;\n }\n return this._normSign();\n };\n\n BN.prototype._normSign = function _normSign () {\n // -0 = 0\n if (this.length === 1 && this.words[0] === 0) {\n this.negative = 0;\n }\n return this;\n };\n\n BN.prototype.inspect = function inspect () {\n return (this.red ? '';\n };\n\n /*\n\n var zeros = [];\n var groupSizes = [];\n var groupBases = [];\n\n var s = '';\n var i = -1;\n while (++i < BN.wordSize) {\n zeros[i] = s;\n s += '0';\n }\n groupSizes[0] = 0;\n groupSizes[1] = 0;\n groupBases[0] = 0;\n groupBases[1] = 0;\n var base = 2 - 1;\n while (++base < 36 + 1) {\n var groupSize = 0;\n var groupBase = 1;\n while (groupBase < (1 << BN.wordSize) / base) {\n groupBase *= base;\n groupSize += 1;\n }\n groupSizes[base] = groupSize;\n groupBases[base] = groupBase;\n }\n\n */\n\n var zeros = [\n '',\n '0',\n '00',\n '000',\n '0000',\n '00000',\n '000000',\n '0000000',\n '00000000',\n '000000000',\n '0000000000',\n '00000000000',\n '000000000000',\n '0000000000000',\n '00000000000000',\n '000000000000000',\n '0000000000000000',\n '00000000000000000',\n '000000000000000000',\n '0000000000000000000',\n '00000000000000000000',\n '000000000000000000000',\n '0000000000000000000000',\n '00000000000000000000000',\n '000000000000000000000000',\n '0000000000000000000000000'\n ];\n\n var groupSizes = [\n 0, 0,\n 25, 16, 12, 11, 10, 9, 8,\n 8, 7, 7, 7, 7, 6, 6,\n 6, 6, 6, 6, 6, 5, 5,\n 5, 5, 5, 5, 5, 5, 5,\n 5, 5, 5, 5, 5, 5, 5\n ];\n\n var groupBases = [\n 0, 0,\n 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216,\n 43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625,\n 16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632,\n 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149,\n 24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176\n ];\n\n BN.prototype.toString = function toString (base, padding) {\n base = base || 10;\n padding = padding | 0 || 1;\n\n var out;\n if (base === 16 || base === 'hex') {\n out = '';\n var off = 0;\n var carry = 0;\n for (var i = 0; i < this.length; i++) {\n var w = this.words[i];\n var word = (((w << off) | carry) & 0xffffff).toString(16);\n carry = (w >>> (24 - off)) & 0xffffff;\n if (carry !== 0 || i !== this.length - 1) {\n out = zeros[6 - word.length] + word + out;\n } else {\n out = word + out;\n }\n off += 2;\n if (off >= 26) {\n off -= 26;\n i--;\n }\n }\n if (carry !== 0) {\n out = carry.toString(16) + out;\n }\n while (out.length % padding !== 0) {\n out = '0' + out;\n }\n if (this.negative !== 0) {\n out = '-' + out;\n }\n return out;\n }\n\n if (base === (base | 0) && base >= 2 && base <= 36) {\n // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base));\n var groupSize = groupSizes[base];\n // var groupBase = Math.pow(base, groupSize);\n var groupBase = groupBases[base];\n out = '';\n var c = this.clone();\n c.negative = 0;\n while (!c.isZero()) {\n var r = c.modn(groupBase).toString(base);\n c = c.idivn(groupBase);\n\n if (!c.isZero()) {\n out = zeros[groupSize - r.length] + r + out;\n } else {\n out = r + out;\n }\n }\n if (this.isZero()) {\n out = '0' + out;\n }\n while (out.length % padding !== 0) {\n out = '0' + out;\n }\n if (this.negative !== 0) {\n out = '-' + out;\n }\n return out;\n }\n\n assert(false, 'Base should be between 2 and 36');\n };\n\n BN.prototype.toNumber = function toNumber () {\n var ret = this.words[0];\n if (this.length === 2) {\n ret += this.words[1] * 0x4000000;\n } else if (this.length === 3 && this.words[2] === 0x01) {\n // NOTE: at this stage it is known that the top bit is set\n ret += 0x10000000000000 + (this.words[1] * 0x4000000);\n } else if (this.length > 2) {\n assert(false, 'Number can only safely store up to 53 bits');\n }\n return (this.negative !== 0) ? -ret : ret;\n };\n\n BN.prototype.toJSON = function toJSON () {\n return this.toString(16);\n };\n\n BN.prototype.toBuffer = function toBuffer (endian, length) {\n assert(typeof Buffer !== 'undefined');\n return this.toArrayLike(Buffer, endian, length);\n };\n\n BN.prototype.toArray = function toArray (endian, length) {\n return this.toArrayLike(Array, endian, length);\n };\n\n BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) {\n var byteLength = this.byteLength();\n var reqLength = length || Math.max(1, byteLength);\n assert(byteLength <= reqLength, 'byte array longer than desired length');\n assert(reqLength > 0, 'Requested array length <= 0');\n\n this.strip();\n var littleEndian = endian === 'le';\n var res = new ArrayType(reqLength);\n\n var b, i;\n var q = this.clone();\n if (!littleEndian) {\n // Assume big-endian\n for (i = 0; i < reqLength - byteLength; i++) {\n res[i] = 0;\n }\n\n for (i = 0; !q.isZero(); i++) {\n b = q.andln(0xff);\n q.iushrn(8);\n\n res[reqLength - i - 1] = b;\n }\n } else {\n for (i = 0; !q.isZero(); i++) {\n b = q.andln(0xff);\n q.iushrn(8);\n\n res[i] = b;\n }\n\n for (; i < reqLength; i++) {\n res[i] = 0;\n }\n }\n\n return res;\n };\n\n if (Math.clz32) {\n BN.prototype._countBits = function _countBits (w) {\n return 32 - Math.clz32(w);\n };\n } else {\n BN.prototype._countBits = function _countBits (w) {\n var t = w;\n var r = 0;\n if (t >= 0x1000) {\n r += 13;\n t >>>= 13;\n }\n if (t >= 0x40) {\n r += 7;\n t >>>= 7;\n }\n if (t >= 0x8) {\n r += 4;\n t >>>= 4;\n }\n if (t >= 0x02) {\n r += 2;\n t >>>= 2;\n }\n return r + t;\n };\n }\n\n BN.prototype._zeroBits = function _zeroBits (w) {\n // Short-cut\n if (w === 0) return 26;\n\n var t = w;\n var r = 0;\n if ((t & 0x1fff) === 0) {\n r += 13;\n t >>>= 13;\n }\n if ((t & 0x7f) === 0) {\n r += 7;\n t >>>= 7;\n }\n if ((t & 0xf) === 0) {\n r += 4;\n t >>>= 4;\n }\n if ((t & 0x3) === 0) {\n r += 2;\n t >>>= 2;\n }\n if ((t & 0x1) === 0) {\n r++;\n }\n return r;\n };\n\n // Return number of used bits in a BN\n BN.prototype.bitLength = function bitLength () {\n var w = this.words[this.length - 1];\n var hi = this._countBits(w);\n return (this.length - 1) * 26 + hi;\n };\n\n function toBitArray (num) {\n var w = new Array(num.bitLength());\n\n for (var bit = 0; bit < w.length; bit++) {\n var off = (bit / 26) | 0;\n var wbit = bit % 26;\n\n w[bit] = (num.words[off] & (1 << wbit)) >>> wbit;\n }\n\n return w;\n }\n\n // Number of trailing zero bits\n BN.prototype.zeroBits = function zeroBits () {\n if (this.isZero()) return 0;\n\n var r = 0;\n for (var i = 0; i < this.length; i++) {\n var b = this._zeroBits(this.words[i]);\n r += b;\n if (b !== 26) break;\n }\n return r;\n };\n\n BN.prototype.byteLength = function byteLength () {\n return Math.ceil(this.bitLength() / 8);\n };\n\n BN.prototype.toTwos = function toTwos (width) {\n if (this.negative !== 0) {\n return this.abs().inotn(width).iaddn(1);\n }\n return this.clone();\n };\n\n BN.prototype.fromTwos = function fromTwos (width) {\n if (this.testn(width - 1)) {\n return this.notn(width).iaddn(1).ineg();\n }\n return this.clone();\n };\n\n BN.prototype.isNeg = function isNeg () {\n return this.negative !== 0;\n };\n\n // Return negative clone of `this`\n BN.prototype.neg = function neg () {\n return this.clone().ineg();\n };\n\n BN.prototype.ineg = function ineg () {\n if (!this.isZero()) {\n this.negative ^= 1;\n }\n\n return this;\n };\n\n // Or `num` with `this` in-place\n BN.prototype.iuor = function iuor (num) {\n while (this.length < num.length) {\n this.words[this.length++] = 0;\n }\n\n for (var i = 0; i < num.length; i++) {\n this.words[i] = this.words[i] | num.words[i];\n }\n\n return this.strip();\n };\n\n BN.prototype.ior = function ior (num) {\n assert((this.negative | num.negative) === 0);\n return this.iuor(num);\n };\n\n // Or `num` with `this`\n BN.prototype.or = function or (num) {\n if (this.length > num.length) return this.clone().ior(num);\n return num.clone().ior(this);\n };\n\n BN.prototype.uor = function uor (num) {\n if (this.length > num.length) return this.clone().iuor(num);\n return num.clone().iuor(this);\n };\n\n // And `num` with `this` in-place\n BN.prototype.iuand = function iuand (num) {\n // b = min-length(num, this)\n var b;\n if (this.length > num.length) {\n b = num;\n } else {\n b = this;\n }\n\n for (var i = 0; i < b.length; i++) {\n this.words[i] = this.words[i] & num.words[i];\n }\n\n this.length = b.length;\n\n return this.strip();\n };\n\n BN.prototype.iand = function iand (num) {\n assert((this.negative | num.negative) === 0);\n return this.iuand(num);\n };\n\n // And `num` with `this`\n BN.prototype.and = function and (num) {\n if (this.length > num.length) return this.clone().iand(num);\n return num.clone().iand(this);\n };\n\n BN.prototype.uand = function uand (num) {\n if (this.length > num.length) return this.clone().iuand(num);\n return num.clone().iuand(this);\n };\n\n // Xor `num` with `this` in-place\n BN.prototype.iuxor = function iuxor (num) {\n // a.length > b.length\n var a;\n var b;\n if (this.length > num.length) {\n a = this;\n b = num;\n } else {\n a = num;\n b = this;\n }\n\n for (var i = 0; i < b.length; i++) {\n this.words[i] = a.words[i] ^ b.words[i];\n }\n\n if (this !== a) {\n for (; i < a.length; i++) {\n this.words[i] = a.words[i];\n }\n }\n\n this.length = a.length;\n\n return this.strip();\n };\n\n BN.prototype.ixor = function ixor (num) {\n assert((this.negative | num.negative) === 0);\n return this.iuxor(num);\n };\n\n // Xor `num` with `this`\n BN.prototype.xor = function xor (num) {\n if (this.length > num.length) return this.clone().ixor(num);\n return num.clone().ixor(this);\n };\n\n BN.prototype.uxor = function uxor (num) {\n if (this.length > num.length) return this.clone().iuxor(num);\n return num.clone().iuxor(this);\n };\n\n // Not ``this`` with ``width`` bitwidth\n BN.prototype.inotn = function inotn (width) {\n assert(typeof width === 'number' && width >= 0);\n\n var bytesNeeded = Math.ceil(width / 26) | 0;\n var bitsLeft = width % 26;\n\n // Extend the buffer with leading zeroes\n this._expand(bytesNeeded);\n\n if (bitsLeft > 0) {\n bytesNeeded--;\n }\n\n // Handle complete words\n for (var i = 0; i < bytesNeeded; i++) {\n this.words[i] = ~this.words[i] & 0x3ffffff;\n }\n\n // Handle the residue\n if (bitsLeft > 0) {\n this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft));\n }\n\n // And remove leading zeroes\n return this.strip();\n };\n\n BN.prototype.notn = function notn (width) {\n return this.clone().inotn(width);\n };\n\n // Set `bit` of `this`\n BN.prototype.setn = function setn (bit, val) {\n assert(typeof bit === 'number' && bit >= 0);\n\n var off = (bit / 26) | 0;\n var wbit = bit % 26;\n\n this._expand(off + 1);\n\n if (val) {\n this.words[off] = this.words[off] | (1 << wbit);\n } else {\n this.words[off] = this.words[off] & ~(1 << wbit);\n }\n\n return this.strip();\n };\n\n // Add `num` to `this` in-place\n BN.prototype.iadd = function iadd (num) {\n var r;\n\n // negative + positive\n if (this.negative !== 0 && num.negative === 0) {\n this.negative = 0;\n r = this.isub(num);\n this.negative ^= 1;\n return this._normSign();\n\n // positive + negative\n } else if (this.negative === 0 && num.negative !== 0) {\n num.negative = 0;\n r = this.isub(num);\n num.negative = 1;\n return r._normSign();\n }\n\n // a.length > b.length\n var a, b;\n if (this.length > num.length) {\n a = this;\n b = num;\n } else {\n a = num;\n b = this;\n }\n\n var carry = 0;\n for (var i = 0; i < b.length; i++) {\n r = (a.words[i] | 0) + (b.words[i] | 0) + carry;\n this.words[i] = r & 0x3ffffff;\n carry = r >>> 26;\n }\n for (; carry !== 0 && i < a.length; i++) {\n r = (a.words[i] | 0) + carry;\n this.words[i] = r & 0x3ffffff;\n carry = r >>> 26;\n }\n\n this.length = a.length;\n if (carry !== 0) {\n this.words[this.length] = carry;\n this.length++;\n // Copy the rest of the words\n } else if (a !== this) {\n for (; i < a.length; i++) {\n this.words[i] = a.words[i];\n }\n }\n\n return this;\n };\n\n // Add `num` to `this`\n BN.prototype.add = function add (num) {\n var res;\n if (num.negative !== 0 && this.negative === 0) {\n num.negative = 0;\n res = this.sub(num);\n num.negative ^= 1;\n return res;\n } else if (num.negative === 0 && this.negative !== 0) {\n this.negative = 0;\n res = num.sub(this);\n this.negative = 1;\n return res;\n }\n\n if (this.length > num.length) return this.clone().iadd(num);\n\n return num.clone().iadd(this);\n };\n\n // Subtract `num` from `this` in-place\n BN.prototype.isub = function isub (num) {\n // this - (-num) = this + num\n if (num.negative !== 0) {\n num.negative = 0;\n var r = this.iadd(num);\n num.negative = 1;\n return r._normSign();\n\n // -this - num = -(this + num)\n } else if (this.negative !== 0) {\n this.negative = 0;\n this.iadd(num);\n this.negative = 1;\n return this._normSign();\n }\n\n // At this point both numbers are positive\n var cmp = this.cmp(num);\n\n // Optimization - zeroify\n if (cmp === 0) {\n this.negative = 0;\n this.length = 1;\n this.words[0] = 0;\n return this;\n }\n\n // a > b\n var a, b;\n if (cmp > 0) {\n a = this;\n b = num;\n } else {\n a = num;\n b = this;\n }\n\n var carry = 0;\n for (var i = 0; i < b.length; i++) {\n r = (a.words[i] | 0) - (b.words[i] | 0) + carry;\n carry = r >> 26;\n this.words[i] = r & 0x3ffffff;\n }\n for (; carry !== 0 && i < a.length; i++) {\n r = (a.words[i] | 0) + carry;\n carry = r >> 26;\n this.words[i] = r & 0x3ffffff;\n }\n\n // Copy rest of the words\n if (carry === 0 && i < a.length && a !== this) {\n for (; i < a.length; i++) {\n this.words[i] = a.words[i];\n }\n }\n\n this.length = Math.max(this.length, i);\n\n if (a !== this) {\n this.negative = 1;\n }\n\n return this.strip();\n };\n\n // Subtract `num` from `this`\n BN.prototype.sub = function sub (num) {\n return this.clone().isub(num);\n };\n\n function smallMulTo (self, num, out) {\n out.negative = num.negative ^ self.negative;\n var len = (self.length + num.length) | 0;\n out.length = len;\n len = (len - 1) | 0;\n\n // Peel one iteration (compiler can't do it, because of code complexity)\n var a = self.words[0] | 0;\n var b = num.words[0] | 0;\n var r = a * b;\n\n var lo = r & 0x3ffffff;\n var carry = (r / 0x4000000) | 0;\n out.words[0] = lo;\n\n for (var k = 1; k < len; k++) {\n // Sum all words with the same `i + j = k` and accumulate `ncarry`,\n // note that ncarry could be >= 0x3ffffff\n var ncarry = carry >>> 26;\n var rword = carry & 0x3ffffff;\n var maxJ = Math.min(k, num.length - 1);\n for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {\n var i = (k - j) | 0;\n a = self.words[i] | 0;\n b = num.words[j] | 0;\n r = a * b + rword;\n ncarry += (r / 0x4000000) | 0;\n rword = r & 0x3ffffff;\n }\n out.words[k] = rword | 0;\n carry = ncarry | 0;\n }\n if (carry !== 0) {\n out.words[k] = carry | 0;\n } else {\n out.length--;\n }\n\n return out.strip();\n }\n\n // TODO(indutny): it may be reasonable to omit it for users who don't need\n // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit\n // multiplication (like elliptic secp256k1).\n var comb10MulTo = function comb10MulTo (self, num, out) {\n var a = self.words;\n var b = num.words;\n var o = out.words;\n var c = 0;\n var lo;\n var mid;\n var hi;\n var a0 = a[0] | 0;\n var al0 = a0 & 0x1fff;\n var ah0 = a0 >>> 13;\n var a1 = a[1] | 0;\n var al1 = a1 & 0x1fff;\n var ah1 = a1 >>> 13;\n var a2 = a[2] | 0;\n var al2 = a2 & 0x1fff;\n var ah2 = a2 >>> 13;\n var a3 = a[3] | 0;\n var al3 = a3 & 0x1fff;\n var ah3 = a3 >>> 13;\n var a4 = a[4] | 0;\n var al4 = a4 & 0x1fff;\n var ah4 = a4 >>> 13;\n var a5 = a[5] | 0;\n var al5 = a5 & 0x1fff;\n var ah5 = a5 >>> 13;\n var a6 = a[6] | 0;\n var al6 = a6 & 0x1fff;\n var ah6 = a6 >>> 13;\n var a7 = a[7] | 0;\n var al7 = a7 & 0x1fff;\n var ah7 = a7 >>> 13;\n var a8 = a[8] | 0;\n var al8 = a8 & 0x1fff;\n var ah8 = a8 >>> 13;\n var a9 = a[9] | 0;\n var al9 = a9 & 0x1fff;\n var ah9 = a9 >>> 13;\n var b0 = b[0] | 0;\n var bl0 = b0 & 0x1fff;\n var bh0 = b0 >>> 13;\n var b1 = b[1] | 0;\n var bl1 = b1 & 0x1fff;\n var bh1 = b1 >>> 13;\n var b2 = b[2] | 0;\n var bl2 = b2 & 0x1fff;\n var bh2 = b2 >>> 13;\n var b3 = b[3] | 0;\n var bl3 = b3 & 0x1fff;\n var bh3 = b3 >>> 13;\n var b4 = b[4] | 0;\n var bl4 = b4 & 0x1fff;\n var bh4 = b4 >>> 13;\n var b5 = b[5] | 0;\n var bl5 = b5 & 0x1fff;\n var bh5 = b5 >>> 13;\n var b6 = b[6] | 0;\n var bl6 = b6 & 0x1fff;\n var bh6 = b6 >>> 13;\n var b7 = b[7] | 0;\n var bl7 = b7 & 0x1fff;\n var bh7 = b7 >>> 13;\n var b8 = b[8] | 0;\n var bl8 = b8 & 0x1fff;\n var bh8 = b8 >>> 13;\n var b9 = b[9] | 0;\n var bl9 = b9 & 0x1fff;\n var bh9 = b9 >>> 13;\n\n out.negative = self.negative ^ num.negative;\n out.length = 19;\n /* k = 0 */\n lo = Math.imul(al0, bl0);\n mid = Math.imul(al0, bh0);\n mid = (mid + Math.imul(ah0, bl0)) | 0;\n hi = Math.imul(ah0, bh0);\n var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0;\n w0 &= 0x3ffffff;\n /* k = 1 */\n lo = Math.imul(al1, bl0);\n mid = Math.imul(al1, bh0);\n mid = (mid + Math.imul(ah1, bl0)) | 0;\n hi = Math.imul(ah1, bh0);\n lo = (lo + Math.imul(al0, bl1)) | 0;\n mid = (mid + Math.imul(al0, bh1)) | 0;\n mid = (mid + Math.imul(ah0, bl1)) | 0;\n hi = (hi + Math.imul(ah0, bh1)) | 0;\n var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0;\n w1 &= 0x3ffffff;\n /* k = 2 */\n lo = Math.imul(al2, bl0);\n mid = Math.imul(al2, bh0);\n mid = (mid + Math.imul(ah2, bl0)) | 0;\n hi = Math.imul(ah2, bh0);\n lo = (lo + Math.imul(al1, bl1)) | 0;\n mid = (mid + Math.imul(al1, bh1)) | 0;\n mid = (mid + Math.imul(ah1, bl1)) | 0;\n hi = (hi + Math.imul(ah1, bh1)) | 0;\n lo = (lo + Math.imul(al0, bl2)) | 0;\n mid = (mid + Math.imul(al0, bh2)) | 0;\n mid = (mid + Math.imul(ah0, bl2)) | 0;\n hi = (hi + Math.imul(ah0, bh2)) | 0;\n var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0;\n w2 &= 0x3ffffff;\n /* k = 3 */\n lo = Math.imul(al3, bl0);\n mid = Math.imul(al3, bh0);\n mid = (mid + Math.imul(ah3, bl0)) | 0;\n hi = Math.imul(ah3, bh0);\n lo = (lo + Math.imul(al2, bl1)) | 0;\n mid = (mid + Math.imul(al2, bh1)) | 0;\n mid = (mid + Math.imul(ah2, bl1)) | 0;\n hi = (hi + Math.imul(ah2, bh1)) | 0;\n lo = (lo + Math.imul(al1, bl2)) | 0;\n mid = (mid + Math.imul(al1, bh2)) | 0;\n mid = (mid + Math.imul(ah1, bl2)) | 0;\n hi = (hi + Math.imul(ah1, bh2)) | 0;\n lo = (lo + Math.imul(al0, bl3)) | 0;\n mid = (mid + Math.imul(al0, bh3)) | 0;\n mid = (mid + Math.imul(ah0, bl3)) | 0;\n hi = (hi + Math.imul(ah0, bh3)) | 0;\n var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0;\n w3 &= 0x3ffffff;\n /* k = 4 */\n lo = Math.imul(al4, bl0);\n mid = Math.imul(al4, bh0);\n mid = (mid + Math.imul(ah4, bl0)) | 0;\n hi = Math.imul(ah4, bh0);\n lo = (lo + Math.imul(al3, bl1)) | 0;\n mid = (mid + Math.imul(al3, bh1)) | 0;\n mid = (mid + Math.imul(ah3, bl1)) | 0;\n hi = (hi + Math.imul(ah3, bh1)) | 0;\n lo = (lo + Math.imul(al2, bl2)) | 0;\n mid = (mid + Math.imul(al2, bh2)) | 0;\n mid = (mid + Math.imul(ah2, bl2)) | 0;\n hi = (hi + Math.imul(ah2, bh2)) | 0;\n lo = (lo + Math.imul(al1, bl3)) | 0;\n mid = (mid + Math.imul(al1, bh3)) | 0;\n mid = (mid + Math.imul(ah1, bl3)) | 0;\n hi = (hi + Math.imul(ah1, bh3)) | 0;\n lo = (lo + Math.imul(al0, bl4)) | 0;\n mid = (mid + Math.imul(al0, bh4)) | 0;\n mid = (mid + Math.imul(ah0, bl4)) | 0;\n hi = (hi + Math.imul(ah0, bh4)) | 0;\n var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0;\n w4 &= 0x3ffffff;\n /* k = 5 */\n lo = Math.imul(al5, bl0);\n mid = Math.imul(al5, bh0);\n mid = (mid + Math.imul(ah5, bl0)) | 0;\n hi = Math.imul(ah5, bh0);\n lo = (lo + Math.imul(al4, bl1)) | 0;\n mid = (mid + Math.imul(al4, bh1)) | 0;\n mid = (mid + Math.imul(ah4, bl1)) | 0;\n hi = (hi + Math.imul(ah4, bh1)) | 0;\n lo = (lo + Math.imul(al3, bl2)) | 0;\n mid = (mid + Math.imul(al3, bh2)) | 0;\n mid = (mid + Math.imul(ah3, bl2)) | 0;\n hi = (hi + Math.imul(ah3, bh2)) | 0;\n lo = (lo + Math.imul(al2, bl3)) | 0;\n mid = (mid + Math.imul(al2, bh3)) | 0;\n mid = (mid + Math.imul(ah2, bl3)) | 0;\n hi = (hi + Math.imul(ah2, bh3)) | 0;\n lo = (lo + Math.imul(al1, bl4)) | 0;\n mid = (mid + Math.imul(al1, bh4)) | 0;\n mid = (mid + Math.imul(ah1, bl4)) | 0;\n hi = (hi + Math.imul(ah1, bh4)) | 0;\n lo = (lo + Math.imul(al0, bl5)) | 0;\n mid = (mid + Math.imul(al0, bh5)) | 0;\n mid = (mid + Math.imul(ah0, bl5)) | 0;\n hi = (hi + Math.imul(ah0, bh5)) | 0;\n var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0;\n w5 &= 0x3ffffff;\n /* k = 6 */\n lo = Math.imul(al6, bl0);\n mid = Math.imul(al6, bh0);\n mid = (mid + Math.imul(ah6, bl0)) | 0;\n hi = Math.imul(ah6, bh0);\n lo = (lo + Math.imul(al5, bl1)) | 0;\n mid = (mid + Math.imul(al5, bh1)) | 0;\n mid = (mid + Math.imul(ah5, bl1)) | 0;\n hi = (hi + Math.imul(ah5, bh1)) | 0;\n lo = (lo + Math.imul(al4, bl2)) | 0;\n mid = (mid + Math.imul(al4, bh2)) | 0;\n mid = (mid + Math.imul(ah4, bl2)) | 0;\n hi = (hi + Math.imul(ah4, bh2)) | 0;\n lo = (lo + Math.imul(al3, bl3)) | 0;\n mid = (mid + Math.imul(al3, bh3)) | 0;\n mid = (mid + Math.imul(ah3, bl3)) | 0;\n hi = (hi + Math.imul(ah3, bh3)) | 0;\n lo = (lo + Math.imul(al2, bl4)) | 0;\n mid = (mid + Math.imul(al2, bh4)) | 0;\n mid = (mid + Math.imul(ah2, bl4)) | 0;\n hi = (hi + Math.imul(ah2, bh4)) | 0;\n lo = (lo + Math.imul(al1, bl5)) | 0;\n mid = (mid + Math.imul(al1, bh5)) | 0;\n mid = (mid + Math.imul(ah1, bl5)) | 0;\n hi = (hi + Math.imul(ah1, bh5)) | 0;\n lo = (lo + Math.imul(al0, bl6)) | 0;\n mid = (mid + Math.imul(al0, bh6)) | 0;\n mid = (mid + Math.imul(ah0, bl6)) | 0;\n hi = (hi + Math.imul(ah0, bh6)) | 0;\n var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0;\n w6 &= 0x3ffffff;\n /* k = 7 */\n lo = Math.imul(al7, bl0);\n mid = Math.imul(al7, bh0);\n mid = (mid + Math.imul(ah7, bl0)) | 0;\n hi = Math.imul(ah7, bh0);\n lo = (lo + Math.imul(al6, bl1)) | 0;\n mid = (mid + Math.imul(al6, bh1)) | 0;\n mid = (mid + Math.imul(ah6, bl1)) | 0;\n hi = (hi + Math.imul(ah6, bh1)) | 0;\n lo = (lo + Math.imul(al5, bl2)) | 0;\n mid = (mid + Math.imul(al5, bh2)) | 0;\n mid = (mid + Math.imul(ah5, bl2)) | 0;\n hi = (hi + Math.imul(ah5, bh2)) | 0;\n lo = (lo + Math.imul(al4, bl3)) | 0;\n mid = (mid + Math.imul(al4, bh3)) | 0;\n mid = (mid + Math.imul(ah4, bl3)) | 0;\n hi = (hi + Math.imul(ah4, bh3)) | 0;\n lo = (lo + Math.imul(al3, bl4)) | 0;\n mid = (mid + Math.imul(al3, bh4)) | 0;\n mid = (mid + Math.imul(ah3, bl4)) | 0;\n hi = (hi + Math.imul(ah3, bh4)) | 0;\n lo = (lo + Math.imul(al2, bl5)) | 0;\n mid = (mid + Math.imul(al2, bh5)) | 0;\n mid = (mid + Math.imul(ah2, bl5)) | 0;\n hi = (hi + Math.imul(ah2, bh5)) | 0;\n lo = (lo + Math.imul(al1, bl6)) | 0;\n mid = (mid + Math.imul(al1, bh6)) | 0;\n mid = (mid + Math.imul(ah1, bl6)) | 0;\n hi = (hi + Math.imul(ah1, bh6)) | 0;\n lo = (lo + Math.imul(al0, bl7)) | 0;\n mid = (mid + Math.imul(al0, bh7)) | 0;\n mid = (mid + Math.imul(ah0, bl7)) | 0;\n hi = (hi + Math.imul(ah0, bh7)) | 0;\n var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0;\n w7 &= 0x3ffffff;\n /* k = 8 */\n lo = Math.imul(al8, bl0);\n mid = Math.imul(al8, bh0);\n mid = (mid + Math.imul(ah8, bl0)) | 0;\n hi = Math.imul(ah8, bh0);\n lo = (lo + Math.imul(al7, bl1)) | 0;\n mid = (mid + Math.imul(al7, bh1)) | 0;\n mid = (mid + Math.imul(ah7, bl1)) | 0;\n hi = (hi + Math.imul(ah7, bh1)) | 0;\n lo = (lo + Math.imul(al6, bl2)) | 0;\n mid = (mid + Math.imul(al6, bh2)) | 0;\n mid = (mid + Math.imul(ah6, bl2)) | 0;\n hi = (hi + Math.imul(ah6, bh2)) | 0;\n lo = (lo + Math.imul(al5, bl3)) | 0;\n mid = (mid + Math.imul(al5, bh3)) | 0;\n mid = (mid + Math.imul(ah5, bl3)) | 0;\n hi = (hi + Math.imul(ah5, bh3)) | 0;\n lo = (lo + Math.imul(al4, bl4)) | 0;\n mid = (mid + Math.imul(al4, bh4)) | 0;\n mid = (mid + Math.imul(ah4, bl4)) | 0;\n hi = (hi + Math.imul(ah4, bh4)) | 0;\n lo = (lo + Math.imul(al3, bl5)) | 0;\n mid = (mid + Math.imul(al3, bh5)) | 0;\n mid = (mid + Math.imul(ah3, bl5)) | 0;\n hi = (hi + Math.imul(ah3, bh5)) | 0;\n lo = (lo + Math.imul(al2, bl6)) | 0;\n mid = (mid + Math.imul(al2, bh6)) | 0;\n mid = (mid + Math.imul(ah2, bl6)) | 0;\n hi = (hi + Math.imul(ah2, bh6)) | 0;\n lo = (lo + Math.imul(al1, bl7)) | 0;\n mid = (mid + Math.imul(al1, bh7)) | 0;\n mid = (mid + Math.imul(ah1, bl7)) | 0;\n hi = (hi + Math.imul(ah1, bh7)) | 0;\n lo = (lo + Math.imul(al0, bl8)) | 0;\n mid = (mid + Math.imul(al0, bh8)) | 0;\n mid = (mid + Math.imul(ah0, bl8)) | 0;\n hi = (hi + Math.imul(ah0, bh8)) | 0;\n var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0;\n w8 &= 0x3ffffff;\n /* k = 9 */\n lo = Math.imul(al9, bl0);\n mid = Math.imul(al9, bh0);\n mid = (mid + Math.imul(ah9, bl0)) | 0;\n hi = Math.imul(ah9, bh0);\n lo = (lo + Math.imul(al8, bl1)) | 0;\n mid = (mid + Math.imul(al8, bh1)) | 0;\n mid = (mid + Math.imul(ah8, bl1)) | 0;\n hi = (hi + Math.imul(ah8, bh1)) | 0;\n lo = (lo + Math.imul(al7, bl2)) | 0;\n mid = (mid + Math.imul(al7, bh2)) | 0;\n mid = (mid + Math.imul(ah7, bl2)) | 0;\n hi = (hi + Math.imul(ah7, bh2)) | 0;\n lo = (lo + Math.imul(al6, bl3)) | 0;\n mid = (mid + Math.imul(al6, bh3)) | 0;\n mid = (mid + Math.imul(ah6, bl3)) | 0;\n hi = (hi + Math.imul(ah6, bh3)) | 0;\n lo = (lo + Math.imul(al5, bl4)) | 0;\n mid = (mid + Math.imul(al5, bh4)) | 0;\n mid = (mid + Math.imul(ah5, bl4)) | 0;\n hi = (hi + Math.imul(ah5, bh4)) | 0;\n lo = (lo + Math.imul(al4, bl5)) | 0;\n mid = (mid + Math.imul(al4, bh5)) | 0;\n mid = (mid + Math.imul(ah4, bl5)) | 0;\n hi = (hi + Math.imul(ah4, bh5)) | 0;\n lo = (lo + Math.imul(al3, bl6)) | 0;\n mid = (mid + Math.imul(al3, bh6)) | 0;\n mid = (mid + Math.imul(ah3, bl6)) | 0;\n hi = (hi + Math.imul(ah3, bh6)) | 0;\n lo = (lo + Math.imul(al2, bl7)) | 0;\n mid = (mid + Math.imul(al2, bh7)) | 0;\n mid = (mid + Math.imul(ah2, bl7)) | 0;\n hi = (hi + Math.imul(ah2, bh7)) | 0;\n lo = (lo + Math.imul(al1, bl8)) | 0;\n mid = (mid + Math.imul(al1, bh8)) | 0;\n mid = (mid + Math.imul(ah1, bl8)) | 0;\n hi = (hi + Math.imul(ah1, bh8)) | 0;\n lo = (lo + Math.imul(al0, bl9)) | 0;\n mid = (mid + Math.imul(al0, bh9)) | 0;\n mid = (mid + Math.imul(ah0, bl9)) | 0;\n hi = (hi + Math.imul(ah0, bh9)) | 0;\n var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0;\n w9 &= 0x3ffffff;\n /* k = 10 */\n lo = Math.imul(al9, bl1);\n mid = Math.imul(al9, bh1);\n mid = (mid + Math.imul(ah9, bl1)) | 0;\n hi = Math.imul(ah9, bh1);\n lo = (lo + Math.imul(al8, bl2)) | 0;\n mid = (mid + Math.imul(al8, bh2)) | 0;\n mid = (mid + Math.imul(ah8, bl2)) | 0;\n hi = (hi + Math.imul(ah8, bh2)) | 0;\n lo = (lo + Math.imul(al7, bl3)) | 0;\n mid = (mid + Math.imul(al7, bh3)) | 0;\n mid = (mid + Math.imul(ah7, bl3)) | 0;\n hi = (hi + Math.imul(ah7, bh3)) | 0;\n lo = (lo + Math.imul(al6, bl4)) | 0;\n mid = (mid + Math.imul(al6, bh4)) | 0;\n mid = (mid + Math.imul(ah6, bl4)) | 0;\n hi = (hi + Math.imul(ah6, bh4)) | 0;\n lo = (lo + Math.imul(al5, bl5)) | 0;\n mid = (mid + Math.imul(al5, bh5)) | 0;\n mid = (mid + Math.imul(ah5, bl5)) | 0;\n hi = (hi + Math.imul(ah5, bh5)) | 0;\n lo = (lo + Math.imul(al4, bl6)) | 0;\n mid = (mid + Math.imul(al4, bh6)) | 0;\n mid = (mid + Math.imul(ah4, bl6)) | 0;\n hi = (hi + Math.imul(ah4, bh6)) | 0;\n lo = (lo + Math.imul(al3, bl7)) | 0;\n mid = (mid + Math.imul(al3, bh7)) | 0;\n mid = (mid + Math.imul(ah3, bl7)) | 0;\n hi = (hi + Math.imul(ah3, bh7)) | 0;\n lo = (lo + Math.imul(al2, bl8)) | 0;\n mid = (mid + Math.imul(al2, bh8)) | 0;\n mid = (mid + Math.imul(ah2, bl8)) | 0;\n hi = (hi + Math.imul(ah2, bh8)) | 0;\n lo = (lo + Math.imul(al1, bl9)) | 0;\n mid = (mid + Math.imul(al1, bh9)) | 0;\n mid = (mid + Math.imul(ah1, bl9)) | 0;\n hi = (hi + Math.imul(ah1, bh9)) | 0;\n var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0;\n w10 &= 0x3ffffff;\n /* k = 11 */\n lo = Math.imul(al9, bl2);\n mid = Math.imul(al9, bh2);\n mid = (mid + Math.imul(ah9, bl2)) | 0;\n hi = Math.imul(ah9, bh2);\n lo = (lo + Math.imul(al8, bl3)) | 0;\n mid = (mid + Math.imul(al8, bh3)) | 0;\n mid = (mid + Math.imul(ah8, bl3)) | 0;\n hi = (hi + Math.imul(ah8, bh3)) | 0;\n lo = (lo + Math.imul(al7, bl4)) | 0;\n mid = (mid + Math.imul(al7, bh4)) | 0;\n mid = (mid + Math.imul(ah7, bl4)) | 0;\n hi = (hi + Math.imul(ah7, bh4)) | 0;\n lo = (lo + Math.imul(al6, bl5)) | 0;\n mid = (mid + Math.imul(al6, bh5)) | 0;\n mid = (mid + Math.imul(ah6, bl5)) | 0;\n hi = (hi + Math.imul(ah6, bh5)) | 0;\n lo = (lo + Math.imul(al5, bl6)) | 0;\n mid = (mid + Math.imul(al5, bh6)) | 0;\n mid = (mid + Math.imul(ah5, bl6)) | 0;\n hi = (hi + Math.imul(ah5, bh6)) | 0;\n lo = (lo + Math.imul(al4, bl7)) | 0;\n mid = (mid + Math.imul(al4, bh7)) | 0;\n mid = (mid + Math.imul(ah4, bl7)) | 0;\n hi = (hi + Math.imul(ah4, bh7)) | 0;\n lo = (lo + Math.imul(al3, bl8)) | 0;\n mid = (mid + Math.imul(al3, bh8)) | 0;\n mid = (mid + Math.imul(ah3, bl8)) | 0;\n hi = (hi + Math.imul(ah3, bh8)) | 0;\n lo = (lo + Math.imul(al2, bl9)) | 0;\n mid = (mid + Math.imul(al2, bh9)) | 0;\n mid = (mid + Math.imul(ah2, bl9)) | 0;\n hi = (hi + Math.imul(ah2, bh9)) | 0;\n var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0;\n w11 &= 0x3ffffff;\n /* k = 12 */\n lo = Math.imul(al9, bl3);\n mid = Math.imul(al9, bh3);\n mid = (mid + Math.imul(ah9, bl3)) | 0;\n hi = Math.imul(ah9, bh3);\n lo = (lo + Math.imul(al8, bl4)) | 0;\n mid = (mid + Math.imul(al8, bh4)) | 0;\n mid = (mid + Math.imul(ah8, bl4)) | 0;\n hi = (hi + Math.imul(ah8, bh4)) | 0;\n lo = (lo + Math.imul(al7, bl5)) | 0;\n mid = (mid + Math.imul(al7, bh5)) | 0;\n mid = (mid + Math.imul(ah7, bl5)) | 0;\n hi = (hi + Math.imul(ah7, bh5)) | 0;\n lo = (lo + Math.imul(al6, bl6)) | 0;\n mid = (mid + Math.imul(al6, bh6)) | 0;\n mid = (mid + Math.imul(ah6, bl6)) | 0;\n hi = (hi + Math.imul(ah6, bh6)) | 0;\n lo = (lo + Math.imul(al5, bl7)) | 0;\n mid = (mid + Math.imul(al5, bh7)) | 0;\n mid = (mid + Math.imul(ah5, bl7)) | 0;\n hi = (hi + Math.imul(ah5, bh7)) | 0;\n lo = (lo + Math.imul(al4, bl8)) | 0;\n mid = (mid + Math.imul(al4, bh8)) | 0;\n mid = (mid + Math.imul(ah4, bl8)) | 0;\n hi = (hi + Math.imul(ah4, bh8)) | 0;\n lo = (lo + Math.imul(al3, bl9)) | 0;\n mid = (mid + Math.imul(al3, bh9)) | 0;\n mid = (mid + Math.imul(ah3, bl9)) | 0;\n hi = (hi + Math.imul(ah3, bh9)) | 0;\n var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0;\n w12 &= 0x3ffffff;\n /* k = 13 */\n lo = Math.imul(al9, bl4);\n mid = Math.imul(al9, bh4);\n mid = (mid + Math.imul(ah9, bl4)) | 0;\n hi = Math.imul(ah9, bh4);\n lo = (lo + Math.imul(al8, bl5)) | 0;\n mid = (mid + Math.imul(al8, bh5)) | 0;\n mid = (mid + Math.imul(ah8, bl5)) | 0;\n hi = (hi + Math.imul(ah8, bh5)) | 0;\n lo = (lo + Math.imul(al7, bl6)) | 0;\n mid = (mid + Math.imul(al7, bh6)) | 0;\n mid = (mid + Math.imul(ah7, bl6)) | 0;\n hi = (hi + Math.imul(ah7, bh6)) | 0;\n lo = (lo + Math.imul(al6, bl7)) | 0;\n mid = (mid + Math.imul(al6, bh7)) | 0;\n mid = (mid + Math.imul(ah6, bl7)) | 0;\n hi = (hi + Math.imul(ah6, bh7)) | 0;\n lo = (lo + Math.imul(al5, bl8)) | 0;\n mid = (mid + Math.imul(al5, bh8)) | 0;\n mid = (mid + Math.imul(ah5, bl8)) | 0;\n hi = (hi + Math.imul(ah5, bh8)) | 0;\n lo = (lo + Math.imul(al4, bl9)) | 0;\n mid = (mid + Math.imul(al4, bh9)) | 0;\n mid = (mid + Math.imul(ah4, bl9)) | 0;\n hi = (hi + Math.imul(ah4, bh9)) | 0;\n var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0;\n w13 &= 0x3ffffff;\n /* k = 14 */\n lo = Math.imul(al9, bl5);\n mid = Math.imul(al9, bh5);\n mid = (mid + Math.imul(ah9, bl5)) | 0;\n hi = Math.imul(ah9, bh5);\n lo = (lo + Math.imul(al8, bl6)) | 0;\n mid = (mid + Math.imul(al8, bh6)) | 0;\n mid = (mid + Math.imul(ah8, bl6)) | 0;\n hi = (hi + Math.imul(ah8, bh6)) | 0;\n lo = (lo + Math.imul(al7, bl7)) | 0;\n mid = (mid + Math.imul(al7, bh7)) | 0;\n mid = (mid + Math.imul(ah7, bl7)) | 0;\n hi = (hi + Math.imul(ah7, bh7)) | 0;\n lo = (lo + Math.imul(al6, bl8)) | 0;\n mid = (mid + Math.imul(al6, bh8)) | 0;\n mid = (mid + Math.imul(ah6, bl8)) | 0;\n hi = (hi + Math.imul(ah6, bh8)) | 0;\n lo = (lo + Math.imul(al5, bl9)) | 0;\n mid = (mid + Math.imul(al5, bh9)) | 0;\n mid = (mid + Math.imul(ah5, bl9)) | 0;\n hi = (hi + Math.imul(ah5, bh9)) | 0;\n var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0;\n w14 &= 0x3ffffff;\n /* k = 15 */\n lo = Math.imul(al9, bl6);\n mid = Math.imul(al9, bh6);\n mid = (mid + Math.imul(ah9, bl6)) | 0;\n hi = Math.imul(ah9, bh6);\n lo = (lo + Math.imul(al8, bl7)) | 0;\n mid = (mid + Math.imul(al8, bh7)) | 0;\n mid = (mid + Math.imul(ah8, bl7)) | 0;\n hi = (hi + Math.imul(ah8, bh7)) | 0;\n lo = (lo + Math.imul(al7, bl8)) | 0;\n mid = (mid + Math.imul(al7, bh8)) | 0;\n mid = (mid + Math.imul(ah7, bl8)) | 0;\n hi = (hi + Math.imul(ah7, bh8)) | 0;\n lo = (lo + Math.imul(al6, bl9)) | 0;\n mid = (mid + Math.imul(al6, bh9)) | 0;\n mid = (mid + Math.imul(ah6, bl9)) | 0;\n hi = (hi + Math.imul(ah6, bh9)) | 0;\n var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0;\n w15 &= 0x3ffffff;\n /* k = 16 */\n lo = Math.imul(al9, bl7);\n mid = Math.imul(al9, bh7);\n mid = (mid + Math.imul(ah9, bl7)) | 0;\n hi = Math.imul(ah9, bh7);\n lo = (lo + Math.imul(al8, bl8)) | 0;\n mid = (mid + Math.imul(al8, bh8)) | 0;\n mid = (mid + Math.imul(ah8, bl8)) | 0;\n hi = (hi + Math.imul(ah8, bh8)) | 0;\n lo = (lo + Math.imul(al7, bl9)) | 0;\n mid = (mid + Math.imul(al7, bh9)) | 0;\n mid = (mid + Math.imul(ah7, bl9)) | 0;\n hi = (hi + Math.imul(ah7, bh9)) | 0;\n var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0;\n w16 &= 0x3ffffff;\n /* k = 17 */\n lo = Math.imul(al9, bl8);\n mid = Math.imul(al9, bh8);\n mid = (mid + Math.imul(ah9, bl8)) | 0;\n hi = Math.imul(ah9, bh8);\n lo = (lo + Math.imul(al8, bl9)) | 0;\n mid = (mid + Math.imul(al8, bh9)) | 0;\n mid = (mid + Math.imul(ah8, bl9)) | 0;\n hi = (hi + Math.imul(ah8, bh9)) | 0;\n var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0;\n w17 &= 0x3ffffff;\n /* k = 18 */\n lo = Math.imul(al9, bl9);\n mid = Math.imul(al9, bh9);\n mid = (mid + Math.imul(ah9, bl9)) | 0;\n hi = Math.imul(ah9, bh9);\n var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0;\n w18 &= 0x3ffffff;\n o[0] = w0;\n o[1] = w1;\n o[2] = w2;\n o[3] = w3;\n o[4] = w4;\n o[5] = w5;\n o[6] = w6;\n o[7] = w7;\n o[8] = w8;\n o[9] = w9;\n o[10] = w10;\n o[11] = w11;\n o[12] = w12;\n o[13] = w13;\n o[14] = w14;\n o[15] = w15;\n o[16] = w16;\n o[17] = w17;\n o[18] = w18;\n if (c !== 0) {\n o[19] = c;\n out.length++;\n }\n return out;\n };\n\n // Polyfill comb\n if (!Math.imul) {\n comb10MulTo = smallMulTo;\n }\n\n function bigMulTo (self, num, out) {\n out.negative = num.negative ^ self.negative;\n out.length = self.length + num.length;\n\n var carry = 0;\n var hncarry = 0;\n for (var k = 0; k < out.length - 1; k++) {\n // Sum all words with the same `i + j = k` and accumulate `ncarry`,\n // note that ncarry could be >= 0x3ffffff\n var ncarry = hncarry;\n hncarry = 0;\n var rword = carry & 0x3ffffff;\n var maxJ = Math.min(k, num.length - 1);\n for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {\n var i = k - j;\n var a = self.words[i] | 0;\n var b = num.words[j] | 0;\n var r = a * b;\n\n var lo = r & 0x3ffffff;\n ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0;\n lo = (lo + rword) | 0;\n rword = lo & 0x3ffffff;\n ncarry = (ncarry + (lo >>> 26)) | 0;\n\n hncarry += ncarry >>> 26;\n ncarry &= 0x3ffffff;\n }\n out.words[k] = rword;\n carry = ncarry;\n ncarry = hncarry;\n }\n if (carry !== 0) {\n out.words[k] = carry;\n } else {\n out.length--;\n }\n\n return out.strip();\n }\n\n function jumboMulTo (self, num, out) {\n var fftm = new FFTM();\n return fftm.mulp(self, num, out);\n }\n\n BN.prototype.mulTo = function mulTo (num, out) {\n var res;\n var len = this.length + num.length;\n if (this.length === 10 && num.length === 10) {\n res = comb10MulTo(this, num, out);\n } else if (len < 63) {\n res = smallMulTo(this, num, out);\n } else if (len < 1024) {\n res = bigMulTo(this, num, out);\n } else {\n res = jumboMulTo(this, num, out);\n }\n\n return res;\n };\n\n // Cooley-Tukey algorithm for FFT\n // slightly revisited to rely on looping instead of recursion\n\n function FFTM (x, y) {\n this.x = x;\n this.y = y;\n }\n\n FFTM.prototype.makeRBT = function makeRBT (N) {\n var t = new Array(N);\n var l = BN.prototype._countBits(N) - 1;\n for (var i = 0; i < N; i++) {\n t[i] = this.revBin(i, l, N);\n }\n\n return t;\n };\n\n // Returns binary-reversed representation of `x`\n FFTM.prototype.revBin = function revBin (x, l, N) {\n if (x === 0 || x === N - 1) return x;\n\n var rb = 0;\n for (var i = 0; i < l; i++) {\n rb |= (x & 1) << (l - i - 1);\n x >>= 1;\n }\n\n return rb;\n };\n\n // Performs \"tweedling\" phase, therefore 'emulating'\n // behaviour of the recursive algorithm\n FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) {\n for (var i = 0; i < N; i++) {\n rtws[i] = rws[rbt[i]];\n itws[i] = iws[rbt[i]];\n }\n };\n\n FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) {\n this.permute(rbt, rws, iws, rtws, itws, N);\n\n for (var s = 1; s < N; s <<= 1) {\n var l = s << 1;\n\n var rtwdf = Math.cos(2 * Math.PI / l);\n var itwdf = Math.sin(2 * Math.PI / l);\n\n for (var p = 0; p < N; p += l) {\n var rtwdf_ = rtwdf;\n var itwdf_ = itwdf;\n\n for (var j = 0; j < s; j++) {\n var re = rtws[p + j];\n var ie = itws[p + j];\n\n var ro = rtws[p + j + s];\n var io = itws[p + j + s];\n\n var rx = rtwdf_ * ro - itwdf_ * io;\n\n io = rtwdf_ * io + itwdf_ * ro;\n ro = rx;\n\n rtws[p + j] = re + ro;\n itws[p + j] = ie + io;\n\n rtws[p + j + s] = re - ro;\n itws[p + j + s] = ie - io;\n\n /* jshint maxdepth : false */\n if (j !== l) {\n rx = rtwdf * rtwdf_ - itwdf * itwdf_;\n\n itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_;\n rtwdf_ = rx;\n }\n }\n }\n }\n };\n\n FFTM.prototype.guessLen13b = function guessLen13b (n, m) {\n var N = Math.max(m, n) | 1;\n var odd = N & 1;\n var i = 0;\n for (N = N / 2 | 0; N; N = N >>> 1) {\n i++;\n }\n\n return 1 << i + 1 + odd;\n };\n\n FFTM.prototype.conjugate = function conjugate (rws, iws, N) {\n if (N <= 1) return;\n\n for (var i = 0; i < N / 2; i++) {\n var t = rws[i];\n\n rws[i] = rws[N - i - 1];\n rws[N - i - 1] = t;\n\n t = iws[i];\n\n iws[i] = -iws[N - i - 1];\n iws[N - i - 1] = -t;\n }\n };\n\n FFTM.prototype.normalize13b = function normalize13b (ws, N) {\n var carry = 0;\n for (var i = 0; i < N / 2; i++) {\n var w = Math.round(ws[2 * i + 1] / N) * 0x2000 +\n Math.round(ws[2 * i] / N) +\n carry;\n\n ws[i] = w & 0x3ffffff;\n\n if (w < 0x4000000) {\n carry = 0;\n } else {\n carry = w / 0x4000000 | 0;\n }\n }\n\n return ws;\n };\n\n FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) {\n var carry = 0;\n for (var i = 0; i < len; i++) {\n carry = carry + (ws[i] | 0);\n\n rws[2 * i] = carry & 0x1fff; carry = carry >>> 13;\n rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13;\n }\n\n // Pad with zeroes\n for (i = 2 * len; i < N; ++i) {\n rws[i] = 0;\n }\n\n assert(carry === 0);\n assert((carry & ~0x1fff) === 0);\n };\n\n FFTM.prototype.stub = function stub (N) {\n var ph = new Array(N);\n for (var i = 0; i < N; i++) {\n ph[i] = 0;\n }\n\n return ph;\n };\n\n FFTM.prototype.mulp = function mulp (x, y, out) {\n var N = 2 * this.guessLen13b(x.length, y.length);\n\n var rbt = this.makeRBT(N);\n\n var _ = this.stub(N);\n\n var rws = new Array(N);\n var rwst = new Array(N);\n var iwst = new Array(N);\n\n var nrws = new Array(N);\n var nrwst = new Array(N);\n var niwst = new Array(N);\n\n var rmws = out.words;\n rmws.length = N;\n\n this.convert13b(x.words, x.length, rws, N);\n this.convert13b(y.words, y.length, nrws, N);\n\n this.transform(rws, _, rwst, iwst, N, rbt);\n this.transform(nrws, _, nrwst, niwst, N, rbt);\n\n for (var i = 0; i < N; i++) {\n var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i];\n iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i];\n rwst[i] = rx;\n }\n\n this.conjugate(rwst, iwst, N);\n this.transform(rwst, iwst, rmws, _, N, rbt);\n this.conjugate(rmws, _, N);\n this.normalize13b(rmws, N);\n\n out.negative = x.negative ^ y.negative;\n out.length = x.length + y.length;\n return out.strip();\n };\n\n // Multiply `this` by `num`\n BN.prototype.mul = function mul (num) {\n var out = new BN(null);\n out.words = new Array(this.length + num.length);\n return this.mulTo(num, out);\n };\n\n // Multiply employing FFT\n BN.prototype.mulf = function mulf (num) {\n var out = new BN(null);\n out.words = new Array(this.length + num.length);\n return jumboMulTo(this, num, out);\n };\n\n // In-place Multiplication\n BN.prototype.imul = function imul (num) {\n return this.clone().mulTo(num, this);\n };\n\n BN.prototype.imuln = function imuln (num) {\n assert(typeof num === 'number');\n assert(num < 0x4000000);\n\n // Carry\n var carry = 0;\n for (var i = 0; i < this.length; i++) {\n var w = (this.words[i] | 0) * num;\n var lo = (w & 0x3ffffff) + (carry & 0x3ffffff);\n carry >>= 26;\n carry += (w / 0x4000000) | 0;\n // NOTE: lo is 27bit maximum\n carry += lo >>> 26;\n this.words[i] = lo & 0x3ffffff;\n }\n\n if (carry !== 0) {\n this.words[i] = carry;\n this.length++;\n }\n\n return this;\n };\n\n BN.prototype.muln = function muln (num) {\n return this.clone().imuln(num);\n };\n\n // `this` * `this`\n BN.prototype.sqr = function sqr () {\n return this.mul(this);\n };\n\n // `this` * `this` in-place\n BN.prototype.isqr = function isqr () {\n return this.imul(this.clone());\n };\n\n // Math.pow(`this`, `num`)\n BN.prototype.pow = function pow (num) {\n var w = toBitArray(num);\n if (w.length === 0) return new BN(1);\n\n // Skip leading zeroes\n var res = this;\n for (var i = 0; i < w.length; i++, res = res.sqr()) {\n if (w[i] !== 0) break;\n }\n\n if (++i < w.length) {\n for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) {\n if (w[i] === 0) continue;\n\n res = res.mul(q);\n }\n }\n\n return res;\n };\n\n // Shift-left in-place\n BN.prototype.iushln = function iushln (bits) {\n assert(typeof bits === 'number' && bits >= 0);\n var r = bits % 26;\n var s = (bits - r) / 26;\n var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r);\n var i;\n\n if (r !== 0) {\n var carry = 0;\n\n for (i = 0; i < this.length; i++) {\n var newCarry = this.words[i] & carryMask;\n var c = ((this.words[i] | 0) - newCarry) << r;\n this.words[i] = c | carry;\n carry = newCarry >>> (26 - r);\n }\n\n if (carry) {\n this.words[i] = carry;\n this.length++;\n }\n }\n\n if (s !== 0) {\n for (i = this.length - 1; i >= 0; i--) {\n this.words[i + s] = this.words[i];\n }\n\n for (i = 0; i < s; i++) {\n this.words[i] = 0;\n }\n\n this.length += s;\n }\n\n return this.strip();\n };\n\n BN.prototype.ishln = function ishln (bits) {\n // TODO(indutny): implement me\n assert(this.negative === 0);\n return this.iushln(bits);\n };\n\n // Shift-right in-place\n // NOTE: `hint` is a lowest bit before trailing zeroes\n // NOTE: if `extended` is present - it will be filled with destroyed bits\n BN.prototype.iushrn = function iushrn (bits, hint, extended) {\n assert(typeof bits === 'number' && bits >= 0);\n var h;\n if (hint) {\n h = (hint - (hint % 26)) / 26;\n } else {\n h = 0;\n }\n\n var r = bits % 26;\n var s = Math.min((bits - r) / 26, this.length);\n var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);\n var maskedWords = extended;\n\n h -= s;\n h = Math.max(0, h);\n\n // Extended mode, copy masked part\n if (maskedWords) {\n for (var i = 0; i < s; i++) {\n maskedWords.words[i] = this.words[i];\n }\n maskedWords.length = s;\n }\n\n if (s === 0) {\n // No-op, we should not move anything at all\n } else if (this.length > s) {\n this.length -= s;\n for (i = 0; i < this.length; i++) {\n this.words[i] = this.words[i + s];\n }\n } else {\n this.words[0] = 0;\n this.length = 1;\n }\n\n var carry = 0;\n for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) {\n var word = this.words[i] | 0;\n this.words[i] = (carry << (26 - r)) | (word >>> r);\n carry = word & mask;\n }\n\n // Push carried bits as a mask\n if (maskedWords && carry !== 0) {\n maskedWords.words[maskedWords.length++] = carry;\n }\n\n if (this.length === 0) {\n this.words[0] = 0;\n this.length = 1;\n }\n\n return this.strip();\n };\n\n BN.prototype.ishrn = function ishrn (bits, hint, extended) {\n // TODO(indutny): implement me\n assert(this.negative === 0);\n return this.iushrn(bits, hint, extended);\n };\n\n // Shift-left\n BN.prototype.shln = function shln (bits) {\n return this.clone().ishln(bits);\n };\n\n BN.prototype.ushln = function ushln (bits) {\n return this.clone().iushln(bits);\n };\n\n // Shift-right\n BN.prototype.shrn = function shrn (bits) {\n return this.clone().ishrn(bits);\n };\n\n BN.prototype.ushrn = function ushrn (bits) {\n return this.clone().iushrn(bits);\n };\n\n // Test if n bit is set\n BN.prototype.testn = function testn (bit) {\n assert(typeof bit === 'number' && bit >= 0);\n var r = bit % 26;\n var s = (bit - r) / 26;\n var q = 1 << r;\n\n // Fast case: bit is much higher than all existing words\n if (this.length <= s) return false;\n\n // Check bit and return\n var w = this.words[s];\n\n return !!(w & q);\n };\n\n // Return only lowers bits of number (in-place)\n BN.prototype.imaskn = function imaskn (bits) {\n assert(typeof bits === 'number' && bits >= 0);\n var r = bits % 26;\n var s = (bits - r) / 26;\n\n assert(this.negative === 0, 'imaskn works only with positive numbers');\n\n if (this.length <= s) {\n return this;\n }\n\n if (r !== 0) {\n s++;\n }\n this.length = Math.min(s, this.length);\n\n if (r !== 0) {\n var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);\n this.words[this.length - 1] &= mask;\n }\n\n return this.strip();\n };\n\n // Return only lowers bits of number\n BN.prototype.maskn = function maskn (bits) {\n return this.clone().imaskn(bits);\n };\n\n // Add plain number `num` to `this`\n BN.prototype.iaddn = function iaddn (num) {\n assert(typeof num === 'number');\n assert(num < 0x4000000);\n if (num < 0) return this.isubn(-num);\n\n // Possible sign change\n if (this.negative !== 0) {\n if (this.length === 1 && (this.words[0] | 0) < num) {\n this.words[0] = num - (this.words[0] | 0);\n this.negative = 0;\n return this;\n }\n\n this.negative = 0;\n this.isubn(num);\n this.negative = 1;\n return this;\n }\n\n // Add without checks\n return this._iaddn(num);\n };\n\n BN.prototype._iaddn = function _iaddn (num) {\n this.words[0] += num;\n\n // Carry\n for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) {\n this.words[i] -= 0x4000000;\n if (i === this.length - 1) {\n this.words[i + 1] = 1;\n } else {\n this.words[i + 1]++;\n }\n }\n this.length = Math.max(this.length, i + 1);\n\n return this;\n };\n\n // Subtract plain number `num` from `this`\n BN.prototype.isubn = function isubn (num) {\n assert(typeof num === 'number');\n assert(num < 0x4000000);\n if (num < 0) return this.iaddn(-num);\n\n if (this.negative !== 0) {\n this.negative = 0;\n this.iaddn(num);\n this.negative = 1;\n return this;\n }\n\n this.words[0] -= num;\n\n if (this.length === 1 && this.words[0] < 0) {\n this.words[0] = -this.words[0];\n this.negative = 1;\n } else {\n // Carry\n for (var i = 0; i < this.length && this.words[i] < 0; i++) {\n this.words[i] += 0x4000000;\n this.words[i + 1] -= 1;\n }\n }\n\n return this.strip();\n };\n\n BN.prototype.addn = function addn (num) {\n return this.clone().iaddn(num);\n };\n\n BN.prototype.subn = function subn (num) {\n return this.clone().isubn(num);\n };\n\n BN.prototype.iabs = function iabs () {\n this.negative = 0;\n\n return this;\n };\n\n BN.prototype.abs = function abs () {\n return this.clone().iabs();\n };\n\n BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) {\n var len = num.length + shift;\n var i;\n\n this._expand(len);\n\n var w;\n var carry = 0;\n for (i = 0; i < num.length; i++) {\n w = (this.words[i + shift] | 0) + carry;\n var right = (num.words[i] | 0) * mul;\n w -= right & 0x3ffffff;\n carry = (w >> 26) - ((right / 0x4000000) | 0);\n this.words[i + shift] = w & 0x3ffffff;\n }\n for (; i < this.length - shift; i++) {\n w = (this.words[i + shift] | 0) + carry;\n carry = w >> 26;\n this.words[i + shift] = w & 0x3ffffff;\n }\n\n if (carry === 0) return this.strip();\n\n // Subtraction overflow\n assert(carry === -1);\n carry = 0;\n for (i = 0; i < this.length; i++) {\n w = -(this.words[i] | 0) + carry;\n carry = w >> 26;\n this.words[i] = w & 0x3ffffff;\n }\n this.negative = 1;\n\n return this.strip();\n };\n\n BN.prototype._wordDiv = function _wordDiv (num, mode) {\n var shift = this.length - num.length;\n\n var a = this.clone();\n var b = num;\n\n // Normalize\n var bhi = b.words[b.length - 1] | 0;\n var bhiBits = this._countBits(bhi);\n shift = 26 - bhiBits;\n if (shift !== 0) {\n b = b.ushln(shift);\n a.iushln(shift);\n bhi = b.words[b.length - 1] | 0;\n }\n\n // Initialize quotient\n var m = a.length - b.length;\n var q;\n\n if (mode !== 'mod') {\n q = new BN(null);\n q.length = m + 1;\n q.words = new Array(q.length);\n for (var i = 0; i < q.length; i++) {\n q.words[i] = 0;\n }\n }\n\n var diff = a.clone()._ishlnsubmul(b, 1, m);\n if (diff.negative === 0) {\n a = diff;\n if (q) {\n q.words[m] = 1;\n }\n }\n\n for (var j = m - 1; j >= 0; j--) {\n var qj = (a.words[b.length + j] | 0) * 0x4000000 +\n (a.words[b.length + j - 1] | 0);\n\n // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max\n // (0x7ffffff)\n qj = Math.min((qj / bhi) | 0, 0x3ffffff);\n\n a._ishlnsubmul(b, qj, j);\n while (a.negative !== 0) {\n qj--;\n a.negative = 0;\n a._ishlnsubmul(b, 1, j);\n if (!a.isZero()) {\n a.negative ^= 1;\n }\n }\n if (q) {\n q.words[j] = qj;\n }\n }\n if (q) {\n q.strip();\n }\n a.strip();\n\n // Denormalize\n if (mode !== 'div' && shift !== 0) {\n a.iushrn(shift);\n }\n\n return {\n div: q || null,\n mod: a\n };\n };\n\n // NOTE: 1) `mode` can be set to `mod` to request mod only,\n // to `div` to request div only, or be absent to\n // request both div & mod\n // 2) `positive` is true if unsigned mod is requested\n BN.prototype.divmod = function divmod (num, mode, positive) {\n assert(!num.isZero());\n\n if (this.isZero()) {\n return {\n div: new BN(0),\n mod: new BN(0)\n };\n }\n\n var div, mod, res;\n if (this.negative !== 0 && num.negative === 0) {\n res = this.neg().divmod(num, mode);\n\n if (mode !== 'mod') {\n div = res.div.neg();\n }\n\n if (mode !== 'div') {\n mod = res.mod.neg();\n if (positive && mod.negative !== 0) {\n mod.iadd(num);\n }\n }\n\n return {\n div: div,\n mod: mod\n };\n }\n\n if (this.negative === 0 && num.negative !== 0) {\n res = this.divmod(num.neg(), mode);\n\n if (mode !== 'mod') {\n div = res.div.neg();\n }\n\n return {\n div: div,\n mod: res.mod\n };\n }\n\n if ((this.negative & num.negative) !== 0) {\n res = this.neg().divmod(num.neg(), mode);\n\n if (mode !== 'div') {\n mod = res.mod.neg();\n if (positive && mod.negative !== 0) {\n mod.isub(num);\n }\n }\n\n return {\n div: res.div,\n mod: mod\n };\n }\n\n // Both numbers are positive at this point\n\n // Strip both numbers to approximate shift value\n if (num.length > this.length || this.cmp(num) < 0) {\n return {\n div: new BN(0),\n mod: this\n };\n }\n\n // Very short reduction\n if (num.length === 1) {\n if (mode === 'div') {\n return {\n div: this.divn(num.words[0]),\n mod: null\n };\n }\n\n if (mode === 'mod') {\n return {\n div: null,\n mod: new BN(this.modn(num.words[0]))\n };\n }\n\n return {\n div: this.divn(num.words[0]),\n mod: new BN(this.modn(num.words[0]))\n };\n }\n\n return this._wordDiv(num, mode);\n };\n\n // Find `this` / `num`\n BN.prototype.div = function div (num) {\n return this.divmod(num, 'div', false).div;\n };\n\n // Find `this` % `num`\n BN.prototype.mod = function mod (num) {\n return this.divmod(num, 'mod', false).mod;\n };\n\n BN.prototype.umod = function umod (num) {\n return this.divmod(num, 'mod', true).mod;\n };\n\n // Find Round(`this` / `num`)\n BN.prototype.divRound = function divRound (num) {\n var dm = this.divmod(num);\n\n // Fast case - exact division\n if (dm.mod.isZero()) return dm.div;\n\n var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod;\n\n var half = num.ushrn(1);\n var r2 = num.andln(1);\n var cmp = mod.cmp(half);\n\n // Round down\n if (cmp < 0 || r2 === 1 && cmp === 0) return dm.div;\n\n // Round up\n return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1);\n };\n\n BN.prototype.modn = function modn (num) {\n assert(num <= 0x3ffffff);\n var p = (1 << 26) % num;\n\n var acc = 0;\n for (var i = this.length - 1; i >= 0; i--) {\n acc = (p * acc + (this.words[i] | 0)) % num;\n }\n\n return acc;\n };\n\n // In-place division by number\n BN.prototype.idivn = function idivn (num) {\n assert(num <= 0x3ffffff);\n\n var carry = 0;\n for (var i = this.length - 1; i >= 0; i--) {\n var w = (this.words[i] | 0) + carry * 0x4000000;\n this.words[i] = (w / num) | 0;\n carry = w % num;\n }\n\n return this.strip();\n };\n\n BN.prototype.divn = function divn (num) {\n return this.clone().idivn(num);\n };\n\n BN.prototype.egcd = function egcd (p) {\n assert(p.negative === 0);\n assert(!p.isZero());\n\n var x = this;\n var y = p.clone();\n\n if (x.negative !== 0) {\n x = x.umod(p);\n } else {\n x = x.clone();\n }\n\n // A * x + B * y = x\n var A = new BN(1);\n var B = new BN(0);\n\n // C * x + D * y = y\n var C = new BN(0);\n var D = new BN(1);\n\n var g = 0;\n\n while (x.isEven() && y.isEven()) {\n x.iushrn(1);\n y.iushrn(1);\n ++g;\n }\n\n var yp = y.clone();\n var xp = x.clone();\n\n while (!x.isZero()) {\n for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1);\n if (i > 0) {\n x.iushrn(i);\n while (i-- > 0) {\n if (A.isOdd() || B.isOdd()) {\n A.iadd(yp);\n B.isub(xp);\n }\n\n A.iushrn(1);\n B.iushrn(1);\n }\n }\n\n for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);\n if (j > 0) {\n y.iushrn(j);\n while (j-- > 0) {\n if (C.isOdd() || D.isOdd()) {\n C.iadd(yp);\n D.isub(xp);\n }\n\n C.iushrn(1);\n D.iushrn(1);\n }\n }\n\n if (x.cmp(y) >= 0) {\n x.isub(y);\n A.isub(C);\n B.isub(D);\n } else {\n y.isub(x);\n C.isub(A);\n D.isub(B);\n }\n }\n\n return {\n a: C,\n b: D,\n gcd: y.iushln(g)\n };\n };\n\n // This is reduced incarnation of the binary EEA\n // above, designated to invert members of the\n // _prime_ fields F(p) at a maximal speed\n BN.prototype._invmp = function _invmp (p) {\n assert(p.negative === 0);\n assert(!p.isZero());\n\n var a = this;\n var b = p.clone();\n\n if (a.negative !== 0) {\n a = a.umod(p);\n } else {\n a = a.clone();\n }\n\n var x1 = new BN(1);\n var x2 = new BN(0);\n\n var delta = b.clone();\n\n while (a.cmpn(1) > 0 && b.cmpn(1) > 0) {\n for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1);\n if (i > 0) {\n a.iushrn(i);\n while (i-- > 0) {\n if (x1.isOdd()) {\n x1.iadd(delta);\n }\n\n x1.iushrn(1);\n }\n }\n\n for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);\n if (j > 0) {\n b.iushrn(j);\n while (j-- > 0) {\n if (x2.isOdd()) {\n x2.iadd(delta);\n }\n\n x2.iushrn(1);\n }\n }\n\n if (a.cmp(b) >= 0) {\n a.isub(b);\n x1.isub(x2);\n } else {\n b.isub(a);\n x2.isub(x1);\n }\n }\n\n var res;\n if (a.cmpn(1) === 0) {\n res = x1;\n } else {\n res = x2;\n }\n\n if (res.cmpn(0) < 0) {\n res.iadd(p);\n }\n\n return res;\n };\n\n BN.prototype.gcd = function gcd (num) {\n if (this.isZero()) return num.abs();\n if (num.isZero()) return this.abs();\n\n var a = this.clone();\n var b = num.clone();\n a.negative = 0;\n b.negative = 0;\n\n // Remove common factor of two\n for (var shift = 0; a.isEven() && b.isEven(); shift++) {\n a.iushrn(1);\n b.iushrn(1);\n }\n\n do {\n while (a.isEven()) {\n a.iushrn(1);\n }\n while (b.isEven()) {\n b.iushrn(1);\n }\n\n var r = a.cmp(b);\n if (r < 0) {\n // Swap `a` and `b` to make `a` always bigger than `b`\n var t = a;\n a = b;\n b = t;\n } else if (r === 0 || b.cmpn(1) === 0) {\n break;\n }\n\n a.isub(b);\n } while (true);\n\n return b.iushln(shift);\n };\n\n // Invert number in the field F(num)\n BN.prototype.invm = function invm (num) {\n return this.egcd(num).a.umod(num);\n };\n\n BN.prototype.isEven = function isEven () {\n return (this.words[0] & 1) === 0;\n };\n\n BN.prototype.isOdd = function isOdd () {\n return (this.words[0] & 1) === 1;\n };\n\n // And first word and num\n BN.prototype.andln = function andln (num) {\n return this.words[0] & num;\n };\n\n // Increment at the bit position in-line\n BN.prototype.bincn = function bincn (bit) {\n assert(typeof bit === 'number');\n var r = bit % 26;\n var s = (bit - r) / 26;\n var q = 1 << r;\n\n // Fast case: bit is much higher than all existing words\n if (this.length <= s) {\n this._expand(s + 1);\n this.words[s] |= q;\n return this;\n }\n\n // Add bit and propagate, if needed\n var carry = q;\n for (var i = s; carry !== 0 && i < this.length; i++) {\n var w = this.words[i] | 0;\n w += carry;\n carry = w >>> 26;\n w &= 0x3ffffff;\n this.words[i] = w;\n }\n if (carry !== 0) {\n this.words[i] = carry;\n this.length++;\n }\n return this;\n };\n\n BN.prototype.isZero = function isZero () {\n return this.length === 1 && this.words[0] === 0;\n };\n\n BN.prototype.cmpn = function cmpn (num) {\n var negative = num < 0;\n\n if (this.negative !== 0 && !negative) return -1;\n if (this.negative === 0 && negative) return 1;\n\n this.strip();\n\n var res;\n if (this.length > 1) {\n res = 1;\n } else {\n if (negative) {\n num = -num;\n }\n\n assert(num <= 0x3ffffff, 'Number is too big');\n\n var w = this.words[0] | 0;\n res = w === num ? 0 : w < num ? -1 : 1;\n }\n if (this.negative !== 0) return -res | 0;\n return res;\n };\n\n // Compare two numbers and return:\n // 1 - if `this` > `num`\n // 0 - if `this` == `num`\n // -1 - if `this` < `num`\n BN.prototype.cmp = function cmp (num) {\n if (this.negative !== 0 && num.negative === 0) return -1;\n if (this.negative === 0 && num.negative !== 0) return 1;\n\n var res = this.ucmp(num);\n if (this.negative !== 0) return -res | 0;\n return res;\n };\n\n // Unsigned comparison\n BN.prototype.ucmp = function ucmp (num) {\n // At this point both numbers have the same sign\n if (this.length > num.length) return 1;\n if (this.length < num.length) return -1;\n\n var res = 0;\n for (var i = this.length - 1; i >= 0; i--) {\n var a = this.words[i] | 0;\n var b = num.words[i] | 0;\n\n if (a === b) continue;\n if (a < b) {\n res = -1;\n } else if (a > b) {\n res = 1;\n }\n break;\n }\n return res;\n };\n\n BN.prototype.gtn = function gtn (num) {\n return this.cmpn(num) === 1;\n };\n\n BN.prototype.gt = function gt (num) {\n return this.cmp(num) === 1;\n };\n\n BN.prototype.gten = function gten (num) {\n return this.cmpn(num) >= 0;\n };\n\n BN.prototype.gte = function gte (num) {\n return this.cmp(num) >= 0;\n };\n\n BN.prototype.ltn = function ltn (num) {\n return this.cmpn(num) === -1;\n };\n\n BN.prototype.lt = function lt (num) {\n return this.cmp(num) === -1;\n };\n\n BN.prototype.lten = function lten (num) {\n return this.cmpn(num) <= 0;\n };\n\n BN.prototype.lte = function lte (num) {\n return this.cmp(num) <= 0;\n };\n\n BN.prototype.eqn = function eqn (num) {\n return this.cmpn(num) === 0;\n };\n\n BN.prototype.eq = function eq (num) {\n return this.cmp(num) === 0;\n };\n\n //\n // A reduce context, could be using montgomery or something better, depending\n // on the `m` itself.\n //\n BN.red = function red (num) {\n return new Red(num);\n };\n\n BN.prototype.toRed = function toRed (ctx) {\n assert(!this.red, 'Already a number in reduction context');\n assert(this.negative === 0, 'red works only with positives');\n return ctx.convertTo(this)._forceRed(ctx);\n };\n\n BN.prototype.fromRed = function fromRed () {\n assert(this.red, 'fromRed works only with numbers in reduction context');\n return this.red.convertFrom(this);\n };\n\n BN.prototype._forceRed = function _forceRed (ctx) {\n this.red = ctx;\n return this;\n };\n\n BN.prototype.forceRed = function forceRed (ctx) {\n assert(!this.red, 'Already a number in reduction context');\n return this._forceRed(ctx);\n };\n\n BN.prototype.redAdd = function redAdd (num) {\n assert(this.red, 'redAdd works only with red numbers');\n return this.red.add(this, num);\n };\n\n BN.prototype.redIAdd = function redIAdd (num) {\n assert(this.red, 'redIAdd works only with red numbers');\n return this.red.iadd(this, num);\n };\n\n BN.prototype.redSub = function redSub (num) {\n assert(this.red, 'redSub works only with red numbers');\n return this.red.sub(this, num);\n };\n\n BN.prototype.redISub = function redISub (num) {\n assert(this.red, 'redISub works only with red numbers');\n return this.red.isub(this, num);\n };\n\n BN.prototype.redShl = function redShl (num) {\n assert(this.red, 'redShl works only with red numbers');\n return this.red.shl(this, num);\n };\n\n BN.prototype.redMul = function redMul (num) {\n assert(this.red, 'redMul works only with red numbers');\n this.red._verify2(this, num);\n return this.red.mul(this, num);\n };\n\n BN.prototype.redIMul = function redIMul (num) {\n assert(this.red, 'redMul works only with red numbers');\n this.red._verify2(this, num);\n return this.red.imul(this, num);\n };\n\n BN.prototype.redSqr = function redSqr () {\n assert(this.red, 'redSqr works only with red numbers');\n this.red._verify1(this);\n return this.red.sqr(this);\n };\n\n BN.prototype.redISqr = function redISqr () {\n assert(this.red, 'redISqr works only with red numbers');\n this.red._verify1(this);\n return this.red.isqr(this);\n };\n\n // Square root over p\n BN.prototype.redSqrt = function redSqrt () {\n assert(this.red, 'redSqrt works only with red numbers');\n this.red._verify1(this);\n return this.red.sqrt(this);\n };\n\n BN.prototype.redInvm = function redInvm () {\n assert(this.red, 'redInvm works only with red numbers');\n this.red._verify1(this);\n return this.red.invm(this);\n };\n\n // Return negative clone of `this` % `red modulo`\n BN.prototype.redNeg = function redNeg () {\n assert(this.red, 'redNeg works only with red numbers');\n this.red._verify1(this);\n return this.red.neg(this);\n };\n\n BN.prototype.redPow = function redPow (num) {\n assert(this.red && !num.red, 'redPow(normalNum)');\n this.red._verify1(this);\n return this.red.pow(this, num);\n };\n\n // Prime numbers with efficient reduction\n var primes = {\n k256: null,\n p224: null,\n p192: null,\n p25519: null\n };\n\n // Pseudo-Mersenne prime\n function MPrime (name, p) {\n // P = 2 ^ N - K\n this.name = name;\n this.p = new BN(p, 16);\n this.n = this.p.bitLength();\n this.k = new BN(1).iushln(this.n).isub(this.p);\n\n this.tmp = this._tmp();\n }\n\n MPrime.prototype._tmp = function _tmp () {\n var tmp = new BN(null);\n tmp.words = new Array(Math.ceil(this.n / 13));\n return tmp;\n };\n\n MPrime.prototype.ireduce = function ireduce (num) {\n // Assumes that `num` is less than `P^2`\n // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P)\n var r = num;\n var rlen;\n\n do {\n this.split(r, this.tmp);\n r = this.imulK(r);\n r = r.iadd(this.tmp);\n rlen = r.bitLength();\n } while (rlen > this.n);\n\n var cmp = rlen < this.n ? -1 : r.ucmp(this.p);\n if (cmp === 0) {\n r.words[0] = 0;\n r.length = 1;\n } else if (cmp > 0) {\n r.isub(this.p);\n } else {\n r.strip();\n }\n\n return r;\n };\n\n MPrime.prototype.split = function split (input, out) {\n input.iushrn(this.n, 0, out);\n };\n\n MPrime.prototype.imulK = function imulK (num) {\n return num.imul(this.k);\n };\n\n function K256 () {\n MPrime.call(\n this,\n 'k256',\n 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f');\n }\n inherits(K256, MPrime);\n\n K256.prototype.split = function split (input, output) {\n // 256 = 9 * 26 + 22\n var mask = 0x3fffff;\n\n var outLen = Math.min(input.length, 9);\n for (var i = 0; i < outLen; i++) {\n output.words[i] = input.words[i];\n }\n output.length = outLen;\n\n if (input.length <= 9) {\n input.words[0] = 0;\n input.length = 1;\n return;\n }\n\n // Shift by 9 limbs\n var prev = input.words[9];\n output.words[output.length++] = prev & mask;\n\n for (i = 10; i < input.length; i++) {\n var next = input.words[i] | 0;\n input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22);\n prev = next;\n }\n prev >>>= 22;\n input.words[i - 10] = prev;\n if (prev === 0 && input.length > 10) {\n input.length -= 10;\n } else {\n input.length -= 9;\n }\n };\n\n K256.prototype.imulK = function imulK (num) {\n // K = 0x1000003d1 = [ 0x40, 0x3d1 ]\n num.words[num.length] = 0;\n num.words[num.length + 1] = 0;\n num.length += 2;\n\n // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390\n var lo = 0;\n for (var i = 0; i < num.length; i++) {\n var w = num.words[i] | 0;\n lo += w * 0x3d1;\n num.words[i] = lo & 0x3ffffff;\n lo = w * 0x40 + ((lo / 0x4000000) | 0);\n }\n\n // Fast length reduction\n if (num.words[num.length - 1] === 0) {\n num.length--;\n if (num.words[num.length - 1] === 0) {\n num.length--;\n }\n }\n return num;\n };\n\n function P224 () {\n MPrime.call(\n this,\n 'p224',\n 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001');\n }\n inherits(P224, MPrime);\n\n function P192 () {\n MPrime.call(\n this,\n 'p192',\n 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff');\n }\n inherits(P192, MPrime);\n\n function P25519 () {\n // 2 ^ 255 - 19\n MPrime.call(\n this,\n '25519',\n '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed');\n }\n inherits(P25519, MPrime);\n\n P25519.prototype.imulK = function imulK (num) {\n // K = 0x13\n var carry = 0;\n for (var i = 0; i < num.length; i++) {\n var hi = (num.words[i] | 0) * 0x13 + carry;\n var lo = hi & 0x3ffffff;\n hi >>>= 26;\n\n num.words[i] = lo;\n carry = hi;\n }\n if (carry !== 0) {\n num.words[num.length++] = carry;\n }\n return num;\n };\n\n // Exported mostly for testing purposes, use plain name instead\n BN._prime = function prime (name) {\n // Cached version of prime\n if (primes[name]) return primes[name];\n\n var prime;\n if (name === 'k256') {\n prime = new K256();\n } else if (name === 'p224') {\n prime = new P224();\n } else if (name === 'p192') {\n prime = new P192();\n } else if (name === 'p25519') {\n prime = new P25519();\n } else {\n throw new Error('Unknown prime ' + name);\n }\n primes[name] = prime;\n\n return prime;\n };\n\n //\n // Base reduction engine\n //\n function Red (m) {\n if (typeof m === 'string') {\n var prime = BN._prime(m);\n this.m = prime.p;\n this.prime = prime;\n } else {\n assert(m.gtn(1), 'modulus must be greater than 1');\n this.m = m;\n this.prime = null;\n }\n }\n\n Red.prototype._verify1 = function _verify1 (a) {\n assert(a.negative === 0, 'red works only with positives');\n assert(a.red, 'red works only with red numbers');\n };\n\n Red.prototype._verify2 = function _verify2 (a, b) {\n assert((a.negative | b.negative) === 0, 'red works only with positives');\n assert(a.red && a.red === b.red,\n 'red works only with red numbers');\n };\n\n Red.prototype.imod = function imod (a) {\n if (this.prime) return this.prime.ireduce(a)._forceRed(this);\n return a.umod(this.m)._forceRed(this);\n };\n\n Red.prototype.neg = function neg (a) {\n if (a.isZero()) {\n return a.clone();\n }\n\n return this.m.sub(a)._forceRed(this);\n };\n\n Red.prototype.add = function add (a, b) {\n this._verify2(a, b);\n\n var res = a.add(b);\n if (res.cmp(this.m) >= 0) {\n res.isub(this.m);\n }\n return res._forceRed(this);\n };\n\n Red.prototype.iadd = function iadd (a, b) {\n this._verify2(a, b);\n\n var res = a.iadd(b);\n if (res.cmp(this.m) >= 0) {\n res.isub(this.m);\n }\n return res;\n };\n\n Red.prototype.sub = function sub (a, b) {\n this._verify2(a, b);\n\n var res = a.sub(b);\n if (res.cmpn(0) < 0) {\n res.iadd(this.m);\n }\n return res._forceRed(this);\n };\n\n Red.prototype.isub = function isub (a, b) {\n this._verify2(a, b);\n\n var res = a.isub(b);\n if (res.cmpn(0) < 0) {\n res.iadd(this.m);\n }\n return res;\n };\n\n Red.prototype.shl = function shl (a, num) {\n this._verify1(a);\n return this.imod(a.ushln(num));\n };\n\n Red.prototype.imul = function imul (a, b) {\n this._verify2(a, b);\n return this.imod(a.imul(b));\n };\n\n Red.prototype.mul = function mul (a, b) {\n this._verify2(a, b);\n return this.imod(a.mul(b));\n };\n\n Red.prototype.isqr = function isqr (a) {\n return this.imul(a, a.clone());\n };\n\n Red.prototype.sqr = function sqr (a) {\n return this.mul(a, a);\n };\n\n Red.prototype.sqrt = function sqrt (a) {\n if (a.isZero()) return a.clone();\n\n var mod3 = this.m.andln(3);\n assert(mod3 % 2 === 1);\n\n // Fast case\n if (mod3 === 3) {\n var pow = this.m.add(new BN(1)).iushrn(2);\n return this.pow(a, pow);\n }\n\n // Tonelli-Shanks algorithm (Totally unoptimized and slow)\n //\n // Find Q and S, that Q * 2 ^ S = (P - 1)\n var q = this.m.subn(1);\n var s = 0;\n while (!q.isZero() && q.andln(1) === 0) {\n s++;\n q.iushrn(1);\n }\n assert(!q.isZero());\n\n var one = new BN(1).toRed(this);\n var nOne = one.redNeg();\n\n // Find quadratic non-residue\n // NOTE: Max is such because of generalized Riemann hypothesis.\n var lpow = this.m.subn(1).iushrn(1);\n var z = this.m.bitLength();\n z = new BN(2 * z * z).toRed(this);\n\n while (this.pow(z, lpow).cmp(nOne) !== 0) {\n z.redIAdd(nOne);\n }\n\n var c = this.pow(z, q);\n var r = this.pow(a, q.addn(1).iushrn(1));\n var t = this.pow(a, q);\n var m = s;\n while (t.cmp(one) !== 0) {\n var tmp = t;\n for (var i = 0; tmp.cmp(one) !== 0; i++) {\n tmp = tmp.redSqr();\n }\n assert(i < m);\n var b = this.pow(c, new BN(1).iushln(m - i - 1));\n\n r = r.redMul(b);\n c = b.redSqr();\n t = t.redMul(c);\n m = i;\n }\n\n return r;\n };\n\n Red.prototype.invm = function invm (a) {\n var inv = a._invmp(this.m);\n if (inv.negative !== 0) {\n inv.negative = 0;\n return this.imod(inv).redNeg();\n } else {\n return this.imod(inv);\n }\n };\n\n Red.prototype.pow = function pow (a, num) {\n if (num.isZero()) return new BN(1).toRed(this);\n if (num.cmpn(1) === 0) return a.clone();\n\n var windowSize = 4;\n var wnd = new Array(1 << windowSize);\n wnd[0] = new BN(1).toRed(this);\n wnd[1] = a;\n for (var i = 2; i < wnd.length; i++) {\n wnd[i] = this.mul(wnd[i - 1], a);\n }\n\n var res = wnd[0];\n var current = 0;\n var currentLen = 0;\n var start = num.bitLength() % 26;\n if (start === 0) {\n start = 26;\n }\n\n for (i = num.length - 1; i >= 0; i--) {\n var word = num.words[i];\n for (var j = start - 1; j >= 0; j--) {\n var bit = (word >> j) & 1;\n if (res !== wnd[0]) {\n res = this.sqr(res);\n }\n\n if (bit === 0 && current === 0) {\n currentLen = 0;\n continue;\n }\n\n current <<= 1;\n current |= bit;\n currentLen++;\n if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue;\n\n res = this.mul(res, wnd[current]);\n currentLen = 0;\n current = 0;\n }\n start = 26;\n }\n\n return res;\n };\n\n Red.prototype.convertTo = function convertTo (num) {\n var r = num.umod(this.m);\n\n return r === num ? r.clone() : r;\n };\n\n Red.prototype.convertFrom = function convertFrom (num) {\n var res = num.clone();\n res.red = null;\n return res;\n };\n\n //\n // Montgomery method engine\n //\n\n BN.mont = function mont (num) {\n return new Mont(num);\n };\n\n function Mont (m) {\n Red.call(this, m);\n\n this.shift = this.m.bitLength();\n if (this.shift % 26 !== 0) {\n this.shift += 26 - (this.shift % 26);\n }\n\n this.r = new BN(1).iushln(this.shift);\n this.r2 = this.imod(this.r.sqr());\n this.rinv = this.r._invmp(this.m);\n\n this.minv = this.rinv.mul(this.r).isubn(1).div(this.m);\n this.minv = this.minv.umod(this.r);\n this.minv = this.r.sub(this.minv);\n }\n inherits(Mont, Red);\n\n Mont.prototype.convertTo = function convertTo (num) {\n return this.imod(num.ushln(this.shift));\n };\n\n Mont.prototype.convertFrom = function convertFrom (num) {\n var r = this.imod(num.mul(this.rinv));\n r.red = null;\n return r;\n };\n\n Mont.prototype.imul = function imul (a, b) {\n if (a.isZero() || b.isZero()) {\n a.words[0] = 0;\n a.length = 1;\n return a;\n }\n\n var t = a.imul(b);\n var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);\n var u = t.isub(c).iushrn(this.shift);\n var res = u;\n\n if (u.cmp(this.m) >= 0) {\n res = u.isub(this.m);\n } else if (u.cmpn(0) < 0) {\n res = u.iadd(this.m);\n }\n\n return res._forceRed(this);\n };\n\n Mont.prototype.mul = function mul (a, b) {\n if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this);\n\n var t = a.mul(b);\n var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);\n var u = t.isub(c).iushrn(this.shift);\n var res = u;\n if (u.cmp(this.m) >= 0) {\n res = u.isub(this.m);\n } else if (u.cmpn(0) < 0) {\n res = u.iadd(this.m);\n }\n\n return res._forceRed(this);\n };\n\n Mont.prototype.invm = function invm (a) {\n // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R\n var res = this.imod(a._invmp(this.m).mul(this.r2));\n return res._forceRed(this);\n };\n})(typeof module === 'undefined' || module, this);\n","var bn = require('bn.js');\nvar brorand = require('brorand');\n\nfunction MillerRabin(rand) {\n this.rand = rand || new brorand.Rand();\n}\nmodule.exports = MillerRabin;\n\nMillerRabin.create = function create(rand) {\n return new MillerRabin(rand);\n};\n\nMillerRabin.prototype._randbelow = function _randbelow(n) {\n var len = n.bitLength();\n var min_bytes = Math.ceil(len / 8);\n\n // Generage random bytes until a number less than n is found.\n // This ensures that 0..n-1 have an equal probability of being selected.\n do\n var a = new bn(this.rand.generate(min_bytes));\n while (a.cmp(n) >= 0);\n\n return a;\n};\n\nMillerRabin.prototype._randrange = function _randrange(start, stop) {\n // Generate a random number greater than or equal to start and less than stop.\n var size = stop.sub(start);\n return start.add(this._randbelow(size));\n};\n\nMillerRabin.prototype.test = function test(n, k, cb) {\n var len = n.bitLength();\n var red = bn.mont(n);\n var rone = new bn(1).toRed(red);\n\n if (!k)\n k = Math.max(1, (len / 48) | 0);\n\n // Find d and s, (n - 1) = (2 ^ s) * d;\n var n1 = n.subn(1);\n for (var s = 0; !n1.testn(s); s++) {}\n var d = n.shrn(s);\n\n var rn1 = n1.toRed(red);\n\n var prime = true;\n for (; k > 0; k--) {\n var a = this._randrange(new bn(2), n1);\n if (cb)\n cb(a);\n\n var x = a.toRed(red).redPow(d);\n if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)\n continue;\n\n for (var i = 1; i < s; i++) {\n x = x.redSqr();\n\n if (x.cmp(rone) === 0)\n return false;\n if (x.cmp(rn1) === 0)\n break;\n }\n\n if (i === s)\n return false;\n }\n\n return prime;\n};\n\nMillerRabin.prototype.getDivisor = function getDivisor(n, k) {\n var len = n.bitLength();\n var red = bn.mont(n);\n var rone = new bn(1).toRed(red);\n\n if (!k)\n k = Math.max(1, (len / 48) | 0);\n\n // Find d and s, (n - 1) = (2 ^ s) * d;\n var n1 = n.subn(1);\n for (var s = 0; !n1.testn(s); s++) {}\n var d = n.shrn(s);\n\n var rn1 = n1.toRed(red);\n\n for (; k > 0; k--) {\n var a = this._randrange(new bn(2), n1);\n\n var g = n.gcd(a);\n if (g.cmpn(1) !== 0)\n return g;\n\n var x = a.toRed(red).redPow(d);\n if (x.cmp(rone) === 0 || x.cmp(rn1) === 0)\n continue;\n\n for (var i = 1; i < s; i++) {\n x = x.redSqr();\n\n if (x.cmp(rone) === 0)\n return x.fromRed().subn(1).gcd(n);\n if (x.cmp(rn1) === 0)\n break;\n }\n\n if (i === s) {\n x = x.redSqr();\n return x.fromRed().subn(1).gcd(n);\n }\n }\n\n return false;\n};\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n'use strict';\n\nmodule.exports = Readable;\n/**/\n\nvar Duplex;\n/**/\n\nReadable.ReadableState = ReadableState;\n/**/\n\nvar EE = require('events').EventEmitter;\n\nvar EElistenerCount = function EElistenerCount(emitter, type) {\n return emitter.listeners(type).length;\n};\n/**/\n\n/**/\n\n\nvar Stream = require('./internal/streams/stream');\n/**/\n\n\nvar Buffer = require('buffer').Buffer;\n\nvar OurUint8Array = global.Uint8Array || function () {};\n\nfunction _uint8ArrayToBuffer(chunk) {\n return Buffer.from(chunk);\n}\n\nfunction _isUint8Array(obj) {\n return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;\n}\n/**/\n\n\nvar debugUtil = require('util');\n\nvar debug;\n\nif (debugUtil && debugUtil.debuglog) {\n debug = debugUtil.debuglog('stream');\n} else {\n debug = function debug() {};\n}\n/**/\n\n\nvar BufferList = require('./internal/streams/buffer_list');\n\nvar destroyImpl = require('./internal/streams/destroy');\n\nvar _require = require('./internal/streams/state'),\n getHighWaterMark = _require.getHighWaterMark;\n\nvar _require$codes = require('../errors').codes,\n ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE,\n ERR_STREAM_PUSH_AFTER_EOF = _require$codes.ERR_STREAM_PUSH_AFTER_EOF,\n ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,\n ERR_STREAM_UNSHIFT_AFTER_END_EVENT = _require$codes.ERR_STREAM_UNSHIFT_AFTER_END_EVENT; // Lazy loaded to improve the startup performance.\n\n\nvar StringDecoder;\nvar createReadableStreamAsyncIterator;\nvar from;\n\nrequire('inherits')(Readable, Stream);\n\nvar errorOrDestroy = destroyImpl.errorOrDestroy;\nvar kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume'];\n\nfunction prependListener(emitter, event, fn) {\n // Sadly this is not cacheable as some libraries bundle their own\n // event emitter implementation with them.\n if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn); // This is a hack to make sure that our error handler is attached before any\n // userland ones. NEVER DO THIS. This is here only because this code needs\n // to continue to work with older versions of Node.js that do not include\n // the prependListener() method. The goal is to eventually remove this hack.\n\n if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (Array.isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]];\n}\n\nfunction ReadableState(options, stream, isDuplex) {\n Duplex = Duplex || require('./_stream_duplex');\n options = options || {}; // Duplex streams are both readable and writable, but share\n // the same options object.\n // However, some cases require setting options to different\n // values for the readable and the writable sides of the duplex stream.\n // These options can be provided separately as readableXXX and writableXXX.\n\n if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag. Used to make read(n) ignore n and to\n // make all the buffer merging and length checks go away\n\n this.objectMode = !!options.objectMode;\n if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode; // the point at which it stops calling _read() to fill the buffer\n // Note: 0 is a valid value, means \"don't call _read preemptively ever\"\n\n this.highWaterMark = getHighWaterMark(this, options, 'readableHighWaterMark', isDuplex); // A linked list is used to store data chunks instead of an array because the\n // linked list can remove elements from the beginning faster than\n // array.shift()\n\n this.buffer = new BufferList();\n this.length = 0;\n this.pipes = null;\n this.pipesCount = 0;\n this.flowing = null;\n this.ended = false;\n this.endEmitted = false;\n this.reading = false; // a flag to be able to tell if the event 'readable'/'data' is emitted\n // immediately, or on a later tick. We set this to true at first, because\n // any actions that shouldn't happen until \"later\" should generally also\n // not happen before the first read call.\n\n this.sync = true; // whenever we return null, then we set a flag to say\n // that we're awaiting a 'readable' event emission.\n\n this.needReadable = false;\n this.emittedReadable = false;\n this.readableListening = false;\n this.resumeScheduled = false;\n this.paused = true; // Should close be emitted on destroy. Defaults to true.\n\n this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'end' (and potentially 'finish')\n\n this.autoDestroy = !!options.autoDestroy; // has it been destroyed\n\n this.destroyed = false; // Crypto is kind of old and crusty. Historically, its default string\n // encoding is 'binary' so we have to make this configurable.\n // Everything else in the universe uses 'utf8', though.\n\n this.defaultEncoding = options.defaultEncoding || 'utf8'; // the number of writers that are awaiting a drain event in .pipe()s\n\n this.awaitDrain = 0; // if true, a maybeReadMore has been scheduled\n\n this.readingMore = false;\n this.decoder = null;\n this.encoding = null;\n\n if (options.encoding) {\n if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;\n this.decoder = new StringDecoder(options.encoding);\n this.encoding = options.encoding;\n }\n}\n\nfunction Readable(options) {\n Duplex = Duplex || require('./_stream_duplex');\n if (!(this instanceof Readable)) return new Readable(options); // Checking for a Stream.Duplex instance is faster here instead of inside\n // the ReadableState constructor, at least with V8 6.5\n\n var isDuplex = this instanceof Duplex;\n this._readableState = new ReadableState(options, this, isDuplex); // legacy\n\n this.readable = true;\n\n if (options) {\n if (typeof options.read === 'function') this._read = options.read;\n if (typeof options.destroy === 'function') this._destroy = options.destroy;\n }\n\n Stream.call(this);\n}\n\nObject.defineProperty(Readable.prototype, 'destroyed', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n if (this._readableState === undefined) {\n return false;\n }\n\n return this._readableState.destroyed;\n },\n set: function set(value) {\n // we ignore the value if the stream\n // has not been initialized yet\n if (!this._readableState) {\n return;\n } // backward compatibility, the user is explicitly\n // managing destroyed\n\n\n this._readableState.destroyed = value;\n }\n});\nReadable.prototype.destroy = destroyImpl.destroy;\nReadable.prototype._undestroy = destroyImpl.undestroy;\n\nReadable.prototype._destroy = function (err, cb) {\n cb(err);\n}; // Manually shove something into the read() buffer.\n// This returns true if the highWaterMark has not been hit yet,\n// similar to how Writable.write() returns true if you should\n// write() some more.\n\n\nReadable.prototype.push = function (chunk, encoding) {\n var state = this._readableState;\n var skipChunkCheck;\n\n if (!state.objectMode) {\n if (typeof chunk === 'string') {\n encoding = encoding || state.defaultEncoding;\n\n if (encoding !== state.encoding) {\n chunk = Buffer.from(chunk, encoding);\n encoding = '';\n }\n\n skipChunkCheck = true;\n }\n } else {\n skipChunkCheck = true;\n }\n\n return readableAddChunk(this, chunk, encoding, false, skipChunkCheck);\n}; // Unshift should *always* be something directly out of read()\n\n\nReadable.prototype.unshift = function (chunk) {\n return readableAddChunk(this, chunk, null, true, false);\n};\n\nfunction readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) {\n debug('readableAddChunk', chunk);\n var state = stream._readableState;\n\n if (chunk === null) {\n state.reading = false;\n onEofChunk(stream, state);\n } else {\n var er;\n if (!skipChunkCheck) er = chunkInvalid(state, chunk);\n\n if (er) {\n errorOrDestroy(stream, er);\n } else if (state.objectMode || chunk && chunk.length > 0) {\n if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) {\n chunk = _uint8ArrayToBuffer(chunk);\n }\n\n if (addToFront) {\n if (state.endEmitted) errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT());else addChunk(stream, state, chunk, true);\n } else if (state.ended) {\n errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF());\n } else if (state.destroyed) {\n return false;\n } else {\n state.reading = false;\n\n if (state.decoder && !encoding) {\n chunk = state.decoder.write(chunk);\n if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state);\n } else {\n addChunk(stream, state, chunk, false);\n }\n }\n } else if (!addToFront) {\n state.reading = false;\n maybeReadMore(stream, state);\n }\n } // We can push more data if we are below the highWaterMark.\n // Also, if we have no data yet, we can stand some more bytes.\n // This is to work around cases where hwm=0, such as the repl.\n\n\n return !state.ended && (state.length < state.highWaterMark || state.length === 0);\n}\n\nfunction addChunk(stream, state, chunk, addToFront) {\n if (state.flowing && state.length === 0 && !state.sync) {\n state.awaitDrain = 0;\n stream.emit('data', chunk);\n } else {\n // update the buffer info.\n state.length += state.objectMode ? 1 : chunk.length;\n if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk);\n if (state.needReadable) emitReadable(stream);\n }\n\n maybeReadMore(stream, state);\n}\n\nfunction chunkInvalid(state, chunk) {\n var er;\n\n if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {\n er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer', 'Uint8Array'], chunk);\n }\n\n return er;\n}\n\nReadable.prototype.isPaused = function () {\n return this._readableState.flowing === false;\n}; // backwards compatibility.\n\n\nReadable.prototype.setEncoding = function (enc) {\n if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;\n var decoder = new StringDecoder(enc);\n this._readableState.decoder = decoder; // If setEncoding(null), decoder.encoding equals utf8\n\n this._readableState.encoding = this._readableState.decoder.encoding; // Iterate over current buffer to convert already stored Buffers:\n\n var p = this._readableState.buffer.head;\n var content = '';\n\n while (p !== null) {\n content += decoder.write(p.data);\n p = p.next;\n }\n\n this._readableState.buffer.clear();\n\n if (content !== '') this._readableState.buffer.push(content);\n this._readableState.length = content.length;\n return this;\n}; // Don't raise the hwm > 1GB\n\n\nvar MAX_HWM = 0x40000000;\n\nfunction computeNewHighWaterMark(n) {\n if (n >= MAX_HWM) {\n // TODO(ronag): Throw ERR_VALUE_OUT_OF_RANGE.\n n = MAX_HWM;\n } else {\n // Get the next highest power of 2 to prevent increasing hwm excessively in\n // tiny amounts\n n--;\n n |= n >>> 1;\n n |= n >>> 2;\n n |= n >>> 4;\n n |= n >>> 8;\n n |= n >>> 16;\n n++;\n }\n\n return n;\n} // This function is designed to be inlinable, so please take care when making\n// changes to the function body.\n\n\nfunction howMuchToRead(n, state) {\n if (n <= 0 || state.length === 0 && state.ended) return 0;\n if (state.objectMode) return 1;\n\n if (n !== n) {\n // Only flow one buffer at a time\n if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length;\n } // If we're asking for more than the current hwm, then raise the hwm.\n\n\n if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);\n if (n <= state.length) return n; // Don't have enough\n\n if (!state.ended) {\n state.needReadable = true;\n return 0;\n }\n\n return state.length;\n} // you can override either this method, or the async _read(n) below.\n\n\nReadable.prototype.read = function (n) {\n debug('read', n);\n n = parseInt(n, 10);\n var state = this._readableState;\n var nOrig = n;\n if (n !== 0) state.emittedReadable = false; // if we're doing read(0) to trigger a readable event, but we\n // already have a bunch of data in the buffer, then just trigger\n // the 'readable' event and move on.\n\n if (n === 0 && state.needReadable && ((state.highWaterMark !== 0 ? state.length >= state.highWaterMark : state.length > 0) || state.ended)) {\n debug('read: emitReadable', state.length, state.ended);\n if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this);\n return null;\n }\n\n n = howMuchToRead(n, state); // if we've ended, and we're now clear, then finish it up.\n\n if (n === 0 && state.ended) {\n if (state.length === 0) endReadable(this);\n return null;\n } // All the actual chunk generation logic needs to be\n // *below* the call to _read. The reason is that in certain\n // synthetic stream cases, such as passthrough streams, _read\n // may be a completely synchronous operation which may change\n // the state of the read buffer, providing enough data when\n // before there was *not* enough.\n //\n // So, the steps are:\n // 1. Figure out what the state of things will be after we do\n // a read from the buffer.\n //\n // 2. If that resulting state will trigger a _read, then call _read.\n // Note that this may be asynchronous, or synchronous. Yes, it is\n // deeply ugly to write APIs this way, but that still doesn't mean\n // that the Readable class should behave improperly, as streams are\n // designed to be sync/async agnostic.\n // Take note if the _read call is sync or async (ie, if the read call\n // has returned yet), so that we know whether or not it's safe to emit\n // 'readable' etc.\n //\n // 3. Actually pull the requested chunks out of the buffer and return.\n // if we need a readable event, then we need to do some reading.\n\n\n var doRead = state.needReadable;\n debug('need readable', doRead); // if we currently have less than the highWaterMark, then also read some\n\n if (state.length === 0 || state.length - n < state.highWaterMark) {\n doRead = true;\n debug('length less than watermark', doRead);\n } // however, if we've ended, then there's no point, and if we're already\n // reading, then it's unnecessary.\n\n\n if (state.ended || state.reading) {\n doRead = false;\n debug('reading or ended', doRead);\n } else if (doRead) {\n debug('do read');\n state.reading = true;\n state.sync = true; // if the length is currently zero, then we *need* a readable event.\n\n if (state.length === 0) state.needReadable = true; // call internal read method\n\n this._read(state.highWaterMark);\n\n state.sync = false; // If _read pushed data synchronously, then `reading` will be false,\n // and we need to re-evaluate how much data we can return to the user.\n\n if (!state.reading) n = howMuchToRead(nOrig, state);\n }\n\n var ret;\n if (n > 0) ret = fromList(n, state);else ret = null;\n\n if (ret === null) {\n state.needReadable = state.length <= state.highWaterMark;\n n = 0;\n } else {\n state.length -= n;\n state.awaitDrain = 0;\n }\n\n if (state.length === 0) {\n // If we have nothing in the buffer, then we want to know\n // as soon as we *do* get something into the buffer.\n if (!state.ended) state.needReadable = true; // If we tried to read() past the EOF, then emit end on the next tick.\n\n if (nOrig !== n && state.ended) endReadable(this);\n }\n\n if (ret !== null) this.emit('data', ret);\n return ret;\n};\n\nfunction onEofChunk(stream, state) {\n debug('onEofChunk');\n if (state.ended) return;\n\n if (state.decoder) {\n var chunk = state.decoder.end();\n\n if (chunk && chunk.length) {\n state.buffer.push(chunk);\n state.length += state.objectMode ? 1 : chunk.length;\n }\n }\n\n state.ended = true;\n\n if (state.sync) {\n // if we are sync, wait until next tick to emit the data.\n // Otherwise we risk emitting data in the flow()\n // the readable code triggers during a read() call\n emitReadable(stream);\n } else {\n // emit 'readable' now to make sure it gets picked up.\n state.needReadable = false;\n\n if (!state.emittedReadable) {\n state.emittedReadable = true;\n emitReadable_(stream);\n }\n }\n} // Don't emit readable right away in sync mode, because this can trigger\n// another read() call => stack overflow. This way, it might trigger\n// a nextTick recursion warning, but that's not so bad.\n\n\nfunction emitReadable(stream) {\n var state = stream._readableState;\n debug('emitReadable', state.needReadable, state.emittedReadable);\n state.needReadable = false;\n\n if (!state.emittedReadable) {\n debug('emitReadable', state.flowing);\n state.emittedReadable = true;\n process.nextTick(emitReadable_, stream);\n }\n}\n\nfunction emitReadable_(stream) {\n var state = stream._readableState;\n debug('emitReadable_', state.destroyed, state.length, state.ended);\n\n if (!state.destroyed && (state.length || state.ended)) {\n stream.emit('readable');\n state.emittedReadable = false;\n } // The stream needs another readable event if\n // 1. It is not flowing, as the flow mechanism will take\n // care of it.\n // 2. It is not ended.\n // 3. It is below the highWaterMark, so we can schedule\n // another readable later.\n\n\n state.needReadable = !state.flowing && !state.ended && state.length <= state.highWaterMark;\n flow(stream);\n} // at this point, the user has presumably seen the 'readable' event,\n// and called read() to consume some data. that may have triggered\n// in turn another _read(n) call, in which case reading = true if\n// it's in progress.\n// However, if we're not ended, or reading, and the length < hwm,\n// then go ahead and try to read some more preemptively.\n\n\nfunction maybeReadMore(stream, state) {\n if (!state.readingMore) {\n state.readingMore = true;\n process.nextTick(maybeReadMore_, stream, state);\n }\n}\n\nfunction maybeReadMore_(stream, state) {\n // Attempt to read more data if we should.\n //\n // The conditions for reading more data are (one of):\n // - Not enough data buffered (state.length < state.highWaterMark). The loop\n // is responsible for filling the buffer with enough data if such data\n // is available. If highWaterMark is 0 and we are not in the flowing mode\n // we should _not_ attempt to buffer any extra data. We'll get more data\n // when the stream consumer calls read() instead.\n // - No data in the buffer, and the stream is in flowing mode. In this mode\n // the loop below is responsible for ensuring read() is called. Failing to\n // call read here would abort the flow and there's no other mechanism for\n // continuing the flow if the stream consumer has just subscribed to the\n // 'data' event.\n //\n // In addition to the above conditions to keep reading data, the following\n // conditions prevent the data from being read:\n // - The stream has ended (state.ended).\n // - There is already a pending 'read' operation (state.reading). This is a\n // case where the the stream has called the implementation defined _read()\n // method, but they are processing the call asynchronously and have _not_\n // called push() with new data. In this case we skip performing more\n // read()s. The execution ends in this method again after the _read() ends\n // up calling push() with more data.\n while (!state.reading && !state.ended && (state.length < state.highWaterMark || state.flowing && state.length === 0)) {\n var len = state.length;\n debug('maybeReadMore read 0');\n stream.read(0);\n if (len === state.length) // didn't get any data, stop spinning.\n break;\n }\n\n state.readingMore = false;\n} // abstract method. to be overridden in specific implementation classes.\n// call cb(er, data) where data is <= n in length.\n// for virtual (non-string, non-buffer) streams, \"length\" is somewhat\n// arbitrary, and perhaps not very meaningful.\n\n\nReadable.prototype._read = function (n) {\n errorOrDestroy(this, new ERR_METHOD_NOT_IMPLEMENTED('_read()'));\n};\n\nReadable.prototype.pipe = function (dest, pipeOpts) {\n var src = this;\n var state = this._readableState;\n\n switch (state.pipesCount) {\n case 0:\n state.pipes = dest;\n break;\n\n case 1:\n state.pipes = [state.pipes, dest];\n break;\n\n default:\n state.pipes.push(dest);\n break;\n }\n\n state.pipesCount += 1;\n debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);\n var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr;\n var endFn = doEnd ? onend : unpipe;\n if (state.endEmitted) process.nextTick(endFn);else src.once('end', endFn);\n dest.on('unpipe', onunpipe);\n\n function onunpipe(readable, unpipeInfo) {\n debug('onunpipe');\n\n if (readable === src) {\n if (unpipeInfo && unpipeInfo.hasUnpiped === false) {\n unpipeInfo.hasUnpiped = true;\n cleanup();\n }\n }\n }\n\n function onend() {\n debug('onend');\n dest.end();\n } // when the dest drains, it reduces the awaitDrain counter\n // on the source. This would be more elegant with a .once()\n // handler in flow(), but adding and removing repeatedly is\n // too slow.\n\n\n var ondrain = pipeOnDrain(src);\n dest.on('drain', ondrain);\n var cleanedUp = false;\n\n function cleanup() {\n debug('cleanup'); // cleanup event handlers once the pipe is broken\n\n dest.removeListener('close', onclose);\n dest.removeListener('finish', onfinish);\n dest.removeListener('drain', ondrain);\n dest.removeListener('error', onerror);\n dest.removeListener('unpipe', onunpipe);\n src.removeListener('end', onend);\n src.removeListener('end', unpipe);\n src.removeListener('data', ondata);\n cleanedUp = true; // if the reader is waiting for a drain event from this\n // specific writer, then it would cause it to never start\n // flowing again.\n // So, if this is awaiting a drain, then we just call it now.\n // If we don't know, then assume that we are waiting for one.\n\n if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();\n }\n\n src.on('data', ondata);\n\n function ondata(chunk) {\n debug('ondata');\n var ret = dest.write(chunk);\n debug('dest.write', ret);\n\n if (ret === false) {\n // If the user unpiped during `dest.write()`, it is possible\n // to get stuck in a permanently paused state if that write\n // also returned false.\n // => Check whether `dest` is still a piping destination.\n if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {\n debug('false write response, pause', state.awaitDrain);\n state.awaitDrain++;\n }\n\n src.pause();\n }\n } // if the dest has an error, then stop piping into it.\n // however, don't suppress the throwing behavior for this.\n\n\n function onerror(er) {\n debug('onerror', er);\n unpipe();\n dest.removeListener('error', onerror);\n if (EElistenerCount(dest, 'error') === 0) errorOrDestroy(dest, er);\n } // Make sure our error handler is attached before userland ones.\n\n\n prependListener(dest, 'error', onerror); // Both close and finish should trigger unpipe, but only once.\n\n function onclose() {\n dest.removeListener('finish', onfinish);\n unpipe();\n }\n\n dest.once('close', onclose);\n\n function onfinish() {\n debug('onfinish');\n dest.removeListener('close', onclose);\n unpipe();\n }\n\n dest.once('finish', onfinish);\n\n function unpipe() {\n debug('unpipe');\n src.unpipe(dest);\n } // tell the dest that it's being piped to\n\n\n dest.emit('pipe', src); // start the flow if it hasn't been started already.\n\n if (!state.flowing) {\n debug('pipe resume');\n src.resume();\n }\n\n return dest;\n};\n\nfunction pipeOnDrain(src) {\n return function pipeOnDrainFunctionResult() {\n var state = src._readableState;\n debug('pipeOnDrain', state.awaitDrain);\n if (state.awaitDrain) state.awaitDrain--;\n\n if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) {\n state.flowing = true;\n flow(src);\n }\n };\n}\n\nReadable.prototype.unpipe = function (dest) {\n var state = this._readableState;\n var unpipeInfo = {\n hasUnpiped: false\n }; // if we're not piping anywhere, then do nothing.\n\n if (state.pipesCount === 0) return this; // just one destination. most common case.\n\n if (state.pipesCount === 1) {\n // passed in one, but it's not the right one.\n if (dest && dest !== state.pipes) return this;\n if (!dest) dest = state.pipes; // got a match.\n\n state.pipes = null;\n state.pipesCount = 0;\n state.flowing = false;\n if (dest) dest.emit('unpipe', this, unpipeInfo);\n return this;\n } // slow case. multiple pipe destinations.\n\n\n if (!dest) {\n // remove all.\n var dests = state.pipes;\n var len = state.pipesCount;\n state.pipes = null;\n state.pipesCount = 0;\n state.flowing = false;\n\n for (var i = 0; i < len; i++) {\n dests[i].emit('unpipe', this, {\n hasUnpiped: false\n });\n }\n\n return this;\n } // try to find the right one.\n\n\n var index = indexOf(state.pipes, dest);\n if (index === -1) return this;\n state.pipes.splice(index, 1);\n state.pipesCount -= 1;\n if (state.pipesCount === 1) state.pipes = state.pipes[0];\n dest.emit('unpipe', this, unpipeInfo);\n return this;\n}; // set up data events if they are asked for\n// Ensure readable listeners eventually get something\n\n\nReadable.prototype.on = function (ev, fn) {\n var res = Stream.prototype.on.call(this, ev, fn);\n var state = this._readableState;\n\n if (ev === 'data') {\n // update readableListening so that resume() may be a no-op\n // a few lines down. This is needed to support once('readable').\n state.readableListening = this.listenerCount('readable') > 0; // Try start flowing on next tick if stream isn't explicitly paused\n\n if (state.flowing !== false) this.resume();\n } else if (ev === 'readable') {\n if (!state.endEmitted && !state.readableListening) {\n state.readableListening = state.needReadable = true;\n state.flowing = false;\n state.emittedReadable = false;\n debug('on readable', state.length, state.reading);\n\n if (state.length) {\n emitReadable(this);\n } else if (!state.reading) {\n process.nextTick(nReadingNextTick, this);\n }\n }\n }\n\n return res;\n};\n\nReadable.prototype.addListener = Readable.prototype.on;\n\nReadable.prototype.removeListener = function (ev, fn) {\n var res = Stream.prototype.removeListener.call(this, ev, fn);\n\n if (ev === 'readable') {\n // We need to check if there is someone still listening to\n // readable and reset the state. However this needs to happen\n // after readable has been emitted but before I/O (nextTick) to\n // support once('readable', fn) cycles. This means that calling\n // resume within the same tick will have no\n // effect.\n process.nextTick(updateReadableListening, this);\n }\n\n return res;\n};\n\nReadable.prototype.removeAllListeners = function (ev) {\n var res = Stream.prototype.removeAllListeners.apply(this, arguments);\n\n if (ev === 'readable' || ev === undefined) {\n // We need to check if there is someone still listening to\n // readable and reset the state. However this needs to happen\n // after readable has been emitted but before I/O (nextTick) to\n // support once('readable', fn) cycles. This means that calling\n // resume within the same tick will have no\n // effect.\n process.nextTick(updateReadableListening, this);\n }\n\n return res;\n};\n\nfunction updateReadableListening(self) {\n var state = self._readableState;\n state.readableListening = self.listenerCount('readable') > 0;\n\n if (state.resumeScheduled && !state.paused) {\n // flowing needs to be set to true now, otherwise\n // the upcoming resume will not flow.\n state.flowing = true; // crude way to check if we should resume\n } else if (self.listenerCount('data') > 0) {\n self.resume();\n }\n}\n\nfunction nReadingNextTick(self) {\n debug('readable nexttick read 0');\n self.read(0);\n} // pause() and resume() are remnants of the legacy readable stream API\n// If the user uses them, then switch into old mode.\n\n\nReadable.prototype.resume = function () {\n var state = this._readableState;\n\n if (!state.flowing) {\n debug('resume'); // we flow only if there is no one listening\n // for readable, but we still have to call\n // resume()\n\n state.flowing = !state.readableListening;\n resume(this, state);\n }\n\n state.paused = false;\n return this;\n};\n\nfunction resume(stream, state) {\n if (!state.resumeScheduled) {\n state.resumeScheduled = true;\n process.nextTick(resume_, stream, state);\n }\n}\n\nfunction resume_(stream, state) {\n debug('resume', state.reading);\n\n if (!state.reading) {\n stream.read(0);\n }\n\n state.resumeScheduled = false;\n stream.emit('resume');\n flow(stream);\n if (state.flowing && !state.reading) stream.read(0);\n}\n\nReadable.prototype.pause = function () {\n debug('call pause flowing=%j', this._readableState.flowing);\n\n if (this._readableState.flowing !== false) {\n debug('pause');\n this._readableState.flowing = false;\n this.emit('pause');\n }\n\n this._readableState.paused = true;\n return this;\n};\n\nfunction flow(stream) {\n var state = stream._readableState;\n debug('flow', state.flowing);\n\n while (state.flowing && stream.read() !== null) {\n ;\n }\n} // wrap an old-style stream as the async data source.\n// This is *not* part of the readable stream interface.\n// It is an ugly unfortunate mess of history.\n\n\nReadable.prototype.wrap = function (stream) {\n var _this = this;\n\n var state = this._readableState;\n var paused = false;\n stream.on('end', function () {\n debug('wrapped end');\n\n if (state.decoder && !state.ended) {\n var chunk = state.decoder.end();\n if (chunk && chunk.length) _this.push(chunk);\n }\n\n _this.push(null);\n });\n stream.on('data', function (chunk) {\n debug('wrapped data');\n if (state.decoder) chunk = state.decoder.write(chunk); // don't skip over falsy values in objectMode\n\n if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return;\n\n var ret = _this.push(chunk);\n\n if (!ret) {\n paused = true;\n stream.pause();\n }\n }); // proxy all the other methods.\n // important when wrapping filters and duplexes.\n\n for (var i in stream) {\n if (this[i] === undefined && typeof stream[i] === 'function') {\n this[i] = function methodWrap(method) {\n return function methodWrapReturnFunction() {\n return stream[method].apply(stream, arguments);\n };\n }(i);\n }\n } // proxy certain important events.\n\n\n for (var n = 0; n < kProxyEvents.length; n++) {\n stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n]));\n } // when we try to consume some more bytes, simply unpause the\n // underlying stream.\n\n\n this._read = function (n) {\n debug('wrapped _read', n);\n\n if (paused) {\n paused = false;\n stream.resume();\n }\n };\n\n return this;\n};\n\nif (typeof Symbol === 'function') {\n Readable.prototype[Symbol.asyncIterator] = function () {\n if (createReadableStreamAsyncIterator === undefined) {\n createReadableStreamAsyncIterator = require('./internal/streams/async_iterator');\n }\n\n return createReadableStreamAsyncIterator(this);\n };\n}\n\nObject.defineProperty(Readable.prototype, 'readableHighWaterMark', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._readableState.highWaterMark;\n }\n});\nObject.defineProperty(Readable.prototype, 'readableBuffer', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._readableState && this._readableState.buffer;\n }\n});\nObject.defineProperty(Readable.prototype, 'readableFlowing', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._readableState.flowing;\n },\n set: function set(state) {\n if (this._readableState) {\n this._readableState.flowing = state;\n }\n }\n}); // exposed for testing purposes only.\n\nReadable._fromList = fromList;\nObject.defineProperty(Readable.prototype, 'readableLength', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._readableState.length;\n }\n}); // Pluck off n bytes from an array of buffers.\n// Length is the combined lengths of all the buffers in the list.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\n\nfunction fromList(n, state) {\n // nothing buffered\n if (state.length === 0) return null;\n var ret;\n if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) {\n // read it all, truncate the list\n if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.first();else ret = state.buffer.concat(state.length);\n state.buffer.clear();\n } else {\n // read part of list\n ret = state.buffer.consume(n, state.decoder);\n }\n return ret;\n}\n\nfunction endReadable(stream) {\n var state = stream._readableState;\n debug('endReadable', state.endEmitted);\n\n if (!state.endEmitted) {\n state.ended = true;\n process.nextTick(endReadableNT, state, stream);\n }\n}\n\nfunction endReadableNT(state, stream) {\n debug('endReadableNT', state.endEmitted, state.length); // Check that we didn't get one last unshift.\n\n if (!state.endEmitted && state.length === 0) {\n state.endEmitted = true;\n stream.readable = false;\n stream.emit('end');\n\n if (state.autoDestroy) {\n // In case of duplex streams we need a way to detect\n // if the writable side is ready for autoDestroy as well\n var wState = stream._writableState;\n\n if (!wState || wState.autoDestroy && wState.finished) {\n stream.destroy();\n }\n }\n }\n}\n\nif (typeof Symbol === 'function') {\n Readable.from = function (iterable, opts) {\n if (from === undefined) {\n from = require('./internal/streams/from');\n }\n\n return from(Readable, iterable, opts);\n };\n}\n\nfunction indexOf(xs, x) {\n for (var i = 0, l = xs.length; i < l; i++) {\n if (xs[i] === x) return i;\n }\n\n return -1;\n}","module.exports = require('events').EventEmitter;\n","'use strict'; // undocumented cb() API, needed for core, not for public API\n\nfunction destroy(err, cb) {\n var _this = this;\n\n var readableDestroyed = this._readableState && this._readableState.destroyed;\n var writableDestroyed = this._writableState && this._writableState.destroyed;\n\n if (readableDestroyed || writableDestroyed) {\n if (cb) {\n cb(err);\n } else if (err) {\n if (!this._writableState) {\n process.nextTick(emitErrorNT, this, err);\n } else if (!this._writableState.errorEmitted) {\n this._writableState.errorEmitted = true;\n process.nextTick(emitErrorNT, this, err);\n }\n }\n\n return this;\n } // we set destroyed to true before firing error callbacks in order\n // to make it re-entrance safe in case destroy() is called within callbacks\n\n\n if (this._readableState) {\n this._readableState.destroyed = true;\n } // if this is a duplex stream mark the writable part as destroyed as well\n\n\n if (this._writableState) {\n this._writableState.destroyed = true;\n }\n\n this._destroy(err || null, function (err) {\n if (!cb && err) {\n if (!_this._writableState) {\n process.nextTick(emitErrorAndCloseNT, _this, err);\n } else if (!_this._writableState.errorEmitted) {\n _this._writableState.errorEmitted = true;\n process.nextTick(emitErrorAndCloseNT, _this, err);\n } else {\n process.nextTick(emitCloseNT, _this);\n }\n } else if (cb) {\n process.nextTick(emitCloseNT, _this);\n cb(err);\n } else {\n process.nextTick(emitCloseNT, _this);\n }\n });\n\n return this;\n}\n\nfunction emitErrorAndCloseNT(self, err) {\n emitErrorNT(self, err);\n emitCloseNT(self);\n}\n\nfunction emitCloseNT(self) {\n if (self._writableState && !self._writableState.emitClose) return;\n if (self._readableState && !self._readableState.emitClose) return;\n self.emit('close');\n}\n\nfunction undestroy() {\n if (this._readableState) {\n this._readableState.destroyed = false;\n this._readableState.reading = false;\n this._readableState.ended = false;\n this._readableState.endEmitted = false;\n }\n\n if (this._writableState) {\n this._writableState.destroyed = false;\n this._writableState.ended = false;\n this._writableState.ending = false;\n this._writableState.finalCalled = false;\n this._writableState.prefinished = false;\n this._writableState.finished = false;\n this._writableState.errorEmitted = false;\n }\n}\n\nfunction emitErrorNT(self, err) {\n self.emit('error', err);\n}\n\nfunction errorOrDestroy(stream, err) {\n // We have tests that rely on errors being emitted\n // in the same tick, so changing this is semver major.\n // For now when you opt-in to autoDestroy we allow\n // the error to be emitted nextTick. In a future\n // semver major update we should change the default to this.\n var rState = stream._readableState;\n var wState = stream._writableState;\n if (rState && rState.autoDestroy || wState && wState.autoDestroy) stream.destroy(err);else stream.emit('error', err);\n}\n\nmodule.exports = {\n destroy: destroy,\n undestroy: undestroy,\n errorOrDestroy: errorOrDestroy\n};","'use strict';\n\nvar ERR_INVALID_OPT_VALUE = require('../../../errors').codes.ERR_INVALID_OPT_VALUE;\n\nfunction highWaterMarkFrom(options, isDuplex, duplexKey) {\n return options.highWaterMark != null ? options.highWaterMark : isDuplex ? options[duplexKey] : null;\n}\n\nfunction getHighWaterMark(state, options, duplexKey, isDuplex) {\n var hwm = highWaterMarkFrom(options, isDuplex, duplexKey);\n\n if (hwm != null) {\n if (!(isFinite(hwm) && Math.floor(hwm) === hwm) || hwm < 0) {\n var name = isDuplex ? duplexKey : 'highWaterMark';\n throw new ERR_INVALID_OPT_VALUE(name, hwm);\n }\n\n return Math.floor(hwm);\n } // Default value\n\n\n return state.objectMode ? 16 : 16 * 1024;\n}\n\nmodule.exports = {\n getHighWaterMark: getHighWaterMark\n};","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n// A bit simpler than readable streams.\n// Implement an async ._write(chunk, encoding, cb), and it'll handle all\n// the drain event emission and buffering.\n'use strict';\n\nmodule.exports = Writable;\n/* */\n\nfunction WriteReq(chunk, encoding, cb) {\n this.chunk = chunk;\n this.encoding = encoding;\n this.callback = cb;\n this.next = null;\n} // It seems a linked list but it is not\n// there will be only 2 of these for each stream\n\n\nfunction CorkedRequest(state) {\n var _this = this;\n\n this.next = null;\n this.entry = null;\n\n this.finish = function () {\n onCorkedFinish(_this, state);\n };\n}\n/* */\n\n/**/\n\n\nvar Duplex;\n/**/\n\nWritable.WritableState = WritableState;\n/**/\n\nvar internalUtil = {\n deprecate: require('util-deprecate')\n};\n/**/\n\n/**/\n\nvar Stream = require('./internal/streams/stream');\n/**/\n\n\nvar Buffer = require('buffer').Buffer;\n\nvar OurUint8Array = global.Uint8Array || function () {};\n\nfunction _uint8ArrayToBuffer(chunk) {\n return Buffer.from(chunk);\n}\n\nfunction _isUint8Array(obj) {\n return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;\n}\n\nvar destroyImpl = require('./internal/streams/destroy');\n\nvar _require = require('./internal/streams/state'),\n getHighWaterMark = _require.getHighWaterMark;\n\nvar _require$codes = require('../errors').codes,\n ERR_INVALID_ARG_TYPE = _require$codes.ERR_INVALID_ARG_TYPE,\n ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,\n ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK,\n ERR_STREAM_CANNOT_PIPE = _require$codes.ERR_STREAM_CANNOT_PIPE,\n ERR_STREAM_DESTROYED = _require$codes.ERR_STREAM_DESTROYED,\n ERR_STREAM_NULL_VALUES = _require$codes.ERR_STREAM_NULL_VALUES,\n ERR_STREAM_WRITE_AFTER_END = _require$codes.ERR_STREAM_WRITE_AFTER_END,\n ERR_UNKNOWN_ENCODING = _require$codes.ERR_UNKNOWN_ENCODING;\n\nvar errorOrDestroy = destroyImpl.errorOrDestroy;\n\nrequire('inherits')(Writable, Stream);\n\nfunction nop() {}\n\nfunction WritableState(options, stream, isDuplex) {\n Duplex = Duplex || require('./_stream_duplex');\n options = options || {}; // Duplex streams are both readable and writable, but share\n // the same options object.\n // However, some cases require setting options to different\n // values for the readable and the writable sides of the duplex stream,\n // e.g. options.readableObjectMode vs. options.writableObjectMode, etc.\n\n if (typeof isDuplex !== 'boolean') isDuplex = stream instanceof Duplex; // object stream flag to indicate whether or not this stream\n // contains buffers or objects.\n\n this.objectMode = !!options.objectMode;\n if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode; // the point at which write() starts returning false\n // Note: 0 is a valid value, means that we always return false if\n // the entire buffer is not flushed immediately on write()\n\n this.highWaterMark = getHighWaterMark(this, options, 'writableHighWaterMark', isDuplex); // if _final has been called\n\n this.finalCalled = false; // drain event flag.\n\n this.needDrain = false; // at the start of calling end()\n\n this.ending = false; // when end() has been called, and returned\n\n this.ended = false; // when 'finish' is emitted\n\n this.finished = false; // has it been destroyed\n\n this.destroyed = false; // should we decode strings into buffers before passing to _write?\n // this is here so that some node-core streams can optimize string\n // handling at a lower level.\n\n var noDecode = options.decodeStrings === false;\n this.decodeStrings = !noDecode; // Crypto is kind of old and crusty. Historically, its default string\n // encoding is 'binary' so we have to make this configurable.\n // Everything else in the universe uses 'utf8', though.\n\n this.defaultEncoding = options.defaultEncoding || 'utf8'; // not an actual buffer we keep track of, but a measurement\n // of how much we're waiting to get pushed to some underlying\n // socket or file.\n\n this.length = 0; // a flag to see when we're in the middle of a write.\n\n this.writing = false; // when true all writes will be buffered until .uncork() call\n\n this.corked = 0; // a flag to be able to tell if the onwrite cb is called immediately,\n // or on a later tick. We set this to true at first, because any\n // actions that shouldn't happen until \"later\" should generally also\n // not happen before the first write call.\n\n this.sync = true; // a flag to know if we're processing previously buffered items, which\n // may call the _write() callback in the same tick, so that we don't\n // end up in an overlapped onwrite situation.\n\n this.bufferProcessing = false; // the callback that's passed to _write(chunk,cb)\n\n this.onwrite = function (er) {\n onwrite(stream, er);\n }; // the callback that the user supplies to write(chunk,encoding,cb)\n\n\n this.writecb = null; // the amount that is being written when _write is called.\n\n this.writelen = 0;\n this.bufferedRequest = null;\n this.lastBufferedRequest = null; // number of pending user-supplied write callbacks\n // this must be 0 before 'finish' can be emitted\n\n this.pendingcb = 0; // emit prefinish if the only thing we're waiting for is _write cbs\n // This is relevant for synchronous Transform streams\n\n this.prefinished = false; // True if the error was already emitted and should not be thrown again\n\n this.errorEmitted = false; // Should close be emitted on destroy. Defaults to true.\n\n this.emitClose = options.emitClose !== false; // Should .destroy() be called after 'finish' (and potentially 'end')\n\n this.autoDestroy = !!options.autoDestroy; // count buffered requests\n\n this.bufferedRequestCount = 0; // allocate the first CorkedRequest, there is always\n // one allocated and free to use, and we maintain at most two\n\n this.corkedRequestsFree = new CorkedRequest(this);\n}\n\nWritableState.prototype.getBuffer = function getBuffer() {\n var current = this.bufferedRequest;\n var out = [];\n\n while (current) {\n out.push(current);\n current = current.next;\n }\n\n return out;\n};\n\n(function () {\n try {\n Object.defineProperty(WritableState.prototype, 'buffer', {\n get: internalUtil.deprecate(function writableStateBufferGetter() {\n return this.getBuffer();\n }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003')\n });\n } catch (_) {}\n})(); // Test _writableState for inheritance to account for Duplex streams,\n// whose prototype chain only points to Readable.\n\n\nvar realHasInstance;\n\nif (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') {\n realHasInstance = Function.prototype[Symbol.hasInstance];\n Object.defineProperty(Writable, Symbol.hasInstance, {\n value: function value(object) {\n if (realHasInstance.call(this, object)) return true;\n if (this !== Writable) return false;\n return object && object._writableState instanceof WritableState;\n }\n });\n} else {\n realHasInstance = function realHasInstance(object) {\n return object instanceof this;\n };\n}\n\nfunction Writable(options) {\n Duplex = Duplex || require('./_stream_duplex'); // Writable ctor is applied to Duplexes, too.\n // `realHasInstance` is necessary because using plain `instanceof`\n // would return false, as no `_writableState` property is attached.\n // Trying to use the custom `instanceof` for Writable here will also break the\n // Node.js LazyTransform implementation, which has a non-trivial getter for\n // `_writableState` that would lead to infinite recursion.\n // Checking for a Stream.Duplex instance is faster here instead of inside\n // the WritableState constructor, at least with V8 6.5\n\n var isDuplex = this instanceof Duplex;\n if (!isDuplex && !realHasInstance.call(Writable, this)) return new Writable(options);\n this._writableState = new WritableState(options, this, isDuplex); // legacy.\n\n this.writable = true;\n\n if (options) {\n if (typeof options.write === 'function') this._write = options.write;\n if (typeof options.writev === 'function') this._writev = options.writev;\n if (typeof options.destroy === 'function') this._destroy = options.destroy;\n if (typeof options.final === 'function') this._final = options.final;\n }\n\n Stream.call(this);\n} // Otherwise people can pipe Writable streams, which is just wrong.\n\n\nWritable.prototype.pipe = function () {\n errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE());\n};\n\nfunction writeAfterEnd(stream, cb) {\n var er = new ERR_STREAM_WRITE_AFTER_END(); // TODO: defer error events consistently everywhere, not just the cb\n\n errorOrDestroy(stream, er);\n process.nextTick(cb, er);\n} // Checks that a user-supplied chunk is valid, especially for the particular\n// mode the stream is in. Currently this means that `null` is never accepted\n// and undefined/non-string values are only allowed in object mode.\n\n\nfunction validChunk(stream, state, chunk, cb) {\n var er;\n\n if (chunk === null) {\n er = new ERR_STREAM_NULL_VALUES();\n } else if (typeof chunk !== 'string' && !state.objectMode) {\n er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk);\n }\n\n if (er) {\n errorOrDestroy(stream, er);\n process.nextTick(cb, er);\n return false;\n }\n\n return true;\n}\n\nWritable.prototype.write = function (chunk, encoding, cb) {\n var state = this._writableState;\n var ret = false;\n\n var isBuf = !state.objectMode && _isUint8Array(chunk);\n\n if (isBuf && !Buffer.isBuffer(chunk)) {\n chunk = _uint8ArrayToBuffer(chunk);\n }\n\n if (typeof encoding === 'function') {\n cb = encoding;\n encoding = null;\n }\n\n if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;\n if (typeof cb !== 'function') cb = nop;\n if (state.ending) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) {\n state.pendingcb++;\n ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);\n }\n return ret;\n};\n\nWritable.prototype.cork = function () {\n this._writableState.corked++;\n};\n\nWritable.prototype.uncork = function () {\n var state = this._writableState;\n\n if (state.corked) {\n state.corked--;\n if (!state.writing && !state.corked && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);\n }\n};\n\nWritable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {\n // node::ParseEncoding() requires lower case.\n if (typeof encoding === 'string') encoding = encoding.toLowerCase();\n if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new ERR_UNKNOWN_ENCODING(encoding);\n this._writableState.defaultEncoding = encoding;\n return this;\n};\n\nObject.defineProperty(Writable.prototype, 'writableBuffer', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._writableState && this._writableState.getBuffer();\n }\n});\n\nfunction decodeChunk(state, chunk, encoding) {\n if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {\n chunk = Buffer.from(chunk, encoding);\n }\n\n return chunk;\n}\n\nObject.defineProperty(Writable.prototype, 'writableHighWaterMark', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._writableState.highWaterMark;\n }\n}); // if we're already writing something, then just put this\n// in the queue, and wait our turn. Otherwise, call _write\n// If we return false, then we need a drain event, so set that flag.\n\nfunction writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {\n if (!isBuf) {\n var newChunk = decodeChunk(state, chunk, encoding);\n\n if (chunk !== newChunk) {\n isBuf = true;\n encoding = 'buffer';\n chunk = newChunk;\n }\n }\n\n var len = state.objectMode ? 1 : chunk.length;\n state.length += len;\n var ret = state.length < state.highWaterMark; // we must ensure that previous needDrain will not be reset to false.\n\n if (!ret) state.needDrain = true;\n\n if (state.writing || state.corked) {\n var last = state.lastBufferedRequest;\n state.lastBufferedRequest = {\n chunk: chunk,\n encoding: encoding,\n isBuf: isBuf,\n callback: cb,\n next: null\n };\n\n if (last) {\n last.next = state.lastBufferedRequest;\n } else {\n state.bufferedRequest = state.lastBufferedRequest;\n }\n\n state.bufferedRequestCount += 1;\n } else {\n doWrite(stream, state, false, len, chunk, encoding, cb);\n }\n\n return ret;\n}\n\nfunction doWrite(stream, state, writev, len, chunk, encoding, cb) {\n state.writelen = len;\n state.writecb = cb;\n state.writing = true;\n state.sync = true;\n if (state.destroyed) state.onwrite(new ERR_STREAM_DESTROYED('write'));else if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);\n state.sync = false;\n}\n\nfunction onwriteError(stream, state, sync, er, cb) {\n --state.pendingcb;\n\n if (sync) {\n // defer the callback if we are being called synchronously\n // to avoid piling up things on the stack\n process.nextTick(cb, er); // this can emit finish, and it will always happen\n // after error\n\n process.nextTick(finishMaybe, stream, state);\n stream._writableState.errorEmitted = true;\n errorOrDestroy(stream, er);\n } else {\n // the caller expect this to happen before if\n // it is async\n cb(er);\n stream._writableState.errorEmitted = true;\n errorOrDestroy(stream, er); // this can emit finish, but finish must\n // always follow error\n\n finishMaybe(stream, state);\n }\n}\n\nfunction onwriteStateUpdate(state) {\n state.writing = false;\n state.writecb = null;\n state.length -= state.writelen;\n state.writelen = 0;\n}\n\nfunction onwrite(stream, er) {\n var state = stream._writableState;\n var sync = state.sync;\n var cb = state.writecb;\n if (typeof cb !== 'function') throw new ERR_MULTIPLE_CALLBACK();\n onwriteStateUpdate(state);\n if (er) onwriteError(stream, state, sync, er, cb);else {\n // Check if we're actually ready to finish, but don't emit yet\n var finished = needFinish(state) || stream.destroyed;\n\n if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {\n clearBuffer(stream, state);\n }\n\n if (sync) {\n process.nextTick(afterWrite, stream, state, finished, cb);\n } else {\n afterWrite(stream, state, finished, cb);\n }\n }\n}\n\nfunction afterWrite(stream, state, finished, cb) {\n if (!finished) onwriteDrain(stream, state);\n state.pendingcb--;\n cb();\n finishMaybe(stream, state);\n} // Must force callback to be called on nextTick, so that we don't\n// emit 'drain' before the write() consumer gets the 'false' return\n// value, and has a chance to attach a 'drain' listener.\n\n\nfunction onwriteDrain(stream, state) {\n if (state.length === 0 && state.needDrain) {\n state.needDrain = false;\n stream.emit('drain');\n }\n} // if there's something in the buffer waiting, then process it\n\n\nfunction clearBuffer(stream, state) {\n state.bufferProcessing = true;\n var entry = state.bufferedRequest;\n\n if (stream._writev && entry && entry.next) {\n // Fast case, write everything using _writev()\n var l = state.bufferedRequestCount;\n var buffer = new Array(l);\n var holder = state.corkedRequestsFree;\n holder.entry = entry;\n var count = 0;\n var allBuffers = true;\n\n while (entry) {\n buffer[count] = entry;\n if (!entry.isBuf) allBuffers = false;\n entry = entry.next;\n count += 1;\n }\n\n buffer.allBuffers = allBuffers;\n doWrite(stream, state, true, state.length, buffer, '', holder.finish); // doWrite is almost always async, defer these to save a bit of time\n // as the hot path ends with doWrite\n\n state.pendingcb++;\n state.lastBufferedRequest = null;\n\n if (holder.next) {\n state.corkedRequestsFree = holder.next;\n holder.next = null;\n } else {\n state.corkedRequestsFree = new CorkedRequest(state);\n }\n\n state.bufferedRequestCount = 0;\n } else {\n // Slow case, write chunks one-by-one\n while (entry) {\n var chunk = entry.chunk;\n var encoding = entry.encoding;\n var cb = entry.callback;\n var len = state.objectMode ? 1 : chunk.length;\n doWrite(stream, state, false, len, chunk, encoding, cb);\n entry = entry.next;\n state.bufferedRequestCount--; // if we didn't call the onwrite immediately, then\n // it means that we need to wait until it does.\n // also, that means that the chunk and cb are currently\n // being processed, so move the buffer counter past them.\n\n if (state.writing) {\n break;\n }\n }\n\n if (entry === null) state.lastBufferedRequest = null;\n }\n\n state.bufferedRequest = entry;\n state.bufferProcessing = false;\n}\n\nWritable.prototype._write = function (chunk, encoding, cb) {\n cb(new ERR_METHOD_NOT_IMPLEMENTED('_write()'));\n};\n\nWritable.prototype._writev = null;\n\nWritable.prototype.end = function (chunk, encoding, cb) {\n var state = this._writableState;\n\n if (typeof chunk === 'function') {\n cb = chunk;\n chunk = null;\n encoding = null;\n } else if (typeof encoding === 'function') {\n cb = encoding;\n encoding = null;\n }\n\n if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); // .end() fully uncorks\n\n if (state.corked) {\n state.corked = 1;\n this.uncork();\n } // ignore unnecessary end() calls.\n\n\n if (!state.ending) endWritable(this, state, cb);\n return this;\n};\n\nObject.defineProperty(Writable.prototype, 'writableLength', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n return this._writableState.length;\n }\n});\n\nfunction needFinish(state) {\n return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;\n}\n\nfunction callFinal(stream, state) {\n stream._final(function (err) {\n state.pendingcb--;\n\n if (err) {\n errorOrDestroy(stream, err);\n }\n\n state.prefinished = true;\n stream.emit('prefinish');\n finishMaybe(stream, state);\n });\n}\n\nfunction prefinish(stream, state) {\n if (!state.prefinished && !state.finalCalled) {\n if (typeof stream._final === 'function' && !state.destroyed) {\n state.pendingcb++;\n state.finalCalled = true;\n process.nextTick(callFinal, stream, state);\n } else {\n state.prefinished = true;\n stream.emit('prefinish');\n }\n }\n}\n\nfunction finishMaybe(stream, state) {\n var need = needFinish(state);\n\n if (need) {\n prefinish(stream, state);\n\n if (state.pendingcb === 0) {\n state.finished = true;\n stream.emit('finish');\n\n if (state.autoDestroy) {\n // In case of duplex streams we need a way to detect\n // if the readable side is ready for autoDestroy as well\n var rState = stream._readableState;\n\n if (!rState || rState.autoDestroy && rState.endEmitted) {\n stream.destroy();\n }\n }\n }\n }\n\n return need;\n}\n\nfunction endWritable(stream, state, cb) {\n state.ending = true;\n finishMaybe(stream, state);\n\n if (cb) {\n if (state.finished) process.nextTick(cb);else stream.once('finish', cb);\n }\n\n state.ended = true;\n stream.writable = false;\n}\n\nfunction onCorkedFinish(corkReq, state, err) {\n var entry = corkReq.entry;\n corkReq.entry = null;\n\n while (entry) {\n var cb = entry.callback;\n state.pendingcb--;\n cb(err);\n entry = entry.next;\n } // reuse the free corkReq.\n\n\n state.corkedRequestsFree.next = corkReq;\n}\n\nObject.defineProperty(Writable.prototype, 'destroyed', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function get() {\n if (this._writableState === undefined) {\n return false;\n }\n\n return this._writableState.destroyed;\n },\n set: function set(value) {\n // we ignore the value if the stream\n // has not been initialized yet\n if (!this._writableState) {\n return;\n } // backward compatibility, the user is explicitly\n // managing destroyed\n\n\n this._writableState.destroyed = value;\n }\n});\nWritable.prototype.destroy = destroyImpl.destroy;\nWritable.prototype._undestroy = destroyImpl.undestroy;\n\nWritable.prototype._destroy = function (err, cb) {\n cb(err);\n};","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n// a transform stream is a readable/writable stream where you do\n// something with the data. Sometimes it's called a \"filter\",\n// but that's not a great name for it, since that implies a thing where\n// some bits pass through, and others are simply ignored. (That would\n// be a valid example of a transform, of course.)\n//\n// While the output is causally related to the input, it's not a\n// necessarily symmetric or synchronous transformation. For example,\n// a zlib stream might take multiple plain-text writes(), and then\n// emit a single compressed chunk some time in the future.\n//\n// Here's how this works:\n//\n// The Transform stream has all the aspects of the readable and writable\n// stream classes. When you write(chunk), that calls _write(chunk,cb)\n// internally, and returns false if there's a lot of pending writes\n// buffered up. When you call read(), that calls _read(n) until\n// there's enough pending readable data buffered up.\n//\n// In a transform stream, the written data is placed in a buffer. When\n// _read(n) is called, it transforms the queued up data, calling the\n// buffered _write cb's as it consumes chunks. If consuming a single\n// written chunk would result in multiple output chunks, then the first\n// outputted bit calls the readcb, and subsequent chunks just go into\n// the read buffer, and will cause it to emit 'readable' if necessary.\n//\n// This way, back-pressure is actually determined by the reading side,\n// since _read has to be called to start processing a new chunk. However,\n// a pathological inflate type of transform can cause excessive buffering\n// here. For example, imagine a stream where every byte of input is\n// interpreted as an integer from 0-255, and then results in that many\n// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in\n// 1kb of data being output. In this case, you could write a very small\n// amount of input, and end up with a very large amount of output. In\n// such a pathological inflating mechanism, there'd be no way to tell\n// the system to stop doing the transform. A single 4MB write could\n// cause the system to run out of memory.\n//\n// However, even in such a pathological case, only a single written chunk\n// would be consumed, and then the rest would wait (un-transformed) until\n// the results of the previous transformed chunk were consumed.\n'use strict';\n\nmodule.exports = Transform;\n\nvar _require$codes = require('../errors').codes,\n ERR_METHOD_NOT_IMPLEMENTED = _require$codes.ERR_METHOD_NOT_IMPLEMENTED,\n ERR_MULTIPLE_CALLBACK = _require$codes.ERR_MULTIPLE_CALLBACK,\n ERR_TRANSFORM_ALREADY_TRANSFORMING = _require$codes.ERR_TRANSFORM_ALREADY_TRANSFORMING,\n ERR_TRANSFORM_WITH_LENGTH_0 = _require$codes.ERR_TRANSFORM_WITH_LENGTH_0;\n\nvar Duplex = require('./_stream_duplex');\n\nrequire('inherits')(Transform, Duplex);\n\nfunction afterTransform(er, data) {\n var ts = this._transformState;\n ts.transforming = false;\n var cb = ts.writecb;\n\n if (cb === null) {\n return this.emit('error', new ERR_MULTIPLE_CALLBACK());\n }\n\n ts.writechunk = null;\n ts.writecb = null;\n if (data != null) // single equals check for both `null` and `undefined`\n this.push(data);\n cb(er);\n var rs = this._readableState;\n rs.reading = false;\n\n if (rs.needReadable || rs.length < rs.highWaterMark) {\n this._read(rs.highWaterMark);\n }\n}\n\nfunction Transform(options) {\n if (!(this instanceof Transform)) return new Transform(options);\n Duplex.call(this, options);\n this._transformState = {\n afterTransform: afterTransform.bind(this),\n needTransform: false,\n transforming: false,\n writecb: null,\n writechunk: null,\n writeencoding: null\n }; // start out asking for a readable event once data is transformed.\n\n this._readableState.needReadable = true; // we have implemented the _read method, and done the other things\n // that Readable wants before the first _read call, so unset the\n // sync guard flag.\n\n this._readableState.sync = false;\n\n if (options) {\n if (typeof options.transform === 'function') this._transform = options.transform;\n if (typeof options.flush === 'function') this._flush = options.flush;\n } // When the writable side finishes, then flush out anything remaining.\n\n\n this.on('prefinish', prefinish);\n}\n\nfunction prefinish() {\n var _this = this;\n\n if (typeof this._flush === 'function' && !this._readableState.destroyed) {\n this._flush(function (er, data) {\n done(_this, er, data);\n });\n } else {\n done(this, null, null);\n }\n}\n\nTransform.prototype.push = function (chunk, encoding) {\n this._transformState.needTransform = false;\n return Duplex.prototype.push.call(this, chunk, encoding);\n}; // This is the part where you do stuff!\n// override this function in implementation classes.\n// 'chunk' is an input chunk.\n//\n// Call `push(newChunk)` to pass along transformed output\n// to the readable side. You may call 'push' zero or more times.\n//\n// Call `cb(err)` when you are done with this chunk. If you pass\n// an error, then that'll put the hurt on the whole operation. If you\n// never call cb(), then you'll never get another chunk.\n\n\nTransform.prototype._transform = function (chunk, encoding, cb) {\n cb(new ERR_METHOD_NOT_IMPLEMENTED('_transform()'));\n};\n\nTransform.prototype._write = function (chunk, encoding, cb) {\n var ts = this._transformState;\n ts.writecb = cb;\n ts.writechunk = chunk;\n ts.writeencoding = encoding;\n\n if (!ts.transforming) {\n var rs = this._readableState;\n if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);\n }\n}; // Doesn't matter what the args are here.\n// _transform does all the work.\n// That we got here means that the readable side wants more data.\n\n\nTransform.prototype._read = function (n) {\n var ts = this._transformState;\n\n if (ts.writechunk !== null && !ts.transforming) {\n ts.transforming = true;\n\n this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);\n } else {\n // mark that we need a transform, so that any data that comes in\n // will get processed, now that we've asked for it.\n ts.needTransform = true;\n }\n};\n\nTransform.prototype._destroy = function (err, cb) {\n Duplex.prototype._destroy.call(this, err, function (err2) {\n cb(err2);\n });\n};\n\nfunction done(stream, er, data) {\n if (er) return stream.emit('error', er);\n if (data != null) // single equals check for both `null` and `undefined`\n stream.push(data); // TODO(BridgeAR): Write a test for these two error cases\n // if there's nothing in the write buffer, then that means\n // that nothing more will ever be provided\n\n if (stream._writableState.length) throw new ERR_TRANSFORM_WITH_LENGTH_0();\n if (stream._transformState.transforming) throw new ERR_TRANSFORM_ALREADY_TRANSFORMING();\n return stream.push(null);\n}","'use strict';\n\nvar utils = exports;\n\nfunction toArray(msg, enc) {\n if (Array.isArray(msg))\n return msg.slice();\n if (!msg)\n return [];\n var res = [];\n if (typeof msg !== 'string') {\n for (var i = 0; i < msg.length; i++)\n res[i] = msg[i] | 0;\n return res;\n }\n if (enc === 'hex') {\n msg = msg.replace(/[^a-z0-9]+/ig, '');\n if (msg.length % 2 !== 0)\n msg = '0' + msg;\n for (var i = 0; i < msg.length; i += 2)\n res.push(parseInt(msg[i] + msg[i + 1], 16));\n } else {\n for (var i = 0; i < msg.length; i++) {\n var c = msg.charCodeAt(i);\n var hi = c >> 8;\n var lo = c & 0xff;\n if (hi)\n res.push(hi, lo);\n else\n res.push(lo);\n }\n }\n return res;\n}\nutils.toArray = toArray;\n\nfunction zero2(word) {\n if (word.length === 1)\n return '0' + word;\n else\n return word;\n}\nutils.zero2 = zero2;\n\nfunction toHex(msg) {\n var res = '';\n for (var i = 0; i < msg.length; i++)\n res += zero2(msg[i].toString(16));\n return res;\n}\nutils.toHex = toHex;\n\nutils.encode = function encode(arr, enc) {\n if (enc === 'hex')\n return toHex(arr);\n else\n return arr;\n};\n","'use strict';\n\nvar curve = exports;\n\ncurve.base = require('./base');\ncurve.short = require('./short');\ncurve.mont = require('./mont');\ncurve.edwards = require('./edwards');\n","'use strict';\n\nvar utils = require('../utils');\nvar rotr32 = utils.rotr32;\n\nfunction ft_1(s, x, y, z) {\n if (s === 0)\n return ch32(x, y, z);\n if (s === 1 || s === 3)\n return p32(x, y, z);\n if (s === 2)\n return maj32(x, y, z);\n}\nexports.ft_1 = ft_1;\n\nfunction ch32(x, y, z) {\n return (x & y) ^ ((~x) & z);\n}\nexports.ch32 = ch32;\n\nfunction maj32(x, y, z) {\n return (x & y) ^ (x & z) ^ (y & z);\n}\nexports.maj32 = maj32;\n\nfunction p32(x, y, z) {\n return x ^ y ^ z;\n}\nexports.p32 = p32;\n\nfunction s0_256(x) {\n return rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22);\n}\nexports.s0_256 = s0_256;\n\nfunction s1_256(x) {\n return rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25);\n}\nexports.s1_256 = s1_256;\n\nfunction g0_256(x) {\n return rotr32(x, 7) ^ rotr32(x, 18) ^ (x >>> 3);\n}\nexports.g0_256 = g0_256;\n\nfunction g1_256(x) {\n return rotr32(x, 17) ^ rotr32(x, 19) ^ (x >>> 10);\n}\nexports.g1_256 = g1_256;\n","'use strict';\n\nvar utils = require('../utils');\nvar common = require('../common');\nvar shaCommon = require('./common');\nvar assert = require('minimalistic-assert');\n\nvar sum32 = utils.sum32;\nvar sum32_4 = utils.sum32_4;\nvar sum32_5 = utils.sum32_5;\nvar ch32 = shaCommon.ch32;\nvar maj32 = shaCommon.maj32;\nvar s0_256 = shaCommon.s0_256;\nvar s1_256 = shaCommon.s1_256;\nvar g0_256 = shaCommon.g0_256;\nvar g1_256 = shaCommon.g1_256;\n\nvar BlockHash = common.BlockHash;\n\nvar sha256_K = [\n 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,\n 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,\n 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,\n 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,\n 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,\n 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,\n 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,\n 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,\n 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,\n 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,\n 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,\n 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,\n 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,\n 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,\n 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,\n 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2\n];\n\nfunction SHA256() {\n if (!(this instanceof SHA256))\n return new SHA256();\n\n BlockHash.call(this);\n this.h = [\n 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,\n 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19\n ];\n this.k = sha256_K;\n this.W = new Array(64);\n}\nutils.inherits(SHA256, BlockHash);\nmodule.exports = SHA256;\n\nSHA256.blockSize = 512;\nSHA256.outSize = 256;\nSHA256.hmacStrength = 192;\nSHA256.padLength = 64;\n\nSHA256.prototype._update = function _update(msg, start) {\n var W = this.W;\n\n for (var i = 0; i < 16; i++)\n W[i] = msg[start + i];\n for (; i < W.length; i++)\n W[i] = sum32_4(g1_256(W[i - 2]), W[i - 7], g0_256(W[i - 15]), W[i - 16]);\n\n var a = this.h[0];\n var b = this.h[1];\n var c = this.h[2];\n var d = this.h[3];\n var e = this.h[4];\n var f = this.h[5];\n var g = this.h[6];\n var h = this.h[7];\n\n assert(this.k.length === W.length);\n for (i = 0; i < W.length; i++) {\n var T1 = sum32_5(h, s1_256(e), ch32(e, f, g), this.k[i], W[i]);\n var T2 = sum32(s0_256(a), maj32(a, b, c));\n h = g;\n g = f;\n f = e;\n e = sum32(d, T1);\n d = c;\n c = b;\n b = a;\n a = sum32(T1, T2);\n }\n\n this.h[0] = sum32(this.h[0], a);\n this.h[1] = sum32(this.h[1], b);\n this.h[2] = sum32(this.h[2], c);\n this.h[3] = sum32(this.h[3], d);\n this.h[4] = sum32(this.h[4], e);\n this.h[5] = sum32(this.h[5], f);\n this.h[6] = sum32(this.h[6], g);\n this.h[7] = sum32(this.h[7], h);\n};\n\nSHA256.prototype._digest = function digest(enc) {\n if (enc === 'hex')\n return utils.toHex32(this.h, 'big');\n else\n return utils.split32(this.h, 'big');\n};\n","'use strict';\n\nvar utils = require('../utils');\nvar common = require('../common');\nvar assert = require('minimalistic-assert');\n\nvar rotr64_hi = utils.rotr64_hi;\nvar rotr64_lo = utils.rotr64_lo;\nvar shr64_hi = utils.shr64_hi;\nvar shr64_lo = utils.shr64_lo;\nvar sum64 = utils.sum64;\nvar sum64_hi = utils.sum64_hi;\nvar sum64_lo = utils.sum64_lo;\nvar sum64_4_hi = utils.sum64_4_hi;\nvar sum64_4_lo = utils.sum64_4_lo;\nvar sum64_5_hi = utils.sum64_5_hi;\nvar sum64_5_lo = utils.sum64_5_lo;\n\nvar BlockHash = common.BlockHash;\n\nvar sha512_K = [\n 0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,\n 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,\n 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,\n 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,\n 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,\n 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,\n 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,\n 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,\n 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,\n 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,\n 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,\n 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,\n 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,\n 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,\n 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,\n 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,\n 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,\n 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,\n 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,\n 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,\n 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,\n 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,\n 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,\n 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,\n 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,\n 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,\n 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,\n 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,\n 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,\n 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,\n 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,\n 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,\n 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,\n 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,\n 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,\n 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,\n 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,\n 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,\n 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,\n 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817\n];\n\nfunction SHA512() {\n if (!(this instanceof SHA512))\n return new SHA512();\n\n BlockHash.call(this);\n this.h = [\n 0x6a09e667, 0xf3bcc908,\n 0xbb67ae85, 0x84caa73b,\n 0x3c6ef372, 0xfe94f82b,\n 0xa54ff53a, 0x5f1d36f1,\n 0x510e527f, 0xade682d1,\n 0x9b05688c, 0x2b3e6c1f,\n 0x1f83d9ab, 0xfb41bd6b,\n 0x5be0cd19, 0x137e2179 ];\n this.k = sha512_K;\n this.W = new Array(160);\n}\nutils.inherits(SHA512, BlockHash);\nmodule.exports = SHA512;\n\nSHA512.blockSize = 1024;\nSHA512.outSize = 512;\nSHA512.hmacStrength = 192;\nSHA512.padLength = 128;\n\nSHA512.prototype._prepareBlock = function _prepareBlock(msg, start) {\n var W = this.W;\n\n // 32 x 32bit words\n for (var i = 0; i < 32; i++)\n W[i] = msg[start + i];\n for (; i < W.length; i += 2) {\n var c0_hi = g1_512_hi(W[i - 4], W[i - 3]); // i - 2\n var c0_lo = g1_512_lo(W[i - 4], W[i - 3]);\n var c1_hi = W[i - 14]; // i - 7\n var c1_lo = W[i - 13];\n var c2_hi = g0_512_hi(W[i - 30], W[i - 29]); // i - 15\n var c2_lo = g0_512_lo(W[i - 30], W[i - 29]);\n var c3_hi = W[i - 32]; // i - 16\n var c3_lo = W[i - 31];\n\n W[i] = sum64_4_hi(\n c0_hi, c0_lo,\n c1_hi, c1_lo,\n c2_hi, c2_lo,\n c3_hi, c3_lo);\n W[i + 1] = sum64_4_lo(\n c0_hi, c0_lo,\n c1_hi, c1_lo,\n c2_hi, c2_lo,\n c3_hi, c3_lo);\n }\n};\n\nSHA512.prototype._update = function _update(msg, start) {\n this._prepareBlock(msg, start);\n\n var W = this.W;\n\n var ah = this.h[0];\n var al = this.h[1];\n var bh = this.h[2];\n var bl = this.h[3];\n var ch = this.h[4];\n var cl = this.h[5];\n var dh = this.h[6];\n var dl = this.h[7];\n var eh = this.h[8];\n var el = this.h[9];\n var fh = this.h[10];\n var fl = this.h[11];\n var gh = this.h[12];\n var gl = this.h[13];\n var hh = this.h[14];\n var hl = this.h[15];\n\n assert(this.k.length === W.length);\n for (var i = 0; i < W.length; i += 2) {\n var c0_hi = hh;\n var c0_lo = hl;\n var c1_hi = s1_512_hi(eh, el);\n var c1_lo = s1_512_lo(eh, el);\n var c2_hi = ch64_hi(eh, el, fh, fl, gh, gl);\n var c2_lo = ch64_lo(eh, el, fh, fl, gh, gl);\n var c3_hi = this.k[i];\n var c3_lo = this.k[i + 1];\n var c4_hi = W[i];\n var c4_lo = W[i + 1];\n\n var T1_hi = sum64_5_hi(\n c0_hi, c0_lo,\n c1_hi, c1_lo,\n c2_hi, c2_lo,\n c3_hi, c3_lo,\n c4_hi, c4_lo);\n var T1_lo = sum64_5_lo(\n c0_hi, c0_lo,\n c1_hi, c1_lo,\n c2_hi, c2_lo,\n c3_hi, c3_lo,\n c4_hi, c4_lo);\n\n c0_hi = s0_512_hi(ah, al);\n c0_lo = s0_512_lo(ah, al);\n c1_hi = maj64_hi(ah, al, bh, bl, ch, cl);\n c1_lo = maj64_lo(ah, al, bh, bl, ch, cl);\n\n var T2_hi = sum64_hi(c0_hi, c0_lo, c1_hi, c1_lo);\n var T2_lo = sum64_lo(c0_hi, c0_lo, c1_hi, c1_lo);\n\n hh = gh;\n hl = gl;\n\n gh = fh;\n gl = fl;\n\n fh = eh;\n fl = el;\n\n eh = sum64_hi(dh, dl, T1_hi, T1_lo);\n el = sum64_lo(dl, dl, T1_hi, T1_lo);\n\n dh = ch;\n dl = cl;\n\n ch = bh;\n cl = bl;\n\n bh = ah;\n bl = al;\n\n ah = sum64_hi(T1_hi, T1_lo, T2_hi, T2_lo);\n al = sum64_lo(T1_hi, T1_lo, T2_hi, T2_lo);\n }\n\n sum64(this.h, 0, ah, al);\n sum64(this.h, 2, bh, bl);\n sum64(this.h, 4, ch, cl);\n sum64(this.h, 6, dh, dl);\n sum64(this.h, 8, eh, el);\n sum64(this.h, 10, fh, fl);\n sum64(this.h, 12, gh, gl);\n sum64(this.h, 14, hh, hl);\n};\n\nSHA512.prototype._digest = function digest(enc) {\n if (enc === 'hex')\n return utils.toHex32(this.h, 'big');\n else\n return utils.split32(this.h, 'big');\n};\n\nfunction ch64_hi(xh, xl, yh, yl, zh) {\n var r = (xh & yh) ^ ((~xh) & zh);\n if (r < 0)\n r += 0x100000000;\n return r;\n}\n\nfunction ch64_lo(xh, xl, yh, yl, zh, zl) {\n var r = (xl & yl) ^ ((~xl) & zl);\n if (r < 0)\n r += 0x100000000;\n return r;\n}\n\nfunction maj64_hi(xh, xl, yh, yl, zh) {\n var r = (xh & yh) ^ (xh & zh) ^ (yh & zh);\n if (r < 0)\n r += 0x100000000;\n return r;\n}\n\nfunction maj64_lo(xh, xl, yh, yl, zh, zl) {\n var r = (xl & yl) ^ (xl & zl) ^ (yl & zl);\n if (r < 0)\n r += 0x100000000;\n return r;\n}\n\nfunction s0_512_hi(xh, xl) {\n var c0_hi = rotr64_hi(xh, xl, 28);\n var c1_hi = rotr64_hi(xl, xh, 2); // 34\n var c2_hi = rotr64_hi(xl, xh, 7); // 39\n\n var r = c0_hi ^ c1_hi ^ c2_hi;\n if (r < 0)\n r += 0x100000000;\n return r;\n}\n\nfunction s0_512_lo(xh, xl) {\n var c0_lo = rotr64_lo(xh, xl, 28);\n var c1_lo = rotr64_lo(xl, xh, 2); // 34\n var c2_lo = rotr64_lo(xl, xh, 7); // 39\n\n var r = c0_lo ^ c1_lo ^ c2_lo;\n if (r < 0)\n r += 0x100000000;\n return r;\n}\n\nfunction s1_512_hi(xh, xl) {\n var c0_hi = rotr64_hi(xh, xl, 14);\n var c1_hi = rotr64_hi(xh, xl, 18);\n var c2_hi = rotr64_hi(xl, xh, 9); // 41\n\n var r = c0_hi ^ c1_hi ^ c2_hi;\n if (r < 0)\n r += 0x100000000;\n return r;\n}\n\nfunction s1_512_lo(xh, xl) {\n var c0_lo = rotr64_lo(xh, xl, 14);\n var c1_lo = rotr64_lo(xh, xl, 18);\n var c2_lo = rotr64_lo(xl, xh, 9); // 41\n\n var r = c0_lo ^ c1_lo ^ c2_lo;\n if (r < 0)\n r += 0x100000000;\n return r;\n}\n\nfunction g0_512_hi(xh, xl) {\n var c0_hi = rotr64_hi(xh, xl, 1);\n var c1_hi = rotr64_hi(xh, xl, 8);\n var c2_hi = shr64_hi(xh, xl, 7);\n\n var r = c0_hi ^ c1_hi ^ c2_hi;\n if (r < 0)\n r += 0x100000000;\n return r;\n}\n\nfunction g0_512_lo(xh, xl) {\n var c0_lo = rotr64_lo(xh, xl, 1);\n var c1_lo = rotr64_lo(xh, xl, 8);\n var c2_lo = shr64_lo(xh, xl, 7);\n\n var r = c0_lo ^ c1_lo ^ c2_lo;\n if (r < 0)\n r += 0x100000000;\n return r;\n}\n\nfunction g1_512_hi(xh, xl) {\n var c0_hi = rotr64_hi(xh, xl, 19);\n var c1_hi = rotr64_hi(xl, xh, 29); // 61\n var c2_hi = shr64_hi(xh, xl, 6);\n\n var r = c0_hi ^ c1_hi ^ c2_hi;\n if (r < 0)\n r += 0x100000000;\n return r;\n}\n\nfunction g1_512_lo(xh, xl) {\n var c0_lo = rotr64_lo(xh, xl, 19);\n var c1_lo = rotr64_lo(xl, xh, 29); // 61\n var c2_lo = shr64_lo(xh, xl, 6);\n\n var r = c0_lo ^ c1_lo ^ c2_lo;\n if (r < 0)\n r += 0x100000000;\n return r;\n}\n","(function (module, exports) {\n 'use strict';\n\n // Utils\n function assert (val, msg) {\n if (!val) throw new Error(msg || 'Assertion failed');\n }\n\n // Could use `inherits` module, but don't want to move from single file\n // architecture yet.\n function inherits (ctor, superCtor) {\n ctor.super_ = superCtor;\n var TempCtor = function () {};\n TempCtor.prototype = superCtor.prototype;\n ctor.prototype = new TempCtor();\n ctor.prototype.constructor = ctor;\n }\n\n // BN\n\n function BN (number, base, endian) {\n if (BN.isBN(number)) {\n return number;\n }\n\n this.negative = 0;\n this.words = null;\n this.length = 0;\n\n // Reduction context\n this.red = null;\n\n if (number !== null) {\n if (base === 'le' || base === 'be') {\n endian = base;\n base = 10;\n }\n\n this._init(number || 0, base || 10, endian || 'be');\n }\n }\n if (typeof module === 'object') {\n module.exports = BN;\n } else {\n exports.BN = BN;\n }\n\n BN.BN = BN;\n BN.wordSize = 26;\n\n var Buffer;\n try {\n Buffer = require('buffer').Buffer;\n } catch (e) {\n }\n\n BN.isBN = function isBN (num) {\n if (num instanceof BN) {\n return true;\n }\n\n return num !== null && typeof num === 'object' &&\n num.constructor.wordSize === BN.wordSize && Array.isArray(num.words);\n };\n\n BN.max = function max (left, right) {\n if (left.cmp(right) > 0) return left;\n return right;\n };\n\n BN.min = function min (left, right) {\n if (left.cmp(right) < 0) return left;\n return right;\n };\n\n BN.prototype._init = function init (number, base, endian) {\n if (typeof number === 'number') {\n return this._initNumber(number, base, endian);\n }\n\n if (typeof number === 'object') {\n return this._initArray(number, base, endian);\n }\n\n if (base === 'hex') {\n base = 16;\n }\n assert(base === (base | 0) && base >= 2 && base <= 36);\n\n number = number.toString().replace(/\\s+/g, '');\n var start = 0;\n if (number[0] === '-') {\n start++;\n }\n\n if (base === 16) {\n this._parseHex(number, start);\n } else {\n this._parseBase(number, base, start);\n }\n\n if (number[0] === '-') {\n this.negative = 1;\n }\n\n this._strip();\n\n if (endian !== 'le') return;\n\n this._initArray(this.toArray(), base, endian);\n };\n\n BN.prototype._initNumber = function _initNumber (number, base, endian) {\n if (number < 0) {\n this.negative = 1;\n number = -number;\n }\n if (number < 0x4000000) {\n this.words = [number & 0x3ffffff];\n this.length = 1;\n } else if (number < 0x10000000000000) {\n this.words = [\n number & 0x3ffffff,\n (number / 0x4000000) & 0x3ffffff\n ];\n this.length = 2;\n } else {\n assert(number < 0x20000000000000); // 2 ^ 53 (unsafe)\n this.words = [\n number & 0x3ffffff,\n (number / 0x4000000) & 0x3ffffff,\n 1\n ];\n this.length = 3;\n }\n\n if (endian !== 'le') return;\n\n // Reverse the bytes\n this._initArray(this.toArray(), base, endian);\n };\n\n BN.prototype._initArray = function _initArray (number, base, endian) {\n // Perhaps a Uint8Array\n assert(typeof number.length === 'number');\n if (number.length <= 0) {\n this.words = [0];\n this.length = 1;\n return this;\n }\n\n this.length = Math.ceil(number.length / 3);\n this.words = new Array(this.length);\n for (var i = 0; i < this.length; i++) {\n this.words[i] = 0;\n }\n\n var j, w;\n var off = 0;\n if (endian === 'be') {\n for (i = number.length - 1, j = 0; i >= 0; i -= 3) {\n w = number[i] | (number[i - 1] << 8) | (number[i - 2] << 16);\n this.words[j] |= (w << off) & 0x3ffffff;\n this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;\n off += 24;\n if (off >= 26) {\n off -= 26;\n j++;\n }\n }\n } else if (endian === 'le') {\n for (i = 0, j = 0; i < number.length; i += 3) {\n w = number[i] | (number[i + 1] << 8) | (number[i + 2] << 16);\n this.words[j] |= (w << off) & 0x3ffffff;\n this.words[j + 1] = (w >>> (26 - off)) & 0x3ffffff;\n off += 24;\n if (off >= 26) {\n off -= 26;\n j++;\n }\n }\n }\n return this._strip();\n };\n\n function parseHex (str, start, end) {\n var r = 0;\n var len = Math.min(str.length, end);\n var z = 0;\n for (var i = start; i < len; i++) {\n var c = str.charCodeAt(i) - 48;\n\n r <<= 4;\n\n var b;\n\n // 'a' - 'f'\n if (c >= 49 && c <= 54) {\n b = c - 49 + 0xa;\n\n // 'A' - 'F'\n } else if (c >= 17 && c <= 22) {\n b = c - 17 + 0xa;\n\n // '0' - '9'\n } else {\n b = c;\n }\n\n r |= b;\n z |= b;\n }\n\n assert(!(z & 0xf0), 'Invalid character in ' + str);\n return r;\n }\n\n BN.prototype._parseHex = function _parseHex (number, start) {\n // Create possibly bigger array to ensure that it fits the number\n this.length = Math.ceil((number.length - start) / 6);\n this.words = new Array(this.length);\n for (var i = 0; i < this.length; i++) {\n this.words[i] = 0;\n }\n\n var j, w;\n // Scan 24-bit chunks and add them to the number\n var off = 0;\n for (i = number.length - 6, j = 0; i >= start; i -= 6) {\n w = parseHex(number, i, i + 6);\n this.words[j] |= (w << off) & 0x3ffffff;\n // NOTE: `0x3fffff` is intentional here, 26bits max shift + 24bit hex limb\n this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;\n off += 24;\n if (off >= 26) {\n off -= 26;\n j++;\n }\n }\n if (i + 6 !== start) {\n w = parseHex(number, start, i + 6);\n this.words[j] |= (w << off) & 0x3ffffff;\n this.words[j + 1] |= w >>> (26 - off) & 0x3fffff;\n }\n this._strip();\n };\n\n function parseBase (str, start, end, mul) {\n var r = 0;\n var b = 0;\n var len = Math.min(str.length, end);\n for (var i = start; i < len; i++) {\n var c = str.charCodeAt(i) - 48;\n\n r *= mul;\n\n // 'a'\n if (c >= 49) {\n b = c - 49 + 0xa;\n\n // 'A'\n } else if (c >= 17) {\n b = c - 17 + 0xa;\n\n // '0' - '9'\n } else {\n b = c;\n }\n assert(c >= 0 && b < mul, 'Invalid character');\n r += b;\n }\n return r;\n }\n\n BN.prototype._parseBase = function _parseBase (number, base, start) {\n // Initialize as zero\n this.words = [0];\n this.length = 1;\n\n // Find length of limb in base\n for (var limbLen = 0, limbPow = 1; limbPow <= 0x3ffffff; limbPow *= base) {\n limbLen++;\n }\n limbLen--;\n limbPow = (limbPow / base) | 0;\n\n var total = number.length - start;\n var mod = total % limbLen;\n var end = Math.min(total, total - mod) + start;\n\n var word = 0;\n for (var i = start; i < end; i += limbLen) {\n word = parseBase(number, i, i + limbLen, base);\n\n this.imuln(limbPow);\n if (this.words[0] + word < 0x4000000) {\n this.words[0] += word;\n } else {\n this._iaddn(word);\n }\n }\n\n if (mod !== 0) {\n var pow = 1;\n word = parseBase(number, i, number.length, base);\n\n for (i = 0; i < mod; i++) {\n pow *= base;\n }\n\n this.imuln(pow);\n if (this.words[0] + word < 0x4000000) {\n this.words[0] += word;\n } else {\n this._iaddn(word);\n }\n }\n };\n\n BN.prototype.copy = function copy (dest) {\n dest.words = new Array(this.length);\n for (var i = 0; i < this.length; i++) {\n dest.words[i] = this.words[i];\n }\n dest.length = this.length;\n dest.negative = this.negative;\n dest.red = this.red;\n };\n\n function move (dest, src) {\n dest.words = src.words;\n dest.length = src.length;\n dest.negative = src.negative;\n dest.red = src.red;\n }\n\n BN.prototype._move = function _move (dest) {\n move(dest, this);\n };\n\n BN.prototype.clone = function clone () {\n var r = new BN(null);\n this.copy(r);\n return r;\n };\n\n BN.prototype._expand = function _expand (size) {\n while (this.length < size) {\n this.words[this.length++] = 0;\n }\n return this;\n };\n\n // Remove leading `0` from `this`\n BN.prototype._strip = function strip () {\n while (this.length > 1 && this.words[this.length - 1] === 0) {\n this.length--;\n }\n return this._normSign();\n };\n\n BN.prototype._normSign = function _normSign () {\n // -0 = 0\n if (this.length === 1 && this.words[0] === 0) {\n this.negative = 0;\n }\n return this;\n };\n\n // Check Symbol.for because not everywhere where Symbol defined\n // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#Browser_compatibility\n if (typeof Symbol !== 'undefined' && typeof Symbol.for === 'function') {\n BN.prototype[Symbol.for('nodejs.util.inspect.custom')] = inspect;\n } else {\n BN.prototype.inspect = inspect;\n }\n\n function inspect () {\n return (this.red ? '';\n }\n\n /*\n\n var zeros = [];\n var groupSizes = [];\n var groupBases = [];\n\n var s = '';\n var i = -1;\n while (++i < BN.wordSize) {\n zeros[i] = s;\n s += '0';\n }\n groupSizes[0] = 0;\n groupSizes[1] = 0;\n groupBases[0] = 0;\n groupBases[1] = 0;\n var base = 2 - 1;\n while (++base < 36 + 1) {\n var groupSize = 0;\n var groupBase = 1;\n while (groupBase < (1 << BN.wordSize) / base) {\n groupBase *= base;\n groupSize += 1;\n }\n groupSizes[base] = groupSize;\n groupBases[base] = groupBase;\n }\n\n */\n\n var zeros = [\n '',\n '0',\n '00',\n '000',\n '0000',\n '00000',\n '000000',\n '0000000',\n '00000000',\n '000000000',\n '0000000000',\n '00000000000',\n '000000000000',\n '0000000000000',\n '00000000000000',\n '000000000000000',\n '0000000000000000',\n '00000000000000000',\n '000000000000000000',\n '0000000000000000000',\n '00000000000000000000',\n '000000000000000000000',\n '0000000000000000000000',\n '00000000000000000000000',\n '000000000000000000000000',\n '0000000000000000000000000'\n ];\n\n var groupSizes = [\n 0, 0,\n 25, 16, 12, 11, 10, 9, 8,\n 8, 7, 7, 7, 7, 6, 6,\n 6, 6, 6, 6, 6, 5, 5,\n 5, 5, 5, 5, 5, 5, 5,\n 5, 5, 5, 5, 5, 5, 5\n ];\n\n var groupBases = [\n 0, 0,\n 33554432, 43046721, 16777216, 48828125, 60466176, 40353607, 16777216,\n 43046721, 10000000, 19487171, 35831808, 62748517, 7529536, 11390625,\n 16777216, 24137569, 34012224, 47045881, 64000000, 4084101, 5153632,\n 6436343, 7962624, 9765625, 11881376, 14348907, 17210368, 20511149,\n 24300000, 28629151, 33554432, 39135393, 45435424, 52521875, 60466176\n ];\n\n BN.prototype.toString = function toString (base, padding) {\n base = base || 10;\n padding = padding | 0 || 1;\n\n var out;\n if (base === 16 || base === 'hex') {\n out = '';\n var off = 0;\n var carry = 0;\n for (var i = 0; i < this.length; i++) {\n var w = this.words[i];\n var word = (((w << off) | carry) & 0xffffff).toString(16);\n carry = (w >>> (24 - off)) & 0xffffff;\n if (carry !== 0 || i !== this.length - 1) {\n out = zeros[6 - word.length] + word + out;\n } else {\n out = word + out;\n }\n off += 2;\n if (off >= 26) {\n off -= 26;\n i--;\n }\n }\n if (carry !== 0) {\n out = carry.toString(16) + out;\n }\n while (out.length % padding !== 0) {\n out = '0' + out;\n }\n if (this.negative !== 0) {\n out = '-' + out;\n }\n return out;\n }\n\n if (base === (base | 0) && base >= 2 && base <= 36) {\n // var groupSize = Math.floor(BN.wordSize * Math.LN2 / Math.log(base));\n var groupSize = groupSizes[base];\n // var groupBase = Math.pow(base, groupSize);\n var groupBase = groupBases[base];\n out = '';\n var c = this.clone();\n c.negative = 0;\n while (!c.isZero()) {\n var r = c.modrn(groupBase).toString(base);\n c = c.idivn(groupBase);\n\n if (!c.isZero()) {\n out = zeros[groupSize - r.length] + r + out;\n } else {\n out = r + out;\n }\n }\n if (this.isZero()) {\n out = '0' + out;\n }\n while (out.length % padding !== 0) {\n out = '0' + out;\n }\n if (this.negative !== 0) {\n out = '-' + out;\n }\n return out;\n }\n\n assert(false, 'Base should be between 2 and 36');\n };\n\n BN.prototype.toNumber = function toNumber () {\n var ret = this.words[0];\n if (this.length === 2) {\n ret += this.words[1] * 0x4000000;\n } else if (this.length === 3 && this.words[2] === 0x01) {\n // NOTE: at this stage it is known that the top bit is set\n ret += 0x10000000000000 + (this.words[1] * 0x4000000);\n } else if (this.length > 2) {\n assert(false, 'Number can only safely store up to 53 bits');\n }\n return (this.negative !== 0) ? -ret : ret;\n };\n\n BN.prototype.toJSON = function toJSON () {\n return this.toString(16, 2);\n };\n\n if (Buffer) {\n BN.prototype.toBuffer = function toBuffer (endian, length) {\n return this.toArrayLike(Buffer, endian, length);\n };\n }\n\n BN.prototype.toArray = function toArray (endian, length) {\n return this.toArrayLike(Array, endian, length);\n };\n\n var allocate = function allocate (ArrayType, size) {\n if (ArrayType.allocUnsafe) {\n return ArrayType.allocUnsafe(size);\n }\n return new ArrayType(size);\n };\n\n BN.prototype.toArrayLike = function toArrayLike (ArrayType, endian, length) {\n this._strip();\n\n var byteLength = this.byteLength();\n var reqLength = length || Math.max(1, byteLength);\n assert(byteLength <= reqLength, 'byte array longer than desired length');\n assert(reqLength > 0, 'Requested array length <= 0');\n\n var res = allocate(ArrayType, reqLength);\n var postfix = endian === 'le' ? 'LE' : 'BE';\n this['_toArrayLike' + postfix](res, byteLength);\n return res;\n };\n\n BN.prototype._toArrayLikeLE = function _toArrayLikeLE (res, byteLength) {\n var position = 0;\n var carry = 0;\n\n for (var i = 0, shift = 0; i < this.length; i++) {\n var word = (this.words[i] << shift) | carry;\n\n res[position++] = word & 0xff;\n if (position < res.length) {\n res[position++] = (word >> 8) & 0xff;\n }\n if (position < res.length) {\n res[position++] = (word >> 16) & 0xff;\n }\n\n if (shift === 6) {\n if (position < res.length) {\n res[position++] = (word >> 24) & 0xff;\n }\n carry = 0;\n shift = 0;\n } else {\n carry = word >>> 24;\n shift += 2;\n }\n }\n\n if (position < res.length) {\n res[position++] = carry;\n\n while (position < res.length) {\n res[position++] = 0;\n }\n }\n };\n\n BN.prototype._toArrayLikeBE = function _toArrayLikeBE (res, byteLength) {\n var position = res.length - 1;\n var carry = 0;\n\n for (var i = 0, shift = 0; i < this.length; i++) {\n var word = (this.words[i] << shift) | carry;\n\n res[position--] = word & 0xff;\n if (position >= 0) {\n res[position--] = (word >> 8) & 0xff;\n }\n if (position >= 0) {\n res[position--] = (word >> 16) & 0xff;\n }\n\n if (shift === 6) {\n if (position >= 0) {\n res[position--] = (word >> 24) & 0xff;\n }\n carry = 0;\n shift = 0;\n } else {\n carry = word >>> 24;\n shift += 2;\n }\n }\n\n if (position >= 0) {\n res[position--] = carry;\n\n while (position >= 0) {\n res[position--] = 0;\n }\n }\n };\n\n if (Math.clz32) {\n BN.prototype._countBits = function _countBits (w) {\n return 32 - Math.clz32(w);\n };\n } else {\n BN.prototype._countBits = function _countBits (w) {\n var t = w;\n var r = 0;\n if (t >= 0x1000) {\n r += 13;\n t >>>= 13;\n }\n if (t >= 0x40) {\n r += 7;\n t >>>= 7;\n }\n if (t >= 0x8) {\n r += 4;\n t >>>= 4;\n }\n if (t >= 0x02) {\n r += 2;\n t >>>= 2;\n }\n return r + t;\n };\n }\n\n BN.prototype._zeroBits = function _zeroBits (w) {\n // Short-cut\n if (w === 0) return 26;\n\n var t = w;\n var r = 0;\n if ((t & 0x1fff) === 0) {\n r += 13;\n t >>>= 13;\n }\n if ((t & 0x7f) === 0) {\n r += 7;\n t >>>= 7;\n }\n if ((t & 0xf) === 0) {\n r += 4;\n t >>>= 4;\n }\n if ((t & 0x3) === 0) {\n r += 2;\n t >>>= 2;\n }\n if ((t & 0x1) === 0) {\n r++;\n }\n return r;\n };\n\n // Return number of used bits in a BN\n BN.prototype.bitLength = function bitLength () {\n var w = this.words[this.length - 1];\n var hi = this._countBits(w);\n return (this.length - 1) * 26 + hi;\n };\n\n function toBitArray (num) {\n var w = new Array(num.bitLength());\n\n for (var bit = 0; bit < w.length; bit++) {\n var off = (bit / 26) | 0;\n var wbit = bit % 26;\n\n w[bit] = (num.words[off] >>> wbit) & 0x01;\n }\n\n return w;\n }\n\n // Number of trailing zero bits\n BN.prototype.zeroBits = function zeroBits () {\n if (this.isZero()) return 0;\n\n var r = 0;\n for (var i = 0; i < this.length; i++) {\n var b = this._zeroBits(this.words[i]);\n r += b;\n if (b !== 26) break;\n }\n return r;\n };\n\n BN.prototype.byteLength = function byteLength () {\n return Math.ceil(this.bitLength() / 8);\n };\n\n BN.prototype.toTwos = function toTwos (width) {\n if (this.negative !== 0) {\n return this.abs().inotn(width).iaddn(1);\n }\n return this.clone();\n };\n\n BN.prototype.fromTwos = function fromTwos (width) {\n if (this.testn(width - 1)) {\n return this.notn(width).iaddn(1).ineg();\n }\n return this.clone();\n };\n\n BN.prototype.isNeg = function isNeg () {\n return this.negative !== 0;\n };\n\n // Return negative clone of `this`\n BN.prototype.neg = function neg () {\n return this.clone().ineg();\n };\n\n BN.prototype.ineg = function ineg () {\n if (!this.isZero()) {\n this.negative ^= 1;\n }\n\n return this;\n };\n\n // Or `num` with `this` in-place\n BN.prototype.iuor = function iuor (num) {\n while (this.length < num.length) {\n this.words[this.length++] = 0;\n }\n\n for (var i = 0; i < num.length; i++) {\n this.words[i] = this.words[i] | num.words[i];\n }\n\n return this._strip();\n };\n\n BN.prototype.ior = function ior (num) {\n assert((this.negative | num.negative) === 0);\n return this.iuor(num);\n };\n\n // Or `num` with `this`\n BN.prototype.or = function or (num) {\n if (this.length > num.length) return this.clone().ior(num);\n return num.clone().ior(this);\n };\n\n BN.prototype.uor = function uor (num) {\n if (this.length > num.length) return this.clone().iuor(num);\n return num.clone().iuor(this);\n };\n\n // And `num` with `this` in-place\n BN.prototype.iuand = function iuand (num) {\n // b = min-length(num, this)\n var b;\n if (this.length > num.length) {\n b = num;\n } else {\n b = this;\n }\n\n for (var i = 0; i < b.length; i++) {\n this.words[i] = this.words[i] & num.words[i];\n }\n\n this.length = b.length;\n\n return this._strip();\n };\n\n BN.prototype.iand = function iand (num) {\n assert((this.negative | num.negative) === 0);\n return this.iuand(num);\n };\n\n // And `num` with `this`\n BN.prototype.and = function and (num) {\n if (this.length > num.length) return this.clone().iand(num);\n return num.clone().iand(this);\n };\n\n BN.prototype.uand = function uand (num) {\n if (this.length > num.length) return this.clone().iuand(num);\n return num.clone().iuand(this);\n };\n\n // Xor `num` with `this` in-place\n BN.prototype.iuxor = function iuxor (num) {\n // a.length > b.length\n var a;\n var b;\n if (this.length > num.length) {\n a = this;\n b = num;\n } else {\n a = num;\n b = this;\n }\n\n for (var i = 0; i < b.length; i++) {\n this.words[i] = a.words[i] ^ b.words[i];\n }\n\n if (this !== a) {\n for (; i < a.length; i++) {\n this.words[i] = a.words[i];\n }\n }\n\n this.length = a.length;\n\n return this._strip();\n };\n\n BN.prototype.ixor = function ixor (num) {\n assert((this.negative | num.negative) === 0);\n return this.iuxor(num);\n };\n\n // Xor `num` with `this`\n BN.prototype.xor = function xor (num) {\n if (this.length > num.length) return this.clone().ixor(num);\n return num.clone().ixor(this);\n };\n\n BN.prototype.uxor = function uxor (num) {\n if (this.length > num.length) return this.clone().iuxor(num);\n return num.clone().iuxor(this);\n };\n\n // Not ``this`` with ``width`` bitwidth\n BN.prototype.inotn = function inotn (width) {\n assert(typeof width === 'number' && width >= 0);\n\n var bytesNeeded = Math.ceil(width / 26) | 0;\n var bitsLeft = width % 26;\n\n // Extend the buffer with leading zeroes\n this._expand(bytesNeeded);\n\n if (bitsLeft > 0) {\n bytesNeeded--;\n }\n\n // Handle complete words\n for (var i = 0; i < bytesNeeded; i++) {\n this.words[i] = ~this.words[i] & 0x3ffffff;\n }\n\n // Handle the residue\n if (bitsLeft > 0) {\n this.words[i] = ~this.words[i] & (0x3ffffff >> (26 - bitsLeft));\n }\n\n // And remove leading zeroes\n return this._strip();\n };\n\n BN.prototype.notn = function notn (width) {\n return this.clone().inotn(width);\n };\n\n // Set `bit` of `this`\n BN.prototype.setn = function setn (bit, val) {\n assert(typeof bit === 'number' && bit >= 0);\n\n var off = (bit / 26) | 0;\n var wbit = bit % 26;\n\n this._expand(off + 1);\n\n if (val) {\n this.words[off] = this.words[off] | (1 << wbit);\n } else {\n this.words[off] = this.words[off] & ~(1 << wbit);\n }\n\n return this._strip();\n };\n\n // Add `num` to `this` in-place\n BN.prototype.iadd = function iadd (num) {\n var r;\n\n // negative + positive\n if (this.negative !== 0 && num.negative === 0) {\n this.negative = 0;\n r = this.isub(num);\n this.negative ^= 1;\n return this._normSign();\n\n // positive + negative\n } else if (this.negative === 0 && num.negative !== 0) {\n num.negative = 0;\n r = this.isub(num);\n num.negative = 1;\n return r._normSign();\n }\n\n // a.length > b.length\n var a, b;\n if (this.length > num.length) {\n a = this;\n b = num;\n } else {\n a = num;\n b = this;\n }\n\n var carry = 0;\n for (var i = 0; i < b.length; i++) {\n r = (a.words[i] | 0) + (b.words[i] | 0) + carry;\n this.words[i] = r & 0x3ffffff;\n carry = r >>> 26;\n }\n for (; carry !== 0 && i < a.length; i++) {\n r = (a.words[i] | 0) + carry;\n this.words[i] = r & 0x3ffffff;\n carry = r >>> 26;\n }\n\n this.length = a.length;\n if (carry !== 0) {\n this.words[this.length] = carry;\n this.length++;\n // Copy the rest of the words\n } else if (a !== this) {\n for (; i < a.length; i++) {\n this.words[i] = a.words[i];\n }\n }\n\n return this;\n };\n\n // Add `num` to `this`\n BN.prototype.add = function add (num) {\n var res;\n if (num.negative !== 0 && this.negative === 0) {\n num.negative = 0;\n res = this.sub(num);\n num.negative ^= 1;\n return res;\n } else if (num.negative === 0 && this.negative !== 0) {\n this.negative = 0;\n res = num.sub(this);\n this.negative = 1;\n return res;\n }\n\n if (this.length > num.length) return this.clone().iadd(num);\n\n return num.clone().iadd(this);\n };\n\n // Subtract `num` from `this` in-place\n BN.prototype.isub = function isub (num) {\n // this - (-num) = this + num\n if (num.negative !== 0) {\n num.negative = 0;\n var r = this.iadd(num);\n num.negative = 1;\n return r._normSign();\n\n // -this - num = -(this + num)\n } else if (this.negative !== 0) {\n this.negative = 0;\n this.iadd(num);\n this.negative = 1;\n return this._normSign();\n }\n\n // At this point both numbers are positive\n var cmp = this.cmp(num);\n\n // Optimization - zeroify\n if (cmp === 0) {\n this.negative = 0;\n this.length = 1;\n this.words[0] = 0;\n return this;\n }\n\n // a > b\n var a, b;\n if (cmp > 0) {\n a = this;\n b = num;\n } else {\n a = num;\n b = this;\n }\n\n var carry = 0;\n for (var i = 0; i < b.length; i++) {\n r = (a.words[i] | 0) - (b.words[i] | 0) + carry;\n carry = r >> 26;\n this.words[i] = r & 0x3ffffff;\n }\n for (; carry !== 0 && i < a.length; i++) {\n r = (a.words[i] | 0) + carry;\n carry = r >> 26;\n this.words[i] = r & 0x3ffffff;\n }\n\n // Copy rest of the words\n if (carry === 0 && i < a.length && a !== this) {\n for (; i < a.length; i++) {\n this.words[i] = a.words[i];\n }\n }\n\n this.length = Math.max(this.length, i);\n\n if (a !== this) {\n this.negative = 1;\n }\n\n return this._strip();\n };\n\n // Subtract `num` from `this`\n BN.prototype.sub = function sub (num) {\n return this.clone().isub(num);\n };\n\n function smallMulTo (self, num, out) {\n out.negative = num.negative ^ self.negative;\n var len = (self.length + num.length) | 0;\n out.length = len;\n len = (len - 1) | 0;\n\n // Peel one iteration (compiler can't do it, because of code complexity)\n var a = self.words[0] | 0;\n var b = num.words[0] | 0;\n var r = a * b;\n\n var lo = r & 0x3ffffff;\n var carry = (r / 0x4000000) | 0;\n out.words[0] = lo;\n\n for (var k = 1; k < len; k++) {\n // Sum all words with the same `i + j = k` and accumulate `ncarry`,\n // note that ncarry could be >= 0x3ffffff\n var ncarry = carry >>> 26;\n var rword = carry & 0x3ffffff;\n var maxJ = Math.min(k, num.length - 1);\n for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {\n var i = (k - j) | 0;\n a = self.words[i] | 0;\n b = num.words[j] | 0;\n r = a * b + rword;\n ncarry += (r / 0x4000000) | 0;\n rword = r & 0x3ffffff;\n }\n out.words[k] = rword | 0;\n carry = ncarry | 0;\n }\n if (carry !== 0) {\n out.words[k] = carry | 0;\n } else {\n out.length--;\n }\n\n return out._strip();\n }\n\n // TODO(indutny): it may be reasonable to omit it for users who don't need\n // to work with 256-bit numbers, otherwise it gives 20% improvement for 256-bit\n // multiplication (like elliptic secp256k1).\n var comb10MulTo = function comb10MulTo (self, num, out) {\n var a = self.words;\n var b = num.words;\n var o = out.words;\n var c = 0;\n var lo;\n var mid;\n var hi;\n var a0 = a[0] | 0;\n var al0 = a0 & 0x1fff;\n var ah0 = a0 >>> 13;\n var a1 = a[1] | 0;\n var al1 = a1 & 0x1fff;\n var ah1 = a1 >>> 13;\n var a2 = a[2] | 0;\n var al2 = a2 & 0x1fff;\n var ah2 = a2 >>> 13;\n var a3 = a[3] | 0;\n var al3 = a3 & 0x1fff;\n var ah3 = a3 >>> 13;\n var a4 = a[4] | 0;\n var al4 = a4 & 0x1fff;\n var ah4 = a4 >>> 13;\n var a5 = a[5] | 0;\n var al5 = a5 & 0x1fff;\n var ah5 = a5 >>> 13;\n var a6 = a[6] | 0;\n var al6 = a6 & 0x1fff;\n var ah6 = a6 >>> 13;\n var a7 = a[7] | 0;\n var al7 = a7 & 0x1fff;\n var ah7 = a7 >>> 13;\n var a8 = a[8] | 0;\n var al8 = a8 & 0x1fff;\n var ah8 = a8 >>> 13;\n var a9 = a[9] | 0;\n var al9 = a9 & 0x1fff;\n var ah9 = a9 >>> 13;\n var b0 = b[0] | 0;\n var bl0 = b0 & 0x1fff;\n var bh0 = b0 >>> 13;\n var b1 = b[1] | 0;\n var bl1 = b1 & 0x1fff;\n var bh1 = b1 >>> 13;\n var b2 = b[2] | 0;\n var bl2 = b2 & 0x1fff;\n var bh2 = b2 >>> 13;\n var b3 = b[3] | 0;\n var bl3 = b3 & 0x1fff;\n var bh3 = b3 >>> 13;\n var b4 = b[4] | 0;\n var bl4 = b4 & 0x1fff;\n var bh4 = b4 >>> 13;\n var b5 = b[5] | 0;\n var bl5 = b5 & 0x1fff;\n var bh5 = b5 >>> 13;\n var b6 = b[6] | 0;\n var bl6 = b6 & 0x1fff;\n var bh6 = b6 >>> 13;\n var b7 = b[7] | 0;\n var bl7 = b7 & 0x1fff;\n var bh7 = b7 >>> 13;\n var b8 = b[8] | 0;\n var bl8 = b8 & 0x1fff;\n var bh8 = b8 >>> 13;\n var b9 = b[9] | 0;\n var bl9 = b9 & 0x1fff;\n var bh9 = b9 >>> 13;\n\n out.negative = self.negative ^ num.negative;\n out.length = 19;\n /* k = 0 */\n lo = Math.imul(al0, bl0);\n mid = Math.imul(al0, bh0);\n mid = (mid + Math.imul(ah0, bl0)) | 0;\n hi = Math.imul(ah0, bh0);\n var w0 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w0 >>> 26)) | 0;\n w0 &= 0x3ffffff;\n /* k = 1 */\n lo = Math.imul(al1, bl0);\n mid = Math.imul(al1, bh0);\n mid = (mid + Math.imul(ah1, bl0)) | 0;\n hi = Math.imul(ah1, bh0);\n lo = (lo + Math.imul(al0, bl1)) | 0;\n mid = (mid + Math.imul(al0, bh1)) | 0;\n mid = (mid + Math.imul(ah0, bl1)) | 0;\n hi = (hi + Math.imul(ah0, bh1)) | 0;\n var w1 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w1 >>> 26)) | 0;\n w1 &= 0x3ffffff;\n /* k = 2 */\n lo = Math.imul(al2, bl0);\n mid = Math.imul(al2, bh0);\n mid = (mid + Math.imul(ah2, bl0)) | 0;\n hi = Math.imul(ah2, bh0);\n lo = (lo + Math.imul(al1, bl1)) | 0;\n mid = (mid + Math.imul(al1, bh1)) | 0;\n mid = (mid + Math.imul(ah1, bl1)) | 0;\n hi = (hi + Math.imul(ah1, bh1)) | 0;\n lo = (lo + Math.imul(al0, bl2)) | 0;\n mid = (mid + Math.imul(al0, bh2)) | 0;\n mid = (mid + Math.imul(ah0, bl2)) | 0;\n hi = (hi + Math.imul(ah0, bh2)) | 0;\n var w2 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w2 >>> 26)) | 0;\n w2 &= 0x3ffffff;\n /* k = 3 */\n lo = Math.imul(al3, bl0);\n mid = Math.imul(al3, bh0);\n mid = (mid + Math.imul(ah3, bl0)) | 0;\n hi = Math.imul(ah3, bh0);\n lo = (lo + Math.imul(al2, bl1)) | 0;\n mid = (mid + Math.imul(al2, bh1)) | 0;\n mid = (mid + Math.imul(ah2, bl1)) | 0;\n hi = (hi + Math.imul(ah2, bh1)) | 0;\n lo = (lo + Math.imul(al1, bl2)) | 0;\n mid = (mid + Math.imul(al1, bh2)) | 0;\n mid = (mid + Math.imul(ah1, bl2)) | 0;\n hi = (hi + Math.imul(ah1, bh2)) | 0;\n lo = (lo + Math.imul(al0, bl3)) | 0;\n mid = (mid + Math.imul(al0, bh3)) | 0;\n mid = (mid + Math.imul(ah0, bl3)) | 0;\n hi = (hi + Math.imul(ah0, bh3)) | 0;\n var w3 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w3 >>> 26)) | 0;\n w3 &= 0x3ffffff;\n /* k = 4 */\n lo = Math.imul(al4, bl0);\n mid = Math.imul(al4, bh0);\n mid = (mid + Math.imul(ah4, bl0)) | 0;\n hi = Math.imul(ah4, bh0);\n lo = (lo + Math.imul(al3, bl1)) | 0;\n mid = (mid + Math.imul(al3, bh1)) | 0;\n mid = (mid + Math.imul(ah3, bl1)) | 0;\n hi = (hi + Math.imul(ah3, bh1)) | 0;\n lo = (lo + Math.imul(al2, bl2)) | 0;\n mid = (mid + Math.imul(al2, bh2)) | 0;\n mid = (mid + Math.imul(ah2, bl2)) | 0;\n hi = (hi + Math.imul(ah2, bh2)) | 0;\n lo = (lo + Math.imul(al1, bl3)) | 0;\n mid = (mid + Math.imul(al1, bh3)) | 0;\n mid = (mid + Math.imul(ah1, bl3)) | 0;\n hi = (hi + Math.imul(ah1, bh3)) | 0;\n lo = (lo + Math.imul(al0, bl4)) | 0;\n mid = (mid + Math.imul(al0, bh4)) | 0;\n mid = (mid + Math.imul(ah0, bl4)) | 0;\n hi = (hi + Math.imul(ah0, bh4)) | 0;\n var w4 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w4 >>> 26)) | 0;\n w4 &= 0x3ffffff;\n /* k = 5 */\n lo = Math.imul(al5, bl0);\n mid = Math.imul(al5, bh0);\n mid = (mid + Math.imul(ah5, bl0)) | 0;\n hi = Math.imul(ah5, bh0);\n lo = (lo + Math.imul(al4, bl1)) | 0;\n mid = (mid + Math.imul(al4, bh1)) | 0;\n mid = (mid + Math.imul(ah4, bl1)) | 0;\n hi = (hi + Math.imul(ah4, bh1)) | 0;\n lo = (lo + Math.imul(al3, bl2)) | 0;\n mid = (mid + Math.imul(al3, bh2)) | 0;\n mid = (mid + Math.imul(ah3, bl2)) | 0;\n hi = (hi + Math.imul(ah3, bh2)) | 0;\n lo = (lo + Math.imul(al2, bl3)) | 0;\n mid = (mid + Math.imul(al2, bh3)) | 0;\n mid = (mid + Math.imul(ah2, bl3)) | 0;\n hi = (hi + Math.imul(ah2, bh3)) | 0;\n lo = (lo + Math.imul(al1, bl4)) | 0;\n mid = (mid + Math.imul(al1, bh4)) | 0;\n mid = (mid + Math.imul(ah1, bl4)) | 0;\n hi = (hi + Math.imul(ah1, bh4)) | 0;\n lo = (lo + Math.imul(al0, bl5)) | 0;\n mid = (mid + Math.imul(al0, bh5)) | 0;\n mid = (mid + Math.imul(ah0, bl5)) | 0;\n hi = (hi + Math.imul(ah0, bh5)) | 0;\n var w5 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w5 >>> 26)) | 0;\n w5 &= 0x3ffffff;\n /* k = 6 */\n lo = Math.imul(al6, bl0);\n mid = Math.imul(al6, bh0);\n mid = (mid + Math.imul(ah6, bl0)) | 0;\n hi = Math.imul(ah6, bh0);\n lo = (lo + Math.imul(al5, bl1)) | 0;\n mid = (mid + Math.imul(al5, bh1)) | 0;\n mid = (mid + Math.imul(ah5, bl1)) | 0;\n hi = (hi + Math.imul(ah5, bh1)) | 0;\n lo = (lo + Math.imul(al4, bl2)) | 0;\n mid = (mid + Math.imul(al4, bh2)) | 0;\n mid = (mid + Math.imul(ah4, bl2)) | 0;\n hi = (hi + Math.imul(ah4, bh2)) | 0;\n lo = (lo + Math.imul(al3, bl3)) | 0;\n mid = (mid + Math.imul(al3, bh3)) | 0;\n mid = (mid + Math.imul(ah3, bl3)) | 0;\n hi = (hi + Math.imul(ah3, bh3)) | 0;\n lo = (lo + Math.imul(al2, bl4)) | 0;\n mid = (mid + Math.imul(al2, bh4)) | 0;\n mid = (mid + Math.imul(ah2, bl4)) | 0;\n hi = (hi + Math.imul(ah2, bh4)) | 0;\n lo = (lo + Math.imul(al1, bl5)) | 0;\n mid = (mid + Math.imul(al1, bh5)) | 0;\n mid = (mid + Math.imul(ah1, bl5)) | 0;\n hi = (hi + Math.imul(ah1, bh5)) | 0;\n lo = (lo + Math.imul(al0, bl6)) | 0;\n mid = (mid + Math.imul(al0, bh6)) | 0;\n mid = (mid + Math.imul(ah0, bl6)) | 0;\n hi = (hi + Math.imul(ah0, bh6)) | 0;\n var w6 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w6 >>> 26)) | 0;\n w6 &= 0x3ffffff;\n /* k = 7 */\n lo = Math.imul(al7, bl0);\n mid = Math.imul(al7, bh0);\n mid = (mid + Math.imul(ah7, bl0)) | 0;\n hi = Math.imul(ah7, bh0);\n lo = (lo + Math.imul(al6, bl1)) | 0;\n mid = (mid + Math.imul(al6, bh1)) | 0;\n mid = (mid + Math.imul(ah6, bl1)) | 0;\n hi = (hi + Math.imul(ah6, bh1)) | 0;\n lo = (lo + Math.imul(al5, bl2)) | 0;\n mid = (mid + Math.imul(al5, bh2)) | 0;\n mid = (mid + Math.imul(ah5, bl2)) | 0;\n hi = (hi + Math.imul(ah5, bh2)) | 0;\n lo = (lo + Math.imul(al4, bl3)) | 0;\n mid = (mid + Math.imul(al4, bh3)) | 0;\n mid = (mid + Math.imul(ah4, bl3)) | 0;\n hi = (hi + Math.imul(ah4, bh3)) | 0;\n lo = (lo + Math.imul(al3, bl4)) | 0;\n mid = (mid + Math.imul(al3, bh4)) | 0;\n mid = (mid + Math.imul(ah3, bl4)) | 0;\n hi = (hi + Math.imul(ah3, bh4)) | 0;\n lo = (lo + Math.imul(al2, bl5)) | 0;\n mid = (mid + Math.imul(al2, bh5)) | 0;\n mid = (mid + Math.imul(ah2, bl5)) | 0;\n hi = (hi + Math.imul(ah2, bh5)) | 0;\n lo = (lo + Math.imul(al1, bl6)) | 0;\n mid = (mid + Math.imul(al1, bh6)) | 0;\n mid = (mid + Math.imul(ah1, bl6)) | 0;\n hi = (hi + Math.imul(ah1, bh6)) | 0;\n lo = (lo + Math.imul(al0, bl7)) | 0;\n mid = (mid + Math.imul(al0, bh7)) | 0;\n mid = (mid + Math.imul(ah0, bl7)) | 0;\n hi = (hi + Math.imul(ah0, bh7)) | 0;\n var w7 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w7 >>> 26)) | 0;\n w7 &= 0x3ffffff;\n /* k = 8 */\n lo = Math.imul(al8, bl0);\n mid = Math.imul(al8, bh0);\n mid = (mid + Math.imul(ah8, bl0)) | 0;\n hi = Math.imul(ah8, bh0);\n lo = (lo + Math.imul(al7, bl1)) | 0;\n mid = (mid + Math.imul(al7, bh1)) | 0;\n mid = (mid + Math.imul(ah7, bl1)) | 0;\n hi = (hi + Math.imul(ah7, bh1)) | 0;\n lo = (lo + Math.imul(al6, bl2)) | 0;\n mid = (mid + Math.imul(al6, bh2)) | 0;\n mid = (mid + Math.imul(ah6, bl2)) | 0;\n hi = (hi + Math.imul(ah6, bh2)) | 0;\n lo = (lo + Math.imul(al5, bl3)) | 0;\n mid = (mid + Math.imul(al5, bh3)) | 0;\n mid = (mid + Math.imul(ah5, bl3)) | 0;\n hi = (hi + Math.imul(ah5, bh3)) | 0;\n lo = (lo + Math.imul(al4, bl4)) | 0;\n mid = (mid + Math.imul(al4, bh4)) | 0;\n mid = (mid + Math.imul(ah4, bl4)) | 0;\n hi = (hi + Math.imul(ah4, bh4)) | 0;\n lo = (lo + Math.imul(al3, bl5)) | 0;\n mid = (mid + Math.imul(al3, bh5)) | 0;\n mid = (mid + Math.imul(ah3, bl5)) | 0;\n hi = (hi + Math.imul(ah3, bh5)) | 0;\n lo = (lo + Math.imul(al2, bl6)) | 0;\n mid = (mid + Math.imul(al2, bh6)) | 0;\n mid = (mid + Math.imul(ah2, bl6)) | 0;\n hi = (hi + Math.imul(ah2, bh6)) | 0;\n lo = (lo + Math.imul(al1, bl7)) | 0;\n mid = (mid + Math.imul(al1, bh7)) | 0;\n mid = (mid + Math.imul(ah1, bl7)) | 0;\n hi = (hi + Math.imul(ah1, bh7)) | 0;\n lo = (lo + Math.imul(al0, bl8)) | 0;\n mid = (mid + Math.imul(al0, bh8)) | 0;\n mid = (mid + Math.imul(ah0, bl8)) | 0;\n hi = (hi + Math.imul(ah0, bh8)) | 0;\n var w8 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w8 >>> 26)) | 0;\n w8 &= 0x3ffffff;\n /* k = 9 */\n lo = Math.imul(al9, bl0);\n mid = Math.imul(al9, bh0);\n mid = (mid + Math.imul(ah9, bl0)) | 0;\n hi = Math.imul(ah9, bh0);\n lo = (lo + Math.imul(al8, bl1)) | 0;\n mid = (mid + Math.imul(al8, bh1)) | 0;\n mid = (mid + Math.imul(ah8, bl1)) | 0;\n hi = (hi + Math.imul(ah8, bh1)) | 0;\n lo = (lo + Math.imul(al7, bl2)) | 0;\n mid = (mid + Math.imul(al7, bh2)) | 0;\n mid = (mid + Math.imul(ah7, bl2)) | 0;\n hi = (hi + Math.imul(ah7, bh2)) | 0;\n lo = (lo + Math.imul(al6, bl3)) | 0;\n mid = (mid + Math.imul(al6, bh3)) | 0;\n mid = (mid + Math.imul(ah6, bl3)) | 0;\n hi = (hi + Math.imul(ah6, bh3)) | 0;\n lo = (lo + Math.imul(al5, bl4)) | 0;\n mid = (mid + Math.imul(al5, bh4)) | 0;\n mid = (mid + Math.imul(ah5, bl4)) | 0;\n hi = (hi + Math.imul(ah5, bh4)) | 0;\n lo = (lo + Math.imul(al4, bl5)) | 0;\n mid = (mid + Math.imul(al4, bh5)) | 0;\n mid = (mid + Math.imul(ah4, bl5)) | 0;\n hi = (hi + Math.imul(ah4, bh5)) | 0;\n lo = (lo + Math.imul(al3, bl6)) | 0;\n mid = (mid + Math.imul(al3, bh6)) | 0;\n mid = (mid + Math.imul(ah3, bl6)) | 0;\n hi = (hi + Math.imul(ah3, bh6)) | 0;\n lo = (lo + Math.imul(al2, bl7)) | 0;\n mid = (mid + Math.imul(al2, bh7)) | 0;\n mid = (mid + Math.imul(ah2, bl7)) | 0;\n hi = (hi + Math.imul(ah2, bh7)) | 0;\n lo = (lo + Math.imul(al1, bl8)) | 0;\n mid = (mid + Math.imul(al1, bh8)) | 0;\n mid = (mid + Math.imul(ah1, bl8)) | 0;\n hi = (hi + Math.imul(ah1, bh8)) | 0;\n lo = (lo + Math.imul(al0, bl9)) | 0;\n mid = (mid + Math.imul(al0, bh9)) | 0;\n mid = (mid + Math.imul(ah0, bl9)) | 0;\n hi = (hi + Math.imul(ah0, bh9)) | 0;\n var w9 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w9 >>> 26)) | 0;\n w9 &= 0x3ffffff;\n /* k = 10 */\n lo = Math.imul(al9, bl1);\n mid = Math.imul(al9, bh1);\n mid = (mid + Math.imul(ah9, bl1)) | 0;\n hi = Math.imul(ah9, bh1);\n lo = (lo + Math.imul(al8, bl2)) | 0;\n mid = (mid + Math.imul(al8, bh2)) | 0;\n mid = (mid + Math.imul(ah8, bl2)) | 0;\n hi = (hi + Math.imul(ah8, bh2)) | 0;\n lo = (lo + Math.imul(al7, bl3)) | 0;\n mid = (mid + Math.imul(al7, bh3)) | 0;\n mid = (mid + Math.imul(ah7, bl3)) | 0;\n hi = (hi + Math.imul(ah7, bh3)) | 0;\n lo = (lo + Math.imul(al6, bl4)) | 0;\n mid = (mid + Math.imul(al6, bh4)) | 0;\n mid = (mid + Math.imul(ah6, bl4)) | 0;\n hi = (hi + Math.imul(ah6, bh4)) | 0;\n lo = (lo + Math.imul(al5, bl5)) | 0;\n mid = (mid + Math.imul(al5, bh5)) | 0;\n mid = (mid + Math.imul(ah5, bl5)) | 0;\n hi = (hi + Math.imul(ah5, bh5)) | 0;\n lo = (lo + Math.imul(al4, bl6)) | 0;\n mid = (mid + Math.imul(al4, bh6)) | 0;\n mid = (mid + Math.imul(ah4, bl6)) | 0;\n hi = (hi + Math.imul(ah4, bh6)) | 0;\n lo = (lo + Math.imul(al3, bl7)) | 0;\n mid = (mid + Math.imul(al3, bh7)) | 0;\n mid = (mid + Math.imul(ah3, bl7)) | 0;\n hi = (hi + Math.imul(ah3, bh7)) | 0;\n lo = (lo + Math.imul(al2, bl8)) | 0;\n mid = (mid + Math.imul(al2, bh8)) | 0;\n mid = (mid + Math.imul(ah2, bl8)) | 0;\n hi = (hi + Math.imul(ah2, bh8)) | 0;\n lo = (lo + Math.imul(al1, bl9)) | 0;\n mid = (mid + Math.imul(al1, bh9)) | 0;\n mid = (mid + Math.imul(ah1, bl9)) | 0;\n hi = (hi + Math.imul(ah1, bh9)) | 0;\n var w10 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w10 >>> 26)) | 0;\n w10 &= 0x3ffffff;\n /* k = 11 */\n lo = Math.imul(al9, bl2);\n mid = Math.imul(al9, bh2);\n mid = (mid + Math.imul(ah9, bl2)) | 0;\n hi = Math.imul(ah9, bh2);\n lo = (lo + Math.imul(al8, bl3)) | 0;\n mid = (mid + Math.imul(al8, bh3)) | 0;\n mid = (mid + Math.imul(ah8, bl3)) | 0;\n hi = (hi + Math.imul(ah8, bh3)) | 0;\n lo = (lo + Math.imul(al7, bl4)) | 0;\n mid = (mid + Math.imul(al7, bh4)) | 0;\n mid = (mid + Math.imul(ah7, bl4)) | 0;\n hi = (hi + Math.imul(ah7, bh4)) | 0;\n lo = (lo + Math.imul(al6, bl5)) | 0;\n mid = (mid + Math.imul(al6, bh5)) | 0;\n mid = (mid + Math.imul(ah6, bl5)) | 0;\n hi = (hi + Math.imul(ah6, bh5)) | 0;\n lo = (lo + Math.imul(al5, bl6)) | 0;\n mid = (mid + Math.imul(al5, bh6)) | 0;\n mid = (mid + Math.imul(ah5, bl6)) | 0;\n hi = (hi + Math.imul(ah5, bh6)) | 0;\n lo = (lo + Math.imul(al4, bl7)) | 0;\n mid = (mid + Math.imul(al4, bh7)) | 0;\n mid = (mid + Math.imul(ah4, bl7)) | 0;\n hi = (hi + Math.imul(ah4, bh7)) | 0;\n lo = (lo + Math.imul(al3, bl8)) | 0;\n mid = (mid + Math.imul(al3, bh8)) | 0;\n mid = (mid + Math.imul(ah3, bl8)) | 0;\n hi = (hi + Math.imul(ah3, bh8)) | 0;\n lo = (lo + Math.imul(al2, bl9)) | 0;\n mid = (mid + Math.imul(al2, bh9)) | 0;\n mid = (mid + Math.imul(ah2, bl9)) | 0;\n hi = (hi + Math.imul(ah2, bh9)) | 0;\n var w11 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w11 >>> 26)) | 0;\n w11 &= 0x3ffffff;\n /* k = 12 */\n lo = Math.imul(al9, bl3);\n mid = Math.imul(al9, bh3);\n mid = (mid + Math.imul(ah9, bl3)) | 0;\n hi = Math.imul(ah9, bh3);\n lo = (lo + Math.imul(al8, bl4)) | 0;\n mid = (mid + Math.imul(al8, bh4)) | 0;\n mid = (mid + Math.imul(ah8, bl4)) | 0;\n hi = (hi + Math.imul(ah8, bh4)) | 0;\n lo = (lo + Math.imul(al7, bl5)) | 0;\n mid = (mid + Math.imul(al7, bh5)) | 0;\n mid = (mid + Math.imul(ah7, bl5)) | 0;\n hi = (hi + Math.imul(ah7, bh5)) | 0;\n lo = (lo + Math.imul(al6, bl6)) | 0;\n mid = (mid + Math.imul(al6, bh6)) | 0;\n mid = (mid + Math.imul(ah6, bl6)) | 0;\n hi = (hi + Math.imul(ah6, bh6)) | 0;\n lo = (lo + Math.imul(al5, bl7)) | 0;\n mid = (mid + Math.imul(al5, bh7)) | 0;\n mid = (mid + Math.imul(ah5, bl7)) | 0;\n hi = (hi + Math.imul(ah5, bh7)) | 0;\n lo = (lo + Math.imul(al4, bl8)) | 0;\n mid = (mid + Math.imul(al4, bh8)) | 0;\n mid = (mid + Math.imul(ah4, bl8)) | 0;\n hi = (hi + Math.imul(ah4, bh8)) | 0;\n lo = (lo + Math.imul(al3, bl9)) | 0;\n mid = (mid + Math.imul(al3, bh9)) | 0;\n mid = (mid + Math.imul(ah3, bl9)) | 0;\n hi = (hi + Math.imul(ah3, bh9)) | 0;\n var w12 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w12 >>> 26)) | 0;\n w12 &= 0x3ffffff;\n /* k = 13 */\n lo = Math.imul(al9, bl4);\n mid = Math.imul(al9, bh4);\n mid = (mid + Math.imul(ah9, bl4)) | 0;\n hi = Math.imul(ah9, bh4);\n lo = (lo + Math.imul(al8, bl5)) | 0;\n mid = (mid + Math.imul(al8, bh5)) | 0;\n mid = (mid + Math.imul(ah8, bl5)) | 0;\n hi = (hi + Math.imul(ah8, bh5)) | 0;\n lo = (lo + Math.imul(al7, bl6)) | 0;\n mid = (mid + Math.imul(al7, bh6)) | 0;\n mid = (mid + Math.imul(ah7, bl6)) | 0;\n hi = (hi + Math.imul(ah7, bh6)) | 0;\n lo = (lo + Math.imul(al6, bl7)) | 0;\n mid = (mid + Math.imul(al6, bh7)) | 0;\n mid = (mid + Math.imul(ah6, bl7)) | 0;\n hi = (hi + Math.imul(ah6, bh7)) | 0;\n lo = (lo + Math.imul(al5, bl8)) | 0;\n mid = (mid + Math.imul(al5, bh8)) | 0;\n mid = (mid + Math.imul(ah5, bl8)) | 0;\n hi = (hi + Math.imul(ah5, bh8)) | 0;\n lo = (lo + Math.imul(al4, bl9)) | 0;\n mid = (mid + Math.imul(al4, bh9)) | 0;\n mid = (mid + Math.imul(ah4, bl9)) | 0;\n hi = (hi + Math.imul(ah4, bh9)) | 0;\n var w13 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w13 >>> 26)) | 0;\n w13 &= 0x3ffffff;\n /* k = 14 */\n lo = Math.imul(al9, bl5);\n mid = Math.imul(al9, bh5);\n mid = (mid + Math.imul(ah9, bl5)) | 0;\n hi = Math.imul(ah9, bh5);\n lo = (lo + Math.imul(al8, bl6)) | 0;\n mid = (mid + Math.imul(al8, bh6)) | 0;\n mid = (mid + Math.imul(ah8, bl6)) | 0;\n hi = (hi + Math.imul(ah8, bh6)) | 0;\n lo = (lo + Math.imul(al7, bl7)) | 0;\n mid = (mid + Math.imul(al7, bh7)) | 0;\n mid = (mid + Math.imul(ah7, bl7)) | 0;\n hi = (hi + Math.imul(ah7, bh7)) | 0;\n lo = (lo + Math.imul(al6, bl8)) | 0;\n mid = (mid + Math.imul(al6, bh8)) | 0;\n mid = (mid + Math.imul(ah6, bl8)) | 0;\n hi = (hi + Math.imul(ah6, bh8)) | 0;\n lo = (lo + Math.imul(al5, bl9)) | 0;\n mid = (mid + Math.imul(al5, bh9)) | 0;\n mid = (mid + Math.imul(ah5, bl9)) | 0;\n hi = (hi + Math.imul(ah5, bh9)) | 0;\n var w14 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w14 >>> 26)) | 0;\n w14 &= 0x3ffffff;\n /* k = 15 */\n lo = Math.imul(al9, bl6);\n mid = Math.imul(al9, bh6);\n mid = (mid + Math.imul(ah9, bl6)) | 0;\n hi = Math.imul(ah9, bh6);\n lo = (lo + Math.imul(al8, bl7)) | 0;\n mid = (mid + Math.imul(al8, bh7)) | 0;\n mid = (mid + Math.imul(ah8, bl7)) | 0;\n hi = (hi + Math.imul(ah8, bh7)) | 0;\n lo = (lo + Math.imul(al7, bl8)) | 0;\n mid = (mid + Math.imul(al7, bh8)) | 0;\n mid = (mid + Math.imul(ah7, bl8)) | 0;\n hi = (hi + Math.imul(ah7, bh8)) | 0;\n lo = (lo + Math.imul(al6, bl9)) | 0;\n mid = (mid + Math.imul(al6, bh9)) | 0;\n mid = (mid + Math.imul(ah6, bl9)) | 0;\n hi = (hi + Math.imul(ah6, bh9)) | 0;\n var w15 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w15 >>> 26)) | 0;\n w15 &= 0x3ffffff;\n /* k = 16 */\n lo = Math.imul(al9, bl7);\n mid = Math.imul(al9, bh7);\n mid = (mid + Math.imul(ah9, bl7)) | 0;\n hi = Math.imul(ah9, bh7);\n lo = (lo + Math.imul(al8, bl8)) | 0;\n mid = (mid + Math.imul(al8, bh8)) | 0;\n mid = (mid + Math.imul(ah8, bl8)) | 0;\n hi = (hi + Math.imul(ah8, bh8)) | 0;\n lo = (lo + Math.imul(al7, bl9)) | 0;\n mid = (mid + Math.imul(al7, bh9)) | 0;\n mid = (mid + Math.imul(ah7, bl9)) | 0;\n hi = (hi + Math.imul(ah7, bh9)) | 0;\n var w16 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w16 >>> 26)) | 0;\n w16 &= 0x3ffffff;\n /* k = 17 */\n lo = Math.imul(al9, bl8);\n mid = Math.imul(al9, bh8);\n mid = (mid + Math.imul(ah9, bl8)) | 0;\n hi = Math.imul(ah9, bh8);\n lo = (lo + Math.imul(al8, bl9)) | 0;\n mid = (mid + Math.imul(al8, bh9)) | 0;\n mid = (mid + Math.imul(ah8, bl9)) | 0;\n hi = (hi + Math.imul(ah8, bh9)) | 0;\n var w17 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w17 >>> 26)) | 0;\n w17 &= 0x3ffffff;\n /* k = 18 */\n lo = Math.imul(al9, bl9);\n mid = Math.imul(al9, bh9);\n mid = (mid + Math.imul(ah9, bl9)) | 0;\n hi = Math.imul(ah9, bh9);\n var w18 = (((c + lo) | 0) + ((mid & 0x1fff) << 13)) | 0;\n c = (((hi + (mid >>> 13)) | 0) + (w18 >>> 26)) | 0;\n w18 &= 0x3ffffff;\n o[0] = w0;\n o[1] = w1;\n o[2] = w2;\n o[3] = w3;\n o[4] = w4;\n o[5] = w5;\n o[6] = w6;\n o[7] = w7;\n o[8] = w8;\n o[9] = w9;\n o[10] = w10;\n o[11] = w11;\n o[12] = w12;\n o[13] = w13;\n o[14] = w14;\n o[15] = w15;\n o[16] = w16;\n o[17] = w17;\n o[18] = w18;\n if (c !== 0) {\n o[19] = c;\n out.length++;\n }\n return out;\n };\n\n // Polyfill comb\n if (!Math.imul) {\n comb10MulTo = smallMulTo;\n }\n\n function bigMulTo (self, num, out) {\n out.negative = num.negative ^ self.negative;\n out.length = self.length + num.length;\n\n var carry = 0;\n var hncarry = 0;\n for (var k = 0; k < out.length - 1; k++) {\n // Sum all words with the same `i + j = k` and accumulate `ncarry`,\n // note that ncarry could be >= 0x3ffffff\n var ncarry = hncarry;\n hncarry = 0;\n var rword = carry & 0x3ffffff;\n var maxJ = Math.min(k, num.length - 1);\n for (var j = Math.max(0, k - self.length + 1); j <= maxJ; j++) {\n var i = k - j;\n var a = self.words[i] | 0;\n var b = num.words[j] | 0;\n var r = a * b;\n\n var lo = r & 0x3ffffff;\n ncarry = (ncarry + ((r / 0x4000000) | 0)) | 0;\n lo = (lo + rword) | 0;\n rword = lo & 0x3ffffff;\n ncarry = (ncarry + (lo >>> 26)) | 0;\n\n hncarry += ncarry >>> 26;\n ncarry &= 0x3ffffff;\n }\n out.words[k] = rword;\n carry = ncarry;\n ncarry = hncarry;\n }\n if (carry !== 0) {\n out.words[k] = carry;\n } else {\n out.length--;\n }\n\n return out._strip();\n }\n\n function jumboMulTo (self, num, out) {\n // Temporary disable, see https://github.com/indutny/bn.js/issues/211\n // var fftm = new FFTM();\n // return fftm.mulp(self, num, out);\n return bigMulTo(self, num, out);\n }\n\n BN.prototype.mulTo = function mulTo (num, out) {\n var res;\n var len = this.length + num.length;\n if (this.length === 10 && num.length === 10) {\n res = comb10MulTo(this, num, out);\n } else if (len < 63) {\n res = smallMulTo(this, num, out);\n } else if (len < 1024) {\n res = bigMulTo(this, num, out);\n } else {\n res = jumboMulTo(this, num, out);\n }\n\n return res;\n };\n\n // Cooley-Tukey algorithm for FFT\n // slightly revisited to rely on looping instead of recursion\n\n function FFTM (x, y) {\n this.x = x;\n this.y = y;\n }\n\n FFTM.prototype.makeRBT = function makeRBT (N) {\n var t = new Array(N);\n var l = BN.prototype._countBits(N) - 1;\n for (var i = 0; i < N; i++) {\n t[i] = this.revBin(i, l, N);\n }\n\n return t;\n };\n\n // Returns binary-reversed representation of `x`\n FFTM.prototype.revBin = function revBin (x, l, N) {\n if (x === 0 || x === N - 1) return x;\n\n var rb = 0;\n for (var i = 0; i < l; i++) {\n rb |= (x & 1) << (l - i - 1);\n x >>= 1;\n }\n\n return rb;\n };\n\n // Performs \"tweedling\" phase, therefore 'emulating'\n // behaviour of the recursive algorithm\n FFTM.prototype.permute = function permute (rbt, rws, iws, rtws, itws, N) {\n for (var i = 0; i < N; i++) {\n rtws[i] = rws[rbt[i]];\n itws[i] = iws[rbt[i]];\n }\n };\n\n FFTM.prototype.transform = function transform (rws, iws, rtws, itws, N, rbt) {\n this.permute(rbt, rws, iws, rtws, itws, N);\n\n for (var s = 1; s < N; s <<= 1) {\n var l = s << 1;\n\n var rtwdf = Math.cos(2 * Math.PI / l);\n var itwdf = Math.sin(2 * Math.PI / l);\n\n for (var p = 0; p < N; p += l) {\n var rtwdf_ = rtwdf;\n var itwdf_ = itwdf;\n\n for (var j = 0; j < s; j++) {\n var re = rtws[p + j];\n var ie = itws[p + j];\n\n var ro = rtws[p + j + s];\n var io = itws[p + j + s];\n\n var rx = rtwdf_ * ro - itwdf_ * io;\n\n io = rtwdf_ * io + itwdf_ * ro;\n ro = rx;\n\n rtws[p + j] = re + ro;\n itws[p + j] = ie + io;\n\n rtws[p + j + s] = re - ro;\n itws[p + j + s] = ie - io;\n\n /* jshint maxdepth : false */\n if (j !== l) {\n rx = rtwdf * rtwdf_ - itwdf * itwdf_;\n\n itwdf_ = rtwdf * itwdf_ + itwdf * rtwdf_;\n rtwdf_ = rx;\n }\n }\n }\n }\n };\n\n FFTM.prototype.guessLen13b = function guessLen13b (n, m) {\n var N = Math.max(m, n) | 1;\n var odd = N & 1;\n var i = 0;\n for (N = N / 2 | 0; N; N = N >>> 1) {\n i++;\n }\n\n return 1 << i + 1 + odd;\n };\n\n FFTM.prototype.conjugate = function conjugate (rws, iws, N) {\n if (N <= 1) return;\n\n for (var i = 0; i < N / 2; i++) {\n var t = rws[i];\n\n rws[i] = rws[N - i - 1];\n rws[N - i - 1] = t;\n\n t = iws[i];\n\n iws[i] = -iws[N - i - 1];\n iws[N - i - 1] = -t;\n }\n };\n\n FFTM.prototype.normalize13b = function normalize13b (ws, N) {\n var carry = 0;\n for (var i = 0; i < N / 2; i++) {\n var w = Math.round(ws[2 * i + 1] / N) * 0x2000 +\n Math.round(ws[2 * i] / N) +\n carry;\n\n ws[i] = w & 0x3ffffff;\n\n if (w < 0x4000000) {\n carry = 0;\n } else {\n carry = w / 0x4000000 | 0;\n }\n }\n\n return ws;\n };\n\n FFTM.prototype.convert13b = function convert13b (ws, len, rws, N) {\n var carry = 0;\n for (var i = 0; i < len; i++) {\n carry = carry + (ws[i] | 0);\n\n rws[2 * i] = carry & 0x1fff; carry = carry >>> 13;\n rws[2 * i + 1] = carry & 0x1fff; carry = carry >>> 13;\n }\n\n // Pad with zeroes\n for (i = 2 * len; i < N; ++i) {\n rws[i] = 0;\n }\n\n assert(carry === 0);\n assert((carry & ~0x1fff) === 0);\n };\n\n FFTM.prototype.stub = function stub (N) {\n var ph = new Array(N);\n for (var i = 0; i < N; i++) {\n ph[i] = 0;\n }\n\n return ph;\n };\n\n FFTM.prototype.mulp = function mulp (x, y, out) {\n var N = 2 * this.guessLen13b(x.length, y.length);\n\n var rbt = this.makeRBT(N);\n\n var _ = this.stub(N);\n\n var rws = new Array(N);\n var rwst = new Array(N);\n var iwst = new Array(N);\n\n var nrws = new Array(N);\n var nrwst = new Array(N);\n var niwst = new Array(N);\n\n var rmws = out.words;\n rmws.length = N;\n\n this.convert13b(x.words, x.length, rws, N);\n this.convert13b(y.words, y.length, nrws, N);\n\n this.transform(rws, _, rwst, iwst, N, rbt);\n this.transform(nrws, _, nrwst, niwst, N, rbt);\n\n for (var i = 0; i < N; i++) {\n var rx = rwst[i] * nrwst[i] - iwst[i] * niwst[i];\n iwst[i] = rwst[i] * niwst[i] + iwst[i] * nrwst[i];\n rwst[i] = rx;\n }\n\n this.conjugate(rwst, iwst, N);\n this.transform(rwst, iwst, rmws, _, N, rbt);\n this.conjugate(rmws, _, N);\n this.normalize13b(rmws, N);\n\n out.negative = x.negative ^ y.negative;\n out.length = x.length + y.length;\n return out._strip();\n };\n\n // Multiply `this` by `num`\n BN.prototype.mul = function mul (num) {\n var out = new BN(null);\n out.words = new Array(this.length + num.length);\n return this.mulTo(num, out);\n };\n\n // Multiply employing FFT\n BN.prototype.mulf = function mulf (num) {\n var out = new BN(null);\n out.words = new Array(this.length + num.length);\n return jumboMulTo(this, num, out);\n };\n\n // In-place Multiplication\n BN.prototype.imul = function imul (num) {\n return this.clone().mulTo(num, this);\n };\n\n BN.prototype.imuln = function imuln (num) {\n var isNegNum = num < 0;\n if (isNegNum) num = -num;\n\n assert(typeof num === 'number');\n assert(num < 0x4000000);\n\n // Carry\n var carry = 0;\n for (var i = 0; i < this.length; i++) {\n var w = (this.words[i] | 0) * num;\n var lo = (w & 0x3ffffff) + (carry & 0x3ffffff);\n carry >>= 26;\n carry += (w / 0x4000000) | 0;\n // NOTE: lo is 27bit maximum\n carry += lo >>> 26;\n this.words[i] = lo & 0x3ffffff;\n }\n\n if (carry !== 0) {\n this.words[i] = carry;\n this.length++;\n }\n\n return isNegNum ? this.ineg() : this;\n };\n\n BN.prototype.muln = function muln (num) {\n return this.clone().imuln(num);\n };\n\n // `this` * `this`\n BN.prototype.sqr = function sqr () {\n return this.mul(this);\n };\n\n // `this` * `this` in-place\n BN.prototype.isqr = function isqr () {\n return this.imul(this.clone());\n };\n\n // Math.pow(`this`, `num`)\n BN.prototype.pow = function pow (num) {\n var w = toBitArray(num);\n if (w.length === 0) return new BN(1);\n\n // Skip leading zeroes\n var res = this;\n for (var i = 0; i < w.length; i++, res = res.sqr()) {\n if (w[i] !== 0) break;\n }\n\n if (++i < w.length) {\n for (var q = res.sqr(); i < w.length; i++, q = q.sqr()) {\n if (w[i] === 0) continue;\n\n res = res.mul(q);\n }\n }\n\n return res;\n };\n\n // Shift-left in-place\n BN.prototype.iushln = function iushln (bits) {\n assert(typeof bits === 'number' && bits >= 0);\n var r = bits % 26;\n var s = (bits - r) / 26;\n var carryMask = (0x3ffffff >>> (26 - r)) << (26 - r);\n var i;\n\n if (r !== 0) {\n var carry = 0;\n\n for (i = 0; i < this.length; i++) {\n var newCarry = this.words[i] & carryMask;\n var c = ((this.words[i] | 0) - newCarry) << r;\n this.words[i] = c | carry;\n carry = newCarry >>> (26 - r);\n }\n\n if (carry) {\n this.words[i] = carry;\n this.length++;\n }\n }\n\n if (s !== 0) {\n for (i = this.length - 1; i >= 0; i--) {\n this.words[i + s] = this.words[i];\n }\n\n for (i = 0; i < s; i++) {\n this.words[i] = 0;\n }\n\n this.length += s;\n }\n\n return this._strip();\n };\n\n BN.prototype.ishln = function ishln (bits) {\n // TODO(indutny): implement me\n assert(this.negative === 0);\n return this.iushln(bits);\n };\n\n // Shift-right in-place\n // NOTE: `hint` is a lowest bit before trailing zeroes\n // NOTE: if `extended` is present - it will be filled with destroyed bits\n BN.prototype.iushrn = function iushrn (bits, hint, extended) {\n assert(typeof bits === 'number' && bits >= 0);\n var h;\n if (hint) {\n h = (hint - (hint % 26)) / 26;\n } else {\n h = 0;\n }\n\n var r = bits % 26;\n var s = Math.min((bits - r) / 26, this.length);\n var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);\n var maskedWords = extended;\n\n h -= s;\n h = Math.max(0, h);\n\n // Extended mode, copy masked part\n if (maskedWords) {\n for (var i = 0; i < s; i++) {\n maskedWords.words[i] = this.words[i];\n }\n maskedWords.length = s;\n }\n\n if (s === 0) {\n // No-op, we should not move anything at all\n } else if (this.length > s) {\n this.length -= s;\n for (i = 0; i < this.length; i++) {\n this.words[i] = this.words[i + s];\n }\n } else {\n this.words[0] = 0;\n this.length = 1;\n }\n\n var carry = 0;\n for (i = this.length - 1; i >= 0 && (carry !== 0 || i >= h); i--) {\n var word = this.words[i] | 0;\n this.words[i] = (carry << (26 - r)) | (word >>> r);\n carry = word & mask;\n }\n\n // Push carried bits as a mask\n if (maskedWords && carry !== 0) {\n maskedWords.words[maskedWords.length++] = carry;\n }\n\n if (this.length === 0) {\n this.words[0] = 0;\n this.length = 1;\n }\n\n return this._strip();\n };\n\n BN.prototype.ishrn = function ishrn (bits, hint, extended) {\n // TODO(indutny): implement me\n assert(this.negative === 0);\n return this.iushrn(bits, hint, extended);\n };\n\n // Shift-left\n BN.prototype.shln = function shln (bits) {\n return this.clone().ishln(bits);\n };\n\n BN.prototype.ushln = function ushln (bits) {\n return this.clone().iushln(bits);\n };\n\n // Shift-right\n BN.prototype.shrn = function shrn (bits) {\n return this.clone().ishrn(bits);\n };\n\n BN.prototype.ushrn = function ushrn (bits) {\n return this.clone().iushrn(bits);\n };\n\n // Test if n bit is set\n BN.prototype.testn = function testn (bit) {\n assert(typeof bit === 'number' && bit >= 0);\n var r = bit % 26;\n var s = (bit - r) / 26;\n var q = 1 << r;\n\n // Fast case: bit is much higher than all existing words\n if (this.length <= s) return false;\n\n // Check bit and return\n var w = this.words[s];\n\n return !!(w & q);\n };\n\n // Return only lowers bits of number (in-place)\n BN.prototype.imaskn = function imaskn (bits) {\n assert(typeof bits === 'number' && bits >= 0);\n var r = bits % 26;\n var s = (bits - r) / 26;\n\n assert(this.negative === 0, 'imaskn works only with positive numbers');\n\n if (this.length <= s) {\n return this;\n }\n\n if (r !== 0) {\n s++;\n }\n this.length = Math.min(s, this.length);\n\n if (r !== 0) {\n var mask = 0x3ffffff ^ ((0x3ffffff >>> r) << r);\n this.words[this.length - 1] &= mask;\n }\n\n return this._strip();\n };\n\n // Return only lowers bits of number\n BN.prototype.maskn = function maskn (bits) {\n return this.clone().imaskn(bits);\n };\n\n // Add plain number `num` to `this`\n BN.prototype.iaddn = function iaddn (num) {\n assert(typeof num === 'number');\n assert(num < 0x4000000);\n if (num < 0) return this.isubn(-num);\n\n // Possible sign change\n if (this.negative !== 0) {\n if (this.length === 1 && (this.words[0] | 0) <= num) {\n this.words[0] = num - (this.words[0] | 0);\n this.negative = 0;\n return this;\n }\n\n this.negative = 0;\n this.isubn(num);\n this.negative = 1;\n return this;\n }\n\n // Add without checks\n return this._iaddn(num);\n };\n\n BN.prototype._iaddn = function _iaddn (num) {\n this.words[0] += num;\n\n // Carry\n for (var i = 0; i < this.length && this.words[i] >= 0x4000000; i++) {\n this.words[i] -= 0x4000000;\n if (i === this.length - 1) {\n this.words[i + 1] = 1;\n } else {\n this.words[i + 1]++;\n }\n }\n this.length = Math.max(this.length, i + 1);\n\n return this;\n };\n\n // Subtract plain number `num` from `this`\n BN.prototype.isubn = function isubn (num) {\n assert(typeof num === 'number');\n assert(num < 0x4000000);\n if (num < 0) return this.iaddn(-num);\n\n if (this.negative !== 0) {\n this.negative = 0;\n this.iaddn(num);\n this.negative = 1;\n return this;\n }\n\n this.words[0] -= num;\n\n if (this.length === 1 && this.words[0] < 0) {\n this.words[0] = -this.words[0];\n this.negative = 1;\n } else {\n // Carry\n for (var i = 0; i < this.length && this.words[i] < 0; i++) {\n this.words[i] += 0x4000000;\n this.words[i + 1] -= 1;\n }\n }\n\n return this._strip();\n };\n\n BN.prototype.addn = function addn (num) {\n return this.clone().iaddn(num);\n };\n\n BN.prototype.subn = function subn (num) {\n return this.clone().isubn(num);\n };\n\n BN.prototype.iabs = function iabs () {\n this.negative = 0;\n\n return this;\n };\n\n BN.prototype.abs = function abs () {\n return this.clone().iabs();\n };\n\n BN.prototype._ishlnsubmul = function _ishlnsubmul (num, mul, shift) {\n var len = num.length + shift;\n var i;\n\n this._expand(len);\n\n var w;\n var carry = 0;\n for (i = 0; i < num.length; i++) {\n w = (this.words[i + shift] | 0) + carry;\n var right = (num.words[i] | 0) * mul;\n w -= right & 0x3ffffff;\n carry = (w >> 26) - ((right / 0x4000000) | 0);\n this.words[i + shift] = w & 0x3ffffff;\n }\n for (; i < this.length - shift; i++) {\n w = (this.words[i + shift] | 0) + carry;\n carry = w >> 26;\n this.words[i + shift] = w & 0x3ffffff;\n }\n\n if (carry === 0) return this._strip();\n\n // Subtraction overflow\n assert(carry === -1);\n carry = 0;\n for (i = 0; i < this.length; i++) {\n w = -(this.words[i] | 0) + carry;\n carry = w >> 26;\n this.words[i] = w & 0x3ffffff;\n }\n this.negative = 1;\n\n return this._strip();\n };\n\n BN.prototype._wordDiv = function _wordDiv (num, mode) {\n var shift = this.length - num.length;\n\n var a = this.clone();\n var b = num;\n\n // Normalize\n var bhi = b.words[b.length - 1] | 0;\n var bhiBits = this._countBits(bhi);\n shift = 26 - bhiBits;\n if (shift !== 0) {\n b = b.ushln(shift);\n a.iushln(shift);\n bhi = b.words[b.length - 1] | 0;\n }\n\n // Initialize quotient\n var m = a.length - b.length;\n var q;\n\n if (mode !== 'mod') {\n q = new BN(null);\n q.length = m + 1;\n q.words = new Array(q.length);\n for (var i = 0; i < q.length; i++) {\n q.words[i] = 0;\n }\n }\n\n var diff = a.clone()._ishlnsubmul(b, 1, m);\n if (diff.negative === 0) {\n a = diff;\n if (q) {\n q.words[m] = 1;\n }\n }\n\n for (var j = m - 1; j >= 0; j--) {\n var qj = (a.words[b.length + j] | 0) * 0x4000000 +\n (a.words[b.length + j - 1] | 0);\n\n // NOTE: (qj / bhi) is (0x3ffffff * 0x4000000 + 0x3ffffff) / 0x2000000 max\n // (0x7ffffff)\n qj = Math.min((qj / bhi) | 0, 0x3ffffff);\n\n a._ishlnsubmul(b, qj, j);\n while (a.negative !== 0) {\n qj--;\n a.negative = 0;\n a._ishlnsubmul(b, 1, j);\n if (!a.isZero()) {\n a.negative ^= 1;\n }\n }\n if (q) {\n q.words[j] = qj;\n }\n }\n if (q) {\n q._strip();\n }\n a._strip();\n\n // Denormalize\n if (mode !== 'div' && shift !== 0) {\n a.iushrn(shift);\n }\n\n return {\n div: q || null,\n mod: a\n };\n };\n\n // NOTE: 1) `mode` can be set to `mod` to request mod only,\n // to `div` to request div only, or be absent to\n // request both div & mod\n // 2) `positive` is true if unsigned mod is requested\n BN.prototype.divmod = function divmod (num, mode, positive) {\n assert(!num.isZero());\n\n if (this.isZero()) {\n return {\n div: new BN(0),\n mod: new BN(0)\n };\n }\n\n var div, mod, res;\n if (this.negative !== 0 && num.negative === 0) {\n res = this.neg().divmod(num, mode);\n\n if (mode !== 'mod') {\n div = res.div.neg();\n }\n\n if (mode !== 'div') {\n mod = res.mod.neg();\n if (positive && mod.negative !== 0) {\n mod.iadd(num);\n }\n }\n\n return {\n div: div,\n mod: mod\n };\n }\n\n if (this.negative === 0 && num.negative !== 0) {\n res = this.divmod(num.neg(), mode);\n\n if (mode !== 'mod') {\n div = res.div.neg();\n }\n\n return {\n div: div,\n mod: res.mod\n };\n }\n\n if ((this.negative & num.negative) !== 0) {\n res = this.neg().divmod(num.neg(), mode);\n\n if (mode !== 'div') {\n mod = res.mod.neg();\n if (positive && mod.negative !== 0) {\n mod.isub(num);\n }\n }\n\n return {\n div: res.div,\n mod: mod\n };\n }\n\n // Both numbers are positive at this point\n\n // Strip both numbers to approximate shift value\n if (num.length > this.length || this.cmp(num) < 0) {\n return {\n div: new BN(0),\n mod: this\n };\n }\n\n // Very short reduction\n if (num.length === 1) {\n if (mode === 'div') {\n return {\n div: this.divn(num.words[0]),\n mod: null\n };\n }\n\n if (mode === 'mod') {\n return {\n div: null,\n mod: new BN(this.modrn(num.words[0]))\n };\n }\n\n return {\n div: this.divn(num.words[0]),\n mod: new BN(this.modrn(num.words[0]))\n };\n }\n\n return this._wordDiv(num, mode);\n };\n\n // Find `this` / `num`\n BN.prototype.div = function div (num) {\n return this.divmod(num, 'div', false).div;\n };\n\n // Find `this` % `num`\n BN.prototype.mod = function mod (num) {\n return this.divmod(num, 'mod', false).mod;\n };\n\n BN.prototype.umod = function umod (num) {\n return this.divmod(num, 'mod', true).mod;\n };\n\n // Find Round(`this` / `num`)\n BN.prototype.divRound = function divRound (num) {\n var dm = this.divmod(num);\n\n // Fast case - exact division\n if (dm.mod.isZero()) return dm.div;\n\n var mod = dm.div.negative !== 0 ? dm.mod.isub(num) : dm.mod;\n\n var half = num.ushrn(1);\n var r2 = num.andln(1);\n var cmp = mod.cmp(half);\n\n // Round down\n if (cmp < 0 || (r2 === 1 && cmp === 0)) return dm.div;\n\n // Round up\n return dm.div.negative !== 0 ? dm.div.isubn(1) : dm.div.iaddn(1);\n };\n\n BN.prototype.modrn = function modrn (num) {\n var isNegNum = num < 0;\n if (isNegNum) num = -num;\n\n assert(num <= 0x3ffffff);\n var p = (1 << 26) % num;\n\n var acc = 0;\n for (var i = this.length - 1; i >= 0; i--) {\n acc = (p * acc + (this.words[i] | 0)) % num;\n }\n\n return isNegNum ? -acc : acc;\n };\n\n // WARNING: DEPRECATED\n BN.prototype.modn = function modn (num) {\n return this.modrn(num);\n };\n\n // In-place division by number\n BN.prototype.idivn = function idivn (num) {\n var isNegNum = num < 0;\n if (isNegNum) num = -num;\n\n assert(num <= 0x3ffffff);\n\n var carry = 0;\n for (var i = this.length - 1; i >= 0; i--) {\n var w = (this.words[i] | 0) + carry * 0x4000000;\n this.words[i] = (w / num) | 0;\n carry = w % num;\n }\n\n this._strip();\n return isNegNum ? this.ineg() : this;\n };\n\n BN.prototype.divn = function divn (num) {\n return this.clone().idivn(num);\n };\n\n BN.prototype.egcd = function egcd (p) {\n assert(p.negative === 0);\n assert(!p.isZero());\n\n var x = this;\n var y = p.clone();\n\n if (x.negative !== 0) {\n x = x.umod(p);\n } else {\n x = x.clone();\n }\n\n // A * x + B * y = x\n var A = new BN(1);\n var B = new BN(0);\n\n // C * x + D * y = y\n var C = new BN(0);\n var D = new BN(1);\n\n var g = 0;\n\n while (x.isEven() && y.isEven()) {\n x.iushrn(1);\n y.iushrn(1);\n ++g;\n }\n\n var yp = y.clone();\n var xp = x.clone();\n\n while (!x.isZero()) {\n for (var i = 0, im = 1; (x.words[0] & im) === 0 && i < 26; ++i, im <<= 1);\n if (i > 0) {\n x.iushrn(i);\n while (i-- > 0) {\n if (A.isOdd() || B.isOdd()) {\n A.iadd(yp);\n B.isub(xp);\n }\n\n A.iushrn(1);\n B.iushrn(1);\n }\n }\n\n for (var j = 0, jm = 1; (y.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);\n if (j > 0) {\n y.iushrn(j);\n while (j-- > 0) {\n if (C.isOdd() || D.isOdd()) {\n C.iadd(yp);\n D.isub(xp);\n }\n\n C.iushrn(1);\n D.iushrn(1);\n }\n }\n\n if (x.cmp(y) >= 0) {\n x.isub(y);\n A.isub(C);\n B.isub(D);\n } else {\n y.isub(x);\n C.isub(A);\n D.isub(B);\n }\n }\n\n return {\n a: C,\n b: D,\n gcd: y.iushln(g)\n };\n };\n\n // This is reduced incarnation of the binary EEA\n // above, designated to invert members of the\n // _prime_ fields F(p) at a maximal speed\n BN.prototype._invmp = function _invmp (p) {\n assert(p.negative === 0);\n assert(!p.isZero());\n\n var a = this;\n var b = p.clone();\n\n if (a.negative !== 0) {\n a = a.umod(p);\n } else {\n a = a.clone();\n }\n\n var x1 = new BN(1);\n var x2 = new BN(0);\n\n var delta = b.clone();\n\n while (a.cmpn(1) > 0 && b.cmpn(1) > 0) {\n for (var i = 0, im = 1; (a.words[0] & im) === 0 && i < 26; ++i, im <<= 1);\n if (i > 0) {\n a.iushrn(i);\n while (i-- > 0) {\n if (x1.isOdd()) {\n x1.iadd(delta);\n }\n\n x1.iushrn(1);\n }\n }\n\n for (var j = 0, jm = 1; (b.words[0] & jm) === 0 && j < 26; ++j, jm <<= 1);\n if (j > 0) {\n b.iushrn(j);\n while (j-- > 0) {\n if (x2.isOdd()) {\n x2.iadd(delta);\n }\n\n x2.iushrn(1);\n }\n }\n\n if (a.cmp(b) >= 0) {\n a.isub(b);\n x1.isub(x2);\n } else {\n b.isub(a);\n x2.isub(x1);\n }\n }\n\n var res;\n if (a.cmpn(1) === 0) {\n res = x1;\n } else {\n res = x2;\n }\n\n if (res.cmpn(0) < 0) {\n res.iadd(p);\n }\n\n return res;\n };\n\n BN.prototype.gcd = function gcd (num) {\n if (this.isZero()) return num.abs();\n if (num.isZero()) return this.abs();\n\n var a = this.clone();\n var b = num.clone();\n a.negative = 0;\n b.negative = 0;\n\n // Remove common factor of two\n for (var shift = 0; a.isEven() && b.isEven(); shift++) {\n a.iushrn(1);\n b.iushrn(1);\n }\n\n do {\n while (a.isEven()) {\n a.iushrn(1);\n }\n while (b.isEven()) {\n b.iushrn(1);\n }\n\n var r = a.cmp(b);\n if (r < 0) {\n // Swap `a` and `b` to make `a` always bigger than `b`\n var t = a;\n a = b;\n b = t;\n } else if (r === 0 || b.cmpn(1) === 0) {\n break;\n }\n\n a.isub(b);\n } while (true);\n\n return b.iushln(shift);\n };\n\n // Invert number in the field F(num)\n BN.prototype.invm = function invm (num) {\n return this.egcd(num).a.umod(num);\n };\n\n BN.prototype.isEven = function isEven () {\n return (this.words[0] & 1) === 0;\n };\n\n BN.prototype.isOdd = function isOdd () {\n return (this.words[0] & 1) === 1;\n };\n\n // And first word and num\n BN.prototype.andln = function andln (num) {\n return this.words[0] & num;\n };\n\n // Increment at the bit position in-line\n BN.prototype.bincn = function bincn (bit) {\n assert(typeof bit === 'number');\n var r = bit % 26;\n var s = (bit - r) / 26;\n var q = 1 << r;\n\n // Fast case: bit is much higher than all existing words\n if (this.length <= s) {\n this._expand(s + 1);\n this.words[s] |= q;\n return this;\n }\n\n // Add bit and propagate, if needed\n var carry = q;\n for (var i = s; carry !== 0 && i < this.length; i++) {\n var w = this.words[i] | 0;\n w += carry;\n carry = w >>> 26;\n w &= 0x3ffffff;\n this.words[i] = w;\n }\n if (carry !== 0) {\n this.words[i] = carry;\n this.length++;\n }\n return this;\n };\n\n BN.prototype.isZero = function isZero () {\n return this.length === 1 && this.words[0] === 0;\n };\n\n BN.prototype.cmpn = function cmpn (num) {\n var negative = num < 0;\n\n if (this.negative !== 0 && !negative) return -1;\n if (this.negative === 0 && negative) return 1;\n\n this._strip();\n\n var res;\n if (this.length > 1) {\n res = 1;\n } else {\n if (negative) {\n num = -num;\n }\n\n assert(num <= 0x3ffffff, 'Number is too big');\n\n var w = this.words[0] | 0;\n res = w === num ? 0 : w < num ? -1 : 1;\n }\n if (this.negative !== 0) return -res | 0;\n return res;\n };\n\n // Compare two numbers and return:\n // 1 - if `this` > `num`\n // 0 - if `this` == `num`\n // -1 - if `this` < `num`\n BN.prototype.cmp = function cmp (num) {\n if (this.negative !== 0 && num.negative === 0) return -1;\n if (this.negative === 0 && num.negative !== 0) return 1;\n\n var res = this.ucmp(num);\n if (this.negative !== 0) return -res | 0;\n return res;\n };\n\n // Unsigned comparison\n BN.prototype.ucmp = function ucmp (num) {\n // At this point both numbers have the same sign\n if (this.length > num.length) return 1;\n if (this.length < num.length) return -1;\n\n var res = 0;\n for (var i = this.length - 1; i >= 0; i--) {\n var a = this.words[i] | 0;\n var b = num.words[i] | 0;\n\n if (a === b) continue;\n if (a < b) {\n res = -1;\n } else if (a > b) {\n res = 1;\n }\n break;\n }\n return res;\n };\n\n BN.prototype.gtn = function gtn (num) {\n return this.cmpn(num) === 1;\n };\n\n BN.prototype.gt = function gt (num) {\n return this.cmp(num) === 1;\n };\n\n BN.prototype.gten = function gten (num) {\n return this.cmpn(num) >= 0;\n };\n\n BN.prototype.gte = function gte (num) {\n return this.cmp(num) >= 0;\n };\n\n BN.prototype.ltn = function ltn (num) {\n return this.cmpn(num) === -1;\n };\n\n BN.prototype.lt = function lt (num) {\n return this.cmp(num) === -1;\n };\n\n BN.prototype.lten = function lten (num) {\n return this.cmpn(num) <= 0;\n };\n\n BN.prototype.lte = function lte (num) {\n return this.cmp(num) <= 0;\n };\n\n BN.prototype.eqn = function eqn (num) {\n return this.cmpn(num) === 0;\n };\n\n BN.prototype.eq = function eq (num) {\n return this.cmp(num) === 0;\n };\n\n //\n // A reduce context, could be using montgomery or something better, depending\n // on the `m` itself.\n //\n BN.red = function red (num) {\n return new Red(num);\n };\n\n BN.prototype.toRed = function toRed (ctx) {\n assert(!this.red, 'Already a number in reduction context');\n assert(this.negative === 0, 'red works only with positives');\n return ctx.convertTo(this)._forceRed(ctx);\n };\n\n BN.prototype.fromRed = function fromRed () {\n assert(this.red, 'fromRed works only with numbers in reduction context');\n return this.red.convertFrom(this);\n };\n\n BN.prototype._forceRed = function _forceRed (ctx) {\n this.red = ctx;\n return this;\n };\n\n BN.prototype.forceRed = function forceRed (ctx) {\n assert(!this.red, 'Already a number in reduction context');\n return this._forceRed(ctx);\n };\n\n BN.prototype.redAdd = function redAdd (num) {\n assert(this.red, 'redAdd works only with red numbers');\n return this.red.add(this, num);\n };\n\n BN.prototype.redIAdd = function redIAdd (num) {\n assert(this.red, 'redIAdd works only with red numbers');\n return this.red.iadd(this, num);\n };\n\n BN.prototype.redSub = function redSub (num) {\n assert(this.red, 'redSub works only with red numbers');\n return this.red.sub(this, num);\n };\n\n BN.prototype.redISub = function redISub (num) {\n assert(this.red, 'redISub works only with red numbers');\n return this.red.isub(this, num);\n };\n\n BN.prototype.redShl = function redShl (num) {\n assert(this.red, 'redShl works only with red numbers');\n return this.red.shl(this, num);\n };\n\n BN.prototype.redMul = function redMul (num) {\n assert(this.red, 'redMul works only with red numbers');\n this.red._verify2(this, num);\n return this.red.mul(this, num);\n };\n\n BN.prototype.redIMul = function redIMul (num) {\n assert(this.red, 'redMul works only with red numbers');\n this.red._verify2(this, num);\n return this.red.imul(this, num);\n };\n\n BN.prototype.redSqr = function redSqr () {\n assert(this.red, 'redSqr works only with red numbers');\n this.red._verify1(this);\n return this.red.sqr(this);\n };\n\n BN.prototype.redISqr = function redISqr () {\n assert(this.red, 'redISqr works only with red numbers');\n this.red._verify1(this);\n return this.red.isqr(this);\n };\n\n // Square root over p\n BN.prototype.redSqrt = function redSqrt () {\n assert(this.red, 'redSqrt works only with red numbers');\n this.red._verify1(this);\n return this.red.sqrt(this);\n };\n\n BN.prototype.redInvm = function redInvm () {\n assert(this.red, 'redInvm works only with red numbers');\n this.red._verify1(this);\n return this.red.invm(this);\n };\n\n // Return negative clone of `this` % `red modulo`\n BN.prototype.redNeg = function redNeg () {\n assert(this.red, 'redNeg works only with red numbers');\n this.red._verify1(this);\n return this.red.neg(this);\n };\n\n BN.prototype.redPow = function redPow (num) {\n assert(this.red && !num.red, 'redPow(normalNum)');\n this.red._verify1(this);\n return this.red.pow(this, num);\n };\n\n // Prime numbers with efficient reduction\n var primes = {\n k256: null,\n p224: null,\n p192: null,\n p25519: null\n };\n\n // Pseudo-Mersenne prime\n function MPrime (name, p) {\n // P = 2 ^ N - K\n this.name = name;\n this.p = new BN(p, 16);\n this.n = this.p.bitLength();\n this.k = new BN(1).iushln(this.n).isub(this.p);\n\n this.tmp = this._tmp();\n }\n\n MPrime.prototype._tmp = function _tmp () {\n var tmp = new BN(null);\n tmp.words = new Array(Math.ceil(this.n / 13));\n return tmp;\n };\n\n MPrime.prototype.ireduce = function ireduce (num) {\n // Assumes that `num` is less than `P^2`\n // num = HI * (2 ^ N - K) + HI * K + LO = HI * K + LO (mod P)\n var r = num;\n var rlen;\n\n do {\n this.split(r, this.tmp);\n r = this.imulK(r);\n r = r.iadd(this.tmp);\n rlen = r.bitLength();\n } while (rlen > this.n);\n\n var cmp = rlen < this.n ? -1 : r.ucmp(this.p);\n if (cmp === 0) {\n r.words[0] = 0;\n r.length = 1;\n } else if (cmp > 0) {\n r.isub(this.p);\n } else {\n r._strip();\n }\n\n return r;\n };\n\n MPrime.prototype.split = function split (input, out) {\n input.iushrn(this.n, 0, out);\n };\n\n MPrime.prototype.imulK = function imulK (num) {\n return num.imul(this.k);\n };\n\n function K256 () {\n MPrime.call(\n this,\n 'k256',\n 'ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff fffffffe fffffc2f');\n }\n inherits(K256, MPrime);\n\n K256.prototype.split = function split (input, output) {\n // 256 = 9 * 26 + 22\n var mask = 0x3fffff;\n\n var outLen = Math.min(input.length, 9);\n for (var i = 0; i < outLen; i++) {\n output.words[i] = input.words[i];\n }\n output.length = outLen;\n\n if (input.length <= 9) {\n input.words[0] = 0;\n input.length = 1;\n return;\n }\n\n // Shift by 9 limbs\n var prev = input.words[9];\n output.words[output.length++] = prev & mask;\n\n for (i = 10; i < input.length; i++) {\n var next = input.words[i] | 0;\n input.words[i - 10] = ((next & mask) << 4) | (prev >>> 22);\n prev = next;\n }\n prev >>>= 22;\n input.words[i - 10] = prev;\n if (prev === 0 && input.length > 10) {\n input.length -= 10;\n } else {\n input.length -= 9;\n }\n };\n\n K256.prototype.imulK = function imulK (num) {\n // K = 0x1000003d1 = [ 0x40, 0x3d1 ]\n num.words[num.length] = 0;\n num.words[num.length + 1] = 0;\n num.length += 2;\n\n // bounded at: 0x40 * 0x3ffffff + 0x3d0 = 0x100000390\n var lo = 0;\n for (var i = 0; i < num.length; i++) {\n var w = num.words[i] | 0;\n lo += w * 0x3d1;\n num.words[i] = lo & 0x3ffffff;\n lo = w * 0x40 + ((lo / 0x4000000) | 0);\n }\n\n // Fast length reduction\n if (num.words[num.length - 1] === 0) {\n num.length--;\n if (num.words[num.length - 1] === 0) {\n num.length--;\n }\n }\n return num;\n };\n\n function P224 () {\n MPrime.call(\n this,\n 'p224',\n 'ffffffff ffffffff ffffffff ffffffff 00000000 00000000 00000001');\n }\n inherits(P224, MPrime);\n\n function P192 () {\n MPrime.call(\n this,\n 'p192',\n 'ffffffff ffffffff ffffffff fffffffe ffffffff ffffffff');\n }\n inherits(P192, MPrime);\n\n function P25519 () {\n // 2 ^ 255 - 19\n MPrime.call(\n this,\n '25519',\n '7fffffffffffffff ffffffffffffffff ffffffffffffffff ffffffffffffffed');\n }\n inherits(P25519, MPrime);\n\n P25519.prototype.imulK = function imulK (num) {\n // K = 0x13\n var carry = 0;\n for (var i = 0; i < num.length; i++) {\n var hi = (num.words[i] | 0) * 0x13 + carry;\n var lo = hi & 0x3ffffff;\n hi >>>= 26;\n\n num.words[i] = lo;\n carry = hi;\n }\n if (carry !== 0) {\n num.words[num.length++] = carry;\n }\n return num;\n };\n\n // Exported mostly for testing purposes, use plain name instead\n BN._prime = function prime (name) {\n // Cached version of prime\n if (primes[name]) return primes[name];\n\n var prime;\n if (name === 'k256') {\n prime = new K256();\n } else if (name === 'p224') {\n prime = new P224();\n } else if (name === 'p192') {\n prime = new P192();\n } else if (name === 'p25519') {\n prime = new P25519();\n } else {\n throw new Error('Unknown prime ' + name);\n }\n primes[name] = prime;\n\n return prime;\n };\n\n //\n // Base reduction engine\n //\n function Red (m) {\n if (typeof m === 'string') {\n var prime = BN._prime(m);\n this.m = prime.p;\n this.prime = prime;\n } else {\n assert(m.gtn(1), 'modulus must be greater than 1');\n this.m = m;\n this.prime = null;\n }\n }\n\n Red.prototype._verify1 = function _verify1 (a) {\n assert(a.negative === 0, 'red works only with positives');\n assert(a.red, 'red works only with red numbers');\n };\n\n Red.prototype._verify2 = function _verify2 (a, b) {\n assert((a.negative | b.negative) === 0, 'red works only with positives');\n assert(a.red && a.red === b.red,\n 'red works only with red numbers');\n };\n\n Red.prototype.imod = function imod (a) {\n if (this.prime) return this.prime.ireduce(a)._forceRed(this);\n\n move(a, a.umod(this.m)._forceRed(this));\n return a;\n };\n\n Red.prototype.neg = function neg (a) {\n if (a.isZero()) {\n return a.clone();\n }\n\n return this.m.sub(a)._forceRed(this);\n };\n\n Red.prototype.add = function add (a, b) {\n this._verify2(a, b);\n\n var res = a.add(b);\n if (res.cmp(this.m) >= 0) {\n res.isub(this.m);\n }\n return res._forceRed(this);\n };\n\n Red.prototype.iadd = function iadd (a, b) {\n this._verify2(a, b);\n\n var res = a.iadd(b);\n if (res.cmp(this.m) >= 0) {\n res.isub(this.m);\n }\n return res;\n };\n\n Red.prototype.sub = function sub (a, b) {\n this._verify2(a, b);\n\n var res = a.sub(b);\n if (res.cmpn(0) < 0) {\n res.iadd(this.m);\n }\n return res._forceRed(this);\n };\n\n Red.prototype.isub = function isub (a, b) {\n this._verify2(a, b);\n\n var res = a.isub(b);\n if (res.cmpn(0) < 0) {\n res.iadd(this.m);\n }\n return res;\n };\n\n Red.prototype.shl = function shl (a, num) {\n this._verify1(a);\n return this.imod(a.ushln(num));\n };\n\n Red.prototype.imul = function imul (a, b) {\n this._verify2(a, b);\n return this.imod(a.imul(b));\n };\n\n Red.prototype.mul = function mul (a, b) {\n this._verify2(a, b);\n return this.imod(a.mul(b));\n };\n\n Red.prototype.isqr = function isqr (a) {\n return this.imul(a, a.clone());\n };\n\n Red.prototype.sqr = function sqr (a) {\n return this.mul(a, a);\n };\n\n Red.prototype.sqrt = function sqrt (a) {\n if (a.isZero()) return a.clone();\n\n var mod3 = this.m.andln(3);\n assert(mod3 % 2 === 1);\n\n // Fast case\n if (mod3 === 3) {\n var pow = this.m.add(new BN(1)).iushrn(2);\n return this.pow(a, pow);\n }\n\n // Tonelli-Shanks algorithm (Totally unoptimized and slow)\n //\n // Find Q and S, that Q * 2 ^ S = (P - 1)\n var q = this.m.subn(1);\n var s = 0;\n while (!q.isZero() && q.andln(1) === 0) {\n s++;\n q.iushrn(1);\n }\n assert(!q.isZero());\n\n var one = new BN(1).toRed(this);\n var nOne = one.redNeg();\n\n // Find quadratic non-residue\n // NOTE: Max is such because of generalized Riemann hypothesis.\n var lpow = this.m.subn(1).iushrn(1);\n var z = this.m.bitLength();\n z = new BN(2 * z * z).toRed(this);\n\n while (this.pow(z, lpow).cmp(nOne) !== 0) {\n z.redIAdd(nOne);\n }\n\n var c = this.pow(z, q);\n var r = this.pow(a, q.addn(1).iushrn(1));\n var t = this.pow(a, q);\n var m = s;\n while (t.cmp(one) !== 0) {\n var tmp = t;\n for (var i = 0; tmp.cmp(one) !== 0; i++) {\n tmp = tmp.redSqr();\n }\n assert(i < m);\n var b = this.pow(c, new BN(1).iushln(m - i - 1));\n\n r = r.redMul(b);\n c = b.redSqr();\n t = t.redMul(c);\n m = i;\n }\n\n return r;\n };\n\n Red.prototype.invm = function invm (a) {\n var inv = a._invmp(this.m);\n if (inv.negative !== 0) {\n inv.negative = 0;\n return this.imod(inv).redNeg();\n } else {\n return this.imod(inv);\n }\n };\n\n Red.prototype.pow = function pow (a, num) {\n if (num.isZero()) return new BN(1).toRed(this);\n if (num.cmpn(1) === 0) return a.clone();\n\n var windowSize = 4;\n var wnd = new Array(1 << windowSize);\n wnd[0] = new BN(1).toRed(this);\n wnd[1] = a;\n for (var i = 2; i < wnd.length; i++) {\n wnd[i] = this.mul(wnd[i - 1], a);\n }\n\n var res = wnd[0];\n var current = 0;\n var currentLen = 0;\n var start = num.bitLength() % 26;\n if (start === 0) {\n start = 26;\n }\n\n for (i = num.length - 1; i >= 0; i--) {\n var word = num.words[i];\n for (var j = start - 1; j >= 0; j--) {\n var bit = (word >> j) & 1;\n if (res !== wnd[0]) {\n res = this.sqr(res);\n }\n\n if (bit === 0 && current === 0) {\n currentLen = 0;\n continue;\n }\n\n current <<= 1;\n current |= bit;\n currentLen++;\n if (currentLen !== windowSize && (i !== 0 || j !== 0)) continue;\n\n res = this.mul(res, wnd[current]);\n currentLen = 0;\n current = 0;\n }\n start = 26;\n }\n\n return res;\n };\n\n Red.prototype.convertTo = function convertTo (num) {\n var r = num.umod(this.m);\n\n return r === num ? r.clone() : r;\n };\n\n Red.prototype.convertFrom = function convertFrom (num) {\n var res = num.clone();\n res.red = null;\n return res;\n };\n\n //\n // Montgomery method engine\n //\n\n BN.mont = function mont (num) {\n return new Mont(num);\n };\n\n function Mont (m) {\n Red.call(this, m);\n\n this.shift = this.m.bitLength();\n if (this.shift % 26 !== 0) {\n this.shift += 26 - (this.shift % 26);\n }\n\n this.r = new BN(1).iushln(this.shift);\n this.r2 = this.imod(this.r.sqr());\n this.rinv = this.r._invmp(this.m);\n\n this.minv = this.rinv.mul(this.r).isubn(1).div(this.m);\n this.minv = this.minv.umod(this.r);\n this.minv = this.r.sub(this.minv);\n }\n inherits(Mont, Red);\n\n Mont.prototype.convertTo = function convertTo (num) {\n return this.imod(num.ushln(this.shift));\n };\n\n Mont.prototype.convertFrom = function convertFrom (num) {\n var r = this.imod(num.mul(this.rinv));\n r.red = null;\n return r;\n };\n\n Mont.prototype.imul = function imul (a, b) {\n if (a.isZero() || b.isZero()) {\n a.words[0] = 0;\n a.length = 1;\n return a;\n }\n\n var t = a.imul(b);\n var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);\n var u = t.isub(c).iushrn(this.shift);\n var res = u;\n\n if (u.cmp(this.m) >= 0) {\n res = u.isub(this.m);\n } else if (u.cmpn(0) < 0) {\n res = u.iadd(this.m);\n }\n\n return res._forceRed(this);\n };\n\n Mont.prototype.mul = function mul (a, b) {\n if (a.isZero() || b.isZero()) return new BN(0)._forceRed(this);\n\n var t = a.mul(b);\n var c = t.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m);\n var u = t.isub(c).iushrn(this.shift);\n var res = u;\n if (u.cmp(this.m) >= 0) {\n res = u.isub(this.m);\n } else if (u.cmpn(0) < 0) {\n res = u.iadd(this.m);\n }\n\n return res._forceRed(this);\n };\n\n Mont.prototype.invm = function invm (a) {\n // (AR)^-1 * R^2 = (A^-1 * R^-1) * R^2 = A^-1 * R\n var res = this.imod(a._invmp(this.m).mul(this.r2));\n return res._forceRed(this);\n };\n})(typeof module === 'undefined' || module, this);\n","var inherits = require('inherits');\nvar Reporter = require('../base').Reporter;\nvar Buffer = require('buffer').Buffer;\n\nfunction DecoderBuffer(base, options) {\n Reporter.call(this, options);\n if (!Buffer.isBuffer(base)) {\n this.error('Input not Buffer');\n return;\n }\n\n this.base = base;\n this.offset = 0;\n this.length = base.length;\n}\ninherits(DecoderBuffer, Reporter);\nexports.DecoderBuffer = DecoderBuffer;\n\nDecoderBuffer.prototype.save = function save() {\n return { offset: this.offset, reporter: Reporter.prototype.save.call(this) };\n};\n\nDecoderBuffer.prototype.restore = function restore(save) {\n // Return skipped data\n var res = new DecoderBuffer(this.base);\n res.offset = save.offset;\n res.length = this.offset;\n\n this.offset = save.offset;\n Reporter.prototype.restore.call(this, save.reporter);\n\n return res;\n};\n\nDecoderBuffer.prototype.isEmpty = function isEmpty() {\n return this.offset === this.length;\n};\n\nDecoderBuffer.prototype.readUInt8 = function readUInt8(fail) {\n if (this.offset + 1 <= this.length)\n return this.base.readUInt8(this.offset++, true);\n else\n return this.error(fail || 'DecoderBuffer overrun');\n}\n\nDecoderBuffer.prototype.skip = function skip(bytes, fail) {\n if (!(this.offset + bytes <= this.length))\n return this.error(fail || 'DecoderBuffer overrun');\n\n var res = new DecoderBuffer(this.base);\n\n // Share reporter state\n res._reporterState = this._reporterState;\n\n res.offset = this.offset;\n res.length = this.offset + bytes;\n this.offset += bytes;\n return res;\n}\n\nDecoderBuffer.prototype.raw = function raw(save) {\n return this.base.slice(save ? save.offset : this.offset, this.length);\n}\n\nfunction EncoderBuffer(value, reporter) {\n if (Array.isArray(value)) {\n this.length = 0;\n this.value = value.map(function(item) {\n if (!(item instanceof EncoderBuffer))\n item = new EncoderBuffer(item, reporter);\n this.length += item.length;\n return item;\n }, this);\n } else if (typeof value === 'number') {\n if (!(0 <= value && value <= 0xff))\n return reporter.error('non-byte EncoderBuffer value');\n this.value = value;\n this.length = 1;\n } else if (typeof value === 'string') {\n this.value = value;\n this.length = Buffer.byteLength(value);\n } else if (Buffer.isBuffer(value)) {\n this.value = value;\n this.length = value.length;\n } else {\n return reporter.error('Unsupported type: ' + typeof value);\n }\n}\nexports.EncoderBuffer = EncoderBuffer;\n\nEncoderBuffer.prototype.join = function join(out, offset) {\n if (!out)\n out = new Buffer(this.length);\n if (!offset)\n offset = 0;\n\n if (this.length === 0)\n return out;\n\n if (Array.isArray(this.value)) {\n this.value.forEach(function(item) {\n item.join(out, offset);\n offset += item.length;\n });\n } else {\n if (typeof this.value === 'number')\n out[offset] = this.value;\n else if (typeof this.value === 'string')\n out.write(this.value, offset);\n else if (Buffer.isBuffer(this.value))\n this.value.copy(out, offset);\n offset += this.length;\n }\n\n return out;\n};\n","var constants = exports;\n\n// Helper\nconstants._reverse = function reverse(map) {\n var res = {};\n\n Object.keys(map).forEach(function(key) {\n // Convert key to integer if it is stringified\n if ((key | 0) == key)\n key = key | 0;\n\n var value = map[key];\n res[value] = key;\n });\n\n return res;\n};\n\nconstants.der = require('./der');\n","var inherits = require('inherits');\n\nvar asn1 = require('../../asn1');\nvar base = asn1.base;\nvar bignum = asn1.bignum;\n\n// Import DER constants\nvar der = asn1.constants.der;\n\nfunction DERDecoder(entity) {\n this.enc = 'der';\n this.name = entity.name;\n this.entity = entity;\n\n // Construct base tree\n this.tree = new DERNode();\n this.tree._init(entity.body);\n};\nmodule.exports = DERDecoder;\n\nDERDecoder.prototype.decode = function decode(data, options) {\n if (!(data instanceof base.DecoderBuffer))\n data = new base.DecoderBuffer(data, options);\n\n return this.tree._decode(data, options);\n};\n\n// Tree methods\n\nfunction DERNode(parent) {\n base.Node.call(this, 'der', parent);\n}\ninherits(DERNode, base.Node);\n\nDERNode.prototype._peekTag = function peekTag(buffer, tag, any) {\n if (buffer.isEmpty())\n return false;\n\n var state = buffer.save();\n var decodedTag = derDecodeTag(buffer, 'Failed to peek tag: \"' + tag + '\"');\n if (buffer.isError(decodedTag))\n return decodedTag;\n\n buffer.restore(state);\n\n return decodedTag.tag === tag || decodedTag.tagStr === tag ||\n (decodedTag.tagStr + 'of') === tag || any;\n};\n\nDERNode.prototype._decodeTag = function decodeTag(buffer, tag, any) {\n var decodedTag = derDecodeTag(buffer,\n 'Failed to decode tag of \"' + tag + '\"');\n if (buffer.isError(decodedTag))\n return decodedTag;\n\n var len = derDecodeLen(buffer,\n decodedTag.primitive,\n 'Failed to get length of \"' + tag + '\"');\n\n // Failure\n if (buffer.isError(len))\n return len;\n\n if (!any &&\n decodedTag.tag !== tag &&\n decodedTag.tagStr !== tag &&\n decodedTag.tagStr + 'of' !== tag) {\n return buffer.error('Failed to match tag: \"' + tag + '\"');\n }\n\n if (decodedTag.primitive || len !== null)\n return buffer.skip(len, 'Failed to match body of: \"' + tag + '\"');\n\n // Indefinite length... find END tag\n var state = buffer.save();\n var res = this._skipUntilEnd(\n buffer,\n 'Failed to skip indefinite length body: \"' + this.tag + '\"');\n if (buffer.isError(res))\n return res;\n\n len = buffer.offset - state.offset;\n buffer.restore(state);\n return buffer.skip(len, 'Failed to match body of: \"' + tag + '\"');\n};\n\nDERNode.prototype._skipUntilEnd = function skipUntilEnd(buffer, fail) {\n while (true) {\n var tag = derDecodeTag(buffer, fail);\n if (buffer.isError(tag))\n return tag;\n var len = derDecodeLen(buffer, tag.primitive, fail);\n if (buffer.isError(len))\n return len;\n\n var res;\n if (tag.primitive || len !== null)\n res = buffer.skip(len)\n else\n res = this._skipUntilEnd(buffer, fail);\n\n // Failure\n if (buffer.isError(res))\n return res;\n\n if (tag.tagStr === 'end')\n break;\n }\n};\n\nDERNode.prototype._decodeList = function decodeList(buffer, tag, decoder,\n options) {\n var result = [];\n while (!buffer.isEmpty()) {\n var possibleEnd = this._peekTag(buffer, 'end');\n if (buffer.isError(possibleEnd))\n return possibleEnd;\n\n var res = decoder.decode(buffer, 'der', options);\n if (buffer.isError(res) && possibleEnd)\n break;\n result.push(res);\n }\n return result;\n};\n\nDERNode.prototype._decodeStr = function decodeStr(buffer, tag) {\n if (tag === 'bitstr') {\n var unused = buffer.readUInt8();\n if (buffer.isError(unused))\n return unused;\n return { unused: unused, data: buffer.raw() };\n } else if (tag === 'bmpstr') {\n var raw = buffer.raw();\n if (raw.length % 2 === 1)\n return buffer.error('Decoding of string type: bmpstr length mismatch');\n\n var str = '';\n for (var i = 0; i < raw.length / 2; i++) {\n str += String.fromCharCode(raw.readUInt16BE(i * 2));\n }\n return str;\n } else if (tag === 'numstr') {\n var numstr = buffer.raw().toString('ascii');\n if (!this._isNumstr(numstr)) {\n return buffer.error('Decoding of string type: ' +\n 'numstr unsupported characters');\n }\n return numstr;\n } else if (tag === 'octstr') {\n return buffer.raw();\n } else if (tag === 'objDesc') {\n return buffer.raw();\n } else if (tag === 'printstr') {\n var printstr = buffer.raw().toString('ascii');\n if (!this._isPrintstr(printstr)) {\n return buffer.error('Decoding of string type: ' +\n 'printstr unsupported characters');\n }\n return printstr;\n } else if (/str$/.test(tag)) {\n return buffer.raw().toString();\n } else {\n return buffer.error('Decoding of string type: ' + tag + ' unsupported');\n }\n};\n\nDERNode.prototype._decodeObjid = function decodeObjid(buffer, values, relative) {\n var result;\n var identifiers = [];\n var ident = 0;\n while (!buffer.isEmpty()) {\n var subident = buffer.readUInt8();\n ident <<= 7;\n ident |= subident & 0x7f;\n if ((subident & 0x80) === 0) {\n identifiers.push(ident);\n ident = 0;\n }\n }\n if (subident & 0x80)\n identifiers.push(ident);\n\n var first = (identifiers[0] / 40) | 0;\n var second = identifiers[0] % 40;\n\n if (relative)\n result = identifiers;\n else\n result = [first, second].concat(identifiers.slice(1));\n\n if (values) {\n var tmp = values[result.join(' ')];\n if (tmp === undefined)\n tmp = values[result.join('.')];\n if (tmp !== undefined)\n result = tmp;\n }\n\n return result;\n};\n\nDERNode.prototype._decodeTime = function decodeTime(buffer, tag) {\n var str = buffer.raw().toString();\n if (tag === 'gentime') {\n var year = str.slice(0, 4) | 0;\n var mon = str.slice(4, 6) | 0;\n var day = str.slice(6, 8) | 0;\n var hour = str.slice(8, 10) | 0;\n var min = str.slice(10, 12) | 0;\n var sec = str.slice(12, 14) | 0;\n } else if (tag === 'utctime') {\n var year = str.slice(0, 2) | 0;\n var mon = str.slice(2, 4) | 0;\n var day = str.slice(4, 6) | 0;\n var hour = str.slice(6, 8) | 0;\n var min = str.slice(8, 10) | 0;\n var sec = str.slice(10, 12) | 0;\n if (year < 70)\n year = 2000 + year;\n else\n year = 1900 + year;\n } else {\n return buffer.error('Decoding ' + tag + ' time is not supported yet');\n }\n\n return Date.UTC(year, mon - 1, day, hour, min, sec, 0);\n};\n\nDERNode.prototype._decodeNull = function decodeNull(buffer) {\n return null;\n};\n\nDERNode.prototype._decodeBool = function decodeBool(buffer) {\n var res = buffer.readUInt8();\n if (buffer.isError(res))\n return res;\n else\n return res !== 0;\n};\n\nDERNode.prototype._decodeInt = function decodeInt(buffer, values) {\n // Bigint, return as it is (assume big endian)\n var raw = buffer.raw();\n var res = new bignum(raw);\n\n if (values)\n res = values[res.toString(10)] || res;\n\n return res;\n};\n\nDERNode.prototype._use = function use(entity, obj) {\n if (typeof entity === 'function')\n entity = entity(obj);\n return entity._getDecoder('der').tree;\n};\n\n// Utility methods\n\nfunction derDecodeTag(buf, fail) {\n var tag = buf.readUInt8(fail);\n if (buf.isError(tag))\n return tag;\n\n var cls = der.tagClass[tag >> 6];\n var primitive = (tag & 0x20) === 0;\n\n // Multi-octet tag - load\n if ((tag & 0x1f) === 0x1f) {\n var oct = tag;\n tag = 0;\n while ((oct & 0x80) === 0x80) {\n oct = buf.readUInt8(fail);\n if (buf.isError(oct))\n return oct;\n\n tag <<= 7;\n tag |= oct & 0x7f;\n }\n } else {\n tag &= 0x1f;\n }\n var tagStr = der.tag[tag];\n\n return {\n cls: cls,\n primitive: primitive,\n tag: tag,\n tagStr: tagStr\n };\n}\n\nfunction derDecodeLen(buf, primitive, fail) {\n var len = buf.readUInt8(fail);\n if (buf.isError(len))\n return len;\n\n // Indefinite form\n if (!primitive && len === 0x80)\n return null;\n\n // Definite form\n if ((len & 0x80) === 0) {\n // Short form\n return len;\n }\n\n // Long form\n var num = len & 0x7f;\n if (num > 4)\n return buf.error('length octect is too long');\n\n len = 0;\n for (var i = 0; i < num; i++) {\n len <<= 8;\n var j = buf.readUInt8(fail);\n if (buf.isError(j))\n return j;\n len |= j;\n }\n\n return len;\n}\n","var inherits = require('inherits');\nvar Buffer = require('buffer').Buffer;\n\nvar asn1 = require('../../asn1');\nvar base = asn1.base;\n\n// Import DER constants\nvar der = asn1.constants.der;\n\nfunction DEREncoder(entity) {\n this.enc = 'der';\n this.name = entity.name;\n this.entity = entity;\n\n // Construct base tree\n this.tree = new DERNode();\n this.tree._init(entity.body);\n};\nmodule.exports = DEREncoder;\n\nDEREncoder.prototype.encode = function encode(data, reporter) {\n return this.tree._encode(data, reporter).join();\n};\n\n// Tree methods\n\nfunction DERNode(parent) {\n base.Node.call(this, 'der', parent);\n}\ninherits(DERNode, base.Node);\n\nDERNode.prototype._encodeComposite = function encodeComposite(tag,\n primitive,\n cls,\n content) {\n var encodedTag = encodeTag(tag, primitive, cls, this.reporter);\n\n // Short form\n if (content.length < 0x80) {\n var header = new Buffer(2);\n header[0] = encodedTag;\n header[1] = content.length;\n return this._createEncoderBuffer([ header, content ]);\n }\n\n // Long form\n // Count octets required to store length\n var lenOctets = 1;\n for (var i = content.length; i >= 0x100; i >>= 8)\n lenOctets++;\n\n var header = new Buffer(1 + 1 + lenOctets);\n header[0] = encodedTag;\n header[1] = 0x80 | lenOctets;\n\n for (var i = 1 + lenOctets, j = content.length; j > 0; i--, j >>= 8)\n header[i] = j & 0xff;\n\n return this._createEncoderBuffer([ header, content ]);\n};\n\nDERNode.prototype._encodeStr = function encodeStr(str, tag) {\n if (tag === 'bitstr') {\n return this._createEncoderBuffer([ str.unused | 0, str.data ]);\n } else if (tag === 'bmpstr') {\n var buf = new Buffer(str.length * 2);\n for (var i = 0; i < str.length; i++) {\n buf.writeUInt16BE(str.charCodeAt(i), i * 2);\n }\n return this._createEncoderBuffer(buf);\n } else if (tag === 'numstr') {\n if (!this._isNumstr(str)) {\n return this.reporter.error('Encoding of string type: numstr supports ' +\n 'only digits and space');\n }\n return this._createEncoderBuffer(str);\n } else if (tag === 'printstr') {\n if (!this._isPrintstr(str)) {\n return this.reporter.error('Encoding of string type: printstr supports ' +\n 'only latin upper and lower case letters, ' +\n 'digits, space, apostrophe, left and rigth ' +\n 'parenthesis, plus sign, comma, hyphen, ' +\n 'dot, slash, colon, equal sign, ' +\n 'question mark');\n }\n return this._createEncoderBuffer(str);\n } else if (/str$/.test(tag)) {\n return this._createEncoderBuffer(str);\n } else if (tag === 'objDesc') {\n return this._createEncoderBuffer(str);\n } else {\n return this.reporter.error('Encoding of string type: ' + tag +\n ' unsupported');\n }\n};\n\nDERNode.prototype._encodeObjid = function encodeObjid(id, values, relative) {\n if (typeof id === 'string') {\n if (!values)\n return this.reporter.error('string objid given, but no values map found');\n if (!values.hasOwnProperty(id))\n return this.reporter.error('objid not found in values map');\n id = values[id].split(/[\\s\\.]+/g);\n for (var i = 0; i < id.length; i++)\n id[i] |= 0;\n } else if (Array.isArray(id)) {\n id = id.slice();\n for (var i = 0; i < id.length; i++)\n id[i] |= 0;\n }\n\n if (!Array.isArray(id)) {\n return this.reporter.error('objid() should be either array or string, ' +\n 'got: ' + JSON.stringify(id));\n }\n\n if (!relative) {\n if (id[1] >= 40)\n return this.reporter.error('Second objid identifier OOB');\n id.splice(0, 2, id[0] * 40 + id[1]);\n }\n\n // Count number of octets\n var size = 0;\n for (var i = 0; i < id.length; i++) {\n var ident = id[i];\n for (size++; ident >= 0x80; ident >>= 7)\n size++;\n }\n\n var objid = new Buffer(size);\n var offset = objid.length - 1;\n for (var i = id.length - 1; i >= 0; i--) {\n var ident = id[i];\n objid[offset--] = ident & 0x7f;\n while ((ident >>= 7) > 0)\n objid[offset--] = 0x80 | (ident & 0x7f);\n }\n\n return this._createEncoderBuffer(objid);\n};\n\nfunction two(num) {\n if (num < 10)\n return '0' + num;\n else\n return num;\n}\n\nDERNode.prototype._encodeTime = function encodeTime(time, tag) {\n var str;\n var date = new Date(time);\n\n if (tag === 'gentime') {\n str = [\n two(date.getFullYear()),\n two(date.getUTCMonth() + 1),\n two(date.getUTCDate()),\n two(date.getUTCHours()),\n two(date.getUTCMinutes()),\n two(date.getUTCSeconds()),\n 'Z'\n ].join('');\n } else if (tag === 'utctime') {\n str = [\n two(date.getFullYear() % 100),\n two(date.getUTCMonth() + 1),\n two(date.getUTCDate()),\n two(date.getUTCHours()),\n two(date.getUTCMinutes()),\n two(date.getUTCSeconds()),\n 'Z'\n ].join('');\n } else {\n this.reporter.error('Encoding ' + tag + ' time is not supported yet');\n }\n\n return this._encodeStr(str, 'octstr');\n};\n\nDERNode.prototype._encodeNull = function encodeNull() {\n return this._createEncoderBuffer('');\n};\n\nDERNode.prototype._encodeInt = function encodeInt(num, values) {\n if (typeof num === 'string') {\n if (!values)\n return this.reporter.error('String int or enum given, but no values map');\n if (!values.hasOwnProperty(num)) {\n return this.reporter.error('Values map doesn\\'t contain: ' +\n JSON.stringify(num));\n }\n num = values[num];\n }\n\n // Bignum, assume big endian\n if (typeof num !== 'number' && !Buffer.isBuffer(num)) {\n var numArray = num.toArray();\n if (!num.sign && numArray[0] & 0x80) {\n numArray.unshift(0);\n }\n num = new Buffer(numArray);\n }\n\n if (Buffer.isBuffer(num)) {\n var size = num.length;\n if (num.length === 0)\n size++;\n\n var out = new Buffer(size);\n num.copy(out);\n if (num.length === 0)\n out[0] = 0\n return this._createEncoderBuffer(out);\n }\n\n if (num < 0x80)\n return this._createEncoderBuffer(num);\n\n if (num < 0x100)\n return this._createEncoderBuffer([0, num]);\n\n var size = 1;\n for (var i = num; i >= 0x100; i >>= 8)\n size++;\n\n var out = new Array(size);\n for (var i = out.length - 1; i >= 0; i--) {\n out[i] = num & 0xff;\n num >>= 8;\n }\n if(out[0] & 0x80) {\n out.unshift(0);\n }\n\n return this._createEncoderBuffer(new Buffer(out));\n};\n\nDERNode.prototype._encodeBool = function encodeBool(value) {\n return this._createEncoderBuffer(value ? 0xff : 0);\n};\n\nDERNode.prototype._use = function use(entity, obj) {\n if (typeof entity === 'function')\n entity = entity(obj);\n return entity._getEncoder('der').tree;\n};\n\nDERNode.prototype._skipDefault = function skipDefault(dataBuffer, reporter, parent) {\n var state = this._baseState;\n var i;\n if (state['default'] === null)\n return false;\n\n var data = dataBuffer.join();\n if (state.defaultBuffer === undefined)\n state.defaultBuffer = this._encodeValue(state['default'], reporter, parent).join();\n\n if (data.length !== state.defaultBuffer.length)\n return false;\n\n for (i=0; i < data.length; i++)\n if (data[i] !== state.defaultBuffer[i])\n return false;\n\n return true;\n};\n\n// Utility methods\n\nfunction encodeTag(tag, primitive, cls, reporter) {\n var res;\n\n if (tag === 'seqof')\n tag = 'seq';\n else if (tag === 'setof')\n tag = 'set';\n\n if (der.tagByName.hasOwnProperty(tag))\n res = der.tagByName[tag];\n else if (typeof tag === 'number' && (tag | 0) === tag)\n res = tag;\n else\n return reporter.error('Unknown tag: ' + tag);\n\n if (res >= 0x1f)\n return reporter.error('Multi-octet tag encoding unsupported');\n\n if (!primitive)\n res |= 0x20;\n\n res |= (der.tagClassByName[cls || 'universal'] << 6);\n\n return res;\n}\n","var createHash = require('create-hash')\nvar Buffer = require('safe-buffer').Buffer\n\nmodule.exports = function (seed, len) {\n var t = Buffer.alloc(0)\n var i = 0\n var c\n while (t.length < len) {\n c = i2ops(i++)\n t = Buffer.concat([t, createHash('sha1').update(seed).update(c).digest()])\n }\n return t.slice(0, len)\n}\n\nfunction i2ops (c) {\n var out = Buffer.allocUnsafe(4)\n out.writeUInt32BE(c, 0)\n return out\n}\n","module.exports = function xor (a, b) {\n var len = a.length\n var i = -1\n while (++i < len) {\n a[i] ^= b[i]\n }\n return a\n}\n","var BN = require('bn.js')\nvar Buffer = require('safe-buffer').Buffer\n\nfunction withPublic (paddedMsg, key) {\n return Buffer.from(paddedMsg\n .toRed(BN.mont(key.modulus))\n .redPow(new BN(key.publicExponent))\n .fromRed()\n .toArray())\n}\n\nmodule.exports = withPublic\n","'use strict'\n\n/**\n * Export all library models.\n * \n * See the full model specification: http://moneroecosystem.org/monero-java/monero-spec.pdf\n */\nmodule.exports = {};\n\n// export common models\nmodule.exports.GenUtils = require(\"./src/main/js/common/GenUtils\");\nmodule.exports.BigInteger = require(\"./src/main/js/common/biginteger\").BigInteger;\nmodule.exports.Filter = require(\"./src/main/js/common/Filter\");\nmodule.exports.MoneroError = require(\"./src/main/js/common/MoneroError\");\nmodule.exports.HttpClient = require(\"./src/main/js/common/HttpClient\");\nmodule.exports.LibraryUtils = require(\"./src/main/js/common/LibraryUtils\");\nmodule.exports.MoneroRpcConnection = require(\"./src/main/js/common/MoneroRpcConnection\");\nmodule.exports.MoneroRpcError = require(\"./src/main/js/common/MoneroRpcError\");\nmodule.exports.SslOptions = require(\"./src/main/js/common/SslOptions\");\n\n// export daemon models\nmodule.exports.ConnectionType = require(\"./src/main/js/daemon/model/ConnectionType\");\nmodule.exports.MoneroAltChain = require(\"./src/main/js/daemon/model/MoneroAltChain\");\nmodule.exports.MoneroBan = require(\"./src/main/js/daemon/model/MoneroBan\");\nmodule.exports.MoneroBlockHeader = require(\"./src/main/js/daemon/model/MoneroBlockHeader\");\nmodule.exports.MoneroBlock = require(\"./src/main/js/daemon/model/MoneroBlock\");\nmodule.exports.MoneroBlockTemplate = require(\"./src/main/js/daemon/model/MoneroBlockTemplate\");\nmodule.exports.MoneroDaemonConnection = require(\"./src/main/js/daemon/model/MoneroDaemonConnection\");\nmodule.exports.MoneroDaemonConnectionSpan = require(\"./src/main/js/daemon/model/MoneroDaemonConnectionSpan\");\nmodule.exports.MoneroDaemonInfo = require(\"./src/main/js/daemon/model/MoneroDaemonInfo\");\nmodule.exports.MoneroDaemonPeer = require(\"./src/main/js/daemon/model/MoneroDaemonPeer\");\nmodule.exports.MoneroDaemonSyncInfo = require(\"./src/main/js/daemon/model/MoneroDaemonSyncInfo\");\nmodule.exports.MoneroDaemonUpdateCheckResult = require(\"./src/main/js/daemon/model/MoneroDaemonUpdateCheckResult\");\nmodule.exports.MoneroDaemonUpdateDownloadResult = require(\"./src/main/js/daemon/model/MoneroDaemonUpdateDownloadResult\");\nmodule.exports.MoneroHardForkInfo = require(\"./src/main/js/daemon/model/MoneroHardForkInfo\");\nmodule.exports.MoneroKeyImage = require(\"./src/main/js/daemon/model/MoneroKeyImage\");\nmodule.exports.MoneroKeyImageSpentStatus = require(\"./src/main/js/daemon/model/MoneroKeyImageSpentStatus\");\nmodule.exports.MoneroMinerTxSum = require(\"./src/main/js/daemon/model/MoneroMinerTxSum\");\nmodule.exports.MoneroMiningStatus = require(\"./src/main/js/daemon/model/MoneroMiningStatus\");\nmodule.exports.MoneroNetworkType = require(\"./src/main/js/daemon/model/MoneroNetworkType\");\nmodule.exports.MoneroOutput = require(\"./src/main/js/daemon/model/MoneroOutput\");\nmodule.exports.MoneroOutputHistogramEntry = require(\"./src/main/js/daemon/model/MoneroOutputHistogramEntry\");\nmodule.exports.MoneroSubmitTxResult = require(\"./src/main/js/daemon/model/MoneroSubmitTxResult\");\nmodule.exports.MoneroTx = require(\"./src/main/js/daemon/model/MoneroTx\");\nmodule.exports.MoneroTxPoolStats = require(\"./src/main/js/daemon/model/MoneroTxPoolStats\");\nmodule.exports.MoneroVersion = require(\"./src/main/js/daemon/model/MoneroVersion\");\n\n// export wallet models\nmodule.exports.MoneroAccount = require(\"./src/main/js/wallet/model/MoneroAccount\");\nmodule.exports.MoneroAccountTag = require(\"./src/main/js/wallet/model/MoneroAccountTag\");\nmodule.exports.MoneroAddressBookEntry = require(\"./src/main/js/wallet/model/MoneroAddressBookEntry\");\nmodule.exports.MoneroCheck = require(\"./src/main/js/wallet/model/MoneroCheck\");\nmodule.exports.MoneroCheckReserve = require(\"./src/main/js/wallet/model/MoneroCheckReserve\");\nmodule.exports.MoneroCheckTx = require(\"./src/main/js/wallet/model/MoneroCheckTx\");\nmodule.exports.MoneroDestination = require(\"./src/main/js/wallet/model/MoneroDestination\");\nmodule.exports.MoneroIntegratedAddress = require(\"./src/main/js/wallet/model/MoneroIntegratedAddress\");\nmodule.exports.MoneroKeyImageImportResult = require(\"./src/main/js/wallet/model/MoneroKeyImageImportResult\");\nmodule.exports.MoneroMultisigInfo = require(\"./src/main/js/wallet/model/MoneroMultisigInfo\");\nmodule.exports.MoneroMultisigInitResult = require(\"./src/main/js/wallet/model/MoneroMultisigInitResult\");\nmodule.exports.MoneroMultisigSignResult = require(\"./src/main/js/wallet/model/MoneroMultisigSignResult\");\nmodule.exports.MoneroOutputWallet = require(\"./src/main/js/wallet/model/MoneroOutputWallet\");\nmodule.exports.MoneroOutputQuery = require(\"./src/main/js/wallet/model/MoneroOutputQuery\");\nmodule.exports.MoneroTxPriority = require(\"./src/main/js/wallet/model/MoneroTxPriority\");\nmodule.exports.MoneroTxConfig = require(\"./src/main/js/wallet/model/MoneroTxConfig\");\nmodule.exports.MoneroSubaddress = require(\"./src/main/js/wallet/model/MoneroSubaddress\");\nmodule.exports.MoneroSyncResult = require(\"./src/main/js/wallet/model/MoneroSyncResult\");\nmodule.exports.MoneroTransfer = require(\"./src/main/js/wallet/model/MoneroTransfer\");\nmodule.exports.MoneroIncomingTransfer = require(\"./src/main/js/wallet/model/MoneroIncomingTransfer\");\nmodule.exports.MoneroOutgoingTransfer = require(\"./src/main/js/wallet/model/MoneroOutgoingTransfer\");\nmodule.exports.MoneroTransferQuery = require(\"./src/main/js/wallet/model/MoneroTransferQuery\");\nmodule.exports.MoneroTxSet = require(\"./src/main/js/wallet/model/MoneroTxSet\");\nmodule.exports.MoneroTxWallet = require(\"./src/main/js/wallet/model/MoneroTxWallet\");\nmodule.exports.MoneroTxQuery = require(\"./src/main/js/wallet/model/MoneroTxQuery\");\nmodule.exports.MoneroWalletListener = require(\"./src/main/js/wallet/model/MoneroWalletListener\");\nmodule.exports.MoneroWalletConfig = require(\"./src/main/js/wallet/model/MoneroWalletConfig\");\n\n// export daemon, wallet, and utils classes\nmodule.exports.MoneroUtils = require(\"./src/main/js/common/MoneroUtils\");\nmodule.exports.MoneroDaemon = require(\"./src/main/js/daemon/MoneroDaemon\");\nmodule.exports.MoneroWallet = require(\"./src/main/js/wallet/MoneroWallet\");\nmodule.exports.MoneroDaemonRpc = require(\"./src/main/js/daemon/MoneroDaemonRpc\");\nmodule.exports.MoneroWalletRpc = require(\"./src/main/js/wallet/MoneroWalletRpc\");\nmodule.exports.MoneroWalletKeys = require(\"./src/main/js/wallet/MoneroWalletKeys\");\nmodule.exports.MoneroWalletWasm = require(\"./src/main/js/wallet/MoneroWalletWasm\");\n\n// ---------------------------- GLOBAL FUNCTIONS ------------------------------\n\n/**\n *

Create a client connected to monero-daemon-rpc.

\n * \n *

Examples:

\n * \n * \n * let daemon = monerojs.connectToDaemonRpc(\"http://localhost:38081\", \"superuser\", \"abctesting123\");

\n * \n * let daemon = monerojs.connectToDaemonRpc({
\n *    uri: \"http://localhost:38081\",
\n *    username: \"superuser\",
\n *    password: \"abctesting123\"
\n * });\n *
\n * \n * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - uri of monero-daemon-rpc or JS config object or MoneroRpcConnection\n * @param {string} uriOrConfigOrConnection.uri - uri of monero-daemon-rpc\n * @param {string} uriOrConfigOrConnection.username - username to authenticate with monero-daemon-rpc (optional)\n * @param {string} uriOrConfigOrConnection.password - password to authenticate with monero-daemon-rpc (optional)\n * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true)\n * @param {number} uriOrConfigOrConnection.pollInterval - poll interval to query for updates in ms (default 5000)\n * @param {boolean} uriOrConfigOrConnection.proxyToWorker - run the daemon client in a web worker if true (default true if browser, false otherwise)\n * @param {string} username - username to authenticate with monero-daemon-rpc (optional)\n * @param {string} password - password to authenticate with monero-daemon-rpc (optional)\n * @param {boolean} rejectUnauthorized - rejects self-signed certificates if true (default true)\n * @param {number} pollInterval - poll interval to query for updates in ms (default 5000)\n * @param {boolean} proxyToWorker - runs the daemon client in a web worker if true (default true if browser, false otherwise)\n * @return {MoneroDaemonRpc} the daemon RPC client\n */\nmodule.exports.connectToDaemonRpc = function() { return new module.exports.MoneroDaemonRpc(...arguments); }\n\n/**\n *

Create a client connected to monero-wallet-rpc.

\n * \n *

Examples:

\n * \n * \n * let walletRpc = monerojs.connectToWalletRpc(\"http://localhost:38081\", \"superuser\", \"abctesting123\");

\n * \n * let walletRpc = monerojs.connectToWalletRpc({
\n *    uri: \"http://localhost:38081\",
\n *    username: \"superuser\",
\n *    password: \"abctesting123\",
\n *    rejectUnauthorized: false // e.g. local development
\n * });\n *
\n * \n * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - uri of monero-wallet-rpc or JS config object or MoneroRpcConnection\n * @param {string} uriOrConfigOrConnection.uri - uri of monero-wallet-rpc\n * @param {string} uriOrConfigOrConnection.username - username to authenticate with monero-wallet-rpc (optional)\n * @param {string} uriOrConfigOrConnection.password - password to authenticate with monero-wallet-rpc (optional)\n * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true)\n * @param {string} username - username to authenticate with monero-wallet-rpc (optional)\n * @param {string} password - password to authenticate with monero-wallet-rpc (optional)\n * @param {boolean} rejectUnauthorized - rejects self-signed certificates if true (default true)\n * @return {MoneroWalletRpc} the wallet RPC client\n */\nmodule.exports.connectToWalletRpc = function() { return new module.exports.MoneroWalletRpc(...arguments); }\n\n/**\n *

Create a wallet using WebAssembly bindings to monero-core.

\n * \n *

Example:

\n * \n * \n * let wallet = await monerojs.createWalletWasm({
\n *    path: \"./test_wallets/wallet1\", // leave blank for in-memory wallet
\n *    password: \"supersecretpassword\",
\n *    networkType: MoneroNetworkType.STAGENET,
\n *    mnemonic: \"coexist igloo pamphlet lagoon...\",
\n *    restoreHeight: 1543218,
\n *    server: new monerojs.MoneroRpcConnection(\"http://localhost:38081\", \"daemon_user\", \"daemon_password_123\"),
\n * });\n *
\n * \n * @param {object|MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object\n * @param {string} config.path - path of the wallet to create (optional, in-memory wallet if not given)\n * @param {string} config.password - password of the wallet to create\n * @param {string|number} config.networkType - network type of the wallet to create (one of \"mainnet\", \"testnet\", \"stagenet\" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)\n * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)\n * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase\n * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys)\n * @param {string} config.privateViewKey - private view key of the wallet to create (optional)\n * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional)\n * @param {number} config.restoreHeight - block height to start scanning frsom (defaults to 0 unless generating random wallet)\n * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to \"English\" or auto-detected)\n * @param {string} config.serverUri - uri of the wallet's daemon (optional)\n * @param {string} config.serverUsername - username to authenticate with the daemon (optional)\n * @param {string} config.serverPassword - password to authenticate with the daemon (optional)\n * @param {boolean} config.rejectUnauthorized - reject self-signed server certificates if true (defaults to true)\n * @param {MoneroRpcConnection|object} config.server - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional)\n * @param {boolean} config.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)\n * @param {fs} config.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)\n * @return {MoneroWalletWasm} the created wallet\n */\nmodule.exports.createWalletWasm = function() { return module.exports.MoneroWalletWasm.createWallet(...arguments); }\n\n/**\n *

Open an existing wallet using WebAssembly bindings to monero-core.

\n * \n *

Examples:

\n * \n * \n * let wallet1 = await monerojs.openWalletWasm(
\n *    \"./wallets/wallet1\",
\n *    \"supersecretpassword\",
\n *    MoneroNetworkType.STAGENET,
\n *    \"http://localhost:38081\" // daemon uri
\n * );

\n * \n * let wallet2 = await monerojs.openWalletWasm({
\n *    path: \"./wallets/wallet2\",
\n *    password: \"supersecretpassword\",
\n *    networkType: MoneroNetworkType.STAGENET,
\n *    serverUri: \"http://localhost:38081\", // daemon configuration
\n *    serverUsername: \"superuser\",
\n *    serverPassword: \"abctesting123\"
\n * });\n *
\n * \n * @param {MoneroWalletConfig|object|string} configOrPath - MoneroWalletConfig or equivalent config object or a path to a wallet to open\n * @param {string} configOrPath.path - path of the wallet to open (optional if 'keysData' provided)\n * @param {string} configOrPath.password - password of the wallet to open\n * @param {string|number} configOrPath.networkType - network type of the wallet to open (one of \"mainnet\", \"testnet\", \"stagenet\" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)\n * @param {Uint8Array} configOrPath.keysData - wallet keys data to open (optional if path provided)\n * @param {Uint8Array} configOrPath.cacheData - wallet cache data to open (optional)\n * @param {string} configOrPath.serverUri - uri of the wallet's daemon (optional)\n * @param {string} configOrPath.serverUsername - username to authenticate with the daemon (optional)\n * @param {string} configOrPath.serverPassword - password to authenticate with the daemon (optional)\n * @param {boolean} configOrPath.rejectUnauthorized - reject self-signed server certificates if true (defaults to true)\n * @param {MoneroRpcConnection|object} configOrPath.server - MoneroRpcConnection or equivalent JS object configuring the daemon connection (optional)\n * @param {boolean} configOrPath.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)\n * @param {fs} configOrPath.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)\n * @param {string} password - password of the wallet to open\n * @param {string|number} networkType - network type of the wallet to open\n * @param {string|MoneroRpcConnection} daemonUriOrConnection - daemon URI or MoneroRpcConnection\n * @param {boolean} proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)\n * @param {fs} fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)\n * @return {MoneroWalletWasm} the opened wallet\n */\nmodule.exports.openWalletWasm = function() { return module.exports.MoneroWalletWasm.openWallet(...arguments); }\n\n/**\n *

Create a wallet using WebAssembly bindings to monero-core.

\n * \n *

Example:

\n * \n * \n * let wallet = await monerojs.createWalletKeys({
\n *    password: \"abc123\",
\n *    networkType: MoneroNetworkType.STAGENET,
\n *    mnemonic: \"coexist igloo pamphlet lagoon...\"
\n * });\n *
\n * \n * @param {MoneroWalletConfig|object} config - MoneroWalletConfig or equivalent config object\n * @param {string|number} config.networkType - network type of the wallet to create (one of \"mainnet\", \"testnet\", \"stagenet\" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)\n * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)\n * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase\n * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys)\n * @param {string} config.privateViewKey - private view key of the wallet to create (optional)\n * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional)\n * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to \"English\" or auto-detected)\n * @return {MoneroWalletKeys} the created wallet\n */\nmodule.exports.createWalletKeys = function() { return module.exports.MoneroWalletKeys.createWallet(...arguments); }\n","const MoneroUtils = require(\"./MoneroUtils\");\nconst PromiseThrottle = require(\"promise-throttle\");\nconst Request = require(\"request-promise\");\n\n/**\n * Handle HTTP requests with a uniform interface.\n * \n * @hideconstructor\n */\nclass HttpClient {\n \n /**\n *

Make a HTTP request.

\n * \n * @param {object} request - configures the request to make\n * @param {string} request.method - HTTP method (\"GET\", \"PUT\", \"POST\", \"DELETE\", etc)\n * @param {string} request.uri - uri to request\n * @param {string|object|Uint8Array} request.body - request body\n * @param {string} request.username - username to authenticate the request (optional)\n * @param {string} request.password - password to authenticate the request (optional)\n * @param {object} request.headers - headers to add to the request (optional)\n * @param {string} request.requestApi - one of \"fetch\" or \"xhr\" (default \"fetch\")\n * @param {boolean} request.resolveWithFullResponse - return full response if true, else body only (default false)\n * @param {boolean} request.rejectUnauthorized - whether or not to reject self-signed certificates (default true)\n * @returns {object} response - the response object\n * @returns {string|object|Uint8Array} response.body - the response body\n * @returns {number} response.statusCode - the response code\n * @returns {number} response.statusText - the response message\n * @returns {object} response.headers - the response headers\n */\n static async request(request) {\n \n // assign defaults\n request = Object.assign(HttpClient.DEFAULT_REQUEST, request);\n \n // validate request\n try { new URL(request.uri); } catch (e) { throw new Error(\"Invalid request URL: \" + request.uri); }\n if (request.body && !(typeof request.body === \"string\" || typeof request.body === \"object\")) {\n throw new Error(\"Request body type is not string or object\");\n }\n \n // initialize promise throttle one time\n if (!HttpClient.PROMISE_THROTTLE) {\n HttpClient.PROMISE_THROTTLE = new PromiseThrottle({\n requestsPerSecond: MoneroUtils.MAX_REQUESTS_PER_SECOND,\n promiseImplementation: Promise\n });\n }\n \n // request using fetch or xhr\n return request.requestApi === \"fetch\" ? HttpClient._requestFetch(request) : HttpClient._requestXhr(request);\n }\n \n // ----------------------------- PRIVATE HELPERS ----------------------------\n \n static async _requestFetch(req) {\n \n // build request options\n let opts = {\n method: req.method,\n uri: req.uri,\n body: req.body,\n agent: req.uri.startsWith(\"https\") ? HttpClient._getHttpsAgent() : HttpClient._getHttpAgent(),\n rejectUnauthorized: req.rejectUnauthorized,\n resolveWithFullResponse: req.resolveWithFullResponse,\n requestCert: true // TODO: part of config?\n };\n if (req.username) {\n opts.forever = true;\n opts.auth = {\n user: req.username,\n pass: req.password,\n sendImmediately: false\n }\n }\n if (req.body instanceof Uint8Array) opts.encoding = null;\n \n // queue and throttle request to execute in serial and rate limited\n let resp = await HttpClient._queueTask(async function() {\n return HttpClient.PROMISE_THROTTLE.add(function(opts) { return Request(opts); }.bind(this, opts));\n });\n \n // normalize response\n let normalizedResponse = {};\n if (req.resolveWithFullResponse) {\n normalizedResponse.statusCode = resp.statusCode;\n normalizedResponse.statusText = resp.statusMessage;\n normalizedResponse.headers = resp.headers;\n normalizedResponse.body = resp.body;\n } else {\n normalizedResponse.body = resp;\n }\n return normalizedResponse;\n }\n \n static async _requestXhr(req) {\n if (req.headers) throw new Error(\"Custom headers not implemented in XHR request\"); // TODO\n \n // collect params from request which change on await\n let method = req.method;\n let uri = req.uri;\n let username = req.username;\n let password = req.password;\n let body = req.body;\n let isBinary = body instanceof Uint8Array;\n \n // queue and throttle request to execute in serial and rate limited\n let resp = await HttpClient._queueTask(async function() {\n return HttpClient.PROMISE_THROTTLE.add(function() {\n return new Promise(function(resolve, reject) {\n let digestAuthRequest = new HttpClient.digestAuthRequest(method, uri, username, password);\n digestAuthRequest.request(function(resp) {\n resolve(resp);\n }, function(resp) {\n if (resp.status) resolve(resp);\n else reject(new Error(\"Request failed without response: \" + method + \" \" + uri));\n }, body);\n });\n }.bind(this));\n });\n \n // normalize response\n let normalizedResponse = {};\n normalizedResponse.statusCode = resp.status;\n normalizedResponse.statusText = resp.statusText;\n normalizedResponse.headers = HttpClient._parseXhrResponseHeaders(resp.getAllResponseHeaders());\n normalizedResponse.body = isBinary ? new Uint8Array(resp.response) : resp.response;\n if (normalizedResponse.body instanceof ArrayBuffer) normalizedResponse.body = new Uint8Array(normalizedResponse.body); // handle empty binary request\n return normalizedResponse;\n }\n \n /**\n * Executes given tasks serially (first in, first out).\n * \n * @param {function} asyncFn is an asynchronous function to execute after previously given tasks\n */\n static async _queueTask(asyncFn) {\n \n // initialize task queue one time\n if (!HttpClient.TASK_QUEUE) {\n const async = require(\"async\");\n HttpClient.TASK_QUEUE = async.queue(function(asyncFn, callback) {\n if (asyncFn.then) asyncFn.then(resp => { callback(resp); }).catch(err => { callback(undefined, err); });\n else asyncFn().then(resp => { callback(resp); }).catch(err => { callback(undefined, err); });\n }, 1);\n }\n \n // return promise which resolves when task is executed\n return new Promise(function(resolve, reject) {\n HttpClient.TASK_QUEUE.push(asyncFn, function(resp, err) {\n if (err !== undefined) reject(err);\n else resolve(resp);\n });\n });\n }\n \n /**\n * Get a singleton instance of an HTTP client to share.\n * \n * @return {http.Agent} a shared agent for network requests among library instances\n */\n static _getHttpAgent() {\n if (!HttpClient.HTTP_AGENT) {\n let http = require('http');\n HttpClient.HTTP_AGENT = new http.Agent({keepAlive: true});\n }\n return HttpClient.HTTP_AGENT;\n }\n \n /**\n * Get a singleton instance of an HTTPS client to share.\n * \n * @return {https.Agent} a shared agent for network requests among library instances\n */\n static _getHttpsAgent() {\n if (!HttpClient.HTTPS_AGENT) {\n let https = require('https');\n HttpClient.HTTPS_AGENT = new https.Agent({keepAlive: true});\n }\n return HttpClient.HTTPS_AGENT;\n }\n \n \n static _parseXhrResponseHeaders(headersStr) {\n let headerMap = {};\n let headers = headersStr.trim().split(/[\\r\\n]+/);\n for (let header of headers) {\n let headerVals = header.split(\": \");\n headerMap[headerVals[0]] = headerVals[1];\n }\n return headerMap;\n }\n}\n\n// default request config\nHttpClient.DEFAULT_REQUEST = {\n method: \"GET\",\n requestApi: \"fetch\",\n resolveWithFullResponse: false,\n rejectUnauthorized: true\n}\n\n/**\n * Modification of digest auth request by @inorganik.\n * \n * Dependent on CryptoJS MD5 hashing: http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5.js\n * \n * MIT licensed.\n */\nHttpClient.digestAuthRequest = function(method, url, username, password) {\n var self = this;\n\n if (typeof CryptoJS === 'undefined' && typeof require === 'function') {\n var CryptoJS = require('crypto-js');\n }\n\n this.scheme = null; // we just echo the scheme, to allow for 'Digest', 'X-Digest', 'JDigest' etc\n this.nonce = null; // server issued nonce\n this.realm = null; // server issued realm\n this.qop = null; // \"quality of protection\" - '' or 'auth' or 'auth-int'\n this.response = null; // hashed response to server challenge\n this.opaque = null; // hashed response to server challenge\n this.nc = 1; // nonce count - increments with each request used with the same nonce\n this.cnonce = null; // client nonce\n\n // settings\n this.timeout = 60000; // timeout\n this.loggingOn = false; // toggle console logging\n\n // determine if a post, so that request will send data\n this.post = false;\n if (method.toLowerCase() === 'post' || method.toLowerCase() === 'put') {\n this.post = true;\n }\n\n // start here\n // successFn - will be passed JSON data\n // errorFn - will be passed the failed authenticatedRequest\n // data - optional, for POSTS\n this.request = function(successFn, errorFn, data) {\n \n // stringify json\n if (data) {\n try {\n self.data = data instanceof Uint8Array || typeof data === \"string\" ? data : JSON.stringify(data);\n } catch (e) {\n console.error(e);\n throw e;\n }\n }\n self.successFn = successFn;\n self.errorFn = errorFn;\n\n if (!self.nonce) {\n self.makeUnauthenticatedRequest(self.data);\n } else {\n self.makeAuthenticatedRequest();\n }\n }\n this.makeUnauthenticatedRequest = function(data) {\n self.firstRequest = new XMLHttpRequest();\n self.firstRequest.open(method, url, true);\n self.firstRequest.timeout = self.timeout;\n // if we are posting, add appropriate headers\n if (self.post && data) {\n if (typeof data === \"string\") {\n self.firstRequest.setRequestHeader('Content-type', 'text/plain');\n } else {\n self.firstRequest.responseType = \"arraybuffer\";\n }\n }\n\n self.firstRequest.onreadystatechange = function() {\n\n // 2: received headers, 3: loading, 4: done\n if (self.firstRequest.readyState === 2) {\n\n var responseHeaders = self.firstRequest.getAllResponseHeaders();\n responseHeaders = responseHeaders.split('\\n');\n // get authenticate header\n var digestHeaders;\n for(var i = 0; i < responseHeaders.length; i++) {\n if (responseHeaders[i].match(/www-authenticate/i) != null) {\n digestHeaders = responseHeaders[i];\n }\n }\n\n if (digestHeaders != null) {\n // parse auth header and get digest auth keys\n digestHeaders = digestHeaders.slice(digestHeaders.indexOf(':') + 1, -1);\n digestHeaders = digestHeaders.split(',');\n self.scheme = digestHeaders[0].split(/\\s/)[1];\n for (var i = 0; i < digestHeaders.length; i++) {\n var equalIndex = digestHeaders[i].indexOf('='),\n key = digestHeaders[i].substring(0, equalIndex),\n val = digestHeaders[i].substring(equalIndex + 1);\n val = val.replace(/['\"]+/g, '');\n // find realm\n if (key.match(/realm/i) != null) {\n self.realm = val;\n }\n // find nonce\n if (key.match(/nonce/i) != null) {\n self.nonce = val;\n }\n // find opaque\n if (key.match(/opaque/i) != null) {\n self.opaque = val;\n }\n // find QOP\n if (key.match(/qop/i) != null) {\n self.qop = val;\n }\n }\n // client generated keys\n self.cnonce = self.generateCnonce();\n self.nc++;\n // if logging, show headers received:\n self.log('received headers:');\n self.log(' realm: '+self.realm);\n self.log(' nonce: '+self.nonce);\n self.log(' opaque: '+self.opaque);\n self.log(' qop: '+self.qop);\n // now we can make an authenticated request\n self.makeAuthenticatedRequest();\n }\n }\n if (self.firstRequest.readyState === 4) {\n if (self.firstRequest.status === 200) {\n self.log('Authentication not required for '+url);\n if (data instanceof Uint8Array) {\n console.log(\"BINARY RESPONSE 1\");\n self.successFn(self.firstRequest);\n } else {\n if (self.firstRequest.responseText !== 'undefined') {\n if (self.firstRequest.responseText.length > 0) {\n // If JSON, parse and return object\n if (self.isJson(self.firstRequest.responseText)) { // TODO: redundant\n self.successFn(self.firstRequest);\n } else {\n self.successFn(self.firstRequest);\n }\n }\n } else {\n self.successFn();\n }\n }\n }\n }\n }\n // send\n if (self.post) {\n // in case digest auth not required\n self.firstRequest.send(self.data);\n } else {\n self.firstRequest.send();\n }\n self.log('Unauthenticated request to '+url);\n\n // handle error\n self.firstRequest.onerror = function() {\n if (self.firstRequest.status !== 401) {\n self.log('Error ('+self.firstRequest.status+') on unauthenticated request to '+url);\n self.errorFn(self.firstRequest);\n }\n }\n }\n this.makeAuthenticatedRequest= function() {\n\n self.response = self.formulateResponse();\n self.authenticatedRequest = new XMLHttpRequest();\n self.authenticatedRequest.open(method, url, true);\n self.authenticatedRequest.timeout = self.timeout;\n var digestAuthHeader = self.scheme+' '+\n 'username=\"'+username+'\", '+\n 'realm=\"'+self.realm+'\", '+\n 'nonce=\"'+self.nonce+'\", '+\n 'uri=\"'+url+'\", '+\n 'response=\"'+self.response+'\", '+\n 'opaque=\"'+self.opaque+'\", '+\n 'qop='+self.qop+', '+\n 'nc='+('00000000' + self.nc).slice(-8)+', '+\n 'cnonce=\"'+self.cnonce+'\"';\n self.authenticatedRequest.setRequestHeader('Authorization', digestAuthHeader);\n self.log('digest auth header response to be sent:');\n self.log(digestAuthHeader);\n // if we are posting, add appropriate headers\n if (self.post && self.data) {\n if (typeof self.data === \"string\") {\n self.authenticatedRequest.setRequestHeader('Content-type', 'text/plain');\n } else {\n self.authenticatedRequest.responseType = \"arraybuffer\"; \n }\n }\n self.authenticatedRequest.onload = function() {\n // success\n if (self.authenticatedRequest.status >= 200 && self.authenticatedRequest.status < 400) {\n // increment nonce count\n self.nc++;\n // return data\n if (self.data instanceof Uint8Array) {\n self.successFn(self.authenticatedRequest);\n } else {\n if (self.authenticatedRequest.responseText !== 'undefined' && self.authenticatedRequest.responseText.length > 0 ) {\n // If JSON, parse and return object\n if (self.isJson(self.authenticatedRequest.responseText)) { // TODO: redundant from not parsing\n self.successFn(self.authenticatedRequest);\n } else {\n self.successFn(self.authenticatedRequest);\n }\n } else {\n self.successFn();\n }\n }\n }\n // failure\n else {\n self.nonce = null;\n self.errorFn(self.authenticatedRequest);\n }\n }\n // handle errors\n self.authenticatedRequest.onerror = function() {\n self.log('Error ('+self.authenticatedRequest.status+') on authenticated request to '+url);\n self.nonce = null;\n self.errorFn(self.authenticatedRequest);\n };\n // send\n if (self.post) {\n self.authenticatedRequest.send(self.data);\n } else {\n self.authenticatedRequest.send();\n }\n self.log('Authenticated request to '+url);\n }\n // hash response based on server challenge\n this.formulateResponse = function() {\n var HA1 = CryptoJS.MD5(username+':'+self.realm+':'+password).toString();\n var HA2 = CryptoJS.MD5(method+':'+url).toString();\n var response = CryptoJS.MD5(HA1+':'+\n self.nonce+':'+\n ('00000000' + self.nc).slice(-8)+':'+\n self.cnonce+':'+\n self.qop+':'+\n HA2).toString();\n return response;\n }\n // generate 16 char client nonce\n this.generateCnonce = function() {\n var characters = 'abcdef0123456789';\n var token = '';\n for (var i = 0; i < 16; i++) {\n var randNum = Math.round(Math.random() * characters.length);\n token += characters.substr(randNum, 1);\n }\n return token;\n }\n this.abort = function() {\n self.log('[digestAuthRequest] Aborted request to '+url);\n if (self.firstRequest != null) {\n if (self.firstRequest.readyState != 4) self.firstRequest.abort();\n }\n if (self.authenticatedRequest != null) {\n if (self.authenticatedRequest.readyState != 4) self.authenticatedRequest.abort();\n }\n }\n this.isJson = function(str) {\n try {\n JSON.parse(str);\n } catch (e) {\n return false;\n }\n return true;\n }\n this.log = function(str) {\n if (self.loggingOn) {\n console.log('[digestAuthRequest] '+str);\n }\n }\n this.version = function() { return '0.8.0' }\n}\n\nmodule.exports = HttpClient;","var baseGetTag = require('./_baseGetTag'),\n isObject = require('./isObject');\n\n/** `Object#toString` result references. */\nvar asyncTag = '[object AsyncFunction]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n proxyTag = '[object Proxy]';\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n if (!isObject(value)) {\n return false;\n }\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\nmodule.exports = isFunction;\n","var Symbol = require('./_Symbol'),\n getRawTag = require('./_getRawTag'),\n objectToString = require('./_objectToString');\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nmodule.exports = baseGetTag;\n","var root = require('./_root');\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nmodule.exports = Symbol;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nmodule.exports = isArray;\n","'use strict'\n\nvar tough = require('tough-cookie')\n\nvar Cookie = tough.Cookie\nvar CookieJar = tough.CookieJar\n\nexports.parse = function (str) {\n if (str && str.uri) {\n str = str.uri\n }\n if (typeof str !== 'string') {\n throw new Error('The cookie function only accepts STRING as param')\n }\n return Cookie.parse(str, {loose: true})\n}\n\n// Adapt the sometimes-Async api of tough.CookieJar to our requirements\nfunction RequestJar (store) {\n var self = this\n self._jar = new CookieJar(store, {looseMode: true})\n}\nRequestJar.prototype.setCookie = function (cookieOrStr, uri, options) {\n var self = this\n return self._jar.setCookieSync(cookieOrStr, uri, options || {})\n}\nRequestJar.prototype.getCookieString = function (uri) {\n var self = this\n return self._jar.getCookieStringSync(uri)\n}\nRequestJar.prototype.getCookies = function (uri) {\n var self = this\n return self._jar.getCookiesSync(uri)\n}\n\nexports.jar = function (store) {\n return new RequestJar(store)\n}\n","/*!\n * Copyright (c) 2015, Salesforce.com, Inc.\n * All rights reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of Salesforce.com nor the names of its contributors may\n * be used to endorse or promote products derived from this software without\n * specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n * POSSIBILITY OF SUCH DAMAGE.\n */\n'use strict';\nvar net = require('net');\nvar urlParse = require('url').parse;\nvar util = require('util');\nvar pubsuffix = require('./pubsuffix-psl');\nvar Store = require('./store').Store;\nvar MemoryCookieStore = require('./memstore').MemoryCookieStore;\nvar pathMatch = require('./pathMatch').pathMatch;\nvar VERSION = require('../package.json').version;\n\nvar punycode;\ntry {\n punycode = require('punycode');\n} catch(e) {\n console.warn(\"tough-cookie: can't load punycode; won't use punycode for domain normalization\");\n}\n\n// From RFC6265 S4.1.1\n// note that it excludes \\x3B \";\"\nvar COOKIE_OCTETS = /^[\\x21\\x23-\\x2B\\x2D-\\x3A\\x3C-\\x5B\\x5D-\\x7E]+$/;\n\nvar CONTROL_CHARS = /[\\x00-\\x1F]/;\n\n// From Chromium // '\\r', '\\n' and '\\0' should be treated as a terminator in\n// the \"relaxed\" mode, see:\n// https://github.com/ChromiumWebApps/chromium/blob/b3d3b4da8bb94c1b2e061600df106d590fda3620/net/cookies/parsed_cookie.cc#L60\nvar TERMINATORS = ['\\n', '\\r', '\\0'];\n\n// RFC6265 S4.1.1 defines path value as 'any CHAR except CTLs or \";\"'\n// Note ';' is \\x3B\nvar PATH_VALUE = /[\\x20-\\x3A\\x3C-\\x7E]+/;\n\n// date-time parsing constants (RFC6265 S5.1.1)\n\nvar DATE_DELIM = /[\\x09\\x20-\\x2F\\x3B-\\x40\\x5B-\\x60\\x7B-\\x7E]/;\n\nvar MONTH_TO_NUM = {\n jan:0, feb:1, mar:2, apr:3, may:4, jun:5,\n jul:6, aug:7, sep:8, oct:9, nov:10, dec:11\n};\nvar NUM_TO_MONTH = [\n 'Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'\n];\nvar NUM_TO_DAY = [\n 'Sun','Mon','Tue','Wed','Thu','Fri','Sat'\n];\n\nvar MAX_TIME = 2147483647000; // 31-bit max\nvar MIN_TIME = 0; // 31-bit min\n\n/*\n * Parses a Natural number (i.e., non-negative integer) with either the\n * *DIGIT ( non-digit *OCTET )\n * or\n * *DIGIT\n * grammar (RFC6265 S5.1.1).\n *\n * The \"trailingOK\" boolean controls if the grammar accepts a\n * \"( non-digit *OCTET )\" trailer.\n */\nfunction parseDigits(token, minDigits, maxDigits, trailingOK) {\n var count = 0;\n while (count < token.length) {\n var c = token.charCodeAt(count);\n // \"non-digit = %x00-2F / %x3A-FF\"\n if (c <= 0x2F || c >= 0x3A) {\n break;\n }\n count++;\n }\n\n // constrain to a minimum and maximum number of digits.\n if (count < minDigits || count > maxDigits) {\n return null;\n }\n\n if (!trailingOK && count != token.length) {\n return null;\n }\n\n return parseInt(token.substr(0,count), 10);\n}\n\nfunction parseTime(token) {\n var parts = token.split(':');\n var result = [0,0,0];\n\n /* RF6256 S5.1.1:\n * time = hms-time ( non-digit *OCTET )\n * hms-time = time-field \":\" time-field \":\" time-field\n * time-field = 1*2DIGIT\n */\n\n if (parts.length !== 3) {\n return null;\n }\n\n for (var i = 0; i < 3; i++) {\n // \"time-field\" must be strictly \"1*2DIGIT\", HOWEVER, \"hms-time\" can be\n // followed by \"( non-digit *OCTET )\" so therefore the last time-field can\n // have a trailer\n var trailingOK = (i == 2);\n var num = parseDigits(parts[i], 1, 2, trailingOK);\n if (num === null) {\n return null;\n }\n result[i] = num;\n }\n\n return result;\n}\n\nfunction parseMonth(token) {\n token = String(token).substr(0,3).toLowerCase();\n var num = MONTH_TO_NUM[token];\n return num >= 0 ? num : null;\n}\n\n/*\n * RFC6265 S5.1.1 date parser (see RFC for full grammar)\n */\nfunction parseDate(str) {\n if (!str) {\n return;\n }\n\n /* RFC6265 S5.1.1:\n * 2. Process each date-token sequentially in the order the date-tokens\n * appear in the cookie-date\n */\n var tokens = str.split(DATE_DELIM);\n if (!tokens) {\n return;\n }\n\n var hour = null;\n var minute = null;\n var second = null;\n var dayOfMonth = null;\n var month = null;\n var year = null;\n\n for (var i=0; i= 70 && year <= 99) {\n year += 1900;\n } else if (year >= 0 && year <= 69) {\n year += 2000;\n }\n }\n }\n }\n\n /* RFC 6265 S5.1.1\n * \"5. Abort these steps and fail to parse the cookie-date if:\n * * at least one of the found-day-of-month, found-month, found-\n * year, or found-time flags is not set,\n * * the day-of-month-value is less than 1 or greater than 31,\n * * the year-value is less than 1601,\n * * the hour-value is greater than 23,\n * * the minute-value is greater than 59, or\n * * the second-value is greater than 59.\n * (Note that leap seconds cannot be represented in this syntax.)\"\n *\n * So, in order as above:\n */\n if (\n dayOfMonth === null || month === null || year === null || second === null ||\n dayOfMonth < 1 || dayOfMonth > 31 ||\n year < 1601 ||\n hour > 23 ||\n minute > 59 ||\n second > 59\n ) {\n return;\n }\n\n return new Date(Date.UTC(year, month, dayOfMonth, hour, minute, second));\n}\n\nfunction formatDate(date) {\n var d = date.getUTCDate(); d = d >= 10 ? d : '0'+d;\n var h = date.getUTCHours(); h = h >= 10 ? h : '0'+h;\n var m = date.getUTCMinutes(); m = m >= 10 ? m : '0'+m;\n var s = date.getUTCSeconds(); s = s >= 10 ? s : '0'+s;\n return NUM_TO_DAY[date.getUTCDay()] + ', ' +\n d+' '+ NUM_TO_MONTH[date.getUTCMonth()] +' '+ date.getUTCFullYear() +' '+\n h+':'+m+':'+s+' GMT';\n}\n\n// S5.1.2 Canonicalized Host Names\nfunction canonicalDomain(str) {\n if (str == null) {\n return null;\n }\n str = str.trim().replace(/^\\./,''); // S4.1.2.3 & S5.2.3: ignore leading .\n\n // convert to IDN if any non-ASCII characters\n if (punycode && /[^\\u0001-\\u007f]/.test(str)) {\n str = punycode.toASCII(str);\n }\n\n return str.toLowerCase();\n}\n\n// S5.1.3 Domain Matching\nfunction domainMatch(str, domStr, canonicalize) {\n if (str == null || domStr == null) {\n return null;\n }\n if (canonicalize !== false) {\n str = canonicalDomain(str);\n domStr = canonicalDomain(domStr);\n }\n\n /*\n * \"The domain string and the string are identical. (Note that both the\n * domain string and the string will have been canonicalized to lower case at\n * this point)\"\n */\n if (str == domStr) {\n return true;\n }\n\n /* \"All of the following [three] conditions hold:\" (order adjusted from the RFC) */\n\n /* \"* The string is a host name (i.e., not an IP address).\" */\n if (net.isIP(str)) {\n return false;\n }\n\n /* \"* The domain string is a suffix of the string\" */\n var idx = str.indexOf(domStr);\n if (idx <= 0) {\n return false; // it's a non-match (-1) or prefix (0)\n }\n\n // e.g \"a.b.c\".indexOf(\"b.c\") === 2\n // 5 === 3+2\n if (str.length !== domStr.length + idx) { // it's not a suffix\n return false;\n }\n\n /* \"* The last character of the string that is not included in the domain\n * string is a %x2E (\".\") character.\" */\n if (str.substr(idx-1,1) !== '.') {\n return false;\n }\n\n return true;\n}\n\n\n// RFC6265 S5.1.4 Paths and Path-Match\n\n/*\n * \"The user agent MUST use an algorithm equivalent to the following algorithm\n * to compute the default-path of a cookie:\"\n *\n * Assumption: the path (and not query part or absolute uri) is passed in.\n */\nfunction defaultPath(path) {\n // \"2. If the uri-path is empty or if the first character of the uri-path is not\n // a %x2F (\"/\") character, output %x2F (\"/\") and skip the remaining steps.\n if (!path || path.substr(0,1) !== \"/\") {\n return \"/\";\n }\n\n // \"3. If the uri-path contains no more than one %x2F (\"/\") character, output\n // %x2F (\"/\") and skip the remaining step.\"\n if (path === \"/\") {\n return path;\n }\n\n var rightSlash = path.lastIndexOf(\"/\");\n if (rightSlash === 0) {\n return \"/\";\n }\n\n // \"4. Output the characters of the uri-path from the first character up to,\n // but not including, the right-most %x2F (\"/\").\"\n return path.slice(0, rightSlash);\n}\n\nfunction trimTerminator(str) {\n for (var t = 0; t < TERMINATORS.length; t++) {\n var terminatorIdx = str.indexOf(TERMINATORS[t]);\n if (terminatorIdx !== -1) {\n str = str.substr(0,terminatorIdx);\n }\n }\n\n return str;\n}\n\nfunction parseCookiePair(cookiePair, looseMode) {\n cookiePair = trimTerminator(cookiePair);\n\n var firstEq = cookiePair.indexOf('=');\n if (looseMode) {\n if (firstEq === 0) { // '=' is immediately at start\n cookiePair = cookiePair.substr(1);\n firstEq = cookiePair.indexOf('='); // might still need to split on '='\n }\n } else { // non-loose mode\n if (firstEq <= 0) { // no '=' or is at start\n return; // needs to have non-empty \"cookie-name\"\n }\n }\n\n var cookieName, cookieValue;\n if (firstEq <= 0) {\n cookieName = \"\";\n cookieValue = cookiePair.trim();\n } else {\n cookieName = cookiePair.substr(0, firstEq).trim();\n cookieValue = cookiePair.substr(firstEq+1).trim();\n }\n\n if (CONTROL_CHARS.test(cookieName) || CONTROL_CHARS.test(cookieValue)) {\n return;\n }\n\n var c = new Cookie();\n c.key = cookieName;\n c.value = cookieValue;\n return c;\n}\n\nfunction parse(str, options) {\n if (!options || typeof options !== 'object') {\n options = {};\n }\n str = str.trim();\n\n // We use a regex to parse the \"name-value-pair\" part of S5.2\n var firstSemi = str.indexOf(';'); // S5.2 step 1\n var cookiePair = (firstSemi === -1) ? str : str.substr(0, firstSemi);\n var c = parseCookiePair(cookiePair, !!options.loose);\n if (!c) {\n return;\n }\n\n if (firstSemi === -1) {\n return c;\n }\n\n // S5.2.3 \"unparsed-attributes consist of the remainder of the set-cookie-string\n // (including the %x3B (\";\") in question).\" plus later on in the same section\n // \"discard the first \";\" and trim\".\n var unparsed = str.slice(firstSemi + 1).trim();\n\n // \"If the unparsed-attributes string is empty, skip the rest of these\n // steps.\"\n if (unparsed.length === 0) {\n return c;\n }\n\n /*\n * S5.2 says that when looping over the items \"[p]rocess the attribute-name\n * and attribute-value according to the requirements in the following\n * subsections\" for every item. Plus, for many of the individual attributes\n * in S5.3 it says to use the \"attribute-value of the last attribute in the\n * cookie-attribute-list\". Therefore, in this implementation, we overwrite\n * the previous value.\n */\n var cookie_avs = unparsed.split(';');\n while (cookie_avs.length) {\n var av = cookie_avs.shift().trim();\n if (av.length === 0) { // happens if \";;\" appears\n continue;\n }\n var av_sep = av.indexOf('=');\n var av_key, av_value;\n\n if (av_sep === -1) {\n av_key = av;\n av_value = null;\n } else {\n av_key = av.substr(0,av_sep);\n av_value = av.substr(av_sep+1);\n }\n\n av_key = av_key.trim().toLowerCase();\n\n if (av_value) {\n av_value = av_value.trim();\n }\n\n switch(av_key) {\n case 'expires': // S5.2.1\n if (av_value) {\n var exp = parseDate(av_value);\n // \"If the attribute-value failed to parse as a cookie date, ignore the\n // cookie-av.\"\n if (exp) {\n // over and underflow not realistically a concern: V8's getTime() seems to\n // store something larger than a 32-bit time_t (even with 32-bit node)\n c.expires = exp;\n }\n }\n break;\n\n case 'max-age': // S5.2.2\n if (av_value) {\n // \"If the first character of the attribute-value is not a DIGIT or a \"-\"\n // character ...[or]... If the remainder of attribute-value contains a\n // non-DIGIT character, ignore the cookie-av.\"\n if (/^-?[0-9]+$/.test(av_value)) {\n var delta = parseInt(av_value, 10);\n // \"If delta-seconds is less than or equal to zero (0), let expiry-time\n // be the earliest representable date and time.\"\n c.setMaxAge(delta);\n }\n }\n break;\n\n case 'domain': // S5.2.3\n // \"If the attribute-value is empty, the behavior is undefined. However,\n // the user agent SHOULD ignore the cookie-av entirely.\"\n if (av_value) {\n // S5.2.3 \"Let cookie-domain be the attribute-value without the leading %x2E\n // (\".\") character.\"\n var domain = av_value.trim().replace(/^\\./, '');\n if (domain) {\n // \"Convert the cookie-domain to lower case.\"\n c.domain = domain.toLowerCase();\n }\n }\n break;\n\n case 'path': // S5.2.4\n /*\n * \"If the attribute-value is empty or if the first character of the\n * attribute-value is not %x2F (\"/\"):\n * Let cookie-path be the default-path.\n * Otherwise:\n * Let cookie-path be the attribute-value.\"\n *\n * We'll represent the default-path as null since it depends on the\n * context of the parsing.\n */\n c.path = av_value && av_value[0] === \"/\" ? av_value : null;\n break;\n\n case 'secure': // S5.2.5\n /*\n * \"If the attribute-name case-insensitively matches the string \"Secure\",\n * the user agent MUST append an attribute to the cookie-attribute-list\n * with an attribute-name of Secure and an empty attribute-value.\"\n */\n c.secure = true;\n break;\n\n case 'httponly': // S5.2.6 -- effectively the same as 'secure'\n c.httpOnly = true;\n break;\n\n default:\n c.extensions = c.extensions || [];\n c.extensions.push(av);\n break;\n }\n }\n\n return c;\n}\n\n// avoid the V8 deoptimization monster!\nfunction jsonParse(str) {\n var obj;\n try {\n obj = JSON.parse(str);\n } catch (e) {\n return e;\n }\n return obj;\n}\n\nfunction fromJSON(str) {\n if (!str) {\n return null;\n }\n\n var obj;\n if (typeof str === 'string') {\n obj = jsonParse(str);\n if (obj instanceof Error) {\n return null;\n }\n } else {\n // assume it's an Object\n obj = str;\n }\n\n var c = new Cookie();\n for (var i=0; i 1) {\n var lindex = path.lastIndexOf('/');\n if (lindex === 0) {\n break;\n }\n path = path.substr(0,lindex);\n permutations.push(path);\n }\n permutations.push('/');\n return permutations;\n}\n\nfunction getCookieContext(url) {\n if (url instanceof Object) {\n return url;\n }\n // NOTE: decodeURI will throw on malformed URIs (see GH-32).\n // Therefore, we will just skip decoding for such URIs.\n try {\n url = decodeURI(url);\n }\n catch(err) {\n // Silently swallow error\n }\n\n return urlParse(url);\n}\n\nfunction Cookie(options) {\n options = options || {};\n\n Object.keys(options).forEach(function(prop) {\n if (Cookie.prototype.hasOwnProperty(prop) &&\n Cookie.prototype[prop] !== options[prop] &&\n prop.substr(0,1) !== '_')\n {\n this[prop] = options[prop];\n }\n }, this);\n\n this.creation = this.creation || new Date();\n\n // used to break creation ties in cookieCompare():\n Object.defineProperty(this, 'creationIndex', {\n configurable: false,\n enumerable: false, // important for assert.deepEqual checks\n writable: true,\n value: ++Cookie.cookiesCreated\n });\n}\n\nCookie.cookiesCreated = 0; // incremented each time a cookie is created\n\nCookie.parse = parse;\nCookie.fromJSON = fromJSON;\n\nCookie.prototype.key = \"\";\nCookie.prototype.value = \"\";\n\n// the order in which the RFC has them:\nCookie.prototype.expires = \"Infinity\"; // coerces to literal Infinity\nCookie.prototype.maxAge = null; // takes precedence over expires for TTL\nCookie.prototype.domain = null;\nCookie.prototype.path = null;\nCookie.prototype.secure = false;\nCookie.prototype.httpOnly = false;\nCookie.prototype.extensions = null;\n\n// set by the CookieJar:\nCookie.prototype.hostOnly = null; // boolean when set\nCookie.prototype.pathIsDefault = null; // boolean when set\nCookie.prototype.creation = null; // Date when set; defaulted by Cookie.parse\nCookie.prototype.lastAccessed = null; // Date when set\nObject.defineProperty(Cookie.prototype, 'creationIndex', {\n configurable: true,\n enumerable: false,\n writable: true,\n value: 0\n});\n\nCookie.serializableProperties = Object.keys(Cookie.prototype)\n .filter(function(prop) {\n return !(\n Cookie.prototype[prop] instanceof Function ||\n prop === 'creationIndex' ||\n prop.substr(0,1) === '_'\n );\n });\n\nCookie.prototype.inspect = function inspect() {\n var now = Date.now();\n return 'Cookie=\"'+this.toString() +\n '; hostOnly='+(this.hostOnly != null ? this.hostOnly : '?') +\n '; aAge='+(this.lastAccessed ? (now-this.lastAccessed.getTime())+'ms' : '?') +\n '; cAge='+(this.creation ? (now-this.creation.getTime())+'ms' : '?') +\n '\"';\n};\n\n// Use the new custom inspection symbol to add the custom inspect function if\n// available.\nif (util.inspect.custom) {\n Cookie.prototype[util.inspect.custom] = Cookie.prototype.inspect;\n}\n\nCookie.prototype.toJSON = function() {\n var obj = {};\n\n var props = Cookie.serializableProperties;\n for (var i=0; i self._pos) {\n\t\t\t\tvar newData = response.substr(self._pos)\n\t\t\t\tif (self._charset === 'x-user-defined') {\n\t\t\t\t\tvar buffer = new Buffer(newData.length)\n\t\t\t\t\tfor (var i = 0; i < newData.length; i++)\n\t\t\t\t\t\tbuffer[i] = newData.charCodeAt(i) & 0xff\n\n\t\t\t\t\tself.push(buffer)\n\t\t\t\t} else {\n\t\t\t\t\tself.push(newData, self._charset)\n\t\t\t\t}\n\t\t\t\tself._pos = response.length\n\t\t\t}\n\t\t\tbreak\n\t\tcase 'arraybuffer':\n\t\t\tif (xhr.readyState !== rStates.DONE || !xhr.response)\n\t\t\t\tbreak\n\t\t\tresponse = xhr.response\n\t\t\tself.push(new Buffer(new Uint8Array(response)))\n\t\t\tbreak\n\t\tcase 'moz-chunked-arraybuffer': // take whole\n\t\t\tresponse = xhr.response\n\t\t\tif (xhr.readyState !== rStates.LOADING || !response)\n\t\t\t\tbreak\n\t\t\tself.push(new Buffer(new Uint8Array(response)))\n\t\t\tbreak\n\t\tcase 'ms-stream':\n\t\t\tresponse = xhr.response\n\t\t\tif (xhr.readyState !== rStates.LOADING)\n\t\t\t\tbreak\n\t\t\tvar reader = new global.MSStreamReader()\n\t\t\treader.onprogress = function () {\n\t\t\t\tif (reader.result.byteLength > self._pos) {\n\t\t\t\t\tself.push(new Buffer(new Uint8Array(reader.result.slice(self._pos))))\n\t\t\t\t\tself._pos = reader.result.byteLength\n\t\t\t\t}\n\t\t\t}\n\t\t\treader.onload = function () {\n\t\t\t\tself.push(null)\n\t\t\t}\n\t\t\t// reader.onerror = ??? // TODO: this\n\t\t\treader.readAsArrayBuffer(response)\n\t\t\tbreak\n\t}\n\n\t// The ms-stream case handles end separately in reader.onload()\n\tif (self._xhr.readyState === rStates.DONE && self._mode !== 'ms-stream') {\n\t\tself.push(null)\n\t}\n}\n","exports = module.exports = require('./lib/_stream_readable.js');\nexports.Stream = exports;\nexports.Readable = exports;\nexports.Writable = require('./lib/_stream_writable.js');\nexports.Duplex = require('./lib/_stream_duplex.js');\nexports.Transform = require('./lib/_stream_transform.js');\nexports.PassThrough = require('./lib/_stream_passthrough.js');\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\n/**/\n\nvar pna = require('process-nextick-args');\n/**/\n\nmodule.exports = Readable;\n\n/**/\nvar isArray = require('isarray');\n/**/\n\n/**/\nvar Duplex;\n/**/\n\nReadable.ReadableState = ReadableState;\n\n/**/\nvar EE = require('events').EventEmitter;\n\nvar EElistenerCount = function (emitter, type) {\n return emitter.listeners(type).length;\n};\n/**/\n\n/**/\nvar Stream = require('./internal/streams/stream');\n/**/\n\n/**/\n\nvar Buffer = require('safe-buffer').Buffer;\nvar OurUint8Array = global.Uint8Array || function () {};\nfunction _uint8ArrayToBuffer(chunk) {\n return Buffer.from(chunk);\n}\nfunction _isUint8Array(obj) {\n return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;\n}\n\n/**/\n\n/**/\nvar util = Object.create(require('core-util-is'));\nutil.inherits = require('inherits');\n/**/\n\n/**/\nvar debugUtil = require('util');\nvar debug = void 0;\nif (debugUtil && debugUtil.debuglog) {\n debug = debugUtil.debuglog('stream');\n} else {\n debug = function () {};\n}\n/**/\n\nvar BufferList = require('./internal/streams/BufferList');\nvar destroyImpl = require('./internal/streams/destroy');\nvar StringDecoder;\n\nutil.inherits(Readable, Stream);\n\nvar kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume'];\n\nfunction prependListener(emitter, event, fn) {\n // Sadly this is not cacheable as some libraries bundle their own\n // event emitter implementation with them.\n if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn);\n\n // This is a hack to make sure that our error handler is attached before any\n // userland ones. NEVER DO THIS. This is here only because this code needs\n // to continue to work with older versions of Node.js that do not include\n // the prependListener() method. The goal is to eventually remove this hack.\n if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]];\n}\n\nfunction ReadableState(options, stream) {\n Duplex = Duplex || require('./_stream_duplex');\n\n options = options || {};\n\n // Duplex streams are both readable and writable, but share\n // the same options object.\n // However, some cases require setting options to different\n // values for the readable and the writable sides of the duplex stream.\n // These options can be provided separately as readableXXX and writableXXX.\n var isDuplex = stream instanceof Duplex;\n\n // object stream flag. Used to make read(n) ignore n and to\n // make all the buffer merging and length checks go away\n this.objectMode = !!options.objectMode;\n\n if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode;\n\n // the point at which it stops calling _read() to fill the buffer\n // Note: 0 is a valid value, means \"don't call _read preemptively ever\"\n var hwm = options.highWaterMark;\n var readableHwm = options.readableHighWaterMark;\n var defaultHwm = this.objectMode ? 16 : 16 * 1024;\n\n if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (readableHwm || readableHwm === 0)) this.highWaterMark = readableHwm;else this.highWaterMark = defaultHwm;\n\n // cast to ints.\n this.highWaterMark = Math.floor(this.highWaterMark);\n\n // A linked list is used to store data chunks instead of an array because the\n // linked list can remove elements from the beginning faster than\n // array.shift()\n this.buffer = new BufferList();\n this.length = 0;\n this.pipes = null;\n this.pipesCount = 0;\n this.flowing = null;\n this.ended = false;\n this.endEmitted = false;\n this.reading = false;\n\n // a flag to be able to tell if the event 'readable'/'data' is emitted\n // immediately, or on a later tick. We set this to true at first, because\n // any actions that shouldn't happen until \"later\" should generally also\n // not happen before the first read call.\n this.sync = true;\n\n // whenever we return null, then we set a flag to say\n // that we're awaiting a 'readable' event emission.\n this.needReadable = false;\n this.emittedReadable = false;\n this.readableListening = false;\n this.resumeScheduled = false;\n\n // has it been destroyed\n this.destroyed = false;\n\n // Crypto is kind of old and crusty. Historically, its default string\n // encoding is 'binary' so we have to make this configurable.\n // Everything else in the universe uses 'utf8', though.\n this.defaultEncoding = options.defaultEncoding || 'utf8';\n\n // the number of writers that are awaiting a drain event in .pipe()s\n this.awaitDrain = 0;\n\n // if true, a maybeReadMore has been scheduled\n this.readingMore = false;\n\n this.decoder = null;\n this.encoding = null;\n if (options.encoding) {\n if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;\n this.decoder = new StringDecoder(options.encoding);\n this.encoding = options.encoding;\n }\n}\n\nfunction Readable(options) {\n Duplex = Duplex || require('./_stream_duplex');\n\n if (!(this instanceof Readable)) return new Readable(options);\n\n this._readableState = new ReadableState(options, this);\n\n // legacy\n this.readable = true;\n\n if (options) {\n if (typeof options.read === 'function') this._read = options.read;\n\n if (typeof options.destroy === 'function') this._destroy = options.destroy;\n }\n\n Stream.call(this);\n}\n\nObject.defineProperty(Readable.prototype, 'destroyed', {\n get: function () {\n if (this._readableState === undefined) {\n return false;\n }\n return this._readableState.destroyed;\n },\n set: function (value) {\n // we ignore the value if the stream\n // has not been initialized yet\n if (!this._readableState) {\n return;\n }\n\n // backward compatibility, the user is explicitly\n // managing destroyed\n this._readableState.destroyed = value;\n }\n});\n\nReadable.prototype.destroy = destroyImpl.destroy;\nReadable.prototype._undestroy = destroyImpl.undestroy;\nReadable.prototype._destroy = function (err, cb) {\n this.push(null);\n cb(err);\n};\n\n// Manually shove something into the read() buffer.\n// This returns true if the highWaterMark has not been hit yet,\n// similar to how Writable.write() returns true if you should\n// write() some more.\nReadable.prototype.push = function (chunk, encoding) {\n var state = this._readableState;\n var skipChunkCheck;\n\n if (!state.objectMode) {\n if (typeof chunk === 'string') {\n encoding = encoding || state.defaultEncoding;\n if (encoding !== state.encoding) {\n chunk = Buffer.from(chunk, encoding);\n encoding = '';\n }\n skipChunkCheck = true;\n }\n } else {\n skipChunkCheck = true;\n }\n\n return readableAddChunk(this, chunk, encoding, false, skipChunkCheck);\n};\n\n// Unshift should *always* be something directly out of read()\nReadable.prototype.unshift = function (chunk) {\n return readableAddChunk(this, chunk, null, true, false);\n};\n\nfunction readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) {\n var state = stream._readableState;\n if (chunk === null) {\n state.reading = false;\n onEofChunk(stream, state);\n } else {\n var er;\n if (!skipChunkCheck) er = chunkInvalid(state, chunk);\n if (er) {\n stream.emit('error', er);\n } else if (state.objectMode || chunk && chunk.length > 0) {\n if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) {\n chunk = _uint8ArrayToBuffer(chunk);\n }\n\n if (addToFront) {\n if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true);\n } else if (state.ended) {\n stream.emit('error', new Error('stream.push() after EOF'));\n } else {\n state.reading = false;\n if (state.decoder && !encoding) {\n chunk = state.decoder.write(chunk);\n if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state);\n } else {\n addChunk(stream, state, chunk, false);\n }\n }\n } else if (!addToFront) {\n state.reading = false;\n }\n }\n\n return needMoreData(state);\n}\n\nfunction addChunk(stream, state, chunk, addToFront) {\n if (state.flowing && state.length === 0 && !state.sync) {\n stream.emit('data', chunk);\n stream.read(0);\n } else {\n // update the buffer info.\n state.length += state.objectMode ? 1 : chunk.length;\n if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk);\n\n if (state.needReadable) emitReadable(stream);\n }\n maybeReadMore(stream, state);\n}\n\nfunction chunkInvalid(state, chunk) {\n var er;\n if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {\n er = new TypeError('Invalid non-string/buffer chunk');\n }\n return er;\n}\n\n// if it's past the high water mark, we can push in some more.\n// Also, if we have no data yet, we can stand some\n// more bytes. This is to work around cases where hwm=0,\n// such as the repl. Also, if the push() triggered a\n// readable event, and the user called read(largeNumber) such that\n// needReadable was set, then we ought to push more, so that another\n// 'readable' event will be triggered.\nfunction needMoreData(state) {\n return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0);\n}\n\nReadable.prototype.isPaused = function () {\n return this._readableState.flowing === false;\n};\n\n// backwards compatibility.\nReadable.prototype.setEncoding = function (enc) {\n if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder;\n this._readableState.decoder = new StringDecoder(enc);\n this._readableState.encoding = enc;\n return this;\n};\n\n// Don't raise the hwm > 8MB\nvar MAX_HWM = 0x800000;\nfunction computeNewHighWaterMark(n) {\n if (n >= MAX_HWM) {\n n = MAX_HWM;\n } else {\n // Get the next highest power of 2 to prevent increasing hwm excessively in\n // tiny amounts\n n--;\n n |= n >>> 1;\n n |= n >>> 2;\n n |= n >>> 4;\n n |= n >>> 8;\n n |= n >>> 16;\n n++;\n }\n return n;\n}\n\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction howMuchToRead(n, state) {\n if (n <= 0 || state.length === 0 && state.ended) return 0;\n if (state.objectMode) return 1;\n if (n !== n) {\n // Only flow one buffer at a time\n if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length;\n }\n // If we're asking for more than the current hwm, then raise the hwm.\n if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n);\n if (n <= state.length) return n;\n // Don't have enough\n if (!state.ended) {\n state.needReadable = true;\n return 0;\n }\n return state.length;\n}\n\n// you can override either this method, or the async _read(n) below.\nReadable.prototype.read = function (n) {\n debug('read', n);\n n = parseInt(n, 10);\n var state = this._readableState;\n var nOrig = n;\n\n if (n !== 0) state.emittedReadable = false;\n\n // if we're doing read(0) to trigger a readable event, but we\n // already have a bunch of data in the buffer, then just trigger\n // the 'readable' event and move on.\n if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) {\n debug('read: emitReadable', state.length, state.ended);\n if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this);\n return null;\n }\n\n n = howMuchToRead(n, state);\n\n // if we've ended, and we're now clear, then finish it up.\n if (n === 0 && state.ended) {\n if (state.length === 0) endReadable(this);\n return null;\n }\n\n // All the actual chunk generation logic needs to be\n // *below* the call to _read. The reason is that in certain\n // synthetic stream cases, such as passthrough streams, _read\n // may be a completely synchronous operation which may change\n // the state of the read buffer, providing enough data when\n // before there was *not* enough.\n //\n // So, the steps are:\n // 1. Figure out what the state of things will be after we do\n // a read from the buffer.\n //\n // 2. If that resulting state will trigger a _read, then call _read.\n // Note that this may be asynchronous, or synchronous. Yes, it is\n // deeply ugly to write APIs this way, but that still doesn't mean\n // that the Readable class should behave improperly, as streams are\n // designed to be sync/async agnostic.\n // Take note if the _read call is sync or async (ie, if the read call\n // has returned yet), so that we know whether or not it's safe to emit\n // 'readable' etc.\n //\n // 3. Actually pull the requested chunks out of the buffer and return.\n\n // if we need a readable event, then we need to do some reading.\n var doRead = state.needReadable;\n debug('need readable', doRead);\n\n // if we currently have less than the highWaterMark, then also read some\n if (state.length === 0 || state.length - n < state.highWaterMark) {\n doRead = true;\n debug('length less than watermark', doRead);\n }\n\n // however, if we've ended, then there's no point, and if we're already\n // reading, then it's unnecessary.\n if (state.ended || state.reading) {\n doRead = false;\n debug('reading or ended', doRead);\n } else if (doRead) {\n debug('do read');\n state.reading = true;\n state.sync = true;\n // if the length is currently zero, then we *need* a readable event.\n if (state.length === 0) state.needReadable = true;\n // call internal read method\n this._read(state.highWaterMark);\n state.sync = false;\n // If _read pushed data synchronously, then `reading` will be false,\n // and we need to re-evaluate how much data we can return to the user.\n if (!state.reading) n = howMuchToRead(nOrig, state);\n }\n\n var ret;\n if (n > 0) ret = fromList(n, state);else ret = null;\n\n if (ret === null) {\n state.needReadable = true;\n n = 0;\n } else {\n state.length -= n;\n }\n\n if (state.length === 0) {\n // If we have nothing in the buffer, then we want to know\n // as soon as we *do* get something into the buffer.\n if (!state.ended) state.needReadable = true;\n\n // If we tried to read() past the EOF, then emit end on the next tick.\n if (nOrig !== n && state.ended) endReadable(this);\n }\n\n if (ret !== null) this.emit('data', ret);\n\n return ret;\n};\n\nfunction onEofChunk(stream, state) {\n if (state.ended) return;\n if (state.decoder) {\n var chunk = state.decoder.end();\n if (chunk && chunk.length) {\n state.buffer.push(chunk);\n state.length += state.objectMode ? 1 : chunk.length;\n }\n }\n state.ended = true;\n\n // emit 'readable' now to make sure it gets picked up.\n emitReadable(stream);\n}\n\n// Don't emit readable right away in sync mode, because this can trigger\n// another read() call => stack overflow. This way, it might trigger\n// a nextTick recursion warning, but that's not so bad.\nfunction emitReadable(stream) {\n var state = stream._readableState;\n state.needReadable = false;\n if (!state.emittedReadable) {\n debug('emitReadable', state.flowing);\n state.emittedReadable = true;\n if (state.sync) pna.nextTick(emitReadable_, stream);else emitReadable_(stream);\n }\n}\n\nfunction emitReadable_(stream) {\n debug('emit readable');\n stream.emit('readable');\n flow(stream);\n}\n\n// at this point, the user has presumably seen the 'readable' event,\n// and called read() to consume some data. that may have triggered\n// in turn another _read(n) call, in which case reading = true if\n// it's in progress.\n// However, if we're not ended, or reading, and the length < hwm,\n// then go ahead and try to read some more preemptively.\nfunction maybeReadMore(stream, state) {\n if (!state.readingMore) {\n state.readingMore = true;\n pna.nextTick(maybeReadMore_, stream, state);\n }\n}\n\nfunction maybeReadMore_(stream, state) {\n var len = state.length;\n while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) {\n debug('maybeReadMore read 0');\n stream.read(0);\n if (len === state.length)\n // didn't get any data, stop spinning.\n break;else len = state.length;\n }\n state.readingMore = false;\n}\n\n// abstract method. to be overridden in specific implementation classes.\n// call cb(er, data) where data is <= n in length.\n// for virtual (non-string, non-buffer) streams, \"length\" is somewhat\n// arbitrary, and perhaps not very meaningful.\nReadable.prototype._read = function (n) {\n this.emit('error', new Error('_read() is not implemented'));\n};\n\nReadable.prototype.pipe = function (dest, pipeOpts) {\n var src = this;\n var state = this._readableState;\n\n switch (state.pipesCount) {\n case 0:\n state.pipes = dest;\n break;\n case 1:\n state.pipes = [state.pipes, dest];\n break;\n default:\n state.pipes.push(dest);\n break;\n }\n state.pipesCount += 1;\n debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts);\n\n var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr;\n\n var endFn = doEnd ? onend : unpipe;\n if (state.endEmitted) pna.nextTick(endFn);else src.once('end', endFn);\n\n dest.on('unpipe', onunpipe);\n function onunpipe(readable, unpipeInfo) {\n debug('onunpipe');\n if (readable === src) {\n if (unpipeInfo && unpipeInfo.hasUnpiped === false) {\n unpipeInfo.hasUnpiped = true;\n cleanup();\n }\n }\n }\n\n function onend() {\n debug('onend');\n dest.end();\n }\n\n // when the dest drains, it reduces the awaitDrain counter\n // on the source. This would be more elegant with a .once()\n // handler in flow(), but adding and removing repeatedly is\n // too slow.\n var ondrain = pipeOnDrain(src);\n dest.on('drain', ondrain);\n\n var cleanedUp = false;\n function cleanup() {\n debug('cleanup');\n // cleanup event handlers once the pipe is broken\n dest.removeListener('close', onclose);\n dest.removeListener('finish', onfinish);\n dest.removeListener('drain', ondrain);\n dest.removeListener('error', onerror);\n dest.removeListener('unpipe', onunpipe);\n src.removeListener('end', onend);\n src.removeListener('end', unpipe);\n src.removeListener('data', ondata);\n\n cleanedUp = true;\n\n // if the reader is waiting for a drain event from this\n // specific writer, then it would cause it to never start\n // flowing again.\n // So, if this is awaiting a drain, then we just call it now.\n // If we don't know, then assume that we are waiting for one.\n if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain();\n }\n\n // If the user pushes more data while we're writing to dest then we'll end up\n // in ondata again. However, we only want to increase awaitDrain once because\n // dest will only emit one 'drain' event for the multiple writes.\n // => Introduce a guard on increasing awaitDrain.\n var increasedAwaitDrain = false;\n src.on('data', ondata);\n function ondata(chunk) {\n debug('ondata');\n increasedAwaitDrain = false;\n var ret = dest.write(chunk);\n if (false === ret && !increasedAwaitDrain) {\n // If the user unpiped during `dest.write()`, it is possible\n // to get stuck in a permanently paused state if that write\n // also returned false.\n // => Check whether `dest` is still a piping destination.\n if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) {\n debug('false write response, pause', src._readableState.awaitDrain);\n src._readableState.awaitDrain++;\n increasedAwaitDrain = true;\n }\n src.pause();\n }\n }\n\n // if the dest has an error, then stop piping into it.\n // however, don't suppress the throwing behavior for this.\n function onerror(er) {\n debug('onerror', er);\n unpipe();\n dest.removeListener('error', onerror);\n if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er);\n }\n\n // Make sure our error handler is attached before userland ones.\n prependListener(dest, 'error', onerror);\n\n // Both close and finish should trigger unpipe, but only once.\n function onclose() {\n dest.removeListener('finish', onfinish);\n unpipe();\n }\n dest.once('close', onclose);\n function onfinish() {\n debug('onfinish');\n dest.removeListener('close', onclose);\n unpipe();\n }\n dest.once('finish', onfinish);\n\n function unpipe() {\n debug('unpipe');\n src.unpipe(dest);\n }\n\n // tell the dest that it's being piped to\n dest.emit('pipe', src);\n\n // start the flow if it hasn't been started already.\n if (!state.flowing) {\n debug('pipe resume');\n src.resume();\n }\n\n return dest;\n};\n\nfunction pipeOnDrain(src) {\n return function () {\n var state = src._readableState;\n debug('pipeOnDrain', state.awaitDrain);\n if (state.awaitDrain) state.awaitDrain--;\n if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) {\n state.flowing = true;\n flow(src);\n }\n };\n}\n\nReadable.prototype.unpipe = function (dest) {\n var state = this._readableState;\n var unpipeInfo = { hasUnpiped: false };\n\n // if we're not piping anywhere, then do nothing.\n if (state.pipesCount === 0) return this;\n\n // just one destination. most common case.\n if (state.pipesCount === 1) {\n // passed in one, but it's not the right one.\n if (dest && dest !== state.pipes) return this;\n\n if (!dest) dest = state.pipes;\n\n // got a match.\n state.pipes = null;\n state.pipesCount = 0;\n state.flowing = false;\n if (dest) dest.emit('unpipe', this, unpipeInfo);\n return this;\n }\n\n // slow case. multiple pipe destinations.\n\n if (!dest) {\n // remove all.\n var dests = state.pipes;\n var len = state.pipesCount;\n state.pipes = null;\n state.pipesCount = 0;\n state.flowing = false;\n\n for (var i = 0; i < len; i++) {\n dests[i].emit('unpipe', this, unpipeInfo);\n }return this;\n }\n\n // try to find the right one.\n var index = indexOf(state.pipes, dest);\n if (index === -1) return this;\n\n state.pipes.splice(index, 1);\n state.pipesCount -= 1;\n if (state.pipesCount === 1) state.pipes = state.pipes[0];\n\n dest.emit('unpipe', this, unpipeInfo);\n\n return this;\n};\n\n// set up data events if they are asked for\n// Ensure readable listeners eventually get something\nReadable.prototype.on = function (ev, fn) {\n var res = Stream.prototype.on.call(this, ev, fn);\n\n if (ev === 'data') {\n // Start flowing on next tick if stream isn't explicitly paused\n if (this._readableState.flowing !== false) this.resume();\n } else if (ev === 'readable') {\n var state = this._readableState;\n if (!state.endEmitted && !state.readableListening) {\n state.readableListening = state.needReadable = true;\n state.emittedReadable = false;\n if (!state.reading) {\n pna.nextTick(nReadingNextTick, this);\n } else if (state.length) {\n emitReadable(this);\n }\n }\n }\n\n return res;\n};\nReadable.prototype.addListener = Readable.prototype.on;\n\nfunction nReadingNextTick(self) {\n debug('readable nexttick read 0');\n self.read(0);\n}\n\n// pause() and resume() are remnants of the legacy readable stream API\n// If the user uses them, then switch into old mode.\nReadable.prototype.resume = function () {\n var state = this._readableState;\n if (!state.flowing) {\n debug('resume');\n state.flowing = true;\n resume(this, state);\n }\n return this;\n};\n\nfunction resume(stream, state) {\n if (!state.resumeScheduled) {\n state.resumeScheduled = true;\n pna.nextTick(resume_, stream, state);\n }\n}\n\nfunction resume_(stream, state) {\n if (!state.reading) {\n debug('resume read 0');\n stream.read(0);\n }\n\n state.resumeScheduled = false;\n state.awaitDrain = 0;\n stream.emit('resume');\n flow(stream);\n if (state.flowing && !state.reading) stream.read(0);\n}\n\nReadable.prototype.pause = function () {\n debug('call pause flowing=%j', this._readableState.flowing);\n if (false !== this._readableState.flowing) {\n debug('pause');\n this._readableState.flowing = false;\n this.emit('pause');\n }\n return this;\n};\n\nfunction flow(stream) {\n var state = stream._readableState;\n debug('flow', state.flowing);\n while (state.flowing && stream.read() !== null) {}\n}\n\n// wrap an old-style stream as the async data source.\n// This is *not* part of the readable stream interface.\n// It is an ugly unfortunate mess of history.\nReadable.prototype.wrap = function (stream) {\n var _this = this;\n\n var state = this._readableState;\n var paused = false;\n\n stream.on('end', function () {\n debug('wrapped end');\n if (state.decoder && !state.ended) {\n var chunk = state.decoder.end();\n if (chunk && chunk.length) _this.push(chunk);\n }\n\n _this.push(null);\n });\n\n stream.on('data', function (chunk) {\n debug('wrapped data');\n if (state.decoder) chunk = state.decoder.write(chunk);\n\n // don't skip over falsy values in objectMode\n if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return;\n\n var ret = _this.push(chunk);\n if (!ret) {\n paused = true;\n stream.pause();\n }\n });\n\n // proxy all the other methods.\n // important when wrapping filters and duplexes.\n for (var i in stream) {\n if (this[i] === undefined && typeof stream[i] === 'function') {\n this[i] = function (method) {\n return function () {\n return stream[method].apply(stream, arguments);\n };\n }(i);\n }\n }\n\n // proxy certain important events.\n for (var n = 0; n < kProxyEvents.length; n++) {\n stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n]));\n }\n\n // when we try to consume some more bytes, simply unpause the\n // underlying stream.\n this._read = function (n) {\n debug('wrapped _read', n);\n if (paused) {\n paused = false;\n stream.resume();\n }\n };\n\n return this;\n};\n\nObject.defineProperty(Readable.prototype, 'readableHighWaterMark', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function () {\n return this._readableState.highWaterMark;\n }\n});\n\n// exposed for testing purposes only.\nReadable._fromList = fromList;\n\n// Pluck off n bytes from an array of buffers.\n// Length is the combined lengths of all the buffers in the list.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction fromList(n, state) {\n // nothing buffered\n if (state.length === 0) return null;\n\n var ret;\n if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) {\n // read it all, truncate the list\n if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length);\n state.buffer.clear();\n } else {\n // read part of list\n ret = fromListPartial(n, state.buffer, state.decoder);\n }\n\n return ret;\n}\n\n// Extracts only enough buffered data to satisfy the amount requested.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction fromListPartial(n, list, hasStrings) {\n var ret;\n if (n < list.head.data.length) {\n // slice is the same for buffers and strings\n ret = list.head.data.slice(0, n);\n list.head.data = list.head.data.slice(n);\n } else if (n === list.head.data.length) {\n // first chunk is a perfect match\n ret = list.shift();\n } else {\n // result spans more than one buffer\n ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list);\n }\n return ret;\n}\n\n// Copies a specified amount of characters from the list of buffered data\n// chunks.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction copyFromBufferString(n, list) {\n var p = list.head;\n var c = 1;\n var ret = p.data;\n n -= ret.length;\n while (p = p.next) {\n var str = p.data;\n var nb = n > str.length ? str.length : n;\n if (nb === str.length) ret += str;else ret += str.slice(0, n);\n n -= nb;\n if (n === 0) {\n if (nb === str.length) {\n ++c;\n if (p.next) list.head = p.next;else list.head = list.tail = null;\n } else {\n list.head = p;\n p.data = str.slice(nb);\n }\n break;\n }\n ++c;\n }\n list.length -= c;\n return ret;\n}\n\n// Copies a specified amount of bytes from the list of buffered data chunks.\n// This function is designed to be inlinable, so please take care when making\n// changes to the function body.\nfunction copyFromBuffer(n, list) {\n var ret = Buffer.allocUnsafe(n);\n var p = list.head;\n var c = 1;\n p.data.copy(ret);\n n -= p.data.length;\n while (p = p.next) {\n var buf = p.data;\n var nb = n > buf.length ? buf.length : n;\n buf.copy(ret, ret.length - n, 0, nb);\n n -= nb;\n if (n === 0) {\n if (nb === buf.length) {\n ++c;\n if (p.next) list.head = p.next;else list.head = list.tail = null;\n } else {\n list.head = p;\n p.data = buf.slice(nb);\n }\n break;\n }\n ++c;\n }\n list.length -= c;\n return ret;\n}\n\nfunction endReadable(stream) {\n var state = stream._readableState;\n\n // If we get here before consuming all the bytes, then that is a\n // bug in node. Should never happen.\n if (state.length > 0) throw new Error('\"endReadable()\" called on non-empty stream');\n\n if (!state.endEmitted) {\n state.ended = true;\n pna.nextTick(endReadableNT, state, stream);\n }\n}\n\nfunction endReadableNT(state, stream) {\n // Check that we didn't get one last unshift.\n if (!state.endEmitted && state.length === 0) {\n state.endEmitted = true;\n stream.readable = false;\n stream.emit('end');\n }\n}\n\nfunction indexOf(xs, x) {\n for (var i = 0, l = xs.length; i < l; i++) {\n if (xs[i] === x) return i;\n }\n return -1;\n}","module.exports = require('events').EventEmitter;\n","'use strict';\n\n/**/\n\nvar pna = require('process-nextick-args');\n/**/\n\n// undocumented cb() API, needed for core, not for public API\nfunction destroy(err, cb) {\n var _this = this;\n\n var readableDestroyed = this._readableState && this._readableState.destroyed;\n var writableDestroyed = this._writableState && this._writableState.destroyed;\n\n if (readableDestroyed || writableDestroyed) {\n if (cb) {\n cb(err);\n } else if (err && (!this._writableState || !this._writableState.errorEmitted)) {\n pna.nextTick(emitErrorNT, this, err);\n }\n return this;\n }\n\n // we set destroyed to true before firing error callbacks in order\n // to make it re-entrance safe in case destroy() is called within callbacks\n\n if (this._readableState) {\n this._readableState.destroyed = true;\n }\n\n // if this is a duplex stream mark the writable part as destroyed as well\n if (this._writableState) {\n this._writableState.destroyed = true;\n }\n\n this._destroy(err || null, function (err) {\n if (!cb && err) {\n pna.nextTick(emitErrorNT, _this, err);\n if (_this._writableState) {\n _this._writableState.errorEmitted = true;\n }\n } else if (cb) {\n cb(err);\n }\n });\n\n return this;\n}\n\nfunction undestroy() {\n if (this._readableState) {\n this._readableState.destroyed = false;\n this._readableState.reading = false;\n this._readableState.ended = false;\n this._readableState.endEmitted = false;\n }\n\n if (this._writableState) {\n this._writableState.destroyed = false;\n this._writableState.ended = false;\n this._writableState.ending = false;\n this._writableState.finished = false;\n this._writableState.errorEmitted = false;\n }\n}\n\nfunction emitErrorNT(self, err) {\n self.emit('error', err);\n}\n\nmodule.exports = {\n destroy: destroy,\n undestroy: undestroy\n};","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// A bit simpler than readable streams.\n// Implement an async ._write(chunk, encoding, cb), and it'll handle all\n// the drain event emission and buffering.\n\n'use strict';\n\n/**/\n\nvar pna = require('process-nextick-args');\n/**/\n\nmodule.exports = Writable;\n\n/* */\nfunction WriteReq(chunk, encoding, cb) {\n this.chunk = chunk;\n this.encoding = encoding;\n this.callback = cb;\n this.next = null;\n}\n\n// It seems a linked list but it is not\n// there will be only 2 of these for each stream\nfunction CorkedRequest(state) {\n var _this = this;\n\n this.next = null;\n this.entry = null;\n this.finish = function () {\n onCorkedFinish(_this, state);\n };\n}\n/* */\n\n/**/\nvar asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : pna.nextTick;\n/**/\n\n/**/\nvar Duplex;\n/**/\n\nWritable.WritableState = WritableState;\n\n/**/\nvar util = Object.create(require('core-util-is'));\nutil.inherits = require('inherits');\n/**/\n\n/**/\nvar internalUtil = {\n deprecate: require('util-deprecate')\n};\n/**/\n\n/**/\nvar Stream = require('./internal/streams/stream');\n/**/\n\n/**/\n\nvar Buffer = require('safe-buffer').Buffer;\nvar OurUint8Array = global.Uint8Array || function () {};\nfunction _uint8ArrayToBuffer(chunk) {\n return Buffer.from(chunk);\n}\nfunction _isUint8Array(obj) {\n return Buffer.isBuffer(obj) || obj instanceof OurUint8Array;\n}\n\n/**/\n\nvar destroyImpl = require('./internal/streams/destroy');\n\nutil.inherits(Writable, Stream);\n\nfunction nop() {}\n\nfunction WritableState(options, stream) {\n Duplex = Duplex || require('./_stream_duplex');\n\n options = options || {};\n\n // Duplex streams are both readable and writable, but share\n // the same options object.\n // However, some cases require setting options to different\n // values for the readable and the writable sides of the duplex stream.\n // These options can be provided separately as readableXXX and writableXXX.\n var isDuplex = stream instanceof Duplex;\n\n // object stream flag to indicate whether or not this stream\n // contains buffers or objects.\n this.objectMode = !!options.objectMode;\n\n if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode;\n\n // the point at which write() starts returning false\n // Note: 0 is a valid value, means that we always return false if\n // the entire buffer is not flushed immediately on write()\n var hwm = options.highWaterMark;\n var writableHwm = options.writableHighWaterMark;\n var defaultHwm = this.objectMode ? 16 : 16 * 1024;\n\n if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (writableHwm || writableHwm === 0)) this.highWaterMark = writableHwm;else this.highWaterMark = defaultHwm;\n\n // cast to ints.\n this.highWaterMark = Math.floor(this.highWaterMark);\n\n // if _final has been called\n this.finalCalled = false;\n\n // drain event flag.\n this.needDrain = false;\n // at the start of calling end()\n this.ending = false;\n // when end() has been called, and returned\n this.ended = false;\n // when 'finish' is emitted\n this.finished = false;\n\n // has it been destroyed\n this.destroyed = false;\n\n // should we decode strings into buffers before passing to _write?\n // this is here so that some node-core streams can optimize string\n // handling at a lower level.\n var noDecode = options.decodeStrings === false;\n this.decodeStrings = !noDecode;\n\n // Crypto is kind of old and crusty. Historically, its default string\n // encoding is 'binary' so we have to make this configurable.\n // Everything else in the universe uses 'utf8', though.\n this.defaultEncoding = options.defaultEncoding || 'utf8';\n\n // not an actual buffer we keep track of, but a measurement\n // of how much we're waiting to get pushed to some underlying\n // socket or file.\n this.length = 0;\n\n // a flag to see when we're in the middle of a write.\n this.writing = false;\n\n // when true all writes will be buffered until .uncork() call\n this.corked = 0;\n\n // a flag to be able to tell if the onwrite cb is called immediately,\n // or on a later tick. We set this to true at first, because any\n // actions that shouldn't happen until \"later\" should generally also\n // not happen before the first write call.\n this.sync = true;\n\n // a flag to know if we're processing previously buffered items, which\n // may call the _write() callback in the same tick, so that we don't\n // end up in an overlapped onwrite situation.\n this.bufferProcessing = false;\n\n // the callback that's passed to _write(chunk,cb)\n this.onwrite = function (er) {\n onwrite(stream, er);\n };\n\n // the callback that the user supplies to write(chunk,encoding,cb)\n this.writecb = null;\n\n // the amount that is being written when _write is called.\n this.writelen = 0;\n\n this.bufferedRequest = null;\n this.lastBufferedRequest = null;\n\n // number of pending user-supplied write callbacks\n // this must be 0 before 'finish' can be emitted\n this.pendingcb = 0;\n\n // emit prefinish if the only thing we're waiting for is _write cbs\n // This is relevant for synchronous Transform streams\n this.prefinished = false;\n\n // True if the error was already emitted and should not be thrown again\n this.errorEmitted = false;\n\n // count buffered requests\n this.bufferedRequestCount = 0;\n\n // allocate the first CorkedRequest, there is always\n // one allocated and free to use, and we maintain at most two\n this.corkedRequestsFree = new CorkedRequest(this);\n}\n\nWritableState.prototype.getBuffer = function getBuffer() {\n var current = this.bufferedRequest;\n var out = [];\n while (current) {\n out.push(current);\n current = current.next;\n }\n return out;\n};\n\n(function () {\n try {\n Object.defineProperty(WritableState.prototype, 'buffer', {\n get: internalUtil.deprecate(function () {\n return this.getBuffer();\n }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003')\n });\n } catch (_) {}\n})();\n\n// Test _writableState for inheritance to account for Duplex streams,\n// whose prototype chain only points to Readable.\nvar realHasInstance;\nif (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') {\n realHasInstance = Function.prototype[Symbol.hasInstance];\n Object.defineProperty(Writable, Symbol.hasInstance, {\n value: function (object) {\n if (realHasInstance.call(this, object)) return true;\n if (this !== Writable) return false;\n\n return object && object._writableState instanceof WritableState;\n }\n });\n} else {\n realHasInstance = function (object) {\n return object instanceof this;\n };\n}\n\nfunction Writable(options) {\n Duplex = Duplex || require('./_stream_duplex');\n\n // Writable ctor is applied to Duplexes, too.\n // `realHasInstance` is necessary because using plain `instanceof`\n // would return false, as no `_writableState` property is attached.\n\n // Trying to use the custom `instanceof` for Writable here will also break the\n // Node.js LazyTransform implementation, which has a non-trivial getter for\n // `_writableState` that would lead to infinite recursion.\n if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) {\n return new Writable(options);\n }\n\n this._writableState = new WritableState(options, this);\n\n // legacy.\n this.writable = true;\n\n if (options) {\n if (typeof options.write === 'function') this._write = options.write;\n\n if (typeof options.writev === 'function') this._writev = options.writev;\n\n if (typeof options.destroy === 'function') this._destroy = options.destroy;\n\n if (typeof options.final === 'function') this._final = options.final;\n }\n\n Stream.call(this);\n}\n\n// Otherwise people can pipe Writable streams, which is just wrong.\nWritable.prototype.pipe = function () {\n this.emit('error', new Error('Cannot pipe, not readable'));\n};\n\nfunction writeAfterEnd(stream, cb) {\n var er = new Error('write after end');\n // TODO: defer error events consistently everywhere, not just the cb\n stream.emit('error', er);\n pna.nextTick(cb, er);\n}\n\n// Checks that a user-supplied chunk is valid, especially for the particular\n// mode the stream is in. Currently this means that `null` is never accepted\n// and undefined/non-string values are only allowed in object mode.\nfunction validChunk(stream, state, chunk, cb) {\n var valid = true;\n var er = false;\n\n if (chunk === null) {\n er = new TypeError('May not write null values to stream');\n } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) {\n er = new TypeError('Invalid non-string/buffer chunk');\n }\n if (er) {\n stream.emit('error', er);\n pna.nextTick(cb, er);\n valid = false;\n }\n return valid;\n}\n\nWritable.prototype.write = function (chunk, encoding, cb) {\n var state = this._writableState;\n var ret = false;\n var isBuf = !state.objectMode && _isUint8Array(chunk);\n\n if (isBuf && !Buffer.isBuffer(chunk)) {\n chunk = _uint8ArrayToBuffer(chunk);\n }\n\n if (typeof encoding === 'function') {\n cb = encoding;\n encoding = null;\n }\n\n if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding;\n\n if (typeof cb !== 'function') cb = nop;\n\n if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) {\n state.pendingcb++;\n ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb);\n }\n\n return ret;\n};\n\nWritable.prototype.cork = function () {\n var state = this._writableState;\n\n state.corked++;\n};\n\nWritable.prototype.uncork = function () {\n var state = this._writableState;\n\n if (state.corked) {\n state.corked--;\n\n if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);\n }\n};\n\nWritable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {\n // node::ParseEncoding() requires lower case.\n if (typeof encoding === 'string') encoding = encoding.toLowerCase();\n if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding);\n this._writableState.defaultEncoding = encoding;\n return this;\n};\n\nfunction decodeChunk(state, chunk, encoding) {\n if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') {\n chunk = Buffer.from(chunk, encoding);\n }\n return chunk;\n}\n\nObject.defineProperty(Writable.prototype, 'writableHighWaterMark', {\n // making it explicit this property is not enumerable\n // because otherwise some prototype manipulation in\n // userland will fail\n enumerable: false,\n get: function () {\n return this._writableState.highWaterMark;\n }\n});\n\n// if we're already writing something, then just put this\n// in the queue, and wait our turn. Otherwise, call _write\n// If we return false, then we need a drain event, so set that flag.\nfunction writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) {\n if (!isBuf) {\n var newChunk = decodeChunk(state, chunk, encoding);\n if (chunk !== newChunk) {\n isBuf = true;\n encoding = 'buffer';\n chunk = newChunk;\n }\n }\n var len = state.objectMode ? 1 : chunk.length;\n\n state.length += len;\n\n var ret = state.length < state.highWaterMark;\n // we must ensure that previous needDrain will not be reset to false.\n if (!ret) state.needDrain = true;\n\n if (state.writing || state.corked) {\n var last = state.lastBufferedRequest;\n state.lastBufferedRequest = {\n chunk: chunk,\n encoding: encoding,\n isBuf: isBuf,\n callback: cb,\n next: null\n };\n if (last) {\n last.next = state.lastBufferedRequest;\n } else {\n state.bufferedRequest = state.lastBufferedRequest;\n }\n state.bufferedRequestCount += 1;\n } else {\n doWrite(stream, state, false, len, chunk, encoding, cb);\n }\n\n return ret;\n}\n\nfunction doWrite(stream, state, writev, len, chunk, encoding, cb) {\n state.writelen = len;\n state.writecb = cb;\n state.writing = true;\n state.sync = true;\n if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite);\n state.sync = false;\n}\n\nfunction onwriteError(stream, state, sync, er, cb) {\n --state.pendingcb;\n\n if (sync) {\n // defer the callback if we are being called synchronously\n // to avoid piling up things on the stack\n pna.nextTick(cb, er);\n // this can emit finish, and it will always happen\n // after error\n pna.nextTick(finishMaybe, stream, state);\n stream._writableState.errorEmitted = true;\n stream.emit('error', er);\n } else {\n // the caller expect this to happen before if\n // it is async\n cb(er);\n stream._writableState.errorEmitted = true;\n stream.emit('error', er);\n // this can emit finish, but finish must\n // always follow error\n finishMaybe(stream, state);\n }\n}\n\nfunction onwriteStateUpdate(state) {\n state.writing = false;\n state.writecb = null;\n state.length -= state.writelen;\n state.writelen = 0;\n}\n\nfunction onwrite(stream, er) {\n var state = stream._writableState;\n var sync = state.sync;\n var cb = state.writecb;\n\n onwriteStateUpdate(state);\n\n if (er) onwriteError(stream, state, sync, er, cb);else {\n // Check if we're actually ready to finish, but don't emit yet\n var finished = needFinish(state);\n\n if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) {\n clearBuffer(stream, state);\n }\n\n if (sync) {\n /**/\n asyncWrite(afterWrite, stream, state, finished, cb);\n /**/\n } else {\n afterWrite(stream, state, finished, cb);\n }\n }\n}\n\nfunction afterWrite(stream, state, finished, cb) {\n if (!finished) onwriteDrain(stream, state);\n state.pendingcb--;\n cb();\n finishMaybe(stream, state);\n}\n\n// Must force callback to be called on nextTick, so that we don't\n// emit 'drain' before the write() consumer gets the 'false' return\n// value, and has a chance to attach a 'drain' listener.\nfunction onwriteDrain(stream, state) {\n if (state.length === 0 && state.needDrain) {\n state.needDrain = false;\n stream.emit('drain');\n }\n}\n\n// if there's something in the buffer waiting, then process it\nfunction clearBuffer(stream, state) {\n state.bufferProcessing = true;\n var entry = state.bufferedRequest;\n\n if (stream._writev && entry && entry.next) {\n // Fast case, write everything using _writev()\n var l = state.bufferedRequestCount;\n var buffer = new Array(l);\n var holder = state.corkedRequestsFree;\n holder.entry = entry;\n\n var count = 0;\n var allBuffers = true;\n while (entry) {\n buffer[count] = entry;\n if (!entry.isBuf) allBuffers = false;\n entry = entry.next;\n count += 1;\n }\n buffer.allBuffers = allBuffers;\n\n doWrite(stream, state, true, state.length, buffer, '', holder.finish);\n\n // doWrite is almost always async, defer these to save a bit of time\n // as the hot path ends with doWrite\n state.pendingcb++;\n state.lastBufferedRequest = null;\n if (holder.next) {\n state.corkedRequestsFree = holder.next;\n holder.next = null;\n } else {\n state.corkedRequestsFree = new CorkedRequest(state);\n }\n state.bufferedRequestCount = 0;\n } else {\n // Slow case, write chunks one-by-one\n while (entry) {\n var chunk = entry.chunk;\n var encoding = entry.encoding;\n var cb = entry.callback;\n var len = state.objectMode ? 1 : chunk.length;\n\n doWrite(stream, state, false, len, chunk, encoding, cb);\n entry = entry.next;\n state.bufferedRequestCount--;\n // if we didn't call the onwrite immediately, then\n // it means that we need to wait until it does.\n // also, that means that the chunk and cb are currently\n // being processed, so move the buffer counter past them.\n if (state.writing) {\n break;\n }\n }\n\n if (entry === null) state.lastBufferedRequest = null;\n }\n\n state.bufferedRequest = entry;\n state.bufferProcessing = false;\n}\n\nWritable.prototype._write = function (chunk, encoding, cb) {\n cb(new Error('_write() is not implemented'));\n};\n\nWritable.prototype._writev = null;\n\nWritable.prototype.end = function (chunk, encoding, cb) {\n var state = this._writableState;\n\n if (typeof chunk === 'function') {\n cb = chunk;\n chunk = null;\n encoding = null;\n } else if (typeof encoding === 'function') {\n cb = encoding;\n encoding = null;\n }\n\n if (chunk !== null && chunk !== undefined) this.write(chunk, encoding);\n\n // .end() fully uncorks\n if (state.corked) {\n state.corked = 1;\n this.uncork();\n }\n\n // ignore unnecessary end() calls.\n if (!state.ending && !state.finished) endWritable(this, state, cb);\n};\n\nfunction needFinish(state) {\n return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing;\n}\nfunction callFinal(stream, state) {\n stream._final(function (err) {\n state.pendingcb--;\n if (err) {\n stream.emit('error', err);\n }\n state.prefinished = true;\n stream.emit('prefinish');\n finishMaybe(stream, state);\n });\n}\nfunction prefinish(stream, state) {\n if (!state.prefinished && !state.finalCalled) {\n if (typeof stream._final === 'function') {\n state.pendingcb++;\n state.finalCalled = true;\n pna.nextTick(callFinal, stream, state);\n } else {\n state.prefinished = true;\n stream.emit('prefinish');\n }\n }\n}\n\nfunction finishMaybe(stream, state) {\n var need = needFinish(state);\n if (need) {\n prefinish(stream, state);\n if (state.pendingcb === 0) {\n state.finished = true;\n stream.emit('finish');\n }\n }\n return need;\n}\n\nfunction endWritable(stream, state, cb) {\n state.ending = true;\n finishMaybe(stream, state);\n if (cb) {\n if (state.finished) pna.nextTick(cb);else stream.once('finish', cb);\n }\n state.ended = true;\n stream.writable = false;\n}\n\nfunction onCorkedFinish(corkReq, state, err) {\n var entry = corkReq.entry;\n corkReq.entry = null;\n while (entry) {\n var cb = entry.callback;\n state.pendingcb--;\n cb(err);\n entry = entry.next;\n }\n if (state.corkedRequestsFree) {\n state.corkedRequestsFree.next = corkReq;\n } else {\n state.corkedRequestsFree = corkReq;\n }\n}\n\nObject.defineProperty(Writable.prototype, 'destroyed', {\n get: function () {\n if (this._writableState === undefined) {\n return false;\n }\n return this._writableState.destroyed;\n },\n set: function (value) {\n // we ignore the value if the stream\n // has not been initialized yet\n if (!this._writableState) {\n return;\n }\n\n // backward compatibility, the user is explicitly\n // managing destroyed\n this._writableState.destroyed = value;\n }\n});\n\nWritable.prototype.destroy = destroyImpl.destroy;\nWritable.prototype._undestroy = destroyImpl.undestroy;\nWritable.prototype._destroy = function (err, cb) {\n this.end();\n cb(err);\n};","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n// a transform stream is a readable/writable stream where you do\n// something with the data. Sometimes it's called a \"filter\",\n// but that's not a great name for it, since that implies a thing where\n// some bits pass through, and others are simply ignored. (That would\n// be a valid example of a transform, of course.)\n//\n// While the output is causally related to the input, it's not a\n// necessarily symmetric or synchronous transformation. For example,\n// a zlib stream might take multiple plain-text writes(), and then\n// emit a single compressed chunk some time in the future.\n//\n// Here's how this works:\n//\n// The Transform stream has all the aspects of the readable and writable\n// stream classes. When you write(chunk), that calls _write(chunk,cb)\n// internally, and returns false if there's a lot of pending writes\n// buffered up. When you call read(), that calls _read(n) until\n// there's enough pending readable data buffered up.\n//\n// In a transform stream, the written data is placed in a buffer. When\n// _read(n) is called, it transforms the queued up data, calling the\n// buffered _write cb's as it consumes chunks. If consuming a single\n// written chunk would result in multiple output chunks, then the first\n// outputted bit calls the readcb, and subsequent chunks just go into\n// the read buffer, and will cause it to emit 'readable' if necessary.\n//\n// This way, back-pressure is actually determined by the reading side,\n// since _read has to be called to start processing a new chunk. However,\n// a pathological inflate type of transform can cause excessive buffering\n// here. For example, imagine a stream where every byte of input is\n// interpreted as an integer from 0-255, and then results in that many\n// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in\n// 1kb of data being output. In this case, you could write a very small\n// amount of input, and end up with a very large amount of output. In\n// such a pathological inflating mechanism, there'd be no way to tell\n// the system to stop doing the transform. A single 4MB write could\n// cause the system to run out of memory.\n//\n// However, even in such a pathological case, only a single written chunk\n// would be consumed, and then the rest would wait (un-transformed) until\n// the results of the previous transformed chunk were consumed.\n\n'use strict';\n\nmodule.exports = Transform;\n\nvar Duplex = require('./_stream_duplex');\n\n/**/\nvar util = Object.create(require('core-util-is'));\nutil.inherits = require('inherits');\n/**/\n\nutil.inherits(Transform, Duplex);\n\nfunction afterTransform(er, data) {\n var ts = this._transformState;\n ts.transforming = false;\n\n var cb = ts.writecb;\n\n if (!cb) {\n return this.emit('error', new Error('write callback called multiple times'));\n }\n\n ts.writechunk = null;\n ts.writecb = null;\n\n if (data != null) // single equals check for both `null` and `undefined`\n this.push(data);\n\n cb(er);\n\n var rs = this._readableState;\n rs.reading = false;\n if (rs.needReadable || rs.length < rs.highWaterMark) {\n this._read(rs.highWaterMark);\n }\n}\n\nfunction Transform(options) {\n if (!(this instanceof Transform)) return new Transform(options);\n\n Duplex.call(this, options);\n\n this._transformState = {\n afterTransform: afterTransform.bind(this),\n needTransform: false,\n transforming: false,\n writecb: null,\n writechunk: null,\n writeencoding: null\n };\n\n // start out asking for a readable event once data is transformed.\n this._readableState.needReadable = true;\n\n // we have implemented the _read method, and done the other things\n // that Readable wants before the first _read call, so unset the\n // sync guard flag.\n this._readableState.sync = false;\n\n if (options) {\n if (typeof options.transform === 'function') this._transform = options.transform;\n\n if (typeof options.flush === 'function') this._flush = options.flush;\n }\n\n // When the writable side finishes, then flush out anything remaining.\n this.on('prefinish', prefinish);\n}\n\nfunction prefinish() {\n var _this = this;\n\n if (typeof this._flush === 'function') {\n this._flush(function (er, data) {\n done(_this, er, data);\n });\n } else {\n done(this, null, null);\n }\n}\n\nTransform.prototype.push = function (chunk, encoding) {\n this._transformState.needTransform = false;\n return Duplex.prototype.push.call(this, chunk, encoding);\n};\n\n// This is the part where you do stuff!\n// override this function in implementation classes.\n// 'chunk' is an input chunk.\n//\n// Call `push(newChunk)` to pass along transformed output\n// to the readable side. You may call 'push' zero or more times.\n//\n// Call `cb(err)` when you are done with this chunk. If you pass\n// an error, then that'll put the hurt on the whole operation. If you\n// never call cb(), then you'll never get another chunk.\nTransform.prototype._transform = function (chunk, encoding, cb) {\n throw new Error('_transform() is not implemented');\n};\n\nTransform.prototype._write = function (chunk, encoding, cb) {\n var ts = this._transformState;\n ts.writecb = cb;\n ts.writechunk = chunk;\n ts.writeencoding = encoding;\n if (!ts.transforming) {\n var rs = this._readableState;\n if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark);\n }\n};\n\n// Doesn't matter what the args are here.\n// _transform does all the work.\n// That we got here means that the readable side wants more data.\nTransform.prototype._read = function (n) {\n var ts = this._transformState;\n\n if (ts.writechunk !== null && ts.writecb && !ts.transforming) {\n ts.transforming = true;\n this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);\n } else {\n // mark that we need a transform, so that any data that comes in\n // will get processed, now that we've asked for it.\n ts.needTransform = true;\n }\n};\n\nTransform.prototype._destroy = function (err, cb) {\n var _this2 = this;\n\n Duplex.prototype._destroy.call(this, err, function (err2) {\n cb(err2);\n _this2.emit('close');\n });\n};\n\nfunction done(stream, er, data) {\n if (er) return stream.emit('error', er);\n\n if (data != null) // single equals check for both `null` and `undefined`\n stream.push(data);\n\n // if there's nothing in the write buffer, then that means\n // that nothing more will ever be provided\n if (stream._writableState.length) throw new Error('Calling transform done when ws.length != 0');\n\n if (stream._transformState.transforming) throw new Error('Calling transform done when still transforming');\n\n return stream.push(null);\n}","'use strict';\n\n// Note: adler32 takes 12% for level 0 and 2% for level 6.\n// It isn't worth it to make additional optimizations as in original.\n// Small size is preferable.\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n// claim that you wrote the original software. If you use this software\n// in a product, an acknowledgment in the product documentation would be\n// appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n// misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\nfunction adler32(adler, buf, len, pos) {\n var s1 = (adler & 0xffff) |0,\n s2 = ((adler >>> 16) & 0xffff) |0,\n n = 0;\n\n while (len !== 0) {\n // Set limit ~ twice less than 5552, to keep\n // s2 in 31-bits, because we force signed ints.\n // in other case %= will fail.\n n = len > 2000 ? 2000 : len;\n len -= n;\n\n do {\n s1 = (s1 + buf[pos++]) |0;\n s2 = (s2 + s1) |0;\n } while (--n);\n\n s1 %= 65521;\n s2 %= 65521;\n }\n\n return (s1 | (s2 << 16)) |0;\n}\n\n\nmodule.exports = adler32;\n","'use strict';\n\n// Note: we can't get significant speed boost here.\n// So write code to minimize size - no pregenerated tables\n// and array tools dependencies.\n\n// (C) 1995-2013 Jean-loup Gailly and Mark Adler\n// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin\n//\n// This software is provided 'as-is', without any express or implied\n// warranty. In no event will the authors be held liable for any damages\n// arising from the use of this software.\n//\n// Permission is granted to anyone to use this software for any purpose,\n// including commercial applications, and to alter it and redistribute it\n// freely, subject to the following restrictions:\n//\n// 1. The origin of this software must not be misrepresented; you must not\n// claim that you wrote the original software. If you use this software\n// in a product, an acknowledgment in the product documentation would be\n// appreciated but is not required.\n// 2. Altered source versions must be plainly marked as such, and must not be\n// misrepresented as being the original software.\n// 3. This notice may not be removed or altered from any source distribution.\n\n// Use ordinary array, since untyped makes no boost here\nfunction makeTable() {\n var c, table = [];\n\n for (var n = 0; n < 256; n++) {\n c = n;\n for (var k = 0; k < 8; k++) {\n c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));\n }\n table[n] = c;\n }\n\n return table;\n}\n\n// Create table on load. Just 255 signed longs. Not a problem.\nvar crcTable = makeTable();\n\n\nfunction crc32(crc, buf, len, pos) {\n var t = crcTable,\n end = pos + len;\n\n crc ^= -1;\n\n for (var i = pos; i < end; i++) {\n crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];\n }\n\n return (crc ^ (-1)); // >>> 0;\n}\n\n\nmodule.exports = crc32;\n","// Copyright 2015 Joyent, Inc.\n\nmodule.exports = {\n\tVerifier: Verifier,\n\tSigner: Signer\n};\n\nvar nacl = require('tweetnacl');\nvar stream = require('stream');\nvar util = require('util');\nvar assert = require('assert-plus');\nvar Buffer = require('safer-buffer').Buffer;\nvar Signature = require('./signature');\n\nfunction Verifier(key, hashAlgo) {\n\tif (hashAlgo.toLowerCase() !== 'sha512')\n\t\tthrow (new Error('ED25519 only supports the use of ' +\n\t\t 'SHA-512 hashes'));\n\n\tthis.key = key;\n\tthis.chunks = [];\n\n\tstream.Writable.call(this, {});\n}\nutil.inherits(Verifier, stream.Writable);\n\nVerifier.prototype._write = function (chunk, enc, cb) {\n\tthis.chunks.push(chunk);\n\tcb();\n};\n\nVerifier.prototype.update = function (chunk) {\n\tif (typeof (chunk) === 'string')\n\t\tchunk = Buffer.from(chunk, 'binary');\n\tthis.chunks.push(chunk);\n};\n\nVerifier.prototype.verify = function (signature, fmt) {\n\tvar sig;\n\tif (Signature.isSignature(signature, [2, 0])) {\n\t\tif (signature.type !== 'ed25519')\n\t\t\treturn (false);\n\t\tsig = signature.toBuffer('raw');\n\n\t} else if (typeof (signature) === 'string') {\n\t\tsig = Buffer.from(signature, 'base64');\n\n\t} else if (Signature.isSignature(signature, [1, 0])) {\n\t\tthrow (new Error('signature was created by too old ' +\n\t\t 'a version of sshpk and cannot be verified'));\n\t}\n\n\tassert.buffer(sig);\n\treturn (nacl.sign.detached.verify(\n\t new Uint8Array(Buffer.concat(this.chunks)),\n\t new Uint8Array(sig),\n\t new Uint8Array(this.key.part.A.data)));\n};\n\nfunction Signer(key, hashAlgo) {\n\tif (hashAlgo.toLowerCase() !== 'sha512')\n\t\tthrow (new Error('ED25519 only supports the use of ' +\n\t\t 'SHA-512 hashes'));\n\n\tthis.key = key;\n\tthis.chunks = [];\n\n\tstream.Writable.call(this, {});\n}\nutil.inherits(Signer, stream.Writable);\n\nSigner.prototype._write = function (chunk, enc, cb) {\n\tthis.chunks.push(chunk);\n\tcb();\n};\n\nSigner.prototype.update = function (chunk) {\n\tif (typeof (chunk) === 'string')\n\t\tchunk = Buffer.from(chunk, 'binary');\n\tthis.chunks.push(chunk);\n};\n\nSigner.prototype.sign = function () {\n\tvar sig = nacl.sign.detached(\n\t new Uint8Array(Buffer.concat(this.chunks)),\n\t new Uint8Array(Buffer.concat([\n\t\tthis.key.part.k.data, this.key.part.A.data])));\n\tvar sigBuf = Buffer.from(sig);\n\tvar sigObj = Signature.parse(sigBuf, 'ed25519', 'raw');\n\tsigObj.hashAlgorithm = 'sha512';\n\treturn (sigObj);\n};\n","// Copyright 2015 Joyent, Inc.\n\nmodule.exports = {\n\tread: read,\n\twrite: write\n};\n\nvar assert = require('assert-plus');\nvar Buffer = require('safer-buffer').Buffer;\nvar utils = require('../utils');\nvar Key = require('../key');\nvar PrivateKey = require('../private-key');\n\nvar pem = require('./pem');\nvar ssh = require('./ssh');\nvar rfc4253 = require('./rfc4253');\nvar dnssec = require('./dnssec');\n\nvar DNSSEC_PRIVKEY_HEADER_PREFIX = 'Private-key-format: v1';\n\nfunction read(buf, options) {\n\tif (typeof (buf) === 'string') {\n\t\tif (buf.trim().match(/^[-]+[ ]*BEGIN/))\n\t\t\treturn (pem.read(buf, options));\n\t\tif (buf.match(/^\\s*ssh-[a-z]/))\n\t\t\treturn (ssh.read(buf, options));\n\t\tif (buf.match(/^\\s*ecdsa-/))\n\t\t\treturn (ssh.read(buf, options));\n\t\tif (findDNSSECHeader(buf))\n\t\t\treturn (dnssec.read(buf, options));\n\t\tbuf = Buffer.from(buf, 'binary');\n\t} else {\n\t\tassert.buffer(buf);\n\t\tif (findPEMHeader(buf))\n\t\t\treturn (pem.read(buf, options));\n\t\tif (findSSHHeader(buf))\n\t\t\treturn (ssh.read(buf, options));\n\t\tif (findDNSSECHeader(buf))\n\t\t\treturn (dnssec.read(buf, options));\n\t}\n\tif (buf.readUInt32BE(0) < buf.length)\n\t\treturn (rfc4253.read(buf, options));\n\tthrow (new Error('Failed to auto-detect format of key'));\n}\n\nfunction findSSHHeader(buf) {\n\tvar offset = 0;\n\twhile (offset < buf.length &&\n\t (buf[offset] === 32 || buf[offset] === 10 || buf[offset] === 9))\n\t\t++offset;\n\tif (offset + 4 <= buf.length &&\n\t buf.slice(offset, offset + 4).toString('ascii') === 'ssh-')\n\t\treturn (true);\n\tif (offset + 6 <= buf.length &&\n\t buf.slice(offset, offset + 6).toString('ascii') === 'ecdsa-')\n\t\treturn (true);\n\treturn (false);\n}\n\nfunction findPEMHeader(buf) {\n\tvar offset = 0;\n\twhile (offset < buf.length &&\n\t (buf[offset] === 32 || buf[offset] === 10))\n\t\t++offset;\n\tif (buf[offset] !== 45)\n\t\treturn (false);\n\twhile (offset < buf.length &&\n\t (buf[offset] === 45))\n\t\t++offset;\n\twhile (offset < buf.length &&\n\t (buf[offset] === 32))\n\t\t++offset;\n\tif (offset + 5 > buf.length ||\n\t buf.slice(offset, offset + 5).toString('ascii') !== 'BEGIN')\n\t\treturn (false);\n\treturn (true);\n}\n\nfunction findDNSSECHeader(buf) {\n\t// private case first\n\tif (buf.length <= DNSSEC_PRIVKEY_HEADER_PREFIX.length)\n\t\treturn (false);\n\tvar headerCheck = buf.slice(0, DNSSEC_PRIVKEY_HEADER_PREFIX.length);\n\tif (headerCheck.toString('ascii') === DNSSEC_PRIVKEY_HEADER_PREFIX)\n\t\treturn (true);\n\n\t// public-key RFC3110 ?\n\t// 'domain.com. IN KEY ...' or 'domain.com. IN DNSKEY ...'\n\t// skip any comment-lines\n\tif (typeof (buf) !== 'string') {\n\t\tbuf = buf.toString('ascii');\n\t}\n\tvar lines = buf.split('\\n');\n\tvar line = 0;\n\t/* JSSTYLED */\n\twhile (lines[line].match(/^\\;/))\n\t\tline++;\n\tif (lines[line].toString('ascii').match(/\\. IN KEY /))\n\t\treturn (true);\n\tif (lines[line].toString('ascii').match(/\\. IN DNSKEY /))\n\t\treturn (true);\n\treturn (false);\n}\n\nfunction write(key, options) {\n\tthrow (new Error('\"auto\" format cannot be used for writing'));\n}\n","'use strict';\n\nvar crypto_hash_sha512 = require('tweetnacl').lowlevel.crypto_hash;\n\n/*\n * This file is a 1:1 port from the OpenBSD blowfish.c and bcrypt_pbkdf.c. As a\n * result, it retains the original copyright and license. The two files are\n * under slightly different (but compatible) licenses, and are here combined in\n * one file.\n *\n * Credit for the actual porting work goes to:\n * Devi Mandiri \n */\n\n/*\n * The Blowfish portions are under the following license:\n *\n * Blowfish block cipher for OpenBSD\n * Copyright 1997 Niels Provos \n * All rights reserved.\n *\n * Implementation advice by David Mazieres .\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n * 1. Redistributions of source code must retain the above copyright\n * notice, this list of conditions and the following disclaimer.\n * 2. Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n * 3. The name of the author may not be used to endorse or promote products\n * derived from this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n/*\n * The bcrypt_pbkdf portions are under the following license:\n *\n * Copyright (c) 2013 Ted Unangst \n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n/*\n * Performance improvements (Javascript-specific):\n *\n * Copyright 2016, Joyent Inc\n * Author: Alex Wilson \n *\n * Permission to use, copy, modify, and distribute this software for any\n * purpose with or without fee is hereby granted, provided that the above\n * copyright notice and this permission notice appear in all copies.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n */\n\n// Ported from OpenBSD bcrypt_pbkdf.c v1.9\n\nvar BLF_J = 0;\n\nvar Blowfish = function() {\n this.S = [\n new Uint32Array([\n 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,\n 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,\n 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,\n 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,\n 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,\n 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,\n 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,\n 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,\n 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,\n 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,\n 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,\n 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,\n 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,\n 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,\n 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,\n 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,\n 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,\n 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,\n 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,\n 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,\n 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,\n 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,\n 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,\n 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,\n 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,\n 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,\n 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,\n 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,\n 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,\n 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,\n 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,\n 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,\n 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,\n 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,\n 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,\n 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,\n 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,\n 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,\n 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,\n 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,\n 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,\n 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,\n 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,\n 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,\n 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,\n 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,\n 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,\n 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,\n 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,\n 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,\n 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,\n 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,\n 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,\n 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,\n 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,\n 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,\n 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,\n 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,\n 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,\n 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,\n 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,\n 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,\n 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,\n 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a]),\n new Uint32Array([\n 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,\n 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,\n 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,\n 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,\n 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,\n 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,\n 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,\n 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,\n 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,\n 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,\n 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,\n 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,\n 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,\n 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,\n 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,\n 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,\n 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,\n 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,\n 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,\n 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,\n 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,\n 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,\n 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,\n 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,\n 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,\n 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,\n 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,\n 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,\n 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,\n 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,\n 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,\n 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,\n 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,\n 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,\n 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,\n 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,\n 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,\n 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,\n 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,\n 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,\n 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,\n 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,\n 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,\n 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,\n 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,\n 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,\n 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,\n 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,\n 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,\n 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,\n 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,\n 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,\n 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,\n 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,\n 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,\n 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,\n 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,\n 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,\n 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,\n 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,\n 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,\n 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,\n 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,\n 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7]),\n new Uint32Array([\n 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,\n 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,\n 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,\n 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,\n 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,\n 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,\n 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,\n 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,\n 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,\n 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,\n 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,\n 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,\n 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,\n 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,\n 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,\n 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,\n 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,\n 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,\n 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,\n 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,\n 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,\n 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,\n 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,\n 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,\n 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,\n 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,\n 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,\n 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,\n 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,\n 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,\n 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,\n 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,\n 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,\n 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,\n 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,\n 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,\n 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,\n 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,\n 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,\n 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,\n 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,\n 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,\n 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,\n 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,\n 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,\n 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,\n 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,\n 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,\n 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,\n 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,\n 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,\n 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,\n 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,\n 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,\n 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,\n 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,\n 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,\n 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,\n 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,\n 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,\n 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,\n 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,\n 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,\n 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0]),\n new Uint32Array([\n 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,\n 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,\n 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,\n 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,\n 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,\n 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,\n 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,\n 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,\n 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,\n 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,\n 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,\n 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,\n 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,\n 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,\n 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,\n 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,\n 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,\n 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,\n 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,\n 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,\n 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,\n 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,\n 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,\n 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,\n 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,\n 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,\n 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,\n 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,\n 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,\n 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,\n 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,\n 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,\n 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,\n 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,\n 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,\n 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,\n 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,\n 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,\n 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,\n 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,\n 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,\n 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,\n 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,\n 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,\n 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,\n 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,\n 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,\n 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,\n 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,\n 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,\n 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,\n 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,\n 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,\n 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,\n 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,\n 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,\n 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,\n 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,\n 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,\n 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,\n 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,\n 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,\n 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,\n 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6])\n ];\n this.P = new Uint32Array([\n 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,\n 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,\n 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,\n 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,\n 0x9216d5d9, 0x8979fb1b]);\n};\n\nfunction F(S, x8, i) {\n return (((S[0][x8[i+3]] +\n S[1][x8[i+2]]) ^\n S[2][x8[i+1]]) +\n S[3][x8[i]]);\n};\n\nBlowfish.prototype.encipher = function(x, x8) {\n if (x8 === undefined) {\n x8 = new Uint8Array(x.buffer);\n if (x.byteOffset !== 0)\n x8 = x8.subarray(x.byteOffset);\n }\n x[0] ^= this.P[0];\n for (var i = 1; i < 16; i += 2) {\n x[1] ^= F(this.S, x8, 0) ^ this.P[i];\n x[0] ^= F(this.S, x8, 4) ^ this.P[i+1];\n }\n var t = x[0];\n x[0] = x[1] ^ this.P[17];\n x[1] = t;\n};\n\nBlowfish.prototype.decipher = function(x) {\n var x8 = new Uint8Array(x.buffer);\n if (x.byteOffset !== 0)\n x8 = x8.subarray(x.byteOffset);\n x[0] ^= this.P[17];\n for (var i = 16; i > 0; i -= 2) {\n x[1] ^= F(this.S, x8, 0) ^ this.P[i];\n x[0] ^= F(this.S, x8, 4) ^ this.P[i-1];\n }\n var t = x[0];\n x[0] = x[1] ^ this.P[0];\n x[1] = t;\n};\n\nfunction stream2word(data, databytes){\n var i, temp = 0;\n for (i = 0; i < 4; i++, BLF_J++) {\n if (BLF_J >= databytes) BLF_J = 0;\n temp = (temp << 8) | data[BLF_J];\n }\n return temp;\n};\n\nBlowfish.prototype.expand0state = function(key, keybytes) {\n var d = new Uint32Array(2), i, k;\n var d8 = new Uint8Array(d.buffer);\n\n for (i = 0, BLF_J = 0; i < 18; i++) {\n this.P[i] ^= stream2word(key, keybytes);\n }\n BLF_J = 0;\n\n for (i = 0; i < 18; i += 2) {\n this.encipher(d, d8);\n this.P[i] = d[0];\n this.P[i+1] = d[1];\n }\n\n for (i = 0; i < 4; i++) {\n for (k = 0; k < 256; k += 2) {\n this.encipher(d, d8);\n this.S[i][k] = d[0];\n this.S[i][k+1] = d[1];\n }\n }\n};\n\nBlowfish.prototype.expandstate = function(data, databytes, key, keybytes) {\n var d = new Uint32Array(2), i, k;\n\n for (i = 0, BLF_J = 0; i < 18; i++) {\n this.P[i] ^= stream2word(key, keybytes);\n }\n\n for (i = 0, BLF_J = 0; i < 18; i += 2) {\n d[0] ^= stream2word(data, databytes);\n d[1] ^= stream2word(data, databytes);\n this.encipher(d);\n this.P[i] = d[0];\n this.P[i+1] = d[1];\n }\n\n for (i = 0; i < 4; i++) {\n for (k = 0; k < 256; k += 2) {\n d[0] ^= stream2word(data, databytes);\n d[1] ^= stream2word(data, databytes);\n this.encipher(d);\n this.S[i][k] = d[0];\n this.S[i][k+1] = d[1];\n }\n }\n BLF_J = 0;\n};\n\nBlowfish.prototype.enc = function(data, blocks) {\n for (var i = 0; i < blocks; i++) {\n this.encipher(data.subarray(i*2));\n }\n};\n\nBlowfish.prototype.dec = function(data, blocks) {\n for (var i = 0; i < blocks; i++) {\n this.decipher(data.subarray(i*2));\n }\n};\n\nvar BCRYPT_BLOCKS = 8,\n BCRYPT_HASHSIZE = 32;\n\nfunction bcrypt_hash(sha2pass, sha2salt, out) {\n var state = new Blowfish(),\n cdata = new Uint32Array(BCRYPT_BLOCKS), i,\n ciphertext = new Uint8Array([79,120,121,99,104,114,111,109,97,116,105,\n 99,66,108,111,119,102,105,115,104,83,119,97,116,68,121,110,97,109,\n 105,116,101]); //\"OxychromaticBlowfishSwatDynamite\"\n\n state.expandstate(sha2salt, 64, sha2pass, 64);\n for (i = 0; i < 64; i++) {\n state.expand0state(sha2salt, 64);\n state.expand0state(sha2pass, 64);\n }\n\n for (i = 0; i < BCRYPT_BLOCKS; i++)\n cdata[i] = stream2word(ciphertext, ciphertext.byteLength);\n for (i = 0; i < 64; i++)\n state.enc(cdata, cdata.byteLength / 8);\n\n for (i = 0; i < BCRYPT_BLOCKS; i++) {\n out[4*i+3] = cdata[i] >>> 24;\n out[4*i+2] = cdata[i] >>> 16;\n out[4*i+1] = cdata[i] >>> 8;\n out[4*i+0] = cdata[i];\n }\n};\n\nfunction bcrypt_pbkdf(pass, passlen, salt, saltlen, key, keylen, rounds) {\n var sha2pass = new Uint8Array(64),\n sha2salt = new Uint8Array(64),\n out = new Uint8Array(BCRYPT_HASHSIZE),\n tmpout = new Uint8Array(BCRYPT_HASHSIZE),\n countsalt = new Uint8Array(saltlen+4),\n i, j, amt, stride, dest, count,\n origkeylen = keylen;\n\n if (rounds < 1)\n return -1;\n if (passlen === 0 || saltlen === 0 || keylen === 0 ||\n keylen > (out.byteLength * out.byteLength) || saltlen > (1<<20))\n return -1;\n\n stride = Math.floor((keylen + out.byteLength - 1) / out.byteLength);\n amt = Math.floor((keylen + stride - 1) / stride);\n\n for (i = 0; i < saltlen; i++)\n countsalt[i] = salt[i];\n\n crypto_hash_sha512(sha2pass, pass, passlen);\n\n for (count = 1; keylen > 0; count++) {\n countsalt[saltlen+0] = count >>> 24;\n countsalt[saltlen+1] = count >>> 16;\n countsalt[saltlen+2] = count >>> 8;\n countsalt[saltlen+3] = count;\n\n crypto_hash_sha512(sha2salt, countsalt, saltlen + 4);\n bcrypt_hash(sha2pass, sha2salt, tmpout);\n for (i = out.byteLength; i--;)\n out[i] = tmpout[i];\n\n for (i = 1; i < rounds; i++) {\n crypto_hash_sha512(sha2salt, tmpout, tmpout.byteLength);\n bcrypt_hash(sha2pass, sha2salt, tmpout);\n for (j = 0; j < out.byteLength; j++)\n out[j] ^= tmpout[j];\n }\n\n amt = Math.min(amt, keylen);\n for (i = 0; i < amt; i++) {\n dest = i * stride + (count - 1);\n if (dest >= origkeylen)\n break;\n key[dest] = out[i];\n }\n keylen -= i;\n }\n\n return 0;\n};\n\nmodule.exports = {\n BLOCKS: BCRYPT_BLOCKS,\n HASHSIZE: BCRYPT_HASHSIZE,\n hash: bcrypt_hash,\n pbkdf: bcrypt_pbkdf\n};\n","// Copyright 2015 Joyent, Inc.\n\nmodule.exports = {\n\tread: read,\n\twrite: write\n};\n\nvar assert = require('assert-plus');\nvar Buffer = require('safer-buffer').Buffer;\nvar rfc4253 = require('./rfc4253');\nvar utils = require('../utils');\nvar Key = require('../key');\nvar PrivateKey = require('../private-key');\n\nvar sshpriv = require('./ssh-private');\n\n/*JSSTYLED*/\nvar SSHKEY_RE = /^([a-z0-9-]+)[ \\t]+([a-zA-Z0-9+\\/]+[=]*)([ \\t]+([^ \\t][^\\n]*[\\n]*)?)?$/;\n/*JSSTYLED*/\nvar SSHKEY_RE2 = /^([a-z0-9-]+)[ \\t\\n]+([a-zA-Z0-9+\\/][a-zA-Z0-9+\\/ \\t\\n=]*)([^a-zA-Z0-9+\\/ \\t\\n=].*)?$/;\n\nfunction read(buf, options) {\n\tif (typeof (buf) !== 'string') {\n\t\tassert.buffer(buf, 'buf');\n\t\tbuf = buf.toString('ascii');\n\t}\n\n\tvar trimmed = buf.trim().replace(/[\\\\\\r]/g, '');\n\tvar m = trimmed.match(SSHKEY_RE);\n\tif (!m)\n\t\tm = trimmed.match(SSHKEY_RE2);\n\tassert.ok(m, 'key must match regex');\n\n\tvar type = rfc4253.algToKeyType(m[1]);\n\tvar kbuf = Buffer.from(m[2], 'base64');\n\n\t/*\n\t * This is a bit tricky. If we managed to parse the key and locate the\n\t * key comment with the regex, then do a non-partial read and assert\n\t * that we have consumed all bytes. If we couldn't locate the key\n\t * comment, though, there may be whitespace shenanigans going on that\n\t * have conjoined the comment to the rest of the key. We do a partial\n\t * read in this case to try to make the best out of a sorry situation.\n\t */\n\tvar key;\n\tvar ret = {};\n\tif (m[4]) {\n\t\ttry {\n\t\t\tkey = rfc4253.read(kbuf);\n\n\t\t} catch (e) {\n\t\t\tm = trimmed.match(SSHKEY_RE2);\n\t\t\tassert.ok(m, 'key must match regex');\n\t\t\tkbuf = Buffer.from(m[2], 'base64');\n\t\t\tkey = rfc4253.readInternal(ret, 'public', kbuf);\n\t\t}\n\t} else {\n\t\tkey = rfc4253.readInternal(ret, 'public', kbuf);\n\t}\n\n\tassert.strictEqual(type, key.type);\n\n\tif (m[4] && m[4].length > 0) {\n\t\tkey.comment = m[4];\n\n\t} else if (ret.consumed) {\n\t\t/*\n\t\t * Now the magic: trying to recover the key comment when it's\n\t\t * gotten conjoined to the key or otherwise shenanigan'd.\n\t\t *\n\t\t * Work out how much base64 we used, then drop all non-base64\n\t\t * chars from the beginning up to this point in the the string.\n\t\t * Then offset in this and try to make up for missing = chars.\n\t\t */\n\t\tvar data = m[2] + (m[3] ? m[3] : '');\n\t\tvar realOffset = Math.ceil(ret.consumed / 3) * 4;\n\t\tdata = data.slice(0, realOffset - 2). /*JSSTYLED*/\n\t\t replace(/[^a-zA-Z0-9+\\/=]/g, '') +\n\t\t data.slice(realOffset - 2);\n\n\t\tvar padding = ret.consumed % 3;\n\t\tif (padding > 0 &&\n\t\t data.slice(realOffset - 1, realOffset) !== '=')\n\t\t\trealOffset--;\n\t\twhile (data.slice(realOffset, realOffset + 1) === '=')\n\t\t\trealOffset++;\n\n\t\t/* Finally, grab what we think is the comment & clean it up. */\n\t\tvar trailer = data.slice(realOffset);\n\t\ttrailer = trailer.replace(/[\\r\\n]/g, ' ').\n\t\t replace(/^\\s+/, '');\n\t\tif (trailer.match(/^[a-zA-Z0-9]/))\n\t\t\tkey.comment = trailer;\n\t}\n\n\treturn (key);\n}\n\nfunction write(key, options) {\n\tassert.object(key);\n\tif (!Key.isKey(key))\n\t\tthrow (new Error('Must be a public key'));\n\n\tvar parts = [];\n\tvar alg = rfc4253.keyTypeToAlg(key);\n\tparts.push(alg);\n\n\tvar buf = rfc4253.write(key);\n\tparts.push(buf.toString('base64'));\n\n\tif (key.comment)\n\t\tparts.push(key.comment);\n\n\treturn (Buffer.from(parts.join(' ')));\n}\n","// Copyright 2017 Joyent, Inc.\n\nmodule.exports = {\n\tread: read,\n\tverify: verify,\n\tsign: sign,\n\tsignAsync: signAsync,\n\twrite: write\n};\n\nvar assert = require('assert-plus');\nvar asn1 = require('asn1');\nvar Buffer = require('safer-buffer').Buffer;\nvar algs = require('../algs');\nvar utils = require('../utils');\nvar Key = require('../key');\nvar PrivateKey = require('../private-key');\nvar pem = require('./pem');\nvar Identity = require('../identity');\nvar Signature = require('../signature');\nvar Certificate = require('../certificate');\nvar pkcs8 = require('./pkcs8');\n\n/*\n * This file is based on RFC5280 (X.509).\n */\n\n/* Helper to read in a single mpint */\nfunction readMPInt(der, nm) {\n\tassert.strictEqual(der.peek(), asn1.Ber.Integer,\n\t nm + ' is not an Integer');\n\treturn (utils.mpNormalize(der.readString(asn1.Ber.Integer, true)));\n}\n\nfunction verify(cert, key) {\n\tvar sig = cert.signatures.x509;\n\tassert.object(sig, 'x509 signature');\n\n\tvar algParts = sig.algo.split('-');\n\tif (algParts[0] !== key.type)\n\t\treturn (false);\n\n\tvar blob = sig.cache;\n\tif (blob === undefined) {\n\t\tvar der = new asn1.BerWriter();\n\t\twriteTBSCert(cert, der);\n\t\tblob = der.buffer;\n\t}\n\n\tvar verifier = key.createVerify(algParts[1]);\n\tverifier.write(blob);\n\treturn (verifier.verify(sig.signature));\n}\n\nfunction Local(i) {\n\treturn (asn1.Ber.Context | asn1.Ber.Constructor | i);\n}\n\nfunction Context(i) {\n\treturn (asn1.Ber.Context | i);\n}\n\nvar SIGN_ALGS = {\n\t'rsa-md5': '1.2.840.113549.1.1.4',\n\t'rsa-sha1': '1.2.840.113549.1.1.5',\n\t'rsa-sha256': '1.2.840.113549.1.1.11',\n\t'rsa-sha384': '1.2.840.113549.1.1.12',\n\t'rsa-sha512': '1.2.840.113549.1.1.13',\n\t'dsa-sha1': '1.2.840.10040.4.3',\n\t'dsa-sha256': '2.16.840.1.101.3.4.3.2',\n\t'ecdsa-sha1': '1.2.840.10045.4.1',\n\t'ecdsa-sha256': '1.2.840.10045.4.3.2',\n\t'ecdsa-sha384': '1.2.840.10045.4.3.3',\n\t'ecdsa-sha512': '1.2.840.10045.4.3.4',\n\t'ed25519-sha512': '1.3.101.112'\n};\nObject.keys(SIGN_ALGS).forEach(function (k) {\n\tSIGN_ALGS[SIGN_ALGS[k]] = k;\n});\nSIGN_ALGS['1.3.14.3.2.3'] = 'rsa-md5';\nSIGN_ALGS['1.3.14.3.2.29'] = 'rsa-sha1';\n\nvar EXTS = {\n\t'issuerKeyId': '2.5.29.35',\n\t'altName': '2.5.29.17',\n\t'basicConstraints': '2.5.29.19',\n\t'keyUsage': '2.5.29.15',\n\t'extKeyUsage': '2.5.29.37'\n};\n\nfunction read(buf, options) {\n\tif (typeof (buf) === 'string') {\n\t\tbuf = Buffer.from(buf, 'binary');\n\t}\n\tassert.buffer(buf, 'buf');\n\n\tvar der = new asn1.BerReader(buf);\n\n\tder.readSequence();\n\tif (Math.abs(der.length - der.remain) > 1) {\n\t\tthrow (new Error('DER sequence does not contain whole byte ' +\n\t\t 'stream'));\n\t}\n\n\tvar tbsStart = der.offset;\n\tder.readSequence();\n\tvar sigOffset = der.offset + der.length;\n\tvar tbsEnd = sigOffset;\n\n\tif (der.peek() === Local(0)) {\n\t\tder.readSequence(Local(0));\n\t\tvar version = der.readInt();\n\t\tassert.ok(version <= 3,\n\t\t 'only x.509 versions up to v3 supported');\n\t}\n\n\tvar cert = {};\n\tcert.signatures = {};\n\tvar sig = (cert.signatures.x509 = {});\n\tsig.extras = {};\n\n\tcert.serial = readMPInt(der, 'serial');\n\n\tder.readSequence();\n\tvar after = der.offset + der.length;\n\tvar certAlgOid = der.readOID();\n\tvar certAlg = SIGN_ALGS[certAlgOid];\n\tif (certAlg === undefined)\n\t\tthrow (new Error('unknown signature algorithm ' + certAlgOid));\n\n\tder._offset = after;\n\tcert.issuer = Identity.parseAsn1(der);\n\n\tder.readSequence();\n\tcert.validFrom = readDate(der);\n\tcert.validUntil = readDate(der);\n\n\tcert.subjects = [Identity.parseAsn1(der)];\n\n\tder.readSequence();\n\tafter = der.offset + der.length;\n\tcert.subjectKey = pkcs8.readPkcs8(undefined, 'public', der);\n\tder._offset = after;\n\n\t/* issuerUniqueID */\n\tif (der.peek() === Local(1)) {\n\t\tder.readSequence(Local(1));\n\t\tsig.extras.issuerUniqueID =\n\t\t buf.slice(der.offset, der.offset + der.length);\n\t\tder._offset += der.length;\n\t}\n\n\t/* subjectUniqueID */\n\tif (der.peek() === Local(2)) {\n\t\tder.readSequence(Local(2));\n\t\tsig.extras.subjectUniqueID =\n\t\t buf.slice(der.offset, der.offset + der.length);\n\t\tder._offset += der.length;\n\t}\n\n\t/* extensions */\n\tif (der.peek() === Local(3)) {\n\t\tder.readSequence(Local(3));\n\t\tvar extEnd = der.offset + der.length;\n\t\tder.readSequence();\n\n\t\twhile (der.offset < extEnd)\n\t\t\treadExtension(cert, buf, der);\n\n\t\tassert.strictEqual(der.offset, extEnd);\n\t}\n\n\tassert.strictEqual(der.offset, sigOffset);\n\n\tder.readSequence();\n\tafter = der.offset + der.length;\n\tvar sigAlgOid = der.readOID();\n\tvar sigAlg = SIGN_ALGS[sigAlgOid];\n\tif (sigAlg === undefined)\n\t\tthrow (new Error('unknown signature algorithm ' + sigAlgOid));\n\tder._offset = after;\n\n\tvar sigData = der.readString(asn1.Ber.BitString, true);\n\tif (sigData[0] === 0)\n\t\tsigData = sigData.slice(1);\n\tvar algParts = sigAlg.split('-');\n\n\tsig.signature = Signature.parse(sigData, algParts[0], 'asn1');\n\tsig.signature.hashAlgorithm = algParts[1];\n\tsig.algo = sigAlg;\n\tsig.cache = buf.slice(tbsStart, tbsEnd);\n\n\treturn (new Certificate(cert));\n}\n\nfunction readDate(der) {\n\tif (der.peek() === asn1.Ber.UTCTime) {\n\t\treturn (utcTimeToDate(der.readString(asn1.Ber.UTCTime)));\n\t} else if (der.peek() === asn1.Ber.GeneralizedTime) {\n\t\treturn (gTimeToDate(der.readString(asn1.Ber.GeneralizedTime)));\n\t} else {\n\t\tthrow (new Error('Unsupported date format'));\n\t}\n}\n\n/* RFC5280, section 4.2.1.6 (GeneralName type) */\nvar ALTNAME = {\n\tOtherName: Local(0),\n\tRFC822Name: Context(1),\n\tDNSName: Context(2),\n\tX400Address: Local(3),\n\tDirectoryName: Local(4),\n\tEDIPartyName: Local(5),\n\tURI: Context(6),\n\tIPAddress: Context(7),\n\tOID: Context(8)\n};\n\n/* RFC5280, section 4.2.1.12 (KeyPurposeId) */\nvar EXTPURPOSE = {\n\t'serverAuth': '1.3.6.1.5.5.7.3.1',\n\t'clientAuth': '1.3.6.1.5.5.7.3.2',\n\t'codeSigning': '1.3.6.1.5.5.7.3.3',\n\n\t/* See https://github.com/joyent/oid-docs/blob/master/root.md */\n\t'joyentDocker': '1.3.6.1.4.1.38678.1.4.1',\n\t'joyentCmon': '1.3.6.1.4.1.38678.1.4.2'\n};\nvar EXTPURPOSE_REV = {};\nObject.keys(EXTPURPOSE).forEach(function (k) {\n\tEXTPURPOSE_REV[EXTPURPOSE[k]] = k;\n});\n\nvar KEYUSEBITS = [\n\t'signature', 'identity', 'keyEncryption',\n\t'encryption', 'keyAgreement', 'ca', 'crl'\n];\n\nfunction readExtension(cert, buf, der) {\n\tder.readSequence();\n\tvar after = der.offset + der.length;\n\tvar extId = der.readOID();\n\tvar id;\n\tvar sig = cert.signatures.x509;\n\tif (!sig.extras.exts)\n\t\tsig.extras.exts = [];\n\n\tvar critical;\n\tif (der.peek() === asn1.Ber.Boolean)\n\t\tcritical = der.readBoolean();\n\n\tswitch (extId) {\n\tcase (EXTS.basicConstraints):\n\t\tder.readSequence(asn1.Ber.OctetString);\n\t\tder.readSequence();\n\t\tvar bcEnd = der.offset + der.length;\n\t\tvar ca = false;\n\t\tif (der.peek() === asn1.Ber.Boolean)\n\t\t\tca = der.readBoolean();\n\t\tif (cert.purposes === undefined)\n\t\t\tcert.purposes = [];\n\t\tif (ca === true)\n\t\t\tcert.purposes.push('ca');\n\t\tvar bc = { oid: extId, critical: critical };\n\t\tif (der.offset < bcEnd && der.peek() === asn1.Ber.Integer)\n\t\t\tbc.pathLen = der.readInt();\n\t\tsig.extras.exts.push(bc);\n\t\tbreak;\n\tcase (EXTS.extKeyUsage):\n\t\tder.readSequence(asn1.Ber.OctetString);\n\t\tder.readSequence();\n\t\tif (cert.purposes === undefined)\n\t\t\tcert.purposes = [];\n\t\tvar ekEnd = der.offset + der.length;\n\t\twhile (der.offset < ekEnd) {\n\t\t\tvar oid = der.readOID();\n\t\t\tcert.purposes.push(EXTPURPOSE_REV[oid] || oid);\n\t\t}\n\t\t/*\n\t\t * This is a bit of a hack: in the case where we have a cert\n\t\t * that's only allowed to do serverAuth or clientAuth (and not\n\t\t * the other), we want to make sure all our Subjects are of\n\t\t * the right type. But we already parsed our Subjects and\n\t\t * decided if they were hosts or users earlier (since it appears\n\t\t * first in the cert).\n\t\t *\n\t\t * So we go through and mutate them into the right kind here if\n\t\t * it doesn't match. This might not be hugely beneficial, as it\n\t\t * seems that single-purpose certs are not often seen in the\n\t\t * wild.\n\t\t */\n\t\tif (cert.purposes.indexOf('serverAuth') !== -1 &&\n\t\t cert.purposes.indexOf('clientAuth') === -1) {\n\t\t\tcert.subjects.forEach(function (ide) {\n\t\t\t\tif (ide.type !== 'host') {\n\t\t\t\t\tide.type = 'host';\n\t\t\t\t\tide.hostname = ide.uid ||\n\t\t\t\t\t ide.email ||\n\t\t\t\t\t ide.components[0].value;\n\t\t\t\t}\n\t\t\t});\n\t\t} else if (cert.purposes.indexOf('clientAuth') !== -1 &&\n\t\t cert.purposes.indexOf('serverAuth') === -1) {\n\t\t\tcert.subjects.forEach(function (ide) {\n\t\t\t\tif (ide.type !== 'user') {\n\t\t\t\t\tide.type = 'user';\n\t\t\t\t\tide.uid = ide.hostname ||\n\t\t\t\t\t ide.email ||\n\t\t\t\t\t ide.components[0].value;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\tsig.extras.exts.push({ oid: extId, critical: critical });\n\t\tbreak;\n\tcase (EXTS.keyUsage):\n\t\tder.readSequence(asn1.Ber.OctetString);\n\t\tvar bits = der.readString(asn1.Ber.BitString, true);\n\t\tvar setBits = readBitField(bits, KEYUSEBITS);\n\t\tsetBits.forEach(function (bit) {\n\t\t\tif (cert.purposes === undefined)\n\t\t\t\tcert.purposes = [];\n\t\t\tif (cert.purposes.indexOf(bit) === -1)\n\t\t\t\tcert.purposes.push(bit);\n\t\t});\n\t\tsig.extras.exts.push({ oid: extId, critical: critical,\n\t\t bits: bits });\n\t\tbreak;\n\tcase (EXTS.altName):\n\t\tder.readSequence(asn1.Ber.OctetString);\n\t\tder.readSequence();\n\t\tvar aeEnd = der.offset + der.length;\n\t\twhile (der.offset < aeEnd) {\n\t\t\tswitch (der.peek()) {\n\t\t\tcase ALTNAME.OtherName:\n\t\t\tcase ALTNAME.EDIPartyName:\n\t\t\t\tder.readSequence();\n\t\t\t\tder._offset += der.length;\n\t\t\t\tbreak;\n\t\t\tcase ALTNAME.OID:\n\t\t\t\tder.readOID(ALTNAME.OID);\n\t\t\t\tbreak;\n\t\t\tcase ALTNAME.RFC822Name:\n\t\t\t\t/* RFC822 specifies email addresses */\n\t\t\t\tvar email = der.readString(ALTNAME.RFC822Name);\n\t\t\t\tid = Identity.forEmail(email);\n\t\t\t\tif (!cert.subjects[0].equals(id))\n\t\t\t\t\tcert.subjects.push(id);\n\t\t\t\tbreak;\n\t\t\tcase ALTNAME.DirectoryName:\n\t\t\t\tder.readSequence(ALTNAME.DirectoryName);\n\t\t\t\tid = Identity.parseAsn1(der);\n\t\t\t\tif (!cert.subjects[0].equals(id))\n\t\t\t\t\tcert.subjects.push(id);\n\t\t\t\tbreak;\n\t\t\tcase ALTNAME.DNSName:\n\t\t\t\tvar host = der.readString(\n\t\t\t\t ALTNAME.DNSName);\n\t\t\t\tid = Identity.forHost(host);\n\t\t\t\tif (!cert.subjects[0].equals(id))\n\t\t\t\t\tcert.subjects.push(id);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tder.readString(der.peek());\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tsig.extras.exts.push({ oid: extId, critical: critical });\n\t\tbreak;\n\tdefault:\n\t\tsig.extras.exts.push({\n\t\t\toid: extId,\n\t\t\tcritical: critical,\n\t\t\tdata: der.readString(asn1.Ber.OctetString, true)\n\t\t});\n\t\tbreak;\n\t}\n\n\tder._offset = after;\n}\n\nvar UTCTIME_RE =\n /^([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})?Z$/;\nfunction utcTimeToDate(t) {\n\tvar m = t.match(UTCTIME_RE);\n\tassert.ok(m, 'timestamps must be in UTC');\n\tvar d = new Date();\n\n\tvar thisYear = d.getUTCFullYear();\n\tvar century = Math.floor(thisYear / 100) * 100;\n\n\tvar year = parseInt(m[1], 10);\n\tif (thisYear % 100 < 50 && year >= 60)\n\t\tyear += (century - 1);\n\telse\n\t\tyear += century;\n\td.setUTCFullYear(year, parseInt(m[2], 10) - 1, parseInt(m[3], 10));\n\td.setUTCHours(parseInt(m[4], 10), parseInt(m[5], 10));\n\tif (m[6] && m[6].length > 0)\n\t\td.setUTCSeconds(parseInt(m[6], 10));\n\treturn (d);\n}\n\nvar GTIME_RE =\n /^([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})?Z$/;\nfunction gTimeToDate(t) {\n\tvar m = t.match(GTIME_RE);\n\tassert.ok(m);\n\tvar d = new Date();\n\n\td.setUTCFullYear(parseInt(m[1], 10), parseInt(m[2], 10) - 1,\n\t parseInt(m[3], 10));\n\td.setUTCHours(parseInt(m[4], 10), parseInt(m[5], 10));\n\tif (m[6] && m[6].length > 0)\n\t\td.setUTCSeconds(parseInt(m[6], 10));\n\treturn (d);\n}\n\nfunction zeroPad(n) {\n\tvar s = '' + n;\n\twhile (s.length < 2)\n\t\ts = '0' + s;\n\treturn (s);\n}\n\nfunction dateToUTCTime(d) {\n\tvar s = '';\n\ts += zeroPad(d.getUTCFullYear() % 100);\n\ts += zeroPad(d.getUTCMonth() + 1);\n\ts += zeroPad(d.getUTCDate());\n\ts += zeroPad(d.getUTCHours());\n\ts += zeroPad(d.getUTCMinutes());\n\ts += zeroPad(d.getUTCSeconds());\n\ts += 'Z';\n\treturn (s);\n}\n\nfunction sign(cert, key) {\n\tif (cert.signatures.x509 === undefined)\n\t\tcert.signatures.x509 = {};\n\tvar sig = cert.signatures.x509;\n\n\tsig.algo = key.type + '-' + key.defaultHashAlgorithm();\n\tif (SIGN_ALGS[sig.algo] === undefined)\n\t\treturn (false);\n\n\tvar der = new asn1.BerWriter();\n\twriteTBSCert(cert, der);\n\tvar blob = der.buffer;\n\tsig.cache = blob;\n\n\tvar signer = key.createSign();\n\tsigner.write(blob);\n\tcert.signatures.x509.signature = signer.sign();\n\n\treturn (true);\n}\n\nfunction signAsync(cert, signer, done) {\n\tif (cert.signatures.x509 === undefined)\n\t\tcert.signatures.x509 = {};\n\tvar sig = cert.signatures.x509;\n\n\tvar der = new asn1.BerWriter();\n\twriteTBSCert(cert, der);\n\tvar blob = der.buffer;\n\tsig.cache = blob;\n\n\tsigner(blob, function (err, signature) {\n\t\tif (err) {\n\t\t\tdone(err);\n\t\t\treturn;\n\t\t}\n\t\tsig.algo = signature.type + '-' + signature.hashAlgorithm;\n\t\tif (SIGN_ALGS[sig.algo] === undefined) {\n\t\t\tdone(new Error('Invalid signing algorithm \"' +\n\t\t\t sig.algo + '\"'));\n\t\t\treturn;\n\t\t}\n\t\tsig.signature = signature;\n\t\tdone();\n\t});\n}\n\nfunction write(cert, options) {\n\tvar sig = cert.signatures.x509;\n\tassert.object(sig, 'x509 signature');\n\n\tvar der = new asn1.BerWriter();\n\tder.startSequence();\n\tif (sig.cache) {\n\t\tder._ensure(sig.cache.length);\n\t\tsig.cache.copy(der._buf, der._offset);\n\t\tder._offset += sig.cache.length;\n\t} else {\n\t\twriteTBSCert(cert, der);\n\t}\n\n\tder.startSequence();\n\tder.writeOID(SIGN_ALGS[sig.algo]);\n\tif (sig.algo.match(/^rsa-/))\n\t\tder.writeNull();\n\tder.endSequence();\n\n\tvar sigData = sig.signature.toBuffer('asn1');\n\tvar data = Buffer.alloc(sigData.length + 1);\n\tdata[0] = 0;\n\tsigData.copy(data, 1);\n\tder.writeBuffer(data, asn1.Ber.BitString);\n\tder.endSequence();\n\n\treturn (der.buffer);\n}\n\nfunction writeTBSCert(cert, der) {\n\tvar sig = cert.signatures.x509;\n\tassert.object(sig, 'x509 signature');\n\n\tder.startSequence();\n\n\tder.startSequence(Local(0));\n\tder.writeInt(2);\n\tder.endSequence();\n\n\tder.writeBuffer(utils.mpNormalize(cert.serial), asn1.Ber.Integer);\n\n\tder.startSequence();\n\tder.writeOID(SIGN_ALGS[sig.algo]);\n\tif (sig.algo.match(/^rsa-/))\n\t\tder.writeNull();\n\tder.endSequence();\n\n\tcert.issuer.toAsn1(der);\n\n\tder.startSequence();\n\tder.writeString(dateToUTCTime(cert.validFrom), asn1.Ber.UTCTime);\n\tder.writeString(dateToUTCTime(cert.validUntil), asn1.Ber.UTCTime);\n\tder.endSequence();\n\n\tvar subject = cert.subjects[0];\n\tvar altNames = cert.subjects.slice(1);\n\tsubject.toAsn1(der);\n\n\tpkcs8.writePkcs8(der, cert.subjectKey);\n\n\tif (sig.extras && sig.extras.issuerUniqueID) {\n\t\tder.writeBuffer(sig.extras.issuerUniqueID, Local(1));\n\t}\n\n\tif (sig.extras && sig.extras.subjectUniqueID) {\n\t\tder.writeBuffer(sig.extras.subjectUniqueID, Local(2));\n\t}\n\n\tif (altNames.length > 0 || subject.type === 'host' ||\n\t (cert.purposes !== undefined && cert.purposes.length > 0) ||\n\t (sig.extras && sig.extras.exts)) {\n\t\tder.startSequence(Local(3));\n\t\tder.startSequence();\n\n\t\tvar exts = [];\n\t\tif (cert.purposes !== undefined && cert.purposes.length > 0) {\n\t\t\texts.push({\n\t\t\t\toid: EXTS.basicConstraints,\n\t\t\t\tcritical: true\n\t\t\t});\n\t\t\texts.push({\n\t\t\t\toid: EXTS.keyUsage,\n\t\t\t\tcritical: true\n\t\t\t});\n\t\t\texts.push({\n\t\t\t\toid: EXTS.extKeyUsage,\n\t\t\t\tcritical: true\n\t\t\t});\n\t\t}\n\t\texts.push({ oid: EXTS.altName });\n\t\tif (sig.extras && sig.extras.exts)\n\t\t\texts = sig.extras.exts;\n\n\t\tfor (var i = 0; i < exts.length; ++i) {\n\t\t\tder.startSequence();\n\t\t\tder.writeOID(exts[i].oid);\n\n\t\t\tif (exts[i].critical !== undefined)\n\t\t\t\tder.writeBoolean(exts[i].critical);\n\n\t\t\tif (exts[i].oid === EXTS.altName) {\n\t\t\t\tder.startSequence(asn1.Ber.OctetString);\n\t\t\t\tder.startSequence();\n\t\t\t\tif (subject.type === 'host') {\n\t\t\t\t\tder.writeString(subject.hostname,\n\t\t\t\t\t Context(2));\n\t\t\t\t}\n\t\t\t\tfor (var j = 0; j < altNames.length; ++j) {\n\t\t\t\t\tif (altNames[j].type === 'host') {\n\t\t\t\t\t\tder.writeString(\n\t\t\t\t\t\t altNames[j].hostname,\n\t\t\t\t\t\t ALTNAME.DNSName);\n\t\t\t\t\t} else if (altNames[j].type ===\n\t\t\t\t\t 'email') {\n\t\t\t\t\t\tder.writeString(\n\t\t\t\t\t\t altNames[j].email,\n\t\t\t\t\t\t ALTNAME.RFC822Name);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t/*\n\t\t\t\t\t\t * Encode anything else as a\n\t\t\t\t\t\t * DN style name for now.\n\t\t\t\t\t\t */\n\t\t\t\t\t\tder.startSequence(\n\t\t\t\t\t\t ALTNAME.DirectoryName);\n\t\t\t\t\t\taltNames[j].toAsn1(der);\n\t\t\t\t\t\tder.endSequence();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tder.endSequence();\n\t\t\t\tder.endSequence();\n\t\t\t} else if (exts[i].oid === EXTS.basicConstraints) {\n\t\t\t\tder.startSequence(asn1.Ber.OctetString);\n\t\t\t\tder.startSequence();\n\t\t\t\tvar ca = (cert.purposes.indexOf('ca') !== -1);\n\t\t\t\tvar pathLen = exts[i].pathLen;\n\t\t\t\tder.writeBoolean(ca);\n\t\t\t\tif (pathLen !== undefined)\n\t\t\t\t\tder.writeInt(pathLen);\n\t\t\t\tder.endSequence();\n\t\t\t\tder.endSequence();\n\t\t\t} else if (exts[i].oid === EXTS.extKeyUsage) {\n\t\t\t\tder.startSequence(asn1.Ber.OctetString);\n\t\t\t\tder.startSequence();\n\t\t\t\tcert.purposes.forEach(function (purpose) {\n\t\t\t\t\tif (purpose === 'ca')\n\t\t\t\t\t\treturn;\n\t\t\t\t\tif (KEYUSEBITS.indexOf(purpose) !== -1)\n\t\t\t\t\t\treturn;\n\t\t\t\t\tvar oid = purpose;\n\t\t\t\t\tif (EXTPURPOSE[purpose] !== undefined)\n\t\t\t\t\t\toid = EXTPURPOSE[purpose];\n\t\t\t\t\tder.writeOID(oid);\n\t\t\t\t});\n\t\t\t\tder.endSequence();\n\t\t\t\tder.endSequence();\n\t\t\t} else if (exts[i].oid === EXTS.keyUsage) {\n\t\t\t\tder.startSequence(asn1.Ber.OctetString);\n\t\t\t\t/*\n\t\t\t\t * If we parsed this certificate from a byte\n\t\t\t\t * stream (i.e. we didn't generate it in sshpk)\n\t\t\t\t * then we'll have a \".bits\" property on the\n\t\t\t\t * ext with the original raw byte contents.\n\t\t\t\t *\n\t\t\t\t * If we have this, use it here instead of\n\t\t\t\t * regenerating it. This guarantees we output\n\t\t\t\t * the same data we parsed, so signatures still\n\t\t\t\t * validate.\n\t\t\t\t */\n\t\t\t\tif (exts[i].bits !== undefined) {\n\t\t\t\t\tder.writeBuffer(exts[i].bits,\n\t\t\t\t\t asn1.Ber.BitString);\n\t\t\t\t} else {\n\t\t\t\t\tvar bits = writeBitField(cert.purposes,\n\t\t\t\t\t KEYUSEBITS);\n\t\t\t\t\tder.writeBuffer(bits,\n\t\t\t\t\t asn1.Ber.BitString);\n\t\t\t\t}\n\t\t\t\tder.endSequence();\n\t\t\t} else {\n\t\t\t\tder.writeBuffer(exts[i].data,\n\t\t\t\t asn1.Ber.OctetString);\n\t\t\t}\n\n\t\t\tder.endSequence();\n\t\t}\n\n\t\tder.endSequence();\n\t\tder.endSequence();\n\t}\n\n\tder.endSequence();\n}\n\n/*\n * Reads an ASN.1 BER bitfield out of the Buffer produced by doing\n * `BerReader#readString(asn1.Ber.BitString)`. That function gives us the raw\n * contents of the BitString tag, which is a count of unused bits followed by\n * the bits as a right-padded byte string.\n *\n * `bits` is the Buffer, `bitIndex` should contain an array of string names\n * for the bits in the string, ordered starting with bit #0 in the ASN.1 spec.\n *\n * Returns an array of Strings, the names of the bits that were set to 1.\n */\nfunction readBitField(bits, bitIndex) {\n\tvar bitLen = 8 * (bits.length - 1) - bits[0];\n\tvar setBits = {};\n\tfor (var i = 0; i < bitLen; ++i) {\n\t\tvar byteN = 1 + Math.floor(i / 8);\n\t\tvar bit = 7 - (i % 8);\n\t\tvar mask = 1 << bit;\n\t\tvar bitVal = ((bits[byteN] & mask) !== 0);\n\t\tvar name = bitIndex[i];\n\t\tif (bitVal && typeof (name) === 'string') {\n\t\t\tsetBits[name] = true;\n\t\t}\n\t}\n\treturn (Object.keys(setBits));\n}\n\n/*\n * `setBits` is an array of strings, containing the names for each bit that\n * sould be set to 1. `bitIndex` is same as in `readBitField()`.\n *\n * Returns a Buffer, ready to be written out with `BerWriter#writeString()`.\n */\nfunction writeBitField(setBits, bitIndex) {\n\tvar bitLen = bitIndex.length;\n\tvar blen = Math.ceil(bitLen / 8);\n\tvar unused = blen * 8 - bitLen;\n\tvar bits = Buffer.alloc(1 + blen); // zero-filled\n\tbits[0] = unused;\n\tfor (var i = 0; i < bitLen; ++i) {\n\t\tvar byteN = 1 + Math.floor(i / 8);\n\t\tvar bit = 7 - (i % 8);\n\t\tvar mask = 1 << bit;\n\t\tvar name = bitIndex[i];\n\t\tif (name === undefined)\n\t\t\tcontinue;\n\t\tvar bitVal = (setBits.indexOf(name) !== -1);\n\t\tif (bitVal) {\n\t\t\tbits[byteN] |= mask;\n\t\t}\n\t}\n\treturn (bits);\n}\n","/*\n * extsprintf.js: extended POSIX-style sprintf\n */\n\nvar mod_assert = require('assert');\nvar mod_util = require('util');\n\n/*\n * Public interface\n */\nexports.sprintf = jsSprintf;\nexports.printf = jsPrintf;\nexports.fprintf = jsFprintf;\n\n/*\n * Stripped down version of s[n]printf(3c). We make a best effort to throw an\n * exception when given a format string we don't understand, rather than\n * ignoring it, so that we won't break existing programs if/when we go implement\n * the rest of this.\n *\n * This implementation currently supports specifying\n *\t- field alignment ('-' flag),\n * \t- zero-pad ('0' flag)\n *\t- always show numeric sign ('+' flag),\n *\t- field width\n *\t- conversions for strings, decimal integers, and floats (numbers).\n *\t- argument size specifiers. These are all accepted but ignored, since\n *\t Javascript has no notion of the physical size of an argument.\n *\n * Everything else is currently unsupported, most notably precision, unsigned\n * numbers, non-decimal numbers, and characters.\n */\nfunction jsSprintf(fmt)\n{\n\tvar regex = [\n\t '([^%]*)',\t\t\t\t/* normal text */\n\t '%',\t\t\t\t/* start of format */\n\t '([\\'\\\\-+ #0]*?)',\t\t\t/* flags (optional) */\n\t '([1-9]\\\\d*)?',\t\t\t/* width (optional) */\n\t '(\\\\.([1-9]\\\\d*))?',\t\t/* precision (optional) */\n\t '[lhjztL]*?',\t\t\t/* length mods (ignored) */\n\t '([diouxXfFeEgGaAcCsSp%jr])'\t/* conversion */\n\t].join('');\n\n\tvar re = new RegExp(regex);\n\tvar args = Array.prototype.slice.call(arguments, 1);\n\tvar flags, width, precision, conversion;\n\tvar left, pad, sign, arg, match;\n\tvar ret = '';\n\tvar argn = 1;\n\n\tmod_assert.equal('string', typeof (fmt));\n\n\twhile ((match = re.exec(fmt)) !== null) {\n\t\tret += match[1];\n\t\tfmt = fmt.substring(match[0].length);\n\n\t\tflags = match[2] || '';\n\t\twidth = match[3] || 0;\n\t\tprecision = match[4] || '';\n\t\tconversion = match[6];\n\t\tleft = false;\n\t\tsign = false;\n\t\tpad = ' ';\n\n\t\tif (conversion == '%') {\n\t\t\tret += '%';\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (args.length === 0)\n\t\t\tthrow (new Error('too few args to sprintf'));\n\n\t\targ = args.shift();\n\t\targn++;\n\n\t\tif (flags.match(/[\\' #]/))\n\t\t\tthrow (new Error(\n\t\t\t 'unsupported flags: ' + flags));\n\n\t\tif (precision.length > 0)\n\t\t\tthrow (new Error(\n\t\t\t 'non-zero precision not supported'));\n\n\t\tif (flags.match(/-/))\n\t\t\tleft = true;\n\n\t\tif (flags.match(/0/))\n\t\t\tpad = '0';\n\n\t\tif (flags.match(/\\+/))\n\t\t\tsign = true;\n\n\t\tswitch (conversion) {\n\t\tcase 's':\n\t\t\tif (arg === undefined || arg === null)\n\t\t\t\tthrow (new Error('argument ' + argn +\n\t\t\t\t ': attempted to print undefined or null ' +\n\t\t\t\t 'as a string'));\n\t\t\tret += doPad(pad, width, left, arg.toString());\n\t\t\tbreak;\n\n\t\tcase 'd':\n\t\t\targ = Math.floor(arg);\n\t\t\t/*jsl:fallthru*/\n\t\tcase 'f':\n\t\t\tsign = sign && arg > 0 ? '+' : '';\n\t\t\tret += sign + doPad(pad, width, left,\n\t\t\t arg.toString());\n\t\t\tbreak;\n\n\t\tcase 'x':\n\t\t\tret += doPad(pad, width, left, arg.toString(16));\n\t\t\tbreak;\n\n\t\tcase 'j': /* non-standard */\n\t\t\tif (width === 0)\n\t\t\t\twidth = 10;\n\t\t\tret += mod_util.inspect(arg, false, width);\n\t\t\tbreak;\n\n\t\tcase 'r': /* non-standard */\n\t\t\tret += dumpException(arg);\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tthrow (new Error('unsupported conversion: ' +\n\t\t\t conversion));\n\t\t}\n\t}\n\n\tret += fmt;\n\treturn (ret);\n}\n\nfunction jsPrintf() {\n\tvar args = Array.prototype.slice.call(arguments);\n\targs.unshift(process.stdout);\n\tjsFprintf.apply(null, args);\n}\n\nfunction jsFprintf(stream) {\n\tvar args = Array.prototype.slice.call(arguments, 1);\n\treturn (stream.write(jsSprintf.apply(this, args)));\n}\n\nfunction doPad(chr, width, left, str)\n{\n\tvar ret = str;\n\n\twhile (ret.length < width) {\n\t\tif (left)\n\t\t\tret += chr;\n\t\telse\n\t\t\tret = chr + ret;\n\t}\n\n\treturn (ret);\n}\n\n/*\n * This function dumps long stack traces for exceptions having a cause() method.\n * See node-verror for an example.\n */\nfunction dumpException(ex)\n{\n\tvar ret;\n\n\tif (!(ex instanceof Error))\n\t\tthrow (new Error(jsSprintf('invalid type for %%r: %j', ex)));\n\n\t/* Note that V8 prepends \"ex.stack\" with ex.toString(). */\n\tret = 'EXCEPTION: ' + ex.constructor.name + ': ' + ex.stack;\n\n\tif (ex.cause && typeof (ex.cause) === 'function') {\n\t\tvar cex = ex.cause();\n\t\tif (cex) {\n\t\t\tret += '\\nCaused by: ' + dumpException(cex);\n\t\t}\n\t}\n\n\treturn (ret);\n}\n","var bind = Function.prototype.bind,\n slice = Array.prototype.slice,\n toString = Object.prototype.toString;\n\nexports.bind = function (func, that) {\n\tvar args = slice.call(arguments, 2);\n\n\tif (bind) {\n\t\targs.unshift(that);\n\n\t\treturn bind.apply(func, args);\n\t}\n\n\treturn function () {\n\t\treturn func.apply(that, args.concat(slice.call(arguments)));\n\t};\n}\n\nexports.slice = function (object, begin, end) {\n\treturn slice.call(object, begin, end);\n};\n\nexports.toString = function (object) {\n\treturn toString.call(object);\n};\n\n\nexports.isNull = nativeTypeChecker('Null');\nexports.isDate = nativeTypeChecker('Date');\nexports.isMath = nativeTypeChecker('Math');\nexports.isJSON = nativeTypeChecker('JSON');\nexports.isError = nativeTypeChecker('Error');\nexports.isArray = Array.isArray || nativeTypeChecker('Array');\nexports.isObject = nativeTypeChecker('Object');\nexports.isRegExp = nativeTypeChecker('RegExp');\nexports.isNumber = nativeTypeChecker('Number');\nexports.isString = nativeTypeChecker('String');\nexports.isBoolean = nativeTypeChecker('Boolean');\nexports.isFunction = nativeTypeChecker('Function');\nexports.isArguments = nativeTypeChecker('Arguments');\nexports.isUndefined = nativeTypeChecker('Undefined');\n\nfunction nativeTypeChecker (type) {\n\ttype = '[object ' + type + ']';\n\n\treturn function (object) {return toString.call(object) === type;};\n}\n\n\nexports.isValid = function (object) {\n\treturn !exports.isInvalid(object);\n}\n\nexports.isInvalid = function (object) {\n\treturn exports.isNull(object) || exports.isUndefined(object);\n}\n\n\nexports.isImmutable = function (object) {\n\treturn !exports.isMutable(object);\n};\n\nexports.isMutable = function (object) {\n\treturn object &&\n\t\t!exports.isNumber(object) &&\n\t\t!exports.isString(object) &&\n\t\t!exports.isBoolean(object);\n};\n\n\nexports.isEnumerable = function (object) {\n\tif (!object) return false;\n\n\tif (exports.isNumber(object)) return exports.isInteger(object);\n\n\tif (exports.isInteger(object.length)) return object.length >= 0;\n\n\treturn exports.isEnumerableObject(object);\n};\n\nexports.isEnumerableObject = function (object) {\n\tfor (var _ in object) return true;\n\n\treturn false;\n};\n\nexports.isEmpty = function (object) {\n\treturn exports.isObject(object) ?\n\t\t!exports.isEnumerableObject(object) :\n\t\t!exports.isEnumerable(object);\n}\n\n\nexports.isFiniteNumber = function (number) {\n\treturn exports.isNumber(number) && isFinite(number);\n};\n\nexports.isInteger = function (number) {\n\treturn exports.isFiniteNumber(number) && Math.floor(number) === number;\n};\n\nexports.isVague = function (object) {\n\treturn object && typeof object === 'object';\n};\n\nexports.isList = function (list) {\n\treturn (\n\t\texports.isVague(list) &&\n\t\texports.isInteger(list.length) && list.length >= 0);\n};\n\n\nexports.isNaN = isNaN;\n\n\nexports.nativeTypeOf = function (object) {\n\tvar nativeType = object.toString(object);\n\n\treturn nativeType.substring(8, nativeType.length - 1);\n};\n\nexports.typeOf = function (object) {\n\treturn exports.isObject(object) ?\n\t\tobject.constructor.name || 'Object' :\n\t\texports.nativeTypeOf(object);\n};\n\n\nexports.safeApply = function (func, args, that) {\n\treturn exports.isFunction(func) ?\n\t\tfunc.apply(that || this, args) :\n\t\tundefined;\n};\n\n\nexports.enumerate = function (object, iterator, that, _ignoreForEach) {\n\tif (!object) return object;\n\n\tthat = that || this;\n\n\tif (!_ignoreForEach && exports.isFunction(object.forEach))\n\t\treturn object.forEach(iterator, that);\n\n\tvar key = 0, end = object.length;\n\n\tif (exports.isString(object)) {\n\t\tfor (; key < end; key += 1) iterator.call(that, object.charAt(key), key, object);\n\n\t} if (exports.isList(object)) {\n\t\tfor (; key < end; key += 1) iterator.call(that, object[key], key, object);\n\n\t} else if (exports.isInteger(object)) {\n\t\tif (object < 0) {\n\t\t\tend = 0;\n\t\t\tkey = object;\n\n\t\t} else end = object;\n\n\t\tfor (; key < end; key += 1) iterator.call(that, key, Math.abs(key), object);\n\n\t} else exports.enumerateObject(object, iterator, that);\n\n\treturn object;\n};\n\nexports.enumerateObject = function (object, iterator, that) {\n\tvar key;\n\n\tfor (key in object) iterator.call(that, object[key], key, object);\n\n\treturn object;\n}\n\n\nexports.assignAll = function (target, giver, filter, that, _method) {\n\tif (!exports.isMutable(target)) return target;\n\n\t_method = _method === 'enumerate' ? _method : 'enumerateObject';\n\n\texports[_method](giver, function (value, key) {\n\t\tif (!exports.safeApply(filter, arguments, that || target)) {\n\t\t\ttarget[key] = value;\n\t\t}\n\t});\n\n\treturn target;\n};\n\nexports.assignList = function (target, giver, filter, that) {\n\treturn exports.assignAll(target, giver, filter, that, 'enumerate');\n};\n\nexports.assign = function (target, giver, filter, that) {\n\treturn exports.assignAll(target, giver, function (_, key) {\n\t\tif (!giver.hasOwnProperty(key)) return true;\n\n\t\treturn exports.safeApply(filter, arguments, that || this);\n\t}, that);\n};\n\n\nexports.toArray = function (object, begin, end) {\n\tif (exports.isArray()) return exports.isInteger(begin) ?\n\t\texports.slice(object, begin, end) :\n\t\tobject;\n\n\tif (exports.isArguments(object) || exports.isString(object))\n\t\treturn exports.slice(object, begin, end);\n\n\tif (!exports.isList(object)) return undefined;\n\n\tif (!exports.isInteger(end)) end = object.length;\n\n\tbegin = begin || 0;\n\n\treturn exports.assignList([], object, function (_, i) {\n\t\treturn begin > i || i >= end;\n\t});\n};\n","var stream = require('stream')\n\n\nfunction isStream (obj) {\n return obj instanceof stream.Stream\n}\n\n\nfunction isReadable (obj) {\n return isStream(obj) && typeof obj._read == 'function' && typeof obj._readableState == 'object'\n}\n\n\nfunction isWritable (obj) {\n return isStream(obj) && typeof obj._write == 'function' && typeof obj._writableState == 'object'\n}\n\n\nfunction isDuplex (obj) {\n return isReadable(obj) && isWritable(obj)\n}\n\n\nmodule.exports = isStream\nmodule.exports.isReadable = isReadable\nmodule.exports.isWritable = isWritable\nmodule.exports.isDuplex = isDuplex\n","'use strict';\n\nvar stringify = require('./stringify');\nvar parse = require('./parse');\nvar formats = require('./formats');\n\nmodule.exports = {\n formats: formats,\n parse: parse,\n stringify: stringify\n};\n","'use strict';\n\nvar has = Object.prototype.hasOwnProperty;\n\nvar hexTable = (function () {\n var array = [];\n for (var i = 0; i < 256; ++i) {\n array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase());\n }\n\n return array;\n}());\n\nvar compactQueue = function compactQueue(queue) {\n var obj;\n\n while (queue.length) {\n var item = queue.pop();\n obj = item.obj[item.prop];\n\n if (Array.isArray(obj)) {\n var compacted = [];\n\n for (var j = 0; j < obj.length; ++j) {\n if (typeof obj[j] !== 'undefined') {\n compacted.push(obj[j]);\n }\n }\n\n item.obj[item.prop] = compacted;\n }\n }\n\n return obj;\n};\n\nvar arrayToObject = function arrayToObject(source, options) {\n var obj = options && options.plainObjects ? Object.create(null) : {};\n for (var i = 0; i < source.length; ++i) {\n if (typeof source[i] !== 'undefined') {\n obj[i] = source[i];\n }\n }\n\n return obj;\n};\n\nvar merge = function merge(target, source, options) {\n if (!source) {\n return target;\n }\n\n if (typeof source !== 'object') {\n if (Array.isArray(target)) {\n target.push(source);\n } else if (typeof target === 'object') {\n if (options.plainObjects || options.allowPrototypes || !has.call(Object.prototype, source)) {\n target[source] = true;\n }\n } else {\n return [target, source];\n }\n\n return target;\n }\n\n if (typeof target !== 'object') {\n return [target].concat(source);\n }\n\n var mergeTarget = target;\n if (Array.isArray(target) && !Array.isArray(source)) {\n mergeTarget = arrayToObject(target, options);\n }\n\n if (Array.isArray(target) && Array.isArray(source)) {\n source.forEach(function (item, i) {\n if (has.call(target, i)) {\n if (target[i] && typeof target[i] === 'object') {\n target[i] = merge(target[i], item, options);\n } else {\n target.push(item);\n }\n } else {\n target[i] = item;\n }\n });\n return target;\n }\n\n return Object.keys(source).reduce(function (acc, key) {\n var value = source[key];\n\n if (has.call(acc, key)) {\n acc[key] = merge(acc[key], value, options);\n } else {\n acc[key] = value;\n }\n return acc;\n }, mergeTarget);\n};\n\nvar assign = function assignSingleSource(target, source) {\n return Object.keys(source).reduce(function (acc, key) {\n acc[key] = source[key];\n return acc;\n }, target);\n};\n\nvar decode = function (str) {\n try {\n return decodeURIComponent(str.replace(/\\+/g, ' '));\n } catch (e) {\n return str;\n }\n};\n\nvar encode = function encode(str) {\n // This code was originally written by Brian White (mscdex) for the io.js core querystring library.\n // It has been adapted here for stricter adherence to RFC 3986\n if (str.length === 0) {\n return str;\n }\n\n var string = typeof str === 'string' ? str : String(str);\n\n var out = '';\n for (var i = 0; i < string.length; ++i) {\n var c = string.charCodeAt(i);\n\n if (\n c === 0x2D // -\n || c === 0x2E // .\n || c === 0x5F // _\n || c === 0x7E // ~\n || (c >= 0x30 && c <= 0x39) // 0-9\n || (c >= 0x41 && c <= 0x5A) // a-z\n || (c >= 0x61 && c <= 0x7A) // A-Z\n ) {\n out += string.charAt(i);\n continue;\n }\n\n if (c < 0x80) {\n out = out + hexTable[c];\n continue;\n }\n\n if (c < 0x800) {\n out = out + (hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)]);\n continue;\n }\n\n if (c < 0xD800 || c >= 0xE000) {\n out = out + (hexTable[0xE0 | (c >> 12)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]);\n continue;\n }\n\n i += 1;\n c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF));\n out += hexTable[0xF0 | (c >> 18)]\n + hexTable[0x80 | ((c >> 12) & 0x3F)]\n + hexTable[0x80 | ((c >> 6) & 0x3F)]\n + hexTable[0x80 | (c & 0x3F)];\n }\n\n return out;\n};\n\nvar compact = function compact(value) {\n var queue = [{ obj: { o: value }, prop: 'o' }];\n var refs = [];\n\n for (var i = 0; i < queue.length; ++i) {\n var item = queue[i];\n var obj = item.obj[item.prop];\n\n var keys = Object.keys(obj);\n for (var j = 0; j < keys.length; ++j) {\n var key = keys[j];\n var val = obj[key];\n if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) {\n queue.push({ obj: obj, prop: key });\n refs.push(val);\n }\n }\n }\n\n return compactQueue(queue);\n};\n\nvar isRegExp = function isRegExp(obj) {\n return Object.prototype.toString.call(obj) === '[object RegExp]';\n};\n\nvar isBuffer = function isBuffer(obj) {\n if (obj === null || typeof obj === 'undefined') {\n return false;\n }\n\n return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj));\n};\n\nmodule.exports = {\n arrayToObject: arrayToObject,\n assign: assign,\n compact: compact,\n decode: decode,\n encode: encode,\n isBuffer: isBuffer,\n isRegExp: isRegExp,\n merge: merge\n};\n","'use strict';\n\nvar replace = String.prototype.replace;\nvar percentTwenties = /%20/g;\n\nmodule.exports = {\n 'default': 'RFC3986',\n formatters: {\n RFC1738: function (value) {\n return replace.call(value, percentTwenties, '+');\n },\n RFC3986: function (value) {\n return value;\n }\n },\n RFC1738: 'RFC1738',\n RFC3986: 'RFC3986'\n};\n","'use strict';\n\nvar util = require('./util');\n\nmodule.exports = SchemaObject;\n\nfunction SchemaObject(obj) {\n util.copy(obj, this);\n}\n","'use strict';\n\nmodule.exports = function (data, opts) {\n if (!opts) opts = {};\n if (typeof opts === 'function') opts = { cmp: opts };\n var cycles = (typeof opts.cycles === 'boolean') ? opts.cycles : false;\n\n var cmp = opts.cmp && (function (f) {\n return function (node) {\n return function (a, b) {\n var aobj = { key: a, value: node[a] };\n var bobj = { key: b, value: node[b] };\n return f(aobj, bobj);\n };\n };\n })(opts.cmp);\n\n var seen = [];\n return (function stringify (node) {\n if (node && node.toJSON && typeof node.toJSON === 'function') {\n node = node.toJSON();\n }\n\n if (node === undefined) return;\n if (typeof node == 'number') return isFinite(node) ? '' + node : 'null';\n if (typeof node !== 'object') return JSON.stringify(node);\n\n var i, out;\n if (Array.isArray(node)) {\n out = '[';\n for (i = 0; i < node.length; i++) {\n if (i) out += ',';\n out += stringify(node[i]) || 'null';\n }\n return out + ']';\n }\n\n if (node === null) return 'null';\n\n if (seen.indexOf(node) !== -1) {\n if (cycles) return JSON.stringify('__cycle__');\n throw new TypeError('Converting circular structure to JSON');\n }\n\n var seenIndex = seen.push(node) - 1;\n var keys = Object.keys(node).sort(cmp && cmp(node));\n out = '';\n for (i = 0; i < keys.length; i++) {\n var key = keys[i];\n var value = stringify(node[key]);\n\n if (!value) continue;\n if (out) out += ',';\n out += JSON.stringify(key) + ':' + value;\n }\n seen.splice(seenIndex, 1);\n return '{' + out + '}';\n })(data);\n};\n","'use strict';\nmodule.exports = function generate_validate(it, $keyword, $ruleType) {\n var out = '';\n var $async = it.schema.$async === true,\n $refKeywords = it.util.schemaHasRulesExcept(it.schema, it.RULES.all, '$ref'),\n $id = it.self._getId(it.schema);\n if (it.isTop) {\n if ($async) {\n it.async = true;\n var $es7 = it.opts.async == 'es7';\n it.yieldAwait = $es7 ? 'await' : 'yield';\n }\n out += ' var validate = ';\n if ($async) {\n if ($es7) {\n out += ' (async function ';\n } else {\n if (it.opts.async != '*') {\n out += 'co.wrap';\n }\n out += '(function* ';\n }\n } else {\n out += ' (function ';\n }\n out += ' (data, dataPath, parentData, parentDataProperty, rootData) { \\'use strict\\'; ';\n if ($id && (it.opts.sourceCode || it.opts.processCode)) {\n out += ' ' + ('/\\*# sourceURL=' + $id + ' */') + ' ';\n }\n }\n if (typeof it.schema == 'boolean' || !($refKeywords || it.schema.$ref)) {\n var $keyword = 'false schema';\n var $lvl = it.level;\n var $dataLvl = it.dataLevel;\n var $schema = it.schema[$keyword];\n var $schemaPath = it.schemaPath + it.util.getProperty($keyword);\n var $errSchemaPath = it.errSchemaPath + '/' + $keyword;\n var $breakOnError = !it.opts.allErrors;\n var $errorKeyword;\n var $data = 'data' + ($dataLvl || '');\n var $valid = 'valid' + $lvl;\n if (it.schema === false) {\n if (it.isTop) {\n $breakOnError = true;\n } else {\n out += ' var ' + ($valid) + ' = false; ';\n }\n var $$outStack = $$outStack || [];\n $$outStack.push(out);\n out = ''; /* istanbul ignore else */\n if (it.createErrors !== false) {\n out += ' { keyword: \\'' + ($errorKeyword || 'false schema') + '\\' , dataPath: (dataPath || \\'\\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';\n if (it.opts.messages !== false) {\n out += ' , message: \\'boolean schema is false\\' ';\n }\n if (it.opts.verbose) {\n out += ' , schema: false , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';\n }\n out += ' } ';\n } else {\n out += ' {} ';\n }\n var __err = out;\n out = $$outStack.pop();\n if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */\n if (it.async) {\n out += ' throw new ValidationError([' + (__err) + ']); ';\n } else {\n out += ' validate.errors = [' + (__err) + ']; return false; ';\n }\n } else {\n out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';\n }\n } else {\n if (it.isTop) {\n if ($async) {\n out += ' return data; ';\n } else {\n out += ' validate.errors = null; return true; ';\n }\n } else {\n out += ' var ' + ($valid) + ' = true; ';\n }\n }\n if (it.isTop) {\n out += ' }); return validate; ';\n }\n return out;\n }\n if (it.isTop) {\n var $top = it.isTop,\n $lvl = it.level = 0,\n $dataLvl = it.dataLevel = 0,\n $data = 'data';\n it.rootId = it.resolve.fullPath(it.self._getId(it.root.schema));\n it.baseId = it.baseId || it.rootId;\n delete it.isTop;\n it.dataPathArr = [undefined];\n out += ' var vErrors = null; ';\n out += ' var errors = 0; ';\n out += ' if (rootData === undefined) rootData = data; ';\n } else {\n var $lvl = it.level,\n $dataLvl = it.dataLevel,\n $data = 'data' + ($dataLvl || '');\n if ($id) it.baseId = it.resolve.url(it.baseId, $id);\n if ($async && !it.async) throw new Error('async schema in sync schema');\n out += ' var errs_' + ($lvl) + ' = errors;';\n }\n var $valid = 'valid' + $lvl,\n $breakOnError = !it.opts.allErrors,\n $closingBraces1 = '',\n $closingBraces2 = '';\n var $errorKeyword;\n var $typeSchema = it.schema.type,\n $typeIsArray = Array.isArray($typeSchema);\n if ($typeIsArray && $typeSchema.length == 1) {\n $typeSchema = $typeSchema[0];\n $typeIsArray = false;\n }\n if (it.schema.$ref && $refKeywords) {\n if (it.opts.extendRefs == 'fail') {\n throw new Error('$ref: validation keywords used in schema at path \"' + it.errSchemaPath + '\" (see option extendRefs)');\n } else if (it.opts.extendRefs !== true) {\n $refKeywords = false;\n it.logger.warn('$ref: keywords ignored in schema at path \"' + it.errSchemaPath + '\"');\n }\n }\n if ($typeSchema) {\n if (it.opts.coerceTypes) {\n var $coerceToTypes = it.util.coerceToTypes(it.opts.coerceTypes, $typeSchema);\n }\n var $rulesGroup = it.RULES.types[$typeSchema];\n if ($coerceToTypes || $typeIsArray || $rulesGroup === true || ($rulesGroup && !$shouldUseGroup($rulesGroup))) {\n var $schemaPath = it.schemaPath + '.type',\n $errSchemaPath = it.errSchemaPath + '/type';\n var $schemaPath = it.schemaPath + '.type',\n $errSchemaPath = it.errSchemaPath + '/type',\n $method = $typeIsArray ? 'checkDataTypes' : 'checkDataType';\n out += ' if (' + (it.util[$method]($typeSchema, $data, true)) + ') { ';\n if ($coerceToTypes) {\n var $dataType = 'dataType' + $lvl,\n $coerced = 'coerced' + $lvl;\n out += ' var ' + ($dataType) + ' = typeof ' + ($data) + '; ';\n if (it.opts.coerceTypes == 'array') {\n out += ' if (' + ($dataType) + ' == \\'object\\' && Array.isArray(' + ($data) + ')) ' + ($dataType) + ' = \\'array\\'; ';\n }\n out += ' var ' + ($coerced) + ' = undefined; ';\n var $bracesCoercion = '';\n var arr1 = $coerceToTypes;\n if (arr1) {\n var $type, $i = -1,\n l1 = arr1.length - 1;\n while ($i < l1) {\n $type = arr1[$i += 1];\n if ($i) {\n out += ' if (' + ($coerced) + ' === undefined) { ';\n $bracesCoercion += '}';\n }\n if (it.opts.coerceTypes == 'array' && $type != 'array') {\n out += ' if (' + ($dataType) + ' == \\'array\\' && ' + ($data) + '.length == 1) { ' + ($coerced) + ' = ' + ($data) + ' = ' + ($data) + '[0]; ' + ($dataType) + ' = typeof ' + ($data) + '; } ';\n }\n if ($type == 'string') {\n out += ' if (' + ($dataType) + ' == \\'number\\' || ' + ($dataType) + ' == \\'boolean\\') ' + ($coerced) + ' = \\'\\' + ' + ($data) + '; else if (' + ($data) + ' === null) ' + ($coerced) + ' = \\'\\'; ';\n } else if ($type == 'number' || $type == 'integer') {\n out += ' if (' + ($dataType) + ' == \\'boolean\\' || ' + ($data) + ' === null || (' + ($dataType) + ' == \\'string\\' && ' + ($data) + ' && ' + ($data) + ' == +' + ($data) + ' ';\n if ($type == 'integer') {\n out += ' && !(' + ($data) + ' % 1)';\n }\n out += ')) ' + ($coerced) + ' = +' + ($data) + '; ';\n } else if ($type == 'boolean') {\n out += ' if (' + ($data) + ' === \\'false\\' || ' + ($data) + ' === 0 || ' + ($data) + ' === null) ' + ($coerced) + ' = false; else if (' + ($data) + ' === \\'true\\' || ' + ($data) + ' === 1) ' + ($coerced) + ' = true; ';\n } else if ($type == 'null') {\n out += ' if (' + ($data) + ' === \\'\\' || ' + ($data) + ' === 0 || ' + ($data) + ' === false) ' + ($coerced) + ' = null; ';\n } else if (it.opts.coerceTypes == 'array' && $type == 'array') {\n out += ' if (' + ($dataType) + ' == \\'string\\' || ' + ($dataType) + ' == \\'number\\' || ' + ($dataType) + ' == \\'boolean\\' || ' + ($data) + ' == null) ' + ($coerced) + ' = [' + ($data) + ']; ';\n }\n }\n }\n out += ' ' + ($bracesCoercion) + ' if (' + ($coerced) + ' === undefined) { ';\n var $$outStack = $$outStack || [];\n $$outStack.push(out);\n out = ''; /* istanbul ignore else */\n if (it.createErrors !== false) {\n out += ' { keyword: \\'' + ($errorKeyword || 'type') + '\\' , dataPath: (dataPath || \\'\\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \\'';\n if ($typeIsArray) {\n out += '' + ($typeSchema.join(\",\"));\n } else {\n out += '' + ($typeSchema);\n }\n out += '\\' } ';\n if (it.opts.messages !== false) {\n out += ' , message: \\'should be ';\n if ($typeIsArray) {\n out += '' + ($typeSchema.join(\",\"));\n } else {\n out += '' + ($typeSchema);\n }\n out += '\\' ';\n }\n if (it.opts.verbose) {\n out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';\n }\n out += ' } ';\n } else {\n out += ' {} ';\n }\n var __err = out;\n out = $$outStack.pop();\n if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */\n if (it.async) {\n out += ' throw new ValidationError([' + (__err) + ']); ';\n } else {\n out += ' validate.errors = [' + (__err) + ']; return false; ';\n }\n } else {\n out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';\n }\n out += ' } else { ';\n var $parentData = $dataLvl ? 'data' + (($dataLvl - 1) || '') : 'parentData',\n $parentDataProperty = $dataLvl ? it.dataPathArr[$dataLvl] : 'parentDataProperty';\n out += ' ' + ($data) + ' = ' + ($coerced) + '; ';\n if (!$dataLvl) {\n out += 'if (' + ($parentData) + ' !== undefined)';\n }\n out += ' ' + ($parentData) + '[' + ($parentDataProperty) + '] = ' + ($coerced) + '; } ';\n } else {\n var $$outStack = $$outStack || [];\n $$outStack.push(out);\n out = ''; /* istanbul ignore else */\n if (it.createErrors !== false) {\n out += ' { keyword: \\'' + ($errorKeyword || 'type') + '\\' , dataPath: (dataPath || \\'\\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \\'';\n if ($typeIsArray) {\n out += '' + ($typeSchema.join(\",\"));\n } else {\n out += '' + ($typeSchema);\n }\n out += '\\' } ';\n if (it.opts.messages !== false) {\n out += ' , message: \\'should be ';\n if ($typeIsArray) {\n out += '' + ($typeSchema.join(\",\"));\n } else {\n out += '' + ($typeSchema);\n }\n out += '\\' ';\n }\n if (it.opts.verbose) {\n out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';\n }\n out += ' } ';\n } else {\n out += ' {} ';\n }\n var __err = out;\n out = $$outStack.pop();\n if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */\n if (it.async) {\n out += ' throw new ValidationError([' + (__err) + ']); ';\n } else {\n out += ' validate.errors = [' + (__err) + ']; return false; ';\n }\n } else {\n out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';\n }\n }\n out += ' } ';\n }\n }\n if (it.schema.$ref && !$refKeywords) {\n out += ' ' + (it.RULES.all.$ref.code(it, '$ref')) + ' ';\n if ($breakOnError) {\n out += ' } if (errors === ';\n if ($top) {\n out += '0';\n } else {\n out += 'errs_' + ($lvl);\n }\n out += ') { ';\n $closingBraces2 += '}';\n }\n } else {\n if (it.opts.v5 && it.schema.patternGroups) {\n it.logger.warn('keyword \"patternGroups\" is deprecated and disabled. Use option patternGroups: true to enable.');\n }\n var arr2 = it.RULES;\n if (arr2) {\n var $rulesGroup, i2 = -1,\n l2 = arr2.length - 1;\n while (i2 < l2) {\n $rulesGroup = arr2[i2 += 1];\n if ($shouldUseGroup($rulesGroup)) {\n if ($rulesGroup.type) {\n out += ' if (' + (it.util.checkDataType($rulesGroup.type, $data)) + ') { ';\n }\n if (it.opts.useDefaults && !it.compositeRule) {\n if ($rulesGroup.type == 'object' && it.schema.properties) {\n var $schema = it.schema.properties,\n $schemaKeys = Object.keys($schema);\n var arr3 = $schemaKeys;\n if (arr3) {\n var $propertyKey, i3 = -1,\n l3 = arr3.length - 1;\n while (i3 < l3) {\n $propertyKey = arr3[i3 += 1];\n var $sch = $schema[$propertyKey];\n if ($sch.default !== undefined) {\n var $passData = $data + it.util.getProperty($propertyKey);\n out += ' if (' + ($passData) + ' === undefined) ' + ($passData) + ' = ';\n if (it.opts.useDefaults == 'shared') {\n out += ' ' + (it.useDefault($sch.default)) + ' ';\n } else {\n out += ' ' + (JSON.stringify($sch.default)) + ' ';\n }\n out += '; ';\n }\n }\n }\n } else if ($rulesGroup.type == 'array' && Array.isArray(it.schema.items)) {\n var arr4 = it.schema.items;\n if (arr4) {\n var $sch, $i = -1,\n l4 = arr4.length - 1;\n while ($i < l4) {\n $sch = arr4[$i += 1];\n if ($sch.default !== undefined) {\n var $passData = $data + '[' + $i + ']';\n out += ' if (' + ($passData) + ' === undefined) ' + ($passData) + ' = ';\n if (it.opts.useDefaults == 'shared') {\n out += ' ' + (it.useDefault($sch.default)) + ' ';\n } else {\n out += ' ' + (JSON.stringify($sch.default)) + ' ';\n }\n out += '; ';\n }\n }\n }\n }\n }\n var arr5 = $rulesGroup.rules;\n if (arr5) {\n var $rule, i5 = -1,\n l5 = arr5.length - 1;\n while (i5 < l5) {\n $rule = arr5[i5 += 1];\n if ($shouldUseRule($rule)) {\n var $code = $rule.code(it, $rule.keyword, $rulesGroup.type);\n if ($code) {\n out += ' ' + ($code) + ' ';\n if ($breakOnError) {\n $closingBraces1 += '}';\n }\n }\n }\n }\n }\n if ($breakOnError) {\n out += ' ' + ($closingBraces1) + ' ';\n $closingBraces1 = '';\n }\n if ($rulesGroup.type) {\n out += ' } ';\n if ($typeSchema && $typeSchema === $rulesGroup.type && !$coerceToTypes) {\n out += ' else { ';\n var $schemaPath = it.schemaPath + '.type',\n $errSchemaPath = it.errSchemaPath + '/type';\n var $$outStack = $$outStack || [];\n $$outStack.push(out);\n out = ''; /* istanbul ignore else */\n if (it.createErrors !== false) {\n out += ' { keyword: \\'' + ($errorKeyword || 'type') + '\\' , dataPath: (dataPath || \\'\\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { type: \\'';\n if ($typeIsArray) {\n out += '' + ($typeSchema.join(\",\"));\n } else {\n out += '' + ($typeSchema);\n }\n out += '\\' } ';\n if (it.opts.messages !== false) {\n out += ' , message: \\'should be ';\n if ($typeIsArray) {\n out += '' + ($typeSchema.join(\",\"));\n } else {\n out += '' + ($typeSchema);\n }\n out += '\\' ';\n }\n if (it.opts.verbose) {\n out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';\n }\n out += ' } ';\n } else {\n out += ' {} ';\n }\n var __err = out;\n out = $$outStack.pop();\n if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */\n if (it.async) {\n out += ' throw new ValidationError([' + (__err) + ']); ';\n } else {\n out += ' validate.errors = [' + (__err) + ']; return false; ';\n }\n } else {\n out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';\n }\n out += ' } ';\n }\n }\n if ($breakOnError) {\n out += ' if (errors === ';\n if ($top) {\n out += '0';\n } else {\n out += 'errs_' + ($lvl);\n }\n out += ') { ';\n $closingBraces2 += '}';\n }\n }\n }\n }\n }\n if ($breakOnError) {\n out += ' ' + ($closingBraces2) + ' ';\n }\n if ($top) {\n if ($async) {\n out += ' if (errors === 0) return data; ';\n out += ' else throw new ValidationError(vErrors); ';\n } else {\n out += ' validate.errors = vErrors; ';\n out += ' return errors === 0; ';\n }\n out += ' }); return validate;';\n } else {\n out += ' var ' + ($valid) + ' = errors === errs_' + ($lvl) + ';';\n }\n out = it.util.cleanUpCode(out);\n if ($top) {\n out = it.util.finalCleanUpCode(out, $async);\n }\n\n function $shouldUseGroup($rulesGroup) {\n var rules = $rulesGroup.rules;\n for (var i = 0; i < rules.length; i++)\n if ($shouldUseRule(rules[i])) return true;\n }\n\n function $shouldUseRule($rule) {\n return it.schema[$rule.keyword] !== undefined || ($rule.implements && $ruleImplementsSomeKeyword($rule));\n }\n\n function $ruleImplementsSomeKeyword($rule) {\n var impl = $rule.implements;\n for (var i = 0; i < impl.length; i++)\n if (it.schema[impl[i]] !== undefined) return true;\n }\n return out;\n}\n","\n/**\n * slice() reference.\n */\n\nvar slice = Array.prototype.slice;\n\n/**\n * Expose `co`.\n */\n\nmodule.exports = co['default'] = co.co = co;\n\n/**\n * Wrap the given generator `fn` into a\n * function that returns a promise.\n * This is a separate function so that\n * every `co()` call doesn't create a new,\n * unnecessary closure.\n *\n * @param {GeneratorFunction} fn\n * @return {Function}\n * @api public\n */\n\nco.wrap = function (fn) {\n createPromise.__generatorFunction__ = fn;\n return createPromise;\n function createPromise() {\n return co.call(this, fn.apply(this, arguments));\n }\n};\n\n/**\n * Execute the generator function or a generator\n * and return a promise.\n *\n * @param {Function} fn\n * @return {Promise}\n * @api public\n */\n\nfunction co(gen) {\n var ctx = this;\n var args = slice.call(arguments, 1)\n\n // we wrap everything in a promise to avoid promise chaining,\n // which leads to memory leak errors.\n // see https://github.com/tj/co/issues/180\n return new Promise(function(resolve, reject) {\n if (typeof gen === 'function') gen = gen.apply(ctx, args);\n if (!gen || typeof gen.next !== 'function') return resolve(gen);\n\n onFulfilled();\n\n /**\n * @param {Mixed} res\n * @return {Promise}\n * @api private\n */\n\n function onFulfilled(res) {\n var ret;\n try {\n ret = gen.next(res);\n } catch (e) {\n return reject(e);\n }\n next(ret);\n }\n\n /**\n * @param {Error} err\n * @return {Promise}\n * @api private\n */\n\n function onRejected(err) {\n var ret;\n try {\n ret = gen.throw(err);\n } catch (e) {\n return reject(e);\n }\n next(ret);\n }\n\n /**\n * Get the next value in the generator,\n * return a promise.\n *\n * @param {Object} ret\n * @return {Promise}\n * @api private\n */\n\n function next(ret) {\n if (ret.done) return resolve(ret.value);\n var value = toPromise.call(ctx, ret.value);\n if (value && isPromise(value)) return value.then(onFulfilled, onRejected);\n return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '\n + 'but the following object was passed: \"' + String(ret.value) + '\"'));\n }\n });\n}\n\n/**\n * Convert a `yield`ed value into a promise.\n *\n * @param {Mixed} obj\n * @return {Promise}\n * @api private\n */\n\nfunction toPromise(obj) {\n if (!obj) return obj;\n if (isPromise(obj)) return obj;\n if (isGeneratorFunction(obj) || isGenerator(obj)) return co.call(this, obj);\n if ('function' == typeof obj) return thunkToPromise.call(this, obj);\n if (Array.isArray(obj)) return arrayToPromise.call(this, obj);\n if (isObject(obj)) return objectToPromise.call(this, obj);\n return obj;\n}\n\n/**\n * Convert a thunk to a promise.\n *\n * @param {Function}\n * @return {Promise}\n * @api private\n */\n\nfunction thunkToPromise(fn) {\n var ctx = this;\n return new Promise(function (resolve, reject) {\n fn.call(ctx, function (err, res) {\n if (err) return reject(err);\n if (arguments.length > 2) res = slice.call(arguments, 1);\n resolve(res);\n });\n });\n}\n\n/**\n * Convert an array of \"yieldables\" to a promise.\n * Uses `Promise.all()` internally.\n *\n * @param {Array} obj\n * @return {Promise}\n * @api private\n */\n\nfunction arrayToPromise(obj) {\n return Promise.all(obj.map(toPromise, this));\n}\n\n/**\n * Convert an object of \"yieldables\" to a promise.\n * Uses `Promise.all()` internally.\n *\n * @param {Object} obj\n * @return {Promise}\n * @api private\n */\n\nfunction objectToPromise(obj){\n var results = new obj.constructor();\n var keys = Object.keys(obj);\n var promises = [];\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i];\n var promise = toPromise.call(this, obj[key]);\n if (promise && isPromise(promise)) defer(promise, key);\n else results[key] = obj[key];\n }\n return Promise.all(promises).then(function () {\n return results;\n });\n\n function defer(promise, key) {\n // predefine the key in the result\n results[key] = undefined;\n promises.push(promise.then(function (res) {\n results[key] = res;\n }));\n }\n}\n\n/**\n * Check if `obj` is a promise.\n *\n * @param {Object} obj\n * @return {Boolean}\n * @api private\n */\n\nfunction isPromise(obj) {\n return 'function' == typeof obj.then;\n}\n\n/**\n * Check if `obj` is a generator.\n *\n * @param {Mixed} obj\n * @return {Boolean}\n * @api private\n */\n\nfunction isGenerator(obj) {\n return 'function' == typeof obj.next && 'function' == typeof obj.throw;\n}\n\n/**\n * Check if `obj` is a generator function.\n *\n * @param {Mixed} obj\n * @return {Boolean}\n * @api private\n */\nfunction isGeneratorFunction(obj) {\n var constructor = obj.constructor;\n if (!constructor) return false;\n if ('GeneratorFunction' === constructor.name || 'GeneratorFunction' === constructor.displayName) return true;\n return isGenerator(constructor.prototype);\n}\n\n/**\n * Check for plain object.\n *\n * @param {Mixed} val\n * @return {Boolean}\n * @api private\n */\n\nfunction isObject(val) {\n return Object == val.constructor;\n}\n","'use strict';\nmodule.exports = function generate__limit(it, $keyword, $ruleType) {\n var out = ' ';\n var $lvl = it.level;\n var $dataLvl = it.dataLevel;\n var $schema = it.schema[$keyword];\n var $schemaPath = it.schemaPath + it.util.getProperty($keyword);\n var $errSchemaPath = it.errSchemaPath + '/' + $keyword;\n var $breakOnError = !it.opts.allErrors;\n var $errorKeyword;\n var $data = 'data' + ($dataLvl || '');\n var $isData = it.opts.$data && $schema && $schema.$data,\n $schemaValue;\n if ($isData) {\n out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';\n $schemaValue = 'schema' + $lvl;\n } else {\n $schemaValue = $schema;\n }\n var $isMax = $keyword == 'maximum',\n $exclusiveKeyword = $isMax ? 'exclusiveMaximum' : 'exclusiveMinimum',\n $schemaExcl = it.schema[$exclusiveKeyword],\n $isDataExcl = it.opts.$data && $schemaExcl && $schemaExcl.$data,\n $op = $isMax ? '<' : '>',\n $notOp = $isMax ? '>' : '<',\n $errorKeyword = undefined;\n if ($isDataExcl) {\n var $schemaValueExcl = it.util.getData($schemaExcl.$data, $dataLvl, it.dataPathArr),\n $exclusive = 'exclusive' + $lvl,\n $exclType = 'exclType' + $lvl,\n $exclIsNumber = 'exclIsNumber' + $lvl,\n $opExpr = 'op' + $lvl,\n $opStr = '\\' + ' + $opExpr + ' + \\'';\n out += ' var schemaExcl' + ($lvl) + ' = ' + ($schemaValueExcl) + '; ';\n $schemaValueExcl = 'schemaExcl' + $lvl;\n out += ' var ' + ($exclusive) + '; var ' + ($exclType) + ' = typeof ' + ($schemaValueExcl) + '; if (' + ($exclType) + ' != \\'boolean\\' && ' + ($exclType) + ' != \\'undefined\\' && ' + ($exclType) + ' != \\'number\\') { ';\n var $errorKeyword = $exclusiveKeyword;\n var $$outStack = $$outStack || [];\n $$outStack.push(out);\n out = ''; /* istanbul ignore else */\n if (it.createErrors !== false) {\n out += ' { keyword: \\'' + ($errorKeyword || '_exclusiveLimit') + '\\' , dataPath: (dataPath || \\'\\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';\n if (it.opts.messages !== false) {\n out += ' , message: \\'' + ($exclusiveKeyword) + ' should be boolean\\' ';\n }\n if (it.opts.verbose) {\n out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';\n }\n out += ' } ';\n } else {\n out += ' {} ';\n }\n var __err = out;\n out = $$outStack.pop();\n if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */\n if (it.async) {\n out += ' throw new ValidationError([' + (__err) + ']); ';\n } else {\n out += ' validate.errors = [' + (__err) + ']; return false; ';\n }\n } else {\n out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';\n }\n out += ' } else if ( ';\n if ($isData) {\n out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \\'number\\') || ';\n }\n out += ' ' + ($exclType) + ' == \\'number\\' ? ( (' + ($exclusive) + ' = ' + ($schemaValue) + ' === undefined || ' + ($schemaValueExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ') ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValueExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) : ( (' + ($exclusive) + ' = ' + ($schemaValueExcl) + ' === true) ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaValue) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { var op' + ($lvl) + ' = ' + ($exclusive) + ' ? \\'' + ($op) + '\\' : \\'' + ($op) + '=\\';';\n } else {\n var $exclIsNumber = typeof $schemaExcl == 'number',\n $opStr = $op;\n if ($exclIsNumber && $isData) {\n var $opExpr = '\\'' + $opStr + '\\'';\n out += ' if ( ';\n if ($isData) {\n out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \\'number\\') || ';\n }\n out += ' ( ' + ($schemaValue) + ' === undefined || ' + ($schemaExcl) + ' ' + ($op) + '= ' + ($schemaValue) + ' ? ' + ($data) + ' ' + ($notOp) + '= ' + ($schemaExcl) + ' : ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' ) || ' + ($data) + ' !== ' + ($data) + ') { ';\n } else {\n if ($exclIsNumber && $schema === undefined) {\n $exclusive = true;\n $errorKeyword = $exclusiveKeyword;\n $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword;\n $schemaValue = $schemaExcl;\n $notOp += '=';\n } else {\n if ($exclIsNumber) $schemaValue = Math[$isMax ? 'min' : 'max']($schemaExcl, $schema);\n if ($schemaExcl === ($exclIsNumber ? $schemaValue : true)) {\n $exclusive = true;\n $errorKeyword = $exclusiveKeyword;\n $errSchemaPath = it.errSchemaPath + '/' + $exclusiveKeyword;\n $notOp += '=';\n } else {\n $exclusive = false;\n $opStr += '=';\n }\n }\n var $opExpr = '\\'' + $opStr + '\\'';\n out += ' if ( ';\n if ($isData) {\n out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \\'number\\') || ';\n }\n out += ' ' + ($data) + ' ' + ($notOp) + ' ' + ($schemaValue) + ' || ' + ($data) + ' !== ' + ($data) + ') { ';\n }\n }\n $errorKeyword = $errorKeyword || $keyword;\n var $$outStack = $$outStack || [];\n $$outStack.push(out);\n out = ''; /* istanbul ignore else */\n if (it.createErrors !== false) {\n out += ' { keyword: \\'' + ($errorKeyword || '_limit') + '\\' , dataPath: (dataPath || \\'\\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { comparison: ' + ($opExpr) + ', limit: ' + ($schemaValue) + ', exclusive: ' + ($exclusive) + ' } ';\n if (it.opts.messages !== false) {\n out += ' , message: \\'should be ' + ($opStr) + ' ';\n if ($isData) {\n out += '\\' + ' + ($schemaValue);\n } else {\n out += '' + ($schemaValue) + '\\'';\n }\n }\n if (it.opts.verbose) {\n out += ' , schema: ';\n if ($isData) {\n out += 'validate.schema' + ($schemaPath);\n } else {\n out += '' + ($schema);\n }\n out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';\n }\n out += ' } ';\n } else {\n out += ' {} ';\n }\n var __err = out;\n out = $$outStack.pop();\n if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */\n if (it.async) {\n out += ' throw new ValidationError([' + (__err) + ']); ';\n } else {\n out += ' validate.errors = [' + (__err) + ']; return false; ';\n }\n } else {\n out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';\n }\n out += ' } ';\n if ($breakOnError) {\n out += ' else { ';\n }\n return out;\n}\n","'use strict';\nmodule.exports = function generate__limitItems(it, $keyword, $ruleType) {\n var out = ' ';\n var $lvl = it.level;\n var $dataLvl = it.dataLevel;\n var $schema = it.schema[$keyword];\n var $schemaPath = it.schemaPath + it.util.getProperty($keyword);\n var $errSchemaPath = it.errSchemaPath + '/' + $keyword;\n var $breakOnError = !it.opts.allErrors;\n var $errorKeyword;\n var $data = 'data' + ($dataLvl || '');\n var $isData = it.opts.$data && $schema && $schema.$data,\n $schemaValue;\n if ($isData) {\n out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';\n $schemaValue = 'schema' + $lvl;\n } else {\n $schemaValue = $schema;\n }\n var $op = $keyword == 'maxItems' ? '>' : '<';\n out += 'if ( ';\n if ($isData) {\n out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \\'number\\') || ';\n }\n out += ' ' + ($data) + '.length ' + ($op) + ' ' + ($schemaValue) + ') { ';\n var $errorKeyword = $keyword;\n var $$outStack = $$outStack || [];\n $$outStack.push(out);\n out = ''; /* istanbul ignore else */\n if (it.createErrors !== false) {\n out += ' { keyword: \\'' + ($errorKeyword || '_limitItems') + '\\' , dataPath: (dataPath || \\'\\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } ';\n if (it.opts.messages !== false) {\n out += ' , message: \\'should NOT have ';\n if ($keyword == 'maxItems') {\n out += 'more';\n } else {\n out += 'less';\n }\n out += ' than ';\n if ($isData) {\n out += '\\' + ' + ($schemaValue) + ' + \\'';\n } else {\n out += '' + ($schema);\n }\n out += ' items\\' ';\n }\n if (it.opts.verbose) {\n out += ' , schema: ';\n if ($isData) {\n out += 'validate.schema' + ($schemaPath);\n } else {\n out += '' + ($schema);\n }\n out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';\n }\n out += ' } ';\n } else {\n out += ' {} ';\n }\n var __err = out;\n out = $$outStack.pop();\n if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */\n if (it.async) {\n out += ' throw new ValidationError([' + (__err) + ']); ';\n } else {\n out += ' validate.errors = [' + (__err) + ']; return false; ';\n }\n } else {\n out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';\n }\n out += '} ';\n if ($breakOnError) {\n out += ' else { ';\n }\n return out;\n}\n","'use strict';\nmodule.exports = function generate__limitLength(it, $keyword, $ruleType) {\n var out = ' ';\n var $lvl = it.level;\n var $dataLvl = it.dataLevel;\n var $schema = it.schema[$keyword];\n var $schemaPath = it.schemaPath + it.util.getProperty($keyword);\n var $errSchemaPath = it.errSchemaPath + '/' + $keyword;\n var $breakOnError = !it.opts.allErrors;\n var $errorKeyword;\n var $data = 'data' + ($dataLvl || '');\n var $isData = it.opts.$data && $schema && $schema.$data,\n $schemaValue;\n if ($isData) {\n out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';\n $schemaValue = 'schema' + $lvl;\n } else {\n $schemaValue = $schema;\n }\n var $op = $keyword == 'maxLength' ? '>' : '<';\n out += 'if ( ';\n if ($isData) {\n out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \\'number\\') || ';\n }\n if (it.opts.unicode === false) {\n out += ' ' + ($data) + '.length ';\n } else {\n out += ' ucs2length(' + ($data) + ') ';\n }\n out += ' ' + ($op) + ' ' + ($schemaValue) + ') { ';\n var $errorKeyword = $keyword;\n var $$outStack = $$outStack || [];\n $$outStack.push(out);\n out = ''; /* istanbul ignore else */\n if (it.createErrors !== false) {\n out += ' { keyword: \\'' + ($errorKeyword || '_limitLength') + '\\' , dataPath: (dataPath || \\'\\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } ';\n if (it.opts.messages !== false) {\n out += ' , message: \\'should NOT be ';\n if ($keyword == 'maxLength') {\n out += 'longer';\n } else {\n out += 'shorter';\n }\n out += ' than ';\n if ($isData) {\n out += '\\' + ' + ($schemaValue) + ' + \\'';\n } else {\n out += '' + ($schema);\n }\n out += ' characters\\' ';\n }\n if (it.opts.verbose) {\n out += ' , schema: ';\n if ($isData) {\n out += 'validate.schema' + ($schemaPath);\n } else {\n out += '' + ($schema);\n }\n out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';\n }\n out += ' } ';\n } else {\n out += ' {} ';\n }\n var __err = out;\n out = $$outStack.pop();\n if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */\n if (it.async) {\n out += ' throw new ValidationError([' + (__err) + ']); ';\n } else {\n out += ' validate.errors = [' + (__err) + ']; return false; ';\n }\n } else {\n out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';\n }\n out += '} ';\n if ($breakOnError) {\n out += ' else { ';\n }\n return out;\n}\n","'use strict';\nmodule.exports = function generate__limitProperties(it, $keyword, $ruleType) {\n var out = ' ';\n var $lvl = it.level;\n var $dataLvl = it.dataLevel;\n var $schema = it.schema[$keyword];\n var $schemaPath = it.schemaPath + it.util.getProperty($keyword);\n var $errSchemaPath = it.errSchemaPath + '/' + $keyword;\n var $breakOnError = !it.opts.allErrors;\n var $errorKeyword;\n var $data = 'data' + ($dataLvl || '');\n var $isData = it.opts.$data && $schema && $schema.$data,\n $schemaValue;\n if ($isData) {\n out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';\n $schemaValue = 'schema' + $lvl;\n } else {\n $schemaValue = $schema;\n }\n var $op = $keyword == 'maxProperties' ? '>' : '<';\n out += 'if ( ';\n if ($isData) {\n out += ' (' + ($schemaValue) + ' !== undefined && typeof ' + ($schemaValue) + ' != \\'number\\') || ';\n }\n out += ' Object.keys(' + ($data) + ').length ' + ($op) + ' ' + ($schemaValue) + ') { ';\n var $errorKeyword = $keyword;\n var $$outStack = $$outStack || [];\n $$outStack.push(out);\n out = ''; /* istanbul ignore else */\n if (it.createErrors !== false) {\n out += ' { keyword: \\'' + ($errorKeyword || '_limitProperties') + '\\' , dataPath: (dataPath || \\'\\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { limit: ' + ($schemaValue) + ' } ';\n if (it.opts.messages !== false) {\n out += ' , message: \\'should NOT have ';\n if ($keyword == 'maxProperties') {\n out += 'more';\n } else {\n out += 'less';\n }\n out += ' than ';\n if ($isData) {\n out += '\\' + ' + ($schemaValue) + ' + \\'';\n } else {\n out += '' + ($schema);\n }\n out += ' properties\\' ';\n }\n if (it.opts.verbose) {\n out += ' , schema: ';\n if ($isData) {\n out += 'validate.schema' + ($schemaPath);\n } else {\n out += '' + ($schema);\n }\n out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';\n }\n out += ' } ';\n } else {\n out += ' {} ';\n }\n var __err = out;\n out = $$outStack.pop();\n if (!it.compositeRule && $breakOnError) { /* istanbul ignore if */\n if (it.async) {\n out += ' throw new ValidationError([' + (__err) + ']); ';\n } else {\n out += ' validate.errors = [' + (__err) + ']; return false; ';\n }\n } else {\n out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';\n }\n out += '} ';\n if ($breakOnError) {\n out += ' else { ';\n }\n return out;\n}\n","(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n typeof define === 'function' && define.amd ? define(['exports'], factory) :\n (factory((global.async = global.async || {})));\n}(this, (function (exports) { 'use strict';\n\nfunction slice(arrayLike, start) {\n start = start|0;\n var newLen = Math.max(arrayLike.length - start, 0);\n var newArr = Array(newLen);\n for(var idx = 0; idx < newLen; idx++) {\n newArr[idx] = arrayLike[start + idx];\n }\n return newArr;\n}\n\n/**\n * Creates a continuation function with some arguments already applied.\n *\n * Useful as a shorthand when combined with other control flow functions. Any\n * arguments passed to the returned function are added to the arguments\n * originally passed to apply.\n *\n * @name apply\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {Function} fn - The function you want to eventually apply all\n * arguments to. Invokes with (arguments...).\n * @param {...*} arguments... - Any number of arguments to automatically apply\n * when the continuation is called.\n * @returns {Function} the partially-applied function\n * @example\n *\n * // using apply\n * async.parallel([\n * async.apply(fs.writeFile, 'testfile1', 'test1'),\n * async.apply(fs.writeFile, 'testfile2', 'test2')\n * ]);\n *\n *\n * // the same process without using apply\n * async.parallel([\n * function(callback) {\n * fs.writeFile('testfile1', 'test1', callback);\n * },\n * function(callback) {\n * fs.writeFile('testfile2', 'test2', callback);\n * }\n * ]);\n *\n * // It's possible to pass any number of additional arguments when calling the\n * // continuation:\n *\n * node> var fn = async.apply(sys.puts, 'one');\n * node> fn('two', 'three');\n * one\n * two\n * three\n */\nvar apply = function(fn/*, ...args*/) {\n var args = slice(arguments, 1);\n return function(/*callArgs*/) {\n var callArgs = slice(arguments);\n return fn.apply(null, args.concat(callArgs));\n };\n};\n\nvar initialParams = function (fn) {\n return function (/*...args, callback*/) {\n var args = slice(arguments);\n var callback = args.pop();\n fn.call(this, args, callback);\n };\n};\n\n/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nvar hasSetImmediate = typeof setImmediate === 'function' && setImmediate;\nvar hasNextTick = typeof process === 'object' && typeof process.nextTick === 'function';\n\nfunction fallback(fn) {\n setTimeout(fn, 0);\n}\n\nfunction wrap(defer) {\n return function (fn/*, ...args*/) {\n var args = slice(arguments, 1);\n defer(function () {\n fn.apply(null, args);\n });\n };\n}\n\nvar _defer;\n\nif (hasSetImmediate) {\n _defer = setImmediate;\n} else if (hasNextTick) {\n _defer = process.nextTick;\n} else {\n _defer = fallback;\n}\n\nvar setImmediate$1 = wrap(_defer);\n\n/**\n * Take a sync function and make it async, passing its return value to a\n * callback. This is useful for plugging sync functions into a waterfall,\n * series, or other async functions. Any arguments passed to the generated\n * function will be passed to the wrapped function (except for the final\n * callback argument). Errors thrown will be passed to the callback.\n *\n * If the function passed to `asyncify` returns a Promise, that promises's\n * resolved/rejected state will be used to call the callback, rather than simply\n * the synchronous return value.\n *\n * This also means you can asyncify ES2017 `async` functions.\n *\n * @name asyncify\n * @static\n * @memberOf module:Utils\n * @method\n * @alias wrapSync\n * @category Util\n * @param {Function} func - The synchronous function, or Promise-returning\n * function to convert to an {@link AsyncFunction}.\n * @returns {AsyncFunction} An asynchronous wrapper of the `func`. To be\n * invoked with `(args..., callback)`.\n * @example\n *\n * // passing a regular synchronous function\n * async.waterfall([\n * async.apply(fs.readFile, filename, \"utf8\"),\n * async.asyncify(JSON.parse),\n * function (data, next) {\n * // data is the result of parsing the text.\n * // If there was a parsing error, it would have been caught.\n * }\n * ], callback);\n *\n * // passing a function returning a promise\n * async.waterfall([\n * async.apply(fs.readFile, filename, \"utf8\"),\n * async.asyncify(function (contents) {\n * return db.model.create(contents);\n * }),\n * function (model, next) {\n * // `model` is the instantiated model object.\n * // If there was an error, this function would be skipped.\n * }\n * ], callback);\n *\n * // es2017 example, though `asyncify` is not needed if your JS environment\n * // supports async functions out of the box\n * var q = async.queue(async.asyncify(async function(file) {\n * var intermediateStep = await processFile(file);\n * return await somePromise(intermediateStep)\n * }));\n *\n * q.push(files);\n */\nfunction asyncify(func) {\n return initialParams(function (args, callback) {\n var result;\n try {\n result = func.apply(this, args);\n } catch (e) {\n return callback(e);\n }\n // if result is Promise object\n if (isObject(result) && typeof result.then === 'function') {\n result.then(function(value) {\n invokeCallback(callback, null, value);\n }, function(err) {\n invokeCallback(callback, err.message ? err : new Error(err));\n });\n } else {\n callback(null, result);\n }\n });\n}\n\nfunction invokeCallback(callback, error, value) {\n try {\n callback(error, value);\n } catch (e) {\n setImmediate$1(rethrow, e);\n }\n}\n\nfunction rethrow(error) {\n throw error;\n}\n\nvar supportsSymbol = typeof Symbol === 'function';\n\nfunction isAsync(fn) {\n return supportsSymbol && fn[Symbol.toStringTag] === 'AsyncFunction';\n}\n\nfunction wrapAsync(asyncFn) {\n return isAsync(asyncFn) ? asyncify(asyncFn) : asyncFn;\n}\n\nfunction applyEach$1(eachfn) {\n return function(fns/*, ...args*/) {\n var args = slice(arguments, 1);\n var go = initialParams(function(args, callback) {\n var that = this;\n return eachfn(fns, function (fn, cb) {\n wrapAsync(fn).apply(that, args.concat(cb));\n }, callback);\n });\n if (args.length) {\n return go.apply(this, args);\n }\n else {\n return go;\n }\n };\n}\n\n/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\n/** Built-in value references. */\nvar Symbol$1 = root.Symbol;\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag$1),\n tag = value[symToStringTag$1];\n\n try {\n value[symToStringTag$1] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag$1] = tag;\n } else {\n delete value[symToStringTag$1];\n }\n }\n return result;\n}\n\n/** Used for built-in method references. */\nvar objectProto$1 = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString$1 = objectProto$1.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString$1.call(value);\n}\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]';\nvar undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol$1 ? Symbol$1.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\n/** `Object#toString` result references. */\nvar asyncTag = '[object AsyncFunction]';\nvar funcTag = '[object Function]';\nvar genTag = '[object GeneratorFunction]';\nvar proxyTag = '[object Proxy]';\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n if (!isObject(value)) {\n return false;\n }\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\n/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n return value != null && isLength(value.length) && !isFunction(value);\n}\n\n// A temporary value used to identify if the loop should be broken.\n// See #1064, #1293\nvar breakLoop = {};\n\n/**\n * This method returns `undefined`.\n *\n * @static\n * @memberOf _\n * @since 2.3.0\n * @category Util\n * @example\n *\n * _.times(2, _.noop);\n * // => [undefined, undefined]\n */\nfunction noop() {\n // No operation performed.\n}\n\nfunction once(fn) {\n return function () {\n if (fn === null) return;\n var callFn = fn;\n fn = null;\n callFn.apply(this, arguments);\n };\n}\n\nvar iteratorSymbol = typeof Symbol === 'function' && Symbol.iterator;\n\nvar getIterator = function (coll) {\n return iteratorSymbol && coll[iteratorSymbol] && coll[iteratorSymbol]();\n};\n\n/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\n/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]';\n\n/**\n * The base implementation of `_.isArguments`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n */\nfunction baseIsArguments(value) {\n return isObjectLike(value) && baseGetTag(value) == argsTag;\n}\n\n/** Used for built-in method references. */\nvar objectProto$3 = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty$2 = objectProto$3.hasOwnProperty;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto$3.propertyIsEnumerable;\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n * else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nvar isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n return isObjectLike(value) && hasOwnProperty$2.call(value, 'callee') &&\n !propertyIsEnumerable.call(value, 'callee');\n};\n\n/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\n/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined;\n\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\n/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER$1 = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER$1 : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\n/** `Object#toString` result references. */\nvar argsTag$1 = '[object Arguments]';\nvar arrayTag = '[object Array]';\nvar boolTag = '[object Boolean]';\nvar dateTag = '[object Date]';\nvar errorTag = '[object Error]';\nvar funcTag$1 = '[object Function]';\nvar mapTag = '[object Map]';\nvar numberTag = '[object Number]';\nvar objectTag = '[object Object]';\nvar regexpTag = '[object RegExp]';\nvar setTag = '[object Set]';\nvar stringTag = '[object String]';\nvar weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]';\nvar dataViewTag = '[object DataView]';\nvar float32Tag = '[object Float32Array]';\nvar float64Tag = '[object Float64Array]';\nvar int8Tag = '[object Int8Array]';\nvar int16Tag = '[object Int16Array]';\nvar int32Tag = '[object Int32Array]';\nvar uint8Tag = '[object Uint8Array]';\nvar uint8ClampedTag = '[object Uint8ClampedArray]';\nvar uint16Tag = '[object Uint16Array]';\nvar uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values of typed arrays. */\nvar typedArrayTags = {};\ntypedArrayTags[float32Tag] = typedArrayTags[float64Tag] =\ntypedArrayTags[int8Tag] = typedArrayTags[int16Tag] =\ntypedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =\ntypedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =\ntypedArrayTags[uint32Tag] = true;\ntypedArrayTags[argsTag$1] = typedArrayTags[arrayTag] =\ntypedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =\ntypedArrayTags[dataViewTag] = typedArrayTags[dateTag] =\ntypedArrayTags[errorTag] = typedArrayTags[funcTag$1] =\ntypedArrayTags[mapTag] = typedArrayTags[numberTag] =\ntypedArrayTags[objectTag] = typedArrayTags[regexpTag] =\ntypedArrayTags[setTag] = typedArrayTags[stringTag] =\ntypedArrayTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.isTypedArray` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n */\nfunction baseIsTypedArray(value) {\n return isObjectLike(value) &&\n isLength(value.length) && !!typedArrayTags[baseGetTag(value)];\n}\n\n/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\n/** Detect free variable `exports`. */\nvar freeExports$1 = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule$1 = freeExports$1 && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports$1 = freeModule$1 && freeModule$1.exports === freeExports$1;\n\n/** Detect free variable `process` from Node.js. */\nvar freeProcess = moduleExports$1 && freeGlobal.process;\n\n/** Used to access faster Node.js helpers. */\nvar nodeUtil = (function() {\n try {\n // Use `util.types` for Node.js 10+.\n var types = freeModule$1 && freeModule$1.require && freeModule$1.require('util').types;\n\n if (types) {\n return types;\n }\n\n // Legacy `process.binding('util')` for Node.js < 10.\n return freeProcess && freeProcess.binding && freeProcess.binding('util');\n } catch (e) {}\n}());\n\n/* Node.js helper references. */\nvar nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;\n\n/**\n * Checks if `value` is classified as a typed array.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n * @example\n *\n * _.isTypedArray(new Uint8Array);\n * // => true\n *\n * _.isTypedArray([]);\n * // => false\n */\nvar isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;\n\n/** Used for built-in method references. */\nvar objectProto$2 = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty$1 = objectProto$2.hasOwnProperty;\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n var isArr = isArray(value),\n isArg = !isArr && isArguments(value),\n isBuff = !isArr && !isArg && isBuffer(value),\n isType = !isArr && !isArg && !isBuff && isTypedArray(value),\n skipIndexes = isArr || isArg || isBuff || isType,\n result = skipIndexes ? baseTimes(value.length, String) : [],\n length = result.length;\n\n for (var key in value) {\n if ((inherited || hasOwnProperty$1.call(value, key)) &&\n !(skipIndexes && (\n // Safari 9 has enumerable `arguments.length` in strict mode.\n key == 'length' ||\n // Node.js 0.10 has enumerable non-index properties on buffers.\n (isBuff && (key == 'offset' || key == 'parent')) ||\n // PhantomJS 2 has enumerable non-index properties on typed arrays.\n (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||\n // Skip index properties.\n isIndex(key, length)\n ))) {\n result.push(key);\n }\n }\n return result;\n}\n\n/** Used for built-in method references. */\nvar objectProto$5 = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto$5;\n\n return value === proto;\n}\n\n/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeKeys = overArg(Object.keys, Object);\n\n/** Used for built-in method references. */\nvar objectProto$4 = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty$3 = objectProto$4.hasOwnProperty;\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n if (!isPrototype(object)) {\n return nativeKeys(object);\n }\n var result = [];\n for (var key in Object(object)) {\n if (hasOwnProperty$3.call(object, key) && key != 'constructor') {\n result.push(key);\n }\n }\n return result;\n}\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\nfunction createArrayIterator(coll) {\n var i = -1;\n var len = coll.length;\n return function next() {\n return ++i < len ? {value: coll[i], key: i} : null;\n }\n}\n\nfunction createES2015Iterator(iterator) {\n var i = -1;\n return function next() {\n var item = iterator.next();\n if (item.done)\n return null;\n i++;\n return {value: item.value, key: i};\n }\n}\n\nfunction createObjectIterator(obj) {\n var okeys = keys(obj);\n var i = -1;\n var len = okeys.length;\n return function next() {\n var key = okeys[++i];\n return i < len ? {value: obj[key], key: key} : null;\n };\n}\n\nfunction iterator(coll) {\n if (isArrayLike(coll)) {\n return createArrayIterator(coll);\n }\n\n var iterator = getIterator(coll);\n return iterator ? createES2015Iterator(iterator) : createObjectIterator(coll);\n}\n\nfunction onlyOnce(fn) {\n return function() {\n if (fn === null) throw new Error(\"Callback was already called.\");\n var callFn = fn;\n fn = null;\n callFn.apply(this, arguments);\n };\n}\n\nfunction _eachOfLimit(limit) {\n return function (obj, iteratee, callback) {\n callback = once(callback || noop);\n if (limit <= 0 || !obj) {\n return callback(null);\n }\n var nextElem = iterator(obj);\n var done = false;\n var running = 0;\n var looping = false;\n\n function iterateeCallback(err, value) {\n running -= 1;\n if (err) {\n done = true;\n callback(err);\n }\n else if (value === breakLoop || (done && running <= 0)) {\n done = true;\n return callback(null);\n }\n else if (!looping) {\n replenish();\n }\n }\n\n function replenish () {\n looping = true;\n while (running < limit && !done) {\n var elem = nextElem();\n if (elem === null) {\n done = true;\n if (running <= 0) {\n callback(null);\n }\n return;\n }\n running += 1;\n iteratee(elem.value, elem.key, onlyOnce(iterateeCallback));\n }\n looping = false;\n }\n\n replenish();\n };\n}\n\n/**\n * The same as [`eachOf`]{@link module:Collections.eachOf} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name eachOfLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.eachOf]{@link module:Collections.eachOf}\n * @alias forEachOfLimit\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each\n * item in `coll`. The `key` is the item's key, or index in the case of an\n * array.\n * Invoked with (item, key, callback).\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n */\nfunction eachOfLimit(coll, limit, iteratee, callback) {\n _eachOfLimit(limit)(coll, wrapAsync(iteratee), callback);\n}\n\nfunction doLimit(fn, limit) {\n return function (iterable, iteratee, callback) {\n return fn(iterable, limit, iteratee, callback);\n };\n}\n\n// eachOf implementation optimized for array-likes\nfunction eachOfArrayLike(coll, iteratee, callback) {\n callback = once(callback || noop);\n var index = 0,\n completed = 0,\n length = coll.length;\n if (length === 0) {\n callback(null);\n }\n\n function iteratorCallback(err, value) {\n if (err) {\n callback(err);\n } else if ((++completed === length) || value === breakLoop) {\n callback(null);\n }\n }\n\n for (; index < length; index++) {\n iteratee(coll[index], index, onlyOnce(iteratorCallback));\n }\n}\n\n// a generic version of eachOf which can handle array, object, and iterator cases.\nvar eachOfGeneric = doLimit(eachOfLimit, Infinity);\n\n/**\n * Like [`each`]{@link module:Collections.each}, except that it passes the key (or index) as the second argument\n * to the iteratee.\n *\n * @name eachOf\n * @static\n * @memberOf module:Collections\n * @method\n * @alias forEachOf\n * @category Collection\n * @see [async.each]{@link module:Collections.each}\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each\n * item in `coll`.\n * The `key` is the item's key, or index in the case of an array.\n * Invoked with (item, key, callback).\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n * @example\n *\n * var obj = {dev: \"/dev.json\", test: \"/test.json\", prod: \"/prod.json\"};\n * var configs = {};\n *\n * async.forEachOf(obj, function (value, key, callback) {\n * fs.readFile(__dirname + value, \"utf8\", function (err, data) {\n * if (err) return callback(err);\n * try {\n * configs[key] = JSON.parse(data);\n * } catch (e) {\n * return callback(e);\n * }\n * callback();\n * });\n * }, function (err) {\n * if (err) console.error(err.message);\n * // configs is now a map of JSON data\n * doSomethingWith(configs);\n * });\n */\nvar eachOf = function(coll, iteratee, callback) {\n var eachOfImplementation = isArrayLike(coll) ? eachOfArrayLike : eachOfGeneric;\n eachOfImplementation(coll, wrapAsync(iteratee), callback);\n};\n\nfunction doParallel(fn) {\n return function (obj, iteratee, callback) {\n return fn(eachOf, obj, wrapAsync(iteratee), callback);\n };\n}\n\nfunction _asyncMap(eachfn, arr, iteratee, callback) {\n callback = callback || noop;\n arr = arr || [];\n var results = [];\n var counter = 0;\n var _iteratee = wrapAsync(iteratee);\n\n eachfn(arr, function (value, _, callback) {\n var index = counter++;\n _iteratee(value, function (err, v) {\n results[index] = v;\n callback(err);\n });\n }, function (err) {\n callback(err, results);\n });\n}\n\n/**\n * Produces a new collection of values by mapping each value in `coll` through\n * the `iteratee` function. The `iteratee` is called with an item from `coll`\n * and a callback for when it has finished processing. Each of these callback\n * takes 2 arguments: an `error`, and the transformed item from `coll`. If\n * `iteratee` passes an error to its callback, the main `callback` (for the\n * `map` function) is immediately called with the error.\n *\n * Note, that since this function applies the `iteratee` to each item in\n * parallel, there is no guarantee that the `iteratee` functions will complete\n * in order. However, the results array will be in the same order as the\n * original `coll`.\n *\n * If `map` is passed an Object, the results will be an Array. The results\n * will roughly be in the order of the original Objects' keys (but this can\n * vary across JavaScript engines).\n *\n * @name map\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with the transformed item.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Results is an Array of the\n * transformed items from the `coll`. Invoked with (err, results).\n * @example\n *\n * async.map(['file1','file2','file3'], fs.stat, function(err, results) {\n * // results is now an array of stats for each file\n * });\n */\nvar map = doParallel(_asyncMap);\n\n/**\n * Applies the provided arguments to each function in the array, calling\n * `callback` after all functions have completed. If you only provide the first\n * argument, `fns`, then it will return a function which lets you pass in the\n * arguments as if it were a single function call. If more arguments are\n * provided, `callback` is required while `args` is still optional.\n *\n * @name applyEach\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array|Iterable|Object} fns - A collection of {@link AsyncFunction}s\n * to all call with the same arguments\n * @param {...*} [args] - any number of separate arguments to pass to the\n * function.\n * @param {Function} [callback] - the final argument should be the callback,\n * called when all functions have completed processing.\n * @returns {Function} - If only the first argument, `fns`, is provided, it will\n * return a function which lets you pass in the arguments as if it were a single\n * function call. The signature is `(..args, callback)`. If invoked with any\n * arguments, `callback` is required.\n * @example\n *\n * async.applyEach([enableSearch, updateSchema], 'bucket', callback);\n *\n * // partial application example:\n * async.each(\n * buckets,\n * async.applyEach([enableSearch, updateSchema]),\n * callback\n * );\n */\nvar applyEach = applyEach$1(map);\n\nfunction doParallelLimit(fn) {\n return function (obj, limit, iteratee, callback) {\n return fn(_eachOfLimit(limit), obj, wrapAsync(iteratee), callback);\n };\n}\n\n/**\n * The same as [`map`]{@link module:Collections.map} but runs a maximum of `limit` async operations at a time.\n *\n * @name mapLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.map]{@link module:Collections.map}\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with the transformed item.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Results is an array of the\n * transformed items from the `coll`. Invoked with (err, results).\n */\nvar mapLimit = doParallelLimit(_asyncMap);\n\n/**\n * The same as [`map`]{@link module:Collections.map} but runs only a single async operation at a time.\n *\n * @name mapSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.map]{@link module:Collections.map}\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with the transformed item.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Results is an array of the\n * transformed items from the `coll`. Invoked with (err, results).\n */\nvar mapSeries = doLimit(mapLimit, 1);\n\n/**\n * The same as [`applyEach`]{@link module:ControlFlow.applyEach} but runs only a single async operation at a time.\n *\n * @name applyEachSeries\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.applyEach]{@link module:ControlFlow.applyEach}\n * @category Control Flow\n * @param {Array|Iterable|Object} fns - A collection of {@link AsyncFunction}s to all\n * call with the same arguments\n * @param {...*} [args] - any number of separate arguments to pass to the\n * function.\n * @param {Function} [callback] - the final argument should be the callback,\n * called when all functions have completed processing.\n * @returns {Function} - If only the first argument is provided, it will return\n * a function which lets you pass in the arguments as if it were a single\n * function call.\n */\nvar applyEachSeries = applyEach$1(mapSeries);\n\n/**\n * A specialized version of `_.forEach` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns `array`.\n */\nfunction arrayEach(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (iteratee(array[index], index, array) === false) {\n break;\n }\n }\n return array;\n}\n\n/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\n/**\n * The base implementation of `baseForOwn` which iterates over `object`\n * properties returned by `keysFunc` and invokes `iteratee` for each property.\n * Iteratee functions may exit iteration early by explicitly returning `false`.\n *\n * @private\n * @param {Object} object The object to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @returns {Object} Returns `object`.\n */\nvar baseFor = createBaseFor();\n\n/**\n * The base implementation of `_.forOwn` without support for iteratee shorthands.\n *\n * @private\n * @param {Object} object The object to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Object} Returns `object`.\n */\nfunction baseForOwn(object, iteratee) {\n return object && baseFor(object, iteratee, keys);\n}\n\n/**\n * The base implementation of `_.findIndex` and `_.findLastIndex` without\n * support for iteratee shorthands.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {Function} predicate The function invoked per iteration.\n * @param {number} fromIndex The index to search from.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseFindIndex(array, predicate, fromIndex, fromRight) {\n var length = array.length,\n index = fromIndex + (fromRight ? 1 : -1);\n\n while ((fromRight ? index-- : ++index < length)) {\n if (predicate(array[index], index, array)) {\n return index;\n }\n }\n return -1;\n}\n\n/**\n * The base implementation of `_.isNaN` without support for number objects.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.\n */\nfunction baseIsNaN(value) {\n return value !== value;\n}\n\n/**\n * A specialized version of `_.indexOf` which performs strict equality\n * comparisons of values, i.e. `===`.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction strictIndexOf(array, value, fromIndex) {\n var index = fromIndex - 1,\n length = array.length;\n\n while (++index < length) {\n if (array[index] === value) {\n return index;\n }\n }\n return -1;\n}\n\n/**\n * The base implementation of `_.indexOf` without `fromIndex` bounds checks.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} value The value to search for.\n * @param {number} fromIndex The index to search from.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction baseIndexOf(array, value, fromIndex) {\n return value === value\n ? strictIndexOf(array, value, fromIndex)\n : baseFindIndex(array, baseIsNaN, fromIndex);\n}\n\n/**\n * Determines the best order for running the {@link AsyncFunction}s in `tasks`, based on\n * their requirements. Each function can optionally depend on other functions\n * being completed first, and each function is run as soon as its requirements\n * are satisfied.\n *\n * If any of the {@link AsyncFunction}s pass an error to their callback, the `auto` sequence\n * will stop. Further tasks will not execute (so any other functions depending\n * on it will not run), and the main `callback` is immediately called with the\n * error.\n *\n * {@link AsyncFunction}s also receive an object containing the results of functions which\n * have completed so far as the first argument, if they have dependencies. If a\n * task function has no dependencies, it will only be passed a callback.\n *\n * @name auto\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Object} tasks - An object. Each of its properties is either a\n * function or an array of requirements, with the {@link AsyncFunction} itself the last item\n * in the array. The object's key of a property serves as the name of the task\n * defined by that property, i.e. can be used when specifying requirements for\n * other tasks. The function receives one or two arguments:\n * * a `results` object, containing the results of the previously executed\n * functions, only passed if the task has any dependencies,\n * * a `callback(err, result)` function, which must be called when finished,\n * passing an `error` (which can be `null`) and the result of the function's\n * execution.\n * @param {number} [concurrency=Infinity] - An optional `integer` for\n * determining the maximum number of tasks that can be run in parallel. By\n * default, as many as possible.\n * @param {Function} [callback] - An optional callback which is called when all\n * the tasks have been completed. It receives the `err` argument if any `tasks`\n * pass an error to their callback. Results are always returned; however, if an\n * error occurs, no further `tasks` will be performed, and the results object\n * will only contain partial results. Invoked with (err, results).\n * @returns undefined\n * @example\n *\n * async.auto({\n * // this function will just be passed a callback\n * readData: async.apply(fs.readFile, 'data.txt', 'utf-8'),\n * showData: ['readData', function(results, cb) {\n * // results.readData is the file's contents\n * // ...\n * }]\n * }, callback);\n *\n * async.auto({\n * get_data: function(callback) {\n * console.log('in get_data');\n * // async code to get some data\n * callback(null, 'data', 'converted to array');\n * },\n * make_folder: function(callback) {\n * console.log('in make_folder');\n * // async code to create a directory to store a file in\n * // this is run at the same time as getting the data\n * callback(null, 'folder');\n * },\n * write_file: ['get_data', 'make_folder', function(results, callback) {\n * console.log('in write_file', JSON.stringify(results));\n * // once there is some data and the directory exists,\n * // write the data to a file in the directory\n * callback(null, 'filename');\n * }],\n * email_link: ['write_file', function(results, callback) {\n * console.log('in email_link', JSON.stringify(results));\n * // once the file is written let's email a link to it...\n * // results.write_file contains the filename returned by write_file.\n * callback(null, {'file':results.write_file, 'email':'user@example.com'});\n * }]\n * }, function(err, results) {\n * console.log('err = ', err);\n * console.log('results = ', results);\n * });\n */\nvar auto = function (tasks, concurrency, callback) {\n if (typeof concurrency === 'function') {\n // concurrency is optional, shift the args.\n callback = concurrency;\n concurrency = null;\n }\n callback = once(callback || noop);\n var keys$$1 = keys(tasks);\n var numTasks = keys$$1.length;\n if (!numTasks) {\n return callback(null);\n }\n if (!concurrency) {\n concurrency = numTasks;\n }\n\n var results = {};\n var runningTasks = 0;\n var hasError = false;\n\n var listeners = Object.create(null);\n\n var readyTasks = [];\n\n // for cycle detection:\n var readyToCheck = []; // tasks that have been identified as reachable\n // without the possibility of returning to an ancestor task\n var uncheckedDependencies = {};\n\n baseForOwn(tasks, function (task, key) {\n if (!isArray(task)) {\n // no dependencies\n enqueueTask(key, [task]);\n readyToCheck.push(key);\n return;\n }\n\n var dependencies = task.slice(0, task.length - 1);\n var remainingDependencies = dependencies.length;\n if (remainingDependencies === 0) {\n enqueueTask(key, task);\n readyToCheck.push(key);\n return;\n }\n uncheckedDependencies[key] = remainingDependencies;\n\n arrayEach(dependencies, function (dependencyName) {\n if (!tasks[dependencyName]) {\n throw new Error('async.auto task `' + key +\n '` has a non-existent dependency `' +\n dependencyName + '` in ' +\n dependencies.join(', '));\n }\n addListener(dependencyName, function () {\n remainingDependencies--;\n if (remainingDependencies === 0) {\n enqueueTask(key, task);\n }\n });\n });\n });\n\n checkForDeadlocks();\n processQueue();\n\n function enqueueTask(key, task) {\n readyTasks.push(function () {\n runTask(key, task);\n });\n }\n\n function processQueue() {\n if (readyTasks.length === 0 && runningTasks === 0) {\n return callback(null, results);\n }\n while(readyTasks.length && runningTasks < concurrency) {\n var run = readyTasks.shift();\n run();\n }\n\n }\n\n function addListener(taskName, fn) {\n var taskListeners = listeners[taskName];\n if (!taskListeners) {\n taskListeners = listeners[taskName] = [];\n }\n\n taskListeners.push(fn);\n }\n\n function taskComplete(taskName) {\n var taskListeners = listeners[taskName] || [];\n arrayEach(taskListeners, function (fn) {\n fn();\n });\n processQueue();\n }\n\n\n function runTask(key, task) {\n if (hasError) return;\n\n var taskCallback = onlyOnce(function(err, result) {\n runningTasks--;\n if (arguments.length > 2) {\n result = slice(arguments, 1);\n }\n if (err) {\n var safeResults = {};\n baseForOwn(results, function(val, rkey) {\n safeResults[rkey] = val;\n });\n safeResults[key] = result;\n hasError = true;\n listeners = Object.create(null);\n\n callback(err, safeResults);\n } else {\n results[key] = result;\n taskComplete(key);\n }\n });\n\n runningTasks++;\n var taskFn = wrapAsync(task[task.length - 1]);\n if (task.length > 1) {\n taskFn(results, taskCallback);\n } else {\n taskFn(taskCallback);\n }\n }\n\n function checkForDeadlocks() {\n // Kahn's algorithm\n // https://en.wikipedia.org/wiki/Topological_sorting#Kahn.27s_algorithm\n // http://connalle.blogspot.com/2013/10/topological-sortingkahn-algorithm.html\n var currentTask;\n var counter = 0;\n while (readyToCheck.length) {\n currentTask = readyToCheck.pop();\n counter++;\n arrayEach(getDependents(currentTask), function (dependent) {\n if (--uncheckedDependencies[dependent] === 0) {\n readyToCheck.push(dependent);\n }\n });\n }\n\n if (counter !== numTasks) {\n throw new Error(\n 'async.auto cannot execute tasks due to a recursive dependency'\n );\n }\n }\n\n function getDependents(taskName) {\n var result = [];\n baseForOwn(tasks, function (task, key) {\n if (isArray(task) && baseIndexOf(task, taskName, 0) >= 0) {\n result.push(key);\n }\n });\n return result;\n }\n};\n\n/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol$1 ? Symbol$1.prototype : undefined;\nvar symbolToString = symbolProto ? symbolProto.toString : undefined;\n\n/**\n * The base implementation of `_.toString` which doesn't convert nullish\n * values to empty strings.\n *\n * @private\n * @param {*} value The value to process.\n * @returns {string} Returns the string.\n */\nfunction baseToString(value) {\n // Exit early for strings to avoid a performance hit in some environments.\n if (typeof value == 'string') {\n return value;\n }\n if (isArray(value)) {\n // Recursively convert values (susceptible to call stack limits).\n return arrayMap(value, baseToString) + '';\n }\n if (isSymbol(value)) {\n return symbolToString ? symbolToString.call(value) : '';\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\n/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\n/**\n * Casts `array` to a slice if it's needed.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {number} start The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the cast slice.\n */\nfunction castSlice(array, start, end) {\n var length = array.length;\n end = end === undefined ? length : end;\n return (!start && end >= length) ? array : baseSlice(array, start, end);\n}\n\n/**\n * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol\n * that is not found in the character symbols.\n *\n * @private\n * @param {Array} strSymbols The string symbols to inspect.\n * @param {Array} chrSymbols The character symbols to find.\n * @returns {number} Returns the index of the last unmatched string symbol.\n */\nfunction charsEndIndex(strSymbols, chrSymbols) {\n var index = strSymbols.length;\n\n while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}\n return index;\n}\n\n/**\n * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol\n * that is not found in the character symbols.\n *\n * @private\n * @param {Array} strSymbols The string symbols to inspect.\n * @param {Array} chrSymbols The character symbols to find.\n * @returns {number} Returns the index of the first unmatched string symbol.\n */\nfunction charsStartIndex(strSymbols, chrSymbols) {\n var index = -1,\n length = strSymbols.length;\n\n while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}\n return index;\n}\n\n/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\n/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff';\nvar rsComboMarksRange = '\\\\u0300-\\\\u036f';\nvar reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f';\nvar rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff';\nvar rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange;\nvar rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\n/** Used to compose unicode character classes. */\nvar rsAstralRange$1 = '\\\\ud800-\\\\udfff';\nvar rsComboMarksRange$1 = '\\\\u0300-\\\\u036f';\nvar reComboHalfMarksRange$1 = '\\\\ufe20-\\\\ufe2f';\nvar rsComboSymbolsRange$1 = '\\\\u20d0-\\\\u20ff';\nvar rsComboRange$1 = rsComboMarksRange$1 + reComboHalfMarksRange$1 + rsComboSymbolsRange$1;\nvar rsVarRange$1 = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange$1 + ']';\nvar rsCombo = '[' + rsComboRange$1 + ']';\nvar rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]';\nvar rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')';\nvar rsNonAstral = '[^' + rsAstralRange$1 + ']';\nvar rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}';\nvar rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]';\nvar rsZWJ$1 = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?';\nvar rsOptVar = '[' + rsVarRange$1 + ']?';\nvar rsOptJoin = '(?:' + rsZWJ$1 + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*';\nvar rsSeq = rsOptVar + reOptMod + rsOptJoin;\nvar rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\n/**\n * Converts `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction stringToArray(string) {\n return hasUnicode(string)\n ? unicodeToArray(string)\n : asciiToArray(string);\n}\n\n/**\n * Converts `value` to a string. An empty string is returned for `null`\n * and `undefined` values. The sign of `-0` is preserved.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.toString(null);\n * // => ''\n *\n * _.toString(-0);\n * // => '-0'\n *\n * _.toString([1, 2, 3]);\n * // => '1,2,3'\n */\nfunction toString(value) {\n return value == null ? '' : baseToString(value);\n}\n\n/** Used to match leading and trailing whitespace. */\nvar reTrim = /^\\s+|\\s+$/g;\n\n/**\n * Removes leading and trailing whitespace or specified characters from `string`.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to trim.\n * @param {string} [chars=whitespace] The characters to trim.\n * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.\n * @returns {string} Returns the trimmed string.\n * @example\n *\n * _.trim(' abc ');\n * // => 'abc'\n *\n * _.trim('-_-abc-_-', '_-');\n * // => 'abc'\n *\n * _.map([' foo ', ' bar '], _.trim);\n * // => ['foo', 'bar']\n */\nfunction trim(string, chars, guard) {\n string = toString(string);\n if (string && (guard || chars === undefined)) {\n return string.replace(reTrim, '');\n }\n if (!string || !(chars = baseToString(chars))) {\n return string;\n }\n var strSymbols = stringToArray(string),\n chrSymbols = stringToArray(chars),\n start = charsStartIndex(strSymbols, chrSymbols),\n end = charsEndIndex(strSymbols, chrSymbols) + 1;\n\n return castSlice(strSymbols, start, end).join('');\n}\n\nvar FN_ARGS = /^(?:async\\s+)?(function)?\\s*[^\\(]*\\(\\s*([^\\)]*)\\)/m;\nvar FN_ARG_SPLIT = /,/;\nvar FN_ARG = /(=.+)?(\\s*)$/;\nvar STRIP_COMMENTS = /((\\/\\/.*$)|(\\/\\*[\\s\\S]*?\\*\\/))/mg;\n\nfunction parseParams(func) {\n func = func.toString().replace(STRIP_COMMENTS, '');\n func = func.match(FN_ARGS)[2].replace(' ', '');\n func = func ? func.split(FN_ARG_SPLIT) : [];\n func = func.map(function (arg){\n return trim(arg.replace(FN_ARG, ''));\n });\n return func;\n}\n\n/**\n * A dependency-injected version of the [async.auto]{@link module:ControlFlow.auto} function. Dependent\n * tasks are specified as parameters to the function, after the usual callback\n * parameter, with the parameter names matching the names of the tasks it\n * depends on. This can provide even more readable task graphs which can be\n * easier to maintain.\n *\n * If a final callback is specified, the task results are similarly injected,\n * specified as named parameters after the initial error parameter.\n *\n * The autoInject function is purely syntactic sugar and its semantics are\n * otherwise equivalent to [async.auto]{@link module:ControlFlow.auto}.\n *\n * @name autoInject\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.auto]{@link module:ControlFlow.auto}\n * @category Control Flow\n * @param {Object} tasks - An object, each of whose properties is an {@link AsyncFunction} of\n * the form 'func([dependencies...], callback). The object's key of a property\n * serves as the name of the task defined by that property, i.e. can be used\n * when specifying requirements for other tasks.\n * * The `callback` parameter is a `callback(err, result)` which must be called\n * when finished, passing an `error` (which can be `null`) and the result of\n * the function's execution. The remaining parameters name other tasks on\n * which the task is dependent, and the results from those tasks are the\n * arguments of those parameters.\n * @param {Function} [callback] - An optional callback which is called when all\n * the tasks have been completed. It receives the `err` argument if any `tasks`\n * pass an error to their callback, and a `results` object with any completed\n * task results, similar to `auto`.\n * @example\n *\n * // The example from `auto` can be rewritten as follows:\n * async.autoInject({\n * get_data: function(callback) {\n * // async code to get some data\n * callback(null, 'data', 'converted to array');\n * },\n * make_folder: function(callback) {\n * // async code to create a directory to store a file in\n * // this is run at the same time as getting the data\n * callback(null, 'folder');\n * },\n * write_file: function(get_data, make_folder, callback) {\n * // once there is some data and the directory exists,\n * // write the data to a file in the directory\n * callback(null, 'filename');\n * },\n * email_link: function(write_file, callback) {\n * // once the file is written let's email a link to it...\n * // write_file contains the filename returned by write_file.\n * callback(null, {'file':write_file, 'email':'user@example.com'});\n * }\n * }, function(err, results) {\n * console.log('err = ', err);\n * console.log('email_link = ', results.email_link);\n * });\n *\n * // If you are using a JS minifier that mangles parameter names, `autoInject`\n * // will not work with plain functions, since the parameter names will be\n * // collapsed to a single letter identifier. To work around this, you can\n * // explicitly specify the names of the parameters your task function needs\n * // in an array, similar to Angular.js dependency injection.\n *\n * // This still has an advantage over plain `auto`, since the results a task\n * // depends on are still spread into arguments.\n * async.autoInject({\n * //...\n * write_file: ['get_data', 'make_folder', function(get_data, make_folder, callback) {\n * callback(null, 'filename');\n * }],\n * email_link: ['write_file', function(write_file, callback) {\n * callback(null, {'file':write_file, 'email':'user@example.com'});\n * }]\n * //...\n * }, function(err, results) {\n * console.log('err = ', err);\n * console.log('email_link = ', results.email_link);\n * });\n */\nfunction autoInject(tasks, callback) {\n var newTasks = {};\n\n baseForOwn(tasks, function (taskFn, key) {\n var params;\n var fnIsAsync = isAsync(taskFn);\n var hasNoDeps =\n (!fnIsAsync && taskFn.length === 1) ||\n (fnIsAsync && taskFn.length === 0);\n\n if (isArray(taskFn)) {\n params = taskFn.slice(0, -1);\n taskFn = taskFn[taskFn.length - 1];\n\n newTasks[key] = params.concat(params.length > 0 ? newTask : taskFn);\n } else if (hasNoDeps) {\n // no dependencies, use the function as-is\n newTasks[key] = taskFn;\n } else {\n params = parseParams(taskFn);\n if (taskFn.length === 0 && !fnIsAsync && params.length === 0) {\n throw new Error(\"autoInject task functions require explicit parameters.\");\n }\n\n // remove callback param\n if (!fnIsAsync) params.pop();\n\n newTasks[key] = params.concat(newTask);\n }\n\n function newTask(results, taskCb) {\n var newArgs = arrayMap(params, function (name) {\n return results[name];\n });\n newArgs.push(taskCb);\n wrapAsync(taskFn).apply(null, newArgs);\n }\n });\n\n auto(newTasks, callback);\n}\n\n// Simple doubly linked list (https://en.wikipedia.org/wiki/Doubly_linked_list) implementation\n// used for queues. This implementation assumes that the node provided by the user can be modified\n// to adjust the next and last properties. We implement only the minimal functionality\n// for queue support.\nfunction DLL() {\n this.head = this.tail = null;\n this.length = 0;\n}\n\nfunction setInitial(dll, node) {\n dll.length = 1;\n dll.head = dll.tail = node;\n}\n\nDLL.prototype.removeLink = function(node) {\n if (node.prev) node.prev.next = node.next;\n else this.head = node.next;\n if (node.next) node.next.prev = node.prev;\n else this.tail = node.prev;\n\n node.prev = node.next = null;\n this.length -= 1;\n return node;\n};\n\nDLL.prototype.empty = function () {\n while(this.head) this.shift();\n return this;\n};\n\nDLL.prototype.insertAfter = function(node, newNode) {\n newNode.prev = node;\n newNode.next = node.next;\n if (node.next) node.next.prev = newNode;\n else this.tail = newNode;\n node.next = newNode;\n this.length += 1;\n};\n\nDLL.prototype.insertBefore = function(node, newNode) {\n newNode.prev = node.prev;\n newNode.next = node;\n if (node.prev) node.prev.next = newNode;\n else this.head = newNode;\n node.prev = newNode;\n this.length += 1;\n};\n\nDLL.prototype.unshift = function(node) {\n if (this.head) this.insertBefore(this.head, node);\n else setInitial(this, node);\n};\n\nDLL.prototype.push = function(node) {\n if (this.tail) this.insertAfter(this.tail, node);\n else setInitial(this, node);\n};\n\nDLL.prototype.shift = function() {\n return this.head && this.removeLink(this.head);\n};\n\nDLL.prototype.pop = function() {\n return this.tail && this.removeLink(this.tail);\n};\n\nDLL.prototype.toArray = function () {\n var arr = Array(this.length);\n var curr = this.head;\n for(var idx = 0; idx < this.length; idx++) {\n arr[idx] = curr.data;\n curr = curr.next;\n }\n return arr;\n};\n\nDLL.prototype.remove = function (testFn) {\n var curr = this.head;\n while(!!curr) {\n var next = curr.next;\n if (testFn(curr)) {\n this.removeLink(curr);\n }\n curr = next;\n }\n return this;\n};\n\nfunction queue(worker, concurrency, payload) {\n if (concurrency == null) {\n concurrency = 1;\n }\n else if(concurrency === 0) {\n throw new Error('Concurrency must not be zero');\n }\n\n var _worker = wrapAsync(worker);\n var numRunning = 0;\n var workersList = [];\n\n var processingScheduled = false;\n function _insert(data, insertAtFront, callback) {\n if (callback != null && typeof callback !== 'function') {\n throw new Error('task callback must be a function');\n }\n q.started = true;\n if (!isArray(data)) {\n data = [data];\n }\n if (data.length === 0 && q.idle()) {\n // call drain immediately if there are no tasks\n return setImmediate$1(function() {\n q.drain();\n });\n }\n\n for (var i = 0, l = data.length; i < l; i++) {\n var item = {\n data: data[i],\n callback: callback || noop\n };\n\n if (insertAtFront) {\n q._tasks.unshift(item);\n } else {\n q._tasks.push(item);\n }\n }\n\n if (!processingScheduled) {\n processingScheduled = true;\n setImmediate$1(function() {\n processingScheduled = false;\n q.process();\n });\n }\n }\n\n function _next(tasks) {\n return function(err){\n numRunning -= 1;\n\n for (var i = 0, l = tasks.length; i < l; i++) {\n var task = tasks[i];\n\n var index = baseIndexOf(workersList, task, 0);\n if (index === 0) {\n workersList.shift();\n } else if (index > 0) {\n workersList.splice(index, 1);\n }\n\n task.callback.apply(task, arguments);\n\n if (err != null) {\n q.error(err, task.data);\n }\n }\n\n if (numRunning <= (q.concurrency - q.buffer) ) {\n q.unsaturated();\n }\n\n if (q.idle()) {\n q.drain();\n }\n q.process();\n };\n }\n\n var isProcessing = false;\n var q = {\n _tasks: new DLL(),\n concurrency: concurrency,\n payload: payload,\n saturated: noop,\n unsaturated:noop,\n buffer: concurrency / 4,\n empty: noop,\n drain: noop,\n error: noop,\n started: false,\n paused: false,\n push: function (data, callback) {\n _insert(data, false, callback);\n },\n kill: function () {\n q.drain = noop;\n q._tasks.empty();\n },\n unshift: function (data, callback) {\n _insert(data, true, callback);\n },\n remove: function (testFn) {\n q._tasks.remove(testFn);\n },\n process: function () {\n // Avoid trying to start too many processing operations. This can occur\n // when callbacks resolve synchronously (#1267).\n if (isProcessing) {\n return;\n }\n isProcessing = true;\n while(!q.paused && numRunning < q.concurrency && q._tasks.length){\n var tasks = [], data = [];\n var l = q._tasks.length;\n if (q.payload) l = Math.min(l, q.payload);\n for (var i = 0; i < l; i++) {\n var node = q._tasks.shift();\n tasks.push(node);\n workersList.push(node);\n data.push(node.data);\n }\n\n numRunning += 1;\n\n if (q._tasks.length === 0) {\n q.empty();\n }\n\n if (numRunning === q.concurrency) {\n q.saturated();\n }\n\n var cb = onlyOnce(_next(tasks));\n _worker(data, cb);\n }\n isProcessing = false;\n },\n length: function () {\n return q._tasks.length;\n },\n running: function () {\n return numRunning;\n },\n workersList: function () {\n return workersList;\n },\n idle: function() {\n return q._tasks.length + numRunning === 0;\n },\n pause: function () {\n q.paused = true;\n },\n resume: function () {\n if (q.paused === false) { return; }\n q.paused = false;\n setImmediate$1(q.process);\n }\n };\n return q;\n}\n\n/**\n * A cargo of tasks for the worker function to complete. Cargo inherits all of\n * the same methods and event callbacks as [`queue`]{@link module:ControlFlow.queue}.\n * @typedef {Object} CargoObject\n * @memberOf module:ControlFlow\n * @property {Function} length - A function returning the number of items\n * waiting to be processed. Invoke like `cargo.length()`.\n * @property {number} payload - An `integer` for determining how many tasks\n * should be process per round. This property can be changed after a `cargo` is\n * created to alter the payload on-the-fly.\n * @property {Function} push - Adds `task` to the `queue`. The callback is\n * called once the `worker` has finished processing the task. Instead of a\n * single task, an array of `tasks` can be submitted. The respective callback is\n * used for every task in the list. Invoke like `cargo.push(task, [callback])`.\n * @property {Function} saturated - A callback that is called when the\n * `queue.length()` hits the concurrency and further tasks will be queued.\n * @property {Function} empty - A callback that is called when the last item\n * from the `queue` is given to a `worker`.\n * @property {Function} drain - A callback that is called when the last item\n * from the `queue` has returned from the `worker`.\n * @property {Function} idle - a function returning false if there are items\n * waiting or being processed, or true if not. Invoke like `cargo.idle()`.\n * @property {Function} pause - a function that pauses the processing of tasks\n * until `resume()` is called. Invoke like `cargo.pause()`.\n * @property {Function} resume - a function that resumes the processing of\n * queued tasks when the queue is paused. Invoke like `cargo.resume()`.\n * @property {Function} kill - a function that removes the `drain` callback and\n * empties remaining tasks from the queue forcing it to go idle. Invoke like `cargo.kill()`.\n */\n\n/**\n * Creates a `cargo` object with the specified payload. Tasks added to the\n * cargo will be processed altogether (up to the `payload` limit). If the\n * `worker` is in progress, the task is queued until it becomes available. Once\n * the `worker` has completed some tasks, each callback of those tasks is\n * called. Check out [these](https://camo.githubusercontent.com/6bbd36f4cf5b35a0f11a96dcd2e97711ffc2fb37/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130382f62626330636662302d356632392d313165322d393734662d3333393763363464633835382e676966) [animations](https://camo.githubusercontent.com/f4810e00e1c5f5f8addbe3e9f49064fd5d102699/68747470733a2f2f662e636c6f75642e6769746875622e636f6d2f6173736574732f313637363837312f36383130312f38346339323036362d356632392d313165322d383134662d3964336430323431336266642e676966)\n * for how `cargo` and `queue` work.\n *\n * While [`queue`]{@link module:ControlFlow.queue} passes only one task to one of a group of workers\n * at a time, cargo passes an array of tasks to a single worker, repeating\n * when the worker is finished.\n *\n * @name cargo\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.queue]{@link module:ControlFlow.queue}\n * @category Control Flow\n * @param {AsyncFunction} worker - An asynchronous function for processing an array\n * of queued tasks. Invoked with `(tasks, callback)`.\n * @param {number} [payload=Infinity] - An optional `integer` for determining\n * how many tasks should be processed per round; if omitted, the default is\n * unlimited.\n * @returns {module:ControlFlow.CargoObject} A cargo object to manage the tasks. Callbacks can\n * attached as certain properties to listen for specific events during the\n * lifecycle of the cargo and inner queue.\n * @example\n *\n * // create a cargo object with payload 2\n * var cargo = async.cargo(function(tasks, callback) {\n * for (var i=0; i true\n */\nfunction identity(value) {\n return value;\n}\n\nfunction _createTester(check, getResult) {\n return function(eachfn, arr, iteratee, cb) {\n cb = cb || noop;\n var testPassed = false;\n var testResult;\n eachfn(arr, function(value, _, callback) {\n iteratee(value, function(err, result) {\n if (err) {\n callback(err);\n } else if (check(result) && !testResult) {\n testPassed = true;\n testResult = getResult(true, value);\n callback(null, breakLoop);\n } else {\n callback();\n }\n });\n }, function(err) {\n if (err) {\n cb(err);\n } else {\n cb(null, testPassed ? testResult : getResult(false));\n }\n });\n };\n}\n\nfunction _findGetResult(v, x) {\n return x;\n}\n\n/**\n * Returns the first value in `coll` that passes an async truth test. The\n * `iteratee` is applied in parallel, meaning the first iteratee to return\n * `true` will fire the detect `callback` with that result. That means the\n * result might not be the first item in the original `coll` (in terms of order)\n * that passes the test.\n\n * If order within the original `coll` is important, then look at\n * [`detectSeries`]{@link module:Collections.detectSeries}.\n *\n * @name detect\n * @static\n * @memberOf module:Collections\n * @method\n * @alias find\n * @category Collections\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.\n * The iteratee must complete with a boolean value as its result.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the `iteratee` functions have finished.\n * Result will be the first item in the array that passes the truth test\n * (iteratee) or the value `undefined` if none passed. Invoked with\n * (err, result).\n * @example\n *\n * async.detect(['file1','file2','file3'], function(filePath, callback) {\n * fs.access(filePath, function(err) {\n * callback(null, !err)\n * });\n * }, function(err, result) {\n * // result now equals the first file in the list that exists\n * });\n */\nvar detect = doParallel(_createTester(identity, _findGetResult));\n\n/**\n * The same as [`detect`]{@link module:Collections.detect} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name detectLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.detect]{@link module:Collections.detect}\n * @alias findLimit\n * @category Collections\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.\n * The iteratee must complete with a boolean value as its result.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the `iteratee` functions have finished.\n * Result will be the first item in the array that passes the truth test\n * (iteratee) or the value `undefined` if none passed. Invoked with\n * (err, result).\n */\nvar detectLimit = doParallelLimit(_createTester(identity, _findGetResult));\n\n/**\n * The same as [`detect`]{@link module:Collections.detect} but runs only a single async operation at a time.\n *\n * @name detectSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.detect]{@link module:Collections.detect}\n * @alias findSeries\n * @category Collections\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A truth test to apply to each item in `coll`.\n * The iteratee must complete with a boolean value as its result.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the `iteratee` functions have finished.\n * Result will be the first item in the array that passes the truth test\n * (iteratee) or the value `undefined` if none passed. Invoked with\n * (err, result).\n */\nvar detectSeries = doLimit(detectLimit, 1);\n\nfunction consoleFunc(name) {\n return function (fn/*, ...args*/) {\n var args = slice(arguments, 1);\n args.push(function (err/*, ...args*/) {\n var args = slice(arguments, 1);\n if (typeof console === 'object') {\n if (err) {\n if (console.error) {\n console.error(err);\n }\n } else if (console[name]) {\n arrayEach(args, function (x) {\n console[name](x);\n });\n }\n }\n });\n wrapAsync(fn).apply(null, args);\n };\n}\n\n/**\n * Logs the result of an [`async` function]{@link AsyncFunction} to the\n * `console` using `console.dir` to display the properties of the resulting object.\n * Only works in Node.js or in browsers that support `console.dir` and\n * `console.error` (such as FF and Chrome).\n * If multiple arguments are returned from the async function,\n * `console.dir` is called on each argument in order.\n *\n * @name dir\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} function - The function you want to eventually apply\n * all arguments to.\n * @param {...*} arguments... - Any number of arguments to apply to the function.\n * @example\n *\n * // in a module\n * var hello = function(name, callback) {\n * setTimeout(function() {\n * callback(null, {hello: name});\n * }, 1000);\n * };\n *\n * // in the node repl\n * node> async.dir(hello, 'world');\n * {hello: 'world'}\n */\nvar dir = consoleFunc('dir');\n\n/**\n * The post-check version of [`during`]{@link module:ControlFlow.during}. To reflect the difference in\n * the order of operations, the arguments `test` and `fn` are switched.\n *\n * Also a version of [`doWhilst`]{@link module:ControlFlow.doWhilst} with asynchronous `test` function.\n * @name doDuring\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.during]{@link module:ControlFlow.during}\n * @category Control Flow\n * @param {AsyncFunction} fn - An async function which is called each time\n * `test` passes. Invoked with (callback).\n * @param {AsyncFunction} test - asynchronous truth test to perform before each\n * execution of `fn`. Invoked with (...args, callback), where `...args` are the\n * non-error args from the previous callback of `fn`.\n * @param {Function} [callback] - A callback which is called after the test\n * function has failed and repeated execution of `fn` has stopped. `callback`\n * will be passed an error if one occurred, otherwise `null`.\n */\nfunction doDuring(fn, test, callback) {\n callback = onlyOnce(callback || noop);\n var _fn = wrapAsync(fn);\n var _test = wrapAsync(test);\n\n function next(err/*, ...args*/) {\n if (err) return callback(err);\n var args = slice(arguments, 1);\n args.push(check);\n _test.apply(this, args);\n }\n\n function check(err, truth) {\n if (err) return callback(err);\n if (!truth) return callback(null);\n _fn(next);\n }\n\n check(null, true);\n\n}\n\n/**\n * The post-check version of [`whilst`]{@link module:ControlFlow.whilst}. To reflect the difference in\n * the order of operations, the arguments `test` and `iteratee` are switched.\n *\n * `doWhilst` is to `whilst` as `do while` is to `while` in plain JavaScript.\n *\n * @name doWhilst\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.whilst]{@link module:ControlFlow.whilst}\n * @category Control Flow\n * @param {AsyncFunction} iteratee - A function which is called each time `test`\n * passes. Invoked with (callback).\n * @param {Function} test - synchronous truth test to perform after each\n * execution of `iteratee`. Invoked with any non-error callback results of\n * `iteratee`.\n * @param {Function} [callback] - A callback which is called after the test\n * function has failed and repeated execution of `iteratee` has stopped.\n * `callback` will be passed an error and any arguments passed to the final\n * `iteratee`'s callback. Invoked with (err, [results]);\n */\nfunction doWhilst(iteratee, test, callback) {\n callback = onlyOnce(callback || noop);\n var _iteratee = wrapAsync(iteratee);\n var next = function(err/*, ...args*/) {\n if (err) return callback(err);\n var args = slice(arguments, 1);\n if (test.apply(this, args)) return _iteratee(next);\n callback.apply(null, [null].concat(args));\n };\n _iteratee(next);\n}\n\n/**\n * Like ['doWhilst']{@link module:ControlFlow.doWhilst}, except the `test` is inverted. Note the\n * argument ordering differs from `until`.\n *\n * @name doUntil\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.doWhilst]{@link module:ControlFlow.doWhilst}\n * @category Control Flow\n * @param {AsyncFunction} iteratee - An async function which is called each time\n * `test` fails. Invoked with (callback).\n * @param {Function} test - synchronous truth test to perform after each\n * execution of `iteratee`. Invoked with any non-error callback results of\n * `iteratee`.\n * @param {Function} [callback] - A callback which is called after the test\n * function has passed and repeated execution of `iteratee` has stopped. `callback`\n * will be passed an error and any arguments passed to the final `iteratee`'s\n * callback. Invoked with (err, [results]);\n */\nfunction doUntil(iteratee, test, callback) {\n doWhilst(iteratee, function() {\n return !test.apply(this, arguments);\n }, callback);\n}\n\n/**\n * Like [`whilst`]{@link module:ControlFlow.whilst}, except the `test` is an asynchronous function that\n * is passed a callback in the form of `function (err, truth)`. If error is\n * passed to `test` or `fn`, the main callback is immediately called with the\n * value of the error.\n *\n * @name during\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.whilst]{@link module:ControlFlow.whilst}\n * @category Control Flow\n * @param {AsyncFunction} test - asynchronous truth test to perform before each\n * execution of `fn`. Invoked with (callback).\n * @param {AsyncFunction} fn - An async function which is called each time\n * `test` passes. Invoked with (callback).\n * @param {Function} [callback] - A callback which is called after the test\n * function has failed and repeated execution of `fn` has stopped. `callback`\n * will be passed an error, if one occurred, otherwise `null`.\n * @example\n *\n * var count = 0;\n *\n * async.during(\n * function (callback) {\n * return callback(null, count < 5);\n * },\n * function (callback) {\n * count++;\n * setTimeout(callback, 1000);\n * },\n * function (err) {\n * // 5 seconds have passed\n * }\n * );\n */\nfunction during(test, fn, callback) {\n callback = onlyOnce(callback || noop);\n var _fn = wrapAsync(fn);\n var _test = wrapAsync(test);\n\n function next(err) {\n if (err) return callback(err);\n _test(check);\n }\n\n function check(err, truth) {\n if (err) return callback(err);\n if (!truth) return callback(null);\n _fn(next);\n }\n\n _test(check);\n}\n\nfunction _withoutIndex(iteratee) {\n return function (value, index, callback) {\n return iteratee(value, callback);\n };\n}\n\n/**\n * Applies the function `iteratee` to each item in `coll`, in parallel.\n * The `iteratee` is called with an item from the list, and a callback for when\n * it has finished. If the `iteratee` passes an error to its `callback`, the\n * main `callback` (for the `each` function) is immediately called with the\n * error.\n *\n * Note, that since this function applies `iteratee` to each item in parallel,\n * there is no guarantee that the iteratee functions will complete in order.\n *\n * @name each\n * @static\n * @memberOf module:Collections\n * @method\n * @alias forEach\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to\n * each item in `coll`. Invoked with (item, callback).\n * The array index is not passed to the iteratee.\n * If you need the index, use `eachOf`.\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n * @example\n *\n * // assuming openFiles is an array of file names and saveFile is a function\n * // to save the modified contents of that file:\n *\n * async.each(openFiles, saveFile, function(err){\n * // if any of the saves produced an error, err would equal that error\n * });\n *\n * // assuming openFiles is an array of file names\n * async.each(openFiles, function(file, callback) {\n *\n * // Perform operation on file here.\n * console.log('Processing file ' + file);\n *\n * if( file.length > 32 ) {\n * console.log('This file name is too long');\n * callback('File name too long');\n * } else {\n * // Do work to process file here\n * console.log('File processed');\n * callback();\n * }\n * }, function(err) {\n * // if any of the file processing produced an error, err would equal that error\n * if( err ) {\n * // One of the iterations produced an error.\n * // All processing will now stop.\n * console.log('A file failed to process');\n * } else {\n * console.log('All files have been processed successfully');\n * }\n * });\n */\nfunction eachLimit(coll, iteratee, callback) {\n eachOf(coll, _withoutIndex(wrapAsync(iteratee)), callback);\n}\n\n/**\n * The same as [`each`]{@link module:Collections.each} but runs a maximum of `limit` async operations at a time.\n *\n * @name eachLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.each]{@link module:Collections.each}\n * @alias forEachLimit\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The array index is not passed to the iteratee.\n * If you need the index, use `eachOfLimit`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n */\nfunction eachLimit$1(coll, limit, iteratee, callback) {\n _eachOfLimit(limit)(coll, _withoutIndex(wrapAsync(iteratee)), callback);\n}\n\n/**\n * The same as [`each`]{@link module:Collections.each} but runs only a single async operation at a time.\n *\n * @name eachSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.each]{@link module:Collections.each}\n * @alias forEachSeries\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each\n * item in `coll`.\n * The array index is not passed to the iteratee.\n * If you need the index, use `eachOfSeries`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called when all\n * `iteratee` functions have finished, or an error occurs. Invoked with (err).\n */\nvar eachSeries = doLimit(eachLimit$1, 1);\n\n/**\n * Wrap an async function and ensure it calls its callback on a later tick of\n * the event loop. If the function already calls its callback on a next tick,\n * no extra deferral is added. This is useful for preventing stack overflows\n * (`RangeError: Maximum call stack size exceeded`) and generally keeping\n * [Zalgo](http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony)\n * contained. ES2017 `async` functions are returned as-is -- they are immune\n * to Zalgo's corrupting influences, as they always resolve on a later tick.\n *\n * @name ensureAsync\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} fn - an async function, one that expects a node-style\n * callback as its last argument.\n * @returns {AsyncFunction} Returns a wrapped function with the exact same call\n * signature as the function passed in.\n * @example\n *\n * function sometimesAsync(arg, callback) {\n * if (cache[arg]) {\n * return callback(null, cache[arg]); // this would be synchronous!!\n * } else {\n * doSomeIO(arg, callback); // this IO would be asynchronous\n * }\n * }\n *\n * // this has a risk of stack overflows if many results are cached in a row\n * async.mapSeries(args, sometimesAsync, done);\n *\n * // this will defer sometimesAsync's callback if necessary,\n * // preventing stack overflows\n * async.mapSeries(args, async.ensureAsync(sometimesAsync), done);\n */\nfunction ensureAsync(fn) {\n if (isAsync(fn)) return fn;\n return initialParams(function (args, callback) {\n var sync = true;\n args.push(function () {\n var innerArgs = arguments;\n if (sync) {\n setImmediate$1(function () {\n callback.apply(null, innerArgs);\n });\n } else {\n callback.apply(null, innerArgs);\n }\n });\n fn.apply(this, args);\n sync = false;\n });\n}\n\nfunction notId(v) {\n return !v;\n}\n\n/**\n * Returns `true` if every element in `coll` satisfies an async test. If any\n * iteratee call returns `false`, the main `callback` is immediately called.\n *\n * @name every\n * @static\n * @memberOf module:Collections\n * @method\n * @alias all\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collection in parallel.\n * The iteratee must complete with a boolean result value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result will be either `true` or `false`\n * depending on the values of the async tests. Invoked with (err, result).\n * @example\n *\n * async.every(['file1','file2','file3'], function(filePath, callback) {\n * fs.access(filePath, function(err) {\n * callback(null, !err)\n * });\n * }, function(err, result) {\n * // if result is true then every file exists\n * });\n */\nvar every = doParallel(_createTester(notId, notId));\n\n/**\n * The same as [`every`]{@link module:Collections.every} but runs a maximum of `limit` async operations at a time.\n *\n * @name everyLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.every]{@link module:Collections.every}\n * @alias allLimit\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collection in parallel.\n * The iteratee must complete with a boolean result value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result will be either `true` or `false`\n * depending on the values of the async tests. Invoked with (err, result).\n */\nvar everyLimit = doParallelLimit(_createTester(notId, notId));\n\n/**\n * The same as [`every`]{@link module:Collections.every} but runs only a single async operation at a time.\n *\n * @name everySeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.every]{@link module:Collections.every}\n * @alias allSeries\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collection in series.\n * The iteratee must complete with a boolean result value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result will be either `true` or `false`\n * depending on the values of the async tests. Invoked with (err, result).\n */\nvar everySeries = doLimit(everyLimit, 1);\n\n/**\n * The base implementation of `_.property` without support for deep paths.\n *\n * @private\n * @param {string} key The key of the property to get.\n * @returns {Function} Returns the new accessor function.\n */\nfunction baseProperty(key) {\n return function(object) {\n return object == null ? undefined : object[key];\n };\n}\n\nfunction filterArray(eachfn, arr, iteratee, callback) {\n var truthValues = new Array(arr.length);\n eachfn(arr, function (x, index, callback) {\n iteratee(x, function (err, v) {\n truthValues[index] = !!v;\n callback(err);\n });\n }, function (err) {\n if (err) return callback(err);\n var results = [];\n for (var i = 0; i < arr.length; i++) {\n if (truthValues[i]) results.push(arr[i]);\n }\n callback(null, results);\n });\n}\n\nfunction filterGeneric(eachfn, coll, iteratee, callback) {\n var results = [];\n eachfn(coll, function (x, index, callback) {\n iteratee(x, function (err, v) {\n if (err) {\n callback(err);\n } else {\n if (v) {\n results.push({index: index, value: x});\n }\n callback();\n }\n });\n }, function (err) {\n if (err) {\n callback(err);\n } else {\n callback(null, arrayMap(results.sort(function (a, b) {\n return a.index - b.index;\n }), baseProperty('value')));\n }\n });\n}\n\nfunction _filter(eachfn, coll, iteratee, callback) {\n var filter = isArrayLike(coll) ? filterArray : filterGeneric;\n filter(eachfn, coll, wrapAsync(iteratee), callback || noop);\n}\n\n/**\n * Returns a new array of all the values in `coll` which pass an async truth\n * test. This operation is performed in parallel, but the results array will be\n * in the same order as the original.\n *\n * @name filter\n * @static\n * @memberOf module:Collections\n * @method\n * @alias select\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {Function} iteratee - A truth test to apply to each item in `coll`.\n * The `iteratee` is passed a `callback(err, truthValue)`, which must be called\n * with a boolean argument once it has completed. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n * @example\n *\n * async.filter(['file1','file2','file3'], function(filePath, callback) {\n * fs.access(filePath, function(err) {\n * callback(null, !err)\n * });\n * }, function(err, results) {\n * // results now equals an array of the existing files\n * });\n */\nvar filter = doParallel(_filter);\n\n/**\n * The same as [`filter`]{@link module:Collections.filter} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name filterLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.filter]{@link module:Collections.filter}\n * @alias selectLimit\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {Function} iteratee - A truth test to apply to each item in `coll`.\n * The `iteratee` is passed a `callback(err, truthValue)`, which must be called\n * with a boolean argument once it has completed. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n */\nvar filterLimit = doParallelLimit(_filter);\n\n/**\n * The same as [`filter`]{@link module:Collections.filter} but runs only a single async operation at a time.\n *\n * @name filterSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.filter]{@link module:Collections.filter}\n * @alias selectSeries\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {Function} iteratee - A truth test to apply to each item in `coll`.\n * The `iteratee` is passed a `callback(err, truthValue)`, which must be called\n * with a boolean argument once it has completed. Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results)\n */\nvar filterSeries = doLimit(filterLimit, 1);\n\n/**\n * Calls the asynchronous function `fn` with a callback parameter that allows it\n * to call itself again, in series, indefinitely.\n\n * If an error is passed to the callback then `errback` is called with the\n * error, and execution stops, otherwise it will never be called.\n *\n * @name forever\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {AsyncFunction} fn - an async function to call repeatedly.\n * Invoked with (next).\n * @param {Function} [errback] - when `fn` passes an error to it's callback,\n * this function will be called, and execution stops. Invoked with (err).\n * @example\n *\n * async.forever(\n * function(next) {\n * // next is suitable for passing to things that need a callback(err [, whatever]);\n * // it will result in this function being called again.\n * },\n * function(err) {\n * // if next is called with a value in its first parameter, it will appear\n * // in here as 'err', and execution will stop.\n * }\n * );\n */\nfunction forever(fn, errback) {\n var done = onlyOnce(errback || noop);\n var task = wrapAsync(ensureAsync(fn));\n\n function next(err) {\n if (err) return done(err);\n task(next);\n }\n next();\n}\n\n/**\n * The same as [`groupBy`]{@link module:Collections.groupBy} but runs a maximum of `limit` async operations at a time.\n *\n * @name groupByLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.groupBy]{@link module:Collections.groupBy}\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with a `key` to group the value under.\n * Invoked with (value, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Result is an `Object` whoses\n * properties are arrays of values which returned the corresponding key.\n */\nvar groupByLimit = function(coll, limit, iteratee, callback) {\n callback = callback || noop;\n var _iteratee = wrapAsync(iteratee);\n mapLimit(coll, limit, function(val, callback) {\n _iteratee(val, function(err, key) {\n if (err) return callback(err);\n return callback(null, {key: key, val: val});\n });\n }, function(err, mapResults) {\n var result = {};\n // from MDN, handle object having an `hasOwnProperty` prop\n var hasOwnProperty = Object.prototype.hasOwnProperty;\n\n for (var i = 0; i < mapResults.length; i++) {\n if (mapResults[i]) {\n var key = mapResults[i].key;\n var val = mapResults[i].val;\n\n if (hasOwnProperty.call(result, key)) {\n result[key].push(val);\n } else {\n result[key] = [val];\n }\n }\n }\n\n return callback(err, result);\n });\n};\n\n/**\n * Returns a new object, where each value corresponds to an array of items, from\n * `coll`, that returned the corresponding key. That is, the keys of the object\n * correspond to the values passed to the `iteratee` callback.\n *\n * Note: Since this function applies the `iteratee` to each item in parallel,\n * there is no guarantee that the `iteratee` functions will complete in order.\n * However, the values for each key in the `result` will be in the same order as\n * the original `coll`. For Objects, the values will roughly be in the order of\n * the original Objects' keys (but this can vary across JavaScript engines).\n *\n * @name groupBy\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with a `key` to group the value under.\n * Invoked with (value, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Result is an `Object` whoses\n * properties are arrays of values which returned the corresponding key.\n * @example\n *\n * async.groupBy(['userId1', 'userId2', 'userId3'], function(userId, callback) {\n * db.findById(userId, function(err, user) {\n * if (err) return callback(err);\n * return callback(null, user.age);\n * });\n * }, function(err, result) {\n * // result is object containing the userIds grouped by age\n * // e.g. { 30: ['userId1', 'userId3'], 42: ['userId2']};\n * });\n */\nvar groupBy = doLimit(groupByLimit, Infinity);\n\n/**\n * The same as [`groupBy`]{@link module:Collections.groupBy} but runs only a single async operation at a time.\n *\n * @name groupBySeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.groupBy]{@link module:Collections.groupBy}\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with a `key` to group the value under.\n * Invoked with (value, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. Result is an `Object` whoses\n * properties are arrays of values which returned the corresponding key.\n */\nvar groupBySeries = doLimit(groupByLimit, 1);\n\n/**\n * Logs the result of an `async` function to the `console`. Only works in\n * Node.js or in browsers that support `console.log` and `console.error` (such\n * as FF and Chrome). If multiple arguments are returned from the async\n * function, `console.log` is called on each argument in order.\n *\n * @name log\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} function - The function you want to eventually apply\n * all arguments to.\n * @param {...*} arguments... - Any number of arguments to apply to the function.\n * @example\n *\n * // in a module\n * var hello = function(name, callback) {\n * setTimeout(function() {\n * callback(null, 'hello ' + name);\n * }, 1000);\n * };\n *\n * // in the node repl\n * node> async.log(hello, 'world');\n * 'hello world'\n */\nvar log = consoleFunc('log');\n\n/**\n * The same as [`mapValues`]{@link module:Collections.mapValues} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name mapValuesLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.mapValues]{@link module:Collections.mapValues}\n * @category Collection\n * @param {Object} obj - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - A function to apply to each value and key\n * in `coll`.\n * The iteratee should complete with the transformed value as its result.\n * Invoked with (value, key, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. `result` is a new object consisting\n * of each key from `obj`, with each transformed value on the right-hand side.\n * Invoked with (err, result).\n */\nfunction mapValuesLimit(obj, limit, iteratee, callback) {\n callback = once(callback || noop);\n var newObj = {};\n var _iteratee = wrapAsync(iteratee);\n eachOfLimit(obj, limit, function(val, key, next) {\n _iteratee(val, key, function (err, result) {\n if (err) return next(err);\n newObj[key] = result;\n next();\n });\n }, function (err) {\n callback(err, newObj);\n });\n}\n\n/**\n * A relative of [`map`]{@link module:Collections.map}, designed for use with objects.\n *\n * Produces a new Object by mapping each value of `obj` through the `iteratee`\n * function. The `iteratee` is called each `value` and `key` from `obj` and a\n * callback for when it has finished processing. Each of these callbacks takes\n * two arguments: an `error`, and the transformed item from `obj`. If `iteratee`\n * passes an error to its callback, the main `callback` (for the `mapValues`\n * function) is immediately called with the error.\n *\n * Note, the order of the keys in the result is not guaranteed. The keys will\n * be roughly in the order they complete, (but this is very engine-specific)\n *\n * @name mapValues\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Object} obj - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each value and key\n * in `coll`.\n * The iteratee should complete with the transformed value as its result.\n * Invoked with (value, key, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. `result` is a new object consisting\n * of each key from `obj`, with each transformed value on the right-hand side.\n * Invoked with (err, result).\n * @example\n *\n * async.mapValues({\n * f1: 'file1',\n * f2: 'file2',\n * f3: 'file3'\n * }, function (file, key, callback) {\n * fs.stat(file, callback);\n * }, function(err, result) {\n * // result is now a map of stats for each file, e.g.\n * // {\n * // f1: [stats for file1],\n * // f2: [stats for file2],\n * // f3: [stats for file3]\n * // }\n * });\n */\n\nvar mapValues = doLimit(mapValuesLimit, Infinity);\n\n/**\n * The same as [`mapValues`]{@link module:Collections.mapValues} but runs only a single async operation at a time.\n *\n * @name mapValuesSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.mapValues]{@link module:Collections.mapValues}\n * @category Collection\n * @param {Object} obj - A collection to iterate over.\n * @param {AsyncFunction} iteratee - A function to apply to each value and key\n * in `coll`.\n * The iteratee should complete with the transformed value as its result.\n * Invoked with (value, key, callback).\n * @param {Function} [callback] - A callback which is called when all `iteratee`\n * functions have finished, or an error occurs. `result` is a new object consisting\n * of each key from `obj`, with each transformed value on the right-hand side.\n * Invoked with (err, result).\n */\nvar mapValuesSeries = doLimit(mapValuesLimit, 1);\n\nfunction has(obj, key) {\n return key in obj;\n}\n\n/**\n * Caches the results of an async function. When creating a hash to store\n * function results against, the callback is omitted from the hash and an\n * optional hash function can be used.\n *\n * If no hash function is specified, the first argument is used as a hash key,\n * which may work reasonably if it is a string or a data type that converts to a\n * distinct string. Note that objects and arrays will not behave reasonably.\n * Neither will cases where the other arguments are significant. In such cases,\n * specify your own hash function.\n *\n * The cache of results is exposed as the `memo` property of the function\n * returned by `memoize`.\n *\n * @name memoize\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} fn - The async function to proxy and cache results from.\n * @param {Function} hasher - An optional function for generating a custom hash\n * for storing results. It has all the arguments applied to it apart from the\n * callback, and must be synchronous.\n * @returns {AsyncFunction} a memoized version of `fn`\n * @example\n *\n * var slow_fn = function(name, callback) {\n * // do something\n * callback(null, result);\n * };\n * var fn = async.memoize(slow_fn);\n *\n * // fn can now be used as if it were slow_fn\n * fn('some name', function() {\n * // callback\n * });\n */\nfunction memoize(fn, hasher) {\n var memo = Object.create(null);\n var queues = Object.create(null);\n hasher = hasher || identity;\n var _fn = wrapAsync(fn);\n var memoized = initialParams(function memoized(args, callback) {\n var key = hasher.apply(null, args);\n if (has(memo, key)) {\n setImmediate$1(function() {\n callback.apply(null, memo[key]);\n });\n } else if (has(queues, key)) {\n queues[key].push(callback);\n } else {\n queues[key] = [callback];\n _fn.apply(null, args.concat(function(/*args*/) {\n var args = slice(arguments);\n memo[key] = args;\n var q = queues[key];\n delete queues[key];\n for (var i = 0, l = q.length; i < l; i++) {\n q[i].apply(null, args);\n }\n }));\n }\n });\n memoized.memo = memo;\n memoized.unmemoized = fn;\n return memoized;\n}\n\n/**\n * Calls `callback` on a later loop around the event loop. In Node.js this just\n * calls `process.nextTick`. In the browser it will use `setImmediate` if\n * available, otherwise `setTimeout(callback, 0)`, which means other higher\n * priority events may precede the execution of `callback`.\n *\n * This is used internally for browser-compatibility purposes.\n *\n * @name nextTick\n * @static\n * @memberOf module:Utils\n * @method\n * @see [async.setImmediate]{@link module:Utils.setImmediate}\n * @category Util\n * @param {Function} callback - The function to call on a later loop around\n * the event loop. Invoked with (args...).\n * @param {...*} args... - any number of additional arguments to pass to the\n * callback on the next tick.\n * @example\n *\n * var call_order = [];\n * async.nextTick(function() {\n * call_order.push('two');\n * // call_order now equals ['one','two']\n * });\n * call_order.push('one');\n *\n * async.setImmediate(function (a, b, c) {\n * // a, b, and c equal 1, 2, and 3\n * }, 1, 2, 3);\n */\nvar _defer$1;\n\nif (hasNextTick) {\n _defer$1 = process.nextTick;\n} else if (hasSetImmediate) {\n _defer$1 = setImmediate;\n} else {\n _defer$1 = fallback;\n}\n\nvar nextTick = wrap(_defer$1);\n\nfunction _parallel(eachfn, tasks, callback) {\n callback = callback || noop;\n var results = isArrayLike(tasks) ? [] : {};\n\n eachfn(tasks, function (task, key, callback) {\n wrapAsync(task)(function (err, result) {\n if (arguments.length > 2) {\n result = slice(arguments, 1);\n }\n results[key] = result;\n callback(err);\n });\n }, function (err) {\n callback(err, results);\n });\n}\n\n/**\n * Run the `tasks` collection of functions in parallel, without waiting until\n * the previous function has completed. If any of the functions pass an error to\n * its callback, the main `callback` is immediately called with the value of the\n * error. Once the `tasks` have completed, the results are passed to the final\n * `callback` as an array.\n *\n * **Note:** `parallel` is about kicking-off I/O tasks in parallel, not about\n * parallel execution of code. If your tasks do not use any timers or perform\n * any I/O, they will actually be executed in series. Any synchronous setup\n * sections for each task will happen one after the other. JavaScript remains\n * single-threaded.\n *\n * **Hint:** Use [`reflect`]{@link module:Utils.reflect} to continue the\n * execution of other tasks when a task fails.\n *\n * It is also possible to use an object instead of an array. Each property will\n * be run as a function and the results will be passed to the final `callback`\n * as an object instead of an array. This can be a more readable way of handling\n * results from {@link async.parallel}.\n *\n * @name parallel\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array|Iterable|Object} tasks - A collection of\n * [async functions]{@link AsyncFunction} to run.\n * Each async function can complete with any number of optional `result` values.\n * @param {Function} [callback] - An optional callback to run once all the\n * functions have completed successfully. This function gets a results array\n * (or object) containing all the result arguments passed to the task callbacks.\n * Invoked with (err, results).\n *\n * @example\n * async.parallel([\n * function(callback) {\n * setTimeout(function() {\n * callback(null, 'one');\n * }, 200);\n * },\n * function(callback) {\n * setTimeout(function() {\n * callback(null, 'two');\n * }, 100);\n * }\n * ],\n * // optional callback\n * function(err, results) {\n * // the results array will equal ['one','two'] even though\n * // the second function had a shorter timeout.\n * });\n *\n * // an example using an object instead of an array\n * async.parallel({\n * one: function(callback) {\n * setTimeout(function() {\n * callback(null, 1);\n * }, 200);\n * },\n * two: function(callback) {\n * setTimeout(function() {\n * callback(null, 2);\n * }, 100);\n * }\n * }, function(err, results) {\n * // results is now equals to: {one: 1, two: 2}\n * });\n */\nfunction parallelLimit(tasks, callback) {\n _parallel(eachOf, tasks, callback);\n}\n\n/**\n * The same as [`parallel`]{@link module:ControlFlow.parallel} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name parallelLimit\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.parallel]{@link module:ControlFlow.parallel}\n * @category Control Flow\n * @param {Array|Iterable|Object} tasks - A collection of\n * [async functions]{@link AsyncFunction} to run.\n * Each async function can complete with any number of optional `result` values.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {Function} [callback] - An optional callback to run once all the\n * functions have completed successfully. This function gets a results array\n * (or object) containing all the result arguments passed to the task callbacks.\n * Invoked with (err, results).\n */\nfunction parallelLimit$1(tasks, limit, callback) {\n _parallel(_eachOfLimit(limit), tasks, callback);\n}\n\n/**\n * A queue of tasks for the worker function to complete.\n * @typedef {Object} QueueObject\n * @memberOf module:ControlFlow\n * @property {Function} length - a function returning the number of items\n * waiting to be processed. Invoke with `queue.length()`.\n * @property {boolean} started - a boolean indicating whether or not any\n * items have been pushed and processed by the queue.\n * @property {Function} running - a function returning the number of items\n * currently being processed. Invoke with `queue.running()`.\n * @property {Function} workersList - a function returning the array of items\n * currently being processed. Invoke with `queue.workersList()`.\n * @property {Function} idle - a function returning false if there are items\n * waiting or being processed, or true if not. Invoke with `queue.idle()`.\n * @property {number} concurrency - an integer for determining how many `worker`\n * functions should be run in parallel. This property can be changed after a\n * `queue` is created to alter the concurrency on-the-fly.\n * @property {Function} push - add a new task to the `queue`. Calls `callback`\n * once the `worker` has finished processing the task. Instead of a single task,\n * a `tasks` array can be submitted. The respective callback is used for every\n * task in the list. Invoke with `queue.push(task, [callback])`,\n * @property {Function} unshift - add a new task to the front of the `queue`.\n * Invoke with `queue.unshift(task, [callback])`.\n * @property {Function} remove - remove items from the queue that match a test\n * function. The test function will be passed an object with a `data` property,\n * and a `priority` property, if this is a\n * [priorityQueue]{@link module:ControlFlow.priorityQueue} object.\n * Invoked with `queue.remove(testFn)`, where `testFn` is of the form\n * `function ({data, priority}) {}` and returns a Boolean.\n * @property {Function} saturated - a callback that is called when the number of\n * running workers hits the `concurrency` limit, and further tasks will be\n * queued.\n * @property {Function} unsaturated - a callback that is called when the number\n * of running workers is less than the `concurrency` & `buffer` limits, and\n * further tasks will not be queued.\n * @property {number} buffer - A minimum threshold buffer in order to say that\n * the `queue` is `unsaturated`.\n * @property {Function} empty - a callback that is called when the last item\n * from the `queue` is given to a `worker`.\n * @property {Function} drain - a callback that is called when the last item\n * from the `queue` has returned from the `worker`.\n * @property {Function} error - a callback that is called when a task errors.\n * Has the signature `function(error, task)`.\n * @property {boolean} paused - a boolean for determining whether the queue is\n * in a paused state.\n * @property {Function} pause - a function that pauses the processing of tasks\n * until `resume()` is called. Invoke with `queue.pause()`.\n * @property {Function} resume - a function that resumes the processing of\n * queued tasks when the queue is paused. Invoke with `queue.resume()`.\n * @property {Function} kill - a function that removes the `drain` callback and\n * empties remaining tasks from the queue forcing it to go idle. No more tasks\n * should be pushed to the queue after calling this function. Invoke with `queue.kill()`.\n */\n\n/**\n * Creates a `queue` object with the specified `concurrency`. Tasks added to the\n * `queue` are processed in parallel (up to the `concurrency` limit). If all\n * `worker`s are in progress, the task is queued until one becomes available.\n * Once a `worker` completes a `task`, that `task`'s callback is called.\n *\n * @name queue\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {AsyncFunction} worker - An async function for processing a queued task.\n * If you want to handle errors from an individual task, pass a callback to\n * `q.push()`. Invoked with (task, callback).\n * @param {number} [concurrency=1] - An `integer` for determining how many\n * `worker` functions should be run in parallel. If omitted, the concurrency\n * defaults to `1`. If the concurrency is `0`, an error is thrown.\n * @returns {module:ControlFlow.QueueObject} A queue object to manage the tasks. Callbacks can\n * attached as certain properties to listen for specific events during the\n * lifecycle of the queue.\n * @example\n *\n * // create a queue object with concurrency 2\n * var q = async.queue(function(task, callback) {\n * console.log('hello ' + task.name);\n * callback();\n * }, 2);\n *\n * // assign a callback\n * q.drain = function() {\n * console.log('all items have been processed');\n * };\n *\n * // add some items to the queue\n * q.push({name: 'foo'}, function(err) {\n * console.log('finished processing foo');\n * });\n * q.push({name: 'bar'}, function (err) {\n * console.log('finished processing bar');\n * });\n *\n * // add some items to the queue (batch-wise)\n * q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function(err) {\n * console.log('finished processing item');\n * });\n *\n * // add some items to the front of the queue\n * q.unshift({name: 'bar'}, function (err) {\n * console.log('finished processing bar');\n * });\n */\nvar queue$1 = function (worker, concurrency) {\n var _worker = wrapAsync(worker);\n return queue(function (items, cb) {\n _worker(items[0], cb);\n }, concurrency, 1);\n};\n\n/**\n * The same as [async.queue]{@link module:ControlFlow.queue} only tasks are assigned a priority and\n * completed in ascending priority order.\n *\n * @name priorityQueue\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.queue]{@link module:ControlFlow.queue}\n * @category Control Flow\n * @param {AsyncFunction} worker - An async function for processing a queued task.\n * If you want to handle errors from an individual task, pass a callback to\n * `q.push()`.\n * Invoked with (task, callback).\n * @param {number} concurrency - An `integer` for determining how many `worker`\n * functions should be run in parallel. If omitted, the concurrency defaults to\n * `1`. If the concurrency is `0`, an error is thrown.\n * @returns {module:ControlFlow.QueueObject} A priorityQueue object to manage the tasks. There are two\n * differences between `queue` and `priorityQueue` objects:\n * * `push(task, priority, [callback])` - `priority` should be a number. If an\n * array of `tasks` is given, all tasks will be assigned the same priority.\n * * The `unshift` method was removed.\n */\nvar priorityQueue = function(worker, concurrency) {\n // Start with a normal queue\n var q = queue$1(worker, concurrency);\n\n // Override push to accept second parameter representing priority\n q.push = function(data, priority, callback) {\n if (callback == null) callback = noop;\n if (typeof callback !== 'function') {\n throw new Error('task callback must be a function');\n }\n q.started = true;\n if (!isArray(data)) {\n data = [data];\n }\n if (data.length === 0) {\n // call drain immediately if there are no tasks\n return setImmediate$1(function() {\n q.drain();\n });\n }\n\n priority = priority || 0;\n var nextNode = q._tasks.head;\n while (nextNode && priority >= nextNode.priority) {\n nextNode = nextNode.next;\n }\n\n for (var i = 0, l = data.length; i < l; i++) {\n var item = {\n data: data[i],\n priority: priority,\n callback: callback\n };\n\n if (nextNode) {\n q._tasks.insertBefore(nextNode, item);\n } else {\n q._tasks.push(item);\n }\n }\n setImmediate$1(q.process);\n };\n\n // Remove unshift function\n delete q.unshift;\n\n return q;\n};\n\n/**\n * Runs the `tasks` array of functions in parallel, without waiting until the\n * previous function has completed. Once any of the `tasks` complete or pass an\n * error to its callback, the main `callback` is immediately called. It's\n * equivalent to `Promise.race()`.\n *\n * @name race\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array} tasks - An array containing [async functions]{@link AsyncFunction}\n * to run. Each function can complete with an optional `result` value.\n * @param {Function} callback - A callback to run once any of the functions have\n * completed. This function gets an error or result from the first function that\n * completed. Invoked with (err, result).\n * @returns undefined\n * @example\n *\n * async.race([\n * function(callback) {\n * setTimeout(function() {\n * callback(null, 'one');\n * }, 200);\n * },\n * function(callback) {\n * setTimeout(function() {\n * callback(null, 'two');\n * }, 100);\n * }\n * ],\n * // main callback\n * function(err, result) {\n * // the result will be equal to 'two' as it finishes earlier\n * });\n */\nfunction race(tasks, callback) {\n callback = once(callback || noop);\n if (!isArray(tasks)) return callback(new TypeError('First argument to race must be an array of functions'));\n if (!tasks.length) return callback();\n for (var i = 0, l = tasks.length; i < l; i++) {\n wrapAsync(tasks[i])(callback);\n }\n}\n\n/**\n * Same as [`reduce`]{@link module:Collections.reduce}, only operates on `array` in reverse order.\n *\n * @name reduceRight\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.reduce]{@link module:Collections.reduce}\n * @alias foldr\n * @category Collection\n * @param {Array} array - A collection to iterate over.\n * @param {*} memo - The initial state of the reduction.\n * @param {AsyncFunction} iteratee - A function applied to each item in the\n * array to produce the next step in the reduction.\n * The `iteratee` should complete with the next state of the reduction.\n * If the iteratee complete with an error, the reduction is stopped and the\n * main `callback` is immediately called with the error.\n * Invoked with (memo, item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result is the reduced value. Invoked with\n * (err, result).\n */\nfunction reduceRight (array, memo, iteratee, callback) {\n var reversed = slice(array).reverse();\n reduce(reversed, memo, iteratee, callback);\n}\n\n/**\n * Wraps the async function in another function that always completes with a\n * result object, even when it errors.\n *\n * The result object has either the property `error` or `value`.\n *\n * @name reflect\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} fn - The async function you want to wrap\n * @returns {Function} - A function that always passes null to it's callback as\n * the error. The second argument to the callback will be an `object` with\n * either an `error` or a `value` property.\n * @example\n *\n * async.parallel([\n * async.reflect(function(callback) {\n * // do some stuff ...\n * callback(null, 'one');\n * }),\n * async.reflect(function(callback) {\n * // do some more stuff but error ...\n * callback('bad stuff happened');\n * }),\n * async.reflect(function(callback) {\n * // do some more stuff ...\n * callback(null, 'two');\n * })\n * ],\n * // optional callback\n * function(err, results) {\n * // values\n * // results[0].value = 'one'\n * // results[1].error = 'bad stuff happened'\n * // results[2].value = 'two'\n * });\n */\nfunction reflect(fn) {\n var _fn = wrapAsync(fn);\n return initialParams(function reflectOn(args, reflectCallback) {\n args.push(function callback(error, cbArg) {\n if (error) {\n reflectCallback(null, { error: error });\n } else {\n var value;\n if (arguments.length <= 2) {\n value = cbArg;\n } else {\n value = slice(arguments, 1);\n }\n reflectCallback(null, { value: value });\n }\n });\n\n return _fn.apply(this, args);\n });\n}\n\n/**\n * A helper function that wraps an array or an object of functions with `reflect`.\n *\n * @name reflectAll\n * @static\n * @memberOf module:Utils\n * @method\n * @see [async.reflect]{@link module:Utils.reflect}\n * @category Util\n * @param {Array|Object|Iterable} tasks - The collection of\n * [async functions]{@link AsyncFunction} to wrap in `async.reflect`.\n * @returns {Array} Returns an array of async functions, each wrapped in\n * `async.reflect`\n * @example\n *\n * let tasks = [\n * function(callback) {\n * setTimeout(function() {\n * callback(null, 'one');\n * }, 200);\n * },\n * function(callback) {\n * // do some more stuff but error ...\n * callback(new Error('bad stuff happened'));\n * },\n * function(callback) {\n * setTimeout(function() {\n * callback(null, 'two');\n * }, 100);\n * }\n * ];\n *\n * async.parallel(async.reflectAll(tasks),\n * // optional callback\n * function(err, results) {\n * // values\n * // results[0].value = 'one'\n * // results[1].error = Error('bad stuff happened')\n * // results[2].value = 'two'\n * });\n *\n * // an example using an object instead of an array\n * let tasks = {\n * one: function(callback) {\n * setTimeout(function() {\n * callback(null, 'one');\n * }, 200);\n * },\n * two: function(callback) {\n * callback('two');\n * },\n * three: function(callback) {\n * setTimeout(function() {\n * callback(null, 'three');\n * }, 100);\n * }\n * };\n *\n * async.parallel(async.reflectAll(tasks),\n * // optional callback\n * function(err, results) {\n * // values\n * // results.one.value = 'one'\n * // results.two.error = 'two'\n * // results.three.value = 'three'\n * });\n */\nfunction reflectAll(tasks) {\n var results;\n if (isArray(tasks)) {\n results = arrayMap(tasks, reflect);\n } else {\n results = {};\n baseForOwn(tasks, function(task, key) {\n results[key] = reflect.call(this, task);\n });\n }\n return results;\n}\n\nfunction reject$1(eachfn, arr, iteratee, callback) {\n _filter(eachfn, arr, function(value, cb) {\n iteratee(value, function(err, v) {\n cb(err, !v);\n });\n }, callback);\n}\n\n/**\n * The opposite of [`filter`]{@link module:Collections.filter}. Removes values that pass an `async` truth test.\n *\n * @name reject\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.filter]{@link module:Collections.filter}\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {Function} iteratee - An async truth test to apply to each item in\n * `coll`.\n * The should complete with a boolean value as its `result`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n * @example\n *\n * async.reject(['file1','file2','file3'], function(filePath, callback) {\n * fs.access(filePath, function(err) {\n * callback(null, !err)\n * });\n * }, function(err, results) {\n * // results now equals an array of missing files\n * createFiles(results);\n * });\n */\nvar reject = doParallel(reject$1);\n\n/**\n * The same as [`reject`]{@link module:Collections.reject} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name rejectLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.reject]{@link module:Collections.reject}\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {Function} iteratee - An async truth test to apply to each item in\n * `coll`.\n * The should complete with a boolean value as its `result`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n */\nvar rejectLimit = doParallelLimit(reject$1);\n\n/**\n * The same as [`reject`]{@link module:Collections.reject} but runs only a single async operation at a time.\n *\n * @name rejectSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.reject]{@link module:Collections.reject}\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {Function} iteratee - An async truth test to apply to each item in\n * `coll`.\n * The should complete with a boolean value as its `result`.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Invoked with (err, results).\n */\nvar rejectSeries = doLimit(rejectLimit, 1);\n\n/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant$1(value) {\n return function() {\n return value;\n };\n}\n\n/**\n * Attempts to get a successful response from `task` no more than `times` times\n * before returning an error. If the task is successful, the `callback` will be\n * passed the result of the successful task. If all attempts fail, the callback\n * will be passed the error and result (if any) of the final attempt.\n *\n * @name retry\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @see [async.retryable]{@link module:ControlFlow.retryable}\n * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - Can be either an\n * object with `times` and `interval` or a number.\n * * `times` - The number of attempts to make before giving up. The default\n * is `5`.\n * * `interval` - The time to wait between retries, in milliseconds. The\n * default is `0`. The interval may also be specified as a function of the\n * retry count (see example).\n * * `errorFilter` - An optional synchronous function that is invoked on\n * erroneous result. If it returns `true` the retry attempts will continue;\n * if the function returns `false` the retry flow is aborted with the current\n * attempt's error and result being returned to the final callback.\n * Invoked with (err).\n * * If `opts` is a number, the number specifies the number of times to retry,\n * with the default interval of `0`.\n * @param {AsyncFunction} task - An async function to retry.\n * Invoked with (callback).\n * @param {Function} [callback] - An optional callback which is called when the\n * task has succeeded, or after the final failed attempt. It receives the `err`\n * and `result` arguments of the last attempt at completing the `task`. Invoked\n * with (err, results).\n *\n * @example\n *\n * // The `retry` function can be used as a stand-alone control flow by passing\n * // a callback, as shown below:\n *\n * // try calling apiMethod 3 times\n * async.retry(3, apiMethod, function(err, result) {\n * // do something with the result\n * });\n *\n * // try calling apiMethod 3 times, waiting 200 ms between each retry\n * async.retry({times: 3, interval: 200}, apiMethod, function(err, result) {\n * // do something with the result\n * });\n *\n * // try calling apiMethod 10 times with exponential backoff\n * // (i.e. intervals of 100, 200, 400, 800, 1600, ... milliseconds)\n * async.retry({\n * times: 10,\n * interval: function(retryCount) {\n * return 50 * Math.pow(2, retryCount);\n * }\n * }, apiMethod, function(err, result) {\n * // do something with the result\n * });\n *\n * // try calling apiMethod the default 5 times no delay between each retry\n * async.retry(apiMethod, function(err, result) {\n * // do something with the result\n * });\n *\n * // try calling apiMethod only when error condition satisfies, all other\n * // errors will abort the retry control flow and return to final callback\n * async.retry({\n * errorFilter: function(err) {\n * return err.message === 'Temporary error'; // only retry on a specific error\n * }\n * }, apiMethod, function(err, result) {\n * // do something with the result\n * });\n *\n * // to retry individual methods that are not as reliable within other\n * // control flow functions, use the `retryable` wrapper:\n * async.auto({\n * users: api.getUsers.bind(api),\n * payments: async.retryable(3, api.getPayments.bind(api))\n * }, function(err, results) {\n * // do something with the results\n * });\n *\n */\nfunction retry(opts, task, callback) {\n var DEFAULT_TIMES = 5;\n var DEFAULT_INTERVAL = 0;\n\n var options = {\n times: DEFAULT_TIMES,\n intervalFunc: constant$1(DEFAULT_INTERVAL)\n };\n\n function parseTimes(acc, t) {\n if (typeof t === 'object') {\n acc.times = +t.times || DEFAULT_TIMES;\n\n acc.intervalFunc = typeof t.interval === 'function' ?\n t.interval :\n constant$1(+t.interval || DEFAULT_INTERVAL);\n\n acc.errorFilter = t.errorFilter;\n } else if (typeof t === 'number' || typeof t === 'string') {\n acc.times = +t || DEFAULT_TIMES;\n } else {\n throw new Error(\"Invalid arguments for async.retry\");\n }\n }\n\n if (arguments.length < 3 && typeof opts === 'function') {\n callback = task || noop;\n task = opts;\n } else {\n parseTimes(options, opts);\n callback = callback || noop;\n }\n\n if (typeof task !== 'function') {\n throw new Error(\"Invalid arguments for async.retry\");\n }\n\n var _task = wrapAsync(task);\n\n var attempt = 1;\n function retryAttempt() {\n _task(function(err) {\n if (err && attempt++ < options.times &&\n (typeof options.errorFilter != 'function' ||\n options.errorFilter(err))) {\n setTimeout(retryAttempt, options.intervalFunc(attempt));\n } else {\n callback.apply(null, arguments);\n }\n });\n }\n\n retryAttempt();\n}\n\n/**\n * A close relative of [`retry`]{@link module:ControlFlow.retry}. This method\n * wraps a task and makes it retryable, rather than immediately calling it\n * with retries.\n *\n * @name retryable\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.retry]{@link module:ControlFlow.retry}\n * @category Control Flow\n * @param {Object|number} [opts = {times: 5, interval: 0}| 5] - optional\n * options, exactly the same as from `retry`\n * @param {AsyncFunction} task - the asynchronous function to wrap.\n * This function will be passed any arguments passed to the returned wrapper.\n * Invoked with (...args, callback).\n * @returns {AsyncFunction} The wrapped function, which when invoked, will\n * retry on an error, based on the parameters specified in `opts`.\n * This function will accept the same parameters as `task`.\n * @example\n *\n * async.auto({\n * dep1: async.retryable(3, getFromFlakyService),\n * process: [\"dep1\", async.retryable(3, function (results, cb) {\n * maybeProcessData(results.dep1, cb);\n * })]\n * }, callback);\n */\nvar retryable = function (opts, task) {\n if (!task) {\n task = opts;\n opts = null;\n }\n var _task = wrapAsync(task);\n return initialParams(function (args, callback) {\n function taskFn(cb) {\n _task.apply(null, args.concat(cb));\n }\n\n if (opts) retry(opts, taskFn, callback);\n else retry(taskFn, callback);\n\n });\n};\n\n/**\n * Run the functions in the `tasks` collection in series, each one running once\n * the previous function has completed. If any functions in the series pass an\n * error to its callback, no more functions are run, and `callback` is\n * immediately called with the value of the error. Otherwise, `callback`\n * receives an array of results when `tasks` have completed.\n *\n * It is also possible to use an object instead of an array. Each property will\n * be run as a function, and the results will be passed to the final `callback`\n * as an object instead of an array. This can be a more readable way of handling\n * results from {@link async.series}.\n *\n * **Note** that while many implementations preserve the order of object\n * properties, the [ECMAScript Language Specification](http://www.ecma-international.org/ecma-262/5.1/#sec-8.6)\n * explicitly states that\n *\n * > The mechanics and order of enumerating the properties is not specified.\n *\n * So if you rely on the order in which your series of functions are executed,\n * and want this to work on all platforms, consider using an array.\n *\n * @name series\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array|Iterable|Object} tasks - A collection containing\n * [async functions]{@link AsyncFunction} to run in series.\n * Each function can complete with any number of optional `result` values.\n * @param {Function} [callback] - An optional callback to run once all the\n * functions have completed. This function gets a results array (or object)\n * containing all the result arguments passed to the `task` callbacks. Invoked\n * with (err, result).\n * @example\n * async.series([\n * function(callback) {\n * // do some stuff ...\n * callback(null, 'one');\n * },\n * function(callback) {\n * // do some more stuff ...\n * callback(null, 'two');\n * }\n * ],\n * // optional callback\n * function(err, results) {\n * // results is now equal to ['one', 'two']\n * });\n *\n * async.series({\n * one: function(callback) {\n * setTimeout(function() {\n * callback(null, 1);\n * }, 200);\n * },\n * two: function(callback){\n * setTimeout(function() {\n * callback(null, 2);\n * }, 100);\n * }\n * }, function(err, results) {\n * // results is now equal to: {one: 1, two: 2}\n * });\n */\nfunction series(tasks, callback) {\n _parallel(eachOfSeries, tasks, callback);\n}\n\n/**\n * Returns `true` if at least one element in the `coll` satisfies an async test.\n * If any iteratee call returns `true`, the main `callback` is immediately\n * called.\n *\n * @name some\n * @static\n * @memberOf module:Collections\n * @method\n * @alias any\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collections in parallel.\n * The iteratee should complete with a boolean `result` value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the iteratee functions have finished.\n * Result will be either `true` or `false` depending on the values of the async\n * tests. Invoked with (err, result).\n * @example\n *\n * async.some(['file1','file2','file3'], function(filePath, callback) {\n * fs.access(filePath, function(err) {\n * callback(null, !err)\n * });\n * }, function(err, result) {\n * // if result is true then at least one of the files exists\n * });\n */\nvar some = doParallel(_createTester(Boolean, identity));\n\n/**\n * The same as [`some`]{@link module:Collections.some} but runs a maximum of `limit` async operations at a time.\n *\n * @name someLimit\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.some]{@link module:Collections.some}\n * @alias anyLimit\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collections in parallel.\n * The iteratee should complete with a boolean `result` value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the iteratee functions have finished.\n * Result will be either `true` or `false` depending on the values of the async\n * tests. Invoked with (err, result).\n */\nvar someLimit = doParallelLimit(_createTester(Boolean, identity));\n\n/**\n * The same as [`some`]{@link module:Collections.some} but runs only a single async operation at a time.\n *\n * @name someSeries\n * @static\n * @memberOf module:Collections\n * @method\n * @see [async.some]{@link module:Collections.some}\n * @alias anySeries\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async truth test to apply to each item\n * in the collections in series.\n * The iteratee should complete with a boolean `result` value.\n * Invoked with (item, callback).\n * @param {Function} [callback] - A callback which is called as soon as any\n * iteratee returns `true`, or after all the iteratee functions have finished.\n * Result will be either `true` or `false` depending on the values of the async\n * tests. Invoked with (err, result).\n */\nvar someSeries = doLimit(someLimit, 1);\n\n/**\n * Sorts a list by the results of running each `coll` value through an async\n * `iteratee`.\n *\n * @name sortBy\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {AsyncFunction} iteratee - An async function to apply to each item in\n * `coll`.\n * The iteratee should complete with a value to use as the sort criteria as\n * its `result`.\n * Invoked with (item, callback).\n * @param {Function} callback - A callback which is called after all the\n * `iteratee` functions have finished, or an error occurs. Results is the items\n * from the original `coll` sorted by the values returned by the `iteratee`\n * calls. Invoked with (err, results).\n * @example\n *\n * async.sortBy(['file1','file2','file3'], function(file, callback) {\n * fs.stat(file, function(err, stats) {\n * callback(err, stats.mtime);\n * });\n * }, function(err, results) {\n * // results is now the original array of files sorted by\n * // modified date\n * });\n *\n * // By modifying the callback parameter the\n * // sorting order can be influenced:\n *\n * // ascending order\n * async.sortBy([1,9,3,5], function(x, callback) {\n * callback(null, x);\n * }, function(err,result) {\n * // result callback\n * });\n *\n * // descending order\n * async.sortBy([1,9,3,5], function(x, callback) {\n * callback(null, x*-1); //<- x*-1 instead of x, turns the order around\n * }, function(err,result) {\n * // result callback\n * });\n */\nfunction sortBy (coll, iteratee, callback) {\n var _iteratee = wrapAsync(iteratee);\n map(coll, function (x, callback) {\n _iteratee(x, function (err, criteria) {\n if (err) return callback(err);\n callback(null, {value: x, criteria: criteria});\n });\n }, function (err, results) {\n if (err) return callback(err);\n callback(null, arrayMap(results.sort(comparator), baseProperty('value')));\n });\n\n function comparator(left, right) {\n var a = left.criteria, b = right.criteria;\n return a < b ? -1 : a > b ? 1 : 0;\n }\n}\n\n/**\n * Sets a time limit on an asynchronous function. If the function does not call\n * its callback within the specified milliseconds, it will be called with a\n * timeout error. The code property for the error object will be `'ETIMEDOUT'`.\n *\n * @name timeout\n * @static\n * @memberOf module:Utils\n * @method\n * @category Util\n * @param {AsyncFunction} asyncFn - The async function to limit in time.\n * @param {number} milliseconds - The specified time limit.\n * @param {*} [info] - Any variable you want attached (`string`, `object`, etc)\n * to timeout Error for more information..\n * @returns {AsyncFunction} Returns a wrapped function that can be used with any\n * of the control flow functions.\n * Invoke this function with the same parameters as you would `asyncFunc`.\n * @example\n *\n * function myFunction(foo, callback) {\n * doAsyncTask(foo, function(err, data) {\n * // handle errors\n * if (err) return callback(err);\n *\n * // do some stuff ...\n *\n * // return processed data\n * return callback(null, data);\n * });\n * }\n *\n * var wrapped = async.timeout(myFunction, 1000);\n *\n * // call `wrapped` as you would `myFunction`\n * wrapped({ bar: 'bar' }, function(err, data) {\n * // if `myFunction` takes < 1000 ms to execute, `err`\n * // and `data` will have their expected values\n *\n * // else `err` will be an Error with the code 'ETIMEDOUT'\n * });\n */\nfunction timeout(asyncFn, milliseconds, info) {\n var fn = wrapAsync(asyncFn);\n\n return initialParams(function (args, callback) {\n var timedOut = false;\n var timer;\n\n function timeoutCallback() {\n var name = asyncFn.name || 'anonymous';\n var error = new Error('Callback function \"' + name + '\" timed out.');\n error.code = 'ETIMEDOUT';\n if (info) {\n error.info = info;\n }\n timedOut = true;\n callback(error);\n }\n\n args.push(function () {\n if (!timedOut) {\n callback.apply(null, arguments);\n clearTimeout(timer);\n }\n });\n\n // setup timer and call original function\n timer = setTimeout(timeoutCallback, milliseconds);\n fn.apply(null, args);\n });\n}\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeCeil = Math.ceil;\nvar nativeMax = Math.max;\n\n/**\n * The base implementation of `_.range` and `_.rangeRight` which doesn't\n * coerce arguments.\n *\n * @private\n * @param {number} start The start of the range.\n * @param {number} end The end of the range.\n * @param {number} step The value to increment or decrement by.\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Array} Returns the range of numbers.\n */\nfunction baseRange(start, end, step, fromRight) {\n var index = -1,\n length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),\n result = Array(length);\n\n while (length--) {\n result[fromRight ? length : ++index] = start;\n start += step;\n }\n return result;\n}\n\n/**\n * The same as [times]{@link module:ControlFlow.times} but runs a maximum of `limit` async operations at a\n * time.\n *\n * @name timesLimit\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.times]{@link module:ControlFlow.times}\n * @category Control Flow\n * @param {number} count - The number of times to run the function.\n * @param {number} limit - The maximum number of async operations at a time.\n * @param {AsyncFunction} iteratee - The async function to call `n` times.\n * Invoked with the iteration index and a callback: (n, next).\n * @param {Function} callback - see [async.map]{@link module:Collections.map}.\n */\nfunction timeLimit(count, limit, iteratee, callback) {\n var _iteratee = wrapAsync(iteratee);\n mapLimit(baseRange(0, count, 1), limit, _iteratee, callback);\n}\n\n/**\n * Calls the `iteratee` function `n` times, and accumulates results in the same\n * manner you would use with [map]{@link module:Collections.map}.\n *\n * @name times\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.map]{@link module:Collections.map}\n * @category Control Flow\n * @param {number} n - The number of times to run the function.\n * @param {AsyncFunction} iteratee - The async function to call `n` times.\n * Invoked with the iteration index and a callback: (n, next).\n * @param {Function} callback - see {@link module:Collections.map}.\n * @example\n *\n * // Pretend this is some complicated async factory\n * var createUser = function(id, callback) {\n * callback(null, {\n * id: 'user' + id\n * });\n * };\n *\n * // generate 5 users\n * async.times(5, function(n, next) {\n * createUser(n, function(err, user) {\n * next(err, user);\n * });\n * }, function(err, users) {\n * // we should now have 5 users\n * });\n */\nvar times = doLimit(timeLimit, Infinity);\n\n/**\n * The same as [times]{@link module:ControlFlow.times} but runs only a single async operation at a time.\n *\n * @name timesSeries\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.times]{@link module:ControlFlow.times}\n * @category Control Flow\n * @param {number} n - The number of times to run the function.\n * @param {AsyncFunction} iteratee - The async function to call `n` times.\n * Invoked with the iteration index and a callback: (n, next).\n * @param {Function} callback - see {@link module:Collections.map}.\n */\nvar timesSeries = doLimit(timeLimit, 1);\n\n/**\n * A relative of `reduce`. Takes an Object or Array, and iterates over each\n * element in series, each step potentially mutating an `accumulator` value.\n * The type of the accumulator defaults to the type of collection passed in.\n *\n * @name transform\n * @static\n * @memberOf module:Collections\n * @method\n * @category Collection\n * @param {Array|Iterable|Object} coll - A collection to iterate over.\n * @param {*} [accumulator] - The initial state of the transform. If omitted,\n * it will default to an empty Object or Array, depending on the type of `coll`\n * @param {AsyncFunction} iteratee - A function applied to each item in the\n * collection that potentially modifies the accumulator.\n * Invoked with (accumulator, item, key, callback).\n * @param {Function} [callback] - A callback which is called after all the\n * `iteratee` functions have finished. Result is the transformed accumulator.\n * Invoked with (err, result).\n * @example\n *\n * async.transform([1,2,3], function(acc, item, index, callback) {\n * // pointless async:\n * process.nextTick(function() {\n * acc.push(item * 2)\n * callback(null)\n * });\n * }, function(err, result) {\n * // result is now equal to [2, 4, 6]\n * });\n *\n * @example\n *\n * async.transform({a: 1, b: 2, c: 3}, function (obj, val, key, callback) {\n * setImmediate(function () {\n * obj[key] = val * 2;\n * callback();\n * })\n * }, function (err, result) {\n * // result is equal to {a: 2, b: 4, c: 6}\n * })\n */\nfunction transform (coll, accumulator, iteratee, callback) {\n if (arguments.length <= 3) {\n callback = iteratee;\n iteratee = accumulator;\n accumulator = isArray(coll) ? [] : {};\n }\n callback = once(callback || noop);\n var _iteratee = wrapAsync(iteratee);\n\n eachOf(coll, function(v, k, cb) {\n _iteratee(accumulator, v, k, cb);\n }, function(err) {\n callback(err, accumulator);\n });\n}\n\n/**\n * It runs each task in series but stops whenever any of the functions were\n * successful. If one of the tasks were successful, the `callback` will be\n * passed the result of the successful task. If all tasks fail, the callback\n * will be passed the error and result (if any) of the final attempt.\n *\n * @name tryEach\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array|Iterable|Object} tasks - A collection containing functions to\n * run, each function is passed a `callback(err, result)` it must call on\n * completion with an error `err` (which can be `null`) and an optional `result`\n * value.\n * @param {Function} [callback] - An optional callback which is called when one\n * of the tasks has succeeded, or all have failed. It receives the `err` and\n * `result` arguments of the last attempt at completing the `task`. Invoked with\n * (err, results).\n * @example\n * async.tryEach([\n * function getDataFromFirstWebsite(callback) {\n * // Try getting the data from the first website\n * callback(err, data);\n * },\n * function getDataFromSecondWebsite(callback) {\n * // First website failed,\n * // Try getting the data from the backup website\n * callback(err, data);\n * }\n * ],\n * // optional callback\n * function(err, results) {\n * Now do something with the data.\n * });\n *\n */\nfunction tryEach(tasks, callback) {\n var error = null;\n var result;\n callback = callback || noop;\n eachSeries(tasks, function(task, callback) {\n wrapAsync(task)(function (err, res/*, ...args*/) {\n if (arguments.length > 2) {\n result = slice(arguments, 1);\n } else {\n result = res;\n }\n error = err;\n callback(!err);\n });\n }, function () {\n callback(error, result);\n });\n}\n\n/**\n * Undoes a [memoize]{@link module:Utils.memoize}d function, reverting it to the original,\n * unmemoized form. Handy for testing.\n *\n * @name unmemoize\n * @static\n * @memberOf module:Utils\n * @method\n * @see [async.memoize]{@link module:Utils.memoize}\n * @category Util\n * @param {AsyncFunction} fn - the memoized function\n * @returns {AsyncFunction} a function that calls the original unmemoized function\n */\nfunction unmemoize(fn) {\n return function () {\n return (fn.unmemoized || fn).apply(null, arguments);\n };\n}\n\n/**\n * Repeatedly call `iteratee`, while `test` returns `true`. Calls `callback` when\n * stopped, or an error occurs.\n *\n * @name whilst\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Function} test - synchronous truth test to perform before each\n * execution of `iteratee`. Invoked with ().\n * @param {AsyncFunction} iteratee - An async function which is called each time\n * `test` passes. Invoked with (callback).\n * @param {Function} [callback] - A callback which is called after the test\n * function has failed and repeated execution of `iteratee` has stopped. `callback`\n * will be passed an error and any arguments passed to the final `iteratee`'s\n * callback. Invoked with (err, [results]);\n * @returns undefined\n * @example\n *\n * var count = 0;\n * async.whilst(\n * function() { return count < 5; },\n * function(callback) {\n * count++;\n * setTimeout(function() {\n * callback(null, count);\n * }, 1000);\n * },\n * function (err, n) {\n * // 5 seconds have passed, n = 5\n * }\n * );\n */\nfunction whilst(test, iteratee, callback) {\n callback = onlyOnce(callback || noop);\n var _iteratee = wrapAsync(iteratee);\n if (!test()) return callback(null);\n var next = function(err/*, ...args*/) {\n if (err) return callback(err);\n if (test()) return _iteratee(next);\n var args = slice(arguments, 1);\n callback.apply(null, [null].concat(args));\n };\n _iteratee(next);\n}\n\n/**\n * Repeatedly call `iteratee` until `test` returns `true`. Calls `callback` when\n * stopped, or an error occurs. `callback` will be passed an error and any\n * arguments passed to the final `iteratee`'s callback.\n *\n * The inverse of [whilst]{@link module:ControlFlow.whilst}.\n *\n * @name until\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @see [async.whilst]{@link module:ControlFlow.whilst}\n * @category Control Flow\n * @param {Function} test - synchronous truth test to perform before each\n * execution of `iteratee`. Invoked with ().\n * @param {AsyncFunction} iteratee - An async function which is called each time\n * `test` fails. Invoked with (callback).\n * @param {Function} [callback] - A callback which is called after the test\n * function has passed and repeated execution of `iteratee` has stopped. `callback`\n * will be passed an error and any arguments passed to the final `iteratee`'s\n * callback. Invoked with (err, [results]);\n */\nfunction until(test, iteratee, callback) {\n whilst(function() {\n return !test.apply(this, arguments);\n }, iteratee, callback);\n}\n\n/**\n * Runs the `tasks` array of functions in series, each passing their results to\n * the next in the array. However, if any of the `tasks` pass an error to their\n * own callback, the next function is not executed, and the main `callback` is\n * immediately called with the error.\n *\n * @name waterfall\n * @static\n * @memberOf module:ControlFlow\n * @method\n * @category Control Flow\n * @param {Array} tasks - An array of [async functions]{@link AsyncFunction}\n * to run.\n * Each function should complete with any number of `result` values.\n * The `result` values will be passed as arguments, in order, to the next task.\n * @param {Function} [callback] - An optional callback to run once all the\n * functions have completed. This will be passed the results of the last task's\n * callback. Invoked with (err, [results]).\n * @returns undefined\n * @example\n *\n * async.waterfall([\n * function(callback) {\n * callback(null, 'one', 'two');\n * },\n * function(arg1, arg2, callback) {\n * // arg1 now equals 'one' and arg2 now equals 'two'\n * callback(null, 'three');\n * },\n * function(arg1, callback) {\n * // arg1 now equals 'three'\n * callback(null, 'done');\n * }\n * ], function (err, result) {\n * // result now equals 'done'\n * });\n *\n * // Or, with named functions:\n * async.waterfall([\n * myFirstFunction,\n * mySecondFunction,\n * myLastFunction,\n * ], function (err, result) {\n * // result now equals 'done'\n * });\n * function myFirstFunction(callback) {\n * callback(null, 'one', 'two');\n * }\n * function mySecondFunction(arg1, arg2, callback) {\n * // arg1 now equals 'one' and arg2 now equals 'two'\n * callback(null, 'three');\n * }\n * function myLastFunction(arg1, callback) {\n * // arg1 now equals 'three'\n * callback(null, 'done');\n * }\n */\nvar waterfall = function(tasks, callback) {\n callback = once(callback || noop);\n if (!isArray(tasks)) return callback(new Error('First argument to waterfall must be an array of functions'));\n if (!tasks.length) return callback();\n var taskIndex = 0;\n\n function nextTask(args) {\n var task = wrapAsync(tasks[taskIndex++]);\n args.push(onlyOnce(next));\n task.apply(null, args);\n }\n\n function next(err/*, ...args*/) {\n if (err || taskIndex === tasks.length) {\n return callback.apply(null, arguments);\n }\n nextTask(slice(arguments, 1));\n }\n\n nextTask([]);\n};\n\n/**\n * An \"async function\" in the context of Async is an asynchronous function with\n * a variable number of parameters, with the final parameter being a callback.\n * (`function (arg1, arg2, ..., callback) {}`)\n * The final callback is of the form `callback(err, results...)`, which must be\n * called once the function is completed. The callback should be called with a\n * Error as its first argument to signal that an error occurred.\n * Otherwise, if no error occurred, it should be called with `null` as the first\n * argument, and any additional `result` arguments that may apply, to signal\n * successful completion.\n * The callback must be called exactly once, ideally on a later tick of the\n * JavaScript event loop.\n *\n * This type of function is also referred to as a \"Node-style async function\",\n * or a \"continuation passing-style function\" (CPS). Most of the methods of this\n * library are themselves CPS/Node-style async functions, or functions that\n * return CPS/Node-style async functions.\n *\n * Wherever we accept a Node-style async function, we also directly accept an\n * [ES2017 `async` function]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function}.\n * In this case, the `async` function will not be passed a final callback\n * argument, and any thrown error will be used as the `err` argument of the\n * implicit callback, and the return value will be used as the `result` value.\n * (i.e. a `rejected` of the returned Promise becomes the `err` callback\n * argument, and a `resolved` value becomes the `result`.)\n *\n * Note, due to JavaScript limitations, we can only detect native `async`\n * functions and not transpilied implementations.\n * Your environment must have `async`/`await` support for this to work.\n * (e.g. Node > v7.6, or a recent version of a modern browser).\n * If you are using `async` functions through a transpiler (e.g. Babel), you\n * must still wrap the function with [asyncify]{@link module:Utils.asyncify},\n * because the `async function` will be compiled to an ordinary function that\n * returns a promise.\n *\n * @typedef {Function} AsyncFunction\n * @static\n */\n\n/**\n * Async is a utility module which provides straight-forward, powerful functions\n * for working with asynchronous JavaScript. Although originally designed for\n * use with [Node.js](http://nodejs.org) and installable via\n * `npm install --save async`, it can also be used directly in the browser.\n * @module async\n * @see AsyncFunction\n */\n\n\n/**\n * A collection of `async` functions for manipulating collections, such as\n * arrays and objects.\n * @module Collections\n */\n\n/**\n * A collection of `async` functions for controlling the flow through a script.\n * @module ControlFlow\n */\n\n/**\n * A collection of `async` utility functions.\n * @module Utils\n */\n\nvar index = {\n apply: apply,\n applyEach: applyEach,\n applyEachSeries: applyEachSeries,\n asyncify: asyncify,\n auto: auto,\n autoInject: autoInject,\n cargo: cargo,\n compose: compose,\n concat: concat,\n concatLimit: concatLimit,\n concatSeries: concatSeries,\n constant: constant,\n detect: detect,\n detectLimit: detectLimit,\n detectSeries: detectSeries,\n dir: dir,\n doDuring: doDuring,\n doUntil: doUntil,\n doWhilst: doWhilst,\n during: during,\n each: eachLimit,\n eachLimit: eachLimit$1,\n eachOf: eachOf,\n eachOfLimit: eachOfLimit,\n eachOfSeries: eachOfSeries,\n eachSeries: eachSeries,\n ensureAsync: ensureAsync,\n every: every,\n everyLimit: everyLimit,\n everySeries: everySeries,\n filter: filter,\n filterLimit: filterLimit,\n filterSeries: filterSeries,\n forever: forever,\n groupBy: groupBy,\n groupByLimit: groupByLimit,\n groupBySeries: groupBySeries,\n log: log,\n map: map,\n mapLimit: mapLimit,\n mapSeries: mapSeries,\n mapValues: mapValues,\n mapValuesLimit: mapValuesLimit,\n mapValuesSeries: mapValuesSeries,\n memoize: memoize,\n nextTick: nextTick,\n parallel: parallelLimit,\n parallelLimit: parallelLimit$1,\n priorityQueue: priorityQueue,\n queue: queue$1,\n race: race,\n reduce: reduce,\n reduceRight: reduceRight,\n reflect: reflect,\n reflectAll: reflectAll,\n reject: reject,\n rejectLimit: rejectLimit,\n rejectSeries: rejectSeries,\n retry: retry,\n retryable: retryable,\n seq: seq,\n series: series,\n setImmediate: setImmediate$1,\n some: some,\n someLimit: someLimit,\n someSeries: someSeries,\n sortBy: sortBy,\n timeout: timeout,\n times: times,\n timesLimit: timeLimit,\n timesSeries: timesSeries,\n transform: transform,\n tryEach: tryEach,\n unmemoize: unmemoize,\n until: until,\n waterfall: waterfall,\n whilst: whilst,\n\n // aliases\n all: every,\n allLimit: everyLimit,\n allSeries: everySeries,\n any: some,\n anyLimit: someLimit,\n anySeries: someSeries,\n find: detect,\n findLimit: detectLimit,\n findSeries: detectSeries,\n forEach: eachLimit,\n forEachSeries: eachSeries,\n forEachLimit: eachLimit$1,\n forEachOf: eachOf,\n forEachOfSeries: eachOfSeries,\n forEachOfLimit: eachOfLimit,\n inject: reduce,\n foldl: reduce,\n foldr: reduceRight,\n select: filter,\n selectLimit: filterLimit,\n selectSeries: filterSeries,\n wrapSync: asyncify\n};\n\nexports['default'] = index;\nexports.apply = apply;\nexports.applyEach = applyEach;\nexports.applyEachSeries = applyEachSeries;\nexports.asyncify = asyncify;\nexports.auto = auto;\nexports.autoInject = autoInject;\nexports.cargo = cargo;\nexports.compose = compose;\nexports.concat = concat;\nexports.concatLimit = concatLimit;\nexports.concatSeries = concatSeries;\nexports.constant = constant;\nexports.detect = detect;\nexports.detectLimit = detectLimit;\nexports.detectSeries = detectSeries;\nexports.dir = dir;\nexports.doDuring = doDuring;\nexports.doUntil = doUntil;\nexports.doWhilst = doWhilst;\nexports.during = during;\nexports.each = eachLimit;\nexports.eachLimit = eachLimit$1;\nexports.eachOf = eachOf;\nexports.eachOfLimit = eachOfLimit;\nexports.eachOfSeries = eachOfSeries;\nexports.eachSeries = eachSeries;\nexports.ensureAsync = ensureAsync;\nexports.every = every;\nexports.everyLimit = everyLimit;\nexports.everySeries = everySeries;\nexports.filter = filter;\nexports.filterLimit = filterLimit;\nexports.filterSeries = filterSeries;\nexports.forever = forever;\nexports.groupBy = groupBy;\nexports.groupByLimit = groupByLimit;\nexports.groupBySeries = groupBySeries;\nexports.log = log;\nexports.map = map;\nexports.mapLimit = mapLimit;\nexports.mapSeries = mapSeries;\nexports.mapValues = mapValues;\nexports.mapValuesLimit = mapValuesLimit;\nexports.mapValuesSeries = mapValuesSeries;\nexports.memoize = memoize;\nexports.nextTick = nextTick;\nexports.parallel = parallelLimit;\nexports.parallelLimit = parallelLimit$1;\nexports.priorityQueue = priorityQueue;\nexports.queue = queue$1;\nexports.race = race;\nexports.reduce = reduce;\nexports.reduceRight = reduceRight;\nexports.reflect = reflect;\nexports.reflectAll = reflectAll;\nexports.reject = reject;\nexports.rejectLimit = rejectLimit;\nexports.rejectSeries = rejectSeries;\nexports.retry = retry;\nexports.retryable = retryable;\nexports.seq = seq;\nexports.series = series;\nexports.setImmediate = setImmediate$1;\nexports.some = some;\nexports.someLimit = someLimit;\nexports.someSeries = someSeries;\nexports.sortBy = sortBy;\nexports.timeout = timeout;\nexports.times = times;\nexports.timesLimit = timeLimit;\nexports.timesSeries = timesSeries;\nexports.transform = transform;\nexports.tryEach = tryEach;\nexports.unmemoize = unmemoize;\nexports.until = until;\nexports.waterfall = waterfall;\nexports.whilst = whilst;\nexports.all = every;\nexports.allLimit = everyLimit;\nexports.allSeries = everySeries;\nexports.any = some;\nexports.anyLimit = someLimit;\nexports.anySeries = someSeries;\nexports.find = detect;\nexports.findLimit = detectLimit;\nexports.findSeries = detectSeries;\nexports.forEach = eachLimit;\nexports.forEachSeries = eachSeries;\nexports.forEachLimit = eachLimit$1;\nexports.forEachOf = eachOf;\nexports.forEachOfSeries = eachOfSeries;\nexports.forEachOfLimit = eachOfLimit;\nexports.inject = reduce;\nexports.foldl = reduce;\nexports.foldr = reduceRight;\nexports.select = filter;\nexports.selectLimit = filterLimit;\nexports.selectSeries = filterSeries;\nexports.wrapSync = asyncify;\n\nObject.defineProperty(exports, '__esModule', { value: true });\n\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 (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_algo = C.algo;\n\n\t // Initialization and round constants tables\n\t var H = [];\n\t var K = [];\n\n\t // Compute constants\n\t (function () {\n\t function isPrime(n) {\n\t var sqrtN = Math.sqrt(n);\n\t for (var factor = 2; factor <= sqrtN; factor++) {\n\t if (!(n % factor)) {\n\t return false;\n\t }\n\t }\n\n\t return true;\n\t }\n\n\t function getFractionalBits(n) {\n\t return ((n - (n | 0)) * 0x100000000) | 0;\n\t }\n\n\t var n = 2;\n\t var nPrime = 0;\n\t while (nPrime < 64) {\n\t if (isPrime(n)) {\n\t if (nPrime < 8) {\n\t H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2));\n\t }\n\t K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3));\n\n\t nPrime++;\n\t }\n\n\t n++;\n\t }\n\t }());\n\n\t // Reusable object\n\t var W = [];\n\n\t /**\n\t * SHA-256 hash algorithm.\n\t */\n\t var SHA256 = C_algo.SHA256 = Hasher.extend({\n\t _doReset: function () {\n\t this._hash = new WordArray.init(H.slice(0));\n\t },\n\n\t _doProcessBlock: function (M, offset) {\n\t // Shortcut\n\t var H = this._hash.words;\n\n\t // Working variables\n\t var a = H[0];\n\t var b = H[1];\n\t var c = H[2];\n\t var d = H[3];\n\t var e = H[4];\n\t var f = H[5];\n\t var g = H[6];\n\t var h = H[7];\n\n\t // Computation\n\t for (var i = 0; i < 64; i++) {\n\t if (i < 16) {\n\t W[i] = M[offset + i] | 0;\n\t } else {\n\t var gamma0x = W[i - 15];\n\t var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^\n\t ((gamma0x << 14) | (gamma0x >>> 18)) ^\n\t (gamma0x >>> 3);\n\n\t var gamma1x = W[i - 2];\n\t var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^\n\t ((gamma1x << 13) | (gamma1x >>> 19)) ^\n\t (gamma1x >>> 10);\n\n\t W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16];\n\t }\n\n\t var ch = (e & f) ^ (~e & g);\n\t var maj = (a & b) ^ (a & c) ^ (b & c);\n\n\t var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22));\n\t var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25));\n\n\t var t1 = h + sigma1 + ch + K[i] + W[i];\n\t var t2 = sigma0 + maj;\n\n\t h = g;\n\t g = f;\n\t f = e;\n\t e = (d + t1) | 0;\n\t d = c;\n\t c = b;\n\t b = a;\n\t a = (t1 + t2) | 0;\n\t }\n\n\t // Intermediate hash value\n\t H[0] = (H[0] + a) | 0;\n\t H[1] = (H[1] + b) | 0;\n\t H[2] = (H[2] + c) | 0;\n\t H[3] = (H[3] + d) | 0;\n\t H[4] = (H[4] + e) | 0;\n\t H[5] = (H[5] + f) | 0;\n\t H[6] = (H[6] + g) | 0;\n\t H[7] = (H[7] + h) | 0;\n\t },\n\n\t _doFinalize: function () {\n\t // Shortcuts\n\t var data = this._data;\n\t var dataWords = data.words;\n\n\t var nBitsTotal = this._nDataBytes * 8;\n\t var nBitsLeft = data.sigBytes * 8;\n\n\t // Add padding\n\t dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);\n\t dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000);\n\t dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal;\n\t data.sigBytes = dataWords.length * 4;\n\n\t // Hash final blocks\n\t this._process();\n\n\t // Return final computed hash\n\t return this._hash;\n\t },\n\n\t clone: function () {\n\t var clone = Hasher.clone.call(this);\n\t clone._hash = this._hash.clone();\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.SHA256('message');\n\t * var hash = CryptoJS.SHA256(wordArray);\n\t */\n\t C.SHA256 = Hasher._createHelper(SHA256);\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.HmacSHA256(message, key);\n\t */\n\t C.HmacSHA256 = Hasher._createHmacHelper(SHA256);\n\t}(Math));\n\n\n\treturn CryptoJS.SHA256;\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 () {\n\t // Shortcuts\n\t var C = CryptoJS;\n\t var C_lib = C.lib;\n\t var Hasher = C_lib.Hasher;\n\t var C_x64 = C.x64;\n\t var X64Word = C_x64.Word;\n\t var X64WordArray = C_x64.WordArray;\n\t var C_algo = C.algo;\n\n\t function X64Word_create() {\n\t return X64Word.create.apply(X64Word, arguments);\n\t }\n\n\t // Constants\n\t var K = [\n\t X64Word_create(0x428a2f98, 0xd728ae22), X64Word_create(0x71374491, 0x23ef65cd),\n\t X64Word_create(0xb5c0fbcf, 0xec4d3b2f), X64Word_create(0xe9b5dba5, 0x8189dbbc),\n\t X64Word_create(0x3956c25b, 0xf348b538), X64Word_create(0x59f111f1, 0xb605d019),\n\t X64Word_create(0x923f82a4, 0xaf194f9b), X64Word_create(0xab1c5ed5, 0xda6d8118),\n\t X64Word_create(0xd807aa98, 0xa3030242), X64Word_create(0x12835b01, 0x45706fbe),\n\t X64Word_create(0x243185be, 0x4ee4b28c), X64Word_create(0x550c7dc3, 0xd5ffb4e2),\n\t X64Word_create(0x72be5d74, 0xf27b896f), X64Word_create(0x80deb1fe, 0x3b1696b1),\n\t X64Word_create(0x9bdc06a7, 0x25c71235), X64Word_create(0xc19bf174, 0xcf692694),\n\t X64Word_create(0xe49b69c1, 0x9ef14ad2), X64Word_create(0xefbe4786, 0x384f25e3),\n\t X64Word_create(0x0fc19dc6, 0x8b8cd5b5), X64Word_create(0x240ca1cc, 0x77ac9c65),\n\t X64Word_create(0x2de92c6f, 0x592b0275), X64Word_create(0x4a7484aa, 0x6ea6e483),\n\t X64Word_create(0x5cb0a9dc, 0xbd41fbd4), X64Word_create(0x76f988da, 0x831153b5),\n\t X64Word_create(0x983e5152, 0xee66dfab), X64Word_create(0xa831c66d, 0x2db43210),\n\t X64Word_create(0xb00327c8, 0x98fb213f), X64Word_create(0xbf597fc7, 0xbeef0ee4),\n\t X64Word_create(0xc6e00bf3, 0x3da88fc2), X64Word_create(0xd5a79147, 0x930aa725),\n\t X64Word_create(0x06ca6351, 0xe003826f), X64Word_create(0x14292967, 0x0a0e6e70),\n\t X64Word_create(0x27b70a85, 0x46d22ffc), X64Word_create(0x2e1b2138, 0x5c26c926),\n\t X64Word_create(0x4d2c6dfc, 0x5ac42aed), X64Word_create(0x53380d13, 0x9d95b3df),\n\t X64Word_create(0x650a7354, 0x8baf63de), X64Word_create(0x766a0abb, 0x3c77b2a8),\n\t X64Word_create(0x81c2c92e, 0x47edaee6), X64Word_create(0x92722c85, 0x1482353b),\n\t X64Word_create(0xa2bfe8a1, 0x4cf10364), X64Word_create(0xa81a664b, 0xbc423001),\n\t X64Word_create(0xc24b8b70, 0xd0f89791), X64Word_create(0xc76c51a3, 0x0654be30),\n\t X64Word_create(0xd192e819, 0xd6ef5218), X64Word_create(0xd6990624, 0x5565a910),\n\t X64Word_create(0xf40e3585, 0x5771202a), X64Word_create(0x106aa070, 0x32bbd1b8),\n\t X64Word_create(0x19a4c116, 0xb8d2d0c8), X64Word_create(0x1e376c08, 0x5141ab53),\n\t X64Word_create(0x2748774c, 0xdf8eeb99), X64Word_create(0x34b0bcb5, 0xe19b48a8),\n\t X64Word_create(0x391c0cb3, 0xc5c95a63), X64Word_create(0x4ed8aa4a, 0xe3418acb),\n\t X64Word_create(0x5b9cca4f, 0x7763e373), X64Word_create(0x682e6ff3, 0xd6b2b8a3),\n\t X64Word_create(0x748f82ee, 0x5defb2fc), X64Word_create(0x78a5636f, 0x43172f60),\n\t X64Word_create(0x84c87814, 0xa1f0ab72), X64Word_create(0x8cc70208, 0x1a6439ec),\n\t X64Word_create(0x90befffa, 0x23631e28), X64Word_create(0xa4506ceb, 0xde82bde9),\n\t X64Word_create(0xbef9a3f7, 0xb2c67915), X64Word_create(0xc67178f2, 0xe372532b),\n\t X64Word_create(0xca273ece, 0xea26619c), X64Word_create(0xd186b8c7, 0x21c0c207),\n\t X64Word_create(0xeada7dd6, 0xcde0eb1e), X64Word_create(0xf57d4f7f, 0xee6ed178),\n\t X64Word_create(0x06f067aa, 0x72176fba), X64Word_create(0x0a637dc5, 0xa2c898a6),\n\t X64Word_create(0x113f9804, 0xbef90dae), X64Word_create(0x1b710b35, 0x131c471b),\n\t X64Word_create(0x28db77f5, 0x23047d84), X64Word_create(0x32caab7b, 0x40c72493),\n\t X64Word_create(0x3c9ebe0a, 0x15c9bebc), X64Word_create(0x431d67c4, 0x9c100d4c),\n\t X64Word_create(0x4cc5d4be, 0xcb3e42b6), X64Word_create(0x597f299c, 0xfc657e2a),\n\t X64Word_create(0x5fcb6fab, 0x3ad6faec), X64Word_create(0x6c44198c, 0x4a475817)\n\t ];\n\n\t // Reusable objects\n\t var W = [];\n\t (function () {\n\t for (var i = 0; i < 80; i++) {\n\t W[i] = X64Word_create();\n\t }\n\t }());\n\n\t /**\n\t * SHA-512 hash algorithm.\n\t */\n\t var SHA512 = C_algo.SHA512 = Hasher.extend({\n\t _doReset: function () {\n\t this._hash = new X64WordArray.init([\n\t new X64Word.init(0x6a09e667, 0xf3bcc908), new X64Word.init(0xbb67ae85, 0x84caa73b),\n\t new X64Word.init(0x3c6ef372, 0xfe94f82b), new X64Word.init(0xa54ff53a, 0x5f1d36f1),\n\t new X64Word.init(0x510e527f, 0xade682d1), new X64Word.init(0x9b05688c, 0x2b3e6c1f),\n\t new X64Word.init(0x1f83d9ab, 0xfb41bd6b), new X64Word.init(0x5be0cd19, 0x137e2179)\n\t ]);\n\t },\n\n\t _doProcessBlock: function (M, offset) {\n\t // Shortcuts\n\t var H = this._hash.words;\n\n\t var H0 = H[0];\n\t var H1 = H[1];\n\t var H2 = H[2];\n\t var H3 = H[3];\n\t var H4 = H[4];\n\t var H5 = H[5];\n\t var H6 = H[6];\n\t var H7 = H[7];\n\n\t var H0h = H0.high;\n\t var H0l = H0.low;\n\t var H1h = H1.high;\n\t var H1l = H1.low;\n\t var H2h = H2.high;\n\t var H2l = H2.low;\n\t var H3h = H3.high;\n\t var H3l = H3.low;\n\t var H4h = H4.high;\n\t var H4l = H4.low;\n\t var H5h = H5.high;\n\t var H5l = H5.low;\n\t var H6h = H6.high;\n\t var H6l = H6.low;\n\t var H7h = H7.high;\n\t var H7l = H7.low;\n\n\t // Working variables\n\t var ah = H0h;\n\t var al = H0l;\n\t var bh = H1h;\n\t var bl = H1l;\n\t var ch = H2h;\n\t var cl = H2l;\n\t var dh = H3h;\n\t var dl = H3l;\n\t var eh = H4h;\n\t var el = H4l;\n\t var fh = H5h;\n\t var fl = H5l;\n\t var gh = H6h;\n\t var gl = H6l;\n\t var hh = H7h;\n\t var hl = H7l;\n\n\t // Rounds\n\t for (var i = 0; i < 80; i++) {\n\t var Wil;\n\t var Wih;\n\n\t // Shortcut\n\t var Wi = W[i];\n\n\t // Extend message\n\t if (i < 16) {\n\t Wih = Wi.high = M[offset + i * 2] | 0;\n\t Wil = Wi.low = M[offset + i * 2 + 1] | 0;\n\t } else {\n\t // Gamma0\n\t var gamma0x = W[i - 15];\n\t var gamma0xh = gamma0x.high;\n\t var gamma0xl = gamma0x.low;\n\t var gamma0h = ((gamma0xh >>> 1) | (gamma0xl << 31)) ^ ((gamma0xh >>> 8) | (gamma0xl << 24)) ^ (gamma0xh >>> 7);\n\t var gamma0l = ((gamma0xl >>> 1) | (gamma0xh << 31)) ^ ((gamma0xl >>> 8) | (gamma0xh << 24)) ^ ((gamma0xl >>> 7) | (gamma0xh << 25));\n\n\t // Gamma1\n\t var gamma1x = W[i - 2];\n\t var gamma1xh = gamma1x.high;\n\t var gamma1xl = gamma1x.low;\n\t var gamma1h = ((gamma1xh >>> 19) | (gamma1xl << 13)) ^ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^ (gamma1xh >>> 6);\n\t var gamma1l = ((gamma1xl >>> 19) | (gamma1xh << 13)) ^ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^ ((gamma1xl >>> 6) | (gamma1xh << 26));\n\n\t // W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]\n\t var Wi7 = W[i - 7];\n\t var Wi7h = Wi7.high;\n\t var Wi7l = Wi7.low;\n\n\t var Wi16 = W[i - 16];\n\t var Wi16h = Wi16.high;\n\t var Wi16l = Wi16.low;\n\n\t Wil = gamma0l + Wi7l;\n\t Wih = gamma0h + Wi7h + ((Wil >>> 0) < (gamma0l >>> 0) ? 1 : 0);\n\t Wil = Wil + gamma1l;\n\t Wih = Wih + gamma1h + ((Wil >>> 0) < (gamma1l >>> 0) ? 1 : 0);\n\t Wil = Wil + Wi16l;\n\t Wih = Wih + Wi16h + ((Wil >>> 0) < (Wi16l >>> 0) ? 1 : 0);\n\n\t Wi.high = Wih;\n\t Wi.low = Wil;\n\t }\n\n\t var chh = (eh & fh) ^ (~eh & gh);\n\t var chl = (el & fl) ^ (~el & gl);\n\t var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch);\n\t var majl = (al & bl) ^ (al & cl) ^ (bl & cl);\n\n\t var sigma0h = ((ah >>> 28) | (al << 4)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7));\n\t var sigma0l = ((al >>> 28) | (ah << 4)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7));\n\t var sigma1h = ((eh >>> 14) | (el << 18)) ^ ((eh >>> 18) | (el << 14)) ^ ((eh << 23) | (el >>> 9));\n\t var sigma1l = ((el >>> 14) | (eh << 18)) ^ ((el >>> 18) | (eh << 14)) ^ ((el << 23) | (eh >>> 9));\n\n\t // t1 = h + sigma1 + ch + K[i] + W[i]\n\t var Ki = K[i];\n\t var Kih = Ki.high;\n\t var Kil = Ki.low;\n\n\t var t1l = hl + sigma1l;\n\t var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0);\n\t var t1l = t1l + chl;\n\t var t1h = t1h + chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0);\n\t var t1l = t1l + Kil;\n\t var t1h = t1h + Kih + ((t1l >>> 0) < (Kil >>> 0) ? 1 : 0);\n\t var t1l = t1l + Wil;\n\t var t1h = t1h + Wih + ((t1l >>> 0) < (Wil >>> 0) ? 1 : 0);\n\n\t // t2 = sigma0 + maj\n\t var t2l = sigma0l + majl;\n\t var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0);\n\n\t // Update working variables\n\t hh = gh;\n\t hl = gl;\n\t gh = fh;\n\t gl = fl;\n\t fh = eh;\n\t fl = el;\n\t el = (dl + t1l) | 0;\n\t eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;\n\t dh = ch;\n\t dl = cl;\n\t ch = bh;\n\t cl = bl;\n\t bh = ah;\n\t bl = al;\n\t al = (t1l + t2l) | 0;\n\t ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0;\n\t }\n\n\t // Intermediate hash value\n\t H0l = H0.low = (H0l + al);\n\t H0.high = (H0h + ah + ((H0l >>> 0) < (al >>> 0) ? 1 : 0));\n\t H1l = H1.low = (H1l + bl);\n\t H1.high = (H1h + bh + ((H1l >>> 0) < (bl >>> 0) ? 1 : 0));\n\t H2l = H2.low = (H2l + cl);\n\t H2.high = (H2h + ch + ((H2l >>> 0) < (cl >>> 0) ? 1 : 0));\n\t H3l = H3.low = (H3l + dl);\n\t H3.high = (H3h + dh + ((H3l >>> 0) < (dl >>> 0) ? 1 : 0));\n\t H4l = H4.low = (H4l + el);\n\t H4.high = (H4h + eh + ((H4l >>> 0) < (el >>> 0) ? 1 : 0));\n\t H5l = H5.low = (H5l + fl);\n\t H5.high = (H5h + fh + ((H5l >>> 0) < (fl >>> 0) ? 1 : 0));\n\t H6l = H6.low = (H6l + gl);\n\t H6.high = (H6h + gh + ((H6l >>> 0) < (gl >>> 0) ? 1 : 0));\n\t H7l = H7.low = (H7l + hl);\n\t H7.high = (H7h + hh + ((H7l >>> 0) < (hl >>> 0) ? 1 : 0));\n\t },\n\n\t _doFinalize: function () {\n\t // Shortcuts\n\t var data = this._data;\n\t var dataWords = data.words;\n\n\t var nBitsTotal = this._nDataBytes * 8;\n\t var nBitsLeft = data.sigBytes * 8;\n\n\t // Add padding\n\t dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);\n\t dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 30] = Math.floor(nBitsTotal / 0x100000000);\n\t dataWords[(((nBitsLeft + 128) >>> 10) << 5) + 31] = nBitsTotal;\n\t data.sigBytes = dataWords.length * 4;\n\n\t // Hash final blocks\n\t this._process();\n\n\t // Convert hash to 32-bit word array before returning\n\t var hash = this._hash.toX32();\n\n\t // Return final computed hash\n\t return hash;\n\t },\n\n\t clone: function () {\n\t var clone = Hasher.clone.call(this);\n\t clone._hash = this._hash.clone();\n\n\t return clone;\n\t },\n\n\t blockSize: 1024/32\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.SHA512('message');\n\t * var hash = CryptoJS.SHA512(wordArray);\n\t */\n\t C.SHA512 = Hasher._createHelper(SHA512);\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.HmacSHA512(message, key);\n\t */\n\t C.HmacSHA512 = Hasher._createHmacHelper(SHA512);\n\t}());\n\n\n\treturn CryptoJS.SHA512;\n\n}));","/**\n * SSL options for remote endpoints.\n */\nclass SslOptions {\n \n constructor(state) {\n this.state = Object.assign({}, state);\n }\n \n getPrivateKeyPath() {\n return this.state.privateKeyPath;\n }\n \n setPrivateKeyPath(privateKeyPath) {\n this.state.privateKeyPath = privateKeyPath;\n return this;\n }\n \n getCertificatePath() {\n return this.state.certificatePath;\n }\n \n setCertificatePath(certificatePath) {\n this.state.certificatePath = certificatePath;\n return this;\n }\n \n getCertificateAuthorityFile() {\n return this.state.certificateAuthorityFile;\n }\n \n setCertificateAuthorityFile(certificateAuthorityFile) {\n this.state.certificateAuthorityFile = certificateAuthorityFile;\n return this;\n }\n \n getAllowedFingerprints() {\n return this.state.allowedFingerprints;\n }\n \n setAllowedFingerprints(allowedFingerprints) {\n this.state.allowedFingerprints = allowedFingerprints;\n return this;\n }\n \n getAllowAnyCert() {\n return this.state.allowAnyCert;\n }\n \n setAllowAnyCert(allowAnyCert) {\n this.state.allowAnyCert = allowAnyCert;\n return this;\n }\n}\n\nmodule.exports = SslOptions;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\n\n/**\n * Models an alternative chain seen by the node.\n */\nclass MoneroAltChain {\n \n constructor(state) {\n state = Object.assign({}, state);\n if (state.difficulty !== undefined && !(state.difficulty instanceof BigInteger)) state.difficulty = BigInteger.parse(state.difficulty);\n this.state = state;\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (this.getDifficulty()) json.difficulty = this.getDifficulty().toString();\n return json;\n }\n \n getBlockHashes(blockHashes) {\n return this.state.blockHashes;\n }\n \n setBlockHashes(blockHashes) {\n this.state.blockHashes = blockHashes;\n return this;\n }\n \n getDifficulty() {\n return this.state.difficulty;\n }\n \n setDifficulty(difficulty) {\n this.state.difficulty = difficulty;\n return this;\n }\n \n getHeight() {\n return this.state.height;\n }\n \n setHeight(height) {\n this.state.height = height;\n return this;\n }\n \n getLength() {\n return this.state.length;\n }\n \n setLength(length) {\n this.state.length = length;\n return this;\n }\n \n getMainChainParentBlockHash() {\n return this.state.mainChainParentBlockHash;\n }\n \n setMainChainParentBlockHash(mainChainParentBlockHash) {\n this.state.mainChainParentBlockHash = mainChainParentBlockHash;\n return this;\n }\n}\n\nmodule.exports = MoneroAltChain;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\n\n/**\n * Monero block template to mine.\n */\nclass MoneroBlockTemplate {\n \n constructor(state) {\n state = Object.assign({}, state);\n this.state = state;\n \n // deserialize BigIntegers\n if (state.expectedReward !== undefined && !(state.expectedReward instanceof BigInteger)) state.expectedReward = BigInteger.parse(state.expectedReward);\n if (state.difficulty !== undefined && !(state.difficulty instanceof BigInteger)) state.difficulty = BigInteger.parse(state.difficulty);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (this.getExpectedReward()) json.expectedReward = this.getExpectedReward().toString();\n if (this.getDifficulty()) json.difficulty = this.getDifficulty().toString();\n return json;\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (json.expectedReward) json.expectedReward = json.expectedReward.toString();\n if (json.difficulty) json.difficulty = json.difficulty.toString();\n return json;\n }\n \n getBlockTemplateBlob() {\n return this.state.blockTemplateBlob;\n }\n \n setBlockTemplateBlob(blockTemplateBlob) {\n this.state.blockTemplateBlob = blockTemplateBlob;\n return this;\n }\n \n getBlockHashingBlob() {\n return this.state.blockHashingBlob;\n }\n \n setBlockHashingBlob(blockHashingBlob) {\n this.state.blockHashingBlob = blockHashingBlob;\n return this;\n }\n \n getDifficulty() {\n return this.state.difficulty;\n }\n \n setDifficulty(difficulty) {\n this.state.difficulty = difficulty;\n return this;\n }\n \n getExpectedReward() {\n return this.state.expectedReward;\n }\n \n setExpectedReward(expectedReward) {\n this.state.expectedReward = expectedReward;\n return this;\n }\n \n getHeight() {\n return this.state.height;\n }\n \n setHeight(height) {\n this.state.height = height;\n return this;\n }\n \n getPrevHash() {\n return this.state.prevId;\n }\n \n setPrevHash(prevId) {\n this.state.prevId = prevId;\n return this;\n }\n \n getReservedOffset() {\n return this.state.reservedOffset;\n }\n \n setReservedOffset(reservedOffset) {\n this.state.reservedOffset = reservedOffset;\n return this;\n }\n \n getSeedHeight() {\n return this.state.height;\n }\n \n setSeedHeight(seedHeight) {\n this.state.seedHeight = seedHeight;\n return this;\n }\n \n getSeedHash() {\n return this.state.seedHash;\n }\n \n setSeedHash(seedHash) {\n this.state.seedHash = seedHash;\n return this;\n }\n \n getNextSeedHash() {\n return this.state.nextSeedHash\n }\n \n setNextSeedHash(nextSeedHash) {\n this.state.nextSeedHash = nextSeedHash;\n return this;\n }\n}\n\nmodule.exports = MoneroBlockTemplate;","/**\n * Monero daemon connection span.\n */\nclass MoneroDaemonConnectionSpan {\n \n constructor(state) {\n this.state = Object.assign({}, state);\n }\n \n toJson() {\n return Object.assign({}, this.state);\n }\n \n getConnectionId() {\n return this.state.connectionId;\n }\n\n setConnectionId(connectionId) {\n this.state.connectionId = connectionId;\n return this;\n }\n \n getNumBlocks() {\n return this.state.numBlocks;\n }\n\n setNumBlocks(numBlocks) {\n this.state.numBlocks = numBlocks;\n return this;\n }\n \n getRemoteAddress() {\n return this.state.remoteAddress;\n }\n\n setRemoteAddress(remoteAddress) {\n this.state.remoteAddress = remoteAddress;\n return this;\n }\n \n getRate() {\n return this.state.rate;\n }\n\n setRate(rate) {\n this.state.rate = rate;\n return this;\n }\n \n getSpeed() {\n return this.state.speed;\n }\n\n setSpeed(speed) {\n this.state.speed = speed;\n return this;\n }\n \n getSize() {\n return this.state.size;\n }\n \n setSize(size) {\n this.state.size = size;\n return this;\n }\n \n getStartHeight() {\n return this.state.startHeight;\n }\n \n setStartHeight(startHeight) {\n this.state.startHeight = startHeight;\n return this;\n }\n}\n\nmodule.exports = MoneroDaemonConnectionSpan;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\n\n/**\n * Monero daemon info.\n */\nclass MoneroDaemonInfo {\n \n constructor(state) {\n state = Object.assign({}, state);\n this.state = state;\n \n // deserialize BigIntegers\n if (state.difficulty !== undefined && !(state.difficulty instanceof BigInteger)) state.difficulty = BigInteger.parse(state.difficulty);\n if (state.cumulativeDifficulty !== undefined && !(state.cumulativeDifficulty instanceof BigInteger)) state.cumulativeDifficulty = BigInteger.parse(state.cumulativeDifficulty);\n if (state.credits !== undefined && !(state.credits instanceof BigInteger)) state.credits = BigInteger.parse(state.credits);\n }\n \n toJson() {\n let json = Object.assign([], this.state);\n if (json.difficulty) json.difficulty = json.difficulty.toString();\n if (json.cumulativeDifficulty) json.cumulativeDifficulty = json.cumulativeDifficulty.toString();\n if (json.credits) json.credits = json.credits.toString();\n return json;\n }\n \n getVersion() {\n return this.state.version;\n }\n \n setVersion(version) {\n this.state.version = version;\n return this;\n }\n \n getNumAltBlocks() {\n return this.state.numAltBlocks;\n }\n \n setNumAltBlocks(numAltBlocks) {\n this.state.numAltBlocks = numAltBlocks;\n return this;\n }\n \n getBlockSizeLimit() {\n return this.state.blockSizeLimit;\n }\n \n setBlockSizeLimit(blockSizeLimit) {\n this.state.blockSizeLimit = blockSizeLimit;\n return this;\n }\n \n getBlockSizeMedian() {\n return this.state.blockSizeMedian;\n }\n \n setBlockSizeMedian(blockSizeMedian) {\n this.state.blockSizeMedian = blockSizeMedian;\n return this;\n }\n \n getBlockWeightLimit() {\n return this.state.blockWeightLimit;\n }\n \n setBlockWeightLimit(blockWeightLimit) {\n this.state.blockWeightLimit = blockWeightLimit;\n return this;\n }\n \n getBlockWeightMedian() {\n return this.state.blockWeightMedian;\n }\n \n setBlockWeightMedian(blockWeightMedian) {\n this.state.blockWeightMedian = blockWeightMedian;\n return this;\n }\n \n getBootstrapDaemonAddress() {\n return this.state.bootstrapDaemonAddress;\n }\n \n setBootstrapDaemonAddress(bootstrapDaemonAddress) {\n this.state.bootstrapDaemonAddress = bootstrapDaemonAddress;\n return this;\n }\n \n getDifficulty() {\n return this.state.difficulty;\n }\n \n setDifficulty(difficulty) {\n this.state.difficulty = difficulty;\n return this;\n }\n \n getCumulativeDifficulty() {\n return this.state.cumulativeDifficulty;\n }\n \n setCumulativeDifficulty(cumulativeDifficulty) {\n this.state.cumulativeDifficulty = cumulativeDifficulty;\n return this;\n }\n \n getFreeSpace() {\n return this.state.freeSpace;\n }\n \n setFreeSpace(freeSpace) {\n this.state.freeSpace = freeSpace;\n return this;\n }\n \n getNumOfflinePeers() {\n return this.state.numOfflinePeers;\n }\n \n setNumOfflinePeers(numOfflinePeers) {\n this.state.numOfflinePeers = numOfflinePeers;\n return this;\n }\n \n getNumOnlinePeers() {\n return this.state.numOnlinePeers;\n }\n \n setNumOnlinePeers(numOnlinePeers) {\n this.state.numOnlinePeers = numOnlinePeers;\n return this;\n }\n \n getHeight() {\n return this.state.height;\n }\n \n setHeight(height) {\n this.state.height = height;\n return this;\n }\n \n getHeightWithoutBootstrap() {\n return this.state.heightWithoutBootstrap;\n }\n \n setHeightWithoutBootstrap(heightWithoutBootstrap) {\n this.state.heightWithoutBootstrap = heightWithoutBootstrap;\n return this;\n }\n \n getNetworkType() {\n return this.state.networkType;\n }\n\n setNetworkType(networkType) {\n this.state.networkType = networkType;\n return this;\n }\n\n isOffline() {\n return this.state.isOffline;\n }\n \n setIsOffline(isOffline) {\n this.state.isOffline = isOffline;\n return this;\n }\n \n getNumIncomingConnections() {\n return this.state.numIncomingConnections;\n }\n \n setNumIncomingConnections(numIncomingConnections) {\n this.state.numIncomingConnections = numIncomingConnections;\n return this;\n }\n \n getNumOutgoingConnections() {\n return this.state.numOutgoingConnections;\n }\n \n setNumOutgoingConnections(numOutgoingConnections) {\n this.state.numOutgoingConnections = numOutgoingConnections;\n return this;\n }\n \n getNumRpcConnections() {\n return this.state.numRpcConnections;\n }\n \n setNumRpcConnections(numRpcConnections) {\n this.state.numRpcConnections = numRpcConnections;\n return this;\n }\n \n getStartTimestamp() {\n return this.state.startTimestamp;\n }\n \n setStartTimestamp(startTimestamp) {\n this.state.startTimestamp = startTimestamp;\n return this;\n }\n \n getTarget() {\n return this.state.target;\n }\n \n setTarget(target) {\n this.state.target = target;\n return this;\n }\n \n getTargetHeight() {\n return this.state.targetHeight;\n }\n \n setTargetHeight(targetHeight) {\n this.state.targetHeight = targetHeight;\n return this;\n }\n \n getTopBlockHash() {\n return this.state.topBlockHash;\n }\n \n setTopBlockHash(topBlockHash) {\n this.state.topBlockHash = topBlockHash;\n return this;\n }\n \n getNumTxs() {\n return this.state.numTxs;\n }\n \n setNumTxs(numTxs) {\n this.state.numTxs = numTxs;\n return this;\n }\n \n getNumTxsPool() {\n return this.state.numTxsPool;\n }\n \n setNumTxsPool(numTxsPool) {\n this.state.numTxsPool = numTxsPool;\n return this;\n }\n \n getWasBootstrapEverUsed() {\n return this.state.wasBootstrapEverUsed;\n }\n \n setWasBootstrapEverUsed(wasBootstrapEverUsed) {\n this.state.wasBootstrapEverUsed = wasBootstrapEverUsed;\n return this;\n }\n \n getDatabaseSize() {\n return this.state.databaseSize;\n }\n \n setDatabaseSize(databaseSize) {\n this.state.databaseSize = databaseSize;\n return this;\n }\n \n getUpdateAvailable() {\n return this.state.updateAvailable;\n }\n \n setUpdateAvailable(updateAvailable) {\n this.state.updateAvailable = updateAvailable;\n return this;\n }\n \n getCredits() {\n return this.state.credits;\n }\n \n setCredits(credits) {\n this.state.credits = credits;\n return this;\n }\n}\n\nmodule.exports = MoneroDaemonInfo;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\nconst MoneroDaemonConnection = require(\"./MoneroDaemonConnection\");\nconst MoneroDaemonConnectionSpan = require(\"./MoneroDaemonConnectionSpan\");\n\n/**\n * Models daemon synchronization information.\n */\nclass MoneroDaemonSyncInfo {\n \n constructor(state) {\n \n // copy state\n state = Object.assign({}, state);\n \n // deserialize if necessary\n if (state.connections) {\n for (let i = 0; i < state.connections.length; i++) {\n if (!(state.connections[i] instanceof MoneroDaemonConnection)) {\n state.connections[i] = new MoneroDaemonConnection(state.connections[i]);\n }\n }\n }\n if (state.spans) {\n for (let i = 0; i < state.spans.length; i++) {\n if (!(state.spans[i] instanceof MoneroDaemonConnectionSpan)) {\n state.spans[i] = new MoneroDaemonConnectionSpan(state.spans[i]);\n }\n }\n }\n if (state.credits !== undefined && !(state.credits instanceof BigInteger)) state.credits = BigInteger.parse(state.credits);\n \n // assign internal state\n this.state = state;\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (json.connections) {\n for (let i = 0; i < json.connections.length; i++) {\n json.connections[i] = json.connections[i].toJson();\n }\n }\n if (json.spans) {\n for (let i = 0; i < json.spans.length; i++) {\n json.spans[i] = json.spans[i].toJson();\n }\n }\n if (json.credits) json.credits = json.credits.toString();\n return json;\n }\n \n getHeight() {\n return this.state.height;\n }\n \n setHeight(height) {\n this.state.height = height;\n return this;\n }\n \n getConnections() {\n return this.state.connections;\n }\n \n setConnections(connections) {\n this.state.connections = connections;\n return this;\n }\n \n getSpans() {\n return this.state.spans;\n }\n \n setSpans(spans) {\n this.state.spans = spans;\n return this;\n }\n \n getTargetHeight() {\n return this.state.targetHeight;\n }\n \n setTargetHeight(targetHeight) {\n this.state.targetHeight = targetHeight;\n return this;\n }\n \n getNextNeededPruningSeed() {\n return this.state.nextNeededPruningSeed;\n }\n \n setNextNeededPruningSeed(nextNeededPruningSeed) {\n this.state.nextNeededPruningSeed = nextNeededPruningSeed;\n return this;\n }\n \n getOverview() {\n return this.state.overview;\n }\n \n setOverview(overview) {\n this.state.overview = overview;\n return this;\n }\n \n getCredits() {\n return this.state.credits;\n }\n \n setCredits(credits) {\n this.state.credits = credits;\n return this;\n }\n \n getTopBlockHash() {\n return this.state.topBlockHash;\n }\n \n setTopBlockHash(topBlockHash) {\n this.state.topBlockHash = topBlockHash;\n return this;\n }\n}\n\nmodule.exports = MoneroDaemonSyncInfo;","/**\n * Models the result of checking for a daemon update.\n */\nclass MoneroDaemonUpdateCheckResult {\n \n /**\n * Deep copy constructor.\n * \n * @param {MoneroDaemonUpdateCheckResult} is an existing result to deep copy from\n */\n constructor(result) {\n this.state = {};\n if (result !== undefined) {\n assert(result instanceof MoneroDaemonUpdateCheckResult);\n this.setIsUpdateAvailable(result.isUpdateAvailable());\n this.setVersion(result.getVersion());\n this.setHash(result.getHash());\n this.setAutoUri(result.getAutoUri());\n this.setUserUri(result.getUserUri());\n }\n }\n \n /**\n * Indicates if an update is available.\n * \n * @return {boolean} true if an update is available, false otherwise\n */\n isUpdateAvailable() {\n return this.state.isUpdateAvailable;\n }\n \n setIsUpdateAvailable(isUpdateAvailable) {\n this.state.isUpdateAvailable = isUpdateAvailable;\n return this;\n }\n \n /**\n * Get the update's version.\n * \n * @return {string} is the update's version\n */\n getVersion() {\n return this.state.version;\n }\n \n setVersion(version) {\n this.state.version = version;\n return this;\n }\n \n /**\n * Get the update's hash.\n * \n * @return {string} is the update's hash\n */\n getHash() {\n return this.state.hash;\n }\n \n setHash(hash) {\n this.state.hash = hash;\n return this;\n }\n \n /**\n * Get the uri to automatically download the update.\n * \n * @return {string} is the uri to automatically download the update\n */\n getAutoUri() {\n return this.state.autoUri;\n }\n \n setAutoUri(autoUri) {\n this.state.autoUri = autoUri;\n return this;\n }\n \n /**\n * Get the uri to manually download the update.\n * \n * @return {string} is the uri to manually download the update\n */\n getUserUri() {\n return this.state.userUri;\n }\n \n setUserUri(userUri) {\n this.state.userUri = userUri;\n return this;\n }\n}\n\nmodule.exports = MoneroDaemonUpdateCheckResult;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\n\n/**\n * Monero hard fork info.\n */\nclass MoneroHardForkInfo {\n \n constructor(state) {\n this.state = Object.assign({}, state);\n if (this.state.credits !== undefined && !(this.state.credits instanceof BigInteger)) this.state.credits = BigInteger.parse(this.state.credits);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (json.credits) json.credits = json.credits.toString();\n return json;\n }\n \n getEarliestHeight() {\n return this.state.earliestHeight;\n }\n\n setEarliestHeight(earliestHeight) {\n this.state.earliestHeight = earliestHeight;\n return this;\n }\n\n isEnabled() {\n return this.state.isEnabled;\n }\n\n setIsEnabled(isEnabled) {\n this.state.isEnabled = isEnabled;\n return this;\n }\n\n getState() {\n return this.state.state;\n }\n\n setState(state) {\n this.state.state = state;\n return this;\n }\n\n getThreshold() {\n return this.state.threshold;\n }\n\n setThreshold(threshold) {\n this.state.threshold = threshold;\n return this;\n }\n\n getVersion() {\n return this.state.version;\n }\n\n setVersion(version) {\n this.state.version = version;\n return this;\n }\n\n getNumVotes() {\n return this.state.numVotes;\n }\n\n setNumVotes(numVotes) {\n this.state.numVotes = numVotes;\n return this;\n }\n\n getWindow() {\n return this.state.window;\n }\n\n setWindow(window) {\n this.state.window = window;\n return this;\n }\n\n getVoting() {\n return this.state.voting;\n }\n\n setVoting(voting) {\n this.state.voting = voting;\n return this;\n }\n \n getCredits() {\n return this.state.credits;\n }\n \n setCredits(credits) {\n this.state.credits = credits;\n return this;\n }\n \n getTopBlockHash() {\n return this.state.topBlockHash;\n }\n \n setTopBlockHash(topBlockHash) {\n this.state.topBlockHash = topBlockHash;\n return this;\n }\n}\n\nmodule.exports = MoneroHardForkInfo;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\n\n/**\n * Model for the summation of miner emissions and fees.\n */\nclass MoneroMinerTxSum {\n \n constructor(state) {\n state = Object.assign({}, state);\n this.state = state;\n \n // deserialize BigIntegers\n if (state.emissionSum !== undefined && !(state.emissionSum instanceof BigInteger)) state.emissionSum = BigInteger.parse(state.emissionSum);\n if (state.feeSum !== undefined && !(state.feeSum instanceof BigInteger)) state.feeSum = BigInteger.parse(state.feeSum);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (this.getEmissionSum()) json.emissionSum = this.getEmissionSum().toString();\n if (this.getFeeSum()) json.feeSum = this.getFeeSum().toString();\n return json;\n }\n \n getEmissionSum() {\n return this.state.emissionSum;\n }\n \n setEmissionSum(emissionSum) {\n this.state.emissionSum = emissionSum;\n return this;\n }\n \n getFeeSum() {\n return this.state.feeSum;\n }\n \n setFeeSum(feeSum) {\n this.state.feeSum = feeSum;\n return this;\n }\n}\n\nmodule.exports = MoneroMinerTxSum;","/**\n * Models daemon mining status.\n */\nclass MoneroMiningStatus {\n \n constructor(state) {\n if (!state) state = {};\n else if (state instanceof MoneroMiningStatus) state = state.toJson();\n else if (typeof state === \"object\") state = Object.assign({}, state);\n else throw new MoneroError(\"state must be a MoneroMiningStatus or JavaScript object\");\n this.state = state;\n }\n \n toJson() {\n return Object.assign({}, this.state);\n }\n \n isActive() {\n return this.state.isActive;\n }\n \n setIsActive(isActive) {\n this.state.isActive = isActive;\n return this;\n }\n \n getAddress() {\n return this.state.address;\n }\n \n setAddress(address) {\n this.state.address = address;\n return this;\n }\n \n getSpeed() {\n return this.state.speed;\n }\n \n setSpeed(speed) {\n this.state.speed = speed;\n return this;\n }\n \n getNumThreads() {\n return this.state.numThreads;\n }\n \n setNumThreads(numThreads) {\n this.state.numThreads = numThreads;\n return this;\n }\n \n isBackground() {\n return this.state.isBackground;\n }\n \n setIsBackground(isBackground) {\n this.state.isBackground = isBackground;\n return this;\n }\n}\n\nmodule.exports = MoneroMiningStatus;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\n\n/**\n * Entry in a Monero output histogram (see get_output_histogram of Daemon RPC documentation).\n */\nclass MoneroOutputHistogramEntry {\n \n constructor(state) {\n this.state = Object.assign({}, state);\n if (this.state.amount !== undefined && !(this.state.amount instanceof BigInteger)) this.state.amount = BigInteger.parse(this.state.amount);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (json.amount) json.amount = json.amount.toString();\n return json;\n }\n \n getAmount() {\n return this.state.amount;\n }\n \n setAmount(amount) {\n this.state.amount = amount;\n return this;\n }\n\n getNumInstances() {\n return this.state.numInstances;\n }\n\n setNumInstances(numInstances) {\n this.state.numInstances = numInstances;\n return this;\n }\n\n getNumUnlockedInstances() {\n return this.state.numUnlockedInstances;\n }\n\n setNumUnlockedInstances(numUnlockedInstances) {\n this.state.numUnlockedInstances = numUnlockedInstances;\n return this;\n }\n\n getNumRecentInstances() {\n return this.state.numRecentInstances;\n }\n\n setNumRecentInstances(numRecentInstances) {\n this.state.numRecentInstances = numRecentInstances;\n return this;\n }\n}\n\nmodule.exports = MoneroOutputHistogramEntry;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\n\n/**\n * Models the result from submitting a tx to a daemon.\n */\nclass MoneroSubmitTxResult {\n \n constructor(state) {\n state = Object.assign({}, state);\n this.state = state;\n \n // deserialize BigIntegers\n if (state.credits !== undefined && !(state.credits instanceof BigInteger)) state.credits = BigInteger.parse(state.credits);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (json.credits) json.credits = json.credits.toString();\n return json;\n }\n \n isGood() {\n return this.state.isGood;\n }\n \n setIsGood(isGood) {\n this.state.isGood = isGood;\n return this;\n }\n \n isRelayed() {\n return this.state.isRelayed;\n }\n \n setIsRelayed(isRelayed) {\n this.state.isRelayed = isRelayed;\n return this;\n }\n \n isDoubleSpendSeen() {\n return this.state.isDoubleSpendSeen;\n }\n \n setIsDoubleSpend(isDoubleSpendSeen) {\n this.state.isDoubleSpendSeen = isDoubleSpendSeen\n return this;\n }\n \n isFeeTooLow() {\n return this.state.isFeeTooLow;\n }\n \n setIsFeeTooLow(isFeeTooLow) {\n this.state.isFeeTooLow = isFeeTooLow;\n return this;\n }\n \n isMixinTooLow() {\n return this.state.isMixinTooLow;\n }\n \n setIsMixinTooLow(isMixinTooLow) {\n this.state.isMixinTooLow = isMixinTooLow;\n return this;\n }\n \n hasInvalidInput() {\n return this.state.hasInvalidInput;\n }\n \n setHasInvalidInput(hasInvalidInput) {\n this.state.hasInvalidInput = hasInvalidInput;\n return this;\n }\n \n hasInvalidOutput() {\n return this.state.hasInvalidOutput;\n }\n \n setHasInvalidOutput(hasInvalidOutput) {\n this.state.hasInvalidOutput = hasInvalidOutput;\n return this;\n }\n \n hasTooFewOutputs() {\n return this.state.hasTooFewOutputs;\n }\n \n setHasTooFewOutputs(hasTooFewOutputs) {\n this.state.hasTooFewOutputs = hasTooFewOutputs;\n return this;\n }\n \n isOverspend() {\n return this.state.isOverspend;\n }\n \n setIsOverspend(isOverspend) {\n this.state.isOverspend = isOverspend;\n return this;\n }\n \n getReason() {\n return this.state.reason;\n }\n \n setReason(reason) {\n this.state.reason = reason;\n return this;\n }\n \n isTooBig() {\n return this.state.isTooBig;\n }\n \n setIsTooBig(isTooBig) {\n this.state.isTooBig = isTooBig;\n return this;\n }\n \n getSanityCheckFailed() {\n return this.state.sanityCheckFailed;\n }\n \n setSanityCheckFailed(sanityCheckFailed) {\n this.state.sanityCheckFailed = sanityCheckFailed;\n return this;\n }\n \n getCredits() {\n return this.state.credits;\n }\n \n setCredits(credits) {\n this.state.credits = credits;\n return this;\n }\n \n getTopBlockHash() {\n return this.state.topBlockHash;\n }\n \n setTopBlockHash(topBlockHash) {\n this.state.topBlockHash = topBlockHash;\n return this;\n }\n}\n\nmodule.exports = MoneroSubmitTxResult;","/**\n * Represents an account tag.\n */\nclass MoneroAccountTag {\n \n constructor(tag, label, accountIndices) {\n this.tag = tag;\n this.label = label;\n this.accountIndices = accountIndices;\n }\n \n getTag() {\n return this.tag;\n }\n \n setTag(tag) {\n this.tag = tag;\n return this;\n }\n \n getLabel() {\n return this.label;\n }\n \n setLabel(label) {\n this.label = label;\n return this;\n }\n \n getAccountIndices() {\n return this.accountIndices;\n }\n \n setAccountIndices(accountIndices) {\n this.accoutIndices = accountIndices;\n return this;\n }\n}\n\nmodule.exports = MoneroAccountTag;","const BigInteger = require(\"../../common/biginteger\").BigInteger;\nconst MoneroCheck = require(\"./MoneroCheck\");\n\n/**\n * Results from checking a reserve proof.\n * \n * @extends {MoneroCheck}\n */\nclass MoneroCheckReserve extends MoneroCheck {\n \n constructor(state) {\n super(state);\n if (this.state.totalAmount !== undefined && !(this.state.totalAmount instanceof BigInteger)) this.state.totalAmount = BigInteger.parse(this.state.totalAmount);\n if (this.state.unconfirmedSpentAmount !== undefined && !(this.state.unconfirmedSpentAmount instanceof BigInteger)) this.state.unconfirmedSpentAmount = BigInteger.parse(this.state.unconfirmedSpentAmount);\n }\n \n toJson() {\n let json = Object.assign({}, this.state);\n if (this.getTotalAmount()) json.totalAmount = this.getTotalAmount().toString();\n if (this.getUnconfirmedSpentAmount()) json.unconfirmedSpentAmount = this.getUnconfirmedSpentAmount().toString();\n return json;\n }\n \n getTotalAmount() {\n return this.state.totalAmount;\n }\n\n setTotalAmount(totalAmount) {\n this.state.totalAmount = totalAmount;\n return this;\n }\n \n getUnconfirmedSpentAmount() {\n return this.state.unconfirmedSpentAmount;\n }\n\n setUnconfirmedSpentAmount(unconfirmedSpentAmount) {\n this.state.unconfirmedSpentAmount = unconfirmedSpentAmount;\n return this;\n }\n}\n\nmodule.exports = MoneroCheckReserve;","/**\n * Copyright (c) woodser\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\n/**\n * Monero daemon interface and default implementations.\n * \n * @interface\n */\nclass MoneroDaemon {\n \n /**\n * Indicates if the client is connected to the daemon via RPC.\n * \n * @return {boolean} true if the client is connected to the daemon, false otherwise\n */\n async isConnected() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Gets the version of the daemon.\n * \n * @return {MoneroVersion} the version of the daemon\n */\n async getVersion() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Indicates if the daemon is trusted xor untrusted.\n * \n * @return {boolean} true if the daemon is trusted, false otherwise\n */\n async isTrusted() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get the number of blocks in the longest chain known to the node.\n * \n * @return {int} the number of blocks\n */\n async getHeight() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get a block's hash by its height.\n * \n * @param {int} height - height of the block hash to get\n * @return {string} the block's hash at the given height\n */\n async getBlockHash(height) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get a block template for mining a new block.\n * \n * @param {string} walletAddress - address of the wallet to receive miner transactions if block is successfully mined\n * @param {int} reserveSize - reserve size (optional)\n * @return {MoneroBlockTemplate} is a block template for mining a new block\n */\n async getBlockTemplate(walletAddress, reserveSize) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get the last block's header.\n * \n * @return {MoneroBlockHeader} last block's header\n */\n async getLastBlockHeader() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get a block header by its hash.\n * \n * @param {string} blockHash - hash of the block to get the header of\n * @return {MoneroBlockHeader} block's header\n */\n async getBlockHeaderByHash(blockHash) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get a block header by its height.\n * \n * @param {int} height - height of the block to get the header of\n * @return {MoneroBlockHeader} block's header\n */\n async getBlockHeaderByHeight(height) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get block headers for the given range.\n * \n * @param {int} startHeight - start height lower bound inclusive (optional)\n * @param {int} endHeight - end height upper bound inclusive (optional)\n * @return {MoneroBlockHeader[]} for the given range\n */\n async getBlockHeadersByRange(startHeight, endHeight) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get a block by hash.\n * \n * @param {string} blockHash - hash of the block to get\n * @return {MoneroBlock} with the given hash\n */\n async getBlockByHash(blockHash) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get blocks by hash.\n * \n * @param {string[]} blockHashes - array of hashes; first 10 blocks hashes goes sequential,\n * next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on,\n * and the last one is always genesis block\n * @param {int} startHeight - start height to get blocks by hash\n * @param {boolean} prune - specifies if returned blocks should be pruned (defaults to false) // TODO: test default\n * @return {MoneroBlock[]} retrieved blocks\n */\n async getBlocksByHash(blockHashes, startHeight, prune) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get a block by height.\n * \n * @param {int} height - height of the block to get\n * @return {MoneroBlock} with the given height\n */\n async getBlockByHeight(height) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get blocks at the given heights.\n * \n * @param {int[]} heights - heights of the blocks to get\n * @return {MoneroBlock[]} are blocks at the given heights\n */\n async getBlocksByHeight(heights) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get blocks in the given height range.\n * \n * @param {int} startHeight - start height lower bound inclusive (optional)\n * @param {int} endHeight - end height upper bound inclusive (optional)\n * @return {MoneroBlock[]} are blocks in the given height range\n */\n async getBlocksByRange(startHeight, endHeight) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get blocks in the given height range as chunked requests so that each request is\n * not too big.\n * \n * @param {int} startHeight - start height lower bound inclusive (optional)\n * @param {int} endHeight - end height upper bound inclusive (optional)\n * @param {int} maxChunkSize - maximum chunk size in any one request (default 3,000,000 bytes)\n * @return {MoneroBlock[]} blocks in the given height range\n */\n async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get block hashes as a binary request to the daemon.\n * \n * @param {string[]} blockHashes - specify block hashes to fetch; first 10 blocks hash goes\n * sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64\n * and so on, and the last one is always genesis block\n * @param {int} startHeight - starting height of block hashes to return\n * @return {string[]} requested block hashes \n */\n async getBlockHashes(blockHashes, startHeight) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get a transaction by hash.\n * \n * @param {string} txHash - hash of the transaction to get\n * @param {boolean} prune - specifies if the returned tx should be pruned (defaults to false)\n * @return {MoneroTx} transaction with the given hash\n */\n async getTx(txHash, prune = false) {\n return (await this.getTxs([txHash], prune))[0];\n }\n \n /**\n * Get transactions by hashes.\n * \n * @param {string[]} txHashes - hashes of transactions to get\n * @param {boolean} prune - specifies if the returned txs should be pruned (defaults to false)\n * @return {MoneroTx[]} transactions with the given hashes\n */\n async getTxs(txHashes, prune = false) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get a transaction hex by hash.\n * \n * @param {string} txHash - hash of the transaction to get hex from\n * @param {boolean} prune - specifies if the returned tx hex should be pruned (defaults to false)\n * @return {string} tx hex with the given hash\n */\n async getTxHex(txHash, prune = false) {\n return (await this.getTxHexes([txHash], prune))[0];\n }\n \n /**\n * Get transaction hexes by hashes.\n * \n * @param {string[]} txHashes - hashes of transactions to get hexes from\n * @param {boolean} prune - specifies if the returned tx hexes should be pruned (defaults to false)\n * @return {string[]} tx hexes\n */\n async getTxHexes(txHashes, prune = false) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Gets the total emissions and fees from the genesis block to the current height.\n * \n * @param {int} height - height to start computing the miner sum\n * @param {int} numBlocks - number of blocks to include in the sum\n * @return {MoneroMinerTxSum} encapsulates the total emissions and fees since the genesis block\n */\n async getMinerTxSum(height, numBlocks) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get the fee estimate per kB.\n * \n * @param {int} graceBlocks TODO\n * @return {BigInteger} fee estimate per kB.\n */\n async getFeeEstimate(graceBlocks) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Submits a transaction to the daemon's pool.\n * \n * @param {string} txHex - raw transaction hex to submit\n * @param {boolean} doNotRelay specifies if the tx should be relayed (optional)\n * @return {MoneroSubmitTxResult} contains submission results\n */\n async submitTxHex(txHex, doNotRelay) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Relays a transaction by hash.\n * \n * @param {string} txHash - hash of the transaction to relay\n */\n async relayTxByHash(txHash) {\n const assert = require(\"assert\");\n assert.equal(typeof txHash, \"string\", \"Must provide a transaction hash\");\n await this.relayTxsByHash([txHash]);\n }\n \n /**\n * Relays transactions by hash.\n * \n * @param {string[]} txHashes - hashes of the transactinos to relay\n */\n async relayTxsByHash(txHashes) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get valid transactions seen by the node but not yet mined into a block, as well\n * as spent key image information for the tx pool.\n * \n * @return {MoneroTx[]} are transactions in the transaction pool\n */\n async getTxPool() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get hashes of transactions in the transaction pool.\n * \n * @return {string[]} are hashes of transactions in the transaction pool\n */\n async getTxPoolHashes() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get all transaction pool backlog.\n * \n * @return {MoneroTxBacklogEntry[]} backlog entries \n */\n async getTxPoolBacklog() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get transaction pool statistics.\n * \n * @return {MoneroTxPoolStats} contains statistics about the transaction pool\n */\n async getTxPoolStats() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Flush transactions from the tx pool.\n * \n * @param {(string|string[])} hashes - specific transactions to flush (defaults to all)\n */\n async flushTxPool(hashes) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get the spent status of the given key image.\n * \n * @param {string} keyImage - key image hex to get the status of\n * @return {MoneroKeyImageSpentStatus} status of the key image\n */\n async getKeyImageSpentStatus(keyImage) {\n return (await this.getKeyImageSpentStatuses([keyImage]))[0];\n }\n \n /**\n * Get the spent status of each given key image.\n * \n * @param {string[]} keyImages are hex key images to get the statuses of\n * @return {MoneroKeyImageSpentStatus[]} status for each key image\n */\n async getKeyImageSpentStatuses(keyImages) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get outputs identified by a list of output amounts and indices as a binary\n * request.\n * \n * @param {MoneroOutput[]} outputs - identify each output by amount and index\n * @return {MoneroOutput[]} identified outputs\n */\n async getOutputs(outputs) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get a histogram of output amounts. For all amounts (possibly filtered by\n * parameters), gives the number of outputs on the chain for that amount.\n * RingCT outputs counts as 0 amount.\n * \n * @param {BigInteger[]} amounts - amounts of outputs to make the histogram with\n * @param {int} minCount - TODO\n * @param {int} maxCount - TODO\n * @param {boolean} isUnlocked - makes a histogram with outputs with the specified lock state\n * @param {int} recentCutoff - TODO\n * @return {MoneroOutputHistogramEntry[]} are entries meeting the parameters\n */\n async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Creates an output distribution.\n * \n * @param {BigInteger[]} amounts - amounts of outputs to make the distribution with\n * @param {boolean} cumulative - specifies if the results should be cumulative (defaults to TODO)\n * @param {int} startHeight - start height lower bound inclusive (optional)\n * @param {int} endHeight - end height upper bound inclusive (optional)\n * @return {MoneroOutputDistributionEntry[]} are entries meeting the parameters\n */\n async getOutputDistribution(amounts, cumulative, startHeight, endHeight) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get general information about the state of the node and the network.\n * \n * @return {MoneroDaemonInfo} is general information about the node and network\n */\n async getInfo() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get synchronization information.\n * \n * @return {MoneroDaemonSyncInfo} contains sync information\n */\n async getSyncInfo() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Look up information regarding hard fork voting and readiness.\n * \n * @return {MoneroHardForkInfo} contains hard fork information\n */\n async getHardForkInfo() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get alternative chains seen by the node.\n * \n * @return {MoneroAltChain[]} alternative chains\n */\n async getAltChains() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get known block hashes which are not on the main chain.\n * \n * @return {string[]} known block hashes which are not on the main chain\n */\n async getAltBlockHashes() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get the download bandwidth limit.\n * \n * @return {int} download bandwidth limit\n */\n async getDownloadLimit() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Set the download bandwidth limit.\n * \n * @param {int} limit - download limit to set (-1 to reset to default)\n * @return {int} new download limit after setting\n */\n async setDownloadLimit(limit) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Reset the download bandwidth limit.\n * \n * @return {int} download bandwidth limit after resetting\n */\n async resetDownloadLimit() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get the upload bandwidth limit.\n * \n * @return {int} upload bandwidth limit\n */\n async getUploadLimit() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Set the upload bandwidth limit.\n * \n * @param limit - upload limit to set (-1 to reset to default)\n * @return {int} new upload limit after setting\n */\n async setUploadLimit(limit) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Reset the upload bandwidth limit.\n * \n * @return {int} upload bandwidth limit after resetting\n */\n async resetUploadLimit() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get known peers including their last known online status.\n * \n * @return {MoneroDaemonPeer[]} known peers\n */\n async getKnownPeers() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get incoming and outgoing connections to the node.\n * \n * @return {MoneroDaemonConnection[]} daemon's peer connections\n */\n async getConnections() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Limit number of outgoing peers.\n * \n * @param {int} limit - maximum number of outgoing peers\n */\n async setOutgoingPeerLimit(limit) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Limit number of incoming peers.\n * \n * @param {int} limit - maximum number of incoming peers\n */\n async setIncomingPeerLimit(limit) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get peer bans.\n * \n * @return {MoneroBan[]} entries about banned peers\n */\n async getPeerBans() {\n throw new MoneroError(\"Subclass must implement\");\n }\n\n /**\n * Ban a peer node.\n * \n * @param {MoneroBan} ban - contains information about a node to ban\n */\n async setPeerBan(ban) {\n return await this.setPeerBans([ban]);\n }\n \n /**\n * Ban peers nodes.\n * \n * @param {MoneroBan[]} bans - specify which peers to ban\n */\n async setPeerBans(bans) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Start mining.\n * \n * @param {string} address - address given miner rewards if the daemon mines a block\n * @param {integer} numThreads - number of mining threads to run\n * @param {boolean} isBackground - specifies if the miner should run in the background or not\n * @param {boolean} ignoreBattery - specifies if the battery state (e.g. on laptop) should be ignored or not\n */\n async startMining(address, numThreads, isBackground, ignoreBattery) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Stop mining.\n */\n async stopMining() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get the daemon's mining status.\n * \n * @return {MoneroMiningStatus} daemon's mining status\n */\n async getMiningStatus() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Submit a mined block to the network.\n * \n * @param {string} blockBlob - mined block to submit\n */\n async submitBlock(blockBlob) {\n await this.submitBlocks([blockBlob]);\n }\n \n /**\n * Submit mined blocks to the network.\n * \n * @param {string[]} blockBlobs - mined blocks to submit\n */\n async submitBlocks(blockBlobs) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Check for update.\n * \n * @return {MoneroDaemonUpdateCheckResult} the result\n */\n async checkForUpdate() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Download an update.\n * \n * @param {string} path - path to download the update (optional)\n * @return {MoneroDaemonUpdateDownloadResult} the result\n */\n async downloadUpdate(path) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Safely disconnect and shut down the daemon.\n */\n async stop() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Get the header of the next block added to the chain.\n * \n * @return {MoneroBlockHeader} header of the next block added to the chain\n */\n async getNextBlockHeader() {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Register a listener to be notified when blocks are added to the chain.\n * \n * @param {function} listener - invoked with MoneroBlockHeaders as blocks are added to the chain\n */\n async addBlockListener(listener) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n /**\n * Unregister a listener to be notified when blocks are added to the chain.\n * \n * @param {function} listener - previously registered listener to be unregistered\n */\n async removeBlockListener(listener) {\n throw new MoneroError(\"Subclass must implement\");\n }\n \n // ----------------------------- STATIC UTILITIES ---------------------------\n \n /**\n * Parses a network string to an enumerated type.\n * \n * @param {string} network - network string to parse\n * @return {MoneroNetworkType} enumerated network type\n */\n static parseNetworkType(network) {\n const MoneroNetworkType = require(\"./model/MoneroNetworkType\");\n if (network === \"mainnet\") return MoneroNetworkType.MAINNET;\n if (network === \"testnet\") return MoneroNetworkType.TESTNET;\n if (network === \"stagenet\") return MoneroNetworkType.STAGENET;\n throw new MoneroError(\"Invalid network type to parse: \" + network);\n }\n}\n\nmodule.exports = MoneroDaemon;","const assert = require(\"assert\");\nconst LibraryUtils = require(\"../common/LibraryUtils\");\nconst MoneroError = require(\"../common/MoneroError\");\nconst MoneroNetworkType = require(\"../daemon/model/MoneroNetworkType\");\nconst MoneroSubaddress = require(\"./model/MoneroSubaddress\");\nconst MoneroUtils = require(\"../common/MoneroUtils\");\nconst MoneroVersion = require(\"../daemon/model/MoneroVersion\");\nconst MoneroWallet = require(\"./MoneroWallet\");\nconst MoneroWalletConfig = require(\"./model/MoneroWalletConfig\");\n\n/**\n * Implements a MoneroWallet which only manages keys using WebAssembly.\n * \n * @implements {MoneroWallet}\n * @hideconstructor\n */\nclass MoneroWalletKeys extends MoneroWallet {\n \n // --------------------------- STATIC UTILITIES -----------------------------\n \n /**\n *

Create a wallet using WebAssembly bindings to monero-core.

\n * \n *

Example:

\n * \n * \n * let wallet = await MoneroWalletKeys.createWallet({
\n *    password: \"abc123\",
\n *    networkType: MoneroNetworkType.STAGENET,
\n *    mnemonic: \"coexist igloo pamphlet lagoon...\"
\n * });\n *
\n * \n * @param {MoneroWalletConfig|object} config - MoneroWalletConfig or equivalent config object\n * @param {string|number} config.networkType - network type of the wallet to create (one of \"mainnet\", \"testnet\", \"stagenet\" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)\n * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)\n * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase\n * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys)\n * @param {string} config.privateViewKey - private view key of the wallet to create (optional)\n * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional)\n * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to \"English\" or auto-detected)\n * @return {MoneroWalletKeys} the created wallet\n */\n static async createWallet(config) {\n \n // normalize and validate config\n if (config === undefined) throw new MoneroError(\"Must provide config to create wallet\");\n config = config instanceof MoneroWalletConfig ? config : new MoneroWalletConfig(config);\n if (config.getMnemonic() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) {\n throw new MoneroError(\"Wallet may be initialized with a mnemonic or keys but not both\");\n }\n if (config.getNetworkType() === undefined) throw new MoneroError(\"Must provide a networkType: 'mainnet', 'testnet' or 'stagenet'\");\n if (config.getSaveCurrent() === true) throw new MoneroError(\"Cannot save current wallet when creating keys-only wallet\");\n \n // create wallet\n if (config.getMnemonic() !== undefined) {\n if (config.getLanguage() !== undefined) throw new MoneroError(\"Cannot provide language when creating wallet from mnemonic\");\n return MoneroWalletKeys._createWalletFromMnemonic(config.getNetworkType(), config.getMnemonic(), config.getSeedOffset());\n } else if (config.getPrimaryAddress() !== undefined) {\n if (config.getSeedOffset() !== undefined) throw new MoneroError(\"Cannot provide seedOffset when creating wallet from keys\");\n return MoneroWalletKeys._createWalletFromKeys(config.getNetworkType(), config.getPrimaryAddress(), config.getPrivateViewKey(), config.getPrivateSpendKey(), config.getLanguage());\n } else {\n if (config.getSeedOffset() !== undefined) throw new MoneroError(\"Cannot provide seedOffset when creating random wallet\");\n if (config.getRestoreHeight() !== undefined) throw new MoneroError(\"Cannot provide restoreHeight when creating random wallet\");\n return MoneroWalletKeys._createWalletRandom(config.getNetworkType(), config.getLanguage());\n }\n }\n \n static async _createWalletRandom(networkType, language) {\n\n // validate and sanitize params\n MoneroNetworkType.validate(networkType);\n if (language === undefined) language = \"English\";\n \n // load wasm module\n let module = await LibraryUtils.loadKeysModule();\n \n // queue call to wasm module\n return module.queueTask(async function() {\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = async function(cppAddress) {\n if (typeof cppAddress === \"string\") reject(new MoneroError(cppAddress));\n else resolve(new MoneroWalletKeys(cppAddress));\n };\n \n // create wallet in wasm and invoke callback when done\n module.create_keys_wallet_random(networkType, language, callbackFn);\n });\n });\n }\n \n static async _createWalletFromMnemonic(networkType, mnemonic, seedOffset) {\n \n // validate and sanitize params\n MoneroNetworkType.validate(networkType);\n if (mnemonic === undefined) throw Error(\"Must define mnemonic phrase to create wallet from\");\n if (seedOffset === undefined) seedOffset = \"\";\n \n // load wasm module\n let module = await LibraryUtils.loadKeysModule();\n \n // queue call to wasm module\n return module.queueTask(async function() {\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = async function(cppAddress) {\n if (typeof cppAddress === \"string\") reject(new MoneroError(cppAddress));\n else resolve(new MoneroWalletKeys(cppAddress));\n };\n \n // create wallet in wasm and invoke callback when done\n module.create_keys_wallet_from_mnemonic(networkType, mnemonic, seedOffset, callbackFn);\n });\n });\n }\n \n static async _createWalletFromKeys(networkType, address, privateViewKey, privateSpendKey, language) {\n \n // validate and sanitize params\n MoneroNetworkType.validate(networkType);\n if (address === undefined) address = \"\";\n if (privateViewKey === undefined) privateViewKey = \"\";\n if (privateSpendKey === undefined) privateSpendKey = \"\";\n if (language === undefined) language = \"English\";\n \n // load wasm module\n let module = await LibraryUtils.loadKeysModule();\n \n // queue call to wasm module\n return module.queueTask(async function() {\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = async function(cppAddress) {\n if (typeof cppAddress === \"string\") reject(new MoneroError(cppAddress));\n else resolve(new MoneroWalletKeys(cppAddress));\n };\n \n // create wallet in wasm and invoke callback when done\n module.create_keys_wallet_from_keys(networkType, address, privateViewKey, privateSpendKey, language, callbackFn);\n });\n });\n }\n \n static async getMnemonicLanguages() {\n let module = await LibraryUtils.loadKeysModule();\n return module.queueTask(async function() {\n return JSON.parse(module.get_keys_wallet_mnemonic_languages()).languages;\n });\n }\n \n // --------------------------- INSTANCE METHODS -----------------------------\n \n /**\n * Internal constructor which is given the memory address of a C++ wallet\n * instance.\n * \n * This method should not be called externally but should be called through\n * static wallet creation utilities in this class.\n * \n * @param {int} cppAddress - address of the wallet instance in C++\n */\n constructor(cppAddress) {\n super();\n this._cppAddress = cppAddress;\n this._module = LibraryUtils.getWasmModule();\n if (!this._module.create_core_wallet_from_mnemonic) throw new Error(\"WASM module not loaded - create wallet instance using static utilities\"); // static utilites pre-load wasm module\n }\n \n async isViewOnly() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.is_view_only(that._cppAddress);\n });\n }\n \n async isConnected() {\n return false;\n }\n \n async getVersion() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n let versionStr = that._module.get_version(that._cppAddress);\n let versionJson = JSON.parse(versionStr);\n return new MoneroVersion(versionJson.number, versionJson.isRelease);\n });\n }\n \n /**\n * @ignore\n */\n getPath() {\n this._assertNotClosed();\n throw new Error(\"MoneroWalletKeys does not support a persisted path\");\n }\n \n async getMnemonic() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n let mnemonic = that._module.get_mnemonic(that._cppAddress);\n return mnemonic ? mnemonic : undefined;\n });\n }\n \n async getMnemonicLanguage() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n let mnemonicLanguage = that._module.get_mnemonic_language(that._cppAddress);\n return mnemonicLanguage ? mnemonicLanguage : undefined;\n });\n }\n \n async getPrivateSpendKey() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n let privateSpendKey = that._module.get_private_spend_key(that._cppAddress);\n return privateSpendKey ? privateSpendKey : undefined;\n });\n }\n \n async getPrivateViewKey() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.get_private_view_key(that._cppAddress);\n });\n }\n \n async getPublicViewKey() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.get_public_view_key(that._cppAddress);\n });\n }\n \n async getPublicSpendKey() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.get_public_spend_key(that._cppAddress);\n });\n }\n \n async getAddress(accountIdx, subaddressIdx) {\n this._assertNotClosed();\n assert(typeof accountIdx === \"number\");\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.get_address(that._cppAddress, accountIdx, subaddressIdx);\n });\n }\n \n async getAddressIndex(address) {\n this._assertNotClosed();\n if (!MoneroUtils.isValidAddress(address)) throw new MoneroError(\"Invalid address\");\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n try {\n let subaddressJson = JSON.parse(that._module.get_address_index(that._cppAddress, address));\n return new MoneroSubaddress(subaddressJson);\n } catch (e) {\n throw new Error(\"Address doesn't belong to the wallet\");\n }\n });\n }\n \n getAccounts() {\n this._assertNotClosed();\n throw new Error(\"MoneroWalletKeys does not support getting an enumerable set of accounts; query specific accounts\");\n }\n \n // getIntegratedAddress(paymentId) // TODO\n // decodeIntegratedAddress\n \n async close(save) {\n if (this._isClosed) return; // closing a closed wallet has no effect\n \n // save wallet if requested\n if (save) await this.save();\n \n // queue task to use wasm module\n let that = this;\n return that._module.queueTask(async function() {\n return new Promise(function(resolve, reject) {\n if (that._isClosed) {\n resolve();\n return;\n }\n \n // define callback for wasm\n let callbackFn = async function() {\n delete that._cppAddress;\n that._isClosed = true;\n resolve();\n };\n \n // close wallet in wasm and invoke callback when done\n that._module.close(that._cppAddress, false, callbackFn); // saving handled external to webassembly\n });\n });\n }\n \n async isClosed() {\n return this._isClosed;\n }\n \n // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS --------------\n \n async getPrimaryAddress() { return super.getPrimaryAddress(...arguments); }\n async getSubaddress() { return super.getSubaddress(...arguments); }\n \n // ----------------------------- PRIVATE HELPERS ----------------------------\n \n _assertNotClosed() {\n if (this._isClosed) throw new MoneroError(\"Wallet is closed\");\n }\n}\n\nmodule.exports = MoneroWalletKeys;","const assert = require(\"assert\");\nconst BigInteger = require(\"../common/biginteger\").BigInteger;\nconst GenUtils = require(\"../common/GenUtils\");\nconst LibraryUtils = require(\"../common/LibraryUtils\");\nconst MoneroAccount = require(\"./model/MoneroAccount\");\nconst MoneroAddressBookEntry = require(\"./model/MoneroAddressBookEntry\");\nconst MoneroBlock = require(\"../daemon/model/MoneroBlock\");\nconst MoneroCheckTx = require(\"./model/MoneroCheckTx\");\nconst MoneroDaemonRpc = require(\"../daemon/MoneroDaemonRpc\");\nconst MoneroError = require(\"../common/MoneroError\");\nconst MoneroIntegratedAddress = require(\"./model/MoneroIntegratedAddress\");\nconst MoneroKeyImage = require(\"../daemon/model/MoneroKeyImage\");\nconst MoneroKeyImageImportResult = require(\"./model/MoneroKeyImageImportResult\");\nconst MoneroMultisigInfo = require(\"./model/MoneroMultisigInfo\");\nconst MoneroMultisigInitResult = require(\"./model/MoneroMultisigInitResult\");\nconst MoneroMultisigSignResult = require(\"./model/MoneroMultisigSignResult\");\nconst MoneroNetworkType = require(\"../daemon/model/MoneroNetworkType\");\nconst MoneroOutputWallet = require(\"./model/MoneroOutputWallet\");\nconst MoneroRpcConnection = require(\"../common/MoneroRpcConnection\");\nconst MoneroSubaddress = require(\"./model/MoneroSubaddress\");\nconst MoneroSyncResult = require(\"./model/MoneroSyncResult\");\nconst MoneroTxConfig = require(\"./model/MoneroTxConfig\");\nconst MoneroTxSet = require(\"./model/MoneroTxSet\");\nconst MoneroTxWallet = require(\"./model/MoneroTxWallet\");\nconst MoneroUtils = require(\"../common/MoneroUtils\");\nconst MoneroWallet = require(\"./MoneroWallet\");\nconst MoneroWalletConfig = require(\"./model/MoneroWalletConfig\");\nconst MoneroWalletKeys = require(\"./MoneroWalletKeys\");\nconst MoneroWalletListener = require(\"./model/MoneroWalletListener\");\n\n/**\n * Implements a MoneroWallet using WebAssembly bindings to monero-project's wallet2.\n * \n * @extends {MoneroWalletKeys}\n * @implements {MoneroWallet}\n * @hideconstructor\n */\nclass MoneroWalletWasm extends MoneroWalletKeys {\n \n // --------------------------- STATIC UTILITIES -----------------------------\n \n /**\n * Check if a wallet exists at a given path.\n * \n * @param {string} path - path of the wallet on the file system\n * @param {fs} - Node.js compatible file system to use (optional, defaults to disk if nodejs)\n * @return {boolean} true if a wallet exists at the given path, false otherwise\n */\n static async walletExists(path, fs) {\n assert(path, \"Must provide a path to look for a wallet\");\n if (!fs) fs = MoneroWalletWasm._getFs();\n if (!fs) throw new MoneroError(\"Must provide file system to check if wallet exists\");\n let exists = fs.existsSync(path); // TODO: look for keys file\n console.log(\"Wallet exists at \" + path + \": \" + exists);\n return exists;\n }\n \n /**\n *

Open an existing wallet using WebAssembly bindings to wallet2.h.

\n * \n *

Examples:

\n * \n * \n * let wallet1 = await MoneroWalletWasm.openWallet(
\n *    \"./wallets/wallet1\",
\n *    \"supersecretpassword\",
\n *    MoneroNetworkType.STAGENET,
\n *    \"http://localhost:38081\" // daemon uri
\n * );

\n * \n * let wallet2 = await MoneroWalletWasm.openWallet({
\n *    path: \"./wallets/wallet2\",
\n *    password: \"supersecretpassword\",
\n *    networkType: MoneroNetworkType.STAGENET,
\n *    serverUri: \"http://localhost:38081\", // daemon configuration
\n *    serverUsername: \"superuser\",
\n *    serverPassword: \"abctesting123\"
\n * });\n *
\n * \n * @param {MoneroWalletConfig|object|string} configOrPath - MoneroWalletConfig or equivalent config object or a path to a wallet to open\n * @param {string} configOrPath.path - path of the wallet to open (optional if 'keysData' provided)\n * @param {string} configOrPath.password - password of the wallet to open\n * @param {string|number} configOrPath.networkType - network type of the wallet to open (one of \"mainnet\", \"testnet\", \"stagenet\" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)\n * @param {Uint8Array} configOrPath.keysData - wallet keys data to open (optional if path provided)\n * @param {Uint8Array} configOrPath.cacheData - wallet cache data to open (optional)\n * @param {string} configOrPath.serverUri - uri of the wallet's daemon (optional)\n * @param {string} configOrPath.serverUsername - username to authenticate with the daemon (optional)\n * @param {string} configOrPath.serverPassword - password to authenticate with the daemon (optional)\n * @param {boolean} configOrPath.rejectUnauthorized - reject self-signed server certificates if true (defaults to true)\n * @param {MoneroRpcConnection|object} configOrPath.server - MoneroRpcConnection or equivalent JS object configuring the daemon connection (optional)\n * @param {boolean} configOrPath.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)\n * @param {fs} configOrPath.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)\n * @param {string} password - password of the wallet to open\n * @param {string|number} networkType - network type of the wallet to open\n * @param {string|MoneroRpcConnection} daemonUriOrConnection - daemon URI or MoneroRpcConnection\n * @param {boolean} proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)\n * @param {fs} fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)\n * @return {MoneroWalletWasm} the opened wallet\n */\n static async openWallet(configOrPath, password, networkType, daemonUriOrConnection, proxyToWorker, fs) {\n\n // normalize and validate config\n let config;\n if (typeof configOrPath === \"object\") {\n config = configOrPath instanceof MoneroWalletConfig ? configOrPath : new MoneroWalletConfig(configOrPath);\n if (password !== undefined || networkType !== undefined || daemonUriOrConnection !== undefined || proxyToWorker !== undefined || fs !== undefined) throw new MoneroError(\"Can specify config object or params but not both when opening WASM wallet\")\n } else {\n config = new MoneroWalletConfig().setPath(configOrPath).setPassword(password).setNetworkType(networkType).setProxyToWorker(proxyToWorker).setFs(fs);\n if (typeof daemonUriOrConnection === \"object\") config.setServer(daemonUriOrConnection);\n else config.setServerUri(daemonUriOrConnection);\n }\n if (config.getProxyToWorker() === undefined) config.setProxyToWorker(GenUtils.isBrowser());\n if (config.getMnemonic() !== undefined) throw new MoneroError(\"Cannot specify mnemonic when opening wallet\");\n if (config.getSeedOffset() !== undefined) throw new MoneroError(\"Cannot specify seed offset when opening wallet\");\n if (config.getPrimaryAddress() !== undefined) throw new MoneroError(\"Cannot specify primary address when opening wallet\");\n if (config.getPrivateViewKey() !== undefined) throw new MoneroError(\"Cannot specify private view key when opening wallet\");\n if (config.getPrivateSpendKey() !== undefined) throw new MoneroError(\"Cannot specify private spend key when opening wallet\");\n if (config.getRestoreHeight() !== undefined) throw new MoneroError(\"Cannot specify restore height when opening wallet\");\n if (config.getLanguage() !== undefined) throw new MoneroError(\"Cannot specify language when opening wallet\");\n if (config.getSaveCurrent() === true) throw new MoneroError(\"Cannot save current wallet when opening JNI wallet\");\n \n // read wallet data from disk if not provided\n if (!config.getKeysData()) {\n let fs = config.getFs() ? config.getFs() : MoneroWalletWasm._getFs();\n if (!fs) throw new MoneroError(\"Must provide file system to read wallet data from\");\n if (!await this.walletExists(config.getPath(), fs)) throw new MoneroError(\"Wallet does not exist at path: \" + config.getPath());\n config.setKeysData(fs.readFileSync(config.getPath() + \".keys\"));\n config.setCacheData(fs.readFileSync(config.getPath()));\n }\n \n // open wallet from data\n return MoneroWalletWasm._openWalletData(config.getPath(), config.getPassword(), config.getNetworkType(), config.getKeysData(), config.getCacheData(), config.getServer(), config.getProxyToWorker(), config.getFs());\n }\n \n /**\n *

Create a wallet using WebAssembly bindings to wallet2.h.

\n * \n *

Example:

\n * \n * \n * let wallet = await MoneroWalletWasm.createWallet({
\n *    path: \"./test_wallets/wallet1\", // leave blank for in-memory wallet
\n *    password: \"supersecretpassword\",
\n *    networkType: MoneroNetworkType.STAGENET,
\n *    mnemonic: \"coexist igloo pamphlet lagoon...\",
\n *    restoreHeight: 1543218,
\n *    server: new MoneroRpcConnection(\"http://localhost:38081\", \"daemon_user\", \"daemon_password_123\"),
\n * });\n *
\n * \n * @param {object|MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object\n * @param {string} config.path - path of the wallet to create (optional, in-memory wallet if not given)\n * @param {string} config.password - password of the wallet to create\n * @param {string|number} config.networkType - network type of the wallet to create (one of \"mainnet\", \"testnet\", \"stagenet\" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)\n * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)\n * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase\n * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys)\n * @param {string} config.privateViewKey - private view key of the wallet to create (optional)\n * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional)\n * @param {number} config.restoreHeight - block height to start scanning from (defaults to 0 unless generating random wallet)\n * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to \"English\" or auto-detected)\n * @param {string} config.serverUri - uri of the wallet's daemon (optional)\n * @param {string} config.serverUsername - username to authenticate with the daemon (optional)\n * @param {string} config.serverPassword - password to authenticate with the daemon (optional)\n * @param {boolean} config.rejectUnauthorized - reject self-signed server certificates if true (defaults to true)\n * @param {MoneroRpcConnection|object} config.server - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional)\n * @param {boolean} config.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)\n * @param {fs} config.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)\n * @return {MoneroWalletWasm} the created wallet\n */\n static async createWallet(config) {\n \n // normalize and validate config\n if (config === undefined) throw new MoneroError(\"Must provide config to create wallet\");\n config = config instanceof MoneroWalletConfig ? config : new MoneroWalletConfig(config);\n if (config.getMnemonic() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) {\n throw new MoneroError(\"Wallet may be initialized with a mnemonic or keys but not both\");\n } // TODO: factor this much out to common\n if (config.getNetworkType() === undefined) throw new MoneroError(\"Must provide a networkType: 'mainnet', 'testnet' or 'stagenet'\");\n if (config.getSaveCurrent() === true) throw new MoneroError(\"Cannot save current wallet when creating WASM wallet\");\n \n // create wallet\n if (config.getMnemonic() !== undefined) {\n if (config.getLanguage() !== undefined) throw new MoneroError(\"Cannot provide language when creating wallet from mnemonic\");\n return MoneroWalletWasm._createWalletFromMnemonic(config.getPath(), config.getPassword(), config.getNetworkType(), config.getMnemonic(), config.getServer(), config.getRestoreHeight(), config.getSeedOffset(), config.getProxyToWorker(), config.getFs());\n } else if (config.getPrimaryAddress() !== undefined) {\n if (config.getSeedOffset() !== undefined) throw new MoneroError(\"Cannot provide seedOffset when creating wallet from keys\");\n return MoneroWalletWasm._createWalletFromKeys(config.getPath(), config.getPassword(), config.getNetworkType(), config.getPrimaryAddress(), config.getPrivateViewKey(), config.getPrivateSpendKey(), config.getServer(), config.getRestoreHeight(), config.getLanguage(), config.getProxyToWorker(), config.getFs());\n } else {\n if (config.getSeedOffset() !== undefined) throw new MoneroError(\"Cannot provide seedOffset when creating random wallet\");\n if (config.getRestoreHeight() !== undefined) throw new MoneroError(\"Cannot provide restoreHeight when creating random wallet\");\n return MoneroWalletWasm._createWalletRandom(config.getPath(), config.getPassword(), config.getNetworkType(), config.getServer(), config.getLanguage(), config.getProxyToWorker(), config.getFs());\n }\n }\n \n static async _createWalletRandom(path, password, networkType, daemonUriOrConnection, language, proxyToWorker, fs) {\n if (proxyToWorker === undefined) proxyToWorker = GenUtils.isBrowser();\n if (proxyToWorker) return MoneroWalletWasmProxy._createWalletRandom(path, password, networkType, daemonUriOrConnection, language, fs);\n \n // validate and normalize params\n if (path === undefined) path = \"\";\n if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error(\"Wallet already exists: \" + path);\n assert(password, \"Must provide a password to create the wallet with\");\n MoneroNetworkType.validate(networkType);\n if (language === undefined) language = \"English\";\n let daemonConnection = typeof daemonUriOrConnection === \"string\" ? new MoneroRpcConnection(daemonUriOrConnection) : daemonUriOrConnection;\n let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : \"\";\n let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : \"\";\n let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : \"\";\n let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true;\n \n // load wasm module\n let module = await LibraryUtils.loadCoreModule();\n \n // create wallet in queue\n let wallet = await module.queueTask(async function() {\n return new Promise(function(resolve, reject) {\n \n // register fn informing if unauthorized reqs should be rejected\n let rejectUnauthorizedFnId = GenUtils.getUUID();\n LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return rejectUnauthorized });\n \n // define callback for wasm\n let callbackFn = async function(cppAddress) {\n if (typeof cppAddress === \"string\") reject(new MoneroError(cppAddress));\n else resolve(new MoneroWalletWasm(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId));\n };\n \n // create wallet in wasm and invoke callback when done\n module.create_core_wallet_random(password, networkType, daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, language, callbackFn);\n });\n });\n \n // save wallet\n if (path) await wallet.save();\n return wallet;\n }\n \n static async _createWalletFromMnemonic(path, password, networkType, mnemonic, daemonUriOrConnection, restoreHeight, seedOffset, proxyToWorker, fs) {\n if (proxyToWorker === undefined) proxyToWorker = GenUtils.isBrowser();\n if (proxyToWorker) return MoneroWalletWasmProxy._createWalletFromMnemonic(path, password, networkType, mnemonic, daemonUriOrConnection, restoreHeight, seedOffset, fs);\n \n // validate and normalize params\n if (path === undefined) path = \"\";\n if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error(\"Wallet already exists: \" + path);\n assert(password, \"Must provide a password to create the wallet with\");\n MoneroNetworkType.validate(networkType);\n let daemonConnection = typeof daemonUriOrConnection === \"string\" ? new MoneroRpcConnection(daemonUriOrConnection) : daemonUriOrConnection;\n let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : \"\";\n let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : \"\";\n let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : \"\";\n let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true;\n if (restoreHeight === undefined) restoreHeight = 0;\n if (seedOffset === undefined) seedOffset = \"\";\n \n // load wasm module\n let module = await LibraryUtils.loadCoreModule();\n \n // create wallet in queue\n let wallet = await module.queueTask(async function() {\n return new Promise(function(resolve, reject) {\n \n // register fn informing if unauthorized reqs should be rejected\n let rejectUnauthorizedFnId = GenUtils.getUUID();\n LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return rejectUnauthorized });\n \n // define callback for wasm\n let callbackFn = async function(cppAddress) {\n if (typeof cppAddress === \"string\") reject(new MoneroError(cppAddress));\n else resolve(new MoneroWalletWasm(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId));\n };\n \n // create wallet in wasm and invoke callback when done\n module.create_core_wallet_from_mnemonic(password, networkType, mnemonic, daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, restoreHeight, seedOffset, callbackFn);\n });\n });\n \n // save wallet\n if (path) await wallet.save();\n return wallet;\n }\n \n static async _createWalletFromKeys(path, password, networkType, address, viewKey, spendKey, daemonUriOrConnection, restoreHeight, language, proxyToWorker, fs) {\n if (proxyToWorker === undefined) proxyToWorker = GenUtils.isBrowser();\n if (proxyToWorker) return MoneroWalletWasmProxy._createWalletFromKeys(path, password, networkType, address, viewKey, spendKey, daemonUriOrConnection, restoreHeight, language, fs);\n \n // validate and normalize params\n if (path === undefined) path = \"\";\n if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error(\"Wallet already exists: \" + path);\n assert(password, \"Must provide a password to create the wallet with\");\n MoneroNetworkType.validate(networkType);\n if (address === undefined) address = \"\";\n if (viewKey === undefined) viewKey = \"\";\n if (spendKey === undefined) spendKey = \"\";\n let daemonConnection = typeof daemonUriOrConnection === \"string\" ? new MoneroRpcConnection(daemonUriOrConnection) : daemonUriOrConnection;\n let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : \"\";\n let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : \"\";\n let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : \"\";\n let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true;\n if (restoreHeight === undefined) restoreHeight = 0;\n if (language === undefined) language = \"English\";\n \n // load wasm module\n let module = await LibraryUtils.loadCoreModule();\n \n // create wallet in queue\n let wallet = await module.queueTask(async function() {\n return new Promise(function(resolve, reject) {\n \n // register fn informing if unauthorized reqs should be rejected\n let rejectUnauthorizedFnId = GenUtils.getUUID();\n LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return rejectUnauthorized });\n \n // define callback for wasm\n let callbackFn = async function(cppAddress) {\n if (typeof cppAddress === \"string\") reject(new MoneroError(cppAddress));\n else resolve(new MoneroWalletWasm(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId));\n };\n \n // create wallet in wasm and invoke callback when done\n module.create_core_wallet_from_keys(password, networkType, address, viewKey, spendKey, daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, restoreHeight, language, callbackFn);\n });\n });\n \n // save wallet\n if (path) await wallet.save();\n return wallet;\n }\n \n static async getMnemonicLanguages() {\n let module = await LibraryUtils.loadCoreModule();\n return module.queueTask(async function() {\n return JSON.parse(module.get_keys_wallet_mnemonic_languages()).languages;\n });\n }\n \n // --------------------------- INSTANCE METHODS -----------------------------\n \n /**\n * Internal constructor which is given the memory address of a C++ wallet\n * instance.\n * \n * This method should not be called externally but should be called through\n * static wallet creation utilities in this class.\n * \n * @param {int} cppAddress - address of the wallet instance in C++\n * @param {string} path - path of the wallet instance\n * @param {string} password - password of the wallet instance\n * @param {FileSystem} fs - node.js-compatible file system to read/write wallet files\n * @param {boolean} rejectUnauthorized - specifies if unauthorized requests (e.g. self-signed certificates) should be rejected\n * @param {string} rejectUnauthorizedFnId - unique identifier for http_client_wasm to query rejectUnauthorized\n */\n constructor(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId) {\n super(cppAddress);\n this._path = path;\n this._password = password;\n this._listeners = [];\n this._fs = fs ? fs : (path ? MoneroWalletWasm._getFs() : undefined);\n this._isClosed = false;\n this._wasmListener = new WalletWasmListener(this); // receives notifications from wasm c++\n this._wasmListenerHandle = 0; // memory address of the wallet listener in c++\n this._rejectUnauthorized = rejectUnauthorized;\n this._rejectUnauthorizedConfigId = rejectUnauthorizedFnId;\n let that = this;\n LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return that._rejectUnauthorized }); // register fn informing if unauthorized reqs should be rejected\n }\n \n // ------------ WALLET METHODS SPECIFIC TO WASM IMPLEMENTATION --------------\n \n /**\n * Get the maximum height of the peers the wallet's daemon is connected to.\n *\n * @return {number} the maximum height of the peers the wallet's daemon is connected to\n */\n async getDaemonMaxPeerHeight() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(resp) {\n resolve(resp);\n }\n \n // sync wallet in wasm and invoke callback when done\n that._module.get_daemon_max_peer_height(that._cppAddress, callbackFn);\n });\n });\n }\n \n /**\n * Indicates if the wallet's daemon is synced with the network.\n * \n * @return {boolean} true if the daemon is synced with the network, false otherwise\n */\n async isDaemonSynced() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(resp) {\n resolve(resp);\n }\n \n // sync wallet in wasm and invoke callback when done\n that._module.is_daemon_synced(that._cppAddress, callbackFn);\n });\n });\n }\n \n /**\n * Indicates if the wallet is synced with the daemon.\n * \n * @return {boolean} true if the wallet is synced with the daemon, false otherwise\n */\n async isSynced() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(resp) {\n resolve(resp);\n }\n \n // sync wallet in wasm and invoke callback when done\n that._module.is_synced(that._cppAddress, callbackFn);\n });\n });\n }\n \n /**\n * Get the wallet's network type (mainnet, testnet, or stagenet).\n * \n * @return {MoneroNetworkType} the wallet's network type\n */\n async getNetworkType() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.get_network_type(that._cppAddress);\n });\n }\n \n /**\n * Get the height of the first block that the wallet scans.\n * \n * @return {number} the height of the first block that the wallet scans\n */\n async getSyncHeight() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.get_sync_height(that._cppAddress);\n });\n }\n \n /**\n * Set the height of the first block that the wallet scans.\n * \n * @param {number} syncHeight - height of the first block that the wallet scans\n */\n async setSyncHeight(syncHeight) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.set_sync_height(that._cppAddress, syncHeight);\n });\n }\n \n /**\n * Register a listener to receive wallet notifications.\n * \n * @param {MoneroWalletListener} listener - listener to receive wallet notifications\n */\n async addListener(listener) {\n this._assertNotClosed();\n assert(listener instanceof MoneroWalletListener, \"Listener must be instance of MoneroWalletListener\");\n this._listeners.push(listener);\n await this._setIsListening(true);\n }\n \n /**\n * Unregister a listener to receive wallet notifications.\n * \n * @param {MoneroWalletListener} listener - listener to unregister\n */\n async removeListener(listener) {\n this._assertNotClosed();\n let idx = this._listeners.indexOf(listener);\n if (idx > -1) this._listeners.splice(idx, 1);\n else throw new MoneroError(\"Listener is not registered with wallet\");\n if (this._listeners.length === 0) await this._setIsListening(false);\n }\n \n /**\n * Get the listeners registered with the wallet.\n * \n * @return {MoneroWalletListener[]} the registered listeners\n */\n getListeners() {\n this._assertNotClosed();\n return this._listeners;\n }\n \n /**\n * Move the wallet from its current path to the given path.\n * \n * @param {string} path is the new wallet's path\n * @param {string} password is the new wallet's password\n */\n async moveTo(path, password) {\n this._assertNotClosed();\n throw new Error(\"Not implemented\");\n }\n \n // -------------------------- COMMON WALLET METHODS -------------------------\n \n async setDaemonConnection(uriOrRpcConnection, username, password, rejectUnauthorized) {\n this._assertNotClosed();\n \n // normalize connection\n let connection = new MoneroRpcConnection(uriOrRpcConnection, username, password, rejectUnauthorized);\n let uri = connection.getUri();\n username = connection.getUsername();\n password = connection.getPassword();\n rejectUnauthorized = connection.getRejectUnauthorized();\n if (!uri) uri = \"\";\n if (!username) username = \"\";\n if (!password) password = \"\";\n this._rejectUnauthorized = rejectUnauthorized; // persist locally\n \n // set connection in queue\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(resp) { resolve(); }\n \n // sync wallet in wasm and invoke callback when done\n that._module.set_daemon_connection(that._cppAddress, uri, username, password, callbackFn);\n });\n });\n }\n \n async getDaemonConnection() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n let connectionContainerStr = that._module.get_daemon_connection(that._cppAddress);\n if (!connectionContainerStr) resolve();\n else {\n let jsonConnection = JSON.parse(connectionContainerStr);\n resolve(new MoneroRpcConnection(jsonConnection.uri, jsonConnection.username, jsonConnection.password, that._rejectUnauthorized));\n }\n });\n });\n }\n \n async isConnected() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(resp) {\n resolve(resp);\n }\n \n // sync wallet in wasm and invoke callback when done\n that._module.is_connected(that._cppAddress, callbackFn);\n });\n });\n }\n \n async getVersion() {\n this._assertNotClosed();\n throw new Error(\"Not implemented\");\n }\n \n async getPath() {\n this._assertNotClosed();\n return this._path;\n }\n \n async getIntegratedAddress(paymentId) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n try {\n return new MoneroIntegratedAddress(JSON.parse(that._module.get_integrated_address(that._cppAddress, \"\", paymentId ? paymentId : \"\")));\n } catch (e) {\n throw new MoneroError(\"Invalid payment ID: \" + paymentId);\n }\n });\n }\n \n async decodeIntegratedAddress(integratedAddress) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n try {\n return new MoneroIntegratedAddress(JSON.parse(that._module.decode_integrated_address(that._cppAddress, integratedAddress)));\n } catch (e) {\n throw new MoneroError(\"Invalid integrated address: \" + integratedAddress);\n }\n });\n }\n \n async getHeight() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(resp) {\n resolve(resp);\n }\n \n // sync wallet in wasm and invoke callback when done\n that._module.get_height(that._cppAddress, callbackFn);\n });\n });\n }\n \n async getDaemonHeight() {\n this._assertNotClosed();\n if (!(await this.isConnected())) throw new MoneroError(\"Wallet is not connected to daemon\");\n \n // schedule task\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(resp) {\n resolve(resp);\n }\n \n // sync wallet in wasm and invoke callback when done\n that._module.get_daemon_height(that._cppAddress, callbackFn);\n });\n });\n }\n \n async getHeightByDate(year, month, day) {\n this._assertNotClosed();\n if (!(await this.isConnected())) throw new MoneroError(\"Wallet is not connected to daemon\");\n \n // schedule task\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(resp) {\n if (typeof resp === \"string\") reject(new MoneroError(resp));\n else resolve(resp);\n }\n \n // sync wallet in wasm and invoke callback when done\n that._module.get_height_by_date(that._cppAddress, year, month, day, callbackFn);\n });\n });\n }\n \n async sync(listenerOrStartHeight, startHeight) {\n this._assertNotClosed();\n if (!(await this.isConnected())) throw new MoneroError(\"Wallet is not connected to daemon\");\n \n // normalize params\n startHeight = listenerOrStartHeight instanceof MoneroWalletListener ? startHeight : listenerOrStartHeight;\n let listener = listenerOrStartHeight instanceof MoneroWalletListener ? listenerOrStartHeight : undefined;\n if (startHeight === undefined) startHeight = Math.max(await this.getHeight(), await this.getSyncHeight());\n \n // register listener if given\n if (listener) await this.addListener(listener);\n \n // sync wallet\n let err;\n let result;\n try {\n let that = this;\n result = await that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = async function(resp) {\n if (resp.charAt(0) !== \"{\") reject(new MoneroError(resp));\n else {\n let respJson = JSON.parse(resp);\n resolve(new MoneroSyncResult(respJson.numBlocksFetched, respJson.receivedMoney));\n }\n }\n \n // sync wallet in wasm and invoke callback when done\n that._module.sync(that._cppAddress, startHeight, callbackFn);\n });\n });\n } catch (e) {\n err = e;\n }\n \n // unregister listener\n if (listener) await this.removeListener(listener);\n \n // throw error or return\n if (err) throw err;\n return result;\n }\n \n async startSyncing() {\n this._assertNotClosed();\n if (!(await this.isConnected())) throw new MoneroError(\"Wallet is not connected to daemon\");\n if (!this._syncingEnabled) {\n this._syncingEnabled = true;\n this._runSyncLoop(); // sync wallet on loop in background\n }\n }\n \n async stopSyncing() {\n this._assertNotClosed();\n this._syncingEnabled = false;\n this._module.stop_syncing(this._cppAddress); // task is not queued so wallet stops immediately\n }\n \n async rescanSpent() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n let callbackFn = function() { resolve(); }\n that._module.rescan_spent(that._cppAddress, callbackFn);\n });\n });\n }\n \n async rescanBlockchain() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n let callbackFn = function() { resolve(); }\n that._module.rescan_blockchain(that._cppAddress, callbackFn);\n });\n });\n }\n \n async getBalance(accountIdx, subaddressIdx) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n \n // get balance encoded in json string\n let balanceStr;\n if (accountIdx === undefined) {\n assert(subaddressIdx === undefined, \"Subaddress index must be undefined if account index is undefined\");\n balanceStr = that._module.get_balance_wallet(that._cppAddress);\n } else if (subaddressIdx === undefined) {\n balanceStr = that._module.get_balance_account(that._cppAddress, accountIdx);\n } else {\n balanceStr = that._module.get_balance_subaddress(that._cppAddress, accountIdx, subaddressIdx);\n }\n \n // parse json string to BigInteger\n return BigInteger.parse(JSON.parse(GenUtils.stringifyBIs(balanceStr)).balance);\n });\n }\n \n async getUnlockedBalance(accountIdx, subaddressIdx) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n \n // get balance encoded in json string\n let unlockedBalanceStr;\n if (accountIdx === undefined) {\n assert(subaddressIdx === undefined, \"Subaddress index must be undefined if account index is undefined\");\n unlockedBalanceStr = that._module.get_unlocked_balance_wallet(that._cppAddress);\n } else if (subaddressIdx === undefined) {\n unlockedBalanceStr = that._module.get_unlocked_balance_account(that._cppAddress, accountIdx);\n } else {\n unlockedBalanceStr = that._module.get_unlocked_balance_subaddress(that._cppAddress, accountIdx, subaddressIdx);\n }\n \n // parse json string to BigInteger\n return BigInteger.parse(JSON.parse(GenUtils.stringifyBIs(unlockedBalanceStr)).unlockedBalance);\n });\n }\n \n async getAccounts(includeSubaddresses, tag) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n let accountsStr = that._module.get_accounts(that._cppAddress, includeSubaddresses ? true : false, tag ? tag : \"\");\n let accounts = [];\n for (let accountJson of JSON.parse(GenUtils.stringifyBIs(accountsStr)).accounts) {\n accounts.push(MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson)));\n }\n return accounts;\n });\n }\n \n async getAccount(accountIdx, includeSubaddresses) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n let accountStr = that._module.get_account(that._cppAddress, accountIdx, includeSubaddresses ? true : false);\n let accountJson = JSON.parse(GenUtils.stringifyBIs(accountStr));\n return MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson));\n });\n\n }\n \n async createAccount(label) {\n if (label === undefined) label = \"\";\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n let accountStr = that._module.create_account(that._cppAddress, label);\n let accountJson = JSON.parse(GenUtils.stringifyBIs(accountStr));\n return MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson));\n });\n }\n \n async getSubaddresses(accountIdx, subaddressIndices) {\n let args = {accountIdx: accountIdx, subaddressIndices: subaddressIndices === undefined ? [] : GenUtils.listify(subaddressIndices)};\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n let subaddressesJson = JSON.parse(GenUtils.stringifyBIs(that._module.get_subaddresses(that._cppAddress, JSON.stringify(args)))).subaddresses;\n let subaddresses = [];\n for (let subaddressJson of subaddressesJson) subaddresses.push(MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson)));\n return subaddresses;\n });\n }\n \n async createSubaddress(accountIdx, label) {\n if (label === undefined) label = \"\";\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n let subaddressStr = that._module.create_subaddress(that._cppAddress, accountIdx, label);\n let subaddressJson = JSON.parse(GenUtils.stringifyBIs(subaddressStr));\n return MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson));\n });\n }\n \n async getTxs(query, missingTxHashes) {\n this._assertNotClosed();\n \n // copy and normalize query up to block\n query = MoneroWallet._normalizeTxQuery(query);\n \n // schedule task\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(blocksJsonStr) {\n \n // check for error\n if (blocksJsonStr.charAt(0) !== \"{\") {\n reject(new MoneroError(blocksJsonStr));\n return;\n }\n \n // resolve with deserialized txs\n try {\n resolve(MoneroWalletWasm._deserializeTxs(query, blocksJsonStr, missingTxHashes));\n } catch (e) {\n reject(e);\n }\n }\n \n // sync wallet in wasm and invoke callback when done\n that._module.get_txs(that._cppAddress, JSON.stringify(query.getBlock().toJson()), callbackFn);\n });\n });\n }\n \n async getTransfers(query) {\n this._assertNotClosed();\n \n // copy and normalize query up to block\n query = MoneroWallet._normalizeTransferQuery(query);\n \n // return promise which resolves on callback\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(blocksJsonStr) {\n \n // check for error\n if (blocksJsonStr.charAt(0) !== \"{\") {\n reject(new MoneroError(blocksJsonStr));\n return;\n }\n \n // resolve with deserialized transfers \n try {\n resolve(MoneroWalletWasm._deserializeTransfers(query, blocksJsonStr));\n } catch (e) {\n reject(e);\n }\n }\n \n // sync wallet in wasm and invoke callback when done\n that._module.get_transfers(that._cppAddress, JSON.stringify(query.getTxQuery().getBlock().toJson()), callbackFn);\n });\n });\n }\n \n async getOutputs(query) {\n this._assertNotClosed();\n \n // copy and normalize query up to block\n query = MoneroWallet._normalizeOutputQuery(query);\n \n // return promise which resolves on callback\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(blocksJsonStr) {\n \n // check for error\n if (blocksJsonStr.charAt(0) !== \"{\") {\n reject(new MoneroError(blocksJsonStr));\n return;\n }\n \n // resolve with deserialized outputs\n try {\n resolve(MoneroWalletWasm._deserializeOutputs(query, blocksJsonStr));\n } catch (e) {\n reject(e);\n }\n }\n \n // sync wallet in wasm and invoke callback when done\n that._module.get_outputs(that._cppAddress, JSON.stringify(query.getTxQuery().getBlock().toJson()), callbackFn);\n });\n });\n }\n \n async getOutputsHex() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n that._module.get_outputs_hex(that._cppAddress, function(outputsHex) { resolve(outputsHex); });\n });\n });\n }\n \n async importOutputsHex(outputsHex) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n that._module.import_outputs_hex(that._cppAddress, outputsHex, function(numImported) { resolve(numImported); });\n });\n });\n }\n \n async getKeyImages() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n let callback = function(keyImagesStr) {\n let keyImages = [];\n for (let keyImageJson of JSON.parse(GenUtils.stringifyBIs(keyImagesStr)).keyImages) keyImages.push(new MoneroKeyImage(keyImageJson));\n resolve(keyImages);\n }\n that._module.get_key_images(that._cppAddress, callback);\n });\n });\n }\n \n async importKeyImages(keyImages) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n let callback = function(keyImageImportResultStr) {\n resolve(new MoneroKeyImageImportResult(JSON.parse(GenUtils.stringifyBIs(keyImageImportResultStr))));\n }\n that._module.import_key_images(that._cppAddress, JSON.stringify({keyImages: keyImages.map(keyImage => keyImage.toJson())}), callback);\n });\n });\n }\n \n async getNewKeyImagesFromLastImport() {\n this._assertNotClosed();\n throw new MoneroError(\"Not implemented\");\n }\n \n async createTxs(config) {\n this._assertNotClosed();\n \n // validate, copy, and normalize config\n config = MoneroWallet._normalizeCreateTxsConfig(config);\n if (config.getCanSplit() === undefined) config.setCanSplit(true);\n \n // check for payment id to avoid error in wasm \n if (config.getPaymentId()) throw new MoneroError(\"Standalone payment IDs are obsolete. Use subaddresses or integrated addresses instead\"); // TODO: this should no longer be necessary, remove and re-test\n \n // return promise which resolves on callback\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(txSetJsonStr) {\n if (txSetJsonStr.charAt(0) !== '{') reject(new MoneroError(txSetJsonStr)); // json expected, else error\n else resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBIs(txSetJsonStr))).getTxs());\n }\n \n // create txs in wasm and invoke callback when done\n that._module.create_txs(that._cppAddress, JSON.stringify(config.toJson()), callbackFn);\n });\n });\n }\n \n async sweepOutput(config) {\n this._assertNotClosed();\n \n // normalize and validate config\n config = MoneroWallet._normalizeSweepOutputConfig(config);\n \n // return promise which resolves on callback\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(txSetJsonStr) {\n if (txSetJsonStr.charAt(0) !== '{') reject(new MoneroError(txSetJsonStr)); // json expected, else error\n else resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBIs(txSetJsonStr))).getTxs()[0]);\n }\n \n // sweep output in wasm and invoke callback when done\n that._module.sweep_output(that._cppAddress, JSON.stringify(config.toJson()), callbackFn);\n });\n });\n }\n\n async sweepUnlocked(config) {\n this._assertNotClosed();\n \n // validate and normalize config\n config = MoneroWallet._normalizeSweepUnlockedConfig(config);\n \n // return promise which resolves on callback\n let that = this;\n return that._module.queueTask(async function() { // TODO: could factor this pattern out, invoked with module params and callback handler\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(txSetsJson) {\n if (txSetsJson.charAt(0) !== '{') reject(new MoneroError(txSetsJson)); // json expected, else error\n else {\n let txSets = [];\n for (let txSetJson of JSON.parse(GenUtils.stringifyBIs(txSetsJson)).txSets) txSets.push(new MoneroTxSet(txSetJson));\n let txs = [];\n for (let txSet of txSets) for (let tx of txSet.getTxs()) txs.push(tx);\n resolve(txs);\n }\n }\n \n // sweep unlocked in wasm and invoke callback when done\n that._module.sweep_unlocked(that._cppAddress, JSON.stringify(config.toJson()), callbackFn);\n });\n });\n }\n \n async sweepDust(relay) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n \n // define callback for wasm\n let callbackFn = function(txSetJsonStr) {\n if (txSetJsonStr.charAt(0) !== '{') reject(new MoneroError(txSetJsonStr)); // json expected, else error\n else resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBIs(txSetJsonStr))).getTxs());\n }\n \n // sync wallet in wasm and invoke callback when done\n that._module.sweep_dust(that._cppAddress, relay, callbackFn);\n });\n });\n }\n \n async relayTxs(txsOrMetadatas) {\n this._assertNotClosed();\n assert(Array.isArray(txsOrMetadatas), \"Must provide an array of txs or their metadata to relay\");\n let txMetadatas = [];\n for (let txOrMetadata of txsOrMetadatas) txMetadatas.push(txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata);\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n let callback = function(txHashesJson) {\n if (txHashesJson.charAt(0) !== \"{\") reject(new MoneroError(txHashesJson));\n else resolve(JSON.parse(txHashesJson).txHashes);\n }\n that._module.relay_txs(that._cppAddress, JSON.stringify({txMetadatas: txMetadatas}), callback);\n });\n });\n }\n \n async parseTxSet(txSet) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new MoneroTxSet(JSON.parse(GenUtils.stringifyBIs(that._module.parse_tx_set(that._cppAddress, JSON.stringify(txSet.toJson())))));\n });\n }\n \n async signTxs(unsignedTxHex) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.sign_txs(that._cppAddress, unsignedTxHex);\n });\n }\n \n async submitTxs(signedTxHex) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n let callbackFn = function(resp) {\n resolve(JSON.parse(resp).txHashes);\n }\n that._module.submit_txs(that._cppAddress, signedTxHex, callbackFn);\n });\n });\n }\n \n async signMessage(message) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.sign_message(that._cppAddress, message);\n });\n }\n \n async verifyMessage(message, address, signature) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.verify_message(that._cppAddress, message, address, signature);\n });\n }\n \n async getTxKey(txHash) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.get_tx_key(that._cppAddress, txHash);\n });\n }\n \n async checkTxKey(txHash, txKey, address) {\n throw new Error(\"MoneroWalletWasm.checkTxKey() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html\")\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new MoneroCheckTx(JSON.parse(GenUtils.stringifyBIs(that._module.check_tx_key(that._cppAddress, txHash, txKey, address))));\n });\n }\n \n async getTxProof(txHash, address, message) {\n throw new Error(\"MoneroWalletWasm.checkTxKey() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html\")\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.get_tx_proof(that._cppAddress, txHash, address, message);\n });\n }\n \n async checkTxProof(txHash, address, message, signature) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new MoneroCheckTx(JSON.parse(GenUtils.stringifyBIs(that._module.check_tx_proof(that._cppAddress, txHash, address, message, signature))));\n });\n }\n \n async getSpendProof(txHash, message) {\n throw new Error(\"MoneroWalletWasm.getSpendProof() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html\"); // TODO\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.get_spend_proof(that._cppAddress, txHash, message);\n });\n }\n \n async checkSpendProof(txHash, message, signature) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.check_spend_proof(that._cppAddress, txHash, message, signature);\n });\n }\n \n async getReserveProofWallet(message) {\n throw new Error(\"MoneroWalletWasm.getReserveProofWallet() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html\"); // TODO\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.get_reserve_proof_wallet(that._cppAddress, message);\n });\n }\n \n async getReserveProofAccount(accountIdx, amount, message) {\n throw new Error(\"MoneroWalletWasm.getReserveProofAccount() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html\"); // TODO\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.get_reserve_proof_account(that._cppAddress, accountIdx, amount.toString(), message);\n });\n }\n\n async checkReserveProof(address, message, signature) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new MoneroCheckReserve(JSON.parse(GenUtils.stringifyBIs(that._module.check_reserve_proof(that._cppAddress, address, message, signature))));\n });\n }\n \n async getTxNotes(txHashes) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return JSON.parse(that._module.get_tx_notes(that._cppAddress, JSON.stringify({txHashes: txHashes}))).txNotes;\n });\n }\n \n async setTxNotes(txHashes, notes) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n that._module.set_tx_notes(that._cppAddress, JSON.stringify({txHashes: txHashes, txNotes: notes}));\n });\n }\n \n async getAddressBookEntries(entryIndices) {\n if (!entryIndices) entryIndices = [];\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n let entries = [];\n for (let entryJson of JSON.parse(that._module.get_address_book_entries(that._cppAddress, JSON.stringify({entryIndices: entryIndices}))).entries) {\n entries.push(new MoneroAddressBookEntry(entryJson));\n }\n return entries;\n });\n }\n \n async addAddressBookEntry(address, description) {\n if (!address) address = \"\";\n if (!description) description = \"\";\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.add_address_book_entry(that._cppAddress, address, description);\n });\n }\n \n async editAddressBookEntry(index, setAddress, address, setDescription, description) {\n if (!setAddress) setAddress = false;\n if (!address) address = \"\";\n if (!setDescription) setDescription = false;\n if (!description) description = \"\";\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n that._module.edit_address_book_entry(that._cppAddress, index, setAddress, address, setDescription, description);\n });\n }\n \n async deleteAddressBookEntry(entryIdx) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n that._module.delete_address_book_entry(that._cppAddress, entryIdx);\n });\n }\n \n async tagAccounts(tag, accountIndices) {\n if (!tag) tag = \"\";\n if (!accountIndices) accountIndices = [];\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n that._module.tag_accounts(that._cppAddress, JSON.stringify({tag: tag, accountIndices: accountIndices}));\n });\n }\n\n async untagAccounts(accountIndices) {\n if (!accountIndices) accountIndices = [];\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n that._module.tag_accounts(that._cppAddress, JSON.stringify({accountIndices: accountIndices}));\n });\n }\n \n async getAccountTags() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n let accountTags = [];\n for (let accountTagJson of JSON.parse(that._module.get_account_tags(that._cppAddress)).accountTags) accountTags.push(new MoneroAccountTag(accountTagJson));\n return accountTags;\n });\n }\n\n async setAccountTagLabel(tag, label) {\n if (!tag) tag = \"\";\n if (!llabel) label = \"\";\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n that._module.set_account_tag_label(that._cppAddress, tag, label);\n });\n }\n \n async createPaymentUri(config) {\n config = MoneroWallet._normalizeCreateTxsConfig(config);\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n try {\n return that._module.create_payment_uri(that._cppAddress, JSON.stringify(config.toJson()));\n } catch (e) {\n throw new MoneroError(\"Cannot make URI from supplied parameters\");\n }\n });\n }\n \n async parsePaymentUri(uri) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n try {\n return new MoneroTxConfig(JSON.parse(GenUtils.stringifyBIs(that._module.parse_payment_uri(that._cppAddress, uri))));\n } catch (e) {\n throw new MoneroError(e.message);\n }\n });\n }\n \n async getAttribute(key) {\n this._assertNotClosed();\n assert(typeof key === \"string\", \"Attribute key must be a string\");\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n let value = that._module.get_attribute(that._cppAddress, key);\n return value === \"\" ? null : value;\n });\n }\n \n async setAttribute(key, val) {\n this._assertNotClosed();\n assert(typeof key === \"string\", \"Attribute key must be a string\");\n assert(typeof val === \"string\", \"Attribute value must be a string\");\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n that._module.set_attribute(that._cppAddress, key, val);\n });\n }\n \n async startMining(numThreads, backgroundMining, ignoreBattery) {\n this._assertNotClosed();\n let daemon = new MoneroDaemonRpc(await this.getDaemonConnection());\n await daemon.startMining(await this.getPrimaryAddress(), numThreads, backgroundMining, ignoreBattery);\n }\n \n async stopMining() {\n this._assertNotClosed();\n let daemon = new MoneroDaemonRpc(await this.getDaemonConnection());\n await daemon.stopMining();\n }\n \n async isMultisigImportNeeded() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.is_multisig_import_needed(that._cppAddress);\n });\n }\n \n async isMultisig() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.is_multisig(that._cppAddress);\n });\n }\n \n async getMultisigInfo() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new MoneroMultisigInfo(JSON.parse(that._module.get_multisig_info(that._cppAddress)));\n });\n }\n \n async prepareMultisig() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.prepare_multisig(that._cppAddress);\n });\n }\n \n async makeMultisig(multisigHexes, threshold, password) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new MoneroMultisigInitResult(JSON.parse(that._module.make_multisig(that._cppAddress, JSON.stringify({multisigHexes: multisigHexes, threshold: threshold, password: password}))));\n });\n }\n \n async exchangeMultisigKeys(multisigHexes, password) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new MoneroMultisigInitResult(JSON.parse(that._module.exchange_multisig_keys(that._cppAddress, JSON.stringify({multisigHexes: multisigHexes, password: password}))));\n });\n }\n \n async getMultisigHex() {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return that._module.get_multisig_hex(that._cppAddress);\n });\n }\n \n async importMultisigHex(multisigHexes) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n let callbackFn = function(resp) {\n if (typeof resp === \"string\") reject(new MoneroError(resp));\n else resolve(resp);\n }\n that._module.import_multisig_hex(that._cppAddress, JSON.stringify({multisigHexes: multisigHexes}), callbackFn);\n });\n });\n }\n \n async signMultisigTxHex(multisigTxHex) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new MoneroMultisigSignResult(JSON.parse(that._module.sign_multisig_tx_hex(that._cppAddress, multisigTxHex)));\n });\n }\n \n async submitMultisigTxHex(signedMultisigTxHex) {\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n return new Promise(function(resolve, reject) {\n let callbackFn = function(resp) { resolve(JSON.parse(resp).txHashes); }\n that._module.submit_multisig_tx_hex(that._cppAddress, signedMultisigTxHex, callbackFn);\n });\n });\n }\n \n /**\n * Get the wallet's keys and cache data.\n * \n * @return {DataView[]} is the keys and cache data respectively\n */\n async getData() {\n this._assertNotClosed();\n \n // queue call to wasm module\n let viewOnly = await this.isViewOnly();\n let that = this;\n return that._module.queueTask(async function() {\n that._assertNotClosed();\n\n // store views in array\n let views = [];\n \n // malloc cache buffer and get buffer location in c++ heap\n let cacheBufferLoc = JSON.parse(that._module.get_cache_file_buffer(that._cppAddress, that._password));\n \n // read binary data from heap to DataView\n let view = new DataView(new ArrayBuffer(cacheBufferLoc.length));\n for (let i = 0; i < cacheBufferLoc.length; i++) {\n view.setInt8(i, that._module.HEAPU8[cacheBufferLoc.pointer / Uint8Array.BYTES_PER_ELEMENT + i]);\n }\n \n // free binary on heap\n that._module._free(cacheBufferLoc.pointer);\n \n // write cache file\n views.push(Buffer.from(view.buffer));\n \n // malloc keys buffer and get buffer location in c++ heap\n let keysBufferLoc = JSON.parse(that._module.get_keys_file_buffer(that._cppAddress, that._password, viewOnly));\n \n // read binary data from heap to DataView\n view = new DataView(new ArrayBuffer(keysBufferLoc.length));\n for (let i = 0; i < keysBufferLoc.length; i++) {\n view.setInt8(i, that._module.HEAPU8[keysBufferLoc.pointer / Uint8Array.BYTES_PER_ELEMENT + i]);\n }\n \n // free binary on heap\n that._module._free(keysBufferLoc.pointer);\n \n // prepend keys file\n views.unshift(Buffer.from(view.buffer));\n return views;\n });\n }\n\n async save() {\n this._assertNotClosed();\n \n // path must be set\n let path = await this.getPath();\n if (!path) throw new MoneroError(\"Cannot save wallet because path is not set\");\n \n // write address file\n this._fs.writeFileSync(path + \".address.txt\", await this.getPrimaryAddress());\n \n // write keys and cache data\n let data = await this.getData();\n this._fs.writeFileSync(path + \".keys\", data[0], \"binary\");\n this._fs.writeFileSync(path, data[1], \"binary\");\n }\n \n async close(save) {\n if (this._isClosed) return; // no effect if closed\n this._syncingEnabled = false;\n await this._setIsListening(false);\n await this.stopSyncing();\n await super.close(save);\n delete this._path;\n delete this._password;\n delete this._listeners;\n delete this._wasmListener;\n LibraryUtils.setRejectUnauthorizedFn(this._rejectUnauthorizedConfigId, undefined); // unregister fn informing if unauthorized reqs should be rejected\n }\n \n // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS --------------\n \n async getTx() { return super.getTx(...arguments); }\n async getIncomingTransfers() { return super.getIncomingTransfers(...arguments); }\n async getOutgoingTransfers() { return super.getOutgoingTransfers(...arguments); }\n async createTx() { return super.createTx(...arguments); }\n async relayTx() { return super.relayTx(...arguments); }\n async getTxNote() { return super.getTxNote(...arguments); }\n async setTxNote() { return super.setTxNote(...arguments); }\n \n // ---------------------------- PRIVATE HELPERS ----------------------------\n \n static _getFs() {\n if (!MoneroWalletWasm.FS) MoneroWalletWasm.FS = GenUtils.isBrowser() ? undefined : require('fs');\n return MoneroWalletWasm.FS;\n }\n \n static async _openWalletData(path, password, networkType, keysData, cacheData, daemonUriOrConnection, proxyToWorker, fs) {\n if (proxyToWorker) return MoneroWalletWasmProxy.openWalletData(path, password, networkType, keysData, cacheData, daemonUriOrConnection, fs);\n \n // validate and normalize parameters\n assert(password, \"Must provide a password to open the wallet\");\n if (networkType === undefined) throw new MoneroError(\"Must provide the wallet's network type\");\n MoneroNetworkType.validate(networkType);\n let daemonConnection = typeof daemonUriOrConnection === \"string\" ? new MoneroRpcConnection(daemonUriOrConnection) : daemonUriOrConnection;\n let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : \"\";\n let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : \"\";\n let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : \"\";\n let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true;\n \n // load wasm module\n let module = await LibraryUtils.loadCoreModule();\n \n // open wallet in queue\n return module.queueTask(async function() {\n return new Promise(function(resolve, reject) {\n \n // register fn informing if unauthorized reqs should be rejected\n let rejectUnauthorizedFnId = GenUtils.getUUID();\n LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return rejectUnauthorized });\n \n // define callback for wasm\n let callbackFn = async function(cppAddress) {\n if (typeof cppAddress === \"string\") reject(new MoneroError(cppAddress));\n else resolve(new MoneroWalletWasm(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId));\n };\n \n // create wallet in wasm and invoke callback when done\n module.open_core_wallet(password, networkType, keysData, cacheData, daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, callbackFn);\n });\n });\n }\n \n /**\n * Loop while syncing enabled.\n */\n async _runSyncLoop() {\n if (this._syncLoopRunning) return; // only run one loop at a time\n this._syncLoopRunning = true;\n \n // sync while enabled\n let label = this._path ? this._path : (this._browserMainPath ? this._browserMainPath : \"in-memory wallet\"); // label for log\n while (this._syncingEnabled) {\n try {\n console.log(\"Background synchronizing \" + label);\n await this.sync();\n } catch (e) {\n if (!this._isClosed) console.log(\"Failed to background synchronize \" + label + \": \" + e.message);\n }\n \n // only wait if syncing still enabled\n if (this._syncingEnabled) await new Promise(function(resolve) { setTimeout(resolve, MoneroUtils.WALLET_REFRESH_RATE); });\n }\n \n this._syncLoopRunning = false;\n }\n \n /**\n * Enables or disables listening in the c++ wallet.\n */\n async _setIsListening(isEnabled) {\n let that = this;\n return that._module.queueTask(async function() {\n if (isEnabled) {\n that._wasmListenerHandle = that._module.set_listener(\n that._cppAddress,\n that._wasmListenerHandle,\n function(height, startHeight, endHeight, percentDone, message) { that._wasmListener.onSyncProgress(height, startHeight, endHeight, percentDone, message); },\n function(height) { that._wasmListener.onNewBlock(height); },\n function(newBalanceStr, newUnlockedBalanceStr) { that._wasmListener.onBalancesChanged(newBalanceStr, newUnlockedBalanceStr); },\n function(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockHeight, isLocked) { that._wasmListener.onOutputReceived(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockHeight, isLocked); },\n function(height, txHash, amountStr, accountIdx, subaddressIdx, version) { that._wasmListener.onOutputSpent(height, txHash, amountStr, accountIdx, subaddressIdx, version); });\n } else {\n that._wasmListenerHandle = that._module.set_listener(that._cppAddress, that._wasmListenerHandle, undefined, undefined, undefined, undefined, undefined);\n }\n });\n }\n \n static _sanitizeBlock(block) {\n for (let tx of block.getTxs()) MoneroWalletWasm._sanitizeTxWallet(tx);\n return block;\n }\n \n static _sanitizeTxWallet(tx) {\n assert(tx instanceof MoneroTxWallet);\n return tx;\n }\n \n static _sanitizeAccount(account) {\n if (account.getSubaddresses()) {\n for (let subaddress of account.getSubaddresses()) MoneroWalletWasm._sanitizeSubaddress(subaddress);\n }\n return account;\n }\n \n static _sanitizeSubaddress(subaddress) {\n if (subaddress.getLabel() === \"\") subaddress.setLabel(undefined);\n return subaddress\n }\n \n static _deserializeBlocks(blocksJsonStr) {\n let blocksJson = JSON.parse(GenUtils.stringifyBIs(blocksJsonStr));\n let deserializedBlocks = {};\n deserializedBlocks.blocks = [];\n deserializedBlocks.missingTxHashes = [];\n if (blocksJson.blocks) for (let blockJson of blocksJson.blocks) deserializedBlocks.blocks.push(MoneroWalletWasm._sanitizeBlock(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET)));\n if (blocksJson.missingTxHashes) for (let missingTxHash of blocksJson.missingTxHashes) deserializedBlocks.missingTxHashes.push(missingTxHash);\n return deserializedBlocks;\n }\n \n static _deserializeTxs(query, blocksJsonStr, missingTxHashes) {\n \n // deserialize blocks\n let deserializedBlocks = MoneroWalletWasm._deserializeBlocks(blocksJsonStr);\n if (missingTxHashes === undefined && deserializedBlocks.missingTxHashes.length > 0) throw new MoneroError(\"Wallet missing requested tx hashes: \" + deserializedBlocks.missingTxHashes);\n for (let missingTxHash of deserializedBlocks.missingTxHashes) missingTxHashes.push(missingTxHash);\n let blocks = deserializedBlocks.blocks;\n \n // collect txs\n let txs = [];\n for (let block of blocks) {\n MoneroWalletWasm._sanitizeBlock(block);\n for (let tx of block.getTxs()) {\n if (block.getHeight() === undefined) tx.setBlock(undefined); // dereference placeholder block for unconfirmed txs\n txs.push(tx);\n }\n }\n \n // re-sort txs which is lost over wasm serialization // TODO: confirm that order is lost\n if (query.getHashes() !== undefined) {\n let txMap = new Map();\n for (let tx of txs) txMap[tx.getHash()] = tx;\n let txsSorted = [];\n for (let txHash of query.getHashes()) if (txMap[txHash] !== undefined) txsSorted.push(txMap[txHash]);\n txs = txsSorted;\n }\n \n return txs;\n }\n \n static _deserializeTransfers(query, blocksJsonStr) {\n \n // deserialize blocks\n let deserializedBlocks = MoneroWalletWasm._deserializeBlocks(blocksJsonStr);\n if (deserializedBlocks.missingTxHashes.length > 0) throw new MoneroError(\"Wallet missing requested tx hashes: \" + deserializedBlocks.missingTxHashes);\n let blocks = deserializedBlocks.blocks;\n \n // collect transfers\n let transfers = [];\n for (let block of blocks) {\n for (let tx of block.getTxs()) {\n if (block.getHeight() === undefined) tx.setBlock(undefined); // dereference placeholder block for unconfirmed txs\n if (tx.getOutgoingTransfer() !== undefined) transfers.push(tx.getOutgoingTransfer());\n if (tx.getIncomingTransfers() !== undefined) {\n for (let transfer of tx.getIncomingTransfers()) transfers.push(transfer);\n }\n }\n }\n \n return transfers;\n }\n \n static _deserializeOutputs(query, blocksJsonStr) {\n \n // deserialize blocks\n let deserializedBlocks = MoneroWalletWasm._deserializeBlocks(blocksJsonStr);\n if (deserializedBlocks.missingTxHashes.length > 0) throw new MoneroError(\"Wallet missing requested tx hashes: \" + deserializedBlocks.missingTxHashes);\n let blocks = deserializedBlocks.blocks;\n \n // collect outputs\n let outputs = [];\n for (let block of blocks) {\n for (let tx of block.getTxs()) {\n for (let output of tx.getOutputs()) outputs.push(output);\n }\n }\n \n return outputs;\n }\n \n /**\n * Set the path of the wallet on the browser main thread if run as a web worker.\n * \n * @param {string} browserMainPath - path of the wallet on the browser main thread\n */\n _setBrowserMainPath(browserMainPath) {\n this._browserMainPath = browserMainPath;\n }\n}\n\n// ------------------------------- LISTENERS --------------------------------\n\n/**\n * Receives notifications directly from wasm c++.\n * \n * @private\n */\nclass WalletWasmListener {\n \n constructor(wallet) {\n this._wallet = wallet;\n }\n \n onSyncProgress(height, startHeight, endHeight, percentDone, message) {\n for (let listener of this._wallet.getListeners()) {\n listener.onSyncProgress(height, startHeight, endHeight, percentDone, message);\n }\n }\n \n onNewBlock(height) {\n for (let listener of this._wallet.getListeners()) listener.onNewBlock(height);\n }\n \n onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) {\n for (let listener of this._wallet.getListeners()) listener.onBalancesChanged(BigInteger.parse(newBalanceStr), BigInteger.parse(newUnlockedBalanceStr));\n }\n \n onOutputReceived(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockHeight, isLocked) {\n \n // build received output\n let output = new MoneroOutputWallet();\n output.setAmount(BigInteger.parse(amountStr));\n output.setAccountIndex(accountIdx);\n output.setSubaddressIndex(subaddressIdx);\n let tx = new MoneroTxWallet();\n tx.setHash(txHash);\n tx.setVersion(version);\n tx.setUnlockHeight(unlockHeight);\n output.setTx(tx);\n tx.setOutputs([output]);\n tx.setIsIncoming(true);\n tx.setIsLocked(isLocked);\n if (height > 0) {\n let block = new MoneroBlock().setHeight(height);\n block.setTxs([tx]);\n tx.setBlock(block);\n tx.setIsConfirmed(true);\n tx.setInTxPool(false);\n tx.setIsFailed(false);\n } else {\n tx.setIsConfirmed(false);\n tx.setInTxPool(true);\n }\n \n // announce output\n for (let listener of this._wallet.getListeners()) listener.onOutputReceived(tx.getOutputs()[0]);\n }\n \n onOutputSpent(height, txHash, amountStr, accountIdx, subaddressIdx, version) {\n \n // build spent output\n let output = new MoneroOutputWallet();\n output.setAmount(BigInteger.parse(amountStr));\n output.setAccountIndex(accountIdx);\n output.setSubaddressIndex(subaddressIdx);\n let tx = new MoneroTxWallet();\n tx.setHash(txHash);\n tx.setVersion(version);\n output.setTx(tx);\n tx.setInputs([output]);\n if (height > 0) {\n let block = new MoneroBlock().setHeight(height);\n block.setTxs([tx]);\n tx.setBlock(block);\n tx.setIsConfirmed(true);\n tx.setInTxPool(false);\n tx.setIsFailed(false);\n } else {\n tx.setIsConfirmed(false);\n tx.setInTxPool(true);\n }\n \n // notify wallet listeners\n for (let listener of this._wallet.getListeners()) listener.onOutputSpent(tx.getInputs()[0]);\n }\n}\n\n/**\n * Wraps a sync listener as a general wallet listener.\n * \n * @private\n */\nclass SyncListenerWrapper extends MoneroWalletListener {\n \n constructor(listener) {\n super();\n this._listener = listener;\n }\n \n onSyncProgress(height, startHeight, endHeight, percentDone, message) {\n this._listener.onSyncProgress(height, startHeight, endHeight, percentDone, message);\n }\n}\n\n/**\n * Implements a MoneroWallet by proxying requests to a web worker which runs a core wallet.\n * \n * TODO: sort these methods according to master sort in MoneroWallet.js\n * TODO: probably only allow one listener to web worker then propogate to registered listeners for performance\n * TODO: ability to recycle worker for use in another wallet\n * TODO: using LibraryUtils.WORKER_OBJECTS directly breaks encapsulation\n * \n * @private\n */\nclass MoneroWalletWasmProxy extends MoneroWallet {\n \n // -------------------------- WALLET STATIC UTILS ---------------------------\n \n static async openWalletData(path, password, networkType, keysData, cacheData, daemonUriOrConnection, fs) {\n let walletId = GenUtils.getUUID();\n let daemonUriOrConfig = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection.getConfig() : daemonUriOrConnection;\n await LibraryUtils.invokeWorker(walletId, \"openWalletData\", [path, password, networkType, keysData, cacheData, daemonUriOrConfig]);\n let wallet = new MoneroWalletWasmProxy(walletId, LibraryUtils.getWorker(), path, fs);\n if (path) await wallet.save();\n return wallet;\n }\n \n static async _createWalletRandom(path, password, networkType, daemonUriOrConnection, language, fs) {\n if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error(\"Wallet already exists: \" + path);\n let walletId = GenUtils.getUUID();\n let daemonUriOrConfig = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection.getConfig() : daemonUriOrConnection;\n await LibraryUtils.invokeWorker(walletId, \"_createWalletRandom\", [path, password, networkType, daemonUriOrConfig, language]);\n let wallet = new MoneroWalletWasmProxy(walletId, LibraryUtils.getWorker(), path, fs);\n if (path) await wallet.save();\n return wallet;\n }\n \n static async _createWalletFromMnemonic(path, password, networkType, mnemonic, daemonUriOrConnection, restoreHeight, seedOffset, fs) {\n if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error(\"Wallet already exists: \" + path);\n let walletId = GenUtils.getUUID();\n let daemonUriOrConfig = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection.getConfig() : daemonUriOrConnection;\n await LibraryUtils.invokeWorker(walletId, \"_createWalletFromMnemonic\", [path, password, networkType, mnemonic, daemonUriOrConfig, restoreHeight, seedOffset]);\n let wallet = new MoneroWalletWasmProxy(walletId, LibraryUtils.getWorker(), path, fs);\n if (path) await wallet.save();\n return wallet;\n }\n \n static async _createWalletFromKeys(path, password, networkType, address, viewKey, spendKey, daemonUriOrConnection, restoreHeight, language, fs) {\n if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error(\"Wallet already exists: \" + path);\n let walletId = GenUtils.getUUID();\n let daemonUriOrConfig = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection.getConfig() : daemonUriOrConnection;\n await LibraryUtils.invokeWorker(walletId, \"_createWalletFromKeys\", [path, password, networkType, address, viewKey, spendKey, daemonUriOrConfig, restoreHeight, language]);\n let wallet = new MoneroWalletWasmProxy(walletId, LibraryUtils.getWorker(), path, fs);\n if (path) await wallet.save();\n return wallet;\n }\n \n // --------------------------- INSTANCE METHODS ----------------------------\n \n /**\n * Internal constructor which is given a worker to communicate with via messages.\n * \n * This method should not be called externally but should be called through\n * static wallet creation utilities in this class.\n * \n * @param {string} walletId - identifies the wallet with the worker\n * @param {Worker} worker - web worker to communicate with via messages\n */\n constructor(walletId, worker, path, fs) {\n super();\n this._walletId = walletId;\n this._worker = worker;\n this._path = path;\n this._fs = fs ? fs : (path ? MoneroWalletWasm._getFs() : undefined);\n this._wrappedListeners = [];\n }\n \n async isViewOnly() {\n return this._invokeWorker(\"isViewOnly\");\n }\n \n async getNetworkType() {\n return this._invokeWorker(\"getNetworkType\");\n }\n \n async getVersion() {\n throw new Error(\"Not implemented\");\n }\n \n getPath() {\n return this._path;\n }\n \n async getMnemonic() {\n return this._invokeWorker(\"getMnemonic\");\n }\n \n async getMnemonicLanguage() {\n return this._invokeWorker(\"getMnemonicLanguage\");\n }\n \n async getMnemonicLanguages() {\n return this._invokeWorker(\"getMnemonicLanguages\");\n }\n \n async getPrivateSpendKey() {\n return this._invokeWorker(\"getPrivateSpendKey\");\n }\n \n async getPrivateViewKey() {\n return this._invokeWorker(\"getPrivateViewKey\");\n }\n \n async getPublicViewKey() {\n return this._invokeWorker(\"getPublicViewKey\");\n }\n \n async getPublicSpendKey() {\n return this._invokeWorker(\"getPublicSpendKey\");\n }\n \n async getAddress(accountIdx, subaddressIdx) {\n return this._invokeWorker(\"getAddress\", Array.from(arguments));\n }\n \n async getAddressIndex(address) {\n let subaddressJson = await this._invokeWorker(\"getAddressIndex\", Array.from(arguments));\n return MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson));\n }\n \n async getIntegratedAddress(paymentId) {\n return new MoneroIntegratedAddress(await this._invokeWorker(\"getIntegratedAddress\", Array.from(arguments)));\n }\n \n async decodeIntegratedAddress(integratedAddress) {\n return new MoneroIntegratedAddress(await this._invokeWorker(\"decodeIntegratedAddress\", Array.from(arguments)));\n }\n \n async setDaemonConnection(uriOrRpcConnection, username, password) {\n if (!uriOrRpcConnection) await this._invokeWorker(\"setDaemonConnection\");\n else {\n let connection = uriOrRpcConnection instanceof MoneroRpcConnection? uriOrRpcConnection : new MoneroRpcConnection({uri: uriOrRpcConnection, username: username, password: password});\n await this._invokeWorker(\"setDaemonConnection\", connection.getConfig());\n }\n }\n \n async getDaemonConnection() {\n let rpcConfig = await this._invokeWorker(\"getDaemonConnection\");\n return rpcConfig ? new MoneroRpcConnection(rpcConfig) : undefined;\n }\n \n async isConnected() {\n return this._invokeWorker(\"isConnected\");\n }\n \n async getSyncHeight() {\n return this._invokeWorker(\"getSyncHeight\");\n }\n \n async setSyncHeight(syncHeight) {\n return this._invokeWorker(\"setSyncHeight\", [syncHeight]);\n }\n \n async getDaemonHeight() {\n return this._invokeWorker(\"getDaemonHeight\");\n }\n \n async getDaemonMaxPeerHeight() {\n return this._invokeWorker(\"getDaemonMaxPeerHeight\");\n }\n \n async getHeightByDate(year, month, day) {\n return this._invokeWorker(\"getHeightByDate\", [year, month, day]);\n }\n \n async isDaemonSynced() {\n return this._invokeWorker(\"isDaemonSynced\");\n }\n \n async getHeight() {\n return this._invokeWorker(\"getHeight\");\n }\n \n async addListener(listener) {\n let wrappedListener = new WalletWorkerListener(listener);\n let listenerId = wrappedListener.getId();\n LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks[\"onSyncProgress_\" + listenerId] = [wrappedListener.onSyncProgress, wrappedListener];\n LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks[\"onNewBlock_\" + listenerId] = [wrappedListener.onNewBlock, wrappedListener];\n LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks[\"onBalancesChanged_\" + listenerId] = [wrappedListener.onBalancesChanged, wrappedListener];\n LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks[\"onOutputReceived_\" + listenerId] = [wrappedListener.onOutputReceived, wrappedListener];\n LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks[\"onOutputSpent_\" + listenerId] = [wrappedListener.onOutputSpent, wrappedListener];\n this._wrappedListeners.push(wrappedListener);\n return this._invokeWorker(\"addListener\", [listenerId]);\n }\n \n async removeListener(listener) {\n for (let i = 0; i < this._wrappedListeners.length; i++) {\n if (this._wrappedListeners[i].getListener() === listener) {\n let listenerId = this._wrappedListeners[i].getId();\n await this._invokeWorker(\"removeListener\", [listenerId]);\n delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks[\"onSyncProgress_\" + listenerId];\n delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks[\"onNewBlock_\" + listenerId];\n delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks[\"onBalancesChanged_\" + listenerId];\n delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks[\"onOutputReceived_\" + listenerId];\n delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks[\"onOutputSpent_\" + listenerId];\n this._wrappedListeners.splice(i, 1);\n return;\n }\n }\n throw new MoneroError(\"Listener is not registered with wallet\");\n }\n \n getListeners() {\n let listeners = [];\n for (let wrappedListener of this._wrappedListeners) listeners.push(wrappedListener.getListener());\n return listeners;\n }\n \n async isSynced() {\n return this._invokeWorker(\"isSynced\");\n }\n \n async sync(listenerOrStartHeight, startHeight) {\n \n // normalize params\n startHeight = listenerOrStartHeight instanceof MoneroWalletListener ? startHeight : listenerOrStartHeight;\n let listener = listenerOrStartHeight instanceof MoneroWalletListener ? listenerOrStartHeight : undefined;\n if (startHeight === undefined) startHeight = Math.max(await this.getHeight(), await this.getSyncHeight());\n \n // register listener if given\n if (listener) await this.addListener(listener);\n \n // sync wallet in worker \n let err;\n let result;\n try {\n let resultJson = await this._invokeWorker(\"sync\", [startHeight]);\n result = new MoneroSyncResult(resultJson.numBlocksFetched, resultJson.receivedMoney);\n } catch (e) {\n err = e;\n }\n \n // unregister listener\n if (listener) await this.removeListener(listener);\n \n // throw error or return\n if (err) throw err;\n return result;\n }\n \n async startSyncing() {\n return this._invokeWorker(\"startSyncing\");\n }\n \n async stopSyncing() {\n return this._invokeWorker(\"stopSyncing\");\n }\n \n async rescanSpent() {\n return this._invokeWorker(\"rescanSpent\");\n }\n \n async rescanBlockchain() {\n return this._invokeWorker(\"rescanBlockchain\");\n }\n \n async getBalance(accountIdx, subaddressIdx) {\n return BigInteger.parse(await this._invokeWorker(\"getBalance\", Array.from(arguments)));\n }\n \n async getUnlockedBalance(accountIdx, subaddressIdx) {\n let unlockedBalanceStr = await this._invokeWorker(\"getUnlockedBalance\", Array.from(arguments));\n return BigInteger.parse(unlockedBalanceStr);\n }\n \n async getAccounts(includeSubaddresses, tag) {\n let accounts = [];\n for (let accountJson of (await this._invokeWorker(\"getAccounts\", Array.from(arguments)))) {\n accounts.push(MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson)));\n }\n return accounts;\n }\n \n async getAccount(accountIdx, includeSubaddresses) {\n let accountJson = await this._invokeWorker(\"getAccount\", Array.from(arguments));\n return MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson));\n }\n \n async createAccount(label) {\n let accountJson = await this._invokeWorker(\"createAccount\", Array.from(arguments));\n return MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson));\n }\n \n async getSubaddresses(accountIdx, subaddressIndices) {\n let subaddresses = [];\n for (let subaddressJson of (await this._invokeWorker(\"getSubaddresses\", Array.from(arguments)))) {\n subaddresses.push(MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson)));\n }\n return subaddresses;\n }\n \n async createSubaddress(accountIdx, label) {\n let subaddressJson = await this._invokeWorker(\"createSubaddress\", Array.from(arguments));\n return MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson));\n }\n \n async getTxs(query, missingTxHashes) {\n query = MoneroWallet._normalizeTxQuery(query);\n let blockJsons = await this._invokeWorker(\"getTxs\", [query.getBlock().toJson()]);\n return MoneroWalletWasm._deserializeTxs(query, JSON.stringify({blocks: blockJsons}), missingTxHashes); // initialize txs from blocks json string TODO: this stringifies then utility parses, avoid\n }\n \n async getTransfers(query) {\n query = MoneroWallet._normalizeTransferQuery(query);\n let blockJsons = await this._invokeWorker(\"getTransfers\", [query.getTxQuery().getBlock().toJson()]);\n return MoneroWalletWasm._deserializeTransfers(query, JSON.stringify({blocks: blockJsons})); // initialize transfers from blocks json string TODO: this stringifies then utility parses, avoid\n }\n \n async getOutputs(query) {\n query = MoneroWallet._normalizeOutputQuery(query);\n let blockJsons = await this._invokeWorker(\"getOutputs\", [query.getTxQuery().getBlock().toJson()]);\n return MoneroWalletWasm._deserializeOutputs(query, JSON.stringify({blocks: blockJsons})); // initialize transfers from blocks json string TODO: this stringifies then utility parses, avoid\n }\n \n async getOutputsHex() {\n return this._invokeWorker(\"getOutputsHex\");\n }\n \n async importOutputsHex(outputsHex) {\n return this._invokeWorker(\"importOutputsHex\", [outputsHex]);\n }\n \n async getKeyImages() {\n let keyImages = [];\n for (let keyImageJson of await this._invokeWorker(\"getKeyImages\")) keyImages.push(new MoneroKeyImage(keyImageJson));\n return keyImages;\n }\n \n async importKeyImages(keyImages) {\n let keyImagesJson = [];\n for (let keyImage of keyImages) keyImagesJson.push(keyImage.toJson());\n return new MoneroKeyImageImportResult(await this._invokeWorker(\"importKeyImages\", [keyImagesJson]));\n }\n \n async getNewKeyImagesFromLastImport() {\n throw new MoneroError(\"MoneroWalletWasm.getNewKeyImagesFromLastImport() not implemented\");\n }\n \n async createTxs(config) {\n config = MoneroWallet._normalizeCreateTxsConfig(config);\n let txSetJson = await this._invokeWorker(\"createTxs\", [config.toJson()]);\n return new MoneroTxSet(txSetJson).getTxs();\n }\n \n async sweepOutput(config) {\n config = MoneroWallet._normalizeSweepOutputConfig(config);\n let txSetJson = await this._invokeWorker(\"sweepOutput\", [config.toJson()]);\n return new MoneroTxSet(txSetJson).getTxs()[0];\n }\n\n async sweepUnlocked(config) {\n config = MoneroWallet._normalizeSweepUnlockedConfig(config);\n let txSetsJson = await this._invokeWorker(\"sweepUnlocked\", [config.toJson()]);\n let txs = [];\n for (let txSetJson of txSetsJson) for (let tx of new MoneroTxSet(txSetJson).getTxs()) txs.push(tx);\n return txs;\n }\n \n async sweepDust(relay) {\n return new MoneroTxSet(await this._invokeWorker(\"sweepDust\", [relay])).getTxs();\n }\n \n async relayTxs(txsOrMetadatas) {\n assert(Array.isArray(txsOrMetadatas), \"Must provide an array of txs or their metadata to relay\");\n let txMetadatas = [];\n for (let txOrMetadata of txsOrMetadatas) txMetadatas.push(txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata);\n return this._invokeWorker(\"relayTxs\", [txMetadatas]);\n }\n \n async parseTxSet(txSet) {\n return new MoneroTxSet(await this._invokeWorker(\"parseTxSet\", [txSet.toJson()]));\n }\n \n async signTxs(unsignedTxHex) {\n return this._invokeWorker(\"signTxs\", Array.from(arguments));\n }\n \n async submitTxs(signedTxHex) {\n return this._invokeWorker(\"submitTxs\", Array.from(arguments));\n }\n \n async signMessage(message) {\n return this._invokeWorker(\"signMessage\", Array.from(arguments));\n }\n \n async verifyMessage(message, address, signature) {\n return this._invokeWorker(\"verifyMessage\", Array.from(arguments));\n }\n \n async getTxKey(txHash) {\n return this._invokeWorker(\"getTxKey\", Array.from(arguments));\n }\n \n async checkTxKey(txHash, txKey, address) {\n return new MoneroCheckTx(await this._invokeWorker(\"checkTxKey\", Array.from(arguments)));\n }\n \n async getTxProof(txHash, address, message) {\n return this._invokeWorker(\"getTxProof\", Array.from(arguments));\n }\n \n async checkTxProof(txHash, address, message, signature) {\n return new MoneroCheckTx(await this._invokeWorker(\"checkTxProof\", Array.from(arguments)));\n }\n \n async getSpendProof(txHash, message) {\n return this._invokeWorker(\"getSpendProof\", Array.from(arguments));\n }\n \n async checkSpendProof(txHash, message, signature) {\n return this._invokeWorker(\"checkSpendProof\", Array.from(arguments));\n }\n \n async getReserveProofWallet(message) {\n return this._invokeWorker(\"getReserveProofWallet\", Array.from(arguments));\n }\n \n async getReserveProofAccount(accountIdx, amount, message) {\n return this._invokeWorker(\"getReserveProofAccount\", Array.from(arguments));\n }\n\n async checkReserveProof(address, message, signature) {\n return new MoneroCheckReserve(await this._invokeWorker(\"checkReserveProof\", Array.from(arguments)));\n }\n \n async getTxNotes(txHashes) {\n return this._invokeWorker(\"getTxNotes\", Array.from(arguments));\n }\n \n async setTxNotes(txHashes, notes) {\n return this._invokeWorker(\"setTxNotes\", Array.from(arguments));\n }\n \n async getAddressBookEntries(entryIndices) {\n if (!entryIndices) entryIndices = [];\n let entries = [];\n for (let entryJson of await this._invokeWorker(\"getAddressBookEntries\", Array.from(arguments))) {\n entries.push(new MoneroAddressBookEntry(entryJson));\n }\n return entries;\n }\n \n async addAddressBookEntry(address, description) {\n return this._invokeWorker(\"addAddressBookEntry\", Array.from(arguments));\n }\n \n async editAddressBookEntry(index, setAddress, address, setDescription, description) {\n return this._invokeWorker(\"editAddressBookEntry\", Array.from(arguments));\n }\n \n async deleteAddressBookEntry(entryIdx) {\n return this._invokeWorker(\"deleteAddressBookEntry\", Array.from(arguments));\n }\n \n async tagAccounts(tag, accountIndices) {\n return this._invokeWorker(\"tagAccounts\", Array.from(arguments));\n }\n\n async untagAccounts(accountIndices) {\n return this._invokeWorker(\"untagAccounts\", Array.from(arguments));\n }\n \n async getAccountTags() {\n return this._invokeWorker(\"getAccountTags\", Array.from(arguments));\n }\n\n async setAccountTagLabel(tag, label) {\n return this._invokeWorker(\"setAccountTagLabel\", Array.from(arguments));\n }\n \n async createPaymentUri(config) {\n config = MoneroWallet._normalizeCreateTxsConfig(config);\n return this._invokeWorker(\"createPaymentUri\", [config.toJson()]);\n }\n \n async parsePaymentUri(uri) {\n return new MoneroTxConfig(await this._invokeWorker(\"parsePaymentUri\", Array.from(arguments)));\n }\n \n async getAttribute(key) {\n return this._invokeWorker(\"getAttribute\", Array.from(arguments));\n }\n \n async setAttribute(key, val) {\n return this._invokeWorker(\"setAttribute\", Array.from(arguments));\n }\n \n async startMining(numThreads, backgroundMining, ignoreBattery) {\n return this._invokeWorker(\"startMining\", Array.from(arguments));\n }\n \n async stopMining() {\n return this._invokeWorker(\"stopMining\", Array.from(arguments));\n }\n \n async isMultisigImportNeeded() {\n return this._invokeWorker(\"isMultisigImportNeeded\");\n }\n \n async isMultisig() {\n return this._invokeWorker(\"isMultisig\");\n }\n \n async getMultisigInfo() {\n return new MoneroMultisigInfo(await this._invokeWorker(\"getMultisigInfo\"));\n }\n \n async prepareMultisig() {\n return this._invokeWorker(\"prepareMultisig\");\n }\n \n async makeMultisig(multisigHexes, threshold, password) {\n return new MoneroMultisigInitResult(await this._invokeWorker(\"makeMultisig\", Array.from(arguments)));\n }\n \n async exchangeMultisigKeys(multisigHexes, password) {\n return new MoneroMultisigInitResult(await this._invokeWorker(\"exchangeMultisigKeys\", Array.from(arguments)));\n }\n \n async getMultisigHex() {\n return this._invokeWorker(\"getMultisigHex\");\n }\n \n async importMultisigHex(multisigHexes) {\n return this._invokeWorker(\"importMultisigHex\", Array.from(arguments));\n }\n \n async signMultisigTxHex(multisigTxHex) {\n return new MoneroMultisigSignResult(await this._invokeWorker(\"signMultisigTxHex\", Array.from(arguments)));\n }\n \n async submitMultisigTxHex(signedMultisigTxHex) {\n return this._invokeWorker(\"submitMultisigTxHex\", Array.from(arguments));\n }\n \n async getData() {\n return this._invokeWorker(\"getData\");\n }\n \n async moveTo(path, password) {\n throw new Error(\"MoneroWalletWasmProxy.moveTo() not implemented\");\n }\n \n // TODO: factor this duplicate code with MoneroWalletWasm save(), common util\n async save() {\n assert(!await this.isClosed(), \"Wallet is closed\");\n \n // path must be set\n let path = await this.getPath();\n if (!path) throw new MoneroError(\"Cannot save wallet because path is not set\");\n \n // write address file\n this._fs.writeFileSync(path + \".address.txt\", await this.getPrimaryAddress());\n \n // write keys and cache data\n let data = await this.getData();\n this._fs.writeFileSync(path + \".keys\", data[0], \"binary\");\n this._fs.writeFileSync(path, data[1], \"binary\");\n }\n \n async close(save) {\n if (save) await this.save();\n while (this._wrappedListeners.length) await this.removeListener(this._wrappedListeners[0].getListener());\n await this._invokeWorker(\"close\");\n delete LibraryUtils.WORKER_OBJECTS[this._walletId];\n }\n \n async isClosed() {\n return this._invokeWorker(\"isClosed\");\n }\n \n // --------------------------- PRIVATE HELPERS ------------------------------\n \n async _invokeWorker(fnName, args) {\n return LibraryUtils.invokeWorker(this._walletId, fnName, args);\n }\n}\n\n/**\n * Internal listener to bridge notifications to external listeners.\n * \n * @private\n */\nclass WalletWorkerListener {\n \n constructor(listener) {\n this._id = GenUtils.getUUID();\n this._listener = listener;\n }\n \n getId() {\n return this._id;\n }\n \n getListener() {\n return this._listener;\n }\n \n onSyncProgress(height, startHeight, endHeight, percentDone, message) {\n this._listener.onSyncProgress(height, startHeight, endHeight, percentDone, message);\n }\n\n onNewBlock(height) {\n this._listener.onNewBlock(height);\n }\n \n onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) {\n this._listener.onBalancesChanged(BigInteger.parse(newBalanceStr), BigInteger.parse(newUnlockedBalanceStr));\n }\n\n onOutputReceived(blockJson) {\n let block = new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET);\n this._listener.onOutputReceived(block.getTxs()[0].getOutputs()[0]);\n }\n \n onOutputSpent(blockJson) {\n let block = new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET);\n this._listener.onOutputSpent(block.getTxs()[0].getInputs()[0]);\n }\n}\n\nmodule.exports = MoneroWalletWasm;","module.exports = ws;","const assert = require(\"assert\");\nconst GenUtils = require(\"./GenUtils\");\nconst LibraryUtils = require(\"./LibraryUtils\");\nconst MoneroBan = require(\"../daemon/model/MoneroBan\");\nconst MoneroBlock = require(\"../daemon/model/MoneroBlock\");\nconst MoneroDaemonRpc = require(\"../daemon/MoneroDaemonRpc\");\nconst MoneroError = require(\"./MoneroError\");\nconst MoneroKeyImage = require(\"../daemon/model/MoneroKeyImage\");\nconst MoneroRpcConnection = require(\"./MoneroRpcConnection\");\nconst MoneroTxConfig = require(\"../wallet/model/MoneroTxConfig\");\nconst MoneroTxSet = require(\"../wallet/model/MoneroTxSet\");\nconst MoneroUtils = require(\"./MoneroUtils\");\nconst MoneroWalletListener = require(\"../wallet/model/MoneroWalletListener\");\nconst MoneroWalletWasm = require(\"../wallet/MoneroWalletWasm\");\n\n/**\n * Web worker to manage a daemon and wasm wallet off the main thread with messages.\n * \n * Required message format: e.data[0] = object id, e.data[1] = function name, e.data[2+] = function args\n *\n * This file must be browserified and placed in the web app root.\n * \n * @private\n */\nonmessage = async function(e) {\n \n // initialize one time\n await self.initOneTime();\n \n // validate params\n let objectId = e.data[0];\n let fnName = e.data[1];\n assert(objectId, \"Must provide object id to apply function to\");\n assert(fnName.length >= 2, \"Must provide a function name with length >= 2\");\n if (!self[fnName]) throw new Error(\"Method '\" + fnName + \"' is not registered with worker\");\n e.data.splice(1, 1); // remove function name\n \n // execute worker function and post result to callback\n let callbackFn = \"on\" + fnName.charAt(0).toUpperCase() + fnName.substring(1);\n try {\n postMessage([objectId, callbackFn, {result: await self[fnName].apply(null, e.data)}]);\n } catch (e) {\n postMessage([objectId, callbackFn, {error: e.message}]);\n }\n}\n\nself.initOneTime = async function() {\n if (!self.isInitialized) {\n self.WORKER_OBJECTS = {};\n self.isInitialized = true;\n }\n}\n\n// --------------------------- STATIC UTILITIES -------------------------------\n\nself.getWasmMemoryUsed = async function(objectId) {\t// TODO: object id not needed for static utilites, using throwaway uuid\n return LibraryUtils.getWasmModule() && LibraryUtils.getWasmModule().HEAP8 ? LibraryUtils.getWasmModule().HEAP8.length : undefined;\n}\n\n// ---------------------------- DAEMON METHODS --------------------------------\n\nself.connectDaemonRpc = async function(daemonId, config) {\n self.WORKER_OBJECTS[daemonId] = new MoneroDaemonRpc(config);\n}\n\nself.daemonGetRpcConnection = async function(daemonId) {\n let connection = await self.WORKER_OBJECTS[daemonId].getRpcConnection();\n return connection ? connection.getConfig() : undefined;\n}\n\nself.daemonIsConnected = async function(daemonId) {\n return self.WORKER_OBJECTS[daemonId].isConnected();\n}\n\nself.daemonGetVersion = async function(daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getVersion()).toJson();\n}\n\nself.daemonIsTrusted = async function(daemonId) {\n return self.WORKER_OBJECTS[daemonId].isTrusted();\n}\n\nself.daemonGetHeight = async function(daemonId) {\n return self.WORKER_OBJECTS[daemonId].getHeight();\n}\n\nself.daemonGetBlockHash = async function(daemonId, height) {\n return self.WORKER_OBJECTS[daemonId].getBlockHash(height);\n}\n\nself.daemonGetBlockTemplate = async function(daemonId, walletAddress, reserveSize) {\n return (await self.WORKER_OBJECTS[daemonId].getBlockTemplate(walletAddress, reserveSize)).toJson();\n}\n\nself.daemonGetLastBlockHeader = async function(daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getLastBlockHeader()).toJson();\n}\n\nself.daemonGetBlockHeaderByHash = async function(daemonId, hash) {\n return (await self.WORKER_OBJECTS[daemonId].getBlockHeaderByHash(hash)).toJson();\n}\n\nself.daemonGetBlockHeaderByHeight = async function(daemonId, height) {\n return (await self.WORKER_OBJECTS[daemonId].getBlockHeaderByHeight(height)).toJson();\n}\n\nself.daemonGetBlockHeadersByRange = async function(daemonId, startHeight, endHeight) {\n let blockHeadersJson = [];\n for (let blockHeader of await self.WORKER_OBJECTS[daemonId].getBlockHeadersByRange(startHeight, endHeight)) blockHeadersJson.push(blockHeader.toJson());\n return blockHeadersJson;\n}\n\nself.daemonGetBlockByHash = async function(daemonId, blockHash) {\n return (await self.WORKER_OBJECTS[daemonId].getBlockByHash(blockHash)).toJson();\n}\n\nself.daemonGetBlocksByHash = async function(daemonId, blockHashes, startHeight, prune) {\n let blocksJson = [];\n for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByHash(blockHashes, startHeight, prune)) blocksJson.push(block.toJson());\n return blocksJson;\n}\n\nself.daemonGetBlockByHeight = async function(daemonId, height) {\n return (await self.WORKER_OBJECTS[daemonId].getBlockByHeight(height)).toJson();\n}\n\nself.daemonGetBlocksByHeight = async function(daemonId, heights) {\n let blocksJson = [];\n for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByHeight(heights)) blocksJson.push(block.toJson());\n return blocksJson;\n}\n\nself.daemonGetBlocksByRange = async function(daemonId, startHeight, endHeight) {\n let blocksJson = [];\n for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByRange(startHeight, endHeight)) blocksJson.push(block.toJson());\n return blocksJson;\n}\n\nself.daemonGetBlocksByRangeChunked = async function(daemonId, startHeight, endHeight, maxChunkSize) {\n let blocksJson = [];\n for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize)) blocksJson.push(block.toJson());\n return blocksJson;\n}\n\nself.daemonGetBlockHashes = async function(daemonId, blockHashes, startHeight) {\n throw new Error(\"worker.getBlockHashes not implemented\");\n}\n\n// TODO: factor common code with self.getTxs()\nself.daemonGetTxs = async function(daemonId, txHashes, prune) {\n \n // get txs\n let txs = await self.WORKER_OBJECTS[daemonId].getTxs(txHashes, prune);\n \n // collect unique blocks to preserve model relationships as trees (based on monero_wasm_bridge.cpp::get_txs)\n let blocks = [];\n let unconfirmedBlock = undefined\n let seenBlocks = new Set();\n for (let tx of txs) {\n if (!tx.getBlock()) {\n if (!unconfirmedBlock) unconfirmedBlock = new MoneroBlock().setTxs([]);\n tx.setBlock(unconfirmedBlock);\n unconfirmedBlock.getTxs().push(tx);\n }\n if (!seenBlocks.has(tx.getBlock())) {\n seenBlocks.add(tx.getBlock());\n blocks.push(tx.getBlock());\n }\n }\n \n // serialize blocks to json\n for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson();\n return blocks;\n}\n\nself.daemonGetTxHexes = async function(daemonId, txHashes, prune) {\n return self.WORKER_OBJECTS[daemonId].getTxHexes(txHashes, prune);\n}\n\nself.daemonGetMinerTxSum = async function(daemonId, height, numBlocks) {\n return (await self.WORKER_OBJECTS[daemonId].getMinerTxSum(height, numBlocks)).toJson();\n}\n\nself.daemonGetFeeEstimate = async function(daemonId, graceBlocks) {\n return (await self.WORKER_OBJECTS[daemonId].getFeeEstimate(graceBlocks)).toString();\n}\n\nself.daemonSubmitTxHex = async function(daemonId, txHex, doNotRelay) {\n return (await self.WORKER_OBJECTS[daemonId].submitTxHex(txHex, doNotRelay)).toJson();\n}\n\nself.daemonRelayTxsByHash = async function(daemonId, txHashes) {\n return self.WORKER_OBJECTS[daemonId].relayTxsByHash(txHashes);\n}\n\nself.daemonGetTxPool = async function(daemonId) {\n let txs = await self.WORKER_OBJECTS[daemonId].getTxPool();\n let block = new MoneroBlock().setTxs(txs);\n for (let tx of txs) tx.setBlock(block)\n return block.toJson();\n}\n\nself.daemonGetTxPoolHashes = async function(daemonId) {\n return self.WORKER_OBJECTS[daemonId].getTxPoolHashes();\n}\n\n//async getTxPoolBacklog() {\n// throw new MoneroError(\"Not implemented\");\n//}\n\nself.daemonGetTxPoolStats = async function(daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getTxPoolStats()).toJson();\n}\n\nself.daemonFlushTxPool = async function(daemonId, hashes) {\n return self.WORKER_OBJECTS[daemonId].flushTxPool(hashes);\n}\n\nself.daemonGetKeyImageSpentStatuses = async function(daemonId, keyImages) {\n return self.WORKER_OBJECTS[daemonId].getKeyImageSpentStatuses(keyImages);\n}\n\n//\n//async getOutputs(outputs) {\n// throw new MoneroError(\"Not implemented\");\n//}\n\nself.daemonGetOutputHistogram = async function(daemonId, amounts, minCount, maxCount, isUnlocked, recentCutoff) {\n let entriesJson = [];\n for (let entry of await self.WORKER_OBJECTS[daemonId].getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff)) {\n entriesJson.push(entry.toJson());\n }\n return entriesJson;\n}\n\n//\n//async getOutputDistribution(amounts, cumulative, startHeight, endHeight) {\n// throw new MoneroError(\"Not implemented\");\n//}\n\nself.daemonGetInfo = async function(daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getInfo()).toJson();\n}\n\nself.daemonGetSyncInfo = async function(daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getSyncInfo()).toJson();\n}\n\nself.daemonGetHardForkInfo = async function(daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getHardForkInfo()).toJson();\n}\n\nself.daemonGetAltChains = async function(daemonId) {\n let altChainsJson = [];\n for (let altChain of await self.WORKER_OBJECTS[daemonId].getAltChains()) altChainsJson.push(altChain.toJson());\n return altChainsJson;\n}\n\nself.daemonGetAltBlockHashes = async function(daemonId) {\n return self.WORKER_OBJECTS[daemonId].getAltBlockHashes();\n}\n\nself.daemonGetDownloadLimit = async function(daemonId) {\n return self.WORKER_OBJECTS[daemonId].getDownloadLimit();\n}\n\nself.daemonSetDownloadLimit = async function(daemonId, limit) {\n return self.WORKER_OBJECTS[daemonId].setDownloadLimit(limit);\n}\n\nself.daemonResetDownloadLimit = async function(daemonId) {\n return self.WORKER_OBJECTS[daemonId].resetDownloadLimit();\n}\n\nself.daemonGetUploadLimit = async function(daemonId) {\n return self.WORKER_OBJECTS[daemonId].getUploadLimit();\n}\n\nself.daemonSetUploadLimit = async function(daemonId, limit) {\n return self.WORKER_OBJECTS[daemonId].setUploadLimit(limit);\n}\n\nself.daemonResetUploadLimit = async function(daemonId) {\n return self.WORKER_OBJECTS[daemonId].resetUploadLimit();\n}\n\nself.daemonGetKnownPeers = async function(daemonId) {\n let peersJson = [];\n for (let peer of await self.WORKER_OBJECTS[daemonId].getKnownPeers()) peersJson.push(peer.toJson());\n return peersJson;\n}\n\nself.daemonGetConnections = async function(daemonId) {\n let connectionsJson = [];\n for (let connection of await self.WORKER_OBJECTS[daemonId].getConnections()) connectionsJson.push(connection.toJson());\n return connectionsJson;\n}\n\nself.daemonSetOutgoingPeerLimit = async function(daemonId, limit) {\n return self.WORKER_OBJECTS[daemonId].setOutgoingPeerLimit(limit);\n}\n\nself.daemonSetIncomingPeerLimit = async function(daemonId, limit) {\n return self.WORKER_OBJECTS[daemonId].setIncomingPeerLimit(limit);\n}\n\nself.daemonGetPeerBans = async function(daemonId) {\n let bansJson = [];\n for (let ban of await self.WORKER_OBJECTS[daemonId].getPeerBans()) bansJson.push(ban.toJson());\n return bansJson;\n}\n\nself.daemonSetPeerBans = async function(daemonId, bansJson) {\n let bans = [];\n for (let banJson of bansJson) bans.push(new MoneroBan(banJson));\n return self.WORKER_OBJECTS[daemonId].setPeerBans(bans);\n}\n\nself.daemonStartMining = async function(daemonId, address, numThreads, isBackground, ignoreBattery) {\n return self.WORKER_OBJECTS[daemonId].startMining(address, numThreads, isBackground, ignoreBattery);\n}\n\nself.daemonStopMining = async function(daemonId) {\n return self.WORKER_OBJECTS[daemonId].stopMining();\n}\n\nself.daemonGetMiningStatus = async function(daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getMiningStatus()).toJson();\n}\n\n//\n//async submitBlocks(blockBlobs) {\n// throw new MoneroError(\"Not implemented\");\n//}\n//\n//async checkForUpdate() {\n// throw new MoneroError(\"Not implemented\");\n//}\n//\n//async downloadUpdate(path) {\n// throw new MoneroError(\"Not implemented\");\n//}\n\nself.daemonStop = async function(daemonId) {\n return self.WORKER_OBJECTS[daemonId].stop();\n}\n\nself.daemonGetNextBlockHeader = async function(daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getNextBlockHeader()).toJson();\n}\n\nself.daemonAddBlockListener = async function(daemonId, listenerId) {\n let listener = function(blockHeader) {\n self.postMessage([daemonId, \"onNewBlockHeader_\" + listenerId, blockHeader.toJson()]);\n }\n if (!self.daemonListeners) self.daemonListeners = {};\n self.daemonListeners[listenerId] = listener;\n await self.WORKER_OBJECTS[daemonId].addBlockListener(listener);\n}\n\nself.daemonRemoveBlockListener = async function(daemonId, listenerId) {\n if (!self.daemonListeners[listenerId]) throw new MoneroError(\"No daemon worker listener registered with id: \" + listenerId);\n await self.WORKER_OBJECTS[daemonId].removeBlockListener(self.daemonListeners[listenerId]);\n delete self.daemonListeners[listenerId];\n}\n\n//------------------------------ WALLET METHODS -------------------------------\n\nself.openWalletData = async function(walletId, path, password, networkType, keysData, cacheData, daemonUriOrConfig) {\n let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined;\n self.WORKER_OBJECTS[walletId] = await MoneroWalletWasm.openWallet({path: \"\", password: password, networkType: networkType, keysData: keysData, cacheData: cacheData, server: daemonConnection, proxyToWorker: false});\n self.WORKER_OBJECTS[walletId]._setBrowserMainPath(path);\n}\n\nself._createWalletRandom = async function(walletId, path, password, networkType, daemonUriOrConfig, language) {\n let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined;\n self.WORKER_OBJECTS[walletId] = await MoneroWalletWasm._createWalletRandom(\"\", password, networkType, daemonConnection, language, false);\n self.WORKER_OBJECTS[walletId]._setBrowserMainPath(path);\n}\n\nself._createWalletFromMnemonic = async function(walletId, path, password, networkType, mnemonic, daemonUriOrConfig, restoreHeight, seedOffset) {\n let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined;\n self.WORKER_OBJECTS[walletId] = await MoneroWalletWasm._createWalletFromMnemonic(\"\", password, networkType, mnemonic, daemonConnection, restoreHeight, seedOffset, false);\n self.WORKER_OBJECTS[walletId]._setBrowserMainPath(path);\n}\n\nself._createWalletFromKeys = async function(walletId, path, password, networkType, address, viewKey, spendKey, daemonUriOrConfig, restoreHeight, language) {\n let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined;\n self.WORKER_OBJECTS[walletId] = await MoneroWalletWasm._createWalletFromKeys(\"\", password, networkType, address, viewKey, spendKey, daemonConnection, restoreHeight, language, false);\n self.WORKER_OBJECTS[walletId]._setBrowserMainPath(path);\n}\n\nself.isViewOnly = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].isViewOnly();\n}\n\nself.getNetworkType = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getNetworkType();\n}\n\n//\n//async getVersion() {\n// throw new Error(\"Not implemented\");\n//}\n\nself.getMnemonic = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getMnemonic();\n}\n\nself.getMnemonicLanguage = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getMnemonicLanguage();\n}\n\nself.getMnemonicLanguages = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getMnemonicLanguages();\n}\n\nself.getPrivateSpendKey = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getPrivateSpendKey();\n}\n\nself.getPrivateViewKey = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getPrivateViewKey();\n}\n\nself.getPublicViewKey = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getPublicViewKey();\n}\n\nself.getPublicSpendKey = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getPublicSpendKey();\n}\n\nself.getAddress = async function(walletId, accountIdx, subaddressIdx) {\n return self.WORKER_OBJECTS[walletId].getAddress(accountIdx, subaddressIdx);\n}\n\nself.getAddressIndex = async function(walletId, address) {\n return (await self.WORKER_OBJECTS[walletId].getAddressIndex(address)).toJson();\n}\n\nself.getIntegratedAddress = async function(walletId, paymentId) {\n return (await self.WORKER_OBJECTS[walletId].getIntegratedAddress(paymentId)).toJson();\n}\n\nself.decodeIntegratedAddress = async function(walletId, integratedAddress) {\n return (await self.WORKER_OBJECTS[walletId].decodeIntegratedAddress(integratedAddress)).toJson();\n}\n\nself.setDaemonConnection = async function(walletId, config) {\n return self.WORKER_OBJECTS[walletId].setDaemonConnection(config ? new MoneroRpcConnection(config) : undefined);\n}\n\nself.getDaemonConnection = async function(walletId) {\n let connection = await self.WORKER_OBJECTS[walletId].getDaemonConnection();\n return connection ? connection.getConfig() : undefined;\n}\n\nself.isConnected = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].isConnected();\n}\n\nself.getSyncHeight = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getSyncHeight();\n}\n\nself.setSyncHeight = async function(walletId, syncHeight) {\n return self.WORKER_OBJECTS[walletId].setSyncHeight(syncHeight);\n}\n\nself.getDaemonHeight = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getDaemonHeight();\n}\n\nself.getDaemonMaxPeerHeight = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getDaemonMaxPeerHeight()\n}\n\nself.getHeightByDate = async function(walletId, year, month, day) {\n return self.WORKER_OBJECTS[walletId].getHeightByDate(year, month, day);\n}\n\nself.isDaemonSynced = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].isDaemonSynced();\n}\n\nself.getHeight = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getHeight();\n}\n\nself.addListener = async function(walletId, listenerId) {\n \n /**\n * Internal listener to bridge notifications to external listeners.\n * \n * TODO: MoneroWalletListener is not defined until scripts imported\n * \n * @private\n */\n class WalletWorkerHelperListener extends MoneroWalletListener {\n \n constructor(walletId, id, worker) {\n super();\n this.walletId = walletId;\n this.id = id;\n this.worker = worker;\n }\n \n getId() {\n return this.id;\n }\n \n onSyncProgress(height, startHeight, endHeight, percentDone, message) {\n this.worker.postMessage([this.walletId, \"onSyncProgress_\" + this.getId(), height, startHeight, endHeight, percentDone, message]);\n }\n\n onNewBlock(height) { \n this.worker.postMessage([this.walletId, \"onNewBlock_\" + this.getId(), height]);\n }\n \n onBalancesChanged(newBalance, newUnlockedBalance) {\n this.worker.postMessage([this.walletId, \"onBalancesChanged_\" + this.getId(), newBalance.toString(), newUnlockedBalance.toString()]);\n }\n\n onOutputReceived(output) {\n let block = output.getTx().getBlock();\n if (block === undefined) block = new MoneroBlock().setTxs([output.getTx()]);\n this.worker.postMessage([this.walletId, \"onOutputReceived_\" + this.getId(), block.toJson()]); // serialize from root block\n }\n \n onOutputSpent(output) {\n let block = output.getTx().getBlock();\n if (block === undefined) block = new MoneroBlock().setTxs([output.getTx()]);\n this.worker.postMessage([this.walletId, \"onOutputSpent_\" + this.getId(), block.toJson()]); // serialize from root block\n }\n }\n \n let listener = new WalletWorkerHelperListener(walletId, listenerId, self);\n if (!self.listeners) self.listeners = [];\n self.listeners.push(listener);\n await self.WORKER_OBJECTS[walletId].addListener(listener);\n}\n\nself.removeListener = async function(walletId, listenerId) {\n for (let i = 0; i < self.listeners.length; i++) {\n if (self.listeners[i].getId() !== listenerId) continue;\n await self.WORKER_OBJECTS[walletId].removeListener(self.listeners[i]);\n self.listeners.splice(i, 1);\n return;\n }\n throw new MoneroError(\"Listener is not registered with wallet\");\n}\n\nself.isSynced = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].isSynced();\n}\n\nself.sync = async function(walletId, startHeight) {\n return await self.WORKER_OBJECTS[walletId].sync(startHeight);\n}\n\nself.startSyncing = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].startSyncing();\n}\n\nself.stopSyncing = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].stopSyncing();\n}\n\nself.rescanSpent = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].rescanSpent();\n}\n\nself.rescanBlockchain = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].rescanBlockchain();\n}\n\nself.getBalance = async function(walletId, accountIdx, subaddressIdx) {\n return (await self.WORKER_OBJECTS[walletId].getBalance(accountIdx, subaddressIdx)).toString();\n}\n\nself.getUnlockedBalance = async function(walletId, accountIdx, subaddressIdx) {\n return (await self.WORKER_OBJECTS[walletId].getUnlockedBalance(accountIdx, subaddressIdx)).toString();\n}\n\nself.getAccounts = async function(walletId, includeSubaddresses, tag) {\n let accountJsons = [];\n for (let account of await self.WORKER_OBJECTS[walletId].getAccounts(includeSubaddresses, tag)) accountJsons.push(account.toJson());\n return accountJsons;\n}\n\nself.getAccount = async function(walletId, accountIdx, includeSubaddresses) {\n return (await self.WORKER_OBJECTS[walletId].getAccount(accountIdx, includeSubaddresses)).toJson();\n}\n\nself.createAccount = async function(walletId, label) {\n return (await self.WORKER_OBJECTS[walletId].createAccount(label)).toJson();\n}\n\nself.getSubaddresses = async function(walletId, accountIdx, subaddressIndices) {\n let subaddressJsons = [];\n for (let subaddress of await self.WORKER_OBJECTS[walletId].getSubaddresses(accountIdx, subaddressIndices)) subaddressJsons.push(subaddress.toJson());\n return subaddressJsons;\n}\n\nself.createSubaddress = async function(walletId, accountIdx, label) {\n return (await self.WORKER_OBJECTS[walletId].createSubaddress(accountIdx, label)).toJson();\n}\n\n// TODO: easier or more efficient way than serializing from root blocks?\nself.getTxs = async function(walletId, blockJsonQuery) {\n \n // deserialize query which is json string rooted at block\n let query = new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0];\n \n // get txs\n let txs = await self.WORKER_OBJECTS[walletId].getTxs(query);\n \n // collect unique blocks to preserve model relationships as trees (based on monero_wasm_bridge.cpp::get_txs)\n let seenBlocks = new Set();\n let unconfirmedBlock = undefined;\n let blocks = [];\n for (let tx of txs) {\n if (!tx.getBlock()) {\n if (!unconfirmedBlock) unconfirmedBlock = new MoneroBlock().setTxs([]);\n tx.setBlock(unconfirmedBlock);\n unconfirmedBlock.getTxs().push(tx);\n }\n if (!seenBlocks.has(tx.getBlock())) {\n seenBlocks.add(tx.getBlock());\n blocks.push(tx.getBlock());\n }\n }\n \n // serialize blocks to json\n for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson();\n return blocks;\n}\n\nself.getTransfers = async function(walletId, blockJsonQuery) {\n \n // deserialize query which is json string rooted at block\n let query = new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0].getTransferQuery();\n \n // get transfers\n let transfers = await self.WORKER_OBJECTS[walletId].getTransfers(query);\n \n // collect unique blocks to preserve model relationships as tree\n let unconfirmedBlock = undefined;\n let blocks = [];\n let seenBlocks = new Set();\n for (let transfer of transfers) {\n let tx = transfer.getTx();\n if (!tx.getBlock()) {\n if (!unconfirmedBlock) unconfirmedBlock = new MoneroBlock().setTxs([]);\n tx.setBlock(unconfirmedBlock);\n unconfirmedBlock.getTxs().push(tx);\n }\n if (!seenBlocks.has(tx.getBlock())) {\n seenBlocks.add(tx.getBlock());\n blocks.push(tx.getBlock());\n }\n }\n \n // serialize blocks to json\n for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson();\n return blocks;\n}\n\nself.getOutputs = async function(walletId, blockJsonQuery) {\n\n // deserialize query which is json string rooted at block\n let query = new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0].getOutputQuery();\n \n // get outputs\n let outputs = await self.WORKER_OBJECTS[walletId].getOutputs(query);\n \n // collect unique blocks to preserve model relationships as tree\n let unconfirmedBlock = undefined;\n let blocks = [];\n let seenBlocks = new Set();\n for (let output of outputs) {\n let tx = output.getTx();\n if (!tx.getBlock()) {\n if (!unconfirmedBlock) unconfirmedBlock = new MoneroBlock().setTxs([]);\n tx.setBlock(unconfirmedBlock);\n unconfirmedBlock.getTxs().push(tx);\n }\n if (!seenBlocks.has(tx.getBlock())) {\n seenBlocks.add(tx.getBlock());\n blocks.push(tx.getBlock());\n }\n }\n \n // serialize blocks to json\n for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson();\n return blocks;\n}\n\nself.getOutputsHex = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getOutputsHex();\n}\n\nself.importOutputsHex = async function(walletId, outputsHex) {\n return self.WORKER_OBJECTS[walletId].importOutputsHex(outputsHex);\n}\n\nself.getKeyImages = async function(walletId) {\n let keyImagesJson = [];\n for (let keyImage of await self.WORKER_OBJECTS[walletId].getKeyImages()) keyImagesJson.push(keyImage.toJson());\n return keyImagesJson;\n}\n\nself.importKeyImages = async function(walletId, keyImagesJson) {\n let keyImages = [];\n for (let keyImageJson of keyImagesJson) keyImages.push(new MoneroKeyImage(keyImageJson));\n return (await self.WORKER_OBJECTS[walletId].importKeyImages(keyImages)).toJson();\n}\n\n//async getNewKeyImagesFromLastImport() {\n// throw new MoneroError(\"Not implemented\");\n//}\n\nself.createTxs = async function(walletId, config) {\n if (typeof config === \"object\") config = new MoneroTxConfig(config);\n let txs = await self.WORKER_OBJECTS[walletId].createTxs(config);\n return txs[0].getTxSet().toJson();\n}\n\nself.sweepOutput = async function(walletId, config) {\n if (typeof config === \"object\") config = new MoneroTxConfig(config);\n let tx = await self.WORKER_OBJECTS[walletId].sweepOutput(config);\n return tx.getTxSet().toJson();\n}\n\nself.sweepUnlocked = async function(walletId, config) {\n if (typeof config === \"object\") config = new MoneroTxConfig(config);\n let txs = await self.WORKER_OBJECTS[walletId].sweepUnlocked(config);\n let txSets = [];\n for (let tx of txs) if (!GenUtils.arrayContains(txSets, tx.getTxSet())) txSets.push(tx.getTxSet());\n let txSetsJson = [];\n for (let txSet of txSets) txSetsJson.push(txSet.toJson());\n return txSetsJson;\n}\n\nself.sweepDust = async function(walletId, relay) {\n let txs = await self.WORKER_OBJECTS[walletId].sweepDust(relay);\n return txs[0].getTxSet().toJson();\n}\n\nself.relayTxs = async function(walletId, txMetadatas) {\n return self.WORKER_OBJECTS[walletId].relayTxs(txMetadatas);\n}\n\nself.parseTxSet = async function(walletId, txSetJson) {\n return (await self.WORKER_OBJECTS[walletId].parseTxSet(new MoneroTxSet(txSetJson))).toJson();\n}\n\nself.signTxs = async function(walletId, unsignedTxHex) {\n return self.WORKER_OBJECTS[walletId].signTxs(unsignedTxHex);\n}\n\nself.submitTxs = async function(walletId, signedTxHex) {\n return self.WORKER_OBJECTS[walletId].submitTxs(signedTxHex);\n}\n\nself.signMessage = async function(walletId, message) {\n return self.WORKER_OBJECTS[walletId].signMessage(message);\n}\n\nself.verifyMessage = async function(walletId, message, address, signature) {\n return self.WORKER_OBJECTS[walletId].verifyMessage(message, address, signature);\n}\n\nself.getTxKey = async function(walletId, txHash) {\n return self.WORKER_OBJECTS[walletId].getTxKey(txHash);\n}\n\nself.checkTxKey = async function(walletId, txHash, txKey, address) {\n return (await self.WORKER_OBJECTS[walletId].checkTxKey(txHash, txKey, address)).toJson();\n}\n\nself.getTxProof = async function(walletId, txHash, address, message) {\n return self.WORKER_OBJECTS[walletId].getTxProof(txHash, address, message);\n}\n\nself.checkTxProof = async function(walletId, txHash, address, message, signature) {\n return (self.WORKER_OBJECTS[walletId].checkTxProof(txHash, address, message, signature)).toJson();\n}\n\nself.getSpendProof = async function(walletId, txHash, message) {\n return self.WORKER_OBJECTS[walletId].getSpendProof(txHash, message);\n}\n\nself.checkSpendProof = async function(walletId, txHash, message, signature) {\n return self.WORKER_OBJECTS[walletId].checkSpendProof(txHash, message, signature);\n}\n\nself.getReserveProofWallet = async function(walletId, message) {\n return self.WORKER_OBJECTS[walletId].getReserveProofWallet(message);\n}\n\nself.getReserveProofAccount = async function(walletId, accountIdx, amount, message) {\n return self.WORKER_OBJECTS[walletId].getReserveProofAccount(accountIdx, amount, message);\n}\n\nself.checkReserveProof = async function(walletId, address, message, signature) {\n return (await self.WORKER_OBJECTS[walletId].checkReserveProof(address, message, signature)).toJson();\n}\n\nself.getTxNotes = async function(walletId, txHashes) {\n return self.WORKER_OBJECTS[walletId].getTxNotes(txHashes);\n}\n\nself.setTxNotes = async function(walletId, txHashes, txNotes) {\n return self.WORKER_OBJECTS[walletId].setTxNotes(txHashes, txNotes);\n}\n\nself.getAddressBookEntries = async function(walletId, entryIndices) {\n let entriesJson = [];\n for (let entry of await self.WORKER_OBJECTS[walletId].getAddressBookEntries(entryIndices)) entriesJson.push(entry.toJson());\n return entriesJson;\n}\n\nself.addAddressBookEntry = async function(walletId, address, description) {\n return self.WORKER_OBJECTS[walletId].addAddressBookEntry(address, description);\n}\n\nself.editAddressBookEntry = async function(walletId, index, setAddress, address, setDescription, description) {\n return self.WORKER_OBJECTS[walletId].editAddressBookEntry(index, setAddress, address, setDescription, description);\n}\n\nself.deleteAddressBookEntry = async function(walletId, index) {\n return self.WORKER_OBJECTS[walletId].deleteAddressBookEntry(index);\n}\n\nself.tagAccounts = async function(walletId, tag, accountIndices) {\n throw new Error(\"Not implemented\");\n}\n\nself.untagAccounts = async function(walletId, accountIndices) {\n throw new Error(\"Not implemented\");\n}\n\nself.getAccountTags = async function(walletId) {\n throw new Error(\"Not implemented\");\n}\n\nself.setAccountTagLabel = async function(walletId, tag, label) {\n throw new Error(\"Not implemented\");\n}\n\nself.createPaymentUri = async function(walletId, configJson) {\n return self.WORKER_OBJECTS[walletId].createPaymentUri(new MoneroTxConfig(configJson));\n}\n\nself.parsePaymentUri = async function(walletId, uri) {\n return (await self.WORKER_OBJECTS[walletId].parsePaymentUri(uri)).toJson();\n}\n\nself.getAttribute = async function(walletId, key) {\n return self.WORKER_OBJECTS[walletId].getAttribute(key);\n}\n\nself.setAttribute = async function(walletId, key, value) {\n return self.WORKER_OBJECTS[walletId].setAttribute(key, value);\n}\n\nself.startMining = async function(walletId, numThreads, backgroundMining, ignoreBattery) {\n return self.WORKER_OBJECTS[walletId].startMining(numThreads, backgroundMining, ignoreBattery);\n}\n\nself.stopMining = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].stopMining();\n}\n\nself.isMultisigImportNeeded = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].isMultisigImportNeeded();\n}\n\nself.isMultisig = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].isMultisig();\n}\n\nself.getMultisigInfo = async function(walletId) {\n return (await self.WORKER_OBJECTS[walletId].getMultisigInfo()).toJson();\n}\n\nself.prepareMultisig = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].prepareMultisig();\n}\n\nself.makeMultisig = async function(walletId, multisigHexes, threshold, password) {\n return (await self.WORKER_OBJECTS[walletId].makeMultisig(multisigHexes, threshold, password)).toJson();\n}\n\nself.exchangeMultisigKeys = async function(walletId, multisigHexes, password) {\n return (await self.WORKER_OBJECTS[walletId].exchangeMultisigKeys(multisigHexes, password)).toJson();\n}\n\nself.getMultisigHex = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getMultisigHex();\n}\n\nself.importMultisigHex = async function(walletId, multisigHexes) {\n return self.WORKER_OBJECTS[walletId].importMultisigHex(multisigHexes);\n}\n\nself.signMultisigTxHex = async function(walletId, multisigTxHex) {\n return (await self.WORKER_OBJECTS[walletId].signMultisigTxHex(multisigTxHex)).toJson();\n}\n\nself.submitMultisigTxHex = async function(walletId, signedMultisigTxHex) {\n return self.WORKER_OBJECTS[walletId].submitMultisigTxHex(signedMultisigTxHex);\n}\n\nself.getData = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].getData();\n}\n\nself.isClosed = async function(walletId) {\n return self.WORKER_OBJECTS[walletId].isClosed();\n}\n\nself.close = async function(walletId, save) {\n return self.WORKER_OBJECTS[walletId].close(save); // TODO: remove listeners and delete wallet from WORKER_OBJECTS\n}","/*\nobject-assign\n(c) Sindre Sorhus\n@license MIT\n*/\n\n'use strict';\n/* eslint-disable no-unused-vars */\nvar getOwnPropertySymbols = Object.getOwnPropertySymbols;\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\nvar propIsEnumerable = Object.prototype.propertyIsEnumerable;\n\nfunction toObject(val) {\n\tif (val === null || val === undefined) {\n\t\tthrow new TypeError('Object.assign cannot be called with null or undefined');\n\t}\n\n\treturn Object(val);\n}\n\nfunction shouldUseNative() {\n\ttry {\n\t\tif (!Object.assign) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Detect buggy property enumeration order in older V8 versions.\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=4118\n\t\tvar test1 = new String('abc'); // eslint-disable-line no-new-wrappers\n\t\ttest1[5] = 'de';\n\t\tif (Object.getOwnPropertyNames(test1)[0] === '5') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test2 = {};\n\t\tfor (var i = 0; i < 10; i++) {\n\t\t\ttest2['_' + String.fromCharCode(i)] = i;\n\t\t}\n\t\tvar order2 = Object.getOwnPropertyNames(test2).map(function (n) {\n\t\t\treturn test2[n];\n\t\t});\n\t\tif (order2.join('') !== '0123456789') {\n\t\t\treturn false;\n\t\t}\n\n\t\t// https://bugs.chromium.org/p/v8/issues/detail?id=3056\n\t\tvar test3 = {};\n\t\t'abcdefghijklmnopqrst'.split('').forEach(function (letter) {\n\t\t\ttest3[letter] = letter;\n\t\t});\n\t\tif (Object.keys(Object.assign({}, test3)).join('') !==\n\t\t\t\t'abcdefghijklmnopqrst') {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t} catch (err) {\n\t\t// We don't expect any of the above to throw, but better to be safe.\n\t\treturn false;\n\t}\n}\n\nmodule.exports = shouldUseNative() ? Object.assign : function (target, source) {\n\tvar from;\n\tvar to = toObject(target);\n\tvar symbols;\n\n\tfor (var s = 1; s < arguments.length; s++) {\n\t\tfrom = Object(arguments[s]);\n\n\t\tfor (var key in from) {\n\t\t\tif (hasOwnProperty.call(from, key)) {\n\t\t\t\tto[key] = from[key];\n\t\t\t}\n\t\t}\n\n\t\tif (getOwnPropertySymbols) {\n\t\t\tsymbols = getOwnPropertySymbols(from);\n\t\t\tfor (var i = 0; i < symbols.length; i++) {\n\t\t\t\tif (propIsEnumerable.call(from, symbols[i])) {\n\t\t\t\t\tto[symbols[i]] = from[symbols[i]];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn to;\n};\n","module.exports = function isBuffer(arg) {\n return arg && typeof arg === 'object'\n && typeof arg.copy === 'function'\n && typeof arg.fill === 'function'\n && typeof arg.readUInt8 === 'function';\n}","(function (global, undefined) {\n \"use strict\";\n\n if (global.setImmediate) {\n return;\n }\n\n var nextHandle = 1; // Spec says greater than zero\n var tasksByHandle = {};\n var currentlyRunningATask = false;\n var doc = global.document;\n var registerImmediate;\n\n function setImmediate(callback) {\n // Callback can either be a function or a string\n if (typeof callback !== \"function\") {\n callback = new Function(\"\" + callback);\n }\n // Copy function arguments\n var args = new Array(arguments.length - 1);\n for (var i = 0; i < args.length; i++) {\n args[i] = arguments[i + 1];\n }\n // Store and register the task\n var task = { callback: callback, args: args };\n tasksByHandle[nextHandle] = task;\n registerImmediate(nextHandle);\n return nextHandle++;\n }\n\n function clearImmediate(handle) {\n delete tasksByHandle[handle];\n }\n\n function run(task) {\n var callback = task.callback;\n var args = task.args;\n switch (args.length) {\n case 0:\n callback();\n break;\n case 1:\n callback(args[0]);\n break;\n case 2:\n callback(args[0], args[1]);\n break;\n case 3:\n callback(args[0], args[1], args[2]);\n break;\n default:\n callback.apply(undefined, args);\n break;\n }\n }\n\n function runIfPresent(handle) {\n // From the spec: \"Wait until any invocations of this algorithm started before this one have completed.\"\n // So if we're currently running a task, we'll need to delay this invocation.\n if (currentlyRunningATask) {\n // Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a\n // \"too much recursion\" error.\n setTimeout(runIfPresent, 0, handle);\n } else {\n var task = tasksByHandle[handle];\n if (task) {\n currentlyRunningATask = true;\n try {\n run(task);\n } finally {\n clearImmediate(handle);\n currentlyRunningATask = false;\n }\n }\n }\n }\n\n function installNextTickImplementation() {\n registerImmediate = function(handle) {\n process.nextTick(function () { runIfPresent(handle); });\n };\n }\n\n function canUsePostMessage() {\n // The test against `importScripts` prevents this implementation from being installed inside a web worker,\n // where `global.postMessage` means something completely different and can't be used for this purpose.\n if (global.postMessage && !global.importScripts) {\n var postMessageIsAsynchronous = true;\n var oldOnMessage = global.onmessage;\n global.onmessage = function() {\n postMessageIsAsynchronous = false;\n };\n global.postMessage(\"\", \"*\");\n global.onmessage = oldOnMessage;\n return postMessageIsAsynchronous;\n }\n }\n\n function installPostMessageImplementation() {\n // Installs an event handler on `global` for the `message` event: see\n // * https://developer.mozilla.org/en/DOM/window.postMessage\n // * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages\n\n var messagePrefix = \"setImmediate$\" + Math.random() + \"$\";\n var onGlobalMessage = function(event) {\n if (event.source === global &&\n typeof event.data === \"string\" &&\n event.data.indexOf(messagePrefix) === 0) {\n runIfPresent(+event.data.slice(messagePrefix.length));\n }\n };\n\n if (global.addEventListener) {\n global.addEventListener(\"message\", onGlobalMessage, false);\n } else {\n global.attachEvent(\"onmessage\", onGlobalMessage);\n }\n\n registerImmediate = function(handle) {\n global.postMessage(messagePrefix + handle, \"*\");\n };\n }\n\n function installMessageChannelImplementation() {\n var channel = new MessageChannel();\n channel.port1.onmessage = function(event) {\n var handle = event.data;\n runIfPresent(handle);\n };\n\n registerImmediate = function(handle) {\n channel.port2.postMessage(handle);\n };\n }\n\n function installReadyStateChangeImplementation() {\n var html = doc.documentElement;\n registerImmediate = function(handle) {\n // Create a \";\n else if (dependencyPath.endsWith(\".css\"))\n str += \"\";\n else if (dependencyPath.endsWith(\".png\") || dependencyPath.endsWith(\".img\"))\n str += \"\";\n else\n throw new Error(\"Unrecognized dependency path extension: \" + dependencyPath);\n }\n }\n str += \"\";\n if (content.div)\n str += $(\"
\").append(content.div.clone()).html(); // add cloned div as string\n str += \"\";\n return str;\n }\n /**\n * Opens the given div in a new window.\n *\n * @param content specifies optional window content\n * content.div is a pre-existing div to stringify and add to the body\n * content.title is the title of the new tab\n * content.dependencyPaths specifies paths to js, css, or img paths\n * content.internalCss is css to embed in the html document\n * content.metas are meta elements with keys/values to include\n * @param onLoad(err, window) is invoked with a reference to the window when available\n */\n static newWindow(content, onLoad) {\n let onLoadCalled = false;\n let w = window.open();\n if (!GenUtils.isInitialized(w) || !GenUtils.isInitialized(w.document)) {\n onLoadOnce(new Error(\"Could not get window reference\"));\n return;\n }\n w.opener = null;\n w.document.write(GenUtils.buildHtmlDocument(content));\n w.addEventListener('load', function () {\n onLoadOnce(null, w);\n });\n w.document.close();\n // prevents onLoad() from being called multiple times\n function onLoadOnce(err, window) {\n if (onLoadCalled)\n return;\n onLoadCalled = true;\n if (onLoad)\n onLoad(err, window);\n }\n }\n /**\n * Converts the given image to a base64 encoded data url.\n *\n * @param img is the image to convert\n * @param quality is a number between 0 and 1 specifying the image quality\n */\n static imgToDataUrl(img, quality) {\n let canvas = document.createElement('canvas');\n canvas.height = img.naturalHeight;\n canvas.width = img.naturalWidth;\n let context = canvas.getContext('2d');\n context.drawImage(img, 0, 0);\n return canvas.toDataURL(quality);\n }\n /**\n * Determines if the image at the given URL is accessible.\n *\n * @param url is the url to an image\n * @param timeout is the maximum time to wait\n * @param onDone(bool) when the image is determined to be accessible or not\n */\n static isImageAccessible(url, timeout, onDone) {\n // track return so it only executes once\n let returned = false;\n // attempt to load favicon\n let img = new Image();\n img.onload = onResponse;\n img.onerror = onResponse;\n img.src = url + \"?\" + (+new Date()); // trigger image load with cache buster\n // nest failure timeouts to give response a chance when browser is under load\n setTimeout(function () {\n setImmediate(function () {\n setImmediate(function () {\n setImmediate(function () {\n if (!returned) {\n returned = true;\n onDone(false);\n }\n });\n });\n });\n }, timeout);\n function onResponse(e) {\n if (returned)\n return;\n returned = true;\n if (typeof e === 'undefined' || e.type === \"error\")\n onDone(false);\n else\n onDone(true);\n }\n }\n /**\n * Determines if the given file is a zip file.\n *\n * @param file is a file\n * @return true if the given file is a zip file, false otherwise\n */\n static isZipFile(file) {\n return file.name.endsWith(\".zip\") || file.type === 'application/zip';\n }\n /**\n * Determines if the given file is a json file.\n *\n * @param file is a file\n * @return true if the given file is a json file, false otherwise\n */\n static isJsonFile(file) {\n return file.name.endsWith(\".json\") || file.type === 'application/json';\n }\n /**\n * Determines if the given file is a txt file.\n *\n * @param file is a file\n * @return true if the given file is a txt file, false otherwise\n */\n static isTxtFile(file) {\n return file.name.endsWith(\".txt\") || file.type === 'text/plain';\n }\n /**\n * Fetches the given list of images.\n *\n * Prerequisite: async.js.\n *\n * @param paths are the paths to the images to fetch\n * @param onDone(err, images) is called when done\n */\n static getImages(paths, onDone) {\n // listify paths\n if (!GenUtils.isArray(paths)) {\n GenUtils.assertTrue(GenUtils.isString(paths));\n paths = [paths];\n }\n // collect functions to fetch images\n let funcs = [];\n for (let i = 0; i < paths.length; i++) {\n funcs.push(loadFunc(paths[i]));\n }\n // fetch in parallel\n async.parallel(funcs, onDone);\n // callback static to fetch a single image\n function loadFunc(path) {\n return function (onDone) {\n let img = new Image();\n img.onload = function () { onDone(null, img); };\n img.onerror = function () { onDone(new Error(\"Cannot load image: \" + path)); };\n img.src = path;\n };\n }\n }\n /**\n * Returns a string indentation of the given length;\n *\n * @param length is the length of the indentation\n * @return {string} is an indentation string of the given length\n */\n static getIndent(length) {\n let str = \"\";\n for (let i = 0; i < length; i++)\n str += ' '; // two spaces\n return str;\n }\n static initPolyfills() {\n // Polyfill Object.assign()\n // Credit: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign\n if (typeof Object.assign != 'function') {\n // Must be writable: true, enumerable: false, configurable: true\n Object.defineProperty(Object, \"assign\", {\n value: function assign(target, varArgs) {\n 'use strict';\n if (target == null) { // TypeError if undefined or null\n throw new TypeError('Cannot convert undefined or null to object');\n }\n let to = Object(target);\n for (let index = 1; index < arguments.length; index++) {\n let nextSource = arguments[index];\n if (nextSource != null) { // Skip over if undefined or null\n for (let nextKey in nextSource) {\n // Avoid bugs when hasOwnProperty is shadowed\n if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {\n to[nextKey] = nextSource[nextKey];\n }\n }\n }\n }\n return to;\n },\n writable: true,\n configurable: true\n });\n }\n /**\n * Polyfill str.startsWith(searchString, position).\n *\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith#Polyfill\n */\n String.prototype.startsWith = function (searchString, position) {\n return this.substr(position || 0, searchString.length) === searchString;\n };\n /**\n * Polyfill str.endsWith(searchString, position).\n *\n * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith#Polyfill\n */\n String.prototype.endsWith = function (searchString, position) {\n if (!(position < this.length))\n position = this.length; // works better than >= because it compensates for NaN\n else\n position |= 0; // round position\n return this.substr(position - searchString.length, searchString.length) === searchString;\n };\n }\n /**\n * Generates a v4 UUID.\n *\n * Source: https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript\n */\n static getUUID() {\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {\n let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);\n return v.toString(16);\n });\n }\n /**\n * Indicates if the current environment is a browser.\n *\n * @return {boolean} true if the environment is a browser, false otherwise\n */\n static isBrowser() {\n let isWorker = typeof importScripts === 'function';\n let isBrowserMain = new Function(\"try {return this===window;}catch(e){return false;}\")();\n let isJsDom = isBrowserMain ? new Function(\"try {return window.navigator.userAgent.includes('jsdom');}catch(e){return false;}\")() : false;\n return isWorker || (isBrowserMain && !isJsDom);\n }\n /**\n * Indicates if the current environment is Deno\n *\n * @return {boolean} true if the environment is Deno, false otherwise\n */\n static isDeno() {\n return typeof Deno === \"object\" && Deno.hasOwnProperty(\"version\") && typeof Deno.version === \"object\" && Deno.version.hasOwnProperty(\"deno\") && typeof Deno.version.deno === \"string\";\n }\n /**\n * Indicates if the current environment is a firefox-based browser.\n *\n * @return {boolean} true if the environment is a firefox-based browser, false otherwise\n */\n static isFirefox() {\n return this.isBrowser() && navigator.userAgent.indexOf(\"Firefox\") > 0;\n }\n /**\n * Gets the IE version number.\n *\n * Credit: https://stackoverflow.com/questions/19999388/check-if-user-is-using-ie-with-jquery/21712356#21712356\n *\n * @return the IE version number or null if not IE\n */\n static getIEVersion() {\n let ua = window.navigator.userAgent;\n let msie = ua.indexOf('MSIE ');\n if (msie > 0) {\n // IE 10 or older => return version number\n return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);\n }\n let trident = ua.indexOf('Trident/');\n if (trident > 0) {\n // IE 11 => return version number\n let rv = ua.indexOf('rv:');\n return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);\n }\n let edge = ua.indexOf('Edge/');\n if (edge > 0) {\n // Edge (IE 12+) => return version number\n return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);\n }\n // other browser\n return null;\n }\n /**\n * Gets a parameter value.\n *\n * Credit: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript\n *\n * @param name is the name of the parameter to get the value of\n * @param url is a URL to get the parameter from, uses the window's current href if not given\n * @return the parameter's value\n */\n static getParameterByName(name, url) {\n if (!url)\n url = window.location.href;\n name = name.replace(/[\\[\\]]/g, \"\\\\$&\");\n let regex = new RegExp(\"[?&]\" + name + \"(=([^&#]*)|&|#|$)\"), results = regex.exec(url);\n if (!results)\n return null;\n if (!results[2])\n return '';\n return decodeURIComponent(results[2].replace(/\\+/g, \" \"));\n }\n /**\n * Gets a non-cryptographically secure random number within a given range.\n *\n * @param min is the minimum range of the int to generate, inclusive\n * @param max is the maximum range of the int to generate, inclusive\n *\n * Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random\n */\n static getRandomInt(min, max) {\n min = Math.ceil(min);\n max = Math.floor(max);\n return Math.floor(Math.random() * (max - min + 1)) + min;\n }\n /**\n * Gets random ints.\n *\n * @param min is the minimum range of the ints to generate, inclusive\n * @param max is the maximum range of the ints to generate, inclusive\n * @param count is the number of random ints to get\n */\n static getRandomInts(min, max, count) {\n GenUtils.assertTrue(typeof count === \"number\");\n let ints = [];\n for (let i = 0; i < count; i++)\n ints.push(GenUtils.getRandomInt(min, max));\n return ints;\n }\n /**\n * Gets a given number of unique random ints within a range.\n *\n * @param min is the minimum range of the ints to generate, inclusive\n * @param max is the maximum range of the ints to generate, inclusive\n * @param count is the number of unique random ints to get\n */\n static getUniqueRandomInts(min, max, count) {\n let ints = [];\n GenUtils.assertTrue(count >= 0);\n GenUtils.assertTrue(max - min + 1 >= count);\n while (ints.length < count) {\n let randomInt = GenUtils.getRandomInt(min, max);\n if (!ints.includes(randomInt))\n ints.push(randomInt);\n }\n return ints;\n }\n /**\n * Randomize array element order in-place using Durstenfeld shuffle algorithm.\n *\n * Credit: https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array\n */\n static shuffle(array) {\n for (var i = array.length - 1; i > 0; i--) {\n var j = Math.floor(Math.random() * (i + 1));\n var temp = array[i];\n array[i] = array[j];\n array[j] = temp;\n }\n }\n /**\n * Sorts an array by natural ordering.\n *\n * @param the array to sort\n */\n static sort(array) {\n array.sort((a, b) => a === b ? 0 : a > b ? 1 : -1);\n }\n /**\n * Sets the given value ensuring a previous value is not overwritten.\n *\n * TODO: remove for portability because function passing not supported in other languages, use reconcile only\n *\n * @param obj is the object to invoke the getter and setter on\n * @param getFn gets the current value\n * @param setFn sets the current value\n * @param val is the value to set iff it does not overwrite a previous value\n * @param [config] specifies reconciliation configuration\n * config.resolveDefined uses defined value if true or undefined, undefined if false\n * config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined\n * config.resolveMax uses max over min if true, min over max if false, must be equal if undefined\n * @param [errMsg] is the error message to throw if the values cannot be reconciled (optional)\n */\n static safeSet(obj, getFn, setFn, val, config, errMsg) {\n let curVal = getFn.call(obj);\n let reconciledVal = GenUtils.reconcile(curVal, val, config, errMsg);\n if (curVal !== reconciledVal)\n setFn.call(obj, reconciledVal);\n }\n /**\n * Reconciles two values.\n *\n * TODO: remove custom error message\n *\n * @param val1 is a value to reconcile\n * @param val2 is a value to reconcile\n * @param [config] specifies reconciliation configuration\n * config.resolveDefined uses defined value if true or undefined, undefined if false\n * config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined\n * config.resolveMax uses max over min if true, min over max if false, must be equal if undefined\n * @param [errMsg] is the error message to throw if the values cannot be reconciled (optional)\n * @return the reconciled value if reconcilable, throws error otherwise\n */\n static reconcile(val1, val2, config, errMsg) {\n // check for equality\n if (val1 === val2)\n return val1;\n // check for bigint equality\n let comparison; // save comparison for later if applicable\n if (typeof val1 === \"bigint\" && typeof val2 === \"bigint\") {\n if (val1 === val2)\n return val1;\n }\n // resolve one value defined\n if (val1 === undefined || val2 === undefined) {\n if (config && config.resolveDefined === false)\n return undefined; // use undefined\n else\n return val1 === undefined ? val2 : val1; // use defined value\n }\n // resolve different booleans\n if (config && config.resolveTrue !== undefined && typeof val1 === \"boolean\" && typeof val2 === \"boolean\") {\n assert.equal(typeof config.resolveTrue, \"boolean\");\n return config.resolveTrue;\n }\n // resolve different numbers\n if (config && config.resolveMax !== undefined) {\n assert.equal(typeof config.resolveMax, \"boolean\");\n // resolve js numbers\n if (typeof val1 === \"number\" && typeof val2 === \"number\") {\n return config.resolveMax ? Math.max(val1, val2) : Math.min(val1, val2);\n }\n // resolve bigints\n if (typeof val1 === \"bigint\" && typeof val2 === \"bigint\") {\n return config.resolveMax ? (comparison < 0 ? val2 : val1) : (comparison < 0 ? val1 : val2);\n }\n }\n // assert deep equality\n assert.deepEqual(val1, val2, errMsg ? errMsg : \"Cannot reconcile values \" + val1 + \" and \" + val2 + \" with config: \" + JSON.stringify(config));\n return val1;\n }\n /**\n * Returns a human-friendly key value line.\n *\n * @param key is the key\n * @param value is the value\n * @param indent indents the line\n * @param newline specifies if the string should be terminated with a newline or not\n * @param ignoreUndefined specifies if undefined values should return an empty string\n * @return {string} is the human-friendly key value line\n */\n static kvLine(key, value, indent = 0, newline = true, ignoreUndefined = true) {\n if (value === undefined && ignoreUndefined)\n return \"\";\n return GenUtils.getIndent(indent) + key + \": \" + value + (newline ? '\\n' : \"\");\n }\n /**\n * Replace big integers (16 or more consecutive digits) with strings in order\n * to preserve numeric precision.\n *\n * @param {string} str is the string to be modified\n * @return {string} the modified string with big numbers converted to strings\n */\n static stringifyBigInts(str) {\n return str.replace(/(\"[^\"]*\"\\s*:\\s*)(\\d{16,})/g, '$1\"$2\"');\n }\n /**\n * Print the current stack trace.\n *\n * @param {string} msg - optional message to print with the trace\n */\n static printStackTrace(msg) {\n try {\n throw new Error(msg);\n }\n catch (err) {\n console.error(err.stack);\n }\n }\n /**\n * Wait for the duration.\n *\n * @param {number} durationMs - the duration to wait for in milliseconds\n */\n static async waitFor(durationMs) {\n return new Promise(function (resolve) { setTimeout(resolve, durationMs); });\n }\n /**\n * Kill the given nodejs child process.\n *\n * @param {ChildProcess} process - the nodejs child process to kill\n * @param {number | NodeJS.Signals} [signal] - the kill signal, e.g. SIGTERM, SIGKILL, SIGINT (default)\n * @return {Promise} the exit code from killing the process\n */\n static async killProcess(process, signal) {\n return new Promise((resolve, reject) => {\n process.on(\"exit\", function (code, signal) { resolve(code); });\n process.on(\"error\", function (err) { reject(err); });\n try {\n if (!process.kill(signal === undefined ? \"SIGINT\" : signal))\n resolve(undefined); // resolve immediately if not running\n }\n catch (err) {\n reject(err);\n }\n });\n }\n /**\n * Normalize a URI.\n *\n * @param {string} uri - the URI to normalize\n * @return {string} the normalized URI\n */\n static normalizeUri(uri) {\n if (!uri)\n throw Error(\"Must provide URI to normalize\");\n uri = uri.replace(/\\/$/, \"\"); // strip trailing slash\n if (!new RegExp(\"^\\\\w+://.+\").test(uri))\n uri = \"http://\" + uri; // assume http if protocol not given\n return uri;\n }\n /**\n * Get the absolute value of the given bigint or number.\n *\n * @param {bigint | number} bi - the bigint or number to get the absolute value of\n * @return {bigint | number} the absolute value of the given bigint or number\n */\n static abs(bi) {\n return bi < 0 ? -bi : bi;\n }\n /**\n * Get an enum key name by value.\n *\n * @param {any} enumType is the enum type to get the key from\n * @param {any} enumValue is the enum value to get the key for\n * @return {string | undefined} the enum key name\n */\n static getEnumKeyByValue(enumType, enumValue) {\n for (let key in enumType) {\n if (enumType[key] === enumValue)\n return key;\n }\n return undefined;\n }\n /**\n * Resolve the given promise with a timeout.\n *\n * @param promise the promise to resolve within the timeout\n * @param timeoutMs the timeout in milliseconds to resolve the promise\n * @return the result of the promise unless error thrown\n */\n static async executeWithTimeout(promise, timeoutMs) {\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n reject('Execution timed out in ' + timeoutMs + ' milliseconds');\n }, timeoutMs);\n promise.then((result) => {\n clearTimeout(timeoutId);\n resolve(result);\n }, (error) => {\n clearTimeout(timeoutId);\n reject(error);\n });\n });\n }\n}\n","/**\n * Exception when interacting with a Monero wallet or daemon.\n */\nexport default class MoneroError extends Error {\n /**\n * Constructs the error.\n *\n * @param {string} message is a human-readable message of the error\n * @param {number} [code] is the error code (optional)\n */\n constructor(message, code) {\n super(message);\n this.code = code;\n }\n getCode() {\n return this.code;\n }\n toString() {\n if (this.message === undefined && this.getCode() === undefined)\n return super.message;\n let str = \"\";\n if (this.getCode() !== undefined)\n str += this.getCode() + \": \";\n str += this.message;\n return str;\n }\n}\n","import GenUtils from \"./GenUtils\";\nimport async from \"async\";\n/**\n * Simple thread pool using the async library.\n */\nexport default class ThreadPool {\n /**\n * Construct the thread pool.\n *\n * @param {number} [maxConcurrency] - maximum number of threads in the pool (default 1)\n */\n constructor(maxConcurrency) {\n if (maxConcurrency === undefined)\n maxConcurrency = 1;\n if (maxConcurrency < 1)\n throw new Error(\"Max concurrency must be greater than or equal to 1\");\n // manager concurrency with async queue\n //import async from \"async\";\n this.taskQueue = async.queue((asyncFn, callback) => {\n if (asyncFn.then)\n asyncFn.then(resp => { callback(resp); }).catch(err => { callback(undefined, err); });\n else\n asyncFn().then(resp => { callback(resp); }).catch(err => { callback(undefined, err); });\n }, maxConcurrency);\n // use drain listeners to support await all\n this.drainListeners = [];\n this.taskQueue.drain = () => {\n for (let listener of this.drainListeners)\n listener();\n };\n }\n /**\n * Submit an asynchronous function to run using the thread pool.\n *\n * @param {function} asyncFn - asynchronous function to run with the thread pool\n * @return {Promise} resolves when the function completes execution\n */\n async submit(asyncFn) {\n return new Promise((resolve, reject) => {\n this.taskQueue.push(asyncFn, (resp, err) => {\n if (err !== undefined)\n reject(err);\n else\n resolve(resp);\n });\n });\n }\n /**\n * Await all functions to complete.\n *\n * @return {Promise} resolves when all functions complete\n */\n async awaitAll() {\n if (this.taskQueue.length === 0)\n return;\n return new Promise((resolve) => {\n this.drainListeners.push(() => {\n GenUtils.remove(this.drainListeners, this);\n resolve();\n });\n });\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"./GenUtils\";\nimport MoneroError from \"./MoneroError\";\nimport ThreadPool from \"./ThreadPool\";\nimport path from \"path\";\n/**\n * Collection of helper utilities for the library.\n */\nclass LibraryUtils {\n /**\n * Log a message.\n *\n * @param {number} level - log level of the message\n * @param {string} msg - message to log\n */\n static log(level, msg) {\n assert(level === parseInt(level, 10) && level >= 0, \"Log level must be an integer >= 0\");\n if (LibraryUtils.LOG_LEVEL >= level)\n console.log(msg);\n }\n /**\n * Set the library's log level with 0 being least verbose.\n *\n * @param {number} level - the library's log level\n */\n static async setLogLevel(level) {\n assert(level === parseInt(level, 10) && level >= 0, \"Log level must be an integer >= 0\");\n LibraryUtils.LOG_LEVEL = level;\n if (LibraryUtils.WASM_MODULE)\n LibraryUtils.WASM_MODULE.set_log_level(level);\n if (LibraryUtils.WORKER)\n await LibraryUtils.invokeWorker(undefined, \"setLogLevel\", [level]);\n }\n /**\n * Get the library's log level.\n *\n * @return {number} the library's log level\n */\n static getLogLevel() {\n return LibraryUtils.LOG_LEVEL;\n }\n /**\n * Get the total memory used by WebAssembly.\n *\n * @return {Promise} the total memory used by WebAssembly\n */\n static async getWasmMemoryUsed() {\n let total = 0;\n if (LibraryUtils.WORKER)\n total += await LibraryUtils.invokeWorker(undefined, \"getWasmMemoryUsed\", []);\n if (LibraryUtils.getWasmModule() && LibraryUtils.getWasmModule().HEAP8)\n total += LibraryUtils.getWasmModule().HEAP8.length;\n return total;\n }\n /**\n * Get the WebAssembly module in the current context (nodejs, browser main thread or worker).\n */\n static getWasmModule() {\n return LibraryUtils.WASM_MODULE;\n }\n /**\n * Load the WebAssembly full module with caching.\n *\n * The full module is a superset of the keys module and overrides it.\n */\n static async loadWasmModule() {\n // use cache if suitable, full module supersedes keys module because it is superset\n if (LibraryUtils.WASM_MODULE && LibraryUtils.FULL_LOADED)\n return LibraryUtils.WASM_MODULE;\n // load module\n const module = await require(\"#monero-ts/monero.js\")();\n LibraryUtils.WASM_MODULE = module;\n delete LibraryUtils.WASM_MODULE.then;\n LibraryUtils.FULL_LOADED = true;\n LibraryUtils.initWasmModule(LibraryUtils.WASM_MODULE);\n return module;\n }\n /**\n * Register a function by id which informs if unauthorized requests (e.g.\n * self-signed certificates) should be rejected.\n *\n * @param {string} fnId - unique identifier for the function\n * @param {function} fn - function to inform if unauthorized requests should be rejected\n */\n static setRejectUnauthorizedFn(fnId, fn) {\n if (!LibraryUtils.REJECT_UNAUTHORIZED_FNS)\n LibraryUtils.REJECT_UNAUTHORIZED_FNS = [];\n if (fn === undefined)\n delete LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId];\n else\n LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId] = fn;\n }\n /**\n * Indicate if unauthorized requests should be rejected.\n *\n * @param {string} fnId - uniquely identifies the function\n */\n static isRejectUnauthorized(fnId) {\n if (!LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId])\n throw new Error(\"No function registered with id \" + fnId + \" to inform if unauthorized reqs should be rejected\");\n return LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId]();\n }\n /**\n * Set the path to load the worker. Defaults to \"/monero.worker.js\" in the browser\n * and \"./MoneroWebWorker.js\" in node.\n *\n * @param {string} workerDistPath - path to load the worker\n */\n static setWorkerDistPath(workerDistPath) {\n let path = LibraryUtils.prefixWindowsPath(workerDistPath ? workerDistPath : LibraryUtils.WORKER_DIST_PATH_DEFAULT);\n if (path !== LibraryUtils.WORKER_DIST_PATH)\n delete LibraryUtils.WORKER;\n LibraryUtils.WORKER_DIST_PATH = path;\n }\n /**\n * Set the worker loader closure to customize worker loading.\n * Takes precedence over default loading mechanisms.\n *\n * Could be as simple as `() => new Worker(new URL(\"monero-ts/dist/monero.worker.js\", import.meta.url));` for browsers.\n *\n * @param {function} loader - loader function which instantiates a worker\n */\n static setWorkerLoader(loader) {\n LibraryUtils.WORKER_LOADER = loader;\n }\n /**\n * Get a singleton instance of a worker to share.\n *\n * @return {Worker} a worker to share among wallet instances\n */\n static async getWorker() {\n // one time initialization\n if (!LibraryUtils.WORKER) {\n // try to load worker with user provided closure\n if (LibraryUtils.WORKER_LOADER) {\n LibraryUtils.WORKER = LibraryUtils.WORKER_LOADER();\n }\n else {\n // otherwise use standard loading mechanisms for browser and node\n if (GenUtils.isBrowser()) {\n LibraryUtils.WORKER = new Worker(LibraryUtils.WORKER_DIST_PATH);\n }\n else if (GenUtils.isDeno()) {\n LibraryUtils.WORKER = new Worker(LibraryUtils.WORKER_DIST_PATH, { type: \"module\" });\n }\n else {\n const Worker = require(\"web-worker\"); // import web worker if nodejs\n LibraryUtils.WORKER = new Worker(LibraryUtils.WORKER_DIST_PATH);\n }\n }\n LibraryUtils.WORKER_OBJECTS = {}; // store per object running in the worker\n // receive worker errors\n LibraryUtils.WORKER.onerror = function (err) {\n console.error(\"Error posting message to monero.worker.js; is it built and copied to the app's public or build directory?\");\n console.log(err);\n };\n // receive worker messages\n LibraryUtils.WORKER.onmessage = function (e) {\n // lookup object id, callback function, and this arg\n let thisArg = undefined;\n let callbackFn = LibraryUtils.WORKER_OBJECTS[e.data[0]].callbacks[e.data[1]]; // look up by object id then by function name\n if (callbackFn === undefined)\n throw new Error(\"No worker callback function defined for key '\" + e.data[1] + \"'\");\n if (callbackFn instanceof Array) { // this arg may be stored with callback function\n thisArg = callbackFn[1];\n callbackFn = callbackFn[0];\n }\n // invoke callback function with this arg and arguments\n callbackFn.apply(thisArg, e.data.slice(2));\n };\n }\n return LibraryUtils.WORKER;\n }\n static addWorkerCallback(objectId, callbackId, callbackArgs) {\n LibraryUtils.WORKER_OBJECTS[objectId].callbacks[callbackId] = callbackArgs;\n }\n static removeWorkerCallback(objectId, callbackId) {\n delete LibraryUtils.WORKER_OBJECTS[objectId].callbacks[callbackId];\n }\n static removeWorkerObject(objectId) {\n delete LibraryUtils.WORKER_OBJECTS[objectId];\n }\n /**\n * Terminate monero-ts's singleton worker.\n */\n static async terminateWorker() {\n if (LibraryUtils.WORKER) {\n LibraryUtils.WORKER.terminate();\n delete LibraryUtils.WORKER;\n LibraryUtils.WORKER = undefined;\n }\n }\n /**\n * Invoke a worker function and get the result with error handling.\n *\n * @param {string} objectId identifies the worker object to invoke (default random id)\n * @param {string} fnName is the name of the function to invoke\n * @param {any[]} [args] are function arguments to invoke with\n * @return {any} resolves with response payload from the worker or an error\n */\n static async invokeWorker(objectId, fnName, args) {\n assert(fnName.length >= 2);\n let worker = await LibraryUtils.getWorker();\n let randomObject = objectId === undefined;\n if (randomObject)\n objectId = GenUtils.getUUID();\n if (!LibraryUtils.WORKER_OBJECTS[objectId])\n LibraryUtils.WORKER_OBJECTS[objectId] = { callbacks: {} };\n let callbackId = GenUtils.getUUID();\n try {\n return await new Promise((resolve, reject) => {\n LibraryUtils.WORKER_OBJECTS[objectId].callbacks[callbackId] = (resp) => {\n delete LibraryUtils.WORKER_OBJECTS[objectId].callbacks[callbackId];\n if (randomObject)\n delete LibraryUtils.WORKER_OBJECTS[objectId];\n resp ? (resp.error ? reject(new Error(JSON.stringify(resp.error))) : resolve(resp.result)) : resolve(undefined);\n };\n worker.postMessage([objectId, fnName, callbackId].concat(args === undefined ? [] : GenUtils.listify(args)));\n });\n }\n catch (e) {\n throw LibraryUtils.deserializeError(JSON.parse(e.message));\n }\n }\n static serializeError(err) {\n const serializedErr = { name: err.name, message: err.message, code: err.code, stack: err.stack };\n if (err instanceof MoneroError)\n serializedErr.type = \"MoneroError\";\n return serializedErr;\n }\n static deserializeError(serializedErr) {\n const err = serializedErr.type === \"MoneroError\" ? new MoneroError(serializedErr.message, serializedErr.code) : new Error(serializedErr.message);\n err.name = serializedErr.name;\n err.stack = err.stack + \"\\nWorker error: \" + serializedErr.stack;\n return err;\n }\n static async queueTask(asyncFn) {\n return LibraryUtils.MUTEX.submit(asyncFn);\n }\n static async exists(fs, path) {\n try {\n await fs.access(path);\n return true;\n }\n catch (err) {\n return false;\n }\n }\n // ------------------------------ PRIVATE HELPERS ---------------------------\n static initWasmModule(wasmModule) {\n wasmModule.taskQueue = new ThreadPool(1);\n wasmModule.queueTask = async function (asyncFn) { return wasmModule.taskQueue.submit(asyncFn); };\n }\n static prefixWindowsPath(path) {\n if (/^[A-Z]:/.test(path) && path.indexOf(\"file://\") == -1)\n path = \"file://\" + path; // prepend e.g. C: paths with file://\n return path;\n }\n}\n// static variables\nLibraryUtils.LOG_LEVEL = 0;\nLibraryUtils.MUTEX = new ThreadPool(1);\nLibraryUtils.WORKER_DIST_PATH_DEFAULT = GenUtils.isBrowser() ? \"/monero.worker.js\" : function () {\n // get worker path in dist (assumes library is running from src or dist)\n let curPath = path.normalize(__dirname);\n const targetPath = path.join('monero-ts', 'dist');\n if (!curPath.includes(targetPath))\n curPath = path.join(curPath, \"../../../../dist/src/main/js/common\");\n curPath = LibraryUtils.prefixWindowsPath(path.join(curPath, \"./MoneroWebWorker.js\"));\n if (GenUtils.isDeno())\n curPath = path.join(\"file://\", curPath);\n return curPath;\n}();\nLibraryUtils.WORKER_DIST_PATH = LibraryUtils.WORKER_DIST_PATH_DEFAULT;\nLibraryUtils.WORKER_LOADER = undefined;\nexport default LibraryUtils;\n","'use strict';\n\nexport default function bind(fn, thisArg) {\n return function wrap() {\n return fn.apply(thisArg, arguments);\n };\n}\n","'use strict';\n\nimport bind from './helpers/bind.js';\n\n// utils is a library of generic helper functions non-specific to axios\n\nconst {toString} = Object.prototype;\nconst {getPrototypeOf} = Object;\n\nconst kindOf = (cache => thing => {\n const str = toString.call(thing);\n return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());\n})(Object.create(null));\n\nconst kindOfTest = (type) => {\n type = type.toLowerCase();\n return (thing) => kindOf(thing) === type\n}\n\nconst typeOfTest = type => thing => typeof thing === type;\n\n/**\n * Determine if a value is an Array\n *\n * @param {Object} val The value to test\n *\n * @returns {boolean} True if value is an Array, otherwise false\n */\nconst {isArray} = Array;\n\n/**\n * Determine if a value is undefined\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if the value is undefined, otherwise false\n */\nconst isUndefined = typeOfTest('undefined');\n\n/**\n * Determine if a value is a Buffer\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is a Buffer, otherwise false\n */\nfunction isBuffer(val) {\n return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)\n && isFunction(val.constructor.isBuffer) && val.constructor.isBuffer(val);\n}\n\n/**\n * Determine if a value is an ArrayBuffer\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is an ArrayBuffer, otherwise false\n */\nconst isArrayBuffer = kindOfTest('ArrayBuffer');\n\n\n/**\n * Determine if a value is a view on an ArrayBuffer\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false\n */\nfunction isArrayBufferView(val) {\n let result;\n if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {\n result = ArrayBuffer.isView(val);\n } else {\n result = (val) && (val.buffer) && (isArrayBuffer(val.buffer));\n }\n return result;\n}\n\n/**\n * Determine if a value is a String\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is a String, otherwise false\n */\nconst isString = typeOfTest('string');\n\n/**\n * Determine if a value is a Function\n *\n * @param {*} val The value to test\n * @returns {boolean} True if value is a Function, otherwise false\n */\nconst isFunction = typeOfTest('function');\n\n/**\n * Determine if a value is a Number\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is a Number, otherwise false\n */\nconst isNumber = typeOfTest('number');\n\n/**\n * Determine if a value is an Object\n *\n * @param {*} thing The value to test\n *\n * @returns {boolean} True if value is an Object, otherwise false\n */\nconst isObject = (thing) => thing !== null && typeof thing === 'object';\n\n/**\n * Determine if a value is a Boolean\n *\n * @param {*} thing The value to test\n * @returns {boolean} True if value is a Boolean, otherwise false\n */\nconst isBoolean = thing => thing === true || thing === false;\n\n/**\n * Determine if a value is a plain Object\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is a plain Object, otherwise false\n */\nconst isPlainObject = (val) => {\n if (kindOf(val) !== 'object') {\n return false;\n }\n\n const prototype = getPrototypeOf(val);\n return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in val) && !(Symbol.iterator in val);\n}\n\n/**\n * Determine if a value is a Date\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is a Date, otherwise false\n */\nconst isDate = kindOfTest('Date');\n\n/**\n * Determine if a value is a File\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is a File, otherwise false\n */\nconst isFile = kindOfTest('File');\n\n/**\n * Determine if a value is a Blob\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is a Blob, otherwise false\n */\nconst isBlob = kindOfTest('Blob');\n\n/**\n * Determine if a value is a FileList\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is a File, otherwise false\n */\nconst isFileList = kindOfTest('FileList');\n\n/**\n * Determine if a value is a Stream\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is a Stream, otherwise false\n */\nconst isStream = (val) => isObject(val) && isFunction(val.pipe);\n\n/**\n * Determine if a value is a FormData\n *\n * @param {*} thing The value to test\n *\n * @returns {boolean} True if value is an FormData, otherwise false\n */\nconst isFormData = (thing) => {\n let kind;\n return thing && (\n (typeof FormData === 'function' && thing instanceof FormData) || (\n isFunction(thing.append) && (\n (kind = kindOf(thing)) === 'formdata' ||\n // detect form-data instance\n (kind === 'object' && isFunction(thing.toString) && thing.toString() === '[object FormData]')\n )\n )\n )\n}\n\n/**\n * Determine if a value is a URLSearchParams object\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is a URLSearchParams object, otherwise false\n */\nconst isURLSearchParams = kindOfTest('URLSearchParams');\n\nconst [isReadableStream, isRequest, isResponse, isHeaders] = ['ReadableStream', 'Request', 'Response', 'Headers'].map(kindOfTest);\n\n/**\n * Trim excess whitespace off the beginning and end of a string\n *\n * @param {String} str The String to trim\n *\n * @returns {String} The String freed of excess whitespace\n */\nconst trim = (str) => str.trim ?\n str.trim() : str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n\n/**\n * Iterate over an Array or an Object invoking a function for each item.\n *\n * If `obj` is an Array callback will be called passing\n * the value, index, and complete array for each item.\n *\n * If 'obj' is an Object callback will be called passing\n * the value, key, and complete object for each property.\n *\n * @param {Object|Array} obj The object to iterate\n * @param {Function} fn The callback to invoke for each item\n *\n * @param {Boolean} [allOwnKeys = false]\n * @returns {any}\n */\nfunction forEach(obj, fn, {allOwnKeys = false} = {}) {\n // Don't bother if no value provided\n if (obj === null || typeof obj === 'undefined') {\n return;\n }\n\n let i;\n let l;\n\n // Force an array if not already something iterable\n if (typeof obj !== 'object') {\n /*eslint no-param-reassign:0*/\n obj = [obj];\n }\n\n if (isArray(obj)) {\n // Iterate over array values\n for (i = 0, l = obj.length; i < l; i++) {\n fn.call(null, obj[i], i, obj);\n }\n } else {\n // Iterate over object keys\n const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj);\n const len = keys.length;\n let key;\n\n for (i = 0; i < len; i++) {\n key = keys[i];\n fn.call(null, obj[key], key, obj);\n }\n }\n}\n\nfunction findKey(obj, key) {\n key = key.toLowerCase();\n const keys = Object.keys(obj);\n let i = keys.length;\n let _key;\n while (i-- > 0) {\n _key = keys[i];\n if (key === _key.toLowerCase()) {\n return _key;\n }\n }\n return null;\n}\n\nconst _global = (() => {\n /*eslint no-undef:0*/\n if (typeof globalThis !== \"undefined\") return globalThis;\n return typeof self !== \"undefined\" ? self : (typeof window !== 'undefined' ? window : global)\n})();\n\nconst isContextDefined = (context) => !isUndefined(context) && context !== _global;\n\n/**\n * Accepts varargs expecting each argument to be an object, then\n * immutably merges the properties of each object and returns result.\n *\n * When multiple objects contain the same key the later object in\n * the arguments list will take precedence.\n *\n * Example:\n *\n * ```js\n * var result = merge({foo: 123}, {foo: 456});\n * console.log(result.foo); // outputs 456\n * ```\n *\n * @param {Object} obj1 Object to merge\n *\n * @returns {Object} Result of all merge properties\n */\nfunction merge(/* obj1, obj2, obj3, ... */) {\n const {caseless} = isContextDefined(this) && this || {};\n const result = {};\n const assignValue = (val, key) => {\n const targetKey = caseless && findKey(result, key) || key;\n if (isPlainObject(result[targetKey]) && isPlainObject(val)) {\n result[targetKey] = merge(result[targetKey], val);\n } else if (isPlainObject(val)) {\n result[targetKey] = merge({}, val);\n } else if (isArray(val)) {\n result[targetKey] = val.slice();\n } else {\n result[targetKey] = val;\n }\n }\n\n for (let i = 0, l = arguments.length; i < l; i++) {\n arguments[i] && forEach(arguments[i], assignValue);\n }\n return result;\n}\n\n/**\n * Extends object a by mutably adding to it the properties of object b.\n *\n * @param {Object} a The object to be extended\n * @param {Object} b The object to copy properties from\n * @param {Object} thisArg The object to bind function to\n *\n * @param {Boolean} [allOwnKeys]\n * @returns {Object} The resulting value of object a\n */\nconst extend = (a, b, thisArg, {allOwnKeys}= {}) => {\n forEach(b, (val, key) => {\n if (thisArg && isFunction(val)) {\n a[key] = bind(val, thisArg);\n } else {\n a[key] = val;\n }\n }, {allOwnKeys});\n return a;\n}\n\n/**\n * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)\n *\n * @param {string} content with BOM\n *\n * @returns {string} content value without BOM\n */\nconst stripBOM = (content) => {\n if (content.charCodeAt(0) === 0xFEFF) {\n content = content.slice(1);\n }\n return content;\n}\n\n/**\n * Inherit the prototype methods from one constructor into another\n * @param {function} constructor\n * @param {function} superConstructor\n * @param {object} [props]\n * @param {object} [descriptors]\n *\n * @returns {void}\n */\nconst inherits = (constructor, superConstructor, props, descriptors) => {\n constructor.prototype = Object.create(superConstructor.prototype, descriptors);\n constructor.prototype.constructor = constructor;\n Object.defineProperty(constructor, 'super', {\n value: superConstructor.prototype\n });\n props && Object.assign(constructor.prototype, props);\n}\n\n/**\n * Resolve object with deep prototype chain to a flat object\n * @param {Object} sourceObj source object\n * @param {Object} [destObj]\n * @param {Function|Boolean} [filter]\n * @param {Function} [propFilter]\n *\n * @returns {Object}\n */\nconst toFlatObject = (sourceObj, destObj, filter, propFilter) => {\n let props;\n let i;\n let prop;\n const merged = {};\n\n destObj = destObj || {};\n // eslint-disable-next-line no-eq-null,eqeqeq\n if (sourceObj == null) return destObj;\n\n do {\n props = Object.getOwnPropertyNames(sourceObj);\n i = props.length;\n while (i-- > 0) {\n prop = props[i];\n if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) {\n destObj[prop] = sourceObj[prop];\n merged[prop] = true;\n }\n }\n sourceObj = filter !== false && getPrototypeOf(sourceObj);\n } while (sourceObj && (!filter || filter(sourceObj, destObj)) && sourceObj !== Object.prototype);\n\n return destObj;\n}\n\n/**\n * Determines whether a string ends with the characters of a specified string\n *\n * @param {String} str\n * @param {String} searchString\n * @param {Number} [position= 0]\n *\n * @returns {boolean}\n */\nconst endsWith = (str, searchString, position) => {\n str = String(str);\n if (position === undefined || position > str.length) {\n position = str.length;\n }\n position -= searchString.length;\n const lastIndex = str.indexOf(searchString, position);\n return lastIndex !== -1 && lastIndex === position;\n}\n\n\n/**\n * Returns new array from array like object or null if failed\n *\n * @param {*} [thing]\n *\n * @returns {?Array}\n */\nconst toArray = (thing) => {\n if (!thing) return null;\n if (isArray(thing)) return thing;\n let i = thing.length;\n if (!isNumber(i)) return null;\n const arr = new Array(i);\n while (i-- > 0) {\n arr[i] = thing[i];\n }\n return arr;\n}\n\n/**\n * Checking if the Uint8Array exists and if it does, it returns a function that checks if the\n * thing passed in is an instance of Uint8Array\n *\n * @param {TypedArray}\n *\n * @returns {Array}\n */\n// eslint-disable-next-line func-names\nconst isTypedArray = (TypedArray => {\n // eslint-disable-next-line func-names\n return thing => {\n return TypedArray && thing instanceof TypedArray;\n };\n})(typeof Uint8Array !== 'undefined' && getPrototypeOf(Uint8Array));\n\n/**\n * For each entry in the object, call the function with the key and value.\n *\n * @param {Object} obj - The object to iterate over.\n * @param {Function} fn - The function to call for each entry.\n *\n * @returns {void}\n */\nconst forEachEntry = (obj, fn) => {\n const generator = obj && obj[Symbol.iterator];\n\n const iterator = generator.call(obj);\n\n let result;\n\n while ((result = iterator.next()) && !result.done) {\n const pair = result.value;\n fn.call(obj, pair[0], pair[1]);\n }\n}\n\n/**\n * It takes a regular expression and a string, and returns an array of all the matches\n *\n * @param {string} regExp - The regular expression to match against.\n * @param {string} str - The string to search.\n *\n * @returns {Array}\n */\nconst matchAll = (regExp, str) => {\n let matches;\n const arr = [];\n\n while ((matches = regExp.exec(str)) !== null) {\n arr.push(matches);\n }\n\n return arr;\n}\n\n/* Checking if the kindOfTest function returns true when passed an HTMLFormElement. */\nconst isHTMLForm = kindOfTest('HTMLFormElement');\n\nconst toCamelCase = str => {\n return str.toLowerCase().replace(/[-_\\s]([a-z\\d])(\\w*)/g,\n function replacer(m, p1, p2) {\n return p1.toUpperCase() + p2;\n }\n );\n};\n\n/* Creating a function that will check if an object has a property. */\nconst hasOwnProperty = (({hasOwnProperty}) => (obj, prop) => hasOwnProperty.call(obj, prop))(Object.prototype);\n\n/**\n * Determine if a value is a RegExp object\n *\n * @param {*} val The value to test\n *\n * @returns {boolean} True if value is a RegExp object, otherwise false\n */\nconst isRegExp = kindOfTest('RegExp');\n\nconst reduceDescriptors = (obj, reducer) => {\n const descriptors = Object.getOwnPropertyDescriptors(obj);\n const reducedDescriptors = {};\n\n forEach(descriptors, (descriptor, name) => {\n let ret;\n if ((ret = reducer(descriptor, name, obj)) !== false) {\n reducedDescriptors[name] = ret || descriptor;\n }\n });\n\n Object.defineProperties(obj, reducedDescriptors);\n}\n\n/**\n * Makes all methods read-only\n * @param {Object} obj\n */\n\nconst freezeMethods = (obj) => {\n reduceDescriptors(obj, (descriptor, name) => {\n // skip restricted props in strict mode\n if (isFunction(obj) && ['arguments', 'caller', 'callee'].indexOf(name) !== -1) {\n return false;\n }\n\n const value = obj[name];\n\n if (!isFunction(value)) return;\n\n descriptor.enumerable = false;\n\n if ('writable' in descriptor) {\n descriptor.writable = false;\n return;\n }\n\n if (!descriptor.set) {\n descriptor.set = () => {\n throw Error('Can not rewrite read-only method \\'' + name + '\\'');\n };\n }\n });\n}\n\nconst toObjectSet = (arrayOrString, delimiter) => {\n const obj = {};\n\n const define = (arr) => {\n arr.forEach(value => {\n obj[value] = true;\n });\n }\n\n isArray(arrayOrString) ? define(arrayOrString) : define(String(arrayOrString).split(delimiter));\n\n return obj;\n}\n\nconst noop = () => {}\n\nconst toFiniteNumber = (value, defaultValue) => {\n return value != null && Number.isFinite(value = +value) ? value : defaultValue;\n}\n\nconst ALPHA = 'abcdefghijklmnopqrstuvwxyz'\n\nconst DIGIT = '0123456789';\n\nconst ALPHABET = {\n DIGIT,\n ALPHA,\n ALPHA_DIGIT: ALPHA + ALPHA.toUpperCase() + DIGIT\n}\n\nconst generateString = (size = 16, alphabet = ALPHABET.ALPHA_DIGIT) => {\n let str = '';\n const {length} = alphabet;\n while (size--) {\n str += alphabet[Math.random() * length|0]\n }\n\n return str;\n}\n\n/**\n * If the thing is a FormData object, return true, otherwise return false.\n *\n * @param {unknown} thing - The thing to check.\n *\n * @returns {boolean}\n */\nfunction isSpecCompliantForm(thing) {\n return !!(thing && isFunction(thing.append) && thing[Symbol.toStringTag] === 'FormData' && thing[Symbol.iterator]);\n}\n\nconst toJSONObject = (obj) => {\n const stack = new Array(10);\n\n const visit = (source, i) => {\n\n if (isObject(source)) {\n if (stack.indexOf(source) >= 0) {\n return;\n }\n\n if(!('toJSON' in source)) {\n stack[i] = source;\n const target = isArray(source) ? [] : {};\n\n forEach(source, (value, key) => {\n const reducedValue = visit(value, i + 1);\n !isUndefined(reducedValue) && (target[key] = reducedValue);\n });\n\n stack[i] = undefined;\n\n return target;\n }\n }\n\n return source;\n }\n\n return visit(obj, 0);\n}\n\nconst isAsyncFn = kindOfTest('AsyncFunction');\n\nconst isThenable = (thing) =>\n thing && (isObject(thing) || isFunction(thing)) && isFunction(thing.then) && isFunction(thing.catch);\n\n// original code\n// https://github.com/DigitalBrainJS/AxiosPromise/blob/16deab13710ec09779922131f3fa5954320f83ab/lib/utils.js#L11-L34\n\nconst _setImmediate = ((setImmediateSupported, postMessageSupported) => {\n if (setImmediateSupported) {\n return setImmediate;\n }\n\n return postMessageSupported ? ((token, callbacks) => {\n _global.addEventListener(\"message\", ({source, data}) => {\n if (source === _global && data === token) {\n callbacks.length && callbacks.shift()();\n }\n }, false);\n\n return (cb) => {\n callbacks.push(cb);\n _global.postMessage(token, \"*\");\n }\n })(`axios@${Math.random()}`, []) : (cb) => setTimeout(cb);\n})(\n typeof setImmediate === 'function',\n isFunction(_global.postMessage)\n);\n\nconst asap = typeof queueMicrotask !== 'undefined' ?\n queueMicrotask.bind(_global) : ( typeof process !== 'undefined' && process.nextTick || _setImmediate);\n\n// *********************\n\nexport default {\n isArray,\n isArrayBuffer,\n isBuffer,\n isFormData,\n isArrayBufferView,\n isString,\n isNumber,\n isBoolean,\n isObject,\n isPlainObject,\n isReadableStream,\n isRequest,\n isResponse,\n isHeaders,\n isUndefined,\n isDate,\n isFile,\n isBlob,\n isRegExp,\n isFunction,\n isStream,\n isURLSearchParams,\n isTypedArray,\n isFileList,\n forEach,\n merge,\n extend,\n trim,\n stripBOM,\n inherits,\n toFlatObject,\n kindOf,\n kindOfTest,\n endsWith,\n toArray,\n forEachEntry,\n matchAll,\n isHTMLForm,\n hasOwnProperty,\n hasOwnProp: hasOwnProperty, // an alias to avoid ESLint no-prototype-builtins detection\n reduceDescriptors,\n freezeMethods,\n toObjectSet,\n toCamelCase,\n noop,\n toFiniteNumber,\n findKey,\n global: _global,\n isContextDefined,\n ALPHABET,\n generateString,\n isSpecCompliantForm,\n toJSONObject,\n isAsyncFn,\n isThenable,\n setImmediate: _setImmediate,\n asap\n};\n","'use strict';\n\nimport utils from '../utils.js';\n\n/**\n * Create an Error with the specified message, config, error code, request and response.\n *\n * @param {string} message The error message.\n * @param {string} [code] The error code (for example, 'ECONNABORTED').\n * @param {Object} [config] The config.\n * @param {Object} [request] The request.\n * @param {Object} [response] The response.\n *\n * @returns {Error} The created error.\n */\nfunction AxiosError(message, code, config, request, response) {\n Error.call(this);\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, this.constructor);\n } else {\n this.stack = (new Error()).stack;\n }\n\n this.message = message;\n this.name = 'AxiosError';\n code && (this.code = code);\n config && (this.config = config);\n request && (this.request = request);\n response && (this.response = response);\n}\n\nutils.inherits(AxiosError, Error, {\n toJSON: function toJSON() {\n return {\n // Standard\n message: this.message,\n name: this.name,\n // Microsoft\n description: this.description,\n number: this.number,\n // Mozilla\n fileName: this.fileName,\n lineNumber: this.lineNumber,\n columnNumber: this.columnNumber,\n stack: this.stack,\n // Axios\n config: utils.toJSONObject(this.config),\n code: this.code,\n status: this.response && this.response.status ? this.response.status : null\n };\n }\n});\n\nconst prototype = AxiosError.prototype;\nconst descriptors = {};\n\n[\n 'ERR_BAD_OPTION_VALUE',\n 'ERR_BAD_OPTION',\n 'ECONNABORTED',\n 'ETIMEDOUT',\n 'ERR_NETWORK',\n 'ERR_FR_TOO_MANY_REDIRECTS',\n 'ERR_DEPRECATED',\n 'ERR_BAD_RESPONSE',\n 'ERR_BAD_REQUEST',\n 'ERR_CANCELED',\n 'ERR_NOT_SUPPORT',\n 'ERR_INVALID_URL'\n// eslint-disable-next-line func-names\n].forEach(code => {\n descriptors[code] = {value: code};\n});\n\nObject.defineProperties(AxiosError, descriptors);\nObject.defineProperty(prototype, 'isAxiosError', {value: true});\n\n// eslint-disable-next-line func-names\nAxiosError.from = (error, code, config, request, response, customProps) => {\n const axiosError = Object.create(prototype);\n\n utils.toFlatObject(error, axiosError, function filter(obj) {\n return obj !== Error.prototype;\n }, prop => {\n return prop !== 'isAxiosError';\n });\n\n AxiosError.call(axiosError, error.message, code, config, request, response);\n\n axiosError.cause = error;\n\n axiosError.name = error.name;\n\n customProps && Object.assign(axiosError, customProps);\n\n return axiosError;\n};\n\nexport default AxiosError;\n","'use strict';\n\nimport utils from '../utils.js';\nimport AxiosError from '../core/AxiosError.js';\n// temporary hotfix to avoid circular references until AxiosURLSearchParams is refactored\nimport PlatformFormData from '../platform/node/classes/FormData.js';\n\n/**\n * Determines if the given thing is a array or js object.\n *\n * @param {string} thing - The object or array to be visited.\n *\n * @returns {boolean}\n */\nfunction isVisitable(thing) {\n return utils.isPlainObject(thing) || utils.isArray(thing);\n}\n\n/**\n * It removes the brackets from the end of a string\n *\n * @param {string} key - The key of the parameter.\n *\n * @returns {string} the key without the brackets.\n */\nfunction removeBrackets(key) {\n return utils.endsWith(key, '[]') ? key.slice(0, -2) : key;\n}\n\n/**\n * It takes a path, a key, and a boolean, and returns a string\n *\n * @param {string} path - The path to the current key.\n * @param {string} key - The key of the current object being iterated over.\n * @param {string} dots - If true, the key will be rendered with dots instead of brackets.\n *\n * @returns {string} The path to the current key.\n */\nfunction renderKey(path, key, dots) {\n if (!path) return key;\n return path.concat(key).map(function each(token, i) {\n // eslint-disable-next-line no-param-reassign\n token = removeBrackets(token);\n return !dots && i ? '[' + token + ']' : token;\n }).join(dots ? '.' : '');\n}\n\n/**\n * If the array is an array and none of its elements are visitable, then it's a flat array.\n *\n * @param {Array} arr - The array to check\n *\n * @returns {boolean}\n */\nfunction isFlatArray(arr) {\n return utils.isArray(arr) && !arr.some(isVisitable);\n}\n\nconst predicates = utils.toFlatObject(utils, {}, null, function filter(prop) {\n return /^is[A-Z]/.test(prop);\n});\n\n/**\n * Convert a data object to FormData\n *\n * @param {Object} obj\n * @param {?Object} [formData]\n * @param {?Object} [options]\n * @param {Function} [options.visitor]\n * @param {Boolean} [options.metaTokens = true]\n * @param {Boolean} [options.dots = false]\n * @param {?Boolean} [options.indexes = false]\n *\n * @returns {Object}\n **/\n\n/**\n * It converts an object into a FormData object\n *\n * @param {Object} obj - The object to convert to form data.\n * @param {string} formData - The FormData object to append to.\n * @param {Object} options\n *\n * @returns\n */\nfunction toFormData(obj, formData, options) {\n if (!utils.isObject(obj)) {\n throw new TypeError('target must be an object');\n }\n\n // eslint-disable-next-line no-param-reassign\n formData = formData || new (PlatformFormData || FormData)();\n\n // eslint-disable-next-line no-param-reassign\n options = utils.toFlatObject(options, {\n metaTokens: true,\n dots: false,\n indexes: false\n }, false, function defined(option, source) {\n // eslint-disable-next-line no-eq-null,eqeqeq\n return !utils.isUndefined(source[option]);\n });\n\n const metaTokens = options.metaTokens;\n // eslint-disable-next-line no-use-before-define\n const visitor = options.visitor || defaultVisitor;\n const dots = options.dots;\n const indexes = options.indexes;\n const _Blob = options.Blob || typeof Blob !== 'undefined' && Blob;\n const useBlob = _Blob && utils.isSpecCompliantForm(formData);\n\n if (!utils.isFunction(visitor)) {\n throw new TypeError('visitor must be a function');\n }\n\n function convertValue(value) {\n if (value === null) return '';\n\n if (utils.isDate(value)) {\n return value.toISOString();\n }\n\n if (!useBlob && utils.isBlob(value)) {\n throw new AxiosError('Blob is not supported. Use a Buffer instead.');\n }\n\n if (utils.isArrayBuffer(value) || utils.isTypedArray(value)) {\n return useBlob && typeof Blob === 'function' ? new Blob([value]) : Buffer.from(value);\n }\n\n return value;\n }\n\n /**\n * Default visitor.\n *\n * @param {*} value\n * @param {String|Number} key\n * @param {Array} path\n * @this {FormData}\n *\n * @returns {boolean} return true to visit the each prop of the value recursively\n */\n function defaultVisitor(value, key, path) {\n let arr = value;\n\n if (value && !path && typeof value === 'object') {\n if (utils.endsWith(key, '{}')) {\n // eslint-disable-next-line no-param-reassign\n key = metaTokens ? key : key.slice(0, -2);\n // eslint-disable-next-line no-param-reassign\n value = JSON.stringify(value);\n } else if (\n (utils.isArray(value) && isFlatArray(value)) ||\n ((utils.isFileList(value) || utils.endsWith(key, '[]')) && (arr = utils.toArray(value))\n )) {\n // eslint-disable-next-line no-param-reassign\n key = removeBrackets(key);\n\n arr.forEach(function each(el, index) {\n !(utils.isUndefined(el) || el === null) && formData.append(\n // eslint-disable-next-line no-nested-ternary\n indexes === true ? renderKey([key], index, dots) : (indexes === null ? key : key + '[]'),\n convertValue(el)\n );\n });\n return false;\n }\n }\n\n if (isVisitable(value)) {\n return true;\n }\n\n formData.append(renderKey(path, key, dots), convertValue(value));\n\n return false;\n }\n\n const stack = [];\n\n const exposedHelpers = Object.assign(predicates, {\n defaultVisitor,\n convertValue,\n isVisitable\n });\n\n function build(value, path) {\n if (utils.isUndefined(value)) return;\n\n if (stack.indexOf(value) !== -1) {\n throw Error('Circular reference detected in ' + path.join('.'));\n }\n\n stack.push(value);\n\n utils.forEach(value, function each(el, key) {\n const result = !(utils.isUndefined(el) || el === null) && visitor.call(\n formData, el, utils.isString(key) ? key.trim() : key, path, exposedHelpers\n );\n\n if (result === true) {\n build(el, path ? path.concat(key) : [key]);\n }\n });\n\n stack.pop();\n }\n\n if (!utils.isObject(obj)) {\n throw new TypeError('data must be an object');\n }\n\n build(obj);\n\n return formData;\n}\n\nexport default toFormData;\n","'use strict';\n\nimport toFormData from './toFormData.js';\n\n/**\n * It encodes a string by replacing all characters that are not in the unreserved set with\n * their percent-encoded equivalents\n *\n * @param {string} str - The string to encode.\n *\n * @returns {string} The encoded string.\n */\nfunction encode(str) {\n const charMap = {\n '!': '%21',\n \"'\": '%27',\n '(': '%28',\n ')': '%29',\n '~': '%7E',\n '%20': '+',\n '%00': '\\x00'\n };\n return encodeURIComponent(str).replace(/[!'()~]|%20|%00/g, function replacer(match) {\n return charMap[match];\n });\n}\n\n/**\n * It takes a params object and converts it to a FormData object\n *\n * @param {Object} params - The parameters to be converted to a FormData object.\n * @param {Object} options - The options object passed to the Axios constructor.\n *\n * @returns {void}\n */\nfunction AxiosURLSearchParams(params, options) {\n this._pairs = [];\n\n params && toFormData(params, this, options);\n}\n\nconst prototype = AxiosURLSearchParams.prototype;\n\nprototype.append = function append(name, value) {\n this._pairs.push([name, value]);\n};\n\nprototype.toString = function toString(encoder) {\n const _encode = encoder ? function(value) {\n return encoder.call(this, value, encode);\n } : encode;\n\n return this._pairs.map(function each(pair) {\n return _encode(pair[0]) + '=' + _encode(pair[1]);\n }, '').join('&');\n};\n\nexport default AxiosURLSearchParams;\n","'use strict';\n\nimport utils from '../utils.js';\nimport AxiosURLSearchParams from '../helpers/AxiosURLSearchParams.js';\n\n/**\n * It replaces all instances of the characters `:`, `$`, `,`, `+`, `[`, and `]` with their\n * URI encoded counterparts\n *\n * @param {string} val The value to be encoded.\n *\n * @returns {string} The encoded value.\n */\nfunction encode(val) {\n return encodeURIComponent(val).\n replace(/%3A/gi, ':').\n replace(/%24/g, '$').\n replace(/%2C/gi, ',').\n replace(/%20/g, '+').\n replace(/%5B/gi, '[').\n replace(/%5D/gi, ']');\n}\n\n/**\n * Build a URL by appending params to the end\n *\n * @param {string} url The base of the url (e.g., http://www.google.com)\n * @param {object} [params] The params to be appended\n * @param {?object} options\n *\n * @returns {string} The formatted url\n */\nexport default function buildURL(url, params, options) {\n /*eslint no-param-reassign:0*/\n if (!params) {\n return url;\n }\n \n const _encode = options && options.encode || encode;\n\n const serializeFn = options && options.serialize;\n\n let serializedParams;\n\n if (serializeFn) {\n serializedParams = serializeFn(params, options);\n } else {\n serializedParams = utils.isURLSearchParams(params) ?\n params.toString() :\n new AxiosURLSearchParams(params, options).toString(_encode);\n }\n\n if (serializedParams) {\n const hashmarkIndex = url.indexOf(\"#\");\n\n if (hashmarkIndex !== -1) {\n url = url.slice(0, hashmarkIndex);\n }\n url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams;\n }\n\n return url;\n}\n","'use strict';\n\nimport utils from './../utils.js';\n\nclass InterceptorManager {\n constructor() {\n this.handlers = [];\n }\n\n /**\n * Add a new interceptor to the stack\n *\n * @param {Function} fulfilled The function to handle `then` for a `Promise`\n * @param {Function} rejected The function to handle `reject` for a `Promise`\n *\n * @return {Number} An ID used to remove interceptor later\n */\n use(fulfilled, rejected, options) {\n this.handlers.push({\n fulfilled,\n rejected,\n synchronous: options ? options.synchronous : false,\n runWhen: options ? options.runWhen : null\n });\n return this.handlers.length - 1;\n }\n\n /**\n * Remove an interceptor from the stack\n *\n * @param {Number} id The ID that was returned by `use`\n *\n * @returns {Boolean} `true` if the interceptor was removed, `false` otherwise\n */\n eject(id) {\n if (this.handlers[id]) {\n this.handlers[id] = null;\n }\n }\n\n /**\n * Clear all interceptors from the stack\n *\n * @returns {void}\n */\n clear() {\n if (this.handlers) {\n this.handlers = [];\n }\n }\n\n /**\n * Iterate over all the registered interceptors\n *\n * This method is particularly useful for skipping over any\n * interceptors that may have become `null` calling `eject`.\n *\n * @param {Function} fn The function to call for each interceptor\n *\n * @returns {void}\n */\n forEach(fn) {\n utils.forEach(this.handlers, function forEachHandler(h) {\n if (h !== null) {\n fn(h);\n }\n });\n }\n}\n\nexport default InterceptorManager;\n","'use strict';\n\nexport default {\n silentJSONParsing: true,\n forcedJSONParsing: true,\n clarifyTimeoutError: false\n};\n","import URLSearchParams from './classes/URLSearchParams.js'\nimport FormData from './classes/FormData.js'\nimport Blob from './classes/Blob.js'\n\nexport default {\n isBrowser: true,\n classes: {\n URLSearchParams,\n FormData,\n Blob\n },\n protocols: ['http', 'https', 'file', 'blob', 'url', 'data']\n};\n","'use strict';\n\nimport AxiosURLSearchParams from '../../../helpers/AxiosURLSearchParams.js';\nexport default typeof URLSearchParams !== 'undefined' ? URLSearchParams : AxiosURLSearchParams;\n","'use strict';\n\nexport default typeof FormData !== 'undefined' ? FormData : null;\n","'use strict'\n\nexport default typeof Blob !== 'undefined' ? Blob : null\n","const hasBrowserEnv = typeof window !== 'undefined' && typeof document !== 'undefined';\n\n/**\n * Determine if we're running in a standard browser environment\n *\n * This allows axios to run in a web worker, and react-native.\n * Both environments support XMLHttpRequest, but not fully standard globals.\n *\n * web workers:\n * typeof window -> undefined\n * typeof document -> undefined\n *\n * react-native:\n * navigator.product -> 'ReactNative'\n * nativescript\n * navigator.product -> 'NativeScript' or 'NS'\n *\n * @returns {boolean}\n */\nconst hasStandardBrowserEnv = (\n (product) => {\n return hasBrowserEnv && ['ReactNative', 'NativeScript', 'NS'].indexOf(product) < 0\n })(typeof navigator !== 'undefined' && navigator.product);\n\n/**\n * Determine if we're running in a standard browser webWorker environment\n *\n * Although the `isStandardBrowserEnv` method indicates that\n * `allows axios to run in a web worker`, the WebWorker will still be\n * filtered out due to its judgment standard\n * `typeof window !== 'undefined' && typeof document !== 'undefined'`.\n * This leads to a problem when axios post `FormData` in webWorker\n */\nconst hasStandardBrowserWebWorkerEnv = (() => {\n return (\n typeof WorkerGlobalScope !== 'undefined' &&\n // eslint-disable-next-line no-undef\n self instanceof WorkerGlobalScope &&\n typeof self.importScripts === 'function'\n );\n})();\n\nconst origin = hasBrowserEnv && window.location.href || 'http://localhost';\n\nexport {\n hasBrowserEnv,\n hasStandardBrowserWebWorkerEnv,\n hasStandardBrowserEnv,\n origin\n}\n","import platform from './node/index.js';\nimport * as utils from './common/utils.js';\n\nexport default {\n ...utils,\n ...platform\n}\n","'use strict';\n\nimport utils from '../utils.js';\n\n/**\n * It takes a string like `foo[x][y][z]` and returns an array like `['foo', 'x', 'y', 'z']\n *\n * @param {string} name - The name of the property to get.\n *\n * @returns An array of strings.\n */\nfunction parsePropPath(name) {\n // foo[x][y][z]\n // foo.x.y.z\n // foo-x-y-z\n // foo x y z\n return utils.matchAll(/\\w+|\\[(\\w*)]/g, name).map(match => {\n return match[0] === '[]' ? '' : match[1] || match[0];\n });\n}\n\n/**\n * Convert an array to an object.\n *\n * @param {Array} arr - The array to convert to an object.\n *\n * @returns An object with the same keys and values as the array.\n */\nfunction arrayToObject(arr) {\n const obj = {};\n const keys = Object.keys(arr);\n let i;\n const len = keys.length;\n let key;\n for (i = 0; i < len; i++) {\n key = keys[i];\n obj[key] = arr[key];\n }\n return obj;\n}\n\n/**\n * It takes a FormData object and returns a JavaScript object\n *\n * @param {string} formData The FormData object to convert to JSON.\n *\n * @returns {Object | null} The converted object.\n */\nfunction formDataToJSON(formData) {\n function buildPath(path, value, target, index) {\n let name = path[index++];\n\n if (name === '__proto__') return true;\n\n const isNumericKey = Number.isFinite(+name);\n const isLast = index >= path.length;\n name = !name && utils.isArray(target) ? target.length : name;\n\n if (isLast) {\n if (utils.hasOwnProp(target, name)) {\n target[name] = [target[name], value];\n } else {\n target[name] = value;\n }\n\n return !isNumericKey;\n }\n\n if (!target[name] || !utils.isObject(target[name])) {\n target[name] = [];\n }\n\n const result = buildPath(path, value, target[name], index);\n\n if (result && utils.isArray(target[name])) {\n target[name] = arrayToObject(target[name]);\n }\n\n return !isNumericKey;\n }\n\n if (utils.isFormData(formData) && utils.isFunction(formData.entries)) {\n const obj = {};\n\n utils.forEachEntry(formData, (name, value) => {\n buildPath(parsePropPath(name), value, obj, 0);\n });\n\n return obj;\n }\n\n return null;\n}\n\nexport default formDataToJSON;\n","'use strict';\n\nimport utils from '../utils.js';\nimport AxiosError from '../core/AxiosError.js';\nimport transitionalDefaults from './transitional.js';\nimport toFormData from '../helpers/toFormData.js';\nimport toURLEncodedForm from '../helpers/toURLEncodedForm.js';\nimport platform from '../platform/index.js';\nimport formDataToJSON from '../helpers/formDataToJSON.js';\n\n/**\n * It takes a string, tries to parse it, and if it fails, it returns the stringified version\n * of the input\n *\n * @param {any} rawValue - The value to be stringified.\n * @param {Function} parser - A function that parses a string into a JavaScript object.\n * @param {Function} encoder - A function that takes a value and returns a string.\n *\n * @returns {string} A stringified version of the rawValue.\n */\nfunction stringifySafely(rawValue, parser, encoder) {\n if (utils.isString(rawValue)) {\n try {\n (parser || JSON.parse)(rawValue);\n return utils.trim(rawValue);\n } catch (e) {\n if (e.name !== 'SyntaxError') {\n throw e;\n }\n }\n }\n\n return (encoder || JSON.stringify)(rawValue);\n}\n\nconst defaults = {\n\n transitional: transitionalDefaults,\n\n adapter: ['xhr', 'http', 'fetch'],\n\n transformRequest: [function transformRequest(data, headers) {\n const contentType = headers.getContentType() || '';\n const hasJSONContentType = contentType.indexOf('application/json') > -1;\n const isObjectPayload = utils.isObject(data);\n\n if (isObjectPayload && utils.isHTMLForm(data)) {\n data = new FormData(data);\n }\n\n const isFormData = utils.isFormData(data);\n\n if (isFormData) {\n return hasJSONContentType ? JSON.stringify(formDataToJSON(data)) : data;\n }\n\n if (utils.isArrayBuffer(data) ||\n utils.isBuffer(data) ||\n utils.isStream(data) ||\n utils.isFile(data) ||\n utils.isBlob(data) ||\n utils.isReadableStream(data)\n ) {\n return data;\n }\n if (utils.isArrayBufferView(data)) {\n return data.buffer;\n }\n if (utils.isURLSearchParams(data)) {\n headers.setContentType('application/x-www-form-urlencoded;charset=utf-8', false);\n return data.toString();\n }\n\n let isFileList;\n\n if (isObjectPayload) {\n if (contentType.indexOf('application/x-www-form-urlencoded') > -1) {\n return toURLEncodedForm(data, this.formSerializer).toString();\n }\n\n if ((isFileList = utils.isFileList(data)) || contentType.indexOf('multipart/form-data') > -1) {\n const _FormData = this.env && this.env.FormData;\n\n return toFormData(\n isFileList ? {'files[]': data} : data,\n _FormData && new _FormData(),\n this.formSerializer\n );\n }\n }\n\n if (isObjectPayload || hasJSONContentType ) {\n headers.setContentType('application/json', false);\n return stringifySafely(data);\n }\n\n return data;\n }],\n\n transformResponse: [function transformResponse(data) {\n const transitional = this.transitional || defaults.transitional;\n const forcedJSONParsing = transitional && transitional.forcedJSONParsing;\n const JSONRequested = this.responseType === 'json';\n\n if (utils.isResponse(data) || utils.isReadableStream(data)) {\n return data;\n }\n\n if (data && utils.isString(data) && ((forcedJSONParsing && !this.responseType) || JSONRequested)) {\n const silentJSONParsing = transitional && transitional.silentJSONParsing;\n const strictJSONParsing = !silentJSONParsing && JSONRequested;\n\n try {\n return JSON.parse(data);\n } catch (e) {\n if (strictJSONParsing) {\n if (e.name === 'SyntaxError') {\n throw AxiosError.from(e, AxiosError.ERR_BAD_RESPONSE, this, null, this.response);\n }\n throw e;\n }\n }\n }\n\n return data;\n }],\n\n /**\n * A timeout in milliseconds to abort a request. If set to 0 (default) a\n * timeout is not created.\n */\n timeout: 0,\n\n xsrfCookieName: 'XSRF-TOKEN',\n xsrfHeaderName: 'X-XSRF-TOKEN',\n\n maxContentLength: -1,\n maxBodyLength: -1,\n\n env: {\n FormData: platform.classes.FormData,\n Blob: platform.classes.Blob\n },\n\n validateStatus: function validateStatus(status) {\n return status >= 200 && status < 300;\n },\n\n headers: {\n common: {\n 'Accept': 'application/json, text/plain, */*',\n 'Content-Type': undefined\n }\n }\n};\n\nutils.forEach(['delete', 'get', 'head', 'post', 'put', 'patch'], (method) => {\n defaults.headers[method] = {};\n});\n\nexport default defaults;\n","'use strict';\n\nimport utils from '../utils.js';\nimport toFormData from './toFormData.js';\nimport platform from '../platform/index.js';\n\nexport default function toURLEncodedForm(data, options) {\n return toFormData(data, new platform.classes.URLSearchParams(), Object.assign({\n visitor: function(value, key, path, helpers) {\n if (platform.isNode && utils.isBuffer(value)) {\n this.append(key, value.toString('base64'));\n return false;\n }\n\n return helpers.defaultVisitor.apply(this, arguments);\n }\n }, options));\n}\n","'use strict';\n\nimport utils from './../utils.js';\n\n// RawAxiosHeaders whose duplicates are ignored by node\n// c.f. https://nodejs.org/api/http.html#http_message_headers\nconst ignoreDuplicateOf = utils.toObjectSet([\n 'age', 'authorization', 'content-length', 'content-type', 'etag',\n 'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since',\n 'last-modified', 'location', 'max-forwards', 'proxy-authorization',\n 'referer', 'retry-after', 'user-agent'\n]);\n\n/**\n * Parse headers into an object\n *\n * ```\n * Date: Wed, 27 Aug 2014 08:58:49 GMT\n * Content-Type: application/json\n * Connection: keep-alive\n * Transfer-Encoding: chunked\n * ```\n *\n * @param {String} rawHeaders Headers needing to be parsed\n *\n * @returns {Object} Headers parsed into an object\n */\nexport default rawHeaders => {\n const parsed = {};\n let key;\n let val;\n let i;\n\n rawHeaders && rawHeaders.split('\\n').forEach(function parser(line) {\n i = line.indexOf(':');\n key = line.substring(0, i).trim().toLowerCase();\n val = line.substring(i + 1).trim();\n\n if (!key || (parsed[key] && ignoreDuplicateOf[key])) {\n return;\n }\n\n if (key === 'set-cookie') {\n if (parsed[key]) {\n parsed[key].push(val);\n } else {\n parsed[key] = [val];\n }\n } else {\n parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;\n }\n });\n\n return parsed;\n};\n","'use strict';\n\nimport utils from '../utils.js';\nimport parseHeaders from '../helpers/parseHeaders.js';\n\nconst $internals = Symbol('internals');\n\nfunction normalizeHeader(header) {\n return header && String(header).trim().toLowerCase();\n}\n\nfunction normalizeValue(value) {\n if (value === false || value == null) {\n return value;\n }\n\n return utils.isArray(value) ? value.map(normalizeValue) : String(value);\n}\n\nfunction parseTokens(str) {\n const tokens = Object.create(null);\n const tokensRE = /([^\\s,;=]+)\\s*(?:=\\s*([^,;]+))?/g;\n let match;\n\n while ((match = tokensRE.exec(str))) {\n tokens[match[1]] = match[2];\n }\n\n return tokens;\n}\n\nconst isValidHeaderName = (str) => /^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(str.trim());\n\nfunction matchHeaderValue(context, value, header, filter, isHeaderNameFilter) {\n if (utils.isFunction(filter)) {\n return filter.call(this, value, header);\n }\n\n if (isHeaderNameFilter) {\n value = header;\n }\n\n if (!utils.isString(value)) return;\n\n if (utils.isString(filter)) {\n return value.indexOf(filter) !== -1;\n }\n\n if (utils.isRegExp(filter)) {\n return filter.test(value);\n }\n}\n\nfunction formatHeader(header) {\n return header.trim()\n .toLowerCase().replace(/([a-z\\d])(\\w*)/g, (w, char, str) => {\n return char.toUpperCase() + str;\n });\n}\n\nfunction buildAccessors(obj, header) {\n const accessorName = utils.toCamelCase(' ' + header);\n\n ['get', 'set', 'has'].forEach(methodName => {\n Object.defineProperty(obj, methodName + accessorName, {\n value: function(arg1, arg2, arg3) {\n return this[methodName].call(this, header, arg1, arg2, arg3);\n },\n configurable: true\n });\n });\n}\n\nclass AxiosHeaders {\n constructor(headers) {\n headers && this.set(headers);\n }\n\n set(header, valueOrRewrite, rewrite) {\n const self = this;\n\n function setHeader(_value, _header, _rewrite) {\n const lHeader = normalizeHeader(_header);\n\n if (!lHeader) {\n throw new Error('header name must be a non-empty string');\n }\n\n const key = utils.findKey(self, lHeader);\n\n if(!key || self[key] === undefined || _rewrite === true || (_rewrite === undefined && self[key] !== false)) {\n self[key || _header] = normalizeValue(_value);\n }\n }\n\n const setHeaders = (headers, _rewrite) =>\n utils.forEach(headers, (_value, _header) => setHeader(_value, _header, _rewrite));\n\n if (utils.isPlainObject(header) || header instanceof this.constructor) {\n setHeaders(header, valueOrRewrite)\n } else if(utils.isString(header) && (header = header.trim()) && !isValidHeaderName(header)) {\n setHeaders(parseHeaders(header), valueOrRewrite);\n } else if (utils.isHeaders(header)) {\n for (const [key, value] of header.entries()) {\n setHeader(value, key, rewrite);\n }\n } else {\n header != null && setHeader(valueOrRewrite, header, rewrite);\n }\n\n return this;\n }\n\n get(header, parser) {\n header = normalizeHeader(header);\n\n if (header) {\n const key = utils.findKey(this, header);\n\n if (key) {\n const value = this[key];\n\n if (!parser) {\n return value;\n }\n\n if (parser === true) {\n return parseTokens(value);\n }\n\n if (utils.isFunction(parser)) {\n return parser.call(this, value, key);\n }\n\n if (utils.isRegExp(parser)) {\n return parser.exec(value);\n }\n\n throw new TypeError('parser must be boolean|regexp|function');\n }\n }\n }\n\n has(header, matcher) {\n header = normalizeHeader(header);\n\n if (header) {\n const key = utils.findKey(this, header);\n\n return !!(key && this[key] !== undefined && (!matcher || matchHeaderValue(this, this[key], key, matcher)));\n }\n\n return false;\n }\n\n delete(header, matcher) {\n const self = this;\n let deleted = false;\n\n function deleteHeader(_header) {\n _header = normalizeHeader(_header);\n\n if (_header) {\n const key = utils.findKey(self, _header);\n\n if (key && (!matcher || matchHeaderValue(self, self[key], key, matcher))) {\n delete self[key];\n\n deleted = true;\n }\n }\n }\n\n if (utils.isArray(header)) {\n header.forEach(deleteHeader);\n } else {\n deleteHeader(header);\n }\n\n return deleted;\n }\n\n clear(matcher) {\n const keys = Object.keys(this);\n let i = keys.length;\n let deleted = false;\n\n while (i--) {\n const key = keys[i];\n if(!matcher || matchHeaderValue(this, this[key], key, matcher, true)) {\n delete this[key];\n deleted = true;\n }\n }\n\n return deleted;\n }\n\n normalize(format) {\n const self = this;\n const headers = {};\n\n utils.forEach(this, (value, header) => {\n const key = utils.findKey(headers, header);\n\n if (key) {\n self[key] = normalizeValue(value);\n delete self[header];\n return;\n }\n\n const normalized = format ? formatHeader(header) : String(header).trim();\n\n if (normalized !== header) {\n delete self[header];\n }\n\n self[normalized] = normalizeValue(value);\n\n headers[normalized] = true;\n });\n\n return this;\n }\n\n concat(...targets) {\n return this.constructor.concat(this, ...targets);\n }\n\n toJSON(asStrings) {\n const obj = Object.create(null);\n\n utils.forEach(this, (value, header) => {\n value != null && value !== false && (obj[header] = asStrings && utils.isArray(value) ? value.join(', ') : value);\n });\n\n return obj;\n }\n\n [Symbol.iterator]() {\n return Object.entries(this.toJSON())[Symbol.iterator]();\n }\n\n toString() {\n return Object.entries(this.toJSON()).map(([header, value]) => header + ': ' + value).join('\\n');\n }\n\n get [Symbol.toStringTag]() {\n return 'AxiosHeaders';\n }\n\n static from(thing) {\n return thing instanceof this ? thing : new this(thing);\n }\n\n static concat(first, ...targets) {\n const computed = new this(first);\n\n targets.forEach((target) => computed.set(target));\n\n return computed;\n }\n\n static accessor(header) {\n const internals = this[$internals] = (this[$internals] = {\n accessors: {}\n });\n\n const accessors = internals.accessors;\n const prototype = this.prototype;\n\n function defineAccessor(_header) {\n const lHeader = normalizeHeader(_header);\n\n if (!accessors[lHeader]) {\n buildAccessors(prototype, _header);\n accessors[lHeader] = true;\n }\n }\n\n utils.isArray(header) ? header.forEach(defineAccessor) : defineAccessor(header);\n\n return this;\n }\n}\n\nAxiosHeaders.accessor(['Content-Type', 'Content-Length', 'Accept', 'Accept-Encoding', 'User-Agent', 'Authorization']);\n\n// reserved names hotfix\nutils.reduceDescriptors(AxiosHeaders.prototype, ({value}, key) => {\n let mapped = key[0].toUpperCase() + key.slice(1); // map `set` => `Set`\n return {\n get: () => value,\n set(headerValue) {\n this[mapped] = headerValue;\n }\n }\n});\n\nutils.freezeMethods(AxiosHeaders);\n\nexport default AxiosHeaders;\n","'use strict';\n\nimport utils from './../utils.js';\nimport defaults from '../defaults/index.js';\nimport AxiosHeaders from '../core/AxiosHeaders.js';\n\n/**\n * Transform the data for a request or a response\n *\n * @param {Array|Function} fns A single function or Array of functions\n * @param {?Object} response The response object\n *\n * @returns {*} The resulting transformed data\n */\nexport default function transformData(fns, response) {\n const config = this || defaults;\n const context = response || config;\n const headers = AxiosHeaders.from(context.headers);\n let data = context.data;\n\n utils.forEach(fns, function transform(fn) {\n data = fn.call(config, data, headers.normalize(), response ? response.status : undefined);\n });\n\n headers.normalize();\n\n return data;\n}\n","'use strict';\n\nexport default function isCancel(value) {\n return !!(value && value.__CANCEL__);\n}\n","'use strict';\n\nimport AxiosError from '../core/AxiosError.js';\nimport utils from '../utils.js';\n\n/**\n * A `CanceledError` is an object that is thrown when an operation is canceled.\n *\n * @param {string=} message The message.\n * @param {Object=} config The config.\n * @param {Object=} request The request.\n *\n * @returns {CanceledError} The created error.\n */\nfunction CanceledError(message, config, request) {\n // eslint-disable-next-line no-eq-null,eqeqeq\n AxiosError.call(this, message == null ? 'canceled' : message, AxiosError.ERR_CANCELED, config, request);\n this.name = 'CanceledError';\n}\n\nutils.inherits(CanceledError, AxiosError, {\n __CANCEL__: true\n});\n\nexport default CanceledError;\n","'use strict';\n\nimport AxiosError from './AxiosError.js';\n\n/**\n * Resolve or reject a Promise based on response status.\n *\n * @param {Function} resolve A function that resolves the promise.\n * @param {Function} reject A function that rejects the promise.\n * @param {object} response The response.\n *\n * @returns {object} The response.\n */\nexport default function settle(resolve, reject, response) {\n const validateStatus = response.config.validateStatus;\n if (!response.status || !validateStatus || validateStatus(response.status)) {\n resolve(response);\n } else {\n reject(new AxiosError(\n 'Request failed with status code ' + response.status,\n [AxiosError.ERR_BAD_REQUEST, AxiosError.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4],\n response.config,\n response.request,\n response\n ));\n }\n}\n","'use strict';\n\n/**\n * Calculate data maxRate\n * @param {Number} [samplesCount= 10]\n * @param {Number} [min= 1000]\n * @returns {Function}\n */\nfunction speedometer(samplesCount, min) {\n samplesCount = samplesCount || 10;\n const bytes = new Array(samplesCount);\n const timestamps = new Array(samplesCount);\n let head = 0;\n let tail = 0;\n let firstSampleTS;\n\n min = min !== undefined ? min : 1000;\n\n return function push(chunkLength) {\n const now = Date.now();\n\n const startedAt = timestamps[tail];\n\n if (!firstSampleTS) {\n firstSampleTS = now;\n }\n\n bytes[head] = chunkLength;\n timestamps[head] = now;\n\n let i = tail;\n let bytesCount = 0;\n\n while (i !== head) {\n bytesCount += bytes[i++];\n i = i % samplesCount;\n }\n\n head = (head + 1) % samplesCount;\n\n if (head === tail) {\n tail = (tail + 1) % samplesCount;\n }\n\n if (now - firstSampleTS < min) {\n return;\n }\n\n const passed = startedAt && now - startedAt;\n\n return passed ? Math.round(bytesCount * 1000 / passed) : undefined;\n };\n}\n\nexport default speedometer;\n","import speedometer from \"./speedometer.js\";\nimport throttle from \"./throttle.js\";\nimport utils from \"../utils.js\";\n\nexport const progressEventReducer = (listener, isDownloadStream, freq = 3) => {\n let bytesNotified = 0;\n const _speedometer = speedometer(50, 250);\n\n return throttle(e => {\n const loaded = e.loaded;\n const total = e.lengthComputable ? e.total : undefined;\n const progressBytes = loaded - bytesNotified;\n const rate = _speedometer(progressBytes);\n const inRange = loaded <= total;\n\n bytesNotified = loaded;\n\n const data = {\n loaded,\n total,\n progress: total ? (loaded / total) : undefined,\n bytes: progressBytes,\n rate: rate ? rate : undefined,\n estimated: rate && total && inRange ? (total - loaded) / rate : undefined,\n event: e,\n lengthComputable: total != null,\n [isDownloadStream ? 'download' : 'upload']: true\n };\n\n listener(data);\n }, freq);\n}\n\nexport const progressEventDecorator = (total, throttled) => {\n const lengthComputable = total != null;\n\n return [(loaded) => throttled[0]({\n lengthComputable,\n total,\n loaded\n }), throttled[1]];\n}\n\nexport const asyncDecorator = (fn) => (...args) => utils.asap(() => fn(...args));\n","/**\n * Throttle decorator\n * @param {Function} fn\n * @param {Number} freq\n * @return {Function}\n */\nfunction throttle(fn, freq) {\n let timestamp = 0;\n let threshold = 1000 / freq;\n let lastArgs;\n let timer;\n\n const invoke = (args, now = Date.now()) => {\n timestamp = now;\n lastArgs = null;\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n fn.apply(null, args);\n }\n\n const throttled = (...args) => {\n const now = Date.now();\n const passed = now - timestamp;\n if ( passed >= threshold) {\n invoke(args, now);\n } else {\n lastArgs = args;\n if (!timer) {\n timer = setTimeout(() => {\n timer = null;\n invoke(lastArgs)\n }, threshold - passed);\n }\n }\n }\n\n const flush = () => lastArgs && invoke(lastArgs);\n\n return [throttled, flush];\n}\n\nexport default throttle;\n","'use strict';\n\nimport utils from './../utils.js';\nimport platform from '../platform/index.js';\n\nexport default platform.hasStandardBrowserEnv ?\n\n// Standard browser envs have full support of the APIs needed to test\n// whether the request URL is of the same origin as current location.\n (function standardBrowserEnv() {\n const msie = /(msie|trident)/i.test(navigator.userAgent);\n const urlParsingNode = document.createElement('a');\n let originURL;\n\n /**\n * Parse a URL to discover its components\n *\n * @param {String} url The URL to be parsed\n * @returns {Object}\n */\n function resolveURL(url) {\n let href = url;\n\n if (msie) {\n // IE needs attribute set twice to normalize properties\n urlParsingNode.setAttribute('href', href);\n href = urlParsingNode.href;\n }\n\n urlParsingNode.setAttribute('href', href);\n\n // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils\n return {\n href: urlParsingNode.href,\n protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',\n host: urlParsingNode.host,\n search: urlParsingNode.search ? urlParsingNode.search.replace(/^\\?/, '') : '',\n hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',\n hostname: urlParsingNode.hostname,\n port: urlParsingNode.port,\n pathname: (urlParsingNode.pathname.charAt(0) === '/') ?\n urlParsingNode.pathname :\n '/' + urlParsingNode.pathname\n };\n }\n\n originURL = resolveURL(window.location.href);\n\n /**\n * Determine if a URL shares the same origin as the current location\n *\n * @param {String} requestURL The URL to test\n * @returns {boolean} True if URL shares the same origin, otherwise false\n */\n return function isURLSameOrigin(requestURL) {\n const parsed = (utils.isString(requestURL)) ? resolveURL(requestURL) : requestURL;\n return (parsed.protocol === originURL.protocol &&\n parsed.host === originURL.host);\n };\n })() :\n\n // Non standard browser envs (web workers, react-native) lack needed support.\n (function nonStandardBrowserEnv() {\n return function isURLSameOrigin() {\n return true;\n };\n })();\n","import utils from './../utils.js';\nimport platform from '../platform/index.js';\n\nexport default platform.hasStandardBrowserEnv ?\n\n // Standard browser envs support document.cookie\n {\n write(name, value, expires, path, domain, secure) {\n const cookie = [name + '=' + encodeURIComponent(value)];\n\n utils.isNumber(expires) && cookie.push('expires=' + new Date(expires).toGMTString());\n\n utils.isString(path) && cookie.push('path=' + path);\n\n utils.isString(domain) && cookie.push('domain=' + domain);\n\n secure === true && cookie.push('secure');\n\n document.cookie = cookie.join('; ');\n },\n\n read(name) {\n const match = document.cookie.match(new RegExp('(^|;\\\\s*)(' + name + ')=([^;]*)'));\n return (match ? decodeURIComponent(match[3]) : null);\n },\n\n remove(name) {\n this.write(name, '', Date.now() - 86400000);\n }\n }\n\n :\n\n // Non-standard browser env (web workers, react-native) lack needed support.\n {\n write() {},\n read() {\n return null;\n },\n remove() {}\n };\n\n","'use strict';\n\nimport isAbsoluteURL from '../helpers/isAbsoluteURL.js';\nimport combineURLs from '../helpers/combineURLs.js';\n\n/**\n * Creates a new URL by combining the baseURL with the requestedURL,\n * only when the requestedURL is not already an absolute URL.\n * If the requestURL is absolute, this function returns the requestedURL untouched.\n *\n * @param {string} baseURL The base URL\n * @param {string} requestedURL Absolute or relative URL to combine\n *\n * @returns {string} The combined full path\n */\nexport default function buildFullPath(baseURL, requestedURL) {\n if (baseURL && !isAbsoluteURL(requestedURL)) {\n return combineURLs(baseURL, requestedURL);\n }\n return requestedURL;\n}\n","'use strict';\n\n/**\n * Determines whether the specified URL is absolute\n *\n * @param {string} url The URL to test\n *\n * @returns {boolean} True if the specified URL is absolute, otherwise false\n */\nexport default function isAbsoluteURL(url) {\n // A URL is considered absolute if it begins with \"://\" or \"//\" (protocol-relative URL).\n // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed\n // by any combination of letters, digits, plus, period, or hyphen.\n return /^([a-z][a-z\\d+\\-.]*:)?\\/\\//i.test(url);\n}\n","'use strict';\n\n/**\n * Creates a new URL by combining the specified URLs\n *\n * @param {string} baseURL The base URL\n * @param {string} relativeURL The relative URL\n *\n * @returns {string} The combined URL\n */\nexport default function combineURLs(baseURL, relativeURL) {\n return relativeURL\n ? baseURL.replace(/\\/?\\/$/, '') + '/' + relativeURL.replace(/^\\/+/, '')\n : baseURL;\n}\n","'use strict';\n\nimport utils from '../utils.js';\nimport AxiosHeaders from \"./AxiosHeaders.js\";\n\nconst headersToObject = (thing) => thing instanceof AxiosHeaders ? { ...thing } : thing;\n\n/**\n * Config-specific merge-function which creates a new config-object\n * by merging two configuration objects together.\n *\n * @param {Object} config1\n * @param {Object} config2\n *\n * @returns {Object} New object resulting from merging config2 to config1\n */\nexport default function mergeConfig(config1, config2) {\n // eslint-disable-next-line no-param-reassign\n config2 = config2 || {};\n const config = {};\n\n function getMergedValue(target, source, caseless) {\n if (utils.isPlainObject(target) && utils.isPlainObject(source)) {\n return utils.merge.call({caseless}, target, source);\n } else if (utils.isPlainObject(source)) {\n return utils.merge({}, source);\n } else if (utils.isArray(source)) {\n return source.slice();\n }\n return source;\n }\n\n // eslint-disable-next-line consistent-return\n function mergeDeepProperties(a, b, caseless) {\n if (!utils.isUndefined(b)) {\n return getMergedValue(a, b, caseless);\n } else if (!utils.isUndefined(a)) {\n return getMergedValue(undefined, a, caseless);\n }\n }\n\n // eslint-disable-next-line consistent-return\n function valueFromConfig2(a, b) {\n if (!utils.isUndefined(b)) {\n return getMergedValue(undefined, b);\n }\n }\n\n // eslint-disable-next-line consistent-return\n function defaultToConfig2(a, b) {\n if (!utils.isUndefined(b)) {\n return getMergedValue(undefined, b);\n } else if (!utils.isUndefined(a)) {\n return getMergedValue(undefined, a);\n }\n }\n\n // eslint-disable-next-line consistent-return\n function mergeDirectKeys(a, b, prop) {\n if (prop in config2) {\n return getMergedValue(a, b);\n } else if (prop in config1) {\n return getMergedValue(undefined, a);\n }\n }\n\n const mergeMap = {\n url: valueFromConfig2,\n method: valueFromConfig2,\n data: valueFromConfig2,\n baseURL: defaultToConfig2,\n transformRequest: defaultToConfig2,\n transformResponse: defaultToConfig2,\n paramsSerializer: defaultToConfig2,\n timeout: defaultToConfig2,\n timeoutMessage: defaultToConfig2,\n withCredentials: defaultToConfig2,\n withXSRFToken: defaultToConfig2,\n adapter: defaultToConfig2,\n responseType: defaultToConfig2,\n xsrfCookieName: defaultToConfig2,\n xsrfHeaderName: defaultToConfig2,\n onUploadProgress: defaultToConfig2,\n onDownloadProgress: defaultToConfig2,\n decompress: defaultToConfig2,\n maxContentLength: defaultToConfig2,\n maxBodyLength: defaultToConfig2,\n beforeRedirect: defaultToConfig2,\n transport: defaultToConfig2,\n httpAgent: defaultToConfig2,\n httpsAgent: defaultToConfig2,\n cancelToken: defaultToConfig2,\n socketPath: defaultToConfig2,\n responseEncoding: defaultToConfig2,\n validateStatus: mergeDirectKeys,\n headers: (a, b) => mergeDeepProperties(headersToObject(a), headersToObject(b), true)\n };\n\n utils.forEach(Object.keys(Object.assign({}, config1, config2)), function computeConfigValue(prop) {\n const merge = mergeMap[prop] || mergeDeepProperties;\n const configValue = merge(config1[prop], config2[prop], prop);\n (utils.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue);\n });\n\n return config;\n}\n","import platform from \"../platform/index.js\";\nimport utils from \"../utils.js\";\nimport isURLSameOrigin from \"./isURLSameOrigin.js\";\nimport cookies from \"./cookies.js\";\nimport buildFullPath from \"../core/buildFullPath.js\";\nimport mergeConfig from \"../core/mergeConfig.js\";\nimport AxiosHeaders from \"../core/AxiosHeaders.js\";\nimport buildURL from \"./buildURL.js\";\n\nexport default (config) => {\n const newConfig = mergeConfig({}, config);\n\n let {data, withXSRFToken, xsrfHeaderName, xsrfCookieName, headers, auth} = newConfig;\n\n newConfig.headers = headers = AxiosHeaders.from(headers);\n\n newConfig.url = buildURL(buildFullPath(newConfig.baseURL, newConfig.url), config.params, config.paramsSerializer);\n\n // HTTP basic authentication\n if (auth) {\n headers.set('Authorization', 'Basic ' +\n btoa((auth.username || '') + ':' + (auth.password ? unescape(encodeURIComponent(auth.password)) : ''))\n );\n }\n\n let contentType;\n\n if (utils.isFormData(data)) {\n if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv) {\n headers.setContentType(undefined); // Let the browser set it\n } else if ((contentType = headers.getContentType()) !== false) {\n // fix semicolon duplication issue for ReactNative FormData implementation\n const [type, ...tokens] = contentType ? contentType.split(';').map(token => token.trim()).filter(Boolean) : [];\n headers.setContentType([type || 'multipart/form-data', ...tokens].join('; '));\n }\n }\n\n // Add xsrf header\n // This is only done if running in a standard browser environment.\n // Specifically not if we're in a web worker, or react-native.\n\n if (platform.hasStandardBrowserEnv) {\n withXSRFToken && utils.isFunction(withXSRFToken) && (withXSRFToken = withXSRFToken(newConfig));\n\n if (withXSRFToken || (withXSRFToken !== false && isURLSameOrigin(newConfig.url))) {\n // Add xsrf header\n const xsrfValue = xsrfHeaderName && xsrfCookieName && cookies.read(xsrfCookieName);\n\n if (xsrfValue) {\n headers.set(xsrfHeaderName, xsrfValue);\n }\n }\n }\n\n return newConfig;\n}\n\n","import utils from './../utils.js';\nimport settle from './../core/settle.js';\nimport transitionalDefaults from '../defaults/transitional.js';\nimport AxiosError from '../core/AxiosError.js';\nimport CanceledError from '../cancel/CanceledError.js';\nimport parseProtocol from '../helpers/parseProtocol.js';\nimport platform from '../platform/index.js';\nimport AxiosHeaders from '../core/AxiosHeaders.js';\nimport {progressEventReducer} from '../helpers/progressEventReducer.js';\nimport resolveConfig from \"../helpers/resolveConfig.js\";\n\nconst isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';\n\nexport default isXHRAdapterSupported && function (config) {\n return new Promise(function dispatchXhrRequest(resolve, reject) {\n const _config = resolveConfig(config);\n let requestData = _config.data;\n const requestHeaders = AxiosHeaders.from(_config.headers).normalize();\n let {responseType, onUploadProgress, onDownloadProgress} = _config;\n let onCanceled;\n let uploadThrottled, downloadThrottled;\n let flushUpload, flushDownload;\n\n function done() {\n flushUpload && flushUpload(); // flush events\n flushDownload && flushDownload(); // flush events\n\n _config.cancelToken && _config.cancelToken.unsubscribe(onCanceled);\n\n _config.signal && _config.signal.removeEventListener('abort', onCanceled);\n }\n\n let request = new XMLHttpRequest();\n\n request.open(_config.method.toUpperCase(), _config.url, true);\n\n // Set the request timeout in MS\n request.timeout = _config.timeout;\n\n function onloadend() {\n if (!request) {\n return;\n }\n // Prepare the response\n const responseHeaders = AxiosHeaders.from(\n 'getAllResponseHeaders' in request && request.getAllResponseHeaders()\n );\n const responseData = !responseType || responseType === 'text' || responseType === 'json' ?\n request.responseText : request.response;\n const response = {\n data: responseData,\n status: request.status,\n statusText: request.statusText,\n headers: responseHeaders,\n config,\n request\n };\n\n settle(function _resolve(value) {\n resolve(value);\n done();\n }, function _reject(err) {\n reject(err);\n done();\n }, response);\n\n // Clean up request\n request = null;\n }\n\n if ('onloadend' in request) {\n // Use onloadend if available\n request.onloadend = onloadend;\n } else {\n // Listen for ready state to emulate onloadend\n request.onreadystatechange = function handleLoad() {\n if (!request || request.readyState !== 4) {\n return;\n }\n\n // The request errored out and we didn't get a response, this will be\n // handled by onerror instead\n // With one exception: request that using file: protocol, most browsers\n // will return status as 0 even though it's a successful request\n if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {\n return;\n }\n // readystate handler is calling before onerror or ontimeout handlers,\n // so we should call onloadend on the next 'tick'\n setTimeout(onloadend);\n };\n }\n\n // Handle browser request cancellation (as opposed to a manual cancellation)\n request.onabort = function handleAbort() {\n if (!request) {\n return;\n }\n\n reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request));\n\n // Clean up request\n request = null;\n };\n\n // Handle low level network errors\n request.onerror = function handleError() {\n // Real errors are hidden from us by the browser\n // onerror should only fire if it's a network error\n reject(new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request));\n\n // Clean up request\n request = null;\n };\n\n // Handle timeout\n request.ontimeout = function handleTimeout() {\n let timeoutErrorMessage = _config.timeout ? 'timeout of ' + _config.timeout + 'ms exceeded' : 'timeout exceeded';\n const transitional = _config.transitional || transitionalDefaults;\n if (_config.timeoutErrorMessage) {\n timeoutErrorMessage = _config.timeoutErrorMessage;\n }\n reject(new AxiosError(\n timeoutErrorMessage,\n transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED,\n config,\n request));\n\n // Clean up request\n request = null;\n };\n\n // Remove Content-Type if data is undefined\n requestData === undefined && requestHeaders.setContentType(null);\n\n // Add headers to the request\n if ('setRequestHeader' in request) {\n utils.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) {\n request.setRequestHeader(key, val);\n });\n }\n\n // Add withCredentials to request if needed\n if (!utils.isUndefined(_config.withCredentials)) {\n request.withCredentials = !!_config.withCredentials;\n }\n\n // Add responseType to request if needed\n if (responseType && responseType !== 'json') {\n request.responseType = _config.responseType;\n }\n\n // Handle progress if needed\n if (onDownloadProgress) {\n ([downloadThrottled, flushDownload] = progressEventReducer(onDownloadProgress, true));\n request.addEventListener('progress', downloadThrottled);\n }\n\n // Not all browsers support upload events\n if (onUploadProgress && request.upload) {\n ([uploadThrottled, flushUpload] = progressEventReducer(onUploadProgress));\n\n request.upload.addEventListener('progress', uploadThrottled);\n\n request.upload.addEventListener('loadend', flushUpload);\n }\n\n if (_config.cancelToken || _config.signal) {\n // Handle cancellation\n // eslint-disable-next-line func-names\n onCanceled = cancel => {\n if (!request) {\n return;\n }\n reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel);\n request.abort();\n request = null;\n };\n\n _config.cancelToken && _config.cancelToken.subscribe(onCanceled);\n if (_config.signal) {\n _config.signal.aborted ? onCanceled() : _config.signal.addEventListener('abort', onCanceled);\n }\n }\n\n const protocol = parseProtocol(_config.url);\n\n if (protocol && platform.protocols.indexOf(protocol) === -1) {\n reject(new AxiosError('Unsupported protocol ' + protocol + ':', AxiosError.ERR_BAD_REQUEST, config));\n return;\n }\n\n\n // Send the request\n request.send(requestData || null);\n });\n}\n","'use strict';\n\nexport default function parseProtocol(url) {\n const match = /^([-+\\w]{1,25})(:?\\/\\/|:)/.exec(url);\n return match && match[1] || '';\n}\n","import CanceledError from \"../cancel/CanceledError.js\";\nimport AxiosError from \"../core/AxiosError.js\";\n\nconst composeSignals = (signals, timeout) => {\n let controller = new AbortController();\n\n let aborted;\n\n const onabort = function (cancel) {\n if (!aborted) {\n aborted = true;\n unsubscribe();\n const err = cancel instanceof Error ? cancel : this.reason;\n controller.abort(err instanceof AxiosError ? err : new CanceledError(err instanceof Error ? err.message : err));\n }\n }\n\n let timer = timeout && setTimeout(() => {\n onabort(new AxiosError(`timeout ${timeout} of ms exceeded`, AxiosError.ETIMEDOUT))\n }, timeout)\n\n const unsubscribe = () => {\n if (signals) {\n timer && clearTimeout(timer);\n timer = null;\n signals.forEach(signal => {\n signal &&\n (signal.removeEventListener ? signal.removeEventListener('abort', onabort) : signal.unsubscribe(onabort));\n });\n signals = null;\n }\n }\n\n signals.forEach((signal) => signal && signal.addEventListener && signal.addEventListener('abort', onabort));\n\n const {signal} = controller;\n\n signal.unsubscribe = unsubscribe;\n\n return [signal, () => {\n timer && clearTimeout(timer);\n timer = null;\n }];\n}\n\nexport default composeSignals;\n","\nexport const streamChunk = function* (chunk, chunkSize) {\n let len = chunk.byteLength;\n\n if (!chunkSize || len < chunkSize) {\n yield chunk;\n return;\n }\n\n let pos = 0;\n let end;\n\n while (pos < len) {\n end = pos + chunkSize;\n yield chunk.slice(pos, end);\n pos = end;\n }\n}\n\nexport const readBytes = async function* (iterable, chunkSize, encode) {\n for await (const chunk of iterable) {\n yield* streamChunk(ArrayBuffer.isView(chunk) ? chunk : (await encode(String(chunk))), chunkSize);\n }\n}\n\nexport const trackStream = (stream, chunkSize, onProgress, onFinish, encode) => {\n const iterator = readBytes(stream, chunkSize, encode);\n\n let bytes = 0;\n let done;\n let _onFinish = (e) => {\n if (!done) {\n done = true;\n onFinish && onFinish(e);\n }\n }\n\n return new ReadableStream({\n async pull(controller) {\n try {\n const {done, value} = await iterator.next();\n\n if (done) {\n _onFinish();\n controller.close();\n return;\n }\n\n let len = value.byteLength;\n if (onProgress) {\n let loadedBytes = bytes += len;\n onProgress(loadedBytes);\n }\n controller.enqueue(new Uint8Array(value));\n } catch (err) {\n _onFinish(err);\n throw err;\n }\n },\n cancel(reason) {\n _onFinish(reason);\n return iterator.return();\n }\n }, {\n highWaterMark: 2\n })\n}\n","import platform from \"../platform/index.js\";\nimport utils from \"../utils.js\";\nimport AxiosError from \"../core/AxiosError.js\";\nimport composeSignals from \"../helpers/composeSignals.js\";\nimport {trackStream} from \"../helpers/trackStream.js\";\nimport AxiosHeaders from \"../core/AxiosHeaders.js\";\nimport {progressEventReducer, progressEventDecorator, asyncDecorator} from \"../helpers/progressEventReducer.js\";\nimport resolveConfig from \"../helpers/resolveConfig.js\";\nimport settle from \"../core/settle.js\";\n\nconst isFetchSupported = typeof fetch === 'function' && typeof Request === 'function' && typeof Response === 'function';\nconst isReadableStreamSupported = isFetchSupported && typeof ReadableStream === 'function';\n\n// used only inside the fetch adapter\nconst encodeText = isFetchSupported && (typeof TextEncoder === 'function' ?\n ((encoder) => (str) => encoder.encode(str))(new TextEncoder()) :\n async (str) => new Uint8Array(await new Response(str).arrayBuffer())\n);\n\nconst test = (fn, ...args) => {\n try {\n return !!fn(...args);\n } catch (e) {\n return false\n }\n}\n\nconst supportsRequestStream = isReadableStreamSupported && test(() => {\n let duplexAccessed = false;\n\n const hasContentType = new Request(platform.origin, {\n body: new ReadableStream(),\n method: 'POST',\n get duplex() {\n duplexAccessed = true;\n return 'half';\n },\n }).headers.has('Content-Type');\n\n return duplexAccessed && !hasContentType;\n});\n\nconst DEFAULT_CHUNK_SIZE = 64 * 1024;\n\nconst supportsResponseStream = isReadableStreamSupported &&\n test(() => utils.isReadableStream(new Response('').body));\n\n\nconst resolvers = {\n stream: supportsResponseStream && ((res) => res.body)\n};\n\nisFetchSupported && (((res) => {\n ['text', 'arrayBuffer', 'blob', 'formData', 'stream'].forEach(type => {\n !resolvers[type] && (resolvers[type] = utils.isFunction(res[type]) ? (res) => res[type]() :\n (_, config) => {\n throw new AxiosError(`Response type '${type}' is not supported`, AxiosError.ERR_NOT_SUPPORT, config);\n })\n });\n})(new Response));\n\nconst getBodyLength = async (body) => {\n if (body == null) {\n return 0;\n }\n\n if(utils.isBlob(body)) {\n return body.size;\n }\n\n if(utils.isSpecCompliantForm(body)) {\n return (await new Request(body).arrayBuffer()).byteLength;\n }\n\n if(utils.isArrayBufferView(body) || utils.isArrayBuffer(body)) {\n return body.byteLength;\n }\n\n if(utils.isURLSearchParams(body)) {\n body = body + '';\n }\n\n if(utils.isString(body)) {\n return (await encodeText(body)).byteLength;\n }\n}\n\nconst resolveBodyLength = async (headers, body) => {\n const length = utils.toFiniteNumber(headers.getContentLength());\n\n return length == null ? getBodyLength(body) : length;\n}\n\nexport default isFetchSupported && (async (config) => {\n let {\n url,\n method,\n data,\n signal,\n cancelToken,\n timeout,\n onDownloadProgress,\n onUploadProgress,\n responseType,\n headers,\n withCredentials = 'same-origin',\n fetchOptions\n } = resolveConfig(config);\n\n responseType = responseType ? (responseType + '').toLowerCase() : 'text';\n\n let [composedSignal, stopTimeout] = (signal || cancelToken || timeout) ?\n composeSignals([signal, cancelToken], timeout) : [];\n\n let finished, request;\n\n const onFinish = () => {\n !finished && setTimeout(() => {\n composedSignal && composedSignal.unsubscribe();\n });\n\n finished = true;\n }\n\n let requestContentLength;\n\n try {\n if (\n onUploadProgress && supportsRequestStream && method !== 'get' && method !== 'head' &&\n (requestContentLength = await resolveBodyLength(headers, data)) !== 0\n ) {\n let _request = new Request(url, {\n method: 'POST',\n body: data,\n duplex: \"half\"\n });\n\n let contentTypeHeader;\n\n if (utils.isFormData(data) && (contentTypeHeader = _request.headers.get('content-type'))) {\n headers.setContentType(contentTypeHeader)\n }\n\n if (_request.body) {\n const [onProgress, flush] = progressEventDecorator(\n requestContentLength,\n progressEventReducer(asyncDecorator(onUploadProgress))\n );\n\n data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush, encodeText);\n }\n }\n\n if (!utils.isString(withCredentials)) {\n withCredentials = withCredentials ? 'include' : 'omit';\n }\n\n request = new Request(url, {\n ...fetchOptions,\n signal: composedSignal,\n method: method.toUpperCase(),\n headers: headers.normalize().toJSON(),\n body: data,\n duplex: \"half\",\n credentials: withCredentials\n });\n\n let response = await fetch(request);\n\n const isStreamResponse = supportsResponseStream && (responseType === 'stream' || responseType === 'response');\n\n if (supportsResponseStream && (onDownloadProgress || isStreamResponse)) {\n const options = {};\n\n ['status', 'statusText', 'headers'].forEach(prop => {\n options[prop] = response[prop];\n });\n\n const responseContentLength = utils.toFiniteNumber(response.headers.get('content-length'));\n\n const [onProgress, flush] = onDownloadProgress && progressEventDecorator(\n responseContentLength,\n progressEventReducer(asyncDecorator(onDownloadProgress), true)\n ) || [];\n\n response = new Response(\n trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => {\n flush && flush();\n isStreamResponse && onFinish();\n }, encodeText),\n options\n );\n }\n\n responseType = responseType || 'text';\n\n let responseData = await resolvers[utils.findKey(resolvers, responseType) || 'text'](response, config);\n\n !isStreamResponse && onFinish();\n\n stopTimeout && stopTimeout();\n\n return await new Promise((resolve, reject) => {\n settle(resolve, reject, {\n data: responseData,\n headers: AxiosHeaders.from(response.headers),\n status: response.status,\n statusText: response.statusText,\n config,\n request\n })\n })\n } catch (err) {\n onFinish();\n\n if (err && err.name === 'TypeError' && /fetch/i.test(err.message)) {\n throw Object.assign(\n new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request),\n {\n cause: err.cause || err\n }\n )\n }\n\n throw AxiosError.from(err, err && err.code, config, request);\n }\n});\n\n\n","import utils from '../utils.js';\nimport httpAdapter from './http.js';\nimport xhrAdapter from './xhr.js';\nimport fetchAdapter from './fetch.js';\nimport AxiosError from \"../core/AxiosError.js\";\n\nconst knownAdapters = {\n http: httpAdapter,\n xhr: xhrAdapter,\n fetch: fetchAdapter\n}\n\nutils.forEach(knownAdapters, (fn, value) => {\n if (fn) {\n try {\n Object.defineProperty(fn, 'name', {value});\n } catch (e) {\n // eslint-disable-next-line no-empty\n }\n Object.defineProperty(fn, 'adapterName', {value});\n }\n});\n\nconst renderReason = (reason) => `- ${reason}`;\n\nconst isResolvedHandle = (adapter) => utils.isFunction(adapter) || adapter === null || adapter === false;\n\nexport default {\n getAdapter: (adapters) => {\n adapters = utils.isArray(adapters) ? adapters : [adapters];\n\n const {length} = adapters;\n let nameOrAdapter;\n let adapter;\n\n const rejectedReasons = {};\n\n for (let i = 0; i < length; i++) {\n nameOrAdapter = adapters[i];\n let id;\n\n adapter = nameOrAdapter;\n\n if (!isResolvedHandle(nameOrAdapter)) {\n adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()];\n\n if (adapter === undefined) {\n throw new AxiosError(`Unknown adapter '${id}'`);\n }\n }\n\n if (adapter) {\n break;\n }\n\n rejectedReasons[id || '#' + i] = adapter;\n }\n\n if (!adapter) {\n\n const reasons = Object.entries(rejectedReasons)\n .map(([id, state]) => `adapter ${id} ` +\n (state === false ? 'is not supported by the environment' : 'is not available in the build')\n );\n\n let s = length ?\n (reasons.length > 1 ? 'since :\\n' + reasons.map(renderReason).join('\\n') : ' ' + renderReason(reasons[0])) :\n 'as no adapter specified';\n\n throw new AxiosError(\n `There is no suitable adapter to dispatch the request ` + s,\n 'ERR_NOT_SUPPORT'\n );\n }\n\n return adapter;\n },\n adapters: knownAdapters\n}\n","// eslint-disable-next-line strict\nexport default null;\n","'use strict';\n\nimport transformData from './transformData.js';\nimport isCancel from '../cancel/isCancel.js';\nimport defaults from '../defaults/index.js';\nimport CanceledError from '../cancel/CanceledError.js';\nimport AxiosHeaders from '../core/AxiosHeaders.js';\nimport adapters from \"../adapters/adapters.js\";\n\n/**\n * Throws a `CanceledError` if cancellation has been requested.\n *\n * @param {Object} config The config that is to be used for the request\n *\n * @returns {void}\n */\nfunction throwIfCancellationRequested(config) {\n if (config.cancelToken) {\n config.cancelToken.throwIfRequested();\n }\n\n if (config.signal && config.signal.aborted) {\n throw new CanceledError(null, config);\n }\n}\n\n/**\n * Dispatch a request to the server using the configured adapter.\n *\n * @param {object} config The config that is to be used for the request\n *\n * @returns {Promise} The Promise to be fulfilled\n */\nexport default function dispatchRequest(config) {\n throwIfCancellationRequested(config);\n\n config.headers = AxiosHeaders.from(config.headers);\n\n // Transform request data\n config.data = transformData.call(\n config,\n config.transformRequest\n );\n\n if (['post', 'put', 'patch'].indexOf(config.method) !== -1) {\n config.headers.setContentType('application/x-www-form-urlencoded', false);\n }\n\n const adapter = adapters.getAdapter(config.adapter || defaults.adapter);\n\n return adapter(config).then(function onAdapterResolution(response) {\n throwIfCancellationRequested(config);\n\n // Transform response data\n response.data = transformData.call(\n config,\n config.transformResponse,\n response\n );\n\n response.headers = AxiosHeaders.from(response.headers);\n\n return response;\n }, function onAdapterRejection(reason) {\n if (!isCancel(reason)) {\n throwIfCancellationRequested(config);\n\n // Transform response data\n if (reason && reason.response) {\n reason.response.data = transformData.call(\n config,\n config.transformResponse,\n reason.response\n );\n reason.response.headers = AxiosHeaders.from(reason.response.headers);\n }\n }\n\n return Promise.reject(reason);\n });\n}\n","export const VERSION = \"1.7.4\";","'use strict';\n\nimport {VERSION} from '../env/data.js';\nimport AxiosError from '../core/AxiosError.js';\n\nconst validators = {};\n\n// eslint-disable-next-line func-names\n['object', 'boolean', 'number', 'function', 'string', 'symbol'].forEach((type, i) => {\n validators[type] = function validator(thing) {\n return typeof thing === type || 'a' + (i < 1 ? 'n ' : ' ') + type;\n };\n});\n\nconst deprecatedWarnings = {};\n\n/**\n * Transitional option validator\n *\n * @param {function|boolean?} validator - set to false if the transitional option has been removed\n * @param {string?} version - deprecated version / removed since version\n * @param {string?} message - some message with additional info\n *\n * @returns {function}\n */\nvalidators.transitional = function transitional(validator, version, message) {\n function formatMessage(opt, desc) {\n return '[Axios v' + VERSION + '] Transitional option \\'' + opt + '\\'' + desc + (message ? '. ' + message : '');\n }\n\n // eslint-disable-next-line func-names\n return (value, opt, opts) => {\n if (validator === false) {\n throw new AxiosError(\n formatMessage(opt, ' has been removed' + (version ? ' in ' + version : '')),\n AxiosError.ERR_DEPRECATED\n );\n }\n\n if (version && !deprecatedWarnings[opt]) {\n deprecatedWarnings[opt] = true;\n // eslint-disable-next-line no-console\n console.warn(\n formatMessage(\n opt,\n ' has been deprecated since v' + version + ' and will be removed in the near future'\n )\n );\n }\n\n return validator ? validator(value, opt, opts) : true;\n };\n};\n\n/**\n * Assert object's properties type\n *\n * @param {object} options\n * @param {object} schema\n * @param {boolean?} allowUnknown\n *\n * @returns {object}\n */\n\nfunction assertOptions(options, schema, allowUnknown) {\n if (typeof options !== 'object') {\n throw new AxiosError('options must be an object', AxiosError.ERR_BAD_OPTION_VALUE);\n }\n const keys = Object.keys(options);\n let i = keys.length;\n while (i-- > 0) {\n const opt = keys[i];\n const validator = schema[opt];\n if (validator) {\n const value = options[opt];\n const result = value === undefined || validator(value, opt, options);\n if (result !== true) {\n throw new AxiosError('option ' + opt + ' must be ' + result, AxiosError.ERR_BAD_OPTION_VALUE);\n }\n continue;\n }\n if (allowUnknown !== true) {\n throw new AxiosError('Unknown option ' + opt, AxiosError.ERR_BAD_OPTION);\n }\n }\n}\n\nexport default {\n assertOptions,\n validators\n};\n","'use strict';\n\nimport utils from './../utils.js';\nimport buildURL from '../helpers/buildURL.js';\nimport InterceptorManager from './InterceptorManager.js';\nimport dispatchRequest from './dispatchRequest.js';\nimport mergeConfig from './mergeConfig.js';\nimport buildFullPath from './buildFullPath.js';\nimport validator from '../helpers/validator.js';\nimport AxiosHeaders from './AxiosHeaders.js';\n\nconst validators = validator.validators;\n\n/**\n * Create a new instance of Axios\n *\n * @param {Object} instanceConfig The default config for the instance\n *\n * @return {Axios} A new instance of Axios\n */\nclass Axios {\n constructor(instanceConfig) {\n this.defaults = instanceConfig;\n this.interceptors = {\n request: new InterceptorManager(),\n response: new InterceptorManager()\n };\n }\n\n /**\n * Dispatch a request\n *\n * @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults)\n * @param {?Object} config\n *\n * @returns {Promise} The Promise to be fulfilled\n */\n async request(configOrUrl, config) {\n try {\n return await this._request(configOrUrl, config);\n } catch (err) {\n if (err instanceof Error) {\n let dummy;\n\n Error.captureStackTrace ? Error.captureStackTrace(dummy = {}) : (dummy = new Error());\n\n // slice off the Error: ... line\n const stack = dummy.stack ? dummy.stack.replace(/^.+\\n/, '') : '';\n try {\n if (!err.stack) {\n err.stack = stack;\n // match without the 2 top stack lines\n } else if (stack && !String(err.stack).endsWith(stack.replace(/^.+\\n.+\\n/, ''))) {\n err.stack += '\\n' + stack\n }\n } catch (e) {\n // ignore the case where \"stack\" is an un-writable property\n }\n }\n\n throw err;\n }\n }\n\n _request(configOrUrl, config) {\n /*eslint no-param-reassign:0*/\n // Allow for axios('example/url'[, config]) a la fetch API\n if (typeof configOrUrl === 'string') {\n config = config || {};\n config.url = configOrUrl;\n } else {\n config = configOrUrl || {};\n }\n\n config = mergeConfig(this.defaults, config);\n\n const {transitional, paramsSerializer, headers} = config;\n\n if (transitional !== undefined) {\n validator.assertOptions(transitional, {\n silentJSONParsing: validators.transitional(validators.boolean),\n forcedJSONParsing: validators.transitional(validators.boolean),\n clarifyTimeoutError: validators.transitional(validators.boolean)\n }, false);\n }\n\n if (paramsSerializer != null) {\n if (utils.isFunction(paramsSerializer)) {\n config.paramsSerializer = {\n serialize: paramsSerializer\n }\n } else {\n validator.assertOptions(paramsSerializer, {\n encode: validators.function,\n serialize: validators.function\n }, true);\n }\n }\n\n // Set config.method\n config.method = (config.method || this.defaults.method || 'get').toLowerCase();\n\n // Flatten headers\n let contextHeaders = headers && utils.merge(\n headers.common,\n headers[config.method]\n );\n\n headers && utils.forEach(\n ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],\n (method) => {\n delete headers[method];\n }\n );\n\n config.headers = AxiosHeaders.concat(contextHeaders, headers);\n\n // filter out skipped interceptors\n const requestInterceptorChain = [];\n let synchronousRequestInterceptors = true;\n this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {\n if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {\n return;\n }\n\n synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;\n\n requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);\n });\n\n const responseInterceptorChain = [];\n this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {\n responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);\n });\n\n let promise;\n let i = 0;\n let len;\n\n if (!synchronousRequestInterceptors) {\n const chain = [dispatchRequest.bind(this), undefined];\n chain.unshift.apply(chain, requestInterceptorChain);\n chain.push.apply(chain, responseInterceptorChain);\n len = chain.length;\n\n promise = Promise.resolve(config);\n\n while (i < len) {\n promise = promise.then(chain[i++], chain[i++]);\n }\n\n return promise;\n }\n\n len = requestInterceptorChain.length;\n\n let newConfig = config;\n\n i = 0;\n\n while (i < len) {\n const onFulfilled = requestInterceptorChain[i++];\n const onRejected = requestInterceptorChain[i++];\n try {\n newConfig = onFulfilled(newConfig);\n } catch (error) {\n onRejected.call(this, error);\n break;\n }\n }\n\n try {\n promise = dispatchRequest.call(this, newConfig);\n } catch (error) {\n return Promise.reject(error);\n }\n\n i = 0;\n len = responseInterceptorChain.length;\n\n while (i < len) {\n promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);\n }\n\n return promise;\n }\n\n getUri(config) {\n config = mergeConfig(this.defaults, config);\n const fullPath = buildFullPath(config.baseURL, config.url);\n return buildURL(fullPath, config.params, config.paramsSerializer);\n }\n}\n\n// Provide aliases for supported request methods\nutils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {\n /*eslint func-names:0*/\n Axios.prototype[method] = function(url, config) {\n return this.request(mergeConfig(config || {}, {\n method,\n url,\n data: (config || {}).data\n }));\n };\n});\n\nutils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {\n /*eslint func-names:0*/\n\n function generateHTTPMethod(isForm) {\n return function httpMethod(url, data, config) {\n return this.request(mergeConfig(config || {}, {\n method,\n headers: isForm ? {\n 'Content-Type': 'multipart/form-data'\n } : {},\n url,\n data\n }));\n };\n }\n\n Axios.prototype[method] = generateHTTPMethod();\n\n Axios.prototype[method + 'Form'] = generateHTTPMethod(true);\n});\n\nexport default Axios;\n","'use strict';\n\nimport CanceledError from './CanceledError.js';\n\n/**\n * A `CancelToken` is an object that can be used to request cancellation of an operation.\n *\n * @param {Function} executor The executor function.\n *\n * @returns {CancelToken}\n */\nclass CancelToken {\n constructor(executor) {\n if (typeof executor !== 'function') {\n throw new TypeError('executor must be a function.');\n }\n\n let resolvePromise;\n\n this.promise = new Promise(function promiseExecutor(resolve) {\n resolvePromise = resolve;\n });\n\n const token = this;\n\n // eslint-disable-next-line func-names\n this.promise.then(cancel => {\n if (!token._listeners) return;\n\n let i = token._listeners.length;\n\n while (i-- > 0) {\n token._listeners[i](cancel);\n }\n token._listeners = null;\n });\n\n // eslint-disable-next-line func-names\n this.promise.then = onfulfilled => {\n let _resolve;\n // eslint-disable-next-line func-names\n const promise = new Promise(resolve => {\n token.subscribe(resolve);\n _resolve = resolve;\n }).then(onfulfilled);\n\n promise.cancel = function reject() {\n token.unsubscribe(_resolve);\n };\n\n return promise;\n };\n\n executor(function cancel(message, config, request) {\n if (token.reason) {\n // Cancellation has already been requested\n return;\n }\n\n token.reason = new CanceledError(message, config, request);\n resolvePromise(token.reason);\n });\n }\n\n /**\n * Throws a `CanceledError` if cancellation has been requested.\n */\n throwIfRequested() {\n if (this.reason) {\n throw this.reason;\n }\n }\n\n /**\n * Subscribe to the cancel signal\n */\n\n subscribe(listener) {\n if (this.reason) {\n listener(this.reason);\n return;\n }\n\n if (this._listeners) {\n this._listeners.push(listener);\n } else {\n this._listeners = [listener];\n }\n }\n\n /**\n * Unsubscribe from the cancel signal\n */\n\n unsubscribe(listener) {\n if (!this._listeners) {\n return;\n }\n const index = this._listeners.indexOf(listener);\n if (index !== -1) {\n this._listeners.splice(index, 1);\n }\n }\n\n /**\n * Returns an object that contains a new `CancelToken` and a function that, when called,\n * cancels the `CancelToken`.\n */\n static source() {\n let cancel;\n const token = new CancelToken(function executor(c) {\n cancel = c;\n });\n return {\n token,\n cancel\n };\n }\n}\n\nexport default CancelToken;\n","const HttpStatusCode = {\n Continue: 100,\n SwitchingProtocols: 101,\n Processing: 102,\n EarlyHints: 103,\n Ok: 200,\n Created: 201,\n Accepted: 202,\n NonAuthoritativeInformation: 203,\n NoContent: 204,\n ResetContent: 205,\n PartialContent: 206,\n MultiStatus: 207,\n AlreadyReported: 208,\n ImUsed: 226,\n MultipleChoices: 300,\n MovedPermanently: 301,\n Found: 302,\n SeeOther: 303,\n NotModified: 304,\n UseProxy: 305,\n Unused: 306,\n TemporaryRedirect: 307,\n PermanentRedirect: 308,\n BadRequest: 400,\n Unauthorized: 401,\n PaymentRequired: 402,\n Forbidden: 403,\n NotFound: 404,\n MethodNotAllowed: 405,\n NotAcceptable: 406,\n ProxyAuthenticationRequired: 407,\n RequestTimeout: 408,\n Conflict: 409,\n Gone: 410,\n LengthRequired: 411,\n PreconditionFailed: 412,\n PayloadTooLarge: 413,\n UriTooLong: 414,\n UnsupportedMediaType: 415,\n RangeNotSatisfiable: 416,\n ExpectationFailed: 417,\n ImATeapot: 418,\n MisdirectedRequest: 421,\n UnprocessableEntity: 422,\n Locked: 423,\n FailedDependency: 424,\n TooEarly: 425,\n UpgradeRequired: 426,\n PreconditionRequired: 428,\n TooManyRequests: 429,\n RequestHeaderFieldsTooLarge: 431,\n UnavailableForLegalReasons: 451,\n InternalServerError: 500,\n NotImplemented: 501,\n BadGateway: 502,\n ServiceUnavailable: 503,\n GatewayTimeout: 504,\n HttpVersionNotSupported: 505,\n VariantAlsoNegotiates: 506,\n InsufficientStorage: 507,\n LoopDetected: 508,\n NotExtended: 510,\n NetworkAuthenticationRequired: 511,\n};\n\nObject.entries(HttpStatusCode).forEach(([key, value]) => {\n HttpStatusCode[value] = key;\n});\n\nexport default HttpStatusCode;\n","'use strict';\n\nimport utils from './utils.js';\nimport bind from './helpers/bind.js';\nimport Axios from './core/Axios.js';\nimport mergeConfig from './core/mergeConfig.js';\nimport defaults from './defaults/index.js';\nimport formDataToJSON from './helpers/formDataToJSON.js';\nimport CanceledError from './cancel/CanceledError.js';\nimport CancelToken from './cancel/CancelToken.js';\nimport isCancel from './cancel/isCancel.js';\nimport {VERSION} from './env/data.js';\nimport toFormData from './helpers/toFormData.js';\nimport AxiosError from './core/AxiosError.js';\nimport spread from './helpers/spread.js';\nimport isAxiosError from './helpers/isAxiosError.js';\nimport AxiosHeaders from \"./core/AxiosHeaders.js\";\nimport adapters from './adapters/adapters.js';\nimport HttpStatusCode from './helpers/HttpStatusCode.js';\n\n/**\n * Create an instance of Axios\n *\n * @param {Object} defaultConfig The default config for the instance\n *\n * @returns {Axios} A new instance of Axios\n */\nfunction createInstance(defaultConfig) {\n const context = new Axios(defaultConfig);\n const instance = bind(Axios.prototype.request, context);\n\n // Copy axios.prototype to instance\n utils.extend(instance, Axios.prototype, context, {allOwnKeys: true});\n\n // Copy context to instance\n utils.extend(instance, context, null, {allOwnKeys: true});\n\n // Factory for creating new instances\n instance.create = function create(instanceConfig) {\n return createInstance(mergeConfig(defaultConfig, instanceConfig));\n };\n\n return instance;\n}\n\n// Create the default instance to be exported\nconst axios = createInstance(defaults);\n\n// Expose Axios class to allow class inheritance\naxios.Axios = Axios;\n\n// Expose Cancel & CancelToken\naxios.CanceledError = CanceledError;\naxios.CancelToken = CancelToken;\naxios.isCancel = isCancel;\naxios.VERSION = VERSION;\naxios.toFormData = toFormData;\n\n// Expose AxiosError class\naxios.AxiosError = AxiosError;\n\n// alias for CanceledError for backward compatibility\naxios.Cancel = axios.CanceledError;\n\n// Expose all/spread\naxios.all = function all(promises) {\n return Promise.all(promises);\n};\n\naxios.spread = spread;\n\n// Expose isAxiosError\naxios.isAxiosError = isAxiosError;\n\n// Expose mergeConfig\naxios.mergeConfig = mergeConfig;\n\naxios.AxiosHeaders = AxiosHeaders;\n\naxios.formToJSON = thing => formDataToJSON(utils.isHTMLForm(thing) ? new FormData(thing) : thing);\n\naxios.getAdapter = adapters.getAdapter;\n\naxios.HttpStatusCode = HttpStatusCode;\n\naxios.default = axios;\n\n// this module should only have a default export\nexport default axios\n","'use strict';\n\n/**\n * Syntactic sugar for invoking a function and expanding an array for arguments.\n *\n * Common use case would be to use `Function.prototype.apply`.\n *\n * ```js\n * function f(x, y, z) {}\n * var args = [1, 2, 3];\n * f.apply(null, args);\n * ```\n *\n * With `spread` this example can be re-written.\n *\n * ```js\n * spread(function(x, y, z) {})([1, 2, 3]);\n * ```\n *\n * @param {Function} callback\n *\n * @returns {Function}\n */\nexport default function spread(callback) {\n return function wrap(arr) {\n return callback.apply(null, arr);\n };\n}\n","'use strict';\n\nimport utils from './../utils.js';\n\n/**\n * Determines whether the payload is an error thrown by Axios\n *\n * @param {*} payload The value to test\n *\n * @returns {boolean} True if the payload is an error thrown by Axios, otherwise false\n */\nexport default function isAxiosError(payload) {\n return utils.isObject(payload) && (payload.isAxiosError === true);\n}\n","import GenUtils from \"./GenUtils\";\nimport LibraryUtils from \"./LibraryUtils\";\nimport ThreadPool from \"./ThreadPool\";\nimport PromiseThrottle from \"promise-throttle\";\nimport http from \"http\";\nimport https from \"https\";\nimport axios from \"axios\";\n/**\n * Handle HTTP requests with a uniform interface.\n */\nclass HttpClient {\n /**\n *

Make a HTTP request.

\n *\n * @param {object} request - configures the request to make\n * @param {string} request.method - HTTP method (\"GET\", \"PUT\", \"POST\", \"DELETE\", etc)\n * @param {string} request.uri - uri to request\n * @param {string|Uint8Array|object} request.body - request body\n * @param {string} [request.username] - username to authenticate the request (optional)\n * @param {string} [request.password] - password to authenticate the request (optional)\n * @param {object} [request.headers] - headers to add to the request (optional)\n * @param {boolean} [request.resolveWithFullResponse] - return full response if true, else body only (default false)\n * @param {boolean} [request.rejectUnauthorized] - whether or not to reject self-signed certificates (default true)\n * @param {number} request.timeout - maximum time allowed in milliseconds\n * @param {number} request.proxyToWorker - proxy request to worker thread\n * @return {object} response - the response object\n * @return {string|Uint8Array|object} response.body - the response body\n * @return {number} response.statusCode - the response code\n * @return {String} response.statusText - the response message\n * @return {object} response.headers - the response headers\n */\n static async request(request) {\n // proxy to worker if configured\n if (request.proxyToWorker) {\n try {\n return await LibraryUtils.invokeWorker(undefined, \"httpRequest\", request);\n }\n catch (err) {\n if (err.message.length > 0 && err.message.charAt(0) === \"{\") {\n let parsed = JSON.parse(err.message);\n err.message = parsed.statusMessage;\n err.statusCode = parsed.statusCode;\n }\n throw err;\n }\n }\n // assign defaults\n request = Object.assign({}, HttpClient.DEFAULT_REQUEST, request);\n // validate request\n try {\n request.host = new URL(request.uri).host;\n } // hostname:port\n catch (err) {\n throw new Error(\"Invalid request URL: \" + request.uri);\n }\n if (request.body && !(typeof request.body === \"string\" || typeof request.body === \"object\")) {\n throw new Error(\"Request body type is not string or object\");\n }\n // initialize one task queue per host\n if (!HttpClient.TASK_QUEUES[request.host])\n HttpClient.TASK_QUEUES[request.host] = new ThreadPool(1);\n // initialize one promise throttle per host\n if (!HttpClient.PROMISE_THROTTLES[request.host]) {\n HttpClient.PROMISE_THROTTLES[request.host] = new PromiseThrottle({\n requestsPerSecond: HttpClient.MAX_REQUESTS_PER_SECOND,\n promiseImplementation: Promise\n });\n }\n // request using fetch or xhr with timeout\n let timeout = request.timeout === undefined ? HttpClient.DEFAULT_TIMEOUT : request.timeout === 0 ? HttpClient.MAX_TIMEOUT : request.timeout;\n let requestPromise = HttpClient.requestAxios(request);\n return GenUtils.executeWithTimeout(requestPromise, timeout);\n }\n // ----------------------------- PRIVATE HELPERS ----------------------------\n /**\n * Get a singleton instance of an HTTP client to share.\n *\n * @return {http.Agent} a shared agent for network requests among library instances\n */\n static getHttpAgent() {\n if (!HttpClient.HTTP_AGENT)\n HttpClient.HTTP_AGENT = new http.Agent({\n keepAlive: true,\n family: 4 // use IPv4\n });\n return HttpClient.HTTP_AGENT;\n }\n /**\n * Get a singleton instance of an HTTPS client to share.\n *\n * @return {https.Agent} a shared agent for network requests among library instances\n */\n static getHttpsAgent() {\n if (!HttpClient.HTTPS_AGENT)\n HttpClient.HTTPS_AGENT = new https.Agent({\n keepAlive: true,\n family: 4 // use IPv4\n });\n return HttpClient.HTTPS_AGENT;\n }\n static async requestAxios(req) {\n if (req.headers)\n throw new Error(\"Custom headers not implemented in XHR request\"); // TODO\n // collect params from request which change on await\n const method = req.method;\n const uri = req.uri;\n const host = req.host;\n const username = req.username;\n const password = req.password;\n const body = req.body;\n const isBinary = body instanceof Uint8Array;\n // queue and throttle requests to execute in serial and rate limited per host\n const resp = await HttpClient.TASK_QUEUES[host].submit(async function () {\n return HttpClient.PROMISE_THROTTLES[host].add(function () {\n return new Promise(function (resolve, reject) {\n HttpClient.axiosDigestAuthRequest(method, uri, username, password, body).then(function (resp) {\n resolve(resp);\n }).catch(function (error) {\n if (error.response?.status)\n resolve(error.response);\n reject(new Error(\"Request failed without response: \" + method + \" \" + uri + \" due to underlying error:\\n\" + error.message + \"\\n\" + error.stack));\n });\n });\n }.bind(this));\n });\n // normalize response\n let normalizedResponse = {};\n normalizedResponse.statusCode = resp.status;\n normalizedResponse.statusText = resp.statusText;\n normalizedResponse.headers = { ...resp.headers };\n normalizedResponse.body = isBinary ? new Uint8Array(resp.data) : resp.data;\n if (normalizedResponse.body instanceof ArrayBuffer)\n normalizedResponse.body = new Uint8Array(normalizedResponse.body); // handle empty binary request\n return normalizedResponse;\n }\n}\nHttpClient.MAX_REQUESTS_PER_SECOND = 50;\n// default request config\nHttpClient.DEFAULT_REQUEST = {\n method: \"GET\",\n resolveWithFullResponse: false,\n rejectUnauthorized: true\n};\n// rate limit requests per host\nHttpClient.PROMISE_THROTTLES = [];\nHttpClient.TASK_QUEUES = [];\nHttpClient.DEFAULT_TIMEOUT = 60000;\nHttpClient.MAX_TIMEOUT = 2147483647; // max 32-bit signed number\nHttpClient.axiosDigestAuthRequest = async function (method, url, username, password, body) {\n if (typeof CryptoJS === 'undefined' && typeof require === 'function') {\n var CryptoJS = require('crypto-js');\n }\n const generateCnonce = function () {\n const characters = 'abcdef0123456789';\n let token = '';\n for (let i = 0; i < 16; i++) {\n const randNum = Math.round(Math.random() * characters.length);\n token += characters.slice(randNum, randNum + 1);\n }\n return token;\n };\n let count = 0;\n return axios.request({\n url: url,\n method: method,\n timeout: this.timeout,\n headers: {\n 'Content-Type': 'application/json'\n },\n responseType: body instanceof Uint8Array ? 'arraybuffer' : undefined,\n httpAgent: url.startsWith(\"https\") ? undefined : HttpClient.getHttpAgent(),\n httpsAgent: url.startsWith(\"https\") ? HttpClient.getHttpsAgent() : undefined,\n data: body,\n transformResponse: res => res,\n adapter: GenUtils.isDeno() ? ['fetch'] : ['http', 'xhr', 'fetch']\n }).catch(async (err) => {\n if (err.response?.status === 401) {\n let authHeader = err.response.headers['www-authenticate'].replace(/,\\sDigest.*/, \"\");\n if (!authHeader) {\n throw err;\n }\n // Digest qop=\"auth\",algorithm=MD5,realm=\"monero-rpc\",nonce=\"hBZ2rZIxElv4lqCRrUylXA==\",stale=false\n const authHeaderMap = authHeader.replace(\"Digest \", \"\").replaceAll('\"', \"\").split(\",\").reduce((prev, curr) => ({ ...prev, [curr.split(\"=\")[0]]: curr.split(\"=\").slice(1).join('=') }), {});\n ++count;\n const cnonce = generateCnonce();\n const HA1 = CryptoJS.MD5(username + ':' + authHeaderMap.realm + ':' + password).toString();\n const HA2 = CryptoJS.MD5(method + ':' + url).toString();\n const response = CryptoJS.MD5(HA1 + ':' +\n authHeaderMap.nonce + ':' +\n ('00000000' + count).slice(-8) + ':' +\n cnonce + ':' +\n authHeaderMap.qop + ':' +\n HA2).toString();\n const digestAuthHeader = 'Digest' + ' ' +\n 'username=\"' + username + '\", ' +\n 'realm=\"' + authHeaderMap.realm + '\", ' +\n 'nonce=\"' + authHeaderMap.nonce + '\", ' +\n 'uri=\"' + url + '\", ' +\n 'response=\"' + response + '\", ' +\n 'opaque=\"' + (authHeaderMap.opaque ?? null) + '\", ' +\n 'qop=' + authHeaderMap.qop + ', ' +\n 'nc=' + ('00000000' + count).slice(-8) + ', ' +\n 'cnonce=\"' + cnonce + '\"';\n const finalResponse = await axios.request({\n url: url,\n method: method,\n timeout: this.timeout,\n headers: {\n 'Authorization': digestAuthHeader,\n 'Content-Type': 'application/json'\n },\n responseType: body instanceof Uint8Array ? 'arraybuffer' : undefined,\n httpAgent: url.startsWith(\"https\") ? undefined : HttpClient.getHttpAgent(),\n httpsAgent: url.startsWith(\"https\") ? HttpClient.getHttpsAgent() : undefined,\n data: body,\n transformResponse: res => res,\n adapter: GenUtils.isDeno() ? ['fetch'] : ['http', 'xhr', 'fetch']\n });\n return finalResponse;\n }\n throw err;\n }).catch(err => {\n throw err;\n });\n};\nexport default HttpClient;\n","/**\n * Monero banhammer.\n */\nexport default class MoneroBan {\n constructor(ban) {\n Object.assign(this, ban);\n }\n toJson() {\n return Object.assign({}, this);\n }\n getHost() {\n return this.host;\n }\n setHost(host) {\n this.host = host;\n return this;\n }\n getIp() {\n return this.ip;\n }\n setIp(ip) {\n this.ip = ip;\n return this;\n }\n getIsBanned() {\n return this.isBanned;\n }\n setIsBanned(isBanned) {\n this.isBanned = isBanned;\n return this;\n }\n getSeconds() {\n return this.seconds;\n }\n setSeconds(seconds) {\n this.seconds = seconds;\n return this;\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"../../common/GenUtils\";\n/**\n * Models a Monero block header which contains information about the block.\n */\nexport default class MoneroBlockHeader {\n constructor(header) {\n Object.assign(this, header);\n // deserialize bigints\n if (this.difficulty !== undefined && typeof this.difficulty !== \"bigint\")\n this.difficulty = BigInt(this.difficulty);\n if (this.cumulativeDifficulty !== undefined && typeof this.cumulativeDifficulty !== \"bigint\")\n this.cumulativeDifficulty = BigInt(this.cumulativeDifficulty);\n if (this.reward !== undefined && typeof this.reward !== \"bigint\")\n this.reward = BigInt(this.reward);\n }\n copy() {\n return new MoneroBlockHeader(this);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (this.getDifficulty() !== undefined)\n json.difficulty = this.getDifficulty().toString();\n if (this.getCumulativeDifficulty() !== undefined)\n json.cumulativeDifficulty = this.getCumulativeDifficulty().toString();\n if (this.getReward() !== undefined)\n json.reward = this.getReward().toString();\n return json;\n }\n getHash() {\n return this.hash;\n }\n setHash(hash) {\n this.hash = hash;\n return this;\n }\n /**\n * Return the block's height which is the total number of blocks that have occurred before.\n *\n * @return {number} the block's height\n */\n getHeight() {\n return this.height;\n }\n /**\n * Set the block's height which is the total number of blocks that have occurred before.\n *\n * @param {number} height is the block's height to set\n * @return {MoneroBlockHeader} a reference to this header for chaining\n */\n setHeight(height) {\n this.height = height;\n return this;\n }\n getTimestamp() {\n return this.timestamp;\n }\n setTimestamp(timestamp) {\n this.timestamp = timestamp;\n return this;\n }\n getSize() {\n return this.size;\n }\n setSize(size) {\n this.size = size;\n return this;\n }\n getWeight() {\n return this.weight;\n }\n setWeight(weight) {\n this.weight = weight;\n return this;\n }\n getLongTermWeight() {\n return this.longTermWeight;\n }\n setLongTermWeight(longTermWeight) {\n this.longTermWeight = longTermWeight;\n return this;\n }\n getDepth() {\n return this.depth;\n }\n setDepth(depth) {\n this.depth = depth;\n return this;\n }\n getDifficulty() {\n return this.difficulty;\n }\n setDifficulty(difficulty) {\n this.difficulty = difficulty;\n return this;\n }\n getCumulativeDifficulty() {\n return this.cumulativeDifficulty;\n }\n setCumulativeDifficulty(cumulativeDifficulty) {\n this.cumulativeDifficulty = cumulativeDifficulty;\n return this;\n }\n getMajorVersion() {\n return this.majorVersion;\n }\n setMajorVersion(majorVersion) {\n this.majorVersion = majorVersion;\n return this;\n }\n getMinorVersion() {\n return this.minorVersion;\n }\n setMinorVersion(minorVersion) {\n this.minorVersion = minorVersion;\n return this;\n }\n getNonce() {\n return this.nonce;\n }\n setNonce(nonce) {\n this.nonce = nonce;\n return this;\n }\n getMinerTxHash() {\n return this.minerTxHash;\n }\n setMinerTxHash(minerTxHash) {\n this.minerTxHash = minerTxHash;\n return this;\n }\n getNumTxs() {\n return this.numTxs;\n }\n setNumTxs(numTxs) {\n this.numTxs = numTxs;\n return this;\n }\n getOrphanStatus() {\n return this.orphanStatus;\n }\n setOrphanStatus(orphanStatus) {\n this.orphanStatus = orphanStatus;\n return this;\n }\n getPrevHash() {\n return this.prevHash;\n }\n setPrevHash(prevHash) {\n this.prevHash = prevHash;\n return this;\n }\n getReward() {\n return this.reward;\n }\n setReward(reward) {\n this.reward = reward;\n return this;\n }\n getPowHash() {\n return this.powHash;\n }\n setPowHash(powHash) {\n this.powHash = powHash;\n return this;\n }\n merge(header) {\n assert(header instanceof MoneroBlockHeader);\n if (this === header)\n return this;\n this.setHash(GenUtils.reconcile(this.getHash(), header.getHash()));\n this.setHeight(GenUtils.reconcile(this.getHeight(), header.getHeight(), { resolveMax: true })); // height can increase\n this.setTimestamp(GenUtils.reconcile(this.getTimestamp(), header.getTimestamp(), { resolveMax: true })); // block timestamp can increase\n this.setSize(GenUtils.reconcile(this.getSize(), header.getSize()));\n this.setWeight(GenUtils.reconcile(this.getWeight(), header.getWeight()));\n this.setDepth(GenUtils.reconcile(this.getDepth(), header.getDepth()));\n this.setDifficulty(GenUtils.reconcile(this.getDifficulty(), header.getDifficulty()));\n this.setCumulativeDifficulty(GenUtils.reconcile(this.getCumulativeDifficulty(), header.getCumulativeDifficulty()));\n this.setMajorVersion(GenUtils.reconcile(this.getMajorVersion(), header.getMajorVersion()));\n this.setMinorVersion(GenUtils.reconcile(this.getMinorVersion(), header.getMinorVersion()));\n this.setNonce(GenUtils.reconcile(this.getNonce(), header.getNonce()));\n this.setMinerTxHash(GenUtils.reconcile(this.getMinerTxHash(), header.getMinerTxHash()));\n this.setNumTxs(GenUtils.reconcile(this.getNumTxs(), header.getNumTxs()));\n this.setOrphanStatus(GenUtils.reconcile(this.getOrphanStatus(), header.getOrphanStatus()));\n this.setPrevHash(GenUtils.reconcile(this.getPrevHash(), header.getPrevHash()));\n this.setReward(GenUtils.reconcile(this.getReward(), header.getReward()));\n this.setPowHash(GenUtils.reconcile(this.getPowHash(), header.getPowHash()));\n return this;\n }\n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.kvLine(\"Hash\", this.getHash(), indent);\n str += GenUtils.kvLine(\"Height\", this.getHeight(), indent);\n str += GenUtils.kvLine(\"Timestamp\", this.getTimestamp(), indent);\n str += GenUtils.kvLine(\"Size\", this.getSize(), indent);\n str += GenUtils.kvLine(\"Weight\", this.getWeight(), indent);\n str += GenUtils.kvLine(\"Depth\", this.getDepth(), indent);\n str += GenUtils.kvLine(\"Difficulty\", this.getDifficulty(), indent);\n str += GenUtils.kvLine(\"Cumulative difficulty\", this.getCumulativeDifficulty(), indent);\n str += GenUtils.kvLine(\"Major version\", this.getMajorVersion(), indent);\n str += GenUtils.kvLine(\"Minor version\", this.getMinorVersion(), indent);\n str += GenUtils.kvLine(\"Nonce\", this.getNonce(), indent);\n str += GenUtils.kvLine(\"Miner tx hash\", this.getMinerTxHash(), indent);\n str += GenUtils.kvLine(\"Num txs\", this.getNumTxs(), indent);\n str += GenUtils.kvLine(\"Orphan status\", this.getOrphanStatus(), indent);\n str += GenUtils.kvLine(\"Prev hash\", this.getPrevHash(), indent);\n str += GenUtils.kvLine(\"Reward\", this.getReward(), indent);\n str += GenUtils.kvLine(\"Pow hash\", this.getPowHash(), indent);\n return str[str.length - 1] === \"\\n\" ? str.slice(0, str.length - 1) : str; // strip last newline\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"../../common/GenUtils\";\n/**\n * Models a Monero key image.\n */\nexport default class MoneroKeyImage {\n /**\n * Construct the model.\n *\n * @param {string|Partial} [keyImageOrHex] is a MoneroKeyImage or hex string to initialize from (optional)\n * @param {string} [signature] is the key image's signature\n */\n constructor(hexOrKeyImage, signature) {\n if (typeof hexOrKeyImage === \"string\") {\n this.setHex(hexOrKeyImage);\n this.setSignature(signature);\n }\n else {\n Object.assign(this, hexOrKeyImage);\n }\n }\n getHex() {\n return this.hex;\n }\n setHex(hex) {\n this.hex = hex;\n return this;\n }\n getSignature() {\n return this.signature;\n }\n setSignature(signature) {\n this.signature = signature;\n return this;\n }\n copy() {\n return new MoneroKeyImage(this);\n }\n toJson() {\n return Object.assign({}, this);\n }\n merge(keyImage) {\n assert(keyImage instanceof MoneroKeyImage);\n if (keyImage === this)\n return this;\n this.setHex(GenUtils.reconcile(this.getHex(), keyImage.getHex()));\n this.setSignature(GenUtils.reconcile(this.getSignature(), keyImage.getSignature()));\n return this;\n }\n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.kvLine(\"Hex\", this.getHex(), indent);\n str += GenUtils.kvLine(\"Signature\", this.getSignature(), indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"../../common/GenUtils\";\nimport MoneroKeyImage from \"./MoneroKeyImage\";\n/**\n * Models a Monero transaction output.\n */\nexport default class MoneroOutput {\n /**\n * Construct the model.\n *\n * @param {MoneroOutput} [output] is existing state to initialize from (optional)\n */\n constructor(output) {\n Object.assign(this, output);\n // deserialize fields if necessary\n if (this.amount !== undefined && typeof this.amount !== \"bigint\")\n this.amount = BigInt(this.amount);\n if (this.keyImage)\n this.keyImage = this.keyImage instanceof MoneroKeyImage ? this.keyImage.copy() : new MoneroKeyImage(this.keyImage);\n }\n getTx() {\n return this.tx;\n }\n setTx(tx) {\n this.tx = tx;\n return this;\n }\n getKeyImage() {\n return this.keyImage;\n }\n setKeyImage(keyImage) {\n this.keyImage = keyImage === undefined ? undefined : keyImage instanceof MoneroKeyImage ? keyImage : new MoneroKeyImage(keyImage);\n return this;\n }\n getAmount() {\n return this.amount;\n }\n setAmount(amount) {\n this.amount = amount;\n return this;\n }\n getIndex() {\n return this.index;\n }\n setIndex(index) {\n this.index = index;\n return this;\n }\n getRingOutputIndices() {\n return this.ringOutputIndices;\n }\n setRingOutputIndices(ringOutputIndices) {\n this.ringOutputIndices = ringOutputIndices;\n return this;\n }\n getStealthPublicKey() {\n return this.stealthPublicKey;\n }\n setStealthPublicKey(stealthPublicKey) {\n this.stealthPublicKey = stealthPublicKey;\n return this;\n }\n copy() {\n return new MoneroOutput(this);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (this.getAmount() !== undefined)\n json.amount = this.getAmount().toString();\n if (this.getKeyImage() !== undefined)\n json.keyImage = this.getKeyImage() ? this.getKeyImage().toJson() : undefined;\n delete json.tx;\n return json;\n }\n merge(output) {\n assert(output instanceof MoneroOutput);\n if (this === output)\n return this;\n // merge txs if they're different which comes back to merging outputs\n if (this.getTx() !== output.getTx())\n this.getTx().merge(output.getTx());\n // otherwise merge output fields\n else {\n if (this.getKeyImage() === undefined)\n this.setKeyImage(output.getKeyImage());\n else if (output.getKeyImage() !== undefined)\n this.getKeyImage().merge(output.getKeyImage());\n this.setAmount(GenUtils.reconcile(this.getAmount(), output.getAmount()));\n this.setIndex(GenUtils.reconcile(this.getIndex(), output.getIndex()));\n }\n return this;\n }\n toString(indent = 0) {\n let str = \"\";\n if (this.getKeyImage() !== undefined) {\n str += GenUtils.kvLine(\"Key image\", \"\", indent);\n str += this.getKeyImage().toString(indent + 1) + \"\\n\";\n }\n str += GenUtils.kvLine(\"Amount\", this.getAmount(), indent);\n str += GenUtils.kvLine(\"Index\", this.getIndex(), indent);\n str += GenUtils.kvLine(\"Ring output indices\", this.getRingOutputIndices(), indent);\n str += GenUtils.kvLine(\"Stealth public key\", this.getStealthPublicKey(), indent);\n return str === \"\" ? str : str.slice(0, str.length - 1); // strip last newline\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"../../common/GenUtils\";\nimport MoneroOutput from \"./MoneroOutput\";\n/**\n * Represents a transaction on the Monero network.\n */\nclass MoneroTx {\n constructor(tx) {\n Object.assign(this, tx);\n this.block = undefined;\n // deserialize extra\n if (this.extra !== undefined)\n this.extra = new Uint8Array(this.extra);\n // deserialize bigints\n if (this.fee !== undefined && typeof this.fee !== \"bigint\")\n this.fee = BigInt(this.fee);\n if (this.unlockTime !== undefined && typeof this.unlockTime !== \"bigint\")\n this.unlockTime = BigInt(this.unlockTime);\n // copy inputs\n if (this.inputs) {\n this.inputs = this.inputs.slice();\n for (let i = 0; i < this.inputs.length; i++) {\n this.inputs[i] = new MoneroOutput(this.inputs[i]).setTx(this);\n }\n }\n // copy outputs\n if (this.outputs) {\n this.outputs = this.outputs.slice();\n for (let i = 0; i < this.outputs.length; i++) {\n this.outputs[i] = new MoneroOutput(this.outputs[i]).setTx(this);\n }\n }\n }\n /**\n * @return {MoneroBlock} tx block\n */\n getBlock() {\n return this.block;\n }\n /**\n * @param {MoneroBlock} block - tx block\n * @return {MoneroTx} this tx for chaining\n */\n setBlock(block) {\n this.block = block;\n return this;\n }\n /**\n * @return {number} tx height\n */\n getHeight() {\n return this.getBlock() === undefined ? undefined : this.getBlock().getHeight();\n }\n /**\n * @return {string} tx hash\n */\n getHash() {\n return this.hash;\n }\n /**\n * @param {string} hash - tx hash\n * @return {MoneroTx} this tx for chaining\n */\n setHash(hash) {\n this.hash = hash;\n return this;\n }\n /**\n * @return {number} tx version\n */\n getVersion() {\n return this.version;\n }\n /**\n * @param {number} version - tx version\n * @return {MoneroTx} this tx for chaining\n */\n setVersion(version) {\n this.version = version;\n return this;\n }\n /**\n * @return {boolean} true if the tx is a miner tx, false otherwise\n */\n getIsMinerTx() {\n return this.isMinerTx;\n }\n /**\n * @param {boolean} miner - true if the tx is a miner tx, false otherwise\n * @return {MoneroTx} this tx for chaining\n */\n setIsMinerTx(miner) {\n this.isMinerTx = miner;\n return this;\n }\n /**\n * @return {string} tx payment id\n */\n getPaymentId() {\n return this.paymentId;\n }\n /**\n * @param {string} paymentId - tx payment id\n * @return {MoneroTx} this tx for chaining\n */\n setPaymentId(paymentId) {\n this.paymentId = paymentId;\n return this;\n }\n /**\n * @return {bigint} tx fee\n */\n getFee() {\n return this.fee;\n }\n /**\n * @param {bigint} fee - tx fee\n * @return {MoneroTx} this tx for chaining\n */\n setFee(fee) {\n this.fee = fee;\n return this;\n }\n /**\n * @return {number} tx ring size\n */\n getRingSize() {\n return this.ringSize;\n }\n /**\n * @param {number} ringSize - tx ring size\n * @return {MoneroTx} this tx for chaining\n */\n setRingSize(ringSize) {\n this.ringSize = ringSize;\n return this;\n }\n /**\n * @return {boolean} true if the tx is set to be relayed, false otherwise\n */\n getRelay() {\n return this.relay;\n }\n /**\n * @param {boolean} relay - true if the tx is set to be relayed, false otherwise\n * @return {MoneroTx} this tx for chaining\n */\n setRelay(relay) {\n this.relay = relay;\n return this;\n }\n /**\n * @return {boolean} true if the tx is relayed, false otherwise\n */\n getIsRelayed() {\n return this.isRelayed;\n }\n /**\n * @param {boolean} isRelayed - true if the tx is relayed, false otherwise\n * @return {MoneroTx} this tx for chaining\n */\n setIsRelayed(isRelayed) {\n this.isRelayed = isRelayed;\n return this;\n }\n /**\n * @return {boolean} true if the tx is confirmed, false otherwise\n */\n getIsConfirmed() {\n return this.isConfirmed;\n }\n /**\n * @param {boolean} isConfirmed - true if the tx is confirmed, false otherwise\n * @return {MoneroTx} this tx for chaining\n */\n setIsConfirmed(isConfirmed) {\n this.isConfirmed = isConfirmed;\n return this;\n }\n /**\n * @return {boolean} true if the tx is in the memory pool, false otherwise\n */\n getInTxPool() {\n return this.inTxPool;\n }\n /**\n * @param {boolean} inTxPool - true if the tx is in the memory pool, false otherwise\n * @return {MoneroTx} this tx for chaining\n */\n setInTxPool(inTxPool) {\n this.inTxPool = inTxPool;\n return this;\n }\n /**\n * @return {number} number of block confirmations\n */\n getNumConfirmations() {\n return this.numConfirmations;\n }\n /**\n * @param {number} numConfirmations - number of block confirmations\n * @return {MoneroTx} this tx for chaining\n */\n setNumConfirmations(numConfirmations) {\n this.numConfirmations = numConfirmations;\n return this;\n }\n /**\n * Get the minimum height or timestamp for the transactions to unlock.\n *\n * @return {bigint} the minimum height or timestamp for the transaction to unlock\n */\n getUnlockTime() {\n return this.unlockTime;\n }\n setUnlockTime(unlockTime) {\n if (unlockTime !== undefined && typeof unlockTime !== \"bigint\")\n unlockTime = BigInt(unlockTime);\n this.unlockTime = unlockTime;\n return this;\n }\n /**\n * @return {number} timestamp the tx was last relayed from the node\n */\n getLastRelayedTimestamp() {\n return this.lastRelayedTimestamp;\n }\n /**\n * @param {number} lastRelayedTimestamp - timestamp the tx was last relayed from the node\n * @return {MoneroTx} this tx for chaining\n */\n setLastRelayedTimestamp(lastRelayedTimestamp) {\n this.lastRelayedTimestamp = lastRelayedTimestamp;\n return this;\n }\n /**\n * @return {number} timestamp the tx was received at the node\n */\n getReceivedTimestamp() {\n return this.receivedTimestamp;\n }\n /**\n * @param {number} receivedTimestamp - timestamp the tx was received at the node\n * @return {MoneroTx} this tx for chaining\n */\n setReceivedTimestamp(receivedTimestamp) {\n this.receivedTimestamp = receivedTimestamp;\n return this;\n }\n /**\n * @return {boolean} true if a double spend has been seen, false otherwise\n */\n getIsDoubleSpendSeen() {\n return this.isDoubleSpendSeen;\n }\n /**\n * @param {boolean} isDoubleSpendSeen - true if a double spend has been seen, false otherwise\n * @return {MoneroTx} this tx for chaining\n */\n setIsDoubleSpendSeen(isDoubleSpendSeen) {\n this.isDoubleSpendSeen = isDoubleSpendSeen;\n return this;\n }\n /**\n * @return {string} tx key\n */\n getKey() {\n return this.key;\n }\n /**\n * @param {string} key - tx key\n * @return {MoneroTx} this tx for chaining\n */\n setKey(key) {\n this.key = key;\n return this;\n }\n /**\n * Get full transaction hex. Full hex = pruned hex + prunable hex.\n *\n * @return {string|undefined} full tx hex\n */\n getFullHex() {\n return this.fullHex;\n }\n /**\n * @param {string} fullHex - full tx hex\n * @return {MoneroTx} this tx for chaining\n */\n setFullHex(fullHex) {\n this.fullHex = fullHex;\n return this;\n }\n /**\n * Get pruned transaction hex. Full hex = pruned hex + prunable hex.\n *\n * @return {string} pruned tx hex\n */\n getPrunedHex() {\n return this.prunedHex;\n }\n /**\n * @param {string} prunedHex - pruned tx hex\n * @return {MoneroTx} this tx for chaining\n */\n setPrunedHex(prunedHex) {\n this.prunedHex = prunedHex;\n return this;\n }\n /**\n * Get prunable transaction hex which is hex that is removed from a pruned\n * transaction. Full hex = pruned hex + prunable hex.\n *\n * @return {string} prunable tx hex\n */\n getPrunableHex() {\n return this.prunableHex;\n }\n /**\n * @param {string} prunableHex - prunable tx hex\n * @return {MoneroTx} this tx for chaining\n */\n setPrunableHex(prunableHex) {\n this.prunableHex = prunableHex;\n return this;\n }\n /**\n * @return {string} prunable tx hash\n */\n getPrunableHash() {\n return this.prunableHash;\n }\n /**\n * @param {string} prunableHash - prunable tx hash\n * @return {MoneroTx} this tx for chaining\n */\n setPrunableHash(prunableHash) {\n this.prunableHash = prunableHash;\n return this;\n }\n /**\n * @return {number} tx size\n */\n getSize() {\n return this.size;\n }\n /**\n * @param {number} size - tx size\n * @return {MoneroTx} this tx for chaining\n */\n setSize(size) {\n this.size = size;\n return this;\n }\n /**\n * @return {number} tx weight\n */\n getWeight() {\n return this.weight;\n }\n /**\n * @param {number} weight - tx weight\n * @return {MoneroTx} this tx for chaining\n */\n setWeight(weight) {\n this.weight = weight;\n return this;\n }\n /**\n * @return {MoneroOutput[]} tx inputs\n */\n getInputs() {\n return this.inputs;\n }\n /**\n * @param {MoneroOutput[]} - tx inputs\n * @return {MoneroTx} this tx for chaining\n */\n setInputs(inputs) {\n this.inputs = inputs;\n return this;\n }\n /**\n * @return {MoneroOutput[]} tx outputs\n */\n getOutputs() {\n return this.outputs;\n }\n /**\n * @param {MoneroOutput[]} outputs - tx outputs\n * @return {MoneroTx} this tx for chaining\n */\n setOutputs(outputs) {\n this.outputs = outputs;\n return this;\n }\n /**\n * @return {number[]} tx output indices\n */\n getOutputIndices() {\n return this.outputIndices;\n }\n /**\n * @param {number[]} outputIndices - tx output indices\n * @return {MoneroTx} this tx for chaining\n */\n setOutputIndices(outputIndices) {\n this.outputIndices = outputIndices;\n return this;\n }\n /**\n * @return {string} tx metadata\n */\n getMetadata() {\n return this.metadata;\n }\n /**\n * @param {string} metadata - tx metadata\n * @return {MoneroTx} this tx for chaining\n */\n setMetadata(metadata) {\n this.metadata = metadata;\n return this;\n }\n /**\n * @return {Uint8Array} tx extra\n */\n getExtra() {\n return this.extra;\n }\n /**\n * @param {Uint8Array} extra - tx extra\n * @return {MoneroTx} this tx for chaining\n */\n setExtra(extra) {\n this.extra = extra;\n return this;\n }\n /**\n * @return {any} RCT signatures\n */\n getRctSignatures() {\n return this.rctSignatures;\n }\n /**\n * @param {any} rctSignatures - RCT signatures\n * @return {MoneroTx} this tx for chaining\n */\n setRctSignatures(rctSignatures) {\n this.rctSignatures = rctSignatures;\n return this;\n }\n /**\n * @return {any} prunable RCT signature data\n */\n getRctSigPrunable() {\n return this.rctSigPrunable;\n }\n /**\n * @param {any} rctSigPrunable - prunable RCT signature data\n * @return {MoneroTx} this tx for chaining\n */\n setRctSigPrunable(rctSigPrunable) {\n this.rctSigPrunable = rctSigPrunable;\n return this;\n }\n /**\n * @return {boolean} true if kept by a block, false otherwise\n */\n getIsKeptByBlock() {\n return this.isKeptByBlock;\n }\n /**\n * @param {boolean} isKeptByBlock - true if kept by a block, false otherwise\n * @return {MoneroTx} this tx for chaining\n */\n setIsKeptByBlock(isKeptByBlock) {\n this.isKeptByBlock = isKeptByBlock;\n return this;\n }\n /**\n * @return {boolean} true if the tx failed, false otherwise\n */\n getIsFailed() {\n return this.isFailed;\n }\n /**\n * @param {boolean} isFailed - true if the tx failed, false otherwise\n * @return {MoneroTx} this tx for chaining\n */\n setIsFailed(isFailed) {\n this.isFailed = isFailed;\n return this;\n }\n /**\n * @return {number} block height of the last tx failure\n */\n getLastFailedHeight() {\n return this.lastFailedHeight;\n }\n /**\n * @param {number} lastFailedHeight - block height of the last tx failure\n * @return {MoneroTx} this tx for chaining\n */\n setLastFailedHeight(lastFailedHeight) {\n this.lastFailedHeight = lastFailedHeight;\n return this;\n }\n /**\n * @return {string} block hash of the last tx failure\n */\n getLastFailedHash() {\n return this.lastFailedHash;\n }\n /**\n * @param {string} lastFailedHash - block hash of the last tx failure\n * @return {MoneroTx} this tx for chaining\n */\n setLastFailedHash(lastFailedHash) {\n this.lastFailedHash = lastFailedHash;\n return this;\n }\n /**\n * @return {number} max used block height\n */\n getMaxUsedBlockHeight() {\n return this.maxUsedBlockHeight;\n }\n /**\n * @param {number} maxUsedBlockHeight - max used block height\n * @return {MoneroTx} this tx for chaining\n */\n setMaxUsedBlockHeight(maxUsedBlockHeight) {\n this.maxUsedBlockHeight = maxUsedBlockHeight;\n return this;\n }\n /**\n * @return {string} max used block hash\n */\n getMaxUsedBlockHash() {\n return this.maxUsedBlockHash;\n }\n /**\n * @param {string} maxUsedBlockHash - max used block hash\n * @return {MoneroTx} this tx for chaining\n */\n setMaxUsedBlockHash(maxUsedBlockHash) {\n this.maxUsedBlockHash = maxUsedBlockHash;\n return this;\n }\n /**\n * @return {string[]} tx signatures\n */\n getSignatures() {\n return this.signatures;\n }\n /**\n * @param {string[]} signatures - tx signatures\n * @return {MoneroTx} this tx for chaining\n */\n setSignatures(signatures) {\n this.signatures = signatures;\n return this;\n }\n /**\n * @return {MoneroTx} a copy of this tx\n */\n copy() {\n return new MoneroTx(this);\n }\n /**\n * @return {any} json representation of this tx\n */\n toJson() {\n let json = Object.assign({}, this);\n if (this.getFee() !== undefined)\n json.fee = this.getFee().toString();\n if (this.getUnlockTime() !== undefined)\n json.unlockTime = this.getUnlockTime().toString();\n if (this.getInputs()) {\n json.inputs = [];\n for (let input of this.getInputs())\n json.inputs.push(input.toJson());\n }\n if (this.getOutputs()) {\n json.outputs = [];\n for (let output of this.getOutputs())\n json.outputs.push(output.toJson());\n }\n if (this.getExtra() !== undefined)\n json.extra = Array.from(this.getExtra(), byte => byte);\n delete json.block; // do not serialize parent block\n return json;\n }\n /**\n * Updates this transaction by merging the latest information from the given\n * transaction.\n *\n * @param {MoneroTx} tx - the transaction to update this transaction with\n * @return {MoneroTx} this for method chaining\n */\n merge(tx) {\n assert(tx instanceof MoneroTx);\n if (this === tx)\n return this;\n // merge blocks if they're different\n if (this.getBlock() !== tx.getBlock()) {\n if (this.getBlock() === undefined) {\n this.setBlock(tx.getBlock());\n this.getBlock().getTxs[this.getBlock().getTxs().indexOf(tx)] = this; // update block to point to this tx\n }\n else if (tx.getBlock() !== undefined) {\n this.getBlock().merge(tx.getBlock()); // comes back to merging txs\n return this;\n }\n }\n // otherwise merge tx fields\n this.setHash(GenUtils.reconcile(this.getHash(), tx.getHash()));\n this.setVersion(GenUtils.reconcile(this.getVersion(), tx.getVersion()));\n this.setPaymentId(GenUtils.reconcile(this.getPaymentId(), tx.getPaymentId()));\n this.setFee(GenUtils.reconcile(this.getFee(), tx.getFee()));\n this.setRingSize(GenUtils.reconcile(this.getRingSize(), tx.getRingSize()));\n this.setIsConfirmed(GenUtils.reconcile(this.getIsConfirmed(), tx.getIsConfirmed(), { resolveTrue: true })); // tx can become confirmed\n this.setIsMinerTx(GenUtils.reconcile(this.getIsMinerTx(), tx.getIsMinerTx()));\n this.setRelay(GenUtils.reconcile(this.getRelay(), tx.getRelay(), { resolveTrue: true })); // tx can become relayed\n this.setIsRelayed(GenUtils.reconcile(this.getIsRelayed(), tx.getIsRelayed(), { resolveTrue: true })); // tx can become relayed\n this.setIsDoubleSpendSeen(GenUtils.reconcile(this.getIsDoubleSpendSeen(), tx.getIsDoubleSpendSeen(), { resolveTrue: true })); // double spend can become seen\n this.setKey(GenUtils.reconcile(this.getKey(), tx.getKey()));\n this.setFullHex(GenUtils.reconcile(this.getFullHex(), tx.getFullHex()));\n this.setPrunedHex(GenUtils.reconcile(this.getPrunedHex(), tx.getPrunedHex()));\n this.setPrunableHex(GenUtils.reconcile(this.getPrunableHex(), tx.getPrunableHex()));\n this.setPrunableHash(GenUtils.reconcile(this.getPrunableHash(), tx.getPrunableHash()));\n this.setSize(GenUtils.reconcile(this.getSize(), tx.getSize()));\n this.setWeight(GenUtils.reconcile(this.getWeight(), tx.getWeight()));\n this.setOutputIndices(GenUtils.reconcile(this.getOutputIndices(), tx.getOutputIndices()));\n this.setMetadata(GenUtils.reconcile(this.getMetadata(), tx.getMetadata()));\n this.setExtra(GenUtils.reconcile(this.getExtra(), tx.getExtra()));\n this.setRctSignatures(GenUtils.reconcile(this.getRctSignatures(), tx.getRctSignatures()));\n this.setRctSigPrunable(GenUtils.reconcile(this.getRctSigPrunable(), tx.getRctSigPrunable()));\n this.setIsKeptByBlock(GenUtils.reconcile(this.getIsKeptByBlock(), tx.getIsKeptByBlock()));\n this.setIsFailed(GenUtils.reconcile(this.getIsFailed(), tx.getIsFailed(), { resolveTrue: true }));\n this.setLastFailedHeight(GenUtils.reconcile(this.getLastFailedHeight(), tx.getLastFailedHeight()));\n this.setLastFailedHash(GenUtils.reconcile(this.getLastFailedHash(), tx.getLastFailedHash()));\n this.setMaxUsedBlockHeight(GenUtils.reconcile(this.getMaxUsedBlockHeight(), tx.getMaxUsedBlockHeight()));\n this.setMaxUsedBlockHash(GenUtils.reconcile(this.getMaxUsedBlockHash(), tx.getMaxUsedBlockHash()));\n this.setSignatures(GenUtils.reconcile(this.getSignatures(), tx.getSignatures()));\n this.setUnlockTime(GenUtils.reconcile(this.getUnlockTime(), tx.getUnlockTime()));\n this.setNumConfirmations(GenUtils.reconcile(this.getNumConfirmations(), tx.getNumConfirmations(), { resolveMax: true })); // num confirmations can increase\n // merge inputs\n if (tx.getInputs()) {\n for (let merger of tx.getInputs()) {\n let merged = false;\n merger.setTx(this);\n if (!this.getInputs())\n this.setInputs([]);\n for (let mergee of this.getInputs()) {\n if (mergee.getKeyImage().getHex() === merger.getKeyImage().getHex()) {\n mergee.merge(merger);\n merged = true;\n break;\n }\n }\n if (!merged)\n this.getInputs().push(merger);\n }\n }\n // merge outputs\n if (tx.getOutputs()) {\n for (let output of tx.getOutputs())\n output.setTx(this);\n if (!this.getOutputs())\n this.setOutputs(tx.getOutputs());\n else {\n // merge outputs if key image or stealth public key present, otherwise append\n for (let merger of tx.getOutputs()) {\n let merged = false;\n merger.setTx(this);\n for (let mergee of this.getOutputs()) {\n if ((merger.getKeyImage() && mergee.getKeyImage().getHex() === merger.getKeyImage().getHex()) ||\n (merger.getStealthPublicKey() && mergee.getStealthPublicKey() === merger.getStealthPublicKey())) {\n mergee.merge(merger);\n merged = true;\n break;\n }\n }\n if (!merged)\n this.getOutputs().push(merger); // append output\n }\n }\n }\n // handle unrelayed -> relayed -> confirmed\n if (this.getIsConfirmed()) {\n this.setInTxPool(false);\n this.setReceivedTimestamp(undefined);\n this.setLastRelayedTimestamp(undefined);\n }\n else {\n this.setInTxPool(GenUtils.reconcile(this.getInTxPool(), tx.getInTxPool(), { resolveTrue: true })); // unrelayed -> tx pool\n this.setReceivedTimestamp(GenUtils.reconcile(this.getReceivedTimestamp(), tx.getReceivedTimestamp(), { resolveMax: false })); // take earliest receive time\n this.setLastRelayedTimestamp(GenUtils.reconcile(this.getLastRelayedTimestamp(), tx.getLastRelayedTimestamp(), { resolveMax: true })); // take latest relay time\n }\n return this; // for chaining\n }\n /**\n * @param {number} [indent] - starting indentation\n * @return {string} string representation of this tx\n */\n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.getIndent(indent) + \"=== TX ===\\n\";\n str += GenUtils.kvLine(\"Tx hash\", this.getHash(), indent);\n str += GenUtils.kvLine(\"Height\", this.getHeight(), indent);\n str += GenUtils.kvLine(\"Version\", this.getVersion(), indent);\n str += GenUtils.kvLine(\"Is miner tx\", this.getIsMinerTx(), indent);\n str += GenUtils.kvLine(\"Payment ID\", this.getPaymentId(), indent);\n str += GenUtils.kvLine(\"Fee\", this.getFee(), indent);\n str += GenUtils.kvLine(\"Ring size\", this.getRingSize(), indent);\n str += GenUtils.kvLine(\"Relay\", this.getRelay(), indent);\n str += GenUtils.kvLine(\"Is relayed\", this.getIsRelayed(), indent);\n str += GenUtils.kvLine(\"Is confirmed\", this.getIsConfirmed(), indent);\n str += GenUtils.kvLine(\"In tx pool\", this.getInTxPool(), indent);\n str += GenUtils.kvLine(\"Num confirmations\", this.getNumConfirmations(), indent);\n str += GenUtils.kvLine(\"Unlock time\", this.getUnlockTime(), indent);\n str += GenUtils.kvLine(\"Last relayed time\", this.getLastRelayedTimestamp(), indent);\n str += GenUtils.kvLine(\"Received time\", this.getReceivedTimestamp(), indent);\n str += GenUtils.kvLine(\"Is double spend\", this.getIsDoubleSpendSeen(), indent);\n str += GenUtils.kvLine(\"Key\", this.getKey(), indent);\n str += GenUtils.kvLine(\"Full hex\", this.getFullHex(), indent);\n str += GenUtils.kvLine(\"Pruned hex\", this.getPrunedHex(), indent);\n str += GenUtils.kvLine(\"Prunable hex\", this.getPrunableHex(), indent);\n str += GenUtils.kvLine(\"Prunable hash\", this.getPrunableHash(), indent);\n str += GenUtils.kvLine(\"Size\", this.getSize(), indent);\n str += GenUtils.kvLine(\"Weight\", this.getWeight(), indent);\n str += GenUtils.kvLine(\"Output indices\", this.getOutputIndices(), indent);\n str += GenUtils.kvLine(\"Metadata\", this.getMetadata(), indent);\n str += GenUtils.kvLine(\"Extra\", this.getExtra(), indent);\n str += GenUtils.kvLine(\"RCT signatures\", this.getRctSignatures(), indent);\n str += GenUtils.kvLine(\"RCT sig prunable\", this.getRctSigPrunable(), indent);\n str += GenUtils.kvLine(\"Kept by block\", this.getIsKeptByBlock(), indent);\n str += GenUtils.kvLine(\"Is failed\", this.getIsFailed(), indent);\n str += GenUtils.kvLine(\"Last failed height\", this.getLastFailedHeight(), indent);\n str += GenUtils.kvLine(\"Last failed hash\", this.getLastFailedHash(), indent);\n str += GenUtils.kvLine(\"Max used block height\", this.getMaxUsedBlockHeight(), indent);\n str += GenUtils.kvLine(\"Max used block hash\", this.getMaxUsedBlockHash(), indent);\n str += GenUtils.kvLine(\"Signatures\", this.getSignatures(), indent);\n if (this.getInputs() !== undefined) {\n str += GenUtils.kvLine(\"Inputs\", \"\", indent);\n for (let i = 0; i < this.getInputs().length; i++) {\n str += GenUtils.kvLine(i + 1, \"\", indent + 1);\n str += this.getInputs()[i].toString(indent + 2);\n str += '\\n';\n }\n }\n if (this.getOutputs() !== undefined) {\n str += GenUtils.kvLine(\"Outputs\", \"\", indent);\n for (let i = 0; i < this.getOutputs().length; i++) {\n str += GenUtils.kvLine(i + 1, \"\", indent + 1);\n str += this.getOutputs()[i].toString(indent + 2);\n str += '\\n';\n }\n }\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\nMoneroTx.DEFAULT_PAYMENT_ID = \"0000000000000000\";\nexport default MoneroTx;\n","import assert from \"assert\";\nimport GenUtils from \"../../common/GenUtils\";\nimport MoneroError from \"../../common/MoneroError\";\n/**\n * Models a base transfer of funds to or from the wallet.\n */\nexport default class MoneroTransfer {\n /**\n * Construct the transfer.\n *\n * @param {Partial} transfer existing state to initialize from (optional)\n */\n constructor(transfer) {\n Object.assign(this, transfer);\n if (this.amount !== undefined && typeof this.amount !== \"bigint\")\n this.amount = BigInt(this.amount);\n this.validate();\n }\n copy() {\n return new MoneroTransfer(this);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (this.getAmount() !== undefined)\n json.amount = this.getAmount().toString();\n delete json.tx; // parent tx is not serialized\n return json;\n }\n getTx() {\n return this.tx;\n }\n setTx(tx) {\n this.tx = tx;\n return this;\n }\n getIsOutgoing() {\n let isIncoming = this.getIsIncoming();\n assert(typeof isIncoming === \"boolean\");\n return !isIncoming;\n }\n getIsIncoming() {\n throw new Error(\"Subclass must implement\");\n }\n getAccountIndex() {\n return this.accountIndex;\n }\n setAccountIndex(accountIndex) {\n this.accountIndex = accountIndex;\n this.validate();\n return this;\n }\n getAmount() {\n return this.amount;\n }\n setAmount(amount) {\n this.amount = amount;\n return this;\n }\n /**\n * Updates this transaction by merging the latest information from the given\n * transaction.\n *\n * Merging can modify or build references to the transfer given so it\n * should not be re-used or it should be copied before calling this method.\n *\n * @param transfer is the transfer to merge into this one\n * @return {MoneroTransfer} the merged transfer\n */\n merge(transfer) {\n assert(transfer instanceof MoneroTransfer);\n if (this === transfer)\n return this;\n // merge transactions if they're different which comes back to merging transfers\n if (this.getTx() !== transfer.getTx()) {\n this.getTx().merge(transfer.getTx());\n return this;\n }\n // otherwise merge transfer fields\n this.setAccountIndex(GenUtils.reconcile(this.getAccountIndex(), transfer.getAccountIndex()));\n // TODO monero-project: failed tx in pool (after testUpdateLockedDifferentAccounts()) causes non-originating saved wallets to return duplicate incoming transfers but one has amount of 0\n if (this.getAmount() !== undefined && transfer.getAmount() !== undefined && this.getAmount() !== transfer.getAmount() && (this.getAmount() === 0n || transfer.getAmount() === 0n)) {\n console.warn(\"monero-project returning transfers with 0 amount/numSuggestedConfirmations\");\n }\n else {\n this.setAmount(GenUtils.reconcile(this.getAmount(), transfer.getAmount()));\n }\n return this;\n }\n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.kvLine(\"Is incoming\", this.getIsIncoming(), indent);\n str += GenUtils.kvLine(\"Account index\", this.getAccountIndex(), indent);\n str += GenUtils.kvLine(\"Amount\", this.getAmount() ? this.getAmount().toString() : undefined, indent);\n return str === \"\" ? str : str.slice(0, str.length - 1); // strip last newline\n }\n validate() {\n if (this.getAccountIndex() !== undefined && this.getAccountIndex() < 0)\n throw new MoneroError(\"Account index must be >= 0\");\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"../../common/GenUtils\";\nimport MoneroTransfer from \"./MoneroTransfer\";\n/**\n * Models an incoming transfer of funds to the wallet.\n */\nexport default class MoneroIncomingTransfer extends MoneroTransfer {\n /**\n * Construct the transfer.\n *\n * @param {MoneroTransfer} [transfer] is existing state to initialize from (optional)\n */\n constructor(transfer) {\n super(transfer);\n }\n getIsIncoming() {\n return true;\n }\n getSubaddressIndex() {\n return this.subaddressIndex;\n }\n setSubaddressIndex(subaddressIndex) {\n this.subaddressIndex = subaddressIndex;\n return this;\n }\n getAddress() {\n return this.address;\n }\n setAddress(address) {\n this.address = address;\n return this;\n }\n /**\n * Return how many confirmations till it's not economically worth re-writing the chain.\n * That is, the number of confirmations before the transaction is highly unlikely to be\n * double spent or overwritten and may be considered settled, e.g. for a merchant to trust\n * as finalized.\n *\n * @return {number} is the number of confirmations before it's not worth rewriting the chain\n */\n getNumSuggestedConfirmations() {\n return this.numSuggestedConfirmations;\n }\n setNumSuggestedConfirmations(numSuggestedConfirmations) {\n this.numSuggestedConfirmations = numSuggestedConfirmations;\n return this;\n }\n copy() {\n return new MoneroIncomingTransfer(this.toJson());\n }\n /**\n * Updates this transaction by merging the latest information from the given\n * transaction.\n *\n * Merging can modify or build references to the transfer given so it\n * should not be re-used or it should be copied before calling this method.\n *\n * @param {MoneroIncomingTransfer} transfer is the transfer to merge into this one\n * @return {MoneroIncomingTransfer}\n */\n merge(transfer) {\n super.merge(transfer);\n assert(transfer instanceof MoneroIncomingTransfer);\n if (this === transfer)\n return this;\n this.setSubaddressIndex(GenUtils.reconcile(this.getSubaddressIndex(), transfer.getSubaddressIndex()));\n this.setAddress(GenUtils.reconcile(this.getAddress(), transfer.getAddress()));\n this.setNumSuggestedConfirmations(GenUtils.reconcile(this.getNumSuggestedConfirmations(), transfer.getNumSuggestedConfirmations(), { resolveMax: false }));\n return this;\n }\n toString(indent = 0) {\n let str = super.toString(indent) + \"\\n\";\n str += GenUtils.kvLine(\"Subaddress index\", this.getSubaddressIndex(), indent);\n str += GenUtils.kvLine(\"Address\", this.getAddress(), indent);\n str += GenUtils.kvLine(\"Num suggested confirmations\", this.getNumSuggestedConfirmations(), indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n // -------------------- OVERRIDE COVARIANT RETURN TYPES ---------------------\n setTx(tx) {\n super.setTx(tx);\n return this;\n }\n setAmount(amount) {\n super.setAmount(amount);\n return this;\n }\n setAccountIndex(accountIndex) {\n super.setAccountIndex(accountIndex);\n return this;\n }\n}\n","import GenUtils from \"../../common/GenUtils\";\nimport MoneroError from \"../../common/MoneroError\";\n/**\n * Models an outgoing transfer destination.\n */\nexport default class MoneroDestination {\n /**\n * Construct a destination to send funds to.\n *\n * @param {Partial|string} destinationOrAddress is a MoneroDestination or hex string to initialize from (optional)\n * @param {bigint} [amount] - the destination amount\n */\n constructor(destinationOrAddress, amount) {\n if (typeof destinationOrAddress === \"string\") {\n this.setAddress(destinationOrAddress);\n this.setAmount(amount);\n }\n else {\n if (amount !== undefined)\n throw new Error(\"Amount parameter must be undefined when initializing a MoneroDestination from a MoneroDestination\");\n Object.assign(this, destinationOrAddress);\n if (this.amount && typeof this.amount !== \"bigint\")\n this.amount = BigInt(this.amount);\n }\n }\n getAddress() {\n return this.address;\n }\n setAddress(address) {\n this.address = address;\n return this;\n }\n getAmount() {\n return this.amount;\n }\n setAmount(amount) {\n if (amount !== undefined && typeof amount !== \"bigint\") {\n if (typeof amount === \"number\")\n throw new MoneroError(\"Destination amount must be BigInt or string\");\n try {\n amount = BigInt(amount);\n }\n catch (err) {\n throw new MoneroError(\"Invalid destination amount: \" + amount);\n }\n }\n this.amount = amount;\n return this;\n }\n copy() {\n return new MoneroDestination(this);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (this.getAmount() !== undefined)\n json.amount = this.getAmount().toString();\n return json;\n }\n toString(indent = 0) {\n let str = GenUtils.kvLine(\"Address\", this.getAddress(), indent);\n str += GenUtils.kvLine(\"Amount\", this.getAmount() ? this.getAmount().toString() : undefined, indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"../../common/GenUtils\";\nimport MoneroDestination from \"./MoneroDestination\";\nimport MoneroTransfer from \"./MoneroTransfer\";\n/**\n * Models an outgoing transfer of funds from the wallet.\n */\nexport default class MoneroOutgoingTransfer extends MoneroTransfer {\n /**\n * Construct the model.\n *\n * @param {MoneroOutgoingTranser [transfer] existing state to initialize from (optional)\n */\n constructor(transfer) {\n super(transfer);\n // copy destinations\n if (this.destinations) {\n this.destinations = this.destinations.slice();\n for (let i = 0; i < this.destinations.length; i++) {\n this.destinations[i] = new MoneroDestination(this.destinations[i]);\n }\n }\n }\n getIsIncoming() {\n return false;\n }\n getSubaddressIndices() {\n return this.subaddressIndices;\n }\n setSubaddressIndices(subaddressIndices) {\n this.subaddressIndices = subaddressIndices;\n return this;\n }\n getAddresses() {\n return this.addresses;\n }\n setAddresses(addresses) {\n this.addresses = addresses;\n return this;\n }\n getDestinations() {\n return this.destinations;\n }\n setDestinations(destinations) {\n this.destinations = destinations;\n return this;\n }\n copy() {\n return new MoneroOutgoingTransfer(this);\n }\n toJson() {\n let json = Object.assign({}, this, super.toJson()); // merge json onto inherited state\n if (this.getDestinations() !== undefined) {\n json.destinations = [];\n for (let destination of this.getDestinations())\n json.destinations.push(destination.toJson());\n }\n delete json.tx; // parent tx is not serialized\n return json;\n }\n /**\n * Updates this transaction by merging the latest information from the given\n * transaction.\n *\n * Merging can modify or build references to the transfer given so it\n * should not be re-used or it should be copied before calling this method.\n *\n * @param transfer is the transfer to merge into this one\n */\n merge(transfer) {\n super.merge(transfer);\n assert(transfer instanceof MoneroOutgoingTransfer);\n if (this === transfer)\n return this;\n this.setSubaddressIndices(GenUtils.reconcile(this.getSubaddressIndices(), transfer.getSubaddressIndices()));\n this.setAddresses(GenUtils.reconcile(this.getAddresses(), transfer.getAddresses()));\n this.setDestinations(GenUtils.reconcile(this.getDestinations(), transfer.getDestinations()));\n return this;\n }\n toString(indent = 0) {\n let str = super.toString(indent) + \"\\n\";\n str += GenUtils.kvLine(\"Subaddress indices\", this.getSubaddressIndices(), indent);\n str += GenUtils.kvLine(\"Addresses\", this.getAddresses(), indent);\n if (this.getDestinations() !== undefined) {\n str += GenUtils.kvLine(\"Destinations\", \"\", indent);\n for (let i = 0; i < this.getDestinations().length; i++) {\n str += GenUtils.kvLine(i + 1, \"\", indent + 1);\n str += this.getDestinations()[i].toString(indent + 2) + \"\\n\";\n }\n }\n return str.slice(0, str.length - 1); // strip last newline\n }\n // -------------------- OVERRIDE COVARIANT RETURN TYPES ---------------------\n setTx(tx) {\n super.setTx(tx);\n return this;\n }\n setAmount(amount) {\n super.setAmount(amount);\n return this;\n }\n setAccountIndex(accountIndex) {\n super.setAccountIndex(accountIndex);\n return this;\n }\n}\n","/*!\r\n * decimal.js v10.4.3\r\n * An arbitrary-precision Decimal type for JavaScript.\r\n * https://github.com/MikeMcl/decimal.js\r\n * Copyright (c) 2022 Michael Mclaughlin \r\n * MIT Licence\r\n */\r\n\r\n\r\n// ----------------------------------- EDITABLE DEFAULTS ------------------------------------ //\r\n\r\n\r\n // The maximum exponent magnitude.\r\n // The limit on the value of `toExpNeg`, `toExpPos`, `minE` and `maxE`.\r\nvar EXP_LIMIT = 9e15, // 0 to 9e15\r\n\r\n // The limit on the value of `precision`, and on the value of the first argument to\r\n // `toDecimalPlaces`, `toExponential`, `toFixed`, `toPrecision` and `toSignificantDigits`.\r\n MAX_DIGITS = 1e9, // 0 to 1e9\r\n\r\n // Base conversion alphabet.\r\n NUMERALS = '0123456789abcdef',\r\n\r\n // The natural logarithm of 10 (1025 digits).\r\n LN10 = '2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058',\r\n\r\n // Pi (1025 digits).\r\n PI = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632789',\r\n\r\n\r\n // The initial configuration properties of the Decimal constructor.\r\n DEFAULTS = {\r\n\r\n // These values must be integers within the stated ranges (inclusive).\r\n // Most of these values can be changed at run-time using the `Decimal.config` method.\r\n\r\n // The maximum number of significant digits of the result of a calculation or base conversion.\r\n // E.g. `Decimal.config({ precision: 20 });`\r\n precision: 20, // 1 to MAX_DIGITS\r\n\r\n // The rounding mode used when rounding to `precision`.\r\n //\r\n // ROUND_UP 0 Away from zero.\r\n // ROUND_DOWN 1 Towards zero.\r\n // ROUND_CEIL 2 Towards +Infinity.\r\n // ROUND_FLOOR 3 Towards -Infinity.\r\n // ROUND_HALF_UP 4 Towards nearest neighbour. If equidistant, up.\r\n // ROUND_HALF_DOWN 5 Towards nearest neighbour. If equidistant, down.\r\n // ROUND_HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour.\r\n // ROUND_HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity.\r\n // ROUND_HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity.\r\n //\r\n // E.g.\r\n // `Decimal.rounding = 4;`\r\n // `Decimal.rounding = Decimal.ROUND_HALF_UP;`\r\n rounding: 4, // 0 to 8\r\n\r\n // The modulo mode used when calculating the modulus: a mod n.\r\n // The quotient (q = a / n) is calculated according to the corresponding rounding mode.\r\n // The remainder (r) is calculated as: r = a - n * q.\r\n //\r\n // UP 0 The remainder is positive if the dividend is negative, else is negative.\r\n // DOWN 1 The remainder has the same sign as the dividend (JavaScript %).\r\n // FLOOR 3 The remainder has the same sign as the divisor (Python %).\r\n // HALF_EVEN 6 The IEEE 754 remainder function.\r\n // EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)). Always positive.\r\n //\r\n // Truncated division (1), floored division (3), the IEEE 754 remainder (6), and Euclidian\r\n // division (9) are commonly used for the modulus operation. The other rounding modes can also\r\n // be used, but they may not give useful results.\r\n modulo: 1, // 0 to 9\r\n\r\n // The exponent value at and beneath which `toString` returns exponential notation.\r\n // JavaScript numbers: -7\r\n toExpNeg: -7, // 0 to -EXP_LIMIT\r\n\r\n // The exponent value at and above which `toString` returns exponential notation.\r\n // JavaScript numbers: 21\r\n toExpPos: 21, // 0 to EXP_LIMIT\r\n\r\n // The minimum exponent value, beneath which underflow to zero occurs.\r\n // JavaScript numbers: -324 (5e-324)\r\n minE: -EXP_LIMIT, // -1 to -EXP_LIMIT\r\n\r\n // The maximum exponent value, above which overflow to Infinity occurs.\r\n // JavaScript numbers: 308 (1.7976931348623157e+308)\r\n maxE: EXP_LIMIT, // 1 to EXP_LIMIT\r\n\r\n // Whether to use cryptographically-secure random number generation, if available.\r\n crypto: false // true/false\r\n },\r\n\r\n\r\n// ----------------------------------- END OF EDITABLE DEFAULTS ------------------------------- //\r\n\r\n\r\n inexact, quadrant,\r\n external = true,\r\n\r\n decimalError = '[DecimalError] ',\r\n invalidArgument = decimalError + 'Invalid argument: ',\r\n precisionLimitExceeded = decimalError + 'Precision limit exceeded',\r\n cryptoUnavailable = decimalError + 'crypto unavailable',\r\n tag = '[object Decimal]',\r\n\r\n mathfloor = Math.floor,\r\n mathpow = Math.pow,\r\n\r\n isBinary = /^0b([01]+(\\.[01]*)?|\\.[01]+)(p[+-]?\\d+)?$/i,\r\n isHex = /^0x([0-9a-f]+(\\.[0-9a-f]*)?|\\.[0-9a-f]+)(p[+-]?\\d+)?$/i,\r\n isOctal = /^0o([0-7]+(\\.[0-7]*)?|\\.[0-7]+)(p[+-]?\\d+)?$/i,\r\n isDecimal = /^(\\d+(\\.\\d*)?|\\.\\d+)(e[+-]?\\d+)?$/i,\r\n\r\n BASE = 1e7,\r\n LOG_BASE = 7,\r\n MAX_SAFE_INTEGER = 9007199254740991,\r\n\r\n LN10_PRECISION = LN10.length - 1,\r\n PI_PRECISION = PI.length - 1,\r\n\r\n // Decimal.prototype object\r\n P = { toStringTag: tag };\r\n\r\n\r\n// Decimal prototype methods\r\n\r\n\r\n/*\r\n * absoluteValue abs\r\n * ceil\r\n * clampedTo clamp\r\n * comparedTo cmp\r\n * cosine cos\r\n * cubeRoot cbrt\r\n * decimalPlaces dp\r\n * dividedBy div\r\n * dividedToIntegerBy divToInt\r\n * equals eq\r\n * floor\r\n * greaterThan gt\r\n * greaterThanOrEqualTo gte\r\n * hyperbolicCosine cosh\r\n * hyperbolicSine sinh\r\n * hyperbolicTangent tanh\r\n * inverseCosine acos\r\n * inverseHyperbolicCosine acosh\r\n * inverseHyperbolicSine asinh\r\n * inverseHyperbolicTangent atanh\r\n * inverseSine asin\r\n * inverseTangent atan\r\n * isFinite\r\n * isInteger isInt\r\n * isNaN\r\n * isNegative isNeg\r\n * isPositive isPos\r\n * isZero\r\n * lessThan lt\r\n * lessThanOrEqualTo lte\r\n * logarithm log\r\n * [maximum] [max]\r\n * [minimum] [min]\r\n * minus sub\r\n * modulo mod\r\n * naturalExponential exp\r\n * naturalLogarithm ln\r\n * negated neg\r\n * plus add\r\n * precision sd\r\n * round\r\n * sine sin\r\n * squareRoot sqrt\r\n * tangent tan\r\n * times mul\r\n * toBinary\r\n * toDecimalPlaces toDP\r\n * toExponential\r\n * toFixed\r\n * toFraction\r\n * toHexadecimal toHex\r\n * toNearest\r\n * toNumber\r\n * toOctal\r\n * toPower pow\r\n * toPrecision\r\n * toSignificantDigits toSD\r\n * toString\r\n * truncated trunc\r\n * valueOf toJSON\r\n */\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the absolute value of this Decimal.\r\n *\r\n */\r\nP.absoluteValue = P.abs = function () {\r\n var x = new this.constructor(this);\r\n if (x.s < 0) x.s = 1;\r\n return finalise(x);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the value of this Decimal rounded to a whole number in the\r\n * direction of positive Infinity.\r\n *\r\n */\r\nP.ceil = function () {\r\n return finalise(new this.constructor(this), this.e + 1, 2);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the value of this Decimal clamped to the range\r\n * delineated by `min` and `max`.\r\n *\r\n * min {number|string|Decimal}\r\n * max {number|string|Decimal}\r\n *\r\n */\r\nP.clampedTo = P.clamp = function (min, max) {\r\n var k,\r\n x = this,\r\n Ctor = x.constructor;\r\n min = new Ctor(min);\r\n max = new Ctor(max);\r\n if (!min.s || !max.s) return new Ctor(NaN);\r\n if (min.gt(max)) throw Error(invalidArgument + max);\r\n k = x.cmp(min);\r\n return k < 0 ? min : x.cmp(max) > 0 ? max : new Ctor(x);\r\n};\r\n\r\n\r\n/*\r\n * Return\r\n * 1 if the value of this Decimal is greater than the value of `y`,\r\n * -1 if the value of this Decimal is less than the value of `y`,\r\n * 0 if they have the same value,\r\n * NaN if the value of either Decimal is NaN.\r\n *\r\n */\r\nP.comparedTo = P.cmp = function (y) {\r\n var i, j, xdL, ydL,\r\n x = this,\r\n xd = x.d,\r\n yd = (y = new x.constructor(y)).d,\r\n xs = x.s,\r\n ys = y.s;\r\n\r\n // Either NaN or ±Infinity?\r\n if (!xd || !yd) {\r\n return !xs || !ys ? NaN : xs !== ys ? xs : xd === yd ? 0 : !xd ^ xs < 0 ? 1 : -1;\r\n }\r\n\r\n // Either zero?\r\n if (!xd[0] || !yd[0]) return xd[0] ? xs : yd[0] ? -ys : 0;\r\n\r\n // Signs differ?\r\n if (xs !== ys) return xs;\r\n\r\n // Compare exponents.\r\n if (x.e !== y.e) return x.e > y.e ^ xs < 0 ? 1 : -1;\r\n\r\n xdL = xd.length;\r\n ydL = yd.length;\r\n\r\n // Compare digit by digit.\r\n for (i = 0, j = xdL < ydL ? xdL : ydL; i < j; ++i) {\r\n if (xd[i] !== yd[i]) return xd[i] > yd[i] ^ xs < 0 ? 1 : -1;\r\n }\r\n\r\n // Compare lengths.\r\n return xdL === ydL ? 0 : xdL > ydL ^ xs < 0 ? 1 : -1;\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the cosine of the value in radians of this Decimal.\r\n *\r\n * Domain: [-Infinity, Infinity]\r\n * Range: [-1, 1]\r\n *\r\n * cos(0) = 1\r\n * cos(-0) = 1\r\n * cos(Infinity) = NaN\r\n * cos(-Infinity) = NaN\r\n * cos(NaN) = NaN\r\n *\r\n */\r\nP.cosine = P.cos = function () {\r\n var pr, rm,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (!x.d) return new Ctor(NaN);\r\n\r\n // cos(0) = cos(-0) = 1\r\n if (!x.d[0]) return new Ctor(1);\r\n\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n Ctor.precision = pr + Math.max(x.e, x.sd()) + LOG_BASE;\r\n Ctor.rounding = 1;\r\n\r\n x = cosine(Ctor, toLessThanHalfPi(Ctor, x));\r\n\r\n Ctor.precision = pr;\r\n Ctor.rounding = rm;\r\n\r\n return finalise(quadrant == 2 || quadrant == 3 ? x.neg() : x, pr, rm, true);\r\n};\r\n\r\n\r\n/*\r\n *\r\n * Return a new Decimal whose value is the cube root of the value of this Decimal, rounded to\r\n * `precision` significant digits using rounding mode `rounding`.\r\n *\r\n * cbrt(0) = 0\r\n * cbrt(-0) = -0\r\n * cbrt(1) = 1\r\n * cbrt(-1) = -1\r\n * cbrt(N) = N\r\n * cbrt(-I) = -I\r\n * cbrt(I) = I\r\n *\r\n * Math.cbrt(x) = (x < 0 ? -Math.pow(-x, 1/3) : Math.pow(x, 1/3))\r\n *\r\n */\r\nP.cubeRoot = P.cbrt = function () {\r\n var e, m, n, r, rep, s, sd, t, t3, t3plusx,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (!x.isFinite() || x.isZero()) return new Ctor(x);\r\n external = false;\r\n\r\n // Initial estimate.\r\n s = x.s * mathpow(x.s * x, 1 / 3);\r\n\r\n // Math.cbrt underflow/overflow?\r\n // Pass x to Math.pow as integer, then adjust the exponent of the result.\r\n if (!s || Math.abs(s) == 1 / 0) {\r\n n = digitsToString(x.d);\r\n e = x.e;\r\n\r\n // Adjust n exponent so it is a multiple of 3 away from x exponent.\r\n if (s = (e - n.length + 1) % 3) n += (s == 1 || s == -2 ? '0' : '00');\r\n s = mathpow(n, 1 / 3);\r\n\r\n // Rarely, e may be one less than the result exponent value.\r\n e = mathfloor((e + 1) / 3) - (e % 3 == (e < 0 ? -1 : 2));\r\n\r\n if (s == 1 / 0) {\r\n n = '5e' + e;\r\n } else {\r\n n = s.toExponential();\r\n n = n.slice(0, n.indexOf('e') + 1) + e;\r\n }\r\n\r\n r = new Ctor(n);\r\n r.s = x.s;\r\n } else {\r\n r = new Ctor(s.toString());\r\n }\r\n\r\n sd = (e = Ctor.precision) + 3;\r\n\r\n // Halley's method.\r\n // TODO? Compare Newton's method.\r\n for (;;) {\r\n t = r;\r\n t3 = t.times(t).times(t);\r\n t3plusx = t3.plus(x);\r\n r = divide(t3plusx.plus(x).times(t), t3plusx.plus(t3), sd + 2, 1);\r\n\r\n // TODO? Replace with for-loop and checkRoundingDigits.\r\n if (digitsToString(t.d).slice(0, sd) === (n = digitsToString(r.d)).slice(0, sd)) {\r\n n = n.slice(sd - 3, sd + 1);\r\n\r\n // The 4th rounding digit may be in error by -1 so if the 4 rounding digits are 9999 or 4999\r\n // , i.e. approaching a rounding boundary, continue the iteration.\r\n if (n == '9999' || !rep && n == '4999') {\r\n\r\n // On the first iteration only, check to see if rounding up gives the exact result as the\r\n // nines may infinitely repeat.\r\n if (!rep) {\r\n finalise(t, e + 1, 0);\r\n\r\n if (t.times(t).times(t).eq(x)) {\r\n r = t;\r\n break;\r\n }\r\n }\r\n\r\n sd += 4;\r\n rep = 1;\r\n } else {\r\n\r\n // If the rounding digits are null, 0{0,4} or 50{0,3}, check for an exact result.\r\n // If not, then there are further digits and m will be truthy.\r\n if (!+n || !+n.slice(1) && n.charAt(0) == '5') {\r\n\r\n // Truncate to the first rounding digit.\r\n finalise(r, e + 1, 1);\r\n m = !r.times(r).times(r).eq(x);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n }\r\n\r\n external = true;\r\n\r\n return finalise(r, e, Ctor.rounding, m);\r\n};\r\n\r\n\r\n/*\r\n * Return the number of decimal places of the value of this Decimal.\r\n *\r\n */\r\nP.decimalPlaces = P.dp = function () {\r\n var w,\r\n d = this.d,\r\n n = NaN;\r\n\r\n if (d) {\r\n w = d.length - 1;\r\n n = (w - mathfloor(this.e / LOG_BASE)) * LOG_BASE;\r\n\r\n // Subtract the number of trailing zeros of the last word.\r\n w = d[w];\r\n if (w) for (; w % 10 == 0; w /= 10) n--;\r\n if (n < 0) n = 0;\r\n }\r\n\r\n return n;\r\n};\r\n\r\n\r\n/*\r\n * n / 0 = I\r\n * n / N = N\r\n * n / I = 0\r\n * 0 / n = 0\r\n * 0 / 0 = N\r\n * 0 / N = N\r\n * 0 / I = 0\r\n * N / n = N\r\n * N / 0 = N\r\n * N / N = N\r\n * N / I = N\r\n * I / n = I\r\n * I / 0 = I\r\n * I / N = N\r\n * I / I = N\r\n *\r\n * Return a new Decimal whose value is the value of this Decimal divided by `y`, rounded to\r\n * `precision` significant digits using rounding mode `rounding`.\r\n *\r\n */\r\nP.dividedBy = P.div = function (y) {\r\n return divide(this, new this.constructor(y));\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the integer part of dividing the value of this Decimal\r\n * by the value of `y`, rounded to `precision` significant digits using rounding mode `rounding`.\r\n *\r\n */\r\nP.dividedToIntegerBy = P.divToInt = function (y) {\r\n var x = this,\r\n Ctor = x.constructor;\r\n return finalise(divide(x, new Ctor(y), 0, 1, 1), Ctor.precision, Ctor.rounding);\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Decimal is equal to the value of `y`, otherwise return false.\r\n *\r\n */\r\nP.equals = P.eq = function (y) {\r\n return this.cmp(y) === 0;\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the value of this Decimal rounded to a whole number in the\r\n * direction of negative Infinity.\r\n *\r\n */\r\nP.floor = function () {\r\n return finalise(new this.constructor(this), this.e + 1, 3);\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Decimal is greater than the value of `y`, otherwise return\r\n * false.\r\n *\r\n */\r\nP.greaterThan = P.gt = function (y) {\r\n return this.cmp(y) > 0;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Decimal is greater than or equal to the value of `y`,\r\n * otherwise return false.\r\n *\r\n */\r\nP.greaterThanOrEqualTo = P.gte = function (y) {\r\n var k = this.cmp(y);\r\n return k == 1 || k === 0;\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the hyperbolic cosine of the value in radians of this\r\n * Decimal.\r\n *\r\n * Domain: [-Infinity, Infinity]\r\n * Range: [1, Infinity]\r\n *\r\n * cosh(x) = 1 + x^2/2! + x^4/4! + x^6/6! + ...\r\n *\r\n * cosh(0) = 1\r\n * cosh(-0) = 1\r\n * cosh(Infinity) = Infinity\r\n * cosh(-Infinity) = Infinity\r\n * cosh(NaN) = NaN\r\n *\r\n * x time taken (ms) result\r\n * 1000 9 9.8503555700852349694e+433\r\n * 10000 25 4.4034091128314607936e+4342\r\n * 100000 171 1.4033316802130615897e+43429\r\n * 1000000 3817 1.5166076984010437725e+434294\r\n * 10000000 abandoned after 2 minute wait\r\n *\r\n * TODO? Compare performance of cosh(x) = 0.5 * (exp(x) + exp(-x))\r\n *\r\n */\r\nP.hyperbolicCosine = P.cosh = function () {\r\n var k, n, pr, rm, len,\r\n x = this,\r\n Ctor = x.constructor,\r\n one = new Ctor(1);\r\n\r\n if (!x.isFinite()) return new Ctor(x.s ? 1 / 0 : NaN);\r\n if (x.isZero()) return one;\r\n\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n Ctor.precision = pr + Math.max(x.e, x.sd()) + 4;\r\n Ctor.rounding = 1;\r\n len = x.d.length;\r\n\r\n // Argument reduction: cos(4x) = 1 - 8cos^2(x) + 8cos^4(x) + 1\r\n // i.e. cos(x) = 1 - cos^2(x/4)(8 - 8cos^2(x/4))\r\n\r\n // Estimate the optimum number of times to use the argument reduction.\r\n // TODO? Estimation reused from cosine() and may not be optimal here.\r\n if (len < 32) {\r\n k = Math.ceil(len / 3);\r\n n = (1 / tinyPow(4, k)).toString();\r\n } else {\r\n k = 16;\r\n n = '2.3283064365386962890625e-10';\r\n }\r\n\r\n x = taylorSeries(Ctor, 1, x.times(n), new Ctor(1), true);\r\n\r\n // Reverse argument reduction\r\n var cosh2_x,\r\n i = k,\r\n d8 = new Ctor(8);\r\n for (; i--;) {\r\n cosh2_x = x.times(x);\r\n x = one.minus(cosh2_x.times(d8.minus(cosh2_x.times(d8))));\r\n }\r\n\r\n return finalise(x, Ctor.precision = pr, Ctor.rounding = rm, true);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the hyperbolic sine of the value in radians of this\r\n * Decimal.\r\n *\r\n * Domain: [-Infinity, Infinity]\r\n * Range: [-Infinity, Infinity]\r\n *\r\n * sinh(x) = x + x^3/3! + x^5/5! + x^7/7! + ...\r\n *\r\n * sinh(0) = 0\r\n * sinh(-0) = -0\r\n * sinh(Infinity) = Infinity\r\n * sinh(-Infinity) = -Infinity\r\n * sinh(NaN) = NaN\r\n *\r\n * x time taken (ms)\r\n * 10 2 ms\r\n * 100 5 ms\r\n * 1000 14 ms\r\n * 10000 82 ms\r\n * 100000 886 ms 1.4033316802130615897e+43429\r\n * 200000 2613 ms\r\n * 300000 5407 ms\r\n * 400000 8824 ms\r\n * 500000 13026 ms 8.7080643612718084129e+217146\r\n * 1000000 48543 ms\r\n *\r\n * TODO? Compare performance of sinh(x) = 0.5 * (exp(x) - exp(-x))\r\n *\r\n */\r\nP.hyperbolicSine = P.sinh = function () {\r\n var k, pr, rm, len,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (!x.isFinite() || x.isZero()) return new Ctor(x);\r\n\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n Ctor.precision = pr + Math.max(x.e, x.sd()) + 4;\r\n Ctor.rounding = 1;\r\n len = x.d.length;\r\n\r\n if (len < 3) {\r\n x = taylorSeries(Ctor, 2, x, x, true);\r\n } else {\r\n\r\n // Alternative argument reduction: sinh(3x) = sinh(x)(3 + 4sinh^2(x))\r\n // i.e. sinh(x) = sinh(x/3)(3 + 4sinh^2(x/3))\r\n // 3 multiplications and 1 addition\r\n\r\n // Argument reduction: sinh(5x) = sinh(x)(5 + sinh^2(x)(20 + 16sinh^2(x)))\r\n // i.e. sinh(x) = sinh(x/5)(5 + sinh^2(x/5)(20 + 16sinh^2(x/5)))\r\n // 4 multiplications and 2 additions\r\n\r\n // Estimate the optimum number of times to use the argument reduction.\r\n k = 1.4 * Math.sqrt(len);\r\n k = k > 16 ? 16 : k | 0;\r\n\r\n x = x.times(1 / tinyPow(5, k));\r\n x = taylorSeries(Ctor, 2, x, x, true);\r\n\r\n // Reverse argument reduction\r\n var sinh2_x,\r\n d5 = new Ctor(5),\r\n d16 = new Ctor(16),\r\n d20 = new Ctor(20);\r\n for (; k--;) {\r\n sinh2_x = x.times(x);\r\n x = x.times(d5.plus(sinh2_x.times(d16.times(sinh2_x).plus(d20))));\r\n }\r\n }\r\n\r\n Ctor.precision = pr;\r\n Ctor.rounding = rm;\r\n\r\n return finalise(x, pr, rm, true);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the hyperbolic tangent of the value in radians of this\r\n * Decimal.\r\n *\r\n * Domain: [-Infinity, Infinity]\r\n * Range: [-1, 1]\r\n *\r\n * tanh(x) = sinh(x) / cosh(x)\r\n *\r\n * tanh(0) = 0\r\n * tanh(-0) = -0\r\n * tanh(Infinity) = 1\r\n * tanh(-Infinity) = -1\r\n * tanh(NaN) = NaN\r\n *\r\n */\r\nP.hyperbolicTangent = P.tanh = function () {\r\n var pr, rm,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (!x.isFinite()) return new Ctor(x.s);\r\n if (x.isZero()) return new Ctor(x);\r\n\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n Ctor.precision = pr + 7;\r\n Ctor.rounding = 1;\r\n\r\n return divide(x.sinh(), x.cosh(), Ctor.precision = pr, Ctor.rounding = rm);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the arccosine (inverse cosine) in radians of the value of\r\n * this Decimal.\r\n *\r\n * Domain: [-1, 1]\r\n * Range: [0, pi]\r\n *\r\n * acos(x) = pi/2 - asin(x)\r\n *\r\n * acos(0) = pi/2\r\n * acos(-0) = pi/2\r\n * acos(1) = 0\r\n * acos(-1) = pi\r\n * acos(1/2) = pi/3\r\n * acos(-1/2) = 2*pi/3\r\n * acos(|x| > 1) = NaN\r\n * acos(NaN) = NaN\r\n *\r\n */\r\nP.inverseCosine = P.acos = function () {\r\n var halfPi,\r\n x = this,\r\n Ctor = x.constructor,\r\n k = x.abs().cmp(1),\r\n pr = Ctor.precision,\r\n rm = Ctor.rounding;\r\n\r\n if (k !== -1) {\r\n return k === 0\r\n // |x| is 1\r\n ? x.isNeg() ? getPi(Ctor, pr, rm) : new Ctor(0)\r\n // |x| > 1 or x is NaN\r\n : new Ctor(NaN);\r\n }\r\n\r\n if (x.isZero()) return getPi(Ctor, pr + 4, rm).times(0.5);\r\n\r\n // TODO? Special case acos(0.5) = pi/3 and acos(-0.5) = 2*pi/3\r\n\r\n Ctor.precision = pr + 6;\r\n Ctor.rounding = 1;\r\n\r\n x = x.asin();\r\n halfPi = getPi(Ctor, pr + 4, rm).times(0.5);\r\n\r\n Ctor.precision = pr;\r\n Ctor.rounding = rm;\r\n\r\n return halfPi.minus(x);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the inverse of the hyperbolic cosine in radians of the\r\n * value of this Decimal.\r\n *\r\n * Domain: [1, Infinity]\r\n * Range: [0, Infinity]\r\n *\r\n * acosh(x) = ln(x + sqrt(x^2 - 1))\r\n *\r\n * acosh(x < 1) = NaN\r\n * acosh(NaN) = NaN\r\n * acosh(Infinity) = Infinity\r\n * acosh(-Infinity) = NaN\r\n * acosh(0) = NaN\r\n * acosh(-0) = NaN\r\n * acosh(1) = 0\r\n * acosh(-1) = NaN\r\n *\r\n */\r\nP.inverseHyperbolicCosine = P.acosh = function () {\r\n var pr, rm,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (x.lte(1)) return new Ctor(x.eq(1) ? 0 : NaN);\r\n if (!x.isFinite()) return new Ctor(x);\r\n\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n Ctor.precision = pr + Math.max(Math.abs(x.e), x.sd()) + 4;\r\n Ctor.rounding = 1;\r\n external = false;\r\n\r\n x = x.times(x).minus(1).sqrt().plus(x);\r\n\r\n external = true;\r\n Ctor.precision = pr;\r\n Ctor.rounding = rm;\r\n\r\n return x.ln();\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the inverse of the hyperbolic sine in radians of the value\r\n * of this Decimal.\r\n *\r\n * Domain: [-Infinity, Infinity]\r\n * Range: [-Infinity, Infinity]\r\n *\r\n * asinh(x) = ln(x + sqrt(x^2 + 1))\r\n *\r\n * asinh(NaN) = NaN\r\n * asinh(Infinity) = Infinity\r\n * asinh(-Infinity) = -Infinity\r\n * asinh(0) = 0\r\n * asinh(-0) = -0\r\n *\r\n */\r\nP.inverseHyperbolicSine = P.asinh = function () {\r\n var pr, rm,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (!x.isFinite() || x.isZero()) return new Ctor(x);\r\n\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n Ctor.precision = pr + 2 * Math.max(Math.abs(x.e), x.sd()) + 6;\r\n Ctor.rounding = 1;\r\n external = false;\r\n\r\n x = x.times(x).plus(1).sqrt().plus(x);\r\n\r\n external = true;\r\n Ctor.precision = pr;\r\n Ctor.rounding = rm;\r\n\r\n return x.ln();\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the inverse of the hyperbolic tangent in radians of the\r\n * value of this Decimal.\r\n *\r\n * Domain: [-1, 1]\r\n * Range: [-Infinity, Infinity]\r\n *\r\n * atanh(x) = 0.5 * ln((1 + x) / (1 - x))\r\n *\r\n * atanh(|x| > 1) = NaN\r\n * atanh(NaN) = NaN\r\n * atanh(Infinity) = NaN\r\n * atanh(-Infinity) = NaN\r\n * atanh(0) = 0\r\n * atanh(-0) = -0\r\n * atanh(1) = Infinity\r\n * atanh(-1) = -Infinity\r\n *\r\n */\r\nP.inverseHyperbolicTangent = P.atanh = function () {\r\n var pr, rm, wpr, xsd,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (!x.isFinite()) return new Ctor(NaN);\r\n if (x.e >= 0) return new Ctor(x.abs().eq(1) ? x.s / 0 : x.isZero() ? x : NaN);\r\n\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n xsd = x.sd();\r\n\r\n if (Math.max(xsd, pr) < 2 * -x.e - 1) return finalise(new Ctor(x), pr, rm, true);\r\n\r\n Ctor.precision = wpr = xsd - x.e;\r\n\r\n x = divide(x.plus(1), new Ctor(1).minus(x), wpr + pr, 1);\r\n\r\n Ctor.precision = pr + 4;\r\n Ctor.rounding = 1;\r\n\r\n x = x.ln();\r\n\r\n Ctor.precision = pr;\r\n Ctor.rounding = rm;\r\n\r\n return x.times(0.5);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the arcsine (inverse sine) in radians of the value of this\r\n * Decimal.\r\n *\r\n * Domain: [-Infinity, Infinity]\r\n * Range: [-pi/2, pi/2]\r\n *\r\n * asin(x) = 2*atan(x/(1 + sqrt(1 - x^2)))\r\n *\r\n * asin(0) = 0\r\n * asin(-0) = -0\r\n * asin(1/2) = pi/6\r\n * asin(-1/2) = -pi/6\r\n * asin(1) = pi/2\r\n * asin(-1) = -pi/2\r\n * asin(|x| > 1) = NaN\r\n * asin(NaN) = NaN\r\n *\r\n * TODO? Compare performance of Taylor series.\r\n *\r\n */\r\nP.inverseSine = P.asin = function () {\r\n var halfPi, k,\r\n pr, rm,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (x.isZero()) return new Ctor(x);\r\n\r\n k = x.abs().cmp(1);\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n\r\n if (k !== -1) {\r\n\r\n // |x| is 1\r\n if (k === 0) {\r\n halfPi = getPi(Ctor, pr + 4, rm).times(0.5);\r\n halfPi.s = x.s;\r\n return halfPi;\r\n }\r\n\r\n // |x| > 1 or x is NaN\r\n return new Ctor(NaN);\r\n }\r\n\r\n // TODO? Special case asin(1/2) = pi/6 and asin(-1/2) = -pi/6\r\n\r\n Ctor.precision = pr + 6;\r\n Ctor.rounding = 1;\r\n\r\n x = x.div(new Ctor(1).minus(x.times(x)).sqrt().plus(1)).atan();\r\n\r\n Ctor.precision = pr;\r\n Ctor.rounding = rm;\r\n\r\n return x.times(2);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the arctangent (inverse tangent) in radians of the value\r\n * of this Decimal.\r\n *\r\n * Domain: [-Infinity, Infinity]\r\n * Range: [-pi/2, pi/2]\r\n *\r\n * atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ...\r\n *\r\n * atan(0) = 0\r\n * atan(-0) = -0\r\n * atan(1) = pi/4\r\n * atan(-1) = -pi/4\r\n * atan(Infinity) = pi/2\r\n * atan(-Infinity) = -pi/2\r\n * atan(NaN) = NaN\r\n *\r\n */\r\nP.inverseTangent = P.atan = function () {\r\n var i, j, k, n, px, t, r, wpr, x2,\r\n x = this,\r\n Ctor = x.constructor,\r\n pr = Ctor.precision,\r\n rm = Ctor.rounding;\r\n\r\n if (!x.isFinite()) {\r\n if (!x.s) return new Ctor(NaN);\r\n if (pr + 4 <= PI_PRECISION) {\r\n r = getPi(Ctor, pr + 4, rm).times(0.5);\r\n r.s = x.s;\r\n return r;\r\n }\r\n } else if (x.isZero()) {\r\n return new Ctor(x);\r\n } else if (x.abs().eq(1) && pr + 4 <= PI_PRECISION) {\r\n r = getPi(Ctor, pr + 4, rm).times(0.25);\r\n r.s = x.s;\r\n return r;\r\n }\r\n\r\n Ctor.precision = wpr = pr + 10;\r\n Ctor.rounding = 1;\r\n\r\n // TODO? if (x >= 1 && pr <= PI_PRECISION) atan(x) = halfPi * x.s - atan(1 / x);\r\n\r\n // Argument reduction\r\n // Ensure |x| < 0.42\r\n // atan(x) = 2 * atan(x / (1 + sqrt(1 + x^2)))\r\n\r\n k = Math.min(28, wpr / LOG_BASE + 2 | 0);\r\n\r\n for (i = k; i; --i) x = x.div(x.times(x).plus(1).sqrt().plus(1));\r\n\r\n external = false;\r\n\r\n j = Math.ceil(wpr / LOG_BASE);\r\n n = 1;\r\n x2 = x.times(x);\r\n r = new Ctor(x);\r\n px = x;\r\n\r\n // atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ...\r\n for (; i !== -1;) {\r\n px = px.times(x2);\r\n t = r.minus(px.div(n += 2));\r\n\r\n px = px.times(x2);\r\n r = t.plus(px.div(n += 2));\r\n\r\n if (r.d[j] !== void 0) for (i = j; r.d[i] === t.d[i] && i--;);\r\n }\r\n\r\n if (k) r = r.times(2 << (k - 1));\r\n\r\n external = true;\r\n\r\n return finalise(r, Ctor.precision = pr, Ctor.rounding = rm, true);\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Decimal is a finite number, otherwise return false.\r\n *\r\n */\r\nP.isFinite = function () {\r\n return !!this.d;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Decimal is an integer, otherwise return false.\r\n *\r\n */\r\nP.isInteger = P.isInt = function () {\r\n return !!this.d && mathfloor(this.e / LOG_BASE) > this.d.length - 2;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Decimal is NaN, otherwise return false.\r\n *\r\n */\r\nP.isNaN = function () {\r\n return !this.s;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Decimal is negative, otherwise return false.\r\n *\r\n */\r\nP.isNegative = P.isNeg = function () {\r\n return this.s < 0;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Decimal is positive, otherwise return false.\r\n *\r\n */\r\nP.isPositive = P.isPos = function () {\r\n return this.s > 0;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Decimal is 0 or -0, otherwise return false.\r\n *\r\n */\r\nP.isZero = function () {\r\n return !!this.d && this.d[0] === 0;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Decimal is less than `y`, otherwise return false.\r\n *\r\n */\r\nP.lessThan = P.lt = function (y) {\r\n return this.cmp(y) < 0;\r\n};\r\n\r\n\r\n/*\r\n * Return true if the value of this Decimal is less than or equal to `y`, otherwise return false.\r\n *\r\n */\r\nP.lessThanOrEqualTo = P.lte = function (y) {\r\n return this.cmp(y) < 1;\r\n};\r\n\r\n\r\n/*\r\n * Return the logarithm of the value of this Decimal to the specified base, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * If no base is specified, return log[10](arg).\r\n *\r\n * log[base](arg) = ln(arg) / ln(base)\r\n *\r\n * The result will always be correctly rounded if the base of the log is 10, and 'almost always'\r\n * otherwise:\r\n *\r\n * Depending on the rounding mode, the result may be incorrectly rounded if the first fifteen\r\n * rounding digits are [49]99999999999999 or [50]00000000000000. In that case, the maximum error\r\n * between the result and the correctly rounded result will be one ulp (unit in the last place).\r\n *\r\n * log[-b](a) = NaN\r\n * log[0](a) = NaN\r\n * log[1](a) = NaN\r\n * log[NaN](a) = NaN\r\n * log[Infinity](a) = NaN\r\n * log[b](0) = -Infinity\r\n * log[b](-0) = -Infinity\r\n * log[b](-a) = NaN\r\n * log[b](1) = 0\r\n * log[b](Infinity) = Infinity\r\n * log[b](NaN) = NaN\r\n *\r\n * [base] {number|string|Decimal} The base of the logarithm.\r\n *\r\n */\r\nP.logarithm = P.log = function (base) {\r\n var isBase10, d, denominator, k, inf, num, sd, r,\r\n arg = this,\r\n Ctor = arg.constructor,\r\n pr = Ctor.precision,\r\n rm = Ctor.rounding,\r\n guard = 5;\r\n\r\n // Default base is 10.\r\n if (base == null) {\r\n base = new Ctor(10);\r\n isBase10 = true;\r\n } else {\r\n base = new Ctor(base);\r\n d = base.d;\r\n\r\n // Return NaN if base is negative, or non-finite, or is 0 or 1.\r\n if (base.s < 0 || !d || !d[0] || base.eq(1)) return new Ctor(NaN);\r\n\r\n isBase10 = base.eq(10);\r\n }\r\n\r\n d = arg.d;\r\n\r\n // Is arg negative, non-finite, 0 or 1?\r\n if (arg.s < 0 || !d || !d[0] || arg.eq(1)) {\r\n return new Ctor(d && !d[0] ? -1 / 0 : arg.s != 1 ? NaN : d ? 0 : 1 / 0);\r\n }\r\n\r\n // The result will have a non-terminating decimal expansion if base is 10 and arg is not an\r\n // integer power of 10.\r\n if (isBase10) {\r\n if (d.length > 1) {\r\n inf = true;\r\n } else {\r\n for (k = d[0]; k % 10 === 0;) k /= 10;\r\n inf = k !== 1;\r\n }\r\n }\r\n\r\n external = false;\r\n sd = pr + guard;\r\n num = naturalLogarithm(arg, sd);\r\n denominator = isBase10 ? getLn10(Ctor, sd + 10) : naturalLogarithm(base, sd);\r\n\r\n // The result will have 5 rounding digits.\r\n r = divide(num, denominator, sd, 1);\r\n\r\n // If at a rounding boundary, i.e. the result's rounding digits are [49]9999 or [50]0000,\r\n // calculate 10 further digits.\r\n //\r\n // If the result is known to have an infinite decimal expansion, repeat this until it is clear\r\n // that the result is above or below the boundary. Otherwise, if after calculating the 10\r\n // further digits, the last 14 are nines, round up and assume the result is exact.\r\n // Also assume the result is exact if the last 14 are zero.\r\n //\r\n // Example of a result that will be incorrectly rounded:\r\n // log[1048576](4503599627370502) = 2.60000000000000009610279511444746...\r\n // The above result correctly rounded using ROUND_CEIL to 1 decimal place should be 2.7, but it\r\n // will be given as 2.6 as there are 15 zeros immediately after the requested decimal place, so\r\n // the exact result would be assumed to be 2.6, which rounded using ROUND_CEIL to 1 decimal\r\n // place is still 2.6.\r\n if (checkRoundingDigits(r.d, k = pr, rm)) {\r\n\r\n do {\r\n sd += 10;\r\n num = naturalLogarithm(arg, sd);\r\n denominator = isBase10 ? getLn10(Ctor, sd + 10) : naturalLogarithm(base, sd);\r\n r = divide(num, denominator, sd, 1);\r\n\r\n if (!inf) {\r\n\r\n // Check for 14 nines from the 2nd rounding digit, as the first may be 4.\r\n if (+digitsToString(r.d).slice(k + 1, k + 15) + 1 == 1e14) {\r\n r = finalise(r, pr + 1, 0);\r\n }\r\n\r\n break;\r\n }\r\n } while (checkRoundingDigits(r.d, k += 10, rm));\r\n }\r\n\r\n external = true;\r\n\r\n return finalise(r, pr, rm);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the maximum of the arguments and the value of this Decimal.\r\n *\r\n * arguments {number|string|Decimal}\r\n *\r\nP.max = function () {\r\n Array.prototype.push.call(arguments, this);\r\n return maxOrMin(this.constructor, arguments, 'lt');\r\n};\r\n */\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the minimum of the arguments and the value of this Decimal.\r\n *\r\n * arguments {number|string|Decimal}\r\n *\r\nP.min = function () {\r\n Array.prototype.push.call(arguments, this);\r\n return maxOrMin(this.constructor, arguments, 'gt');\r\n};\r\n */\r\n\r\n\r\n/*\r\n * n - 0 = n\r\n * n - N = N\r\n * n - I = -I\r\n * 0 - n = -n\r\n * 0 - 0 = 0\r\n * 0 - N = N\r\n * 0 - I = -I\r\n * N - n = N\r\n * N - 0 = N\r\n * N - N = N\r\n * N - I = N\r\n * I - n = I\r\n * I - 0 = I\r\n * I - N = N\r\n * I - I = N\r\n *\r\n * Return a new Decimal whose value is the value of this Decimal minus `y`, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n */\r\nP.minus = P.sub = function (y) {\r\n var d, e, i, j, k, len, pr, rm, xd, xe, xLTy, yd,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n y = new Ctor(y);\r\n\r\n // If either is not finite...\r\n if (!x.d || !y.d) {\r\n\r\n // Return NaN if either is NaN.\r\n if (!x.s || !y.s) y = new Ctor(NaN);\r\n\r\n // Return y negated if x is finite and y is ±Infinity.\r\n else if (x.d) y.s = -y.s;\r\n\r\n // Return x if y is finite and x is ±Infinity.\r\n // Return x if both are ±Infinity with different signs.\r\n // Return NaN if both are ±Infinity with the same sign.\r\n else y = new Ctor(y.d || x.s !== y.s ? x : NaN);\r\n\r\n return y;\r\n }\r\n\r\n // If signs differ...\r\n if (x.s != y.s) {\r\n y.s = -y.s;\r\n return x.plus(y);\r\n }\r\n\r\n xd = x.d;\r\n yd = y.d;\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n\r\n // If either is zero...\r\n if (!xd[0] || !yd[0]) {\r\n\r\n // Return y negated if x is zero and y is non-zero.\r\n if (yd[0]) y.s = -y.s;\r\n\r\n // Return x if y is zero and x is non-zero.\r\n else if (xd[0]) y = new Ctor(x);\r\n\r\n // Return zero if both are zero.\r\n // From IEEE 754 (2008) 6.3: 0 - 0 = -0 - -0 = -0 when rounding to -Infinity.\r\n else return new Ctor(rm === 3 ? -0 : 0);\r\n\r\n return external ? finalise(y, pr, rm) : y;\r\n }\r\n\r\n // x and y are finite, non-zero numbers with the same sign.\r\n\r\n // Calculate base 1e7 exponents.\r\n e = mathfloor(y.e / LOG_BASE);\r\n xe = mathfloor(x.e / LOG_BASE);\r\n\r\n xd = xd.slice();\r\n k = xe - e;\r\n\r\n // If base 1e7 exponents differ...\r\n if (k) {\r\n xLTy = k < 0;\r\n\r\n if (xLTy) {\r\n d = xd;\r\n k = -k;\r\n len = yd.length;\r\n } else {\r\n d = yd;\r\n e = xe;\r\n len = xd.length;\r\n }\r\n\r\n // Numbers with massively different exponents would result in a very high number of\r\n // zeros needing to be prepended, but this can be avoided while still ensuring correct\r\n // rounding by limiting the number of zeros to `Math.ceil(pr / LOG_BASE) + 2`.\r\n i = Math.max(Math.ceil(pr / LOG_BASE), len) + 2;\r\n\r\n if (k > i) {\r\n k = i;\r\n d.length = 1;\r\n }\r\n\r\n // Prepend zeros to equalise exponents.\r\n d.reverse();\r\n for (i = k; i--;) d.push(0);\r\n d.reverse();\r\n\r\n // Base 1e7 exponents equal.\r\n } else {\r\n\r\n // Check digits to determine which is the bigger number.\r\n\r\n i = xd.length;\r\n len = yd.length;\r\n xLTy = i < len;\r\n if (xLTy) len = i;\r\n\r\n for (i = 0; i < len; i++) {\r\n if (xd[i] != yd[i]) {\r\n xLTy = xd[i] < yd[i];\r\n break;\r\n }\r\n }\r\n\r\n k = 0;\r\n }\r\n\r\n if (xLTy) {\r\n d = xd;\r\n xd = yd;\r\n yd = d;\r\n y.s = -y.s;\r\n }\r\n\r\n len = xd.length;\r\n\r\n // Append zeros to `xd` if shorter.\r\n // Don't add zeros to `yd` if shorter as subtraction only needs to start at `yd` length.\r\n for (i = yd.length - len; i > 0; --i) xd[len++] = 0;\r\n\r\n // Subtract yd from xd.\r\n for (i = yd.length; i > k;) {\r\n\r\n if (xd[--i] < yd[i]) {\r\n for (j = i; j && xd[--j] === 0;) xd[j] = BASE - 1;\r\n --xd[j];\r\n xd[i] += BASE;\r\n }\r\n\r\n xd[i] -= yd[i];\r\n }\r\n\r\n // Remove trailing zeros.\r\n for (; xd[--len] === 0;) xd.pop();\r\n\r\n // Remove leading zeros and adjust exponent accordingly.\r\n for (; xd[0] === 0; xd.shift()) --e;\r\n\r\n // Zero?\r\n if (!xd[0]) return new Ctor(rm === 3 ? -0 : 0);\r\n\r\n y.d = xd;\r\n y.e = getBase10Exponent(xd, e);\r\n\r\n return external ? finalise(y, pr, rm) : y;\r\n};\r\n\r\n\r\n/*\r\n * n % 0 = N\r\n * n % N = N\r\n * n % I = n\r\n * 0 % n = 0\r\n * -0 % n = -0\r\n * 0 % 0 = N\r\n * 0 % N = N\r\n * 0 % I = 0\r\n * N % n = N\r\n * N % 0 = N\r\n * N % N = N\r\n * N % I = N\r\n * I % n = N\r\n * I % 0 = N\r\n * I % N = N\r\n * I % I = N\r\n *\r\n * Return a new Decimal whose value is the value of this Decimal modulo `y`, rounded to\r\n * `precision` significant digits using rounding mode `rounding`.\r\n *\r\n * The result depends on the modulo mode.\r\n *\r\n */\r\nP.modulo = P.mod = function (y) {\r\n var q,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n y = new Ctor(y);\r\n\r\n // Return NaN if x is ±Infinity or NaN, or y is NaN or ±0.\r\n if (!x.d || !y.s || y.d && !y.d[0]) return new Ctor(NaN);\r\n\r\n // Return x if y is ±Infinity or x is ±0.\r\n if (!y.d || x.d && !x.d[0]) {\r\n return finalise(new Ctor(x), Ctor.precision, Ctor.rounding);\r\n }\r\n\r\n // Prevent rounding of intermediate calculations.\r\n external = false;\r\n\r\n if (Ctor.modulo == 9) {\r\n\r\n // Euclidian division: q = sign(y) * floor(x / abs(y))\r\n // result = x - q * y where 0 <= result < abs(y)\r\n q = divide(x, y.abs(), 0, 3, 1);\r\n q.s *= y.s;\r\n } else {\r\n q = divide(x, y, 0, Ctor.modulo, 1);\r\n }\r\n\r\n q = q.times(y);\r\n\r\n external = true;\r\n\r\n return x.minus(q);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the natural exponential of the value of this Decimal,\r\n * i.e. the base e raised to the power the value of this Decimal, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n */\r\nP.naturalExponential = P.exp = function () {\r\n return naturalExponential(this);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the natural logarithm of the value of this Decimal,\r\n * rounded to `precision` significant digits using rounding mode `rounding`.\r\n *\r\n */\r\nP.naturalLogarithm = P.ln = function () {\r\n return naturalLogarithm(this);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the value of this Decimal negated, i.e. as if multiplied by\r\n * -1.\r\n *\r\n */\r\nP.negated = P.neg = function () {\r\n var x = new this.constructor(this);\r\n x.s = -x.s;\r\n return finalise(x);\r\n};\r\n\r\n\r\n/*\r\n * n + 0 = n\r\n * n + N = N\r\n * n + I = I\r\n * 0 + n = n\r\n * 0 + 0 = 0\r\n * 0 + N = N\r\n * 0 + I = I\r\n * N + n = N\r\n * N + 0 = N\r\n * N + N = N\r\n * N + I = N\r\n * I + n = I\r\n * I + 0 = I\r\n * I + N = N\r\n * I + I = I\r\n *\r\n * Return a new Decimal whose value is the value of this Decimal plus `y`, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n */\r\nP.plus = P.add = function (y) {\r\n var carry, d, e, i, k, len, pr, rm, xd, yd,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n y = new Ctor(y);\r\n\r\n // If either is not finite...\r\n if (!x.d || !y.d) {\r\n\r\n // Return NaN if either is NaN.\r\n if (!x.s || !y.s) y = new Ctor(NaN);\r\n\r\n // Return x if y is finite and x is ±Infinity.\r\n // Return x if both are ±Infinity with the same sign.\r\n // Return NaN if both are ±Infinity with different signs.\r\n // Return y if x is finite and y is ±Infinity.\r\n else if (!x.d) y = new Ctor(y.d || x.s === y.s ? x : NaN);\r\n\r\n return y;\r\n }\r\n\r\n // If signs differ...\r\n if (x.s != y.s) {\r\n y.s = -y.s;\r\n return x.minus(y);\r\n }\r\n\r\n xd = x.d;\r\n yd = y.d;\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n\r\n // If either is zero...\r\n if (!xd[0] || !yd[0]) {\r\n\r\n // Return x if y is zero.\r\n // Return y if y is non-zero.\r\n if (!yd[0]) y = new Ctor(x);\r\n\r\n return external ? finalise(y, pr, rm) : y;\r\n }\r\n\r\n // x and y are finite, non-zero numbers with the same sign.\r\n\r\n // Calculate base 1e7 exponents.\r\n k = mathfloor(x.e / LOG_BASE);\r\n e = mathfloor(y.e / LOG_BASE);\r\n\r\n xd = xd.slice();\r\n i = k - e;\r\n\r\n // If base 1e7 exponents differ...\r\n if (i) {\r\n\r\n if (i < 0) {\r\n d = xd;\r\n i = -i;\r\n len = yd.length;\r\n } else {\r\n d = yd;\r\n e = k;\r\n len = xd.length;\r\n }\r\n\r\n // Limit number of zeros prepended to max(ceil(pr / LOG_BASE), len) + 1.\r\n k = Math.ceil(pr / LOG_BASE);\r\n len = k > len ? k + 1 : len + 1;\r\n\r\n if (i > len) {\r\n i = len;\r\n d.length = 1;\r\n }\r\n\r\n // Prepend zeros to equalise exponents. Note: Faster to use reverse then do unshifts.\r\n d.reverse();\r\n for (; i--;) d.push(0);\r\n d.reverse();\r\n }\r\n\r\n len = xd.length;\r\n i = yd.length;\r\n\r\n // If yd is longer than xd, swap xd and yd so xd points to the longer array.\r\n if (len - i < 0) {\r\n i = len;\r\n d = yd;\r\n yd = xd;\r\n xd = d;\r\n }\r\n\r\n // Only start adding at yd.length - 1 as the further digits of xd can be left as they are.\r\n for (carry = 0; i;) {\r\n carry = (xd[--i] = xd[i] + yd[i] + carry) / BASE | 0;\r\n xd[i] %= BASE;\r\n }\r\n\r\n if (carry) {\r\n xd.unshift(carry);\r\n ++e;\r\n }\r\n\r\n // Remove trailing zeros.\r\n // No need to check for zero, as +x + +y != 0 && -x + -y != 0\r\n for (len = xd.length; xd[--len] == 0;) xd.pop();\r\n\r\n y.d = xd;\r\n y.e = getBase10Exponent(xd, e);\r\n\r\n return external ? finalise(y, pr, rm) : y;\r\n};\r\n\r\n\r\n/*\r\n * Return the number of significant digits of the value of this Decimal.\r\n *\r\n * [z] {boolean|number} Whether to count integer-part trailing zeros: true, false, 1 or 0.\r\n *\r\n */\r\nP.precision = P.sd = function (z) {\r\n var k,\r\n x = this;\r\n\r\n if (z !== void 0 && z !== !!z && z !== 1 && z !== 0) throw Error(invalidArgument + z);\r\n\r\n if (x.d) {\r\n k = getPrecision(x.d);\r\n if (z && x.e + 1 > k) k = x.e + 1;\r\n } else {\r\n k = NaN;\r\n }\r\n\r\n return k;\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the value of this Decimal rounded to a whole number using\r\n * rounding mode `rounding`.\r\n *\r\n */\r\nP.round = function () {\r\n var x = this,\r\n Ctor = x.constructor;\r\n\r\n return finalise(new Ctor(x), x.e + 1, Ctor.rounding);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the sine of the value in radians of this Decimal.\r\n *\r\n * Domain: [-Infinity, Infinity]\r\n * Range: [-1, 1]\r\n *\r\n * sin(x) = x - x^3/3! + x^5/5! - ...\r\n *\r\n * sin(0) = 0\r\n * sin(-0) = -0\r\n * sin(Infinity) = NaN\r\n * sin(-Infinity) = NaN\r\n * sin(NaN) = NaN\r\n *\r\n */\r\nP.sine = P.sin = function () {\r\n var pr, rm,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (!x.isFinite()) return new Ctor(NaN);\r\n if (x.isZero()) return new Ctor(x);\r\n\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n Ctor.precision = pr + Math.max(x.e, x.sd()) + LOG_BASE;\r\n Ctor.rounding = 1;\r\n\r\n x = sine(Ctor, toLessThanHalfPi(Ctor, x));\r\n\r\n Ctor.precision = pr;\r\n Ctor.rounding = rm;\r\n\r\n return finalise(quadrant > 2 ? x.neg() : x, pr, rm, true);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the square root of this Decimal, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * sqrt(-n) = N\r\n * sqrt(N) = N\r\n * sqrt(-I) = N\r\n * sqrt(I) = I\r\n * sqrt(0) = 0\r\n * sqrt(-0) = -0\r\n *\r\n */\r\nP.squareRoot = P.sqrt = function () {\r\n var m, n, sd, r, rep, t,\r\n x = this,\r\n d = x.d,\r\n e = x.e,\r\n s = x.s,\r\n Ctor = x.constructor;\r\n\r\n // Negative/NaN/Infinity/zero?\r\n if (s !== 1 || !d || !d[0]) {\r\n return new Ctor(!s || s < 0 && (!d || d[0]) ? NaN : d ? x : 1 / 0);\r\n }\r\n\r\n external = false;\r\n\r\n // Initial estimate.\r\n s = Math.sqrt(+x);\r\n\r\n // Math.sqrt underflow/overflow?\r\n // Pass x to Math.sqrt as integer, then adjust the exponent of the result.\r\n if (s == 0 || s == 1 / 0) {\r\n n = digitsToString(d);\r\n\r\n if ((n.length + e) % 2 == 0) n += '0';\r\n s = Math.sqrt(n);\r\n e = mathfloor((e + 1) / 2) - (e < 0 || e % 2);\r\n\r\n if (s == 1 / 0) {\r\n n = '5e' + e;\r\n } else {\r\n n = s.toExponential();\r\n n = n.slice(0, n.indexOf('e') + 1) + e;\r\n }\r\n\r\n r = new Ctor(n);\r\n } else {\r\n r = new Ctor(s.toString());\r\n }\r\n\r\n sd = (e = Ctor.precision) + 3;\r\n\r\n // Newton-Raphson iteration.\r\n for (;;) {\r\n t = r;\r\n r = t.plus(divide(x, t, sd + 2, 1)).times(0.5);\r\n\r\n // TODO? Replace with for-loop and checkRoundingDigits.\r\n if (digitsToString(t.d).slice(0, sd) === (n = digitsToString(r.d)).slice(0, sd)) {\r\n n = n.slice(sd - 3, sd + 1);\r\n\r\n // The 4th rounding digit may be in error by -1 so if the 4 rounding digits are 9999 or\r\n // 4999, i.e. approaching a rounding boundary, continue the iteration.\r\n if (n == '9999' || !rep && n == '4999') {\r\n\r\n // On the first iteration only, check to see if rounding up gives the exact result as the\r\n // nines may infinitely repeat.\r\n if (!rep) {\r\n finalise(t, e + 1, 0);\r\n\r\n if (t.times(t).eq(x)) {\r\n r = t;\r\n break;\r\n }\r\n }\r\n\r\n sd += 4;\r\n rep = 1;\r\n } else {\r\n\r\n // If the rounding digits are null, 0{0,4} or 50{0,3}, check for an exact result.\r\n // If not, then there are further digits and m will be truthy.\r\n if (!+n || !+n.slice(1) && n.charAt(0) == '5') {\r\n\r\n // Truncate to the first rounding digit.\r\n finalise(r, e + 1, 1);\r\n m = !r.times(r).eq(x);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n }\r\n\r\n external = true;\r\n\r\n return finalise(r, e, Ctor.rounding, m);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the tangent of the value in radians of this Decimal.\r\n *\r\n * Domain: [-Infinity, Infinity]\r\n * Range: [-Infinity, Infinity]\r\n *\r\n * tan(0) = 0\r\n * tan(-0) = -0\r\n * tan(Infinity) = NaN\r\n * tan(-Infinity) = NaN\r\n * tan(NaN) = NaN\r\n *\r\n */\r\nP.tangent = P.tan = function () {\r\n var pr, rm,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (!x.isFinite()) return new Ctor(NaN);\r\n if (x.isZero()) return new Ctor(x);\r\n\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n Ctor.precision = pr + 10;\r\n Ctor.rounding = 1;\r\n\r\n x = x.sin();\r\n x.s = 1;\r\n x = divide(x, new Ctor(1).minus(x.times(x)).sqrt(), pr + 10, 0);\r\n\r\n Ctor.precision = pr;\r\n Ctor.rounding = rm;\r\n\r\n return finalise(quadrant == 2 || quadrant == 4 ? x.neg() : x, pr, rm, true);\r\n};\r\n\r\n\r\n/*\r\n * n * 0 = 0\r\n * n * N = N\r\n * n * I = I\r\n * 0 * n = 0\r\n * 0 * 0 = 0\r\n * 0 * N = N\r\n * 0 * I = N\r\n * N * n = N\r\n * N * 0 = N\r\n * N * N = N\r\n * N * I = N\r\n * I * n = I\r\n * I * 0 = N\r\n * I * N = N\r\n * I * I = I\r\n *\r\n * Return a new Decimal whose value is this Decimal times `y`, rounded to `precision` significant\r\n * digits using rounding mode `rounding`.\r\n *\r\n */\r\nP.times = P.mul = function (y) {\r\n var carry, e, i, k, r, rL, t, xdL, ydL,\r\n x = this,\r\n Ctor = x.constructor,\r\n xd = x.d,\r\n yd = (y = new Ctor(y)).d;\r\n\r\n y.s *= x.s;\r\n\r\n // If either is NaN, ±Infinity or ±0...\r\n if (!xd || !xd[0] || !yd || !yd[0]) {\r\n\r\n return new Ctor(!y.s || xd && !xd[0] && !yd || yd && !yd[0] && !xd\r\n\r\n // Return NaN if either is NaN.\r\n // Return NaN if x is ±0 and y is ±Infinity, or y is ±0 and x is ±Infinity.\r\n ? NaN\r\n\r\n // Return ±Infinity if either is ±Infinity.\r\n // Return ±0 if either is ±0.\r\n : !xd || !yd ? y.s / 0 : y.s * 0);\r\n }\r\n\r\n e = mathfloor(x.e / LOG_BASE) + mathfloor(y.e / LOG_BASE);\r\n xdL = xd.length;\r\n ydL = yd.length;\r\n\r\n // Ensure xd points to the longer array.\r\n if (xdL < ydL) {\r\n r = xd;\r\n xd = yd;\r\n yd = r;\r\n rL = xdL;\r\n xdL = ydL;\r\n ydL = rL;\r\n }\r\n\r\n // Initialise the result array with zeros.\r\n r = [];\r\n rL = xdL + ydL;\r\n for (i = rL; i--;) r.push(0);\r\n\r\n // Multiply!\r\n for (i = ydL; --i >= 0;) {\r\n carry = 0;\r\n for (k = xdL + i; k > i;) {\r\n t = r[k] + yd[i] * xd[k - i - 1] + carry;\r\n r[k--] = t % BASE | 0;\r\n carry = t / BASE | 0;\r\n }\r\n\r\n r[k] = (r[k] + carry) % BASE | 0;\r\n }\r\n\r\n // Remove trailing zeros.\r\n for (; !r[--rL];) r.pop();\r\n\r\n if (carry) ++e;\r\n else r.shift();\r\n\r\n y.d = r;\r\n y.e = getBase10Exponent(r, e);\r\n\r\n return external ? finalise(y, Ctor.precision, Ctor.rounding) : y;\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Decimal in base 2, round to `sd` significant\r\n * digits using rounding mode `rm`.\r\n *\r\n * If the optional `sd` argument is present then return binary exponential notation.\r\n *\r\n * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n */\r\nP.toBinary = function (sd, rm) {\r\n return toStringBinary(this, 2, sd, rm);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the value of this Decimal rounded to a maximum of `dp`\r\n * decimal places using rounding mode `rm` or `rounding` if `rm` is omitted.\r\n *\r\n * If `dp` is omitted, return a new Decimal whose value is the value of this Decimal.\r\n *\r\n * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n */\r\nP.toDecimalPlaces = P.toDP = function (dp, rm) {\r\n var x = this,\r\n Ctor = x.constructor;\r\n\r\n x = new Ctor(x);\r\n if (dp === void 0) return x;\r\n\r\n checkInt32(dp, 0, MAX_DIGITS);\r\n\r\n if (rm === void 0) rm = Ctor.rounding;\r\n else checkInt32(rm, 0, 8);\r\n\r\n return finalise(x, dp + x.e + 1, rm);\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Decimal in exponential notation rounded to\r\n * `dp` fixed decimal places using rounding mode `rounding`.\r\n *\r\n * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n */\r\nP.toExponential = function (dp, rm) {\r\n var str,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (dp === void 0) {\r\n str = finiteToString(x, true);\r\n } else {\r\n checkInt32(dp, 0, MAX_DIGITS);\r\n\r\n if (rm === void 0) rm = Ctor.rounding;\r\n else checkInt32(rm, 0, 8);\r\n\r\n x = finalise(new Ctor(x), dp + 1, rm);\r\n str = finiteToString(x, true, dp + 1);\r\n }\r\n\r\n return x.isNeg() && !x.isZero() ? '-' + str : str;\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Decimal in normal (fixed-point) notation to\r\n * `dp` fixed decimal places and rounded using rounding mode `rm` or `rounding` if `rm` is\r\n * omitted.\r\n *\r\n * As with JavaScript numbers, (-0).toFixed(0) is '0', but e.g. (-0.00001).toFixed(0) is '-0'.\r\n *\r\n * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n * (-0).toFixed(0) is '0', but (-0.1).toFixed(0) is '-0'.\r\n * (-0).toFixed(1) is '0.0', but (-0.01).toFixed(1) is '-0.0'.\r\n * (-0).toFixed(3) is '0.000'.\r\n * (-0.5).toFixed(0) is '-0'.\r\n *\r\n */\r\nP.toFixed = function (dp, rm) {\r\n var str, y,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (dp === void 0) {\r\n str = finiteToString(x);\r\n } else {\r\n checkInt32(dp, 0, MAX_DIGITS);\r\n\r\n if (rm === void 0) rm = Ctor.rounding;\r\n else checkInt32(rm, 0, 8);\r\n\r\n y = finalise(new Ctor(x), dp + x.e + 1, rm);\r\n str = finiteToString(y, false, dp + y.e + 1);\r\n }\r\n\r\n // To determine whether to add the minus sign look at the value before it was rounded,\r\n // i.e. look at `x` rather than `y`.\r\n return x.isNeg() && !x.isZero() ? '-' + str : str;\r\n};\r\n\r\n\r\n/*\r\n * Return an array representing the value of this Decimal as a simple fraction with an integer\r\n * numerator and an integer denominator.\r\n *\r\n * The denominator will be a positive non-zero value less than or equal to the specified maximum\r\n * denominator. If a maximum denominator is not specified, the denominator will be the lowest\r\n * value necessary to represent the number exactly.\r\n *\r\n * [maxD] {number|string|Decimal} Maximum denominator. Integer >= 1 and < Infinity.\r\n *\r\n */\r\nP.toFraction = function (maxD) {\r\n var d, d0, d1, d2, e, k, n, n0, n1, pr, q, r,\r\n x = this,\r\n xd = x.d,\r\n Ctor = x.constructor;\r\n\r\n if (!xd) return new Ctor(x);\r\n\r\n n1 = d0 = new Ctor(1);\r\n d1 = n0 = new Ctor(0);\r\n\r\n d = new Ctor(d1);\r\n e = d.e = getPrecision(xd) - x.e - 1;\r\n k = e % LOG_BASE;\r\n d.d[0] = mathpow(10, k < 0 ? LOG_BASE + k : k);\r\n\r\n if (maxD == null) {\r\n\r\n // d is 10**e, the minimum max-denominator needed.\r\n maxD = e > 0 ? d : n1;\r\n } else {\r\n n = new Ctor(maxD);\r\n if (!n.isInt() || n.lt(n1)) throw Error(invalidArgument + n);\r\n maxD = n.gt(d) ? (e > 0 ? d : n1) : n;\r\n }\r\n\r\n external = false;\r\n n = new Ctor(digitsToString(xd));\r\n pr = Ctor.precision;\r\n Ctor.precision = e = xd.length * LOG_BASE * 2;\r\n\r\n for (;;) {\r\n q = divide(n, d, 0, 1, 1);\r\n d2 = d0.plus(q.times(d1));\r\n if (d2.cmp(maxD) == 1) break;\r\n d0 = d1;\r\n d1 = d2;\r\n d2 = n1;\r\n n1 = n0.plus(q.times(d2));\r\n n0 = d2;\r\n d2 = d;\r\n d = n.minus(q.times(d2));\r\n n = d2;\r\n }\r\n\r\n d2 = divide(maxD.minus(d0), d1, 0, 1, 1);\r\n n0 = n0.plus(d2.times(n1));\r\n d0 = d0.plus(d2.times(d1));\r\n n0.s = n1.s = x.s;\r\n\r\n // Determine which fraction is closer to x, n0/d0 or n1/d1?\r\n r = divide(n1, d1, e, 1).minus(x).abs().cmp(divide(n0, d0, e, 1).minus(x).abs()) < 1\r\n ? [n1, d1] : [n0, d0];\r\n\r\n Ctor.precision = pr;\r\n external = true;\r\n\r\n return r;\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Decimal in base 16, round to `sd` significant\r\n * digits using rounding mode `rm`.\r\n *\r\n * If the optional `sd` argument is present then return binary exponential notation.\r\n *\r\n * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n */\r\nP.toHexadecimal = P.toHex = function (sd, rm) {\r\n return toStringBinary(this, 16, sd, rm);\r\n};\r\n\r\n\r\n/*\r\n * Returns a new Decimal whose value is the nearest multiple of `y` in the direction of rounding\r\n * mode `rm`, or `Decimal.rounding` if `rm` is omitted, to the value of this Decimal.\r\n *\r\n * The return value will always have the same sign as this Decimal, unless either this Decimal\r\n * or `y` is NaN, in which case the return value will be also be NaN.\r\n *\r\n * The return value is not affected by the value of `precision`.\r\n *\r\n * y {number|string|Decimal} The magnitude to round to a multiple of.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n * 'toNearest() rounding mode not an integer: {rm}'\r\n * 'toNearest() rounding mode out of range: {rm}'\r\n *\r\n */\r\nP.toNearest = function (y, rm) {\r\n var x = this,\r\n Ctor = x.constructor;\r\n\r\n x = new Ctor(x);\r\n\r\n if (y == null) {\r\n\r\n // If x is not finite, return x.\r\n if (!x.d) return x;\r\n\r\n y = new Ctor(1);\r\n rm = Ctor.rounding;\r\n } else {\r\n y = new Ctor(y);\r\n if (rm === void 0) {\r\n rm = Ctor.rounding;\r\n } else {\r\n checkInt32(rm, 0, 8);\r\n }\r\n\r\n // If x is not finite, return x if y is not NaN, else NaN.\r\n if (!x.d) return y.s ? x : y;\r\n\r\n // If y is not finite, return Infinity with the sign of x if y is Infinity, else NaN.\r\n if (!y.d) {\r\n if (y.s) y.s = x.s;\r\n return y;\r\n }\r\n }\r\n\r\n // If y is not zero, calculate the nearest multiple of y to x.\r\n if (y.d[0]) {\r\n external = false;\r\n x = divide(x, y, 0, rm, 1).times(y);\r\n external = true;\r\n finalise(x);\r\n\r\n // If y is zero, return zero with the sign of x.\r\n } else {\r\n y.s = x.s;\r\n x = y;\r\n }\r\n\r\n return x;\r\n};\r\n\r\n\r\n/*\r\n * Return the value of this Decimal converted to a number primitive.\r\n * Zero keeps its sign.\r\n *\r\n */\r\nP.toNumber = function () {\r\n return +this;\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Decimal in base 8, round to `sd` significant\r\n * digits using rounding mode `rm`.\r\n *\r\n * If the optional `sd` argument is present then return binary exponential notation.\r\n *\r\n * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n */\r\nP.toOctal = function (sd, rm) {\r\n return toStringBinary(this, 8, sd, rm);\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the value of this Decimal raised to the power `y`, rounded\r\n * to `precision` significant digits using rounding mode `rounding`.\r\n *\r\n * ECMAScript compliant.\r\n *\r\n * pow(x, NaN) = NaN\r\n * pow(x, ±0) = 1\r\n\r\n * pow(NaN, non-zero) = NaN\r\n * pow(abs(x) > 1, +Infinity) = +Infinity\r\n * pow(abs(x) > 1, -Infinity) = +0\r\n * pow(abs(x) == 1, ±Infinity) = NaN\r\n * pow(abs(x) < 1, +Infinity) = +0\r\n * pow(abs(x) < 1, -Infinity) = +Infinity\r\n * pow(+Infinity, y > 0) = +Infinity\r\n * pow(+Infinity, y < 0) = +0\r\n * pow(-Infinity, odd integer > 0) = -Infinity\r\n * pow(-Infinity, even integer > 0) = +Infinity\r\n * pow(-Infinity, odd integer < 0) = -0\r\n * pow(-Infinity, even integer < 0) = +0\r\n * pow(+0, y > 0) = +0\r\n * pow(+0, y < 0) = +Infinity\r\n * pow(-0, odd integer > 0) = -0\r\n * pow(-0, even integer > 0) = +0\r\n * pow(-0, odd integer < 0) = -Infinity\r\n * pow(-0, even integer < 0) = +Infinity\r\n * pow(finite x < 0, finite non-integer) = NaN\r\n *\r\n * For non-integer or very large exponents pow(x, y) is calculated using\r\n *\r\n * x^y = exp(y*ln(x))\r\n *\r\n * Assuming the first 15 rounding digits are each equally likely to be any digit 0-9, the\r\n * probability of an incorrectly rounded result\r\n * P([49]9{14} | [50]0{14}) = 2 * 0.2 * 10^-14 = 4e-15 = 1/2.5e+14\r\n * i.e. 1 in 250,000,000,000,000\r\n *\r\n * If a result is incorrectly rounded the maximum error will be 1 ulp (unit in last place).\r\n *\r\n * y {number|string|Decimal} The power to which to raise this Decimal.\r\n *\r\n */\r\nP.toPower = P.pow = function (y) {\r\n var e, k, pr, r, rm, s,\r\n x = this,\r\n Ctor = x.constructor,\r\n yn = +(y = new Ctor(y));\r\n\r\n // Either ±Infinity, NaN or ±0?\r\n if (!x.d || !y.d || !x.d[0] || !y.d[0]) return new Ctor(mathpow(+x, yn));\r\n\r\n x = new Ctor(x);\r\n\r\n if (x.eq(1)) return x;\r\n\r\n pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n\r\n if (y.eq(1)) return finalise(x, pr, rm);\r\n\r\n // y exponent\r\n e = mathfloor(y.e / LOG_BASE);\r\n\r\n // If y is a small integer use the 'exponentiation by squaring' algorithm.\r\n if (e >= y.d.length - 1 && (k = yn < 0 ? -yn : yn) <= MAX_SAFE_INTEGER) {\r\n r = intPow(Ctor, x, k, pr);\r\n return y.s < 0 ? new Ctor(1).div(r) : finalise(r, pr, rm);\r\n }\r\n\r\n s = x.s;\r\n\r\n // if x is negative\r\n if (s < 0) {\r\n\r\n // if y is not an integer\r\n if (e < y.d.length - 1) return new Ctor(NaN);\r\n\r\n // Result is positive if x is negative and the last digit of integer y is even.\r\n if ((y.d[e] & 1) == 0) s = 1;\r\n\r\n // if x.eq(-1)\r\n if (x.e == 0 && x.d[0] == 1 && x.d.length == 1) {\r\n x.s = s;\r\n return x;\r\n }\r\n }\r\n\r\n // Estimate result exponent.\r\n // x^y = 10^e, where e = y * log10(x)\r\n // log10(x) = log10(x_significand) + x_exponent\r\n // log10(x_significand) = ln(x_significand) / ln(10)\r\n k = mathpow(+x, yn);\r\n e = k == 0 || !isFinite(k)\r\n ? mathfloor(yn * (Math.log('0.' + digitsToString(x.d)) / Math.LN10 + x.e + 1))\r\n : new Ctor(k + '').e;\r\n\r\n // Exponent estimate may be incorrect e.g. x: 0.999999999999999999, y: 2.29, e: 0, r.e: -1.\r\n\r\n // Overflow/underflow?\r\n if (e > Ctor.maxE + 1 || e < Ctor.minE - 1) return new Ctor(e > 0 ? s / 0 : 0);\r\n\r\n external = false;\r\n Ctor.rounding = x.s = 1;\r\n\r\n // Estimate the extra guard digits needed to ensure five correct rounding digits from\r\n // naturalLogarithm(x). Example of failure without these extra digits (precision: 10):\r\n // new Decimal(2.32456).pow('2087987436534566.46411')\r\n // should be 1.162377823e+764914905173815, but is 1.162355823e+764914905173815\r\n k = Math.min(12, (e + '').length);\r\n\r\n // r = x^y = exp(y*ln(x))\r\n r = naturalExponential(y.times(naturalLogarithm(x, pr + k)), pr);\r\n\r\n // r may be Infinity, e.g. (0.9999999999999999).pow(-1e+40)\r\n if (r.d) {\r\n\r\n // Truncate to the required precision plus five rounding digits.\r\n r = finalise(r, pr + 5, 1);\r\n\r\n // If the rounding digits are [49]9999 or [50]0000 increase the precision by 10 and recalculate\r\n // the result.\r\n if (checkRoundingDigits(r.d, pr, rm)) {\r\n e = pr + 10;\r\n\r\n // Truncate to the increased precision plus five rounding digits.\r\n r = finalise(naturalExponential(y.times(naturalLogarithm(x, e + k)), e), e + 5, 1);\r\n\r\n // Check for 14 nines from the 2nd rounding digit (the first rounding digit may be 4 or 9).\r\n if (+digitsToString(r.d).slice(pr + 1, pr + 15) + 1 == 1e14) {\r\n r = finalise(r, pr + 1, 0);\r\n }\r\n }\r\n }\r\n\r\n r.s = s;\r\n external = true;\r\n Ctor.rounding = rm;\r\n\r\n return finalise(r, pr, rm);\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Decimal rounded to `sd` significant digits\r\n * using rounding mode `rounding`.\r\n *\r\n * Return exponential notation if `sd` is less than the number of digits necessary to represent\r\n * the integer part of the value in normal notation.\r\n *\r\n * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n */\r\nP.toPrecision = function (sd, rm) {\r\n var str,\r\n x = this,\r\n Ctor = x.constructor;\r\n\r\n if (sd === void 0) {\r\n str = finiteToString(x, x.e <= Ctor.toExpNeg || x.e >= Ctor.toExpPos);\r\n } else {\r\n checkInt32(sd, 1, MAX_DIGITS);\r\n\r\n if (rm === void 0) rm = Ctor.rounding;\r\n else checkInt32(rm, 0, 8);\r\n\r\n x = finalise(new Ctor(x), sd, rm);\r\n str = finiteToString(x, sd <= x.e || x.e <= Ctor.toExpNeg, sd);\r\n }\r\n\r\n return x.isNeg() && !x.isZero() ? '-' + str : str;\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the value of this Decimal rounded to a maximum of `sd`\r\n * significant digits using rounding mode `rm`, or to `precision` and `rounding` respectively if\r\n * omitted.\r\n *\r\n * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive.\r\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\r\n *\r\n * 'toSD() digits out of range: {sd}'\r\n * 'toSD() digits not an integer: {sd}'\r\n * 'toSD() rounding mode not an integer: {rm}'\r\n * 'toSD() rounding mode out of range: {rm}'\r\n *\r\n */\r\nP.toSignificantDigits = P.toSD = function (sd, rm) {\r\n var x = this,\r\n Ctor = x.constructor;\r\n\r\n if (sd === void 0) {\r\n sd = Ctor.precision;\r\n rm = Ctor.rounding;\r\n } else {\r\n checkInt32(sd, 1, MAX_DIGITS);\r\n\r\n if (rm === void 0) rm = Ctor.rounding;\r\n else checkInt32(rm, 0, 8);\r\n }\r\n\r\n return finalise(new Ctor(x), sd, rm);\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Decimal.\r\n *\r\n * Return exponential notation if this Decimal has a positive exponent equal to or greater than\r\n * `toExpPos`, or a negative exponent equal to or less than `toExpNeg`.\r\n *\r\n */\r\nP.toString = function () {\r\n var x = this,\r\n Ctor = x.constructor,\r\n str = finiteToString(x, x.e <= Ctor.toExpNeg || x.e >= Ctor.toExpPos);\r\n\r\n return x.isNeg() && !x.isZero() ? '-' + str : str;\r\n};\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the value of this Decimal truncated to a whole number.\r\n *\r\n */\r\nP.truncated = P.trunc = function () {\r\n return finalise(new this.constructor(this), this.e + 1, 1);\r\n};\r\n\r\n\r\n/*\r\n * Return a string representing the value of this Decimal.\r\n * Unlike `toString`, negative zero will include the minus sign.\r\n *\r\n */\r\nP.valueOf = P.toJSON = function () {\r\n var x = this,\r\n Ctor = x.constructor,\r\n str = finiteToString(x, x.e <= Ctor.toExpNeg || x.e >= Ctor.toExpPos);\r\n\r\n return x.isNeg() ? '-' + str : str;\r\n};\r\n\r\n\r\n// Helper functions for Decimal.prototype (P) and/or Decimal methods, and their callers.\r\n\r\n\r\n/*\r\n * digitsToString P.cubeRoot, P.logarithm, P.squareRoot, P.toFraction, P.toPower,\r\n * finiteToString, naturalExponential, naturalLogarithm\r\n * checkInt32 P.toDecimalPlaces, P.toExponential, P.toFixed, P.toNearest,\r\n * P.toPrecision, P.toSignificantDigits, toStringBinary, random\r\n * checkRoundingDigits P.logarithm, P.toPower, naturalExponential, naturalLogarithm\r\n * convertBase toStringBinary, parseOther\r\n * cos P.cos\r\n * divide P.atanh, P.cubeRoot, P.dividedBy, P.dividedToIntegerBy,\r\n * P.logarithm, P.modulo, P.squareRoot, P.tan, P.tanh, P.toFraction,\r\n * P.toNearest, toStringBinary, naturalExponential, naturalLogarithm,\r\n * taylorSeries, atan2, parseOther\r\n * finalise P.absoluteValue, P.atan, P.atanh, P.ceil, P.cos, P.cosh,\r\n * P.cubeRoot, P.dividedToIntegerBy, P.floor, P.logarithm, P.minus,\r\n * P.modulo, P.negated, P.plus, P.round, P.sin, P.sinh, P.squareRoot,\r\n * P.tan, P.times, P.toDecimalPlaces, P.toExponential, P.toFixed,\r\n * P.toNearest, P.toPower, P.toPrecision, P.toSignificantDigits,\r\n * P.truncated, divide, getLn10, getPi, naturalExponential,\r\n * naturalLogarithm, ceil, floor, round, trunc\r\n * finiteToString P.toExponential, P.toFixed, P.toPrecision, P.toString, P.valueOf,\r\n * toStringBinary\r\n * getBase10Exponent P.minus, P.plus, P.times, parseOther\r\n * getLn10 P.logarithm, naturalLogarithm\r\n * getPi P.acos, P.asin, P.atan, toLessThanHalfPi, atan2\r\n * getPrecision P.precision, P.toFraction\r\n * getZeroString digitsToString, finiteToString\r\n * intPow P.toPower, parseOther\r\n * isOdd toLessThanHalfPi\r\n * maxOrMin max, min\r\n * naturalExponential P.naturalExponential, P.toPower\r\n * naturalLogarithm P.acosh, P.asinh, P.atanh, P.logarithm, P.naturalLogarithm,\r\n * P.toPower, naturalExponential\r\n * nonFiniteToString finiteToString, toStringBinary\r\n * parseDecimal Decimal\r\n * parseOther Decimal\r\n * sin P.sin\r\n * taylorSeries P.cosh, P.sinh, cos, sin\r\n * toLessThanHalfPi P.cos, P.sin\r\n * toStringBinary P.toBinary, P.toHexadecimal, P.toOctal\r\n * truncate intPow\r\n *\r\n * Throws: P.logarithm, P.precision, P.toFraction, checkInt32, getLn10, getPi,\r\n * naturalLogarithm, config, parseOther, random, Decimal\r\n */\r\n\r\n\r\nfunction digitsToString(d) {\r\n var i, k, ws,\r\n indexOfLastWord = d.length - 1,\r\n str = '',\r\n w = d[0];\r\n\r\n if (indexOfLastWord > 0) {\r\n str += w;\r\n for (i = 1; i < indexOfLastWord; i++) {\r\n ws = d[i] + '';\r\n k = LOG_BASE - ws.length;\r\n if (k) str += getZeroString(k);\r\n str += ws;\r\n }\r\n\r\n w = d[i];\r\n ws = w + '';\r\n k = LOG_BASE - ws.length;\r\n if (k) str += getZeroString(k);\r\n } else if (w === 0) {\r\n return '0';\r\n }\r\n\r\n // Remove trailing zeros of last w.\r\n for (; w % 10 === 0;) w /= 10;\r\n\r\n return str + w;\r\n}\r\n\r\n\r\nfunction checkInt32(i, min, max) {\r\n if (i !== ~~i || i < min || i > max) {\r\n throw Error(invalidArgument + i);\r\n }\r\n}\r\n\r\n\r\n/*\r\n * Check 5 rounding digits if `repeating` is null, 4 otherwise.\r\n * `repeating == null` if caller is `log` or `pow`,\r\n * `repeating != null` if caller is `naturalLogarithm` or `naturalExponential`.\r\n */\r\nfunction checkRoundingDigits(d, i, rm, repeating) {\r\n var di, k, r, rd;\r\n\r\n // Get the length of the first word of the array d.\r\n for (k = d[0]; k >= 10; k /= 10) --i;\r\n\r\n // Is the rounding digit in the first word of d?\r\n if (--i < 0) {\r\n i += LOG_BASE;\r\n di = 0;\r\n } else {\r\n di = Math.ceil((i + 1) / LOG_BASE);\r\n i %= LOG_BASE;\r\n }\r\n\r\n // i is the index (0 - 6) of the rounding digit.\r\n // E.g. if within the word 3487563 the first rounding digit is 5,\r\n // then i = 4, k = 1000, rd = 3487563 % 1000 = 563\r\n k = mathpow(10, LOG_BASE - i);\r\n rd = d[di] % k | 0;\r\n\r\n if (repeating == null) {\r\n if (i < 3) {\r\n if (i == 0) rd = rd / 100 | 0;\r\n else if (i == 1) rd = rd / 10 | 0;\r\n r = rm < 4 && rd == 99999 || rm > 3 && rd == 49999 || rd == 50000 || rd == 0;\r\n } else {\r\n r = (rm < 4 && rd + 1 == k || rm > 3 && rd + 1 == k / 2) &&\r\n (d[di + 1] / k / 100 | 0) == mathpow(10, i - 2) - 1 ||\r\n (rd == k / 2 || rd == 0) && (d[di + 1] / k / 100 | 0) == 0;\r\n }\r\n } else {\r\n if (i < 4) {\r\n if (i == 0) rd = rd / 1000 | 0;\r\n else if (i == 1) rd = rd / 100 | 0;\r\n else if (i == 2) rd = rd / 10 | 0;\r\n r = (repeating || rm < 4) && rd == 9999 || !repeating && rm > 3 && rd == 4999;\r\n } else {\r\n r = ((repeating || rm < 4) && rd + 1 == k ||\r\n (!repeating && rm > 3) && rd + 1 == k / 2) &&\r\n (d[di + 1] / k / 1000 | 0) == mathpow(10, i - 3) - 1;\r\n }\r\n }\r\n\r\n return r;\r\n}\r\n\r\n\r\n// Convert string of `baseIn` to an array of numbers of `baseOut`.\r\n// Eg. convertBase('255', 10, 16) returns [15, 15].\r\n// Eg. convertBase('ff', 16, 10) returns [2, 5, 5].\r\nfunction convertBase(str, baseIn, baseOut) {\r\n var j,\r\n arr = [0],\r\n arrL,\r\n i = 0,\r\n strL = str.length;\r\n\r\n for (; i < strL;) {\r\n for (arrL = arr.length; arrL--;) arr[arrL] *= baseIn;\r\n arr[0] += NUMERALS.indexOf(str.charAt(i++));\r\n for (j = 0; j < arr.length; j++) {\r\n if (arr[j] > baseOut - 1) {\r\n if (arr[j + 1] === void 0) arr[j + 1] = 0;\r\n arr[j + 1] += arr[j] / baseOut | 0;\r\n arr[j] %= baseOut;\r\n }\r\n }\r\n }\r\n\r\n return arr.reverse();\r\n}\r\n\r\n\r\n/*\r\n * cos(x) = 1 - x^2/2! + x^4/4! - ...\r\n * |x| < pi/2\r\n *\r\n */\r\nfunction cosine(Ctor, x) {\r\n var k, len, y;\r\n\r\n if (x.isZero()) return x;\r\n\r\n // Argument reduction: cos(4x) = 8*(cos^4(x) - cos^2(x)) + 1\r\n // i.e. cos(x) = 8*(cos^4(x/4) - cos^2(x/4)) + 1\r\n\r\n // Estimate the optimum number of times to use the argument reduction.\r\n len = x.d.length;\r\n if (len < 32) {\r\n k = Math.ceil(len / 3);\r\n y = (1 / tinyPow(4, k)).toString();\r\n } else {\r\n k = 16;\r\n y = '2.3283064365386962890625e-10';\r\n }\r\n\r\n Ctor.precision += k;\r\n\r\n x = taylorSeries(Ctor, 1, x.times(y), new Ctor(1));\r\n\r\n // Reverse argument reduction\r\n for (var i = k; i--;) {\r\n var cos2x = x.times(x);\r\n x = cos2x.times(cos2x).minus(cos2x).times(8).plus(1);\r\n }\r\n\r\n Ctor.precision -= k;\r\n\r\n return x;\r\n}\r\n\r\n\r\n/*\r\n * Perform division in the specified base.\r\n */\r\nvar divide = (function () {\r\n\r\n // Assumes non-zero x and k, and hence non-zero result.\r\n function multiplyInteger(x, k, base) {\r\n var temp,\r\n carry = 0,\r\n i = x.length;\r\n\r\n for (x = x.slice(); i--;) {\r\n temp = x[i] * k + carry;\r\n x[i] = temp % base | 0;\r\n carry = temp / base | 0;\r\n }\r\n\r\n if (carry) x.unshift(carry);\r\n\r\n return x;\r\n }\r\n\r\n function compare(a, b, aL, bL) {\r\n var i, r;\r\n\r\n if (aL != bL) {\r\n r = aL > bL ? 1 : -1;\r\n } else {\r\n for (i = r = 0; i < aL; i++) {\r\n if (a[i] != b[i]) {\r\n r = a[i] > b[i] ? 1 : -1;\r\n break;\r\n }\r\n }\r\n }\r\n\r\n return r;\r\n }\r\n\r\n function subtract(a, b, aL, base) {\r\n var i = 0;\r\n\r\n // Subtract b from a.\r\n for (; aL--;) {\r\n a[aL] -= i;\r\n i = a[aL] < b[aL] ? 1 : 0;\r\n a[aL] = i * base + a[aL] - b[aL];\r\n }\r\n\r\n // Remove leading zeros.\r\n for (; !a[0] && a.length > 1;) a.shift();\r\n }\r\n\r\n return function (x, y, pr, rm, dp, base) {\r\n var cmp, e, i, k, logBase, more, prod, prodL, q, qd, rem, remL, rem0, sd, t, xi, xL, yd0,\r\n yL, yz,\r\n Ctor = x.constructor,\r\n sign = x.s == y.s ? 1 : -1,\r\n xd = x.d,\r\n yd = y.d;\r\n\r\n // Either NaN, Infinity or 0?\r\n if (!xd || !xd[0] || !yd || !yd[0]) {\r\n\r\n return new Ctor(// Return NaN if either NaN, or both Infinity or 0.\r\n !x.s || !y.s || (xd ? yd && xd[0] == yd[0] : !yd) ? NaN :\r\n\r\n // Return ±0 if x is 0 or y is ±Infinity, or return ±Infinity as y is 0.\r\n xd && xd[0] == 0 || !yd ? sign * 0 : sign / 0);\r\n }\r\n\r\n if (base) {\r\n logBase = 1;\r\n e = x.e - y.e;\r\n } else {\r\n base = BASE;\r\n logBase = LOG_BASE;\r\n e = mathfloor(x.e / logBase) - mathfloor(y.e / logBase);\r\n }\r\n\r\n yL = yd.length;\r\n xL = xd.length;\r\n q = new Ctor(sign);\r\n qd = q.d = [];\r\n\r\n // Result exponent may be one less than e.\r\n // The digit array of a Decimal from toStringBinary may have trailing zeros.\r\n for (i = 0; yd[i] == (xd[i] || 0); i++);\r\n\r\n if (yd[i] > (xd[i] || 0)) e--;\r\n\r\n if (pr == null) {\r\n sd = pr = Ctor.precision;\r\n rm = Ctor.rounding;\r\n } else if (dp) {\r\n sd = pr + (x.e - y.e) + 1;\r\n } else {\r\n sd = pr;\r\n }\r\n\r\n if (sd < 0) {\r\n qd.push(1);\r\n more = true;\r\n } else {\r\n\r\n // Convert precision in number of base 10 digits to base 1e7 digits.\r\n sd = sd / logBase + 2 | 0;\r\n i = 0;\r\n\r\n // divisor < 1e7\r\n if (yL == 1) {\r\n k = 0;\r\n yd = yd[0];\r\n sd++;\r\n\r\n // k is the carry.\r\n for (; (i < xL || k) && sd--; i++) {\r\n t = k * base + (xd[i] || 0);\r\n qd[i] = t / yd | 0;\r\n k = t % yd | 0;\r\n }\r\n\r\n more = k || i < xL;\r\n\r\n // divisor >= 1e7\r\n } else {\r\n\r\n // Normalise xd and yd so highest order digit of yd is >= base/2\r\n k = base / (yd[0] + 1) | 0;\r\n\r\n if (k > 1) {\r\n yd = multiplyInteger(yd, k, base);\r\n xd = multiplyInteger(xd, k, base);\r\n yL = yd.length;\r\n xL = xd.length;\r\n }\r\n\r\n xi = yL;\r\n rem = xd.slice(0, yL);\r\n remL = rem.length;\r\n\r\n // Add zeros to make remainder as long as divisor.\r\n for (; remL < yL;) rem[remL++] = 0;\r\n\r\n yz = yd.slice();\r\n yz.unshift(0);\r\n yd0 = yd[0];\r\n\r\n if (yd[1] >= base / 2) ++yd0;\r\n\r\n do {\r\n k = 0;\r\n\r\n // Compare divisor and remainder.\r\n cmp = compare(yd, rem, yL, remL);\r\n\r\n // If divisor < remainder.\r\n if (cmp < 0) {\r\n\r\n // Calculate trial digit, k.\r\n rem0 = rem[0];\r\n if (yL != remL) rem0 = rem0 * base + (rem[1] || 0);\r\n\r\n // k will be how many times the divisor goes into the current remainder.\r\n k = rem0 / yd0 | 0;\r\n\r\n // Algorithm:\r\n // 1. product = divisor * trial digit (k)\r\n // 2. if product > remainder: product -= divisor, k--\r\n // 3. remainder -= product\r\n // 4. if product was < remainder at 2:\r\n // 5. compare new remainder and divisor\r\n // 6. If remainder > divisor: remainder -= divisor, k++\r\n\r\n if (k > 1) {\r\n if (k >= base) k = base - 1;\r\n\r\n // product = divisor * trial digit.\r\n prod = multiplyInteger(yd, k, base);\r\n prodL = prod.length;\r\n remL = rem.length;\r\n\r\n // Compare product and remainder.\r\n cmp = compare(prod, rem, prodL, remL);\r\n\r\n // product > remainder.\r\n if (cmp == 1) {\r\n k--;\r\n\r\n // Subtract divisor from product.\r\n subtract(prod, yL < prodL ? yz : yd, prodL, base);\r\n }\r\n } else {\r\n\r\n // cmp is -1.\r\n // If k is 0, there is no need to compare yd and rem again below, so change cmp to 1\r\n // to avoid it. If k is 1 there is a need to compare yd and rem again below.\r\n if (k == 0) cmp = k = 1;\r\n prod = yd.slice();\r\n }\r\n\r\n prodL = prod.length;\r\n if (prodL < remL) prod.unshift(0);\r\n\r\n // Subtract product from remainder.\r\n subtract(rem, prod, remL, base);\r\n\r\n // If product was < previous remainder.\r\n if (cmp == -1) {\r\n remL = rem.length;\r\n\r\n // Compare divisor and new remainder.\r\n cmp = compare(yd, rem, yL, remL);\r\n\r\n // If divisor < new remainder, subtract divisor from remainder.\r\n if (cmp < 1) {\r\n k++;\r\n\r\n // Subtract divisor from remainder.\r\n subtract(rem, yL < remL ? yz : yd, remL, base);\r\n }\r\n }\r\n\r\n remL = rem.length;\r\n } else if (cmp === 0) {\r\n k++;\r\n rem = [0];\r\n } // if cmp === 1, k will be 0\r\n\r\n // Add the next digit, k, to the result array.\r\n qd[i++] = k;\r\n\r\n // Update the remainder.\r\n if (cmp && rem[0]) {\r\n rem[remL++] = xd[xi] || 0;\r\n } else {\r\n rem = [xd[xi]];\r\n remL = 1;\r\n }\r\n\r\n } while ((xi++ < xL || rem[0] !== void 0) && sd--);\r\n\r\n more = rem[0] !== void 0;\r\n }\r\n\r\n // Leading zero?\r\n if (!qd[0]) qd.shift();\r\n }\r\n\r\n // logBase is 1 when divide is being used for base conversion.\r\n if (logBase == 1) {\r\n q.e = e;\r\n inexact = more;\r\n } else {\r\n\r\n // To calculate q.e, first get the number of digits of qd[0].\r\n for (i = 1, k = qd[0]; k >= 10; k /= 10) i++;\r\n q.e = i + e * logBase - 1;\r\n\r\n finalise(q, dp ? pr + q.e + 1 : pr, rm, more);\r\n }\r\n\r\n return q;\r\n };\r\n})();\r\n\r\n\r\n/*\r\n * Round `x` to `sd` significant digits using rounding mode `rm`.\r\n * Check for over/under-flow.\r\n */\r\n function finalise(x, sd, rm, isTruncated) {\r\n var digits, i, j, k, rd, roundUp, w, xd, xdi,\r\n Ctor = x.constructor;\r\n\r\n // Don't round if sd is null or undefined.\r\n out: if (sd != null) {\r\n xd = x.d;\r\n\r\n // Infinity/NaN.\r\n if (!xd) return x;\r\n\r\n // rd: the rounding digit, i.e. the digit after the digit that may be rounded up.\r\n // w: the word of xd containing rd, a base 1e7 number.\r\n // xdi: the index of w within xd.\r\n // digits: the number of digits of w.\r\n // i: what would be the index of rd within w if all the numbers were 7 digits long (i.e. if\r\n // they had leading zeros)\r\n // j: if > 0, the actual index of rd within w (if < 0, rd is a leading zero).\r\n\r\n // Get the length of the first word of the digits array xd.\r\n for (digits = 1, k = xd[0]; k >= 10; k /= 10) digits++;\r\n i = sd - digits;\r\n\r\n // Is the rounding digit in the first word of xd?\r\n if (i < 0) {\r\n i += LOG_BASE;\r\n j = sd;\r\n w = xd[xdi = 0];\r\n\r\n // Get the rounding digit at index j of w.\r\n rd = w / mathpow(10, digits - j - 1) % 10 | 0;\r\n } else {\r\n xdi = Math.ceil((i + 1) / LOG_BASE);\r\n k = xd.length;\r\n if (xdi >= k) {\r\n if (isTruncated) {\r\n\r\n // Needed by `naturalExponential`, `naturalLogarithm` and `squareRoot`.\r\n for (; k++ <= xdi;) xd.push(0);\r\n w = rd = 0;\r\n digits = 1;\r\n i %= LOG_BASE;\r\n j = i - LOG_BASE + 1;\r\n } else {\r\n break out;\r\n }\r\n } else {\r\n w = k = xd[xdi];\r\n\r\n // Get the number of digits of w.\r\n for (digits = 1; k >= 10; k /= 10) digits++;\r\n\r\n // Get the index of rd within w.\r\n i %= LOG_BASE;\r\n\r\n // Get the index of rd within w, adjusted for leading zeros.\r\n // The number of leading zeros of w is given by LOG_BASE - digits.\r\n j = i - LOG_BASE + digits;\r\n\r\n // Get the rounding digit at index j of w.\r\n rd = j < 0 ? 0 : w / mathpow(10, digits - j - 1) % 10 | 0;\r\n }\r\n }\r\n\r\n // Are there any non-zero digits after the rounding digit?\r\n isTruncated = isTruncated || sd < 0 ||\r\n xd[xdi + 1] !== void 0 || (j < 0 ? w : w % mathpow(10, digits - j - 1));\r\n\r\n // The expression `w % mathpow(10, digits - j - 1)` returns all the digits of w to the right\r\n // of the digit at (left-to-right) index j, e.g. if w is 908714 and j is 2, the expression\r\n // will give 714.\r\n\r\n roundUp = rm < 4\r\n ? (rd || isTruncated) && (rm == 0 || rm == (x.s < 0 ? 3 : 2))\r\n : rd > 5 || rd == 5 && (rm == 4 || isTruncated || rm == 6 &&\r\n\r\n // Check whether the digit to the left of the rounding digit is odd.\r\n ((i > 0 ? j > 0 ? w / mathpow(10, digits - j) : 0 : xd[xdi - 1]) % 10) & 1 ||\r\n rm == (x.s < 0 ? 8 : 7));\r\n\r\n if (sd < 1 || !xd[0]) {\r\n xd.length = 0;\r\n if (roundUp) {\r\n\r\n // Convert sd to decimal places.\r\n sd -= x.e + 1;\r\n\r\n // 1, 0.1, 0.01, 0.001, 0.0001 etc.\r\n xd[0] = mathpow(10, (LOG_BASE - sd % LOG_BASE) % LOG_BASE);\r\n x.e = -sd || 0;\r\n } else {\r\n\r\n // Zero.\r\n xd[0] = x.e = 0;\r\n }\r\n\r\n return x;\r\n }\r\n\r\n // Remove excess digits.\r\n if (i == 0) {\r\n xd.length = xdi;\r\n k = 1;\r\n xdi--;\r\n } else {\r\n xd.length = xdi + 1;\r\n k = mathpow(10, LOG_BASE - i);\r\n\r\n // E.g. 56700 becomes 56000 if 7 is the rounding digit.\r\n // j > 0 means i > number of leading zeros of w.\r\n xd[xdi] = j > 0 ? (w / mathpow(10, digits - j) % mathpow(10, j) | 0) * k : 0;\r\n }\r\n\r\n if (roundUp) {\r\n for (;;) {\r\n\r\n // Is the digit to be rounded up in the first word of xd?\r\n if (xdi == 0) {\r\n\r\n // i will be the length of xd[0] before k is added.\r\n for (i = 1, j = xd[0]; j >= 10; j /= 10) i++;\r\n j = xd[0] += k;\r\n for (k = 1; j >= 10; j /= 10) k++;\r\n\r\n // if i != k the length has increased.\r\n if (i != k) {\r\n x.e++;\r\n if (xd[0] == BASE) xd[0] = 1;\r\n }\r\n\r\n break;\r\n } else {\r\n xd[xdi] += k;\r\n if (xd[xdi] != BASE) break;\r\n xd[xdi--] = 0;\r\n k = 1;\r\n }\r\n }\r\n }\r\n\r\n // Remove trailing zeros.\r\n for (i = xd.length; xd[--i] === 0;) xd.pop();\r\n }\r\n\r\n if (external) {\r\n\r\n // Overflow?\r\n if (x.e > Ctor.maxE) {\r\n\r\n // Infinity.\r\n x.d = null;\r\n x.e = NaN;\r\n\r\n // Underflow?\r\n } else if (x.e < Ctor.minE) {\r\n\r\n // Zero.\r\n x.e = 0;\r\n x.d = [0];\r\n // Ctor.underflow = true;\r\n } // else Ctor.underflow = false;\r\n }\r\n\r\n return x;\r\n}\r\n\r\n\r\nfunction finiteToString(x, isExp, sd) {\r\n if (!x.isFinite()) return nonFiniteToString(x);\r\n var k,\r\n e = x.e,\r\n str = digitsToString(x.d),\r\n len = str.length;\r\n\r\n if (isExp) {\r\n if (sd && (k = sd - len) > 0) {\r\n str = str.charAt(0) + '.' + str.slice(1) + getZeroString(k);\r\n } else if (len > 1) {\r\n str = str.charAt(0) + '.' + str.slice(1);\r\n }\r\n\r\n str = str + (x.e < 0 ? 'e' : 'e+') + x.e;\r\n } else if (e < 0) {\r\n str = '0.' + getZeroString(-e - 1) + str;\r\n if (sd && (k = sd - len) > 0) str += getZeroString(k);\r\n } else if (e >= len) {\r\n str += getZeroString(e + 1 - len);\r\n if (sd && (k = sd - e - 1) > 0) str = str + '.' + getZeroString(k);\r\n } else {\r\n if ((k = e + 1) < len) str = str.slice(0, k) + '.' + str.slice(k);\r\n if (sd && (k = sd - len) > 0) {\r\n if (e + 1 === len) str += '.';\r\n str += getZeroString(k);\r\n }\r\n }\r\n\r\n return str;\r\n}\r\n\r\n\r\n// Calculate the base 10 exponent from the base 1e7 exponent.\r\nfunction getBase10Exponent(digits, e) {\r\n var w = digits[0];\r\n\r\n // Add the number of digits of the first word of the digits array.\r\n for ( e *= LOG_BASE; w >= 10; w /= 10) e++;\r\n return e;\r\n}\r\n\r\n\r\nfunction getLn10(Ctor, sd, pr) {\r\n if (sd > LN10_PRECISION) {\r\n\r\n // Reset global state in case the exception is caught.\r\n external = true;\r\n if (pr) Ctor.precision = pr;\r\n throw Error(precisionLimitExceeded);\r\n }\r\n return finalise(new Ctor(LN10), sd, 1, true);\r\n}\r\n\r\n\r\nfunction getPi(Ctor, sd, rm) {\r\n if (sd > PI_PRECISION) throw Error(precisionLimitExceeded);\r\n return finalise(new Ctor(PI), sd, rm, true);\r\n}\r\n\r\n\r\nfunction getPrecision(digits) {\r\n var w = digits.length - 1,\r\n len = w * LOG_BASE + 1;\r\n\r\n w = digits[w];\r\n\r\n // If non-zero...\r\n if (w) {\r\n\r\n // Subtract the number of trailing zeros of the last word.\r\n for (; w % 10 == 0; w /= 10) len--;\r\n\r\n // Add the number of digits of the first word.\r\n for (w = digits[0]; w >= 10; w /= 10) len++;\r\n }\r\n\r\n return len;\r\n}\r\n\r\n\r\nfunction getZeroString(k) {\r\n var zs = '';\r\n for (; k--;) zs += '0';\r\n return zs;\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the value of Decimal `x` to the power `n`, where `n` is an\r\n * integer of type number.\r\n *\r\n * Implements 'exponentiation by squaring'. Called by `pow` and `parseOther`.\r\n *\r\n */\r\nfunction intPow(Ctor, x, n, pr) {\r\n var isTruncated,\r\n r = new Ctor(1),\r\n\r\n // Max n of 9007199254740991 takes 53 loop iterations.\r\n // Maximum digits array length; leaves [28, 34] guard digits.\r\n k = Math.ceil(pr / LOG_BASE + 4);\r\n\r\n external = false;\r\n\r\n for (;;) {\r\n if (n % 2) {\r\n r = r.times(x);\r\n if (truncate(r.d, k)) isTruncated = true;\r\n }\r\n\r\n n = mathfloor(n / 2);\r\n if (n === 0) {\r\n\r\n // To ensure correct rounding when r.d is truncated, increment the last word if it is zero.\r\n n = r.d.length - 1;\r\n if (isTruncated && r.d[n] === 0) ++r.d[n];\r\n break;\r\n }\r\n\r\n x = x.times(x);\r\n truncate(x.d, k);\r\n }\r\n\r\n external = true;\r\n\r\n return r;\r\n}\r\n\r\n\r\nfunction isOdd(n) {\r\n return n.d[n.d.length - 1] & 1;\r\n}\r\n\r\n\r\n/*\r\n * Handle `max` and `min`. `ltgt` is 'lt' or 'gt'.\r\n */\r\nfunction maxOrMin(Ctor, args, ltgt) {\r\n var y,\r\n x = new Ctor(args[0]),\r\n i = 0;\r\n\r\n for (; ++i < args.length;) {\r\n y = new Ctor(args[i]);\r\n if (!y.s) {\r\n x = y;\r\n break;\r\n } else if (x[ltgt](y)) {\r\n x = y;\r\n }\r\n }\r\n\r\n return x;\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the natural exponential of `x` rounded to `sd` significant\r\n * digits.\r\n *\r\n * Taylor/Maclaurin series.\r\n *\r\n * exp(x) = x^0/0! + x^1/1! + x^2/2! + x^3/3! + ...\r\n *\r\n * Argument reduction:\r\n * Repeat x = x / 32, k += 5, until |x| < 0.1\r\n * exp(x) = exp(x / 2^k)^(2^k)\r\n *\r\n * Previously, the argument was initially reduced by\r\n * exp(x) = exp(r) * 10^k where r = x - k * ln10, k = floor(x / ln10)\r\n * to first put r in the range [0, ln10], before dividing by 32 until |x| < 0.1, but this was\r\n * found to be slower than just dividing repeatedly by 32 as above.\r\n *\r\n * Max integer argument: exp('20723265836946413') = 6.3e+9000000000000000\r\n * Min integer argument: exp('-20723265836946411') = 1.2e-9000000000000000\r\n * (Math object integer min/max: Math.exp(709) = 8.2e+307, Math.exp(-745) = 5e-324)\r\n *\r\n * exp(Infinity) = Infinity\r\n * exp(-Infinity) = 0\r\n * exp(NaN) = NaN\r\n * exp(±0) = 1\r\n *\r\n * exp(x) is non-terminating for any finite, non-zero x.\r\n *\r\n * The result will always be correctly rounded.\r\n *\r\n */\r\nfunction naturalExponential(x, sd) {\r\n var denominator, guard, j, pow, sum, t, wpr,\r\n rep = 0,\r\n i = 0,\r\n k = 0,\r\n Ctor = x.constructor,\r\n rm = Ctor.rounding,\r\n pr = Ctor.precision;\r\n\r\n // 0/NaN/Infinity?\r\n if (!x.d || !x.d[0] || x.e > 17) {\r\n\r\n return new Ctor(x.d\r\n ? !x.d[0] ? 1 : x.s < 0 ? 0 : 1 / 0\r\n : x.s ? x.s < 0 ? 0 : x : 0 / 0);\r\n }\r\n\r\n if (sd == null) {\r\n external = false;\r\n wpr = pr;\r\n } else {\r\n wpr = sd;\r\n }\r\n\r\n t = new Ctor(0.03125);\r\n\r\n // while abs(x) >= 0.1\r\n while (x.e > -2) {\r\n\r\n // x = x / 2^5\r\n x = x.times(t);\r\n k += 5;\r\n }\r\n\r\n // Use 2 * log10(2^k) + 5 (empirically derived) to estimate the increase in precision\r\n // necessary to ensure the first 4 rounding digits are correct.\r\n guard = Math.log(mathpow(2, k)) / Math.LN10 * 2 + 5 | 0;\r\n wpr += guard;\r\n denominator = pow = sum = new Ctor(1);\r\n Ctor.precision = wpr;\r\n\r\n for (;;) {\r\n pow = finalise(pow.times(x), wpr, 1);\r\n denominator = denominator.times(++i);\r\n t = sum.plus(divide(pow, denominator, wpr, 1));\r\n\r\n if (digitsToString(t.d).slice(0, wpr) === digitsToString(sum.d).slice(0, wpr)) {\r\n j = k;\r\n while (j--) sum = finalise(sum.times(sum), wpr, 1);\r\n\r\n // Check to see if the first 4 rounding digits are [49]999.\r\n // If so, repeat the summation with a higher precision, otherwise\r\n // e.g. with precision: 18, rounding: 1\r\n // exp(18.404272462595034083567793919843761) = 98372560.1229999999 (should be 98372560.123)\r\n // `wpr - guard` is the index of first rounding digit.\r\n if (sd == null) {\r\n\r\n if (rep < 3 && checkRoundingDigits(sum.d, wpr - guard, rm, rep)) {\r\n Ctor.precision = wpr += 10;\r\n denominator = pow = t = new Ctor(1);\r\n i = 0;\r\n rep++;\r\n } else {\r\n return finalise(sum, Ctor.precision = pr, rm, external = true);\r\n }\r\n } else {\r\n Ctor.precision = pr;\r\n return sum;\r\n }\r\n }\r\n\r\n sum = t;\r\n }\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the natural logarithm of `x` rounded to `sd` significant\r\n * digits.\r\n *\r\n * ln(-n) = NaN\r\n * ln(0) = -Infinity\r\n * ln(-0) = -Infinity\r\n * ln(1) = 0\r\n * ln(Infinity) = Infinity\r\n * ln(-Infinity) = NaN\r\n * ln(NaN) = NaN\r\n *\r\n * ln(n) (n != 1) is non-terminating.\r\n *\r\n */\r\nfunction naturalLogarithm(y, sd) {\r\n var c, c0, denominator, e, numerator, rep, sum, t, wpr, x1, x2,\r\n n = 1,\r\n guard = 10,\r\n x = y,\r\n xd = x.d,\r\n Ctor = x.constructor,\r\n rm = Ctor.rounding,\r\n pr = Ctor.precision;\r\n\r\n // Is x negative or Infinity, NaN, 0 or 1?\r\n if (x.s < 0 || !xd || !xd[0] || !x.e && xd[0] == 1 && xd.length == 1) {\r\n return new Ctor(xd && !xd[0] ? -1 / 0 : x.s != 1 ? NaN : xd ? 0 : x);\r\n }\r\n\r\n if (sd == null) {\r\n external = false;\r\n wpr = pr;\r\n } else {\r\n wpr = sd;\r\n }\r\n\r\n Ctor.precision = wpr += guard;\r\n c = digitsToString(xd);\r\n c0 = c.charAt(0);\r\n\r\n if (Math.abs(e = x.e) < 1.5e15) {\r\n\r\n // Argument reduction.\r\n // The series converges faster the closer the argument is to 1, so using\r\n // ln(a^b) = b * ln(a), ln(a) = ln(a^b) / b\r\n // multiply the argument by itself until the leading digits of the significand are 7, 8, 9,\r\n // 10, 11, 12 or 13, recording the number of multiplications so the sum of the series can\r\n // later be divided by this number, then separate out the power of 10 using\r\n // ln(a*10^b) = ln(a) + b*ln(10).\r\n\r\n // max n is 21 (gives 0.9, 1.0 or 1.1) (9e15 / 21 = 4.2e14).\r\n //while (c0 < 9 && c0 != 1 || c0 == 1 && c.charAt(1) > 1) {\r\n // max n is 6 (gives 0.7 - 1.3)\r\n while (c0 < 7 && c0 != 1 || c0 == 1 && c.charAt(1) > 3) {\r\n x = x.times(y);\r\n c = digitsToString(x.d);\r\n c0 = c.charAt(0);\r\n n++;\r\n }\r\n\r\n e = x.e;\r\n\r\n if (c0 > 1) {\r\n x = new Ctor('0.' + c);\r\n e++;\r\n } else {\r\n x = new Ctor(c0 + '.' + c.slice(1));\r\n }\r\n } else {\r\n\r\n // The argument reduction method above may result in overflow if the argument y is a massive\r\n // number with exponent >= 1500000000000000 (9e15 / 6 = 1.5e15), so instead recall this\r\n // function using ln(x*10^e) = ln(x) + e*ln(10).\r\n t = getLn10(Ctor, wpr + 2, pr).times(e + '');\r\n x = naturalLogarithm(new Ctor(c0 + '.' + c.slice(1)), wpr - guard).plus(t);\r\n Ctor.precision = pr;\r\n\r\n return sd == null ? finalise(x, pr, rm, external = true) : x;\r\n }\r\n\r\n // x1 is x reduced to a value near 1.\r\n x1 = x;\r\n\r\n // Taylor series.\r\n // ln(y) = ln((1 + x)/(1 - x)) = 2(x + x^3/3 + x^5/5 + x^7/7 + ...)\r\n // where x = (y - 1)/(y + 1) (|x| < 1)\r\n sum = numerator = x = divide(x.minus(1), x.plus(1), wpr, 1);\r\n x2 = finalise(x.times(x), wpr, 1);\r\n denominator = 3;\r\n\r\n for (;;) {\r\n numerator = finalise(numerator.times(x2), wpr, 1);\r\n t = sum.plus(divide(numerator, new Ctor(denominator), wpr, 1));\r\n\r\n if (digitsToString(t.d).slice(0, wpr) === digitsToString(sum.d).slice(0, wpr)) {\r\n sum = sum.times(2);\r\n\r\n // Reverse the argument reduction. Check that e is not 0 because, besides preventing an\r\n // unnecessary calculation, -0 + 0 = +0 and to ensure correct rounding -0 needs to stay -0.\r\n if (e !== 0) sum = sum.plus(getLn10(Ctor, wpr + 2, pr).times(e + ''));\r\n sum = divide(sum, new Ctor(n), wpr, 1);\r\n\r\n // Is rm > 3 and the first 4 rounding digits 4999, or rm < 4 (or the summation has\r\n // been repeated previously) and the first 4 rounding digits 9999?\r\n // If so, restart the summation with a higher precision, otherwise\r\n // e.g. with precision: 12, rounding: 1\r\n // ln(135520028.6126091714265381533) = 18.7246299999 when it should be 18.72463.\r\n // `wpr - guard` is the index of first rounding digit.\r\n if (sd == null) {\r\n if (checkRoundingDigits(sum.d, wpr - guard, rm, rep)) {\r\n Ctor.precision = wpr += guard;\r\n t = numerator = x = divide(x1.minus(1), x1.plus(1), wpr, 1);\r\n x2 = finalise(x.times(x), wpr, 1);\r\n denominator = rep = 1;\r\n } else {\r\n return finalise(sum, Ctor.precision = pr, rm, external = true);\r\n }\r\n } else {\r\n Ctor.precision = pr;\r\n return sum;\r\n }\r\n }\r\n\r\n sum = t;\r\n denominator += 2;\r\n }\r\n}\r\n\r\n\r\n// ±Infinity, NaN.\r\nfunction nonFiniteToString(x) {\r\n // Unsigned.\r\n return String(x.s * x.s / 0);\r\n}\r\n\r\n\r\n/*\r\n * Parse the value of a new Decimal `x` from string `str`.\r\n */\r\nfunction parseDecimal(x, str) {\r\n var e, i, len;\r\n\r\n // Decimal point?\r\n if ((e = str.indexOf('.')) > -1) str = str.replace('.', '');\r\n\r\n // Exponential form?\r\n if ((i = str.search(/e/i)) > 0) {\r\n\r\n // Determine exponent.\r\n if (e < 0) e = i;\r\n e += +str.slice(i + 1);\r\n str = str.substring(0, i);\r\n } else if (e < 0) {\r\n\r\n // Integer.\r\n e = str.length;\r\n }\r\n\r\n // Determine leading zeros.\r\n for (i = 0; str.charCodeAt(i) === 48; i++);\r\n\r\n // Determine trailing zeros.\r\n for (len = str.length; str.charCodeAt(len - 1) === 48; --len);\r\n str = str.slice(i, len);\r\n\r\n if (str) {\r\n len -= i;\r\n x.e = e = e - i - 1;\r\n x.d = [];\r\n\r\n // Transform base\r\n\r\n // e is the base 10 exponent.\r\n // i is where to slice str to get the first word of the digits array.\r\n i = (e + 1) % LOG_BASE;\r\n if (e < 0) i += LOG_BASE;\r\n\r\n if (i < len) {\r\n if (i) x.d.push(+str.slice(0, i));\r\n for (len -= LOG_BASE; i < len;) x.d.push(+str.slice(i, i += LOG_BASE));\r\n str = str.slice(i);\r\n i = LOG_BASE - str.length;\r\n } else {\r\n i -= len;\r\n }\r\n\r\n for (; i--;) str += '0';\r\n x.d.push(+str);\r\n\r\n if (external) {\r\n\r\n // Overflow?\r\n if (x.e > x.constructor.maxE) {\r\n\r\n // Infinity.\r\n x.d = null;\r\n x.e = NaN;\r\n\r\n // Underflow?\r\n } else if (x.e < x.constructor.minE) {\r\n\r\n // Zero.\r\n x.e = 0;\r\n x.d = [0];\r\n // x.constructor.underflow = true;\r\n } // else x.constructor.underflow = false;\r\n }\r\n } else {\r\n\r\n // Zero.\r\n x.e = 0;\r\n x.d = [0];\r\n }\r\n\r\n return x;\r\n}\r\n\r\n\r\n/*\r\n * Parse the value of a new Decimal `x` from a string `str`, which is not a decimal value.\r\n */\r\nfunction parseOther(x, str) {\r\n var base, Ctor, divisor, i, isFloat, len, p, xd, xe;\r\n\r\n if (str.indexOf('_') > -1) {\r\n str = str.replace(/(\\d)_(?=\\d)/g, '$1');\r\n if (isDecimal.test(str)) return parseDecimal(x, str);\r\n } else if (str === 'Infinity' || str === 'NaN') {\r\n if (!+str) x.s = NaN;\r\n x.e = NaN;\r\n x.d = null;\r\n return x;\r\n }\r\n\r\n if (isHex.test(str)) {\r\n base = 16;\r\n str = str.toLowerCase();\r\n } else if (isBinary.test(str)) {\r\n base = 2;\r\n } else if (isOctal.test(str)) {\r\n base = 8;\r\n } else {\r\n throw Error(invalidArgument + str);\r\n }\r\n\r\n // Is there a binary exponent part?\r\n i = str.search(/p/i);\r\n\r\n if (i > 0) {\r\n p = +str.slice(i + 1);\r\n str = str.substring(2, i);\r\n } else {\r\n str = str.slice(2);\r\n }\r\n\r\n // Convert `str` as an integer then divide the result by `base` raised to a power such that the\r\n // fraction part will be restored.\r\n i = str.indexOf('.');\r\n isFloat = i >= 0;\r\n Ctor = x.constructor;\r\n\r\n if (isFloat) {\r\n str = str.replace('.', '');\r\n len = str.length;\r\n i = len - i;\r\n\r\n // log[10](16) = 1.2041... , log[10](88) = 1.9444....\r\n divisor = intPow(Ctor, new Ctor(base), i, i * 2);\r\n }\r\n\r\n xd = convertBase(str, base, BASE);\r\n xe = xd.length - 1;\r\n\r\n // Remove trailing zeros.\r\n for (i = xe; xd[i] === 0; --i) xd.pop();\r\n if (i < 0) return new Ctor(x.s * 0);\r\n x.e = getBase10Exponent(xd, xe);\r\n x.d = xd;\r\n external = false;\r\n\r\n // At what precision to perform the division to ensure exact conversion?\r\n // maxDecimalIntegerPartDigitCount = ceil(log[10](b) * otherBaseIntegerPartDigitCount)\r\n // log[10](2) = 0.30103, log[10](8) = 0.90309, log[10](16) = 1.20412\r\n // E.g. ceil(1.2 * 3) = 4, so up to 4 decimal digits are needed to represent 3 hex int digits.\r\n // maxDecimalFractionPartDigitCount = {Hex:4|Oct:3|Bin:1} * otherBaseFractionPartDigitCount\r\n // Therefore using 4 * the number of digits of str will always be enough.\r\n if (isFloat) x = divide(x, divisor, len * 4);\r\n\r\n // Multiply by the binary exponent part if present.\r\n if (p) x = x.times(Math.abs(p) < 54 ? mathpow(2, p) : Decimal.pow(2, p));\r\n external = true;\r\n\r\n return x;\r\n}\r\n\r\n\r\n/*\r\n * sin(x) = x - x^3/3! + x^5/5! - ...\r\n * |x| < pi/2\r\n *\r\n */\r\nfunction sine(Ctor, x) {\r\n var k,\r\n len = x.d.length;\r\n\r\n if (len < 3) {\r\n return x.isZero() ? x : taylorSeries(Ctor, 2, x, x);\r\n }\r\n\r\n // Argument reduction: sin(5x) = 16*sin^5(x) - 20*sin^3(x) + 5*sin(x)\r\n // i.e. sin(x) = 16*sin^5(x/5) - 20*sin^3(x/5) + 5*sin(x/5)\r\n // and sin(x) = sin(x/5)(5 + sin^2(x/5)(16sin^2(x/5) - 20))\r\n\r\n // Estimate the optimum number of times to use the argument reduction.\r\n k = 1.4 * Math.sqrt(len);\r\n k = k > 16 ? 16 : k | 0;\r\n\r\n x = x.times(1 / tinyPow(5, k));\r\n x = taylorSeries(Ctor, 2, x, x);\r\n\r\n // Reverse argument reduction\r\n var sin2_x,\r\n d5 = new Ctor(5),\r\n d16 = new Ctor(16),\r\n d20 = new Ctor(20);\r\n for (; k--;) {\r\n sin2_x = x.times(x);\r\n x = x.times(d5.plus(sin2_x.times(d16.times(sin2_x).minus(d20))));\r\n }\r\n\r\n return x;\r\n}\r\n\r\n\r\n// Calculate Taylor series for `cos`, `cosh`, `sin` and `sinh`.\r\nfunction taylorSeries(Ctor, n, x, y, isHyperbolic) {\r\n var j, t, u, x2,\r\n i = 1,\r\n pr = Ctor.precision,\r\n k = Math.ceil(pr / LOG_BASE);\r\n\r\n external = false;\r\n x2 = x.times(x);\r\n u = new Ctor(y);\r\n\r\n for (;;) {\r\n t = divide(u.times(x2), new Ctor(n++ * n++), pr, 1);\r\n u = isHyperbolic ? y.plus(t) : y.minus(t);\r\n y = divide(t.times(x2), new Ctor(n++ * n++), pr, 1);\r\n t = u.plus(y);\r\n\r\n if (t.d[k] !== void 0) {\r\n for (j = k; t.d[j] === u.d[j] && j--;);\r\n if (j == -1) break;\r\n }\r\n\r\n j = u;\r\n u = y;\r\n y = t;\r\n t = j;\r\n i++;\r\n }\r\n\r\n external = true;\r\n t.d.length = k + 1;\r\n\r\n return t;\r\n}\r\n\r\n\r\n// Exponent e must be positive and non-zero.\r\nfunction tinyPow(b, e) {\r\n var n = b;\r\n while (--e) n *= b;\r\n return n;\r\n}\r\n\r\n\r\n// Return the absolute value of `x` reduced to less than or equal to half pi.\r\nfunction toLessThanHalfPi(Ctor, x) {\r\n var t,\r\n isNeg = x.s < 0,\r\n pi = getPi(Ctor, Ctor.precision, 1),\r\n halfPi = pi.times(0.5);\r\n\r\n x = x.abs();\r\n\r\n if (x.lte(halfPi)) {\r\n quadrant = isNeg ? 4 : 1;\r\n return x;\r\n }\r\n\r\n t = x.divToInt(pi);\r\n\r\n if (t.isZero()) {\r\n quadrant = isNeg ? 3 : 2;\r\n } else {\r\n x = x.minus(t.times(pi));\r\n\r\n // 0 <= x < pi\r\n if (x.lte(halfPi)) {\r\n quadrant = isOdd(t) ? (isNeg ? 2 : 3) : (isNeg ? 4 : 1);\r\n return x;\r\n }\r\n\r\n quadrant = isOdd(t) ? (isNeg ? 1 : 4) : (isNeg ? 3 : 2);\r\n }\r\n\r\n return x.minus(pi).abs();\r\n}\r\n\r\n\r\n/*\r\n * Return the value of Decimal `x` as a string in base `baseOut`.\r\n *\r\n * If the optional `sd` argument is present include a binary exponent suffix.\r\n */\r\nfunction toStringBinary(x, baseOut, sd, rm) {\r\n var base, e, i, k, len, roundUp, str, xd, y,\r\n Ctor = x.constructor,\r\n isExp = sd !== void 0;\r\n\r\n if (isExp) {\r\n checkInt32(sd, 1, MAX_DIGITS);\r\n if (rm === void 0) rm = Ctor.rounding;\r\n else checkInt32(rm, 0, 8);\r\n } else {\r\n sd = Ctor.precision;\r\n rm = Ctor.rounding;\r\n }\r\n\r\n if (!x.isFinite()) {\r\n str = nonFiniteToString(x);\r\n } else {\r\n str = finiteToString(x);\r\n i = str.indexOf('.');\r\n\r\n // Use exponential notation according to `toExpPos` and `toExpNeg`? No, but if required:\r\n // maxBinaryExponent = floor((decimalExponent + 1) * log[2](10))\r\n // minBinaryExponent = floor(decimalExponent * log[2](10))\r\n // log[2](10) = 3.321928094887362347870319429489390175864\r\n\r\n if (isExp) {\r\n base = 2;\r\n if (baseOut == 16) {\r\n sd = sd * 4 - 3;\r\n } else if (baseOut == 8) {\r\n sd = sd * 3 - 2;\r\n }\r\n } else {\r\n base = baseOut;\r\n }\r\n\r\n // Convert the number as an integer then divide the result by its base raised to a power such\r\n // that the fraction part will be restored.\r\n\r\n // Non-integer.\r\n if (i >= 0) {\r\n str = str.replace('.', '');\r\n y = new Ctor(1);\r\n y.e = str.length - i;\r\n y.d = convertBase(finiteToString(y), 10, base);\r\n y.e = y.d.length;\r\n }\r\n\r\n xd = convertBase(str, 10, base);\r\n e = len = xd.length;\r\n\r\n // Remove trailing zeros.\r\n for (; xd[--len] == 0;) xd.pop();\r\n\r\n if (!xd[0]) {\r\n str = isExp ? '0p+0' : '0';\r\n } else {\r\n if (i < 0) {\r\n e--;\r\n } else {\r\n x = new Ctor(x);\r\n x.d = xd;\r\n x.e = e;\r\n x = divide(x, y, sd, rm, 0, base);\r\n xd = x.d;\r\n e = x.e;\r\n roundUp = inexact;\r\n }\r\n\r\n // The rounding digit, i.e. the digit after the digit that may be rounded up.\r\n i = xd[sd];\r\n k = base / 2;\r\n roundUp = roundUp || xd[sd + 1] !== void 0;\r\n\r\n roundUp = rm < 4\r\n ? (i !== void 0 || roundUp) && (rm === 0 || rm === (x.s < 0 ? 3 : 2))\r\n : i > k || i === k && (rm === 4 || roundUp || rm === 6 && xd[sd - 1] & 1 ||\r\n rm === (x.s < 0 ? 8 : 7));\r\n\r\n xd.length = sd;\r\n\r\n if (roundUp) {\r\n\r\n // Rounding up may mean the previous digit has to be rounded up and so on.\r\n for (; ++xd[--sd] > base - 1;) {\r\n xd[sd] = 0;\r\n if (!sd) {\r\n ++e;\r\n xd.unshift(1);\r\n }\r\n }\r\n }\r\n\r\n // Determine trailing zeros.\r\n for (len = xd.length; !xd[len - 1]; --len);\r\n\r\n // E.g. [4, 11, 15] becomes 4bf.\r\n for (i = 0, str = ''; i < len; i++) str += NUMERALS.charAt(xd[i]);\r\n\r\n // Add binary exponent suffix?\r\n if (isExp) {\r\n if (len > 1) {\r\n if (baseOut == 16 || baseOut == 8) {\r\n i = baseOut == 16 ? 4 : 3;\r\n for (--len; len % i; len++) str += '0';\r\n xd = convertBase(str, base, baseOut);\r\n for (len = xd.length; !xd[len - 1]; --len);\r\n\r\n // xd[0] will always be be 1\r\n for (i = 1, str = '1.'; i < len; i++) str += NUMERALS.charAt(xd[i]);\r\n } else {\r\n str = str.charAt(0) + '.' + str.slice(1);\r\n }\r\n }\r\n\r\n str = str + (e < 0 ? 'p' : 'p+') + e;\r\n } else if (e < 0) {\r\n for (; ++e;) str = '0' + str;\r\n str = '0.' + str;\r\n } else {\r\n if (++e > len) for (e -= len; e-- ;) str += '0';\r\n else if (e < len) str = str.slice(0, e) + '.' + str.slice(e);\r\n }\r\n }\r\n\r\n str = (baseOut == 16 ? '0x' : baseOut == 2 ? '0b' : baseOut == 8 ? '0o' : '') + str;\r\n }\r\n\r\n return x.s < 0 ? '-' + str : str;\r\n}\r\n\r\n\r\n// Does not strip trailing zeros.\r\nfunction truncate(arr, len) {\r\n if (arr.length > len) {\r\n arr.length = len;\r\n return true;\r\n }\r\n}\r\n\r\n\r\n// Decimal methods\r\n\r\n\r\n/*\r\n * abs\r\n * acos\r\n * acosh\r\n * add\r\n * asin\r\n * asinh\r\n * atan\r\n * atanh\r\n * atan2\r\n * cbrt\r\n * ceil\r\n * clamp\r\n * clone\r\n * config\r\n * cos\r\n * cosh\r\n * div\r\n * exp\r\n * floor\r\n * hypot\r\n * ln\r\n * log\r\n * log2\r\n * log10\r\n * max\r\n * min\r\n * mod\r\n * mul\r\n * pow\r\n * random\r\n * round\r\n * set\r\n * sign\r\n * sin\r\n * sinh\r\n * sqrt\r\n * sub\r\n * sum\r\n * tan\r\n * tanh\r\n * trunc\r\n */\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the absolute value of `x`.\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction abs(x) {\r\n return new this(x).abs();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the arccosine in radians of `x`.\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction acos(x) {\r\n return new this(x).acos();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the inverse of the hyperbolic cosine of `x`, rounded to\r\n * `precision` significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal} A value in radians.\r\n *\r\n */\r\nfunction acosh(x) {\r\n return new this(x).acosh();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the sum of `x` and `y`, rounded to `precision` significant\r\n * digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal}\r\n * y {number|string|Decimal}\r\n *\r\n */\r\nfunction add(x, y) {\r\n return new this(x).plus(y);\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the arcsine in radians of `x`, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction asin(x) {\r\n return new this(x).asin();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the inverse of the hyperbolic sine of `x`, rounded to\r\n * `precision` significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal} A value in radians.\r\n *\r\n */\r\nfunction asinh(x) {\r\n return new this(x).asinh();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the arctangent in radians of `x`, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction atan(x) {\r\n return new this(x).atan();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the inverse of the hyperbolic tangent of `x`, rounded to\r\n * `precision` significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal} A value in radians.\r\n *\r\n */\r\nfunction atanh(x) {\r\n return new this(x).atanh();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the arctangent in radians of `y/x` in the range -pi to pi\r\n * (inclusive), rounded to `precision` significant digits using rounding mode `rounding`.\r\n *\r\n * Domain: [-Infinity, Infinity]\r\n * Range: [-pi, pi]\r\n *\r\n * y {number|string|Decimal} The y-coordinate.\r\n * x {number|string|Decimal} The x-coordinate.\r\n *\r\n * atan2(±0, -0) = ±pi\r\n * atan2(±0, +0) = ±0\r\n * atan2(±0, -x) = ±pi for x > 0\r\n * atan2(±0, x) = ±0 for x > 0\r\n * atan2(-y, ±0) = -pi/2 for y > 0\r\n * atan2(y, ±0) = pi/2 for y > 0\r\n * atan2(±y, -Infinity) = ±pi for finite y > 0\r\n * atan2(±y, +Infinity) = ±0 for finite y > 0\r\n * atan2(±Infinity, x) = ±pi/2 for finite x\r\n * atan2(±Infinity, -Infinity) = ±3*pi/4\r\n * atan2(±Infinity, +Infinity) = ±pi/4\r\n * atan2(NaN, x) = NaN\r\n * atan2(y, NaN) = NaN\r\n *\r\n */\r\nfunction atan2(y, x) {\r\n y = new this(y);\r\n x = new this(x);\r\n var r,\r\n pr = this.precision,\r\n rm = this.rounding,\r\n wpr = pr + 4;\r\n\r\n // Either NaN\r\n if (!y.s || !x.s) {\r\n r = new this(NaN);\r\n\r\n // Both ±Infinity\r\n } else if (!y.d && !x.d) {\r\n r = getPi(this, wpr, 1).times(x.s > 0 ? 0.25 : 0.75);\r\n r.s = y.s;\r\n\r\n // x is ±Infinity or y is ±0\r\n } else if (!x.d || y.isZero()) {\r\n r = x.s < 0 ? getPi(this, pr, rm) : new this(0);\r\n r.s = y.s;\r\n\r\n // y is ±Infinity or x is ±0\r\n } else if (!y.d || x.isZero()) {\r\n r = getPi(this, wpr, 1).times(0.5);\r\n r.s = y.s;\r\n\r\n // Both non-zero and finite\r\n } else if (x.s < 0) {\r\n this.precision = wpr;\r\n this.rounding = 1;\r\n r = this.atan(divide(y, x, wpr, 1));\r\n x = getPi(this, wpr, 1);\r\n this.precision = pr;\r\n this.rounding = rm;\r\n r = y.s < 0 ? r.minus(x) : r.plus(x);\r\n } else {\r\n r = this.atan(divide(y, x, wpr, 1));\r\n }\r\n\r\n return r;\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the cube root of `x`, rounded to `precision` significant\r\n * digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction cbrt(x) {\r\n return new this(x).cbrt();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is `x` rounded to an integer using `ROUND_CEIL`.\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction ceil(x) {\r\n return finalise(x = new this(x), x.e + 1, 2);\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is `x` clamped to the range delineated by `min` and `max`.\r\n *\r\n * x {number|string|Decimal}\r\n * min {number|string|Decimal}\r\n * max {number|string|Decimal}\r\n *\r\n */\r\nfunction clamp(x, min, max) {\r\n return new this(x).clamp(min, max);\r\n}\r\n\r\n\r\n/*\r\n * Configure global settings for a Decimal constructor.\r\n *\r\n * `obj` is an object with one or more of the following properties,\r\n *\r\n * precision {number}\r\n * rounding {number}\r\n * toExpNeg {number}\r\n * toExpPos {number}\r\n * maxE {number}\r\n * minE {number}\r\n * modulo {number}\r\n * crypto {boolean|number}\r\n * defaults {true}\r\n *\r\n * E.g. Decimal.config({ precision: 20, rounding: 4 })\r\n *\r\n */\r\nfunction config(obj) {\r\n if (!obj || typeof obj !== 'object') throw Error(decimalError + 'Object expected');\r\n var i, p, v,\r\n useDefaults = obj.defaults === true,\r\n ps = [\r\n 'precision', 1, MAX_DIGITS,\r\n 'rounding', 0, 8,\r\n 'toExpNeg', -EXP_LIMIT, 0,\r\n 'toExpPos', 0, EXP_LIMIT,\r\n 'maxE', 0, EXP_LIMIT,\r\n 'minE', -EXP_LIMIT, 0,\r\n 'modulo', 0, 9\r\n ];\r\n\r\n for (i = 0; i < ps.length; i += 3) {\r\n if (p = ps[i], useDefaults) this[p] = DEFAULTS[p];\r\n if ((v = obj[p]) !== void 0) {\r\n if (mathfloor(v) === v && v >= ps[i + 1] && v <= ps[i + 2]) this[p] = v;\r\n else throw Error(invalidArgument + p + ': ' + v);\r\n }\r\n }\r\n\r\n if (p = 'crypto', useDefaults) this[p] = DEFAULTS[p];\r\n if ((v = obj[p]) !== void 0) {\r\n if (v === true || v === false || v === 0 || v === 1) {\r\n if (v) {\r\n if (typeof crypto != 'undefined' && crypto &&\r\n (crypto.getRandomValues || crypto.randomBytes)) {\r\n this[p] = true;\r\n } else {\r\n throw Error(cryptoUnavailable);\r\n }\r\n } else {\r\n this[p] = false;\r\n }\r\n } else {\r\n throw Error(invalidArgument + p + ': ' + v);\r\n }\r\n }\r\n\r\n return this;\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the cosine of `x`, rounded to `precision` significant\r\n * digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal} A value in radians.\r\n *\r\n */\r\nfunction cos(x) {\r\n return new this(x).cos();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the hyperbolic cosine of `x`, rounded to precision\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal} A value in radians.\r\n *\r\n */\r\nfunction cosh(x) {\r\n return new this(x).cosh();\r\n}\r\n\r\n\r\n/*\r\n * Create and return a Decimal constructor with the same configuration properties as this Decimal\r\n * constructor.\r\n *\r\n */\r\nfunction clone(obj) {\r\n var i, p, ps;\r\n\r\n /*\r\n * The Decimal constructor and exported function.\r\n * Return a new Decimal instance.\r\n *\r\n * v {number|string|Decimal} A numeric value.\r\n *\r\n */\r\n function Decimal(v) {\r\n var e, i, t,\r\n x = this;\r\n\r\n // Decimal called without new.\r\n if (!(x instanceof Decimal)) return new Decimal(v);\r\n\r\n // Retain a reference to this Decimal constructor, and shadow Decimal.prototype.constructor\r\n // which points to Object.\r\n x.constructor = Decimal;\r\n\r\n // Duplicate.\r\n if (isDecimalInstance(v)) {\r\n x.s = v.s;\r\n\r\n if (external) {\r\n if (!v.d || v.e > Decimal.maxE) {\r\n\r\n // Infinity.\r\n x.e = NaN;\r\n x.d = null;\r\n } else if (v.e < Decimal.minE) {\r\n\r\n // Zero.\r\n x.e = 0;\r\n x.d = [0];\r\n } else {\r\n x.e = v.e;\r\n x.d = v.d.slice();\r\n }\r\n } else {\r\n x.e = v.e;\r\n x.d = v.d ? v.d.slice() : v.d;\r\n }\r\n\r\n return;\r\n }\r\n\r\n t = typeof v;\r\n\r\n if (t === 'number') {\r\n if (v === 0) {\r\n x.s = 1 / v < 0 ? -1 : 1;\r\n x.e = 0;\r\n x.d = [0];\r\n return;\r\n }\r\n\r\n if (v < 0) {\r\n v = -v;\r\n x.s = -1;\r\n } else {\r\n x.s = 1;\r\n }\r\n\r\n // Fast path for small integers.\r\n if (v === ~~v && v < 1e7) {\r\n for (e = 0, i = v; i >= 10; i /= 10) e++;\r\n\r\n if (external) {\r\n if (e > Decimal.maxE) {\r\n x.e = NaN;\r\n x.d = null;\r\n } else if (e < Decimal.minE) {\r\n x.e = 0;\r\n x.d = [0];\r\n } else {\r\n x.e = e;\r\n x.d = [v];\r\n }\r\n } else {\r\n x.e = e;\r\n x.d = [v];\r\n }\r\n\r\n return;\r\n\r\n // Infinity, NaN.\r\n } else if (v * 0 !== 0) {\r\n if (!v) x.s = NaN;\r\n x.e = NaN;\r\n x.d = null;\r\n return;\r\n }\r\n\r\n return parseDecimal(x, v.toString());\r\n\r\n } else if (t !== 'string') {\r\n throw Error(invalidArgument + v);\r\n }\r\n\r\n // Minus sign?\r\n if ((i = v.charCodeAt(0)) === 45) {\r\n v = v.slice(1);\r\n x.s = -1;\r\n } else {\r\n // Plus sign?\r\n if (i === 43) v = v.slice(1);\r\n x.s = 1;\r\n }\r\n\r\n return isDecimal.test(v) ? parseDecimal(x, v) : parseOther(x, v);\r\n }\r\n\r\n Decimal.prototype = P;\r\n\r\n Decimal.ROUND_UP = 0;\r\n Decimal.ROUND_DOWN = 1;\r\n Decimal.ROUND_CEIL = 2;\r\n Decimal.ROUND_FLOOR = 3;\r\n Decimal.ROUND_HALF_UP = 4;\r\n Decimal.ROUND_HALF_DOWN = 5;\r\n Decimal.ROUND_HALF_EVEN = 6;\r\n Decimal.ROUND_HALF_CEIL = 7;\r\n Decimal.ROUND_HALF_FLOOR = 8;\r\n Decimal.EUCLID = 9;\r\n\r\n Decimal.config = Decimal.set = config;\r\n Decimal.clone = clone;\r\n Decimal.isDecimal = isDecimalInstance;\r\n\r\n Decimal.abs = abs;\r\n Decimal.acos = acos;\r\n Decimal.acosh = acosh; // ES6\r\n Decimal.add = add;\r\n Decimal.asin = asin;\r\n Decimal.asinh = asinh; // ES6\r\n Decimal.atan = atan;\r\n Decimal.atanh = atanh; // ES6\r\n Decimal.atan2 = atan2;\r\n Decimal.cbrt = cbrt; // ES6\r\n Decimal.ceil = ceil;\r\n Decimal.clamp = clamp;\r\n Decimal.cos = cos;\r\n Decimal.cosh = cosh; // ES6\r\n Decimal.div = div;\r\n Decimal.exp = exp;\r\n Decimal.floor = floor;\r\n Decimal.hypot = hypot; // ES6\r\n Decimal.ln = ln;\r\n Decimal.log = log;\r\n Decimal.log10 = log10; // ES6\r\n Decimal.log2 = log2; // ES6\r\n Decimal.max = max;\r\n Decimal.min = min;\r\n Decimal.mod = mod;\r\n Decimal.mul = mul;\r\n Decimal.pow = pow;\r\n Decimal.random = random;\r\n Decimal.round = round;\r\n Decimal.sign = sign; // ES6\r\n Decimal.sin = sin;\r\n Decimal.sinh = sinh; // ES6\r\n Decimal.sqrt = sqrt;\r\n Decimal.sub = sub;\r\n Decimal.sum = sum;\r\n Decimal.tan = tan;\r\n Decimal.tanh = tanh; // ES6\r\n Decimal.trunc = trunc; // ES6\r\n\r\n if (obj === void 0) obj = {};\r\n if (obj) {\r\n if (obj.defaults !== true) {\r\n ps = ['precision', 'rounding', 'toExpNeg', 'toExpPos', 'maxE', 'minE', 'modulo', 'crypto'];\r\n for (i = 0; i < ps.length;) if (!obj.hasOwnProperty(p = ps[i++])) obj[p] = this[p];\r\n }\r\n }\r\n\r\n Decimal.config(obj);\r\n\r\n return Decimal;\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is `x` divided by `y`, rounded to `precision` significant\r\n * digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal}\r\n * y {number|string|Decimal}\r\n *\r\n */\r\nfunction div(x, y) {\r\n return new this(x).div(y);\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the natural exponential of `x`, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal} The power to which to raise the base of the natural log.\r\n *\r\n */\r\nfunction exp(x) {\r\n return new this(x).exp();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is `x` round to an integer using `ROUND_FLOOR`.\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction floor(x) {\r\n return finalise(x = new this(x), x.e + 1, 3);\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the square root of the sum of the squares of the arguments,\r\n * rounded to `precision` significant digits using rounding mode `rounding`.\r\n *\r\n * hypot(a, b, ...) = sqrt(a^2 + b^2 + ...)\r\n *\r\n * arguments {number|string|Decimal}\r\n *\r\n */\r\nfunction hypot() {\r\n var i, n,\r\n t = new this(0);\r\n\r\n external = false;\r\n\r\n for (i = 0; i < arguments.length;) {\r\n n = new this(arguments[i++]);\r\n if (!n.d) {\r\n if (n.s) {\r\n external = true;\r\n return new this(1 / 0);\r\n }\r\n t = n;\r\n } else if (t.d) {\r\n t = t.plus(n.times(n));\r\n }\r\n }\r\n\r\n external = true;\r\n\r\n return t.sqrt();\r\n}\r\n\r\n\r\n/*\r\n * Return true if object is a Decimal instance (where Decimal is any Decimal constructor),\r\n * otherwise return false.\r\n *\r\n */\r\nfunction isDecimalInstance(obj) {\r\n return obj instanceof Decimal || obj && obj.toStringTag === tag || false;\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the natural logarithm of `x`, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction ln(x) {\r\n return new this(x).ln();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the log of `x` to the base `y`, or to base 10 if no base\r\n * is specified, rounded to `precision` significant digits using rounding mode `rounding`.\r\n *\r\n * log[y](x)\r\n *\r\n * x {number|string|Decimal} The argument of the logarithm.\r\n * y {number|string|Decimal} The base of the logarithm.\r\n *\r\n */\r\nfunction log(x, y) {\r\n return new this(x).log(y);\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the base 2 logarithm of `x`, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction log2(x) {\r\n return new this(x).log(2);\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the base 10 logarithm of `x`, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction log10(x) {\r\n return new this(x).log(10);\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the maximum of the arguments.\r\n *\r\n * arguments {number|string|Decimal}\r\n *\r\n */\r\nfunction max() {\r\n return maxOrMin(this, arguments, 'lt');\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the minimum of the arguments.\r\n *\r\n * arguments {number|string|Decimal}\r\n *\r\n */\r\nfunction min() {\r\n return maxOrMin(this, arguments, 'gt');\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is `x` modulo `y`, rounded to `precision` significant digits\r\n * using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal}\r\n * y {number|string|Decimal}\r\n *\r\n */\r\nfunction mod(x, y) {\r\n return new this(x).mod(y);\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is `x` multiplied by `y`, rounded to `precision` significant\r\n * digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal}\r\n * y {number|string|Decimal}\r\n *\r\n */\r\nfunction mul(x, y) {\r\n return new this(x).mul(y);\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is `x` raised to the power `y`, rounded to precision\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal} The base.\r\n * y {number|string|Decimal} The exponent.\r\n *\r\n */\r\nfunction pow(x, y) {\r\n return new this(x).pow(y);\r\n}\r\n\r\n\r\n/*\r\n * Returns a new Decimal with a random value equal to or greater than 0 and less than 1, and with\r\n * `sd`, or `Decimal.precision` if `sd` is omitted, significant digits (or less if trailing zeros\r\n * are produced).\r\n *\r\n * [sd] {number} Significant digits. Integer, 0 to MAX_DIGITS inclusive.\r\n *\r\n */\r\nfunction random(sd) {\r\n var d, e, k, n,\r\n i = 0,\r\n r = new this(1),\r\n rd = [];\r\n\r\n if (sd === void 0) sd = this.precision;\r\n else checkInt32(sd, 1, MAX_DIGITS);\r\n\r\n k = Math.ceil(sd / LOG_BASE);\r\n\r\n if (!this.crypto) {\r\n for (; i < k;) rd[i++] = Math.random() * 1e7 | 0;\r\n\r\n // Browsers supporting crypto.getRandomValues.\r\n } else if (crypto.getRandomValues) {\r\n d = crypto.getRandomValues(new Uint32Array(k));\r\n\r\n for (; i < k;) {\r\n n = d[i];\r\n\r\n // 0 <= n < 4294967296\r\n // Probability n >= 4.29e9, is 4967296 / 4294967296 = 0.00116 (1 in 865).\r\n if (n >= 4.29e9) {\r\n d[i] = crypto.getRandomValues(new Uint32Array(1))[0];\r\n } else {\r\n\r\n // 0 <= n <= 4289999999\r\n // 0 <= (n % 1e7) <= 9999999\r\n rd[i++] = n % 1e7;\r\n }\r\n }\r\n\r\n // Node.js supporting crypto.randomBytes.\r\n } else if (crypto.randomBytes) {\r\n\r\n // buffer\r\n d = crypto.randomBytes(k *= 4);\r\n\r\n for (; i < k;) {\r\n\r\n // 0 <= n < 2147483648\r\n n = d[i] + (d[i + 1] << 8) + (d[i + 2] << 16) + ((d[i + 3] & 0x7f) << 24);\r\n\r\n // Probability n >= 2.14e9, is 7483648 / 2147483648 = 0.0035 (1 in 286).\r\n if (n >= 2.14e9) {\r\n crypto.randomBytes(4).copy(d, i);\r\n } else {\r\n\r\n // 0 <= n <= 2139999999\r\n // 0 <= (n % 1e7) <= 9999999\r\n rd.push(n % 1e7);\r\n i += 4;\r\n }\r\n }\r\n\r\n i = k / 4;\r\n } else {\r\n throw Error(cryptoUnavailable);\r\n }\r\n\r\n k = rd[--i];\r\n sd %= LOG_BASE;\r\n\r\n // Convert trailing digits to zeros according to sd.\r\n if (k && sd) {\r\n n = mathpow(10, LOG_BASE - sd);\r\n rd[i] = (k / n | 0) * n;\r\n }\r\n\r\n // Remove trailing words which are zero.\r\n for (; rd[i] === 0; i--) rd.pop();\r\n\r\n // Zero?\r\n if (i < 0) {\r\n e = 0;\r\n rd = [0];\r\n } else {\r\n e = -1;\r\n\r\n // Remove leading words which are zero and adjust exponent accordingly.\r\n for (; rd[0] === 0; e -= LOG_BASE) rd.shift();\r\n\r\n // Count the digits of the first word of rd to determine leading zeros.\r\n for (k = 1, n = rd[0]; n >= 10; n /= 10) k++;\r\n\r\n // Adjust the exponent for leading zeros of the first word of rd.\r\n if (k < LOG_BASE) e -= LOG_BASE - k;\r\n }\r\n\r\n r.e = e;\r\n r.d = rd;\r\n\r\n return r;\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is `x` rounded to an integer using rounding mode `rounding`.\r\n *\r\n * To emulate `Math.round`, set rounding to 7 (ROUND_HALF_CEIL).\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction round(x) {\r\n return finalise(x = new this(x), x.e + 1, this.rounding);\r\n}\r\n\r\n\r\n/*\r\n * Return\r\n * 1 if x > 0,\r\n * -1 if x < 0,\r\n * 0 if x is 0,\r\n * -0 if x is -0,\r\n * NaN otherwise\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction sign(x) {\r\n x = new this(x);\r\n return x.d ? (x.d[0] ? x.s : 0 * x.s) : x.s || NaN;\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the sine of `x`, rounded to `precision` significant digits\r\n * using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal} A value in radians.\r\n *\r\n */\r\nfunction sin(x) {\r\n return new this(x).sin();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the hyperbolic sine of `x`, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal} A value in radians.\r\n *\r\n */\r\nfunction sinh(x) {\r\n return new this(x).sinh();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the square root of `x`, rounded to `precision` significant\r\n * digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction sqrt(x) {\r\n return new this(x).sqrt();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is `x` minus `y`, rounded to `precision` significant digits\r\n * using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal}\r\n * y {number|string|Decimal}\r\n *\r\n */\r\nfunction sub(x, y) {\r\n return new this(x).sub(y);\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the sum of the arguments, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * Only the result is rounded, not the intermediate calculations.\r\n *\r\n * arguments {number|string|Decimal}\r\n *\r\n */\r\nfunction sum() {\r\n var i = 0,\r\n args = arguments,\r\n x = new this(args[i]);\r\n\r\n external = false;\r\n for (; x.s && ++i < args.length;) x = x.plus(args[i]);\r\n external = true;\r\n\r\n return finalise(x, this.precision, this.rounding);\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the tangent of `x`, rounded to `precision` significant\r\n * digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal} A value in radians.\r\n *\r\n */\r\nfunction tan(x) {\r\n return new this(x).tan();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is the hyperbolic tangent of `x`, rounded to `precision`\r\n * significant digits using rounding mode `rounding`.\r\n *\r\n * x {number|string|Decimal} A value in radians.\r\n *\r\n */\r\nfunction tanh(x) {\r\n return new this(x).tanh();\r\n}\r\n\r\n\r\n/*\r\n * Return a new Decimal whose value is `x` truncated to an integer.\r\n *\r\n * x {number|string|Decimal}\r\n *\r\n */\r\nfunction trunc(x) {\r\n return finalise(x = new this(x), x.e + 1, 1);\r\n}\r\n\r\n\r\nP[Symbol.for('nodejs.util.inspect.custom')] = P.toString;\r\nP[Symbol.toStringTag] = 'Decimal';\r\n\r\n// Create and configure initial Decimal constructor.\r\nexport var Decimal = P.constructor = clone(DEFAULTS);\r\n\r\n// Create the internal constants from their string values.\r\nLN10 = new Decimal(LN10);\r\nPI = new Decimal(PI);\r\n\r\nexport default Decimal;\r\n","/**\n * Monero integrated address model.\n */\nexport default class MoneroIntegratedAddress {\n constructor(integratedAddress) {\n Object.assign(this, integratedAddress);\n }\n toJson() {\n return Object.assign({}, this);\n }\n getStandardAddress() {\n return this.standardAddress;\n }\n setStandardAddress(standardAddress) {\n this.standardAddress = standardAddress;\n return this;\n }\n getPaymentId() {\n return this.paymentId;\n }\n setPaymentId(paymentId) {\n this.paymentId = paymentId;\n return this;\n }\n getIntegratedAddress() {\n return this.integratedAddress;\n }\n setIntegratedAddress(integratedAddress) {\n this.integratedAddress = integratedAddress;\n return this;\n }\n toString() {\n return this.integratedAddress;\n }\n}\n","import MoneroError from \"../../common/MoneroError\";\n/**\n * Defines the Monero network types (mainnet, testnet, and stagenet).\n */\nclass MoneroNetworkType {\n /**\n * Validate and normalize the given network type.\n *\n * @param {MoneroNetworkType | number | string} networkType - the network type to validate and normalize\n * @return {MoneroNetworkType} the given network type\n */\n static from(networkType) {\n if (typeof networkType === \"string\")\n return MoneroNetworkType.parse(networkType);\n MoneroNetworkType.validate(networkType);\n return networkType;\n }\n /**\n * Validate the given network type.\n *\n * @param {MoneroNetworkType} networkType - the network type to validate as a numeric\n */\n static validate(networkType) {\n if (typeof networkType === \"string\")\n MoneroNetworkType.parse(networkType);\n else if (networkType !== 0 && networkType !== 1 && networkType !== 2)\n throw new MoneroError(\"Network type is invalid: \" + networkType);\n }\n /**\n * Indicates if the given network type is valid or not.\n *\n * @param {MoneroNetworkType | number} networkType - the network type to validate as a numeric\n * @return {boolean} true if the network type is valid, false otherwise\n */\n static isValid(networkType) {\n try {\n MoneroNetworkType.validate(networkType);\n return true;\n }\n catch (err) {\n return false;\n }\n }\n /**\n * Parse the given string as a network type.\n *\n * @param {string} networkTypeStr - \"mainnet\", \"testnet\", or \"stagenet\" (case insensitive)\n * @return {MoneroNetworkType} the network type as a numeric\n */\n static parse(networkTypeStr) {\n let str = (\"\" + networkTypeStr).toLowerCase();\n switch (str) {\n case \"mainnet\": return MoneroNetworkType.MAINNET;\n case \"testnet\": return MoneroNetworkType.TESTNET;\n case \"stagenet\": return MoneroNetworkType.STAGENET;\n default: throw new MoneroError(\"Invalid network type to parse: '\" + networkTypeStr + \"'\");\n }\n }\n /**\n * Get the network type in human-readable form.\n *\n * @return {string} the network type in human-readable form\n */\n static toString(networkType) {\n if (networkType === 0)\n return \"mainnet\";\n if (networkType === 1)\n return \"testnet\";\n if (networkType === 2)\n return \"stagenet\";\n throw new MoneroError(\"Invalid network type: \" + networkType);\n }\n}\n/**\n * Mainnet (value=0).\n */\nMoneroNetworkType.MAINNET = 0;\n/**\n * Testnet (value=1).\n */\nMoneroNetworkType.TESTNET = 1;\n/**\n * Stagnet (value=2).\n */\nMoneroNetworkType.STAGENET = 2;\nexport default MoneroNetworkType;\n","import assert from \"assert\";\nimport Decimal from 'decimal.js';\nimport GenUtils from \"./GenUtils\";\nimport LibraryUtils from \"./LibraryUtils\";\nimport MoneroError from \"./MoneroError\";\nimport MoneroIntegratedAddress from \"../wallet/model/MoneroIntegratedAddress\";\nimport MoneroNetworkType from \"../daemon/model/MoneroNetworkType\";\n/**\n * Collection of Monero utilities. Runs in a worker thread by default.\n */\nclass MoneroUtils {\n /**\n *

Get the version of the monero-ts library.

\n *\n * @return {string} the version of this monero-ts library\n */\n static getVersion() {\n return \"0.11.6\";\n }\n /**\n * Enable or disable proxying these utilities to a worker thread.\n *\n * @param {boolean} proxyToWorker - specifies if utilities should be proxied to a worker\n */\n static setProxyToWorker(proxyToWorker) {\n MoneroUtils.PROXY_TO_WORKER = proxyToWorker || false;\n }\n /**\n * Validate the given mnemonic, throw an error if invalid.\n *\n * TODO: improve validation, use network type\n *\n * @param {string} mnemonic - mnemonic to validate\n */\n static async validateMnemonic(mnemonic) {\n assert(mnemonic, \"Mnemonic phrase is not initialized\");\n let words = mnemonic.split(\" \");\n if (words.length !== MoneroUtils.NUM_MNEMONIC_WORDS)\n throw new MoneroError(\"Mnemonic phrase is \" + words.length + \" words but must be \" + MoneroUtils.NUM_MNEMONIC_WORDS);\n }\n /**\n * Indicates if a private view key is valid.\n *\n * @param {string} privateViewKey is the private view key to validate\n * @return {Promise} true if the private view key is valid, false otherwise\n */\n static async isValidPrivateViewKey(privateViewKey) {\n try {\n await MoneroUtils.validatePrivateViewKey(privateViewKey);\n return true;\n }\n catch (e) {\n return false;\n }\n }\n /**\n * Indicates if a public view key is valid.\n *\n * @param {string} publicViewKey is the public view key to validate\n * @return {Promise} true if the public view key is valid, false otherwise\n */\n static async isValidPublicViewKey(publicViewKey) {\n try {\n await MoneroUtils.validatePublicViewKey(publicViewKey);\n return true;\n }\n catch (e) {\n return false;\n }\n }\n /**\n * Indicates if a private spend key is valid.\n *\n * @param {string} privateSpendKey is the private spend key to validate\n * @return {Promise} true if the private spend key is valid, false otherwise\n */\n static async isValidPrivateSpendKey(privateSpendKey) {\n try {\n await MoneroUtils.validatePrivateSpendKey(privateSpendKey);\n return true;\n }\n catch (e) {\n return false;\n }\n }\n /**\n * Indicates if a public spend key is valid.\n *\n * @param {string} publicSpendKey is the public spend key to validate\n * @return {Promise} true if the public spend key is valid, false otherwise\n */\n static async isValidPublicSpendKey(publicSpendKey) {\n try {\n await MoneroUtils.validatePublicSpendKey(publicSpendKey);\n return true;\n }\n catch (e) {\n return false;\n }\n }\n /**\n * Validate the given private view key, throw an error if invalid.\n *\n * @param {string} privateViewKey - private view key to validate\n */\n static async validatePrivateViewKey(privateViewKey) {\n if (!MoneroUtils.isHex64(privateViewKey))\n throw new MoneroError(\"private view key expected to be 64 hex characters\");\n }\n /**\n * Validate the given public view key, throw an error if invalid.\n *\n * @param {string} publicViewKey - public view key to validate\n */\n static async validatePublicViewKey(publicViewKey) {\n if (!MoneroUtils.isHex64(publicViewKey))\n throw new MoneroError(\"public view key expected to be 64 hex characters\");\n }\n /**\n * Validate the given private spend key, throw an error if invalid.\n *\n * @param {string} privateSpendKey - private spend key to validate\n */\n static async validatePrivateSpendKey(privateSpendKey) {\n if (!MoneroUtils.isHex64(privateSpendKey))\n throw new MoneroError(\"private spend key expected to be 64 hex characters\");\n }\n /**\n * Validate the given public spend key, throw an error if invalid.\n *\n * @param {string} publicSpendKey - public spend key to validate\n */\n static async validatePublicSpendKey(publicSpendKey) {\n if (!MoneroUtils.isHex64(publicSpendKey))\n throw new MoneroError(\"public spend key expected to be 64 hex characters\");\n }\n /**\n * Get an integrated address.\n *\n * @param {MoneroNetworkType} networkType - network type of the integrated address\n * @param {string} standardAddress - address to derive the integrated address from\n * @param {string} [paymentId] - optionally specifies the integrated address's payment id (defaults to random payment id)\n * @return {Promise} the integrated address\n */\n static async getIntegratedAddress(networkType, standardAddress, paymentId) {\n if (MoneroUtils.PROXY_TO_WORKER)\n return new MoneroIntegratedAddress(await LibraryUtils.invokeWorker(undefined, \"moneroUtilsGetIntegratedAddress\", Array.from(arguments)));\n // validate inputs\n MoneroNetworkType.validate(networkType);\n assert(typeof standardAddress === \"string\", \"Address is not string\");\n assert(standardAddress.length > 0, \"Address is empty\");\n assert(GenUtils.isBase58(standardAddress), \"Address is not base 58\");\n // load keys module by default\n if (LibraryUtils.getWasmModule() === undefined)\n await LibraryUtils.loadWasmModule();\n // get integrated address in queue\n return LibraryUtils.getWasmModule().queueTask(async () => {\n let integratedAddressJson = LibraryUtils.getWasmModule().get_integrated_address_util(networkType, standardAddress, paymentId ? paymentId : \"\");\n if (integratedAddressJson.charAt(0) !== '{')\n throw new MoneroError(integratedAddressJson);\n return new MoneroIntegratedAddress(JSON.parse(integratedAddressJson));\n });\n }\n /**\n * Determine if the given address is valid.\n *\n * @param {string} address - address\n * @param {MoneroNetworkType} networkType - network type of the address to validate\n * @return {Promise} true if the address is valid, false otherwise\n */\n static async isValidAddress(address, networkType) {\n try {\n await MoneroUtils.validateAddress(address, networkType);\n return true;\n }\n catch (err) {\n return false;\n }\n }\n /**\n * Validate the given address, throw an error if invalid.\n *\n * @param {string} address - address to validate\n * @param {MoneroNetworkType} networkType - network type of the address to validate\n */\n static async validateAddress(address, networkType) {\n if (MoneroUtils.PROXY_TO_WORKER)\n return LibraryUtils.invokeWorker(undefined, \"moneroUtilsValidateAddress\", Array.from(arguments));\n // validate inputs\n assert(typeof address === \"string\", \"Address is not string\");\n assert(address.length > 0, \"Address is empty\");\n assert(GenUtils.isBase58(address), \"Address is not base 58\");\n networkType = MoneroNetworkType.from(networkType);\n // load keys module by default\n if (LibraryUtils.getWasmModule() === undefined)\n await LibraryUtils.loadWasmModule();\n // validate address in queue\n return LibraryUtils.getWasmModule().queueTask(async function () {\n let errMsg = LibraryUtils.getWasmModule().validate_address(address, networkType);\n if (errMsg)\n throw new MoneroError(errMsg);\n });\n }\n /**\n * Determine if the given payment id is valid.\n *\n * @param {string} paymentId - payment id to determine if valid\n * @return {Promise} true if the payment id is valid, false otherwise\n */\n static async isValidPaymentId(paymentId) {\n try {\n await MoneroUtils.validatePaymentId(paymentId);\n return true;\n }\n catch (e) {\n return false;\n }\n }\n /**\n * Validate the given payment id, throw an error if invalid.\n *\n * TODO: improve validation\n *\n * @param {string} paymentId - payment id to validate\n */\n static async validatePaymentId(paymentId) {\n assert.equal(typeof paymentId, \"string\");\n assert(paymentId.length === 16 || paymentId.length === 64);\n }\n /**\n * Decode tx extra according to https://cryptonote.org/cns/cns005.txt and\n * returns the last tx pub key.\n *\n * TODO: use c++ bridge for this\n *\n * @param [byte[]] txExtra - array of tx extra bytes\n * @return {string} the last pub key as a hexidecimal string\n */\n static async getLastTxPubKey(txExtra) {\n let lastPubKeyIdx;\n for (let i = 0; i < txExtra.length; i++) {\n let tag = txExtra[i];\n if (tag === 0 || tag === 2) {\n i += 1 + txExtra[i + 1]; // advance to next tag\n }\n else if (tag === 1) {\n lastPubKeyIdx = i + 1;\n i += 1 + 32; // advance to next tag\n }\n else\n throw new MoneroError(\"Invalid sub-field tag: \" + tag);\n }\n return Buffer.from(new Uint8Array(txExtra.slice(lastPubKeyIdx, lastPubKeyIdx + 32))).toString(\"hex\");\n }\n /**\n * Determines if two payment ids are functionally equal.\n *\n * For example, 03284e41c342f032 and 03284e41c342f032000000000000000000000000000000000000000000000000 are considered equal.\n *\n * @param {string} paymentId1 is a payment id to compare\n * @param {string} paymentId2 is a payment id to compare\n * @return {bool} true if the payment ids are equal, false otherwise\n */\n static paymentIdsEqual(paymentId1, paymentId2) {\n let maxLength = Math.max(paymentId1.length, paymentId2.length);\n for (let i = 0; i < maxLength; i++) {\n if (i < paymentId1.length && i < paymentId2.length && paymentId1[i] !== paymentId2[i])\n return false;\n if (i >= paymentId1.length && paymentId2[i] !== '0')\n return false;\n if (i >= paymentId2.length && paymentId1[i] !== '0')\n return false;\n }\n return true;\n }\n /**\n * Merges a transaction into a list of existing transactions.\n *\n * @param {MoneroTx[]} txs - existing transactions to merge into\n * @param {MoneroTx} tx - transaction to merge into the list\n */\n static mergeTx(txs, tx) {\n for (let aTx of txs) {\n if (aTx.getHash() === tx.getHash()) {\n aTx.merge(tx);\n return;\n }\n }\n txs.push(tx);\n }\n /**\n * Convert the given JSON to a binary Uint8Array using Monero's portable storage format.\n *\n * @param {object} json - json to convert to binary\n * @return {Promise} the json converted to portable storage binary\n */\n static async jsonToBinary(json) {\n if (MoneroUtils.PROXY_TO_WORKER)\n return LibraryUtils.invokeWorker(undefined, \"moneroUtilsJsonToBinary\", Array.from(arguments));\n // load keys module by default\n if (LibraryUtils.getWasmModule() === undefined)\n await LibraryUtils.loadWasmModule();\n // use wasm in queue\n return LibraryUtils.getWasmModule().queueTask(async function () {\n // serialize json to binary which is stored in c++ heap\n let binMemInfoStr = LibraryUtils.getWasmModule().malloc_binary_from_json(JSON.stringify(json));\n // sanitize binary memory address info\n let binMemInfo = JSON.parse(binMemInfoStr);\n binMemInfo.ptr = parseInt(binMemInfo.ptr);\n binMemInfo.length = parseInt(binMemInfo.length);\n // read binary data from heap to Uint8Array\n let view = new Uint8Array(binMemInfo.length);\n for (let i = 0; i < binMemInfo.length; i++) {\n view[i] = LibraryUtils.getWasmModule().HEAPU8[binMemInfo.ptr / Uint8Array.BYTES_PER_ELEMENT + i];\n }\n // free binary on heap\n LibraryUtils.getWasmModule()._free(binMemInfo.ptr);\n // return json from binary data\n return view;\n });\n }\n /**\n * Convert the given portable storage binary to JSON.\n *\n * @param {Uint8Array} uint8arr - binary data in Monero's portable storage format\n * @return {Promise} JSON object converted from the binary data\n */\n static async binaryToJson(uint8arr) {\n if (MoneroUtils.PROXY_TO_WORKER)\n return LibraryUtils.invokeWorker(undefined, \"moneroUtilsBinaryToJson\", Array.from(arguments));\n // load keys module by default\n if (LibraryUtils.getWasmModule() === undefined)\n await LibraryUtils.loadWasmModule();\n // use wasm in queue\n return LibraryUtils.getWasmModule().queueTask(async function () {\n // allocate space in c++ heap for binary\n let ptr = LibraryUtils.getWasmModule()._malloc(uint8arr.length * uint8arr.BYTES_PER_ELEMENT);\n let heap = new Uint8Array(LibraryUtils.getWasmModule().HEAPU8.buffer, ptr, uint8arr.length * uint8arr.BYTES_PER_ELEMENT);\n if (ptr !== heap.byteOffset)\n throw new MoneroError(\"Memory ptr !== heap.byteOffset\"); // should be equal\n // write binary to heap\n heap.set(new Uint8Array(uint8arr.buffer));\n // create object with binary memory address info\n let binMemInfo = { ptr: ptr, length: uint8arr.length };\n // convert binary to json str\n const ret_string = LibraryUtils.getWasmModule().binary_to_json(JSON.stringify(binMemInfo));\n // free binary on heap\n LibraryUtils.getWasmModule()._free(ptr);\n // parse and return json\n return JSON.parse(ret_string);\n });\n }\n /**\n * Convert the binary response from daemon RPC block retrieval to JSON.\n *\n * @param {Uint8Array} uint8arr - binary response from daemon RPC when getting blocks\n * @return {Promise} JSON object with the blocks data\n */\n static async binaryBlocksToJson(uint8arr) {\n if (MoneroUtils.PROXY_TO_WORKER)\n return LibraryUtils.invokeWorker(undefined, \"moneroUtilsBinaryBlocksToJson\", Array.from(arguments));\n // load keys module by default\n if (LibraryUtils.getWasmModule() === undefined)\n await LibraryUtils.loadWasmModule();\n // use wasm in queue\n return LibraryUtils.getWasmModule().queueTask(async function () {\n // allocate space in c++ heap for binary\n let ptr = LibraryUtils.getWasmModule()._malloc(uint8arr.length * uint8arr.BYTES_PER_ELEMENT);\n let heap = new Uint8Array(LibraryUtils.getWasmModule().HEAPU8.buffer, ptr, uint8arr.length * uint8arr.BYTES_PER_ELEMENT);\n if (ptr !== heap.byteOffset)\n throw new MoneroError(\"Memory ptr !== heap.byteOffset\"); // should be equal\n // write binary to heap\n heap.set(new Uint8Array(uint8arr.buffer));\n // create object with binary memory address info\n let binMemInfo = { ptr: ptr, length: uint8arr.length };\n // convert binary to json str\n const json_str = LibraryUtils.getWasmModule().binary_blocks_to_json(JSON.stringify(binMemInfo));\n // free memory\n LibraryUtils.getWasmModule()._free(ptr);\n // parse result to json\n let json = JSON.parse(json_str); // parsing json gives arrays of block and tx strings\n json.blocks = json.blocks.map(blockStr => JSON.parse(blockStr)); // replace block strings with parsed blocks\n json.txs = json.txs.map(txs => txs ? txs.map(tx => JSON.parse(tx.replace(\",\", \"{\") + \"}\")) : []); // modify tx string to proper json and parse // TODO: more efficient way than this json manipulation?\n return json;\n });\n }\n /**\n * Convert XMR to atomic units.\n *\n * @param {number | string} amountXmr - amount in XMR to convert to atomic units\n * @return {bigint} amount in atomic units\n */\n static xmrToAtomicUnits(amountXmr) {\n return BigInt(new Decimal(amountXmr).mul(MoneroUtils.AU_PER_XMR.toString()).toDecimalPlaces(0, Decimal.ROUND_HALF_UP).toFixed(0));\n }\n /**\n * Convert atomic units to XMR.\n *\n * @param {bigint | string} amountAtomicUnits - amount in atomic units to convert to XMR\n * @return {number} amount in XMR\n */\n static atomicUnitsToXmr(amountAtomicUnits) {\n return new Decimal(amountAtomicUnits.toString()).div(MoneroUtils.AU_PER_XMR.toString()).toDecimalPlaces(12, Decimal.ROUND_HALF_UP).toNumber();\n }\n /**\n * Divide one atomic units by another.\n *\n * @param {bigint} au1 dividend\n * @param {bigint} au2 divisor\n * @returns {number} the result\n */\n static divide(au1, au2) {\n return new Decimal(au1.toString()).div(new Decimal(au2.toString())).toDecimalPlaces(12, Decimal.ROUND_HALF_UP).toNumber();\n }\n /**\n * Multiply a bigint by a number or bigint.\n *\n * @param a bigint to multiply\n * @param b bigint or number to multiply by\n * @returns the product as a bigint\n */\n static multiply(a, b) {\n return BigInt(new Decimal(a.toString()).mul(new Decimal(b.toString())).toDecimalPlaces(0, Decimal.ROUND_HALF_UP).toString());\n }\n static isHex64(str) {\n return typeof str === \"string\" && str.length === 64 && GenUtils.isHex(str);\n }\n /**\n * Determine if the given unlock time is a timestamp or block height.\n *\n * @param unlockTime is the unlock time to check\n * @return {boolean} true if the unlock time is a timestamp, false if a block height\n */\n static isTimestamp(unlockTime) {\n // threshold for distinguishing between timestamp and block height\n // current block height is around 3 million, current unix timestamp is around 1.7 billion\n const threshold = 500000000n;\n return unlockTime >= threshold;\n }\n}\n// static variables\nMoneroUtils.PROXY_TO_WORKER = false;\nMoneroUtils.NUM_MNEMONIC_WORDS = 25;\nMoneroUtils.AU_PER_XMR = 1000000000000n;\nMoneroUtils.RING_SIZE = 12;\nexport default MoneroUtils;\n","import assert from \"assert\";\nimport GenUtils from \"../../common/GenUtils\";\nimport MoneroTxWallet from \"./MoneroTxWallet\";\nimport MoneroUtils from \"../../common/MoneroUtils\";\n/**\n * Groups transactions who share common hex data which is needed in order to\n * sign and submit the transactions.\n *\n * For example, multisig transactions created from createTxs() share a common\n * hex string which is needed in order to sign and submit the multisig\n * transactions.\n */\nexport default class MoneroTxSet {\n constructor(txSet) {\n Object.assign(this, txSet);\n // copy txs\n if (this.txs) {\n for (let i = 0; i < this.txs.length; i++) {\n this.txs[i] = new MoneroTxWallet(this.txs[i]);\n this.txs[i].setTxSet(this);\n }\n }\n }\n toJson() {\n let json = Object.assign({}, this); // copy state\n if (this.getTxs() !== undefined) {\n json.txs = [];\n for (let tx of this.getTxs())\n json.txs.push(tx.toJson());\n }\n return json;\n }\n getTxs() {\n return this.txs;\n }\n setTxs(txs) {\n this.txs = txs;\n return this;\n }\n getMultisigTxHex() {\n return this.multisigTxHex;\n }\n setMultisigTxHex(multisigTxHex) {\n this.multisigTxHex = multisigTxHex;\n return this;\n }\n getUnsignedTxHex() {\n return this.unsignedTxHex;\n }\n setUnsignedTxHex(unsignedTxHex) {\n this.unsignedTxHex = unsignedTxHex;\n return this;\n }\n getSignedTxHex() {\n return this.signedTxHex;\n }\n setSignedTxHex(signedTxHex) {\n this.signedTxHex = signedTxHex;\n return this;\n }\n merge(txSet) {\n assert(txSet instanceof MoneroTxSet);\n if (this === txSet)\n return this;\n // merge sets\n this.setMultisigTxHex(GenUtils.reconcile(this.getMultisigTxHex(), txSet.getMultisigTxHex()));\n this.setUnsignedTxHex(GenUtils.reconcile(this.getUnsignedTxHex(), txSet.getUnsignedTxHex()));\n this.setSignedTxHex(GenUtils.reconcile(this.getSignedTxHex(), txSet.getSignedTxHex()));\n // merge txs\n if (txSet.getTxs() !== undefined) {\n for (let tx of txSet.getTxs()) {\n tx.setTxSet(this);\n MoneroUtils.mergeTx(this.getTxs(), tx);\n }\n }\n return this;\n }\n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.kvLine(\"Multisig tx hex: \", this.getMultisigTxHex(), indent);\n str += GenUtils.kvLine(\"Unsigned tx hex: \", this.getUnsignedTxHex(), indent);\n str += GenUtils.kvLine(\"Signed tx hex: \", this.getSignedTxHex(), indent);\n if (this.getTxs() !== undefined) {\n str += GenUtils.kvLine(\"Txs\", \"\", indent);\n for (let tx of this.getTxs()) {\n str += tx.toString(indent + 1) + \"\\n\";\n }\n }\n return str;\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"../../common/GenUtils\";\nimport MoneroError from \"../../common/MoneroError\";\nimport MoneroIncomingTransfer from \"./MoneroIncomingTransfer\";\nimport MoneroOutgoingTransfer from \"./MoneroOutgoingTransfer\";\nimport MoneroOutputWallet from \"./MoneroOutputWallet\";\nimport MoneroTx from \"../../daemon/model/MoneroTx\";\nimport MoneroTxSet from \"./MoneroTxSet\";\n/**\n * Models a Monero transaction with wallet extensions.\n */\nexport default class MoneroTxWallet extends MoneroTx {\n /**\n * Construct the model.\n *\n * @param {Partial} [tx] is existing state to initialize from (optional)\n */\n constructor(tx) {\n super(tx);\n this.setTxSet(this.getTxSet()); // preserve reference to tx set\n // copy incoming transfers\n if (this.incomingTransfers) {\n this.incomingTransfers = this.incomingTransfers.slice();\n for (let i = 0; i < this.incomingTransfers.length; i++) {\n this.incomingTransfers[i] = new MoneroIncomingTransfer(this.incomingTransfers[i]).setTx(this);\n }\n }\n // copy outgoing transfer\n if (this.outgoingTransfer) {\n this.outgoingTransfer = new MoneroOutgoingTransfer(this.outgoingTransfer).setTx(this);\n }\n // copy inputs\n if (this.inputs) {\n this.inputs = this.inputs.slice();\n for (let i = 0; i < this.inputs.length; i++) {\n this.inputs[i] = new MoneroOutputWallet(this.inputs[i]).setTx(this);\n }\n }\n // copy outputs\n if (this.outputs) {\n this.outputs = this.outputs.slice();\n for (let i = 0; i < this.outputs.length; i++) {\n this.outputs[i] = new MoneroOutputWallet(this.outputs[i]).setTx(this);\n }\n }\n // deserialize bigints\n if (this.inputSum !== undefined && typeof this.inputSum !== \"bigint\")\n this.inputSum = BigInt(this.inputSum);\n if (this.outputSum !== undefined && typeof this.outputSum !== \"bigint\")\n this.outputSum = BigInt(this.outputSum);\n if (this.changeAmount !== undefined && typeof this.changeAmount !== \"bigint\")\n this.changeAmount = BigInt(this.changeAmount);\n }\n /**\n * @return {any} json representation of this tx\n */\n toJson() {\n let json = Object.assign({}, this, super.toJson()); // merge json onto inherited state\n if (this.getIncomingTransfers() !== undefined) {\n json.incomingTransfers = [];\n for (let incomingTransfer of this.getIncomingTransfers())\n json.incomingTransfers.push(incomingTransfer.toJson());\n }\n if (this.getOutgoingTransfer() !== undefined)\n json.outgoingTransfer = this.getOutgoingTransfer().toJson();\n if (this.getInputSum() !== undefined)\n json.inputSum = this.getInputSum().toString();\n if (this.getOutputSum() !== undefined)\n json.outputSum = this.getOutputSum().toString();\n if (this.getChangeAmount() !== undefined)\n json.changeAmount = this.getChangeAmount().toString();\n delete json.block; // do not serialize parent block\n delete json.txSet; // do not serialize parent tx set\n return json;\n }\n /**\n * @return {MoneroTxSet} tx set containing txs\n */\n getTxSet() {\n return this.txSet;\n }\n /**\n * @param {MoneroTxSet} txSet - tx set containing txs\n * @return {MoneroTxWallet} this tx for chaining\n */\n setTxSet(txSet) {\n this.txSet = txSet;\n return this;\n }\n /**\n * @return {boolean} true if the tx has incoming funds, false otherwise\n */\n getIsIncoming() {\n return this.isIncoming;\n }\n /**\n * @param {boolean} isIncoming - true if the tx has incoming funds, false otherwise\n * @return {MoneroTxWallet} this tx for chaining\n */\n setIsIncoming(isIncoming) {\n this.isIncoming = isIncoming;\n return this;\n }\n /**\n * @return {boolean} true if the tx has outgoing funds, false otherwise\n */\n getIsOutgoing() {\n return this.isOutgoing;\n }\n /**\n * @param {boolean} isOutgoing - true if the tx has outgoing funds, false otherwise\n * @return {MoneroTxWallet} this tx for chaining\n */\n setIsOutgoing(isOutgoing) {\n this.isOutgoing = isOutgoing;\n return this;\n }\n /**\n * @return {bigint} amount received in the tx\n */\n getIncomingAmount() {\n if (this.getIncomingTransfers() === undefined)\n return undefined;\n let incomingAmt = 0n;\n for (let transfer of this.getIncomingTransfers())\n incomingAmt = incomingAmt + transfer.getAmount();\n return incomingAmt;\n }\n /**\n * @return {bigint} amount spent in the tx\n */\n getOutgoingAmount() {\n return this.getOutgoingTransfer() ? this.getOutgoingTransfer().getAmount() : undefined;\n }\n /**\n * @param {MoneroTransferQuery} [transferQuery] - query to get specific transfers\n * @return {MoneroTransfer[]} transfers matching the query\n */\n getTransfers(transferQuery) {\n let transfers = [];\n if (this.getOutgoingTransfer() && (!transferQuery || transferQuery.meetsCriteria(this.getOutgoingTransfer())))\n transfers.push(this.getOutgoingTransfer());\n if (this.getIncomingTransfers() !== undefined) {\n for (let transfer of this.getIncomingTransfers()) {\n if (!transferQuery || transferQuery.meetsCriteria(transfer))\n transfers.push(transfer);\n }\n }\n return transfers;\n }\n /**\n * @param {MoneroTransferQuery} transferQuery - query to keep only specific transfers\n * @return {MoneroTransfer[]} remaining transfers matching the query\n */\n filterTransfers(transferQuery) {\n let transfers = [];\n // collect outgoing transfer or erase if filtered\n if (this.getOutgoingTransfer() && (!transferQuery || transferQuery.meetsCriteria(this.getOutgoingTransfer())))\n transfers.push(this.getOutgoingTransfer());\n else\n this.setOutgoingTransfer(undefined);\n // collect incoming transfers or erase if filtered\n if (this.getIncomingTransfers() !== undefined) {\n let toRemoves = [];\n for (let transfer of this.getIncomingTransfers()) {\n if (transferQuery.meetsCriteria(transfer))\n transfers.push(transfer);\n else\n toRemoves.push(transfer);\n }\n this.setIncomingTransfers(this.getIncomingTransfers().filter(function (transfer) {\n return !toRemoves.includes(transfer);\n }));\n if (this.getIncomingTransfers().length === 0)\n this.setIncomingTransfers(undefined);\n }\n return transfers;\n }\n /**\n * @return {MoneroIncomingTransfer[]} incoming transfers\n */\n getIncomingTransfers() {\n return this.incomingTransfers;\n }\n /**\n * @param {MoneroIncomingTransfer[]} incomingTransfers - incoming transfers\n * @return {MoneroTxWallet} this tx for chaining\n */\n setIncomingTransfers(incomingTransfers) {\n this.incomingTransfers = incomingTransfers;\n return this;\n }\n /**\n * @return {MoneroOutgoingTransfer} outgoing transfers\n */\n getOutgoingTransfer() {\n return this.outgoingTransfer;\n }\n /**\n * @param {MoneroOutgoingTransfer} outgoingTransfer - outgoing transfer\n * @return {MoneroTxWallet} this tx for chaining\n */\n setOutgoingTransfer(outgoingTransfer) {\n this.outgoingTransfer = outgoingTransfer;\n return this;\n }\n /**\n * @param {MoneroOutputWallet[]} outputQuery - query to get specific inputs\n * @return {MoneroOutputWallet[]} inputs matching the query\n */\n getInputsWallet(outputQuery) {\n let inputs = [];\n for (let output of super.getInputs())\n if (!outputQuery || outputQuery.meetsCriteria(output))\n inputs.push(output);\n return inputs;\n }\n /**\n * @param {MoneroOutputWallet[]} inputs - tx inputs\n * @return {MoneroTxWallet} this tx for chaining\n */\n setInputsWallet(inputs) {\n // validate that all inputs are wallet inputs\n if (inputs) {\n for (let output of inputs) {\n if (!(output instanceof MoneroOutputWallet))\n throw new MoneroError(\"Wallet transaction inputs must be of type MoneroOutputWallet\");\n }\n }\n super.setInputs(inputs);\n return this;\n }\n /**\n * @param {MoneroOutputQuery} [outputQuery] - query to get specific outputs\n * @return {MoneroOutputWallet[]} outputs matching the query\n */\n getOutputsWallet(outputQuery) {\n let outputs = [];\n for (let output of super.getOutputs())\n if (!outputQuery || outputQuery.meetsCriteria(output))\n outputs.push(output);\n return outputs;\n }\n /**\n * @param {MoneroOutputWallet[]} outputs - tx outputs\n * @return {MoneroTxWallet} this tx for chaining\n */\n setOutputsWallet(outputs) {\n // validate that all outputs are wallet outputs\n if (outputs) {\n for (let output of outputs) {\n if (!(output instanceof MoneroOutputWallet))\n throw new MoneroError(\"Wallet transaction outputs must be of type MoneroOutputWallet\");\n }\n }\n super.setOutputs(outputs);\n return this;\n }\n /**\n * @param {MoneroOutputQuery} outputQuery - query to keep only specific outputs\n * @return {MoneroTransfer[]} remaining outputs matching the query\n */\n filterOutputs(outputQuery) {\n let outputs = [];\n if (super.getOutputs()) {\n let toRemoves = [];\n for (let output of super.getOutputs()) {\n if (!outputQuery || outputQuery.meetsCriteria(output))\n outputs.push(output);\n else\n toRemoves.push(output);\n }\n this.setOutputs(super.getOutputs().filter(function (output) {\n return !toRemoves.includes(output);\n }));\n if (this.getOutputs().length === 0)\n this.setOutputs(undefined);\n }\n return outputs;\n }\n /**\n * @return {string} tx note\n */\n getNote() {\n return this.note;\n }\n /**\n * @param {string} note - tx note\n * @return {MoneroTxWallet} this tx for chaining\n */\n setNote(note) {\n this.note = note;\n return this;\n }\n /**\n * @return {boolean} true if the tx is locked, false otherwise\n */\n getIsLocked() {\n return this.isLocked;\n }\n /**\n * @param {boolean} isLocked - true if the tx is locked, false otherwise\n * @return {MoneroTxWallet} this tx for chaining\n */\n setIsLocked(isLocked) {\n this.isLocked = isLocked;\n return this;\n }\n /**\n * @return {bigint} sum of tx inputs\n */\n getInputSum() {\n return this.inputSum;\n }\n /**\n * @param {bigint} inputSum - sum of tx inputs\n * @return {MoneroTxWallet} this tx for chaining\n */\n setInputSum(inputSum) {\n this.inputSum = inputSum;\n return this;\n }\n /**\n * @return {bigint} sum of tx outputs\n */\n getOutputSum() {\n return this.outputSum;\n }\n /**\n * @param {bigint} outputSum - sum of tx outputs\n * @return {MoneroTxWallet} this tx for chaining\n */\n setOutputSum(outputSum) {\n this.outputSum = outputSum;\n return this;\n }\n /**\n * @return {string} change address\n */\n getChangeAddress() {\n return this.changeAddress;\n }\n /**\n * @param {string} changeAddress - change address\n * @return {MoneroTxWallet} this tx for chaining\n */\n setChangeAddress(changeAddress) {\n this.changeAddress = changeAddress;\n return this;\n }\n /**\n * @return {bigint} change amount\n */\n getChangeAmount() {\n return this.changeAmount;\n }\n /**\n * @param {bigint} changeAmount - change amount\n * @return {MoneroTxWallet} this tx for chaining\n */\n setChangeAmount(changeAmount) {\n this.changeAmount = changeAmount;\n return this;\n }\n /**\n * @return {number} number of dummy outputs\n */\n getNumDummyOutputs() {\n return this.numDummyOutputs;\n }\n /**\n * @param {number} numDummyOutputs - number of dummy outputs\n * @return {MoneroTxWallet} this tx for chaining\n */\n setNumDummyOutputs(numDummyOutputs) {\n this.numDummyOutputs = numDummyOutputs;\n return this;\n }\n /**\n * @return {string} tx extra as hex\n */\n getExtraHex() {\n return this.extraHex;\n }\n /**\n * @param {string} extraHex - tx extra as hex\n * @return {MoneroTxWallet} this tx for chaining\n */\n setExtraHex(extraHex) {\n this.extraHex = extraHex;\n return this;\n }\n /**\n * @return {MoneroTxWallet} a copy of this tx\n */\n copy() {\n return new MoneroTxWallet(this);\n }\n /**\n * Updates this transaction by merging the latest information from the given\n * transaction.\n *\n * Merging can modify or build references to the transaction given so it\n * should not be re-used or it should be copied before calling this method.\n *\n * @param {MoneroTxWallet} tx - the transaction to merge into this transaction\n */\n merge(tx) {\n assert(tx instanceof MoneroTxWallet);\n if (this === tx)\n return this;\n // merge base classes\n super.merge(tx);\n // merge tx set if they're different which comes back to merging txs\n //import MoneroTxSet from \"./MoneroTxSet\";\n if (this.getTxSet() !== tx.getTxSet()) {\n if (this.getTxSet() == undefined) {\n this.setTxSet(new MoneroTxSet().setTxs([this]));\n }\n if (tx.getTxSet() === undefined) {\n tx.setTxSet(new MoneroTxSet().setTxs([tx]));\n }\n this.getTxSet().merge(tx.getTxSet());\n return this;\n }\n // merge incoming transfers\n if (tx.getIncomingTransfers()) {\n if (this.getIncomingTransfers() === undefined)\n this.setIncomingTransfers([]);\n for (let transfer of tx.getIncomingTransfers()) {\n transfer.setTx(this);\n MoneroTxWallet.mergeIncomingTransfer(this.getIncomingTransfers(), transfer);\n }\n }\n // merge outgoing transfer\n if (tx.getOutgoingTransfer()) {\n tx.getOutgoingTransfer().setTx(this);\n if (this.getOutgoingTransfer() === undefined)\n this.setOutgoingTransfer(tx.getOutgoingTransfer());\n else\n this.getOutgoingTransfer().merge(tx.getOutgoingTransfer());\n }\n // merge simple extensions\n this.setIsIncoming(GenUtils.reconcile(this.getIsIncoming(), tx.getIsIncoming(), { resolveTrue: true })); // outputs seen on confirmation\n this.setIsOutgoing(GenUtils.reconcile(this.getIsOutgoing(), tx.getIsOutgoing()));\n this.setNote(GenUtils.reconcile(this.getNote(), tx.getNote()));\n this.setIsLocked(GenUtils.reconcile(this.getIsLocked(), tx.getIsLocked(), { resolveTrue: false })); // tx can become unlocked\n this.setInputSum(GenUtils.reconcile(this.getInputSum(), tx.getInputSum()));\n this.setOutputSum(GenUtils.reconcile(this.getOutputSum(), tx.getOutputSum()));\n this.setChangeAddress(GenUtils.reconcile(this.getChangeAddress(), tx.getChangeAddress()));\n this.setChangeAmount(GenUtils.reconcile(this.getChangeAmount(), tx.getChangeAmount()));\n this.setNumDummyOutputs(GenUtils.reconcile(this.getNumDummyOutputs(), tx.getNumDummyOutputs()));\n this.setExtraHex(GenUtils.reconcile(this.getExtraHex(), tx.getExtraHex()));\n return this; // for chaining\n }\n /**\n * @param {number} [indent] - starting indentation\n * @param {boolean} [oneLine] - string is one line if true, multiple lines if false\n * @return {string} string representation of this tx\n */\n toString(indent = 0, oneLine = false) {\n let str = \"\";\n // represent tx with one line string\n // TODO: proper csv export\n if (oneLine) {\n str += this.getHash() + \", \";\n str += (this.getIsConfirmed() ? this.getBlock().getTimestamp() : this.getReceivedTimestamp()) + \", \";\n str += this.getIsConfirmed() + \", \";\n str += (this.getOutgoingAmount() ? this.getOutgoingAmount().toString() : \"\") + \", \";\n str += this.getIncomingAmount() ? this.getIncomingAmount().toString() : \"\";\n return str;\n }\n // otherwise stringify all fields\n str += super.toString(indent) + \"\\n\";\n str += GenUtils.kvLine(\"Is incoming\", this.getIsIncoming(), indent);\n str += GenUtils.kvLine(\"Incoming amount\", this.getIncomingAmount(), indent);\n if (this.getIncomingTransfers() !== undefined) {\n str += GenUtils.kvLine(\"Incoming transfers\", \"\", indent);\n for (let i = 0; i < this.getIncomingTransfers().length; i++) {\n str += GenUtils.kvLine(i + 1, \"\", indent + 1);\n str += this.getIncomingTransfers()[i].toString(indent + 2) + \"\\n\";\n }\n }\n str += GenUtils.kvLine(\"Is outgoing\", this.getIsOutgoing(), indent);\n str += GenUtils.kvLine(\"Outgoing amount\", this.getOutgoingAmount(), indent);\n if (this.getOutgoingTransfer() !== undefined) {\n str += GenUtils.kvLine(\"Outgoing transfer\", \"\", indent);\n str += this.getOutgoingTransfer().toString(indent + 1) + \"\\n\";\n }\n str += GenUtils.kvLine(\"Note\", this.getNote(), indent);\n str += GenUtils.kvLine(\"Is locked\", this.getIsLocked(), indent);\n str += GenUtils.kvLine(\"Input sum\", this.getInputSum(), indent);\n str += GenUtils.kvLine(\"Output sum\", this.getOutputSum(), indent);\n str += GenUtils.kvLine(\"Change address\", this.getChangeAddress(), indent);\n str += GenUtils.kvLine(\"Change amount\", this.getChangeAmount(), indent);\n str += GenUtils.kvLine(\"Num dummy outputs\", this.getNumDummyOutputs(), indent);\n str += GenUtils.kvLine(\"Extra hex\", this.getExtraHex(), indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n // private helper to merge transfers\n static mergeIncomingTransfer(transfers, transfer) {\n for (let aTransfer of transfers) {\n if (aTransfer.getAccountIndex() === transfer.getAccountIndex() && aTransfer.getSubaddressIndex() === transfer.getSubaddressIndex()) {\n aTransfer.merge(transfer);\n return;\n }\n }\n transfers.push(transfer);\n }\n // -------------------- OVERRIDE COVARIANT RETURN TYPES ---------------------\n setBlock(block) {\n super.setBlock(block);\n return this;\n }\n setHash(hash) {\n super.setHash(hash);\n return this;\n }\n setVersion(version) {\n super.setVersion(version);\n return this;\n }\n setIsMinerTx(isMinerTx) {\n super.setIsMinerTx(isMinerTx);\n return this;\n }\n setPaymentId(paymentId) {\n super.setPaymentId(paymentId);\n return this;\n }\n setFee(fee) {\n super.setFee(fee);\n return this;\n }\n setRingSize(ringSize) {\n super.setRingSize(ringSize);\n return this;\n }\n setRelay(relay) {\n super.setRelay(relay);\n return this;\n }\n setIsRelayed(isRelayed) {\n super.setIsRelayed(isRelayed);\n return this;\n }\n setIsConfirmed(isConfirmed) {\n super.setIsConfirmed(isConfirmed);\n return this;\n }\n setInTxPool(inTxPool) {\n super.setInTxPool(inTxPool);\n return this;\n }\n setNumConfirmations(numConfirmations) {\n super.setNumConfirmations(numConfirmations);\n return this;\n }\n setUnlockTime(unlockTime) {\n super.setUnlockTime(unlockTime);\n return this;\n }\n setLastRelayedTimestamp(lastRelayedTimestamp) {\n super.setLastRelayedTimestamp(lastRelayedTimestamp);\n return this;\n }\n setReceivedTimestamp(receivedTimestamp) {\n super.setReceivedTimestamp(receivedTimestamp);\n return this;\n }\n setIsDoubleSpendSeen(isDoubleSpendSeen) {\n super.setIsDoubleSpendSeen(isDoubleSpendSeen);\n return this;\n }\n setKey(key) {\n super.setKey(key);\n return this;\n }\n setFullHex(fullHex) {\n super.setFullHex(fullHex);\n return this;\n }\n setPrunedHex(prunedHex) {\n super.setPrunedHex(prunedHex);\n return this;\n }\n setPrunableHex(prunableHex) {\n super.setPrunableHex(prunableHex);\n return this;\n }\n setPrunableHash(prunableHash) {\n super.setPrunableHash(prunableHash);\n return this;\n }\n setSize(size) {\n super.setSize(size);\n return this;\n }\n setWeight(weight) {\n super.setWeight(weight);\n return this;\n }\n setInputs(inputs) {\n super.setInputs(inputs);\n return this;\n }\n setOutputs(outputs) {\n super.setOutputs(outputs);\n return this;\n }\n setOutputIndices(outputIndices) {\n super.setOutputIndices(outputIndices);\n return this;\n }\n setMetadata(metadata) {\n super.setMetadata(metadata);\n return this;\n }\n setExtra(extra) {\n super.setExtra(extra);\n return this;\n }\n setRctSignatures(rctSignatures) {\n super.setRctSignatures(rctSignatures);\n return this;\n }\n setRctSigPrunable(rctSigPrunable) {\n super.setRctSigPrunable(rctSigPrunable);\n return this;\n }\n setIsKeptByBlock(isKeptByBlock) {\n super.setIsKeptByBlock(isKeptByBlock);\n return this;\n }\n setIsFailed(isFailed) {\n super.setIsFailed(isFailed);\n return this;\n }\n setLastFailedHeight(lastFailedHeight) {\n super.setLastFailedHeight(lastFailedHeight);\n return this;\n }\n setLastFailedHash(lastFailedHash) {\n super.setLastFailedHash(lastFailedHash);\n return this;\n }\n setMaxUsedBlockHeight(maxUsedBlockHeight) {\n super.setMaxUsedBlockHeight(maxUsedBlockHeight);\n return this;\n }\n setMaxUsedBlockHash(maxUsedBlockHash) {\n super.setMaxUsedBlockHash(maxUsedBlockHash);\n return this;\n }\n setSignatures(signatures) {\n super.setSignatures(signatures);\n return this;\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"../../common/GenUtils\";\nimport MoneroError from \"../../common/MoneroError\";\nimport MoneroOutput from \"../../daemon/model/MoneroOutput\";\nimport MoneroTxWallet from \"./MoneroTxWallet\";\n/**\n * Models a Monero output with wallet extensions.\n */\nexport default class MoneroOutputWallet extends MoneroOutput {\n /**\n * Construct the model.\n *\n * @param {MoneroOutputWallet} [output] is existing state to initialize from (optional)\n */\n constructor(output) {\n super(output);\n }\n getTx() {\n return super.getTx();\n }\n setTx(tx) {\n if (tx !== undefined && !(tx instanceof MoneroTxWallet))\n throw new MoneroError(\"Wallet output's transaction must be of type MoneroTxWallet\");\n super.setTx(tx);\n return this;\n }\n getAccountIndex() {\n return this.accountIndex;\n }\n setAccountIndex(accountIndex) {\n this.accountIndex = accountIndex;\n return this;\n }\n getSubaddressIndex() {\n return this.subaddressIndex;\n }\n setSubaddressIndex(subaddressIndex) {\n this.subaddressIndex = subaddressIndex;\n return this;\n }\n getIsSpent() {\n return this.isSpent;\n }\n setIsSpent(isSpent) {\n this.isSpent = isSpent;\n return this;\n }\n /**\n * Indicates if this output has been deemed 'malicious' and will therefore\n * not be spent by the wallet.\n *\n * @return Boolean is whether or not this output is frozen\n */\n getIsFrozen() {\n return this.isFrozen;\n }\n setIsFrozen(isFrozen) {\n this.isFrozen = isFrozen;\n return this;\n }\n getIsLocked() {\n if (this.getTx() === undefined)\n return undefined;\n return this.getTx().getIsLocked();\n }\n copy() {\n return new MoneroOutputWallet(this.toJson());\n }\n toJson() {\n let json = Object.assign({}, this, super.toJson());\n delete json.tx;\n return json;\n }\n /**\n * Updates this output by merging the latest information from the given\n * output.\n *\n * Merging can modify or build references to the output given so it\n * should not be re-used or it should be copied before calling this method.\n *\n * @param output is the output to merge into this one\n */\n merge(output) {\n assert(output instanceof MoneroOutputWallet);\n if (this === output)\n return;\n super.merge(output);\n this.setAccountIndex(GenUtils.reconcile(this.getAccountIndex(), output.getAccountIndex()));\n this.setSubaddressIndex(GenUtils.reconcile(this.getSubaddressIndex(), output.getSubaddressIndex()));\n this.setIsSpent(GenUtils.reconcile(this.getIsSpent(), output.getIsSpent(), { resolveTrue: true })); // output can become spent\n this.setIsFrozen(GenUtils.reconcile(this.getIsFrozen(), output.getIsFrozen()));\n return this;\n }\n toString(indent = 0) {\n let str = super.toString(indent) + \"\\n\";\n str += GenUtils.kvLine(\"Account index\", this.getAccountIndex(), indent);\n str += GenUtils.kvLine(\"Subaddress index\", this.getSubaddressIndex(), indent);\n str += GenUtils.kvLine(\"Is spent\", this.getIsSpent(), indent);\n str += GenUtils.kvLine(\"Is frozen\", this.getIsFrozen(), indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n // -------------------- OVERRIDE COVARIANT RETURN TYPES ---------------------\n setKeyImage(keyImage) {\n super.setKeyImage(keyImage);\n return this;\n }\n setAmount(amount) {\n super.setAmount(amount);\n return this;\n }\n setIndex(index) {\n super.setIndex(index);\n return this;\n }\n setRingOutputIndices(ringOutputIndices) {\n super.setRingOutputIndices(ringOutputIndices);\n return this;\n }\n setStealthPublicKey(stealthPublicKey) {\n super.setStealthPublicKey(stealthPublicKey);\n return this;\n }\n}\n","import MoneroError from \"../../common/MoneroError\";\nimport MoneroOutputWallet from \"./MoneroOutputWallet\";\nimport MoneroTxQuery from \"./MoneroTxQuery\";\n/**\n * Configuration to query wallet outputs.\n */\nexport default class MoneroOutputQuery extends MoneroOutputWallet {\n /**\n *

Construct the output query.

\n *\n *

Example:

\n *\n * \n * // get available outputs in account 0 with a minimum amount
\n * let outputs = await wallet.getOutputs({
\n *    isSpent: false,
\n *    isLocked: false,
\n *    accountIndex: 0,
\n *    minAmount: 750000n
\n * });\n *
\n *\n *

All configuration is optional. All outputs are returned except those that don't meet criteria defined in this query.

\n *\n * @param {MoneroOutputQuery} [config] - output query configuration (optional)\n * @param {number} config.accountIndex - get outputs in this account index\n * @param {number} config.subaddressIndex - get outputs in this subaddress index\n * @param {number[]} config.subaddressIndices - get outputs in these subaddress indices\n * @param {bigint} config.amount - get outputs with this amount\n * @param {bigint} config.minAmount - get outputs with amount greater than or equal to this amount\n * @param {bigint} config.maxAmount - get outputs with amount less than or equal to this amount\n * @param {boolean} config.isSpent - get spent xor unspent outputs\n * @param {boolean} config.isFrozen - get frozen xor thawed outputs\n * @param {MoneroKeyImage} config.keyImage - get outputs with a key image matching fields defined in this key image\n * @param {string} config.keyImage.hex - get outputs with this key image hex\n * @param {string} config.keyImage.signature - get outputs with this key image signature\n * @param {MoneroTxQuery} config.txQuery - get outputs whose tx match this tx query\n */\n constructor(query) {\n super(query);\n if (this.minAmount !== undefined && typeof this.minAmount !== \"bigint\")\n this.minAmount = BigInt(this.minAmount);\n if (this.maxAmount !== undefined && typeof this.maxAmount !== \"bigint\")\n this.maxAmount = BigInt(this.maxAmount);\n if (this.txQuery && !(this.txQuery instanceof MoneroTxQuery))\n this.txQuery = new MoneroTxQuery(this.txQuery);\n if (this.txQuery)\n this.txQuery.setOutputQuery(this);\n if (this.isLocked !== undefined)\n throw new MoneroError(\"isLocked must be part of tx query, not output query\");\n }\n copy() {\n return new MoneroOutputQuery(this);\n }\n toJson() {\n let json = Object.assign({}, this, super.toJson());\n if (this.getMinAmount() !== undefined)\n json.minAmount = this.getMinAmount().toString();\n if (this.getMaxAmount() !== undefined)\n json.maxAmount = this.getMaxAmount().toString();\n delete json.txQuery;\n return json;\n }\n getMinAmount() {\n return this.minAmount;\n }\n setMinAmount(minAmount) {\n this.minAmount = minAmount;\n return this;\n }\n getMaxAmount() {\n return this.maxAmount;\n }\n setMaxAmount(maxAmount) {\n this.maxAmount = maxAmount;\n return this;\n }\n getTxQuery() {\n return this.txQuery;\n }\n setTxQuery(txQuery) {\n this.txQuery = txQuery === undefined ? undefined : txQuery instanceof MoneroTxQuery ? txQuery : new MoneroTxQuery(txQuery);\n if (txQuery)\n this.txQuery.outputQuery = this;\n return this;\n }\n getSubaddressIndices() {\n return this.subaddressIndices;\n }\n setSubaddressIndices(subaddressIndices) {\n this.subaddressIndices = subaddressIndices;\n return this;\n }\n meetsCriteria(output, queryParent = true) {\n if (!(output instanceof MoneroOutputWallet))\n throw new Error(\"Output not given to MoneroOutputQuery.meetsCriteria(output)\");\n // filter on output\n if (this.getAccountIndex() !== undefined && this.getAccountIndex() !== output.getAccountIndex())\n return false;\n if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() !== output.getSubaddressIndex())\n return false;\n if (this.getAmount() !== undefined && this.getAmount() !== output.getAmount())\n return false;\n if (this.getIsSpent() !== undefined && this.getIsSpent() !== output.getIsSpent())\n return false;\n if (this.getIsFrozen() !== undefined && this.getIsFrozen() !== output.getIsFrozen())\n return false;\n // filter on output's key image\n if (this.getKeyImage() !== undefined) {\n if (output.getKeyImage() === undefined)\n return false;\n if (this.getKeyImage().getHex() !== undefined && this.getKeyImage().getHex() !== output.getKeyImage().getHex())\n return false;\n if (this.getKeyImage().getSignature() !== undefined && this.getKeyImage().getSignature() !== output.getKeyImage().getSignature())\n return false;\n }\n // filter on extensions\n if (this.getSubaddressIndices() !== undefined && !this.getSubaddressIndices().includes(output.getSubaddressIndex()))\n return false;\n // filter with tx query\n if (this.getTxQuery() && !this.getTxQuery().meetsCriteria(output.getTx(), false))\n return false;\n // filter on remaining fields\n if (this.getMinAmount() !== undefined && (output.getAmount() === undefined || output.getAmount() < this.getMinAmount()))\n return false;\n if (this.getMaxAmount() !== undefined && (output.getAmount() === undefined || output.getAmount() > this.getMaxAmount()))\n return false;\n // output meets query\n return true;\n }\n // -------------------- OVERRIDE COVARIANT RETURN TYPES ---------------------\n setTx(tx) {\n super.setTx(tx);\n return this;\n }\n setAccountIndex(accountIndex) {\n super.setAccountIndex(accountIndex);\n return this;\n }\n setSubaddressIndex(subaddressIndex) {\n super.setSubaddressIndex(subaddressIndex);\n return this;\n }\n setIsSpent(isSpent) {\n super.setIsSpent(isSpent);\n return this;\n }\n setIsFrozen(isFrozen) {\n super.setIsFrozen(isFrozen);\n return this;\n }\n setKeyImage(keyImage) {\n super.setKeyImage(keyImage);\n return this;\n }\n setAmount(amount) {\n super.setAmount(amount);\n return this;\n }\n setIndex(index) {\n super.setIndex(index);\n return this;\n }\n setRingOutputIndices(ringOutputIndices) {\n super.setRingOutputIndices(ringOutputIndices);\n return this;\n }\n setStealthPublicKey(stealthPublicKey) {\n super.setStealthPublicKey(stealthPublicKey);\n return this;\n }\n}\n","import MoneroIncomingTransfer from \"./MoneroIncomingTransfer\";\nimport MoneroOutgoingTransfer from \"./MoneroOutgoingTransfer\";\nimport MoneroTransfer from \"./MoneroTransfer\";\nimport MoneroTxQuery from \"./MoneroTxQuery\";\nimport MoneroError from \"../../common/MoneroError\";\n/**\n * Configuration to query wallet transfers.\n */\nexport default class MoneroTransferQuery extends MoneroTransfer {\n /**\n *

Construct the transfer query.

\n *\n *

Example:

\n *\n * \n * // get incoming transfers to account 0, subaddress 1
\n * let transfers = await wallet.getTransfers({
\n *    accountIndex: 0,
\n *    subaddressIndex: 0
\n * });\n *
\n *\n *

All configuration is optional. All transfers are returned except those that don't meet criteria defined in this query.

\n *\n * @param {Partial} [query] - transfer query configuration (optional)\n * @param {bigint} query.amount - get transfers with this amount\n * @param {number} query.accountIndex - get transfers to/from this account index\n * @param {number} query.subaddressIndex - get transfers to/from this subaddress index\n * @param {number[]} query.subaddressIndices - get transfers to/from these subaddress indices\n * @param {string} query.address - get transfers to/from this wallet address\n * @param {string[]} query.addresses - get transfers to/from these wallet addresses\n * @param {boolean} query.isIncoming - get transfers which are incoming if true\n * @param {boolean} query.isOutgoing - get transfers which are outgoing if true\n * @param {boolean} query.hasDestinations - get transfers with known destinations if true (destinations are only stored locally with the wallet)\n * @param {MoneroTxQuery} query.txQuery - get transfers whose tx match this tx query\n */\n constructor(query) {\n super(query);\n if (this.txQuery && !(this.txQuery instanceof MoneroTxQuery))\n this.txQuery = new MoneroTxQuery(this.txQuery);\n if (this.txQuery)\n this.txQuery.setTransferQuery(this);\n // alias isOutgoing to isIncoming\n if (this.isOutgoing !== undefined)\n this.isIncoming = !this.isOutgoing;\n this.validate();\n }\n copy() {\n return new MoneroTransferQuery(this);\n }\n toJson() {\n let json = Object.assign({}, this, super.toJson());\n delete json.txQuery;\n return json;\n }\n getTxQuery() {\n return this.txQuery;\n }\n setTxQuery(txQuery) {\n this.txQuery = txQuery;\n if (txQuery)\n txQuery.setTransferQuery(this);\n return this;\n }\n getIsIncoming() {\n return this.isIncoming;\n }\n setIsIncoming(isIncoming) {\n this.isIncoming = isIncoming;\n return this;\n }\n getIsOutgoing() {\n return this.isIncoming === undefined ? undefined : !this.isIncoming;\n }\n setIsOutgoing(isOutgoing) {\n this.isIncoming = isOutgoing === undefined ? undefined : !isOutgoing;\n return this;\n }\n getAddress() {\n return this.address;\n }\n setAddress(address) {\n this.address = address;\n return this;\n }\n getAddresses() {\n return this.addresses;\n }\n setAddresses(addresses) {\n this.addresses = addresses;\n return this;\n }\n getSubaddressIndex() {\n return this.subaddressIndex;\n }\n setSubaddressIndex(subaddressIndex) {\n this.subaddressIndex = subaddressIndex;\n this.validate();\n return this;\n }\n getSubaddressIndices() {\n return this.subaddressIndices;\n }\n setSubaddressIndices(subaddressIndices) {\n this.subaddressIndices = subaddressIndices;\n this.validate();\n return this;\n }\n getDestinations() {\n return this.destinations;\n }\n setDestinations(destinations) {\n this.destinations = destinations;\n return this;\n }\n getHasDestinations() {\n return this.hasDestinations;\n }\n setHasDestinations(hasDestinations) {\n this.hasDestinations = hasDestinations;\n return this;\n }\n /**\n * Convenience method to query outputs by the locked state of their tx.\n *\n * @param isLocked specifies if the output's tx must be locked or unlocked (optional)\n * @return {MoneroOutputQuery} this query for chaining\n */\n setIsLocked(isLocked) {\n if (this.txQuery === undefined)\n this.txQuery = new MoneroTxQuery();\n this.getTxQuery().setIsLocked(isLocked);\n return this;\n }\n meetsCriteria(transfer, queryParent = true) {\n if (!(transfer instanceof MoneroTransfer))\n throw new Error(\"Transfer not given to MoneroTransferQuery.meetsCriteria(transfer)\");\n // filter on common fields\n if (this.getIsIncoming() !== undefined && this.getIsIncoming() !== transfer.getIsIncoming())\n return false;\n if (this.getIsOutgoing() !== undefined && this.getIsOutgoing() !== transfer.getIsOutgoing())\n return false;\n if (this.getAmount() !== undefined && this.getAmount() !== transfer.getAmount())\n return false;\n if (this.getAccountIndex() !== undefined && this.getAccountIndex() !== transfer.getAccountIndex())\n return false;\n // filter on incoming fields\n if (transfer instanceof MoneroIncomingTransfer) {\n if (this.getHasDestinations() !== undefined)\n return false;\n if (this.getAddress() !== undefined && this.getAddress() !== transfer.getAddress())\n return false;\n if (this.getAddresses() !== undefined && !this.getAddresses().includes(transfer.getAddress()))\n return false;\n if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() !== transfer.getSubaddressIndex())\n return false;\n if (this.getSubaddressIndices() !== undefined && !this.getSubaddressIndices().includes(transfer.getSubaddressIndex()))\n return false;\n }\n // filter on outgoing fields\n else if (transfer instanceof MoneroOutgoingTransfer) {\n // filter on addresses which must have overlap\n if (this.getAddress() !== undefined && (transfer.getAddresses() === undefined || !transfer.getAddresses().includes(this.getAddress())))\n return false; // TODO: will filter all transfers that don't contain addresses (outgoing txs might not have this field initialized)\n if (this.getAddresses() !== undefined) {\n if (!transfer.getAddresses())\n return false;\n if (!this.getAddresses().some(address => transfer.getAddresses().includes(address)))\n return false;\n }\n // filter on subaddress indices\n if (this.getSubaddressIndex() !== undefined && (transfer.getSubaddressIndices() === undefined || !transfer.getSubaddressIndices().includes(this.getSubaddressIndex())))\n return false;\n if (this.getSubaddressIndices() !== undefined) {\n if (!transfer.getSubaddressIndices())\n return false;\n if (!this.getSubaddressIndices().some(subaddressIdx => transfer.getSubaddressIndices().includes(subaddressIdx)))\n return false;\n }\n // filter on having destinations\n if (this.getHasDestinations() !== undefined) {\n if (this.getHasDestinations() && transfer.getDestinations() === undefined)\n return false;\n if (!this.getHasDestinations() && transfer.getDestinations() !== undefined)\n return false;\n }\n // filter on destinations TODO: start with test for this\n // if (this.getDestionations() !== undefined && this.getDestionations() !== transfer.getDestionations()) return false;\n }\n // otherwise invalid type\n else\n throw new Error(\"Transfer must be MoneroIncomingTransfer or MoneroOutgoingTransfer\");\n // filter with tx filter\n if (queryParent && this.getTxQuery() !== undefined && !this.getTxQuery().meetsCriteria(transfer.getTx()))\n return false;\n return true;\n }\n validate() {\n if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() < 0)\n throw new MoneroError(\"Subaddress index must be >= 0\");\n if (this.getSubaddressIndices() !== undefined)\n for (let subaddressIdx of this.getSubaddressIndices())\n if (subaddressIdx < 0)\n throw new MoneroError(\"Subaddress indices must be >= 0\");\n }\n // -------------------- OVERRIDE COVARIANT RETURN TYPES ---------------------\n setTx(tx) {\n super.setTx(tx);\n return this;\n }\n setAmount(amount) {\n super.setAmount(amount);\n return this;\n }\n setAccountIndex(accountIndex) {\n super.setAccountIndex(accountIndex);\n return this;\n }\n}\n","import assert from \"assert\";\nimport MoneroOutputQuery from \"./MoneroOutputQuery\";\nimport MoneroTransferQuery from \"./MoneroTransferQuery\";\nimport MoneroTxWallet from \"./MoneroTxWallet\";\n/**\n *

Configuration to query transactions.

\n */\nexport default class MoneroTxQuery extends MoneroTxWallet {\n /**\n *

Construct the transaction query.

\n *\n *

Example:

\n *\n * \n * // get transactions with unlocked incoming transfers to account 0
\n * let txs = await wallet.getTxs({
\n *    isLocked: false,
\n *    transferQuery: {
\n *      isIncoming: true,
\n *      accountIndex: 0
\n *    }
\n * });\n *
\n *\n *

All configuration is optional. All transactions are returned except those that don't meet criteria defined in this query.

\n *\n * @param {MoneroTxQuery} [query] - tx query configuration\n * @param {string} [query.hash] - get a tx with this hash\n * @param {string[]} [query.txHashes] - get txs with these hashes\n * @param {number} [query.height] - get txs with this height\n * @param {number} [query.minHeight] - get txs with height greater than or equal to this height\n * @param {number} [query.maxHeight] - get txs with height less than or equal to this height\n * @param {boolean} [query.isConfirmed] - get confirmed or unconfirmed txs\n * @param {boolean} [query.inTxPool] - get txs in or out of the tx pool\n * @param {boolean} [query.relay] - get txs with the same relay status\n * @param {boolean} [query.isRelayed] - get relayed or non-relayed txs\n * @param {boolean} [query.isFailed] - get failed or non-failed txs\n * @param {boolean} [query.isMinerTx] - get miner or non-miner txs\n * @param {boolean} [query.isLocked] - get locked or unlocked txs\n * @param {boolean} [query.isIncoming] - get txs with or without incoming transfers\n * @param {boolean} [query.isOutgoing] - get txs with or without outgoing transfers\n * @param {string} [query.paymentId] - get txs with this payment ID\n * @param {string} [query.paymentIds] - get txs with a payment ID among these payment IDs\n * @param {boolean} [query.hasPaymentId] - get txs with or without payment IDs\n * @param {Partial} [query.transferQuery] - get txs with transfers matching this transfer query\n * @param {Partial} [query.inputQuery] - get txs with inputs matching this input query\n * @param {Partial} [query.outputQuery] - get txs with outputs matching this output query\n */\n constructor(query) {\n super(query);\n // copy queries\n if (this.transferQuery)\n this.transferQuery = new MoneroTransferQuery(this.transferQuery);\n if (this.inputQuery)\n this.inputQuery = new MoneroOutputQuery(this.inputQuery);\n if (this.outputQuery)\n this.outputQuery = new MoneroOutputQuery(this.outputQuery);\n // link cycles\n if (this.transferQuery)\n this.getTransferQuery().setTxQuery(this);\n if (this.inputQuery)\n this.getInputQuery().setTxQuery(this);\n if (this.outputQuery)\n this.getOutputQuery().setTxQuery(this);\n // alias 'hash' to hashes\n if (this.hash) {\n this.setHashes([this.hash]);\n delete this.hash;\n }\n }\n copy() {\n return new MoneroTxQuery(this);\n }\n toJson() {\n let json = Object.assign({}, this, super.toJson()); // merge json onto inherited state\n if (this.getTransferQuery() !== undefined)\n json.transferQuery = this.getTransferQuery().toJson();\n if (this.getInputQuery() !== undefined)\n json.inputQuery = this.getInputQuery().toJson();\n if (this.getOutputQuery() !== undefined)\n json.outputQuery = this.getOutputQuery().toJson();\n delete json.block; // do not serialize parent block\n return json;\n }\n getIsIncoming() {\n return this.isIncoming;\n }\n setIsIncoming(isIncoming) {\n this.isIncoming = isIncoming;\n return this;\n }\n getIsOutgoing() {\n return this.isOutgoing;\n }\n setIsOutgoing(isOutgoing) {\n this.isOutgoing = isOutgoing;\n return this;\n }\n getHashes() {\n return this.hashes;\n }\n setHashes(hashes) {\n this.hashes = hashes;\n return this;\n }\n setHash(hash) {\n if (hash === undefined)\n return this.setHashes(undefined);\n assert(typeof hash === \"string\");\n return this.setHashes([hash]);\n }\n getHasPaymentId() {\n return this.hasPaymentId;\n }\n setHasPaymentId(hasPaymentId) {\n this.hasPaymentId = hasPaymentId;\n return this;\n }\n getPaymentIds() {\n return this.paymentIds;\n }\n setPaymentIds(paymentIds) {\n this.paymentIds = paymentIds;\n return this;\n }\n setPaymentId(paymentId) {\n if (paymentId === undefined)\n return this.setPaymentIds(undefined);\n assert(typeof paymentId === \"string\");\n return this.setPaymentIds([paymentId]);\n }\n getHeight() {\n return this.height;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n getMinHeight() {\n return this.minHeight;\n }\n setMinHeight(minHeight) {\n this.minHeight = minHeight;\n return this;\n }\n getMaxHeight() {\n return this.maxHeight;\n }\n setMaxHeight(maxHeight) {\n this.maxHeight = maxHeight;\n return this;\n }\n getIncludeOutputs() {\n return this.includeOutputs;\n }\n setIncludeOutputs(includeOutputs) {\n this.includeOutputs = includeOutputs;\n return this;\n }\n getTransferQuery() {\n return this.transferQuery;\n }\n setTransferQuery(transferQuery) {\n this.transferQuery = transferQuery === undefined ? undefined : transferQuery instanceof MoneroTransferQuery ? transferQuery : new MoneroTransferQuery(transferQuery);\n if (transferQuery)\n this.transferQuery.txQuery = this;\n return this;\n }\n getInputQuery() {\n return this.inputQuery;\n }\n setInputQuery(inputQuery) {\n this.inputQuery = inputQuery;\n if (inputQuery)\n inputQuery.txQuery = this;\n return this;\n }\n getOutputQuery() {\n return this.outputQuery;\n }\n setOutputQuery(outputQuery) {\n this.outputQuery = outputQuery === undefined ? undefined : outputQuery instanceof MoneroOutputQuery ? outputQuery : new MoneroOutputQuery(outputQuery);\n if (outputQuery)\n this.outputQuery.txQuery = this;\n return this;\n }\n meetsCriteria(tx, queryChildren) {\n if (!(tx instanceof MoneroTxWallet))\n throw new Error(\"Tx not given to MoneroTxQuery.meetsCriteria(tx)\");\n if (queryChildren === undefined)\n queryChildren = true;\n // filter on tx\n if (this.getHash() !== undefined && this.getHash() !== tx.getHash())\n return false;\n if (this.getPaymentId() !== undefined && this.getPaymentId() !== tx.getPaymentId())\n return false;\n if (this.getIsConfirmed() !== undefined && this.getIsConfirmed() !== tx.getIsConfirmed())\n return false;\n if (this.getInTxPool() !== undefined && this.getInTxPool() !== tx.getInTxPool())\n return false;\n if (this.getRelay() !== undefined && this.getRelay() !== tx.getRelay())\n return false;\n if (this.getIsRelayed() !== undefined && this.getIsRelayed() !== tx.getIsRelayed())\n return false;\n if (this.getIsFailed() !== undefined && this.getIsFailed() !== tx.getIsFailed())\n return false;\n if (this.getIsMinerTx() !== undefined && this.getIsMinerTx() !== tx.getIsMinerTx())\n return false;\n if (this.getIsLocked() !== undefined && this.getIsLocked() !== tx.getIsLocked())\n return false;\n // filter on having a payment id\n if (this.getHasPaymentId() !== undefined) {\n if (this.getHasPaymentId() && tx.getPaymentId() === undefined)\n return false;\n if (!this.getHasPaymentId() && tx.getPaymentId() !== undefined)\n return false;\n }\n // filter on incoming\n if (this.getIsIncoming() !== undefined) {\n if (this.getIsIncoming() && !tx.getIsIncoming())\n return false;\n if (!this.getIsIncoming() && tx.getIsIncoming())\n return false;\n }\n // filter on outgoing\n if (this.getIsOutgoing() !== undefined) {\n if (this.getIsOutgoing() && !tx.getIsOutgoing())\n return false;\n if (!this.getIsOutgoing() && tx.getIsOutgoing())\n return false;\n }\n // filter on remaining fields\n let txHeight = tx.getBlock() === undefined ? undefined : tx.getBlock().getHeight();\n if (this.getHashes() !== undefined && !this.getHashes().includes(tx.getHash()))\n return false;\n if (this.getPaymentIds() !== undefined && !this.getPaymentIds().includes(tx.getPaymentId()))\n return false;\n if (this.getHeight() !== undefined && (txHeight === undefined || txHeight !== this.getHeight()))\n return false;\n if (this.getMinHeight() !== undefined && txHeight !== undefined && txHeight < this.getMinHeight())\n return false; // do not filter unconfirmed\n if (this.getMaxHeight() !== undefined && (txHeight === undefined || txHeight > this.getMaxHeight()))\n return false;\n // TODO: filtering not complete\n // done if not querying transfers or outputs\n if (!queryChildren)\n return true;\n // at least one transfer must meet transfer filter if defined\n if (this.getTransferQuery() !== undefined) {\n let matchFound = false;\n if (tx.getOutgoingTransfer() && this.getTransferQuery().meetsCriteria(tx.getOutgoingTransfer(), false))\n matchFound = true;\n else if (tx.getIncomingTransfers()) {\n for (let incomingTransfer of tx.getIncomingTransfers()) {\n if (this.getTransferQuery().meetsCriteria(incomingTransfer, false)) {\n matchFound = true;\n break;\n }\n }\n }\n if (!matchFound)\n return false;\n }\n // at least one input must meet input query if defined\n if (this.getInputQuery() !== undefined) {\n if (tx.getInputs() === undefined || tx.getInputs().length === 0)\n return false;\n let matchFound = false;\n for (let input of tx.getInputsWallet()) {\n if (this.getInputQuery().meetsCriteria(input, false)) {\n matchFound = true;\n break;\n }\n }\n if (!matchFound)\n return false;\n }\n // at least one output must meet output query if defined\n if (this.getOutputQuery() !== undefined) {\n if (tx.getOutputs() === undefined || tx.getOutputs().length === 0)\n return false;\n let matchFound = false;\n for (let output of tx.getOutputsWallet()) {\n if (this.getOutputQuery().meetsCriteria(output, false)) {\n matchFound = true;\n break;\n }\n }\n if (!matchFound)\n return false;\n }\n return true; // transaction meets filter criteria\n }\n // ------------------- OVERRIDE CO-VARIANT RETURN TYPES ---------------------\n setIncomingTransfers(incomingTransfers) {\n super.setIncomingTransfers(incomingTransfers);\n return this;\n }\n setOutgoingTransfer(outgoingTransfer) {\n super.setOutgoingTransfer(outgoingTransfer);\n return this;\n }\n setOutputs(outputs) {\n super.setOutputs(outputs);\n return this;\n }\n setNote(note) {\n super.setNote(note);\n return this;\n }\n setIsLocked(isLocked) {\n super.setIsLocked(isLocked);\n return this;\n }\n setBlock(block) {\n super.setBlock(block);\n return this;\n }\n setVersion(version) {\n super.setVersion(version);\n return this;\n }\n setIsMinerTx(isMinerTx) {\n super.setIsMinerTx(isMinerTx);\n return this;\n }\n setFee(fee) {\n super.setFee(fee);\n return this;\n }\n setRingSize(ringSize) {\n super.setRingSize(ringSize);\n return this;\n }\n setRelay(relay) {\n super.setRelay(relay);\n return this;\n }\n setIsRelayed(isRelayed) {\n super.setIsRelayed(isRelayed);\n return this;\n }\n setIsConfirmed(isConfirmed) {\n super.setIsConfirmed(isConfirmed);\n return this;\n }\n setInTxPool(inTxPool) {\n super.setInTxPool(inTxPool);\n return this;\n }\n setNumConfirmations(numConfirmations) {\n super.setNumConfirmations(numConfirmations);\n return this;\n }\n setUnlockTime(unlockTime) {\n super.setUnlockTime(unlockTime);\n return this;\n }\n setLastRelayedTimestamp(lastRelayedTimestamp) {\n super.setLastRelayedTimestamp(lastRelayedTimestamp);\n return this;\n }\n setReceivedTimestamp(receivedTimestamp) {\n super.setReceivedTimestamp(receivedTimestamp);\n return this;\n }\n setIsDoubleSpendSeen(isDoubleSpendSeen) {\n super.setIsDoubleSpendSeen(isDoubleSpendSeen);\n return this;\n }\n setKey(key) {\n super.setKey(key);\n return this;\n }\n setFullHex(hex) {\n super.setFullHex(hex);\n return this;\n }\n setPrunedHex(prunedHex) {\n super.setPrunedHex(prunedHex);\n return this;\n }\n setPrunableHex(prunableHex) {\n super.setPrunableHex(prunableHex);\n return this;\n }\n setPrunableHash(prunableHash) {\n super.setPrunableHash(prunableHash);\n return this;\n }\n setSize(size) {\n super.setSize(size);\n return this;\n }\n setWeight(weight) {\n super.setWeight(weight);\n return this;\n }\n setInputs(inputs) {\n super.setInputs(inputs);\n return this;\n }\n setOutputIndices(outputIndices) {\n super.setOutputIndices(outputIndices);\n return this;\n }\n setMetadata(metadata) {\n super.setMetadata(metadata);\n return this;\n }\n setTxSet(txSet) {\n super.setTxSet(txSet);\n return this;\n }\n setExtra(extra) {\n super.setExtra(extra);\n return this;\n }\n setRctSignatures(rctSignatures) {\n super.setRctSignatures(rctSignatures);\n return this;\n }\n setRctSigPrunable(rctSigPrunable) {\n super.setRctSigPrunable(rctSigPrunable);\n return this;\n }\n setIsKeptByBlock(isKeptByBlock) {\n super.setIsKeptByBlock(isKeptByBlock);\n return this;\n }\n setIsFailed(isFailed) {\n super.setIsFailed(isFailed);\n return this;\n }\n setLastFailedHeight(lastFailedHeight) {\n super.setLastFailedHeight(lastFailedHeight);\n return this;\n }\n setLastFailedHash(lastFailedId) {\n super.setLastFailedHash(lastFailedId);\n return this;\n }\n setMaxUsedBlockHeight(maxUsedBlockHeight) {\n super.setMaxUsedBlockHeight(maxUsedBlockHeight);\n return this;\n }\n setMaxUsedBlockHash(maxUsedBlockId) {\n super.setMaxUsedBlockHash(maxUsedBlockId);\n return this;\n }\n setSignatures(signatures) {\n super.setSignatures(signatures);\n return this;\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"../../common/GenUtils\";\nimport MoneroBlockHeader from \"./MoneroBlockHeader\";\nimport MoneroTx from \"./MoneroTx\";\nimport MoneroTxQuery from \"../../wallet/model/MoneroTxQuery\";\nimport MoneroTxWallet from \"../../wallet/model/MoneroTxWallet\";\n/**\n * Enumerates types to deserialize to.\n */\nvar DeserializationType;\n(function (DeserializationType) {\n DeserializationType[DeserializationType[\"TX\"] = 0] = \"TX\";\n DeserializationType[DeserializationType[\"TX_WALLET\"] = 1] = \"TX_WALLET\";\n DeserializationType[DeserializationType[\"TX_QUERY\"] = 2] = \"TX_QUERY\";\n})(DeserializationType || (DeserializationType = {}));\n/**\n * Models a Monero block in the blockchain.\n */\nclass MoneroBlock extends MoneroBlockHeader {\n constructor(block, txType) {\n super(block);\n // copy miner tx\n if (this.minerTx) {\n this.minerTx = this.deserializeTx(this.minerTx, txType).setBlock(this);\n }\n // copy non-miner txs\n if (this.txs) {\n this.txs = this.txs.slice();\n for (let i = 0; i < this.txs.length; i++) {\n this.txs[i] = this.deserializeTx(this.txs[i], txType).setBlock(this);\n }\n }\n }\n getHex() {\n return this.hex;\n }\n setHex(hex) {\n this.hex = hex;\n return this;\n }\n getMinerTx() {\n return this.minerTx;\n }\n setMinerTx(minerTx) {\n this.minerTx = minerTx;\n return this;\n }\n getTxs() {\n return this.txs;\n }\n setTxs(txs) {\n this.txs = txs;\n return this;\n }\n getTxHashes() {\n return this.txHashes;\n }\n setTxHashes(txHashes) {\n this.txHashes = txHashes;\n return this;\n }\n copy() {\n return new MoneroBlock(this);\n }\n toJson() {\n let json = super.toJson();\n if (this.getMinerTx() !== undefined)\n json.minerTx = this.getMinerTx().toJson();\n if (this.getTxs() !== undefined) {\n json.txs = [];\n for (let tx of this.getTxs())\n json.txs.push(tx.toJson());\n }\n return json;\n }\n merge(block) {\n assert(block instanceof MoneroBlock);\n if (this === block)\n return this;\n // merge header fields\n super.merge(block);\n // merge reconcilable block extensions\n this.setHex(GenUtils.reconcile(this.getHex(), block.getHex()));\n this.setTxHashes(GenUtils.reconcile(this.getTxHashes(), block.getTxHashes()));\n // merge miner tx\n if (this.getMinerTx() === undefined)\n this.setMinerTx(block.getMinerTx());\n if (block.getMinerTx() !== undefined) {\n block.getMinerTx().setBlock(this);\n this.getMinerTx().merge(block.getMinerTx());\n }\n // merge non-miner txs\n if (block.getTxs() !== undefined) {\n for (let tx of block.getTxs()) {\n tx.setBlock(this);\n MoneroBlock.mergeTx(this.getTxs(), tx);\n }\n }\n return this;\n }\n toString(indent = 0) {\n let str = super.toString(indent) + \"\\n\";\n str += GenUtils.kvLine(\"Hex\", this.getHex(), indent);\n if (this.getTxs() !== undefined) {\n str += GenUtils.kvLine(\"Txs\", \"\", indent);\n for (let tx of this.getTxs()) {\n str += tx.toString(indent + 1) + \"\\n\";\n }\n }\n if (this.getMinerTx() !== undefined) {\n str += GenUtils.kvLine(\"Miner tx\", \"\", indent);\n str += this.getMinerTx().toString(indent + 1) + \"\\n\";\n }\n str += GenUtils.kvLine(\"Txs hashes\", this.getTxHashes(), indent);\n return str[str.length - 1] === \"\\n\" ? str.slice(0, str.length - 1) : str; // strip last newline\n }\n // helper to merge txs\n static mergeTx(txs, tx) {\n for (let aTx of txs) {\n if (aTx.getHash() === tx.getHash()) {\n aTx.merge(tx);\n return;\n }\n }\n txs.push(tx);\n }\n // -------------------- OVERRIDE COVARIANT RETURN TYPES ---------------------\n setHeight(height) {\n super.setHeight(height);\n return this;\n }\n setTimestamp(timestamp) {\n super.setTimestamp(timestamp);\n return this;\n }\n setSize(size) {\n super.setSize(size);\n return this;\n }\n setWeight(weight) {\n super.setWeight(weight);\n return this;\n }\n setLongTermWeight(longTermWeight) {\n super.setLongTermWeight(longTermWeight);\n return this;\n }\n setDepth(depth) {\n super.setDepth(depth);\n return this;\n }\n setDifficulty(difficulty) {\n super.setDifficulty(difficulty);\n return this;\n }\n setCumulativeDifficulty(cumulativeDifficulty) {\n super.setCumulativeDifficulty(cumulativeDifficulty);\n return this;\n }\n setMajorVersion(majorVersion) {\n super.setMajorVersion(majorVersion);\n return this;\n }\n setMinorVersion(minorVersion) {\n super.setMinorVersion(minorVersion);\n return this;\n }\n setNonce(nonce) {\n super.setNonce(nonce);\n return this;\n }\n setMinerTxHash(minerTxHash) {\n super.setMinerTxHash(minerTxHash);\n return this;\n }\n setNumTxs(numTxs) {\n super.setNumTxs(numTxs);\n return this;\n }\n setOrphanStatus(orphanStatus) {\n super.setOrphanStatus(orphanStatus);\n return this;\n }\n setPrevHash(prevHash) {\n super.setPrevHash(prevHash);\n return this;\n }\n setReward(reward) {\n super.setReward(reward);\n return this;\n }\n setPowHash(powHash) {\n super.setPowHash(powHash);\n return this;\n }\n deserializeTx(tx, txType) {\n if (txType === undefined) {\n if (!(tx instanceof MoneroTx))\n throw new Error(\"Must provide DeserializationType if tx is not instanceof MoneroTx\");\n return tx.copy();\n }\n else if (txType === MoneroBlock.DeserializationType.TX || txType === undefined) {\n return new MoneroTx(tx);\n }\n else if (txType === MoneroBlock.DeserializationType.TX_WALLET) {\n return new MoneroTxWallet(tx);\n }\n else if (txType === MoneroBlock.DeserializationType.TX_QUERY) {\n return new MoneroTxQuery(tx);\n }\n else {\n throw new Error(\"Unrecognized tx deserialization type: \" + txType);\n }\n }\n}\nMoneroBlock.DeserializationType = DeserializationType;\nexport default MoneroBlock;\n","import MoneroError from \"./MoneroError\";\n/**\n * Error when interacting with Monero RPC.\n */\nexport default class MoneroRpcError extends MoneroError {\n /**\n * Constructs the error.\n *\n * @param {string} rpcDescription is a description of the error from rpc\n * @param {number} rpcCode is the error code from rpc\n * @param {string} [rpcMethod] is the rpc method invoked\n * @param {object} [rpcParams] are parameters sent with the rpc request\n */\n constructor(rpcDescription, rpcCode, rpcMethod, rpcParams) {\n super(rpcDescription, rpcCode);\n this.rpcMethod = rpcMethod;\n this.rpcParams = rpcParams;\n }\n getRpcMethod() {\n return this.rpcMethod;\n }\n getRpcParams() {\n return this.rpcParams;\n }\n toString() {\n let str = super.toString();\n if (this.rpcMethod)\n str += \"\\nRPC request: '\" + this.rpcMethod + \"'\";\n return str;\n }\n}\n","import GenUtils from \"./GenUtils\";\nimport HttpClient from \"./HttpClient\";\nimport LibraryUtils from \"./LibraryUtils\";\nimport MoneroError from \"./MoneroError\";\nimport MoneroRpcError from \"./MoneroRpcError\";\nimport MoneroUtils from \"./MoneroUtils\";\nimport ThreadPool from \"./ThreadPool\";\n/**\n * Maintains a connection and sends requests to a Monero RPC API.\n */\nclass MoneroRpcConnection {\n /**\n *

Construct a RPC connection.

\n *\n *

Examples:

\n *\n * \n * let connection1 = new MoneroRpcConnection(\"http://localhost:38081\", \"daemon_user\", \"daemon_password_123\")

\n *\n * let connection2 = new MoneroRpcConnection({
\n *    uri: http://localhost:38081,
\n *    username: \"daemon_user\",
\n *    password: \"daemon_password_123\",
\n *    rejectUnauthorized: false, // accept self-signed certificates e.g. for local development
\n *    proxyToWorker: true // proxy request to worker (default false)
\n * });\n *
\n *\n * @param {string|Partial} uriOrConnection - MoneroRpcConnection or URI of the RPC endpoint\n * @param {string} uriOrConnection.uri - URI of the RPC endpoint\n * @param {string} [uriOrConnection.username] - username to authenticate with the RPC endpoint (optional)\n * @param {string} [uriOrConnection.password] - password to authenticate with the RPC endpoint (optional)\n * @param {string} [uriOrConnection.zmqUri] - URI of the ZMQ endpoint (optional)\n * @param {string} [uriOrConnection.proxyUri] - URI of a proxy server to route requests through (optional)\n * @param {boolean} [uriOrConnection.rejectUnauthorized] - rejects self-signed certificates if true (default true)\n * @param {boolean} uriOrConnection.proxyToWorker - proxy requests to worker (default true)\n * @param {string} username - username to authenticate with the RPC endpoint (optional)\n * @param {string} password - password to authenticate with the RPC endpoint (optional)\n */\n constructor(uriOrConnection, username, password) {\n // validate and normalize config\n if (typeof uriOrConnection === \"string\") {\n Object.assign(this, MoneroRpcConnection.DEFAULT_CONFIG);\n this.uri = uriOrConnection;\n this.setCredentials(username, password);\n }\n else {\n if (username !== undefined || password !== undefined)\n throw new MoneroError(\"Can provide config object or params but not both\");\n Object.assign(this, MoneroRpcConnection.DEFAULT_CONFIG, uriOrConnection);\n this.setCredentials(this.username, this.password);\n }\n // normalize uris\n if (this.uri)\n this.uri = GenUtils.normalizeUri(this.uri);\n if (this.zmqUri)\n this.zmqUri = GenUtils.normalizeUri(this.zmqUri);\n if (this.proxyUri)\n this.proxyUri = GenUtils.normalizeUri(this.proxyUri);\n // initialize mutexes\n this.checkConnectionMutex = new ThreadPool(1);\n this.sendRequestMutex = new ThreadPool(1);\n }\n setCredentials(username, password) {\n if (username === \"\")\n username = undefined;\n if (password === \"\")\n password = undefined;\n if (username || password) {\n if (!username)\n throw new MoneroError(\"username must be defined because password is defined\");\n if (!password)\n throw new MoneroError(\"password must be defined because username is defined\");\n }\n if (this.username === \"\")\n this.username = undefined;\n if (this.password === \"\")\n this.password = undefined;\n if (this.username !== username || this.password !== password) {\n this.isOnline = undefined;\n this.isAuthenticated = undefined;\n }\n this.username = username;\n this.password = password;\n return this;\n }\n getUri() {\n return this.uri;\n }\n getUsername() {\n return this.username ? this.username : \"\";\n }\n getPassword() {\n return this.password ? this.password : \"\";\n }\n getZmqUri() {\n return this.zmqUri;\n }\n setZmqUri(zmqUri) {\n this.zmqUri = zmqUri;\n return this;\n }\n getProxyUri() {\n return this.proxyUri;\n }\n setProxyUri(proxyUri) {\n this.proxyUri = proxyUri;\n return this;\n }\n getRejectUnauthorized() {\n return this.rejectUnauthorized;\n }\n setProxyToWorker(proxyToWorker) {\n this.proxyToWorker = proxyToWorker;\n return this;\n }\n getProxyToWorker() {\n return this.proxyToWorker;\n }\n /**\n * Set the connection's priority relative to other connections. Priority 1 is highest,\n * then priority 2, etc. The default priority of 0 is lowest priority.\n *\n * @param {number} [priority] - the connection priority (default 0)\n * @return {MoneroRpcConnection} this connection\n */\n setPriority(priority) {\n if (!(priority >= 0))\n throw new MoneroError(\"Priority must be >= 0\");\n this.priority = priority;\n return this;\n }\n getPriority() {\n return this.priority;\n }\n /**\n * Set the RPC request timeout in milliseconds.\n *\n * @param {number} timeoutMs is the timeout in milliseconds, 0 to disable timeout, or undefined to use default\n * @return {MoneroRpcConnection} this connection\n */\n setTimeout(timeoutMs) {\n this.timeoutMs = timeoutMs;\n return this;\n }\n getTimeout() {\n return this.timeoutMs;\n }\n setAttribute(key, value) {\n if (!this.attributes)\n this.attributes = new Map();\n this.attributes.put(key, value);\n return this;\n }\n getAttribute(key) {\n return this.attributes.get(key);\n }\n /**\n * Check the connection status to update isOnline, isAuthenticated, and response time.\n *\n * @param {number} timeoutMs - maximum response time before considered offline\n * @return {Promise} true if there is a change in status, false otherwise\n */\n async checkConnection(timeoutMs) {\n return this.queueCheckConnection(async () => {\n await LibraryUtils.loadWasmModule(); // cache wasm for binary request\n let isOnlineBefore = this.isOnline;\n let isAuthenticatedBefore = this.isAuthenticated;\n let startTime = Date.now();\n try {\n if (this.fakeDisconnected)\n throw new Error(\"Connection is fake disconnected\");\n let heights = [];\n for (let i = 0; i < 100; i++)\n heights.push(i);\n await this.sendBinaryRequest(\"get_blocks_by_height.bin\", { heights: heights }, timeoutMs); // assume daemon connection\n this.isOnline = true;\n this.isAuthenticated = true;\n }\n catch (err) {\n this.isOnline = false;\n this.isAuthenticated = undefined;\n this.responseTime = undefined;\n if (err instanceof MoneroRpcError) {\n if (err.getCode() === 401) {\n this.isOnline = true;\n this.isAuthenticated = false;\n }\n else if (err.getCode() === 404) { // fallback to latency check\n this.isOnline = true;\n this.isAuthenticated = true;\n }\n }\n }\n if (this.isOnline)\n this.responseTime = Date.now() - startTime;\n return isOnlineBefore !== this.isOnline || isAuthenticatedBefore !== this.isAuthenticated;\n });\n }\n /**\n * Indicates if the connection is connected according to the last call to checkConnection().

\n *\n * Note: must call checkConnection() manually unless using MoneroConnectionManager.\n *\n * @return {boolean} true or false to indicate if connected, or undefined if checkConnection() has not been called\n */\n isConnected() {\n return this.isOnline === undefined ? undefined : this.isOnline && this.isAuthenticated !== false;\n }\n /**\n * Indicates if the connection is online according to the last call to checkConnection().

\n *\n * Note: must call checkConnection() manually unless using MoneroConnectionManager.\n *\n * @return {boolean} true or false to indicate if online, or undefined if checkConnection() has not been called\n */\n getIsOnline() {\n return this.isOnline;\n }\n /**\n * Indicates if the connection is authenticated according to the last call to checkConnection().

\n *\n * Note: must call checkConnection() manually unless using MoneroConnectionManager.\n *\n * @return {boolean} true if authenticated or no authentication, false if not authenticated, or undefined if checkConnection() has not been called\n */\n getIsAuthenticated() {\n return this.isAuthenticated;\n }\n getResponseTime() {\n return this.responseTime;\n }\n /**\n * Send a JSON RPC request.\n *\n * @param {string} method - JSON RPC method to invoke\n * @param {object} params - request parameters\n * @param {number} [timeoutMs] - overrides the request timeout in milliseconds\n * @return {object} is the response map\n */\n async sendJsonRequest(method, params, timeoutMs) {\n return this.queueSendRequest(async () => {\n try {\n // build request body\n let body = JSON.stringify({\n id: \"0\",\n jsonrpc: \"2.0\",\n method: method,\n params: params\n });\n // logging\n if (LibraryUtils.getLogLevel() >= 2)\n LibraryUtils.log(2, \"Sending json request with method '\" + method + \"' and body: \" + body);\n // proxy uri is not supported\n if (this.getProxyUri())\n throw new MoneroError(\"Proxy URI not supported for JSON requests\");\n // send http request\n let startTime = new Date().getTime();\n let resp = await HttpClient.request({\n method: \"POST\",\n uri: this.getUri() + '/json_rpc',\n username: this.getUsername(),\n password: this.getPassword(),\n body: body,\n timeout: timeoutMs === undefined ? this.timeoutMs : timeoutMs,\n rejectUnauthorized: this.rejectUnauthorized,\n proxyToWorker: this.proxyToWorker\n });\n // validate response\n MoneroRpcConnection.validateHttpResponse(resp);\n // deserialize response\n if (resp.body[0] != '{')\n throw resp.body;\n resp = JSON.parse(resp.body.replace(/(\"[^\"]*\"\\s*:\\s*)(\\d{16,})/g, '$1\"$2\"')); // replace 16 or more digits with strings and parse\n if (LibraryUtils.getLogLevel() >= 3) {\n let respStr = JSON.stringify(resp);\n LibraryUtils.log(3, \"Received response from method='\" + method + \"', response=\" + respStr.substring(0, Math.min(1000, respStr.length)) + \"(\" + (new Date().getTime() - startTime) + \" ms)\");\n }\n // check rpc response for errors\n this.validateRpcResponse(resp, method, params);\n return resp;\n }\n catch (err) {\n if (err instanceof MoneroRpcError)\n throw err;\n else\n throw new MoneroRpcError(err, err.statusCode, method, params);\n }\n });\n }\n /**\n * Send a RPC request to the given path and with the given paramters.\n *\n * E.g. \"/get_transactions\" with params\n *\n * @param {string} path - JSON RPC path to invoke\n * @param {object} params - request parameters\n * @param {number} [timeoutMs] - overrides the request timeout in milliseconds\n * @return {object} is the response map\n */\n async sendPathRequest(path, params, timeoutMs) {\n return this.queueSendRequest(async () => {\n try {\n // logging\n if (LibraryUtils.getLogLevel() >= 2)\n LibraryUtils.log(2, \"Sending path request with path '\" + path + \"' and params: \" + JSON.stringify(params));\n // proxy uri is not supported\n if (this.getProxyUri())\n throw new MoneroError(\"Proxy URI not supported for path requests\");\n // send http request\n let startTime = new Date().getTime();\n let resp = await HttpClient.request({\n method: \"POST\",\n uri: this.getUri() + '/' + path,\n username: this.getUsername(),\n password: this.getPassword(),\n body: JSON.stringify(params),\n timeout: timeoutMs === undefined ? this.timeoutMs : timeoutMs,\n rejectUnauthorized: this.rejectUnauthorized,\n proxyToWorker: this.proxyToWorker\n });\n // validate response\n MoneroRpcConnection.validateHttpResponse(resp);\n // deserialize response\n if (resp.body[0] != '{')\n throw resp.body;\n resp = JSON.parse(resp.body.replace(/(\"[^\"]*\"\\s*:\\s*)(\\d{16,})/g, '$1\"$2\"')); // replace 16 or more digits with strings and parse\n if (typeof resp === \"string\")\n resp = JSON.parse(resp); // TODO: some responses returned as strings?\n if (LibraryUtils.getLogLevel() >= 3) {\n let respStr = JSON.stringify(resp);\n LibraryUtils.log(3, \"Received response from path='\" + path + \"', response=\" + respStr.substring(0, Math.min(1000, respStr.length)) + \"(\" + (new Date().getTime() - startTime) + \" ms)\");\n }\n // check rpc response for errors\n this.validateRpcResponse(resp, path, params);\n return resp;\n }\n catch (err) {\n if (err instanceof MoneroRpcError)\n throw err;\n else\n throw new MoneroRpcError(err, err.statusCode, path, params);\n }\n });\n }\n /**\n * Send a binary RPC request.\n *\n * @param {string} path - path of the binary RPC method to invoke\n * @param {object} [params] - request parameters\n * @param {number} [timeoutMs] - request timeout in milliseconds\n * @return {Uint8Array} the binary response\n */\n async sendBinaryRequest(path, params, timeoutMs) {\n return this.queueSendRequest(async () => {\n // serialize params\n let paramsBin = await MoneroUtils.jsonToBinary(params);\n try {\n // logging\n if (LibraryUtils.getLogLevel() >= 2)\n LibraryUtils.log(2, \"Sending binary request with path '\" + path + \"' and params: \" + JSON.stringify(params));\n // proxy uri is not supported\n if (this.getProxyUri())\n throw new MoneroError(\"Proxy URI not supported for binary requests\");\n // send http request\n let resp = await HttpClient.request({\n method: \"POST\",\n uri: this.getUri() + '/' + path,\n username: this.getUsername(),\n password: this.getPassword(),\n body: paramsBin,\n timeout: timeoutMs === undefined ? this.timeoutMs : timeoutMs,\n rejectUnauthorized: this.rejectUnauthorized,\n proxyToWorker: this.proxyToWorker\n });\n // validate response\n MoneroRpcConnection.validateHttpResponse(resp);\n // process response\n resp = resp.body;\n if (!(resp instanceof Uint8Array)) {\n console.error(\"resp is not uint8array\");\n console.error(resp);\n }\n if (resp.error)\n throw new MoneroRpcError(resp.error.message, resp.error.code, path, params);\n return resp;\n }\n catch (err) {\n if (err instanceof MoneroRpcError)\n throw err;\n else\n throw new MoneroRpcError(err, err.statusCode, path, params);\n }\n });\n }\n getConfig() {\n return {\n uri: this.uri,\n username: this.username,\n password: this.password,\n zmqUri: this.zmqUri,\n proxyUri: this.proxyUri,\n rejectUnauthorized: this.rejectUnauthorized,\n proxyToWorker: this.proxyToWorker,\n priority: this.priority,\n timeoutMs: this.timeoutMs\n };\n }\n toJson() {\n let json = Object.assign({}, this);\n json.checkConnectionMutex = undefined;\n json.sendRequestMutex = undefined;\n return json;\n }\n toString() {\n return this.getUri() + \" (username=\" + this.getUsername() + \", password=\" + (this.getPassword() ? \"***\" : this.getPassword()) + \", zmqUri=\" + this.getZmqUri() + \", proxyUri=\" + this.getProxyUri() + \", priority=\" + this.getPriority() + \", timeoutMs=\" + this.getTimeout() + \", isOnline=\" + this.getIsOnline() + \", isAuthenticated=\" + this.getIsAuthenticated() + \")\";\n }\n setFakeDisconnected(fakeDisconnected) {\n this.fakeDisconnected = fakeDisconnected;\n }\n // ------------------------------ PRIVATE HELPERS --------------------------\n async queueCheckConnection(asyncFn) {\n return this.checkConnectionMutex.submit(asyncFn);\n }\n async queueSendRequest(asyncFn) {\n return this.sendRequestMutex.submit(asyncFn);\n }\n static validateHttpResponse(resp) {\n let code = resp.statusCode;\n if (code < 200 || code > 299) {\n let content = resp.body;\n throw new MoneroRpcError(code + \" \" + resp.statusText + (!content ? \"\" : (\": \" + content)), code, undefined, undefined);\n }\n }\n validateRpcResponse(resp, method, params) {\n if (resp.error === undefined)\n return;\n let errorMsg = resp.error.message;\n if (errorMsg === \"\")\n errorMsg = \"Received error response from RPC request with method '\" + method + \"' to \" + this.getUri(); // TODO (monero-project): response sometimes has empty error message\n throw new MoneroRpcError(resp.error.message, resp.error.code, method, params);\n }\n}\n// default config\n/** @private */\nMoneroRpcConnection.DEFAULT_CONFIG = {\n uri: undefined,\n username: undefined,\n password: undefined,\n zmqUri: undefined,\n proxyUri: undefined,\n rejectUnauthorized: true,\n proxyToWorker: false,\n priority: 0,\n timeoutMs: undefined\n};\nexport default MoneroRpcConnection;\n","import MoneroRpcConnection from \"../../common/MoneroRpcConnection\";\n/**\n * Configuration to connect to monerod.\n */\nexport default class MoneroDaemonConfig {\n /**\n * Construct a configuration to open or create a wallet.\n *\n * @param {Partial} [config] - MoneroDaemonConfig to construct from (optional)\n * @param {string|Partial} [config.server] - uri or MoneroRpcConnection to the daemon (optional)\n * @param {boolean} [config.proxyToWorker] - proxy daemon requests to a worker (default true)\n * @param {string[]} [config.cmd] - command to start monerod (optional)\n * @param {number} [config.pollInterval] - interval in milliseconds to poll the daemon for updates (default 20000)\n */\n constructor(config) {\n Object.assign(this, config);\n if (this.server)\n this.setServer(this.server);\n this.setProxyToWorker(this.proxyToWorker);\n }\n copy() {\n return new MoneroDaemonConfig(this);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (json.server)\n json.server = json.server.toJson();\n return json;\n }\n getServer() {\n return this.server;\n }\n setServer(server) {\n if (server && !(server instanceof MoneroRpcConnection))\n server = new MoneroRpcConnection(server);\n this.server = server;\n return this;\n }\n getProxyToWorker() {\n return this.proxyToWorker;\n }\n setProxyToWorker(proxyToWorker) {\n this.proxyToWorker = proxyToWorker;\n return this;\n }\n getCmd() {\n return this.cmd;\n }\n setCmd(cmd) {\n this.cmd = cmd;\n return this;\n }\n getPollInterval() {\n return this.pollInterval;\n }\n setPollInterval(pollInterval) {\n this.pollInterval = pollInterval;\n return this;\n }\n}\n","/**\n * Receives notifications as a daemon is updated.\n */\nexport default class MoneroDaemonListener {\n /**\n * Called when a new block is added to the chain.\n *\n * @param {MoneroBlockHeader} header - the header of the block added to the chain\n */\n async onBlockHeader(header) {\n this.lastHeader = header;\n }\n /**\n * Get the last notified block header.\n *\n * @return {MoneroBlockHeader} the last notified block header\n */\n getLastBlockHeader() {\n return this.lastHeader;\n }\n}\n","/**\n * Run a task in a fixed period loop.\n */\nexport default class TaskLooper {\n /**\n * Build the looper with a function to invoke on a fixed period loop.\n *\n * @param {function} fn - the async function to invoke\n */\n constructor(fn) {\n this._fn = fn;\n this._isStarted = false;\n this._isLooping = false;\n }\n /**\n * Get the task function to invoke on a fixed period loop.\n *\n * @return {function} the task function\n */\n getTask() {\n return this._fn;\n }\n /**\n * Start the task loop.\n *\n * @param {number} periodInMs the loop period in milliseconds\n * @param {boolean} targetFixedPeriod specifies if the task should target a fixed period by accounting for run time (default false)\n * @return {TaskLooper} this instance for chaining\n */\n start(periodInMs, targetFixedPeriod) {\n if (periodInMs <= 0)\n throw new Error(\"Looper period must be greater than 0 ms\");\n this.setPeriodInMs(periodInMs);\n if (this._isStarted)\n return;\n this._isStarted = true;\n this._runLoop(targetFixedPeriod);\n }\n /**\n * Indicates if looping.\n *\n * @return {boolean} true if looping, false otherwise\n */\n isStarted() {\n return this._isStarted;\n }\n /**\n * Stop the task loop.\n */\n stop() {\n this._isStarted = false;\n clearTimeout(this._timeout);\n this._timeout = undefined;\n }\n /**\n * Set the loop period in milliseconds.\n *\n * @param {number} periodInMs the loop period in milliseconds\n */\n setPeriodInMs(periodInMs) {\n if (periodInMs <= 0)\n throw new Error(\"Looper period must be greater than 0 ms\");\n this._periodInMs = periodInMs;\n }\n async _runLoop(targetFixedPeriod) {\n this._isLooping = true;\n while (this._isStarted) {\n const startTime = Date.now();\n await this._fn();\n let that = this;\n if (this._isStarted)\n await new Promise((resolve) => { this._timeout = setTimeout(resolve, that._periodInMs - (targetFixedPeriod ? (Date.now() - startTime) : 0)); });\n }\n this._isLooping = false;\n }\n}\n","/**\n * Models an alternative chain seen by the node.\n */\nexport default class MoneroAltChain {\n constructor(altChain) {\n Object.assign(this, altChain);\n if (this.difficulty !== undefined && typeof this.difficulty !== \"bigint\")\n this.difficulty = BigInt(this.difficulty);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (this.getDifficulty() !== undefined)\n json.difficulty = this.getDifficulty().toString();\n return json;\n }\n getBlockHashes() {\n return this.blockHashes;\n }\n setBlockHashes(blockHashes) {\n this.blockHashes = blockHashes;\n return this;\n }\n getDifficulty() {\n return this.difficulty;\n }\n setDifficulty(difficulty) {\n this.difficulty = difficulty;\n return this;\n }\n getHeight() {\n return this.height;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n getLength() {\n return this.length;\n }\n setLength(length) {\n this.length = length;\n return this;\n }\n getMainChainParentBlockHash() {\n return this.mainChainParentBlockHash;\n }\n setMainChainParentBlockHash(mainChainParentBlockHash) {\n this.mainChainParentBlockHash = mainChainParentBlockHash;\n return this;\n }\n}\n","/**\n * Monero block template to mine.\n */\nexport default class MoneroBlockTemplate {\n constructor(template) {\n Object.assign(this, template);\n if (this.expectedReward !== undefined && typeof this.expectedReward !== \"bigint\")\n this.expectedReward = BigInt(this.expectedReward);\n if (this.difficulty !== undefined && typeof this.difficulty !== \"bigint\")\n this.difficulty = BigInt(this.difficulty);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (this.getExpectedReward() !== undefined)\n json.expectedReward = this.getExpectedReward().toString();\n if (this.getDifficulty() !== undefined)\n json.difficulty = this.getDifficulty().toString();\n return json;\n }\n getBlockTemplateBlob() {\n return this.blockTemplateBlob;\n }\n setBlockTemplateBlob(blockTemplateBlob) {\n this.blockTemplateBlob = blockTemplateBlob;\n return this;\n }\n getBlockHashingBlob() {\n return this.blockHashingBlob;\n }\n setBlockHashingBlob(blockHashingBlob) {\n this.blockHashingBlob = blockHashingBlob;\n return this;\n }\n getDifficulty() {\n return this.difficulty;\n }\n setDifficulty(difficulty) {\n this.difficulty = difficulty;\n return this;\n }\n getExpectedReward() {\n return this.expectedReward;\n }\n setExpectedReward(expectedReward) {\n this.expectedReward = expectedReward;\n return this;\n }\n getHeight() {\n return this.height;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n getPrevHash() {\n return this.prevId;\n }\n setPrevHash(prevId) {\n this.prevId = prevId;\n return this;\n }\n getReservedOffset() {\n return this.reservedOffset;\n }\n setReservedOffset(reservedOffset) {\n this.reservedOffset = reservedOffset;\n return this;\n }\n getSeedHeight() {\n return this.height;\n }\n setSeedHeight(seedHeight) {\n this.seedHeight = seedHeight;\n return this;\n }\n getSeedHash() {\n return this.seedHash;\n }\n setSeedHash(seedHash) {\n this.seedHash = seedHash;\n return this;\n }\n getNextSeedHash() {\n return this.nextSeedHash;\n }\n setNextSeedHash(nextSeedHash) {\n this.nextSeedHash = nextSeedHash;\n return this;\n }\n}\n","/**\n * Monero daemon connection span.\n */\nexport default class MoneroConnectionSpan {\n constructor(span) {\n Object.assign(this, span);\n }\n toJson() {\n return Object.assign({}, this);\n }\n getConnectionId() {\n return this.connectionId;\n }\n setConnectionId(connectionId) {\n this.connectionId = connectionId;\n return this;\n }\n getNumBlocks() {\n return this.numBlocks;\n }\n setNumBlocks(numBlocks) {\n this.numBlocks = numBlocks;\n return this;\n }\n getRemoteAddress() {\n return this.remoteAddress;\n }\n setRemoteAddress(remoteAddress) {\n this.remoteAddress = remoteAddress;\n return this;\n }\n getRate() {\n return this.rate;\n }\n setRate(rate) {\n this.rate = rate;\n return this;\n }\n getSpeed() {\n return this.speed;\n }\n setSpeed(speed) {\n this.speed = speed;\n return this;\n }\n getSize() {\n return this.size;\n }\n setSize(size) {\n this.size = size;\n return this;\n }\n getStartHeight() {\n return this.startHeight;\n }\n setStartHeight(startHeight) {\n this.startHeight = startHeight;\n return this;\n }\n}\n","import assert from \"assert\";\nimport MoneroError from \"../common/MoneroError\";\n/**\n * Copyright (c) woodser\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/**\n * Monero daemon interface and default implementations.\n */\nexport default class MoneroDaemon {\n /**\n * Register a listener to receive daemon notifications.\n *\n * @param {MoneroDaemonListener} listener - listener to receive daemon notifications\n * @return {Promise}\n */\n async addListener(listener) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Unregister a listener to receive daemon notifications.\n *\n * @param {MoneroDaemonListener} listener - listener to unregister\n * @return {Promise}\n */\n async removeListener(listener) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get the listeners registered with the daemon.\n *\n * @return {MoneroDaemonListener[]} the registered listeners\n */\n getListeners() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Indicates if the client is connected to the daemon via RPC.\n *\n * @return {Promise} true if the client is connected to the daemon, false otherwise\n */\n async isConnected() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Gets the version of the daemon.\n *\n * @return {Promise} the version of the daemon\n */\n async getVersion() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Indicates if the daemon is trusted xor untrusted.\n *\n * @return {Promise} true if the daemon is trusted, false otherwise\n */\n async isTrusted() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get the number of blocks in the longest chain known to the node.\n *\n * @return {Promise} the number of blocks!\n */\n async getHeight() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get a block's hash by its height.\n *\n * @param {number} height - height of the block hash to get\n * @return {Promise} the block's hash at the given height\n */\n async getBlockHash(height) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get a block template for mining a new block.\n *\n * @param {string} walletAddress - address of the wallet to receive miner transactions if block is successfully mined\n * @param {number} [reserveSize] - reserve size (optional)\n * @return {Promise} is a block template for mining a new block\n */\n async getBlockTemplate(walletAddress, reserveSize) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get the last block's header.\n *\n * @return {Promise} last block's header\n */\n async getLastBlockHeader() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get a block header by its hash.\n *\n * @param {string} blockHash - hash of the block to get the header of\n * @return {Promise} block's header\n */\n async getBlockHeaderByHash(blockHash) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get a block header by its height.\n *\n * @param {number} height - height of the block to get the header of\n * @return {Promise} block's header\n */\n async getBlockHeaderByHeight(height) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get block headers for the given range.\n *\n * @param {number} [startHeight] - start height lower bound inclusive (optional)\n * @param {number} [endHeight] - end height upper bound inclusive (optional)\n * @return {Promise} for the given range\n */\n async getBlockHeadersByRange(startHeight, endHeight) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get a block by hash.\n *\n * @param {string} blockHash - hash of the block to get\n * @return {Promise} with the given hash\n */\n async getBlockByHash(blockHash) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get blocks by hash.\n *\n * @param {string[]} blockHashes - array of hashes; first 10 blocks hashes goes sequential,\n * next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on,\n * and the last one is always genesis block\n * @param {number} startHeight - start height to get blocks by hash\n * @param {boolean} [prune] - specifies if returned blocks should be pruned (defaults to false) // TODO: test default\n * @return {Promise} retrieved blocks\n */\n async getBlocksByHash(blockHashes, startHeight, prune = false) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get a block by height.\n *\n * @param {number} height - height of the block to get\n * @return {Promise} with the given height\n */\n async getBlockByHeight(height) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get blocks at the given heights.\n *\n * @param {number[]} heights - heights of the blocks to get\n * @return {Promise} are blocks at the given heights\n */\n async getBlocksByHeight(heights) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get blocks in the given height range.\n *\n * @param {number} [startHeight] - start height lower bound inclusive (optional)\n * @param {number} [endHeight] - end height upper bound inclusive (optional)\n * @return {Promise} are blocks in the given height range\n */\n async getBlocksByRange(startHeight, endHeight) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get blocks in the given height range as chunked requests so that each request is\n * not too big.\n *\n * @param {number} [startHeight] - start height lower bound inclusive (optional)\n * @param {number} [endHeight] - end height upper bound inclusive (optional)\n * @param {number} [maxChunkSize] - maximum chunk size in any one request (default 3,000,000 bytes)\n * @return {Promise} blocks in the given height range\n */\n async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get block hashes as a binary request to the daemon.\n *\n * @param {string[]} blockHashes - specify block hashes to fetch; first 10 blocks hash goes\n * sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64\n * and so on, and the last one is always genesis block\n * @param {number} startHeight - starting height of block hashes to return\n * @return {Promise} requested block hashes\n */\n async getBlockHashes(blockHashes, startHeight) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get a transaction by hash.\n *\n * @param {string} txHash - hash of the transaction to get\n * @param {boolean} [prune] - specifies if the returned tx should be pruned (defaults to false)\n * @return {Promise} transaction with the given hash or undefined if not found\n */\n async getTx(txHash, prune = false) {\n return (await this.getTxs([txHash], prune))[0];\n }\n /**\n * Get transactions by hashes.\n *\n * @param {string[]} txHashes - hashes of transactions to get\n * @param {boolean} [prune] - specifies if the returned txs should be pruned (defaults to false)\n * @return {Promise} found transactions with the given hashes\n */\n async getTxs(txHashes, prune = false) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get a transaction hex by hash.\n *\n * @param {string} txHash - hash of the transaction to get hex from\n * @param {boolean} [prune] - specifies if the returned tx hex should be pruned (defaults to false)\n * @return {Promise} tx hex with the given hash\n */\n async getTxHex(txHash, prune = false) {\n return (await this.getTxHexes([txHash], prune))[0];\n }\n /**\n * Get transaction hexes by hashes.\n *\n * @param {string[]} txHashes - hashes of transactions to get hexes from\n * @param {boolean} [prune] - specifies if the returned tx hexes should be pruned (defaults to false)\n * @return {Promise} tx hexes\n */\n async getTxHexes(txHashes, prune = false) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Gets the total emissions and fees from the genesis block to the current height.\n *\n * @param {number} height - height to start computing the miner sum\n * @param {number} numBlocks - number of blocks to include in the sum\n * @return {Promise} encapsulates the total emissions and fees since the genesis block\n */\n async getMinerTxSum(height, numBlocks) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get mining fee estimates per kB.\n *\n * @param {number} graceBlocks TODO\n * @return {Promise} mining fee estimates per kB\n */\n async getFeeEstimate(graceBlocks) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Submits a transaction to the daemon's pool.\n *\n * @param {string} txHex - raw transaction hex to submit\n * @param {boolean} doNotRelay specifies if the tx should be relayed (default false, i.e. relay)\n * @return {Promise} contains submission results\n */\n async submitTxHex(txHex, doNotRelay = false) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Relays a transaction by hash.\n *\n * @param {string} txHash - hash of the transaction to relay\n * @return {Promise}\n */\n async relayTxByHash(txHash) {\n assert.equal(typeof txHash, \"string\", \"Must provide a transaction hash\");\n await this.relayTxsByHash([txHash]);\n }\n /**\n * Relays transactions by hash.\n *\n * @param {string[]} txHashes - hashes of the transactinos to relay\n * @return {Promise}\n */\n async relayTxsByHash(txHashes) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get valid transactions seen by the node but not yet mined into a block, as well\n * as spent key image information for the tx pool.\n *\n * @return {Promise} are transactions in the transaction pool!\n */\n async getTxPool() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get hashes of transactions in the transaction pool.\n *\n * @return {string[]} are hashes of transactions in the transaction pool\n */\n async getTxPoolHashes() {\n throw new MoneroError(\"Subclass must implement\");\n }\n // /**\n // * Get all transaction pool backlog.\n // * \n // * @return {Promise} backlog entries \n // */\n // async getTxPoolBacklog(): Promise {\n // throw new MoneroError(\"Subclass must implement\");\n // }\n /**\n * Get transaction pool statistics.\n *\n * @return {Promise} contains statistics about the transaction pool\n */\n async getTxPoolStats() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Flush transactions from the tx pool.\n *\n * @param {(string | string[])} [hashes] - specific transactions to flush (defaults to all)\n * @return {Promise}\n */\n async flushTxPool(hashes) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get the spent status of the given key image.\n *\n * @param {string} keyImage - key image hex to get the status of\n * @return {Promise} status of the key image\n */\n async getKeyImageSpentStatus(keyImage) {\n return (await this.getKeyImageSpentStatuses([keyImage]))[0];\n }\n /**\n * Get the spent status of each given key image.\n *\n * @param {string[]} keyImages are hex key images to get the statuses of\n * @return {Promise} status for each key image\n */\n async getKeyImageSpentStatuses(keyImages) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get outputs identified by a list of output amounts and indices as a binary\n * request.\n *\n * @param {MoneroOutput[]} outputs - identify each output by amount and index\n * @return {Promise} identified outputs\n */\n async getOutputs(outputs) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get a histogram of output amounts. For all amounts (possibly filtered by\n * parameters), gives the number of outputs on the chain for that amount.\n * RingCT outputs counts as 0 amount.\n *\n * @param {bigint[]} [amounts] - amounts of outputs to make the histogram with\n * @param {number} [minCount] - TODO\n * @param {number} [maxCount] - TODO\n * @param {boolean} [isUnlocked] - makes a histogram with outputs with the specified lock state\n * @param {number} [recentCutoff] - TODO\n * @return {Promise} are entries meeting the parameters\n */\n async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) {\n throw new MoneroError(\"Subclass must implement\");\n }\n // /**\n // * Creates an output distribution.\n // * \n // * @param {bigint[]} amounts - amounts of outputs to make the distribution with\n // * @param {boolean} [cumulative] - specifies if the results should be cumulative (defaults to TODO)\n // * @param {number} [startHeight] - start height lower bound inclusive (optional)\n // * @param {number} [endHeight] - end height upper bound inclusive (optional)\n // * @return {Promise} are entries meeting the parameters\n // */\n // async getOutputDistribution(amounts: bigint[], cumulative?: boolean, startHeight?: number, endHeight?: number): Promise {\n // throw new MoneroError(\"Subclass must implement\");\n // }\n /**\n * Get general information about the state of the node and the network.\n *\n * @return {Promise} is general information about the node and network\n */\n async getInfo() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get synchronization information.\n *\n * @return {Promise} contains sync information\n */\n async getSyncInfo() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Look up information regarding hard fork voting and readiness.\n *\n * @return {Promise } contains hard fork information\n */\n async getHardForkInfo() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get alternative chains seen by the node.\n *\n * @return {Promise} alternative chains\n */\n async getAltChains() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get known block hashes which are not on the main chain.\n *\n * @return {Promise} known block hashes which are not on the main chain\n */\n async getAltBlockHashes() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get the download bandwidth limit.\n *\n * @return {Promise} download bandwidth limit\n */\n async getDownloadLimit() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Set the download bandwidth limit.\n *\n * @param {number} limit - download limit to set (-1 to reset to default)\n * @return {number} new download limit after setting\n */\n async setDownloadLimit(limit) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Reset the download bandwidth limit.\n *\n * @return {Promise} download bandwidth limit after resetting\n */\n async resetDownloadLimit() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get the upload bandwidth limit.\n *\n * @return {Promise} upload bandwidth limit\n */\n async getUploadLimit() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Set the upload bandwidth limit.\n *\n * @param limit - upload limit to set (-1 to reset to default)\n * @return {Promise} new upload limit after setting\n */\n async setUploadLimit(limit) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Reset the upload bandwidth limit.\n *\n * @return {Promise} upload bandwidth limit after resetting\n */\n async resetUploadLimit() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get peers with active incoming or outgoing connections to the node.\n *\n * @return {Promise} the daemon's peers\n */\n async getPeers() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get known peers including their last known online status.\n *\n * @return {MoneroPeer[]} the daemon's known peers\n */\n async getKnownPeers() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Limit number of outgoing peers.\n *\n * @param {number} limit - maximum number of outgoing peers\n * @return {Promise}\n */\n async setOutgoingPeerLimit(limit) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Limit number of incoming peers.\n *\n * @param {number} limit - maximum number of incoming peers\n * @return {Promise}\n */\n async setIncomingPeerLimit(limit) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get peer bans.\n *\n * @return {Promise} entries about banned peers\n */\n async getPeerBans() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Ban a peer node.\n *\n * @param {MoneroBan} ban - contains information about a node to ban\n * @return {Promise}\n */\n async setPeerBan(ban) {\n return await this.setPeerBans([ban]);\n }\n /**\n * Ban peers nodes.\n *\n * @param {MoneroBan[]} bans - specify which peers to ban\n * @return {Promise}\n */\n async setPeerBans(bans) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Start mining.\n *\n * @param {string} address - address given miner rewards if the daemon mines a block\n * @param {integer} [numThreads] - number of mining threads to run (default 1)\n * @param {boolean} [isBackground] - specifies if the miner should run in the background or not (default false)\n * @param {boolean} [ignoreBattery] - specifies if the battery state (e.g. on laptop) should be ignored or not (default false)\n * @return {Promise}\n */\n async startMining(address, numThreads, isBackground, ignoreBattery) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Stop mining.\n *\n * @return {Promise}\n */\n async stopMining() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get the daemon's mining status.\n *\n * @return {Promise} daemon's mining status\n */\n async getMiningStatus() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Submit a mined block to the network.\n *\n * @param {string} blockBlob - mined block to submit\n * @return {Promise}\n */\n async submitBlock(blockBlob) {\n await this.submitBlocks([blockBlob]);\n }\n /**\n * Prune the blockchain.\n *\n * @param {boolean} check specifies to check the pruning (default false)\n * @return {Promise} the prune result\n */\n async pruneBlockchain(check) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Submit mined blocks to the network.\n *\n * @param {string[]} blockBlobs - mined blocks to submit\n * @return {Promise}\n */\n async submitBlocks(blockBlobs) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Check for update.\n *\n * @return {Promise} the result\n */\n async checkForUpdate() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Download an update.\n *\n * @param {string} [path] - path to download the update (optional)\n * @return {Promise} the result\n */\n async downloadUpdate(path) {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Safely disconnect and shut down the daemon.\n *\n * @return {Promise}\n */\n async stop() {\n throw new MoneroError(\"Subclass must implement\");\n }\n /**\n * Get the header of the next block added to the chain.\n *\n * @return {Promise} header of the next block added to the chain\n */\n async waitForNextBlockHeader() {\n throw new MoneroError(\"Subclass must implement\");\n }\n}\n","/**\n * Monero daemon info.\n */\nexport default class MoneroDaemonInfo {\n constructor(info) {\n Object.assign(this, info);\n // deserialize bigints\n if (this.difficulty !== undefined && typeof this.difficulty !== \"bigint\")\n this.difficulty = BigInt(this.difficulty);\n if (this.cumulativeDifficulty !== undefined && typeof this.cumulativeDifficulty !== \"bigint\")\n this.cumulativeDifficulty = BigInt(this.cumulativeDifficulty);\n if (this.credits !== undefined && typeof this.credits !== \"bigint\")\n this.credits = BigInt(this.credits);\n }\n toJson() {\n let json = Object.assign([], this);\n if (json.difficulty !== undefined)\n json.difficulty = json.difficulty.toString();\n if (json.cumulativeDifficulty !== undefined)\n json.cumulativeDifficulty = json.cumulativeDifficulty.toString();\n if (json.credits !== undefined)\n json.credits = json.credits.toString();\n return json;\n }\n getVersion() {\n return this.version;\n }\n setVersion(version) {\n this.version = version;\n return this;\n }\n getNumAltBlocks() {\n return this.numAltBlocks;\n }\n setNumAltBlocks(numAltBlocks) {\n this.numAltBlocks = numAltBlocks;\n return this;\n }\n getBlockSizeLimit() {\n return this.blockSizeLimit;\n }\n setBlockSizeLimit(blockSizeLimit) {\n this.blockSizeLimit = blockSizeLimit;\n return this;\n }\n getBlockSizeMedian() {\n return this.blockSizeMedian;\n }\n setBlockSizeMedian(blockSizeMedian) {\n this.blockSizeMedian = blockSizeMedian;\n return this;\n }\n getBlockWeightLimit() {\n return this.blockWeightLimit;\n }\n setBlockWeightLimit(blockWeightLimit) {\n this.blockWeightLimit = blockWeightLimit;\n return this;\n }\n getBlockWeightMedian() {\n return this.blockWeightMedian;\n }\n setBlockWeightMedian(blockWeightMedian) {\n this.blockWeightMedian = blockWeightMedian;\n return this;\n }\n getBootstrapDaemonAddress() {\n return this.bootstrapDaemonAddress;\n }\n setBootstrapDaemonAddress(bootstrapDaemonAddress) {\n this.bootstrapDaemonAddress = bootstrapDaemonAddress;\n return this;\n }\n getDifficulty() {\n return this.difficulty;\n }\n setDifficulty(difficulty) {\n this.difficulty = difficulty;\n return this;\n }\n getCumulativeDifficulty() {\n return this.cumulativeDifficulty;\n }\n setCumulativeDifficulty(cumulativeDifficulty) {\n this.cumulativeDifficulty = cumulativeDifficulty;\n return this;\n }\n getFreeSpace() {\n return this.freeSpace;\n }\n setFreeSpace(freeSpace) {\n this.freeSpace = freeSpace;\n return this;\n }\n getNumOfflinePeers() {\n return this.numOfflinePeers;\n }\n setNumOfflinePeers(numOfflinePeers) {\n this.numOfflinePeers = numOfflinePeers;\n return this;\n }\n getNumOnlinePeers() {\n return this.numOnlinePeers;\n }\n setNumOnlinePeers(numOnlinePeers) {\n this.numOnlinePeers = numOnlinePeers;\n return this;\n }\n getHeight() {\n return this.height;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n getHeightWithoutBootstrap() {\n return this.heightWithoutBootstrap;\n }\n setHeightWithoutBootstrap(heightWithoutBootstrap) {\n this.heightWithoutBootstrap = heightWithoutBootstrap;\n return this;\n }\n getNetworkType() {\n return this.networkType;\n }\n setNetworkType(networkType) {\n this.networkType = networkType;\n return this;\n }\n getIsOffline() {\n return this.isOffline;\n }\n setIsOffline(isOffline) {\n this.isOffline = isOffline;\n return this;\n }\n getNumIncomingConnections() {\n return this.numIncomingConnections;\n }\n setNumIncomingConnections(numIncomingConnections) {\n this.numIncomingConnections = numIncomingConnections;\n return this;\n }\n getNumOutgoingConnections() {\n return this.numOutgoingConnections;\n }\n setNumOutgoingConnections(numOutgoingConnections) {\n this.numOutgoingConnections = numOutgoingConnections;\n return this;\n }\n getNumRpcConnections() {\n return this.numRpcConnections;\n }\n setNumRpcConnections(numRpcConnections) {\n this.numRpcConnections = numRpcConnections;\n return this;\n }\n getStartTimestamp() {\n return this.startTimestamp;\n }\n setStartTimestamp(startTimestamp) {\n this.startTimestamp = startTimestamp;\n return this;\n }\n getAdjustedTimestamp() {\n return this.adjustedTimestamp;\n }\n setAdjustedTimestamp(adjustedTimestamp) {\n this.adjustedTimestamp = adjustedTimestamp;\n return this;\n }\n getTarget() {\n return this.target;\n }\n setTarget(target) {\n this.target = target;\n return this;\n }\n getTargetHeight() {\n return this.targetHeight;\n }\n setTargetHeight(targetHeight) {\n this.targetHeight = targetHeight;\n return this;\n }\n getTopBlockHash() {\n return this.topBlockHash;\n }\n setTopBlockHash(topBlockHash) {\n this.topBlockHash = topBlockHash;\n return this;\n }\n getNumTxs() {\n return this.numTxs;\n }\n setNumTxs(numTxs) {\n this.numTxs = numTxs;\n return this;\n }\n getNumTxsPool() {\n return this.numTxsPool;\n }\n setNumTxsPool(numTxsPool) {\n this.numTxsPool = numTxsPool;\n return this;\n }\n getWasBootstrapEverUsed() {\n return this.wasBootstrapEverUsed;\n }\n setWasBootstrapEverUsed(wasBootstrapEverUsed) {\n this.wasBootstrapEverUsed = wasBootstrapEverUsed;\n return this;\n }\n getDatabaseSize() {\n return this.databaseSize;\n }\n setDatabaseSize(databaseSize) {\n this.databaseSize = databaseSize;\n return this;\n }\n getUpdateAvailable() {\n return this.updateAvailable;\n }\n setUpdateAvailable(updateAvailable) {\n this.updateAvailable = updateAvailable;\n return this;\n }\n getCredits() {\n return this.credits;\n }\n setCredits(credits) {\n this.credits = credits;\n return this;\n }\n getIsBusySyncing() {\n return this.isBusySyncing;\n }\n setIsBusySyncing(isBusySyncing) {\n this.isBusySyncing = isBusySyncing;\n return this;\n }\n getIsSynchronized() {\n return this.isSynchronized;\n }\n setIsSynchronized(isSynchronized) {\n this.isSynchronized = isSynchronized;\n return this;\n }\n getIsRestricted() {\n return this.isRestricted;\n }\n setIsRestricted(isRestricted) {\n this.isRestricted = isRestricted;\n return this;\n }\n}\n","/**\n * Models a peer to the daemon.\n */\nexport default class MoneroPeer {\n constructor(peer) {\n Object.assign(this, peer);\n if (this.rpcCreditsPerHash !== undefined && typeof this.rpcCreditsPerHash !== \"bigint\")\n this.rpcCreditsPerHash = BigInt(this.rpcCreditsPerHash);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (json.rpcCreditsPerHash !== undefined)\n json.rpcCreditsPerHash = json.rpcCreditsPerHash.toString();\n return json;\n }\n getId() {\n return this.id;\n }\n setId(id) {\n this.id = id;\n return this;\n }\n getAddress() {\n return this.address;\n }\n setAddress(address) {\n this.address = address;\n return this;\n }\n getHost() {\n return this.host;\n }\n setHost(host) {\n this.host = host;\n return this;\n }\n getPort() {\n return this.port;\n }\n setPort(port) {\n this.port = port;\n return this;\n }\n /**\n * Indicates if the peer was online when last checked (aka \"white listed\" as\n * opposed to \"gray listed\").\n *\n * @return {boolean} true if peer was online when last checked, false otherwise\n */\n getIsOnline() {\n return this.isOnline;\n }\n setIsOnline(isOnline) {\n this.isOnline = isOnline;\n return this;\n }\n getLastSeenTimestamp() {\n return this.lastSeenTimestamp;\n }\n setLastSeenTimestamp(lastSeenTimestamp) {\n this.lastSeenTimestamp = lastSeenTimestamp;\n return this;\n }\n getPruningSeed() {\n return this.pruningSeed;\n }\n setPruningSeed(pruningSeed) {\n this.pruningSeed = pruningSeed;\n return this;\n }\n getRpcPort() {\n return this.rpcPort;\n }\n setRpcPort(rpcPort) {\n this.rpcPort = rpcPort;\n return this;\n }\n getRpcCreditsPerHash() {\n return this.rpcCreditsPerHash;\n }\n setRpcCreditsPerHash(rpcCreditsPerHash) {\n this.rpcCreditsPerHash = rpcCreditsPerHash;\n return this;\n }\n getAvgDownload() {\n return this.avgDownload;\n }\n setAvgDownload(avgDownload) {\n this.avgDownload = avgDownload;\n return this;\n }\n getAvgUpload() {\n return this.avgUpload;\n }\n setAvgUpload(avgUpload) {\n this.avgUpload = avgUpload;\n return this;\n }\n getCurrentDownload() {\n return this.currentDownload;\n }\n setCurrentDownload(currentDownload) {\n this.currentDownload = currentDownload;\n return this;\n }\n getCurrentUpload() {\n return this.currentUpload;\n }\n setCurrentUpload(currentUpload) {\n this.currentUpload = currentUpload;\n return this;\n }\n getHeight() {\n return this.height;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n getIsIncoming() {\n return this.isIncoming;\n }\n setIsIncoming(isIncoming) {\n this.isIncoming = isIncoming;\n return this;\n }\n getLiveTime() {\n return this.liveTime;\n }\n setLiveTime(liveTime) {\n this.liveTime = liveTime;\n return this;\n }\n getIsLocalIp() {\n return this.isLocalIp;\n }\n setIsLocalIp(isLocalIp) {\n this.isLocalIp = isLocalIp;\n return this;\n }\n getIsLocalHost() {\n return this.isLocalHost;\n }\n setIsLocalHost(isLocalHost) {\n this.isLocalHost = isLocalHost;\n return this;\n }\n getNumReceives() {\n return this.numReceives;\n }\n setNumReceives(numReceives) {\n this.numReceives = numReceives;\n return this;\n }\n getNumSends() {\n return this.numSends;\n }\n setNumSends(numSends) {\n this.numSends = numSends;\n return this;\n }\n getReceiveIdleTime() {\n return this.receiveIdleTime;\n }\n setReceiveIdleTime(receiveIdleTime) {\n this.receiveIdleTime = receiveIdleTime;\n return this;\n }\n getSendIdleTime() {\n return this.sendIdleTime;\n }\n setSendIdleTime(sendIdleTime) {\n this.sendIdleTime = sendIdleTime;\n return this;\n }\n getState() {\n return this.state;\n }\n setState(state) {\n this.state = state;\n return this;\n }\n getNumSupportFlags() {\n return this.numSupportFlags;\n }\n setNumSupportFlags(numSupportFlags) {\n this.numSupportFlags = numSupportFlags;\n return this;\n }\n getType() {\n return this.type;\n }\n setType(type) {\n this.type = type;\n return this;\n }\n}\n","import MoneroConnectionSpan from \"./MoneroConnectionSpan\";\nimport MoneroPeer from \"./MoneroPeer\";\n/**\n * Models daemon synchronization information.\n */\nexport default class MoneroDaemonSyncInfo {\n constructor(info) {\n Object.assign(this, info);\n // deserialize bigints\n if (this.credits !== undefined && typeof this.credits !== \"bigint\")\n this.credits = BigInt(this.credits);\n // copy peers\n if (this.peers) {\n for (let i = 0; i < this.peers.length; i++) {\n this.peers[i] = new MoneroPeer(this.peers[i]);\n }\n }\n // copy spans\n if (this.spans) {\n for (let i = 0; i < this.spans.length; i++) {\n this.spans[i] = new MoneroConnectionSpan(this.spans[i]);\n }\n }\n }\n toJson() {\n let json = Object.assign({}, this);\n if (json.peers !== undefined) {\n for (let i = 0; i < json.peers.length; i++) {\n json.peers[i] = json.peers[i].toJson();\n }\n }\n if (json.spans !== undefined) {\n for (let i = 0; i < json.spans.length; i++) {\n json.spans[i] = json.spans[i].toJson();\n }\n }\n if (json.credits !== undefined)\n json.credits = json.credits.toString();\n return json;\n }\n getHeight() {\n return this.height;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n getPeers() {\n return this.peers;\n }\n setPeers(peers) {\n this.peers = peers;\n return this;\n }\n getSpans() {\n return this.spans;\n }\n setSpans(spans) {\n this.spans = spans;\n return this;\n }\n getTargetHeight() {\n return this.targetHeight;\n }\n setTargetHeight(targetHeight) {\n this.targetHeight = targetHeight;\n return this;\n }\n getNextNeededPruningSeed() {\n return this.nextNeededPruningSeed;\n }\n setNextNeededPruningSeed(nextNeededPruningSeed) {\n this.nextNeededPruningSeed = nextNeededPruningSeed;\n return this;\n }\n getOverview() {\n return this.overview;\n }\n setOverview(overview) {\n this.overview = overview;\n return this;\n }\n getCredits() {\n return this.credits;\n }\n setCredits(credits) {\n this.credits = credits;\n return this;\n }\n getTopBlockHash() {\n return this.topBlockHash;\n }\n setTopBlockHash(topBlockHash) {\n this.topBlockHash = topBlockHash;\n return this;\n }\n}\n","/**\n * Models the result of checking for a daemon update.\n */\nexport default class MoneroDaemonUpdateCheckResult {\n constructor(result) {\n Object.assign(this, result);\n }\n /**\n * Indicates if an update is available.\n *\n * @return {boolean} true if an update is available, false otherwise\n */\n getIsUpdateAvailable() {\n return this.isUpdateAvailable;\n }\n setIsUpdateAvailable(isUpdateAvailable) {\n this.isUpdateAvailable = isUpdateAvailable;\n return this;\n }\n /**\n * Get the update's version.\n *\n * @return {string} is the update's version\n */\n getVersion() {\n return this.version;\n }\n setVersion(version) {\n this.version = version;\n return this;\n }\n /**\n * Get the update's hash.\n *\n * @return {string} is the update's hash\n */\n getHash() {\n return this.hash;\n }\n setHash(hash) {\n this.hash = hash;\n return this;\n }\n /**\n * Get the uri to automatically download the update.\n *\n * @return {string} is the uri to automatically download the update\n */\n getAutoUri() {\n return this.autoUri;\n }\n setAutoUri(autoUri) {\n this.autoUri = autoUri;\n return this;\n }\n /**\n * Get the uri to manually download the update.\n *\n * @return {string} is the uri to manually download the update\n */\n getUserUri() {\n return this.userUri;\n }\n setUserUri(userUri) {\n this.userUri = userUri;\n return this;\n }\n}\n","import MoneroDaemonUpdateCheckResult from \"./MoneroDaemonUpdateCheckResult\";\n/**\n * Models the result of downloading an update.\n */\nexport default class MoneroDaemonUpdateDownloadResult extends MoneroDaemonUpdateCheckResult {\n constructor(state) {\n super(state);\n }\n /**\n * Get the path the update was downloaded to.\n *\n * @return {string} is the path the update was downloaded to\n */\n getDownloadPath() {\n return this.downloadPath;\n }\n setDownloadPath(downloadPath) {\n this.downloadPath = downloadPath;\n return this;\n }\n}\n","import GenUtils from \"../../common/GenUtils\";\n/**\n * Models a Monero fee estimate.\n */\nexport default class MoneroFeeEstimate {\n constructor(feeEstimate) {\n Object.assign(this, feeEstimate);\n // deserialize\n if (this.fee !== undefined && typeof this.fee !== \"bigint\")\n this.fee = BigInt(this.fee);\n if (this.fees !== undefined) {\n for (let i = 0; i < this.fees.length; i++) {\n if (typeof this.fees[i] !== \"bigint\")\n this.fees[i] = BigInt(this.fees[i]);\n }\n }\n if (this.quantizationMask !== undefined && typeof this.quantizationMask !== \"bigint\")\n this.quantizationMask = BigInt(this.quantizationMask);\n }\n getFee() {\n return this.fee;\n }\n setFee(fee) {\n this.fee = fee;\n return this;\n }\n getFees() {\n return this.fees;\n }\n setFees(fees) {\n this.fees = fees;\n return this;\n }\n getQuantizationMask() {\n return this.quantizationMask;\n }\n setQuantizationMask(quantizationMask) {\n this.quantizationMask = quantizationMask;\n return this;\n }\n copy() {\n return new MoneroFeeEstimate(this);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (this.getFee())\n json.fee = this.getFee().toString();\n if (this.getFees())\n for (let i = 0; i < this.getFees().length; i++)\n json.fees[i] = this.getFees()[i].toString();\n if (this.getQuantizationMask())\n json.quantizationMask = this.getQuantizationMask().toString();\n return json;\n }\n toString(indent = 0) {\n let str = \"\";\n let json = this.toJson();\n str += GenUtils.kvLine(\"Fee\", json.fee, indent);\n str += GenUtils.kvLine(\"Fees\", json.fees, indent);\n str += GenUtils.kvLine(\"Quantization mask\", json.quantizationMask, indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n","/**\n * Monero hard fork info.\n */\nexport default class MoneroHardForkInfo {\n constructor(info) {\n Object.assign(this, info);\n if (this.credits !== undefined && typeof this.credits !== \"bigint\")\n this.credits = BigInt(this.credits);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (json.credits !== undefined)\n json.credits = json.credits.toString();\n return json;\n }\n getEarliestHeight() {\n return this.earliestHeight;\n }\n setEarliestHeight(earliestHeight) {\n this.earliestHeight = earliestHeight;\n return this;\n }\n getIsEnabled() {\n return this.isEnabled;\n }\n setIsEnabled(isEnabled) {\n this.isEnabled = isEnabled;\n return this;\n }\n getState() {\n return this.state;\n }\n setState(state) {\n this.state = state;\n return this;\n }\n getThreshold() {\n return this.threshold;\n }\n setThreshold(threshold) {\n this.threshold = threshold;\n return this;\n }\n getVersion() {\n return this.version;\n }\n setVersion(version) {\n this.version = version;\n return this;\n }\n getNumVotes() {\n return this.numVotes;\n }\n setNumVotes(numVotes) {\n this.numVotes = numVotes;\n return this;\n }\n getWindow() {\n return this.window;\n }\n setWindow(window) {\n this.window = window;\n return this;\n }\n getVoting() {\n return this.voting;\n }\n setVoting(voting) {\n this.voting = voting;\n return this;\n }\n getCredits() {\n return this.credits;\n }\n setCredits(credits) {\n this.credits = credits;\n return this;\n }\n getTopBlockHash() {\n return this.topBlockHash;\n }\n setTopBlockHash(topBlockHash) {\n this.topBlockHash = topBlockHash;\n return this;\n }\n}\n","/**\n * Model for the summation of miner emissions and fees.\n */\nexport default class MoneroMinerTxSum {\n constructor(txSum) {\n Object.assign(this, txSum);\n // deserialize bigints\n if (this.emissionSum !== undefined && typeof this.emissionSum !== \"bigint\")\n this.emissionSum = BigInt(this.emissionSum);\n if (this.feeSum !== undefined && typeof this.feeSum !== \"bigint\")\n this.feeSum = BigInt(this.feeSum);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (this.getEmissionSum() !== undefined)\n json.emissionSum = this.getEmissionSum().toString();\n if (this.getFeeSum() !== undefined)\n json.feeSum = this.getFeeSum().toString();\n return json;\n }\n getEmissionSum() {\n return this.emissionSum;\n }\n setEmissionSum(emissionSum) {\n this.emissionSum = emissionSum;\n return this;\n }\n getFeeSum() {\n return this.feeSum;\n }\n setFeeSum(feeSum) {\n this.feeSum = feeSum;\n return this;\n }\n}\n","/**\n * Models daemon mining status.\n */\nexport default class MoneroMiningStatus {\n constructor(status) {\n Object.assign(this, status);\n }\n toJson() {\n return Object.assign({}, this);\n }\n getIsActive() {\n return this.isActive;\n }\n setIsActive(isActive) {\n this.isActive = isActive;\n return this;\n }\n getAddress() {\n return this.address;\n }\n setAddress(address) {\n this.address = address;\n return this;\n }\n getSpeed() {\n return this.speed;\n }\n setSpeed(speed) {\n this.speed = speed;\n return this;\n }\n getNumThreads() {\n return this.numThreads;\n }\n setNumThreads(numThreads) {\n this.numThreads = numThreads;\n return this;\n }\n getIsBackground() {\n return this.isBackground;\n }\n setIsBackground(isBackground) {\n this.isBackground = isBackground;\n return this;\n }\n}\n","/**\n * Entry in a Monero output histogram (see get_output_histogram of Daemon RPC documentation).\n */\nexport default class MoneroOutputHistogramEntry {\n constructor(entry) {\n Object.assign(this, entry);\n if (this.amount !== undefined && typeof this.amount !== \"bigint\")\n this.amount = BigInt(this.amount);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (json.amount !== undefined)\n json.amount = json.amount.toString();\n return json;\n }\n getAmount() {\n return this.amount;\n }\n setAmount(amount) {\n this.amount = amount;\n return this;\n }\n getNumInstances() {\n return this.numInstances;\n }\n setNumInstances(numInstances) {\n this.numInstances = numInstances;\n return this;\n }\n getNumUnlockedInstances() {\n return this.numUnlockedInstances;\n }\n setNumUnlockedInstances(numUnlockedInstances) {\n this.numUnlockedInstances = numUnlockedInstances;\n return this;\n }\n getNumRecentInstances() {\n return this.numRecentInstances;\n }\n setNumRecentInstances(numRecentInstances) {\n this.numRecentInstances = numRecentInstances;\n return this;\n }\n}\n","/**\n * Result of pruning the blockchain.\n */\nexport default class MoneroPruneResult {\n constructor(result) {\n Object.assign(this, result);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (this.getIsPruned())\n json.isPruned = this.getIsPruned();\n if (this.getPruningSeed())\n json.pruningSeed = this.getPruningSeed();\n return json;\n }\n getIsPruned() {\n return this.isPruned;\n }\n setIsPruned(isPruned) {\n this.isPruned = isPruned;\n return this;\n }\n getPruningSeed() {\n return this.pruningSeed;\n }\n setPruningSeed(pruningSeed) {\n this.pruningSeed = pruningSeed;\n return this;\n }\n}\n","/**\n * Models the result from submitting a tx to a daemon.\n */\nexport default class MoneroSubmitTxResult {\n constructor(result) {\n Object.assign(this, result);\n if (this.credits !== undefined && typeof this.credits !== \"bigint\")\n this.credits = BigInt(this.credits);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (json.credits !== undefined)\n json.credits = json.credits.toString();\n return json;\n }\n getIsGood() {\n return this.isGood;\n }\n setIsGood(isGood) {\n this.isGood = isGood;\n return this;\n }\n getIsRelayed() {\n return this.isRelayed;\n }\n setIsRelayed(isRelayed) {\n this.isRelayed = isRelayed;\n return this;\n }\n getIsDoubleSpendSeen() {\n return this.isDoubleSpendSeen;\n }\n setIsDoubleSpendSeen(isDoubleSpendSeen) {\n this.isDoubleSpendSeen = isDoubleSpendSeen;\n return this;\n }\n getIsFeeTooLow() {\n return this.isFeeTooLow;\n }\n setIsFeeTooLow(isFeeTooLow) {\n this.isFeeTooLow = isFeeTooLow;\n return this;\n }\n getIsMixinTooLow() {\n return this.isMixinTooLow;\n }\n setIsMixinTooLow(isMixinTooLow) {\n this.isMixinTooLow = isMixinTooLow;\n return this;\n }\n getHasInvalidInput() {\n return this.hasInvalidInput;\n }\n setHasInvalidInput(hasInvalidInput) {\n this.hasInvalidInput = hasInvalidInput;\n return this;\n }\n getHasInvalidOutput() {\n return this.hasInvalidOutput;\n }\n setHasInvalidOutput(hasInvalidOutput) {\n this.hasInvalidOutput = hasInvalidOutput;\n return this;\n }\n getHasTooFewOutputs() {\n return this.hasTooFewOutputs;\n }\n setHasTooFewOutputs(hasTooFewOutputs) {\n this.hasTooFewOutputs = hasTooFewOutputs;\n return this;\n }\n getIsOverspend() {\n return this.isOverspend;\n }\n setIsOverspend(isOverspend) {\n this.isOverspend = isOverspend;\n return this;\n }\n getReason() {\n return this.reason;\n }\n setReason(reason) {\n this.reason = reason;\n return this;\n }\n getIsTooBig() {\n return this.isTooBig;\n }\n setIsTooBig(isTooBig) {\n this.isTooBig = isTooBig;\n return this;\n }\n getSanityCheckFailed() {\n return this.sanityCheckFailed;\n }\n setSanityCheckFailed(sanityCheckFailed) {\n this.sanityCheckFailed = sanityCheckFailed;\n return this;\n }\n getCredits() {\n return this.credits;\n }\n setCredits(credits) {\n this.credits = credits;\n return this;\n }\n getTopBlockHash() {\n return this.topBlockHash;\n }\n setTopBlockHash(topBlockHash) {\n this.topBlockHash = topBlockHash;\n return this;\n }\n getIsTxExtraTooBig() {\n return this.isTxExtraTooBig;\n }\n setIsTxExtraTooBig(isTxExtraTooBig) {\n this.isTxExtraTooBig = isTxExtraTooBig;\n return this;\n }\n getIsNonzeroUnlockTime() {\n return this.isNonzeroUnlockTime;\n }\n setIsNonzeroUnlockTime(isNonzeroUnlockTime) {\n this.isNonzeroUnlockTime = isNonzeroUnlockTime;\n return this;\n }\n}\n","/**\n * Models transaction pool statistics.\n */\nexport default class MoneroTxPoolStats {\n constructor(stats) {\n Object.assign(this, stats);\n if (this.feeTotal !== undefined && typeof this.feeTotal !== \"bigint\")\n this.feeTotal = BigInt(this.feeTotal);\n if (this.histo !== undefined && !(this.histo instanceof Map))\n this.histo = new Map(JSON.parse(this.histo));\n }\n toJson() {\n let json = Object.assign({}, this);\n if (json.feeTotal)\n json.feeTotal = json.feeTotal.toString();\n if (json.histo)\n json.histo = JSON.stringify([...json.histo]); // convert map to array of key-value pairs then stringify\n return json;\n }\n getNumTxs() {\n return this.numTxs;\n }\n setNumTxs(numTxs) {\n this.numTxs = numTxs;\n return this;\n }\n getNumNotRelayed() {\n return this.numNotRelayed;\n }\n setNumNotRelayed(numNotRelayed) {\n this.numNotRelayed = numNotRelayed;\n return this;\n }\n getNumFailing() {\n return this.numFailing;\n }\n setNumFailing(numFailing) {\n this.numFailing = numFailing;\n return this;\n }\n getNumDoubleSpends() {\n return this.numDoubleSpends;\n }\n setNumDoubleSpends(numDoubleSpends) {\n this.numDoubleSpends = numDoubleSpends;\n return this;\n }\n getNum10m() {\n return this.num10m;\n }\n setNum10m(num10m) {\n this.num10m = num10m;\n return this;\n }\n getFeeTotal() {\n return this.feeTotal;\n }\n setFeeTotal(feeTotal) {\n this.feeTotal = feeTotal;\n return this;\n }\n getBytesMax() {\n return this.bytesMax;\n }\n setBytesMax(bytesMax) {\n this.bytesMax = bytesMax;\n return this;\n }\n getBytesMed() {\n return this.bytesMed;\n }\n setBytesMed(bytesMed) {\n this.bytesMed = bytesMed;\n return this;\n }\n getBytesMin() {\n return this.bytesMin;\n }\n setBytesMin(bytesMin) {\n this.bytesMin = bytesMin;\n return this;\n }\n getBytesTotal() {\n return this.bytesTotal;\n }\n setBytesTotal(bytesTotal) {\n this.bytesTotal = bytesTotal;\n return this;\n }\n getHisto() {\n return this.histo;\n }\n setHisto(histo) {\n this.histo = histo;\n return this;\n }\n getHisto98pc() {\n return this.histo98pc;\n }\n setHisto98pc(histo98pc) {\n this.histo98pc = histo98pc;\n return this;\n }\n getOldestTimestamp() {\n return this.oldestTimestamp;\n }\n setOldestTimestamp(oldestTimestamp) {\n this.oldestTimestamp = oldestTimestamp;\n return this;\n }\n}\n","/**\n * Models a Monero version.\n */\nexport default class MoneroVersion {\n constructor(number, isRelease) {\n this.number = number;\n this.isRelease = isRelease;\n }\n getNumber() {\n return this.number;\n }\n setNumber(number) {\n this.number = number;\n return this;\n }\n getIsRelease() {\n return this.isRelease;\n }\n setIsRelease(isRelease) {\n this.isRelease = isRelease;\n return this;\n }\n copy() {\n return new MoneroVersion(this.number, this.isRelease);\n }\n toJson() {\n return Object.assign({}, this);\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"../common/GenUtils\";\nimport LibraryUtils from \"../common/LibraryUtils\";\nimport TaskLooper from \"../common/TaskLooper\";\nimport MoneroAltChain from \"./model/MoneroAltChain\";\nimport MoneroBan from \"./model/MoneroBan\";\nimport MoneroBlock from \"./model/MoneroBlock\";\nimport MoneroBlockHeader from \"./model/MoneroBlockHeader\";\nimport MoneroBlockTemplate from \"./model/MoneroBlockTemplate\";\nimport MoneroConnectionSpan from \"./model/MoneroConnectionSpan\";\nimport MoneroDaemon from \"./MoneroDaemon\";\nimport MoneroDaemonConfig from \"./model/MoneroDaemonConfig\";\nimport MoneroDaemonInfo from \"./model/MoneroDaemonInfo\";\nimport MoneroDaemonListener from \"./model/MoneroDaemonListener\";\nimport MoneroDaemonSyncInfo from \"./model/MoneroDaemonSyncInfo\";\nimport MoneroDaemonUpdateCheckResult from \"./model/MoneroDaemonUpdateCheckResult\";\nimport MoneroDaemonUpdateDownloadResult from \"./model/MoneroDaemonUpdateDownloadResult\";\nimport MoneroFeeEstimate from \"./model/MoneroFeeEstimate\";\nimport MoneroError from \"../common/MoneroError\";\nimport MoneroHardForkInfo from \"./model/MoneroHardForkInfo\";\nimport MoneroKeyImage from \"./model/MoneroKeyImage\";\nimport MoneroMinerTxSum from \"./model/MoneroMinerTxSum\";\nimport MoneroMiningStatus from \"./model/MoneroMiningStatus\";\nimport MoneroNetworkType from \"./model/MoneroNetworkType\";\nimport MoneroOutput from \"./model/MoneroOutput\";\nimport MoneroOutputHistogramEntry from \"./model/MoneroOutputHistogramEntry\";\nimport MoneroPeer from \"./model/MoneroPeer\";\nimport MoneroPruneResult from \"./model/MoneroPruneResult\";\nimport MoneroRpcConnection from \"../common/MoneroRpcConnection\";\nimport MoneroSubmitTxResult from \"./model/MoneroSubmitTxResult\";\nimport MoneroTx from \"./model/MoneroTx\";\nimport MoneroTxPoolStats from \"./model/MoneroTxPoolStats\";\nimport MoneroUtils from \"../common/MoneroUtils\";\nimport MoneroVersion from \"./model/MoneroVersion\";\n/**\n * Copyright (c) woodser\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/**\n * Implements a MoneroDaemon as a client of monerod.\n */\nclass MoneroDaemonRpc extends MoneroDaemon {\n /** @private */\n constructor(config, proxyDaemon) {\n super();\n this.config = config;\n this.proxyDaemon = proxyDaemon;\n if (config.proxyToWorker)\n return;\n this.listeners = []; // block listeners\n this.cachedHeaders = {}; // cached headers for fetching blocks in bound chunks\n }\n /**\n * Get the internal process running monerod.\n *\n * @return {ChildProcess} the node process running monerod, undefined if not created from new process\n */\n getProcess() {\n return this.process;\n }\n /**\n * Stop the internal process running monerod, if applicable.\n *\n * @param {boolean} [force] specifies if the process should be destroyed forcibly (default false)\n * @return {Promise} the exit code from stopping the process\n */\n async stopProcess(force = false) {\n if (this.process === undefined)\n throw new MoneroError(\"MoneroDaemonRpc instance not created from new process\");\n let listenersCopy = GenUtils.copyArray(await this.getListeners());\n for (let listener of listenersCopy)\n await this.removeListener(listener);\n return GenUtils.killProcess(this.process, force ? \"SIGKILL\" : undefined);\n }\n async addListener(listener) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.addListener(listener);\n assert(listener instanceof MoneroDaemonListener, \"Listener must be instance of MoneroDaemonListener\");\n this.listeners.push(listener);\n this.refreshListening();\n }\n async removeListener(listener) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.removeListener(listener);\n assert(listener instanceof MoneroDaemonListener, \"Listener must be instance of MoneroDaemonListener\");\n let idx = this.listeners.indexOf(listener);\n if (idx > -1)\n this.listeners.splice(idx, 1);\n else\n throw new MoneroError(\"Listener is not registered with daemon\");\n this.refreshListening();\n }\n getListeners() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getListeners();\n return this.listeners;\n }\n /**\n * Get the daemon's RPC connection.\n *\n * @return {MoneroRpcConnection} the daemon's rpc connection\n */\n async getRpcConnection() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getRpcConnection();\n return this.config.getServer();\n }\n async isConnected() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.isConnected();\n try {\n await this.getVersion();\n return true;\n }\n catch (e) {\n return false;\n }\n }\n async getVersion() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getVersion();\n let resp = await this.config.getServer().sendJsonRequest(\"get_version\");\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n return new MoneroVersion(resp.result.version, resp.result.release);\n }\n async isTrusted() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.isTrusted();\n let resp = await this.config.getServer().sendPathRequest(\"get_height\");\n MoneroDaemonRpc.checkResponseStatus(resp);\n return !resp.untrusted;\n }\n async getHeight() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getHeight();\n let resp = await this.config.getServer().sendJsonRequest(\"get_block_count\");\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n return resp.result.count;\n }\n async getBlockHash(height) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getBlockHash(height);\n return (await this.config.getServer().sendJsonRequest(\"on_get_block_hash\", [height])).result; // TODO monero-wallet-rpc: no status returned\n }\n async getBlockTemplate(walletAddress, reserveSize) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getBlockTemplate(walletAddress, reserveSize);\n assert(walletAddress && typeof walletAddress === \"string\", \"Must specify wallet address to be mined to\");\n let resp = await this.config.getServer().sendJsonRequest(\"get_block_template\", { wallet_address: walletAddress, reserve_size: reserveSize });\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n return MoneroDaemonRpc.convertRpcBlockTemplate(resp.result);\n }\n async getLastBlockHeader() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getLastBlockHeader();\n let resp = await this.config.getServer().sendJsonRequest(\"get_last_block_header\");\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n return MoneroDaemonRpc.convertRpcBlockHeader(resp.result.block_header);\n }\n async getBlockHeaderByHash(blockHash) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getBlockHeaderByHash(blockHash);\n let resp = await this.config.getServer().sendJsonRequest(\"get_block_header_by_hash\", { hash: blockHash });\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n return MoneroDaemonRpc.convertRpcBlockHeader(resp.result.block_header);\n }\n async getBlockHeaderByHeight(height) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getBlockHeaderByHeight(height);\n let resp = await this.config.getServer().sendJsonRequest(\"get_block_header_by_height\", { height: height });\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n return MoneroDaemonRpc.convertRpcBlockHeader(resp.result.block_header);\n }\n async getBlockHeadersByRange(startHeight, endHeight) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getBlockHeadersByRange(startHeight, endHeight);\n // fetch block headers\n let resp = await this.config.getServer().sendJsonRequest(\"get_block_headers_range\", {\n start_height: startHeight,\n end_height: endHeight\n });\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n // build headers\n let headers = [];\n for (let rpcHeader of resp.result.headers) {\n headers.push(MoneroDaemonRpc.convertRpcBlockHeader(rpcHeader));\n }\n return headers;\n }\n async getBlockByHash(blockHash) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getBlockByHash(blockHash);\n let resp = await this.config.getServer().sendJsonRequest(\"get_block\", { hash: blockHash });\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n return MoneroDaemonRpc.convertRpcBlock(resp.result);\n }\n async getBlockByHeight(height) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getBlockByHeight(height);\n let resp = await this.config.getServer().sendJsonRequest(\"get_block\", { height: height });\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n return MoneroDaemonRpc.convertRpcBlock(resp.result);\n }\n async getBlocksByHeight(heights) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getBlocksByHeight(heights);\n // fetch blocks in binary\n let respBin = await this.config.getServer().sendBinaryRequest(\"get_blocks_by_height.bin\", { heights: heights });\n // convert binary blocks to json\n let rpcBlocks = await MoneroUtils.binaryBlocksToJson(respBin);\n MoneroDaemonRpc.checkResponseStatus(rpcBlocks);\n // build blocks with transactions\n assert.equal(rpcBlocks.txs.length, rpcBlocks.blocks.length);\n let blocks = [];\n for (let blockIdx = 0; blockIdx < rpcBlocks.blocks.length; blockIdx++) {\n // build block\n let block = MoneroDaemonRpc.convertRpcBlock(rpcBlocks.blocks[blockIdx]);\n block.setHeight(heights[blockIdx]);\n blocks.push(block);\n // build transactions\n let txs = [];\n for (let txIdx = 0; txIdx < rpcBlocks.txs[blockIdx].length; txIdx++) {\n let tx = new MoneroTx();\n txs.push(tx);\n tx.setHash(rpcBlocks.blocks[blockIdx].tx_hashes[txIdx]);\n tx.setIsConfirmed(true);\n tx.setInTxPool(false);\n tx.setIsMinerTx(false);\n tx.setRelay(true);\n tx.setIsRelayed(true);\n tx.setIsFailed(false);\n tx.setIsDoubleSpendSeen(false);\n MoneroDaemonRpc.convertRpcTx(rpcBlocks.txs[blockIdx][txIdx], tx);\n }\n // merge into one block\n block.setTxs([]);\n for (let tx of txs) {\n if (tx.getBlock())\n block.merge(tx.getBlock());\n else\n block.getTxs().push(tx.setBlock(block));\n }\n }\n return blocks;\n }\n async getBlocksByRange(startHeight, endHeight) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getBlocksByRange(startHeight, endHeight);\n if (startHeight === undefined)\n startHeight = 0;\n if (endHeight === undefined)\n endHeight = await this.getHeight() - 1;\n let heights = [];\n for (let height = startHeight; height <= endHeight; height++)\n heights.push(height);\n return await this.getBlocksByHeight(heights);\n }\n async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize);\n if (startHeight === undefined)\n startHeight = 0;\n if (endHeight === undefined)\n endHeight = await this.getHeight() - 1;\n let lastHeight = startHeight - 1;\n let blocks = [];\n while (lastHeight < endHeight) {\n for (let block of await this.getMaxBlocks(lastHeight + 1, endHeight, maxChunkSize)) {\n blocks.push(block);\n }\n lastHeight = blocks[blocks.length - 1].getHeight();\n }\n return blocks;\n }\n async getTxs(txHashes, prune = false) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getTxs(txHashes, prune);\n // validate input\n assert(Array.isArray(txHashes) && txHashes.length > 0, \"Must provide an array of transaction hashes\");\n assert(prune === undefined || typeof prune === \"boolean\", \"Prune must be a boolean or undefined\");\n // fetch transactions\n let resp = await this.config.getServer().sendPathRequest(\"get_transactions\", {\n txs_hashes: txHashes,\n decode_as_json: true,\n prune: prune\n });\n try {\n MoneroDaemonRpc.checkResponseStatus(resp);\n }\n catch (e) {\n if (e.message.indexOf(\"Failed to parse hex representation of transaction hash\") >= 0)\n throw new MoneroError(\"Invalid transaction hash\");\n throw e;\n }\n // build transaction models\n let txs = [];\n if (resp.txs) {\n for (let txIdx = 0; txIdx < resp.txs.length; txIdx++) {\n let tx = new MoneroTx();\n tx.setIsMinerTx(false);\n txs.push(MoneroDaemonRpc.convertRpcTx(resp.txs[txIdx], tx));\n }\n }\n return txs;\n }\n async getTxHexes(txHashes, prune = false) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getTxHexes(txHashes, prune);\n let hexes = [];\n for (let tx of await this.getTxs(txHashes, prune))\n hexes.push(prune ? tx.getPrunedHex() : tx.getFullHex());\n return hexes;\n }\n async getMinerTxSum(height, numBlocks) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getMinerTxSum(height, numBlocks);\n if (height === undefined)\n height = 0;\n else\n assert(height >= 0, \"Height must be an integer >= 0\");\n if (numBlocks === undefined)\n numBlocks = await this.getHeight();\n else\n assert(numBlocks >= 0, \"Count must be an integer >= 0\");\n let resp = await this.config.getServer().sendJsonRequest(\"get_coinbase_tx_sum\", { height: height, count: numBlocks });\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n let txSum = new MoneroMinerTxSum();\n txSum.setEmissionSum(BigInt(resp.result.emission_amount));\n txSum.setFeeSum(BigInt(resp.result.fee_amount));\n return txSum;\n }\n async getFeeEstimate(graceBlocks) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getFeeEstimate(graceBlocks);\n let resp = await this.config.getServer().sendJsonRequest(\"get_fee_estimate\", { grace_blocks: graceBlocks });\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n let feeEstimate = new MoneroFeeEstimate();\n feeEstimate.setFee(BigInt(resp.result.fee));\n feeEstimate.setQuantizationMask(BigInt(resp.result.quantization_mask));\n if (resp.result.fees !== undefined) {\n let fees = [];\n for (let i = 0; i < resp.result.fees.length; i++)\n fees.push(BigInt(resp.result.fees[i]));\n feeEstimate.setFees(fees);\n }\n return feeEstimate;\n }\n async submitTxHex(txHex, doNotRelay) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.submitTxHex(txHex, doNotRelay);\n let resp = await this.config.getServer().sendPathRequest(\"send_raw_transaction\", { tx_as_hex: txHex, do_not_relay: doNotRelay });\n let result = MoneroDaemonRpc.convertRpcSubmitTxResult(resp);\n // set isGood based on status\n try {\n MoneroDaemonRpc.checkResponseStatus(resp);\n result.setIsGood(true);\n }\n catch (e) {\n result.setIsGood(false);\n }\n return result;\n }\n async relayTxsByHash(txHashes) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.relayTxsByHash(txHashes);\n let resp = await this.config.getServer().sendJsonRequest(\"relay_tx\", { txids: txHashes });\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n }\n async getTxPool() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getTxPool();\n // send rpc request\n let resp = await this.config.getServer().sendPathRequest(\"get_transaction_pool\");\n MoneroDaemonRpc.checkResponseStatus(resp);\n // build txs\n let txs = [];\n if (resp.transactions) {\n for (let rpcTx of resp.transactions) {\n let tx = new MoneroTx();\n txs.push(tx);\n tx.setIsConfirmed(false);\n tx.setIsMinerTx(false);\n tx.setInTxPool(true);\n tx.setNumConfirmations(0);\n MoneroDaemonRpc.convertRpcTx(rpcTx, tx);\n }\n }\n return txs;\n }\n async getTxPoolHashes() {\n throw new MoneroError(\"Not implemented\");\n }\n // async getTxPoolBacklog(): Promise {\n // throw new MoneroError(\"Not implemented\");\n // }\n async getTxPoolStats() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getTxPoolStats();\n let resp = await this.config.getServer().sendPathRequest(\"get_transaction_pool_stats\");\n MoneroDaemonRpc.checkResponseStatus(resp);\n return MoneroDaemonRpc.convertRpcTxPoolStats(resp.pool_stats);\n }\n async flushTxPool(hashes) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.flushTxPool(hashes);\n if (hashes)\n hashes = GenUtils.listify(hashes);\n let resp = await this.config.getServer().sendJsonRequest(\"flush_txpool\", { txids: hashes });\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n }\n async getKeyImageSpentStatuses(keyImages) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getKeyImageSpentStatuses(keyImages);\n if (keyImages === undefined || keyImages.length === 0)\n throw new MoneroError(\"Must provide key images to check the status of\");\n let resp = await this.config.getServer().sendPathRequest(\"is_key_image_spent\", { key_images: keyImages });\n MoneroDaemonRpc.checkResponseStatus(resp);\n return resp.spent_status;\n }\n async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff);\n // send rpc request\n let resp = await this.config.getServer().sendJsonRequest(\"get_output_histogram\", {\n amounts: amounts,\n min_count: minCount,\n max_count: maxCount,\n unlocked: isUnlocked,\n recent_cutoff: recentCutoff\n });\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n // build histogram entries from response\n let entries = [];\n if (!resp.result.histogram)\n return entries;\n for (let rpcEntry of resp.result.histogram) {\n entries.push(MoneroDaemonRpc.convertRpcOutputHistogramEntry(rpcEntry));\n }\n return entries;\n }\n async getOutputDistribution(amounts, cumulative, startHeight, endHeight) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getOutputDistribution(amounts, cumulative, startHeight, endHeight);\n throw new MoneroError(\"Not implemented (response 'distribution' field is binary)\");\n // let amountStrs = [];\n // for (let amount of amounts) amountStrs.push(amount.toJSValue());\n // console.log(amountStrs);\n // console.log(cumulative);\n // console.log(startHeight);\n // console.log(endHeight);\n // \n // // send rpc request\n // console.log(\"*********** SENDING REQUEST *************\");\n // if (startHeight === undefined) startHeight = 0;\n // let resp = await this.config.getServer().sendJsonRequest(\"get_output_distribution\", {\n // amounts: amountStrs,\n // cumulative: cumulative,\n // from_height: startHeight,\n // to_height: endHeight\n // });\n // \n // console.log(\"RESPONSE\");\n // console.log(resp);\n // \n // // build distribution entries from response\n // let entries = [];\n // if (!resp.result.distributions) return entries; \n // for (let rpcEntry of resp.result.distributions) {\n // let entry = MoneroDaemonRpc.convertRpcOutputDistributionEntry(rpcEntry);\n // entries.push(entry);\n // }\n // return entries;\n }\n async getInfo() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getInfo();\n let resp = await this.config.getServer().sendJsonRequest(\"get_info\");\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n return MoneroDaemonRpc.convertRpcInfo(resp.result);\n }\n async getSyncInfo() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getSyncInfo();\n let resp = await this.config.getServer().sendJsonRequest(\"sync_info\");\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n return MoneroDaemonRpc.convertRpcSyncInfo(resp.result);\n }\n async getHardForkInfo() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getHardForkInfo();\n let resp = await this.config.getServer().sendJsonRequest(\"hard_fork_info\");\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n return MoneroDaemonRpc.convertRpcHardForkInfo(resp.result);\n }\n async getAltChains() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getAltChains();\n // // mocked response for test\n // let resp = {\n // status: \"OK\",\n // chains: [\n // {\n // block_hash: \"697cf03c89a9b118f7bdf11b1b3a6a028d7b3617d2d0ed91322c5709acf75625\",\n // difficulty: 14114729638300280,\n // height: 1562062,\n // length: 2\n // }\n // ]\n // }\n let resp = await this.config.getServer().sendJsonRequest(\"get_alternate_chains\");\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n let chains = [];\n if (!resp.result.chains)\n return chains;\n for (let rpcChain of resp.result.chains)\n chains.push(MoneroDaemonRpc.convertRpcAltChain(rpcChain));\n return chains;\n }\n async getAltBlockHashes() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getAltBlockHashes();\n // // mocked response for test\n // let resp = {\n // status: \"OK\",\n // untrusted: false,\n // blks_hashes: [\"9c2277c5470234be8b32382cdf8094a103aba4fcd5e875a6fc159dc2ec00e011\",\"637c0e0f0558e284493f38a5fcca3615db59458d90d3a5eff0a18ff59b83f46f\",\"6f3adc174a2e8082819ebb965c96a095e3e8b63929ad9be2d705ad9c086a6b1c\",\"697cf03c89a9b118f7bdf11b1b3a6a028d7b3617d2d0ed91322c5709acf75625\"]\n // }\n let resp = await this.config.getServer().sendPathRequest(\"get_alt_blocks_hashes\");\n MoneroDaemonRpc.checkResponseStatus(resp);\n if (!resp.blks_hashes)\n return [];\n return resp.blks_hashes;\n }\n async getDownloadLimit() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getDownloadLimit();\n return (await this.getBandwidthLimits())[0];\n }\n async setDownloadLimit(limit) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.setDownloadLimit(limit);\n if (limit == -1)\n return await this.resetDownloadLimit();\n if (!(GenUtils.isInt(limit) && limit > 0))\n throw new MoneroError(\"Download limit must be an integer greater than 0\");\n return (await this.setBandwidthLimits(limit, 0))[0];\n }\n async resetDownloadLimit() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.resetDownloadLimit();\n return (await this.setBandwidthLimits(-1, 0))[0];\n }\n async getUploadLimit() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getUploadLimit();\n return (await this.getBandwidthLimits())[1];\n }\n async setUploadLimit(limit) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.setUploadLimit(limit);\n if (limit == -1)\n return await this.resetUploadLimit();\n if (!(GenUtils.isInt(limit) && limit > 0))\n throw new MoneroError(\"Upload limit must be an integer greater than 0\");\n return (await this.setBandwidthLimits(0, limit))[1];\n }\n async resetUploadLimit() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.resetUploadLimit();\n return (await this.setBandwidthLimits(0, -1))[1];\n }\n async getPeers() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getPeers();\n let resp = await this.config.getServer().sendJsonRequest(\"get_connections\");\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n let peers = [];\n if (!resp.result.connections)\n return peers;\n for (let rpcConnection of resp.result.connections) {\n peers.push(MoneroDaemonRpc.convertRpcConnection(rpcConnection));\n }\n return peers;\n }\n async getKnownPeers() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getKnownPeers();\n // tx config\n let resp = await this.config.getServer().sendPathRequest(\"get_peer_list\");\n MoneroDaemonRpc.checkResponseStatus(resp);\n // build peers\n let peers = [];\n if (resp.gray_list) {\n for (let rpcPeer of resp.gray_list) {\n let peer = MoneroDaemonRpc.convertRpcPeer(rpcPeer);\n peer.setIsOnline(false); // gray list means offline last checked\n peers.push(peer);\n }\n }\n if (resp.white_list) {\n for (let rpcPeer of resp.white_list) {\n let peer = MoneroDaemonRpc.convertRpcPeer(rpcPeer);\n peer.setIsOnline(true); // white list means online last checked\n peers.push(peer);\n }\n }\n return peers;\n }\n async setOutgoingPeerLimit(limit) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.setOutgoingPeerLimit(limit);\n if (!(GenUtils.isInt(limit) && limit >= 0))\n throw new MoneroError(\"Outgoing peer limit must be >= 0\");\n let resp = await this.config.getServer().sendPathRequest(\"out_peers\", { out_peers: limit });\n MoneroDaemonRpc.checkResponseStatus(resp);\n }\n async setIncomingPeerLimit(limit) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.setIncomingPeerLimit(limit);\n if (!(GenUtils.isInt(limit) && limit >= 0))\n throw new MoneroError(\"Incoming peer limit must be >= 0\");\n let resp = await this.config.getServer().sendPathRequest(\"in_peers\", { in_peers: limit });\n MoneroDaemonRpc.checkResponseStatus(resp);\n }\n async getPeerBans() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getPeerBans();\n let resp = await this.config.getServer().sendJsonRequest(\"get_bans\");\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n let bans = [];\n for (let rpcBan of resp.result.bans) {\n let ban = new MoneroBan();\n ban.setHost(rpcBan.host);\n ban.setIp(rpcBan.ip);\n ban.setSeconds(rpcBan.seconds);\n bans.push(ban);\n }\n return bans;\n }\n async setPeerBans(bans) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.setPeerBans(bans);\n let rpcBans = [];\n for (let ban of bans)\n rpcBans.push(MoneroDaemonRpc.convertToRpcBan(ban));\n let resp = await this.config.getServer().sendJsonRequest(\"set_bans\", { bans: rpcBans });\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n }\n async startMining(address, numThreads, isBackground, ignoreBattery) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.startMining(address, numThreads, isBackground, ignoreBattery);\n assert(address, \"Must provide address to mine to\");\n assert(GenUtils.isInt(numThreads) && numThreads > 0, \"Number of threads must be an integer greater than 0\");\n assert(isBackground === undefined || typeof isBackground === \"boolean\");\n assert(ignoreBattery === undefined || typeof ignoreBattery === \"boolean\");\n let resp = await this.config.getServer().sendPathRequest(\"start_mining\", {\n miner_address: address,\n threads_count: numThreads,\n do_background_mining: isBackground,\n ignore_battery: ignoreBattery,\n });\n MoneroDaemonRpc.checkResponseStatus(resp);\n }\n async stopMining() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.stopMining();\n let resp = await this.config.getServer().sendPathRequest(\"stop_mining\");\n MoneroDaemonRpc.checkResponseStatus(resp);\n }\n async getMiningStatus() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.getMiningStatus();\n let resp = await this.config.getServer().sendPathRequest(\"mining_status\");\n MoneroDaemonRpc.checkResponseStatus(resp);\n return MoneroDaemonRpc.convertRpcMiningStatus(resp);\n }\n async submitBlocks(blockBlobs) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.submitBlocks(blockBlobs);\n assert(Array.isArray(blockBlobs) && blockBlobs.length > 0, \"Must provide an array of mined block blobs to submit\");\n let resp = await this.config.getServer().sendJsonRequest(\"submit_block\", blockBlobs);\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n }\n async pruneBlockchain(check) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.pruneBlockchain();\n let resp = await this.config.getServer().sendJsonRequest(\"prune_blockchain\", { check: check }, 0);\n MoneroDaemonRpc.checkResponseStatus(resp.result);\n let result = new MoneroPruneResult();\n result.setIsPruned(resp.result.pruned);\n result.setPruningSeed(resp.result.pruning_seed);\n return result;\n }\n async checkForUpdate() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.checkForUpdate();\n let resp = await this.config.getServer().sendPathRequest(\"update\", { command: \"check\" });\n MoneroDaemonRpc.checkResponseStatus(resp);\n return MoneroDaemonRpc.convertRpcUpdateCheckResult(resp);\n }\n async downloadUpdate(path) {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.downloadUpdate(path);\n let resp = await this.config.getServer().sendPathRequest(\"update\", { command: \"download\", path: path });\n MoneroDaemonRpc.checkResponseStatus(resp);\n return MoneroDaemonRpc.convertRpcUpdateDownloadResult(resp);\n }\n async stop() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.stop();\n let resp = await this.config.getServer().sendPathRequest(\"stop_daemon\");\n MoneroDaemonRpc.checkResponseStatus(resp);\n }\n async waitForNextBlockHeader() {\n if (this.config.proxyToWorker)\n return this.proxyDaemon.waitForNextBlockHeader();\n let that = this;\n return new Promise(async function (resolve) {\n await that.addListener(new class extends MoneroDaemonListener {\n async onBlockHeader(header) {\n await that.removeListener(this);\n resolve(header);\n }\n });\n });\n }\n getPollInterval() {\n return this.config.pollInterval;\n }\n // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS --------------\n async getTx(txHash, prune = false) { return super.getTx(txHash, prune); }\n ;\n async getTxHex(txHash, prune = false) { return super.getTxHex(txHash, prune); }\n ;\n async getKeyImageSpentStatus(keyImage) { return super.getKeyImageSpentStatus(keyImage); }\n async setPeerBan(ban) { return super.setPeerBan(ban); }\n async submitBlock(blockBlob) { return super.submitBlock(blockBlob); }\n // ------------------------------- PRIVATE ----------------------------------\n refreshListening() {\n if (this.pollListener == undefined && this.listeners.length)\n this.pollListener = new DaemonPoller(this);\n if (this.pollListener !== undefined)\n this.pollListener.setIsPolling(this.listeners.length > 0);\n }\n async getBandwidthLimits() {\n let resp = await this.config.getServer().sendPathRequest(\"get_limit\");\n MoneroDaemonRpc.checkResponseStatus(resp);\n return [resp.limit_down, resp.limit_up];\n }\n async setBandwidthLimits(downLimit, upLimit) {\n if (downLimit === undefined)\n downLimit = 0;\n if (upLimit === undefined)\n upLimit = 0;\n let resp = await this.config.getServer().sendPathRequest(\"set_limit\", { limit_down: downLimit, limit_up: upLimit });\n MoneroDaemonRpc.checkResponseStatus(resp);\n return [resp.limit_down, resp.limit_up];\n }\n /**\n * Get a contiguous chunk of blocks starting from a given height up to a maximum\n * height or amount of block data fetched from the blockchain, whichever comes first.\n *\n * @param {number} [startHeight] - start height to retrieve blocks (default 0)\n * @param {number} [maxHeight] - maximum end height to retrieve blocks (default blockchain height)\n * @param {number} [maxReqSize] - maximum amount of block data to fetch from the blockchain in bytes (default 3,000,000 bytes)\n * @return {MoneroBlock[]} are the resulting chunk of blocks\n */\n async getMaxBlocks(startHeight, maxHeight, maxReqSize) {\n if (startHeight === undefined)\n startHeight = 0;\n if (maxHeight === undefined)\n maxHeight = await this.getHeight() - 1;\n if (maxReqSize === undefined)\n maxReqSize = MoneroDaemonRpc.MAX_REQ_SIZE;\n // determine end height to fetch\n let reqSize = 0;\n let endHeight = startHeight - 1;\n while (reqSize < maxReqSize && endHeight < maxHeight) {\n // get header of next block\n let header = await this.getBlockHeaderByHeightCached(endHeight + 1, maxHeight);\n // block cannot be bigger than max request size\n assert(header.getSize() <= maxReqSize, \"Block exceeds maximum request size: \" + header.getSize());\n // done iterating if fetching block would exceed max request size\n if (reqSize + header.getSize() > maxReqSize)\n break;\n // otherwise block is included\n reqSize += header.getSize();\n endHeight++;\n }\n return endHeight >= startHeight ? await this.getBlocksByRange(startHeight, endHeight) : [];\n }\n /**\n * Retrieves a header by height from the cache or fetches and caches a header\n * range if not already in the cache.\n *\n * @param {number} height - height of the header to retrieve from the cache\n * @param {number} maxHeight - maximum height of headers to cache\n */\n async getBlockHeaderByHeightCached(height, maxHeight) {\n // get header from cache\n let cachedHeader = this.cachedHeaders[height];\n if (cachedHeader)\n return cachedHeader;\n // fetch and cache headers if not in cache\n let endHeight = Math.min(maxHeight, height + MoneroDaemonRpc.NUM_HEADERS_PER_REQ - 1); // TODO: could specify end height to cache to optimize small requests (would like to have time profiling in place though)\n let headers = await this.getBlockHeadersByRange(height, endHeight);\n for (let header of headers) {\n this.cachedHeaders[header.getHeight()] = header;\n }\n // return the cached header\n return this.cachedHeaders[height];\n }\n // --------------------------------- STATIC ---------------------------------\n static async connectToDaemonRpc(uriOrConfig, username, password) {\n let config = MoneroDaemonRpc.normalizeConfig(uriOrConfig, username, password);\n if (config.cmd)\n return MoneroDaemonRpc.startMonerodProcess(config);\n return new MoneroDaemonRpc(config, config.proxyToWorker ? await MoneroDaemonRpcProxy.connect(config) : undefined);\n }\n static async startMonerodProcess(config) {\n assert(GenUtils.isArray(config.cmd), \"Must provide string array with command line parameters\");\n // start process\n let childProcess = require('child_process').spawn(config.cmd[0], config.cmd.slice(1), {\n env: { ...process.env, LANG: 'en_US.UTF-8' } // scrape output in english\n });\n childProcess.stdout.setEncoding('utf8');\n childProcess.stderr.setEncoding('utf8');\n // return promise which resolves after starting monerod\n let uri;\n let output = \"\";\n try {\n return await new Promise(function (resolve, reject) {\n // handle stdout\n childProcess.stdout.on('data', async function (data) {\n let line = data.toString();\n LibraryUtils.log(2, line);\n output += line + '\\n'; // capture output in case of error\n // extract uri from e.g. \"I Binding on 127.0.0.1 (IPv4):38085\"\n let uriLineContains = \"Binding on \";\n let uriLineContainsIdx = line.indexOf(uriLineContains);\n if (uriLineContainsIdx >= 0) {\n let host = line.substring(uriLineContainsIdx + uriLineContains.length, line.lastIndexOf(' '));\n let unformattedLine = line.replace(/\\u001b\\[.*?m/g, '').trim(); // remove color formatting\n let port = unformattedLine.substring(unformattedLine.lastIndexOf(':') + 1);\n let sslIdx = config.cmd.indexOf(\"--rpc-ssl\");\n let sslEnabled = sslIdx >= 0 ? \"enabled\" == config.cmd[sslIdx + 1].toLowerCase() : false;\n uri = (sslEnabled ? \"https\" : \"http\") + \"://\" + host + \":\" + port;\n }\n // read success message\n if (line.indexOf(\"core RPC server started ok\") >= 0) {\n // get username and password from params\n let userPassIdx = config.cmd.indexOf(\"--rpc-login\");\n let userPass = userPassIdx >= 0 ? config.cmd[userPassIdx + 1] : undefined;\n let username = userPass === undefined ? undefined : userPass.substring(0, userPass.indexOf(':'));\n let password = userPass === undefined ? undefined : userPass.substring(userPass.indexOf(':') + 1);\n // create client connected to internal process\n config = config.copy().setServer({ uri: uri, username: username, password: password, rejectUnauthorized: config.getServer() ? config.getServer().getRejectUnauthorized() : undefined });\n config.setProxyToWorker(config.proxyToWorker);\n config.cmd = undefined;\n let daemon = await MoneroDaemonRpc.connectToDaemonRpc(config);\n daemon.process = childProcess;\n // resolve promise with client connected to internal process \n this.isResolved = true;\n resolve(daemon);\n }\n });\n // handle stderr\n childProcess.stderr.on('data', function (data) {\n if (LibraryUtils.getLogLevel() >= 2)\n console.error(data);\n });\n // handle exit\n childProcess.on(\"exit\", function (code) {\n if (!this.isResolved)\n reject(new Error(\"monerod process terminated with exit code \" + code + (output ? \":\\n\\n\" + output : \"\")));\n });\n // handle error\n childProcess.on(\"error\", function (err) {\n if (err.message.indexOf(\"ENOENT\") >= 0)\n reject(new Error(\"monerod does not exist at path '\" + config.cmd[0] + \"'\"));\n if (!this.isResolved)\n reject(err);\n });\n // handle uncaught exception\n childProcess.on(\"uncaughtException\", function (err, origin) {\n console.error(\"Uncaught exception in monerod process: \" + err.message);\n console.error(origin);\n if (!this.isResolved)\n reject(err);\n });\n });\n }\n catch (err) {\n throw new MoneroError(err.message);\n }\n }\n static normalizeConfig(uriOrConfig, username, password) {\n let config = undefined;\n if (typeof uriOrConfig === \"string\") {\n config = new MoneroDaemonConfig({ server: new MoneroRpcConnection(uriOrConfig, username, password) });\n }\n else if (uriOrConfig.uri !== undefined) {\n config = new MoneroDaemonConfig({ server: new MoneroRpcConnection(uriOrConfig) });\n // transfer worker proxy setting from rpc connection to daemon config\n config.setProxyToWorker(uriOrConfig.proxyToWorker);\n config.getServer().setProxyToWorker(MoneroRpcConnection.DEFAULT_CONFIG.proxyToWorker);\n }\n else if (GenUtils.isArray(uriOrConfig)) {\n config = new MoneroDaemonConfig({ cmd: uriOrConfig });\n }\n else {\n config = new MoneroDaemonConfig(uriOrConfig);\n }\n if (config.proxyToWorker === undefined)\n config.proxyToWorker = true;\n if (config.pollInterval === undefined)\n config.pollInterval = MoneroDaemonRpc.DEFAULT_POLL_PERIOD;\n return config;\n }\n static checkResponseStatus(resp) {\n if (resp.status !== \"OK\")\n throw new MoneroError(resp.status);\n }\n static convertRpcBlockHeader(rpcHeader) {\n if (!rpcHeader)\n return undefined;\n let header = new MoneroBlockHeader();\n for (let key of Object.keys(rpcHeader)) {\n let val = rpcHeader[key];\n if (key === \"block_size\")\n GenUtils.safeSet(header, header.getSize, header.setSize, val);\n else if (key === \"depth\")\n GenUtils.safeSet(header, header.getDepth, header.setDepth, val);\n else if (key === \"difficulty\") { } // handled by wide_difficulty\n else if (key === \"cumulative_difficulty\") { } // handled by wide_cumulative_difficulty\n else if (key === \"difficulty_top64\") { } // handled by wide_difficulty\n else if (key === \"cumulative_difficulty_top64\") { } // handled by wide_cumulative_difficulty\n else if (key === \"wide_difficulty\")\n header.setDifficulty(GenUtils.reconcile(header.getDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val)));\n else if (key === \"wide_cumulative_difficulty\")\n header.setCumulativeDifficulty(GenUtils.reconcile(header.getCumulativeDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val)));\n else if (key === \"hash\")\n GenUtils.safeSet(header, header.getHash, header.setHash, val);\n else if (key === \"height\")\n GenUtils.safeSet(header, header.getHeight, header.setHeight, val);\n else if (key === \"major_version\")\n GenUtils.safeSet(header, header.getMajorVersion, header.setMajorVersion, val);\n else if (key === \"minor_version\")\n GenUtils.safeSet(header, header.getMinorVersion, header.setMinorVersion, val);\n else if (key === \"nonce\")\n GenUtils.safeSet(header, header.getNonce, header.setNonce, val);\n else if (key === \"num_txes\")\n GenUtils.safeSet(header, header.getNumTxs, header.setNumTxs, val);\n else if (key === \"orphan_status\")\n GenUtils.safeSet(header, header.getOrphanStatus, header.setOrphanStatus, val);\n else if (key === \"prev_hash\" || key === \"prev_id\")\n GenUtils.safeSet(header, header.getPrevHash, header.setPrevHash, val);\n else if (key === \"reward\")\n GenUtils.safeSet(header, header.getReward, header.setReward, BigInt(val));\n else if (key === \"timestamp\")\n GenUtils.safeSet(header, header.getTimestamp, header.setTimestamp, val);\n else if (key === \"block_weight\")\n GenUtils.safeSet(header, header.getWeight, header.setWeight, val);\n else if (key === \"long_term_weight\")\n GenUtils.safeSet(header, header.getLongTermWeight, header.setLongTermWeight, val);\n else if (key === \"pow_hash\")\n GenUtils.safeSet(header, header.getPowHash, header.setPowHash, val === \"\" ? undefined : val);\n else if (key === \"tx_hashes\") { } // used in block model, not header model\n else if (key === \"miner_tx\") { } // used in block model, not header model\n else if (key === \"miner_tx_hash\")\n header.setMinerTxHash(val);\n else\n console.log(\"WARNING: ignoring unexpected block header field: '\" + key + \"': \" + val);\n }\n return header;\n }\n static convertRpcBlock(rpcBlock) {\n // build block\n let block = new MoneroBlock(MoneroDaemonRpc.convertRpcBlockHeader(rpcBlock.block_header ? rpcBlock.block_header : rpcBlock));\n block.setHex(rpcBlock.blob);\n block.setTxHashes(rpcBlock.tx_hashes === undefined ? [] : rpcBlock.tx_hashes);\n // build miner tx\n let rpcMinerTx = rpcBlock.json ? JSON.parse(rpcBlock.json).miner_tx : rpcBlock.miner_tx; // may need to be parsed from json\n let minerTx = new MoneroTx();\n block.setMinerTx(minerTx);\n minerTx.setIsConfirmed(true);\n minerTx.setInTxPool(false);\n minerTx.setIsMinerTx(true);\n MoneroDaemonRpc.convertRpcTx(rpcMinerTx, minerTx);\n return block;\n }\n /**\n * Transfers RPC tx fields to a given MoneroTx without overwriting previous values.\n *\n * TODO: switch from safe set\n *\n * @param rpcTx - RPC map containing transaction fields\n * @param tx - MoneroTx to populate with values (optional)\n * @return tx - same tx that was passed in or a new one if none given\n */\n static convertRpcTx(rpcTx, tx) {\n if (rpcTx === undefined)\n return undefined;\n if (tx === undefined)\n tx = new MoneroTx();\n // initialize from rpc map\n let header;\n for (let key of Object.keys(rpcTx)) {\n let val = rpcTx[key];\n if (key === \"tx_hash\" || key === \"id_hash\")\n GenUtils.safeSet(tx, tx.getHash, tx.setHash, val);\n else if (key === \"block_timestamp\") {\n if (!header)\n header = new MoneroBlockHeader();\n GenUtils.safeSet(header, header.getTimestamp, header.setTimestamp, val);\n }\n else if (key === \"block_height\") {\n if (!header)\n header = new MoneroBlockHeader();\n GenUtils.safeSet(header, header.getHeight, header.setHeight, val);\n }\n else if (key === \"last_relayed_time\")\n GenUtils.safeSet(tx, tx.getLastRelayedTimestamp, tx.setLastRelayedTimestamp, val);\n else if (key === \"receive_time\" || key === \"received_timestamp\")\n GenUtils.safeSet(tx, tx.getReceivedTimestamp, tx.setReceivedTimestamp, val);\n else if (key === \"confirmations\")\n GenUtils.safeSet(tx, tx.getNumConfirmations, tx.setNumConfirmations, val);\n else if (key === \"in_pool\") {\n GenUtils.safeSet(tx, tx.getIsConfirmed, tx.setIsConfirmed, !val);\n GenUtils.safeSet(tx, tx.getInTxPool, tx.setInTxPool, val);\n }\n else if (key === \"double_spend_seen\")\n GenUtils.safeSet(tx, tx.getIsDoubleSpendSeen, tx.setIsDoubleSpendSeen, val);\n else if (key === \"version\")\n GenUtils.safeSet(tx, tx.getVersion, tx.setVersion, val);\n else if (key === \"extra\") {\n if (typeof val === \"string\")\n console.log(\"WARNING: extra field as string not being asigned to int[]: \" + key + \": \" + val); // TODO: how to set string to int[]? - or, extra is string which can encode int[]\n else\n GenUtils.safeSet(tx, tx.getExtra, tx.setExtra, new Uint8Array(val));\n }\n else if (key === \"vin\") {\n if (val.length !== 1 || !val[0].gen) { // ignore miner input TODO: why?\n tx.setInputs(val.map(rpcVin => MoneroDaemonRpc.convertRpcOutput(rpcVin, tx)));\n }\n }\n else if (key === \"vout\")\n tx.setOutputs(val.map(rpcOutput => MoneroDaemonRpc.convertRpcOutput(rpcOutput, tx)));\n else if (key === \"rct_signatures\") {\n GenUtils.safeSet(tx, tx.getRctSignatures, tx.setRctSignatures, val);\n if (val.txnFee)\n GenUtils.safeSet(tx, tx.getFee, tx.setFee, BigInt(val.txnFee));\n }\n else if (key === \"rctsig_prunable\")\n GenUtils.safeSet(tx, tx.getRctSigPrunable, tx.setRctSigPrunable, val);\n else if (key === \"unlock_time\")\n GenUtils.safeSet(tx, tx.getUnlockTime, tx.setUnlockTime, val);\n else if (key === \"as_json\" || key === \"tx_json\") { } // handled last so tx is as initialized as possible\n else if (key === \"as_hex\" || key === \"tx_blob\")\n GenUtils.safeSet(tx, tx.getFullHex, tx.setFullHex, val ? val : undefined);\n else if (key === \"blob_size\")\n GenUtils.safeSet(tx, tx.getSize, tx.setSize, val);\n else if (key === \"weight\")\n GenUtils.safeSet(tx, tx.getWeight, tx.setWeight, val);\n else if (key === \"fee\")\n GenUtils.safeSet(tx, tx.getFee, tx.setFee, BigInt(val));\n else if (key === \"relayed\")\n GenUtils.safeSet(tx, tx.getIsRelayed, tx.setIsRelayed, val);\n else if (key === \"output_indices\")\n GenUtils.safeSet(tx, tx.getOutputIndices, tx.setOutputIndices, val);\n else if (key === \"do_not_relay\")\n GenUtils.safeSet(tx, tx.getRelay, tx.setRelay, !val);\n else if (key === \"kept_by_block\")\n GenUtils.safeSet(tx, tx.getIsKeptByBlock, tx.setIsKeptByBlock, val);\n else if (key === \"signatures\")\n GenUtils.safeSet(tx, tx.getSignatures, tx.setSignatures, val);\n else if (key === \"last_failed_height\") {\n if (val === 0)\n GenUtils.safeSet(tx, tx.getIsFailed, tx.setIsFailed, false);\n else {\n GenUtils.safeSet(tx, tx.getIsFailed, tx.setIsFailed, true);\n GenUtils.safeSet(tx, tx.getLastFailedHeight, tx.setLastFailedHeight, val);\n }\n }\n else if (key === \"last_failed_id_hash\") {\n if (val === MoneroDaemonRpc.DEFAULT_ID)\n GenUtils.safeSet(tx, tx.getIsFailed, tx.setIsFailed, false);\n else {\n GenUtils.safeSet(tx, tx.getIsFailed, tx.setIsFailed, true);\n GenUtils.safeSet(tx, tx.getLastFailedHash, tx.setLastFailedHash, val);\n }\n }\n else if (key === \"max_used_block_height\")\n GenUtils.safeSet(tx, tx.getMaxUsedBlockHeight, tx.setMaxUsedBlockHeight, val);\n else if (key === \"max_used_block_id_hash\")\n GenUtils.safeSet(tx, tx.getMaxUsedBlockHash, tx.setMaxUsedBlockHash, val);\n else if (key === \"prunable_hash\")\n GenUtils.safeSet(tx, tx.getPrunableHash, tx.setPrunableHash, val ? val : undefined);\n else if (key === \"prunable_as_hex\")\n GenUtils.safeSet(tx, tx.getPrunableHex, tx.setPrunableHex, val ? val : undefined);\n else if (key === \"pruned_as_hex\")\n GenUtils.safeSet(tx, tx.getPrunedHex, tx.setPrunedHex, val ? val : undefined);\n else\n console.log(\"WARNING: ignoring unexpected field in rpc tx: \" + key + \": \" + val);\n }\n // link block and tx\n if (header)\n tx.setBlock(new MoneroBlock(header).setTxs([tx]));\n // TODO monerod: unconfirmed txs misreport block height and timestamp?\n if (tx.getBlock() && tx.getBlock().getHeight() !== undefined && tx.getBlock().getHeight() === tx.getBlock().getTimestamp()) {\n tx.setBlock(undefined);\n tx.setIsConfirmed(false);\n }\n // initialize remaining known fields\n if (tx.getIsConfirmed()) {\n GenUtils.safeSet(tx, tx.getIsRelayed, tx.setIsRelayed, true);\n GenUtils.safeSet(tx, tx.getRelay, tx.setRelay, true);\n GenUtils.safeSet(tx, tx.getIsFailed, tx.setIsFailed, false);\n }\n else {\n tx.setNumConfirmations(0);\n }\n if (tx.getIsFailed() === undefined)\n tx.setIsFailed(false);\n if (tx.getOutputIndices() && tx.getOutputs()) {\n assert.equal(tx.getOutputs().length, tx.getOutputIndices().length);\n for (let i = 0; i < tx.getOutputs().length; i++) {\n tx.getOutputs()[i].setIndex(tx.getOutputIndices()[i]); // transfer output indices to outputs\n }\n }\n if (rpcTx.as_json)\n MoneroDaemonRpc.convertRpcTx(JSON.parse(rpcTx.as_json), tx);\n if (rpcTx.tx_json)\n MoneroDaemonRpc.convertRpcTx(JSON.parse(rpcTx.tx_json), tx);\n if (!tx.getIsRelayed())\n tx.setLastRelayedTimestamp(undefined); // TODO monerod: returns last_relayed_timestamp despite relayed: false, self inconsistent\n // return built transaction\n return tx;\n }\n static convertRpcOutput(rpcOutput, tx) {\n let output = new MoneroOutput();\n output.setTx(tx);\n for (let key of Object.keys(rpcOutput)) {\n let val = rpcOutput[key];\n if (key === \"gen\")\n throw new MoneroError(\"Output with 'gen' from daemon rpc is miner tx which we ignore (i.e. each miner input is undefined)\");\n else if (key === \"key\") {\n GenUtils.safeSet(output, output.getAmount, output.setAmount, BigInt(val.amount));\n GenUtils.safeSet(output, output.getKeyImage, output.setKeyImage, new MoneroKeyImage(val.k_image));\n GenUtils.safeSet(output, output.getRingOutputIndices, output.setRingOutputIndices, val.key_offsets);\n }\n else if (key === \"amount\")\n GenUtils.safeSet(output, output.getAmount, output.setAmount, BigInt(val));\n else if (key === \"target\") {\n let pubKey = val.key === undefined ? val.tagged_key.key : val.key; // TODO (monerod): rpc json uses {tagged_key={key=...}}, binary blocks use {key=...}\n GenUtils.safeSet(output, output.getStealthPublicKey, output.setStealthPublicKey, pubKey);\n }\n else\n console.log(\"WARNING: ignoring unexpected field output: \" + key + \": \" + val);\n }\n return output;\n }\n static convertRpcBlockTemplate(rpcTemplate) {\n let template = new MoneroBlockTemplate();\n for (let key of Object.keys(rpcTemplate)) {\n let val = rpcTemplate[key];\n if (key === \"blockhashing_blob\")\n template.setBlockHashingBlob(val);\n else if (key === \"blocktemplate_blob\")\n template.setBlockTemplateBlob(val);\n else if (key === \"expected_reward\")\n template.setExpectedReward(val);\n else if (key === \"difficulty\") { } // handled by wide_difficulty\n else if (key === \"difficulty_top64\") { } // handled by wide_difficulty\n else if (key === \"wide_difficulty\")\n template.setDifficulty(GenUtils.reconcile(template.getDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val)));\n else if (key === \"height\")\n template.setHeight(val);\n else if (key === \"prev_hash\")\n template.setPrevHash(val);\n else if (key === \"reserved_offset\")\n template.setReservedOffset(val);\n else if (key === \"status\") { } // handled elsewhere\n else if (key === \"untrusted\") { } // handled elsewhere\n else if (key === \"seed_height\")\n template.setSeedHeight(val);\n else if (key === \"seed_hash\")\n template.setSeedHash(val);\n else if (key === \"next_seed_hash\")\n template.setNextSeedHash(val);\n else\n console.log(\"WARNING: ignoring unexpected field in block template: \" + key + \": \" + val);\n }\n if (\"\" === template.getNextSeedHash())\n template.setNextSeedHash(undefined);\n return template;\n }\n static convertRpcInfo(rpcInfo) {\n if (!rpcInfo)\n return undefined;\n let info = new MoneroDaemonInfo();\n for (let key of Object.keys(rpcInfo)) {\n let val = rpcInfo[key];\n if (key === \"version\")\n info.setVersion(val);\n else if (key === \"alt_blocks_count\")\n info.setNumAltBlocks(val);\n else if (key === \"block_size_limit\")\n info.setBlockSizeLimit(val);\n else if (key === \"block_size_median\")\n info.setBlockSizeMedian(val);\n else if (key === \"block_weight_limit\")\n info.setBlockWeightLimit(val);\n else if (key === \"block_weight_median\")\n info.setBlockWeightMedian(val);\n else if (key === \"bootstrap_daemon_address\") {\n if (val)\n info.setBootstrapDaemonAddress(val);\n }\n else if (key === \"difficulty\") { } // handled by wide_difficulty\n else if (key === \"cumulative_difficulty\") { } // handled by wide_cumulative_difficulty\n else if (key === \"difficulty_top64\") { } // handled by wide_difficulty\n else if (key === \"cumulative_difficulty_top64\") { } // handled by wide_cumulative_difficulty\n else if (key === \"wide_difficulty\")\n info.setDifficulty(GenUtils.reconcile(info.getDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val)));\n else if (key === \"wide_cumulative_difficulty\")\n info.setCumulativeDifficulty(GenUtils.reconcile(info.getCumulativeDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val)));\n else if (key === \"free_space\")\n info.setFreeSpace(BigInt(val));\n else if (key === \"database_size\")\n info.setDatabaseSize(val);\n else if (key === \"grey_peerlist_size\")\n info.setNumOfflinePeers(val);\n else if (key === \"height\")\n info.setHeight(val);\n else if (key === \"height_without_bootstrap\")\n info.setHeightWithoutBootstrap(val);\n else if (key === \"incoming_connections_count\")\n info.setNumIncomingConnections(val);\n else if (key === \"offline\")\n info.setIsOffline(val);\n else if (key === \"outgoing_connections_count\")\n info.setNumOutgoingConnections(val);\n else if (key === \"rpc_connections_count\")\n info.setNumRpcConnections(val);\n else if (key === \"start_time\")\n info.setStartTimestamp(val);\n else if (key === \"adjusted_time\")\n info.setAdjustedTimestamp(val);\n else if (key === \"status\") { } // handled elsewhere\n else if (key === \"target\")\n info.setTarget(val);\n else if (key === \"target_height\")\n info.setTargetHeight(val);\n else if (key === \"top_block_hash\")\n info.setTopBlockHash(val);\n else if (key === \"tx_count\")\n info.setNumTxs(val);\n else if (key === \"tx_pool_size\")\n info.setNumTxsPool(val);\n else if (key === \"untrusted\") { } // handled elsewhere\n else if (key === \"was_bootstrap_ever_used\")\n info.setWasBootstrapEverUsed(val);\n else if (key === \"white_peerlist_size\")\n info.setNumOnlinePeers(val);\n else if (key === \"update_available\")\n info.setUpdateAvailable(val);\n else if (key === \"nettype\")\n GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.parse(val));\n else if (key === \"mainnet\") {\n if (val)\n GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.MAINNET);\n }\n else if (key === \"testnet\") {\n if (val)\n GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.TESTNET);\n }\n else if (key === \"stagenet\") {\n if (val)\n GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.STAGENET);\n }\n else if (key === \"credits\")\n info.setCredits(BigInt(val));\n else if (key === \"top_block_hash\" || key === \"top_hash\")\n info.setTopBlockHash(GenUtils.reconcile(info.getTopBlockHash(), \"\" === val ? undefined : val));\n else if (key === \"busy_syncing\")\n info.setIsBusySyncing(val);\n else if (key === \"synchronized\")\n info.setIsSynchronized(val);\n else if (key === \"restricted\")\n info.setIsRestricted(val);\n else\n console.log(\"WARNING: Ignoring unexpected info field: \" + key + \": \" + val);\n }\n return info;\n }\n /**\n * Initializes sync info from RPC sync info.\n *\n * @param rpcSyncInfo - rpc map to initialize the sync info from\n * @return {MoneroDaemonSyncInfo} is sync info initialized from the map\n */\n static convertRpcSyncInfo(rpcSyncInfo) {\n let syncInfo = new MoneroDaemonSyncInfo();\n for (let key of Object.keys(rpcSyncInfo)) {\n let val = rpcSyncInfo[key];\n if (key === \"height\")\n syncInfo.setHeight(val);\n else if (key === \"peers\") {\n syncInfo.setPeers([]);\n let rpcConnections = val;\n for (let rpcConnection of rpcConnections) {\n syncInfo.getPeers().push(MoneroDaemonRpc.convertRpcConnection(rpcConnection.info));\n }\n }\n else if (key === \"spans\") {\n syncInfo.setSpans([]);\n let rpcSpans = val;\n for (let rpcSpan of rpcSpans) {\n syncInfo.getSpans().push(MoneroDaemonRpc.convertRpcConnectionSpan(rpcSpan));\n }\n }\n else if (key === \"status\") { } // handled elsewhere\n else if (key === \"target_height\")\n syncInfo.setTargetHeight(val);\n else if (key === \"next_needed_pruning_seed\")\n syncInfo.setNextNeededPruningSeed(val);\n else if (key === \"overview\") { // this returns [] without pruning\n let overview;\n try {\n overview = JSON.parse(val);\n if (overview !== undefined && overview.length > 0)\n console.error(\"Ignoring non-empty 'overview' field (not implemented): \" + overview); // TODO\n }\n catch (e) {\n console.error(\"Failed to parse 'overview' field: \" + overview + \": \" + e.message);\n }\n }\n else if (key === \"credits\")\n syncInfo.setCredits(BigInt(val));\n else if (key === \"top_hash\")\n syncInfo.setTopBlockHash(\"\" === val ? undefined : val);\n else if (key === \"untrusted\") { } // handled elsewhere\n else\n console.log(\"WARNING: ignoring unexpected field in sync info: \" + key + \": \" + val);\n }\n return syncInfo;\n }\n static convertRpcHardForkInfo(rpcHardForkInfo) {\n let info = new MoneroHardForkInfo();\n for (let key of Object.keys(rpcHardForkInfo)) {\n let val = rpcHardForkInfo[key];\n if (key === \"earliest_height\")\n info.setEarliestHeight(val);\n else if (key === \"enabled\")\n info.setIsEnabled(val);\n else if (key === \"state\")\n info.setState(val);\n else if (key === \"status\") { } // handled elsewhere\n else if (key === \"untrusted\") { } // handled elsewhere\n else if (key === \"threshold\")\n info.setThreshold(val);\n else if (key === \"version\")\n info.setVersion(val);\n else if (key === \"votes\")\n info.setNumVotes(val);\n else if (key === \"voting\")\n info.setVoting(val);\n else if (key === \"window\")\n info.setWindow(val);\n else if (key === \"credits\")\n info.setCredits(BigInt(val));\n else if (key === \"top_hash\")\n info.setTopBlockHash(\"\" === val ? undefined : val);\n else\n console.log(\"WARNING: ignoring unexpected field in hard fork info: \" + key + \": \" + val);\n }\n return info;\n }\n static convertRpcConnectionSpan(rpcConnectionSpan) {\n let span = new MoneroConnectionSpan();\n for (let key of Object.keys(rpcConnectionSpan)) {\n let val = rpcConnectionSpan[key];\n if (key === \"connection_id\")\n span.setConnectionId(val);\n else if (key === \"nblocks\")\n span.setNumBlocks(val);\n else if (key === \"rate\")\n span.setRate(val);\n else if (key === \"remote_address\") {\n if (val !== \"\")\n span.setRemoteAddress(val);\n }\n else if (key === \"size\")\n span.setSize(val);\n else if (key === \"speed\")\n span.setSpeed(val);\n else if (key === \"start_block_height\")\n span.setStartHeight(val);\n else\n console.log(\"WARNING: ignoring unexpected field in daemon connection span: \" + key + \": \" + val);\n }\n return span;\n }\n static convertRpcOutputHistogramEntry(rpcEntry) {\n let entry = new MoneroOutputHistogramEntry();\n for (let key of Object.keys(rpcEntry)) {\n let val = rpcEntry[key];\n if (key === \"amount\")\n entry.setAmount(BigInt(val));\n else if (key === \"total_instances\")\n entry.setNumInstances(val);\n else if (key === \"unlocked_instances\")\n entry.setNumUnlockedInstances(val);\n else if (key === \"recent_instances\")\n entry.setNumRecentInstances(val);\n else\n console.log(\"WARNING: ignoring unexpected field in output histogram: \" + key + \": \" + val);\n }\n return entry;\n }\n static convertRpcSubmitTxResult(rpcResult) {\n assert(rpcResult);\n let result = new MoneroSubmitTxResult();\n for (let key of Object.keys(rpcResult)) {\n let val = rpcResult[key];\n if (key === \"double_spend\")\n result.setIsDoubleSpendSeen(val);\n else if (key === \"fee_too_low\")\n result.setIsFeeTooLow(val);\n else if (key === \"invalid_input\")\n result.setHasInvalidInput(val);\n else if (key === \"invalid_output\")\n result.setHasInvalidOutput(val);\n else if (key === \"too_few_outputs\")\n result.setHasTooFewOutputs(val);\n else if (key === \"low_mixin\")\n result.setIsMixinTooLow(val);\n else if (key === \"not_relayed\")\n result.setIsRelayed(!val);\n else if (key === \"overspend\")\n result.setIsOverspend(val);\n else if (key === \"reason\")\n result.setReason(val === \"\" ? undefined : val);\n else if (key === \"too_big\")\n result.setIsTooBig(val);\n else if (key === \"sanity_check_failed\")\n result.setSanityCheckFailed(val);\n else if (key === \"credits\")\n result.setCredits(BigInt(val));\n else if (key === \"status\" || key === \"untrusted\") { } // handled elsewhere\n else if (key === \"top_hash\")\n result.setTopBlockHash(\"\" === val ? undefined : val);\n else if (key === \"tx_extra_too_big\")\n result.setIsTxExtraTooBig(val);\n else if (key === \"nonzero_unlock_time\")\n result.setIsNonzeroUnlockTime(val);\n else\n console.log(\"WARNING: ignoring unexpected field in submit tx hex result: \" + key + \": \" + val);\n }\n return result;\n }\n static convertRpcTxPoolStats(rpcStats) {\n assert(rpcStats);\n let stats = new MoneroTxPoolStats();\n for (let key of Object.keys(rpcStats)) {\n let val = rpcStats[key];\n if (key === \"bytes_max\")\n stats.setBytesMax(val);\n else if (key === \"bytes_med\")\n stats.setBytesMed(val);\n else if (key === \"bytes_min\")\n stats.setBytesMin(val);\n else if (key === \"bytes_total\")\n stats.setBytesTotal(val);\n else if (key === \"histo_98pc\")\n stats.setHisto98pc(val);\n else if (key === \"num_10m\")\n stats.setNum10m(val);\n else if (key === \"num_double_spends\")\n stats.setNumDoubleSpends(val);\n else if (key === \"num_failing\")\n stats.setNumFailing(val);\n else if (key === \"num_not_relayed\")\n stats.setNumNotRelayed(val);\n else if (key === \"oldest\")\n stats.setOldestTimestamp(val);\n else if (key === \"txs_total\")\n stats.setNumTxs(val);\n else if (key === \"fee_total\")\n stats.setFeeTotal(BigInt(val));\n else if (key === \"histo\") {\n stats.setHisto(new Map());\n for (let elem of val)\n stats.getHisto().set(elem.bytes, elem.txs);\n }\n else\n console.log(\"WARNING: ignoring unexpected field in tx pool stats: \" + key + \": \" + val);\n }\n // uninitialize some stats if not applicable\n if (stats.getHisto98pc() === 0)\n stats.setHisto98pc(undefined);\n if (stats.getNumTxs() === 0) {\n stats.setBytesMin(undefined);\n stats.setBytesMed(undefined);\n stats.setBytesMax(undefined);\n stats.setHisto98pc(undefined);\n stats.setOldestTimestamp(undefined);\n }\n return stats;\n }\n static convertRpcAltChain(rpcChain) {\n assert(rpcChain);\n let chain = new MoneroAltChain();\n for (let key of Object.keys(rpcChain)) {\n let val = rpcChain[key];\n if (key === \"block_hash\") { } // using block_hashes instead\n else if (key === \"difficulty\") { } // handled by wide_difficulty\n else if (key === \"difficulty_top64\") { } // handled by wide_difficulty\n else if (key === \"wide_difficulty\")\n chain.setDifficulty(GenUtils.reconcile(chain.getDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val)));\n else if (key === \"height\")\n chain.setHeight(val);\n else if (key === \"length\")\n chain.setLength(val);\n else if (key === \"block_hashes\")\n chain.setBlockHashes(val);\n else if (key === \"main_chain_parent_block\")\n chain.setMainChainParentBlockHash(val);\n else\n console.log(\"WARNING: ignoring unexpected field in alternative chain: \" + key + \": \" + val);\n }\n return chain;\n }\n static convertRpcPeer(rpcPeer) {\n assert(rpcPeer);\n let peer = new MoneroPeer();\n for (let key of Object.keys(rpcPeer)) {\n let val = rpcPeer[key];\n if (key === \"host\")\n peer.setHost(val);\n else if (key === \"id\")\n peer.setId(\"\" + val); // TODO monero-wallet-rpc: peer id is BigInt but string in `get_connections`\n else if (key === \"ip\") { } // host used instead which is consistently a string\n else if (key === \"last_seen\")\n peer.setLastSeenTimestamp(val);\n else if (key === \"port\")\n peer.setPort(val);\n else if (key === \"rpc_port\")\n peer.setRpcPort(val);\n else if (key === \"pruning_seed\")\n peer.setPruningSeed(val);\n else if (key === \"rpc_credits_per_hash\")\n peer.setRpcCreditsPerHash(BigInt(val));\n else\n console.log(\"WARNING: ignoring unexpected field in rpc peer: \" + key + \": \" + val);\n }\n return peer;\n }\n static convertRpcConnection(rpcConnection) {\n let peer = new MoneroPeer();\n peer.setIsOnline(true);\n for (let key of Object.keys(rpcConnection)) {\n let val = rpcConnection[key];\n if (key === \"address\")\n peer.setAddress(val);\n else if (key === \"avg_download\")\n peer.setAvgDownload(val);\n else if (key === \"avg_upload\")\n peer.setAvgUpload(val);\n else if (key === \"connection_id\")\n peer.setId(val);\n else if (key === \"current_download\")\n peer.setCurrentDownload(val);\n else if (key === \"current_upload\")\n peer.setCurrentUpload(val);\n else if (key === \"height\")\n peer.setHeight(val);\n else if (key === \"host\")\n peer.setHost(val);\n else if (key === \"ip\") { } // host used instead which is consistently a string\n else if (key === \"incoming\")\n peer.setIsIncoming(val);\n else if (key === \"live_time\")\n peer.setLiveTime(val);\n else if (key === \"local_ip\")\n peer.setIsLocalIp(val);\n else if (key === \"localhost\")\n peer.setIsLocalHost(val);\n else if (key === \"peer_id\")\n peer.setId(val);\n else if (key === \"port\")\n peer.setPort(parseInt(val));\n else if (key === \"rpc_port\")\n peer.setRpcPort(val);\n else if (key === \"recv_count\")\n peer.setNumReceives(val);\n else if (key === \"recv_idle_time\")\n peer.setReceiveIdleTime(val);\n else if (key === \"send_count\")\n peer.setNumSends(val);\n else if (key === \"send_idle_time\")\n peer.setSendIdleTime(val);\n else if (key === \"state\")\n peer.setState(val);\n else if (key === \"support_flags\")\n peer.setNumSupportFlags(val);\n else if (key === \"pruning_seed\")\n peer.setPruningSeed(val);\n else if (key === \"rpc_credits_per_hash\")\n peer.setRpcCreditsPerHash(BigInt(val));\n else if (key === \"address_type\")\n peer.setType(val);\n else\n console.log(\"WARNING: ignoring unexpected field in peer: \" + key + \": \" + val);\n }\n return peer;\n }\n static convertToRpcBan(ban) {\n let rpcBan = {};\n rpcBan.host = ban.getHost();\n rpcBan.ip = ban.getIp();\n rpcBan.ban = ban.getIsBanned();\n rpcBan.seconds = ban.getSeconds();\n return rpcBan;\n }\n static convertRpcMiningStatus(rpcStatus) {\n let status = new MoneroMiningStatus();\n status.setIsActive(rpcStatus.active);\n status.setSpeed(rpcStatus.speed);\n status.setNumThreads(rpcStatus.threads_count);\n if (rpcStatus.active) {\n status.setAddress(rpcStatus.address);\n status.setIsBackground(rpcStatus.is_background_mining_enabled);\n }\n return status;\n }\n static convertRpcUpdateCheckResult(rpcResult) {\n assert(rpcResult);\n let result = new MoneroDaemonUpdateCheckResult();\n for (let key of Object.keys(rpcResult)) {\n let val = rpcResult[key];\n if (key === \"auto_uri\")\n result.setAutoUri(val);\n else if (key === \"hash\")\n result.setHash(val);\n else if (key === \"path\") { } // handled elsewhere\n else if (key === \"status\") { } // handled elsewhere\n else if (key === \"update\")\n result.setIsUpdateAvailable(val);\n else if (key === \"user_uri\")\n result.setUserUri(val);\n else if (key === \"version\")\n result.setVersion(val);\n else if (key === \"untrusted\") { } // handled elsewhere\n else\n console.log(\"WARNING: ignoring unexpected field in rpc check update result: \" + key + \": \" + val);\n }\n if (result.getAutoUri() === \"\")\n result.setAutoUri(undefined);\n if (result.getUserUri() === \"\")\n result.setUserUri(undefined);\n if (result.getVersion() === \"\")\n result.setVersion(undefined);\n if (result.getHash() === \"\")\n result.setHash(undefined);\n return result;\n }\n static convertRpcUpdateDownloadResult(rpcResult) {\n let result = new MoneroDaemonUpdateDownloadResult(MoneroDaemonRpc.convertRpcUpdateCheckResult(rpcResult));\n result.setDownloadPath(rpcResult[\"path\"]);\n if (result.getDownloadPath() === \"\")\n result.setDownloadPath(undefined);\n return result;\n }\n /**\n * Converts a '0x' prefixed hexidecimal string to a bigint.\n *\n * @param {string} hex is the '0x' prefixed hexidecimal string to convert\n * @return {bigint} the hexicedimal converted to decimal\n */\n static prefixedHexToBI(hex) {\n assert(hex.substring(0, 2) === \"0x\");\n return BigInt(hex);\n }\n}\n// static variables\nMoneroDaemonRpc.MAX_REQ_SIZE = \"3000000\";\nMoneroDaemonRpc.DEFAULT_ID = \"0000000000000000000000000000000000000000000000000000000000000000\"; // uninitialized tx or block hash from daemon rpc\nMoneroDaemonRpc.NUM_HEADERS_PER_REQ = 750; // number of headers to fetch and cache per request\nMoneroDaemonRpc.DEFAULT_POLL_PERIOD = 20000; // default interval between polling the daemon in ms\n/**\n * Implements a MoneroDaemon by proxying requests to a worker.\n *\n * @private\n */\nclass MoneroDaemonRpcProxy {\n constructor(daemonId, worker) {\n this.daemonId = daemonId;\n this.worker = worker;\n this.wrappedListeners = [];\n }\n // --------------------------- STATIC UTILITIES -----------------------------\n static async connect(config) {\n let daemonId = GenUtils.getUUID();\n config = Object.assign({}, config.toJson(), { proxyToWorker: false });\n await LibraryUtils.invokeWorker(daemonId, \"connectDaemonRpc\", [config]);\n return new MoneroDaemonRpcProxy(daemonId, await LibraryUtils.getWorker());\n }\n // ---------------------------- INSTANCE METHODS ----------------------------\n async addListener(listener) {\n let wrappedListener = new DaemonWorkerListener(listener);\n let listenerId = wrappedListener.getId();\n LibraryUtils.addWorkerCallback(this.daemonId, \"onBlockHeader_\" + listenerId, [wrappedListener.onBlockHeader, wrappedListener]);\n this.wrappedListeners.push(wrappedListener);\n return this.invokeWorker(\"daemonAddListener\", [listenerId]);\n }\n async removeListener(listener) {\n for (let i = 0; i < this.wrappedListeners.length; i++) {\n if (this.wrappedListeners[i].getListener() === listener) {\n let listenerId = this.wrappedListeners[i].getId();\n await this.invokeWorker(\"daemonRemoveListener\", [listenerId]);\n LibraryUtils.removeWorkerCallback(this.daemonId, \"onBlockHeader_\" + listenerId);\n this.wrappedListeners.splice(i, 1);\n return;\n }\n }\n throw new MoneroError(\"Listener is not registered with daemon\");\n }\n async getListeners() {\n let listeners = [];\n for (let wrappedListener of this.wrappedListeners)\n listeners.push(wrappedListener.getListener());\n return listeners;\n }\n async getRpcConnection() {\n let config = await this.invokeWorker(\"daemonGetRpcConnection\");\n return new MoneroRpcConnection(config);\n }\n async isConnected() {\n return this.invokeWorker(\"daemonIsConnected\");\n }\n async getVersion() {\n let versionJson = await this.invokeWorker(\"daemonGetVersion\");\n return new MoneroVersion(versionJson.number, versionJson.isRelease);\n }\n async isTrusted() {\n return this.invokeWorker(\"daemonIsTrusted\");\n }\n async getHeight() {\n return this.invokeWorker(\"daemonGetHeight\");\n }\n async getBlockHash(height) {\n return this.invokeWorker(\"daemonGetBlockHash\", Array.from(arguments));\n }\n async getBlockTemplate(walletAddress, reserveSize) {\n return new MoneroBlockTemplate(await this.invokeWorker(\"daemonGetBlockTemplate\", Array.from(arguments)));\n }\n async getLastBlockHeader() {\n return new MoneroBlockHeader(await this.invokeWorker(\"daemonGetLastBlockHeader\"));\n }\n async getBlockHeaderByHash(blockHash) {\n return new MoneroBlockHeader(await this.invokeWorker(\"daemonGetBlockHeaderByHash\", Array.from(arguments)));\n }\n async getBlockHeaderByHeight(height) {\n return new MoneroBlockHeader(await this.invokeWorker(\"daemonGetBlockHeaderByHeight\", Array.from(arguments)));\n }\n async getBlockHeadersByRange(startHeight, endHeight) {\n let blockHeadersJson = await this.invokeWorker(\"daemonGetBlockHeadersByRange\", Array.from(arguments));\n let headers = [];\n for (let blockHeaderJson of blockHeadersJson)\n headers.push(new MoneroBlockHeader(blockHeaderJson));\n return headers;\n }\n async getBlockByHash(blockHash) {\n return new MoneroBlock(await this.invokeWorker(\"daemonGetBlockByHash\", Array.from(arguments)), MoneroBlock.DeserializationType.TX);\n }\n async getBlocksByHash(blockHashes, startHeight, prune) {\n let blocksJson = await this.invokeWorker(\"daemonGetBlocksByHash\", Array.from(arguments));\n let blocks = [];\n for (let blockJson of blocksJson)\n blocks.push(new MoneroBlock(blockJson));\n return blocks;\n }\n async getBlockByHeight(height) {\n return new MoneroBlock(await this.invokeWorker(\"daemonGetBlockByHeight\", Array.from(arguments)), MoneroBlock.DeserializationType.TX);\n }\n async getBlocksByHeight(heights) {\n let blocksJson = await this.invokeWorker(\"daemonGetBlocksByHeight\", Array.from(arguments));\n let blocks = [];\n for (let blockJson of blocksJson)\n blocks.push(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX));\n return blocks;\n }\n async getBlocksByRange(startHeight, endHeight) {\n let blocksJson = await this.invokeWorker(\"daemonGetBlocksByRange\", Array.from(arguments));\n let blocks = [];\n for (let blockJson of blocksJson)\n blocks.push(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX));\n return blocks;\n }\n async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) {\n let blocksJson = await this.invokeWorker(\"daemonGetBlocksByRangeChunked\", Array.from(arguments));\n let blocks = [];\n for (let blockJson of blocksJson)\n blocks.push(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX));\n return blocks;\n }\n async getBlockHashes(blockHashes, startHeight) {\n return this.invokeWorker(\"daemonGetBlockHashes\", Array.from(arguments));\n }\n async getTxs(txHashes, prune = false) {\n // deserialize txs from blocks\n let blocks = [];\n for (let blockJson of await this.invokeWorker(\"daemonGetTxs\", Array.from(arguments))) {\n blocks.push(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX));\n }\n // collect txs\n let txs = [];\n for (let block of blocks) {\n for (let tx of block.getTxs()) {\n if (!tx.getIsConfirmed())\n tx.setBlock(undefined);\n txs.push(tx);\n }\n }\n return txs;\n }\n async getTxHexes(txHashes, prune = false) {\n return this.invokeWorker(\"daemonGetTxHexes\", Array.from(arguments));\n }\n async getMinerTxSum(height, numBlocks) {\n return new MoneroMinerTxSum(await this.invokeWorker(\"daemonGetMinerTxSum\", Array.from(arguments)));\n }\n async getFeeEstimate(graceBlocks) {\n return new MoneroFeeEstimate(await this.invokeWorker(\"daemonGetFeeEstimate\", Array.from(arguments)));\n }\n async submitTxHex(txHex, doNotRelay) {\n return new MoneroSubmitTxResult(await this.invokeWorker(\"daemonSubmitTxHex\", Array.from(arguments)));\n }\n async relayTxsByHash(txHashes) {\n return this.invokeWorker(\"daemonRelayTxsByHash\", Array.from(arguments));\n }\n async getTxPool() {\n let blockJson = await this.invokeWorker(\"daemonGetTxPool\");\n let txs = new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX).getTxs();\n for (let tx of txs)\n tx.setBlock(undefined);\n return txs ? txs : [];\n }\n async getTxPoolHashes() {\n return this.invokeWorker(\"daemonGetTxPoolHashes\", Array.from(arguments));\n }\n async getTxPoolBacklog() {\n throw new MoneroError(\"Not implemented\");\n }\n async getTxPoolStats() {\n return new MoneroTxPoolStats(await this.invokeWorker(\"daemonGetTxPoolStats\"));\n }\n async flushTxPool(hashes) {\n return this.invokeWorker(\"daemonFlushTxPool\", Array.from(arguments));\n }\n async getKeyImageSpentStatuses(keyImages) {\n return this.invokeWorker(\"daemonGetKeyImageSpentStatuses\", Array.from(arguments));\n }\n async getOutputs(outputs) {\n throw new MoneroError(\"Not implemented\");\n }\n async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) {\n let entries = [];\n for (let entryJson of await this.invokeWorker(\"daemonGetOutputHistogram\", [amounts, minCount, maxCount, isUnlocked, recentCutoff])) {\n entries.push(new MoneroOutputHistogramEntry(entryJson));\n }\n return entries;\n }\n async getOutputDistribution(amounts, cumulative, startHeight, endHeight) {\n throw new MoneroError(\"Not implemented\");\n }\n async getInfo() {\n return new MoneroDaemonInfo(await this.invokeWorker(\"daemonGetInfo\"));\n }\n async getSyncInfo() {\n return new MoneroDaemonSyncInfo(await this.invokeWorker(\"daemonGetSyncInfo\"));\n }\n async getHardForkInfo() {\n return new MoneroHardForkInfo(await this.invokeWorker(\"daemonGetHardForkInfo\"));\n }\n async getAltChains() {\n let altChains = [];\n for (let altChainJson of await this.invokeWorker(\"daemonGetAltChains\"))\n altChains.push(new MoneroAltChain(altChainJson));\n return altChains;\n }\n async getAltBlockHashes() {\n return this.invokeWorker(\"daemonGetAltBlockHashes\");\n }\n async getDownloadLimit() {\n return this.invokeWorker(\"daemonGetDownloadLimit\");\n }\n async setDownloadLimit(limit) {\n return this.invokeWorker(\"daemonSetDownloadLimit\", Array.from(arguments));\n }\n async resetDownloadLimit() {\n return this.invokeWorker(\"daemonResetDownloadLimit\");\n }\n async getUploadLimit() {\n return this.invokeWorker(\"daemonGetUploadLimit\");\n }\n async setUploadLimit(limit) {\n return this.invokeWorker(\"daemonSetUploadLimit\", Array.from(arguments));\n }\n async resetUploadLimit() {\n return this.invokeWorker(\"daemonResetUploadLimit\");\n }\n async getPeers() {\n let peers = [];\n for (let peerJson of await this.invokeWorker(\"daemonGetPeers\"))\n peers.push(new MoneroPeer(peerJson));\n return peers;\n }\n async getKnownPeers() {\n let peers = [];\n for (let peerJson of await this.invokeWorker(\"daemonGetKnownPeers\"))\n peers.push(new MoneroPeer(peerJson));\n return peers;\n }\n async setOutgoingPeerLimit(limit) {\n return this.invokeWorker(\"daemonSetIncomingPeerLimit\", Array.from(arguments));\n }\n async setIncomingPeerLimit(limit) {\n return this.invokeWorker(\"daemonSetIncomingPeerLimit\", Array.from(arguments));\n }\n async getPeerBans() {\n let bans = [];\n for (let banJson of await this.invokeWorker(\"daemonGetPeerBans\"))\n bans.push(new MoneroBan(banJson));\n return bans;\n }\n async setPeerBans(bans) {\n let bansJson = [];\n for (let ban of bans)\n bansJson.push(ban.toJson());\n return this.invokeWorker(\"daemonSetPeerBans\", [bansJson]);\n }\n async startMining(address, numThreads, isBackground, ignoreBattery) {\n return this.invokeWorker(\"daemonStartMining\", Array.from(arguments));\n }\n async stopMining() {\n await this.invokeWorker(\"daemonStopMining\");\n }\n async getMiningStatus() {\n return new MoneroMiningStatus(await this.invokeWorker(\"daemonGetMiningStatus\"));\n }\n async submitBlocks(blockBlobs) {\n return this.invokeWorker(\"daemonSubmitBlocks\", Array.from(arguments));\n }\n async pruneBlockchain(check) {\n return new MoneroPruneResult(await this.invokeWorker(\"daemonPruneBlockchain\"));\n }\n async checkForUpdate() {\n throw new MoneroError(\"Not implemented\");\n }\n async downloadUpdate(path) {\n throw new MoneroError(\"Not implemented\");\n }\n async stop() {\n while (this.wrappedListeners.length)\n await this.removeListener(this.wrappedListeners[0].getListener());\n return this.invokeWorker(\"daemonStop\");\n }\n async waitForNextBlockHeader() {\n return new MoneroBlockHeader(await this.invokeWorker(\"daemonWaitForNextBlockHeader\"));\n }\n // --------------------------- PRIVATE HELPERS ------------------------------\n // TODO: duplicated with MoneroWalletFullProxy\n async invokeWorker(fnName, args) {\n return LibraryUtils.invokeWorker(this.daemonId, fnName, args);\n }\n}\n/**\n * Polls a Monero daemon for updates and notifies listeners as they occur.\n *\n * @private\n */\nclass DaemonPoller {\n constructor(daemon) {\n let that = this;\n this.daemon = daemon;\n this.looper = new TaskLooper(async function () { await that.poll(); });\n }\n setIsPolling(isPolling) {\n this.isPolling = isPolling;\n if (isPolling)\n this.looper.start(this.daemon.getPollInterval());\n else\n this.looper.stop();\n }\n async poll() {\n try {\n // get latest block header\n let header = await this.daemon.getLastBlockHeader();\n // save first header for comparison\n if (!this.lastHeader) {\n this.lastHeader = await this.daemon.getLastBlockHeader();\n return;\n }\n // compare header to last\n if (header.getHash() !== this.lastHeader.getHash()) {\n this.lastHeader = header;\n await this.announceBlockHeader(header);\n }\n }\n catch (err) {\n console.error(\"Failed to background poll daemon header\");\n console.error(err);\n }\n }\n async announceBlockHeader(header) {\n for (let listener of await this.daemon.getListeners()) {\n try {\n await listener.onBlockHeader(header); // notify listener\n }\n catch (err) {\n console.error(\"Error calling listener on block header\", err);\n }\n }\n }\n}\n/**\n * Internal listener to bridge notifications to external listeners.\n *\n * @private\n */\nclass DaemonWorkerListener {\n constructor(listener) {\n this.id = GenUtils.getUUID();\n this.listener = listener;\n }\n getId() {\n return this.id;\n }\n getListener() {\n return this.listener;\n }\n async onBlockHeader(headerJson) {\n this.listener.onBlockHeader(new MoneroBlockHeader(headerJson));\n }\n}\nexport default MoneroDaemonRpc;\n","import assert from \"assert\";\nimport MoneroDestination from \"./MoneroDestination\";\nimport MoneroError from \"../../common/MoneroError\";\n/**\n * Configures a transaction to send, sweep, or create a payment URI.\n */\nexport default class MoneroTxConfig {\n /**\n *

Generic request to transfer funds from a wallet.

\n *\n *

Example:

\n *\n * \n * let config1 = new MoneroTxConfig({
\n *    accountIndex: 0,
\n *    address: \"59aZULsUF3YN...\",
\n *    amount: 500000n,
\n *    priority: MoneroTxPriority.NORMAL,
\n *    relay: true
\n * });\n *
\n *\n * @param {Partial} [config] - configures the transaction to create (optional)\n * @param {string} [config.address] - single destination address\n * @param {bigint} [config.amount] - single destination amount\n * @param {number} [config.accountIndex] - source account index to transfer funds from\n * @param {number} [config.subaddressIndex] - source subaddress index to transfer funds from\n * @param {number[]} [config.subaddressIndices] - source subaddress indices to transfer funds from\n * @param {boolean} [config.relay] - relay the transaction to peers to commit to the blockchain\n * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL)\n * @param {MoneroDestination[]} [config.destinations] - addresses and amounts in a multi-destination tx\n * @param {number[]} [config.subtractFeeFrom] - list of destination indices to split the transaction fee\n * @param {string} [config.paymentId] - transaction payment ID\n * @param {bigint} [config.unlockTime] - minimum height or timestamp for the transaction to unlock (default 0)\n * @param {string} [config.note] - transaction note saved locally with the wallet\n * @param {string} [config.recipientName] - recipient name saved locally with the wallet\n * @param {boolean} [config.canSplit] - allow funds to be transferred using multiple transactions\n * @param {bigint} [config.belowAmount] - for sweep requests, include outputs below this amount when sweeping wallet, account, subaddress, or all unlocked funds\n * @param {boolean} [config.sweepEachSubaddress] - for sweep requests, sweep each subaddress individually instead of together if true\n * @param {string} [config.keyImage] - key image to sweep (ignored except in sweepOutput() requests)\n */\n constructor(config) {\n Object.assign(this, config);\n // deserialize bigints\n if (this.amount !== undefined && typeof this.amount !== \"bigint\")\n this.amount = BigInt(this.amount);\n if (this.fee !== undefined && typeof this.fee !== \"bigint\")\n this.fee = BigInt(this.fee);\n if (this.belowAmount !== undefined && typeof this.belowAmount !== \"bigint\")\n this.belowAmount = BigInt(this.belowAmount);\n // copy destinations\n if (this.destinations) {\n assert(this.address === undefined && this.amount === undefined, \"Tx configuration may specify destinations or an address/amount but not both\");\n this.setDestinations(this.destinations.map(destination => new MoneroDestination(destination)));\n }\n // alias 'address' and 'amount' to single destination to support e.g. createTx({address: \"...\"})\n if (this.address || this.amount) {\n assert(!this.destinations, \"Tx configuration may specify destinations or an address/amount but not both\");\n this.setAddress(this.address);\n this.setAmount(this.amount);\n delete this.address;\n delete this.amount;\n }\n // alias 'subaddressIndex' to subaddress indices\n if (this.subaddressIndex !== undefined) {\n this.setSubaddressIndices([this.subaddressIndex]);\n delete this.subaddressIndex;\n }\n }\n copy() {\n return new MoneroTxConfig(this);\n }\n toJson() {\n let json = Object.assign({}, this); // copy state\n if (this.getDestinations() !== undefined) {\n json.destinations = [];\n for (let destination of this.getDestinations())\n json.destinations.push(destination.toJson());\n }\n if (this.getFee())\n json.fee = this.getFee().toString();\n if (this.getBelowAmount())\n json.belowAmount = this.getBelowAmount().toString();\n return json;\n }\n /**\n * Set the address of a single-destination configuration.\n *\n * @param {string} address - the address to set for the single destination\n * @return {MoneroTxConfig} this configuration for chaining\n */\n setAddress(address) {\n if (this.destinations !== undefined && this.destinations.length > 1)\n throw new MoneroError(\"Cannot set address because MoneroTxConfig already has multiple destinations\");\n if (this.destinations === undefined || this.destinations.length === 0)\n this.addDestination(new MoneroDestination(address));\n else\n this.destinations[0].setAddress(address);\n return this;\n }\n /**\n * Get the address of a single-destination configuration.\n *\n * @return {string} the address of the single destination\n */\n getAddress() {\n if (this.destinations === undefined || this.destinations.length !== 1)\n throw new MoneroError(\"Cannot get address because MoneroTxConfig does not have exactly one destination\");\n return this.destinations[0].getAddress();\n }\n /**\n * Set the amount of a single-destination configuration.\n *\n * @param {bigint} amount - the amount to set for the single destination\n * @return {MoneroTxConfig} this configuration for chaining\n */\n setAmount(amount) {\n if (amount !== undefined && typeof this.amount !== \"bigint\") {\n if (typeof amount === \"number\")\n throw new MoneroError(\"Destination amount must be bigint or string\");\n try {\n amount = BigInt(amount);\n }\n catch (err) {\n throw new MoneroError(\"Invalid destination amount: \" + amount);\n }\n }\n if (this.destinations !== undefined && this.destinations.length > 1)\n throw new MoneroError(\"Cannot set amount because MoneroTxConfig already has multiple destinations\");\n if (this.destinations === undefined || this.destinations.length === 0)\n this.addDestination(new MoneroDestination(undefined, amount));\n else\n this.destinations[0].setAmount(amount);\n return this;\n }\n /**\n * Get the amount of a single-destination configuration.\n *\n * @return {bigint} the amount of the single destination\n */\n getAmount() {\n if (this.destinations === undefined || this.destinations.length !== 1)\n throw new MoneroError(\"Cannot get amount because MoneroTxConfig does not have exactly one destination\");\n return this.destinations[0].getAmount();\n }\n addDestination(destinationOrAddress, amount) {\n if (typeof destinationOrAddress === \"string\")\n return this.addDestination(new MoneroDestination(destinationOrAddress, amount));\n assert(destinationOrAddress instanceof MoneroDestination);\n if (this.destinations === undefined)\n this.destinations = [];\n this.destinations.push(destinationOrAddress);\n return this;\n }\n getDestinations() {\n return this.destinations;\n }\n setDestinations(destinations) {\n if (arguments.length > 1)\n destinations = Array.from(arguments);\n this.destinations = destinations;\n return this;\n }\n setDestination(destination) {\n return this.setDestinations(destination ? [destination] : undefined);\n }\n getSubtractFeeFrom() {\n return this.subtractFeeFrom;\n }\n setSubtractFeeFrom(destinationIndices) {\n if (arguments.length > 1)\n destinationIndices = Array.from(arguments);\n this.subtractFeeFrom = destinationIndices;\n return this;\n }\n getPaymentId() {\n return this.paymentId;\n }\n setPaymentId(paymentId) {\n this.paymentId = paymentId;\n return this;\n }\n getPriority() {\n return this.priority;\n }\n setPriority(priority) {\n this.priority = priority;\n return this;\n }\n getFee() {\n return this.fee;\n }\n setFee(fee) {\n this.fee = fee;\n return this;\n }\n getAccountIndex() {\n return this.accountIndex;\n }\n setAccountIndex(accountIndex) {\n this.accountIndex = accountIndex;\n return this;\n }\n setSubaddressIndex(subaddressIndex) {\n this.setSubaddressIndices([subaddressIndex]);\n return this;\n }\n getSubaddressIndices() {\n return this.subaddressIndices;\n }\n setSubaddressIndices(subaddressIndices) {\n if (arguments.length > 1)\n subaddressIndices = Array.from(arguments);\n this.subaddressIndices = subaddressIndices;\n return this;\n }\n getRelay() {\n return this.relay;\n }\n setRelay(relay) {\n this.relay = relay;\n return this;\n }\n getCanSplit() {\n return this.canSplit;\n }\n setCanSplit(canSplit) {\n this.canSplit = canSplit;\n return this;\n }\n getNote() {\n return this.note;\n }\n setNote(note) {\n this.note = note;\n return this;\n }\n getRecipientName() {\n return this.recipientName;\n }\n setRecipientName(recipientName) {\n this.recipientName = recipientName;\n return this;\n }\n // --------------------------- SPECIFIC TO SWEEP ----------------------------\n getBelowAmount() {\n return this.belowAmount;\n }\n setBelowAmount(belowAmount) {\n this.belowAmount = belowAmount;\n return this;\n }\n getSweepEachSubaddress() {\n return this.sweepEachSubaddress;\n }\n setSweepEachSubaddress(sweepEachSubaddress) {\n this.sweepEachSubaddress = sweepEachSubaddress;\n return this;\n }\n /**\n * Get the key image hex of the output to sweep.\n *\n * return {string} is the key image hex of the output to sweep\n */\n getKeyImage() {\n return this.keyImage;\n }\n /**\n * Set the key image hex of the output to sweep.\n *\n * @param {string} keyImage is the key image hex of the output to sweep\n */\n setKeyImage(keyImage) {\n this.keyImage = keyImage;\n return this;\n }\n}\n","import MoneroNetworkType from \"../../daemon/model/MoneroNetworkType\";\nimport MoneroRpcConnection from \"../../common/MoneroRpcConnection\";\n/**\n * Configuration to create a Monero wallet.\n */\nexport default class MoneroWalletConfig {\n /**\n * Construct a configuration to open or create a wallet.\n *\n * @param {Partial} [config] - MoneroWalletConfig or equivalent config object\n * @param {string} [config.path] - path of the wallet to open or create\n * @param {string} [config.password] - password of the wallet to open\n * @param {string|number} [config.networkType] - network type of the wallet to open (one of \"mainnet\", \"testnet\", \"stagenet\" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)\n * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given)\n * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed phrase\n * @param {boolean} [config.isMultisig] - restore multisig wallet from seed\n * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys)\n * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional)\n * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional)\n * @param {number} [config.restoreHeight] - block height to start scanning from (defaults to 0 unless generating random wallet)\n * @param {string} [config.language] - language of the wallet's seed phrase (defaults to \"English\" or auto-detected)\n * @param {number} [config.accountLookahead] - number of accounts to scan (optional)\n * @param {number} [config.subaddressLookahead] - number of subaddresses to scan per account (optional)\n * @param {string|Partial} [config.server] - uri or MoneroRpcConnection to the wallet's server (optional)\n * @param {MoneroConnectionManager} [config.connectionManager] - manage connections to monerod (optional)\n * @param {boolean} [config.rejectUnauthorized] - reject self-signed server certificates if true (default true)\n * @param {Uint8Array} [config.keysData] - wallet keys data to open (optional)\n * @param {Uint8Array} [config.cacheData] - wallet cache data to open (optional)\n * @param {boolean} [config.proxyToWorker] - proxies wallet operations to a worker in order to not block the main thread (default true)\n * @param {any} [config.fs] - file system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser)\n * @param {boolean} [config.saveCurrent] - specifies if the current RPC wallet should be saved before being closed\n * @param {number} [config.accountLookahead] - number of accounts to scan (optional)\n * @param {number} [config.subaddressLookahead] - number of subaddresses to scan per account (optional)\n * @param {string[]} [config.cmd] - command to start wallet daemon (optional)\n */\n constructor(config) {\n Object.assign(this, config);\n // normalize config\n if (this.server)\n this.setServer(this.server);\n this.setProxyToWorker(this.proxyToWorker);\n if (this.networkType !== undefined)\n this.networkType = MoneroNetworkType.from(this.networkType);\n }\n copy() {\n return new MoneroWalletConfig(this);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (json.server)\n json.server = json.server.toJson();\n json.fs = undefined;\n json.connectionManager = undefined;\n return json;\n }\n getPath() {\n return this.path;\n }\n setPath(path) {\n this.path = path;\n return this;\n }\n getPassword() {\n return this.password;\n }\n setPassword(password) {\n this.password = password;\n return this;\n }\n getNetworkType() {\n return this.networkType;\n }\n setNetworkType(networkTypeOrStr) {\n this.networkType = networkTypeOrStr === undefined ? undefined : MoneroNetworkType.from(networkTypeOrStr);\n return this;\n }\n getServer() {\n return this.server;\n }\n setServer(server) {\n if (server && !(server instanceof MoneroRpcConnection))\n server = new MoneroRpcConnection(server);\n this.server = server;\n return this;\n }\n getConnectionManager() {\n return this.connectionManager;\n }\n setConnectionManager(connectionManager) {\n this.connectionManager = connectionManager;\n return this;\n }\n getSeed() {\n return this.seed;\n }\n setSeed(seed) {\n this.seed = seed;\n return this;\n }\n getSeedOffset() {\n return this.seedOffset;\n }\n setSeedOffset(seedOffset) {\n this.seedOffset = seedOffset;\n return this;\n }\n getIsMultisig() {\n return this.isMultisig;\n }\n setIsMultisig(isMultisig) {\n this.isMultisig = isMultisig;\n return this;\n }\n getPrimaryAddress() {\n return this.primaryAddress;\n }\n setPrimaryAddress(primaryAddress) {\n this.primaryAddress = primaryAddress;\n return this;\n }\n getPrivateViewKey() {\n return this.privateViewKey;\n }\n setPrivateViewKey(privateViewKey) {\n this.privateViewKey = privateViewKey;\n return this;\n }\n getPrivateSpendKey() {\n return this.privateSpendKey;\n }\n setPrivateSpendKey(privateSpendKey) {\n this.privateSpendKey = privateSpendKey;\n return this;\n }\n getRestoreHeight() {\n return this.restoreHeight;\n }\n setRestoreHeight(restoreHeight) {\n this.restoreHeight = restoreHeight;\n return this;\n }\n getLanguage() {\n return this.language;\n }\n setLanguage(language) {\n this.language = language;\n return this;\n }\n getSaveCurrent() {\n return this.saveCurrent;\n }\n setSaveCurrent(saveCurrent) {\n this.saveCurrent = saveCurrent;\n return this;\n }\n getProxyToWorker() {\n return this.proxyToWorker;\n }\n setProxyToWorker(proxyToWorker) {\n this.proxyToWorker = proxyToWorker;\n return this;\n }\n getFs() {\n return this.fs;\n }\n setFs(fs) {\n this.fs = fs;\n return this;\n }\n getKeysData() {\n return this.keysData;\n }\n setKeysData(keysData) {\n this.keysData = keysData;\n return this;\n }\n getCacheData() {\n return this.cacheData;\n }\n setCacheData(cacheData) {\n this.cacheData = cacheData;\n return this;\n }\n getAccountLookahead() {\n return this.accountLookahead;\n }\n setAccountLookahead(accountLookahead) {\n this.accountLookahead = accountLookahead;\n return this;\n }\n getSubaddressLookahead() {\n return this.subaddressLookahead;\n }\n setSubaddressLookahead(subaddressLookahead) {\n this.subaddressLookahead = subaddressLookahead;\n return this;\n }\n}\n","/**\n * Default wallet listener which takes no action on notifications.\n */\nexport default class MoneroWalletListener {\n /**\n * Invoked as the wallet is synchronized.\n *\n * @param {number} height - height of the synced block\n * @param {number} startHeight - starting height of the sync request\n * @param {number} endHeight - ending height of the sync request\n * @param {number} percentDone - sync progress as a percentage\n * @param {string} message - human-readable description of the current progress\n * @return {Promise}\n */\n async onSyncProgress(height, startHeight, endHeight, percentDone, message) { }\n /**\n * Invoked when a new block is added to the chain.\n *\n * @param {number} height - the height of the new block (i.e. the number of blocks before it).\n * @return {Promise}\n */\n async onNewBlock(height) { }\n /**\n * Invoked when the wallet's balances change.\n *\n * @param {bigint} newBalance - new wallet balance\n * @param {bigint} newUnlockedBalance - new unlocked wallet balance\n * @return {Promise}\n */\n async onBalancesChanged(newBalance, newUnlockedBalance) { }\n /**\n * Invoked 3 times per received output: once when unconfirmed, once when confirmed, and\n * once when unlocked.\n *\n * The notified output includes basic fields only, so the output or its transaction should be fetched to get all available fields.\n *\n * @param {MoneroOutputWallet} output - the received output\n * @return {Promise}\n */\n async onOutputReceived(output) { }\n /**\n * Invoked twice per spent output: once when confirmed and once when unlocked.\n *\n * The notified output includes basic fields only, so the output or its transaction should be fetched to get all available fields.\n *\n * @param {MoneroOutputWallet} output - the spent output\n * @return {Promise}\n */\n async onOutputSpent(output) { }\n}\n","import GenUtils from \"../../common/GenUtils\";\n/**\n * Monero subaddress model.\n */\nexport default class MoneroSubaddress {\n constructor(subaddress) {\n Object.assign(this, subaddress);\n if (this.balance !== undefined && typeof this.balance !== \"bigint\")\n this.balance = BigInt(this.balance);\n if (this.unlockedBalance !== undefined && typeof this.unlockedBalance !== \"bigint\")\n this.unlockedBalance = BigInt(this.unlockedBalance);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (json.balance !== undefined)\n json.balance = json.balance.toString();\n if (json.unlockedBalance !== undefined)\n json.unlockedBalance = json.unlockedBalance.toString();\n return json;\n }\n getAccountIndex() {\n return this.accountIndex;\n }\n setAccountIndex(accountIndex) {\n this.accountIndex = accountIndex;\n return this;\n }\n getIndex() {\n return this.index;\n }\n setIndex(index) {\n this.index = index;\n return this;\n }\n getAddress() {\n return this.address;\n }\n setAddress(address) {\n this.address = address;\n return this;\n }\n getLabel() {\n return this.label;\n }\n setLabel(label) {\n this.label = label;\n return this;\n }\n getBalance() {\n return this.balance;\n }\n setBalance(balance) {\n this.balance = balance;\n return this;\n }\n getUnlockedBalance() {\n return this.unlockedBalance;\n }\n setUnlockedBalance(unlockedBalance) {\n this.unlockedBalance = unlockedBalance;\n return this;\n }\n getNumUnspentOutputs() {\n return this.numUnspentOutputs;\n }\n setNumUnspentOutputs(numUnspentOutputs) {\n this.numUnspentOutputs = numUnspentOutputs;\n return this;\n }\n getIsUsed() {\n return this.isUsed;\n }\n setIsUsed(isUsed) {\n this.isUsed = isUsed;\n return this;\n }\n getNumBlocksToUnlock() {\n return this.numBlocksToUnlock;\n }\n setNumBlocksToUnlock(numBlocksToUnlock) {\n this.numBlocksToUnlock = numBlocksToUnlock;\n return this;\n }\n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.kvLine(\"Account index\", this.getAccountIndex(), indent);\n str += GenUtils.kvLine(\"Subaddress index\", this.getIndex(), indent);\n str += GenUtils.kvLine(\"Address\", this.getAddress(), indent);\n str += GenUtils.kvLine(\"Label\", this.getLabel(), indent);\n str += GenUtils.kvLine(\"Balance\", this.getBalance(), indent);\n str += GenUtils.kvLine(\"Unlocked balance\", this.getUnlockedBalance(), indent);\n str += GenUtils.kvLine(\"Num unspent outputs\", this.getNumUnspentOutputs(), indent);\n str += GenUtils.kvLine(\"Is used\", this.getIsUsed(), indent);\n str += GenUtils.kvLine(\"Num blocks to unlock\", this.getNumBlocksToUnlock(), indent);\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n","/**\n * Default connection manager listener which takes no action on notifications.\n */\nexport default class MoneroConnectionManagerListener {\n /**\n * Notified on connection change events.\n *\n * @param {MoneroRpcConnection | undefined} connection - the connection manager's current connection\n * @return {Promise}\n */\n async onConnectionChanged(connection) { }\n}\n","/**\n * Enumerate message signature types.\n */\nvar MoneroMessageSignatureType;\n(function (MoneroMessageSignatureType) {\n /**\n * Sign with spend key (value=0).\n */\n MoneroMessageSignatureType[MoneroMessageSignatureType[\"SIGN_WITH_SPEND_KEY\"] = 0] = \"SIGN_WITH_SPEND_KEY\";\n /**\n * Sign with the view key (value=1).\n */\n MoneroMessageSignatureType[MoneroMessageSignatureType[\"SIGN_WITH_VIEW_KEY\"] = 1] = \"SIGN_WITH_VIEW_KEY\";\n})(MoneroMessageSignatureType || (MoneroMessageSignatureType = {}));\nexport default MoneroMessageSignatureType;\n","import assert from \"assert\";\nimport MoneroBlock from \"../daemon/model/MoneroBlock\";\nimport MoneroConnectionManagerListener from \"../common/MoneroConnectionManagerListener\";\nimport MoneroError from \"../common/MoneroError\";\nimport MoneroMessageSignatureType from \"./model/MoneroMessageSignatureType\";\nimport MoneroOutputQuery from \"./model/MoneroOutputQuery\";\nimport MoneroTransferQuery from \"./model/MoneroTransferQuery\";\nimport MoneroTxConfig from \"./model/MoneroTxConfig\";\nimport MoneroTxQuery from \"./model/MoneroTxQuery\";\nimport MoneroTxSet from \"./model/MoneroTxSet\";\nimport MoneroUtils from \"../common/MoneroUtils\";\nimport MoneroWalletListener from \"./model/MoneroWalletListener\";\n/**\n * Copyright (c) woodser\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n/**\n * Monero wallet interface and default implementations.\n *\n * @interface\n */\nclass MoneroWallet {\n /**\n * Hidden constructor.\n *\n * @private\n */\n constructor() {\n this.listeners = [];\n this._isClosed = false;\n // no code needed\n }\n /**\n * Register a listener to receive wallet notifications.\n *\n * @param {MoneroWalletListener} listener - listener to receive wallet notifications\n * @return {Promise}\n */\n async addListener(listener) {\n assert(listener instanceof MoneroWalletListener, \"Listener must be instance of MoneroWalletListener\");\n this.listeners.push(listener);\n }\n /**\n * Unregister a listener to receive wallet notifications.\n *\n * @param {MoneroWalletListener} listener - listener to unregister\n * @return {Promise}\n */\n async removeListener(listener) {\n let idx = this.listeners.indexOf(listener);\n if (idx > -1)\n this.listeners.splice(idx, 1);\n else\n throw new MoneroError(\"Listener is not registered with wallet\");\n }\n /**\n * Get the listeners registered with the wallet.\n *\n * @return {MoneroWalletListener[]} the registered listeners\n */\n getListeners() {\n return this.listeners;\n }\n /**\n * Indicates if the wallet is view-only, meaning it does not have the private\n * spend key and can therefore only observe incoming outputs.\n *\n * @return {Promise} true if the wallet is view-only, false otherwise\n */\n async isViewOnly() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Set the wallet's daemon connection.\n *\n * @param {MoneroRpcConnection | string} [uriOrConnection] - daemon's URI or connection (defaults to offline)\n * @return {Promise}\n */\n async setDaemonConnection(uriOrConnection) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the wallet's daemon connection.\n *\n * @return {Promise} the wallet's daemon connection\n */\n async getDaemonConnection() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Set the wallet's daemon connection manager.\n *\n * @param {MoneroConnectionManager} connectionManager manages connections to monerod\n * @return {Promise}\n */\n async setConnectionManager(connectionManager) {\n if (this.connectionManager)\n this.connectionManager.removeListener(this.connectionManagerListener);\n this.connectionManager = connectionManager;\n if (!connectionManager)\n return;\n let that = this;\n if (!this.connectionManagerListener)\n this.connectionManagerListener = new class extends MoneroConnectionManagerListener {\n async onConnectionChanged(connection) {\n await that.setDaemonConnection(connection);\n }\n };\n connectionManager.addListener(this.connectionManagerListener);\n await this.setDaemonConnection(connectionManager.getConnection());\n }\n /**\n * Get the wallet's daemon connection manager.\n *\n * @return {Promise} the wallet's daemon connection manager\n */\n async getConnectionManager() {\n return this.connectionManager;\n }\n /**\n * Indicates if the wallet is connected to daemon.\n *\n * @return {Promise} true if the wallet is connected to a daemon, false otherwise\n */\n async isConnectedToDaemon() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Gets the version of the wallet.\n *\n * @return {Promise} the version of the wallet\n */\n async getVersion() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the wallet's path.\n *\n * @return {Promise} the path the wallet can be opened with\n */\n async getPath() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the wallet's mnemonic phrase or seed.\n *\n * @return {Promise} the wallet's mnemonic phrase or seed.\n */\n async getSeed() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the language of the wallet's mnemonic phrase or seed.\n *\n * @return {Promise} the language of the wallet's mnemonic phrase or seed.\n */\n async getSeedLanguage() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the wallet's private view key.\n *\n * @return {Promise} the wallet's private view key\n */\n async getPrivateViewKey() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the wallet's private spend key.\n *\n * @return {Promise} the wallet's private spend key\n */\n async getPrivateSpendKey() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the wallet's public view key.\n *\n * @return {Promise} the wallet's public view key\n */\n async getPublicViewKey() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the wallet's public spend key.\n *\n * @return {Promise} the wallet's public spend key\n */\n async getPublicSpendKey() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the wallet's primary address.\n *\n * @return {Promise} the wallet's primary address\n */\n async getPrimaryAddress() {\n return await this.getAddress(0, 0);\n }\n /**\n * Get the address of a specific subaddress.\n *\n * @param {number} accountIdx - the account index of the address's subaddress\n * @param {number} subaddressIdx - the subaddress index within the account\n * @return {Promise} the receive address of the specified subaddress\n */\n async getAddress(accountIdx, subaddressIdx) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the account and subaddress index of the given address.\n *\n * @param {string} address - address to get the account and subaddress index from\n * @return {Promise} the account and subaddress indices\n */\n async getAddressIndex(address) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get an integrated address based on the given standard address and payment\n * ID. Uses the wallet's primary address if an address is not given.\n * Generates a random payment ID if a payment ID is not given.\n *\n * @param {string} standardAddress is the standard address to generate the integrated address from (wallet's primary address if undefined)\n * @param {string} paymentId is the payment ID to generate an integrated address from (randomly generated if undefined)\n * @return {Promise} the integrated address\n */\n async getIntegratedAddress(standardAddress, paymentId) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Decode an integrated address to get its standard address and payment id.\n *\n * @param {string} integratedAddress - integrated address to decode\n * @return {Promise} the decoded integrated address including standard address and payment id\n */\n async decodeIntegratedAddress(integratedAddress) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the block height that the wallet is synced to.\n *\n * @return {Promise} the block height that the wallet is synced to\n */\n async getHeight() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the blockchain's height.\n *\n * @return {Promise} the blockchain's height\n */\n async getDaemonHeight() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the blockchain's height by date as a conservative estimate for scanning.\n *\n * @param {number} year - year of the height to get\n * @param {number} month - month of the height to get as a number between 1 and 12\n * @param {number} day - day of the height to get as a number between 1 and 31\n * @return {Promise} the blockchain's approximate height at the given date\n */\n async getHeightByDate(year, month, day) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Synchronize the wallet with the daemon as a one-time synchronous process.\n *\n * @param {MoneroWalletListener|number} [listenerOrStartHeight] - listener xor start height (defaults to no sync listener, the last synced block)\n * @param {number} [startHeight] - startHeight if not given in first arg (defaults to last synced block)\n * @return {Promise}\n */\n async sync(listenerOrStartHeight, startHeight) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Start background synchronizing with a maximum period between syncs.\n *\n * @param {number} [syncPeriodInMs] - maximum period between syncs in milliseconds (default is wallet-specific)\n * @return {Promise}\n */\n async startSyncing(syncPeriodInMs) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Stop synchronizing the wallet with the daemon.\n *\n * @return {Promise}\n */\n async stopSyncing() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Scan transactions by their hash/id.\n *\n * @param {string[]} txHashes - tx hashes to scan\n * @return {Promise}\n */\n async scanTxs(txHashes) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n *

Rescan the blockchain for spent outputs.

\n *\n *

Note: this can only be called with a trusted daemon.

\n *\n *

Example use case: peer multisig hex is import when connected to an untrusted daemon,\n * so the wallet will not rescan spent outputs. Then the wallet connects to a trusted\n * daemon. This method should be manually invoked to rescan outputs.

\n *\n * @return {Promise}\n */\n async rescanSpent() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n *

Rescan the blockchain from scratch, losing any information which cannot be recovered from\n * the blockchain itself.

\n *\n *

WARNING: This method discards local wallet data like destination addresses, tx secret keys,\n * tx notes, etc.

\n *\n * @return {Promise}\n */\n async rescanBlockchain() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the balance of the wallet, account, or subaddress.\n *\n * @param {number} [accountIdx] - index of the account to get the balance of (default all accounts)\n * @param {number} [subaddressIdx] - index of the subaddress to get the balance of (default all subaddresses)\n * @return {Promise} the balance of the wallet, account, or subaddress\n */\n async getBalance(accountIdx, subaddressIdx) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the unlocked balance of the wallet, account, or subaddress.\n *\n * @param {number} [accountIdx] - index of the account to get the unlocked balance of (optional)\n * @param {number} [subaddressIdx] - index of the subaddress to get the unlocked balance of (optional)\n * @return {Promise} the unlocked balance of the wallet, account, or subaddress\n */\n async getUnlockedBalance(accountIdx, subaddressIdx) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the number of blocks until the next and last funds unlock. Ignores txs with unlock time as timestamp.\n *\n * @return {Promise} the number of blocks until the next and last funds unlock in elements 0 and 1, respectively, or undefined if no balance\n */\n async getNumBlocksToUnlock() {\n // get balances\n let balance = await this.getBalance();\n if (balance === 0n)\n return [undefined, undefined]; // skip if no balance\n let unlockedBalance = await this.getUnlockedBalance();\n // compute number of blocks until next funds available\n let txs;\n let height;\n let numBlocksToNextUnlock = undefined;\n if (unlockedBalance > 0n)\n numBlocksToNextUnlock = 0;\n else {\n txs = await this.getTxs({ isLocked: true }); // get locked txs\n height = await this.getHeight(); // get most recent height\n for (let tx of txs) {\n if (!tx.getIsConfirmed() && MoneroUtils.isTimestamp(tx.getUnlockTime()))\n continue;\n let numBlocksToUnlock = Math.max((tx.getIsConfirmed() ? tx.getHeight() : height) + 10, Number(tx.getUnlockTime())) - height;\n numBlocksToNextUnlock = numBlocksToNextUnlock === undefined ? numBlocksToUnlock : Math.min(numBlocksToNextUnlock, numBlocksToUnlock);\n }\n }\n // compute number of blocks until all funds available\n let numBlocksToLastUnlock = undefined;\n if (balance === unlockedBalance) {\n if (unlockedBalance > 0n)\n numBlocksToLastUnlock = 0;\n }\n else {\n if (!txs) {\n txs = await this.getTxs({ isLocked: true }); // get locked txs\n height = await this.getHeight(); // get most recent height\n }\n for (let tx of txs) {\n if (!tx.getIsConfirmed() && MoneroUtils.isTimestamp(tx.getUnlockTime()))\n continue;\n let numBlocksToUnlock = Math.max((tx.getIsConfirmed() ? tx.getHeight() : height) + 10, Number(tx.getUnlockTime())) - height;\n numBlocksToLastUnlock = numBlocksToLastUnlock === undefined ? numBlocksToUnlock : Math.max(numBlocksToLastUnlock, numBlocksToUnlock);\n }\n }\n return [numBlocksToNextUnlock, numBlocksToLastUnlock];\n }\n /**\n * Get accounts with a given tag.\n *\n * @param {boolean} includeSubaddresses - include subaddresses if true\n * @param {string} tag - tag for filtering accounts, all accounts if undefined\n * @return {Promise} all accounts with the given tag\n */\n async getAccounts(includeSubaddresses, tag) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get an account.\n *\n * @param {number} accountIdx - index of the account to get\n * @param {boolean} includeSubaddresses - include subaddresses if true\n * @return {Promise} the retrieved account\n */\n async getAccount(accountIdx, includeSubaddresses) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Create a new account with a label for the first subaddress.\n *\n * @param {string} [label] - label for account's first subaddress (optional)\n * @return {Promise} the created account\n */\n async createAccount(label) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Set an account label.\n *\n * @param {number} accountIdx - index of the account to set the label for\n * @param {string} label - the label to set\n * @return {Promise}\n */\n async setAccountLabel(accountIdx, label) {\n await this.setSubaddressLabel(accountIdx, 0, label);\n }\n /**\n * Get subaddresses in an account.\n *\n * @param {number} accountIdx - account to get subaddresses within\n * @param {number[]} [subaddressIndices] - indices of subaddresses to get (optional)\n * @return {Promise} the retrieved subaddresses\n */\n async getSubaddresses(accountIdx, subaddressIndices) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get a subaddress.\n *\n * @param {number} accountIdx - index of the subaddress's account\n * @param {number} subaddressIdx - index of the subaddress within the account\n * @return {Promise} the retrieved subaddress\n */\n async getSubaddress(accountIdx, subaddressIdx) {\n assert(accountIdx >= 0);\n assert(subaddressIdx >= 0);\n return (await this.getSubaddresses(accountIdx, [subaddressIdx]))[0];\n }\n /**\n * Create a subaddress within an account.\n *\n * @param {number} accountIdx - index of the account to create the subaddress within\n * @param {string} [label] - the label for the subaddress (optional)\n * @return {Promise} the created subaddress\n */\n async createSubaddress(accountIdx, label) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Set a subaddress label.\n *\n * @param {number} accountIdx - index of the account to set the label for\n * @param {number} subaddressIdx - index of the subaddress to set the label for\n * @param {Promise} label - the label to set\n */\n async setSubaddressLabel(accountIdx, subaddressIdx, label) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get a wallet transaction by hash.\n *\n * @param {string} txHash - hash of a transaction to get\n * @return {Promise } the identified transaction or undefined if not found\n */\n async getTx(txHash) {\n let txs = await this.getTxs([txHash]);\n return txs.length === 0 ? undefined : txs[0];\n }\n /**\n *

Get wallet transactions. Wallet transactions contain one or more\n * transfers that are either incoming or outgoing to the wallet.

\n *\n *

Results can be filtered by passing a query object. Transactions must\n * meet every criteria defined in the query in order to be returned. All\n * criteria are optional and no filtering is applied when not defined.

\n *\n * @param {string[] | MoneroTxQuery} [query] - configures the query (optional)\n * @param {boolean} [query.isConfirmed] - get txs that are confirmed or not (optional)\n * @param {boolean} [query.inTxPool] - get txs that are in the tx pool or not (optional)\n * @param {boolean} [query.isRelayed] - get txs that are relayed or not (optional)\n * @param {boolean} [query.isFailed] - get txs that are failed or not (optional)\n * @param {boolean} [query.isMinerTx] - get miner txs or not (optional)\n * @param {string} [query.hash] - get a tx with the hash (optional)\n * @param {string[]} [query.hashes] - get txs with the hashes (optional)\n * @param {string} [query.paymentId] - get transactions with the payment id (optional)\n * @param {string[]} [query.paymentIds] - get transactions with the payment ids (optional)\n * @param {boolean} [query.hasPaymentId] - get transactions with a payment id or not (optional)\n * @param {number} [query.minHeight] - get txs with height >= the given height (optional)\n * @param {number} [query.maxHeight] - get txs with height <= the given height (optional)\n * @param {boolean} [query.isOutgoing] - get txs with an outgoing transfer or not (optional)\n * @param {boolean} [query.isIncoming] - get txs with an incoming transfer or not (optional)\n * @param {MoneroTransferQuery} [query.transferQuery] - get txs that have a transfer that meets this query (optional)\n * @param {boolean} [query.includeOutputs] - specifies that tx outputs should be returned with tx results (optional)\n * @return {Promise} wallet transactions per the configuration\n */\n async getTxs(query) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n *

Get incoming and outgoing transfers to and from this wallet. An outgoing\n * transfer represents a total amount sent from one or more subaddresses\n * within an account to individual destination addresses, each with their\n * own amount. An incoming transfer represents a total amount received into\n * a subaddress within an account. Transfers belong to transactions which\n * are stored on the blockchain.

\n *\n *

Results can be filtered by passing a query object. Transfers must\n * meet every criteria defined in the query in order to be returned. All\n * criteria are optional and no filtering is applied when not defined.

\n *\n * @param {MoneroTransferQuery} [query] - configures the query (optional)\n * @param {boolean} [query.isOutgoing] - get transfers that are outgoing or not (optional)\n * @param {boolean} [query.isIncoming] - get transfers that are incoming or not (optional)\n * @param {string} [query.address] - wallet's address that a transfer either originated from (if outgoing) or is destined for (if incoming) (optional)\n * @param {number} [query.accountIndex] - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific account index (optional)\n * @param {number} [query.subaddressIndex] - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific subaddress index (optional)\n * @param {int[]} [query.subaddressIndices] - get transfers that either originated from (if outgoing) or are destined for (if incoming) specific subaddress indices (optional)\n * @param {bigint} [query.amount] - amount being transferred (optional)\n * @param {MoneroDestination[] | MoneroDestinationModel[]} [query.destinations] - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional)\n * @param {boolean} [query.hasDestinations] - get transfers that have destinations or not (optional)\n * @param {MoneroTxQuery} [query.txQuery] - get transfers whose transaction meets this query (optional)\n * @return {Promise} wallet transfers that meet the query\n */\n async getTransfers(query) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get incoming transfers.\n *\n * @param {Partial} [query] - configures the query (optional)\n * @param {string} [query.address] - get incoming transfers to a specific address in the wallet (optional)\n * @param {number} [query.accountIndex] - get incoming transfers to a specific account index (optional)\n * @param {number} [query.subaddressIndex] - get incoming transfers to a specific subaddress index (optional)\n * @param {int[]} [query.subaddressIndices] - get transfers destined for specific subaddress indices (optional)\n * @param {bigint} [query.amount] - amount being transferred (optional)\n * @param {MoneroTxQuery} [query.txQuery] - get transfers whose transaction meets this query (optional)\n * @return {Promise} incoming transfers that meet the query\n */\n async getIncomingTransfers(query) {\n const queryNormalized = MoneroWallet.normalizeTransferQuery(query);\n if (queryNormalized.getIsIncoming() === false)\n throw new MoneroError(\"Transfer query contradicts getting incoming transfers\");\n queryNormalized.setIsIncoming(true);\n return this.getTransfers(queryNormalized);\n }\n /**\n * Get outgoing transfers.\n *\n * @param {Partial} [query] - configures the query (optional)\n * @param {string} [query.address] - get outgoing transfers from a specific address in the wallet (optional)\n * @param {number} [query.accountIndex] - get outgoing transfers from a specific account index (optional)\n * @param {number} [query.subaddressIndex] - get outgoing transfers from a specific subaddress index (optional)\n * @param {int[]} [query.subaddressIndices] - get outgoing transfers from specific subaddress indices (optional)\n * @param {bigint} [query.amount] - amount being transferred (optional)\n * @param {MoneroDestination[] | MoneroDestinationModel[]} [query.destinations] - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional)\n * @param {boolean} [query.hasDestinations] - get transfers that have destinations or not (optional)\n * @param {MoneroTxQuery} [query.txQuery] - get transfers whose transaction meets this query (optional)\n * @return {Promise} outgoing transfers that meet the query\n */\n async getOutgoingTransfers(query) {\n const queryNormalized = MoneroWallet.normalizeTransferQuery(query);\n if (queryNormalized.getIsOutgoing() === false)\n throw new MoneroError(\"Transfer query contradicts getting outgoing transfers\");\n queryNormalized.setIsOutgoing(true);\n return this.getTransfers(queryNormalized);\n }\n /**\n *

Get outputs created from previous transactions that belong to the wallet\n * (i.e. that the wallet can spend one time). Outputs are part of\n * transactions which are stored in blocks on the blockchain.

\n *\n *

Results can be filtered by passing a query object. Outputs must\n * meet every criteria defined in the query in order to be returned. All\n * filtering is optional and no filtering is applied when not defined.

\n *\n * @param {Parital} [query] - configures the query (optional)\n * @param {number} [query.accountIndex] - get outputs associated with a specific account index (optional)\n * @param {number} [query.subaddressIndex] - get outputs associated with a specific subaddress index (optional)\n * @param {int[]} [query.subaddressIndices] - get outputs associated with specific subaddress indices (optional)\n * @param {bigint} [query.amount] - get outputs with a specific amount (optional)\n * @param {bigint} [query.minAmount] - get outputs greater than or equal to a minimum amount (optional)\n * @param {bigint} [query.maxAmount] - get outputs less than or equal to a maximum amount (optional)\n * @param {boolean} [query.isSpent] - get outputs that are spent or not (optional)\n * @param {string|MoneroKeyImage} [query.keyImage] - get output with a key image or which matches fields defined in a MoneroKeyImage (optional)\n * @param {MoneroTxQuery} [query.txQuery] - get outputs whose transaction meets this filter (optional)\n * @return {Promise} the queried outputs\n */\n async getOutputs(query) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Export outputs in hex format.\n *\n * @param {boolean} [all] - export all outputs if true, else export the outputs since the last export (default false)\n * @return {Promise} outputs in hex format\n */\n async exportOutputs(all = false) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Import outputs in hex format.\n *\n * @param {string} outputsHex - outputs in hex format\n * @return {Promise} the number of outputs imported\n */\n async importOutputs(outputsHex) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Export signed key images.\n *\n * @param {boolean} [all] - export all key images if true, else export the key images since the last export (default false)\n * @return {Promise} the wallet's signed key images\n */\n async exportKeyImages(all = false) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Import signed key images and verify their spent status.\n *\n * @param {MoneroKeyImage[]} keyImages - images to import and verify (requires hex and signature)\n * @return {Promise} results of the import\n */\n async importKeyImages(keyImages) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get new key images from the last imported outputs.\n *\n * @return {Promise} the key images from the last imported outputs\n */\n async getNewKeyImagesFromLastImport() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Freeze an output.\n *\n * @param {string} keyImage - key image of the output to freeze\n * @return {Promise}\n */\n async freezeOutput(keyImage) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Thaw a frozen output.\n *\n * @param {string} keyImage - key image of the output to thaw\n * @return {Promise}\n */\n async thawOutput(keyImage) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Check if an output is frozen.\n *\n * @param {string} keyImage - key image of the output to check if frozen\n * @return {Promise} true if the output is frozen, false otherwise\n */\n async isOutputFrozen(keyImage) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get the current default fee priority (unimportant, normal, elevated, etc).\n *\n * @return {Promise} the current fee priority\n */\n async getDefaultFeePriority() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Create a transaction to transfer funds from this wallet.\n *\n * @param {MoneroTxConfig} config - configures the transaction to create (required)\n * @param {string} config.address - single destination address (required unless `destinations` provided)\n * @param {bigint|string} config.amount - single destination amount (required unless `destinations` provided)\n * @param {number} config.accountIndex - source account index to transfer funds from (required)\n * @param {number} [config.subaddressIndex] - source subaddress index to transfer funds from (optional)\n * @param {number[]} [config.subaddressIndices] - source subaddress indices to transfer funds from (optional)\n * @param {boolean} [config.relay] - relay the transaction to peers to commit to the blockchain (default false)\n * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL)\n * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided)\n * @param {number[]} [config.subtractFeeFrom] - list of destination indices to split the transaction fee (optional)\n * @param {string} [config.paymentId] - transaction payment ID (optional)\n * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transaction to unlock (default 0)\n * @return {Promise} the created transaction\n */\n async createTx(config) {\n const configNormalized = MoneroWallet.normalizeCreateTxsConfig(config);\n if (configNormalized.getCanSplit() !== undefined)\n assert.equal(configNormalized.getCanSplit(), false, \"Cannot split transactions using createTx(); use createTxs()\");\n configNormalized.setCanSplit(false);\n return (await this.createTxs(configNormalized))[0];\n }\n /**\n * Create one or more transactions to transfer funds from this wallet.\n *\n * @param {Partial} config - configures the transactions to create (required)\n * @param {string} config.address - single destination address (required unless `destinations` provided)\n * @param {bigint|string} config.amount - single destination amount (required unless `destinations` provided)\n * @param {number} config.accountIndex - source account index to transfer funds from (required)\n * @param {number} [config.subaddressIndex] - source subaddress index to transfer funds from (optional)\n * @param {int[]} [config.subaddressIndices] - source subaddress indices to transfer funds from (optional)\n * @param {boolean} [config.relay] - relay the transactions to peers to commit to the blockchain (default false)\n * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL)\n * @param {MoneroDestination[] | MoneroDestinationModel[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided)\n * @param {string} [config.paymentId] - transaction payment ID (optional)\n * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transactions to unlock (default 0)\n * @param {boolean} [config.canSplit] - allow funds to be transferred using multiple transactions (default true)\n * @return {Promise} the created transactions\n */\n async createTxs(config) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Sweep an output by key image.\n *\n * @param {Partial} config - configures the transaction to create (required)\n * @param {string} config.address - single destination address (required)\n * @param {string} config.keyImage - key image to sweep (required)\n * @param {boolean} [config.relay] - relay the transaction to peers to commit to the blockchain (default false)\n * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transaction to unlock (default 0)\n * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL)\n * @return {Promise} the created transaction\n */\n async sweepOutput(config) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Sweep all unlocked funds according to the given configuration.\n *\n * @param {Partial} config - configures the transactions to create (required)\n * @param {string} config.address - single destination address (required)\n * @param {number} [config.accountIndex] - source account index to sweep from (optional, defaults to all accounts)\n * @param {number} [config.subaddressIndex] - source subaddress index to sweep from (optional, defaults to all subaddresses)\n * @param {number[]} [config.subaddressIndices] - source subaddress indices to sweep from (optional)\n * @param {boolean} [config.relay] - relay the transactions to peers to commit to the blockchain (default false)\n * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL)\n * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transactions to unlock (default 0)\n * @param {boolean} [config.sweepEachSubaddress] - sweep each subaddress individually if true (default false)\n * @return {Promise} the created transactions\n */\n async sweepUnlocked(config) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n *

Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

\n *\n *

NOTE: Dust only exists pre RCT, so this method will throw \"no dust to sweep\" on new wallets.

\n *\n * @param {boolean} [relay] - specifies if the resulting transaction should be relayed (default false)\n * @return {Promise} the created transactions\n */\n async sweepDust(relay) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Relay a previously created transaction.\n *\n * @param {(MoneroTxWallet | string)} txOrMetadata - transaction or its metadata to relay\n * @return {Promise} the hash of the relayed tx\n */\n async relayTx(txOrMetadata) {\n return (await this.relayTxs([txOrMetadata]))[0];\n }\n /**\n * Relay previously created transactions.\n *\n * @param {(MoneroTxWallet[] | string[])} txsOrMetadatas - transactions or their metadata to relay\n * @return {Promise} the hashes of the relayed txs\n */\n async relayTxs(txsOrMetadatas) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Describe a tx set from unsigned tx hex.\n *\n * @param {string} unsignedTxHex - unsigned tx hex\n * @return {Promise} the tx set containing structured transactions\n */\n async describeUnsignedTxSet(unsignedTxHex) {\n return this.describeTxSet(new MoneroTxSet().setUnsignedTxHex(unsignedTxHex));\n }\n /**\n * Describe a tx set from multisig tx hex.\n *\n * @param {string} multisigTxHex - multisig tx hex\n * @return {Promise} the tx set containing structured transactions\n */\n async describeMultisigTxSet(multisigTxHex) {\n return this.describeTxSet(new MoneroTxSet().setMultisigTxHex(multisigTxHex));\n }\n /**\n * Describe a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions.\n *\n * @param {MoneroTxSet} txSet - a tx set containing unsigned or multisig tx hex\n * @return {Promise} txSet - the tx set containing structured transactions\n */\n async describeTxSet(txSet) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Sign unsigned transactions from a view-only wallet.\n *\n * @param {string} unsignedTxHex - unsigned transaction hex from when the transactions were created\n * @return {Promise} the signed transaction set\n */\n async signTxs(unsignedTxHex) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Submit signed transactions from a view-only wallet.\n *\n * @param {string} signedTxHex - signed transaction hex from signTxs()\n * @return {Promise} the resulting transaction hashes\n */\n async submitTxs(signedTxHex) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Sign a message.\n *\n * @param {string} message - the message to sign\n * @param {MoneroMessageSignatureType} [signatureType] - sign with spend key or view key (default spend key)\n * @param {number} [accountIdx] - the account index of the message signature (default 0)\n * @param {number} [subaddressIdx] - the subaddress index of the message signature (default 0)\n * @return {Promise} the signature\n */\n async signMessage(message, signatureType = MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY, accountIdx = 0, subaddressIdx = 0) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Verify a signature on a message.\n *\n * @param {string} message - signed message\n * @param {string} address - signing address\n * @param {string} signature - signature\n * @return {Promise} true if the signature is good, false otherwise\n */\n async verifyMessage(message, address, signature) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get a transaction's secret key from its hash.\n *\n * @param {string} txHash - transaction's hash\n * @return {Promise} - transaction's secret key\n */\n async getTxKey(txHash) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Check a transaction in the blockchain with its secret key.\n *\n * @param {string} txHash - transaction to check\n * @param {string} txKey - transaction's secret key\n * @param {string} address - destination public address of the transaction\n * @return {romise} the result of the check\n */\n async checkTxKey(txHash, txKey, address) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get a transaction signature to prove it.\n *\n * @param {string} txHash - transaction to prove\n * @param {string} address - destination public address of the transaction\n * @param {string} [message] - message to include with the signature to further authenticate the proof (optional)\n * @return {Promise} the transaction signature\n */\n async getTxProof(txHash, address, message) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Prove a transaction by checking its signature.\n *\n * @param {string} txHash - transaction to prove\n * @param {string} address - destination public address of the transaction\n * @param {string | undefined} message - message included with the signature to further authenticate the proof\n * @param {string} signature - transaction signature to confirm\n * @return {Promise} the result of the check\n */\n async checkTxProof(txHash, address, message, signature) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address.\n *\n * @param {string} txHash - transaction to prove\n * @param {string} [message] - message to include with the signature to further authenticate the proof (optional)\n * @return {Promise} the transaction signature\n */\n async getSpendProof(txHash, message) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address.\n *\n * @param {string} txHash - transaction to prove\n * @param {string | undefined} message - message included with the signature to further authenticate the proof (optional)\n * @param {string} signature - transaction signature to confirm\n * @return {Promise} true if the signature is good, false otherwise\n */\n async checkSpendProof(txHash, message, signature) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Generate a signature to prove the entire balance of the wallet.\n *\n * @param {string} [message] - message included with the signature to further authenticate the proof (optional)\n * @return {Promise} the reserve proof signature\n */\n async getReserveProofWallet(message) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Generate a signature to prove an available amount in an account.\n *\n * @param {number} accountIdx - account to prove ownership of the amount\n * @param {bigint} amount - minimum amount to prove as available in the account\n * @param {string} [message] - message to include with the signature to further authenticate the proof (optional)\n * @return {Promise} the reserve proof signature\n */\n async getReserveProofAccount(accountIdx, amount, message) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Proves a wallet has a disposable reserve using a signature.\n *\n * @param {string} address - public wallet address\n * @param {string | undefined} message - message included with the signature to further authenticate the proof (optional)\n * @param {string} signature - reserve proof signature to check\n * @return {Promise} the result of checking the signature proof\n */\n async checkReserveProof(address, message, signature) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get a transaction note.\n *\n * @param {string} txHash - transaction to get the note of\n * @return {Promise} the tx note\n */\n async getTxNote(txHash) {\n return (await this.getTxNotes([txHash]))[0];\n }\n /**\n * Get notes for multiple transactions.\n *\n * @param {string[]} txHashes - hashes of the transactions to get notes for\n * @return {Promise} notes for the transactions\n */\n async getTxNotes(txHashes) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Set a note for a specific transaction.\n *\n * @param {string} txHash - hash of the transaction to set a note for\n * @param {string} note - the transaction note\n * @return {Promise}\n */\n async setTxNote(txHash, note) {\n await this.setTxNotes([txHash], [note]);\n }\n /**\n * Set notes for multiple transactions.\n *\n * @param {string[]} txHashes - transactions to set notes for\n * @param {string[]} notes - notes to set for the transactions\n * @return {Promise}\n */\n async setTxNotes(txHashes, notes) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get address book entries.\n *\n * @param {number[]} [entryIndices] - indices of the entries to get\n * @return {Promise} the address book entries\n */\n async getAddressBookEntries(entryIndices) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Add an address book entry.\n *\n * @param {string} address - entry address\n * @param {string} [description] - entry description (optional)\n * @return {Promise} the index of the added entry\n */\n async addAddressBookEntry(address, description) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Edit an address book entry.\n *\n * @param {number} index - index of the address book entry to edit\n * @param {boolean} setAddress - specifies if the address should be updated\n * @param {string | undefined} address - updated address\n * @param {boolean} setDescription - specifies if the description should be updated\n * @param {string | undefined} description - updated description\n * @return {Promise}\n */\n async editAddressBookEntry(index, setAddress, address, setDescription, description) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Delete an address book entry.\n *\n * @param {number} entryIdx - index of the entry to delete\n * @return {Promise}\n */\n async deleteAddressBookEntry(entryIdx) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Tag accounts.\n *\n * @param {string} tag - tag to apply to the specified accounts\n * @param {number[]} accountIndices - indices of the accounts to tag\n * @return {Promise}\n */\n async tagAccounts(tag, accountIndices) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Untag accounts.\n *\n * @param {number[]} accountIndices - indices of the accounts to untag\n * @return {Promise}\n */\n async untagAccounts(accountIndices) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Return all account tags.\n *\n * @return {Promise} the wallet's account tags\n */\n async getAccountTags() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Sets a human-readable description for a tag.\n *\n * @param {string} tag - tag to set a description for\n * @param {string} label - label to set for the tag\n * @return {Promise}\n */\n async setAccountTagLabel(tag, label) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Creates a payment URI from a send configuration.\n *\n * @param {MoneroTxConfig} config - specifies configuration for a potential tx\n * @return {Promise} the payment uri\n */\n async getPaymentUri(config) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Parses a payment URI to a tx config.\n *\n * @param {string} uri - payment uri to parse\n * @return {Promise} the send configuration parsed from the uri\n */\n async parsePaymentUri(uri) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get an attribute.\n *\n * @param {string} key - attribute to get the value of\n * @return {Promise} the attribute's value\n */\n async getAttribute(key) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Set an arbitrary attribute.\n *\n * @param {string} key - attribute key\n * @param {string} val - attribute value\n * @return {Promise}\n */\n async setAttribute(key, val) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Start mining.\n *\n * @param {number} [numThreads] - number of threads created for mining (optional)\n * @param {boolean} [backgroundMining] - specifies if mining should occur in the background (optional)\n * @param {boolean} [ignoreBattery] - specifies if the battery should be ignored for mining (optional)\n * @return {Promise}\n */\n async startMining(numThreads, backgroundMining, ignoreBattery) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Stop mining.\n *\n * @return {Promise}\n */\n async stopMining() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Indicates if importing multisig data is needed for returning a correct balance.\n *\n * @return {Promise} true if importing multisig data is needed for returning a correct balance, false otherwise\n */\n async isMultisigImportNeeded() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Indicates if this wallet is a multisig wallet.\n *\n * @return {Promise} true if this is a multisig wallet, false otherwise\n */\n async isMultisig() {\n return (await this.getMultisigInfo()).getIsMultisig();\n }\n /**\n * Get multisig info about this wallet.\n *\n * @return {Promise} multisig info about this wallet\n */\n async getMultisigInfo() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Get multisig info as hex to share with participants to begin creating a\n * multisig wallet.\n *\n * @return {Promise} this wallet's multisig hex to share with participants\n */\n async prepareMultisig() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Make this wallet multisig by importing multisig hex from participants.\n *\n * @param {string[]} multisigHexes - multisig hex from each participant\n * @param {number} threshold - number of signatures needed to sign transfers\n * @param {string} password - wallet password\n * @return {Promise} this wallet's multisig hex to share with participants\n */\n async makeMultisig(multisigHexes, threshold, password) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Exchange multisig hex with participants in a M/N multisig wallet.\n *\n * This process must be repeated with participants exactly N-M times.\n *\n * @param {string[]} multisigHexes are multisig hex from each participant\n * @param {string} password - wallet's password // TODO monero-project: redundant? wallet is created with password\n * @return {Promise} the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done\n */\n async exchangeMultisigKeys(multisigHexes, password) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Export this wallet's multisig info as hex for other participants.\n *\n * @return {Promise} this wallet's multisig info as hex for other participants\n */\n async exportMultisigHex() {\n throw new MoneroError(\"Not supported?\");\n }\n /**\n * Import multisig info as hex from other participants.\n *\n * @param {string[]} multisigHexes - multisig hex from each participant\n * @return {Promise} the number of outputs signed with the given multisig hex\n */\n async importMultisigHex(multisigHexes) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Sign multisig transactions from a multisig wallet.\n *\n * @param {string} multisigTxHex - unsigned multisig transactions as hex\n * @return {MoneroMultisigSignResult} the result of signing the multisig transactions\n */\n async signMultisigTxHex(multisigTxHex) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Submit signed multisig transactions from a multisig wallet.\n *\n * @param {string} signedMultisigTxHex - signed multisig hex returned from signMultisigTxHex()\n * @return {Promise} the resulting transaction hashes\n */\n async submitMultisigTxHex(signedMultisigTxHex) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Change the wallet password.\n *\n * @param {string} oldPassword - the wallet's old password\n * @param {string} newPassword - the wallet's new password\n * @return {Promise}\n */\n async changePassword(oldPassword, newPassword) {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Save the wallet at its current path.\n *\n * @return {Promise}\n */\n async save() {\n throw new MoneroError(\"Not supported\");\n }\n /**\n * Optionally save then close the wallet.\n *\n * @param {boolean} [save] - specifies if the wallet should be saved before being closed (default false)\n * @return {Promise}\n */\n async close(save = false) {\n if (this.connectionManager)\n this.connectionManager.removeListener(this.connectionManagerListener);\n this.connectionManager = undefined;\n this.connectionManagerListener = undefined;\n this.listeners.splice(0, this.listeners.length);\n this._isClosed = true;\n }\n /**\n * Indicates if this wallet is closed or not.\n *\n * @return {Promise} true if the wallet is closed, false otherwise\n */\n async isClosed() {\n return this._isClosed;\n }\n // -------------------------------- PRIVATE ---------------------------------\n /**\n * @private\n */\n async announceSyncProgress(height, startHeight, endHeight, percentDone, message) {\n for (let listener of this.listeners) {\n try {\n await listener.onSyncProgress(height, startHeight, endHeight, percentDone, message);\n }\n catch (err) {\n console.error(\"Error calling listener on sync progress\", err);\n }\n }\n }\n /**\n * @private\n */\n async announceNewBlock(height) {\n for (let listener of this.listeners) {\n try {\n await listener.onNewBlock(height);\n }\n catch (err) {\n console.error(\"Error calling listener on new block\", err);\n }\n }\n }\n /**\n * @private\n */\n async announceBalancesChanged(newBalance, newUnlockedBalance) {\n for (let listener of this.listeners) {\n try {\n await listener.onBalancesChanged(newBalance, newUnlockedBalance);\n }\n catch (err) {\n console.error(\"Error calling listener on balances changed\", err);\n }\n }\n }\n /**\n * @private\n */\n async announceOutputReceived(output) {\n for (let listener of this.listeners) {\n try {\n await listener.onOutputReceived(output);\n }\n catch (err) {\n console.error(\"Error calling listener on output received\", err);\n }\n }\n }\n /**\n * @private\n */\n async announceOutputSpent(output) {\n for (let listener of this.listeners) {\n try {\n await listener.onOutputSpent(output);\n }\n catch (err) {\n console.error(\"Error calling listener on output spent\", err);\n }\n }\n }\n static normalizeTxQuery(query) {\n if (query instanceof MoneroTxQuery)\n query = query.copy();\n else if (Array.isArray(query))\n query = new MoneroTxQuery().setHashes(query);\n else {\n query = Object.assign({}, query);\n query = new MoneroTxQuery(query);\n }\n if (query.getBlock() === undefined)\n query.setBlock(new MoneroBlock().setTxs([query]));\n if (query.getInputQuery())\n query.getInputQuery().setTxQuery(query);\n if (query.getOutputQuery())\n query.getOutputQuery().setTxQuery(query);\n return query;\n }\n static normalizeTransferQuery(query) {\n query = new MoneroTransferQuery(query);\n if (query.getTxQuery() !== undefined) {\n let txQuery = query.getTxQuery().copy();\n query = txQuery.getTransferQuery();\n }\n if (query.getTxQuery() === undefined)\n query.setTxQuery(new MoneroTxQuery());\n query.getTxQuery().setTransferQuery(query);\n if (query.getTxQuery().getBlock() === undefined)\n query.getTxQuery().setBlock(new MoneroBlock().setTxs([query.getTxQuery()]));\n return query;\n }\n static normalizeOutputQuery(query) {\n query = new MoneroOutputQuery(query);\n if (query.getTxQuery() !== undefined) {\n let txQuery = query.getTxQuery().copy();\n query = txQuery.getOutputQuery();\n }\n if (query.getTxQuery() === undefined)\n query.setTxQuery(new MoneroTxQuery());\n query.getTxQuery().setOutputQuery(query);\n if (query.getTxQuery().getBlock() === undefined)\n query.getTxQuery().setBlock(new MoneroBlock().setTxs([query.getTxQuery()]));\n return query;\n }\n static normalizeCreateTxsConfig(config) {\n if (config === undefined || !(config instanceof Object))\n throw new MoneroError(\"Must provide MoneroTxConfig or equivalent JS object\");\n config = new MoneroTxConfig(config);\n assert(config.getDestinations() && config.getDestinations().length > 0, \"Must provide destinations\");\n assert.equal(config.getSweepEachSubaddress(), undefined);\n assert.equal(config.getBelowAmount(), undefined);\n return config;\n }\n static normalizeSweepOutputConfig(config) {\n if (config === undefined || !(config instanceof Object))\n throw new MoneroError(\"Must provide MoneroTxConfig or equivalent JS object\");\n config = new MoneroTxConfig(config);\n assert.equal(config.getSweepEachSubaddress(), undefined);\n assert.equal(config.getBelowAmount(), undefined);\n assert.equal(config.getCanSplit(), undefined, \"Cannot split transactions when sweeping an output\");\n if (!config.getDestinations() || config.getDestinations().length !== 1 || !config.getDestinations()[0].getAddress())\n throw new MoneroError(\"Must provide exactly one destination address to sweep output to\");\n if (config.getSubtractFeeFrom() && config.getSubtractFeeFrom().length > 0)\n throw new MoneroError(\"Sweep transactions do not support subtracting fees from destinations\");\n return config;\n }\n static normalizeSweepUnlockedConfig(config) {\n if (config === undefined || !(config instanceof Object))\n throw new MoneroError(\"Must provide MoneroTxConfig or equivalent JS object\");\n config = new MoneroTxConfig(config);\n if (config.getDestinations() === undefined || config.getDestinations().length != 1)\n throw new MoneroError(\"Must provide exactly one destination to sweep to\");\n if (config.getDestinations()[0].getAddress() === undefined)\n throw new MoneroError(\"Must provide destination address to sweep to\");\n if (config.getDestinations()[0].getAmount() !== undefined)\n throw new MoneroError(\"Cannot provide amount in sweep config\");\n if (config.getKeyImage() !== undefined)\n throw new MoneroError(\"Key image defined; use sweepOutput() to sweep an output by its key image\");\n if (config.getSubaddressIndices() !== undefined && config.getSubaddressIndices().length === 0)\n config.setSubaddressIndices(undefined);\n if (config.getAccountIndex() === undefined && config.getSubaddressIndices() !== undefined)\n throw new MoneroError(\"Must provide account index if subaddress indices are provided\");\n if (config.getSubtractFeeFrom() && config.getSubtractFeeFrom().length > 0)\n throw new MoneroError(\"Sweep transactions do not support subtracting fees from destinations\");\n return config;\n }\n}\n// static variables\nMoneroWallet.DEFAULT_LANGUAGE = \"English\";\nexport default MoneroWallet;\n","import assert from \"assert\";\nimport GenUtils from \"../common/GenUtils\";\nimport LibraryUtils from \"../common/LibraryUtils\";\nimport MoneroError from \"../common/MoneroError\";\nimport MoneroIntegratedAddress from \"./model/MoneroIntegratedAddress\";\nimport MoneroNetworkType from \"../daemon/model/MoneroNetworkType\";\nimport MoneroSubaddress from \"./model/MoneroSubaddress\";\nimport MoneroVersion from \"../daemon/model/MoneroVersion\";\nimport MoneroWallet from \"./MoneroWallet\";\nimport MoneroWalletConfig from \"./model/MoneroWalletConfig\";\n/**\n * Implements a MoneroWallet which only manages keys using WebAssembly.\n */\nexport class MoneroWalletKeys extends MoneroWallet {\n // --------------------------- STATIC UTILITIES -----------------------------\n /**\n *

Create a wallet using WebAssembly bindings to monero-project.

\n *\n *

Example:

\n *\n * \n * let wallet = await MoneroWalletKeys.createWallet({
\n *    password: \"abc123\",
\n *    networkType: MoneroNetworkType.STAGENET,
\n *    seed: \"coexist igloo pamphlet lagoon...\"
\n * });\n *
\n *\n * @param {MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object\n * @param {string|number} config.networkType - network type of the wallet to create (one of \"mainnet\", \"testnet\", \"stagenet\" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)\n * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given)\n * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed phrase\n * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys)\n * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional)\n * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional)\n * @param {string} [config.language] - language of the wallet's seed (defaults to \"English\" or auto-detected)\n * @return {MoneroWalletKeys} the created wallet\n */\n static async createWallet(config) {\n // normalize and validate config\n if (config === undefined)\n throw new MoneroError(\"Must provide config to create wallet\");\n config = config instanceof MoneroWalletConfig ? config : new MoneroWalletConfig(config);\n if (config.getSeed() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) {\n throw new MoneroError(\"Wallet may be initialized with a seed or keys but not both\");\n }\n if (config.getNetworkType() === undefined)\n throw new MoneroError(\"Must provide a networkType: 'mainnet', 'testnet' or 'stagenet'\");\n if (config.getSaveCurrent() === true)\n throw new MoneroError(\"Cannot save current wallet when creating keys-only wallet\");\n // initialize proxied wallet if configured\n if (config.getProxyToWorker() === undefined)\n config.setProxyToWorker(true);\n if (config.getProxyToWorker()) {\n let walletProxy = await MoneroWalletKeysProxy.createWallet(config);\n ;\n return new MoneroWalletKeys(undefined, walletProxy);\n }\n // disallow server connection\n if (config.getServer() !== undefined)\n throw new MoneroError(\"Cannot initialize keys wallet with server connection\");\n // create wallet\n if (config.getSeed() !== undefined)\n return MoneroWalletKeys.createWalletFromSeed(config);\n else if (config.getPrivateSpendKey() !== undefined || config.getPrimaryAddress() !== undefined)\n return MoneroWalletKeys.createWalletFromKeys(config);\n else\n return MoneroWalletKeys.createWalletRandom(config);\n }\n static async createWalletRandom(config) {\n // validate and sanitize params\n config = config.copy();\n if (config.getSeedOffset() !== undefined)\n throw new MoneroError(\"Cannot provide seedOffset when creating random wallet\");\n if (config.getRestoreHeight() !== undefined)\n throw new MoneroError(\"Cannot provide restoreHeight when creating random wallet\");\n MoneroNetworkType.validate(config.getNetworkType());\n if (config.getLanguage() === undefined)\n config.setLanguage(\"English\");\n // load wasm module\n let module = await LibraryUtils.loadWasmModule();\n // queue call to wasm module\n return module.queueTask(async () => {\n return new Promise((resolve, reject) => {\n // create wallet in wasm which invokes callback when done\n module.create_keys_wallet_random(JSON.stringify(config.toJson()), (cppAddress) => {\n if (typeof cppAddress === \"string\")\n reject(new MoneroError(cppAddress));\n else\n resolve(new MoneroWalletKeys(cppAddress));\n });\n });\n });\n }\n static async createWalletFromSeed(config) {\n // validate and sanitize params\n MoneroNetworkType.validate(config.getNetworkType());\n if (config.getSeed() === undefined)\n throw Error(\"Must define seed to create wallet from\");\n if (config.getSeedOffset() === undefined)\n config.setSeedOffset(\"\");\n if (config.getLanguage() !== undefined)\n throw new MoneroError(\"Cannot provide language when creating wallet from seed\");\n // load wasm module\n let module = await LibraryUtils.loadWasmModule();\n // queue call to wasm module\n return module.queueTask(async () => {\n return new Promise((resolve, reject) => {\n // create wallet in wasm which invokes callback when done\n module.create_keys_wallet_from_seed(JSON.stringify(config.toJson()), (cppAddress) => {\n if (typeof cppAddress === \"string\")\n reject(new MoneroError(cppAddress));\n else\n resolve(new MoneroWalletKeys(cppAddress));\n });\n });\n });\n }\n static async createWalletFromKeys(config) {\n // validate and sanitize params\n if (config.getSeedOffset() !== undefined)\n throw new MoneroError(\"Cannot provide seedOffset when creating wallet from keys\");\n MoneroNetworkType.validate(config.getNetworkType());\n if (config.getPrimaryAddress() === undefined)\n config.setPrimaryAddress(\"\");\n if (config.getPrivateViewKey() === undefined)\n config.setPrivateViewKey(\"\");\n if (config.getPrivateSpendKey() === undefined)\n config.setPrivateSpendKey(\"\");\n if (config.getLanguage() === undefined)\n config.setLanguage(\"English\");\n // load wasm module\n let module = await LibraryUtils.loadWasmModule();\n // queue call to wasm module\n return module.queueTask(async () => {\n return new Promise((resolve, reject) => {\n // create wallet in wasm which invokes callback when done\n module.create_keys_wallet_from_keys(JSON.stringify(config.toJson()), (cppAddress) => {\n if (typeof cppAddress === \"string\")\n reject(new MoneroError(cppAddress));\n else\n resolve(new MoneroWalletKeys(cppAddress));\n });\n });\n });\n }\n static async getSeedLanguages() {\n let module = await LibraryUtils.loadWasmModule();\n return module.queueTask(async () => {\n return JSON.parse(module.get_keys_wallet_seed_languages()).languages;\n });\n }\n // --------------------------- INSTANCE METHODS -----------------------------\n /**\n * Internal constructor which is given the memory address of a C++ wallet\n * instance.\n *\n * This method should not be called externally but should be called through\n * static wallet creation utilities in this class.\n *\n * @param {number} cppAddress - address of the wallet instance in C++\n * @param {MoneroWalletKeysProxy} walletProxy - proxy\n *\n * @private\n */\n constructor(cppAddress, walletProxy) {\n super();\n if (!cppAddress && !walletProxy)\n throw new MoneroError(\"Must provide cppAddress or walletProxy\");\n if (walletProxy)\n this.walletProxy = walletProxy;\n else {\n this.cppAddress = cppAddress;\n this.module = LibraryUtils.getWasmModule();\n if (!this.module.create_full_wallet)\n throw new MoneroError(\"WASM module not loaded - create wallet instance using static utilities\"); // static utilites pre-load wasm module\n }\n }\n async isViewOnly() {\n if (this.getWalletProxy())\n return this.getWalletProxy().isViewOnly();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return this.module.is_view_only(this.cppAddress);\n });\n }\n async isConnectedToDaemon() {\n if (this.getWalletProxy())\n return this.getWalletProxy().isConnectedToDaemon();\n return false;\n }\n async getVersion() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getVersion();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let versionStr = this.module.get_version(this.cppAddress);\n let versionJson = JSON.parse(versionStr);\n return new MoneroVersion(versionJson.number, versionJson.isRelease);\n });\n }\n /**\n * @ignore\n */\n getPath() {\n throw new MoneroError(\"MoneroWalletKeys does not support a persisted path\");\n }\n async getSeed() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getSeed();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let resp = this.module.get_seed(this.cppAddress);\n const errorStr = \"error: \";\n if (resp.indexOf(errorStr) === 0)\n throw new MoneroError(resp.substring(errorStr.length));\n return resp ? resp : undefined;\n });\n }\n async getSeedLanguage() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getSeedLanguage();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let resp = this.module.get_seed_language(this.cppAddress);\n let errorKey = \"error: \";\n if (resp.indexOf(errorKey) === 0)\n throw new MoneroError(resp.substring(errorKey.length));\n return resp ? resp : undefined;\n });\n }\n async getPrivateSpendKey() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getPrivateSpendKey();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let resp = this.module.get_private_spend_key(this.cppAddress);\n let errorKey = \"error: \";\n if (resp.indexOf(errorKey) === 0)\n throw new MoneroError(resp.substring(errorKey.length));\n return resp ? resp : undefined;\n });\n }\n async getPrivateViewKey() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getPrivateViewKey();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let resp = this.module.get_private_view_key(this.cppAddress);\n let errorKey = \"error: \";\n if (resp.indexOf(errorKey) === 0)\n throw new MoneroError(resp.substring(errorKey.length));\n return resp ? resp : undefined;\n });\n }\n async getPublicViewKey() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getPublicViewKey();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let resp = this.module.get_public_view_key(this.cppAddress);\n let errorKey = \"error: \";\n if (resp.indexOf(errorKey) === 0)\n throw new MoneroError(resp.substring(errorKey.length));\n return resp ? resp : undefined;\n });\n }\n async getPublicSpendKey() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getPublicSpendKey();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let resp = this.module.get_public_spend_key(this.cppAddress);\n let errorKey = \"error: \";\n if (resp.indexOf(errorKey) === 0)\n throw new MoneroError(resp.substring(errorKey.length));\n return resp ? resp : undefined;\n });\n }\n async getAddress(accountIdx, subaddressIdx) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getAddress(accountIdx, subaddressIdx);\n assert(typeof accountIdx === \"number\");\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return this.module.get_address(this.cppAddress, accountIdx, subaddressIdx);\n });\n }\n async getAddressIndex(address) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getAddressIndex(address);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let resp = this.module.get_address_index(this.cppAddress, address);\n if (resp.charAt(0) !== '{')\n throw new MoneroError(resp);\n return new MoneroSubaddress(JSON.parse(resp));\n });\n }\n async getAccounts(includeSubaddresses, tag) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getAccounts();\n throw new MoneroError(\"MoneroWalletKeys does not support getting an enumerable set of accounts; query specific accounts\");\n }\n // getIntegratedAddress(paymentId) // TODO\n // decodeIntegratedAddress\n async close(save = false) {\n if (this._isClosed)\n return; // no effect if closed\n if (this.getWalletProxy()) {\n await this.getWalletProxy().close(save);\n await super.close();\n this._isClosed = true;\n return;\n }\n // save wallet if requested\n if (save)\n await this.save();\n // close super\n await super.close();\n this._isClosed = true;\n // queue task to use wasm module\n return this.module.queueTask(async () => {\n return new Promise((resolve, reject) => {\n if (this._isClosed) {\n resolve(undefined);\n return;\n }\n // close wallet in wasm and invoke callback when done\n this.module.close(this.cppAddress, false, async () => {\n delete this.cppAddress;\n this._isClosed = true;\n resolve();\n });\n });\n });\n }\n async isClosed() {\n return this._isClosed;\n }\n // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS --------------\n async getPrimaryAddress() { return super.getPrimaryAddress(); }\n async getSubaddress(accountIdx, subaddressIdx) { return super.getSubaddress(accountIdx, subaddressIdx); }\n // ----------------------------- PRIVATE HELPERS ----------------------------\n static sanitizeSubaddress(subaddress) {\n if (subaddress.getLabel() === \"\")\n subaddress.setLabel(undefined);\n return subaddress;\n }\n assertNotClosed() {\n if (this._isClosed)\n throw new MoneroError(\"Wallet is closed\");\n }\n getWalletProxy() {\n this.assertNotClosed();\n return this.walletProxy;\n }\n}\n/**\n * Implements a MoneroWallet by proxying requests to a worker which runs a keys-only wallet.\n *\n * TODO: sort these methods according to master sort in MoneroWallet.ts\n * TODO: probably only allow one listener to worker then propogate to registered listeners for performance\n *\n * @private\n */\nexport class MoneroWalletKeysProxy extends MoneroWallet {\n // -------------------------- WALLET STATIC UTILS ---------------------------\n static async createWallet(config) {\n let walletId = GenUtils.getUUID();\n await LibraryUtils.invokeWorker(walletId, \"createWalletKeys\", [config.toJson()]);\n return new MoneroWalletKeysProxy(walletId, await LibraryUtils.getWorker());\n }\n // --------------------------- INSTANCE METHODS ----------------------------\n /**\n * Internal constructor which is given a worker to communicate with via messages.\n *\n * This method should not be called externally but should be called through\n * static wallet creation utilities in this class.\n *\n * @param {string} walletId - identifies the wallet with the worker\n * @param {Worker} worker - worker to communicate with via messages\n *\n * @protected\n */\n constructor(walletId, worker) {\n super();\n this.walletId = walletId;\n this.worker = worker;\n }\n async isViewOnly() {\n return this.invokeWorker(\"isViewOnly\");\n }\n async getVersion() {\n throw new MoneroError(\"Not implemented\");\n }\n async getSeed() {\n return this.invokeWorker(\"getSeed\");\n }\n async getSeedLanguage() {\n return this.invokeWorker(\"getSeedLanguage\");\n }\n async getSeedLanguages() {\n return this.invokeWorker(\"getSeedLanguages\");\n }\n async getPrivateSpendKey() {\n return this.invokeWorker(\"getPrivateSpendKey\");\n }\n async getPrivateViewKey() {\n return this.invokeWorker(\"getPrivateViewKey\");\n }\n async getPublicViewKey() {\n return this.invokeWorker(\"getPublicViewKey\");\n }\n async getPublicSpendKey() {\n return this.invokeWorker(\"getPublicSpendKey\");\n }\n async getAddress(accountIdx, subaddressIdx) {\n return this.invokeWorker(\"getAddress\", Array.from(arguments));\n }\n async getAddressIndex(address) {\n let subaddressJson = await this.invokeWorker(\"getAddressIndex\", Array.from(arguments));\n return MoneroWalletKeys.sanitizeSubaddress(new MoneroSubaddress(subaddressJson));\n }\n async getIntegratedAddress(standardAddress, paymentId) {\n return new MoneroIntegratedAddress(await this.invokeWorker(\"getIntegratedAddress\", Array.from(arguments)));\n }\n async decodeIntegratedAddress(integratedAddress) {\n return new MoneroIntegratedAddress(await this.invokeWorker(\"decodeIntegratedAddress\", Array.from(arguments)));\n }\n async close(save) {\n await this.invokeWorker(\"close\", Array.from(arguments));\n LibraryUtils.removeWorkerObject(this.walletId);\n }\n async isClosed() {\n return this.invokeWorker(\"isClosed\");\n }\n async invokeWorker(fnName, args) {\n return await LibraryUtils.invokeWorker(this.walletId, fnName, args);\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"../../common/GenUtils\";\nimport MoneroSubaddress from \"./MoneroSubaddress\";\n/**\n * Monero account model.\n */\nexport default class MoneroAccount {\n constructor(account) {\n Object.assign(this, account);\n // deserialize balances\n if (this.balance !== undefined && typeof this.balance !== \"bigint\")\n this.balance = BigInt(this.balance);\n if (this.unlockedBalance !== undefined && typeof this.unlockedBalance !== \"bigint\")\n this.unlockedBalance = BigInt(this.unlockedBalance);\n // copy subaddresses\n if (this.subaddresses) {\n for (let i = 0; i < this.subaddresses.length; i++) {\n this.subaddresses[i] = new MoneroSubaddress(this.subaddresses[i]);\n }\n }\n }\n toJson() {\n let json = Object.assign({}, this);\n if (json.balance !== undefined)\n json.balance = json.balance.toString();\n if (json.unlockedBalance !== undefined)\n json.unlockedBalance = json.unlockedBalance.toString();\n if (json.subaddresses !== undefined) {\n for (let i = 0; i < json.subaddresses.length; i++) {\n json.subaddresses[i] = json.subaddresses[i].toJson();\n }\n }\n return json;\n }\n getIndex() {\n return this.index;\n }\n setIndex(index) {\n this.index = index;\n return this;\n }\n getPrimaryAddress() {\n return this.primaryAddress;\n }\n setPrimaryAddress(primaryAddress) {\n this.primaryAddress = primaryAddress;\n return this;\n }\n getBalance() {\n return this.balance;\n }\n setBalance(balance) {\n this.balance = balance;\n return this;\n }\n getUnlockedBalance() {\n return this.unlockedBalance;\n }\n setUnlockedBalance(unlockedBalance) {\n this.unlockedBalance = unlockedBalance;\n return this;\n }\n getLabel() {\n return this.label;\n }\n setLabel(label) {\n this.label = label;\n return this;\n }\n getTag() {\n return this.tag;\n }\n setTag(tag) {\n this.tag = tag;\n return this;\n }\n getSubaddresses() {\n return this.subaddresses;\n }\n setSubaddresses(subaddresses) {\n assert(subaddresses === undefined || Array.isArray(subaddresses), \"Given subaddresses must be undefined or an array of subaddresses\");\n this.subaddresses = subaddresses;\n if (subaddresses) {\n for (let subaddress of subaddresses) {\n subaddress.setAccountIndex(this.index);\n }\n }\n return this;\n }\n toString(indent = 0) {\n let str = \"\";\n str += GenUtils.kvLine(\"Index\", this.getIndex(), indent);\n str += GenUtils.kvLine(\"Primary address\", this.getPrimaryAddress(), indent);\n str += GenUtils.kvLine(\"Balance\", this.getBalance(), indent);\n str += GenUtils.kvLine(\"Unlocked balance\", this.getUnlockedBalance(), indent);\n str += GenUtils.kvLine(\"Label\", this.getTag(), indent);\n str += GenUtils.kvLine(\"Tag\", this.getTag(), indent);\n if (this.getSubaddresses() !== undefined) {\n str += GenUtils.kvLine(\"Subaddresses\", \"\", indent);\n for (let i = 0; i < this.getSubaddresses().length; i++) {\n str += GenUtils.kvLine(i + 1, \"\", indent + 1);\n str += this.getSubaddresses()[i].toString(indent + 2) + \"\\n\";\n }\n }\n return str.slice(0, str.length - 1); // strip last newline\n }\n}\n","/**\n * Represents an account tag.\n */\nexport default class MoneroAccountTag {\n constructor(accountTag) {\n Object.assign(this, accountTag);\n }\n getTag() {\n return this.tag;\n }\n setTag(tag) {\n this.tag = tag;\n return this;\n }\n getLabel() {\n return this.label;\n }\n setLabel(label) {\n this.label = label;\n return this;\n }\n getAccountIndices() {\n return this.accountIndices;\n }\n setAccountIndices(accountIndices) {\n this.accountIndices = accountIndices;\n return this;\n }\n}\n","/**\n * Monero address book entry model\n */\nexport default class MoneroAddressBookEntry {\n constructor(entry) {\n Object.assign(this, entry);\n }\n toJson() {\n return Object.assign({}, this);\n }\n getIndex() {\n return this.index;\n }\n setIndex(index) {\n this.index = index;\n return this;\n }\n getAddress() {\n return this.address;\n }\n setAddress(address) {\n this.address = address;\n return this;\n }\n getDescription() {\n return this.description;\n }\n setDescription(description) {\n this.description = description;\n return this;\n }\n getPaymentId() {\n return this.paymentId;\n }\n setPaymentId(paymentId) {\n this.paymentId = paymentId;\n return this;\n }\n}\n","/**\n * Base class for results from checking a transaction or reserve proof.\n */\nexport default class MoneroCheck {\n constructor(check) {\n Object.assign(this, check);\n }\n getIsGood() {\n return this.isGood;\n }\n setIsGood(isGood) {\n this.isGood = isGood;\n return this;\n }\n}\n","import MoneroCheck from \"./MoneroCheck\";\n/**\n * Results from checking a transaction key.\n */\nexport default class MoneroCheckTx extends MoneroCheck {\n constructor(check) {\n super(check);\n if (this.receivedAmount !== undefined && typeof this.receivedAmount !== \"bigint\")\n this.receivedAmount = BigInt(this.receivedAmount);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (this.getReceivedAmount() !== undefined)\n json.receivedAmount = this.getReceivedAmount().toString();\n return json;\n }\n getInTxPool() {\n return this.inTxPool;\n }\n setInTxPool(inTxPool) {\n this.inTxPool = inTxPool;\n return this;\n }\n getNumConfirmations() {\n return this.numConfirmations;\n }\n setNumConfirmations(numConfirmations) {\n this.numConfirmations = numConfirmations;\n return this;\n }\n getReceivedAmount() {\n return this.receivedAmount;\n }\n setReceivedAmount(receivedAmount) {\n this.receivedAmount = receivedAmount;\n return this;\n }\n}\n","import MoneroCheck from \"./MoneroCheck\";\n/**\n * Results from checking a reserve proof.\n */\nexport default class MoneroCheckReserve extends MoneroCheck {\n constructor(check) {\n super(check);\n if (this.totalAmount !== undefined && typeof this.totalAmount !== \"bigint\")\n this.totalAmount = BigInt(this.totalAmount);\n if (this.unconfirmedSpentAmount !== undefined && typeof this.unconfirmedSpentAmount !== \"bigint\")\n this.unconfirmedSpentAmount = BigInt(this.unconfirmedSpentAmount);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (this.getTotalAmount() !== undefined)\n json.totalAmount = this.getTotalAmount().toString();\n if (this.getUnconfirmedSpentAmount() !== undefined)\n json.unconfirmedSpentAmount = this.getUnconfirmedSpentAmount().toString();\n return json;\n }\n getTotalAmount() {\n return this.totalAmount;\n }\n setTotalAmount(totalAmount) {\n this.totalAmount = totalAmount;\n return this;\n }\n getUnconfirmedSpentAmount() {\n return this.unconfirmedSpentAmount;\n }\n setUnconfirmedSpentAmount(unconfirmedSpentAmount) {\n this.unconfirmedSpentAmount = unconfirmedSpentAmount;\n return this;\n }\n}\n","/**\n * Models results from importing key images.\n */\nexport default class MoneroKeyImageImportResult {\n constructor(result) {\n Object.assign(this, result);\n if (this.spentAmount !== undefined && typeof this.spentAmount !== \"bigint\")\n this.spentAmount = BigInt(this.spentAmount);\n if (this.unspentAmount !== undefined && typeof this.unspentAmount !== \"bigint\")\n this.unspentAmount = BigInt(this.unspentAmount);\n }\n toJson() {\n let json = Object.assign({}, this);\n if (this.getSpentAmount() !== undefined)\n json.spentAmount = this.getSpentAmount().toString();\n if (this.getUnspentAmount() !== undefined)\n json.unspentAmount = this.getUnspentAmount().toString();\n return json;\n }\n getHeight() {\n return this.height;\n }\n setHeight(height) {\n this.height = height;\n return this;\n }\n getSpentAmount() {\n return this.spentAmount;\n }\n setSpentAmount(spentAmount) {\n this.spentAmount = spentAmount;\n return this;\n }\n getUnspentAmount() {\n return this.unspentAmount;\n }\n setUnspentAmount(unspentAmount) {\n this.unspentAmount = unspentAmount;\n return this;\n }\n}\n","/**\n * Models information about a multisig wallet.\n */\nexport default class MoneroMultisigInfo {\n constructor(multisigInfo) {\n Object.assign(this, multisigInfo);\n }\n toJson() {\n return Object.assign({}, this);\n }\n getIsMultisig() {\n return this.isMultisig;\n }\n setIsMultisig(isMultisig) {\n this.isMultisig = isMultisig;\n return this;\n }\n getIsReady() {\n return this.isReady;\n }\n setIsReady(isReady) {\n this.isReady = isReady;\n return this;\n }\n getThreshold() {\n return this.threshold;\n }\n setThreshold(threshold) {\n this.threshold = threshold;\n return this;\n }\n getNumParticipants() {\n return this.numParticipants;\n }\n setNumParticipants(numParticipants) {\n this.numParticipants = numParticipants;\n return this;\n }\n}\n","/**\n * Models the result of initializing a multisig wallet which results in the\n * multisig wallet's address xor another multisig hex to share with\n * participants to create the wallet.\n */\nexport default class MoneroMultisigInitResult {\n constructor(result) {\n Object.assign(this, result);\n }\n toJson() {\n return Object.assign({}, this);\n }\n getAddress() {\n return this.address;\n }\n setAddress(address) {\n this.address = address;\n return this;\n }\n getMultisigHex() {\n return this.multisigHex;\n }\n setMultisigHex(multisigHex) {\n this.multisigHex = multisigHex;\n return this;\n }\n}\n","/**\n * Models the result of signing multisig tx hex.\n */\nexport default class MoneroMultisigSignResult {\n constructor(result) {\n Object.assign(this, result);\n }\n toJson() {\n return Object.assign({}, this);\n }\n getSignedMultisigTxHex() {\n return this.signedMultisigTxHex;\n }\n setSignedMultisigTxHex(signedTxMultisigHex) {\n this.signedMultisigTxHex = signedTxMultisigHex;\n return this;\n }\n getTxHashes() {\n return this.txHashes;\n }\n setTxHashes(txHashes) {\n this.txHashes = txHashes;\n return this;\n }\n}\n","/**\n * Result from syncing a Monero wallet.\n */\nexport default class MoneroSyncResult {\n constructor(numBlocksFetched, receivedMoney) {\n this.setNumBlocksFetched(numBlocksFetched);\n this.setReceivedMoney(receivedMoney);\n }\n getNumBlocksFetched() {\n return this.numBlocksFetched;\n }\n setNumBlocksFetched(numBlocksFetched) {\n this.numBlocksFetched = numBlocksFetched;\n return this;\n }\n getReceivedMoney() {\n return this.receivedMoney;\n }\n setReceivedMoney(receivedMoney) {\n this.receivedMoney = receivedMoney;\n return this;\n }\n}\n","/**\n * Message signature verification result.\n */\nexport default class MoneroMessageSignatureResult {\n constructor(result) {\n Object.assign(this, result);\n }\n toJson() {\n return Object.assign({}, this);\n }\n getIsGood() {\n return this.isGood;\n }\n setIsGood(isGood) {\n this.isGood = isGood;\n return this;\n }\n getIsOld() {\n return this.isOld;\n }\n setIsOld(isOld) {\n this.isOld = isOld;\n return this;\n }\n getSignatureType() {\n return this.signatureType;\n }\n setSignatureType(signatureType) {\n this.signatureType = signatureType;\n return this;\n }\n getVersion() {\n return this.version;\n }\n setVersion(version) {\n this.version = version;\n return this;\n }\n}\n","import assert from \"assert\";\nimport Path from \"path\";\nimport GenUtils from \"../common/GenUtils\";\nimport LibraryUtils from \"../common/LibraryUtils\";\nimport TaskLooper from \"../common/TaskLooper\";\nimport MoneroAccount from \"./model/MoneroAccount\";\nimport MoneroAccountTag from \"./model/MoneroAccountTag\";\nimport MoneroAddressBookEntry from \"./model/MoneroAddressBookEntry\";\nimport MoneroBlock from \"../daemon/model/MoneroBlock\";\nimport MoneroCheckTx from \"./model/MoneroCheckTx\";\nimport MoneroCheckReserve from \"./model/MoneroCheckReserve\";\nimport MoneroDaemonRpc from \"../daemon/MoneroDaemonRpc\";\nimport MoneroError from \"../common/MoneroError\";\nimport MoneroIntegratedAddress from \"./model/MoneroIntegratedAddress\";\nimport MoneroKeyImage from \"../daemon/model/MoneroKeyImage\";\nimport MoneroKeyImageImportResult from \"./model/MoneroKeyImageImportResult\";\nimport MoneroMultisigInfo from \"./model/MoneroMultisigInfo\";\nimport MoneroMultisigInitResult from \"./model/MoneroMultisigInitResult\";\nimport MoneroMultisigSignResult from \"./model/MoneroMultisigSignResult\";\nimport MoneroNetworkType from \"../daemon/model/MoneroNetworkType\";\nimport MoneroOutputWallet from \"./model/MoneroOutputWallet\";\nimport MoneroRpcConnection from \"../common/MoneroRpcConnection\";\nimport MoneroSubaddress from \"./model/MoneroSubaddress\";\nimport MoneroSyncResult from \"./model/MoneroSyncResult\";\nimport MoneroTxConfig from \"./model/MoneroTxConfig\";\nimport MoneroTxSet from \"./model/MoneroTxSet\";\nimport MoneroTxWallet from \"./model/MoneroTxWallet\";\nimport MoneroWallet from \"./MoneroWallet\";\nimport MoneroWalletConfig from \"./model/MoneroWalletConfig\";\nimport { MoneroWalletKeys, MoneroWalletKeysProxy } from \"./MoneroWalletKeys\";\nimport MoneroWalletListener from \"./model/MoneroWalletListener\";\nimport MoneroMessageSignatureType from \"./model/MoneroMessageSignatureType\";\nimport MoneroMessageSignatureResult from \"./model/MoneroMessageSignatureResult\";\nimport fs from \"fs\";\n/**\n * Implements a Monero wallet using client-side WebAssembly bindings to monero-project's wallet2 in C++.\n */\nclass MoneroWalletFull extends MoneroWalletKeys {\n /**\n * Internal constructor which is given the memory address of a C++ wallet instance.\n *\n * This constructor should be called through static wallet creation utilities in this class.\n *\n * @param {number} cppAddress - address of the wallet instance in C++\n * @param {string} path - path of the wallet instance\n * @param {string} password - password of the wallet instance\n * @param {FileSystem} fs - node.js-compatible file system to read/write wallet files\n * @param {boolean} rejectUnauthorized - specifies if unauthorized requests (e.g. self-signed certificates) should be rejected\n * @param {string} rejectUnauthorizedFnId - unique identifier for http_client_wasm to query rejectUnauthorized\n * @param {MoneroWalletFullProxy} walletProxy - proxy to invoke wallet operations in a web worker\n *\n * @private\n */\n constructor(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId, walletProxy) {\n super(cppAddress, walletProxy);\n if (walletProxy)\n return;\n this.path = path;\n this.password = password;\n this.listeners = [];\n this.fs = fs ? fs : (path ? MoneroWalletFull.getFs() : undefined);\n this._isClosed = false;\n this.wasmListener = new WalletWasmListener(this); // receives notifications from wasm c++\n this.wasmListenerHandle = 0; // memory address of the wallet listener in c++\n this.rejectUnauthorized = rejectUnauthorized;\n this.rejectUnauthorizedConfigId = rejectUnauthorizedFnId;\n this.syncPeriodInMs = MoneroWalletFull.DEFAULT_SYNC_PERIOD_IN_MS;\n LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => this.rejectUnauthorized); // register fn informing if unauthorized reqs should be rejected\n }\n // --------------------------- STATIC UTILITIES -----------------------------\n /**\n * Check if a wallet exists at a given path.\n *\n * @param {string} path - path of the wallet on the file system\n * @param {any} fs - file system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser)\n * @return {boolean} true if a wallet exists at the given path, false otherwise\n */\n static async walletExists(path, fs) {\n assert(path, \"Must provide a path to look for a wallet\");\n if (!fs)\n fs = MoneroWalletFull.getFs();\n if (!fs)\n throw new MoneroError(\"Must provide file system to check if wallet exists\");\n let exists = await LibraryUtils.exists(fs, path + \".keys\");\n LibraryUtils.log(1, \"Wallet exists at \" + path + \": \" + exists);\n return exists;\n }\n static async openWallet(config) {\n // validate config\n config = new MoneroWalletConfig(config);\n if (config.getProxyToWorker() === undefined)\n config.setProxyToWorker(true);\n if (config.getSeed() !== undefined)\n throw new MoneroError(\"Cannot specify seed when opening wallet\");\n if (config.getSeedOffset() !== undefined)\n throw new MoneroError(\"Cannot specify seed offset when opening wallet\");\n if (config.getPrimaryAddress() !== undefined)\n throw new MoneroError(\"Cannot specify primary address when opening wallet\");\n if (config.getPrivateViewKey() !== undefined)\n throw new MoneroError(\"Cannot specify private view key when opening wallet\");\n if (config.getPrivateSpendKey() !== undefined)\n throw new MoneroError(\"Cannot specify private spend key when opening wallet\");\n if (config.getRestoreHeight() !== undefined)\n throw new MoneroError(\"Cannot specify restore height when opening wallet\");\n if (config.getLanguage() !== undefined)\n throw new MoneroError(\"Cannot specify language when opening wallet\");\n if (config.getSaveCurrent() === true)\n throw new MoneroError(\"Cannot save current wallet when opening full wallet\");\n if (config.getFs() === undefined)\n config.setFs(MoneroWalletFull.getFs());\n // set server from connection manager if provided\n if (config.getConnectionManager()) {\n if (config.getServer())\n throw new MoneroError(\"Wallet can be opened with a server or connection manager but not both\");\n config.setServer(config.getConnectionManager().getConnection());\n }\n // read wallet data from disk unless provided\n if (!config.getKeysData()) {\n let fs = config.getFs();\n if (!fs)\n throw new MoneroError(\"Must provide file system to read wallet data from\");\n if (!await this.walletExists(config.getPath(), fs))\n throw new MoneroError(\"Wallet does not exist at path: \" + config.getPath());\n config.setKeysData(await fs.readFile(config.getPath() + \".keys\"));\n config.setCacheData(await LibraryUtils.exists(fs, config.getPath()) ? await fs.readFile(config.getPath()) : \"\");\n }\n // open wallet from data\n const wallet = await MoneroWalletFull.openWalletData(config);\n // set connection manager\n await wallet.setConnectionManager(config.getConnectionManager());\n return wallet;\n }\n static async createWallet(config) {\n // validate config\n if (config === undefined)\n throw new MoneroError(\"Must provide config to create wallet\");\n if (config.getSeed() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined))\n throw new MoneroError(\"Wallet may be initialized with a seed or keys but not both\");\n if (config.getNetworkType() === undefined)\n throw new MoneroError(\"Must provide a networkType: 'mainnet', 'testnet' or 'stagenet'\");\n MoneroNetworkType.validate(config.getNetworkType());\n if (config.getSaveCurrent() === true)\n throw new MoneroError(\"Cannot save current wallet when creating full WASM wallet\");\n if (config.getPath() === undefined)\n config.setPath(\"\");\n if (config.getPath() && await MoneroWalletFull.walletExists(config.getPath(), config.getFs()))\n throw new MoneroError(\"Wallet already exists: \" + config.getPath());\n if (config.getPassword() === undefined)\n config.setPassword(\"\");\n // set server from connection manager if provided\n if (config.getConnectionManager()) {\n if (config.getServer())\n throw new MoneroError(\"Wallet can be created with a server or connection manager but not both\");\n config.setServer(config.getConnectionManager().getConnection());\n }\n // create proxied or local wallet\n let wallet;\n if (config.getProxyToWorker() === undefined)\n config.setProxyToWorker(true);\n if (config.getProxyToWorker()) {\n let walletProxy = await MoneroWalletFullProxy.createWallet(config);\n wallet = new MoneroWalletFull(undefined, undefined, undefined, undefined, undefined, undefined, walletProxy);\n }\n else {\n if (config.getSeed() !== undefined) {\n if (config.getLanguage() !== undefined)\n throw new MoneroError(\"Cannot provide language when creating wallet from seed\");\n wallet = await MoneroWalletFull.createWalletFromSeed(config);\n }\n else if (config.getPrivateSpendKey() !== undefined || config.getPrimaryAddress() !== undefined) {\n if (config.getSeedOffset() !== undefined)\n throw new MoneroError(\"Cannot provide seedOffset when creating wallet from keys\");\n wallet = await MoneroWalletFull.createWalletFromKeys(config);\n }\n else {\n if (config.getSeedOffset() !== undefined)\n throw new MoneroError(\"Cannot provide seedOffset when creating random wallet\");\n if (config.getRestoreHeight() !== undefined)\n throw new MoneroError(\"Cannot provide restoreHeight when creating random wallet\");\n wallet = await MoneroWalletFull.createWalletRandom(config);\n }\n }\n // set connection manager\n await wallet.setConnectionManager(config.getConnectionManager());\n return wallet;\n }\n static async createWalletFromSeed(config) {\n // validate and normalize params\n let daemonConnection = config.getServer();\n let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true;\n if (config.getRestoreHeight() === undefined)\n config.setRestoreHeight(0);\n if (config.getSeedOffset() === undefined)\n config.setSeedOffset(\"\");\n // load full wasm module\n let module = await LibraryUtils.loadWasmModule();\n // create wallet in queue\n let wallet = await module.queueTask(async () => {\n return new Promise((resolve, reject) => {\n // register fn informing if unauthorized reqs should be rejected\n let rejectUnauthorizedFnId = GenUtils.getUUID();\n LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => rejectUnauthorized);\n // create wallet in wasm which invokes callback when done\n module.create_full_wallet(JSON.stringify(config.toJson()), rejectUnauthorizedFnId, async (cppAddress) => {\n if (typeof cppAddress === \"string\")\n reject(new MoneroError(cppAddress));\n else\n resolve(new MoneroWalletFull(cppAddress, config.getPath(), config.getPassword(), config.getFs(), config.getServer() ? config.getServer().getRejectUnauthorized() : undefined, rejectUnauthorizedFnId));\n });\n });\n });\n // save wallet\n if (config.getPath())\n await wallet.save();\n return wallet;\n }\n static async createWalletFromKeys(config) {\n // validate and normalize params\n MoneroNetworkType.validate(config.getNetworkType());\n if (config.getPrimaryAddress() === undefined)\n config.setPrimaryAddress(\"\");\n if (config.getPrivateViewKey() === undefined)\n config.setPrivateViewKey(\"\");\n if (config.getPrivateSpendKey() === undefined)\n config.setPrivateSpendKey(\"\");\n let daemonConnection = config.getServer();\n let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true;\n if (config.getRestoreHeight() === undefined)\n config.setRestoreHeight(0);\n if (config.getLanguage() === undefined)\n config.setLanguage(\"English\");\n // load full wasm module\n let module = await LibraryUtils.loadWasmModule();\n // create wallet in queue\n let wallet = await module.queueTask(async () => {\n return new Promise((resolve, reject) => {\n // register fn informing if unauthorized reqs should be rejected\n let rejectUnauthorizedFnId = GenUtils.getUUID();\n LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => rejectUnauthorized);\n // create wallet in wasm which invokes callback when done\n module.create_full_wallet(JSON.stringify(config.toJson()), rejectUnauthorizedFnId, async (cppAddress) => {\n if (typeof cppAddress === \"string\")\n reject(new MoneroError(cppAddress));\n else\n resolve(new MoneroWalletFull(cppAddress, config.getPath(), config.getPassword(), config.getFs(), config.getServer() ? config.getServer().getRejectUnauthorized() : undefined, rejectUnauthorizedFnId));\n });\n });\n });\n // save wallet\n if (config.getPath())\n await wallet.save();\n return wallet;\n }\n static async createWalletRandom(config) {\n // validate and normalize params\n if (config.getLanguage() === undefined)\n config.setLanguage(\"English\");\n let daemonConnection = config.getServer();\n let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true;\n // load wasm module\n let module = await LibraryUtils.loadWasmModule();\n // create wallet in queue\n let wallet = await module.queueTask(async () => {\n return new Promise((resolve, reject) => {\n // register fn informing if unauthorized reqs should be rejected\n let rejectUnauthorizedFnId = GenUtils.getUUID();\n LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => rejectUnauthorized);\n // create wallet in wasm which invokes callback when done\n module.create_full_wallet(JSON.stringify(config.toJson()), rejectUnauthorizedFnId, async (cppAddress) => {\n if (typeof cppAddress === \"string\")\n reject(new MoneroError(cppAddress));\n else\n resolve(new MoneroWalletFull(cppAddress, config.getPath(), config.getPassword(), config.getFs(), config.getServer() ? config.getServer().getRejectUnauthorized() : undefined, rejectUnauthorizedFnId));\n });\n });\n });\n // save wallet\n if (config.getPath())\n await wallet.save();\n return wallet;\n }\n static async getSeedLanguages() {\n let module = await LibraryUtils.loadWasmModule();\n return module.queueTask(async () => {\n return JSON.parse(module.get_keys_wallet_seed_languages()).languages;\n });\n }\n static getFs() {\n if (!MoneroWalletFull.FS)\n MoneroWalletFull.FS = fs.promises;\n return MoneroWalletFull.FS;\n }\n // ------------ WALLET METHODS SPECIFIC TO WASM IMPLEMENTATION --------------\n // TODO: move these to MoneroWallet.ts, others can be unsupported\n /**\n * Get the maximum height of the peers the wallet's daemon is connected to.\n *\n * @return {Promise} the maximum height of the peers the wallet's daemon is connected to\n */\n async getDaemonMaxPeerHeight() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getDaemonMaxPeerHeight();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n // call wasm which invokes callback when done\n this.module.get_daemon_max_peer_height(this.cppAddress, (resp) => {\n resolve(resp);\n });\n });\n });\n }\n /**\n * Indicates if the wallet's daemon is synced with the network.\n *\n * @return {Promise} true if the daemon is synced with the network, false otherwise\n */\n async isDaemonSynced() {\n if (this.getWalletProxy())\n return this.getWalletProxy().isDaemonSynced();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n // call wasm which invokes callback when done\n this.module.is_daemon_synced(this.cppAddress, (resp) => {\n resolve(resp);\n });\n });\n });\n }\n /**\n * Indicates if the wallet is synced with the daemon.\n *\n * @return {Promise} true if the wallet is synced with the daemon, false otherwise\n */\n async isSynced() {\n if (this.getWalletProxy())\n return this.getWalletProxy().isSynced();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.is_synced(this.cppAddress, (resp) => {\n resolve(resp);\n });\n });\n });\n }\n /**\n * Get the wallet's network type (mainnet, testnet, or stagenet).\n *\n * @return {Promise} the wallet's network type\n */\n async getNetworkType() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getNetworkType();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return this.module.get_network_type(this.cppAddress);\n });\n }\n /**\n * Get the height of the first block that the wallet scans.\n *\n * @return {Promise} the height of the first block that the wallet scans\n */\n async getRestoreHeight() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getRestoreHeight();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return this.module.get_restore_height(this.cppAddress);\n });\n }\n /**\n * Set the height of the first block that the wallet scans.\n *\n * @param {number} restoreHeight - height of the first block that the wallet scans\n * @return {Promise}\n */\n async setRestoreHeight(restoreHeight) {\n if (this.getWalletProxy())\n return this.getWalletProxy().setRestoreHeight(restoreHeight);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n this.module.set_restore_height(this.cppAddress, restoreHeight);\n });\n }\n /**\n * Move the wallet from its current path to the given path.\n *\n * @param {string} path - the wallet's destination path\n * @return {Promise}\n */\n async moveTo(path) {\n if (this.getWalletProxy())\n return this.getWalletProxy().moveTo(path);\n return MoneroWalletFull.moveTo(path, this);\n }\n // -------------------------- COMMON WALLET METHODS -------------------------\n async addListener(listener) {\n if (this.getWalletProxy())\n return this.getWalletProxy().addListener(listener);\n await super.addListener(listener);\n await this.refreshListening();\n }\n async removeListener(listener) {\n if (this.getWalletProxy())\n return this.getWalletProxy().removeListener(listener);\n await super.removeListener(listener);\n await this.refreshListening();\n }\n getListeners() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getListeners();\n return super.getListeners();\n }\n async setDaemonConnection(uriOrConnection) {\n if (this.getWalletProxy())\n return this.getWalletProxy().setDaemonConnection(uriOrConnection);\n // normalize connection\n let connection = !uriOrConnection ? undefined : uriOrConnection instanceof MoneroRpcConnection ? uriOrConnection : new MoneroRpcConnection(uriOrConnection);\n let uri = connection && connection.getUri() ? connection.getUri() : \"\";\n let username = connection && connection.getUsername() ? connection.getUsername() : \"\";\n let password = connection && connection.getPassword() ? connection.getPassword() : \"\";\n let proxyUri = connection && connection.getProxyUri() ? connection.getProxyUri() : \"\";\n let rejectUnauthorized = connection ? connection.getRejectUnauthorized() : undefined;\n this.rejectUnauthorized = rejectUnauthorized; // persist locally\n // set connection in queue\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.set_daemon_connection(this.cppAddress, uri, username, password, proxyUri, (resp) => {\n resolve();\n });\n });\n });\n }\n async getDaemonConnection() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getDaemonConnection();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n let connectionContainerStr = this.module.get_daemon_connection(this.cppAddress);\n if (!connectionContainerStr)\n resolve(undefined);\n else {\n let jsonConnection = JSON.parse(connectionContainerStr);\n resolve(new MoneroRpcConnection({ uri: jsonConnection.uri, username: jsonConnection.username, password: jsonConnection.password, proxyUri: jsonConnection.proxyUri, rejectUnauthorized: this.rejectUnauthorized }));\n }\n });\n });\n }\n async isConnectedToDaemon() {\n if (this.getWalletProxy())\n return this.getWalletProxy().isConnectedToDaemon();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.is_connected_to_daemon(this.cppAddress, (resp) => {\n resolve(resp);\n });\n });\n });\n }\n async getVersion() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getVersion();\n throw new MoneroError(\"Not implemented\");\n }\n async getPath() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getPath();\n return this.path;\n }\n async getIntegratedAddress(standardAddress, paymentId) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getIntegratedAddress(standardAddress, paymentId);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n try {\n let result = this.module.get_integrated_address(this.cppAddress, standardAddress ? standardAddress : \"\", paymentId ? paymentId : \"\");\n if (result.charAt(0) !== '{')\n throw new MoneroError(result);\n return new MoneroIntegratedAddress(JSON.parse(result));\n }\n catch (err) {\n if (err.message.includes(\"Invalid payment ID\"))\n throw new MoneroError(\"Invalid payment ID: \" + paymentId);\n throw new MoneroError(err.message);\n }\n });\n }\n async decodeIntegratedAddress(integratedAddress) {\n if (this.getWalletProxy())\n return this.getWalletProxy().decodeIntegratedAddress(integratedAddress);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n try {\n let result = this.module.decode_integrated_address(this.cppAddress, integratedAddress);\n if (result.charAt(0) !== '{')\n throw new MoneroError(result);\n return new MoneroIntegratedAddress(JSON.parse(result));\n }\n catch (err) {\n throw new MoneroError(err.message);\n }\n });\n }\n async getHeight() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getHeight();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.get_height(this.cppAddress, (resp) => {\n resolve(resp);\n });\n });\n });\n }\n async getDaemonHeight() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getDaemonHeight();\n if (!await this.isConnectedToDaemon())\n throw new MoneroError(\"Wallet is not connected to daemon\");\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.get_daemon_height(this.cppAddress, (resp) => {\n resolve(resp);\n });\n });\n });\n }\n async getHeightByDate(year, month, day) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getHeightByDate(year, month, day);\n if (!await this.isConnectedToDaemon())\n throw new MoneroError(\"Wallet is not connected to daemon\");\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.get_height_by_date(this.cppAddress, year, month, day, (resp) => {\n if (typeof resp === \"string\")\n reject(new MoneroError(resp));\n else\n resolve(resp);\n });\n });\n });\n }\n /**\n * Synchronize the wallet with the daemon as a one-time synchronous process.\n *\n * @param {MoneroWalletListener|number} [listenerOrStartHeight] - listener xor start height (defaults to no sync listener, the last synced block)\n * @param {number} [startHeight] - startHeight if not given in first arg (defaults to last synced block)\n * @param {boolean} [allowConcurrentCalls] - allow other wallet methods to be processed simultaneously during sync (default false)

WARNING: enabling this option will crash wallet execution if another call makes a simultaneous network request. TODO: possible to sync wasm network requests in http_client_wasm.cpp?\n */\n async sync(listenerOrStartHeight, startHeight, allowConcurrentCalls = false) {\n if (this.getWalletProxy())\n return this.getWalletProxy().sync(listenerOrStartHeight, startHeight, allowConcurrentCalls);\n if (!await this.isConnectedToDaemon())\n throw new MoneroError(\"Wallet is not connected to daemon\");\n // normalize params\n startHeight = listenerOrStartHeight === undefined || listenerOrStartHeight instanceof MoneroWalletListener ? startHeight : listenerOrStartHeight;\n let listener = listenerOrStartHeight instanceof MoneroWalletListener ? listenerOrStartHeight : undefined;\n if (startHeight === undefined)\n startHeight = Math.max(await this.getHeight(), await this.getRestoreHeight());\n // register listener if given\n if (listener)\n await this.addListener(listener);\n // sync wallet\n let err;\n let result;\n try {\n let that = this;\n result = await (allowConcurrentCalls ? syncWasm() : this.module.queueTask(async () => syncWasm()));\n function syncWasm() {\n that.assertNotClosed();\n return new Promise((resolve, reject) => {\n // sync wallet in wasm which invokes callback when done\n that.module.sync(that.cppAddress, startHeight, async (resp) => {\n if (resp.charAt(0) !== '{')\n reject(new MoneroError(resp));\n else {\n let respJson = JSON.parse(resp);\n resolve(new MoneroSyncResult(respJson.numBlocksFetched, respJson.receivedMoney));\n }\n });\n });\n }\n }\n catch (e) {\n err = e;\n }\n // unregister listener\n if (listener)\n await this.removeListener(listener);\n // throw error or return\n if (err)\n throw err;\n return result;\n }\n async startSyncing(syncPeriodInMs) {\n if (this.getWalletProxy())\n return this.getWalletProxy().startSyncing(syncPeriodInMs);\n if (!await this.isConnectedToDaemon())\n throw new MoneroError(\"Wallet is not connected to daemon\");\n this.syncPeriodInMs = syncPeriodInMs === undefined ? MoneroWalletFull.DEFAULT_SYNC_PERIOD_IN_MS : syncPeriodInMs;\n if (!this.syncLooper)\n this.syncLooper = new TaskLooper(async () => await this.backgroundSync());\n this.syncLooper.start(this.syncPeriodInMs);\n }\n async stopSyncing() {\n if (this.getWalletProxy())\n return this.getWalletProxy().stopSyncing();\n this.assertNotClosed();\n if (this.syncLooper)\n this.syncLooper.stop();\n this.module.stop_syncing(this.cppAddress); // task is not queued so wallet stops immediately\n }\n async scanTxs(txHashes) {\n if (this.getWalletProxy())\n return this.getWalletProxy().scanTxs(txHashes);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.scan_txs(this.cppAddress, JSON.stringify({ txHashes: txHashes }), (err) => {\n if (err)\n reject(new MoneroError(err));\n else\n resolve();\n });\n });\n });\n }\n async rescanSpent() {\n if (this.getWalletProxy())\n return this.getWalletProxy().rescanSpent();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.rescan_spent(this.cppAddress, () => resolve());\n });\n });\n }\n async rescanBlockchain() {\n if (this.getWalletProxy())\n return this.getWalletProxy().rescanBlockchain();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.rescan_blockchain(this.cppAddress, () => resolve());\n });\n });\n }\n async getBalance(accountIdx, subaddressIdx) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getBalance(accountIdx, subaddressIdx);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n // get balance encoded in json string\n let balanceStr;\n if (accountIdx === undefined) {\n assert(subaddressIdx === undefined, \"Subaddress index must be undefined if account index is undefined\");\n balanceStr = this.module.get_balance_wallet(this.cppAddress);\n }\n else if (subaddressIdx === undefined) {\n balanceStr = this.module.get_balance_account(this.cppAddress, accountIdx);\n }\n else {\n balanceStr = this.module.get_balance_subaddress(this.cppAddress, accountIdx, subaddressIdx);\n }\n // parse json string to bigint\n return BigInt(JSON.parse(GenUtils.stringifyBigInts(balanceStr)).balance);\n });\n }\n async getUnlockedBalance(accountIdx, subaddressIdx) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getUnlockedBalance(accountIdx, subaddressIdx);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n // get balance encoded in json string\n let unlockedBalanceStr;\n if (accountIdx === undefined) {\n assert(subaddressIdx === undefined, \"Subaddress index must be undefined if account index is undefined\");\n unlockedBalanceStr = this.module.get_unlocked_balance_wallet(this.cppAddress);\n }\n else if (subaddressIdx === undefined) {\n unlockedBalanceStr = this.module.get_unlocked_balance_account(this.cppAddress, accountIdx);\n }\n else {\n unlockedBalanceStr = this.module.get_unlocked_balance_subaddress(this.cppAddress, accountIdx, subaddressIdx);\n }\n // parse json string to bigint\n return BigInt(JSON.parse(GenUtils.stringifyBigInts(unlockedBalanceStr)).unlockedBalance);\n });\n }\n async getAccounts(includeSubaddresses, tag) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getAccounts(includeSubaddresses, tag);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let accountsStr = this.module.get_accounts(this.cppAddress, includeSubaddresses ? true : false, tag ? tag : \"\");\n let accounts = [];\n for (let accountJson of JSON.parse(GenUtils.stringifyBigInts(accountsStr)).accounts) {\n accounts.push(MoneroWalletFull.sanitizeAccount(new MoneroAccount(accountJson)));\n }\n return accounts;\n });\n }\n async getAccount(accountIdx, includeSubaddresses) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getAccount(accountIdx, includeSubaddresses);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let accountStr = this.module.get_account(this.cppAddress, accountIdx, includeSubaddresses ? true : false);\n let accountJson = JSON.parse(GenUtils.stringifyBigInts(accountStr));\n return MoneroWalletFull.sanitizeAccount(new MoneroAccount(accountJson));\n });\n }\n async createAccount(label) {\n if (this.getWalletProxy())\n return this.getWalletProxy().createAccount(label);\n if (label === undefined)\n label = \"\";\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let accountStr = this.module.create_account(this.cppAddress, label);\n let accountJson = JSON.parse(GenUtils.stringifyBigInts(accountStr));\n return MoneroWalletFull.sanitizeAccount(new MoneroAccount(accountJson));\n });\n }\n async getSubaddresses(accountIdx, subaddressIndices) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getSubaddresses(accountIdx, subaddressIndices);\n let args = { accountIdx: accountIdx, subaddressIndices: subaddressIndices === undefined ? [] : GenUtils.listify(subaddressIndices) };\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let subaddressesJson = JSON.parse(GenUtils.stringifyBigInts(this.module.get_subaddresses(this.cppAddress, JSON.stringify(args)))).subaddresses;\n let subaddresses = [];\n for (let subaddressJson of subaddressesJson)\n subaddresses.push(MoneroWalletKeys.sanitizeSubaddress(new MoneroSubaddress(subaddressJson)));\n return subaddresses;\n });\n }\n async createSubaddress(accountIdx, label) {\n if (this.getWalletProxy())\n return this.getWalletProxy().createSubaddress(accountIdx, label);\n if (label === undefined)\n label = \"\";\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let subaddressStr = this.module.create_subaddress(this.cppAddress, accountIdx, label);\n let subaddressJson = JSON.parse(GenUtils.stringifyBigInts(subaddressStr));\n return MoneroWalletKeys.sanitizeSubaddress(new MoneroSubaddress(subaddressJson));\n });\n }\n async setSubaddressLabel(accountIdx, subaddressIdx, label) {\n if (this.getWalletProxy())\n return this.getWalletProxy().setSubaddressLabel(accountIdx, subaddressIdx, label);\n if (label === undefined)\n label = \"\";\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n this.module.set_subaddress_label(this.cppAddress, accountIdx, subaddressIdx, label);\n });\n }\n async getTxs(query) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getTxs(query);\n // copy and normalize query up to block\n const queryNormalized = query = MoneroWallet.normalizeTxQuery(query);\n // schedule task\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n // call wasm which invokes callback\n this.module.get_txs(this.cppAddress, JSON.stringify(queryNormalized.getBlock().toJson()), (blocksJsonStr) => {\n // check for error\n if (blocksJsonStr.charAt(0) !== '{') {\n reject(new MoneroError(blocksJsonStr));\n return;\n }\n // resolve with deserialized txs\n try {\n resolve(MoneroWalletFull.deserializeTxs(queryNormalized, blocksJsonStr));\n }\n catch (err) {\n reject(err);\n }\n });\n });\n });\n }\n async getTransfers(query) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getTransfers(query);\n // copy and normalize query up to block\n const queryNormalized = MoneroWallet.normalizeTransferQuery(query);\n // return promise which resolves on callback\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n // call wasm which invokes callback\n this.module.get_transfers(this.cppAddress, JSON.stringify(queryNormalized.getTxQuery().getBlock().toJson()), (blocksJsonStr) => {\n // check for error\n if (blocksJsonStr.charAt(0) !== '{') {\n reject(new MoneroError(blocksJsonStr));\n return;\n }\n // resolve with deserialized transfers \n try {\n resolve(MoneroWalletFull.deserializeTransfers(queryNormalized, blocksJsonStr));\n }\n catch (err) {\n reject(err);\n }\n });\n });\n });\n }\n async getOutputs(query) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getOutputs(query);\n // copy and normalize query up to block\n const queryNormalized = MoneroWallet.normalizeOutputQuery(query);\n // return promise which resolves on callback\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n // call wasm which invokes callback\n this.module.get_outputs(this.cppAddress, JSON.stringify(queryNormalized.getTxQuery().getBlock().toJson()), (blocksJsonStr) => {\n // check for error\n if (blocksJsonStr.charAt(0) !== '{') {\n reject(new MoneroError(blocksJsonStr));\n return;\n }\n // resolve with deserialized outputs\n try {\n resolve(MoneroWalletFull.deserializeOutputs(queryNormalized, blocksJsonStr));\n }\n catch (err) {\n reject(err);\n }\n });\n });\n });\n }\n async exportOutputs(all = false) {\n if (this.getWalletProxy())\n return this.getWalletProxy().exportOutputs(all);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.export_outputs(this.cppAddress, all, (outputsHex) => resolve(outputsHex));\n });\n });\n }\n async importOutputs(outputsHex) {\n if (this.getWalletProxy())\n return this.getWalletProxy().importOutputs(outputsHex);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.import_outputs(this.cppAddress, outputsHex, (numImported) => resolve(numImported));\n });\n });\n }\n async exportKeyImages(all = false) {\n if (this.getWalletProxy())\n return this.getWalletProxy().exportKeyImages(all);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.export_key_images(this.cppAddress, all, (keyImagesStr) => {\n if (keyImagesStr.charAt(0) !== '{')\n reject(new MoneroError(keyImagesStr)); // json expected, else error\n else {\n let keyImages = [];\n for (let keyImageJson of JSON.parse(GenUtils.stringifyBigInts(keyImagesStr)).keyImages)\n keyImages.push(new MoneroKeyImage(keyImageJson));\n resolve(keyImages);\n }\n });\n });\n });\n }\n async importKeyImages(keyImages) {\n if (this.getWalletProxy())\n return this.getWalletProxy().importKeyImages(keyImages);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.import_key_images(this.cppAddress, JSON.stringify({ keyImages: keyImages.map(keyImage => keyImage.toJson()) }), (keyImageImportResultStr) => {\n if (keyImageImportResultStr.charAt(0) !== '{')\n reject(new MoneroError(keyImageImportResultStr)); // json expected, else error\n else\n resolve(new MoneroKeyImageImportResult(JSON.parse(GenUtils.stringifyBigInts(keyImageImportResultStr))));\n });\n });\n });\n }\n async getNewKeyImagesFromLastImport() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getNewKeyImagesFromLastImport();\n throw new MoneroError(\"Not implemented\");\n }\n async freezeOutput(keyImage) {\n if (this.getWalletProxy())\n return this.getWalletProxy().freezeOutput(keyImage);\n if (!keyImage)\n throw new MoneroError(\"Must specify key image to freeze\");\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.freeze_output(this.cppAddress, keyImage, () => resolve());\n });\n });\n }\n async thawOutput(keyImage) {\n if (this.getWalletProxy())\n return this.getWalletProxy().thawOutput(keyImage);\n if (!keyImage)\n throw new MoneroError(\"Must specify key image to thaw\");\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.thaw_output(this.cppAddress, keyImage, () => resolve());\n });\n });\n }\n async isOutputFrozen(keyImage) {\n if (this.getWalletProxy())\n return this.getWalletProxy().isOutputFrozen(keyImage);\n if (!keyImage)\n throw new MoneroError(\"Must specify key image to check if frozen\");\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.is_output_frozen(this.cppAddress, keyImage, (result) => resolve(result));\n });\n });\n }\n async getDefaultFeePriority() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getDefaultFeePriority();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.get_default_fee_priority(this.cppAddress, (result) => resolve(result));\n });\n });\n }\n async createTxs(config) {\n if (this.getWalletProxy())\n return this.getWalletProxy().createTxs(config);\n // validate, copy, and normalize config\n const configNormalized = MoneroWallet.normalizeCreateTxsConfig(config);\n if (configNormalized.getCanSplit() === undefined)\n configNormalized.setCanSplit(true);\n // create txs in queue\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n // create txs in wasm which invokes callback when done\n this.module.create_txs(this.cppAddress, JSON.stringify(configNormalized.toJson()), (txSetJsonStr) => {\n if (txSetJsonStr.charAt(0) !== '{')\n reject(new MoneroError(txSetJsonStr)); // json expected, else error\n else\n resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBigInts(txSetJsonStr))).getTxs());\n });\n });\n });\n }\n async sweepOutput(config) {\n if (this.getWalletProxy())\n return this.getWalletProxy().sweepOutput(config);\n // normalize and validate config\n const configNormalized = MoneroWallet.normalizeSweepOutputConfig(config);\n // sweep output in queue\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n // sweep output in wasm which invokes callback when done\n this.module.sweep_output(this.cppAddress, JSON.stringify(configNormalized.toJson()), (txSetJsonStr) => {\n if (txSetJsonStr.charAt(0) !== '{')\n reject(new MoneroError(txSetJsonStr)); // json expected, else error\n else\n resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBigInts(txSetJsonStr))).getTxs()[0]);\n });\n });\n });\n }\n async sweepUnlocked(config) {\n if (this.getWalletProxy())\n return this.getWalletProxy().sweepUnlocked(config);\n // validate and normalize config\n const configNormalized = MoneroWallet.normalizeSweepUnlockedConfig(config);\n // sweep unlocked in queue\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n // sweep unlocked in wasm which invokes callback when done\n this.module.sweep_unlocked(this.cppAddress, JSON.stringify(configNormalized.toJson()), (txSetsJson) => {\n if (txSetsJson.charAt(0) !== '{')\n reject(new MoneroError(txSetsJson)); // json expected, else error\n else {\n let txSets = [];\n for (let txSetJson of JSON.parse(GenUtils.stringifyBigInts(txSetsJson)).txSets)\n txSets.push(new MoneroTxSet(txSetJson));\n let txs = [];\n for (let txSet of txSets)\n for (let tx of txSet.getTxs())\n txs.push(tx);\n resolve(txs);\n }\n });\n });\n });\n }\n async sweepDust(relay) {\n if (this.getWalletProxy())\n return this.getWalletProxy().sweepDust(relay);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n // call wasm which invokes callback when done\n this.module.sweep_dust(this.cppAddress, relay, (txSetJsonStr) => {\n if (txSetJsonStr.charAt(0) !== '{')\n reject(new MoneroError(txSetJsonStr)); // json expected, else error\n else {\n let txSet = new MoneroTxSet(JSON.parse(GenUtils.stringifyBigInts(txSetJsonStr)));\n if (txSet.getTxs() === undefined)\n txSet.setTxs([]);\n resolve(txSet.getTxs());\n }\n });\n });\n });\n }\n async relayTxs(txsOrMetadatas) {\n if (this.getWalletProxy())\n return this.getWalletProxy().relayTxs(txsOrMetadatas);\n assert(Array.isArray(txsOrMetadatas), \"Must provide an array of txs or their metadata to relay\");\n let txMetadatas = [];\n for (let txOrMetadata of txsOrMetadatas)\n txMetadatas.push(txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.relay_txs(this.cppAddress, JSON.stringify({ txMetadatas: txMetadatas }), (txHashesJson) => {\n if (txHashesJson.charAt(0) !== '{')\n reject(new MoneroError(txHashesJson));\n else\n resolve(JSON.parse(txHashesJson).txHashes);\n });\n });\n });\n }\n async describeTxSet(txSet) {\n if (this.getWalletProxy())\n return this.getWalletProxy().describeTxSet(txSet);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n txSet = new MoneroTxSet({ unsignedTxHex: txSet.getUnsignedTxHex(), signedTxHex: txSet.getSignedTxHex(), multisigTxHex: txSet.getMultisigTxHex() });\n try {\n return new MoneroTxSet(JSON.parse(GenUtils.stringifyBigInts(this.module.describe_tx_set(this.cppAddress, JSON.stringify(txSet.toJson())))));\n }\n catch (err) {\n throw new MoneroError(this.module.get_exception_message(err));\n }\n });\n }\n async signTxs(unsignedTxHex) {\n if (this.getWalletProxy())\n return this.getWalletProxy().signTxs(unsignedTxHex);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n try {\n return new MoneroTxSet(JSON.parse(GenUtils.stringifyBigInts(this.module.sign_txs(this.cppAddress, unsignedTxHex))));\n }\n catch (err) {\n throw new MoneroError(this.module.get_exception_message(err));\n }\n });\n }\n async submitTxs(signedTxHex) {\n if (this.getWalletProxy())\n return this.getWalletProxy().submitTxs(signedTxHex);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.submit_txs(this.cppAddress, signedTxHex, (resp) => {\n if (resp.charAt(0) !== '{')\n reject(new MoneroError(resp));\n else\n resolve(JSON.parse(resp).txHashes);\n });\n });\n });\n }\n async signMessage(message, signatureType = MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY, accountIdx = 0, subaddressIdx = 0) {\n if (this.getWalletProxy())\n return this.getWalletProxy().signMessage(message, signatureType, accountIdx, subaddressIdx);\n // assign defaults\n signatureType = signatureType || MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY;\n accountIdx = accountIdx || 0;\n subaddressIdx = subaddressIdx || 0;\n // queue task to sign message\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n try {\n return this.module.sign_message(this.cppAddress, message, signatureType === MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY ? 0 : 1, accountIdx, subaddressIdx);\n }\n catch (err) {\n throw new MoneroError(this.module.get_exception_message(err));\n }\n });\n }\n async verifyMessage(message, address, signature) {\n if (this.getWalletProxy())\n return this.getWalletProxy().verifyMessage(message, address, signature);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let result;\n try {\n result = JSON.parse(this.module.verify_message(this.cppAddress, message, address, signature));\n }\n catch (err) {\n result = { isGood: false };\n }\n return new MoneroMessageSignatureResult(result.isGood ?\n { isGood: result.isGood, isOld: result.isOld, signatureType: result.signatureType === \"spend\" ? MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY : MoneroMessageSignatureType.SIGN_WITH_VIEW_KEY, version: result.version } :\n { isGood: false });\n });\n }\n async getTxKey(txHash) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getTxKey(txHash);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n try {\n return this.module.get_tx_key(this.cppAddress, txHash);\n }\n catch (err) {\n throw new MoneroError(this.module.get_exception_message(err));\n }\n });\n }\n async checkTxKey(txHash, txKey, address) {\n if (this.getWalletProxy())\n return this.getWalletProxy().checkTxKey(txHash, txKey, address);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.check_tx_key(this.cppAddress, txHash, txKey, address, (respJsonStr) => {\n if (respJsonStr.charAt(0) !== '{')\n reject(new MoneroError(respJsonStr));\n else\n resolve(new MoneroCheckTx(JSON.parse(GenUtils.stringifyBigInts(respJsonStr))));\n });\n });\n });\n }\n async getTxProof(txHash, address, message) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getTxProof(txHash, address, message);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.get_tx_proof(this.cppAddress, txHash || \"\", address || \"\", message || \"\", (signature) => {\n let errorKey = \"error: \";\n if (signature.indexOf(errorKey) === 0)\n reject(new MoneroError(signature.substring(errorKey.length)));\n else\n resolve(signature);\n });\n });\n });\n }\n async checkTxProof(txHash, address, message, signature) {\n if (this.getWalletProxy())\n return this.getWalletProxy().checkTxProof(txHash, address, message, signature);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.check_tx_proof(this.cppAddress, txHash || \"\", address || \"\", message || \"\", signature || \"\", (respJsonStr) => {\n if (respJsonStr.charAt(0) !== '{')\n reject(new MoneroError(respJsonStr));\n else\n resolve(new MoneroCheckTx(JSON.parse(GenUtils.stringifyBigInts(respJsonStr))));\n });\n });\n });\n }\n async getSpendProof(txHash, message) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getSpendProof(txHash, message);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.get_spend_proof(this.cppAddress, txHash || \"\", message || \"\", (signature) => {\n let errorKey = \"error: \";\n if (signature.indexOf(errorKey) === 0)\n reject(new MoneroError(signature.substring(errorKey.length)));\n else\n resolve(signature);\n });\n });\n });\n }\n async checkSpendProof(txHash, message, signature) {\n if (this.getWalletProxy())\n return this.getWalletProxy().checkSpendProof(txHash, message, signature);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.check_spend_proof(this.cppAddress, txHash || \"\", message || \"\", signature || \"\", (resp) => {\n typeof resp === \"string\" ? reject(new MoneroError(resp)) : resolve(resp);\n });\n });\n });\n }\n async getReserveProofWallet(message) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getReserveProofWallet(message);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.get_reserve_proof_wallet(this.cppAddress, message, (signature) => {\n let errorKey = \"error: \";\n if (signature.indexOf(errorKey) === 0)\n reject(new MoneroError(signature.substring(errorKey.length), -1));\n else\n resolve(signature);\n });\n });\n });\n }\n async getReserveProofAccount(accountIdx, amount, message) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getReserveProofAccount(accountIdx, amount, message);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.get_reserve_proof_account(this.cppAddress, accountIdx, amount.toString(), message, (signature) => {\n let errorKey = \"error: \";\n if (signature.indexOf(errorKey) === 0)\n reject(new MoneroError(signature.substring(errorKey.length), -1));\n else\n resolve(signature);\n });\n });\n });\n }\n async checkReserveProof(address, message, signature) {\n if (this.getWalletProxy())\n return this.getWalletProxy().checkReserveProof(address, message, signature);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.check_reserve_proof(this.cppAddress, address, message, signature, (respJsonStr) => {\n if (respJsonStr.charAt(0) !== '{')\n reject(new MoneroError(respJsonStr, -1));\n else\n resolve(new MoneroCheckReserve(JSON.parse(GenUtils.stringifyBigInts(respJsonStr))));\n });\n });\n });\n }\n async getTxNotes(txHashes) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getTxNotes(txHashes);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n try {\n return JSON.parse(this.module.get_tx_notes(this.cppAddress, JSON.stringify({ txHashes: txHashes }))).txNotes;\n }\n catch (err) {\n throw new MoneroError(this.module.get_exception_message(err));\n }\n });\n }\n async setTxNotes(txHashes, notes) {\n if (this.getWalletProxy())\n return this.getWalletProxy().setTxNotes(txHashes, notes);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n try {\n this.module.set_tx_notes(this.cppAddress, JSON.stringify({ txHashes: txHashes, txNotes: notes }));\n }\n catch (err) {\n throw new MoneroError(this.module.get_exception_message(err));\n }\n });\n }\n async getAddressBookEntries(entryIndices) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getAddressBookEntries(entryIndices);\n if (!entryIndices)\n entryIndices = [];\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let entries = [];\n for (let entryJson of JSON.parse(this.module.get_address_book_entries(this.cppAddress, JSON.stringify({ entryIndices: entryIndices }))).entries) {\n entries.push(new MoneroAddressBookEntry(entryJson));\n }\n return entries;\n });\n }\n async addAddressBookEntry(address, description) {\n if (this.getWalletProxy())\n return this.getWalletProxy().addAddressBookEntry(address, description);\n if (!address)\n address = \"\";\n if (!description)\n description = \"\";\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return this.module.add_address_book_entry(this.cppAddress, address, description);\n });\n }\n async editAddressBookEntry(index, setAddress, address, setDescription, description) {\n if (this.getWalletProxy())\n return this.getWalletProxy().editAddressBookEntry(index, setAddress, address, setDescription, description);\n if (!setAddress)\n setAddress = false;\n if (!address)\n address = \"\";\n if (!setDescription)\n setDescription = false;\n if (!description)\n description = \"\";\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n this.module.edit_address_book_entry(this.cppAddress, index, setAddress, address, setDescription, description);\n });\n }\n async deleteAddressBookEntry(entryIdx) {\n if (this.getWalletProxy())\n return this.getWalletProxy().deleteAddressBookEntry(entryIdx);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n this.module.delete_address_book_entry(this.cppAddress, entryIdx);\n });\n }\n async tagAccounts(tag, accountIndices) {\n if (this.getWalletProxy())\n return this.getWalletProxy().tagAccounts(tag, accountIndices);\n if (!tag)\n tag = \"\";\n if (!accountIndices)\n accountIndices = [];\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n this.module.tag_accounts(this.cppAddress, JSON.stringify({ tag: tag, accountIndices: accountIndices }));\n });\n }\n async untagAccounts(accountIndices) {\n if (this.getWalletProxy())\n return this.getWalletProxy().untagAccounts(accountIndices);\n if (!accountIndices)\n accountIndices = [];\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n this.module.tag_accounts(this.cppAddress, JSON.stringify({ accountIndices: accountIndices }));\n });\n }\n async getAccountTags() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getAccountTags();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let accountTags = [];\n for (let accountTagJson of JSON.parse(this.module.get_account_tags(this.cppAddress)).accountTags)\n accountTags.push(new MoneroAccountTag(accountTagJson));\n return accountTags;\n });\n }\n async setAccountTagLabel(tag, label) {\n if (this.getWalletProxy())\n return this.getWalletProxy().setAccountTagLabel(tag, label);\n if (!tag)\n tag = \"\";\n if (!label)\n label = \"\";\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n this.module.set_account_tag_label(this.cppAddress, tag, label);\n });\n }\n async getPaymentUri(config) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getPaymentUri(config);\n config = MoneroWallet.normalizeCreateTxsConfig(config);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n try {\n return this.module.get_payment_uri(this.cppAddress, JSON.stringify(config.toJson()));\n }\n catch (err) {\n throw new MoneroError(\"Cannot make URI from supplied parameters\");\n }\n });\n }\n async parsePaymentUri(uri) {\n if (this.getWalletProxy())\n return this.getWalletProxy().parsePaymentUri(uri);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n try {\n return new MoneroTxConfig(JSON.parse(GenUtils.stringifyBigInts(this.module.parse_payment_uri(this.cppAddress, uri))));\n }\n catch (err) {\n throw new MoneroError(err.message);\n }\n });\n }\n async getAttribute(key) {\n if (this.getWalletProxy())\n return this.getWalletProxy().getAttribute(key);\n this.assertNotClosed();\n assert(typeof key === \"string\", \"Attribute key must be a string\");\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n let value = this.module.get_attribute(this.cppAddress, key);\n return value === \"\" ? null : value;\n });\n }\n async setAttribute(key, val) {\n if (this.getWalletProxy())\n return this.getWalletProxy().setAttribute(key, val);\n this.assertNotClosed();\n assert(typeof key === \"string\", \"Attribute key must be a string\");\n assert(typeof val === \"string\", \"Attribute value must be a string\");\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n this.module.set_attribute(this.cppAddress, key, val);\n });\n }\n async startMining(numThreads, backgroundMining, ignoreBattery) {\n if (this.getWalletProxy())\n return this.getWalletProxy().startMining(numThreads, backgroundMining, ignoreBattery);\n this.assertNotClosed();\n let daemon = await MoneroDaemonRpc.connectToDaemonRpc(await this.getDaemonConnection());\n await daemon.startMining(await this.getPrimaryAddress(), numThreads, backgroundMining, ignoreBattery);\n }\n async stopMining() {\n if (this.getWalletProxy())\n return this.getWalletProxy().stopMining();\n this.assertNotClosed();\n let daemon = await MoneroDaemonRpc.connectToDaemonRpc(await this.getDaemonConnection());\n await daemon.stopMining();\n }\n async isMultisigImportNeeded() {\n if (this.getWalletProxy())\n return this.getWalletProxy().isMultisigImportNeeded();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return this.module.is_multisig_import_needed(this.cppAddress);\n });\n }\n async isMultisig() {\n if (this.getWalletProxy())\n return this.getWalletProxy().isMultisig();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return this.module.is_multisig(this.cppAddress);\n });\n }\n async getMultisigInfo() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getMultisigInfo();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new MoneroMultisigInfo(JSON.parse(this.module.get_multisig_info(this.cppAddress)));\n });\n }\n async prepareMultisig() {\n if (this.getWalletProxy())\n return this.getWalletProxy().prepareMultisig();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return this.module.prepare_multisig(this.cppAddress);\n });\n }\n async makeMultisig(multisigHexes, threshold, password) {\n if (this.getWalletProxy())\n return this.getWalletProxy().makeMultisig(multisigHexes, threshold, password);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.make_multisig(this.cppAddress, JSON.stringify({ multisigHexes: multisigHexes, threshold: threshold, password: password }), (resp) => {\n let errorKey = \"error: \";\n if (resp.indexOf(errorKey) === 0)\n reject(new MoneroError(resp.substring(errorKey.length)));\n else\n resolve(resp);\n });\n });\n });\n }\n async exchangeMultisigKeys(multisigHexes, password) {\n if (this.getWalletProxy())\n return this.getWalletProxy().exchangeMultisigKeys(multisigHexes, password);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.exchange_multisig_keys(this.cppAddress, JSON.stringify({ multisigHexes: multisigHexes, password: password }), (resp) => {\n let errorKey = \"error: \";\n if (resp.indexOf(errorKey) === 0)\n reject(new MoneroError(resp.substring(errorKey.length)));\n else\n resolve(new MoneroMultisigInitResult(JSON.parse(resp)));\n });\n });\n });\n }\n async exportMultisigHex() {\n if (this.getWalletProxy())\n return this.getWalletProxy().exportMultisigHex();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return this.module.export_multisig_hex(this.cppAddress);\n });\n }\n async importMultisigHex(multisigHexes) {\n if (this.getWalletProxy())\n return this.getWalletProxy().importMultisigHex(multisigHexes);\n if (!GenUtils.isArray(multisigHexes))\n throw new MoneroError(\"Must provide string[] to importMultisigHex()\");\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.import_multisig_hex(this.cppAddress, JSON.stringify({ multisigHexes: multisigHexes }), (resp) => {\n if (typeof resp === \"string\")\n reject(new MoneroError(resp));\n else\n resolve(resp);\n });\n });\n });\n }\n async signMultisigTxHex(multisigTxHex) {\n if (this.getWalletProxy())\n return this.getWalletProxy().signMultisigTxHex(multisigTxHex);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.sign_multisig_tx_hex(this.cppAddress, multisigTxHex, (resp) => {\n if (resp.charAt(0) !== '{')\n reject(new MoneroError(resp));\n else\n resolve(new MoneroMultisigSignResult(JSON.parse(resp)));\n });\n });\n });\n }\n async submitMultisigTxHex(signedMultisigTxHex) {\n if (this.getWalletProxy())\n return this.getWalletProxy().submitMultisigTxHex(signedMultisigTxHex);\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.submit_multisig_tx_hex(this.cppAddress, signedMultisigTxHex, (resp) => {\n if (resp.charAt(0) !== '{')\n reject(new MoneroError(resp));\n else\n resolve(JSON.parse(resp).txHashes);\n });\n });\n });\n }\n /**\n * Get the wallet's keys and cache data.\n *\n * @return {Promise} is the keys and cache data, respectively\n */\n async getData() {\n if (this.getWalletProxy())\n return this.getWalletProxy().getData();\n // queue call to wasm module\n let viewOnly = await this.isViewOnly();\n return this.module.queueTask(async () => {\n this.assertNotClosed();\n // store views in array\n let views = [];\n // malloc cache buffer and get buffer location in c++ heap\n let cacheBufferLoc = JSON.parse(this.module.get_cache_file_buffer(this.cppAddress));\n // read binary data from heap to DataView\n let view = new DataView(new ArrayBuffer(cacheBufferLoc.length));\n for (let i = 0; i < cacheBufferLoc.length; i++) {\n view.setInt8(i, this.module.HEAPU8[cacheBufferLoc.pointer / Uint8Array.BYTES_PER_ELEMENT + i]);\n }\n // free binary on heap\n this.module._free(cacheBufferLoc.pointer);\n // write cache file\n views.push(Buffer.from(view.buffer));\n // malloc keys buffer and get buffer location in c++ heap\n let keysBufferLoc = JSON.parse(this.module.get_keys_file_buffer(this.cppAddress, this.password, viewOnly));\n // read binary data from heap to DataView\n view = new DataView(new ArrayBuffer(keysBufferLoc.length));\n for (let i = 0; i < keysBufferLoc.length; i++) {\n view.setInt8(i, this.module.HEAPU8[keysBufferLoc.pointer / Uint8Array.BYTES_PER_ELEMENT + i]);\n }\n // free binary on heap\n this.module._free(keysBufferLoc.pointer);\n // prepend keys file\n views.unshift(Buffer.from(view.buffer));\n return views;\n });\n }\n async changePassword(oldPassword, newPassword) {\n if (this.getWalletProxy())\n return this.getWalletProxy().changePassword(oldPassword, newPassword);\n if (oldPassword !== this.password)\n throw new MoneroError(\"Invalid original password.\"); // wallet2 verify_password loads from disk so verify password here\n if (newPassword === undefined)\n newPassword = \"\";\n await this.module.queueTask(async () => {\n this.assertNotClosed();\n return new Promise((resolve, reject) => {\n this.module.change_wallet_password(this.cppAddress, oldPassword, newPassword, (errMsg) => {\n if (errMsg)\n reject(new MoneroError(errMsg));\n else\n resolve();\n });\n });\n });\n this.password = newPassword;\n if (this.path)\n await this.save(); // auto save\n }\n async save() {\n if (this.getWalletProxy())\n return this.getWalletProxy().save();\n return MoneroWalletFull.save(this);\n }\n async close(save = false) {\n if (this._isClosed)\n return; // no effect if closed\n if (save)\n await this.save();\n if (this.getWalletProxy()) {\n await this.getWalletProxy().close(false);\n await super.close();\n return;\n }\n await this.refreshListening();\n await this.stopSyncing();\n await super.close();\n delete this.path;\n delete this.password;\n delete this.wasmListener;\n LibraryUtils.setRejectUnauthorizedFn(this.rejectUnauthorizedConfigId, undefined); // unregister fn informing if unauthorized reqs should be rejected\n }\n // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS --------------\n async getNumBlocksToUnlock() { return super.getNumBlocksToUnlock(); }\n async getTx(txHash) { return super.getTx(txHash); }\n async getIncomingTransfers(query) { return super.getIncomingTransfers(query); }\n async getOutgoingTransfers(query) { return super.getOutgoingTransfers(query); }\n async createTx(config) { return super.createTx(config); }\n async relayTx(txOrMetadata) { return super.relayTx(txOrMetadata); }\n async getTxNote(txHash) { return super.getTxNote(txHash); }\n async setTxNote(txHash, note) { return super.setTxNote(txHash, note); }\n // ---------------------------- PRIVATE HELPERS ----------------------------\n static async openWalletData(config) {\n if (config.proxyToWorker) {\n let walletProxy = await MoneroWalletFullProxy.openWalletData(config);\n return new MoneroWalletFull(undefined, undefined, undefined, undefined, undefined, undefined, walletProxy);\n }\n // validate and normalize parameters\n if (config.networkType === undefined)\n throw new MoneroError(\"Must provide the wallet's network type\");\n config.networkType = MoneroNetworkType.from(config.networkType);\n let daemonConnection = config.getServer();\n let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : \"\";\n let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : \"\";\n let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : \"\";\n let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true;\n // load wasm module\n let module = await LibraryUtils.loadWasmModule();\n // open wallet in queue\n return module.queueTask(async () => {\n return new Promise((resolve, reject) => {\n // register fn informing if unauthorized reqs should be rejected\n let rejectUnauthorizedFnId = GenUtils.getUUID();\n LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => rejectUnauthorized);\n // create wallet in wasm which invokes callback when done\n module.open_wallet_full(config.password, config.networkType, config.keysData ?? \"\", config.cacheData ?? \"\", daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, (cppAddress) => {\n if (typeof cppAddress === \"string\")\n reject(new MoneroError(cppAddress));\n else\n resolve(new MoneroWalletFull(cppAddress, config.path, config.password, config.fs, rejectUnauthorized, rejectUnauthorizedFnId));\n });\n });\n });\n }\n getWalletProxy() {\n return super.getWalletProxy();\n }\n async backgroundSync() {\n let label = this.path ? this.path : (this.browserMainPath ? this.browserMainPath : \"in-memory wallet\"); // label for log\n LibraryUtils.log(1, \"Background synchronizing \" + label);\n try {\n await this.sync();\n }\n catch (err) {\n if (!this._isClosed)\n console.error(\"Failed to background synchronize \" + label + \": \" + err.message);\n }\n }\n async refreshListening() {\n let isEnabled = this.listeners.length > 0;\n if (this.wasmListenerHandle === 0 && !isEnabled || this.wasmListenerHandle > 0 && isEnabled)\n return; // no difference\n return this.module.queueTask(async () => {\n return new Promise((resolve, reject) => {\n this.module.set_listener(this.cppAddress, this.wasmListenerHandle, newListenerHandle => {\n if (typeof newListenerHandle === \"string\")\n reject(new MoneroError(newListenerHandle));\n else {\n this.wasmListenerHandle = newListenerHandle;\n resolve();\n }\n }, isEnabled ? async (height, startHeight, endHeight, percentDone, message) => await this.wasmListener.onSyncProgress(height, startHeight, endHeight, percentDone, message) : undefined, isEnabled ? async (height) => await this.wasmListener.onNewBlock(height) : undefined, isEnabled ? async (newBalanceStr, newUnlockedBalanceStr) => await this.wasmListener.onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) : undefined, isEnabled ? async (height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockTime, isLocked) => await this.wasmListener.onOutputReceived(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockTime, isLocked) : undefined, isEnabled ? async (height, txHash, amountStr, accountIdxStr, subaddressIdxStr, version, unlockTime, isLocked) => await this.wasmListener.onOutputSpent(height, txHash, amountStr, accountIdxStr, subaddressIdxStr, version, unlockTime, isLocked) : undefined);\n });\n });\n }\n static sanitizeBlock(block) {\n for (let tx of block.getTxs())\n MoneroWalletFull.sanitizeTxWallet(tx);\n return block;\n }\n static sanitizeTxWallet(tx) {\n assert(tx instanceof MoneroTxWallet);\n return tx;\n }\n static sanitizeAccount(account) {\n if (account.getSubaddresses()) {\n for (let subaddress of account.getSubaddresses())\n MoneroWalletKeys.sanitizeSubaddress(subaddress);\n }\n return account;\n }\n static deserializeBlocks(blocksJsonStr) {\n let blocksJson = JSON.parse(GenUtils.stringifyBigInts(blocksJsonStr));\n let deserializedBlocks = {};\n deserializedBlocks.blocks = [];\n if (blocksJson.blocks)\n for (let blockJson of blocksJson.blocks)\n deserializedBlocks.blocks.push(MoneroWalletFull.sanitizeBlock(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET)));\n return deserializedBlocks;\n }\n static deserializeTxs(query, blocksJsonStr) {\n // deserialize blocks\n let deserializedBlocks = MoneroWalletFull.deserializeBlocks(blocksJsonStr);\n let blocks = deserializedBlocks.blocks;\n // collect txs\n let txs = [];\n for (let block of blocks) {\n MoneroWalletFull.sanitizeBlock(block);\n for (let tx of block.getTxs()) {\n if (block.getHeight() === undefined)\n tx.setBlock(undefined); // dereference placeholder block for unconfirmed txs\n txs.push(tx);\n }\n }\n // re-sort txs which is lost over wasm serialization // TODO: confirm that order is lost\n if (query.getHashes() !== undefined) {\n let txMap = new Map();\n for (let tx of txs)\n txMap[tx.getHash()] = tx;\n let txsSorted = [];\n for (let txHash of query.getHashes())\n if (txMap[txHash] !== undefined)\n txsSorted.push(txMap[txHash]);\n txs = txsSorted;\n }\n return txs;\n }\n static deserializeTransfers(query, blocksJsonStr) {\n // deserialize blocks\n let deserializedBlocks = MoneroWalletFull.deserializeBlocks(blocksJsonStr);\n let blocks = deserializedBlocks.blocks;\n // collect transfers\n let transfers = [];\n for (let block of blocks) {\n for (let tx of block.getTxs()) {\n if (block.getHeight() === undefined)\n tx.setBlock(undefined); // dereference placeholder block for unconfirmed txs\n if (tx.getOutgoingTransfer() !== undefined)\n transfers.push(tx.getOutgoingTransfer());\n if (tx.getIncomingTransfers() !== undefined) {\n for (let transfer of tx.getIncomingTransfers())\n transfers.push(transfer);\n }\n }\n }\n return transfers;\n }\n static deserializeOutputs(query, blocksJsonStr) {\n // deserialize blocks\n let deserializedBlocks = MoneroWalletFull.deserializeBlocks(blocksJsonStr);\n let blocks = deserializedBlocks.blocks;\n // collect outputs\n let outputs = [];\n for (let block of blocks) {\n for (let tx of block.getTxs()) {\n for (let output of tx.getOutputs())\n outputs.push(output);\n }\n }\n return outputs;\n }\n /**\n * Set the path of the wallet on the browser main thread if run as a worker.\n *\n * @param {string} browserMainPath - path of the wallet on the browser main thread\n */\n setBrowserMainPath(browserMainPath) {\n this.browserMainPath = browserMainPath;\n }\n static async moveTo(path, wallet) {\n // save and return if same path\n if (Path.normalize(wallet.path) === Path.normalize(path)) {\n return wallet.save();\n }\n return LibraryUtils.queueTask(async () => {\n if (await wallet.isClosed())\n throw new MoneroError(\"Wallet is closed\");\n if (!path)\n throw new MoneroError(\"Must provide path of destination wallet\");\n // create destination directory if it doesn't exist\n let walletDir = Path.dirname(path);\n if (!await LibraryUtils.exists(wallet.fs, walletDir)) {\n try {\n await wallet.fs.mkdir(walletDir);\n }\n catch (err) {\n throw new MoneroError(\"Destination path \" + path + \" does not exist and cannot be created: \" + err.message);\n }\n }\n // get wallet data\n const data = await wallet.getData();\n // write wallet files\n await wallet.fs.writeFile(path + \".keys\", data[0], \"binary\");\n await wallet.fs.writeFile(path, data[1], \"binary\");\n await wallet.fs.writeFile(path + \".address.txt\", await wallet.getPrimaryAddress());\n let oldPath = wallet.path;\n wallet.path = path;\n // delete old wallet files\n if (oldPath) {\n await wallet.fs.unlink(oldPath + \".address.txt\");\n await wallet.fs.unlink(oldPath + \".keys\");\n await wallet.fs.unlink(oldPath);\n }\n });\n }\n static async save(wallet) {\n return LibraryUtils.queueTask(async () => {\n if (await wallet.isClosed())\n throw new MoneroError(\"Wallet is closed\");\n // path must be set\n let path = await wallet.getPath();\n if (!path)\n throw new MoneroError(\"Cannot save wallet because path is not set\");\n // get wallet data\n const data = await wallet.getData();\n // write wallet files to *.new\n let pathNew = path + \".new\";\n await wallet.fs.writeFile(pathNew + \".keys\", data[0], \"binary\");\n await wallet.fs.writeFile(pathNew, data[1], \"binary\");\n await wallet.fs.writeFile(pathNew + \".address.txt\", await wallet.getPrimaryAddress());\n // replace old wallet files with new\n await wallet.fs.rename(pathNew + \".keys\", path + \".keys\");\n await wallet.fs.rename(pathNew, path);\n await wallet.fs.rename(pathNew + \".address.txt\", path + \".address.txt\");\n });\n }\n}\n// static variables\nMoneroWalletFull.DEFAULT_SYNC_PERIOD_IN_MS = 20000;\nexport default MoneroWalletFull;\n/**\n * Implements a MoneroWallet by proxying requests to a worker which runs a full wallet.\n *\n * @private\n */\nclass MoneroWalletFullProxy extends MoneroWalletKeysProxy {\n // -------------------------- WALLET STATIC UTILS ---------------------------\n static async openWalletData(config) {\n let walletId = GenUtils.getUUID();\n if (config.password === undefined)\n config.password = \"\";\n let daemonConnection = config.getServer();\n await LibraryUtils.invokeWorker(walletId, \"openWalletData\", [config.path, config.password, config.networkType, config.keysData, config.cacheData, daemonConnection ? daemonConnection.toJson() : undefined]);\n let wallet = new MoneroWalletFullProxy(walletId, await LibraryUtils.getWorker(), config.path, config.getFs());\n if (config.path)\n await wallet.save();\n return wallet;\n }\n static async createWallet(config) {\n if (config.getPath() && await MoneroWalletFull.walletExists(config.getPath(), config.getFs()))\n throw new MoneroError(\"Wallet already exists: \" + config.getPath());\n let walletId = GenUtils.getUUID();\n await LibraryUtils.invokeWorker(walletId, \"createWalletFull\", [config.toJson()]);\n let wallet = new MoneroWalletFullProxy(walletId, await LibraryUtils.getWorker(), config.getPath(), config.getFs());\n if (config.getPath())\n await wallet.save();\n return wallet;\n }\n // --------------------------- INSTANCE METHODS ----------------------------\n /**\n * Internal constructor which is given a worker to communicate with via messages.\n *\n * This method should not be called externally but should be called through\n * static wallet creation utilities in this class.\n *\n * @param {string} walletId - identifies the wallet with the worker\n * @param {Worker} worker - worker to communicate with via messages\n */\n constructor(walletId, worker, path, fs) {\n super(walletId, worker);\n this.path = path;\n this.fs = fs ? fs : (path ? MoneroWalletFull.getFs() : undefined);\n this.wrappedListeners = [];\n }\n getPath() {\n return this.path;\n }\n async getNetworkType() {\n return this.invokeWorker(\"getNetworkType\");\n }\n async setSubaddressLabel(accountIdx, subaddressIdx, label) {\n return this.invokeWorker(\"setSubaddressLabel\", Array.from(arguments));\n }\n async setDaemonConnection(uriOrRpcConnection) {\n if (!uriOrRpcConnection)\n await this.invokeWorker(\"setDaemonConnection\");\n else {\n let connection = !uriOrRpcConnection ? undefined : uriOrRpcConnection instanceof MoneroRpcConnection ? uriOrRpcConnection : new MoneroRpcConnection(uriOrRpcConnection);\n await this.invokeWorker(\"setDaemonConnection\", connection ? connection.getConfig() : undefined);\n }\n }\n async getDaemonConnection() {\n let rpcConfig = await this.invokeWorker(\"getDaemonConnection\");\n return rpcConfig ? new MoneroRpcConnection(rpcConfig) : undefined;\n }\n async isConnectedToDaemon() {\n return this.invokeWorker(\"isConnectedToDaemon\");\n }\n async getRestoreHeight() {\n return this.invokeWorker(\"getRestoreHeight\");\n }\n async setRestoreHeight(restoreHeight) {\n return this.invokeWorker(\"setRestoreHeight\", [restoreHeight]);\n }\n async getDaemonHeight() {\n return this.invokeWorker(\"getDaemonHeight\");\n }\n async getDaemonMaxPeerHeight() {\n return this.invokeWorker(\"getDaemonMaxPeerHeight\");\n }\n async getHeightByDate(year, month, day) {\n return this.invokeWorker(\"getHeightByDate\", [year, month, day]);\n }\n async isDaemonSynced() {\n return this.invokeWorker(\"isDaemonSynced\");\n }\n async getHeight() {\n return this.invokeWorker(\"getHeight\");\n }\n async addListener(listener) {\n let wrappedListener = new WalletWorkerListener(listener);\n let listenerId = wrappedListener.getId();\n LibraryUtils.addWorkerCallback(this.walletId, \"onSyncProgress_\" + listenerId, [wrappedListener.onSyncProgress, wrappedListener]);\n LibraryUtils.addWorkerCallback(this.walletId, \"onNewBlock_\" + listenerId, [wrappedListener.onNewBlock, wrappedListener]);\n LibraryUtils.addWorkerCallback(this.walletId, \"onBalancesChanged_\" + listenerId, [wrappedListener.onBalancesChanged, wrappedListener]);\n LibraryUtils.addWorkerCallback(this.walletId, \"onOutputReceived_\" + listenerId, [wrappedListener.onOutputReceived, wrappedListener]);\n LibraryUtils.addWorkerCallback(this.walletId, \"onOutputSpent_\" + listenerId, [wrappedListener.onOutputSpent, wrappedListener]);\n this.wrappedListeners.push(wrappedListener);\n return this.invokeWorker(\"addListener\", [listenerId]);\n }\n async removeListener(listener) {\n for (let i = 0; i < this.wrappedListeners.length; i++) {\n if (this.wrappedListeners[i].getListener() === listener) {\n let listenerId = this.wrappedListeners[i].getId();\n await this.invokeWorker(\"removeListener\", [listenerId]);\n LibraryUtils.removeWorkerCallback(this.walletId, \"onSyncProgress_\" + listenerId);\n LibraryUtils.removeWorkerCallback(this.walletId, \"onNewBlock_\" + listenerId);\n LibraryUtils.removeWorkerCallback(this.walletId, \"onBalancesChanged_\" + listenerId);\n LibraryUtils.removeWorkerCallback(this.walletId, \"onOutputReceived_\" + listenerId);\n LibraryUtils.removeWorkerCallback(this.walletId, \"onOutputSpent_\" + listenerId);\n this.wrappedListeners.splice(i, 1);\n return;\n }\n }\n throw new MoneroError(\"Listener is not registered with wallet\");\n }\n getListeners() {\n let listeners = [];\n for (let wrappedListener of this.wrappedListeners)\n listeners.push(wrappedListener.getListener());\n return listeners;\n }\n async isSynced() {\n return this.invokeWorker(\"isSynced\");\n }\n async sync(listenerOrStartHeight, startHeight, allowConcurrentCalls = false) {\n // normalize params\n startHeight = listenerOrStartHeight instanceof MoneroWalletListener ? startHeight : listenerOrStartHeight;\n let listener = listenerOrStartHeight instanceof MoneroWalletListener ? listenerOrStartHeight : undefined;\n if (startHeight === undefined)\n startHeight = Math.max(await this.getHeight(), await this.getRestoreHeight());\n // register listener if given\n if (listener)\n await this.addListener(listener);\n // sync wallet in worker \n let err;\n let result;\n try {\n let resultJson = await this.invokeWorker(\"sync\", [startHeight, allowConcurrentCalls]);\n result = new MoneroSyncResult(resultJson.numBlocksFetched, resultJson.receivedMoney);\n }\n catch (e) {\n err = e;\n }\n // unregister listener\n if (listener)\n await this.removeListener(listener);\n // throw error or return\n if (err)\n throw err;\n return result;\n }\n async startSyncing(syncPeriodInMs) {\n return this.invokeWorker(\"startSyncing\", Array.from(arguments));\n }\n async stopSyncing() {\n return this.invokeWorker(\"stopSyncing\");\n }\n async scanTxs(txHashes) {\n assert(Array.isArray(txHashes), \"Must provide an array of txs hashes to scan\");\n return this.invokeWorker(\"scanTxs\", [txHashes]);\n }\n async rescanSpent() {\n return this.invokeWorker(\"rescanSpent\");\n }\n async rescanBlockchain() {\n return this.invokeWorker(\"rescanBlockchain\");\n }\n async getBalance(accountIdx, subaddressIdx) {\n return BigInt(await this.invokeWorker(\"getBalance\", Array.from(arguments)));\n }\n async getUnlockedBalance(accountIdx, subaddressIdx) {\n let unlockedBalanceStr = await this.invokeWorker(\"getUnlockedBalance\", Array.from(arguments));\n return BigInt(unlockedBalanceStr);\n }\n async getAccounts(includeSubaddresses, tag) {\n let accounts = [];\n for (let accountJson of (await this.invokeWorker(\"getAccounts\", Array.from(arguments)))) {\n accounts.push(MoneroWalletFull.sanitizeAccount(new MoneroAccount(accountJson)));\n }\n return accounts;\n }\n async getAccount(accountIdx, includeSubaddresses) {\n let accountJson = await this.invokeWorker(\"getAccount\", Array.from(arguments));\n return MoneroWalletFull.sanitizeAccount(new MoneroAccount(accountJson));\n }\n async createAccount(label) {\n let accountJson = await this.invokeWorker(\"createAccount\", Array.from(arguments));\n return MoneroWalletFull.sanitizeAccount(new MoneroAccount(accountJson));\n }\n async getSubaddresses(accountIdx, subaddressIndices) {\n let subaddresses = [];\n for (let subaddressJson of (await this.invokeWorker(\"getSubaddresses\", Array.from(arguments)))) {\n subaddresses.push(MoneroWalletKeys.sanitizeSubaddress(new MoneroSubaddress(subaddressJson)));\n }\n return subaddresses;\n }\n async createSubaddress(accountIdx, label) {\n let subaddressJson = await this.invokeWorker(\"createSubaddress\", Array.from(arguments));\n return MoneroWalletKeys.sanitizeSubaddress(new MoneroSubaddress(subaddressJson));\n }\n async getTxs(query) {\n query = MoneroWallet.normalizeTxQuery(query);\n let respJson = await this.invokeWorker(\"getTxs\", [query.getBlock().toJson()]);\n return MoneroWalletFull.deserializeTxs(query, JSON.stringify({ blocks: respJson.blocks })); // initialize txs from blocks json string TODO: this stringifies then utility parses, avoid\n }\n async getTransfers(query) {\n query = MoneroWallet.normalizeTransferQuery(query);\n let blockJsons = await this.invokeWorker(\"getTransfers\", [query.getTxQuery().getBlock().toJson()]);\n return MoneroWalletFull.deserializeTransfers(query, JSON.stringify({ blocks: blockJsons })); // initialize transfers from blocks json string TODO: this stringifies then utility parses, avoid\n }\n async getOutputs(query) {\n query = MoneroWallet.normalizeOutputQuery(query);\n let blockJsons = await this.invokeWorker(\"getOutputs\", [query.getTxQuery().getBlock().toJson()]);\n return MoneroWalletFull.deserializeOutputs(query, JSON.stringify({ blocks: blockJsons })); // initialize transfers from blocks json string TODO: this stringifies then utility parses, avoid\n }\n async exportOutputs(all) {\n return this.invokeWorker(\"exportOutputs\", [all]);\n }\n async importOutputs(outputsHex) {\n return this.invokeWorker(\"importOutputs\", [outputsHex]);\n }\n async exportKeyImages(all) {\n let keyImages = [];\n for (let keyImageJson of await this.invokeWorker(\"getKeyImages\", [all]))\n keyImages.push(new MoneroKeyImage(keyImageJson));\n return keyImages;\n }\n async importKeyImages(keyImages) {\n let keyImagesJson = [];\n for (let keyImage of keyImages)\n keyImagesJson.push(keyImage.toJson());\n return new MoneroKeyImageImportResult(await this.invokeWorker(\"importKeyImages\", [keyImagesJson]));\n }\n async getNewKeyImagesFromLastImport() {\n throw new MoneroError(\"MoneroWalletFull.getNewKeyImagesFromLastImport() not implemented\");\n }\n async freezeOutput(keyImage) {\n return this.invokeWorker(\"freezeOutput\", [keyImage]);\n }\n async thawOutput(keyImage) {\n return this.invokeWorker(\"thawOutput\", [keyImage]);\n }\n async isOutputFrozen(keyImage) {\n return this.invokeWorker(\"isOutputFrozen\", [keyImage]);\n }\n async getDefaultFeePriority() {\n return this.invokeWorker(\"getDefaultFeePriority\");\n }\n async createTxs(config) {\n config = MoneroWallet.normalizeCreateTxsConfig(config);\n let txSetJson = await this.invokeWorker(\"createTxs\", [config.toJson()]);\n return new MoneroTxSet(txSetJson).getTxs();\n }\n async sweepOutput(config) {\n config = MoneroWallet.normalizeSweepOutputConfig(config);\n let txSetJson = await this.invokeWorker(\"sweepOutput\", [config.toJson()]);\n return new MoneroTxSet(txSetJson).getTxs()[0];\n }\n async sweepUnlocked(config) {\n config = MoneroWallet.normalizeSweepUnlockedConfig(config);\n let txSetsJson = await this.invokeWorker(\"sweepUnlocked\", [config.toJson()]);\n let txs = [];\n for (let txSetJson of txSetsJson)\n for (let tx of new MoneroTxSet(txSetJson).getTxs())\n txs.push(tx);\n return txs;\n }\n async sweepDust(relay) {\n return new MoneroTxSet(await this.invokeWorker(\"sweepDust\", [relay])).getTxs() || [];\n }\n async relayTxs(txsOrMetadatas) {\n assert(Array.isArray(txsOrMetadatas), \"Must provide an array of txs or their metadata to relay\");\n let txMetadatas = [];\n for (let txOrMetadata of txsOrMetadatas)\n txMetadatas.push(txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata);\n return this.invokeWorker(\"relayTxs\", [txMetadatas]);\n }\n async describeTxSet(txSet) {\n return new MoneroTxSet(await this.invokeWorker(\"describeTxSet\", [txSet.toJson()]));\n }\n async signTxs(unsignedTxHex) {\n return new MoneroTxSet(await this.invokeWorker(\"signTxs\", Array.from(arguments)));\n }\n async submitTxs(signedTxHex) {\n return this.invokeWorker(\"submitTxs\", Array.from(arguments));\n }\n async signMessage(message, signatureType, accountIdx, subaddressIdx) {\n return this.invokeWorker(\"signMessage\", Array.from(arguments));\n }\n async verifyMessage(message, address, signature) {\n return new MoneroMessageSignatureResult(await this.invokeWorker(\"verifyMessage\", Array.from(arguments)));\n }\n async getTxKey(txHash) {\n return this.invokeWorker(\"getTxKey\", Array.from(arguments));\n }\n async checkTxKey(txHash, txKey, address) {\n return new MoneroCheckTx(await this.invokeWorker(\"checkTxKey\", Array.from(arguments)));\n }\n async getTxProof(txHash, address, message) {\n return this.invokeWorker(\"getTxProof\", Array.from(arguments));\n }\n async checkTxProof(txHash, address, message, signature) {\n return new MoneroCheckTx(await this.invokeWorker(\"checkTxProof\", Array.from(arguments)));\n }\n async getSpendProof(txHash, message) {\n return this.invokeWorker(\"getSpendProof\", Array.from(arguments));\n }\n async checkSpendProof(txHash, message, signature) {\n return this.invokeWorker(\"checkSpendProof\", Array.from(arguments));\n }\n async getReserveProofWallet(message) {\n return this.invokeWorker(\"getReserveProofWallet\", Array.from(arguments));\n }\n async getReserveProofAccount(accountIdx, amount, message) {\n try {\n return await this.invokeWorker(\"getReserveProofAccount\", [accountIdx, amount.toString(), message]);\n }\n catch (e) {\n throw new MoneroError(e.message, -1);\n }\n }\n async checkReserveProof(address, message, signature) {\n try {\n return new MoneroCheckReserve(await this.invokeWorker(\"checkReserveProof\", Array.from(arguments)));\n }\n catch (e) {\n throw new MoneroError(e.message, -1);\n }\n }\n async getTxNotes(txHashes) {\n return this.invokeWorker(\"getTxNotes\", Array.from(arguments));\n }\n async setTxNotes(txHashes, notes) {\n return this.invokeWorker(\"setTxNotes\", Array.from(arguments));\n }\n async getAddressBookEntries(entryIndices) {\n if (!entryIndices)\n entryIndices = [];\n let entries = [];\n for (let entryJson of await this.invokeWorker(\"getAddressBookEntries\", Array.from(arguments))) {\n entries.push(new MoneroAddressBookEntry(entryJson));\n }\n return entries;\n }\n async addAddressBookEntry(address, description) {\n return this.invokeWorker(\"addAddressBookEntry\", Array.from(arguments));\n }\n async editAddressBookEntry(index, setAddress, address, setDescription, description) {\n return this.invokeWorker(\"editAddressBookEntry\", Array.from(arguments));\n }\n async deleteAddressBookEntry(entryIdx) {\n return this.invokeWorker(\"deleteAddressBookEntry\", Array.from(arguments));\n }\n async tagAccounts(tag, accountIndices) {\n return this.invokeWorker(\"tagAccounts\", Array.from(arguments));\n }\n async untagAccounts(accountIndices) {\n return this.invokeWorker(\"untagAccounts\", Array.from(arguments));\n }\n async getAccountTags() {\n return this.invokeWorker(\"getAccountTags\", Array.from(arguments));\n }\n async setAccountTagLabel(tag, label) {\n return this.invokeWorker(\"setAccountTagLabel\", Array.from(arguments));\n }\n async getPaymentUri(config) {\n config = MoneroWallet.normalizeCreateTxsConfig(config);\n return this.invokeWorker(\"getPaymentUri\", [config.toJson()]);\n }\n async parsePaymentUri(uri) {\n return new MoneroTxConfig(await this.invokeWorker(\"parsePaymentUri\", Array.from(arguments)));\n }\n async getAttribute(key) {\n return this.invokeWorker(\"getAttribute\", Array.from(arguments));\n }\n async setAttribute(key, val) {\n return this.invokeWorker(\"setAttribute\", Array.from(arguments));\n }\n async startMining(numThreads, backgroundMining, ignoreBattery) {\n return this.invokeWorker(\"startMining\", Array.from(arguments));\n }\n async stopMining() {\n return this.invokeWorker(\"stopMining\", Array.from(arguments));\n }\n async isMultisigImportNeeded() {\n return this.invokeWorker(\"isMultisigImportNeeded\");\n }\n async isMultisig() {\n return this.invokeWorker(\"isMultisig\");\n }\n async getMultisigInfo() {\n return new MoneroMultisigInfo(await this.invokeWorker(\"getMultisigInfo\"));\n }\n async prepareMultisig() {\n return this.invokeWorker(\"prepareMultisig\");\n }\n async makeMultisig(multisigHexes, threshold, password) {\n return await this.invokeWorker(\"makeMultisig\", Array.from(arguments));\n }\n async exchangeMultisigKeys(multisigHexes, password) {\n return new MoneroMultisigInitResult(await this.invokeWorker(\"exchangeMultisigKeys\", Array.from(arguments)));\n }\n async exportMultisigHex() {\n return this.invokeWorker(\"exportMultisigHex\");\n }\n async importMultisigHex(multisigHexes) {\n return this.invokeWorker(\"importMultisigHex\", Array.from(arguments));\n }\n async signMultisigTxHex(multisigTxHex) {\n return new MoneroMultisigSignResult(await this.invokeWorker(\"signMultisigTxHex\", Array.from(arguments)));\n }\n async submitMultisigTxHex(signedMultisigTxHex) {\n return this.invokeWorker(\"submitMultisigTxHex\", Array.from(arguments));\n }\n async getData() {\n return this.invokeWorker(\"getData\");\n }\n async moveTo(path) {\n return MoneroWalletFull.moveTo(path, this);\n }\n async changePassword(oldPassword, newPassword) {\n await this.invokeWorker(\"changePassword\", Array.from(arguments));\n if (this.path)\n await this.save(); // auto save\n }\n async save() {\n return MoneroWalletFull.save(this);\n }\n async close(save) {\n if (await this.isClosed())\n return;\n if (save)\n await this.save();\n while (this.wrappedListeners.length)\n await this.removeListener(this.wrappedListeners[0].getListener());\n await super.close(false);\n }\n}\n// -------------------------------- LISTENING ---------------------------------\n/**\n * Receives notifications directly from wasm c++.\n *\n * @private\n */\nclass WalletWasmListener {\n constructor(wallet) {\n this.wallet = wallet;\n }\n async onSyncProgress(height, startHeight, endHeight, percentDone, message) {\n await this.wallet.announceSyncProgress(height, startHeight, endHeight, percentDone, message);\n }\n async onNewBlock(height) {\n await this.wallet.announceNewBlock(height);\n }\n async onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) {\n await this.wallet.announceBalancesChanged(newBalanceStr, newUnlockedBalanceStr);\n }\n async onOutputReceived(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockTime, isLocked) {\n // build received output\n let output = new MoneroOutputWallet();\n output.setAmount(BigInt(amountStr));\n output.setAccountIndex(accountIdx);\n output.setSubaddressIndex(subaddressIdx);\n let tx = new MoneroTxWallet();\n tx.setHash(txHash);\n tx.setVersion(version);\n tx.setUnlockTime(unlockTime);\n output.setTx(tx);\n tx.setOutputs([output]);\n tx.setIsIncoming(true);\n tx.setIsLocked(isLocked);\n if (height > 0) {\n let block = new MoneroBlock().setHeight(height);\n block.setTxs([tx]);\n tx.setBlock(block);\n tx.setIsConfirmed(true);\n tx.setInTxPool(false);\n tx.setIsFailed(false);\n }\n else {\n tx.setIsConfirmed(false);\n tx.setInTxPool(true);\n }\n // announce output\n await this.wallet.announceOutputReceived(output);\n }\n async onOutputSpent(height, txHash, amountStr, accountIdxStr, subaddressIdxStr, version, unlockTime, isLocked) {\n // build spent output\n let output = new MoneroOutputWallet();\n output.setAmount(BigInt(amountStr));\n if (accountIdxStr)\n output.setAccountIndex(parseInt(accountIdxStr));\n if (subaddressIdxStr)\n output.setSubaddressIndex(parseInt(subaddressIdxStr));\n let tx = new MoneroTxWallet();\n tx.setHash(txHash);\n tx.setVersion(version);\n tx.setUnlockTime(unlockTime);\n tx.setIsLocked(isLocked);\n output.setTx(tx);\n tx.setInputs([output]);\n if (height > 0) {\n let block = new MoneroBlock().setHeight(height);\n block.setTxs([tx]);\n tx.setBlock(block);\n tx.setIsConfirmed(true);\n tx.setInTxPool(false);\n tx.setIsFailed(false);\n }\n else {\n tx.setIsConfirmed(false);\n tx.setInTxPool(true);\n }\n // announce output\n await this.wallet.announceOutputSpent(output);\n }\n}\n/**\n * Internal listener to bridge notifications to external listeners.\n *\n * @private\n */\nclass WalletWorkerListener {\n constructor(listener) {\n this.id = GenUtils.getUUID();\n this.listener = listener;\n }\n getId() {\n return this.id;\n }\n getListener() {\n return this.listener;\n }\n onSyncProgress(height, startHeight, endHeight, percentDone, message) {\n this.listener.onSyncProgress(height, startHeight, endHeight, percentDone, message);\n }\n async onNewBlock(height) {\n await this.listener.onNewBlock(height);\n }\n async onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) {\n await this.listener.onBalancesChanged(BigInt(newBalanceStr), BigInt(newUnlockedBalanceStr));\n }\n async onOutputReceived(blockJson) {\n let block = new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET);\n await this.listener.onOutputReceived(block.getTxs()[0].getOutputs()[0]);\n }\n async onOutputSpent(blockJson) {\n let block = new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET);\n await this.listener.onOutputSpent(block.getTxs()[0].getInputs()[0]);\n }\n}\n","import assert from \"assert\";\nimport GenUtils from \"./GenUtils\";\nimport HttpClient from \"./HttpClient\";\nimport LibraryUtils from \"./LibraryUtils\";\nimport MoneroBan from \"../daemon/model/MoneroBan\";\nimport MoneroBlock from \"../daemon/model/MoneroBlock\";\nimport MoneroDaemonConfig from \"../daemon/model/MoneroDaemonConfig\";\nimport MoneroDaemonListener from \"../daemon/model/MoneroDaemonListener\";\nimport MoneroDaemonRpc from \"../daemon/MoneroDaemonRpc\";\nimport MoneroError from \"./MoneroError\";\nimport MoneroKeyImage from \"../daemon/model/MoneroKeyImage\";\nimport MoneroRpcConnection from \"./MoneroRpcConnection\";\nimport MoneroTxConfig from \"../wallet/model/MoneroTxConfig\";\nimport MoneroTxSet from \"../wallet/model/MoneroTxSet\";\nimport MoneroUtils from \"./MoneroUtils\";\nimport MoneroWalletConfig from \"../wallet/model/MoneroWalletConfig\";\nimport MoneroWalletListener from \"../wallet/model/MoneroWalletListener\";\nimport { MoneroWalletKeys } from \"../wallet/MoneroWalletKeys\";\nimport MoneroWalletFull from \"../wallet/MoneroWalletFull\";\nif (GenUtils.isDeno() && typeof self === \"undefined\" && typeof globalThis === \"object\" && typeof DedicatedWorkerGlobalScope === \"function\" && DedicatedWorkerGlobalScope.prototype.isPrototypeOf(globalThis)) {\n self = globalThis;\n globalThis.self = globalThis;\n}\n// expose some modules to the worker\nself.HttpClient = HttpClient;\nself.LibraryUtils = LibraryUtils;\nself.GenUtils = GenUtils;\n/**\n * Worker to manage a daemon and wasm wallet off the main thread using messages.\n *\n * Required message format: e.data[0] = object id, e.data[1] = function name, e.data[2+] = function args\n *\n * For browser applications, this file must be browserified and placed in the web app root.\n *\n * @private\n */\nself.onmessage = async function (e) {\n // initialize one time\n await self.initOneTime();\n // validate params\n let objectId = e.data[0];\n let fnName = e.data[1];\n let callbackId = e.data[2];\n assert(fnName, \"Must provide function name to worker\");\n assert(callbackId, \"Must provide callback id to worker\");\n if (!self[fnName])\n throw new Error(\"Method '\" + fnName + \"' is not registered with worker\");\n e.data.splice(1, 2); // remove function name and callback id to apply function with arguments\n // execute worker function and post result to callback\n try {\n postMessage([objectId, callbackId, { result: await self[fnName].apply(null, e.data) }]);\n }\n catch (e) {\n if (!(e instanceof Error))\n e = new Error(e);\n postMessage([objectId, callbackId, { error: LibraryUtils.serializeError(e) }]);\n }\n};\nself.initOneTime = async function () {\n if (!self.isInitialized) {\n self.WORKER_OBJECTS = {};\n self.isInitialized = true;\n MoneroUtils.PROXY_TO_WORKER = false;\n }\n};\n// --------------------------- STATIC UTILITIES -------------------------------\nself.httpRequest = async function (objectId, opts) {\n try {\n return await HttpClient.request(Object.assign(opts, { proxyToWorker: false }));\n }\n catch (err) {\n throw err.statusCode ? new Error(JSON.stringify({ statusCode: err.statusCode, statusMessage: err.message })) : err;\n }\n};\nself.setLogLevel = async function (objectId, level) {\n return LibraryUtils.setLogLevel(level);\n};\nself.getWasmMemoryUsed = async function (objectId) {\n return LibraryUtils.getWasmModule() && LibraryUtils.getWasmModule().HEAP8 ? LibraryUtils.getWasmModule().HEAP8.length : undefined;\n};\n// ----------------------------- MONERO UTILS ---------------------------------\nself.moneroUtilsGetIntegratedAddress = async function (objectId, networkType, standardAddress, paymentId) {\n return (await MoneroUtils.getIntegratedAddress(networkType, standardAddress, paymentId)).toJson();\n};\nself.moneroUtilsValidateAddress = async function (objectId, address, networkType) {\n return MoneroUtils.validateAddress(address, networkType);\n};\nself.moneroUtilsJsonToBinary = async function (objectId, json) {\n return MoneroUtils.jsonToBinary(json);\n};\nself.moneroUtilsBinaryToJson = async function (objectId, uint8arr) {\n return MoneroUtils.binaryToJson(uint8arr);\n};\nself.moneroUtilsBinaryBlocksToJson = async function (objectId, uint8arr) {\n return MoneroUtils.binaryBlocksToJson(uint8arr);\n};\n// ---------------------------- DAEMON METHODS --------------------------------\nself.daemonAddListener = async function (daemonId, listenerId) {\n let listener = new class extends MoneroDaemonListener {\n async onBlockHeader(blockHeader) {\n self.postMessage([daemonId, \"onBlockHeader_\" + listenerId, blockHeader.toJson()]);\n }\n };\n if (!self.daemonListeners)\n self.daemonListeners = {};\n self.daemonListeners[listenerId] = listener;\n await self.WORKER_OBJECTS[daemonId].addListener(listener);\n};\nself.daemonRemoveListener = async function (daemonId, listenerId) {\n if (!self.daemonListeners[listenerId])\n throw new MoneroError(\"No daemon worker listener registered with id: \" + listenerId);\n await self.WORKER_OBJECTS[daemonId].removeListener(self.daemonListeners[listenerId]);\n delete self.daemonListeners[listenerId];\n};\nself.connectDaemonRpc = async function (daemonId, config) {\n self.WORKER_OBJECTS[daemonId] = await MoneroDaemonRpc.connectToDaemonRpc(new MoneroDaemonConfig(config));\n};\nself.daemonGetRpcConnection = async function (daemonId) {\n let connection = await self.WORKER_OBJECTS[daemonId].getRpcConnection();\n return connection ? connection.getConfig() : undefined;\n};\nself.daemonIsConnected = async function (daemonId) {\n return self.WORKER_OBJECTS[daemonId].isConnected();\n};\nself.daemonGetVersion = async function (daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getVersion()).toJson();\n};\nself.daemonIsTrusted = async function (daemonId) {\n return self.WORKER_OBJECTS[daemonId].isTrusted();\n};\nself.daemonGetHeight = async function (daemonId) {\n return self.WORKER_OBJECTS[daemonId].getHeight();\n};\nself.daemonGetBlockHash = async function (daemonId, height) {\n return self.WORKER_OBJECTS[daemonId].getBlockHash(height);\n};\nself.daemonGetBlockTemplate = async function (daemonId, walletAddress, reserveSize) {\n return (await self.WORKER_OBJECTS[daemonId].getBlockTemplate(walletAddress, reserveSize)).toJson();\n};\nself.daemonGetLastBlockHeader = async function (daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getLastBlockHeader()).toJson();\n};\nself.daemonGetBlockHeaderByHash = async function (daemonId, hash) {\n return (await self.WORKER_OBJECTS[daemonId].getBlockHeaderByHash(hash)).toJson();\n};\nself.daemonGetBlockHeaderByHeight = async function (daemonId, height) {\n return (await self.WORKER_OBJECTS[daemonId].getBlockHeaderByHeight(height)).toJson();\n};\nself.daemonGetBlockHeadersByRange = async function (daemonId, startHeight, endHeight) {\n let blockHeadersJson = [];\n for (let blockHeader of await self.WORKER_OBJECTS[daemonId].getBlockHeadersByRange(startHeight, endHeight))\n blockHeadersJson.push(blockHeader.toJson());\n return blockHeadersJson;\n};\nself.daemonGetBlockByHash = async function (daemonId, blockHash) {\n return (await self.WORKER_OBJECTS[daemonId].getBlockByHash(blockHash)).toJson();\n};\nself.daemonGetBlocksByHash = async function (daemonId, blockHashes, startHeight, prune) {\n let blocksJson = [];\n for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByHash(blockHashes, startHeight, prune))\n blocksJson.push(block.toJson());\n return blocksJson;\n};\nself.daemonGetBlockByHeight = async function (daemonId, height) {\n return (await self.WORKER_OBJECTS[daemonId].getBlockByHeight(height)).toJson();\n};\nself.daemonGetBlocksByHeight = async function (daemonId, heights) {\n let blocksJson = [];\n for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByHeight(heights))\n blocksJson.push(block.toJson());\n return blocksJson;\n};\nself.daemonGetBlocksByRange = async function (daemonId, startHeight, endHeight) {\n let blocksJson = [];\n for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByRange(startHeight, endHeight))\n blocksJson.push(block.toJson());\n return blocksJson;\n};\nself.daemonGetBlocksByRangeChunked = async function (daemonId, startHeight, endHeight, maxChunkSize) {\n let blocksJson = [];\n for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize))\n blocksJson.push(block.toJson());\n return blocksJson;\n};\nself.daemonGetBlockHashes = async function (daemonId, blockHashes, startHeight) {\n throw new Error(\"worker.getBlockHashes not implemented\");\n};\n// TODO: factor common code with self.getTxs()\nself.daemonGetTxs = async function (daemonId, txHashes, prune) {\n // get txs\n let txs = await self.WORKER_OBJECTS[daemonId].getTxs(txHashes, prune);\n // collect unique blocks to preserve model relationships as trees (based on monero_wasm_bridge.cpp::get_txs)\n let blocks = [];\n let unconfirmedBlock = undefined;\n let seenBlocks = new Set();\n for (let tx of txs) {\n if (!tx.getBlock()) {\n if (!unconfirmedBlock)\n unconfirmedBlock = new MoneroBlock().setTxs([]);\n tx.setBlock(unconfirmedBlock);\n unconfirmedBlock.getTxs().push(tx);\n }\n if (!seenBlocks.has(tx.getBlock())) {\n seenBlocks.add(tx.getBlock());\n blocks.push(tx.getBlock());\n }\n }\n // serialize blocks to json\n for (let i = 0; i < blocks.length; i++)\n blocks[i] = blocks[i].toJson();\n return blocks;\n};\nself.daemonGetTxHexes = async function (daemonId, txHashes, prune) {\n return self.WORKER_OBJECTS[daemonId].getTxHexes(txHashes, prune);\n};\nself.daemonGetMinerTxSum = async function (daemonId, height, numBlocks) {\n return (await self.WORKER_OBJECTS[daemonId].getMinerTxSum(height, numBlocks)).toJson();\n};\nself.daemonGetFeeEstimate = async function (daemonId, graceBlocks) {\n return (await self.WORKER_OBJECTS[daemonId].getFeeEstimate(graceBlocks)).toJson();\n};\nself.daemonSubmitTxHex = async function (daemonId, txHex, doNotRelay) {\n return (await self.WORKER_OBJECTS[daemonId].submitTxHex(txHex, doNotRelay)).toJson();\n};\nself.daemonRelayTxsByHash = async function (daemonId, txHashes) {\n return self.WORKER_OBJECTS[daemonId].relayTxsByHash(txHashes);\n};\nself.daemonGetTxPool = async function (daemonId) {\n let txs = await self.WORKER_OBJECTS[daemonId].getTxPool();\n let block = new MoneroBlock().setTxs(txs);\n for (let tx of txs)\n tx.setBlock(block);\n return block.toJson();\n};\nself.daemonGetTxPoolHashes = async function (daemonId) {\n return self.WORKER_OBJECTS[daemonId].getTxPoolHashes();\n};\n//async getTxPoolBacklog() {\n// throw new MoneroError(\"Not implemented\");\n//}\nself.daemonGetTxPoolStats = async function (daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getTxPoolStats()).toJson();\n};\nself.daemonFlushTxPool = async function (daemonId, hashes) {\n return self.WORKER_OBJECTS[daemonId].flushTxPool(hashes);\n};\nself.daemonGetKeyImageSpentStatuses = async function (daemonId, keyImages) {\n return self.WORKER_OBJECTS[daemonId].getKeyImageSpentStatuses(keyImages);\n};\n//\n//async getOutputs(outputs) {\n// throw new MoneroError(\"Not implemented\");\n//}\nself.daemonGetOutputHistogram = async function (daemonId, amounts, minCount, maxCount, isUnlocked, recentCutoff) {\n let entriesJson = [];\n for (let entry of await self.WORKER_OBJECTS[daemonId].getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff)) {\n entriesJson.push(entry.toJson());\n }\n return entriesJson;\n};\n//\n//async getOutputDistribution(amounts, cumulative, startHeight, endHeight) {\n// throw new MoneroError(\"Not implemented\");\n//}\nself.daemonGetInfo = async function (daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getInfo()).toJson();\n};\nself.daemonGetSyncInfo = async function (daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getSyncInfo()).toJson();\n};\nself.daemonGetHardForkInfo = async function (daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getHardForkInfo()).toJson();\n};\nself.daemonGetAltChains = async function (daemonId) {\n let altChainsJson = [];\n for (let altChain of await self.WORKER_OBJECTS[daemonId].getAltChains())\n altChainsJson.push(altChain.toJson());\n return altChainsJson;\n};\nself.daemonGetAltBlockHashes = async function (daemonId) {\n return self.WORKER_OBJECTS[daemonId].getAltBlockHashes();\n};\nself.daemonGetDownloadLimit = async function (daemonId) {\n return self.WORKER_OBJECTS[daemonId].getDownloadLimit();\n};\nself.daemonSetDownloadLimit = async function (daemonId, limit) {\n return self.WORKER_OBJECTS[daemonId].setDownloadLimit(limit);\n};\nself.daemonResetDownloadLimit = async function (daemonId) {\n return self.WORKER_OBJECTS[daemonId].resetDownloadLimit();\n};\nself.daemonGetUploadLimit = async function (daemonId) {\n return self.WORKER_OBJECTS[daemonId].getUploadLimit();\n};\nself.daemonSetUploadLimit = async function (daemonId, limit) {\n return self.WORKER_OBJECTS[daemonId].setUploadLimit(limit);\n};\nself.daemonResetUploadLimit = async function (daemonId) {\n return self.WORKER_OBJECTS[daemonId].resetUploadLimit();\n};\nself.daemonGetPeers = async function (daemonId) {\n let peersJson = [];\n for (let peer of await self.WORKER_OBJECTS[daemonId].getPeers())\n peersJson.push(peer.toJson());\n return peersJson;\n};\nself.daemonGetKnownPeers = async function (daemonId) {\n let peersJson = [];\n for (let peer of await self.WORKER_OBJECTS[daemonId].getKnownPeers())\n peersJson.push(peer.toJson());\n return peersJson;\n};\nself.daemonSetOutgoingPeerLimit = async function (daemonId, limit) {\n return self.WORKER_OBJECTS[daemonId].setOutgoingPeerLimit(limit);\n};\nself.daemonSetIncomingPeerLimit = async function (daemonId, limit) {\n return self.WORKER_OBJECTS[daemonId].setIncomingPeerLimit(limit);\n};\nself.daemonGetPeerBans = async function (daemonId) {\n let bansJson = [];\n for (let ban of await self.WORKER_OBJECTS[daemonId].getPeerBans())\n bansJson.push(ban.toJson());\n return bansJson;\n};\nself.daemonSetPeerBans = async function (daemonId, bansJson) {\n let bans = [];\n for (let banJson of bansJson)\n bans.push(new MoneroBan(banJson));\n return self.WORKER_OBJECTS[daemonId].setPeerBans(bans);\n};\nself.daemonStartMining = async function (daemonId, address, numThreads, isBackground, ignoreBattery) {\n return self.WORKER_OBJECTS[daemonId].startMining(address, numThreads, isBackground, ignoreBattery);\n};\nself.daemonStopMining = async function (daemonId) {\n return self.WORKER_OBJECTS[daemonId].stopMining();\n};\nself.daemonGetMiningStatus = async function (daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].getMiningStatus()).toJson();\n};\nself.daemonSubmitBlocks = async function (daemonId, blockBlobs) {\n return self.WORKER_OBJECTS[daemonId].submitBlocks(blockBlobs);\n};\nself.daemonPruneBlockchain = async function (daemonId, check) {\n return (await self.WORKER_OBJECTS[daemonId].pruneBlockchain(check)).toJson();\n};\n//async checkForUpdate() {\n// throw new MoneroError(\"Not implemented\");\n//}\n//\n//async downloadUpdate(path) {\n// throw new MoneroError(\"Not implemented\");\n//}\nself.daemonStop = async function (daemonId) {\n return self.WORKER_OBJECTS[daemonId].stop();\n};\nself.daemonWaitForNextBlockHeader = async function (daemonId) {\n return (await self.WORKER_OBJECTS[daemonId].waitForNextBlockHeader()).toJson();\n};\n//------------------------------ WALLET METHODS -------------------------------\nself.openWalletData = async function (walletId, path, password, networkType, keysData, cacheData, daemonUriOrConfig) {\n let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined;\n self.WORKER_OBJECTS[walletId] = await MoneroWalletFull.openWallet({ path: \"\", password: password, networkType: networkType, keysData: keysData, cacheData: cacheData, server: daemonConnection, proxyToWorker: false });\n self.WORKER_OBJECTS[walletId].setBrowserMainPath(path);\n};\nself.createWalletKeys = async function (walletId, configJson) {\n let config = new MoneroWalletConfig(configJson);\n config.setProxyToWorker(false);\n self.WORKER_OBJECTS[walletId] = await MoneroWalletKeys.createWallet(config);\n};\nself.createWalletFull = async function (walletId, configJson) {\n let config = new MoneroWalletConfig(configJson);\n let path = config.getPath();\n config.setPath(\"\");\n config.setProxyToWorker(false);\n self.WORKER_OBJECTS[walletId] = await MoneroWalletFull.createWallet(config);\n self.WORKER_OBJECTS[walletId].setBrowserMainPath(path);\n};\nself.isViewOnly = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].isViewOnly();\n};\nself.getNetworkType = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getNetworkType();\n};\n//\n//async getVersion() {\n// throw new Error(\"Not implemented\");\n//}\nself.getSeed = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getSeed();\n};\nself.getSeedLanguage = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getSeedLanguage();\n};\nself.getSeedLanguages = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getSeedLanguages();\n};\nself.getPrivateSpendKey = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getPrivateSpendKey();\n};\nself.getPrivateViewKey = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getPrivateViewKey();\n};\nself.getPublicViewKey = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getPublicViewKey();\n};\nself.getPublicSpendKey = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getPublicSpendKey();\n};\nself.getAddress = async function (walletId, accountIdx, subaddressIdx) {\n return self.WORKER_OBJECTS[walletId].getAddress(accountIdx, subaddressIdx);\n};\nself.getAddressIndex = async function (walletId, address) {\n return (await self.WORKER_OBJECTS[walletId].getAddressIndex(address)).toJson();\n};\nself.setSubaddressLabel = async function (walletId, accountIdx, subaddressIdx, label) {\n await self.WORKER_OBJECTS[walletId].setSubaddressLabel(accountIdx, subaddressIdx, label);\n};\nself.getIntegratedAddress = async function (walletId, standardAddress, paymentId) {\n return (await self.WORKER_OBJECTS[walletId].getIntegratedAddress(standardAddress, paymentId)).toJson();\n};\nself.decodeIntegratedAddress = async function (walletId, integratedAddress) {\n return (await self.WORKER_OBJECTS[walletId].decodeIntegratedAddress(integratedAddress)).toJson();\n};\nself.setDaemonConnection = async function (walletId, config) {\n return self.WORKER_OBJECTS[walletId].setDaemonConnection(config ? new MoneroRpcConnection(Object.assign(config, { proxyToWorker: false })) : undefined);\n};\nself.getDaemonConnection = async function (walletId) {\n let connection = await self.WORKER_OBJECTS[walletId].getDaemonConnection();\n return connection ? connection.getConfig() : undefined;\n};\nself.isConnectedToDaemon = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].isConnectedToDaemon();\n};\nself.getRestoreHeight = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getRestoreHeight();\n};\nself.setRestoreHeight = async function (walletId, restoreHeight) {\n return self.WORKER_OBJECTS[walletId].setRestoreHeight(restoreHeight);\n};\nself.getDaemonHeight = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getDaemonHeight();\n};\nself.getDaemonMaxPeerHeight = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getDaemonMaxPeerHeight();\n};\nself.getHeightByDate = async function (walletId, year, month, day) {\n return self.WORKER_OBJECTS[walletId].getHeightByDate(year, month, day);\n};\nself.isDaemonSynced = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].isDaemonSynced();\n};\nself.getHeight = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getHeight();\n};\nself.addListener = async function (walletId, listenerId) {\n /**\n * Internal listener to bridge notifications to external listeners.\n *\n * TODO: MoneroWalletListener is not defined until scripts imported\n *\n * @private\n */\n class WalletWorkerHelperListener extends MoneroWalletListener {\n constructor(walletId, id, worker) {\n super();\n this.walletId = walletId;\n this.id = id;\n this.worker = worker;\n }\n getId() {\n return this.id;\n }\n async onSyncProgress(height, startHeight, endHeight, percentDone, message) {\n this.worker.postMessage([this.walletId, \"onSyncProgress_\" + this.getId(), height, startHeight, endHeight, percentDone, message]);\n }\n async onNewBlock(height) {\n this.worker.postMessage([this.walletId, \"onNewBlock_\" + this.getId(), height]);\n }\n async onBalancesChanged(newBalance, newUnlockedBalance) {\n this.worker.postMessage([this.walletId, \"onBalancesChanged_\" + this.getId(), newBalance.toString(), newUnlockedBalance.toString()]);\n }\n async onOutputReceived(output) {\n let block = output.getTx().getBlock();\n if (block === undefined)\n block = new MoneroBlock().setTxs([output.getTx()]);\n this.worker.postMessage([this.walletId, \"onOutputReceived_\" + this.getId(), block.toJson()]); // serialize from root block\n }\n async onOutputSpent(output) {\n let block = output.getTx().getBlock();\n if (block === undefined)\n block = new MoneroBlock().setTxs([output.getTx()]);\n this.worker.postMessage([this.walletId, \"onOutputSpent_\" + this.getId(), block.toJson()]); // serialize from root block\n }\n }\n let listener = new WalletWorkerHelperListener(walletId, listenerId, self);\n if (!self.listeners)\n self.listeners = [];\n self.listeners.push(listener);\n await self.WORKER_OBJECTS[walletId].addListener(listener);\n};\nself.removeListener = async function (walletId, listenerId) {\n for (let i = 0; i < self.listeners.length; i++) {\n if (self.listeners[i].getId() !== listenerId)\n continue;\n await self.WORKER_OBJECTS[walletId].removeListener(self.listeners[i]);\n self.listeners.splice(i, 1);\n return;\n }\n throw new MoneroError(\"Listener is not registered with wallet\");\n};\nself.isSynced = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].isSynced();\n};\nself.sync = async function (walletId, startHeight, allowConcurrentCalls) {\n return (await self.WORKER_OBJECTS[walletId].sync(undefined, startHeight, allowConcurrentCalls));\n};\nself.startSyncing = async function (walletId, syncPeriodInMs) {\n return self.WORKER_OBJECTS[walletId].startSyncing(syncPeriodInMs);\n};\nself.stopSyncing = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].stopSyncing();\n};\nself.scanTxs = async function (walletId, txHashes) {\n return self.WORKER_OBJECTS[walletId].scanTxs(txHashes);\n};\nself.rescanSpent = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].rescanSpent();\n};\nself.rescanBlockchain = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].rescanBlockchain();\n};\nself.getBalance = async function (walletId, accountIdx, subaddressIdx) {\n return (await self.WORKER_OBJECTS[walletId].getBalance(accountIdx, subaddressIdx)).toString();\n};\nself.getUnlockedBalance = async function (walletId, accountIdx, subaddressIdx) {\n return (await self.WORKER_OBJECTS[walletId].getUnlockedBalance(accountIdx, subaddressIdx)).toString();\n};\nself.getAccounts = async function (walletId, includeSubaddresses, tag) {\n let accountJsons = [];\n for (let account of await self.WORKER_OBJECTS[walletId].getAccounts(includeSubaddresses, tag))\n accountJsons.push(account.toJson());\n return accountJsons;\n};\nself.getAccount = async function (walletId, accountIdx, includeSubaddresses) {\n return (await self.WORKER_OBJECTS[walletId].getAccount(accountIdx, includeSubaddresses)).toJson();\n};\nself.createAccount = async function (walletId, label) {\n return (await self.WORKER_OBJECTS[walletId].createAccount(label)).toJson();\n};\nself.getSubaddresses = async function (walletId, accountIdx, subaddressIndices) {\n let subaddressJsons = [];\n for (let subaddress of await self.WORKER_OBJECTS[walletId].getSubaddresses(accountIdx, subaddressIndices))\n subaddressJsons.push(subaddress.toJson());\n return subaddressJsons;\n};\nself.createSubaddress = async function (walletId, accountIdx, label) {\n return (await self.WORKER_OBJECTS[walletId].createSubaddress(accountIdx, label)).toJson();\n};\n// TODO: easier or more efficient way than serializing from root blocks?\nself.getTxs = async function (walletId, blockJsonQuery) {\n // deserialize query which is json string rooted at block\n let query = new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0];\n // get txs\n let txs = await self.WORKER_OBJECTS[walletId].getTxs(query);\n // collect unique blocks to preserve model relationships as trees (based on monero_wasm_bridge.cpp::get_txs)\n let seenBlocks = new Set();\n let unconfirmedBlock = undefined;\n let blocks = [];\n for (let tx of txs) {\n if (!tx.getBlock()) {\n if (!unconfirmedBlock)\n unconfirmedBlock = new MoneroBlock().setTxs([]);\n tx.setBlock(unconfirmedBlock);\n unconfirmedBlock.getTxs().push(tx);\n }\n if (!seenBlocks.has(tx.getBlock())) {\n seenBlocks.add(tx.getBlock());\n blocks.push(tx.getBlock());\n }\n }\n // serialize blocks to json\n for (let i = 0; i < blocks.length; i++)\n blocks[i] = blocks[i].toJson();\n return { blocks: blocks };\n};\nself.getTransfers = async function (walletId, blockJsonQuery) {\n // deserialize query which is json string rooted at block\n let query = new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0].getTransferQuery();\n // get transfers\n let transfers = await self.WORKER_OBJECTS[walletId].getTransfers(query);\n // collect unique blocks to preserve model relationships as tree\n let unconfirmedBlock = undefined;\n let blocks = [];\n let seenBlocks = new Set();\n for (let transfer of transfers) {\n let tx = transfer.getTx();\n if (!tx.getBlock()) {\n if (!unconfirmedBlock)\n unconfirmedBlock = new MoneroBlock().setTxs([]);\n tx.setBlock(unconfirmedBlock);\n unconfirmedBlock.getTxs().push(tx);\n }\n if (!seenBlocks.has(tx.getBlock())) {\n seenBlocks.add(tx.getBlock());\n blocks.push(tx.getBlock());\n }\n }\n // serialize blocks to json\n for (let i = 0; i < blocks.length; i++)\n blocks[i] = blocks[i].toJson();\n return blocks;\n};\nself.getOutputs = async function (walletId, blockJsonQuery) {\n // deserialize query which is json string rooted at block\n let query = new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0].getOutputQuery();\n // get outputs\n let outputs = await self.WORKER_OBJECTS[walletId].getOutputs(query);\n // collect unique blocks to preserve model relationships as tree\n let unconfirmedBlock = undefined;\n let blocks = [];\n let seenBlocks = new Set();\n for (let output of outputs) {\n let tx = output.getTx();\n if (!tx.getBlock()) {\n if (!unconfirmedBlock)\n unconfirmedBlock = new MoneroBlock().setTxs([]);\n tx.setBlock(unconfirmedBlock);\n unconfirmedBlock.getTxs().push(tx);\n }\n if (!seenBlocks.has(tx.getBlock())) {\n seenBlocks.add(tx.getBlock());\n blocks.push(tx.getBlock());\n }\n }\n // serialize blocks to json\n for (let i = 0; i < blocks.length; i++)\n blocks[i] = blocks[i].toJson();\n return blocks;\n};\nself.exportOutputs = async function (walletId, all) {\n return self.WORKER_OBJECTS[walletId].exportOutputs(all);\n};\nself.importOutputs = async function (walletId, outputsHex) {\n return self.WORKER_OBJECTS[walletId].importOutputs(outputsHex);\n};\nself.getKeyImages = async function (walletId, all) {\n let keyImagesJson = [];\n for (let keyImage of await self.WORKER_OBJECTS[walletId].exportKeyImages(all))\n keyImagesJson.push(keyImage.toJson());\n return keyImagesJson;\n};\nself.importKeyImages = async function (walletId, keyImagesJson) {\n let keyImages = [];\n for (let keyImageJson of keyImagesJson)\n keyImages.push(new MoneroKeyImage(keyImageJson));\n return (await self.WORKER_OBJECTS[walletId].importKeyImages(keyImages)).toJson();\n};\n//async getNewKeyImagesFromLastImport() {\n// throw new MoneroError(\"Not implemented\");\n//}\nself.freezeOutput = async function (walletId, keyImage) {\n return self.WORKER_OBJECTS[walletId].freezeOutput(keyImage);\n};\nself.thawOutput = async function (walletId, keyImage) {\n return self.WORKER_OBJECTS[walletId].thawOutput(keyImage);\n};\nself.isOutputFrozen = async function (walletId, keyImage) {\n return self.WORKER_OBJECTS[walletId].isOutputFrozen(keyImage);\n};\nself.getDefaultFeePriority = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getDefaultFeePriority();\n};\nself.createTxs = async function (walletId, config) {\n if (typeof config === \"object\")\n config = new MoneroTxConfig(config);\n let txs = await self.WORKER_OBJECTS[walletId].createTxs(config);\n return txs[0].getTxSet().toJson();\n};\nself.sweepOutput = async function (walletId, config) {\n if (typeof config === \"object\")\n config = new MoneroTxConfig(config);\n let tx = await self.WORKER_OBJECTS[walletId].sweepOutput(config);\n return tx.getTxSet().toJson();\n};\nself.sweepUnlocked = async function (walletId, config) {\n if (typeof config === \"object\")\n config = new MoneroTxConfig(config);\n let txs = await self.WORKER_OBJECTS[walletId].sweepUnlocked(config);\n let txSets = [];\n for (let tx of txs)\n if (!GenUtils.arrayContains(txSets, tx.getTxSet()))\n txSets.push(tx.getTxSet());\n let txSetsJson = [];\n for (let txSet of txSets)\n txSetsJson.push(txSet.toJson());\n return txSetsJson;\n};\nself.sweepDust = async function (walletId, relay) {\n let txs = await self.WORKER_OBJECTS[walletId].sweepDust(relay);\n return txs.length === 0 ? {} : txs[0].getTxSet().toJson();\n};\nself.relayTxs = async function (walletId, txMetadatas) {\n return self.WORKER_OBJECTS[walletId].relayTxs(txMetadatas);\n};\nself.describeTxSet = async function (walletId, txSetJson) {\n return (await self.WORKER_OBJECTS[walletId].describeTxSet(new MoneroTxSet(txSetJson))).toJson();\n};\nself.signTxs = async function (walletId, unsignedTxHex) {\n return self.WORKER_OBJECTS[walletId].signTxs(unsignedTxHex);\n};\nself.submitTxs = async function (walletId, signedTxHex) {\n return self.WORKER_OBJECTS[walletId].submitTxs(signedTxHex);\n};\nself.signMessage = async function (walletId, message, signatureType, accountIdx, subaddressIdx) {\n return self.WORKER_OBJECTS[walletId].signMessage(message, signatureType, accountIdx, subaddressIdx);\n};\nself.verifyMessage = async function (walletId, message, address, signature) {\n return (await self.WORKER_OBJECTS[walletId].verifyMessage(message, address, signature)).toJson();\n};\nself.getTxKey = async function (walletId, txHash) {\n return self.WORKER_OBJECTS[walletId].getTxKey(txHash);\n};\nself.checkTxKey = async function (walletId, txHash, txKey, address) {\n return (await self.WORKER_OBJECTS[walletId].checkTxKey(txHash, txKey, address)).toJson();\n};\nself.getTxProof = async function (walletId, txHash, address, message) {\n return self.WORKER_OBJECTS[walletId].getTxProof(txHash, address, message);\n};\nself.checkTxProof = async function (walletId, txHash, address, message, signature) {\n return (await self.WORKER_OBJECTS[walletId].checkTxProof(txHash, address, message, signature)).toJson();\n};\nself.getSpendProof = async function (walletId, txHash, message) {\n return self.WORKER_OBJECTS[walletId].getSpendProof(txHash, message);\n};\nself.checkSpendProof = async function (walletId, txHash, message, signature) {\n return self.WORKER_OBJECTS[walletId].checkSpendProof(txHash, message, signature);\n};\nself.getReserveProofWallet = async function (walletId, message) {\n return self.WORKER_OBJECTS[walletId].getReserveProofWallet(message);\n};\nself.getReserveProofAccount = async function (walletId, accountIdx, amountStr, message) {\n return self.WORKER_OBJECTS[walletId].getReserveProofAccount(accountIdx, amountStr, message);\n};\nself.checkReserveProof = async function (walletId, address, message, signature) {\n return (await self.WORKER_OBJECTS[walletId].checkReserveProof(address, message, signature)).toJson();\n};\nself.getTxNotes = async function (walletId, txHashes) {\n return self.WORKER_OBJECTS[walletId].getTxNotes(txHashes);\n};\nself.setTxNotes = async function (walletId, txHashes, txNotes) {\n return self.WORKER_OBJECTS[walletId].setTxNotes(txHashes, txNotes);\n};\nself.getAddressBookEntries = async function (walletId, entryIndices) {\n let entriesJson = [];\n for (let entry of await self.WORKER_OBJECTS[walletId].getAddressBookEntries(entryIndices))\n entriesJson.push(entry.toJson());\n return entriesJson;\n};\nself.addAddressBookEntry = async function (walletId, address, description) {\n return self.WORKER_OBJECTS[walletId].addAddressBookEntry(address, description);\n};\nself.editAddressBookEntry = async function (walletId, index, setAddress, address, setDescription, description) {\n return self.WORKER_OBJECTS[walletId].editAddressBookEntry(index, setAddress, address, setDescription, description);\n};\nself.deleteAddressBookEntry = async function (walletId, index) {\n return self.WORKER_OBJECTS[walletId].deleteAddressBookEntry(index);\n};\nself.tagAccounts = async function (walletId, tag, accountIndices) {\n throw new Error(\"Not implemented\");\n};\nself.untagAccounts = async function (walletId, accountIndices) {\n throw new Error(\"Not implemented\");\n};\nself.getAccountTags = async function (walletId) {\n throw new Error(\"Not implemented\");\n};\nself.setAccountTagLabel = async function (walletId, tag, label) {\n throw new Error(\"Not implemented\");\n};\nself.getPaymentUri = async function (walletId, configJson) {\n return self.WORKER_OBJECTS[walletId].getPaymentUri(new MoneroTxConfig(configJson));\n};\nself.parsePaymentUri = async function (walletId, uri) {\n return (await self.WORKER_OBJECTS[walletId].parsePaymentUri(uri)).toJson();\n};\nself.getAttribute = async function (walletId, key) {\n return self.WORKER_OBJECTS[walletId].getAttribute(key);\n};\nself.setAttribute = async function (walletId, key, value) {\n return self.WORKER_OBJECTS[walletId].setAttribute(key, value);\n};\nself.startMining = async function (walletId, numThreads, backgroundMining, ignoreBattery) {\n return self.WORKER_OBJECTS[walletId].startMining(numThreads, backgroundMining, ignoreBattery);\n};\nself.stopMining = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].stopMining();\n};\nself.isMultisigImportNeeded = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].isMultisigImportNeeded();\n};\nself.isMultisig = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].isMultisig();\n};\nself.getMultisigInfo = async function (walletId) {\n return (await self.WORKER_OBJECTS[walletId].getMultisigInfo()).toJson();\n};\nself.prepareMultisig = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].prepareMultisig();\n};\nself.makeMultisig = async function (walletId, multisigHexes, threshold, password) {\n return await self.WORKER_OBJECTS[walletId].makeMultisig(multisigHexes, threshold, password);\n};\nself.exchangeMultisigKeys = async function (walletId, multisigHexes, password) {\n return (await self.WORKER_OBJECTS[walletId].exchangeMultisigKeys(multisigHexes, password)).toJson();\n};\nself.exportMultisigHex = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].exportMultisigHex();\n};\nself.importMultisigHex = async function (walletId, multisigHexes) {\n return self.WORKER_OBJECTS[walletId].importMultisigHex(multisigHexes);\n};\nself.signMultisigTxHex = async function (walletId, multisigTxHex) {\n return (await self.WORKER_OBJECTS[walletId].signMultisigTxHex(multisigTxHex)).toJson();\n};\nself.submitMultisigTxHex = async function (walletId, signedMultisigTxHex) {\n return self.WORKER_OBJECTS[walletId].submitMultisigTxHex(signedMultisigTxHex);\n};\nself.getData = async function (walletId) {\n return self.WORKER_OBJECTS[walletId].getData();\n};\nself.changePassword = async function (walletId, oldPassword, newPassword) {\n return self.WORKER_OBJECTS[walletId].changePassword(oldPassword, newPassword);\n};\nself.isClosed = async function (walletId) {\n return !self.WORKER_OBJECTS[walletId] || self.WORKER_OBJECTS[walletId].isClosed();\n};\nself.close = async function (walletId, save) {\n return self.WORKER_OBJECTS[walletId].close(save);\n delete self.WORKER_OBJECTS[walletId];\n};\n"],"names":["asn1","exports","bignum","define","base","constants","decoders","encoders","inherits","Entity","name","body","this","prototype","_createNamed","Base","Generated","entity","_initNamed","call","_getDecoder","enc","hasOwnProperty","decode","data","options","_getEncoder","encode","reporter","Reporter","Buffer","DecoderBuffer","isBuffer","offset","length","error","EncoderBuffer","value","Array","isArray","map","item","isEncoderBuffer","byteLength","isDecoderBuffer","constructor","save","restore","isEmpty","readUInt8","skip","raw","res","fail","bytes","_reporterState","slice","join","out","alloc","forEach","write","copy","Node","assert","tags","methods","concat","parent","state","_baseState","children","tag","args","reverseArgs","choice","optional","any","obj","use","useDecoder","key","explicit","implicit","contains","_wrap","module","stateProps","clone","cstate","prop","method","push","apply","arguments","_init","filter","child","equal","_useArgs","arg","Object","keys","Error","def","val","num","newKey","_decode","input","wrapResult","prevObj","result","present","prevKey","enterKey","_peekTag","isError","_decodeGeneric","_decodeChoice","e","enterObject","_decodeTag","start","track","path","_getUse","leaveObject","exitKey","leaveKey","_decodeList","test","_decodeStr","_decodeObjid","_decodeTime","_decodeNull","_decodeBool","_decodeInt","_use","match","some","node","type","_createEncoderBuffer","_encode","_encodeValue","undefined","_skipDefault","content","primitive","_encodeChoice","_encodePrimitive","cls","_encodeComposite","JSON","stringify","_encodeStr","_encodeObjid","_encodeTime","_encodeNull","_encodeInt","_encodeBool","_isNumstr","str","_isPrintstr","errors","ReporterError","msg","rethrow","pathLen","index","prev","now","err","inherited","elem","message","stack","partial","captureStackTrace","reverse","tagClass","tagClassByName","tagByName","_reverse","der","DERDecoder","tree","DERNode","derDecodeTag","buf","oct","tagStr","derDecodeLen","len","i","j","buffer","decodedTag","_skipUntilEnd","decoder","possibleEnd","unused","String","fromCharCode","readUInt16BE","numstr","toString","printstr","values","relative","identifiers","ident","subident","first","second","tmp","year","mon","day","hour","min","sec","Date","UTC","pem","PEMDecoder","lines","split","label","toUpperCase","re","end","base64","replace","from","DEREncoder","two","encodedTag","encodeTag","header","lenOctets","writeUInt16BE","charCodeAt","id","splice","size","objid","time","date","getUTCFullYear","getUTCMonth","getUTCDate","getUTCHours","getUTCMinutes","getUTCSeconds","numArray","toArray","sign","unshift","dataBuffer","defaultBuffer","PEMEncoder","p","ctor","superCtor","super_","TempCtor","BN","number","endian","isBN","negative","words","red","wordSize","window","parseHex4Bits","string","c","parseHexByte","lowerBound","r","parseBase","mul","Math","max","left","right","cmp","_initNumber","_initArray","_parseHex","_parseBase","ceil","w","off","strip","limbLen","limbPow","total","mod","word","imuln","_iaddn","pow","dest","_expand","_normSign","inspect","zeros","groupSizes","groupBases","smallMulTo","self","a","b","lo","carry","k","ncarry","rword","maxJ","padding","groupSize","groupBase","isZero","modn","idivn","toNumber","ret","toJSON","toBuffer","toArrayLike","ArrayType","reqLength","littleEndian","q","andln","iushrn","clz32","_countBits","t","_zeroBits","bitLength","hi","zeroBits","toTwos","width","abs","inotn","iaddn","fromTwos","testn","notn","ineg","isNeg","neg","iuor","ior","or","uor","iuand","iand","and","uand","iuxor","ixor","xor","uxor","bytesNeeded","bitsLeft","setn","bit","wbit","iadd","isub","add","sub","comb10MulTo","mid","o","a0","al0","ah0","a1","al1","ah1","a2","al2","ah2","a3","al3","ah3","a4","al4","ah4","a5","al5","ah5","a6","al6","ah6","a7","al7","ah7","a8","al8","ah8","a9","al9","ah9","b0","bl0","bh0","b1","bl1","bh1","b2","bl2","bh2","b3","bl3","bh3","b4","bl4","bh4","b5","bl5","bh5","b6","bl6","bh6","b7","bl7","bh7","b8","bl8","bh8","b9","bl9","bh9","w0","imul","w1","w2","w3","w4","w5","w6","w7","w8","w9","w10","w11","w12","w13","w14","w15","w16","w17","w18","jumboMulTo","FFTM","mulp","x","y","mulTo","hncarry","bigMulTo","makeRBT","N","l","revBin","rb","permute","rbt","rws","iws","rtws","itws","transform","s","rtwdf","cos","PI","itwdf","sin","rtwdf_","itwdf_","ie","ro","io","rx","guessLen13b","n","m","odd","conjugate","normalize13b","ws","round","convert13b","stub","ph","_","rwst","iwst","nrws","nrwst","niwst","rmws","mulf","muln","sqr","isqr","toBitArray","iushln","bits","carryMask","newCarry","ishln","hint","extended","h","mask","maskedWords","ishrn","shln","ushln","shrn","ushrn","imaskn","maskn","isubn","addn","subn","iabs","_ishlnsubmul","shift","_wordDiv","mode","bhi","diff","qj","div","divmod","positive","divn","umod","divRound","dm","half","r2","acc","egcd","A","B","C","D","g","isEven","yp","xp","im","isOdd","jm","gcd","_invmp","x1","x2","delta","cmpn","invm","bincn","ucmp","gtn","gt","gten","gte","ltn","lt","lten","lte","eqn","eq","Red","toRed","ctx","convertTo","_forceRed","fromRed","convertFrom","forceRed","redAdd","redIAdd","redSub","redISub","redShl","shl","redMul","_verify2","redIMul","redSqr","_verify1","redISqr","redSqrt","sqrt","redInvm","redNeg","redPow","primes","k256","p224","p192","p25519","MPrime","_tmp","K256","P224","P192","P25519","prime","_prime","Mont","imod","rinv","minv","ireduce","rlen","imulK","_strip","output","outLen","next","mod3","one","nOne","lpow","z","inv","wnd","current","currentLen","mont","u","_typeof","Symbol","iterator","_defineProperties","target","props","descriptor","enumerable","configurable","writable","defineProperty","prim","toPrimitive","TypeError","_toPrimitive","_createClass","Constructor","protoProps","staticProps","isDeepEqual","isDeepStrictEqual","_require$codes","codes","ERR_AMBIGUOUS_ARGUMENT","ERR_INVALID_ARG_TYPE","ERR_INVALID_ARG_VALUE","ERR_INVALID_RETURN_VALUE","ERR_MISSING_ARGS","AssertionError","_require$types","isPromise","isRegExp","objectAssign","objectIs","RegExpPrototypeTest","lazyLoadComparison","comparison","Map","warned","ok","NO_EXCEPTION_SENTINEL","innerFail","innerOk","fn","argLen","generatedMessage","actual","expected","operator","stackStartFn","_len","_key","internalMessage","argsLen","process","emitWarning","console","warn","bind","errArgs","notEqual","deepEqual","notDeepEqual","deepStrictEqual","notDeepStrictEqual","strictEqual","notStrictEqual","Comparison","_this","instance","_classCallCheck","expectedException","compareExceptionKey","isPrototypeOf","getActual","checkIsPromise","then","catch","waitForActual","promiseFn","Promise","resolve","resultPromise","expectsError","details","fnType","expectsNoError","internalMatch","regexp","fnName","strict","_len6","_key6","throws","_len2","_key2","rejects","_len3","_key3","doesNotThrow","_len4","_key4","doesNotReject","_len5","_key5","ifError","newErr","origStack","tmp2","tmp1","pos","indexOf","doesNotMatch","ownKeys","getOwnPropertySymbols","getOwnPropertyDescriptor","_objectSpread","_toPropertyKey","getOwnPropertyDescriptors","defineProperties","_possibleConstructorReturn","_assertThisInitialized","ReferenceError","_wrapNativeSuper","Class","_cache","Function","has","get","set","Wrapper","_construct","_getPrototypeOf","create","_setPrototypeOf","Parent","_isNativeReflectConstruct","Reflect","construct","sham","Proxy","Boolean","valueOf","setPrototypeOf","__proto__","getPrototypeOf","endsWith","search","this_len","substring","blue","green","white","kReadableOperator","strictEqualObject","notStrictEqualObject","notIdentical","copyError","source","inspectValue","compact","customInspect","depth","maxArrayLength","Infinity","showHidden","breakLength","showProxy","sorted","getters","_Error","_inspect$custom","subClass","superClass","_inherits","Derived","hasNativeReflectConstruct","_super","Super","NewTarget","limit","stackTraceLimit","stderr","isTTY","getColorDepth","other","lastPos","skipped","actualInspected","actualLines","expectedLines","indicator","inputLength","columns","count","floor","maxCount","log","repeat","pop","maxLines","_actualLines","printedLines","skippedMsg","cur","expectedLine","actualLine","divergingLines","createErrDiff","_res","knownOperators","code","recurseTimes","custom","util","createErrorType","NodeError","_Base","arg1","arg2","arg3","getMessage","oneOf","thing","determiner","substr","reason","inspected","RangeError","_slicedToArray","arr","_arrayWithHoles","f","done","return","_iterableToArrayLimit","minLen","_arrayLikeToArray","_unsupportedIterableToArray","_nonIterableRest","arr2","regexFlagsSupported","flags","arrayFromSet","array","arrayFromMap","is","objectGetOwnPropertySymbols","numberIsNaN","Number","isNaN","uncurryThis","propertyIsEnumerable","objectToString","isAnyArrayBuffer","isArrayBufferView","isDate","isMap","isSet","isNativeError","isBoxedPrimitive","isNumberObject","isStringObject","isBooleanObject","isBigIntObject","isSymbolObject","isFloat32Array","isFloat64Array","isNonIndex","getOwnNonIndexProperties","compare","kNoIterator","kIsArray","kIsSet","kIsMap","innerDeepEqual","val1","val2","memos","buf1","buf2","val1Tag","keys1","keys2","keyCheck","getTime","RegExp","Uint8Array","byteOffset","areSimilarTypedArrays","areSimilarFloatArrays","_keys","_keys2","BigInt","isEqualBoxedPrimitive","getEnumerables","iterationType","aKeys","bKeys","symbolKeysA","symbolKeysB","_symbolKeysB","position","val2MemoA","val2MemoB","areEq","memo","aValues","Set","setMightHaveLoosePrim","bValues","_i","_val","setHasEqualElement","setEquiv","aEntries","_aEntries$i","item1","item2","mapMightHaveLoosePrim","bEntries","_i2","_bEntries$_i","mapHasEqualEntry","mapEquiv","keysA","objEquiv","delete","setValues","findLooseMatchingPrimitives","altValue","curB","key1","key2","arrayLike","newLen","newArr","idx","callArgs","initialParams","callback","isObject","hasSetImmediate","setImmediate","hasNextTick","nextTick","fallback","setTimeout","wrap","defer","setImmediate$1","asyncify","func","invokeCallback","supportsSymbol","isAsync","toStringTag","wrapAsync","asyncFn","applyEach$1","eachfn","fns","go","that","cb","freeGlobal","freeSelf","root","Symbol$1","objectProto","nativeObjectToString","symToStringTag$1","nativeObjectToString$1","nullTag","undefinedTag","symToStringTag","baseGetTag","isOwn","unmasked","getRawTag","asyncTag","funcTag","genTag","proxyTag","MAX_SAFE_INTEGER","isLength","isArrayLike","isFunction","breakLoop","noop","once","callFn","iteratorSymbol","getIterator","coll","isObjectLike","baseIsArguments","objectProto$3","hasOwnProperty$2","isArguments","freeExports","nodeType","freeModule","MAX_SAFE_INTEGER$1","reIsUint","isIndex","typedArrayTags","freeExports$1","freeModule$1","freeProcess","nodeUtil","require","types","binding","nodeIsTypedArray","isTypedArray","hasOwnProperty$1","arrayLikeKeys","isArr","isArg","isBuff","isType","skipIndexes","iteratee","baseTimes","objectProto$5","nativeKeys","overArg","hasOwnProperty$3","baseKeys","object","Ctor","createArrayIterator","okeys","createES2015Iterator","onlyOnce","_eachOfLimit","nextElem","running","looping","iterateeCallback","replenish","eachOfLimit","doLimit","iterable","eachOfArrayLike","completed","iteratorCallback","eachOfGeneric","eachOf","doParallel","_asyncMap","results","counter","_iteratee","v","applyEach","doParallelLimit","mapLimit","mapSeries","applyEachSeries","arrayEach","fromRight","baseFor","keysFunc","baseForOwn","baseIsNaN","baseIndexOf","fromIndex","strictIndexOf","predicate","baseFindIndex","auto","tasks","concurrency","numTasks","runningTasks","hasError","listeners","readyTasks","readyToCheck","uncheckedDependencies","enqueueTask","task","taskCallback","safeResults","rkey","processQueue","taskFn","runTask","run","getDependents","taskName","dependencies","remainingDependencies","dependencyName","taskListeners","dependent","checkForDeadlocks","arrayMap","symbolTag","INFINITY","symbolProto","symbolToString","baseToString","isSymbol","castSlice","baseSlice","reHasUnicode","rsAstralRange$1","rsAstral","rsCombo","rsFitz","rsNonAstral","rsRegional","rsSurrPair","reOptMod","rsModifier","rsOptVar","rsSeq","rsSymbol","reUnicode","stringToArray","hasUnicode","unicodeToArray","asciiToArray","reTrim","trim","chars","guard","strSymbols","chrSymbols","charsStartIndex","charsEndIndex","FN_ARGS","FN_ARG_SPLIT","FN_ARG","STRIP_COMMENTS","autoInject","newTasks","params","fnIsAsync","hasNoDeps","newTask","parseParams","taskCb","newArgs","DLL","head","tail","setInitial","dll","queue","worker","payload","_worker","numRunning","workersList","processingScheduled","_insert","insertAtFront","started","idle","drain","_tasks","_next","unsaturated","isProcessing","saturated","empty","paused","kill","remove","testFn","pause","resume","cargo","removeLink","insertAfter","newNode","insertBefore","curr","eachOfSeries","reduce","seq","_functions","newargs","nextargs","compose","_concat","concatLimit","mapResults","concatSeries","constant","identity","_createTester","check","getResult","testResult","testPassed","_findGetResult","detect","detectLimit","detectSeries","consoleFunc","dir","doDuring","_fn","_test","truth","doWhilst","doUntil","during","_withoutIndex","eachLimit","eachLimit$1","eachSeries","ensureAsync","sync","innerArgs","notId","every","everyLimit","everySeries","baseProperty","filterArray","truthValues","filterGeneric","sort","_filter","filterLimit","filterSeries","forever","errback","groupByLimit","groupBy","groupBySeries","mapValuesLimit","newObj","mapValues","mapValuesSeries","memoize","hasher","queues","memoized","unmemoized","_parallel","parallelLimit","parallelLimit$1","queue$1","items","priorityQueue","priority","nextNode","race","reduceRight","reflect","reflectCallback","cbArg","reflectAll","reject$1","reject","rejectLimit","rejectSeries","constant$1","retry","opts","times","intervalFunc","interval","errorFilter","parseTimes","_task","attempt","retryAttempt","retryable","series","someLimit","someSeries","sortBy","comparator","criteria","timeout","milliseconds","info","timer","timedOut","clearTimeout","nativeCeil","nativeMax","timeLimit","step","baseRange","timesSeries","accumulator","tryEach","unmemoize","whilst","until","waterfall","taskIndex","nextTask","each","parallel","timesLimit","all","allLimit","allSeries","anyLimit","anySeries","find","findLimit","findSeries","forEachSeries","forEachLimit","forEachOf","forEachOfSeries","forEachOfLimit","inject","foldl","foldr","select","selectLimit","selectSeries","wrapSync","factory","_scriptName","monero_ts","document","currentScript","src","moduleArg","readyPromiseResolve","readyPromiseReject","readAsync","readBinary","Module","readyPromise","ENVIRONMENT_IS_WEB","ENVIRONMENT_IS_WORKER","importScripts","ENVIRONMENT_IS_NODE","versions","moduleOverrides","assign","thisProgram","quit_","status","toThrow","scriptDirectory","fs","nodePath","__dirname","filename","isFileURI","URL","normalize","readFileSync","binary","readFile","argv","exitCode","location","href","startsWith","lastIndexOf","url","xhr","XMLHttpRequest","open","responseType","send","response","onload","onerror","fetch","credentials","arrayBuffer","wasmMemory","wasmBinary","intArrayFromBase64","decoded","atob","EXITSTATUS","HEAP8","HEAPU8","HEAP16","HEAPU16","HEAP32","HEAPU32","HEAPF32","HEAP64","HEAPU64","HEAPF64","ABORT","updateMemoryViews","Int8Array","Int16Array","Uint16Array","Int32Array","Uint32Array","Float32Array","Float64Array","BigInt64Array","BigUint64Array","__ATPRERUN__","__ATINIT__","__ATPOSTRUN__","runDependencies","runDependencyWatcher","dependenciesFulfilled","addRunDependency","removeRunDependency","clearInterval","abort","what","WebAssembly","RuntimeError","wasmBinaryFile","dataURIPrefix","isDataURI","instantiateArrayBuffer","binaryFile","imports","receiver","file","bin","ds","DecompressionStream","decompressedStream","ReadableStream","controller","enqueue","close","pipeThrough","Response","tryParseAsDataURI","getBinarySync","getBinaryPromise","instantiate","ExitStatus","callRuntimeCallbacks","callbacks","noExitRuntime","stackRestore","__emscripten_stack_restore","stackSave","_emscripten_stack_get_current","_BIO_free","_BIO_new_mem_buf","_CONF_modules_unload","_CRYPTO_free","_PEM_read_bio","_PEM_write","__ZN2hw6trezor12register_allEv","__ZN4epee13file_io_utils19load_file_to_stringERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERS7_m","__ZN4epee13file_io_utils19save_string_to_fileERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_","__ZNK5tools6Notify6notifyEPKcS2_z","UTF8Decoder","TextDecoder","UTF8ArrayToString","heapOrArray","maxBytesToRead","endIdx","endPtr","subarray","u0","u1","u2","ch","UTF8ToString","ptr","exceptionCaught","uncaughtExceptionCount","exceptionLast","ExceptionInfo","excPtr","set_type","get_type","set_destructor","destructor","get_destructor","set_caught","caught","get_caught","set_rethrown","rethrown","get_rethrown","init","set_adjusted_ptr","adjustedPtr","get_adjusted_ptr","setTempRet0","__emscripten_tempret_set","findMatchingCatch","thrown","thrownType","caughtType","adjusted_ptr_addr","___cxa_can_catch","___cxa_rethrow","syscallGetVarargI","SYSCALLS","varargs","syscallGetVarargP","PATH","isAbs","charAt","splitPath","exec","normalizeArray","parts","allowAboveRoot","up","last","isAbsolute","trailingSlash","dirname","basename","lastSlash","paths","join2","randomFill","view","crypto","getRandomValues","crypto_module","randomBytes","initRandomFill","PATH_FS","resolvedPath","resolvedAbsolute","FS","cwd","to","fromParts","toParts","samePartsLength","outputParts","FS_stdin_getChar_buffer","lengthBytesUTF8","stringToUTF8Array","heap","outIdx","maxBytesToWrite","startIdx","intArrayFromString","stringy","dontAddNull","u8array","numBytesWritten","embind_charCodes","BindingError","InternalError","TTY","ttys","shutdown","register","dev","ops","registerDevice","stream_ops","stream","tty","rdev","ErrnoError","seekable","fsync","read","get_char","bytesRead","timestamp","put_char","default_tty_ops","fd","stdin","readSync","includes","prompt","FS_stdin_getChar","ioctl_tcgets","c_iflag","c_oflag","c_cflag","c_lflag","c_cc","ioctl_tcsets","optional_actions","ioctl_tiocgwinsz","default_tty1_ops","alignMemory","alignment","mmapAlloc","_emscripten_builtin_memalign","address","fill","zeroMemory","MEMFS","ops_table","mount","createNode","isBlkdev","isFIFO","getattr","node_ops","setattr","lookup","mknod","rename","unlink","rmdir","readdir","symlink","llseek","allocate","mmap","msync","link","readlink","chrdev","chrdev_stream_ops","isDir","contents","isFile","usedBytes","isLink","isChrdev","getFileDataAsTypedArray","expandFileStorage","newCapacity","prevCapacity","oldContents","resizeFileStorage","newSize","attr","ino","nlink","uid","gid","atime","mtime","ctime","blksize","blocks","genericErrors","old_node","new_dir","new_name","new_node","lookupNode","entries","newname","oldpath","canOwn","whence","prot","allocated","mmapFlags","preloadPlugins","FS_getMode","canRead","canWrite","mounts","devices","streams","nextInode","nameTable","currentPath","initialized","ignorePermissions","errno","filesystems","syncFSRequests","FSStream","shared","isRead","isWrite","isAppend","FSNode","mounted","readMode","writeMode","isFolder","isDevice","lookupPath","follow_mount","recurse_count","current_path","islast","isMountpoint","follow","getPath","isRoot","mountpoint","hashName","parentid","hash","hashAddNode","name_next","hashRemoveNode","errCode","mayLookup","nodeName","destroyNode","isSocket","flagsToPermissionString","flag","perms","nodePermissions","mayCreate","mayDelete","isdir","mayOpen","MAX_OPEN_FDS","nextfd","getStreamChecked","getStream","createStream","closeStream","dupStream","origStream","dup","device","getDevice","major","minor","makedev","ma","mi","getMounts","syncfs","populate","doCallback","errored","pseudo","mountRoot","unmount","mkdir","mkdirTree","dirs","d","mkdev","newpath","old_path","new_path","old_dir","old_dirname","new_dirname","old_name","stat","dontFollow","lstat","chmod","lchmod","fchmod","chown","lchown","fchown","truncate","ftruncate","utime","FS_modeStringToFlags","created","ungotten","readFiles","isClosed","getdents","seeking","bytesWritten","ioctl","cmd","encoding","writeFile","actualNumBytes","ArrayBuffer","isView","chdir","createDefaultDirectories","createDefaultDevices","randomBuffer","randomLeft","randomByte","createDevice","createSpecialDirectories","proc_self","createStandardStreams","staticInit","quit","findObject","dontResolveLastLink","analyzePath","exists","parentExists","parentPath","parentObject","createPath","part","createFile","properties","createDataFile","forceLoadFile","createLazyFile","LazyUint8Array","lengthKnown","chunks","chunkOffset","chunkSize","chunkNum","getter","setDataGetter","cacheLength","datalength","getResponseHeader","hasByteServing","usesGzip","lazyArray","setRequestHeader","overrideMimeType","responseText","doXHR","_length","_chunkSize","writeChunks","DEFAULT_POLLMASK","calculateAt","dirfd","allowEmpty","getStreamFromFD","doStat","doMsync","addr","getStr","bigintToI53Checked","NaN","stringToUTF8","outPtr","readLatin1String","awaitingDependencies","registeredTypes","typeDependencies","throwBindingError","throwInternalError","registerType","rawType","registeredInstance","ignoreDuplicateRegistrations","sharedRegisterType","integerReadValueFromPointer","signed","pointer","emval_freelist","emval_handles","__emval_decref","handle","Emval","readPointer","wasmTable","UnboundTypeError","_emscripten_get_now","EmValType","fromWireType","rv","toWireType","destructors","argPackAdvance","readValueFromPointer","destructorFunction","floatReadValueFromPointer","createNamedFunction","runDestructors","del","runAndAbortIfError","handleException","keepRuntimeAlive","runtimeKeepaliveCounter","_proc_exit","_exit","callUserCallback","maybeExit","Asyncify","instrumentWasmImports","importPattern","original","instrumentWasmExports","exportCallStack","maybeStopUnwind","State","Normal","Unwinding","Rewinding","Disabled","StackSize","currData","handleSleepReturnValue","callStackNameToId","callStackIdToName","callStackId","asyncPromiseHandlers","sleepCallbacks","getCallStackId","funcName","_asyncify_stop_unwind","Fibers","trampoline","whenDone","allocateData","_malloc","setDataHeader","setDataRewindFunc","stackSize","bottomOfCallStack","rewindId","getDataRewindFuncName","getDataRewindFunc","wasmExports","doRewind","handleSleep","startAsync","reachedCallback","reachedAfterCallback","_asyncify_start_rewind","Browser","mainLoop","asyncWasmReturnValue","handled","_asyncify_start_unwind","_asyncify_stop_rewind","_free","handleAsync","wakeUp","ensureOverloadTable","proto","methodName","humanName","overloadTable","prevFunc","argCount","embind__requireFunction","signature","rawFunction","sig","fp","rtn","dynCallLegacy","dynCall","getTypeName","___getTypeName","UTF16Decoder","UTF16ToString","maxIdx","codeUnit","stringToUTF16","startPtr","numCharsToWrite","lengthBytesUTF16","UTF32ToString","utf32","stringToUTF32","lengthBytesUTF32","getExecutableName","emval_methodCallers","requireRegisteredType","impl","reflectConstruct","MONTH_DAYS_LEAP_CUMULATIVE","MONTH_DAYS_REGULAR_CUMULATIVE","performance","growMemory","pages","grow","ENV","getEnvStrings","strings","env","USER","LOGNAME","PWD","HOME","LANG","navigator","languages","doWritev","iov","iovcnt","_rx_slow_hash","_v4_generate_JIT_code","functionsInTableMap","baseErrorType","errorClass","uleb128Encode","freeTableIndexes","setWasmTableEntry","createPreloadedFile","dontCreateFile","preFinish","fullname","processData","byteArray","finish","fileData","FS_createDataFile","plugin","FS_handledByPreloadPlugin","noRunDep","dep","asyncLoad","embind_init_charCodes","super","calledRun","wasmImports","Ta","Va","Ra","Q","Ua","Wa","Ya","fa","ea","Xa","condition","line","___cxa_increment_exception_refcount","___cxa_get_exception_ptr","_setThrew","___cxa_decrement_exception_refcount","arg0","T","db","ya","ua","ta","cwdLengthInBytes","Ca","op","termios","argp","winsize","va","pa","wa","nofollow","U","kb","bufsize","endChar","jb","olddirfd","newdirfd","xa","ib","gb","Aa","$","primitiveType","minRange","maxRange","isUnsignedType","embindRepr","Ka","trueValue","falseValue","wt","Ja","rawArgTypesAddr","rawInvoker","argTypes","firstElement","heap32VectorToArray","argsIndex","getFunctionName","numArguments","exposePublicSymbol","unboundTypes","seen","visit","throwUnboundTypeError","myTypes","dependentTypes","getTypeConverters","onComplete","typeConverters","myTypeConverters","unregisteredTypes","registered","dt","whenDependentTypesAreResolved","invokerArgsArray","replacePublicSymbol","classType","cppInvokerFunc","cppTargetFunc","isClassMethodFunc","needsDestructorStack","usesDestructorStack","returns","expectedArgCount","argsWired","invokerFuncArgs","thisWired","onDone","param","craftInvokerFunction","bitshift","dataTypeIndex","TA","decodeMemoryView","Z","stdStringIsUTF8","decodeStartPtr","currentBytePtr","stringSegment","valueIsOfTypeString","Uint8ClampedArray","charCode","charSize","decodeString","encodeString","readCharAt","lengthBytesUTF","La","isVoid","za","mb","caller","destructorsRef","Ia","Fa","kind","emval_lookupTypes","retType","argN","functionName","returnType","emval_returnValue","Y","Ga","Ea","tmPtr","getUTCDay","yday","na","dst","guessedOffset","getTimezoneOffset","getFullYear","summerOffset","winterOffset","dstOffset","nonDstOffset","trueOffset","setTime","getDay","getMonth","getDate","ydayFromDate","getSeconds","getMinutes","getHours","getYear","timeMs","ja","ka","la","oa","timezone","daylight","std_name","dst_name","currentYear","winter","summer","stdTimezoneOffset","extractZone","timezoneOffset","absOffset","padStart","winterName","summerName","K","hb","J","fb","requestedSize","oldSize","maxHeapSize","cutDown","overGrownHeapSize","ra","__environ","environ_buf","bufSize","stringToAscii","sa","penviron_count","penviron_buf_size","R","G","lb","pnum","V","doReadv","qa","newOffset","L","ga","sp","dynCall_diii","ha","dynCall_fiii","dynCall_i","dynCall_ii","dynCall_iii","dynCall_iiii","dynCall_iiiii","ia","dynCall_iiiiid","dynCall_iiiiii","dynCall_iiiiiii","P","dynCall_iiiiiiii","dynCall_iiiiiiiii","Na","dynCall_iiiiiiiiii","I","a10","a11","dynCall_iiiiiiiiiiii","ab","dynCall_iiiiij","da","dynCall_iiiiiji","$a","dynCall_iiiiijj","dynCall_iiiiji","ba","dynCall_iij","eb","dynCall_j","S","dynCall_ji","X","dynCall_jii","W","dynCall_jiii","M","dynCall_jiiii","Oa","dynCall_jiiiii","dynCall_v","dynCall_vi","dynCall_vii","dynCall_viii","dynCall_viiii","E","dynCall_viiiii","O","dynCall_viiiiii","dynCall_viiiiiii","Sa","dynCall_viiiiiiii","F","dynCall_viiiiiiiiii","H","a12","a13","a14","a15","dynCall_viiiiiiiiiiiiiii","Ha","dynCall_viiiji","Qa","dynCall_viiijjjjii","aa","dynCall_viij","bb","dynCall_viijii","Za","dynCall_viijiiiij","ca","dynCall_viijjd","dynCall_viji","Pa","dynCall_vijiijii","_a","uri","username","password","reject_unauthorized_fn_id","body_length","HttpClient","LibraryUtils","GenUtils","loadWasmModule","BYTES_PER_ELEMENT","wakeUpCalled","request","resolveWithFullResponse","rejectUnauthorized","isRejectUnauthorized","resp","respBin","nDataBytes","bodyPtr","respContainer","statusCode","statusText","headers","bodyLength","respStr","lengthBytes","nb","Ba","Ma","Da","receiveInstance","createWasm","__emscripten_tempret_get","doRun","postRun","preRun","WeakMap","funcPtr","updateTableMap","getFunctionAddress","getEmptyTableSlot","wrapped","typeNames","parameters","sigToWasmTypes","typeSectionBody","sigRet","sigParam","typeCodes","generateFuncType","Instance","wrappedFunc","convertJsFunctionToWasm","chr","runCaller","b64","lens","getLens","validLen","placeHoldersLen","toByteArray","Arr","_byteLength","curByte","revLookup","fromByteArray","uint8","extraBytes","maxChunkLength","len2","encodeChunk","move","_move","for","modrn","allocUnsafe","_toArrayLikeLE","_toArrayLikeBE","isNegNum","Rand","rand","generate","_rand","getBytes","getByte","msCrypto","asUInt32Array","readUInt32BE","scrubVec","cryptBlock","keySchedule","SUB_MIX","SBOX","nRounds","t0","t1","t2","t3","SUB_MIX0","SUB_MIX1","SUB_MIX2","SUB_MIX3","s0","s1","s2","s3","ksRow","RCON","INV_SBOX","INV_SUB_MIX","xi","sx","x4","x8","AES","_reset","blockSize","keySize","keyWords","ksRows","invKeySchedule","ik","ksR","tt","_nRounds","_keySchedule","_invKeySchedule","encryptBlockRaw","encryptBlock","writeUInt32BE","decryptBlock","m1","scrub","aes","Transform","GHASH","incr32","StreamCipher","iv","decrypt","_cipher","ck","_ghash","_finID","ghash","toPad","update","ivBits","writeUIntBE","calcIv","_prev","_secCache","_decrypt","_alen","_mode","_authTag","_called","_update","chunk","rump","encrypt","_final","final","xorTest","getAuthTag","setAuthTag","setAAD","ciphers","deciphers","modes","createCipher","Cipher","createCipheriv","Cipheriv","createDecipher","Decipher","createDecipheriv","Decipheriv","listCiphers","getCiphers","AuthCipher","MODES","ebtk","Splitter","_last","_autopadding","cache","suite","config","toLowerCase","flush","padded","unpad","setAutoPadding","setTo","autoPadding","PADDING","equals","padBuff","writeUInt8","ZEROES","fromArray","block","_multiply","lsbVi","Vi","Zi","abl","bl","pad","encryptStart","encryptByte","byteParam","shiftIn","getBlock","modeModules","ECB","CBC","CFB","CFB8","CFB1","OFB","CTR","GCM","DES","aesModes","desModes","keyLen","ivLen","CipherBase","des","EDE","modeName","_des","des3","getr","priv","modulus","prime1","prime2","crt","blinds","blinder","publicExponent","unblinder","blind","blinded","c1","c2","qinv","coefficient","exponent1","m2","exponent2","createHash","verify","algorithms","Sign","algorithm","Writable","_hashType","_hash","_tag","_signType","Verify","createSign","createVerify","_write","digest","sigBuffer","createHmac","EC","parseKeys","curves","getKey","algo","hlen","hbits","bits2int","bits2octets","obits","makeKey","kv","makeR","hashType","signType","curve","curveId","keyFromPrivate","privateKey","toDER","ecSign","priv_key","dsaSign","checkValue","pub","pubkey","subjectPrivateKey","ecVerify","pub_key","unpacked","montp","dsaVerify","padNum","ieee754","customInspectSymbol","SlowBuffer","INSPECT_MAX_BYTES","K_MAX_LENGTH","createBuffer","encodingOrOffset","isEncoding","fromString","arrayView","isInstance","fromArrayBuffer","fromArrayLike","fromArrayView","SharedArrayBuffer","checked","fromObject","assertSize","mustMatch","loweredCase","utf8ToBytes","base64ToBytes","slowToString","hexSlice","utf8Slice","asciiSlice","latin1Slice","base64Slice","utf16leSlice","swap","bidirectionalIndexOf","arrayIndexOf","indexSize","arrLength","valLength","foundIndex","found","hexWrite","remaining","strLen","parsed","parseInt","utf8Write","blitBuffer","asciiWrite","asciiToBytes","base64Write","ucs2Write","units","utf16leToBytes","firstByte","codePoint","bytesPerSequence","secondByte","thirdByte","fourthByte","tempCodePoint","codePoints","MAX_ARGUMENTS_LENGTH","decodeCodePointsArray","kMaxLength","TYPED_ARRAY_SUPPORT","foo","typedArraySupport","poolSize","allocUnsafeSlow","_isBuffer","list","swap16","swap32","swap64","toLocaleString","thisStart","thisEnd","thisCopy","targetCopy","isFinite","_arr","hexSliceLookupTable","checkOffset","ext","checkInt","wrtBigUInt64LE","checkIntBI","wrtBigUInt64BE","checkIEEE754","writeFloat","noAssert","writeDouble","newBuf","readUintLE","readUIntLE","readUintBE","readUIntBE","readUint8","readUint16LE","readUInt16LE","readUint16BE","readUint32LE","readUInt32LE","readUint32BE","readBigUInt64LE","defineBigIntMethod","validateNumber","boundsError","readBigUInt64BE","readIntLE","readIntBE","readInt8","readInt16LE","readInt16BE","readInt32LE","readInt32BE","readBigInt64LE","readBigInt64BE","readFloatLE","readFloatBE","readDoubleLE","readDoubleBE","writeUintLE","writeUIntLE","writeUintBE","writeUint8","writeUint16LE","writeUInt16LE","writeUint16BE","writeUint32LE","writeUInt32LE","writeUint32BE","writeBigUInt64LE","writeBigUInt64BE","writeIntLE","writeIntBE","writeInt8","writeInt16LE","writeInt16BE","writeInt32LE","writeInt32BE","writeBigInt64LE","writeBigInt64BE","writeFloatLE","writeFloatBE","writeDoubleLE","writeDoubleBE","targetStart","copyWithin","sym","addNumericalSeparator","range","ERR_OUT_OF_RANGE","checkBounds","ERR_BUFFER_OUT_OF_BOUNDS","received","isInteger","INVALID_BASE64_RE","leadSurrogate","base64clean","alphabet","table","i16","BufferBigIntNotDefined","GetIntrinsic","callBind","$indexOf","allowMissing","intrinsic","$apply","$call","$reflectApply","$gOPD","$defineProperty","$max","originalFunction","applyBind","StringDecoder","hashMode","_finalOrDigest","__final","_decoder","_encoding","inputEnc","outputEnc","outData","_toString","_transform","_flush","fin","elliptic","ECDH","aliases","secp256k1","secp224r1","prime256v1","prime192v1","ed25519","secp384r1","secp521r1","curveType","ec","formatReturnValue","bn","p256","secp256r1","secp192r1","p384","p521","generateKeys","format","genKeyPair","getPublicKey","computeSecret","inenc","keyFromPublic","getPublic","getPrivate","getX","getPrivateKey","setPublicKey","_importPublic","setPrivateKey","_priv","_importPrivate","MD5","RIPEMD160","sha","Hash","alg","Legacy","md5","ZEROS","Hmac","blocksize","_alg","ipad","_ipad","opad","_opad","rng","pseudoRandomBytes","prng","algos","algoKeys","hashes","getHashes","pbkdf2","pbkdf2Sync","dh","DiffieHellmanGroup","createDiffieHellmanGroup","getDiffieHellman","createDiffieHellman","DiffieHellman","createECDH","publicEncrypt","privateEncrypt","publicDecrypt","privateDecrypt","rf","randomFillSync","createCredentials","CryptoJS","BlockCipher","lib","C_algo","SUB_MIX_0","SUB_MIX_1","SUB_MIX_2","SUB_MIX_3","INV_SUB_MIX_0","INV_SUB_MIX_1","INV_SUB_MIX_2","INV_SUB_MIX_3","extend","_doReset","_keyPriorReset","sigBytes","invKsRow","_doCryptBlock","_createHelper","ORIG_P","ORIG_S","BLOWFISH_CTX","pbox","sbox","BlowFish_Encrypt","temp","Xl","Xr","Blowfish","keysize","Row","Col","keyIndex","Data1","Data2","BlowFishInit","BlowFish_Decrypt","ivSize","C_lib","WordArray","BufferedBlockAlgorithm","C_enc","Base64","EvpKDF","C_mode","BlockCipherMode","Pkcs7","CipherParams","OpenSSLFormatter","SerializableCipher","OpenSSLKdf","PasswordBasedCipher","Utf8","cfg","createEncryptor","_ENC_XFORM_MODE","createDecryptor","_DEC_XFORM_MODE","xformMode","_xformMode","reset","dataUpdate","_append","_process","finalize","_doFinalize","selectCipherStrategy","cipher","ciphertext","Encryptor","Decryptor","_iv","xorBlock","_prevBlock","processBlock","thisBlock","blockSizeBytes","nPaddingBytes","paddingWord","paddingWords","modeCreator","_minBufferSize","__creator","_doProcessBlock","finalProcessedBlocks","_data","cipherParams","mixIn","formatter","OpenSSL","salt","parse","openSSLStr","ciphertextWords","encryptor","cipherCfg","_parse","kdf","execute","random","compute","derivedParams","globalThis","cryptoSecureRandomInt","subtype","overrides","$super","propertyName","encoder","Hex","wordArray","thisWords","thatWords","thisSigBytes","thatSigBytes","clamp","thatByte","nBytes","hexChars","bite","hexStr","hexStrLength","Latin1","latin1Chars","latin1Str","latin1StrLength","decodeURIComponent","escape","utf8Str","unescape","encodeURIComponent","_nDataBytes","doFlush","processedWords","dataWords","dataSigBytes","nBlocksReady","nWordsReady","nBytesReady","Hasher","messageUpdate","_createHmacHelper","HMAC","_map","base64Chars","triplet","paddingChar","base64Str","base64StrLength","reverseMap","_reverseMap","paddingIndex","bitsCombined","parseLoop","Base64url","urlSafe","_safe_map","swapEndian","Utf16","Utf16BE","utf16Chars","utf16Str","utf16StrLength","Utf16LE","iterations","derivedKey","derivedKeyWords","_hasher","hasherBlockSize","hasherBlockSizeBytes","oKey","_oKey","iKey","_iKey","oKeyWords","iKeyWords","innerHash","superInit","subInit","typedArray","typedArrayByteLength","offset_i","M_offset_i","M_offset_0","M_offset_1","M_offset_2","M_offset_3","M_offset_4","M_offset_5","M_offset_6","M_offset_7","M_offset_8","M_offset_9","M_offset_10","M_offset_11","M_offset_12","M_offset_13","M_offset_14","M_offset_15","FF","GG","HH","II","nBitsTotal","nBitsLeft","nBitsTotalH","nBitsTotalL","H_i","HmacMD5","generateKeystreamAndEncrypt","keystream","CTRGladman","incWord","_counter","incCounter","_keystream","AnsiX923","lastBytePos","Ansix923","Iso10126","Iso97971","ZeroPadding","NoPadding","SHA256","PBKDF2","hmac","blockIndex","blockIndexWords","blockWords","blockWordsLength","intermediate","intermediateWords","C_","RabbitLegacy","_X","_C","_b","nextState","IV","IV_0","IV_1","i0","i2","i1","i3","gx","gh","gl","Rabbit","RC4","keySigBytes","_S","keyByteIndex","keyByte","_j","generateKeystreamWord","keystreamWord","RC4Drop","drop","_zl","_zr","_sl","_sr","_hl","_hr","al","cl","dl","el","ar","br","cr","dr","er","hl","hr","zl","zr","sl","sr","f1","f2","f3","f4","f5","rotl","HmacRIPEMD160","SHA1","HmacSHA1","SHA224","HmacSHA224","isPrime","sqrtN","factor","getFractionalBits","nPrime","gamma0x","gamma0","gamma1x","gamma1","maj","sigma0","HmacSHA256","X64Word","x64","Word","RHO_OFFSETS","PI_INDEXES","ROUND_CONSTANTS","newY","LFSR","roundConstantMsw","roundConstantLsw","bitPosition","SHA3","outputLength","_state","nBlockSizeLanes","M2i","M2i1","lane","high","low","tMsw","tLsw","Tx","Tx4","Tx1","Tx1Msw","Tx1Lsw","laneIndex","laneMsw","laneLsw","rhoOffset","TPiLane","T0","state0","TLane","Tx1Lane","Tx2Lane","roundConstant","blockSizeBits","outputLengthBytes","outputLengthLanes","hashWords","HmacSHA3","C_x64","X64WordArray","SHA512","SHA384","HmacSHA384","X64Word_create","H0","H1","H2","H3","H4","H5","H6","H7","H0h","H0l","H1h","H1l","H2h","H2l","H3h","H3l","H4h","H4l","H5h","H5l","H6h","H6l","H7h","H7l","ah","bh","eh","fh","fl","hh","Wil","Wih","Wi","gamma0xh","gamma0xl","gamma0h","gamma0l","gamma1xh","gamma1xl","gamma1h","gamma1l","Wi7","Wi7h","Wi7l","Wi16","Wi16h","Wi16l","t1l","chh","chl","majh","majl","sigma0h","sigma0l","sigma1h","sigma1l","Ki","Kih","Kil","t1h","t2l","toX32","HmacSHA512","PC1","PC2","BIT_SHIFTS","SBOX_P","SBOX_MASK","keyBits","keyBitPos","subKeys","_subKeys","nSubKey","subKey","bitShift","invSubKeys","_invSubKeys","_lBlock","_rBlock","exchangeLR","exchangeRL","lBlock","rBlock","TripleDES","key3","_des1","_des2","_des3","X32WordArray","x64Words","x64WordsLength","x32Words","x64Word","wordsLength","hasPropertyDescriptors","$SyntaxError","$TypeError","gopd","property","nonEnumerable","nonWritable","nonConfigurable","loose","desc","hasSymbols","toStr","defineDataProperty","supportsDescriptors","predicates","utils","CBCState","_cbcInit","_cbcState","inp","inOff","outOff","superProto","bufferOff","_updateDecrypt","_updateEncrypt","_buffer","_flushBuffer","inputOff","outputOff","_finalEncrypt","_finalDecrypt","_pad","_unpad","DESState","_desState","deriveKeys","shiftTable","kL","kR","pc1","r28shl","pc2","ip","_encrypt","lStart","rStart","keyL","keyR","expand","substitute","rip","EDEState","k1","k2","k3","_edeState","inL","inR","outL","outR","pc2table","sTable","permuteTable","padSplit","group","generatePrime","DH","ENCODINGS","gen","generator","genc","millerRabin","TWENTYFOUR","ELEVEN","TEN","THREE","SEVEN","_pub","primeCache","malleable","setGenerator","__prime","_primeLen","_primeCode","hex","rem","simpleSieve","fermatTest","checkPrime","__gen","_gen","secret","getPrime","front","getGenerator","findPrime","ONE","TWO","FIVE","FOUR","_getPrimes","n2","version","eddsa","getNAF","getJSF","BaseCurve","conf","zero","pointFromJSON","gRed","_wnafT1","_wnafT2","_wnafT3","_wnafT4","_bitLength","adjustCount","redN","_maxwellTrick","BasePoint","precomputed","point","validate","_fixedNafMul","doubles","_getDoubles","naf","nafW","repr","jpoint","mixedAdd","points","toP","_wnafMul","nafPoints","_getNAFPoints","dblp","_wnafMulAdd","defW","coeffs","jacobianResult","wndWidth","comb","toJ","jsf","decodePoint","pointFromX","encodeCompressed","getY","precompute","power","beta","_getBeta","_hasDoubles","dbl","EdwardsCurve","twisted","mOneA","dd","oneC","Point","zOne","_mulA","_mulC","rhs","lhs","y2","pointFromY","isInfinity","fromJSON","_extDbl","nx","ny","nt","nz","_projDbl","_extAdd","_projAdd","mulAdd","jmulAdd","zi","eqXToP","xc","short","edwards","MontCurve","i4","a24","diffAdd","jumlAdd","ShortCurve","tinv","zeroA","threeA","endo","_getEndomorphism","_endoWnafT1","_endoWnafT2","isRed","inf","JPoint","lambda","betas","_getEndoRoots","lambdas","basis","vec","_getEndoBasis","ntinv","prevR","aprxSqrt","y1","len1","_endoSplit","v1","v2","p1","p2","q1","q2","ax","_endoWnafMulAdd","npoints","ncoeffs","pre","endoMul","obj2point","ys1","dyinv","_precompute","negate","zinv","zinv2","ay","pz2","z2","h2","h3","jx","jy","jz","jz4","jyd","jx2","jyd2","jyd4","dny","_zeroDbl","_threeDbl","_dbl","xx","yy","yyyy","yyyy8","c8","gamma","alpha","beta4","beta8","ggamma8","jy2","jxd4","jyd8","trpl","zz","mm","ee","yyu4","kbase","z3","pz3","zs","PresetCurve","defineCurve","sha256","sha384","sha512","HmacDRBG","KeyPair","Signature","nh","keyPair","fromPrivate","fromPublic","drbg","pers","persEnc","entropy","hmacStrength","entropyEnc","nonce","ns2","_truncateToN","truncOnly","bkey","ns1","iter","kp","kpX","recoveryParam","canonical","sinv","recoverPubKey","isYOdd","isSecondKey","rInv","getKeyRecoveryParam","Qprime","privEnc","pubEnc","derive","_importDER","Position","place","getLength","initial","octetLen","rmPadding","constructLength","octets","LN2","slen","backHalf","parseBytes","EDDSA","pointClass","encodingLength","keyFromSecret","hashInt","messagePrefix","Rencoded","encodePoint","s_","pubBytes","makeSignature","SG","intFromLE","fromSecret","lastIx","normed","xIsOdd","encodeInt","decodeInt","isPoint","cachedProperty","_secret","_pubBytes","privBytes","getSecret","_R","_Rencoded","_Sencoded","Sencoded","toBytes","toHex","minAssert","minUtils","zero2","m8","d1","d2","m14","m24","computer","ReflectOwnKeys","ReflectApply","getOwnPropertyNames","NumberIsNaN","EventEmitter","emitter","errorListener","removeListener","resolver","eventTargetAgnosticAddListener","handler","on","addErrorHandlerIfEventEmitter","_events","_eventsCount","_maxListeners","defaultMaxListeners","checkListener","listener","_getMaxListeners","_addListener","prepend","events","existing","warning","newListener","emit","onceWrapper","fired","wrapFn","_onceWrap","_listeners","unwrap","evlistener","unwrapListeners","arrayClone","listenerCount","addEventListener","wrapListener","removeEventListener","setMaxListeners","getMaxListeners","doError","context","addListener","prependListener","prependOnceListener","originalListener","spliceOne","removeAllListeners","rawListeners","eventNames","used","keyStart","ivStart","isCallable","thisArg","forEachArray","forEachString","forEachObject","bound","boundLength","boundArgs","Empty","implementation","SyntaxError","$Function","getEvalledConstructor","expressionSyntax","throwTypeError","ThrowTypeError","calleeThrows","gOPDthrows","hasProto","getProto","needsEval","TypedArray","INTRINSICS","AggregateError","Atomics","DataView","decodeURI","encodeURI","eval","EvalError","FinalizationRegistry","parseFloat","URIError","WeakRef","WeakSet","errorProto","doEval","LEGACY_ALIASES","hasOwn","$concat","$spliceApply","$replace","$strSlice","$exec","rePropName","reEscapeChar","getBaseIntrinsic","alias","intrinsicName","quote","subString","stringToPath","intrinsicBaseName","intrinsicRealName","skipFurtherCaching","hasArrayLengthDefineBug","$Object","origSymbol","hasSymbolSham","symObj","syms","HashBase","_block","_blockSize","_blockOffset","_finalized","prefix","throwIfNotStringOrBuffer","_digest","common","ripemd","sha1","sha224","ripemd160","BlockHash","pending","pendingTotal","outSize","padLength","_delta8","_delta32","join32","inner","outer","rotl32","sum32","sum32_3","sum32_4","Kh","Ah","Bh","Ch","Dh","Eh","rh","sh","toHex32","split32","shaCommon","sum32_5","ft_1","sha1_K","ch32","maj32","s0_256","s1_256","g0_256","g1_256","sha256_K","T1","T2","rotr64_hi","rotr64_lo","shr64_hi","shr64_lo","sum64","sum64_hi","sum64_lo","sum64_4_hi","sum64_4_lo","sum64_5_hi","sum64_5_lo","sha512_K","ch64_hi","xh","xl","yh","yl","zh","ch64_lo","maj64_hi","maj64_lo","s0_512_hi","s0_512_lo","s1_512_lo","g0_512_hi","g0_512_lo","g1_512_lo","_prepareBlock","c0_hi","c0_lo","c1_hi","c1_lo","c2_hi","c2_lo","c3_hi","c3_lo","c4_hi","c4_lo","T1_hi","T1_lo","T2_hi","T2_lo","rotr32","p32","isSurrogatePair","htonl","zero8","predResist","minEntropy","_reseed","reseedInterval","nonceEnc","seed","_hmac","kmac","reseed","addEnc","http","https","validateParams","protocol","isLE","mLen","eLen","eMax","eBias","nBits","rt","hasToStringTag","$toString","callBound","isStandardArguments","isLegacyArguments","callee","supportsStandardArguments","badArrayLike","isCallableMarker","fnToStr","reflectApply","constructorRegex","isES6ClassFn","fnStr","tryFunctionObject","isIE68","isDDA","strClass","GeneratorFunction","isFnRegex","generatorFunc","getGeneratorFunc","getPolyfill","shim","polyfill","whichTypedArray","ARRAY16","_c","_d","fnF","fnG","fnH","fnI","Dir","util_1","Dirent_1","iteratorInfo","getParentPath","validateCallback","promisify","closeBase","readBase","recursive","default","build","closeBaseAsync","closeSync","readBaseAsync","asyncIterator","dirEnt","Dirent","constants_1","encoding_1","S_IFMT","S_IFDIR","S_IFREG","S_IFBLK","S_IFCHR","S_IFLNK","S_IFIFO","S_IFSOCK","dirent","getNode","strToEncoding","getName","_checkModeProperty","isDirectory","isBlockDevice","isCharacterDevice","isSymbolicLink","Stats","bigint","stats","getStatNumber","getSize","birthtime","atimeMs","mtimeMs","ctimeMs","birthtimeMs","atimeNs","mtimeNs","ctimeNs","birthtimeNs","O_RDONLY","O_WRONLY","O_RDWR","O_CREAT","O_EXCL","O_NOCTTY","O_TRUNC","O_APPEND","O_DIRECTORY","O_NOATIME","O_NOFOLLOW","O_SYNC","O_SYMLINK","O_DIRECT","O_NONBLOCK","S_IRWXU","S_IRUSR","S_IWUSR","S_IXUSR","S_IRWXG","S_IRGRP","S_IWGRP","S_IXGRP","S_IRWXO","S_IROTH","S_IWOTH","S_IXOTH","F_OK","R_OK","W_OK","X_OK","UV_FS_SYMLINK_DIR","UV_FS_SYMLINK_JUNCTION","UV_FS_COPYFILE_EXCL","UV_FS_COPYFILE_FICLONE","UV_FS_COPYFILE_FICLONE_FORCE","COPYFILE_EXCL","COPYFILE_FICLONE","COPYFILE_FICLONE_FORCE","ENCODING_UTF8","assertEncoding","buffer_1","memfs","vol","Volume","createFsFromVolume","Stats_1","volume_1","fsSynchronousApiList_1","fsCallbackApiList_1","fsSynchronousApiList","fsCallbackApiList","StatWatcher","FSWatcher","WriteStream","ReadStream","promises","_toUnixTimestamp","toUnixTimestamp","__vol","json","fromNestedJSON","semantic","bufferFrom","bufferAllocUnsafe","bufferV0P12Ponyfill","kCode","messages","makeNodeError","stackStartFunction","fmt","isWriting","servers","newNotAllowedError","newTypeMismatchError","newNotFoundError","assertCanWrite","assertName","separator","syncHandleAllowed","lastSlashIndex","nameRegex","klass","DOMException","File","Link","SEP","process_1","events_1","getuid","getgid","perm","_uid","_gid","_atime","_mtime","_ctime","_perm","_nlink","getString","getBuffer","setString","touch","setBuffer","setModeProperty","setIsFile","setIsDirectory","setIsSymlink","isSymlink","makeSymlink","steps","actualLen","_steps","syncSteps","setNode","createChild","setChild","deleteChild","getChild","walk","stop","seekTo","FileHandle","appendFile","datasync","readableWebStream","pull","async","readv","buffers","utimes","writev","FsPromises","cp","opendir","statfs","lutimes","access","copyFile","mkdtemp","realpath","rm","watch","FLAGS","ERRSTR","PATH_STR","FD","MODE_INT","CB","UID","GID","LEN","ATIME","MTIME","PREFIX","BUFFER","OFFSET","LENGTH","POSITION","rs","wx","getWriteFileOptions","writeFileDefaults","getRealpathOptsAndCb","getRealpathOptions","getStatOptsAndCb","getStatOptions","getAppendFileOptsAndCb","getAppendFileOpts","getOpendirOptsAndCb","getOpendirOptions","getReaddirOptsAndCb","getReaddirOptions","getReadFileOptions","getRmOptsAndCb","getRmdirOptions","getDefaultOptsAndCb","getDefaultOpts","optsDefaults","getMkdirOptions","getOptions","optsGenerator","optsAndCbGenerator","mkdirDefaults","ERRSTR_OPTS","tipeof","defaults","getOpts","rmdirDefaults","getRmOpts","withFileTypes","bufferSize","appendFileDefaults","statDefaults","realpathDefaults","unixify","getWriteSyncArgs","getWriteArgs","bufToUint8","isWin","modeToNumber","_modeToNumber","nullCheck","pathToFilename","hostname","platform","pathname","third","codePointAt","getPathFromURLPosix","pathString","createError","errorCode","path2","pathFormatted","ENOENT","EBADF","EINVAL","EPERM","EPROTO","EEXIST","ENOTDIR","EISDIR","EACCES","ENOTEMPTY","EMFILE","ENOSYS","ERR_FS_EISDIR","formatError","genRndStr6","flagsToNumber","flagsNum","isFd","validateFd","dataToBuffer","bufferToEncoding","buffer_2","queueMicrotask_1","tipa","tipb","tipc","tipd","isSeparator","char","filepath","stripTrailing","removeTrailingSeparator","normalizePath","toTreeSync","tree_dump_1","tab","subtree","readdirSync","printTree","entry","readlinkSync","createProcess","maybeReturnProcess","queueMicrotask","_setImmediate","ref","unref","filenameToSteps","pathToSteps","dataToStr","pathModule","node_1","setImmediate_1","setTimeoutUnref_1","stream_1","FileHandle_1","FsPromises_1","print_1","constants_2","options_1","Dir_1","resolveCrossPlatform","sep","posix","_resolve","fullPathSansSlash","validateUid","validateGid","notImplemented","promisesApi","inodes","releasedInos","fds","releasedFds","maxFiles","openFiles","statWatchers","cpSync","lutimesSync","statfsSync","openAsBlob","createLink","_ReadStream","FsReadStream","_WriteStream","FsWriteStream","deleteLink","newInoNumber","newFdNumber","releasedFd","deleteNode","getLink","getLinkOrThrow","getResolvedLink","filenameOrSteps","getResolvedLinkOrThrow","resolveSymlinks","getLinkAsDirOrThrow","getLinkParent","getLinkParentAsDirOrThrow","getFileByFd","getFileByFdOrThrow","_toJSON","asBuffer","dirPath","isRelative","links","mkdirpBase","writeFileSync","nestedJSON","flatJSON","flatten","pathPrefix","contentOrNode","joinedPath","flattenJSON","toTree","mountSync","openLink","realLink","openFile","modeNum","dirLink","openBase","openSync","fileName","closeFile","openFileOrGetById","readvBase","readvSync","readFileBase","userOwnsFd","writeBase","writeSync","asStr","writevBase","nodeBuf","writevSync","writeFileBase","isUserFd","written","linkBase","filename1","filename2","steps1","link1","steps2","dir2","copyFileBase","existsSync","copyFileSync","srcFilename","destFilename","linkSync","existingPath","newPath","existingPathFilename","newPathFilename","unlinkBase","unlinkSync","symlinkBase","targetFilename","pathFilename","pathSteps","symlinkSync","realpathBase","realpathSync","lstatBase","throwIfNoEntry","lstatSync","statBase","statSync","fstatBase","fstatSync","fstat","renameBase","oldPathFilename","newPathSteps","newPathDirLink","oldLinkParent","renameSync","oldPath","existsBase","accessBase","accessSync","appendFileSync","readdirBase","recurseOptions","childList","fullPath","readlinkBase","fsyncBase","fsyncSync","fdatasyncBase","fdatasyncSync","fdatasync","ftruncateBase","ftruncateSync","truncateBase","truncateSync","futimesBase","futimesSync","futimes","utimesBase","utimesSync","mkdirBase","mkdirSync","mkdtempBase","mkdtempSync","rmdirBase","rmdirSync","rmBase","force","rmSync","fchmodBase","fchmodSync","chmodBase","chmodSync","lchmodBase","lchmodSync","fchownBase","fchownSync","chownBase","chownSync","lchownBase","lchownSync","watchFile","persistent","watcher","unwatchFile","createReadStream","createWriteStream","givenOptions","opendirBase","opendirSync","emitStop","onInterval","hasChanged","loop","timeoutRef","pool","_vol","highWaterMark","Readable","autoClose","destroy","closeOnOpen","setDefaultEncoding","_read","destroyed","_readableState","thisPool","toRead","_destroy","err2","closed","_writev","_writableState","destroySoon","_filename","_filenameEncoded","_recursive","_listenerRemovers","_onParentChild","_getName","_emit","_persist","_timer","_link","watchLinkNodeChanged","onNodeChange","removers","watchLinkChildrenChanged","onLinkChildAdd","onLinkChildDelete","removeLinkNodeListeners","curLink","childLink","clear","brorand","MillerRabin","_randbelow","min_bytes","_randrange","rone","n1","rn1","getDivisor","hasMap","mapSizeDescriptor","mapSize","mapForEach","hasSet","setSizeDescriptor","setSize","setForEach","weakMapHas","weakSetHas","weakRefDeref","deref","booleanValueOf","functionToString","$match","$slice","$toUpperCase","$toLowerCase","$test","$join","$arrSlice","$floor","bigIntValueOf","gOPS","symToString","hasShammedSymbols","isEnumerable","gPO","addNumericSeparator","sepRegex","int","intStr","dec","utilInspect","inspectCustom","inspectSymbol","wrapQuotes","defaultStyle","quoteChar","quoteStyle","inspect_","maxStringLength","indent","numericSeparator","inspectString","bigIntStr","maxDepth","baseIndent","getIndent","noIndent","newOpts","nameOf","arrObjKeys","symString","markBoxed","HTMLElement","getAttribute","attrs","attributes","childNodes","xs","singleLineValues","indentedJoin","cause","mapParts","collectionOf","setParts","isWeakMap","weakCollectionOf","isWeakSet","isWeakRef","isNumber","isBigInt","isBoolean","isString","ys","isPlainObject","protoTag","stringTag","trailer","lowbyte","lineJoiner","symMap","keysShim","isArgs","hasDontEnumBug","hasProtoEnumBug","dontEnums","equalsConstructorPrototype","excludedKeys","$applicationCache","$console","$external","$frame","$frameElement","$frames","$innerHeight","$innerWidth","$onmozfullscreenchange","$onmozfullscreenerror","$outerHeight","$outerWidth","$pageXOffset","$pageYOffset","$parent","$scrollLeft","$scrollTop","$scrollX","$scrollY","$self","$webkitIndexedDB","$webkitStorageInfo","$window","hasAutomationEqualityBug","theKeys","skipProto","skipConstructor","equalsConstructorPrototypeIfNotBuggy","origKeys","originalKeys","keysWorksWithArguments","objectKeys","toObject","$push","$propIsEnumerable","originalGetSymbols","source1","getSymbols","nextKey","propValue","letters","lacksProperEnumerationOrder","preventExtensions","thrower","assignHasPendingExceptions","certificate","RSAPrivateKey","RSAPublicKey","PublicKey","AlgorithmIdentifier","bitstr","null_","PrivateKeyInfo","octstr","PrivateKey","EncryptedPrivateKeyInfo","EncryptedPrivateKey","DSAPrivateKey","DSAparam","ECPrivateKey","ECParameters","namedCurve","asn","Time","utcTime","utctime","generalTime","gentime","AttributeTypeValue","SubjectPublicKeyInfo","RelativeDistinguishedName","setof","RDNSequence","seqof","Name","rdnSequence","Validity","Extension","bool","TBSCertificate","X509Certificate","findProc","startRegex","fullRegex","evp","okey","decrypted","cipherText","cipherKey","match2","aesid","fixProc","compat","passphrase","ndata","stripped","tbsCertificate","subjectPublicKeyInfo","subjectPublicKey","kde","kdeparams","iters","keylen","assertPath","normalizeStringPosix","lastSegmentLength","dots","trailingSeparator","joined","fromStart","fromEnd","fromLen","toStart","toLen","lastCommonSep","fromCode","_makeLong","hasRoot","matchedSlash","extIdx","firstNonSlashEnd","extname","startDot","startPart","preDotState","pathObject","_format","delimiter","win32","ZERO_BUF","checkParameters","defaultEncoding","subtle","toBrowser","checks","getNextTick","browserPbkdf2","importKey","deriveBits","promise","resolvePromise","browser","prom","checkNative","MAX_ALLOC","sizes","rmd160","saltLen","getDigest","ipad1","ipad2","DK","block1","destPos","hLen","cachedSetTimeout","cachedClearTimeout","defaultSetTimout","defaultClearTimeout","runTimeout","fun","currentQueue","draining","queueIndex","cleanUpNextTick","drainQueue","marker","runClearTimeout","Item","title","umask","PromiseThrottle","requestsPerSecond","promiseImplementation","lastStartTime","queued","opt","weight","signal","dequeue","addAll","addedPromises","inc","elapsed","_execute","candidate","aborted","i2ops","mgf","withPublic","zBuffer","iHash","maskedSeed","maskedDb","dif","oaep","ps","pkcs1","publicKey","paddedMsg","hLen2","dblen","nonZero","MAX_BYTES","generated","oldBrowser","safeBuffer","randombytes","kBufferMaxLength","kMaxUint32","assertOffset","actualFill","ourBuf","uint","Duplex","allowHalfOpen","readable","onend","ended","onEndNT","PassThrough","ReadableState","debug","EElistenerCount","Stream","OurUint8Array","debugUtil","debuglog","createReadableStreamAsyncIterator","BufferList","destroyImpl","getHighWaterMark","ERR_STREAM_PUSH_AFTER_EOF","ERR_METHOD_NOT_IMPLEMENTED","ERR_STREAM_UNSHIFT_AFTER_END_EVENT","errorOrDestroy","kProxyEvents","isDuplex","objectMode","readableObjectMode","pipes","pipesCount","flowing","endEmitted","reading","needReadable","emittedReadable","readableListening","resumeScheduled","emitClose","autoDestroy","awaitDrain","readingMore","readableAddChunk","addToFront","skipChunkCheck","emitReadable","emitReadable_","onEofChunk","chunkInvalid","_uint8ArrayToBuffer","addChunk","maybeReadMore","_undestroy","undestroy","isPaused","setEncoding","MAX_HWM","howMuchToRead","computeNewHighWaterMark","flow","maybeReadMore_","updateReadableListening","nReadingNextTick","resume_","fromList","consume","endReadable","endReadableNT","wState","finished","nOrig","doRead","pipe","pipeOpts","endFn","stdout","unpipe","onunpipe","unpipeInfo","hasUnpiped","onclose","onfinish","ondrain","ondata","cleanedUp","needDrain","pipeOnDrain","event","dests","ev","_fromList","ERR_MULTIPLE_CALLBACK","ERR_TRANSFORM_ALREADY_TRANSFORMING","ERR_TRANSFORM_WITH_LENGTH_0","afterTransform","ts","_transformState","transforming","writecb","writechunk","needTransform","writeencoding","prefinish","CorkedRequest","corkReq","pendingcb","onCorkedFinish","corkedRequestsFree","WritableState","realHasInstance","internalUtil","deprecate","ERR_STREAM_CANNOT_PIPE","ERR_STREAM_DESTROYED","ERR_STREAM_NULL_VALUES","ERR_STREAM_WRITE_AFTER_END","ERR_UNKNOWN_ENCODING","nop","writableObjectMode","finalCalled","ending","noDecode","decodeStrings","writing","corked","bufferProcessing","onwrite","writelen","onwriteStateUpdate","finishMaybe","errorEmitted","onwriteError","needFinish","bufferedRequest","clearBuffer","afterWrite","lastBufferedRequest","prefinished","bufferedRequestCount","doWrite","onwriteDrain","holder","allBuffers","isBuf","callFinal","need","rState","hasInstance","writeAfterEnd","validChunk","newChunk","decodeChunk","writeOrBuffer","cork","uncork","endWritable","_Object$setPrototypeO","_defineProperty","kLastResolve","kLastReject","kError","kEnded","kLastPromise","kHandlePromise","kStream","createIterResult","readAndResolve","onReadable","AsyncIteratorPrototype","ReadableStreamAsyncIteratorPrototype","lastPromise","wrapForNext","_this2","_Object$create","enumerableOnly","symbols","hasStrings","_getString","_getBuffer","emitErrorAndCloseNT","emitErrorNT","emitCloseNT","readableDestroyed","writableDestroyed","ERR_STREAM_PREMATURE_CLOSE","eos","called","onlegacyfinish","writableEnded","readableEnded","onrequest","req","setHeader","isRequest","popCallback","destroys","destroyer","ERR_INVALID_OPT_VALUE","duplexKey","hwm","highWaterMarkFrom","pipeline","_e","fn1","fn2","fn3","fn4","fn5","tl","tr","copyProps","SafeBuffer","safer","Safer","kStringMaxLength","MAX_LENGTH","MAX_STRING_LENGTH","finalSize","_finalSize","accum","assigned","remainder","lowBits","highBits","Algorithm","Sha","_w","rotl30","ft","Sha1","rotl5","Sha256","Sha224","_f","_g","_h","sigma1","Sha384","_ah","_bh","_ch","_dh","_eh","_fh","_gh","_hh","_al","_bl","_cl","_dl","_el","_fl","_gl","writeInt64BE","Sha512","Gamma0","Gamma0l","Gamma1","Gamma1l","getCarry","t2h","$WeakMap","$Map","$weakMapGet","$weakMapSet","$weakMapHas","$mapGet","$mapSet","$mapHas","listGetNode","$wm","$m","$o","channel","objects","listGet","listHas","listSet","EE","_isStdio","didOnEnd","cleanup","ClientRequest","statusCodes","defaultProtocol","host","port","IncomingMessage","Agent","defaultMaxSockets","globalAgent","STATUS_CODES","METHODS","getXHR","XDomainRequest","checkTypeSupport","writableStream","WritableStream","abortController","AbortController","arraybuffer","msstream","mozchunkedarraybuffer","capability","rStates","readyStates","preferBinary","_opts","_body","_headers","auth","useFetch","decideMode","_fetchTimer","_socketTimeout","_socketTimer","_onFinish","lowerName","unsafeHeaders","getHeader","removeHeader","_destroyed","headersObj","Blob","headersList","keyName","_fetchAbortController","requestTimeout","withCredentials","_fetchResponse","_resetTimers","_connect","_xhr","ontimeout","_response","onreadystatechange","readyState","LOADING","DONE","_onXHRProgress","onprogress","statusValid","flushHeaders","setNoDelay","setSocketKeepAlive","UNSENT","OPENED","HEADERS_RECEIVED","resetTimers","rawHeaders","trailers","rawTrailers","statusMessage","_resumeFetch","pipeTo","reader","getReader","_pos","responseURL","getAllResponseHeaders","matches","_charset","mimeType","charsetMatch","newData","MSStreamReader","readAsArrayBuffer","nenc","retried","_normalizeEncoding","normalizeEncoding","text","utf16Text","utf16End","fillLast","utf8FillLast","base64Text","base64End","simpleWrite","simpleEnd","lastNeed","lastTotal","lastChar","utf8CheckByte","byte","utf8CheckExtraBytes","utf8CheckIncomplete","tslib_1","__exportStar","printBinary","isLast","global","punycode","maxInt","tMax","skew","damp","regexPunycode","regexNonASCII","regexSeparators","baseMinusTMin","stringFromCharCode","mapDomain","ucs2decode","extra","ucs2encode","digitToBasic","digit","adapt","numPoints","firstTime","basic","oldi","baseMinusT","bias","handledCPCount","basicLength","currentValue","handledCPCountPlusOne","qMinusT","percentTwenties","Format","formatters","RFC1738","RFC3986","formats","allowDots","allowPrototypes","allowSparse","arrayLimit","charset","charsetSentinel","comma","ignoreQueryPrefix","interpretNumericEntities","parameterLimit","parseArrays","plainObjects","strictNullHandling","$0","numberStr","parseArrayValue","givenKey","valuesParsed","segment","chain","leaf","cleanRoot","parseObject","normalizeParseOptions","tempObj","cleanStr","skipIndex","bracketEqualsPos","maybeMap","encodedVal","combine","parseValues","merge","getSideChannel","arrayPrefixGenerators","brackets","indices","pushToArray","valueOrArray","toISO","toISOString","defaultFormat","addQueryPrefix","encodeValuesOnly","serializeDate","skipNulls","sentinel","generateArrayPrefix","commaRoundTrip","sideChannel","tmpSc","findFlag","objKeys","adjustedPrefix","keyPrefix","valueSideChannel","normalizeStringifyOptions","arrayFormat","hexTable","arrayToObject","refs","compacted","compactQueue","strWithoutPlus","defaultEncoder","mapped","mergeTarget","targetItem","Url","slashes","query","protocolPattern","portPattern","simplePathPattern","unwise","autoEscape","nonHostChars","hostEndingChars","hostnamePartPattern","hostnamePartStart","unsafeProtocol","javascript","hostlessProtocol","slashedProtocol","ftp","gopher","querystring","urlParse","parseQueryString","slashesDenoteHost","queryIndex","splitter","uSplit","rest","simplePath","lowerProto","atSign","hostEnd","hec","parseHost","ipv6Hostname","hostparts","newpart","validParts","notHost","toASCII","ae","esc","qm","resolveObject","rel","tkeys","tk","tkey","rkeys","rk","relPath","isSourceAbs","isRelAbs","mustEndAbs","removeAllDots","srcPath","psychotic","authInHost","hasTrailingSlash","localStorage","trace","isArgumentsObject","isGeneratorFunction","BigIntSupported","SymbolSupported","ObjectToString","numberValue","stringValue","booleanValue","bigIntValue","symbolValue","checkBoxedPrimitive","prototypeValueOf","isMapToString","isSetToString","isWeakMapToString","isWeakSetToString","isArrayBufferToString","isArrayBuffer","working","isDataViewToString","isDataView","isUint8Array","isUint8ClampedArray","isUint16Array","isUint32Array","isInt8Array","isInt16Array","isInt32Array","isBigInt64Array","isBigUint64Array","SharedArrayBufferCopy","isSharedArrayBufferToString","isSharedArrayBuffer","isAsyncFunction","isMapIterator","isSetIterator","isGeneratorObject","isWebAssemblyCompiledModule","descriptors","formatRegExp","isNull","noDeprecation","throwDeprecation","traceDeprecation","debugs","debugEnvRegex","NODE_DEBUG","debugEnv","stylize","stylizeNoColor","colors","_extend","isUndefined","stylizeWithColor","formatValue","styleType","style","styles","simple","formatPrimitive","visibleKeys","arrayToHash","braces","toUTCString","formatProperty","formatArray","reduceToSingleString","pid","isNullOrUndefined","isPrimitive","months","origin","kCustomPromisifiedSymbol","callbackifyOnRejected","newReason","promiseResolve","promiseReject","callbackify","callbackified","maybeCb","rej","availableTypedArrays","gOPD","typedArrays","trySlices","tryTypedArrays","child_process","web","possibleNames","extendStatics","__extends","__","__assign","__rest","__decorate","decorators","decorate","__param","paramIndex","decorator","__esDecorate","descriptorIn","contextIn","initializers","extraInitializers","accept","addInitializer","__runInitializers","useValue","__propKey","__setFunctionName","description","__metadata","metadataKey","metadataValue","metadata","__awaiter","_arguments","fulfilled","rejected","__generator","sent","trys","verb","__createBinding","__esModule","__values","__read","__spread","__spreadArrays","il","jl","__spreadArray","pack","__await","__asyncGenerator","fulfill","settle","__asyncDelegator","__asyncValues","__makeTemplateObject","cooked","__setModuleDefault","__importStar","__importDefault","__classPrivateFieldGet","__classPrivateFieldSet","__classPrivateFieldIn","__addDisposableResource","dispose","asyncDispose","_SuppressedError","SuppressedError","suppressed","__disposeResources","rec","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","loaded","__webpack_modules__","definition","nmd","isDefined","isInitialized","isUninitialized","isInt","isUpperCase","isLowerCase","assertHex","assertTrue","isHex","isBase32","assertBase58","isBase58","assertBase64","isBase64","btoa","assertFalse","assertNull","assertNotNull","assertDefined","assertUndefined","assertInitialized","assertUninitialized","assertEquals","assertNotEquals","assertInt","assertNumber","assertBoolean","assertString","assertArray","assertFunction","assertObject","inheritsFrom","invoke","getPowerSet","got","getPowerSetOfLength","powerSet","powerSetOfLength","getIndices","toUniqueArray","copyArray","toLowerCaseArray","listify","arrOrElem","arrayContains","compareByReference","strContains","arraysEqual","arr1","objectsEqual","map1","map2","deleteUndefinedKeys","getCombinations","combinationSize","indexCombinations","combinations","indexCombinationsIdx","indexCombination","combination","indexCombinationIdx","getDownloadableA","createElement","createObjectURL","download","innerHTML","copyProperties","deleteProperties","hasWhitespace","isWhitespace","isNewline","countNonWhitespaceCharacters","getWhitespaceTokens","getLines","getInternalStyleSheet","styleSheets","styleSheet","getInternalStyleSheetText","internalCss","internalStyleSheet","cssRules","cssText","buildHtmlDocument","metas","meta","setAttribute","outerHTML","dependencyPaths","dependencyPath","append","html","newWindow","onLoad","onLoadCalled","onLoadOnce","opener","imgToDataUrl","img","quality","canvas","height","naturalHeight","naturalWidth","getContext","drawImage","toDataURL","isImageAccessible","returned","Image","onResponse","isZipFile","isJsonFile","isTxtFile","getImages","funcs","loadFunc","initPolyfills","varArgs","nextSource","searchString","getUUID","isBrowser","isWorker","isBrowserMain","isJsDom","isDeno","Deno","deno","isFirefox","userAgent","getIEVersion","msie","edge","getParameterByName","getRandomInt","getRandomInts","ints","getUniqueRandomInts","randomInt","shuffle","safeSet","getFn","setFn","errMsg","curVal","reconciledVal","reconcile","resolveDefined","resolveTrue","resolveMax","kvLine","newline","ignoreUndefined","stringifyBigInts","printStackTrace","waitFor","durationMs","killProcess","normalizeUri","bi","getEnumKeyByValue","enumType","enumValue","executeWithTimeout","timeoutMs","timeoutId","MoneroError","getCode","ThreadPool","maxConcurrency","taskQueue","drainListeners","submit","awaitAll","level","LOG_LEVEL","setLogLevel","WASM_MODULE","set_log_level","WORKER","invokeWorker","getLogLevel","getWasmMemoryUsed","getWasmModule","FULL_LOADED","initWasmModule","setRejectUnauthorizedFn","fnId","REJECT_UNAUTHORIZED_FNS","setWorkerDistPath","workerDistPath","prefixWindowsPath","WORKER_DIST_PATH_DEFAULT","WORKER_DIST_PATH","setWorkerLoader","loader","WORKER_LOADER","getWorker","Worker","WORKER_OBJECTS","onmessage","callbackFn","addWorkerCallback","objectId","callbackId","callbackArgs","removeWorkerCallback","removeWorkerObject","terminateWorker","terminate","randomObject","postMessage","deserializeError","serializeError","serializedErr","queueTask","MUTEX","wasmModule","curPath","targetPath","kindOf","kindOfTest","typeOfTest","isBlob","isFileList","isURLSearchParams","isReadableStream","isResponse","isHeaders","allOwnKeys","findKey","_global","isContextDefined","isHTMLForm","reduceDescriptors","reducer","reducedDescriptors","ALPHA","DIGIT","ALPHABET","ALPHA_DIGIT","isAsyncFn","setImmediateSupported","postMessageSupported","token","asap","isFormData","FormData","isStream","caseless","assignValue","targetKey","stripBOM","superConstructor","toFlatObject","sourceObj","destObj","propFilter","merged","lastIndex","forEachEntry","pair","matchAll","regExp","hasOwnProp","freezeMethods","toObjectSet","arrayOrString","toCamelCase","toFiniteNumber","defaultValue","generateString","isSpecCompliantForm","toJSONObject","reducedValue","isThenable","AxiosError","lineNumber","columnNumber","customProps","axiosError","isVisitable","removeBrackets","renderKey","formData","metaTokens","indexes","option","visitor","defaultVisitor","useBlob","convertValue","isFlatArray","exposedHelpers","charMap","AxiosURLSearchParams","_pairs","buildURL","serializeFn","serialize","serializedParams","hashmarkIndex","handlers","synchronous","runWhen","eject","silentJSONParsing","forcedJSONParsing","clarifyTimeoutError","classes","URLSearchParams","protocols","hasBrowserEnv","hasStandardBrowserEnv","product","hasStandardBrowserWebWorkerEnv","WorkerGlobalScope","buildPath","isNumericKey","parsePropPath","transitional","adapter","transformRequest","contentType","getContentType","hasJSONContentType","isObjectPayload","setContentType","helpers","isNode","toURLEncodedForm","formSerializer","_FormData","rawValue","parser","stringifySafely","transformResponse","JSONRequested","strictJSONParsing","ERR_BAD_RESPONSE","xsrfCookieName","xsrfHeaderName","maxContentLength","maxBodyLength","validateStatus","ignoreDuplicateOf","$internals","normalizeHeader","normalizeValue","matchHeaderValue","isHeaderNameFilter","AxiosHeaders","valueOrRewrite","rewrite","_value","_header","_rewrite","lHeader","setHeaders","parseHeaders","tokens","tokensRE","parseTokens","matcher","deleted","deleteHeader","normalized","formatHeader","targets","asStrings","computed","accessor","accessors","defineAccessor","accessorName","buildAccessors","headerValue","transformData","isCancel","__CANCEL__","CanceledError","ERR_CANCELED","ERR_BAD_REQUEST","progressEventReducer","isDownloadStream","freq","bytesNotified","_speedometer","samplesCount","timestamps","firstSampleTS","chunkLength","startedAt","bytesCount","passed","lastArgs","threshold","lengthComputable","progressBytes","rate","progress","estimated","progressEventDecorator","throttled","asyncDecorator","urlParsingNode","originURL","resolveURL","requestURL","expires","domain","secure","cookie","toGMTString","buildFullPath","baseURL","requestedURL","relativeURL","combineURLs","headersToObject","mergeConfig","config1","config2","getMergedValue","mergeDeepProperties","valueFromConfig2","defaultToConfig2","mergeDirectKeys","mergeMap","paramsSerializer","timeoutMessage","withXSRFToken","onUploadProgress","onDownloadProgress","decompress","beforeRedirect","transport","httpAgent","httpsAgent","cancelToken","socketPath","responseEncoding","configValue","newConfig","isURLSameOrigin","xsrfValue","cookies","_config","resolveConfig","requestData","requestHeaders","onCanceled","uploadThrottled","downloadThrottled","flushUpload","flushDownload","unsubscribe","onloadend","responseHeaders","onabort","ECONNABORTED","ERR_NETWORK","timeoutErrorMessage","ETIMEDOUT","upload","cancel","subscribe","parseProtocol","signals","streamChunk","trackStream","onProgress","onFinish","readBytes","loadedBytes","isFetchSupported","Request","isReadableStreamSupported","encodeText","TextEncoder","supportsRequestStream","duplexAccessed","hasContentType","duplex","supportsResponseStream","resolvers","ERR_NOT_SUPPORT","fetchOptions","composedSignal","stopTimeout","requestContentLength","getContentLength","getBodyLength","resolveBodyLength","contentTypeHeader","_request","isStreamResponse","responseContentLength","responseData","knownAdapters","renderReason","isResolvedHandle","adapters","nameOrAdapter","rejectedReasons","reasons","throwIfCancellationRequested","throwIfRequested","dispatchRequest","validators","deprecatedWarnings","validator","formatMessage","ERR_DEPRECATED","assertOptions","schema","allowUnknown","ERR_BAD_OPTION_VALUE","ERR_BAD_OPTION","Axios","instanceConfig","interceptors","configOrUrl","dummy","boolean","function","contextHeaders","requestInterceptorChain","synchronousRequestInterceptors","interceptor","responseInterceptorChain","onFulfilled","onRejected","getUri","generateHTTPMethod","isForm","CancelToken","executor","onfulfilled","HttpStatusCode","Continue","SwitchingProtocols","Processing","EarlyHints","Ok","Created","Accepted","NonAuthoritativeInformation","NoContent","ResetContent","PartialContent","MultiStatus","AlreadyReported","ImUsed","MultipleChoices","MovedPermanently","Found","SeeOther","NotModified","UseProxy","Unused","TemporaryRedirect","PermanentRedirect","BadRequest","Unauthorized","PaymentRequired","Forbidden","NotFound","MethodNotAllowed","NotAcceptable","ProxyAuthenticationRequired","RequestTimeout","Conflict","Gone","LengthRequired","PreconditionFailed","PayloadTooLarge","UriTooLong","UnsupportedMediaType","RangeNotSatisfiable","ExpectationFailed","ImATeapot","MisdirectedRequest","UnprocessableEntity","Locked","FailedDependency","TooEarly","UpgradeRequired","PreconditionRequired","TooManyRequests","RequestHeaderFieldsTooLarge","UnavailableForLegalReasons","InternalServerError","NotImplemented","BadGateway","ServiceUnavailable","GatewayTimeout","HttpVersionNotSupported","VariantAlsoNegotiates","InsufficientStorage","LoopDetected","NotExtended","NetworkAuthenticationRequired","axios","createInstance","defaultConfig","VERSION","toFormData","Cancel","spread","isAxiosError","formToJSON","getAdapter","proxyToWorker","DEFAULT_REQUEST","TASK_QUEUES","PROMISE_THROTTLES","MAX_REQUESTS_PER_SECOND","DEFAULT_TIMEOUT","MAX_TIMEOUT","requestPromise","requestAxios","getHttpAgent","HTTP_AGENT","keepAlive","family","getHttpsAgent","HTTPS_AGENT","isBinary","axiosDigestAuthRequest","normalizedResponse","authHeader","authHeaderMap","replaceAll","cnonce","randNum","characters","generateCnonce","HA1","realm","HA2","qop","digestAuthHeader","opaque","finalResponse","MoneroBan","ban","toJson","getHost","setHost","getIp","setIp","getIsBanned","isBanned","setIsBanned","seconds","setSeconds","MoneroBlockHeader","difficulty","cumulativeDifficulty","reward","getDifficulty","getCumulativeDifficulty","getReward","getHash","setHash","getHeight","setHeight","getTimestamp","setTimestamp","getWeight","setWeight","getLongTermWeight","longTermWeight","setLongTermWeight","getDepth","setDepth","setDifficulty","setCumulativeDifficulty","getMajorVersion","majorVersion","setMajorVersion","getMinorVersion","minorVersion","setMinorVersion","getNonce","setNonce","getMinerTxHash","minerTxHash","setMinerTxHash","getNumTxs","numTxs","setNumTxs","getOrphanStatus","orphanStatus","setOrphanStatus","getPrevHash","prevHash","setPrevHash","setReward","getPowHash","powHash","setPowHash","MoneroKeyImage","hexOrKeyImage","setHex","setSignature","getHex","getSignature","keyImage","MoneroOutput","amount","getTx","tx","setTx","getKeyImage","setKeyImage","getAmount","setAmount","getIndex","setIndex","getRingOutputIndices","ringOutputIndices","setRingOutputIndices","getStealthPublicKey","stealthPublicKey","setStealthPublicKey","MoneroTx","fee","unlockTime","inputs","outputs","setBlock","getVersion","setVersion","getIsMinerTx","isMinerTx","setIsMinerTx","miner","getPaymentId","paymentId","setPaymentId","getFee","setFee","getRingSize","ringSize","setRingSize","getRelay","relay","setRelay","getIsRelayed","isRelayed","setIsRelayed","getIsConfirmed","isConfirmed","setIsConfirmed","getInTxPool","inTxPool","setInTxPool","getNumConfirmations","numConfirmations","setNumConfirmations","getUnlockTime","setUnlockTime","getLastRelayedTimestamp","lastRelayedTimestamp","setLastRelayedTimestamp","getReceivedTimestamp","receivedTimestamp","setReceivedTimestamp","getIsDoubleSpendSeen","isDoubleSpendSeen","setIsDoubleSpendSeen","setKey","getFullHex","fullHex","setFullHex","getPrunedHex","prunedHex","setPrunedHex","getPrunableHex","prunableHex","setPrunableHex","getPrunableHash","prunableHash","setPrunableHash","getInputs","setInputs","getOutputs","setOutputs","getOutputIndices","outputIndices","setOutputIndices","getMetadata","setMetadata","getExtra","setExtra","getRctSignatures","rctSignatures","setRctSignatures","getRctSigPrunable","rctSigPrunable","setRctSigPrunable","getIsKeptByBlock","isKeptByBlock","setIsKeptByBlock","getIsFailed","isFailed","setIsFailed","getLastFailedHeight","lastFailedHeight","setLastFailedHeight","getLastFailedHash","lastFailedHash","setLastFailedHash","getMaxUsedBlockHeight","maxUsedBlockHeight","setMaxUsedBlockHeight","getMaxUsedBlockHash","maxUsedBlockHash","setMaxUsedBlockHash","getSignatures","signatures","setSignatures","getTxs","merger","mergee","DEFAULT_PAYMENT_ID","MoneroTransfer","transfer","getIsOutgoing","isIncoming","getIsIncoming","getAccountIndex","accountIndex","setAccountIndex","MoneroIncomingTransfer","getSubaddressIndex","subaddressIndex","setSubaddressIndex","getAddress","setAddress","getNumSuggestedConfirmations","numSuggestedConfirmations","setNumSuggestedConfirmations","MoneroDestination","destinationOrAddress","MoneroOutgoingTransfer","destinations","getSubaddressIndices","subaddressIndices","setSubaddressIndices","getAddresses","addresses","setAddresses","getDestinations","setDestinations","destination","inexact","quadrant","EXP_LIMIT","MAX_DIGITS","NUMERALS","LN10","DEFAULTS","precision","rounding","modulo","toExpNeg","toExpPos","minE","maxE","external","decimalError","invalidArgument","precisionLimitExceeded","cryptoUnavailable","mathfloor","mathpow","isOctal","isDecimal","BASE","LOG_BASE","LN10_PRECISION","PI_PRECISION","digitsToString","indexOfLastWord","getZeroString","checkInt32","checkRoundingDigits","repeating","di","rd","convertBase","baseIn","baseOut","arrL","strL","absoluteValue","finalise","clampedTo","comparedTo","xdL","ydL","xd","yd","cosine","pr","sd","tinyPow","taylorSeries","cos2x","minus","plus","toLessThanHalfPi","cubeRoot","cbrt","rep","t3plusx","toExponential","divide","decimalPlaces","dp","dividedBy","dividedToIntegerBy","divToInt","greaterThan","greaterThanOrEqualTo","hyperbolicCosine","cosh","cosh2_x","d8","hyperbolicSine","sinh","sinh2_x","d5","d16","d20","hyperbolicTangent","tanh","inverseCosine","acos","halfPi","getPi","asin","inverseHyperbolicCosine","acosh","ln","inverseHyperbolicSine","asinh","inverseHyperbolicTangent","atanh","wpr","xsd","inverseSine","atan","inverseTangent","px","isNegative","isPositive","isPos","lessThan","lessThanOrEqualTo","logarithm","isBase10","denominator","naturalLogarithm","getLn10","xe","xLTy","getBase10Exponent","naturalExponential","exp","negated","getPrecision","sine","sin2_x","squareRoot","tangent","tan","rL","toBinary","toStringBinary","toDecimalPlaces","toDP","finiteToString","toFixed","toFraction","maxD","d0","n0","toHexadecimal","toNearest","toOctal","toPower","yn","intPow","toPrecision","toSignificantDigits","toSD","truncated","trunc","multiplyInteger","aL","bL","subtract","logBase","more","prod","prodL","qd","remL","rem0","xL","yd0","yL","yz","isTruncated","digits","roundUp","xdi","isExp","nonFiniteToString","maxOrMin","ltgt","sum","c0","numerator","parseDecimal","parseOther","divisor","isFloat","Decimal","isHyperbolic","pi","atan2","useDefaults","hypot","isDecimalInstance","log2","log10","ROUND_UP","ROUND_DOWN","ROUND_CEIL","ROUND_FLOOR","ROUND_HALF_UP","ROUND_HALF_DOWN","ROUND_HALF_EVEN","ROUND_HALF_CEIL","ROUND_HALF_FLOOR","EUCLID","MoneroIntegratedAddress","integratedAddress","getStandardAddress","standardAddress","setStandardAddress","getIntegratedAddress","setIntegratedAddress","MoneroNetworkType","networkType","isValid","networkTypeStr","MAINNET","TESTNET","STAGENET","MoneroUtils","setProxyToWorker","PROXY_TO_WORKER","validateMnemonic","mnemonic","NUM_MNEMONIC_WORDS","isValidPrivateViewKey","privateViewKey","validatePrivateViewKey","isValidPublicViewKey","publicViewKey","validatePublicViewKey","isValidPrivateSpendKey","privateSpendKey","validatePrivateSpendKey","isValidPublicSpendKey","publicSpendKey","validatePublicSpendKey","isHex64","integratedAddressJson","get_integrated_address_util","isValidAddress","validateAddress","validate_address","isValidPaymentId","validatePaymentId","getLastTxPubKey","txExtra","lastPubKeyIdx","paymentIdsEqual","paymentId1","paymentId2","maxLength","mergeTx","txs","aTx","jsonToBinary","binMemInfoStr","malloc_binary_from_json","binMemInfo","binaryToJson","uint8arr","ret_string","binary_to_json","binaryBlocksToJson","json_str","binary_blocks_to_json","blockStr","xmrToAtomicUnits","amountXmr","AU_PER_XMR","atomicUnitsToXmr","amountAtomicUnits","au1","au2","multiply","isTimestamp","RING_SIZE","MoneroTxSet","txSet","MoneroTxWallet","setTxSet","setTxs","getMultisigTxHex","multisigTxHex","setMultisigTxHex","getUnsignedTxHex","unsignedTxHex","setUnsignedTxHex","getSignedTxHex","signedTxHex","setSignedTxHex","getTxSet","incomingTransfers","outgoingTransfer","MoneroOutputWallet","inputSum","outputSum","changeAmount","getIncomingTransfers","incomingTransfer","getOutgoingTransfer","getInputSum","getOutputSum","getChangeAmount","setIsIncoming","isOutgoing","setIsOutgoing","getIncomingAmount","incomingAmt","getOutgoingAmount","getTransfers","transferQuery","transfers","meetsCriteria","filterTransfers","setOutgoingTransfer","toRemoves","setIncomingTransfers","getInputsWallet","outputQuery","setInputsWallet","getOutputsWallet","setOutputsWallet","filterOutputs","getNote","note","setNote","getIsLocked","isLocked","setIsLocked","setInputSum","setOutputSum","getChangeAddress","changeAddress","setChangeAddress","setChangeAmount","getNumDummyOutputs","numDummyOutputs","setNumDummyOutputs","getExtraHex","extraHex","setExtraHex","mergeIncomingTransfer","oneLine","aTransfer","getIsSpent","isSpent","setIsSpent","getIsFrozen","isFrozen","setIsFrozen","MoneroOutputQuery","minAmount","maxAmount","txQuery","MoneroTxQuery","setOutputQuery","getMinAmount","getMaxAmount","setMinAmount","setMaxAmount","getTxQuery","setTxQuery","queryParent","MoneroTransferQuery","setTransferQuery","getHasDestinations","hasDestinations","setHasDestinations","subaddressIdx","inputQuery","getTransferQuery","getInputQuery","getOutputQuery","setHashes","getHasPaymentId","hasPaymentId","setHasPaymentId","getPaymentIds","paymentIds","setPaymentIds","getMinHeight","minHeight","setMinHeight","getMaxHeight","maxHeight","setMaxHeight","getIncludeOutputs","includeOutputs","setIncludeOutputs","setInputQuery","queryChildren","txHeight","matchFound","lastFailedId","maxUsedBlockId","DeserializationType","MoneroBlock","txType","minerTx","deserializeTx","getMinerTx","setMinerTx","getTxHashes","txHashes","setTxHashes","TX","TX_WALLET","TX_QUERY","MoneroRpcError","rpcDescription","rpcCode","rpcMethod","rpcParams","getRpcMethod","getRpcParams","MoneroRpcConnection","uriOrConnection","DEFAULT_CONFIG","setCredentials","zmqUri","proxyUri","checkConnectionMutex","sendRequestMutex","isOnline","isAuthenticated","getUsername","getPassword","getZmqUri","setZmqUri","getProxyUri","setProxyUri","getRejectUnauthorized","getProxyToWorker","setPriority","getPriority","getTimeout","put","checkConnection","queueCheckConnection","isOnlineBefore","isAuthenticatedBefore","startTime","fakeDisconnected","heights","sendBinaryRequest","responseTime","isConnected","getIsOnline","getIsAuthenticated","getResponseTime","sendJsonRequest","queueSendRequest","jsonrpc","validateHttpResponse","validateRpcResponse","sendPathRequest","paramsBin","getConfig","setFakeDisconnected","errorMsg","MoneroDaemonConfig","server","setServer","getServer","getCmd","setCmd","getPollInterval","pollInterval","setPollInterval","MoneroDaemonListener","onBlockHeader","lastHeader","getLastBlockHeader","TaskLooper","_isStarted","_isLooping","getTask","periodInMs","targetFixedPeriod","setPeriodInMs","_runLoop","isStarted","_timeout","_periodInMs","MoneroAltChain","altChain","getBlockHashes","blockHashes","setBlockHashes","setLength","getMainChainParentBlockHash","mainChainParentBlockHash","setMainChainParentBlockHash","MoneroBlockTemplate","template","expectedReward","getExpectedReward","getBlockTemplateBlob","blockTemplateBlob","setBlockTemplateBlob","getBlockHashingBlob","blockHashingBlob","setBlockHashingBlob","setExpectedReward","prevId","getReservedOffset","reservedOffset","setReservedOffset","getSeedHeight","setSeedHeight","seedHeight","getSeedHash","seedHash","setSeedHash","getNextSeedHash","nextSeedHash","setNextSeedHash","MoneroConnectionSpan","span","getConnectionId","connectionId","setConnectionId","getNumBlocks","numBlocks","setNumBlocks","getRemoteAddress","remoteAddress","setRemoteAddress","getRate","setRate","getSpeed","speed","setSpeed","getStartHeight","startHeight","setStartHeight","MoneroDaemon","getListeners","isTrusted","getBlockHash","getBlockTemplate","walletAddress","reserveSize","getBlockHeaderByHash","blockHash","getBlockHeaderByHeight","getBlockHeadersByRange","endHeight","getBlockByHash","getBlocksByHash","prune","getBlockByHeight","getBlocksByHeight","getBlocksByRange","getBlocksByRangeChunked","maxChunkSize","txHash","getTxHex","getTxHexes","getMinerTxSum","getFeeEstimate","graceBlocks","submitTxHex","txHex","doNotRelay","relayTxByHash","relayTxsByHash","getTxPool","getTxPoolHashes","getTxPoolStats","flushTxPool","getKeyImageSpentStatus","getKeyImageSpentStatuses","keyImages","getOutputHistogram","amounts","minCount","isUnlocked","recentCutoff","getInfo","getSyncInfo","getHardForkInfo","getAltChains","getAltBlockHashes","getDownloadLimit","setDownloadLimit","resetDownloadLimit","getUploadLimit","setUploadLimit","resetUploadLimit","getPeers","getKnownPeers","setOutgoingPeerLimit","setIncomingPeerLimit","getPeerBans","setPeerBan","setPeerBans","bans","startMining","numThreads","isBackground","ignoreBattery","stopMining","getMiningStatus","submitBlock","blockBlob","submitBlocks","pruneBlockchain","blockBlobs","checkForUpdate","downloadUpdate","waitForNextBlockHeader","MoneroDaemonInfo","credits","getNumAltBlocks","numAltBlocks","setNumAltBlocks","getBlockSizeLimit","blockSizeLimit","setBlockSizeLimit","getBlockSizeMedian","blockSizeMedian","setBlockSizeMedian","getBlockWeightLimit","blockWeightLimit","setBlockWeightLimit","getBlockWeightMedian","blockWeightMedian","setBlockWeightMedian","getBootstrapDaemonAddress","bootstrapDaemonAddress","setBootstrapDaemonAddress","getFreeSpace","freeSpace","setFreeSpace","getNumOfflinePeers","numOfflinePeers","setNumOfflinePeers","getNumOnlinePeers","numOnlinePeers","setNumOnlinePeers","getHeightWithoutBootstrap","heightWithoutBootstrap","setHeightWithoutBootstrap","getNetworkType","setNetworkType","getIsOffline","isOffline","setIsOffline","getNumIncomingConnections","numIncomingConnections","setNumIncomingConnections","getNumOutgoingConnections","numOutgoingConnections","setNumOutgoingConnections","getNumRpcConnections","numRpcConnections","setNumRpcConnections","getStartTimestamp","startTimestamp","setStartTimestamp","getAdjustedTimestamp","adjustedTimestamp","setAdjustedTimestamp","getTarget","setTarget","getTargetHeight","targetHeight","setTargetHeight","getTopBlockHash","topBlockHash","setTopBlockHash","getNumTxsPool","numTxsPool","setNumTxsPool","getWasBootstrapEverUsed","wasBootstrapEverUsed","setWasBootstrapEverUsed","getDatabaseSize","databaseSize","setDatabaseSize","getUpdateAvailable","updateAvailable","setUpdateAvailable","getCredits","setCredits","getIsBusySyncing","isBusySyncing","setIsBusySyncing","getIsSynchronized","isSynchronized","setIsSynchronized","getIsRestricted","isRestricted","setIsRestricted","MoneroPeer","peer","rpcCreditsPerHash","getId","setId","getPort","setPort","setIsOnline","getLastSeenTimestamp","lastSeenTimestamp","setLastSeenTimestamp","getPruningSeed","pruningSeed","setPruningSeed","getRpcPort","rpcPort","setRpcPort","getRpcCreditsPerHash","setRpcCreditsPerHash","getAvgDownload","avgDownload","setAvgDownload","getAvgUpload","avgUpload","setAvgUpload","getCurrentDownload","currentDownload","setCurrentDownload","getCurrentUpload","currentUpload","setCurrentUpload","getLiveTime","liveTime","setLiveTime","getIsLocalIp","isLocalIp","setIsLocalIp","getIsLocalHost","isLocalHost","setIsLocalHost","getNumReceives","numReceives","setNumReceives","getNumSends","numSends","setNumSends","getReceiveIdleTime","receiveIdleTime","setReceiveIdleTime","getSendIdleTime","sendIdleTime","setSendIdleTime","getState","setState","getNumSupportFlags","numSupportFlags","setNumSupportFlags","getType","setType","MoneroDaemonSyncInfo","peers","spans","setPeers","getSpans","setSpans","getNextNeededPruningSeed","nextNeededPruningSeed","setNextNeededPruningSeed","getOverview","overview","setOverview","MoneroDaemonUpdateCheckResult","getIsUpdateAvailable","isUpdateAvailable","setIsUpdateAvailable","getAutoUri","autoUri","setAutoUri","getUserUri","userUri","setUserUri","MoneroDaemonUpdateDownloadResult","getDownloadPath","downloadPath","setDownloadPath","MoneroFeeEstimate","feeEstimate","fees","quantizationMask","getFees","setFees","getQuantizationMask","setQuantizationMask","MoneroHardForkInfo","getEarliestHeight","earliestHeight","setEarliestHeight","getIsEnabled","isEnabled","setIsEnabled","getThreshold","setThreshold","getNumVotes","numVotes","setNumVotes","getWindow","setWindow","getVoting","voting","setVoting","MoneroMinerTxSum","txSum","emissionSum","feeSum","getEmissionSum","getFeeSum","setEmissionSum","setFeeSum","MoneroMiningStatus","getIsActive","isActive","setIsActive","getNumThreads","setNumThreads","getIsBackground","setIsBackground","MoneroOutputHistogramEntry","getNumInstances","numInstances","setNumInstances","getNumUnlockedInstances","numUnlockedInstances","setNumUnlockedInstances","getNumRecentInstances","numRecentInstances","setNumRecentInstances","MoneroPruneResult","getIsPruned","isPruned","setIsPruned","MoneroSubmitTxResult","getIsGood","isGood","setIsGood","getIsFeeTooLow","isFeeTooLow","setIsFeeTooLow","getIsMixinTooLow","isMixinTooLow","setIsMixinTooLow","getHasInvalidInput","hasInvalidInput","setHasInvalidInput","getHasInvalidOutput","hasInvalidOutput","setHasInvalidOutput","getHasTooFewOutputs","hasTooFewOutputs","setHasTooFewOutputs","getIsOverspend","isOverspend","setIsOverspend","getReason","setReason","getIsTooBig","isTooBig","setIsTooBig","getSanityCheckFailed","sanityCheckFailed","setSanityCheckFailed","getIsTxExtraTooBig","isTxExtraTooBig","setIsTxExtraTooBig","getIsNonzeroUnlockTime","isNonzeroUnlockTime","setIsNonzeroUnlockTime","MoneroTxPoolStats","feeTotal","histo","getNumNotRelayed","numNotRelayed","setNumNotRelayed","getNumFailing","numFailing","setNumFailing","getNumDoubleSpends","numDoubleSpends","setNumDoubleSpends","getNum10m","num10m","setNum10m","getFeeTotal","setFeeTotal","getBytesMax","bytesMax","setBytesMax","getBytesMed","bytesMed","setBytesMed","getBytesMin","bytesMin","setBytesMin","getBytesTotal","bytesTotal","setBytesTotal","getHisto","setHisto","getHisto98pc","histo98pc","setHisto98pc","getOldestTimestamp","oldestTimestamp","setOldestTimestamp","MoneroVersion","isRelease","getNumber","setNumber","getIsRelease","setIsRelease","MoneroDaemonRpc","proxyDaemon","cachedHeaders","getProcess","stopProcess","listenersCopy","refreshListening","getRpcConnection","checkResponseStatus","release","untrusted","wallet_address","reserve_size","convertRpcBlockTemplate","convertRpcBlockHeader","block_header","start_height","end_height","rpcHeader","convertRpcBlock","rpcBlocks","blockIdx","txIdx","tx_hashes","convertRpcTx","lastHeight","getMaxBlocks","txs_hashes","decode_as_json","hexes","emission_amount","fee_amount","grace_blocks","quantization_mask","tx_as_hex","do_not_relay","convertRpcSubmitTxResult","txids","transactions","rpcTx","convertRpcTxPoolStats","pool_stats","key_images","spent_status","min_count","max_count","unlocked","recent_cutoff","histogram","rpcEntry","convertRpcOutputHistogramEntry","getOutputDistribution","cumulative","convertRpcInfo","convertRpcSyncInfo","convertRpcHardForkInfo","chains","rpcChain","convertRpcAltChain","blks_hashes","getBandwidthLimits","setBandwidthLimits","connections","rpcConnection","convertRpcConnection","gray_list","rpcPeer","convertRpcPeer","white_list","out_peers","in_peers","rpcBan","rpcBans","convertToRpcBan","miner_address","threads_count","do_background_mining","ignore_battery","convertRpcMiningStatus","pruned","pruning_seed","command","convertRpcUpdateCheckResult","convertRpcUpdateDownloadResult","pollListener","DaemonPoller","setIsPolling","limit_down","limit_up","downLimit","upLimit","maxReqSize","MAX_REQ_SIZE","reqSize","getBlockHeaderByHeightCached","cachedHeader","NUM_HEADERS_PER_REQ","connectToDaemonRpc","uriOrConfig","normalizeConfig","startMonerodProcess","MoneroDaemonRpcProxy","connect","childProcess","uriLineContainsIdx","uriLineContains","unformattedLine","sslIdx","sslEnabled","userPassIdx","userPass","daemon","isResolved","DEFAULT_POLL_PERIOD","prefixedHexToBI","rpcBlock","blob","rpcMinerTx","miner_tx","rpcVin","convertRpcOutput","rpcOutput","txnFee","DEFAULT_ID","as_json","tx_json","k_image","key_offsets","pubKey","tagged_key","rpcTemplate","rpcInfo","rpcSyncInfo","syncInfo","rpcConnections","rpcSpans","rpcSpan","convertRpcConnectionSpan","rpcHardForkInfo","rpcConnectionSpan","rpcResult","rpcStats","rpcStatus","active","is_background_mining_enabled","daemonId","wrappedListeners","wrappedListener","DaemonWorkerListener","listenerId","getListener","versionJson","blockHeadersJson","blockHeaderJson","blocksJson","blockJson","getTxPoolBacklog","entryJson","altChains","altChainJson","peerJson","banJson","bansJson","looper","poll","isPolling","announceBlockHeader","headerJson","MoneroTxConfig","belowAmount","getBelowAmount","addDestination","setDestination","getSubtractFeeFrom","subtractFeeFrom","setSubtractFeeFrom","destinationIndices","getCanSplit","canSplit","setCanSplit","getRecipientName","recipientName","setRecipientName","setBelowAmount","getSweepEachSubaddress","sweepEachSubaddress","setSweepEachSubaddress","MoneroWalletConfig","connectionManager","setPath","setPassword","networkTypeOrStr","getConnectionManager","setConnectionManager","getSeed","setSeed","getSeedOffset","seedOffset","setSeedOffset","getIsMultisig","isMultisig","setIsMultisig","getPrimaryAddress","primaryAddress","setPrimaryAddress","getPrivateViewKey","setPrivateViewKey","getPrivateSpendKey","setPrivateSpendKey","getRestoreHeight","restoreHeight","setRestoreHeight","getLanguage","language","setLanguage","getSaveCurrent","saveCurrent","setSaveCurrent","getFs","setFs","getKeysData","keysData","setKeysData","getCacheData","cacheData","setCacheData","getAccountLookahead","accountLookahead","setAccountLookahead","getSubaddressLookahead","subaddressLookahead","setSubaddressLookahead","MoneroWalletListener","onSyncProgress","percentDone","onNewBlock","onBalancesChanged","newBalance","newUnlockedBalance","onOutputReceived","onOutputSpent","MoneroSubaddress","subaddress","balance","unlockedBalance","getLabel","setLabel","getBalance","setBalance","getUnlockedBalance","setUnlockedBalance","getNumUnspentOutputs","numUnspentOutputs","setNumUnspentOutputs","getIsUsed","isUsed","setIsUsed","getNumBlocksToUnlock","numBlocksToUnlock","setNumBlocksToUnlock","MoneroConnectionManagerListener","onConnectionChanged","connection","MoneroMessageSignatureType","MoneroWallet","_isClosed","isViewOnly","setDaemonConnection","getDaemonConnection","connectionManagerListener","getConnection","isConnectedToDaemon","getSeedLanguage","getPublicViewKey","getPublicSpendKey","accountIdx","getAddressIndex","decodeIntegratedAddress","getDaemonHeight","getHeightByDate","month","listenerOrStartHeight","startSyncing","syncPeriodInMs","stopSyncing","scanTxs","rescanSpent","rescanBlockchain","numBlocksToNextUnlock","numBlocksToLastUnlock","getAccounts","includeSubaddresses","getAccount","createAccount","setAccountLabel","setSubaddressLabel","getSubaddresses","getSubaddress","createSubaddress","queryNormalized","normalizeTransferQuery","getOutgoingTransfers","exportOutputs","importOutputs","outputsHex","exportKeyImages","importKeyImages","getNewKeyImagesFromLastImport","freezeOutput","thawOutput","isOutputFrozen","getDefaultFeePriority","createTx","configNormalized","normalizeCreateTxsConfig","createTxs","sweepOutput","sweepUnlocked","sweepDust","relayTx","txOrMetadata","relayTxs","txsOrMetadatas","describeUnsignedTxSet","describeTxSet","describeMultisigTxSet","signTxs","submitTxs","signMessage","signatureType","SIGN_WITH_SPEND_KEY","verifyMessage","getTxKey","checkTxKey","txKey","getTxProof","checkTxProof","getSpendProof","checkSpendProof","getReserveProofWallet","getReserveProofAccount","checkReserveProof","getTxNote","getTxNotes","setTxNote","setTxNotes","notes","getAddressBookEntries","entryIndices","addAddressBookEntry","editAddressBookEntry","setDescription","deleteAddressBookEntry","entryIdx","tagAccounts","accountIndices","untagAccounts","getAccountTags","setAccountTagLabel","getPaymentUri","parsePaymentUri","backgroundMining","isMultisigImportNeeded","getMultisigInfo","prepareMultisig","makeMultisig","multisigHexes","exchangeMultisigKeys","exportMultisigHex","importMultisigHex","signMultisigTxHex","submitMultisigTxHex","signedMultisigTxHex","changePassword","oldPassword","newPassword","announceSyncProgress","announceNewBlock","announceBalancesChanged","announceOutputReceived","announceOutputSpent","normalizeTxQuery","normalizeOutputQuery","normalizeSweepOutputConfig","normalizeSweepUnlockedConfig","DEFAULT_LANGUAGE","MoneroWalletKeys","createWallet","walletProxy","MoneroWalletKeysProxy","createWalletFromSeed","createWalletFromKeys","createWalletRandom","create_keys_wallet_random","cppAddress","create_keys_wallet_from_seed","create_keys_wallet_from_keys","getSeedLanguages","get_keys_wallet_seed_languages","create_full_wallet","getWalletProxy","assertNotClosed","is_view_only","versionStr","get_version","get_seed","errorStr","get_seed_language","errorKey","get_private_spend_key","get_private_view_key","get_public_view_key","get_public_spend_key","get_address","get_address_index","sanitizeSubaddress","walletId","subaddressJson","MoneroAccount","account","subaddresses","getTag","setTag","setSubaddresses","MoneroAccountTag","accountTag","getAccountIndices","setAccountIndices","MoneroAddressBookEntry","getDescription","MoneroCheck","MoneroCheckTx","receivedAmount","getReceivedAmount","setReceivedAmount","MoneroCheckReserve","totalAmount","unconfirmedSpentAmount","getTotalAmount","getUnconfirmedSpentAmount","setTotalAmount","setUnconfirmedSpentAmount","MoneroKeyImageImportResult","spentAmount","unspentAmount","getSpentAmount","getUnspentAmount","setSpentAmount","setUnspentAmount","MoneroMultisigInfo","multisigInfo","getIsReady","isReady","setIsReady","getNumParticipants","numParticipants","setNumParticipants","MoneroMultisigInitResult","getMultisigHex","multisigHex","setMultisigHex","MoneroMultisigSignResult","getSignedMultisigTxHex","setSignedMultisigTxHex","signedTxMultisigHex","MoneroSyncResult","numBlocksFetched","receivedMoney","setNumBlocksFetched","setReceivedMoney","getNumBlocksFetched","getReceivedMoney","MoneroMessageSignatureResult","getIsOld","isOld","setIsOld","getSignatureType","setSignatureType","MoneroWalletFull","rejectUnauthorizedFnId","wasmListener","WalletWasmListener","wasmListenerHandle","rejectUnauthorizedConfigId","DEFAULT_SYNC_PERIOD_IN_MS","walletExists","openWallet","wallet","openWalletData","MoneroWalletFullProxy","daemonConnection","getDaemonMaxPeerHeight","get_daemon_max_peer_height","isDaemonSynced","is_daemon_synced","isSynced","is_synced","get_network_type","get_restore_height","set_restore_height","moveTo","set_daemon_connection","connectionContainerStr","get_daemon_connection","jsonConnection","is_connected_to_daemon","get_integrated_address","decode_integrated_address","get_height","get_daemon_height","get_height_by_date","allowConcurrentCalls","syncWasm","respJson","syncLooper","backgroundSync","stop_syncing","scan_txs","rescan_spent","rescan_blockchain","balanceStr","get_balance_wallet","get_balance_account","get_balance_subaddress","unlockedBalanceStr","get_unlocked_balance_wallet","get_unlocked_balance_account","get_unlocked_balance_subaddress","accountsStr","get_accounts","accounts","accountJson","sanitizeAccount","accountStr","get_account","create_account","subaddressesJson","get_subaddresses","subaddressStr","create_subaddress","set_subaddress_label","get_txs","blocksJsonStr","deserializeTxs","get_transfers","deserializeTransfers","get_outputs","deserializeOutputs","export_outputs","import_outputs","numImported","export_key_images","keyImagesStr","keyImageJson","import_key_images","keyImageImportResultStr","freeze_output","thaw_output","is_output_frozen","get_default_fee_priority","create_txs","txSetJsonStr","sweep_output","sweep_unlocked","txSetsJson","txSets","txSetJson","sweep_dust","txMetadatas","relay_txs","txHashesJson","describe_tx_set","get_exception_message","sign_txs","submit_txs","sign_message","verify_message","SIGN_WITH_VIEW_KEY","get_tx_key","check_tx_key","respJsonStr","get_tx_proof","check_tx_proof","get_spend_proof","check_spend_proof","get_reserve_proof_wallet","get_reserve_proof_account","check_reserve_proof","get_tx_notes","txNotes","set_tx_notes","get_address_book_entries","add_address_book_entry","edit_address_book_entry","delete_address_book_entry","tag_accounts","accountTags","accountTagJson","get_account_tags","set_account_tag_label","get_payment_uri","parse_payment_uri","get_attribute","set_attribute","is_multisig_import_needed","is_multisig","get_multisig_info","prepare_multisig","make_multisig","exchange_multisig_keys","export_multisig_hex","import_multisig_hex","sign_multisig_tx_hex","submit_multisig_tx_hex","getData","viewOnly","views","cacheBufferLoc","get_cache_file_buffer","setInt8","keysBufferLoc","get_keys_file_buffer","change_wallet_password","daemonUri","daemonUsername","daemonPassword","open_wallet_full","browserMainPath","set_listener","newListenerHandle","newBalanceStr","newUnlockedBalanceStr","amountStr","accountIdxStr","subaddressIdxStr","sanitizeBlock","sanitizeTxWallet","deserializeBlocks","deserializedBlocks","txMap","txsSorted","setBrowserMainPath","walletDir","pathNew","uriOrRpcConnection","rpcConfig","WalletWorkerListener","resultJson","blockJsons","keyImagesJson","DedicatedWorkerGlobalScope","initOneTime","httpRequest","moneroUtilsGetIntegratedAddress","moneroUtilsValidateAddress","moneroUtilsJsonToBinary","moneroUtilsBinaryToJson","moneroUtilsBinaryBlocksToJson","daemonAddListener","blockHeader","daemonListeners","daemonRemoveListener","connectDaemonRpc","daemonGetRpcConnection","daemonIsConnected","daemonGetVersion","daemonIsTrusted","daemonGetHeight","daemonGetBlockHash","daemonGetBlockTemplate","daemonGetLastBlockHeader","daemonGetBlockHeaderByHash","daemonGetBlockHeaderByHeight","daemonGetBlockHeadersByRange","daemonGetBlockByHash","daemonGetBlocksByHash","daemonGetBlockByHeight","daemonGetBlocksByHeight","daemonGetBlocksByRange","daemonGetBlocksByRangeChunked","daemonGetBlockHashes","daemonGetTxs","unconfirmedBlock","seenBlocks","daemonGetTxHexes","daemonGetMinerTxSum","daemonGetFeeEstimate","daemonSubmitTxHex","daemonRelayTxsByHash","daemonGetTxPool","daemonGetTxPoolHashes","daemonGetTxPoolStats","daemonFlushTxPool","daemonGetKeyImageSpentStatuses","daemonGetOutputHistogram","entriesJson","daemonGetInfo","daemonGetSyncInfo","daemonGetHardForkInfo","daemonGetAltChains","altChainsJson","daemonGetAltBlockHashes","daemonGetDownloadLimit","daemonSetDownloadLimit","daemonResetDownloadLimit","daemonGetUploadLimit","daemonSetUploadLimit","daemonResetUploadLimit","daemonGetPeers","peersJson","daemonGetKnownPeers","daemonSetOutgoingPeerLimit","daemonSetIncomingPeerLimit","daemonGetPeerBans","daemonSetPeerBans","daemonStartMining","daemonStopMining","daemonGetMiningStatus","daemonSubmitBlocks","daemonPruneBlockchain","daemonStop","daemonWaitForNextBlockHeader","daemonUriOrConfig","createWalletKeys","configJson","createWalletFull","accountJsons","subaddressJsons","blockJsonQuery","getKeyImages"],"sourceRoot":""} \ No newline at end of file diff --git a/dist/monero_core.js b/dist/monero_core.js deleted file mode 100644 index fe9d419e5..000000000 --- a/dist/monero_core.js +++ /dev/null @@ -1,22 +0,0 @@ - -var monero_javascript = (function() { - var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; - if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; - return ( -function(monero_javascript) { - monero_javascript = monero_javascript || {}; - -var Module=typeof monero_javascript!=="undefined"?monero_javascript:{};var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise(function(resolve,reject){readyPromiseResolve=resolve;readyPromiseReject=reject});if(!Object.getOwnPropertyDescriptor(Module["ready"],"_main")){Object.defineProperty(Module["ready"],"_main",{configurable:true,get:function(){abort("You are getting _main on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_main",{configurable:true,set:function(){abort("You are setting _main on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_malloc")){Object.defineProperty(Module["ready"],"_malloc",{configurable:true,get:function(){abort("You are getting _malloc on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_malloc",{configurable:true,set:function(){abort("You are setting _malloc on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_free")){Object.defineProperty(Module["ready"],"_free",{configurable:true,get:function(){abort("You are getting _free on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_free",{configurable:true,set:function(){abort("You are setting _free on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_stackSave")){Object.defineProperty(Module["ready"],"_stackSave",{configurable:true,get:function(){abort("You are getting _stackSave on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_stackSave",{configurable:true,set:function(){abort("You are setting _stackSave on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_stackRestore")){Object.defineProperty(Module["ready"],"_stackRestore",{configurable:true,get:function(){abort("You are getting _stackRestore on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_stackRestore",{configurable:true,set:function(){abort("You are setting _stackRestore on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_stackAlloc")){Object.defineProperty(Module["ready"],"_stackAlloc",{configurable:true,get:function(){abort("You are getting _stackAlloc on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_stackAlloc",{configurable:true,set:function(){abort("You are setting _stackAlloc on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"___data_end")){Object.defineProperty(Module["ready"],"___data_end",{configurable:true,get:function(){abort("You are getting ___data_end on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"___data_end",{configurable:true,set:function(){abort("You are setting ___data_end on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"___wasm_call_ctors")){Object.defineProperty(Module["ready"],"___wasm_call_ctors",{configurable:true,get:function(){abort("You are getting ___wasm_call_ctors on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"___wasm_call_ctors",{configurable:true,set:function(){abort("You are setting ___wasm_call_ctors on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_fflush")){Object.defineProperty(Module["ready"],"_fflush",{configurable:true,get:function(){abort("You are getting _fflush on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_fflush",{configurable:true,set:function(){abort("You are setting _fflush on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"___errno_location")){Object.defineProperty(Module["ready"],"___errno_location",{configurable:true,get:function(){abort("You are getting ___errno_location on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"___errno_location",{configurable:true,set:function(){abort("You are setting ___errno_location on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"__ZSt18uncaught_exceptionv")){Object.defineProperty(Module["ready"],"__ZSt18uncaught_exceptionv",{configurable:true,get:function(){abort("You are getting __ZSt18uncaught_exceptionv on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"__ZSt18uncaught_exceptionv",{configurable:true,set:function(){abort("You are setting __ZSt18uncaught_exceptionv on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_setThrew")){Object.defineProperty(Module["ready"],"_setThrew",{configurable:true,get:function(){abort("You are getting _setThrew on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_setThrew",{configurable:true,set:function(){abort("You are setting _setThrew on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"___cxa_is_pointer_type")){Object.defineProperty(Module["ready"],"___cxa_is_pointer_type",{configurable:true,get:function(){abort("You are getting ___cxa_is_pointer_type on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"___cxa_is_pointer_type",{configurable:true,set:function(){abort("You are setting ___cxa_is_pointer_type on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"___cxa_can_catch")){Object.defineProperty(Module["ready"],"___cxa_can_catch",{configurable:true,get:function(){abort("You are getting ___cxa_can_catch on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"___cxa_can_catch",{configurable:true,set:function(){abort("You are setting ___cxa_can_catch on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_emscripten_main_thread_process_queued_calls")){Object.defineProperty(Module["ready"],"_emscripten_main_thread_process_queued_calls",{configurable:true,get:function(){abort("You are getting _emscripten_main_thread_process_queued_calls on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_emscripten_main_thread_process_queued_calls",{configurable:true,set:function(){abort("You are setting _emscripten_main_thread_process_queued_calls on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_memalign")){Object.defineProperty(Module["ready"],"_memalign",{configurable:true,get:function(){abort("You are getting _memalign on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_memalign",{configurable:true,set:function(){abort("You are setting _memalign on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_memset")){Object.defineProperty(Module["ready"],"_memset",{configurable:true,get:function(){abort("You are getting _memset on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_memset",{configurable:true,set:function(){abort("You are setting _memset on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"__get_tzname")){Object.defineProperty(Module["ready"],"__get_tzname",{configurable:true,get:function(){abort("You are getting __get_tzname on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"__get_tzname",{configurable:true,set:function(){abort("You are setting __get_tzname on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"__get_daylight")){Object.defineProperty(Module["ready"],"__get_daylight",{configurable:true,get:function(){abort("You are getting __get_daylight on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"__get_daylight",{configurable:true,set:function(){abort("You are setting __get_daylight on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"__get_timezone")){Object.defineProperty(Module["ready"],"__get_timezone",{configurable:true,get:function(){abort("You are getting __get_timezone on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"__get_timezone",{configurable:true,set:function(){abort("You are setting __get_timezone on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_htonl")){Object.defineProperty(Module["ready"],"_htonl",{configurable:true,get:function(){abort("You are getting _htonl on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_htonl",{configurable:true,set:function(){abort("You are setting _htonl on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_htons")){Object.defineProperty(Module["ready"],"_htons",{configurable:true,get:function(){abort("You are getting _htons on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_htons",{configurable:true,set:function(){abort("You are setting _htons on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_ntohs")){Object.defineProperty(Module["ready"],"_ntohs",{configurable:true,get:function(){abort("You are getting _ntohs on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_ntohs",{configurable:true,set:function(){abort("You are setting _ntohs on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"onRuntimeInitialized")){Object.defineProperty(Module["ready"],"onRuntimeInitialized",{configurable:true,get:function(){abort("You are getting onRuntimeInitialized on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"onRuntimeInitialized",{configurable:true,set:function(){abort("You are setting onRuntimeInitialized on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string";ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(Module["ENVIRONMENT"]){throw new Error("Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -s ENVIRONMENT=web or -s ENVIRONMENT=node)")}var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;var nodeFS;var nodePath;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=function shell_read(filename,binary){if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);return nodeFS["readFileSync"](filename,binary?null:"utf8")};readBinary=function readBinary(filename){var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);process["on"]("unhandledRejection",abort);quit_=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){read_=function shell_read(f){return read(f)}}readBinary=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){arguments_=scriptArgs}else if(typeof arguments!="undefined"){arguments_=arguments}if(typeof quit==="function"){quit_=function(status){quit(status)}}if(typeof print!=="undefined"){if(typeof console==="undefined")console={};console.log=print;console.warn=console.error=typeof printErr!=="undefined"?printErr:print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{throw new Error("environment detection error")}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(!Object.getOwnPropertyDescriptor(Module,"arguments"))Object.defineProperty(Module,"arguments",{configurable:true,get:function(){abort("Module.arguments has been replaced with plain arguments_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(!Object.getOwnPropertyDescriptor(Module,"thisProgram"))Object.defineProperty(Module,"thisProgram",{configurable:true,get:function(){abort("Module.thisProgram has been replaced with plain thisProgram (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});if(Module["quit"])quit_=Module["quit"];if(!Object.getOwnPropertyDescriptor(Module,"quit"))Object.defineProperty(Module,"quit",{configurable:true,get:function(){abort("Module.quit has been replaced with plain quit_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});assert(typeof Module["memoryInitializerPrefixURL"]==="undefined","Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead");assert(typeof Module["pthreadMainPrefixURL"]==="undefined","Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead");assert(typeof Module["cdInitializerPrefixURL"]==="undefined","Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead");assert(typeof Module["filePackagePrefixURL"]==="undefined","Module.filePackagePrefixURL option was removed, use Module.locateFile instead");assert(typeof Module["read"]==="undefined","Module.read option was removed (modify read_ in JS)");assert(typeof Module["readAsync"]==="undefined","Module.readAsync option was removed (modify readAsync in JS)");assert(typeof Module["readBinary"]==="undefined","Module.readBinary option was removed (modify readBinary in JS)");assert(typeof Module["setWindowTitle"]==="undefined","Module.setWindowTitle option was removed (modify setWindowTitle in JS)");assert(typeof Module["TOTAL_MEMORY"]==="undefined","Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY");if(!Object.getOwnPropertyDescriptor(Module,"read"))Object.defineProperty(Module,"read",{configurable:true,get:function(){abort("Module.read has been replaced with plain read_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});if(!Object.getOwnPropertyDescriptor(Module,"readAsync"))Object.defineProperty(Module,"readAsync",{configurable:true,get:function(){abort("Module.readAsync has been replaced with plain readAsync (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});if(!Object.getOwnPropertyDescriptor(Module,"readBinary"))Object.defineProperty(Module,"readBinary",{configurable:true,get:function(){abort("Module.readBinary has been replaced with plain readBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});if(!Object.getOwnPropertyDescriptor(Module,"setWindowTitle"))Object.defineProperty(Module,"setWindowTitle",{configurable:true,get:function(){abort("Module.setWindowTitle has been replaced with plain setWindowTitle (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});var STACK_ALIGN=16;function dynamicAlloc(size){assert(DYNAMICTOP_PTR);var ret=HEAP32[DYNAMICTOP_PTR>>2];var end=ret+size+15&-16;assert(end<=HEAP8.length,"failure to dynamicAlloc - memory growth etc. is not supported there, call malloc/sbrk directly");HEAP32[DYNAMICTOP_PTR>>2]=end;return ret}function alignMemory(size,factor){if(!factor)factor=STACK_ALIGN;return Math.ceil(size/factor)*factor}function getNativeTypeSize(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return 4}else if(type[0]==="i"){var bits=Number(type.substr(1));assert(bits%8===0,"getNativeTypeSize invalid bits "+bits+", type "+type);return bits/8}else{return 0}}}}function warnOnce(text){if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;err(text)}}function convertJsFunctionToWasm(func,sig){if(typeof WebAssembly.Function==="function"){var typeNames={"i":"i32","j":"i64","f":"f32","d":"f64"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i>>0)+ +(high>>>0)*4294967296:+(low>>>0)+ +(high|0)*4294967296}function dynCall(sig,ptr,args){if(args&&args.length){assert(args.length===sig.substring(1).replace(/j/g,"--").length);assert("dynCall_"+sig in Module,"bad function pointer type - no table for sig '"+sig+"'");return Module["dynCall_"+sig].apply(null,[ptr].concat(args))}else{assert(sig.length==1);assert("dynCall_"+sig in Module,"bad function pointer type - no table for sig '"+sig+"'");return Module["dynCall_"+sig].call(null,ptr)}}var tempRet0=0;var setTempRet0=function(value){tempRet0=value};var getTempRet0=function(){return tempRet0};var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(!Object.getOwnPropertyDescriptor(Module,"wasmBinary"))Object.defineProperty(Module,"wasmBinary",{configurable:true,get:function(){abort("Module.wasmBinary has been replaced with plain wasmBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});var noExitRuntime;if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(!Object.getOwnPropertyDescriptor(Module,"noExitRuntime"))Object.defineProperty(Module,"noExitRuntime",{configurable:true,get:function(){abort("Module.noExitRuntime has been replaced with plain noExitRuntime (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});if(typeof WebAssembly!=="object"){abort("no native wasm support detected")}function setValue(ptr,value,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":7145,"maximum":7145+5,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret},"array":function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string")return UTF8ToString(ret);if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;assert(returnType!=="array",'Return type should not be "array".');if(args){for(var i=0;i0;assert(!asyncMode||!prevRunningAsync,"Cannot have multiple async ccalls in flight at once");if(runningAsync&&!prevRunningAsync){assert(asyncMode,"The call to "+ident+" is running asynchronously. If this was intended, add the async option to the ccall/cwrap call.");return new Promise(function(resolve){Asyncify.asyncFinalizers.push(function(ret){if(stack!==0)stackRestore(stack);resolve(convertReturnValue(ret))})})}ret=convertReturnValue(ret);if(stack!==0)stackRestore(stack);if(opts&&opts.async)return Promise.resolve(ret);return ret}var ALLOC_NONE=3;var UTF8Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(heap,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heap[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heap.subarray&&UTF8Decoder){return UTF8Decoder.decode(heap.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;if(u>=2097152)warnOnce("Invalid Unicode code point 0x"+u.toString(16)+" encountered when serializing a JS string to an UTF-8 string on the asm.js/wasm heap! (Valid unicode code points should be in range 0-0x1FFFFF).");heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){assert(typeof maxBytesToWrite=="number","stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!");return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;function UTF16ToString(ptr,maxBytesToRead){assert(ptr%2==0,"Pointer passed to UTF16ToString must be aligned to two bytes!");var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder){return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr))}else{var i=0;var str="";while(1){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0||i==maxBytesToRead/2)return str;++i;str+=String.fromCharCode(codeUnit)}}}function stringToUTF16(str,outPtr,maxBytesToWrite){assert(outPtr%2==0,"Pointer passed to stringToUTF16 must be aligned to two bytes!");assert(typeof maxBytesToWrite=="number","stringToUTF16(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!");if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}function lengthBytesUTF16(str){return str.length*2}function UTF32ToString(ptr,maxBytesToRead){assert(ptr%4==0,"Pointer passed to UTF32ToString must be aligned to four bytes!");var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str}function stringToUTF32(str,outPtr,maxBytesToWrite){assert(outPtr%4==0,"Pointer passed to stringToUTF32 must be aligned to four bytes!");assert(typeof maxBytesToWrite=="number","stringToUTF32(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!");if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}function lengthBytesUTF32(str){var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len}function allocateUTF8(str){var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8Array(str,HEAP8,ret,size);return ret}function writeArrayToMemory(array,buffer){assert(array.length>=0,"writeArrayToMemory array must have a length (should be an array or typed array)");HEAP8.set(array,buffer)}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var STACK_BASE=6561440,STACK_MAX=1318560,DYNAMIC_BASE=6561440,DYNAMICTOP_PTR=1318384;assert(STACK_BASE%16===0,"stack must start aligned");assert(DYNAMIC_BASE%16===0,"heap must start aligned");var TOTAL_STACK=5242880;if(Module["TOTAL_STACK"])assert(TOTAL_STACK===Module["TOTAL_STACK"],"the stack size can no longer be determined at runtime");var INITIAL_INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;if(!Object.getOwnPropertyDescriptor(Module,"INITIAL_MEMORY"))Object.defineProperty(Module,"INITIAL_MEMORY",{configurable:true,get:function(){abort("Module.INITIAL_MEMORY has been replaced with plain INITIAL_INITIAL_MEMORY (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});assert(INITIAL_INITIAL_MEMORY>=TOTAL_STACK,"INITIAL_MEMORY should be larger than TOTAL_STACK, was "+INITIAL_INITIAL_MEMORY+"! (TOTAL_STACK="+TOTAL_STACK+")");assert(typeof Int32Array!=="undefined"&&typeof Float64Array!=="undefined"&&Int32Array.prototype.subarray!==undefined&&Int32Array.prototype.set!==undefined,"JS engine does not provide full typed array support");if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_INITIAL_MEMORY/WASM_PAGE_SIZE,"maximum":2147483648/WASM_PAGE_SIZE})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_INITIAL_MEMORY=buffer.byteLength;assert(INITIAL_INITIAL_MEMORY%WASM_PAGE_SIZE===0);assert(65536%WASM_PAGE_SIZE===0);updateGlobalBufferAndViews(buffer);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function writeStackCookie(){assert((STACK_MAX&3)==0);HEAPU32[(STACK_MAX>>2)+1]=34821223;HEAPU32[(STACK_MAX>>2)+2]=2310721022;HEAP32[0]=1668509029}function checkStackCookie(){var cookie1=HEAPU32[(STACK_MAX>>2)+1];var cookie2=HEAPU32[(STACK_MAX>>2)+2];if(cookie1!=34821223||cookie2!=2310721022){abort("Stack overflow! Stack cookie has been overwritten, expected hex dwords 0x89BACDFE and 0x2135467, but received 0x"+cookie2.toString(16)+" "+cookie1.toString(16))}if(HEAP32[0]!==1668509029)abort("Runtime error: The application has corrupted its heap memory area (address zero)!")}(function(){var h16=new Int16Array(1);var h8=new Int8Array(h16.buffer);h16[0]=25459;if(h8[0]!==115||h8[1]!==99)throw"Runtime error: expected the system to be little-endian!"})();function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){checkStackCookie();assert(!runtimeInitialized);runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();TTY.init();PIPEFS.root=FS.mount(PIPEFS,{},null);SOCKFS.root=FS.mount(SOCKFS,{},null);callRuntimeCallbacks(__ATINIT__)}function preMain(){checkStackCookie();FS.ignorePermissions=false;callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){checkStackCookie();runtimeExited=true}function postRun(){checkStackCookie();if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}assert(Math.imul,"This browser does not support Math.imul(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");assert(Math.fround,"This browser does not support Math.fround(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");assert(Math.clz32,"This browser does not support Math.clz32(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");assert(Math.trunc,"This browser does not support Math.trunc(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");var Math_abs=Math.abs;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_min=Math.min;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;var runDependencyTracking={};function getUniqueRunDependency(id){var orig=id;while(1){if(!runDependencyTracking[id])return id;id=orig+Math.random()}}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(id){assert(!runDependencyTracking[id]);runDependencyTracking[id]=1;if(runDependencyWatcher===null&&typeof setInterval!=="undefined"){runDependencyWatcher=setInterval(function(){if(ABORT){clearInterval(runDependencyWatcher);runDependencyWatcher=null;return}var shown=false;for(var dep in runDependencyTracking){if(!shown){shown=true;err("still waiting on run dependencies:")}err("dependency: "+dep)}if(shown){err("(end of list)")}},1e4)}}else{err("warning: run dependency added without ID")}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(id){assert(runDependencyTracking[id]);delete runDependencyTracking[id]}else{err("warning: run dependency removed without ID")}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";err(what);ABORT=true;EXITSTATUS=1;var output="abort("+what+") at "+stackTrace();what=output;var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}function hasPrefix(str,prefix){return String.prototype.startsWith?str.startsWith(prefix):str.indexOf(prefix)===0}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return hasPrefix(filename,dataURIPrefix)}var fileURIPrefix="file://";function isFileURI(filename){return hasPrefix(filename,fileURIPrefix)}function createExportWrapper(name,fixedasm){return function(){var displayName=name;var asm=fixedasm;if(!fixedasm){asm=Module["asm"]}assert(runtimeInitialized,"native function `"+displayName+"` called before runtime initialization");assert(!runtimeExited,"native function `"+displayName+"` called after runtime exit (use NO_EXIT_RUNTIME to keep it alive after main() exits)");if(!asm[name]){assert(asm[name],"exported native function `"+displayName+"` not found")}return asm[name].apply(null,arguments)}}var wasmBinaryFile="monero_core.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"&&!isFileURI(wasmBinaryFile)){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(){var info={"env":asmLibraryArg,"wasi_snapshot_preview1":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;exports=Asyncify.instrumentWasmExports(exports);Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");var trueModule=Module;function receiveInstantiatedSource(output){assert(Module===trueModule,"the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?");trueModule=null;receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&typeof fetch==="function"){fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);exports=Asyncify.instrumentWasmExports(exports);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}var tempDouble;var tempI64;function js_send_binary_request(uri,username,password,reject_unauthorized_fn_id,method,body,body_length,timeout){const monerojs=require("../index");const HttpClient=monerojs.HttpClient;const LibraryUtils=monerojs.LibraryUtils;const GenUtils=monerojs.GenUtils;return Asyncify.handleSleep(function(wakeUp){LibraryUtils.loadCoreModule().then(module=>{let ptr=body;let length=body_length;let view=new Uint8Array(length);for(let i=0;i{let respBin=resp.body;if(!(respBin instanceof Uint8Array)){console.error("resp is not uint8array");console.error(respBin)}let nDataBytes=respBin.length*respBin.BYTES_PER_ELEMENT;let bodyPtr=Module._malloc(nDataBytes);let heap=new Uint8Array(Module.HEAPU8.buffer,bodyPtr,nDataBytes);heap.set(new Uint8Array(respBin.buffer,respBin.byteOffset,nDataBytes));let respContainer={code:resp.statusCode,message:resp.statusText,headers:resp.headers,bodyPtr:bodyPtr,bodyLength:respBin.length};let respStr=JSON.stringify(respContainer);let lengthBytes=Module.lengthBytesUTF8(respStr)+1;let ptr=Module._malloc(lengthBytes);Module.stringToUTF8(respStr,ptr,lengthBytes);wakeUpCalled=true;wakeUp(ptr)}).catch(err=>{if(wakeUpCalled){console.error("Error caught in JS after previously calling wakeUp(): "+err);throw new Error("Error caught in JS after previously calling wakeUp(): "+err)}let str=err.message?err.message:""+err;str=JSON.stringify({error:str});let lengthBytes=Module.lengthBytesUTF8(str)+1;let ptr=Module._malloc(lengthBytes);Module.stringToUTF8(str,ptr,lengthBytes);wakeUpCalled=true;wakeUp(ptr)})}).catch(err=>{throw new Error("Could not load core wasm module")})})}function js_send_json_request(uri,username,password,reject_unauthorized_fn_id,method,body,timeout){const monerojs=require("../index");const HttpClient=monerojs.HttpClient;const LibraryUtils=monerojs.LibraryUtils;const GenUtils=monerojs.GenUtils;return Asyncify.handleSleep(function(wakeUp){let wakeUpCalled=false;HttpClient.request({method:UTF8ToString(method),uri:UTF8ToString(uri),username:UTF8ToString(username),password:UTF8ToString(password),body:UTF8ToString(body),resolveWithFullResponse:true,rejectUnauthorized:LibraryUtils.isRejectUnauthorized(UTF8ToString(reject_unauthorized_fn_id)),requestApi:GenUtils.isFirefox()?"xhr":"fetch"}).then(resp=>{let respContainer={code:resp.statusCode,message:resp.statusText,body:resp.body,headers:resp.headers};let respStr=JSON.stringify(respContainer);let lengthBytes=Module.lengthBytesUTF8(respStr)+1;let ptr=Module._malloc(lengthBytes);Module.stringToUTF8(respStr,ptr,lengthBytes);wakeUpCalled=true;wakeUp(ptr)}).catch(err=>{if(wakeUpCalled){console.error("Error caught in JS after previously calling wakeUp(): "+err);throw new Error("Error caught in JS after previously calling wakeUp(): "+err)}let str=err.message?err.message:""+err;str=JSON.stringify({error:str});let lengthBytes=Module.lengthBytesUTF8(str)+1;let ptr=Module._malloc(lengthBytes);Module.stringToUTF8(str,ptr,lengthBytes);wakeUpCalled=true;wakeUp(ptr)})})}__ATINIT__.push({func:function(){___wasm_call_ctors()}});function demangle(func){warnOnce("warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling");return func}function demangleAll(text){var regex=/\b_Z[\w\d_]+/g;return text.replace(regex,function(x){var y=demangle(x);return x===y?x:y+" ["+x+"]"})}function jsStackTrace(){var err=new Error;if(!err.stack){try{throw new Error}catch(e){err=e}if(!err.stack){return"(no stack trace available)"}}return err.stack.toString()}function stackTrace(){var js=jsStackTrace();if(Module["extraStackTrace"])js+="\n"+Module["extraStackTrace"]();return demangleAll(js)}function _BIO_ctrl(){err("missing function: BIO_ctrl");abort(-1)}function _BIO_ctrl_pending(){err("missing function: BIO_ctrl_pending");abort(-1)}function _BIO_free(){err("missing function: BIO_free");abort(-1)}function _BIO_new_bio_pair(){err("missing function: BIO_new_bio_pair");abort(-1)}function _BIO_new_mem_buf(){err("missing function: BIO_new_mem_buf");abort(-1)}function _BIO_read(){err("missing function: BIO_read");abort(-1)}function _BIO_write(){err("missing function: BIO_write");abort(-1)}function _CONF_modules_unload(){err("missing function: CONF_modules_unload");abort(-1)}function _CRYPTO_free(){err("missing function: CRYPTO_free");abort(-1)}function _ERR_clear_error(){err("missing function: ERR_clear_error");abort(-1)}function _ERR_get_error(){err("missing function: ERR_get_error");abort(-1)}function _ERR_reason_error_string(){err("missing function: ERR_reason_error_string");abort(-1)}function _PEM_read_bio(){err("missing function: PEM_read_bio");abort(-1)}function _PEM_write(){err("missing function: PEM_write");abort(-1)}function _SSL_CTX_ctrl(){err("missing function: SSL_CTX_ctrl");abort(-1)}function _SSL_CTX_free(){err("missing function: SSL_CTX_free");abort(-1)}function _SSL_CTX_get_default_passwd_cb_userdata(){err("missing function: SSL_CTX_get_default_passwd_cb_userdata");abort(-1)}function _SSL_CTX_get_ex_data(){err("missing function: SSL_CTX_get_ex_data");abort(-1)}function _SSL_CTX_new(){err("missing function: SSL_CTX_new");abort(-1)}function _SSL_CTX_set_default_passwd_cb_userdata(){err("missing function: SSL_CTX_set_default_passwd_cb_userdata");abort(-1)}function _SSL_CTX_set_ex_data(){err("missing function: SSL_CTX_set_ex_data");abort(-1)}function _SSL_CTX_set_options(){err("missing function: SSL_CTX_set_options");abort(-1)}function _SSL_ctrl(){err("missing function: SSL_ctrl");abort(-1)}function _SSL_free(){err("missing function: SSL_free");abort(-1)}function _SSL_get_error(){err("missing function: SSL_get_error");abort(-1)}function _SSL_get_ex_data(){err("missing function: SSL_get_ex_data");abort(-1)}function _SSL_get_shutdown(){err("missing function: SSL_get_shutdown");abort(-1)}function _SSL_new(){err("missing function: SSL_new");abort(-1)}function _SSL_read(){err("missing function: SSL_read");abort(-1)}function _SSL_set_bio(){err("missing function: SSL_set_bio");abort(-1)}function _SSL_set_ex_data(){err("missing function: SSL_set_ex_data");abort(-1)}function _SSL_shutdown(){err("missing function: SSL_shutdown");abort(-1)}function _SSL_write(){err("missing function: SSL_write");abort(-1)}function _TLS_client_method(){err("missing function: TLS_client_method");abort(-1)}function _TLS_method(){err("missing function: TLS_method");abort(-1)}function _TLS_server_method(){err("missing function: TLS_server_method");abort(-1)}function __ZN2hw6trezor12register_allEv(){err("missing function: _ZN2hw6trezor12register_allEv");abort(-1)}function __ZN4epee9net_utils4http16http_client_auth13do_handle_401ERKNS1_18http_response_infoE(){err("missing function: _ZN4epee9net_utils4http16http_client_auth13do_handle_401ERKNS1_18http_response_infoE");abort(-1)}function __ZN4epee9net_utils4http16http_client_auth17do_get_auth_fieldEN5boost16basic_string_refIcNSt3__211char_traitsIcEEEES8_(){err("missing function: _ZN4epee9net_utils4http16http_client_auth17do_get_auth_fieldEN5boost16basic_string_refIcNSt3__211char_traitsIcEEEES8_");abort(-1)}function __ZN4epee9net_utils4http16http_client_authC1ENS1_5loginE(){err("missing function: _ZN4epee9net_utils4http16http_client_authC1ENS1_5loginE");abort(-1)}function __ZN5boost10filesystem6detail12current_pathEPNS_6system10error_codeE(){err("missing function: _ZN5boost10filesystem6detail12current_pathEPNS_6system10error_codeE");abort(-1)}function __ZN5boost10filesystem6detail18create_directoriesERKNS0_4pathEPNS_6system10error_codeE(){err("missing function: _ZN5boost10filesystem6detail18create_directoriesERKNS0_4pathEPNS_6system10error_codeE");abort(-1)}function __ZN5boost10filesystem6detail5spaceERKNS0_4pathEPNS_6system10error_codeE(){err("missing function: _ZN5boost10filesystem6detail5spaceERKNS0_4pathEPNS_6system10error_codeE");abort(-1)}function __ZN5boost10filesystem6detail6removeERKNS0_4pathEPNS_6system10error_codeE(){err("missing function: _ZN5boost10filesystem6detail6removeERKNS0_4pathEPNS_6system10error_codeE");abort(-1)}function __ZN5boost10filesystem6detail6statusERKNS0_4pathEPNS_6system10error_codeE(){err("missing function: _ZN5boost10filesystem6detail6statusERKNS0_4pathEPNS_6system10error_codeE");abort(-1)}function __ZN5boost10filesystem6detail9canonicalERKNS0_4pathES4_PNS_6system10error_codeE(){err("missing function: _ZN5boost10filesystem6detail9canonicalERKNS0_4pathES4_PNS_6system10error_codeE");abort(-1)}function __ZN5tools6Notify6notifyEPKcS2_z(){err("missing function: _ZN5tools6Notify6notifyEPKcS2_z");abort(-1)}function __ZN5tools9dns_utils25load_txt_records_from_dnsERNSt3__26vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEERKSA_(){err("missing function: _ZN5tools9dns_utils25load_txt_records_from_dnsERNSt3__26vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEERKSA_");abort(-1)}function __ZN5tools9dns_utils35get_account_address_as_str_from_urlERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERbNS1_8functionIFS7_S9_RKNS1_6vectorIS7_NS5_IS7_EEEEbEEE(){err("missing function: _ZN5tools9dns_utils35get_account_address_as_str_from_urlERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERbNS1_8functionIFS7_S9_RKNS1_6vectorIS7_NS5_IS7_EEEEbEEE");abort(-1)}function __ZNK10cryptonote10Blockchain29get_current_blockchain_heightEv(){err("missing function: _ZNK10cryptonote10Blockchain29get_current_blockchain_heightEv");abort(-1)}function __ZNK10cryptonote10Blockchain30get_pending_block_id_by_heightEy(){err("missing function: _ZNK10cryptonote10Blockchain30get_pending_block_id_by_heightEy");abort(-1)}function __ZNK3net5socks9connectorclERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RN5boost4asio20basic_waitable_timerINS2_6chrono12steady_clockENSC_11wait_traitsISF_EENSC_8executorEEE(){err("missing function: _ZNK3net5socks9connectorclERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RN5boost4asio20basic_waitable_timerINS2_6chrono12steady_clockENSC_11wait_traitsISF_EENSC_8executorEEE");abort(-1)}function __ZNK4epee9net_utils13ssl_options_t14create_contextEv(){err("missing function: _ZNK4epee9net_utils13ssl_options_t14create_contextEv");abort(-1)}function __ZNK4epee9net_utils13ssl_options_t9handshakeERN5boost4asio3ssl6streamINS3_19basic_stream_socketINS3_2ip3tcpENS3_8executorEEEEENS4_11stream_base14handshake_typeERKNSt3__212basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEENSF_6chrono8durationIxNSF_5ratioILx1ELx1000EEEEE(){err("missing function: _ZNK4epee9net_utils13ssl_options_t9handshakeERN5boost4asio3ssl6streamINS3_19basic_stream_socketINS3_2ip3tcpENS3_8executorEEEEENS4_11stream_base14handshake_typeERKNSt3__212basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEENSF_6chrono8durationIxNSF_5ratioILx1ELx1000EEEEE");abort(-1)}function __ZNK4epee9net_utils14direct_connectclERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RN5boost4asio20basic_waitable_timerINS2_6chrono12steady_clockENSC_11wait_traitsISF_EENSC_8executorEEE(){err("missing function: _ZNK4epee9net_utils14direct_connectclERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RN5boost4asio20basic_waitable_timerINS2_6chrono12steady_clockENSC_11wait_traitsISF_EENSC_8executorEEE");abort(-1)}function __ZNK5boost10filesystem4path11parent_pathEv(){err("missing function: _ZNK5boost10filesystem4path11parent_pathEv");abort(-1)}function ___assert_fail(condition,filename,line,func){abort("Assertion failed: "+UTF8ToString(condition)+", at: "+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}var ExceptionInfoAttrs={DESTRUCTOR_OFFSET:0,REFCOUNT_OFFSET:4,TYPE_OFFSET:8,CAUGHT_OFFSET:12,RETHROWN_OFFSET:13,SIZE:16};function ___cxa_allocate_exception(size){return _malloc(size+ExceptionInfoAttrs.SIZE)+ExceptionInfoAttrs.SIZE}function _atexit(func,arg){warnOnce("atexit() called, but EXIT_RUNTIME is not set, so atexits() will not be called. set EXIT_RUNTIME to 1 (see the FAQ)")}function ___cxa_atexit(a0,a1){return _atexit(a0,a1)}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-ExceptionInfoAttrs.SIZE;this.set_type=function(type){HEAP32[this.ptr+ExceptionInfoAttrs.TYPE_OFFSET>>2]=type};this.get_type=function(){return HEAP32[this.ptr+ExceptionInfoAttrs.TYPE_OFFSET>>2]};this.set_destructor=function(destructor){HEAP32[this.ptr+ExceptionInfoAttrs.DESTRUCTOR_OFFSET>>2]=destructor};this.get_destructor=function(){return HEAP32[this.ptr+ExceptionInfoAttrs.DESTRUCTOR_OFFSET>>2]};this.set_refcount=function(refcount){HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2]=refcount};this.set_caught=function(caught){caught=caught?1:0;HEAP8[this.ptr+ExceptionInfoAttrs.CAUGHT_OFFSET>>0]=caught};this.get_caught=function(){return HEAP8[this.ptr+ExceptionInfoAttrs.CAUGHT_OFFSET>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+ExceptionInfoAttrs.RETHROWN_OFFSET>>0]=rethrown};this.get_rethrown=function(){return HEAP8[this.ptr+ExceptionInfoAttrs.RETHROWN_OFFSET>>0]!=0};this.init=function(type,destructor){this.set_type(type);this.set_destructor(destructor);this.set_refcount(0);this.set_caught(false);this.set_rethrown(false)};this.add_ref=function(){var value=HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2];HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2]=value+1};this.release_ref=function(){var prev=HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2];HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2]=prev-1;assert(prev>0);return prev===1}}function CatchInfo(ptr){this.free=function(){_free(this.ptr);this.ptr=0};this.set_base_ptr=function(basePtr){HEAP32[this.ptr>>2]=basePtr};this.get_base_ptr=function(){return HEAP32[this.ptr>>2]};this.set_adjusted_ptr=function(adjustedPtr){var ptrSize=4;HEAP32[this.ptr+ptrSize>>2]=adjustedPtr};this.get_adjusted_ptr=function(){var ptrSize=4;return HEAP32[this.ptr+ptrSize>>2]};this.get_exception_ptr=function(){var isPointer=___cxa_is_pointer_type(this.get_exception_info().get_type());if(isPointer){return HEAP32[this.get_base_ptr()>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.get_base_ptr()};this.get_exception_info=function(){return new ExceptionInfo(this.get_base_ptr())};if(ptr===undefined){this.ptr=_malloc(8);this.set_adjusted_ptr(0)}else{this.ptr=ptr}}var exceptionCaught=[];function exception_addRef(info){info.add_ref()}function ___cxa_begin_catch(ptr){var catchInfo=new CatchInfo(ptr);var info=catchInfo.get_exception_info();if(!info.get_caught()){info.set_caught(true);__ZSt18uncaught_exceptionv.uncaught_exceptions--}info.set_rethrown(false);exceptionCaught.push(catchInfo);exception_addRef(info);return catchInfo.get_exception_ptr()}function ___cxa_free_exception(ptr){try{return _free(new ExceptionInfo(ptr).ptr)}catch(e){err("exception during cxa_free_exception: "+e)}}function exception_decRef(info){if(info.release_ref()&&!info.get_rethrown()){var destructor=info.get_destructor();if(destructor){Module["dynCall_ii"](destructor,info.excPtr)}___cxa_free_exception(info.excPtr)}}function ___cxa_decrement_exception_refcount(ptr){if(!ptr)return;exception_decRef(new ExceptionInfo(ptr))}var exceptionLast=0;function ___cxa_end_catch(){_setThrew(0);assert(exceptionCaught.length>0);var catchInfo=exceptionCaught.pop();exception_decRef(catchInfo.get_exception_info());catchInfo.free();exceptionLast=0}function ___resumeException(catchInfoPtr){var catchInfo=new CatchInfo(catchInfoPtr);var ptr=catchInfo.get_base_ptr();if(!exceptionLast){exceptionLast=ptr}catchInfo.free();throw ptr}function ___cxa_find_matching_catch_2(){var thrown=exceptionLast;if(!thrown){return(setTempRet0(0),0)|0}var info=new ExceptionInfo(thrown);var thrownType=info.get_type();var catchInfo=new CatchInfo;catchInfo.set_base_ptr(thrown);if(!thrownType){return(setTempRet0(0),catchInfo.ptr)|0}var typeArray=Array.prototype.slice.call(arguments);var thrownBuf=1318544;HEAP32[thrownBuf>>2]=thrown;for(var i=0;i>2];if(thrown!==adjusted){catchInfo.set_adjusted_ptr(adjusted)}return(setTempRet0(caughtType),catchInfo.ptr)|0}}return(setTempRet0(thrownType),catchInfo.ptr)|0}function ___cxa_find_matching_catch_3(){var thrown=exceptionLast;if(!thrown){return(setTempRet0(0),0)|0}var info=new ExceptionInfo(thrown);var thrownType=info.get_type();var catchInfo=new CatchInfo;catchInfo.set_base_ptr(thrown);if(!thrownType){return(setTempRet0(0),catchInfo.ptr)|0}var typeArray=Array.prototype.slice.call(arguments);var thrownBuf=1318544;HEAP32[thrownBuf>>2]=thrown;for(var i=0;i>2];if(thrown!==adjusted){catchInfo.set_adjusted_ptr(adjusted)}return(setTempRet0(caughtType),catchInfo.ptr)|0}}return(setTempRet0(thrownType),catchInfo.ptr)|0}function ___cxa_increment_exception_refcount(ptr){if(!ptr)return;exception_addRef(new ExceptionInfo(ptr))}function ___cxa_rethrow(){var catchInfo=exceptionCaught.pop();var info=catchInfo.get_exception_info();var ptr=catchInfo.get_base_ptr();if(!info.get_rethrown()){exceptionCaught.push(catchInfo);info.set_rethrown(true)}else{catchInfo.free()}exceptionLast=ptr;throw ptr}function ___cxa_rethrow_primary_exception(ptr){if(!ptr)return;var catchInfo=new CatchInfo;catchInfo.set_base_ptr(ptr);var info=catchInfo.get_exception_info();exceptionCaught.push(catchInfo);info.set_rethrown(true);___cxa_rethrow()}function ___cxa_throw(ptr,type,destructor){var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;if(!("uncaught_exception"in __ZSt18uncaught_exceptionv)){__ZSt18uncaught_exceptionv.uncaught_exceptions=1}else{__ZSt18uncaught_exceptionv.uncaught_exceptions++}throw ptr}function ___cxa_uncaught_exceptions(){return __ZSt18uncaught_exceptionv.uncaught_exceptions}function ___handle_stack_overflow(){abort("stack overflow")}function setErrNo(value){HEAP32[___errno_location()>>2]=value;return value}function ___map_file(pathname,size){setErrNo(63);return-1}var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(path){var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path==="/")return"/";var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!=="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=path.charAt(0)==="/"}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(function(p){return!!p}),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:function(from,to){from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node}return node},getFileDataAsRegularArray:function(node){if(node.contents&&node.contents.subarray){var arr=[];for(var i=0;i=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);return},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;return}if(!node.contents||node.contents.subarray){var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize;return}if(!node.contents)node.contents=[];if(node.contents.length>newSize)node.contents.length=newSize;else while(node.contents.length=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);assert(size>=0);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length8){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),false);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:function(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?mount+"/"+path:mount+path}path=path?node.name+"/"+path:node.name;node=node.parent}},hashName:function(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:function(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:function(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode:function(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode:function(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:function(node){FS.hashRemoveNode(node)},isRoot:function(node){return node===node.parent},isMountpoint:function(node){return!!node.mounted},isFile:function(mode){return(mode&61440)===32768},isDir:function(mode){return(mode&61440)===16384},isLink:function(mode){return(mode&61440)===40960},isChrdev:function(mode){return(mode&61440)===8192},isBlkdev:function(mode){return(mode&61440)===24576},isFIFO:function(mode){return(mode&61440)===4096},isSocket:function(mode){return(mode&49152)===49152},flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function(str){var flags=FS.flagModes[str];if(typeof flags==="undefined"){throw new Error("Unknown file open mode: "+str)}return flags},flagsToPermissionString:function(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:function(node,perms){if(FS.ignorePermissions){return 0}if(perms.indexOf("r")!==-1&&!(node.mode&292)){return 2}else if(perms.indexOf("w")!==-1&&!(node.mode&146)){return 2}else if(perms.indexOf("x")!==-1&&!(node.mode&73)){return 2}return 0},mayLookup:function(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:function(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:function(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:function(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:function(fd_start,fd_end){fd_start=fd_start||0;fd_end=fd_end||FS.MAX_OPEN_FDS;for(var fd=fd_start;fd<=fd_end;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:function(fd){return FS.streams[fd]},createStream:function(stream,fd_start,fd_end){if(!FS.FSStream){FS.FSStream=function(){};FS.FSStream.prototype={object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}}}}var newStream=new FS.FSStream;for(var p in stream){newStream[p]=stream[p]}stream=newStream;var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:function(fd){FS.streams[fd]=null},chrdev_stream_ops:{open:function(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:function(){throw new FS.ErrnoError(70)}},major:function(dev){return dev>>8},minor:function(dev){return dev&255},makedev:function(ma,mi){return ma<<8|mi},registerDevice:function(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:function(dev){return FS.devices[dev]},getMounts:function(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:function(populate,callback){if(typeof populate==="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err("warning: "+FS.syncFSRequests+" FS.syncfs operations in flight at once, probably just doing extra work")}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){assert(FS.syncFSRequests>0);FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(function(mount){if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:function(type,opts,mountpoint){if(typeof type==="string"){throw type}var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:function(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(function(hash){var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.indexOf(current.mount)!==-1){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);assert(idx!==-1);node.mount.mounts.splice(idx,1)},lookup:function(parent,name){return parent.node_ops.lookup(parent,name)},mknod:function(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:function(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:function(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:function(path,mode){var dirs=path.split("/");var d="";for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=function(from,to){if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);if(typeof Uint8Array!="undefined")xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}else{return intArrayFromString(xhr.responseText||"",true)}};var lazyArray=this;lazyArray.setDataGetter(function(chunkNum){var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]==="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]==="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!=="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(function(key){var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}return fn.apply(null,arguments)}});stream_ops.read=function stream_ops_read(stream,buffer,offset,length,position){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);assert(size>=0);if(contents.slice){for(var i=0;i>2]=stat.dev;HEAP32[buf+4>>2]=0;HEAP32[buf+8>>2]=stat.ino;HEAP32[buf+12>>2]=stat.mode;HEAP32[buf+16>>2]=stat.nlink;HEAP32[buf+20>>2]=stat.uid;HEAP32[buf+24>>2]=stat.gid;HEAP32[buf+28>>2]=stat.rdev;HEAP32[buf+32>>2]=0;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAP32[buf+48>>2]=4096;HEAP32[buf+52>>2]=stat.blocks;HEAP32[buf+56>>2]=stat.atime.getTime()/1e3|0;HEAP32[buf+60>>2]=0;HEAP32[buf+64>>2]=stat.mtime.getTime()/1e3|0;HEAP32[buf+68>>2]=0;HEAP32[buf+72>>2]=stat.ctime.getTime()/1e3|0;HEAP32[buf+76>>2]=0;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+80>>2]=tempI64[0],HEAP32[buf+84>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},doMkdir:function(path,mode){path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0},doMknod:function(path,mode,dev){switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0},doReadlink:function(path,buf,bufsize){if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len},doAccess:function(path,amode){if(amode&~7){return-28}var node;var lookup=FS.lookupPath(path,{follow:true});node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0},doDup:function(path,flags,suggestFD){var suggest=FS.getStream(suggestFD);if(suggest)FS.close(suggest);return FS.open(path,flags,0,suggestFD,suggestFD).fd},doReadv:function(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr}return ret},varargs:undefined,get:function(){assert(SYSCALLS.varargs!=undefined);SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream},get64:function(low,high){if(low>=0)assert(high===0);else assert(high===-1);return low}};function ___sys__newselect(nfds,readfds,writefds,exceptfds,timeout){try{assert(nfds<=64,"nfds must be less than or equal to 64");assert(!exceptfds,"exceptfds not supported");var total=0;var srcReadLow=readfds?HEAP32[readfds>>2]:0,srcReadHigh=readfds?HEAP32[readfds+4>>2]:0;var srcWriteLow=writefds?HEAP32[writefds>>2]:0,srcWriteHigh=writefds?HEAP32[writefds+4>>2]:0;var srcExceptLow=exceptfds?HEAP32[exceptfds>>2]:0,srcExceptHigh=exceptfds?HEAP32[exceptfds+4>>2]:0;var dstReadLow=0,dstReadHigh=0;var dstWriteLow=0,dstWriteHigh=0;var dstExceptLow=0,dstExceptHigh=0;var allLow=(readfds?HEAP32[readfds>>2]:0)|(writefds?HEAP32[writefds>>2]:0)|(exceptfds?HEAP32[exceptfds>>2]:0);var allHigh=(readfds?HEAP32[readfds+4>>2]:0)|(writefds?HEAP32[writefds+4>>2]:0)|(exceptfds?HEAP32[exceptfds+4>>2]:0);var check=function(fd,low,high,val){return fd<32?low&val:high&val};for(var fd=0;fd>2]=dstReadLow;HEAP32[readfds+4>>2]=dstReadHigh}if(writefds){HEAP32[writefds>>2]=dstWriteLow;HEAP32[writefds+4>>2]=dstWriteHigh}if(exceptfds){HEAP32[exceptfds>>2]=dstExceptLow;HEAP32[exceptfds+4>>2]=dstExceptHigh}return total}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}var newStream;newStream=FS.open(stream.path,stream.flags,0,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 12:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_fdatasync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_ftruncate64(fd,zero,low,high){try{var length=SYSCALLS.get64(low,high);FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_getpid(){return 42}function ___sys_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:case 21505:{if(!stream.tty)return-59;return 0}case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:{if(!stream.tty)return-59;return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.get();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.get();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;return 0}case 21524:{if(!stream.tty)return-59;return 0}default:abort("bad ioctl syscall "+op)}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_madvise1(addr,length,advice){return 0}function ___sys_mkdir(path,mode){try{path=SYSCALLS.getStr(path);return SYSCALLS.doMkdir(path,mode)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_mlock(addr,len){return 0}function syscallMmap2(addr,len,prot,flags,fd,off){off<<=12;var ptr;var allocated=false;if((flags&16)!==0&&addr%16384!==0){return-28}if((flags&32)!==0){ptr=_memalign(16384,len);if(!ptr)return-48;_memset(ptr,0,len);allocated=true}else{var info=FS.getStream(fd);if(!info)return-8;var res=FS.mmap(info,addr,len,off,prot,flags);ptr=res.ptr;allocated=res.allocated}SYSCALLS.mappings[ptr]={malloc:ptr,len:len,allocated:allocated,fd:fd,prot:prot,flags:flags,offset:off};return ptr}function ___sys_mmap2(addr,len,prot,flags,fd,off){try{return syscallMmap2(addr,len,prot,flags,fd,off)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_msync(addr,len,flags){try{var info=SYSCALLS.mappings[addr];if(!info)return 0;SYSCALLS.doMsync(addr,FS.getStream(info.fd),len,info.flags,0);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_munlock(addr,len){return 0}function syscallMunmap(addr,len){if((addr|0)===-1||len===0){return-28}var info=SYSCALLS.mappings[addr];if(!info)return 0;if(len===info.len){var stream=FS.getStream(info.fd);if(info.prot&2){SYSCALLS.doMsync(addr,stream,len,info.flags,info.offset)}FS.munmap(stream);SYSCALLS.mappings[addr]=null;if(info.allocated){_free(info.malloc)}}return 0}function ___sys_munmap(addr,len){try{return syscallMunmap(addr,len)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_open(path,flags,varargs){SYSCALLS.varargs=varargs;try{var pathname=SYSCALLS.getStr(path);var mode=SYSCALLS.get();var stream=FS.open(pathname,flags,mode);return stream.fd}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_pause(){return-27}var PIPEFS={BUCKET_BUFFER_SIZE:8192,mount:function(mount){return FS.createNode(null,"/",16384|511,0)},createPipe:function(){var pipe={buckets:[]};pipe.buckets.push({buffer:new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),offset:0,roffset:0});var rName=PIPEFS.nextname();var wName=PIPEFS.nextname();var rNode=FS.createNode(PIPEFS.root,rName,4096,0);var wNode=FS.createNode(PIPEFS.root,wName,4096,0);rNode.pipe=pipe;wNode.pipe=pipe;var readableStream=FS.createStream({path:rName,node:rNode,flags:FS.modeStringToFlags("r"),seekable:false,stream_ops:PIPEFS.stream_ops});rNode.stream=readableStream;var writableStream=FS.createStream({path:wName,node:wNode,flags:FS.modeStringToFlags("w"),seekable:false,stream_ops:PIPEFS.stream_ops});wNode.stream=writableStream;return{readable_fd:readableStream.fd,writable_fd:writableStream.fd}},stream_ops:{poll:function(stream){var pipe=stream.node.pipe;if((stream.flags&2097155)===1){return 256|4}else{if(pipe.buckets.length>0){for(var i=0;i0){return 64|1}}}}return 0},ioctl:function(stream,request,varargs){return ERRNO_CODES.EINVAL},fsync:function(stream){return ERRNO_CODES.EINVAL},read:function(stream,buffer,offset,length,position){var pipe=stream.node.pipe;var currentLength=0;for(var i=0;i=dataLen){currBucket.buffer.set(data,currBucket.offset);currBucket.offset+=dataLen;return dataLen}else if(freeBytesInCurrBuffer>0){currBucket.buffer.set(data.subarray(0,freeBytesInCurrBuffer),currBucket.offset);currBucket.offset+=freeBytesInCurrBuffer;data=data.subarray(freeBytesInCurrBuffer,data.byteLength)}var numBuckets=data.byteLength/PIPEFS.BUCKET_BUFFER_SIZE|0;var remElements=data.byteLength%PIPEFS.BUCKET_BUFFER_SIZE;for(var i=0;i0){var newBucket={buffer:new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),offset:data.byteLength,roffset:0};pipe.buckets.push(newBucket);newBucket.buffer.set(data)}return dataLen},close:function(stream){var pipe=stream.node.pipe;pipe.buckets=null}},nextname:function(){if(!PIPEFS.nextname.current){PIPEFS.nextname.current=0}return"pipe["+PIPEFS.nextname.current+++"]"}};function ___sys_pipe(fdPtr){try{if(fdPtr==0){throw new FS.ErrnoError(21)}var res=PIPEFS.createPipe();HEAP32[fdPtr>>2]=res.readable_fd;HEAP32[fdPtr+4>>2]=res.writable_fd;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_pwrite64(fd,buf,count,zero,low,high){try{var stream=SYSCALLS.getStreamFromFD(fd);var offset=SYSCALLS.get64(low,high);return FS.write(stream,HEAP8,buf,count,offset)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_read(fd,buf,count){try{var stream=SYSCALLS.getStreamFromFD(fd);return FS.read(stream,HEAP8,buf,count)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_rename(old_path,new_path){try{old_path=SYSCALLS.getStr(old_path);new_path=SYSCALLS.getStr(new_path);FS.rename(old_path,new_path);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}var SOCKFS={mount:function(mount){Module["websocket"]=Module["websocket"]&&"object"===typeof Module["websocket"]?Module["websocket"]:{};Module["websocket"]._callbacks={};Module["websocket"]["on"]=function(event,callback){if("function"===typeof callback){this._callbacks[event]=callback}return this};Module["websocket"].emit=function(event,param){if("function"===typeof this._callbacks[event]){this._callbacks[event].call(this,param)}};return FS.createNode(null,"/",16384|511,0)},createSocket:function(family,type,protocol){type&=~526336;var streaming=type==1;if(protocol){assert(streaming==(protocol==6))}var sock={family:family,type:type,protocol:protocol,server:null,error:null,peers:{},pending:[],recv_queue:[],sock_ops:SOCKFS.websocket_sock_ops};var name=SOCKFS.nextname();var node=FS.createNode(SOCKFS.root,name,49152,0);node.sock=sock;var stream=FS.createStream({path:name,node:node,flags:FS.modeStringToFlags("r+"),seekable:false,stream_ops:SOCKFS.stream_ops});sock.stream=stream;return sock},getSocket:function(fd){var stream=FS.getStream(fd);if(!stream||!FS.isSocket(stream.node.mode)){return null}return stream.node.sock},stream_ops:{poll:function(stream){var sock=stream.node.sock;return sock.sock_ops.poll(sock)},ioctl:function(stream,request,varargs){var sock=stream.node.sock;return sock.sock_ops.ioctl(sock,request,varargs)},read:function(stream,buffer,offset,length,position){var sock=stream.node.sock;var msg=sock.sock_ops.recvmsg(sock,length);if(!msg){return 0}buffer.set(msg.buffer,offset);return msg.buffer.length},write:function(stream,buffer,offset,length,position){var sock=stream.node.sock;return sock.sock_ops.sendmsg(sock,buffer,offset,length)},close:function(stream){var sock=stream.node.sock;sock.sock_ops.close(sock)}},nextname:function(){if(!SOCKFS.nextname.current){SOCKFS.nextname.current=0}return"socket["+SOCKFS.nextname.current+++"]"},websocket_sock_ops:{createPeer:function(sock,addr,port){var ws;if(typeof addr==="object"){ws=addr;addr=null;port=null}if(ws){if(ws._socket){addr=ws._socket.remoteAddress;port=ws._socket.remotePort}else{var result=/ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);if(!result){throw new Error("WebSocket URL must be in the format ws(s)://address:port")}addr=result[1];port=parseInt(result[2],10)}}else{try{var runtimeConfig=Module["websocket"]&&"object"===typeof Module["websocket"];var url="ws:#".replace("#","//");if(runtimeConfig){if("string"===typeof Module["websocket"]["url"]){url=Module["websocket"]["url"]}}if(url==="ws://"||url==="wss://"){var parts=addr.split("/");url=url+parts[0]+":"+port+"/"+parts.slice(1).join("/")}var subProtocols="binary";if(runtimeConfig){if("string"===typeof Module["websocket"]["subprotocol"]){subProtocols=Module["websocket"]["subprotocol"]}}var opts=undefined;if(subProtocols!=="null"){subProtocols=subProtocols.replace(/^ +| +$/g,"").split(/ *, */);opts=ENVIRONMENT_IS_NODE?{"protocol":subProtocols.toString()}:subProtocols}if(runtimeConfig&&null===Module["websocket"]["subprotocol"]){subProtocols="null";opts=undefined}var WebSocketConstructor;if(ENVIRONMENT_IS_NODE){WebSocketConstructor=require("ws")}else{WebSocketConstructor=WebSocket}ws=new WebSocketConstructor(url,opts);ws.binaryType="arraybuffer"}catch(e){throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH)}}var peer={addr:addr,port:port,socket:ws,dgram_send_queue:[]};SOCKFS.websocket_sock_ops.addPeer(sock,peer);SOCKFS.websocket_sock_ops.handlePeerEvents(sock,peer);if(sock.type===2&&typeof sock.sport!=="undefined"){peer.dgram_send_queue.push(new Uint8Array([255,255,255,255,"p".charCodeAt(0),"o".charCodeAt(0),"r".charCodeAt(0),"t".charCodeAt(0),(sock.sport&65280)>>8,sock.sport&255]))}return peer},getPeer:function(sock,addr,port){return sock.peers[addr+":"+port]},addPeer:function(sock,peer){sock.peers[peer.addr+":"+peer.port]=peer},removePeer:function(sock,peer){delete sock.peers[peer.addr+":"+peer.port]},handlePeerEvents:function(sock,peer){var first=true;var handleOpen=function(){Module["websocket"].emit("open",sock.stream.fd);try{var queued=peer.dgram_send_queue.shift();while(queued){peer.socket.send(queued);queued=peer.dgram_send_queue.shift()}}catch(e){peer.socket.close()}};function handleMessage(data){if(typeof data==="string"){var encoder=new TextEncoder;data=encoder.encode(data)}else{assert(data.byteLength!==undefined);if(data.byteLength==0){return}else{data=new Uint8Array(data)}}var wasfirst=first;first=false;if(wasfirst&&data.length===10&&data[0]===255&&data[1]===255&&data[2]===255&&data[3]===255&&data[4]==="p".charCodeAt(0)&&data[5]==="o".charCodeAt(0)&&data[6]==="r".charCodeAt(0)&&data[7]==="t".charCodeAt(0)){var newport=data[8]<<8|data[9];SOCKFS.websocket_sock_ops.removePeer(sock,peer);peer.port=newport;SOCKFS.websocket_sock_ops.addPeer(sock,peer);return}sock.recv_queue.push({addr:peer.addr,port:peer.port,data:data});Module["websocket"].emit("message",sock.stream.fd)}if(ENVIRONMENT_IS_NODE){peer.socket.on("open",handleOpen);peer.socket.on("message",function(data,flags){if(!flags.binary){return}handleMessage(new Uint8Array(data).buffer)});peer.socket.on("close",function(){Module["websocket"].emit("close",sock.stream.fd)});peer.socket.on("error",function(error){sock.error=ERRNO_CODES.ECONNREFUSED;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])})}else{peer.socket.onopen=handleOpen;peer.socket.onclose=function(){Module["websocket"].emit("close",sock.stream.fd)};peer.socket.onmessage=function peer_socket_onmessage(event){handleMessage(event.data)};peer.socket.onerror=function(error){sock.error=ERRNO_CODES.ECONNREFUSED;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])}}},poll:function(sock){if(sock.type===1&&sock.server){return sock.pending.length?64|1:0}var mask=0;var dest=sock.type===1?SOCKFS.websocket_sock_ops.getPeer(sock,sock.daddr,sock.dport):null;if(sock.recv_queue.length||!dest||dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=64|1}if(!dest||dest&&dest.socket.readyState===dest.socket.OPEN){mask|=4}if(dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=16}return mask},ioctl:function(sock,request,arg){switch(request){case 21531:var bytes=0;if(sock.recv_queue.length){bytes=sock.recv_queue[0].data.length}HEAP32[arg>>2]=bytes;return 0;default:return ERRNO_CODES.EINVAL}},close:function(sock){if(sock.server){try{sock.server.close()}catch(e){}sock.server=null}var peers=Object.keys(sock.peers);for(var i=0;i>>0}function jstoi_q(str){return parseInt(str)}function __inet_pton6_raw(str){var words;var w,offset,z;var valid6regx=/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i;var parts=[];if(!valid6regx.test(str)){return null}if(str==="::"){return[0,0,0,0,0,0,0,0]}if(str.indexOf("::")===0){str=str.replace("::","Z:")}else{str=str.replace("::",":Z:")}if(str.indexOf(".")>0){str=str.replace(new RegExp("[.]","g"),":");words=str.split(":");words[words.length-4]=jstoi_q(words[words.length-4])+jstoi_q(words[words.length-3])*256;words[words.length-3]=jstoi_q(words[words.length-2])+jstoi_q(words[words.length-1])*256;words=words.slice(0,words.length-2)}else{words=str.split(":")}offset=0;z=0;for(w=0;w>8&255)+"."+(addr>>16&255)+"."+(addr>>24&255)}function __inet_ntop6_raw(ints){var str="";var word=0;var longest=0;var lastzero=0;var zstart=0;var len=0;var i=0;var parts=[ints[0]&65535,ints[0]>>16,ints[1]&65535,ints[1]>>16,ints[2]&65535,ints[2]>>16,ints[3]&65535,ints[3]>>16];var hasipv4=true;var v4part="";for(i=0;i<5;i++){if(parts[i]!==0){hasipv4=false;break}}if(hasipv4){v4part=__inet_ntop4_raw(parts[6]|parts[7]<<16);if(parts[5]===-1){str="::ffff:";str+=v4part;return str}if(parts[5]===0){str="::";if(v4part==="0.0.0.0")v4part="";if(v4part==="0.0.0.1")v4part="1";str+=v4part;return str}}for(word=0;word<8;word++){if(parts[word]===0){if(word-lastzero>1){len=0}lastzero=word;len++}if(len>longest){longest=len;zstart=word-longest+1}}for(word=0;word<8;word++){if(longest>1){if(parts[word]===0&&word>=zstart&&word>1];var port=_ntohs(HEAPU16[sa+2>>1]);var addr;switch(family){case 2:if(salen!==16){return{errno:28}}addr=HEAP32[sa+4>>2];addr=__inet_ntop4_raw(addr);break;case 10:if(salen!==28){return{errno:28}}addr=[HEAP32[sa+8>>2],HEAP32[sa+12>>2],HEAP32[sa+16>>2],HEAP32[sa+20>>2]];addr=__inet_ntop6_raw(addr);break;default:return{errno:5}}return{family:family,addr:addr,port:port}}function __write_sockaddr(sa,family,addr,port){switch(family){case 2:addr=__inet_pton4_raw(addr);HEAP16[sa>>1]=family;HEAP32[sa+4>>2]=addr;HEAP16[sa+2>>1]=_htons(port);break;case 10:addr=__inet_pton6_raw(addr);HEAP32[sa>>2]=family;HEAP32[sa+8>>2]=addr[0];HEAP32[sa+12>>2]=addr[1];HEAP32[sa+16>>2]=addr[2];HEAP32[sa+20>>2]=addr[3];HEAP16[sa+2>>1]=_htons(port);HEAP32[sa+4>>2]=0;HEAP32[sa+24>>2]=0;break;default:return{errno:5}}return{}}function ___sys_socketcall(call,socketvararg){try{SYSCALLS.varargs=socketvararg;var getSocketFromFD=function(){var socket=SOCKFS.getSocket(SYSCALLS.get());if(!socket)throw new FS.ErrnoError(8);return socket};var getSocketAddress=function(allowNull){var addrp=SYSCALLS.get(),addrlen=SYSCALLS.get();if(allowNull&&addrp===0)return null;var info=__read_sockaddr(addrp,addrlen);if(info.errno)throw new FS.ErrnoError(info.errno);info.addr=DNS.lookup_addr(info.addr)||info.addr;return info};switch(call){case 1:{var domain=SYSCALLS.get(),type=SYSCALLS.get(),protocol=SYSCALLS.get();var sock=SOCKFS.createSocket(domain,type,protocol);assert(sock.stream.fd<64);return sock.stream.fd}case 2:{var sock=getSocketFromFD(),info=getSocketAddress();sock.sock_ops.bind(sock,info.addr,info.port);return 0}case 3:{var sock=getSocketFromFD(),info=getSocketAddress();sock.sock_ops.connect(sock,info.addr,info.port);return 0}case 4:{var sock=getSocketFromFD(),backlog=SYSCALLS.get();sock.sock_ops.listen(sock,backlog);return 0}case 5:{var sock=getSocketFromFD(),addr=SYSCALLS.get(),addrlen=SYSCALLS.get();var newsock=sock.sock_ops.accept(sock);if(addr){var res=__write_sockaddr(addr,newsock.family,DNS.lookup_name(newsock.daddr),newsock.dport);assert(!res.errno)}return newsock.stream.fd}case 6:{var sock=getSocketFromFD(),addr=SYSCALLS.get(),addrlen=SYSCALLS.get();var res=__write_sockaddr(addr,sock.family,DNS.lookup_name(sock.saddr||"0.0.0.0"),sock.sport);assert(!res.errno);return 0}case 7:{var sock=getSocketFromFD(),addr=SYSCALLS.get(),addrlen=SYSCALLS.get();if(!sock.daddr){return-53}var res=__write_sockaddr(addr,sock.family,DNS.lookup_name(sock.daddr),sock.dport);assert(!res.errno);return 0}case 11:{var sock=getSocketFromFD(),message=SYSCALLS.get(),length=SYSCALLS.get(),flags=SYSCALLS.get(),dest=getSocketAddress(true);if(!dest){return FS.write(sock.stream,HEAP8,message,length)}else{return sock.sock_ops.sendmsg(sock,HEAP8,message,length,dest.addr,dest.port)}}case 12:{var sock=getSocketFromFD(),buf=SYSCALLS.get(),len=SYSCALLS.get(),flags=SYSCALLS.get(),addr=SYSCALLS.get(),addrlen=SYSCALLS.get();var msg=sock.sock_ops.recvmsg(sock,len);if(!msg)return 0;if(addr){var res=__write_sockaddr(addr,sock.family,DNS.lookup_name(msg.addr),msg.port);assert(!res.errno)}HEAPU8.set(msg.buffer,buf);return msg.buffer.byteLength}case 14:{return-50}case 15:{var sock=getSocketFromFD(),level=SYSCALLS.get(),optname=SYSCALLS.get(),optval=SYSCALLS.get(),optlen=SYSCALLS.get();if(level===1){if(optname===4){HEAP32[optval>>2]=sock.error;HEAP32[optlen>>2]=4;sock.error=null;return 0}}return-50}case 16:{var sock=getSocketFromFD(),message=SYSCALLS.get(),flags=SYSCALLS.get();var iov=HEAP32[message+8>>2];var num=HEAP32[message+12>>2];var addr,port;var name=HEAP32[message>>2];var namelen=HEAP32[message+4>>2];if(name){var info=__read_sockaddr(name,namelen);if(info.errno)return-info.errno;port=info.port;addr=DNS.lookup_addr(info.addr)||info.addr}var total=0;for(var i=0;i>2]}var view=new Uint8Array(total);var offset=0;for(var i=0;i>2];var iovlen=HEAP32[iov+(8*i+4)>>2];for(var j=0;j>0]}}return sock.sock_ops.sendmsg(sock,view,0,total,addr,port)}case 17:{var sock=getSocketFromFD(),message=SYSCALLS.get(),flags=SYSCALLS.get();var iov=HEAP32[message+8>>2];var num=HEAP32[message+12>>2];var total=0;for(var i=0;i>2]}var msg=sock.sock_ops.recvmsg(sock,total);if(!msg)return 0;var name=HEAP32[message>>2];if(name){var res=__write_sockaddr(name,sock.family,DNS.lookup_name(msg.addr),msg.port);assert(!res.errno)}var bytesRead=0;var bytesRemaining=msg.buffer.byteLength;for(var i=0;bytesRemaining>0&&i>2];var iovlen=HEAP32[iov+(8*i+4)>>2];if(!iovlen){continue}var length=Math.min(iovlen,bytesRemaining);var buf=msg.buffer.subarray(bytesRead,bytesRead+length);HEAPU8.set(buf,iovbase+bytesRead);bytesRead+=length;bytesRemaining-=length}return bytesRead}default:{return-52}}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_stat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+size)}}function embind_init_charCodes(){var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes}var embind_charCodes=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return function(){"use strict";return body.apply(this,arguments)}}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return this.name+": "+this.message}};return errorClass}var BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i>shift])},destructorFunction:null})}var emval_free_list=[];var emval_handle_array=[{},{value:undefined},{value:null},{value:true},{value:false}];function __emval_decref(handle){if(handle>4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i>2])}function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=emval_handle_array[handle].value;__emval_decref(handle);return rv},"toWireType":function(destructors,value){return __emval_register(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function craftInvokerFunction(humanName,argTypes,classType,cppInvokerFunc,cppTargetFunc){var argCount=argTypes.length;if(argCount<2){throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!")}var isClassMethodFunc=argTypes[1]!==null&&classType!==null;var needsDestructorStack=false;for(var i=1;i>2)+i])}return array}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function embind__requireFunction(signature,rawFunction){signature=readLatin1String(signature);function makeDynCaller(dynCall){var argCache=[rawFunction];return function(){argCache.length=arguments.length+1;for(var i=0;i>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=function(value){return value};if(minRange===0){var bitshift=32-8*size;fromWireType=function(value){return value<>>bitshift}}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(valuemaxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0},"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(i==length||HEAPU8[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+4+i]=charCode}}else{for(var i=0;i>2];var HEAP=getHeap();var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||HEAP[currentBytePtr>>shift]==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},"toWireType":function(destructors,value){if(!(typeof value==="string")){throwBindingError("Cannot pass non-string to C++ string type "+name)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}function requireRegisteredType(rawType,humanName){var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl}function __emval_lookupTypes(argCount,argTypes){var a=new Array(argCount);for(var i=0;i>2)+i],"parameter "+i)}return a}function requireHandle(handle){if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handle_array[handle].value}function __emval_call(handle,argCount,argTypes,argv){handle=requireHandle(handle);var types=__emval_lookupTypes(argCount,argTypes);var args=new Array(argCount);for(var i=0;i4){emval_handle_array[handle].refcount+=1}}function __emval_take_value(type,argv){type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](argv);return __emval_register(v)}function _exit(status){exit(status)}function __exit(a0){return _exit(a0)}function _abort(){abort()}var _emscripten_get_now;if(ENVIRONMENT_IS_NODE){_emscripten_get_now=function(){var t=process["hrtime"]();return t[0]*1e3+t[1]/1e6}}else if(typeof dateNow!=="undefined"){_emscripten_get_now=dateNow}else _emscripten_get_now=function(){return performance.now()};var _emscripten_get_now_is_monotonic=true;function _clock_gettime(clk_id,tp){var now;if(clk_id===0){now=Date.now()}else if((clk_id===1||clk_id===4)&&_emscripten_get_now_is_monotonic){now=_emscripten_get_now()}else{setErrNo(28);return-1}HEAP32[tp>>2]=now/1e3|0;HEAP32[tp+4>>2]=now%1e3*1e3*1e3|0;return 0}function _emscripten_get_sbrk_ptr(){return 1318384}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function _emscripten_get_heap_size(){return HEAPU8.length}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){console.error("emscripten_realloc_buffer: Attempted to grow heap from "+buffer.byteLength+" bytes to "+size+" bytes, but got error: "+e)}}function _emscripten_resize_heap(requestedSize){requestedSize=requestedSize>>>0;var oldSize=_emscripten_get_heap_size();assert(requestedSize>oldSize);var PAGE_MULTIPLE=65536;var maxHeapSize=2147483648;if(requestedSize>maxHeapSize){err("Cannot enlarge memory, asked to go up to "+requestedSize+" bytes, but the limit is "+maxHeapSize+" bytes!");return false}var minHeapSize=16777216;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(minHeapSize,requestedSize,overGrownHeapSize),PAGE_MULTIPLE));var t0=_emscripten_get_now();var replacement=emscripten_realloc_buffer(newSize);var t1=_emscripten_get_now();console.log("Heap resize call from "+oldSize+" to "+newSize+" took "+(t1-t0)+" msecs. Success: "+!!replacement);if(replacement){return true}}err("Failed to grow the heap from "+oldSize+" bytes to "+newSize+" bytes, not enough memory!");return false}var ENV={};function getExecutableName(){return thisProgram||"./this.program"}function getEnvStrings(){if(!getEnvStrings.strings){var lang=(typeof navigator==="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+"="+env[x])}getEnvStrings.strings=strings}return getEnvStrings.strings}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAP32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAP32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAP32[penviron_buf_size>>2]=bufSize;return 0}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_read(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doReadv(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var stream=SYSCALLS.getStreamFromFD(fd);var HIGH_OFFSET=4294967296;var offset=offset_high*HIGH_OFFSET+(offset_low>>>0);var DOUBLE_LIMIT=9007199254740992;if(offset<=-DOUBLE_LIMIT||offset>=DOUBLE_LIMIT){return-61}FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doWritev(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _ftime(p){var millis=Date.now();HEAP32[p>>2]=millis/1e3|0;HEAP16[p+4>>1]=millis%1e3;HEAP16[p+6>>1]=0;HEAP16[p+8>>1]=0;return 0}function _getTempRet0(){return getTempRet0()|0}function _gettimeofday(ptr){var now=Date.now();HEAP32[ptr>>2]=now/1e3|0;HEAP32[ptr+4>>2]=now%1e3*1e3|0;return 0}var ___tm_current=1318400;var ___tm_timezone=(stringToUTF8("GMT",1318448,4),1318448);function _gmtime_r(time,tmPtr){var date=new Date(HEAP32[time>>2]*1e3);HEAP32[tmPtr>>2]=date.getUTCSeconds();HEAP32[tmPtr+4>>2]=date.getUTCMinutes();HEAP32[tmPtr+8>>2]=date.getUTCHours();HEAP32[tmPtr+12>>2]=date.getUTCDate();HEAP32[tmPtr+16>>2]=date.getUTCMonth();HEAP32[tmPtr+20>>2]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getUTCDay();HEAP32[tmPtr+36>>2]=0;HEAP32[tmPtr+32>>2]=0;var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+40>>2]=___tm_timezone;return tmPtr}function _gmtime(time){return _gmtime_r(time,___tm_current)}function _llvm_eh_typeid_for(type){return type}function _tzset(){if(_tzset.called)return;_tzset.called=true;HEAP32[__get_timezone()>>2]=(new Date).getTimezoneOffset()*60;var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);HEAP32[__get_daylight()>>2]=Number(winter.getTimezoneOffset()!=summer.getTimezoneOffset());function extractZone(date){var match=date.toTimeString().match(/\(([A-Za-z ]+)\)$/);return match?match[1]:"GMT"}var winterName=extractZone(winter);var summerName=extractZone(summer);var winterNamePtr=allocateUTF8(winterName);var summerNamePtr=allocateUTF8(summerName);if(summer.getTimezoneOffset()>2]=winterNamePtr;HEAP32[__get_tzname()+4>>2]=summerNamePtr}else{HEAP32[__get_tzname()>>2]=summerNamePtr;HEAP32[__get_tzname()+4>>2]=winterNamePtr}}function _mktime(tmPtr){_tzset();var date=new Date(HEAP32[tmPtr+20>>2]+1900,HEAP32[tmPtr+16>>2],HEAP32[tmPtr+12>>2],HEAP32[tmPtr+8>>2],HEAP32[tmPtr+4>>2],HEAP32[tmPtr>>2],0);var dst=HEAP32[tmPtr+32>>2];var guessedOffset=date.getTimezoneOffset();var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dstOffset=Math.min(winterOffset,summerOffset);if(dst<0){HEAP32[tmPtr+32>>2]=Number(summerOffset!=winterOffset&&dstOffset==guessedOffset)}else if(dst>0!=(dstOffset==guessedOffset)){var nonDstOffset=Math.max(winterOffset,summerOffset);var trueOffset=dst>0?dstOffset:nonDstOffset;date.setTime(date.getTime()+(trueOffset-guessedOffset)*6e4)}HEAP32[tmPtr+24>>2]=date.getDay();var yday=(date.getTime()-start.getTime())/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;return date.getTime()/1e3|0}function _usleep(useconds){var start=_emscripten_get_now();while(_emscripten_get_now()-start>2];var nanoseconds=HEAP32[rqtp+4>>2];if(nanoseconds<0||nanoseconds>999999999||seconds<0){setErrNo(28);return-1}if(rmtp!==0){HEAP32[rmtp>>2]=0;HEAP32[rmtp+4>>2]=0}return _usleep(seconds*1e6+nanoseconds/1e3)}function _pthread_attr_destroy(attr){return 0}function _pthread_attr_getdetachstate(attr,detachstate){return 0}function _pthread_attr_init(attr){return 0}function _pthread_attr_setstacksize(){}function _pthread_condattr_destroy(){return 0}function _pthread_condattr_init(){return 0}function _pthread_condattr_setclock(){return 0}function _pthread_create(){return 6}function _pthread_detach(){}function _pthread_join(){}function _pthread_mutexattr_destroy(){}function _pthread_mutexattr_init(){}function _pthread_mutexattr_settype(){}function _pthread_sigmask(how,set,oldset){err("pthread_sigmask() is not supported: this is a no-op.");return 0}function _rx_seedheight(){err("missing function: rx_seedheight");abort(-1)}function _rx_slow_hash(){err("missing function: rx_slow_hash");abort(-1)}function _setTempRet0($i){setTempRet0($i|0)}function _sigfillset(set){HEAP32[set>>2]=-1>>>0;return 0}function __isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}function __arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum}var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=__isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value==="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}else{return thisDate.getFullYear()}}else{return thisDate.getFullYear()-1}}var EXPANSION_RULES_2={"%a":function(date){return WEEKDAYS[date.tm_wday].substring(0,3)},"%A":function(date){return WEEKDAYS[date.tm_wday]},"%b":function(date){return MONTHS[date.tm_mon].substring(0,3)},"%B":function(date){return MONTHS[date.tm_mon]},"%C":function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":function(date){return leadingNulls(date.tm_mday,2)},"%e":function(date){return leadingSomething(date.tm_mday,2," ")},"%g":function(date){return getWeekBasedYear(date).toString().substring(2)},"%G":function(date){return getWeekBasedYear(date)},"%H":function(date){return leadingNulls(date.tm_hour,2)},"%I":function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":function(date){return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900)?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,date.tm_mon-1),3)},"%m":function(date){return leadingNulls(date.tm_mon+1,2)},"%M":function(date){return leadingNulls(date.tm_min,2)},"%n":function(){return"\n"},"%p":function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}else{return"PM"}},"%S":function(date){return leadingNulls(date.tm_sec,2)},"%t":function(){return"\t"},"%u":function(date){return date.tm_wday||7},"%U":function(date){var janFirst=new Date(date.tm_year+1900,0,1);var firstSunday=janFirst.getDay()===0?janFirst:__addDays(janFirst,7-janFirst.getDay());var endDate=new Date(date.tm_year+1900,date.tm_mon,date.tm_mday);if(compareByDay(firstSunday,endDate)<0){var februaryFirstUntilEndMonth=__arraySum(__isLeapYear(endDate.getFullYear())?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,endDate.getMonth()-1)-31;var firstSundayUntilEndJanuary=31-firstSunday.getDate();var days=firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();return leadingNulls(Math.ceil(days/7),2)}return compareByDay(firstSunday,janFirst)===0?"01":"00"},"%V":function(date){var janFourthThisYear=new Date(date.tm_year+1900,0,4);var janFourthNextYear=new Date(date.tm_year+1901,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);var endDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);if(compareByDay(endDate,firstWeekStartThisYear)<0){return"53"}if(compareByDay(firstWeekStartNextYear,endDate)<=0){return"01"}var daysDifference;if(firstWeekStartThisYear.getFullYear()=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":function(date){return date.tm_zone},"%%":function(){return"%"}};for(var rule in EXPANSION_RULES_2){if(pattern.indexOf(rule)>=0){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}function _sysconf(name){switch(name){case 30:return 16384;case 85:var maxHeapSize=2147483648;return maxHeapSize/16384;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:case 79:return 200809;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1;case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32;case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1e3;case 89:return 700;case 71:return 256;case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:{if(typeof navigator==="object")return navigator["hardwareConcurrency"]||1;return 1}}setErrNo(28);return-1}function _time(ptr){var ret=Date.now()/1e3|0;if(ptr){HEAP32[ptr>>2]=ret}return ret}function _v4_generate_JIT_code(){err("missing function: v4_generate_JIT_code");abort(-1)}function _emscripten_set_main_loop_timing(mode,value){Browser.mainLoop.timingMode=mode;Browser.mainLoop.timingValue=value;if(!Browser.mainLoop.func){console.error("emscripten_set_main_loop_timing: Cannot set timing mode for main loop since a main loop does not exist! Call emscripten_set_main_loop first to set one up.");return 1}if(mode==0){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,Browser.mainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,timeUntilNextTick)};Browser.mainLoop.method="timeout"}else if(mode==1){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_rAF(){Browser.requestAnimationFrame(Browser.mainLoop.runner)};Browser.mainLoop.method="rAF"}else if(mode==2){if(typeof setImmediate==="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var Browser_setImmediate_messageHandler=function(event){if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",Browser_setImmediate_messageHandler,true);setImmediate=function Browser_emulated_setImmediate(func){setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){if(Module["setImmediates"]===undefined)Module["setImmediates"]=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setImmediate(){setImmediate(Browser.mainLoop.runner)};Browser.mainLoop.method="immediate"}return 0}function _emscripten_set_main_loop(func,fps,simulateInfiniteLoop,arg,noSetTiming){noExitRuntime=true;assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.");Browser.mainLoop.func=func;Browser.mainLoop.arg=arg;var browserIterationFunc;if(typeof arg!=="undefined"){browserIterationFunc=function(){Module["dynCall_vi"](func,arg)}}else{browserIterationFunc=function(){Module["dynCall_v"](func)}}var thisMainLoopId=Browser.mainLoop.currentlyRunningMainloop;Browser.mainLoop.runner=function Browser_mainLoop_runner(){if(ABORT)return;if(Browser.mainLoop.queue.length>0){var start=Date.now();var blocker=Browser.mainLoop.queue.shift();blocker.func(blocker.arg);if(Browser.mainLoop.remainingBlockers){var remaining=Browser.mainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){Browser.mainLoop.remainingBlockers=next}else{next=next+.5;Browser.mainLoop.remainingBlockers=(8*remaining+next)/9}}console.log('main loop blocker "'+blocker.name+'" took '+(Date.now()-start)+" ms");Browser.mainLoop.updateStatus();if(thisMainLoopId1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else if(Browser.mainLoop.timingMode==0){Browser.mainLoop.tickStartTime=_emscripten_get_now()}if(Browser.mainLoop.method==="timeout"&&Module.ctx){warnOnce("Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates!");Browser.mainLoop.method=""}Browser.mainLoop.runIter(browserIterationFunc);checkStackCookie();if(thisMainLoopId0)_emscripten_set_main_loop_timing(0,1e3/fps);else _emscripten_set_main_loop_timing(1,1);Browser.mainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}}var Browser={mainLoop:{scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null;Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var timingMode=Browser.mainLoop.timingMode;var timingValue=Browser.mainLoop.timingValue;var func=Browser.mainLoop.func;Browser.mainLoop.func=null;_emscripten_set_main_loop(func,0,false,Browser.mainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);Browser.mainLoop.scheduler()},updateStatus:function(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=Browser.mainLoop.remainingBlockers;var expected=Browser.mainLoop.expectedBlockers;if(remaining){if(remaining=6){var curr=leftchar>>leftbits-6&63;leftbits-=6;ret+=BASE[curr]}}if(leftbits==2){ret+=BASE[(leftchar&3)<<4];ret+=PAD+PAD}else if(leftbits==4){ret+=BASE[(leftchar&15)<<2];ret+=PAD}return ret}audio.src="data:audio/x-"+name.substr(-3)+";base64,"+encode64(byteArray);finish(audio)};audio.src=url;Browser.safeSetTimeout(function(){finish(audio)},1e4)}else{return fail()}};Module["preloadPlugins"].push(audioPlugin);function pointerLockChange(){Browser.pointerLock=document["pointerLockElement"]===Module["canvas"]||document["mozPointerLockElement"]===Module["canvas"]||document["webkitPointerLockElement"]===Module["canvas"]||document["msPointerLockElement"]===Module["canvas"]}var canvas=Module["canvas"];if(canvas){canvas.requestPointerLock=canvas["requestPointerLock"]||canvas["mozRequestPointerLock"]||canvas["webkitRequestPointerLock"]||canvas["msRequestPointerLock"]||function(){};canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||function(){};canvas.exitPointerLock=canvas.exitPointerLock.bind(document);document.addEventListener("pointerlockchange",pointerLockChange,false);document.addEventListener("mozpointerlockchange",pointerLockChange,false);document.addEventListener("webkitpointerlockchange",pointerLockChange,false);document.addEventListener("mspointerlockchange",pointerLockChange,false);if(Module["elementPointerLock"]){canvas.addEventListener("click",function(ev){if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},createContext:function(canvas,useWebGL,setInModule,webGLContextAttributes){if(useWebGL&&Module.ctx&&canvas==Module.canvas)return Module.ctx;var ctx;var contextHandle;if(useWebGL){var contextAttributes={antialias:false,alpha:false,majorVersion:1};if(webGLContextAttributes){for(var attribute in webGLContextAttributes){contextAttributes[attribute]=webGLContextAttributes[attribute]}}if(typeof GL!=="undefined"){contextHandle=GL.createContext(canvas,contextAttributes);if(contextHandle){ctx=GL.getContext(contextHandle).GLctx}}}else{ctx=canvas.getContext("2d")}if(!ctx)return null;if(setInModule){if(!useWebGL)assert(typeof GLctx==="undefined","cannot set in module if GLctx is used, but we are a non-GL context that would replace it");Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Module.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(function(callback){callback()});Browser.init()}return ctx},destroyContext:function(canvas,useWebGL,setInModule){},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen:function(lockPointer,resizeCanvas){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;if(typeof Browser.lockPointer==="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas==="undefined")Browser.resizeCanvas=false;var canvas=Module["canvas"];function fullscreenChange(){Browser.isFullscreen=false;var canvasContainer=canvas.parentNode;if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvasContainer){canvas.exitFullscreen=Browser.exitFullscreen;if(Browser.lockPointer)canvas.requestPointerLock();Browser.isFullscreen=true;if(Browser.resizeCanvas){Browser.setFullscreenCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}else{canvasContainer.parentNode.insertBefore(canvas,canvasContainer);canvasContainer.parentNode.removeChild(canvasContainer);if(Browser.resizeCanvas){Browser.setWindowedCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}if(Module["onFullScreen"])Module["onFullScreen"](Browser.isFullscreen);if(Module["onFullscreen"])Module["onFullscreen"](Browser.isFullscreen)}if(!Browser.fullscreenHandlersInstalled){Browser.fullscreenHandlersInstalled=true;document.addEventListener("fullscreenchange",fullscreenChange,false);document.addEventListener("mozfullscreenchange",fullscreenChange,false);document.addEventListener("webkitfullscreenchange",fullscreenChange,false);document.addEventListener("MSFullscreenChange",fullscreenChange,false)}var canvasContainer=document.createElement("div");canvas.parentNode.insertBefore(canvasContainer,canvas);canvasContainer.appendChild(canvas);canvasContainer.requestFullscreen=canvasContainer["requestFullscreen"]||canvasContainer["mozRequestFullScreen"]||canvasContainer["msRequestFullscreen"]||(canvasContainer["webkitRequestFullscreen"]?function(){canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"])}:null)||(canvasContainer["webkitRequestFullScreen"]?function(){canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"])}:null);canvasContainer.requestFullscreen()},requestFullScreen:function(){abort("Module.requestFullScreen has been replaced by Module.requestFullscreen (without a capital S)")},exitFullscreen:function(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||function(){};CFS.apply(document,[]);return true},nextRAF:0,fakeRequestAnimationFrame:function(func){var now=Date.now();if(Browser.nextRAF===0){Browser.nextRAF=now+1e3/60}else{while(now+2>=Browser.nextRAF){Browser.nextRAF+=1e3/60}}var delay=Math.max(Browser.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame:function(func){if(typeof requestAnimationFrame==="function"){requestAnimationFrame(func);return}var RAF=Browser.fakeRequestAnimationFrame;RAF(func)},safeCallback:function(func){return function(){if(!ABORT)return func.apply(null,arguments)}},allowAsyncCallbacks:true,queuedAsyncCallbacks:[],pauseAsyncCallbacks:function(){Browser.allowAsyncCallbacks=false},resumeAsyncCallbacks:function(){Browser.allowAsyncCallbacks=true;if(Browser.queuedAsyncCallbacks.length>0){var callbacks=Browser.queuedAsyncCallbacks;Browser.queuedAsyncCallbacks=[];callbacks.forEach(function(func){func()})}},safeRequestAnimationFrame:function(func){return Browser.requestAnimationFrame(function(){if(ABORT)return;if(Browser.allowAsyncCallbacks){func()}else{Browser.queuedAsyncCallbacks.push(func)}})},safeSetTimeout:function(func,timeout){noExitRuntime=true;return setTimeout(function(){if(ABORT)return;if(Browser.allowAsyncCallbacks){func()}else{Browser.queuedAsyncCallbacks.push(func)}},timeout)},safeSetInterval:function(func,timeout){noExitRuntime=true;return setInterval(function(){if(ABORT)return;if(Browser.allowAsyncCallbacks){func()}},timeout)},getMimetype:function(name){return{"jpg":"image/jpeg","jpeg":"image/jpeg","png":"image/png","bmp":"image/bmp","ogg":"audio/ogg","wav":"audio/wav","mp3":"audio/mpeg"}[name.substr(name.lastIndexOf(".")+1)]},getUserMedia:function(func){if(!window.getUserMedia){window.getUserMedia=navigator["getUserMedia"]||navigator["mozGetUserMedia"]}window.getUserMedia(func)},getMovementX:function(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY:function(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta:function(event){var delta=0;switch(event.type){case"DOMMouseScroll":delta=event.detail/3;break;case"mousewheel":delta=event.wheelDelta/120;break;case"wheel":delta=event.deltaY;switch(event.deltaMode){case 0:delta/=100;break;case 1:delta/=3;break;case 2:delta*=80;break;default:throw"unrecognized mouse wheel delta mode: "+event.deltaMode}break;default:throw"unrecognized mouse wheel event: "+event.type}return delta},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(event){if(Browser.pointerLock){if(event.type!="mousemove"&&"mozMovementX"in event){Browser.mouseMovementX=Browser.mouseMovementY=0}else{Browser.mouseMovementX=Browser.getMovementX(event);Browser.mouseMovementY=Browser.getMovementY(event)}if(typeof SDL!="undefined"){Browser.mouseX=SDL.mouseX+Browser.mouseMovementX;Browser.mouseY=SDL.mouseY+Browser.mouseMovementY}else{Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}}else{var rect=Module["canvas"].getBoundingClientRect();var cw=Module["canvas"].width;var ch=Module["canvas"].height;var scrollX=typeof window.scrollX!=="undefined"?window.scrollX:window.pageXOffset;var scrollY=typeof window.scrollY!=="undefined"?window.scrollY:window.pageYOffset;assert(typeof scrollX!=="undefined"&&typeof scrollY!=="undefined","Unable to retrieve scroll position, mouse positions likely broken.");if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var adjustedX=touch.pageX-(scrollX+rect.left);var adjustedY=touch.pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);var coords={x:adjustedX,y:adjustedY};if(event.type==="touchstart"){Browser.lastTouches[touch.identifier]=coords;Browser.touches[touch.identifier]=coords}else if(event.type==="touchend"||event.type==="touchmove"){var last=Browser.touches[touch.identifier];if(!last)last=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}var x=event.pageX-(scrollX+rect.left);var y=event.pageY-(scrollY+rect.top);x=x*(cw/rect.width);y=y*(ch/rect.height);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y}},asyncLoad:function(url,onload,onerror,noRunDep){var dep=!noRunDep?getUniqueRunDependency("al "+url):"";readAsync(url,function(arrayBuffer){assert(arrayBuffer,'Loading data file "'+url+'" failed (no arrayBuffer).');onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},function(event){if(onerror){onerror()}else{throw'Loading data file "'+url+'" failed.'}});if(dep)addRunDependency(dep)},resizeListeners:[],updateResizeListeners:function(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(function(listener){listener(canvas.width,canvas.height)})},setCanvasSize:function(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags|8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags&~8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions:function(canvas,wNative,hNative){if(wNative&&hNative){canvas.widthNative=wNative;canvas.heightNative=hNative}else{wNative=canvas.widthNative;hNative=canvas.heightNative}var w=wNative;var h=hNative;if(Module["forcedAspectRatio"]&&Module["forcedAspectRatio"]>0){if(w/h>2]=stack;HEAP32[ptr+4>>2]=stack+stackSize},setDataRewindFunc:function(ptr){var bottomOfCallStack=Asyncify.exportCallStack[0];var rewindId=Asyncify.getCallStackId(bottomOfCallStack);HEAP32[ptr+8>>2]=rewindId},getDataRewindFunc:function(ptr){var id=HEAP32[ptr+8>>2];var func=Asyncify.callStackIdToFunc[id];return func},handleSleep:function(startAsync){if(ABORT)return;noExitRuntime=true;if(Asyncify.state===Asyncify.State.Normal){var reachedCallback=false;var reachedAfterCallback=false;startAsync(function(handleSleepReturnValue){assert(!handleSleepReturnValue||typeof handleSleepReturnValue==="number");if(ABORT)return;Asyncify.handleSleepReturnValue=handleSleepReturnValue||0;reachedCallback=true;if(!reachedAfterCallback){return}assert(!Asyncify.exportCallStack.length,"Waking up (starting to rewind) must be done from JS, without compiled code on the stack.");Asyncify.state=Asyncify.State.Rewinding;runAndAbortIfError(function(){Module["_asyncify_start_rewind"](Asyncify.currData)});if(Browser.mainLoop.func){Browser.mainLoop.resume()}var start=Asyncify.getDataRewindFunc(Asyncify.currData);var asyncWasmReturnValue=start();if(!Asyncify.currData){var asyncFinalizers=Asyncify.asyncFinalizers;Asyncify.asyncFinalizers=[];asyncFinalizers.forEach(function(func){func(asyncWasmReturnValue)})}});reachedAfterCallback=true;if(!reachedCallback){Asyncify.state=Asyncify.State.Unwinding;Asyncify.currData=Asyncify.allocateData();runAndAbortIfError(function(){Module["_asyncify_start_unwind"](Asyncify.currData)});if(Browser.mainLoop.func){Browser.mainLoop.pause()}}}else if(Asyncify.state===Asyncify.State.Rewinding){Asyncify.state=Asyncify.State.Normal;runAndAbortIfError(Module["_asyncify_stop_rewind"]);_free(Asyncify.currData);Asyncify.currData=null;Asyncify.sleepCallbacks.forEach(function(func){func()})}else{abort("invalid state: "+Asyncify.state)}return Asyncify.handleSleepReturnValue},handleAsync:function(startAsync){return Asyncify.handleSleep(function(wakeUp){startAsync().then(wakeUp)})}};var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.staticInit();embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");InternalError=Module["InternalError"]=extendError(Error,"InternalError");init_emval();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");Module["requestFullscreen"]=function Module_requestFullscreen(lockPointer,resizeCanvas){Browser.requestFullscreen(lockPointer,resizeCanvas)};Module["requestFullScreen"]=function Module_requestFullScreen(){Browser.requestFullScreen()};Module["requestAnimationFrame"]=function Module_requestAnimationFrame(func){Browser.requestAnimationFrame(func)};Module["setCanvasSize"]=function Module_setCanvasSize(width,height,noUpdates){Browser.setCanvasSize(width,height,noUpdates)};Module["pauseMainLoop"]=function Module_pauseMainLoop(){Browser.mainLoop.pause()};Module["resumeMainLoop"]=function Module_resumeMainLoop(){Browser.mainLoop.resume()};Module["getUserMedia"]=function Module_getUserMedia(){Browser.getUserMedia()};Module["createContext"]=function Module_createContext(canvas,useWebGL,setInModule,webGLContextAttributes){return Browser.createContext(canvas,useWebGL,setInModule,webGLContextAttributes)};var ASSERTIONS=true;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}function intArrayToString(array){var ret=[];for(var i=0;i255){if(ASSERTIONS){assert(false,"Character code "+chr+" ("+String.fromCharCode(chr)+") at offset "+i+" not in 0x00-0xFF.")}chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}var asmLibraryArg={"BIO_ctrl":_BIO_ctrl,"BIO_ctrl_pending":_BIO_ctrl_pending,"BIO_free":_BIO_free,"BIO_new_bio_pair":_BIO_new_bio_pair,"BIO_new_mem_buf":_BIO_new_mem_buf,"BIO_read":_BIO_read,"BIO_write":_BIO_write,"CONF_modules_unload":_CONF_modules_unload,"CRYPTO_free":_CRYPTO_free,"ERR_clear_error":_ERR_clear_error,"ERR_get_error":_ERR_get_error,"ERR_reason_error_string":_ERR_reason_error_string,"PEM_read_bio":_PEM_read_bio,"PEM_write":_PEM_write,"SSL_CTX_ctrl":_SSL_CTX_ctrl,"SSL_CTX_free":_SSL_CTX_free,"SSL_CTX_get_default_passwd_cb_userdata":_SSL_CTX_get_default_passwd_cb_userdata,"SSL_CTX_get_ex_data":_SSL_CTX_get_ex_data,"SSL_CTX_new":_SSL_CTX_new,"SSL_CTX_set_default_passwd_cb_userdata":_SSL_CTX_set_default_passwd_cb_userdata,"SSL_CTX_set_ex_data":_SSL_CTX_set_ex_data,"SSL_CTX_set_options":_SSL_CTX_set_options,"SSL_ctrl":_SSL_ctrl,"SSL_free":_SSL_free,"SSL_get_error":_SSL_get_error,"SSL_get_ex_data":_SSL_get_ex_data,"SSL_get_shutdown":_SSL_get_shutdown,"SSL_new":_SSL_new,"SSL_read":_SSL_read,"SSL_set_bio":_SSL_set_bio,"SSL_set_ex_data":_SSL_set_ex_data,"SSL_shutdown":_SSL_shutdown,"SSL_write":_SSL_write,"TLS_client_method":_TLS_client_method,"TLS_method":_TLS_method,"TLS_server_method":_TLS_server_method,"_ZN2hw6trezor12register_allEv":__ZN2hw6trezor12register_allEv,"_ZN4epee9net_utils4http16http_client_auth13do_handle_401ERKNS1_18http_response_infoE":__ZN4epee9net_utils4http16http_client_auth13do_handle_401ERKNS1_18http_response_infoE,"_ZN4epee9net_utils4http16http_client_auth17do_get_auth_fieldEN5boost16basic_string_refIcNSt3__211char_traitsIcEEEES8_":__ZN4epee9net_utils4http16http_client_auth17do_get_auth_fieldEN5boost16basic_string_refIcNSt3__211char_traitsIcEEEES8_,"_ZN4epee9net_utils4http16http_client_authC1ENS1_5loginE":__ZN4epee9net_utils4http16http_client_authC1ENS1_5loginE,"_ZN5boost10filesystem6detail12current_pathEPNS_6system10error_codeE":__ZN5boost10filesystem6detail12current_pathEPNS_6system10error_codeE,"_ZN5boost10filesystem6detail18create_directoriesERKNS0_4pathEPNS_6system10error_codeE":__ZN5boost10filesystem6detail18create_directoriesERKNS0_4pathEPNS_6system10error_codeE,"_ZN5boost10filesystem6detail5spaceERKNS0_4pathEPNS_6system10error_codeE":__ZN5boost10filesystem6detail5spaceERKNS0_4pathEPNS_6system10error_codeE,"_ZN5boost10filesystem6detail6removeERKNS0_4pathEPNS_6system10error_codeE":__ZN5boost10filesystem6detail6removeERKNS0_4pathEPNS_6system10error_codeE,"_ZN5boost10filesystem6detail6statusERKNS0_4pathEPNS_6system10error_codeE":__ZN5boost10filesystem6detail6statusERKNS0_4pathEPNS_6system10error_codeE,"_ZN5boost10filesystem6detail9canonicalERKNS0_4pathES4_PNS_6system10error_codeE":__ZN5boost10filesystem6detail9canonicalERKNS0_4pathES4_PNS_6system10error_codeE,"_ZN5tools6Notify6notifyEPKcS2_z":__ZN5tools6Notify6notifyEPKcS2_z,"_ZN5tools9dns_utils25load_txt_records_from_dnsERNSt3__26vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEERKSA_":__ZN5tools9dns_utils25load_txt_records_from_dnsERNSt3__26vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEERKSA_,"_ZN5tools9dns_utils35get_account_address_as_str_from_urlERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERbNS1_8functionIFS7_S9_RKNS1_6vectorIS7_NS5_IS7_EEEEbEEE":__ZN5tools9dns_utils35get_account_address_as_str_from_urlERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERbNS1_8functionIFS7_S9_RKNS1_6vectorIS7_NS5_IS7_EEEEbEEE,"_ZNK10cryptonote10Blockchain29get_current_blockchain_heightEv":__ZNK10cryptonote10Blockchain29get_current_blockchain_heightEv,"_ZNK10cryptonote10Blockchain30get_pending_block_id_by_heightEy":__ZNK10cryptonote10Blockchain30get_pending_block_id_by_heightEy,"_ZNK3net5socks9connectorclERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RN5boost4asio20basic_waitable_timerINS2_6chrono12steady_clockENSC_11wait_traitsISF_EENSC_8executorEEE":__ZNK3net5socks9connectorclERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RN5boost4asio20basic_waitable_timerINS2_6chrono12steady_clockENSC_11wait_traitsISF_EENSC_8executorEEE,"_ZNK4epee9net_utils13ssl_options_t14create_contextEv":__ZNK4epee9net_utils13ssl_options_t14create_contextEv,"_ZNK4epee9net_utils13ssl_options_t9handshakeERN5boost4asio3ssl6streamINS3_19basic_stream_socketINS3_2ip3tcpENS3_8executorEEEEENS4_11stream_base14handshake_typeERKNSt3__212basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEENSF_6chrono8durationIxNSF_5ratioILx1ELx1000EEEEE":__ZNK4epee9net_utils13ssl_options_t9handshakeERN5boost4asio3ssl6streamINS3_19basic_stream_socketINS3_2ip3tcpENS3_8executorEEEEENS4_11stream_base14handshake_typeERKNSt3__212basic_stringIcNSF_11char_traitsIcEENSF_9allocatorIcEEEENSF_6chrono8durationIxNSF_5ratioILx1ELx1000EEEEE,"_ZNK4epee9net_utils14direct_connectclERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RN5boost4asio20basic_waitable_timerINS2_6chrono12steady_clockENSC_11wait_traitsISF_EENSC_8executorEEE":__ZNK4epee9net_utils14direct_connectclERKNSt3__212basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEESA_RN5boost4asio20basic_waitable_timerINS2_6chrono12steady_clockENSC_11wait_traitsISF_EENSC_8executorEEE,"_ZNK5boost10filesystem4path11parent_pathEv":__ZNK5boost10filesystem4path11parent_pathEv,"__assert_fail":___assert_fail,"__cxa_allocate_exception":___cxa_allocate_exception,"__cxa_atexit":___cxa_atexit,"__cxa_begin_catch":___cxa_begin_catch,"__cxa_decrement_exception_refcount":___cxa_decrement_exception_refcount,"__cxa_end_catch":___cxa_end_catch,"__cxa_find_matching_catch_2":___cxa_find_matching_catch_2,"__cxa_find_matching_catch_3":___cxa_find_matching_catch_3,"__cxa_free_exception":___cxa_free_exception,"__cxa_increment_exception_refcount":___cxa_increment_exception_refcount,"__cxa_rethrow":___cxa_rethrow,"__cxa_rethrow_primary_exception":___cxa_rethrow_primary_exception,"__cxa_throw":___cxa_throw,"__cxa_uncaught_exceptions":___cxa_uncaught_exceptions,"__handle_stack_overflow":___handle_stack_overflow,"__map_file":___map_file,"__resumeException":___resumeException,"__sys__newselect":___sys__newselect,"__sys_fcntl64":___sys_fcntl64,"__sys_fdatasync":___sys_fdatasync,"__sys_ftruncate64":___sys_ftruncate64,"__sys_getpid":___sys_getpid,"__sys_ioctl":___sys_ioctl,"__sys_madvise1":___sys_madvise1,"__sys_mkdir":___sys_mkdir,"__sys_mlock":___sys_mlock,"__sys_mmap2":___sys_mmap2,"__sys_msync":___sys_msync,"__sys_munlock":___sys_munlock,"__sys_munmap":___sys_munmap,"__sys_open":___sys_open,"__sys_pause":___sys_pause,"__sys_pipe":___sys_pipe,"__sys_pwrite64":___sys_pwrite64,"__sys_read":___sys_read,"__sys_rename":___sys_rename,"__sys_socketcall":___sys_socketcall,"__sys_stat64":___sys_stat64,"_embind_register_bool":__embind_register_bool,"_embind_register_emval":__embind_register_emval,"_embind_register_float":__embind_register_float,"_embind_register_function":__embind_register_function,"_embind_register_integer":__embind_register_integer,"_embind_register_memory_view":__embind_register_memory_view,"_embind_register_std_string":__embind_register_std_string,"_embind_register_std_wstring":__embind_register_std_wstring,"_embind_register_void":__embind_register_void,"_emval_call":__emval_call,"_emval_decref":__emval_decref,"_emval_equals":__emval_equals,"_emval_incref":__emval_incref,"_emval_take_value":__emval_take_value,"_exit":__exit,"abort":_abort,"atexit":_atexit,"clock_gettime":_clock_gettime,"emscripten_get_sbrk_ptr":_emscripten_get_sbrk_ptr,"emscripten_memcpy_big":_emscripten_memcpy_big,"emscripten_resize_heap":_emscripten_resize_heap,"environ_get":_environ_get,"environ_sizes_get":_environ_sizes_get,"exit":_exit,"fd_close":_fd_close,"fd_read":_fd_read,"fd_seek":_fd_seek,"fd_write":_fd_write,"ftime":_ftime,"getTempRet0":_getTempRet0,"gettimeofday":_gettimeofday,"gmtime":_gmtime,"gmtime_r":_gmtime_r,"invoke_diii":invoke_diii,"invoke_fiii":invoke_fiii,"invoke_i":invoke_i,"invoke_ii":invoke_ii,"invoke_iii":invoke_iii,"invoke_iiii":invoke_iiii,"invoke_iiiii":invoke_iiiii,"invoke_iiiiid":invoke_iiiiid,"invoke_iiiiii":invoke_iiiiii,"invoke_iiiiiii":invoke_iiiiiii,"invoke_iiiiiiii":invoke_iiiiiiii,"invoke_iiiiiiiiiii":invoke_iiiiiiiiiii,"invoke_iiiiiiiiiiii":invoke_iiiiiiiiiiii,"invoke_iiiiiiiiiiiii":invoke_iiiiiiiiiiiii,"invoke_iiiiiiiijii":invoke_iiiiiiiijii,"invoke_iiiiiijii":invoke_iiiiiijii,"invoke_iiiiij":invoke_iiiiij,"invoke_ji":invoke_ji,"invoke_jii":invoke_jii,"invoke_jiii":invoke_jiii,"invoke_jiiii":invoke_jiiii,"invoke_v":invoke_v,"invoke_vi":invoke_vi,"invoke_vii":invoke_vii,"invoke_viii":invoke_viii,"invoke_viiii":invoke_viiii,"invoke_viiiii":invoke_viiiii,"invoke_viiiiiii":invoke_viiiiiii,"invoke_viiiiiiiiii":invoke_viiiiiiiiii,"invoke_viiiiiiiiiiiiiii":invoke_viiiiiiiiiiiiiii,"invoke_viiiji":invoke_viiiji,"invoke_viij":invoke_viij,"invoke_viijii":invoke_viijii,"invoke_viijiii":invoke_viijiii,"js_send_binary_request":js_send_binary_request,"js_send_json_request":js_send_json_request,"llvm_eh_typeid_for":_llvm_eh_typeid_for,"memory":wasmMemory,"mktime":_mktime,"nanosleep":_nanosleep,"pthread_attr_destroy":_pthread_attr_destroy,"pthread_attr_getdetachstate":_pthread_attr_getdetachstate,"pthread_attr_init":_pthread_attr_init,"pthread_attr_setstacksize":_pthread_attr_setstacksize,"pthread_condattr_destroy":_pthread_condattr_destroy,"pthread_condattr_init":_pthread_condattr_init,"pthread_condattr_setclock":_pthread_condattr_setclock,"pthread_create":_pthread_create,"pthread_detach":_pthread_detach,"pthread_join":_pthread_join,"pthread_mutexattr_destroy":_pthread_mutexattr_destroy,"pthread_mutexattr_init":_pthread_mutexattr_init,"pthread_mutexattr_settype":_pthread_mutexattr_settype,"pthread_sigmask":_pthread_sigmask,"rx_seedheight":_rx_seedheight,"rx_slow_hash":_rx_slow_hash,"setTempRet0":_setTempRet0,"sigfillset":_sigfillset,"strftime_l":_strftime_l,"sysconf":_sysconf,"table":wasmTable,"time":_time,"v4_generate_JIT_code":_v4_generate_JIT_code};Asyncify.instrumentWasmImports(asmLibraryArg);var asm=createWasm();var ___wasm_call_ctors=Module["___wasm_call_ctors"]=createExportWrapper("__wasm_call_ctors");var _free=Module["_free"]=createExportWrapper("free");var _memset=Module["_memset"]=createExportWrapper("memset");var __ZN5boost13serialization16singleton_module8get_lockEv=Module["__ZN5boost13serialization16singleton_module8get_lockEv"]=createExportWrapper("_ZN5boost13serialization16singleton_module8get_lockEv");var ___errno_location=Module["___errno_location"]=createExportWrapper("__errno_location");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet210pending_txEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet210pending_txEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet210pending_txEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote11transactionEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote11transactionEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote11transactionEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote8txin_genEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote8txin_genEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote8txin_genEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote14txin_to_scriptEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote14txin_to_scriptEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote14txin_to_scriptEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto4hashEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto4hashEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto4hashEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote18txin_to_scripthashEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote18txin_to_scripthashEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote18txin_to_scripthashEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote15txout_to_scriptEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote15txout_to_scriptEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote15txout_to_scriptEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto10public_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto10public_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto10public_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote11txin_to_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote11txin_to_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote11txin_to_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9key_imageEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9key_imageEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9key_imageEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote6tx_outEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote6tx_outEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote6tx_outEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote19txout_to_scripthashEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote19txout_to_scripthashEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote19txout_to_scripthashEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote12txout_to_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote12txout_to_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote12txout_to_keyEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9signatureEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9signatureEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9signatureEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct10rctSigBaseEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct10rctSigBaseEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct10rctSigBaseEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct3keyEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct3keyEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct3keyEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct9ecdhTupleEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct9ecdhTupleEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct9ecdhTupleEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct14rctSigPrunableEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct14rctSigPrunableEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct14rctSigPrunableEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct8rangeSigEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct8rangeSigEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct8rangeSigEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct7boroSigEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct7boroSigEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct7boroSigEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct11BulletproofEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct11BulletproofEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct11BulletproofEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct5mgSigEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct5mgSigEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct5mgSigEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote20tx_destination_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote20tx_destination_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote20tx_destination_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote22account_public_addressEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote22account_public_addressEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote22account_public_addressEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24listImNS4_9allocatorImEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24listImNS4_9allocatorImEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24listImNS4_9allocatorImEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet220tx_construction_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet220tx_construction_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet220tx_construction_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote15tx_source_entryENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote15tx_source_entryENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN10cryptonote15tx_source_entryENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote15tx_source_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote15tx_source_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote15tx_source_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIyN3rct5ctkeyEEENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIyN3rct5ctkeyEEENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIyN3rct5ctkeyEEENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIyN3rct5ctkeyEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIyN3rct5ctkeyEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIyN3rct5ctkeyEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct5ctkeyEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct5ctkeyEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct5ctkeyEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct14multisig_kLRkiEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct14multisig_kLRkiEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct14multisig_kLRkiEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct9RCTConfigEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct9RCTConfigEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct9RCTConfigEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorImNS4_9allocatorImEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorImNS4_9allocatorImEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorImNS4_9allocatorImEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet212multisig_sigENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet212multisig_sigENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet212multisig_sigENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet212multisig_sigEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet212multisig_sigEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet212multisig_sigEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct6rctSigEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct6rctSigEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct6rctSigEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN3rct3keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN3rct3keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN3rct3keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct12multisig_outEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct12multisig_outEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3rct12multisig_outEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet210pending_txEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet210pending_txEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet210pending_txEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote11transactionEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote11transactionEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote11transactionEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote8txin_genEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote8txin_genEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote8txin_genEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote14txin_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote14txin_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote14txin_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto4hashEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto4hashEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto4hashEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote18txin_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote18txin_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote18txin_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote15txout_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote15txout_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote15txout_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto10public_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto10public_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto10public_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote11txin_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote11txin_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote11txin_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9key_imageEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9key_imageEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9key_imageEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote6tx_outEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote6tx_outEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote6tx_outEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote19txout_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote19txout_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote19txout_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote12txout_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote12txout_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote12txout_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9signatureEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9signatureEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9signatureEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct10rctSigBaseEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct10rctSigBaseEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct10rctSigBaseEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct3keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct3keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct3keyEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct9ecdhTupleEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct9ecdhTupleEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct9ecdhTupleEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct14rctSigPrunableEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct14rctSigPrunableEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct14rctSigPrunableEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct8rangeSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct8rangeSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct8rangeSigEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct7boroSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct7boroSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct7boroSigEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct11BulletproofEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct11BulletproofEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct11BulletproofEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct5mgSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct5mgSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct5mgSigEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote20tx_destination_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote20tx_destination_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote20tx_destination_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote22account_public_addressEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote22account_public_addressEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote22account_public_addressEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24listImNS4_9allocatorImEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24listImNS4_9allocatorImEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24listImNS4_9allocatorImEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet220tx_construction_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet220tx_construction_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet220tx_construction_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote15tx_source_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote15tx_source_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN10cryptonote15tx_source_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote15tx_source_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote15tx_source_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote15tx_source_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIyN3rct5ctkeyEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIyN3rct5ctkeyEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIyN3rct5ctkeyEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIyN3rct5ctkeyEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIyN3rct5ctkeyEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIyN3rct5ctkeyEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct5ctkeyEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct5ctkeyEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct5ctkeyEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct14multisig_kLRkiEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct14multisig_kLRkiEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct14multisig_kLRkiEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct9RCTConfigEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct9RCTConfigEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct9RCTConfigEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorImNS4_9allocatorImEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorImNS4_9allocatorImEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorImNS4_9allocatorImEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet212multisig_sigENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet212multisig_sigENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet212multisig_sigENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet212multisig_sigEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet212multisig_sigEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet212multisig_sigEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct6rctSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct6rctSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct6rctSigEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN3rct3keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN3rct3keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN3rct3keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct12multisig_outEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct12multisig_outEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3rct12multisig_outEE16load_object_dataERNS1_14basic_iarchiveEPvj");var _malloc=Module["_malloc"]=createExportWrapper("malloc");var _htons=Module["_htons"]=createExportWrapper("htons");var _htonl=Module["_htonl"]=createExportWrapper("htonl");var _fflush=Module["_fflush"]=createExportWrapper("fflush");var _ntohs=Module["_ntohs"]=createExportWrapper("ntohs");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet2EE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet2EE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet2EE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools9hashchainEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools9hashchainEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools9hashchainEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet216transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet216transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet216transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote18transaction_prefixEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote18transaction_prefixEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote18transaction_prefixEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote16subaddress_indexEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote16subaddress_indexEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN10cryptonote16subaddress_indexEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIyN6crypto4hashEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIyN6crypto4hashEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIyN6crypto4hashEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet226confirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet226confirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet226confirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet216address_book_rowEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet216address_book_rowEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet216address_book_rowEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto5hash8EE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto5hash8EE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto5hash8EE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet220pool_payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet220pool_payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet220pool_payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet2EE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet2EE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet2EE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto4hashEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto4hashEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto4hashEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools9hashchainEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools9hashchainEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools9hashchainEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet216transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet216transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet216transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote11transactionEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote11transactionEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote11transactionEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS_7variantIN10cryptonote8txin_genEJNS7_14txin_to_scriptENS7_18txin_to_scripthashENS7_11txin_to_keyEEEENS4_9allocatorISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENS_7variantIN10cryptonote8txin_genEJNS5_14txin_to_scriptENS5_18txin_to_scripthashENS5_11txin_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote8txin_genEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote8txin_genEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote8txin_genEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote14txin_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote14txin_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote14txin_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote18txin_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote18txin_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote18txin_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote15txout_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote15txout_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote15txout_to_scriptEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto10public_keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto10public_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto10public_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto10public_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote11txin_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote11txin_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote11txin_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIyNS4_9allocatorIyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN10cryptonote6tx_outENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote6tx_outEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote6tx_outEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote6tx_outEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENS_7variantIN10cryptonote15txout_to_scriptEJNS5_19txout_to_scripthashENS5_12txout_to_keyEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote19txout_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote19txout_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote19txout_to_scripthashEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote12txout_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote12txout_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote12txout_to_keyEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIhNS4_9allocatorIhEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_IN6crypto9signatureENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto9signatureENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto9signatureEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto9signatureEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto9signatureEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct10rctSigBaseEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct10rctSigBaseEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct10rctSigBaseEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct9ecdhTupleENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct9ecdhTupleEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct9ecdhTupleEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct9ecdhTupleEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct14rctSigPrunableEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct14rctSigPrunableEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct14rctSigPrunableEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct8rangeSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct8rangeSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct8rangeSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct8rangeSigEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct7boroSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct7boroSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct7boroSigEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct3keyEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct3keyEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct3keyEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct11BulletproofENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct11BulletproofEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct11BulletproofEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct11BulletproofEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct5mgSigENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct5mgSigEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct5mgSigEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN3rct5mgSigEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_IN3rct3keyENS4_9allocatorIS7_EEEENS8_ISA_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN3rct3keyENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote18transaction_prefixEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote18transaction_prefixEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote18transaction_prefixEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto9key_imageEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto9key_imageEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto9key_imageEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote16subaddress_indexEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote16subaddress_indexEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote16subaddress_indexEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet213multisig_infoEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet213multisig_infoEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet213multisig_infoEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet213multisig_info2LREE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet213multisig_info2LREE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet213multisig_info2LREE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIyN6crypto4hashEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIyN6crypto4hashEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIyN6crypto4hashEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote22account_public_addressEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote22account_public_addressEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote22account_public_addressEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN10cryptonote20tx_destination_entryENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote20tx_destination_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote20tx_destination_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN10cryptonote20tx_destination_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__23setIjNS4_4lessIjEENS4_9allocatorIjEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet215payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet215payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet215payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet226confirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet226confirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet226confirmed_transfer_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet216address_book_rowEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet216address_book_rowEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet216address_book_rowEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto5hash8EE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto5hash8EE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN6crypto5hash8EE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__26vectorIN4epee7mlockedIN5tools8scrubbedIN6crypto9ec_scalarEEEEENS4_9allocatorISD_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet220pool_payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet220pool_payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveEN5tools7wallet220pool_payment_detailsEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet2EE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet2EE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet2EE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto4hashENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools9hashchainEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools9hashchainEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools9hashchainEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__25dequeIN6crypto4hashENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet216transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet216transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet216transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote18transaction_prefixEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote18transaction_prefixEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote18transaction_prefixEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote16subaddress_indexEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote16subaddress_indexEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN10cryptonote16subaddress_indexEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIyN6crypto4hashEEENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIyN6crypto4hashEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIyN6crypto4hashEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIyN6crypto4hashEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto9key_imageEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet228unconfirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet228unconfirmed_transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_4pairIN6crypto9key_imageENS5_IyNS4_9allocatorIyEEEEEENS9_ISC_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIN6crypto9key_imageENS4_6vectorIyNS4_9allocatorIyEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215payment_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215payment_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215payment_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SE_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet226confirmed_transfer_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet226confirmed_transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet226confirmed_transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet226confirmed_transfer_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashENS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSB_INS4_4pairIKS7_SD_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashEN5tools7wallet215payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyEmNS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_mEEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet216address_book_rowENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet216address_book_rowEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet216address_book_rowEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet216address_book_rowEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto5hash8EE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto5hash8EE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto5hash8EE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_setIN6crypto4hashENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyEN10cryptonote16subaddress_indexENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN10cryptonote16subaddress_indexEN6crypto10public_keyENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS5_INS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEENS9_ISD_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEENS9_ISB_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto4hashENS4_6vectorIN4epee7mlockedIN5tools8scrubbedINS6_9ec_scalarEEEEENS4_9allocatorISF_EEEENS4_4hashIS7_EENS4_8equal_toIS7_EENSG_INS4_4pairIKS7_SI_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4hashISB_EENS4_8equal_toISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__218unordered_multimapIN6crypto4hashEN5tools7wallet220pool_payment_detailsENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_SA_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet220pool_payment_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet220pool_payment_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet220pool_payment_detailsEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairINS4_3mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESC_NS4_4lessISC_EENSA_INS5_IKSC_SC_EEEEEENS4_6vectorISC_NSA_ISC_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__23mapINS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_NS4_4lessISB_EENS9_INS4_4pairIKSB_SB_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairIKNS4_12basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEESB_EEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9key_imageENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215unsigned_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215unsigned_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215unsigned_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet220tx_construction_dataENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet220tx_construction_dataENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet220tx_construction_dataENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215unsigned_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215unsigned_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215unsigned_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet220tx_construction_dataENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet220tx_construction_dataENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet220tx_construction_dataENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213signed_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213signed_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213signed_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet210pending_txENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet210pending_txENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet210pending_txENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213signed_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213signed_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213signed_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet210pending_txENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet210pending_txENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet210pending_txENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN6crypto9key_imageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215multisig_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215multisig_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet215multisig_tx_setEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215multisig_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215multisig_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet215multisig_tx_setEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet219reserve_proof_entryENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet219reserve_proof_entryENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet219reserve_proof_entryENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet219reserve_proof_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet219reserve_proof_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet219reserve_proof_entryEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9signatureENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9signatureENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9signatureENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet219reserve_proof_entryENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet219reserve_proof_entryENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet219reserve_proof_entryENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet219reserve_proof_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet219reserve_proof_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet219reserve_proof_entryEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9signatureENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9signatureENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__213unordered_mapIN6crypto10public_keyENS6_9signatureENS4_4hashIS7_EENS4_8equal_toIS7_EENS4_9allocatorINS4_4pairIKS7_S8_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_15binary_iarchiveENSt3__24pairImNS4_6vectorIN5tools7wallet216transfer_detailsENS4_9allocatorIS9_EEEEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213multisig_infoEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213multisig_infoEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213multisig_infoEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213multisig_info2LREE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213multisig_info2LREE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN5tools7wallet213multisig_info2LREE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_infoENS4_9allocatorIS8_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213multisig_infoEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213multisig_infoEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213multisig_infoEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN5tools7wallet213multisig_info2LRENS4_9allocatorIS9_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213multisig_info2LREE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213multisig_info2LREE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN5tools7wallet213multisig_info2LREE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3mms17authorized_signerENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3mms17authorized_signerENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3mms17authorized_signerENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms17authorized_signerEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms17authorized_signerEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms17authorized_signerEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3mms17authorized_signerENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3mms17authorized_signerENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3mms17authorized_signerENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms17authorized_signerEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms17authorized_signerEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms17authorized_signerEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms16auto_config_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms16auto_config_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms16auto_config_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms16auto_config_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms16auto_config_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms16auto_config_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms13message_storeEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms13message_storeEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms13message_storeEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3mms7messageENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3mms7messageENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveENSt3__26vectorIN3mms7messageENS4_9allocatorIS7_EEEEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms7messageEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms7messageEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms7messageEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms9file_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms9file_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN3mms9file_dataEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9chacha_ivEE16save_object_dataERNS1_14basic_oarchiveEPKv=Module["__ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9chacha_ivEE16save_object_dataERNS1_14basic_oarchiveEPKv"]=createExportWrapper("_ZNK5boost7archive6detail11oserializerINS0_24portable_binary_oarchiveEN6crypto9chacha_ivEE16save_object_dataERNS1_14basic_oarchiveEPKv");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms9file_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms9file_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms9file_dataEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9chacha_ivEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9chacha_ivEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN6crypto9chacha_ivEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms13message_storeEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms13message_storeEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms13message_storeEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3mms7messageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3mms7messageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveENSt3__26vectorIN3mms7messageENS4_9allocatorIS7_EEEEE16load_object_dataERNS1_14basic_iarchiveEPvj");var __ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms7messageEE16load_object_dataERNS1_14basic_iarchiveEPvj=Module["__ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms7messageEE16load_object_dataERNS1_14basic_iarchiveEPvj"]=createExportWrapper("_ZNK5boost7archive6detail11iserializerINS0_24portable_binary_iarchiveEN3mms7messageEE16load_object_dataERNS1_14basic_iarchiveEPvj");var ___getTypeName=Module["___getTypeName"]=createExportWrapper("__getTypeName");var ___embind_register_native_and_builtin_types=Module["___embind_register_native_and_builtin_types"]=createExportWrapper("__embind_register_native_and_builtin_types");var __get_tzname=Module["__get_tzname"]=createExportWrapper("_get_tzname");var __get_daylight=Module["__get_daylight"]=createExportWrapper("_get_daylight");var __get_timezone=Module["__get_timezone"]=createExportWrapper("_get_timezone");var _setThrew=Module["_setThrew"]=createExportWrapper("setThrew");var stackSave=Module["stackSave"]=createExportWrapper("stackSave");var stackRestore=Module["stackRestore"]=createExportWrapper("stackRestore");var stackAlloc=Module["stackAlloc"]=createExportWrapper("stackAlloc");var __ZSt18uncaught_exceptionv=Module["__ZSt18uncaught_exceptionv"]=createExportWrapper("_ZSt18uncaught_exceptionv");var ___cxa_can_catch=Module["___cxa_can_catch"]=createExportWrapper("__cxa_can_catch");var ___cxa_is_pointer_type=Module["___cxa_is_pointer_type"]=createExportWrapper("__cxa_is_pointer_type");var _memalign=Module["_memalign"]=createExportWrapper("memalign");var _emscripten_main_thread_process_queued_calls=Module["_emscripten_main_thread_process_queued_calls"]=createExportWrapper("emscripten_main_thread_process_queued_calls");var dynCall_v=Module["dynCall_v"]=createExportWrapper("dynCall_v");var dynCall_vi=Module["dynCall_vi"]=createExportWrapper("dynCall_vi");var dynCall_vii=Module["dynCall_vii"]=createExportWrapper("dynCall_vii");var dynCall_viii=Module["dynCall_viii"]=createExportWrapper("dynCall_viii");var dynCall_viiii=Module["dynCall_viiii"]=createExportWrapper("dynCall_viiii");var dynCall_viiiii=Module["dynCall_viiiii"]=createExportWrapper("dynCall_viiiii");var dynCall_viiiiiii=Module["dynCall_viiiiiii"]=createExportWrapper("dynCall_viiiiiii");var dynCall_viiiiiiiiii=Module["dynCall_viiiiiiiiii"]=createExportWrapper("dynCall_viiiiiiiiii");var dynCall_viiiiiiiiiiiiiii=Module["dynCall_viiiiiiiiiiiiiii"]=createExportWrapper("dynCall_viiiiiiiiiiiiiii");var dynCall_viiiji=Module["dynCall_viiiji"]=createExportWrapper("dynCall_viiiji");var dynCall_viij=Module["dynCall_viij"]=createExportWrapper("dynCall_viij");var dynCall_viijii=Module["dynCall_viijii"]=createExportWrapper("dynCall_viijii");var dynCall_viijiii=Module["dynCall_viijiii"]=createExportWrapper("dynCall_viijiii");var dynCall_i=Module["dynCall_i"]=createExportWrapper("dynCall_i");var dynCall_ii=Module["dynCall_ii"]=createExportWrapper("dynCall_ii");var dynCall_iii=Module["dynCall_iii"]=createExportWrapper("dynCall_iii");var dynCall_iiii=Module["dynCall_iiii"]=createExportWrapper("dynCall_iiii");var dynCall_iiiii=Module["dynCall_iiiii"]=createExportWrapper("dynCall_iiiii");var dynCall_iiiiii=Module["dynCall_iiiiii"]=createExportWrapper("dynCall_iiiiii");var dynCall_iiiiiii=Module["dynCall_iiiiiii"]=createExportWrapper("dynCall_iiiiiii");var dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=createExportWrapper("dynCall_iiiiiiii");var dynCall_iiiiiiiiiii=Module["dynCall_iiiiiiiiiii"]=createExportWrapper("dynCall_iiiiiiiiiii");var dynCall_iiiiiiiiiiii=Module["dynCall_iiiiiiiiiiii"]=createExportWrapper("dynCall_iiiiiiiiiiii");var dynCall_iiiiiiiiiiiii=Module["dynCall_iiiiiiiiiiiii"]=createExportWrapper("dynCall_iiiiiiiiiiiii");var dynCall_iiiiiiiijii=Module["dynCall_iiiiiiiijii"]=createExportWrapper("dynCall_iiiiiiiijii");var dynCall_iiiiiijii=Module["dynCall_iiiiiijii"]=createExportWrapper("dynCall_iiiiiijii");var dynCall_iiiiij=Module["dynCall_iiiiij"]=createExportWrapper("dynCall_iiiiij");var dynCall_iiiiid=Module["dynCall_iiiiid"]=createExportWrapper("dynCall_iiiiid");var dynCall_ji=Module["dynCall_ji"]=createExportWrapper("dynCall_ji");var dynCall_jii=Module["dynCall_jii"]=createExportWrapper("dynCall_jii");var dynCall_jiii=Module["dynCall_jiii"]=createExportWrapper("dynCall_jiii");var dynCall_jiiii=Module["dynCall_jiiii"]=createExportWrapper("dynCall_jiiii");var dynCall_fiii=Module["dynCall_fiii"]=createExportWrapper("dynCall_fiii");var dynCall_diii=Module["dynCall_diii"]=createExportWrapper("dynCall_diii");var ___set_stack_limit=Module["___set_stack_limit"]=createExportWrapper("__set_stack_limit");var dynCall_iij=Module["dynCall_iij"]=createExportWrapper("dynCall_iij");var dynCall_iiiiijii=Module["dynCall_iiiiijii"]=createExportWrapper("dynCall_iiiiijii");var dynCall_iiijiii=Module["dynCall_iiijiii"]=createExportWrapper("dynCall_iiijiii");var dynCall_iiiijii=Module["dynCall_iiiijii"]=createExportWrapper("dynCall_iiiijii");var dynCall_vij=Module["dynCall_vij"]=createExportWrapper("dynCall_vij");var dynCall_viiji=Module["dynCall_viiji"]=createExportWrapper("dynCall_viiji");var dynCall_viiiiii=Module["dynCall_viiiiii"]=createExportWrapper("dynCall_viiiiii");var dynCall_vijiiii=Module["dynCall_vijiiii"]=createExportWrapper("dynCall_vijiiii");var dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=createExportWrapper("dynCall_iiiiiiiii");var dynCall_vijjjdi=Module["dynCall_vijjjdi"]=createExportWrapper("dynCall_vijjjdi");var dynCall_vijj=Module["dynCall_vijj"]=createExportWrapper("dynCall_vijj");var dynCall_viji=Module["dynCall_viji"]=createExportWrapper("dynCall_viji");var dynCall_vijiijiij=Module["dynCall_vijiijiij"]=createExportWrapper("dynCall_vijiijiij");var dynCall_vijiiji=Module["dynCall_vijiiji"]=createExportWrapper("dynCall_vijiiji");var dynCall_vijiijii=Module["dynCall_vijiijii"]=createExportWrapper("dynCall_vijiijii");var dynCall_vijii=Module["dynCall_vijii"]=createExportWrapper("dynCall_vijii");var dynCall_vijij=Module["dynCall_vijij"]=createExportWrapper("dynCall_vijij");var dynCall_viiiiiiii=Module["dynCall_viiiiiiii"]=createExportWrapper("dynCall_viiiiiiii");var dynCall_viiiiiiiii=Module["dynCall_viiiiiiiii"]=createExportWrapper("dynCall_viiiiiiiii");var dynCall_viiiiiiiiiiii=Module["dynCall_viiiiiiiiiiii"]=createExportWrapper("dynCall_viiiiiiiiiiii");var dynCall_viiiiiiiiiii=Module["dynCall_viiiiiiiiiii"]=createExportWrapper("dynCall_viiiiiiiiiii");var dynCall_viiiiiiiiiiiii=Module["dynCall_viiiiiiiiiiiii"]=createExportWrapper("dynCall_viiiiiiiiiiiii");var dynCall_iiiij=Module["dynCall_iiiij"]=createExportWrapper("dynCall_iiiij");var dynCall_iiiiiiiiiiiiii=Module["dynCall_iiiiiiiiiiiiii"]=createExportWrapper("dynCall_iiiiiiiiiiiiii");var dynCall_jiji=Module["dynCall_jiji"]=createExportWrapper("dynCall_jiji");var dynCall_iidiiii=Module["dynCall_iidiiii"]=createExportWrapper("dynCall_iidiiii");var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=createExportWrapper("dynCall_iiiiijj");var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=createExportWrapper("dynCall_iiiiiijj");var __growWasmMemory=Module["__growWasmMemory"]=createExportWrapper("__growWasmMemory");var _asyncify_start_unwind=Module["_asyncify_start_unwind"]=createExportWrapper("asyncify_start_unwind");var _asyncify_stop_unwind=Module["_asyncify_stop_unwind"]=createExportWrapper("asyncify_stop_unwind");var _asyncify_start_rewind=Module["_asyncify_start_rewind"]=createExportWrapper("asyncify_start_rewind");var _asyncify_stop_rewind=Module["_asyncify_stop_rewind"]=createExportWrapper("asyncify_stop_rewind");function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return dynCall_iiii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return dynCall_iii(index,a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{dynCall_vi(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_v(index){var sp=stackSave();try{dynCall_v(index)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_vii(index,a1,a2){var sp=stackSave();try{dynCall_vii(index,a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_ii(index,a1){var sp=stackSave();try{return dynCall_ii(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return dynCall_iiiii(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return dynCall_iiiiiii(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viii(index,a1,a2,a3){var sp=stackSave();try{dynCall_viii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return dynCall_iiiiii(index,a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiii(index,a1,a2,a3,a4){var sp=stackSave();try{dynCall_viiii(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{dynCall_viiiii(index,a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_i(index){var sp=stackSave();try{return dynCall_i(index)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiid(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return dynCall_iiiiid(index,a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{return dynCall_iiiiiiii(index,a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{return dynCall_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12){var sp=stackSave();try{return dynCall_iiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_fiii(index,a1,a2,a3){var sp=stackSave();try{return dynCall_fiii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_diii(index,a1,a2,a3){var sp=stackSave();try{return dynCall_diii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{dynCall_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11){var sp=stackSave();try{return dynCall_iiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{dynCall_viiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15){var sp=stackSave();try{dynCall_viiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viijiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{dynCall_viijiii(index,a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiijii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9){var sp=stackSave();try{return dynCall_iiiiiijii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiijii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11){var sp=stackSave();try{return dynCall_iiiiiiiijii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_jiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return dynCall_jiiii(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viij(index,a1,a2,a3,a4){var sp=stackSave();try{dynCall_viij(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_ji(index,a1){var sp=stackSave();try{return dynCall_ji(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_jii(index,a1,a2){var sp=stackSave();try{return dynCall_jii(index,a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_jiii(index,a1,a2,a3){var sp=stackSave();try{return dynCall_jiii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiji(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{dynCall_viiiji(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viijii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{dynCall_viijii(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiij(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return dynCall_iiiiij(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}if(!Object.getOwnPropertyDescriptor(Module,"intArrayFromString"))Module["intArrayFromString"]=function(){abort("'intArrayFromString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["intArrayToString"]=intArrayToString;if(!Object.getOwnPropertyDescriptor(Module,"ccall"))Module["ccall"]=function(){abort("'ccall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"cwrap"))Module["cwrap"]=function(){abort("'cwrap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"setValue"))Module["setValue"]=function(){abort("'setValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getValue"))Module["getValue"]=function(){abort("'getValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"allocate"))Module["allocate"]=function(){abort("'allocate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getMemory"))Module["getMemory"]=function(){abort("'getMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"UTF8ArrayToString"))Module["UTF8ArrayToString"]=function(){abort("'UTF8ArrayToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["UTF8ToString"]=UTF8ToString;if(!Object.getOwnPropertyDescriptor(Module,"stringToUTF8Array"))Module["stringToUTF8Array"]=function(){abort("'stringToUTF8Array' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["stringToUTF8"]=stringToUTF8;Module["lengthBytesUTF8"]=lengthBytesUTF8;if(!Object.getOwnPropertyDescriptor(Module,"stackTrace"))Module["stackTrace"]=function(){abort("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"addOnPreRun"))Module["addOnPreRun"]=function(){abort("'addOnPreRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"addOnInit"))Module["addOnInit"]=function(){abort("'addOnInit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"addOnPreMain"))Module["addOnPreMain"]=function(){abort("'addOnPreMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"addOnExit"))Module["addOnExit"]=function(){abort("'addOnExit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"addOnPostRun"))Module["addOnPostRun"]=function(){abort("'addOnPostRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeStringToMemory"))Module["writeStringToMemory"]=function(){abort("'writeStringToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeArrayToMemory"))Module["writeArrayToMemory"]=function(){abort("'writeArrayToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeAsciiToMemory"))Module["writeAsciiToMemory"]=function(){abort("'writeAsciiToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"addRunDependency"))Module["addRunDependency"]=function(){abort("'addRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"removeRunDependency"))Module["removeRunDependency"]=function(){abort("'removeRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createFolder"))Module["FS_createFolder"]=function(){abort("'FS_createFolder' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createPath"))Module["FS_createPath"]=function(){abort("'FS_createPath' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createDataFile"))Module["FS_createDataFile"]=function(){abort("'FS_createDataFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createPreloadedFile"))Module["FS_createPreloadedFile"]=function(){abort("'FS_createPreloadedFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createLazyFile"))Module["FS_createLazyFile"]=function(){abort("'FS_createLazyFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createLink"))Module["FS_createLink"]=function(){abort("'FS_createLink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createDevice"))Module["FS_createDevice"]=function(){abort("'FS_createDevice' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_unlink"))Module["FS_unlink"]=function(){abort("'FS_unlink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"dynamicAlloc"))Module["dynamicAlloc"]=function(){abort("'dynamicAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"loadDynamicLibrary"))Module["loadDynamicLibrary"]=function(){abort("'loadDynamicLibrary' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"loadWebAssemblyModule"))Module["loadWebAssemblyModule"]=function(){abort("'loadWebAssemblyModule' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getLEB"))Module["getLEB"]=function(){abort("'getLEB' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getFunctionTables"))Module["getFunctionTables"]=function(){abort("'getFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"alignFunctionTables"))Module["alignFunctionTables"]=function(){abort("'alignFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"registerFunctions"))Module["registerFunctions"]=function(){abort("'registerFunctions' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["addFunction"]=addFunction;if(!Object.getOwnPropertyDescriptor(Module,"removeFunction"))Module["removeFunction"]=function(){abort("'removeFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getFuncWrapper"))Module["getFuncWrapper"]=function(){abort("'getFuncWrapper' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"prettyPrint"))Module["prettyPrint"]=function(){abort("'prettyPrint' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["makeBigInt"]=makeBigInt;if(!Object.getOwnPropertyDescriptor(Module,"dynCall"))Module["dynCall"]=function(){abort("'dynCall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getCompilerSetting"))Module["getCompilerSetting"]=function(){abort("'getCompilerSetting' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"print"))Module["print"]=function(){abort("'print' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"printErr"))Module["printErr"]=function(){abort("'printErr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["getTempRet0"]=getTempRet0;if(!Object.getOwnPropertyDescriptor(Module,"setTempRet0"))Module["setTempRet0"]=function(){abort("'setTempRet0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"callMain"))Module["callMain"]=function(){abort("'callMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"abort"))Module["abort"]=function(){abort("'abort' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stringToNewUTF8"))Module["stringToNewUTF8"]=function(){abort("'stringToNewUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emscripten_realloc_buffer"))Module["emscripten_realloc_buffer"]=function(){abort("'emscripten_realloc_buffer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ENV"))Module["ENV"]=function(){abort("'ENV' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ERRNO_CODES"))Module["ERRNO_CODES"]=function(){abort("'ERRNO_CODES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ERRNO_MESSAGES"))Module["ERRNO_MESSAGES"]=function(){abort("'ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"setErrNo"))Module["setErrNo"]=function(){abort("'setErrNo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"DNS"))Module["DNS"]=function(){abort("'DNS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"GAI_ERRNO_MESSAGES"))Module["GAI_ERRNO_MESSAGES"]=function(){abort("'GAI_ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"Protocols"))Module["Protocols"]=function(){abort("'Protocols' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"Sockets"))Module["Sockets"]=function(){abort("'Sockets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"traverseStack"))Module["traverseStack"]=function(){abort("'traverseStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"UNWIND_CACHE"))Module["UNWIND_CACHE"]=function(){abort("'UNWIND_CACHE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"withBuiltinMalloc"))Module["withBuiltinMalloc"]=function(){abort("'withBuiltinMalloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"readAsmConstArgsArray"))Module["readAsmConstArgsArray"]=function(){abort("'readAsmConstArgsArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"readAsmConstArgs"))Module["readAsmConstArgs"]=function(){abort("'readAsmConstArgs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"jstoi_q"))Module["jstoi_q"]=function(){abort("'jstoi_q' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"jstoi_s"))Module["jstoi_s"]=function(){abort("'jstoi_s' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getExecutableName"))Module["getExecutableName"]=function(){abort("'getExecutableName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"listenOnce"))Module["listenOnce"]=function(){abort("'listenOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"autoResumeAudioContext"))Module["autoResumeAudioContext"]=function(){abort("'autoResumeAudioContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"abortStackOverflow"))Module["abortStackOverflow"]=function(){abort("'abortStackOverflow' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"reallyNegative"))Module["reallyNegative"]=function(){abort("'reallyNegative' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"formatString"))Module["formatString"]=function(){abort("'formatString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"PATH"))Module["PATH"]=function(){abort("'PATH' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"PATH_FS"))Module["PATH_FS"]=function(){abort("'PATH_FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SYSCALLS"))Module["SYSCALLS"]=function(){abort("'SYSCALLS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"syscallMmap2"))Module["syscallMmap2"]=function(){abort("'syscallMmap2' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"syscallMunmap"))Module["syscallMunmap"]=function(){abort("'syscallMunmap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"JSEvents"))Module["JSEvents"]=function(){abort("'JSEvents' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"specialHTMLTargets"))Module["specialHTMLTargets"]=function(){abort("'specialHTMLTargets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"maybeCStringToJsString"))Module["maybeCStringToJsString"]=function(){abort("'maybeCStringToJsString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"findEventTarget"))Module["findEventTarget"]=function(){abort("'findEventTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"findCanvasEventTarget"))Module["findCanvasEventTarget"]=function(){abort("'findCanvasEventTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"polyfillSetImmediate"))Module["polyfillSetImmediate"]=function(){abort("'polyfillSetImmediate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"demangle"))Module["demangle"]=function(){abort("'demangle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"demangleAll"))Module["demangleAll"]=function(){abort("'demangleAll' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"jsStackTrace"))Module["jsStackTrace"]=function(){abort("'jsStackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stackTrace"))Module["stackTrace"]=function(){abort("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getEnvStrings"))Module["getEnvStrings"]=function(){abort("'getEnvStrings' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"checkWasiClock"))Module["checkWasiClock"]=function(){abort("'checkWasiClock' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeI53ToI64"))Module["writeI53ToI64"]=function(){abort("'writeI53ToI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeI53ToI64Clamped"))Module["writeI53ToI64Clamped"]=function(){abort("'writeI53ToI64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeI53ToI64Signaling"))Module["writeI53ToI64Signaling"]=function(){abort("'writeI53ToI64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeI53ToU64Clamped"))Module["writeI53ToU64Clamped"]=function(){abort("'writeI53ToU64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeI53ToU64Signaling"))Module["writeI53ToU64Signaling"]=function(){abort("'writeI53ToU64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"readI53FromI64"))Module["readI53FromI64"]=function(){abort("'readI53FromI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"readI53FromU64"))Module["readI53FromU64"]=function(){abort("'readI53FromU64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"convertI32PairToI53"))Module["convertI32PairToI53"]=function(){abort("'convertI32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"convertU32PairToI53"))Module["convertU32PairToI53"]=function(){abort("'convertU32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"exceptionLast"))Module["exceptionLast"]=function(){abort("'exceptionLast' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"exceptionCaught"))Module["exceptionCaught"]=function(){abort("'exceptionCaught' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ExceptionInfoAttrs"))Module["ExceptionInfoAttrs"]=function(){abort("'ExceptionInfoAttrs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ExceptionInfo"))Module["ExceptionInfo"]=function(){abort("'ExceptionInfo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"CatchInfo"))Module["CatchInfo"]=function(){abort("'CatchInfo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"exception_addRef"))Module["exception_addRef"]=function(){abort("'exception_addRef' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"exception_decRef"))Module["exception_decRef"]=function(){abort("'exception_decRef' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"Browser"))Module["Browser"]=function(){abort("'Browser' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"FS"))Module["FS"]=function(){abort("'FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"MEMFS"))Module["MEMFS"]=function(){abort("'MEMFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"TTY"))Module["TTY"]=function(){abort("'TTY' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"PIPEFS"))Module["PIPEFS"]=function(){abort("'PIPEFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SOCKFS"))Module["SOCKFS"]=function(){abort("'SOCKFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"tempFixedLengthArray"))Module["tempFixedLengthArray"]=function(){abort("'tempFixedLengthArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"miniTempWebGLFloatBuffers"))Module["miniTempWebGLFloatBuffers"]=function(){abort("'miniTempWebGLFloatBuffers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"heapObjectForWebGLType"))Module["heapObjectForWebGLType"]=function(){abort("'heapObjectForWebGLType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"heapAccessShiftForWebGLHeap"))Module["heapAccessShiftForWebGLHeap"]=function(){abort("'heapAccessShiftForWebGLHeap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"GL"))Module["GL"]=function(){abort("'GL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emscriptenWebGLGet"))Module["emscriptenWebGLGet"]=function(){abort("'emscriptenWebGLGet' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"computeUnpackAlignedImageSize"))Module["computeUnpackAlignedImageSize"]=function(){abort("'computeUnpackAlignedImageSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emscriptenWebGLGetTexPixelData"))Module["emscriptenWebGLGetTexPixelData"]=function(){abort("'emscriptenWebGLGetTexPixelData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emscriptenWebGLGetUniform"))Module["emscriptenWebGLGetUniform"]=function(){abort("'emscriptenWebGLGetUniform' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emscriptenWebGLGetVertexAttrib"))Module["emscriptenWebGLGetVertexAttrib"]=function(){abort("'emscriptenWebGLGetVertexAttrib' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeGLArray"))Module["writeGLArray"]=function(){abort("'writeGLArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"AL"))Module["AL"]=function(){abort("'AL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SDL_unicode"))Module["SDL_unicode"]=function(){abort("'SDL_unicode' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SDL_ttfContext"))Module["SDL_ttfContext"]=function(){abort("'SDL_ttfContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SDL_audio"))Module["SDL_audio"]=function(){abort("'SDL_audio' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SDL"))Module["SDL"]=function(){abort("'SDL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SDL_gfx"))Module["SDL_gfx"]=function(){abort("'SDL_gfx' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"GLUT"))Module["GLUT"]=function(){abort("'GLUT' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"EGL"))Module["EGL"]=function(){abort("'EGL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"GLFW_Window"))Module["GLFW_Window"]=function(){abort("'GLFW_Window' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"GLFW"))Module["GLFW"]=function(){abort("'GLFW' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"GLEW"))Module["GLEW"]=function(){abort("'GLEW' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"IDBStore"))Module["IDBStore"]=function(){abort("'IDBStore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"runAndAbortIfError"))Module["runAndAbortIfError"]=function(){abort("'runAndAbortIfError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"Asyncify"))Module["Asyncify"]=function(){abort("'Asyncify' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"Fibers"))Module["Fibers"]=function(){abort("'Fibers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emval_handle_array"))Module["emval_handle_array"]=function(){abort("'emval_handle_array' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emval_free_list"))Module["emval_free_list"]=function(){abort("'emval_free_list' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emval_symbols"))Module["emval_symbols"]=function(){abort("'emval_symbols' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"init_emval"))Module["init_emval"]=function(){abort("'init_emval' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"count_emval_handles"))Module["count_emval_handles"]=function(){abort("'count_emval_handles' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"get_first_emval"))Module["get_first_emval"]=function(){abort("'get_first_emval' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getStringOrSymbol"))Module["getStringOrSymbol"]=function(){abort("'getStringOrSymbol' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"requireHandle"))Module["requireHandle"]=function(){abort("'requireHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emval_newers"))Module["emval_newers"]=function(){abort("'emval_newers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"craftEmvalAllocator"))Module["craftEmvalAllocator"]=function(){abort("'craftEmvalAllocator' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emval_get_global"))Module["emval_get_global"]=function(){abort("'emval_get_global' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emval_methodCallers"))Module["emval_methodCallers"]=function(){abort("'emval_methodCallers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"InternalError"))Module["InternalError"]=function(){abort("'InternalError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"BindingError"))Module["BindingError"]=function(){abort("'BindingError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"UnboundTypeError"))Module["UnboundTypeError"]=function(){abort("'UnboundTypeError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"PureVirtualError"))Module["PureVirtualError"]=function(){abort("'PureVirtualError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"init_embind"))Module["init_embind"]=function(){abort("'init_embind' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"throwInternalError"))Module["throwInternalError"]=function(){abort("'throwInternalError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"throwBindingError"))Module["throwBindingError"]=function(){abort("'throwBindingError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"throwUnboundTypeError"))Module["throwUnboundTypeError"]=function(){abort("'throwUnboundTypeError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ensureOverloadTable"))Module["ensureOverloadTable"]=function(){abort("'ensureOverloadTable' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"exposePublicSymbol"))Module["exposePublicSymbol"]=function(){abort("'exposePublicSymbol' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"replacePublicSymbol"))Module["replacePublicSymbol"]=function(){abort("'replacePublicSymbol' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"extendError"))Module["extendError"]=function(){abort("'extendError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"createNamedFunction"))Module["createNamedFunction"]=function(){abort("'createNamedFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"registeredInstances"))Module["registeredInstances"]=function(){abort("'registeredInstances' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getBasestPointer"))Module["getBasestPointer"]=function(){abort("'getBasestPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"registerInheritedInstance"))Module["registerInheritedInstance"]=function(){abort("'registerInheritedInstance' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"unregisterInheritedInstance"))Module["unregisterInheritedInstance"]=function(){abort("'unregisterInheritedInstance' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getInheritedInstance"))Module["getInheritedInstance"]=function(){abort("'getInheritedInstance' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getInheritedInstanceCount"))Module["getInheritedInstanceCount"]=function(){abort("'getInheritedInstanceCount' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getLiveInheritedInstances"))Module["getLiveInheritedInstances"]=function(){abort("'getLiveInheritedInstances' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"registeredTypes"))Module["registeredTypes"]=function(){abort("'registeredTypes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"awaitingDependencies"))Module["awaitingDependencies"]=function(){abort("'awaitingDependencies' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"typeDependencies"))Module["typeDependencies"]=function(){abort("'typeDependencies' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"registeredPointers"))Module["registeredPointers"]=function(){abort("'registeredPointers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"registerType"))Module["registerType"]=function(){abort("'registerType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"whenDependentTypesAreResolved"))Module["whenDependentTypesAreResolved"]=function(){abort("'whenDependentTypesAreResolved' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"embind_charCodes"))Module["embind_charCodes"]=function(){abort("'embind_charCodes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"embind_init_charCodes"))Module["embind_init_charCodes"]=function(){abort("'embind_init_charCodes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"readLatin1String"))Module["readLatin1String"]=function(){abort("'readLatin1String' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getTypeName"))Module["getTypeName"]=function(){abort("'getTypeName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"heap32VectorToArray"))Module["heap32VectorToArray"]=function(){abort("'heap32VectorToArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"requireRegisteredType"))Module["requireRegisteredType"]=function(){abort("'requireRegisteredType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getShiftFromSize"))Module["getShiftFromSize"]=function(){abort("'getShiftFromSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"integerReadValueFromPointer"))Module["integerReadValueFromPointer"]=function(){abort("'integerReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"enumReadValueFromPointer"))Module["enumReadValueFromPointer"]=function(){abort("'enumReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"floatReadValueFromPointer"))Module["floatReadValueFromPointer"]=function(){abort("'floatReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"simpleReadValueFromPointer"))Module["simpleReadValueFromPointer"]=function(){abort("'simpleReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"runDestructors"))Module["runDestructors"]=function(){abort("'runDestructors' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"new_"))Module["new_"]=function(){abort("'new_' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"craftInvokerFunction"))Module["craftInvokerFunction"]=function(){abort("'craftInvokerFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"embind__requireFunction"))Module["embind__requireFunction"]=function(){abort("'embind__requireFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"tupleRegistrations"))Module["tupleRegistrations"]=function(){abort("'tupleRegistrations' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"structRegistrations"))Module["structRegistrations"]=function(){abort("'structRegistrations' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"genericPointerToWireType"))Module["genericPointerToWireType"]=function(){abort("'genericPointerToWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"constNoSmartPtrRawPointerToWireType"))Module["constNoSmartPtrRawPointerToWireType"]=function(){abort("'constNoSmartPtrRawPointerToWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"nonConstNoSmartPtrRawPointerToWireType"))Module["nonConstNoSmartPtrRawPointerToWireType"]=function(){abort("'nonConstNoSmartPtrRawPointerToWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"init_RegisteredPointer"))Module["init_RegisteredPointer"]=function(){abort("'init_RegisteredPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"RegisteredPointer"))Module["RegisteredPointer"]=function(){abort("'RegisteredPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"RegisteredPointer_getPointee"))Module["RegisteredPointer_getPointee"]=function(){abort("'RegisteredPointer_getPointee' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"RegisteredPointer_destructor"))Module["RegisteredPointer_destructor"]=function(){abort("'RegisteredPointer_destructor' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"RegisteredPointer_deleteObject"))Module["RegisteredPointer_deleteObject"]=function(){abort("'RegisteredPointer_deleteObject' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"RegisteredPointer_fromWireType"))Module["RegisteredPointer_fromWireType"]=function(){abort("'RegisteredPointer_fromWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"runDestructor"))Module["runDestructor"]=function(){abort("'runDestructor' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"releaseClassHandle"))Module["releaseClassHandle"]=function(){abort("'releaseClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"finalizationGroup"))Module["finalizationGroup"]=function(){abort("'finalizationGroup' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"detachFinalizer_deps"))Module["detachFinalizer_deps"]=function(){abort("'detachFinalizer_deps' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"detachFinalizer"))Module["detachFinalizer"]=function(){abort("'detachFinalizer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"attachFinalizer"))Module["attachFinalizer"]=function(){abort("'attachFinalizer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"makeClassHandle"))Module["makeClassHandle"]=function(){abort("'makeClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"init_ClassHandle"))Module["init_ClassHandle"]=function(){abort("'init_ClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ClassHandle"))Module["ClassHandle"]=function(){abort("'ClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ClassHandle_isAliasOf"))Module["ClassHandle_isAliasOf"]=function(){abort("'ClassHandle_isAliasOf' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"throwInstanceAlreadyDeleted"))Module["throwInstanceAlreadyDeleted"]=function(){abort("'throwInstanceAlreadyDeleted' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ClassHandle_clone"))Module["ClassHandle_clone"]=function(){abort("'ClassHandle_clone' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ClassHandle_delete"))Module["ClassHandle_delete"]=function(){abort("'ClassHandle_delete' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"deletionQueue"))Module["deletionQueue"]=function(){abort("'deletionQueue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ClassHandle_isDeleted"))Module["ClassHandle_isDeleted"]=function(){abort("'ClassHandle_isDeleted' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ClassHandle_deleteLater"))Module["ClassHandle_deleteLater"]=function(){abort("'ClassHandle_deleteLater' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"flushPendingDeletes"))Module["flushPendingDeletes"]=function(){abort("'flushPendingDeletes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"delayFunction"))Module["delayFunction"]=function(){abort("'delayFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"setDelayFunction"))Module["setDelayFunction"]=function(){abort("'setDelayFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"RegisteredClass"))Module["RegisteredClass"]=function(){abort("'RegisteredClass' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"shallowCopyInternalPointer"))Module["shallowCopyInternalPointer"]=function(){abort("'shallowCopyInternalPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"downcastPointer"))Module["downcastPointer"]=function(){abort("'downcastPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"upcastPointer"))Module["upcastPointer"]=function(){abort("'upcastPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"validateThis"))Module["validateThis"]=function(){abort("'validateThis' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"char_0"))Module["char_0"]=function(){abort("'char_0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"char_9"))Module["char_9"]=function(){abort("'char_9' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"makeLegalFunctionName"))Module["makeLegalFunctionName"]=function(){abort("'makeLegalFunctionName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"warnOnce"))Module["warnOnce"]=function(){abort("'warnOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stackSave"))Module["stackSave"]=function(){abort("'stackSave' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stackRestore"))Module["stackRestore"]=function(){abort("'stackRestore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stackAlloc"))Module["stackAlloc"]=function(){abort("'stackAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"AsciiToString"))Module["AsciiToString"]=function(){abort("'AsciiToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stringToAscii"))Module["stringToAscii"]=function(){abort("'stringToAscii' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"UTF16ToString"))Module["UTF16ToString"]=function(){abort("'UTF16ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stringToUTF16"))Module["stringToUTF16"]=function(){abort("'stringToUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"lengthBytesUTF16"))Module["lengthBytesUTF16"]=function(){abort("'lengthBytesUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"UTF32ToString"))Module["UTF32ToString"]=function(){abort("'UTF32ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stringToUTF32"))Module["stringToUTF32"]=function(){abort("'stringToUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"lengthBytesUTF32"))Module["lengthBytesUTF32"]=function(){abort("'lengthBytesUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"allocateUTF8"))Module["allocateUTF8"]=function(){abort("'allocateUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"allocateUTF8OnStack"))Module["allocateUTF8OnStack"]=function(){abort("'allocateUTF8OnStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["writeStackCookie"]=writeStackCookie;Module["checkStackCookie"]=checkStackCookie;if(!Object.getOwnPropertyDescriptor(Module,"ALLOC_NORMAL"))Object.defineProperty(Module,"ALLOC_NORMAL",{configurable:true,get:function(){abort("'ALLOC_NORMAL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}});if(!Object.getOwnPropertyDescriptor(Module,"ALLOC_STACK"))Object.defineProperty(Module,"ALLOC_STACK",{configurable:true,get:function(){abort("'ALLOC_STACK' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}});if(!Object.getOwnPropertyDescriptor(Module,"ALLOC_DYNAMIC"))Object.defineProperty(Module,"ALLOC_DYNAMIC",{configurable:true,get:function(){abort("'ALLOC_DYNAMIC' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}});if(!Object.getOwnPropertyDescriptor(Module,"ALLOC_NONE"))Object.defineProperty(Module,"ALLOC_NONE",{configurable:true,get:function(){abort("'ALLOC_NONE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}});var calledRun;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(args){args=args||arguments_;if(runDependencies>0){return}writeStackCookie();preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();assert(!Module["_main"],'compiled without a main, but one is present. if you added it from JS, use Module["onRuntimeInitialized"]');postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}checkStackCookie()}Module["run"]=run;function checkUnflushedContent(){var print=out;var printErr=err;var has=false;out=err=function(x){has=true};try{var flush=Module["_fflush"];if(flush)flush(0);["stdout","stderr"].forEach(function(name){var info=FS.analyzePath("/dev/"+name);if(!info)return;var stream=info.object;var rdev=stream.rdev;var tty=TTY.ttys[rdev];if(tty&&tty.output&&tty.output.length){has=true}})}catch(e){}out=print;err=printErr;if(has){warnOnce("stdio streams had content in them that was not flushed. you should set EXIT_RUNTIME to 1 (see the FAQ), or make sure to emit a newline when you printf etc.")}}function exit(status,implicit){checkUnflushedContent();if(implicit&&noExitRuntime&&status===0){return}if(noExitRuntime){if(!implicit){var msg="program exited (with status: "+status+"), but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)";readyPromiseReject(msg);err(msg)}}else{ABORT=true;EXITSTATUS=status;exitRuntime();if(Module["onExit"])Module["onExit"](status)}quit_(status,new ExitStatus(status))}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}noExitRuntime=true;run(); - - - return monero_javascript.ready -} -); -})(); -if (typeof exports === 'object' && typeof module === 'object') - module.exports = monero_javascript; - else if (typeof define === 'function' && define['amd']) - define([], function() { return monero_javascript; }); - else if (typeof exports === 'object') - exports["monero_javascript"] = monero_javascript; - \ No newline at end of file diff --git a/dist/monero_core.wasm b/dist/monero_core.wasm deleted file mode 100644 index 8ce76b25a..000000000 Binary files a/dist/monero_core.wasm and /dev/null differ diff --git a/dist/monero_core_keys.js b/dist/monero_core_keys.js deleted file mode 100644 index 0911d5a03..000000000 --- a/dist/monero_core_keys.js +++ /dev/null @@ -1,22 +0,0 @@ - -var monero_javascript = (function() { - var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; - if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; - return ( -function(monero_javascript) { - monero_javascript = monero_javascript || {}; - -var Module=typeof monero_javascript!=="undefined"?monero_javascript:{};var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise(function(resolve,reject){readyPromiseResolve=resolve;readyPromiseReject=reject});if(!Object.getOwnPropertyDescriptor(Module["ready"],"_main")){Object.defineProperty(Module["ready"],"_main",{configurable:true,get:function(){abort("You are getting _main on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_main",{configurable:true,set:function(){abort("You are setting _main on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_malloc")){Object.defineProperty(Module["ready"],"_malloc",{configurable:true,get:function(){abort("You are getting _malloc on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_malloc",{configurable:true,set:function(){abort("You are setting _malloc on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_free")){Object.defineProperty(Module["ready"],"_free",{configurable:true,get:function(){abort("You are getting _free on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_free",{configurable:true,set:function(){abort("You are setting _free on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_stackSave")){Object.defineProperty(Module["ready"],"_stackSave",{configurable:true,get:function(){abort("You are getting _stackSave on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_stackSave",{configurable:true,set:function(){abort("You are setting _stackSave on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_stackRestore")){Object.defineProperty(Module["ready"],"_stackRestore",{configurable:true,get:function(){abort("You are getting _stackRestore on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_stackRestore",{configurable:true,set:function(){abort("You are setting _stackRestore on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_stackAlloc")){Object.defineProperty(Module["ready"],"_stackAlloc",{configurable:true,get:function(){abort("You are getting _stackAlloc on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_stackAlloc",{configurable:true,set:function(){abort("You are setting _stackAlloc on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"___data_end")){Object.defineProperty(Module["ready"],"___data_end",{configurable:true,get:function(){abort("You are getting ___data_end on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"___data_end",{configurable:true,set:function(){abort("You are setting ___data_end on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"___wasm_call_ctors")){Object.defineProperty(Module["ready"],"___wasm_call_ctors",{configurable:true,get:function(){abort("You are getting ___wasm_call_ctors on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"___wasm_call_ctors",{configurable:true,set:function(){abort("You are setting ___wasm_call_ctors on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_fflush")){Object.defineProperty(Module["ready"],"_fflush",{configurable:true,get:function(){abort("You are getting _fflush on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_fflush",{configurable:true,set:function(){abort("You are setting _fflush on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"___errno_location")){Object.defineProperty(Module["ready"],"___errno_location",{configurable:true,get:function(){abort("You are getting ___errno_location on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"___errno_location",{configurable:true,set:function(){abort("You are setting ___errno_location on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"__ZSt18uncaught_exceptionv")){Object.defineProperty(Module["ready"],"__ZSt18uncaught_exceptionv",{configurable:true,get:function(){abort("You are getting __ZSt18uncaught_exceptionv on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"__ZSt18uncaught_exceptionv",{configurable:true,set:function(){abort("You are setting __ZSt18uncaught_exceptionv on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_setThrew")){Object.defineProperty(Module["ready"],"_setThrew",{configurable:true,get:function(){abort("You are getting _setThrew on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_setThrew",{configurable:true,set:function(){abort("You are setting _setThrew on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"___cxa_is_pointer_type")){Object.defineProperty(Module["ready"],"___cxa_is_pointer_type",{configurable:true,get:function(){abort("You are getting ___cxa_is_pointer_type on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"___cxa_is_pointer_type",{configurable:true,set:function(){abort("You are setting ___cxa_is_pointer_type on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"___cxa_can_catch")){Object.defineProperty(Module["ready"],"___cxa_can_catch",{configurable:true,get:function(){abort("You are getting ___cxa_can_catch on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"___cxa_can_catch",{configurable:true,set:function(){abort("You are setting ___cxa_can_catch on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"__get_tzname")){Object.defineProperty(Module["ready"],"__get_tzname",{configurable:true,get:function(){abort("You are getting __get_tzname on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"__get_tzname",{configurable:true,set:function(){abort("You are setting __get_tzname on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"__get_daylight")){Object.defineProperty(Module["ready"],"__get_daylight",{configurable:true,get:function(){abort("You are getting __get_daylight on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"__get_daylight",{configurable:true,set:function(){abort("You are setting __get_daylight on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"__get_timezone")){Object.defineProperty(Module["ready"],"__get_timezone",{configurable:true,get:function(){abort("You are getting __get_timezone on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"__get_timezone",{configurable:true,set:function(){abort("You are setting __get_timezone on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_memset")){Object.defineProperty(Module["ready"],"_memset",{configurable:true,get:function(){abort("You are getting _memset on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_memset",{configurable:true,set:function(){abort("You are setting _memset on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"_emscripten_main_thread_process_queued_calls")){Object.defineProperty(Module["ready"],"_emscripten_main_thread_process_queued_calls",{configurable:true,get:function(){abort("You are getting _emscripten_main_thread_process_queued_calls on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"_emscripten_main_thread_process_queued_calls",{configurable:true,set:function(){abort("You are setting _emscripten_main_thread_process_queued_calls on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}if(!Object.getOwnPropertyDescriptor(Module["ready"],"onRuntimeInitialized")){Object.defineProperty(Module["ready"],"onRuntimeInitialized",{configurable:true,get:function(){abort("You are getting onRuntimeInitialized on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}});Object.defineProperty(Module["ready"],"onRuntimeInitialized",{configurable:true,set:function(){abort("You are setting onRuntimeInitialized on the Promise object, instead of the instance. Use .then() to get called back with the instance, see the MODULARIZE docs in src/settings.js")}})}var moduleOverrides={};var key;for(key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var arguments_=[];var thisProgram="./this.program";var quit_=function(status,toThrow){throw toThrow};var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof process.versions==="object"&&typeof process.versions.node==="string";ENVIRONMENT_IS_SHELL=!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_NODE&&!ENVIRONMENT_IS_WORKER;if(Module["ENVIRONMENT"]){throw new Error("Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -s ENVIRONMENT=web or -s ENVIRONMENT=node)")}var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;var nodeFS;var nodePath;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require("path").dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=function shell_read(filename,binary){if(!nodeFS)nodeFS=require("fs");if(!nodePath)nodePath=require("path");filename=nodePath["normalize"](filename);return nodeFS["readFileSync"](filename,binary?null:"utf8")};readBinary=function readBinary(filename){var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}assert(ret.buffer);return ret};if(process["argv"].length>1){thisProgram=process["argv"][1].replace(/\\/g,"/")}arguments_=process["argv"].slice(2);process["on"]("unhandledRejection",abort);quit_=function(status){process["exit"](status)};Module["inspect"]=function(){return"[Emscripten Module object]"}}else if(ENVIRONMENT_IS_SHELL){if(typeof read!="undefined"){read_=function shell_read(f){return read(f)}}readBinary=function readBinary(f){var data;if(typeof readbuffer==="function"){return new Uint8Array(readbuffer(f))}data=read(f,"binary");assert(typeof data==="object");return data};if(typeof scriptArgs!="undefined"){arguments_=scriptArgs}else if(typeof arguments!="undefined"){arguments_=arguments}if(typeof quit==="function"){quit_=function(status){quit(status)}}if(typeof print!=="undefined"){if(typeof console==="undefined")console={};console.log=print;console.warn=console.error=typeof printErr!=="undefined"?printErr:print}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=function shell_read(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=function readBinary(url){var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=function readAsync(url,onload,onerror){var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=function xhr_onload(){if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=function(title){document.title=title}}else{throw new Error("environment detection error")}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);for(key in moduleOverrides){if(moduleOverrides.hasOwnProperty(key)){Module[key]=moduleOverrides[key]}}moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(!Object.getOwnPropertyDescriptor(Module,"arguments"))Object.defineProperty(Module,"arguments",{configurable:true,get:function(){abort("Module.arguments has been replaced with plain arguments_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(!Object.getOwnPropertyDescriptor(Module,"thisProgram"))Object.defineProperty(Module,"thisProgram",{configurable:true,get:function(){abort("Module.thisProgram has been replaced with plain thisProgram (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});if(Module["quit"])quit_=Module["quit"];if(!Object.getOwnPropertyDescriptor(Module,"quit"))Object.defineProperty(Module,"quit",{configurable:true,get:function(){abort("Module.quit has been replaced with plain quit_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});assert(typeof Module["memoryInitializerPrefixURL"]==="undefined","Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead");assert(typeof Module["pthreadMainPrefixURL"]==="undefined","Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead");assert(typeof Module["cdInitializerPrefixURL"]==="undefined","Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead");assert(typeof Module["filePackagePrefixURL"]==="undefined","Module.filePackagePrefixURL option was removed, use Module.locateFile instead");assert(typeof Module["read"]==="undefined","Module.read option was removed (modify read_ in JS)");assert(typeof Module["readAsync"]==="undefined","Module.readAsync option was removed (modify readAsync in JS)");assert(typeof Module["readBinary"]==="undefined","Module.readBinary option was removed (modify readBinary in JS)");assert(typeof Module["setWindowTitle"]==="undefined","Module.setWindowTitle option was removed (modify setWindowTitle in JS)");assert(typeof Module["TOTAL_MEMORY"]==="undefined","Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY");if(!Object.getOwnPropertyDescriptor(Module,"read"))Object.defineProperty(Module,"read",{configurable:true,get:function(){abort("Module.read has been replaced with plain read_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});if(!Object.getOwnPropertyDescriptor(Module,"readAsync"))Object.defineProperty(Module,"readAsync",{configurable:true,get:function(){abort("Module.readAsync has been replaced with plain readAsync (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});if(!Object.getOwnPropertyDescriptor(Module,"readBinary"))Object.defineProperty(Module,"readBinary",{configurable:true,get:function(){abort("Module.readBinary has been replaced with plain readBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});if(!Object.getOwnPropertyDescriptor(Module,"setWindowTitle"))Object.defineProperty(Module,"setWindowTitle",{configurable:true,get:function(){abort("Module.setWindowTitle has been replaced with plain setWindowTitle (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});var STACK_ALIGN=16;function dynamicAlloc(size){assert(DYNAMICTOP_PTR);var ret=HEAP32[DYNAMICTOP_PTR>>2];var end=ret+size+15&-16;assert(end<=HEAP8.length,"failure to dynamicAlloc - memory growth etc. is not supported there, call malloc/sbrk directly");HEAP32[DYNAMICTOP_PTR>>2]=end;return ret}function alignMemory(size,factor){if(!factor)factor=STACK_ALIGN;return Math.ceil(size/factor)*factor}function getNativeTypeSize(type){switch(type){case"i1":case"i8":return 1;case"i16":return 2;case"i32":return 4;case"i64":return 8;case"float":return 4;case"double":return 8;default:{if(type[type.length-1]==="*"){return 4}else if(type[0]==="i"){var bits=Number(type.substr(1));assert(bits%8===0,"getNativeTypeSize invalid bits "+bits+", type "+type);return bits/8}else{return 0}}}}function warnOnce(text){if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;err(text)}}function convertJsFunctionToWasm(func,sig){if(typeof WebAssembly.Function==="function"){var typeNames={"i":"i32","j":"i64","f":"f32","d":"f64"};var type={parameters:[],results:sig[0]=="v"?[]:[typeNames[sig[0]]]};for(var i=1;i>>0)+ +(high>>>0)*4294967296:+(low>>>0)+ +(high|0)*4294967296}function dynCall(sig,ptr,args){if(args&&args.length){assert(args.length===sig.substring(1).replace(/j/g,"--").length);assert("dynCall_"+sig in Module,"bad function pointer type - no table for sig '"+sig+"'");return Module["dynCall_"+sig].apply(null,[ptr].concat(args))}else{assert(sig.length==1);assert("dynCall_"+sig in Module,"bad function pointer type - no table for sig '"+sig+"'");return Module["dynCall_"+sig].call(null,ptr)}}var tempRet0=0;var setTempRet0=function(value){tempRet0=value};var getTempRet0=function(){return tempRet0};var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];if(!Object.getOwnPropertyDescriptor(Module,"wasmBinary"))Object.defineProperty(Module,"wasmBinary",{configurable:true,get:function(){abort("Module.wasmBinary has been replaced with plain wasmBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});var noExitRuntime;if(Module["noExitRuntime"])noExitRuntime=Module["noExitRuntime"];if(!Object.getOwnPropertyDescriptor(Module,"noExitRuntime"))Object.defineProperty(Module,"noExitRuntime",{configurable:true,get:function(){abort("Module.noExitRuntime has been replaced with plain noExitRuntime (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});if(typeof WebAssembly!=="object"){abort("no native wasm support detected")}function setValue(ptr,value,type,noSafe){type=type||"i8";if(type.charAt(type.length-1)==="*")type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}var wasmMemory;var wasmTable=new WebAssembly.Table({"initial":1906,"maximum":1906+5,"element":"anyfunc"});var ABORT=false;var EXITSTATUS=0;function assert(condition,text){if(!condition){abort("Assertion failed: "+text)}}function getCFunc(ident){var func=Module["_"+ident];assert(func,"Cannot call unknown function "+ident+", make sure it is exported");return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret},"array":function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string")return UTF8ToString(ret);if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;assert(returnType!=="array",'Return type should not be "array".');if(args){for(var i=0;i=endIdx))++endPtr;if(endPtr-idx>16&&heap.subarray&&UTF8Decoder){return UTF8Decoder.decode(heap.subarray(idx,endPtr))}else{var str="";while(idx>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;if(u>=2097152)warnOnce("Invalid Unicode code point 0x"+u.toString(16)+" encountered when serializing a JS string to an UTF-8 string on the asm.js/wasm heap! (Valid unicode code points should be in range 0-0x1FFFFF).");heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){assert(typeof maxBytesToWrite=="number","stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!");return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}var UTF16Decoder=typeof TextDecoder!=="undefined"?new TextDecoder("utf-16le"):undefined;function UTF16ToString(ptr,maxBytesToRead){assert(ptr%2==0,"Pointer passed to UTF16ToString must be aligned to two bytes!");var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder){return UTF16Decoder.decode(HEAPU8.subarray(ptr,endPtr))}else{var i=0;var str="";while(1){var codeUnit=HEAP16[ptr+i*2>>1];if(codeUnit==0||i==maxBytesToRead/2)return str;++i;str+=String.fromCharCode(codeUnit)}}}function stringToUTF16(str,outPtr,maxBytesToWrite){assert(outPtr%2==0,"Pointer passed to stringToUTF16 must be aligned to two bytes!");assert(typeof maxBytesToWrite=="number","stringToUTF16(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!");if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}HEAP16[outPtr>>1]=0;return outPtr-startPtr}function lengthBytesUTF16(str){return str.length*2}function UTF32ToString(ptr,maxBytesToRead){assert(ptr%4==0,"Pointer passed to UTF32ToString must be aligned to four bytes!");var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str}function stringToUTF32(str,outPtr,maxBytesToWrite){assert(outPtr%4==0,"Pointer passed to stringToUTF32 must be aligned to four bytes!");assert(typeof maxBytesToWrite=="number","stringToUTF32(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!");if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>2]=0;return outPtr-startPtr}function lengthBytesUTF32(str){var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len}function allocateUTF8(str){var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8Array(str,HEAP8,ret,size);return ret}function writeArrayToMemory(array,buffer){assert(array.length>=0,"writeArrayToMemory array must have a length (should be an array or typed array)");HEAP8.set(array,buffer)}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}var WASM_PAGE_SIZE=65536;function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var STACK_BASE=5660288,STACK_MAX=417408,DYNAMIC_BASE=5660288,DYNAMICTOP_PTR=417232;assert(STACK_BASE%16===0,"stack must start aligned");assert(DYNAMIC_BASE%16===0,"heap must start aligned");var TOTAL_STACK=5242880;if(Module["TOTAL_STACK"])assert(TOTAL_STACK===Module["TOTAL_STACK"],"the stack size can no longer be determined at runtime");var INITIAL_INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;if(!Object.getOwnPropertyDescriptor(Module,"INITIAL_MEMORY"))Object.defineProperty(Module,"INITIAL_MEMORY",{configurable:true,get:function(){abort("Module.INITIAL_MEMORY has been replaced with plain INITIAL_INITIAL_MEMORY (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)")}});assert(INITIAL_INITIAL_MEMORY>=TOTAL_STACK,"INITIAL_MEMORY should be larger than TOTAL_STACK, was "+INITIAL_INITIAL_MEMORY+"! (TOTAL_STACK="+TOTAL_STACK+")");assert(typeof Int32Array!=="undefined"&&typeof Float64Array!=="undefined"&&Int32Array.prototype.subarray!==undefined&&Int32Array.prototype.set!==undefined,"JS engine does not provide full typed array support");if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_INITIAL_MEMORY/WASM_PAGE_SIZE,"maximum":2147483648/WASM_PAGE_SIZE})}if(wasmMemory){buffer=wasmMemory.buffer}INITIAL_INITIAL_MEMORY=buffer.byteLength;assert(INITIAL_INITIAL_MEMORY%WASM_PAGE_SIZE===0);assert(65536%WASM_PAGE_SIZE===0);updateGlobalBufferAndViews(buffer);HEAP32[DYNAMICTOP_PTR>>2]=DYNAMIC_BASE;function writeStackCookie(){assert((STACK_MAX&3)==0);HEAPU32[(STACK_MAX>>2)+1]=34821223;HEAPU32[(STACK_MAX>>2)+2]=2310721022;HEAP32[0]=1668509029}function checkStackCookie(){var cookie1=HEAPU32[(STACK_MAX>>2)+1];var cookie2=HEAPU32[(STACK_MAX>>2)+2];if(cookie1!=34821223||cookie2!=2310721022){abort("Stack overflow! Stack cookie has been overwritten, expected hex dwords 0x89BACDFE and 0x2135467, but received 0x"+cookie2.toString(16)+" "+cookie1.toString(16))}if(HEAP32[0]!==1668509029)abort("Runtime error: The application has corrupted its heap memory area (address zero)!")}(function(){var h16=new Int16Array(1);var h8=new Int8Array(h16.buffer);h16[0]=25459;if(h8[0]!==115||h8[1]!==99)throw"Runtime error: expected the system to be little-endian!"})();function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func==="number"){if(callback.arg===undefined){Module["dynCall_v"](func)}else{Module["dynCall_vi"](func,callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){checkStackCookie();assert(!runtimeInitialized);runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){checkStackCookie();FS.ignorePermissions=false;callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){checkStackCookie();runtimeExited=true}function postRun(){checkStackCookie();if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}assert(Math.imul,"This browser does not support Math.imul(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");assert(Math.fround,"This browser does not support Math.fround(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");assert(Math.clz32,"This browser does not support Math.clz32(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");assert(Math.trunc,"This browser does not support Math.trunc(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill");var Math_abs=Math.abs;var Math_ceil=Math.ceil;var Math_floor=Math.floor;var Math_min=Math.min;var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;var runDependencyTracking={};function getUniqueRunDependency(id){var orig=id;while(1){if(!runDependencyTracking[id])return id;id=orig+Math.random()}}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(id){assert(!runDependencyTracking[id]);runDependencyTracking[id]=1;if(runDependencyWatcher===null&&typeof setInterval!=="undefined"){runDependencyWatcher=setInterval(function(){if(ABORT){clearInterval(runDependencyWatcher);runDependencyWatcher=null;return}var shown=false;for(var dep in runDependencyTracking){if(!shown){shown=true;err("still waiting on run dependencies:")}err("dependency: "+dep)}if(shown){err("(end of list)")}},1e4)}}else{err("warning: run dependency added without ID")}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(id){assert(runDependencyTracking[id]);delete runDependencyTracking[id]}else{err("warning: run dependency removed without ID")}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module["preloadedImages"]={};Module["preloadedAudios"]={};function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what+="";err(what);ABORT=true;EXITSTATUS=1;var output="abort("+what+") at "+stackTrace();what=output;var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}function hasPrefix(str,prefix){return String.prototype.startsWith?str.startsWith(prefix):str.indexOf(prefix)===0}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return hasPrefix(filename,dataURIPrefix)}var fileURIPrefix="file://";function isFileURI(filename){return hasPrefix(filename,fileURIPrefix)}function createExportWrapper(name,fixedasm){return function(){var displayName=name;var asm=fixedasm;if(!fixedasm){asm=Module["asm"]}assert(runtimeInitialized,"native function `"+displayName+"` called before runtime initialization");assert(!runtimeExited,"native function `"+displayName+"` called after runtime exit (use NO_EXIT_RUNTIME to keep it alive after main() exits)");if(!asm[name]){assert(asm[name],"exported native function `"+displayName+"` not found")}return asm[name].apply(null,arguments)}}var wasmBinaryFile="monero_core_keys.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(){try{if(wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(wasmBinaryFile)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)&&typeof fetch==="function"&&!isFileURI(wasmBinaryFile)){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary()})}return new Promise(function(resolve,reject){resolve(getBinary())})}function createWasm(){var info={"env":asmLibraryArg,"wasi_snapshot_preview1":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");var trueModule=Module;function receiveInstantiatedSource(output){assert(Module===trueModule,"the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?");trueModule=null;receiveInstance(output["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==="function"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&typeof fetch==="function"){fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiatedSource,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(receiveInstantiatedSource)})})}else{return instantiateArrayBuffer(receiveInstantiatedSource)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync();return{}}var tempDouble;var tempI64;__ATINIT__.push({func:function(){___wasm_call_ctors()}});function demangle(func){warnOnce("warning: build with -s DEMANGLE_SUPPORT=1 to link in libcxxabi demangling");return func}function demangleAll(text){var regex=/\b_Z[\w\d_]+/g;return text.replace(regex,function(x){var y=demangle(x);return x===y?x:y+" ["+x+"]"})}function jsStackTrace(){var err=new Error;if(!err.stack){try{throw new Error}catch(e){err=e}if(!err.stack){return"(no stack trace available)"}}return err.stack.toString()}function stackTrace(){var js=jsStackTrace();if(Module["extraStackTrace"])js+="\n"+Module["extraStackTrace"]();return demangleAll(js)}function _CONF_modules_unload(){err("missing function: CONF_modules_unload");abort(-1)}function _ERR_reason_error_string(){err("missing function: ERR_reason_error_string");abort(-1)}function __ZN5boost11regex_errorC1ERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_15regex_constants10error_typeEl(){err("missing function: _ZN5boost11regex_errorC1ERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_15regex_constants10error_typeEl");abort(-1)}function __ZN5boost11regex_errorD1Ev(){err("missing function: _ZN5boost11regex_errorD1Ev");abort(-1)}function __ZN5boost16re_detail_10720011raw_storage6insertEmm(){err("missing function: _ZN5boost16re_detail_10720011raw_storage6insertEmm");abort(-1)}function __ZN5boost16re_detail_10720011raw_storage6resizeEm(){err("missing function: _ZN5boost16re_detail_10720011raw_storage6resizeEm");abort(-1)}function __ZN5boost16re_detail_10720013get_mem_blockEv(){err("missing function: _ZN5boost16re_detail_10720013get_mem_blockEv");abort(-1)}function __ZN5boost16re_detail_10720013put_mem_blockEPv(){err("missing function: _ZN5boost16re_detail_10720013put_mem_blockEPv");abort(-1)}function __ZN5boost16re_detail_10720014verify_optionsEjNS_15regex_constants12_match_flagsE(){err("missing function: _ZN5boost16re_detail_10720014verify_optionsEjNS_15regex_constants12_match_flagsE");abort(-1)}function __ZN5boost16re_detail_10720019raise_runtime_errorERKSt13runtime_error(){err("missing function: _ZN5boost16re_detail_10720019raise_runtime_errorERKSt13runtime_error");abort(-1)}function __ZN5boost16re_detail_10720024get_default_error_stringENS_15regex_constants10error_typeE(){err("missing function: _ZN5boost16re_detail_10720024get_default_error_stringENS_15regex_constants10error_typeE");abort(-1)}function __ZN5boost16re_detail_10720027cpp_regex_traits_char_layerIcE4initEv(){err("missing function: _ZN5boost16re_detail_10720027cpp_regex_traits_char_layerIcE4initEv");abort(-1)}function __ZN5boost16re_detail_10720027lookup_default_collate_nameERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE(){err("missing function: _ZN5boost16re_detail_10720027lookup_default_collate_nameERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE");abort(-1)}function __ZN5boost24scoped_static_mutex_lockC1ERNS_12static_mutexEb(){err("missing function: _ZN5boost24scoped_static_mutex_lockC1ERNS_12static_mutexEb");abort(-1)}function __ZN5boost24scoped_static_mutex_lockD1Ev(){err("missing function: _ZN5boost24scoped_static_mutex_lockD1Ev");abort(-1)}function __ZNK5boost11regex_error5raiseEv(){err("missing function: _ZNK5boost11regex_error5raiseEv");abort(-1)}function ___assert_fail(condition,filename,line,func){abort("Assertion failed: "+UTF8ToString(condition)+", at: "+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"])}var ExceptionInfoAttrs={DESTRUCTOR_OFFSET:0,REFCOUNT_OFFSET:4,TYPE_OFFSET:8,CAUGHT_OFFSET:12,RETHROWN_OFFSET:13,SIZE:16};function ___cxa_allocate_exception(size){return _malloc(size+ExceptionInfoAttrs.SIZE)+ExceptionInfoAttrs.SIZE}function _atexit(func,arg){warnOnce("atexit() called, but EXIT_RUNTIME is not set, so atexits() will not be called. set EXIT_RUNTIME to 1 (see the FAQ)")}function ___cxa_atexit(a0,a1){return _atexit(a0,a1)}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-ExceptionInfoAttrs.SIZE;this.set_type=function(type){HEAP32[this.ptr+ExceptionInfoAttrs.TYPE_OFFSET>>2]=type};this.get_type=function(){return HEAP32[this.ptr+ExceptionInfoAttrs.TYPE_OFFSET>>2]};this.set_destructor=function(destructor){HEAP32[this.ptr+ExceptionInfoAttrs.DESTRUCTOR_OFFSET>>2]=destructor};this.get_destructor=function(){return HEAP32[this.ptr+ExceptionInfoAttrs.DESTRUCTOR_OFFSET>>2]};this.set_refcount=function(refcount){HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2]=refcount};this.set_caught=function(caught){caught=caught?1:0;HEAP8[this.ptr+ExceptionInfoAttrs.CAUGHT_OFFSET>>0]=caught};this.get_caught=function(){return HEAP8[this.ptr+ExceptionInfoAttrs.CAUGHT_OFFSET>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+ExceptionInfoAttrs.RETHROWN_OFFSET>>0]=rethrown};this.get_rethrown=function(){return HEAP8[this.ptr+ExceptionInfoAttrs.RETHROWN_OFFSET>>0]!=0};this.init=function(type,destructor){this.set_type(type);this.set_destructor(destructor);this.set_refcount(0);this.set_caught(false);this.set_rethrown(false)};this.add_ref=function(){var value=HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2];HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2]=value+1};this.release_ref=function(){var prev=HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2];HEAP32[this.ptr+ExceptionInfoAttrs.REFCOUNT_OFFSET>>2]=prev-1;assert(prev>0);return prev===1}}function CatchInfo(ptr){this.free=function(){_free(this.ptr);this.ptr=0};this.set_base_ptr=function(basePtr){HEAP32[this.ptr>>2]=basePtr};this.get_base_ptr=function(){return HEAP32[this.ptr>>2]};this.set_adjusted_ptr=function(adjustedPtr){var ptrSize=4;HEAP32[this.ptr+ptrSize>>2]=adjustedPtr};this.get_adjusted_ptr=function(){var ptrSize=4;return HEAP32[this.ptr+ptrSize>>2]};this.get_exception_ptr=function(){var isPointer=___cxa_is_pointer_type(this.get_exception_info().get_type());if(isPointer){return HEAP32[this.get_base_ptr()>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.get_base_ptr()};this.get_exception_info=function(){return new ExceptionInfo(this.get_base_ptr())};if(ptr===undefined){this.ptr=_malloc(8);this.set_adjusted_ptr(0)}else{this.ptr=ptr}}var exceptionCaught=[];function exception_addRef(info){info.add_ref()}function ___cxa_begin_catch(ptr){var catchInfo=new CatchInfo(ptr);var info=catchInfo.get_exception_info();if(!info.get_caught()){info.set_caught(true);__ZSt18uncaught_exceptionv.uncaught_exceptions--}info.set_rethrown(false);exceptionCaught.push(catchInfo);exception_addRef(info);return catchInfo.get_exception_ptr()}var exceptionLast=0;function ___cxa_free_exception(ptr){try{return _free(new ExceptionInfo(ptr).ptr)}catch(e){err("exception during cxa_free_exception: "+e)}}function exception_decRef(info){if(info.release_ref()&&!info.get_rethrown()){var destructor=info.get_destructor();if(destructor){Module["dynCall_ii"](destructor,info.excPtr)}___cxa_free_exception(info.excPtr)}}function ___cxa_end_catch(){_setThrew(0);assert(exceptionCaught.length>0);var catchInfo=exceptionCaught.pop();exception_decRef(catchInfo.get_exception_info());catchInfo.free();exceptionLast=0}function ___resumeException(catchInfoPtr){var catchInfo=new CatchInfo(catchInfoPtr);var ptr=catchInfo.get_base_ptr();if(!exceptionLast){exceptionLast=ptr}catchInfo.free();throw ptr}function ___cxa_find_matching_catch_2(){var thrown=exceptionLast;if(!thrown){return(setTempRet0(0),0)|0}var info=new ExceptionInfo(thrown);var thrownType=info.get_type();var catchInfo=new CatchInfo;catchInfo.set_base_ptr(thrown);if(!thrownType){return(setTempRet0(0),catchInfo.ptr)|0}var typeArray=Array.prototype.slice.call(arguments);var thrownBuf=417392;HEAP32[thrownBuf>>2]=thrown;for(var i=0;i>2];if(thrown!==adjusted){catchInfo.set_adjusted_ptr(adjusted)}return(setTempRet0(caughtType),catchInfo.ptr)|0}}return(setTempRet0(thrownType),catchInfo.ptr)|0}function ___cxa_find_matching_catch_3(){var thrown=exceptionLast;if(!thrown){return(setTempRet0(0),0)|0}var info=new ExceptionInfo(thrown);var thrownType=info.get_type();var catchInfo=new CatchInfo;catchInfo.set_base_ptr(thrown);if(!thrownType){return(setTempRet0(0),catchInfo.ptr)|0}var typeArray=Array.prototype.slice.call(arguments);var thrownBuf=417392;HEAP32[thrownBuf>>2]=thrown;for(var i=0;i>2];if(thrown!==adjusted){catchInfo.set_adjusted_ptr(adjusted)}return(setTempRet0(caughtType),catchInfo.ptr)|0}}return(setTempRet0(thrownType),catchInfo.ptr)|0}function ___cxa_rethrow(){var catchInfo=exceptionCaught.pop();var info=catchInfo.get_exception_info();var ptr=catchInfo.get_base_ptr();if(!info.get_rethrown()){exceptionCaught.push(catchInfo);info.set_rethrown(true)}else{catchInfo.free()}exceptionLast=ptr;throw ptr}function ___cxa_throw(ptr,type,destructor){var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;if(!("uncaught_exception"in __ZSt18uncaught_exceptionv)){__ZSt18uncaught_exceptionv.uncaught_exceptions=1}else{__ZSt18uncaught_exceptionv.uncaught_exceptions++}throw ptr}function ___cxa_uncaught_exceptions(){return __ZSt18uncaught_exceptionv.uncaught_exceptions}function ___handle_stack_overflow(){abort("stack overflow")}function setErrNo(value){HEAP32[___errno_location()>>2]=value;return value}function ___map_file(pathname,size){setErrNo(63);return-1}var PATH={splitPath:function(filename){var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)==="/",trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:function(path){var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path==="/")return"/";var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},extname:function(path){return PATH.splitPath(path)[3]},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:function(l,r){return PATH.normalize(l+"/"+r)}};var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!=="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=path.charAt(0)==="/"}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(function(p){return!!p}),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:function(from,to){from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node}return node},getFileDataAsRegularArray:function(node){if(node.contents&&node.contents.subarray){var arr=[];for(var i=0;i=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0);return},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0;return}if(!node.contents||node.contents.subarray){var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize;return}if(!node.contents)node.contents=[];if(node.contents.length>newSize)node.contents.length=newSize;else while(node.contents.length=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);assert(size>=0);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length8){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split("/").filter(function(p){return!!p}),false);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:function(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?mount+"/"+path:mount+path}path=path?node.name+"/"+path:node.name;node=node.parent}},hashName:function(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode:function(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:function(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode:function(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode:function(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:function(node){FS.hashRemoveNode(node)},isRoot:function(node){return node===node.parent},isMountpoint:function(node){return!!node.mounted},isFile:function(mode){return(mode&61440)===32768},isDir:function(mode){return(mode&61440)===16384},isLink:function(mode){return(mode&61440)===40960},isChrdev:function(mode){return(mode&61440)===8192},isBlkdev:function(mode){return(mode&61440)===24576},isFIFO:function(mode){return(mode&61440)===4096},isSocket:function(mode){return(mode&49152)===49152},flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function(str){var flags=FS.flagModes[str];if(typeof flags==="undefined"){throw new Error("Unknown file open mode: "+str)}return flags},flagsToPermissionString:function(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:function(node,perms){if(FS.ignorePermissions){return 0}if(perms.indexOf("r")!==-1&&!(node.mode&292)){return 2}else if(perms.indexOf("w")!==-1&&!(node.mode&146)){return 2}else if(perms.indexOf("x")!==-1&&!(node.mode&73)){return 2}return 0},mayLookup:function(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:function(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:function(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:function(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:function(fd_start,fd_end){fd_start=fd_start||0;fd_end=fd_end||FS.MAX_OPEN_FDS;for(var fd=fd_start;fd<=fd_end;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:function(fd){return FS.streams[fd]},createStream:function(stream,fd_start,fd_end){if(!FS.FSStream){FS.FSStream=function(){};FS.FSStream.prototype={object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}}}}var newStream=new FS.FSStream;for(var p in stream){newStream[p]=stream[p]}stream=newStream;var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:function(fd){FS.streams[fd]=null},chrdev_stream_ops:{open:function(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:function(){throw new FS.ErrnoError(70)}},major:function(dev){return dev>>8},minor:function(dev){return dev&255},makedev:function(ma,mi){return ma<<8|mi},registerDevice:function(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:function(dev){return FS.devices[dev]},getMounts:function(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:function(populate,callback){if(typeof populate==="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err("warning: "+FS.syncFSRequests+" FS.syncfs operations in flight at once, probably just doing extra work")}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){assert(FS.syncFSRequests>0);FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(function(mount){if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:function(type,opts,mountpoint){if(typeof type==="string"){throw type}var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:function(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(function(hash){var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.indexOf(current.mount)!==-1){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);assert(idx!==-1);node.mount.mounts.splice(idx,1)},lookup:function(parent,name){return parent.node_ops.lookup(parent,name)},mknod:function(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:function(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:function(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:function(path,mode){var dirs=path.split("/");var d="";for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=function(from,to){if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);if(typeof Uint8Array!="undefined")xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}else{return intArrayFromString(xhr.responseText||"",true)}};var lazyArray=this;lazyArray.setDataGetter(function(chunkNum){var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]==="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]==="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!=="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(function(key){var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}return fn.apply(null,arguments)}});stream_ops.read=function stream_ops_read(stream,buffer,offset,length,position){if(!FS.forceLoadFile(node)){throw new FS.ErrnoError(29)}var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);assert(size>=0);if(contents.slice){for(var i=0;i>2]=stat.dev;HEAP32[buf+4>>2]=0;HEAP32[buf+8>>2]=stat.ino;HEAP32[buf+12>>2]=stat.mode;HEAP32[buf+16>>2]=stat.nlink;HEAP32[buf+20>>2]=stat.uid;HEAP32[buf+24>>2]=stat.gid;HEAP32[buf+28>>2]=stat.rdev;HEAP32[buf+32>>2]=0;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAP32[buf+48>>2]=4096;HEAP32[buf+52>>2]=stat.blocks;HEAP32[buf+56>>2]=stat.atime.getTime()/1e3|0;HEAP32[buf+60>>2]=0;HEAP32[buf+64>>2]=stat.mtime.getTime()/1e3|0;HEAP32[buf+68>>2]=0;HEAP32[buf+72>>2]=stat.ctime.getTime()/1e3|0;HEAP32[buf+76>>2]=0;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+80>>2]=tempI64[0],HEAP32[buf+84>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},doMkdir:function(path,mode){path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0},doMknod:function(path,mode,dev){switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0},doReadlink:function(path,buf,bufsize){if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len},doAccess:function(path,amode){if(amode&~7){return-28}var node;var lookup=FS.lookupPath(path,{follow:true});node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0},doDup:function(path,flags,suggestFD){var suggest=FS.getStream(suggestFD);if(suggest)FS.close(suggest);return FS.open(path,flags,0,suggestFD,suggestFD).fd},doReadv:function(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2];var len=HEAP32[iov+(i*8+4)>>2];var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr}return ret},varargs:undefined,get:function(){assert(SYSCALLS.varargs!=undefined);SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream},get64:function(low,high){if(low>=0)assert(high===0);else assert(high===-1);return low}};function ___sys_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}var newStream;newStream=FS.open(stream.path,stream.flags,0,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 12:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_getpid(){return 42}function ___sys_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:case 21505:{if(!stream.tty)return-59;return 0}case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:{if(!stream.tty)return-59;return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.get();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.get();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;return 0}case 21524:{if(!stream.tty)return-59;return 0}default:abort("bad ioctl syscall "+op)}}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_mkdir(path,mode){try{path=SYSCALLS.getStr(path);return SYSCALLS.doMkdir(path,mode)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_mlock(addr,len){return 0}function ___sys_munlock(addr,len){return 0}function syscallMunmap(addr,len){if((addr|0)===-1||len===0){return-28}var info=SYSCALLS.mappings[addr];if(!info)return 0;if(len===info.len){var stream=FS.getStream(info.fd);if(info.prot&2){SYSCALLS.doMsync(addr,stream,len,info.flags,info.offset)}FS.munmap(stream);SYSCALLS.mappings[addr]=null;if(info.allocated){_free(info.malloc)}}return 0}function ___sys_munmap(addr,len){try{return syscallMunmap(addr,len)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_open(path,flags,varargs){SYSCALLS.varargs=varargs;try{var pathname=SYSCALLS.getStr(path);var mode=SYSCALLS.get();var stream=FS.open(pathname,flags,mode);return stream.fd}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_read(fd,buf,count){try{var stream=SYSCALLS.getStreamFromFD(fd);return FS.read(stream,HEAP8,buf,count)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function ___sys_stat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return-e.errno}}function getShiftFromSize(size){switch(size){case 1:return 0;case 2:return 1;case 4:return 2;case 8:return 3;default:throw new TypeError("Unknown type size: "+size)}}function embind_init_charCodes(){var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes}var embind_charCodes=undefined;function readLatin1String(ptr){var ret="";var c=ptr;while(HEAPU8[c]){ret+=embind_charCodes[HEAPU8[c++]]}return ret}var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var char_0=48;var char_9=57;function makeLegalFunctionName(name){if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return"_"+name}else{return name}}function createNamedFunction(name,body){name=makeLegalFunctionName(name);return function(){"use strict";return body.apply(this,arguments)}}function extendError(baseErrorType,errorName){var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return this.name+": "+this.message}};return errorClass}var BindingError=undefined;function throwBindingError(message){throw new BindingError(message)}var InternalError=undefined;function throwInternalError(message){throw new InternalError(message)}function whenDependentTypesAreResolved(myTypes,dependentTypes,getTypeConverters){myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i>shift])},destructorFunction:null})}var emval_free_list=[];var emval_handle_array=[{},{value:undefined},{value:null},{value:true},{value:false}];function __emval_decref(handle){if(handle>4&&0===--emval_handle_array[handle].refcount){emval_handle_array[handle]=undefined;emval_free_list.push(handle)}}function count_emval_handles(){var count=0;for(var i=5;i>2])}function __embind_register_emval(rawType,name){name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(handle){var rv=emval_handle_array[handle].value;__emval_decref(handle);return rv},"toWireType":function(destructors,value){return __emval_register(value)},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})}function _embind_repr(v){if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}}function floatReadValueFromPointer(name,shift){switch(shift){case 2:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>2])};case 3:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>3])};default:throw new TypeError("Unknown float type: "+name)}}function __embind_register_float(rawType,name,size){var shift=getShiftFromSize(size);name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(value){return value},"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}return value},"argPackAdvance":8,"readValueFromPointer":floatReadValueFromPointer(name,shift),destructorFunction:null})}function runDestructors(destructors){while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}}function craftInvokerFunction(humanName,argTypes,classType,cppInvokerFunc,cppTargetFunc){var argCount=argTypes.length;if(argCount<2){throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!")}var isClassMethodFunc=argTypes[1]!==null&&classType!==null;var needsDestructorStack=false;for(var i=1;i>2)+i])}return array}function replacePublicSymbol(name,value,numArguments){if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}}function embind__requireFunction(signature,rawFunction){signature=readLatin1String(signature);function makeDynCaller(dynCall){var argCache=[rawFunction];return function(){argCache.length=arguments.length+1;for(var i=0;i>1]}:function readU16FromPointer(pointer){return HEAPU16[pointer>>1]};case 2:return signed?function readS32FromPointer(pointer){return HEAP32[pointer>>2]}:function readU32FromPointer(pointer){return HEAPU32[pointer>>2]};default:throw new TypeError("Unknown integer type: "+name)}}function __embind_register_integer(primitiveType,name,size,minRange,maxRange){name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var shift=getShiftFromSize(size);var fromWireType=function(value){return value};if(minRange===0){var bitshift=32-8*size;fromWireType=function(value){return value<>>bitshift}}var isUnsignedType=name.indexOf("unsigned")!=-1;registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":function(destructors,value){if(typeof value!=="number"&&typeof value!=="boolean"){throw new TypeError('Cannot convert "'+_embind_repr(value)+'" to '+this.name)}if(valuemaxRange){throw new TypeError('Passing a number "'+_embind_repr(value)+'" from JS side to C/C++ side to an argument of type "'+name+'", which is outside the valid range ['+minRange+", "+maxRange+"]!")}return isUnsignedType?value>>>0:value|0},"argPackAdvance":8,"readValueFromPointer":integerReadValueFromPointer(name,shift,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){handle=handle>>2;var heap=HEAPU32;var size=heap[handle];var data=heap[handle+1];return new TA(buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":8,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})}function __embind_register_std_string(rawType,name){name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":function(value){var length=HEAPU32[value>>2];var str;if(stdStringIsUTF8){var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i;if(i==length||HEAPU8[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr+4,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+4+i]=charCode}}else{for(var i=0;i>2];var HEAP=getHeap();var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||HEAP[currentBytePtr>>shift]==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},"toWireType":function(destructors,value){if(!(typeof value==="string")){throwBindingError("Cannot pass non-string to C++ string type "+name)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>2]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":8,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:function(ptr){_free(ptr)}})}function __embind_register_void(rawType,name){name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":function(){return undefined},"toWireType":function(destructors,o){return undefined}})}function requireRegisteredType(rawType,humanName){var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl}function __emval_lookupTypes(argCount,argTypes){var a=new Array(argCount);for(var i=0;i>2)+i],"parameter "+i)}return a}function requireHandle(handle){if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handle_array[handle].value}function __emval_call(handle,argCount,argTypes,argv){handle=requireHandle(handle);var types=__emval_lookupTypes(argCount,argTypes);var args=new Array(argCount);for(var i=0;i4){emval_handle_array[handle].refcount+=1}}function __emval_take_value(type,argv){type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](argv);return __emval_register(v)}function _exit(status){exit(status)}function __exit(a0){return _exit(a0)}function _abort(){abort()}function _emscripten_get_sbrk_ptr(){return 417232}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function _emscripten_get_heap_size(){return HEAPU8.length}var _emscripten_get_now;if(ENVIRONMENT_IS_NODE){_emscripten_get_now=function(){var t=process["hrtime"]();return t[0]*1e3+t[1]/1e6}}else if(typeof dateNow!=="undefined"){_emscripten_get_now=dateNow}else _emscripten_get_now=function(){return performance.now()};function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){console.error("emscripten_realloc_buffer: Attempted to grow heap from "+buffer.byteLength+" bytes to "+size+" bytes, but got error: "+e)}}function _emscripten_resize_heap(requestedSize){requestedSize=requestedSize>>>0;var oldSize=_emscripten_get_heap_size();assert(requestedSize>oldSize);var PAGE_MULTIPLE=65536;var maxHeapSize=2147483648;if(requestedSize>maxHeapSize){err("Cannot enlarge memory, asked to go up to "+requestedSize+" bytes, but the limit is "+maxHeapSize+" bytes!");return false}var minHeapSize=16777216;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(minHeapSize,requestedSize,overGrownHeapSize),PAGE_MULTIPLE));var t0=_emscripten_get_now();var replacement=emscripten_realloc_buffer(newSize);var t1=_emscripten_get_now();console.log("Heap resize call from "+oldSize+" to "+newSize+" took "+(t1-t0)+" msecs. Success: "+!!replacement);if(replacement){return true}}err("Failed to grow the heap from "+oldSize+" bytes to "+newSize+" bytes, not enough memory!");return false}var ENV={};function getExecutableName(){return thisProgram||"./this.program"}function getEnvStrings(){if(!getEnvStrings.strings){var lang=(typeof navigator==="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+"="+env[x])}getEnvStrings.strings=strings}return getEnvStrings.strings}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAP32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAP32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAP32[penviron_buf_size>>2]=bufSize;return 0}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_read(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doReadv(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var stream=SYSCALLS.getStreamFromFD(fd);var HIGH_OFFSET=4294967296;var offset=offset_high*HIGH_OFFSET+(offset_low>>>0);var DOUBLE_LIMIT=9007199254740992;if(offset<=-DOUBLE_LIMIT||offset>=DOUBLE_LIMIT){return-61}FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math_abs(tempDouble)>=1?tempDouble>0?(Math_min(+Math_floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math_ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doWritev(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==="undefined"||!(e instanceof FS.ErrnoError))abort(e);return e.errno}}function _ftime(p){var millis=Date.now();HEAP32[p>>2]=millis/1e3|0;HEAP16[p+4>>1]=millis%1e3;HEAP16[p+6>>1]=0;HEAP16[p+8>>1]=0;return 0}function _getTempRet0(){return getTempRet0()|0}function _gettimeofday(ptr){var now=Date.now();HEAP32[ptr>>2]=now/1e3|0;HEAP32[ptr+4>>2]=now%1e3*1e3|0;return 0}var ___tm_current=417248;var ___tm_timezone=(stringToUTF8("GMT",417296,4),417296);function _gmtime_r(time,tmPtr){var date=new Date(HEAP32[time>>2]*1e3);HEAP32[tmPtr>>2]=date.getUTCSeconds();HEAP32[tmPtr+4>>2]=date.getUTCMinutes();HEAP32[tmPtr+8>>2]=date.getUTCHours();HEAP32[tmPtr+12>>2]=date.getUTCDate();HEAP32[tmPtr+16>>2]=date.getUTCMonth();HEAP32[tmPtr+20>>2]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getUTCDay();HEAP32[tmPtr+36>>2]=0;HEAP32[tmPtr+32>>2]=0;var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+40>>2]=___tm_timezone;return tmPtr}function _gmtime(time){return _gmtime_r(time,___tm_current)}function _llvm_eh_typeid_for(type){return type}function _tzset(){if(_tzset.called)return;_tzset.called=true;HEAP32[__get_timezone()>>2]=(new Date).getTimezoneOffset()*60;var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);HEAP32[__get_daylight()>>2]=Number(winter.getTimezoneOffset()!=summer.getTimezoneOffset());function extractZone(date){var match=date.toTimeString().match(/\(([A-Za-z ]+)\)$/);return match?match[1]:"GMT"}var winterName=extractZone(winter);var summerName=extractZone(summer);var winterNamePtr=allocateUTF8(winterName);var summerNamePtr=allocateUTF8(summerName);if(summer.getTimezoneOffset()>2]=winterNamePtr;HEAP32[__get_tzname()+4>>2]=summerNamePtr}else{HEAP32[__get_tzname()>>2]=summerNamePtr;HEAP32[__get_tzname()+4>>2]=winterNamePtr}}function _mktime(tmPtr){_tzset();var date=new Date(HEAP32[tmPtr+20>>2]+1900,HEAP32[tmPtr+16>>2],HEAP32[tmPtr+12>>2],HEAP32[tmPtr+8>>2],HEAP32[tmPtr+4>>2],HEAP32[tmPtr>>2],0);var dst=HEAP32[tmPtr+32>>2];var guessedOffset=date.getTimezoneOffset();var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dstOffset=Math.min(winterOffset,summerOffset);if(dst<0){HEAP32[tmPtr+32>>2]=Number(summerOffset!=winterOffset&&dstOffset==guessedOffset)}else if(dst>0!=(dstOffset==guessedOffset)){var nonDstOffset=Math.max(winterOffset,summerOffset);var trueOffset=dst>0?dstOffset:nonDstOffset;date.setTime(date.getTime()+(trueOffset-guessedOffset)*6e4)}HEAP32[tmPtr+24>>2]=date.getDay();var yday=(date.getTime()-start.getTime())/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;return date.getTime()/1e3|0}function _pthread_condattr_destroy(){return 0}function _pthread_condattr_init(){return 0}function _pthread_condattr_setclock(){return 0}function _pthread_detach(){}function _pthread_join(){}function _pthread_mutexattr_destroy(){}function _pthread_mutexattr_init(){}function _pthread_mutexattr_settype(){}function _setTempRet0($i){setTempRet0($i|0)}function __isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}function __arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum}var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=__isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value==="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}else{return thisDate.getFullYear()}}else{return thisDate.getFullYear()-1}}var EXPANSION_RULES_2={"%a":function(date){return WEEKDAYS[date.tm_wday].substring(0,3)},"%A":function(date){return WEEKDAYS[date.tm_wday]},"%b":function(date){return MONTHS[date.tm_mon].substring(0,3)},"%B":function(date){return MONTHS[date.tm_mon]},"%C":function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":function(date){return leadingNulls(date.tm_mday,2)},"%e":function(date){return leadingSomething(date.tm_mday,2," ")},"%g":function(date){return getWeekBasedYear(date).toString().substring(2)},"%G":function(date){return getWeekBasedYear(date)},"%H":function(date){return leadingNulls(date.tm_hour,2)},"%I":function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":function(date){return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900)?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,date.tm_mon-1),3)},"%m":function(date){return leadingNulls(date.tm_mon+1,2)},"%M":function(date){return leadingNulls(date.tm_min,2)},"%n":function(){return"\n"},"%p":function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}else{return"PM"}},"%S":function(date){return leadingNulls(date.tm_sec,2)},"%t":function(){return"\t"},"%u":function(date){return date.tm_wday||7},"%U":function(date){var janFirst=new Date(date.tm_year+1900,0,1);var firstSunday=janFirst.getDay()===0?janFirst:__addDays(janFirst,7-janFirst.getDay());var endDate=new Date(date.tm_year+1900,date.tm_mon,date.tm_mday);if(compareByDay(firstSunday,endDate)<0){var februaryFirstUntilEndMonth=__arraySum(__isLeapYear(endDate.getFullYear())?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,endDate.getMonth()-1)-31;var firstSundayUntilEndJanuary=31-firstSunday.getDate();var days=firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();return leadingNulls(Math.ceil(days/7),2)}return compareByDay(firstSunday,janFirst)===0?"01":"00"},"%V":function(date){var janFourthThisYear=new Date(date.tm_year+1900,0,4);var janFourthNextYear=new Date(date.tm_year+1901,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);var endDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);if(compareByDay(endDate,firstWeekStartThisYear)<0){return"53"}if(compareByDay(firstWeekStartNextYear,endDate)<=0){return"01"}var daysDifference;if(firstWeekStartThisYear.getFullYear()=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":function(date){return date.tm_zone},"%%":function(){return"%"}};for(var rule in EXPANSION_RULES_2){if(pattern.indexOf(rule)>=0){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}function _sysconf(name){switch(name){case 30:return 16384;case 85:var maxHeapSize=2147483648;return maxHeapSize/16384;case 132:case 133:case 12:case 137:case 138:case 15:case 235:case 16:case 17:case 18:case 19:case 20:case 149:case 13:case 10:case 236:case 153:case 9:case 21:case 22:case 159:case 154:case 14:case 77:case 78:case 139:case 80:case 81:case 82:case 68:case 67:case 164:case 11:case 29:case 47:case 48:case 95:case 52:case 51:case 46:case 79:return 200809;case 27:case 246:case 127:case 128:case 23:case 24:case 160:case 161:case 181:case 182:case 242:case 183:case 184:case 243:case 244:case 245:case 165:case 178:case 179:case 49:case 50:case 168:case 169:case 175:case 170:case 171:case 172:case 97:case 76:case 32:case 173:case 35:return-1;case 176:case 177:case 7:case 155:case 8:case 157:case 125:case 126:case 92:case 93:case 129:case 130:case 131:case 94:case 91:return 1;case 74:case 60:case 69:case 70:case 4:return 1024;case 31:case 42:case 72:return 32;case 87:case 26:case 33:return 2147483647;case 34:case 1:return 47839;case 38:case 36:return 99;case 43:case 37:return 2048;case 0:return 2097152;case 3:return 65536;case 28:return 32768;case 44:return 32767;case 75:return 16384;case 39:return 1e3;case 89:return 700;case 71:return 256;case 40:return 255;case 2:return 100;case 180:return 64;case 25:return 20;case 5:return 16;case 6:return 6;case 73:return 4;case 84:{if(typeof navigator==="object")return navigator["hardwareConcurrency"]||1;return 1}}setErrNo(28);return-1}function _time(ptr){var ret=Date.now()/1e3|0;if(ptr){HEAP32[ptr>>2]=ret}return ret}function _v4_generate_JIT_code(){err("missing function: v4_generate_JIT_code");abort(-1)}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.staticInit();embind_init_charCodes();BindingError=Module["BindingError"]=extendError(Error,"BindingError");InternalError=Module["InternalError"]=extendError(Error,"InternalError");init_emval();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");var ASSERTIONS=true;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}function intArrayToString(array){var ret=[];for(var i=0;i255){if(ASSERTIONS){assert(false,"Character code "+chr+" ("+String.fromCharCode(chr)+") at offset "+i+" not in 0x00-0xFF.")}chr&=255}ret.push(String.fromCharCode(chr))}return ret.join("")}var asmLibraryArg={"CONF_modules_unload":_CONF_modules_unload,"ERR_reason_error_string":_ERR_reason_error_string,"_ZN5boost11regex_errorC1ERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_15regex_constants10error_typeEl":__ZN5boost11regex_errorC1ERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_15regex_constants10error_typeEl,"_ZN5boost11regex_errorD1Ev":__ZN5boost11regex_errorD1Ev,"_ZN5boost16re_detail_10720011raw_storage6insertEmm":__ZN5boost16re_detail_10720011raw_storage6insertEmm,"_ZN5boost16re_detail_10720011raw_storage6resizeEm":__ZN5boost16re_detail_10720011raw_storage6resizeEm,"_ZN5boost16re_detail_10720013get_mem_blockEv":__ZN5boost16re_detail_10720013get_mem_blockEv,"_ZN5boost16re_detail_10720013put_mem_blockEPv":__ZN5boost16re_detail_10720013put_mem_blockEPv,"_ZN5boost16re_detail_10720014verify_optionsEjNS_15regex_constants12_match_flagsE":__ZN5boost16re_detail_10720014verify_optionsEjNS_15regex_constants12_match_flagsE,"_ZN5boost16re_detail_10720019raise_runtime_errorERKSt13runtime_error":__ZN5boost16re_detail_10720019raise_runtime_errorERKSt13runtime_error,"_ZN5boost16re_detail_10720024get_default_error_stringENS_15regex_constants10error_typeE":__ZN5boost16re_detail_10720024get_default_error_stringENS_15regex_constants10error_typeE,"_ZN5boost16re_detail_10720027cpp_regex_traits_char_layerIcE4initEv":__ZN5boost16re_detail_10720027cpp_regex_traits_char_layerIcE4initEv,"_ZN5boost16re_detail_10720027lookup_default_collate_nameERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE":__ZN5boost16re_detail_10720027lookup_default_collate_nameERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE,"_ZN5boost24scoped_static_mutex_lockC1ERNS_12static_mutexEb":__ZN5boost24scoped_static_mutex_lockC1ERNS_12static_mutexEb,"_ZN5boost24scoped_static_mutex_lockD1Ev":__ZN5boost24scoped_static_mutex_lockD1Ev,"_ZNK5boost11regex_error5raiseEv":__ZNK5boost11regex_error5raiseEv,"__assert_fail":___assert_fail,"__cxa_allocate_exception":___cxa_allocate_exception,"__cxa_atexit":___cxa_atexit,"__cxa_begin_catch":___cxa_begin_catch,"__cxa_end_catch":___cxa_end_catch,"__cxa_find_matching_catch_2":___cxa_find_matching_catch_2,"__cxa_find_matching_catch_3":___cxa_find_matching_catch_3,"__cxa_free_exception":___cxa_free_exception,"__cxa_rethrow":___cxa_rethrow,"__cxa_throw":___cxa_throw,"__cxa_uncaught_exceptions":___cxa_uncaught_exceptions,"__handle_stack_overflow":___handle_stack_overflow,"__map_file":___map_file,"__resumeException":___resumeException,"__sys_fcntl64":___sys_fcntl64,"__sys_getpid":___sys_getpid,"__sys_ioctl":___sys_ioctl,"__sys_mkdir":___sys_mkdir,"__sys_mlock":___sys_mlock,"__sys_munlock":___sys_munlock,"__sys_munmap":___sys_munmap,"__sys_open":___sys_open,"__sys_read":___sys_read,"__sys_stat64":___sys_stat64,"_embind_register_bool":__embind_register_bool,"_embind_register_emval":__embind_register_emval,"_embind_register_float":__embind_register_float,"_embind_register_function":__embind_register_function,"_embind_register_integer":__embind_register_integer,"_embind_register_memory_view":__embind_register_memory_view,"_embind_register_std_string":__embind_register_std_string,"_embind_register_std_wstring":__embind_register_std_wstring,"_embind_register_void":__embind_register_void,"_emval_call":__emval_call,"_emval_decref":__emval_decref,"_emval_equals":__emval_equals,"_emval_incref":__emval_incref,"_emval_take_value":__emval_take_value,"_exit":__exit,"abort":_abort,"atexit":_atexit,"emscripten_get_sbrk_ptr":_emscripten_get_sbrk_ptr,"emscripten_memcpy_big":_emscripten_memcpy_big,"emscripten_resize_heap":_emscripten_resize_heap,"environ_get":_environ_get,"environ_sizes_get":_environ_sizes_get,"exit":_exit,"fd_close":_fd_close,"fd_read":_fd_read,"fd_seek":_fd_seek,"fd_write":_fd_write,"ftime":_ftime,"getTempRet0":_getTempRet0,"gettimeofday":_gettimeofday,"gmtime":_gmtime,"gmtime_r":_gmtime_r,"invoke_diii":invoke_diii,"invoke_fiii":invoke_fiii,"invoke_i":invoke_i,"invoke_ii":invoke_ii,"invoke_iii":invoke_iii,"invoke_iiii":invoke_iiii,"invoke_iiiii":invoke_iiiii,"invoke_iiiiid":invoke_iiiiid,"invoke_iiiiii":invoke_iiiiii,"invoke_iiiiiii":invoke_iiiiiii,"invoke_iiiiiiii":invoke_iiiiiiii,"invoke_iiiiiiiiiii":invoke_iiiiiiiiiii,"invoke_iiiiiiiiiiii":invoke_iiiiiiiiiiii,"invoke_iiiiiiiiiiiii":invoke_iiiiiiiiiiiii,"invoke_iiiiij":invoke_iiiiij,"invoke_ji":invoke_ji,"invoke_jii":invoke_jii,"invoke_jiii":invoke_jiii,"invoke_jiiii":invoke_jiiii,"invoke_v":invoke_v,"invoke_vi":invoke_vi,"invoke_vii":invoke_vii,"invoke_viii":invoke_viii,"invoke_viiii":invoke_viiii,"invoke_viiiii":invoke_viiiii,"invoke_viiiiiii":invoke_viiiiiii,"invoke_viiiiiiiiii":invoke_viiiiiiiiii,"invoke_viiiiiiiiiiiiiii":invoke_viiiiiiiiiiiiiii,"invoke_viiiji":invoke_viiiji,"invoke_viij":invoke_viij,"invoke_viijii":invoke_viijii,"llvm_eh_typeid_for":_llvm_eh_typeid_for,"memory":wasmMemory,"mktime":_mktime,"pthread_condattr_destroy":_pthread_condattr_destroy,"pthread_condattr_init":_pthread_condattr_init,"pthread_condattr_setclock":_pthread_condattr_setclock,"pthread_detach":_pthread_detach,"pthread_join":_pthread_join,"pthread_mutexattr_destroy":_pthread_mutexattr_destroy,"pthread_mutexattr_init":_pthread_mutexattr_init,"pthread_mutexattr_settype":_pthread_mutexattr_settype,"setTempRet0":_setTempRet0,"strftime_l":_strftime_l,"sysconf":_sysconf,"table":wasmTable,"time":_time,"v4_generate_JIT_code":_v4_generate_JIT_code};var asm=createWasm();var ___wasm_call_ctors=Module["___wasm_call_ctors"]=createExportWrapper("__wasm_call_ctors");var _malloc=Module["_malloc"]=createExportWrapper("malloc");var __ZN5boost13serialization16singleton_module8get_lockEv=Module["__ZN5boost13serialization16singleton_module8get_lockEv"]=createExportWrapper("_ZN5boost13serialization16singleton_module8get_lockEv");var _free=Module["_free"]=createExportWrapper("free");var _memset=Module["_memset"]=createExportWrapper("memset");var ___errno_location=Module["___errno_location"]=createExportWrapper("__errno_location");var _fflush=Module["_fflush"]=createExportWrapper("fflush");var ___getTypeName=Module["___getTypeName"]=createExportWrapper("__getTypeName");var ___embind_register_native_and_builtin_types=Module["___embind_register_native_and_builtin_types"]=createExportWrapper("__embind_register_native_and_builtin_types");var __get_tzname=Module["__get_tzname"]=createExportWrapper("_get_tzname");var __get_daylight=Module["__get_daylight"]=createExportWrapper("_get_daylight");var __get_timezone=Module["__get_timezone"]=createExportWrapper("_get_timezone");var _setThrew=Module["_setThrew"]=createExportWrapper("setThrew");var stackSave=Module["stackSave"]=createExportWrapper("stackSave");var stackRestore=Module["stackRestore"]=createExportWrapper("stackRestore");var stackAlloc=Module["stackAlloc"]=createExportWrapper("stackAlloc");var __ZSt18uncaught_exceptionv=Module["__ZSt18uncaught_exceptionv"]=createExportWrapper("_ZSt18uncaught_exceptionv");var ___cxa_can_catch=Module["___cxa_can_catch"]=createExportWrapper("__cxa_can_catch");var ___cxa_is_pointer_type=Module["___cxa_is_pointer_type"]=createExportWrapper("__cxa_is_pointer_type");var _emscripten_main_thread_process_queued_calls=Module["_emscripten_main_thread_process_queued_calls"]=createExportWrapper("emscripten_main_thread_process_queued_calls");var dynCall_v=Module["dynCall_v"]=createExportWrapper("dynCall_v");var dynCall_vi=Module["dynCall_vi"]=createExportWrapper("dynCall_vi");var dynCall_vii=Module["dynCall_vii"]=createExportWrapper("dynCall_vii");var dynCall_viii=Module["dynCall_viii"]=createExportWrapper("dynCall_viii");var dynCall_viiii=Module["dynCall_viiii"]=createExportWrapper("dynCall_viiii");var dynCall_viiiii=Module["dynCall_viiiii"]=createExportWrapper("dynCall_viiiii");var dynCall_viiiiiii=Module["dynCall_viiiiiii"]=createExportWrapper("dynCall_viiiiiii");var dynCall_viiiiiiiiii=Module["dynCall_viiiiiiiiii"]=createExportWrapper("dynCall_viiiiiiiiii");var dynCall_viiiiiiiiiiiiiii=Module["dynCall_viiiiiiiiiiiiiii"]=createExportWrapper("dynCall_viiiiiiiiiiiiiii");var dynCall_viiiji=Module["dynCall_viiiji"]=createExportWrapper("dynCall_viiiji");var dynCall_viij=Module["dynCall_viij"]=createExportWrapper("dynCall_viij");var dynCall_viijii=Module["dynCall_viijii"]=createExportWrapper("dynCall_viijii");var dynCall_i=Module["dynCall_i"]=createExportWrapper("dynCall_i");var dynCall_ii=Module["dynCall_ii"]=createExportWrapper("dynCall_ii");var dynCall_iii=Module["dynCall_iii"]=createExportWrapper("dynCall_iii");var dynCall_iiii=Module["dynCall_iiii"]=createExportWrapper("dynCall_iiii");var dynCall_iiiii=Module["dynCall_iiiii"]=createExportWrapper("dynCall_iiiii");var dynCall_iiiiii=Module["dynCall_iiiiii"]=createExportWrapper("dynCall_iiiiii");var dynCall_iiiiiii=Module["dynCall_iiiiiii"]=createExportWrapper("dynCall_iiiiiii");var dynCall_iiiiiiii=Module["dynCall_iiiiiiii"]=createExportWrapper("dynCall_iiiiiiii");var dynCall_iiiiiiiiiii=Module["dynCall_iiiiiiiiiii"]=createExportWrapper("dynCall_iiiiiiiiiii");var dynCall_iiiiiiiiiiii=Module["dynCall_iiiiiiiiiiii"]=createExportWrapper("dynCall_iiiiiiiiiiii");var dynCall_iiiiiiiiiiiii=Module["dynCall_iiiiiiiiiiiii"]=createExportWrapper("dynCall_iiiiiiiiiiiii");var dynCall_iiiiij=Module["dynCall_iiiiij"]=createExportWrapper("dynCall_iiiiij");var dynCall_iiiiid=Module["dynCall_iiiiid"]=createExportWrapper("dynCall_iiiiid");var dynCall_ji=Module["dynCall_ji"]=createExportWrapper("dynCall_ji");var dynCall_jii=Module["dynCall_jii"]=createExportWrapper("dynCall_jii");var dynCall_jiii=Module["dynCall_jiii"]=createExportWrapper("dynCall_jiii");var dynCall_jiiii=Module["dynCall_jiiii"]=createExportWrapper("dynCall_jiiii");var dynCall_fiii=Module["dynCall_fiii"]=createExportWrapper("dynCall_fiii");var dynCall_diii=Module["dynCall_diii"]=createExportWrapper("dynCall_diii");var ___set_stack_limit=Module["___set_stack_limit"]=createExportWrapper("__set_stack_limit");var dynCall_viiiiiiiii=Module["dynCall_viiiiiiiii"]=createExportWrapper("dynCall_viiiiiiiii");var dynCall_viiiiiiii=Module["dynCall_viiiiiiii"]=createExportWrapper("dynCall_viiiiiiii");var dynCall_viiiiiiiiiiii=Module["dynCall_viiiiiiiiiiii"]=createExportWrapper("dynCall_viiiiiiiiiiii");var dynCall_viiiiii=Module["dynCall_viiiiii"]=createExportWrapper("dynCall_viiiiii");var dynCall_viiiiiiiiiii=Module["dynCall_viiiiiiiiiii"]=createExportWrapper("dynCall_viiiiiiiiiii");var dynCall_viiiiiiiiiiiii=Module["dynCall_viiiiiiiiiiiii"]=createExportWrapper("dynCall_viiiiiiiiiiiii");var dynCall_iiiiiiiii=Module["dynCall_iiiiiiiii"]=createExportWrapper("dynCall_iiiiiiiii");var dynCall_vijjjdi=Module["dynCall_vijjjdi"]=createExportWrapper("dynCall_vijjjdi");var dynCall_vij=Module["dynCall_vij"]=createExportWrapper("dynCall_vij");var dynCall_vijj=Module["dynCall_vijj"]=createExportWrapper("dynCall_vijj");var dynCall_viiji=Module["dynCall_viiji"]=createExportWrapper("dynCall_viiji");var dynCall_vijiiii=Module["dynCall_vijiiii"]=createExportWrapper("dynCall_vijiiii");var dynCall_iiiij=Module["dynCall_iiiij"]=createExportWrapper("dynCall_iiiij");var dynCall_iiiiiiiiiiiiii=Module["dynCall_iiiiiiiiiiiiii"]=createExportWrapper("dynCall_iiiiiiiiiiiiii");var dynCall_jiji=Module["dynCall_jiji"]=createExportWrapper("dynCall_jiji");var dynCall_iidiiii=Module["dynCall_iidiiii"]=createExportWrapper("dynCall_iidiiii");var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=createExportWrapper("dynCall_iiiiijj");var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=createExportWrapper("dynCall_iiiiiijj");var __growWasmMemory=Module["__growWasmMemory"]=createExportWrapper("__growWasmMemory");function invoke_vii(index,a1,a2){var sp=stackSave();try{dynCall_vii(index,a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_ii(index,a1){var sp=stackSave();try{return dynCall_ii(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return dynCall_iiii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return dynCall_iii(index,a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viii(index,a1,a2,a3){var sp=stackSave();try{dynCall_viii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_v(index){var sp=stackSave();try{dynCall_v(index)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return dynCall_iiiiii(index,a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{dynCall_vi(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return dynCall_iiiii(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return dynCall_iiiiiii(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiii(index,a1,a2,a3,a4){var sp=stackSave();try{dynCall_viiii(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{dynCall_viiiii(index,a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiid(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return dynCall_iiiiid(index,a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{return dynCall_iiiiiiii(index,a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{return dynCall_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12){var sp=stackSave();try{return dynCall_iiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_fiii(index,a1,a2,a3){var sp=stackSave();try{return dynCall_fiii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_diii(index,a1,a2,a3){var sp=stackSave();try{return dynCall_diii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_i(index){var sp=stackSave();try{return dynCall_i(index)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{dynCall_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11){var sp=stackSave();try{return dynCall_iiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10){var sp=stackSave();try{dynCall_viiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15){var sp=stackSave();try{dynCall_viiiiiiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_jiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return dynCall_jiiii(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viij(index,a1,a2,a3,a4){var sp=stackSave();try{dynCall_viij(index,a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_ji(index,a1){var sp=stackSave();try{return dynCall_ji(index,a1)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_jii(index,a1,a2){var sp=stackSave();try{return dynCall_jii(index,a1,a2)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_jiii(index,a1,a2,a3){var sp=stackSave();try{return dynCall_jiii(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viiiji(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{dynCall_viiiji(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_viijii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{dynCall_viijii(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}function invoke_iiiiij(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return dynCall_iiiiij(index,a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0&&e!=="longjmp")throw e;_setThrew(1,0)}}if(!Object.getOwnPropertyDescriptor(Module,"intArrayFromString"))Module["intArrayFromString"]=function(){abort("'intArrayFromString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["intArrayToString"]=intArrayToString;if(!Object.getOwnPropertyDescriptor(Module,"ccall"))Module["ccall"]=function(){abort("'ccall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"cwrap"))Module["cwrap"]=function(){abort("'cwrap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"setValue"))Module["setValue"]=function(){abort("'setValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getValue"))Module["getValue"]=function(){abort("'getValue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"allocate"))Module["allocate"]=function(){abort("'allocate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getMemory"))Module["getMemory"]=function(){abort("'getMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"UTF8ArrayToString"))Module["UTF8ArrayToString"]=function(){abort("'UTF8ArrayToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["UTF8ToString"]=UTF8ToString;if(!Object.getOwnPropertyDescriptor(Module,"stringToUTF8Array"))Module["stringToUTF8Array"]=function(){abort("'stringToUTF8Array' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["stringToUTF8"]=stringToUTF8;Module["lengthBytesUTF8"]=lengthBytesUTF8;if(!Object.getOwnPropertyDescriptor(Module,"stackTrace"))Module["stackTrace"]=function(){abort("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"addOnPreRun"))Module["addOnPreRun"]=function(){abort("'addOnPreRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"addOnInit"))Module["addOnInit"]=function(){abort("'addOnInit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"addOnPreMain"))Module["addOnPreMain"]=function(){abort("'addOnPreMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"addOnExit"))Module["addOnExit"]=function(){abort("'addOnExit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"addOnPostRun"))Module["addOnPostRun"]=function(){abort("'addOnPostRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeStringToMemory"))Module["writeStringToMemory"]=function(){abort("'writeStringToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeArrayToMemory"))Module["writeArrayToMemory"]=function(){abort("'writeArrayToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeAsciiToMemory"))Module["writeAsciiToMemory"]=function(){abort("'writeAsciiToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"addRunDependency"))Module["addRunDependency"]=function(){abort("'addRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"removeRunDependency"))Module["removeRunDependency"]=function(){abort("'removeRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createFolder"))Module["FS_createFolder"]=function(){abort("'FS_createFolder' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createPath"))Module["FS_createPath"]=function(){abort("'FS_createPath' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createDataFile"))Module["FS_createDataFile"]=function(){abort("'FS_createDataFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createPreloadedFile"))Module["FS_createPreloadedFile"]=function(){abort("'FS_createPreloadedFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createLazyFile"))Module["FS_createLazyFile"]=function(){abort("'FS_createLazyFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createLink"))Module["FS_createLink"]=function(){abort("'FS_createLink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_createDevice"))Module["FS_createDevice"]=function(){abort("'FS_createDevice' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"FS_unlink"))Module["FS_unlink"]=function(){abort("'FS_unlink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you")};if(!Object.getOwnPropertyDescriptor(Module,"dynamicAlloc"))Module["dynamicAlloc"]=function(){abort("'dynamicAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"loadDynamicLibrary"))Module["loadDynamicLibrary"]=function(){abort("'loadDynamicLibrary' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"loadWebAssemblyModule"))Module["loadWebAssemblyModule"]=function(){abort("'loadWebAssemblyModule' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getLEB"))Module["getLEB"]=function(){abort("'getLEB' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getFunctionTables"))Module["getFunctionTables"]=function(){abort("'getFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"alignFunctionTables"))Module["alignFunctionTables"]=function(){abort("'alignFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"registerFunctions"))Module["registerFunctions"]=function(){abort("'registerFunctions' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["addFunction"]=addFunction;if(!Object.getOwnPropertyDescriptor(Module,"removeFunction"))Module["removeFunction"]=function(){abort("'removeFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getFuncWrapper"))Module["getFuncWrapper"]=function(){abort("'getFuncWrapper' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"prettyPrint"))Module["prettyPrint"]=function(){abort("'prettyPrint' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["makeBigInt"]=makeBigInt;if(!Object.getOwnPropertyDescriptor(Module,"dynCall"))Module["dynCall"]=function(){abort("'dynCall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getCompilerSetting"))Module["getCompilerSetting"]=function(){abort("'getCompilerSetting' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"print"))Module["print"]=function(){abort("'print' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"printErr"))Module["printErr"]=function(){abort("'printErr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["getTempRet0"]=getTempRet0;if(!Object.getOwnPropertyDescriptor(Module,"setTempRet0"))Module["setTempRet0"]=function(){abort("'setTempRet0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"callMain"))Module["callMain"]=function(){abort("'callMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"abort"))Module["abort"]=function(){abort("'abort' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stringToNewUTF8"))Module["stringToNewUTF8"]=function(){abort("'stringToNewUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emscripten_realloc_buffer"))Module["emscripten_realloc_buffer"]=function(){abort("'emscripten_realloc_buffer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ENV"))Module["ENV"]=function(){abort("'ENV' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ERRNO_CODES"))Module["ERRNO_CODES"]=function(){abort("'ERRNO_CODES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ERRNO_MESSAGES"))Module["ERRNO_MESSAGES"]=function(){abort("'ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"setErrNo"))Module["setErrNo"]=function(){abort("'setErrNo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"DNS"))Module["DNS"]=function(){abort("'DNS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"GAI_ERRNO_MESSAGES"))Module["GAI_ERRNO_MESSAGES"]=function(){abort("'GAI_ERRNO_MESSAGES' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"Protocols"))Module["Protocols"]=function(){abort("'Protocols' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"Sockets"))Module["Sockets"]=function(){abort("'Sockets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"traverseStack"))Module["traverseStack"]=function(){abort("'traverseStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"UNWIND_CACHE"))Module["UNWIND_CACHE"]=function(){abort("'UNWIND_CACHE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"withBuiltinMalloc"))Module["withBuiltinMalloc"]=function(){abort("'withBuiltinMalloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"readAsmConstArgsArray"))Module["readAsmConstArgsArray"]=function(){abort("'readAsmConstArgsArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"readAsmConstArgs"))Module["readAsmConstArgs"]=function(){abort("'readAsmConstArgs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"jstoi_q"))Module["jstoi_q"]=function(){abort("'jstoi_q' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"jstoi_s"))Module["jstoi_s"]=function(){abort("'jstoi_s' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getExecutableName"))Module["getExecutableName"]=function(){abort("'getExecutableName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"listenOnce"))Module["listenOnce"]=function(){abort("'listenOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"autoResumeAudioContext"))Module["autoResumeAudioContext"]=function(){abort("'autoResumeAudioContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"abortStackOverflow"))Module["abortStackOverflow"]=function(){abort("'abortStackOverflow' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"reallyNegative"))Module["reallyNegative"]=function(){abort("'reallyNegative' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"formatString"))Module["formatString"]=function(){abort("'formatString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"PATH"))Module["PATH"]=function(){abort("'PATH' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"PATH_FS"))Module["PATH_FS"]=function(){abort("'PATH_FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SYSCALLS"))Module["SYSCALLS"]=function(){abort("'SYSCALLS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"syscallMmap2"))Module["syscallMmap2"]=function(){abort("'syscallMmap2' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"syscallMunmap"))Module["syscallMunmap"]=function(){abort("'syscallMunmap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"JSEvents"))Module["JSEvents"]=function(){abort("'JSEvents' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"specialHTMLTargets"))Module["specialHTMLTargets"]=function(){abort("'specialHTMLTargets' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"maybeCStringToJsString"))Module["maybeCStringToJsString"]=function(){abort("'maybeCStringToJsString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"findEventTarget"))Module["findEventTarget"]=function(){abort("'findEventTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"findCanvasEventTarget"))Module["findCanvasEventTarget"]=function(){abort("'findCanvasEventTarget' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"polyfillSetImmediate"))Module["polyfillSetImmediate"]=function(){abort("'polyfillSetImmediate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"demangle"))Module["demangle"]=function(){abort("'demangle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"demangleAll"))Module["demangleAll"]=function(){abort("'demangleAll' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"jsStackTrace"))Module["jsStackTrace"]=function(){abort("'jsStackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stackTrace"))Module["stackTrace"]=function(){abort("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getEnvStrings"))Module["getEnvStrings"]=function(){abort("'getEnvStrings' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"checkWasiClock"))Module["checkWasiClock"]=function(){abort("'checkWasiClock' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeI53ToI64"))Module["writeI53ToI64"]=function(){abort("'writeI53ToI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeI53ToI64Clamped"))Module["writeI53ToI64Clamped"]=function(){abort("'writeI53ToI64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeI53ToI64Signaling"))Module["writeI53ToI64Signaling"]=function(){abort("'writeI53ToI64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeI53ToU64Clamped"))Module["writeI53ToU64Clamped"]=function(){abort("'writeI53ToU64Clamped' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeI53ToU64Signaling"))Module["writeI53ToU64Signaling"]=function(){abort("'writeI53ToU64Signaling' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"readI53FromI64"))Module["readI53FromI64"]=function(){abort("'readI53FromI64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"readI53FromU64"))Module["readI53FromU64"]=function(){abort("'readI53FromU64' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"convertI32PairToI53"))Module["convertI32PairToI53"]=function(){abort("'convertI32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"convertU32PairToI53"))Module["convertU32PairToI53"]=function(){abort("'convertU32PairToI53' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"exceptionLast"))Module["exceptionLast"]=function(){abort("'exceptionLast' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"exceptionCaught"))Module["exceptionCaught"]=function(){abort("'exceptionCaught' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ExceptionInfoAttrs"))Module["ExceptionInfoAttrs"]=function(){abort("'ExceptionInfoAttrs' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ExceptionInfo"))Module["ExceptionInfo"]=function(){abort("'ExceptionInfo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"CatchInfo"))Module["CatchInfo"]=function(){abort("'CatchInfo' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"exception_addRef"))Module["exception_addRef"]=function(){abort("'exception_addRef' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"exception_decRef"))Module["exception_decRef"]=function(){abort("'exception_decRef' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"Browser"))Module["Browser"]=function(){abort("'Browser' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"FS"))Module["FS"]=function(){abort("'FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"MEMFS"))Module["MEMFS"]=function(){abort("'MEMFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"TTY"))Module["TTY"]=function(){abort("'TTY' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"PIPEFS"))Module["PIPEFS"]=function(){abort("'PIPEFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SOCKFS"))Module["SOCKFS"]=function(){abort("'SOCKFS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"tempFixedLengthArray"))Module["tempFixedLengthArray"]=function(){abort("'tempFixedLengthArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"miniTempWebGLFloatBuffers"))Module["miniTempWebGLFloatBuffers"]=function(){abort("'miniTempWebGLFloatBuffers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"heapObjectForWebGLType"))Module["heapObjectForWebGLType"]=function(){abort("'heapObjectForWebGLType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"heapAccessShiftForWebGLHeap"))Module["heapAccessShiftForWebGLHeap"]=function(){abort("'heapAccessShiftForWebGLHeap' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"GL"))Module["GL"]=function(){abort("'GL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emscriptenWebGLGet"))Module["emscriptenWebGLGet"]=function(){abort("'emscriptenWebGLGet' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"computeUnpackAlignedImageSize"))Module["computeUnpackAlignedImageSize"]=function(){abort("'computeUnpackAlignedImageSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emscriptenWebGLGetTexPixelData"))Module["emscriptenWebGLGetTexPixelData"]=function(){abort("'emscriptenWebGLGetTexPixelData' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emscriptenWebGLGetUniform"))Module["emscriptenWebGLGetUniform"]=function(){abort("'emscriptenWebGLGetUniform' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emscriptenWebGLGetVertexAttrib"))Module["emscriptenWebGLGetVertexAttrib"]=function(){abort("'emscriptenWebGLGetVertexAttrib' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"writeGLArray"))Module["writeGLArray"]=function(){abort("'writeGLArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"AL"))Module["AL"]=function(){abort("'AL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SDL_unicode"))Module["SDL_unicode"]=function(){abort("'SDL_unicode' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SDL_ttfContext"))Module["SDL_ttfContext"]=function(){abort("'SDL_ttfContext' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SDL_audio"))Module["SDL_audio"]=function(){abort("'SDL_audio' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SDL"))Module["SDL"]=function(){abort("'SDL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"SDL_gfx"))Module["SDL_gfx"]=function(){abort("'SDL_gfx' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"GLUT"))Module["GLUT"]=function(){abort("'GLUT' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"EGL"))Module["EGL"]=function(){abort("'EGL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"GLFW_Window"))Module["GLFW_Window"]=function(){abort("'GLFW_Window' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"GLFW"))Module["GLFW"]=function(){abort("'GLFW' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"GLEW"))Module["GLEW"]=function(){abort("'GLEW' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"IDBStore"))Module["IDBStore"]=function(){abort("'IDBStore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"runAndAbortIfError"))Module["runAndAbortIfError"]=function(){abort("'runAndAbortIfError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emval_handle_array"))Module["emval_handle_array"]=function(){abort("'emval_handle_array' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emval_free_list"))Module["emval_free_list"]=function(){abort("'emval_free_list' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emval_symbols"))Module["emval_symbols"]=function(){abort("'emval_symbols' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"init_emval"))Module["init_emval"]=function(){abort("'init_emval' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"count_emval_handles"))Module["count_emval_handles"]=function(){abort("'count_emval_handles' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"get_first_emval"))Module["get_first_emval"]=function(){abort("'get_first_emval' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getStringOrSymbol"))Module["getStringOrSymbol"]=function(){abort("'getStringOrSymbol' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"requireHandle"))Module["requireHandle"]=function(){abort("'requireHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emval_newers"))Module["emval_newers"]=function(){abort("'emval_newers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"craftEmvalAllocator"))Module["craftEmvalAllocator"]=function(){abort("'craftEmvalAllocator' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emval_get_global"))Module["emval_get_global"]=function(){abort("'emval_get_global' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"emval_methodCallers"))Module["emval_methodCallers"]=function(){abort("'emval_methodCallers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"InternalError"))Module["InternalError"]=function(){abort("'InternalError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"BindingError"))Module["BindingError"]=function(){abort("'BindingError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"UnboundTypeError"))Module["UnboundTypeError"]=function(){abort("'UnboundTypeError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"PureVirtualError"))Module["PureVirtualError"]=function(){abort("'PureVirtualError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"init_embind"))Module["init_embind"]=function(){abort("'init_embind' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"throwInternalError"))Module["throwInternalError"]=function(){abort("'throwInternalError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"throwBindingError"))Module["throwBindingError"]=function(){abort("'throwBindingError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"throwUnboundTypeError"))Module["throwUnboundTypeError"]=function(){abort("'throwUnboundTypeError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ensureOverloadTable"))Module["ensureOverloadTable"]=function(){abort("'ensureOverloadTable' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"exposePublicSymbol"))Module["exposePublicSymbol"]=function(){abort("'exposePublicSymbol' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"replacePublicSymbol"))Module["replacePublicSymbol"]=function(){abort("'replacePublicSymbol' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"extendError"))Module["extendError"]=function(){abort("'extendError' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"createNamedFunction"))Module["createNamedFunction"]=function(){abort("'createNamedFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"registeredInstances"))Module["registeredInstances"]=function(){abort("'registeredInstances' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getBasestPointer"))Module["getBasestPointer"]=function(){abort("'getBasestPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"registerInheritedInstance"))Module["registerInheritedInstance"]=function(){abort("'registerInheritedInstance' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"unregisterInheritedInstance"))Module["unregisterInheritedInstance"]=function(){abort("'unregisterInheritedInstance' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getInheritedInstance"))Module["getInheritedInstance"]=function(){abort("'getInheritedInstance' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getInheritedInstanceCount"))Module["getInheritedInstanceCount"]=function(){abort("'getInheritedInstanceCount' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getLiveInheritedInstances"))Module["getLiveInheritedInstances"]=function(){abort("'getLiveInheritedInstances' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"registeredTypes"))Module["registeredTypes"]=function(){abort("'registeredTypes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"awaitingDependencies"))Module["awaitingDependencies"]=function(){abort("'awaitingDependencies' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"typeDependencies"))Module["typeDependencies"]=function(){abort("'typeDependencies' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"registeredPointers"))Module["registeredPointers"]=function(){abort("'registeredPointers' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"registerType"))Module["registerType"]=function(){abort("'registerType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"whenDependentTypesAreResolved"))Module["whenDependentTypesAreResolved"]=function(){abort("'whenDependentTypesAreResolved' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"embind_charCodes"))Module["embind_charCodes"]=function(){abort("'embind_charCodes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"embind_init_charCodes"))Module["embind_init_charCodes"]=function(){abort("'embind_init_charCodes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"readLatin1String"))Module["readLatin1String"]=function(){abort("'readLatin1String' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getTypeName"))Module["getTypeName"]=function(){abort("'getTypeName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"heap32VectorToArray"))Module["heap32VectorToArray"]=function(){abort("'heap32VectorToArray' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"requireRegisteredType"))Module["requireRegisteredType"]=function(){abort("'requireRegisteredType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"getShiftFromSize"))Module["getShiftFromSize"]=function(){abort("'getShiftFromSize' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"integerReadValueFromPointer"))Module["integerReadValueFromPointer"]=function(){abort("'integerReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"enumReadValueFromPointer"))Module["enumReadValueFromPointer"]=function(){abort("'enumReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"floatReadValueFromPointer"))Module["floatReadValueFromPointer"]=function(){abort("'floatReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"simpleReadValueFromPointer"))Module["simpleReadValueFromPointer"]=function(){abort("'simpleReadValueFromPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"runDestructors"))Module["runDestructors"]=function(){abort("'runDestructors' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"new_"))Module["new_"]=function(){abort("'new_' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"craftInvokerFunction"))Module["craftInvokerFunction"]=function(){abort("'craftInvokerFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"embind__requireFunction"))Module["embind__requireFunction"]=function(){abort("'embind__requireFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"tupleRegistrations"))Module["tupleRegistrations"]=function(){abort("'tupleRegistrations' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"structRegistrations"))Module["structRegistrations"]=function(){abort("'structRegistrations' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"genericPointerToWireType"))Module["genericPointerToWireType"]=function(){abort("'genericPointerToWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"constNoSmartPtrRawPointerToWireType"))Module["constNoSmartPtrRawPointerToWireType"]=function(){abort("'constNoSmartPtrRawPointerToWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"nonConstNoSmartPtrRawPointerToWireType"))Module["nonConstNoSmartPtrRawPointerToWireType"]=function(){abort("'nonConstNoSmartPtrRawPointerToWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"init_RegisteredPointer"))Module["init_RegisteredPointer"]=function(){abort("'init_RegisteredPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"RegisteredPointer"))Module["RegisteredPointer"]=function(){abort("'RegisteredPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"RegisteredPointer_getPointee"))Module["RegisteredPointer_getPointee"]=function(){abort("'RegisteredPointer_getPointee' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"RegisteredPointer_destructor"))Module["RegisteredPointer_destructor"]=function(){abort("'RegisteredPointer_destructor' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"RegisteredPointer_deleteObject"))Module["RegisteredPointer_deleteObject"]=function(){abort("'RegisteredPointer_deleteObject' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"RegisteredPointer_fromWireType"))Module["RegisteredPointer_fromWireType"]=function(){abort("'RegisteredPointer_fromWireType' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"runDestructor"))Module["runDestructor"]=function(){abort("'runDestructor' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"releaseClassHandle"))Module["releaseClassHandle"]=function(){abort("'releaseClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"finalizationGroup"))Module["finalizationGroup"]=function(){abort("'finalizationGroup' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"detachFinalizer_deps"))Module["detachFinalizer_deps"]=function(){abort("'detachFinalizer_deps' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"detachFinalizer"))Module["detachFinalizer"]=function(){abort("'detachFinalizer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"attachFinalizer"))Module["attachFinalizer"]=function(){abort("'attachFinalizer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"makeClassHandle"))Module["makeClassHandle"]=function(){abort("'makeClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"init_ClassHandle"))Module["init_ClassHandle"]=function(){abort("'init_ClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ClassHandle"))Module["ClassHandle"]=function(){abort("'ClassHandle' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ClassHandle_isAliasOf"))Module["ClassHandle_isAliasOf"]=function(){abort("'ClassHandle_isAliasOf' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"throwInstanceAlreadyDeleted"))Module["throwInstanceAlreadyDeleted"]=function(){abort("'throwInstanceAlreadyDeleted' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ClassHandle_clone"))Module["ClassHandle_clone"]=function(){abort("'ClassHandle_clone' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ClassHandle_delete"))Module["ClassHandle_delete"]=function(){abort("'ClassHandle_delete' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"deletionQueue"))Module["deletionQueue"]=function(){abort("'deletionQueue' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ClassHandle_isDeleted"))Module["ClassHandle_isDeleted"]=function(){abort("'ClassHandle_isDeleted' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"ClassHandle_deleteLater"))Module["ClassHandle_deleteLater"]=function(){abort("'ClassHandle_deleteLater' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"flushPendingDeletes"))Module["flushPendingDeletes"]=function(){abort("'flushPendingDeletes' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"delayFunction"))Module["delayFunction"]=function(){abort("'delayFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"setDelayFunction"))Module["setDelayFunction"]=function(){abort("'setDelayFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"RegisteredClass"))Module["RegisteredClass"]=function(){abort("'RegisteredClass' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"shallowCopyInternalPointer"))Module["shallowCopyInternalPointer"]=function(){abort("'shallowCopyInternalPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"downcastPointer"))Module["downcastPointer"]=function(){abort("'downcastPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"upcastPointer"))Module["upcastPointer"]=function(){abort("'upcastPointer' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"validateThis"))Module["validateThis"]=function(){abort("'validateThis' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"char_0"))Module["char_0"]=function(){abort("'char_0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"char_9"))Module["char_9"]=function(){abort("'char_9' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"makeLegalFunctionName"))Module["makeLegalFunctionName"]=function(){abort("'makeLegalFunctionName' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"warnOnce"))Module["warnOnce"]=function(){abort("'warnOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stackSave"))Module["stackSave"]=function(){abort("'stackSave' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stackRestore"))Module["stackRestore"]=function(){abort("'stackRestore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stackAlloc"))Module["stackAlloc"]=function(){abort("'stackAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"AsciiToString"))Module["AsciiToString"]=function(){abort("'AsciiToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stringToAscii"))Module["stringToAscii"]=function(){abort("'stringToAscii' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"UTF16ToString"))Module["UTF16ToString"]=function(){abort("'UTF16ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stringToUTF16"))Module["stringToUTF16"]=function(){abort("'stringToUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"lengthBytesUTF16"))Module["lengthBytesUTF16"]=function(){abort("'lengthBytesUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"UTF32ToString"))Module["UTF32ToString"]=function(){abort("'UTF32ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"stringToUTF32"))Module["stringToUTF32"]=function(){abort("'stringToUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"lengthBytesUTF32"))Module["lengthBytesUTF32"]=function(){abort("'lengthBytesUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"allocateUTF8"))Module["allocateUTF8"]=function(){abort("'allocateUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};if(!Object.getOwnPropertyDescriptor(Module,"allocateUTF8OnStack"))Module["allocateUTF8OnStack"]=function(){abort("'allocateUTF8OnStack' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")};Module["writeStackCookie"]=writeStackCookie;Module["checkStackCookie"]=checkStackCookie;if(!Object.getOwnPropertyDescriptor(Module,"ALLOC_NORMAL"))Object.defineProperty(Module,"ALLOC_NORMAL",{configurable:true,get:function(){abort("'ALLOC_NORMAL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}});if(!Object.getOwnPropertyDescriptor(Module,"ALLOC_STACK"))Object.defineProperty(Module,"ALLOC_STACK",{configurable:true,get:function(){abort("'ALLOC_STACK' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}});if(!Object.getOwnPropertyDescriptor(Module,"ALLOC_DYNAMIC"))Object.defineProperty(Module,"ALLOC_DYNAMIC",{configurable:true,get:function(){abort("'ALLOC_DYNAMIC' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}});if(!Object.getOwnPropertyDescriptor(Module,"ALLOC_NONE"))Object.defineProperty(Module,"ALLOC_NONE",{configurable:true,get:function(){abort("'ALLOC_NONE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)")}});var calledRun;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(args){args=args||arguments_;if(runDependencies>0){return}writeStackCookie();preRun();if(runDependencies>0)return;function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();assert(!Module["_main"],'compiled without a main, but one is present. if you added it from JS, use Module["onRuntimeInitialized"]');postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}checkStackCookie()}Module["run"]=run;function checkUnflushedContent(){var print=out;var printErr=err;var has=false;out=err=function(x){has=true};try{var flush=Module["_fflush"];if(flush)flush(0);["stdout","stderr"].forEach(function(name){var info=FS.analyzePath("/dev/"+name);if(!info)return;var stream=info.object;var rdev=stream.rdev;var tty=TTY.ttys[rdev];if(tty&&tty.output&&tty.output.length){has=true}})}catch(e){}out=print;err=printErr;if(has){warnOnce("stdio streams had content in them that was not flushed. you should set EXIT_RUNTIME to 1 (see the FAQ), or make sure to emit a newline when you printf etc.")}}function exit(status,implicit){checkUnflushedContent();if(implicit&&noExitRuntime&&status===0){return}if(noExitRuntime){if(!implicit){var msg="program exited (with status: "+status+"), but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)";readyPromiseReject(msg);err(msg)}}else{ABORT=true;EXITSTATUS=status;exitRuntime();if(Module["onExit"])Module["onExit"](status)}quit_(status,new ExitStatus(status))}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}noExitRuntime=true;run(); - - - return monero_javascript.ready -} -); -})(); -if (typeof exports === 'object' && typeof module === 'object') - module.exports = monero_javascript; - else if (typeof define === 'function' && define['amd']) - define([], function() { return monero_javascript; }); - else if (typeof exports === 'object') - exports["monero_javascript"] = monero_javascript; - \ No newline at end of file diff --git a/dist/monero_core_keys.wasm b/dist/monero_core_keys.wasm deleted file mode 100644 index 6198ea73a..000000000 Binary files a/dist/monero_core_keys.wasm and /dev/null differ diff --git a/dist/src/main/ts/common/Filter.d.ts b/dist/src/main/ts/common/Filter.d.ts new file mode 100644 index 000000000..29c5abd3b --- /dev/null +++ b/dist/src/main/ts/common/Filter.d.ts @@ -0,0 +1,23 @@ +/** + * Base filter. + * + * @private + */ +export default class Filter { + /** + * Indicates if the given value meets the criteria of this filter. + * + * @param val is the value to test + * @return true if the value meets the criteria of this filter, false otherwise + */ + meetsCriteria(val: any): boolean; + /** + * Returns a new array comprised of elements from the given array that meet + * the filter's criteria. + * + * @param filter implements meetsCriteria(elem) to filter the given array + * @param array is the array to apply the filter to + * @return the new array of filtered elements + */ + static apply(filter: Filter, array: any[]): any[]; +} diff --git a/dist/src/main/ts/common/Filter.js b/dist/src/main/ts/common/Filter.js new file mode 100644 index 000000000..932e592b4 --- /dev/null +++ b/dist/src/main/ts/common/Filter.js @@ -0,0 +1,30 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Base filter. + * + * @private + */ +class Filter { + + /** + * Indicates if the given value meets the criteria of this filter. + * + * @param val is the value to test + * @return true if the value meets the criteria of this filter, false otherwise + */ + meetsCriteria(val) { + throw new Error("Subclass must implement"); + } + + /** + * Returns a new array comprised of elements from the given array that meet + * the filter's criteria. + * + * @param filter implements meetsCriteria(elem) to filter the given array + * @param array is the array to apply the filter to + * @return the new array of filtered elements + */ + static apply(filter, array) { + return array.filter((elem) => !filter || filter.meetsCriteria(elem)); + } +}exports.default = Filter; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJGaWx0ZXIiLCJtZWV0c0NyaXRlcmlhIiwidmFsIiwiRXJyb3IiLCJhcHBseSIsImZpbHRlciIsImFycmF5IiwiZWxlbSIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvY29tbW9uL0ZpbHRlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEJhc2UgZmlsdGVyLlxuICogXG4gKiBAcHJpdmF0ZVxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBGaWx0ZXIge1xuICBcbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgZ2l2ZW4gdmFsdWUgbWVldHMgdGhlIGNyaXRlcmlhIG9mIHRoaXMgZmlsdGVyLlxuICAgKiBcbiAgICogQHBhcmFtIHZhbCBpcyB0aGUgdmFsdWUgdG8gdGVzdFxuICAgKiBAcmV0dXJuIHRydWUgaWYgdGhlIHZhbHVlIG1lZXRzIHRoZSBjcml0ZXJpYSBvZiB0aGlzIGZpbHRlciwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBtZWV0c0NyaXRlcmlhKHZhbDogYW55KTogYm9vbGVhbiB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgbmV3IGFycmF5IGNvbXByaXNlZCBvZiBlbGVtZW50cyBmcm9tIHRoZSBnaXZlbiBhcnJheSB0aGF0IG1lZXRcbiAgICogdGhlIGZpbHRlcidzIGNyaXRlcmlhLlxuICAgKiBcbiAgICogQHBhcmFtIGZpbHRlciBpbXBsZW1lbnRzIG1lZXRzQ3JpdGVyaWEoZWxlbSkgdG8gZmlsdGVyIHRoZSBnaXZlbiBhcnJheVxuICAgKiBAcGFyYW0gYXJyYXkgaXMgdGhlIGFycmF5IHRvIGFwcGx5IHRoZSBmaWx0ZXIgdG9cbiAgICogQHJldHVybiB0aGUgbmV3IGFycmF5IG9mIGZpbHRlcmVkIGVsZW1lbnRzXG4gICAqL1xuICBzdGF0aWMgYXBwbHkoZmlsdGVyOiBGaWx0ZXIsIGFycmF5OiBhbnlbXSk6IGFueVtdIHtcbiAgICByZXR1cm4gYXJyYXkuZmlsdGVyKGVsZW0gPT4gIWZpbHRlciB8fCBmaWx0ZXIubWVldHNDcml0ZXJpYShlbGVtKSk7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InFHQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSxNQUFNLENBQUM7O0VBRTFCO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNFQyxhQUFhQSxDQUFDQyxHQUFRLEVBQVc7SUFDL0IsTUFBTSxJQUFJQyxLQUFLLENBQUMseUJBQXlCLENBQUM7RUFDNUM7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNFLE9BQU9DLEtBQUtBLENBQUNDLE1BQWMsRUFBRUMsS0FBWSxFQUFTO0lBQ2hELE9BQU9BLEtBQUssQ0FBQ0QsTUFBTSxDQUFDLENBQUFFLElBQUksS0FBSSxDQUFDRixNQUFNLElBQUlBLE1BQU0sQ0FBQ0osYUFBYSxDQUFDTSxJQUFJLENBQUMsQ0FBQztFQUNwRTtBQUNGLENBQUNDLE9BQUEsQ0FBQUMsT0FBQSxHQUFBVCxNQUFBIn0= \ No newline at end of file diff --git a/dist/src/main/ts/common/GenUtils.d.ts b/dist/src/main/ts/common/GenUtils.d.ts new file mode 100644 index 000000000..5d7960343 --- /dev/null +++ b/dist/src/main/ts/common/GenUtils.d.ts @@ -0,0 +1,750 @@ +/// +/// +import { ChildProcess } from "child_process"; +/** + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + * Collection of general purpose utilities. + */ +export default class GenUtils { + /** + * Indicates if the given argument is defined. + * + * @param {any} arg is the arg to test + * @return {boolean} true if the given arg is defined, false otherwise + */ + static isDefined(arg: any): boolean; + /** + * Indicates if the given argument is undefined. + * + * @param arg is the arg to test + * @return {boolean} true if the given arg is undefined, false otherwise + */ + static isUndefined(arg: any): boolean; + /** + * Indicates if the given arg is initialized. + * + * @param {any} arg is the arg to test + * @return {boolean} true if the given arg is initialized, false otherwise + */ + static isInitialized(arg: any): boolean; + /** + * Indicates if the given arg is uninitialized. + * + * @param arg is the arg to test + * @return true if the given arg is uninitialized, false otherwise + */ + static isUninitialized(arg: any): boolean; + /** + * Indicates if the given argument is a number. + * + * @param {any} arg is the argument to test + * @return {boolean} true if the argument is a number, false otherwise + */ + static isNumber(arg: any): boolean; + /** + * Indicates if the given argument is an integer. + * + * @param {any} arg is the argument to test + * @return {boolean} true if the given argument is an integer, false otherwise + */ + static isInt(arg: any): boolean; + /** + * Indicates if the given argument is an array. + * + * @param {any} arg is the argument to test as being an array + * @return {booolean} true if the argument is an array, false otherwise + */ + static isArray(arg: any): boolean; + /** + * Indicates if the given argument is a string. + * + * @param {any} arg is the argument to test as being a string + * @return {boolean} true if the argument is a string, false otherwise + */ + static isString(arg: any): boolean; + /** + * Determines if the given argument is a boolean. + * + * @param {any} arg is the argument to test as being a boolean + * @return {boolean} true if the argument is a boolean, false otherwise + */ + static isBoolean(arg: any): boolean; + /** + * Determines if the given argument is a static. + * + * @param {any} arg is the argument to test as being a static + * @return {boolean} true if the argument is a static, false otherwise + */ + static isFunction(arg: any): boolean; + /** + * Indicates if the given argument is an object and optionally if it has the given constructor name. + * + * @param {any} arg is the argument to test + * @param {any} obj is an object to test arg instanceof obj (optional) + * @return {boolean} true if the given argument is an object and optionally has the given constructor name + */ + static isObject(arg: any, obj?: any): boolean; + /** + * Determines if all alphabet characters in the given string are upper case. + * + * @param {string} str is the string to test + * @return {boolean} true if the string is upper case, false otherwise + */ + static isUpperCase(str: string): boolean; + /** + * Determines if all alphabet characters in the given string are lower case. + * + * @param str is the string to test + * @param true if the string is lower case, false otherwise + */ + static isLowerCase(str: any): boolean; + /** + * Asserts that the given argument is hex. + * + * @param arg is the argument to assert as hex + * @param msg is the message to throw if the argument is not hex + */ + static assertHex(str: any, msg: any): void; + /** + * Indicates if the given argument is a hexidemal string. + * + * Credit: https://github.com/roryrjb/is-hex/blob/master/is-hex.js. + * + * @param str is the string to test + * @return true if the given string is hexidecimal, false otherwise + */ + static isHex(arg: any): boolean; + /** + * Determines if the given string is base32. + */ + static isBase32(str: any): boolean; + /** + * Asserts that the given argument is base58. + * + * @param arg is the argument to assert as base58 + * @param msg is the message to throw if the argument is not base58 + */ + static assertBase58(str: any, msg: any): void; + /** + * Determines if the given string is base58. + */ + static isBase58(str: any): boolean; + /** + * Asserts that the given argument is base64. + * + * @param arg is the argument to assert as base64 + * @param msg is the message to throw if the argument is not base64 + */ + static assertBase64(str: any, msg: any): void; + /** + * Determines if the given string is base64. + */ + static isBase64(str: any): boolean; + /** + * Throws an exception with the given message. + * + * @param msg defines the message to throw the exception with (optional) + */ + static fail(msg?: any): void; + /** + * Asserts that the given condition is true. Throws an exception if not a boolean or false. + * + * @param {boolean} condition is the boolean to assert true + * @param {string} [msg] is the message to throw if condition is false (optional) + */ + static assertTrue(condition: any, msg?: any): void; + /** + * Asserts that the given boolean is false. Throws an exception if not a boolean or true. + * + * @param bool is the boolean to assert false + * @param msg is the message to throw if bool is true (optional) + */ + static assertFalse(bool: any, msg?: any): void; + /** + * Asserts that the given argument is null. Throws an exception if not null. + * + * @param arg is the argument to assert null + * @param msg is the message to throw if arg is not null (optional) + */ + static assertNull(arg: any, msg?: any): void; + /** + * Asserts that the given argument is not null. Throws an exception if null. + * + * @param arg is the argument to assert not null + * @param msg is the message to throw if arg is null (optional) + */ + static assertNotNull(arg: any, msg?: any): void; + /** + * Asserts that the given argument is defined. Throws an exception if undefined. + * + * @param arg is the argument to assert defined + * @param msg is the message to throw if arg is undefined (optional) + */ + static assertDefined(arg: any, msg?: any): void; + /** + * Asserts that the given argument is undefined. Throws an exception if defined. + * + * @param arg is the argument to assert undefined + * @param msg is the message to throw if arg is defined (optional) + */ + static assertUndefined(arg: any, msg?: any): void; + /** + * Asserts that the given argument is initialized. Throws an exception if not initialized. + * + * @param arg is the argument to assert as initialized + * @param msg is the message to throw if arg is not initialized (optional) + */ + static assertInitialized(arg: any, msg?: any): void; + /** + * Asserts that the given argument is uninitialized. Throws an exception if initialized. + * + * @param arg is the argument to assert as uninitialized + * @param msg is the message to throw if arg is initialized (optional) + */ + static assertUninitialized(arg: any, msg?: any): void; + /** + * Asserts that the given arguments are equal. Throws an exception if not equal. + * + * @param arg1 is an argument to assert as equal + * @param arg2 is an argument to assert as equal + * @param msg is the message to throw if the arguments are not equal + */ + static assertEquals(arg1: any, arg2: any, msg?: any): void; + /** + * Asserts that the given arguments are not equal. Throws an exception if equal. + * + * @param arg1 is an argument to assert as not equal + * @param arg2 is an argument to assert as not equal + * @param msg is the message to throw if the arguments are equal + */ + static assertNotEquals(arg1: any, arg2: any, msg?: any): void; + /** + * Asserts that the given argument is an integer. + * + * @param arg is the argument to assert as an integer + * @param msg is the message to throw if the argument is not an integer + */ + static assertInt(arg: any, msg?: any): void; + /** + * Asserts that the given argument is a number. + * + * @param arg is the argument to assert as a number + * @param msg is the message to throw if the argument is not a number + */ + static assertNumber(arg: any, msg?: any): void; + /** + * Asserts that the given argument is a boolean. + * + * @param arg is the argument to assert as a boolean + * @param msg is the message to throw if the argument is not a boolean + */ + static assertBoolean(arg: any, msg?: any): void; + /** + * Asserts that the given argument is a string. + * + * @param arg is the argument to assert as a string + * @param msg is the message to throw if the argument is not a string + */ + static assertString(arg: any, msg?: any): void; + /** + * Asserts that the given argument is an array. + * + * @param arg is the argument to assert as an array + * @param msg is the message to throw if the argument is not an array + */ + static assertArray(arg: any, msg?: any): void; + /** + * Asserts that the given argument is a static. + * + * @param arg is the argument to assert as a static + * @param msg is the message to throw if the argument is not a static + */ + static assertFunction(arg: any, msg?: any): void; + /** + * Asserts that the given argument is an object with the given name. + * + * @param arg is the argument to test + * @param obj is an object to assert arg instanceof obj (optional) + * @param msg is the message to throw if the argument is not the specified object + */ + static assertObject(arg: any, obj: any, msg?: any): void; + /** + * Sets the child's prototype to the parent's prototype. + * + * @param child is the child class + * @param parent is the parent class + */ + static inheritsFrom(child: any, parent: any): void; + /** + * Invokes functions with arguments. + * + * arguments[0] is assumed to be an array of functions to invoke + * arguments[1...n] are args to invoke the functions with + */ + static invoke(): void; + /** + * Returns the power set of the given array. + * + * @param arr is the array to get the power set of + * @return [][] is the power set of the given array + */ + static getPowerSet(arr: any): any[]; + /** + * Returns the power set of the given array whose elements are the given size. + * + * @param arr is the array to get the power set of + * @param size is the required size of the elements within the power set + * returns [][] is the power set of the given array whose elements are the given size + */ + static getPowerSetOfLength(arr: any, size: any): any[]; + /** + * Returns an array of indices of the given size. + * + * @param size specifies the size to get indices for + * @return array of the given size with indices starting at 0 + */ + static getIndices(size: any): any[]; + /** + * Returns a new array containing unique elements of the given array. + * + * @param arr is the array to return unique elements from + * @return a new array with the given array's unique elements + */ + static toUniqueArray(arr: any): any; + /** + * Copies the given array. + * + * @param arr is the array to copy + * @return a copy of the given array + */ + static copyArray(arr: any): any[]; + /** + * Removes every instance of the given value from the given array. + * + * @param arr is the array to remove the value from + * @param val is the value to remove from the array + * @return true if the value is found and removed, false otherwise + */ + static remove(arr: any, val: any): boolean; + /** + * Returns a copy of the given array where each element is lowercase. + * + * @param arr is the array to convert to lowercase + * @return a copy of the given array where each element is lowercase + */ + static toLowerCaseArray(arr: any): any[]; + /** + * Listifies the given argument. + * + * @param arrOrElem is an array or an element in the array + * @return an array which is the given arg if it's an array or an array with the given arg as an element + */ + static listify(arrOrElem: any): any; + /** + * Indicates if the given array contains the given object. + * + * @param {any} arr - array that may or may not contain the object + * @param {any} obj - object to check for inclusion in the array + * @param {boolean} [compareByReference] - compare strictly by reference, forgoing deep equality check (default false) + * @return true if the array contains the object, false otherwise + */ + static arrayContains(arr: any, obj: any, compareByReference?: boolean): boolean; + /** + * Indicates if the given string contains the given substring. + * + * @param str is the string to search for a substring + * @param substring is the substring to searchin within the string + * @return true if the substring is within the string, false otherwise + */ + static strContains(str: any, substring: any): boolean; + /** + * Determines if two arrays are equal. + * + * @param arr1 is an array to compare + * @param arr2 is an array to compare + * @return true if the arrays are equal, false otherwise + */ + static arraysEqual(arr1: any, arr2: any): boolean; + /** + * Determines if two arguments are deep equal. + * + * @param arg1 is an argument to compare + * @param arg2 is an argument to compare + * @return true if the arguments are deep equals, false otherwise + */ + static equals(arg1: any, arg2: any): boolean; + /** + * Determines if two objects are deep equal. + * + * Undefined values are considered equal to non-existent keys. + * + * @param map1 is a map to compare + * @param map2 is a map to compare + * @return true if the maps have identical keys and values, false otherwise + */ + static objectsEqual(map1: any, map2: any): boolean; + /** + * Deletes properties from the object that are undefined. + * + * @param obj is the object to delete undefined keys from + */ + static deleteUndefinedKeys(obj: any): void; + /** + * Returns combinations of the given array of the given size. + * + * @param arr is the array to get combinations from + * @param combinationSize specifies the size of each combination + */ + static getCombinations(arr: any, combinationSize: any): any[]; + /** + * Gets an 'a' element that is downloadable when clicked. + * + * @param name is the name of the file to download + * @param contents are the string contents of the file to download + * @return 'a' dom element with downloadable file + */ + static getDownloadableA(name: any, contents: any): HTMLAnchorElement; + /** + * Copies properties in the given object to a new object. + * + * @param obj is object to copy properties for + * @return a new object with properties copied from the given object + */ + static copyProperties(obj: any): any; + /** + * Deletes all properties in the given object. + * + * @param obj is the object to delete properties from + */ + static deleteProperties(obj: any): void; + /** + * Indicates if the given string contains whitespace. + * + * @param str is the string to test + * @return true if the string contains whitespace, false otherwise + */ + static hasWhitespace(str: any): boolean; + /** + * Indicates if the given character is whitespace. + * + * @param char is the character to test + * @return true if the given character is whitespace, false otherwise + */ + static isWhitespace(char: any): boolean; + /** + * Indicates if the given character is a newline. + * + * @param char is the character to test + * @return true if the given character is a newline, false otherwise + */ + static isNewline(char: any): boolean; + /** + * Counts the number of non-whitespace characters in the given string. + * + * @param str is the string to count the number of non-whitespace characters in + * @return int is the number of non-whitespace characters in the given string + */ + static countNonWhitespaceCharacters(str: any): number; + /** + * Returns tokens separated by whitespace from the given string. + * + * @param str is the string to get tokens from + * @return string[] are the tokens separated by whitespace within the string + */ + static getWhitespaceTokens(str: any): any; + /** + * Returns lines separated by newlines from the given string. + * + * @param str is the string to get lines from + * @param string[] are the lines separated by newlines within the string + */ + static getLines(str: any): any; + /** + * Returns the document's first stylesheet which has no href. + * + * @return StyleSheet is the internal stylesheet + */ + static getInternalStyleSheet(): CSSStyleSheet; + /** + * Returns the document's internal stylesheet as text. + * + * @return str is the document's internal stylesheet + */ + static getInternalStyleSheetText(): string; + /** + * Manually builds an HTML document string. + * + * @param content specifies optional document content + * content.div is a pre-existing div to stringify and add to the body + * content.title is the title of the new tab + * content.dependencyPaths specifies paths to js, css, or img paths + * content.internalCss is css to embed in the html document + * content.metas are meta elements with keys/values to include + * @return str is the document string + */ + static buildHtmlDocument(content: any): string; + /** + * Opens the given div in a new window. + * + * @param content specifies optional window content + * content.div is a pre-existing div to stringify and add to the body + * content.title is the title of the new tab + * content.dependencyPaths specifies paths to js, css, or img paths + * content.internalCss is css to embed in the html document + * content.metas are meta elements with keys/values to include + * @param onLoad(err, window) is invoked with a reference to the window when available + */ + static newWindow(content: any, onLoad: any): void; + /** + * Converts the given image to a base64 encoded data url. + * + * @param img is the image to convert + * @param quality is a number between 0 and 1 specifying the image quality + */ + static imgToDataUrl(img: any, quality: any): string; + /** + * Determines if the image at the given URL is accessible. + * + * @param url is the url to an image + * @param timeout is the maximum time to wait + * @param onDone(bool) when the image is determined to be accessible or not + */ + static isImageAccessible(url: any, timeout: any, onDone: any): void; + /** + * Determines if the given file is a zip file. + * + * @param file is a file + * @return true if the given file is a zip file, false otherwise + */ + static isZipFile(file: any): any; + /** + * Determines if the given file is a json file. + * + * @param file is a file + * @return true if the given file is a json file, false otherwise + */ + static isJsonFile(file: any): any; + /** + * Determines if the given file is a txt file. + * + * @param file is a file + * @return true if the given file is a txt file, false otherwise + */ + static isTxtFile(file: any): any; + /** + * Fetches the given list of images. + * + * Prerequisite: async.js. + * + * @param paths are the paths to the images to fetch + * @param onDone(err, images) is called when done + */ + static getImages(paths: any, onDone: any): void; + /** + * Returns a string indentation of the given length; + * + * @param length is the length of the indentation + * @return {string} is an indentation string of the given length + */ + static getIndent(length: any): string; + static initPolyfills(): void; + /** + * Generates a v4 UUID. + * + * Source: https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript + */ + static getUUID(): string; + /** + * Indicates if the current environment is a browser. + * + * @return {boolean} true if the environment is a browser, false otherwise + */ + static isBrowser(): boolean; + /** + * Indicates if the current environment is Deno + * + * @return {boolean} true if the environment is Deno, false otherwise + */ + static isDeno(): boolean; + /** + * Indicates if the current environment is a firefox-based browser. + * + * @return {boolean} true if the environment is a firefox-based browser, false otherwise + */ + static isFirefox(): boolean; + /** + * Gets the IE version number. + * + * Credit: https://stackoverflow.com/questions/19999388/check-if-user-is-using-ie-with-jquery/21712356#21712356 + * + * @return the IE version number or null if not IE + */ + static getIEVersion(): number; + /** + * Gets a parameter value. + * + * Credit: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript + * + * @param name is the name of the parameter to get the value of + * @param url is a URL to get the parameter from, uses the window's current href if not given + * @return the parameter's value + */ + static getParameterByName(name: any, url: any): string; + /** + * Gets a non-cryptographically secure random number within a given range. + * + * @param min is the minimum range of the int to generate, inclusive + * @param max is the maximum range of the int to generate, inclusive + * + * Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random + */ + static getRandomInt(min: any, max: any): any; + /** + * Gets random ints. + * + * @param min is the minimum range of the ints to generate, inclusive + * @param max is the maximum range of the ints to generate, inclusive + * @param count is the number of random ints to get + */ + static getRandomInts(min: any, max: any, count: any): any[]; + /** + * Gets a given number of unique random ints within a range. + * + * @param min is the minimum range of the ints to generate, inclusive + * @param max is the maximum range of the ints to generate, inclusive + * @param count is the number of unique random ints to get + */ + static getUniqueRandomInts(min: any, max: any, count: any): any[]; + /** + * Randomize array element order in-place using Durstenfeld shuffle algorithm. + * + * Credit: https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array + */ + static shuffle(array: any): void; + /** + * Sorts an array by natural ordering. + * + * @param the array to sort + */ + static sort(array: any): void; + /** + * Sets the given value ensuring a previous value is not overwritten. + * + * TODO: remove for portability because function passing not supported in other languages, use reconcile only + * + * @param obj is the object to invoke the getter and setter on + * @param getFn gets the current value + * @param setFn sets the current value + * @param val is the value to set iff it does not overwrite a previous value + * @param [config] specifies reconciliation configuration + * config.resolveDefined uses defined value if true or undefined, undefined if false + * config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined + * config.resolveMax uses max over min if true, min over max if false, must be equal if undefined + * @param [errMsg] is the error message to throw if the values cannot be reconciled (optional) + */ + static safeSet(obj: any, getFn: any, setFn: any, val: any, config?: any, errMsg?: any): void; + /** + * Reconciles two values. + * + * TODO: remove custom error message + * + * @param val1 is a value to reconcile + * @param val2 is a value to reconcile + * @param [config] specifies reconciliation configuration + * config.resolveDefined uses defined value if true or undefined, undefined if false + * config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined + * config.resolveMax uses max over min if true, min over max if false, must be equal if undefined + * @param [errMsg] is the error message to throw if the values cannot be reconciled (optional) + * @return the reconciled value if reconcilable, throws error otherwise + */ + static reconcile(val1: any, val2: any, config?: any, errMsg?: any): any; + /** + * Returns a human-friendly key value line. + * + * @param key is the key + * @param value is the value + * @param indent indents the line + * @param newline specifies if the string should be terminated with a newline or not + * @param ignoreUndefined specifies if undefined values should return an empty string + * @return {string} is the human-friendly key value line + */ + static kvLine(key: any, value: any, indent?: number, newline?: boolean, ignoreUndefined?: boolean): string; + /** + * Replace big integers (16 or more consecutive digits) with strings in order + * to preserve numeric precision. + * + * @param {string} str is the string to be modified + * @return {string} the modified string with big numbers converted to strings + */ + static stringifyBigInts(str: any): any; + /** + * Print the current stack trace. + * + * @param {string} msg - optional message to print with the trace + */ + static printStackTrace(msg: any): void; + /** + * Wait for the duration. + * + * @param {number} durationMs - the duration to wait for in milliseconds + */ + static waitFor(durationMs: any): Promise; + /** + * Kill the given nodejs child process. + * + * @param {ChildProcess} process - the nodejs child process to kill + * @param {number | NodeJS.Signals} [signal] - the kill signal, e.g. SIGTERM, SIGKILL, SIGINT (default) + * @return {Promise} the exit code from killing the process + */ + static killProcess(process: ChildProcess, signal?: number | NodeJS.Signals): Promise; + /** + * Normalize a URI. + * + * @param {string} uri - the URI to normalize + * @return {string} the normalized URI + */ + static normalizeUri(uri: any): any; + /** + * Get the absolute value of the given bigint or number. + * + * @param {bigint | number} bi - the bigint or number to get the absolute value of + * @return {bigint | number} the absolute value of the given bigint or number + */ + static abs(bi: bigint | number): bigint | number; + /** + * Get an enum key name by value. + * + * @param {any} enumType is the enum type to get the key from + * @param {any} enumValue is the enum value to get the key for + * @return {string | undefined} the enum key name + */ + static getEnumKeyByValue(enumType: any, enumValue: any): string | undefined; + /** + * Resolve the given promise with a timeout. + * + * @param promise the promise to resolve within the timeout + * @param timeoutMs the timeout in milliseconds to resolve the promise + * @return the result of the promise unless error thrown + */ + static executeWithTimeout(promise: any, timeoutMs: any): Promise; +} diff --git a/dist/src/main/ts/common/GenUtils.js b/dist/src/main/ts/common/GenUtils.js new file mode 100644 index 000000000..4304d952b --- /dev/null +++ b/dist/src/main/ts/common/GenUtils.js @@ -0,0 +1,1520 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _async = _interopRequireDefault(require("async")); + + + + +/** + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Collection of general purpose utilities. + */ +class GenUtils { + + /** + * Indicates if the given argument is defined. + * + * @param {any} arg is the arg to test + * @return {boolean} true if the given arg is defined, false otherwise + */ + static isDefined(arg) { + return typeof arg !== 'undefined'; + } + + /** + * Indicates if the given argument is undefined. + * + * @param arg is the arg to test + * @return {boolean} true if the given arg is undefined, false otherwise + */ + static isUndefined(arg) { + return typeof arg === 'undefined'; + } + + /** + * Indicates if the given arg is initialized. + * + * @param {any} arg is the arg to test + * @return {boolean} true if the given arg is initialized, false otherwise + */ + static isInitialized(arg) { + return arg !== undefined && arg !== null; + } + + /** + * Indicates if the given arg is uninitialized. + * + * @param arg is the arg to test + * @return true if the given arg is uninitialized, false otherwise + */ + static isUninitialized(arg) { + if (!arg) return true; + return false; + } + + /** + * Indicates if the given argument is a number. + * + * @param {any} arg is the argument to test + * @return {boolean} true if the argument is a number, false otherwise + */ + static isNumber(arg) { + return !isNaN(parseFloat(arg)) && isFinite(arg); + } + + /** + * Indicates if the given argument is an integer. + * + * @param {any} arg is the argument to test + * @return {boolean} true if the given argument is an integer, false otherwise + */ + static isInt(arg) { + return arg === parseInt("" + Number(arg)) && !isNaN(arg) && !isNaN(parseInt(arg, 10)); + } + + /** + * Indicates if the given argument is an array. + * + * @param {any} arg is the argument to test as being an array + * @return {booolean} true if the argument is an array, false otherwise + */ + static isArray(arg) { + return arg instanceof Array && Array.isArray(arg); + } + + /** + * Indicates if the given argument is a string. + * + * @param {any} arg is the argument to test as being a string + * @return {boolean} true if the argument is a string, false otherwise + */ + static isString(arg) { + return typeof arg === 'string'; + } + + /** + * Determines if the given argument is a boolean. + * + * @param {any} arg is the argument to test as being a boolean + * @return {boolean} true if the argument is a boolean, false otherwise + */ + static isBoolean(arg) { + return typeof arg == typeof true; + } + + /** + * Determines if the given argument is a static. + * + * @param {any} arg is the argument to test as being a static + * @return {boolean} true if the argument is a static, false otherwise + */ + static isFunction(arg) { + return typeof arg === "function"; + } + + /** + * Indicates if the given argument is an object and optionally if it has the given constructor name. + * + * @param {any} arg is the argument to test + * @param {any} obj is an object to test arg instanceof obj (optional) + * @return {boolean} true if the given argument is an object and optionally has the given constructor name + */ + static isObject(arg, obj) { + if (!arg) return false; + if (typeof arg !== 'object') return false; + if (obj && !(arg instanceof obj)) return false; + return true; + } + + /** + * Determines if all alphabet characters in the given string are upper case. + * + * @param {string} str is the string to test + * @return {boolean} true if the string is upper case, false otherwise + */ + static isUpperCase(str) { + return str.toUpperCase() === str; + } + + /** + * Determines if all alphabet characters in the given string are lower case. + * + * @param str is the string to test + * @param true if the string is lower case, false otherwise + */ + static isLowerCase(str) { + return str.toLowerCase() === str; + } + + /** + * Asserts that the given argument is hex. + * + * @param arg is the argument to assert as hex + * @param msg is the message to throw if the argument is not hex + */ + static assertHex(str, msg) { + GenUtils.assertTrue(GenUtils.isHex(str), msg ? msg : "Argument asserted as hex but is not hex"); + } + + /** + * Indicates if the given argument is a hexidemal string. + * + * Credit: https://github.com/roryrjb/is-hex/blob/master/is-hex.js. + * + * @param str is the string to test + * @return true if the given string is hexidecimal, false otherwise + */ + static isHex(arg) { + if (typeof arg !== 'string') return false; + if (arg.length === 0) return false; + return (arg.match(/([0-9]|[a-f])/gim) || []).length === arg.length; + } + + /** + * Determines if the given string is base32. + */ + static isBase32(str) { + if (typeof str !== 'string') return false; + GenUtils.assertTrue(str.length > 0, "Cannot determine if empty string is base32"); + return /^[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]+$/.test(str); + } + + /** + * Asserts that the given argument is base58. + * + * @param arg is the argument to assert as base58 + * @param msg is the message to throw if the argument is not base58 + */ + static assertBase58(str, msg) { + GenUtils.assertTrue(GenUtils.isBase58(str), msg ? msg : "Argument asserted as base58 but is not base58"); + } + + /** + * Determines if the given string is base58. + */ + static isBase58(str) { + if (typeof str !== 'string') return false; + GenUtils.assertTrue(str.length > 0, "Cannot determine if empty string is base58"); + return /^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$/.test(str); + } + + /** + * Asserts that the given argument is base64. + * + * @param arg is the argument to assert as base64 + * @param msg is the message to throw if the argument is not base64 + */ + static assertBase64(str, msg) { + GenUtils.assertTrue(GenUtils.isBase64(str), msg ? msg : "Argument asserted as base64 but is not base64"); + } + + /** + * Determines if the given string is base64. + */ + static isBase64(str) { + if (typeof str !== 'string') return false; + GenUtils.assertTrue(str.length > 0, "Cannot determine if empty string is base64"); + try { + return btoa(atob(str)) == str; + } catch (err) { + return false; + } + } + + /** + * Throws an exception with the given message. + * + * @param msg defines the message to throw the exception with (optional) + */ + static fail(msg) { + throw new Error(msg ? msg : "Failure (no message)"); + } + + /** + * Asserts that the given condition is true. Throws an exception if not a boolean or false. + * + * @param {boolean} condition is the boolean to assert true + * @param {string} [msg] is the message to throw if condition is false (optional) + */ + static assertTrue(condition, msg) { + if (typeof condition !== 'boolean') throw new Error("Argument is not a boolean"); + if (!condition) throw new Error(msg ? msg : "Boolean asserted as true but was false"); + } + + /** + * Asserts that the given boolean is false. Throws an exception if not a boolean or true. + * + * @param bool is the boolean to assert false + * @param msg is the message to throw if bool is true (optional) + */ + static assertFalse(bool, msg) { + if (typeof bool !== 'boolean') throw new Error("Argument is not a boolean"); + if (bool) throw new Error(msg ? msg : "Boolean asserted as false but was true"); + } + + /** + * Asserts that the given argument is null. Throws an exception if not null. + * + * @param arg is the argument to assert null + * @param msg is the message to throw if arg is not null (optional) + */ + static assertNull(arg, msg) { + if (arg !== null) throw new Error(msg ? msg : "Argument asserted as null but was not null: " + arg); + } + + /** + * Asserts that the given argument is not null. Throws an exception if null. + * + * @param arg is the argument to assert not null + * @param msg is the message to throw if arg is null (optional) + */ + static assertNotNull(arg, msg) { + if (arg === null) throw new Error(msg ? msg : "Argument asserted as not null but was null"); + } + + /** + * Asserts that the given argument is defined. Throws an exception if undefined. + * + * @param arg is the argument to assert defined + * @param msg is the message to throw if arg is undefined (optional) + */ + static assertDefined(arg, msg) { + if (GenUtils.isUndefined(arg)) throw new Error(msg ? msg : "Argument asserted as defined but was undefined"); + } + + /** + * Asserts that the given argument is undefined. Throws an exception if defined. + * + * @param arg is the argument to assert undefined + * @param msg is the message to throw if arg is defined (optional) + */ + static assertUndefined(arg, msg) { + if (GenUtils.isDefined(arg)) throw new Error(msg ? msg : "Argument asserted as undefined but was defined: " + arg); + } + + /** + * Asserts that the given argument is initialized. Throws an exception if not initialized. + * + * @param arg is the argument to assert as initialized + * @param msg is the message to throw if arg is not initialized (optional) + */ + static assertInitialized(arg, msg) { + if (GenUtils.isUninitialized(arg)) { + throw new Error(msg ? msg : "Argument asserted as initialized but was " + arg); + } + } + + /** + * Asserts that the given argument is uninitialized. Throws an exception if initialized. + * + * @param arg is the argument to assert as uninitialized + * @param msg is the message to throw if arg is initialized (optional) + */ + static assertUninitialized(arg, msg) { + if (GenUtils.isInitialized(arg)) throw new Error(msg ? msg : "Argument asserted as uninitialized but was initialized"); + } + + /** + * Asserts that the given arguments are equal. Throws an exception if not equal. + * + * @param arg1 is an argument to assert as equal + * @param arg2 is an argument to assert as equal + * @param msg is the message to throw if the arguments are not equal + */ + static assertEquals(arg1, arg2, msg) { + GenUtils.assertTrue(GenUtils.equals(arg1, arg2), msg ? msg : "Arguments asserted as equal but are not equal: " + arg1 + " vs " + arg2); + } + + /** + * Asserts that the given arguments are not equal. Throws an exception if equal. + * + * @param arg1 is an argument to assert as not equal + * @param arg2 is an argument to assert as not equal + * @param msg is the message to throw if the arguments are equal + */ + static assertNotEquals(arg1, arg2, msg) { + if (arg1 === arg2) throw new Error(msg ? msg : "Arguments asserted as not equal but are equal: " + arg1 + " vs " + arg2); + } + + /** + * Asserts that the given argument is an integer. + * + * @param arg is the argument to assert as an integer + * @param msg is the message to throw if the argument is not an integer + */ + static assertInt(arg, msg) { + if (!GenUtils.isInt(arg)) throw new Error(msg ? msg : "Argument asserted as an integer but is not an integer"); + } + + /** + * Asserts that the given argument is a number. + * + * @param arg is the argument to assert as a number + * @param msg is the message to throw if the argument is not a number + */ + static assertNumber(arg, msg) { + if (!GenUtils.isNumber(arg)) throw new Error(msg ? msg : "Argument asserted as a number but is not a number"); + } + + /** + * Asserts that the given argument is a boolean. + * + * @param arg is the argument to assert as a boolean + * @param msg is the message to throw if the argument is not a boolean + */ + static assertBoolean(arg, msg) { + if (!GenUtils.isBoolean(arg)) throw new Error(msg ? msg : "Argument asserted as a boolean but is not a boolean"); + } + + /** + * Asserts that the given argument is a string. + * + * @param arg is the argument to assert as a string + * @param msg is the message to throw if the argument is not a string + */ + static assertString(arg, msg) { + if (!GenUtils.isString(arg)) throw new Error(msg ? msg : "Argument asserted as a string but is not a string: " + arg); + } + + /** + * Asserts that the given argument is an array. + * + * @param arg is the argument to assert as an array + * @param msg is the message to throw if the argument is not an array + */ + static assertArray(arg, msg) { + if (!GenUtils.isArray(arg)) throw new Error(msg ? msg : "Argument asserted as an array but is not an array"); + } + + /** + * Asserts that the given argument is a static. + * + * @param arg is the argument to assert as a static + * @param msg is the message to throw if the argument is not a static + */ + static assertFunction(arg, msg) { + if (!GenUtils.isFunction(arg)) throw new Error(msg ? msg : "Argument asserted as a static but is not a static"); + } + + /** + * Asserts that the given argument is an object with the given name. + * + * @param arg is the argument to test + * @param obj is an object to assert arg instanceof obj (optional) + * @param msg is the message to throw if the argument is not the specified object + */ + static assertObject(arg, obj, msg) { + GenUtils.assertInitialized(arg, msg); + if (obj) { + if (!GenUtils.isObject(arg, obj)) throw new Error(msg ? msg : "Argument asserted as object '" + obj.name + "' but was not"); + } else { + if (!GenUtils.isObject(arg)) throw new Error(msg ? msg : "Argument asserted as object but was not"); + } + } + + /** + * Sets the child's prototype to the parent's prototype. + * + * @param child is the child class + * @param parent is the parent class + */ + static inheritsFrom(child, parent) { + child.prototype = Object.create(parent.prototype); + child.prototype.constructor = child; + } + + /** + * Invokes functions with arguments. + * + * arguments[0] is assumed to be an array of functions to invoke + * arguments[1...n] are args to invoke the functions with + */ + static invoke() { + let fns = arguments[0]; + let args = []; + for (let i = 1; i < arguments.length; i++) args.push(arguments[i]); + for (let i = 0; i < fns.length; i++) { + GenUtils.assertFunction(fns[i], "Functions[" + i + "] is not a static"); + fns[i].apply(null, args); + } + } + + /** + * Returns the power set of the given array. + * + * @param arr is the array to get the power set of + * @return [][] is the power set of the given array + */ + static getPowerSet(arr) { + let fn = function (n, src, got, all) { + if (n == 0) { + if (got.length > 0) { + all[all.length] = got; + } + return; + } + for (let j = 0; j < src.length; j++) { + fn(n - 1, src.slice(j + 1), got.concat([src[j]]), all); + } + return; + }; + let all = []; + all.push([]); + for (let i = 0; i < arr.length; i++) { + fn(i, arr, [], all); + } + all.push(arr); + return all; + } + + /** + * Returns the power set of the given array whose elements are the given size. + * + * @param arr is the array to get the power set of + * @param size is the required size of the elements within the power set + * returns [][] is the power set of the given array whose elements are the given size + */ + static getPowerSetOfLength(arr, size) { + GenUtils.assertInitialized(arr); + GenUtils.assertInitialized(size); + GenUtils.assertTrue(size >= 1); + let powerSet = GenUtils.getPowerSet(arr); + let powerSetOfLength = []; + for (let i = 0; i < powerSet.length; i++) { + if (powerSet[i].length === size) { + powerSetOfLength.push(powerSet[i]); + } + } + return powerSetOfLength; + } + + /** + * Returns an array of indices of the given size. + * + * @param size specifies the size to get indices for + * @return array of the given size with indices starting at 0 + */ + static getIndices(size) { + let indices = []; + for (let i = 0; i < size; i++) { + indices.push(i); + } + return indices; + } + + /** + * Returns a new array containing unique elements of the given array. + * + * @param arr is the array to return unique elements from + * @return a new array with the given array's unique elements + */ + static toUniqueArray(arr) { + return arr.filter(function (value, index, self) { + return self.indexOf(value) === index; + }); + } + + /** + * Copies the given array. + * + * @param arr is the array to copy + * @return a copy of the given array + */ + static copyArray(arr) { + GenUtils.assertArray(arr); + let copy = []; + for (let i = 0; i < arr.length; i++) copy.push(arr[i]); + return copy; + } + + /** + * Removes every instance of the given value from the given array. + * + * @param arr is the array to remove the value from + * @param val is the value to remove from the array + * @return true if the value is found and removed, false otherwise + */ + static remove(arr, val) { + let found = false; + for (let i = arr.length - 1; i >= 0; i--) { + if (arr[i] === val) { + arr.splice(i, 1); + found = true; + i--; + } + } + return found; + } + + /** + * Returns a copy of the given array where each element is lowercase. + * + * @param arr is the array to convert to lowercase + * @return a copy of the given array where each element is lowercase + */ + static toLowerCaseArray(arr) { + let arr2 = []; + for (let i = 0; i < arr.length; i++) { + arr2.push(arr[i].toLowerCase()); + } + return arr2; + } + + /** + * Listifies the given argument. + * + * @param arrOrElem is an array or an element in the array + * @return an array which is the given arg if it's an array or an array with the given arg as an element + */ + static listify(arrOrElem) { + return GenUtils.isArray(arrOrElem) ? arrOrElem : [arrOrElem]; + } + + /** + * Indicates if the given array contains the given object. + * + * @param {any} arr - array that may or may not contain the object + * @param {any} obj - object to check for inclusion in the array + * @param {boolean} [compareByReference] - compare strictly by reference, forgoing deep equality check (default false) + * @return true if the array contains the object, false otherwise + */ + static arrayContains(arr, obj, compareByReference = false) { + GenUtils.assertTrue(GenUtils.isArray(arr)); + for (let i = 0; i < arr.length; i++) { + if (arr[i] === obj) return true; + if (!compareByReference && GenUtils.equals(arr[i], obj)) return true; + } + return false; + } + + /** + * Indicates if the given string contains the given substring. + * + * @param str is the string to search for a substring + * @param substring is the substring to searchin within the string + * @return true if the substring is within the string, false otherwise + */ + static strContains(str, substring) { + return str.indexOf(substring) > -1; + } + + /** + * Determines if two arrays are equal. + * + * @param arr1 is an array to compare + * @param arr2 is an array to compare + * @return true if the arrays are equal, false otherwise + */ + static arraysEqual(arr1, arr2) { + if (arr1 === arr2) return true; + if (arr1 == null && arr2 == null) return true; + if (arr1 == null || arr2 == null) return false; + if (typeof arr1 === 'undefined' && typeof arr2 === 'undefined') return true; + if (typeof arr1 === 'undefined' || typeof arr2 === 'undefined') return false; + if (!GenUtils.isArray(arr1)) throw new Error("First argument is not an array"); + if (!GenUtils.isArray(arr2)) throw new Error("Second argument is not an array"); + if (arr1.length != arr2.length) return false; + for (let i = 0; i < arr1.length; ++i) { + if (!GenUtils.equals(arr1[i], arr2[i])) return false; + } + return true; + } + + /** + * Determines if two arguments are deep equal. + * + * @param arg1 is an argument to compare + * @param arg2 is an argument to compare + * @return true if the arguments are deep equals, false otherwise + */ + static equals(arg1, arg2) { + if (GenUtils.isArray(arg1) && GenUtils.isArray(arg2)) return GenUtils.arraysEqual(arg1, arg2); + if (GenUtils.isObject(arg1) && GenUtils.isObject(arg2)) return GenUtils.objectsEqual(arg1, arg2); + return arg1 === arg2; + } + + /** + * Determines if two objects are deep equal. + * + * Undefined values are considered equal to non-existent keys. + * + * @param map1 is a map to compare + * @param map2 is a map to compare + * @return true if the maps have identical keys and values, false otherwise + */ + static objectsEqual(map1, map2) { + let keys1 = Object.keys(map1); + let keys2 = Object.keys(map2); + + // compare each key1 to keys2 + for (let key1 of keys1) { + let found = false; + for (let key2 of keys2) { + if (key1 === key2) { + if (!GenUtils.equals(map1[key1], map2[key2])) return false; + found = true; + break; + } + } + if (!found && map1[key1] !== undefined) return false; // allows undefined values to equal non-existent keys + } + + // compare each key2 to keys1 + for (let key2 of keys2) { + let found = false; + for (let key1 of keys1) { + if (key1 === key2) { + found = true; // no need to re-compare which was done earlier + break; + } + } + if (!found && map2[key2] !== undefined) return false; // allows undefined values to equal non-existent keys + } + return true; + + // TODO: support strict option? + // if (strict) { + // let keys1 = Object.keys(map1); + // if (keys1.length !== Object.keys(map2).length) return false; + // for (let i = 0; i < keys1.length; i++) { + // let key = Object.keys(map1)[i]; + // if (!GenUtils.equals(map1[key], map2[key])) return false; + // } + // } + } + + /** + * Deletes properties from the object that are undefined. + * + * @param obj is the object to delete undefined keys from + */ + static deleteUndefinedKeys(obj) { + for (let key of Object.keys(obj)) { + if (obj[key] === undefined) delete obj[key]; + } + } + + /** + * Returns combinations of the given array of the given size. + * + * @param arr is the array to get combinations from + * @param combinationSize specifies the size of each combination + */ + static getCombinations(arr, combinationSize) { + + // validate input + GenUtils.assertInitialized(arr); + GenUtils.assertInitialized(combinationSize); + GenUtils.assertTrue(combinationSize >= 1); + + // get combinations of array indices of the given size + let indexCombinations = GenUtils.getPowerSetOfLength(GenUtils.getIndices(arr.length), combinationSize); + + // collect combinations from each combination of array indices + let combinations = []; + for (let indexCombinationsIdx = 0; indexCombinationsIdx < indexCombinations.length; indexCombinationsIdx++) { + + // get combination of array indices + let indexCombination = indexCombinations[indexCombinationsIdx]; + + // build combination from array + let combination = []; + for (let indexCombinationIdx = 0; indexCombinationIdx < indexCombination.length; indexCombinationIdx++) { + combination.push(arr[indexCombination[indexCombinationIdx]]); + } + + // add to combinations + combinations.push(combination); + } + + return combinations; + } + + /** + * Gets an 'a' element that is downloadable when clicked. + * + * @param name is the name of the file to download + * @param contents are the string contents of the file to download + * @return 'a' dom element with downloadable file + */ + static getDownloadableA(name, contents) { + let a = window.document.createElement('a'); + a.href = window.URL.createObjectURL(new Blob([contents], { type: 'text/plain' })); + a.download = name; + a.target = "_blank"; + a.innerHTML = name; + return a; + } + + /** + * Copies properties in the given object to a new object. + * + * @param obj is object to copy properties for + * @return a new object with properties copied from the given object + */ + static copyProperties(obj) { + return JSON.parse(JSON.stringify(obj)); + } + + /** + * Deletes all properties in the given object. + * + * @param obj is the object to delete properties from + */ + static deleteProperties(obj) { + let props = []; + for (let prop in obj) props.push(prop); // TODO: if (obj.hasOwnProperty(prop)) { ... + for (let i = 0; i < props.length; i++) delete obj[props[i].toString()]; + } + + /** + * Indicates if the given string contains whitespace. + * + * @param str is the string to test + * @return true if the string contains whitespace, false otherwise + */ + static hasWhitespace(str) { + return /\s/g.test(str); + } + + /** + * Indicates if the given character is whitespace. + * + * @param char is the character to test + * @return true if the given character is whitespace, false otherwise + */ + static isWhitespace(char) { + return /\s/.test(char); + } + + /** + * Indicates if the given character is a newline. + * + * @param char is the character to test + * @return true if the given character is a newline, false otherwise + */ + static isNewline(char) { + return char === '\n' || char === '\r'; + } + + /** + * Counts the number of non-whitespace characters in the given string. + * + * @param str is the string to count the number of non-whitespace characters in + * @return int is the number of non-whitespace characters in the given string + */ + static countNonWhitespaceCharacters(str) { + let count = 0; + for (let i = 0; i < str.length; i++) { + if (!GenUtils.isWhitespace(str.charAt(i))) count++; + } + return count; + } + + /** + * Returns tokens separated by whitespace from the given string. + * + * @param str is the string to get tokens from + * @return string[] are the tokens separated by whitespace within the string + */ + static getWhitespaceTokens(str) { + return str.match(/\S+/g); + } + + /** + * Returns lines separated by newlines from the given string. + * + * @param str is the string to get lines from + * @param string[] are the lines separated by newlines within the string + */ + static getLines(str) { + return str.match(/[^\r\n]+/g); + } + + /** + * Returns the document's first stylesheet which has no href. + * + * @return StyleSheet is the internal stylesheet + */ + static getInternalStyleSheet() { + for (let i = 0; i < document.styleSheets.length; i++) { + let styleSheet = document.styleSheets[i]; + if (!styleSheet.href) return styleSheet; + } + return null; + } + + /** + * Returns the document's internal stylesheet as text. + * + * @return str is the document's internal stylesheet + */ + static getInternalStyleSheetText() { + let internalCss = ""; + let internalStyleSheet = GenUtils.getInternalStyleSheet(); + if (!internalStyleSheet) return null; + for (let i = 0; i < internalStyleSheet.cssRules.length; i++) { + internalCss += internalStyleSheet.cssRules[i].cssText + "\n"; + } + return internalCss; + } + + /** + * Manually builds an HTML document string. + * + * @param content specifies optional document content + * content.div is a pre-existing div to stringify and add to the body + * content.title is the title of the new tab + * content.dependencyPaths specifies paths to js, css, or img paths + * content.internalCss is css to embed in the html document + * content.metas are meta elements with keys/values to include + * @return str is the document string + */ + static buildHtmlDocument(content) { + let str = ""; + str += ""; + + // add metas + if (content.metas) { + let metas = GenUtils.listify(content.metas); + for (let i = 0; i < metas.length; i++) { + let meta = metas[i]; + let elem = document.createElement("meta"); + for (let prop in meta) { + if (meta.hasOwnProperty(prop)) { + elem.setAttribute(prop.toString(), meta[prop.toString()]); + } + } + str += elem.outerHTML; + } + } + + // add title and internal css + str += content.title ? "" + content.title + "" : ""; + str += content.internalCss ? "" : ""; + + // add dependency paths + if (content.dependencyPaths) { + let dependencyPaths = GenUtils.listify(content.dependencyPaths); + for (let i = 0; i < dependencyPaths.length; i++) { + let dependencyPath = dependencyPaths[i]; + if (dependencyPath.endsWith(".js")) str += "";else + if (dependencyPath.endsWith(".css")) str += "";else + if (dependencyPath.endsWith(".png") || dependencyPath.endsWith(".img")) str += "";else + throw new Error("Unrecognized dependency path extension: " + dependencyPath); + } + } + str += ""; + if (content.div) str += $("
").append(content.div.clone()).html(); // add cloned div as string + str += ""; + return str; + } + + /** + * Opens the given div in a new window. + * + * @param content specifies optional window content + * content.div is a pre-existing div to stringify and add to the body + * content.title is the title of the new tab + * content.dependencyPaths specifies paths to js, css, or img paths + * content.internalCss is css to embed in the html document + * content.metas are meta elements with keys/values to include + * @param onLoad(err, window) is invoked with a reference to the window when available + */ + static newWindow(content, onLoad) { + let onLoadCalled = false; + let w = window.open(); + if (!GenUtils.isInitialized(w) || !GenUtils.isInitialized(w.document)) { + onLoadOnce(new Error("Could not get window reference")); + return; + } + w.opener = null; + w.document.write(GenUtils.buildHtmlDocument(content)); + w.addEventListener('load', function () { + onLoadOnce(null, w); + }); + w.document.close(); + + // prevents onLoad() from being called multiple times + function onLoadOnce(err, window) { + if (onLoadCalled) return; + onLoadCalled = true; + if (onLoad) onLoad(err, window); + } + } + + /** + * Converts the given image to a base64 encoded data url. + * + * @param img is the image to convert + * @param quality is a number between 0 and 1 specifying the image quality + */ + static imgToDataUrl(img, quality) { + let canvas = document.createElement('canvas'); + canvas.height = img.naturalHeight; + canvas.width = img.naturalWidth; + let context = canvas.getContext('2d'); + context.drawImage(img, 0, 0); + return canvas.toDataURL(quality); + } + + /** + * Determines if the image at the given URL is accessible. + * + * @param url is the url to an image + * @param timeout is the maximum time to wait + * @param onDone(bool) when the image is determined to be accessible or not + */ + static isImageAccessible(url, timeout, onDone) { + + // track return so it only executes once + let returned = false; + + // attempt to load favicon + let img = new Image(); + img.onload = onResponse; + img.onerror = onResponse; + img.src = url + "?" + +new Date(); // trigger image load with cache buster + + // nest failure timeouts to give response a chance when browser is under load + setTimeout(function () { + setImmediate(function () { + setImmediate(function () { + setImmediate(function () { + if (!returned) { + returned = true; + onDone(false); + } + }); + }); + }); + }, timeout); + + function onResponse(e) { + if (returned) return; + returned = true; + if (typeof e === 'undefined' || e.type === "error") onDone(false);else + onDone(true); + } + } + + /** + * Determines if the given file is a zip file. + * + * @param file is a file + * @return true if the given file is a zip file, false otherwise + */ + static isZipFile(file) { + return file.name.endsWith(".zip") || file.type === 'application/zip'; + } + + /** + * Determines if the given file is a json file. + * + * @param file is a file + * @return true if the given file is a json file, false otherwise + */ + static isJsonFile(file) { + return file.name.endsWith(".json") || file.type === 'application/json'; + } + + /** + * Determines if the given file is a txt file. + * + * @param file is a file + * @return true if the given file is a txt file, false otherwise + */ + static isTxtFile(file) { + return file.name.endsWith(".txt") || file.type === 'text/plain'; + } + + /** + * Fetches the given list of images. + * + * Prerequisite: async.js. + * + * @param paths are the paths to the images to fetch + * @param onDone(err, images) is called when done + */ + static getImages(paths, onDone) { + + // listify paths + if (!GenUtils.isArray(paths)) { + GenUtils.assertTrue(GenUtils.isString(paths)); + paths = [paths]; + } + + // collect functions to fetch images + let funcs = []; + for (let i = 0; i < paths.length; i++) { + funcs.push(loadFunc(paths[i])); + } + + // fetch in parallel + _async.default.parallel(funcs, onDone); + + // callback static to fetch a single image + function loadFunc(path) { + return function (onDone) { + let img = new Image(); + img.onload = function () {onDone(null, img);}; + img.onerror = function () {onDone(new Error("Cannot load image: " + path));}; + img.src = path; + }; + } + } + + /** + * Returns a string indentation of the given length; + * + * @param length is the length of the indentation + * @return {string} is an indentation string of the given length + */ + static getIndent(length) { + let str = ""; + for (let i = 0; i < length; i++) str += ' '; // two spaces + return str; + } + + static initPolyfills() { + + // Polyfill Object.assign() + // Credit: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign + if (typeof Object.assign != 'function') { + // Must be writable: true, enumerable: false, configurable: true + Object.defineProperty(Object, "assign", { + value: function assign(target, varArgs) {// .length of static is 2 + 'use strict'; + if (target == null) {// TypeError if undefined or null + throw new TypeError('Cannot convert undefined or null to object'); + } + + let to = Object(target); + + for (let index = 1; index < arguments.length; index++) { + let nextSource = arguments[index]; + + if (nextSource != null) {// Skip over if undefined or null + for (let nextKey in nextSource) { + // Avoid bugs when hasOwnProperty is shadowed + if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { + to[nextKey] = nextSource[nextKey]; + } + } + } + } + return to; + }, + writable: true, + configurable: true + }); + } + + /** + * Polyfill str.startsWith(searchString, position). + * + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith#Polyfill + */ + String.prototype.startsWith = function (searchString, position) { + return this.substr(position || 0, searchString.length) === searchString; + }; + + /** + * Polyfill str.endsWith(searchString, position). + * + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith#Polyfill + */ + String.prototype.endsWith = function (searchString, position) { + if (!(position < this.length)) position = this.length; // works better than >= because it compensates for NaN + else position |= 0; // round position + return this.substr(position - searchString.length, searchString.length) === searchString; + }; + } + + /** + * Generates a v4 UUID. + * + * Source: https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript + */ + static getUUID() { + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + let r = Math.random() * 16 | 0,v = c == 'x' ? r : r & 0x3 | 0x8; + return v.toString(16); + }); + } + + /** + * Indicates if the current environment is a browser. + * + * @return {boolean} true if the environment is a browser, false otherwise + */ + static isBrowser() { + let isWorker = typeof importScripts === 'function'; + let isBrowserMain = new Function("try {return this===window;}catch(e){return false;}")(); + let isJsDom = isBrowserMain ? new Function("try {return window.navigator.userAgent.includes('jsdom');}catch(e){return false;}")() : false; + return isWorker || isBrowserMain && !isJsDom; + } + + /** + * Indicates if the current environment is Deno + * + * @return {boolean} true if the environment is Deno, false otherwise + */ + static isDeno() { + return typeof Deno === "object" && Deno.hasOwnProperty("version") && typeof Deno.version === "object" && Deno.version.hasOwnProperty("deno") && typeof Deno.version.deno === "string"; + } + + /** + * Indicates if the current environment is a firefox-based browser. + * + * @return {boolean} true if the environment is a firefox-based browser, false otherwise + */ + static isFirefox() { + return this.isBrowser() && navigator.userAgent.indexOf("Firefox") > 0; + } + + /** + * Gets the IE version number. + * + * Credit: https://stackoverflow.com/questions/19999388/check-if-user-is-using-ie-with-jquery/21712356#21712356 + * + * @return the IE version number or null if not IE + */ + static getIEVersion() { + let ua = window.navigator.userAgent; + + let msie = ua.indexOf('MSIE '); + if (msie > 0) { + // IE 10 or older => return version number + return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10); + } + + let trident = ua.indexOf('Trident/'); + if (trident > 0) { + // IE 11 => return version number + let rv = ua.indexOf('rv:'); + return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10); + } + + let edge = ua.indexOf('Edge/'); + if (edge > 0) { + // Edge (IE 12+) => return version number + return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10); + } + + // other browser + return null; + } + + /** + * Gets a parameter value. + * + * Credit: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript + * + * @param name is the name of the parameter to get the value of + * @param url is a URL to get the parameter from, uses the window's current href if not given + * @return the parameter's value + */ + static getParameterByName(name, url) { + if (!url) url = window.location.href; + name = name.replace(/[\[\]]/g, "\\$&"); + let regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),results = regex.exec(url); + if (!results) return null; + if (!results[2]) return ''; + return decodeURIComponent(results[2].replace(/\+/g, " ")); + } + + /** + * Gets a non-cryptographically secure random number within a given range. + * + * @param min is the minimum range of the int to generate, inclusive + * @param max is the maximum range of the int to generate, inclusive + * + * Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random + */ + static getRandomInt(min, max) { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + /** + * Gets random ints. + * + * @param min is the minimum range of the ints to generate, inclusive + * @param max is the maximum range of the ints to generate, inclusive + * @param count is the number of random ints to get + */ + static getRandomInts(min, max, count) { + GenUtils.assertTrue(typeof count === "number"); + let ints = []; + for (let i = 0; i < count; i++) ints.push(GenUtils.getRandomInt(min, max)); + return ints; + } + + /** + * Gets a given number of unique random ints within a range. + * + * @param min is the minimum range of the ints to generate, inclusive + * @param max is the maximum range of the ints to generate, inclusive + * @param count is the number of unique random ints to get + */ + static getUniqueRandomInts(min, max, count) { + let ints = []; + GenUtils.assertTrue(count >= 0); + GenUtils.assertTrue(max - min + 1 >= count); + while (ints.length < count) { + let randomInt = GenUtils.getRandomInt(min, max); + if (!ints.includes(randomInt)) ints.push(randomInt); + } + return ints; + } + + /** + * Randomize array element order in-place using Durstenfeld shuffle algorithm. + * + * Credit: https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array + */ + static shuffle(array) { + for (var i = array.length - 1; i > 0; i--) { + var j = Math.floor(Math.random() * (i + 1)); + var temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + } + + /** + * Sorts an array by natural ordering. + * + * @param the array to sort + */ + static sort(array) { + array.sort((a, b) => a === b ? 0 : a > b ? 1 : -1); + } + + /** + * Sets the given value ensuring a previous value is not overwritten. + * + * TODO: remove for portability because function passing not supported in other languages, use reconcile only + * + * @param obj is the object to invoke the getter and setter on + * @param getFn gets the current value + * @param setFn sets the current value + * @param val is the value to set iff it does not overwrite a previous value + * @param [config] specifies reconciliation configuration + * config.resolveDefined uses defined value if true or undefined, undefined if false + * config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined + * config.resolveMax uses max over min if true, min over max if false, must be equal if undefined + * @param [errMsg] is the error message to throw if the values cannot be reconciled (optional) + */ + static safeSet(obj, getFn, setFn, val, config, errMsg) { + let curVal = getFn.call(obj); + let reconciledVal = GenUtils.reconcile(curVal, val, config, errMsg); + if (curVal !== reconciledVal) setFn.call(obj, reconciledVal); + } + + /** + * Reconciles two values. + * + * TODO: remove custom error message + * + * @param val1 is a value to reconcile + * @param val2 is a value to reconcile + * @param [config] specifies reconciliation configuration + * config.resolveDefined uses defined value if true or undefined, undefined if false + * config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined + * config.resolveMax uses max over min if true, min over max if false, must be equal if undefined + * @param [errMsg] is the error message to throw if the values cannot be reconciled (optional) + * @return the reconciled value if reconcilable, throws error otherwise + */ + static reconcile(val1, val2, config, errMsg) { + + // check for equality + if (val1 === val2) return val1; + + // check for bigint equality + let comparison; // save comparison for later if applicable + if (typeof val1 === "bigint" && typeof val2 === "bigint") { + if (val1 === val2) return val1; + } + + // resolve one value defined + if (val1 === undefined || val2 === undefined) { + if (config && config.resolveDefined === false) return undefined; // use undefined + else return val1 === undefined ? val2 : val1; // use defined value + } + + // resolve different booleans + if (config && config.resolveTrue !== undefined && typeof val1 === "boolean" && typeof val2 === "boolean") { + _assert.default.equal(typeof config.resolveTrue, "boolean"); + return config.resolveTrue; + } + + // resolve different numbers + if (config && config.resolveMax !== undefined) { + _assert.default.equal(typeof config.resolveMax, "boolean"); + + // resolve js numbers + if (typeof val1 === "number" && typeof val2 === "number") { + return config.resolveMax ? Math.max(val1, val2) : Math.min(val1, val2); + } + + // resolve bigints + if (typeof val1 === "bigint" && typeof val2 === "bigint") { + return config.resolveMax ? comparison < 0 ? val2 : val1 : comparison < 0 ? val1 : val2; + } + } + + // assert deep equality + _assert.default.deepEqual(val1, val2, errMsg ? errMsg : "Cannot reconcile values " + val1 + " and " + val2 + " with config: " + JSON.stringify(config)); + return val1; + } + + /** + * Returns a human-friendly key value line. + * + * @param key is the key + * @param value is the value + * @param indent indents the line + * @param newline specifies if the string should be terminated with a newline or not + * @param ignoreUndefined specifies if undefined values should return an empty string + * @return {string} is the human-friendly key value line + */ + static kvLine(key, value, indent = 0, newline = true, ignoreUndefined = true) { + if (value === undefined && ignoreUndefined) return ""; + return GenUtils.getIndent(indent) + key + ": " + value + (newline ? '\n' : ""); + } + + /** + * Replace big integers (16 or more consecutive digits) with strings in order + * to preserve numeric precision. + * + * @param {string} str is the string to be modified + * @return {string} the modified string with big numbers converted to strings + */ + static stringifyBigInts(str) { + return str.replace(/("[^"]*"\s*:\s*)(\d{16,})/g, '$1"$2"'); + } + + /** + * Print the current stack trace. + * + * @param {string} msg - optional message to print with the trace + */ + static printStackTrace(msg) { + try {throw new Error(msg);} + catch (err) {console.error(err.stack);} + } + + /** + * Wait for the duration. + * + * @param {number} durationMs - the duration to wait for in milliseconds + */ + static async waitFor(durationMs) { + return new Promise(function (resolve) {setTimeout(resolve, durationMs);}); + } + + /** + * Kill the given nodejs child process. + * + * @param {ChildProcess} process - the nodejs child process to kill + * @param {number | NodeJS.Signals} [signal] - the kill signal, e.g. SIGTERM, SIGKILL, SIGINT (default) + * @return {Promise} the exit code from killing the process + */ + static async killProcess(process, signal) { + return new Promise((resolve, reject) => { + process.on("exit", function (code, signal) {resolve(code);}); + process.on("error", function (err) {reject(err);}); + try { + if (!process.kill(signal === undefined ? "SIGINT" : signal)) resolve(undefined); // resolve immediately if not running + } catch (err) { + reject(err); + } + }); + } + + /** + * Normalize a URI. + * + * @param {string} uri - the URI to normalize + * @return {string} the normalized URI + */ + static normalizeUri(uri) { + if (!uri) throw Error("Must provide URI to normalize"); + uri = uri.replace(/\/$/, ""); // strip trailing slash + if (!new RegExp("^\\w+://.+").test(uri)) uri = "http://" + uri; // assume http if protocol not given + return uri; + } + + /** + * Get the absolute value of the given bigint or number. + * + * @param {bigint | number} bi - the bigint or number to get the absolute value of + * @return {bigint | number} the absolute value of the given bigint or number + */ + static abs(bi) { + return bi < 0 ? -bi : bi; + } + + /** + * Get an enum key name by value. + * + * @param {any} enumType is the enum type to get the key from + * @param {any} enumValue is the enum value to get the key for + * @return {string | undefined} the enum key name + */ + static getEnumKeyByValue(enumType, enumValue) { + for (let key in enumType) { + if (enumType[key] === enumValue) return key; + } + return undefined; + } + + /** + * Resolve the given promise with a timeout. + * + * @param promise the promise to resolve within the timeout + * @param timeoutMs the timeout in milliseconds to resolve the promise + * @return the result of the promise unless error thrown + */ + static async executeWithTimeout(promise, timeoutMs) { + return new Promise((resolve, reject) => { + const timeoutId = setTimeout(() => { + reject('Execution timed out in ' + timeoutMs + ' milliseconds'); + }, timeoutMs); + promise.then( + (result) => { + clearTimeout(timeoutId); + resolve(result); + }, + (error) => { + clearTimeout(timeoutId); + reject(error); + } + ); + }); + } +}exports.default = GenUtils; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfYXN5bmMiLCJHZW5VdGlscyIsImlzRGVmaW5lZCIsImFyZyIsImlzVW5kZWZpbmVkIiwiaXNJbml0aWFsaXplZCIsInVuZGVmaW5lZCIsImlzVW5pbml0aWFsaXplZCIsImlzTnVtYmVyIiwiaXNOYU4iLCJwYXJzZUZsb2F0IiwiaXNGaW5pdGUiLCJpc0ludCIsInBhcnNlSW50IiwiTnVtYmVyIiwiaXNBcnJheSIsIkFycmF5IiwiaXNTdHJpbmciLCJpc0Jvb2xlYW4iLCJpc0Z1bmN0aW9uIiwiaXNPYmplY3QiLCJvYmoiLCJpc1VwcGVyQ2FzZSIsInN0ciIsInRvVXBwZXJDYXNlIiwiaXNMb3dlckNhc2UiLCJ0b0xvd2VyQ2FzZSIsImFzc2VydEhleCIsIm1zZyIsImFzc2VydFRydWUiLCJpc0hleCIsImxlbmd0aCIsIm1hdGNoIiwiaXNCYXNlMzIiLCJ0ZXN0IiwiYXNzZXJ0QmFzZTU4IiwiaXNCYXNlNTgiLCJhc3NlcnRCYXNlNjQiLCJpc0Jhc2U2NCIsImJ0b2EiLCJhdG9iIiwiZXJyIiwiZmFpbCIsIkVycm9yIiwiY29uZGl0aW9uIiwiYXNzZXJ0RmFsc2UiLCJib29sIiwiYXNzZXJ0TnVsbCIsImFzc2VydE5vdE51bGwiLCJhc3NlcnREZWZpbmVkIiwiYXNzZXJ0VW5kZWZpbmVkIiwiYXNzZXJ0SW5pdGlhbGl6ZWQiLCJhc3NlcnRVbmluaXRpYWxpemVkIiwiYXNzZXJ0RXF1YWxzIiwiYXJnMSIsImFyZzIiLCJlcXVhbHMiLCJhc3NlcnROb3RFcXVhbHMiLCJhc3NlcnRJbnQiLCJhc3NlcnROdW1iZXIiLCJhc3NlcnRCb29sZWFuIiwiYXNzZXJ0U3RyaW5nIiwiYXNzZXJ0QXJyYXkiLCJhc3NlcnRGdW5jdGlvbiIsImFzc2VydE9iamVjdCIsIm5hbWUiLCJpbmhlcml0c0Zyb20iLCJjaGlsZCIsInBhcmVudCIsInByb3RvdHlwZSIsIk9iamVjdCIsImNyZWF0ZSIsImNvbnN0cnVjdG9yIiwiaW52b2tlIiwiZm5zIiwiYXJndW1lbnRzIiwiYXJncyIsImkiLCJwdXNoIiwiYXBwbHkiLCJnZXRQb3dlclNldCIsImFyciIsImZuIiwibiIsInNyYyIsImdvdCIsImFsbCIsImoiLCJzbGljZSIsImNvbmNhdCIsImdldFBvd2VyU2V0T2ZMZW5ndGgiLCJzaXplIiwicG93ZXJTZXQiLCJwb3dlclNldE9mTGVuZ3RoIiwiZ2V0SW5kaWNlcyIsImluZGljZXMiLCJ0b1VuaXF1ZUFycmF5IiwiZmlsdGVyIiwidmFsdWUiLCJpbmRleCIsInNlbGYiLCJpbmRleE9mIiwiY29weUFycmF5IiwiY29weSIsInJlbW92ZSIsInZhbCIsImZvdW5kIiwic3BsaWNlIiwidG9Mb3dlckNhc2VBcnJheSIsImFycjIiLCJsaXN0aWZ5IiwiYXJyT3JFbGVtIiwiYXJyYXlDb250YWlucyIsImNvbXBhcmVCeVJlZmVyZW5jZSIsInN0ckNvbnRhaW5zIiwic3Vic3RyaW5nIiwiYXJyYXlzRXF1YWwiLCJhcnIxIiwib2JqZWN0c0VxdWFsIiwibWFwMSIsIm1hcDIiLCJrZXlzMSIsImtleXMiLCJrZXlzMiIsImtleTEiLCJrZXkyIiwiZGVsZXRlVW5kZWZpbmVkS2V5cyIsImtleSIsImdldENvbWJpbmF0aW9ucyIsImNvbWJpbmF0aW9uU2l6ZSIsImluZGV4Q29tYmluYXRpb25zIiwiY29tYmluYXRpb25zIiwiaW5kZXhDb21iaW5hdGlvbnNJZHgiLCJpbmRleENvbWJpbmF0aW9uIiwiY29tYmluYXRpb24iLCJpbmRleENvbWJpbmF0aW9uSWR4IiwiZ2V0RG93bmxvYWRhYmxlQSIsImNvbnRlbnRzIiwiYSIsIndpbmRvdyIsImRvY3VtZW50IiwiY3JlYXRlRWxlbWVudCIsImhyZWYiLCJVUkwiLCJjcmVhdGVPYmplY3RVUkwiLCJCbG9iIiwidHlwZSIsImRvd25sb2FkIiwidGFyZ2V0IiwiaW5uZXJIVE1MIiwiY29weVByb3BlcnRpZXMiLCJKU09OIiwicGFyc2UiLCJzdHJpbmdpZnkiLCJkZWxldGVQcm9wZXJ0aWVzIiwicHJvcHMiLCJwcm9wIiwidG9TdHJpbmciLCJoYXNXaGl0ZXNwYWNlIiwiaXNXaGl0ZXNwYWNlIiwiY2hhciIsImlzTmV3bGluZSIsImNvdW50Tm9uV2hpdGVzcGFjZUNoYXJhY3RlcnMiLCJjb3VudCIsImNoYXJBdCIsImdldFdoaXRlc3BhY2VUb2tlbnMiLCJnZXRMaW5lcyIsImdldEludGVybmFsU3R5bGVTaGVldCIsInN0eWxlU2hlZXRzIiwic3R5bGVTaGVldCIsImdldEludGVybmFsU3R5bGVTaGVldFRleHQiLCJpbnRlcm5hbENzcyIsImludGVybmFsU3R5bGVTaGVldCIsImNzc1J1bGVzIiwiY3NzVGV4dCIsImJ1aWxkSHRtbERvY3VtZW50IiwiY29udGVudCIsIm1ldGFzIiwibWV0YSIsImVsZW0iLCJoYXNPd25Qcm9wZXJ0eSIsInNldEF0dHJpYnV0ZSIsIm91dGVySFRNTCIsInRpdGxlIiwiZGVwZW5kZW5jeVBhdGhzIiwiZGVwZW5kZW5jeVBhdGgiLCJlbmRzV2l0aCIsImRpdiIsIiQiLCJhcHBlbmQiLCJjbG9uZSIsImh0bWwiLCJuZXdXaW5kb3ciLCJvbkxvYWQiLCJvbkxvYWRDYWxsZWQiLCJ3Iiwib3BlbiIsIm9uTG9hZE9uY2UiLCJvcGVuZXIiLCJ3cml0ZSIsImFkZEV2ZW50TGlzdGVuZXIiLCJjbG9zZSIsImltZ1RvRGF0YVVybCIsImltZyIsInF1YWxpdHkiLCJjYW52YXMiLCJoZWlnaHQiLCJuYXR1cmFsSGVpZ2h0Iiwid2lkdGgiLCJuYXR1cmFsV2lkdGgiLCJjb250ZXh0IiwiZ2V0Q29udGV4dCIsImRyYXdJbWFnZSIsInRvRGF0YVVSTCIsImlzSW1hZ2VBY2Nlc3NpYmxlIiwidXJsIiwidGltZW91dCIsIm9uRG9uZSIsInJldHVybmVkIiwiSW1hZ2UiLCJvbmxvYWQiLCJvblJlc3BvbnNlIiwib25lcnJvciIsIkRhdGUiLCJzZXRUaW1lb3V0Iiwic2V0SW1tZWRpYXRlIiwiZSIsImlzWmlwRmlsZSIsImZpbGUiLCJpc0pzb25GaWxlIiwiaXNUeHRGaWxlIiwiZ2V0SW1hZ2VzIiwicGF0aHMiLCJmdW5jcyIsImxvYWRGdW5jIiwiYXN5bmMiLCJwYXJhbGxlbCIsInBhdGgiLCJnZXRJbmRlbnQiLCJpbml0UG9seWZpbGxzIiwiYXNzaWduIiwiZGVmaW5lUHJvcGVydHkiLCJ2YXJBcmdzIiwiVHlwZUVycm9yIiwidG8iLCJuZXh0U291cmNlIiwibmV4dEtleSIsImNhbGwiLCJ3cml0YWJsZSIsImNvbmZpZ3VyYWJsZSIsIlN0cmluZyIsInN0YXJ0c1dpdGgiLCJzZWFyY2hTdHJpbmciLCJwb3NpdGlvbiIsInN1YnN0ciIsImdldFVVSUQiLCJyZXBsYWNlIiwiYyIsInIiLCJNYXRoIiwicmFuZG9tIiwidiIsImlzQnJvd3NlciIsImlzV29ya2VyIiwiaW1wb3J0U2NyaXB0cyIsImlzQnJvd3Nlck1haW4iLCJGdW5jdGlvbiIsImlzSnNEb20iLCJpc0Rlbm8iLCJEZW5vIiwidmVyc2lvbiIsImRlbm8iLCJpc0ZpcmVmb3giLCJuYXZpZ2F0b3IiLCJ1c2VyQWdlbnQiLCJnZXRJRVZlcnNpb24iLCJ1YSIsIm1zaWUiLCJ0cmlkZW50IiwicnYiLCJlZGdlIiwiZ2V0UGFyYW1ldGVyQnlOYW1lIiwibG9jYXRpb24iLCJyZWdleCIsIlJlZ0V4cCIsInJlc3VsdHMiLCJleGVjIiwiZGVjb2RlVVJJQ29tcG9uZW50IiwiZ2V0UmFuZG9tSW50IiwibWluIiwibWF4IiwiY2VpbCIsImZsb29yIiwiZ2V0UmFuZG9tSW50cyIsImludHMiLCJnZXRVbmlxdWVSYW5kb21JbnRzIiwicmFuZG9tSW50IiwiaW5jbHVkZXMiLCJzaHVmZmxlIiwiYXJyYXkiLCJ0ZW1wIiwic29ydCIsImIiLCJzYWZlU2V0IiwiZ2V0Rm4iLCJzZXRGbiIsImNvbmZpZyIsImVyck1zZyIsImN1clZhbCIsInJlY29uY2lsZWRWYWwiLCJyZWNvbmNpbGUiLCJ2YWwxIiwidmFsMiIsImNvbXBhcmlzb24iLCJyZXNvbHZlRGVmaW5lZCIsInJlc29sdmVUcnVlIiwiYXNzZXJ0IiwiZXF1YWwiLCJyZXNvbHZlTWF4IiwiZGVlcEVxdWFsIiwia3ZMaW5lIiwiaW5kZW50IiwibmV3bGluZSIsImlnbm9yZVVuZGVmaW5lZCIsInN0cmluZ2lmeUJpZ0ludHMiLCJwcmludFN0YWNrVHJhY2UiLCJjb25zb2xlIiwiZXJyb3IiLCJzdGFjayIsIndhaXRGb3IiLCJkdXJhdGlvbk1zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJraWxsUHJvY2VzcyIsInByb2Nlc3MiLCJzaWduYWwiLCJyZWplY3QiLCJvbiIsImNvZGUiLCJraWxsIiwibm9ybWFsaXplVXJpIiwidXJpIiwiYWJzIiwiYmkiLCJnZXRFbnVtS2V5QnlWYWx1ZSIsImVudW1UeXBlIiwiZW51bVZhbHVlIiwiZXhlY3V0ZVdpdGhUaW1lb3V0IiwicHJvbWlzZSIsInRpbWVvdXRNcyIsInRpbWVvdXRJZCIsInRoZW4iLCJyZXN1bHQiLCJjbGVhclRpbWVvdXQiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2NvbW1vbi9HZW5VdGlscy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBhc3luYyBmcm9tIFwiYXN5bmNcIjtcbmltcG9ydCB7IENoaWxkUHJvY2VzcyB9IGZyb20gXCJjaGlsZF9wcm9jZXNzXCI7XG5cbmRlY2xhcmUgdmFyIERlbm86IGFueTtcblxuLyoqXG4gKiBNSVQgTGljZW5zZVxuICogXG4gKiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5XG4gKiBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0byBkZWFsXG4gKiBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzXG4gKiB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsXG4gKiBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbiAqIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4gKiBcbiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbFxuICogY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbiAqIFxuICogVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuICogSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4gKiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbiAqIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbiAqIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4gKiBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRVxuICogU09GVFdBUkUuXG4gKi9cblxuLyoqXG4gKiBDb2xsZWN0aW9uIG9mIGdlbmVyYWwgcHVycG9zZSB1dGlsaXRpZXMuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEdlblV0aWxzIHtcbiAgXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGdpdmVuIGFyZ3VtZW50IGlzIGRlZmluZWQuXG4gICAqIFxuICAgKiBAcGFyYW0ge2FueX0gYXJnIGlzIHRoZSBhcmcgdG8gdGVzdFxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHRoZSBnaXZlbiBhcmcgaXMgZGVmaW5lZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgaXNEZWZpbmVkKGFyZzogYW55KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHR5cGVvZiBhcmcgIT09ICd1bmRlZmluZWQnO1xuICB9XG5cbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgZ2l2ZW4gYXJndW1lbnQgaXMgdW5kZWZpbmVkLlxuICAgKiBcbiAgICogQHBhcmFtIGFyZyBpcyB0aGUgYXJnIHRvIHRlc3RcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gdHJ1ZSBpZiB0aGUgZ2l2ZW4gYXJnIGlzIHVuZGVmaW5lZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgaXNVbmRlZmluZWQoYXJnKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICd1bmRlZmluZWQnO1xuICB9XG5cbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgZ2l2ZW4gYXJnIGlzIGluaXRpYWxpemVkLlxuICAgKiBcbiAgICogQHBhcmFtIHthbnl9IGFyZyBpcyB0aGUgYXJnIHRvIHRlc3RcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gdHJ1ZSBpZiB0aGUgZ2l2ZW4gYXJnIGlzIGluaXRpYWxpemVkLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIHN0YXRpYyBpc0luaXRpYWxpemVkKGFyZzogYW55KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGFyZyAhPT0gdW5kZWZpbmVkICYmIGFyZyAhPT0gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGdpdmVuIGFyZyBpcyB1bmluaXRpYWxpemVkLlxuICAgKiBcbiAgICogQHBhcmFtIGFyZyBpcyB0aGUgYXJnIHRvIHRlc3RcbiAgICogQHJldHVybiB0cnVlIGlmIHRoZSBnaXZlbiBhcmcgaXMgdW5pbml0aWFsaXplZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgaXNVbmluaXRpYWxpemVkKGFyZzogYW55KTogYm9vbGVhbiB7XG4gICAgaWYgKCFhcmcpIHJldHVybiB0cnVlO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGdpdmVuIGFyZ3VtZW50IGlzIGEgbnVtYmVyLlxuICAgKiBcbiAgICogQHBhcmFtIHthbnl9IGFyZyBpcyB0aGUgYXJndW1lbnQgdG8gdGVzdFxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHRoZSBhcmd1bWVudCBpcyBhIG51bWJlciwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgaXNOdW1iZXIoYXJnOiBhbnkpOiBib29sZWFuIHtcbiAgICByZXR1cm4gIWlzTmFOKHBhcnNlRmxvYXQoYXJnKSkgJiYgaXNGaW5pdGUoYXJnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGdpdmVuIGFyZ3VtZW50IGlzIGFuIGludGVnZXIuXG4gICAqIFxuICAgKiBAcGFyYW0ge2FueX0gYXJnIGlzIHRoZSBhcmd1bWVudCB0byB0ZXN0XG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgdGhlIGdpdmVuIGFyZ3VtZW50IGlzIGFuIGludGVnZXIsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGlzSW50KGFyZzogYW55KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGFyZyA9PT0gcGFyc2VJbnQoXCJcIiArIE51bWJlcihhcmcpKSAmJiAhaXNOYU4oYXJnKSAmJiAhaXNOYU4ocGFyc2VJbnQoYXJnLCAxMCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgZ2l2ZW4gYXJndW1lbnQgaXMgYW4gYXJyYXkuXG4gICAqIFxuICAgKiBAcGFyYW0ge2FueX0gYXJnIGlzIHRoZSBhcmd1bWVudCB0byB0ZXN0IGFzIGJlaW5nIGFuIGFycmF5XG4gICAqIEByZXR1cm4ge2Jvb29sZWFufSB0cnVlIGlmIHRoZSBhcmd1bWVudCBpcyBhbiBhcnJheSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgaXNBcnJheShhcmc6IGFueSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBhcmcgaW5zdGFuY2VvZiBBcnJheSAmJiBBcnJheS5pc0FycmF5KGFyZyk7XG4gIH1cblxuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIHRoZSBnaXZlbiBhcmd1bWVudCBpcyBhIHN0cmluZy5cbiAgICogXG4gICAqIEBwYXJhbSB7YW55fSBhcmcgaXMgdGhlIGFyZ3VtZW50IHRvIHRlc3QgYXMgYmVpbmcgYSBzdHJpbmdcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gdHJ1ZSBpZiB0aGUgYXJndW1lbnQgaXMgYSBzdHJpbmcsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGlzU3RyaW5nKGFyZzogYW55KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdzdHJpbmcnO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVybWluZXMgaWYgdGhlIGdpdmVuIGFyZ3VtZW50IGlzIGEgYm9vbGVhbi5cbiAgICogXG4gICAqIEBwYXJhbSB7YW55fSBhcmcgaXMgdGhlIGFyZ3VtZW50IHRvIHRlc3QgYXMgYmVpbmcgYSBib29sZWFuXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgdGhlIGFyZ3VtZW50IGlzIGEgYm9vbGVhbiwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgaXNCb29sZWFuKGFyZzogYW55KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHR5cGVvZihhcmcpID09IHR5cGVvZih0cnVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGlmIHRoZSBnaXZlbiBhcmd1bWVudCBpcyBhIHN0YXRpYy5cbiAgICogXG4gICAqIEBwYXJhbSB7YW55fSBhcmcgaXMgdGhlIGFyZ3VtZW50IHRvIHRlc3QgYXMgYmVpbmcgYSBzdGF0aWNcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gdHJ1ZSBpZiB0aGUgYXJndW1lbnQgaXMgYSBzdGF0aWMsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGlzRnVuY3Rpb24oYXJnOiBhbnkpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gXCJmdW5jdGlvblwiO1xuICB9XG5cbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgZ2l2ZW4gYXJndW1lbnQgaXMgYW4gb2JqZWN0IGFuZCBvcHRpb25hbGx5IGlmIGl0IGhhcyB0aGUgZ2l2ZW4gY29uc3RydWN0b3IgbmFtZS5cbiAgICogXG4gICAqIEBwYXJhbSB7YW55fSBhcmcgaXMgdGhlIGFyZ3VtZW50IHRvIHRlc3RcbiAgICogQHBhcmFtIHthbnl9IG9iaiBpcyBhbiBvYmplY3QgdG8gdGVzdCBhcmcgaW5zdGFuY2VvZiBvYmogKG9wdGlvbmFsKVxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHRoZSBnaXZlbiBhcmd1bWVudCBpcyBhbiBvYmplY3QgYW5kIG9wdGlvbmFsbHkgaGFzIHRoZSBnaXZlbiBjb25zdHJ1Y3RvciBuYW1lXG4gICAqL1xuICBzdGF0aWMgaXNPYmplY3QoYXJnOiBhbnksIG9iaj86IGFueSk6IGJvb2xlYW4ge1xuICAgIGlmICghYXJnKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKHR5cGVvZiBhcmcgIT09ICdvYmplY3QnKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKG9iaiAmJiAhKGFyZyBpbnN0YW5jZW9mIG9iaikpIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGlmIGFsbCBhbHBoYWJldCBjaGFyYWN0ZXJzIGluIHRoZSBnaXZlbiBzdHJpbmcgYXJlIHVwcGVyIGNhc2UuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyIGlzIHRoZSBzdHJpbmcgdG8gdGVzdFxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHRoZSBzdHJpbmcgaXMgdXBwZXIgY2FzZSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgaXNVcHBlckNhc2Uoc3RyOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gc3RyLnRvVXBwZXJDYXNlKCkgPT09IHN0cjtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGlmIGFsbCBhbHBoYWJldCBjaGFyYWN0ZXJzIGluIHRoZSBnaXZlbiBzdHJpbmcgYXJlIGxvd2VyIGNhc2UuXG4gICAqIFxuICAgKiBAcGFyYW0gc3RyIGlzIHRoZSBzdHJpbmcgdG8gdGVzdFxuICAgKiBAcGFyYW0gdHJ1ZSBpZiB0aGUgc3RyaW5nIGlzIGxvd2VyIGNhc2UsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGlzTG93ZXJDYXNlKHN0cikge1xuICAgIHJldHVybiBzdHIudG9Mb3dlckNhc2UoKSA9PT0gc3RyO1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgZ2l2ZW4gYXJndW1lbnQgaXMgaGV4LlxuICAgKiBcbiAgICogQHBhcmFtIGFyZyBpcyB0aGUgYXJndW1lbnQgdG8gYXNzZXJ0IGFzIGhleFxuICAgKiBAcGFyYW0gbXNnIGlzIHRoZSBtZXNzYWdlIHRvIHRocm93IGlmIHRoZSBhcmd1bWVudCBpcyBub3QgaGV4XG4gICAqL1xuICBzdGF0aWMgYXNzZXJ0SGV4KHN0ciwgbXNnKSB7XG4gICAgR2VuVXRpbHMuYXNzZXJ0VHJ1ZShHZW5VdGlscy5pc0hleChzdHIpLCBtc2cgPyBtc2cgOiBcIkFyZ3VtZW50IGFzc2VydGVkIGFzIGhleCBidXQgaXMgbm90IGhleFwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGdpdmVuIGFyZ3VtZW50IGlzIGEgaGV4aWRlbWFsIHN0cmluZy5cbiAgICogXG4gICAqIENyZWRpdDogaHR0cHM6Ly9naXRodWIuY29tL3JvcnlyamIvaXMtaGV4L2Jsb2IvbWFzdGVyL2lzLWhleC5qcy5cbiAgICogXG4gICAqIEBwYXJhbSBzdHIgaXMgdGhlIHN0cmluZyB0byB0ZXN0XG4gICAqIEByZXR1cm4gdHJ1ZSBpZiB0aGUgZ2l2ZW4gc3RyaW5nIGlzIGhleGlkZWNpbWFsLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIHN0YXRpYyBpc0hleChhcmcpIHtcbiAgICBpZiAodHlwZW9mIGFyZyAhPT0gJ3N0cmluZycpIHJldHVybiBmYWxzZTtcbiAgICBpZiAoYXJnLmxlbmd0aCA9PT0gMCkgcmV0dXJuIGZhbHNlO1xuICAgIHJldHVybiAoYXJnLm1hdGNoKC8oWzAtOV18W2EtZl0pL2dpbSkgfHwgW10pLmxlbmd0aCA9PT0gYXJnLmxlbmd0aDtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGlmIHRoZSBnaXZlbiBzdHJpbmcgaXMgYmFzZTMyLlxuICAgKi9cbiAgc3RhdGljIGlzQmFzZTMyKHN0cikge1xuICAgIGlmICh0eXBlb2Ygc3RyICE9PSAnc3RyaW5nJykgcmV0dXJuIGZhbHNlO1xuICAgIEdlblV0aWxzLmFzc2VydFRydWUoc3RyLmxlbmd0aCA+IDAsIFwiQ2Fubm90IGRldGVybWluZSBpZiBlbXB0eSBzdHJpbmcgaXMgYmFzZTMyXCIpO1xuICAgIHJldHVybiAvXltBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjIzNDU2N10rJC8udGVzdChzdHIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgZ2l2ZW4gYXJndW1lbnQgaXMgYmFzZTU4LlxuICAgKiBcbiAgICogQHBhcmFtIGFyZyBpcyB0aGUgYXJndW1lbnQgdG8gYXNzZXJ0IGFzIGJhc2U1OFxuICAgKiBAcGFyYW0gbXNnIGlzIHRoZSBtZXNzYWdlIHRvIHRocm93IGlmIHRoZSBhcmd1bWVudCBpcyBub3QgYmFzZTU4XG4gICAqL1xuICBzdGF0aWMgYXNzZXJ0QmFzZTU4KHN0ciwgbXNnKSB7XG4gICAgR2VuVXRpbHMuYXNzZXJ0VHJ1ZShHZW5VdGlscy5pc0Jhc2U1OChzdHIpLCBtc2cgPyBtc2cgOiBcIkFyZ3VtZW50IGFzc2VydGVkIGFzIGJhc2U1OCBidXQgaXMgbm90IGJhc2U1OFwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGlmIHRoZSBnaXZlbiBzdHJpbmcgaXMgYmFzZTU4LlxuICAgKi9cbiAgc3RhdGljIGlzQmFzZTU4KHN0cikge1xuICAgIGlmICh0eXBlb2Ygc3RyICE9PSAnc3RyaW5nJykgcmV0dXJuIGZhbHNlO1xuICAgIEdlblV0aWxzLmFzc2VydFRydWUoc3RyLmxlbmd0aCA+IDAsIFwiQ2Fubm90IGRldGVybWluZSBpZiBlbXB0eSBzdHJpbmcgaXMgYmFzZTU4XCIpO1xuICAgIHJldHVybiAvXlsxMjM0NTY3ODlBQkNERUZHSEpLTE1OUFFSU1RVVldYWVphYmNkZWZnaGlqa21ub3BxcnN0dXZ3eHl6XSskLy50ZXN0KHN0cik7XG4gIH1cblxuICAvKipcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSBnaXZlbiBhcmd1bWVudCBpcyBiYXNlNjQuXG4gICAqIFxuICAgKiBAcGFyYW0gYXJnIGlzIHRoZSBhcmd1bWVudCB0byBhc3NlcnQgYXMgYmFzZTY0XG4gICAqIEBwYXJhbSBtc2cgaXMgdGhlIG1lc3NhZ2UgdG8gdGhyb3cgaWYgdGhlIGFyZ3VtZW50IGlzIG5vdCBiYXNlNjRcbiAgICovXG4gIHN0YXRpYyBhc3NlcnRCYXNlNjQoc3RyLCBtc2cpIHtcbiAgICBHZW5VdGlscy5hc3NlcnRUcnVlKEdlblV0aWxzLmlzQmFzZTY0KHN0ciksIG1zZyA/IG1zZyA6IFwiQXJndW1lbnQgYXNzZXJ0ZWQgYXMgYmFzZTY0IGJ1dCBpcyBub3QgYmFzZTY0XCIpO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVybWluZXMgaWYgdGhlIGdpdmVuIHN0cmluZyBpcyBiYXNlNjQuXG4gICAqL1xuICBzdGF0aWMgaXNCYXNlNjQoc3RyKSB7XG4gICAgaWYgKHR5cGVvZiBzdHIgIT09ICdzdHJpbmcnKSByZXR1cm4gZmFsc2U7XG4gICAgR2VuVXRpbHMuYXNzZXJ0VHJ1ZShzdHIubGVuZ3RoID4gMCwgXCJDYW5ub3QgZGV0ZXJtaW5lIGlmIGVtcHR5IHN0cmluZyBpcyBiYXNlNjRcIik7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBidG9hKGF0b2Ioc3RyKSkgPT0gc3RyO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaHJvd3MgYW4gZXhjZXB0aW9uIHdpdGggdGhlIGdpdmVuIG1lc3NhZ2UuXG4gICAqIFxuICAgKiBAcGFyYW0gbXNnIGRlZmluZXMgdGhlIG1lc3NhZ2UgdG8gdGhyb3cgdGhlIGV4Y2VwdGlvbiB3aXRoIChvcHRpb25hbClcbiAgICovXG4gIHN0YXRpYyBmYWlsKG1zZz8pIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IobXNnID8gbXNnIDogXCJGYWlsdXJlIChubyBtZXNzYWdlKVwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIGdpdmVuIGNvbmRpdGlvbiBpcyB0cnVlLiAgVGhyb3dzIGFuIGV4Y2VwdGlvbiBpZiBub3QgYSBib29sZWFuIG9yIGZhbHNlLlxuICAgKiBcbiAgICogQHBhcmFtIHtib29sZWFufSBjb25kaXRpb24gaXMgdGhlIGJvb2xlYW4gdG8gYXNzZXJ0IHRydWVcbiAgICogQHBhcmFtIHtzdHJpbmd9IFttc2ddIGlzIHRoZSBtZXNzYWdlIHRvIHRocm93IGlmIGNvbmRpdGlvbiBpcyBmYWxzZSAob3B0aW9uYWwpXG4gICAqL1xuICBzdGF0aWMgYXNzZXJ0VHJ1ZShjb25kaXRpb24sIG1zZz8pIHtcbiAgICBpZiAodHlwZW9mIGNvbmRpdGlvbiAhPT0gJ2Jvb2xlYW4nKSB0aHJvdyBuZXcgRXJyb3IoXCJBcmd1bWVudCBpcyBub3QgYSBib29sZWFuXCIpO1xuICAgIGlmICghY29uZGl0aW9uKSB0aHJvdyBuZXcgRXJyb3IobXNnID8gbXNnIDogXCJCb29sZWFuIGFzc2VydGVkIGFzIHRydWUgYnV0IHdhcyBmYWxzZVwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIGdpdmVuIGJvb2xlYW4gaXMgZmFsc2UuICBUaHJvd3MgYW4gZXhjZXB0aW9uIGlmIG5vdCBhIGJvb2xlYW4gb3IgdHJ1ZS5cbiAgICogXG4gICAqIEBwYXJhbSBib29sIGlzIHRoZSBib29sZWFuIHRvIGFzc2VydCBmYWxzZVxuICAgKiBAcGFyYW0gbXNnIGlzIHRoZSBtZXNzYWdlIHRvIHRocm93IGlmIGJvb2wgaXMgdHJ1ZSAob3B0aW9uYWwpXG4gICAqL1xuICBzdGF0aWMgYXNzZXJ0RmFsc2UoYm9vbCwgbXNnPykge1xuICAgIGlmICh0eXBlb2YgYm9vbCAhPT0gJ2Jvb2xlYW4nKSB0aHJvdyBuZXcgRXJyb3IoXCJBcmd1bWVudCBpcyBub3QgYSBib29sZWFuXCIpO1xuICAgIGlmIChib29sKSB0aHJvdyBuZXcgRXJyb3IobXNnID8gbXNnIDogXCJCb29sZWFuIGFzc2VydGVkIGFzIGZhbHNlIGJ1dCB3YXMgdHJ1ZVwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIGdpdmVuIGFyZ3VtZW50IGlzIG51bGwuICBUaHJvd3MgYW4gZXhjZXB0aW9uIGlmIG5vdCBudWxsLlxuICAgKiBcbiAgICogQHBhcmFtIGFyZyBpcyB0aGUgYXJndW1lbnQgdG8gYXNzZXJ0IG51bGxcbiAgICogQHBhcmFtIG1zZyBpcyB0aGUgbWVzc2FnZSB0byB0aHJvdyBpZiBhcmcgaXMgbm90IG51bGwgKG9wdGlvbmFsKVxuICAgKi9cbiAgc3RhdGljIGFzc2VydE51bGwoYXJnLCBtc2c/KSB7XG4gICAgaWYgKGFyZyAhPT0gbnVsbCkgdGhyb3cgbmV3IEVycm9yKG1zZyA/IG1zZyA6IFwiQXJndW1lbnQgYXNzZXJ0ZWQgYXMgbnVsbCBidXQgd2FzIG5vdCBudWxsOiBcIiArIGFyZyk7XG4gIH1cblxuICAvKipcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSBnaXZlbiBhcmd1bWVudCBpcyBub3QgbnVsbC4gIFRocm93cyBhbiBleGNlcHRpb24gaWYgbnVsbC5cbiAgICogXG4gICAqIEBwYXJhbSBhcmcgaXMgdGhlIGFyZ3VtZW50IHRvIGFzc2VydCBub3QgbnVsbFxuICAgKiBAcGFyYW0gbXNnIGlzIHRoZSBtZXNzYWdlIHRvIHRocm93IGlmIGFyZyBpcyBudWxsIChvcHRpb25hbClcbiAgICovXG4gIHN0YXRpYyBhc3NlcnROb3ROdWxsKGFyZywgbXNnPykge1xuICAgIGlmIChhcmcgPT09IG51bGwpIHRocm93IG5ldyBFcnJvcihtc2cgPyBtc2cgOiBcIkFyZ3VtZW50IGFzc2VydGVkIGFzIG5vdCBudWxsIGJ1dCB3YXMgbnVsbFwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIGdpdmVuIGFyZ3VtZW50IGlzIGRlZmluZWQuICBUaHJvd3MgYW4gZXhjZXB0aW9uIGlmIHVuZGVmaW5lZC5cbiAgICogXG4gICAqIEBwYXJhbSBhcmcgaXMgdGhlIGFyZ3VtZW50IHRvIGFzc2VydCBkZWZpbmVkXG4gICAqIEBwYXJhbSBtc2cgaXMgdGhlIG1lc3NhZ2UgdG8gdGhyb3cgaWYgYXJnIGlzIHVuZGVmaW5lZCAob3B0aW9uYWwpXG4gICAqL1xuICBzdGF0aWMgYXNzZXJ0RGVmaW5lZChhcmcsIG1zZz8pIHtcbiAgICBpZiAoR2VuVXRpbHMuaXNVbmRlZmluZWQoYXJnKSkgdGhyb3cgbmV3IEVycm9yKG1zZyA/IG1zZyA6IFwiQXJndW1lbnQgYXNzZXJ0ZWQgYXMgZGVmaW5lZCBidXQgd2FzIHVuZGVmaW5lZFwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIGdpdmVuIGFyZ3VtZW50IGlzIHVuZGVmaW5lZC4gIFRocm93cyBhbiBleGNlcHRpb24gaWYgZGVmaW5lZC5cbiAgICogXG4gICAqIEBwYXJhbSBhcmcgaXMgdGhlIGFyZ3VtZW50IHRvIGFzc2VydCB1bmRlZmluZWRcbiAgICogQHBhcmFtIG1zZyBpcyB0aGUgbWVzc2FnZSB0byB0aHJvdyBpZiBhcmcgaXMgZGVmaW5lZCAob3B0aW9uYWwpXG4gICAqL1xuICBzdGF0aWMgYXNzZXJ0VW5kZWZpbmVkKGFyZywgbXNnPykge1xuICAgIGlmIChHZW5VdGlscy5pc0RlZmluZWQoYXJnKSkgdGhyb3cgbmV3IEVycm9yKG1zZyA/IG1zZyA6IFwiQXJndW1lbnQgYXNzZXJ0ZWQgYXMgdW5kZWZpbmVkIGJ1dCB3YXMgZGVmaW5lZDogXCIgKyBhcmcpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgZ2l2ZW4gYXJndW1lbnQgaXMgaW5pdGlhbGl6ZWQuICBUaHJvd3MgYW4gZXhjZXB0aW9uIGlmIG5vdCBpbml0aWFsaXplZC5cbiAgICogXG4gICAqIEBwYXJhbSBhcmcgaXMgdGhlIGFyZ3VtZW50IHRvIGFzc2VydCBhcyBpbml0aWFsaXplZFxuICAgKiBAcGFyYW0gbXNnIGlzIHRoZSBtZXNzYWdlIHRvIHRocm93IGlmIGFyZyBpcyBub3QgaW5pdGlhbGl6ZWQgKG9wdGlvbmFsKVxuICAgKi9cbiAgc3RhdGljIGFzc2VydEluaXRpYWxpemVkKGFyZywgbXNnPykge1xuICAgIGlmIChHZW5VdGlscy5pc1VuaW5pdGlhbGl6ZWQoYXJnKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKG1zZyA/IG1zZyA6IFwiQXJndW1lbnQgYXNzZXJ0ZWQgYXMgaW5pdGlhbGl6ZWQgYnV0IHdhcyBcIiArIGFyZyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgZ2l2ZW4gYXJndW1lbnQgaXMgdW5pbml0aWFsaXplZC4gIFRocm93cyBhbiBleGNlcHRpb24gaWYgaW5pdGlhbGl6ZWQuXG4gICAqIFxuICAgKiBAcGFyYW0gYXJnIGlzIHRoZSBhcmd1bWVudCB0byBhc3NlcnQgYXMgdW5pbml0aWFsaXplZFxuICAgKiBAcGFyYW0gbXNnIGlzIHRoZSBtZXNzYWdlIHRvIHRocm93IGlmIGFyZyBpcyBpbml0aWFsaXplZCAob3B0aW9uYWwpXG4gICAqL1xuICBzdGF0aWMgYXNzZXJ0VW5pbml0aWFsaXplZChhcmcsIG1zZz8pIHtcbiAgICBpZiAoR2VuVXRpbHMuaXNJbml0aWFsaXplZChhcmcpKSB0aHJvdyBuZXcgRXJyb3IobXNnID8gbXNnIDogXCJBcmd1bWVudCBhc3NlcnRlZCBhcyB1bmluaXRpYWxpemVkIGJ1dCB3YXMgaW5pdGlhbGl6ZWRcIik7XG4gIH1cblxuICAvKipcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSBnaXZlbiBhcmd1bWVudHMgYXJlIGVxdWFsLiAgVGhyb3dzIGFuIGV4Y2VwdGlvbiBpZiBub3QgZXF1YWwuXG4gICAqIFxuICAgKiBAcGFyYW0gYXJnMSBpcyBhbiBhcmd1bWVudCB0byBhc3NlcnQgYXMgZXF1YWxcbiAgICogQHBhcmFtIGFyZzIgaXMgYW4gYXJndW1lbnQgdG8gYXNzZXJ0IGFzIGVxdWFsXG4gICAqIEBwYXJhbSBtc2cgaXMgdGhlIG1lc3NhZ2UgdG8gdGhyb3cgaWYgdGhlIGFyZ3VtZW50cyBhcmUgbm90IGVxdWFsXG4gICAqL1xuICBzdGF0aWMgYXNzZXJ0RXF1YWxzKGFyZzEsIGFyZzIsIG1zZz8pIHtcbiAgICBHZW5VdGlscy5hc3NlcnRUcnVlKEdlblV0aWxzLmVxdWFscyhhcmcxLCBhcmcyKSwgbXNnID8gbXNnIDogXCJBcmd1bWVudHMgYXNzZXJ0ZWQgYXMgZXF1YWwgYnV0IGFyZSBub3QgZXF1YWw6IFwiICsgYXJnMSArIFwiIHZzIFwiICsgYXJnMik7XG4gIH1cblxuICAvKipcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSBnaXZlbiBhcmd1bWVudHMgYXJlIG5vdCBlcXVhbC4gIFRocm93cyBhbiBleGNlcHRpb24gaWYgZXF1YWwuXG4gICAqIFxuICAgKiBAcGFyYW0gYXJnMSBpcyBhbiBhcmd1bWVudCB0byBhc3NlcnQgYXMgbm90IGVxdWFsXG4gICAqIEBwYXJhbSBhcmcyIGlzIGFuIGFyZ3VtZW50IHRvIGFzc2VydCBhcyBub3QgZXF1YWxcbiAgICogQHBhcmFtIG1zZyBpcyB0aGUgbWVzc2FnZSB0byB0aHJvdyBpZiB0aGUgYXJndW1lbnRzIGFyZSBlcXVhbFxuICAgKi9cbiAgc3RhdGljIGFzc2VydE5vdEVxdWFscyhhcmcxLCBhcmcyLCBtc2c/KSB7XG4gICAgaWYgKGFyZzEgPT09IGFyZzIpIHRocm93IG5ldyBFcnJvcihtc2cgPyBtc2cgOiBcIkFyZ3VtZW50cyBhc3NlcnRlZCBhcyBub3QgZXF1YWwgYnV0IGFyZSBlcXVhbDogXCIgKyBhcmcxICsgXCIgdnMgXCIgKyBhcmcyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIGdpdmVuIGFyZ3VtZW50IGlzIGFuIGludGVnZXIuXG4gICAqIFxuICAgKiBAcGFyYW0gYXJnIGlzIHRoZSBhcmd1bWVudCB0byBhc3NlcnQgYXMgYW4gaW50ZWdlclxuICAgKiBAcGFyYW0gbXNnIGlzIHRoZSBtZXNzYWdlIHRvIHRocm93IGlmIHRoZSBhcmd1bWVudCBpcyBub3QgYW4gaW50ZWdlclxuICAgKi9cbiAgc3RhdGljIGFzc2VydEludChhcmcsIG1zZz8pIHtcbiAgICBpZiAoIUdlblV0aWxzLmlzSW50KGFyZykpIHRocm93IG5ldyBFcnJvcihtc2cgPyBtc2cgOiBcIkFyZ3VtZW50IGFzc2VydGVkIGFzIGFuIGludGVnZXIgYnV0IGlzIG5vdCBhbiBpbnRlZ2VyXCIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgZ2l2ZW4gYXJndW1lbnQgaXMgYSBudW1iZXIuXG4gICAqIFxuICAgKiBAcGFyYW0gYXJnIGlzIHRoZSBhcmd1bWVudCB0byBhc3NlcnQgYXMgYSBudW1iZXJcbiAgICogQHBhcmFtIG1zZyBpcyB0aGUgbWVzc2FnZSB0byB0aHJvdyBpZiB0aGUgYXJndW1lbnQgaXMgbm90IGEgbnVtYmVyXG4gICAqL1xuICBzdGF0aWMgYXNzZXJ0TnVtYmVyKGFyZywgbXNnPykge1xuICAgIGlmICghR2VuVXRpbHMuaXNOdW1iZXIoYXJnKSkgdGhyb3cgbmV3IEVycm9yKG1zZyA/IG1zZyA6IFwiQXJndW1lbnQgYXNzZXJ0ZWQgYXMgYSBudW1iZXIgYnV0IGlzIG5vdCBhIG51bWJlclwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIGdpdmVuIGFyZ3VtZW50IGlzIGEgYm9vbGVhbi5cbiAgICogXG4gICAqIEBwYXJhbSBhcmcgaXMgdGhlIGFyZ3VtZW50IHRvIGFzc2VydCBhcyBhIGJvb2xlYW5cbiAgICogQHBhcmFtIG1zZyBpcyB0aGUgbWVzc2FnZSB0byB0aHJvdyBpZiB0aGUgYXJndW1lbnQgaXMgbm90IGEgYm9vbGVhblxuICAgKi9cbiAgc3RhdGljIGFzc2VydEJvb2xlYW4oYXJnLCBtc2c/KSB7XG4gICAgaWYgKCFHZW5VdGlscy5pc0Jvb2xlYW4oYXJnKSkgdGhyb3cgbmV3IEVycm9yKG1zZyA/IG1zZyA6IFwiQXJndW1lbnQgYXNzZXJ0ZWQgYXMgYSBib29sZWFuIGJ1dCBpcyBub3QgYSBib29sZWFuXCIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgZ2l2ZW4gYXJndW1lbnQgaXMgYSBzdHJpbmcuXG4gICAqIFxuICAgKiBAcGFyYW0gYXJnIGlzIHRoZSBhcmd1bWVudCB0byBhc3NlcnQgYXMgYSBzdHJpbmdcbiAgICogQHBhcmFtIG1zZyBpcyB0aGUgbWVzc2FnZSB0byB0aHJvdyBpZiB0aGUgYXJndW1lbnQgaXMgbm90IGEgc3RyaW5nXG4gICAqL1xuICBzdGF0aWMgYXNzZXJ0U3RyaW5nKGFyZywgbXNnPykge1xuICAgIGlmICghR2VuVXRpbHMuaXNTdHJpbmcoYXJnKSkgdGhyb3cgbmV3IEVycm9yKG1zZyA/IG1zZyA6IFwiQXJndW1lbnQgYXNzZXJ0ZWQgYXMgYSBzdHJpbmcgYnV0IGlzIG5vdCBhIHN0cmluZzogXCIgKyBhcmcpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VydHMgdGhhdCB0aGUgZ2l2ZW4gYXJndW1lbnQgaXMgYW4gYXJyYXkuXG4gICAqIFxuICAgKiBAcGFyYW0gYXJnIGlzIHRoZSBhcmd1bWVudCB0byBhc3NlcnQgYXMgYW4gYXJyYXlcbiAgICogQHBhcmFtIG1zZyBpcyB0aGUgbWVzc2FnZSB0byB0aHJvdyBpZiB0aGUgYXJndW1lbnQgaXMgbm90IGFuIGFycmF5XG4gICAqL1xuICBzdGF0aWMgYXNzZXJ0QXJyYXkoYXJnLCBtc2c/KSB7XG4gICAgaWYgKCFHZW5VdGlscy5pc0FycmF5KGFyZykpIHRocm93IG5ldyBFcnJvcihtc2cgPyBtc2cgOiBcIkFyZ3VtZW50IGFzc2VydGVkIGFzIGFuIGFycmF5IGJ1dCBpcyBub3QgYW4gYXJyYXlcIik7XG4gIH1cblxuICAvKipcbiAgICogQXNzZXJ0cyB0aGF0IHRoZSBnaXZlbiBhcmd1bWVudCBpcyBhIHN0YXRpYy5cbiAgICogXG4gICAqIEBwYXJhbSBhcmcgaXMgdGhlIGFyZ3VtZW50IHRvIGFzc2VydCBhcyBhIHN0YXRpY1xuICAgKiBAcGFyYW0gbXNnIGlzIHRoZSBtZXNzYWdlIHRvIHRocm93IGlmIHRoZSBhcmd1bWVudCBpcyBub3QgYSBzdGF0aWNcbiAgICovXG4gIHN0YXRpYyBhc3NlcnRGdW5jdGlvbihhcmcsIG1zZz8pIHtcbiAgICBpZiAoIUdlblV0aWxzLmlzRnVuY3Rpb24oYXJnKSkgdGhyb3cgbmV3IEVycm9yKG1zZyA/IG1zZyA6IFwiQXJndW1lbnQgYXNzZXJ0ZWQgYXMgYSBzdGF0aWMgYnV0IGlzIG5vdCBhIHN0YXRpY1wiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NlcnRzIHRoYXQgdGhlIGdpdmVuIGFyZ3VtZW50IGlzIGFuIG9iamVjdCB3aXRoIHRoZSBnaXZlbiBuYW1lLlxuICAgKiBcbiAgICogQHBhcmFtIGFyZyBpcyB0aGUgYXJndW1lbnQgdG8gdGVzdFxuICAgKiBAcGFyYW0gb2JqIGlzIGFuIG9iamVjdCB0byBhc3NlcnQgYXJnIGluc3RhbmNlb2Ygb2JqIChvcHRpb25hbClcbiAgICogQHBhcmFtIG1zZyBpcyB0aGUgbWVzc2FnZSB0byB0aHJvdyBpZiB0aGUgYXJndW1lbnQgaXMgbm90IHRoZSBzcGVjaWZpZWQgb2JqZWN0XG4gICAqL1xuICBzdGF0aWMgYXNzZXJ0T2JqZWN0KGFyZywgb2JqLCBtc2c/KSB7XG4gICAgR2VuVXRpbHMuYXNzZXJ0SW5pdGlhbGl6ZWQoYXJnLCBtc2cpO1xuICAgIGlmIChvYmopIHtcbiAgICAgIGlmICghR2VuVXRpbHMuaXNPYmplY3QoYXJnLCBvYmopKSB0aHJvdyBuZXcgRXJyb3IobXNnID8gbXNnIDogXCJBcmd1bWVudCBhc3NlcnRlZCBhcyBvYmplY3QgJ1wiICsgb2JqLm5hbWUgKyBcIicgYnV0IHdhcyBub3RcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICghR2VuVXRpbHMuaXNPYmplY3QoYXJnKSkgdGhyb3cgbmV3IEVycm9yKG1zZyA/IG1zZyA6IFwiQXJndW1lbnQgYXNzZXJ0ZWQgYXMgb2JqZWN0IGJ1dCB3YXMgbm90XCIpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBjaGlsZCdzIHByb3RvdHlwZSB0byB0aGUgcGFyZW50J3MgcHJvdG90eXBlLlxuICAgKiBcbiAgICogQHBhcmFtIGNoaWxkIGlzIHRoZSBjaGlsZCBjbGFzc1xuICAgKiBAcGFyYW0gcGFyZW50IGlzIHRoZSBwYXJlbnQgY2xhc3NcbiAgICovXG4gIHN0YXRpYyBpbmhlcml0c0Zyb20oY2hpbGQsIHBhcmVudCkge1xuICAgIGNoaWxkLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUocGFyZW50LnByb3RvdHlwZSk7XG4gICAgY2hpbGQucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gY2hpbGQ7XG4gIH1cblxuICAvKipcbiAgICogSW52b2tlcyBmdW5jdGlvbnMgd2l0aCBhcmd1bWVudHMuXG4gICAqIFxuICAgKiBhcmd1bWVudHNbMF0gaXMgYXNzdW1lZCB0byBiZSBhbiBhcnJheSBvZiBmdW5jdGlvbnMgdG8gaW52b2tlXG4gICAqIGFyZ3VtZW50c1sxLi4ubl0gYXJlIGFyZ3MgdG8gaW52b2tlIHRoZSBmdW5jdGlvbnMgd2l0aFxuICAgKi9cbiAgc3RhdGljIGludm9rZSgpIHtcbiAgICBsZXQgZm5zID0gYXJndW1lbnRzWzBdO1xuICAgIGxldCBhcmdzID0gW107XG4gICAgZm9yIChsZXQgaSA9IDE7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIGFyZ3MucHVzaChhcmd1bWVudHNbaV0pO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZm5zLmxlbmd0aDsgaSsrKSB7XG4gICAgICBHZW5VdGlscy5hc3NlcnRGdW5jdGlvbihmbnNbaV0sIFwiRnVuY3Rpb25zW1wiICsgaSArIFwiXSBpcyBub3QgYSBzdGF0aWNcIik7XG4gICAgICBmbnNbaV0uYXBwbHkobnVsbCwgYXJncyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHBvd2VyIHNldCBvZiB0aGUgZ2l2ZW4gYXJyYXkuXG4gICAqIFxuICAgKiBAcGFyYW0gYXJyIGlzIHRoZSBhcnJheSB0byBnZXQgdGhlIHBvd2VyIHNldCBvZlxuICAgKiBAcmV0dXJuIFtdW10gaXMgdGhlIHBvd2VyIHNldCBvZiB0aGUgZ2l2ZW4gYXJyYXlcbiAgICovXG4gIHN0YXRpYyBnZXRQb3dlclNldChhcnIpIHtcbiAgICBsZXQgZm4gPSBmdW5jdGlvbihuLCBzcmMsIGdvdCwgYWxsKSB7XG4gICAgICBpZiAobiA9PSAwKSB7XG4gICAgICAgIGlmIChnb3QubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGFsbFthbGwubGVuZ3RoXSA9IGdvdDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHNyYy5sZW5ndGg7IGorKykge1xuICAgICAgICBmbihuIC0gMSwgc3JjLnNsaWNlKGogKyAxKSwgZ290LmNvbmNhdChbIHNyY1tqXSBdKSwgYWxsKTtcbiAgICAgIH1cbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgbGV0IGFsbCA9IFtdO1xuICAgIGFsbC5wdXNoKFtdKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xuICAgICAgZm4oaSwgYXJyLCBbXSwgYWxsKTtcbiAgICB9XG4gICAgYWxsLnB1c2goYXJyKTtcbiAgICByZXR1cm4gYWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHBvd2VyIHNldCBvZiB0aGUgZ2l2ZW4gYXJyYXkgd2hvc2UgZWxlbWVudHMgYXJlIHRoZSBnaXZlbiBzaXplLlxuICAgKiBcbiAgICogQHBhcmFtIGFyciBpcyB0aGUgYXJyYXkgdG8gZ2V0IHRoZSBwb3dlciBzZXQgb2ZcbiAgICogQHBhcmFtIHNpemUgaXMgdGhlIHJlcXVpcmVkIHNpemUgb2YgdGhlIGVsZW1lbnRzIHdpdGhpbiB0aGUgcG93ZXIgc2V0XG4gICAqIHJldHVybnMgW11bXSBpcyB0aGUgcG93ZXIgc2V0IG9mIHRoZSBnaXZlbiBhcnJheSB3aG9zZSBlbGVtZW50cyBhcmUgdGhlIGdpdmVuIHNpemUgXG4gICAqL1xuICBzdGF0aWMgZ2V0UG93ZXJTZXRPZkxlbmd0aChhcnIsIHNpemUpIHtcbiAgICBHZW5VdGlscy5hc3NlcnRJbml0aWFsaXplZChhcnIpO1xuICAgIEdlblV0aWxzLmFzc2VydEluaXRpYWxpemVkKHNpemUpO1xuICAgIEdlblV0aWxzLmFzc2VydFRydWUoc2l6ZSA+PSAxKTtcbiAgICBsZXQgcG93ZXJTZXQgPSBHZW5VdGlscy5nZXRQb3dlclNldChhcnIpO1xuICAgIGxldCBwb3dlclNldE9mTGVuZ3RoID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb3dlclNldC5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKHBvd2VyU2V0W2ldLmxlbmd0aCA9PT0gc2l6ZSkge1xuICAgICAgICBwb3dlclNldE9mTGVuZ3RoLnB1c2gocG93ZXJTZXRbaV0pO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcG93ZXJTZXRPZkxlbmd0aDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGFuIGFycmF5IG9mIGluZGljZXMgb2YgdGhlIGdpdmVuIHNpemUuXG4gICAqIFxuICAgKiBAcGFyYW0gc2l6ZSBzcGVjaWZpZXMgdGhlIHNpemUgdG8gZ2V0IGluZGljZXMgZm9yXG4gICAqIEByZXR1cm4gYXJyYXkgb2YgdGhlIGdpdmVuIHNpemUgd2l0aCBpbmRpY2VzIHN0YXJ0aW5nIGF0IDBcbiAgICovXG4gIHN0YXRpYyBnZXRJbmRpY2VzKHNpemUpIHtcbiAgICBsZXQgaW5kaWNlcyA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgc2l6ZTsgaSsrKSB7XG4gICAgICBpbmRpY2VzLnB1c2goaSk7XG4gICAgfVxuICAgIHJldHVybiBpbmRpY2VzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBuZXcgYXJyYXkgY29udGFpbmluZyB1bmlxdWUgZWxlbWVudHMgb2YgdGhlIGdpdmVuIGFycmF5LlxuICAgKiBcbiAgICogQHBhcmFtIGFyciBpcyB0aGUgYXJyYXkgdG8gcmV0dXJuIHVuaXF1ZSBlbGVtZW50cyBmcm9tXG4gICAqIEByZXR1cm4gYSBuZXcgYXJyYXkgd2l0aCB0aGUgZ2l2ZW4gYXJyYXkncyB1bmlxdWUgZWxlbWVudHNcbiAgICovXG4gIHN0YXRpYyB0b1VuaXF1ZUFycmF5KGFycikge1xuICAgIHJldHVybiBhcnIuZmlsdGVyKGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgc2VsZikge1xuICAgICAgcmV0dXJuIHNlbGYuaW5kZXhPZih2YWx1ZSkgPT09IGluZGV4O1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENvcGllcyB0aGUgZ2l2ZW4gYXJyYXkuXG4gICAqIFxuICAgKiBAcGFyYW0gYXJyIGlzIHRoZSBhcnJheSB0byBjb3B5XG4gICAqIEByZXR1cm4gYSBjb3B5IG9mIHRoZSBnaXZlbiBhcnJheVxuICAgKi9cbiAgc3RhdGljIGNvcHlBcnJheShhcnIpIHtcbiAgICBHZW5VdGlscy5hc3NlcnRBcnJheShhcnIpO1xuICAgIGxldCBjb3B5ID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnIubGVuZ3RoOyBpKyspIGNvcHkucHVzaChhcnJbaV0pO1xuICAgIHJldHVybiBjb3B5O1xuICB9XG4gIFxuICAvKipcbiAgICogUmVtb3ZlcyBldmVyeSBpbnN0YW5jZSBvZiB0aGUgZ2l2ZW4gdmFsdWUgZnJvbSB0aGUgZ2l2ZW4gYXJyYXkuXG4gICAqIFxuICAgKiBAcGFyYW0gYXJyIGlzIHRoZSBhcnJheSB0byByZW1vdmUgdGhlIHZhbHVlIGZyb21cbiAgICogQHBhcmFtIHZhbCBpcyB0aGUgdmFsdWUgdG8gcmVtb3ZlIGZyb20gdGhlIGFycmF5XG4gICAqIEByZXR1cm4gdHJ1ZSBpZiB0aGUgdmFsdWUgaXMgZm91bmQgYW5kIHJlbW92ZWQsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIHJlbW92ZShhcnIsIHZhbCkge1xuICAgIGxldCBmb3VuZCA9IGZhbHNlO1xuICAgIGZvciAobGV0IGkgPSBhcnIubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgIGlmIChhcnJbaV0gPT09IHZhbCkge1xuICAgICAgICBhcnIuc3BsaWNlKGksIDEpO1xuICAgICAgICBmb3VuZCA9IHRydWU7XG4gICAgICAgIGktLTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZvdW5kO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBjb3B5IG9mIHRoZSBnaXZlbiBhcnJheSB3aGVyZSBlYWNoIGVsZW1lbnQgaXMgbG93ZXJjYXNlLlxuICAgKiBcbiAgICogQHBhcmFtIGFyciBpcyB0aGUgYXJyYXkgdG8gY29udmVydCB0byBsb3dlcmNhc2VcbiAgICogQHJldHVybiBhIGNvcHkgb2YgdGhlIGdpdmVuIGFycmF5IHdoZXJlIGVhY2ggZWxlbWVudCBpcyBsb3dlcmNhc2VcbiAgICovXG4gIHN0YXRpYyB0b0xvd2VyQ2FzZUFycmF5KGFycikge1xuICAgIGxldCBhcnIyID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnIubGVuZ3RoOyBpKyspIHtcbiAgICAgIGFycjIucHVzaChhcnJbaV0udG9Mb3dlckNhc2UoKSk7XG4gICAgfVxuICAgIHJldHVybiBhcnIyO1xuICB9XG5cbiAgLyoqXG4gICAqIExpc3RpZmllcyB0aGUgZ2l2ZW4gYXJndW1lbnQuXG4gICAqIFxuICAgKiBAcGFyYW0gYXJyT3JFbGVtIGlzIGFuIGFycmF5IG9yIGFuIGVsZW1lbnQgaW4gdGhlIGFycmF5XG4gICAqIEByZXR1cm4gYW4gYXJyYXkgd2hpY2ggaXMgdGhlIGdpdmVuIGFyZyBpZiBpdCdzIGFuIGFycmF5IG9yIGFuIGFycmF5IHdpdGggdGhlIGdpdmVuIGFyZyBhcyBhbiBlbGVtZW50XG4gICAqL1xuICBzdGF0aWMgbGlzdGlmeShhcnJPckVsZW0pIHtcbiAgICByZXR1cm4gR2VuVXRpbHMuaXNBcnJheShhcnJPckVsZW0pID8gYXJyT3JFbGVtIDogW2Fyck9yRWxlbV07XG4gIH1cblxuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIHRoZSBnaXZlbiBhcnJheSBjb250YWlucyB0aGUgZ2l2ZW4gb2JqZWN0LlxuICAgKiBcbiAgICogQHBhcmFtIHthbnl9IGFyciAtIGFycmF5IHRoYXQgbWF5IG9yIG1heSBub3QgY29udGFpbiB0aGUgb2JqZWN0XG4gICAqIEBwYXJhbSB7YW55fSBvYmogLSBvYmplY3QgdG8gY2hlY2sgZm9yIGluY2x1c2lvbiBpbiB0aGUgYXJyYXlcbiAgICogQHBhcmFtIHtib29sZWFufSBbY29tcGFyZUJ5UmVmZXJlbmNlXSAtIGNvbXBhcmUgc3RyaWN0bHkgYnkgcmVmZXJlbmNlLCBmb3Jnb2luZyBkZWVwIGVxdWFsaXR5IGNoZWNrIChkZWZhdWx0IGZhbHNlKVxuICAgKiBAcmV0dXJuIHRydWUgaWYgdGhlIGFycmF5IGNvbnRhaW5zIHRoZSBvYmplY3QsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGFycmF5Q29udGFpbnMoYXJyLCBvYmosIGNvbXBhcmVCeVJlZmVyZW5jZSA9IGZhbHNlKSB7XG4gICAgR2VuVXRpbHMuYXNzZXJ0VHJ1ZShHZW5VdGlscy5pc0FycmF5KGFycikpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYXJyLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoYXJyW2ldID09PSBvYmopIHJldHVybiB0cnVlO1xuICAgICAgaWYgKCFjb21wYXJlQnlSZWZlcmVuY2UgJiYgR2VuVXRpbHMuZXF1YWxzKGFycltpXSwgb2JqKSkgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGdpdmVuIHN0cmluZyBjb250YWlucyB0aGUgZ2l2ZW4gc3Vic3RyaW5nLlxuICAgKiBcbiAgICogQHBhcmFtIHN0ciBpcyB0aGUgc3RyaW5nIHRvIHNlYXJjaCBmb3IgYSBzdWJzdHJpbmdcbiAgICogQHBhcmFtIHN1YnN0cmluZyBpcyB0aGUgc3Vic3RyaW5nIHRvIHNlYXJjaGluIHdpdGhpbiB0aGUgc3RyaW5nXG4gICAqIEByZXR1cm4gdHJ1ZSBpZiB0aGUgc3Vic3RyaW5nIGlzIHdpdGhpbiB0aGUgc3RyaW5nLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIHN0YXRpYyBzdHJDb250YWlucyhzdHIsIHN1YnN0cmluZykge1xuICAgIHJldHVybiBzdHIuaW5kZXhPZihzdWJzdHJpbmcpID4gLTE7XG4gIH1cblxuICAvKipcbiAgICogRGV0ZXJtaW5lcyBpZiB0d28gYXJyYXlzIGFyZSBlcXVhbC5cbiAgICogXG4gICAqIEBwYXJhbSBhcnIxIGlzIGFuIGFycmF5IHRvIGNvbXBhcmVcbiAgICogQHBhcmFtIGFycjIgaXMgYW4gYXJyYXkgdG8gY29tcGFyZVxuICAgKiBAcmV0dXJuIHRydWUgaWYgdGhlIGFycmF5cyBhcmUgZXF1YWwsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGFycmF5c0VxdWFsKGFycjEsIGFycjIpIHtcbiAgICBpZiAoYXJyMSA9PT0gYXJyMikgcmV0dXJuIHRydWU7XG4gICAgaWYgKGFycjEgPT0gbnVsbCAmJiBhcnIyID09IG51bGwpIHJldHVybiB0cnVlO1xuICAgIGlmIChhcnIxID09IG51bGwgfHwgYXJyMiA9PSBudWxsKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKHR5cGVvZiBhcnIxID09PSAndW5kZWZpbmVkJyAmJiB0eXBlb2YgYXJyMiA9PT0gJ3VuZGVmaW5lZCcpIHJldHVybiB0cnVlO1xuICAgIGlmICh0eXBlb2YgYXJyMSA9PT0gJ3VuZGVmaW5lZCcgfHwgdHlwZW9mIGFycjIgPT09ICd1bmRlZmluZWQnKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKCFHZW5VdGlscy5pc0FycmF5KGFycjEpKSB0aHJvdyBuZXcgRXJyb3IoXCJGaXJzdCBhcmd1bWVudCBpcyBub3QgYW4gYXJyYXlcIik7XG4gICAgaWYgKCFHZW5VdGlscy5pc0FycmF5KGFycjIpKSB0aHJvdyBuZXcgRXJyb3IoXCJTZWNvbmQgYXJndW1lbnQgaXMgbm90IGFuIGFycmF5XCIpO1xuICAgIGlmIChhcnIxLmxlbmd0aCAhPSBhcnIyLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYXJyMS5sZW5ndGg7ICsraSkge1xuICAgICAgaWYgKCFHZW5VdGlscy5lcXVhbHMoYXJyMVtpXSwgYXJyMltpXSkpIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKipcbiAgICogRGV0ZXJtaW5lcyBpZiB0d28gYXJndW1lbnRzIGFyZSBkZWVwIGVxdWFsLlxuICAgKiBcbiAgICogQHBhcmFtIGFyZzEgaXMgYW4gYXJndW1lbnQgdG8gY29tcGFyZVxuICAgKiBAcGFyYW0gYXJnMiBpcyBhbiBhcmd1bWVudCB0byBjb21wYXJlXG4gICAqIEByZXR1cm4gdHJ1ZSBpZiB0aGUgYXJndW1lbnRzIGFyZSBkZWVwIGVxdWFscywgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgZXF1YWxzKGFyZzEsIGFyZzIpIHtcbiAgICBpZiAoR2VuVXRpbHMuaXNBcnJheShhcmcxKSAmJiBHZW5VdGlscy5pc0FycmF5KGFyZzIpKSByZXR1cm4gR2VuVXRpbHMuYXJyYXlzRXF1YWwoYXJnMSwgYXJnMik7XG4gICAgaWYgKEdlblV0aWxzLmlzT2JqZWN0KGFyZzEpICYmIEdlblV0aWxzLmlzT2JqZWN0KGFyZzIpKSByZXR1cm4gR2VuVXRpbHMub2JqZWN0c0VxdWFsKGFyZzEsIGFyZzIpO1xuICAgIHJldHVybiBhcmcxID09PSBhcmcyO1xuICB9XG4gIFxuICAvKipcbiAgICogRGV0ZXJtaW5lcyBpZiB0d28gb2JqZWN0cyBhcmUgZGVlcCBlcXVhbC5cbiAgICogXG4gICAqIFVuZGVmaW5lZCB2YWx1ZXMgYXJlIGNvbnNpZGVyZWQgZXF1YWwgdG8gbm9uLWV4aXN0ZW50IGtleXMuXG4gICAqIFxuICAgKiBAcGFyYW0gbWFwMSBpcyBhIG1hcCB0byBjb21wYXJlXG4gICAqIEBwYXJhbSBtYXAyIGlzIGEgbWFwIHRvIGNvbXBhcmVcbiAgICogQHJldHVybiB0cnVlIGlmIHRoZSBtYXBzIGhhdmUgaWRlbnRpY2FsIGtleXMgYW5kIHZhbHVlcywgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgb2JqZWN0c0VxdWFsKG1hcDEsIG1hcDIpIHtcbiAgICBsZXQga2V5czEgPSBPYmplY3Qua2V5cyhtYXAxKTtcbiAgICBsZXQga2V5czIgPSBPYmplY3Qua2V5cyhtYXAyKTtcbiAgICBcbiAgICAvLyBjb21wYXJlIGVhY2gga2V5MSB0byBrZXlzMlxuICAgIGZvciAobGV0IGtleTEgb2Yga2V5czEpIHtcbiAgICAgIGxldCBmb3VuZCA9IGZhbHNlO1xuICAgICAgZm9yIChsZXQga2V5MiBvZiBrZXlzMikge1xuICAgICAgICBpZiAoa2V5MSA9PT0ga2V5Mikge1xuICAgICAgICAgIGlmICghR2VuVXRpbHMuZXF1YWxzKG1hcDFba2V5MV0sIG1hcDJba2V5Ml0pKSByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgZm91bmQgPSB0cnVlO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoIWZvdW5kICYmIG1hcDFba2V5MV0gIT09IHVuZGVmaW5lZCkgcmV0dXJuIGZhbHNlOyAvLyBhbGxvd3MgdW5kZWZpbmVkIHZhbHVlcyB0byBlcXVhbCBub24tZXhpc3RlbnQga2V5c1xuICAgIH1cbiAgICBcbiAgICAvLyBjb21wYXJlIGVhY2gga2V5MiB0byBrZXlzMVxuICAgIGZvciAobGV0IGtleTIgb2Yga2V5czIpIHtcbiAgICAgIGxldCBmb3VuZCA9IGZhbHNlO1xuICAgICAgZm9yIChsZXQga2V5MSBvZiBrZXlzMSkge1xuICAgICAgICBpZiAoa2V5MSA9PT0ga2V5Mikge1xuICAgICAgICAgIGZvdW5kID0gdHJ1ZTsgLy8gbm8gbmVlZCB0byByZS1jb21wYXJlIHdoaWNoIHdhcyBkb25lIGVhcmxpZXJcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKCFmb3VuZCAmJiBtYXAyW2tleTJdICE9PSB1bmRlZmluZWQpIHJldHVybiBmYWxzZTsgLy8gYWxsb3dzIHVuZGVmaW5lZCB2YWx1ZXMgdG8gZXF1YWwgbm9uLWV4aXN0ZW50IGtleXNcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gICAgXG4gICAgLy8gVE9ETzogc3VwcG9ydCBzdHJpY3Qgb3B0aW9uP1xuLy8gICAgaWYgKHN0cmljdCkge1xuLy8gICAgICBsZXQga2V5czEgPSBPYmplY3Qua2V5cyhtYXAxKTtcbi8vICAgICAgaWYgKGtleXMxLmxlbmd0aCAhPT0gT2JqZWN0LmtleXMobWFwMikubGVuZ3RoKSByZXR1cm4gZmFsc2U7XG4vLyAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwga2V5czEubGVuZ3RoOyBpKyspIHtcbi8vICAgICAgICBsZXQga2V5ID0gT2JqZWN0LmtleXMobWFwMSlbaV07XG4vLyAgICAgICAgaWYgKCFHZW5VdGlscy5lcXVhbHMobWFwMVtrZXldLCBtYXAyW2tleV0pKSByZXR1cm4gZmFsc2U7XG4vLyAgICAgIH1cbi8vICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIERlbGV0ZXMgcHJvcGVydGllcyBmcm9tIHRoZSBvYmplY3QgdGhhdCBhcmUgdW5kZWZpbmVkLlxuICAgKiBcbiAgICogQHBhcmFtIG9iaiBpcyB0aGUgb2JqZWN0IHRvIGRlbGV0ZSB1bmRlZmluZWQga2V5cyBmcm9tXG4gICAqL1xuICBzdGF0aWMgZGVsZXRlVW5kZWZpbmVkS2V5cyhvYmopIHtcbiAgICBmb3IgKGxldCBrZXkgb2YgT2JqZWN0LmtleXMob2JqKSkge1xuICAgICAgaWYgKG9ialtrZXldID09PSB1bmRlZmluZWQpIGRlbGV0ZSBvYmpba2V5XTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBjb21iaW5hdGlvbnMgb2YgdGhlIGdpdmVuIGFycmF5IG9mIHRoZSBnaXZlbiBzaXplLlxuICAgKiBcbiAgICogQHBhcmFtIGFyciBpcyB0aGUgYXJyYXkgdG8gZ2V0IGNvbWJpbmF0aW9ucyBmcm9tXG4gICAqIEBwYXJhbSBjb21iaW5hdGlvblNpemUgc3BlY2lmaWVzIHRoZSBzaXplIG9mIGVhY2ggY29tYmluYXRpb25cbiAgICovXG4gIHN0YXRpYyBnZXRDb21iaW5hdGlvbnMoYXJyLCBjb21iaW5hdGlvblNpemUpIHtcbiAgICBcbiAgICAvLyB2YWxpZGF0ZSBpbnB1dFxuICAgIEdlblV0aWxzLmFzc2VydEluaXRpYWxpemVkKGFycik7XG4gICAgR2VuVXRpbHMuYXNzZXJ0SW5pdGlhbGl6ZWQoY29tYmluYXRpb25TaXplKTtcbiAgICBHZW5VdGlscy5hc3NlcnRUcnVlKGNvbWJpbmF0aW9uU2l6ZSA+PSAxKTtcbiAgICBcbiAgICAvLyBnZXQgY29tYmluYXRpb25zIG9mIGFycmF5IGluZGljZXMgb2YgdGhlIGdpdmVuIHNpemVcbiAgICBsZXQgaW5kZXhDb21iaW5hdGlvbnMgPSBHZW5VdGlscy5nZXRQb3dlclNldE9mTGVuZ3RoKEdlblV0aWxzLmdldEluZGljZXMoYXJyLmxlbmd0aCksIGNvbWJpbmF0aW9uU2l6ZSk7XG4gICAgXG4gICAgLy8gY29sbGVjdCBjb21iaW5hdGlvbnMgZnJvbSBlYWNoIGNvbWJpbmF0aW9uIG9mIGFycmF5IGluZGljZXNcbiAgICBsZXQgY29tYmluYXRpb25zID0gW107XG4gICAgZm9yIChsZXQgaW5kZXhDb21iaW5hdGlvbnNJZHggPSAwOyBpbmRleENvbWJpbmF0aW9uc0lkeCA8IGluZGV4Q29tYmluYXRpb25zLmxlbmd0aDsgaW5kZXhDb21iaW5hdGlvbnNJZHgrKykge1xuICAgICAgXG4gICAgICAvLyBnZXQgY29tYmluYXRpb24gb2YgYXJyYXkgaW5kaWNlc1xuICAgICAgbGV0IGluZGV4Q29tYmluYXRpb24gPSBpbmRleENvbWJpbmF0aW9uc1tpbmRleENvbWJpbmF0aW9uc0lkeF07XG4gICAgICBcbiAgICAgIC8vIGJ1aWxkIGNvbWJpbmF0aW9uIGZyb20gYXJyYXlcbiAgICAgIGxldCBjb21iaW5hdGlvbiA9IFtdO1xuICAgICAgZm9yIChsZXQgaW5kZXhDb21iaW5hdGlvbklkeCA9IDA7IGluZGV4Q29tYmluYXRpb25JZHggPCBpbmRleENvbWJpbmF0aW9uLmxlbmd0aDsgaW5kZXhDb21iaW5hdGlvbklkeCsrKSB7XG4gICAgICAgIGNvbWJpbmF0aW9uLnB1c2goYXJyW2luZGV4Q29tYmluYXRpb25baW5kZXhDb21iaW5hdGlvbklkeF1dKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gYWRkIHRvIGNvbWJpbmF0aW9uc1xuICAgICAgY29tYmluYXRpb25zLnB1c2goY29tYmluYXRpb24pO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gY29tYmluYXRpb25zO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgYW4gJ2EnIGVsZW1lbnQgdGhhdCBpcyBkb3dubG9hZGFibGUgd2hlbiBjbGlja2VkLlxuICAgKiBcbiAgICogQHBhcmFtIG5hbWUgaXMgdGhlIG5hbWUgb2YgdGhlIGZpbGUgdG8gZG93bmxvYWRcbiAgICogQHBhcmFtIGNvbnRlbnRzIGFyZSB0aGUgc3RyaW5nIGNvbnRlbnRzIG9mIHRoZSBmaWxlIHRvIGRvd25sb2FkXG4gICAqIEByZXR1cm4gJ2EnIGRvbSBlbGVtZW50IHdpdGggZG93bmxvYWRhYmxlIGZpbGVcbiAgICovXG4gIHN0YXRpYyBnZXREb3dubG9hZGFibGVBKG5hbWUsIGNvbnRlbnRzKSB7XG4gICAgbGV0IGEgPSB3aW5kb3cuZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO1xuICAgIGEuaHJlZiA9IHdpbmRvdy5VUkwuY3JlYXRlT2JqZWN0VVJMKG5ldyBCbG9iKFtjb250ZW50c10sIHt0eXBlOiAndGV4dC9wbGFpbid9KSk7XG4gICAgYS5kb3dubG9hZCA9IG5hbWU7XG4gICAgYS50YXJnZXQ9XCJfYmxhbmtcIjtcbiAgICBhLmlubmVySFRNTCA9IG5hbWU7XG4gICAgcmV0dXJuIGE7XG4gIH1cblxuICAvKipcbiAgICogQ29waWVzIHByb3BlcnRpZXMgaW4gdGhlIGdpdmVuIG9iamVjdCB0byBhIG5ldyBvYmplY3QuXG4gICAqIFxuICAgKiBAcGFyYW0gb2JqIGlzIG9iamVjdCB0byBjb3B5IHByb3BlcnRpZXMgZm9yXG4gICAqIEByZXR1cm4gYSBuZXcgb2JqZWN0IHdpdGggcHJvcGVydGllcyBjb3BpZWQgZnJvbSB0aGUgZ2l2ZW4gb2JqZWN0XG4gICAqL1xuICBzdGF0aWMgY29weVByb3BlcnRpZXMob2JqKSB7XG4gICAgcmV0dXJuIEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkob2JqKSlcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGVzIGFsbCBwcm9wZXJ0aWVzIGluIHRoZSBnaXZlbiBvYmplY3QuXG4gICAqIFxuICAgKiBAcGFyYW0gb2JqIGlzIHRoZSBvYmplY3QgdG8gZGVsZXRlIHByb3BlcnRpZXMgZnJvbVxuICAgKi9cbiAgc3RhdGljIGRlbGV0ZVByb3BlcnRpZXMob2JqKSB7XG4gICAgbGV0IHByb3BzID0gW107XG4gICAgZm9yIChsZXQgcHJvcCBpbiBvYmopIHByb3BzLnB1c2gocHJvcCk7IC8vIFRPRE86IGlmIChvYmouaGFzT3duUHJvcGVydHkocHJvcCkpIHsgLi4uXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwcm9wcy5sZW5ndGg7IGkrKykgZGVsZXRlIG9ialtwcm9wc1tpXS50b1N0cmluZygpXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGdpdmVuIHN0cmluZyBjb250YWlucyB3aGl0ZXNwYWNlLlxuICAgKiBcbiAgICogQHBhcmFtIHN0ciBpcyB0aGUgc3RyaW5nIHRvIHRlc3RcbiAgICogQHJldHVybiB0cnVlIGlmIHRoZSBzdHJpbmcgY29udGFpbnMgd2hpdGVzcGFjZSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgaGFzV2hpdGVzcGFjZShzdHIpIHtcbiAgICByZXR1cm4gL1xccy9nLnRlc3Qoc3RyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGdpdmVuIGNoYXJhY3RlciBpcyB3aGl0ZXNwYWNlLlxuICAgKiBcbiAgICogQHBhcmFtIGNoYXIgaXMgdGhlIGNoYXJhY3RlciB0byB0ZXN0XG4gICAqIEByZXR1cm4gdHJ1ZSBpZiB0aGUgZ2l2ZW4gY2hhcmFjdGVyIGlzIHdoaXRlc3BhY2UsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGlzV2hpdGVzcGFjZShjaGFyKSB7XG4gICAgcmV0dXJuIC9cXHMvLnRlc3QoY2hhcik7XG4gIH1cblxuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIHRoZSBnaXZlbiBjaGFyYWN0ZXIgaXMgYSBuZXdsaW5lLlxuICAgKiBcbiAgICogQHBhcmFtIGNoYXIgaXMgdGhlIGNoYXJhY3RlciB0byB0ZXN0XG4gICAqIEByZXR1cm4gdHJ1ZSBpZiB0aGUgZ2l2ZW4gY2hhcmFjdGVyIGlzIGEgbmV3bGluZSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgaXNOZXdsaW5lKGNoYXIpIHtcbiAgICByZXR1cm4gY2hhciA9PT0gJ1xcbicgfHwgY2hhciA9PT0gJ1xccic7XG4gIH1cblxuICAvKipcbiAgICogQ291bnRzIHRoZSBudW1iZXIgb2Ygbm9uLXdoaXRlc3BhY2UgY2hhcmFjdGVycyBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxuICAgKiBcbiAgICogQHBhcmFtIHN0ciBpcyB0aGUgc3RyaW5nIHRvIGNvdW50IHRoZSBudW1iZXIgb2Ygbm9uLXdoaXRlc3BhY2UgY2hhcmFjdGVycyBpblxuICAgKiBAcmV0dXJuIGludCBpcyB0aGUgbnVtYmVyIG9mIG5vbi13aGl0ZXNwYWNlIGNoYXJhY3RlcnMgaW4gdGhlIGdpdmVuIHN0cmluZ1xuICAgKi9cbiAgc3RhdGljIGNvdW50Tm9uV2hpdGVzcGFjZUNoYXJhY3RlcnMoc3RyKSB7XG4gICAgbGV0IGNvdW50ID0gMDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHN0ci5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKCFHZW5VdGlscy5pc1doaXRlc3BhY2Uoc3RyLmNoYXJBdChpKSkpIGNvdW50Kys7XG4gICAgfVxuICAgIHJldHVybiBjb3VudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRva2VucyBzZXBhcmF0ZWQgYnkgd2hpdGVzcGFjZSBmcm9tIHRoZSBnaXZlbiBzdHJpbmcuXG4gICAqIFxuICAgKiBAcGFyYW0gc3RyIGlzIHRoZSBzdHJpbmcgdG8gZ2V0IHRva2VucyBmcm9tXG4gICAqIEByZXR1cm4gc3RyaW5nW10gYXJlIHRoZSB0b2tlbnMgc2VwYXJhdGVkIGJ5IHdoaXRlc3BhY2Ugd2l0aGluIHRoZSBzdHJpbmdcbiAgICovXG4gIHN0YXRpYyBnZXRXaGl0ZXNwYWNlVG9rZW5zKHN0cikge1xuICAgIHJldHVybiBzdHIubWF0Y2goL1xcUysvZyk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBsaW5lcyBzZXBhcmF0ZWQgYnkgbmV3bGluZXMgZnJvbSB0aGUgZ2l2ZW4gc3RyaW5nLlxuICAgKiBcbiAgICogQHBhcmFtIHN0ciBpcyB0aGUgc3RyaW5nIHRvIGdldCBsaW5lcyBmcm9tXG4gICAqIEBwYXJhbSBzdHJpbmdbXSBhcmUgdGhlIGxpbmVzIHNlcGFyYXRlZCBieSBuZXdsaW5lcyB3aXRoaW4gdGhlIHN0cmluZ1xuICAgKi9cbiAgc3RhdGljIGdldExpbmVzKHN0cikge1xuICAgIHJldHVybiBzdHIubWF0Y2goL1teXFxyXFxuXSsvZyk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgZG9jdW1lbnQncyBmaXJzdCBzdHlsZXNoZWV0IHdoaWNoIGhhcyBubyBocmVmLlxuICAgKiBcbiAgICogQHJldHVybiBTdHlsZVNoZWV0IGlzIHRoZSBpbnRlcm5hbCBzdHlsZXNoZWV0XG4gICAqL1xuICBzdGF0aWMgZ2V0SW50ZXJuYWxTdHlsZVNoZWV0KCkge1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZG9jdW1lbnQuc3R5bGVTaGVldHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGxldCBzdHlsZVNoZWV0ID0gZG9jdW1lbnQuc3R5bGVTaGVldHNbaV07XG4gICAgICBpZiAoIXN0eWxlU2hlZXQuaHJlZikgcmV0dXJuIHN0eWxlU2hlZXQ7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGRvY3VtZW50J3MgaW50ZXJuYWwgc3R5bGVzaGVldCBhcyB0ZXh0LlxuICAgKiBcbiAgICogQHJldHVybiBzdHIgaXMgdGhlIGRvY3VtZW50J3MgaW50ZXJuYWwgc3R5bGVzaGVldFxuICAgKi9cbiAgc3RhdGljIGdldEludGVybmFsU3R5bGVTaGVldFRleHQoKSB7XG4gICAgbGV0IGludGVybmFsQ3NzID0gXCJcIjtcbiAgICBsZXQgaW50ZXJuYWxTdHlsZVNoZWV0ID0gR2VuVXRpbHMuZ2V0SW50ZXJuYWxTdHlsZVNoZWV0KCk7XG4gICAgaWYgKCFpbnRlcm5hbFN0eWxlU2hlZXQpIHJldHVybiBudWxsO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaW50ZXJuYWxTdHlsZVNoZWV0LmNzc1J1bGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpbnRlcm5hbENzcyArPSBpbnRlcm5hbFN0eWxlU2hlZXQuY3NzUnVsZXNbaV0uY3NzVGV4dCArIFwiXFxuXCI7XG4gICAgfVxuICAgIHJldHVybiBpbnRlcm5hbENzcztcbiAgfVxuXG4gIC8qKlxuICAgKiBNYW51YWxseSBidWlsZHMgYW4gSFRNTCBkb2N1bWVudCBzdHJpbmcuXG4gICAqIFxuICAgKiBAcGFyYW0gY29udGVudCBzcGVjaWZpZXMgb3B0aW9uYWwgZG9jdW1lbnQgY29udGVudFxuICAgKiAgICAgICAgY29udGVudC5kaXYgaXMgYSBwcmUtZXhpc3RpbmcgZGl2IHRvIHN0cmluZ2lmeSBhbmQgYWRkIHRvIHRoZSBib2R5XG4gICAqICAgICAgICBjb250ZW50LnRpdGxlIGlzIHRoZSB0aXRsZSBvZiB0aGUgbmV3IHRhYlxuICAgKiAgICAgICAgY29udGVudC5kZXBlbmRlbmN5UGF0aHMgc3BlY2lmaWVzIHBhdGhzIHRvIGpzLCBjc3MsIG9yIGltZyBwYXRoc1xuICAgKiAgICAgICAgY29udGVudC5pbnRlcm5hbENzcyBpcyBjc3MgdG8gZW1iZWQgaW4gdGhlIGh0bWwgZG9jdW1lbnRcbiAgICogICAgICAgIGNvbnRlbnQubWV0YXMgYXJlIG1ldGEgZWxlbWVudHMgd2l0aCBrZXlzL3ZhbHVlcyB0byBpbmNsdWRlXG4gICAqIEByZXR1cm4gc3RyIGlzIHRoZSBkb2N1bWVudCBzdHJpbmdcbiAgICovXG4gIHN0YXRpYyBidWlsZEh0bWxEb2N1bWVudChjb250ZW50KSB7XG4gICAgbGV0IHN0ciA9IFwiPCFET0NUWVBFIEhUTUw+XCI7XG4gICAgc3RyICs9IFwiPGh0bWw+PGhlYWQ+XCI7XG4gICAgXG4gICAgLy8gYWRkIG1ldGFzXG4gICAgaWYgKGNvbnRlbnQubWV0YXMpIHtcbiAgICAgIGxldCBtZXRhcyA9IEdlblV0aWxzLmxpc3RpZnkoY29udGVudC5tZXRhcyk7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG1ldGFzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGxldCBtZXRhID0gbWV0YXNbaV07XG4gICAgICAgIGxldCBlbGVtID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcIm1ldGFcIik7XG4gICAgICAgIGZvciAobGV0IHByb3AgaW4gbWV0YSkge1xuICAgICAgICAgIGlmIChtZXRhLmhhc093blByb3BlcnR5KHByb3ApKSB7XG4gICAgICAgICAgICBlbGVtLnNldEF0dHJpYnV0ZShwcm9wLnRvU3RyaW5nKCksIG1ldGFbcHJvcC50b1N0cmluZygpXSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHN0ciArPSBlbGVtLm91dGVySFRNTDtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gYWRkIHRpdGxlIGFuZCBpbnRlcm5hbCBjc3NcbiAgICBzdHIgKz0gY29udGVudC50aXRsZSA/IFwiPHRpdGxlPlwiICsgY29udGVudC50aXRsZSArIFwiPC90aXRsZT5cIiA6IFwiXCI7XG4gICAgc3RyICs9IGNvbnRlbnQuaW50ZXJuYWxDc3MgPyBcIjxzdHlsZT5cIiArIGNvbnRlbnQuaW50ZXJuYWxDc3MgKyBcIjwvc3R5bGU+XCIgOiBcIlwiO1xuICAgIFxuICAgIC8vIGFkZCBkZXBlbmRlbmN5IHBhdGhzXG4gICAgaWYgKGNvbnRlbnQuZGVwZW5kZW5jeVBhdGhzKSB7XG4gICAgICBsZXQgZGVwZW5kZW5jeVBhdGhzID0gR2VuVXRpbHMubGlzdGlmeShjb250ZW50LmRlcGVuZGVuY3lQYXRocyk7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRlcGVuZGVuY3lQYXRocy5sZW5ndGg7IGkrKykge1xuICAgICAgICBsZXQgZGVwZW5kZW5jeVBhdGggPSBkZXBlbmRlbmN5UGF0aHNbaV07XG4gICAgICAgIGlmIChkZXBlbmRlbmN5UGF0aC5lbmRzV2l0aChcIi5qc1wiKSkgc3RyICs9IFwiPHNjcmlwdCBzcmM9J1wiICsgZGVwZW5kZW5jeVBhdGggKyBcIic+PC9zY3JpcHQ+XCI7XG4gICAgICAgIGVsc2UgaWYgKGRlcGVuZGVuY3lQYXRoLmVuZHNXaXRoKFwiLmNzc1wiKSkgc3RyICs9IFwiPGxpbmsgcmVsPSdzdHlsZXNoZWV0JyB0eXBlPSd0ZXh0L2NzcycgaHJlZj0nXCIgKyBkZXBlbmRlbmN5UGF0aCArIFwiJy8+XCI7XG4gICAgICAgIGVsc2UgaWYgKGRlcGVuZGVuY3lQYXRoLmVuZHNXaXRoKFwiLnBuZ1wiKSB8fCBkZXBlbmRlbmN5UGF0aC5lbmRzV2l0aChcIi5pbWdcIikpICBzdHIgKz0gXCI8aW1nIHNyYz0nXCIgKyBkZXBlbmRlbmN5UGF0aCArIFwiJz5cIjtcbiAgICAgICAgZWxzZSB0aHJvdyBuZXcgRXJyb3IoXCJVbnJlY29nbml6ZWQgZGVwZW5kZW5jeSBwYXRoIGV4dGVuc2lvbjogXCIgKyBkZXBlbmRlbmN5UGF0aCk7ICAgICAgXG4gICAgICB9XG4gICAgfVxuICAgIHN0ciArPSBcIjwvaGVhZD48Ym9keT5cIjtcbiAgICBpZiAoY29udGVudC5kaXYpIHN0ciArPSAkKFwiPGRpdj5cIikuYXBwZW5kKGNvbnRlbnQuZGl2LmNsb25lKCkpLmh0bWwoKTsgIC8vIGFkZCBjbG9uZWQgZGl2IGFzIHN0cmluZ1xuICAgIHN0ciArPSBcIjwvYm9keT48L2h0bWw+XCI7XG4gICAgcmV0dXJuIHN0cjtcbiAgfVxuXG4gIC8qKlxuICAgKiBPcGVucyB0aGUgZ2l2ZW4gZGl2IGluIGEgbmV3IHdpbmRvdy5cbiAgICogXG4gICAqIEBwYXJhbSBjb250ZW50IHNwZWNpZmllcyBvcHRpb25hbCB3aW5kb3cgY29udGVudFxuICAgKiAgICAgICAgY29udGVudC5kaXYgaXMgYSBwcmUtZXhpc3RpbmcgZGl2IHRvIHN0cmluZ2lmeSBhbmQgYWRkIHRvIHRoZSBib2R5XG4gICAqICAgICAgICBjb250ZW50LnRpdGxlIGlzIHRoZSB0aXRsZSBvZiB0aGUgbmV3IHRhYlxuICAgKiAgICAgICAgY29udGVudC5kZXBlbmRlbmN5UGF0aHMgc3BlY2lmaWVzIHBhdGhzIHRvIGpzLCBjc3MsIG9yIGltZyBwYXRoc1xuICAgKiAgICAgICAgY29udGVudC5pbnRlcm5hbENzcyBpcyBjc3MgdG8gZW1iZWQgaW4gdGhlIGh0bWwgZG9jdW1lbnRcbiAgICogICAgICAgIGNvbnRlbnQubWV0YXMgYXJlIG1ldGEgZWxlbWVudHMgd2l0aCBrZXlzL3ZhbHVlcyB0byBpbmNsdWRlXG4gICAqIEBwYXJhbSBvbkxvYWQoZXJyLCB3aW5kb3cpIGlzIGludm9rZWQgd2l0aCBhIHJlZmVyZW5jZSB0byB0aGUgd2luZG93IHdoZW4gYXZhaWxhYmxlXG4gICAqL1xuICBzdGF0aWMgbmV3V2luZG93KGNvbnRlbnQsIG9uTG9hZCkge1xuICAgIGxldCBvbkxvYWRDYWxsZWQgPSBmYWxzZTtcbiAgICBsZXQgdyA9IHdpbmRvdy5vcGVuKCk7XG4gICAgaWYgKCFHZW5VdGlscy5pc0luaXRpYWxpemVkKHcpIHx8ICFHZW5VdGlscy5pc0luaXRpYWxpemVkKHcuZG9jdW1lbnQpKSB7XG4gICAgICBvbkxvYWRPbmNlKG5ldyBFcnJvcihcIkNvdWxkIG5vdCBnZXQgd2luZG93IHJlZmVyZW5jZVwiKSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHcub3BlbmVyID0gbnVsbDtcbiAgICB3LmRvY3VtZW50LndyaXRlKEdlblV0aWxzLmJ1aWxkSHRtbERvY3VtZW50KGNvbnRlbnQpKTtcbiAgICB3LmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWQnLCBmdW5jdGlvbigpIHtcbiAgICAgIG9uTG9hZE9uY2UobnVsbCwgdyk7XG4gICAgfSk7XG4gICAgdy5kb2N1bWVudC5jbG9zZSgpO1xuICAgIFxuICAgIC8vIHByZXZlbnRzIG9uTG9hZCgpIGZyb20gYmVpbmcgY2FsbGVkIG11bHRpcGxlIHRpbWVzXG4gICAgZnVuY3Rpb24gb25Mb2FkT25jZShlcnIsIHdpbmRvdz8pIHtcbiAgICAgIGlmIChvbkxvYWRDYWxsZWQpIHJldHVybjtcbiAgICAgIG9uTG9hZENhbGxlZCA9IHRydWU7XG4gICAgICBpZiAob25Mb2FkKSBvbkxvYWQoZXJyLCB3aW5kb3cpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0cyB0aGUgZ2l2ZW4gaW1hZ2UgdG8gYSBiYXNlNjQgZW5jb2RlZCBkYXRhIHVybC5cbiAgICogXG4gICAqIEBwYXJhbSBpbWcgaXMgdGhlIGltYWdlIHRvIGNvbnZlcnRcbiAgICogQHBhcmFtIHF1YWxpdHkgaXMgYSBudW1iZXIgYmV0d2VlbiAwIGFuZCAxIHNwZWNpZnlpbmcgdGhlIGltYWdlIHF1YWxpdHlcbiAgICovXG4gIHN0YXRpYyBpbWdUb0RhdGFVcmwoaW1nLCBxdWFsaXR5KSB7XG4gICAgbGV0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuICAgIGNhbnZhcy5oZWlnaHQgPSBpbWcubmF0dXJhbEhlaWdodDtcbiAgICBjYW52YXMud2lkdGggPSBpbWcubmF0dXJhbFdpZHRoO1xuICAgIGxldCBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7XG4gICAgY29udGV4dC5kcmF3SW1hZ2UoaW1nLCAwLCAwKTtcbiAgICByZXR1cm4gY2FudmFzLnRvRGF0YVVSTChxdWFsaXR5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGlmIHRoZSBpbWFnZSBhdCB0aGUgZ2l2ZW4gVVJMIGlzIGFjY2Vzc2libGUuXG4gICAqIFxuICAgKiBAcGFyYW0gdXJsIGlzIHRoZSB1cmwgdG8gYW4gaW1hZ2VcbiAgICogQHBhcmFtIHRpbWVvdXQgaXMgdGhlIG1heGltdW0gdGltZSB0byB3YWl0XG4gICAqIEBwYXJhbSBvbkRvbmUoYm9vbCkgd2hlbiB0aGUgaW1hZ2UgaXMgZGV0ZXJtaW5lZCB0byBiZSBhY2Nlc3NpYmxlIG9yIG5vdFxuICAgKi9cbiAgc3RhdGljIGlzSW1hZ2VBY2Nlc3NpYmxlKHVybCwgdGltZW91dCwgb25Eb25lKSB7XG4gICAgXG4gICAgLy8gdHJhY2sgcmV0dXJuIHNvIGl0IG9ubHkgZXhlY3V0ZXMgb25jZVxuICAgIGxldCByZXR1cm5lZCA9IGZhbHNlO1xuICAgIFxuICAgIC8vIGF0dGVtcHQgdG8gbG9hZCBmYXZpY29uXG4gICAgbGV0IGltZyA9IG5ldyBJbWFnZSgpO1xuICAgIGltZy5vbmxvYWQgPSBvblJlc3BvbnNlO1xuICAgIGltZy5vbmVycm9yID0gb25SZXNwb25zZTtcbiAgICBpbWcuc3JjID0gdXJsICsgXCI/XCIgKyAoK25ldyBEYXRlKCkpOyAvLyB0cmlnZ2VyIGltYWdlIGxvYWQgd2l0aCBjYWNoZSBidXN0ZXJcbiAgICBcbiAgICAvLyBuZXN0IGZhaWx1cmUgdGltZW91dHMgdG8gZ2l2ZSByZXNwb25zZSBhIGNoYW5jZSB3aGVuIGJyb3dzZXIgaXMgdW5kZXIgbG9hZFxuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICBzZXRJbW1lZGlhdGUoZnVuY3Rpb24oKSB7XG4gICAgICAgIHNldEltbWVkaWF0ZShmdW5jdGlvbigpIHtcbiAgICAgICAgICBzZXRJbW1lZGlhdGUoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBpZiAoIXJldHVybmVkKSB7XG4gICAgICAgICAgICAgIHJldHVybmVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgb25Eb25lKGZhbHNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9LCB0aW1lb3V0KTtcbiAgICBcbiAgICBmdW5jdGlvbiBvblJlc3BvbnNlKGUpIHtcbiAgICAgIGlmIChyZXR1cm5lZCkgcmV0dXJuO1xuICAgICAgcmV0dXJuZWQgPSB0cnVlO1xuICAgICAgaWYgKHR5cGVvZiBlID09PSAndW5kZWZpbmVkJyB8fCBlLnR5cGUgPT09IFwiZXJyb3JcIikgb25Eb25lKGZhbHNlKTtcbiAgICAgIGVsc2Ugb25Eb25lKHRydWUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGlmIHRoZSBnaXZlbiBmaWxlIGlzIGEgemlwIGZpbGUuXG4gICAqIFxuICAgKiBAcGFyYW0gZmlsZSBpcyBhIGZpbGVcbiAgICogQHJldHVybiB0cnVlIGlmIHRoZSBnaXZlbiBmaWxlIGlzIGEgemlwIGZpbGUsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGlzWmlwRmlsZShmaWxlKSB7XG4gICAgcmV0dXJuIGZpbGUubmFtZS5lbmRzV2l0aChcIi56aXBcIikgfHwgZmlsZS50eXBlID09PSAnYXBwbGljYXRpb24vemlwJztcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGlmIHRoZSBnaXZlbiBmaWxlIGlzIGEganNvbiBmaWxlLlxuICAgKiBcbiAgICogQHBhcmFtIGZpbGUgaXMgYSBmaWxlXG4gICAqIEByZXR1cm4gdHJ1ZSBpZiB0aGUgZ2l2ZW4gZmlsZSBpcyBhIGpzb24gZmlsZSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgaXNKc29uRmlsZShmaWxlKSB7XG4gICAgcmV0dXJuIGZpbGUubmFtZS5lbmRzV2l0aChcIi5qc29uXCIpIHx8IGZpbGUudHlwZSA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVybWluZXMgaWYgdGhlIGdpdmVuIGZpbGUgaXMgYSB0eHQgZmlsZS5cbiAgICogXG4gICAqIEBwYXJhbSBmaWxlIGlzIGEgZmlsZVxuICAgKiBAcmV0dXJuIHRydWUgaWYgdGhlIGdpdmVuIGZpbGUgaXMgYSB0eHQgZmlsZSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgaXNUeHRGaWxlKGZpbGUpIHtcbiAgICByZXR1cm4gZmlsZS5uYW1lLmVuZHNXaXRoKFwiLnR4dFwiKSB8fCBmaWxlLnR5cGUgPT09ICd0ZXh0L3BsYWluJztcbiAgfVxuXG4gIC8qKlxuICAgKiBGZXRjaGVzIHRoZSBnaXZlbiBsaXN0IG9mIGltYWdlcy5cbiAgICogXG4gICAqIFByZXJlcXVpc2l0ZTogYXN5bmMuanMuXG4gICAqIFxuICAgKiBAcGFyYW0gcGF0aHMgYXJlIHRoZSBwYXRocyB0byB0aGUgaW1hZ2VzIHRvIGZldGNoXG4gICAqIEBwYXJhbSBvbkRvbmUoZXJyLCBpbWFnZXMpIGlzIGNhbGxlZCB3aGVuIGRvbmVcbiAgICovXG4gIHN0YXRpYyBnZXRJbWFnZXMocGF0aHMsIG9uRG9uZSkge1xuICAgIFxuICAgIC8vIGxpc3RpZnkgcGF0aHNcbiAgICBpZiAoIUdlblV0aWxzLmlzQXJyYXkocGF0aHMpKSB7XG4gICAgICBHZW5VdGlscy5hc3NlcnRUcnVlKEdlblV0aWxzLmlzU3RyaW5nKHBhdGhzKSk7XG4gICAgICBwYXRocyA9IFtwYXRoc107XG4gICAgfVxuICAgIFxuICAgIC8vIGNvbGxlY3QgZnVuY3Rpb25zIHRvIGZldGNoIGltYWdlc1xuICAgIGxldCBmdW5jcyA9IFtdO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcGF0aHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGZ1bmNzLnB1c2gobG9hZEZ1bmMocGF0aHNbaV0pKTtcbiAgICB9XG4gICAgXG4gICAgLy8gZmV0Y2ggaW4gcGFyYWxsZWxcbiAgICBhc3luYy5wYXJhbGxlbChmdW5jcywgb25Eb25lKTtcbiAgICBcbiAgICAvLyBjYWxsYmFjayBzdGF0aWMgdG8gZmV0Y2ggYSBzaW5nbGUgaW1hZ2VcbiAgICBmdW5jdGlvbiBsb2FkRnVuYyhwYXRoKSB7XG4gICAgICByZXR1cm4gZnVuY3Rpb24ob25Eb25lKSB7XG4gICAgICAgIGxldCBpbWcgPSBuZXcgSW1hZ2UoKTtcbiAgICAgICAgaW1nLm9ubG9hZCA9IGZ1bmN0aW9uKCkgeyBvbkRvbmUobnVsbCwgaW1nKTsgfVxuICAgICAgICBpbWcub25lcnJvciA9IGZ1bmN0aW9uKCkgeyBvbkRvbmUobmV3IEVycm9yKFwiQ2Fubm90IGxvYWQgaW1hZ2U6IFwiICsgcGF0aCkpOyB9XG4gICAgICAgIGltZy5zcmMgPSBwYXRoO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFJldHVybnMgYSBzdHJpbmcgaW5kZW50YXRpb24gb2YgdGhlIGdpdmVuIGxlbmd0aDtcbiAgICogXG4gICAqIEBwYXJhbSBsZW5ndGggaXMgdGhlIGxlbmd0aCBvZiB0aGUgaW5kZW50YXRpb25cbiAgICogQHJldHVybiB7c3RyaW5nfSBpcyBhbiBpbmRlbnRhdGlvbiBzdHJpbmcgb2YgdGhlIGdpdmVuIGxlbmd0aFxuICAgKi9cbiAgc3RhdGljIGdldEluZGVudChsZW5ndGgpIHtcbiAgICBsZXQgc3RyID0gXCJcIjtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSBzdHIgKz0gJyAgJzsgLy8gdHdvIHNwYWNlc1xuICAgIHJldHVybiBzdHI7XG4gIH1cbiAgXG4gIHN0YXRpYyBpbml0UG9seWZpbGxzKCkge1xuICAgIFxuICAgIC8vIFBvbHlmaWxsIE9iamVjdC5hc3NpZ24oKVxuICAgIC8vIENyZWRpdDogaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvT2JqZWN0L2Fzc2lnblxuICAgIGlmICh0eXBlb2YgT2JqZWN0LmFzc2lnbiAhPSAnZnVuY3Rpb24nKSB7XG4gICAgICAvLyBNdXN0IGJlIHdyaXRhYmxlOiB0cnVlLCBlbnVtZXJhYmxlOiBmYWxzZSwgY29uZmlndXJhYmxlOiB0cnVlXG4gICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoT2JqZWN0LCBcImFzc2lnblwiLCB7XG4gICAgICAgIHZhbHVlOiBmdW5jdGlvbiBhc3NpZ24odGFyZ2V0LCB2YXJBcmdzKSB7IC8vIC5sZW5ndGggb2Ygc3RhdGljIGlzIDJcbiAgICAgICAgICAndXNlIHN0cmljdCc7XG4gICAgICAgICAgaWYgKHRhcmdldCA9PSBudWxsKSB7IC8vIFR5cGVFcnJvciBpZiB1bmRlZmluZWQgb3IgbnVsbFxuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignQ2Fubm90IGNvbnZlcnQgdW5kZWZpbmVkIG9yIG51bGwgdG8gb2JqZWN0Jyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgbGV0IHRvID0gT2JqZWN0KHRhcmdldCk7XG5cbiAgICAgICAgICBmb3IgKGxldCBpbmRleCA9IDE7IGluZGV4IDwgYXJndW1lbnRzLmxlbmd0aDsgaW5kZXgrKykge1xuICAgICAgICAgICAgbGV0IG5leHRTb3VyY2UgPSBhcmd1bWVudHNbaW5kZXhdO1xuXG4gICAgICAgICAgICBpZiAobmV4dFNvdXJjZSAhPSBudWxsKSB7IC8vIFNraXAgb3ZlciBpZiB1bmRlZmluZWQgb3IgbnVsbFxuICAgICAgICAgICAgICBmb3IgKGxldCBuZXh0S2V5IGluIG5leHRTb3VyY2UpIHtcbiAgICAgICAgICAgICAgICAvLyBBdm9pZCBidWdzIHdoZW4gaGFzT3duUHJvcGVydHkgaXMgc2hhZG93ZWRcbiAgICAgICAgICAgICAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG5leHRTb3VyY2UsIG5leHRLZXkpKSB7XG4gICAgICAgICAgICAgICAgICB0b1tuZXh0S2V5XSA9IG5leHRTb3VyY2VbbmV4dEtleV07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0bztcbiAgICAgICAgfSxcbiAgICAgICAgd3JpdGFibGU6IHRydWUsXG4gICAgICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIC8qKlxuICAgICAqIFBvbHlmaWxsIHN0ci5zdGFydHNXaXRoKHNlYXJjaFN0cmluZywgcG9zaXRpb24pLlxuICAgICAqIFxuICAgICAqIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL1N0cmluZy9zdGFydHNXaXRoI1BvbHlmaWxsXG4gICAgICovXG4gICAgU3RyaW5nLnByb3RvdHlwZS5zdGFydHNXaXRoID0gZnVuY3Rpb24oc2VhcmNoU3RyaW5nLCBwb3NpdGlvbikge1xuICAgICAgcmV0dXJuIHRoaXMuc3Vic3RyKHBvc2l0aW9uIHx8IDAsIHNlYXJjaFN0cmluZy5sZW5ndGgpID09PSBzZWFyY2hTdHJpbmc7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFBvbHlmaWxsIHN0ci5lbmRzV2l0aChzZWFyY2hTdHJpbmcsIHBvc2l0aW9uKS5cbiAgICAgKiBcbiAgICAgKiBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9TdHJpbmcvZW5kc1dpdGgjUG9seWZpbGxcbiAgICAgKi9cbiAgICBTdHJpbmcucHJvdG90eXBlLmVuZHNXaXRoID0gZnVuY3Rpb24oc2VhcmNoU3RyaW5nLCBwb3NpdGlvbikge1xuICAgICAgaWYgKCEocG9zaXRpb24gPCB0aGlzLmxlbmd0aCkpIHBvc2l0aW9uID0gdGhpcy5sZW5ndGg7ICAvLyB3b3JrcyBiZXR0ZXIgdGhhbiA+PSBiZWNhdXNlIGl0IGNvbXBlbnNhdGVzIGZvciBOYU5cbiAgICAgIGVsc2UgcG9zaXRpb24gfD0gMDsgLy8gcm91bmQgcG9zaXRpb25cbiAgICAgIHJldHVybiB0aGlzLnN1YnN0cihwb3NpdGlvbiAtIHNlYXJjaFN0cmluZy5sZW5ndGgsIHNlYXJjaFN0cmluZy5sZW5ndGgpID09PSBzZWFyY2hTdHJpbmc7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlcyBhIHY0IFVVSUQuXG4gICAqIFxuICAgKiBTb3VyY2U6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzEwNTAzNC9jcmVhdGUtZ3VpZC11dWlkLWluLWphdmFzY3JpcHRcbiAgICovXG4gIHN0YXRpYyBnZXRVVUlEKCkge1xuICAgIHJldHVybiAneHh4eHh4eHgteHh4eC00eHh4LXl4eHgteHh4eHh4eHh4eHh4Jy5yZXBsYWNlKC9beHldL2csIGZ1bmN0aW9uKGMpIHtcbiAgICAgIGxldCByID0gTWF0aC5yYW5kb20oKSAqIDE2IHwgMCwgdiA9IGMgPT0gJ3gnID8gciA6IChyICYgMHgzIHwgMHg4KTtcbiAgICAgIHJldHVybiB2LnRvU3RyaW5nKDE2KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgY3VycmVudCBlbnZpcm9ubWVudCBpcyBhIGJyb3dzZXIuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHRoZSBlbnZpcm9ubWVudCBpcyBhIGJyb3dzZXIsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGlzQnJvd3NlcigpIHtcbiAgICBsZXQgaXNXb3JrZXIgPSB0eXBlb2YgaW1wb3J0U2NyaXB0cyA9PT0gJ2Z1bmN0aW9uJztcbiAgICBsZXQgaXNCcm93c2VyTWFpbiA9IG5ldyBGdW5jdGlvbihcInRyeSB7cmV0dXJuIHRoaXM9PT13aW5kb3c7fWNhdGNoKGUpe3JldHVybiBmYWxzZTt9XCIpKCk7XG4gICAgbGV0IGlzSnNEb20gPSBpc0Jyb3dzZXJNYWluID8gbmV3IEZ1bmN0aW9uKFwidHJ5IHtyZXR1cm4gd2luZG93Lm5hdmlnYXRvci51c2VyQWdlbnQuaW5jbHVkZXMoJ2pzZG9tJyk7fWNhdGNoKGUpe3JldHVybiBmYWxzZTt9XCIpKCkgOiBmYWxzZTtcbiAgICByZXR1cm4gaXNXb3JrZXIgfHwgKGlzQnJvd3Nlck1haW4gJiYgIWlzSnNEb20pO1xuICB9XG4gIFxuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIHRoZSBjdXJyZW50IGVudmlyb25tZW50IGlzIERlbm9cbiAgICogXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgdGhlIGVudmlyb25tZW50IGlzIERlbm8sIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGlzRGVubygpIHtcbiAgICByZXR1cm4gdHlwZW9mIERlbm8gPT09IFwib2JqZWN0XCIgJiYgRGVuby5oYXNPd25Qcm9wZXJ0eShcInZlcnNpb25cIikgJiYgdHlwZW9mIERlbm8udmVyc2lvbiA9PT0gXCJvYmplY3RcIiAmJiBEZW5vLnZlcnNpb24uaGFzT3duUHJvcGVydHkoXCJkZW5vXCIpICYmIHR5cGVvZiBEZW5vLnZlcnNpb24uZGVubyA9PT0gXCJzdHJpbmdcIjtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgY3VycmVudCBlbnZpcm9ubWVudCBpcyBhIGZpcmVmb3gtYmFzZWQgYnJvd3Nlci5cbiAgICogXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgdGhlIGVudmlyb25tZW50IGlzIGEgZmlyZWZveC1iYXNlZCBicm93c2VyLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIHN0YXRpYyBpc0ZpcmVmb3goKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNCcm93c2VyKCkgJiYgbmF2aWdhdG9yLnVzZXJBZ2VudC5pbmRleE9mKFwiRmlyZWZveFwiKSA+IDA7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgSUUgdmVyc2lvbiBudW1iZXIuXG4gICAqIFxuICAgKiBDcmVkaXQ6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzE5OTk5Mzg4L2NoZWNrLWlmLXVzZXItaXMtdXNpbmctaWUtd2l0aC1qcXVlcnkvMjE3MTIzNTYjMjE3MTIzNTZcbiAgICogXG4gICAqIEByZXR1cm4gdGhlIElFIHZlcnNpb24gbnVtYmVyIG9yIG51bGwgaWYgbm90IElFXG4gICAqL1xuICBzdGF0aWMgZ2V0SUVWZXJzaW9uKCkge1xuICAgIGxldCB1YSA9IHdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50O1xuXG4gICAgbGV0IG1zaWUgPSB1YS5pbmRleE9mKCdNU0lFICcpO1xuICAgIGlmIChtc2llID4gMCkge1xuICAgICAgICAvLyBJRSAxMCBvciBvbGRlciA9PiByZXR1cm4gdmVyc2lvbiBudW1iZXJcbiAgICAgICAgcmV0dXJuIHBhcnNlSW50KHVhLnN1YnN0cmluZyhtc2llICsgNSwgdWEuaW5kZXhPZignLicsIG1zaWUpKSwgMTApO1xuICAgIH1cblxuICAgIGxldCB0cmlkZW50ID0gdWEuaW5kZXhPZignVHJpZGVudC8nKTtcbiAgICBpZiAodHJpZGVudCA+IDApIHtcbiAgICAgICAgLy8gSUUgMTEgPT4gcmV0dXJuIHZlcnNpb24gbnVtYmVyXG4gICAgICAgIGxldCBydiA9IHVhLmluZGV4T2YoJ3J2OicpO1xuICAgICAgICByZXR1cm4gcGFyc2VJbnQodWEuc3Vic3RyaW5nKHJ2ICsgMywgdWEuaW5kZXhPZignLicsIHJ2KSksIDEwKTtcbiAgICB9XG5cbiAgICBsZXQgZWRnZSA9IHVhLmluZGV4T2YoJ0VkZ2UvJyk7XG4gICAgaWYgKGVkZ2UgPiAwKSB7XG4gICAgICAgLy8gRWRnZSAoSUUgMTIrKSA9PiByZXR1cm4gdmVyc2lvbiBudW1iZXJcbiAgICAgICByZXR1cm4gcGFyc2VJbnQodWEuc3Vic3RyaW5nKGVkZ2UgKyA1LCB1YS5pbmRleE9mKCcuJywgZWRnZSkpLCAxMCk7XG4gICAgfVxuXG4gICAgLy8gb3RoZXIgYnJvd3NlclxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgYSBwYXJhbWV0ZXIgdmFsdWUuXG4gICAqIFxuICAgKiBDcmVkaXQ6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzkwMTExNS9ob3ctY2FuLWktZ2V0LXF1ZXJ5LXN0cmluZy12YWx1ZXMtaW4tamF2YXNjcmlwdFxuICAgKiBcbiAgICogQHBhcmFtIG5hbWUgaXMgdGhlIG5hbWUgb2YgdGhlIHBhcmFtZXRlciB0byBnZXQgdGhlIHZhbHVlIG9mXG4gICAqIEBwYXJhbSB1cmwgaXMgYSBVUkwgdG8gZ2V0IHRoZSBwYXJhbWV0ZXIgZnJvbSwgdXNlcyB0aGUgd2luZG93J3MgY3VycmVudCBocmVmIGlmIG5vdCBnaXZlblxuICAgKiBAcmV0dXJuIHRoZSBwYXJhbWV0ZXIncyB2YWx1ZVxuICAgKi9cbiAgc3RhdGljIGdldFBhcmFtZXRlckJ5TmFtZShuYW1lLCB1cmwpIHtcbiAgICBpZiAoIXVybCkgdXJsID0gd2luZG93LmxvY2F0aW9uLmhyZWY7XG4gICAgbmFtZSA9IG5hbWUucmVwbGFjZSgvW1xcW1xcXV0vZywgXCJcXFxcJCZcIik7XG4gICAgbGV0IHJlZ2V4ID0gbmV3IFJlZ0V4cChcIls/Jl1cIiArIG5hbWUgKyBcIig9KFteJiNdKil8JnwjfCQpXCIpLCByZXN1bHRzID0gcmVnZXguZXhlYyh1cmwpO1xuICAgIGlmICghcmVzdWx0cykgcmV0dXJuIG51bGw7XG4gICAgaWYgKCFyZXN1bHRzWzJdKSByZXR1cm4gJyc7XG4gICAgcmV0dXJuIGRlY29kZVVSSUNvbXBvbmVudChyZXN1bHRzWzJdLnJlcGxhY2UoL1xcKy9nLCBcIiBcIikpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0cyBhIG5vbi1jcnlwdG9ncmFwaGljYWxseSBzZWN1cmUgcmFuZG9tIG51bWJlciB3aXRoaW4gYSBnaXZlbiByYW5nZS5cbiAgICogXG4gICAqIEBwYXJhbSBtaW4gaXMgdGhlIG1pbmltdW0gcmFuZ2Ugb2YgdGhlIGludCB0byBnZW5lcmF0ZSwgaW5jbHVzaXZlXG4gICAqIEBwYXJhbSBtYXggaXMgdGhlIG1heGltdW0gcmFuZ2Ugb2YgdGhlIGludCB0byBnZW5lcmF0ZSwgaW5jbHVzaXZlXG4gICAqIFxuICAgKiBTb3VyY2U6IGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL01hdGgvcmFuZG9tXG4gICAqL1xuICBzdGF0aWMgZ2V0UmFuZG9tSW50KG1pbiwgbWF4KSB7XG4gICAgbWluID0gTWF0aC5jZWlsKG1pbik7XG4gICAgbWF4ID0gTWF0aC5mbG9vcihtYXgpO1xuICAgIHJldHVybiBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAobWF4IC0gbWluICsgMSkpICsgbWluO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0cyByYW5kb20gaW50cy5cbiAgICogXG4gICAqIEBwYXJhbSBtaW4gaXMgdGhlIG1pbmltdW0gcmFuZ2Ugb2YgdGhlIGludHMgdG8gZ2VuZXJhdGUsIGluY2x1c2l2ZVxuICAgKiBAcGFyYW0gbWF4IGlzIHRoZSBtYXhpbXVtIHJhbmdlIG9mIHRoZSBpbnRzIHRvIGdlbmVyYXRlLCBpbmNsdXNpdmVcbiAgICogQHBhcmFtIGNvdW50IGlzIHRoZSBudW1iZXIgb2YgcmFuZG9tIGludHMgdG8gZ2V0XG4gICAqL1xuICBzdGF0aWMgZ2V0UmFuZG9tSW50cyhtaW4sIG1heCwgY291bnQpIHtcbiAgICBHZW5VdGlscy5hc3NlcnRUcnVlKHR5cGVvZiBjb3VudCA9PT0gXCJudW1iZXJcIik7XG4gICAgbGV0IGludHMgPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNvdW50OyBpKyspIGludHMucHVzaChHZW5VdGlscy5nZXRSYW5kb21JbnQobWluLCBtYXgpKTtcbiAgICByZXR1cm4gaW50cztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldHMgYSBnaXZlbiBudW1iZXIgb2YgdW5pcXVlIHJhbmRvbSBpbnRzIHdpdGhpbiBhIHJhbmdlLlxuICAgKiBcbiAgICogQHBhcmFtIG1pbiBpcyB0aGUgbWluaW11bSByYW5nZSBvZiB0aGUgaW50cyB0byBnZW5lcmF0ZSwgaW5jbHVzaXZlXG4gICAqIEBwYXJhbSBtYXggaXMgdGhlIG1heGltdW0gcmFuZ2Ugb2YgdGhlIGludHMgdG8gZ2VuZXJhdGUsIGluY2x1c2l2ZVxuICAgKiBAcGFyYW0gY291bnQgaXMgdGhlIG51bWJlciBvZiB1bmlxdWUgcmFuZG9tIGludHMgdG8gZ2V0XG4gICAqL1xuICBzdGF0aWMgZ2V0VW5pcXVlUmFuZG9tSW50cyhtaW4sIG1heCwgY291bnQpIHtcbiAgICBsZXQgaW50cyA9IFtdO1xuICAgIEdlblV0aWxzLmFzc2VydFRydWUoY291bnQgPj0gMCk7XG4gICAgR2VuVXRpbHMuYXNzZXJ0VHJ1ZShtYXggLSBtaW4gKyAxID49IGNvdW50KTtcbiAgICB3aGlsZSAoaW50cy5sZW5ndGggPCBjb3VudCkge1xuICAgICAgbGV0IHJhbmRvbUludCA9IEdlblV0aWxzLmdldFJhbmRvbUludChtaW4sIG1heCk7XG4gICAgICBpZiAoIWludHMuaW5jbHVkZXMocmFuZG9tSW50KSkgaW50cy5wdXNoKHJhbmRvbUludCk7XG4gICAgfVxuICAgIHJldHVybiBpbnRzO1xuICB9XG4gIFxuICAvKipcbiAgICogUmFuZG9taXplIGFycmF5IGVsZW1lbnQgb3JkZXIgaW4tcGxhY2UgdXNpbmcgRHVyc3RlbmZlbGQgc2h1ZmZsZSBhbGdvcml0aG0uXG4gICAqIFxuICAgKiBDcmVkaXQ6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzI0NTA5NTQvaG93LXRvLXJhbmRvbWl6ZS1zaHVmZmxlLWEtamF2YXNjcmlwdC1hcnJheVxuICAgKi9cbiAgc3RhdGljIHNodWZmbGUoYXJyYXkpIHtcbiAgICBmb3IgKHZhciBpID0gYXJyYXkubGVuZ3RoIC0gMTsgaSA+IDA7IGktLSkge1xuICAgICAgdmFyIGogPSBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAoaSArIDEpKTtcbiAgICAgIHZhciB0ZW1wID0gYXJyYXlbaV07XG4gICAgICBhcnJheVtpXSA9IGFycmF5W2pdO1xuICAgICAgYXJyYXlbal0gPSB0ZW1wO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFNvcnRzIGFuIGFycmF5IGJ5IG5hdHVyYWwgb3JkZXJpbmcuXG4gICAqIFxuICAgKiBAcGFyYW0gdGhlIGFycmF5IHRvIHNvcnRcbiAgICovXG4gIHN0YXRpYyBzb3J0KGFycmF5KSB7XG4gICAgYXJyYXkuc29ydCgoYSwgYikgPT4gYSA9PT0gYiA/IDAgOiBhID4gYiA/IDEgOiAtMSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBnaXZlbiB2YWx1ZSBlbnN1cmluZyBhIHByZXZpb3VzIHZhbHVlIGlzIG5vdCBvdmVyd3JpdHRlbi5cbiAgICogXG4gICAqIFRPRE86IHJlbW92ZSBmb3IgcG9ydGFiaWxpdHkgYmVjYXVzZSBmdW5jdGlvbiBwYXNzaW5nIG5vdCBzdXBwb3J0ZWQgaW4gb3RoZXIgbGFuZ3VhZ2VzLCB1c2UgcmVjb25jaWxlIG9ubHlcbiAgICogXG4gICAqIEBwYXJhbSBvYmogaXMgdGhlIG9iamVjdCB0byBpbnZva2UgdGhlIGdldHRlciBhbmQgc2V0dGVyIG9uXG4gICAqIEBwYXJhbSBnZXRGbiBnZXRzIHRoZSBjdXJyZW50IHZhbHVlXG4gICAqIEBwYXJhbSBzZXRGbiBzZXRzIHRoZSBjdXJyZW50IHZhbHVlXG4gICAqIEBwYXJhbSB2YWwgaXMgdGhlIHZhbHVlIHRvIHNldCBpZmYgaXQgZG9lcyBub3Qgb3ZlcndyaXRlIGEgcHJldmlvdXMgdmFsdWVcbiAgICogQHBhcmFtIFtjb25maWddIHNwZWNpZmllcyByZWNvbmNpbGlhdGlvbiBjb25maWd1cmF0aW9uXG4gICAqICAgICAgICBjb25maWcucmVzb2x2ZURlZmluZWQgdXNlcyBkZWZpbmVkIHZhbHVlIGlmIHRydWUgb3IgdW5kZWZpbmVkLCB1bmRlZmluZWQgaWYgZmFsc2VcbiAgICogICAgICAgIGNvbmZpZy5yZXNvbHZlVHJ1ZSB1c2VzIHRydWUgb3ZlciBmYWxzZSBpZiB0cnVlLCBmYWxzZSBvdmVyIHRydWUgaWYgZmFsc2UsIG11c3QgYmUgZXF1YWwgaWYgdW5kZWZpbmVkXG4gICAqICAgICAgICBjb25maWcucmVzb2x2ZU1heCB1c2VzIG1heCBvdmVyIG1pbiBpZiB0cnVlLCBtaW4gb3ZlciBtYXggaWYgZmFsc2UsIG11c3QgYmUgZXF1YWwgaWYgdW5kZWZpbmVkXG4gICAqIEBwYXJhbSBbZXJyTXNnXSBpcyB0aGUgZXJyb3IgbWVzc2FnZSB0byB0aHJvdyBpZiB0aGUgdmFsdWVzIGNhbm5vdCBiZSByZWNvbmNpbGVkIChvcHRpb25hbClcbiAgICovXG4gIHN0YXRpYyBzYWZlU2V0KG9iaiwgZ2V0Rm4sIHNldEZuLCB2YWwsIGNvbmZpZz8sIGVyck1zZz8pIHtcbiAgICBsZXQgY3VyVmFsID0gZ2V0Rm4uY2FsbChvYmopO1xuICAgIGxldCByZWNvbmNpbGVkVmFsID0gR2VuVXRpbHMucmVjb25jaWxlKGN1clZhbCwgdmFsLCBjb25maWcsIGVyck1zZyk7XG4gICAgaWYgKGN1clZhbCAhPT0gcmVjb25jaWxlZFZhbCkgc2V0Rm4uY2FsbChvYmosIHJlY29uY2lsZWRWYWwpO1xuICB9XG4gIFxuICAvKipcbiAgICogUmVjb25jaWxlcyB0d28gdmFsdWVzLlxuICAgKiBcbiAgICogVE9ETzogcmVtb3ZlIGN1c3RvbSBlcnJvciBtZXNzYWdlXG4gICAqIFxuICAgKiBAcGFyYW0gdmFsMSBpcyBhIHZhbHVlIHRvIHJlY29uY2lsZVxuICAgKiBAcGFyYW0gdmFsMiBpcyBhIHZhbHVlIHRvIHJlY29uY2lsZVxuICAgKiBAcGFyYW0gW2NvbmZpZ10gc3BlY2lmaWVzIHJlY29uY2lsaWF0aW9uIGNvbmZpZ3VyYXRpb25cbiAgICogICAgICAgIGNvbmZpZy5yZXNvbHZlRGVmaW5lZCB1c2VzIGRlZmluZWQgdmFsdWUgaWYgdHJ1ZSBvciB1bmRlZmluZWQsIHVuZGVmaW5lZCBpZiBmYWxzZVxuICAgKiAgICAgICAgY29uZmlnLnJlc29sdmVUcnVlIHVzZXMgdHJ1ZSBvdmVyIGZhbHNlIGlmIHRydWUsIGZhbHNlIG92ZXIgdHJ1ZSBpZiBmYWxzZSwgbXVzdCBiZSBlcXVhbCBpZiB1bmRlZmluZWRcbiAgICogICAgICAgIGNvbmZpZy5yZXNvbHZlTWF4IHVzZXMgbWF4IG92ZXIgbWluIGlmIHRydWUsIG1pbiBvdmVyIG1heCBpZiBmYWxzZSwgbXVzdCBiZSBlcXVhbCBpZiB1bmRlZmluZWRcbiAgICogQHBhcmFtIFtlcnJNc2ddIGlzIHRoZSBlcnJvciBtZXNzYWdlIHRvIHRocm93IGlmIHRoZSB2YWx1ZXMgY2Fubm90IGJlIHJlY29uY2lsZWQgKG9wdGlvbmFsKVxuICAgKiBAcmV0dXJuIHRoZSByZWNvbmNpbGVkIHZhbHVlIGlmIHJlY29uY2lsYWJsZSwgdGhyb3dzIGVycm9yIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIHJlY29uY2lsZSh2YWwxLCB2YWwyLCBjb25maWc/LCBlcnJNc2c/KSB7XG4gICAgXG4gICAgLy8gY2hlY2sgZm9yIGVxdWFsaXR5XG4gICAgaWYgKHZhbDEgPT09IHZhbDIpIHJldHVybiB2YWwxO1xuICAgIFxuICAgIC8vIGNoZWNrIGZvciBiaWdpbnQgZXF1YWxpdHlcbiAgICBsZXQgY29tcGFyaXNvbjsgLy8gc2F2ZSBjb21wYXJpc29uIGZvciBsYXRlciBpZiBhcHBsaWNhYmxlXG4gICAgaWYgKHR5cGVvZiB2YWwxID09PSBcImJpZ2ludFwiICYmIHR5cGVvZiB2YWwyID09PSBcImJpZ2ludFwiKSB7XG4gICAgICBpZiAodmFsMSA9PT0gdmFsMikgcmV0dXJuIHZhbDE7XG4gICAgfVxuICAgIFxuICAgIC8vIHJlc29sdmUgb25lIHZhbHVlIGRlZmluZWRcbiAgICBpZiAodmFsMSA9PT0gdW5kZWZpbmVkIHx8IHZhbDIgPT09IHVuZGVmaW5lZCkge1xuICAgICAgaWYgKGNvbmZpZyAmJiBjb25maWcucmVzb2x2ZURlZmluZWQgPT09IGZhbHNlKSByZXR1cm4gdW5kZWZpbmVkOyAgLy8gdXNlIHVuZGVmaW5lZFxuICAgICAgZWxzZSByZXR1cm4gdmFsMSA9PT0gdW5kZWZpbmVkID8gdmFsMiA6IHZhbDE7ICAvLyB1c2UgZGVmaW5lZCB2YWx1ZVxuICAgIH1cbiAgICBcbiAgICAvLyByZXNvbHZlIGRpZmZlcmVudCBib29sZWFuc1xuICAgIGlmIChjb25maWcgJiYgY29uZmlnLnJlc29sdmVUcnVlICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHZhbDEgPT09IFwiYm9vbGVhblwiICYmIHR5cGVvZiB2YWwyID09PSBcImJvb2xlYW5cIikge1xuICAgICAgYXNzZXJ0LmVxdWFsKHR5cGVvZiBjb25maWcucmVzb2x2ZVRydWUsIFwiYm9vbGVhblwiKTtcbiAgICAgIHJldHVybiBjb25maWcucmVzb2x2ZVRydWU7XG4gICAgfVxuICAgIFxuICAgIC8vIHJlc29sdmUgZGlmZmVyZW50IG51bWJlcnNcbiAgICBpZiAoY29uZmlnICYmIGNvbmZpZy5yZXNvbHZlTWF4ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGFzc2VydC5lcXVhbCh0eXBlb2YgY29uZmlnLnJlc29sdmVNYXgsIFwiYm9vbGVhblwiKTtcbiAgICAgIFxuICAgICAgLy8gcmVzb2x2ZSBqcyBudW1iZXJzXG4gICAgICBpZiAodHlwZW9mIHZhbDEgPT09IFwibnVtYmVyXCIgJiYgdHlwZW9mIHZhbDIgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgcmV0dXJuIGNvbmZpZy5yZXNvbHZlTWF4ID8gTWF0aC5tYXgodmFsMSwgdmFsMikgOiBNYXRoLm1pbih2YWwxLCB2YWwyKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gcmVzb2x2ZSBiaWdpbnRzXG4gICAgICBpZiAodHlwZW9mIHZhbDEgPT09IFwiYmlnaW50XCIgJiYgdHlwZW9mIHZhbDIgPT09IFwiYmlnaW50XCIpIHtcbiAgICAgICAgcmV0dXJuIGNvbmZpZy5yZXNvbHZlTWF4ID8gKGNvbXBhcmlzb24gPCAwID8gdmFsMiA6IHZhbDEpIDogKGNvbXBhcmlzb24gPCAwID8gdmFsMSA6IHZhbDIpO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBhc3NlcnQgZGVlcCBlcXVhbGl0eVxuICAgIGFzc2VydC5kZWVwRXF1YWwodmFsMSwgdmFsMiwgZXJyTXNnID8gZXJyTXNnIDogXCJDYW5ub3QgcmVjb25jaWxlIHZhbHVlcyBcIiArIHZhbDEgKyBcIiBhbmQgXCIgKyB2YWwyICsgXCIgd2l0aCBjb25maWc6IFwiICsgSlNPTi5zdHJpbmdpZnkoY29uZmlnKSk7XG4gICAgcmV0dXJuIHZhbDE7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgaHVtYW4tZnJpZW5kbHkga2V5IHZhbHVlIGxpbmUuXG4gICAqIFxuICAgKiBAcGFyYW0ga2V5IGlzIHRoZSBrZXlcbiAgICogQHBhcmFtIHZhbHVlIGlzIHRoZSB2YWx1ZVxuICAgKiBAcGFyYW0gaW5kZW50IGluZGVudHMgdGhlIGxpbmVcbiAgICogQHBhcmFtIG5ld2xpbmUgc3BlY2lmaWVzIGlmIHRoZSBzdHJpbmcgc2hvdWxkIGJlIHRlcm1pbmF0ZWQgd2l0aCBhIG5ld2xpbmUgb3Igbm90XG4gICAqIEBwYXJhbSBpZ25vcmVVbmRlZmluZWQgc3BlY2lmaWVzIGlmIHVuZGVmaW5lZCB2YWx1ZXMgc2hvdWxkIHJldHVybiBhbiBlbXB0eSBzdHJpbmdcbiAgICogQHJldHVybiB7c3RyaW5nfSBpcyB0aGUgaHVtYW4tZnJpZW5kbHkga2V5IHZhbHVlIGxpbmVcbiAgICovXG4gIHN0YXRpYyBrdkxpbmUoa2V5LCB2YWx1ZSwgaW5kZW50ID0gMCwgbmV3bGluZSA9IHRydWUsIGlnbm9yZVVuZGVmaW5lZCA9IHRydWUpIHtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCAmJiBpZ25vcmVVbmRlZmluZWQpIHJldHVybiBcIlwiO1xuICAgIHJldHVybiBHZW5VdGlscy5nZXRJbmRlbnQoaW5kZW50KSArIGtleSArIFwiOiBcIiArIHZhbHVlICsgKG5ld2xpbmUgPyAnXFxuJyA6IFwiXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogUmVwbGFjZSBiaWcgaW50ZWdlcnMgKDE2IG9yIG1vcmUgY29uc2VjdXRpdmUgZGlnaXRzKSB3aXRoIHN0cmluZ3MgaW4gb3JkZXJcbiAgICogdG8gcHJlc2VydmUgbnVtZXJpYyBwcmVjaXNpb24uXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyIGlzIHRoZSBzdHJpbmcgdG8gYmUgbW9kaWZpZWRcbiAgICogQHJldHVybiB7c3RyaW5nfSB0aGUgbW9kaWZpZWQgc3RyaW5nIHdpdGggYmlnIG51bWJlcnMgY29udmVydGVkIHRvIHN0cmluZ3NcbiAgICovXG4gIHN0YXRpYyBzdHJpbmdpZnlCaWdJbnRzKHN0cikge1xuICAgIHJldHVybiBzdHIucmVwbGFjZSgvKFwiW15cIl0qXCJcXHMqOlxccyopKFxcZHsxNix9KS9nLCAnJDFcIiQyXCInKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFByaW50IHRoZSBjdXJyZW50IHN0YWNrIHRyYWNlLiBcbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtc2cgLSBvcHRpb25hbCBtZXNzYWdlIHRvIHByaW50IHdpdGggdGhlIHRyYWNlXG4gICAqL1xuICBzdGF0aWMgcHJpbnRTdGFja1RyYWNlKG1zZykge1xuICAgIHRyeSB7IHRocm93IG5ldyBFcnJvcihtc2cpOyB9XG4gICAgY2F0Y2ggKGVycjogYW55KSB7IGNvbnNvbGUuZXJyb3IoZXJyLnN0YWNrKTsgfVxuICB9XG4gIFxuICAvKipcbiAgICogV2FpdCBmb3IgdGhlIGR1cmF0aW9uLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IGR1cmF0aW9uTXMgLSB0aGUgZHVyYXRpb24gdG8gd2FpdCBmb3IgaW4gbWlsbGlzZWNvbmRzXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgd2FpdEZvcihkdXJhdGlvbk1zKSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUpIHsgc2V0VGltZW91dChyZXNvbHZlLCBkdXJhdGlvbk1zKTsgfSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBLaWxsIHRoZSBnaXZlbiBub2RlanMgY2hpbGQgcHJvY2Vzcy5cbiAgICogXG4gICAqIEBwYXJhbSB7Q2hpbGRQcm9jZXNzfSBwcm9jZXNzIC0gdGhlIG5vZGVqcyBjaGlsZCBwcm9jZXNzIHRvIGtpbGxcbiAgICogQHBhcmFtIHtudW1iZXIgfCBOb2RlSlMuU2lnbmFsc30gW3NpZ25hbF0gLSB0aGUga2lsbCBzaWduYWwsIGUuZy4gU0lHVEVSTSwgU0lHS0lMTCwgU0lHSU5UIChkZWZhdWx0KVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPG51bWJlciB8IHVuZGVmaW5lZD59IHRoZSBleGl0IGNvZGUgZnJvbSBraWxsaW5nIHRoZSBwcm9jZXNzXG4gICAqL1xuICBzdGF0aWMgYXN5bmMga2lsbFByb2Nlc3MocHJvY2VzczogQ2hpbGRQcm9jZXNzLCBzaWduYWw/OiBudW1iZXIgfCBOb2RlSlMuU2lnbmFscyk6IFByb21pc2U8bnVtYmVyIHwgdW5kZWZpbmVkPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHByb2Nlc3Mub24oXCJleGl0XCIsIGZ1bmN0aW9uKGNvZGUsIHNpZ25hbCkgeyByZXNvbHZlKGNvZGUpOyB9KTtcbiAgICAgIHByb2Nlc3Mub24oXCJlcnJvclwiLCBmdW5jdGlvbihlcnIpIHsgcmVqZWN0KGVycik7IH0pO1xuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKCFwcm9jZXNzLmtpbGwoc2lnbmFsID09PSB1bmRlZmluZWQgPyBcIlNJR0lOVFwiIDogc2lnbmFsKSkgcmVzb2x2ZSh1bmRlZmluZWQpOyAvLyByZXNvbHZlIGltbWVkaWF0ZWx5IGlmIG5vdCBydW5uaW5nXG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogTm9ybWFsaXplIGEgVVJJLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVyaSAtIHRoZSBVUkkgdG8gbm9ybWFsaXplXG4gICAqIEByZXR1cm4ge3N0cmluZ30gdGhlIG5vcm1hbGl6ZWQgVVJJXG4gICAqL1xuICBzdGF0aWMgbm9ybWFsaXplVXJpKHVyaSkge1xuICAgIGlmICghdXJpKSB0aHJvdyBFcnJvcihcIk11c3QgcHJvdmlkZSBVUkkgdG8gbm9ybWFsaXplXCIpO1xuICAgIHVyaSA9IHVyaS5yZXBsYWNlKC9cXC8kLywgXCJcIik7IC8vIHN0cmlwIHRyYWlsaW5nIHNsYXNoXG4gICAgaWYgKCFuZXcgUmVnRXhwKFwiXlxcXFx3KzovLy4rXCIpLnRlc3QodXJpKSkgdXJpPSBcImh0dHA6Ly9cIiArIHVyaTsgLy8gYXNzdW1lIGh0dHAgaWYgcHJvdG9jb2wgbm90IGdpdmVuXG4gICAgcmV0dXJuIHVyaTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgYWJzb2x1dGUgdmFsdWUgb2YgdGhlIGdpdmVuIGJpZ2ludCBvciBudW1iZXIuXG4gICAqIFxuICAgKiBAcGFyYW0ge2JpZ2ludCB8IG51bWJlcn0gYmkgLSB0aGUgYmlnaW50IG9yIG51bWJlciB0byBnZXQgdGhlIGFic29sdXRlIHZhbHVlIG9mXG4gICAqIEByZXR1cm4ge2JpZ2ludCB8IG51bWJlcn0gdGhlIGFic29sdXRlIHZhbHVlIG9mIHRoZSBnaXZlbiBiaWdpbnQgb3IgbnVtYmVyXG4gICAqL1xuICBzdGF0aWMgYWJzKGJpOiBiaWdpbnQgfCBudW1iZXIpOiBiaWdpbnQgfCBudW1iZXIge1xuICAgIHJldHVybiBiaSA8IDAgPyAtYmkgOiBiaTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYW4gZW51bSBrZXkgbmFtZSBieSB2YWx1ZS5cbiAgICogXG4gICAqIEBwYXJhbSB7YW55fSBlbnVtVHlwZSBpcyB0aGUgZW51bSB0eXBlIHRvIGdldCB0aGUga2V5IGZyb21cbiAgICogQHBhcmFtIHthbnl9IGVudW1WYWx1ZSBpcyB0aGUgZW51bSB2YWx1ZSB0byBnZXQgdGhlIGtleSBmb3JcbiAgICogQHJldHVybiB7c3RyaW5nIHwgdW5kZWZpbmVkfSB0aGUgZW51bSBrZXkgbmFtZVxuICAgKi9cbiAgc3RhdGljIGdldEVudW1LZXlCeVZhbHVlKGVudW1UeXBlOiBhbnksIGVudW1WYWx1ZTogYW55KTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICBmb3IgKGxldCBrZXkgaW4gZW51bVR5cGUpIHtcbiAgICAgIGlmIChlbnVtVHlwZVtrZXldID09PSBlbnVtVmFsdWUpIHJldHVybiBrZXk7XG4gICAgfVxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZSB0aGUgZ2l2ZW4gcHJvbWlzZSB3aXRoIGEgdGltZW91dC5cbiAgICogXG4gICAqIEBwYXJhbSBwcm9taXNlIHRoZSBwcm9taXNlIHRvIHJlc29sdmUgd2l0aGluIHRoZSB0aW1lb3V0XG4gICAqIEBwYXJhbSB0aW1lb3V0TXMgdGhlIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIHRvIHJlc29sdmUgdGhlIHByb21pc2VcbiAgICogQHJldHVybiB0aGUgcmVzdWx0IG9mIHRoZSBwcm9taXNlIHVubGVzcyBlcnJvciB0aHJvd25cbiAgICovXG4gIHN0YXRpYyBhc3luYyBleGVjdXRlV2l0aFRpbWVvdXQocHJvbWlzZSwgdGltZW91dE1zKTogUHJvbWlzZTxhbnk+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgdGltZW91dElkID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHJlamVjdCgnRXhlY3V0aW9uIHRpbWVkIG91dCBpbiAnICsgdGltZW91dE1zICsgJyBtaWxsaXNlY29uZHMnKVxuICAgICAgfSwgdGltZW91dE1zKTtcbiAgICAgIHByb21pc2UudGhlbihcbiAgICAgICAgKHJlc3VsdCkgPT4ge1xuICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0SWQpO1xuICAgICAgICAgIHJlc29sdmUocmVzdWx0KTtcbiAgICAgICAgfSxcbiAgICAgICAgKGVycm9yKSA9PiB7XG4gICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXRJZCk7XG4gICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgKTtcbiAgICB9KTtcbiAgfVxufVxuXG4iXSwibWFwcGluZ3MiOiJ5TEFBQSxJQUFBQSxPQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxNQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7Ozs7O0FBS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNlLE1BQU1FLFFBQVEsQ0FBQzs7RUFFNUI7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsT0FBT0MsU0FBU0EsQ0FBQ0MsR0FBUSxFQUFXO0lBQ2xDLE9BQU8sT0FBT0EsR0FBRyxLQUFLLFdBQVc7RUFDbkM7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0Us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 \ No newline at end of file diff --git a/dist/src/main/ts/common/HttpClient.d.ts b/dist/src/main/ts/common/HttpClient.d.ts new file mode 100644 index 000000000..5f55fbdfe --- /dev/null +++ b/dist/src/main/ts/common/HttpClient.d.ts @@ -0,0 +1,52 @@ +/** + * Handle HTTP requests with a uniform interface. + */ +export default class HttpClient { + static MAX_REQUESTS_PER_SECOND: number; + protected static DEFAULT_REQUEST: { + method: string; + resolveWithFullResponse: boolean; + rejectUnauthorized: boolean; + }; + protected static PROMISE_THROTTLES: any[]; + protected static TASK_QUEUES: any[]; + protected static DEFAULT_TIMEOUT: number; + static MAX_TIMEOUT: number; + protected static HTTP_AGENT: any; + protected static HTTPS_AGENT: any; + /** + *

Make a HTTP request.

+ * + * @param {object} request - configures the request to make + * @param {string} request.method - HTTP method ("GET", "PUT", "POST", "DELETE", etc) + * @param {string} request.uri - uri to request + * @param {string|Uint8Array|object} request.body - request body + * @param {string} [request.username] - username to authenticate the request (optional) + * @param {string} [request.password] - password to authenticate the request (optional) + * @param {object} [request.headers] - headers to add to the request (optional) + * @param {boolean} [request.resolveWithFullResponse] - return full response if true, else body only (default false) + * @param {boolean} [request.rejectUnauthorized] - whether or not to reject self-signed certificates (default true) + * @param {number} request.timeout - maximum time allowed in milliseconds + * @param {number} request.proxyToWorker - proxy request to worker thread + * @return {object} response - the response object + * @return {string|Uint8Array|object} response.body - the response body + * @return {number} response.statusCode - the response code + * @return {String} response.statusText - the response message + * @return {object} response.headers - the response headers + */ + static request(request: any): Promise; + /** + * Get a singleton instance of an HTTP client to share. + * + * @return {http.Agent} a shared agent for network requests among library instances + */ + protected static getHttpAgent(): any; + /** + * Get a singleton instance of an HTTPS client to share. + * + * @return {https.Agent} a shared agent for network requests among library instances + */ + protected static getHttpsAgent(): any; + protected static requestAxios(req: any): Promise; + protected static axiosDigestAuthRequest: (method: any, url: any, username: any, password: any, body: any) => Promise>; +} diff --git a/dist/src/main/ts/common/HttpClient.js b/dist/src/main/ts/common/HttpClient.js new file mode 100644 index 000000000..5a64a6797 --- /dev/null +++ b/dist/src/main/ts/common/HttpClient.js @@ -0,0 +1,246 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _GenUtils = _interopRequireDefault(require("./GenUtils")); +var _LibraryUtils = _interopRequireDefault(require("./LibraryUtils")); +var _ThreadPool = _interopRequireDefault(require("./ThreadPool")); +var _promiseThrottle = _interopRequireDefault(require("promise-throttle")); +var _http = _interopRequireDefault(require("http")); +var _https = _interopRequireDefault(require("https")); +var _axios = _interopRequireDefault(require("axios")); + +/** + * Handle HTTP requests with a uniform interface. + */ +class HttpClient { + + static MAX_REQUESTS_PER_SECOND = 50; + + // default request config + static DEFAULT_REQUEST = { + method: "GET", + resolveWithFullResponse: false, + rejectUnauthorized: true + }; + + // rate limit requests per host + static PROMISE_THROTTLES = []; + static TASK_QUEUES = []; + static DEFAULT_TIMEOUT = 60000; + static MAX_TIMEOUT = 2147483647; // max 32-bit signed number + + + + + /** + *

Make a HTTP request.

+ * + * @param {object} request - configures the request to make + * @param {string} request.method - HTTP method ("GET", "PUT", "POST", "DELETE", etc) + * @param {string} request.uri - uri to request + * @param {string|Uint8Array|object} request.body - request body + * @param {string} [request.username] - username to authenticate the request (optional) + * @param {string} [request.password] - password to authenticate the request (optional) + * @param {object} [request.headers] - headers to add to the request (optional) + * @param {boolean} [request.resolveWithFullResponse] - return full response if true, else body only (default false) + * @param {boolean} [request.rejectUnauthorized] - whether or not to reject self-signed certificates (default true) + * @param {number} request.timeout - maximum time allowed in milliseconds + * @param {number} request.proxyToWorker - proxy request to worker thread + * @return {object} response - the response object + * @return {string|Uint8Array|object} response.body - the response body + * @return {number} response.statusCode - the response code + * @return {String} response.statusText - the response message + * @return {object} response.headers - the response headers + */ + static async request(request) { + // proxy to worker if configured + if (request.proxyToWorker) { + try { + return await _LibraryUtils.default.invokeWorker(undefined, "httpRequest", request); + } catch (err) { + if (err.message.length > 0 && err.message.charAt(0) === "{") { + let parsed = JSON.parse(err.message); + err.message = parsed.statusMessage; + err.statusCode = parsed.statusCode; + } + throw err; + } + } + + // assign defaults + request = Object.assign({}, HttpClient.DEFAULT_REQUEST, request); + + // validate request + try {request.host = new URL(request.uri).host;} // hostname:port + catch (err) {throw new Error("Invalid request URL: " + request.uri);} + if (request.body && !(typeof request.body === "string" || typeof request.body === "object")) { + throw new Error("Request body type is not string or object"); + } + + // initialize one task queue per host + if (!HttpClient.TASK_QUEUES[request.host]) HttpClient.TASK_QUEUES[request.host] = new _ThreadPool.default(1); + + // initialize one promise throttle per host + if (!HttpClient.PROMISE_THROTTLES[request.host]) { + HttpClient.PROMISE_THROTTLES[request.host] = new _promiseThrottle.default({ + requestsPerSecond: HttpClient.MAX_REQUESTS_PER_SECOND, // TODO: HttpClient should not depend on MoneroUtils for configuration + promiseImplementation: Promise + }); + } + + // request using fetch or xhr with timeout + let timeout = request.timeout === undefined ? HttpClient.DEFAULT_TIMEOUT : request.timeout === 0 ? HttpClient.MAX_TIMEOUT : request.timeout; + let requestPromise = HttpClient.requestAxios(request); + return _GenUtils.default.executeWithTimeout(requestPromise, timeout); + } + + // ----------------------------- PRIVATE HELPERS ---------------------------- + + + /** + * Get a singleton instance of an HTTP client to share. + * + * @return {http.Agent} a shared agent for network requests among library instances + */ + static getHttpAgent() { + if (!HttpClient.HTTP_AGENT) HttpClient.HTTP_AGENT = new _http.default.Agent({ + keepAlive: true, + family: 4 // use IPv4 + }); + return HttpClient.HTTP_AGENT; + } + + /** + * Get a singleton instance of an HTTPS client to share. + * + * @return {https.Agent} a shared agent for network requests among library instances + */ + static getHttpsAgent() { + if (!HttpClient.HTTPS_AGENT) HttpClient.HTTPS_AGENT = new _https.default.Agent({ + keepAlive: true, + family: 4 // use IPv4 + }); + return HttpClient.HTTPS_AGENT; + } + + static async requestAxios(req) { + if (req.headers) throw new Error("Custom headers not implemented in XHR request"); // TODO + + // collect params from request which change on await + const method = req.method; + const uri = req.uri; + const host = req.host; + const username = req.username; + const password = req.password; + const body = req.body; + const isBinary = body instanceof Uint8Array; + + // queue and throttle requests to execute in serial and rate limited per host + const resp = await HttpClient.TASK_QUEUES[host].submit(async function () { + return HttpClient.PROMISE_THROTTLES[host].add(function () { + return new Promise(function (resolve, reject) { + HttpClient.axiosDigestAuthRequest(method, uri, username, password, body).then(function (resp) { + resolve(resp); + }).catch(function (error) { + if (error.response?.status) resolve(error.response); + reject(new Error("Request failed without response: " + method + " " + uri + " due to underlying error:\n" + error.message + "\n" + error.stack)); + }); + }); + + }.bind(this)); + }); + + // normalize response + let normalizedResponse = {}; + normalizedResponse.statusCode = resp.status; + normalizedResponse.statusText = resp.statusText; + normalizedResponse.headers = { ...resp.headers }; + normalizedResponse.body = isBinary ? new Uint8Array(resp.data) : resp.data; + if (normalizedResponse.body instanceof ArrayBuffer) normalizedResponse.body = new Uint8Array(normalizedResponse.body); // handle empty binary request + return normalizedResponse; + } + + static axiosDigestAuthRequest = async function (method, url, username, password, body) { + if (typeof CryptoJS === 'undefined' && typeof require === 'function') { + var CryptoJS = require('crypto-js'); + } + + const generateCnonce = function () { + const characters = 'abcdef0123456789'; + let token = ''; + for (let i = 0; i < 16; i++) { + const randNum = Math.round(Math.random() * characters.length); + token += characters.slice(randNum, randNum + 1); + } + return token; + }; + + let count = 0; + return _axios.default.request({ + url: url, + method: method, + timeout: this.timeout, + headers: { + 'Content-Type': 'application/json' + }, + responseType: body instanceof Uint8Array ? 'arraybuffer' : undefined, + httpAgent: url.startsWith("https") ? undefined : HttpClient.getHttpAgent(), + httpsAgent: url.startsWith("https") ? HttpClient.getHttpsAgent() : undefined, + data: body, + transformResponse: (res) => res, + adapter: _GenUtils.default.isDeno() ? ['fetch'] : ['http', 'xhr', 'fetch'] + }).catch(async (err) => { + if (err.response?.status === 401) { + let authHeader = err.response.headers['www-authenticate'].replace(/,\sDigest.*/, ""); + if (!authHeader) { + throw err; + } + + // Digest qop="auth",algorithm=MD5,realm="monero-rpc",nonce="hBZ2rZIxElv4lqCRrUylXA==",stale=false + const authHeaderMap = authHeader.replace("Digest ", "").replaceAll('"', "").split(",").reduce((prev, curr) => ({ ...prev, [curr.split("=")[0]]: curr.split("=").slice(1).join('=') }), {}); + + ++count; + + const cnonce = generateCnonce(); + const HA1 = CryptoJS.MD5(username + ':' + authHeaderMap.realm + ':' + password).toString(); + const HA2 = CryptoJS.MD5(method + ':' + url).toString(); + + const response = CryptoJS.MD5(HA1 + ':' + + authHeaderMap.nonce + ':' + + ('00000000' + count).slice(-8) + ':' + + cnonce + ':' + + authHeaderMap.qop + ':' + + HA2).toString(); + const digestAuthHeader = 'Digest' + ' ' + + 'username="' + username + '", ' + + 'realm="' + authHeaderMap.realm + '", ' + + 'nonce="' + authHeaderMap.nonce + '", ' + + 'uri="' + url + '", ' + + 'response="' + response + '", ' + + 'opaque="' + (authHeaderMap.opaque ?? null) + '", ' + + 'qop=' + authHeaderMap.qop + ', ' + + 'nc=' + ('00000000' + count).slice(-8) + ', ' + + 'cnonce="' + cnonce + '"'; + + const finalResponse = await _axios.default.request({ + url: url, + method: method, + timeout: this.timeout, + headers: { + 'Authorization': digestAuthHeader, + 'Content-Type': 'application/json' + }, + responseType: body instanceof Uint8Array ? 'arraybuffer' : undefined, + httpAgent: url.startsWith("https") ? undefined : HttpClient.getHttpAgent(), + httpsAgent: url.startsWith("https") ? HttpClient.getHttpsAgent() : undefined, + data: body, + transformResponse: (res) => res, + adapter: _GenUtils.default.isDeno() ? ['fetch'] : ['http', 'xhr', 'fetch'] + }); + + return finalResponse; + } + throw err; + }).catch((err) => { + throw err; + }); + }; +}exports.default = HttpClient; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfR2VuVXRpbHMiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9MaWJyYXJ5VXRpbHMiLCJfVGhyZWFkUG9vbCIsIl9wcm9taXNlVGhyb3R0bGUiLCJfaHR0cCIsIl9odHRwcyIsIl9heGlvcyIsIkh0dHBDbGllbnQiLCJNQVhfUkVRVUVTVFNfUEVSX1NFQ09ORCIsIkRFRkFVTFRfUkVRVUVTVCIsIm1ldGhvZCIsInJlc29sdmVXaXRoRnVsbFJlc3BvbnNlIiwicmVqZWN0VW5hdXRob3JpemVkIiwiUFJPTUlTRV9USFJPVFRMRVMiLCJUQVNLX1FVRVVFUyIsIkRFRkFVTFRfVElNRU9VVCIsIk1BWF9USU1FT1VUIiwicmVxdWVzdCIsInByb3h5VG9Xb3JrZXIiLCJMaWJyYXJ5VXRpbHMiLCJpbnZva2VXb3JrZXIiLCJ1bmRlZmluZWQiLCJlcnIiLCJtZXNzYWdlIiwibGVuZ3RoIiwiY2hhckF0IiwicGFyc2VkIiwiSlNPTiIsInBhcnNlIiwic3RhdHVzTWVzc2FnZSIsInN0YXR1c0NvZGUiLCJPYmplY3QiLCJhc3NpZ24iLCJob3N0IiwiVVJMIiwidXJpIiwiRXJyb3IiLCJib2R5IiwiVGhyZWFkUG9vbCIsIlByb21pc2VUaHJvdHRsZSIsInJlcXVlc3RzUGVyU2Vjb25kIiwicHJvbWlzZUltcGxlbWVudGF0aW9uIiwiUHJvbWlzZSIsInRpbWVvdXQiLCJyZXF1ZXN0UHJvbWlzZSIsInJlcXVlc3RBeGlvcyIsIkdlblV0aWxzIiwiZXhlY3V0ZVdpdGhUaW1lb3V0IiwiZ2V0SHR0cEFnZW50IiwiSFRUUF9BR0VOVCIsImh0dHAiLCJBZ2VudCIsImtlZXBBbGl2ZSIsImZhbWlseSIsImdldEh0dHBzQWdlbnQiLCJIVFRQU19BR0VOVCIsImh0dHBzIiwicmVxIiwiaGVhZGVycyIsInVzZXJuYW1lIiwicGFzc3dvcmQiLCJpc0JpbmFyeSIsIlVpbnQ4QXJyYXkiLCJyZXNwIiwic3VibWl0IiwiYWRkIiwicmVzb2x2ZSIsInJlamVjdCIsImF4aW9zRGlnZXN0QXV0aFJlcXVlc3QiLCJ0aGVuIiwiY2F0Y2giLCJlcnJvciIsInJlc3BvbnNlIiwic3RhdHVzIiwic3RhY2siLCJiaW5kIiwibm9ybWFsaXplZFJlc3BvbnNlIiwic3RhdHVzVGV4dCIsImRhdGEiLCJBcnJheUJ1ZmZlciIsInVybCIsIkNyeXB0b0pTIiwiZ2VuZXJhdGVDbm9uY2UiLCJjaGFyYWN0ZXJzIiwidG9rZW4iLCJpIiwicmFuZE51bSIsIk1hdGgiLCJyb3VuZCIsInJhbmRvbSIsInNsaWNlIiwiY291bnQiLCJheGlvcyIsInJlc3BvbnNlVHlwZSIsImh0dHBBZ2VudCIsInN0YXJ0c1dpdGgiLCJodHRwc0FnZW50IiwidHJhbnNmb3JtUmVzcG9uc2UiLCJyZXMiLCJhZGFwdGVyIiwiaXNEZW5vIiwiYXV0aEhlYWRlciIsInJlcGxhY2UiLCJhdXRoSGVhZGVyTWFwIiwicmVwbGFjZUFsbCIsInNwbGl0IiwicmVkdWNlIiwicHJldiIsImN1cnIiLCJqb2luIiwiY25vbmNlIiwiSEExIiwiTUQ1IiwicmVhbG0iLCJ0b1N0cmluZyIsIkhBMiIsIm5vbmNlIiwicW9wIiwiZGlnZXN0QXV0aEhlYWRlciIsIm9wYXF1ZSIsImZpbmFsUmVzcG9uc2UiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2NvbW1vbi9IdHRwQ2xpZW50LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi9HZW5VdGlsc1wiO1xuaW1wb3J0IExpYnJhcnlVdGlscyBmcm9tIFwiLi9MaWJyYXJ5VXRpbHNcIjtcbmltcG9ydCBUaHJlYWRQb29sIGZyb20gXCIuL1RocmVhZFBvb2xcIjtcbmltcG9ydCBQcm9taXNlVGhyb3R0bGUgZnJvbSBcInByb21pc2UtdGhyb3R0bGVcIjtcbmltcG9ydCBodHRwIGZyb20gXCJodHRwXCI7XG5pbXBvcnQgaHR0cHMgZnJvbSBcImh0dHBzXCI7XG5pbXBvcnQgYXhpb3MsIHsgQXhpb3NFcnJvciB9IGZyb20gXCJheGlvc1wiO1xuXG4vKipcbiAqIEhhbmRsZSBIVFRQIHJlcXVlc3RzIHdpdGggYSB1bmlmb3JtIGludGVyZmFjZS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgSHR0cENsaWVudCB7XG5cbiAgc3RhdGljIE1BWF9SRVFVRVNUU19QRVJfU0VDT05EID0gNTA7XG5cbiAgLy8gZGVmYXVsdCByZXF1ZXN0IGNvbmZpZ1xuICBwcm90ZWN0ZWQgc3RhdGljIERFRkFVTFRfUkVRVUVTVCA9IHtcbiAgICBtZXRob2Q6IFwiR0VUXCIsXG4gICAgcmVzb2x2ZVdpdGhGdWxsUmVzcG9uc2U6IGZhbHNlLFxuICAgIHJlamVjdFVuYXV0aG9yaXplZDogdHJ1ZVxuICB9XG5cbiAgLy8gcmF0ZSBsaW1pdCByZXF1ZXN0cyBwZXIgaG9zdFxuICBwcm90ZWN0ZWQgc3RhdGljIFBST01JU0VfVEhST1RUTEVTID0gW107XG4gIHByb3RlY3RlZCBzdGF0aWMgVEFTS19RVUVVRVMgPSBbXTtcbiAgcHJvdGVjdGVkIHN0YXRpYyBERUZBVUxUX1RJTUVPVVQgPSA2MDAwMDtcbiAgc3RhdGljIE1BWF9USU1FT1VUID0gMjE0NzQ4MzY0NzsgLy8gbWF4IDMyLWJpdCBzaWduZWQgbnVtYmVyXG5cbiAgcHJvdGVjdGVkIHN0YXRpYyBIVFRQX0FHRU5UOiBhbnk7XG4gIHByb3RlY3RlZCBzdGF0aWMgSFRUUFNfQUdFTlQ6IGFueTtcblxuICAvKipcbiAgICogPHA+TWFrZSBhIEhUVFAgcmVxdWVzdC48cD5cbiAgICogXG4gICAqIEBwYXJhbSB7b2JqZWN0fSByZXF1ZXN0IC0gY29uZmlndXJlcyB0aGUgcmVxdWVzdCB0byBtYWtlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZXF1ZXN0Lm1ldGhvZCAtIEhUVFAgbWV0aG9kIChcIkdFVFwiLCBcIlBVVFwiLCBcIlBPU1RcIiwgXCJERUxFVEVcIiwgZXRjKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVxdWVzdC51cmkgLSB1cmkgdG8gcmVxdWVzdFxuICAgKiBAcGFyYW0ge3N0cmluZ3xVaW50OEFycmF5fG9iamVjdH0gcmVxdWVzdC5ib2R5IC0gcmVxdWVzdCBib2R5XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcmVxdWVzdC51c2VybmFtZV0gLSB1c2VybmFtZSB0byBhdXRoZW50aWNhdGUgdGhlIHJlcXVlc3QgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW3JlcXVlc3QucGFzc3dvcmRdIC0gcGFzc3dvcmQgdG8gYXV0aGVudGljYXRlIHRoZSByZXF1ZXN0IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtvYmplY3R9IFtyZXF1ZXN0LmhlYWRlcnNdIC0gaGVhZGVycyB0byBhZGQgdG8gdGhlIHJlcXVlc3QgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtyZXF1ZXN0LnJlc29sdmVXaXRoRnVsbFJlc3BvbnNlXSAtIHJldHVybiBmdWxsIHJlc3BvbnNlIGlmIHRydWUsIGVsc2UgYm9keSBvbmx5IChkZWZhdWx0IGZhbHNlKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtyZXF1ZXN0LnJlamVjdFVuYXV0aG9yaXplZF0gLSB3aGV0aGVyIG9yIG5vdCB0byByZWplY3Qgc2VsZi1zaWduZWQgY2VydGlmaWNhdGVzIChkZWZhdWx0IHRydWUpXG4gICAqIEBwYXJhbSB7bnVtYmVyfSByZXF1ZXN0LnRpbWVvdXQgLSBtYXhpbXVtIHRpbWUgYWxsb3dlZCBpbiBtaWxsaXNlY29uZHNcbiAgICogQHBhcmFtIHtudW1iZXJ9IHJlcXVlc3QucHJveHlUb1dvcmtlciAtIHByb3h5IHJlcXVlc3QgdG8gd29ya2VyIHRocmVhZFxuICAgKiBAcmV0dXJuIHtvYmplY3R9IHJlc3BvbnNlIC0gdGhlIHJlc3BvbnNlIG9iamVjdFxuICAgKiBAcmV0dXJuIHtzdHJpbmd8VWludDhBcnJheXxvYmplY3R9IHJlc3BvbnNlLmJvZHkgLSB0aGUgcmVzcG9uc2UgYm9keVxuICAgKiBAcmV0dXJuIHtudW1iZXJ9IHJlc3BvbnNlLnN0YXR1c0NvZGUgLSB0aGUgcmVzcG9uc2UgY29kZVxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IHJlc3BvbnNlLnN0YXR1c1RleHQgLSB0aGUgcmVzcG9uc2UgbWVzc2FnZVxuICAgKiBAcmV0dXJuIHtvYmplY3R9IHJlc3BvbnNlLmhlYWRlcnMgLSB0aGUgcmVzcG9uc2UgaGVhZGVyc1xuICAgKi9cbiAgc3RhdGljIGFzeW5jIHJlcXVlc3QocmVxdWVzdCkge1xuICAgIC8vIHByb3h5IHRvIHdvcmtlciBpZiBjb25maWd1cmVkXG4gICAgaWYgKHJlcXVlc3QucHJveHlUb1dvcmtlcikge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IExpYnJhcnlVdGlscy5pbnZva2VXb3JrZXIodW5kZWZpbmVkLCBcImh0dHBSZXF1ZXN0XCIsIHJlcXVlc3QpO1xuICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgaWYgKGVyci5tZXNzYWdlLmxlbmd0aCA+IDAgJiYgZXJyLm1lc3NhZ2UuY2hhckF0KDApID09PSBcIntcIikge1xuICAgICAgICAgIGxldCBwYXJzZWQgPSBKU09OLnBhcnNlKGVyci5tZXNzYWdlKTtcbiAgICAgICAgICBlcnIubWVzc2FnZSA9IHBhcnNlZC5zdGF0dXNNZXNzYWdlO1xuICAgICAgICAgIGVyci5zdGF0dXNDb2RlID0gcGFyc2VkLnN0YXR1c0NvZGU7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIGFzc2lnbiBkZWZhdWx0c1xuICAgIHJlcXVlc3QgPSBPYmplY3QuYXNzaWduKHt9LCBIdHRwQ2xpZW50LkRFRkFVTFRfUkVRVUVTVCwgcmVxdWVzdCk7XG5cbiAgICAvLyB2YWxpZGF0ZSByZXF1ZXN0XG4gICAgdHJ5IHsgcmVxdWVzdC5ob3N0ID0gbmV3IFVSTChyZXF1ZXN0LnVyaSkuaG9zdDsgfSAvLyBob3N0bmFtZTpwb3J0XG4gICAgY2F0Y2ggKGVycikgeyB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIHJlcXVlc3QgVVJMOiBcIiArIHJlcXVlc3QudXJpKTsgfVxuICAgIGlmIChyZXF1ZXN0LmJvZHkgJiYgISh0eXBlb2YgcmVxdWVzdC5ib2R5ID09PSBcInN0cmluZ1wiIHx8IHR5cGVvZiByZXF1ZXN0LmJvZHkgPT09IFwib2JqZWN0XCIpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJSZXF1ZXN0IGJvZHkgdHlwZSBpcyBub3Qgc3RyaW5nIG9yIG9iamVjdFwiKTtcbiAgICB9XG5cbiAgICAvLyBpbml0aWFsaXplIG9uZSB0YXNrIHF1ZXVlIHBlciBob3N0XG4gICAgaWYgKCFIdHRwQ2xpZW50LlRBU0tfUVVFVUVTW3JlcXVlc3QuaG9zdF0pIEh0dHBDbGllbnQuVEFTS19RVUVVRVNbcmVxdWVzdC5ob3N0XSA9IG5ldyBUaHJlYWRQb29sKDEpO1xuXG4gICAgLy8gaW5pdGlhbGl6ZSBvbmUgcHJvbWlzZSB0aHJvdHRsZSBwZXIgaG9zdFxuICAgIGlmICghSHR0cENsaWVudC5QUk9NSVNFX1RIUk9UVExFU1tyZXF1ZXN0Lmhvc3RdKSB7XG4gICAgICBIdHRwQ2xpZW50LlBST01JU0VfVEhST1RUTEVTW3JlcXVlc3QuaG9zdF0gPSBuZXcgUHJvbWlzZVRocm90dGxlKHtcbiAgICAgICAgcmVxdWVzdHNQZXJTZWNvbmQ6IEh0dHBDbGllbnQuTUFYX1JFUVVFU1RTX1BFUl9TRUNPTkQsIC8vIFRPRE86IEh0dHBDbGllbnQgc2hvdWxkIG5vdCBkZXBlbmQgb24gTW9uZXJvVXRpbHMgZm9yIGNvbmZpZ3VyYXRpb25cbiAgICAgICAgcHJvbWlzZUltcGxlbWVudGF0aW9uOiBQcm9taXNlXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyByZXF1ZXN0IHVzaW5nIGZldGNoIG9yIHhociB3aXRoIHRpbWVvdXRcbiAgICBsZXQgdGltZW91dCA9IHJlcXVlc3QudGltZW91dCA9PT0gdW5kZWZpbmVkID8gSHR0cENsaWVudC5ERUZBVUxUX1RJTUVPVVQgOiByZXF1ZXN0LnRpbWVvdXQgPT09IDAgPyBIdHRwQ2xpZW50Lk1BWF9USU1FT1VUIDogcmVxdWVzdC50aW1lb3V0O1xuICAgIGxldCByZXF1ZXN0UHJvbWlzZSA9IEh0dHBDbGllbnQucmVxdWVzdEF4aW9zKHJlcXVlc3QpO1xuICAgIHJldHVybiBHZW5VdGlscy5leGVjdXRlV2l0aFRpbWVvdXQocmVxdWVzdFByb21pc2UsIHRpbWVvdXQpO1xuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gUFJJVkFURSBIRUxQRVJTIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXG4gIC8qKlxuICAgKiBHZXQgYSBzaW5nbGV0b24gaW5zdGFuY2Ugb2YgYW4gSFRUUCBjbGllbnQgdG8gc2hhcmUuXG4gICAqXG4gICAqIEByZXR1cm4ge2h0dHAuQWdlbnR9IGEgc2hhcmVkIGFnZW50IGZvciBuZXR3b3JrIHJlcXVlc3RzIGFtb25nIGxpYnJhcnkgaW5zdGFuY2VzXG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIGdldEh0dHBBZ2VudCgpIHtcbiAgICBpZiAoIUh0dHBDbGllbnQuSFRUUF9BR0VOVCkgSHR0cENsaWVudC5IVFRQX0FHRU5UID0gbmV3IGh0dHAuQWdlbnQoe1xuICAgICAga2VlcEFsaXZlOiB0cnVlLFxuICAgICAgZmFtaWx5OiA0IC8vIHVzZSBJUHY0XG4gICAgfSk7XG4gICAgcmV0dXJuIEh0dHBDbGllbnQuSFRUUF9BR0VOVDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYSBzaW5nbGV0b24gaW5zdGFuY2Ugb2YgYW4gSFRUUFMgY2xpZW50IHRvIHNoYXJlLlxuICAgKlxuICAgKiBAcmV0dXJuIHtodHRwcy5BZ2VudH0gYSBzaGFyZWQgYWdlbnQgZm9yIG5ldHdvcmsgcmVxdWVzdHMgYW1vbmcgbGlicmFyeSBpbnN0YW5jZXNcbiAgICovXG4gIHByb3RlY3RlZCBzdGF0aWMgZ2V0SHR0cHNBZ2VudCgpIHtcbiAgICBpZiAoIUh0dHBDbGllbnQuSFRUUFNfQUdFTlQpIEh0dHBDbGllbnQuSFRUUFNfQUdFTlQgPSBuZXcgaHR0cHMuQWdlbnQoe1xuICAgICAga2VlcEFsaXZlOiB0cnVlLFxuICAgICAgZmFtaWx5OiA0IC8vIHVzZSBJUHY0XG4gICAgfSk7XG4gICAgcmV0dXJuIEh0dHBDbGllbnQuSFRUUFNfQUdFTlQ7XG4gIH1cblxuICBwcm90ZWN0ZWQgc3RhdGljIGFzeW5jIHJlcXVlc3RBeGlvcyhyZXEpIHtcbiAgICBpZiAocmVxLmhlYWRlcnMpIHRocm93IG5ldyBFcnJvcihcIkN1c3RvbSBoZWFkZXJzIG5vdCBpbXBsZW1lbnRlZCBpbiBYSFIgcmVxdWVzdFwiKTsgIC8vIFRPRE9cblxuICAgIC8vIGNvbGxlY3QgcGFyYW1zIGZyb20gcmVxdWVzdCB3aGljaCBjaGFuZ2Ugb24gYXdhaXRcbiAgICBjb25zdCBtZXRob2QgPSByZXEubWV0aG9kO1xuICAgIGNvbnN0IHVyaSA9IHJlcS51cmk7XG4gICAgY29uc3QgaG9zdCA9IHJlcS5ob3N0O1xuICAgIGNvbnN0IHVzZXJuYW1lID0gcmVxLnVzZXJuYW1lO1xuICAgIGNvbnN0IHBhc3N3b3JkID0gcmVxLnBhc3N3b3JkO1xuICAgIGNvbnN0IGJvZHkgPSByZXEuYm9keTtcbiAgICBjb25zdCBpc0JpbmFyeSA9IGJvZHkgaW5zdGFuY2VvZiBVaW50OEFycmF5O1xuXG4gICAgLy8gcXVldWUgYW5kIHRocm90dGxlIHJlcXVlc3RzIHRvIGV4ZWN1dGUgaW4gc2VyaWFsIGFuZCByYXRlIGxpbWl0ZWQgcGVyIGhvc3RcbiAgICBjb25zdCByZXNwID0gYXdhaXQgSHR0cENsaWVudC5UQVNLX1FVRVVFU1tob3N0XS5zdWJtaXQoYXN5bmMgZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gSHR0cENsaWVudC5QUk9NSVNFX1RIUk9UVExFU1tob3N0XS5hZGQoZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgICAgICBIdHRwQ2xpZW50LmF4aW9zRGlnZXN0QXV0aFJlcXVlc3QobWV0aG9kLCB1cmksIHVzZXJuYW1lLCBwYXNzd29yZCwgYm9keSkudGhlbihmdW5jdGlvbihyZXNwKSB7XG4gICAgICAgICAgICByZXNvbHZlKHJlc3ApO1xuICAgICAgICAgIH0pLmNhdGNoKGZ1bmN0aW9uKGVycm9yOiBBeGlvc0Vycm9yKSB7XG4gICAgICAgICAgICBpZiAoZXJyb3IucmVzcG9uc2U/LnN0YXR1cykgcmVzb2x2ZShlcnJvci5yZXNwb25zZSk7XG4gICAgICAgICAgICByZWplY3QobmV3IEVycm9yKFwiUmVxdWVzdCBmYWlsZWQgd2l0aG91dCByZXNwb25zZTogXCIgKyBtZXRob2QgKyBcIiBcIiArIHVyaSArIFwiIGR1ZSB0byB1bmRlcmx5aW5nIGVycm9yOlxcblwiICsgZXJyb3IubWVzc2FnZSArIFwiXFxuXCIgKyBlcnJvci5zdGFjaykpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcblxuICAgICAgfS5iaW5kKHRoaXMpKTtcbiAgICB9KTtcblxuICAgIC8vIG5vcm1hbGl6ZSByZXNwb25zZVxuICAgIGxldCBub3JtYWxpemVkUmVzcG9uc2U6IGFueSA9IHt9O1xuICAgIG5vcm1hbGl6ZWRSZXNwb25zZS5zdGF0dXNDb2RlID0gcmVzcC5zdGF0dXM7XG4gICAgbm9ybWFsaXplZFJlc3BvbnNlLnN0YXR1c1RleHQgPSByZXNwLnN0YXR1c1RleHQ7XG4gICAgbm9ybWFsaXplZFJlc3BvbnNlLmhlYWRlcnMgPSB7Li4ucmVzcC5oZWFkZXJzfTtcbiAgICBub3JtYWxpemVkUmVzcG9uc2UuYm9keSA9IGlzQmluYXJ5ID8gbmV3IFVpbnQ4QXJyYXkocmVzcC5kYXRhKSA6IHJlc3AuZGF0YTtcbiAgICBpZiAobm9ybWFsaXplZFJlc3BvbnNlLmJvZHkgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikgbm9ybWFsaXplZFJlc3BvbnNlLmJvZHkgPSBuZXcgVWludDhBcnJheShub3JtYWxpemVkUmVzcG9uc2UuYm9keSk7ICAvLyBoYW5kbGUgZW1wdHkgYmluYXJ5IHJlcXVlc3RcbiAgICByZXR1cm4gbm9ybWFsaXplZFJlc3BvbnNlO1xuICB9XG5cbiAgcHJvdGVjdGVkIHN0YXRpYyBheGlvc0RpZ2VzdEF1dGhSZXF1ZXN0ID0gYXN5bmMgZnVuY3Rpb24obWV0aG9kLCB1cmwsIHVzZXJuYW1lLCBwYXNzd29yZCwgYm9keSkge1xuICAgIGlmICh0eXBlb2YgQ3J5cHRvSlMgPT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiByZXF1aXJlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB2YXIgQ3J5cHRvSlMgPSByZXF1aXJlKCdjcnlwdG8tanMnKTtcbiAgICB9XG5cbiAgICBjb25zdCBnZW5lcmF0ZUNub25jZSA9IGZ1bmN0aW9uKCk6IHN0cmluZyB7XG4gICAgICBjb25zdCBjaGFyYWN0ZXJzID0gJ2FiY2RlZjAxMjM0NTY3ODknO1xuICAgICAgbGV0IHRva2VuID0gJyc7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDE2OyBpKyspIHtcbiAgICAgICAgY29uc3QgcmFuZE51bSA9IE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIGNoYXJhY3RlcnMubGVuZ3RoKTtcbiAgICAgICAgdG9rZW4gKz0gY2hhcmFjdGVycy5zbGljZShyYW5kTnVtLCByYW5kTnVtKzEpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRva2VuO1xuICAgIH1cblxuICAgIGxldCBjb3VudCA9IDA7XG4gICAgcmV0dXJuIGF4aW9zLnJlcXVlc3Qoe1xuICAgICAgdXJsOiB1cmwsXG4gICAgICBtZXRob2Q6IG1ldGhvZCxcbiAgICAgIHRpbWVvdXQ6IHRoaXMudGltZW91dCxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJ1xuICAgICAgfSxcbiAgICAgIHJlc3BvbnNlVHlwZTogYm9keSBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkgPyAnYXJyYXlidWZmZXInIDogdW5kZWZpbmVkLFxuICAgICAgaHR0cEFnZW50OiB1cmwuc3RhcnRzV2l0aChcImh0dHBzXCIpID8gdW5kZWZpbmVkIDogSHR0cENsaWVudC5nZXRIdHRwQWdlbnQoKSxcbiAgICAgIGh0dHBzQWdlbnQ6IHVybC5zdGFydHNXaXRoKFwiaHR0cHNcIikgPyBIdHRwQ2xpZW50LmdldEh0dHBzQWdlbnQoKSA6IHVuZGVmaW5lZCxcbiAgICAgIGRhdGE6IGJvZHksXG4gICAgICB0cmFuc2Zvcm1SZXNwb25zZTogcmVzID0+IHJlcyxcbiAgICAgIGFkYXB0ZXI6IEdlblV0aWxzLmlzRGVubygpID8gWydmZXRjaCddIDogWydodHRwJywgJ3hocicsICdmZXRjaCddXG4gICAgfSkuY2F0Y2goYXN5bmMgKGVycikgPT4ge1xuICAgICAgaWYgKGVyci5yZXNwb25zZT8uc3RhdHVzID09PSA0MDEpIHtcbiAgICAgICAgbGV0IGF1dGhIZWFkZXIgPSBlcnIucmVzcG9uc2UuaGVhZGVyc1snd3d3LWF1dGhlbnRpY2F0ZSddLnJlcGxhY2UoLyxcXHNEaWdlc3QuKi8sIFwiXCIpO1xuICAgICAgICBpZiAoIWF1dGhIZWFkZXIpIHtcbiAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBEaWdlc3QgcW9wPVwiYXV0aFwiLGFsZ29yaXRobT1NRDUscmVhbG09XCJtb25lcm8tcnBjXCIsbm9uY2U9XCJoQloyclpJeEVsdjRscUNSclV5bFhBPT1cIixzdGFsZT1mYWxzZVxuICAgICAgICBjb25zdCBhdXRoSGVhZGVyTWFwID0gYXV0aEhlYWRlci5yZXBsYWNlKFwiRGlnZXN0IFwiLCBcIlwiKS5yZXBsYWNlQWxsKCdcIicsIFwiXCIpLnNwbGl0KFwiLFwiKS5yZWR1Y2UoKHByZXYsIGN1cnIpID0+ICh7Li4ucHJldiwgW2N1cnIuc3BsaXQoXCI9XCIpWzBdXTogY3Vyci5zcGxpdChcIj1cIikuc2xpY2UoMSkuam9pbignPScpfSksIHt9KVxuXG4gICAgICAgICsrY291bnQ7XG5cbiAgICAgICAgY29uc3QgY25vbmNlID0gZ2VuZXJhdGVDbm9uY2UoKTtcbiAgICAgICAgY29uc3QgSEExID0gQ3J5cHRvSlMuTUQ1KHVzZXJuYW1lKyc6JythdXRoSGVhZGVyTWFwLnJlYWxtKyc6JytwYXNzd29yZCkudG9TdHJpbmcoKTtcbiAgICAgICAgY29uc3QgSEEyID0gQ3J5cHRvSlMuTUQ1KG1ldGhvZCsnOicrdXJsKS50b1N0cmluZygpO1xuXG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gQ3J5cHRvSlMuTUQ1KEhBMSsnOicrXG4gICAgICAgICAgYXV0aEhlYWRlck1hcC5ub25jZSsnOicrXG4gICAgICAgICAgKCcwMDAwMDAwMCcgKyBjb3VudCkuc2xpY2UoLTgpKyc6JytcbiAgICAgICAgICBjbm9uY2UrJzonK1xuICAgICAgICAgIGF1dGhIZWFkZXJNYXAucW9wKyc6JytcbiAgICAgICAgICBIQTIpLnRvU3RyaW5nKCk7XG4gICAgICAgIGNvbnN0IGRpZ2VzdEF1dGhIZWFkZXIgPSAnRGlnZXN0JysnICcrXG4gICAgICAgICAgJ3VzZXJuYW1lPVwiJyt1c2VybmFtZSsnXCIsICcrXG4gICAgICAgICAgJ3JlYWxtPVwiJythdXRoSGVhZGVyTWFwLnJlYWxtKydcIiwgJytcbiAgICAgICAgICAnbm9uY2U9XCInK2F1dGhIZWFkZXJNYXAubm9uY2UrJ1wiLCAnK1xuICAgICAgICAgICd1cmk9XCInK3VybCsnXCIsICcrXG4gICAgICAgICAgJ3Jlc3BvbnNlPVwiJytyZXNwb25zZSsnXCIsICcrXG4gICAgICAgICAgJ29wYXF1ZT1cIicrKGF1dGhIZWFkZXJNYXAub3BhcXVlID8/IG51bGwpKydcIiwgJytcbiAgICAgICAgICAncW9wPScrYXV0aEhlYWRlck1hcC5xb3ArJywgJytcbiAgICAgICAgICAnbmM9JysoJzAwMDAwMDAwJyArIGNvdW50KS5zbGljZSgtOCkrJywgJytcbiAgICAgICAgICAnY25vbmNlPVwiJytjbm9uY2UrJ1wiJztcblxuICAgICAgICBjb25zdCBmaW5hbFJlc3BvbnNlID0gYXdhaXQgYXhpb3MucmVxdWVzdCh7XG4gICAgICAgICAgdXJsOiB1cmwsXG4gICAgICAgICAgbWV0aG9kOiBtZXRob2QsXG4gICAgICAgICAgdGltZW91dDogdGhpcy50aW1lb3V0LFxuICAgICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAgICdBdXRob3JpemF0aW9uJzogZGlnZXN0QXV0aEhlYWRlcixcbiAgICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbidcbiAgICAgICAgICB9LFxuICAgICAgICAgIHJlc3BvbnNlVHlwZTogYm9keSBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkgPyAnYXJyYXlidWZmZXInIDogdW5kZWZpbmVkLFxuICAgICAgICAgIGh0dHBBZ2VudDogdXJsLnN0YXJ0c1dpdGgoXCJodHRwc1wiKSA/IHVuZGVmaW5lZCA6IEh0dHBDbGllbnQuZ2V0SHR0cEFnZW50KCksXG4gICAgICAgICAgaHR0cHNBZ2VudDogdXJsLnN0YXJ0c1dpdGgoXCJodHRwc1wiKSA/IEh0dHBDbGllbnQuZ2V0SHR0cHNBZ2VudCgpIDogdW5kZWZpbmVkLFxuICAgICAgICAgIGRhdGE6IGJvZHksXG4gICAgICAgICAgdHJhbnNmb3JtUmVzcG9uc2U6IHJlcyA9PiByZXMsXG4gICAgICAgICAgYWRhcHRlcjogR2VuVXRpbHMuaXNEZW5vKCkgPyBbJ2ZldGNoJ10gOiBbJ2h0dHAnLCAneGhyJywgJ2ZldGNoJ11cbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGZpbmFsUmVzcG9uc2U7XG4gICAgICB9XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfSkuY2F0Y2goZXJyID0+IHtcbiAgICAgIHRocm93IGVycjtcbiAgICB9KTtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsU0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsYUFBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUUsV0FBQSxHQUFBSCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUcsZ0JBQUEsR0FBQUosc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFJLEtBQUEsR0FBQUwsc0JBQUEsQ0FB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 \ No newline at end of file diff --git a/dist/src/main/ts/common/LibraryUtils.d.ts b/dist/src/main/ts/common/LibraryUtils.d.ts new file mode 100644 index 000000000..2aaf89fd7 --- /dev/null +++ b/dist/src/main/ts/common/LibraryUtils.d.ts @@ -0,0 +1,109 @@ +import ThreadPool from "./ThreadPool"; +/** + * Collection of helper utilities for the library. + */ +export default class LibraryUtils { + static LOG_LEVEL: number; + static WASM_MODULE: any; + static WORKER: any; + static WORKER_OBJECTS: any; + static FULL_LOADED: any; + static REJECT_UNAUTHORIZED_FNS: any; + static readonly MUTEX: ThreadPool; + static WORKER_DIST_PATH_DEFAULT: string; + static WORKER_DIST_PATH: string; + static WORKER_LOADER?: () => Worker; + /** + * Log a message. + * + * @param {number} level - log level of the message + * @param {string} msg - message to log + */ + static log(level: any, msg: any): void; + /** + * Set the library's log level with 0 being least verbose. + * + * @param {number} level - the library's log level + */ + static setLogLevel(level: any): Promise; + /** + * Get the library's log level. + * + * @return {number} the library's log level + */ + static getLogLevel(): number; + /** + * Get the total memory used by WebAssembly. + * + * @return {Promise} the total memory used by WebAssembly + */ + static getWasmMemoryUsed(): Promise; + /** + * Get the WebAssembly module in the current context (nodejs, browser main thread or worker). + */ + static getWasmModule(): any; + /** + * Load the WebAssembly full module with caching. + * + * The full module is a superset of the keys module and overrides it. + */ + static loadWasmModule(): Promise; + /** + * Register a function by id which informs if unauthorized requests (e.g. + * self-signed certificates) should be rejected. + * + * @param {string} fnId - unique identifier for the function + * @param {function} fn - function to inform if unauthorized requests should be rejected + */ + static setRejectUnauthorizedFn(fnId: any, fn: any): void; + /** + * Indicate if unauthorized requests should be rejected. + * + * @param {string} fnId - uniquely identifies the function + */ + static isRejectUnauthorized(fnId: any): any; + /** + * Set the path to load the worker. Defaults to "/monero.worker.js" in the browser + * and "./MoneroWebWorker.js" in node. + * + * @param {string} workerDistPath - path to load the worker + */ + static setWorkerDistPath(workerDistPath: any): void; + /** + * Set the worker loader closure to customize worker loading. + * Takes precedence over default loading mechanisms. + * + * Could be as simple as `() => new Worker(new URL("monero-ts/dist/monero.worker.js", import.meta.url));` for browsers. + * + * @param {function} loader - loader function which instantiates a worker + */ + static setWorkerLoader(loader?: () => Worker): void; + /** + * Get a singleton instance of a worker to share. + * + * @return {Worker} a worker to share among wallet instances + */ + static getWorker(): Promise; + static addWorkerCallback(objectId: any, callbackId: any, callbackArgs: any): void; + static removeWorkerCallback(objectId: any, callbackId: any): void; + static removeWorkerObject(objectId: any): void; + /** + * Terminate monero-ts's singleton worker. + */ + static terminateWorker(): Promise; + /** + * Invoke a worker function and get the result with error handling. + * + * @param {string} objectId identifies the worker object to invoke (default random id) + * @param {string} fnName is the name of the function to invoke + * @param {any[]} [args] are function arguments to invoke with + * @return {any} resolves with response payload from the worker or an error + */ + static invokeWorker(objectId: any, fnName: any, args: any): Promise; + static serializeError(err: any): any; + protected static deserializeError(serializedErr: any): Error; + static queueTask(asyncFn: () => Promise): Promise; + static exists(fs: any, path: string): Promise; + protected static initWasmModule(wasmModule: any): void; + protected static prefixWindowsPath(path: any): any; +} diff --git a/dist/src/main/ts/common/LibraryUtils.js b/dist/src/main/ts/common/LibraryUtils.js new file mode 100644 index 000000000..5341323e3 --- /dev/null +++ b/dist/src/main/ts/common/LibraryUtils.js @@ -0,0 +1,292 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("./GenUtils")); +var _MoneroError = _interopRequireDefault(require("./MoneroError")); +var _ThreadPool = _interopRequireDefault(require("./ThreadPool")); +var _path = _interopRequireDefault(require("path")); + +/** + * Collection of helper utilities for the library. + */ +class LibraryUtils { + + // static variables + static LOG_LEVEL = 0; + + + + + + static MUTEX = new _ThreadPool.default(1); + static WORKER_DIST_PATH_DEFAULT = _GenUtils.default.isBrowser() ? "/monero.worker.js" : function () { + + // get worker path in dist (assumes library is running from src or dist) + let curPath = _path.default.normalize(__dirname); + const targetPath = _path.default.join('monero-ts', 'dist'); + if (!curPath.includes(targetPath)) curPath = _path.default.join(curPath, "../../../../dist/src/main/js/common"); + curPath = LibraryUtils.prefixWindowsPath(_path.default.join(curPath, "./MoneroWebWorker.js")); + if (_GenUtils.default.isDeno()) curPath = _path.default.join("file://", curPath); + return curPath; + }(); + static WORKER_DIST_PATH = LibraryUtils.WORKER_DIST_PATH_DEFAULT; + static WORKER_LOADER = undefined; + + /** + * Log a message. + * + * @param {number} level - log level of the message + * @param {string} msg - message to log + */ + static log(level, msg) { + (0, _assert.default)(level === parseInt(level, 10) && level >= 0, "Log level must be an integer >= 0"); + if (LibraryUtils.LOG_LEVEL >= level) console.log(msg); + } + + /** + * Set the library's log level with 0 being least verbose. + * + * @param {number} level - the library's log level + */ + static async setLogLevel(level) { + (0, _assert.default)(level === parseInt(level, 10) && level >= 0, "Log level must be an integer >= 0"); + LibraryUtils.LOG_LEVEL = level; + if (LibraryUtils.WASM_MODULE) LibraryUtils.WASM_MODULE.set_log_level(level); + if (LibraryUtils.WORKER) await LibraryUtils.invokeWorker(undefined, "setLogLevel", [level]); + } + + /** + * Get the library's log level. + * + * @return {number} the library's log level + */ + static getLogLevel() { + return LibraryUtils.LOG_LEVEL; + } + + /** + * Get the total memory used by WebAssembly. + * + * @return {Promise} the total memory used by WebAssembly + */ + static async getWasmMemoryUsed() { + let total = 0; + if (LibraryUtils.WORKER) total += await LibraryUtils.invokeWorker(undefined, "getWasmMemoryUsed", []); + if (LibraryUtils.getWasmModule() && LibraryUtils.getWasmModule().HEAP8) total += LibraryUtils.getWasmModule().HEAP8.length; + return total; + } + + /** + * Get the WebAssembly module in the current context (nodejs, browser main thread or worker). + */ + static getWasmModule() { + return LibraryUtils.WASM_MODULE; + } + + /** + * Load the WebAssembly full module with caching. + * + * The full module is a superset of the keys module and overrides it. + */ + static async loadWasmModule() { + + // use cache if suitable, full module supersedes keys module because it is superset + if (LibraryUtils.WASM_MODULE && LibraryUtils.FULL_LOADED) return LibraryUtils.WASM_MODULE; + + // load module + const module = await require("#monero-ts/monero.js")(); + LibraryUtils.WASM_MODULE = module; + delete LibraryUtils.WASM_MODULE.then; + LibraryUtils.FULL_LOADED = true; + LibraryUtils.initWasmModule(LibraryUtils.WASM_MODULE); + return module; + } + + /** + * Register a function by id which informs if unauthorized requests (e.g. + * self-signed certificates) should be rejected. + * + * @param {string} fnId - unique identifier for the function + * @param {function} fn - function to inform if unauthorized requests should be rejected + */ + static setRejectUnauthorizedFn(fnId, fn) { + if (!LibraryUtils.REJECT_UNAUTHORIZED_FNS) LibraryUtils.REJECT_UNAUTHORIZED_FNS = []; + if (fn === undefined) delete LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId];else + LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId] = fn; + } + + /** + * Indicate if unauthorized requests should be rejected. + * + * @param {string} fnId - uniquely identifies the function + */ + static isRejectUnauthorized(fnId) { + if (!LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId]) throw new Error("No function registered with id " + fnId + " to inform if unauthorized reqs should be rejected"); + return LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId](); + } + + /** + * Set the path to load the worker. Defaults to "/monero.worker.js" in the browser + * and "./MoneroWebWorker.js" in node. + * + * @param {string} workerDistPath - path to load the worker + */ + static setWorkerDistPath(workerDistPath) { + let path = LibraryUtils.prefixWindowsPath(workerDistPath ? workerDistPath : LibraryUtils.WORKER_DIST_PATH_DEFAULT); + if (path !== LibraryUtils.WORKER_DIST_PATH) delete LibraryUtils.WORKER; + LibraryUtils.WORKER_DIST_PATH = path; + } + + /** + * Set the worker loader closure to customize worker loading. + * Takes precedence over default loading mechanisms. + * + * Could be as simple as `() => new Worker(new URL("monero-ts/dist/monero.worker.js", import.meta.url));` for browsers. + * + * @param {function} loader - loader function which instantiates a worker + */ + static setWorkerLoader(loader) { + LibraryUtils.WORKER_LOADER = loader; + } + + /** + * Get a singleton instance of a worker to share. + * + * @return {Worker} a worker to share among wallet instances + */ + static async getWorker() { + + // one time initialization + if (!LibraryUtils.WORKER) { + + // try to load worker with user provided closure + if (LibraryUtils.WORKER_LOADER) { + LibraryUtils.WORKER = LibraryUtils.WORKER_LOADER(); + } else { + + // otherwise use standard loading mechanisms for browser and node + if (_GenUtils.default.isBrowser()) { + LibraryUtils.WORKER = new Worker(LibraryUtils.WORKER_DIST_PATH); + } else if (_GenUtils.default.isDeno()) { + LibraryUtils.WORKER = new Worker(LibraryUtils.WORKER_DIST_PATH, { type: "module" }); + } else { + const Worker = require("web-worker"); // import web worker if nodejs + LibraryUtils.WORKER = new Worker(LibraryUtils.WORKER_DIST_PATH); + } + } + LibraryUtils.WORKER_OBJECTS = {}; // store per object running in the worker + + // receive worker errors + LibraryUtils.WORKER.onerror = function (err) { + console.error("Error posting message to monero.worker.js; is it built and copied to the app's public or build directory?"); + console.log(err); + }; + + // receive worker messages + LibraryUtils.WORKER.onmessage = function (e) { + + // lookup object id, callback function, and this arg + let thisArg = undefined; + let callbackFn = LibraryUtils.WORKER_OBJECTS[e.data[0]].callbacks[e.data[1]]; // look up by object id then by function name + if (callbackFn === undefined) throw new Error("No worker callback function defined for key '" + e.data[1] + "'"); + if (callbackFn instanceof Array) {// this arg may be stored with callback function + thisArg = callbackFn[1]; + callbackFn = callbackFn[0]; + } + + // invoke callback function with this arg and arguments + callbackFn.apply(thisArg, e.data.slice(2)); + }; + } + return LibraryUtils.WORKER; + } + + static addWorkerCallback(objectId, callbackId, callbackArgs) { + LibraryUtils.WORKER_OBJECTS[objectId].callbacks[callbackId] = callbackArgs; + } + + static removeWorkerCallback(objectId, callbackId) { + delete LibraryUtils.WORKER_OBJECTS[objectId].callbacks[callbackId]; + } + + static removeWorkerObject(objectId) { + delete LibraryUtils.WORKER_OBJECTS[objectId]; + } + + /** + * Terminate monero-ts's singleton worker. + */ + static async terminateWorker() { + if (LibraryUtils.WORKER) { + LibraryUtils.WORKER.terminate(); + delete LibraryUtils.WORKER; + LibraryUtils.WORKER = undefined; + } + } + + /** + * Invoke a worker function and get the result with error handling. + * + * @param {string} objectId identifies the worker object to invoke (default random id) + * @param {string} fnName is the name of the function to invoke + * @param {any[]} [args] are function arguments to invoke with + * @return {any} resolves with response payload from the worker or an error + */ + static async invokeWorker(objectId, fnName, args) { + (0, _assert.default)(fnName.length >= 2); + let worker = await LibraryUtils.getWorker(); + let randomObject = objectId === undefined; + if (randomObject) objectId = _GenUtils.default.getUUID(); + if (!LibraryUtils.WORKER_OBJECTS[objectId]) LibraryUtils.WORKER_OBJECTS[objectId] = { callbacks: {} }; + let callbackId = _GenUtils.default.getUUID(); + try { + return await new Promise((resolve, reject) => { + LibraryUtils.WORKER_OBJECTS[objectId].callbacks[callbackId] = (resp) => {// TODO: this defines function once per callback + delete LibraryUtils.WORKER_OBJECTS[objectId].callbacks[callbackId]; + if (randomObject) delete LibraryUtils.WORKER_OBJECTS[objectId]; + resp ? resp.error ? reject(new Error(JSON.stringify(resp.error))) : resolve(resp.result) : resolve(undefined); + }; + worker.postMessage([objectId, fnName, callbackId].concat(args === undefined ? [] : _GenUtils.default.listify(args))); + }); + } catch (e) { + throw LibraryUtils.deserializeError(JSON.parse(e.message)); + } + } + + static serializeError(err) { + const serializedErr = { name: err.name, message: err.message, code: err.code, stack: err.stack }; + if (err instanceof _MoneroError.default) serializedErr.type = "MoneroError"; + return serializedErr; + } + + static deserializeError(serializedErr) { + const err = serializedErr.type === "MoneroError" ? new _MoneroError.default(serializedErr.message, serializedErr.code) : new Error(serializedErr.message); + err.name = serializedErr.name; + err.stack = err.stack + "\nWorker error: " + serializedErr.stack; + return err; + } + + static async queueTask(asyncFn) { + return LibraryUtils.MUTEX.submit(asyncFn); + } + + static async exists(fs, path) { + try { + await fs.access(path); + return true; + } catch (err) { + return false; + } + } + + // ------------------------------ PRIVATE HELPERS --------------------------- + + static initWasmModule(wasmModule) { + wasmModule.taskQueue = new _ThreadPool.default(1); + wasmModule.queueTask = async function (asyncFn) {return wasmModule.taskQueue.submit(asyncFn);}; + } + + static prefixWindowsPath(path) { + if (/^[A-Z]:/.test(path) && path.indexOf("file://") == -1) path = "file://" + path; // prepend e.g. C: paths with file:// + return path; + } +}exports.default = LibraryUtils; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTW9uZXJvRXJyb3IiLCJfVGhyZWFkUG9vbCIsIl9wYXRoIiwiTGlicmFyeVV0aWxzIiwiTE9HX0xFVkVMIiwiTVVURVgiLCJUaHJlYWRQb29sIiwiV09SS0VSX0RJU1RfUEFUSF9ERUZBVUxUIiwiR2VuVXRpbHMiLCJpc0Jyb3dzZXIiLCJjdXJQYXRoIiwicGF0aCIsIm5vcm1hbGl6ZSIsIl9fZGlybmFtZSIsInRhcmdldFBhdGgiLCJqb2luIiwiaW5jbHVkZXMiLCJwcmVmaXhXaW5kb3dzUGF0aCIsImlzRGVubyIsIldPUktFUl9ESVNUX1BBVEgiLCJXT1JLRVJfTE9BREVSIiwidW5kZWZpbmVkIiwibG9nIiwibGV2ZWwiLCJtc2ciLCJhc3NlcnQiLCJwYXJzZUludCIsImNvbnNvbGUiLCJzZXRMb2dMZXZlbCIsIldBU01fTU9EVUxFIiwic2V0X2xvZ19sZXZlbCIsIldPUktFUiIsImludm9rZVdvcmtlciIsImdldExvZ0xldmVsIiwiZ2V0V2FzbU1lbW9yeVVzZWQiLCJ0b3RhbCIsImdldFdhc21Nb2R1bGUiLCJIRUFQOCIsImxlbmd0aCIsImxvYWRXYXNtTW9kdWxlIiwiRlVMTF9MT0FERUQiLCJtb2R1bGUiLCJ0aGVuIiwiaW5pdFdhc21Nb2R1bGUiLCJzZXRSZWplY3RVbmF1dGhvcml6ZWRGbiIsImZuSWQiLCJmbiIsIlJFSkVDVF9VTkFVVEhPUklaRURfRk5TIiwiaXNSZWplY3RVbmF1dGhvcml6ZWQiLCJFcnJvciIsInNldFdvcmtlckRpc3RQYXRoIiwid29ya2VyRGlzdFBhdGgiLCJzZXRXb3JrZXJMb2FkZXIiLCJsb2FkZXIiLCJnZXRXb3JrZXIiLCJXb3JrZXIiLCJ0eXBlIiwiV09SS0VSX09CSkVDVFMiLCJvbmVycm9yIiwiZXJyIiwiZXJyb3IiLCJvbm1lc3NhZ2UiLCJlIiwidGhpc0FyZyIsImNhbGxiYWNrRm4iLCJkYXRhIiwiY2FsbGJhY2tzIiwiQXJyYXkiLCJhcHBseSIsInNsaWNlIiwiYWRkV29ya2VyQ2FsbGJhY2siLCJvYmplY3RJZCIsImNhbGxiYWNrSWQiLCJjYWxsYmFja0FyZ3MiLCJyZW1vdmVXb3JrZXJDYWxsYmFjayIsInJlbW92ZVdvcmtlck9iamVjdCIsInRlcm1pbmF0ZVdvcmtlciIsInRlcm1pbmF0ZSIsImZuTmFtZSIsImFyZ3MiLCJ3b3JrZXIiLCJyYW5kb21PYmplY3QiLCJnZXRVVUlEIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJyZXNwIiwiSlNPTiIsInN0cmluZ2lmeSIsInJlc3VsdCIsInBvc3RNZXNzYWdlIiwiY29uY2F0IiwibGlzdGlmeSIsImRlc2VyaWFsaXplRXJyb3IiLCJwYXJzZSIsIm1lc3NhZ2UiLCJzZXJpYWxpemVFcnJvciIsInNlcmlhbGl6ZWRFcnIiLCJuYW1lIiwiY29kZSIsInN0YWNrIiwiTW9uZXJvRXJyb3IiLCJxdWV1ZVRhc2siLCJhc3luY0ZuIiwic3VibWl0IiwiZXhpc3RzIiwiZnMiLCJhY2Nlc3MiLCJ3YXNtTW9kdWxlIiwidGFza1F1ZXVlIiwidGVzdCIsImluZGV4T2YiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2NvbW1vbi9MaWJyYXJ5VXRpbHMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgR2VuVXRpbHMgZnJvbSBcIi4vR2VuVXRpbHNcIjtcbmltcG9ydCBNb25lcm9FcnJvciBmcm9tIFwiLi9Nb25lcm9FcnJvclwiO1xuaW1wb3J0IFRocmVhZFBvb2wgZnJvbSBcIi4vVGhyZWFkUG9vbFwiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcblxuLyoqXG4gKiBDb2xsZWN0aW9uIG9mIGhlbHBlciB1dGlsaXRpZXMgZm9yIHRoZSBsaWJyYXJ5LlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBMaWJyYXJ5VXRpbHMge1xuXG4gIC8vIHN0YXRpYyB2YXJpYWJsZXNcbiAgc3RhdGljIExPR19MRVZFTCA9IDA7XG4gIHN0YXRpYyBXQVNNX01PRFVMRTogYW55O1xuICBzdGF0aWMgV09SS0VSOiBhbnk7XG4gIHN0YXRpYyBXT1JLRVJfT0JKRUNUUzogYW55O1xuICBzdGF0aWMgRlVMTF9MT0FERUQ6IGFueTtcbiAgc3RhdGljIFJFSkVDVF9VTkFVVEhPUklaRURfRk5TOiBhbnk7XG4gIHN0YXRpYyByZWFkb25seSBNVVRFWCA9IG5ldyBUaHJlYWRQb29sKDEpO1xuICBzdGF0aWMgV09SS0VSX0RJU1RfUEFUSF9ERUZBVUxUID0gR2VuVXRpbHMuaXNCcm93c2VyKCkgPyBcIi9tb25lcm8ud29ya2VyLmpzXCIgOiBmdW5jdGlvbigpIHtcblxuICAgIC8vIGdldCB3b3JrZXIgcGF0aCBpbiBkaXN0IChhc3N1bWVzIGxpYnJhcnkgaXMgcnVubmluZyBmcm9tIHNyYyBvciBkaXN0KVxuICAgIGxldCBjdXJQYXRoID0gcGF0aC5ub3JtYWxpemUoX19kaXJuYW1lKTtcbiAgICBjb25zdCB0YXJnZXRQYXRoID0gcGF0aC5qb2luKCdtb25lcm8tdHMnLCAnZGlzdCcpO1xuICAgIGlmICghY3VyUGF0aC5pbmNsdWRlcyh0YXJnZXRQYXRoKSkgY3VyUGF0aCA9IHBhdGguam9pbihjdXJQYXRoLCBcIi4uLy4uLy4uLy4uL2Rpc3Qvc3JjL21haW4vanMvY29tbW9uXCIpO1xuICAgIGN1clBhdGggPSBMaWJyYXJ5VXRpbHMucHJlZml4V2luZG93c1BhdGgocGF0aC5qb2luKGN1clBhdGgsIFwiLi9Nb25lcm9XZWJXb3JrZXIuanNcIikpO1xuICAgIGlmIChHZW5VdGlscy5pc0Rlbm8oKSkgY3VyUGF0aCA9IHBhdGguam9pbihcImZpbGU6Ly9cIiwgY3VyUGF0aCk7XG4gICAgcmV0dXJuIGN1clBhdGg7XG4gIH0oKTtcbiAgc3RhdGljIFdPUktFUl9ESVNUX1BBVEggPSBMaWJyYXJ5VXRpbHMuV09SS0VSX0RJU1RfUEFUSF9ERUZBVUxUO1xuICBzdGF0aWMgV09SS0VSX0xPQURFUj86ICgpID0+IFdvcmtlciA9IHVuZGVmaW5lZDtcbiAgXG4gIC8qKlxuICAgKiBMb2cgYSBtZXNzYWdlLlxuICAgKlxuICAgKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgLSBsb2cgbGV2ZWwgb2YgdGhlIG1lc3NhZ2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1zZyAtIG1lc3NhZ2UgdG8gbG9nXG4gICAqL1xuICBzdGF0aWMgbG9nKGxldmVsLCBtc2cpIHtcbiAgICBhc3NlcnQobGV2ZWwgPT09IHBhcnNlSW50KGxldmVsLCAxMCkgJiYgbGV2ZWwgPj0gMCwgXCJMb2cgbGV2ZWwgbXVzdCBiZSBhbiBpbnRlZ2VyID49IDBcIik7XG4gICAgaWYgKExpYnJhcnlVdGlscy5MT0dfTEVWRUwgPj0gbGV2ZWwpIGNvbnNvbGUubG9nKG1zZyk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZXQgdGhlIGxpYnJhcnkncyBsb2cgbGV2ZWwgd2l0aCAwIGJlaW5nIGxlYXN0IHZlcmJvc2UuXG4gICAqXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIHRoZSBsaWJyYXJ5J3MgbG9nIGxldmVsXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgc2V0TG9nTGV2ZWwobGV2ZWwpIHtcbiAgICBhc3NlcnQobGV2ZWwgPT09IHBhcnNlSW50KGxldmVsLCAxMCkgJiYgbGV2ZWwgPj0gMCwgXCJMb2cgbGV2ZWwgbXVzdCBiZSBhbiBpbnRlZ2VyID49IDBcIik7XG4gICAgTGlicmFyeVV0aWxzLkxPR19MRVZFTCA9IGxldmVsO1xuICAgIGlmIChMaWJyYXJ5VXRpbHMuV0FTTV9NT0RVTEUpIExpYnJhcnlVdGlscy5XQVNNX01PRFVMRS5zZXRfbG9nX2xldmVsKGxldmVsKTtcbiAgICBpZiAoTGlicmFyeVV0aWxzLldPUktFUikgYXdhaXQgTGlicmFyeVV0aWxzLmludm9rZVdvcmtlcih1bmRlZmluZWQsIFwic2V0TG9nTGV2ZWxcIiwgW2xldmVsXSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIGxpYnJhcnkncyBsb2cgbGV2ZWwuXG4gICAqXG4gICAqIEByZXR1cm4ge251bWJlcn0gdGhlIGxpYnJhcnkncyBsb2cgbGV2ZWxcbiAgICovXG4gIHN0YXRpYyBnZXRMb2dMZXZlbCgpOiBudW1iZXIge1xuICAgIHJldHVybiBMaWJyYXJ5VXRpbHMuTE9HX0xFVkVMO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSB0b3RhbCBtZW1vcnkgdXNlZCBieSBXZWJBc3NlbWJseS5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8bnVtYmVyPn0gdGhlIHRvdGFsIG1lbW9yeSB1c2VkIGJ5IFdlYkFzc2VtYmx5XG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZ2V0V2FzbU1lbW9yeVVzZWQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBsZXQgdG90YWwgPSAwO1xuICAgIGlmIChMaWJyYXJ5VXRpbHMuV09SS0VSKSB0b3RhbCArPSBhd2FpdCBMaWJyYXJ5VXRpbHMuaW52b2tlV29ya2VyKHVuZGVmaW5lZCwgXCJnZXRXYXNtTWVtb3J5VXNlZFwiLCBbXSkgYXMgbnVtYmVyO1xuICAgIGlmIChMaWJyYXJ5VXRpbHMuZ2V0V2FzbU1vZHVsZSgpICYmIExpYnJhcnlVdGlscy5nZXRXYXNtTW9kdWxlKCkuSEVBUDgpIHRvdGFsICs9IExpYnJhcnlVdGlscy5nZXRXYXNtTW9kdWxlKCkuSEVBUDgubGVuZ3RoO1xuICAgIHJldHVybiB0b3RhbDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgV2ViQXNzZW1ibHkgbW9kdWxlIGluIHRoZSBjdXJyZW50IGNvbnRleHQgKG5vZGVqcywgYnJvd3NlciBtYWluIHRocmVhZCBvciB3b3JrZXIpLlxuICAgKi9cbiAgc3RhdGljIGdldFdhc21Nb2R1bGUoKSB7XG4gICAgcmV0dXJuIExpYnJhcnlVdGlscy5XQVNNX01PRFVMRTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIExvYWQgdGhlIFdlYkFzc2VtYmx5IGZ1bGwgbW9kdWxlIHdpdGggY2FjaGluZy5cbiAgICogXG4gICAqIFRoZSBmdWxsIG1vZHVsZSBpcyBhIHN1cGVyc2V0IG9mIHRoZSBrZXlzIG1vZHVsZSBhbmQgb3ZlcnJpZGVzIGl0LlxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGxvYWRXYXNtTW9kdWxlKCkge1xuICAgIFxuICAgIC8vIHVzZSBjYWNoZSBpZiBzdWl0YWJsZSwgZnVsbCBtb2R1bGUgc3VwZXJzZWRlcyBrZXlzIG1vZHVsZSBiZWNhdXNlIGl0IGlzIHN1cGVyc2V0XG4gICAgaWYgKExpYnJhcnlVdGlscy5XQVNNX01PRFVMRSAmJiBMaWJyYXJ5VXRpbHMuRlVMTF9MT0FERUQpIHJldHVybiBMaWJyYXJ5VXRpbHMuV0FTTV9NT0RVTEU7XG4gICAgXG4gICAgLy8gbG9hZCBtb2R1bGVcbiAgICBjb25zdCBtb2R1bGUgPSBhd2FpdCByZXF1aXJlKFwiI21vbmVyby10cy9tb25lcm8uanNcIikoKTtcbiAgICBMaWJyYXJ5VXRpbHMuV0FTTV9NT0RVTEUgPSBtb2R1bGU7XG4gICAgZGVsZXRlIExpYnJhcnlVdGlscy5XQVNNX01PRFVMRS50aGVuO1xuICAgIExpYnJhcnlVdGlscy5GVUxMX0xPQURFRCA9IHRydWU7XG4gICAgTGlicmFyeVV0aWxzLmluaXRXYXNtTW9kdWxlKExpYnJhcnlVdGlscy5XQVNNX01PRFVMRSk7XG4gICAgcmV0dXJuIG1vZHVsZTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJlZ2lzdGVyIGEgZnVuY3Rpb24gYnkgaWQgd2hpY2ggaW5mb3JtcyBpZiB1bmF1dGhvcml6ZWQgcmVxdWVzdHMgKGUuZy5cbiAgICogc2VsZi1zaWduZWQgY2VydGlmaWNhdGVzKSBzaG91bGQgYmUgcmVqZWN0ZWQuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gZm5JZCAtIHVuaXF1ZSBpZGVudGlmaWVyIGZvciB0aGUgZnVuY3Rpb25cbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBmdW5jdGlvbiB0byBpbmZvcm0gaWYgdW5hdXRob3JpemVkIHJlcXVlc3RzIHNob3VsZCBiZSByZWplY3RlZFxuICAgKi9cbiAgc3RhdGljIHNldFJlamVjdFVuYXV0aG9yaXplZEZuKGZuSWQsIGZuKSB7XG4gICAgaWYgKCFMaWJyYXJ5VXRpbHMuUkVKRUNUX1VOQVVUSE9SSVpFRF9GTlMpIExpYnJhcnlVdGlscy5SRUpFQ1RfVU5BVVRIT1JJWkVEX0ZOUyA9IFtdO1xuICAgIGlmIChmbiA9PT0gdW5kZWZpbmVkKSBkZWxldGUgTGlicmFyeVV0aWxzLlJFSkVDVF9VTkFVVEhPUklaRURfRk5TW2ZuSWRdO1xuICAgIGVsc2UgTGlicmFyeVV0aWxzLlJFSkVDVF9VTkFVVEhPUklaRURfRk5TW2ZuSWRdID0gZm47XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbmRpY2F0ZSBpZiB1bmF1dGhvcml6ZWQgcmVxdWVzdHMgc2hvdWxkIGJlIHJlamVjdGVkLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IGZuSWQgLSB1bmlxdWVseSBpZGVudGlmaWVzIHRoZSBmdW5jdGlvblxuICAgKi9cbiAgc3RhdGljIGlzUmVqZWN0VW5hdXRob3JpemVkKGZuSWQpIHtcbiAgICBpZiAoIUxpYnJhcnlVdGlscy5SRUpFQ1RfVU5BVVRIT1JJWkVEX0ZOU1tmbklkXSkgdGhyb3cgbmV3IEVycm9yKFwiTm8gZnVuY3Rpb24gcmVnaXN0ZXJlZCB3aXRoIGlkIFwiICsgZm5JZCArIFwiIHRvIGluZm9ybSBpZiB1bmF1dGhvcml6ZWQgcmVxcyBzaG91bGQgYmUgcmVqZWN0ZWRcIik7XG4gICAgcmV0dXJuIExpYnJhcnlVdGlscy5SRUpFQ1RfVU5BVVRIT1JJWkVEX0ZOU1tmbklkXSgpO1xuICB9XG4gIFxuICAvKipcbiAgICogU2V0IHRoZSBwYXRoIHRvIGxvYWQgdGhlIHdvcmtlci4gRGVmYXVsdHMgdG8gXCIvbW9uZXJvLndvcmtlci5qc1wiIGluIHRoZSBicm93c2VyXG4gICAqIGFuZCBcIi4vTW9uZXJvV2ViV29ya2VyLmpzXCIgaW4gbm9kZS5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB3b3JrZXJEaXN0UGF0aCAtIHBhdGggdG8gbG9hZCB0aGUgd29ya2VyXG4gICAqL1xuICBzdGF0aWMgc2V0V29ya2VyRGlzdFBhdGgod29ya2VyRGlzdFBhdGgpIHtcbiAgICBsZXQgcGF0aCA9IExpYnJhcnlVdGlscy5wcmVmaXhXaW5kb3dzUGF0aCh3b3JrZXJEaXN0UGF0aCA/IHdvcmtlckRpc3RQYXRoIDogTGlicmFyeVV0aWxzLldPUktFUl9ESVNUX1BBVEhfREVGQVVMVCk7XG4gICAgaWYgKHBhdGggIT09IExpYnJhcnlVdGlscy5XT1JLRVJfRElTVF9QQVRIKSBkZWxldGUgTGlicmFyeVV0aWxzLldPUktFUjtcbiAgICBMaWJyYXJ5VXRpbHMuV09SS0VSX0RJU1RfUEFUSCA9IHBhdGg7XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSB3b3JrZXIgbG9hZGVyIGNsb3N1cmUgdG8gY3VzdG9taXplIHdvcmtlciBsb2FkaW5nLlxuICAgKiBUYWtlcyBwcmVjZWRlbmNlIG92ZXIgZGVmYXVsdCBsb2FkaW5nIG1lY2hhbmlzbXMuXG4gICAqXG4gICAqIENvdWxkIGJlIGFzIHNpbXBsZSBhcyBgKCkgPT4gbmV3IFdvcmtlcihuZXcgVVJMKFwibW9uZXJvLXRzL2Rpc3QvbW9uZXJvLndvcmtlci5qc1wiLCBpbXBvcnQubWV0YS51cmwpKTtgIGZvciBicm93c2Vycy5cbiAgICpcbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gbG9hZGVyIC0gbG9hZGVyIGZ1bmN0aW9uIHdoaWNoIGluc3RhbnRpYXRlcyBhIHdvcmtlclxuICAgKi9cbiAgc3RhdGljIHNldFdvcmtlckxvYWRlcihsb2FkZXI/OiAoKSA9PiBXb3JrZXIpOiB2b2lkIHtcbiAgICBMaWJyYXJ5VXRpbHMuV09SS0VSX0xPQURFUiA9IGxvYWRlcjtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgYSBzaW5nbGV0b24gaW5zdGFuY2Ugb2YgYSB3b3JrZXIgdG8gc2hhcmUuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtXb3JrZXJ9IGEgd29ya2VyIHRvIHNoYXJlIGFtb25nIHdhbGxldCBpbnN0YW5jZXNcbiAgICovXG4gIHN0YXRpYyBhc3luYyBnZXRXb3JrZXIoKSB7XG4gICAgXG4gICAgLy8gb25lIHRpbWUgaW5pdGlhbGl6YXRpb25cbiAgICBpZiAoIUxpYnJhcnlVdGlscy5XT1JLRVIpIHtcblxuICAgICAgLy8gdHJ5IHRvIGxvYWQgd29ya2VyIHdpdGggdXNlciBwcm92aWRlZCBjbG9zdXJlXG4gICAgICBpZiAoTGlicmFyeVV0aWxzLldPUktFUl9MT0FERVIpIHtcbiAgICAgICAgTGlicmFyeVV0aWxzLldPUktFUiA9IExpYnJhcnlVdGlscy5XT1JLRVJfTE9BREVSKCk7XG4gICAgICB9IGVsc2Uge1xuXG4gICAgICAgIC8vIG90aGVyd2lzZSB1c2Ugc3RhbmRhcmQgbG9hZGluZyBtZWNoYW5pc21zIGZvciBicm93c2VyIGFuZCBub2RlXG4gICAgICAgIGlmIChHZW5VdGlscy5pc0Jyb3dzZXIoKSkge1xuICAgICAgICAgIExpYnJhcnlVdGlscy5XT1JLRVIgPSBuZXcgV29ya2VyKExpYnJhcnlVdGlscy5XT1JLRVJfRElTVF9QQVRIKTtcbiAgICAgICAgfSBlbHNlIGlmIChHZW5VdGlscy5pc0Rlbm8oKSkge1xuICAgICAgICAgIExpYnJhcnlVdGlscy5XT1JLRVIgPSBuZXcgV29ya2VyKExpYnJhcnlVdGlscy5XT1JLRVJfRElTVF9QQVRILCB7IHR5cGU6IFwibW9kdWxlXCIgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgV29ya2VyID0gcmVxdWlyZShcIndlYi13b3JrZXJcIik7IC8vIGltcG9ydCB3ZWIgd29ya2VyIGlmIG5vZGVqc1xuICAgICAgICAgIExpYnJhcnlVdGlscy5XT1JLRVIgPSBuZXcgV29ya2VyKExpYnJhcnlVdGlscy5XT1JLRVJfRElTVF9QQVRIKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgTGlicmFyeVV0aWxzLldPUktFUl9PQkpFQ1RTID0ge307ICAvLyBzdG9yZSBwZXIgb2JqZWN0IHJ1bm5pbmcgaW4gdGhlIHdvcmtlclxuICAgICAgXG4gICAgICAvLyByZWNlaXZlIHdvcmtlciBlcnJvcnNcbiAgICAgIExpYnJhcnlVdGlscy5XT1JLRVIub25lcnJvciA9IGZ1bmN0aW9uKGVycikge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgcG9zdGluZyBtZXNzYWdlIHRvIG1vbmVyby53b3JrZXIuanM7IGlzIGl0IGJ1aWx0IGFuZCBjb3BpZWQgdG8gdGhlIGFwcCdzIHB1YmxpYyBvciBidWlsZCBkaXJlY3Rvcnk/XCIpO1xuICAgICAgICBjb25zb2xlLmxvZyhlcnIpO1xuICAgICAgfTtcbiAgICAgIFxuICAgICAgLy8gcmVjZWl2ZSB3b3JrZXIgbWVzc2FnZXNcbiAgICAgIExpYnJhcnlVdGlscy5XT1JLRVIub25tZXNzYWdlID0gZnVuY3Rpb24oZSkge1xuICAgICAgICBcbiAgICAgICAgLy8gbG9va3VwIG9iamVjdCBpZCwgY2FsbGJhY2sgZnVuY3Rpb24sIGFuZCB0aGlzIGFyZ1xuICAgICAgICBsZXQgdGhpc0FyZyA9IHVuZGVmaW5lZDtcbiAgICAgICAgbGV0IGNhbGxiYWNrRm4gPSBMaWJyYXJ5VXRpbHMuV09SS0VSX09CSkVDVFNbZS5kYXRhWzBdXS5jYWxsYmFja3NbZS5kYXRhWzFdXTsgLy8gbG9vayB1cCBieSBvYmplY3QgaWQgdGhlbiBieSBmdW5jdGlvbiBuYW1lXG4gICAgICAgIGlmIChjYWxsYmFja0ZuID09PSB1bmRlZmluZWQpIHRocm93IG5ldyBFcnJvcihcIk5vIHdvcmtlciBjYWxsYmFjayBmdW5jdGlvbiBkZWZpbmVkIGZvciBrZXkgJ1wiICsgZS5kYXRhWzFdICsgXCInXCIpO1xuICAgICAgICBpZiAoY2FsbGJhY2tGbiBpbnN0YW5jZW9mIEFycmF5KSB7ICAvLyB0aGlzIGFyZyBtYXkgYmUgc3RvcmVkIHdpdGggY2FsbGJhY2sgZnVuY3Rpb25cbiAgICAgICAgICB0aGlzQXJnID0gY2FsbGJhY2tGblsxXTtcbiAgICAgICAgICBjYWxsYmFja0ZuID0gY2FsbGJhY2tGblswXTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgLy8gaW52b2tlIGNhbGxiYWNrIGZ1bmN0aW9uIHdpdGggdGhpcyBhcmcgYW5kIGFyZ3VtZW50c1xuICAgICAgICBjYWxsYmFja0ZuLmFwcGx5KHRoaXNBcmcsIGUuZGF0YS5zbGljZSgyKSk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBMaWJyYXJ5VXRpbHMuV09SS0VSO1xuICB9XG5cbiAgc3RhdGljIGFkZFdvcmtlckNhbGxiYWNrKG9iamVjdElkLCBjYWxsYmFja0lkLCBjYWxsYmFja0FyZ3MpIHtcbiAgICBMaWJyYXJ5VXRpbHMuV09SS0VSX09CSkVDVFNbb2JqZWN0SWRdLmNhbGxiYWNrc1tjYWxsYmFja0lkXSA9IGNhbGxiYWNrQXJncztcbiAgfVxuXG4gIHN0YXRpYyByZW1vdmVXb3JrZXJDYWxsYmFjayhvYmplY3RJZCwgY2FsbGJhY2tJZCkge1xuICAgIGRlbGV0ZSBMaWJyYXJ5VXRpbHMuV09SS0VSX09CSkVDVFNbb2JqZWN0SWRdLmNhbGxiYWNrc1tjYWxsYmFja0lkXTtcbiAgfVxuXG4gIHN0YXRpYyByZW1vdmVXb3JrZXJPYmplY3Qob2JqZWN0SWQpIHtcbiAgICBkZWxldGUgTGlicmFyeVV0aWxzLldPUktFUl9PQkpFQ1RTW29iamVjdElkXTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFRlcm1pbmF0ZSBtb25lcm8tdHMncyBzaW5nbGV0b24gd29ya2VyLlxuICAgKi9cbiAgc3RhdGljIGFzeW5jIHRlcm1pbmF0ZVdvcmtlcigpIHtcbiAgICBpZiAoTGlicmFyeVV0aWxzLldPUktFUikge1xuICAgICAgTGlicmFyeVV0aWxzLldPUktFUi50ZXJtaW5hdGUoKTtcbiAgICAgIGRlbGV0ZSBMaWJyYXJ5VXRpbHMuV09SS0VSO1xuICAgICAgTGlicmFyeVV0aWxzLldPUktFUiA9IHVuZGVmaW5lZDtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogSW52b2tlIGEgd29ya2VyIGZ1bmN0aW9uIGFuZCBnZXQgdGhlIHJlc3VsdCB3aXRoIGVycm9yIGhhbmRsaW5nLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IG9iamVjdElkIGlkZW50aWZpZXMgdGhlIHdvcmtlciBvYmplY3QgdG8gaW52b2tlIChkZWZhdWx0IHJhbmRvbSBpZClcbiAgICogQHBhcmFtIHtzdHJpbmd9IGZuTmFtZSBpcyB0aGUgbmFtZSBvZiB0aGUgZnVuY3Rpb24gdG8gaW52b2tlXG4gICAqIEBwYXJhbSB7YW55W119IFthcmdzXSBhcmUgZnVuY3Rpb24gYXJndW1lbnRzIHRvIGludm9rZSB3aXRoXG4gICAqIEByZXR1cm4ge2FueX0gcmVzb2x2ZXMgd2l0aCByZXNwb25zZSBwYXlsb2FkIGZyb20gdGhlIHdvcmtlciBvciBhbiBlcnJvclxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGludm9rZVdvcmtlcihvYmplY3RJZCwgZm5OYW1lLCBhcmdzKSB7XG4gICAgYXNzZXJ0KGZuTmFtZS5sZW5ndGggPj0gMik7XG4gICAgbGV0IHdvcmtlciA9IGF3YWl0IExpYnJhcnlVdGlscy5nZXRXb3JrZXIoKTtcbiAgICBsZXQgcmFuZG9tT2JqZWN0ID0gb2JqZWN0SWQgPT09IHVuZGVmaW5lZDtcbiAgICBpZiAocmFuZG9tT2JqZWN0KSBvYmplY3RJZCA9IEdlblV0aWxzLmdldFVVSUQoKTtcbiAgICBpZiAoIUxpYnJhcnlVdGlscy5XT1JLRVJfT0JKRUNUU1tvYmplY3RJZF0pIExpYnJhcnlVdGlscy5XT1JLRVJfT0JKRUNUU1tvYmplY3RJZF0gPSB7Y2FsbGJhY2tzOiB7fX07XG4gICAgbGV0IGNhbGxiYWNrSWQgPSBHZW5VdGlscy5nZXRVVUlEKCk7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIExpYnJhcnlVdGlscy5XT1JLRVJfT0JKRUNUU1tvYmplY3RJZF0uY2FsbGJhY2tzW2NhbGxiYWNrSWRdID0gKHJlc3ApID0+IHsgIC8vIFRPRE86IHRoaXMgZGVmaW5lcyBmdW5jdGlvbiBvbmNlIHBlciBjYWxsYmFja1xuICAgICAgICAgIGRlbGV0ZSBMaWJyYXJ5VXRpbHMuV09SS0VSX09CSkVDVFNbb2JqZWN0SWRdLmNhbGxiYWNrc1tjYWxsYmFja0lkXTtcbiAgICAgICAgICBpZiAocmFuZG9tT2JqZWN0KSBkZWxldGUgTGlicmFyeVV0aWxzLldPUktFUl9PQkpFQ1RTW29iamVjdElkXTtcbiAgICAgICAgICByZXNwID8gKHJlc3AuZXJyb3IgPyByZWplY3QobmV3IEVycm9yKEpTT04uc3RyaW5naWZ5KHJlc3AuZXJyb3IpKSkgOiByZXNvbHZlKHJlc3AucmVzdWx0KSkgOiByZXNvbHZlKHVuZGVmaW5lZCk7XG4gICAgICAgIH07XG4gICAgICAgIHdvcmtlci5wb3N0TWVzc2FnZShbb2JqZWN0SWQsIGZuTmFtZSwgY2FsbGJhY2tJZF0uY29uY2F0KGFyZ3MgPT09IHVuZGVmaW5lZCA/IFtdIDogR2VuVXRpbHMubGlzdGlmeShhcmdzKSkpO1xuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICB0aHJvdyBMaWJyYXJ5VXRpbHMuZGVzZXJpYWxpemVFcnJvcihKU09OLnBhcnNlKGUubWVzc2FnZSkpO1xuICAgIH1cbiAgfVxuXG4gIHN0YXRpYyBzZXJpYWxpemVFcnJvcihlcnIpIHtcbiAgICBjb25zdCBzZXJpYWxpemVkRXJyOiBhbnkgPSB7IG5hbWU6IGVyci5uYW1lLCBtZXNzYWdlOiBlcnIubWVzc2FnZSwgY29kZTogZXJyLmNvZGUsIHN0YWNrOiBlcnIuc3RhY2sgfTtcbiAgICBpZiAoZXJyIGluc3RhbmNlb2YgTW9uZXJvRXJyb3IpIHNlcmlhbGl6ZWRFcnIudHlwZSA9IFwiTW9uZXJvRXJyb3JcIjtcbiAgICByZXR1cm4gc2VyaWFsaXplZEVycjtcbiAgfVxuXG4gIHByb3RlY3RlZCBzdGF0aWMgZGVzZXJpYWxpemVFcnJvcihzZXJpYWxpemVkRXJyKSB7XG4gICAgY29uc3QgZXJyID0gc2VyaWFsaXplZEVyci50eXBlID09PSBcIk1vbmVyb0Vycm9yXCIgPyBuZXcgTW9uZXJvRXJyb3Ioc2VyaWFsaXplZEVyci5tZXNzYWdlLCBzZXJpYWxpemVkRXJyLmNvZGUpIDogbmV3IEVycm9yKHNlcmlhbGl6ZWRFcnIubWVzc2FnZSk7XG4gICAgZXJyLm5hbWUgPSBzZXJpYWxpemVkRXJyLm5hbWU7XG4gICAgZXJyLnN0YWNrID0gZXJyLnN0YWNrICsgXCJcXG5Xb3JrZXIgZXJyb3I6IFwiICsgc2VyaWFsaXplZEVyci5zdGFjaztcbiAgICByZXR1cm4gZXJyO1xuICB9XG5cbiAgc3RhdGljIGFzeW5jIHF1ZXVlVGFzazxUPihhc3luY0ZuOiAoKSA9PiBQcm9taXNlPFQ+KTogUHJvbWlzZTxUPiB7XG4gICAgcmV0dXJuIExpYnJhcnlVdGlscy5NVVRFWC5zdWJtaXQoYXN5bmNGbik7XG4gIH1cblxuICBzdGF0aWMgYXN5bmMgZXhpc3RzKGZzOiBhbnksIHBhdGg6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBmcy5hY2Nlc3MocGF0aCk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBQUklWQVRFIEhFTFBFUlMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGluaXRXYXNtTW9kdWxlKHdhc21Nb2R1bGUpIHtcbiAgICB3YXNtTW9kdWxlLnRhc2tRdWV1ZSA9IG5ldyBUaHJlYWRQb29sKDEpO1xuICAgIHdhc21Nb2R1bGUucXVldWVUYXNrID0gYXN5bmMgZnVuY3Rpb24oYXN5bmNGbikgeyByZXR1cm4gd2FzbU1vZHVsZS50YXNrUXVldWUuc3VibWl0KGFzeW5jRm4pOyB9XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgcHJlZml4V2luZG93c1BhdGgocGF0aCkge1xuICAgIGlmICgvXltBLVpdOi8udGVzdChwYXRoKSAmJiBwYXRoLmluZGV4T2YoXCJmaWxlOi8vXCIpID09IC0xKSBwYXRoID0gXCJmaWxlOi8vXCIgKyBwYXRoOyAvLyBwcmVwZW5kIGUuZy4gQzogcGF0aHMgd2l0aCBmaWxlOi8vXG4gICAgcmV0dXJuIHBhdGg7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFNBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLFlBQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFHLFdBQUEsR0FBQUosc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFJLEtBQUEsR0FBQUwsc0JBQUEsQ0FBQUMsT0FBQTs7QUFFQTtBQUNBO0FBQ0E7QUFDZSxNQUFNSyxZQUFZLENBQUM7O0VBRWhDO0VBQ0EsT0FBT0MsU0FBUyxHQUFHLENBQUM7Ozs7OztFQU1wQixPQUFnQkMsS0FBSyxHQUFHLElBQUlDLG1CQUFVLENBQUMsQ0FBQyxDQUFDO0VBQ3pDLE9BQU9DLHdCQUF3QixHQUFHQyxpQkFBUSxDQUFDQyxTQUFTLENBQUMsQ0FBQyxHQUFHLG1CQUFtQixHQUFHLFlBQVc7O0lBRXhGO0lBQ0EsSUFBSUMsT0FBTyxHQUFHQyxhQUFJLENBQUNDLFNBQVMsQ0FBQ0MsU0FBUyxDQUFDO0lBQ3ZDLE1BQU1DLFVBQVUsR0FBR0gsYUFBSSxDQUFDSSxJQUFJLENBQUMsV0FBVyxFQUFFLE1BQU0sQ0FBQztJQUNqRCxJQUFJLENBQUNMLE9BQU8sQ0FBQ00sUUFBUSxDQUFDRixVQUFVLENBQUMsRUFBRUosT0FBTyxHQUFHQyxhQUFJLENBQUNJLElBQUksQ0FBQ0wsT0FBTyxFQUFFLHFDQUFxQyxDQUFDO0lBQ3RHQSxPQUFPLEdBQUdQLFlBQVksQ0FBQ2MsaUJBQWlCLENBQUNOLGFBQUksQ0FBQ0ksSUFBSSxDQUFDTCxPQUFPLEVBQUUsc0JBQXNCLENBQUMsQ0FBQztJQUNwRixJQUFJRixpQkFB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 \ No newline at end of file diff --git a/dist/src/main/ts/common/MoneroConnectionManager.d.ts b/dist/src/main/ts/common/MoneroConnectionManager.d.ts new file mode 100644 index 000000000..1085bdd16 --- /dev/null +++ b/dist/src/main/ts/common/MoneroConnectionManager.d.ts @@ -0,0 +1,277 @@ +import MoneroConnectionManagerListener from "./MoneroConnectionManagerListener"; +import MoneroRpcConnection from "./MoneroRpcConnection"; +/** + *

Manages a collection of prioritized connections to daemon or wallet RPC endpoints.

+ * + *

Example usage:

+ * + * + * // imports
+ * import { MoneroRpcConnection, MoneroConnectionManager, MoneroConnectionManagerListener } from "monero-ts";
+ *
+ * // create connection manager
+ * let connectionManager = new MoneroConnectionManager();
+ *
+ * // add managed connections with priorities
+ * await connectionManager.addConnection({uri: "http://localhost:38081", priority: 1}); // use localhost as first priority
+ * await connectionManager.addConnection({uri: "http://example.com"}); // default priority is prioritized last
+ *
+ * // set current connection
+ * await connectionManager.setConnection({uri: "http://foo.bar", username: "admin", password: "password"}); // connection is added if new
+ *
+ * // check connection status
+ * await connectionManager.checkConnection();
+ * console.log("Connection manager is connected: " + connectionManager.isConnected());
+ * console.log("Connection is online: " + connectionManager.getConnection().getIsOnline());
+ * console.log("Connection is authenticated: " + connectionManager.getConnection().getIsAuthenticated());
+ *
+ * // receive notifications of any changes to current connection
+ * connectionManager.addListener(new class extends MoneroConnectionManagerListener {
+ *    async onConnectionChanged(connection) {
+ *      console.log("Connection changed to: " + connection);
+ *    }
+ * });
+ *
+ * // start polling for best connection every 10 seconds and automatically switch
+ * connectionManager.startPolling(10000);
+ *
+ * // automatically switch to best available connection if disconnected
+ * connectionManager.setAutoSwitch(true);
+ *
+ * // get best available connection in order of priority then response time
+ * let bestConnection = await connectionManager.getBestAvailableConnection();
+ *
+ * // check status of all connections
+ * await connectionManager.checkConnections();
+ *
+ * // get connections in order of current connection, online status from last check, priority, and name
+ * let connections = connectionManager.getConnections();
+ *
+ * // clear connection manager
+ * connectionManager.clear(); + *
+ */ +export default class MoneroConnectionManager { + static DEFAULT_TIMEOUT: number; + static DEFAULT_POLL_PERIOD: number; + static DEFAULT_AUTO_SWITCH: boolean; + static MIN_BETTER_RESPONSES: number; + protected proxyToWorker: any; + protected timeoutMs: any; + protected autoSwitch: any; + protected connections: any; + protected responseTimes: any; + protected listeners: any; + protected currentConnection: any; + protected poller: any; + /** + * Specify behavior when polling. + * + * One of PRIORITIZED (poll connections in order of priority until connected; default), CURRENT (poll current connection), or ALL (poll all connections). + */ + static PollType: { + PRIORITIZED: number; + CURRENT: number; + ALL: number; + }; + /** + * Construct a connection manager. + * + * @param {boolean} [proxyToWorker] - configure all connections to proxy to worker (default true) + */ + constructor(proxyToWorker?: boolean); + /** + * Add a listener to receive notifications when the connection changes. + * + * @param {MoneroConnectionManagerListener} listener - the listener to add + * @return {MoneroConnectionManager} this connection manager for chaining + */ + addListener(listener: MoneroConnectionManagerListener): MoneroConnectionManager; + /** + * Remove a listener. + * + * @param {MoneroConnectionManagerListener} listener - the listener to remove + * @return {MoneroConnectionManager} this connection manager for chaining + */ + removeListener(listener: MoneroConnectionManagerListener): MoneroConnectionManager; + /** + * Remove all listeners. + * + * @return {MoneroConnectionManager} this connection manager for chaining + */ + removeListeners(): MoneroConnectionManager; + /** + * Get all listeners. + * + * @return {MoneroConnectionManagerListener[]} all listeners + */ + getListeners(): MoneroConnectionManagerListener[]; + /** + * Add a connection. The connection may have an elevated priority for this manager to use. + * + * @param {string|Partial} uriOrConnection - uri or connection to add + * @return {Promise} this connection manager for chaining + */ + addConnection(uriOrConnection: string | Partial): Promise; + /** + * Remove a connection. + * + * @param {string} uri - of the the connection to remove + * @return {Promise} this connection manager for chaining + */ + removeConnection(uri: string): Promise; + /** + * Set the current connection. + * Provide a URI to select an existing connection without updating its credentials. + * Provide a MoneroRpcConnection to add new connection or replace existing connection with the same URI. + * Notify if current connection changes. + * Does not check the connection. + * + * @param {string|Partial} [uriOrConnection] - is the uri of the connection or the connection to make current (default undefined for no current connection) + * @return {Promise} this connection manager for chaining + */ + setConnection(uriOrConnection?: string | Partial): Promise; + /** + * Get the current connection. + * + * @return {MoneroRpcConnection} the current connection or undefined if no connection set + */ + getConnection(): MoneroRpcConnection; + /** + * Indicates if this manager has a connection with the given URI. + * + * @param {string} uri URI of the connection to check + * @return {boolean} true if this manager has a connection with the given URI, false otherwise + */ + hasConnection(uri: string): boolean; + /** + * Get a connection by URI. + * + * @param {string} uri is the URI of the connection to get + * @return {MoneroRpcConnection} the connection with the URI or undefined if no connection with the URI exists + */ + getConnectionByUri(uri: string): MoneroRpcConnection; + /** + * Get all connections in order of current connection (if applicable), online status, priority, and name. + * + * @return {MoneroRpcConnection[]} the list of sorted connections + */ + getConnections(): MoneroRpcConnection[]; + /** + * Indicates if the connection manager is connected to a node. + * + * @return {boolean|undefined} true if the current connection is set, online, and not unauthenticated, undefined if unknown, false otherwise + */ + isConnected(): boolean | undefined; + /** + * Start polling connections. + * + * @param {number} [periodMs] poll period in milliseconds (default 20s) + * @param {boolean} [autoSwitch] specifies to automatically switch to the best connection (default true unless changed) + * @param {number} [timeoutMs] specifies the timeout to poll a single connection (default 5s unless changed) + * @param {number} [pollType] one of PRIORITIZED (poll connections in order of priority until connected; default), CURRENT (poll current connection), or ALL (poll all connections) + * @param {MoneroRpcConnection[]} [excludedConnections] connections excluded from being polled + * @return {MoneroConnectionManager} this connection manager for chaining + */ + startPolling(periodMs?: number, autoSwitch?: boolean, timeoutMs?: number, pollType?: number, excludedConnections?: MoneroRpcConnection[]): MoneroConnectionManager; + /** + * Stop polling connections. + * + * @return {MoneroConnectionManager} this connection manager for chaining + */ + stopPolling(): MoneroConnectionManager; + /** + * Check the current connection. If disconnected and auto switch enabled, switches to best available connection. + * + * @return {Promise} this connection manager for chaining + */ + checkConnection(): Promise; + /** + * Check all managed connections. + * + * @return {Promise} this connection manager for chaining + */ + checkConnections(): Promise; + /** + * Check all managed connections, returning a promise for each connection check. + * Does not auto switch if disconnected. + * + * @return {Promise[]} a promise for each connection in the order of getConnections(). + */ + checkConnectionPromises(): Promise[]; + /** + * Get the best available connection in order of priority then response time. + * + * @param {MoneroRpcConnection[]} [excludedConnections] - connections to be excluded from consideration (optional) + * @return {Promise} the best available connection in order of priority then response time, undefined if no connections available + */ + getBestAvailableConnection(excludedConnections?: MoneroRpcConnection[]): Promise; + /** + * Automatically switch to the best available connection as connections are polled, based on priority, response time, and consistency. + * + * @param {boolean} autoSwitch specifies if the connection should auto switch to a better connection + * @return {MoneroConnectionManager} this connection manager for chaining + */ + setAutoSwitch(autoSwitch: boolean): MoneroConnectionManager; + /** + * Get if auto switch is enabled or disabled. + * + * @return {boolean} true if auto switch enabled, false otherwise + */ + getAutoSwitch(): boolean; + /** + * Set the maximum request time before its connection is considered offline. + * + * @param {number} timeoutMs - the timeout before the connection is considered offline + * @return {MoneroConnectionManager} this connection manager for chaining + */ + setTimeout(timeoutMs: number): MoneroConnectionManager; + /** + * Get the request timeout. + * + * @return {number} the request timeout before a connection is considered offline + */ + getTimeout(): number; + /** + * Collect connectable peers of the managed connections. + * + * @return {Promise} connectable peers + */ + getPeerConnections(): Promise; + /** + * Disconnect from the current connection. + * + * @return {Promise} this connection manager for chaining + */ + disconnect(): Promise; + /** + * Remove all connections. + * + * @return {Promise} this connection manager for chaining + */ + clear(): Promise; + /** + * Reset to default state. + * + * @return {MoneroConnectionManager} this connection manager for chaining + */ + reset(): MoneroConnectionManager; + protected onConnectionChanged(connection: any): Promise; + protected getConnectionsInAscendingPriority(): any[]; + protected compareConnections(c1: any, c2: any): any; + protected comparePriorities(p1: any, p2: any): number; + protected startPollingConnection(periodMs: any): this; + protected startPollingConnections(periodMs: any): this; + protected startPollingPrioritizedConnections(periodMs: any, excludedConnections: any): this; + checkPrioritizedConnections(excludedConnections: any): Promise; + protected checkConnectionsAux(connections: any, excludedConnections?: any): Promise; + protected processResponses(responses: any): Promise; + protected updateBestConnectionInPriority(): Promise; + /** + * Get the best connection from the given responses. + * + * @param {MoneroRpcConnection[]} responses connection responses to update from + * @return {MoneroRpcConnection} the best response among the given responses or undefined if none are best + */ + protected getBestConnectionFromPrioritizedResponses(responses: any): Promise; +} diff --git a/dist/src/main/ts/common/MoneroConnectionManager.js b/dist/src/main/ts/common/MoneroConnectionManager.js new file mode 100644 index 000000000..702bf8cb8 --- /dev/null +++ b/dist/src/main/ts/common/MoneroConnectionManager.js @@ -0,0 +1,681 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _GenUtils = _interopRequireDefault(require("./GenUtils")); +var _TaskLooper = _interopRequireDefault(require("./TaskLooper")); +var _ThreadPool = _interopRequireDefault(require("./ThreadPool")); + +var _MoneroError = _interopRequireDefault(require("./MoneroError")); +var _MoneroRpcConnection = _interopRequireDefault(require("./MoneroRpcConnection")); + +/** + *

Manages a collection of prioritized connections to daemon or wallet RPC endpoints.

+ * + *

Example usage:

+ * + * + * // imports
+ * import { MoneroRpcConnection, MoneroConnectionManager, MoneroConnectionManagerListener } from "monero-ts";
+ *
+ * // create connection manager
+ * let connectionManager = new MoneroConnectionManager();
+ *
+ * // add managed connections with priorities
+ * await connectionManager.addConnection({uri: "http://localhost:38081", priority: 1}); // use localhost as first priority
+ * await connectionManager.addConnection({uri: "http://example.com"}); // default priority is prioritized last
+ *
+ * // set current connection
+ * await connectionManager.setConnection({uri: "http://foo.bar", username: "admin", password: "password"}); // connection is added if new
+ *
+ * // check connection status
+ * await connectionManager.checkConnection();
+ * console.log("Connection manager is connected: " + connectionManager.isConnected());
+ * console.log("Connection is online: " + connectionManager.getConnection().getIsOnline());
+ * console.log("Connection is authenticated: " + connectionManager.getConnection().getIsAuthenticated());
+ *
+ * // receive notifications of any changes to current connection
+ * connectionManager.addListener(new class extends MoneroConnectionManagerListener {
+ *    async onConnectionChanged(connection) {
+ *      console.log("Connection changed to: " + connection);
+ *    }
+ * });
+ *
+ * // start polling for best connection every 10 seconds and automatically switch
+ * connectionManager.startPolling(10000);
+ *
+ * // automatically switch to best available connection if disconnected
+ * connectionManager.setAutoSwitch(true);
+ *
+ * // get best available connection in order of priority then response time
+ * let bestConnection = await connectionManager.getBestAvailableConnection();
+ *
+ * // check status of all connections
+ * await connectionManager.checkConnections();
+ *
+ * // get connections in order of current connection, online status from last check, priority, and name
+ * let connections = connectionManager.getConnections();
+ *
+ * // clear connection manager
+ * connectionManager.clear(); + *
+ */ +class MoneroConnectionManager { + + // static variables + static DEFAULT_TIMEOUT = 5000; + static DEFAULT_POLL_PERIOD = 20000; + static DEFAULT_AUTO_SWITCH = true; + static MIN_BETTER_RESPONSES = 3; + + // instance variables + + + + + + + + + + /** + * Specify behavior when polling. + * + * One of PRIORITIZED (poll connections in order of priority until connected; default), CURRENT (poll current connection), or ALL (poll all connections). + */ + static PollType = { + PRIORITIZED: 0, + CURRENT: 1, + ALL: 2 + }; + + /** + * Construct a connection manager. + * + * @param {boolean} [proxyToWorker] - configure all connections to proxy to worker (default true) + */ + constructor(proxyToWorker = true) { + this.proxyToWorker = proxyToWorker !== false; + this.timeoutMs = MoneroConnectionManager.DEFAULT_TIMEOUT; + this.autoSwitch = MoneroConnectionManager.DEFAULT_AUTO_SWITCH; + this.connections = []; + this.responseTimes = new Map(); + this.listeners = []; + } + + /** + * Add a listener to receive notifications when the connection changes. + * + * @param {MoneroConnectionManagerListener} listener - the listener to add + * @return {MoneroConnectionManager} this connection manager for chaining + */ + addListener(listener) { + this.listeners.push(listener); + return this; + } + + /** + * Remove a listener. + * + * @param {MoneroConnectionManagerListener} listener - the listener to remove + * @return {MoneroConnectionManager} this connection manager for chaining + */ + removeListener(listener) { + if (!_GenUtils.default.remove(this.listeners, listener)) throw new _MoneroError.default("Monero connection manager does not contain listener to remove"); + return this; + } + + /** + * Remove all listeners. + * + * @return {MoneroConnectionManager} this connection manager for chaining + */ + removeListeners() { + this.listeners.splice(0, this.listeners.length); + return this; + } + + /** + * Get all listeners. + * + * @return {MoneroConnectionManagerListener[]} all listeners + */ + getListeners() { + return this.listeners; + } + + /** + * Add a connection. The connection may have an elevated priority for this manager to use. + * + * @param {string|Partial} uriOrConnection - uri or connection to add + * @return {Promise} this connection manager for chaining + */ + async addConnection(uriOrConnection) { + let connection = uriOrConnection instanceof _MoneroRpcConnection.default ? uriOrConnection : new _MoneroRpcConnection.default(uriOrConnection); + for (let aConnection of this.connections) { + if (aConnection.getUri() === connection.getUri()) throw new _MoneroError.default("Connection URI already exists"); + } + if (this.proxyToWorker !== undefined) connection.setProxyToWorker(this.proxyToWorker); + this.connections.push(connection); + return this; + } + + /** + * Remove a connection. + * + * @param {string} uri - of the the connection to remove + * @return {Promise} this connection manager for chaining + */ + async removeConnection(uri) { + let connection = this.getConnectionByUri(uri); + if (!connection) throw new _MoneroError.default("No connection exists with URI: " + uri); + _GenUtils.default.remove(this.connections, connection); + this.responseTimes.delete(connection.getUri()); + if (connection === this.currentConnection) { + this.currentConnection = undefined; + await this.onConnectionChanged(this.currentConnection); + } + return this; + } + + /** + * Set the current connection. + * Provide a URI to select an existing connection without updating its credentials. + * Provide a MoneroRpcConnection to add new connection or replace existing connection with the same URI. + * Notify if current connection changes. + * Does not check the connection. + * + * @param {string|Partial} [uriOrConnection] - is the uri of the connection or the connection to make current (default undefined for no current connection) + * @return {Promise} this connection manager for chaining + */ + async setConnection(uriOrConnection) { + + // handle uri + if (uriOrConnection && typeof uriOrConnection === "string") { + let connection = this.getConnectionByUri(uriOrConnection); + return this.setConnection(connection === undefined ? new _MoneroRpcConnection.default(uriOrConnection) : connection); + } + + // handle connection + let connection = uriOrConnection; + if (this.currentConnection === connection) return this; + + // check if setting undefined connection + if (!connection) { + this.currentConnection = undefined; + await this.onConnectionChanged(undefined); + return this; + } + + // validate connection + if (!(connection instanceof _MoneroRpcConnection.default)) connection = new _MoneroRpcConnection.default(connection); + if (!connection.getUri()) throw new _MoneroError.default("Connection is missing URI"); + + // add or replace connection + let prevConnection = this.getConnectionByUri(connection.getUri()); + if (prevConnection) _GenUtils.default.remove(this.connections, prevConnection); + await this.addConnection(connection); + this.currentConnection = connection; + await this.onConnectionChanged(this.currentConnection); + + return this; + } + + /** + * Get the current connection. + * + * @return {MoneroRpcConnection} the current connection or undefined if no connection set + */ + getConnection() { + return this.currentConnection; + } + + /** + * Indicates if this manager has a connection with the given URI. + * + * @param {string} uri URI of the connection to check + * @return {boolean} true if this manager has a connection with the given URI, false otherwise + */ + hasConnection(uri) { + return this.getConnectionByUri(uri) !== undefined; + } + + /** + * Get a connection by URI. + * + * @param {string} uri is the URI of the connection to get + * @return {MoneroRpcConnection} the connection with the URI or undefined if no connection with the URI exists + */ + getConnectionByUri(uri) { + for (let connection of this.connections) if (connection.getUri() === uri) return connection; + return undefined; + } + + /** + * Get all connections in order of current connection (if applicable), online status, priority, and name. + * + * @return {MoneroRpcConnection[]} the list of sorted connections + */ + getConnections() { + let sortedConnections = _GenUtils.default.copyArray(this.connections); + sortedConnections.sort(this.compareConnections.bind(this)); + return sortedConnections; + } + + /** + * Indicates if the connection manager is connected to a node. + * + * @return {boolean|undefined} true if the current connection is set, online, and not unauthenticated, undefined if unknown, false otherwise + */ + isConnected() { + if (!this.currentConnection) return false; + return this.currentConnection.isConnected(); + } + + /** + * Start polling connections. + * + * @param {number} [periodMs] poll period in milliseconds (default 20s) + * @param {boolean} [autoSwitch] specifies to automatically switch to the best connection (default true unless changed) + * @param {number} [timeoutMs] specifies the timeout to poll a single connection (default 5s unless changed) + * @param {number} [pollType] one of PRIORITIZED (poll connections in order of priority until connected; default), CURRENT (poll current connection), or ALL (poll all connections) + * @param {MoneroRpcConnection[]} [excludedConnections] connections excluded from being polled + * @return {MoneroConnectionManager} this connection manager for chaining + */ + startPolling(periodMs, autoSwitch, timeoutMs, pollType, excludedConnections) { + + // apply defaults + if (periodMs == undefined) periodMs = MoneroConnectionManager.DEFAULT_POLL_PERIOD; + if (autoSwitch !== undefined) this.setAutoSwitch(autoSwitch); + if (timeoutMs !== undefined) this.setTimeout(timeoutMs); + if (pollType === undefined) pollType = MoneroConnectionManager.PollType.PRIORITIZED; + + // stop polling + this.stopPolling(); + + // start polling + switch (pollType) { + case MoneroConnectionManager.PollType.CURRENT: + this.startPollingConnection(periodMs); + break; + case MoneroConnectionManager.PollType.ALL: + this.startPollingConnections(periodMs); + break; + case MoneroConnectionManager.PollType.PRIORITIZED: + default: + this.startPollingPrioritizedConnections(periodMs, excludedConnections); + } + return this; + } + + /** + * Stop polling connections. + * + * @return {MoneroConnectionManager} this connection manager for chaining + */ + stopPolling() { + if (this.poller) this.poller.stop(); + this.poller = undefined; + return this; + } + + /** + * Check the current connection. If disconnected and auto switch enabled, switches to best available connection. + * + * @return {Promise} this connection manager for chaining + */ + async checkConnection() { + let connectionChanged = false; + let connection = this.getConnection(); + if (connection) { + if (await connection.checkConnection(this.timeoutMs)) connectionChanged = true; + await this.processResponses([connection]); + } + if (this.autoSwitch && !this.isConnected()) { + let bestConnection = await this.getBestAvailableConnection([connection]); + if (bestConnection) { + await this.setConnection(bestConnection); + return this; + } + } + if (connectionChanged) await this.onConnectionChanged(connection); + return this; + } + + /** + * Check all managed connections. + * + * @return {Promise} this connection manager for chaining + */ + async checkConnections() { + await this.checkConnectionsAux(this.getConnections()); + return this; + } + + /** + * Check all managed connections, returning a promise for each connection check. + * Does not auto switch if disconnected. + * + * @return {Promise[]} a promise for each connection in the order of getConnections(). + */ + checkConnectionPromises() { + let checkPromises = []; + let pool = new _ThreadPool.default(this.connections.length); + for (let connection of this.getConnections()) { + checkPromises.push(pool.submit(async () => { + try { + if ((await connection.checkConnection(this.timeoutMs)) && connection === this.currentConnection) await this.onConnectionChanged(connection); + } catch (err) { + + // ignore error + }})); + } + Promise.all(checkPromises); + return checkPromises; + } + + /** + * Get the best available connection in order of priority then response time. + * + * @param {MoneroRpcConnection[]} [excludedConnections] - connections to be excluded from consideration (optional) + * @return {Promise} the best available connection in order of priority then response time, undefined if no connections available + */ + async getBestAvailableConnection(excludedConnections) { + + // try connections within each ascending priority + for (let prioritizedConnections of this.getConnectionsInAscendingPriority()) { + try { + + // create promises to check connections + let that = this; + let checkPromises = []; + for (let connection of prioritizedConnections) { + if (excludedConnections && _GenUtils.default.arrayContains(excludedConnections, connection)) continue; + checkPromises.push(new Promise(async function (resolve, reject) { + await connection.checkConnection(that.timeoutMs); + if (connection.isConnected()) resolve(connection);else + reject(); + })); + } + + // use first available connection + let firstAvailable = await Promise.any(checkPromises); + if (firstAvailable) return firstAvailable; + } catch (err) { + if (!(err instanceof AggregateError)) throw new _MoneroError.default(err); + } + } + return undefined; + } + + /** + * Automatically switch to the best available connection as connections are polled, based on priority, response time, and consistency. + * + * @param {boolean} autoSwitch specifies if the connection should auto switch to a better connection + * @return {MoneroConnectionManager} this connection manager for chaining + */ + setAutoSwitch(autoSwitch) { + this.autoSwitch = autoSwitch; + return this; + } + + /** + * Get if auto switch is enabled or disabled. + * + * @return {boolean} true if auto switch enabled, false otherwise + */ + getAutoSwitch() { + return this.autoSwitch; + } + + /** + * Set the maximum request time before its connection is considered offline. + * + * @param {number} timeoutMs - the timeout before the connection is considered offline + * @return {MoneroConnectionManager} this connection manager for chaining + */ + setTimeout(timeoutMs) { + this.timeoutMs = timeoutMs; + return this; + } + + /** + * Get the request timeout. + * + * @return {number} the request timeout before a connection is considered offline + */ + getTimeout() { + return this.timeoutMs; + } + + /** + * Collect connectable peers of the managed connections. + * + * @return {Promise} connectable peers + */ + async getPeerConnections() { + throw new _MoneroError.default("Not implemented"); + } + + /** + * Disconnect from the current connection. + * + * @return {Promise} this connection manager for chaining + */ + async disconnect() { + await this.setConnection(undefined); + return this; + } + + /** + * Remove all connections. + * + * @return {Promise} this connection manager for chaining + */ + async clear() { + this.connections.splice(0, this.connections.length); + if (this.currentConnection) { + this.currentConnection = undefined; + await this.onConnectionChanged(undefined); + } + return this; + } + + /** + * Reset to default state. + * + * @return {MoneroConnectionManager} this connection manager for chaining + */ + reset() { + this.removeListeners(); + this.stopPolling(); + this.clear(); + this.timeoutMs = MoneroConnectionManager.DEFAULT_TIMEOUT; + this.autoSwitch = MoneroConnectionManager.DEFAULT_AUTO_SWITCH; + return this; + } + + // ------------------------------ PRIVATE HELPERS --------------------------- + + async onConnectionChanged(connection) { + let promises = []; + for (let listener of this.listeners) promises.push(listener.onConnectionChanged(connection)); + return Promise.all(promises); + } + + getConnectionsInAscendingPriority() { + let connectionPriorities = new Map(); + for (let connection of this.connections) { + if (!connectionPriorities.has(connection.getPriority())) connectionPriorities.set(connection.getPriority(), []); + connectionPriorities.get(connection.getPriority()).push(connection); + } + let ascendingPriorities = new Map([...connectionPriorities].sort((a, b) => parseInt(a[0]) - parseInt(b[0]))); // create map in ascending order + let ascendingPrioritiesList = []; + for (let priorityConnections of ascendingPriorities.values()) ascendingPrioritiesList.push(priorityConnections); + if (connectionPriorities.has(0)) ascendingPrioritiesList.push(ascendingPrioritiesList.splice(0, 1)[0]); // move priority 0 to end + return ascendingPrioritiesList; + } + + compareConnections(c1, c2) { + + // current connection is first + if (c1 === this.currentConnection) return -1; + if (c2 === this.currentConnection) return 1; + + // order by availability then priority then by name + if (c1.getIsOnline() === c2.getIsOnline()) { + if (c1.getPriority() === c2.getPriority()) return c1.getUri().localeCompare(c2.getUri()); + return this.comparePriorities(c1.getPriority(), c2.getPriority()) * -1; // order by priority in descending order + } else { + if (c1.getIsOnline()) return -1;else + if (c2.getIsOnline()) return 1;else + if (c1.getIsOnline() === undefined) return -1;else + return 1; // c1 is offline + } + } + + comparePriorities(p1, p2) { + if (p1 == p2) return 0; + if (p1 == 0) return -1; + if (p2 == 0) return 1; + return p2 - p1; + } + + startPollingConnection(periodMs) { + this.poller = new _TaskLooper.default(async () => { + try {await this.checkConnection();} + catch (err) {console.log(err);} + }); + this.poller.start(periodMs); + return this; + } + + startPollingConnections(periodMs) { + this.poller = new _TaskLooper.default(async () => { + try {await this.checkConnections();} + catch (err) {console.log(err);} + }); + this.poller.start(periodMs); + return this; + } + + startPollingPrioritizedConnections(periodMs, excludedConnections) { + this.poller = new _TaskLooper.default(async () => { + try {await this.checkPrioritizedConnections(excludedConnections);} + catch (err) {console.log(err);} + }); + this.poller.start(periodMs); + return this; + } + + async checkPrioritizedConnections(excludedConnections) { + for (let prioritizedConnections of this.getConnectionsInAscendingPriority()) { + let hasConnection = await this.checkConnectionsAux(prioritizedConnections, excludedConnections); + if (hasConnection) return; + } + } + + async checkConnectionsAux(connections, excludedConnections) { + try { + + // check connections in parallel + let that = this; + let checkPromises = []; + let hasConnection = false; + for (let connection of connections) { + if (excludedConnections && _GenUtils.default.arrayContains(excludedConnections, connection)) continue; + checkPromises.push(new Promise(async function (resolve, reject) { + try { + let change = await connection.checkConnection(that.timeoutMs); + if (change && connection === that.getConnection()) await that.onConnectionChanged(connection); + if (connection.isConnected() && !hasConnection) { + hasConnection = true; + if (!that.isConnected() && that.autoSwitch) await that.setConnection(connection); // set first available connection if disconnected + } + resolve(undefined); + } catch (err) { + reject(err); + } + })); + } + await Promise.all(checkPromises); + + // process responses + await this.processResponses(connections); + return hasConnection; + } catch (err) { + throw new _MoneroError.default(err); + } + } + + async processResponses(responses) { + + // add new connections + for (let connection of responses) { + if (!this.responseTimes.has(connection.getUri())) this.responseTimes.set(connection.getUri(), []); + } + + // insert response times or undefined + this.responseTimes.forEach((times, connection) => { + times.unshift(_GenUtils.default.arrayContains(responses, connection) ? connection.getResponseTime() : undefined); + + // remove old response times + if (times.length > MoneroConnectionManager.MIN_BETTER_RESPONSES) times.pop(); + }); + + // update best connection based on responses and priority + return await this.updateBestConnectionInPriority(); + } + + async updateBestConnectionInPriority() { + if (!this.autoSwitch) return undefined; + for (let prioritizedConnections of this.getConnectionsInAscendingPriority()) { + let bestConnectionFromResponses = await this.getBestConnectionFromPrioritizedResponses(prioritizedConnections); + if (bestConnectionFromResponses) { + await this.setConnection(bestConnectionFromResponses); + return bestConnectionFromResponses; + } + } + return undefined; + } + + /** + * Get the best connection from the given responses. + * + * @param {MoneroRpcConnection[]} responses connection responses to update from + * @return {MoneroRpcConnection} the best response among the given responses or undefined if none are best + */ + async getBestConnectionFromPrioritizedResponses(responses) { + + // get best response + let bestResponse = undefined; + for (let connection of responses) { + if (connection.isConnected() === true && (!bestResponse || connection.getResponseTime() < bestResponse.getResponseTime())) bestResponse = connection; + } + + // no update if no responses + if (!bestResponse) return undefined; + + // use best response if disconnected + let bestConnection = await this.getConnection(); + if (!bestConnection || bestConnection.isConnected() !== true) return bestResponse; + + // use best response if different priority (assumes being called in descending priority) + if (this.comparePriorities(bestResponse.getPriority(), bestConnection.getPriority()) !== 0) return bestResponse; + + // keep best connection if not enough data + if (!this.responseTimes.has(bestConnection.getUri())) return bestConnection; + + // check if connection is consistently better + for (let connection of responses) { + if (connection === bestConnection) continue; + if (!this.responseTimes.has(connection.getUri()) || this.responseTimes.get(connection.getUri()).length < MoneroConnectionManager.MIN_BETTER_RESPONSES) continue; + let better = true; + for (let i = 0; i < MoneroConnectionManager.MIN_BETTER_RESPONSES; i++) { + if (this.responseTimes.get(connection.getUri())[i] === undefined || this.responseTimes.get(bestConnection.getUri())[i] || this.responseTimes.get(connection.getUri())[i] > this.responseTimes.get(bestConnection.getUri())[i]) { + better = false; + break; + } + } + if (better) bestConnection = connection; + } + return bestConnection; + } +}exports.default = MoneroConnectionManager; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfR2VuVXRpbHMiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9UYXNrTG9vcGVyIiwiX1RocmVhZFBvb2wiLCJfTW9uZXJvRXJyb3IiLCJfTW9uZXJvUnBjQ29ubmVjdGlvbiIsIk1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyIiwiREVGQVVMVF9USU1FT1VUIiwiREVGQVVMVF9QT0xMX1BFUklPRCIsIkRFRkFVTFRfQVVUT19TV0lUQ0giLCJNSU5fQkVUVEVSX1JFU1BPTlNFUyIsIlBvbGxUeXBlIiwiUFJJT1JJVElaRUQiLCJDVVJSRU5UIiwiQUxMIiwiY29uc3RydWN0b3IiLCJwcm94eVRvV29ya2VyIiwidGltZW91dE1zIiwiYXV0b1N3aXRjaCIsImNvbm5lY3Rpb25zIiwicmVzcG9uc2VUaW1lcyIsIk1hcCIsImxpc3RlbmVycyIsImFkZExpc3RlbmVyIiwibGlzdGVuZXIiLCJwdXNoIiwicmVtb3ZlTGlzdGVuZXIiLCJHZW5VdGlscyIsInJlbW92ZSIsIk1vbmVyb0Vycm9yIiwicmVtb3ZlTGlzdGVuZXJzIiwic3BsaWNlIiwibGVuZ3RoIiwiZ2V0TGlzdGVuZXJzIiwiYWRkQ29ubmVjdGlvbiIsInVyaU9yQ29ubmVjdGlvbiIsImNvbm5lY3Rpb24iLCJNb25lcm9ScGNDb25uZWN0aW9uIiwiYUNvbm5lY3Rpb24iLCJnZXRVcmkiLCJ1bmRlZmluZWQiLCJzZXRQcm94eVRvV29ya2VyIiwicmVtb3ZlQ29ubmVjdGlvbiIsInVyaSIsImdldENvbm5lY3Rpb25CeVVyaSIsImRlbGV0ZSIsImN1cnJlbnRDb25uZWN0aW9uIiwib25Db25uZWN0aW9uQ2hhbmdlZCIsInNldENvbm5lY3Rpb24iLCJwcmV2Q29ubmVjdGlvbiIsImdldENvbm5lY3Rpb24iLCJoYXNDb25uZWN0aW9uIiwiZ2V0Q29ubmVjdGlvbnMiLCJzb3J0ZWRDb25uZWN0aW9ucyIsImNvcHlBcnJheSIsInNvcnQiLCJjb21wYXJlQ29ubmVjdGlvbnMiLCJiaW5kIiwiaXNDb25uZWN0ZWQiLCJzdGFydFBvbGxpbmciLCJwZXJpb2RNcyIsInBvbGxUeXBlIiwiZXhjbHVkZWRDb25uZWN0aW9ucyIsInNldEF1dG9Td2l0Y2giLCJzZXRUaW1lb3V0Iiwic3RvcFBvbGxpbmciLCJzdGFydFBvbGxpbmdDb25uZWN0aW9uIiwic3RhcnRQb2xsaW5nQ29ubmVjdGlvbnMiLCJzdGFydFBvbGxpbmdQcmlvcml0aXplZENvbm5lY3Rpb25zIiwicG9sbGVyIiwic3RvcCIsImNoZWNrQ29ubmVjdGlvbiIsImNvbm5lY3Rpb25DaGFuZ2VkIiwicHJvY2Vzc1Jlc3BvbnNlcyIsImJlc3RDb25uZWN0aW9uIiwiZ2V0QmVzdEF2YWlsYWJsZUNvbm5lY3Rpb24iLCJjaGVja0Nvbm5lY3Rpb25zIiwiY2hlY2tDb25uZWN0aW9uc0F1eCIsImNoZWNrQ29ubmVjdGlvblByb21pc2VzIiwiY2hlY2tQcm9taXNlcyIsInBvb2wiLCJUaHJlYWRQb29sIiwic3VibWl0IiwiZXJyIiwiUHJvbWlzZSIsImFsbCIsInByaW9yaXRpemVkQ29ubmVjdGlvbnMiLCJnZXRDb25uZWN0aW9uc0luQXNjZW5kaW5nUHJpb3JpdHkiLCJ0aGF0IiwiYXJyYXlDb250YWlucyIsInJlc29sdmUiLCJyZWplY3QiLCJmaXJzdEF2YWlsYWJsZSIsImFueSIsIkFnZ3JlZ2F0ZUVycm9yIiwiZ2V0QXV0b1N3aXRjaCIsImdldFRpbWVvdXQiLCJnZXRQZWVyQ29ubmVjdGlvbnMiLCJkaXNjb25uZWN0IiwiY2xlYXIiLCJyZXNldCIsInByb21pc2VzIiwiY29ubmVjdGlvblByaW9yaXRpZXMiLCJoYXMiLCJnZXRQcmlvcml0eSIsInNldCIsImdldCIsImFzY2VuZGluZ1ByaW9yaXRpZXMiLCJhIiwiYiIsInBhcnNlSW50IiwiYXNjZW5kaW5nUHJpb3JpdGllc0xpc3QiLCJwcmlvcml0eUNvbm5lY3Rpb25zIiwidmFsdWVzIiwiYzEiLCJjMiIsImdldElzT25saW5lIiwibG9jYWxlQ29tcGFyZSIsImNvbXBhcmVQcmlvcml0aWVzIiwicDEiLCJwMiIsIlRhc2tMb29wZXIiLCJjb25zb2xlIiwibG9nIiwic3RhcnQiLCJjaGVja1ByaW9yaXRpemVkQ29ubmVjdGlvbnMiLCJjaGFuZ2UiLCJyZXNwb25zZXMiLCJmb3JFYWNoIiwidGltZXMiLCJ1bnNoaWZ0IiwiZ2V0UmVzcG9uc2VUaW1lIiwicG9wIiwidXBkYXRlQmVzdENvbm5lY3Rpb25JblByaW9yaXR5IiwiYmVzdENvbm5lY3Rpb25Gcm9tUmVzcG9uc2VzIiwiZ2V0QmVzdENvbm5lY3Rpb25Gcm9tUHJpb3JpdGl6ZWRSZXNwb25zZXMiLCJiZXN0UmVzcG9uc2UiLCJiZXR0ZXIiLCJpIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9jb21tb24vTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEdlblV0aWxzIGZyb20gXCIuL0dlblV0aWxzXCI7XG5pbXBvcnQgVGFza0xvb3BlciBmcm9tIFwiLi9UYXNrTG9vcGVyXCI7XG5pbXBvcnQgVGhyZWFkUG9vbCBmcm9tIFwiLi9UaHJlYWRQb29sXCI7XG5pbXBvcnQgTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJMaXN0ZW5lciBmcm9tIFwiLi9Nb25lcm9Db25uZWN0aW9uTWFuYWdlckxpc3RlbmVyXCI7XG5pbXBvcnQgTW9uZXJvRXJyb3IgZnJvbSBcIi4vTW9uZXJvRXJyb3JcIjtcbmltcG9ydCBNb25lcm9ScGNDb25uZWN0aW9uIGZyb20gXCIuL01vbmVyb1JwY0Nvbm5lY3Rpb25cIjtcblxuLyoqXG4gKiA8cD5NYW5hZ2VzIGEgY29sbGVjdGlvbiBvZiBwcmlvcml0aXplZCBjb25uZWN0aW9ucyB0byBkYWVtb24gb3Igd2FsbGV0IFJQQyBlbmRwb2ludHMuPC9wPlxuICpcbiAqIDxwPkV4YW1wbGUgdXNhZ2U6PC9wPlxuICogXG4gKiA8Y29kZT5cbiAqIC8vIGltcG9ydHM8YnI+XG4gKiBpbXBvcnQgeyBNb25lcm9ScGNDb25uZWN0aW9uLCBNb25lcm9Db25uZWN0aW9uTWFuYWdlciwgTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJMaXN0ZW5lciB9IGZyb20gXCJtb25lcm8tdHNcIjs8YnI+XG4gKiA8YnI+XG4gKiAvLyBjcmVhdGUgY29ubmVjdGlvbiBtYW5hZ2VyPGJyPlxuICogbGV0IGNvbm5lY3Rpb25NYW5hZ2VyID0gbmV3IE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyKCk7PGJyPlxuICogPGJyPlxuICogLy8gYWRkIG1hbmFnZWQgY29ubmVjdGlvbnMgd2l0aCBwcmlvcml0aWVzPGJyPlxuICogYXdhaXQgY29ubmVjdGlvbk1hbmFnZXIuYWRkQ29ubmVjdGlvbih7dXJpOiBcImh0dHA6Ly9sb2NhbGhvc3Q6MzgwODFcIiwgcHJpb3JpdHk6IDF9KTsgLy8gdXNlIGxvY2FsaG9zdCBhcyBmaXJzdCBwcmlvcml0eTxicj5cbiAqIGF3YWl0IGNvbm5lY3Rpb25NYW5hZ2VyLmFkZENvbm5lY3Rpb24oe3VyaTogXCJodHRwOi8vZXhhbXBsZS5jb21cIn0pOyAvLyBkZWZhdWx0IHByaW9yaXR5IGlzIHByaW9yaXRpemVkIGxhc3Q8YnI+XG4gKiA8YnI+XG4gKiAvLyBzZXQgY3VycmVudCBjb25uZWN0aW9uPGJyPlxuICogYXdhaXQgY29ubmVjdGlvbk1hbmFnZXIuc2V0Q29ubmVjdGlvbih7dXJpOiBcImh0dHA6Ly9mb28uYmFyXCIsIHVzZXJuYW1lOiBcImFkbWluXCIsIHBhc3N3b3JkOiBcInBhc3N3b3JkXCJ9KTsgLy8gY29ubmVjdGlvbiBpcyBhZGRlZCBpZiBuZXc8YnI+XG4gKiA8YnI+XG4gKiAvLyBjaGVjayBjb25uZWN0aW9uIHN0YXR1czxicj5cbiAqIGF3YWl0IGNvbm5lY3Rpb25NYW5hZ2VyLmNoZWNrQ29ubmVjdGlvbigpOzxicj5cbiAqIGNvbnNvbGUubG9nKFwiQ29ubmVjdGlvbiBtYW5hZ2VyIGlzIGNvbm5lY3RlZDogXCIgKyBjb25uZWN0aW9uTWFuYWdlci5pc0Nvbm5lY3RlZCgpKTs8YnI+XG4gKiBjb25zb2xlLmxvZyhcIkNvbm5lY3Rpb24gaXMgb25saW5lOiBcIiArIGNvbm5lY3Rpb25NYW5hZ2VyLmdldENvbm5lY3Rpb24oKS5nZXRJc09ubGluZSgpKTs8YnI+XG4gKiBjb25zb2xlLmxvZyhcIkNvbm5lY3Rpb24gaXMgYXV0aGVudGljYXRlZDogXCIgKyBjb25uZWN0aW9uTWFuYWdlci5nZXRDb25uZWN0aW9uKCkuZ2V0SXNBdXRoZW50aWNhdGVkKCkpOzxicj5cbiAqIDxicj4gXG4gKiAvLyByZWNlaXZlIG5vdGlmaWNhdGlvbnMgb2YgYW55IGNoYW5nZXMgdG8gY3VycmVudCBjb25uZWN0aW9uPGJyPlxuICogY29ubmVjdGlvbk1hbmFnZXIuYWRkTGlzdGVuZXIobmV3IGNsYXNzIGV4dGVuZHMgTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJMaXN0ZW5lciB7PGJyPlxuICogJm5ic3A7Jm5ic3A7IGFzeW5jIG9uQ29ubmVjdGlvbkNoYW5nZWQoY29ubmVjdGlvbikgezxicj5cbiAqICZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyBjb25zb2xlLmxvZyhcIkNvbm5lY3Rpb24gY2hhbmdlZCB0bzogXCIgKyBjb25uZWN0aW9uKTs8YnI+XG4gKiAmbmJzcDsmbmJzcDsgfTxicj5cbiAqIH0pOzxicj5cbiAqIDxicj5cbiAqIC8vIHN0YXJ0IHBvbGxpbmcgZm9yIGJlc3QgY29ubmVjdGlvbiBldmVyeSAxMCBzZWNvbmRzIGFuZCBhdXRvbWF0aWNhbGx5IHN3aXRjaDxicj5cbiAqIGNvbm5lY3Rpb25NYW5hZ2VyLnN0YXJ0UG9sbGluZygxMDAwMCk7PGJyPlxuICogPGJyPlxuICogLy8gYXV0b21hdGljYWxseSBzd2l0Y2ggdG8gYmVzdCBhdmFpbGFibGUgY29ubmVjdGlvbiBpZiBkaXNjb25uZWN0ZWQ8YnI+XG4gKiBjb25uZWN0aW9uTWFuYWdlci5zZXRBdXRvU3dpdGNoKHRydWUpOzxicj5cbiAqIDxicj5cbiAqIC8vIGdldCBiZXN0IGF2YWlsYWJsZSBjb25uZWN0aW9uIGluIG9yZGVyIG9mIHByaW9yaXR5IHRoZW4gcmVzcG9uc2UgdGltZTxicj5cbiAqIGxldCBiZXN0Q29ubmVjdGlvbiA9IGF3YWl0IGNvbm5lY3Rpb25NYW5hZ2VyLmdldEJlc3RBdmFpbGFibGVDb25uZWN0aW9uKCk7PGJyPlxuICogPGJyPlxuICogLy8gY2hlY2sgc3RhdHVzIG9mIGFsbCBjb25uZWN0aW9uczxicj5cbiAqIGF3YWl0IGNvbm5lY3Rpb25NYW5hZ2VyLmNoZWNrQ29ubmVjdGlvbnMoKTs8YnI+XG4gKiA8YnI+XG4gKiAvLyBnZXQgY29ubmVjdGlvbnMgaW4gb3JkZXIgb2YgY3VycmVudCBjb25uZWN0aW9uLCBvbmxpbmUgc3RhdHVzIGZyb20gbGFzdCBjaGVjaywgcHJpb3JpdHksIGFuZCBuYW1lPGJyPlxuICogbGV0IGNvbm5lY3Rpb25zID0gY29ubmVjdGlvbk1hbmFnZXIuZ2V0Q29ubmVjdGlvbnMoKTs8YnI+XG4gKiA8YnI+XG4gKiAvLyBjbGVhciBjb25uZWN0aW9uIG1hbmFnZXI8YnI+XG4gKiBjb25uZWN0aW9uTWFuYWdlci5jbGVhcigpO1xuICogPC9jb2RlPlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9Db25uZWN0aW9uTWFuYWdlciB7XG5cbiAgLy8gc3RhdGljIHZhcmlhYmxlc1xuICBzdGF0aWMgREVGQVVMVF9USU1FT1VUID0gNTAwMDtcbiAgc3RhdGljIERFRkFVTFRfUE9MTF9QRVJJT0QgPSAyMDAwMDtcbiAgc3RhdGljIERFRkFVTFRfQVVUT19TV0lUQ0ggPSB0cnVlO1xuICBzdGF0aWMgTUlOX0JFVFRFUl9SRVNQT05TRVMgPSAzO1xuXG4gIC8vIGluc3RhbmNlIHZhcmlhYmxlc1xuICBwcm90ZWN0ZWQgcHJveHlUb1dvcmtlcjogYW55O1xuICBwcm90ZWN0ZWQgdGltZW91dE1zOiBhbnk7XG4gIHByb3RlY3RlZCBhdXRvU3dpdGNoOiBhbnk7XG4gIHByb3RlY3RlZCBjb25uZWN0aW9uczogYW55O1xuICBwcm90ZWN0ZWQgcmVzcG9uc2VUaW1lczogYW55O1xuICBwcm90ZWN0ZWQgbGlzdGVuZXJzOiBhbnk7XG4gIHByb3RlY3RlZCBjdXJyZW50Q29ubmVjdGlvbjogYW55O1xuICBwcm90ZWN0ZWQgcG9sbGVyOiBhbnk7XG5cbiAgLyoqXG4gICAqIFNwZWNpZnkgYmVoYXZpb3Igd2hlbiBwb2xsaW5nLlxuICAgKiBcbiAgICogT25lIG9mIFBSSU9SSVRJWkVEIChwb2xsIGNvbm5lY3Rpb25zIGluIG9yZGVyIG9mIHByaW9yaXR5IHVudGlsIGNvbm5lY3RlZDsgZGVmYXVsdCksIENVUlJFTlQgKHBvbGwgY3VycmVudCBjb25uZWN0aW9uKSwgb3IgQUxMIChwb2xsIGFsbCBjb25uZWN0aW9ucykuXG4gICAqL1xuICBzdGF0aWMgUG9sbFR5cGUgPSB7XG4gICAgUFJJT1JJVElaRUQ6IDAsXG4gICAgQ1VSUkVOVDogMSxcbiAgICBBTEw6IDJcbiAgfVxuICBcbiAgLyoqXG4gICAqIENvbnN0cnVjdCBhIGNvbm5lY3Rpb24gbWFuYWdlci5cbiAgICogXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3Byb3h5VG9Xb3JrZXJdIC0gY29uZmlndXJlIGFsbCBjb25uZWN0aW9ucyB0byBwcm94eSB0byB3b3JrZXIgKGRlZmF1bHQgdHJ1ZSlcbiAgICovXG4gIGNvbnN0cnVjdG9yKHByb3h5VG9Xb3JrZXIgPSB0cnVlKSB7XG4gICAgdGhpcy5wcm94eVRvV29ya2VyID0gcHJveHlUb1dvcmtlciAhPT0gZmFsc2U7XG4gICAgdGhpcy50aW1lb3V0TXMgPSBNb25lcm9Db25uZWN0aW9uTWFuYWdlci5ERUZBVUxUX1RJTUVPVVQ7XG4gICAgdGhpcy5hdXRvU3dpdGNoID0gTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIuREVGQVVMVF9BVVRPX1NXSVRDSDtcbiAgICB0aGlzLmNvbm5lY3Rpb25zID0gW107XG4gICAgdGhpcy5yZXNwb25zZVRpbWVzID0gbmV3IE1hcCgpO1xuICAgIHRoaXMubGlzdGVuZXJzID0gW107XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBBZGQgYSBsaXN0ZW5lciB0byByZWNlaXZlIG5vdGlmaWNhdGlvbnMgd2hlbiB0aGUgY29ubmVjdGlvbiBjaGFuZ2VzLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9Db25uZWN0aW9uTWFuYWdlckxpc3RlbmVyfSBsaXN0ZW5lciAtIHRoZSBsaXN0ZW5lciB0byBhZGRcbiAgICogQHJldHVybiB7TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJ9IHRoaXMgY29ubmVjdGlvbiBtYW5hZ2VyIGZvciBjaGFpbmluZ1xuICAgKi9cbiAgYWRkTGlzdGVuZXIobGlzdGVuZXI6IE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyTGlzdGVuZXIpOiBNb25lcm9Db25uZWN0aW9uTWFuYWdlciB7XG4gICAgdGhpcy5saXN0ZW5lcnMucHVzaChsaXN0ZW5lcik7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZW1vdmUgYSBsaXN0ZW5lci5cbiAgICogXG4gICAqIEBwYXJhbSB7TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJMaXN0ZW5lcn0gbGlzdGVuZXIgLSB0aGUgbGlzdGVuZXIgdG8gcmVtb3ZlXG4gICAqIEByZXR1cm4ge01vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyfSB0aGlzIGNvbm5lY3Rpb24gbWFuYWdlciBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHJlbW92ZUxpc3RlbmVyKGxpc3RlbmVyOiBNb25lcm9Db25uZWN0aW9uTWFuYWdlckxpc3RlbmVyKTogTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIge1xuICAgIGlmICghR2VuVXRpbHMucmVtb3ZlKHRoaXMubGlzdGVuZXJzLCBsaXN0ZW5lcikpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk1vbmVybyBjb25uZWN0aW9uIG1hbmFnZXIgZG9lcyBub3QgY29udGFpbiBsaXN0ZW5lciB0byByZW1vdmVcIik7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZW1vdmUgYWxsIGxpc3RlbmVycy5cbiAgICogXG4gICAqIEByZXR1cm4ge01vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyfSB0aGlzIGNvbm5lY3Rpb24gbWFuYWdlciBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHJlbW92ZUxpc3RlbmVycygpOiBNb25lcm9Db25uZWN0aW9uTWFuYWdlciB7XG4gICAgdGhpcy5saXN0ZW5lcnMuc3BsaWNlKDAsIHRoaXMubGlzdGVuZXJzLmxlbmd0aCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFsbCBsaXN0ZW5lcnMuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtNb25lcm9Db25uZWN0aW9uTWFuYWdlckxpc3RlbmVyW119IGFsbCBsaXN0ZW5lcnNcbiAgICovXG4gIGdldExpc3RlbmVycygpOiBNb25lcm9Db25uZWN0aW9uTWFuYWdlckxpc3RlbmVyW10ge1xuICAgIHJldHVybiB0aGlzLmxpc3RlbmVyc1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIGNvbm5lY3Rpb24uIFRoZSBjb25uZWN0aW9uIG1heSBoYXZlIGFuIGVsZXZhdGVkIHByaW9yaXR5IGZvciB0aGlzIG1hbmFnZXIgdG8gdXNlLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd8UGFydGlhbDxNb25lcm9ScGNDb25uZWN0aW9uPn0gdXJpT3JDb25uZWN0aW9uIC0gdXJpIG9yIGNvbm5lY3Rpb24gdG8gYWRkXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXI+fSB0aGlzIGNvbm5lY3Rpb24gbWFuYWdlciBmb3IgY2hhaW5pbmdcbiAgICovXG4gIGFzeW5jIGFkZENvbm5lY3Rpb24odXJpT3JDb25uZWN0aW9uOiBzdHJpbmcgfCBQYXJ0aWFsPE1vbmVyb1JwY0Nvbm5lY3Rpb24+KTogUHJvbWlzZTxNb25lcm9Db25uZWN0aW9uTWFuYWdlcj4ge1xuICAgIGxldCBjb25uZWN0aW9uID0gdXJpT3JDb25uZWN0aW9uIGluc3RhbmNlb2YgTW9uZXJvUnBjQ29ubmVjdGlvbiA/IHVyaU9yQ29ubmVjdGlvbiA6IG5ldyBNb25lcm9ScGNDb25uZWN0aW9uKHVyaU9yQ29ubmVjdGlvbik7XG4gICAgZm9yIChsZXQgYUNvbm5lY3Rpb24gb2YgdGhpcy5jb25uZWN0aW9ucykge1xuICAgICAgaWYgKGFDb25uZWN0aW9uLmdldFVyaSgpID09PSBjb25uZWN0aW9uLmdldFVyaSgpKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJDb25uZWN0aW9uIFVSSSBhbHJlYWR5IGV4aXN0c1wiKTtcbiAgICB9XG4gICAgaWYgKHRoaXMucHJveHlUb1dvcmtlciAhPT0gdW5kZWZpbmVkKSBjb25uZWN0aW9uLnNldFByb3h5VG9Xb3JrZXIodGhpcy5wcm94eVRvV29ya2VyKTtcbiAgICB0aGlzLmNvbm5lY3Rpb25zLnB1c2goY29ubmVjdGlvbik7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZW1vdmUgYSBjb25uZWN0aW9uLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVyaSAtIG9mIHRoZSB0aGUgY29ubmVjdGlvbiB0byByZW1vdmVcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9Db25uZWN0aW9uTWFuYWdlcj59IHRoaXMgY29ubmVjdGlvbiBtYW5hZ2VyIGZvciBjaGFpbmluZ1xuICAgKi9cbiAgYXN5bmMgcmVtb3ZlQ29ubmVjdGlvbih1cmk6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXI+IHtcbiAgICBsZXQgY29ubmVjdGlvbiA9IHRoaXMuZ2V0Q29ubmVjdGlvbkJ5VXJpKHVyaSk7XG4gICAgaWYgKCFjb25uZWN0aW9uKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJObyBjb25uZWN0aW9uIGV4aXN0cyB3aXRoIFVSSTogXCIgKyB1cmkpO1xuICAgIEdlblV0aWxzLnJlbW92ZSh0aGlzLmNvbm5lY3Rpb25zLCBjb25uZWN0aW9uKTtcbiAgICB0aGlzLnJlc3BvbnNlVGltZXMuZGVsZXRlKGNvbm5lY3Rpb24uZ2V0VXJpKCkpO1xuICAgIGlmIChjb25uZWN0aW9uID09PSB0aGlzLmN1cnJlbnRDb25uZWN0aW9uKSB7XG4gICAgICB0aGlzLmN1cnJlbnRDb25uZWN0aW9uID0gdW5kZWZpbmVkO1xuICAgICAgYXdhaXQgdGhpcy5vbkNvbm5lY3Rpb25DaGFuZ2VkKHRoaXMuY3VycmVudENvbm5lY3Rpb24pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIFNldCB0aGUgY3VycmVudCBjb25uZWN0aW9uLlxuICAgKiBQcm92aWRlIGEgVVJJIHRvIHNlbGVjdCBhbiBleGlzdGluZyBjb25uZWN0aW9uIHdpdGhvdXQgdXBkYXRpbmcgaXRzIGNyZWRlbnRpYWxzLlxuICAgKiBQcm92aWRlIGEgTW9uZXJvUnBjQ29ubmVjdGlvbiB0byBhZGQgbmV3IGNvbm5lY3Rpb24gb3IgcmVwbGFjZSBleGlzdGluZyBjb25uZWN0aW9uIHdpdGggdGhlIHNhbWUgVVJJLlxuICAgKiBOb3RpZnkgaWYgY3VycmVudCBjb25uZWN0aW9uIGNoYW5nZXMuXG4gICAqIERvZXMgbm90IGNoZWNrIHRoZSBjb25uZWN0aW9uLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd8UGFydGlhbDxNb25lcm9ScGNDb25uZWN0aW9uPn0gW3VyaU9yQ29ubmVjdGlvbl0gLSBpcyB0aGUgdXJpIG9mIHRoZSBjb25uZWN0aW9uIG9yIHRoZSBjb25uZWN0aW9uIHRvIG1ha2UgY3VycmVudCAoZGVmYXVsdCB1bmRlZmluZWQgZm9yIG5vIGN1cnJlbnQgY29ubmVjdGlvbilcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9Db25uZWN0aW9uTWFuYWdlcj59IHRoaXMgY29ubmVjdGlvbiBtYW5hZ2VyIGZvciBjaGFpbmluZ1xuICAgKi9cbiAgYXN5bmMgc2V0Q29ubmVjdGlvbih1cmlPckNvbm5lY3Rpb24/OiBzdHJpbmcgfCBQYXJ0aWFsPE1vbmVyb1JwY0Nvbm5lY3Rpb24+KTogUHJvbWlzZTxNb25lcm9Db25uZWN0aW9uTWFuYWdlcj4ge1xuICAgIFxuICAgIC8vIGhhbmRsZSB1cmlcbiAgICBpZiAodXJpT3JDb25uZWN0aW9uICYmIHR5cGVvZiB1cmlPckNvbm5lY3Rpb24gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIGxldCBjb25uZWN0aW9uID0gdGhpcy5nZXRDb25uZWN0aW9uQnlVcmkodXJpT3JDb25uZWN0aW9uKTtcbiAgICAgIHJldHVybiB0aGlzLnNldENvbm5lY3Rpb24oY29ubmVjdGlvbiA9PT0gdW5kZWZpbmVkID8gbmV3IE1vbmVyb1JwY0Nvbm5lY3Rpb24odXJpT3JDb25uZWN0aW9uKSA6IGNvbm5lY3Rpb24pO1xuICAgIH1cbiAgICBcbiAgICAvLyBoYW5kbGUgY29ubmVjdGlvblxuICAgIGxldCBjb25uZWN0aW9uID0gdXJpT3JDb25uZWN0aW9uO1xuICAgIGlmICh0aGlzLmN1cnJlbnRDb25uZWN0aW9uID09PSBjb25uZWN0aW9uKSByZXR1cm4gdGhpcztcbiAgICBcbiAgICAvLyBjaGVjayBpZiBzZXR0aW5nIHVuZGVmaW5lZCBjb25uZWN0aW9uXG4gICAgaWYgKCFjb25uZWN0aW9uKSB7XG4gICAgICB0aGlzLmN1cnJlbnRDb25uZWN0aW9uID0gdW5kZWZpbmVkO1xuICAgICAgYXdhaXQgdGhpcy5vbkNvbm5lY3Rpb25DaGFuZ2VkKHVuZGVmaW5lZCk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG4gICAgXG4gICAgLy8gdmFsaWRhdGUgY29ubmVjdGlvblxuICAgIGlmICghKGNvbm5lY3Rpb24gaW5zdGFuY2VvZiBNb25lcm9ScGNDb25uZWN0aW9uKSkgY29ubmVjdGlvbiA9IG5ldyBNb25lcm9ScGNDb25uZWN0aW9uKGNvbm5lY3Rpb24pO1xuICAgIGlmICghY29ubmVjdGlvbi5nZXRVcmkoKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ29ubmVjdGlvbiBpcyBtaXNzaW5nIFVSSVwiKTtcblxuICAgIC8vIGFkZCBvciByZXBsYWNlIGNvbm5lY3Rpb25cbiAgICBsZXQgcHJldkNvbm5lY3Rpb24gPSB0aGlzLmdldENvbm5lY3Rpb25CeVVyaShjb25uZWN0aW9uLmdldFVyaSgpKTtcbiAgICBpZiAocHJldkNvbm5lY3Rpb24pIEdlblV0aWxzLnJlbW92ZSh0aGlzLmNvbm5lY3Rpb25zLCBwcmV2Q29ubmVjdGlvbik7XG4gICAgYXdhaXQgdGhpcy5hZGRDb25uZWN0aW9uKGNvbm5lY3Rpb24pO1xuICAgIHRoaXMuY3VycmVudENvbm5lY3Rpb24gPSBjb25uZWN0aW9uO1xuICAgIGF3YWl0IHRoaXMub25Db25uZWN0aW9uQ2hhbmdlZCh0aGlzLmN1cnJlbnRDb25uZWN0aW9uKTtcbiAgICBcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGN1cnJlbnQgY29ubmVjdGlvbi5cbiAgICogXG4gICAqIEByZXR1cm4ge01vbmVyb1JwY0Nvbm5lY3Rpb259IHRoZSBjdXJyZW50IGNvbm5lY3Rpb24gb3IgdW5kZWZpbmVkIGlmIG5vIGNvbm5lY3Rpb24gc2V0XG4gICAqL1xuICBnZXRDb25uZWN0aW9uKCk6IE1vbmVyb1JwY0Nvbm5lY3Rpb24ge1xuICAgIHJldHVybiB0aGlzLmN1cnJlbnRDb25uZWN0aW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGlzIG1hbmFnZXIgaGFzIGEgY29ubmVjdGlvbiB3aXRoIHRoZSBnaXZlbiBVUkkuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdXJpIFVSSSBvZiB0aGUgY29ubmVjdGlvbiB0byBjaGVja1xuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHRoaXMgbWFuYWdlciBoYXMgYSBjb25uZWN0aW9uIHdpdGggdGhlIGdpdmVuIFVSSSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBoYXNDb25uZWN0aW9uKHVyaTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0Q29ubmVjdGlvbkJ5VXJpKHVyaSkgIT09IHVuZGVmaW5lZDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBhIGNvbm5lY3Rpb24gYnkgVVJJLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVyaSBpcyB0aGUgVVJJIG9mIHRoZSBjb25uZWN0aW9uIHRvIGdldFxuICAgKiBAcmV0dXJuIHtNb25lcm9ScGNDb25uZWN0aW9ufSB0aGUgY29ubmVjdGlvbiB3aXRoIHRoZSBVUkkgb3IgdW5kZWZpbmVkIGlmIG5vIGNvbm5lY3Rpb24gd2l0aCB0aGUgVVJJIGV4aXN0c1xuICAgKi9cbiAgZ2V0Q29ubmVjdGlvbkJ5VXJpKHVyaTogc3RyaW5nKTogTW9uZXJvUnBjQ29ubmVjdGlvbiB7XG4gICAgZm9yIChsZXQgY29ubmVjdGlvbiBvZiB0aGlzLmNvbm5lY3Rpb25zKSBpZiAoY29ubmVjdGlvbi5nZXRVcmkoKSA9PT0gdXJpKSByZXR1cm4gY29ubmVjdGlvbjtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGFsbCBjb25uZWN0aW9ucyBpbiBvcmRlciBvZiBjdXJyZW50IGNvbm5lY3Rpb24gKGlmIGFwcGxpY2FibGUpLCBvbmxpbmUgc3RhdHVzLCBwcmlvcml0eSwgYW5kIG5hbWUuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtNb25lcm9ScGNDb25uZWN0aW9uW119IHRoZSBsaXN0IG9mIHNvcnRlZCBjb25uZWN0aW9uc1xuICAgKi9cbiAgZ2V0Q29ubmVjdGlvbnMoKTogTW9uZXJvUnBjQ29ubmVjdGlvbltdIHtcbiAgICBsZXQgc29ydGVkQ29ubmVjdGlvbnMgPSBHZW5VdGlscy5jb3B5QXJyYXkodGhpcy5jb25uZWN0aW9ucyk7XG4gICAgc29ydGVkQ29ubmVjdGlvbnMuc29ydCh0aGlzLmNvbXBhcmVDb25uZWN0aW9ucy5iaW5kKHRoaXMpKTtcbiAgICByZXR1cm4gc29ydGVkQ29ubmVjdGlvbnM7XG4gIH1cblxuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIHRoZSBjb25uZWN0aW9uIG1hbmFnZXIgaXMgY29ubmVjdGVkIHRvIGEgbm9kZS5cbiAgICogXG4gICAqIEByZXR1cm4ge2Jvb2xlYW58dW5kZWZpbmVkfSB0cnVlIGlmIHRoZSBjdXJyZW50IGNvbm5lY3Rpb24gaXMgc2V0LCBvbmxpbmUsIGFuZCBub3QgdW5hdXRoZW50aWNhdGVkLCB1bmRlZmluZWQgaWYgdW5rbm93biwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBpc0Nvbm5lY3RlZCgpOiBib29sZWFuIHwgdW5kZWZpbmVkIHtcbiAgICBpZiAoIXRoaXMuY3VycmVudENvbm5lY3Rpb24pIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gdGhpcy5jdXJyZW50Q29ubmVjdGlvbi5pc0Nvbm5lY3RlZCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IHBvbGxpbmcgY29ubmVjdGlvbnMuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gW3BlcmlvZE1zXSBwb2xsIHBlcmlvZCBpbiBtaWxsaXNlY29uZHMgKGRlZmF1bHQgMjBzKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFthdXRvU3dpdGNoXSBzcGVjaWZpZXMgdG8gYXV0b21hdGljYWxseSBzd2l0Y2ggdG8gdGhlIGJlc3QgY29ubmVjdGlvbiAoZGVmYXVsdCB0cnVlIHVubGVzcyBjaGFuZ2VkKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW3RpbWVvdXRNc10gc3BlY2lmaWVzIHRoZSB0aW1lb3V0IHRvIHBvbGwgYSBzaW5nbGUgY29ubmVjdGlvbiAoZGVmYXVsdCA1cyB1bmxlc3MgY2hhbmdlZClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtwb2xsVHlwZV0gb25lIG9mIFBSSU9SSVRJWkVEIChwb2xsIGNvbm5lY3Rpb25zIGluIG9yZGVyIG9mIHByaW9yaXR5IHVudGlsIGNvbm5lY3RlZDsgZGVmYXVsdCksIENVUlJFTlQgKHBvbGwgY3VycmVudCBjb25uZWN0aW9uKSwgb3IgQUxMIChwb2xsIGFsbCBjb25uZWN0aW9ucylcbiAgICogQHBhcmFtIHtNb25lcm9ScGNDb25uZWN0aW9uW119IFtleGNsdWRlZENvbm5lY3Rpb25zXSBjb25uZWN0aW9ucyBleGNsdWRlZCBmcm9tIGJlaW5nIHBvbGxlZFxuICAgKiBAcmV0dXJuIHtNb25lcm9Db25uZWN0aW9uTWFuYWdlcn0gdGhpcyBjb25uZWN0aW9uIG1hbmFnZXIgZm9yIGNoYWluaW5nXG4gICAqL1xuICBzdGFydFBvbGxpbmcocGVyaW9kTXM/OiBudW1iZXIsIGF1dG9Td2l0Y2g/OiBib29sZWFuLCB0aW1lb3V0TXM/OiBudW1iZXIsIHBvbGxUeXBlPzogbnVtYmVyLCBleGNsdWRlZENvbm5lY3Rpb25zPzogTW9uZXJvUnBjQ29ubmVjdGlvbltdKTogTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIge1xuXG4gICAgLy8gYXBwbHkgZGVmYXVsdHNcbiAgICBpZiAocGVyaW9kTXMgPT0gdW5kZWZpbmVkKSBwZXJpb2RNcyA9IE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyLkRFRkFVTFRfUE9MTF9QRVJJT0Q7XG4gICAgaWYgKGF1dG9Td2l0Y2ggIT09IHVuZGVmaW5lZCkgdGhpcy5zZXRBdXRvU3dpdGNoKGF1dG9Td2l0Y2gpO1xuICAgIGlmICh0aW1lb3V0TXMgIT09IHVuZGVmaW5lZCkgdGhpcy5zZXRUaW1lb3V0KHRpbWVvdXRNcyk7XG4gICAgaWYgKHBvbGxUeXBlID09PSB1bmRlZmluZWQpIHBvbGxUeXBlID0gTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIuUG9sbFR5cGUuUFJJT1JJVElaRUQ7XG5cbiAgICAvLyBzdG9wIHBvbGxpbmdcbiAgICB0aGlzLnN0b3BQb2xsaW5nKCk7XG5cbiAgICAvLyBzdGFydCBwb2xsaW5nXG4gICAgc3dpdGNoIChwb2xsVHlwZSkge1xuICAgICAgY2FzZSBNb25lcm9Db25uZWN0aW9uTWFuYWdlci5Qb2xsVHlwZS5DVVJSRU5UOlxuICAgICAgICB0aGlzLnN0YXJ0UG9sbGluZ0Nvbm5lY3Rpb24ocGVyaW9kTXMpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIuUG9sbFR5cGUuQUxMOlxuICAgICAgICB0aGlzLnN0YXJ0UG9sbGluZ0Nvbm5lY3Rpb25zKHBlcmlvZE1zKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyLlBvbGxUeXBlLlBSSU9SSVRJWkVEOlxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhpcy5zdGFydFBvbGxpbmdQcmlvcml0aXplZENvbm5lY3Rpb25zKHBlcmlvZE1zLCBleGNsdWRlZENvbm5lY3Rpb25zKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogU3RvcCBwb2xsaW5nIGNvbm5lY3Rpb25zLlxuICAgKiBcbiAgICogQHJldHVybiB7TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJ9IHRoaXMgY29ubmVjdGlvbiBtYW5hZ2VyIGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc3RvcFBvbGxpbmcoKTogTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIge1xuICAgIGlmICh0aGlzLnBvbGxlcikgdGhpcy5wb2xsZXIuc3RvcCgpO1xuICAgIHRoaXMucG9sbGVyID0gdW5kZWZpbmVkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrIHRoZSBjdXJyZW50IGNvbm5lY3Rpb24uIElmIGRpc2Nvbm5lY3RlZCBhbmQgYXV0byBzd2l0Y2ggZW5hYmxlZCwgc3dpdGNoZXMgdG8gYmVzdCBhdmFpbGFibGUgY29ubmVjdGlvbi5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXI+fSB0aGlzIGNvbm5lY3Rpb24gbWFuYWdlciBmb3IgY2hhaW5pbmdcbiAgICovXG4gIGFzeW5jIGNoZWNrQ29ubmVjdGlvbigpOiBQcm9taXNlPE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyPiB7XG4gICAgbGV0IGNvbm5lY3Rpb25DaGFuZ2VkID0gZmFsc2U7XG4gICAgbGV0IGNvbm5lY3Rpb24gPSB0aGlzLmdldENvbm5lY3Rpb24oKTtcbiAgICBpZiAoY29ubmVjdGlvbikge1xuICAgICAgaWYgKGF3YWl0IGNvbm5lY3Rpb24uY2hlY2tDb25uZWN0aW9uKHRoaXMudGltZW91dE1zKSkgY29ubmVjdGlvbkNoYW5nZWQgPSB0cnVlO1xuICAgICAgYXdhaXQgdGhpcy5wcm9jZXNzUmVzcG9uc2VzKFtjb25uZWN0aW9uXSk7XG4gICAgfVxuICAgIGlmICh0aGlzLmF1dG9Td2l0Y2ggJiYgIXRoaXMuaXNDb25uZWN0ZWQoKSkge1xuICAgICAgbGV0IGJlc3RDb25uZWN0aW9uID0gYXdhaXQgdGhpcy5nZXRCZXN0QXZhaWxhYmxlQ29ubmVjdGlvbihbY29ubmVjdGlvbl0pO1xuICAgICAgaWYgKGJlc3RDb25uZWN0aW9uKSB7XG4gICAgICAgIGF3YWl0IHRoaXMuc2V0Q29ubmVjdGlvbihiZXN0Q29ubmVjdGlvbik7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoY29ubmVjdGlvbkNoYW5nZWQpIGF3YWl0IHRoaXMub25Db25uZWN0aW9uQ2hhbmdlZChjb25uZWN0aW9uKTsgICBcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIENoZWNrIGFsbCBtYW5hZ2VkIGNvbm5lY3Rpb25zLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9Db25uZWN0aW9uTWFuYWdlcj59IHRoaXMgY29ubmVjdGlvbiBtYW5hZ2VyIGZvciBjaGFpbmluZ1xuICAgKi9cbiAgYXN5bmMgY2hlY2tDb25uZWN0aW9ucygpOiBQcm9taXNlPE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyPiB7XG4gICAgYXdhaXQgdGhpcy5jaGVja0Nvbm5lY3Rpb25zQXV4KHRoaXMuZ2V0Q29ubmVjdGlvbnMoKSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgYWxsIG1hbmFnZWQgY29ubmVjdGlvbnMsIHJldHVybmluZyBhIHByb21pc2UgZm9yIGVhY2ggY29ubmVjdGlvbiBjaGVjay5cbiAgICogRG9lcyBub3QgYXV0byBzd2l0Y2ggaWYgZGlzY29ubmVjdGVkLlxuICAgKlxuICAgKiBAcmV0dXJuIHtQcm9taXNlW119IGEgcHJvbWlzZSBmb3IgZWFjaCBjb25uZWN0aW9uIGluIHRoZSBvcmRlciBvZiBnZXRDb25uZWN0aW9ucygpLlxuICAgKi9cbiAgY2hlY2tDb25uZWN0aW9uUHJvbWlzZXMoKTogUHJvbWlzZTx2b2lkPltdIHtcbiAgICBsZXQgY2hlY2tQcm9taXNlcyA9IFtdO1xuICAgIGxldCBwb29sID0gbmV3IFRocmVhZFBvb2wodGhpcy5jb25uZWN0aW9ucy5sZW5ndGgpO1xuICAgIGZvciAobGV0IGNvbm5lY3Rpb24gb2YgdGhpcy5nZXRDb25uZWN0aW9ucygpKSB7XG4gICAgICBjaGVja1Byb21pc2VzLnB1c2gocG9vbC5zdWJtaXQoYXN5bmMgKCkgPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGlmIChhd2FpdCBjb25uZWN0aW9uLmNoZWNrQ29ubmVjdGlvbih0aGlzLnRpbWVvdXRNcykgJiYgY29ubmVjdGlvbiA9PT0gdGhpcy5jdXJyZW50Q29ubmVjdGlvbikgYXdhaXQgdGhpcy5vbkNvbm5lY3Rpb25DaGFuZ2VkKGNvbm5lY3Rpb24pO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAvLyBpZ25vcmUgZXJyb3JcbiAgICAgICAgfVxuICAgICAgfSkpO1xuICAgIH1cbiAgICBQcm9taXNlLmFsbChjaGVja1Byb21pc2VzKTtcbiAgICByZXR1cm4gY2hlY2tQcm9taXNlcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgYmVzdCBhdmFpbGFibGUgY29ubmVjdGlvbiBpbiBvcmRlciBvZiBwcmlvcml0eSB0aGVuIHJlc3BvbnNlIHRpbWUuXG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb1JwY0Nvbm5lY3Rpb25bXX0gW2V4Y2x1ZGVkQ29ubmVjdGlvbnNdIC0gY29ubmVjdGlvbnMgdG8gYmUgZXhjbHVkZWQgZnJvbSBjb25zaWRlcmF0aW9uIChvcHRpb25hbClcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9ScGNDb25uZWN0aW9uPn0gdGhlIGJlc3QgYXZhaWxhYmxlIGNvbm5lY3Rpb24gaW4gb3JkZXIgb2YgcHJpb3JpdHkgdGhlbiByZXNwb25zZSB0aW1lLCB1bmRlZmluZWQgaWYgbm8gY29ubmVjdGlvbnMgYXZhaWxhYmxlXG4gICAqL1xuICBhc3luYyBnZXRCZXN0QXZhaWxhYmxlQ29ubmVjdGlvbihleGNsdWRlZENvbm5lY3Rpb25zPzogTW9uZXJvUnBjQ29ubmVjdGlvbltdKTogUHJvbWlzZTxNb25lcm9ScGNDb25uZWN0aW9uPiB7XG4gICAgXG4gICAgLy8gdHJ5IGNvbm5lY3Rpb25zIHdpdGhpbiBlYWNoIGFzY2VuZGluZyBwcmlvcml0eVxuICAgIGZvciAobGV0IHByaW9yaXRpemVkQ29ubmVjdGlvbnMgb2YgdGhpcy5nZXRDb25uZWN0aW9uc0luQXNjZW5kaW5nUHJpb3JpdHkoKSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgXG4gICAgICAgIC8vIGNyZWF0ZSBwcm9taXNlcyB0byBjaGVjayBjb25uZWN0aW9uc1xuICAgICAgICBsZXQgdGhhdCA9IHRoaXM7XG4gICAgICAgIGxldCBjaGVja1Byb21pc2VzID0gW107XG4gICAgICAgIGZvciAobGV0IGNvbm5lY3Rpb24gb2YgcHJpb3JpdGl6ZWRDb25uZWN0aW9ucykge1xuICAgICAgICAgIGlmIChleGNsdWRlZENvbm5lY3Rpb25zICYmIEdlblV0aWxzLmFycmF5Q29udGFpbnMoZXhjbHVkZWRDb25uZWN0aW9ucywgY29ubmVjdGlvbikpIGNvbnRpbnVlO1xuICAgICAgICAgIGNoZWNrUHJvbWlzZXMucHVzaChuZXcgUHJvbWlzZShhc3luYyBmdW5jdGlvbihyZXNvbHZlLCByZWplY3QpIHtcbiAgICAgICAgICAgIGF3YWl0IGNvbm5lY3Rpb24uY2hlY2tDb25uZWN0aW9uKHRoYXQudGltZW91dE1zKTtcbiAgICAgICAgICAgIGlmIChjb25uZWN0aW9uLmlzQ29ubmVjdGVkKCkpIHJlc29sdmUoY29ubmVjdGlvbik7XG4gICAgICAgICAgICBlbHNlIHJlamVjdCgpO1xuICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgLy8gdXNlIGZpcnN0IGF2YWlsYWJsZSBjb25uZWN0aW9uXG4gICAgICAgIGxldCBmaXJzdEF2YWlsYWJsZSA9IGF3YWl0IFByb21pc2UuYW55KGNoZWNrUHJvbWlzZXMpO1xuICAgICAgICBpZiAoZmlyc3RBdmFpbGFibGUpIHJldHVybiBmaXJzdEF2YWlsYWJsZTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBpZiAoIShlcnIgaW5zdGFuY2VvZiBBZ2dyZWdhdGVFcnJvcikpIHRocm93IG5ldyBNb25lcm9FcnJvcihlcnIpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIFxuICAvKipcbiAgICogQXV0b21hdGljYWxseSBzd2l0Y2ggdG8gdGhlIGJlc3QgYXZhaWxhYmxlIGNvbm5lY3Rpb24gYXMgY29ubmVjdGlvbnMgYXJlIHBvbGxlZCwgYmFzZWQgb24gcHJpb3JpdHksIHJlc3BvbnNlIHRpbWUsIGFuZCBjb25zaXN0ZW5jeS5cbiAgICogXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gYXV0b1N3aXRjaCBzcGVjaWZpZXMgaWYgdGhlIGNvbm5lY3Rpb24gc2hvdWxkIGF1dG8gc3dpdGNoIHRvIGEgYmV0dGVyIGNvbm5lY3Rpb25cbiAgICogQHJldHVybiB7TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJ9IHRoaXMgY29ubmVjdGlvbiBtYW5hZ2VyIGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0QXV0b1N3aXRjaChhdXRvU3dpdGNoOiBib29sZWFuKTogTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIge1xuICAgIHRoaXMuYXV0b1N3aXRjaCA9IGF1dG9Td2l0Y2g7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgaWYgYXV0byBzd2l0Y2ggaXMgZW5hYmxlZCBvciBkaXNhYmxlZC5cbiAgICogXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgYXV0byBzd2l0Y2ggZW5hYmxlZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBnZXRBdXRvU3dpdGNoKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmF1dG9Td2l0Y2g7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZXQgdGhlIG1heGltdW0gcmVxdWVzdCB0aW1lIGJlZm9yZSBpdHMgY29ubmVjdGlvbiBpcyBjb25zaWRlcmVkIG9mZmxpbmUuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gdGltZW91dE1zIC0gdGhlIHRpbWVvdXQgYmVmb3JlIHRoZSBjb25uZWN0aW9uIGlzIGNvbnNpZGVyZWQgb2ZmbGluZVxuICAgKiBAcmV0dXJuIHtNb25lcm9Db25uZWN0aW9uTWFuYWdlcn0gdGhpcyBjb25uZWN0aW9uIG1hbmFnZXIgZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRUaW1lb3V0KHRpbWVvdXRNczogbnVtYmVyKTogTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIge1xuICAgIHRoaXMudGltZW91dE1zID0gdGltZW91dE1zO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSByZXF1ZXN0IHRpbWVvdXQuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtudW1iZXJ9IHRoZSByZXF1ZXN0IHRpbWVvdXQgYmVmb3JlIGEgY29ubmVjdGlvbiBpcyBjb25zaWRlcmVkIG9mZmxpbmVcbiAgICovXG4gIGdldFRpbWVvdXQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy50aW1lb3V0TXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDb2xsZWN0IGNvbm5lY3RhYmxlIHBlZXJzIG9mIHRoZSBtYW5hZ2VkIGNvbm5lY3Rpb25zLlxuICAgKlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb1JwY0Nvbm5lY3Rpb25bXT59IGNvbm5lY3RhYmxlIHBlZXJzXG4gICAqL1xuICBhc3luYyBnZXRQZWVyQ29ubmVjdGlvbnMoKTogUHJvbWlzZTxNb25lcm9ScGNDb25uZWN0aW9uW10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBEaXNjb25uZWN0IGZyb20gdGhlIGN1cnJlbnQgY29ubmVjdGlvbi5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXI+fSB0aGlzIGNvbm5lY3Rpb24gbWFuYWdlciBmb3IgY2hhaW5pbmdcbiAgICovXG4gIGFzeW5jIGRpc2Nvbm5lY3QoKTogUHJvbWlzZTxNb25lcm9Db25uZWN0aW9uTWFuYWdlcj4ge1xuICAgIGF3YWl0IHRoaXMuc2V0Q29ubmVjdGlvbih1bmRlZmluZWQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogUmVtb3ZlIGFsbCBjb25uZWN0aW9ucy5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXI+fSB0aGlzIGNvbm5lY3Rpb24gbWFuYWdlciBmb3IgY2hhaW5pbmdcbiAgICovXG4gIGFzeW5jIGNsZWFyKCk6IFByb21pc2U8TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXI+IHtcbiAgICB0aGlzLmNvbm5lY3Rpb25zLnNwbGljZSgwLCB0aGlzLmNvbm5lY3Rpb25zLmxlbmd0aCk7XG4gICAgaWYgKHRoaXMuY3VycmVudENvbm5lY3Rpb24pIHtcbiAgICAgIHRoaXMuY3VycmVudENvbm5lY3Rpb24gPSB1bmRlZmluZWQ7XG4gICAgICBhd2FpdCB0aGlzLm9uQ29ubmVjdGlvbkNoYW5nZWQodW5kZWZpbmVkKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXNldCB0byBkZWZhdWx0IHN0YXRlLlxuICAgKiBcbiAgICogQHJldHVybiB7TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJ9IHRoaXMgY29ubmVjdGlvbiBtYW5hZ2VyIGZvciBjaGFpbmluZ1xuICAgKi9cbiAgcmVzZXQoKTogTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIge1xuICAgIHRoaXMucmVtb3ZlTGlzdGVuZXJzKCk7XG4gICAgdGhpcy5zdG9wUG9sbGluZygpO1xuICAgIHRoaXMuY2xlYXIoKTtcbiAgICB0aGlzLnRpbWVvdXRNcyA9IE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyLkRFRkFVTFRfVElNRU9VVDtcbiAgICB0aGlzLmF1dG9Td2l0Y2ggPSBNb25lcm9Db25uZWN0aW9uTWFuYWdlci5ERUZBVUxUX0FVVE9fU1dJVENIO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIFBSSVZBVEUgSEVMUEVSUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgXG4gIHByb3RlY3RlZCBhc3luYyBvbkNvbm5lY3Rpb25DaGFuZ2VkKGNvbm5lY3Rpb24pIHtcbiAgICBsZXQgcHJvbWlzZXMgPSBbXTtcbiAgICBmb3IgKGxldCBsaXN0ZW5lciBvZiB0aGlzLmxpc3RlbmVycykgcHJvbWlzZXMucHVzaChsaXN0ZW5lci5vbkNvbm5lY3Rpb25DaGFuZ2VkKGNvbm5lY3Rpb24pKTtcbiAgICByZXR1cm4gUHJvbWlzZS5hbGwocHJvbWlzZXMpO1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgZ2V0Q29ubmVjdGlvbnNJbkFzY2VuZGluZ1ByaW9yaXR5KCkge1xuICAgIGxldCBjb25uZWN0aW9uUHJpb3JpdGllcyA9IG5ldyBNYXAoKTtcbiAgICBmb3IgKGxldCBjb25uZWN0aW9uIG9mIHRoaXMuY29ubmVjdGlvbnMpIHtcbiAgICAgIGlmICghY29ubmVjdGlvblByaW9yaXRpZXMuaGFzKGNvbm5lY3Rpb24uZ2V0UHJpb3JpdHkoKSkpIGNvbm5lY3Rpb25Qcmlvcml0aWVzLnNldChjb25uZWN0aW9uLmdldFByaW9yaXR5KCksIFtdKTtcbiAgICAgIGNvbm5lY3Rpb25Qcmlvcml0aWVzLmdldChjb25uZWN0aW9uLmdldFByaW9yaXR5KCkpLnB1c2goY29ubmVjdGlvbik7XG4gICAgfVxuICAgIGxldCBhc2NlbmRpbmdQcmlvcml0aWVzID0gbmV3IE1hcChbLi4uY29ubmVjdGlvblByaW9yaXRpZXNdLnNvcnQoKGEsIGIpID0+IHBhcnNlSW50KGFbMF0pIC0gcGFyc2VJbnQoYlswXSkpKTsgLy8gY3JlYXRlIG1hcCBpbiBhc2NlbmRpbmcgb3JkZXJcbiAgICBsZXQgYXNjZW5kaW5nUHJpb3JpdGllc0xpc3QgPSBbXTtcbiAgICBmb3IgKGxldCBwcmlvcml0eUNvbm5lY3Rpb25zIG9mIGFzY2VuZGluZ1ByaW9yaXRpZXMudmFsdWVzKCkpIGFzY2VuZGluZ1ByaW9yaXRpZXNMaXN0LnB1c2gocHJpb3JpdHlDb25uZWN0aW9ucyk7XG4gICAgaWYgKGNvbm5lY3Rpb25Qcmlvcml0aWVzLmhhcygwKSkgYXNjZW5kaW5nUHJpb3JpdGllc0xpc3QucHVzaChhc2NlbmRpbmdQcmlvcml0aWVzTGlzdC5zcGxpY2UoMCwgMSlbMF0pOyAvLyBtb3ZlIHByaW9yaXR5IDAgdG8gZW5kXG4gICAgcmV0dXJuIGFzY2VuZGluZ1ByaW9yaXRpZXNMaXN0O1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgY29tcGFyZUNvbm5lY3Rpb25zKGMxLCBjMikge1xuICAgIFxuICAgICAgLy8gY3VycmVudCBjb25uZWN0aW9uIGlzIGZpcnN0XG4gICAgICBpZiAoYzEgPT09IHRoaXMuY3VycmVudENvbm5lY3Rpb24pIHJldHVybiAtMTtcbiAgICAgIGlmIChjMiA9PT0gdGhpcy5jdXJyZW50Q29ubmVjdGlvbikgcmV0dXJuIDE7XG4gICAgICBcbiAgICAgIC8vIG9yZGVyIGJ5IGF2YWlsYWJpbGl0eSB0aGVuIHByaW9yaXR5IHRoZW4gYnkgbmFtZVxuICAgICAgaWYgKGMxLmdldElzT25saW5lKCkgPT09IGMyLmdldElzT25saW5lKCkpIHtcbiAgICAgICAgaWYgKGMxLmdldFByaW9yaXR5KCkgPT09IGMyLmdldFByaW9yaXR5KCkpIHJldHVybiBjMS5nZXRVcmkoKS5sb2NhbGVDb21wYXJlKGMyLmdldFVyaSgpKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29tcGFyZVByaW9yaXRpZXMoYzEuZ2V0UHJpb3JpdHkoKSwgYzIuZ2V0UHJpb3JpdHkoKSkgKiAtMSAvLyBvcmRlciBieSBwcmlvcml0eSBpbiBkZXNjZW5kaW5nIG9yZGVyXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoYzEuZ2V0SXNPbmxpbmUoKSkgcmV0dXJuIC0xO1xuICAgICAgICBlbHNlIGlmIChjMi5nZXRJc09ubGluZSgpKSByZXR1cm4gMTtcbiAgICAgICAgZWxzZSBpZiAoYzEuZ2V0SXNPbmxpbmUoKSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gLTE7XG4gICAgICAgIGVsc2UgcmV0dXJuIDE7IC8vIGMxIGlzIG9mZmxpbmVcbiAgICAgIH1cbiAgfVxuXG4gIHByb3RlY3RlZCBjb21wYXJlUHJpb3JpdGllcyhwMSwgcDIpIHtcbiAgICBpZiAocDEgPT0gcDIpIHJldHVybiAwO1xuICAgIGlmIChwMSA9PSAwKSByZXR1cm4gLTE7XG4gICAgaWYgKHAyID09IDApIHJldHVybiAxO1xuICAgIHJldHVybiBwMiAtIHAxO1xuICB9XG5cbiAgcHJvdGVjdGVkIHN0YXJ0UG9sbGluZ0Nvbm5lY3Rpb24ocGVyaW9kTXMpIHtcbiAgICB0aGlzLnBvbGxlciA9IG5ldyBUYXNrTG9vcGVyKGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7IGF3YWl0IHRoaXMuY2hlY2tDb25uZWN0aW9uKCk7IH1cbiAgICAgIGNhdGNoIChlcnIpIHsgY29uc29sZS5sb2coZXJyKTsgfVxuICAgIH0pO1xuICAgIHRoaXMucG9sbGVyLnN0YXJ0KHBlcmlvZE1zKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHByb3RlY3RlZCBzdGFydFBvbGxpbmdDb25uZWN0aW9ucyhwZXJpb2RNcykge1xuICAgIHRoaXMucG9sbGVyID0gbmV3IFRhc2tMb29wZXIoYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHsgYXdhaXQgdGhpcy5jaGVja0Nvbm5lY3Rpb25zKCk7IH1cbiAgICAgIGNhdGNoIChlcnIpIHsgY29uc29sZS5sb2coZXJyKTsgfVxuICAgIH0pO1xuICAgIHRoaXMucG9sbGVyLnN0YXJ0KHBlcmlvZE1zKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHByb3RlY3RlZCBzdGFydFBvbGxpbmdQcmlvcml0aXplZENvbm5lY3Rpb25zKHBlcmlvZE1zLCBleGNsdWRlZENvbm5lY3Rpb25zKSB7XG4gICAgdGhpcy5wb2xsZXIgPSBuZXcgVGFza0xvb3Blcihhc3luYyAoKSA9PiB7XG4gICAgICB0cnkgeyBhd2FpdCB0aGlzLmNoZWNrUHJpb3JpdGl6ZWRDb25uZWN0aW9ucyhleGNsdWRlZENvbm5lY3Rpb25zKTsgfVxuICAgICAgY2F0Y2ggKGVycikgeyBjb25zb2xlLmxvZyhlcnIpOyB9XG4gICAgfSk7XG4gICAgdGhpcy5wb2xsZXIuc3RhcnQocGVyaW9kTXMpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgYXN5bmMgY2hlY2tQcmlvcml0aXplZENvbm5lY3Rpb25zKGV4Y2x1ZGVkQ29ubmVjdGlvbnMpIHtcbiAgICBmb3IgKGxldCBwcmlvcml0aXplZENvbm5lY3Rpb25zIG9mIHRoaXMuZ2V0Q29ubmVjdGlvbnNJbkFzY2VuZGluZ1ByaW9yaXR5KCkpIHtcbiAgICAgIGxldCBoYXNDb25uZWN0aW9uID0gYXdhaXQgdGhpcy5jaGVja0Nvbm5lY3Rpb25zQXV4KHByaW9yaXRpemVkQ29ubmVjdGlvbnMsIGV4Y2x1ZGVkQ29ubmVjdGlvbnMpO1xuICAgICAgaWYgKGhhc0Nvbm5lY3Rpb24pIHJldHVybjtcbiAgICB9XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgY2hlY2tDb25uZWN0aW9uc0F1eChjb25uZWN0aW9ucywgZXhjbHVkZWRDb25uZWN0aW9ucz8pIHtcbiAgICB0cnkge1xuXG4gICAgICAvLyBjaGVjayBjb25uZWN0aW9ucyBpbiBwYXJhbGxlbFxuICAgICAgbGV0IHRoYXQgPSB0aGlzO1xuICAgICAgbGV0IGNoZWNrUHJvbWlzZXMgPSBbXTtcbiAgICAgIGxldCBoYXNDb25uZWN0aW9uID0gZmFsc2U7XG4gICAgICBmb3IgKGxldCBjb25uZWN0aW9uIG9mIGNvbm5lY3Rpb25zKSB7XG4gICAgICAgIGlmIChleGNsdWRlZENvbm5lY3Rpb25zICYmIEdlblV0aWxzLmFycmF5Q29udGFpbnMoZXhjbHVkZWRDb25uZWN0aW9ucywgY29ubmVjdGlvbikpIGNvbnRpbnVlO1xuICAgICAgICBjaGVja1Byb21pc2VzLnB1c2gobmV3IFByb21pc2UoYXN5bmMgZnVuY3Rpb24ocmVzb2x2ZSwgcmVqZWN0KSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGxldCBjaGFuZ2UgPSBhd2FpdCBjb25uZWN0aW9uLmNoZWNrQ29ubmVjdGlvbih0aGF0LnRpbWVvdXRNcyk7XG4gICAgICAgICAgICBpZiAoY2hhbmdlICYmIGNvbm5lY3Rpb24gPT09IHRoYXQuZ2V0Q29ubmVjdGlvbigpKSBhd2FpdCB0aGF0Lm9uQ29ubmVjdGlvbkNoYW5nZWQoY29ubmVjdGlvbik7XG4gICAgICAgICAgICBpZiAoY29ubmVjdGlvbi5pc0Nvbm5lY3RlZCgpICYmICFoYXNDb25uZWN0aW9uKSB7XG4gICAgICAgICAgICAgIGhhc0Nvbm5lY3Rpb24gPSB0cnVlO1xuICAgICAgICAgICAgICBpZiAoIXRoYXQuaXNDb25uZWN0ZWQoKSAmJiB0aGF0LmF1dG9Td2l0Y2gpIGF3YWl0IHRoYXQuc2V0Q29ubmVjdGlvbihjb25uZWN0aW9uKTsgLy8gc2V0IGZpcnN0IGF2YWlsYWJsZSBjb25uZWN0aW9uIGlmIGRpc2Nvbm5lY3RlZFxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzb2x2ZSh1bmRlZmluZWQpO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgICAgfVxuICAgICAgICB9KSk7XG4gICAgICB9XG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChjaGVja1Byb21pc2VzKTtcblxuICAgICAgLy8gcHJvY2VzcyByZXNwb25zZXNcbiAgICAgIGF3YWl0IHRoaXMucHJvY2Vzc1Jlc3BvbnNlcyhjb25uZWN0aW9ucyk7XG4gICAgICByZXR1cm4gaGFzQ29ubmVjdGlvbjtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihlcnIpO1xuICAgIH1cbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBwcm9jZXNzUmVzcG9uc2VzKHJlc3BvbnNlcyk6IFByb21pc2U8TW9uZXJvUnBjQ29ubmVjdGlvbj4ge1xuXG4gICAgLy8gYWRkIG5ldyBjb25uZWN0aW9uc1xuICAgIGZvciAobGV0IGNvbm5lY3Rpb24gb2YgcmVzcG9uc2VzKSB7XG4gICAgICBpZiAoIXRoaXMucmVzcG9uc2VUaW1lcy5oYXMoY29ubmVjdGlvbi5nZXRVcmkoKSkpIHRoaXMucmVzcG9uc2VUaW1lcy5zZXQoY29ubmVjdGlvbi5nZXRVcmkoKSwgW10pO1xuICAgIH1cblxuICAgIC8vIGluc2VydCByZXNwb25zZSB0aW1lcyBvciB1bmRlZmluZWRcbiAgICB0aGlzLnJlc3BvbnNlVGltZXMuZm9yRWFjaCgodGltZXMsIGNvbm5lY3Rpb24pID0+IHtcbiAgICAgIHRpbWVzLnVuc2hpZnQoR2VuVXRpbHMuYXJyYXlDb250YWlucyhyZXNwb25zZXMsIGNvbm5lY3Rpb24pID8gY29ubmVjdGlvbi5nZXRSZXNwb25zZVRpbWUoKSA6IHVuZGVmaW5lZCk7XG5cbiAgICAgIC8vIHJlbW92ZSBvbGQgcmVzcG9uc2UgdGltZXNcbiAgICAgIGlmICh0aW1lcy5sZW5ndGggPiBNb25lcm9Db25uZWN0aW9uTWFuYWdlci5NSU5fQkVUVEVSX1JFU1BPTlNFUykgdGltZXMucG9wKCk7XG4gICAgfSk7XG5cbiAgICAvLyB1cGRhdGUgYmVzdCBjb25uZWN0aW9uIGJhc2VkIG9uIHJlc3BvbnNlcyBhbmQgcHJpb3JpdHlcbiAgICByZXR1cm4gYXdhaXQgdGhpcy51cGRhdGVCZXN0Q29ubmVjdGlvbkluUHJpb3JpdHkoKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyB1cGRhdGVCZXN0Q29ubmVjdGlvbkluUHJpb3JpdHkoKTogUHJvbWlzZTxNb25lcm9ScGNDb25uZWN0aW9uPiB7XG4gICAgaWYgKCF0aGlzLmF1dG9Td2l0Y2gpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgZm9yIChsZXQgcHJpb3JpdGl6ZWRDb25uZWN0aW9ucyBvZiB0aGlzLmdldENvbm5lY3Rpb25zSW5Bc2NlbmRpbmdQcmlvcml0eSgpKSB7XG4gICAgICBsZXQgYmVzdENvbm5lY3Rpb25Gcm9tUmVzcG9uc2VzID0gYXdhaXQgdGhpcy5nZXRCZXN0Q29ubmVjdGlvbkZyb21Qcmlvcml0aXplZFJlc3BvbnNlcyhwcmlvcml0aXplZENvbm5lY3Rpb25zKTtcbiAgICAgIGlmIChiZXN0Q29ubmVjdGlvbkZyb21SZXNwb25zZXMpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5zZXRDb25uZWN0aW9uKGJlc3RDb25uZWN0aW9uRnJvbVJlc3BvbnNlcyk7XG4gICAgICAgIHJldHVybiBiZXN0Q29ubmVjdGlvbkZyb21SZXNwb25zZXM7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBiZXN0IGNvbm5lY3Rpb24gZnJvbSB0aGUgZ2l2ZW4gcmVzcG9uc2VzLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9ScGNDb25uZWN0aW9uW119IHJlc3BvbnNlcyBjb25uZWN0aW9uIHJlc3BvbnNlcyB0byB1cGRhdGUgZnJvbVxuICAgKiBAcmV0dXJuIHtNb25lcm9ScGNDb25uZWN0aW9ufSB0aGUgYmVzdCByZXNwb25zZSBhbW9uZyB0aGUgZ2l2ZW4gcmVzcG9uc2VzIG9yIHVuZGVmaW5lZCBpZiBub25lIGFyZSBiZXN0XG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgZ2V0QmVzdENvbm5lY3Rpb25Gcm9tUHJpb3JpdGl6ZWRSZXNwb25zZXMocmVzcG9uc2VzKTogUHJvbWlzZTxNb25lcm9ScGNDb25uZWN0aW9uPiB7XG5cbiAgICAvLyBnZXQgYmVzdCByZXNwb25zZVxuICAgIGxldCBiZXN0UmVzcG9uc2UgPSB1bmRlZmluZWQ7XG4gICAgZm9yIChsZXQgY29ubmVjdGlvbiBvZiByZXNwb25zZXMpIHtcbiAgICAgIGlmIChjb25uZWN0aW9uLmlzQ29ubmVjdGVkKCkgPT09IHRydWUgJiYgKCFiZXN0UmVzcG9uc2UgfHwgY29ubmVjdGlvbi5nZXRSZXNwb25zZVRpbWUoKSA8IGJlc3RSZXNwb25zZS5nZXRSZXNwb25zZVRpbWUoKSkpIGJlc3RSZXNwb25zZSA9IGNvbm5lY3Rpb247XG4gICAgfVxuXG4gICAgLy8gbm8gdXBkYXRlIGlmIG5vIHJlc3BvbnNlc1xuICAgIGlmICghYmVzdFJlc3BvbnNlKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gICAgLy8gdXNlIGJlc3QgcmVzcG9uc2UgaWYgZGlzY29ubmVjdGVkXG4gICAgbGV0IGJlc3RDb25uZWN0aW9uID0gYXdhaXQgdGhpcy5nZXRDb25uZWN0aW9uKCk7XG4gICAgaWYgKCFiZXN0Q29ubmVjdGlvbiB8fCBiZXN0Q29ubmVjdGlvbi5pc0Nvbm5lY3RlZCgpICE9PSB0cnVlKSByZXR1cm4gYmVzdFJlc3BvbnNlO1xuXG4gICAgLy8gdXNlIGJlc3QgcmVzcG9uc2UgaWYgZGlmZmVyZW50IHByaW9yaXR5IChhc3N1bWVzIGJlaW5nIGNhbGxlZCBpbiBkZXNjZW5kaW5nIHByaW9yaXR5KVxuICAgIGlmICh0aGlzLmNvbXBhcmVQcmlvcml0aWVzKGJlc3RSZXNwb25zZS5nZXRQcmlvcml0eSgpLCBiZXN0Q29ubmVjdGlvbi5nZXRQcmlvcml0eSgpKSAhPT0gMCkgcmV0dXJuIGJlc3RSZXNwb25zZTtcblxuICAgIC8vIGtlZXAgYmVzdCBjb25uZWN0aW9uIGlmIG5vdCBlbm91Z2ggZGF0YVxuICAgIGlmICghdGhpcy5yZXNwb25zZVRpbWVzLmhhcyhiZXN0Q29ubmVjdGlvbi5nZXRVcmkoKSkpIHJldHVybiBiZXN0Q29ubmVjdGlvbjtcblxuICAgIC8vIGNoZWNrIGlmIGNvbm5lY3Rpb24gaXMgY29uc2lzdGVudGx5IGJldHRlclxuICAgIGZvciAobGV0IGNvbm5lY3Rpb24gb2YgcmVzcG9uc2VzKSB7XG4gICAgICBpZiAoY29ubmVjdGlvbiA9PT0gYmVzdENvbm5lY3Rpb24pIGNvbnRpbnVlO1xuICAgICAgaWYgKCF0aGlzLnJlc3BvbnNlVGltZXMuaGFzKGNvbm5lY3Rpb24uZ2V0VXJpKCkpIHx8IHRoaXMucmVzcG9uc2VUaW1lcy5nZXQoY29ubmVjdGlvbi5nZXRVcmkoKSkubGVuZ3RoIDwgTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIuTUlOX0JFVFRFUl9SRVNQT05TRVMpIGNvbnRpbnVlO1xuICAgICAgbGV0IGJldHRlciA9IHRydWU7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyLk1JTl9CRVRURVJfUkVTUE9OU0VTOyBpKyspIHtcbiAgICAgICAgaWYgKHRoaXMucmVzcG9uc2VUaW1lcy5nZXQoY29ubmVjdGlvbi5nZXRVcmkoKSlbaV0gPT09IHVuZGVmaW5lZCB8fCB0aGlzLnJlc3BvbnNlVGltZXMuZ2V0KGJlc3RDb25uZWN0aW9uLmdldFVyaSgpKVtpXSB8fCB0aGlzLnJlc3BvbnNlVGltZXMuZ2V0KGNvbm5lY3Rpb24uZ2V0VXJpKCkpW2ldID4gdGhpcy5yZXNwb25zZVRpbWVzLmdldChiZXN0Q29ubmVjdGlvbi5nZXRVcmkoKSlbaV0pIHtcbiAgICAgICAgICBiZXR0ZXIgPSBmYWxzZTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKGJldHRlcikgYmVzdENvbm5lY3Rpb24gPSBjb25uZWN0aW9uO1xuICAgIH1cbiAgICByZXR1cm4gYmVzdENvbm5lY3Rpb247XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLFNBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFdBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLFdBQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTs7QUFF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 \ No newline at end of file diff --git a/dist/src/main/ts/common/MoneroConnectionManagerListener.d.ts b/dist/src/main/ts/common/MoneroConnectionManagerListener.d.ts new file mode 100644 index 000000000..1f756785c --- /dev/null +++ b/dist/src/main/ts/common/MoneroConnectionManagerListener.d.ts @@ -0,0 +1,13 @@ +import MoneroRpcConnection from "./MoneroRpcConnection"; +/** + * Default connection manager listener which takes no action on notifications. + */ +export default class MoneroConnectionManagerListener { + /** + * Notified on connection change events. + * + * @param {MoneroRpcConnection | undefined} connection - the connection manager's current connection + * @return {Promise} + */ + onConnectionChanged(connection: MoneroRpcConnection | undefined): Promise; +} diff --git a/dist/src/main/ts/common/MoneroConnectionManagerListener.js b/dist/src/main/ts/common/MoneroConnectionManagerListener.js new file mode 100644 index 000000000..c930e7dd1 --- /dev/null +++ b/dist/src/main/ts/common/MoneroConnectionManagerListener.js @@ -0,0 +1,16 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; + +/** + * Default connection manager listener which takes no action on notifications. + */ +class MoneroConnectionManagerListener { + + /** + * Notified on connection change events. + * + * @param {MoneroRpcConnection | undefined} connection - the connection manager's current connection + * @return {Promise} + */ + async onConnectionChanged(connection) {} +}exports.default = MoneroConnectionManagerListener; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9Db25uZWN0aW9uTWFuYWdlckxpc3RlbmVyIiwib25Db25uZWN0aW9uQ2hhbmdlZCIsImNvbm5lY3Rpb24iLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2NvbW1vbi9Nb25lcm9Db25uZWN0aW9uTWFuYWdlckxpc3RlbmVyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBNb25lcm9ScGNDb25uZWN0aW9uIGZyb20gXCIuL01vbmVyb1JwY0Nvbm5lY3Rpb25cIjtcblxuLyoqXG4gKiBEZWZhdWx0IGNvbm5lY3Rpb24gbWFuYWdlciBsaXN0ZW5lciB3aGljaCB0YWtlcyBubyBhY3Rpb24gb24gbm90aWZpY2F0aW9ucy5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJMaXN0ZW5lciB7XG4gIFxuICAvKipcbiAgICogTm90aWZpZWQgb24gY29ubmVjdGlvbiBjaGFuZ2UgZXZlbnRzLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9ScGNDb25uZWN0aW9uIHwgdW5kZWZpbmVkfSBjb25uZWN0aW9uIC0gdGhlIGNvbm5lY3Rpb24gbWFuYWdlcidzIGN1cnJlbnQgY29ubmVjdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgb25Db25uZWN0aW9uQ2hhbmdlZChjb25uZWN0aW9uOiBNb25lcm9ScGNDb25uZWN0aW9uIHwgdW5kZWZpbmVkKTogUHJvbWlzZTx2b2lkPiB7IH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7QUFFQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSwrQkFBK0IsQ0FBQzs7RUFFbkQ7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsTUFBTUMsbUJBQW1CQSxDQUFDQyxVQUEyQyxFQUFpQixDQUFFO0FBQzFGLENBQUNDLE9BQUEsQ0FBQUMsT0FBQSxHQUFBSiwrQkFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/common/MoneroError.d.ts b/dist/src/main/ts/common/MoneroError.d.ts new file mode 100644 index 000000000..aef5ed681 --- /dev/null +++ b/dist/src/main/ts/common/MoneroError.d.ts @@ -0,0 +1,15 @@ +/** + * Exception when interacting with a Monero wallet or daemon. + */ +export default class MoneroError extends Error { + code: number; + /** + * Constructs the error. + * + * @param {string} message is a human-readable message of the error + * @param {number} [code] is the error code (optional) + */ + constructor(message: any, code?: any); + getCode(): number; + toString(): string; +} diff --git a/dist/src/main/ts/common/MoneroError.js b/dist/src/main/ts/common/MoneroError.js new file mode 100644 index 000000000..efd88eb48 --- /dev/null +++ b/dist/src/main/ts/common/MoneroError.js @@ -0,0 +1,31 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Exception when interacting with a Monero wallet or daemon. + */ +class MoneroError extends Error { + + + + /** + * Constructs the error. + * + * @param {string} message is a human-readable message of the error + * @param {number} [code] is the error code (optional) + */ + constructor(message, code) { + super(message); + this.code = code; + } + + getCode() { + return this.code; + } + + toString() { + if (this.message === undefined && this.getCode() === undefined) return super.message; + let str = ""; + if (this.getCode() !== undefined) str += this.getCode() + ": "; + str += this.message; + return str; + } +}exports.default = MoneroError; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9FcnJvciIsIkVycm9yIiwiY29uc3RydWN0b3IiLCJtZXNzYWdlIiwiY29kZSIsImdldENvZGUiLCJ0b1N0cmluZyIsInVuZGVmaW5lZCIsInN0ciIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvY29tbW9uL01vbmVyb0Vycm9yLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRXhjZXB0aW9uIHdoZW4gaW50ZXJhY3Rpbmcgd2l0aCBhIE1vbmVybyB3YWxsZXQgb3IgZGFlbW9uLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9FcnJvciBleHRlbmRzIEVycm9yIHtcblxuICBjb2RlOiBudW1iZXI7XG4gIFxuICAvKipcbiAgICogQ29uc3RydWN0cyB0aGUgZXJyb3IuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSBpcyBhIGh1bWFuLXJlYWRhYmxlIG1lc3NhZ2Ugb2YgdGhlIGVycm9yXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbY29kZV0gaXMgdGhlIGVycm9yIGNvZGUgKG9wdGlvbmFsKVxuICAgKi9cbiAgY29uc3RydWN0b3IobWVzc2FnZSwgY29kZT8pIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLmNvZGUgPSBjb2RlO1xuICB9XG4gIFxuICBnZXRDb2RlKCkge1xuICAgIHJldHVybiB0aGlzLmNvZGU7XG4gIH1cbiAgXG4gIHRvU3RyaW5nKCkge1xuICAgIGlmICh0aGlzLm1lc3NhZ2UgPT09IHVuZGVmaW5lZCAmJiB0aGlzLmdldENvZGUoKSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gc3VwZXIubWVzc2FnZTtcbiAgICBsZXQgc3RyID0gXCJcIjtcbiAgICBpZiAodGhpcy5nZXRDb2RlKCkgIT09IHVuZGVmaW5lZCkgc3RyICs9IHRoaXMuZ2V0Q29kZSgpICsgXCI6IFwiO1xuICAgIHN0ciArPSB0aGlzLm1lc3NhZ2U7XG4gICAgcmV0dXJuIHN0cjtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoicUdBQUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUEsV0FBVyxTQUFTQyxLQUFLLENBQUM7Ozs7RUFJN0M7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0VDLFdBQVdBLENBQUNDLE9BQU8sRUFBRUMsSUFBSyxFQUFFO0lBQzFCLEtBQUssQ0FBQ0QsT0FBTyxDQUFDO0lBQ2QsSUFBSSxDQUFDQyxJQUFJLEdBQUdBLElBQUk7RUFDbEI7O0VBRUFDLE9BQU9BLENBQUEsRUFBRztJQUNSLE9BQU8sSUFBSSxDQUFDRCxJQUFJO0VBQ2xCOztFQUVBRSxRQUFRQSxDQUFBLEVBQUc7SUFDVCxJQUFJLElBQUksQ0FBQ0gsT0FBTyxLQUFLSSxTQUFTLElBQUksSUFBSSxDQUFDRixPQUFPLENBQUMsQ0FBQyxLQUFLRSxTQUFTLEVBQUUsT0FBTyxLQUFLLENBQUNKLE9BQU87SUFDcEYsSUFBSUssR0FBRyxHQUFHLEVBQUU7SUFDWixJQUFJLElBQUksQ0FBQ0gsT0FBTyxDQUFDLENBQUMsS0FBS0UsU0FBUyxFQUFFQyxHQUFHLElBQUksSUFBSSxDQUFDSCxPQUFPLENBQUMsQ0FBQyxHQUFHLElBQUk7SUFDOURHLEdBQUcsSUFBSSxJQUFJLENBQUNMLE9BQU87SUFDbkIsT0FBT0ssR0FBRztFQUNaO0FBQ0YsQ0FBQ0MsT0FBQSxDQUFBQyxPQUFBLEdBQUFWLFdBQUEifQ== \ No newline at end of file diff --git a/dist/src/main/ts/common/MoneroRpcConnection.d.ts b/dist/src/main/ts/common/MoneroRpcConnection.d.ts new file mode 100644 index 000000000..9c76a8932 --- /dev/null +++ b/dist/src/main/ts/common/MoneroRpcConnection.d.ts @@ -0,0 +1,162 @@ +import ThreadPool from "./ThreadPool"; +/** + * Maintains a connection and sends requests to a Monero RPC API. + */ +export default class MoneroRpcConnection { + uri: string; + username: string; + password: string; + zmqUri: string; + proxyUri: string; + rejectUnauthorized: boolean; + proxyToWorker: boolean; + priority: number; + timeoutMs: number; + protected isOnline: boolean; + protected isAuthenticated: boolean; + protected attributes: any; + protected fakeDisconnected: boolean; + protected responseTime: number; + protected checkConnectionMutex: ThreadPool; + protected sendRequestMutex: ThreadPool; + /** @private */ + static DEFAULT_CONFIG: Partial; + /** + *

Construct a RPC connection.

+ * + *

Examples:

+ * + * + * let connection1 = new MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123")

+ * + * let connection2 = new MoneroRpcConnection({
+ *    uri: http://localhost:38081,
+ *    username: "daemon_user",
+ *    password: "daemon_password_123",
+ *    rejectUnauthorized: false, // accept self-signed certificates e.g. for local development
+ *    proxyToWorker: true // proxy request to worker (default false)
+ * }); + *
+ * + * @param {string|Partial} uriOrConnection - MoneroRpcConnection or URI of the RPC endpoint + * @param {string} uriOrConnection.uri - URI of the RPC endpoint + * @param {string} [uriOrConnection.username] - username to authenticate with the RPC endpoint (optional) + * @param {string} [uriOrConnection.password] - password to authenticate with the RPC endpoint (optional) + * @param {string} [uriOrConnection.zmqUri] - URI of the ZMQ endpoint (optional) + * @param {string} [uriOrConnection.proxyUri] - URI of a proxy server to route requests through (optional) + * @param {boolean} [uriOrConnection.rejectUnauthorized] - rejects self-signed certificates if true (default true) + * @param {boolean} uriOrConnection.proxyToWorker - proxy requests to worker (default true) + * @param {string} username - username to authenticate with the RPC endpoint (optional) + * @param {string} password - password to authenticate with the RPC endpoint (optional) + */ + constructor(uriOrConnection: string | Partial, username?: string, password?: string); + setCredentials(username: any, password: any): this; + getUri(): string; + getUsername(): string; + getPassword(): string; + getZmqUri(): string; + setZmqUri(zmqUri: any): this; + getProxyUri(): string; + setProxyUri(proxyUri: any): this; + getRejectUnauthorized(): boolean; + setProxyToWorker(proxyToWorker: any): this; + getProxyToWorker(): boolean; + /** + * Set the connection's priority relative to other connections. Priority 1 is highest, + * then priority 2, etc. The default priority of 0 is lowest priority. + * + * @param {number} [priority] - the connection priority (default 0) + * @return {MoneroRpcConnection} this connection + */ + setPriority(priority: any): this; + getPriority(): number; + /** + * Set the RPC request timeout in milliseconds. + * + * @param {number} timeoutMs is the timeout in milliseconds, 0 to disable timeout, or undefined to use default + * @return {MoneroRpcConnection} this connection + */ + setTimeout(timeoutMs: number): this; + getTimeout(): number; + setAttribute(key: any, value: any): this; + getAttribute(key: any): any; + /** + * Check the connection status to update isOnline, isAuthenticated, and response time. + * + * @param {number} timeoutMs - maximum response time before considered offline + * @return {Promise} true if there is a change in status, false otherwise + */ + checkConnection(timeoutMs: any): Promise; + /** + * Indicates if the connection is connected according to the last call to checkConnection().

+ * + * Note: must call checkConnection() manually unless using MoneroConnectionManager. + * + * @return {boolean} true or false to indicate if connected, or undefined if checkConnection() has not been called + */ + isConnected(): boolean; + /** + * Indicates if the connection is online according to the last call to checkConnection().

+ * + * Note: must call checkConnection() manually unless using MoneroConnectionManager. + * + * @return {boolean} true or false to indicate if online, or undefined if checkConnection() has not been called + */ + getIsOnline(): boolean; + /** + * Indicates if the connection is authenticated according to the last call to checkConnection().

+ * + * Note: must call checkConnection() manually unless using MoneroConnectionManager. + * + * @return {boolean} true if authenticated or no authentication, false if not authenticated, or undefined if checkConnection() has not been called + */ + getIsAuthenticated(): boolean; + getResponseTime(): number; + /** + * Send a JSON RPC request. + * + * @param {string} method - JSON RPC method to invoke + * @param {object} params - request parameters + * @param {number} [timeoutMs] - overrides the request timeout in milliseconds + * @return {object} is the response map + */ + sendJsonRequest(method: any, params?: any, timeoutMs?: any): Promise; + /** + * Send a RPC request to the given path and with the given paramters. + * + * E.g. "/get_transactions" with params + * + * @param {string} path - JSON RPC path to invoke + * @param {object} params - request parameters + * @param {number} [timeoutMs] - overrides the request timeout in milliseconds + * @return {object} is the response map + */ + sendPathRequest(path: any, params?: any, timeoutMs?: any): Promise; + /** + * Send a binary RPC request. + * + * @param {string} path - path of the binary RPC method to invoke + * @param {object} [params] - request parameters + * @param {number} [timeoutMs] - request timeout in milliseconds + * @return {Uint8Array} the binary response + */ + sendBinaryRequest(path: any, params?: any, timeoutMs?: any): Promise; + getConfig(): { + uri: string; + username: string; + password: string; + zmqUri: string; + proxyUri: string; + rejectUnauthorized: boolean; + proxyToWorker: boolean; + priority: number; + timeoutMs: number; + }; + toJson(): {} & this; + toString(): string; + setFakeDisconnected(fakeDisconnected: any): void; + protected queueCheckConnection(asyncFn: () => Promise): Promise; + protected queueSendRequest(asyncFn: () => Promise): Promise; + protected static validateHttpResponse(resp: any): void; + protected validateRpcResponse(resp: any, method: any, params: any): void; +} diff --git a/dist/src/main/ts/common/MoneroRpcConnection.js b/dist/src/main/ts/common/MoneroRpcConnection.js new file mode 100644 index 000000000..6350136e7 --- /dev/null +++ b/dist/src/main/ts/common/MoneroRpcConnection.js @@ -0,0 +1,498 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _GenUtils = _interopRequireDefault(require("./GenUtils")); +var _HttpClient = _interopRequireDefault(require("./HttpClient")); +var _LibraryUtils = _interopRequireDefault(require("./LibraryUtils")); +var _MoneroError = _interopRequireDefault(require("./MoneroError")); +var _MoneroRpcError = _interopRequireDefault(require("./MoneroRpcError")); +var _MoneroUtils = _interopRequireDefault(require("./MoneroUtils")); +var _ThreadPool = _interopRequireDefault(require("./ThreadPool")); + +/** + * Maintains a connection and sends requests to a Monero RPC API. + */ +class MoneroRpcConnection { + + // public instance variables + + + + + + + + + + + // private instance variables + + + + + + + + + // default config + /** @private */ + static DEFAULT_CONFIG = { + uri: undefined, + username: undefined, + password: undefined, + zmqUri: undefined, + proxyUri: undefined, + rejectUnauthorized: true, // reject self-signed certificates if true + proxyToWorker: false, + priority: 0, + timeoutMs: undefined + }; + + /** + *

Construct a RPC connection.

+ * + *

Examples:

+ * + * + * let connection1 = new MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123")

+ * + * let connection2 = new MoneroRpcConnection({
+ *    uri: http://localhost:38081,
+ *    username: "daemon_user",
+ *    password: "daemon_password_123",
+ *    rejectUnauthorized: false, // accept self-signed certificates e.g. for local development
+ *    proxyToWorker: true // proxy request to worker (default false)
+ * }); + *
+ * + * @param {string|Partial} uriOrConnection - MoneroRpcConnection or URI of the RPC endpoint + * @param {string} uriOrConnection.uri - URI of the RPC endpoint + * @param {string} [uriOrConnection.username] - username to authenticate with the RPC endpoint (optional) + * @param {string} [uriOrConnection.password] - password to authenticate with the RPC endpoint (optional) + * @param {string} [uriOrConnection.zmqUri] - URI of the ZMQ endpoint (optional) + * @param {string} [uriOrConnection.proxyUri] - URI of a proxy server to route requests through (optional) + * @param {boolean} [uriOrConnection.rejectUnauthorized] - rejects self-signed certificates if true (default true) + * @param {boolean} uriOrConnection.proxyToWorker - proxy requests to worker (default true) + * @param {string} username - username to authenticate with the RPC endpoint (optional) + * @param {string} password - password to authenticate with the RPC endpoint (optional) + */ + constructor(uriOrConnection, username, password) { + + // validate and normalize config + if (typeof uriOrConnection === "string") { + Object.assign(this, MoneroRpcConnection.DEFAULT_CONFIG); + this.uri = uriOrConnection; + this.setCredentials(username, password); + } else { + if (username !== undefined || password !== undefined) throw new _MoneroError.default("Can provide config object or params but not both"); + Object.assign(this, MoneroRpcConnection.DEFAULT_CONFIG, uriOrConnection); + this.setCredentials(this.username, this.password); + } + + // normalize uris + if (this.uri) this.uri = _GenUtils.default.normalizeUri(this.uri); + if (this.zmqUri) this.zmqUri = _GenUtils.default.normalizeUri(this.zmqUri); + if (this.proxyUri) this.proxyUri = _GenUtils.default.normalizeUri(this.proxyUri); + + // initialize mutexes + this.checkConnectionMutex = new _ThreadPool.default(1); + this.sendRequestMutex = new _ThreadPool.default(1); + } + + setCredentials(username, password) { + if (username === "") username = undefined; + if (password === "") password = undefined; + if (username || password) { + if (!username) throw new _MoneroError.default("username must be defined because password is defined"); + if (!password) throw new _MoneroError.default("password must be defined because username is defined"); + } + if (this.username === "") this.username = undefined; + if (this.password === "") this.password = undefined; + if (this.username !== username || this.password !== password) { + this.isOnline = undefined; + this.isAuthenticated = undefined; + } + this.username = username; + this.password = password; + return this; + } + + getUri() { + return this.uri; + } + + getUsername() { + return this.username ? this.username : ""; + } + + getPassword() { + return this.password ? this.password : ""; + } + + getZmqUri() { + return this.zmqUri; + } + + setZmqUri(zmqUri) { + this.zmqUri = zmqUri; + return this; + } + + getProxyUri() { + return this.proxyUri; + } + + setProxyUri(proxyUri) { + this.proxyUri = proxyUri; + return this; + } + + getRejectUnauthorized() { + return this.rejectUnauthorized; + } + + setProxyToWorker(proxyToWorker) { + this.proxyToWorker = proxyToWorker; + return this; + } + + getProxyToWorker() { + return this.proxyToWorker; + } + + /** + * Set the connection's priority relative to other connections. Priority 1 is highest, + * then priority 2, etc. The default priority of 0 is lowest priority. + * + * @param {number} [priority] - the connection priority (default 0) + * @return {MoneroRpcConnection} this connection + */ + setPriority(priority) { + if (!(priority >= 0)) throw new _MoneroError.default("Priority must be >= 0"); + this.priority = priority; + return this; + } + + getPriority() { + return this.priority; + } + + /** + * Set the RPC request timeout in milliseconds. + * + * @param {number} timeoutMs is the timeout in milliseconds, 0 to disable timeout, or undefined to use default + * @return {MoneroRpcConnection} this connection + */ + setTimeout(timeoutMs) { + this.timeoutMs = timeoutMs; + return this; + } + + getTimeout() { + return this.timeoutMs; + } + + setAttribute(key, value) { + if (!this.attributes) this.attributes = new Map(); + this.attributes.put(key, value); + return this; + } + + getAttribute(key) { + return this.attributes.get(key); + } + + /** + * Check the connection status to update isOnline, isAuthenticated, and response time. + * + * @param {number} timeoutMs - maximum response time before considered offline + * @return {Promise} true if there is a change in status, false otherwise + */ + async checkConnection(timeoutMs) { + return this.queueCheckConnection(async () => { + await _LibraryUtils.default.loadWasmModule(); // cache wasm for binary request + let isOnlineBefore = this.isOnline; + let isAuthenticatedBefore = this.isAuthenticated; + let startTime = Date.now(); + try { + if (this.fakeDisconnected) throw new Error("Connection is fake disconnected"); + let heights = []; + for (let i = 0; i < 100; i++) heights.push(i); + await this.sendBinaryRequest("get_blocks_by_height.bin", { heights: heights }, timeoutMs); // assume daemon connection + this.isOnline = true; + this.isAuthenticated = true; + } catch (err) { + this.isOnline = false; + this.isAuthenticated = undefined; + this.responseTime = undefined; + if (err instanceof _MoneroRpcError.default) { + if (err.getCode() === 401) { + this.isOnline = true; + this.isAuthenticated = false; + } else if (err.getCode() === 404) {// fallback to latency check + this.isOnline = true; + this.isAuthenticated = true; + } + } + } + if (this.isOnline) this.responseTime = Date.now() - startTime; + return isOnlineBefore !== this.isOnline || isAuthenticatedBefore !== this.isAuthenticated; + }); + } + + /** + * Indicates if the connection is connected according to the last call to checkConnection().

+ * + * Note: must call checkConnection() manually unless using MoneroConnectionManager. + * + * @return {boolean} true or false to indicate if connected, or undefined if checkConnection() has not been called + */ + isConnected() { + return this.isOnline === undefined ? undefined : this.isOnline && this.isAuthenticated !== false; + } + + /** + * Indicates if the connection is online according to the last call to checkConnection().

+ * + * Note: must call checkConnection() manually unless using MoneroConnectionManager. + * + * @return {boolean} true or false to indicate if online, or undefined if checkConnection() has not been called + */ + getIsOnline() { + return this.isOnline; + } + + /** + * Indicates if the connection is authenticated according to the last call to checkConnection().

+ * + * Note: must call checkConnection() manually unless using MoneroConnectionManager. + * + * @return {boolean} true if authenticated or no authentication, false if not authenticated, or undefined if checkConnection() has not been called + */ + getIsAuthenticated() { + return this.isAuthenticated; + } + + getResponseTime() { + return this.responseTime; + } + + /** + * Send a JSON RPC request. + * + * @param {string} method - JSON RPC method to invoke + * @param {object} params - request parameters + * @param {number} [timeoutMs] - overrides the request timeout in milliseconds + * @return {object} is the response map + */ + async sendJsonRequest(method, params, timeoutMs) { + return this.queueSendRequest(async () => { + try { + + // build request body + let body = JSON.stringify({ // body is stringified so text/plain is returned so bigints are preserved + id: "0", + jsonrpc: "2.0", + method: method, + params: params + }); + + // logging + if (_LibraryUtils.default.getLogLevel() >= 2) _LibraryUtils.default.log(2, "Sending json request with method '" + method + "' and body: " + body); + + // proxy uri is not supported + if (this.getProxyUri()) throw new _MoneroError.default("Proxy URI not supported for JSON requests"); + + // send http request + let startTime = new Date().getTime(); + let resp = await _HttpClient.default.request({ + method: "POST", + uri: this.getUri() + '/json_rpc', + username: this.getUsername(), + password: this.getPassword(), + body: body, + timeout: timeoutMs === undefined ? this.timeoutMs : timeoutMs, + rejectUnauthorized: this.rejectUnauthorized, + proxyToWorker: this.proxyToWorker + }); + + // validate response + MoneroRpcConnection.validateHttpResponse(resp); + + // deserialize response + if (resp.body[0] != '{') throw resp.body; + resp = JSON.parse(resp.body.replace(/("[^"]*"\s*:\s*)(\d{16,})/g, '$1"$2"')); // replace 16 or more digits with strings and parse + if (_LibraryUtils.default.getLogLevel() >= 3) { + let respStr = JSON.stringify(resp); + _LibraryUtils.default.log(3, "Received response from method='" + method + "', response=" + respStr.substring(0, Math.min(1000, respStr.length)) + "(" + (new Date().getTime() - startTime) + " ms)"); + } + + // check rpc response for errors + this.validateRpcResponse(resp, method, params); + return resp; + } catch (err) { + if (err instanceof _MoneroRpcError.default) throw err;else + throw new _MoneroRpcError.default(err, err.statusCode, method, params); + } + }); + } + + /** + * Send a RPC request to the given path and with the given paramters. + * + * E.g. "/get_transactions" with params + * + * @param {string} path - JSON RPC path to invoke + * @param {object} params - request parameters + * @param {number} [timeoutMs] - overrides the request timeout in milliseconds + * @return {object} is the response map + */ + async sendPathRequest(path, params, timeoutMs) { + return this.queueSendRequest(async () => { + try { + + // logging + if (_LibraryUtils.default.getLogLevel() >= 2) _LibraryUtils.default.log(2, "Sending path request with path '" + path + "' and params: " + JSON.stringify(params)); + + // proxy uri is not supported + if (this.getProxyUri()) throw new _MoneroError.default("Proxy URI not supported for path requests"); + + // send http request + let startTime = new Date().getTime(); + let resp = await _HttpClient.default.request({ + method: "POST", + uri: this.getUri() + '/' + path, + username: this.getUsername(), + password: this.getPassword(), + body: JSON.stringify(params), // body is stringified so text/plain is returned so bigints are preserved + timeout: timeoutMs === undefined ? this.timeoutMs : timeoutMs, + rejectUnauthorized: this.rejectUnauthorized, + proxyToWorker: this.proxyToWorker + }); + + // validate response + MoneroRpcConnection.validateHttpResponse(resp); + + // deserialize response + if (resp.body[0] != '{') throw resp.body; + resp = JSON.parse(resp.body.replace(/("[^"]*"\s*:\s*)(\d{16,})/g, '$1"$2"')); // replace 16 or more digits with strings and parse + if (typeof resp === "string") resp = JSON.parse(resp); // TODO: some responses returned as strings? + if (_LibraryUtils.default.getLogLevel() >= 3) { + let respStr = JSON.stringify(resp); + _LibraryUtils.default.log(3, "Received response from path='" + path + "', response=" + respStr.substring(0, Math.min(1000, respStr.length)) + "(" + (new Date().getTime() - startTime) + " ms)"); + } + + // check rpc response for errors + this.validateRpcResponse(resp, path, params); + return resp; + } catch (err) { + if (err instanceof _MoneroRpcError.default) throw err;else + throw new _MoneroRpcError.default(err, err.statusCode, path, params); + } + }); + } + + /** + * Send a binary RPC request. + * + * @param {string} path - path of the binary RPC method to invoke + * @param {object} [params] - request parameters + * @param {number} [timeoutMs] - request timeout in milliseconds + * @return {Uint8Array} the binary response + */ + async sendBinaryRequest(path, params, timeoutMs) { + return this.queueSendRequest(async () => { + + // serialize params + let paramsBin = await _MoneroUtils.default.jsonToBinary(params); + + try { + + // logging + if (_LibraryUtils.default.getLogLevel() >= 2) _LibraryUtils.default.log(2, "Sending binary request with path '" + path + "' and params: " + JSON.stringify(params)); + + // proxy uri is not supported + if (this.getProxyUri()) throw new _MoneroError.default("Proxy URI not supported for binary requests"); + + // send http request + let resp = await _HttpClient.default.request({ + method: "POST", + uri: this.getUri() + '/' + path, + username: this.getUsername(), + password: this.getPassword(), + body: paramsBin, + timeout: timeoutMs === undefined ? this.timeoutMs : timeoutMs, + rejectUnauthorized: this.rejectUnauthorized, + proxyToWorker: this.proxyToWorker + }); + + // validate response + MoneroRpcConnection.validateHttpResponse(resp); + + // process response + resp = resp.body; + if (!(resp instanceof Uint8Array)) { + console.error("resp is not uint8array"); + console.error(resp); + } + if (resp.error) throw new _MoneroRpcError.default(resp.error.message, resp.error.code, path, params); + return resp; + } catch (err) { + if (err instanceof _MoneroRpcError.default) throw err;else + throw new _MoneroRpcError.default(err, err.statusCode, path, params); + } + }); + } + + getConfig() { + return { + uri: this.uri, + username: this.username, + password: this.password, + zmqUri: this.zmqUri, + proxyUri: this.proxyUri, + rejectUnauthorized: this.rejectUnauthorized, + proxyToWorker: this.proxyToWorker, + priority: this.priority, + timeoutMs: this.timeoutMs + }; + } + + toJson() { + let json = Object.assign({}, this); + json.checkConnectionMutex = undefined; + json.sendRequestMutex = undefined; + return json; + } + + toString() { + return this.getUri() + " (username=" + this.getUsername() + ", password=" + (this.getPassword() ? "***" : this.getPassword()) + ", zmqUri=" + this.getZmqUri() + ", proxyUri=" + this.getProxyUri() + ", priority=" + this.getPriority() + ", timeoutMs=" + this.getTimeout() + ", isOnline=" + this.getIsOnline() + ", isAuthenticated=" + this.getIsAuthenticated() + ")"; + } + + setFakeDisconnected(fakeDisconnected) {// used to test connection manager + this.fakeDisconnected = fakeDisconnected; + } + + // ------------------------------ PRIVATE HELPERS -------------------------- + + async queueCheckConnection(asyncFn) { + return this.checkConnectionMutex.submit(asyncFn); + } + + async queueSendRequest(asyncFn) { + return this.sendRequestMutex.submit(asyncFn); + } + + static validateHttpResponse(resp) { + let code = resp.statusCode; + if (code < 200 || code > 299) { + let content = resp.body; + throw new _MoneroRpcError.default(code + " " + resp.statusText + (!content ? "" : ": " + content), code, undefined, undefined); + } + } + + validateRpcResponse(resp, method, params) { + if (resp.error === undefined) return; + let errorMsg = resp.error.message; + if (errorMsg === "") errorMsg = "Received error response from RPC request with method '" + method + "' to " + this.getUri(); // TODO (monero-project): response sometimes has empty error message + throw new _MoneroRpcError.default(resp.error.message, resp.error.code, method, params); + } +}exports.default = MoneroRpcConnection; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfR2VuVXRpbHMiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9IdHRwQ2xpZW50IiwiX0xpYnJhcnlVdGlscyIsIl9Nb25lcm9FcnJvciIsIl9Nb25lcm9ScGNFcnJvciIsIl9Nb25lcm9VdGlscyIsIl9UaHJlYWRQb29sIiwiTW9uZXJvUnBjQ29ubmVjdGlvbiIsIkRFRkFVTFRfQ09ORklHIiwidXJpIiwidW5kZWZpbmVkIiwidXNlcm5hbWUiLCJwYXNzd29yZCIsInptcVVyaSIsInByb3h5VXJpIiwicmVqZWN0VW5hdXRob3JpemVkIiwicHJveHlUb1dvcmtlciIsInByaW9yaXR5IiwidGltZW91dE1zIiwiY29uc3RydWN0b3IiLCJ1cmlPckNvbm5lY3Rpb24iLCJPYmplY3QiLCJhc3NpZ24iLCJzZXRDcmVkZW50aWFscyIsIk1vbmVyb0Vycm9yIiwiR2VuVXRpbHMiLCJub3JtYWxpemVVcmkiLCJjaGVja0Nvbm5lY3Rpb25NdXRleCIsIlRocmVhZFBvb2wiLCJzZW5kUmVxdWVzdE11dGV4IiwiaXNPbmxpbmUiLCJpc0F1dGhlbnRpY2F0ZWQiLCJnZXRVcmkiLCJnZXRVc2VybmFtZSIsImdldFBhc3N3b3JkIiwiZ2V0Wm1xVXJpIiwic2V0Wm1xVXJpIiwiZ2V0UHJveHlVcmkiLCJzZXRQcm94eVVyaSIsImdldFJlamVjdFVuYXV0aG9yaXplZCIsInNldFByb3h5VG9Xb3JrZXIiLCJnZXRQcm94eVRvV29ya2VyIiwic2V0UHJpb3JpdHkiLCJnZXRQcmlvcml0eSIsInNldFRpbWVvdXQiLCJnZXRUaW1lb3V0Iiwic2V0QXR0cmlidXRlIiwia2V5IiwidmFsdWUiLCJhdHRyaWJ1dGVzIiwiTWFwIiwicHV0IiwiZ2V0QXR0cmlidXRlIiwiZ2V0IiwiY2hlY2tDb25uZWN0aW9uIiwicXVldWVDaGVja0Nvbm5lY3Rpb24iLCJMaWJyYXJ5VXRpbHMiLCJsb2FkV2FzbU1vZHVsZSIsImlzT25saW5lQmVmb3JlIiwiaXNBdXRoZW50aWNhdGVkQmVmb3JlIiwic3RhcnRUaW1lIiwiRGF0ZSIsIm5vdyIsImZha2VEaXNjb25uZWN0ZWQiLCJFcnJvciIsImhlaWdodHMiLCJpIiwicHVzaCIsInNlbmRCaW5hcnlSZXF1ZXN0IiwiZXJyIiwicmVzcG9uc2VUaW1lIiwiTW9uZXJvUnBjRXJyb3IiLCJnZXRDb2RlIiwiaXNDb25uZWN0ZWQiLCJnZXRJc09ubGluZSIsImdldElzQXV0aGVudGljYXRlZCIsImdldFJlc3BvbnNlVGltZSIsInNlbmRKc29uUmVxdWVzdCIsIm1ldGhvZCIsInBhcmFtcyIsInF1ZXVlU2VuZFJlcXVlc3QiLCJib2R5IiwiSlNPTiIsInN0cmluZ2lmeSIsImlkIiwianNvbnJwYyIsImdldExvZ0xldmVsIiwibG9nIiwiZ2V0VGltZSIsInJlc3AiLCJIdHRwQ2xpZW50IiwicmVxdWVzdCIsInRpbWVvdXQiLCJ2YWxpZGF0ZUh0dHBSZXNwb25zZSIsInBhcnNlIiwicmVwbGFjZSIsInJlc3BTdHIiLCJzdWJzdHJpbmciLCJNYXRoIiwibWluIiwibGVuZ3RoIiwidmFsaWRhdGVScGNSZXNwb25zZSIsInN0YXR1c0NvZGUiLCJzZW5kUGF0aFJlcXVlc3QiLCJwYXRoIiwicGFyYW1zQmluIiwiTW9uZXJvVXRpbHMiLCJqc29uVG9CaW5hcnkiLCJVaW50OEFycmF5IiwiY29uc29sZSIsImVycm9yIiwibWVzc2FnZSIsImNvZGUiLCJnZXRDb25maWciLCJ0b0pzb24iLCJqc29uIiwidG9TdHJpbmciLCJzZXRGYWtlRGlzY29ubmVjdGVkIiwiYXN5bmNGbiIsInN1Ym1pdCIsImNvbnRlbnQiLCJzdGF0dXNUZXh0IiwiZXJyb3JNc2ciLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2NvbW1vbi9Nb25lcm9ScGNDb25uZWN0aW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi9HZW5VdGlsc1wiO1xuaW1wb3J0IEh0dHBDbGllbnQgZnJvbSBcIi4vSHR0cENsaWVudFwiO1xuaW1wb3J0IExpYnJhcnlVdGlscyBmcm9tIFwiLi9MaWJyYXJ5VXRpbHNcIjtcbmltcG9ydCBNb25lcm9FcnJvciBmcm9tIFwiLi9Nb25lcm9FcnJvclwiO1xuaW1wb3J0IE1vbmVyb1JwY0Vycm9yIGZyb20gXCIuL01vbmVyb1JwY0Vycm9yXCI7XG5pbXBvcnQgTW9uZXJvVXRpbHMgZnJvbSBcIi4vTW9uZXJvVXRpbHNcIjtcbmltcG9ydCBUaHJlYWRQb29sIGZyb20gXCIuL1RocmVhZFBvb2xcIjtcblxuLyoqXG4gKiBNYWludGFpbnMgYSBjb25uZWN0aW9uIGFuZCBzZW5kcyByZXF1ZXN0cyB0byBhIE1vbmVybyBSUEMgQVBJLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9ScGNDb25uZWN0aW9uIHtcblxuICAvLyBwdWJsaWMgaW5zdGFuY2UgdmFyaWFibGVzXG4gIHVyaTogc3RyaW5nO1xuICB1c2VybmFtZTogc3RyaW5nO1xuICBwYXNzd29yZDogc3RyaW5nO1xuICB6bXFVcmk6IHN0cmluZztcbiAgcHJveHlVcmk6IHN0cmluZztcbiAgcmVqZWN0VW5hdXRob3JpemVkOiBib29sZWFuO1xuICBwcm94eVRvV29ya2VyOiBib29sZWFuO1xuICBwcmlvcml0eTogbnVtYmVyO1xuICB0aW1lb3V0TXM6IG51bWJlcjtcblxuICAvLyBwcml2YXRlIGluc3RhbmNlIHZhcmlhYmxlc1xuICBwcm90ZWN0ZWQgaXNPbmxpbmU6IGJvb2xlYW47XG4gIHByb3RlY3RlZCBpc0F1dGhlbnRpY2F0ZWQ6IGJvb2xlYW47XG4gIHByb3RlY3RlZCBhdHRyaWJ1dGVzOiBhbnk7XG4gIHByb3RlY3RlZCBmYWtlRGlzY29ubmVjdGVkOiBib29sZWFuO1xuICBwcm90ZWN0ZWQgcmVzcG9uc2VUaW1lOiBudW1iZXI7XG4gIHByb3RlY3RlZCBjaGVja0Nvbm5lY3Rpb25NdXRleDogVGhyZWFkUG9vbDtcbiAgcHJvdGVjdGVkIHNlbmRSZXF1ZXN0TXV0ZXg6IFRocmVhZFBvb2w7XG5cbiAgLy8gZGVmYXVsdCBjb25maWdcbiAgLyoqIEBwcml2YXRlICovXG4gIHN0YXRpYyBERUZBVUxUX0NPTkZJRzogUGFydGlhbDxNb25lcm9ScGNDb25uZWN0aW9uPiA9IHtcbiAgICB1cmk6IHVuZGVmaW5lZCxcbiAgICB1c2VybmFtZTogdW5kZWZpbmVkLFxuICAgIHBhc3N3b3JkOiB1bmRlZmluZWQsXG4gICAgem1xVXJpOiB1bmRlZmluZWQsXG4gICAgcHJveHlVcmk6IHVuZGVmaW5lZCxcbiAgICByZWplY3RVbmF1dGhvcml6ZWQ6IHRydWUsIC8vIHJlamVjdCBzZWxmLXNpZ25lZCBjZXJ0aWZpY2F0ZXMgaWYgdHJ1ZVxuICAgIHByb3h5VG9Xb3JrZXI6IGZhbHNlLFxuICAgIHByaW9yaXR5OiAwLFxuICAgIHRpbWVvdXRNczogdW5kZWZpbmVkXG4gIH1cblxuICAvKipcbiAgICogPHA+Q29uc3RydWN0IGEgUlBDIGNvbm5lY3Rpb24uPC9wPlxuICAgKiBcbiAgICogPHA+RXhhbXBsZXM6PC9wPlxuICAgKiBcbiAgICogPGNvZGU+XG4gICAqIGxldCBjb25uZWN0aW9uMSA9IG5ldyBNb25lcm9ScGNDb25uZWN0aW9uKFwiaHR0cDovL2xvY2FsaG9zdDozODA4MVwiLCBcImRhZW1vbl91c2VyXCIsIFwiZGFlbW9uX3Bhc3N3b3JkXzEyM1wiKTxicj48YnI+XG4gICAqIFxuICAgKiBsZXQgY29ubmVjdGlvbjIgPSBuZXcgTW9uZXJvUnBjQ29ubmVjdGlvbih7PGJyPlxuICAgKiAmbmJzcDsmbmJzcDsgdXJpOiBodHRwOi8vbG9jYWxob3N0OjM4MDgxLDxicj5cbiAgICogJm5ic3A7Jm5ic3A7IHVzZXJuYW1lOiBcImRhZW1vbl91c2VyXCIsPGJyPlxuICAgKiAmbmJzcDsmbmJzcDsgcGFzc3dvcmQ6IFwiZGFlbW9uX3Bhc3N3b3JkXzEyM1wiLDxicj5cbiAgICogJm5ic3A7Jm5ic3A7IHJlamVjdFVuYXV0aG9yaXplZDogZmFsc2UsIC8vIGFjY2VwdCBzZWxmLXNpZ25lZCBjZXJ0aWZpY2F0ZXMgZS5nLiBmb3IgbG9jYWwgZGV2ZWxvcG1lbnQ8YnI+XG4gICAqICZuYnNwOyZuYnNwOyBwcm94eVRvV29ya2VyOiB0cnVlIC8vIHByb3h5IHJlcXVlc3QgdG8gd29ya2VyIChkZWZhdWx0IGZhbHNlKTxicj5cbiAgICogfSk7XG4gICAqIDwvY29kZT5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfFBhcnRpYWw8TW9uZXJvUnBjQ29ubmVjdGlvbj59IHVyaU9yQ29ubmVjdGlvbiAtIE1vbmVyb1JwY0Nvbm5lY3Rpb24gb3IgVVJJIG9mIHRoZSBSUEMgZW5kcG9pbnRcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVyaU9yQ29ubmVjdGlvbi51cmkgLSBVUkkgb2YgdGhlIFJQQyBlbmRwb2ludFxuICAgKiBAcGFyYW0ge3N0cmluZ30gW3VyaU9yQ29ubmVjdGlvbi51c2VybmFtZV0gLSB1c2VybmFtZSB0byBhdXRoZW50aWNhdGUgd2l0aCB0aGUgUlBDIGVuZHBvaW50IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtzdHJpbmd9IFt1cmlPckNvbm5lY3Rpb24ucGFzc3dvcmRdIC0gcGFzc3dvcmQgdG8gYXV0aGVudGljYXRlIHdpdGggdGhlIFJQQyBlbmRwb2ludCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbdXJpT3JDb25uZWN0aW9uLnptcVVyaV0gLSBVUkkgb2YgdGhlIFpNUSBlbmRwb2ludCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbdXJpT3JDb25uZWN0aW9uLnByb3h5VXJpXSAtIFVSSSBvZiBhIHByb3h5IHNlcnZlciB0byByb3V0ZSByZXF1ZXN0cyB0aHJvdWdoIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtib29sZWFufSBbdXJpT3JDb25uZWN0aW9uLnJlamVjdFVuYXV0aG9yaXplZF0gLSByZWplY3RzIHNlbGYtc2lnbmVkIGNlcnRpZmljYXRlcyBpZiB0cnVlIChkZWZhdWx0IHRydWUpXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gdXJpT3JDb25uZWN0aW9uLnByb3h5VG9Xb3JrZXIgLSBwcm94eSByZXF1ZXN0cyB0byB3b3JrZXIgKGRlZmF1bHQgdHJ1ZSlcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVzZXJuYW1lIC0gdXNlcm5hbWUgdG8gYXV0aGVudGljYXRlIHdpdGggdGhlIFJQQyBlbmRwb2ludCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXNzd29yZCAtIHBhc3N3b3JkIHRvIGF1dGhlbnRpY2F0ZSB3aXRoIHRoZSBSUEMgZW5kcG9pbnQgKG9wdGlvbmFsKVxuICAgKi9cbiAgY29uc3RydWN0b3IodXJpT3JDb25uZWN0aW9uOiBzdHJpbmcgfCBQYXJ0aWFsPE1vbmVyb1JwY0Nvbm5lY3Rpb24+LCB1c2VybmFtZT86IHN0cmluZywgcGFzc3dvcmQ/OiBzdHJpbmcpIHtcblxuICAgIC8vIHZhbGlkYXRlIGFuZCBub3JtYWxpemUgY29uZmlnXG4gICAgaWYgKHR5cGVvZiB1cmlPckNvbm5lY3Rpb24gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIE9iamVjdC5hc3NpZ24odGhpcywgTW9uZXJvUnBjQ29ubmVjdGlvbi5ERUZBVUxUX0NPTkZJRyk7XG4gICAgICB0aGlzLnVyaSA9IHVyaU9yQ29ubmVjdGlvbjtcbiAgICAgIHRoaXMuc2V0Q3JlZGVudGlhbHModXNlcm5hbWUsIHBhc3N3b3JkKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHVzZXJuYW1lICE9PSB1bmRlZmluZWQgfHwgcGFzc3dvcmQgIT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ2FuIHByb3ZpZGUgY29uZmlnIG9iamVjdCBvciBwYXJhbXMgYnV0IG5vdCBib3RoXCIpO1xuICAgICAgT2JqZWN0LmFzc2lnbih0aGlzLCBNb25lcm9ScGNDb25uZWN0aW9uLkRFRkFVTFRfQ09ORklHLCB1cmlPckNvbm5lY3Rpb24pO1xuICAgICAgdGhpcy5zZXRDcmVkZW50aWFscyh0aGlzLnVzZXJuYW1lLCB0aGlzLnBhc3N3b3JkKTtcbiAgICB9XG4gICAgXG4gICAgLy8gbm9ybWFsaXplIHVyaXNcbiAgICBpZiAodGhpcy51cmkpIHRoaXMudXJpID0gR2VuVXRpbHMubm9ybWFsaXplVXJpKHRoaXMudXJpKTtcbiAgICBpZiAodGhpcy56bXFVcmkpIHRoaXMuem1xVXJpID0gR2VuVXRpbHMubm9ybWFsaXplVXJpKHRoaXMuem1xVXJpKTtcbiAgICBpZiAodGhpcy5wcm94eVVyaSkgdGhpcy5wcm94eVVyaSA9IEdlblV0aWxzLm5vcm1hbGl6ZVVyaSh0aGlzLnByb3h5VXJpKTtcblxuICAgIC8vIGluaXRpYWxpemUgbXV0ZXhlc1xuICAgIHRoaXMuY2hlY2tDb25uZWN0aW9uTXV0ZXggPSBuZXcgVGhyZWFkUG9vbCgxKTtcbiAgICB0aGlzLnNlbmRSZXF1ZXN0TXV0ZXggPSBuZXcgVGhyZWFkUG9vbCgxKTtcbiAgfVxuICBcbiAgc2V0Q3JlZGVudGlhbHModXNlcm5hbWUsIHBhc3N3b3JkKSB7XG4gICAgaWYgKHVzZXJuYW1lID09PSBcIlwiKSB1c2VybmFtZSA9IHVuZGVmaW5lZDtcbiAgICBpZiAocGFzc3dvcmQgPT09IFwiXCIpIHBhc3N3b3JkID0gdW5kZWZpbmVkO1xuICAgIGlmICh1c2VybmFtZSB8fCBwYXNzd29yZCkge1xuICAgICAgaWYgKCF1c2VybmFtZSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwidXNlcm5hbWUgbXVzdCBiZSBkZWZpbmVkIGJlY2F1c2UgcGFzc3dvcmQgaXMgZGVmaW5lZFwiKTtcbiAgICAgIGlmICghcGFzc3dvcmQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcInBhc3N3b3JkIG11c3QgYmUgZGVmaW5lZCBiZWNhdXNlIHVzZXJuYW1lIGlzIGRlZmluZWRcIik7XG4gICAgfVxuICAgIGlmICh0aGlzLnVzZXJuYW1lID09PSBcIlwiKSB0aGlzLnVzZXJuYW1lID0gdW5kZWZpbmVkO1xuICAgIGlmICh0aGlzLnBhc3N3b3JkID09PSBcIlwiKSB0aGlzLnBhc3N3b3JkID0gdW5kZWZpbmVkO1xuICAgIGlmICh0aGlzLnVzZXJuYW1lICE9PSB1c2VybmFtZSB8fCB0aGlzLnBhc3N3b3JkICE9PSBwYXNzd29yZCkge1xuICAgICAgdGhpcy5pc09ubGluZSA9IHVuZGVmaW5lZDtcbiAgICAgIHRoaXMuaXNBdXRoZW50aWNhdGVkID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgICB0aGlzLnVzZXJuYW1lID0gdXNlcm5hbWU7XG4gICAgdGhpcy5wYXNzd29yZCA9IHBhc3N3b3JkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRVcmkoKSB7XG4gICAgcmV0dXJuIHRoaXMudXJpO1xuICB9XG5cbiAgZ2V0VXNlcm5hbWUoKSB7XG4gICAgcmV0dXJuIHRoaXMudXNlcm5hbWUgPyB0aGlzLnVzZXJuYW1lIDogXCJcIjtcbiAgfVxuICBcbiAgZ2V0UGFzc3dvcmQoKSB7XG4gICAgcmV0dXJuIHRoaXMucGFzc3dvcmQgPyB0aGlzLnBhc3N3b3JkIDogXCJcIjtcbiAgfVxuXG4gIGdldFptcVVyaSgpIHtcbiAgICByZXR1cm4gdGhpcy56bXFVcmk7XG4gIH1cblxuICBzZXRabXFVcmkoem1xVXJpKSB7XG4gICAgdGhpcy56bXFVcmkgPSB6bXFVcmk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFByb3h5VXJpKCkge1xuICAgIHJldHVybiB0aGlzLnByb3h5VXJpO1xuICB9XG5cbiAgc2V0UHJveHlVcmkocHJveHlVcmkpIHtcbiAgICB0aGlzLnByb3h5VXJpID0gcHJveHlVcmk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFJlamVjdFVuYXV0aG9yaXplZCgpIHtcbiAgICByZXR1cm4gdGhpcy5yZWplY3RVbmF1dGhvcml6ZWQ7XG4gIH1cbiAgXG4gIHNldFByb3h5VG9Xb3JrZXIocHJveHlUb1dvcmtlcikge1xuICAgIHRoaXMucHJveHlUb1dvcmtlciA9IHByb3h5VG9Xb3JrZXI7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFByb3h5VG9Xb3JrZXIoKSB7XG4gICAgcmV0dXJuIHRoaXMucHJveHlUb1dvcmtlcjtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFNldCB0aGUgY29ubmVjdGlvbidzIHByaW9yaXR5IHJlbGF0aXZlIHRvIG90aGVyIGNvbm5lY3Rpb25zLiBQcmlvcml0eSAxIGlzIGhpZ2hlc3QsXG4gICAqIHRoZW4gcHJpb3JpdHkgMiwgZXRjLiBUaGUgZGVmYXVsdCBwcmlvcml0eSBvZiAwIGlzIGxvd2VzdCBwcmlvcml0eS5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbcHJpb3JpdHldIC0gdGhlIGNvbm5lY3Rpb24gcHJpb3JpdHkgKGRlZmF1bHQgMClcbiAgICogQHJldHVybiB7TW9uZXJvUnBjQ29ubmVjdGlvbn0gdGhpcyBjb25uZWN0aW9uXG4gICAqL1xuICBzZXRQcmlvcml0eShwcmlvcml0eSkge1xuICAgIGlmICghKHByaW9yaXR5ID49IDApKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJQcmlvcml0eSBtdXN0IGJlID49IDBcIik7XG4gICAgdGhpcy5wcmlvcml0eSA9IHByaW9yaXR5O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0UHJpb3JpdHkoKSB7XG4gICAgcmV0dXJuIHRoaXMucHJpb3JpdHk7IFxuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0aGUgUlBDIHJlcXVlc3QgdGltZW91dCBpbiBtaWxsaXNlY29uZHMuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gdGltZW91dE1zIGlzIHRoZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcywgMCB0byBkaXNhYmxlIHRpbWVvdXQsIG9yIHVuZGVmaW5lZCB0byB1c2UgZGVmYXVsdFxuICAgKiBAcmV0dXJuIHtNb25lcm9ScGNDb25uZWN0aW9ufSB0aGlzIGNvbm5lY3Rpb25cbiAgICovXG4gIHNldFRpbWVvdXQodGltZW91dE1zOiBudW1iZXIpIHtcbiAgICB0aGlzLnRpbWVvdXRNcyA9IHRpbWVvdXRNcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldFRpbWVvdXQoKSB7XG4gICAgcmV0dXJuIHRoaXMudGltZW91dE1zO1xuICB9XG4gIFxuICBzZXRBdHRyaWJ1dGUoa2V5LCB2YWx1ZSkge1xuICAgIGlmICghdGhpcy5hdHRyaWJ1dGVzKSB0aGlzLmF0dHJpYnV0ZXMgPSBuZXcgTWFwKCk7XG4gICAgdGhpcy5hdHRyaWJ1dGVzLnB1dChrZXksIHZhbHVlKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0QXR0cmlidXRlKGtleSkge1xuICAgIHJldHVybiB0aGlzLmF0dHJpYnV0ZXMuZ2V0KGtleSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDaGVjayB0aGUgY29ubmVjdGlvbiBzdGF0dXMgdG8gdXBkYXRlIGlzT25saW5lLCBpc0F1dGhlbnRpY2F0ZWQsIGFuZCByZXNwb25zZSB0aW1lLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IHRpbWVvdXRNcyAtIG1heGltdW0gcmVzcG9uc2UgdGltZSBiZWZvcmUgY29uc2lkZXJlZCBvZmZsaW5lXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbGVhbj59IHRydWUgaWYgdGhlcmUgaXMgYSBjaGFuZ2UgaW4gc3RhdHVzLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIGFzeW5jIGNoZWNrQ29ubmVjdGlvbih0aW1lb3V0TXMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICByZXR1cm4gdGhpcy5xdWV1ZUNoZWNrQ29ubmVjdGlvbihhc3luYyAoKSA9PiB7XG4gICAgICBhd2FpdCBMaWJyYXJ5VXRpbHMubG9hZFdhc21Nb2R1bGUoKTsgLy8gY2FjaGUgd2FzbSBmb3IgYmluYXJ5IHJlcXVlc3RcbiAgICAgIGxldCBpc09ubGluZUJlZm9yZSA9IHRoaXMuaXNPbmxpbmU7XG4gICAgICBsZXQgaXNBdXRoZW50aWNhdGVkQmVmb3JlID0gdGhpcy5pc0F1dGhlbnRpY2F0ZWQ7XG4gICAgICBsZXQgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGlmICh0aGlzLmZha2VEaXNjb25uZWN0ZWQpIHRocm93IG5ldyBFcnJvcihcIkNvbm5lY3Rpb24gaXMgZmFrZSBkaXNjb25uZWN0ZWRcIik7XG4gICAgICAgIGxldCBoZWlnaHRzID0gW107XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgMTAwOyBpKyspIGhlaWdodHMucHVzaChpKTtcbiAgICAgICAgYXdhaXQgdGhpcy5zZW5kQmluYXJ5UmVxdWVzdChcImdldF9ibG9ja3NfYnlfaGVpZ2h0LmJpblwiLCB7aGVpZ2h0czogaGVpZ2h0c30sIHRpbWVvdXRNcyk7IC8vIGFzc3VtZSBkYWVtb24gY29ubmVjdGlvblxuICAgICAgICB0aGlzLmlzT25saW5lID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5pc0F1dGhlbnRpY2F0ZWQgPSB0cnVlO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIHRoaXMuaXNPbmxpbmUgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5pc0F1dGhlbnRpY2F0ZWQgPSB1bmRlZmluZWQ7XG4gICAgICAgIHRoaXMucmVzcG9uc2VUaW1lID0gdW5kZWZpbmVkO1xuICAgICAgICBpZiAoZXJyIGluc3RhbmNlb2YgTW9uZXJvUnBjRXJyb3IpIHtcbiAgICAgICAgICBpZiAoZXJyLmdldENvZGUoKSA9PT0gNDAxKSB7XG4gICAgICAgICAgICB0aGlzLmlzT25saW5lID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMuaXNBdXRoZW50aWNhdGVkID0gZmFsc2U7XG4gICAgICAgICAgfSBlbHNlIGlmIChlcnIuZ2V0Q29kZSgpID09PSA0MDQpIHsgLy8gZmFsbGJhY2sgdG8gbGF0ZW5jeSBjaGVja1xuICAgICAgICAgICAgdGhpcy5pc09ubGluZSA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmlzQXV0aGVudGljYXRlZCA9IHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAodGhpcy5pc09ubGluZSkgdGhpcy5yZXNwb25zZVRpbWUgPSBEYXRlLm5vdygpIC0gc3RhcnRUaW1lO1xuICAgICAgcmV0dXJuIGlzT25saW5lQmVmb3JlICE9PSB0aGlzLmlzT25saW5lIHx8IGlzQXV0aGVudGljYXRlZEJlZm9yZSAhPT0gdGhpcy5pc0F1dGhlbnRpY2F0ZWQ7XG4gICAgfSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGNvbm5lY3Rpb24gaXMgY29ubmVjdGVkIGFjY29yZGluZyB0byB0aGUgbGFzdCBjYWxsIHRvIGNoZWNrQ29ubmVjdGlvbigpLjxicj48YnI+XG4gICAqIFxuICAgKiBOb3RlOiBtdXN0IGNhbGwgY2hlY2tDb25uZWN0aW9uKCkgbWFudWFsbHkgdW5sZXNzIHVzaW5nIE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyLlxuICAgKiBcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gdHJ1ZSBvciBmYWxzZSB0byBpbmRpY2F0ZSBpZiBjb25uZWN0ZWQsIG9yIHVuZGVmaW5lZCBpZiBjaGVja0Nvbm5lY3Rpb24oKSBoYXMgbm90IGJlZW4gY2FsbGVkXG4gICAqL1xuICBpc0Nvbm5lY3RlZCgpIHtcbiAgICByZXR1cm4gdGhpcy5pc09ubGluZSA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogdGhpcy5pc09ubGluZSAmJiB0aGlzLmlzQXV0aGVudGljYXRlZCAhPT0gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIHRoZSBjb25uZWN0aW9uIGlzIG9ubGluZSBhY2NvcmRpbmcgdG8gdGhlIGxhc3QgY2FsbCB0byBjaGVja0Nvbm5lY3Rpb24oKS48YnI+PGJyPlxuICAgKiBcbiAgICogTm90ZTogbXVzdCBjYWxsIGNoZWNrQ29ubmVjdGlvbigpIG1hbnVhbGx5IHVubGVzcyB1c2luZyBNb25lcm9Db25uZWN0aW9uTWFuYWdlci5cbiAgICogXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgb3IgZmFsc2UgdG8gaW5kaWNhdGUgaWYgb25saW5lLCBvciB1bmRlZmluZWQgaWYgY2hlY2tDb25uZWN0aW9uKCkgaGFzIG5vdCBiZWVuIGNhbGxlZFxuICAgKi9cbiAgZ2V0SXNPbmxpbmUoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNPbmxpbmU7XG4gIH1cblxuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIHRoZSBjb25uZWN0aW9uIGlzIGF1dGhlbnRpY2F0ZWQgYWNjb3JkaW5nIHRvIHRoZSBsYXN0IGNhbGwgdG8gY2hlY2tDb25uZWN0aW9uKCkuPGJyPjxicj5cbiAgICogXG4gICAqIE5vdGU6IG11c3QgY2FsbCBjaGVja0Nvbm5lY3Rpb24oKSBtYW51YWxseSB1bmxlc3MgdXNpbmcgTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIGF1dGhlbnRpY2F0ZWQgb3Igbm8gYXV0aGVudGljYXRpb24sIGZhbHNlIGlmIG5vdCBhdXRoZW50aWNhdGVkLCBvciB1bmRlZmluZWQgaWYgY2hlY2tDb25uZWN0aW9uKCkgaGFzIG5vdCBiZWVuIGNhbGxlZFxuICAgKi9cbiAgZ2V0SXNBdXRoZW50aWNhdGVkKCkge1xuICAgIHJldHVybiB0aGlzLmlzQXV0aGVudGljYXRlZDtcbiAgfVxuXG4gIGdldFJlc3BvbnNlVGltZSgpIHtcbiAgICByZXR1cm4gdGhpcy5yZXNwb25zZVRpbWU7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZW5kIGEgSlNPTiBSUEMgcmVxdWVzdC5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXRob2QgLSBKU09OIFJQQyBtZXRob2QgdG8gaW52b2tlXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJhbXMgLSByZXF1ZXN0IHBhcmFtZXRlcnNcbiAgICogQHBhcmFtIHtudW1iZXJ9IFt0aW1lb3V0TXNdIC0gb3ZlcnJpZGVzIHRoZSByZXF1ZXN0IHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzXG4gICAqIEByZXR1cm4ge29iamVjdH0gaXMgdGhlIHJlc3BvbnNlIG1hcFxuICAgKi9cbiAgYXN5bmMgc2VuZEpzb25SZXF1ZXN0KG1ldGhvZCwgcGFyYW1zPywgdGltZW91dE1zPyk6IFByb21pc2U8YW55PiB7XG4gICAgcmV0dXJuIHRoaXMucXVldWVTZW5kUmVxdWVzdChhc3luYyAoKSA9PiB7XG4gICAgICB0cnkge1xuXG4gICAgICAgIC8vIGJ1aWxkIHJlcXVlc3QgYm9keVxuICAgICAgICBsZXQgYm9keSA9IEpTT04uc3RyaW5naWZ5KHsgIC8vIGJvZHkgaXMgc3RyaW5naWZpZWQgc28gdGV4dC9wbGFpbiBpcyByZXR1cm5lZCBzbyBiaWdpbnRzIGFyZSBwcmVzZXJ2ZWRcbiAgICAgICAgICBpZDogXCIwXCIsXG4gICAgICAgICAganNvbnJwYzogXCIyLjBcIixcbiAgICAgICAgICBtZXRob2Q6IG1ldGhvZCxcbiAgICAgICAgICBwYXJhbXM6IHBhcmFtc1xuICAgICAgICB9KTtcbiAgXG4gICAgICAgIC8vIGxvZ2dpbmdcbiAgICAgICAgaWYgKExpYnJhcnlVdGlscy5nZXRMb2dMZXZlbCgpID49IDIpIExpYnJhcnlVdGlscy5sb2coMiwgXCJTZW5kaW5nIGpzb24gcmVxdWVzdCB3aXRoIG1ldGhvZCAnXCIgKyBtZXRob2QgKyBcIicgYW5kIGJvZHk6IFwiICsgYm9keSk7XG5cbiAgICAgICAgLy8gcHJveHkgdXJpIGlzIG5vdCBzdXBwb3J0ZWRcbiAgICAgICAgaWYgKHRoaXMuZ2V0UHJveHlVcmkoKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiUHJveHkgVVJJIG5vdCBzdXBwb3J0ZWQgZm9yIEpTT04gcmVxdWVzdHNcIik7XG4gICAgICAgIFxuICAgICAgICAvLyBzZW5kIGh0dHAgcmVxdWVzdFxuICAgICAgICBsZXQgc3RhcnRUaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgICAgIGxldCByZXNwID0gYXdhaXQgSHR0cENsaWVudC5yZXF1ZXN0KHtcbiAgICAgICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgICAgIHVyaTogdGhpcy5nZXRVcmkoKSArICcvanNvbl9ycGMnLFxuICAgICAgICAgIHVzZXJuYW1lOiB0aGlzLmdldFVzZXJuYW1lKCksXG4gICAgICAgICAgcGFzc3dvcmQ6IHRoaXMuZ2V0UGFzc3dvcmQoKSxcbiAgICAgICAgICBib2R5OiBib2R5LFxuICAgICAgICAgIHRpbWVvdXQ6IHRpbWVvdXRNcyA9PT0gdW5kZWZpbmVkID8gdGhpcy50aW1lb3V0TXMgOiB0aW1lb3V0TXMsXG4gICAgICAgICAgcmVqZWN0VW5hdXRob3JpemVkOiB0aGlzLnJlamVjdFVuYXV0aG9yaXplZCxcbiAgICAgICAgICBwcm94eVRvV29ya2VyOiB0aGlzLnByb3h5VG9Xb3JrZXJcbiAgICAgICAgfSk7XG4gICAgICAgIFxuICAgICAgICAvLyB2YWxpZGF0ZSByZXNwb25zZVxuICAgICAgICBNb25lcm9ScGNDb25uZWN0aW9uLnZhbGlkYXRlSHR0cFJlc3BvbnNlKHJlc3ApO1xuICAgICAgICBcbiAgICAgICAgLy8gZGVzZXJpYWxpemUgcmVzcG9uc2VcbiAgICAgICAgaWYgKHJlc3AuYm9keVswXSAhPSAneycpIHRocm93IHJlc3AuYm9keTtcbiAgICAgICAgcmVzcCA9IEpTT04ucGFyc2UocmVzcC5ib2R5LnJlcGxhY2UoLyhcIlteXCJdKlwiXFxzKjpcXHMqKShcXGR7MTYsfSkvZywgJyQxXCIkMlwiJykpOyAgLy8gcmVwbGFjZSAxNiBvciBtb3JlIGRpZ2l0cyB3aXRoIHN0cmluZ3MgYW5kIHBhcnNlXG4gICAgICAgIGlmIChMaWJyYXJ5VXRpbHMuZ2V0TG9nTGV2ZWwoKSA+PSAzKSB7XG4gICAgICAgICAgbGV0IHJlc3BTdHIgPSBKU09OLnN0cmluZ2lmeShyZXNwKTtcbiAgICAgICAgICBMaWJyYXJ5VXRpbHMubG9nKDMsIFwiUmVjZWl2ZWQgcmVzcG9uc2UgZnJvbSBtZXRob2Q9J1wiICsgbWV0aG9kICsgXCInLCByZXNwb25zZT1cIiArIHJlc3BTdHIuc3Vic3RyaW5nKDAsIE1hdGgubWluKDEwMDAsIHJlc3BTdHIubGVuZ3RoKSkgKyBcIihcIiArIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0VGltZSkgKyBcIiBtcylcIik7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIGNoZWNrIHJwYyByZXNwb25zZSBmb3IgZXJyb3JzXG4gICAgICAgIHRoaXMudmFsaWRhdGVScGNSZXNwb25zZShyZXNwLCBtZXRob2QsIHBhcmFtcyk7XG4gICAgICAgIHJldHVybiByZXNwO1xuICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgaWYgKGVyciBpbnN0YW5jZW9mIE1vbmVyb1JwY0Vycm9yKSB0aHJvdyBlcnI7XG4gICAgICAgIGVsc2UgdGhyb3cgbmV3IE1vbmVyb1JwY0Vycm9yKGVyciwgZXJyLnN0YXR1c0NvZGUsIG1ldGhvZCwgcGFyYW1zKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFNlbmQgYSBSUEMgcmVxdWVzdCB0byB0aGUgZ2l2ZW4gcGF0aCBhbmQgd2l0aCB0aGUgZ2l2ZW4gcGFyYW10ZXJzLlxuICAgKiBcbiAgICogRS5nLiBcIi9nZXRfdHJhbnNhY3Rpb25zXCIgd2l0aCBwYXJhbXNcbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gSlNPTiBSUEMgcGF0aCB0byBpbnZva2VcbiAgICogQHBhcmFtIHtvYmplY3R9IHBhcmFtcyAtIHJlcXVlc3QgcGFyYW1ldGVyc1xuICAgKiBAcGFyYW0ge251bWJlcn0gW3RpbWVvdXRNc10gLSBvdmVycmlkZXMgdGhlIHJlcXVlc3QgdGltZW91dCBpbiBtaWxsaXNlY29uZHNcbiAgICogQHJldHVybiB7b2JqZWN0fSBpcyB0aGUgcmVzcG9uc2UgbWFwXG4gICAqL1xuICBhc3luYyBzZW5kUGF0aFJlcXVlc3QocGF0aCwgcGFyYW1zPywgdGltZW91dE1zPyk6IFByb21pc2U8YW55PiB7XG4gICAgcmV0dXJuIHRoaXMucXVldWVTZW5kUmVxdWVzdChhc3luYyAoKSA9PiB7XG4gICAgICB0cnkge1xuXG4gICAgICAgIC8vIGxvZ2dpbmdcbiAgICAgICAgaWYgKExpYnJhcnlVdGlscy5nZXRMb2dMZXZlbCgpID49IDIpIExpYnJhcnlVdGlscy5sb2coMiwgXCJTZW5kaW5nIHBhdGggcmVxdWVzdCB3aXRoIHBhdGggJ1wiICsgcGF0aCArIFwiJyBhbmQgcGFyYW1zOiBcIiArIEpTT04uc3RyaW5naWZ5KHBhcmFtcykpO1xuXG4gICAgICAgIC8vIHByb3h5IHVyaSBpcyBub3Qgc3VwcG9ydGVkXG4gICAgICAgIGlmICh0aGlzLmdldFByb3h5VXJpKCkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlByb3h5IFVSSSBub3Qgc3VwcG9ydGVkIGZvciBwYXRoIHJlcXVlc3RzXCIpO1xuICAgICAgICBcbiAgICAgICAgLy8gc2VuZCBodHRwIHJlcXVlc3RcbiAgICAgICAgbGV0IHN0YXJ0VGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgICAgICBsZXQgcmVzcCA9IGF3YWl0IEh0dHBDbGllbnQucmVxdWVzdCh7XG4gICAgICAgICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgICAgICB1cmk6IHRoaXMuZ2V0VXJpKCkgKyAnLycgKyBwYXRoLFxuICAgICAgICAgIHVzZXJuYW1lOiB0aGlzLmdldFVzZXJuYW1lKCksXG4gICAgICAgICAgcGFzc3dvcmQ6IHRoaXMuZ2V0UGFzc3dvcmQoKSxcbiAgICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeShwYXJhbXMpLCAgLy8gYm9keSBpcyBzdHJpbmdpZmllZCBzbyB0ZXh0L3BsYWluIGlzIHJldHVybmVkIHNvIGJpZ2ludHMgYXJlIHByZXNlcnZlZFxuICAgICAgICAgIHRpbWVvdXQ6IHRpbWVvdXRNcyA9PT0gdW5kZWZpbmVkID8gdGhpcy50aW1lb3V0TXMgOiB0aW1lb3V0TXMsXG4gICAgICAgICAgcmVqZWN0VW5hdXRob3JpemVkOiB0aGlzLnJlamVjdFVuYXV0aG9yaXplZCxcbiAgICAgICAgICBwcm94eVRvV29ya2VyOiB0aGlzLnByb3h5VG9Xb3JrZXJcbiAgICAgICAgfSk7XG4gICAgICAgIFxuICAgICAgICAvLyB2YWxpZGF0ZSByZXNwb25zZVxuICAgICAgICBNb25lcm9ScGNDb25uZWN0aW9uLnZhbGlkYXRlSHR0cFJlc3BvbnNlKHJlc3ApO1xuICAgICAgICBcbiAgICAgICAgLy8gZGVzZXJpYWxpemUgcmVzcG9uc2VcbiAgICAgICAgaWYgKHJlc3AuYm9keVswXSAhPSAneycpIHRocm93IHJlc3AuYm9keTtcbiAgICAgICAgcmVzcCA9IEpTT04ucGFyc2UocmVzcC5ib2R5LnJlcGxhY2UoLyhcIlteXCJdKlwiXFxzKjpcXHMqKShcXGR7MTYsfSkvZywgJyQxXCIkMlwiJykpOyAgLy8gcmVwbGFjZSAxNiBvciBtb3JlIGRpZ2l0cyB3aXRoIHN0cmluZ3MgYW5kIHBhcnNlXG4gICAgICAgIGlmICh0eXBlb2YgcmVzcCA9PT0gXCJzdHJpbmdcIikgcmVzcCA9IEpTT04ucGFyc2UocmVzcCk7ICAvLyBUT0RPOiBzb21lIHJlc3BvbnNlcyByZXR1cm5lZCBhcyBzdHJpbmdzP1xuICAgICAgICBpZiAoTGlicmFyeVV0aWxzLmdldExvZ0xldmVsKCkgPj0gMykge1xuICAgICAgICAgIGxldCByZXNwU3RyID0gSlNPTi5zdHJpbmdpZnkocmVzcCk7XG4gICAgICAgICAgTGlicmFyeVV0aWxzLmxvZygzLCBcIlJlY2VpdmVkIHJlc3BvbnNlIGZyb20gcGF0aD0nXCIgKyBwYXRoICsgXCInLCByZXNwb25zZT1cIiArIHJlc3BTdHIuc3Vic3RyaW5nKDAsIE1hdGgubWluKDEwMDAsIHJlc3BTdHIubGVuZ3RoKSkgKyBcIihcIiArIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0VGltZSkgKyBcIiBtcylcIik7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIGNoZWNrIHJwYyByZXNwb25zZSBmb3IgZXJyb3JzXG4gICAgICAgIHRoaXMudmFsaWRhdGVScGNSZXNwb25zZShyZXNwLCBwYXRoLCBwYXJhbXMpO1xuICAgICAgICByZXR1cm4gcmVzcDtcbiAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBNb25lcm9ScGNFcnJvcikgdGhyb3cgZXJyO1xuICAgICAgICBlbHNlIHRocm93IG5ldyBNb25lcm9ScGNFcnJvcihlcnIsIGVyci5zdGF0dXNDb2RlLCBwYXRoLCBwYXJhbXMpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogU2VuZCBhIGJpbmFyeSBSUEMgcmVxdWVzdC5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gcGF0aCBvZiB0aGUgYmluYXJ5IFJQQyBtZXRob2QgdG8gaW52b2tlXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBbcGFyYW1zXSAtIHJlcXVlc3QgcGFyYW1ldGVyc1xuICAgKiBAcGFyYW0ge251bWJlcn0gW3RpbWVvdXRNc10gLSByZXF1ZXN0IHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzXG4gICAqIEByZXR1cm4ge1VpbnQ4QXJyYXl9IHRoZSBiaW5hcnkgcmVzcG9uc2VcbiAgICovXG4gIGFzeW5jIHNlbmRCaW5hcnlSZXF1ZXN0KHBhdGgsIHBhcmFtcz8sIHRpbWVvdXRNcz8pOiBQcm9taXNlPGFueT4ge1xuICAgIHJldHVybiB0aGlzLnF1ZXVlU2VuZFJlcXVlc3QoYXN5bmMgKCkgPT4ge1xuXG4gICAgICAvLyBzZXJpYWxpemUgcGFyYW1zXG4gICAgICBsZXQgcGFyYW1zQmluID0gYXdhaXQgTW9uZXJvVXRpbHMuanNvblRvQmluYXJ5KHBhcmFtcyk7XG4gICAgICAgICAgXG4gICAgICB0cnkge1xuXG4gICAgICAgIC8vIGxvZ2dpbmdcbiAgICAgICAgaWYgKExpYnJhcnlVdGlscy5nZXRMb2dMZXZlbCgpID49IDIpIExpYnJhcnlVdGlscy5sb2coMiwgXCJTZW5kaW5nIGJpbmFyeSByZXF1ZXN0IHdpdGggcGF0aCAnXCIgKyBwYXRoICsgXCInIGFuZCBwYXJhbXM6IFwiICsgSlNPTi5zdHJpbmdpZnkocGFyYW1zKSk7XG5cbiAgICAgICAgLy8gcHJveHkgdXJpIGlzIG5vdCBzdXBwb3J0ZWRcbiAgICAgICAgaWYgKHRoaXMuZ2V0UHJveHlVcmkoKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiUHJveHkgVVJJIG5vdCBzdXBwb3J0ZWQgZm9yIGJpbmFyeSByZXF1ZXN0c1wiKTtcbiAgICAgICAgXG4gICAgICAgIC8vIHNlbmQgaHR0cCByZXF1ZXN0XG4gICAgICAgIGxldCByZXNwID0gYXdhaXQgSHR0cENsaWVudC5yZXF1ZXN0KHtcbiAgICAgICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgICAgIHVyaTogdGhpcy5nZXRVcmkoKSArICcvJyArIHBhdGgsXG4gICAgICAgICAgdXNlcm5hbWU6IHRoaXMuZ2V0VXNlcm5hbWUoKSxcbiAgICAgICAgICBwYXNzd29yZDogdGhpcy5nZXRQYXNzd29yZCgpLFxuICAgICAgICAgIGJvZHk6IHBhcmFtc0JpbixcbiAgICAgICAgICB0aW1lb3V0OiB0aW1lb3V0TXMgPT09IHVuZGVmaW5lZCA/IHRoaXMudGltZW91dE1zIDogdGltZW91dE1zLFxuICAgICAgICAgIHJlamVjdFVuYXV0aG9yaXplZDogdGhpcy5yZWplY3RVbmF1dGhvcml6ZWQsXG4gICAgICAgICAgcHJveHlUb1dvcmtlcjogdGhpcy5wcm94eVRvV29ya2VyXG4gICAgICAgIH0pO1xuICAgICAgICBcbiAgICAgICAgLy8gdmFsaWRhdGUgcmVzcG9uc2VcbiAgICAgICAgTW9uZXJvUnBjQ29ubmVjdGlvbi52YWxpZGF0ZUh0dHBSZXNwb25zZShyZXNwKTtcbiAgICAgICAgXG4gICAgICAgIC8vIHByb2Nlc3MgcmVzcG9uc2VcbiAgICAgICAgcmVzcCA9IHJlc3AuYm9keTtcbiAgICAgICAgaWYgKCEocmVzcCBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcInJlc3AgaXMgbm90IHVpbnQ4YXJyYXlcIik7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihyZXNwKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAocmVzcC5lcnJvcikgdGhyb3cgbmV3IE1vbmVyb1JwY0Vycm9yKHJlc3AuZXJyb3IubWVzc2FnZSwgcmVzcC5lcnJvci5jb2RlLCBwYXRoLCBwYXJhbXMpO1xuICAgICAgICByZXR1cm4gcmVzcDtcbiAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIGlmIChlcnIgaW5zdGFuY2VvZiBNb25lcm9ScGNFcnJvcikgdGhyb3cgZXJyO1xuICAgICAgICBlbHNlIHRocm93IG5ldyBNb25lcm9ScGNFcnJvcihlcnIsIGVyci5zdGF0dXNDb2RlLCBwYXRoLCBwYXJhbXMpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgZ2V0Q29uZmlnKCkge1xuICAgIHJldHVybiB7XG4gICAgICB1cmk6IHRoaXMudXJpLFxuICAgICAgdXNlcm5hbWU6IHRoaXMudXNlcm5hbWUsXG4gICAgICBwYXNzd29yZDogdGhpcy5wYXNzd29yZCxcbiAgICAgIHptcVVyaTogdGhpcy56bXFVcmksXG4gICAgICBwcm94eVVyaTogdGhpcy5wcm94eVVyaSxcbiAgICAgIHJlamVjdFVuYXV0aG9yaXplZDogdGhpcy5yZWplY3RVbmF1dGhvcml6ZWQsXG4gICAgICBwcm94eVRvV29ya2VyOiB0aGlzLnByb3h5VG9Xb3JrZXIsXG4gICAgICBwcmlvcml0eTogdGhpcy5wcmlvcml0eSxcbiAgICAgIHRpbWVvdXRNczogdGhpcy50aW1lb3V0TXNcbiAgICB9O1xuICB9XG5cbiAgdG9Kc29uKCkge1xuICAgIGxldCBqc29uID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcylcbiAgICBqc29uLmNoZWNrQ29ubmVjdGlvbk11dGV4ID0gdW5kZWZpbmVkO1xuICAgIGpzb24uc2VuZFJlcXVlc3RNdXRleCA9IHVuZGVmaW5lZDtcbiAgICByZXR1cm4ganNvbjtcbiAgfVxuICBcbiAgdG9TdHJpbmcoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0VXJpKCkgKyBcIiAodXNlcm5hbWU9XCIgKyB0aGlzLmdldFVzZXJuYW1lKCkgKyBcIiwgcGFzc3dvcmQ9XCIgKyAodGhpcy5nZXRQYXNzd29yZCgpID8gXCIqKipcIiA6IHRoaXMuZ2V0UGFzc3dvcmQoKSkgKyBcIiwgem1xVXJpPVwiICsgdGhpcy5nZXRabXFVcmkoKSArIFwiLCBwcm94eVVyaT1cIiArIHRoaXMuZ2V0UHJveHlVcmkoKSArIFwiLCBwcmlvcml0eT1cIiArIHRoaXMuZ2V0UHJpb3JpdHkoKSArIFwiLCB0aW1lb3V0TXM9XCIgKyB0aGlzLmdldFRpbWVvdXQoKSArIFwiLCBpc09ubGluZT1cIiArIHRoaXMuZ2V0SXNPbmxpbmUoKSArIFwiLCBpc0F1dGhlbnRpY2F0ZWQ9XCIgKyB0aGlzLmdldElzQXV0aGVudGljYXRlZCgpICsgXCIpXCI7XG4gIH1cblxuICBzZXRGYWtlRGlzY29ubmVjdGVkKGZha2VEaXNjb25uZWN0ZWQpIHsgLy8gdXNlZCB0byB0ZXN0IGNvbm5lY3Rpb24gbWFuYWdlclxuICAgIHRoaXMuZmFrZURpc2Nvbm5lY3RlZCA9IGZha2VEaXNjb25uZWN0ZWQ7IFxuICB9XG4gIFxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gUFJJVkFURSBIRUxQRVJTIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgcHJvdGVjdGVkIGFzeW5jIHF1ZXVlQ2hlY2tDb25uZWN0aW9uPFQ+KGFzeW5jRm46ICgpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgICByZXR1cm4gdGhpcy5jaGVja0Nvbm5lY3Rpb25NdXRleC5zdWJtaXQoYXN5bmNGbik7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgcXVldWVTZW5kUmVxdWVzdDxUPihhc3luY0ZuOiAoKSA9PiBQcm9taXNlPFQ+KTogUHJvbWlzZTxUPiB7XG4gICAgcmV0dXJuIHRoaXMuc2VuZFJlcXVlc3RNdXRleC5zdWJtaXQoYXN5bmNGbik7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgdmFsaWRhdGVIdHRwUmVzcG9uc2UocmVzcCkge1xuICAgIGxldCBjb2RlID0gcmVzcC5zdGF0dXNDb2RlO1xuICAgIGlmIChjb2RlIDwgMjAwIHx8IGNvZGUgPiAyOTkpIHtcbiAgICAgIGxldCBjb250ZW50ID0gcmVzcC5ib2R5O1xuICAgICAgdGhyb3cgbmV3IE1vbmVyb1JwY0Vycm9yKGNvZGUgKyBcIiBcIiArIHJlc3Auc3RhdHVzVGV4dCArICghY29udGVudCA/IFwiXCIgOiAoXCI6IFwiICsgY29udGVudCkpLCBjb2RlLCB1bmRlZmluZWQsIHVuZGVmaW5lZCk7XG4gICAgfVxuICB9XG4gIFxuICBwcm90ZWN0ZWQgdmFsaWRhdGVScGNSZXNwb25zZShyZXNwLCBtZXRob2QsIHBhcmFtcykge1xuICAgIGlmIChyZXNwLmVycm9yID09PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICBsZXQgZXJyb3JNc2cgPSByZXNwLmVycm9yLm1lc3NhZ2U7XG4gICAgaWYgKGVycm9yTXNnID09PSBcIlwiKSBlcnJvck1zZyA9IFwiUmVjZWl2ZWQgZXJyb3IgcmVzcG9uc2UgZnJvbSBSUEMgcmVxdWVzdCB3aXRoIG1ldGhvZCAnXCIgKyBtZXRob2QgKyBcIicgdG8gXCIgKyB0aGlzLmdldFVyaSgpOyAvLyBUT0RPIChtb25lcm8tcHJvamVjdCk6IHJlc3BvbnNlIHNvbWV0aW1lcyBoYXMgZW1wdHkgZXJyb3IgbWVzc2FnZVxuICAgIHRocm93IG5ldyBNb25lcm9ScGNFcnJvcihyZXNwLmVycm9yLm1lc3NhZ2UsIHJlc3AuZXJyb3IuY29kZSwgbWV0aG9kLCBwYXJhbXMpO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJ5TEFBQSxJQUFBQSxTQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxXQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRSxhQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRyxZQUFBLEdBQUFKLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBSSxlQUFBLEdBQUFMLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBSyxZQUFBLEdBQUFOLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBTSxXQUFBLEdBQUFQLHNCQUFBLENBQUFDLE9B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 \ No newline at end of file diff --git a/dist/src/main/ts/common/MoneroRpcError.d.ts b/dist/src/main/ts/common/MoneroRpcError.d.ts new file mode 100644 index 000000000..7dfe72e9d --- /dev/null +++ b/dist/src/main/ts/common/MoneroRpcError.d.ts @@ -0,0 +1,20 @@ +import MoneroError from "./MoneroError"; +/** + * Error when interacting with Monero RPC. + */ +export default class MoneroRpcError extends MoneroError { + protected rpcMethod: any; + protected rpcParams: any; + /** + * Constructs the error. + * + * @param {string} rpcDescription is a description of the error from rpc + * @param {number} rpcCode is the error code from rpc + * @param {string} [rpcMethod] is the rpc method invoked + * @param {object} [rpcParams] are parameters sent with the rpc request + */ + constructor(rpcDescription: any, rpcCode: any, rpcMethod?: any, rpcParams?: any); + getRpcMethod(): any; + getRpcParams(): any; + toString(): string; +} diff --git a/dist/src/main/ts/common/MoneroRpcError.js b/dist/src/main/ts/common/MoneroRpcError.js new file mode 100644 index 000000000..b9d136823 --- /dev/null +++ b/dist/src/main/ts/common/MoneroRpcError.js @@ -0,0 +1,40 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _MoneroError = _interopRequireDefault(require("./MoneroError")); + +/** + * Error when interacting with Monero RPC. + */ +class MoneroRpcError extends _MoneroError.default { + + // instance variables + + + + /** + * Constructs the error. + * + * @param {string} rpcDescription is a description of the error from rpc + * @param {number} rpcCode is the error code from rpc + * @param {string} [rpcMethod] is the rpc method invoked + * @param {object} [rpcParams] are parameters sent with the rpc request + */ + constructor(rpcDescription, rpcCode, rpcMethod, rpcParams) { + super(rpcDescription, rpcCode); + this.rpcMethod = rpcMethod; + this.rpcParams = rpcParams; + } + + getRpcMethod() { + return this.rpcMethod; + } + + getRpcParams() { + return this.rpcParams; + } + + toString() { + let str = super.toString(); + if (this.rpcMethod) str += "\nRPC request: '" + this.rpcMethod + "'"; + return str; + } +}exports.default = MoneroRpcError; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfTW9uZXJvRXJyb3IiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIk1vbmVyb1JwY0Vycm9yIiwiTW9uZXJvRXJyb3IiLCJjb25zdHJ1Y3RvciIsInJwY0Rlc2NyaXB0aW9uIiwicnBjQ29kZSIsInJwY01ldGhvZCIsInJwY1BhcmFtcyIsImdldFJwY01ldGhvZCIsImdldFJwY1BhcmFtcyIsInRvU3RyaW5nIiwic3RyIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9jb21tb24vTW9uZXJvUnBjRXJyb3IudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IE1vbmVyb0Vycm9yIGZyb20gXCIuL01vbmVyb0Vycm9yXCI7XG5cbi8qKlxuICogRXJyb3Igd2hlbiBpbnRlcmFjdGluZyB3aXRoIE1vbmVybyBSUEMuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb1JwY0Vycm9yIGV4dGVuZHMgTW9uZXJvRXJyb3Ige1xuXG4gIC8vIGluc3RhbmNlIHZhcmlhYmxlc1xuICBwcm90ZWN0ZWQgcnBjTWV0aG9kOiBhbnk7XG4gIHByb3RlY3RlZCBycGNQYXJhbXM6IGFueTtcbiAgXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIHRoZSBlcnJvci5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBycGNEZXNjcmlwdGlvbiBpcyBhIGRlc2NyaXB0aW9uIG9mIHRoZSBlcnJvciBmcm9tIHJwY1xuICAgKiBAcGFyYW0ge251bWJlcn0gcnBjQ29kZSBpcyB0aGUgZXJyb3IgY29kZSBmcm9tIHJwY1xuICAgKiBAcGFyYW0ge3N0cmluZ30gW3JwY01ldGhvZF0gaXMgdGhlIHJwYyBtZXRob2QgaW52b2tlZFxuICAgKiBAcGFyYW0ge29iamVjdH0gW3JwY1BhcmFtc10gYXJlIHBhcmFtZXRlcnMgc2VudCB3aXRoIHRoZSBycGMgcmVxdWVzdFxuICAgKi9cbiAgY29uc3RydWN0b3IocnBjRGVzY3JpcHRpb24sIHJwY0NvZGUsIHJwY01ldGhvZD8sIHJwY1BhcmFtcz8pIHtcbiAgICBzdXBlcihycGNEZXNjcmlwdGlvbiwgcnBjQ29kZSk7XG4gICAgdGhpcy5ycGNNZXRob2QgPSBycGNNZXRob2Q7XG4gICAgdGhpcy5ycGNQYXJhbXMgPSBycGNQYXJhbXM7XG4gIH1cbiAgXG4gIGdldFJwY01ldGhvZCgpIHtcbiAgICByZXR1cm4gdGhpcy5ycGNNZXRob2Q7XG4gIH1cbiAgXG4gIGdldFJwY1BhcmFtcygpIHtcbiAgICByZXR1cm4gdGhpcy5ycGNQYXJhbXM7XG4gIH1cbiAgXG4gIHRvU3RyaW5nKCkge1xuICAgIGxldCBzdHIgPSBzdXBlci50b1N0cmluZygpO1xuICAgIGlmICh0aGlzLnJwY01ldGhvZCkgc3RyICs9IFwiXFxuUlBDIHJlcXVlc3Q6ICdcIiArIHRoaXMucnBjTWV0aG9kICsgXCInXCI7XG4gICAgcmV0dXJuIHN0cjtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsWUFBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBOztBQUVBO0FBQ0E7QUFDQTtBQUNlLE1BQU1DLGNBQWMsU0FBU0Msb0JBQVcsQ0FBQzs7RUFFdEQ7Ozs7RUFJQTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0VDLFdBQVdBLENBQUNDLGNBQWMsRUFBRUMsT0FBTyxFQUFFQyxTQUFVLEVBQUVDLFNBQVUsRUFBRTtJQUMzRCxLQUFLLENBQUNILGNBQWMsRUFBRUMsT0FBTyxDQUFDO0lBQzlCLElBQUksQ0FBQ0MsU0FBUyxHQUFHQSxTQUFTO0lBQzFCLElBQUksQ0FBQ0MsU0FBUyxHQUFHQSxTQUFTO0VBQzVCOztFQUVBQyxZQUFZQSxDQUFBLEVBQUc7SUFDYixPQUFPLElBQUksQ0FBQ0YsU0FBUztFQUN2Qjs7RUFFQUcsWUFBWUEsQ0FBQSxFQUFHO0lBQ2IsT0FBTyxJQUFJLENBQUNGLFNBQVM7RUFDdkI7O0VBRUFHLFFBQVFBLENBQUEsRUFBRztJQUNULElBQUlDLEdBQUcsR0FBRyxLQUFLLENBQUNELFFBQVEsQ0FBQyxDQUFDO0lBQzFCLElBQUksSUFBSSxDQUFDSixTQUFTLEVBQUVLLEdBQUcsSUFBSSxrQkFBa0IsR0FBRyxJQUFJLENBQUNMLFNBQVMsR0FBRyxHQUFHO0lBQ3BFLE9BQU9LLEdBQUc7RUFDWjtBQUNGLENBQUNDLE9BQUEsQ0FBQUMsT0FBQSxHQUFBWixjQUFBIn0= \ No newline at end of file diff --git a/dist/src/main/ts/common/MoneroUtils.d.ts b/dist/src/main/ts/common/MoneroUtils.d.ts new file mode 100644 index 000000000..2c249ae73 --- /dev/null +++ b/dist/src/main/ts/common/MoneroUtils.d.ts @@ -0,0 +1,207 @@ +import MoneroNetworkType from "../daemon/model/MoneroNetworkType"; +/** + * Collection of Monero utilities. Runs in a worker thread by default. + */ +export default class MoneroUtils { + static PROXY_TO_WORKER: boolean; + static NUM_MNEMONIC_WORDS: number; + static AU_PER_XMR: bigint; + static RING_SIZE: number; + /** + *

Get the version of the monero-ts library.

+ * + * @return {string} the version of this monero-ts library + */ + static getVersion(): string; + /** + * Enable or disable proxying these utilities to a worker thread. + * + * @param {boolean} proxyToWorker - specifies if utilities should be proxied to a worker + */ + static setProxyToWorker(proxyToWorker: any): void; + /** + * Validate the given mnemonic, throw an error if invalid. + * + * TODO: improve validation, use network type + * + * @param {string} mnemonic - mnemonic to validate + */ + static validateMnemonic(mnemonic: any): Promise; + /** + * Indicates if a private view key is valid. + * + * @param {string} privateViewKey is the private view key to validate + * @return {Promise} true if the private view key is valid, false otherwise + */ + static isValidPrivateViewKey(privateViewKey: any): Promise; + /** + * Indicates if a public view key is valid. + * + * @param {string} publicViewKey is the public view key to validate + * @return {Promise} true if the public view key is valid, false otherwise + */ + static isValidPublicViewKey(publicViewKey: any): Promise; + /** + * Indicates if a private spend key is valid. + * + * @param {string} privateSpendKey is the private spend key to validate + * @return {Promise} true if the private spend key is valid, false otherwise + */ + static isValidPrivateSpendKey(privateSpendKey: any): Promise; + /** + * Indicates if a public spend key is valid. + * + * @param {string} publicSpendKey is the public spend key to validate + * @return {Promise} true if the public spend key is valid, false otherwise + */ + static isValidPublicSpendKey(publicSpendKey: any): Promise; + /** + * Validate the given private view key, throw an error if invalid. + * + * @param {string} privateViewKey - private view key to validate + */ + static validatePrivateViewKey(privateViewKey: any): Promise; + /** + * Validate the given public view key, throw an error if invalid. + * + * @param {string} publicViewKey - public view key to validate + */ + static validatePublicViewKey(publicViewKey: any): Promise; + /** + * Validate the given private spend key, throw an error if invalid. + * + * @param {string} privateSpendKey - private spend key to validate + */ + static validatePrivateSpendKey(privateSpendKey: any): Promise; + /** + * Validate the given public spend key, throw an error if invalid. + * + * @param {string} publicSpendKey - public spend key to validate + */ + static validatePublicSpendKey(publicSpendKey: any): Promise; + /** + * Get an integrated address. + * + * @param {MoneroNetworkType} networkType - network type of the integrated address + * @param {string} standardAddress - address to derive the integrated address from + * @param {string} [paymentId] - optionally specifies the integrated address's payment id (defaults to random payment id) + * @return {Promise} the integrated address + */ + static getIntegratedAddress(networkType: MoneroNetworkType, standardAddress: string, paymentId?: string): Promise; + /** + * Determine if the given address is valid. + * + * @param {string} address - address + * @param {MoneroNetworkType} networkType - network type of the address to validate + * @return {Promise} true if the address is valid, false otherwise + */ + static isValidAddress(address: any, networkType: any): Promise; + /** + * Validate the given address, throw an error if invalid. + * + * @param {string} address - address to validate + * @param {MoneroNetworkType} networkType - network type of the address to validate + */ + static validateAddress(address: any, networkType: any): Promise; + /** + * Determine if the given payment id is valid. + * + * @param {string} paymentId - payment id to determine if valid + * @return {Promise} true if the payment id is valid, false otherwise + */ + static isValidPaymentId(paymentId: any): Promise; + /** + * Validate the given payment id, throw an error if invalid. + * + * TODO: improve validation + * + * @param {string} paymentId - payment id to validate + */ + static validatePaymentId(paymentId: any): Promise; + /** + * Decode tx extra according to https://cryptonote.org/cns/cns005.txt and + * returns the last tx pub key. + * + * TODO: use c++ bridge for this + * + * @param [byte[]] txExtra - array of tx extra bytes + * @return {string} the last pub key as a hexidecimal string + */ + static getLastTxPubKey(txExtra: any): Promise; + /** + * Determines if two payment ids are functionally equal. + * + * For example, 03284e41c342f032 and 03284e41c342f032000000000000000000000000000000000000000000000000 are considered equal. + * + * @param {string} paymentId1 is a payment id to compare + * @param {string} paymentId2 is a payment id to compare + * @return {bool} true if the payment ids are equal, false otherwise + */ + static paymentIdsEqual(paymentId1: any, paymentId2: any): boolean; + /** + * Merges a transaction into a list of existing transactions. + * + * @param {MoneroTx[]} txs - existing transactions to merge into + * @param {MoneroTx} tx - transaction to merge into the list + */ + static mergeTx(txs: any, tx: any): void; + /** + * Convert the given JSON to a binary Uint8Array using Monero's portable storage format. + * + * @param {object} json - json to convert to binary + * @return {Promise} the json converted to portable storage binary + */ + static jsonToBinary(json: any): Promise; + /** + * Convert the given portable storage binary to JSON. + * + * @param {Uint8Array} uint8arr - binary data in Monero's portable storage format + * @return {Promise} JSON object converted from the binary data + */ + static binaryToJson(uint8arr: any): Promise; + /** + * Convert the binary response from daemon RPC block retrieval to JSON. + * + * @param {Uint8Array} uint8arr - binary response from daemon RPC when getting blocks + * @return {Promise} JSON object with the blocks data + */ + static binaryBlocksToJson(uint8arr: any): Promise; + /** + * Convert XMR to atomic units. + * + * @param {number | string} amountXmr - amount in XMR to convert to atomic units + * @return {bigint} amount in atomic units + */ + static xmrToAtomicUnits(amountXmr: number | string): bigint; + /** + * Convert atomic units to XMR. + * + * @param {bigint | string} amountAtomicUnits - amount in atomic units to convert to XMR + * @return {number} amount in XMR + */ + static atomicUnitsToXmr(amountAtomicUnits: bigint | string): number; + /** + * Divide one atomic units by another. + * + * @param {bigint} au1 dividend + * @param {bigint} au2 divisor + * @returns {number} the result + */ + static divide(au1: bigint, au2: bigint): number; + /** + * Multiply a bigint by a number or bigint. + * + * @param a bigint to multiply + * @param b bigint or number to multiply by + * @returns the product as a bigint + */ + static multiply(a: bigint, b: number | bigint): bigint; + protected static isHex64(str: any): boolean; + /** + * Determine if the given unlock time is a timestamp or block height. + * + * @param unlockTime is the unlock time to check + * @return {boolean} true if the unlock time is a timestamp, false if a block height + */ + static isTimestamp(unlockTime: bigint): boolean; +} diff --git a/dist/src/main/ts/common/MoneroUtils.js b/dist/src/main/ts/common/MoneroUtils.js new file mode 100644 index 000000000..5fe2fc4da --- /dev/null +++ b/dist/src/main/ts/common/MoneroUtils.js @@ -0,0 +1,477 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _decimal = _interopRequireDefault(require("decimal.js")); +var _GenUtils = _interopRequireDefault(require("./GenUtils")); +var _LibraryUtils = _interopRequireDefault(require("./LibraryUtils")); +var _MoneroError = _interopRequireDefault(require("./MoneroError")); +var _MoneroIntegratedAddress = _interopRequireDefault(require("../wallet/model/MoneroIntegratedAddress")); +var _MoneroNetworkType = _interopRequireDefault(require("../daemon/model/MoneroNetworkType")); + + +/** + * Collection of Monero utilities. Runs in a worker thread by default. + */ +class MoneroUtils { + + // static variables + static PROXY_TO_WORKER = false; + static NUM_MNEMONIC_WORDS = 25; + static AU_PER_XMR = 1000000000000n; + static RING_SIZE = 12; + + /** + *

Get the version of the monero-ts library.

+ * + * @return {string} the version of this monero-ts library + */ + static getVersion() { + return "0.11.6"; + } + + /** + * Enable or disable proxying these utilities to a worker thread. + * + * @param {boolean} proxyToWorker - specifies if utilities should be proxied to a worker + */ + static setProxyToWorker(proxyToWorker) { + MoneroUtils.PROXY_TO_WORKER = proxyToWorker || false; + } + + /** + * Validate the given mnemonic, throw an error if invalid. + * + * TODO: improve validation, use network type + * + * @param {string} mnemonic - mnemonic to validate + */ + static async validateMnemonic(mnemonic) { + (0, _assert.default)(mnemonic, "Mnemonic phrase is not initialized"); + let words = mnemonic.split(" "); + if (words.length !== MoneroUtils.NUM_MNEMONIC_WORDS) throw new _MoneroError.default("Mnemonic phrase is " + words.length + " words but must be " + MoneroUtils.NUM_MNEMONIC_WORDS); + } + + /** + * Indicates if a private view key is valid. + * + * @param {string} privateViewKey is the private view key to validate + * @return {Promise} true if the private view key is valid, false otherwise + */ + static async isValidPrivateViewKey(privateViewKey) { + try { + await MoneroUtils.validatePrivateViewKey(privateViewKey); + return true; + } catch (e) { + return false; + } + } + + /** + * Indicates if a public view key is valid. + * + * @param {string} publicViewKey is the public view key to validate + * @return {Promise} true if the public view key is valid, false otherwise + */ + static async isValidPublicViewKey(publicViewKey) { + try { + await MoneroUtils.validatePublicViewKey(publicViewKey); + return true; + } catch (e) { + return false; + } + } + + /** + * Indicates if a private spend key is valid. + * + * @param {string} privateSpendKey is the private spend key to validate + * @return {Promise} true if the private spend key is valid, false otherwise + */ + static async isValidPrivateSpendKey(privateSpendKey) { + try { + await MoneroUtils.validatePrivateSpendKey(privateSpendKey); + return true; + } catch (e) { + return false; + } + } + + /** + * Indicates if a public spend key is valid. + * + * @param {string} publicSpendKey is the public spend key to validate + * @return {Promise} true if the public spend key is valid, false otherwise + */ + static async isValidPublicSpendKey(publicSpendKey) { + try { + await MoneroUtils.validatePublicSpendKey(publicSpendKey); + return true; + } catch (e) { + return false; + } + } + + /** + * Validate the given private view key, throw an error if invalid. + * + * @param {string} privateViewKey - private view key to validate + */ + static async validatePrivateViewKey(privateViewKey) { + if (!MoneroUtils.isHex64(privateViewKey)) throw new _MoneroError.default("private view key expected to be 64 hex characters"); + } + + /** + * Validate the given public view key, throw an error if invalid. + * + * @param {string} publicViewKey - public view key to validate + */ + static async validatePublicViewKey(publicViewKey) { + if (!MoneroUtils.isHex64(publicViewKey)) throw new _MoneroError.default("public view key expected to be 64 hex characters"); + } + + /** + * Validate the given private spend key, throw an error if invalid. + * + * @param {string} privateSpendKey - private spend key to validate + */ + static async validatePrivateSpendKey(privateSpendKey) { + if (!MoneroUtils.isHex64(privateSpendKey)) throw new _MoneroError.default("private spend key expected to be 64 hex characters"); + } + + /** + * Validate the given public spend key, throw an error if invalid. + * + * @param {string} publicSpendKey - public spend key to validate + */ + static async validatePublicSpendKey(publicSpendKey) { + if (!MoneroUtils.isHex64(publicSpendKey)) throw new _MoneroError.default("public spend key expected to be 64 hex characters"); + } + + /** + * Get an integrated address. + * + * @param {MoneroNetworkType} networkType - network type of the integrated address + * @param {string} standardAddress - address to derive the integrated address from + * @param {string} [paymentId] - optionally specifies the integrated address's payment id (defaults to random payment id) + * @return {Promise} the integrated address + */ + static async getIntegratedAddress(networkType, standardAddress, paymentId) { + if (MoneroUtils.PROXY_TO_WORKER) return new _MoneroIntegratedAddress.default(await _LibraryUtils.default.invokeWorker(undefined, "moneroUtilsGetIntegratedAddress", Array.from(arguments))); + + // validate inputs + _MoneroNetworkType.default.validate(networkType); + (0, _assert.default)(typeof standardAddress === "string", "Address is not string"); + (0, _assert.default)(standardAddress.length > 0, "Address is empty"); + (0, _assert.default)(_GenUtils.default.isBase58(standardAddress), "Address is not base 58"); + + // load keys module by default + if (_LibraryUtils.default.getWasmModule() === undefined) await _LibraryUtils.default.loadWasmModule(); + + // get integrated address in queue + return _LibraryUtils.default.getWasmModule().queueTask(async () => { + let integratedAddressJson = _LibraryUtils.default.getWasmModule().get_integrated_address_util(networkType, standardAddress, paymentId ? paymentId : ""); + if (integratedAddressJson.charAt(0) !== '{') throw new _MoneroError.default(integratedAddressJson); + return new _MoneroIntegratedAddress.default(JSON.parse(integratedAddressJson)); + }); + } + + /** + * Determine if the given address is valid. + * + * @param {string} address - address + * @param {MoneroNetworkType} networkType - network type of the address to validate + * @return {Promise} true if the address is valid, false otherwise + */ + static async isValidAddress(address, networkType) { + try { + await MoneroUtils.validateAddress(address, networkType); + return true; + } catch (err) { + return false; + } + } + + /** + * Validate the given address, throw an error if invalid. + * + * @param {string} address - address to validate + * @param {MoneroNetworkType} networkType - network type of the address to validate + */ + static async validateAddress(address, networkType) { + if (MoneroUtils.PROXY_TO_WORKER) return _LibraryUtils.default.invokeWorker(undefined, "moneroUtilsValidateAddress", Array.from(arguments)); + + // validate inputs + (0, _assert.default)(typeof address === "string", "Address is not string"); + (0, _assert.default)(address.length > 0, "Address is empty"); + (0, _assert.default)(_GenUtils.default.isBase58(address), "Address is not base 58"); + networkType = _MoneroNetworkType.default.from(networkType); + + // load keys module by default + if (_LibraryUtils.default.getWasmModule() === undefined) await _LibraryUtils.default.loadWasmModule(); + + // validate address in queue + return _LibraryUtils.default.getWasmModule().queueTask(async function () { + let errMsg = _LibraryUtils.default.getWasmModule().validate_address(address, networkType); + if (errMsg) throw new _MoneroError.default(errMsg); + }); + } + + /** + * Determine if the given payment id is valid. + * + * @param {string} paymentId - payment id to determine if valid + * @return {Promise} true if the payment id is valid, false otherwise + */ + static async isValidPaymentId(paymentId) { + try { + await MoneroUtils.validatePaymentId(paymentId); + return true; + } catch (e) { + return false; + } + } + + /** + * Validate the given payment id, throw an error if invalid. + * + * TODO: improve validation + * + * @param {string} paymentId - payment id to validate + */ + static async validatePaymentId(paymentId) { + _assert.default.equal(typeof paymentId, "string"); + (0, _assert.default)(paymentId.length === 16 || paymentId.length === 64); + } + + /** + * Decode tx extra according to https://cryptonote.org/cns/cns005.txt and + * returns the last tx pub key. + * + * TODO: use c++ bridge for this + * + * @param [byte[]] txExtra - array of tx extra bytes + * @return {string} the last pub key as a hexidecimal string + */ + static async getLastTxPubKey(txExtra) { + let lastPubKeyIdx; + for (let i = 0; i < txExtra.length; i++) { + let tag = txExtra[i]; + if (tag === 0 || tag === 2) { + i += 1 + txExtra[i + 1]; // advance to next tag + } else if (tag === 1) { + lastPubKeyIdx = i + 1; + i += 1 + 32; // advance to next tag + } else throw new _MoneroError.default("Invalid sub-field tag: " + tag); + } + return Buffer.from(new Uint8Array(txExtra.slice(lastPubKeyIdx, lastPubKeyIdx + 32))).toString("hex"); + } + + /** + * Determines if two payment ids are functionally equal. + * + * For example, 03284e41c342f032 and 03284e41c342f032000000000000000000000000000000000000000000000000 are considered equal. + * + * @param {string} paymentId1 is a payment id to compare + * @param {string} paymentId2 is a payment id to compare + * @return {bool} true if the payment ids are equal, false otherwise + */ + static paymentIdsEqual(paymentId1, paymentId2) { + let maxLength = Math.max(paymentId1.length, paymentId2.length); + for (let i = 0; i < maxLength; i++) { + if (i < paymentId1.length && i < paymentId2.length && paymentId1[i] !== paymentId2[i]) return false; + if (i >= paymentId1.length && paymentId2[i] !== '0') return false; + if (i >= paymentId2.length && paymentId1[i] !== '0') return false; + } + return true; + } + + /** + * Merges a transaction into a list of existing transactions. + * + * @param {MoneroTx[]} txs - existing transactions to merge into + * @param {MoneroTx} tx - transaction to merge into the list + */ + static mergeTx(txs, tx) { + for (let aTx of txs) { + if (aTx.getHash() === tx.getHash()) { + aTx.merge(tx); + return; + } + } + txs.push(tx); + } + + /** + * Convert the given JSON to a binary Uint8Array using Monero's portable storage format. + * + * @param {object} json - json to convert to binary + * @return {Promise} the json converted to portable storage binary + */ + static async jsonToBinary(json) { + if (MoneroUtils.PROXY_TO_WORKER) return _LibraryUtils.default.invokeWorker(undefined, "moneroUtilsJsonToBinary", Array.from(arguments)); + + // load keys module by default + if (_LibraryUtils.default.getWasmModule() === undefined) await _LibraryUtils.default.loadWasmModule(); + + // use wasm in queue + return _LibraryUtils.default.getWasmModule().queueTask(async function () { + + // serialize json to binary which is stored in c++ heap + let binMemInfoStr = _LibraryUtils.default.getWasmModule().malloc_binary_from_json(JSON.stringify(json)); + + // sanitize binary memory address info + let binMemInfo = JSON.parse(binMemInfoStr); + binMemInfo.ptr = parseInt(binMemInfo.ptr); + binMemInfo.length = parseInt(binMemInfo.length); + + // read binary data from heap to Uint8Array + let view = new Uint8Array(binMemInfo.length); + for (let i = 0; i < binMemInfo.length; i++) { + view[i] = _LibraryUtils.default.getWasmModule().HEAPU8[binMemInfo.ptr / Uint8Array.BYTES_PER_ELEMENT + i]; + } + + // free binary on heap + _LibraryUtils.default.getWasmModule()._free(binMemInfo.ptr); + + // return json from binary data + return view; + }); + } + + /** + * Convert the given portable storage binary to JSON. + * + * @param {Uint8Array} uint8arr - binary data in Monero's portable storage format + * @return {Promise} JSON object converted from the binary data + */ + static async binaryToJson(uint8arr) { + if (MoneroUtils.PROXY_TO_WORKER) return _LibraryUtils.default.invokeWorker(undefined, "moneroUtilsBinaryToJson", Array.from(arguments)); + + // load keys module by default + if (_LibraryUtils.default.getWasmModule() === undefined) await _LibraryUtils.default.loadWasmModule(); + + // use wasm in queue + return _LibraryUtils.default.getWasmModule().queueTask(async function () { + + // allocate space in c++ heap for binary + let ptr = _LibraryUtils.default.getWasmModule()._malloc(uint8arr.length * uint8arr.BYTES_PER_ELEMENT); + let heap = new Uint8Array(_LibraryUtils.default.getWasmModule().HEAPU8.buffer, ptr, uint8arr.length * uint8arr.BYTES_PER_ELEMENT); + if (ptr !== heap.byteOffset) throw new _MoneroError.default("Memory ptr !== heap.byteOffset"); // should be equal + + // write binary to heap + heap.set(new Uint8Array(uint8arr.buffer)); + + // create object with binary memory address info + let binMemInfo = { ptr: ptr, length: uint8arr.length }; + + // convert binary to json str + const ret_string = _LibraryUtils.default.getWasmModule().binary_to_json(JSON.stringify(binMemInfo)); + + // free binary on heap + _LibraryUtils.default.getWasmModule()._free(ptr); + + // parse and return json + return JSON.parse(ret_string); + }); + } + + /** + * Convert the binary response from daemon RPC block retrieval to JSON. + * + * @param {Uint8Array} uint8arr - binary response from daemon RPC when getting blocks + * @return {Promise} JSON object with the blocks data + */ + static async binaryBlocksToJson(uint8arr) { + if (MoneroUtils.PROXY_TO_WORKER) return _LibraryUtils.default.invokeWorker(undefined, "moneroUtilsBinaryBlocksToJson", Array.from(arguments)); + + // load keys module by default + if (_LibraryUtils.default.getWasmModule() === undefined) await _LibraryUtils.default.loadWasmModule(); + + // use wasm in queue + return _LibraryUtils.default.getWasmModule().queueTask(async function () { + + // allocate space in c++ heap for binary + let ptr = _LibraryUtils.default.getWasmModule()._malloc(uint8arr.length * uint8arr.BYTES_PER_ELEMENT); + let heap = new Uint8Array(_LibraryUtils.default.getWasmModule().HEAPU8.buffer, ptr, uint8arr.length * uint8arr.BYTES_PER_ELEMENT); + if (ptr !== heap.byteOffset) throw new _MoneroError.default("Memory ptr !== heap.byteOffset"); // should be equal + + // write binary to heap + heap.set(new Uint8Array(uint8arr.buffer)); + + // create object with binary memory address info + let binMemInfo = { ptr: ptr, length: uint8arr.length }; + + // convert binary to json str + const json_str = _LibraryUtils.default.getWasmModule().binary_blocks_to_json(JSON.stringify(binMemInfo)); + + // free memory + _LibraryUtils.default.getWasmModule()._free(ptr); + + // parse result to json + let json = JSON.parse(json_str); // parsing json gives arrays of block and tx strings + json.blocks = json.blocks.map((blockStr) => JSON.parse(blockStr)); // replace block strings with parsed blocks + json.txs = json.txs.map((txs) => txs ? txs.map((tx) => JSON.parse(tx.replace(",", "{") + "}")) : []); // modify tx string to proper json and parse // TODO: more efficient way than this json manipulation? + return json; + }); + } + + /** + * Convert XMR to atomic units. + * + * @param {number | string} amountXmr - amount in XMR to convert to atomic units + * @return {bigint} amount in atomic units + */ + static xmrToAtomicUnits(amountXmr) { + return BigInt(new _decimal.default(amountXmr).mul(MoneroUtils.AU_PER_XMR.toString()).toDecimalPlaces(0, _decimal.default.ROUND_HALF_UP).toFixed(0)); + } + + /** + * Convert atomic units to XMR. + * + * @param {bigint | string} amountAtomicUnits - amount in atomic units to convert to XMR + * @return {number} amount in XMR + */ + static atomicUnitsToXmr(amountAtomicUnits) { + return new _decimal.default(amountAtomicUnits.toString()).div(MoneroUtils.AU_PER_XMR.toString()).toDecimalPlaces(12, _decimal.default.ROUND_HALF_UP).toNumber(); + } + + /** + * Divide one atomic units by another. + * + * @param {bigint} au1 dividend + * @param {bigint} au2 divisor + * @returns {number} the result + */ + static divide(au1, au2) { + return new _decimal.default(au1.toString()).div(new _decimal.default(au2.toString())).toDecimalPlaces(12, _decimal.default.ROUND_HALF_UP).toNumber(); + } + + /** + * Multiply a bigint by a number or bigint. + * + * @param a bigint to multiply + * @param b bigint or number to multiply by + * @returns the product as a bigint + */ + static multiply(a, b) { + return BigInt(new _decimal.default(a.toString()).mul(new _decimal.default(b.toString())).toDecimalPlaces(0, _decimal.default.ROUND_HALF_UP).toString()); + } + + static isHex64(str) { + return typeof str === "string" && str.length === 64 && _GenUtils.default.isHex(str); + } + + /** + * Determine if the given unlock time is a timestamp or block height. + * + * @param unlockTime is the unlock time to check + * @return {boolean} true if the unlock time is a timestamp, false if a block height + */ + static isTimestamp(unlockTime) { + + // threshold for distinguishing between timestamp and block height + // current block height is around 3 million, current unix timestamp is around 1.7 billion + const threshold = 500000000n; + + return unlockTime >= threshold; + } +}exports.default = MoneroUtils; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfZGVjaW1hbCIsIl9HZW5VdGlscyIsIl9MaWJyYXJ5VXRpbHMiLCJfTW9uZXJvRXJyb3IiLCJfTW9uZXJvSW50ZWdyYXRlZEFkZHJlc3MiLCJfTW9uZXJvTmV0d29ya1R5cGUiLCJNb25lcm9VdGlscyIsIlBST1hZX1RPX1dPUktFUiIsIk5VTV9NTkVNT05JQ19XT1JEUyIsIkFVX1BFUl9YTVIiLCJSSU5HX1NJWkUiLCJnZXRWZXJzaW9uIiwic2V0UHJveHlUb1dvcmtlciIsInByb3h5VG9Xb3JrZXIiLCJ2YWxpZGF0ZU1uZW1vbmljIiwibW5lbW9uaWMiLCJhc3NlcnQiLCJ3b3JkcyIsInNwbGl0IiwibGVuZ3RoIiwiTW9uZXJvRXJyb3IiLCJpc1ZhbGlkUHJpdmF0ZVZpZXdLZXkiLCJwcml2YXRlVmlld0tleSIsInZhbGlkYXRlUHJpdmF0ZVZpZXdLZXkiLCJlIiwiaXNWYWxpZFB1YmxpY1ZpZXdLZXkiLCJwdWJsaWNWaWV3S2V5IiwidmFsaWRhdGVQdWJsaWNWaWV3S2V5IiwiaXNWYWxpZFByaXZhdGVTcGVuZEtleSIsInByaXZhdGVTcGVuZEtleSIsInZhbGlkYXRlUHJpdmF0ZVNwZW5kS2V5IiwiaXNWYWxpZFB1YmxpY1NwZW5kS2V5IiwicHVibGljU3BlbmRLZXkiLCJ2YWxpZGF0ZVB1YmxpY1NwZW5kS2V5IiwiaXNIZXg2NCIsImdldEludGVncmF0ZWRBZGRyZXNzIiwibmV0d29ya1R5cGUiLCJzdGFuZGFyZEFkZHJlc3MiLCJwYXltZW50SWQiLCJNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcyIsIkxpYnJhcnlVdGlscyIsImludm9rZVdvcmtlciIsInVuZGVmaW5lZCIsIkFycmF5IiwiZnJvbSIsImFyZ3VtZW50cyIsIk1vbmVyb05ldHdvcmtUeXBlIiwidmFsaWRhdGUiLCJHZW5VdGlscyIsImlzQmFzZTU4IiwiZ2V0V2FzbU1vZHVsZSIsImxvYWRXYXNtTW9kdWxlIiwicXVldWVUYXNrIiwiaW50ZWdyYXRlZEFkZHJlc3NKc29uIiwiZ2V0X2ludGVncmF0ZWRfYWRkcmVzc191dGlsIiwiY2hhckF0IiwiSlNPTiIsInBhcnNlIiwiaXNWYWxpZEFkZHJlc3MiLCJhZGRyZXNzIiwidmFsaWRhdGVBZGRyZXNzIiwiZXJyIiwiZXJyTXNnIiwidmFsaWRhdGVfYWRkcmVzcyIsImlzVmFsaWRQYXltZW50SWQiLCJ2YWxpZGF0ZVBheW1lbnRJZCIsImVxdWFsIiwiZ2V0TGFzdFR4UHViS2V5IiwidHhFeHRyYSIsImxhc3RQdWJLZXlJZHgiLCJpIiwidGFnIiwiQnVmZmVyIiwiVWludDhBcnJheSIsInNsaWNlIiwidG9TdHJpbmciLCJwYXltZW50SWRzRXF1YWwiLCJwYXltZW50SWQxIiwicGF5bWVudElkMiIsIm1heExlbmd0aCIsIk1hdGgiLCJtYXgiLCJtZXJnZVR4IiwidHhzIiwidHgiLCJhVHgiLCJnZXRIYXNoIiwibWVyZ2UiLCJwdXNoIiwianNvblRvQmluYXJ5IiwianNvbiIsImJpbk1lbUluZm9TdHIiLCJtYWxsb2NfYmluYXJ5X2Zyb21fanNvbiIsInN0cmluZ2lmeSIsImJpbk1lbUluZm8iLCJwdHIiLCJwYXJzZUludCIsInZpZXciLCJIRUFQVTgiLCJCWVRFU19QRVJfRUxFTUVOVCIsIl9mcmVlIiwiYmluYXJ5VG9Kc29uIiwidWludDhhcnIiLCJfbWFsbG9jIiwiaGVhcCIsImJ1ZmZlciIsImJ5dGVPZmZzZXQiLCJzZXQiLCJyZXRfc3RyaW5nIiwiYmluYXJ5X3RvX2pzb24iLCJiaW5hcnlCbG9ja3NUb0pzb24iLCJqc29uX3N0ciIsImJpbmFyeV9ibG9ja3NfdG9fanNvbiIsImJsb2NrcyIsIm1hcCIsImJsb2NrU3RyIiwicmVwbGFjZSIsInhtclRvQXRvbWljVW5pdHMiLCJhbW91bnRYbXIiLCJCaWdJbnQiLCJEZWNpbWFsIiwibXVsIiwidG9EZWNpbWFsUGxhY2VzIiwiUk9VTkRfSEFMRl9VUCIsInRvRml4ZWQiLCJhdG9taWNVbml0c1RvWG1yIiwiYW1vdW50QXRvbWljVW5pdHMiLCJkaXYiLCJ0b051bWJlciIsImRpdmlkZSIsImF1MSIsImF1MiIsIm11bHRpcGx5IiwiYSIsImIiLCJzdHIiLCJpc0hleCIsImlzVGltZXN0YW1wIiwidW5sb2NrVGltZSIsInRocmVzaG9sZCIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvY29tbW9uL01vbmVyb1V0aWxzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IERlY2ltYWwgZnJvbSAnZGVjaW1hbC5qcyc7XG5pbXBvcnQgR2VuVXRpbHMgZnJvbSBcIi4vR2VuVXRpbHNcIjtcbmltcG9ydCBMaWJyYXJ5VXRpbHMgZnJvbSBcIi4vTGlicmFyeVV0aWxzXCI7XG5pbXBvcnQgTW9uZXJvRXJyb3IgZnJvbSBcIi4vTW9uZXJvRXJyb3JcIjtcbmltcG9ydCBNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcyBmcm9tIFwiLi4vd2FsbGV0L21vZGVsL01vbmVyb0ludGVncmF0ZWRBZGRyZXNzXCI7XG5pbXBvcnQgTW9uZXJvTmV0d29ya1R5cGUgZnJvbSBcIi4uL2RhZW1vbi9tb2RlbC9Nb25lcm9OZXR3b3JrVHlwZVwiO1xuaW1wb3J0IENvbm5lY3Rpb25UeXBlIGZyb20gXCIuLi9kYWVtb24vbW9kZWwvQ29ubmVjdGlvblR5cGVcIjtcblxuLyoqXG4gKiBDb2xsZWN0aW9uIG9mIE1vbmVybyB1dGlsaXRpZXMuIFJ1bnMgaW4gYSB3b3JrZXIgdGhyZWFkIGJ5IGRlZmF1bHQuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb1V0aWxzIHtcblxuICAvLyBzdGF0aWMgdmFyaWFibGVzXG4gIHN0YXRpYyBQUk9YWV9UT19XT1JLRVIgPSBmYWxzZTtcbiAgc3RhdGljIE5VTV9NTkVNT05JQ19XT1JEUyA9IDI1O1xuICBzdGF0aWMgQVVfUEVSX1hNUiA9IDEwMDAwMDAwMDAwMDBuO1xuICBzdGF0aWMgUklOR19TSVpFID0gMTI7XG5cbiAgLyoqXG4gICAqIDxwPkdldCB0aGUgdmVyc2lvbiBvZiB0aGUgbW9uZXJvLXRzIGxpYnJhcnkuPHA+XG4gICAqIFxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IHRoZSB2ZXJzaW9uIG9mIHRoaXMgbW9uZXJvLXRzIGxpYnJhcnlcbiAgICovXG4gIHN0YXRpYyBnZXRWZXJzaW9uKCkge1xuICAgIHJldHVybiBcIjAuMTEuNlwiO1xuICB9XG4gIFxuICAvKipcbiAgICogRW5hYmxlIG9yIGRpc2FibGUgcHJveHlpbmcgdGhlc2UgdXRpbGl0aWVzIHRvIGEgd29ya2VyIHRocmVhZC5cbiAgICogXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gcHJveHlUb1dvcmtlciAtIHNwZWNpZmllcyBpZiB1dGlsaXRpZXMgc2hvdWxkIGJlIHByb3hpZWQgdG8gYSB3b3JrZXJcbiAgICovXG4gIHN0YXRpYyBzZXRQcm94eVRvV29ya2VyKHByb3h5VG9Xb3JrZXIpIHtcbiAgICBNb25lcm9VdGlscy5QUk9YWV9UT19XT1JLRVIgPSBwcm94eVRvV29ya2VyIHx8IGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIHRoZSBnaXZlbiBtbmVtb25pYywgdGhyb3cgYW4gZXJyb3IgaWYgaW52YWxpZC5cbiAgICpcbiAgICogVE9ETzogaW1wcm92ZSB2YWxpZGF0aW9uLCB1c2UgbmV0d29yayB0eXBlXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gbW5lbW9uaWMgLSBtbmVtb25pYyB0byB2YWxpZGF0ZVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIHZhbGlkYXRlTW5lbW9uaWMobW5lbW9uaWMpIHtcbiAgICBhc3NlcnQobW5lbW9uaWMsIFwiTW5lbW9uaWMgcGhyYXNlIGlzIG5vdCBpbml0aWFsaXplZFwiKTtcbiAgICBsZXQgd29yZHMgPSBtbmVtb25pYy5zcGxpdChcIiBcIik7XG4gICAgaWYgKHdvcmRzLmxlbmd0aCAhPT0gTW9uZXJvVXRpbHMuTlVNX01ORU1PTklDX1dPUkRTKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJNbmVtb25pYyBwaHJhc2UgaXMgXCIgKyB3b3Jkcy5sZW5ndGggKyBcIiB3b3JkcyBidXQgbXVzdCBiZSBcIiArIE1vbmVyb1V0aWxzLk5VTV9NTkVNT05JQ19XT1JEUyk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgYSBwcml2YXRlIHZpZXcga2V5IGlzIHZhbGlkLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHByaXZhdGVWaWV3S2V5IGlzIHRoZSBwcml2YXRlIHZpZXcga2V5IHRvIHZhbGlkYXRlXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbD59IHRydWUgaWYgdGhlIHByaXZhdGUgdmlldyBrZXkgaXMgdmFsaWQsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGlzVmFsaWRQcml2YXRlVmlld0tleShwcml2YXRlVmlld0tleSkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBNb25lcm9VdGlscy52YWxpZGF0ZVByaXZhdGVWaWV3S2V5KHByaXZhdGVWaWV3S2V5KTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgYSBwdWJsaWMgdmlldyBrZXkgaXMgdmFsaWQuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcHVibGljVmlld0tleSBpcyB0aGUgcHVibGljIHZpZXcga2V5IHRvIHZhbGlkYXRlXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbD59IHRydWUgaWYgdGhlIHB1YmxpYyB2aWV3IGtleSBpcyB2YWxpZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgaXNWYWxpZFB1YmxpY1ZpZXdLZXkocHVibGljVmlld0tleSkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBNb25lcm9VdGlscy52YWxpZGF0ZVB1YmxpY1ZpZXdLZXkocHVibGljVmlld0tleSk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIGEgcHJpdmF0ZSBzcGVuZCBrZXkgaXMgdmFsaWQuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcHJpdmF0ZVNwZW5kS2V5IGlzIHRoZSBwcml2YXRlIHNwZW5kIGtleSB0byB2YWxpZGF0ZVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPGJvb2w+fSB0cnVlIGlmIHRoZSBwcml2YXRlIHNwZW5kIGtleSBpcyB2YWxpZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgaXNWYWxpZFByaXZhdGVTcGVuZEtleShwcml2YXRlU3BlbmRLZXkpIHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgTW9uZXJvVXRpbHMudmFsaWRhdGVQcml2YXRlU3BlbmRLZXkocHJpdmF0ZVNwZW5kS2V5KTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgYSBwdWJsaWMgc3BlbmQga2V5IGlzIHZhbGlkLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHB1YmxpY1NwZW5kS2V5IGlzIHRoZSBwdWJsaWMgc3BlbmQga2V5IHRvIHZhbGlkYXRlXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbD59IHRydWUgaWYgdGhlIHB1YmxpYyBzcGVuZCBrZXkgaXMgdmFsaWQsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGlzVmFsaWRQdWJsaWNTcGVuZEtleShwdWJsaWNTcGVuZEtleSkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBNb25lcm9VdGlscy52YWxpZGF0ZVB1YmxpY1NwZW5kS2V5KHB1YmxpY1NwZW5kS2V5KTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGUgZ2l2ZW4gcHJpdmF0ZSB2aWV3IGtleSwgdGhyb3cgYW4gZXJyb3IgaWYgaW52YWxpZC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHByaXZhdGVWaWV3S2V5IC0gcHJpdmF0ZSB2aWV3IGtleSB0byB2YWxpZGF0ZVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIHZhbGlkYXRlUHJpdmF0ZVZpZXdLZXkocHJpdmF0ZVZpZXdLZXkpIHtcbiAgICBpZiAoIU1vbmVyb1V0aWxzLmlzSGV4NjQocHJpdmF0ZVZpZXdLZXkpKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJwcml2YXRlIHZpZXcga2V5IGV4cGVjdGVkIHRvIGJlIDY0IGhleCBjaGFyYWN0ZXJzXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogVmFsaWRhdGUgdGhlIGdpdmVuIHB1YmxpYyB2aWV3IGtleSwgdGhyb3cgYW4gZXJyb3IgaWYgaW52YWxpZC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHB1YmxpY1ZpZXdLZXkgLSBwdWJsaWMgdmlldyBrZXkgdG8gdmFsaWRhdGVcbiAgICovXG4gIHN0YXRpYyBhc3luYyB2YWxpZGF0ZVB1YmxpY1ZpZXdLZXkocHVibGljVmlld0tleSkge1xuICAgIGlmICghTW9uZXJvVXRpbHMuaXNIZXg2NChwdWJsaWNWaWV3S2V5KSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwicHVibGljIHZpZXcga2V5IGV4cGVjdGVkIHRvIGJlIDY0IGhleCBjaGFyYWN0ZXJzXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogVmFsaWRhdGUgdGhlIGdpdmVuIHByaXZhdGUgc3BlbmQga2V5LCB0aHJvdyBhbiBlcnJvciBpZiBpbnZhbGlkLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcHJpdmF0ZVNwZW5kS2V5IC0gcHJpdmF0ZSBzcGVuZCBrZXkgdG8gdmFsaWRhdGVcbiAgICovXG4gIHN0YXRpYyBhc3luYyB2YWxpZGF0ZVByaXZhdGVTcGVuZEtleShwcml2YXRlU3BlbmRLZXkpIHtcbiAgICBpZiAoIU1vbmVyb1V0aWxzLmlzSGV4NjQocHJpdmF0ZVNwZW5kS2V5KSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwicHJpdmF0ZSBzcGVuZCBrZXkgZXhwZWN0ZWQgdG8gYmUgNjQgaGV4IGNoYXJhY3RlcnNcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGUgZ2l2ZW4gcHVibGljIHNwZW5kIGtleSwgdGhyb3cgYW4gZXJyb3IgaWYgaW52YWxpZC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHB1YmxpY1NwZW5kS2V5IC0gcHVibGljIHNwZW5kIGtleSB0byB2YWxpZGF0ZVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIHZhbGlkYXRlUHVibGljU3BlbmRLZXkocHVibGljU3BlbmRLZXkpIHtcbiAgICBpZiAoIU1vbmVyb1V0aWxzLmlzSGV4NjQocHVibGljU3BlbmRLZXkpKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJwdWJsaWMgc3BlbmQga2V5IGV4cGVjdGVkIHRvIGJlIDY0IGhleCBjaGFyYWN0ZXJzXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGFuIGludGVncmF0ZWQgYWRkcmVzcy5cbiAgICogXG4gICAqIEBwYXJhbSB7TW9uZXJvTmV0d29ya1R5cGV9IG5ldHdvcmtUeXBlIC0gbmV0d29yayB0eXBlIG9mIHRoZSBpbnRlZ3JhdGVkIGFkZHJlc3NcbiAgICogQHBhcmFtIHtzdHJpbmd9IHN0YW5kYXJkQWRkcmVzcyAtIGFkZHJlc3MgdG8gZGVyaXZlIHRoZSBpbnRlZ3JhdGVkIGFkZHJlc3MgZnJvbVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW3BheW1lbnRJZF0gLSBvcHRpb25hbGx5IHNwZWNpZmllcyB0aGUgaW50ZWdyYXRlZCBhZGRyZXNzJ3MgcGF5bWVudCBpZCAoZGVmYXVsdHMgdG8gcmFuZG9tIHBheW1lbnQgaWQpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvSW50ZWdyYXRlZEFkZHJlc3M+fSB0aGUgaW50ZWdyYXRlZCBhZGRyZXNzXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZ2V0SW50ZWdyYXRlZEFkZHJlc3MobmV0d29ya1R5cGU6IE1vbmVyb05ldHdvcmtUeXBlLCBzdGFuZGFyZEFkZHJlc3M6IHN0cmluZywgcGF5bWVudElkPzogc3RyaW5nKSB7XG4gICAgaWYgKE1vbmVyb1V0aWxzLlBST1hZX1RPX1dPUktFUikgcmV0dXJuIG5ldyBNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcyhhd2FpdCBMaWJyYXJ5VXRpbHMuaW52b2tlV29ya2VyKHVuZGVmaW5lZCwgXCJtb25lcm9VdGlsc0dldEludGVncmF0ZWRBZGRyZXNzXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSkpO1xuICBcbiAgICAvLyB2YWxpZGF0ZSBpbnB1dHNcbiAgICBNb25lcm9OZXR3b3JrVHlwZS52YWxpZGF0ZShuZXR3b3JrVHlwZSk7XG4gICAgYXNzZXJ0KHR5cGVvZiBzdGFuZGFyZEFkZHJlc3MgPT09IFwic3RyaW5nXCIsIFwiQWRkcmVzcyBpcyBub3Qgc3RyaW5nXCIpO1xuICAgIGFzc2VydChzdGFuZGFyZEFkZHJlc3MubGVuZ3RoID4gMCwgXCJBZGRyZXNzIGlzIGVtcHR5XCIpO1xuICAgIGFzc2VydChHZW5VdGlscy5pc0Jhc2U1OChzdGFuZGFyZEFkZHJlc3MpLCBcIkFkZHJlc3MgaXMgbm90IGJhc2UgNThcIik7XG4gICAgXG4gICAgLy8gbG9hZCBrZXlzIG1vZHVsZSBieSBkZWZhdWx0XG4gICAgaWYgKExpYnJhcnlVdGlscy5nZXRXYXNtTW9kdWxlKCkgPT09IHVuZGVmaW5lZCkgYXdhaXQgTGlicmFyeVV0aWxzLmxvYWRXYXNtTW9kdWxlKCk7XG4gICAgXG4gICAgLy8gZ2V0IGludGVncmF0ZWQgYWRkcmVzcyBpbiBxdWV1ZVxuICAgIHJldHVybiBMaWJyYXJ5VXRpbHMuZ2V0V2FzbU1vZHVsZSgpLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICBsZXQgaW50ZWdyYXRlZEFkZHJlc3NKc29uID0gTGlicmFyeVV0aWxzLmdldFdhc21Nb2R1bGUoKS5nZXRfaW50ZWdyYXRlZF9hZGRyZXNzX3V0aWwobmV0d29ya1R5cGUsIHN0YW5kYXJkQWRkcmVzcywgcGF5bWVudElkID8gcGF5bWVudElkIDogXCJcIik7XG4gICAgICBpZiAoaW50ZWdyYXRlZEFkZHJlc3NKc29uLmNoYXJBdCgwKSAhPT0gJ3snKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoaW50ZWdyYXRlZEFkZHJlc3NKc29uKTtcbiAgICAgIHJldHVybiBuZXcgTW9uZXJvSW50ZWdyYXRlZEFkZHJlc3MoSlNPTi5wYXJzZShpbnRlZ3JhdGVkQWRkcmVzc0pzb24pKTtcbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIERldGVybWluZSBpZiB0aGUgZ2l2ZW4gYWRkcmVzcyBpcyB2YWxpZC5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzIC0gYWRkcmVzc1xuICAgKiBAcGFyYW0ge01vbmVyb05ldHdvcmtUeXBlfSBuZXR3b3JrVHlwZSAtIG5ldHdvcmsgdHlwZSBvZiB0aGUgYWRkcmVzcyB0byB2YWxpZGF0ZVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPGJvb2xlYW4+fSB0cnVlIGlmIHRoZSBhZGRyZXNzIGlzIHZhbGlkLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIHN0YXRpYyBhc3luYyBpc1ZhbGlkQWRkcmVzcyhhZGRyZXNzLCBuZXR3b3JrVHlwZSkge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBNb25lcm9VdGlscy52YWxpZGF0ZUFkZHJlc3MoYWRkcmVzcywgbmV0d29ya1R5cGUpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogVmFsaWRhdGUgdGhlIGdpdmVuIGFkZHJlc3MsIHRocm93IGFuIGVycm9yIGlmIGludmFsaWQuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzIC0gYWRkcmVzcyB0byB2YWxpZGF0ZVxuICAgKiBAcGFyYW0ge01vbmVyb05ldHdvcmtUeXBlfSBuZXR3b3JrVHlwZSAtIG5ldHdvcmsgdHlwZSBvZiB0aGUgYWRkcmVzcyB0byB2YWxpZGF0ZVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIHZhbGlkYXRlQWRkcmVzcyhhZGRyZXNzLCBuZXR3b3JrVHlwZSkge1xuICAgIGlmIChNb25lcm9VdGlscy5QUk9YWV9UT19XT1JLRVIpIHJldHVybiBMaWJyYXJ5VXRpbHMuaW52b2tlV29ya2VyKHVuZGVmaW5lZCwgXCJtb25lcm9VdGlsc1ZhbGlkYXRlQWRkcmVzc1wiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICAgIFxuICAgIC8vIHZhbGlkYXRlIGlucHV0c1xuICAgIGFzc2VydCh0eXBlb2YgYWRkcmVzcyA9PT0gXCJzdHJpbmdcIiwgXCJBZGRyZXNzIGlzIG5vdCBzdHJpbmdcIik7XG4gICAgYXNzZXJ0KGFkZHJlc3MubGVuZ3RoID4gMCwgXCJBZGRyZXNzIGlzIGVtcHR5XCIpO1xuICAgIGFzc2VydChHZW5VdGlscy5pc0Jhc2U1OChhZGRyZXNzKSwgXCJBZGRyZXNzIGlzIG5vdCBiYXNlIDU4XCIpO1xuICAgIG5ldHdvcmtUeXBlID0gTW9uZXJvTmV0d29ya1R5cGUuZnJvbShuZXR3b3JrVHlwZSk7XG4gICAgXG4gICAgLy8gbG9hZCBrZXlzIG1vZHVsZSBieSBkZWZhdWx0XG4gICAgaWYgKExpYnJhcnlVdGlscy5nZXRXYXNtTW9kdWxlKCkgPT09IHVuZGVmaW5lZCkgYXdhaXQgTGlicmFyeVV0aWxzLmxvYWRXYXNtTW9kdWxlKCk7XG4gICAgXG4gICAgLy8gdmFsaWRhdGUgYWRkcmVzcyBpbiBxdWV1ZVxuICAgIHJldHVybiBMaWJyYXJ5VXRpbHMuZ2V0V2FzbU1vZHVsZSgpLnF1ZXVlVGFzayhhc3luYyBmdW5jdGlvbigpIHtcbiAgICAgIGxldCBlcnJNc2cgPSBMaWJyYXJ5VXRpbHMuZ2V0V2FzbU1vZHVsZSgpLnZhbGlkYXRlX2FkZHJlc3MoYWRkcmVzcywgbmV0d29ya1R5cGUpO1xuICAgICAgaWYgKGVyck1zZykgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKGVyck1zZyk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBEZXRlcm1pbmUgaWYgdGhlIGdpdmVuIHBheW1lbnQgaWQgaXMgdmFsaWQuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGF5bWVudElkIC0gcGF5bWVudCBpZCB0byBkZXRlcm1pbmUgaWYgdmFsaWRcbiAgICogQHJldHVybiB7UHJvbWlzZTxib29sPn0gdHJ1ZSBpZiB0aGUgcGF5bWVudCBpZCBpcyB2YWxpZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgaXNWYWxpZFBheW1lbnRJZChwYXltZW50SWQpIHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgTW9uZXJvVXRpbHMudmFsaWRhdGVQYXltZW50SWQocGF5bWVudElkKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGUgZ2l2ZW4gcGF5bWVudCBpZCwgdGhyb3cgYW4gZXJyb3IgaWYgaW52YWxpZC5cbiAgICogXG4gICAqIFRPRE86IGltcHJvdmUgdmFsaWRhdGlvblxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBheW1lbnRJZCAtIHBheW1lbnQgaWQgdG8gdmFsaWRhdGUgXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgdmFsaWRhdGVQYXltZW50SWQocGF5bWVudElkKSB7XG4gICAgYXNzZXJ0LmVxdWFsKHR5cGVvZiBwYXltZW50SWQsIFwic3RyaW5nXCIpO1xuICAgIGFzc2VydChwYXltZW50SWQubGVuZ3RoID09PSAxNiB8fCBwYXltZW50SWQubGVuZ3RoID09PSA2NCk7XG4gIH1cbiAgICBcbiAgLyoqXG4gICAqIERlY29kZSB0eCBleHRyYSBhY2NvcmRpbmcgdG8gaHR0cHM6Ly9jcnlwdG9ub3RlLm9yZy9jbnMvY25zMDA1LnR4dCBhbmRcbiAgICogcmV0dXJucyB0aGUgbGFzdCB0eCBwdWIga2V5LlxuICAgKiBcbiAgICogVE9ETzogdXNlIGMrKyBicmlkZ2UgZm9yIHRoaXNcbiAgICogXG4gICAqIEBwYXJhbSBbYnl0ZVtdXSB0eEV4dHJhIC0gYXJyYXkgb2YgdHggZXh0cmEgYnl0ZXNcbiAgICogQHJldHVybiB7c3RyaW5nfSB0aGUgbGFzdCBwdWIga2V5IGFzIGEgaGV4aWRlY2ltYWwgc3RyaW5nXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZ2V0TGFzdFR4UHViS2V5KHR4RXh0cmEpIHtcbiAgICBsZXQgbGFzdFB1YktleUlkeDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHR4RXh0cmEubGVuZ3RoOyBpKyspIHtcbiAgICAgIGxldCB0YWcgPSB0eEV4dHJhW2ldO1xuICAgICAgaWYgKHRhZyA9PT0gMCB8fCB0YWcgPT09IDIpIHtcbiAgICAgICAgaSArPSAxICsgdHhFeHRyYVtpICsgMV07ICAvLyBhZHZhbmNlIHRvIG5leHQgdGFnXG4gICAgICB9IGVsc2UgaWYgKHRhZyA9PT0gMSkge1xuICAgICAgICBsYXN0UHViS2V5SWR4ID0gaSArIDE7XG4gICAgICAgIGkgKz0gMSArIDMyOyAgICAgICAgICAgICAgLy8gYWR2YW5jZSB0byBuZXh0IHRhZ1xuICAgICAgfSBlbHNlIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkludmFsaWQgc3ViLWZpZWxkIHRhZzogXCIgKyB0YWcpO1xuICAgIH1cbiAgICByZXR1cm4gQnVmZmVyLmZyb20obmV3IFVpbnQ4QXJyYXkodHhFeHRyYS5zbGljZShsYXN0UHViS2V5SWR4LCBsYXN0UHViS2V5SWR4ICsgMzIpKSkudG9TdHJpbmcoXCJoZXhcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBEZXRlcm1pbmVzIGlmIHR3byBwYXltZW50IGlkcyBhcmUgZnVuY3Rpb25hbGx5IGVxdWFsLlxuICAgKiBcbiAgICogRm9yIGV4YW1wbGUsIDAzMjg0ZTQxYzM0MmYwMzIgYW5kIDAzMjg0ZTQxYzM0MmYwMzIwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAgYXJlIGNvbnNpZGVyZWQgZXF1YWwuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGF5bWVudElkMSBpcyBhIHBheW1lbnQgaWQgdG8gY29tcGFyZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGF5bWVudElkMiBpcyBhIHBheW1lbnQgaWQgdG8gY29tcGFyZVxuICAgKiBAcmV0dXJuIHtib29sfSB0cnVlIGlmIHRoZSBwYXltZW50IGlkcyBhcmUgZXF1YWwsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIHBheW1lbnRJZHNFcXVhbChwYXltZW50SWQxLCBwYXltZW50SWQyKSB7XG4gICAgbGV0IG1heExlbmd0aCA9IE1hdGgubWF4KHBheW1lbnRJZDEubGVuZ3RoLCBwYXltZW50SWQyLmxlbmd0aCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBtYXhMZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGkgPCBwYXltZW50SWQxLmxlbmd0aCAmJiBpIDwgcGF5bWVudElkMi5sZW5ndGggJiYgcGF5bWVudElkMVtpXSAhPT0gcGF5bWVudElkMltpXSkgcmV0dXJuIGZhbHNlO1xuICAgICAgaWYgKGkgPj0gcGF5bWVudElkMS5sZW5ndGggJiYgcGF5bWVudElkMltpXSAhPT0gJzAnKSByZXR1cm4gZmFsc2U7XG4gICAgICBpZiAoaSA+PSBwYXltZW50SWQyLmxlbmd0aCAmJiBwYXltZW50SWQxW2ldICE9PSAnMCcpIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBNZXJnZXMgYSB0cmFuc2FjdGlvbiBpbnRvIGEgbGlzdCBvZiBleGlzdGluZyB0cmFuc2FjdGlvbnMuXG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb1R4W119IHR4cyAtIGV4aXN0aW5nIHRyYW5zYWN0aW9ucyB0byBtZXJnZSBpbnRvXG4gICAqIEBwYXJhbSB7TW9uZXJvVHh9IHR4IC0gdHJhbnNhY3Rpb24gdG8gbWVyZ2UgaW50byB0aGUgbGlzdFxuICAgKi9cbiAgc3RhdGljIG1lcmdlVHgodHhzLCB0eCkge1xuICAgIGZvciAobGV0IGFUeCBvZiB0eHMpIHtcbiAgICAgIGlmIChhVHguZ2V0SGFzaCgpID09PSB0eC5nZXRIYXNoKCkpIHtcbiAgICAgICAgYVR4Lm1lcmdlKHR4KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICB0eHMucHVzaCh0eCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDb252ZXJ0IHRoZSBnaXZlbiBKU09OIHRvIGEgYmluYXJ5IFVpbnQ4QXJyYXkgdXNpbmcgTW9uZXJvJ3MgcG9ydGFibGUgc3RvcmFnZSBmb3JtYXQuXG4gICAqIFxuICAgKiBAcGFyYW0ge29iamVjdH0ganNvbiAtIGpzb24gdG8gY29udmVydCB0byBiaW5hcnlcbiAgICogQHJldHVybiB7UHJvbWlzZTxVaW50OEFycmF5Pn0gdGhlIGpzb24gY29udmVydGVkIHRvIHBvcnRhYmxlIHN0b3JhZ2UgYmluYXJ5XG4gICAqL1xuICBzdGF0aWMgYXN5bmMganNvblRvQmluYXJ5KGpzb24pIHtcbiAgICBpZiAoTW9uZXJvVXRpbHMuUFJPWFlfVE9fV09SS0VSKSByZXR1cm4gTGlicmFyeVV0aWxzLmludm9rZVdvcmtlcih1bmRlZmluZWQsIFwibW9uZXJvVXRpbHNKc29uVG9CaW5hcnlcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKTtcbiAgICBcbiAgICAvLyBsb2FkIGtleXMgbW9kdWxlIGJ5IGRlZmF1bHRcbiAgICBpZiAoTGlicmFyeVV0aWxzLmdldFdhc21Nb2R1bGUoKSA9PT0gdW5kZWZpbmVkKSBhd2FpdCBMaWJyYXJ5VXRpbHMubG9hZFdhc21Nb2R1bGUoKTtcbiAgICBcbiAgICAvLyB1c2Ugd2FzbSBpbiBxdWV1ZVxuICAgIHJldHVybiBMaWJyYXJ5VXRpbHMuZ2V0V2FzbU1vZHVsZSgpLnF1ZXVlVGFzayhhc3luYyBmdW5jdGlvbigpIHtcbiAgICAgIFxuICAgICAgLy8gc2VyaWFsaXplIGpzb24gdG8gYmluYXJ5IHdoaWNoIGlzIHN0b3JlZCBpbiBjKysgaGVhcFxuICAgICAgbGV0IGJpbk1lbUluZm9TdHIgPSBMaWJyYXJ5VXRpbHMuZ2V0V2FzbU1vZHVsZSgpLm1hbGxvY19iaW5hcnlfZnJvbV9qc29uKEpTT04uc3RyaW5naWZ5KGpzb24pKTtcbiAgICAgIFxuICAgICAgLy8gc2FuaXRpemUgYmluYXJ5IG1lbW9yeSBhZGRyZXNzIGluZm9cbiAgICAgIGxldCBiaW5NZW1JbmZvID0gSlNPTi5wYXJzZShiaW5NZW1JbmZvU3RyKTtcbiAgICAgIGJpbk1lbUluZm8ucHRyID0gcGFyc2VJbnQoYmluTWVtSW5mby5wdHIpO1xuICAgICAgYmluTWVtSW5mby5sZW5ndGggPSBwYXJzZUludChiaW5NZW1JbmZvLmxlbmd0aCk7XG4gICAgICBcbiAgICAgIC8vIHJlYWQgYmluYXJ5IGRhdGEgZnJvbSBoZWFwIHRvIFVpbnQ4QXJyYXlcbiAgICAgIGxldCB2aWV3ID0gbmV3IFVpbnQ4QXJyYXkoYmluTWVtSW5mby5sZW5ndGgpO1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBiaW5NZW1JbmZvLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZpZXdbaV0gPSBMaWJyYXJ5VXRpbHMuZ2V0V2FzbU1vZHVsZSgpLkhFQVBVOFtiaW5NZW1JbmZvLnB0ciAvIFVpbnQ4QXJyYXkuQllURVNfUEVSX0VMRU1FTlQgKyBpXTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gZnJlZSBiaW5hcnkgb24gaGVhcFxuICAgICAgTGlicmFyeVV0aWxzLmdldFdhc21Nb2R1bGUoKS5fZnJlZShiaW5NZW1JbmZvLnB0cik7XG4gICAgICBcbiAgICAgIC8vIHJldHVybiBqc29uIGZyb20gYmluYXJ5IGRhdGFcbiAgICAgIHJldHVybiB2aWV3O1xuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogQ29udmVydCB0aGUgZ2l2ZW4gcG9ydGFibGUgc3RvcmFnZSBiaW5hcnkgdG8gSlNPTi5cbiAgICogXG4gICAqIEBwYXJhbSB7VWludDhBcnJheX0gdWludDhhcnIgLSBiaW5hcnkgZGF0YSBpbiBNb25lcm8ncyBwb3J0YWJsZSBzdG9yYWdlIGZvcm1hdFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPG9iamVjdD59IEpTT04gb2JqZWN0IGNvbnZlcnRlZCBmcm9tIHRoZSBiaW5hcnkgZGF0YVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGJpbmFyeVRvSnNvbih1aW50OGFycikge1xuICAgIGlmIChNb25lcm9VdGlscy5QUk9YWV9UT19XT1JLRVIpIHJldHVybiBMaWJyYXJ5VXRpbHMuaW52b2tlV29ya2VyKHVuZGVmaW5lZCwgXCJtb25lcm9VdGlsc0JpbmFyeVRvSnNvblwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICAgIFxuICAgIC8vIGxvYWQga2V5cyBtb2R1bGUgYnkgZGVmYXVsdFxuICAgIGlmIChMaWJyYXJ5VXRpbHMuZ2V0V2FzbU1vZHVsZSgpID09PSB1bmRlZmluZWQpIGF3YWl0IExpYnJhcnlVdGlscy5sb2FkV2FzbU1vZHVsZSgpO1xuICAgIFxuICAgIC8vIHVzZSB3YXNtIGluIHF1ZXVlXG4gICAgcmV0dXJuIExpYnJhcnlVdGlscy5nZXRXYXNtTW9kdWxlKCkucXVldWVUYXNrKGFzeW5jIGZ1bmN0aW9uKCkge1xuICAgICAgXG4gICAgICAvLyBhbGxvY2F0ZSBzcGFjZSBpbiBjKysgaGVhcCBmb3IgYmluYXJ5XG4gICAgICBsZXQgcHRyID0gTGlicmFyeVV0aWxzLmdldFdhc21Nb2R1bGUoKS5fbWFsbG9jKHVpbnQ4YXJyLmxlbmd0aCAqIHVpbnQ4YXJyLkJZVEVTX1BFUl9FTEVNRU5UKTtcbiAgICAgIGxldCBoZWFwID0gbmV3IFVpbnQ4QXJyYXkoTGlicmFyeVV0aWxzLmdldFdhc21Nb2R1bGUoKS5IRUFQVTguYnVmZmVyLCBwdHIsIHVpbnQ4YXJyLmxlbmd0aCAqIHVpbnQ4YXJyLkJZVEVTX1BFUl9FTEVNRU5UKTtcbiAgICAgIGlmIChwdHIgIT09IGhlYXAuYnl0ZU9mZnNldCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTWVtb3J5IHB0ciAhPT0gaGVhcC5ieXRlT2Zmc2V0XCIpOyAvLyBzaG91bGQgYmUgZXF1YWxcbiAgICAgIFxuICAgICAgLy8gd3JpdGUgYmluYXJ5IHRvIGhlYXBcbiAgICAgIGhlYXAuc2V0KG5ldyBVaW50OEFycmF5KHVpbnQ4YXJyLmJ1ZmZlcikpO1xuICAgICAgXG4gICAgICAvLyBjcmVhdGUgb2JqZWN0IHdpdGggYmluYXJ5IG1lbW9yeSBhZGRyZXNzIGluZm9cbiAgICAgIGxldCBiaW5NZW1JbmZvID0geyBwdHI6IHB0ciwgbGVuZ3RoOiB1aW50OGFyci5sZW5ndGggfTtcbiAgICAgIFxuICAgICAgLy8gY29udmVydCBiaW5hcnkgdG8ganNvbiBzdHJcbiAgICAgIGNvbnN0IHJldF9zdHJpbmcgPSBMaWJyYXJ5VXRpbHMuZ2V0V2FzbU1vZHVsZSgpLmJpbmFyeV90b19qc29uKEpTT04uc3RyaW5naWZ5KGJpbk1lbUluZm8pKTtcbiAgICAgIFxuICAgICAgLy8gZnJlZSBiaW5hcnkgb24gaGVhcFxuICAgICAgTGlicmFyeVV0aWxzLmdldFdhc21Nb2R1bGUoKS5fZnJlZShwdHIpO1xuICAgICAgXG4gICAgICAvLyBwYXJzZSBhbmQgcmV0dXJuIGpzb25cbiAgICAgIHJldHVybiBKU09OLnBhcnNlKHJldF9zdHJpbmcpO1xuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogQ29udmVydCB0aGUgYmluYXJ5IHJlc3BvbnNlIGZyb20gZGFlbW9uIFJQQyBibG9jayByZXRyaWV2YWwgdG8gSlNPTi5cbiAgICogXG4gICAqIEBwYXJhbSB7VWludDhBcnJheX0gdWludDhhcnIgLSBiaW5hcnkgcmVzcG9uc2UgZnJvbSBkYWVtb24gUlBDIHdoZW4gZ2V0dGluZyBibG9ja3NcbiAgICogQHJldHVybiB7UHJvbWlzZTxvYmplY3Q+fSBKU09OIG9iamVjdCB3aXRoIHRoZSBibG9ja3MgZGF0YVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGJpbmFyeUJsb2Nrc1RvSnNvbih1aW50OGFycikge1xuICAgIGlmIChNb25lcm9VdGlscy5QUk9YWV9UT19XT1JLRVIpIHJldHVybiBMaWJyYXJ5VXRpbHMuaW52b2tlV29ya2VyKHVuZGVmaW5lZCwgXCJtb25lcm9VdGlsc0JpbmFyeUJsb2Nrc1RvSnNvblwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICAgIFxuICAgIC8vIGxvYWQga2V5cyBtb2R1bGUgYnkgZGVmYXVsdFxuICAgIGlmIChMaWJyYXJ5VXRpbHMuZ2V0V2FzbU1vZHVsZSgpID09PSB1bmRlZmluZWQpIGF3YWl0IExpYnJhcnlVdGlscy5sb2FkV2FzbU1vZHVsZSgpO1xuICAgIFxuICAgIC8vIHVzZSB3YXNtIGluIHF1ZXVlXG4gICAgcmV0dXJuIExpYnJhcnlVdGlscy5nZXRXYXNtTW9kdWxlKCkucXVldWVUYXNrKGFzeW5jIGZ1bmN0aW9uKCkge1xuICAgICAgXG4gICAgICAvLyBhbGxvY2F0ZSBzcGFjZSBpbiBjKysgaGVhcCBmb3IgYmluYXJ5XG4gICAgICBsZXQgcHRyID0gTGlicmFyeVV0aWxzLmdldFdhc21Nb2R1bGUoKS5fbWFsbG9jKHVpbnQ4YXJyLmxlbmd0aCAqIHVpbnQ4YXJyLkJZVEVTX1BFUl9FTEVNRU5UKTtcbiAgICAgIGxldCBoZWFwID0gbmV3IFVpbnQ4QXJyYXkoTGlicmFyeVV0aWxzLmdldFdhc21Nb2R1bGUoKS5IRUFQVTguYnVmZmVyLCBwdHIsIHVpbnQ4YXJyLmxlbmd0aCAqIHVpbnQ4YXJyLkJZVEVTX1BFUl9FTEVNRU5UKTtcbiAgICAgIGlmIChwdHIgIT09IGhlYXAuYnl0ZU9mZnNldCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTWVtb3J5IHB0ciAhPT0gaGVhcC5ieXRlT2Zmc2V0XCIpOyAvLyBzaG91bGQgYmUgZXF1YWxcbiAgICAgIFxuICAgICAgLy8gd3JpdGUgYmluYXJ5IHRvIGhlYXBcbiAgICAgIGhlYXAuc2V0KG5ldyBVaW50OEFycmF5KHVpbnQ4YXJyLmJ1ZmZlcikpO1xuICAgICAgXG4gICAgICAvLyBjcmVhdGUgb2JqZWN0IHdpdGggYmluYXJ5IG1lbW9yeSBhZGRyZXNzIGluZm9cbiAgICAgIGxldCBiaW5NZW1JbmZvID0geyBwdHI6IHB0ciwgbGVuZ3RoOiB1aW50OGFyci5sZW5ndGggIH1cblxuICAgICAgLy8gY29udmVydCBiaW5hcnkgdG8ganNvbiBzdHJcbiAgICAgIGNvbnN0IGpzb25fc3RyID0gTGlicmFyeVV0aWxzLmdldFdhc21Nb2R1bGUoKS5iaW5hcnlfYmxvY2tzX3RvX2pzb24oSlNPTi5zdHJpbmdpZnkoYmluTWVtSW5mbykpO1xuICAgICAgXG4gICAgICAvLyBmcmVlIG1lbW9yeVxuICAgICAgTGlicmFyeVV0aWxzLmdldFdhc21Nb2R1bGUoKS5fZnJlZShwdHIpO1xuICAgICAgXG4gICAgICAvLyBwYXJzZSByZXN1bHQgdG8ganNvblxuICAgICAgbGV0IGpzb24gPSBKU09OLnBhcnNlKGpzb25fc3RyKTsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBwYXJzaW5nIGpzb24gZ2l2ZXMgYXJyYXlzIG9mIGJsb2NrIGFuZCB0eCBzdHJpbmdzXG4gICAgICBqc29uLmJsb2NrcyA9IGpzb24uYmxvY2tzLm1hcChibG9ja1N0ciA9PiBKU09OLnBhcnNlKGJsb2NrU3RyKSk7ICAgICAgICAgIC8vIHJlcGxhY2UgYmxvY2sgc3RyaW5ncyB3aXRoIHBhcnNlZCBibG9ja3NcbiAgICAgIGpzb24udHhzID0ganNvbi50eHMubWFwKHR4cyA9PiB0eHMgPyB0eHMubWFwKHR4ID0+IEpTT04ucGFyc2UodHgucmVwbGFjZShcIixcIiwgXCJ7XCIpICsgXCJ9XCIpKSA6IFtdKTsgLy8gbW9kaWZ5IHR4IHN0cmluZyB0byBwcm9wZXIganNvbiBhbmQgcGFyc2UgLy8gVE9ETzogbW9yZSBlZmZpY2llbnQgd2F5IHRoYW4gdGhpcyBqc29uIG1hbmlwdWxhdGlvbj9cbiAgICAgIHJldHVybiBqc29uO1xuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogQ29udmVydCBYTVIgdG8gYXRvbWljIHVuaXRzLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXIgfCBzdHJpbmd9IGFtb3VudFhtciAtIGFtb3VudCBpbiBYTVIgdG8gY29udmVydCB0byBhdG9taWMgdW5pdHNcbiAgICogQHJldHVybiB7YmlnaW50fSBhbW91bnQgaW4gYXRvbWljIHVuaXRzXG4gICAqL1xuICBzdGF0aWMgeG1yVG9BdG9taWNVbml0cyhhbW91bnRYbXI6IG51bWJlciB8IHN0cmluZyk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIEJpZ0ludChuZXcgRGVjaW1hbChhbW91bnRYbXIpLm11bChNb25lcm9VdGlscy5BVV9QRVJfWE1SLnRvU3RyaW5nKCkpLnRvRGVjaW1hbFBsYWNlcygwLCBEZWNpbWFsLlJPVU5EX0hBTEZfVVApLnRvRml4ZWQoMCkpO1xuICB9XG4gIFxuICAvKipcbiAgICogQ29udmVydCBhdG9taWMgdW5pdHMgdG8gWE1SLlxuICAgKiBcbiAgICogQHBhcmFtIHtiaWdpbnQgfCBzdHJpbmd9IGFtb3VudEF0b21pY1VuaXRzIC0gYW1vdW50IGluIGF0b21pYyB1bml0cyB0byBjb252ZXJ0IHRvIFhNUlxuICAgKiBAcmV0dXJuIHtudW1iZXJ9IGFtb3VudCBpbiBYTVIgXG4gICAqL1xuICBzdGF0aWMgYXRvbWljVW5pdHNUb1htcihhbW91bnRBdG9taWNVbml0czogYmlnaW50IHwgc3RyaW5nKTogbnVtYmVyIHtcbiAgICByZXR1cm4gbmV3IERlY2ltYWwoYW1vdW50QXRvbWljVW5pdHMudG9TdHJpbmcoKSkuZGl2KE1vbmVyb1V0aWxzLkFVX1BFUl9YTVIudG9TdHJpbmcoKSkudG9EZWNpbWFsUGxhY2VzKDEyLCBEZWNpbWFsLlJPVU5EX0hBTEZfVVApLnRvTnVtYmVyKCk7XG4gIH1cblxuICAvKipcbiAgICogRGl2aWRlIG9uZSBhdG9taWMgdW5pdHMgYnkgYW5vdGhlci5cbiAgICogXG4gICAqIEBwYXJhbSB7YmlnaW50fSBhdTEgZGl2aWRlbmRcbiAgICogQHBhcmFtIHtiaWdpbnR9IGF1MiBkaXZpc29yXG4gICAqIEByZXR1cm5zIHtudW1iZXJ9IHRoZSByZXN1bHRcbiAgICovXG4gIHN0YXRpYyBkaXZpZGUoYXUxOiBiaWdpbnQsIGF1MjogYmlnaW50KTogbnVtYmVyIHtcbiAgICByZXR1cm4gbmV3IERlY2ltYWwoYXUxLnRvU3RyaW5nKCkpLmRpdihuZXcgRGVjaW1hbChhdTIudG9TdHJpbmcoKSkpLnRvRGVjaW1hbFBsYWNlcygxMiwgRGVjaW1hbC5ST1VORF9IQUxGX1VQKS50b051bWJlcigpO1xuICB9XG5cbiAgLyoqXG4gICAqIE11bHRpcGx5IGEgYmlnaW50IGJ5IGEgbnVtYmVyIG9yIGJpZ2ludC5cbiAgICogXG4gICAqIEBwYXJhbSBhIGJpZ2ludCB0byBtdWx0aXBseVxuICAgKiBAcGFyYW0gYiBiaWdpbnQgb3IgbnVtYmVyIHRvIG11bHRpcGx5IGJ5XG4gICAqIEByZXR1cm5zIHRoZSBwcm9kdWN0IGFzIGEgYmlnaW50XG4gICAqL1xuICBzdGF0aWMgbXVsdGlwbHkoYTogYmlnaW50LCBiOiBudW1iZXIgfCBiaWdpbnQpOiBiaWdpbnQge1xuICAgIHJldHVybiBCaWdJbnQobmV3IERlY2ltYWwoYS50b1N0cmluZygpKS5tdWwobmV3IERlY2ltYWwoYi50b1N0cmluZygpKSkudG9EZWNpbWFsUGxhY2VzKDAsIERlY2ltYWwuUk9VTkRfSEFMRl9VUCkudG9TdHJpbmcoKSk7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgaXNIZXg2NChzdHIpIHtcbiAgICByZXR1cm4gdHlwZW9mIHN0ciA9PT0gXCJzdHJpbmdcIiAmJiBzdHIubGVuZ3RoID09PSA2NCAmJiBHZW5VdGlscy5pc0hleChzdHIpO1xuICB9XG5cbiAgLyoqXG4gICAqIERldGVybWluZSBpZiB0aGUgZ2l2ZW4gdW5sb2NrIHRpbWUgaXMgYSB0aW1lc3RhbXAgb3IgYmxvY2sgaGVpZ2h0LlxuICAgKiBcbiAgICogQHBhcmFtIHVubG9ja1RpbWUgaXMgdGhlIHVubG9jayB0aW1lIHRvIGNoZWNrXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgdGhlIHVubG9jayB0aW1lIGlzIGEgdGltZXN0YW1wLCBmYWxzZSBpZiBhIGJsb2NrIGhlaWdodFxuICAgKi9cbiAgc3RhdGljIGlzVGltZXN0YW1wKHVubG9ja1RpbWU6IGJpZ2ludCkge1xuICAgICAgXG4gICAgLy8gdGhyZXNob2xkIGZvciBkaXN0aW5ndWlzaGluZyBiZXR3ZWVuIHRpbWVzdGFtcCBhbmQgYmxvY2sgaGVpZ2h0XG4gICAgLy8gY3VycmVudCBibG9jayBoZWlnaHQgaXMgYXJvdW5kIDMgbWlsbGlvbiwgY3VycmVudCB1bml4IHRpbWVzdGFtcCBpcyBhcm91bmQgMS43IGJpbGxpb25cbiAgICBjb25zdCB0aHJlc2hvbGQgPSA1MDAwMDAwMDBuO1xuXG4gICAgcmV0dXJuIHVubG9ja1RpbWUgPj0gdGhyZXNob2xkO1xuICB9XG59XG5cbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFFBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLFNBQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFHLGFBQUEsR0FBQUosc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFJLFlBQUEsR0FBQUwsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFLLHdCQUFBLEdBQUFOLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBTSxrQkFBQSxHQUFBUCxzQkFBQSxDQUFBQyxPQUFBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDZSxNQUFNTyxXQUFXLENBQUM7O0VBRS9CO0VBQ0EsT0FBT0MsZUFBZSxHQUFHLEtBQUs7RUFDOUIsT0FBT0Msa0JBQWtCLEdBQUcsRUFBRTtFQUM5QixPQUFPQyxVQUFVLEdB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 \ No newline at end of file diff --git a/dist/src/main/ts/common/MoneroWebWorker.d.ts b/dist/src/main/ts/common/MoneroWebWorker.d.ts new file mode 100644 index 000000000..cb0ff5c3b --- /dev/null +++ b/dist/src/main/ts/common/MoneroWebWorker.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/src/main/ts/common/MoneroWebWorker.js b/dist/src/main/ts/common/MoneroWebWorker.js new file mode 100644 index 000000000..d72cdb571 --- /dev/null +++ b/dist/src/main/ts/common/MoneroWebWorker.js @@ -0,0 +1,1019 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("./GenUtils")); +var _HttpClient = _interopRequireDefault(require("./HttpClient")); +var _LibraryUtils = _interopRequireDefault(require("./LibraryUtils")); +var _MoneroBan = _interopRequireDefault(require("../daemon/model/MoneroBan")); +var _MoneroBlock = _interopRequireDefault(require("../daemon/model/MoneroBlock")); +var _MoneroDaemonConfig = _interopRequireDefault(require("../daemon/model/MoneroDaemonConfig")); +var _MoneroDaemonListener = _interopRequireDefault(require("../daemon/model/MoneroDaemonListener")); +var _MoneroDaemonRpc = _interopRequireDefault(require("../daemon/MoneroDaemonRpc")); +var _MoneroError = _interopRequireDefault(require("./MoneroError")); +var _MoneroKeyImage = _interopRequireDefault(require("../daemon/model/MoneroKeyImage")); +var _MoneroRpcConnection = _interopRequireDefault(require("./MoneroRpcConnection")); +var _MoneroTxConfig = _interopRequireDefault(require("../wallet/model/MoneroTxConfig")); + +var _MoneroTxSet = _interopRequireDefault(require("../wallet/model/MoneroTxSet")); +var _MoneroUtils = _interopRequireDefault(require("./MoneroUtils")); +var _MoneroWalletConfig = _interopRequireDefault(require("../wallet/model/MoneroWalletConfig")); +var _MoneroWalletListener = _interopRequireDefault(require("../wallet/model/MoneroWalletListener")); +var _MoneroWalletKeys = require("../wallet/MoneroWalletKeys"); +var _MoneroWalletFull = _interopRequireDefault(require("../wallet/MoneroWalletFull")); + + + +// deno configuration + +if (_GenUtils.default.isDeno() && typeof self === "undefined" && typeof globalThis === "object" && typeof DedicatedWorkerGlobalScope === "function" && DedicatedWorkerGlobalScope.prototype.isPrototypeOf(globalThis)) { + self = globalThis; + globalThis.self = globalThis; +} + +// expose some modules to the worker +self.HttpClient = _HttpClient.default; +self.LibraryUtils = _LibraryUtils.default; +self.GenUtils = _GenUtils.default; + +/** + * Worker to manage a daemon and wasm wallet off the main thread using messages. + * + * Required message format: e.data[0] = object id, e.data[1] = function name, e.data[2+] = function args + * + * For browser applications, this file must be browserified and placed in the web app root. + * + * @private + */ +self.onmessage = async function (e) { + + // initialize one time + await self.initOneTime(); + + // validate params + let objectId = e.data[0]; + let fnName = e.data[1]; + let callbackId = e.data[2]; + (0, _assert.default)(fnName, "Must provide function name to worker"); + (0, _assert.default)(callbackId, "Must provide callback id to worker"); + if (!self[fnName]) throw new Error("Method '" + fnName + "' is not registered with worker"); + e.data.splice(1, 2); // remove function name and callback id to apply function with arguments + + // execute worker function and post result to callback + try { + postMessage([objectId, callbackId, { result: await self[fnName].apply(null, e.data) }]); + } catch (e) { + if (!(e instanceof Error)) e = new Error(e); + postMessage([objectId, callbackId, { error: _LibraryUtils.default.serializeError(e) }]); + } +}; + +self.initOneTime = async function () { + if (!self.isInitialized) { + self.WORKER_OBJECTS = {}; + self.isInitialized = true; + _MoneroUtils.default.PROXY_TO_WORKER = false; + } +}; + +// --------------------------- STATIC UTILITIES ------------------------------- + +self.httpRequest = async function (objectId, opts) { + try { + return await _HttpClient.default.request(Object.assign(opts, { proxyToWorker: false })); + } catch (err) { + throw err.statusCode ? new Error(JSON.stringify({ statusCode: err.statusCode, statusMessage: err.message })) : err; + } +}; + +self.setLogLevel = async function (objectId, level) { + return _LibraryUtils.default.setLogLevel(level); +}; + +self.getWasmMemoryUsed = async function (objectId) { + return _LibraryUtils.default.getWasmModule() && _LibraryUtils.default.getWasmModule().HEAP8 ? _LibraryUtils.default.getWasmModule().HEAP8.length : undefined; +}; + +// ----------------------------- MONERO UTILS --------------------------------- + +self.moneroUtilsGetIntegratedAddress = async function (objectId, networkType, standardAddress, paymentId) { + return (await _MoneroUtils.default.getIntegratedAddress(networkType, standardAddress, paymentId)).toJson(); +}; + +self.moneroUtilsValidateAddress = async function (objectId, address, networkType) { + return _MoneroUtils.default.validateAddress(address, networkType); +}; + +self.moneroUtilsJsonToBinary = async function (objectId, json) { + return _MoneroUtils.default.jsonToBinary(json); +}; + +self.moneroUtilsBinaryToJson = async function (objectId, uint8arr) { + return _MoneroUtils.default.binaryToJson(uint8arr); +}; + +self.moneroUtilsBinaryBlocksToJson = async function (objectId, uint8arr) { + return _MoneroUtils.default.binaryBlocksToJson(uint8arr); +}; + +// ---------------------------- DAEMON METHODS -------------------------------- + +self.daemonAddListener = async function (daemonId, listenerId) { + let listener = new class extends _MoneroDaemonListener.default { + async onBlockHeader(blockHeader) { + self.postMessage([daemonId, "onBlockHeader_" + listenerId, blockHeader.toJson()]); + } + }(); + if (!self.daemonListeners) self.daemonListeners = {}; + self.daemonListeners[listenerId] = listener; + await self.WORKER_OBJECTS[daemonId].addListener(listener); +}; + +self.daemonRemoveListener = async function (daemonId, listenerId) { + if (!self.daemonListeners[listenerId]) throw new _MoneroError.default("No daemon worker listener registered with id: " + listenerId); + await self.WORKER_OBJECTS[daemonId].removeListener(self.daemonListeners[listenerId]); + delete self.daemonListeners[listenerId]; +}; + +self.connectDaemonRpc = async function (daemonId, config) { + self.WORKER_OBJECTS[daemonId] = await _MoneroDaemonRpc.default.connectToDaemonRpc(new _MoneroDaemonConfig.default(config)); +}; + +self.daemonGetRpcConnection = async function (daemonId) { + let connection = await self.WORKER_OBJECTS[daemonId].getRpcConnection(); + return connection ? connection.getConfig() : undefined; +}; + +self.daemonIsConnected = async function (daemonId) { + return self.WORKER_OBJECTS[daemonId].isConnected(); +}; + +self.daemonGetVersion = async function (daemonId) { + return (await self.WORKER_OBJECTS[daemonId].getVersion()).toJson(); +}; + +self.daemonIsTrusted = async function (daemonId) { + return self.WORKER_OBJECTS[daemonId].isTrusted(); +}; + +self.daemonGetHeight = async function (daemonId) { + return self.WORKER_OBJECTS[daemonId].getHeight(); +}; + +self.daemonGetBlockHash = async function (daemonId, height) { + return self.WORKER_OBJECTS[daemonId].getBlockHash(height); +}; + +self.daemonGetBlockTemplate = async function (daemonId, walletAddress, reserveSize) { + return (await self.WORKER_OBJECTS[daemonId].getBlockTemplate(walletAddress, reserveSize)).toJson(); +}; + +self.daemonGetLastBlockHeader = async function (daemonId) { + return (await self.WORKER_OBJECTS[daemonId].getLastBlockHeader()).toJson(); +}; + +self.daemonGetBlockHeaderByHash = async function (daemonId, hash) { + return (await self.WORKER_OBJECTS[daemonId].getBlockHeaderByHash(hash)).toJson(); +}; + +self.daemonGetBlockHeaderByHeight = async function (daemonId, height) { + return (await self.WORKER_OBJECTS[daemonId].getBlockHeaderByHeight(height)).toJson(); +}; + +self.daemonGetBlockHeadersByRange = async function (daemonId, startHeight, endHeight) { + let blockHeadersJson = []; + for (let blockHeader of await self.WORKER_OBJECTS[daemonId].getBlockHeadersByRange(startHeight, endHeight)) blockHeadersJson.push(blockHeader.toJson()); + return blockHeadersJson; +}; + +self.daemonGetBlockByHash = async function (daemonId, blockHash) { + return (await self.WORKER_OBJECTS[daemonId].getBlockByHash(blockHash)).toJson(); +}; + +self.daemonGetBlocksByHash = async function (daemonId, blockHashes, startHeight, prune) { + let blocksJson = []; + for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByHash(blockHashes, startHeight, prune)) blocksJson.push(block.toJson()); + return blocksJson; +}; + +self.daemonGetBlockByHeight = async function (daemonId, height) { + return (await self.WORKER_OBJECTS[daemonId].getBlockByHeight(height)).toJson(); +}; + +self.daemonGetBlocksByHeight = async function (daemonId, heights) { + let blocksJson = []; + for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByHeight(heights)) blocksJson.push(block.toJson()); + return blocksJson; +}; + +self.daemonGetBlocksByRange = async function (daemonId, startHeight, endHeight) { + let blocksJson = []; + for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByRange(startHeight, endHeight)) blocksJson.push(block.toJson()); + return blocksJson; +}; + +self.daemonGetBlocksByRangeChunked = async function (daemonId, startHeight, endHeight, maxChunkSize) { + let blocksJson = []; + for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize)) blocksJson.push(block.toJson()); + return blocksJson; +}; + +self.daemonGetBlockHashes = async function (daemonId, blockHashes, startHeight) { + throw new Error("worker.getBlockHashes not implemented"); +}; + +// TODO: factor common code with self.getTxs() +self.daemonGetTxs = async function (daemonId, txHashes, prune) { + + // get txs + let txs = await self.WORKER_OBJECTS[daemonId].getTxs(txHashes, prune); + + // collect unique blocks to preserve model relationships as trees (based on monero_wasm_bridge.cpp::get_txs) + let blocks = []; + let unconfirmedBlock = undefined; + let seenBlocks = new Set(); + for (let tx of txs) { + if (!tx.getBlock()) { + if (!unconfirmedBlock) unconfirmedBlock = new _MoneroBlock.default().setTxs([]); + tx.setBlock(unconfirmedBlock); + unconfirmedBlock.getTxs().push(tx); + } + if (!seenBlocks.has(tx.getBlock())) { + seenBlocks.add(tx.getBlock()); + blocks.push(tx.getBlock()); + } + } + + // serialize blocks to json + for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson(); + return blocks; +}; + +self.daemonGetTxHexes = async function (daemonId, txHashes, prune) { + return self.WORKER_OBJECTS[daemonId].getTxHexes(txHashes, prune); +}; + +self.daemonGetMinerTxSum = async function (daemonId, height, numBlocks) { + return (await self.WORKER_OBJECTS[daemonId].getMinerTxSum(height, numBlocks)).toJson(); +}; + +self.daemonGetFeeEstimate = async function (daemonId, graceBlocks) { + return (await self.WORKER_OBJECTS[daemonId].getFeeEstimate(graceBlocks)).toJson(); +}; + +self.daemonSubmitTxHex = async function (daemonId, txHex, doNotRelay) { + return (await self.WORKER_OBJECTS[daemonId].submitTxHex(txHex, doNotRelay)).toJson(); +}; + +self.daemonRelayTxsByHash = async function (daemonId, txHashes) { + return self.WORKER_OBJECTS[daemonId].relayTxsByHash(txHashes); +}; + +self.daemonGetTxPool = async function (daemonId) { + let txs = await self.WORKER_OBJECTS[daemonId].getTxPool(); + let block = new _MoneroBlock.default().setTxs(txs); + for (let tx of txs) tx.setBlock(block); + return block.toJson(); +}; + +self.daemonGetTxPoolHashes = async function (daemonId) { + return self.WORKER_OBJECTS[daemonId].getTxPoolHashes(); +}; + +//async getTxPoolBacklog() { +// throw new MoneroError("Not implemented"); +//} + +self.daemonGetTxPoolStats = async function (daemonId) { + return (await self.WORKER_OBJECTS[daemonId].getTxPoolStats()).toJson(); +}; + +self.daemonFlushTxPool = async function (daemonId, hashes) { + return self.WORKER_OBJECTS[daemonId].flushTxPool(hashes); +}; + +self.daemonGetKeyImageSpentStatuses = async function (daemonId, keyImages) { + return self.WORKER_OBJECTS[daemonId].getKeyImageSpentStatuses(keyImages); +}; + +// +//async getOutputs(outputs) { +// throw new MoneroError("Not implemented"); +//} + +self.daemonGetOutputHistogram = async function (daemonId, amounts, minCount, maxCount, isUnlocked, recentCutoff) { + let entriesJson = []; + for (let entry of await self.WORKER_OBJECTS[daemonId].getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff)) { + entriesJson.push(entry.toJson()); + } + return entriesJson; +}; + +// +//async getOutputDistribution(amounts, cumulative, startHeight, endHeight) { +// throw new MoneroError("Not implemented"); +//} + +self.daemonGetInfo = async function (daemonId) { + return (await self.WORKER_OBJECTS[daemonId].getInfo()).toJson(); +}; + +self.daemonGetSyncInfo = async function (daemonId) { + return (await self.WORKER_OBJECTS[daemonId].getSyncInfo()).toJson(); +}; + +self.daemonGetHardForkInfo = async function (daemonId) { + return (await self.WORKER_OBJECTS[daemonId].getHardForkInfo()).toJson(); +}; + +self.daemonGetAltChains = async function (daemonId) { + let altChainsJson = []; + for (let altChain of await self.WORKER_OBJECTS[daemonId].getAltChains()) altChainsJson.push(altChain.toJson()); + return altChainsJson; +}; + +self.daemonGetAltBlockHashes = async function (daemonId) { + return self.WORKER_OBJECTS[daemonId].getAltBlockHashes(); +}; + +self.daemonGetDownloadLimit = async function (daemonId) { + return self.WORKER_OBJECTS[daemonId].getDownloadLimit(); +}; + +self.daemonSetDownloadLimit = async function (daemonId, limit) { + return self.WORKER_OBJECTS[daemonId].setDownloadLimit(limit); +}; + +self.daemonResetDownloadLimit = async function (daemonId) { + return self.WORKER_OBJECTS[daemonId].resetDownloadLimit(); +}; + +self.daemonGetUploadLimit = async function (daemonId) { + return self.WORKER_OBJECTS[daemonId].getUploadLimit(); +}; + +self.daemonSetUploadLimit = async function (daemonId, limit) { + return self.WORKER_OBJECTS[daemonId].setUploadLimit(limit); +}; + +self.daemonResetUploadLimit = async function (daemonId) { + return self.WORKER_OBJECTS[daemonId].resetUploadLimit(); +}; + +self.daemonGetPeers = async function (daemonId) { + let peersJson = []; + for (let peer of await self.WORKER_OBJECTS[daemonId].getPeers()) peersJson.push(peer.toJson()); + return peersJson; +}; + +self.daemonGetKnownPeers = async function (daemonId) { + let peersJson = []; + for (let peer of await self.WORKER_OBJECTS[daemonId].getKnownPeers()) peersJson.push(peer.toJson()); + return peersJson; +}; + +self.daemonSetOutgoingPeerLimit = async function (daemonId, limit) { + return self.WORKER_OBJECTS[daemonId].setOutgoingPeerLimit(limit); +}; + +self.daemonSetIncomingPeerLimit = async function (daemonId, limit) { + return self.WORKER_OBJECTS[daemonId].setIncomingPeerLimit(limit); +}; + +self.daemonGetPeerBans = async function (daemonId) { + let bansJson = []; + for (let ban of await self.WORKER_OBJECTS[daemonId].getPeerBans()) bansJson.push(ban.toJson()); + return bansJson; +}; + +self.daemonSetPeerBans = async function (daemonId, bansJson) { + let bans = []; + for (let banJson of bansJson) bans.push(new _MoneroBan.default(banJson)); + return self.WORKER_OBJECTS[daemonId].setPeerBans(bans); +}; + +self.daemonStartMining = async function (daemonId, address, numThreads, isBackground, ignoreBattery) { + return self.WORKER_OBJECTS[daemonId].startMining(address, numThreads, isBackground, ignoreBattery); +}; + +self.daemonStopMining = async function (daemonId) { + return self.WORKER_OBJECTS[daemonId].stopMining(); +}; + +self.daemonGetMiningStatus = async function (daemonId) { + return (await self.WORKER_OBJECTS[daemonId].getMiningStatus()).toJson(); +}; + +self.daemonSubmitBlocks = async function (daemonId, blockBlobs) { + return self.WORKER_OBJECTS[daemonId].submitBlocks(blockBlobs); +}; + +self.daemonPruneBlockchain = async function (daemonId, check) { + return (await self.WORKER_OBJECTS[daemonId].pruneBlockchain(check)).toJson(); +}; + +//async checkForUpdate() { +// throw new MoneroError("Not implemented"); +//} +// +//async downloadUpdate(path) { +// throw new MoneroError("Not implemented"); +//} + +self.daemonStop = async function (daemonId) { + return self.WORKER_OBJECTS[daemonId].stop(); +}; + +self.daemonWaitForNextBlockHeader = async function (daemonId) { + return (await self.WORKER_OBJECTS[daemonId].waitForNextBlockHeader()).toJson(); +}; + +//------------------------------ WALLET METHODS ------------------------------- + +self.openWalletData = async function (walletId, path, password, networkType, keysData, cacheData, daemonUriOrConfig) { + let daemonConnection = daemonUriOrConfig ? new _MoneroRpcConnection.default(daemonUriOrConfig) : undefined; + self.WORKER_OBJECTS[walletId] = await _MoneroWalletFull.default.openWallet({ path: "", password: password, networkType: networkType, keysData: keysData, cacheData: cacheData, server: daemonConnection, proxyToWorker: false }); + self.WORKER_OBJECTS[walletId].setBrowserMainPath(path); +}; + +self.createWalletKeys = async function (walletId, configJson) { + let config = new _MoneroWalletConfig.default(configJson); + config.setProxyToWorker(false); + self.WORKER_OBJECTS[walletId] = await _MoneroWalletKeys.MoneroWalletKeys.createWallet(config); +}; + +self.createWalletFull = async function (walletId, configJson) { + let config = new _MoneroWalletConfig.default(configJson); + let path = config.getPath(); + config.setPath(""); + config.setProxyToWorker(false); + self.WORKER_OBJECTS[walletId] = await _MoneroWalletFull.default.createWallet(config); + self.WORKER_OBJECTS[walletId].setBrowserMainPath(path); +}; + +self.isViewOnly = async function (walletId) { + return self.WORKER_OBJECTS[walletId].isViewOnly(); +}; + +self.getNetworkType = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getNetworkType(); +}; + +// +//async getVersion() { +// throw new Error("Not implemented"); +//} + +self.getSeed = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getSeed(); +}; + +self.getSeedLanguage = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getSeedLanguage(); +}; + +self.getSeedLanguages = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getSeedLanguages(); +}; + +self.getPrivateSpendKey = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getPrivateSpendKey(); +}; + +self.getPrivateViewKey = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getPrivateViewKey(); +}; + +self.getPublicViewKey = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getPublicViewKey(); +}; + +self.getPublicSpendKey = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getPublicSpendKey(); +}; + +self.getAddress = async function (walletId, accountIdx, subaddressIdx) { + return self.WORKER_OBJECTS[walletId].getAddress(accountIdx, subaddressIdx); +}; + +self.getAddressIndex = async function (walletId, address) { + return (await self.WORKER_OBJECTS[walletId].getAddressIndex(address)).toJson(); +}; + +self.setSubaddressLabel = async function (walletId, accountIdx, subaddressIdx, label) { + await self.WORKER_OBJECTS[walletId].setSubaddressLabel(accountIdx, subaddressIdx, label); +}; + +self.getIntegratedAddress = async function (walletId, standardAddress, paymentId) { + return (await self.WORKER_OBJECTS[walletId].getIntegratedAddress(standardAddress, paymentId)).toJson(); +}; + +self.decodeIntegratedAddress = async function (walletId, integratedAddress) { + return (await self.WORKER_OBJECTS[walletId].decodeIntegratedAddress(integratedAddress)).toJson(); +}; + +self.setDaemonConnection = async function (walletId, config) { + return self.WORKER_OBJECTS[walletId].setDaemonConnection(config ? new _MoneroRpcConnection.default(Object.assign(config, { proxyToWorker: false })) : undefined); +}; + +self.getDaemonConnection = async function (walletId) { + let connection = await self.WORKER_OBJECTS[walletId].getDaemonConnection(); + return connection ? connection.getConfig() : undefined; +}; + +self.isConnectedToDaemon = async function (walletId) { + return self.WORKER_OBJECTS[walletId].isConnectedToDaemon(); +}; + +self.getRestoreHeight = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getRestoreHeight(); +}; + +self.setRestoreHeight = async function (walletId, restoreHeight) { + return self.WORKER_OBJECTS[walletId].setRestoreHeight(restoreHeight); +}; + +self.getDaemonHeight = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getDaemonHeight(); +}; + +self.getDaemonMaxPeerHeight = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getDaemonMaxPeerHeight(); +}; + +self.getHeightByDate = async function (walletId, year, month, day) { + return self.WORKER_OBJECTS[walletId].getHeightByDate(year, month, day); +}; + +self.isDaemonSynced = async function (walletId) { + return self.WORKER_OBJECTS[walletId].isDaemonSynced(); +}; + +self.getHeight = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getHeight(); +}; + +self.addListener = async function (walletId, listenerId) { + + /** + * Internal listener to bridge notifications to external listeners. + * + * TODO: MoneroWalletListener is not defined until scripts imported + * + * @private + */ + class WalletWorkerHelperListener extends _MoneroWalletListener.default { + + + + + + constructor(walletId, id, worker) { + super(); + this.walletId = walletId; + this.id = id; + this.worker = worker; + } + + getId() { + return this.id; + } + + async onSyncProgress(height, startHeight, endHeight, percentDone, message) { + this.worker.postMessage([this.walletId, "onSyncProgress_" + this.getId(), height, startHeight, endHeight, percentDone, message]); + } + + async onNewBlock(height) { + this.worker.postMessage([this.walletId, "onNewBlock_" + this.getId(), height]); + } + + async onBalancesChanged(newBalance, newUnlockedBalance) { + this.worker.postMessage([this.walletId, "onBalancesChanged_" + this.getId(), newBalance.toString(), newUnlockedBalance.toString()]); + } + + async onOutputReceived(output) { + let block = output.getTx().getBlock(); + if (block === undefined) block = new _MoneroBlock.default().setTxs([output.getTx()]); + this.worker.postMessage([this.walletId, "onOutputReceived_" + this.getId(), block.toJson()]); // serialize from root block + } + + async onOutputSpent(output) { + let block = output.getTx().getBlock(); + if (block === undefined) block = new _MoneroBlock.default().setTxs([output.getTx()]); + this.worker.postMessage([this.walletId, "onOutputSpent_" + this.getId(), block.toJson()]); // serialize from root block + } + } + + let listener = new WalletWorkerHelperListener(walletId, listenerId, self); + if (!self.listeners) self.listeners = []; + self.listeners.push(listener); + await self.WORKER_OBJECTS[walletId].addListener(listener); +}; + +self.removeListener = async function (walletId, listenerId) { + for (let i = 0; i < self.listeners.length; i++) { + if (self.listeners[i].getId() !== listenerId) continue; + await self.WORKER_OBJECTS[walletId].removeListener(self.listeners[i]); + self.listeners.splice(i, 1); + return; + } + throw new _MoneroError.default("Listener is not registered with wallet"); +}; + +self.isSynced = async function (walletId) { + return self.WORKER_OBJECTS[walletId].isSynced(); +}; + +self.sync = async function (walletId, startHeight, allowConcurrentCalls) { + return await self.WORKER_OBJECTS[walletId].sync(undefined, startHeight, allowConcurrentCalls); +}; + +self.startSyncing = async function (walletId, syncPeriodInMs) { + return self.WORKER_OBJECTS[walletId].startSyncing(syncPeriodInMs); +}; + +self.stopSyncing = async function (walletId) { + return self.WORKER_OBJECTS[walletId].stopSyncing(); +}; + +self.scanTxs = async function (walletId, txHashes) { + return self.WORKER_OBJECTS[walletId].scanTxs(txHashes); +}; + +self.rescanSpent = async function (walletId) { + return self.WORKER_OBJECTS[walletId].rescanSpent(); +}; + +self.rescanBlockchain = async function (walletId) { + return self.WORKER_OBJECTS[walletId].rescanBlockchain(); +}; + +self.getBalance = async function (walletId, accountIdx, subaddressIdx) { + return (await self.WORKER_OBJECTS[walletId].getBalance(accountIdx, subaddressIdx)).toString(); +}; + +self.getUnlockedBalance = async function (walletId, accountIdx, subaddressIdx) { + return (await self.WORKER_OBJECTS[walletId].getUnlockedBalance(accountIdx, subaddressIdx)).toString(); +}; + +self.getAccounts = async function (walletId, includeSubaddresses, tag) { + let accountJsons = []; + for (let account of await self.WORKER_OBJECTS[walletId].getAccounts(includeSubaddresses, tag)) accountJsons.push(account.toJson()); + return accountJsons; +}; + +self.getAccount = async function (walletId, accountIdx, includeSubaddresses) { + return (await self.WORKER_OBJECTS[walletId].getAccount(accountIdx, includeSubaddresses)).toJson(); +}; + +self.createAccount = async function (walletId, label) { + return (await self.WORKER_OBJECTS[walletId].createAccount(label)).toJson(); +}; + +self.getSubaddresses = async function (walletId, accountIdx, subaddressIndices) { + let subaddressJsons = []; + for (let subaddress of await self.WORKER_OBJECTS[walletId].getSubaddresses(accountIdx, subaddressIndices)) subaddressJsons.push(subaddress.toJson()); + return subaddressJsons; +}; + +self.createSubaddress = async function (walletId, accountIdx, label) { + return (await self.WORKER_OBJECTS[walletId].createSubaddress(accountIdx, label)).toJson(); +}; + +// TODO: easier or more efficient way than serializing from root blocks? +self.getTxs = async function (walletId, blockJsonQuery) { + + // deserialize query which is json string rooted at block + let query = new _MoneroBlock.default(blockJsonQuery, _MoneroBlock.default.DeserializationType.TX_QUERY).getTxs()[0]; + + // get txs + let txs = await self.WORKER_OBJECTS[walletId].getTxs(query); + + // collect unique blocks to preserve model relationships as trees (based on monero_wasm_bridge.cpp::get_txs) + let seenBlocks = new Set(); + let unconfirmedBlock = undefined; + let blocks = []; + for (let tx of txs) { + if (!tx.getBlock()) { + if (!unconfirmedBlock) unconfirmedBlock = new _MoneroBlock.default().setTxs([]); + tx.setBlock(unconfirmedBlock); + unconfirmedBlock.getTxs().push(tx); + } + if (!seenBlocks.has(tx.getBlock())) { + seenBlocks.add(tx.getBlock()); + blocks.push(tx.getBlock()); + } + } + + // serialize blocks to json + for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson(); + return { blocks: blocks }; +}; + +self.getTransfers = async function (walletId, blockJsonQuery) { + + // deserialize query which is json string rooted at block + let query = new _MoneroBlock.default(blockJsonQuery, _MoneroBlock.default.DeserializationType.TX_QUERY).getTxs()[0].getTransferQuery(); + + // get transfers + let transfers = await self.WORKER_OBJECTS[walletId].getTransfers(query); + + // collect unique blocks to preserve model relationships as tree + let unconfirmedBlock = undefined; + let blocks = []; + let seenBlocks = new Set(); + for (let transfer of transfers) { + let tx = transfer.getTx(); + if (!tx.getBlock()) { + if (!unconfirmedBlock) unconfirmedBlock = new _MoneroBlock.default().setTxs([]); + tx.setBlock(unconfirmedBlock); + unconfirmedBlock.getTxs().push(tx); + } + if (!seenBlocks.has(tx.getBlock())) { + seenBlocks.add(tx.getBlock()); + blocks.push(tx.getBlock()); + } + } + + // serialize blocks to json + for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson(); + return blocks; +}; + +self.getOutputs = async function (walletId, blockJsonQuery) { + + // deserialize query which is json string rooted at block + let query = new _MoneroBlock.default(blockJsonQuery, _MoneroBlock.default.DeserializationType.TX_QUERY).getTxs()[0].getOutputQuery(); + + // get outputs + let outputs = await self.WORKER_OBJECTS[walletId].getOutputs(query); + + // collect unique blocks to preserve model relationships as tree + let unconfirmedBlock = undefined; + let blocks = []; + let seenBlocks = new Set(); + for (let output of outputs) { + let tx = output.getTx(); + if (!tx.getBlock()) { + if (!unconfirmedBlock) unconfirmedBlock = new _MoneroBlock.default().setTxs([]); + tx.setBlock(unconfirmedBlock); + unconfirmedBlock.getTxs().push(tx); + } + if (!seenBlocks.has(tx.getBlock())) { + seenBlocks.add(tx.getBlock()); + blocks.push(tx.getBlock()); + } + } + + // serialize blocks to json + for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson(); + return blocks; +}; + +self.exportOutputs = async function (walletId, all) { + return self.WORKER_OBJECTS[walletId].exportOutputs(all); +}; + +self.importOutputs = async function (walletId, outputsHex) { + return self.WORKER_OBJECTS[walletId].importOutputs(outputsHex); +}; + +self.getKeyImages = async function (walletId, all) { + let keyImagesJson = []; + for (let keyImage of await self.WORKER_OBJECTS[walletId].exportKeyImages(all)) keyImagesJson.push(keyImage.toJson()); + return keyImagesJson; +}; + +self.importKeyImages = async function (walletId, keyImagesJson) { + let keyImages = []; + for (let keyImageJson of keyImagesJson) keyImages.push(new _MoneroKeyImage.default(keyImageJson)); + return (await self.WORKER_OBJECTS[walletId].importKeyImages(keyImages)).toJson(); +}; + +//async getNewKeyImagesFromLastImport() { +// throw new MoneroError("Not implemented"); +//} + +self.freezeOutput = async function (walletId, keyImage) { + return self.WORKER_OBJECTS[walletId].freezeOutput(keyImage); +}; + +self.thawOutput = async function (walletId, keyImage) { + return self.WORKER_OBJECTS[walletId].thawOutput(keyImage); +}; + +self.isOutputFrozen = async function (walletId, keyImage) { + return self.WORKER_OBJECTS[walletId].isOutputFrozen(keyImage); +}; + +self.getDefaultFeePriority = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getDefaultFeePriority(); +}; + +self.createTxs = async function (walletId, config) { + if (typeof config === "object") config = new _MoneroTxConfig.default(config); + let txs = await self.WORKER_OBJECTS[walletId].createTxs(config); + return txs[0].getTxSet().toJson(); +}; + +self.sweepOutput = async function (walletId, config) { + if (typeof config === "object") config = new _MoneroTxConfig.default(config); + let tx = await self.WORKER_OBJECTS[walletId].sweepOutput(config); + return tx.getTxSet().toJson(); +}; + +self.sweepUnlocked = async function (walletId, config) { + if (typeof config === "object") config = new _MoneroTxConfig.default(config); + let txs = await self.WORKER_OBJECTS[walletId].sweepUnlocked(config); + let txSets = []; + for (let tx of txs) if (!_GenUtils.default.arrayContains(txSets, tx.getTxSet())) txSets.push(tx.getTxSet()); + let txSetsJson = []; + for (let txSet of txSets) txSetsJson.push(txSet.toJson()); + return txSetsJson; +}; + +self.sweepDust = async function (walletId, relay) { + let txs = await self.WORKER_OBJECTS[walletId].sweepDust(relay); + return txs.length === 0 ? {} : txs[0].getTxSet().toJson(); +}; + +self.relayTxs = async function (walletId, txMetadatas) { + return self.WORKER_OBJECTS[walletId].relayTxs(txMetadatas); +}; + +self.describeTxSet = async function (walletId, txSetJson) { + return (await self.WORKER_OBJECTS[walletId].describeTxSet(new _MoneroTxSet.default(txSetJson))).toJson(); +}; + +self.signTxs = async function (walletId, unsignedTxHex) { + return self.WORKER_OBJECTS[walletId].signTxs(unsignedTxHex); +}; + +self.submitTxs = async function (walletId, signedTxHex) { + return self.WORKER_OBJECTS[walletId].submitTxs(signedTxHex); +}; + +self.signMessage = async function (walletId, message, signatureType, accountIdx, subaddressIdx) { + return self.WORKER_OBJECTS[walletId].signMessage(message, signatureType, accountIdx, subaddressIdx); +}; + +self.verifyMessage = async function (walletId, message, address, signature) { + return (await self.WORKER_OBJECTS[walletId].verifyMessage(message, address, signature)).toJson(); +}; + +self.getTxKey = async function (walletId, txHash) { + return self.WORKER_OBJECTS[walletId].getTxKey(txHash); +}; + +self.checkTxKey = async function (walletId, txHash, txKey, address) { + return (await self.WORKER_OBJECTS[walletId].checkTxKey(txHash, txKey, address)).toJson(); +}; + +self.getTxProof = async function (walletId, txHash, address, message) { + return self.WORKER_OBJECTS[walletId].getTxProof(txHash, address, message); +}; + +self.checkTxProof = async function (walletId, txHash, address, message, signature) { + return (await self.WORKER_OBJECTS[walletId].checkTxProof(txHash, address, message, signature)).toJson(); +}; + +self.getSpendProof = async function (walletId, txHash, message) { + return self.WORKER_OBJECTS[walletId].getSpendProof(txHash, message); +}; + +self.checkSpendProof = async function (walletId, txHash, message, signature) { + return self.WORKER_OBJECTS[walletId].checkSpendProof(txHash, message, signature); +}; + +self.getReserveProofWallet = async function (walletId, message) { + return self.WORKER_OBJECTS[walletId].getReserveProofWallet(message); +}; + +self.getReserveProofAccount = async function (walletId, accountIdx, amountStr, message) { + return self.WORKER_OBJECTS[walletId].getReserveProofAccount(accountIdx, amountStr, message); +}; + +self.checkReserveProof = async function (walletId, address, message, signature) { + return (await self.WORKER_OBJECTS[walletId].checkReserveProof(address, message, signature)).toJson(); +}; + +self.getTxNotes = async function (walletId, txHashes) { + return self.WORKER_OBJECTS[walletId].getTxNotes(txHashes); +}; + +self.setTxNotes = async function (walletId, txHashes, txNotes) { + return self.WORKER_OBJECTS[walletId].setTxNotes(txHashes, txNotes); +}; + +self.getAddressBookEntries = async function (walletId, entryIndices) { + let entriesJson = []; + for (let entry of await self.WORKER_OBJECTS[walletId].getAddressBookEntries(entryIndices)) entriesJson.push(entry.toJson()); + return entriesJson; +}; + +self.addAddressBookEntry = async function (walletId, address, description) { + return self.WORKER_OBJECTS[walletId].addAddressBookEntry(address, description); +}; + +self.editAddressBookEntry = async function (walletId, index, setAddress, address, setDescription, description) { + return self.WORKER_OBJECTS[walletId].editAddressBookEntry(index, setAddress, address, setDescription, description); +}; + +self.deleteAddressBookEntry = async function (walletId, index) { + return self.WORKER_OBJECTS[walletId].deleteAddressBookEntry(index); +}; + +self.tagAccounts = async function (walletId, tag, accountIndices) { + throw new Error("Not implemented"); +}; + +self.untagAccounts = async function (walletId, accountIndices) { + throw new Error("Not implemented"); +}; + +self.getAccountTags = async function (walletId) { + throw new Error("Not implemented"); +}; + +self.setAccountTagLabel = async function (walletId, tag, label) { + throw new Error("Not implemented"); +}; + +self.getPaymentUri = async function (walletId, configJson) { + return self.WORKER_OBJECTS[walletId].getPaymentUri(new _MoneroTxConfig.default(configJson)); +}; + +self.parsePaymentUri = async function (walletId, uri) { + return (await self.WORKER_OBJECTS[walletId].parsePaymentUri(uri)).toJson(); +}; + +self.getAttribute = async function (walletId, key) { + return self.WORKER_OBJECTS[walletId].getAttribute(key); +}; + +self.setAttribute = async function (walletId, key, value) { + return self.WORKER_OBJECTS[walletId].setAttribute(key, value); +}; + +self.startMining = async function (walletId, numThreads, backgroundMining, ignoreBattery) { + return self.WORKER_OBJECTS[walletId].startMining(numThreads, backgroundMining, ignoreBattery); +}; + +self.stopMining = async function (walletId) { + return self.WORKER_OBJECTS[walletId].stopMining(); +}; + +self.isMultisigImportNeeded = async function (walletId) { + return self.WORKER_OBJECTS[walletId].isMultisigImportNeeded(); +}; + +self.isMultisig = async function (walletId) { + return self.WORKER_OBJECTS[walletId].isMultisig(); +}; + +self.getMultisigInfo = async function (walletId) { + return (await self.WORKER_OBJECTS[walletId].getMultisigInfo()).toJson(); +}; + +self.prepareMultisig = async function (walletId) { + return self.WORKER_OBJECTS[walletId].prepareMultisig(); +}; + +self.makeMultisig = async function (walletId, multisigHexes, threshold, password) { + return await self.WORKER_OBJECTS[walletId].makeMultisig(multisigHexes, threshold, password); +}; + +self.exchangeMultisigKeys = async function (walletId, multisigHexes, password) { + return (await self.WORKER_OBJECTS[walletId].exchangeMultisigKeys(multisigHexes, password)).toJson(); +}; + +self.exportMultisigHex = async function (walletId) { + return self.WORKER_OBJECTS[walletId].exportMultisigHex(); +}; + +self.importMultisigHex = async function (walletId, multisigHexes) { + return self.WORKER_OBJECTS[walletId].importMultisigHex(multisigHexes); +}; + +self.signMultisigTxHex = async function (walletId, multisigTxHex) { + return (await self.WORKER_OBJECTS[walletId].signMultisigTxHex(multisigTxHex)).toJson(); +}; + +self.submitMultisigTxHex = async function (walletId, signedMultisigTxHex) { + return self.WORKER_OBJECTS[walletId].submitMultisigTxHex(signedMultisigTxHex); +}; + +self.getData = async function (walletId) { + return self.WORKER_OBJECTS[walletId].getData(); +}; + +self.changePassword = async function (walletId, oldPassword, newPassword) { + return self.WORKER_OBJECTS[walletId].changePassword(oldPassword, newPassword); +}; + +self.isClosed = async function (walletId) { + return !self.WORKER_OBJECTS[walletId] || self.WORKER_OBJECTS[walletId].isClosed(); +}; + +self.close = async function (walletId, save) { + return self.WORKER_OBJECTS[walletId].close(save); + delete self.WORKER_OBJECTS[walletId]; +}; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfSHR0cENsaWVudCIsIl9MaWJyYXJ5VXRpbHMiLCJfTW9uZXJvQmFuIiwiX01vbmVyb0Jsb2NrIiwiX01vbmVyb0RhZW1vbkNvbmZpZyIsIl9Nb25lcm9EYWVtb25MaXN0ZW5lciIsIl9Nb25lcm9EYWVtb25ScGMiLCJfTW9uZXJvRXJyb3IiLCJfTW9uZXJvS2V5SW1hZ2UiLCJfTW9uZXJvUnBjQ29ubmVjdGlvbiIsIl9Nb25lcm9UeENvbmZpZyIsIl9Nb25lcm9UeFNldCIsIl9Nb25lcm9VdGlscyIsIl9Nb25lcm9XYWxsZXRDb25maWciLCJfTW9uZXJvV2FsbGV0TGlzdGVuZXIiLCJfTW9uZXJvV2FsbGV0S2V5cyIsIl9Nb25lcm9XYWxsZXRGdWxsIiwiR2VuVXRpbHMiLCJpc0Rlbm8iLCJzZWxmIiwiZ2xvYmFsVGhpcyIsIkRlZGljYXRlZFdvcmtlckdsb2JhbFNjb3BlIiwicHJvdG90eXBlIiwiaXNQcm90b3R5cGVPZiIsIkh0dHBDbGllbnQiLCJMaWJyYXJ5VXRpbHMiLCJvbm1lc3NhZ2UiLCJlIiwiaW5pdE9uZVRpbWUiLCJvYmplY3RJZCIsImRhdGEiLCJmbk5hbWUiLCJjYWxsYmFja0lkIiwiYXNzZXJ0IiwiRXJyb3IiLCJzcGxpY2UiLCJwb3N0TWVzc2FnZSIsInJlc3VsdCIsImFwcGx5IiwiZXJyb3IiLCJzZXJpYWxpemVFcnJvciIsImlzSW5pdGlhbGl6ZWQiLCJXT1JLRVJfT0JKRUNUUyIsIk1vbmVyb1V0aWxzIiwiUFJPWFlfVE9fV09SS0VSIiwiaHR0cFJlcXVlc3QiLCJvcHRzIiwicmVxdWVzdCIsIk9iamVjdCIsImFzc2lnbiIsInByb3h5VG9Xb3JrZXIiLCJlcnIiLCJzdGF0dXNDb2RlIiwiSlNPTiIsInN0cmluZ2lmeSIsInN0YXR1c01lc3NhZ2UiLCJtZXNzYWdlIiwic2V0TG9nTGV2ZWwiLCJsZXZlbCIsImdldFdhc21NZW1vcnlVc2VkIiwiZ2V0V2FzbU1vZHVsZSIsIkhFQVA4IiwibGVuZ3RoIiwidW5kZWZpbmVkIiwibW9uZXJvVXRpbHNHZXRJbnRlZ3JhdGVkQWRkcmVzcyIsIm5ldHdvcmtUeXBlIiwic3RhbmRhcmRBZGRyZXNzIiwicGF5bWVudElkIiwiZ2V0SW50ZWdyYXRlZEFkZHJlc3MiLCJ0b0pzb24iLCJtb25lcm9VdGlsc1ZhbGlkYXRlQWRkcmVzcyIsImFkZHJlc3MiLCJ2YWxpZGF0ZUFkZHJlc3MiLCJtb25lcm9VdGlsc0pzb25Ub0JpbmFyeSIsImpzb24iLCJqc29uVG9CaW5hcnkiLCJtb25lcm9VdGlsc0JpbmFyeVRvSnNvbiIsInVpbnQ4YXJyIiwiYmluYXJ5VG9Kc29uIiwibW9uZXJvVXRpbHNCaW5hcnlCbG9ja3NUb0pzb24iLCJiaW5hcnlCbG9ja3NUb0pzb24iLCJkYWVtb25BZGRMaXN0ZW5lciIsImRhZW1vbklkIiwibGlzdGVuZXJJZCIsImxpc3RlbmVyIiwiTW9uZXJvRGFlbW9uTGlzdGVuZXIiLCJvbkJsb2NrSGVhZGVyIiwiYmxvY2tIZWFkZXIiLCJkYWVtb25MaXN0ZW5lcnMiLCJhZGRMaXN0ZW5lciIsImRhZW1vblJlbW92ZUxpc3RlbmVyIiwiTW9uZXJvRXJyb3IiLCJyZW1vdmVMaXN0ZW5lciIsImNvbm5lY3REYWVtb25ScGMiLCJjb25maWciLCJNb25lcm9EYWVtb25ScGMiLCJjb25uZWN0VG9EYWVtb25ScGMiLCJNb25lcm9EYWVtb25Db25maWciLCJkYWVtb25HZXRScGNDb25uZWN0aW9uIiwiY29ubmVjdGlvbiIsImdldFJwY0Nvbm5lY3Rpb24iLCJnZXRDb25maWciLCJkYWVtb25Jc0Nvbm5lY3RlZCIsImlzQ29ubmVjdGVkIiwiZGFlbW9uR2V0VmVyc2lvbiIsImdldFZlcnNpb24iLCJkYWVtb25Jc1RydXN0ZWQiLCJpc1RydXN0ZWQiLCJkYWVtb25HZXRIZWlnaHQiLCJnZXRIZWlnaHQiLCJkYWVtb25HZXRCbG9ja0hhc2giLCJoZWlnaHQiLCJnZXRCbG9ja0hhc2giLCJkYWVtb25HZXRCbG9ja1RlbXBsYXRlIiwid2FsbGV0QWRkcmVzcyIsInJlc2VydmVTaXplIiwiZ2V0QmxvY2tUZW1wbGF0ZSIsImRhZW1vbkdldExhc3RCbG9ja0hlYWRlciIsImdldExhc3RCbG9ja0hlYWRlciIsImRhZW1vbkdldEJsb2NrSGVhZGVyQnlIYXNoIiwiaGFzaCIsImdldEJsb2NrSGVhZGVyQnlIYXNoIiwiZGFlbW9uR2V0QmxvY2tIZWFkZXJCeUhlaWdodCIsImdldEJsb2NrSGVhZGVyQnlIZWlnaHQiLCJkYWVtb25HZXRCbG9ja0hlYWRlcnNCeVJhbmdlIiwic3RhcnRIZWlnaHQiLCJlbmRIZWlnaHQiLCJibG9ja0hlYWRlcnNKc29uIiwiZ2V0QmxvY2tIZWFkZXJzQnlSYW5nZSIsInB1c2giLCJkYWVtb25HZXRCbG9ja0J5SGFzaCIsImJsb2NrSGFzaCIsImdldEJsb2NrQnlIYXNoIiwiZGFlbW9uR2V0QmxvY2tzQnlIYXNoIiwiYmxvY2tIYXNoZXMiLCJwcnVuZSIsImJsb2Nrc0pzb24iLCJibG9jayIsImdldEJsb2Nrc0J5SGFzaCIsImRhZW1vbkdldEJsb2NrQnlIZWlnaHQiLCJnZXRCbG9ja0J5SGVpZ2h0IiwiZGFlbW9uR2V0QmxvY2tzQnlIZWlnaHQiLCJoZWlnaHRzIiwiZ2V0QmxvY2tzQnlIZWlnaHQiLCJkYWVtb25HZXRCbG9ja3NCeVJhbmdlIiwiZ2V0QmxvY2tzQnlSYW5nZSIsImRhZW1vbkdldEJsb2Nrc0J5UmFuZ2VDaHVua2VkIiwibWF4Q2h1bmtTaXplIiwiZ2V0QmxvY2tzQnlSYW5nZUNodW5rZWQiLCJkYWVtb25HZXRCbG9ja0hhc2hlcyIsImRhZW1vbkdldFR4cyIsInR4SGFzaGVzIiwidHhzIiwiZ2V0VHhzIiwiYmxvY2tzIiwidW5jb25maXJtZWRCbG9jayIsInNlZW5CbG9ja3MiLCJTZXQiLCJ0eCIsImdldEJsb2NrIiwiTW9uZXJvQmxvY2siLCJzZXRUeHMiLCJzZXRCbG9jayIsImhhcyIsImFkZCIsImkiLCJkYWVtb25HZXRUeEhleGVzIiwiZ2V0VHhIZXhlcyIsImRhZW1vbkdldE1pbmVyVHhTdW0iLCJudW1CbG9ja3MiLCJnZXRNaW5lclR4U3VtIiwiZGFlbW9uR2V0RmVlRXN0aW1hdGUiLCJncmFjZUJsb2NrcyIsImdldEZlZUVzdGltYXRlIiwiZGFlbW9uU3VibWl0VHhIZXgiLCJ0eEhleCIsImRvTm90UmVsYXkiLCJzdWJtaXRUeEhleCIsImRhZW1vblJlbGF5VHhzQnlIYXNoIiwicmVsYXlUeHNCeUhhc2giLCJkYWVtb25HZXRUeFBvb2wiLCJnZXRUeFBvb2wiLCJkYWVtb25HZXRUeFBvb2xIYXNoZXMiLCJnZXRUeFBvb2xIYXNoZXMiLCJkYWVtb25HZXRUeFBvb2xTdGF0cyIsImdldFR4UG9vbFN0YXRzIiwiZGFlbW9uRmx1c2hUeFBvb2wiLCJoYXNoZXMiLCJmbHVzaFR4UG9vbCIsImRhZW1vbkdldEtleUltYWdlU3BlbnRTdGF0dXNlcyIsImtleUltYWdlcyIsImdldEtleUltYWdlU3BlbnRTdGF0dXNlcyIsImRhZW1vbkdldE91dHB1dEhpc3RvZ3JhbSIsImFtb3VudHMiLCJtaW5Db3VudCIsIm1heENvdW50IiwiaXNVbmxvY2tlZCIsInJlY2VudEN1dG9mZiIsImVudHJpZXNKc29uIiwiZW50cnkiLCJnZXRPdXRwdXRIaXN0b2dyYW0iLCJkYWVtb25HZXRJbmZvIiwiZ2V0SW5mbyIsImRhZW1vbkdldFN5bmNJbmZvIiwiZ2V0U3luY0luZm8iLCJkYWVtb25HZXRIYXJkRm9ya0luZm8iLCJnZXRIYXJkRm9ya0luZm8iLCJkYWVtb25HZXRBbHRDaGFpbnMiLCJhbHRDaGFpbnNKc29uIiwiYWx0Q2hhaW4iLCJnZXRBbHRDaGFpbnMiLCJkYWVtb25HZXRBbHRCbG9ja0hhc2hlcyIsImdldEFsdEJsb2NrSGFzaGVzIiwiZGFlbW9uR2V0RG93bmxvYWRMaW1pdCIsImdldERvd25sb2FkTGltaXQiLCJkYWVtb25TZXREb3dubG9hZExpbWl0IiwibGltaXQiLCJzZXREb3dubG9hZExpbWl0IiwiZGFlbW9uUmVzZXREb3dubG9hZExpbWl0IiwicmVzZXREb3dubG9hZExpbWl0IiwiZGFlbW9uR2V0VXBsb2FkTGltaXQiLCJnZXRVcGxvYWRMaW1pdCIsImRhZW1vblNldFVwbG9hZExpbWl0Iiwic2V0VXBsb2FkTGltaXQiLCJkYWVtb25SZXNldFVwbG9hZExpbWl0IiwicmVzZXRVcGxvYWRMaW1pdCIsImRhZW1vbkdldFBlZXJzIiwicGVlcnNKc29uIiwicGVlciIsImdldFBlZXJzIiwiZGFlbW9uR2V0S25vd25QZWVycyIsImdldEtub3duUGVlcnMiLCJkYWVtb25TZXRPdXRnb2luZ1BlZXJMaW1pdCIsInNldE91dGdvaW5nUGVlckxpbWl0IiwiZGFlbW9uU2V0SW5jb21pbmdQZWVyTGltaXQiLCJzZXRJbmNvbWluZ1BlZXJMaW1pdCIsImRhZW1vbkdldFBlZXJCYW5zIiwiYmFuc0pzb24iLCJiYW4iLCJnZXRQZWVyQmFucyIsImRhZW1vblNldFBlZXJCYW5zIiwiYmFucyIsImJhbkpzb24iLCJNb25lcm9CYW4iLCJzZXRQZWVyQmFucyIsImRhZW1vblN0YXJ0TWluaW5nIiwibnVtVGhyZWFkcyIsImlzQmFja2dyb3VuZCIsImlnbm9yZUJhdHRlcnkiLCJzdGFydE1pbmluZyIsImRhZW1vblN0b3BNaW5pbmciLCJzdG9wTWluaW5nIiwiZGFlbW9uR2V0TWluaW5nU3RhdHVzIiwiZ2V0TWluaW5nU3RhdHVzIiwiZGFlbW9uU3VibWl0QmxvY2tzIiwiYmxvY2tCbG9icyIsInN1Ym1pdEJsb2NrcyIsImRhZW1vblBydW5lQmxvY2tjaGFpbiIsImNoZWNrIiwicHJ1bmVCbG9ja2NoYWluIiwiZGFlbW9uU3RvcCIsInN0b3AiLCJkYWVtb25XYWl0Rm9yTmV4dEJsb2NrSGVhZGVyIiwid2FpdEZvck5leHRCbG9ja0hlYWRlciIsIm9wZW5XYWxsZXREYXRhIiwid2FsbGV0SWQiLCJwYXRoIiwicGFzc3dvcmQiLCJrZXlzRGF0YSIsImNhY2hlRGF0YSIsImRhZW1vblVyaU9yQ29uZmlnIiwiZGFlbW9uQ29ubmVjdGlvbiIsIk1vbmVyb1JwY0Nvbm5lY3Rpb24iLCJNb25lcm9XYWxsZXRGdWxsIiwib3BlbldhbGxldCIsInNlcnZlciIsInNldEJyb3dzZXJNYWluUGF0aCIsImNyZWF0ZVdhbGxldEtleXMiLCJjb25maWdKc29uIiwiTW9uZXJvV2FsbGV0Q29uZmlnIiwic2V0UHJveHlUb1dvcmtlciIsIk1vbmVyb1dhbGxldEtleXMiLCJjcmVhdGVXYWxsZXQiLCJjcmVhdGVXYWxsZXRGdWxsIiwiZ2V0UGF0aCIsInNldFBhdGgiLCJpc1ZpZXdPbmx5IiwiZ2V0TmV0d29ya1R5cGUiLCJnZXRTZWVkIiwiZ2V0U2VlZExhbmd1YWdlIiwiZ2V0U2VlZExhbmd1YWdlcyIsImdldFByaXZhdGVTcGVuZEtleSIsImdldFByaXZhdGVWaWV3S2V5IiwiZ2V0UHVibGljVmlld0tleSIsImdldFB1YmxpY1NwZW5kS2V5IiwiZ2V0QWRkcmVzcyIsImFjY291bnRJZHgiLCJzdWJhZGRyZXNzSWR4IiwiZ2V0QWRkcmVzc0luZGV4Iiwic2V0U3ViYWRkcmVzc0xhYmVsIiwibGFiZWwiLCJkZWNvZGVJbnRlZ3JhdGVkQWRkcmVzcyIsImludGVncmF0ZWRBZGRyZXNzIiwic2V0RGFlbW9uQ29ubmVjdGlvbiIsImdldERhZW1vbkNvbm5lY3Rpb24iLCJpc0Nvbm5lY3RlZFRvRGFlbW9uIiwiZ2V0UmVzdG9yZUhlaWdodCIsInNldFJlc3RvcmVIZWlnaHQiLCJyZXN0b3JlSGVpZ2h0IiwiZ2V0RGFlbW9uSGVpZ2h0IiwiZ2V0RGFlbW9uTWF4UGVlckhlaWdodCIsImdldEhlaWdodEJ5RGF0ZSIsInllYXIiLCJtb250aCIsImRheSIsImlzRGFlbW9uU3luY2VkIiwiV2FsbGV0V29ya2VySGVscGVyTGlzdGVuZXIiLCJNb25lcm9XYWxsZXRMaXN0ZW5lciIsImNvbnN0cnVjdG9yIiwiaWQiLCJ3b3JrZXIiLCJnZXRJZCIsIm9uU3luY1Byb2dyZXNzIiwicGVyY2VudERvbmUiLCJvbk5ld0Jsb2NrIiwib25CYWxhbmNlc0NoYW5nZWQiLCJuZXdCYWxhbmNlIiwibmV3VW5sb2NrZWRCYWxhbmNlIiwidG9TdHJpbmciLCJvbk91dHB1dFJlY2VpdmVkIiwib3V0cHV0IiwiZ2V0VHgiLCJvbk91dHB1dFNwZW50IiwibGlzdGVuZXJzIiwiaXNTeW5jZWQiLCJzeW5jIiwiYWxsb3dDb25jdXJyZW50Q2FsbHMiLCJzdGFydFN5bmNpbmciLCJzeW5jUGVyaW9kSW5NcyIsInN0b3BTeW5jaW5nIiwic2NhblR4cyIsInJlc2NhblNwZW50IiwicmVzY2FuQmxvY2tjaGFpbiIsImdldEJhbGFuY2UiLCJnZXRVbmxvY2tlZEJhbGFuY2UiLCJnZXRBY2NvdW50cyIsImluY2x1ZGVTdWJhZGRyZXNzZXMiLCJ0YWciLCJhY2NvdW50SnNvbnMiLCJhY2NvdW50IiwiZ2V0QWNjb3VudCIsImNyZWF0ZUFjY291bnQiLCJnZXRTdWJhZGRyZXNzZXMiLCJzdWJhZGRyZXNzSW5kaWNlcyIsInN1YmFkZHJlc3NKc29ucyIsInN1YmFkZHJlc3MiLCJjcmVhdGVTdWJhZGRyZXNzIiwiYmxvY2tKc29uUXVlcnkiLCJxdWVyeSIsIkRlc2VyaWFsaXphdGlvblR5cGUiLCJUWF9RVUVSWSIsImdldFRyYW5zZmVycyIsImdldFRyYW5zZmVyUXVlcnkiLCJ0cmFuc2ZlcnMiLCJ0cmFuc2ZlciIsImdldE91dHB1dHMiLCJnZXRPdXRwdXRRdWVyeSIsIm91dHB1dHMiLCJleHBvcnRPdXRwdXRzIiwiYWxsIiwiaW1wb3J0T3V0cHV0cyIsIm91dHB1dHNIZXgiLCJnZXRLZXlJbWFnZXMiLCJrZXlJbWFnZXNKc29uIiwia2V5SW1hZ2UiLCJleHBvcnRLZXlJbWFnZXMiLCJpbXBvcnRLZXlJbWFnZXMiLCJrZXlJbWFnZUpzb24iLCJNb25lcm9LZXlJbWFnZSIsImZyZWV6ZU91dHB1dCIsInRoYXdPdXRwdXQiLCJpc091dHB1dEZyb3plbiIsImdldERlZmF1bHRGZWVQcmlvcml0eSIsImNyZWF0ZVR4cyIsIk1vbmVyb1R4Q29uZmlnIiwiZ2V0VHhTZXQiLCJzd2VlcE91dHB1dCIsInN3ZWVwVW5sb2NrZWQiLCJ0eFNldHMiLCJhcnJheUNvbnRhaW5zIiwidHhTZXRzSnNvbiIsInR4U2V0Iiwic3dlZXBEdXN0IiwicmVsYXkiLCJyZWxheVR4cyIsInR4TWV0YWRhdGFzIiwiZGVzY3JpYmVUeFNldCIsInR4U2V0SnNvbiIsIk1vbmVyb1R4U2V0Iiwic2lnblR4cyIsInVuc2lnbmVkVHhIZXgiLCJzdWJtaXRUeHMiLCJzaWduZWRUeEhleCIsInNpZ25NZXNzYWdlIiwic2lnbmF0dXJlVHlwZSIsInZlcmlmeU1lc3NhZ2UiLCJzaWduYXR1cmUiLCJnZXRUeEtleSIsInR4SGFzaCIsImNoZWNrVHhLZXkiLCJ0eEtleSIsImdldFR4UHJvb2YiLCJjaGVja1R4UHJvb2YiLCJnZXRTcGVuZFByb29mIiwiY2hlY2tTcGVuZFByb29mIiwiZ2V0UmVzZXJ2ZVByb29mV2FsbGV0IiwiZ2V0UmVzZXJ2ZVByb29mQWNjb3VudCIsImFtb3VudFN0ciIsImNoZWNrUmVzZXJ2ZVByb29mIiwiZ2V0VHhOb3RlcyIsInNldFR4Tm90ZXMiLCJ0eE5vdGVzIiwiZ2V0QWRkcmVzc0Jvb2tFbnRyaWVzIiwiZW50cnlJbmRpY2VzIiwiYWRkQWRkcmVzc0Jvb2tFbnRyeSIsImRlc2NyaXB0aW9uIiwiZWRpdEFkZHJlc3NCb29rRW50cnkiLCJpbmRleCIsInNldEFkZHJlc3MiLCJzZXREZXNjcmlwdGlvbiIsImRlbGV0ZUFkZHJlc3NCb29rRW50cnkiLCJ0YWdBY2NvdW50cyIsImFjY291bnRJbmRpY2VzIiwidW50YWdBY2NvdW50cyIsImdldEFjY291bnRUYWdzIiwic2V0QWNjb3VudFRhZ0xhYmVsIiwiZ2V0UGF5bWVudFVyaSIsInBhcnNlUGF5bWVudFVyaSIsInVyaSIsImdldEF0dHJpYnV0ZSIsImtleSIsInNldEF0dHJpYnV0ZSIsInZhbHVlIiwiYmFja2dyb3VuZE1pbmluZyIsImlzTXVsdGlzaWdJbXBvcnROZWVkZWQiLCJpc011bHRpc2lnIiwiZ2V0TXVsdGlzaWdJbmZvIiwicHJlcGFyZU11bHRpc2lnIiwibWFrZU11bHRpc2lnIiwibXVsdGlzaWdIZXhlcyIsInRocmVzaG9sZCIsImV4Y2hhbmdlTXVsdGlzaWdLZXlzIiwiZXhwb3J0TXVsdGlzaWdIZXgiLCJpbXBvcnRNdWx0aXNpZ0hleCIsInNpZ25NdWx0aXNpZ1R4SGV4IiwibXVsdGlzaWdUeEhleCIsInN1Ym1pdE11bHRpc2lnVHhIZXgiLCJzaWduZWRNdWx0aXNpZ1R4SGV4IiwiZ2V0RGF0YSIsImNoYW5nZVBhc3N3b3JkIiwib2xkUGFzc3dvcmQiLCJuZXdQYXNzd29yZCIsImlzQ2xvc2VkIiwiY2xvc2UiLCJzYXZlIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvY29tbW9uL01vbmVyb1dlYldvcmtlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi9HZW5VdGlsc1wiO1xuaW1wb3J0IEh0dHBDbGllbnQgZnJvbSBcIi4vSHR0cENsaWVudFwiO1xuaW1wb3J0IExpYnJhcnlVdGlscyBmcm9tIFwiLi9MaWJyYXJ5VXRpbHNcIjtcbmltcG9ydCBNb25lcm9CYW4gZnJvbSBcIi4uL2RhZW1vbi9tb2RlbC9Nb25lcm9CYW5cIjtcbmltcG9ydCBNb25lcm9CbG9jayBmcm9tIFwiLi4vZGFlbW9uL21vZGVsL01vbmVyb0Jsb2NrXCI7XG5pbXBvcnQgTW9uZXJvRGFlbW9uQ29uZmlnIGZyb20gXCIuLi9kYWVtb24vbW9kZWwvTW9uZXJvRGFlbW9uQ29uZmlnXCI7XG5pbXBvcnQgTW9uZXJvRGFlbW9uTGlzdGVuZXIgZnJvbSBcIi4uL2RhZW1vbi9tb2RlbC9Nb25lcm9EYWVtb25MaXN0ZW5lclwiO1xuaW1wb3J0IE1vbmVyb0RhZW1vblJwYyBmcm9tIFwiLi4vZGFlbW9uL01vbmVyb0RhZW1vblJwY1wiO1xuaW1wb3J0IE1vbmVyb0Vycm9yIGZyb20gXCIuL01vbmVyb0Vycm9yXCI7XG5pbXBvcnQgTW9uZXJvS2V5SW1hZ2UgZnJvbSBcIi4uL2RhZW1vbi9tb2RlbC9Nb25lcm9LZXlJbWFnZVwiO1xuaW1wb3J0IE1vbmVyb1JwY0Nvbm5lY3Rpb24gZnJvbSBcIi4vTW9uZXJvUnBjQ29ubmVjdGlvblwiO1xuaW1wb3J0IE1vbmVyb1R4Q29uZmlnIGZyb20gXCIuLi93YWxsZXQvbW9kZWwvTW9uZXJvVHhDb25maWdcIjtcbmltcG9ydCBNb25lcm9UeFF1ZXJ5IGZyb20gXCIuLi93YWxsZXQvbW9kZWwvTW9uZXJvVHhRdWVyeVwiO1xuaW1wb3J0IE1vbmVyb1R4U2V0IGZyb20gXCIuLi93YWxsZXQvbW9kZWwvTW9uZXJvVHhTZXRcIjtcbmltcG9ydCBNb25lcm9VdGlscyBmcm9tIFwiLi9Nb25lcm9VdGlsc1wiO1xuaW1wb3J0IE1vbmVyb1dhbGxldENvbmZpZyBmcm9tIFwiLi4vd2FsbGV0L21vZGVsL01vbmVyb1dhbGxldENvbmZpZ1wiXG5pbXBvcnQgTW9uZXJvV2FsbGV0TGlzdGVuZXIgZnJvbSBcIi4uL3dhbGxldC9tb2RlbC9Nb25lcm9XYWxsZXRMaXN0ZW5lclwiXG5pbXBvcnQge01vbmVyb1dhbGxldEtleXN9IGZyb20gXCIuLi93YWxsZXQvTW9uZXJvV2FsbGV0S2V5c1wiO1xuaW1wb3J0IE1vbmVyb1dhbGxldEZ1bGwgZnJvbSBcIi4uL3dhbGxldC9Nb25lcm9XYWxsZXRGdWxsXCI7XG5cbmRlY2xhcmUgdmFyIHNlbGY6IGFueTtcblxuLy8gZGVubyBjb25maWd1cmF0aW9uXG5kZWNsYXJlIHZhciBEZWRpY2F0ZWRXb3JrZXJHbG9iYWxTY29wZTogYW55O1xuaWYgKEdlblV0aWxzLmlzRGVubygpICYmIHR5cGVvZiBzZWxmID09PSBcInVuZGVmaW5lZFwiICYmIHR5cGVvZiBnbG9iYWxUaGlzID09PSBcIm9iamVjdFwiICYmIHR5cGVvZiBEZWRpY2F0ZWRXb3JrZXJHbG9iYWxTY29wZSA9PT0gXCJmdW5jdGlvblwiICYmIERlZGljYXRlZFdvcmtlckdsb2JhbFNjb3BlLnByb3RvdHlwZS5pc1Byb3RvdHlwZU9mKGdsb2JhbFRoaXMpKSB7XG4gIHNlbGYgPSBnbG9iYWxUaGlzO1xuICAoZ2xvYmFsVGhpcyBhcyBhbnkpLnNlbGYgPSBnbG9iYWxUaGlzO1xufVxuXG4vLyBleHBvc2Ugc29tZSBtb2R1bGVzIHRvIHRoZSB3b3JrZXJcbnNlbGYuSHR0cENsaWVudCA9IEh0dHBDbGllbnQ7XG5zZWxmLkxpYnJhcnlVdGlscyA9IExpYnJhcnlVdGlscztcbnNlbGYuR2VuVXRpbHMgPSBHZW5VdGlscztcblxuLyoqXG4gKiBXb3JrZXIgdG8gbWFuYWdlIGEgZGFlbW9uIGFuZCB3YXNtIHdhbGxldCBvZmYgdGhlIG1haW4gdGhyZWFkIHVzaW5nIG1lc3NhZ2VzLlxuICogXG4gKiBSZXF1aXJlZCBtZXNzYWdlIGZvcm1hdDogZS5kYXRhWzBdID0gb2JqZWN0IGlkLCBlLmRhdGFbMV0gPSBmdW5jdGlvbiBuYW1lLCBlLmRhdGFbMitdID0gZnVuY3Rpb24gYXJnc1xuICpcbiAqIEZvciBicm93c2VyIGFwcGxpY2F0aW9ucywgdGhpcyBmaWxlIG11c3QgYmUgYnJvd3NlcmlmaWVkIGFuZCBwbGFjZWQgaW4gdGhlIHdlYiBhcHAgcm9vdC5cbiAqIFxuICogQHByaXZhdGVcbiAqL1xuc2VsZi5vbm1lc3NhZ2UgPSBhc3luYyBmdW5jdGlvbihlKSB7XG4gIFxuICAvLyBpbml0aWFsaXplIG9uZSB0aW1lXG4gIGF3YWl0IHNlbGYuaW5pdE9uZVRpbWUoKTtcbiAgXG4gIC8vIHZhbGlkYXRlIHBhcmFtc1xuICBsZXQgb2JqZWN0SWQgPSBlLmRhdGFbMF07XG4gIGxldCBmbk5hbWUgPSBlLmRhdGFbMV07XG4gIGxldCBjYWxsYmFja0lkID0gZS5kYXRhWzJdO1xuICBhc3NlcnQoZm5OYW1lLCBcIk11c3QgcHJvdmlkZSBmdW5jdGlvbiBuYW1lIHRvIHdvcmtlclwiKTtcbiAgYXNzZXJ0KGNhbGxiYWNrSWQsIFwiTXVzdCBwcm92aWRlIGNhbGxiYWNrIGlkIHRvIHdvcmtlclwiKTtcbiAgaWYgKCFzZWxmW2ZuTmFtZV0pIHRocm93IG5ldyBFcnJvcihcIk1ldGhvZCAnXCIgKyBmbk5hbWUgKyBcIicgaXMgbm90IHJlZ2lzdGVyZWQgd2l0aCB3b3JrZXJcIik7XG4gIGUuZGF0YS5zcGxpY2UoMSwgMik7IC8vIHJlbW92ZSBmdW5jdGlvbiBuYW1lIGFuZCBjYWxsYmFjayBpZCB0byBhcHBseSBmdW5jdGlvbiB3aXRoIGFyZ3VtZW50c1xuICBcbiAgLy8gZXhlY3V0ZSB3b3JrZXIgZnVuY3Rpb24gYW5kIHBvc3QgcmVzdWx0IHRvIGNhbGxiYWNrXG4gIHRyeSB7XG4gICAgcG9zdE1lc3NhZ2UoW29iamVjdElkLCBjYWxsYmFja0lkLCB7cmVzdWx0OiBhd2FpdCBzZWxmW2ZuTmFtZV0uYXBwbHkobnVsbCwgZS5kYXRhKX1dKTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgaWYgKCEoZSBpbnN0YW5jZW9mIEVycm9yKSkgZSA9IG5ldyBFcnJvcihlKTtcbiAgICBwb3N0TWVzc2FnZShbb2JqZWN0SWQsIGNhbGxiYWNrSWQsIHtlcnJvcjogTGlicmFyeVV0aWxzLnNlcmlhbGl6ZUVycm9yKGUpfV0pO1xuICB9XG59XG5cbnNlbGYuaW5pdE9uZVRpbWUgPSBhc3luYyBmdW5jdGlvbigpIHtcbiAgaWYgKCFzZWxmLmlzSW5pdGlhbGl6ZWQpIHtcbiAgICBzZWxmLldPUktFUl9PQkpFQ1RTID0ge307XG4gICAgc2VsZi5pc0luaXRpYWxpemVkID0gdHJ1ZTtcbiAgICBNb25lcm9VdGlscy5QUk9YWV9UT19XT1JLRVIgPSBmYWxzZTtcbiAgfVxufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gU1RBVElDIFVUSUxJVElFUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbnNlbGYuaHR0cFJlcXVlc3QgPSBhc3luYyBmdW5jdGlvbihvYmplY3RJZCwgb3B0cykge1xuICB0cnkge1xuICAgIHJldHVybiBhd2FpdCBIdHRwQ2xpZW50LnJlcXVlc3QoT2JqZWN0LmFzc2lnbihvcHRzLCB7cHJveHlUb1dvcmtlcjogZmFsc2V9KSk7ICBcbiAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICB0aHJvdyBlcnIuc3RhdHVzQ29kZSA/IG5ldyBFcnJvcihKU09OLnN0cmluZ2lmeSh7c3RhdHVzQ29kZTogZXJyLnN0YXR1c0NvZGUsIHN0YXR1c01lc3NhZ2U6IGVyci5tZXNzYWdlfSkpIDogZXJyO1xuICB9XG59XG5cbnNlbGYuc2V0TG9nTGV2ZWwgPSBhc3luYyBmdW5jdGlvbihvYmplY3RJZCwgbGV2ZWwpIHtcbiAgcmV0dXJuIExpYnJhcnlVdGlscy5zZXRMb2dMZXZlbChsZXZlbCk7XG59XG5cbnNlbGYuZ2V0V2FzbU1lbW9yeVVzZWQgPSBhc3luYyBmdW5jdGlvbihvYmplY3RJZCkge1xuICByZXR1cm4gTGlicmFyeVV0aWxzLmdldFdhc21Nb2R1bGUoKSAmJiBMaWJyYXJ5VXRpbHMuZ2V0V2FzbU1vZHVsZSgpLkhFQVA4ID8gTGlicmFyeVV0aWxzLmdldFdhc21Nb2R1bGUoKS5IRUFQOC5sZW5ndGggOiB1bmRlZmluZWQ7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIE1PTkVSTyBVVElMUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuc2VsZi5tb25lcm9VdGlsc0dldEludGVncmF0ZWRBZGRyZXNzID0gYXN5bmMgZnVuY3Rpb24ob2JqZWN0SWQsIG5ldHdvcmtUeXBlLCBzdGFuZGFyZEFkZHJlc3MsIHBheW1lbnRJZCkge1xuICByZXR1cm4gKGF3YWl0IE1vbmVyb1V0aWxzLmdldEludGVncmF0ZWRBZGRyZXNzKG5ldHdvcmtUeXBlLCBzdGFuZGFyZEFkZHJlc3MsIHBheW1lbnRJZCkpLnRvSnNvbigpO1xufVxuXG5zZWxmLm1vbmVyb1V0aWxzVmFsaWRhdGVBZGRyZXNzID0gYXN5bmMgZnVuY3Rpb24ob2JqZWN0SWQsIGFkZHJlc3MsIG5ldHdvcmtUeXBlKSB7XG4gIHJldHVybiBNb25lcm9VdGlscy52YWxpZGF0ZUFkZHJlc3MoYWRkcmVzcywgbmV0d29ya1R5cGUpO1xufVxuXG5zZWxmLm1vbmVyb1V0aWxzSnNvblRvQmluYXJ5ID0gYXN5bmMgZnVuY3Rpb24ob2JqZWN0SWQsIGpzb24pIHtcbiAgcmV0dXJuIE1vbmVyb1V0aWxzLmpzb25Ub0JpbmFyeShqc29uKTtcbn1cblxuc2VsZi5tb25lcm9VdGlsc0JpbmFyeVRvSnNvbiA9IGFzeW5jIGZ1bmN0aW9uKG9iamVjdElkLCB1aW50OGFycikge1xuICByZXR1cm4gTW9uZXJvVXRpbHMuYmluYXJ5VG9Kc29uKHVpbnQ4YXJyKTtcbn1cblxuc2VsZi5tb25lcm9VdGlsc0JpbmFyeUJsb2Nrc1RvSnNvbiA9IGFzeW5jIGZ1bmN0aW9uKG9iamVjdElkLCB1aW50OGFycikge1xuICByZXR1cm4gTW9uZXJvVXRpbHMuYmluYXJ5QmxvY2tzVG9Kc29uKHVpbnQ4YXJyKTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBEQUVNT04gTUVUSE9EUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5zZWxmLmRhZW1vbkFkZExpc3RlbmVyID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQsIGxpc3RlbmVySWQpIHtcbiAgbGV0IGxpc3RlbmVyID0gbmV3IGNsYXNzIGV4dGVuZHMgTW9uZXJvRGFlbW9uTGlzdGVuZXIge1xuICAgIGFzeW5jIG9uQmxvY2tIZWFkZXIoYmxvY2tIZWFkZXIpIHtcbiAgICAgIHNlbGYucG9zdE1lc3NhZ2UoW2RhZW1vbklkLCBcIm9uQmxvY2tIZWFkZXJfXCIgKyBsaXN0ZW5lcklkLCBibG9ja0hlYWRlci50b0pzb24oKV0pO1xuICAgIH1cbiAgfVxuICBpZiAoIXNlbGYuZGFlbW9uTGlzdGVuZXJzKSBzZWxmLmRhZW1vbkxpc3RlbmVycyA9IHt9O1xuICBzZWxmLmRhZW1vbkxpc3RlbmVyc1tsaXN0ZW5lcklkXSA9IGxpc3RlbmVyO1xuICBhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5hZGRMaXN0ZW5lcihsaXN0ZW5lcik7XG59XG5cbnNlbGYuZGFlbW9uUmVtb3ZlTGlzdGVuZXIgPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCwgbGlzdGVuZXJJZCkge1xuICBpZiAoIXNlbGYuZGFlbW9uTGlzdGVuZXJzW2xpc3RlbmVySWRdKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJObyBkYWVtb24gd29ya2VyIGxpc3RlbmVyIHJlZ2lzdGVyZWQgd2l0aCBpZDogXCIgKyBsaXN0ZW5lcklkKTtcbiAgYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0ucmVtb3ZlTGlzdGVuZXIoc2VsZi5kYWVtb25MaXN0ZW5lcnNbbGlzdGVuZXJJZF0pO1xuICBkZWxldGUgc2VsZi5kYWVtb25MaXN0ZW5lcnNbbGlzdGVuZXJJZF07XG59XG5cbnNlbGYuY29ubmVjdERhZW1vblJwYyA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkLCBjb25maWcpIHtcbiAgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0gPSBhd2FpdCBNb25lcm9EYWVtb25ScGMuY29ubmVjdFRvRGFlbW9uUnBjKG5ldyBNb25lcm9EYWVtb25Db25maWcoY29uZmlnKSk7XG59XG5cbnNlbGYuZGFlbW9uR2V0UnBjQ29ubmVjdGlvbiA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkKSB7XG4gIGxldCBjb25uZWN0aW9uID0gYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0UnBjQ29ubmVjdGlvbigpO1xuICByZXR1cm4gY29ubmVjdGlvbiA/IGNvbm5lY3Rpb24uZ2V0Q29uZmlnKCkgOiB1bmRlZmluZWQ7XG59XG5cbnNlbGYuZGFlbW9uSXNDb25uZWN0ZWQgPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uaXNDb25uZWN0ZWQoKTtcbn1cblxuc2VsZi5kYWVtb25HZXRWZXJzaW9uID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQpIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5nZXRWZXJzaW9uKCkpLnRvSnNvbigpO1xufVxuXG5zZWxmLmRhZW1vbklzVHJ1c3RlZCA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5pc1RydXN0ZWQoKTtcbn1cblxuc2VsZi5kYWVtb25HZXRIZWlnaHQgPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0SGVpZ2h0KCk7XG59XG5cbnNlbGYuZGFlbW9uR2V0QmxvY2tIYXNoID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQsIGhlaWdodCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0QmxvY2tIYXNoKGhlaWdodCk7XG59XG5cbnNlbGYuZGFlbW9uR2V0QmxvY2tUZW1wbGF0ZSA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkLCB3YWxsZXRBZGRyZXNzLCByZXNlcnZlU2l6ZSkge1xuICByZXR1cm4gKGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLmdldEJsb2NrVGVtcGxhdGUod2FsbGV0QWRkcmVzcywgcmVzZXJ2ZVNpemUpKS50b0pzb24oKTtcbn1cblxuc2VsZi5kYWVtb25HZXRMYXN0QmxvY2tIZWFkZXIgPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCkge1xuICByZXR1cm4gKGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLmdldExhc3RCbG9ja0hlYWRlcigpKS50b0pzb24oKTtcbn1cblxuc2VsZi5kYWVtb25HZXRCbG9ja0hlYWRlckJ5SGFzaCA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkLCBoYXNoKSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0QmxvY2tIZWFkZXJCeUhhc2goaGFzaCkpLnRvSnNvbigpO1xufVxuXG5zZWxmLmRhZW1vbkdldEJsb2NrSGVhZGVyQnlIZWlnaHQgPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCwgaGVpZ2h0KSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0QmxvY2tIZWFkZXJCeUhlaWdodChoZWlnaHQpKS50b0pzb24oKTtcbn1cblxuc2VsZi5kYWVtb25HZXRCbG9ja0hlYWRlcnNCeVJhbmdlID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQsIHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQpIHtcbiAgbGV0IGJsb2NrSGVhZGVyc0pzb24gPSBbXTtcbiAgZm9yIChsZXQgYmxvY2tIZWFkZXIgb2YgYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0QmxvY2tIZWFkZXJzQnlSYW5nZShzdGFydEhlaWdodCwgZW5kSGVpZ2h0KSkgYmxvY2tIZWFkZXJzSnNvbi5wdXNoKGJsb2NrSGVhZGVyLnRvSnNvbigpKTtcbiAgcmV0dXJuIGJsb2NrSGVhZGVyc0pzb247XG59XG5cbnNlbGYuZGFlbW9uR2V0QmxvY2tCeUhhc2ggPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCwgYmxvY2tIYXNoKSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0QmxvY2tCeUhhc2goYmxvY2tIYXNoKSkudG9Kc29uKCk7XG59XG5cbnNlbGYuZGFlbW9uR2V0QmxvY2tzQnlIYXNoID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQsIGJsb2NrSGFzaGVzLCBzdGFydEhlaWdodCwgcHJ1bmUpIHtcbiAgbGV0IGJsb2Nrc0pzb24gPSBbXTtcbiAgZm9yIChsZXQgYmxvY2sgb2YgYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0QmxvY2tzQnlIYXNoKGJsb2NrSGFzaGVzLCBzdGFydEhlaWdodCwgcHJ1bmUpKSBibG9ja3NKc29uLnB1c2goYmxvY2sudG9Kc29uKCkpO1xuICByZXR1cm4gYmxvY2tzSnNvbjtcbn1cblxuc2VsZi5kYWVtb25HZXRCbG9ja0J5SGVpZ2h0ID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQsIGhlaWdodCkge1xuICByZXR1cm4gKGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLmdldEJsb2NrQnlIZWlnaHQoaGVpZ2h0KSkudG9Kc29uKCk7XG59XG5cbnNlbGYuZGFlbW9uR2V0QmxvY2tzQnlIZWlnaHQgPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCwgaGVpZ2h0cykge1xuICBsZXQgYmxvY2tzSnNvbiA9IFtdO1xuICBmb3IgKGxldCBibG9jayBvZiBhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5nZXRCbG9ja3NCeUhlaWdodChoZWlnaHRzKSkgYmxvY2tzSnNvbi5wdXNoKGJsb2NrLnRvSnNvbigpKTtcbiAgcmV0dXJuIGJsb2Nrc0pzb247XG59XG5cbnNlbGYuZGFlbW9uR2V0QmxvY2tzQnlSYW5nZSA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkLCBzdGFydEhlaWdodCwgZW5kSGVpZ2h0KSB7XG4gIGxldCBibG9ja3NKc29uID0gW107XG4gIGZvciAobGV0IGJsb2NrIG9mIGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLmdldEJsb2Nrc0J5UmFuZ2Uoc3RhcnRIZWlnaHQsIGVuZEhlaWdodCkpIGJsb2Nrc0pzb24ucHVzaChibG9jay50b0pzb24oKSk7XG4gIHJldHVybiBibG9ja3NKc29uO1xufVxuXG5zZWxmLmRhZW1vbkdldEJsb2Nrc0J5UmFuZ2VDaHVua2VkID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQsIHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQsIG1heENodW5rU2l6ZSkge1xuICBsZXQgYmxvY2tzSnNvbiA9IFtdO1xuICBmb3IgKGxldCBibG9jayBvZiBhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5nZXRCbG9ja3NCeVJhbmdlQ2h1bmtlZChzdGFydEhlaWdodCwgZW5kSGVpZ2h0LCBtYXhDaHVua1NpemUpKSBibG9ja3NKc29uLnB1c2goYmxvY2sudG9Kc29uKCkpO1xuICByZXR1cm4gYmxvY2tzSnNvbjtcbn1cblxuc2VsZi5kYWVtb25HZXRCbG9ja0hhc2hlcyA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkLCBibG9ja0hhc2hlcywgc3RhcnRIZWlnaHQpIHtcbiAgdGhyb3cgbmV3IEVycm9yKFwid29ya2VyLmdldEJsb2NrSGFzaGVzIG5vdCBpbXBsZW1lbnRlZFwiKTtcbn1cblxuLy8gVE9ETzogZmFjdG9yIGNvbW1vbiBjb2RlIHdpdGggc2VsZi5nZXRUeHMoKVxuc2VsZi5kYWVtb25HZXRUeHMgPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCwgdHhIYXNoZXMsIHBydW5lKSB7XG4gIFxuICAvLyBnZXQgdHhzXG4gIGxldCB0eHMgPSBhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5nZXRUeHModHhIYXNoZXMsIHBydW5lKTtcbiAgXG4gIC8vIGNvbGxlY3QgdW5pcXVlIGJsb2NrcyB0byBwcmVzZXJ2ZSBtb2RlbCByZWxhdGlvbnNoaXBzIGFzIHRyZWVzIChiYXNlZCBvbiBtb25lcm9fd2FzbV9icmlkZ2UuY3BwOjpnZXRfdHhzKVxuICBsZXQgYmxvY2tzID0gW107XG4gIGxldCB1bmNvbmZpcm1lZEJsb2NrID0gdW5kZWZpbmVkXG4gIGxldCBzZWVuQmxvY2tzID0gbmV3IFNldCgpO1xuICBmb3IgKGxldCB0eCBvZiB0eHMpIHtcbiAgICBpZiAoIXR4LmdldEJsb2NrKCkpIHtcbiAgICAgIGlmICghdW5jb25maXJtZWRCbG9jaykgdW5jb25maXJtZWRCbG9jayA9IG5ldyBNb25lcm9CbG9jaygpLnNldFR4cyhbXSk7XG4gICAgICB0eC5zZXRCbG9jayh1bmNvbmZpcm1lZEJsb2NrKTtcbiAgICAgIHVuY29uZmlybWVkQmxvY2suZ2V0VHhzKCkucHVzaCh0eCk7XG4gICAgfVxuICAgIGlmICghc2VlbkJsb2Nrcy5oYXModHguZ2V0QmxvY2soKSkpIHtcbiAgICAgIHNlZW5CbG9ja3MuYWRkKHR4LmdldEJsb2NrKCkpO1xuICAgICAgYmxvY2tzLnB1c2godHguZ2V0QmxvY2soKSk7XG4gICAgfVxuICB9XG4gIFxuICAvLyBzZXJpYWxpemUgYmxvY2tzIHRvIGpzb25cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBibG9ja3MubGVuZ3RoOyBpKyspIGJsb2Nrc1tpXSA9IGJsb2Nrc1tpXS50b0pzb24oKTtcbiAgcmV0dXJuIGJsb2Nrcztcbn1cblxuc2VsZi5kYWVtb25HZXRUeEhleGVzID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQsIHR4SGFzaGVzLCBwcnVuZSkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0VHhIZXhlcyh0eEhhc2hlcywgcHJ1bmUpO1xufVxuXG5zZWxmLmRhZW1vbkdldE1pbmVyVHhTdW0gPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCwgaGVpZ2h0LCBudW1CbG9ja3MpIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5nZXRNaW5lclR4U3VtKGhlaWdodCwgbnVtQmxvY2tzKSkudG9Kc29uKCk7XG59XG5cbnNlbGYuZGFlbW9uR2V0RmVlRXN0aW1hdGUgPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCwgZ3JhY2VCbG9ja3MpIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5nZXRGZWVFc3RpbWF0ZShncmFjZUJsb2NrcykpLnRvSnNvbigpO1xufVxuXG5zZWxmLmRhZW1vblN1Ym1pdFR4SGV4ID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQsIHR4SGV4LCBkb05vdFJlbGF5KSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uc3VibWl0VHhIZXgodHhIZXgsIGRvTm90UmVsYXkpKS50b0pzb24oKTtcbn1cblxuc2VsZi5kYWVtb25SZWxheVR4c0J5SGFzaCA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkLCB0eEhhc2hlcykge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0ucmVsYXlUeHNCeUhhc2godHhIYXNoZXMpO1xufVxuXG5zZWxmLmRhZW1vbkdldFR4UG9vbCA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkKSB7XG4gIGxldCB0eHMgPSBhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5nZXRUeFBvb2woKTtcbiAgbGV0IGJsb2NrID0gbmV3IE1vbmVyb0Jsb2NrKCkuc2V0VHhzKHR4cyk7XG4gIGZvciAobGV0IHR4IG9mIHR4cykgdHguc2V0QmxvY2soYmxvY2spXG4gIHJldHVybiBibG9jay50b0pzb24oKTtcbn1cblxuc2VsZi5kYWVtb25HZXRUeFBvb2xIYXNoZXMgPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0VHhQb29sSGFzaGVzKCk7XG59XG5cbi8vYXN5bmMgZ2V0VHhQb29sQmFja2xvZygpIHtcbi8vICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWRcIik7XG4vL31cblxuc2VsZi5kYWVtb25HZXRUeFBvb2xTdGF0cyA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkKSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0VHhQb29sU3RhdHMoKSkudG9Kc29uKCk7XG59XG5cbnNlbGYuZGFlbW9uRmx1c2hUeFBvb2wgPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCwgaGFzaGVzKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5mbHVzaFR4UG9vbChoYXNoZXMpO1xufVxuXG5zZWxmLmRhZW1vbkdldEtleUltYWdlU3BlbnRTdGF0dXNlcyA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkLCBrZXlJbWFnZXMpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLmdldEtleUltYWdlU3BlbnRTdGF0dXNlcyhrZXlJbWFnZXMpO1xufVxuXG4vL1xuLy9hc3luYyBnZXRPdXRwdXRzKG91dHB1dHMpIHtcbi8vICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWRcIik7XG4vL31cblxuc2VsZi5kYWVtb25HZXRPdXRwdXRIaXN0b2dyYW0gPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCwgYW1vdW50cywgbWluQ291bnQsIG1heENvdW50LCBpc1VubG9ja2VkLCByZWNlbnRDdXRvZmYpIHtcbiAgbGV0IGVudHJpZXNKc29uID0gW107XG4gIGZvciAobGV0IGVudHJ5IG9mIGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLmdldE91dHB1dEhpc3RvZ3JhbShhbW91bnRzLCBtaW5Db3VudCwgbWF4Q291bnQsIGlzVW5sb2NrZWQsIHJlY2VudEN1dG9mZikpIHtcbiAgICBlbnRyaWVzSnNvbi5wdXNoKGVudHJ5LnRvSnNvbigpKTtcbiAgfVxuICByZXR1cm4gZW50cmllc0pzb247XG59XG5cbi8vXG4vL2FzeW5jIGdldE91dHB1dERpc3RyaWJ1dGlvbihhbW91bnRzLCBjdW11bGF0aXZlLCBzdGFydEhlaWdodCwgZW5kSGVpZ2h0KSB7XG4vLyAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IGltcGxlbWVudGVkXCIpO1xuLy99XG5cbnNlbGYuZGFlbW9uR2V0SW5mbyA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkKSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0SW5mbygpKS50b0pzb24oKTtcbn1cblxuc2VsZi5kYWVtb25HZXRTeW5jSW5mbyA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkKSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0U3luY0luZm8oKSkudG9Kc29uKCk7XG59XG5cbnNlbGYuZGFlbW9uR2V0SGFyZEZvcmtJbmZvID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQpIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5nZXRIYXJkRm9ya0luZm8oKSkudG9Kc29uKCk7XG59XG5cbnNlbGYuZGFlbW9uR2V0QWx0Q2hhaW5zID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQpIHtcbiAgbGV0IGFsdENoYWluc0pzb24gPSBbXTtcbiAgZm9yIChsZXQgYWx0Q2hhaW4gb2YgYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uZ2V0QWx0Q2hhaW5zKCkpIGFsdENoYWluc0pzb24ucHVzaChhbHRDaGFpbi50b0pzb24oKSk7XG4gIHJldHVybiBhbHRDaGFpbnNKc29uO1xufVxuXG5zZWxmLmRhZW1vbkdldEFsdEJsb2NrSGFzaGVzID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLmdldEFsdEJsb2NrSGFzaGVzKCk7XG59XG5cbnNlbGYuZGFlbW9uR2V0RG93bmxvYWRMaW1pdCA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5nZXREb3dubG9hZExpbWl0KCk7XG59XG5cbnNlbGYuZGFlbW9uU2V0RG93bmxvYWRMaW1pdCA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkLCBsaW1pdCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uc2V0RG93bmxvYWRMaW1pdChsaW1pdCk7XG59XG5cbnNlbGYuZGFlbW9uUmVzZXREb3dubG9hZExpbWl0ID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLnJlc2V0RG93bmxvYWRMaW1pdCgpO1xufVxuXG5zZWxmLmRhZW1vbkdldFVwbG9hZExpbWl0ID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLmdldFVwbG9hZExpbWl0KCk7XG59XG5cbnNlbGYuZGFlbW9uU2V0VXBsb2FkTGltaXQgPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCwgbGltaXQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLnNldFVwbG9hZExpbWl0KGxpbWl0KTtcbn1cblxuc2VsZi5kYWVtb25SZXNldFVwbG9hZExpbWl0ID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLnJlc2V0VXBsb2FkTGltaXQoKTtcbn1cblxuc2VsZi5kYWVtb25HZXRQZWVycyA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkKSB7XG4gIGxldCBwZWVyc0pzb24gPSBbXTtcbiAgZm9yIChsZXQgcGVlciBvZiBhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5nZXRQZWVycygpKSBwZWVyc0pzb24ucHVzaChwZWVyLnRvSnNvbigpKTtcbiAgcmV0dXJuIHBlZXJzSnNvbjtcbn1cblxuc2VsZi5kYWVtb25HZXRLbm93blBlZXJzID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQpIHtcbiAgbGV0IHBlZXJzSnNvbiA9IFtdO1xuICBmb3IgKGxldCBwZWVyIG9mIGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLmdldEtub3duUGVlcnMoKSkgcGVlcnNKc29uLnB1c2gocGVlci50b0pzb24oKSk7XG4gIHJldHVybiBwZWVyc0pzb247XG59XG5cbnNlbGYuZGFlbW9uU2V0T3V0Z29pbmdQZWVyTGltaXQgPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCwgbGltaXQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLnNldE91dGdvaW5nUGVlckxpbWl0KGxpbWl0KTtcbn1cblxuc2VsZi5kYWVtb25TZXRJbmNvbWluZ1BlZXJMaW1pdCA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkLCBsaW1pdCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1tkYWVtb25JZF0uc2V0SW5jb21pbmdQZWVyTGltaXQobGltaXQpO1xufVxuXG5zZWxmLmRhZW1vbkdldFBlZXJCYW5zID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQpIHtcbiAgbGV0IGJhbnNKc29uID0gW107XG4gIGZvciAobGV0IGJhbiBvZiBhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5nZXRQZWVyQmFucygpKSBiYW5zSnNvbi5wdXNoKGJhbi50b0pzb24oKSk7XG4gIHJldHVybiBiYW5zSnNvbjtcbn1cblxuc2VsZi5kYWVtb25TZXRQZWVyQmFucyA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkLCBiYW5zSnNvbikge1xuICBsZXQgYmFucyA9IFtdO1xuICBmb3IgKGxldCBiYW5Kc29uIG9mIGJhbnNKc29uKSBiYW5zLnB1c2gobmV3IE1vbmVyb0JhbihiYW5Kc29uKSk7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5zZXRQZWVyQmFucyhiYW5zKTtcbn1cblxuc2VsZi5kYWVtb25TdGFydE1pbmluZyA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkLCBhZGRyZXNzLCBudW1UaHJlYWRzLCBpc0JhY2tncm91bmQsIGlnbm9yZUJhdHRlcnkpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLnN0YXJ0TWluaW5nKGFkZHJlc3MsIG51bVRocmVhZHMsIGlzQmFja2dyb3VuZCwgaWdub3JlQmF0dGVyeSk7XG59XG5cbnNlbGYuZGFlbW9uU3RvcE1pbmluZyA9IGFzeW5jIGZ1bmN0aW9uKGRhZW1vbklkKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5zdG9wTWluaW5nKCk7XG59XG5cbnNlbGYuZGFlbW9uR2V0TWluaW5nU3RhdHVzID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQpIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5nZXRNaW5pbmdTdGF0dXMoKSkudG9Kc29uKCk7XG59XG5cbnNlbGYuZGFlbW9uU3VibWl0QmxvY2tzID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQsIGJsb2NrQmxvYnMpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLnN1Ym1pdEJsb2NrcyhibG9ja0Jsb2JzKTtcbn1cblxuc2VsZi5kYWVtb25QcnVuZUJsb2NrY2hhaW4gPSBhc3luYyBmdW5jdGlvbihkYWVtb25JZCwgY2hlY2spIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS5wcnVuZUJsb2NrY2hhaW4oY2hlY2spKS50b0pzb24oKTtcbn1cblxuLy9hc3luYyBjaGVja0ZvclVwZGF0ZSgpIHtcbi8vICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWRcIik7XG4vL31cbi8vXG4vL2FzeW5jIGRvd25sb2FkVXBkYXRlKHBhdGgpIHtcbi8vICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWRcIik7XG4vL31cblxuc2VsZi5kYWVtb25TdG9wID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbZGFlbW9uSWRdLnN0b3AoKTtcbn1cblxuc2VsZi5kYWVtb25XYWl0Rm9yTmV4dEJsb2NrSGVhZGVyID0gYXN5bmMgZnVuY3Rpb24oZGFlbW9uSWQpIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW2RhZW1vbklkXS53YWl0Rm9yTmV4dEJsb2NrSGVhZGVyKCkpLnRvSnNvbigpO1xufVxuXG4vLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBXQUxMRVQgTUVUSE9EUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbnNlbGYub3BlbldhbGxldERhdGEgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgcGF0aCwgcGFzc3dvcmQsIG5ldHdvcmtUeXBlLCBrZXlzRGF0YSwgY2FjaGVEYXRhLCBkYWVtb25VcmlPckNvbmZpZykge1xuICBsZXQgZGFlbW9uQ29ubmVjdGlvbiA9IGRhZW1vblVyaU9yQ29uZmlnID8gbmV3IE1vbmVyb1JwY0Nvbm5lY3Rpb24oZGFlbW9uVXJpT3JDb25maWcpIDogdW5kZWZpbmVkO1xuICBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXSA9IGF3YWl0IE1vbmVyb1dhbGxldEZ1bGwub3BlbldhbGxldCh7cGF0aDogXCJcIiwgcGFzc3dvcmQ6IHBhc3N3b3JkLCBuZXR3b3JrVHlwZTogbmV0d29ya1R5cGUsIGtleXNEYXRhOiBrZXlzRGF0YSwgY2FjaGVEYXRhOiBjYWNoZURhdGEsIHNlcnZlcjogZGFlbW9uQ29ubmVjdGlvbiwgcHJveHlUb1dvcmtlcjogZmFsc2V9KTtcbiAgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uc2V0QnJvd3Nlck1haW5QYXRoKHBhdGgpO1xufVxuXG5zZWxmLmNyZWF0ZVdhbGxldEtleXMgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgY29uZmlnSnNvbikge1xuICBsZXQgY29uZmlnID0gbmV3IE1vbmVyb1dhbGxldENvbmZpZyhjb25maWdKc29uKTtcbiAgY29uZmlnLnNldFByb3h5VG9Xb3JrZXIoZmFsc2UpO1xuICBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXSA9IGF3YWl0IE1vbmVyb1dhbGxldEtleXMuY3JlYXRlV2FsbGV0KGNvbmZpZyk7XG59XG5cbnNlbGYuY3JlYXRlV2FsbGV0RnVsbCA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBjb25maWdKc29uKSB7XG4gIGxldCBjb25maWcgPSBuZXcgTW9uZXJvV2FsbGV0Q29uZmlnKGNvbmZpZ0pzb24pO1xuICBsZXQgcGF0aCA9IGNvbmZpZy5nZXRQYXRoKCk7XG4gIGNvbmZpZy5zZXRQYXRoKFwiXCIpO1xuICBjb25maWcuc2V0UHJveHlUb1dvcmtlcihmYWxzZSk7XG4gIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdID0gYXdhaXQgTW9uZXJvV2FsbGV0RnVsbC5jcmVhdGVXYWxsZXQoY29uZmlnKTtcbiAgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uc2V0QnJvd3Nlck1haW5QYXRoKHBhdGgpO1xufVxuXG5zZWxmLmlzVmlld09ubHkgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uaXNWaWV3T25seSgpO1xufVxuXG5zZWxmLmdldE5ldHdvcmtUeXBlID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldE5ldHdvcmtUeXBlKCk7XG59XG5cbi8vXG4vL2FzeW5jIGdldFZlcnNpb24oKSB7XG4vLyAgdGhyb3cgbmV3IEVycm9yKFwiTm90IGltcGxlbWVudGVkXCIpO1xuLy99XG5cbnNlbGYuZ2V0U2VlZCA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5nZXRTZWVkKCk7XG59XG5cbnNlbGYuZ2V0U2VlZExhbmd1YWdlID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldFNlZWRMYW5ndWFnZSgpO1xufVxuXG5zZWxmLmdldFNlZWRMYW5ndWFnZXMgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0U2VlZExhbmd1YWdlcygpO1xufVxuXG5zZWxmLmdldFByaXZhdGVTcGVuZEtleSA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5nZXRQcml2YXRlU3BlbmRLZXkoKTtcbn1cblxuc2VsZi5nZXRQcml2YXRlVmlld0tleSA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5nZXRQcml2YXRlVmlld0tleSgpO1xufVxuXG5zZWxmLmdldFB1YmxpY1ZpZXdLZXkgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0UHVibGljVmlld0tleSgpO1xufVxuXG5zZWxmLmdldFB1YmxpY1NwZW5kS2V5ID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldFB1YmxpY1NwZW5kS2V5KCk7XG59XG5cbnNlbGYuZ2V0QWRkcmVzcyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBhY2NvdW50SWR4LCBzdWJhZGRyZXNzSWR4KSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5nZXRBZGRyZXNzKGFjY291bnRJZHgsIHN1YmFkZHJlc3NJZHgpO1xufVxuXG5zZWxmLmdldEFkZHJlc3NJbmRleCA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBhZGRyZXNzKSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0QWRkcmVzc0luZGV4KGFkZHJlc3MpKS50b0pzb24oKTtcbn1cblxuc2VsZi5zZXRTdWJhZGRyZXNzTGFiZWwgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCwgbGFiZWwpIHtcbiAgYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uc2V0U3ViYWRkcmVzc0xhYmVsKGFjY291bnRJZHgsIHN1YmFkZHJlc3NJZHgsIGxhYmVsKTtcbn1cblxuc2VsZi5nZXRJbnRlZ3JhdGVkQWRkcmVzcyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBzdGFuZGFyZEFkZHJlc3MsIHBheW1lbnRJZCkge1xuICByZXR1cm4gKGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldEludGVncmF0ZWRBZGRyZXNzKHN0YW5kYXJkQWRkcmVzcywgcGF5bWVudElkKSkudG9Kc29uKCk7XG59XG5cbnNlbGYuZGVjb2RlSW50ZWdyYXRlZEFkZHJlc3MgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgaW50ZWdyYXRlZEFkZHJlc3MpIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5kZWNvZGVJbnRlZ3JhdGVkQWRkcmVzcyhpbnRlZ3JhdGVkQWRkcmVzcykpLnRvSnNvbigpO1xufVxuXG5zZWxmLnNldERhZW1vbkNvbm5lY3Rpb24gPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgY29uZmlnKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5zZXREYWVtb25Db25uZWN0aW9uKGNvbmZpZyA/IG5ldyBNb25lcm9ScGNDb25uZWN0aW9uKE9iamVjdC5hc3NpZ24oY29uZmlnLCB7cHJveHlUb1dvcmtlcjogZmFsc2V9KSkgOiB1bmRlZmluZWQpO1xufVxuXG5zZWxmLmdldERhZW1vbkNvbm5lY3Rpb24gPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICBsZXQgY29ubmVjdGlvbiA9IGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldERhZW1vbkNvbm5lY3Rpb24oKTtcbiAgcmV0dXJuIGNvbm5lY3Rpb24gPyBjb25uZWN0aW9uLmdldENvbmZpZygpIDogdW5kZWZpbmVkO1xufVxuXG5zZWxmLmlzQ29ubmVjdGVkVG9EYWVtb24gPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uaXNDb25uZWN0ZWRUb0RhZW1vbigpO1xufVxuXG5zZWxmLmdldFJlc3RvcmVIZWlnaHQgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0UmVzdG9yZUhlaWdodCgpO1xufVxuXG5zZWxmLnNldFJlc3RvcmVIZWlnaHQgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgcmVzdG9yZUhlaWdodCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uc2V0UmVzdG9yZUhlaWdodChyZXN0b3JlSGVpZ2h0KTtcbn1cblxuc2VsZi5nZXREYWVtb25IZWlnaHQgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0RGFlbW9uSGVpZ2h0KCk7XG59XG5cbnNlbGYuZ2V0RGFlbW9uTWF4UGVlckhlaWdodCA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5nZXREYWVtb25NYXhQZWVySGVpZ2h0KClcbn1cblxuc2VsZi5nZXRIZWlnaHRCeURhdGUgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgeWVhciwgbW9udGgsIGRheSkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0SGVpZ2h0QnlEYXRlKHllYXIsIG1vbnRoLCBkYXkpO1xufVxuXG5zZWxmLmlzRGFlbW9uU3luY2VkID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmlzRGFlbW9uU3luY2VkKCk7XG59XG5cbnNlbGYuZ2V0SGVpZ2h0ID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldEhlaWdodCgpO1xufVxuXG5zZWxmLmFkZExpc3RlbmVyID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIGxpc3RlbmVySWQpIHtcbiAgXG4gIC8qKlxuICAgKiBJbnRlcm5hbCBsaXN0ZW5lciB0byBicmlkZ2Ugbm90aWZpY2F0aW9ucyB0byBleHRlcm5hbCBsaXN0ZW5lcnMuXG4gICAqIFxuICAgKiBUT0RPOiBNb25lcm9XYWxsZXRMaXN0ZW5lciBpcyBub3QgZGVmaW5lZCB1bnRpbCBzY3JpcHRzIGltcG9ydGVkXG4gICAqIFxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgY2xhc3MgV2FsbGV0V29ya2VySGVscGVyTGlzdGVuZXIgZXh0ZW5kcyBNb25lcm9XYWxsZXRMaXN0ZW5lciB7XG5cbiAgICBwcm90ZWN0ZWQgd2FsbGV0SWQ6IHN0cmluZztcbiAgICBwcm90ZWN0ZWQgaWQ6IHN0cmluZztcbiAgICBwcm90ZWN0ZWQgd29ya2VyOiBXb3JrZXI7XG4gICAgXG4gICAgY29uc3RydWN0b3Iod2FsbGV0SWQsIGlkLCB3b3JrZXIpIHtcbiAgICAgIHN1cGVyKCk7XG4gICAgICB0aGlzLndhbGxldElkID0gd2FsbGV0SWQ7XG4gICAgICB0aGlzLmlkID0gaWQ7XG4gICAgICB0aGlzLndvcmtlciA9IHdvcmtlcjtcbiAgICB9XG4gICAgXG4gICAgZ2V0SWQoKSB7XG4gICAgICByZXR1cm4gdGhpcy5pZDtcbiAgICB9XG4gICAgXG4gICAgYXN5bmMgb25TeW5jUHJvZ3Jlc3MoaGVpZ2h0LCBzdGFydEhlaWdodCwgZW5kSGVpZ2h0LCBwZXJjZW50RG9uZSwgbWVzc2FnZSkge1xuICAgICAgdGhpcy53b3JrZXIucG9zdE1lc3NhZ2UoW3RoaXMud2FsbGV0SWQsIFwib25TeW5jUHJvZ3Jlc3NfXCIgKyB0aGlzLmdldElkKCksIGhlaWdodCwgc3RhcnRIZWlnaHQsIGVuZEhlaWdodCwgcGVyY2VudERvbmUsIG1lc3NhZ2VdKTtcbiAgICB9XG5cbiAgICBhc3luYyBvbk5ld0Jsb2NrKGhlaWdodCkgeyBcbiAgICAgIHRoaXMud29ya2VyLnBvc3RNZXNzYWdlKFt0aGlzLndhbGxldElkLCBcIm9uTmV3QmxvY2tfXCIgKyB0aGlzLmdldElkKCksIGhlaWdodF0pO1xuICAgIH1cbiAgICBcbiAgICBhc3luYyBvbkJhbGFuY2VzQ2hhbmdlZChuZXdCYWxhbmNlLCBuZXdVbmxvY2tlZEJhbGFuY2UpIHtcbiAgICAgIHRoaXMud29ya2VyLnBvc3RNZXNzYWdlKFt0aGlzLndhbGxldElkLCBcIm9uQmFsYW5jZXNDaGFuZ2VkX1wiICsgdGhpcy5nZXRJZCgpLCBuZXdCYWxhbmNlLnRvU3RyaW5nKCksIG5ld1VubG9ja2VkQmFsYW5jZS50b1N0cmluZygpXSk7XG4gICAgfVxuXG4gICBhc3luYyBvbk91dHB1dFJlY2VpdmVkKG91dHB1dCkge1xuICAgICAgbGV0IGJsb2NrID0gb3V0cHV0LmdldFR4KCkuZ2V0QmxvY2soKTtcbiAgICAgIGlmIChibG9jayA9PT0gdW5kZWZpbmVkKSBibG9jayA9IG5ldyBNb25lcm9CbG9jaygpLnNldFR4cyhbb3V0cHV0LmdldFR4KCldKTtcbiAgICAgIHRoaXMud29ya2VyLnBvc3RNZXNzYWdlKFt0aGlzLndhbGxldElkLCBcIm9uT3V0cHV0UmVjZWl2ZWRfXCIgKyB0aGlzLmdldElkKCksIGJsb2NrLnRvSnNvbigpXSk7ICAvLyBzZXJpYWxpemUgZnJvbSByb290IGJsb2NrXG4gICAgfVxuICAgIFxuICAgIGFzeW5jIG9uT3V0cHV0U3BlbnQob3V0cHV0KSB7XG4gICAgICBsZXQgYmxvY2sgPSBvdXRwdXQuZ2V0VHgoKS5nZXRCbG9jaygpO1xuICAgICAgaWYgKGJsb2NrID09PSB1bmRlZmluZWQpIGJsb2NrID0gbmV3IE1vbmVyb0Jsb2NrKCkuc2V0VHhzKFtvdXRwdXQuZ2V0VHgoKV0pO1xuICAgICAgdGhpcy53b3JrZXIucG9zdE1lc3NhZ2UoW3RoaXMud2FsbGV0SWQsIFwib25PdXRwdXRTcGVudF9cIiArIHRoaXMuZ2V0SWQoKSwgYmxvY2sudG9Kc29uKCldKTsgICAgIC8vIHNlcmlhbGl6ZSBmcm9tIHJvb3QgYmxvY2tcbiAgICB9XG4gIH1cbiAgXG4gIGxldCBsaXN0ZW5lciA9IG5ldyBXYWxsZXRXb3JrZXJIZWxwZXJMaXN0ZW5lcih3YWxsZXRJZCwgbGlzdGVuZXJJZCwgc2VsZik7XG4gIGlmICghc2VsZi5saXN0ZW5lcnMpIHNlbGYubGlzdGVuZXJzID0gW107XG4gIHNlbGYubGlzdGVuZXJzLnB1c2gobGlzdGVuZXIpO1xuICBhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5hZGRMaXN0ZW5lcihsaXN0ZW5lcik7XG59XG5cbnNlbGYucmVtb3ZlTGlzdGVuZXIgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgbGlzdGVuZXJJZCkge1xuICBmb3IgKGxldCBpID0gMDsgaSA8IHNlbGYubGlzdGVuZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKHNlbGYubGlzdGVuZXJzW2ldLmdldElkKCkgIT09IGxpc3RlbmVySWQpIGNvbnRpbnVlO1xuICAgIGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLnJlbW92ZUxpc3RlbmVyKHNlbGYubGlzdGVuZXJzW2ldKTtcbiAgICBzZWxmLmxpc3RlbmVycy5zcGxpY2UoaSwgMSk7XG4gICAgcmV0dXJuO1xuICB9XG4gIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkxpc3RlbmVyIGlzIG5vdCByZWdpc3RlcmVkIHdpdGggd2FsbGV0XCIpO1xufVxuXG5zZWxmLmlzU3luY2VkID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmlzU3luY2VkKCk7XG59XG5cbnNlbGYuc3luYyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBzdGFydEhlaWdodCwgYWxsb3dDb25jdXJyZW50Q2FsbHMpIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5zeW5jKHVuZGVmaW5lZCwgc3RhcnRIZWlnaHQsIGFsbG93Q29uY3VycmVudENhbGxzKSk7XG59XG5cbnNlbGYuc3RhcnRTeW5jaW5nID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIHN5bmNQZXJpb2RJbk1zKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5zdGFydFN5bmNpbmcoc3luY1BlcmlvZEluTXMpO1xufVxuXG5zZWxmLnN0b3BTeW5jaW5nID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLnN0b3BTeW5jaW5nKCk7XG59XG5cbnNlbGYuc2NhblR4cyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCB0eEhhc2hlcykge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uc2NhblR4cyh0eEhhc2hlcyk7XG59XG5cbnNlbGYucmVzY2FuU3BlbnQgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0ucmVzY2FuU3BlbnQoKTtcbn1cblxuc2VsZi5yZXNjYW5CbG9ja2NoYWluID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLnJlc2NhbkJsb2NrY2hhaW4oKTtcbn1cblxuc2VsZi5nZXRCYWxhbmNlID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIGFjY291bnRJZHgsIHN1YmFkZHJlc3NJZHgpIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5nZXRCYWxhbmNlKGFjY291bnRJZHgsIHN1YmFkZHJlc3NJZHgpKS50b1N0cmluZygpO1xufVxuXG5zZWxmLmdldFVubG9ja2VkQmFsYW5jZSA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBhY2NvdW50SWR4LCBzdWJhZGRyZXNzSWR4KSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0VW5sb2NrZWRCYWxhbmNlKGFjY291bnRJZHgsIHN1YmFkZHJlc3NJZHgpKS50b1N0cmluZygpO1xufVxuXG5zZWxmLmdldEFjY291bnRzID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIGluY2x1ZGVTdWJhZGRyZXNzZXMsIHRhZykge1xuICBsZXQgYWNjb3VudEpzb25zID0gW107XG4gIGZvciAobGV0IGFjY291bnQgb2YgYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0QWNjb3VudHMoaW5jbHVkZVN1YmFkZHJlc3NlcywgdGFnKSkgYWNjb3VudEpzb25zLnB1c2goYWNjb3VudC50b0pzb24oKSk7XG4gIHJldHVybiBhY2NvdW50SnNvbnM7XG59XG5cbnNlbGYuZ2V0QWNjb3VudCA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBhY2NvdW50SWR4LCBpbmNsdWRlU3ViYWRkcmVzc2VzKSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0QWNjb3VudChhY2NvdW50SWR4LCBpbmNsdWRlU3ViYWRkcmVzc2VzKSkudG9Kc29uKCk7XG59XG5cbnNlbGYuY3JlYXRlQWNjb3VudCA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBsYWJlbCkge1xuICByZXR1cm4gKGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmNyZWF0ZUFjY291bnQobGFiZWwpKS50b0pzb24oKTtcbn1cblxuc2VsZi5nZXRTdWJhZGRyZXNzZXMgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgYWNjb3VudElkeCwgc3ViYWRkcmVzc0luZGljZXMpIHtcbiAgbGV0IHN1YmFkZHJlc3NKc29ucyA9IFtdO1xuICBmb3IgKGxldCBzdWJhZGRyZXNzIG9mIGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldFN1YmFkZHJlc3NlcyhhY2NvdW50SWR4LCBzdWJhZGRyZXNzSW5kaWNlcykpIHN1YmFkZHJlc3NKc29ucy5wdXNoKHN1YmFkZHJlc3MudG9Kc29uKCkpO1xuICByZXR1cm4gc3ViYWRkcmVzc0pzb25zO1xufVxuXG5zZWxmLmNyZWF0ZVN1YmFkZHJlc3MgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgYWNjb3VudElkeCwgbGFiZWwpIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5jcmVhdGVTdWJhZGRyZXNzKGFjY291bnRJZHgsIGxhYmVsKSkudG9Kc29uKCk7XG59XG5cbi8vIFRPRE86IGVhc2llciBvciBtb3JlIGVmZmljaWVudCB3YXkgdGhhbiBzZXJpYWxpemluZyBmcm9tIHJvb3QgYmxvY2tzP1xuc2VsZi5nZXRUeHMgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgYmxvY2tKc29uUXVlcnkpIHtcbiAgXG4gIC8vIGRlc2VyaWFsaXplIHF1ZXJ5IHdoaWNoIGlzIGpzb24gc3RyaW5nIHJvb3RlZCBhdCBibG9ja1xuICBsZXQgcXVlcnkgPSBuZXcgTW9uZXJvQmxvY2soYmxvY2tKc29uUXVlcnksIE1vbmVyb0Jsb2NrLkRlc2VyaWFsaXphdGlvblR5cGUuVFhfUVVFUlkpLmdldFR4cygpWzBdO1xuICBcbiAgLy8gZ2V0IHR4c1xuICBsZXQgdHhzID0gYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0VHhzKHF1ZXJ5KTtcbiAgXG4gIC8vIGNvbGxlY3QgdW5pcXVlIGJsb2NrcyB0byBwcmVzZXJ2ZSBtb2RlbCByZWxhdGlvbnNoaXBzIGFzIHRyZWVzIChiYXNlZCBvbiBtb25lcm9fd2FzbV9icmlkZ2UuY3BwOjpnZXRfdHhzKVxuICBsZXQgc2VlbkJsb2NrcyA9IG5ldyBTZXQoKTtcbiAgbGV0IHVuY29uZmlybWVkQmxvY2sgPSB1bmRlZmluZWQ7XG4gIGxldCBibG9ja3MgPSBbXTtcbiAgZm9yIChsZXQgdHggb2YgdHhzKSB7XG4gICAgaWYgKCF0eC5nZXRCbG9jaygpKSB7XG4gICAgICBpZiAoIXVuY29uZmlybWVkQmxvY2spIHVuY29uZmlybWVkQmxvY2sgPSBuZXcgTW9uZXJvQmxvY2soKS5zZXRUeHMoW10pO1xuICAgICAgdHguc2V0QmxvY2sodW5jb25maXJtZWRCbG9jayk7XG4gICAgICB1bmNvbmZpcm1lZEJsb2NrLmdldFR4cygpLnB1c2godHgpO1xuICAgIH1cbiAgICBpZiAoIXNlZW5CbG9ja3MuaGFzKHR4LmdldEJsb2NrKCkpKSB7XG4gICAgICBzZWVuQmxvY2tzLmFkZCh0eC5nZXRCbG9jaygpKTtcbiAgICAgIGJsb2Nrcy5wdXNoKHR4LmdldEJsb2NrKCkpO1xuICAgIH1cbiAgfVxuICBcbiAgLy8gc2VyaWFsaXplIGJsb2NrcyB0byBqc29uXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYmxvY2tzLmxlbmd0aDsgaSsrKSBibG9ja3NbaV0gPSBibG9ja3NbaV0udG9Kc29uKCk7XG4gIHJldHVybiB7YmxvY2tzOiBibG9ja3N9O1xufVxuXG5zZWxmLmdldFRyYW5zZmVycyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBibG9ja0pzb25RdWVyeSkge1xuICBcbiAgLy8gZGVzZXJpYWxpemUgcXVlcnkgd2hpY2ggaXMganNvbiBzdHJpbmcgcm9vdGVkIGF0IGJsb2NrXG4gIGxldCBxdWVyeSA9IChuZXcgTW9uZXJvQmxvY2soYmxvY2tKc29uUXVlcnksIE1vbmVyb0Jsb2NrLkRlc2VyaWFsaXphdGlvblR5cGUuVFhfUVVFUlkpLmdldFR4cygpWzBdIGFzIE1vbmVyb1R4UXVlcnkpLmdldFRyYW5zZmVyUXVlcnkoKTtcbiAgXG4gIC8vIGdldCB0cmFuc2ZlcnNcbiAgbGV0IHRyYW5zZmVycyA9IGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldFRyYW5zZmVycyhxdWVyeSk7XG4gIFxuICAvLyBjb2xsZWN0IHVuaXF1ZSBibG9ja3MgdG8gcHJlc2VydmUgbW9kZWwgcmVsYXRpb25zaGlwcyBhcyB0cmVlXG4gIGxldCB1bmNvbmZpcm1lZEJsb2NrID0gdW5kZWZpbmVkO1xuICBsZXQgYmxvY2tzID0gW107XG4gIGxldCBzZWVuQmxvY2tzID0gbmV3IFNldCgpO1xuICBmb3IgKGxldCB0cmFuc2ZlciBvZiB0cmFuc2ZlcnMpIHtcbiAgICBsZXQgdHggPSB0cmFuc2Zlci5nZXRUeCgpO1xuICAgIGlmICghdHguZ2V0QmxvY2soKSkge1xuICAgICAgaWYgKCF1bmNvbmZpcm1lZEJsb2NrKSB1bmNvbmZpcm1lZEJsb2NrID0gbmV3IE1vbmVyb0Jsb2NrKCkuc2V0VHhzKFtdKTtcbiAgICAgIHR4LnNldEJsb2NrKHVuY29uZmlybWVkQmxvY2spO1xuICAgICAgdW5jb25maXJtZWRCbG9jay5nZXRUeHMoKS5wdXNoKHR4KTtcbiAgICB9XG4gICAgaWYgKCFzZWVuQmxvY2tzLmhhcyh0eC5nZXRCbG9jaygpKSkge1xuICAgICAgc2VlbkJsb2Nrcy5hZGQodHguZ2V0QmxvY2soKSk7XG4gICAgICBibG9ja3MucHVzaCh0eC5nZXRCbG9jaygpKTtcbiAgICB9XG4gIH1cbiAgXG4gIC8vIHNlcmlhbGl6ZSBibG9ja3MgdG8ganNvblxuICBmb3IgKGxldCBpID0gMDsgaSA8IGJsb2Nrcy5sZW5ndGg7IGkrKykgYmxvY2tzW2ldID0gYmxvY2tzW2ldLnRvSnNvbigpO1xuICByZXR1cm4gYmxvY2tzO1xufVxuXG5zZWxmLmdldE91dHB1dHMgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgYmxvY2tKc29uUXVlcnkpIHtcblxuICAvLyBkZXNlcmlhbGl6ZSBxdWVyeSB3aGljaCBpcyBqc29uIHN0cmluZyByb290ZWQgYXQgYmxvY2tcbiAgbGV0IHF1ZXJ5ID0gKG5ldyBNb25lcm9CbG9jayhibG9ja0pzb25RdWVyeSwgTW9uZXJvQmxvY2suRGVzZXJpYWxpemF0aW9uVHlwZS5UWF9RVUVSWSkuZ2V0VHhzKClbMF0gYXMgTW9uZXJvVHhRdWVyeSkuZ2V0T3V0cHV0UXVlcnkoKTtcbiAgXG4gIC8vIGdldCBvdXRwdXRzXG4gIGxldCBvdXRwdXRzID0gYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0T3V0cHV0cyhxdWVyeSk7XG4gIFxuICAvLyBjb2xsZWN0IHVuaXF1ZSBibG9ja3MgdG8gcHJlc2VydmUgbW9kZWwgcmVsYXRpb25zaGlwcyBhcyB0cmVlXG4gIGxldCB1bmNvbmZpcm1lZEJsb2NrID0gdW5kZWZpbmVkO1xuICBsZXQgYmxvY2tzID0gW107XG4gIGxldCBzZWVuQmxvY2tzID0gbmV3IFNldCgpO1xuICBmb3IgKGxldCBvdXRwdXQgb2Ygb3V0cHV0cykge1xuICAgIGxldCB0eCA9IG91dHB1dC5nZXRUeCgpO1xuICAgIGlmICghdHguZ2V0QmxvY2soKSkge1xuICAgICAgaWYgKCF1bmNvbmZpcm1lZEJsb2NrKSB1bmNvbmZpcm1lZEJsb2NrID0gbmV3IE1vbmVyb0Jsb2NrKCkuc2V0VHhzKFtdKTtcbiAgICAgIHR4LnNldEJsb2NrKHVuY29uZmlybWVkQmxvY2spO1xuICAgICAgdW5jb25maXJtZWRCbG9jay5nZXRUeHMoKS5wdXNoKHR4KTtcbiAgICB9XG4gICAgaWYgKCFzZWVuQmxvY2tzLmhhcyh0eC5nZXRCbG9jaygpKSkge1xuICAgICAgc2VlbkJsb2Nrcy5hZGQodHguZ2V0QmxvY2soKSk7XG4gICAgICBibG9ja3MucHVzaCh0eC5nZXRCbG9jaygpKTtcbiAgICB9XG4gIH1cbiAgXG4gIC8vIHNlcmlhbGl6ZSBibG9ja3MgdG8ganNvblxuICBmb3IgKGxldCBpID0gMDsgaSA8IGJsb2Nrcy5sZW5ndGg7IGkrKykgYmxvY2tzW2ldID0gYmxvY2tzW2ldLnRvSnNvbigpO1xuICByZXR1cm4gYmxvY2tzO1xufVxuXG5zZWxmLmV4cG9ydE91dHB1dHMgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgYWxsKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5leHBvcnRPdXRwdXRzKGFsbCk7XG59XG5cbnNlbGYuaW1wb3J0T3V0cHV0cyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBvdXRwdXRzSGV4KSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5pbXBvcnRPdXRwdXRzKG91dHB1dHNIZXgpO1xufVxuXG5zZWxmLmdldEtleUltYWdlcyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBhbGwpIHtcbiAgbGV0IGtleUltYWdlc0pzb24gPSBbXTtcbiAgZm9yIChsZXQga2V5SW1hZ2Ugb2YgYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZXhwb3J0S2V5SW1hZ2VzKGFsbCkpIGtleUltYWdlc0pzb24ucHVzaChrZXlJbWFnZS50b0pzb24oKSk7XG4gIHJldHVybiBrZXlJbWFnZXNKc29uO1xufVxuXG5zZWxmLmltcG9ydEtleUltYWdlcyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBrZXlJbWFnZXNKc29uKSB7XG4gIGxldCBrZXlJbWFnZXMgPSBbXTtcbiAgZm9yIChsZXQga2V5SW1hZ2VKc29uIG9mIGtleUltYWdlc0pzb24pIGtleUltYWdlcy5wdXNoKG5ldyBNb25lcm9LZXlJbWFnZShrZXlJbWFnZUpzb24pKTtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5pbXBvcnRLZXlJbWFnZXMoa2V5SW1hZ2VzKSkudG9Kc29uKCk7XG59XG5cbi8vYXN5bmMgZ2V0TmV3S2V5SW1hZ2VzRnJvbUxhc3RJbXBvcnQoKSB7XG4vLyAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IGltcGxlbWVudGVkXCIpO1xuLy99XG5cbnNlbGYuZnJlZXplT3V0cHV0ID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIGtleUltYWdlKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5mcmVlemVPdXRwdXQoa2V5SW1hZ2UpO1xufVxuXG5zZWxmLnRoYXdPdXRwdXQgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwga2V5SW1hZ2UpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLnRoYXdPdXRwdXQoa2V5SW1hZ2UpO1xufVxuXG5zZWxmLmlzT3V0cHV0RnJvemVuID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIGtleUltYWdlKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5pc091dHB1dEZyb3plbihrZXlJbWFnZSk7XG59XG5cbnNlbGYuZ2V0RGVmYXVsdEZlZVByaW9yaXR5ID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldERlZmF1bHRGZWVQcmlvcml0eSgpO1xufVxuXG5zZWxmLmNyZWF0ZVR4cyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBjb25maWcpIHtcbiAgaWYgKHR5cGVvZiBjb25maWcgPT09IFwib2JqZWN0XCIpIGNvbmZpZyA9IG5ldyBNb25lcm9UeENvbmZpZyhjb25maWcpO1xuICBsZXQgdHhzID0gYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uY3JlYXRlVHhzKGNvbmZpZyk7XG4gIHJldHVybiB0eHNbMF0uZ2V0VHhTZXQoKS50b0pzb24oKTtcbn1cblxuc2VsZi5zd2VlcE91dHB1dCA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBjb25maWcpIHtcbiAgaWYgKHR5cGVvZiBjb25maWcgPT09IFwib2JqZWN0XCIpIGNvbmZpZyA9IG5ldyBNb25lcm9UeENvbmZpZyhjb25maWcpO1xuICBsZXQgdHggPSBhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5zd2VlcE91dHB1dChjb25maWcpO1xuICByZXR1cm4gdHguZ2V0VHhTZXQoKS50b0pzb24oKTtcbn1cblxuc2VsZi5zd2VlcFVubG9ja2VkID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIGNvbmZpZykge1xuICBpZiAodHlwZW9mIGNvbmZpZyA9PT0gXCJvYmplY3RcIikgY29uZmlnID0gbmV3IE1vbmVyb1R4Q29uZmlnKGNvbmZpZyk7XG4gIGxldCB0eHMgPSBhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5zd2VlcFVubG9ja2VkKGNvbmZpZyk7XG4gIGxldCB0eFNldHMgPSBbXTtcbiAgZm9yIChsZXQgdHggb2YgdHhzKSBpZiAoIUdlblV0aWxzLmFycmF5Q29udGFpbnModHhTZXRzLCB0eC5nZXRUeFNldCgpKSkgdHhTZXRzLnB1c2godHguZ2V0VHhTZXQoKSk7XG4gIGxldCB0eFNldHNKc29uID0gW107XG4gIGZvciAobGV0IHR4U2V0IG9mIHR4U2V0cykgdHhTZXRzSnNvbi5wdXNoKHR4U2V0LnRvSnNvbigpKTtcbiAgcmV0dXJuIHR4U2V0c0pzb247XG59XG5cbnNlbGYuc3dlZXBEdXN0ID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIHJlbGF5KSB7XG4gIGxldCB0eHMgPSBhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5zd2VlcER1c3QocmVsYXkpO1xuICByZXR1cm4gdHhzLmxlbmd0aCA9PT0gMCA/IHt9IDogdHhzWzBdLmdldFR4U2V0KCkudG9Kc29uKCk7XG59XG5cbnNlbGYucmVsYXlUeHMgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgdHhNZXRhZGF0YXMpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLnJlbGF5VHhzKHR4TWV0YWRhdGFzKTtcbn1cblxuc2VsZi5kZXNjcmliZVR4U2V0ID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIHR4U2V0SnNvbikge1xuICByZXR1cm4gKGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmRlc2NyaWJlVHhTZXQobmV3IE1vbmVyb1R4U2V0KHR4U2V0SnNvbikpKS50b0pzb24oKTtcbn1cblxuc2VsZi5zaWduVHhzID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIHVuc2lnbmVkVHhIZXgpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLnNpZ25UeHModW5zaWduZWRUeEhleCk7XG59XG5cbnNlbGYuc3VibWl0VHhzID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIHNpZ25lZFR4SGV4KSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5zdWJtaXRUeHMoc2lnbmVkVHhIZXgpO1xufVxuXG5zZWxmLnNpZ25NZXNzYWdlID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIG1lc3NhZ2UsIHNpZ25hdHVyZVR5cGUsIGFjY291bnRJZHgsIHN1YmFkZHJlc3NJZHgpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLnNpZ25NZXNzYWdlKG1lc3NhZ2UsIHNpZ25hdHVyZVR5cGUsIGFjY291bnRJZHgsIHN1YmFkZHJlc3NJZHgpO1xufVxuXG5zZWxmLnZlcmlmeU1lc3NhZ2UgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgbWVzc2FnZSwgYWRkcmVzcywgc2lnbmF0dXJlKSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0udmVyaWZ5TWVzc2FnZShtZXNzYWdlLCBhZGRyZXNzLCBzaWduYXR1cmUpKS50b0pzb24oKTtcbn1cblxuc2VsZi5nZXRUeEtleSA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCB0eEhhc2gpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldFR4S2V5KHR4SGFzaCk7XG59XG5cbnNlbGYuY2hlY2tUeEtleSA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCB0eEhhc2gsIHR4S2V5LCBhZGRyZXNzKSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uY2hlY2tUeEtleSh0eEhhc2gsIHR4S2V5LCBhZGRyZXNzKSkudG9Kc29uKCk7XG59XG5cbnNlbGYuZ2V0VHhQcm9vZiA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCB0eEhhc2gsIGFkZHJlc3MsIG1lc3NhZ2UpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldFR4UHJvb2YodHhIYXNoLCBhZGRyZXNzLCBtZXNzYWdlKTtcbn1cblxuc2VsZi5jaGVja1R4UHJvb2YgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgdHhIYXNoLCBhZGRyZXNzLCBtZXNzYWdlLCBzaWduYXR1cmUpIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5jaGVja1R4UHJvb2YodHhIYXNoLCBhZGRyZXNzLCBtZXNzYWdlLCBzaWduYXR1cmUpKS50b0pzb24oKTtcbn1cblxuc2VsZi5nZXRTcGVuZFByb29mID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIHR4SGFzaCwgbWVzc2FnZSkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0U3BlbmRQcm9vZih0eEhhc2gsIG1lc3NhZ2UpO1xufVxuXG5zZWxmLmNoZWNrU3BlbmRQcm9vZiA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCB0eEhhc2gsIG1lc3NhZ2UsIHNpZ25hdHVyZSkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uY2hlY2tTcGVuZFByb29mKHR4SGFzaCwgbWVzc2FnZSwgc2lnbmF0dXJlKTtcbn1cblxuc2VsZi5nZXRSZXNlcnZlUHJvb2ZXYWxsZXQgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgbWVzc2FnZSkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0UmVzZXJ2ZVByb29mV2FsbGV0KG1lc3NhZ2UpO1xufVxuXG5zZWxmLmdldFJlc2VydmVQcm9vZkFjY291bnQgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgYWNjb3VudElkeCwgYW1vdW50U3RyLCBtZXNzYWdlKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5nZXRSZXNlcnZlUHJvb2ZBY2NvdW50KGFjY291bnRJZHgsIGFtb3VudFN0ciwgbWVzc2FnZSk7XG59XG5cbnNlbGYuY2hlY2tSZXNlcnZlUHJvb2YgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgYWRkcmVzcywgbWVzc2FnZSwgc2lnbmF0dXJlKSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uY2hlY2tSZXNlcnZlUHJvb2YoYWRkcmVzcywgbWVzc2FnZSwgc2lnbmF0dXJlKSkudG9Kc29uKCk7XG59XG5cbnNlbGYuZ2V0VHhOb3RlcyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCB0eEhhc2hlcykge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0VHhOb3Rlcyh0eEhhc2hlcyk7XG59XG5cbnNlbGYuc2V0VHhOb3RlcyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCB0eEhhc2hlcywgdHhOb3Rlcykge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uc2V0VHhOb3Rlcyh0eEhhc2hlcywgdHhOb3Rlcyk7XG59XG5cbnNlbGYuZ2V0QWRkcmVzc0Jvb2tFbnRyaWVzID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIGVudHJ5SW5kaWNlcykge1xuICBsZXQgZW50cmllc0pzb24gPSBbXTtcbiAgZm9yIChsZXQgZW50cnkgb2YgYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0QWRkcmVzc0Jvb2tFbnRyaWVzKGVudHJ5SW5kaWNlcykpIGVudHJpZXNKc29uLnB1c2goZW50cnkudG9Kc29uKCkpO1xuICByZXR1cm4gZW50cmllc0pzb247XG59XG5cbnNlbGYuYWRkQWRkcmVzc0Jvb2tFbnRyeSA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBhZGRyZXNzLCBkZXNjcmlwdGlvbikge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uYWRkQWRkcmVzc0Jvb2tFbnRyeShhZGRyZXNzLCBkZXNjcmlwdGlvbik7XG59XG5cbnNlbGYuZWRpdEFkZHJlc3NCb29rRW50cnkgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgaW5kZXgsIHNldEFkZHJlc3MsIGFkZHJlc3MsIHNldERlc2NyaXB0aW9uLCBkZXNjcmlwdGlvbikge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZWRpdEFkZHJlc3NCb29rRW50cnkoaW5kZXgsIHNldEFkZHJlc3MsIGFkZHJlc3MsIHNldERlc2NyaXB0aW9uLCBkZXNjcmlwdGlvbik7XG59XG5cbnNlbGYuZGVsZXRlQWRkcmVzc0Jvb2tFbnRyeSA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBpbmRleCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZGVsZXRlQWRkcmVzc0Jvb2tFbnRyeShpbmRleCk7XG59XG5cbnNlbGYudGFnQWNjb3VudHMgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgdGFnLCBhY2NvdW50SW5kaWNlcykge1xuICB0aHJvdyBuZXcgRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWRcIik7XG59XG5cbnNlbGYudW50YWdBY2NvdW50cyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBhY2NvdW50SW5kaWNlcykge1xuICB0aHJvdyBuZXcgRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWRcIik7XG59XG5cbnNlbGYuZ2V0QWNjb3VudFRhZ3MgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICB0aHJvdyBuZXcgRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWRcIik7XG59XG5cbnNlbGYuc2V0QWNjb3VudFRhZ0xhYmVsID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIHRhZywgbGFiZWwpIHtcbiAgdGhyb3cgbmV3IEVycm9yKFwiTm90IGltcGxlbWVudGVkXCIpO1xufVxuXG5zZWxmLmdldFBheW1lbnRVcmkgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgY29uZmlnSnNvbikge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0UGF5bWVudFVyaShuZXcgTW9uZXJvVHhDb25maWcoY29uZmlnSnNvbikpO1xufVxuXG5zZWxmLnBhcnNlUGF5bWVudFVyaSA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCB1cmkpIHtcbiAgcmV0dXJuIChhd2FpdCBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5wYXJzZVBheW1lbnRVcmkodXJpKSkudG9Kc29uKCk7XG59XG5cbnNlbGYuZ2V0QXR0cmlidXRlID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIGtleSkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZ2V0QXR0cmlidXRlKGtleSk7XG59XG5cbnNlbGYuc2V0QXR0cmlidXRlID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIGtleSwgdmFsdWUpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLnNldEF0dHJpYnV0ZShrZXksIHZhbHVlKTtcbn1cblxuc2VsZi5zdGFydE1pbmluZyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBudW1UaHJlYWRzLCBiYWNrZ3JvdW5kTWluaW5nLCBpZ25vcmVCYXR0ZXJ5KSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5zdGFydE1pbmluZyhudW1UaHJlYWRzLCBiYWNrZ3JvdW5kTWluaW5nLCBpZ25vcmVCYXR0ZXJ5KTtcbn1cblxuc2VsZi5zdG9wTWluaW5nID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLnN0b3BNaW5pbmcoKTtcbn1cblxuc2VsZi5pc011bHRpc2lnSW1wb3J0TmVlZGVkID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmlzTXVsdGlzaWdJbXBvcnROZWVkZWQoKTtcbn1cblxuc2VsZi5pc011bHRpc2lnID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmlzTXVsdGlzaWcoKTtcbn1cblxuc2VsZi5nZXRNdWx0aXNpZ0luZm8gPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICByZXR1cm4gKGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldE11bHRpc2lnSW5mbygpKS50b0pzb24oKTtcbn1cblxuc2VsZi5wcmVwYXJlTXVsdGlzaWcgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0ucHJlcGFyZU11bHRpc2lnKCk7XG59XG5cbnNlbGYubWFrZU11bHRpc2lnID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQsIG11bHRpc2lnSGV4ZXMsIHRocmVzaG9sZCwgcGFzc3dvcmQpIHtcbiAgcmV0dXJuIGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLm1ha2VNdWx0aXNpZyhtdWx0aXNpZ0hleGVzLCB0aHJlc2hvbGQsIHBhc3N3b3JkKTtcbn1cblxuc2VsZi5leGNoYW5nZU11bHRpc2lnS2V5cyA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBtdWx0aXNpZ0hleGVzLCBwYXNzd29yZCkge1xuICByZXR1cm4gKGF3YWl0IHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmV4Y2hhbmdlTXVsdGlzaWdLZXlzKG11bHRpc2lnSGV4ZXMsIHBhc3N3b3JkKSkudG9Kc29uKCk7XG59XG5cbnNlbGYuZXhwb3J0TXVsdGlzaWdIZXggPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uZXhwb3J0TXVsdGlzaWdIZXgoKTtcbn1cblxuc2VsZi5pbXBvcnRNdWx0aXNpZ0hleCA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBtdWx0aXNpZ0hleGVzKSB7XG4gIHJldHVybiBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXS5pbXBvcnRNdWx0aXNpZ0hleChtdWx0aXNpZ0hleGVzKTtcbn1cblxuc2VsZi5zaWduTXVsdGlzaWdUeEhleCA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBtdWx0aXNpZ1R4SGV4KSB7XG4gIHJldHVybiAoYXdhaXQgc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uc2lnbk11bHRpc2lnVHhIZXgobXVsdGlzaWdUeEhleCkpLnRvSnNvbigpO1xufVxuXG5zZWxmLnN1Ym1pdE11bHRpc2lnVHhIZXggPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgc2lnbmVkTXVsdGlzaWdUeEhleCkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uc3VibWl0TXVsdGlzaWdUeEhleChzaWduZWRNdWx0aXNpZ1R4SGV4KTtcbn1cblxuc2VsZi5nZXREYXRhID0gYXN5bmMgZnVuY3Rpb24od2FsbGV0SWQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmdldERhdGEoKTtcbn1cblxuc2VsZi5jaGFuZ2VQYXNzd29yZCA9IGFzeW5jIGZ1bmN0aW9uKHdhbGxldElkLCBvbGRQYXNzd29yZCwgbmV3UGFzc3dvcmQpIHtcbiAgcmV0dXJuIHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmNoYW5nZVBhc3N3b3JkKG9sZFBhc3N3b3JkLCBuZXdQYXNzd29yZCk7XG59XG5cbnNlbGYuaXNDbG9zZWQgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCkge1xuICByZXR1cm4gIXNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdIHx8IHNlbGYuV09SS0VSX09CSkVDVFNbd2FsbGV0SWRdLmlzQ2xvc2VkKCk7XG59XG5cbnNlbGYuY2xvc2UgPSBhc3luYyBmdW5jdGlvbih3YWxsZXRJZCwgc2F2ZSkge1xuICByZXR1cm4gc2VsZi5XT1JLRVJfT0JKRUNUU1t3YWxsZXRJZF0uY2xvc2Uoc2F2ZSk7XG4gIGRlbGV0ZSBzZWxmLldPUktFUl9PQkpFQ1RTW3dhbGxldElkXTtcbn0iXSwibWFwcGluZ3MiOiJrR0FBQSxJQUFBQSxPQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxTQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRSxXQUFBLEdBQUFILHNCQUFBLENB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 \ No newline at end of file diff --git a/dist/src/main/ts/common/SslOptions.d.ts b/dist/src/main/ts/common/SslOptions.d.ts new file mode 100644 index 000000000..7c043425c --- /dev/null +++ b/dist/src/main/ts/common/SslOptions.d.ts @@ -0,0 +1,21 @@ +/** + * SSL options for remote endpoints. + */ +export default class SslOptions { + privateKeyPath: string; + certificatePath: string; + certificateAuthorityFile: string; + allowedFingerprints: string[]; + allowAnyCert: boolean; + constructor(options?: Partial); + getPrivateKeyPath(): string; + setPrivateKeyPath(privateKeyPath: any): this; + getCertificatePath(): string; + setCertificatePath(certificatePath: any): this; + getCertificateAuthorityFile(): string; + setCertificateAuthorityFile(certificateAuthorityFile: any): this; + getAllowedFingerprints(): string[]; + setAllowedFingerprints(allowedFingerprints: any): this; + getAllowAnyCert(): boolean; + setAllowAnyCert(allowAnyCert: any): this; +} diff --git a/dist/src/main/ts/common/SslOptions.js b/dist/src/main/ts/common/SslOptions.js new file mode 100644 index 000000000..dfa27a521 --- /dev/null +++ b/dist/src/main/ts/common/SslOptions.js @@ -0,0 +1,61 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * SSL options for remote endpoints. + */ +class SslOptions { + + + + + + + + constructor(options) { + Object.assign(this, options); + } + + getPrivateKeyPath() { + return this.privateKeyPath; + } + + setPrivateKeyPath(privateKeyPath) { + this.privateKeyPath = privateKeyPath; + return this; + } + + getCertificatePath() { + return this.certificatePath; + } + + setCertificatePath(certificatePath) { + this.certificatePath = certificatePath; + return this; + } + + getCertificateAuthorityFile() { + return this.certificateAuthorityFile; + } + + setCertificateAuthorityFile(certificateAuthorityFile) { + this.certificateAuthorityFile = certificateAuthorityFile; + return this; + } + + getAllowedFingerprints() { + return this.allowedFingerprints; + } + + setAllowedFingerprints(allowedFingerprints) { + this.allowedFingerprints = allowedFingerprints; + return this; + } + + getAllowAnyCert() { + return this.allowAnyCert; + } + + setAllowAnyCert(allowAnyCert) { + this.allowAnyCert = allowAnyCert; + return this; + } +}exports.default = SslOptions; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJTc2xPcHRpb25zIiwiY29uc3RydWN0b3IiLCJvcHRpb25zIiwiT2JqZWN0IiwiYXNzaWduIiwiZ2V0UHJpdmF0ZUtleVBhdGgiLCJwcml2YXRlS2V5UGF0aCIsInNldFByaXZhdGVLZXlQYXRoIiwiZ2V0Q2VydGlmaWNhdGVQYXRoIiwiY2VydGlmaWNhdGVQYXRoIiwic2V0Q2VydGlmaWNhdGVQYXRoIiwiZ2V0Q2VydGlmaWNhdGVBdXRob3JpdHlGaWxlIiwiY2VydGlmaWNhdGVBdXRob3JpdHlGaWxlIiwic2V0Q2VydGlmaWNhdGVBdXRob3JpdHlGaWxlIiwiZ2V0QWxsb3dlZEZpbmdlcnByaW50cyIsImFsbG93ZWRGaW5nZXJwcmludHMiLCJzZXRBbGxvd2VkRmluZ2VycHJpbnRzIiwiZ2V0QWxsb3dBbnlDZXJ0IiwiYWxsb3dBbnlDZXJ0Iiwic2V0QWxsb3dBbnlDZXJ0IiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9jb21tb24vU3NsT3B0aW9ucy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNTTCBvcHRpb25zIGZvciByZW1vdGUgZW5kcG9pbnRzLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTc2xPcHRpb25zIHtcblxuICBwcml2YXRlS2V5UGF0aDogc3RyaW5nO1xuICBjZXJ0aWZpY2F0ZVBhdGg6IHN0cmluZztcbiAgY2VydGlmaWNhdGVBdXRob3JpdHlGaWxlOiBzdHJpbmc7XG4gIGFsbG93ZWRGaW5nZXJwcmludHM6IHN0cmluZ1tdO1xuICBhbGxvd0FueUNlcnQ6IGJvb2xlYW47XG5cbiAgY29uc3RydWN0b3Iob3B0aW9ucz86IFBhcnRpYWw8U3NsT3B0aW9ucz4pIHtcbiAgICBPYmplY3QuYXNzaWduKHRoaXMsIG9wdGlvbnMpO1xuICB9XG4gIFxuICBnZXRQcml2YXRlS2V5UGF0aCgpIHtcbiAgICByZXR1cm4gdGhpcy5wcml2YXRlS2V5UGF0aDtcbiAgfVxuICBcbiAgc2V0UHJpdmF0ZUtleVBhdGgocHJpdmF0ZUtleVBhdGgpIHtcbiAgICB0aGlzLnByaXZhdGVLZXlQYXRoID0gcHJpdmF0ZUtleVBhdGg7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldENlcnRpZmljYXRlUGF0aCgpIHtcbiAgICByZXR1cm4gdGhpcy5jZXJ0aWZpY2F0ZVBhdGg7XG4gIH1cbiAgXG4gIHNldENlcnRpZmljYXRlUGF0aChjZXJ0aWZpY2F0ZVBhdGgpIHtcbiAgICB0aGlzLmNlcnRpZmljYXRlUGF0aCA9IGNlcnRpZmljYXRlUGF0aDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0Q2VydGlmaWNhdGVBdXRob3JpdHlGaWxlKCkge1xuICAgIHJldHVybiB0aGlzLmNlcnRpZmljYXRlQXV0aG9yaXR5RmlsZTtcbiAgfVxuICBcbiAgc2V0Q2VydGlmaWNhdGVBdXRob3JpdHlGaWxlKGNlcnRpZmljYXRlQXV0aG9yaXR5RmlsZSkge1xuICAgIHRoaXMuY2VydGlmaWNhdGVBdXRob3JpdHlGaWxlID0gY2VydGlmaWNhdGVBdXRob3JpdHlGaWxlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRBbGxvd2VkRmluZ2VycHJpbnRzKCkge1xuICAgIHJldHVybiB0aGlzLmFsbG93ZWRGaW5nZXJwcmludHM7XG4gIH1cbiAgXG4gIHNldEFsbG93ZWRGaW5nZXJwcmludHMoYWxsb3dlZEZpbmdlcnByaW50cykge1xuICAgIHRoaXMuYWxsb3dlZEZpbmdlcnByaW50cyA9IGFsbG93ZWRGaW5nZXJwcmludHM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEFsbG93QW55Q2VydCgpIHtcbiAgICByZXR1cm4gdGhpcy5hbGxvd0FueUNlcnQ7XG4gIH1cbiAgXG4gIHNldEFsbG93QW55Q2VydChhbGxvd0FueUNlcnQpIHtcbiAgICB0aGlzLmFsbG93QW55Q2VydCA9IGFsbG93QW55Q2VydDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoicUdBQUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUEsVUFBVSxDQUFDOzs7Ozs7OztFQVE5QkMsV0FBV0EsQ0FBQ0MsT0FBNkIsRUFBRTtJQUN6Q0MsTUFBTSxDQUFDQyxNQUFNLENBQUMsSUFBSSxFQUFFRixPQUFPLENBQUM7RUFDOUI7O0VBRUFHLGlCQUFpQkEsQ0FBQSxFQUFHO0lBQ2xCLE9BQU8sSUFBSSxDQUFDQyxjQUFjO0VBQzVCOztFQUVBQyxpQkFBaUJBLENBQUNELGNBQWMsRUFBRTtJQUNoQyxJQUFJLENBQUNBLGNBQWMsR0FBR0EsY0FBYztJQUNwQyxPQUFPLElBQUk7RUFDYjs7RUFFQUUsa0JBQWtCQSxDQUFBLEVBQUc7SUFDbkIsT0FBTyxJQUFJLENBQUNDLGVBQWU7RUFDN0I7O0VBRUFDLGtCQUFrQkEsQ0FBQ0QsZUFBZSxFQUFFO0lBQ2xDLElBQUksQ0FBQ0EsZUFBZSxHQUFHQSxlQUFlO0lBQ3RDLE9BQU8sSUFBSTtFQUNiOztFQUVBRSwyQkFBMkJBLENBQUEsRUFBRztJQUM1QixPQUFPLElBQUksQ0FBQ0Msd0JBQXdCO0VBQ3RDOztFQUVBQywyQkFBMkJBLENBQUNELHdCQUF3QixFQUFFO0lBQ3BELElBQUksQ0FBQ0Esd0JBQXdCLEdBQUdBLHdCQUF3QjtJQUN4RCxPQUFPLElBQUk7RUFDYjs7RUFFQUUsc0JBQXNCQSxDQUFBLEVBQUc7SUFDdkIsT0FBTyxJQUFJLENBQUNDLG1CQUFtQjtFQUNqQzs7RUFFQUMsc0JBQXNCQSxDQUFDRCxtQkFBbUIsRUFBRTtJQUMxQyxJQUFJLENBQUNBLG1CQUFtQixHQUFHQSxtQkFBbUI7SUFDOUMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLGVBQWVBLENBQUEsRUFBRztJQUNoQixPQUFPLElBQUksQ0FBQ0MsWUFBWTtFQUMxQjs7RUFFQUMsZUFBZUEsQ0FBQ0QsWUFBWSxFQUFFO0lBQzVCLElBQUksQ0FBQ0EsWUFBWSxHQUFHQSxZQUFZO0lBQ2hDLE9BQU8sSUFBSTtFQUNiO0FBQ0YsQ0FBQ0UsT0FBQSxDQUFBQyxPQUFBLEdBQUFyQixVQUFBIn0= \ No newline at end of file diff --git a/dist/src/main/ts/common/TaskLooper.d.ts b/dist/src/main/ts/common/TaskLooper.d.ts new file mode 100644 index 000000000..9495388a7 --- /dev/null +++ b/dist/src/main/ts/common/TaskLooper.d.ts @@ -0,0 +1,48 @@ +/// +/** + * Run a task in a fixed period loop. + */ +export default class TaskLooper { + _fn: () => Promise; + _isStarted: boolean; + _isLooping: boolean; + _periodInMs: number; + _timeout: NodeJS.Timeout | undefined; + /** + * Build the looper with a function to invoke on a fixed period loop. + * + * @param {function} fn - the async function to invoke + */ + constructor(fn: () => Promise); + /** + * Get the task function to invoke on a fixed period loop. + * + * @return {function} the task function + */ + getTask(): () => Promise; + /** + * Start the task loop. + * + * @param {number} periodInMs the loop period in milliseconds + * @param {boolean} targetFixedPeriod specifies if the task should target a fixed period by accounting for run time (default false) + * @return {TaskLooper} this instance for chaining + */ + start(periodInMs: number, targetFixedPeriod?: boolean): void; + /** + * Indicates if looping. + * + * @return {boolean} true if looping, false otherwise + */ + isStarted(): boolean; + /** + * Stop the task loop. + */ + stop(): void; + /** + * Set the loop period in milliseconds. + * + * @param {number} periodInMs the loop period in milliseconds + */ + setPeriodInMs(periodInMs: any): void; + _runLoop(targetFixedPeriod: boolean): Promise; +} diff --git a/dist/src/main/ts/common/TaskLooper.js b/dist/src/main/ts/common/TaskLooper.js new file mode 100644 index 000000000..69344dc3c --- /dev/null +++ b/dist/src/main/ts/common/TaskLooper.js @@ -0,0 +1,86 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Run a task in a fixed period loop. + */ +class TaskLooper { + + + + + + + + /** + * Build the looper with a function to invoke on a fixed period loop. + * + * @param {function} fn - the async function to invoke + */ + constructor(fn) { + this._fn = fn; + this._isStarted = false; + this._isLooping = false; + } + + /** + * Get the task function to invoke on a fixed period loop. + * + * @return {function} the task function + */ + getTask() { + return this._fn; + } + + /** + * Start the task loop. + * + * @param {number} periodInMs the loop period in milliseconds + * @param {boolean} targetFixedPeriod specifies if the task should target a fixed period by accounting for run time (default false) + * @return {TaskLooper} this instance for chaining + */ + start(periodInMs, targetFixedPeriod) { + if (periodInMs <= 0) throw new Error("Looper period must be greater than 0 ms"); + this.setPeriodInMs(periodInMs); + if (this._isStarted) return; + this._isStarted = true; + this._runLoop(targetFixedPeriod); + } + + /** + * Indicates if looping. + * + * @return {boolean} true if looping, false otherwise + */ + isStarted() { + return this._isStarted; + } + + /** + * Stop the task loop. + */ + stop() { + this._isStarted = false; + clearTimeout(this._timeout); + this._timeout = undefined; + } + + /** + * Set the loop period in milliseconds. + * + * @param {number} periodInMs the loop period in milliseconds + */ + setPeriodInMs(periodInMs) { + if (periodInMs <= 0) throw new Error("Looper period must be greater than 0 ms"); + this._periodInMs = periodInMs; + } + + async _runLoop(targetFixedPeriod) { + this._isLooping = true; + while (this._isStarted) { + const startTime = Date.now(); + await this._fn(); + let that = this; + if (this._isStarted) await new Promise((resolve) => {this._timeout = setTimeout(resolve, that._periodInMs - (targetFixedPeriod ? Date.now() - startTime : 0));}); + } + this._isLooping = false; + } +}exports.default = TaskLooper; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJUYXNrTG9vcGVyIiwiY29uc3RydWN0b3IiLCJmbiIsIl9mbiIsIl9pc1N0YXJ0ZWQiLCJfaXNMb29waW5nIiwiZ2V0VGFzayIsInN0YXJ0IiwicGVyaW9kSW5NcyIsInRhcmdldEZpeGVkUGVyaW9kIiwiRXJyb3IiLCJzZXRQZXJpb2RJbk1zIiwiX3J1bkxvb3AiLCJpc1N0YXJ0ZWQiLCJzdG9wIiwiY2xlYXJUaW1lb3V0IiwiX3RpbWVvdXQiLCJ1bmRlZmluZWQiLCJfcGVyaW9kSW5NcyIsInN0YXJ0VGltZSIsIkRhdGUiLCJub3ciLCJ0aGF0IiwiUHJvbWlzZSIsInJlc29sdmUiLCJzZXRUaW1lb3V0IiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9jb21tb24vVGFza0xvb3Blci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFJ1biBhIHRhc2sgaW4gYSBmaXhlZCBwZXJpb2QgbG9vcC5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgVGFza0xvb3BlciB7XG5cbiAgX2ZuOiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xuICBfaXNTdGFydGVkOiBib29sZWFuO1xuICBfaXNMb29waW5nOiBib29sZWFuO1xuICBfcGVyaW9kSW5NczogbnVtYmVyO1xuICBfdGltZW91dDogTm9kZUpTLlRpbWVvdXQgfCB1bmRlZmluZWQ7XG4gIFxuICAvKipcbiAgICogQnVpbGQgdGhlIGxvb3BlciB3aXRoIGEgZnVuY3Rpb24gdG8gaW52b2tlIG9uIGEgZml4ZWQgcGVyaW9kIGxvb3AuXG4gICAqIFxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmbiAtIHRoZSBhc3luYyBmdW5jdGlvbiB0byBpbnZva2VcbiAgICovXG4gIGNvbnN0cnVjdG9yKGZuOiAoKSA9PiBQcm9taXNlPHZvaWQ+KSB7XG4gICAgdGhpcy5fZm4gPSBmbjtcbiAgICB0aGlzLl9pc1N0YXJ0ZWQgPSBmYWxzZTtcbiAgICB0aGlzLl9pc0xvb3BpbmcgPSBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIHRhc2sgZnVuY3Rpb24gdG8gaW52b2tlIG9uIGEgZml4ZWQgcGVyaW9kIGxvb3AuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtmdW5jdGlvbn0gdGhlIHRhc2sgZnVuY3Rpb25cbiAgICovXG4gIGdldFRhc2soKSB7XG4gICAgcmV0dXJuIHRoaXMuX2ZuO1xuICB9XG4gIFxuICAvKipcbiAgICogU3RhcnQgdGhlIHRhc2sgbG9vcC5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBwZXJpb2RJbk1zIHRoZSBsb29wIHBlcmlvZCBpbiBtaWxsaXNlY29uZHNcbiAgICogQHBhcmFtIHtib29sZWFufSB0YXJnZXRGaXhlZFBlcmlvZCBzcGVjaWZpZXMgaWYgdGhlIHRhc2sgc2hvdWxkIHRhcmdldCBhIGZpeGVkIHBlcmlvZCBieSBhY2NvdW50aW5nIGZvciBydW4gdGltZSAoZGVmYXVsdCBmYWxzZSlcbiAgICogQHJldHVybiB7VGFza0xvb3Blcn0gdGhpcyBpbnN0YW5jZSBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHN0YXJ0KHBlcmlvZEluTXM6IG51bWJlciwgdGFyZ2V0Rml4ZWRQZXJpb2Q/OiBib29sZWFuKSB7XG4gICAgaWYgKHBlcmlvZEluTXMgPD0gMCkgdGhyb3cgbmV3IEVycm9yKFwiTG9vcGVyIHBlcmlvZCBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwIG1zXCIpO1xuICAgIHRoaXMuc2V0UGVyaW9kSW5NcyhwZXJpb2RJbk1zKTtcbiAgICBpZiAodGhpcy5faXNTdGFydGVkKSByZXR1cm47XG4gICAgdGhpcy5faXNTdGFydGVkID0gdHJ1ZTtcbiAgICB0aGlzLl9ydW5Mb29wKHRhcmdldEZpeGVkUGVyaW9kKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgbG9vcGluZy5cbiAgICogXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgbG9vcGluZywgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBpc1N0YXJ0ZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2lzU3RhcnRlZDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFN0b3AgdGhlIHRhc2sgbG9vcC5cbiAgICovXG4gIHN0b3AoKSB7XG4gICAgdGhpcy5faXNTdGFydGVkID0gZmFsc2U7XG4gICAgY2xlYXJUaW1lb3V0KHRoaXMuX3RpbWVvdXQhKTtcbiAgICB0aGlzLl90aW1lb3V0ID0gdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0aGUgbG9vcCBwZXJpb2QgaW4gbWlsbGlzZWNvbmRzLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IHBlcmlvZEluTXMgdGhlIGxvb3AgcGVyaW9kIGluIG1pbGxpc2Vjb25kc1xuICAgKi9cbiAgICBzZXRQZXJpb2RJbk1zKHBlcmlvZEluTXMpIHtcbiAgICAgIGlmIChwZXJpb2RJbk1zIDw9IDApIHRocm93IG5ldyBFcnJvcihcIkxvb3BlciBwZXJpb2QgbXVzdCBiZSBncmVhdGVyIHRoYW4gMCBtc1wiKTtcbiAgICAgIHRoaXMuX3BlcmlvZEluTXMgPSBwZXJpb2RJbk1zO1xuICAgIH1cbiAgXG4gIGFzeW5jIF9ydW5Mb29wKHRhcmdldEZpeGVkUGVyaW9kOiBib29sZWFuKSB7XG4gICAgdGhpcy5faXNMb29waW5nID0gdHJ1ZTtcbiAgICB3aGlsZSAodGhpcy5faXNTdGFydGVkKSB7XG4gICAgICBjb25zdCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgICAgYXdhaXQgdGhpcy5fZm4oKTtcbiAgICAgIGxldCB0aGF0ID0gdGhpcztcbiAgICAgIGlmICh0aGlzLl9pc1N0YXJ0ZWQpIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7IHRoaXMuX3RpbWVvdXQgPSBzZXRUaW1lb3V0KHJlc29sdmUsIHRoYXQuX3BlcmlvZEluTXMgLSAodGFyZ2V0Rml4ZWRQZXJpb2QgPyAoRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSkgOiAwKSk7IH0pO1xuICAgIH1cbiAgICB0aGlzLl9pc0xvb3Bp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 \ No newline at end of file diff --git a/dist/src/main/ts/common/ThreadPool.d.ts b/dist/src/main/ts/common/ThreadPool.d.ts new file mode 100644 index 000000000..0ef266ff9 --- /dev/null +++ b/dist/src/main/ts/common/ThreadPool.d.ts @@ -0,0 +1,26 @@ +/** + * Simple thread pool using the async library. + */ +export default class ThreadPool { + protected taskQueue: any; + protected drainListeners: any; + /** + * Construct the thread pool. + * + * @param {number} [maxConcurrency] - maximum number of threads in the pool (default 1) + */ + constructor(maxConcurrency: any); + /** + * Submit an asynchronous function to run using the thread pool. + * + * @param {function} asyncFn - asynchronous function to run with the thread pool + * @return {Promise} resolves when the function completes execution + */ + submit(asyncFn: any): Promise; + /** + * Await all functions to complete. + * + * @return {Promise} resolves when all functions complete + */ + awaitAll(): Promise; +} diff --git a/dist/src/main/ts/common/ThreadPool.js b/dist/src/main/ts/common/ThreadPool.js new file mode 100644 index 000000000..037463491 --- /dev/null +++ b/dist/src/main/ts/common/ThreadPool.js @@ -0,0 +1,65 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _GenUtils = _interopRequireDefault(require("./GenUtils")); +var _async = _interopRequireDefault(require("async")); + +/** + * Simple thread pool using the async library. + */ +class ThreadPool { + + + + + /** + * Construct the thread pool. + * + * @param {number} [maxConcurrency] - maximum number of threads in the pool (default 1) + */ + constructor(maxConcurrency) { + if (maxConcurrency === undefined) maxConcurrency = 1; + if (maxConcurrency < 1) throw new Error("Max concurrency must be greater than or equal to 1"); + + // manager concurrency with async queue + //import async from "async"; + this.taskQueue = _async.default.queue((asyncFn, callback) => { + if (asyncFn.then) asyncFn.then((resp) => {callback(resp);}).catch((err) => {callback(undefined, err);});else + asyncFn().then((resp) => {callback(resp);}).catch((err) => {callback(undefined, err);}); + }, maxConcurrency); + + // use drain listeners to support await all + this.drainListeners = []; + this.taskQueue.drain = () => { + for (let listener of this.drainListeners) listener(); + }; + } + + /** + * Submit an asynchronous function to run using the thread pool. + * + * @param {function} asyncFn - asynchronous function to run with the thread pool + * @return {Promise} resolves when the function completes execution + */ + async submit(asyncFn) { + return new Promise((resolve, reject) => { + this.taskQueue.push(asyncFn, (resp, err) => { + if (err !== undefined) reject(err);else + resolve(resp); + }); + }); + } + + /** + * Await all functions to complete. + * + * @return {Promise} resolves when all functions complete + */ + async awaitAll() { + if (this.taskQueue.length === 0) return; + return new Promise((resolve) => { + this.drainListeners.push(() => { + _GenUtils.default.remove(this.drainListeners, this); + resolve(); + }); + }); + } +}exports.default = ThreadPool; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfR2VuVXRpbHMiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9hc3luYyIsIlRocmVhZFBvb2wiLCJjb25zdHJ1Y3RvciIsIm1heENvbmN1cnJlbmN5IiwidW5kZWZpbmVkIiwiRXJyb3IiLCJ0YXNrUXVldWUiLCJhc3luYyIsInF1ZXVlIiwiYXN5bmNGbiIsImNhbGxiYWNrIiwidGhlbiIsInJlc3AiLCJjYXRjaCIsImVyciIsImRyYWluTGlzdGVuZXJzIiwiZHJhaW4iLCJsaXN0ZW5lciIsInN1Ym1pdCIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwicHVzaCIsImF3YWl0QWxsIiwibGVuZ3RoIiwiR2VuVXRpbHMiLCJyZW1vdmUiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2NvbW1vbi9UaHJlYWRQb29sLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi9HZW5VdGlsc1wiO1xuaW1wb3J0IGFzeW5jIGZyb20gXCJhc3luY1wiO1xuXG4vKipcbiAqIFNpbXBsZSB0aHJlYWQgcG9vbCB1c2luZyB0aGUgYXN5bmMgbGlicmFyeS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgVGhyZWFkUG9vbCB7XG5cbiAgcHJvdGVjdGVkIHRhc2tRdWV1ZTogYW55O1xuICBwcm90ZWN0ZWQgZHJhaW5MaXN0ZW5lcnM6IGFueTtcbiAgXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3QgdGhlIHRocmVhZCBwb29sLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IFttYXhDb25jdXJyZW5jeV0gLSBtYXhpbXVtIG51bWJlciBvZiB0aHJlYWRzIGluIHRoZSBwb29sIChkZWZhdWx0IDEpXG4gICAqL1xuICBjb25zdHJ1Y3RvcihtYXhDb25jdXJyZW5jeSkge1xuICAgIGlmIChtYXhDb25jdXJyZW5jeSA9PT0gdW5kZWZpbmVkKSBtYXhDb25jdXJyZW5jeSA9IDE7XG4gICAgaWYgKG1heENvbmN1cnJlbmN5IDwgMSkgdGhyb3cgbmV3IEVycm9yKFwiTWF4IGNvbmN1cnJlbmN5IG11c3QgYmUgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIDFcIik7XG4gICAgXG4gICAgLy8gbWFuYWdlciBjb25jdXJyZW5jeSB3aXRoIGFzeW5jIHF1ZXVlXG4gICAgLy9pbXBvcnQgYXN5bmMgZnJvbSBcImFzeW5jXCI7XG4gICAgdGhpcy50YXNrUXVldWUgPSBhc3luYy5xdWV1ZSgoYXN5bmNGbiwgY2FsbGJhY2spID0+IHtcbiAgICAgIGlmIChhc3luY0ZuLnRoZW4pIGFzeW5jRm4udGhlbihyZXNwID0+IHsgY2FsbGJhY2socmVzcCk7IH0pLmNhdGNoKGVyciA9PiB7IGNhbGxiYWNrKHVuZGVmaW5lZCwgZXJyKTsgfSk7XG4gICAgICBlbHNlIGFzeW5jRm4oKS50aGVuKHJlc3AgPT4geyBjYWxsYmFjayhyZXNwKTsgfSkuY2F0Y2goZXJyID0+IHsgY2FsbGJhY2sodW5kZWZpbmVkLCBlcnIpOyB9KTtcbiAgICB9LCBtYXhDb25jdXJyZW5jeSk7XG4gICAgXG4gICAgLy8gdXNlIGRyYWluIGxpc3RlbmVycyB0byBzdXBwb3J0IGF3YWl0IGFsbFxuICAgIHRoaXMuZHJhaW5MaXN0ZW5lcnMgPSBbXTtcbiAgICB0aGlzLnRhc2tRdWV1ZS5kcmFpbiA9ICgpID0+IHtcbiAgICAgIGZvciAobGV0IGxpc3RlbmVyIG9mIHRoaXMuZHJhaW5MaXN0ZW5lcnMpIGxpc3RlbmVyKCk7XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogU3VibWl0IGFuIGFzeW5jaHJvbm91cyBmdW5jdGlvbiB0byBydW4gdXNpbmcgdGhlIHRocmVhZCBwb29sLlxuICAgKiBcbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gYXN5bmNGbiAtIGFzeW5jaHJvbm91cyBmdW5jdGlvbiB0byBydW4gd2l0aCB0aGUgdGhyZWFkIHBvb2xcbiAgICogQHJldHVybiB7UHJvbWlzZTxUPn0gcmVzb2x2ZXMgd2hlbiB0aGUgZnVuY3Rpb24gY29tcGxldGVzIGV4ZWN1dGlvblxuICAgKi9cbiAgYXN5bmMgc3VibWl0PFQ+KGFzeW5jRm4pOiBQcm9taXNlPFQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgdGhpcy50YXNrUXVldWUucHVzaChhc3luY0ZuLCAocmVzcCwgZXJyKSA9PiB7XG4gICAgICAgIGlmIChlcnIgIT09IHVuZGVmaW5lZCkgcmVqZWN0KGVycik7XG4gICAgICAgIGVsc2UgcmVzb2x2ZShyZXNwKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogQXdhaXQgYWxsIGZ1bmN0aW9ucyB0byBjb21wbGV0ZS5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59IHJlc29sdmVzIHdoZW4gYWxsIGZ1bmN0aW9ucyBjb21wbGV0ZVxuICAgKi9cbiAgYXN5bmMgYXdhaXRBbGwoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMudGFza1F1ZXVlLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgdGhpcy5kcmFpbkxpc3RlbmVycy5wdXNoKCgpID0+IHtcbiAgICAgICAgR2VuVXRpbHMucmVtb3ZlKHRoaXMuZHJhaW5MaXN0ZW5lcnMsIHRoaXMpO1xuICAgICAgICByZXNvbHZlKCk7XG4gICAgICB9KVxuICAgIH0pO1xuICB9XG59XG5cbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLFNBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLE1BQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTs7QUFFQTtBQUNBO0FBQ0E7QUFDZSxNQUFNRSxVQUFVLENBQUM7Ozs7O0VBSzlCO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7RUFDRUMsV0FBV0EsQ0FBQ0MsY0FBYyxFQUFFO0lBQzFCLElBQUlBLGNBQWMsS0FBS0MsU0FBUyxFQUFFRCxjQUFjLEdBQUcsQ0FBQztJQUNwRCxJQUFJQSxjQUFjLEdBQUcsQ0FBQyxFQUFFLE1BQU0sSUFBSUUsS0FBSyxDQUFDLG9EQUFvRCxDQUFDOztJQUU3RjtJQUNBO0lBQ0EsSUFBSSxDQUFDQyxTQUFTLEdBQUdDLGNBQUssQ0FBQ0MsS0FBSyxDQUFDLENBQUNDLE9BQU8sRUFBRUMsUUFBUSxLQUFLO01BQ2xELElBQUlELE9BQU8sQ0FBQ0UsSUFBSSxFQUFFRixPQUFPLENBQUNFLElBQUksQ0FBQyxDQUFBQyxJQUFJLEtBQUksQ0FBRUYsUUFBUSxDQUFDRSxJQUFJLENBQUMsQ0FBRSxDQUFDLENBQUMsQ0FBQ0MsS0FBSyxDQUFDLENBQUFDLEdBQUcsS0FBSSxDQUFFSixRQUFRLENBQUNOLFNBQVMsRUFBRVUsR0FBRyxDQUFDLENBQUUsQ0FBQyxDQUFDLENBQUM7TUFDbkdMLE9BQU8sQ0FBQyxDQUFDLENBQUNFLElBQUksQ0FBQyxDQUFBQyxJQUFJLEtBQUksQ0FBRUYsUUFBUSxDQUFDRSxJQUFJLENBQUMsQ0FBRSxDQUFDLENBQUMsQ0FBQ0MsS0FBSyxDQUFDLENBQUFDLEdBQUcsS0FBSSxDQUFFSixRQUFRLENBQUNOLFNBQVMsRUFBRVUsR0FBRyxDQUFDLENBQUUsQ0FBQyxDQUFDO0lBQzlGLENBQUMsRUFBRVgsY0FBYyxDQUFDOztJQUVsQjtJQUNBLElBQUksQ0FBQ1ksY0FBYyxHQUFHLEVBQUU7SUFDeEIsSUFBSSxDQUFDVCxTQUFTLENBQUNVLEtBQUssR0FBRyxNQUFNO01BQzNCLEtBQUssSUFBSUMsUUFBUSxJQUFJLElBQUksQ0FBQ0YsY0FBYyxFQUFFRSxRQUFRLENBQUMsQ0FBQztJQUN0RCxDQUFDO0VBQ0g7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsTUFBTUMsTUFBTUEsQ0FBSVQsT0FBTyxFQUFjO0lBQ25DLE9BQU8sSUFBSVUsT0FBTyxDQUFDLENBQUNDLE9BQU8sRUFBRUMsTUFBTSxLQUFLO01BQ3RDLElBQUksQ0FBQ2YsU0FBUyxDQUFDZ0IsSUFBSSxDQUFDYixPQUFPLEVBQUUsQ0FBQ0csSUFBSSxFQUFFRSxHQUFHLEtBQUs7UUFDMUMsSUFBSUEsR0FBRyxLQUFLVixTQUFTLEVBQUVpQixNQUFNLENBQUNQLEdBQUcsQ0FBQyxDQUFDO1FBQzlCTSxPQUFPLENBQUNSLElBQUksQ0FBQztNQUNwQixDQUFDLENBQUM7SUFDSixDQUFDLENBQUM7RUFDSjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsTUFBTVcsUUFBUUEsQ0FBQSxFQUFrQjtJQUM5QixJQUFJLElBQUksQ0FBQ2pCLFNBQVMsQ0FBQ2tCLE1BQU0sS0FBSyxDQUFDLEVBQUU7SUFDakMsT0FBTyxJQUFJTCxPQUFPLENBQUMsQ0FBQ0MsT0FBTyxLQUFLO01BQzlCLElBQUksQ0FBQ0wsY0FBYyxDQUFDTyxJQUFJLENBQUMsTUFBTTtRQUM3QkcsaUJBQVEsQ0FBQ0MsTUFBTSxDQUFDLElBQUksQ0FBQ1gsY0FBYyxFQUFFLElBQUksQ0FBQztRQUMxQ0ssT0FBTyxDQUFDLENBQUM7TUFDWCxDQUFDLENBQUM7SUFDSixDQUFDLENBQUM7RUFDSjtBQUNGLENBQUNPLE9BQUEsQ0FBQUMsT0FBQSxHQUFBM0IsVUFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/MoneroDaemon.d.ts b/dist/src/main/ts/daemon/MoneroDaemon.d.ts new file mode 100644 index 000000000..2fd3d4c9d --- /dev/null +++ b/dist/src/main/ts/daemon/MoneroDaemon.d.ts @@ -0,0 +1,508 @@ +import MoneroAltChain from "./model/MoneroAltChain"; +import MoneroBan from "./model/MoneroBan"; +import MoneroBlock from "./model/MoneroBlock"; +import MoneroBlockHeader from "./model/MoneroBlockHeader"; +import MoneroBlockTemplate from "./model/MoneroBlockTemplate"; +import MoneroDaemonInfo from "./model/MoneroDaemonInfo"; +import MoneroDaemonListener from "./model/MoneroDaemonListener"; +import MoneroDaemonSyncInfo from "./model/MoneroDaemonSyncInfo"; +import MoneroDaemonUpdateCheckResult from "./model/MoneroDaemonUpdateCheckResult"; +import MoneroDaemonUpdateDownloadResult from "./model/MoneroDaemonUpdateDownloadResult"; +import MoneroFeeEstimate from "./model/MoneroFeeEstimate"; +import MoneroHardForkInfo from "./model/MoneroHardForkInfo"; +import MoneroKeyImageSpentStatus from "./model/MoneroKeyImageSpentStatus"; +import MoneroMinerTxSum from "./model/MoneroMinerTxSum"; +import MoneroMiningStatus from "./model/MoneroMiningStatus"; +import MoneroOutput from "./model/MoneroOutput"; +import MoneroOutputHistogramEntry from "./model/MoneroOutputHistogramEntry"; +import MoneroPeer from "./model/MoneroPeer"; +import MoneroPruneResult from "./model/MoneroPruneResult"; +import MoneroSubmitTxResult from "./model/MoneroSubmitTxResult"; +import MoneroTx from "./model/MoneroTx"; +import MoneroTxPoolStats from "./model/MoneroTxPoolStats"; +import MoneroVersion from "./model/MoneroVersion"; +/** + * Copyright (c) woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + * Monero daemon interface and default implementations. + */ +export default class MoneroDaemon { + /** + * Register a listener to receive daemon notifications. + * + * @param {MoneroDaemonListener} listener - listener to receive daemon notifications + * @return {Promise} + */ + addListener(listener: MoneroDaemonListener): Promise; + /** + * Unregister a listener to receive daemon notifications. + * + * @param {MoneroDaemonListener} listener - listener to unregister + * @return {Promise} + */ + removeListener(listener: MoneroDaemonListener): Promise; + /** + * Get the listeners registered with the daemon. + * + * @return {MoneroDaemonListener[]} the registered listeners + */ + getListeners(): MoneroDaemonListener[]; + /** + * Indicates if the client is connected to the daemon via RPC. + * + * @return {Promise} true if the client is connected to the daemon, false otherwise + */ + isConnected(): Promise; + /** + * Gets the version of the daemon. + * + * @return {Promise} the version of the daemon + */ + getVersion(): Promise; + /** + * Indicates if the daemon is trusted xor untrusted. + * + * @return {Promise} true if the daemon is trusted, false otherwise + */ + isTrusted(): Promise; + /** + * Get the number of blocks in the longest chain known to the node. + * + * @return {Promise} the number of blocks! + */ + getHeight(): Promise; + /** + * Get a block's hash by its height. + * + * @param {number} height - height of the block hash to get + * @return {Promise} the block's hash at the given height + */ + getBlockHash(height: number): Promise; + /** + * Get a block template for mining a new block. + * + * @param {string} walletAddress - address of the wallet to receive miner transactions if block is successfully mined + * @param {number} [reserveSize] - reserve size (optional) + * @return {Promise} is a block template for mining a new block + */ + getBlockTemplate(walletAddress: string, reserveSize?: number): Promise; + /** + * Get the last block's header. + * + * @return {Promise} last block's header + */ + getLastBlockHeader(): Promise; + /** + * Get a block header by its hash. + * + * @param {string} blockHash - hash of the block to get the header of + * @return {Promise} block's header + */ + getBlockHeaderByHash(blockHash: string): Promise; + /** + * Get a block header by its height. + * + * @param {number} height - height of the block to get the header of + * @return {Promise} block's header + */ + getBlockHeaderByHeight(height: number): Promise; + /** + * Get block headers for the given range. + * + * @param {number} [startHeight] - start height lower bound inclusive (optional) + * @param {number} [endHeight] - end height upper bound inclusive (optional) + * @return {Promise} for the given range + */ + getBlockHeadersByRange(startHeight?: number, endHeight?: number): Promise; + /** + * Get a block by hash. + * + * @param {string} blockHash - hash of the block to get + * @return {Promise} with the given hash + */ + getBlockByHash(blockHash: string): Promise; + /** + * Get blocks by hash. + * + * @param {string[]} blockHashes - array of hashes; first 10 blocks hashes goes sequential, + * next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, + * and the last one is always genesis block + * @param {number} startHeight - start height to get blocks by hash + * @param {boolean} [prune] - specifies if returned blocks should be pruned (defaults to false) // TODO: test default + * @return {Promise} retrieved blocks + */ + getBlocksByHash(blockHashes: string[], startHeight: number, prune?: boolean): Promise; + /** + * Get a block by height. + * + * @param {number} height - height of the block to get + * @return {Promise} with the given height + */ + getBlockByHeight(height: number): Promise; + /** + * Get blocks at the given heights. + * + * @param {number[]} heights - heights of the blocks to get + * @return {Promise} are blocks at the given heights + */ + getBlocksByHeight(heights: number[]): Promise; + /** + * Get blocks in the given height range. + * + * @param {number} [startHeight] - start height lower bound inclusive (optional) + * @param {number} [endHeight] - end height upper bound inclusive (optional) + * @return {Promise} are blocks in the given height range + */ + getBlocksByRange(startHeight?: number, endHeight?: number): Promise; + /** + * Get blocks in the given height range as chunked requests so that each request is + * not too big. + * + * @param {number} [startHeight] - start height lower bound inclusive (optional) + * @param {number} [endHeight] - end height upper bound inclusive (optional) + * @param {number} [maxChunkSize] - maximum chunk size in any one request (default 3,000,000 bytes) + * @return {Promise} blocks in the given height range + */ + getBlocksByRangeChunked(startHeight?: number, endHeight?: number, maxChunkSize?: number): Promise; + /** + * Get block hashes as a binary request to the daemon. + * + * @param {string[]} blockHashes - specify block hashes to fetch; first 10 blocks hash goes + * sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 + * and so on, and the last one is always genesis block + * @param {number} startHeight - starting height of block hashes to return + * @return {Promise} requested block hashes + */ + getBlockHashes(blockHashes: string[], startHeight: number): Promise; + /** + * Get a transaction by hash. + * + * @param {string} txHash - hash of the transaction to get + * @param {boolean} [prune] - specifies if the returned tx should be pruned (defaults to false) + * @return {Promise} transaction with the given hash or undefined if not found + */ + getTx(txHash?: string, prune?: boolean): Promise; + /** + * Get transactions by hashes. + * + * @param {string[]} txHashes - hashes of transactions to get + * @param {boolean} [prune] - specifies if the returned txs should be pruned (defaults to false) + * @return {Promise} found transactions with the given hashes + */ + getTxs(txHashes: string[], prune?: boolean): Promise; + /** + * Get a transaction hex by hash. + * + * @param {string} txHash - hash of the transaction to get hex from + * @param {boolean} [prune] - specifies if the returned tx hex should be pruned (defaults to false) + * @return {Promise} tx hex with the given hash + */ + getTxHex(txHash: string, prune?: boolean): Promise; + /** + * Get transaction hexes by hashes. + * + * @param {string[]} txHashes - hashes of transactions to get hexes from + * @param {boolean} [prune] - specifies if the returned tx hexes should be pruned (defaults to false) + * @return {Promise} tx hexes + */ + getTxHexes(txHashes: string[], prune?: boolean): Promise; + /** + * Gets the total emissions and fees from the genesis block to the current height. + * + * @param {number} height - height to start computing the miner sum + * @param {number} numBlocks - number of blocks to include in the sum + * @return {Promise} encapsulates the total emissions and fees since the genesis block + */ + getMinerTxSum(height: number, numBlocks: number): Promise; + /** + * Get mining fee estimates per kB. + * + * @param {number} graceBlocks TODO + * @return {Promise} mining fee estimates per kB + */ + getFeeEstimate(graceBlocks?: number): Promise; + /** + * Submits a transaction to the daemon's pool. + * + * @param {string} txHex - raw transaction hex to submit + * @param {boolean} doNotRelay specifies if the tx should be relayed (default false, i.e. relay) + * @return {Promise} contains submission results + */ + submitTxHex(txHex: string, doNotRelay?: boolean): Promise; + /** + * Relays a transaction by hash. + * + * @param {string} txHash - hash of the transaction to relay + * @return {Promise} + */ + relayTxByHash(txHash: string): Promise; + /** + * Relays transactions by hash. + * + * @param {string[]} txHashes - hashes of the transactinos to relay + * @return {Promise} + */ + relayTxsByHash(txHashes: string[]): Promise; + /** + * Get valid transactions seen by the node but not yet mined into a block, as well + * as spent key image information for the tx pool. + * + * @return {Promise} are transactions in the transaction pool! + */ + getTxPool(): Promise; + /** + * Get hashes of transactions in the transaction pool. + * + * @return {string[]} are hashes of transactions in the transaction pool + */ + getTxPoolHashes(): Promise; + /** + * Get transaction pool statistics. + * + * @return {Promise} contains statistics about the transaction pool + */ + getTxPoolStats(): Promise; + /** + * Flush transactions from the tx pool. + * + * @param {(string | string[])} [hashes] - specific transactions to flush (defaults to all) + * @return {Promise} + */ + flushTxPool(hashes?: string | string[]): Promise; + /** + * Get the spent status of the given key image. + * + * @param {string} keyImage - key image hex to get the status of + * @return {Promise} status of the key image + */ + getKeyImageSpentStatus(keyImage: string): Promise; + /** + * Get the spent status of each given key image. + * + * @param {string[]} keyImages are hex key images to get the statuses of + * @return {Promise} status for each key image + */ + getKeyImageSpentStatuses(keyImages: string[]): Promise; + /** + * Get outputs identified by a list of output amounts and indices as a binary + * request. + * + * @param {MoneroOutput[]} outputs - identify each output by amount and index + * @return {Promise} identified outputs + */ + getOutputs(outputs: MoneroOutput[]): Promise; + /** + * Get a histogram of output amounts. For all amounts (possibly filtered by + * parameters), gives the number of outputs on the chain for that amount. + * RingCT outputs counts as 0 amount. + * + * @param {bigint[]} [amounts] - amounts of outputs to make the histogram with + * @param {number} [minCount] - TODO + * @param {number} [maxCount] - TODO + * @param {boolean} [isUnlocked] - makes a histogram with outputs with the specified lock state + * @param {number} [recentCutoff] - TODO + * @return {Promise} are entries meeting the parameters + */ + getOutputHistogram(amounts?: bigint[], minCount?: number, maxCount?: number, isUnlocked?: boolean, recentCutoff?: number): Promise; + /** + * Get general information about the state of the node and the network. + * + * @return {Promise} is general information about the node and network + */ + getInfo(): Promise; + /** + * Get synchronization information. + * + * @return {Promise} contains sync information + */ + getSyncInfo(): Promise; + /** + * Look up information regarding hard fork voting and readiness. + * + * @return {Promise } contains hard fork information + */ + getHardForkInfo(): Promise; + /** + * Get alternative chains seen by the node. + * + * @return {Promise} alternative chains + */ + getAltChains(): Promise; + /** + * Get known block hashes which are not on the main chain. + * + * @return {Promise} known block hashes which are not on the main chain + */ + getAltBlockHashes(): Promise; + /** + * Get the download bandwidth limit. + * + * @return {Promise} download bandwidth limit + */ + getDownloadLimit(): Promise; + /** + * Set the download bandwidth limit. + * + * @param {number} limit - download limit to set (-1 to reset to default) + * @return {number} new download limit after setting + */ + setDownloadLimit(limit: number): Promise; + /** + * Reset the download bandwidth limit. + * + * @return {Promise} download bandwidth limit after resetting + */ + resetDownloadLimit(): Promise; + /** + * Get the upload bandwidth limit. + * + * @return {Promise} upload bandwidth limit + */ + getUploadLimit(): Promise; + /** + * Set the upload bandwidth limit. + * + * @param limit - upload limit to set (-1 to reset to default) + * @return {Promise} new upload limit after setting + */ + setUploadLimit(limit: number): Promise; + /** + * Reset the upload bandwidth limit. + * + * @return {Promise} upload bandwidth limit after resetting + */ + resetUploadLimit(): Promise; + /** + * Get peers with active incoming or outgoing connections to the node. + * + * @return {Promise} the daemon's peers + */ + getPeers(): Promise; + /** + * Get known peers including their last known online status. + * + * @return {MoneroPeer[]} the daemon's known peers + */ + getKnownPeers(): Promise; + /** + * Limit number of outgoing peers. + * + * @param {number} limit - maximum number of outgoing peers + * @return {Promise} + */ + setOutgoingPeerLimit(limit: number): Promise; + /** + * Limit number of incoming peers. + * + * @param {number} limit - maximum number of incoming peers + * @return {Promise} + */ + setIncomingPeerLimit(limit: number): Promise; + /** + * Get peer bans. + * + * @return {Promise} entries about banned peers + */ + getPeerBans(): Promise; + /** + * Ban a peer node. + * + * @param {MoneroBan} ban - contains information about a node to ban + * @return {Promise} + */ + setPeerBan(ban: MoneroBan): Promise; + /** + * Ban peers nodes. + * + * @param {MoneroBan[]} bans - specify which peers to ban + * @return {Promise} + */ + setPeerBans(bans: MoneroBan[]): Promise; + /** + * Start mining. + * + * @param {string} address - address given miner rewards if the daemon mines a block + * @param {integer} [numThreads] - number of mining threads to run (default 1) + * @param {boolean} [isBackground] - specifies if the miner should run in the background or not (default false) + * @param {boolean} [ignoreBattery] - specifies if the battery state (e.g. on laptop) should be ignored or not (default false) + * @return {Promise} + */ + startMining(address: string, numThreads?: number, isBackground?: boolean, ignoreBattery?: boolean): Promise; + /** + * Stop mining. + * + * @return {Promise} + */ + stopMining(): Promise; + /** + * Get the daemon's mining status. + * + * @return {Promise} daemon's mining status + */ + getMiningStatus(): Promise; + /** + * Submit a mined block to the network. + * + * @param {string} blockBlob - mined block to submit + * @return {Promise} + */ + submitBlock(blockBlob: string): Promise; + /** + * Prune the blockchain. + * + * @param {boolean} check specifies to check the pruning (default false) + * @return {Promise} the prune result + */ + pruneBlockchain(check: boolean): Promise; + /** + * Submit mined blocks to the network. + * + * @param {string[]} blockBlobs - mined blocks to submit + * @return {Promise} + */ + submitBlocks(blockBlobs: string[]): Promise; + /** + * Check for update. + * + * @return {Promise} the result + */ + checkForUpdate(): Promise; + /** + * Download an update. + * + * @param {string} [path] - path to download the update (optional) + * @return {Promise} the result + */ + downloadUpdate(path?: string): Promise; + /** + * Safely disconnect and shut down the daemon. + * + * @return {Promise} + */ + stop(): Promise; + /** + * Get the header of the next block added to the chain. + * + * @return {Promise} header of the next block added to the chain + */ + waitForNextBlockHeader(): Promise; +} diff --git a/dist/src/main/ts/daemon/MoneroDaemon.js b/dist/src/main/ts/daemon/MoneroDaemon.js new file mode 100644 index 000000000..7a80071dd --- /dev/null +++ b/dist/src/main/ts/daemon/MoneroDaemon.js @@ -0,0 +1,733 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); + + + + + + + + + + +var _MoneroError = _interopRequireDefault(require("../common/MoneroError")); + + + + + + +//import MoneroOutputDistributionEntry from "./model/MoneroOutputDistributionEntry"; + + + + + + + + + +/** + * Copyright (c) woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Monero daemon interface and default implementations. + */ +class MoneroDaemon { + + /** + * Register a listener to receive daemon notifications. + * + * @param {MoneroDaemonListener} listener - listener to receive daemon notifications + * @return {Promise} + */ + async addListener(listener) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Unregister a listener to receive daemon notifications. + * + * @param {MoneroDaemonListener} listener - listener to unregister + * @return {Promise} + */ + async removeListener(listener) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get the listeners registered with the daemon. + * + * @return {MoneroDaemonListener[]} the registered listeners + */ + getListeners() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Indicates if the client is connected to the daemon via RPC. + * + * @return {Promise} true if the client is connected to the daemon, false otherwise + */ + async isConnected() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Gets the version of the daemon. + * + * @return {Promise} the version of the daemon + */ + async getVersion() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Indicates if the daemon is trusted xor untrusted. + * + * @return {Promise} true if the daemon is trusted, false otherwise + */ + async isTrusted() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get the number of blocks in the longest chain known to the node. + * + * @return {Promise} the number of blocks! + */ + async getHeight() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get a block's hash by its height. + * + * @param {number} height - height of the block hash to get + * @return {Promise} the block's hash at the given height + */ + async getBlockHash(height) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get a block template for mining a new block. + * + * @param {string} walletAddress - address of the wallet to receive miner transactions if block is successfully mined + * @param {number} [reserveSize] - reserve size (optional) + * @return {Promise} is a block template for mining a new block + */ + async getBlockTemplate(walletAddress, reserveSize) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get the last block's header. + * + * @return {Promise} last block's header + */ + async getLastBlockHeader() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get a block header by its hash. + * + * @param {string} blockHash - hash of the block to get the header of + * @return {Promise} block's header + */ + async getBlockHeaderByHash(blockHash) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get a block header by its height. + * + * @param {number} height - height of the block to get the header of + * @return {Promise} block's header + */ + async getBlockHeaderByHeight(height) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get block headers for the given range. + * + * @param {number} [startHeight] - start height lower bound inclusive (optional) + * @param {number} [endHeight] - end height upper bound inclusive (optional) + * @return {Promise} for the given range + */ + async getBlockHeadersByRange(startHeight, endHeight) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get a block by hash. + * + * @param {string} blockHash - hash of the block to get + * @return {Promise} with the given hash + */ + async getBlockByHash(blockHash) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get blocks by hash. + * + * @param {string[]} blockHashes - array of hashes; first 10 blocks hashes goes sequential, + * next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, + * and the last one is always genesis block + * @param {number} startHeight - start height to get blocks by hash + * @param {boolean} [prune] - specifies if returned blocks should be pruned (defaults to false) // TODO: test default + * @return {Promise} retrieved blocks + */ + async getBlocksByHash(blockHashes, startHeight, prune = false) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get a block by height. + * + * @param {number} height - height of the block to get + * @return {Promise} with the given height + */ + async getBlockByHeight(height) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get blocks at the given heights. + * + * @param {number[]} heights - heights of the blocks to get + * @return {Promise} are blocks at the given heights + */ + async getBlocksByHeight(heights) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get blocks in the given height range. + * + * @param {number} [startHeight] - start height lower bound inclusive (optional) + * @param {number} [endHeight] - end height upper bound inclusive (optional) + * @return {Promise} are blocks in the given height range + */ + async getBlocksByRange(startHeight, endHeight) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get blocks in the given height range as chunked requests so that each request is + * not too big. + * + * @param {number} [startHeight] - start height lower bound inclusive (optional) + * @param {number} [endHeight] - end height upper bound inclusive (optional) + * @param {number} [maxChunkSize] - maximum chunk size in any one request (default 3,000,000 bytes) + * @return {Promise} blocks in the given height range + */ + async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get block hashes as a binary request to the daemon. + * + * @param {string[]} blockHashes - specify block hashes to fetch; first 10 blocks hash goes + * sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 + * and so on, and the last one is always genesis block + * @param {number} startHeight - starting height of block hashes to return + * @return {Promise} requested block hashes + */ + async getBlockHashes(blockHashes, startHeight) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get a transaction by hash. + * + * @param {string} txHash - hash of the transaction to get + * @param {boolean} [prune] - specifies if the returned tx should be pruned (defaults to false) + * @return {Promise} transaction with the given hash or undefined if not found + */ + async getTx(txHash, prune = false) { + return (await this.getTxs([txHash], prune))[0]; + } + + /** + * Get transactions by hashes. + * + * @param {string[]} txHashes - hashes of transactions to get + * @param {boolean} [prune] - specifies if the returned txs should be pruned (defaults to false) + * @return {Promise} found transactions with the given hashes + */ + async getTxs(txHashes, prune = false) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get a transaction hex by hash. + * + * @param {string} txHash - hash of the transaction to get hex from + * @param {boolean} [prune] - specifies if the returned tx hex should be pruned (defaults to false) + * @return {Promise} tx hex with the given hash + */ + async getTxHex(txHash, prune = false) { + return (await this.getTxHexes([txHash], prune))[0]; + } + + /** + * Get transaction hexes by hashes. + * + * @param {string[]} txHashes - hashes of transactions to get hexes from + * @param {boolean} [prune] - specifies if the returned tx hexes should be pruned (defaults to false) + * @return {Promise} tx hexes + */ + async getTxHexes(txHashes, prune = false) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Gets the total emissions and fees from the genesis block to the current height. + * + * @param {number} height - height to start computing the miner sum + * @param {number} numBlocks - number of blocks to include in the sum + * @return {Promise} encapsulates the total emissions and fees since the genesis block + */ + async getMinerTxSum(height, numBlocks) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get mining fee estimates per kB. + * + * @param {number} graceBlocks TODO + * @return {Promise} mining fee estimates per kB + */ + async getFeeEstimate(graceBlocks) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Submits a transaction to the daemon's pool. + * + * @param {string} txHex - raw transaction hex to submit + * @param {boolean} doNotRelay specifies if the tx should be relayed (default false, i.e. relay) + * @return {Promise} contains submission results + */ + async submitTxHex(txHex, doNotRelay = false) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Relays a transaction by hash. + * + * @param {string} txHash - hash of the transaction to relay + * @return {Promise} + */ + async relayTxByHash(txHash) { + _assert.default.equal(typeof txHash, "string", "Must provide a transaction hash"); + await this.relayTxsByHash([txHash]); + } + + /** + * Relays transactions by hash. + * + * @param {string[]} txHashes - hashes of the transactinos to relay + * @return {Promise} + */ + async relayTxsByHash(txHashes) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get valid transactions seen by the node but not yet mined into a block, as well + * as spent key image information for the tx pool. + * + * @return {Promise} are transactions in the transaction pool! + */ + async getTxPool() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get hashes of transactions in the transaction pool. + * + * @return {string[]} are hashes of transactions in the transaction pool + */ + async getTxPoolHashes() { + throw new _MoneroError.default("Subclass must implement"); + } + + // /** + // * Get all transaction pool backlog. + // * + // * @return {Promise} backlog entries + // */ + // async getTxPoolBacklog(): Promise { + // throw new MoneroError("Subclass must implement"); + // } + + /** + * Get transaction pool statistics. + * + * @return {Promise} contains statistics about the transaction pool + */ + async getTxPoolStats() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Flush transactions from the tx pool. + * + * @param {(string | string[])} [hashes] - specific transactions to flush (defaults to all) + * @return {Promise} + */ + async flushTxPool(hashes) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get the spent status of the given key image. + * + * @param {string} keyImage - key image hex to get the status of + * @return {Promise} status of the key image + */ + async getKeyImageSpentStatus(keyImage) { + return (await this.getKeyImageSpentStatuses([keyImage]))[0]; + } + + /** + * Get the spent status of each given key image. + * + * @param {string[]} keyImages are hex key images to get the statuses of + * @return {Promise} status for each key image + */ + async getKeyImageSpentStatuses(keyImages) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get outputs identified by a list of output amounts and indices as a binary + * request. + * + * @param {MoneroOutput[]} outputs - identify each output by amount and index + * @return {Promise} identified outputs + */ + async getOutputs(outputs) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get a histogram of output amounts. For all amounts (possibly filtered by + * parameters), gives the number of outputs on the chain for that amount. + * RingCT outputs counts as 0 amount. + * + * @param {bigint[]} [amounts] - amounts of outputs to make the histogram with + * @param {number} [minCount] - TODO + * @param {number} [maxCount] - TODO + * @param {boolean} [isUnlocked] - makes a histogram with outputs with the specified lock state + * @param {number} [recentCutoff] - TODO + * @return {Promise} are entries meeting the parameters + */ + async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) { + throw new _MoneroError.default("Subclass must implement"); + } + + // /** + // * Creates an output distribution. + // * + // * @param {bigint[]} amounts - amounts of outputs to make the distribution with + // * @param {boolean} [cumulative] - specifies if the results should be cumulative (defaults to TODO) + // * @param {number} [startHeight] - start height lower bound inclusive (optional) + // * @param {number} [endHeight] - end height upper bound inclusive (optional) + // * @return {Promise} are entries meeting the parameters + // */ + // async getOutputDistribution(amounts: bigint[], cumulative?: boolean, startHeight?: number, endHeight?: number): Promise { + // throw new MoneroError("Subclass must implement"); + // } + + /** + * Get general information about the state of the node and the network. + * + * @return {Promise} is general information about the node and network + */ + async getInfo() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get synchronization information. + * + * @return {Promise} contains sync information + */ + async getSyncInfo() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Look up information regarding hard fork voting and readiness. + * + * @return {Promise } contains hard fork information + */ + async getHardForkInfo() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get alternative chains seen by the node. + * + * @return {Promise} alternative chains + */ + async getAltChains() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get known block hashes which are not on the main chain. + * + * @return {Promise} known block hashes which are not on the main chain + */ + async getAltBlockHashes() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get the download bandwidth limit. + * + * @return {Promise} download bandwidth limit + */ + async getDownloadLimit() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Set the download bandwidth limit. + * + * @param {number} limit - download limit to set (-1 to reset to default) + * @return {number} new download limit after setting + */ + async setDownloadLimit(limit) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Reset the download bandwidth limit. + * + * @return {Promise} download bandwidth limit after resetting + */ + async resetDownloadLimit() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get the upload bandwidth limit. + * + * @return {Promise} upload bandwidth limit + */ + async getUploadLimit() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Set the upload bandwidth limit. + * + * @param limit - upload limit to set (-1 to reset to default) + * @return {Promise} new upload limit after setting + */ + async setUploadLimit(limit) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Reset the upload bandwidth limit. + * + * @return {Promise} upload bandwidth limit after resetting + */ + async resetUploadLimit() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get peers with active incoming or outgoing connections to the node. + * + * @return {Promise} the daemon's peers + */ + async getPeers() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get known peers including their last known online status. + * + * @return {MoneroPeer[]} the daemon's known peers + */ + async getKnownPeers() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Limit number of outgoing peers. + * + * @param {number} limit - maximum number of outgoing peers + * @return {Promise} + */ + async setOutgoingPeerLimit(limit) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Limit number of incoming peers. + * + * @param {number} limit - maximum number of incoming peers + * @return {Promise} + */ + async setIncomingPeerLimit(limit) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get peer bans. + * + * @return {Promise} entries about banned peers + */ + async getPeerBans() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Ban a peer node. + * + * @param {MoneroBan} ban - contains information about a node to ban + * @return {Promise} + */ + async setPeerBan(ban) { + return await this.setPeerBans([ban]); + } + + /** + * Ban peers nodes. + * + * @param {MoneroBan[]} bans - specify which peers to ban + * @return {Promise} + */ + async setPeerBans(bans) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Start mining. + * + * @param {string} address - address given miner rewards if the daemon mines a block + * @param {integer} [numThreads] - number of mining threads to run (default 1) + * @param {boolean} [isBackground] - specifies if the miner should run in the background or not (default false) + * @param {boolean} [ignoreBattery] - specifies if the battery state (e.g. on laptop) should be ignored or not (default false) + * @return {Promise} + */ + async startMining(address, numThreads, isBackground, ignoreBattery) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Stop mining. + * + * @return {Promise} + */ + async stopMining() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get the daemon's mining status. + * + * @return {Promise} daemon's mining status + */ + async getMiningStatus() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Submit a mined block to the network. + * + * @param {string} blockBlob - mined block to submit + * @return {Promise} + */ + async submitBlock(blockBlob) { + await this.submitBlocks([blockBlob]); + } + + /** + * Prune the blockchain. + * + * @param {boolean} check specifies to check the pruning (default false) + * @return {Promise} the prune result + */ + async pruneBlockchain(check) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Submit mined blocks to the network. + * + * @param {string[]} blockBlobs - mined blocks to submit + * @return {Promise} + */ + async submitBlocks(blockBlobs) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Check for update. + * + * @return {Promise} the result + */ + async checkForUpdate() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Download an update. + * + * @param {string} [path] - path to download the update (optional) + * @return {Promise} the result + */ + async downloadUpdate(path) { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Safely disconnect and shut down the daemon. + * + * @return {Promise} + */ + async stop() { + throw new _MoneroError.default("Subclass must implement"); + } + + /** + * Get the header of the next block added to the chain. + * + * @return {Promise} header of the next block added to the chain + */ + async waitForNextBlockHeader() { + throw new _MoneroError.default("Subclass must implement"); + } +}exports.default = MoneroDaemon; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfTW9uZXJvRXJyb3IiLCJNb25lcm9EYWVtb24iLCJhZGRMaXN0ZW5lciIsImxpc3RlbmVyIiwiTW9uZXJvRXJyb3IiLCJyZW1vdmVMaXN0ZW5lciIsImdldExpc3RlbmVycyIsImlzQ29ubmVjdGVkIiwiZ2V0VmVyc2lvbiIsImlzVHJ1c3RlZCIsImdldEhlaWdodCIsImdldEJsb2NrSGFzaCIsImhlaWdodCIsImdldEJsb2NrVGVtcGxhdGUiLCJ3YWxsZXRBZGRyZXNzIiwicmVzZXJ2ZVNpemUiLCJnZXRMYXN0QmxvY2tIZWFkZXIiLCJnZXRCbG9ja0hlYWRlckJ5SGFzaCIsImJsb2NrSGFzaCIsImdldEJsb2NrSGVhZGVyQnlIZWlnaHQiLCJnZXRCbG9ja0hlYWRlcnNCeVJhbmdlIiwic3RhcnRIZWlnaHQiLCJlbmRIZWlnaHQiLCJnZXRCbG9ja0J5SGFzaCIsImdldEJsb2Nrc0J5SGFzaCIsImJsb2NrSGFzaGVzIiwicHJ1bmUiLCJnZXRCbG9ja0J5SGVpZ2h0IiwiZ2V0QmxvY2tzQnlIZWlnaHQiLCJoZWlnaHRzIiwiZ2V0QmxvY2tzQnlSYW5nZSIsImdldEJsb2Nrc0J5UmFuZ2VDaHVua2VkIiwibWF4Q2h1bmtTaXplIiwiZ2V0QmxvY2tIYXNoZXMiLCJnZXRUeCIsInR4SGFzaCIsImdldFR4cyIsInR4SGFzaGVzIiwiZ2V0VHhIZXgiLCJnZXRUeEhleGVzIiwiZ2V0TWluZXJUeFN1bSIsIm51bUJsb2NrcyIsImdldEZlZUVzdGltYXRlIiwiZ3JhY2VCbG9ja3MiLCJzdWJtaXRUeEhleCIsInR4SGV4IiwiZG9Ob3RSZWxheSIsInJlbGF5VHhCeUhhc2giLCJhc3NlcnQiLCJlcXVhbCIsInJlbGF5VHhzQnlIYXNoIiwiZ2V0VHhQb29sIiwiZ2V0VHhQb29sSGFzaGVzIiwiZ2V0VHhQb29sU3RhdHMiLCJmbHVzaFR4UG9vbCIsImhhc2hlcyIsImdldEtleUltYWdlU3BlbnRTdGF0dXMiLCJrZXlJbWFnZSIsImdldEtleUltYWdlU3BlbnRTdGF0dXNlcyIsImtleUltYWdlcyIsImdldE91dHB1dHMiLCJvdXRwdXRzIiwiZ2V0T3V0cHV0SGlzdG9ncmFtIiwiYW1vdW50cyIsIm1pbkNvdW50IiwibWF4Q291bnQiLCJpc1VubG9ja2VkIiwicmVjZW50Q3V0b2ZmIiwiZ2V0SW5mbyIsImdldFN5bmNJbmZvIiwiZ2V0SGFyZEZvcmtJbmZvIiwiZ2V0QWx0Q2hhaW5zIiwiZ2V0QWx0QmxvY2tIYXNoZXMiLCJnZXREb3dubG9hZExpbWl0Iiwic2V0RG93bmxvYWRMaW1pdCIsImxpbWl0IiwicmVzZXREb3dubG9hZExpbWl0IiwiZ2V0VXBsb2FkTGltaXQiLCJzZXRVcGxvYWRMaW1pdCIsInJlc2V0VXBsb2FkTGltaXQiLCJnZXRQZWVycyIsImdldEtub3duUGVlcnMiLCJzZXRPdXRnb2luZ1BlZXJMaW1pdCIsInNldEluY29taW5nUGVlckxpbWl0IiwiZ2V0UGVlckJhbnMiLCJzZXRQZWVyQmFuIiwiYmFuIiwic2V0UGVlckJhbnMiLCJiYW5zIiwic3RhcnRNaW5pbmciLCJhZGRyZXNzIiwibnVtVGhyZWFkcyIsImlzQmFja2dyb3VuZCIsImlnbm9yZUJhdHRlcnkiLCJzdG9wTWluaW5nIiwiZ2V0TWluaW5nU3RhdHVzIiwic3VibWl0QmxvY2siLCJibG9ja0Jsb2IiLCJzdWJtaXRCbG9ja3MiLCJwcnVuZUJsb2NrY2hhaW4iLCJjaGVjayIsImJsb2NrQmxvYnMiLCJjaGVja0ZvclVwZGF0ZSIsImRvd25sb2FkVXBkYXRlIiwicGF0aCIsInN0b3AiLCJ3YWl0Rm9yTmV4dEJsb2NrSGVhZGVyIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9kYWVtb24vTW9uZXJvRGFlbW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IE1vbmVyb0FsdENoYWluIGZyb20gXCIuL21vZGVsL01vbmVyb0FsdENoYWluXCI7XG5pbXBvcnQgTW9uZXJvQmFuIGZyb20gXCIuL21vZGVsL01vbmVyb0JhblwiO1xuaW1wb3J0IE1vbmVyb0Jsb2NrIGZyb20gXCIuL21vZGVsL01vbmVyb0Jsb2NrXCI7XG5pbXBvcnQgTW9uZXJvQmxvY2tIZWFkZXIgZnJvbSBcIi4vbW9kZWwvTW9uZXJvQmxvY2tIZWFkZXJcIjtcbmltcG9ydCBNb25lcm9CbG9ja1RlbXBsYXRlIGZyb20gXCIuL21vZGVsL01vbmVyb0Jsb2NrVGVtcGxhdGVcIjtcbmltcG9ydCBNb25lcm9EYWVtb25JbmZvIGZyb20gXCIuL21vZGVsL01vbmVyb0RhZW1vbkluZm9cIjtcbmltcG9ydCBNb25lcm9EYWVtb25MaXN0ZW5lciBmcm9tIFwiLi9tb2RlbC9Nb25lcm9EYWVtb25MaXN0ZW5lclwiO1xuaW1wb3J0IE1vbmVyb0RhZW1vblN5bmNJbmZvIGZyb20gXCIuL21vZGVsL01vbmVyb0RhZW1vblN5bmNJbmZvXCI7XG5pbXBvcnQgTW9uZXJvRGFlbW9uVXBkYXRlQ2hlY2tSZXN1bHQgZnJvbSBcIi4vbW9kZWwvTW9uZXJvRGFlbW9uVXBkYXRlQ2hlY2tSZXN1bHRcIjtcbmltcG9ydCBNb25lcm9EYWVtb25VcGRhdGVEb3dubG9hZFJlc3VsdCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9EYWVtb25VcGRhdGVEb3dubG9hZFJlc3VsdFwiO1xuaW1wb3J0IE1vbmVyb0Vycm9yIGZyb20gXCIuLi9jb21tb24vTW9uZXJvRXJyb3JcIjtcbmltcG9ydCBNb25lcm9GZWVFc3RpbWF0ZSBmcm9tIFwiLi9tb2RlbC9Nb25lcm9GZWVFc3RpbWF0ZVwiO1xuaW1wb3J0IE1vbmVyb0hhcmRGb3JrSW5mbyBmcm9tIFwiLi9tb2RlbC9Nb25lcm9IYXJkRm9ya0luZm9cIjtcbmltcG9ydCBNb25lcm9LZXlJbWFnZVNwZW50U3RhdHVzIGZyb20gXCIuL21vZGVsL01vbmVyb0tleUltYWdlU3BlbnRTdGF0dXNcIjtcbmltcG9ydCBNb25lcm9NaW5lclR4U3VtIGZyb20gXCIuL21vZGVsL01vbmVyb01pbmVyVHhTdW1cIjtcbmltcG9ydCBNb25lcm9NaW5pbmdTdGF0dXMgZnJvbSBcIi4vbW9kZWwvTW9uZXJvTWluaW5nU3RhdHVzXCI7XG5pbXBvcnQgTW9uZXJvT3V0cHV0IGZyb20gXCIuL21vZGVsL01vbmVyb091dHB1dFwiO1xuLy9pbXBvcnQgTW9uZXJvT3V0cHV0RGlzdHJpYnV0aW9uRW50cnkgZnJvbSBcIi4vbW9kZWwvTW9uZXJvT3V0cHV0RGlzdHJpYnV0aW9uRW50cnlcIjtcbmltcG9ydCBNb25lcm9PdXRwdXRIaXN0b2dyYW1FbnRyeSBmcm9tIFwiLi9tb2RlbC9Nb25lcm9PdXRwdXRIaXN0b2dyYW1FbnRyeVwiO1xuaW1wb3J0IE1vbmVyb05ldHdvcmtUeXBlIGZyb20gXCIuL21vZGVsL01vbmVyb05ldHdvcmtUeXBlXCI7XG5pbXBvcnQgTW9uZXJvUGVlciBmcm9tIFwiLi9tb2RlbC9Nb25lcm9QZWVyXCI7XG5pbXBvcnQgTW9uZXJvUHJ1bmVSZXN1bHQgZnJvbSBcIi4vbW9kZWwvTW9uZXJvUHJ1bmVSZXN1bHRcIjtcbmltcG9ydCBNb25lcm9TdWJtaXRUeFJlc3VsdCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9TdWJtaXRUeFJlc3VsdFwiO1xuaW1wb3J0IE1vbmVyb1R4IGZyb20gXCIuL21vZGVsL01vbmVyb1R4XCI7XG5pbXBvcnQgTW9uZXJvVHhQb29sU3RhdHMgZnJvbSBcIi4vbW9kZWwvTW9uZXJvVHhQb29sU3RhdHNcIjtcbmltcG9ydCBNb25lcm9WZXJzaW9uIGZyb20gXCIuL21vZGVsL01vbmVyb1ZlcnNpb25cIjtcblxuLyoqXG4gKiBDb3B5cmlnaHQgKGMpIHdvb2RzZXJcbiAqXG4gKiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5XG4gKiBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0byBkZWFsXG4gKiBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzXG4gKiB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsXG4gKiBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbiAqIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4gKlxuICogVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW4gYWxsXG4gKiBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuICpcbiAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MgT1JcbiAqIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuICogRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4gKiBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSXG4gKiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuICogT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEVcbiAqIFNPRlRXQVJFLlxuICovXG5cbi8qKlxuICogTW9uZXJvIGRhZW1vbiBpbnRlcmZhY2UgYW5kIGRlZmF1bHQgaW1wbGVtZW50YXRpb25zLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9EYWVtb24ge1xuICAgIFxuICAvKipcbiAgICogUmVnaXN0ZXIgYSBsaXN0ZW5lciB0byByZWNlaXZlIGRhZW1vbiBub3RpZmljYXRpb25zLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9EYWVtb25MaXN0ZW5lcn0gbGlzdGVuZXIgLSBsaXN0ZW5lciB0byByZWNlaXZlIGRhZW1vbiBub3RpZmljYXRpb25zXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBhZGRMaXN0ZW5lcihsaXN0ZW5lcjogTW9uZXJvRGFlbW9uTGlzdGVuZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFVucmVnaXN0ZXIgYSBsaXN0ZW5lciB0byByZWNlaXZlIGRhZW1vbiBub3RpZmljYXRpb25zLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9EYWVtb25MaXN0ZW5lcn0gbGlzdGVuZXIgLSBsaXN0ZW5lciB0byB1bnJlZ2lzdGVyXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyByZW1vdmVMaXN0ZW5lcihsaXN0ZW5lcjogTW9uZXJvRGFlbW9uTGlzdGVuZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgbGlzdGVuZXJzIHJlZ2lzdGVyZWQgd2l0aCB0aGUgZGFlbW9uLlxuICAgKiBcbiAgICogQHJldHVybiB7TW9uZXJvRGFlbW9uTGlzdGVuZXJbXX0gdGhlIHJlZ2lzdGVyZWQgbGlzdGVuZXJzXG4gICAqL1xuICBnZXRMaXN0ZW5lcnMoKTogTW9uZXJvRGFlbW9uTGlzdGVuZXJbXSB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGNsaWVudCBpcyBjb25uZWN0ZWQgdG8gdGhlIGRhZW1vbiB2aWEgUlBDLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxib29sZWFuPn0gdHJ1ZSBpZiB0aGUgY2xpZW50IGlzIGNvbm5lY3RlZCB0byB0aGUgZGFlbW9uLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIGFzeW5jIGlzQ29ubmVjdGVkKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0cyB0aGUgdmVyc2lvbiBvZiB0aGUgZGFlbW9uLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9WZXJzaW9uPn0gdGhlIHZlcnNpb24gb2YgdGhlIGRhZW1vblxuICAgKi9cbiAgYXN5bmMgZ2V0VmVyc2lvbigpOiBQcm9taXNlPE1vbmVyb1ZlcnNpb24+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgZGFlbW9uIGlzIHRydXN0ZWQgeG9yIHVudHJ1c3RlZC5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbGVhbj59IHRydWUgaWYgdGhlIGRhZW1vbiBpcyB0cnVzdGVkLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIGFzeW5jIGlzVHJ1c3RlZCgpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgbnVtYmVyIG9mIGJsb2NrcyBpbiB0aGUgbG9uZ2VzdCBjaGFpbiBrbm93biB0byB0aGUgbm9kZS5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8bnVtYmVyPn0gdGhlIG51bWJlciBvZiBibG9ja3MhXG4gICAqL1xuICBhc3luYyBnZXRIZWlnaHQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBhIGJsb2NrJ3MgaGFzaCBieSBpdHMgaGVpZ2h0LlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIGhlaWdodCBvZiB0aGUgYmxvY2sgaGFzaCB0byBnZXRcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSB0aGUgYmxvY2sncyBoYXNoIGF0IHRoZSBnaXZlbiBoZWlnaHRcbiAgICovXG4gIGFzeW5jIGdldEJsb2NrSGFzaChoZWlnaHQ6IG51bWJlcik6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgYSBibG9jayB0ZW1wbGF0ZSBmb3IgbWluaW5nIGEgbmV3IGJsb2NrLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHdhbGxldEFkZHJlc3MgLSBhZGRyZXNzIG9mIHRoZSB3YWxsZXQgdG8gcmVjZWl2ZSBtaW5lciB0cmFuc2FjdGlvbnMgaWYgYmxvY2sgaXMgc3VjY2Vzc2Z1bGx5IG1pbmVkXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbcmVzZXJ2ZVNpemVdIC0gcmVzZXJ2ZSBzaXplIChvcHRpb25hbClcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9CbG9ja1RlbXBsYXRlPn0gaXMgYSBibG9jayB0ZW1wbGF0ZSBmb3IgbWluaW5nIGEgbmV3IGJsb2NrXG4gICAqL1xuICBhc3luYyBnZXRCbG9ja1RlbXBsYXRlKHdhbGxldEFkZHJlc3M6IHN0cmluZywgcmVzZXJ2ZVNpemU/OiBudW1iZXIpOiBQcm9taXNlPE1vbmVyb0Jsb2NrVGVtcGxhdGU+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgbGFzdCBibG9jaydzIGhlYWRlci5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQmxvY2tIZWFkZXI+fSBsYXN0IGJsb2NrJ3MgaGVhZGVyXG4gICAqL1xuICBhc3luYyBnZXRMYXN0QmxvY2tIZWFkZXIoKTogUHJvbWlzZTxNb25lcm9CbG9ja0hlYWRlcj4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGEgYmxvY2sgaGVhZGVyIGJ5IGl0cyBoYXNoLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IGJsb2NrSGFzaCAtIGhhc2ggb2YgdGhlIGJsb2NrIHRvIGdldCB0aGUgaGVhZGVyIG9mXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQmxvY2tIZWFkZXI+fSBibG9jaydzIGhlYWRlclxuICAgKi9cbiAgYXN5bmMgZ2V0QmxvY2tIZWFkZXJCeUhhc2goYmxvY2tIYXNoOiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0Jsb2NrSGVhZGVyPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgYSBibG9jayBoZWFkZXIgYnkgaXRzIGhlaWdodC5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBoZWlnaHQgb2YgdGhlIGJsb2NrIHRvIGdldCB0aGUgaGVhZGVyIG9mXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQmxvY2tIZWFkZXI+fSBibG9jaydzIGhlYWRlclxuICAgKi9cbiAgYXN5bmMgZ2V0QmxvY2tIZWFkZXJCeUhlaWdodChoZWlnaHQ6IG51bWJlcik6IFByb21pc2U8TW9uZXJvQmxvY2tIZWFkZXI+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBibG9jayBoZWFkZXJzIGZvciB0aGUgZ2l2ZW4gcmFuZ2UuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXJ0SGVpZ2h0XSAtIHN0YXJ0IGhlaWdodCBsb3dlciBib3VuZCBpbmNsdXNpdmUgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW2VuZEhlaWdodF0gLSBlbmQgaGVpZ2h0IHVwcGVyIGJvdW5kIGluY2x1c2l2ZSAob3B0aW9uYWwpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQmxvY2tIZWFkZXJbXT59IGZvciB0aGUgZ2l2ZW4gcmFuZ2VcbiAgICovXG4gIGFzeW5jIGdldEJsb2NrSGVhZGVyc0J5UmFuZ2Uoc3RhcnRIZWlnaHQ/OiBudW1iZXIsIGVuZEhlaWdodD86IG51bWJlcik6IFByb21pc2U8TW9uZXJvQmxvY2tIZWFkZXJbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGEgYmxvY2sgYnkgaGFzaC5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBibG9ja0hhc2ggLSBoYXNoIG9mIHRoZSBibG9jayB0byBnZXRcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9CbG9jaz59IHdpdGggdGhlIGdpdmVuIGhhc2hcbiAgICovXG4gIGFzeW5jIGdldEJsb2NrQnlIYXNoKGJsb2NrSGFzaDogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9CbG9jaz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGJsb2NrcyBieSBoYXNoLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gYmxvY2tIYXNoZXMgLSBhcnJheSBvZiBoYXNoZXM7IGZpcnN0IDEwIGJsb2NrcyBoYXNoZXMgZ29lcyBzZXF1ZW50aWFsLFxuICAgKiAgICAgICAgbmV4dCBnb2VzIGluIHBvdygyLG4pIG9mZnNldCwgbGlrZSAyLCA0LCA4LCAxNiwgMzIsIDY0IGFuZCBzbyBvbixcbiAgICogICAgICAgIGFuZCB0aGUgbGFzdCBvbmUgaXMgYWx3YXlzIGdlbmVzaXMgYmxvY2tcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXJ0SGVpZ2h0IC0gc3RhcnQgaGVpZ2h0IHRvIGdldCBibG9ja3MgYnkgaGFzaFxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtwcnVuZV0gLSBzcGVjaWZpZXMgaWYgcmV0dXJuZWQgYmxvY2tzIHNob3VsZCBiZSBwcnVuZWQgKGRlZmF1bHRzIHRvIGZhbHNlKSAgLy8gVE9ETzogdGVzdCBkZWZhdWx0XG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQmxvY2tbXT59IHJldHJpZXZlZCBibG9ja3NcbiAgICovXG4gIGFzeW5jIGdldEJsb2Nrc0J5SGFzaChibG9ja0hhc2hlczogc3RyaW5nW10sIHN0YXJ0SGVpZ2h0OiBudW1iZXIsIHBydW5lID0gZmFsc2UpOiBQcm9taXNlPE1vbmVyb0Jsb2NrW10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBhIGJsb2NrIGJ5IGhlaWdodC5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBoZWlnaHQgb2YgdGhlIGJsb2NrIHRvIGdldFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb0Jsb2NrPn0gd2l0aCB0aGUgZ2l2ZW4gaGVpZ2h0XG4gICAqL1xuICBhc3luYyBnZXRCbG9ja0J5SGVpZ2h0KGhlaWdodDogbnVtYmVyKTogUHJvbWlzZTxNb25lcm9CbG9jaz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGJsb2NrcyBhdCB0aGUgZ2l2ZW4gaGVpZ2h0cy5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyW119IGhlaWdodHMgLSBoZWlnaHRzIG9mIHRoZSBibG9ja3MgdG8gZ2V0XG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQmxvY2tbXT59IGFyZSBibG9ja3MgYXQgdGhlIGdpdmVuIGhlaWdodHNcbiAgICovXG4gIGFzeW5jIGdldEJsb2Nrc0J5SGVpZ2h0KGhlaWdodHM6IG51bWJlcltdKTogUHJvbWlzZTxNb25lcm9CbG9ja1tdPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgYmxvY2tzIGluIHRoZSBnaXZlbiBoZWlnaHQgcmFuZ2UuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXJ0SGVpZ2h0XSAtIHN0YXJ0IGhlaWdodCBsb3dlciBib3VuZCBpbmNsdXNpdmUgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW2VuZEhlaWdodF0gLSBlbmQgaGVpZ2h0IHVwcGVyIGJvdW5kIGluY2x1c2l2ZSAob3B0aW9uYWwpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQmxvY2tbXT59IGFyZSBibG9ja3MgaW4gdGhlIGdpdmVuIGhlaWdodCByYW5nZVxuICAgKi9cbiAgYXN5bmMgZ2V0QmxvY2tzQnlSYW5nZShzdGFydEhlaWdodD86IG51bWJlciwgZW5kSGVpZ2h0PzogbnVtYmVyKTogUHJvbWlzZTxNb25lcm9CbG9ja1tdPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgYmxvY2tzIGluIHRoZSBnaXZlbiBoZWlnaHQgcmFuZ2UgYXMgY2h1bmtlZCByZXF1ZXN0cyBzbyB0aGF0IGVhY2ggcmVxdWVzdCBpc1xuICAgKiBub3QgdG9vIGJpZy5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbc3RhcnRIZWlnaHRdIC0gc3RhcnQgaGVpZ2h0IGxvd2VyIGJvdW5kIGluY2x1c2l2ZSAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbZW5kSGVpZ2h0XSAtIGVuZCBoZWlnaHQgdXBwZXIgYm91bmQgaW5jbHVzaXZlIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFttYXhDaHVua1NpemVdIC0gbWF4aW11bSBjaHVuayBzaXplIGluIGFueSBvbmUgcmVxdWVzdCAoZGVmYXVsdCAzLDAwMCwwMDAgYnl0ZXMpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQmxvY2tbXT59IGJsb2NrcyBpbiB0aGUgZ2l2ZW4gaGVpZ2h0IHJhbmdlXG4gICAqL1xuICBhc3luYyBnZXRCbG9ja3NCeVJhbmdlQ2h1bmtlZChzdGFydEhlaWdodD86IG51bWJlciwgZW5kSGVpZ2h0PzogbnVtYmVyLCBtYXhDaHVua1NpemU/OiBudW1iZXIpOiBQcm9taXNlPE1vbmVyb0Jsb2NrW10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBibG9jayBoYXNoZXMgYXMgYSBiaW5hcnkgcmVxdWVzdCB0byB0aGUgZGFlbW9uLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gYmxvY2tIYXNoZXMgLSBzcGVjaWZ5IGJsb2NrIGhhc2hlcyB0byBmZXRjaDsgZmlyc3QgMTAgYmxvY2tzIGhhc2ggZ29lc1xuICAgKiAgICAgICAgc2VxdWVudGlhbCwgbmV4dCBnb2VzIGluIHBvdygyLG4pIG9mZnNldCwgbGlrZSAyLCA0LCA4LCAxNiwgMzIsIDY0XG4gICAqICAgICAgICBhbmQgc28gb24sIGFuZCB0aGUgbGFzdCBvbmUgaXMgYWx3YXlzIGdlbmVzaXMgYmxvY2tcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXJ0SGVpZ2h0IC0gc3RhcnRpbmcgaGVpZ2h0IG9mIGJsb2NrIGhhc2hlcyB0byByZXR1cm5cbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmdbXT59IHJlcXVlc3RlZCBibG9jayBoYXNoZXMgICAgIFxuICAgKi9cbiAgYXN5bmMgZ2V0QmxvY2tIYXNoZXMoYmxvY2tIYXNoZXM6IHN0cmluZ1tdLCBzdGFydEhlaWdodDogbnVtYmVyKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGEgdHJhbnNhY3Rpb24gYnkgaGFzaC5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0eEhhc2ggLSBoYXNoIG9mIHRoZSB0cmFuc2FjdGlvbiB0byBnZXRcbiAgICogQHBhcmFtIHtib29sZWFufSBbcHJ1bmVdIC0gc3BlY2lmaWVzIGlmIHRoZSByZXR1cm5lZCB0eCBzaG91bGQgYmUgcHJ1bmVkIChkZWZhdWx0cyB0byBmYWxzZSlcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9UeD59IHRyYW5zYWN0aW9uIHdpdGggdGhlIGdpdmVuIGhhc2ggb3IgdW5kZWZpbmVkIGlmIG5vdCBmb3VuZFxuICAgKi9cbiAgYXN5bmMgZ2V0VHgodHhIYXNoPzogc3RyaW5nLCBwcnVuZSA9IGZhbHNlKTogUHJvbWlzZTxNb25lcm9UeHx1bmRlZmluZWQ+IHtcbiAgICByZXR1cm4gKGF3YWl0IHRoaXMuZ2V0VHhzKFt0eEhhc2hdLCBwcnVuZSkpWzBdO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRyYW5zYWN0aW9ucyBieSBoYXNoZXMuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSB0eEhhc2hlcyAtIGhhc2hlcyBvZiB0cmFuc2FjdGlvbnMgdG8gZ2V0XG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3BydW5lXSAtIHNwZWNpZmllcyBpZiB0aGUgcmV0dXJuZWQgdHhzIHNob3VsZCBiZSBwcnVuZWQgKGRlZmF1bHRzIHRvIGZhbHNlKVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb1R4W10+fSBmb3VuZCB0cmFuc2FjdGlvbnMgd2l0aCB0aGUgZ2l2ZW4gaGFzaGVzXG4gICAqL1xuICBhc3luYyBnZXRUeHModHhIYXNoZXM6IHN0cmluZ1tdLCBwcnVuZSA9IGZhbHNlKTogUHJvbWlzZTxNb25lcm9UeFtdPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgYSB0cmFuc2FjdGlvbiBoZXggYnkgaGFzaC5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0eEhhc2ggLSBoYXNoIG9mIHRoZSB0cmFuc2FjdGlvbiB0byBnZXQgaGV4IGZyb21cbiAgICogQHBhcmFtIHtib29sZWFufSBbcHJ1bmVdIC0gc3BlY2lmaWVzIGlmIHRoZSByZXR1cm5lZCB0eCBoZXggc2hvdWxkIGJlIHBydW5lZCAoZGVmYXVsdHMgdG8gZmFsc2UpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nPn0gdHggaGV4IHdpdGggdGhlIGdpdmVuIGhhc2hcbiAgICovXG4gIGFzeW5jIGdldFR4SGV4KHR4SGFzaDogc3RyaW5nLCBwcnVuZSA9IGZhbHNlKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gKGF3YWl0IHRoaXMuZ2V0VHhIZXhlcyhbdHhIYXNoXSwgcHJ1bmUpKVswXTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0cmFuc2FjdGlvbiBoZXhlcyBieSBoYXNoZXMuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSB0eEhhc2hlcyAtIGhhc2hlcyBvZiB0cmFuc2FjdGlvbnMgdG8gZ2V0IGhleGVzIGZyb21cbiAgICogQHBhcmFtIHtib29sZWFufSBbcHJ1bmVdIC0gc3BlY2lmaWVzIGlmIHRoZSByZXR1cm5lZCB0eCBoZXhlcyBzaG91bGQgYmUgcHJ1bmVkIChkZWZhdWx0cyB0byBmYWxzZSlcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmdbXT59IHR4IGhleGVzXG4gICAqL1xuICBhc3luYyBnZXRUeEhleGVzKHR4SGFzaGVzOiBzdHJpbmdbXSwgcHJ1bmUgPSBmYWxzZSk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldHMgdGhlIHRvdGFsIGVtaXNzaW9ucyBhbmQgZmVlcyBmcm9tIHRoZSBnZW5lc2lzIGJsb2NrIHRvIHRoZSBjdXJyZW50IGhlaWdodC5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBoZWlnaHQgdG8gc3RhcnQgY29tcHV0aW5nIHRoZSBtaW5lciBzdW1cbiAgICogQHBhcmFtIHtudW1iZXJ9IG51bUJsb2NrcyAtIG51bWJlciBvZiBibG9ja3MgdG8gaW5jbHVkZSBpbiB0aGUgc3VtXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvTWluZXJUeFN1bT59IGVuY2Fwc3VsYXRlcyB0aGUgdG90YWwgZW1pc3Npb25zIGFuZCBmZWVzIHNpbmNlIHRoZSBnZW5lc2lzIGJsb2NrXG4gICAqL1xuICBhc3luYyBnZXRNaW5lclR4U3VtKGhlaWdodDogbnVtYmVyLCBudW1CbG9ja3M6IG51bWJlcik6IFByb21pc2U8TW9uZXJvTWluZXJUeFN1bT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IG1pbmluZyBmZWUgZXN0aW1hdGVzIHBlciBrQi5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBncmFjZUJsb2NrcyBUT0RPXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvRmVlRXN0aW1hdGU+fSBtaW5pbmcgZmVlIGVzdGltYXRlcyBwZXIga0JcbiAgICovXG4gIGFzeW5jIGdldEZlZUVzdGltYXRlKGdyYWNlQmxvY2tzPzogbnVtYmVyKTogUHJvbWlzZTxNb25lcm9GZWVFc3RpbWF0ZT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogU3VibWl0cyBhIHRyYW5zYWN0aW9uIHRvIHRoZSBkYWVtb24ncyBwb29sLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHR4SGV4IC0gcmF3IHRyYW5zYWN0aW9uIGhleCB0byBzdWJtaXRcbiAgICogQHBhcmFtIHtib29sZWFufSBkb05vdFJlbGF5IHNwZWNpZmllcyBpZiB0aGUgdHggc2hvdWxkIGJlIHJlbGF5ZWQgKGRlZmF1bHQgZmFsc2UsIGkuZS4gcmVsYXkpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvU3VibWl0VHhSZXN1bHQ+fSBjb250YWlucyBzdWJtaXNzaW9uIHJlc3VsdHNcbiAgICovXG4gIGFzeW5jIHN1Ym1pdFR4SGV4KHR4SGV4OiBzdHJpbmcsIGRvTm90UmVsYXkgPSBmYWxzZSk6IFByb21pc2U8TW9uZXJvU3VibWl0VHhSZXN1bHQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJlbGF5cyBhIHRyYW5zYWN0aW9uIGJ5IGhhc2guXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHhIYXNoIC0gaGFzaCBvZiB0aGUgdHJhbnNhY3Rpb24gdG8gcmVsYXlcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHJlbGF5VHhCeUhhc2godHhIYXNoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhc3NlcnQuZXF1YWwodHlwZW9mIHR4SGFzaCwgXCJzdHJpbmdcIiwgXCJNdXN0IHByb3ZpZGUgYSB0cmFuc2FjdGlvbiBoYXNoXCIpO1xuICAgIGF3YWl0IHRoaXMucmVsYXlUeHNCeUhhc2goW3R4SGFzaF0pO1xuICB9XG4gIFxuICAvKipcbiAgICogUmVsYXlzIHRyYW5zYWN0aW9ucyBieSBoYXNoLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gdHhIYXNoZXMgLSBoYXNoZXMgb2YgdGhlIHRyYW5zYWN0aW5vcyB0byByZWxheVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgcmVsYXlUeHNCeUhhc2godHhIYXNoZXM6IHN0cmluZ1tdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHZhbGlkIHRyYW5zYWN0aW9ucyBzZWVuIGJ5IHRoZSBub2RlIGJ1dCBub3QgeWV0IG1pbmVkIGludG8gYSBibG9jaywgYXMgd2VsbFxuICAgKiBhcyBzcGVudCBrZXkgaW1hZ2UgaW5mb3JtYXRpb24gZm9yIHRoZSB0eCBwb29sLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9UeFtdPn0gYXJlIHRyYW5zYWN0aW9ucyBpbiB0aGUgdHJhbnNhY3Rpb24gcG9vbCFcbiAgICovXG4gIGFzeW5jIGdldFR4UG9vbCgpOiBQcm9taXNlPE1vbmVyb1R4W10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBoYXNoZXMgb2YgdHJhbnNhY3Rpb25zIGluIHRoZSB0cmFuc2FjdGlvbiBwb29sLlxuICAgKiBcbiAgICogQHJldHVybiB7c3RyaW5nW119IGFyZSBoYXNoZXMgb2YgdHJhbnNhY3Rpb25zIGluIHRoZSB0cmFuc2FjdGlvbiBwb29sXG4gICAqL1xuICBhc3luYyBnZXRUeFBvb2xIYXNoZXMoKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvLyAvKipcbiAgLy8gICogR2V0IGFsbCB0cmFuc2FjdGlvbiBwb29sIGJhY2tsb2cuXG4gIC8vICAqIFxuICAvLyAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb1R4QmFja2xvZ0VudHJ5W10+fSBiYWNrbG9nIGVudHJpZXMgXG4gIC8vICAqL1xuICAvLyBhc3luYyBnZXRUeFBvb2xCYWNrbG9nKCk6IFByb21pc2U8TW9uZXJvVHhCYWNrbG9nRW50cnlbXT4ge1xuICAvLyAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICAvLyB9XG4gIFxuICAvKipcbiAgICogR2V0IHRyYW5zYWN0aW9uIHBvb2wgc3RhdGlzdGljcy5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvVHhQb29sU3RhdHM+fSBjb250YWlucyBzdGF0aXN0aWNzIGFib3V0IHRoZSB0cmFuc2FjdGlvbiBwb29sXG4gICAqL1xuICBhc3luYyBnZXRUeFBvb2xTdGF0cygpOiBQcm9taXNlPE1vbmVyb1R4UG9vbFN0YXRzPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBGbHVzaCB0cmFuc2FjdGlvbnMgZnJvbSB0aGUgdHggcG9vbC5cbiAgICogXG4gICAqIEBwYXJhbSB7KHN0cmluZyB8IHN0cmluZ1tdKX0gW2hhc2hlc10gLSBzcGVjaWZpYyB0cmFuc2FjdGlvbnMgdG8gZmx1c2ggKGRlZmF1bHRzIHRvIGFsbClcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIGZsdXNoVHhQb29sKGhhc2hlcz86IHN0cmluZyB8IHN0cmluZ1tdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIHNwZW50IHN0YXR1cyBvZiB0aGUgZ2l2ZW4ga2V5IGltYWdlLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleUltYWdlIC0ga2V5IGltYWdlIGhleCB0byBnZXQgdGhlIHN0YXR1cyBvZlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb0tleUltYWdlU3BlbnRTdGF0dXM+fSBzdGF0dXMgb2YgdGhlIGtleSBpbWFnZVxuICAgKi9cbiAgYXN5bmMgZ2V0S2V5SW1hZ2VTcGVudFN0YXR1cyhrZXlJbWFnZTogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9LZXlJbWFnZVNwZW50U3RhdHVzPiB7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLmdldEtleUltYWdlU3BlbnRTdGF0dXNlcyhba2V5SW1hZ2VdKSlbMF07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIHNwZW50IHN0YXR1cyBvZiBlYWNoIGdpdmVuIGtleSBpbWFnZS5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IGtleUltYWdlcyBhcmUgaGV4IGtleSBpbWFnZXMgdG8gZ2V0IHRoZSBzdGF0dXNlcyBvZlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb0tleUltYWdlU3BlbnRTdGF0dXNbXT59IHN0YXR1cyBmb3IgZWFjaCBrZXkgaW1hZ2VcbiAgICovXG4gIGFzeW5jIGdldEtleUltYWdlU3BlbnRTdGF0dXNlcyhrZXlJbWFnZXM6IHN0cmluZ1tdKTogUHJvbWlzZTxNb25lcm9LZXlJbWFnZVNwZW50U3RhdHVzW10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBvdXRwdXRzIGlkZW50aWZpZWQgYnkgYSBsaXN0IG9mIG91dHB1dCBhbW91bnRzIGFuZCBpbmRpY2VzIGFzIGEgYmluYXJ5XG4gICAqIHJlcXVlc3QuXG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb091dHB1dFtdfSBvdXRwdXRzIC0gaWRlbnRpZnkgZWFjaCBvdXRwdXQgYnkgYW1vdW50IGFuZCBpbmRleFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb091dHB1dFtdPn0gaWRlbnRpZmllZCBvdXRwdXRzXG4gICAqL1xuICBhc3luYyBnZXRPdXRwdXRzKG91dHB1dHM6IE1vbmVyb091dHB1dFtdKTogUHJvbWlzZTxNb25lcm9PdXRwdXRbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGEgaGlzdG9ncmFtIG9mIG91dHB1dCBhbW91bnRzLiBGb3IgYWxsIGFtb3VudHMgKHBvc3NpYmx5IGZpbHRlcmVkIGJ5XG4gICAqIHBhcmFtZXRlcnMpLCBnaXZlcyB0aGUgbnVtYmVyIG9mIG91dHB1dHMgb24gdGhlIGNoYWluIGZvciB0aGF0IGFtb3VudC5cbiAgICogUmluZ0NUIG91dHB1dHMgY291bnRzIGFzIDAgYW1vdW50LlxuICAgKiBcbiAgICogQHBhcmFtIHtiaWdpbnRbXX0gW2Ftb3VudHNdIC0gYW1vdW50cyBvZiBvdXRwdXRzIHRvIG1ha2UgdGhlIGhpc3RvZ3JhbSB3aXRoXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbbWluQ291bnRdIC0gVE9ET1xuICAgKiBAcGFyYW0ge251bWJlcn0gW21heENvdW50XSAtIFRPRE9cbiAgICogQHBhcmFtIHtib29sZWFufSBbaXNVbmxvY2tlZF0gLSBtYWtlcyBhIGhpc3RvZ3JhbSB3aXRoIG91dHB1dHMgd2l0aCB0aGUgc3BlY2lmaWVkIGxvY2sgc3RhdGVcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtyZWNlbnRDdXRvZmZdIC0gVE9ET1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb091dHB1dEhpc3RvZ3JhbUVudHJ5W10+fSBhcmUgZW50cmllcyBtZWV0aW5nIHRoZSBwYXJhbWV0ZXJzXG4gICAqL1xuICBhc3luYyBnZXRPdXRwdXRIaXN0b2dyYW0oYW1vdW50cz86IGJpZ2ludFtdLCBtaW5Db3VudD86IG51bWJlciwgbWF4Q291bnQ/OiBudW1iZXIsIGlzVW5sb2NrZWQ/OiBib29sZWFuLCByZWNlbnRDdXRvZmY/OiBudW1iZXIpOiBQcm9taXNlPE1vbmVyb091dHB1dEhpc3RvZ3JhbUVudHJ5W10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLy8gLyoqXG4gIC8vICAqIENyZWF0ZXMgYW4gb3V0cHV0IGRpc3RyaWJ1dGlvbi5cbiAgLy8gICogXG4gIC8vICAqIEBwYXJhbSB7YmlnaW50W119IGFtb3VudHMgLSBhbW91bnRzIG9mIG91dHB1dHMgdG8gbWFrZSB0aGUgZGlzdHJpYnV0aW9uIHdpdGhcbiAgLy8gICogQHBhcmFtIHtib29sZWFufSBbY3VtdWxhdGl2ZV0gLSBzcGVjaWZpZXMgaWYgdGhlIHJlc3VsdHMgc2hvdWxkIGJlIGN1bXVsYXRpdmUgKGRlZmF1bHRzIHRvIFRPRE8pXG4gIC8vICAqIEBwYXJhbSB7bnVtYmVyfSBbc3RhcnRIZWlnaHRdIC0gc3RhcnQgaGVpZ2h0IGxvd2VyIGJvdW5kIGluY2x1c2l2ZSAob3B0aW9uYWwpXG4gIC8vICAqIEBwYXJhbSB7bnVtYmVyfSBbZW5kSGVpZ2h0XSAtIGVuZCBoZWlnaHQgdXBwZXIgYm91bmQgaW5jbHVzaXZlIChvcHRpb25hbClcbiAgLy8gICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9PdXRwdXREaXN0cmlidXRpb25FbnRyeVtdPn0gYXJlIGVudHJpZXMgbWVldGluZyB0aGUgcGFyYW1ldGVyc1xuICAvLyAgKi9cbiAgLy8gYXN5bmMgZ2V0T3V0cHV0RGlzdHJpYnV0aW9uKGFtb3VudHM6IGJpZ2ludFtdLCBjdW11bGF0aXZlPzogYm9vbGVhbiwgc3RhcnRIZWlnaHQ/OiBudW1iZXIsIGVuZEhlaWdodD86IG51bWJlcik6IFByb21pc2U8TW9uZXJvT3V0cHV0RGlzdHJpYnV0aW9uRW50cnlbXT4ge1xuICAvLyAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICAvLyB9XG4gIFxuICAvKipcbiAgICogR2V0IGdlbmVyYWwgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHN0YXRlIG9mIHRoZSBub2RlIGFuZCB0aGUgbmV0d29yay5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvRGFlbW9uSW5mbz59IGlzIGdlbmVyYWwgaW5mb3JtYXRpb24gYWJvdXQgdGhlIG5vZGUgYW5kIG5ldHdvcmtcbiAgICovXG4gIGFzeW5jIGdldEluZm8oKTogUHJvbWlzZTxNb25lcm9EYWVtb25JbmZvPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgc3luY2hyb25pemF0aW9uIGluZm9ybWF0aW9uLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9EYWVtb25TeW5jSW5mbz59IGNvbnRhaW5zIHN5bmMgaW5mb3JtYXRpb25cbiAgICovXG4gIGFzeW5jIGdldFN5bmNJbmZvKCk6IFByb21pc2U8TW9uZXJvRGFlbW9uU3luY0luZm8+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIExvb2sgdXAgaW5mb3JtYXRpb24gcmVnYXJkaW5nIGhhcmQgZm9yayB2b3RpbmcgYW5kIHJlYWRpbmVzcy5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvSGFyZEZvcmtJbmZvPiB9IGNvbnRhaW5zIGhhcmQgZm9yayBpbmZvcm1hdGlvblxuICAgKi9cbiAgYXN5bmMgZ2V0SGFyZEZvcmtJbmZvKCk6IFByb21pc2U8TW9uZXJvSGFyZEZvcmtJbmZvPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgYWx0ZXJuYXRpdmUgY2hhaW5zIHNlZW4gYnkgdGhlIG5vZGUuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb0FsdENoYWluW10+fSBhbHRlcm5hdGl2ZSBjaGFpbnNcbiAgICovXG4gIGFzeW5jIGdldEFsdENoYWlucygpOiBQcm9taXNlPE1vbmVyb0FsdENoYWluW10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBrbm93biBibG9jayBoYXNoZXMgd2hpY2ggYXJlIG5vdCBvbiB0aGUgbWFpbiBjaGFpbi5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nW10+fSBrbm93biBibG9jayBoYXNoZXMgd2hpY2ggYXJlIG5vdCBvbiB0aGUgbWFpbiBjaGFpblxuICAgKi9cbiAgYXN5bmMgZ2V0QWx0QmxvY2tIYXNoZXMoKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSBkb3dubG9hZCBiYW5kd2lkdGggbGltaXQuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPG51bWJlcj59IGRvd25sb2FkIGJhbmR3aWR0aCBsaW1pdFxuICAgKi9cbiAgYXN5bmMgZ2V0RG93bmxvYWRMaW1pdCgpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogU2V0IHRoZSBkb3dubG9hZCBiYW5kd2lkdGggbGltaXQuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gbGltaXQgLSBkb3dubG9hZCBsaW1pdCB0byBzZXQgKC0xIHRvIHJlc2V0IHRvIGRlZmF1bHQpXG4gICAqIEByZXR1cm4ge251bWJlcn0gbmV3IGRvd25sb2FkIGxpbWl0IGFmdGVyIHNldHRpbmdcbiAgICovXG4gIGFzeW5jIHNldERvd25sb2FkTGltaXQobGltaXQ6IG51bWJlcik6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXNldCB0aGUgZG93bmxvYWQgYmFuZHdpZHRoIGxpbWl0LlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxudW1iZXI+fSBkb3dubG9hZCBiYW5kd2lkdGggbGltaXQgYWZ0ZXIgcmVzZXR0aW5nXG4gICAqL1xuICBhc3luYyByZXNldERvd25sb2FkTGltaXQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgdXBsb2FkIGJhbmR3aWR0aCBsaW1pdC5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8bnVtYmVyPn0gdXBsb2FkIGJhbmR3aWR0aCBsaW1pdFxuICAgKi9cbiAgYXN5bmMgZ2V0VXBsb2FkTGltaXQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFNldCB0aGUgdXBsb2FkIGJhbmR3aWR0aCBsaW1pdC5cbiAgICogXG4gICAqIEBwYXJhbSBsaW1pdCAtIHVwbG9hZCBsaW1pdCB0byBzZXQgKC0xIHRvIHJlc2V0IHRvIGRlZmF1bHQpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8bnVtYmVyPn0gbmV3IHVwbG9hZCBsaW1pdCBhZnRlciBzZXR0aW5nXG4gICAqL1xuICBhc3luYyBzZXRVcGxvYWRMaW1pdChsaW1pdDogbnVtYmVyKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJlc2V0IHRoZSB1cGxvYWQgYmFuZHdpZHRoIGxpbWl0LlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxudW1iZXI+fSB1cGxvYWQgYmFuZHdpZHRoIGxpbWl0IGFmdGVyIHJlc2V0dGluZ1xuICAgKi9cbiAgYXN5bmMgcmVzZXRVcGxvYWRMaW1pdCgpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHBlZXJzIHdpdGggYWN0aXZlIGluY29taW5nIG9yIG91dGdvaW5nIGNvbm5lY3Rpb25zIHRvIHRoZSBub2RlLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9QZWVyW10+fSB0aGUgZGFlbW9uJ3MgcGVlcnNcbiAgICovXG4gIGFzeW5jIGdldFBlZXJzKCk6IFByb21pc2U8TW9uZXJvUGVlcltdPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQga25vd24gcGVlcnMgaW5jbHVkaW5nIHRoZWlyIGxhc3Qga25vd24gb25saW5lIHN0YXR1cy5cbiAgICogXG4gICAqIEByZXR1cm4ge01vbmVyb1BlZXJbXX0gdGhlIGRhZW1vbidzIGtub3duIHBlZXJzXG4gICAqL1xuICBhc3luYyBnZXRLbm93blBlZXJzKCk6IFByb21pc2U8TW9uZXJvUGVlcltdPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBMaW1pdCBudW1iZXIgb2Ygb3V0Z29pbmcgcGVlcnMuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gbGltaXQgLSBtYXhpbXVtIG51bWJlciBvZiBvdXRnb2luZyBwZWVyc1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgc2V0T3V0Z29pbmdQZWVyTGltaXQobGltaXQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogTGltaXQgbnVtYmVyIG9mIGluY29taW5nIHBlZXJzLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IGxpbWl0IC0gbWF4aW11bSBudW1iZXIgb2YgaW5jb21pbmcgcGVlcnNcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHNldEluY29taW5nUGVlckxpbWl0KGxpbWl0OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBwZWVyIGJhbnMuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb0JhbltdPn0gZW50cmllcyBhYm91dCBiYW5uZWQgcGVlcnNcbiAgICovXG4gIGFzeW5jIGdldFBlZXJCYW5zKCk6IFByb21pc2U8TW9uZXJvQmFuW10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBCYW4gYSBwZWVyIG5vZGUuXG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb0Jhbn0gYmFuIC0gY29udGFpbnMgaW5mb3JtYXRpb24gYWJvdXQgYSBub2RlIHRvIGJhblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgc2V0UGVlckJhbihiYW46IE1vbmVyb0Jhbik6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBhd2FpdCB0aGlzLnNldFBlZXJCYW5zKFtiYW5dKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEJhbiBwZWVycyBub2Rlcy5cbiAgICogXG4gICAqIEBwYXJhbSB7TW9uZXJvQmFuW119IGJhbnMgLSBzcGVjaWZ5IHdoaWNoIHBlZXJzIHRvIGJhblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgc2V0UGVlckJhbnMoYmFuczogTW9uZXJvQmFuW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFN0YXJ0IG1pbmluZy5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzIC0gYWRkcmVzcyBnaXZlbiBtaW5lciByZXdhcmRzIGlmIHRoZSBkYWVtb24gbWluZXMgYSBibG9ja1xuICAgKiBAcGFyYW0ge2ludGVnZXJ9IFtudW1UaHJlYWRzXSAtIG51bWJlciBvZiBtaW5pbmcgdGhyZWFkcyB0byBydW4gKGRlZmF1bHQgMSlcbiAgICogQHBhcmFtIHtib29sZWFufSBbaXNCYWNrZ3JvdW5kXSAtIHNwZWNpZmllcyBpZiB0aGUgbWluZXIgc2hvdWxkIHJ1biBpbiB0aGUgYmFja2dyb3VuZCBvciBub3QgKGRlZmF1bHQgZmFsc2UpXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2lnbm9yZUJhdHRlcnldIC0gc3BlY2lmaWVzIGlmIHRoZSBiYXR0ZXJ5IHN0YXRlIChlLmcuIG9uIGxhcHRvcCkgc2hvdWxkIGJlIGlnbm9yZWQgb3Igbm90IChkZWZhdWx0IGZhbHNlKVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgc3RhcnRNaW5pbmcoYWRkcmVzczogc3RyaW5nLCBudW1UaHJlYWRzPzogbnVtYmVyLCBpc0JhY2tncm91bmQ/OiBib29sZWFuLCBpZ25vcmVCYXR0ZXJ5PzogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogU3RvcCBtaW5pbmcuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgc3RvcE1pbmluZygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgZGFlbW9uJ3MgbWluaW5nIHN0YXR1cy5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvTWluaW5nU3RhdHVzPn0gZGFlbW9uJ3MgbWluaW5nIHN0YXR1c1xuICAgKi9cbiAgYXN5bmMgZ2V0TWluaW5nU3RhdHVzKCk6IFByb21pc2U8TW9uZXJvTWluaW5nU3RhdHVzPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTdWJtaXQgYSBtaW5lZCBibG9jayB0byB0aGUgbmV0d29yay5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBibG9ja0Jsb2IgLSBtaW5lZCBibG9jayB0byBzdWJtaXRcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHN1Ym1pdEJsb2NrKGJsb2NrQmxvYjogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5zdWJtaXRCbG9ja3MoW2Jsb2NrQmxvYl0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFBydW5lIHRoZSBibG9ja2NoYWluLlxuICAgKiBcbiAgICogQHBhcmFtIHtib29sZWFufSBjaGVjayBzcGVjaWZpZXMgdG8gY2hlY2sgdGhlIHBydW5pbmcgKGRlZmF1bHQgZmFsc2UpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvUHJ1bmVSZXN1bHQ+fSB0aGUgcHJ1bmUgcmVzdWx0XG4gICAqL1xuICBhc3luYyBwcnVuZUJsb2NrY2hhaW4oY2hlY2s6IGJvb2xlYW4pOiBQcm9taXNlPE1vbmVyb1BydW5lUmVzdWx0PiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTdWJtaXQgbWluZWQgYmxvY2tzIHRvIHRoZSBuZXR3b3JrLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gYmxvY2tCbG9icyAtIG1pbmVkIGJsb2NrcyB0byBzdWJtaXRcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHN1Ym1pdEJsb2NrcyhibG9ja0Jsb2JzOiBzdHJpbmdbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlN1YmNsYXNzIG11c3QgaW1wbGVtZW50XCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogQ2hlY2sgZm9yIHVwZGF0ZS5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvRGFlbW9uVXBkYXRlQ2hlY2tSZXN1bHQ+fSB0aGUgcmVzdWx0XG4gICAqL1xuICBhc3luYyBjaGVja0ZvclVwZGF0ZSgpOiBQcm9taXNlPE1vbmVyb0RhZW1vblVwZGF0ZUNoZWNrUmVzdWx0PiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBEb3dubG9hZCBhbiB1cGRhdGUuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gW3BhdGhdIC0gcGF0aCB0byBkb3dubG9hZCB0aGUgdXBkYXRlIChvcHRpb25hbClcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9EYWVtb25VcGRhdGVEb3dubG9hZFJlc3VsdD59IHRoZSByZXN1bHRcbiAgICovXG4gIGFzeW5jIGRvd25sb2FkVXBkYXRlKHBhdGg/OiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0RhZW1vblVwZGF0ZURvd25sb2FkUmVzdWx0PiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTYWZlbHkgZGlzY29ubmVjdCBhbmQgc2h1dCBkb3duIHRoZSBkYWVtb24uXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgc3RvcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgaGVhZGVyIG9mIHRoZSBuZXh0IGJsb2NrIGFkZGVkIHRvIHRoZSBjaGFpbi5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQmxvY2tIZWFkZXI+fSBoZWFkZXIgb2YgdGhlIG5leHQgYmxvY2sgYWRkZWQgdG8gdGhlIGNoYWluXG4gICAqL1xuICBhc3luYyB3YWl0Rm9yTmV4dEJsb2NrSGVhZGVyKCk6IFByb21pc2U8TW9uZXJvQmxvY2tIZWFkZXI+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJjbGFzcyBtdXN0IGltcGxlbWVudFwiKTtcbiAgfVxu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 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/MoneroDaemonRpc.d.ts b/dist/src/main/ts/daemon/MoneroDaemonRpc.d.ts new file mode 100644 index 000000000..4a663541c --- /dev/null +++ b/dist/src/main/ts/daemon/MoneroDaemonRpc.d.ts @@ -0,0 +1,292 @@ +/// +import MoneroAltChain from "./model/MoneroAltChain"; +import MoneroBan from "./model/MoneroBan"; +import MoneroBlock from "./model/MoneroBlock"; +import MoneroBlockHeader from "./model/MoneroBlockHeader"; +import MoneroBlockTemplate from "./model/MoneroBlockTemplate"; +import MoneroConnectionSpan from "./model/MoneroConnectionSpan"; +import MoneroDaemon from "./MoneroDaemon"; +import MoneroDaemonConfig from "./model/MoneroDaemonConfig"; +import MoneroDaemonInfo from "./model/MoneroDaemonInfo"; +import MoneroDaemonListener from "./model/MoneroDaemonListener"; +import MoneroDaemonSyncInfo from "./model/MoneroDaemonSyncInfo"; +import MoneroDaemonUpdateCheckResult from "./model/MoneroDaemonUpdateCheckResult"; +import MoneroDaemonUpdateDownloadResult from "./model/MoneroDaemonUpdateDownloadResult"; +import MoneroFeeEstimate from "./model/MoneroFeeEstimate"; +import MoneroHardForkInfo from "./model/MoneroHardForkInfo"; +import MoneroKeyImageSpentStatus from "./model/MoneroKeyImageSpentStatus"; +import MoneroMinerTxSum from "./model/MoneroMinerTxSum"; +import MoneroMiningStatus from "./model/MoneroMiningStatus"; +import MoneroOutput from "./model/MoneroOutput"; +import MoneroOutputHistogramEntry from "./model/MoneroOutputHistogramEntry"; +import MoneroPeer from "./model/MoneroPeer"; +import MoneroPruneResult from "./model/MoneroPruneResult"; +import MoneroRpcConnection from "../common/MoneroRpcConnection"; +import MoneroSubmitTxResult from "./model/MoneroSubmitTxResult"; +import MoneroTx from "./model/MoneroTx"; +import MoneroTxPoolStats from "./model/MoneroTxPoolStats"; +import MoneroVersion from "./model/MoneroVersion"; +import { ChildProcess } from "child_process"; +/** + * Copyright (c) woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + * Implements a MoneroDaemon as a client of monerod. + */ +declare class MoneroDaemonRpc extends MoneroDaemon { + protected static readonly MAX_REQ_SIZE = "3000000"; + protected static readonly DEFAULT_ID = "0000000000000000000000000000000000000000000000000000000000000000"; + protected static readonly NUM_HEADERS_PER_REQ = 750; + protected static readonly DEFAULT_POLL_PERIOD = 20000; + protected config: Partial; + protected listeners: MoneroDaemonListener[]; + protected cachedHeaders: any; + protected process: any; + protected pollListener: any; + protected proxyDaemon: any; + /** @private */ + constructor(config: MoneroDaemonConfig, proxyDaemon: MoneroDaemonRpcProxy); + /** + * Get the internal process running monerod. + * + * @return {ChildProcess} the node process running monerod, undefined if not created from new process + */ + getProcess(): ChildProcess; + /** + * Stop the internal process running monerod, if applicable. + * + * @param {boolean} [force] specifies if the process should be destroyed forcibly (default false) + * @return {Promise} the exit code from stopping the process + */ + stopProcess(force?: boolean): Promise; + addListener(listener: MoneroDaemonListener): Promise; + removeListener(listener: MoneroDaemonListener): Promise; + getListeners(): MoneroDaemonListener[]; + /** + * Get the daemon's RPC connection. + * + * @return {MoneroRpcConnection} the daemon's rpc connection + */ + getRpcConnection(): Promise; + isConnected(): Promise; + getVersion(): Promise; + isTrusted(): Promise; + getHeight(): Promise; + getBlockHash(height: number): Promise; + getBlockTemplate(walletAddress: string, reserveSize?: number): Promise; + getLastBlockHeader(): Promise; + getBlockHeaderByHash(blockHash: string): Promise; + getBlockHeaderByHeight(height: number): Promise; + getBlockHeadersByRange(startHeight?: number, endHeight?: number): Promise; + getBlockByHash(blockHash: string): Promise; + getBlockByHeight(height: number): Promise; + getBlocksByHeight(heights: number[]): Promise; + getBlocksByRange(startHeight?: number, endHeight?: number): Promise; + getBlocksByRangeChunked(startHeight?: number, endHeight?: number, maxChunkSize?: number): Promise; + getTxs(txHashes: string[], prune?: boolean): Promise; + getTxHexes(txHashes: string[], prune?: boolean): Promise; + getMinerTxSum(height: number, numBlocks: number): Promise; + getFeeEstimate(graceBlocks?: number): Promise; + submitTxHex(txHex: string, doNotRelay: boolean): Promise; + relayTxsByHash(txHashes: string[]): Promise; + getTxPool(): Promise; + getTxPoolHashes(): Promise; + getTxPoolStats(): Promise; + flushTxPool(hashes?: string | string[]): Promise; + getKeyImageSpentStatuses(keyImages: string[]): Promise; + getOutputHistogram(amounts?: bigint[], minCount?: number, maxCount?: number, isUnlocked?: boolean, recentCutoff?: number): Promise; + getOutputDistribution(amounts: any, cumulative: any, startHeight: any, endHeight: any): Promise; + getInfo(): Promise; + getSyncInfo(): Promise; + getHardForkInfo(): Promise; + getAltChains(): Promise; + getAltBlockHashes(): Promise; + getDownloadLimit(): Promise; + setDownloadLimit(limit: number): Promise; + resetDownloadLimit(): Promise; + getUploadLimit(): Promise; + setUploadLimit(limit: number): Promise; + resetUploadLimit(): Promise; + getPeers(): Promise; + getKnownPeers(): Promise; + setOutgoingPeerLimit(limit: number): Promise; + setIncomingPeerLimit(limit: number): Promise; + getPeerBans(): Promise; + setPeerBans(bans: MoneroBan[]): Promise; + startMining(address: string, numThreads?: number, isBackground?: boolean, ignoreBattery?: boolean): Promise; + stopMining(): Promise; + getMiningStatus(): Promise; + submitBlocks(blockBlobs: string[]): Promise; + pruneBlockchain(check: boolean): Promise; + checkForUpdate(): Promise; + downloadUpdate(path?: string): Promise; + stop(): Promise; + waitForNextBlockHeader(): Promise; + getPollInterval(): number; + getTx(txHash?: string, prune?: boolean): Promise; + getTxHex(txHash: string, prune?: boolean): Promise; + getKeyImageSpentStatus(keyImage: string): Promise; + setPeerBan(ban: MoneroBan): Promise; + submitBlock(blockBlob: string): Promise; + protected refreshListening(): void; + protected getBandwidthLimits(): Promise; + protected setBandwidthLimits(downLimit: any, upLimit: any): Promise; + /** + * Get a contiguous chunk of blocks starting from a given height up to a maximum + * height or amount of block data fetched from the blockchain, whichever comes first. + * + * @param {number} [startHeight] - start height to retrieve blocks (default 0) + * @param {number} [maxHeight] - maximum end height to retrieve blocks (default blockchain height) + * @param {number} [maxReqSize] - maximum amount of block data to fetch from the blockchain in bytes (default 3,000,000 bytes) + * @return {MoneroBlock[]} are the resulting chunk of blocks + */ + protected getMaxBlocks(startHeight: any, maxHeight: any, maxReqSize: any): Promise; + /** + * Retrieves a header by height from the cache or fetches and caches a header + * range if not already in the cache. + * + * @param {number} height - height of the header to retrieve from the cache + * @param {number} maxHeight - maximum height of headers to cache + */ + protected getBlockHeaderByHeightCached(height: any, maxHeight: any): Promise; + static connectToDaemonRpc(uriOrConfig: string | Partial | Partial | string[], username?: string, password?: string): Promise; + protected static startMonerodProcess(config: MoneroDaemonConfig): Promise; + protected static normalizeConfig(uriOrConfig: string | Partial | Partial | string[], username?: string, password?: string): MoneroDaemonConfig; + protected static checkResponseStatus(resp: any): void; + protected static convertRpcBlockHeader(rpcHeader: any): MoneroBlockHeader; + protected static convertRpcBlock(rpcBlock: any): MoneroBlock; + /** + * Transfers RPC tx fields to a given MoneroTx without overwriting previous values. + * + * TODO: switch from safe set + * + * @param rpcTx - RPC map containing transaction fields + * @param tx - MoneroTx to populate with values (optional) + * @return tx - same tx that was passed in or a new one if none given + */ + protected static convertRpcTx(rpcTx: any, tx: any): any; + protected static convertRpcOutput(rpcOutput: any, tx: any): MoneroOutput; + protected static convertRpcBlockTemplate(rpcTemplate: any): MoneroBlockTemplate; + protected static convertRpcInfo(rpcInfo: any): MoneroDaemonInfo; + /** + * Initializes sync info from RPC sync info. + * + * @param rpcSyncInfo - rpc map to initialize the sync info from + * @return {MoneroDaemonSyncInfo} is sync info initialized from the map + */ + protected static convertRpcSyncInfo(rpcSyncInfo: any): MoneroDaemonSyncInfo; + protected static convertRpcHardForkInfo(rpcHardForkInfo: any): MoneroHardForkInfo; + protected static convertRpcConnectionSpan(rpcConnectionSpan: any): MoneroConnectionSpan; + protected static convertRpcOutputHistogramEntry(rpcEntry: any): MoneroOutputHistogramEntry; + protected static convertRpcSubmitTxResult(rpcResult: any): MoneroSubmitTxResult; + protected static convertRpcTxPoolStats(rpcStats: any): MoneroTxPoolStats; + protected static convertRpcAltChain(rpcChain: any): MoneroAltChain; + protected static convertRpcPeer(rpcPeer: any): MoneroPeer; + protected static convertRpcConnection(rpcConnection: any): MoneroPeer; + protected static convertToRpcBan(ban: MoneroBan): any; + protected static convertRpcMiningStatus(rpcStatus: any): MoneroMiningStatus; + protected static convertRpcUpdateCheckResult(rpcResult: any): MoneroDaemonUpdateCheckResult; + protected static convertRpcUpdateDownloadResult(rpcResult: any): MoneroDaemonUpdateDownloadResult; + /** + * Converts a '0x' prefixed hexidecimal string to a bigint. + * + * @param {string} hex is the '0x' prefixed hexidecimal string to convert + * @return {bigint} the hexicedimal converted to decimal + */ + protected static prefixedHexToBI(hex: any): bigint; +} +/** + * Implements a MoneroDaemon by proxying requests to a worker. + * + * @private + */ +declare class MoneroDaemonRpcProxy { + private daemonId; + private worker; + private wrappedListeners; + private process; + constructor(daemonId: any, worker: any); + static connect(config: MoneroDaemonConfig): Promise; + addListener(listener: any): Promise; + removeListener(listener: any): Promise; + getListeners(): Promise; + getRpcConnection(): Promise; + isConnected(): Promise; + getVersion(): Promise; + isTrusted(): Promise; + getHeight(): Promise; + getBlockHash(height: any): Promise; + getBlockTemplate(walletAddress: any, reserveSize: any): Promise; + getLastBlockHeader(): Promise; + getBlockHeaderByHash(blockHash: any): Promise; + getBlockHeaderByHeight(height: any): Promise; + getBlockHeadersByRange(startHeight: any, endHeight: any): Promise; + getBlockByHash(blockHash: any): Promise; + getBlocksByHash(blockHashes: any, startHeight: any, prune: any): Promise; + getBlockByHeight(height: any): Promise; + getBlocksByHeight(heights: any): Promise; + getBlocksByRange(startHeight: any, endHeight: any): Promise; + getBlocksByRangeChunked(startHeight: any, endHeight: any, maxChunkSize: any): Promise; + getBlockHashes(blockHashes: any, startHeight: any): Promise; + getTxs(txHashes: any, prune?: boolean): Promise; + getTxHexes(txHashes: any, prune?: boolean): Promise; + getMinerTxSum(height: any, numBlocks: any): Promise; + getFeeEstimate(graceBlocks?: any): Promise; + submitTxHex(txHex: any, doNotRelay: any): Promise; + relayTxsByHash(txHashes: any): Promise; + getTxPool(): Promise; + getTxPoolHashes(): Promise; + getTxPoolBacklog(): Promise; + getTxPoolStats(): Promise; + flushTxPool(hashes: any): Promise; + getKeyImageSpentStatuses(keyImages: any): Promise; + getOutputs(outputs: any): Promise; + getOutputHistogram(amounts: any, minCount: any, maxCount: any, isUnlocked: any, recentCutoff: any): Promise; + getOutputDistribution(amounts: any, cumulative: any, startHeight: any, endHeight: any): Promise; + getInfo(): Promise; + getSyncInfo(): Promise; + getHardForkInfo(): Promise; + getAltChains(): Promise; + getAltBlockHashes(): Promise; + getDownloadLimit(): Promise; + setDownloadLimit(limit: any): Promise; + resetDownloadLimit(): Promise; + getUploadLimit(): Promise; + setUploadLimit(limit: any): Promise; + resetUploadLimit(): Promise; + getPeers(): Promise; + getKnownPeers(): Promise; + setOutgoingPeerLimit(limit: any): Promise; + setIncomingPeerLimit(limit: any): Promise; + getPeerBans(): Promise; + setPeerBans(bans: any): Promise; + startMining(address: any, numThreads: any, isBackground: any, ignoreBattery: any): Promise; + stopMining(): Promise; + getMiningStatus(): Promise; + submitBlocks(blockBlobs: any): Promise; + pruneBlockchain(check: any): Promise; + checkForUpdate(): Promise; + downloadUpdate(path: any): Promise; + stop(): Promise; + waitForNextBlockHeader(): Promise; + protected invokeWorker(fnName: string, args?: any): Promise; +} +export default MoneroDaemonRpc; diff --git a/dist/src/main/ts/daemon/MoneroDaemonRpc.js b/dist/src/main/ts/daemon/MoneroDaemonRpc.js new file mode 100644 index 000000000..0be3b2993 --- /dev/null +++ b/dist/src/main/ts/daemon/MoneroDaemonRpc.js @@ -0,0 +1,1959 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../common/GenUtils")); +var _LibraryUtils = _interopRequireDefault(require("../common/LibraryUtils")); +var _TaskLooper = _interopRequireDefault(require("../common/TaskLooper")); +var _MoneroAltChain = _interopRequireDefault(require("./model/MoneroAltChain")); +var _MoneroBan = _interopRequireDefault(require("./model/MoneroBan")); +var _MoneroBlock = _interopRequireDefault(require("./model/MoneroBlock")); +var _MoneroBlockHeader = _interopRequireDefault(require("./model/MoneroBlockHeader")); +var _MoneroBlockTemplate = _interopRequireDefault(require("./model/MoneroBlockTemplate")); +var _MoneroConnectionSpan = _interopRequireDefault(require("./model/MoneroConnectionSpan")); +var _MoneroDaemon = _interopRequireDefault(require("./MoneroDaemon")); +var _MoneroDaemonConfig = _interopRequireDefault(require("./model/MoneroDaemonConfig")); +var _MoneroDaemonInfo = _interopRequireDefault(require("./model/MoneroDaemonInfo")); +var _MoneroDaemonListener = _interopRequireDefault(require("./model/MoneroDaemonListener")); +var _MoneroDaemonSyncInfo = _interopRequireDefault(require("./model/MoneroDaemonSyncInfo")); +var _MoneroDaemonUpdateCheckResult = _interopRequireDefault(require("./model/MoneroDaemonUpdateCheckResult")); +var _MoneroDaemonUpdateDownloadResult = _interopRequireDefault(require("./model/MoneroDaemonUpdateDownloadResult")); +var _MoneroFeeEstimate = _interopRequireDefault(require("./model/MoneroFeeEstimate")); +var _MoneroError = _interopRequireDefault(require("../common/MoneroError")); +var _MoneroHardForkInfo = _interopRequireDefault(require("./model/MoneroHardForkInfo")); +var _MoneroKeyImage = _interopRequireDefault(require("./model/MoneroKeyImage")); + +var _MoneroMinerTxSum = _interopRequireDefault(require("./model/MoneroMinerTxSum")); +var _MoneroMiningStatus = _interopRequireDefault(require("./model/MoneroMiningStatus")); +var _MoneroNetworkType = _interopRequireDefault(require("./model/MoneroNetworkType")); +var _MoneroOutput = _interopRequireDefault(require("./model/MoneroOutput")); +var _MoneroOutputHistogramEntry = _interopRequireDefault(require("./model/MoneroOutputHistogramEntry")); +var _MoneroPeer = _interopRequireDefault(require("./model/MoneroPeer")); +var _MoneroPruneResult = _interopRequireDefault(require("./model/MoneroPruneResult")); +var _MoneroRpcConnection = _interopRequireDefault(require("../common/MoneroRpcConnection")); +var _MoneroSubmitTxResult = _interopRequireDefault(require("./model/MoneroSubmitTxResult")); +var _MoneroTx = _interopRequireDefault(require("./model/MoneroTx")); +var _MoneroTxPoolStats = _interopRequireDefault(require("./model/MoneroTxPoolStats")); +var _MoneroUtils = _interopRequireDefault(require("../common/MoneroUtils")); +var _MoneroVersion = _interopRequireDefault(require("./model/MoneroVersion")); + + +/** + * Copyright (c) woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Implements a MoneroDaemon as a client of monerod. + */ +class MoneroDaemonRpc extends _MoneroDaemon.default { + + // static variables + static MAX_REQ_SIZE = "3000000"; + static DEFAULT_ID = "0000000000000000000000000000000000000000000000000000000000000000"; // uninitialized tx or block hash from daemon rpc + static NUM_HEADERS_PER_REQ = 750; // number of headers to fetch and cache per request + static DEFAULT_POLL_PERIOD = 20000; // default interval between polling the daemon in ms + + // instance variables + + + + + + + + /** @private */ + constructor(config, proxyDaemon) { + super(); + this.config = config; + this.proxyDaemon = proxyDaemon; + if (config.proxyToWorker) return; + this.listeners = []; // block listeners + this.cachedHeaders = {}; // cached headers for fetching blocks in bound chunks + } + + /** + * Get the internal process running monerod. + * + * @return {ChildProcess} the node process running monerod, undefined if not created from new process + */ + getProcess() { + return this.process; + } + + /** + * Stop the internal process running monerod, if applicable. + * + * @param {boolean} [force] specifies if the process should be destroyed forcibly (default false) + * @return {Promise} the exit code from stopping the process + */ + async stopProcess(force = false) { + if (this.process === undefined) throw new _MoneroError.default("MoneroDaemonRpc instance not created from new process"); + let listenersCopy = _GenUtils.default.copyArray(await this.getListeners()); + for (let listener of listenersCopy) await this.removeListener(listener); + return _GenUtils.default.killProcess(this.process, force ? "SIGKILL" : undefined); + } + + async addListener(listener) { + if (this.config.proxyToWorker) return this.proxyDaemon.addListener(listener); + (0, _assert.default)(listener instanceof _MoneroDaemonListener.default, "Listener must be instance of MoneroDaemonListener"); + this.listeners.push(listener); + this.refreshListening(); + } + + async removeListener(listener) { + if (this.config.proxyToWorker) return this.proxyDaemon.removeListener(listener); + (0, _assert.default)(listener instanceof _MoneroDaemonListener.default, "Listener must be instance of MoneroDaemonListener"); + let idx = this.listeners.indexOf(listener); + if (idx > -1) this.listeners.splice(idx, 1);else + throw new _MoneroError.default("Listener is not registered with daemon"); + this.refreshListening(); + } + + getListeners() { + if (this.config.proxyToWorker) return this.proxyDaemon.getListeners(); + return this.listeners; + } + + /** + * Get the daemon's RPC connection. + * + * @return {MoneroRpcConnection} the daemon's rpc connection + */ + async getRpcConnection() { + if (this.config.proxyToWorker) return this.proxyDaemon.getRpcConnection(); + return this.config.getServer(); + } + + async isConnected() { + if (this.config.proxyToWorker) return this.proxyDaemon.isConnected(); + try { + await this.getVersion(); + return true; + } catch (e) { + return false; + } + } + + async getVersion() { + if (this.config.proxyToWorker) return this.proxyDaemon.getVersion(); + let resp = await this.config.getServer().sendJsonRequest("get_version"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return new _MoneroVersion.default(resp.result.version, resp.result.release); + } + + async isTrusted() { + if (this.config.proxyToWorker) return this.proxyDaemon.isTrusted(); + let resp = await this.config.getServer().sendPathRequest("get_height"); + MoneroDaemonRpc.checkResponseStatus(resp); + return !resp.untrusted; + } + + async getHeight() { + if (this.config.proxyToWorker) return this.proxyDaemon.getHeight(); + let resp = await this.config.getServer().sendJsonRequest("get_block_count"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return resp.result.count; + } + + async getBlockHash(height) { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockHash(height); + return (await this.config.getServer().sendJsonRequest("on_get_block_hash", [height])).result; // TODO monero-wallet-rpc: no status returned + } + + async getBlockTemplate(walletAddress, reserveSize) { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockTemplate(walletAddress, reserveSize); + (0, _assert.default)(walletAddress && typeof walletAddress === "string", "Must specify wallet address to be mined to"); + let resp = await this.config.getServer().sendJsonRequest("get_block_template", { wallet_address: walletAddress, reserve_size: reserveSize }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcBlockTemplate(resp.result); + } + + async getLastBlockHeader() { + if (this.config.proxyToWorker) return this.proxyDaemon.getLastBlockHeader(); + let resp = await this.config.getServer().sendJsonRequest("get_last_block_header"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcBlockHeader(resp.result.block_header); + } + + async getBlockHeaderByHash(blockHash) { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockHeaderByHash(blockHash); + let resp = await this.config.getServer().sendJsonRequest("get_block_header_by_hash", { hash: blockHash }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcBlockHeader(resp.result.block_header); + } + + async getBlockHeaderByHeight(height) { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockHeaderByHeight(height); + let resp = await this.config.getServer().sendJsonRequest("get_block_header_by_height", { height: height }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcBlockHeader(resp.result.block_header); + } + + async getBlockHeadersByRange(startHeight, endHeight) { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockHeadersByRange(startHeight, endHeight); + + // fetch block headers + let resp = await this.config.getServer().sendJsonRequest("get_block_headers_range", { + start_height: startHeight, + end_height: endHeight + }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + + // build headers + let headers = []; + for (let rpcHeader of resp.result.headers) { + headers.push(MoneroDaemonRpc.convertRpcBlockHeader(rpcHeader)); + } + return headers; + } + + async getBlockByHash(blockHash) { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockByHash(blockHash); + let resp = await this.config.getServer().sendJsonRequest("get_block", { hash: blockHash }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcBlock(resp.result); + } + + async getBlockByHeight(height) { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockByHeight(height); + let resp = await this.config.getServer().sendJsonRequest("get_block", { height: height }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcBlock(resp.result); + } + + async getBlocksByHeight(heights) { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlocksByHeight(heights); + + // fetch blocks in binary + let respBin = await this.config.getServer().sendBinaryRequest("get_blocks_by_height.bin", { heights: heights }); + + // convert binary blocks to json + let rpcBlocks = await _MoneroUtils.default.binaryBlocksToJson(respBin); + MoneroDaemonRpc.checkResponseStatus(rpcBlocks); + + // build blocks with transactions + _assert.default.equal(rpcBlocks.txs.length, rpcBlocks.blocks.length); + let blocks = []; + for (let blockIdx = 0; blockIdx < rpcBlocks.blocks.length; blockIdx++) { + + // build block + let block = MoneroDaemonRpc.convertRpcBlock(rpcBlocks.blocks[blockIdx]); + block.setHeight(heights[blockIdx]); + blocks.push(block); + + // build transactions + let txs = []; + for (let txIdx = 0; txIdx < rpcBlocks.txs[blockIdx].length; txIdx++) { + let tx = new _MoneroTx.default(); + txs.push(tx); + tx.setHash(rpcBlocks.blocks[blockIdx].tx_hashes[txIdx]); + tx.setIsConfirmed(true); + tx.setInTxPool(false); + tx.setIsMinerTx(false); + tx.setRelay(true); + tx.setIsRelayed(true); + tx.setIsFailed(false); + tx.setIsDoubleSpendSeen(false); + MoneroDaemonRpc.convertRpcTx(rpcBlocks.txs[blockIdx][txIdx], tx); + } + + // merge into one block + block.setTxs([]); + for (let tx of txs) { + if (tx.getBlock()) block.merge(tx.getBlock());else + block.getTxs().push(tx.setBlock(block)); + } + } + + return blocks; + } + + async getBlocksByRange(startHeight, endHeight) { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlocksByRange(startHeight, endHeight); + if (startHeight === undefined) startHeight = 0; + if (endHeight === undefined) endHeight = (await this.getHeight()) - 1; + let heights = []; + for (let height = startHeight; height <= endHeight; height++) heights.push(height); + return await this.getBlocksByHeight(heights); + } + + async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize); + if (startHeight === undefined) startHeight = 0; + if (endHeight === undefined) endHeight = (await this.getHeight()) - 1; + let lastHeight = startHeight - 1; + let blocks = []; + while (lastHeight < endHeight) { + for (let block of await this.getMaxBlocks(lastHeight + 1, endHeight, maxChunkSize)) { + blocks.push(block); + } + lastHeight = blocks[blocks.length - 1].getHeight(); + } + return blocks; + } + + async getTxs(txHashes, prune = false) { + if (this.config.proxyToWorker) return this.proxyDaemon.getTxs(txHashes, prune); + + // validate input + (0, _assert.default)(Array.isArray(txHashes) && txHashes.length > 0, "Must provide an array of transaction hashes"); + (0, _assert.default)(prune === undefined || typeof prune === "boolean", "Prune must be a boolean or undefined"); + + // fetch transactions + let resp = await this.config.getServer().sendPathRequest("get_transactions", { + txs_hashes: txHashes, + decode_as_json: true, + prune: prune + }); + try { + MoneroDaemonRpc.checkResponseStatus(resp); + } catch (e) { + if (e.message.indexOf("Failed to parse hex representation of transaction hash") >= 0) throw new _MoneroError.default("Invalid transaction hash"); + throw e; + } + + // build transaction models + let txs = []; + if (resp.txs) { + for (let txIdx = 0; txIdx < resp.txs.length; txIdx++) { + let tx = new _MoneroTx.default(); + tx.setIsMinerTx(false); + txs.push(MoneroDaemonRpc.convertRpcTx(resp.txs[txIdx], tx)); + } + } + + return txs; + } + + async getTxHexes(txHashes, prune = false) { + if (this.config.proxyToWorker) return this.proxyDaemon.getTxHexes(txHashes, prune); + let hexes = []; + for (let tx of await this.getTxs(txHashes, prune)) hexes.push(prune ? tx.getPrunedHex() : tx.getFullHex()); + return hexes; + } + + async getMinerTxSum(height, numBlocks) { + if (this.config.proxyToWorker) return this.proxyDaemon.getMinerTxSum(height, numBlocks); + if (height === undefined) height = 0;else + (0, _assert.default)(height >= 0, "Height must be an integer >= 0"); + if (numBlocks === undefined) numBlocks = await this.getHeight();else + (0, _assert.default)(numBlocks >= 0, "Count must be an integer >= 0"); + let resp = await this.config.getServer().sendJsonRequest("get_coinbase_tx_sum", { height: height, count: numBlocks }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + let txSum = new _MoneroMinerTxSum.default(); + txSum.setEmissionSum(BigInt(resp.result.emission_amount)); + txSum.setFeeSum(BigInt(resp.result.fee_amount)); + return txSum; + } + + async getFeeEstimate(graceBlocks) { + if (this.config.proxyToWorker) return this.proxyDaemon.getFeeEstimate(graceBlocks); + let resp = await this.config.getServer().sendJsonRequest("get_fee_estimate", { grace_blocks: graceBlocks }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + let feeEstimate = new _MoneroFeeEstimate.default(); + feeEstimate.setFee(BigInt(resp.result.fee)); + feeEstimate.setQuantizationMask(BigInt(resp.result.quantization_mask)); + if (resp.result.fees !== undefined) { + let fees = []; + for (let i = 0; i < resp.result.fees.length; i++) fees.push(BigInt(resp.result.fees[i])); + feeEstimate.setFees(fees); + } + return feeEstimate; + } + + async submitTxHex(txHex, doNotRelay) { + if (this.config.proxyToWorker) return this.proxyDaemon.submitTxHex(txHex, doNotRelay); + let resp = await this.config.getServer().sendPathRequest("send_raw_transaction", { tx_as_hex: txHex, do_not_relay: doNotRelay }); + let result = MoneroDaemonRpc.convertRpcSubmitTxResult(resp); + + // set isGood based on status + try { + MoneroDaemonRpc.checkResponseStatus(resp); + result.setIsGood(true); + } catch (e) { + result.setIsGood(false); + } + return result; + } + + async relayTxsByHash(txHashes) { + if (this.config.proxyToWorker) return this.proxyDaemon.relayTxsByHash(txHashes); + let resp = await this.config.getServer().sendJsonRequest("relay_tx", { txids: txHashes }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + } + + async getTxPool() { + if (this.config.proxyToWorker) return this.proxyDaemon.getTxPool(); + + // send rpc request + let resp = await this.config.getServer().sendPathRequest("get_transaction_pool"); + MoneroDaemonRpc.checkResponseStatus(resp); + + // build txs + let txs = []; + if (resp.transactions) { + for (let rpcTx of resp.transactions) { + let tx = new _MoneroTx.default(); + txs.push(tx); + tx.setIsConfirmed(false); + tx.setIsMinerTx(false); + tx.setInTxPool(true); + tx.setNumConfirmations(0); + MoneroDaemonRpc.convertRpcTx(rpcTx, tx); + } + } + + return txs; + } + + async getTxPoolHashes() { + throw new _MoneroError.default("Not implemented"); + } + + // async getTxPoolBacklog(): Promise { + // throw new MoneroError("Not implemented"); + // } + + async getTxPoolStats() { + if (this.config.proxyToWorker) return this.proxyDaemon.getTxPoolStats(); + let resp = await this.config.getServer().sendPathRequest("get_transaction_pool_stats"); + MoneroDaemonRpc.checkResponseStatus(resp); + return MoneroDaemonRpc.convertRpcTxPoolStats(resp.pool_stats); + } + + async flushTxPool(hashes) { + if (this.config.proxyToWorker) return this.proxyDaemon.flushTxPool(hashes); + if (hashes) hashes = _GenUtils.default.listify(hashes); + let resp = await this.config.getServer().sendJsonRequest("flush_txpool", { txids: hashes }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + } + + async getKeyImageSpentStatuses(keyImages) { + if (this.config.proxyToWorker) return this.proxyDaemon.getKeyImageSpentStatuses(keyImages); + if (keyImages === undefined || keyImages.length === 0) throw new _MoneroError.default("Must provide key images to check the status of"); + let resp = await this.config.getServer().sendPathRequest("is_key_image_spent", { key_images: keyImages }); + MoneroDaemonRpc.checkResponseStatus(resp); + return resp.spent_status; + } + + async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) { + if (this.config.proxyToWorker) return this.proxyDaemon.getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff); + + // send rpc request + let resp = await this.config.getServer().sendJsonRequest("get_output_histogram", { + amounts: amounts, + min_count: minCount, + max_count: maxCount, + unlocked: isUnlocked, + recent_cutoff: recentCutoff + }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + + // build histogram entries from response + let entries = []; + if (!resp.result.histogram) return entries; + for (let rpcEntry of resp.result.histogram) { + entries.push(MoneroDaemonRpc.convertRpcOutputHistogramEntry(rpcEntry)); + } + return entries; + } + + async getOutputDistribution(amounts, cumulative, startHeight, endHeight) { + if (this.config.proxyToWorker) return this.proxyDaemon.getOutputDistribution(amounts, cumulative, startHeight, endHeight); + throw new _MoneroError.default("Not implemented (response 'distribution' field is binary)"); + + // let amountStrs = []; + // for (let amount of amounts) amountStrs.push(amount.toJSValue()); + // console.log(amountStrs); + // console.log(cumulative); + // console.log(startHeight); + // console.log(endHeight); + // + // // send rpc request + // console.log("*********** SENDING REQUEST *************"); + // if (startHeight === undefined) startHeight = 0; + // let resp = await this.config.getServer().sendJsonRequest("get_output_distribution", { + // amounts: amountStrs, + // cumulative: cumulative, + // from_height: startHeight, + // to_height: endHeight + // }); + // + // console.log("RESPONSE"); + // console.log(resp); + // + // // build distribution entries from response + // let entries = []; + // if (!resp.result.distributions) return entries; + // for (let rpcEntry of resp.result.distributions) { + // let entry = MoneroDaemonRpc.convertRpcOutputDistributionEntry(rpcEntry); + // entries.push(entry); + // } + // return entries; + } + + async getInfo() { + if (this.config.proxyToWorker) return this.proxyDaemon.getInfo(); + let resp = await this.config.getServer().sendJsonRequest("get_info"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcInfo(resp.result); + } + + async getSyncInfo() { + if (this.config.proxyToWorker) return this.proxyDaemon.getSyncInfo(); + let resp = await this.config.getServer().sendJsonRequest("sync_info"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcSyncInfo(resp.result); + } + + async getHardForkInfo() { + if (this.config.proxyToWorker) return this.proxyDaemon.getHardForkInfo(); + let resp = await this.config.getServer().sendJsonRequest("hard_fork_info"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcHardForkInfo(resp.result); + } + + async getAltChains() { + if (this.config.proxyToWorker) return this.proxyDaemon.getAltChains(); + + // // mocked response for test + // let resp = { + // status: "OK", + // chains: [ + // { + // block_hash: "697cf03c89a9b118f7bdf11b1b3a6a028d7b3617d2d0ed91322c5709acf75625", + // difficulty: 14114729638300280, + // height: 1562062, + // length: 2 + // } + // ] + // } + + let resp = await this.config.getServer().sendJsonRequest("get_alternate_chains"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + let chains = []; + if (!resp.result.chains) return chains; + for (let rpcChain of resp.result.chains) chains.push(MoneroDaemonRpc.convertRpcAltChain(rpcChain)); + return chains; + } + + async getAltBlockHashes() { + if (this.config.proxyToWorker) return this.proxyDaemon.getAltBlockHashes(); + + // // mocked response for test + // let resp = { + // status: "OK", + // untrusted: false, + // blks_hashes: ["9c2277c5470234be8b32382cdf8094a103aba4fcd5e875a6fc159dc2ec00e011","637c0e0f0558e284493f38a5fcca3615db59458d90d3a5eff0a18ff59b83f46f","6f3adc174a2e8082819ebb965c96a095e3e8b63929ad9be2d705ad9c086a6b1c","697cf03c89a9b118f7bdf11b1b3a6a028d7b3617d2d0ed91322c5709acf75625"] + // } + + let resp = await this.config.getServer().sendPathRequest("get_alt_blocks_hashes"); + MoneroDaemonRpc.checkResponseStatus(resp); + if (!resp.blks_hashes) return []; + return resp.blks_hashes; + } + + async getDownloadLimit() { + if (this.config.proxyToWorker) return this.proxyDaemon.getDownloadLimit(); + return (await this.getBandwidthLimits())[0]; + } + + async setDownloadLimit(limit) { + if (this.config.proxyToWorker) return this.proxyDaemon.setDownloadLimit(limit); + if (limit == -1) return await this.resetDownloadLimit(); + if (!(_GenUtils.default.isInt(limit) && limit > 0)) throw new _MoneroError.default("Download limit must be an integer greater than 0"); + return (await this.setBandwidthLimits(limit, 0))[0]; + } + + async resetDownloadLimit() { + if (this.config.proxyToWorker) return this.proxyDaemon.resetDownloadLimit(); + return (await this.setBandwidthLimits(-1, 0))[0]; + } + + async getUploadLimit() { + if (this.config.proxyToWorker) return this.proxyDaemon.getUploadLimit(); + return (await this.getBandwidthLimits())[1]; + } + + async setUploadLimit(limit) { + if (this.config.proxyToWorker) return this.proxyDaemon.setUploadLimit(limit); + if (limit == -1) return await this.resetUploadLimit(); + if (!(_GenUtils.default.isInt(limit) && limit > 0)) throw new _MoneroError.default("Upload limit must be an integer greater than 0"); + return (await this.setBandwidthLimits(0, limit))[1]; + } + + async resetUploadLimit() { + if (this.config.proxyToWorker) return this.proxyDaemon.resetUploadLimit(); + return (await this.setBandwidthLimits(0, -1))[1]; + } + + async getPeers() { + if (this.config.proxyToWorker) return this.proxyDaemon.getPeers(); + let resp = await this.config.getServer().sendJsonRequest("get_connections"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + let peers = []; + if (!resp.result.connections) return peers; + for (let rpcConnection of resp.result.connections) { + peers.push(MoneroDaemonRpc.convertRpcConnection(rpcConnection)); + } + return peers; + } + + async getKnownPeers() { + if (this.config.proxyToWorker) return this.proxyDaemon.getKnownPeers(); + + // tx config + let resp = await this.config.getServer().sendPathRequest("get_peer_list"); + MoneroDaemonRpc.checkResponseStatus(resp); + + // build peers + let peers = []; + if (resp.gray_list) { + for (let rpcPeer of resp.gray_list) { + let peer = MoneroDaemonRpc.convertRpcPeer(rpcPeer); + peer.setIsOnline(false); // gray list means offline last checked + peers.push(peer); + } + } + if (resp.white_list) { + for (let rpcPeer of resp.white_list) { + let peer = MoneroDaemonRpc.convertRpcPeer(rpcPeer); + peer.setIsOnline(true); // white list means online last checked + peers.push(peer); + } + } + return peers; + } + + async setOutgoingPeerLimit(limit) { + if (this.config.proxyToWorker) return this.proxyDaemon.setOutgoingPeerLimit(limit); + if (!(_GenUtils.default.isInt(limit) && limit >= 0)) throw new _MoneroError.default("Outgoing peer limit must be >= 0"); + let resp = await this.config.getServer().sendPathRequest("out_peers", { out_peers: limit }); + MoneroDaemonRpc.checkResponseStatus(resp); + } + + async setIncomingPeerLimit(limit) { + if (this.config.proxyToWorker) return this.proxyDaemon.setIncomingPeerLimit(limit); + if (!(_GenUtils.default.isInt(limit) && limit >= 0)) throw new _MoneroError.default("Incoming peer limit must be >= 0"); + let resp = await this.config.getServer().sendPathRequest("in_peers", { in_peers: limit }); + MoneroDaemonRpc.checkResponseStatus(resp); + } + + async getPeerBans() { + if (this.config.proxyToWorker) return this.proxyDaemon.getPeerBans(); + let resp = await this.config.getServer().sendJsonRequest("get_bans"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + let bans = []; + for (let rpcBan of resp.result.bans) { + let ban = new _MoneroBan.default(); + ban.setHost(rpcBan.host); + ban.setIp(rpcBan.ip); + ban.setSeconds(rpcBan.seconds); + bans.push(ban); + } + return bans; + } + + async setPeerBans(bans) { + if (this.config.proxyToWorker) return this.proxyDaemon.setPeerBans(bans); + let rpcBans = []; + for (let ban of bans) rpcBans.push(MoneroDaemonRpc.convertToRpcBan(ban)); + let resp = await this.config.getServer().sendJsonRequest("set_bans", { bans: rpcBans }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + } + + async startMining(address, numThreads, isBackground, ignoreBattery) { + if (this.config.proxyToWorker) return this.proxyDaemon.startMining(address, numThreads, isBackground, ignoreBattery); + (0, _assert.default)(address, "Must provide address to mine to"); + (0, _assert.default)(_GenUtils.default.isInt(numThreads) && numThreads > 0, "Number of threads must be an integer greater than 0"); + (0, _assert.default)(isBackground === undefined || typeof isBackground === "boolean"); + (0, _assert.default)(ignoreBattery === undefined || typeof ignoreBattery === "boolean"); + let resp = await this.config.getServer().sendPathRequest("start_mining", { + miner_address: address, + threads_count: numThreads, + do_background_mining: isBackground, + ignore_battery: ignoreBattery + }); + MoneroDaemonRpc.checkResponseStatus(resp); + } + + async stopMining() { + if (this.config.proxyToWorker) return this.proxyDaemon.stopMining(); + let resp = await this.config.getServer().sendPathRequest("stop_mining"); + MoneroDaemonRpc.checkResponseStatus(resp); + } + + async getMiningStatus() { + if (this.config.proxyToWorker) return this.proxyDaemon.getMiningStatus(); + let resp = await this.config.getServer().sendPathRequest("mining_status"); + MoneroDaemonRpc.checkResponseStatus(resp); + return MoneroDaemonRpc.convertRpcMiningStatus(resp); + } + + async submitBlocks(blockBlobs) { + if (this.config.proxyToWorker) return this.proxyDaemon.submitBlocks(blockBlobs); + (0, _assert.default)(Array.isArray(blockBlobs) && blockBlobs.length > 0, "Must provide an array of mined block blobs to submit"); + let resp = await this.config.getServer().sendJsonRequest("submit_block", blockBlobs); + MoneroDaemonRpc.checkResponseStatus(resp.result); + } + + async pruneBlockchain(check) { + if (this.config.proxyToWorker) return this.proxyDaemon.pruneBlockchain(); + let resp = await this.config.getServer().sendJsonRequest("prune_blockchain", { check: check }, 0); + MoneroDaemonRpc.checkResponseStatus(resp.result); + let result = new _MoneroPruneResult.default(); + result.setIsPruned(resp.result.pruned); + result.setPruningSeed(resp.result.pruning_seed); + return result; + } + + async checkForUpdate() { + if (this.config.proxyToWorker) return this.proxyDaemon.checkForUpdate(); + let resp = await this.config.getServer().sendPathRequest("update", { command: "check" }); + MoneroDaemonRpc.checkResponseStatus(resp); + return MoneroDaemonRpc.convertRpcUpdateCheckResult(resp); + } + + async downloadUpdate(path) { + if (this.config.proxyToWorker) return this.proxyDaemon.downloadUpdate(path); + let resp = await this.config.getServer().sendPathRequest("update", { command: "download", path: path }); + MoneroDaemonRpc.checkResponseStatus(resp); + return MoneroDaemonRpc.convertRpcUpdateDownloadResult(resp); + } + + async stop() { + if (this.config.proxyToWorker) return this.proxyDaemon.stop(); + let resp = await this.config.getServer().sendPathRequest("stop_daemon"); + MoneroDaemonRpc.checkResponseStatus(resp); + } + + async waitForNextBlockHeader() { + if (this.config.proxyToWorker) return this.proxyDaemon.waitForNextBlockHeader(); + let that = this; + return new Promise(async function (resolve) { + await that.addListener(new class extends _MoneroDaemonListener.default { + async onBlockHeader(header) { + await that.removeListener(this); + resolve(header); + } + }()); + }); + } + + getPollInterval() { + return this.config.pollInterval; + } + + // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS -------------- + async getTx(txHash, prune = false) {return super.getTx(txHash, prune);} + async getTxHex(txHash, prune = false) {return super.getTxHex(txHash, prune);} + async getKeyImageSpentStatus(keyImage) {return super.getKeyImageSpentStatus(keyImage);} + async setPeerBan(ban) {return super.setPeerBan(ban);} + async submitBlock(blockBlob) {return super.submitBlock(blockBlob);} + + // ------------------------------- PRIVATE ---------------------------------- + + refreshListening() { + if (this.pollListener == undefined && this.listeners.length) this.pollListener = new DaemonPoller(this); + if (this.pollListener !== undefined) this.pollListener.setIsPolling(this.listeners.length > 0); + } + + async getBandwidthLimits() { + let resp = await this.config.getServer().sendPathRequest("get_limit"); + MoneroDaemonRpc.checkResponseStatus(resp); + return [resp.limit_down, resp.limit_up]; + } + + async setBandwidthLimits(downLimit, upLimit) { + if (downLimit === undefined) downLimit = 0; + if (upLimit === undefined) upLimit = 0; + let resp = await this.config.getServer().sendPathRequest("set_limit", { limit_down: downLimit, limit_up: upLimit }); + MoneroDaemonRpc.checkResponseStatus(resp); + return [resp.limit_down, resp.limit_up]; + } + + /** + * Get a contiguous chunk of blocks starting from a given height up to a maximum + * height or amount of block data fetched from the blockchain, whichever comes first. + * + * @param {number} [startHeight] - start height to retrieve blocks (default 0) + * @param {number} [maxHeight] - maximum end height to retrieve blocks (default blockchain height) + * @param {number} [maxReqSize] - maximum amount of block data to fetch from the blockchain in bytes (default 3,000,000 bytes) + * @return {MoneroBlock[]} are the resulting chunk of blocks + */ + async getMaxBlocks(startHeight, maxHeight, maxReqSize) { + if (startHeight === undefined) startHeight = 0; + if (maxHeight === undefined) maxHeight = (await this.getHeight()) - 1; + if (maxReqSize === undefined) maxReqSize = MoneroDaemonRpc.MAX_REQ_SIZE; + + // determine end height to fetch + let reqSize = 0; + let endHeight = startHeight - 1; + while (reqSize < maxReqSize && endHeight < maxHeight) { + + // get header of next block + let header = await this.getBlockHeaderByHeightCached(endHeight + 1, maxHeight); + + // block cannot be bigger than max request size + (0, _assert.default)(header.getSize() <= maxReqSize, "Block exceeds maximum request size: " + header.getSize()); + + // done iterating if fetching block would exceed max request size + if (reqSize + header.getSize() > maxReqSize) break; + + // otherwise block is included + reqSize += header.getSize(); + endHeight++; + } + return endHeight >= startHeight ? await this.getBlocksByRange(startHeight, endHeight) : []; + } + + /** + * Retrieves a header by height from the cache or fetches and caches a header + * range if not already in the cache. + * + * @param {number} height - height of the header to retrieve from the cache + * @param {number} maxHeight - maximum height of headers to cache + */ + async getBlockHeaderByHeightCached(height, maxHeight) { + + // get header from cache + let cachedHeader = this.cachedHeaders[height]; + if (cachedHeader) return cachedHeader; + + // fetch and cache headers if not in cache + let endHeight = Math.min(maxHeight, height + MoneroDaemonRpc.NUM_HEADERS_PER_REQ - 1); // TODO: could specify end height to cache to optimize small requests (would like to have time profiling in place though) + let headers = await this.getBlockHeadersByRange(height, endHeight); + for (let header of headers) { + this.cachedHeaders[header.getHeight()] = header; + } + + // return the cached header + return this.cachedHeaders[height]; + } + + // --------------------------------- STATIC --------------------------------- + + static async connectToDaemonRpc(uriOrConfig, username, password) { + let config = MoneroDaemonRpc.normalizeConfig(uriOrConfig, username, password); + if (config.cmd) return MoneroDaemonRpc.startMonerodProcess(config); + return new MoneroDaemonRpc(config, config.proxyToWorker ? await MoneroDaemonRpcProxy.connect(config) : undefined); + } + + static async startMonerodProcess(config) { + (0, _assert.default)(_GenUtils.default.isArray(config.cmd), "Must provide string array with command line parameters"); + + // start process + let childProcess = require('child_process').spawn(config.cmd[0], config.cmd.slice(1), { + env: { ...process.env, LANG: 'en_US.UTF-8' } // scrape output in english + }); + childProcess.stdout.setEncoding('utf8'); + childProcess.stderr.setEncoding('utf8'); + + // return promise which resolves after starting monerod + let uri; + let output = ""; + try { + return await new Promise(function (resolve, reject) { + + // handle stdout + childProcess.stdout.on('data', async function (data) { + let line = data.toString(); + _LibraryUtils.default.log(2, line); + output += line + '\n'; // capture output in case of error + + // extract uri from e.g. "I Binding on 127.0.0.1 (IPv4):38085" + let uriLineContains = "Binding on "; + let uriLineContainsIdx = line.indexOf(uriLineContains); + if (uriLineContainsIdx >= 0) { + let host = line.substring(uriLineContainsIdx + uriLineContains.length, line.lastIndexOf(' ')); + let unformattedLine = line.replace(/\u001b\[.*?m/g, '').trim(); // remove color formatting + let port = unformattedLine.substring(unformattedLine.lastIndexOf(':') + 1); + let sslIdx = config.cmd.indexOf("--rpc-ssl"); + let sslEnabled = sslIdx >= 0 ? "enabled" == config.cmd[sslIdx + 1].toLowerCase() : false; + uri = (sslEnabled ? "https" : "http") + "://" + host + ":" + port; + } + + // read success message + if (line.indexOf("core RPC server started ok") >= 0) { + + // get username and password from params + let userPassIdx = config.cmd.indexOf("--rpc-login"); + let userPass = userPassIdx >= 0 ? config.cmd[userPassIdx + 1] : undefined; + let username = userPass === undefined ? undefined : userPass.substring(0, userPass.indexOf(':')); + let password = userPass === undefined ? undefined : userPass.substring(userPass.indexOf(':') + 1); + + // create client connected to internal process + config = config.copy().setServer({ uri: uri, username: username, password: password, rejectUnauthorized: config.getServer() ? config.getServer().getRejectUnauthorized() : undefined }); + config.setProxyToWorker(config.proxyToWorker); + config.cmd = undefined; + let daemon = await MoneroDaemonRpc.connectToDaemonRpc(config); + daemon.process = childProcess; + + // resolve promise with client connected to internal process + this.isResolved = true; + resolve(daemon); + } + }); + + // handle stderr + childProcess.stderr.on('data', function (data) { + if (_LibraryUtils.default.getLogLevel() >= 2) console.error(data); + }); + + // handle exit + childProcess.on("exit", function (code) { + if (!this.isResolved) reject(new Error("monerod process terminated with exit code " + code + (output ? ":\n\n" + output : ""))); + }); + + // handle error + childProcess.on("error", function (err) { + if (err.message.indexOf("ENOENT") >= 0) reject(new Error("monerod does not exist at path '" + config.cmd[0] + "'")); + if (!this.isResolved) reject(err); + }); + + // handle uncaught exception + childProcess.on("uncaughtException", function (err, origin) { + console.error("Uncaught exception in monerod process: " + err.message); + console.error(origin); + if (!this.isResolved) reject(err); + }); + }); + } catch (err) { + throw new _MoneroError.default(err.message); + } + } + + static normalizeConfig(uriOrConfig, username, password) { + let config = undefined; + if (typeof uriOrConfig === "string") { + config = new _MoneroDaemonConfig.default({ server: new _MoneroRpcConnection.default(uriOrConfig, username, password) }); + } else if (uriOrConfig.uri !== undefined) { + config = new _MoneroDaemonConfig.default({ server: new _MoneroRpcConnection.default(uriOrConfig) }); + + // transfer worker proxy setting from rpc connection to daemon config + config.setProxyToWorker(uriOrConfig.proxyToWorker); + config.getServer().setProxyToWorker(_MoneroRpcConnection.default.DEFAULT_CONFIG.proxyToWorker); + } else if (_GenUtils.default.isArray(uriOrConfig)) { + config = new _MoneroDaemonConfig.default({ cmd: uriOrConfig }); + } else { + config = new _MoneroDaemonConfig.default(uriOrConfig); + } + if (config.proxyToWorker === undefined) config.proxyToWorker = true; + if (config.pollInterval === undefined) config.pollInterval = MoneroDaemonRpc.DEFAULT_POLL_PERIOD; + return config; + } + + static checkResponseStatus(resp) { + if (resp.status !== "OK") throw new _MoneroError.default(resp.status); + } + + static convertRpcBlockHeader(rpcHeader) { + if (!rpcHeader) return undefined; + let header = new _MoneroBlockHeader.default(); + for (let key of Object.keys(rpcHeader)) { + let val = rpcHeader[key]; + if (key === "block_size") _GenUtils.default.safeSet(header, header.getSize, header.setSize, val);else + if (key === "depth") _GenUtils.default.safeSet(header, header.getDepth, header.setDepth, val);else + if (key === "difficulty") {} // handled by wide_difficulty + else if (key === "cumulative_difficulty") {} // handled by wide_cumulative_difficulty + else if (key === "difficulty_top64") {} // handled by wide_difficulty + else if (key === "cumulative_difficulty_top64") {} // handled by wide_cumulative_difficulty + else if (key === "wide_difficulty") header.setDifficulty(_GenUtils.default.reconcile(header.getDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val)));else + if (key === "wide_cumulative_difficulty") header.setCumulativeDifficulty(_GenUtils.default.reconcile(header.getCumulativeDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val)));else + if (key === "hash") _GenUtils.default.safeSet(header, header.getHash, header.setHash, val);else + if (key === "height") _GenUtils.default.safeSet(header, header.getHeight, header.setHeight, val);else + if (key === "major_version") _GenUtils.default.safeSet(header, header.getMajorVersion, header.setMajorVersion, val);else + if (key === "minor_version") _GenUtils.default.safeSet(header, header.getMinorVersion, header.setMinorVersion, val);else + if (key === "nonce") _GenUtils.default.safeSet(header, header.getNonce, header.setNonce, val);else + if (key === "num_txes") _GenUtils.default.safeSet(header, header.getNumTxs, header.setNumTxs, val);else + if (key === "orphan_status") _GenUtils.default.safeSet(header, header.getOrphanStatus, header.setOrphanStatus, val);else + if (key === "prev_hash" || key === "prev_id") _GenUtils.default.safeSet(header, header.getPrevHash, header.setPrevHash, val);else + if (key === "reward") _GenUtils.default.safeSet(header, header.getReward, header.setReward, BigInt(val));else + if (key === "timestamp") _GenUtils.default.safeSet(header, header.getTimestamp, header.setTimestamp, val);else + if (key === "block_weight") _GenUtils.default.safeSet(header, header.getWeight, header.setWeight, val);else + if (key === "long_term_weight") _GenUtils.default.safeSet(header, header.getLongTermWeight, header.setLongTermWeight, val);else + if (key === "pow_hash") _GenUtils.default.safeSet(header, header.getPowHash, header.setPowHash, val === "" ? undefined : val);else + if (key === "tx_hashes") {} // used in block model, not header model + else if (key === "miner_tx") {} // used in block model, not header model + else if (key === "miner_tx_hash") header.setMinerTxHash(val);else + console.log("WARNING: ignoring unexpected block header field: '" + key + "': " + val); + } + return header; + } + + static convertRpcBlock(rpcBlock) { + + // build block + let block = new _MoneroBlock.default(MoneroDaemonRpc.convertRpcBlockHeader(rpcBlock.block_header ? rpcBlock.block_header : rpcBlock)); + block.setHex(rpcBlock.blob); + block.setTxHashes(rpcBlock.tx_hashes === undefined ? [] : rpcBlock.tx_hashes); + + // build miner tx + let rpcMinerTx = rpcBlock.json ? JSON.parse(rpcBlock.json).miner_tx : rpcBlock.miner_tx; // may need to be parsed from json + let minerTx = new _MoneroTx.default(); + block.setMinerTx(minerTx); + minerTx.setIsConfirmed(true); + minerTx.setInTxPool(false); + minerTx.setIsMinerTx(true); + MoneroDaemonRpc.convertRpcTx(rpcMinerTx, minerTx); + + return block; + } + + /** + * Transfers RPC tx fields to a given MoneroTx without overwriting previous values. + * + * TODO: switch from safe set + * + * @param rpcTx - RPC map containing transaction fields + * @param tx - MoneroTx to populate with values (optional) + * @return tx - same tx that was passed in or a new one if none given + */ + static convertRpcTx(rpcTx, tx) { + if (rpcTx === undefined) return undefined; + if (tx === undefined) tx = new _MoneroTx.default(); + + // initialize from rpc map + let header; + for (let key of Object.keys(rpcTx)) { + let val = rpcTx[key]; + if (key === "tx_hash" || key === "id_hash") _GenUtils.default.safeSet(tx, tx.getHash, tx.setHash, val);else + if (key === "block_timestamp") { + if (!header) header = new _MoneroBlockHeader.default(); + _GenUtils.default.safeSet(header, header.getTimestamp, header.setTimestamp, val); + } else + if (key === "block_height") { + if (!header) header = new _MoneroBlockHeader.default(); + _GenUtils.default.safeSet(header, header.getHeight, header.setHeight, val); + } else + if (key === "last_relayed_time") _GenUtils.default.safeSet(tx, tx.getLastRelayedTimestamp, tx.setLastRelayedTimestamp, val);else + if (key === "receive_time" || key === "received_timestamp") _GenUtils.default.safeSet(tx, tx.getReceivedTimestamp, tx.setReceivedTimestamp, val);else + if (key === "confirmations") _GenUtils.default.safeSet(tx, tx.getNumConfirmations, tx.setNumConfirmations, val);else + if (key === "in_pool") { + _GenUtils.default.safeSet(tx, tx.getIsConfirmed, tx.setIsConfirmed, !val); + _GenUtils.default.safeSet(tx, tx.getInTxPool, tx.setInTxPool, val); + } else + if (key === "double_spend_seen") _GenUtils.default.safeSet(tx, tx.getIsDoubleSpendSeen, tx.setIsDoubleSpendSeen, val);else + if (key === "version") _GenUtils.default.safeSet(tx, tx.getVersion, tx.setVersion, val);else + if (key === "extra") { + if (typeof val === "string") console.log("WARNING: extra field as string not being asigned to int[]: " + key + ": " + val); // TODO: how to set string to int[]? - or, extra is string which can encode int[] + else _GenUtils.default.safeSet(tx, tx.getExtra, tx.setExtra, new Uint8Array(val)); + } else + if (key === "vin") { + if (val.length !== 1 || !val[0].gen) {// ignore miner input TODO: why? + tx.setInputs(val.map((rpcVin) => MoneroDaemonRpc.convertRpcOutput(rpcVin, tx))); + } + } else + if (key === "vout") tx.setOutputs(val.map((rpcOutput) => MoneroDaemonRpc.convertRpcOutput(rpcOutput, tx)));else + if (key === "rct_signatures") { + _GenUtils.default.safeSet(tx, tx.getRctSignatures, tx.setRctSignatures, val); + if (val.txnFee) _GenUtils.default.safeSet(tx, tx.getFee, tx.setFee, BigInt(val.txnFee)); + } else + if (key === "rctsig_prunable") _GenUtils.default.safeSet(tx, tx.getRctSigPrunable, tx.setRctSigPrunable, val);else + if (key === "unlock_time") _GenUtils.default.safeSet(tx, tx.getUnlockTime, tx.setUnlockTime, val);else + if (key === "as_json" || key === "tx_json") {} // handled last so tx is as initialized as possible + else if (key === "as_hex" || key === "tx_blob") _GenUtils.default.safeSet(tx, tx.getFullHex, tx.setFullHex, val ? val : undefined);else + if (key === "blob_size") _GenUtils.default.safeSet(tx, tx.getSize, tx.setSize, val);else + if (key === "weight") _GenUtils.default.safeSet(tx, tx.getWeight, tx.setWeight, val);else + if (key === "fee") _GenUtils.default.safeSet(tx, tx.getFee, tx.setFee, BigInt(val));else + if (key === "relayed") _GenUtils.default.safeSet(tx, tx.getIsRelayed, tx.setIsRelayed, val);else + if (key === "output_indices") _GenUtils.default.safeSet(tx, tx.getOutputIndices, tx.setOutputIndices, val);else + if (key === "do_not_relay") _GenUtils.default.safeSet(tx, tx.getRelay, tx.setRelay, !val);else + if (key === "kept_by_block") _GenUtils.default.safeSet(tx, tx.getIsKeptByBlock, tx.setIsKeptByBlock, val);else + if (key === "signatures") _GenUtils.default.safeSet(tx, tx.getSignatures, tx.setSignatures, val);else + if (key === "last_failed_height") { + if (val === 0) _GenUtils.default.safeSet(tx, tx.getIsFailed, tx.setIsFailed, false);else + { + _GenUtils.default.safeSet(tx, tx.getIsFailed, tx.setIsFailed, true); + _GenUtils.default.safeSet(tx, tx.getLastFailedHeight, tx.setLastFailedHeight, val); + } + } else + if (key === "last_failed_id_hash") { + if (val === MoneroDaemonRpc.DEFAULT_ID) _GenUtils.default.safeSet(tx, tx.getIsFailed, tx.setIsFailed, false);else + { + _GenUtils.default.safeSet(tx, tx.getIsFailed, tx.setIsFailed, true); + _GenUtils.default.safeSet(tx, tx.getLastFailedHash, tx.setLastFailedHash, val); + } + } else + if (key === "max_used_block_height") _GenUtils.default.safeSet(tx, tx.getMaxUsedBlockHeight, tx.setMaxUsedBlockHeight, val);else + if (key === "max_used_block_id_hash") _GenUtils.default.safeSet(tx, tx.getMaxUsedBlockHash, tx.setMaxUsedBlockHash, val);else + if (key === "prunable_hash") _GenUtils.default.safeSet(tx, tx.getPrunableHash, tx.setPrunableHash, val ? val : undefined);else + if (key === "prunable_as_hex") _GenUtils.default.safeSet(tx, tx.getPrunableHex, tx.setPrunableHex, val ? val : undefined);else + if (key === "pruned_as_hex") _GenUtils.default.safeSet(tx, tx.getPrunedHex, tx.setPrunedHex, val ? val : undefined);else + console.log("WARNING: ignoring unexpected field in rpc tx: " + key + ": " + val); + } + + // link block and tx + if (header) tx.setBlock(new _MoneroBlock.default(header).setTxs([tx])); + + // TODO monerod: unconfirmed txs misreport block height and timestamp? + if (tx.getBlock() && tx.getBlock().getHeight() !== undefined && tx.getBlock().getHeight() === tx.getBlock().getTimestamp()) { + tx.setBlock(undefined); + tx.setIsConfirmed(false); + } + + // initialize remaining known fields + if (tx.getIsConfirmed()) { + _GenUtils.default.safeSet(tx, tx.getIsRelayed, tx.setIsRelayed, true); + _GenUtils.default.safeSet(tx, tx.getRelay, tx.setRelay, true); + _GenUtils.default.safeSet(tx, tx.getIsFailed, tx.setIsFailed, false); + } else { + tx.setNumConfirmations(0); + } + if (tx.getIsFailed() === undefined) tx.setIsFailed(false); + if (tx.getOutputIndices() && tx.getOutputs()) { + _assert.default.equal(tx.getOutputs().length, tx.getOutputIndices().length); + for (let i = 0; i < tx.getOutputs().length; i++) { + tx.getOutputs()[i].setIndex(tx.getOutputIndices()[i]); // transfer output indices to outputs + } + } + if (rpcTx.as_json) MoneroDaemonRpc.convertRpcTx(JSON.parse(rpcTx.as_json), tx); + if (rpcTx.tx_json) MoneroDaemonRpc.convertRpcTx(JSON.parse(rpcTx.tx_json), tx); + if (!tx.getIsRelayed()) tx.setLastRelayedTimestamp(undefined); // TODO monerod: returns last_relayed_timestamp despite relayed: false, self inconsistent + + // return built transaction + return tx; + } + + static convertRpcOutput(rpcOutput, tx) { + let output = new _MoneroOutput.default(); + output.setTx(tx); + for (let key of Object.keys(rpcOutput)) { + let val = rpcOutput[key]; + if (key === "gen") throw new _MoneroError.default("Output with 'gen' from daemon rpc is miner tx which we ignore (i.e. each miner input is undefined)");else + if (key === "key") { + _GenUtils.default.safeSet(output, output.getAmount, output.setAmount, BigInt(val.amount)); + _GenUtils.default.safeSet(output, output.getKeyImage, output.setKeyImage, new _MoneroKeyImage.default(val.k_image)); + _GenUtils.default.safeSet(output, output.getRingOutputIndices, output.setRingOutputIndices, val.key_offsets); + } else + if (key === "amount") _GenUtils.default.safeSet(output, output.getAmount, output.setAmount, BigInt(val));else + if (key === "target") { + let pubKey = val.key === undefined ? val.tagged_key.key : val.key; // TODO (monerod): rpc json uses {tagged_key={key=...}}, binary blocks use {key=...} + _GenUtils.default.safeSet(output, output.getStealthPublicKey, output.setStealthPublicKey, pubKey); + } else + console.log("WARNING: ignoring unexpected field output: " + key + ": " + val); + } + return output; + } + + static convertRpcBlockTemplate(rpcTemplate) { + let template = new _MoneroBlockTemplate.default(); + for (let key of Object.keys(rpcTemplate)) { + let val = rpcTemplate[key]; + if (key === "blockhashing_blob") template.setBlockHashingBlob(val);else + if (key === "blocktemplate_blob") template.setBlockTemplateBlob(val);else + if (key === "expected_reward") template.setExpectedReward(val);else + if (key === "difficulty") {} // handled by wide_difficulty + else if (key === "difficulty_top64") {} // handled by wide_difficulty + else if (key === "wide_difficulty") template.setDifficulty(_GenUtils.default.reconcile(template.getDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val)));else + if (key === "height") template.setHeight(val);else + if (key === "prev_hash") template.setPrevHash(val);else + if (key === "reserved_offset") template.setReservedOffset(val);else + if (key === "status") {} // handled elsewhere + else if (key === "untrusted") {} // handled elsewhere + else if (key === "seed_height") template.setSeedHeight(val);else + if (key === "seed_hash") template.setSeedHash(val);else + if (key === "next_seed_hash") template.setNextSeedHash(val);else + console.log("WARNING: ignoring unexpected field in block template: " + key + ": " + val); + } + if ("" === template.getNextSeedHash()) template.setNextSeedHash(undefined); + return template; + } + + static convertRpcInfo(rpcInfo) { + if (!rpcInfo) return undefined; + let info = new _MoneroDaemonInfo.default(); + for (let key of Object.keys(rpcInfo)) { + let val = rpcInfo[key]; + if (key === "version") info.setVersion(val);else + if (key === "alt_blocks_count") info.setNumAltBlocks(val);else + if (key === "block_size_limit") info.setBlockSizeLimit(val);else + if (key === "block_size_median") info.setBlockSizeMedian(val);else + if (key === "block_weight_limit") info.setBlockWeightLimit(val);else + if (key === "block_weight_median") info.setBlockWeightMedian(val);else + if (key === "bootstrap_daemon_address") {if (val) info.setBootstrapDaemonAddress(val);} else + if (key === "difficulty") {} // handled by wide_difficulty + else if (key === "cumulative_difficulty") {} // handled by wide_cumulative_difficulty + else if (key === "difficulty_top64") {} // handled by wide_difficulty + else if (key === "cumulative_difficulty_top64") {} // handled by wide_cumulative_difficulty + else if (key === "wide_difficulty") info.setDifficulty(_GenUtils.default.reconcile(info.getDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val)));else + if (key === "wide_cumulative_difficulty") info.setCumulativeDifficulty(_GenUtils.default.reconcile(info.getCumulativeDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val)));else + if (key === "free_space") info.setFreeSpace(BigInt(val));else + if (key === "database_size") info.setDatabaseSize(val);else + if (key === "grey_peerlist_size") info.setNumOfflinePeers(val);else + if (key === "height") info.setHeight(val);else + if (key === "height_without_bootstrap") info.setHeightWithoutBootstrap(val);else + if (key === "incoming_connections_count") info.setNumIncomingConnections(val);else + if (key === "offline") info.setIsOffline(val);else + if (key === "outgoing_connections_count") info.setNumOutgoingConnections(val);else + if (key === "rpc_connections_count") info.setNumRpcConnections(val);else + if (key === "start_time") info.setStartTimestamp(val);else + if (key === "adjusted_time") info.setAdjustedTimestamp(val);else + if (key === "status") {} // handled elsewhere + else if (key === "target") info.setTarget(val);else + if (key === "target_height") info.setTargetHeight(val);else + if (key === "top_block_hash") info.setTopBlockHash(val);else + if (key === "tx_count") info.setNumTxs(val);else + if (key === "tx_pool_size") info.setNumTxsPool(val);else + if (key === "untrusted") {} // handled elsewhere + else if (key === "was_bootstrap_ever_used") info.setWasBootstrapEverUsed(val);else + if (key === "white_peerlist_size") info.setNumOnlinePeers(val);else + if (key === "update_available") info.setUpdateAvailable(val);else + if (key === "nettype") _GenUtils.default.safeSet(info, info.getNetworkType, info.setNetworkType, _MoneroNetworkType.default.parse(val));else + if (key === "mainnet") {if (val) _GenUtils.default.safeSet(info, info.getNetworkType, info.setNetworkType, _MoneroNetworkType.default.MAINNET);} else + if (key === "testnet") {if (val) _GenUtils.default.safeSet(info, info.getNetworkType, info.setNetworkType, _MoneroNetworkType.default.TESTNET);} else + if (key === "stagenet") {if (val) _GenUtils.default.safeSet(info, info.getNetworkType, info.setNetworkType, _MoneroNetworkType.default.STAGENET);} else + if (key === "credits") info.setCredits(BigInt(val));else + if (key === "top_block_hash" || key === "top_hash") info.setTopBlockHash(_GenUtils.default.reconcile(info.getTopBlockHash(), "" === val ? undefined : val));else + if (key === "busy_syncing") info.setIsBusySyncing(val);else + if (key === "synchronized") info.setIsSynchronized(val);else + if (key === "restricted") info.setIsRestricted(val);else + console.log("WARNING: Ignoring unexpected info field: " + key + ": " + val); + } + return info; + } + + /** + * Initializes sync info from RPC sync info. + * + * @param rpcSyncInfo - rpc map to initialize the sync info from + * @return {MoneroDaemonSyncInfo} is sync info initialized from the map + */ + static convertRpcSyncInfo(rpcSyncInfo) { + let syncInfo = new _MoneroDaemonSyncInfo.default(); + for (let key of Object.keys(rpcSyncInfo)) { + let val = rpcSyncInfo[key]; + if (key === "height") syncInfo.setHeight(val);else + if (key === "peers") { + syncInfo.setPeers([]); + let rpcConnections = val; + for (let rpcConnection of rpcConnections) { + syncInfo.getPeers().push(MoneroDaemonRpc.convertRpcConnection(rpcConnection.info)); + } + } else + if (key === "spans") { + syncInfo.setSpans([]); + let rpcSpans = val; + for (let rpcSpan of rpcSpans) { + syncInfo.getSpans().push(MoneroDaemonRpc.convertRpcConnectionSpan(rpcSpan)); + } + } else if (key === "status") {} // handled elsewhere + else if (key === "target_height") syncInfo.setTargetHeight(val);else + if (key === "next_needed_pruning_seed") syncInfo.setNextNeededPruningSeed(val);else + if (key === "overview") {// this returns [] without pruning + let overview; + try { + overview = JSON.parse(val); + if (overview !== undefined && overview.length > 0) console.error("Ignoring non-empty 'overview' field (not implemented): " + overview); // TODO + } catch (e) { + console.error("Failed to parse 'overview' field: " + overview + ": " + e.message); + } + } else + if (key === "credits") syncInfo.setCredits(BigInt(val));else + if (key === "top_hash") syncInfo.setTopBlockHash("" === val ? undefined : val);else + if (key === "untrusted") {} // handled elsewhere + else console.log("WARNING: ignoring unexpected field in sync info: " + key + ": " + val); + } + return syncInfo; + } + + static convertRpcHardForkInfo(rpcHardForkInfo) { + let info = new _MoneroHardForkInfo.default(); + for (let key of Object.keys(rpcHardForkInfo)) { + let val = rpcHardForkInfo[key]; + if (key === "earliest_height") info.setEarliestHeight(val);else + if (key === "enabled") info.setIsEnabled(val);else + if (key === "state") info.setState(val);else + if (key === "status") {} // handled elsewhere + else if (key === "untrusted") {} // handled elsewhere + else if (key === "threshold") info.setThreshold(val);else + if (key === "version") info.setVersion(val);else + if (key === "votes") info.setNumVotes(val);else + if (key === "voting") info.setVoting(val);else + if (key === "window") info.setWindow(val);else + if (key === "credits") info.setCredits(BigInt(val));else + if (key === "top_hash") info.setTopBlockHash("" === val ? undefined : val);else + console.log("WARNING: ignoring unexpected field in hard fork info: " + key + ": " + val); + } + return info; + } + + static convertRpcConnectionSpan(rpcConnectionSpan) { + let span = new _MoneroConnectionSpan.default(); + for (let key of Object.keys(rpcConnectionSpan)) { + let val = rpcConnectionSpan[key]; + if (key === "connection_id") span.setConnectionId(val);else + if (key === "nblocks") span.setNumBlocks(val);else + if (key === "rate") span.setRate(val);else + if (key === "remote_address") {if (val !== "") span.setRemoteAddress(val);} else + if (key === "size") span.setSize(val);else + if (key === "speed") span.setSpeed(val);else + if (key === "start_block_height") span.setStartHeight(val);else + console.log("WARNING: ignoring unexpected field in daemon connection span: " + key + ": " + val); + } + return span; + } + + static convertRpcOutputHistogramEntry(rpcEntry) { + let entry = new _MoneroOutputHistogramEntry.default(); + for (let key of Object.keys(rpcEntry)) { + let val = rpcEntry[key]; + if (key === "amount") entry.setAmount(BigInt(val));else + if (key === "total_instances") entry.setNumInstances(val);else + if (key === "unlocked_instances") entry.setNumUnlockedInstances(val);else + if (key === "recent_instances") entry.setNumRecentInstances(val);else + console.log("WARNING: ignoring unexpected field in output histogram: " + key + ": " + val); + } + return entry; + } + + static convertRpcSubmitTxResult(rpcResult) { + (0, _assert.default)(rpcResult); + let result = new _MoneroSubmitTxResult.default(); + for (let key of Object.keys(rpcResult)) { + let val = rpcResult[key]; + if (key === "double_spend") result.setIsDoubleSpendSeen(val);else + if (key === "fee_too_low") result.setIsFeeTooLow(val);else + if (key === "invalid_input") result.setHasInvalidInput(val);else + if (key === "invalid_output") result.setHasInvalidOutput(val);else + if (key === "too_few_outputs") result.setHasTooFewOutputs(val);else + if (key === "low_mixin") result.setIsMixinTooLow(val);else + if (key === "not_relayed") result.setIsRelayed(!val);else + if (key === "overspend") result.setIsOverspend(val);else + if (key === "reason") result.setReason(val === "" ? undefined : val);else + if (key === "too_big") result.setIsTooBig(val);else + if (key === "sanity_check_failed") result.setSanityCheckFailed(val);else + if (key === "credits") result.setCredits(BigInt(val));else + if (key === "status" || key === "untrusted") {} // handled elsewhere + else if (key === "top_hash") result.setTopBlockHash("" === val ? undefined : val);else + if (key === "tx_extra_too_big") result.setIsTxExtraTooBig(val);else + if (key === "nonzero_unlock_time") result.setIsNonzeroUnlockTime(val);else + console.log("WARNING: ignoring unexpected field in submit tx hex result: " + key + ": " + val); + } + return result; + } + + static convertRpcTxPoolStats(rpcStats) { + (0, _assert.default)(rpcStats); + let stats = new _MoneroTxPoolStats.default(); + for (let key of Object.keys(rpcStats)) { + let val = rpcStats[key]; + if (key === "bytes_max") stats.setBytesMax(val);else + if (key === "bytes_med") stats.setBytesMed(val);else + if (key === "bytes_min") stats.setBytesMin(val);else + if (key === "bytes_total") stats.setBytesTotal(val);else + if (key === "histo_98pc") stats.setHisto98pc(val);else + if (key === "num_10m") stats.setNum10m(val);else + if (key === "num_double_spends") stats.setNumDoubleSpends(val);else + if (key === "num_failing") stats.setNumFailing(val);else + if (key === "num_not_relayed") stats.setNumNotRelayed(val);else + if (key === "oldest") stats.setOldestTimestamp(val);else + if (key === "txs_total") stats.setNumTxs(val);else + if (key === "fee_total") stats.setFeeTotal(BigInt(val));else + if (key === "histo") { + stats.setHisto(new Map()); + for (let elem of val) stats.getHisto().set(elem.bytes, elem.txs); + } else + console.log("WARNING: ignoring unexpected field in tx pool stats: " + key + ": " + val); + } + + // uninitialize some stats if not applicable + if (stats.getHisto98pc() === 0) stats.setHisto98pc(undefined); + if (stats.getNumTxs() === 0) { + stats.setBytesMin(undefined); + stats.setBytesMed(undefined); + stats.setBytesMax(undefined); + stats.setHisto98pc(undefined); + stats.setOldestTimestamp(undefined); + } + + return stats; + } + + static convertRpcAltChain(rpcChain) { + (0, _assert.default)(rpcChain); + let chain = new _MoneroAltChain.default(); + for (let key of Object.keys(rpcChain)) { + let val = rpcChain[key]; + if (key === "block_hash") {} // using block_hashes instead + else if (key === "difficulty") {} // handled by wide_difficulty + else if (key === "difficulty_top64") {} // handled by wide_difficulty + else if (key === "wide_difficulty") chain.setDifficulty(_GenUtils.default.reconcile(chain.getDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val)));else + if (key === "height") chain.setHeight(val);else + if (key === "length") chain.setLength(val);else + if (key === "block_hashes") chain.setBlockHashes(val);else + if (key === "main_chain_parent_block") chain.setMainChainParentBlockHash(val);else + console.log("WARNING: ignoring unexpected field in alternative chain: " + key + ": " + val); + } + return chain; + } + + static convertRpcPeer(rpcPeer) { + (0, _assert.default)(rpcPeer); + let peer = new _MoneroPeer.default(); + for (let key of Object.keys(rpcPeer)) { + let val = rpcPeer[key]; + if (key === "host") peer.setHost(val);else + if (key === "id") peer.setId("" + val); // TODO monero-wallet-rpc: peer id is BigInt but string in `get_connections` + else if (key === "ip") {} // host used instead which is consistently a string + else if (key === "last_seen") peer.setLastSeenTimestamp(val);else + if (key === "port") peer.setPort(val);else + if (key === "rpc_port") peer.setRpcPort(val);else + if (key === "pruning_seed") peer.setPruningSeed(val);else + if (key === "rpc_credits_per_hash") peer.setRpcCreditsPerHash(BigInt(val));else + console.log("WARNING: ignoring unexpected field in rpc peer: " + key + ": " + val); + } + return peer; + } + + static convertRpcConnection(rpcConnection) { + let peer = new _MoneroPeer.default(); + peer.setIsOnline(true); + for (let key of Object.keys(rpcConnection)) { + let val = rpcConnection[key]; + if (key === "address") peer.setAddress(val);else + if (key === "avg_download") peer.setAvgDownload(val);else + if (key === "avg_upload") peer.setAvgUpload(val);else + if (key === "connection_id") peer.setId(val);else + if (key === "current_download") peer.setCurrentDownload(val);else + if (key === "current_upload") peer.setCurrentUpload(val);else + if (key === "height") peer.setHeight(val);else + if (key === "host") peer.setHost(val);else + if (key === "ip") {} // host used instead which is consistently a string + else if (key === "incoming") peer.setIsIncoming(val);else + if (key === "live_time") peer.setLiveTime(val);else + if (key === "local_ip") peer.setIsLocalIp(val);else + if (key === "localhost") peer.setIsLocalHost(val);else + if (key === "peer_id") peer.setId(val);else + if (key === "port") peer.setPort(parseInt(val));else + if (key === "rpc_port") peer.setRpcPort(val);else + if (key === "recv_count") peer.setNumReceives(val);else + if (key === "recv_idle_time") peer.setReceiveIdleTime(val);else + if (key === "send_count") peer.setNumSends(val);else + if (key === "send_idle_time") peer.setSendIdleTime(val);else + if (key === "state") peer.setState(val);else + if (key === "support_flags") peer.setNumSupportFlags(val);else + if (key === "pruning_seed") peer.setPruningSeed(val);else + if (key === "rpc_credits_per_hash") peer.setRpcCreditsPerHash(BigInt(val));else + if (key === "address_type") peer.setType(val);else + console.log("WARNING: ignoring unexpected field in peer: " + key + ": " + val); + } + return peer; + } + + static convertToRpcBan(ban) { + let rpcBan = {}; + rpcBan.host = ban.getHost(); + rpcBan.ip = ban.getIp(); + rpcBan.ban = ban.getIsBanned(); + rpcBan.seconds = ban.getSeconds(); + return rpcBan; + } + + static convertRpcMiningStatus(rpcStatus) { + let status = new _MoneroMiningStatus.default(); + status.setIsActive(rpcStatus.active); + status.setSpeed(rpcStatus.speed); + status.setNumThreads(rpcStatus.threads_count); + if (rpcStatus.active) { + status.setAddress(rpcStatus.address); + status.setIsBackground(rpcStatus.is_background_mining_enabled); + } + return status; + } + + static convertRpcUpdateCheckResult(rpcResult) { + (0, _assert.default)(rpcResult); + let result = new _MoneroDaemonUpdateCheckResult.default(); + for (let key of Object.keys(rpcResult)) { + let val = rpcResult[key]; + if (key === "auto_uri") result.setAutoUri(val);else + if (key === "hash") result.setHash(val);else + if (key === "path") {} // handled elsewhere + else if (key === "status") {} // handled elsewhere + else if (key === "update") result.setIsUpdateAvailable(val);else + if (key === "user_uri") result.setUserUri(val);else + if (key === "version") result.setVersion(val);else + if (key === "untrusted") {} // handled elsewhere + else console.log("WARNING: ignoring unexpected field in rpc check update result: " + key + ": " + val); + } + if (result.getAutoUri() === "") result.setAutoUri(undefined); + if (result.getUserUri() === "") result.setUserUri(undefined); + if (result.getVersion() === "") result.setVersion(undefined); + if (result.getHash() === "") result.setHash(undefined); + return result; + } + + static convertRpcUpdateDownloadResult(rpcResult) { + let result = new _MoneroDaemonUpdateDownloadResult.default(MoneroDaemonRpc.convertRpcUpdateCheckResult(rpcResult)); + result.setDownloadPath(rpcResult["path"]); + if (result.getDownloadPath() === "") result.setDownloadPath(undefined); + return result; + } + + /** + * Converts a '0x' prefixed hexidecimal string to a bigint. + * + * @param {string} hex is the '0x' prefixed hexidecimal string to convert + * @return {bigint} the hexicedimal converted to decimal + */ + static prefixedHexToBI(hex) { + (0, _assert.default)(hex.substring(0, 2) === "0x"); + return BigInt(hex); + } +} + +/** + * Implements a MoneroDaemon by proxying requests to a worker. + * + * @private + */ +class MoneroDaemonRpcProxy { + + // state variables + + + + + + constructor(daemonId, worker) { + this.daemonId = daemonId; + this.worker = worker; + this.wrappedListeners = []; + } + + // --------------------------- STATIC UTILITIES ----------------------------- + + static async connect(config) { + let daemonId = _GenUtils.default.getUUID(); + config = Object.assign({}, config.toJson(), { proxyToWorker: false }); + await _LibraryUtils.default.invokeWorker(daemonId, "connectDaemonRpc", [config]); + return new MoneroDaemonRpcProxy(daemonId, await _LibraryUtils.default.getWorker()); + } + + // ---------------------------- INSTANCE METHODS ---------------------------- + + async addListener(listener) { + let wrappedListener = new DaemonWorkerListener(listener); + let listenerId = wrappedListener.getId(); + _LibraryUtils.default.addWorkerCallback(this.daemonId, "onBlockHeader_" + listenerId, [wrappedListener.onBlockHeader, wrappedListener]); + this.wrappedListeners.push(wrappedListener); + return this.invokeWorker("daemonAddListener", [listenerId]); + } + + async removeListener(listener) { + for (let i = 0; i < this.wrappedListeners.length; i++) { + if (this.wrappedListeners[i].getListener() === listener) { + let listenerId = this.wrappedListeners[i].getId(); + await this.invokeWorker("daemonRemoveListener", [listenerId]); + _LibraryUtils.default.removeWorkerCallback(this.daemonId, "onBlockHeader_" + listenerId); + this.wrappedListeners.splice(i, 1); + return; + } + } + throw new _MoneroError.default("Listener is not registered with daemon"); + } + + async getListeners() { + let listeners = []; + for (let wrappedListener of this.wrappedListeners) listeners.push(wrappedListener.getListener()); + return listeners; + } + + async getRpcConnection() { + let config = await this.invokeWorker("daemonGetRpcConnection"); + return new _MoneroRpcConnection.default(config); + } + + async isConnected() { + return this.invokeWorker("daemonIsConnected"); + } + + async getVersion() { + let versionJson = await this.invokeWorker("daemonGetVersion"); + return new _MoneroVersion.default(versionJson.number, versionJson.isRelease); + } + + async isTrusted() { + return this.invokeWorker("daemonIsTrusted"); + } + + async getHeight() { + return this.invokeWorker("daemonGetHeight"); + } + + async getBlockHash(height) { + return this.invokeWorker("daemonGetBlockHash", Array.from(arguments)); + } + + async getBlockTemplate(walletAddress, reserveSize) { + return new _MoneroBlockTemplate.default(await this.invokeWorker("daemonGetBlockTemplate", Array.from(arguments))); + } + + async getLastBlockHeader() { + return new _MoneroBlockHeader.default(await this.invokeWorker("daemonGetLastBlockHeader")); + } + + async getBlockHeaderByHash(blockHash) { + return new _MoneroBlockHeader.default(await this.invokeWorker("daemonGetBlockHeaderByHash", Array.from(arguments))); + } + + async getBlockHeaderByHeight(height) { + return new _MoneroBlockHeader.default(await this.invokeWorker("daemonGetBlockHeaderByHeight", Array.from(arguments))); + } + + async getBlockHeadersByRange(startHeight, endHeight) { + let blockHeadersJson = await this.invokeWorker("daemonGetBlockHeadersByRange", Array.from(arguments)); + let headers = []; + for (let blockHeaderJson of blockHeadersJson) headers.push(new _MoneroBlockHeader.default(blockHeaderJson)); + return headers; + } + + async getBlockByHash(blockHash) { + return new _MoneroBlock.default(await this.invokeWorker("daemonGetBlockByHash", Array.from(arguments)), _MoneroBlock.default.DeserializationType.TX); + } + + async getBlocksByHash(blockHashes, startHeight, prune) { + let blocksJson = await this.invokeWorker("daemonGetBlocksByHash", Array.from(arguments)); + let blocks = []; + for (let blockJson of blocksJson) blocks.push(new _MoneroBlock.default(blockJson)); + return blocks; + } + + async getBlockByHeight(height) { + return new _MoneroBlock.default(await this.invokeWorker("daemonGetBlockByHeight", Array.from(arguments)), _MoneroBlock.default.DeserializationType.TX); + } + + async getBlocksByHeight(heights) { + let blocksJson = await this.invokeWorker("daemonGetBlocksByHeight", Array.from(arguments)); + let blocks = []; + for (let blockJson of blocksJson) blocks.push(new _MoneroBlock.default(blockJson, _MoneroBlock.default.DeserializationType.TX)); + return blocks; + } + + async getBlocksByRange(startHeight, endHeight) { + let blocksJson = await this.invokeWorker("daemonGetBlocksByRange", Array.from(arguments)); + let blocks = []; + for (let blockJson of blocksJson) blocks.push(new _MoneroBlock.default(blockJson, _MoneroBlock.default.DeserializationType.TX)); + return blocks; + } + + async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) { + let blocksJson = await this.invokeWorker("daemonGetBlocksByRangeChunked", Array.from(arguments)); + let blocks = []; + for (let blockJson of blocksJson) blocks.push(new _MoneroBlock.default(blockJson, _MoneroBlock.default.DeserializationType.TX)); + return blocks; + } + + async getBlockHashes(blockHashes, startHeight) { + return this.invokeWorker("daemonGetBlockHashes", Array.from(arguments)); + } + + async getTxs(txHashes, prune = false) { + + // deserialize txs from blocks + let blocks = []; + for (let blockJson of await this.invokeWorker("daemonGetTxs", Array.from(arguments))) { + blocks.push(new _MoneroBlock.default(blockJson, _MoneroBlock.default.DeserializationType.TX)); + } + + // collect txs + let txs = []; + for (let block of blocks) { + for (let tx of block.getTxs()) { + if (!tx.getIsConfirmed()) tx.setBlock(undefined); + txs.push(tx); + } + } + return txs; + } + + async getTxHexes(txHashes, prune = false) { + return this.invokeWorker("daemonGetTxHexes", Array.from(arguments)); + } + + async getMinerTxSum(height, numBlocks) { + return new _MoneroMinerTxSum.default(await this.invokeWorker("daemonGetMinerTxSum", Array.from(arguments))); + } + + async getFeeEstimate(graceBlocks) { + return new _MoneroFeeEstimate.default(await this.invokeWorker("daemonGetFeeEstimate", Array.from(arguments))); + } + + async submitTxHex(txHex, doNotRelay) { + return new _MoneroSubmitTxResult.default(await this.invokeWorker("daemonSubmitTxHex", Array.from(arguments))); + } + + async relayTxsByHash(txHashes) { + return this.invokeWorker("daemonRelayTxsByHash", Array.from(arguments)); + } + + async getTxPool() { + let blockJson = await this.invokeWorker("daemonGetTxPool"); + let txs = new _MoneroBlock.default(blockJson, _MoneroBlock.default.DeserializationType.TX).getTxs(); + for (let tx of txs) tx.setBlock(undefined); + return txs ? txs : []; + } + + async getTxPoolHashes() { + return this.invokeWorker("daemonGetTxPoolHashes", Array.from(arguments)); + } + + async getTxPoolBacklog() { + throw new _MoneroError.default("Not implemented"); + } + + async getTxPoolStats() { + return new _MoneroTxPoolStats.default(await this.invokeWorker("daemonGetTxPoolStats")); + } + + async flushTxPool(hashes) { + return this.invokeWorker("daemonFlushTxPool", Array.from(arguments)); + } + + async getKeyImageSpentStatuses(keyImages) { + return this.invokeWorker("daemonGetKeyImageSpentStatuses", Array.from(arguments)); + } + + async getOutputs(outputs) { + throw new _MoneroError.default("Not implemented"); + } + + async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) { + let entries = []; + for (let entryJson of await this.invokeWorker("daemonGetOutputHistogram", [amounts, minCount, maxCount, isUnlocked, recentCutoff])) { + entries.push(new _MoneroOutputHistogramEntry.default(entryJson)); + } + return entries; + } + + async getOutputDistribution(amounts, cumulative, startHeight, endHeight) { + throw new _MoneroError.default("Not implemented"); + } + + async getInfo() { + return new _MoneroDaemonInfo.default(await this.invokeWorker("daemonGetInfo")); + } + + async getSyncInfo() { + return new _MoneroDaemonSyncInfo.default(await this.invokeWorker("daemonGetSyncInfo")); + } + + async getHardForkInfo() { + return new _MoneroHardForkInfo.default(await this.invokeWorker("daemonGetHardForkInfo")); + } + + async getAltChains() { + let altChains = []; + for (let altChainJson of await this.invokeWorker("daemonGetAltChains")) altChains.push(new _MoneroAltChain.default(altChainJson)); + return altChains; + } + + async getAltBlockHashes() { + return this.invokeWorker("daemonGetAltBlockHashes"); + } + + async getDownloadLimit() { + return this.invokeWorker("daemonGetDownloadLimit"); + } + + async setDownloadLimit(limit) { + return this.invokeWorker("daemonSetDownloadLimit", Array.from(arguments)); + } + + async resetDownloadLimit() { + return this.invokeWorker("daemonResetDownloadLimit"); + } + + async getUploadLimit() { + return this.invokeWorker("daemonGetUploadLimit"); + } + + async setUploadLimit(limit) { + return this.invokeWorker("daemonSetUploadLimit", Array.from(arguments)); + } + + async resetUploadLimit() { + return this.invokeWorker("daemonResetUploadLimit"); + } + + async getPeers() { + let peers = []; + for (let peerJson of await this.invokeWorker("daemonGetPeers")) peers.push(new _MoneroPeer.default(peerJson)); + return peers; + } + + async getKnownPeers() { + let peers = []; + for (let peerJson of await this.invokeWorker("daemonGetKnownPeers")) peers.push(new _MoneroPeer.default(peerJson)); + return peers; + } + + async setOutgoingPeerLimit(limit) { + return this.invokeWorker("daemonSetIncomingPeerLimit", Array.from(arguments)); + } + + async setIncomingPeerLimit(limit) { + return this.invokeWorker("daemonSetIncomingPeerLimit", Array.from(arguments)); + } + + async getPeerBans() { + let bans = []; + for (let banJson of await this.invokeWorker("daemonGetPeerBans")) bans.push(new _MoneroBan.default(banJson)); + return bans; + } + + async setPeerBans(bans) { + let bansJson = []; + for (let ban of bans) bansJson.push(ban.toJson()); + return this.invokeWorker("daemonSetPeerBans", [bansJson]); + } + + async startMining(address, numThreads, isBackground, ignoreBattery) { + return this.invokeWorker("daemonStartMining", Array.from(arguments)); + } + + async stopMining() { + await this.invokeWorker("daemonStopMining"); + } + + async getMiningStatus() { + return new _MoneroMiningStatus.default(await this.invokeWorker("daemonGetMiningStatus")); + } + + async submitBlocks(blockBlobs) { + return this.invokeWorker("daemonSubmitBlocks", Array.from(arguments)); + } + + async pruneBlockchain(check) { + return new _MoneroPruneResult.default(await this.invokeWorker("daemonPruneBlockchain")); + } + + async checkForUpdate() { + throw new _MoneroError.default("Not implemented"); + } + + async downloadUpdate(path) { + throw new _MoneroError.default("Not implemented"); + } + + async stop() { + while (this.wrappedListeners.length) await this.removeListener(this.wrappedListeners[0].getListener()); + return this.invokeWorker("daemonStop"); + } + + async waitForNextBlockHeader() { + return new _MoneroBlockHeader.default(await this.invokeWorker("daemonWaitForNextBlockHeader")); + } + + // --------------------------- PRIVATE HELPERS ------------------------------ + + // TODO: duplicated with MoneroWalletFullProxy + async invokeWorker(fnName, args) { + return _LibraryUtils.default.invokeWorker(this.daemonId, fnName, args); + } +} + +/** + * Polls a Monero daemon for updates and notifies listeners as they occur. + * + * @private + */ +class DaemonPoller { + + + + + + + constructor(daemon) { + let that = this; + this.daemon = daemon; + this.looper = new _TaskLooper.default(async function () {await that.poll();}); + } + + setIsPolling(isPolling) { + this.isPolling = isPolling; + if (isPolling) this.looper.start(this.daemon.getPollInterval());else + this.looper.stop(); + } + + async poll() { + try { + + // get latest block header + let header = await this.daemon.getLastBlockHeader(); + + // save first header for comparison + if (!this.lastHeader) { + this.lastHeader = await this.daemon.getLastBlockHeader(); + return; + } + + // compare header to last + if (header.getHash() !== this.lastHeader.getHash()) { + this.lastHeader = header; + await this.announceBlockHeader(header); + } + } catch (err) { + console.error("Failed to background poll daemon header"); + console.error(err); + } + } + + async announceBlockHeader(header) { + for (let listener of await this.daemon.getListeners()) { + try { + await listener.onBlockHeader(header); // notify listener + } catch (err) { + console.error("Error calling listener on block header", err); + } + } + } +} + +/** + * Internal listener to bridge notifications to external listeners. + * + * @private + */ +class DaemonWorkerListener { + + + + + constructor(listener) { + this.id = _GenUtils.default.getUUID(); + this.listener = listener; + } + + getId() { + return this.id; + } + + getListener() { + return this.listener; + } + + async onBlockHeader(headerJson) { + this.listener.onBlockHeader(new _MoneroBlockHeader.default(headerJson)); + } +}var _default = exports.default = + +MoneroDaemonRpc; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTGlicmFyeVV0aWxzIiwiX1Rhc2tMb29wZXIiLCJfTW9uZXJvQWx0Q2hhaW4iLCJfTW9uZXJvQmFuIiwiX01vbmVyb0Jsb2NrIiwiX01vbmVyb0Jsb2NrSGVhZGVyIiwiX01vbmVyb0Jsb2NrVGVtcGxhdGUiLCJfTW9uZXJvQ29ubmVjdGlvblNwYW4iLCJfTW9uZXJvRGFlbW9uIiwiX01vbmVyb0RhZW1vbkNvbmZpZyIsIl9Nb25lcm9EYWVtb25JbmZvIiwiX01vbmVyb0RhZW1vbkxpc3RlbmVyIiwiX01vbmVyb0RhZW1vblN5bmNJbmZvIiwiX01vbmVyb0RhZW1vblVwZGF0ZUNoZWNrUmVzdWx0IiwiX01vbmVyb0RhZW1vblVwZGF0ZURvd25sb2FkUmVzdWx0IiwiX01vbmVyb0ZlZUVzdGltYXRlIiwiX01vbmVyb0Vycm9yIiwiX01vbmVyb0hhcmRGb3JrSW5mbyIsIl9Nb25lcm9LZXlJbWFnZSIsIl9Nb25lcm9NaW5lclR4U3VtIiwiX01vbmVyb01pbmluZ1N0YXR1cyIsIl9Nb25lcm9OZXR3b3JrVHlwZSIsIl9Nb25lcm9PdXRwdXQiLCJfTW9uZXJvT3V0cHV0SGlzdG9ncmFtRW50cnkiLCJfTW9uZXJvUGVlciIsIl9Nb25lcm9QcnVuZVJlc3VsdCIsIl9Nb25lcm9ScGNDb25uZWN0aW9uIiwiX01vbmVyb1N1Ym1pdFR4UmVzdWx0IiwiX01vbmVyb1R4IiwiX01vbmVyb1R4UG9vbFN0YXRzIiwiX01vbmVyb1V0aWxzIiwiX01vbmVyb1ZlcnNpb24iLCJNb25lcm9EYWVtb25ScGMiLCJNb25lcm9EYWVtb24iLCJNQVhfUkVRX1NJWkUiLCJERUZBVUxUX0lEIiwiTlVNX0hFQURFUlNfUEVSX1JFUSIsIkRFRkFVTFRfUE9MTF9QRVJJT0QiLCJjb25zdHJ1Y3RvciIsImNvbmZpZyIsInByb3h5RGFlbW9uIiwicHJveHlUb1dvcmtlciIsImxpc3RlbmVycyIsImNhY2hlZEhlYWRlcnMiLCJnZXRQcm9jZXNzIiwicHJvY2VzcyIsInN0b3BQcm9jZXNzIiwiZm9yY2UiLCJ1bmRlZmluZWQiLCJNb25lcm9FcnJvciIsImxpc3RlbmVyc0NvcHkiLCJHZW5VdGlscyIsImNvcHlBcnJheSIsImdldExpc3RlbmVycyIsImxpc3RlbmVyIiwicmVtb3ZlTGlzdGVuZXIiLCJraWxsUHJvY2VzcyIsImFkZExpc3RlbmVyIiwiYXNzZXJ0IiwiTW9uZXJvRGFlbW9uTGlzdGVuZXIiLCJwdXNoIiwicmVmcmVzaExpc3RlbmluZyIsImlkeCIsImluZGV4T2YiLCJzcGxpY2UiLCJnZXRScGNDb25uZWN0aW9uIiwiZ2V0U2VydmVyIiwiaXNDb25uZWN0ZWQiLCJnZXRWZXJzaW9uIiwiZSIsInJlc3AiLCJzZW5kSnNvblJlcXVlc3QiLCJjaGVja1Jlc3BvbnNlU3RhdHVzIiwicmVzdWx0IiwiTW9uZXJvVmVyc2lvbiIsInZlcnNpb24iLCJyZWxlYXNlIiwiaXNUcnVzdGVkIiwic2VuZFBhdGhSZXF1ZXN0IiwidW50cnVzdGVkIiwiZ2V0SGVpZ2h0IiwiY291bnQiLCJnZXRCbG9ja0hhc2giLCJoZWlnaHQiLCJnZXRCbG9ja1RlbXBsYXRlIiwid2FsbGV0QWRkcmVzcyIsInJlc2VydmVTaXplIiwid2FsbGV0X2FkZHJlc3MiLCJyZXNlcnZlX3NpemUiLCJjb252ZXJ0UnBjQmxvY2tUZW1wbGF0ZSIsImdldExhc3RCbG9ja0hlYWRlciIsImNvbnZlcnRScGNCbG9ja0hlYWRlciIsImJsb2NrX2hlYWRlciIsImdldEJsb2NrSGVhZGVyQnlIYXNoIiwiYmxvY2tIYXNoIiwiaGFzaCIsImdldEJsb2NrSGVhZGVyQnlIZWlnaHQiLCJnZXRCbG9ja0hlYWRlcnNCeVJhbmdlIiwic3RhcnRIZWlnaHQiLCJlbmRIZWlnaHQiLCJzdGFydF9oZWlnaHQiLCJlbmRfaGVpZ2h0IiwiaGVhZGVycyIsInJwY0hlYWRlciIsImdldEJsb2NrQnlIYXNoIiwiY29udmVydFJwY0Jsb2NrIiwiZ2V0QmxvY2tCeUhlaWdodCIsImdldEJsb2Nrc0J5SGVpZ2h0IiwiaGVpZ2h0cyIsInJlc3BCaW4iLCJzZW5kQmluYXJ5UmVxdWVzdCIsInJwY0Jsb2NrcyIsIk1vbmVyb1V0aWxzIiwiYmluYXJ5QmxvY2tzVG9Kc29uIiwiZXF1YWwiLCJ0eHMiLCJsZW5ndGgiLCJibG9ja3MiLCJibG9ja0lkeCIsImJsb2NrIiwic2V0SGVpZ2h0IiwidHhJZHgiLCJ0eCIsIk1vbmVyb1R4Iiwic2V0SGFzaCIsInR4X2hhc2hlcyIsInNldElzQ29uZmlybWVkIiwic2V0SW5UeFBvb2wiLCJzZXRJc01pbmVyVHgiLCJzZXRSZWxheSIsInNldElzUmVsYXllZCIsInNldElzRmFpbGVkIiwic2V0SXNEb3VibGVTcGVuZFNlZW4iLCJjb252ZXJ0UnBjVHgiLCJzZXRUeHMiLCJnZXRCbG9jayIsIm1lcmdlIiwiZ2V0VHhzIiwic2V0QmxvY2siLCJnZXRCbG9ja3NCeVJhbmdlIiwiZ2V0QmxvY2tzQnlSYW5nZUNodW5rZWQiLCJtYXhDaHVua1NpemUiLCJsYXN0SGVpZ2h0IiwiZ2V0TWF4QmxvY2tzIiwidHhIYXNoZXMiLCJwcnVuZSIsIkFycmF5IiwiaXNBcnJheSIsInR4c19oYXNoZXMiLCJkZWNvZGVfYXNfanNvbiIsIm1lc3NhZ2UiLCJnZXRUeEhleGVzIiwiaGV4ZXMiLCJnZXRQcnVuZWRIZXgiLCJnZXRGdWxsSGV4IiwiZ2V0TWluZXJUeFN1bSIsIm51bUJsb2NrcyIsInR4U3VtIiwiTW9uZXJvTWluZXJUeFN1bSIsInNldEVtaXNzaW9uU3VtIiwiQmlnSW50IiwiZW1pc3Npb25fYW1vdW50Iiwic2V0RmVlU3VtIiwiZmVlX2Ftb3VudCIsImdldEZlZUVzdGltYXRlIiwiZ3JhY2VCbG9ja3MiLCJncmFjZV9ibG9ja3MiLCJmZWVFc3RpbWF0ZSIsIk1vbmVyb0ZlZUVzdGltYXRlIiwic2V0RmVlIiwiZmVlIiwic2V0UXVhbnRpemF0aW9uTWFzayIsInF1YW50aXphdGlvbl9tYXNrIiwiZmVlcyIsImkiLCJzZXRGZWVzIiwic3VibWl0VHhIZXgiLCJ0eEhleCIsImRvTm90UmVsYXkiLCJ0eF9hc19oZXgiLCJkb19ub3RfcmVsYXkiLCJjb252ZXJ0UnBjU3VibWl0VHhSZXN1bHQiLCJzZXRJc0dvb2QiLCJyZWxheVR4c0J5SGFzaCIsInR4aWRzIiwiZ2V0VHhQb29sIiwidHJhbnNhY3Rpb25zIiwicnBjVHgiLCJzZXROdW1Db25maXJtYXRpb25zIiwiZ2V0VHhQb29sSGFzaGVzIiwiZ2V0VHhQb29sU3RhdHMiLCJjb252ZXJ0UnBjVHhQb29sU3RhdHMiLCJwb29sX3N0YXRzIiwiZmx1c2hUeFBvb2wiLCJoYXNoZXMiLCJsaXN0aWZ5IiwiZ2V0S2V5SW1hZ2VTcGVudFN0YXR1c2VzIiwia2V5SW1hZ2VzIiwia2V5X2ltYWdlcyIsInNwZW50X3N0YXR1cyIsImdldE91dHB1dEhpc3RvZ3JhbSIsImFtb3VudHMiLCJtaW5Db3VudCIsIm1heENvdW50IiwiaXNVbmxvY2tlZCIsInJlY2VudEN1dG9mZiIsIm1pbl9jb3VudCIsIm1heF9jb3VudCIsInVubG9ja2VkIiwicmVjZW50X2N1dG9mZiIsImVudHJpZXMiLCJoaXN0b2dyYW0iLCJycGNFbnRyeSIsImNvbnZlcnRScGNPdXRwdXRIaXN0b2dyYW1FbnRyeSIsImdldE91dHB1dERpc3RyaWJ1dGlvbiIsImN1bXVsYXRpdmUiLCJnZXRJbmZvIiwiY29udmVydFJwY0luZm8iLCJnZXRTeW5jSW5mbyIsImNvbnZlcnRScGNTeW5jSW5mbyIsImdldEhhcmRGb3JrSW5mbyIsImNvbnZlcnRScGNIYXJkRm9ya0luZm8iLCJnZXRBbHRDaGFpbnMiLCJjaGFpbnMiLCJycGNDaGFpbiIsImNvbnZlcnRScGNBbHRDaGFpbiIsImdldEFsdEJsb2NrSGFzaGVzIiwiYmxrc19oYXNoZXMiLCJnZXREb3dubG9hZExpbWl0IiwiZ2V0QmFuZHdpZHRoTGltaXRzIiwic2V0RG93bmxvYWRMaW1pdCIsImxpbWl0IiwicmVzZXREb3dubG9hZExpbWl0IiwiaXNJbnQiLCJzZXRCYW5kd2lkdGhMaW1pdHMiLCJnZXRVcGxvYWRMaW1pdCIsInNldFVwbG9hZExpbWl0IiwicmVzZXRVcGxvYWRMaW1pdCIsImdldFBlZXJzIiwicGVlcnMiLCJjb25uZWN0aW9ucyIsInJwY0Nvbm5lY3Rpb24iLCJjb252ZXJ0UnBjQ29ubmVjdGlvbiIsImdldEtub3duUGVlcnMiLCJncmF5X2xpc3QiLCJycGNQZWVyIiwicGVlciIsImNvbnZlcnRScGNQZWVyIiwic2V0SXNPbmxpbmUiLCJ3aGl0ZV9saXN0Iiwic2V0T3V0Z29pbmdQZWVyTGltaXQiLCJvdXRfcGVlcnMiLCJzZXRJbmNvbWluZ1BlZXJMaW1pdCIsImluX3BlZXJzIiwiZ2V0UGVlckJhbnMiLCJiYW5zIiwicnBjQmFuIiwiYmFuIiwiTW9uZXJvQmFuIiwic2V0SG9zdCIsImhvc3QiLCJzZXRJcCIsImlwIiwic2V0U2Vjb25kcyIsInNlY29uZHMiLCJzZXRQZWVyQmFucyIsInJwY0JhbnMiLCJjb252ZXJ0VG9ScGNCYW4iLCJzdGFydE1pbmluZyIsImFkZHJlc3MiLCJudW1UaHJlYWRzIiwiaXNCYWNrZ3JvdW5kIiwiaWdub3JlQmF0dGVyeSIsIm1pbmVyX2FkZHJlc3MiLCJ0aHJlYWRzX2NvdW50IiwiZG9fYmFja2dyb3VuZF9taW5pbmciLCJpZ25vcmVfYmF0dGVyeSIsInN0b3BNaW5pbmciLCJnZXRNaW5pbmdTdGF0dXMiLCJjb252ZXJ0UnBjTWluaW5nU3RhdHVzIiwic3VibWl0QmxvY2tzIiwiYmxvY2tCbG9icyIsInBydW5lQmxvY2tjaGFpbiIsImNoZWNrIiwiTW9uZXJvUHJ1bmVSZXN1bHQiLCJzZXRJc1BydW5lZCIsInBydW5lZCIsInNldFBydW5pbmdTZWVkIiwicHJ1bmluZ19zZWVkIiwiY2hlY2tGb3JVcGRhdGUiLCJjb21tYW5kIiwiY29udmVydFJwY1VwZGF0ZUNoZWNrUmVzdWx0IiwiZG93bmxvYWRVcGRhdGUiLCJwYXRoIiwiY29udmVydFJwY1VwZGF0ZURvd25sb2FkUmVzdWx0Iiwic3RvcCIsIndhaXRGb3JOZXh0QmxvY2tIZWFkZXIiLCJ0aGF0IiwiUHJvbWlzZSIsInJlc29sdmUiLCJvbkJsb2NrSGVhZGVyIiwiaGVhZGVyIiwiZ2V0UG9sbEludGVydmFsIiwicG9sbEludGVydmFsIiwiZ2V0VHgiLCJ0eEhhc2giLCJnZXRUeEhleCIsImdldEtleUltYWdlU3BlbnRTdGF0dXMiLCJrZXlJbWFnZSIsInNldFBlZXJCYW4iLCJzdWJtaXRCbG9jayIsImJsb2NrQmxvYiIsInBvbGxMaXN0ZW5lciIsIkRhZW1vblBvbGxlciIsInNldElzUG9sbGluZyIsImxpbWl0X2Rvd24iLCJsaW1pdF91cCIsImRvd25MaW1pdCIsInVwTGltaXQiLCJtYXhIZWlnaHQiLCJtYXhSZXFTaXplIiwicmVxU2l6ZSIsImdldEJsb2NrSGVhZGVyQnlIZWlnaHRDYWNoZWQiLCJnZXRTaXplIiwiY2FjaGVkSGVhZGVyIiwiTWF0aCIsIm1pbiIsImNvbm5lY3RUb0RhZW1vblJwYyIsInVyaU9yQ29uZmlnIiwidXNlcm5hbWUiLCJwYXNzd29yZCIsIm5vcm1hbGl6ZUNvbmZpZyIsImNtZCIsInN0YXJ0TW9uZXJvZFByb2Nlc3MiLCJNb25lcm9EYWVtb25ScGNQcm94eSIsImNvbm5lY3QiLCJjaGlsZFByb2Nlc3MiLCJzcGF3biIsInNsaWNlIiwiZW52IiwiTEFORyIsInN0ZG91dCIsInNldEVuY29kaW5nIiwic3RkZXJyIiwidXJpIiwib3V0cHV0IiwicmVqZWN0Iiwib24iLCJkYXRhIiwibGluZSIsInRvU3RyaW5nIiwiTGlicmFyeVV0aWxzIiwibG9nIiwidXJpTGluZUNvbnRhaW5zIiwidXJpTGluZUNvbnRhaW5zSWR4Iiwic3Vic3RyaW5nIiwibGFzdEluZGV4T2YiLCJ1bmZvcm1hdHRlZExpbmUiLCJyZXBsYWNlIiwidHJpbSIsInBvcnQiLCJzc2xJZHgiLCJzc2xFbmFibGVkIiwidG9Mb3dlckNhc2UiLCJ1c2VyUGFzc0lkeCIsInVzZXJQYXNzIiwiY29weSIsInNldFNlcnZlciIsInJlamVjdFVuYXV0aG9yaXplZCIsImdldFJlamVjdFVuYXV0aG9yaXplZCIsInNldFByb3h5VG9Xb3JrZXIiLCJkYWVtb24iLCJpc1Jlc29sdmVkIiwiZ2V0TG9nTGV2ZWwiLCJjb25zb2xlIiwiZXJyb3IiLCJjb2RlIiwiRXJyb3IiLCJlcnIiLCJvcmlnaW4iLCJNb25lcm9EYWVtb25Db25maWciLCJzZXJ2ZXIiLCJNb25lcm9ScGNDb25uZWN0aW9uIiwiREVGQVVMVF9DT05GSUciLCJzdGF0dXMiLCJNb25lcm9CbG9ja0hlYWRlciIsImtleSIsIk9iamVjdCIsImtleXMiLCJ2YWwiLCJzYWZlU2V0Iiwic2V0U2l6ZSIsImdldERlcHRoIiwic2V0RGVwdGgiLCJzZXREaWZmaWN1bHR5IiwicmVjb25jaWxlIiwiZ2V0RGlmZmljdWx0eSIsInByZWZpeGVkSGV4VG9CSSIsInNldEN1bXVsYXRpdmVEaWZmaWN1bHR5IiwiZ2V0Q3VtdWxhdGl2ZURpZmZpY3VsdHkiLCJnZXRIYXNoIiwiZ2V0TWFqb3JWZXJzaW9uIiwic2V0TWFqb3JWZXJzaW9uIiwiZ2V0TWlub3JWZXJzaW9uIiwic2V0TWlub3JWZXJzaW9uIiwiZ2V0Tm9uY2UiLCJzZXROb25jZSIsImdldE51bVR4cyIsInNldE51bVR4cyIsImdldE9ycGhhblN0YXR1cyIsInNldE9ycGhhblN0YXR1cyIsImdldFByZXZIYXNoIiwic2V0UHJldkhhc2giLCJnZXRSZXdhcmQiLCJzZXRSZXdhcmQiLCJnZXRUaW1lc3RhbXAiLCJzZXRUaW1lc3RhbXAiLCJnZXRXZWlnaHQiLCJzZXRXZWlnaHQiLCJnZXRMb25nVGVybVdlaWdodCIsInNldExvbmdUZXJtV2VpZ2h0IiwiZ2V0UG93SGFzaCIsInNldFBvd0hhc2giLCJzZXRNaW5lclR4SGFzaCIsInJwY0Jsb2NrIiwiTW9uZXJvQmxvY2siLCJzZXRIZXgiLCJibG9iIiwic2V0VHhIYXNoZXMiLCJycGNNaW5lclR4IiwianNvbiIsIkpTT04iLCJwYXJzZSIsIm1pbmVyX3R4IiwibWluZXJUeCIsInNldE1pbmVyVHgiLCJnZXRMYXN0UmVsYXllZFRpbWVzdGFtcCIsInNldExhc3RSZWxheWVkVGltZXN0YW1wIiwiZ2V0UmVjZWl2ZWRUaW1lc3RhbXAiLCJzZXRSZWNlaXZlZFRpbWVzdGFtcCIsImdldE51bUNvbmZpcm1hdGlvbnMiLCJnZXRJc0NvbmZpcm1lZCIsImdldEluVHhQb29sIiwiZ2V0SXNEb3VibGVTcGVuZFNlZW4iLCJzZXRWZXJzaW9uIiwiZ2V0RXh0cmEiLCJzZXRFeHRyYSIsIlVpbnQ4QXJyYXkiLCJnZW4iLCJzZXRJbnB1dHMiLCJtYXAiLCJycGNWaW4iLCJjb252ZXJ0UnBjT3V0cHV0Iiwic2V0T3V0cHV0cyIsInJwY091dHB1dCIsImdldFJjdFNpZ25hdHVyZXMiLCJzZXRSY3RTaWduYXR1cmVzIiwidHhuRmVlIiwiZ2V0RmVlIiwiZ2V0UmN0U2lnUHJ1bmFibGUiLCJzZXRSY3RTaWdQcnVuYWJsZSIsImdldFVubG9ja1RpbWUiLCJzZXRVbmxvY2tUaW1lIiwic2V0RnVsbEhleCIsImdldElzUmVsYXllZCIsImdldE91dHB1dEluZGljZXMiLCJzZXRPdXRwdXRJbmRpY2VzIiwiZ2V0UmVsYXkiLCJnZXRJc0tlcHRCeUJsb2NrIiwic2V0SXNLZXB0QnlCbG9jayIsImdldFNpZ25hdHVyZXMiLCJzZXRTaWduYXR1cmVzIiwiZ2V0SXNGYWlsZWQiLCJnZXRMYXN0RmFpbGVkSGVpZ2h0Iiwic2V0TGFzdEZhaWxlZEhlaWdodCIsImdldExhc3RGYWlsZWRIYXNoIiwic2V0TGFzdEZhaWxlZEhhc2giLCJnZXRNYXhVc2VkQmxvY2tIZWlnaHQiLCJzZXRNYXhVc2VkQmxvY2tIZWlnaHQiLCJnZXRNYXhVc2VkQmxvY2tIYXNoIiwic2V0TWF4VXNlZEJsb2NrSGFzaCIsImdldFBydW5hYmxlSGFzaCIsInNldFBydW5hYmxlSGFzaCIsImdldFBydW5hYmxlSGV4Iiwic2V0UHJ1bmFibGVIZXgiLCJzZXRQcnVuZWRIZXgiLCJnZXRPdXRwdXRzIiwic2V0SW5kZXgiLCJhc19qc29uIiwidHhfanNvbiIsIk1vbmVyb091dHB1dCIsInNldFR4IiwiZ2V0QW1vdW50Iiwic2V0QW1vdW50IiwiYW1vdW50IiwiZ2V0S2V5SW1hZ2UiLCJzZXRLZXlJbWFnZSIsIk1vbmVyb0tleUltYWdlIiwia19pbWFnZSIsImdldFJpbmdPdXRwdXRJbmRpY2VzIiwic2V0UmluZ091dHB1dEluZGljZXMiLCJrZXlfb2Zmc2V0cyIsInB1YktleSIsInRhZ2dlZF9rZXkiLCJnZXRTdGVhbHRoUHVibGljS2V5Iiwic2V0U3RlYWx0aFB1YmxpY0tleSIsInJwY1RlbXBsYXRlIiwidGVtcGxhdGUiLCJNb25lcm9CbG9ja1RlbXBsYXRlIiwic2V0QmxvY2tIYXNoaW5nQmxvYiIsInNldEJsb2NrVGVtcGxhdGVCbG9iIiwic2V0RXhwZWN0ZWRSZXdhcmQiLCJzZXRSZXNlcnZlZE9mZnNldCIsInNldFNlZWRIZWlnaHQiLCJzZXRTZWVkSGFzaCIsInNldE5leHRTZWVkSGFzaCIsImdldE5leHRTZWVkSGFzaCIsInJwY0luZm8iLCJpbmZvIiwiTW9uZXJvRGFlbW9uSW5mbyIsInNldE51bUFsdEJsb2NrcyIsInNldEJsb2NrU2l6ZUxpbWl0Iiwic2V0QmxvY2tTaXplTWVkaWFuIiwic2V0QmxvY2tXZWlnaHRMaW1pdCIsInNldEJsb2NrV2VpZ2h0TWVkaWFuIiwic2V0Qm9vdHN0cmFwRGFlbW9uQWRkcmVzcyIsInNldEZyZWVTcGFjZSIsInNldERhdGFiYXNlU2l6ZSIsInNldE51bU9mZmxpbmVQZWVycyIsInNldEhlaWdodFdpdGhvdXRCb290c3RyYXAiLCJzZXROdW1JbmNvbWluZ0Nvbm5lY3Rpb25zIiwic2V0SXNPZmZsaW5lIiwic2V0TnVtT3V0Z29pbmdDb25uZWN0aW9ucyIsInNldE51bVJwY0Nvbm5lY3Rpb25zIiwic2V0U3RhcnRUaW1lc3RhbXAiLCJzZXRBZGp1c3RlZFRpbWVzdGFtcCIsInNldFRhcmdldCIsInNldFRhcmdldEhlaWdodCIsInNldFRvcEJsb2NrSGFzaCIsInNldE51bVR4c1Bvb2wiLCJzZXRXYXNCb290c3RyYXBFdmVyVXNlZCIsInNldE51bU9ubGluZVBlZXJzIiwic2V0VXBkYXRlQXZhaWxhYmxlIiwiZ2V0TmV0d29ya1R5cGUiLCJzZXROZXR3b3JrVHlwZSIsIk1vbmVyb05ldHdvcmtUeXBlIiwiTUFJTk5FVCIsIlRFU1RORVQiLCJTVEFHRU5FVCIsInNldENyZWRpdHMiLCJnZXRUb3BCbG9ja0hhc2giLCJzZXRJc0J1c3lTeW5jaW5nIiwic2V0SXNTeW5jaHJvbml6ZWQiLCJzZXRJc1Jlc3RyaWN0ZWQiLCJycGNTeW5jSW5mbyIsInN5bmNJbmZvIiwiTW9uZXJvRGFlbW9uU3luY0luZm8iLCJzZXRQZWVycyIsInJwY0Nvbm5lY3Rpb25zIiwic2V0U3BhbnMiLCJycGNTcGFucyIsInJwY1NwYW4iLCJnZXRTcGFucyIsImNvbnZlcnRScGNDb25uZWN0aW9uU3BhbiIsInNldE5leHROZWVkZWRQcnVuaW5nU2VlZCIsIm92ZXJ2aWV3IiwicnBjSGFyZEZvcmtJbmZvIiwiTW9uZXJvSGFyZEZvcmtJbmZvIiwic2V0RWFybGllc3RIZWlnaHQiLCJzZXRJc0VuYWJsZWQiLCJzZXRTdGF0ZSIsInNldFRocmVzaG9sZCIsInNldE51bVZvdGVzIiwic2V0Vm90aW5nIiwic2V0V2luZG93IiwicnBjQ29ubmVjdGlvblNwYW4iLCJzcGFuIiwiTW9uZXJvQ29ubmVjdGlvblNwYW4iLCJzZXRDb25uZWN0aW9uSWQiLCJzZXROdW1CbG9ja3MiLCJzZXRSYXRlIiwic2V0UmVtb3RlQWRkcmVzcyIsInNldFNwZWVkIiwic2V0U3RhcnRIZWlnaHQiLCJlbnRyeSIsIk1vbmVyb091dHB1dEhpc3RvZ3JhbUVudHJ5Iiwic2V0TnVtSW5zdGFuY2VzIiwic2V0TnVtVW5sb2NrZWRJbnN0YW5jZXMiLCJzZXROdW1SZWNlbnRJbnN0YW5jZXMiLCJycGNSZXN1bHQiLCJNb25lcm9TdWJtaXRUeFJlc3VsdCIsInNldElzRmVlVG9vTG93Iiwic2V0SGFzSW52YWxpZElucHV0Iiwic2V0SGFzSW52YWxpZE91dHB1dCIsInNldEhhc1Rvb0Zld091dHB1dHMiLCJzZXRJc01peGluVG9vTG93Iiwic2V0SXNPdmVyc3BlbmQiLCJzZXRSZWFzb24iLCJzZXRJc1Rvb0JpZyIsInNldFNhbml0eUNoZWNrRmFpbGVkIiwic2V0SXNUeEV4dHJhVG9vQmlnIiwic2V0SXNOb256ZXJvVW5sb2NrVGltZSIsInJwY1N0YXRzIiwic3RhdHMiLCJNb25lcm9UeFBvb2xTdGF0cyIsInNldEJ5dGVzTWF4Iiwic2V0Qnl0ZXNNZWQiLCJzZXRCeXRlc01pbiIsInNldEJ5dGVzVG90YWwiLCJzZXRIaXN0bzk4cGMiLCJzZXROdW0xMG0iLCJzZXROdW1Eb3VibGVTcGVuZHMiLCJzZXROdW1GYWlsaW5nIiwic2V0TnVtTm90UmVsYXllZCIsInNldE9sZGVzdFRpbWVzdGFtcCIsInNldEZlZVRvdGFsIiwic2V0SGlzdG8iLCJNYXAiLCJlbGVtIiwiZ2V0SGlzdG8iLCJzZXQiLCJieXRlcyIsImdldEhpc3RvOThwYyIsImNoYWluIiwiTW9uZXJvQWx0Q2hhaW4iLCJzZXRMZW5ndGgiLCJzZXRCbG9ja0hhc2hlcyIsInNldE1haW5DaGFpblBhcmVudEJsb2NrSGFzaCIsIk1vbmVyb1BlZXIiLCJzZXRJZCIsInNldExhc3RTZWVuVGltZXN0YW1wIiwic2V0UG9ydCIsInNldFJwY1BvcnQiLCJzZXRScGNDcmVkaXRzUGVySGFzaCIsInNldEFkZHJlc3MiLCJzZXRBdmdEb3dubG9hZCIsInNldEF2Z1VwbG9hZCIsInNldEN1cnJlbnREb3dubG9hZCIsInNldEN1cnJlbnRVcGxvYWQiLCJzZXRJc0luY29taW5nIiwic2V0TGl2ZVRpbWUiLCJzZXRJc0xvY2FsSXAiLCJzZXRJc0xvY2FsSG9zdCIsInBhcnNlSW50Iiwic2V0TnVtUmVjZWl2ZXMiLCJzZXRSZWNlaXZlSWRsZVRpbWUiLCJzZXROdW1TZW5kcyIsInNldFNlbmRJZGxlVGltZSIsInNldE51bVN1cHBvcnRGbGFncyIsInNldFR5cGUiLCJnZXRIb3N0IiwiZ2V0SXAiLCJnZXRJc0Jhbm5lZCIsImdldFNlY29uZHMiLCJycGNTdGF0dXMiLCJNb25lcm9NaW5pbmdTdGF0dXMiLCJzZXRJc0FjdGl2ZSIsImFjdGl2ZSIsInNwZWVkIiwic2V0TnVtVGhyZWFkcyIsInNldElzQmFja2dyb3VuZCIsImlzX2JhY2tncm91bmRfbWluaW5nX2VuYWJsZWQiLCJNb25lcm9EYWVtb25VcGRhdGVDaGVja1Jlc3VsdCIsInNldEF1dG9VcmkiLCJzZXRJc1VwZGF0ZUF2YWlsYWJsZSIsInNldFVzZXJVcmkiLCJnZXRBdXRvVXJpIiwiZ2V0VXNlclVyaSIsIk1vbmVyb0RhZW1vblVwZGF0ZURvd25sb2FkUmVzdWx0Iiwic2V0RG93bmxvYWRQYXRoIiwiZ2V0RG93bmxvYWRQYXRoIiwiaGV4IiwiZGFlbW9uSWQiLCJ3b3JrZXIiLCJ3cmFwcGVkTGlzdGVuZXJzIiwiZ2V0VVVJRCIsImFzc2lnbiIsInRvSnNvbiIsImludm9rZVdvcmtlciIsImdldFdvcmtlciIsIndyYXBwZWRMaXN0ZW5lciIsIkRhZW1vbldvcmtlckxpc3RlbmVyIiwibGlzdGVuZXJJZCIsImdldElkIiwiYWRkV29ya2VyQ2FsbGJhY2siLCJnZXRMaXN0ZW5lciIsInJlbW92ZVdvcmtlckNhbGxiYWNrIiwidmVyc2lvbkpzb24iLCJudW1iZXIiLCJpc1JlbGVhc2UiLCJmcm9tIiwiYXJndW1lbnRzIiwiYmxvY2tIZWFkZXJzSnNvbiIsImJsb2NrSGVhZGVySnNvbiIsIkRlc2VyaWFsaXphdGlvblR5cGUiLCJUWCIsImdldEJsb2Nrc0J5SGFzaCIsImJsb2NrSGFzaGVzIiwiYmxvY2tzSnNvbiIsImJsb2NrSnNvbiIsImdldEJsb2NrSGFzaGVzIiwiZ2V0VHhQb29sQmFja2xvZyIsIm91dHB1dHMiLCJlbnRyeUpzb24iLCJhbHRDaGFpbnMiLCJhbHRDaGFpbkpzb24iLCJwZWVySnNvbiIsImJhbkpzb24iLCJiYW5zSnNvbiIsImZuTmFtZSIsImFyZ3MiLCJsb29wZXIiLCJUYXNrTG9vcGVyIiwicG9sbCIsImlzUG9sbGluZyIsInN0YXJ0IiwibGFzdEhlYWRlciIsImFubm91bmNlQmxvY2tIZWFkZXIiLCJpZCIsImhlYWRlckpzb24iLCJfZGVmYXVsdCIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvZGFlbW9uL01vbmVyb0RhZW1vblJwYy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi4vY29tbW9uL0dlblV0aWxzXCI7XG5pbXBvcnQgTGlicmFyeVV0aWxzIGZyb20gXCIuLi9jb21tb24vTGlicmFyeVV0aWxzXCI7XG5pbXBvcnQgVGFza0xvb3BlciBmcm9tIFwiLi4vY29tbW9uL1Rhc2tMb29wZXJcIjtcbmltcG9ydCBNb25lcm9BbHRDaGFpbiBmcm9tIFwiLi9tb2RlbC9Nb25lcm9BbHRDaGFpblwiO1xuaW1wb3J0IE1vbmVyb0JhbiBmcm9tIFwiLi9tb2RlbC9Nb25lcm9CYW5cIjtcbmltcG9ydCBNb25lcm9CbG9jayBmcm9tIFwiLi9tb2RlbC9Nb25lcm9CbG9ja1wiO1xuaW1wb3J0IE1vbmVyb0Jsb2NrSGVhZGVyIGZyb20gXCIuL21vZGVsL01vbmVyb0Jsb2NrSGVhZGVyXCI7XG5pbXBvcnQgTW9uZXJvQmxvY2tUZW1wbGF0ZSBmcm9tIFwiLi9tb2RlbC9Nb25lcm9CbG9ja1RlbXBsYXRlXCI7XG5pbXBvcnQgTW9uZXJvQ29ubmVjdGlvblNwYW4gZnJvbSBcIi4vbW9kZWwvTW9uZXJvQ29ubmVjdGlvblNwYW5cIjtcbmltcG9ydCBNb25lcm9EYWVtb24gZnJvbSBcIi4vTW9uZXJvRGFlbW9uXCI7XG5pbXBvcnQgTW9uZXJvRGFlbW9uQ29uZmlnIGZyb20gXCIuL21vZGVsL01vbmVyb0RhZW1vbkNvbmZpZ1wiO1xuaW1wb3J0IE1vbmVyb0RhZW1vbkluZm8gZnJvbSBcIi4vbW9kZWwvTW9uZXJvRGFlbW9uSW5mb1wiO1xuaW1wb3J0IE1vbmVyb0RhZW1vbkxpc3RlbmVyIGZyb20gXCIuL21vZGVsL01vbmVyb0RhZW1vbkxpc3RlbmVyXCI7XG5pbXBvcnQgTW9uZXJvRGFlbW9uU3luY0luZm8gZnJvbSBcIi4vbW9kZWwvTW9uZXJvRGFlbW9uU3luY0luZm9cIjtcbmltcG9ydCBNb25lcm9EYWVtb25VcGRhdGVDaGVja1Jlc3VsdCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9EYWVtb25VcGRhdGVDaGVja1Jlc3VsdFwiO1xuaW1wb3J0IE1vbmVyb0RhZW1vblVwZGF0ZURvd25sb2FkUmVzdWx0IGZyb20gXCIuL21vZGVsL01vbmVyb0RhZW1vblVwZGF0ZURvd25sb2FkUmVzdWx0XCI7XG5pbXBvcnQgTW9uZXJvRmVlRXN0aW1hdGUgZnJvbSBcIi4vbW9kZWwvTW9uZXJvRmVlRXN0aW1hdGVcIjtcbmltcG9ydCBNb25lcm9FcnJvciBmcm9tIFwiLi4vY29tbW9uL01vbmVyb0Vycm9yXCI7XG5pbXBvcnQgTW9uZXJvSGFyZEZvcmtJbmZvIGZyb20gXCIuL21vZGVsL01vbmVyb0hhcmRGb3JrSW5mb1wiO1xuaW1wb3J0IE1vbmVyb0tleUltYWdlIGZyb20gXCIuL21vZGVsL01vbmVyb0tleUltYWdlXCI7XG5pbXBvcnQgTW9uZXJvS2V5SW1hZ2VTcGVudFN0YXR1cyBmcm9tIFwiLi9tb2RlbC9Nb25lcm9LZXlJbWFnZVNwZW50U3RhdHVzXCI7XG5pbXBvcnQgTW9uZXJvTWluZXJUeFN1bSBmcm9tIFwiLi9tb2RlbC9Nb25lcm9NaW5lclR4U3VtXCI7XG5pbXBvcnQgTW9uZXJvTWluaW5nU3RhdHVzIGZyb20gXCIuL21vZGVsL01vbmVyb01pbmluZ1N0YXR1c1wiO1xuaW1wb3J0IE1vbmVyb05ldHdvcmtUeXBlIGZyb20gXCIuL21vZGVsL01vbmVyb05ldHdvcmtUeXBlXCI7XG5pbXBvcnQgTW9uZXJvT3V0cHV0IGZyb20gXCIuL21vZGVsL01vbmVyb091dHB1dFwiO1xuaW1wb3J0IE1vbmVyb091dHB1dEhpc3RvZ3JhbUVudHJ5IGZyb20gXCIuL21vZGVsL01vbmVyb091dHB1dEhpc3RvZ3JhbUVudHJ5XCI7XG5pbXBvcnQgTW9uZXJvUGVlciBmcm9tIFwiLi9tb2RlbC9Nb25lcm9QZWVyXCI7XG5pbXBvcnQgTW9uZXJvUHJ1bmVSZXN1bHQgZnJvbSBcIi4vbW9kZWwvTW9uZXJvUHJ1bmVSZXN1bHRcIjtcbmltcG9ydCBNb25lcm9ScGNDb25uZWN0aW9uIGZyb20gXCIuLi9jb21tb24vTW9uZXJvUnBjQ29ubmVjdGlvblwiO1xuaW1wb3J0IE1vbmVyb1N1Ym1pdFR4UmVzdWx0IGZyb20gXCIuL21vZGVsL01vbmVyb1N1Ym1pdFR4UmVzdWx0XCI7XG5pbXBvcnQgTW9uZXJvVHggZnJvbSBcIi4vbW9kZWwvTW9uZXJvVHhcIjtcbmltcG9ydCBNb25lcm9UeFBvb2xTdGF0cyBmcm9tIFwiLi9tb2RlbC9Nb25lcm9UeFBvb2xTdGF0c1wiO1xuaW1wb3J0IE1vbmVyb1V0aWxzIGZyb20gXCIuLi9jb21tb24vTW9uZXJvVXRpbHNcIjtcbmltcG9ydCBNb25lcm9WZXJzaW9uIGZyb20gXCIuL21vZGVsL01vbmVyb1ZlcnNpb25cIjtcbmltcG9ydCB7IENoaWxkUHJvY2VzcyB9IGZyb20gXCJjaGlsZF9wcm9jZXNzXCI7XG5cbi8qKlxuICogQ29weXJpZ2h0IChjKSB3b29kc2VyXG4gKlxuICogUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuICogb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxuICogaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0c1xuICogdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuICogY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXG4gKiBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuICpcbiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbFxuICogY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbiAqXG4gKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4gKiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbiAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuICogQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuICogTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbiAqIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFXG4gKiBTT0ZUV0FSRS5cbiAqL1xuXG4vKipcbiAqIEltcGxlbWVudHMgYSBNb25lcm9EYWVtb24gYXMgYSBjbGllbnQgb2YgbW9uZXJvZC5cbiAqL1xuY2xhc3MgTW9uZXJvRGFlbW9uUnBjIGV4dGVuZHMgTW9uZXJvRGFlbW9uIHtcblxuICAvLyBzdGF0aWMgdmFyaWFibGVzXG4gIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgTUFYX1JFUV9TSVpFID0gXCIzMDAwMDAwXCI7XG4gIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgREVGQVVMVF9JRCA9IFwiMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMFwiOyAvLyB1bmluaXRpYWxpemVkIHR4IG9yIGJsb2NrIGhhc2ggZnJvbSBkYWVtb24gcnBjXG4gIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgTlVNX0hFQURFUlNfUEVSX1JFUSA9IDc1MDsgLy8gbnVtYmVyIG9mIGhlYWRlcnMgdG8gZmV0Y2ggYW5kIGNhY2hlIHBlciByZXF1ZXN0XG4gIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgREVGQVVMVF9QT0xMX1BFUklPRCA9IDIwMDAwOyAvLyBkZWZhdWx0IGludGVydmFsIGJldHdlZW4gcG9sbGluZyB0aGUgZGFlbW9uIGluIG1zXG5cbiAgLy8gaW5zdGFuY2UgdmFyaWFibGVzXG4gIHByb3RlY3RlZCBjb25maWc6IFBhcnRpYWw8TW9uZXJvRGFlbW9uQ29uZmlnPjtcbiAgcHJvdGVjdGVkIGxpc3RlbmVyczogTW9uZXJvRGFlbW9uTGlzdGVuZXJbXTtcbiAgcHJvdGVjdGVkIGNhY2hlZEhlYWRlcnM6IGFueTtcbiAgcHJvdGVjdGVkIHByb2Nlc3M6IGFueTtcbiAgcHJvdGVjdGVkIHBvbGxMaXN0ZW5lcjogYW55O1xuICBwcm90ZWN0ZWQgcHJveHlEYWVtb246IGFueTtcbiBcbiAgLyoqIEBwcml2YXRlICovXG4gIGNvbnN0cnVjdG9yKGNvbmZpZzogTW9uZXJvRGFlbW9uQ29uZmlnLCBwcm94eURhZW1vbjogTW9uZXJvRGFlbW9uUnBjUHJveHkpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgIHRoaXMucHJveHlEYWVtb24gPSBwcm94eURhZW1vbjtcbiAgICBpZiAoY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybjtcbiAgICB0aGlzLmxpc3RlbmVycyA9IFtdOyAgICAgIC8vIGJsb2NrIGxpc3RlbmVyc1xuICAgIHRoaXMuY2FjaGVkSGVhZGVycyA9IHt9OyAgLy8gY2FjaGVkIGhlYWRlcnMgZm9yIGZldGNoaW5nIGJsb2NrcyBpbiBib3VuZCBjaHVua3NcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgaW50ZXJuYWwgcHJvY2VzcyBydW5uaW5nIG1vbmVyb2QuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtDaGlsZFByb2Nlc3N9IHRoZSBub2RlIHByb2Nlc3MgcnVubmluZyBtb25lcm9kLCB1bmRlZmluZWQgaWYgbm90IGNyZWF0ZWQgZnJvbSBuZXcgcHJvY2Vzc1xuICAgKi9cbiAgZ2V0UHJvY2VzcygpOiBDaGlsZFByb2Nlc3Mge1xuICAgIHJldHVybiB0aGlzLnByb2Nlc3M7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTdG9wIHRoZSBpbnRlcm5hbCBwcm9jZXNzIHJ1bm5pbmcgbW9uZXJvZCwgaWYgYXBwbGljYWJsZS5cbiAgICogXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2ZvcmNlXSBzcGVjaWZpZXMgaWYgdGhlIHByb2Nlc3Mgc2hvdWxkIGJlIGRlc3Ryb3llZCBmb3JjaWJseSAoZGVmYXVsdCBmYWxzZSlcbiAgICogQHJldHVybiB7UHJvbWlzZTxudW1iZXIgfCB1bmRlZmluZWQ+fSB0aGUgZXhpdCBjb2RlIGZyb20gc3RvcHBpbmcgdGhlIHByb2Nlc3NcbiAgICovXG4gIGFzeW5jIHN0b3BQcm9jZXNzKGZvcmNlID0gZmFsc2UpOiBQcm9taXNlPG51bWJlciB8IHVuZGVmaW5lZD4ge1xuICAgIGlmICh0aGlzLnByb2Nlc3MgPT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTW9uZXJvRGFlbW9uUnBjIGluc3RhbmNlIG5vdCBjcmVhdGVkIGZyb20gbmV3IHByb2Nlc3NcIik7XG4gICAgbGV0IGxpc3RlbmVyc0NvcHkgPSBHZW5VdGlscy5jb3B5QXJyYXkoYXdhaXQgdGhpcy5nZXRMaXN0ZW5lcnMoKSk7XG4gICAgZm9yIChsZXQgbGlzdGVuZXIgb2YgbGlzdGVuZXJzQ29weSkgYXdhaXQgdGhpcy5yZW1vdmVMaXN0ZW5lcihsaXN0ZW5lcik7XG4gICAgcmV0dXJuIEdlblV0aWxzLmtpbGxQcm9jZXNzKHRoaXMucHJvY2VzcywgZm9yY2UgPyBcIlNJR0tJTExcIiA6IHVuZGVmaW5lZCk7XG4gIH1cbiAgXG4gIGFzeW5jIGFkZExpc3RlbmVyKGxpc3RlbmVyOiBNb25lcm9EYWVtb25MaXN0ZW5lcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5hZGRMaXN0ZW5lcihsaXN0ZW5lcik7XG4gICAgYXNzZXJ0KGxpc3RlbmVyIGluc3RhbmNlb2YgTW9uZXJvRGFlbW9uTGlzdGVuZXIsIFwiTGlzdGVuZXIgbXVzdCBiZSBpbnN0YW5jZSBvZiBNb25lcm9EYWVtb25MaXN0ZW5lclwiKTtcbiAgICB0aGlzLmxpc3RlbmVycy5wdXNoKGxpc3RlbmVyKTtcbiAgICB0aGlzLnJlZnJlc2hMaXN0ZW5pbmcoKTtcbiAgfVxuICBcbiAgYXN5bmMgcmVtb3ZlTGlzdGVuZXIobGlzdGVuZXI6IE1vbmVyb0RhZW1vbkxpc3RlbmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLnJlbW92ZUxpc3RlbmVyKGxpc3RlbmVyKTtcbiAgICBhc3NlcnQobGlzdGVuZXIgaW5zdGFuY2VvZiBNb25lcm9EYWVtb25MaXN0ZW5lciwgXCJMaXN0ZW5lciBtdXN0IGJlIGluc3RhbmNlIG9mIE1vbmVyb0RhZW1vbkxpc3RlbmVyXCIpO1xuICAgIGxldCBpZHggPSB0aGlzLmxpc3RlbmVycy5pbmRleE9mKGxpc3RlbmVyKTtcbiAgICBpZiAoaWR4ID4gLTEpIHRoaXMubGlzdGVuZXJzLnNwbGljZShpZHgsIDEpO1xuICAgIGVsc2UgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTGlzdGVuZXIgaXMgbm90IHJlZ2lzdGVyZWQgd2l0aCBkYWVtb25cIik7XG4gICAgdGhpcy5yZWZyZXNoTGlzdGVuaW5nKCk7XG4gIH1cbiAgXG4gIGdldExpc3RlbmVycygpOiBNb25lcm9EYWVtb25MaXN0ZW5lcltdIHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZ2V0TGlzdGVuZXJzKCk7XG4gICAgcmV0dXJuIHRoaXMubGlzdGVuZXJzO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSBkYWVtb24ncyBSUEMgY29ubmVjdGlvbi5cbiAgICogXG4gICAqIEByZXR1cm4ge01vbmVyb1JwY0Nvbm5lY3Rpb259IHRoZSBkYWVtb24ncyBycGMgY29ubmVjdGlvblxuICAgKi9cbiAgYXN5bmMgZ2V0UnBjQ29ubmVjdGlvbigpIHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZ2V0UnBjQ29ubmVjdGlvbigpO1xuICAgIHJldHVybiB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKTtcbiAgfVxuICBcbiAgYXN5bmMgaXNDb25uZWN0ZWQoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmlzQ29ubmVjdGVkKCk7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuZ2V0VmVyc2lvbigpO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG4gIFxuICBhc3luYyBnZXRWZXJzaW9uKCk6IFByb21pc2U8TW9uZXJvVmVyc2lvbj4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5nZXRWZXJzaW9uKCk7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJnZXRfdmVyc2lvblwiKTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwLnJlc3VsdCk7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9WZXJzaW9uKHJlc3AucmVzdWx0LnZlcnNpb24sIHJlc3AucmVzdWx0LnJlbGVhc2UpO1xuICB9XG4gIFxuICBhc3luYyBpc1RydXN0ZWQoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmlzVHJ1c3RlZCgpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZFBhdGhSZXF1ZXN0KFwiZ2V0X2hlaWdodFwiKTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwKTtcbiAgICByZXR1cm4gIXJlc3AudW50cnVzdGVkO1xuICB9XG4gIFxuICBhc3luYyBnZXRIZWlnaHQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZ2V0SGVpZ2h0KCk7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJnZXRfYmxvY2tfY291bnRcIik7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcC5yZXN1bHQpO1xuICAgIHJldHVybiByZXNwLnJlc3VsdC5jb3VudDtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QmxvY2tIYXNoKGhlaWdodDogbnVtYmVyKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZ2V0QmxvY2tIYXNoKGhlaWdodCk7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJvbl9nZXRfYmxvY2tfaGFzaFwiLCBbaGVpZ2h0XSkpLnJlc3VsdDsgIC8vIFRPRE8gbW9uZXJvLXdhbGxldC1ycGM6IG5vIHN0YXR1cyByZXR1cm5lZFxuICB9XG4gIFxuICBhc3luYyBnZXRCbG9ja1RlbXBsYXRlKHdhbGxldEFkZHJlc3M6IHN0cmluZywgcmVzZXJ2ZVNpemU/OiBudW1iZXIpOiBQcm9taXNlPE1vbmVyb0Jsb2NrVGVtcGxhdGU+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZ2V0QmxvY2tUZW1wbGF0ZSh3YWxsZXRBZGRyZXNzLCByZXNlcnZlU2l6ZSk7XG4gICAgYXNzZXJ0KHdhbGxldEFkZHJlc3MgJiYgdHlwZW9mIHdhbGxldEFkZHJlc3MgPT09IFwic3RyaW5nXCIsIFwiTXVzdCBzcGVjaWZ5IHdhbGxldCBhZGRyZXNzIHRvIGJlIG1pbmVkIHRvXCIpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2Jsb2NrX3RlbXBsYXRlXCIsIHt3YWxsZXRfYWRkcmVzczogd2FsbGV0QWRkcmVzcywgcmVzZXJ2ZV9zaXplOiByZXNlcnZlU2l6ZX0pO1xuICAgIE1vbmVyb0RhZW1vblJwYy5jaGVja1Jlc3BvbnNlU3RhdHVzKHJlc3AucmVzdWx0KTtcbiAgICByZXR1cm4gTW9uZXJvRGFlbW9uUnBjLmNvbnZlcnRScGNCbG9ja1RlbXBsYXRlKHJlc3AucmVzdWx0KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0TGFzdEJsb2NrSGVhZGVyKCk6IFByb21pc2U8TW9uZXJvQmxvY2tIZWFkZXI+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZ2V0TGFzdEJsb2NrSGVhZGVyKCk7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJnZXRfbGFzdF9ibG9ja19oZWFkZXJcIik7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcC5yZXN1bHQpO1xuICAgIHJldHVybiBNb25lcm9EYWVtb25ScGMuY29udmVydFJwY0Jsb2NrSGVhZGVyKHJlc3AucmVzdWx0LmJsb2NrX2hlYWRlcik7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEJsb2NrSGVhZGVyQnlIYXNoKGJsb2NrSGFzaDogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9CbG9ja0hlYWRlcj4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5nZXRCbG9ja0hlYWRlckJ5SGFzaChibG9ja0hhc2gpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2Jsb2NrX2hlYWRlcl9ieV9oYXNoXCIsIHtoYXNoOiBibG9ja0hhc2h9KTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwLnJlc3VsdCk7XG4gICAgcmV0dXJuIE1vbmVyb0RhZW1vblJwYy5jb252ZXJ0UnBjQmxvY2tIZWFkZXIocmVzcC5yZXN1bHQuYmxvY2tfaGVhZGVyKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QmxvY2tIZWFkZXJCeUhlaWdodChoZWlnaHQ6IG51bWJlcik6IFByb21pc2U8TW9uZXJvQmxvY2tIZWFkZXI+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZ2V0QmxvY2tIZWFkZXJCeUhlaWdodChoZWlnaHQpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2Jsb2NrX2hlYWRlcl9ieV9oZWlnaHRcIiwge2hlaWdodDogaGVpZ2h0fSk7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcC5yZXN1bHQpO1xuICAgIHJldHVybiBNb25lcm9EYWVtb25ScGMuY29udmVydFJwY0Jsb2NrSGVhZGVyKHJlc3AucmVzdWx0LmJsb2NrX2hlYWRlcik7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEJsb2NrSGVhZGVyc0J5UmFuZ2Uoc3RhcnRIZWlnaHQ/OiBudW1iZXIsIGVuZEhlaWdodD86IG51bWJlcik6IFByb21pc2U8TW9uZXJvQmxvY2tIZWFkZXJbXT4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5nZXRCbG9ja0hlYWRlcnNCeVJhbmdlKHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQpO1xuICAgIFxuICAgIC8vIGZldGNoIGJsb2NrIGhlYWRlcnNcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF9ibG9ja19oZWFkZXJzX3JhbmdlXCIsIHtcbiAgICAgIHN0YXJ0X2hlaWdodDogc3RhcnRIZWlnaHQsXG4gICAgICBlbmRfaGVpZ2h0OiBlbmRIZWlnaHRcbiAgICB9KTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwLnJlc3VsdCk7XG4gICAgXG4gICAgLy8gYnVpbGQgaGVhZGVyc1xuICAgIGxldCBoZWFkZXJzID0gW107XG4gICAgZm9yIChsZXQgcnBjSGVhZGVyIG9mIHJlc3AucmVzdWx0LmhlYWRlcnMpIHtcbiAgICAgIGhlYWRlcnMucHVzaChNb25lcm9EYWVtb25ScGMuY29udmVydFJwY0Jsb2NrSGVhZGVyKHJwY0hlYWRlcikpO1xuICAgIH1cbiAgICByZXR1cm4gaGVhZGVycztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QmxvY2tCeUhhc2goYmxvY2tIYXNoOiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0Jsb2NrPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldEJsb2NrQnlIYXNoKGJsb2NrSGFzaCk7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJnZXRfYmxvY2tcIiwge2hhc2g6IGJsb2NrSGFzaH0pO1xuICAgIE1vbmVyb0RhZW1vblJwYy5jaGVja1Jlc3BvbnNlU3RhdHVzKHJlc3AucmVzdWx0KTtcbiAgICByZXR1cm4gTW9uZXJvRGFlbW9uUnBjLmNvbnZlcnRScGNCbG9jayhyZXNwLnJlc3VsdCk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEJsb2NrQnlIZWlnaHQoaGVpZ2h0OiBudW1iZXIpOiBQcm9taXNlPE1vbmVyb0Jsb2NrPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldEJsb2NrQnlIZWlnaHQoaGVpZ2h0KTtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF9ibG9ja1wiLCB7aGVpZ2h0OiBoZWlnaHR9KTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwLnJlc3VsdCk7XG4gICAgcmV0dXJuIE1vbmVyb0RhZW1vblJwYy5jb252ZXJ0UnBjQmxvY2socmVzcC5yZXN1bHQpO1xuICB9XG4gIFxuICBhc3luYyBnZXRCbG9ja3NCeUhlaWdodChoZWlnaHRzOiBudW1iZXJbXSk6IFByb21pc2U8TW9uZXJvQmxvY2tbXT4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5nZXRCbG9ja3NCeUhlaWdodChoZWlnaHRzKTtcbiAgICBcbiAgICAvLyBmZXRjaCBibG9ja3MgaW4gYmluYXJ5XG4gICAgbGV0IHJlc3BCaW4gPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kQmluYXJ5UmVxdWVzdChcImdldF9ibG9ja3NfYnlfaGVpZ2h0LmJpblwiLCB7aGVpZ2h0czogaGVpZ2h0c30pO1xuICAgIFxuICAgIC8vIGNvbnZlcnQgYmluYXJ5IGJsb2NrcyB0byBqc29uXG4gICAgbGV0IHJwY0Jsb2NrcyA9IGF3YWl0IE1vbmVyb1V0aWxzLmJpbmFyeUJsb2Nrc1RvSnNvbihyZXNwQmluKTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhycGNCbG9ja3MpO1xuICAgIFxuICAgIC8vIGJ1aWxkIGJsb2NrcyB3aXRoIHRyYW5zYWN0aW9uc1xuICAgIGFzc2VydC5lcXVhbChycGNCbG9ja3MudHhzLmxlbmd0aCwgcnBjQmxvY2tzLmJsb2Nrcy5sZW5ndGgpOyAgICBcbiAgICBsZXQgYmxvY2tzID0gW107XG4gICAgZm9yIChsZXQgYmxvY2tJZHggPSAwOyBibG9ja0lkeCA8IHJwY0Jsb2Nrcy5ibG9ja3MubGVuZ3RoOyBibG9ja0lkeCsrKSB7XG4gICAgICBcbiAgICAgIC8vIGJ1aWxkIGJsb2NrXG4gICAgICBsZXQgYmxvY2sgPSBNb25lcm9EYWVtb25ScGMuY29udmVydFJwY0Jsb2NrKHJwY0Jsb2Nrcy5ibG9ja3NbYmxvY2tJZHhdKTtcbiAgICAgIGJsb2NrLnNldEhlaWdodChoZWlnaHRzW2Jsb2NrSWR4XSk7XG4gICAgICBibG9ja3MucHVzaChibG9jayk7XG4gICAgICBcbiAgICAgIC8vIGJ1aWxkIHRyYW5zYWN0aW9uc1xuICAgICAgbGV0IHR4cyA9IFtdO1xuICAgICAgZm9yIChsZXQgdHhJZHggPSAwOyB0eElkeCA8IHJwY0Jsb2Nrcy50eHNbYmxvY2tJZHhdLmxlbmd0aDsgdHhJZHgrKykge1xuICAgICAgICBsZXQgdHggPSBuZXcgTW9uZXJvVHgoKTtcbiAgICAgICAgdHhzLnB1c2godHgpO1xuICAgICAgICB0eC5zZXRIYXNoKHJwY0Jsb2Nrcy5ibG9ja3NbYmxvY2tJZHhdLnR4X2hhc2hlc1t0eElkeF0pO1xuICAgICAgICB0eC5zZXRJc0NvbmZpcm1lZCh0cnVlKTtcbiAgICAgICAgdHguc2V0SW5UeFBvb2woZmFsc2UpO1xuICAgICAgICB0eC5zZXRJc01pbmVyVHgoZmFsc2UpO1xuICAgICAgICB0eC5zZXRSZWxheSh0cnVlKTtcbiAgICAgICAgdHguc2V0SXNSZWxheWVkKHRydWUpO1xuICAgICAgICB0eC5zZXRJc0ZhaWxlZChmYWxzZSk7XG4gICAgICAgIHR4LnNldElzRG91YmxlU3BlbmRTZWVuKGZhbHNlKTtcbiAgICAgICAgTW9uZXJvRGFlbW9uUnBjLmNvbnZlcnRScGNUeChycGNCbG9ja3MudHhzW2Jsb2NrSWR4XVt0eElkeF0sIHR4KTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gbWVyZ2UgaW50byBvbmUgYmxvY2tcbiAgICAgIGJsb2NrLnNldFR4cyhbXSk7XG4gICAgICBmb3IgKGxldCB0eCBvZiB0eHMpIHtcbiAgICAgICAgaWYgKHR4LmdldEJsb2NrKCkpIGJsb2NrLm1lcmdlKHR4LmdldEJsb2NrKCkpO1xuICAgICAgICBlbHNlIGJsb2NrLmdldFR4cygpLnB1c2godHguc2V0QmxvY2soYmxvY2spKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGJsb2NrcztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QmxvY2tzQnlSYW5nZShzdGFydEhlaWdodD86IG51bWJlciwgZW5kSGVpZ2h0PzogbnVtYmVyKTogUHJvbWlzZTxNb25lcm9CbG9ja1tdPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldEJsb2Nrc0J5UmFuZ2Uoc3RhcnRIZWlnaHQsIGVuZEhlaWdodCk7XG4gICAgaWYgKHN0YXJ0SGVpZ2h0ID09PSB1bmRlZmluZWQpIHN0YXJ0SGVpZ2h0ID0gMDtcbiAgICBpZiAoZW5kSGVpZ2h0ID09PSB1bmRlZmluZWQpIGVuZEhlaWdodCA9IGF3YWl0IHRoaXMuZ2V0SGVpZ2h0KCkgLSAxO1xuICAgIGxldCBoZWlnaHRzID0gW107XG4gICAgZm9yIChsZXQgaGVpZ2h0ID0gc3RhcnRIZWlnaHQ7IGhlaWdodCA8PSBlbmRIZWlnaHQ7IGhlaWdodCsrKSBoZWlnaHRzLnB1c2goaGVpZ2h0KTtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5nZXRCbG9ja3NCeUhlaWdodChoZWlnaHRzKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QmxvY2tzQnlSYW5nZUNodW5rZWQoc3RhcnRIZWlnaHQ/OiBudW1iZXIsIGVuZEhlaWdodD86IG51bWJlciwgbWF4Q2h1bmtTaXplPzogbnVtYmVyKTogUHJvbWlzZTxNb25lcm9CbG9ja1tdPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldEJsb2Nrc0J5UmFuZ2VDaHVua2VkKHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQsIG1heENodW5rU2l6ZSk7XG4gICAgaWYgKHN0YXJ0SGVpZ2h0ID09PSB1bmRlZmluZWQpIHN0YXJ0SGVpZ2h0ID0gMDtcbiAgICBpZiAoZW5kSGVpZ2h0ID09PSB1bmRlZmluZWQpIGVuZEhlaWdodCA9IGF3YWl0IHRoaXMuZ2V0SGVpZ2h0KCkgLSAxO1xuICAgIGxldCBsYXN0SGVpZ2h0ID0gc3RhcnRIZWlnaHQgLSAxO1xuICAgIGxldCBibG9ja3MgPSBbXTtcbiAgICB3aGlsZSAobGFzdEhlaWdodCA8IGVuZEhlaWdodCkge1xuICAgICAgZm9yIChsZXQgYmxvY2sgb2YgYXdhaXQgdGhpcy5nZXRNYXhCbG9ja3MobGFzdEhlaWdodCArIDEsIGVuZEhlaWdodCwgbWF4Q2h1bmtTaXplKSkge1xuICAgICAgICBibG9ja3MucHVzaChibG9jayk7XG4gICAgICB9XG4gICAgICBsYXN0SGVpZ2h0ID0gYmxvY2tzW2Jsb2Nrcy5sZW5ndGggLSAxXS5nZXRIZWlnaHQoKTtcbiAgICB9XG4gICAgcmV0dXJuIGJsb2NrcztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0VHhzKHR4SGFzaGVzOiBzdHJpbmdbXSwgcHJ1bmUgPSBmYWxzZSk6IFByb21pc2U8TW9uZXJvVHhbXT4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5nZXRUeHModHhIYXNoZXMsIHBydW5lKTtcbiAgICAgICAgXG4gICAgLy8gdmFsaWRhdGUgaW5wdXRcbiAgICBhc3NlcnQoQXJyYXkuaXNBcnJheSh0eEhhc2hlcykgJiYgdHhIYXNoZXMubGVuZ3RoID4gMCwgXCJNdXN0IHByb3ZpZGUgYW4gYXJyYXkgb2YgdHJhbnNhY3Rpb24gaGFzaGVzXCIpO1xuICAgIGFzc2VydChwcnVuZSA9PT0gdW5kZWZpbmVkIHx8IHR5cGVvZiBwcnVuZSA9PT0gXCJib29sZWFuXCIsIFwiUHJ1bmUgbXVzdCBiZSBhIGJvb2xlYW4gb3IgdW5kZWZpbmVkXCIpO1xuICAgICAgICBcbiAgICAvLyBmZXRjaCB0cmFuc2FjdGlvbnNcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRQYXRoUmVxdWVzdChcImdldF90cmFuc2FjdGlvbnNcIiwge1xuICAgICAgdHhzX2hhc2hlczogdHhIYXNoZXMsXG4gICAgICBkZWNvZGVfYXNfanNvbjogdHJ1ZSxcbiAgICAgIHBydW5lOiBwcnVuZVxuICAgIH0pO1xuICAgIHRyeSB7XG4gICAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIGlmIChlLm1lc3NhZ2UuaW5kZXhPZihcIkZhaWxlZCB0byBwYXJzZSBoZXggcmVwcmVzZW50YXRpb24gb2YgdHJhbnNhY3Rpb24gaGFzaFwiKSA+PSAwKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJJbnZhbGlkIHRyYW5zYWN0aW9uIGhhc2hcIik7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgICAgICAgXG4gICAgLy8gYnVpbGQgdHJhbnNhY3Rpb24gbW9kZWxzXG4gICAgbGV0IHR4cyA9IFtdO1xuICAgIGlmIChyZXNwLnR4cykge1xuICAgICAgZm9yIChsZXQgdHhJZHggPSAwOyB0eElkeCA8IHJlc3AudHhzLmxlbmd0aDsgdHhJZHgrKykge1xuICAgICAgICBsZXQgdHggPSBuZXcgTW9uZXJvVHgoKTtcbiAgICAgICAgdHguc2V0SXNNaW5lclR4KGZhbHNlKTtcbiAgICAgICAgdHhzLnB1c2goTW9uZXJvRGFlbW9uUnBjLmNvbnZlcnRScGNUeChyZXNwLnR4c1t0eElkeF0sIHR4KSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHJldHVybiB0eHM7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFR4SGV4ZXModHhIYXNoZXM6IHN0cmluZ1tdLCBwcnVuZSA9IGZhbHNlKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5nZXRUeEhleGVzKHR4SGFzaGVzLCBwcnVuZSk7XG4gICAgbGV0IGhleGVzID0gW107XG4gICAgZm9yIChsZXQgdHggb2YgYXdhaXQgdGhpcy5nZXRUeHModHhIYXNoZXMsIHBydW5lKSkgaGV4ZXMucHVzaChwcnVuZSA/IHR4LmdldFBydW5lZEhleCgpIDogdHguZ2V0RnVsbEhleCgpKTtcbiAgICByZXR1cm4gaGV4ZXM7XG4gIH1cbiAgXG4gIGFzeW5jIGdldE1pbmVyVHhTdW0oaGVpZ2h0OiBudW1iZXIsIG51bUJsb2NrczogbnVtYmVyKTogUHJvbWlzZTxNb25lcm9NaW5lclR4U3VtPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldE1pbmVyVHhTdW0oaGVpZ2h0LCBudW1CbG9ja3MpO1xuICAgIGlmIChoZWlnaHQgPT09IHVuZGVmaW5lZCkgaGVpZ2h0ID0gMDtcbiAgICBlbHNlIGFzc2VydChoZWlnaHQgPj0gMCwgXCJIZWlnaHQgbXVzdCBiZSBhbiBpbnRlZ2VyID49IDBcIik7XG4gICAgaWYgKG51bUJsb2NrcyA9PT0gdW5kZWZpbmVkKSBudW1CbG9ja3MgPSBhd2FpdCB0aGlzLmdldEhlaWdodCgpO1xuICAgIGVsc2UgYXNzZXJ0KG51bUJsb2NrcyA+PSAwLCBcIkNvdW50IG11c3QgYmUgYW4gaW50ZWdlciA+PSAwXCIpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2NvaW5iYXNlX3R4X3N1bVwiLCB7aGVpZ2h0OiBoZWlnaHQsIGNvdW50OiBudW1CbG9ja3N9KTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwLnJlc3VsdCk7XG4gICAgbGV0IHR4U3VtID0gbmV3IE1vbmVyb01pbmVyVHhTdW0oKTtcbiAgICB0eFN1bS5zZXRFbWlzc2lvblN1bShCaWdJbnQocmVzcC5yZXN1bHQuZW1pc3Npb25fYW1vdW50KSk7XG4gICAgdHhTdW0uc2V0RmVlU3VtKEJpZ0ludChyZXNwLnJlc3VsdC5mZWVfYW1vdW50KSk7XG4gICAgcmV0dXJuIHR4U3VtO1xuICB9XG4gIFxuICBhc3luYyBnZXRGZWVFc3RpbWF0ZShncmFjZUJsb2Nrcz86IG51bWJlcik6IFByb21pc2U8TW9uZXJvRmVlRXN0aW1hdGU+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZ2V0RmVlRXN0aW1hdGUoZ3JhY2VCbG9ja3MpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2ZlZV9lc3RpbWF0ZVwiLCB7Z3JhY2VfYmxvY2tzOiBncmFjZUJsb2Nrc30pO1xuICAgIE1vbmVyb0RhZW1vblJwYy5jaGVja1Jlc3BvbnNlU3RhdHVzKHJlc3AucmVzdWx0KTtcbiAgICBsZXQgZmVlRXN0aW1hdGUgPSBuZXcgTW9uZXJvRmVlRXN0aW1hdGUoKTtcbiAgICBmZWVFc3RpbWF0ZS5zZXRGZWUoQmlnSW50KHJlc3AucmVzdWx0LmZlZSkpO1xuICAgIGZlZUVzdGltYXRlLnNldFF1YW50aXphdGlvbk1hc2soQmlnSW50KHJlc3AucmVzdWx0LnF1YW50aXphdGlvbl9tYXNrKSk7XG4gICAgaWYgKHJlc3AucmVzdWx0LmZlZXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgbGV0IGZlZXMgPSBbXTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcmVzcC5yZXN1bHQuZmVlcy5sZW5ndGg7IGkrKykgZmVlcy5wdXNoKEJpZ0ludChyZXNwLnJlc3VsdC5mZWVzW2ldKSk7XG4gICAgICBmZWVFc3RpbWF0ZS5zZXRGZWVzKGZlZXMpO1xuICAgIH1cbiAgICByZXR1cm4gZmVlRXN0aW1hdGU7XG4gIH1cbiAgXG4gIGFzeW5jIHN1Ym1pdFR4SGV4KHR4SGV4OiBzdHJpbmcsIGRvTm90UmVsYXk6IGJvb2xlYW4pOiBQcm9taXNlPE1vbmVyb1N1Ym1pdFR4UmVzdWx0PiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLnN1Ym1pdFR4SGV4KHR4SGV4LCBkb05vdFJlbGF5KTtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRQYXRoUmVxdWVzdChcInNlbmRfcmF3X3RyYW5zYWN0aW9uXCIsIHt0eF9hc19oZXg6IHR4SGV4LCBkb19ub3RfcmVsYXk6IGRvTm90UmVsYXl9KTtcbiAgICBsZXQgcmVzdWx0ID0gTW9uZXJvRGFlbW9uUnBjLmNvbnZlcnRScGNTdWJtaXRUeFJlc3VsdChyZXNwKTtcbiAgICBcbiAgICAvLyBzZXQgaXNHb29kIGJhc2VkIG9uIHN0YXR1c1xuICAgIHRyeSB7XG4gICAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwKTsgXG4gICAgICByZXN1bHQuc2V0SXNHb29kKHRydWUpO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgcmVzdWx0LnNldElzR29vZChmYWxzZSk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgXG4gIGFzeW5jIHJlbGF5VHhzQnlIYXNoKHR4SGFzaGVzOiBzdHJpbmdbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5yZWxheVR4c0J5SGFzaCh0eEhhc2hlcyk7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJyZWxheV90eFwiLCB7dHhpZHM6IHR4SGFzaGVzfSk7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcC5yZXN1bHQpO1xuICB9XG4gIFxuICBhc3luYyBnZXRUeFBvb2woKTogUHJvbWlzZTxNb25lcm9UeFtdPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldFR4UG9vbCgpO1xuICAgIFxuICAgIC8vIHNlbmQgcnBjIHJlcXVlc3RcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRQYXRoUmVxdWVzdChcImdldF90cmFuc2FjdGlvbl9wb29sXCIpO1xuICAgIE1vbmVyb0RhZW1vblJwYy5jaGVja1Jlc3BvbnNlU3RhdHVzKHJlc3ApO1xuICAgIFxuICAgIC8vIGJ1aWxkIHR4c1xuICAgIGxldCB0eHMgPSBbXTtcbiAgICBpZiAocmVzcC50cmFuc2FjdGlvbnMpIHtcbiAgICAgIGZvciAobGV0IHJwY1R4IG9mIHJlc3AudHJhbnNhY3Rpb25zKSB7XG4gICAgICAgIGxldCB0eCA9IG5ldyBNb25lcm9UeCgpO1xuICAgICAgICB0eHMucHVzaCh0eCk7XG4gICAgICAgIHR4LnNldElzQ29uZmlybWVkKGZhbHNlKTtcbiAgICAgICAgdHguc2V0SXNNaW5lclR4KGZhbHNlKTtcbiAgICAgICAgdHguc2V0SW5UeFBvb2wodHJ1ZSk7XG4gICAgICAgIHR4LnNldE51bUNvbmZpcm1hdGlvbnMoMCk7XG4gICAgICAgIE1vbmVyb0RhZW1vblJwYy5jb252ZXJ0UnBjVHgocnBjVHgsIHR4KTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHR4cztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0VHhQb29sSGFzaGVzKCk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWRcIik7XG4gIH1cbiAgXG4gIC8vIGFzeW5jIGdldFR4UG9vbEJhY2tsb2coKTogUHJvbWlzZTxNb25lcm9UeEJhY2tsb2dFbnRyeVtdPiB7XG4gIC8vICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IGltcGxlbWVudGVkXCIpO1xuICAvLyB9XG5cbiAgYXN5bmMgZ2V0VHhQb29sU3RhdHMoKTogUHJvbWlzZTxNb25lcm9UeFBvb2xTdGF0cz4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5nZXRUeFBvb2xTdGF0cygpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZFBhdGhSZXF1ZXN0KFwiZ2V0X3RyYW5zYWN0aW9uX3Bvb2xfc3RhdHNcIik7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcCk7XG4gICAgcmV0dXJuIE1vbmVyb0RhZW1vblJwYy5jb252ZXJ0UnBjVHhQb29sU3RhdHMocmVzcC5wb29sX3N0YXRzKTtcbiAgfVxuICBcbiAgYXN5bmMgZmx1c2hUeFBvb2woaGFzaGVzPzogc3RyaW5nIHwgc3RyaW5nW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZmx1c2hUeFBvb2woaGFzaGVzKTtcbiAgICBpZiAoaGFzaGVzKSBoYXNoZXMgPSBHZW5VdGlscy5saXN0aWZ5KGhhc2hlcyk7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJmbHVzaF90eHBvb2xcIiwge3R4aWRzOiBoYXNoZXN9KTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwLnJlc3VsdCk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEtleUltYWdlU3BlbnRTdGF0dXNlcyhrZXlJbWFnZXM6IHN0cmluZ1tdKTogUHJvbWlzZTxNb25lcm9LZXlJbWFnZVNwZW50U3RhdHVzW10+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZ2V0S2V5SW1hZ2VTcGVudFN0YXR1c2VzKGtleUltYWdlcyk7XG4gICAgaWYgKGtleUltYWdlcyA9PT0gdW5kZWZpbmVkIHx8IGtleUltYWdlcy5sZW5ndGggPT09IDApIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk11c3QgcHJvdmlkZSBrZXkgaW1hZ2VzIHRvIGNoZWNrIHRoZSBzdGF0dXMgb2ZcIik7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kUGF0aFJlcXVlc3QoXCJpc19rZXlfaW1hZ2Vfc3BlbnRcIiwge2tleV9pbWFnZXM6IGtleUltYWdlc30pO1xuICAgIE1vbmVyb0RhZW1vblJwYy5jaGVja1Jlc3BvbnNlU3RhdHVzKHJlc3ApO1xuICAgIHJldHVybiByZXNwLnNwZW50X3N0YXR1cztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0T3V0cHV0SGlzdG9ncmFtKGFtb3VudHM/OiBiaWdpbnRbXSwgbWluQ291bnQ/OiBudW1iZXIsIG1heENvdW50PzogbnVtYmVyLCBpc1VubG9ja2VkPzogYm9vbGVhbiwgcmVjZW50Q3V0b2ZmPzogbnVtYmVyKTogUHJvbWlzZTxNb25lcm9PdXRwdXRIaXN0b2dyYW1FbnRyeVtdPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldE91dHB1dEhpc3RvZ3JhbShhbW91bnRzLCBtaW5Db3VudCwgbWF4Q291bnQsIGlzVW5sb2NrZWQsIHJlY2VudEN1dG9mZik7XG4gICAgXG4gICAgLy8gc2VuZCBycGMgcmVxdWVzdFxuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X291dHB1dF9oaXN0b2dyYW1cIiwge1xuICAgICAgYW1vdW50czogYW1vdW50cyxcbiAgICAgIG1pbl9jb3VudDogbWluQ291bnQsXG4gICAgICBtYXhfY291bnQ6IG1heENvdW50LFxuICAgICAgdW5sb2NrZWQ6IGlzVW5sb2NrZWQsXG4gICAgICByZWNlbnRfY3V0b2ZmOiByZWNlbnRDdXRvZmZcbiAgICB9KTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwLnJlc3VsdCk7XG4gICAgXG4gICAgLy8gYnVpbGQgaGlzdG9ncmFtIGVudHJpZXMgZnJvbSByZXNwb25zZVxuICAgIGxldCBlbnRyaWVzID0gW107XG4gICAgaWYgKCFyZXNwLnJlc3VsdC5oaXN0b2dyYW0pIHJldHVybiBlbnRyaWVzO1xuICAgIGZvciAobGV0IHJwY0VudHJ5IG9mIHJlc3AucmVzdWx0Lmhpc3RvZ3JhbSkge1xuICAgICAgZW50cmllcy5wdXNoKE1vbmVyb0RhZW1vblJwYy5jb252ZXJ0UnBjT3V0cHV0SGlzdG9ncmFtRW50cnkocnBjRW50cnkpKTtcbiAgICB9XG4gICAgcmV0dXJuIGVudHJpZXM7XG4gIH1cbiAgXG4gIGFzeW5jIGdldE91dHB1dERpc3RyaWJ1dGlvbihhbW91bnRzLCBjdW11bGF0aXZlLCBzdGFydEhlaWdodCwgZW5kSGVpZ2h0KSB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldE91dHB1dERpc3RyaWJ1dGlvbihhbW91bnRzLCBjdW11bGF0aXZlLCBzdGFydEhlaWdodCwgZW5kSGVpZ2h0KTtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWQgKHJlc3BvbnNlICdkaXN0cmlidXRpb24nIGZpZWxkIGlzIGJpbmFyeSlcIik7XG4gICAgXG4vLyAgICBsZXQgYW1vdW50U3RycyA9IFtdO1xuLy8gICAgZm9yIChsZXQgYW1vdW50IG9mIGFtb3VudHMpIGFtb3VudFN0cnMucHVzaChhbW91bnQudG9KU1ZhbHVlKCkpO1xuLy8gICAgY29uc29sZS5sb2coYW1vdW50U3Rycyk7XG4vLyAgICBjb25zb2xlLmxvZyhjdW11bGF0aXZlKTtcbi8vICAgIGNvbnNvbGUubG9nKHN0YXJ0SGVpZ2h0KTtcbi8vICAgIGNvbnNvbGUubG9nKGVuZEhlaWdodCk7XG4vLyAgICBcbi8vICAgIC8vIHNlbmQgcnBjIHJlcXVlc3Rcbi8vICAgIGNvbnNvbGUubG9nKFwiKioqKioqKioqKiogU0VORElORyBSRVFVRVNUICoqKioqKioqKioqKipcIik7XG4vLyAgICBpZiAoc3RhcnRIZWlnaHQgPT09IHVuZGVmaW5lZCkgc3RhcnRIZWlnaHQgPSAwO1xuLy8gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJnZXRfb3V0cHV0X2Rpc3RyaWJ1dGlvblwiLCB7XG4vLyAgICAgIGFtb3VudHM6IGFtb3VudFN0cnMsXG4vLyAgICAgIGN1bXVsYXRpdmU6IGN1bXVsYXRpdmUsXG4vLyAgICAgIGZyb21faGVpZ2h0OiBzdGFydEhlaWdodCxcbi8vICAgICAgdG9faGVpZ2h0OiBlbmRIZWlnaHRcbi8vICAgIH0pO1xuLy8gICAgXG4vLyAgICBjb25zb2xlLmxvZyhcIlJFU1BPTlNFXCIpO1xuLy8gICAgY29uc29sZS5sb2cocmVzcCk7XG4vLyAgICBcbi8vICAgIC8vIGJ1aWxkIGRpc3RyaWJ1dGlvbiBlbnRyaWVzIGZyb20gcmVzcG9uc2Vcbi8vICAgIGxldCBlbnRyaWVzID0gW107XG4vLyAgICBpZiAoIXJlc3AucmVzdWx0LmRpc3RyaWJ1dGlvbnMpIHJldHVybiBlbnRyaWVzOyBcbi8vICAgIGZvciAobGV0IHJwY0VudHJ5IG9mIHJlc3AucmVzdWx0LmRpc3RyaWJ1dGlvbnMpIHtcbi8vICAgICAgbGV0IGVudHJ5ID0gTW9uZXJvRGFlbW9uUnBjLmNvbnZlcnRScGNPdXRwdXREaXN0cmlidXRpb25FbnRyeShycGNFbnRyeSk7XG4vLyAgICAgIGVudHJpZXMucHVzaChlbnRyeSk7XG4vLyAgICB9XG4vLyAgICByZXR1cm4gZW50cmllcztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0SW5mbygpOiBQcm9taXNlPE1vbmVyb0RhZW1vbkluZm8+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZ2V0SW5mbygpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2luZm9cIik7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcC5yZXN1bHQpO1xuICAgIHJldHVybiBNb25lcm9EYWVtb25ScGMuY29udmVydFJwY0luZm8ocmVzcC5yZXN1bHQpO1xuICB9XG4gIFxuICBhc3luYyBnZXRTeW5jSW5mbygpOiBQcm9taXNlPE1vbmVyb0RhZW1vblN5bmNJbmZvPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldFN5bmNJbmZvKCk7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJzeW5jX2luZm9cIik7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcC5yZXN1bHQpO1xuICAgIHJldHVybiBNb25lcm9EYWVtb25ScGMuY29udmVydFJwY1N5bmNJbmZvKHJlc3AucmVzdWx0KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0SGFyZEZvcmtJbmZvKCk6IFByb21pc2U8TW9uZXJvSGFyZEZvcmtJbmZvPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldEhhcmRGb3JrSW5mbygpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiaGFyZF9mb3JrX2luZm9cIik7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcC5yZXN1bHQpO1xuICAgIHJldHVybiBNb25lcm9EYWVtb25ScGMuY29udmVydFJwY0hhcmRGb3JrSW5mbyhyZXNwLnJlc3VsdCk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEFsdENoYWlucygpOiBQcm9taXNlPE1vbmVyb0FsdENoYWluW10+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZ2V0QWx0Q2hhaW5zKCk7XG4gICAgXG4vLyAgICAvLyBtb2NrZWQgcmVzcG9uc2UgZm9yIHRlc3Rcbi8vICAgIGxldCByZXNwID0ge1xuLy8gICAgICAgIHN0YXR1czogXCJPS1wiLFxuLy8gICAgICAgIGNoYWluczogW1xuLy8gICAgICAgICAge1xuLy8gICAgICAgICAgICBibG9ja19oYXNoOiBcIjY5N2NmMDNjODlhOWIxMThmN2JkZjExYjFiM2E2YTAyOGQ3YjM2MTdkMmQwZWQ5MTMyMmM1NzA5YWNmNzU2MjVcIixcbi8vICAgICAgICAgICAgZGlmZmljdWx0eTogMTQxMTQ3Mjk2MzgzMDAyODAsXG4vLyAgICAgICAgICAgIGhlaWdodDogMTU2MjA2Mixcbi8vICAgICAgICAgICAgbGVuZ3RoOiAyXG4vLyAgICAgICAgICB9XG4vLyAgICAgICAgXVxuLy8gICAgfVxuICAgIFxuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2FsdGVybmF0ZV9jaGFpbnNcIik7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcC5yZXN1bHQpO1xuICAgIGxldCBjaGFpbnMgPSBbXTtcbiAgICBpZiAoIXJlc3AucmVzdWx0LmNoYWlucykgcmV0dXJuIGNoYWlucztcbiAgICBmb3IgKGxldCBycGNDaGFpbiBvZiByZXNwLnJlc3VsdC5jaGFpbnMpIGNoYWlucy5wdXNoKE1vbmVyb0RhZW1vblJwYy5jb252ZXJ0UnBjQWx0Q2hhaW4ocnBjQ2hhaW4pKTtcbiAgICByZXR1cm4gY2hhaW5zO1xuICB9XG4gIFxuICBhc3luYyBnZXRBbHRCbG9ja0hhc2hlcygpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldEFsdEJsb2NrSGFzaGVzKCk7XG4gICAgXG4vLyAgICAvLyBtb2NrZWQgcmVzcG9uc2UgZm9yIHRlc3Rcbi8vICAgIGxldCByZXNwID0ge1xuLy8gICAgICAgIHN0YXR1czogXCJPS1wiLFxuLy8gICAgICAgIHVudHJ1c3RlZDogZmFsc2UsXG4vLyAgICAgICAgYmxrc19oYXNoZXM6IFtcIjljMjI3N2M1NDcwMjM0YmU4YjMyMzgyY2RmODA5NGExMDNhYmE0ZmNkNWU4NzVhNmZjMTU5ZGMyZWMwMGUwMTFcIixcIjYzN2MwZTBmMDU1OGUyODQ0OTNmMzhhNWZjY2EzNjE1ZGI1OTQ1OGQ5MGQzYTVlZmYwYTE4ZmY1OWI4M2Y0NmZcIixcIjZmM2FkYzE3NGEyZTgwODI4MTllYmI5NjVjOTZhMDk1ZTNlOGI2MzkyOWFkOWJlMmQ3MDVhZDljMDg2YTZiMWNcIixcIjY5N2NmMDNjODlhOWIxMThmN2JkZjExYjFiM2E2YTAyOGQ3YjM2MTdkMmQwZWQ5MTMyMmM1NzA5YWNmNzU2MjVcIl1cbi8vICAgIH1cbiAgICBcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRQYXRoUmVxdWVzdChcImdldF9hbHRfYmxvY2tzX2hhc2hlc1wiKTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwKTtcbiAgICBpZiAoIXJlc3AuYmxrc19oYXNoZXMpIHJldHVybiBbXTtcbiAgICByZXR1cm4gcmVzcC5ibGtzX2hhc2hlcztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0RG93bmxvYWRMaW1pdCgpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5nZXREb3dubG9hZExpbWl0KCk7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLmdldEJhbmR3aWR0aExpbWl0cygpKVswXTtcbiAgfVxuICBcbiAgYXN5bmMgc2V0RG93bmxvYWRMaW1pdChsaW1pdDogbnVtYmVyKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uc2V0RG93bmxvYWRMaW1pdChsaW1pdCk7XG4gICAgaWYgKGxpbWl0ID09IC0xKSByZXR1cm4gYXdhaXQgdGhpcy5yZXNldERvd25sb2FkTGltaXQoKTtcbiAgICBpZiAoIShHZW5VdGlscy5pc0ludChsaW1pdCkgJiYgbGltaXQgPiAwKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiRG93bmxvYWQgbGltaXQgbXVzdCBiZSBhbiBpbnRlZ2VyIGdyZWF0ZXIgdGhhbiAwXCIpO1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5zZXRCYW5kd2lkdGhMaW1pdHMobGltaXQsIDApKVswXTtcbiAgfVxuICBcbiAgYXN5bmMgcmVzZXREb3dubG9hZExpbWl0KCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLnJlc2V0RG93bmxvYWRMaW1pdCgpO1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5zZXRCYW5kd2lkdGhMaW1pdHMoLTEsIDApKVswXTtcbiAgfVxuXG4gIGFzeW5jIGdldFVwbG9hZExpbWl0KCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldFVwbG9hZExpbWl0KCk7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLmdldEJhbmR3aWR0aExpbWl0cygpKVsxXTtcbiAgfVxuICBcbiAgYXN5bmMgc2V0VXBsb2FkTGltaXQobGltaXQ6IG51bWJlcik6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLnNldFVwbG9hZExpbWl0KGxpbWl0KTtcbiAgICBpZiAobGltaXQgPT0gLTEpIHJldHVybiBhd2FpdCB0aGlzLnJlc2V0VXBsb2FkTGltaXQoKTtcbiAgICBpZiAoIShHZW5VdGlscy5pc0ludChsaW1pdCkgJiYgbGltaXQgPiAwKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiVXBsb2FkIGxpbWl0IG11c3QgYmUgYW4gaW50ZWdlciBncmVhdGVyIHRoYW4gMFwiKTtcbiAgICByZXR1cm4gKGF3YWl0IHRoaXMuc2V0QmFuZHdpZHRoTGltaXRzKDAsIGxpbWl0KSlbMV07XG4gIH1cbiAgXG4gIGFzeW5jIHJlc2V0VXBsb2FkTGltaXQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24ucmVzZXRVcGxvYWRMaW1pdCgpO1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5zZXRCYW5kd2lkdGhMaW1pdHMoMCwgLTEpKVsxXTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UGVlcnMoKTogUHJvbWlzZTxNb25lcm9QZWVyW10+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uZ2V0UGVlcnMoKTtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF9jb25uZWN0aW9uc1wiKTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwLnJlc3VsdCk7XG4gICAgbGV0IHBlZXJzID0gW107XG4gICAgaWYgKCFyZXNwLnJlc3VsdC5jb25uZWN0aW9ucykgcmV0dXJuIHBlZXJzO1xuICAgIGZvciAobGV0IHJwY0Nvbm5lY3Rpb24gb2YgcmVzcC5yZXN1bHQuY29ubmVjdGlvbnMpIHtcbiAgICAgIHBlZXJzLnB1c2goTW9uZXJvRGFlbW9uUnBjLmNvbnZlcnRScGNDb25uZWN0aW9uKHJwY0Nvbm5lY3Rpb24pKTtcbiAgICB9XG4gICAgcmV0dXJuIHBlZXJzO1xuICB9XG4gIFxuICBhc3luYyBnZXRLbm93blBlZXJzKCk6IFByb21pc2U8TW9uZXJvUGVlcltdPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmdldEtub3duUGVlcnMoKTtcbiAgICBcbiAgICAvLyB0eCBjb25maWdcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRQYXRoUmVxdWVzdChcImdldF9wZWVyX2xpc3RcIik7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcCk7XG4gICAgXG4gICAgLy8gYnVpbGQgcGVlcnNcbiAgICBsZXQgcGVlcnMgPSBbXTtcbiAgICBpZiAocmVzcC5ncmF5X2xpc3QpIHtcbiAgICAgIGZvciAobGV0IHJwY1BlZXIgb2YgcmVzcC5ncmF5X2xpc3QpIHtcbiAgICAgICAgbGV0IHBlZXIgPSBNb25lcm9EYWVtb25ScGMuY29udmVydFJwY1BlZXIocnBjUGVlcik7XG4gICAgICAgIHBlZXIuc2V0SXNPbmxpbmUoZmFsc2UpOyAvLyBncmF5IGxpc3QgbWVhbnMgb2ZmbGluZSBsYXN0IGNoZWNrZWRcbiAgICAgICAgcGVlcnMucHVzaChwZWVyKTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKHJlc3Aud2hpdGVfbGlzdCkge1xuICAgICAgZm9yIChsZXQgcnBjUGVlciBvZiByZXNwLndoaXRlX2xpc3QpIHtcbiAgICAgICAgbGV0IHBlZXIgPSBNb25lcm9EYWVtb25ScGMuY29udmVydFJwY1BlZXIocnBjUGVlcik7XG4gICAgICAgIHBlZXIuc2V0SXNPbmxpbmUodHJ1ZSk7IC8vIHdoaXRlIGxpc3QgbWVhbnMgb25saW5lIGxhc3QgY2hlY2tlZFxuICAgICAgICBwZWVycy5wdXNoKHBlZXIpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcGVlcnM7XG4gIH1cbiAgXG4gIGFzeW5jIHNldE91dGdvaW5nUGVlckxpbWl0KGxpbWl0OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uc2V0T3V0Z29pbmdQZWVyTGltaXQobGltaXQpO1xuICAgIGlmICghKEdlblV0aWxzLmlzSW50KGxpbWl0KSAmJiBsaW1pdCA+PSAwKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiT3V0Z29pbmcgcGVlciBsaW1pdCBtdXN0IGJlID49IDBcIik7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kUGF0aFJlcXVlc3QoXCJvdXRfcGVlcnNcIiwge291dF9wZWVyczogbGltaXR9KTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwKTtcbiAgfVxuICBcbiAgYXN5bmMgc2V0SW5jb21pbmdQZWVyTGltaXQobGltaXQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5zZXRJbmNvbWluZ1BlZXJMaW1pdChsaW1pdCk7XG4gICAgaWYgKCEoR2VuVXRpbHMuaXNJbnQobGltaXQpICYmIGxpbWl0ID49IDApKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJJbmNvbWluZyBwZWVyIGxpbWl0IG11c3QgYmUgPj0gMFwiKTtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRQYXRoUmVxdWVzdChcImluX3BlZXJzXCIsIHtpbl9wZWVyczogbGltaXR9KTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UGVlckJhbnMoKTogUHJvbWlzZTxNb25lcm9CYW5bXT4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5nZXRQZWVyQmFucygpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2JhbnNcIik7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcC5yZXN1bHQpO1xuICAgIGxldCBiYW5zID0gW107XG4gICAgZm9yIChsZXQgcnBjQmFuIG9mIHJlc3AucmVzdWx0LmJhbnMpIHtcbiAgICAgIGxldCBiYW4gPSBuZXcgTW9uZXJvQmFuKCk7XG4gICAgICBiYW4uc2V0SG9zdChycGNCYW4uaG9zdCk7XG4gICAgICBiYW4uc2V0SXAocnBjQmFuLmlwKTtcbiAgICAgIGJhbi5zZXRTZWNvbmRzKHJwY0Jhbi5zZWNvbmRzKTtcbiAgICAgIGJhbnMucHVzaChiYW4pO1xuICAgIH1cbiAgICByZXR1cm4gYmFucztcbiAgfVxuICBcbiAgYXN5bmMgc2V0UGVlckJhbnMoYmFuczogTW9uZXJvQmFuW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uc2V0UGVlckJhbnMoYmFucyk7XG4gICAgbGV0IHJwY0JhbnMgPSBbXTtcbiAgICBmb3IgKGxldCBiYW4gb2YgYmFucykgcnBjQmFucy5wdXNoKE1vbmVyb0RhZW1vblJwYy5jb252ZXJ0VG9ScGNCYW4oYmFuKSk7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJzZXRfYmFuc1wiLCB7YmFuczogcnBjQmFuc30pO1xuICAgIE1vbmVyb0RhZW1vblJwYy5jaGVja1Jlc3BvbnNlU3RhdHVzKHJlc3AucmVzdWx0KTtcbiAgfVxuICBcbiAgYXN5bmMgc3RhcnRNaW5pbmcoYWRkcmVzczogc3RyaW5nLCBudW1UaHJlYWRzPzogbnVtYmVyLCBpc0JhY2tncm91bmQ/OiBib29sZWFuLCBpZ25vcmVCYXR0ZXJ5PzogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5zdGFydE1pbmluZyhhZGRyZXNzLCBudW1UaHJlYWRzLCBpc0JhY2tncm91bmQsIGlnbm9yZUJhdHRlcnkpO1xuICAgIGFzc2VydChhZGRyZXNzLCBcIk11c3QgcHJvdmlkZSBhZGRyZXNzIHRvIG1pbmUgdG9cIik7XG4gICAgYXNzZXJ0KEdlblV0aWxzLmlzSW50KG51bVRocmVhZHMpICYmIG51bVRocmVhZHMgPiAwLCBcIk51bWJlciBvZiB0aHJlYWRzIG11c3QgYmUgYW4gaW50ZWdlciBncmVhdGVyIHRoYW4gMFwiKTtcbiAgICBhc3NlcnQoaXNCYWNrZ3JvdW5kID09PSB1bmRlZmluZWQgfHwgdHlwZW9mIGlzQmFja2dyb3VuZCA9PT0gXCJib29sZWFuXCIpO1xuICAgIGFzc2VydChpZ25vcmVCYXR0ZXJ5ID09PSB1bmRlZmluZWQgfHwgdHlwZW9mIGlnbm9yZUJhdHRlcnkgPT09IFwiYm9vbGVhblwiKTtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRQYXRoUmVxdWVzdChcInN0YXJ0X21pbmluZ1wiLCB7XG4gICAgICBtaW5lcl9hZGRyZXNzOiBhZGRyZXNzLFxuICAgICAgdGhyZWFkc19jb3VudDogbnVtVGhyZWFkcyxcbiAgICAgIGRvX2JhY2tncm91bmRfbWluaW5nOiBpc0JhY2tncm91bmQsXG4gICAgICBpZ25vcmVfYmF0dGVyeTogaWdub3JlQmF0dGVyeSxcbiAgICB9KTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwKTtcbiAgfVxuICBcbiAgYXN5bmMgc3RvcE1pbmluZygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uc3RvcE1pbmluZygpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZFBhdGhSZXF1ZXN0KFwic3RvcF9taW5pbmdcIik7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcCk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldE1pbmluZ1N0YXR1cygpOiBQcm9taXNlPE1vbmVyb01pbmluZ1N0YXR1cz4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi5nZXRNaW5pbmdTdGF0dXMoKTtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRQYXRoUmVxdWVzdChcIm1pbmluZ19zdGF0dXNcIik7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcCk7XG4gICAgcmV0dXJuIE1vbmVyb0RhZW1vblJwYy5jb252ZXJ0UnBjTWluaW5nU3RhdHVzKHJlc3ApO1xuICB9XG4gIFxuICBhc3luYyBzdWJtaXRCbG9ja3MoYmxvY2tCbG9iczogc3RyaW5nW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uc3VibWl0QmxvY2tzKGJsb2NrQmxvYnMpO1xuICAgIGFzc2VydChBcnJheS5pc0FycmF5KGJsb2NrQmxvYnMpICYmIGJsb2NrQmxvYnMubGVuZ3RoID4gMCwgXCJNdXN0IHByb3ZpZGUgYW4gYXJyYXkgb2YgbWluZWQgYmxvY2sgYmxvYnMgdG8gc3VibWl0XCIpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwic3VibWl0X2Jsb2NrXCIsIGJsb2NrQmxvYnMpO1xuICAgIE1vbmVyb0RhZW1vblJwYy5jaGVja1Jlc3BvbnNlU3RhdHVzKHJlc3AucmVzdWx0KTtcbiAgfVxuXG4gIGFzeW5jIHBydW5lQmxvY2tjaGFpbihjaGVjazogYm9vbGVhbik6IFByb21pc2U8TW9uZXJvUHJ1bmVSZXN1bHQ+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24ucHJ1bmVCbG9ja2NoYWluKCk7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJwcnVuZV9ibG9ja2NoYWluXCIsIHtjaGVjazogY2hlY2t9LCAwKTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwLnJlc3VsdCk7XG4gICAgbGV0IHJlc3VsdCA9IG5ldyBNb25lcm9QcnVuZVJlc3VsdCgpO1xuICAgIHJlc3VsdC5zZXRJc1BydW5lZChyZXNwLnJlc3VsdC5wcnVuZWQpO1xuICAgIHJlc3VsdC5zZXRQcnVuaW5nU2VlZChyZXNwLnJlc3VsdC5wcnVuaW5nX3NlZWQpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgXG4gIGFzeW5jIGNoZWNrRm9yVXBkYXRlKCk6IFByb21pc2U8TW9uZXJvRGFlbW9uVXBkYXRlQ2hlY2tSZXN1bHQ+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uY2hlY2tGb3JVcGRhdGUoKTtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRQYXRoUmVxdWVzdChcInVwZGF0ZVwiLCB7Y29tbWFuZDogXCJjaGVja1wifSk7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcCk7XG4gICAgcmV0dXJuIE1vbmVyb0RhZW1vblJwYy5jb252ZXJ0UnBjVXBkYXRlQ2hlY2tSZXN1bHQocmVzcCk7XG4gIH1cbiAgXG4gIGFzeW5jIGRvd25sb2FkVXBkYXRlKHBhdGg/OiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0RhZW1vblVwZGF0ZURvd25sb2FkUmVzdWx0PiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLnByb3h5VG9Xb3JrZXIpIHJldHVybiB0aGlzLnByb3h5RGFlbW9uLmRvd25sb2FkVXBkYXRlKHBhdGgpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZFBhdGhSZXF1ZXN0KFwidXBkYXRlXCIsIHtjb21tYW5kOiBcImRvd25sb2FkXCIsIHBhdGg6IHBhdGh9KTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwKTtcbiAgICByZXR1cm4gTW9uZXJvRGFlbW9uUnBjLmNvbnZlcnRScGNVcGRhdGVEb3dubG9hZFJlc3VsdChyZXNwKTtcbiAgfVxuICBcbiAgYXN5bmMgc3RvcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5jb25maWcucHJveHlUb1dvcmtlcikgcmV0dXJuIHRoaXMucHJveHlEYWVtb24uc3RvcCgpO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZFBhdGhSZXF1ZXN0KFwic3RvcF9kYWVtb25cIik7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNoZWNrUmVzcG9uc2VTdGF0dXMocmVzcCk7XG4gIH1cbiAgXG4gIGFzeW5jIHdhaXRGb3JOZXh0QmxvY2tIZWFkZXIoKTogUHJvbWlzZTxNb25lcm9CbG9ja0hlYWRlcj4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5wcm94eVRvV29ya2VyKSByZXR1cm4gdGhpcy5wcm94eURhZW1vbi53YWl0Rm9yTmV4dEJsb2NrSGVhZGVyKCk7XG4gICAgbGV0IHRoYXQgPSB0aGlzO1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShhc3luYyBmdW5jdGlvbihyZXNvbHZlKSB7XG4gICAgICBhd2FpdCB0aGF0LmFkZExpc3RlbmVyKG5ldyBjbGFzcyBleHRlbmRzIE1vbmVyb0RhZW1vbkxpc3RlbmVyIHtcbiAgICAgICAgYXN5bmMgb25CbG9ja0hlYWRlcihoZWFkZXIpIHtcbiAgICAgICAgICBhd2FpdCB0aGF0LnJlbW92ZUxpc3RlbmVyKHRoaXMpO1xuICAgICAgICAgIHJlc29sdmUoaGVhZGVyKTtcbiAgICAgICAgfVxuICAgICAgfSk7IFxuICAgIH0pO1xuICB9XG5cbiAgZ2V0UG9sbEludGVydmFsKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuY29uZmlnLnBvbGxJbnRlcnZhbDtcbiAgfVxuICBcbiAgLy8gLS0tLS0tLS0tLS0gQUREIEpTRE9DIEZPUiBTVVBQT1JURUQgREVGQVVMVCBJTVBMRU1FTlRBVElPTlMgLS0tLS0tLS0tLS0tLS1cbiAgYXN5bmMgZ2V0VHgodHhIYXNoPzogc3RyaW5nLCBwcnVuZSA9IGZhbHNlKTogUHJvbWlzZTxNb25lcm9UeHx1bmRlZmluZWQ+IHsgcmV0dXJuIHN1cGVyLmdldFR4KHR4SGFzaCwgcHJ1bmUpOyB9O1xuICBhc3luYyBnZXRUeEhleCh0eEhhc2g6IHN0cmluZywgcHJ1bmUgPSBmYWxzZSk6IFByb21pc2U8c3RyaW5nPiB7IHJldHVybiBzdXBlci5nZXRUeEhleCh0eEhhc2gsIHBydW5lKTsgfTtcbiAgYXN5bmMgZ2V0S2V5SW1hZ2VTcGVudFN0YXR1cyhrZXlJbWFnZTogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9LZXlJbWFnZVNwZW50U3RhdHVzPiB7IHJldHVybiBzdXBlci5nZXRLZXlJbWFnZVNwZW50U3RhdHVzKGtleUltYWdlKTsgfVxuICBhc3luYyBzZXRQZWVyQmFuKGJhbjogTW9uZXJvQmFuKTogUHJvbWlzZTx2b2lkPiB7IHJldHVybiBzdXBlci5zZXRQZWVyQmFuKGJhbik7IH1cbiAgYXN5bmMgc3VibWl0QmxvY2soYmxvY2tCbG9iOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHsgcmV0dXJuIHN1cGVyLnN1Ym1pdEJsb2NrKGJsb2NrQmxvYik7IH1cbiAgXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gUFJJVkFURSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgcHJvdGVjdGVkIHJlZnJlc2hMaXN0ZW5pbmcoKSB7XG4gICAgaWYgKHRoaXMucG9sbExpc3RlbmVyID09IHVuZGVmaW5lZCAmJiB0aGlzLmxpc3RlbmVycy5sZW5ndGgpIHRoaXMucG9sbExpc3RlbmVyID0gbmV3IERhZW1vblBvbGxlcih0aGlzKTtcbiAgICBpZiAodGhpcy5wb2xsTGlzdGVuZXIgIT09IHVuZGVmaW5lZCkgdGhpcy5wb2xsTGlzdGVuZXIuc2V0SXNQb2xsaW5nKHRoaXMubGlzdGVuZXJzLmxlbmd0aCA+IDApO1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgYXN5bmMgZ2V0QmFuZHdpZHRoTGltaXRzKCkge1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZFBhdGhSZXF1ZXN0KFwiZ2V0X2xpbWl0XCIpO1xuICAgIE1vbmVyb0RhZW1vblJwYy5jaGVja1Jlc3BvbnNlU3RhdHVzKHJlc3ApO1xuICAgIHJldHVybiBbcmVzcC5saW1pdF9kb3duLCByZXNwLmxpbWl0X3VwXTtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIGFzeW5jIHNldEJhbmR3aWR0aExpbWl0cyhkb3duTGltaXQsIHVwTGltaXQpIHtcbiAgICBpZiAoZG93bkxpbWl0ID09PSB1bmRlZmluZWQpIGRvd25MaW1pdCA9IDA7XG4gICAgaWYgKHVwTGltaXQgPT09IHVuZGVmaW5lZCkgdXBMaW1pdCA9IDA7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kUGF0aFJlcXVlc3QoXCJzZXRfbGltaXRcIiwge2xpbWl0X2Rvd246IGRvd25MaW1pdCwgbGltaXRfdXA6IHVwTGltaXR9KTtcbiAgICBNb25lcm9EYWVtb25ScGMuY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwKTtcbiAgICByZXR1cm4gW3Jlc3AubGltaXRfZG93biwgcmVzcC5saW1pdF91cF07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgYSBjb250aWd1b3VzIGNodW5rIG9mIGJsb2NrcyBzdGFydGluZyBmcm9tIGEgZ2l2ZW4gaGVpZ2h0IHVwIHRvIGEgbWF4aW11bVxuICAgKiBoZWlnaHQgb3IgYW1vdW50IG9mIGJsb2NrIGRhdGEgZmV0Y2hlZCBmcm9tIHRoZSBibG9ja2NoYWluLCB3aGljaGV2ZXIgY29tZXMgZmlyc3QuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXJ0SGVpZ2h0XSAtIHN0YXJ0IGhlaWdodCB0byByZXRyaWV2ZSBibG9ja3MgKGRlZmF1bHQgMClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFttYXhIZWlnaHRdIC0gbWF4aW11bSBlbmQgaGVpZ2h0IHRvIHJldHJpZXZlIGJsb2NrcyAoZGVmYXVsdCBibG9ja2NoYWluIGhlaWdodClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFttYXhSZXFTaXplXSAtIG1heGltdW0gYW1vdW50IG9mIGJsb2NrIGRhdGEgdG8gZmV0Y2ggZnJvbSB0aGUgYmxvY2tjaGFpbiBpbiBieXRlcyAoZGVmYXVsdCAzLDAwMCwwMDAgYnl0ZXMpXG4gICAqIEByZXR1cm4ge01vbmVyb0Jsb2NrW119IGFyZSB0aGUgcmVzdWx0aW5nIGNodW5rIG9mIGJsb2Nrc1xuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGdldE1heEJsb2NrcyhzdGFydEhlaWdodCwgbWF4SGVpZ2h0LCBtYXhSZXFTaXplKSB7XG4gICAgaWYgKHN0YXJ0SGVpZ2h0ID09PSB1bmRlZmluZWQpIHN0YXJ0SGVpZ2h0ID0gMDtcbiAgICBpZiAobWF4SGVpZ2h0ID09PSB1bmRlZmluZWQpIG1heEhlaWdodCA9IGF3YWl0IHRoaXMuZ2V0SGVpZ2h0KCkgLSAxO1xuICAgIGlmIChtYXhSZXFTaXplID09PSB1bmRlZmluZWQpIG1heFJlcVNpemUgPSBNb25lcm9EYWVtb25ScGMuTUFYX1JFUV9TSVpFO1xuICAgIFxuICAgIC8vIGRldGVybWluZSBlbmQgaGVpZ2h0IHRvIGZldGNoXG4gICAgbGV0IHJlcVNpemUgPSAwO1xuICAgIGxldCBlbmRIZWlnaHQgPSBzdGFydEhlaWdodCAtIDE7XG4gICAgd2hpbGUgKHJlcVNpemUgPCBtYXhSZXFTaXplICYmIGVuZEhlaWdodCA8IG1heEhlaWdodCkge1xuICAgICAgXG4gICAgICAvLyBnZXQgaGVhZGVyIG9mIG5leHQgYmxvY2tcbiAgICAgIGxldCBoZWFkZXIgPSBhd2FpdCB0aGlzLmdldEJsb2NrSGVhZGVyQnlIZWlnaHRDYWNoZWQoZW5kSGVpZ2h0ICsgMSwgbWF4SGVpZ2h0KTtcbiAgICAgIFxuICAgICAgLy8gYmxvY2sgY2Fubm90IGJlIGJpZ2dlciB0aGFuIG1heCByZXF1ZXN0IHNpemVcbiAgICAgIGFzc2VydChoZWFkZXIuZ2V0U2l6ZSgpIDw9IG1heFJlcVNpemUsIFwiQmxvY2sgZXhjZWVkcyBtYXhpbXVtIHJlcXVlc3Qgc2l6ZTogXCIgKyBoZWFkZXIuZ2V0U2l6ZSgpKTtcbiAgICAgIFxuICAgICAgLy8gZG9uZSBpdGVyYXRpbmcgaWYgZmV0Y2hpbmcgYmxvY2sgd291bGQgZXhjZWVkIG1heCByZXF1ZXN0IHNpemVcbiAgICAgIGlmIChyZXFTaXplICsgaGVhZGVyLmdldFNpemUoKSA+IG1heFJlcVNpemUpIGJyZWFrO1xuICAgICAgXG4gICAgICAvLyBvdGhlcndpc2UgYmxvY2sgaXMgaW5jbHVkZWRcbiAgICAgIHJlcVNpemUgKz0gaGVhZGVyLmdldFNpemUoKTtcbiAgICAgIGVuZEhlaWdodCsrO1xuICAgIH1cbiAgICByZXR1cm4gZW5kSGVpZ2h0ID49IHN0YXJ0SGVpZ2h0ID8gYXdhaXQgdGhpcy5nZXRCbG9ja3NCeVJhbmdlKHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQpIDogW107XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgYSBoZWFkZXIgYnkgaGVpZ2h0IGZyb20gdGhlIGNhY2hlIG9yIGZldGNoZXMgYW5kIGNhY2hlcyBhIGhlYWRlclxuICAgKiByYW5nZSBpZiBub3QgYWxyZWFkeSBpbiB0aGUgY2FjaGUuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gaGVpZ2h0IG9mIHRoZSBoZWFkZXIgdG8gcmV0cmlldmUgZnJvbSB0aGUgY2FjaGVcbiAgICogQHBhcmFtIHtudW1iZXJ9IG1heEhlaWdodCAtIG1heGltdW0gaGVpZ2h0IG9mIGhlYWRlcnMgdG8gY2FjaGVcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBnZXRCbG9ja0hlYWRlckJ5SGVpZ2h0Q2FjaGVkKGhlaWdodCwgbWF4SGVpZ2h0KSB7XG4gICAgXG4gICAgLy8gZ2V0IGhlYWRlciBmcm9tIGNhY2hlXG4gICAgbGV0IGNhY2hlZEhlYWRlciA9IHRoaXMuY2FjaGVkSGVhZGVyc1toZWlnaHRdO1xuICAgIGlmIChjYWNoZWRIZWFkZXIpIHJldHVybiBjYWNoZWRIZWFkZXI7XG4gICAgXG4gICAgLy8gZmV0Y2ggYW5kIGNhY2hlIGhlYWRlcnMgaWYgbm90IGluIGNhY2hlXG4gICAgbGV0IGVuZEhlaWdodCA9IE1hdGgubWluKG1heEhlaWdodCwgaGVpZ2h0ICsgTW9uZXJvRGFlbW9uUnBjLk5VTV9IRUFERVJTX1BFUl9SRVEgLSAxKTsgIC8vIFRPRE86IGNvdWxkIHNwZWNpZnkgZW5kIGhlaWdodCB0byBjYWNoZSB0byBvcHRpbWl6ZSBzbWFsbCByZXF1ZXN0cyAod291bGQgbGlrZSB0byBoYXZlIHRpbWUgcHJvZmlsaW5nIGluIHBsYWNlIHRob3VnaClcbiAgICBsZXQgaGVhZGVycyA9IGF3YWl0IHRoaXMuZ2V0QmxvY2tIZWFkZXJzQnlSYW5nZShoZWlnaHQsIGVuZEhlaWdodCk7XG4gICAgZm9yIChsZXQgaGVhZGVyIG9mIGhlYWRlcnMpIHtcbiAgICAgIHRoaXMuY2FjaGVkSGVhZGVyc1toZWFkZXIuZ2V0SGVpZ2h0KCldID0gaGVhZGVyO1xuICAgIH1cbiAgICBcbiAgICAvLyByZXR1cm4gdGhlIGNhY2hlZCBoZWFkZXJcbiAgICByZXR1cm4gdGhpcy5jYWNoZWRIZWFkZXJzW2hlaWdodF07XG4gIH1cbiAgXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBTVEFUSUMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgc3RhdGljIGFzeW5jIGNvbm5lY3RUb0RhZW1vblJwYyh1cmlPckNvbmZpZzogc3RyaW5nIHwgUGFydGlhbDxNb25lcm9ScGNDb25uZWN0aW9uPiB8IFBhcnRpYWw8TW9uZXJvRGFlbW9uQ29uZmlnPiB8IHN0cmluZ1tdLCB1c2VybmFtZT86IHN0cmluZywgcGFzc3dvcmQ/OiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0RhZW1vblJwYz4ge1xuICAgIGxldCBjb25maWcgPSBNb25lcm9EYWVtb25ScGMubm9ybWFsaXplQ29uZmlnKHVyaU9yQ29uZmlnLCB1c2VybmFtZSwgcGFzc3dvcmQpO1xuICAgIGlmIChjb25maWcuY21kKSByZXR1cm4gTW9uZXJvRGFlbW9uUnBjLnN0YXJ0TW9uZXJvZFByb2Nlc3MoY29uZmlnKTtcbiAgICByZXR1cm4gbmV3IE1vbmVyb0RhZW1vblJwYyhjb25maWcsIGNvbmZpZy5wcm94eVRvV29ya2VyID8gYXdhaXQgTW9uZXJvRGFlbW9uUnBjUHJveHkuY29ubmVjdChjb25maWcpIDogdW5kZWZpbmVkKTtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIHN0YXRpYyBhc3luYyBzdGFydE1vbmVyb2RQcm9jZXNzKGNvbmZpZzogTW9uZXJvRGFlbW9uQ29uZmlnKTogUHJvbWlzZTxNb25lcm9EYWVtb25ScGM+IHtcbiAgICBhc3NlcnQoR2VuVXRpbHMuaXNBcnJheShjb25maWcuY21kKSwgXCJNdXN0IHByb3ZpZGUgc3RyaW5nIGFycmF5IHdpdGggY29tbWFuZCBsaW5lIHBhcmFtZXRlcnNcIik7XG4gICAgXG4gICAgLy8gc3RhcnQgcHJvY2Vzc1xuICAgIGxldCBjaGlsZFByb2Nlc3MgPSByZXF1aXJlKCdjaGlsZF9wcm9jZXNzJykuc3Bhd24oY29uZmlnLmNtZFswXSwgY29uZmlnLmNtZC5zbGljZSgxKSwge1xuICAgICAgZW52OiB7IC4uLnByb2Nlc3MuZW52LCBMQU5HOiAnZW5fVVMuVVRGLTgnIH0gLy8gc2NyYXBlIG91dHB1dCBpbiBlbmdsaXNoXG4gICAgfSk7XG4gICAgY2hpbGRQcm9jZXNzLnN0ZG91dC5zZXRFbmNvZGluZygndXRmOCcpO1xuICAgIGNoaWxkUHJvY2Vzcy5zdGRlcnIuc2V0RW5jb2RpbmcoJ3V0ZjgnKTtcbiAgICBcbiAgICAvLyByZXR1cm4gcHJvbWlzZSB3aGljaCByZXNvbHZlcyBhZnRlciBzdGFydGluZyBtb25lcm9kXG4gICAgbGV0IHVyaTtcbiAgICBsZXQgb3V0cHV0ID0gXCJcIjtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgXG4gICAgICAgIC8vIGhhbmRsZSBzdGRvdXRcbiAgICAgICAgY2hpbGRQcm9jZXNzLnN0ZG91dC5vbignZGF0YScsIGFzeW5jIGZ1bmN0aW9uKGRhdGEpIHtcbiAgICAgICAgICBsZXQgbGluZSA9IGRhdGEudG9TdHJpbmcoKTtcbiAgICAgICAgICBMaWJyYXJ5VXRpbHMubG9nKDIsIGxpbmUpO1xuICAgICAgICAgIG91dHB1dCArPSBsaW5lICsgJ1xcbic7IC8vIGNhcHR1cmUgb3V0cHV0IGluIGNhc2Ugb2YgZXJyb3JcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBleHRyYWN0IHVyaSBmcm9tIGUuZy4gXCJJIEJpbmRpbmcgb24gMTI3LjAuMC4xIChJUHY0KTozODA4NVwiXG4gICAgICAgICAgbGV0IHVyaUxpbmVDb250YWlucyA9IFwiQmluZGluZyBvbiBcIjtcbiAgICAgICAgICBsZXQgdXJpTGluZUNvbnRhaW5zSWR4ID0gbGluZS5pbmRleE9mKHVyaUxpbmVDb250YWlucyk7XG4gICAgICAgICAgaWYgKHVyaUxpbmVDb250YWluc0lkeCA+PSAwKSB7XG4gICAgICAgICAgICBsZXQgaG9zdCA9IGxpbmUuc3Vic3RyaW5nKHVyaUxpbmVDb250YWluc0lkeCArIHVyaUxpbmVDb250YWlucy5sZW5ndGgsIGxpbmUubGFzdEluZGV4T2YoJyAnKSk7XG4gICAgICAgICAgICBsZXQgdW5mb3JtYXR0ZWRMaW5lID0gbGluZS5yZXBsYWNlKC9cXHUwMDFiXFxbLio/bS9nLCAnJykudHJpbSgpOyAvLyByZW1vdmUgY29sb3IgZm9ybWF0dGluZ1xuICAgICAgICAgICAgbGV0IHBvcnQgPSB1bmZvcm1hdHRlZExpbmUuc3Vic3RyaW5nKHVuZm9ybWF0dGVkTGluZS5sYXN0SW5kZXhPZignOicpICsgMSk7XG4gICAgICAgICAgICBsZXQgc3NsSWR4ID0gY29uZmlnLmNtZC5pbmRleE9mKFwiLS1ycGMtc3NsXCIpO1xuICAgICAgICAgICAgbGV0IHNzbEVuYWJsZWQgPSBzc2xJZHggPj0gMCA/IFwiZW5hYmxlZFwiID09IGNvbmZpZy5jbWRbc3NsSWR4ICsgMV0udG9Mb3dlckNhc2UoKSA6IGZhbHNlO1xuICAgICAgICAgICAgdXJpID0gKHNzbEVuYWJsZWQgPyBcImh0dHBzXCIgOiBcImh0dHBcIikgKyBcIjovL1wiICsgaG9zdCArIFwiOlwiICsgcG9ydDtcbiAgICAgICAgICB9XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gcmVhZCBzdWNjZXNzIG1lc3NhZ2VcbiAgICAgICAgICBpZiAobGluZS5pbmRleE9mKFwiY29yZSBSUEMgc2VydmVyIHN0YXJ0ZWQgb2tcIikgPj0gMCkge1xuICAgICAgICAgICAgXG4gICAgICAgICAgICAvLyBnZXQgdXNlcm5hbWUgYW5kIHBhc3N3b3JkIGZyb20gcGFyYW1zXG4gICAgICAgICAgICBsZXQgdXNlclBhc3NJZHggPSBjb25maWcuY21kLmluZGV4T2YoXCItLXJwYy1sb2dpblwiKTtcbiAgICAgICAgICAgIGxldCB1c2VyUGFzcyA9IHVzZXJQYXNzSWR4ID49IDAgPyBjb25maWcuY21kW3VzZXJQYXNzSWR4ICsgMV0gOiB1bmRlZmluZWQ7XG4gICAgICAgICAgICBsZXQgdXNlcm5hbWUgPSB1c2VyUGFzcyA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogdXNlclBhc3Muc3Vic3RyaW5nKDAsIHVzZXJQYXNzLmluZGV4T2YoJzonKSk7XG4gICAgICAgICAgICBsZXQgcGFzc3dvcmQgPSB1c2VyUGFzcyA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogdXNlclBhc3Muc3Vic3RyaW5nKHVzZXJQYXNzLmluZGV4T2YoJzonKSArIDEpO1xuICAgICAgICAgICAgXG4gICAgICAgICAgICAvLyBjcmVhdGUgY2xpZW50IGNvbm5lY3RlZCB0byBpbnRlcm5hbCBwcm9jZXNzXG4gICAgICAgICAgICBjb25maWcgPSBjb25maWcuY29weSgpLnNldFNlcnZlcih7dXJpOiB1cmksIHVzZXJuYW1lOiB1c2VybmFtZSwgcGFzc3dvcmQ6IHBhc3N3b3JkLCByZWplY3RVbmF1dGhvcml6ZWQ6IGNvbmZpZy5nZXRTZXJ2ZXIoKSA/IGNvbmZpZy5nZXRTZXJ2ZXIoKS5nZXRSZWplY3RVbmF1dGhvcml6ZWQoKSA6IHVuZGVmaW5lZH0pO1xuICAgICAgICAgICAgY29uZmlnLnNldFByb3h5VG9Xb3JrZXIoY29uZmlnLnByb3h5VG9Xb3JrZXIpO1xuICAgICAgICAgICAgY29uZmlnLmNtZCA9IHVuZGVmaW5lZFxuICAgICAgICAgICAgbGV0IGRhZW1vbiA9IGF3YWl0IE1vbmVyb0RhZW1vblJwYy5jb25uZWN0VG9EYWVtb25ScGMoY29uZmlnKTtcbiAgICAgICAgICAgIGRhZW1vbi5wcm9jZXNzID0gY2hpbGRQcm9jZXNzO1xuICAgICAgICAgICAgXG4gICAgICAgICAgICAvLyByZXNvbHZlIHByb21pc2Ugd2l0aCBjbGllbnQgY29ubmVjdGVkIHRvIGludGVybmFsIHByb2Nlc3MgXG4gICAgICAgICAgICB0aGlzLmlzUmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgcmVzb2x2ZShkYWVtb24pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIFxuICAgICAgICAvLyBoYW5kbGUgc3RkZXJyXG4gICAgICAgIGNoaWxkUHJvY2Vzcy5zdGRlcnIub24oJ2RhdGEnLCBmdW5jdGlvbihkYXRhKSB7XG4gICAgICAgICAgaWYgKExpYnJhcnlVdGlscy5nZXRMb2dMZXZlbCgpID49IDIpIGNvbnNvbGUuZXJyb3IoZGF0YSk7XG4gICAgICAgIH0pO1xuICAgICAgICBcbiAgICAgICAgLy8gaGFuZGxlIGV4aXRcbiAgICAgICAgY2hpbGRQcm9jZXNzLm9uKFwiZXhpdFwiLCBmdW5jdGlvbihjb2RlKSB7XG4gICAgICAgICAgaWYgKCF0aGlzLmlzUmVzb2x2ZWQpIHJlamVjdChuZXcgRXJyb3IoXCJtb25lcm9kIHByb2Nlc3MgdGVybWluYXRlZCB3aXRoIGV4aXQgY29kZSBcIiArIGNvZGUgKyAob3V0cHV0ID8gXCI6XFxuXFxuXCIgKyBvdXRwdXQgOiBcIlwiKSkpO1xuICAgICAgICB9KTtcbiAgICAgICAgXG4gICAgICAgIC8vIGhhbmRsZSBlcnJvclxuICAgICAgICBjaGlsZFByb2Nlc3Mub24oXCJlcnJvclwiLCBmdW5jdGlvbihlcnIpIHtcbiAgICAgICAgICBpZiAoZXJyLm1lc3NhZ2UuaW5kZXhPZihcIkVOT0VOVFwiKSA+PSAwKSByZWplY3QobmV3IEVycm9yKFwibW9uZXJvZCBkb2VzIG5vdCBleGlzdCBhdCBwYXRoICdcIiArIGNvbmZpZy5jbWRbMF0gKyBcIidcIikpO1xuICAgICAgICAgIGlmICghdGhpcy5pc1Jlc29sdmVkKSByZWplY3QoZXJyKTtcbiAgICAgICAgfSk7XG4gICAgICAgIFxuICAgICAgICAvLyBoYW5kbGUgdW5jYXVnaHQgZXhjZXB0aW9uXG4gICAgICAgIGNoaWxkUHJvY2Vzcy5vbihcInVuY2F1Z2h0RXhjZXB0aW9uXCIsIGZ1bmN0aW9uKGVyciwgb3JpZ2luKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIlVuY2F1Z2h0IGV4Y2VwdGlvbiBpbiBtb25lcm9kIHByb2Nlc3M6IFwiICsgZXJyLm1lc3NhZ2UpO1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3Iob3JpZ2luKTtcbiAgICAgICAgICBpZiAoIXRoaXMuaXNSZXNvbHZlZCkgcmVqZWN0KGVycik7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihlcnIubWVzc2FnZSk7XG4gICAgfVxuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIG5vcm1hbGl6ZUNvbmZpZyh1cmlPckNvbmZpZzogc3RyaW5nIHwgUGFydGlhbDxNb25lcm9ScGNDb25uZWN0aW9uPiB8IFBhcnRpYWw8TW9uZXJvRGFlbW9uQ29uZmlnPiB8IHN0cmluZ1tdLCB1c2VybmFtZT86IHN0cmluZywgcGFzc3dvcmQ/OiBzdHJpbmcpOiBNb25lcm9EYWVtb25Db25maWcge1xuICAgIGxldCBjb25maWc6IHVuZGVmaW5lZCB8IFBhcnRpYWw8TW9uZXJvRGFlbW9uQ29uZmlnPiA9IHVuZGVmaW5lZDtcbiAgICBpZiAodHlwZW9mIHVyaU9yQ29uZmlnID09PSBcInN0cmluZ1wiKSB7XG4gICAgICBjb25maWcgPSBuZXcgTW9uZXJvRGFlbW9uQ29uZmlnKHtzZXJ2ZXI6IG5ldyBNb25lcm9ScGNDb25uZWN0aW9uKHVyaU9yQ29uZmlnIGFzIHN0cmluZywgdXNlcm5hbWUsIHBhc3N3b3JkKX0pO1xuICAgIH0gZWxzZSBpZiAoKHVyaU9yQ29uZmlnIGFzIFBhcnRpYWw8TW9uZXJvUnBjQ29ubmVjdGlvbj4pLnVyaSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25maWcgPSBuZXcgTW9uZXJvRGFlbW9uQ29uZmlnKHtzZXJ2ZXI6IG5ldyBNb25lcm9ScGNDb25uZWN0aW9uKHVyaU9yQ29uZmlnIGFzIFBhcnRpYWw8TW9uZXJvUnBjQ29ubmVjdGlvbj4pfSk7XG5cbiAgICAgIC8vIHRyYW5zZmVyIHdvcmtlciBwcm94eSBzZXR0aW5nIGZyb20gcnBjIGNvbm5lY3Rpb24gdG8gZGFlbW9uIGNvbmZpZ1xuICAgICAgY29uZmlnLnNldFByb3h5VG9Xb3JrZXIoKHVyaU9yQ29uZmlnIGFzIFBhcnRpYWw8TW9uZXJvUnBjQ29ubmVjdGlvbj4pLnByb3h5VG9Xb3JrZXIpO1xuICAgICAgY29uZmlnLmdldFNlcnZlcigpLnNldFByb3h5VG9Xb3JrZXIoTW9uZXJvUnBjQ29ubmVjdGlvbi5ERUZBVUxUX0NPTkZJRy5wcm94eVRvV29ya2VyKTtcbiAgICB9IGVsc2UgaWYgKEdlblV0aWxzLmlzQXJyYXkodXJpT3JDb25maWcpKSB7XG4gICAgICBjb25maWcgPSBuZXcgTW9uZXJvRGFlbW9uQ29uZmlnKHtjbWQ6IHVyaU9yQ29uZmlnIGFzIHN0cmluZ1tdfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbmZpZyA9IG5ldyBNb25lcm9EYWVtb25Db25maWcodXJpT3JDb25maWcgYXMgUGFydGlhbDxNb25lcm9EYWVtb25Db25maWc+KTtcbiAgICB9XG4gICAgaWYgKGNvbmZpZy5wcm94eVRvV29ya2VyID09PSB1bmRlZmluZWQpIGNvbmZpZy5wcm94eVRvV29ya2VyID0gdHJ1ZTtcbiAgICBpZiAoY29uZmlnLnBvbGxJbnRlcnZhbCA9PT0gdW5kZWZpbmVkKSBjb25maWcucG9sbEludGVydmFsID0gTW9uZXJvRGFlbW9uUnBjLkRFRkFVTFRfUE9MTF9QRVJJT0Q7XG4gICAgcmV0dXJuIGNvbmZpZyBhcyBNb25lcm9EYWVtb25Db25maWc7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgY2hlY2tSZXNwb25zZVN0YXR1cyhyZXNwKSB7XG4gICAgaWYgKHJlc3Auc3RhdHVzICE9PSBcIk9LXCIpIHRocm93IG5ldyBNb25lcm9FcnJvcihyZXNwLnN0YXR1cyk7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgY29udmVydFJwY0Jsb2NrSGVhZGVyKHJwY0hlYWRlcikge1xuICAgIGlmICghcnBjSGVhZGVyKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGxldCBoZWFkZXIgPSBuZXcgTW9uZXJvQmxvY2tIZWFkZXIoKTtcbiAgICBmb3IgKGxldCBrZXkgb2YgT2JqZWN0LmtleXMocnBjSGVhZGVyKSkge1xuICAgICAgbGV0IHZhbCA9IHJwY0hlYWRlcltrZXldO1xuICAgICAgaWYgKGtleSA9PT0gXCJibG9ja19zaXplXCIpIEdlblV0aWxzLnNhZmVTZXQoaGVhZGVyLCBoZWFkZXIuZ2V0U2l6ZSwgaGVhZGVyLnNldFNpemUsIHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiZGVwdGhcIikgR2VuVXRpbHMuc2FmZVNldChoZWFkZXIsIGhlYWRlci5nZXREZXB0aCwgaGVhZGVyLnNldERlcHRoLCB2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImRpZmZpY3VsdHlcIikgeyB9ICAvLyBoYW5kbGVkIGJ5IHdpZGVfZGlmZmljdWx0eVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImN1bXVsYXRpdmVfZGlmZmljdWx0eVwiKSB7IH0gLy8gaGFuZGxlZCBieSB3aWRlX2N1bXVsYXRpdmVfZGlmZmljdWx0eVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImRpZmZpY3VsdHlfdG9wNjRcIikgeyB9ICAvLyBoYW5kbGVkIGJ5IHdpZGVfZGlmZmljdWx0eVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImN1bXVsYXRpdmVfZGlmZmljdWx0eV90b3A2NFwiKSB7IH0gLy8gaGFuZGxlZCBieSB3aWRlX2N1bXVsYXRpdmVfZGlmZmljdWx0eVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIndpZGVfZGlmZmljdWx0eVwiKSBoZWFkZXIuc2V0RGlmZmljdWx0eShHZW5VdGlscy5yZWNvbmNpbGUoaGVhZGVyLmdldERpZmZpY3VsdHkoKSwgTW9uZXJvRGFlbW9uUnBjLnByZWZpeGVkSGV4VG9CSSh2YWwpKSk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwid2lkZV9jdW11bGF0aXZlX2RpZmZpY3VsdHlcIikgaGVhZGVyLnNldEN1bXVsYXRpdmVEaWZmaWN1bHR5KEdlblV0aWxzLnJlY29uY2lsZShoZWFkZXIuZ2V0Q3VtdWxhdGl2ZURpZmZpY3VsdHkoKSwgTW9uZXJvRGFlbW9uUnBjLnByZWZpeGVkSGV4VG9CSSh2YWwpKSk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiaGFzaFwiKSBHZW5VdGlscy5zYWZlU2V0KGhlYWRlciwgaGVhZGVyLmdldEhhc2gsIGhlYWRlci5zZXRIYXNoLCB2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImhlaWdodFwiKSBHZW5VdGlscy5zYWZlU2V0KGhlYWRlciwgaGVhZGVyLmdldEhlaWdodCwgaGVhZGVyLnNldEhlaWdodCwgdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJtYWpvcl92ZXJzaW9uXCIpIEdlblV0aWxzLnNhZmVTZXQoaGVhZGVyLCBoZWFkZXIuZ2V0TWFqb3JWZXJzaW9uLCBoZWFkZXIuc2V0TWFqb3JWZXJzaW9uLCB2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIm1pbm9yX3ZlcnNpb25cIikgR2VuVXRpbHMuc2FmZVNldChoZWFkZXIsIGhlYWRlci5nZXRNaW5vclZlcnNpb24sIGhlYWRlci5zZXRNaW5vclZlcnNpb24sIHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwibm9uY2VcIikgR2VuVXRpbHMuc2FmZVNldChoZWFkZXIsIGhlYWRlci5nZXROb25jZSwgaGVhZGVyLnNldE5vbmNlLCB2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIm51bV90eGVzXCIpIEdlblV0aWxzLnNhZmVTZXQoaGVhZGVyLCBoZWFkZXIuZ2V0TnVtVHhzLCBoZWFkZXIuc2V0TnVtVHhzLCB2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIm9ycGhhbl9zdGF0dXNcIikgR2VuVXRpbHMuc2FmZVNldChoZWFkZXIsIGhlYWRlci5nZXRPcnBoYW5TdGF0dXMsIGhlYWRlci5zZXRPcnBoYW5TdGF0dXMsIHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicHJldl9oYXNoXCIgfHwga2V5ID09PSBcInByZXZfaWRcIikgR2VuVXRpbHMuc2FmZVNldChoZWFkZXIsIGhlYWRlci5nZXRQcmV2SGFzaCwgaGVhZGVyLnNldFByZXZIYXNoLCB2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInJld2FyZFwiKSBHZW5VdGlscy5zYWZlU2V0KGhlYWRlciwgaGVhZGVyLmdldFJld2FyZCwgaGVhZGVyLnNldFJld2FyZCwgQmlnSW50KHZhbCkpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInRpbWVzdGFtcFwiKSBHZW5VdGlscy5zYWZlU2V0KGhlYWRlciwgaGVhZGVyLmdldFRpbWVzdGFtcCwgaGVhZGVyLnNldFRpbWVzdGFtcCwgdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJibG9ja193ZWlnaHRcIikgR2VuVXRpbHMuc2FmZVNldChoZWFkZXIsIGhlYWRlci5nZXRXZWlnaHQsIGhlYWRlci5zZXRXZWlnaHQsIHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwibG9uZ190ZXJtX3dlaWdodFwiKSBHZW5VdGlscy5zYWZlU2V0KGhlYWRlciwgaGVhZGVyLmdldExvbmdUZXJtV2VpZ2h0LCBoZWFkZXIuc2V0TG9uZ1Rlcm1XZWlnaHQsIHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicG93X2hhc2hcIikgR2VuVXRpbHMuc2FmZVNldChoZWFkZXIsIGhlYWRlci5nZXRQb3dIYXNoLCBoZWFkZXIuc2V0UG93SGFzaCwgdmFsID09PSBcIlwiID8gdW5kZWZpbmVkIDogdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0eF9oYXNoZXNcIikge30gIC8vIHVzZWQgaW4gYmxvY2sgbW9kZWwsIG5vdCBoZWFkZXIgbW9kZWxcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJtaW5lcl90eFwiKSB7fSAgIC8vIHVzZWQgaW4gYmxvY2sgbW9kZWwsIG5vdCBoZWFkZXIgbW9kZWxcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJtaW5lcl90eF9oYXNoXCIpIGhlYWRlci5zZXRNaW5lclR4SGFzaCh2YWwpO1xuICAgICAgZWxzZSBjb25zb2xlLmxvZyhcIldBUk5JTkc6IGlnbm9yaW5nIHVuZXhwZWN0ZWQgYmxvY2sgaGVhZGVyIGZpZWxkOiAnXCIgKyBrZXkgKyBcIic6IFwiICsgdmFsKTtcbiAgICB9XG4gICAgcmV0dXJuIGhlYWRlcjtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIHN0YXRpYyBjb252ZXJ0UnBjQmxvY2socnBjQmxvY2spIHtcbiAgICBcbiAgICAvLyBidWlsZCBibG9ja1xuICAgIGxldCBibG9jayA9IG5ldyBNb25lcm9CbG9jayhNb25lcm9EYWVtb25ScGMuY29udmVydFJwY0Jsb2NrSGVhZGVyKHJwY0Jsb2NrLmJsb2NrX2hlYWRlciA/IHJwY0Jsb2NrLmJsb2NrX2hlYWRlciA6IHJwY0Jsb2NrKSBhcyBNb25lcm9CbG9jayk7XG4gICAgYmxvY2suc2V0SGV4KHJwY0Jsb2NrLmJsb2IpO1xuICAgIGJsb2NrLnNldFR4SGFzaGVzKHJwY0Jsb2NrLnR4X2hhc2hlcyA9PT0gdW5kZWZpbmVkID8gW10gOiBycGNCbG9jay50eF9oYXNoZXMpO1xuICAgIFxuICAgIC8vIGJ1aWxkIG1pbmVyIHR4XG4gICAgbGV0IHJwY01pbmVyVHggPSBycGNCbG9jay5qc29uID8gSlNPTi5wYXJzZShycGNCbG9jay5qc29uKS5taW5lcl90eCA6IHJwY0Jsb2NrLm1pbmVyX3R4OyAgLy8gbWF5IG5lZWQgdG8gYmUgcGFyc2VkIGZyb20ganNvblxuICAgIGxldCBtaW5lclR4ID0gbmV3IE1vbmVyb1R4KCk7XG4gICAgYmxvY2suc2V0TWluZXJUeChtaW5lclR4KTtcbiAgICBtaW5lclR4LnNldElzQ29uZmlybWVkKHRydWUpO1xuICAgIG1pbmVyVHguc2V0SW5UeFBvb2woZmFsc2UpXG4gICAgbWluZXJUeC5zZXRJc01pbmVyVHgodHJ1ZSk7XG4gICAgTW9uZXJvRGFlbW9uUnBjLmNvbnZlcnRScGNUeChycGNNaW5lclR4LCBtaW5lclR4KTtcbiAgICBcbiAgICByZXR1cm4gYmxvY2s7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBUcmFuc2ZlcnMgUlBDIHR4IGZpZWxkcyB0byBhIGdpdmVuIE1vbmVyb1R4IHdpdGhvdXQgb3ZlcndyaXRpbmcgcHJldmlvdXMgdmFsdWVzLlxuICAgKiBcbiAgICogVE9ETzogc3dpdGNoIGZyb20gc2FmZSBzZXRcbiAgICogXG4gICAqIEBwYXJhbSBycGNUeCAtIFJQQyBtYXAgY29udGFpbmluZyB0cmFuc2FjdGlvbiBmaWVsZHNcbiAgICogQHBhcmFtIHR4ICAtIE1vbmVyb1R4IHRvIHBvcHVsYXRlIHdpdGggdmFsdWVzIChvcHRpb25hbClcbiAgICogQHJldHVybiB0eCAtIHNhbWUgdHggdGhhdCB3YXMgcGFzc2VkIGluIG9yIGEgbmV3IG9uZSBpZiBub25lIGdpdmVuXG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNUeChycGNUeCwgdHgpIHtcbiAgICBpZiAocnBjVHggPT09IHVuZGVmaW5lZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBpZiAodHggPT09IHVuZGVmaW5lZCkgdHggPSBuZXcgTW9uZXJvVHgoKTtcbiAgICBcbiAgICAvLyBpbml0aWFsaXplIGZyb20gcnBjIG1hcFxuICAgIGxldCBoZWFkZXI7XG4gICAgZm9yIChsZXQga2V5IG9mIE9iamVjdC5rZXlzKHJwY1R4KSkge1xuICAgICAgbGV0IHZhbCA9IHJwY1R4W2tleV07XG4gICAgICBpZiAoa2V5ID09PSBcInR4X2hhc2hcIiB8fCBrZXkgPT09IFwiaWRfaGFzaFwiKSBHZW5VdGlscy5zYWZlU2V0KHR4LCB0eC5nZXRIYXNoLCB0eC5zZXRIYXNoLCB2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImJsb2NrX3RpbWVzdGFtcFwiKSB7XG4gICAgICAgIGlmICghaGVhZGVyKSBoZWFkZXIgPSBuZXcgTW9uZXJvQmxvY2tIZWFkZXIoKTtcbiAgICAgICAgR2VuVXRpbHMuc2FmZVNldChoZWFkZXIsIGhlYWRlci5nZXRUaW1lc3RhbXAsIGhlYWRlci5zZXRUaW1lc3RhbXAsIHZhbCk7XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYmxvY2tfaGVpZ2h0XCIpIHtcbiAgICAgICAgaWYgKCFoZWFkZXIpIGhlYWRlciA9IG5ldyBNb25lcm9CbG9ja0hlYWRlcigpO1xuICAgICAgICBHZW5VdGlscy5zYWZlU2V0KGhlYWRlciwgaGVhZGVyLmdldEhlaWdodCwgaGVhZGVyLnNldEhlaWdodCwgdmFsKTtcbiAgICAgIH1cbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJsYXN0X3JlbGF5ZWRfdGltZVwiKSBHZW5VdGlscy5zYWZlU2V0KHR4LCB0eC5nZXRMYXN0UmVsYXllZFRpbWVzdGFtcCwgdHguc2V0TGFzdFJlbGF5ZWRUaW1lc3RhbXAsIHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicmVjZWl2ZV90aW1lXCIgfHwga2V5ID09PSBcInJlY2VpdmVkX3RpbWVzdGFtcFwiKSBHZW5VdGlscy5zYWZlU2V0KHR4LCB0eC5nZXRSZWNlaXZlZFRpbWVzdGFtcCwgdHguc2V0UmVjZWl2ZWRUaW1lc3RhbXAsIHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiY29uZmlybWF0aW9uc1wiKSBHZW5VdGlscy5zYWZlU2V0KHR4LCB0eC5nZXROdW1Db25maXJtYXRpb25zLCB0eC5zZXROdW1Db25maXJtYXRpb25zLCB2YWwpOyBcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJpbl9wb29sXCIpIHtcbiAgICAgICAgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0SXNDb25maXJtZWQsIHR4LnNldElzQ29uZmlybWVkLCAhdmFsKTtcbiAgICAgICAgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0SW5UeFBvb2wsIHR4LnNldEluVHhQb29sLCB2YWwpO1xuICAgICAgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImRvdWJsZV9zcGVuZF9zZWVuXCIpIEdlblV0aWxzLnNhZmVTZXQodHgsIHR4LmdldElzRG91YmxlU3BlbmRTZWVuLCB0eC5zZXRJc0RvdWJsZVNwZW5kU2VlbiwgdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ2ZXJzaW9uXCIpIEdlblV0aWxzLnNhZmVTZXQodHgsIHR4LmdldFZlcnNpb24sIHR4LnNldFZlcnNpb24sIHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiZXh0cmFcIikge1xuICAgICAgICBpZiAodHlwZW9mIHZhbCA9PT0gXCJzdHJpbmdcIikgY29uc29sZS5sb2coXCJXQVJOSU5HOiBleHRyYSBmaWVsZCBhcyBzdHJpbmcgbm90IGJlaW5nIGFzaWduZWQgdG8gaW50W106IFwiICsga2V5ICsgXCI6IFwiICsgdmFsKTsgLy8gVE9ETzogaG93IHRvIHNldCBzdHJpbmcgdG8gaW50W10/IC0gb3IsIGV4dHJhIGlzIHN0cmluZyB3aGljaCBjYW4gZW5jb2RlIGludFtdXG4gICAgICAgIGVsc2UgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0RXh0cmEsIHR4LnNldEV4dHJhLCBuZXcgVWludDhBcnJheSh2YWwpKTtcbiAgICAgIH1cbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ2aW5cIikge1xuICAgICAgICBpZiAodmFsLmxlbmd0aCAhPT0gMSB8fCAhdmFsWzBdLmdlbikgeyAgLy8gaWdub3JlIG1pbmVyIGlucHV0IFRPRE86IHdoeT9cbiAgICAgICAgICB0eC5zZXRJbnB1dHModmFsLm1hcChycGNWaW4gPT4gTW9uZXJvRGFlbW9uUnBjLmNvbnZlcnRScGNPdXRwdXQocnBjVmluLCB0eCkpKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInZvdXRcIikgdHguc2V0T3V0cHV0cyh2YWwubWFwKHJwY091dHB1dCA9PiBNb25lcm9EYWVtb25ScGMuY29udmVydFJwY091dHB1dChycGNPdXRwdXQsIHR4KSkpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInJjdF9zaWduYXR1cmVzXCIpIHtcbiAgICAgICAgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0UmN0U2lnbmF0dXJlcywgdHguc2V0UmN0U2lnbmF0dXJlcywgdmFsKTtcbiAgICAgICAgaWYgKHZhbC50eG5GZWUpIEdlblV0aWxzLnNhZmVTZXQodHgsIHR4LmdldEZlZSwgdHguc2V0RmVlLCBCaWdJbnQodmFsLnR4bkZlZSkpO1xuICAgICAgfSBcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJyY3RzaWdfcHJ1bmFibGVcIikgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0UmN0U2lnUHJ1bmFibGUsIHR4LnNldFJjdFNpZ1BydW5hYmxlLCB2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInVubG9ja190aW1lXCIpIEdlblV0aWxzLnNhZmVTZXQodHgsIHR4LmdldFVubG9ja1RpbWUsIHR4LnNldFVubG9ja1RpbWUsIHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYXNfanNvblwiIHx8IGtleSA9PT0gXCJ0eF9qc29uXCIpIHsgfSAgLy8gaGFuZGxlZCBsYXN0IHNvIHR4IGlzIGFzIGluaXRpYWxpemVkIGFzIHBvc3NpYmxlXG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYXNfaGV4XCIgfHwga2V5ID09PSBcInR4X2Jsb2JcIikgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0RnVsbEhleCwgdHguc2V0RnVsbEhleCwgdmFsID8gdmFsIDogdW5kZWZpbmVkKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJibG9iX3NpemVcIikgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0U2l6ZSwgdHguc2V0U2l6ZSwgdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ3ZWlnaHRcIikgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0V2VpZ2h0LCB0eC5zZXRXZWlnaHQsIHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiZmVlXCIpIEdlblV0aWxzLnNhZmVTZXQodHgsIHR4LmdldEZlZSwgdHguc2V0RmVlLCBCaWdJbnQodmFsKSk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicmVsYXllZFwiKSBHZW5VdGlscy5zYWZlU2V0KHR4LCB0eC5nZXRJc1JlbGF5ZWQsIHR4LnNldElzUmVsYXllZCwgdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJvdXRwdXRfaW5kaWNlc1wiKSBHZW5VdGlscy5zYWZlU2V0KHR4LCB0eC5nZXRPdXRwdXRJbmRpY2VzLCB0eC5zZXRPdXRwdXRJbmRpY2VzLCB2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImRvX25vdF9yZWxheVwiKSBHZW5VdGlscy5zYWZlU2V0KHR4LCB0eC5nZXRSZWxheSwgdHguc2V0UmVsYXksICF2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImtlcHRfYnlfYmxvY2tcIikgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0SXNLZXB0QnlCbG9jaywgdHguc2V0SXNLZXB0QnlCbG9jaywgdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJzaWduYXR1cmVzXCIpIEdlblV0aWxzLnNhZmVTZXQodHgsIHR4LmdldFNpZ25hdHVyZXMsIHR4LnNldFNpZ25hdHVyZXMsIHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwibGFzdF9mYWlsZWRfaGVpZ2h0XCIpIHtcbiAgICAgICAgaWYgKHZhbCA9PT0gMCkgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0SXNGYWlsZWQsIHR4LnNldElzRmFpbGVkLCBmYWxzZSk7XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgIEdlblV0aWxzLnNhZmVTZXQodHgsIHR4LmdldElzRmFpbGVkLCB0eC5zZXRJc0ZhaWxlZCwgdHJ1ZSk7XG4gICAgICAgICAgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0TGFzdEZhaWxlZEhlaWdodCwgdHguc2V0TGFzdEZhaWxlZEhlaWdodCwgdmFsKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImxhc3RfZmFpbGVkX2lkX2hhc2hcIikge1xuICAgICAgICBpZiAodmFsID09PSBNb25lcm9EYWVtb25ScGMuREVGQVVMVF9JRCkgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0SXNGYWlsZWQsIHR4LnNldElzRmFpbGVkLCBmYWxzZSk7XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgIEdlblV0aWxzLnNhZmVTZXQodHgsIHR4LmdldElzRmFpbGVkLCB0eC5zZXRJc0ZhaWxlZCwgdHJ1ZSk7XG4gICAgICAgICAgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0TGFzdEZhaWxlZEhhc2gsIHR4LnNldExhc3RGYWlsZWRIYXNoLCB2YWwpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwibWF4X3VzZWRfYmxvY2tfaGVpZ2h0XCIpIEdlblV0aWxzLnNhZmVTZXQodHgsIHR4LmdldE1heFVzZWRCbG9ja0hlaWdodCwgdHguc2V0TWF4VXNlZEJsb2NrSGVpZ2h0LCB2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIm1heF91c2VkX2Jsb2NrX2lkX2hhc2hcIikgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0TWF4VXNlZEJsb2NrSGFzaCwgdHguc2V0TWF4VXNlZEJsb2NrSGFzaCwgdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJwcnVuYWJsZV9oYXNoXCIpIEdlblV0aWxzLnNhZmVTZXQodHgsIHR4LmdldFBydW5hYmxlSGFzaCwgdHguc2V0UHJ1bmFibGVIYXNoLCB2YWwgPyB2YWwgOiB1bmRlZmluZWQpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInBydW5hYmxlX2FzX2hleFwiKSBHZW5VdGlscy5zYWZlU2V0KHR4LCB0eC5nZXRQcnVuYWJsZUhleCwgdHguc2V0UHJ1bmFibGVIZXgsIHZhbCA/IHZhbCA6IHVuZGVmaW5lZCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicHJ1bmVkX2FzX2hleFwiKSBHZW5VdGlscy5zYWZlU2V0KHR4LCB0eC5nZXRQcnVuZWRIZXgsIHR4LnNldFBydW5lZEhleCwgdmFsID8gdmFsIDogdW5kZWZpbmVkKTtcbiAgICAgIGVsc2UgY29uc29sZS5sb2coXCJXQVJOSU5HOiBpZ25vcmluZyB1bmV4cGVjdGVkIGZpZWxkIGluIHJwYyB0eDogXCIgKyBrZXkgKyBcIjogXCIgKyB2YWwpO1xuICAgIH1cbiAgICBcbiAgICAvLyBsaW5rIGJsb2NrIGFuZCB0eFxuICAgIGlmIChoZWFkZXIpIHR4LnNldEJsb2NrKG5ldyBNb25lcm9CbG9jayhoZWFkZXIpLnNldFR4cyhbdHhdKSk7XG4gICAgXG4gICAgLy8gVE9ETyBtb25lcm9kOiB1bmNvbmZpcm1lZCB0eHMgbWlzcmVwb3J0IGJsb2NrIGhlaWdodCBhbmQgdGltZXN0YW1wP1xuICAgIGlmICh0eC5nZXRCbG9jaygpICYmIHR4LmdldEJsb2NrKCkuZ2V0SGVpZ2h0KCkgIT09IHVuZGVmaW5lZCAmJiB0eC5nZXRCbG9jaygpLmdldEhlaWdodCgpID09PSB0eC5nZXRCbG9jaygpLmdldFRpbWVzdGFtcCgpKSB7XG4gICAgICB0eC5zZXRCbG9jayh1bmRlZmluZWQpO1xuICAgICAgdHguc2V0SXNDb25maXJtZWQoZmFsc2UpO1xuICAgIH1cbiAgICBcbiAgICAvLyBpbml0aWFsaXplIHJlbWFpbmluZyBrbm93biBmaWVsZHNcbiAgICBpZiAodHguZ2V0SXNDb25maXJtZWQoKSkge1xuICAgICAgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0SXNSZWxheWVkLCB0eC5zZXRJc1JlbGF5ZWQsIHRydWUpO1xuICAgICAgR2VuVXRpbHMuc2FmZVNldCh0eCwgdHguZ2V0UmVsYXksIHR4LnNldFJlbGF5LCB0cnVlKTtcbiAgICAgIEdlblV0aWxzLnNhZmVTZXQodHgsIHR4LmdldElzRmFpbGVkLCB0eC5zZXRJc0ZhaWxlZCwgZmFsc2UpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0eC5zZXROdW1Db25maXJtYXRpb25zKDApO1xuICAgIH1cbiAgICBpZiAodHguZ2V0SXNGYWlsZWQoKSA9PT0gdW5kZWZpbmVkKSB0eC5zZXRJc0ZhaWxlZChmYWxzZSk7XG4gICAgaWYgKHR4LmdldE91dHB1dEluZGljZXMoKSAmJiB0eC5nZXRPdXRwdXRzKCkpICB7XG4gICAgICBhc3NlcnQuZXF1YWwodHguZ2V0T3V0cHV0cygpLmxlbmd0aCwgdHguZ2V0T3V0cHV0SW5kaWNlcygpLmxlbmd0aCk7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHR4LmdldE91dHB1dHMoKS5sZW5ndGg7IGkrKykge1xuICAgICAgICB0eC5nZXRPdXRwdXRzKClbaV0uc2V0SW5kZXgodHguZ2V0T3V0cHV0SW5kaWNlcygpW2ldKTsgIC8vIHRyYW5zZmVyIG91dHB1dCBpbmRpY2VzIHRvIG91dHB1dHNcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKHJwY1R4LmFzX2pzb24pIE1vbmVyb0RhZW1vblJwYy5jb252ZXJ0UnBjVHgoSlNPTi5wYXJzZShycGNUeC5hc19qc29uKSwgdHgpO1xuICAgIGlmIChycGNUeC50eF9qc29uKSBNb25lcm9EYWVtb25ScGMuY29udmVydFJwY1R4KEpTT04ucGFyc2UocnBjVHgudHhfanNvbiksIHR4KTtcbiAgICBpZiAoIXR4LmdldElzUmVsYXllZCgpKSB0eC5zZXRMYXN0UmVsYXllZFRpbWVzdGFtcCh1bmRlZmluZWQpOyAgLy8gVE9ETyBtb25lcm9kOiByZXR1cm5zIGxhc3RfcmVsYXllZF90aW1lc3RhbXAgZGVzcGl0ZSByZWxheWVkOiBmYWxzZSwgc2VsZiBpbmNvbnNpc3RlbnRcbiAgICBcbiAgICAvLyByZXR1cm4gYnVpbHQgdHJhbnNhY3Rpb25cbiAgICByZXR1cm4gdHg7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgY29udmVydFJwY091dHB1dChycGNPdXRwdXQsIHR4KSB7XG4gICAgbGV0IG91dHB1dCA9IG5ldyBNb25lcm9PdXRwdXQoKTtcbiAgICBvdXRwdXQuc2V0VHgodHgpO1xuICAgIGZvciAobGV0IGtleSBvZiBPYmplY3Qua2V5cyhycGNPdXRwdXQpKSB7XG4gICAgICBsZXQgdmFsID0gcnBjT3V0cHV0W2tleV07XG4gICAgICBpZiAoa2V5ID09PSBcImdlblwiKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJPdXRwdXQgd2l0aCAnZ2VuJyBmcm9tIGRhZW1vbiBycGMgaXMgbWluZXIgdHggd2hpY2ggd2UgaWdub3JlIChpLmUuIGVhY2ggbWluZXIgaW5wdXQgaXMgdW5kZWZpbmVkKVwiKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJrZXlcIikge1xuICAgICAgICBHZW5VdGlscy5zYWZlU2V0KG91dHB1dCwgb3V0cHV0LmdldEFtb3VudCwgb3V0cHV0LnNldEFtb3VudCwgQmlnSW50KHZhbC5hbW91bnQpKTtcbiAgICAgICAgR2VuVXRpbHMuc2FmZVNldChvdXRwdXQsIG91dHB1dC5nZXRLZXlJbWFnZSwgb3V0cHV0LnNldEtleUltYWdlLCBuZXcgTW9uZXJvS2V5SW1hZ2UodmFsLmtfaW1hZ2UpKTtcbiAgICAgICAgR2VuVXRpbHMuc2FmZVNldChvdXRwdXQsIG91dHB1dC5nZXRSaW5nT3V0cHV0SW5kaWNlcywgb3V0cHV0LnNldFJpbmdPdXRwdXRJbmRpY2VzLCB2YWwua2V5X29mZnNldHMpO1xuICAgICAgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImFtb3VudFwiKSBHZW5VdGlscy5zYWZlU2V0KG91dHB1dCwgb3V0cHV0LmdldEFtb3VudCwgb3V0cHV0LnNldEFtb3VudCwgQmlnSW50KHZhbCkpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInRhcmdldFwiKSB7XG4gICAgICAgIGxldCBwdWJLZXkgPSB2YWwua2V5ID09PSB1bmRlZmluZWQgPyB2YWwudGFnZ2VkX2tleS5rZXkgOiB2YWwua2V5OyAvLyBUT0RPIChtb25lcm9kKTogcnBjIGpzb24gdXNlcyB7dGFnZ2VkX2tleT17a2V5PS4uLn19LCBiaW5hcnkgYmxvY2tzIHVzZSB7a2V5PS4uLn1cbiAgICAgICAgR2VuVXRpbHMuc2FmZVNldChvdXRwdXQsIG91dHB1dC5nZXRTdGVhbHRoUHVibGljS2V5LCBvdXRwdXQuc2V0U3RlYWx0aFB1YmxpY0tleSwgcHViS2V5KTtcbiAgICAgIH1cbiAgICAgIGVsc2UgY29uc29sZS5sb2coXCJXQVJOSU5HOiBpZ25vcmluZyB1bmV4cGVjdGVkIGZpZWxkIG91dHB1dDogXCIgKyBrZXkgKyBcIjogXCIgKyB2YWwpO1xuICAgIH1cbiAgICByZXR1cm4gb3V0cHV0O1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNCbG9ja1RlbXBsYXRlKHJwY1RlbXBsYXRlKSB7XG4gICAgbGV0IHRlbXBsYXRlID0gbmV3IE1vbmVyb0Jsb2NrVGVtcGxhdGUoKTtcbiAgICBmb3IgKGxldCBrZXkgb2YgT2JqZWN0LmtleXMocnBjVGVtcGxhdGUpKSB7XG4gICAgICBsZXQgdmFsID0gcnBjVGVtcGxhdGVba2V5XTtcbiAgICAgIGlmIChrZXkgPT09IFwiYmxvY2toYXNoaW5nX2Jsb2JcIikgdGVtcGxhdGUuc2V0QmxvY2tIYXNoaW5nQmxvYih2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImJsb2NrdGVtcGxhdGVfYmxvYlwiKSB0ZW1wbGF0ZS5zZXRCbG9ja1RlbXBsYXRlQmxvYih2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImV4cGVjdGVkX3Jld2FyZFwiKSB0ZW1wbGF0ZS5zZXRFeHBlY3RlZFJld2FyZCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImRpZmZpY3VsdHlcIikgeyB9ICAvLyBoYW5kbGVkIGJ5IHdpZGVfZGlmZmljdWx0eVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImRpZmZpY3VsdHlfdG9wNjRcIikgeyB9ICAvLyBoYW5kbGVkIGJ5IHdpZGVfZGlmZmljdWx0eVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIndpZGVfZGlmZmljdWx0eVwiKSB0ZW1wbGF0ZS5zZXREaWZmaWN1bHR5KEdlblV0aWxzLnJlY29uY2lsZSh0ZW1wbGF0ZS5nZXREaWZmaWN1bHR5KCksIE1vbmVyb0RhZW1vblJwYy5wcmVmaXhlZEhleFRvQkkodmFsKSkpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImhlaWdodFwiKSB0ZW1wbGF0ZS5zZXRIZWlnaHQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJwcmV2X2hhc2hcIikgdGVtcGxhdGUuc2V0UHJldkhhc2godmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJyZXNlcnZlZF9vZmZzZXRcIikgdGVtcGxhdGUuc2V0UmVzZXJ2ZWRPZmZzZXQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJzdGF0dXNcIikge30gIC8vIGhhbmRsZWQgZWxzZXdoZXJlXG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidW50cnVzdGVkXCIpIHt9ICAvLyBoYW5kbGVkIGVsc2V3aGVyZVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInNlZWRfaGVpZ2h0XCIpIHRlbXBsYXRlLnNldFNlZWRIZWlnaHQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJzZWVkX2hhc2hcIikgdGVtcGxhdGUuc2V0U2VlZEhhc2godmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJuZXh0X3NlZWRfaGFzaFwiKSB0ZW1wbGF0ZS5zZXROZXh0U2VlZEhhc2godmFsKTtcbiAgICAgIGVsc2UgY29uc29sZS5sb2coXCJXQVJOSU5HOiBpZ25vcmluZyB1bmV4cGVjdGVkIGZpZWxkIGluIGJsb2NrIHRlbXBsYXRlOiBcIiArIGtleSArIFwiOiBcIiArIHZhbCk7XG4gICAgfVxuICAgIGlmIChcIlwiID09PSB0ZW1wbGF0ZS5nZXROZXh0U2VlZEhhc2goKSkgdGVtcGxhdGUuc2V0TmV4dFNlZWRIYXNoKHVuZGVmaW5lZCk7XG4gICAgcmV0dXJuIHRlbXBsYXRlO1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNJbmZvKHJwY0luZm8pIHtcbiAgICBpZiAoIXJwY0luZm8pIHJldHVybiB1bmRlZmluZWQ7XG4gICAgbGV0IGluZm8gPSBuZXcgTW9uZXJvRGFlbW9uSW5mbygpO1xuICAgIGZvciAobGV0IGtleSBvZiBPYmplY3Qua2V5cyhycGNJbmZvKSkge1xuICAgICAgbGV0IHZhbCA9IHJwY0luZm9ba2V5XTtcbiAgICAgIGlmIChrZXkgPT09IFwidmVyc2lvblwiKSBpbmZvLnNldFZlcnNpb24odmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJhbHRfYmxvY2tzX2NvdW50XCIpIGluZm8uc2V0TnVtQWx0QmxvY2tzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYmxvY2tfc2l6ZV9saW1pdFwiKSBpbmZvLnNldEJsb2NrU2l6ZUxpbWl0KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYmxvY2tfc2l6ZV9tZWRpYW5cIikgaW5mby5zZXRCbG9ja1NpemVNZWRpYW4odmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJibG9ja193ZWlnaHRfbGltaXRcIikgaW5mby5zZXRCbG9ja1dlaWdodExpbWl0KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYmxvY2tfd2VpZ2h0X21lZGlhblwiKSBpbmZvLnNldEJsb2NrV2VpZ2h0TWVkaWFuKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYm9vdHN0cmFwX2RhZW1vbl9hZGRyZXNzXCIpIHsgaWYgKHZhbCkgaW5mby5zZXRCb290c3RyYXBEYWVtb25BZGRyZXNzKHZhbCk7IH1cbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJkaWZmaWN1bHR5XCIpIHsgfSAgLy8gaGFuZGxlZCBieSB3aWRlX2RpZmZpY3VsdHlcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJjdW11bGF0aXZlX2RpZmZpY3VsdHlcIikgeyB9IC8vIGhhbmRsZWQgYnkgd2lkZV9jdW11bGF0aXZlX2RpZmZpY3VsdHlcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJkaWZmaWN1bHR5X3RvcDY0XCIpIHsgfSAgLy8gaGFuZGxlZCBieSB3aWRlX2RpZmZpY3VsdHlcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJjdW11bGF0aXZlX2RpZmZpY3VsdHlfdG9wNjRcIikgeyB9IC8vIGhhbmRsZWQgYnkgd2lkZV9jdW11bGF0aXZlX2RpZmZpY3VsdHlcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ3aWRlX2RpZmZpY3VsdHlcIikgaW5mby5zZXREaWZmaWN1bHR5KEdlblV0aWxzLnJlY29uY2lsZShpbmZvLmdldERpZmZpY3VsdHkoKSwgTW9uZXJvRGFlbW9uUnBjLnByZWZpeGVkSGV4VG9CSSh2YWwpKSk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwid2lkZV9jdW11bGF0aXZlX2RpZmZpY3VsdHlcIikgaW5mby5zZXRDdW11bGF0aXZlRGlmZmljdWx0eShHZW5VdGlscy5yZWNvbmNpbGUoaW5mby5nZXRDdW11bGF0aXZlRGlmZmljdWx0eSgpLCBNb25lcm9EYWVtb25ScGMucHJlZml4ZWRIZXhUb0JJKHZhbCkpKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJmcmVlX3NwYWNlXCIpIGluZm8uc2V0RnJlZVNwYWNlKEJpZ0ludCh2YWwpKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJkYXRhYmFzZV9zaXplXCIpIGluZm8uc2V0RGF0YWJhc2VTaXplKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiZ3JleV9wZWVybGlzdF9zaXplXCIpIGluZm8uc2V0TnVtT2ZmbGluZVBlZXJzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiaGVpZ2h0XCIpIGluZm8uc2V0SGVpZ2h0KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiaGVpZ2h0X3dpdGhvdXRfYm9vdHN0cmFwXCIpIGluZm8uc2V0SGVpZ2h0V2l0aG91dEJvb3RzdHJhcCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImluY29taW5nX2Nvbm5lY3Rpb25zX2NvdW50XCIpIGluZm8uc2V0TnVtSW5jb21pbmdDb25uZWN0aW9ucyh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIm9mZmxpbmVcIikgaW5mby5zZXRJc09mZmxpbmUodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJvdXRnb2luZ19jb25uZWN0aW9uc19jb3VudFwiKSBpbmZvLnNldE51bU91dGdvaW5nQ29ubmVjdGlvbnModmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJycGNfY29ubmVjdGlvbnNfY291bnRcIikgaW5mby5zZXROdW1ScGNDb25uZWN0aW9ucyh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInN0YXJ0X3RpbWVcIikgaW5mby5zZXRTdGFydFRpbWVzdGFtcCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImFkanVzdGVkX3RpbWVcIikgaW5mby5zZXRBZGp1c3RlZFRpbWVzdGFtcCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInN0YXR1c1wiKSB7fSAgLy8gaGFuZGxlZCBlbHNld2hlcmVcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0YXJnZXRcIikgaW5mby5zZXRUYXJnZXQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0YXJnZXRfaGVpZ2h0XCIpIGluZm8uc2V0VGFyZ2V0SGVpZ2h0KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidG9wX2Jsb2NrX2hhc2hcIikgaW5mby5zZXRUb3BCbG9ja0hhc2godmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0eF9jb3VudFwiKSBpbmZvLnNldE51bVR4cyh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInR4X3Bvb2xfc2l6ZVwiKSBpbmZvLnNldE51bVR4c1Bvb2wodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ1bnRydXN0ZWRcIikge30gLy8gaGFuZGxlZCBlbHNld2hlcmVcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ3YXNfYm9vdHN0cmFwX2V2ZXJfdXNlZFwiKSBpbmZvLnNldFdhc0Jvb3RzdHJhcEV2ZXJVc2VkKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwid2hpdGVfcGVlcmxpc3Rfc2l6ZVwiKSBpbmZvLnNldE51bU9ubGluZVBlZXJzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidXBkYXRlX2F2YWlsYWJsZVwiKSBpbmZvLnNldFVwZGF0ZUF2YWlsYWJsZSh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIm5ldHR5cGVcIikgR2VuVXRpbHMuc2FmZVNldChpbmZvLCBpbmZvLmdldE5ldHdvcmtUeXBlLCBpbmZvLnNldE5ldHdvcmtUeXBlLCBNb25lcm9OZXR3b3JrVHlwZS5wYXJzZSh2YWwpKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJtYWlubmV0XCIpIHsgaWYgKHZhbCkgR2VuVXRpbHMuc2FmZVNldChpbmZvLCBpbmZvLmdldE5ldHdvcmtUeXBlLCBpbmZvLnNldE5ldHdvcmtUeXBlLCBNb25lcm9OZXR3b3JrVHlwZS5NQUlOTkVUKTsgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInRlc3RuZXRcIikgeyBpZiAodmFsKSBHZW5VdGlscy5zYWZlU2V0KGluZm8sIGluZm8uZ2V0TmV0d29ya1R5cGUsIGluZm8uc2V0TmV0d29ya1R5cGUsIE1vbmVyb05ldHdvcmtUeXBlLlRFU1RORVQpOyB9XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwic3RhZ2VuZXRcIikgeyBpZiAodmFsKSBHZW5VdGlscy5zYWZlU2V0KGluZm8sIGluZm8uZ2V0TmV0d29ya1R5cGUsIGluZm8uc2V0TmV0d29ya1R5cGUsIE1vbmVyb05ldHdvcmtUeXBlLlNUQUdFTkVUKTsgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImNyZWRpdHNcIikgaW5mby5zZXRDcmVkaXRzKEJpZ0ludCh2YWwpKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0b3BfYmxvY2tfaGFzaFwiIHx8IGtleSA9PT0gXCJ0b3BfaGFzaFwiKSBpbmZvLnNldFRvcEJsb2NrSGFzaChHZW5VdGlscy5yZWNvbmNpbGUoaW5mby5nZXRUb3BCbG9ja0hhc2goKSwgXCJcIiA9PT0gdmFsID8gdW5kZWZpbmVkIDogdmFsKSlcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJidXN5X3N5bmNpbmdcIikgaW5mby5zZXRJc0J1c3lTeW5jaW5nKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwic3luY2hyb25pemVkXCIpIGluZm8uc2V0SXNTeW5jaHJvbml6ZWQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJyZXN0cmljdGVkXCIpIGluZm8uc2V0SXNSZXN0cmljdGVkKHZhbCk7XG4gICAgICBlbHNlIGNvbnNvbGUubG9nKFwiV0FSTklORzogSWdub3JpbmcgdW5leHBlY3RlZCBpbmZvIGZpZWxkOiBcIiArIGtleSArIFwiOiBcIiArIHZhbCk7XG4gICAgfVxuICAgIHJldHVybiBpbmZvO1xuICB9XG4gIFxuICAvKipcbiAgICogSW5pdGlhbGl6ZXMgc3luYyBpbmZvIGZyb20gUlBDIHN5bmMgaW5mby5cbiAgICogXG4gICAqIEBwYXJhbSBycGNTeW5jSW5mbyAtIHJwYyBtYXAgdG8gaW5pdGlhbGl6ZSB0aGUgc3luYyBpbmZvIGZyb21cbiAgICogQHJldHVybiB7TW9uZXJvRGFlbW9uU3luY0luZm99IGlzIHN5bmMgaW5mbyBpbml0aWFsaXplZCBmcm9tIHRoZSBtYXBcbiAgICovXG4gIHByb3RlY3RlZCBzdGF0aWMgY29udmVydFJwY1N5bmNJbmZvKHJwY1N5bmNJbmZvKSB7XG4gICAgbGV0IHN5bmNJbmZvID0gbmV3IE1vbmVyb0RhZW1vblN5bmNJbmZvKCk7XG4gICAgZm9yIChsZXQga2V5IG9mIE9iamVjdC5rZXlzKHJwY1N5bmNJbmZvKSkge1xuICAgICAgbGV0IHZhbCA9IHJwY1N5bmNJbmZvW2tleV07XG4gICAgICBpZiAoa2V5ID09PSBcImhlaWdodFwiKSBzeW5jSW5mby5zZXRIZWlnaHQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJwZWVyc1wiKSB7XG4gICAgICAgIHN5bmNJbmZvLnNldFBlZXJzKFtdKTtcbiAgICAgICAgbGV0IHJwY0Nvbm5lY3Rpb25zID0gdmFsO1xuICAgICAgICBmb3IgKGxldCBycGNDb25uZWN0aW9uIG9mIHJwY0Nvbm5lY3Rpb25zKSB7XG4gICAgICAgICAgc3luY0luZm8uZ2V0UGVlcnMoKS5wdXNoKE1vbmVyb0RhZW1vblJwYy5jb252ZXJ0UnBjQ29ubmVjdGlvbihycGNDb25uZWN0aW9uLmluZm8pKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInNwYW5zXCIpIHtcbiAgICAgICAgc3luY0luZm8uc2V0U3BhbnMoW10pO1xuICAgICAgICBsZXQgcnBjU3BhbnMgPSB2YWw7XG4gICAgICAgIGZvciAobGV0IHJwY1NwYW4gb2YgcnBjU3BhbnMpIHtcbiAgICAgICAgICBzeW5jSW5mby5nZXRTcGFucygpLnB1c2goTW9uZXJvRGFlbW9uUnBjLmNvbnZlcnRScGNDb25uZWN0aW9uU3BhbihycGNTcGFuKSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoa2V5ID09PSBcInN0YXR1c1wiKSB7fSAgIC8vIGhhbmRsZWQgZWxzZXdoZXJlXG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidGFyZ2V0X2hlaWdodFwiKSBzeW5jSW5mby5zZXRUYXJnZXRIZWlnaHQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJuZXh0X25lZWRlZF9wcnVuaW5nX3NlZWRcIikgc3luY0luZm8uc2V0TmV4dE5lZWRlZFBydW5pbmdTZWVkKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwib3ZlcnZpZXdcIikgeyAgLy8gdGhpcyByZXR1cm5zIFtdIHdpdGhvdXQgcHJ1bmluZ1xuICAgICAgICBsZXQgb3ZlcnZpZXc7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgb3ZlcnZpZXcgPSBKU09OLnBhcnNlKHZhbCk7XG4gICAgICAgICAgaWYgKG92ZXJ2aWV3ICE9PSB1bmRlZmluZWQgJiYgb3ZlcnZpZXcubGVuZ3RoID4gMCkgY29uc29sZS5lcnJvcihcIklnbm9yaW5nIG5vbi1lbXB0eSAnb3ZlcnZpZXcnIGZpZWxkIChub3QgaW1wbGVtZW50ZWQpOiBcIiArIG92ZXJ2aWV3KTsgLy8gVE9ET1xuICAgICAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRmFpbGVkIHRvIHBhcnNlICdvdmVydmlldycgZmllbGQ6IFwiICsgb3ZlcnZpZXcgKyBcIjogXCIgKyBlLm1lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiY3JlZGl0c1wiKSBzeW5jSW5mby5zZXRDcmVkaXRzKEJpZ0ludCh2YWwpKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0b3BfaGFzaFwiKSBzeW5jSW5mby5zZXRUb3BCbG9ja0hhc2goXCJcIiA9PT0gdmFsID8gdW5kZWZpbmVkIDogdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ1bnRydXN0ZWRcIikge30gIC8vIGhhbmRsZWQgZWxzZXdoZXJlXG4gICAgICBlbHNlIGNvbnNvbGUubG9nKFwiV0FSTklORzogaWdub3JpbmcgdW5leHBlY3RlZCBmaWVsZCBpbiBzeW5jIGluZm86IFwiICsga2V5ICsgXCI6IFwiICsgdmFsKTtcbiAgICB9XG4gICAgcmV0dXJuIHN5bmNJbmZvO1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNIYXJkRm9ya0luZm8ocnBjSGFyZEZvcmtJbmZvKSB7XG4gICAgbGV0IGluZm8gPSBuZXcgTW9uZXJvSGFyZEZvcmtJbmZvKCk7XG4gICAgZm9yIChsZXQga2V5IG9mIE9iamVjdC5rZXlzKHJwY0hhcmRGb3JrSW5mbykpIHtcbiAgICAgIGxldCB2YWwgPSBycGNIYXJkRm9ya0luZm9ba2V5XTtcbiAgICAgIGlmIChrZXkgPT09IFwiZWFybGllc3RfaGVpZ2h0XCIpIGluZm8uc2V0RWFybGllc3RIZWlnaHQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJlbmFibGVkXCIpIGluZm8uc2V0SXNFbmFibGVkKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwic3RhdGVcIikgaW5mby5zZXRTdGF0ZSh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInN0YXR1c1wiKSB7fSAgICAgLy8gaGFuZGxlZCBlbHNld2hlcmVcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ1bnRydXN0ZWRcIikge30gIC8vIGhhbmRsZWQgZWxzZXdoZXJlXG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidGhyZXNob2xkXCIpIGluZm8uc2V0VGhyZXNob2xkKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidmVyc2lvblwiKSBpbmZvLnNldFZlcnNpb24odmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ2b3Rlc1wiKSBpbmZvLnNldE51bVZvdGVzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidm90aW5nXCIpIGluZm8uc2V0Vm90aW5nKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwid2luZG93XCIpIGluZm8uc2V0V2luZG93KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiY3JlZGl0c1wiKSBpbmZvLnNldENyZWRpdHMoQmlnSW50KHZhbCkpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInRvcF9oYXNoXCIpIGluZm8uc2V0VG9wQmxvY2tIYXNoKFwiXCIgPT09IHZhbCA/IHVuZGVmaW5lZCA6IHZhbCk7XG4gICAgICBlbHNlIGNvbnNvbGUubG9nKFwiV0FSTklORzogaWdub3JpbmcgdW5leHBlY3RlZCBmaWVsZCBpbiBoYXJkIGZvcmsgaW5mbzogXCIgKyBrZXkgKyBcIjogXCIgKyB2YWwpO1xuICAgIH1cbiAgICByZXR1cm4gaW5mbztcbiAgfVxuICBcbiAgcHJvdGVjdGVkIHN0YXRpYyBjb252ZXJ0UnBjQ29ubmVjdGlvblNwYW4ocnBjQ29ubmVjdGlvblNwYW4pIHtcbiAgICBsZXQgc3BhbiA9IG5ldyBNb25lcm9Db25uZWN0aW9uU3BhbigpO1xuICAgIGZvciAobGV0IGtleSBvZiBPYmplY3Qua2V5cyhycGNDb25uZWN0aW9uU3BhbikpIHtcbiAgICAgIGxldCB2YWwgPSBycGNDb25uZWN0aW9uU3BhbltrZXldO1xuICAgICAgaWYgKGtleSA9PT0gXCJjb25uZWN0aW9uX2lkXCIpIHNwYW4uc2V0Q29ubmVjdGlvbklkKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwibmJsb2Nrc1wiKSBzcGFuLnNldE51bUJsb2Nrcyh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInJhdGVcIikgc3Bhbi5zZXRSYXRlKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicmVtb3RlX2FkZHJlc3NcIikgeyBpZiAodmFsICE9PSBcIlwiKSBzcGFuLnNldFJlbW90ZUFkZHJlc3ModmFsKTsgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInNpemVcIikgc3Bhbi5zZXRTaXplKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwic3BlZWRcIikgc3Bhbi5zZXRTcGVlZCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInN0YXJ0X2Jsb2NrX2hlaWdodFwiKSBzcGFuLnNldFN0YXJ0SGVpZ2h0KHZhbCk7XG4gICAgICBlbHNlIGNvbnNvbGUubG9nKFwiV0FSTklORzogaWdub3JpbmcgdW5leHBlY3RlZCBmaWVsZCBpbiBkYWVtb24gY29ubmVjdGlvbiBzcGFuOiBcIiArIGtleSArIFwiOiBcIiArIHZhbCk7XG4gICAgfVxuICAgIHJldHVybiBzcGFuO1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNPdXRwdXRIaXN0b2dyYW1FbnRyeShycGNFbnRyeSkge1xuICAgIGxldCBlbnRyeSA9IG5ldyBNb25lcm9PdXRwdXRIaXN0b2dyYW1FbnRyeSgpO1xuICAgIGZvciAobGV0IGtleSBvZiBPYmplY3Qua2V5cyhycGNFbnRyeSkpIHtcbiAgICAgIGxldCB2YWwgPSBycGNFbnRyeVtrZXldO1xuICAgICAgaWYgKGtleSA9PT0gXCJhbW91bnRcIikgZW50cnkuc2V0QW1vdW50KEJpZ0ludCh2YWwpKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0b3RhbF9pbnN0YW5jZXNcIikgZW50cnkuc2V0TnVtSW5zdGFuY2VzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidW5sb2NrZWRfaW5zdGFuY2VzXCIpIGVudHJ5LnNldE51bVVubG9ja2VkSW5zdGFuY2VzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicmVjZW50X2luc3RhbmNlc1wiKSBlbnRyeS5zZXROdW1SZWNlbnRJbnN0YW5jZXModmFsKTtcbiAgICAgIGVsc2UgY29uc29sZS5sb2coXCJXQVJOSU5HOiBpZ25vcmluZyB1bmV4cGVjdGVkIGZpZWxkIGluIG91dHB1dCBoaXN0b2dyYW06IFwiICsga2V5ICsgXCI6IFwiICsgdmFsKTtcbiAgICB9XG4gICAgcmV0dXJuIGVudHJ5O1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNTdWJtaXRUeFJlc3VsdChycGNSZXN1bHQpIHtcbiAgICBhc3NlcnQocnBjUmVzdWx0KTtcbiAgICBsZXQgcmVzdWx0ID0gbmV3IE1vbmVyb1N1Ym1pdFR4UmVzdWx0KCk7XG4gICAgZm9yIChsZXQga2V5IG9mIE9iamVjdC5rZXlzKHJwY1Jlc3VsdCkpIHtcbiAgICAgIGxldCB2YWwgPSBycGNSZXN1bHRba2V5XTtcbiAgICAgIGlmIChrZXkgPT09IFwiZG91YmxlX3NwZW5kXCIpIHJlc3VsdC5zZXRJc0RvdWJsZVNwZW5kU2Vlbih2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImZlZV90b29fbG93XCIpIHJlc3VsdC5zZXRJc0ZlZVRvb0xvdyh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImludmFsaWRfaW5wdXRcIikgcmVzdWx0LnNldEhhc0ludmFsaWRJbnB1dCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImludmFsaWRfb3V0cHV0XCIpIHJlc3VsdC5zZXRIYXNJbnZhbGlkT3V0cHV0KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidG9vX2Zld19vdXRwdXRzXCIpIHJlc3VsdC5zZXRIYXNUb29GZXdPdXRwdXRzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwibG93X21peGluXCIpIHJlc3VsdC5zZXRJc01peGluVG9vTG93KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwibm90X3JlbGF5ZWRcIikgcmVzdWx0LnNldElzUmVsYXllZCghdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJvdmVyc3BlbmRcIikgcmVzdWx0LnNldElzT3ZlcnNwZW5kKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicmVhc29uXCIpIHJlc3VsdC5zZXRSZWFzb24odmFsID09PSBcIlwiID8gdW5kZWZpbmVkIDogdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0b29fYmlnXCIpIHJlc3VsdC5zZXRJc1Rvb0JpZyh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInNhbml0eV9jaGVja19mYWlsZWRcIikgcmVzdWx0LnNldFNhbml0eUNoZWNrRmFpbGVkKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiY3JlZGl0c1wiKSByZXN1bHQuc2V0Q3JlZGl0cyhCaWdJbnQodmFsKSlcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJzdGF0dXNcIiB8fCBrZXkgPT09IFwidW50cnVzdGVkXCIpIHt9ICAvLyBoYW5kbGVkIGVsc2V3aGVyZVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInRvcF9oYXNoXCIpIHJlc3VsdC5zZXRUb3BCbG9ja0hhc2goXCJcIiA9PT0gdmFsID8gdW5kZWZpbmVkIDogdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0eF9leHRyYV90b29fYmlnXCIpIHJlc3VsdC5zZXRJc1R4RXh0cmFUb29CaWcodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJub256ZXJvX3VubG9ja190aW1lXCIpIHJlc3VsdC5zZXRJc05vbnplcm9VbmxvY2tUaW1lKHZhbCk7XG4gICAgICBlbHNlIGNvbnNvbGUubG9nKFwiV0FSTklORzogaWdub3JpbmcgdW5leHBlY3RlZCBmaWVsZCBpbiBzdWJtaXQgdHggaGV4IHJlc3VsdDogXCIgKyBrZXkgKyBcIjogXCIgKyB2YWwpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNUeFBvb2xTdGF0cyhycGNTdGF0cykge1xuICAgIGFzc2VydChycGNTdGF0cyk7XG4gICAgbGV0IHN0YXRzID0gbmV3IE1vbmVyb1R4UG9vbFN0YXRzKCk7XG4gICAgZm9yIChsZXQga2V5IG9mIE9iamVjdC5rZXlzKHJwY1N0YXRzKSkge1xuICAgICAgbGV0IHZhbCA9IHJwY1N0YXRzW2tleV07XG4gICAgICBpZiAoa2V5ID09PSBcImJ5dGVzX21heFwiKSBzdGF0cy5zZXRCeXRlc01heCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImJ5dGVzX21lZFwiKSBzdGF0cy5zZXRCeXRlc01lZCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImJ5dGVzX21pblwiKSBzdGF0cy5zZXRCeXRlc01pbih2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImJ5dGVzX3RvdGFsXCIpIHN0YXRzLnNldEJ5dGVzVG90YWwodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJoaXN0b185OHBjXCIpIHN0YXRzLnNldEhpc3RvOThwYyh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIm51bV8xMG1cIikgc3RhdHMuc2V0TnVtMTBtKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwibnVtX2RvdWJsZV9zcGVuZHNcIikgc3RhdHMuc2V0TnVtRG91YmxlU3BlbmRzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwibnVtX2ZhaWxpbmdcIikgc3RhdHMuc2V0TnVtRmFpbGluZyh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIm51bV9ub3RfcmVsYXllZFwiKSBzdGF0cy5zZXROdW1Ob3RSZWxheWVkKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwib2xkZXN0XCIpIHN0YXRzLnNldE9sZGVzdFRpbWVzdGFtcCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInR4c190b3RhbFwiKSBzdGF0cy5zZXROdW1UeHModmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJmZWVfdG90YWxcIikgc3RhdHMuc2V0RmVlVG90YWwoQmlnSW50KHZhbCkpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImhpc3RvXCIpIHtcbiAgICAgICAgc3RhdHMuc2V0SGlzdG8obmV3IE1hcCgpKTtcbiAgICAgICAgZm9yIChsZXQgZWxlbSBvZiB2YWwpIHN0YXRzLmdldEhpc3RvKCkuc2V0KGVsZW0uYnl0ZXMsIGVsZW0udHhzKTtcbiAgICAgIH1cbiAgICAgIGVsc2UgY29uc29sZS5sb2coXCJXQVJOSU5HOiBpZ25vcmluZyB1bmV4cGVjdGVkIGZpZWxkIGluIHR4IHBvb2wgc3RhdHM6IFwiICsga2V5ICsgXCI6IFwiICsgdmFsKTtcbiAgICB9XG5cbiAgICAvLyB1bmluaXRpYWxpemUgc29tZSBzdGF0cyBpZiBub3QgYXBwbGljYWJsZVxuICAgIGlmIChzdGF0cy5nZXRIaXN0bzk4cGMoKSA9PT0gMCkgc3RhdHMuc2V0SGlzdG85OHBjKHVuZGVmaW5lZCk7XG4gICAgaWYgKHN0YXRzLmdldE51bVR4cygpID09PSAwKSB7XG4gICAgICBzdGF0cy5zZXRCeXRlc01pbih1bmRlZmluZWQpO1xuICAgICAgc3RhdHMuc2V0Qnl0ZXNNZWQodW5kZWZpbmVkKTtcbiAgICAgIHN0YXRzLnNldEJ5dGVzTWF4KHVuZGVmaW5lZCk7XG4gICAgICBzdGF0cy5zZXRIaXN0bzk4cGModW5kZWZpbmVkKTtcbiAgICAgIHN0YXRzLnNldE9sZGVzdFRpbWVzdGFtcCh1bmRlZmluZWQpO1xuICAgIH1cblxuICAgIHJldHVybiBzdGF0cztcbiAgfVxuICBcbiAgcHJvdGVjdGVkIHN0YXRpYyBjb252ZXJ0UnBjQWx0Q2hhaW4ocnBjQ2hhaW4pIHtcbiAgICBhc3NlcnQocnBjQ2hhaW4pO1xuICAgIGxldCBjaGFpbiA9IG5ldyBNb25lcm9BbHRDaGFpbigpO1xuICAgIGZvciAobGV0IGtleSBvZiBPYmplY3Qua2V5cyhycGNDaGFpbikpIHtcbiAgICAgIGxldCB2YWwgPSBycGNDaGFpbltrZXldO1xuICAgICAgaWYgKGtleSA9PT0gXCJibG9ja19oYXNoXCIpIHt9ICAvLyB1c2luZyBibG9ja19oYXNoZXMgaW5zdGVhZFxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImRpZmZpY3VsdHlcIikgeyB9IC8vIGhhbmRsZWQgYnkgd2lkZV9kaWZmaWN1bHR5XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiZGlmZmljdWx0eV90b3A2NFwiKSB7IH0gIC8vIGhhbmRsZWQgYnkgd2lkZV9kaWZmaWN1bHR5XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwid2lkZV9kaWZmaWN1bHR5XCIpIGNoYWluLnNldERpZmZpY3VsdHkoR2VuVXRpbHMucmVjb25jaWxlKGNoYWluLmdldERpZmZpY3VsdHkoKSwgTW9uZXJvRGFlbW9uUnBjLnByZWZpeGVkSGV4VG9CSSh2YWwpKSk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiaGVpZ2h0XCIpIGNoYWluLnNldEhlaWdodCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImxlbmd0aFwiKSBjaGFpbi5zZXRMZW5ndGgodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJibG9ja19oYXNoZXNcIikgY2hhaW4uc2V0QmxvY2tIYXNoZXModmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJtYWluX2NoYWluX3BhcmVudF9ibG9ja1wiKSBjaGFpbi5zZXRNYWluQ2hhaW5QYXJlbnRCbG9ja0hhc2godmFsKTtcbiAgICAgIGVsc2UgY29uc29sZS5sb2coXCJXQVJOSU5HOiBpZ25vcmluZyB1bmV4cGVjdGVkIGZpZWxkIGluIGFsdGVybmF0aXZlIGNoYWluOiBcIiArIGtleSArIFwiOiBcIiArIHZhbCk7XG4gICAgfVxuICAgIHJldHVybiBjaGFpbjtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIHN0YXRpYyBjb252ZXJ0UnBjUGVlcihycGNQZWVyKSB7XG4gICAgYXNzZXJ0KHJwY1BlZXIpO1xuICAgIGxldCBwZWVyID0gbmV3IE1vbmVyb1BlZXIoKTtcbiAgICBmb3IgKGxldCBrZXkgb2YgT2JqZWN0LmtleXMocnBjUGVlcikpIHtcbiAgICAgIGxldCB2YWwgPSBycGNQZWVyW2tleV07XG4gICAgICBpZiAoa2V5ID09PSBcImhvc3RcIikgcGVlci5zZXRIb3N0KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiaWRcIikgcGVlci5zZXRJZChcIlwiICsgdmFsKTsgIC8vIFRPRE8gbW9uZXJvLXdhbGxldC1ycGM6IHBlZXIgaWQgaXMgQmlnSW50IGJ1dCBzdHJpbmcgaW4gYGdldF9jb25uZWN0aW9uc2BcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJpcFwiKSB7fSAvLyBob3N0IHVzZWQgaW5zdGVhZCB3aGljaCBpcyBjb25zaXN0ZW50bHkgYSBzdHJpbmdcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJsYXN0X3NlZW5cIikgcGVlci5zZXRMYXN0U2VlblRpbWVzdGFtcCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInBvcnRcIikgcGVlci5zZXRQb3J0KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicnBjX3BvcnRcIikgcGVlci5zZXRScGNQb3J0KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicHJ1bmluZ19zZWVkXCIpIHBlZXIuc2V0UHJ1bmluZ1NlZWQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJycGNfY3JlZGl0c19wZXJfaGFzaFwiKSBwZWVyLnNldFJwY0NyZWRpdHNQZXJIYXNoKEJpZ0ludCh2YWwpKTtcbiAgICAgIGVsc2UgY29uc29sZS5sb2coXCJXQVJOSU5HOiBpZ25vcmluZyB1bmV4cGVjdGVkIGZpZWxkIGluIHJwYyBwZWVyOiBcIiArIGtleSArIFwiOiBcIiArIHZhbCk7XG4gICAgfVxuICAgIHJldHVybiBwZWVyO1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNDb25uZWN0aW9uKHJwY0Nvbm5lY3Rpb24pIHtcbiAgICBsZXQgcGVlciA9IG5ldyBNb25lcm9QZWVyKCk7XG4gICAgcGVlci5zZXRJc09ubGluZSh0cnVlKTtcbiAgICBmb3IgKGxldCBrZXkgb2YgT2JqZWN0LmtleXMocnBjQ29ubmVjdGlvbikpIHtcbiAgICAgIGxldCB2YWwgPSBycGNDb25uZWN0aW9uW2tleV07XG4gICAgICBpZiAoa2V5ID09PSBcImFkZHJlc3NcIikgcGVlci5zZXRBZGRyZXNzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYXZnX2Rvd25sb2FkXCIpIHBlZXIuc2V0QXZnRG93bmxvYWQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJhdmdfdXBsb2FkXCIpIHBlZXIuc2V0QXZnVXBsb2FkKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiY29ubmVjdGlvbl9pZFwiKSBwZWVyLnNldElkKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiY3VycmVudF9kb3dubG9hZFwiKSBwZWVyLnNldEN1cnJlbnREb3dubG9hZCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImN1cnJlbnRfdXBsb2FkXCIpIHBlZXIuc2V0Q3VycmVudFVwbG9hZCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImhlaWdodFwiKSBwZWVyLnNldEhlaWdodCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImhvc3RcIikgcGVlci5zZXRIb3N0KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiaXBcIikge30gLy8gaG9zdCB1c2VkIGluc3RlYWQgd2hpY2ggaXMgY29uc2lzdGVudGx5IGEgc3RyaW5nXG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiaW5jb21pbmdcIikgcGVlci5zZXRJc0luY29taW5nKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwibGl2ZV90aW1lXCIpIHBlZXIuc2V0TGl2ZVRpbWUodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJsb2NhbF9pcFwiKSBwZWVyLnNldElzTG9jYWxJcCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImxvY2FsaG9zdFwiKSBwZWVyLnNldElzTG9jYWxIb3N0KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicGVlcl9pZFwiKSBwZWVyLnNldElkKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicG9ydFwiKSBwZWVyLnNldFBvcnQocGFyc2VJbnQodmFsKSk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicnBjX3BvcnRcIikgcGVlci5zZXRScGNQb3J0KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicmVjdl9jb3VudFwiKSBwZWVyLnNldE51bVJlY2VpdmVzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicmVjdl9pZGxlX3RpbWVcIikgcGVlci5zZXRSZWNlaXZlSWRsZVRpbWUodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJzZW5kX2NvdW50XCIpIHBlZXIuc2V0TnVtU2VuZHModmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJzZW5kX2lkbGVfdGltZVwiKSBwZWVyLnNldFNlbmRJZGxlVGltZSh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInN0YXRlXCIpIHBlZXIuc2V0U3RhdGUodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJzdXBwb3J0X2ZsYWdzXCIpIHBlZXIuc2V0TnVtU3VwcG9ydEZsYWdzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicHJ1bmluZ19zZWVkXCIpIHBlZXIuc2V0UHJ1bmluZ1NlZWQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJycGNfY3JlZGl0c19wZXJfaGFzaFwiKSBwZWVyLnNldFJwY0NyZWRpdHNQZXJIYXNoKEJpZ0ludCh2YWwpKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJhZGRyZXNzX3R5cGVcIikgcGVlci5zZXRUeXBlKHZhbCk7XG4gICAgICBlbHNlIGNvbnNvbGUubG9nKFwiV0FSTklORzogaWdub3JpbmcgdW5leHBlY3RlZCBmaWVsZCBpbiBwZWVyOiBcIiArIGtleSArIFwiOiBcIiArIHZhbCk7XG4gICAgfVxuICAgIHJldHVybiBwZWVyO1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRUb1JwY0JhbihiYW46IE1vbmVyb0Jhbikge1xuICAgIGxldCBycGNCYW46IGFueSA9IHt9O1xuICAgIHJwY0Jhbi5ob3N0ID0gYmFuLmdldEhvc3QoKTtcbiAgICBycGNCYW4uaXAgPSBiYW4uZ2V0SXAoKTtcbiAgICBycGNCYW4uYmFuID0gYmFuLmdldElzQmFubmVkKCk7XG4gICAgcnBjQmFuLnNlY29uZHMgPSBiYW4uZ2V0U2Vjb25kcygpO1xuICAgIHJldHVybiBycGNCYW47XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgY29udmVydFJwY01pbmluZ1N0YXR1cyhycGNTdGF0dXMpIHtcbiAgICBsZXQgc3RhdHVzID0gbmV3IE1vbmVyb01pbmluZ1N0YXR1cygpO1xuICAgIHN0YXR1cy5zZXRJc0FjdGl2ZShycGNTdGF0dXMuYWN0aXZlKTtcbiAgICBzdGF0dXMuc2V0U3BlZWQocnBjU3RhdHVzLnNwZWVkKTtcbiAgICBzdGF0dXMuc2V0TnVtVGhyZWFkcyhycGNTdGF0dXMudGhyZWFkc19jb3VudCk7XG4gICAgaWYgKHJwY1N0YXR1cy5hY3RpdmUpIHtcbiAgICAgIHN0YXR1cy5zZXRBZGRyZXNzKHJwY1N0YXR1cy5hZGRyZXNzKTtcbiAgICAgIHN0YXR1cy5zZXRJc0JhY2tncm91bmQocnBjU3RhdHVzLmlzX2JhY2tncm91bmRfbWluaW5nX2VuYWJsZWQpO1xuICAgIH1cbiAgICByZXR1cm4gc3RhdHVzO1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNVcGRhdGVDaGVja1Jlc3VsdChycGNSZXN1bHQpIHtcbiAgICBhc3NlcnQocnBjUmVzdWx0KTtcbiAgICBsZXQgcmVzdWx0ID0gbmV3IE1vbmVyb0RhZW1vblVwZGF0ZUNoZWNrUmVzdWx0KCk7XG4gICAgZm9yIChsZXQga2V5IG9mIE9iamVjdC5rZXlzKHJwY1Jlc3VsdCkpIHtcbiAgICAgIGxldCB2YWwgPSBycGNSZXN1bHRba2V5XTtcbiAgICAgIGlmIChrZXkgPT09IFwiYXV0b191cmlcIikgcmVzdWx0LnNldEF1dG9VcmkodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJoYXNoXCIpIHJlc3VsdC5zZXRIYXNoKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicGF0aFwiKSB7fSAvLyBoYW5kbGVkIGVsc2V3aGVyZVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInN0YXR1c1wiKSB7fSAvLyBoYW5kbGVkIGVsc2V3aGVyZVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInVwZGF0ZVwiKSByZXN1bHQuc2V0SXNVcGRhdGVBdmFpbGFibGUodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ1c2VyX3VyaVwiKSByZXN1bHQuc2V0VXNlclVyaSh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInZlcnNpb25cIikgcmVzdWx0LnNldFZlcnNpb24odmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ1bnRydXN0ZWRcIikge30gLy8gaGFuZGxlZCBlbHNld2hlcmVcbiAgICAgIGVsc2UgY29uc29sZS5sb2coXCJXQVJOSU5HOiBpZ25vcmluZyB1bmV4cGVjdGVkIGZpZWxkIGluIHJwYyBjaGVjayB1cGRhdGUgcmVzdWx0OiBcIiArIGtleSArIFwiOiBcIiArIHZhbCk7XG4gICAgfVxuICAgIGlmIChyZXN1bHQuZ2V0QXV0b1VyaSgpID09PSBcIlwiKSByZXN1bHQuc2V0QXV0b1VyaSh1bmRlZmluZWQpO1xuICAgIGlmIChyZXN1bHQuZ2V0VXNlclVyaSgpID09PSBcIlwiKSByZXN1bHQuc2V0VXNlclVyaSh1bmRlZmluZWQpO1xuICAgIGlmIChyZXN1bHQuZ2V0VmVyc2lvbigpID09PSBcIlwiKSByZXN1bHQuc2V0VmVyc2lvbih1bmRlZmluZWQpO1xuICAgIGlmIChyZXN1bHQuZ2V0SGFzaCgpID09PSBcIlwiKSByZXN1bHQuc2V0SGFzaCh1bmRlZmluZWQpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgY29udmVydFJwY1VwZGF0ZURvd25sb2FkUmVzdWx0KHJwY1Jlc3VsdCkge1xuICAgIGxldCByZXN1bHQgPSBuZXcgTW9uZXJvRGFlbW9uVXBkYXRlRG93bmxvYWRSZXN1bHQoTW9uZXJvRGFlbW9uUnBjLmNvbnZlcnRScGNVcGRhdGVDaGVja1Jlc3VsdChycGNSZXN1bHQpIGFzIE1vbmVyb0RhZW1vblVwZGF0ZURvd25sb2FkUmVzdWx0KTtcbiAgICByZXN1bHQuc2V0RG93bmxvYWRQYXRoKHJwY1Jlc3VsdFtcInBhdGhcIl0pO1xuICAgIGlmIChyZXN1bHQuZ2V0RG93bmxvYWRQYXRoKCkgPT09IFwiXCIpIHJlc3VsdC5zZXREb3dubG9hZFBhdGgodW5kZWZpbmVkKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnRzIGEgJzB4JyBwcmVmaXhlZCBoZXhpZGVjaW1hbCBzdHJpbmcgdG8gYSBiaWdpbnQuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGV4IGlzIHRoZSAnMHgnIHByZWZpeGVkIGhleGlkZWNpbWFsIHN0cmluZyB0byBjb252ZXJ0XG4gICAqIEByZXR1cm4ge2JpZ2ludH0gdGhlIGhleGljZWRpbWFsIGNvbnZlcnRlZCB0byBkZWNpbWFsXG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIHByZWZpeGVkSGV4VG9CSShoZXgpIHtcbiAgICBhc3NlcnQoaGV4LnN1YnN0cmluZygwLCAyKSA9PT0gXCIweFwiKTtcbiAgICByZXR1cm4gQmlnSW50KGhleCk7XG4gIH1cbn1cblxuLyoqXG4gKiBJbXBsZW1lbnRzIGEgTW9uZXJvRGFlbW9uIGJ5IHByb3h5aW5nIHJlcXVlc3RzIHRvIGEgd29ya2VyLlxuICogXG4gKiBAcHJpdmF0ZVxuICovXG5jbGFzcyBNb25lcm9EYWVtb25ScGNQcm94eSB7XG5cbiAgLy8gc3RhdGUgdmFyaWFibGVzXG4gIHByaXZhdGUgZGFlbW9uSWQ6IGFueTtcbiAgcHJpdmF0ZSB3b3JrZXI6IGFueTtcbiAgcHJpdmF0ZSB3cmFwcGVkTGlzdGVuZXJzOiBhbnk7XG4gIHByaXZhdGUgcHJvY2VzczogYW55O1xuXG4gIGNvbnN0cnVjdG9yKGRhZW1vbklkLCB3b3JrZXIpIHtcbiAgICB0aGlzLmRhZW1vbklkID0gZGFlbW9uSWQ7XG4gICAgdGhpcy53b3JrZXIgPSB3b3JrZXI7XG4gICAgdGhpcy53cmFwcGVkTGlzdGVuZXJzID0gW107XG4gIH1cbiAgXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBTVEFUSUMgVVRJTElUSUVTIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIFxuICBzdGF0aWMgYXN5bmMgY29ubmVjdChjb25maWc6IE1vbmVyb0RhZW1vbkNvbmZpZykge1xuICAgIGxldCBkYWVtb25JZCA9IEdlblV0aWxzLmdldFVVSUQoKTtcbiAgICBjb25maWcgPSBPYmplY3QuYXNzaWduKHt9LCBjb25maWcudG9Kc29uKCksIHtwcm94eVRvV29ya2VyOiBmYWxzZX0pO1xuICAgIGF3YWl0IExpYnJhcnlVdGlscy5pbnZva2VXb3JrZXIoZGFlbW9uSWQsIFwiY29ubmVjdERhZW1vblJwY1wiLCBbY29uZmlnXSk7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9EYWVtb25ScGNQcm94eShkYWVtb25JZCwgYXdhaXQgTGlicmFyeVV0aWxzLmdldFdvcmtlcigpKTtcbiAgfVxuICBcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBJTlNUQU5DRSBNRVRIT0RTIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgXG4gIGFzeW5jIGFkZExpc3RlbmVyKGxpc3RlbmVyKSB7XG4gICAgbGV0IHdyYXBwZWRMaXN0ZW5lciA9IG5ldyBEYWVtb25Xb3JrZXJMaXN0ZW5lcihsaXN0ZW5lcik7XG4gICAgbGV0IGxpc3RlbmVySWQgPSB3cmFwcGVkTGlzdGVuZXIuZ2V0SWQoKTtcbiAgICBMaWJyYXJ5VXRpbHMuYWRkV29ya2VyQ2FsbGJhY2sodGhpcy5kYWVtb25JZCwgXCJvbkJsb2NrSGVhZGVyX1wiICsgbGlzdGVuZXJJZCwgW3dyYXBwZWRMaXN0ZW5lci5vbkJsb2NrSGVhZGVyLCB3cmFwcGVkTGlzdGVuZXJdKTtcbiAgICB0aGlzLndyYXBwZWRMaXN0ZW5lcnMucHVzaCh3cmFwcGVkTGlzdGVuZXIpO1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vbkFkZExpc3RlbmVyXCIsIFtsaXN0ZW5lcklkXSk7XG4gIH1cbiAgXG4gIGFzeW5jIHJlbW92ZUxpc3RlbmVyKGxpc3RlbmVyKSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLndyYXBwZWRMaXN0ZW5lcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmICh0aGlzLndyYXBwZWRMaXN0ZW5lcnNbaV0uZ2V0TGlzdGVuZXIoKSA9PT0gbGlzdGVuZXIpIHtcbiAgICAgICAgbGV0IGxpc3RlbmVySWQgPSB0aGlzLndyYXBwZWRMaXN0ZW5lcnNbaV0uZ2V0SWQoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25SZW1vdmVMaXN0ZW5lclwiLCBbbGlzdGVuZXJJZF0pO1xuICAgICAgICBMaWJyYXJ5VXRpbHMucmVtb3ZlV29ya2VyQ2FsbGJhY2sodGhpcy5kYWVtb25JZCwgXCJvbkJsb2NrSGVhZGVyX1wiICsgbGlzdGVuZXJJZCk7XG4gICAgICAgIHRoaXMud3JhcHBlZExpc3RlbmVycy5zcGxpY2UoaSwgMSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTGlzdGVuZXIgaXMgbm90IHJlZ2lzdGVyZWQgd2l0aCBkYWVtb25cIik7XG4gIH1cbiAgXG4gIGFzeW5jIGdldExpc3RlbmVycygpIHtcbiAgICBsZXQgbGlzdGVuZXJzID0gW107XG4gICAgZm9yIChsZXQgd3JhcHBlZExpc3RlbmVyIG9mIHRoaXMud3JhcHBlZExpc3RlbmVycykgbGlzdGVuZXJzLnB1c2god3JhcHBlZExpc3RlbmVyLmdldExpc3RlbmVyKCkpO1xuICAgIHJldHVybiBsaXN0ZW5lcnM7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFJwY0Nvbm5lY3Rpb24oKSB7XG4gICAgbGV0IGNvbmZpZyA9IGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0UnBjQ29ubmVjdGlvblwiKTtcbiAgICByZXR1cm4gbmV3IE1vbmVyb1JwY0Nvbm5lY3Rpb24oY29uZmlnIGFzIFBhcnRpYWw8TW9uZXJvUnBjQ29ubmVjdGlvbj4pO1xuICB9XG4gIFxuICBhc3luYyBpc0Nvbm5lY3RlZCgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25Jc0Nvbm5lY3RlZFwiKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0VmVyc2lvbigpIHtcbiAgICBsZXQgdmVyc2lvbkpzb246IGFueSA9IGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0VmVyc2lvblwiKTtcbiAgICByZXR1cm4gbmV3IE1vbmVyb1ZlcnNpb24odmVyc2lvbkpzb24ubnVtYmVyLCB2ZXJzaW9uSnNvbi5pc1JlbGVhc2UpO1xuICB9XG4gIFxuICBhc3luYyBpc1RydXN0ZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uSXNUcnVzdGVkXCIpO1xuICB9XG4gIFxuICBhc3luYyBnZXRIZWlnaHQoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0SGVpZ2h0XCIpO1xuICB9XG4gIFxuICBhc3luYyBnZXRCbG9ja0hhc2goaGVpZ2h0KSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0QmxvY2tIYXNoXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEJsb2NrVGVtcGxhdGUod2FsbGV0QWRkcmVzcywgcmVzZXJ2ZVNpemUpIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb0Jsb2NrVGVtcGxhdGUoYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25HZXRCbG9ja1RlbXBsYXRlXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSkpO1xuICB9XG4gIFxuICBhc3luYyBnZXRMYXN0QmxvY2tIZWFkZXIoKSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9CbG9ja0hlYWRlcihhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vbkdldExhc3RCbG9ja0hlYWRlclwiKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEJsb2NrSGVhZGVyQnlIYXNoKGJsb2NrSGFzaCkge1xuICAgIHJldHVybiBuZXcgTW9uZXJvQmxvY2tIZWFkZXIoYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25HZXRCbG9ja0hlYWRlckJ5SGFzaFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QmxvY2tIZWFkZXJCeUhlaWdodChoZWlnaHQpIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb0Jsb2NrSGVhZGVyKGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0QmxvY2tIZWFkZXJCeUhlaWdodFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QmxvY2tIZWFkZXJzQnlSYW5nZShzdGFydEhlaWdodCwgZW5kSGVpZ2h0KSB7XG4gICAgbGV0IGJsb2NrSGVhZGVyc0pzb246IGFueVtdID0gYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25HZXRCbG9ja0hlYWRlcnNCeVJhbmdlXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSkgYXMgYW55W107XG4gICAgbGV0IGhlYWRlcnMgPSBbXTtcbiAgICBmb3IgKGxldCBibG9ja0hlYWRlckpzb24gb2YgYmxvY2tIZWFkZXJzSnNvbikgaGVhZGVycy5wdXNoKG5ldyBNb25lcm9CbG9ja0hlYWRlcihibG9ja0hlYWRlckpzb24pKTtcbiAgICByZXR1cm4gaGVhZGVycztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QmxvY2tCeUhhc2goYmxvY2tIYXNoKSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9CbG9jayhhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vbkdldEJsb2NrQnlIYXNoXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSksIE1vbmVyb0Jsb2NrLkRlc2VyaWFsaXphdGlvblR5cGUuVFgpO1xuICB9XG4gIFxuICBhc3luYyBnZXRCbG9ja3NCeUhhc2goYmxvY2tIYXNoZXMsIHN0YXJ0SGVpZ2h0LCBwcnVuZSkge1xuICAgIGxldCBibG9ja3NKc29uOiBhbnlbXSA9IGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0QmxvY2tzQnlIYXNoXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSkgYXMgYW55W107XG4gICAgbGV0IGJsb2NrcyA9IFtdO1xuICAgIGZvciAobGV0IGJsb2NrSnNvbiBvZiBibG9ja3NKc29uKSBibG9ja3MucHVzaChuZXcgTW9uZXJvQmxvY2soYmxvY2tKc29uKSk7XG4gICAgcmV0dXJuIGJsb2NrcztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QmxvY2tCeUhlaWdodChoZWlnaHQpIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb0Jsb2NrKGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0QmxvY2tCeUhlaWdodFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpLCBNb25lcm9CbG9jay5EZXNlcmlhbGl6YXRpb25UeXBlLlRYKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QmxvY2tzQnlIZWlnaHQoaGVpZ2h0cykge1xuICAgIGxldCBibG9ja3NKc29uOiBhbnlbXT0gYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25HZXRCbG9ja3NCeUhlaWdodFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpIGFzIGFueVtdO1xuICAgIGxldCBibG9ja3MgPSBbXTtcbiAgICBmb3IgKGxldCBibG9ja0pzb24gb2YgYmxvY2tzSnNvbikgYmxvY2tzLnB1c2gobmV3IE1vbmVyb0Jsb2NrKGJsb2NrSnNvbiwgTW9uZXJvQmxvY2suRGVzZXJpYWxpemF0aW9uVHlwZS5UWCkpO1xuICAgIHJldHVybiBibG9ja3M7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEJsb2Nrc0J5UmFuZ2Uoc3RhcnRIZWlnaHQsIGVuZEhlaWdodCkge1xuICAgIGxldCBibG9ja3NKc29uOiBhbnlbXSA9IGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0QmxvY2tzQnlSYW5nZVwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpIGFzIGFueVtdO1xuICAgIGxldCBibG9ja3MgPSBbXTtcbiAgICBmb3IgKGxldCBibG9ja0pzb24gb2YgYmxvY2tzSnNvbikgYmxvY2tzLnB1c2gobmV3IE1vbmVyb0Jsb2NrKGJsb2NrSnNvbiwgTW9uZXJvQmxvY2suRGVzZXJpYWxpemF0aW9uVHlwZS5UWCkpO1xuICAgIHJldHVybiBibG9ja3M7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEJsb2Nrc0J5UmFuZ2VDaHVua2VkKHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQsIG1heENodW5rU2l6ZSkge1xuICAgIGxldCBibG9ja3NKc29uID0gYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25HZXRCbG9ja3NCeVJhbmdlQ2h1bmtlZFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpIGFzIGFueVtdO1xuICAgIGxldCBibG9ja3MgPSBbXTtcbiAgICBmb3IgKGxldCBibG9ja0pzb24gb2YgYmxvY2tzSnNvbikgYmxvY2tzLnB1c2gobmV3IE1vbmVyb0Jsb2NrKGJsb2NrSnNvbiwgTW9uZXJvQmxvY2suRGVzZXJpYWxpemF0aW9uVHlwZS5UWCkpO1xuICAgIHJldHVybiBibG9ja3M7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEJsb2NrSGFzaGVzKGJsb2NrSGFzaGVzLCBzdGFydEhlaWdodCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vbkdldEJsb2NrSGFzaGVzXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFR4cyh0eEhhc2hlcywgcHJ1bmUgPSBmYWxzZSkge1xuICAgIFxuICAgIC8vIGRlc2VyaWFsaXplIHR4cyBmcm9tIGJsb2Nrc1xuICAgIGxldCBibG9ja3MgPSBbXTtcbiAgICBmb3IgKGxldCBibG9ja0pzb24gb2YgYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25HZXRUeHNcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKSBhcyBhbnlbXSkge1xuICAgICAgYmxvY2tzLnB1c2gobmV3IE1vbmVyb0Jsb2NrKGJsb2NrSnNvbiwgTW9uZXJvQmxvY2suRGVzZXJpYWxpemF0aW9uVHlwZS5UWCkpO1xuICAgIH1cbiAgICBcbiAgICAvLyBjb2xsZWN0IHR4c1xuICAgIGxldCB0eHMgPSBbXTtcbiAgICBmb3IgKGxldCBibG9jayBvZiBibG9ja3MpIHtcbiAgICAgIGZvciAobGV0IHR4IG9mIGJsb2NrLmdldFR4cygpKSB7XG4gICAgICAgIGlmICghdHguZ2V0SXNDb25maXJtZWQoKSkgdHguc2V0QmxvY2sodW5kZWZpbmVkKTtcbiAgICAgICAgdHhzLnB1c2godHgpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHhzO1xuICB9XG4gIFxuICBhc3luYyBnZXRUeEhleGVzKHR4SGFzaGVzLCBwcnVuZSA9IGZhbHNlKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0VHhIZXhlc1wiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyBnZXRNaW5lclR4U3VtKGhlaWdodCwgbnVtQmxvY2tzKSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9NaW5lclR4U3VtKGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0TWluZXJUeFN1bVwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0RmVlRXN0aW1hdGUoZ3JhY2VCbG9ja3M/KSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9GZWVFc3RpbWF0ZShhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vbkdldEZlZUVzdGltYXRlXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSkpO1xuICB9XG4gIFxuICBhc3luYyBzdWJtaXRUeEhleCh0eEhleCwgZG9Ob3RSZWxheSkge1xuICAgIHJldHVybiBuZXcgTW9uZXJvU3VibWl0VHhSZXN1bHQoYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25TdWJtaXRUeEhleFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpKTtcbiAgfVxuICBcbiAgYXN5bmMgcmVsYXlUeHNCeUhhc2godHhIYXNoZXMpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25SZWxheVR4c0J5SGFzaFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyBnZXRUeFBvb2woKSB7XG4gICAgbGV0IGJsb2NrSnNvbiA9IGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0VHhQb29sXCIpO1xuICAgIGxldCB0eHMgPSBuZXcgTW9uZXJvQmxvY2soYmxvY2tKc29uLCBNb25lcm9CbG9jay5EZXNlcmlhbGl6YXRpb25UeXBlLlRYKS5nZXRUeHMoKTtcbiAgICBmb3IgKGxldCB0eCBvZiB0eHMpIHR4LnNldEJsb2NrKHVuZGVmaW5lZCk7XG4gICAgcmV0dXJuIHR4cyA/IHR4cyA6IFtdO1xuICB9XG4gIFxuICBhc3luYyBnZXRUeFBvb2xIYXNoZXMoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0VHhQb29sSGFzaGVzXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFR4UG9vbEJhY2tsb2coKSB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IGltcGxlbWVudGVkXCIpO1xuICB9XG4gIFxuICBhc3luYyBnZXRUeFBvb2xTdGF0cygpIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb1R4UG9vbFN0YXRzKGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0VHhQb29sU3RhdHNcIikpO1xuICB9XG4gIFxuICBhc3luYyBmbHVzaFR4UG9vbChoYXNoZXMpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25GbHVzaFR4UG9vbFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyBnZXRLZXlJbWFnZVNwZW50U3RhdHVzZXMoa2V5SW1hZ2VzKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0S2V5SW1hZ2VTcGVudFN0YXR1c2VzXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldE91dHB1dHMob3V0cHV0cyk6IFByb21pc2U8TW9uZXJvT3V0cHV0W10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWRcIik7XG4gIH1cbiAgXG4gIGFzeW5jIGdldE91dHB1dEhpc3RvZ3JhbShhbW91bnRzLCBtaW5Db3VudCwgbWF4Q291bnQsIGlzVW5sb2NrZWQsIHJlY2VudEN1dG9mZikge1xuICAgIGxldCBlbnRyaWVzID0gW107XG4gICAgZm9yIChsZXQgZW50cnlKc29uIG9mIGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0T3V0cHV0SGlzdG9ncmFtXCIsIFthbW91bnRzLCBtaW5Db3VudCwgbWF4Q291bnQsIGlzVW5sb2NrZWQsIHJlY2VudEN1dG9mZl0pIGFzIGFueVtdKSB7XG4gICAgICBlbnRyaWVzLnB1c2gobmV3IE1vbmVyb091dHB1dEhpc3RvZ3JhbUVudHJ5KGVudHJ5SnNvbikpO1xuICAgIH1cbiAgICByZXR1cm4gZW50cmllcztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0T3V0cHV0RGlzdHJpYnV0aW9uKGFtb3VudHMsIGN1bXVsYXRpdmUsIHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQpIHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWRcIik7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEluZm8oKSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9EYWVtb25JbmZvKGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0SW5mb1wiKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFN5bmNJbmZvKCkge1xuICAgIHJldHVybiBuZXcgTW9uZXJvRGFlbW9uU3luY0luZm8oYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25HZXRTeW5jSW5mb1wiKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEhhcmRGb3JrSW5mbygpIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb0hhcmRGb3JrSW5mbyhhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vbkdldEhhcmRGb3JrSW5mb1wiKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEFsdENoYWlucygpIHtcbiAgICBsZXQgYWx0Q2hhaW5zID0gW107XG4gICAgZm9yIChsZXQgYWx0Q2hhaW5Kc29uIG9mIGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uR2V0QWx0Q2hhaW5zXCIpIGFzIGFueSkgYWx0Q2hhaW5zLnB1c2gobmV3IE1vbmVyb0FsdENoYWluKGFsdENoYWluSnNvbikpO1xuICAgIHJldHVybiBhbHRDaGFpbnM7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEFsdEJsb2NrSGFzaGVzKCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vbkdldEFsdEJsb2NrSGFzaGVzXCIpO1xuICB9XG4gIFxuICBhc3luYyBnZXREb3dubG9hZExpbWl0KCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vbkdldERvd25sb2FkTGltaXRcIik7XG4gIH1cbiAgXG4gIGFzeW5jIHNldERvd25sb2FkTGltaXQobGltaXQpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25TZXREb3dubG9hZExpbWl0XCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIHJlc2V0RG93bmxvYWRMaW1pdCgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25SZXNldERvd25sb2FkTGltaXRcIik7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFVwbG9hZExpbWl0KCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vbkdldFVwbG9hZExpbWl0XCIpO1xuICB9XG4gIFxuICBhc3luYyBzZXRVcGxvYWRMaW1pdChsaW1pdCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vblNldFVwbG9hZExpbWl0XCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIHJlc2V0VXBsb2FkTGltaXQoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uUmVzZXRVcGxvYWRMaW1pdFwiKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UGVlcnMoKSB7XG4gICAgbGV0IHBlZXJzID0gW107XG4gICAgZm9yIChsZXQgcGVlckpzb24gb2YgYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25HZXRQZWVyc1wiKSBhcyBhbnkpIHBlZXJzLnB1c2gobmV3IE1vbmVyb1BlZXIocGVlckpzb24pKTtcbiAgICByZXR1cm4gcGVlcnM7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEtub3duUGVlcnMoKSB7XG4gICAgbGV0IHBlZXJzID0gW107XG4gICAgZm9yIChsZXQgcGVlckpzb24gb2YgYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25HZXRLbm93blBlZXJzXCIpIGFzIGFueSkgcGVlcnMucHVzaChuZXcgTW9uZXJvUGVlcihwZWVySnNvbikpO1xuICAgIHJldHVybiBwZWVycztcbiAgfVxuICBcbiAgYXN5bmMgc2V0T3V0Z29pbmdQZWVyTGltaXQobGltaXQpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25TZXRJbmNvbWluZ1BlZXJMaW1pdFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyBzZXRJbmNvbWluZ1BlZXJMaW1pdChsaW1pdCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vblNldEluY29taW5nUGVlckxpbWl0XCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFBlZXJCYW5zKCkge1xuICAgIGxldCBiYW5zID0gW107XG4gICAgZm9yIChsZXQgYmFuSnNvbiBvZiBhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vbkdldFBlZXJCYW5zXCIpIGFzIGFueSkgYmFucy5wdXNoKG5ldyBNb25lcm9CYW4oYmFuSnNvbikpO1xuICAgIHJldHVybiBiYW5zO1xuICB9XG5cbiAgYXN5bmMgc2V0UGVlckJhbnMoYmFucykge1xuICAgIGxldCBiYW5zSnNvbiA9IFtdO1xuICAgIGZvciAobGV0IGJhbiBvZiBiYW5zKSBiYW5zSnNvbi5wdXNoKGJhbi50b0pzb24oKSk7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uU2V0UGVlckJhbnNcIiwgW2JhbnNKc29uXSk7XG4gIH1cbiAgXG4gIGFzeW5jIHN0YXJ0TWluaW5nKGFkZHJlc3MsIG51bVRocmVhZHMsIGlzQmFja2dyb3VuZCwgaWdub3JlQmF0dGVyeSkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vblN0YXJ0TWluaW5nXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIHN0b3BNaW5pbmcoKSB7XG4gICAgYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJkYWVtb25TdG9wTWluaW5nXCIpXG4gIH1cbiAgXG4gIGFzeW5jIGdldE1pbmluZ1N0YXR1cygpIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb01pbmluZ1N0YXR1cyhhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vbkdldE1pbmluZ1N0YXR1c1wiKSk7XG4gIH1cbiAgXG4gIGFzeW5jIHN1Ym1pdEJsb2NrcyhibG9ja0Jsb2JzKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uU3VibWl0QmxvY2tzXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cblxuICBhc3luYyBwcnVuZUJsb2NrY2hhaW4oY2hlY2spIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb1BydW5lUmVzdWx0KGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGFlbW9uUHJ1bmVCbG9ja2NoYWluXCIpKTtcbiAgfVxuICBcbiAgYXN5bmMgY2hlY2tGb3JVcGRhdGUoKTogUHJvbWlzZTxNb25lcm9EYWVtb25VcGRhdGVDaGVja1Jlc3VsdD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBpbXBsZW1lbnRlZFwiKTtcbiAgfVxuICBcbiAgYXN5bmMgZG93bmxvYWRVcGRhdGUocGF0aCk6IFByb21pc2U8TW9uZXJvRGFlbW9uVXBkYXRlRG93bmxvYWRSZXN1bHQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3QgaW1wbGVtZW50ZWRcIik7XG4gIH1cbiAgXG4gIGFzeW5jIHN0b3AoKSB7XG4gICAgd2hpbGUgKHRoaXMud3JhcHBlZExpc3RlbmVycy5sZW5ndGgpIGF3YWl0IHRoaXMucmVtb3ZlTGlzdGVuZXIodGhpcy53cmFwcGVkTGlzdGVuZXJzWzBdLmdldExpc3RlbmVyKCkpO1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vblN0b3BcIik7XG4gIH1cbiAgXG4gIGFzeW5jIHdhaXRGb3JOZXh0QmxvY2tIZWFkZXIoKSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9CbG9ja0hlYWRlcihhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImRhZW1vbldhaXRGb3JOZXh0QmxvY2tIZWFkZXJcIikpO1xuICB9XG4gIFxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gUFJJVkFURSBIRUxQRVJTIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICBcbiAgLy8gVE9ETzogZHVwbGljYXRlZCB3aXRoIE1vbmVyb1dhbGxldEZ1bGxQcm94eVxuICBwcm90ZWN0ZWQgYXN5bmMgaW52b2tlV29ya2VyKGZuTmFtZTogc3RyaW5nLCBhcmdzPzogYW55KSB7XG4gICAgcmV0dXJuIExpYnJhcnlVdGlscy5pbnZva2VXb3JrZXIodGhpcy5kYWVtb25JZCwgZm5OYW1lLCBhcmdzKTtcbiAgfVxufVxuXG4vKipcbiAqIFBvbGxzIGEgTW9uZXJvIGRhZW1vbiBmb3IgdXBkYXRlcyBhbmQgbm90aWZpZXMgbGlzdGVuZXJzIGFzIHRoZXkgb2NjdXIuXG4gKiBcbiAqIEBwcml2YXRlXG4gKi9cbmNsYXNzIERhZW1vblBvbGxlciB7XG5cbiAgcHJvdGVjdGVkIGRhZW1vbjogTW9uZXJvRGFlbW9uUnBjO1xuICBwcm90ZWN0ZWQgbG9vcGVyOiBUYXNrTG9vcGVyO1xuICBwcm90ZWN0ZWQgaXNQb2xsaW5nOiBib29sZWFuO1xuICBwcm90ZWN0ZWQgbGFzdEhlYWRlcjogTW9uZXJvQmxvY2tIZWFkZXI7XG5cbiAgY29uc3RydWN0b3IoZGFlbW9uKSB7XG4gICAgbGV0IHRoYXQgPSB0aGlzO1xuICAgIHRoaXMuZGFlbW9uID0gZGFlbW9uO1xuICAgIHRoaXMubG9vcGVyID0gbmV3IFRhc2tMb29wZXIoYXN5bmMgZnVuY3Rpb24oKSB7IGF3YWl0IHRoYXQucG9sbCgpOyB9KTtcbiAgfVxuICBcbiAgc2V0SXNQb2xsaW5nKGlzUG9sbGluZzogYm9vbGVhbikge1xuICAgIHRoaXMuaXNQb2xsaW5nID0gaXNQb2xsaW5nO1xuICAgIGlmIChpc1BvbGxpbmcpIHRoaXMubG9vcGVyLnN0YXJ0KHRoaXMuZGFlbW9uLmdldFBvbGxJbnRlcnZhbCgpKTtcbiAgICBlbHNlIHRoaXMubG9vcGVyLnN0b3AoKTtcbiAgfVxuICBcbiAgYXN5bmMgcG9sbCgpIHtcbiAgICB0cnkge1xuICAgICAgXG4gICAgICAvLyBnZXQgbGF0ZXN0IGJsb2NrIGhlYWRlclxuICAgICAgbGV0IGhlYWRlciA9IGF3YWl0IHRoaXMuZGFlbW9uLmdldExhc3RCbG9ja0hlYWRlcigpO1xuICAgICAgXG4gICAgICAvLyBzYXZlIGZpcnN0IGhlYWRlciBmb3IgY29tcGFyaXNvblxuICAgICAgaWYgKCF0aGlzLmxhc3RIZWFkZXIpIHtcbiAgICAgICAgdGhpcy5sYXN0SGVhZGVyID0gYXdhaXQgdGhpcy5kYWVtb24uZ2V0TGFzdEJsb2NrSGVhZGVyKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gY29tcGFyZSBoZWFkZXIgdG8gbGFzdFxuICAgICAgaWYgKGhlYWRlci5nZXRIYXNoKCkgIT09IHRoaXMubGFzdEhlYWRlci5nZXRIYXNoKCkpIHtcbiAgICAgICAgdGhpcy5sYXN0SGVhZGVyID0gaGVhZGVyO1xuICAgICAgICBhd2FpdCB0aGlzLmFubm91bmNlQmxvY2tIZWFkZXIoaGVhZGVyKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoXCJGYWlsZWQgdG8gYmFja2dyb3VuZCBwb2xsIGRhZW1vbiBoZWFkZXJcIik7XG4gICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgfVxuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGFubm91bmNlQmxvY2tIZWFkZXIoaGVhZGVyOiBNb25lcm9CbG9ja0hlYWRlcikge1xuICAgIGZvciAobGV0IGxpc3RlbmVyIG9mIGF3YWl0IHRoaXMuZGFlbW9uLmdldExpc3RlbmVycygpKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBsaXN0ZW5lci5vbkJsb2NrSGVhZGVyKGhlYWRlcik7IC8vIG5vdGlmeSBsaXN0ZW5lclxuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBjYWxsaW5nIGxpc3RlbmVyIG9uIGJsb2NrIGhlYWRlclwiLCBlcnIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIEludGVybmFsIGxpc3RlbmVyIHRvIGJyaWRnZSBub3RpZmljYXRpb25zIHRvIGV4dGVybmFsIGxpc3RlbmVycy5cbiAqIFxuICogQHByaXZhdGVcbiAqL1xuY2xhc3MgRGFlbW9uV29ya2VyTGlzdGVuZXIge1xuXG4gIHByb3RlY3RlZCBpZDogYW55O1xuICBwcm90ZWN0ZWQgbGlzdGVuZXI6IGFueTtcblxuICBjb25zdHJ1Y3RvcihsaXN0ZW5lcikge1xuICAgIHRoaXMuaWQgPSBHZW5VdGlscy5nZXRVVUlEKCk7XG4gICAgdGhpcy5saXN0ZW5lciA9IGxpc3RlbmVyO1xuICB9XG4gIFxuICBnZXRJZCgpIHtcbiAgICByZXR1cm4gdGhpcy5pZDtcbiAgfVxuICBcbiAgZ2V0TGlzdGVuZXIoKSB7XG4gICAgcmV0dXJuIHRoaXMubGlzdGVuZXI7XG4gIH1cbiAgXG4gIGFzeW5jIG9uQmxvY2tIZWFkZXIoaGVhZGVySnNvbikge1xuICAgIHRoaXMubGlzdGVuZXIub25CbG9ja0hlYWRlcihuZXcgTW9uZXJvQmxvY2tIZWFkZXIoaGVhZGVySnNvbikpO1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IE1vbmVyb0RhZW1vblJwYztcbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFNBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLGFBQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFHLFdBQUEsR0FBQUosc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFJLGVBQUEsR0FBQUwsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFLLFVBQUEsR0FBQU4sc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFNLFlBQUEsR0FBQVAsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFPLGtCQUFBLEdBQUFSLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBUSxvQkFBQSxHQUFBVCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQVMscUJBQUEsR0FBQVYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFVLGFBQUEsR0FBQVgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFXLG1CQUFBLEdBQUFaLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBWSxpQkFBQSxHQUFBYixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQWEscUJBQUEsR0FBQWQsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFjLHFCQUFBLEdBQUFmLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBZSw4QkFBQSxH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 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/ConnectionType.d.ts b/dist/src/main/ts/daemon/model/ConnectionType.d.ts new file mode 100644 index 000000000..fe2ed62d2 --- /dev/null +++ b/dist/src/main/ts/daemon/model/ConnectionType.d.ts @@ -0,0 +1,28 @@ +/** + * Enumerates connection types. + * + * Based on enums.h in monero-project. + */ +declare enum ConnectionType { + /** + * Invalid connection type (value=0). + */ + INVALID = 0, + /** + * IPV4 connection type (value=1). + */ + IPV4 = 1, + /** + * IPV6 connection type (value=2). + */ + IPV6 = 2, + /** + * TOR connection type (value=3). + */ + TOR = 3, + /** + * I2P connection type (value=4). + */ + I2P = 4 +} +export default ConnectionType; diff --git a/dist/src/main/ts/daemon/model/ConnectionType.js b/dist/src/main/ts/daemon/model/ConnectionType.js new file mode 100644 index 000000000..8d3d50e7d --- /dev/null +++ b/dist/src/main/ts/daemon/model/ConnectionType.js @@ -0,0 +1,37 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; + +/** + * Enumerates connection types. + * + * Based on enums.h in monero-project. + */var +ConnectionType = /*#__PURE__*/function (ConnectionType) {ConnectionType[ConnectionType["INVALID"] = 0] = "INVALID";ConnectionType[ConnectionType["IPV4"] = 1] = "IPV4";ConnectionType[ConnectionType["IPV6"] = 2] = "IPV6";ConnectionType[ConnectionType["TOR"] = 3] = "TOR";ConnectionType[ConnectionType["I2P"] = 4] = "I2P";return ConnectionType;}(ConnectionType || {});var _default = exports.default = + + + + + + + + + + + + + + + + + + + + + + + + + + + +ConnectionType; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJDb25uZWN0aW9uVHlwZSIsIl9kZWZhdWx0IiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9kYWVtb24vbW9kZWwvQ29ubmVjdGlvblR5cGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5cbi8qKlxuICogRW51bWVyYXRlcyBjb25uZWN0aW9uIHR5cGVzLlxuICogXG4gKiBCYXNlZCBvbiBlbnVtcy5oIGluIG1vbmVyby1wcm9qZWN0LlxuICovXG5lbnVtIENvbm5lY3Rpb25UeXBlIHtcblxuICAvKipcbiAgICogSW52YWxpZCBjb25uZWN0aW9uIHR5cGUgKHZhbHVlPTApLlxuICAgKi9cbiAgSU5WQUxJRCA9IDAsXG5cbiAgLyoqXG4gICAqIElQVjQgY29ubmVjdGlvbiB0eXBlICh2YWx1ZT0xKS5cbiAgICovXG4gIElQVjQgPSAxLFxuXG4gIC8qKlxuICAgKiBJUFY2IGNvbm5lY3Rpb24gdHlwZSAodmFsdWU9MikuXG4gICAqL1xuICBJUFY2ID0gMixcblxuICAvKipcbiAgICogVE9SIGNvbm5lY3Rpb24gdHlwZSAodmFsdWU9MykuXG4gICAqL1xuICBUT1IgPSAzLFxuXG4gIC8qKlxuICAgKiBJMlAgY29ubmVjdGlvbiB0eXBlICh2YWx1ZT00KS5cbiAgICovXG4gIEkyUCA9IDRcbn1cblxuZXhwb3J0IGRlZmF1bHQgQ29ubmVjdGlvblR5cGU7Il0sIm1hcHBpbmdzIjoiOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FKQTtBQUtLQSxjQUFjLDBCQUFkQSxjQUFjLEdBQWRBLGNBQWMsQ0FBZEEsY0FBYyw2QkFBZEEsY0FBYyxDQUFkQSxjQUFjLHVCQUFkQSxjQUFjLENBQWRBLGNBQWMsdUJBQWRBLGNBQWMsQ0FBZEEsY0FBYyxxQkFBZEEsY0FBYyxDQUFkQSxjQUFjLDRCQUFkQSxjQUFjLEdBQWRBLGNBQWMsWUFBQUMsUUFBQSxHQUFBQyxPQUFBLENBQUFDLE9BQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUE0QkpILGNBQWMifQ== \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroAltChain.d.ts b/dist/src/main/ts/daemon/model/MoneroAltChain.d.ts new file mode 100644 index 000000000..0837419d1 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroAltChain.d.ts @@ -0,0 +1,22 @@ +/** + * Models an alternative chain seen by the node. + */ +export default class MoneroAltChain { + blockHashes: string[]; + difficulty: bigint; + height: number; + length: number; + mainChainParentBlockHash: string; + constructor(altChain?: Partial); + toJson(): any; + getBlockHashes(): string[]; + setBlockHashes(blockHashes: string[]): MoneroAltChain; + getDifficulty(): bigint; + setDifficulty(difficulty: bigint): MoneroAltChain; + getHeight(): number; + setHeight(height: number): MoneroAltChain; + getLength(): number; + setLength(length: number): MoneroAltChain; + getMainChainParentBlockHash(): string; + setMainChainParentBlockHash(mainChainParentBlockHash: string): MoneroAltChain; +} diff --git a/dist/src/main/ts/daemon/model/MoneroAltChain.js b/dist/src/main/ts/daemon/model/MoneroAltChain.js new file mode 100644 index 000000000..e704f81d1 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroAltChain.js @@ -0,0 +1,68 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Models an alternative chain seen by the node. + */ +class MoneroAltChain { + + + + + + + + constructor(altChain) { + Object.assign(this, altChain); + if (this.difficulty !== undefined && typeof this.difficulty !== "bigint") this.difficulty = BigInt(this.difficulty); + } + + toJson() { + let json = Object.assign({}, this); + if (this.getDifficulty() !== undefined) json.difficulty = this.getDifficulty().toString(); + return json; + } + + getBlockHashes() { + return this.blockHashes; + } + + setBlockHashes(blockHashes) { + this.blockHashes = blockHashes; + return this; + } + + getDifficulty() { + return this.difficulty; + } + + setDifficulty(difficulty) { + this.difficulty = difficulty; + return this; + } + + getHeight() { + return this.height; + } + + setHeight(height) { + this.height = height; + return this; + } + + getLength() { + return this.length; + } + + setLength(length) { + this.length = length; + return this; + } + + getMainChainParentBlockHash() { + return this.mainChainParentBlockHash; + } + + setMainChainParentBlockHash(mainChainParentBlockHash) { + this.mainChainParentBlockHash = mainChainParentBlockHash; + return this; + } +}exports.default = MoneroAltChain; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9BbHRDaGFpbiIsImNvbnN0cnVjdG9yIiwiYWx0Q2hhaW4iLCJPYmplY3QiLCJhc3NpZ24iLCJkaWZmaWN1bHR5IiwidW5kZWZpbmVkIiwiQmlnSW50IiwidG9Kc29uIiwianNvbiIsImdldERpZmZpY3VsdHkiLCJ0b1N0cmluZyIsImdldEJsb2NrSGFzaGVzIiwiYmxvY2tIYXNoZXMiLCJzZXRCbG9ja0hhc2hlcyIsInNldERpZmZpY3VsdHkiLCJnZXRIZWlnaHQiLCJoZWlnaHQiLCJzZXRIZWlnaHQiLCJnZXRMZW5ndGgiLCJsZW5ndGgiLCJzZXRMZW5ndGgiLCJnZXRNYWluQ2hhaW5QYXJlbnRCbG9ja0hhc2giLCJtYWluQ2hhaW5QYXJlbnRCbG9ja0hhc2giLCJzZXRNYWluQ2hhaW5QYXJlbnRCbG9ja0hhc2giLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2RhZW1vbi9tb2RlbC9Nb25lcm9BbHRDaGFpbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1vZGVscyBhbiBhbHRlcm5hdGl2ZSBjaGFpbiBzZWVuIGJ5IHRoZSBub2RlLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9BbHRDaGFpbiB7XG5cbiAgYmxvY2tIYXNoZXM6IHN0cmluZ1tdO1xuICBkaWZmaWN1bHR5OiBiaWdpbnQ7XG4gIGhlaWdodDogbnVtYmVyO1xuICBsZW5ndGg6IG51bWJlcjtcbiAgbWFpbkNoYWluUGFyZW50QmxvY2tIYXNoOiBzdHJpbmc7XG4gIFxuICBjb25zdHJ1Y3RvcihhbHRDaGFpbj86IFBhcnRpYWw8TW9uZXJvQWx0Q2hhaW4+KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCBhbHRDaGFpbik7XG4gICAgaWYgKHRoaXMuZGlmZmljdWx0eSAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLmRpZmZpY3VsdHkgIT09IFwiYmlnaW50XCIpIHRoaXMuZGlmZmljdWx0eSA9IEJpZ0ludCh0aGlzLmRpZmZpY3VsdHkpO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICBsZXQganNvbjogYW55ID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcyk7XG4gICAgaWYgKHRoaXMuZ2V0RGlmZmljdWx0eSgpICE9PSB1bmRlZmluZWQpIGpzb24uZGlmZmljdWx0eSA9IHRoaXMuZ2V0RGlmZmljdWx0eSgpLnRvU3RyaW5nKCk7XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIGdldEJsb2NrSGFzaGVzKCk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gdGhpcy5ibG9ja0hhc2hlcztcbiAgfVxuICBcbiAgc2V0QmxvY2tIYXNoZXMoYmxvY2tIYXNoZXM6IHN0cmluZ1tdKTogTW9uZXJvQWx0Q2hhaW4ge1xuICAgIHRoaXMuYmxvY2tIYXNoZXMgPSBibG9ja0hhc2hlcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0RGlmZmljdWx0eSgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLmRpZmZpY3VsdHk7XG4gIH1cbiAgXG4gIHNldERpZmZpY3VsdHkoZGlmZmljdWx0eTogYmlnaW50KTogTW9uZXJvQWx0Q2hhaW4ge1xuICAgIHRoaXMuZGlmZmljdWx0eSA9IGRpZmZpY3VsdHk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEhlaWdodCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmhlaWdodDtcbiAgfVxuICBcbiAgc2V0SGVpZ2h0KGhlaWdodDogbnVtYmVyKTogTW9uZXJvQWx0Q2hhaW4ge1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRMZW5ndGgoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5sZW5ndGg7XG4gIH1cbiAgXG4gIHNldExlbmd0aChsZW5ndGg6IG51bWJlcik6IE1vbmVyb0FsdENoYWluIHtcbiAgICB0aGlzLmxlbmd0aCA9IGxlbmd0aDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0TWFpbkNoYWluUGFyZW50QmxvY2tIYXNoKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMubWFpbkNoYWluUGFyZW50QmxvY2tIYXNoO1xuICB9XG4gIFxuICBzZXRNYWluQ2hhaW5QYXJlbnRCbG9ja0hhc2gobWFpbkNoYWluUGFyZW50QmxvY2tIYXNoOiBzdHJpbmcpOiBNb25lcm9BbHRDaGFpbiB7XG4gICAgdGhpcy5tYWluQ2hhaW5QYXJlbnRCbG9ja0hhc2ggPSBtYWluQ2hhaW5QYXJlbnRCbG9ja0hhc2g7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InFHQUFBO0FBQ0E7QUFDQTtBQUNlLE1BQU1BLGNBQWMsQ0FBQzs7Ozs7Ozs7RUFRbENDLFdBQVdBLENBQUNDLFFBQWtDLEVBQUU7SUFDOUNDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsUUFBUSxDQUFDO0lBQzdCLElBQUksSUFBSSxDQUFDRyxVQUFVLEtBQUtDLFNBQVMsSUFBSSxPQUFPLElBQUksQ0FBQ0QsVUFBVSxLQUFLLFFBQVEsRUFBRSxJQUFJLENBQUNBLFVBQVUsR0FBR0UsTUFBTSxDQUFDLElBQUksQ0FBQ0YsVUFBVSxDQUFDO0VBQ3JIOztFQUVBRyxNQUFNQSxDQUFBLEVBQVE7SUFDWixJQUFJQyxJQUFTLEdBQUdOLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQztJQUN2QyxJQUFJLElBQUksQ0FBQ00sYUFBYSxDQUFDLENBQUMsS0FBS0osU0FBUyxFQUFFRyxJQUFJLENBQUNKLFVBQVUsR0FBRyxJQUFJLENBQUNLLGFBQWEsQ0FBQyxDQUFDLENBQUNDLFFBQVEsQ0FBQyxDQUFDO0lBQ3pGLE9BQU9GLElBQUk7RUFDYjs7RUFFQUcsY0FBY0EsQ0FBQSxFQUFhO0lBQ3pCLE9BQU8sSUFBSSxDQUFDQyxXQUFXO0VBQ3pCOztFQUVBQyxjQUFjQSxDQUFDRCxXQUFxQixFQUFrQjtJQUNwRCxJQUFJLENBQUNBLFdBQVcsR0FBR0EsV0FBVztJQUM5QixPQUFPLElBQUk7RUFDYjs7RUFFQUgsYUFBYUEsQ0FBQSxFQUFXO0lBQ3RCLE9BQU8sSUFBSSxDQUFDTCxVQUFVO0VBQ3hCOztFQUVBVSxhQUFhQSxDQUFDVixVQUFrQixFQUFrQjtJQUNoRCxJQUFJLENBQUNBLFVBQVUsR0FBR0EsVUFBVTtJQUM1QixPQUFPLElBQUk7RUFDYjs7RUFFQVcsU0FBU0EsQ0FBQSxFQUFXO0lBQ2xCLE9BQU8sSUFBSSxDQUFDQyxNQUFNO0VBQ3BCOztFQUVBQyxTQUFTQSxDQUFDRCxNQUFjLEVBQWtCO0lBQ3hDLElBQUksQ0FBQ0EsTUFBTSxHQUFHQSxNQUFNO0lBQ3BCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxTQUFTQSxDQUFBLEVBQVc7SUFDbEIsT0FBTyxJQUFJLENBQUNDLE1BQU07RUFDcEI7O0VBRUFDLFNBQVNBLENBQUNELE1BQWMsRUFBa0I7SUFDeEMsSUFBSSxDQUFDQSxNQUFNLEdBQUdBLE1BQU07SUFDcEIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLDJCQUEyQkEsQ0FBQSxFQUFXO0lBQ3BDLE9BQU8sSUFBSSxDQUFDQyx3QkFBd0I7RUFDdEM7O0VBRUFDLDJCQUEyQkEsQ0FBQ0Qsd0JBQWdDLEVBQWtCO0lBQzVFLElBQUksQ0FBQ0Esd0JBQXdCLEdBQUdBLHdCQUF3QjtJQUN4RCxPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNFLE9BQUEsQ0FBQUMsT0FBQSxHQUFBMUIsY0FBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroBan.d.ts b/dist/src/main/ts/daemon/model/MoneroBan.d.ts new file mode 100644 index 000000000..0fad01f52 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroBan.d.ts @@ -0,0 +1,19 @@ +/** + * Monero banhammer. + */ +export default class MoneroBan { + host: string; + ip: string; + isBanned: boolean; + seconds: number; + constructor(ban?: Partial); + toJson(): any; + getHost(): string; + setHost(host: string): MoneroBan; + getIp(): string; + setIp(ip: string): MoneroBan; + getIsBanned(): boolean; + setIsBanned(isBanned: boolean): MoneroBan; + getSeconds(): number; + setSeconds(seconds: number): MoneroBan; +} diff --git a/dist/src/main/ts/daemon/model/MoneroBan.js b/dist/src/main/ts/daemon/model/MoneroBan.js new file mode 100644 index 000000000..068955623 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroBan.js @@ -0,0 +1,55 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Monero banhammer. + */ +class MoneroBan { + + + + + + + constructor(ban) { + Object.assign(this, ban); + } + + toJson() { + return Object.assign({}, this); + } + + getHost() { + return this.host; + } + + setHost(host) { + this.host = host; + return this; + } + + getIp() { + return this.ip; + } + + setIp(ip) { + this.ip = ip; + return this; + } + + getIsBanned() { + return this.isBanned; + } + + setIsBanned(isBanned) { + this.isBanned = isBanned; + return this; + } + + getSeconds() { + return this.seconds; + } + + setSeconds(seconds) { + this.seconds = seconds; + return this; + } +}exports.default = MoneroBan; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9CYW4iLCJjb25zdHJ1Y3RvciIsImJhbiIsIk9iamVjdCIsImFzc2lnbiIsInRvSnNvbiIsImdldEhvc3QiLCJob3N0Iiwic2V0SG9zdCIsImdldElwIiwiaXAiLCJzZXRJcCIsImdldElzQmFubmVkIiwiaXNCYW5uZWQiLCJzZXRJc0Jhbm5lZCIsImdldFNlY29uZHMiLCJzZWNvbmRzIiwic2V0U2Vjb25kcyIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvZGFlbW9uL21vZGVsL01vbmVyb0Jhbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1vbmVybyBiYW5oYW1tZXIuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0JhbiB7XG5cbiAgaG9zdDogc3RyaW5nO1xuICBpcDogc3RyaW5nO1xuICBpc0Jhbm5lZDogYm9vbGVhbjtcbiAgc2Vjb25kczogbnVtYmVyO1xuICBcbiAgY29uc3RydWN0b3IoYmFuPzogUGFydGlhbDxNb25lcm9CYW4+KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCBiYW4pO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7fSwgdGhpcyk7XG4gIH1cbiAgXG4gIGdldEhvc3QoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5ob3N0O1xuICB9XG4gIFxuICBzZXRIb3N0KGhvc3Q6IHN0cmluZyk6IE1vbmVyb0JhbiB7XG4gICAgdGhpcy5ob3N0ID0gaG9zdDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0SXAoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5pcDtcbiAgfVxuICBcbiAgc2V0SXAoaXA6IHN0cmluZyk6IE1vbmVyb0JhbiB7XG4gICAgdGhpcy5pcCA9IGlwO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRJc0Jhbm5lZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc0Jhbm5lZDtcbiAgfVxuICBcbiAgc2V0SXNCYW5uZWQoaXNCYW5uZWQ6IGJvb2xlYW4pOiBNb25lcm9CYW4ge1xuICAgIHRoaXMuaXNCYW5uZWQgPSBpc0Jhbm5lZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U2Vjb25kcygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnNlY29uZHM7XG4gIH1cbiAgXG4gIHNldFNlY29uZHMoc2Vjb25kczogbnVtYmVyKTogTW9uZXJvQmFuIHtcbiAgICB0aGlzLnNlY29uZHMgPSBzZWNvbmRzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJxR0FBQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSxTQUFTLENBQUM7Ozs7Ozs7RUFPN0JDLFdBQVdBLENBQUNDLEdBQXdCLEVBQUU7SUFDcENDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsR0FBRyxDQUFDO0VBQzFCOztFQUVBRyxNQUFNQSxDQUFBLEVBQVE7SUFDWixPQUFPRixNQUFNLENBQUNDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUM7RUFDaEM7O0VBRUFFLE9BQU9BLENBQUEsRUFBVztJQUNoQixPQUFPLElBQUksQ0FBQ0MsSUFBSTtFQUNsQjs7RUFFQUMsT0FBT0EsQ0FBQ0QsSUFBWSxFQUFhO0lBQy9CLElBQUksQ0FBQ0EsSUFBSSxHQUFHQSxJQUFJO0lBQ2hCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxLQUFLQSxDQUFBLEVBQVc7SUFDZCxPQUFPLElBQUksQ0FBQ0MsRUFBRTtFQUNoQjs7RUFFQUMsS0FBS0EsQ0FBQ0QsRUFBVSxFQUFhO0lBQzNCLElBQUksQ0FBQ0EsRUFBRSxHQUFHQSxFQUFFO0lBQ1osT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLFdBQVdBLENBQUEsRUFBWTtJQUNyQixPQUFPLElBQUksQ0FBQ0MsUUFBUTtFQUN0Qjs7RUFFQUMsV0FBV0EsQ0FBQ0QsUUFBaUIsRUFBYTtJQUN4QyxJQUFJLENBQUNBLFFBQVEsR0FBR0EsUUFBUTtJQUN4QixPQUFPLElBQUk7RUFDYjs7RUFFQUUsVUFBVUEsQ0FBQSxFQUFXO0lBQ25CLE9BQU8sSUFBSSxDQUFDQyxPQUFPO0VBQ3JCOztFQUVBQyxVQUFVQSxDQUFDRCxPQUFlLEVBQWE7SUFDckMsSUFBSSxDQUFDQSxPQUFPLEdBQUdBLE9BQU87SUFDdEIsT0FBTyxJQUFJO0VBQ2I7QUFDRixDQUFDRSxPQUFBLENBQUFDLE9BQUEsR0FBQW5CLFNBQUEifQ== \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroBlock.d.ts b/dist/src/main/ts/daemon/model/MoneroBlock.d.ts new file mode 100644 index 000000000..92e304789 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroBlock.d.ts @@ -0,0 +1,53 @@ +import MoneroBlockHeader from "./MoneroBlockHeader"; +import MoneroTx from "./MoneroTx"; +/** + * Enumerates types to deserialize to. + */ +declare enum DeserializationType { + TX = 0, + TX_WALLET = 1, + TX_QUERY = 2 +} +/** + * Models a Monero block in the blockchain. + */ +export default class MoneroBlock extends MoneroBlockHeader { + static DeserializationType: typeof DeserializationType; + hex: string; + minerTx: MoneroTx; + txs: MoneroTx[]; + txHashes: string[]; + constructor(block?: Partial, txType?: DeserializationType); + getHex(): string; + setHex(hex: string): MoneroBlock; + getMinerTx(): MoneroTx; + setMinerTx(minerTx: MoneroTx): MoneroBlock; + getTxs(): MoneroTx[]; + setTxs(txs: MoneroTx[]): MoneroBlock; + getTxHashes(): string[]; + setTxHashes(txHashes: string[]): MoneroBlock; + copy(): MoneroBlock; + toJson(): any; + merge(block: MoneroBlock): MoneroBlock; + toString(indent?: number): string; + protected static mergeTx(txs: any, tx: any): void; + setHeight(height: number): MoneroBlock; + setTimestamp(timestamp: number): MoneroBlock; + setSize(size: number): MoneroBlock; + setWeight(weight: number): MoneroBlock; + setLongTermWeight(longTermWeight: number): MoneroBlock; + setDepth(depth: number): MoneroBlock; + setDifficulty(difficulty: bigint): MoneroBlock; + setCumulativeDifficulty(cumulativeDifficulty: bigint): MoneroBlock; + setMajorVersion(majorVersion: number): MoneroBlock; + setMinorVersion(minorVersion: number): MoneroBlock; + setNonce(nonce: number): MoneroBlock; + setMinerTxHash(minerTxHash: string): MoneroBlock; + setNumTxs(numTxs: number): MoneroBlock; + setOrphanStatus(orphanStatus: boolean): MoneroBlock; + setPrevHash(prevHash: string): MoneroBlock; + setReward(reward: bigint): MoneroBlock; + setPowHash(powHash: string): MoneroBlock; + protected deserializeTx(tx: any, txType?: DeserializationType): MoneroTx; +} +export {}; diff --git a/dist/src/main/ts/daemon/model/MoneroBlock.js b/dist/src/main/ts/daemon/model/MoneroBlock.js new file mode 100644 index 000000000..7f7eb00b7 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroBlock.js @@ -0,0 +1,255 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); +var _MoneroBlockHeader = _interopRequireDefault(require("./MoneroBlockHeader")); +var _MoneroTx = _interopRequireDefault(require("./MoneroTx")); +var _MoneroTxQuery = _interopRequireDefault(require("../../wallet/model/MoneroTxQuery")); +var _MoneroTxWallet = _interopRequireDefault(require("../../wallet/model/MoneroTxWallet")); + +/** + * Enumerates types to deserialize to. + */var +DeserializationType = /*#__PURE__*/function (DeserializationType) {DeserializationType[DeserializationType["TX"] = 0] = "TX";DeserializationType[DeserializationType["TX_WALLET"] = 1] = "TX_WALLET";DeserializationType[DeserializationType["TX_QUERY"] = 2] = "TX_QUERY";return DeserializationType;}(DeserializationType || {}); + + + + + +/** + * Models a Monero block in the blockchain. + */ +class MoneroBlock extends _MoneroBlockHeader.default { + + static DeserializationType = DeserializationType; + + + + + + + constructor(block, txType) { + super(block); + + // copy miner tx + if (this.minerTx) { + this.minerTx = this.deserializeTx(this.minerTx, txType).setBlock(this); + } + + // copy non-miner txs + if (this.txs) { + this.txs = this.txs.slice(); + for (let i = 0; i < this.txs.length; i++) { + this.txs[i] = this.deserializeTx(this.txs[i], txType).setBlock(this); + } + } + } + + getHex() { + return this.hex; + } + + setHex(hex) { + this.hex = hex; + return this; + } + + getMinerTx() { + return this.minerTx; + } + + setMinerTx(minerTx) { + this.minerTx = minerTx; + return this; + } + + getTxs() { + return this.txs; + } + + setTxs(txs) { + this.txs = txs; + return this; + } + + getTxHashes() { + return this.txHashes; + } + + setTxHashes(txHashes) { + this.txHashes = txHashes; + return this; + } + + copy() { + return new MoneroBlock(this); + } + + toJson() { + let json = super.toJson(); + if (this.getMinerTx() !== undefined) json.minerTx = this.getMinerTx().toJson(); + if (this.getTxs() !== undefined) { + json.txs = []; + for (let tx of this.getTxs()) json.txs.push(tx.toJson()); + } + return json; + } + + merge(block) { + (0, _assert.default)(block instanceof MoneroBlock); + if (this === block) return this; + + // merge header fields + super.merge(block); + + // merge reconcilable block extensions + this.setHex(_GenUtils.default.reconcile(this.getHex(), block.getHex())); + this.setTxHashes(_GenUtils.default.reconcile(this.getTxHashes(), block.getTxHashes())); + + // merge miner tx + if (this.getMinerTx() === undefined) this.setMinerTx(block.getMinerTx()); + if (block.getMinerTx() !== undefined) { + block.getMinerTx().setBlock(this); + this.getMinerTx().merge(block.getMinerTx()); + } + + // merge non-miner txs + if (block.getTxs() !== undefined) { + for (let tx of block.getTxs()) { + tx.setBlock(this); + MoneroBlock.mergeTx(this.getTxs(), tx); + } + } + + return this; + } + + toString(indent = 0) { + let str = super.toString(indent) + "\n"; + str += _GenUtils.default.kvLine("Hex", this.getHex(), indent); + if (this.getTxs() !== undefined) { + str += _GenUtils.default.kvLine("Txs", "", indent); + for (let tx of this.getTxs()) { + str += tx.toString(indent + 1) + "\n"; + } + } + if (this.getMinerTx() !== undefined) { + str += _GenUtils.default.kvLine("Miner tx", "", indent); + str += this.getMinerTx().toString(indent + 1) + "\n"; + } + str += _GenUtils.default.kvLine("Txs hashes", this.getTxHashes(), indent); + return str[str.length - 1] === "\n" ? str.slice(0, str.length - 1) : str; // strip last newline + } + + // helper to merge txs + static mergeTx(txs, tx) { + for (let aTx of txs) { + if (aTx.getHash() === tx.getHash()) { + aTx.merge(tx); + return; + } + } + txs.push(tx); + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setHeight(height) { + super.setHeight(height); + return this; + } + + setTimestamp(timestamp) { + super.setTimestamp(timestamp); + return this; + } + + setSize(size) { + super.setSize(size); + return this; + } + + setWeight(weight) { + super.setWeight(weight); + return this; + } + + setLongTermWeight(longTermWeight) { + super.setLongTermWeight(longTermWeight); + return this; + } + + setDepth(depth) { + super.setDepth(depth); + return this; + } + + setDifficulty(difficulty) { + super.setDifficulty(difficulty); + return this; + } + + setCumulativeDifficulty(cumulativeDifficulty) { + super.setCumulativeDifficulty(cumulativeDifficulty); + return this; + } + + setMajorVersion(majorVersion) { + super.setMajorVersion(majorVersion); + return this; + } + + setMinorVersion(minorVersion) { + super.setMinorVersion(minorVersion); + return this; + } + + setNonce(nonce) { + super.setNonce(nonce); + return this; + } + + setMinerTxHash(minerTxHash) { + super.setMinerTxHash(minerTxHash); + return this; + } + + setNumTxs(numTxs) { + super.setNumTxs(numTxs); + return this; + } + + setOrphanStatus(orphanStatus) { + super.setOrphanStatus(orphanStatus); + return this; + } + + setPrevHash(prevHash) { + super.setPrevHash(prevHash); + return this; + } + + setReward(reward) { + super.setReward(reward); + return this; + } + + setPowHash(powHash) { + super.setPowHash(powHash); + return this; + } + + deserializeTx(tx, txType) { + if (txType === undefined) { + if (!(tx instanceof _MoneroTx.default)) throw new Error("Must provide DeserializationType if tx is not instanceof MoneroTx"); + return tx.copy(); + } else if (txType === MoneroBlock.DeserializationType.TX || txType === undefined) { + return new _MoneroTx.default(tx); + } else if (txType === MoneroBlock.DeserializationType.TX_WALLET) { + return new _MoneroTxWallet.default(tx); + } else if (txType === MoneroBlock.DeserializationType.TX_QUERY) { + return new _MoneroTxQuery.default(tx); + } else { + throw new Error("Unrecognized tx deserialization type: " + txType); + } + } +}exports.default = MoneroBlock; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTW9uZXJvQmxvY2tIZWFkZXIiLCJfTW9uZXJvVHgiLCJfTW9uZXJvVHhRdWVyeSIsIl9Nb25lcm9UeFdhbGxldCIsIkRlc2VyaWFsaXphdGlvblR5cGUiLCJNb25lcm9CbG9jayIsIk1vbmVyb0Jsb2NrSGVhZGVyIiwiY29uc3RydWN0b3IiLCJibG9jayIsInR4VHlwZSIsIm1pbmVyVHgiLCJkZXNlcmlhbGl6ZVR4Iiwic2V0QmxvY2siLCJ0eHMiLCJzbGljZSIsImkiLCJsZW5ndGgiLCJnZXRIZXgiLCJoZXgiLCJzZXRIZXgiLCJnZXRNaW5lclR4Iiwic2V0TWluZXJUeCIsImdldFR4cyIsInNldFR4cyIsImdldFR4SGFzaGVzIiwidHhIYXNoZXMiLCJzZXRUeEhhc2hlcyIsImNvcHkiLCJ0b0pzb24iLCJqc29uIiwidW5kZWZpbmVkIiwidHgiLCJwdXNoIiwibWVyZ2UiLCJhc3NlcnQiLCJHZW5VdGlscyIsInJlY29uY2lsZSIsIm1lcmdlVHgiLCJ0b1N0cmluZyIsImluZGVudCIsInN0ciIsImt2TGluZSIsImFUeCIsImdldEhhc2giLCJzZXRIZWlnaHQiLCJoZWlnaHQiLCJzZXRUaW1lc3RhbXAiLCJ0aW1lc3RhbXAiLCJzZXRTaXplIiwic2l6ZSIsInNldFdlaWdodCIsIndlaWdodCIsInNldExvbmdUZXJtV2VpZ2h0IiwibG9uZ1Rlcm1XZWlnaHQiLCJzZXREZXB0aCIsImRlcHRoIiwic2V0RGlmZmljdWx0eSIsImRpZmZpY3VsdHkiLCJzZXRDdW11bGF0aXZlRGlmZmljdWx0eSIsImN1bXVsYXRpdmVEaWZmaWN1bHR5Iiwic2V0TWFqb3JWZXJzaW9uIiwibWFqb3JWZXJzaW9uIiwic2V0TWlub3JWZXJzaW9uIiwibWlub3JWZXJzaW9uIiwic2V0Tm9uY2UiLCJub25jZSIsInNldE1pbmVyVHhIYXNoIiwibWluZXJUeEhhc2giLCJzZXROdW1UeHMiLCJudW1UeHMiLCJzZXRPcnBoYW5TdGF0dXMiLCJvcnBoYW5TdGF0dXMiLCJzZXRQcmV2SGFzaCIsInByZXZIYXNoIiwic2V0UmV3YXJkIiwicmV3YXJkIiwic2V0UG93SGFzaCIsInBvd0hhc2giLCJNb25lcm9UeCIsIkVycm9yIiwiVFgiLCJUWF9XQUxMRVQiLCJNb25lcm9UeFdhbGxldCIsIlRYX1FVRVJZIiwiTW9uZXJvVHhRdWVyeSIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvZGFlbW9uL21vZGVsL01vbmVyb0Jsb2NrLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IEdlblV0aWxzIGZyb20gXCIuLi8uLi9jb21tb24vR2VuVXRpbHNcIjtcbmltcG9ydCBNb25lcm9CbG9ja0hlYWRlciBmcm9tIFwiLi9Nb25lcm9CbG9ja0hlYWRlclwiO1xuaW1wb3J0IE1vbmVyb1R4IGZyb20gXCIuL01vbmVyb1R4XCI7XG5pbXBvcnQgTW9uZXJvVHhRdWVyeSBmcm9tIFwiLi4vLi4vd2FsbGV0L21vZGVsL01vbmVyb1R4UXVlcnlcIjtcbmltcG9ydCBNb25lcm9UeFdhbGxldCBmcm9tIFwiLi4vLi4vd2FsbGV0L21vZGVsL01vbmVyb1R4V2FsbGV0XCI7XG5cbi8qKlxuICogRW51bWVyYXRlcyB0eXBlcyB0byBkZXNlcmlhbGl6ZSB0by5cbiAqL1xuZW51bSBEZXNlcmlhbGl6YXRpb25UeXBlIHtcbiAgVFggPSAwLFxuICBUWF9XQUxMRVQgPSAxLFxuICBUWF9RVUVSWSA9IDJcbn1cblxuLyoqXG4gKiBNb2RlbHMgYSBNb25lcm8gYmxvY2sgaW4gdGhlIGJsb2NrY2hhaW4uXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0Jsb2NrIGV4dGVuZHMgTW9uZXJvQmxvY2tIZWFkZXIge1xuXG4gIHN0YXRpYyBEZXNlcmlhbGl6YXRpb25UeXBlID0gRGVzZXJpYWxpemF0aW9uVHlwZTtcblxuICBoZXg6IHN0cmluZztcbiAgbWluZXJUeDogTW9uZXJvVHg7XG4gIHR4czogTW9uZXJvVHhbXTtcbiAgdHhIYXNoZXM6IHN0cmluZ1tdO1xuXG4gIGNvbnN0cnVjdG9yKGJsb2NrPzogUGFydGlhbDxNb25lcm9CbG9jaz4sIHR4VHlwZT86IERlc2VyaWFsaXphdGlvblR5cGUpIHtcbiAgICBzdXBlcihibG9jayk7XG4gICAgXG4gICAgLy8gY29weSBtaW5lciB0eFxuICAgIGlmICh0aGlzLm1pbmVyVHgpIHtcbiAgICAgIHRoaXMubWluZXJUeCA9IHRoaXMuZGVzZXJpYWxpemVUeCh0aGlzLm1pbmVyVHgsIHR4VHlwZSkuc2V0QmxvY2sodGhpcyk7XG4gICAgfVxuICAgIFxuICAgIC8vIGNvcHkgbm9uLW1pbmVyIHR4c1xuICAgIGlmICh0aGlzLnR4cykge1xuICAgICAgdGhpcy50eHMgPSB0aGlzLnR4cy5zbGljZSgpO1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnR4cy5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzLnR4c1tpXSA9IHRoaXMuZGVzZXJpYWxpemVUeCh0aGlzLnR4c1tpXSwgdHhUeXBlKS5zZXRCbG9jayh0aGlzKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBnZXRIZXgoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5oZXg7XG4gIH1cbiAgXG4gIHNldEhleChoZXg6IHN0cmluZyk6IE1vbmVyb0Jsb2NrIHtcbiAgICB0aGlzLmhleCA9IGhleDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0TWluZXJUeCgpOiBNb25lcm9UeCB7XG4gICAgcmV0dXJuIHRoaXMubWluZXJUeDtcbiAgfVxuICBcbiAgc2V0TWluZXJUeChtaW5lclR4OiBNb25lcm9UeCk6IE1vbmVyb0Jsb2NrIHtcbiAgICB0aGlzLm1pbmVyVHggPSBtaW5lclR4O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRUeHMoKTogTW9uZXJvVHhbXSB7XG4gICAgcmV0dXJuIHRoaXMudHhzO1xuICB9XG4gIFxuICBzZXRUeHModHhzOiBNb25lcm9UeFtdKTogTW9uZXJvQmxvY2sge1xuICAgIHRoaXMudHhzID0gdHhzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRUeEhhc2hlcygpOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIHRoaXMudHhIYXNoZXM7XG4gIH1cbiAgXG4gIHNldFR4SGFzaGVzKHR4SGFzaGVzOiBzdHJpbmdbXSk6IE1vbmVyb0Jsb2NrIHtcbiAgICB0aGlzLnR4SGFzaGVzID0gdHhIYXNoZXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGNvcHkoKTogTW9uZXJvQmxvY2sge1xuICAgIHJldHVybiBuZXcgTW9uZXJvQmxvY2sodGhpcyk7XG4gIH1cbiAgXG4gIHRvSnNvbigpOiBhbnkge1xuICAgIGxldCBqc29uID0gc3VwZXIudG9Kc29uKCk7XG4gICAgaWYgKHRoaXMuZ2V0TWluZXJUeCgpICE9PSB1bmRlZmluZWQpIGpzb24ubWluZXJUeCA9IHRoaXMuZ2V0TWluZXJUeCgpLnRvSnNvbigpO1xuICAgIGlmICh0aGlzLmdldFR4cygpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGpzb24udHhzID0gW107XG4gICAgICBmb3IgKGxldCB0eCBvZiB0aGlzLmdldFR4cygpKSBqc29uLnR4cy5wdXNoKHR4LnRvSnNvbigpKTtcbiAgICB9XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIG1lcmdlKGJsb2NrOiBNb25lcm9CbG9jayk6IE1vbmVyb0Jsb2NrIHtcbiAgICBhc3NlcnQoYmxvY2sgaW5zdGFuY2VvZiBNb25lcm9CbG9jayk7XG4gICAgaWYgKHRoaXMgPT09IGJsb2NrKSByZXR1cm4gdGhpcztcbiAgICBcbiAgICAvLyBtZXJnZSBoZWFkZXIgZmllbGRzXG4gICAgc3VwZXIubWVyZ2UoYmxvY2spO1xuICAgIFxuICAgIC8vIG1lcmdlIHJlY29uY2lsYWJsZSBibG9jayBleHRlbnNpb25zXG4gICAgdGhpcy5zZXRIZXgoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0SGV4KCksIGJsb2NrLmdldEhleCgpKSk7XG4gICAgdGhpcy5zZXRUeEhhc2hlcyhHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRUeEhhc2hlcygpLCBibG9jay5nZXRUeEhhc2hlcygpKSk7XG4gICAgXG4gICAgLy8gbWVyZ2UgbWluZXIgdHhcbiAgICBpZiAodGhpcy5nZXRNaW5lclR4KCkgPT09IHVuZGVmaW5lZCkgdGhpcy5zZXRNaW5lclR4KGJsb2NrLmdldE1pbmVyVHgoKSk7XG4gICAgaWYgKGJsb2NrLmdldE1pbmVyVHgoKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBibG9jay5nZXRNaW5lclR4KCkuc2V0QmxvY2sodGhpcyk7XG4gICAgICB0aGlzLmdldE1pbmVyVHgoKS5tZXJnZShibG9jay5nZXRNaW5lclR4KCkpO1xuICAgIH1cbiAgICBcbiAgICAvLyBtZXJnZSBub24tbWluZXIgdHhzXG4gICAgaWYgKGJsb2NrLmdldFR4cygpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGZvciAobGV0IHR4IG9mIGJsb2NrLmdldFR4cygpKSB7XG4gICAgICAgIHR4LnNldEJsb2NrKHRoaXMpO1xuICAgICAgICBNb25lcm9CbG9jay5tZXJnZVR4KHRoaXMuZ2V0VHhzKCksIHR4KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgdG9TdHJpbmcoaW5kZW50ID0gMCk6IHN0cmluZyB7XG4gICAgbGV0IHN0ciA9IHN1cGVyLnRvU3RyaW5nKGluZGVudCkgKyBcIlxcblwiO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJIZXhcIiwgdGhpcy5nZXRIZXgoKSwgaW5kZW50KTtcbiAgICBpZiAodGhpcy5nZXRUeHMoKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiVHhzXCIsIFwiXCIsIGluZGVudCk7XG4gICAgICBmb3IgKGxldCB0eCBvZiB0aGlzLmdldFR4cygpKSB7XG4gICAgICAgIHN0ciArPSB0eC50b1N0cmluZyhpbmRlbnQgKyAxKSArIFwiXFxuXCI7XG4gICAgICB9XG4gICAgfVxuICAgIGlmICh0aGlzLmdldE1pbmVyVHgoKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiTWluZXIgdHhcIiwgXCJcIiwgaW5kZW50KTtcbiAgICAgIHN0ciArPSB0aGlzLmdldE1pbmVyVHgoKS50b1N0cmluZyhpbmRlbnQgKyAxKSArIFwiXFxuXCI7XG4gICAgfVxuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJUeHMgaGFzaGVzXCIsIHRoaXMuZ2V0VHhIYXNoZXMoKSwgaW5kZW50KTtcbiAgICByZXR1cm4gc3RyW3N0ci5sZW5ndGggLSAxXSA9PT0gXCJcXG5cIiA/IHN0ci5zbGljZSgwLCBzdHIubGVuZ3RoIC0gMSkgOiBzdHIgIC8vIHN0cmlwIGxhc3QgbmV3bGluZVxuICB9XG4gIFxuICAvLyBoZWxwZXIgdG8gbWVyZ2UgdHhzXG4gIHByb3RlY3RlZCBzdGF0aWMgbWVyZ2VUeCh0eHMsIHR4KSB7XG4gICAgZm9yIChsZXQgYVR4IG9mIHR4cykge1xuICAgICAgaWYgKGFUeC5nZXRIYXNoKCkgPT09IHR4LmdldEhhc2goKSkge1xuICAgICAgICBhVHgubWVyZ2UodHgpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuICAgIHR4cy5wdXNoKHR4KTtcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tIE9WRVJSSURFIENPVkFSSUFOVCBSRVRVUk4gVFlQRVMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgc2V0SGVpZ2h0KGhlaWdodDogbnVtYmVyKTogTW9uZXJvQmxvY2sge1xuICAgIHN1cGVyLnNldEhlaWdodChoZWlnaHQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBzZXRUaW1lc3RhbXAodGltZXN0YW1wOiBudW1iZXIpOiBNb25lcm9CbG9jayB7XG4gICAgc3VwZXIuc2V0VGltZXN0YW1wKHRpbWVzdGFtcCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHNldFNpemUoc2l6ZTogbnVtYmVyKTogTW9uZXJvQmxvY2sge1xuICAgIHN1cGVyLnNldFNpemUoc2l6ZSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHNldFdlaWdodCh3ZWlnaHQ6IG51bWJlcik6IE1vbmVyb0Jsb2NrIHtcbiAgICBzdXBlci5zZXRXZWlnaHQod2VpZ2h0KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgc2V0TG9uZ1Rlcm1XZWlnaHQobG9uZ1Rlcm1XZWlnaHQ6IG51bWJlcik6IE1vbmVyb0Jsb2NrIHtcbiAgICBzdXBlci5zZXRMb25nVGVybVdlaWdodChsb25nVGVybVdlaWdodCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHNldERlcHRoKGRlcHRoOiBudW1iZXIpOiBNb25lcm9CbG9jayB7XG4gICAgc3VwZXIuc2V0RGVwdGgoZGVwdGgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBzZXREaWZmaWN1bHR5KGRpZmZpY3VsdHk6IGJpZ2ludCk6IE1vbmVyb0Jsb2NrIHtcbiAgICBzdXBlci5zZXREaWZmaWN1bHR5KGRpZmZpY3VsdHkpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBzZXRDdW11bGF0aXZlRGlmZmljdWx0eShjdW11bGF0aXZlRGlmZmljdWx0eTogYmlnaW50KTogTW9uZXJvQmxvY2sge1xuICAgIHN1cGVyLnNldEN1bXVsYXRpdmVEaWZmaWN1bHR5KGN1bXVsYXRpdmVEaWZmaWN1bHR5KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgc2V0TWFqb3JWZXJzaW9uKG1ham9yVmVyc2lvbjogbnVtYmVyKTogTW9uZXJvQmxvY2sge1xuICAgIHN1cGVyLnNldE1ham9yVmVyc2lvbihtYWpvclZlcnNpb24pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBzZXRNaW5vclZlcnNpb24obWlub3JWZXJzaW9uOiBudW1iZXIpOiBNb25lcm9CbG9jayB7XG4gICAgc3VwZXIuc2V0TWlub3JWZXJzaW9uKG1pbm9yVmVyc2lvbik7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHNldE5vbmNlKG5vbmNlOiBudW1iZXIpOiBNb25lcm9CbG9jayB7XG4gICAgc3VwZXIuc2V0Tm9uY2Uobm9uY2UpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBzZXRNaW5lclR4SGFzaChtaW5lclR4SGFzaDogc3RyaW5nKTogTW9uZXJvQmxvY2sge1xuICAgIHN1cGVyLnNldE1pbmVyVHhIYXNoKG1pbmVyVHhIYXNoKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgc2V0TnVtVHhzKG51bVR4czogbnVtYmVyKTogTW9uZXJvQmxvY2sge1xuICAgIHN1cGVyLnNldE51bVR4cyhudW1UeHMpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBzZXRPcnBoYW5TdGF0dXMob3JwaGFuU3RhdHVzOiBib29sZWFuKTogTW9uZXJvQmxvY2sge1xuICAgIHN1cGVyLnNldE9ycGhhblN0YXR1cyhvcnBoYW5TdGF0dXMpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBzZXRQcmV2SGFzaChwcmV2SGFzaDogc3RyaW5nKTogTW9uZXJvQmxvY2sge1xuICAgIHN1cGVyLnNldFByZXZIYXNoKHByZXZIYXNoKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgc2V0UmV3YXJkKHJld2FyZDogYmlnaW50KTogTW9uZXJvQmxvY2sge1xuICAgIHN1cGVyLnNldFJld2FyZChyZXdhcmQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBzZXRQb3dIYXNoKHBvd0hhc2g6IHN0cmluZyk6IE1vbmVyb0Jsb2NrIHtcbiAgICBzdXBlci5zZXRQb3dIYXNoKHBvd0hhc2gpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgcHJvdGVjdGVkIGRlc2VyaWFsaXplVHgodHg6IGFueSwgdHhUeXBlPzogRGVzZXJpYWxpemF0aW9uVHlwZSk6IE1vbmVyb1R4IHtcbiAgICBpZiAodHhUeXBlID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmICghKHR4IGluc3RhbmNlb2YgTW9uZXJvVHgpKSB0aHJvdyBuZXcgRXJyb3IoXCJNdXN0IHByb3ZpZGUgRGVzZXJpYWxpemF0aW9uVHlwZSBpZiB0eCBpcyBub3QgaW5zdGFuY2VvZiBNb25lcm9UeFwiKTtcbiAgICAgIHJldHVybiB0eC5jb3B5KCk7XG4gICAgfSBlbHNlIGlmICh0eFR5cGUgPT09IE1vbmVyb0Jsb2NrLkRlc2VyaWFsaXphdGlvblR5cGUuVFggfHwgdHhUeXBlID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiBuZXcgTW9uZXJvVHgodHgpO1xuICAgIH0gZWxzZSBpZiAodHhUeXBlID09PSBNb25lcm9CbG9jay5EZXNlcmlhbGl6YXRpb25UeXBlLlRYX1dBTExFVCkge1xuICAgICAgcmV0dXJuIG5ldyBNb25lcm9UeFdhbGxldCh0eCk7XG4gICAgfSBlbHNlIGlmICh0eFR5cGUgPT09IE1vbmVyb0Jsb2NrLkRlc2VyaWFsaXphdGlvblR5cGUuVFhfUVVFUlkpIHtcbiAgICAgIHJldHVybiBuZXcgTW9uZXJvVHhRdWVyeSh0eCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIlVucmVjb2duaXplZCB0eCBkZXNlcmlhbGl6YXRpb24gdHlwZTogXCIgKyB0eFR5cGUpO1xuICAgIH1cbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsT0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsU0FBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUUsa0JBQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFHLFNBQUEsR0FBQUosc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFJLGNBQUEsR0FBQUwsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElB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 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroBlockHeader.d.ts b/dist/src/main/ts/daemon/model/MoneroBlockHeader.d.ts new file mode 100644 index 000000000..1ea76fa27 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroBlockHeader.d.ts @@ -0,0 +1,75 @@ +/** + * Models a Monero block header which contains information about the block. + */ +export default class MoneroBlockHeader { + hash: string; + height: number; + timestamp: number; + size: number; + weight: number; + longTermWeight: number; + depth: number; + difficulty: bigint; + cumulativeDifficulty: bigint; + majorVersion: number; + minorVersion: number; + nonce: number; + minerTxHash: string; + numTxs: number; + orphanStatus: boolean; + prevHash: string; + reward: bigint; + powHash: string; + constructor(header?: Partial); + copy(): MoneroBlockHeader; + toJson(): any; + getHash(): string; + setHash(hash: string): this; + /** + * Return the block's height which is the total number of blocks that have occurred before. + * + * @return {number} the block's height + */ + getHeight(): number; + /** + * Set the block's height which is the total number of blocks that have occurred before. + * + * @param {number} height is the block's height to set + * @return {MoneroBlockHeader} a reference to this header for chaining + */ + setHeight(height: number): MoneroBlockHeader; + getTimestamp(): number; + setTimestamp(timestamp: any): MoneroBlockHeader; + getSize(): number; + setSize(size: number): MoneroBlockHeader; + getWeight(): number; + setWeight(weight: number): MoneroBlockHeader; + getLongTermWeight(): number; + setLongTermWeight(longTermWeight: number): MoneroBlockHeader; + getDepth(): number; + setDepth(depth: number): MoneroBlockHeader; + getDifficulty(): bigint; + setDifficulty(difficulty: bigint): MoneroBlockHeader; + getCumulativeDifficulty(): bigint; + setCumulativeDifficulty(cumulativeDifficulty: bigint): MoneroBlockHeader; + getMajorVersion(): number; + setMajorVersion(majorVersion: number): MoneroBlockHeader; + getMinorVersion(): number; + setMinorVersion(minorVersion: number): MoneroBlockHeader; + getNonce(): number; + setNonce(nonce: number): MoneroBlockHeader; + getMinerTxHash(): string; + setMinerTxHash(minerTxHash: string): MoneroBlockHeader; + getNumTxs(): number; + setNumTxs(numTxs: number): MoneroBlockHeader; + getOrphanStatus(): boolean; + setOrphanStatus(orphanStatus: boolean): MoneroBlockHeader; + getPrevHash(): string; + setPrevHash(prevHash: string): MoneroBlockHeader; + getReward(): bigint; + setReward(reward: bigint): MoneroBlockHeader; + getPowHash(): string; + setPowHash(powHash: string): MoneroBlockHeader; + merge(header: MoneroBlockHeader): MoneroBlockHeader; + toString(indent?: number): string; +} diff --git a/dist/src/main/ts/daemon/model/MoneroBlockHeader.js b/dist/src/main/ts/daemon/model/MoneroBlockHeader.js new file mode 100644 index 000000000..42940ed03 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroBlockHeader.js @@ -0,0 +1,267 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); + +/** + * Models a Monero block header which contains information about the block. + */ +class MoneroBlockHeader { + + + + + + + + + + + + + + + + + + + + + constructor(header) { + Object.assign(this, header); + + // deserialize bigints + if (this.difficulty !== undefined && typeof this.difficulty !== "bigint") this.difficulty = BigInt(this.difficulty); + if (this.cumulativeDifficulty !== undefined && typeof this.cumulativeDifficulty !== "bigint") this.cumulativeDifficulty = BigInt(this.cumulativeDifficulty); + if (this.reward !== undefined && typeof this.reward !== "bigint") this.reward = BigInt(this.reward); + } + + copy() { + return new MoneroBlockHeader(this); + } + + toJson() { + let json = Object.assign({}, this); + if (this.getDifficulty() !== undefined) json.difficulty = this.getDifficulty().toString(); + if (this.getCumulativeDifficulty() !== undefined) json.cumulativeDifficulty = this.getCumulativeDifficulty().toString(); + if (this.getReward() !== undefined) json.reward = this.getReward().toString(); + return json; + } + + getHash() { + return this.hash; + } + + setHash(hash) { + this.hash = hash; + return this; + } + + /** + * Return the block's height which is the total number of blocks that have occurred before. + * + * @return {number} the block's height + */ + getHeight() { + return this.height; + } + + /** + * Set the block's height which is the total number of blocks that have occurred before. + * + * @param {number} height is the block's height to set + * @return {MoneroBlockHeader} a reference to this header for chaining + */ + setHeight(height) { + this.height = height; + return this; + } + + getTimestamp() { + return this.timestamp; + } + + setTimestamp(timestamp) { + this.timestamp = timestamp; + return this; + } + + getSize() { + return this.size; + } + + setSize(size) { + this.size = size; + return this; + } + + getWeight() { + return this.weight; + } + + setWeight(weight) { + this.weight = weight; + return this; + } + + getLongTermWeight() { + return this.longTermWeight; + } + + setLongTermWeight(longTermWeight) { + this.longTermWeight = longTermWeight; + return this; + } + + getDepth() { + return this.depth; + } + + setDepth(depth) { + this.depth = depth; + return this; + } + + getDifficulty() { + return this.difficulty; + } + + setDifficulty(difficulty) { + this.difficulty = difficulty; + return this; + } + + getCumulativeDifficulty() { + return this.cumulativeDifficulty; + } + + setCumulativeDifficulty(cumulativeDifficulty) { + this.cumulativeDifficulty = cumulativeDifficulty; + return this; + } + + getMajorVersion() { + return this.majorVersion; + } + + setMajorVersion(majorVersion) { + this.majorVersion = majorVersion; + return this; + } + + getMinorVersion() { + return this.minorVersion; + } + + setMinorVersion(minorVersion) { + this.minorVersion = minorVersion; + return this; + } + + getNonce() { + return this.nonce; + } + + setNonce(nonce) { + this.nonce = nonce; + return this; + } + + getMinerTxHash() { + return this.minerTxHash; + } + + setMinerTxHash(minerTxHash) { + this.minerTxHash = minerTxHash; + return this; + } + + getNumTxs() { + return this.numTxs; + } + + setNumTxs(numTxs) { + this.numTxs = numTxs; + return this; + } + + getOrphanStatus() { + return this.orphanStatus; + } + + setOrphanStatus(orphanStatus) { + this.orphanStatus = orphanStatus; + return this; + } + + getPrevHash() { + return this.prevHash; + } + + setPrevHash(prevHash) { + this.prevHash = prevHash; + return this; + } + + getReward() { + return this.reward; + } + + setReward(reward) { + this.reward = reward; + return this; + } + + getPowHash() { + return this.powHash; + } + + setPowHash(powHash) { + this.powHash = powHash; + return this; + } + + merge(header) { + (0, _assert.default)(header instanceof MoneroBlockHeader); + if (this === header) return this; + this.setHash(_GenUtils.default.reconcile(this.getHash(), header.getHash())); + this.setHeight(_GenUtils.default.reconcile(this.getHeight(), header.getHeight(), { resolveMax: true })); // height can increase + this.setTimestamp(_GenUtils.default.reconcile(this.getTimestamp(), header.getTimestamp(), { resolveMax: true })); // block timestamp can increase + this.setSize(_GenUtils.default.reconcile(this.getSize(), header.getSize())); + this.setWeight(_GenUtils.default.reconcile(this.getWeight(), header.getWeight())); + this.setDepth(_GenUtils.default.reconcile(this.getDepth(), header.getDepth())); + this.setDifficulty(_GenUtils.default.reconcile(this.getDifficulty(), header.getDifficulty())); + this.setCumulativeDifficulty(_GenUtils.default.reconcile(this.getCumulativeDifficulty(), header.getCumulativeDifficulty())); + this.setMajorVersion(_GenUtils.default.reconcile(this.getMajorVersion(), header.getMajorVersion())); + this.setMinorVersion(_GenUtils.default.reconcile(this.getMinorVersion(), header.getMinorVersion())); + this.setNonce(_GenUtils.default.reconcile(this.getNonce(), header.getNonce())); + this.setMinerTxHash(_GenUtils.default.reconcile(this.getMinerTxHash(), header.getMinerTxHash())); + this.setNumTxs(_GenUtils.default.reconcile(this.getNumTxs(), header.getNumTxs())); + this.setOrphanStatus(_GenUtils.default.reconcile(this.getOrphanStatus(), header.getOrphanStatus())); + this.setPrevHash(_GenUtils.default.reconcile(this.getPrevHash(), header.getPrevHash())); + this.setReward(_GenUtils.default.reconcile(this.getReward(), header.getReward())); + this.setPowHash(_GenUtils.default.reconcile(this.getPowHash(), header.getPowHash())); + return this; + } + + toString(indent = 0) { + let str = ""; + str += _GenUtils.default.kvLine("Hash", this.getHash(), indent); + str += _GenUtils.default.kvLine("Height", this.getHeight(), indent); + str += _GenUtils.default.kvLine("Timestamp", this.getTimestamp(), indent); + str += _GenUtils.default.kvLine("Size", this.getSize(), indent); + str += _GenUtils.default.kvLine("Weight", this.getWeight(), indent); + str += _GenUtils.default.kvLine("Depth", this.getDepth(), indent); + str += _GenUtils.default.kvLine("Difficulty", this.getDifficulty(), indent); + str += _GenUtils.default.kvLine("Cumulative difficulty", this.getCumulativeDifficulty(), indent); + str += _GenUtils.default.kvLine("Major version", this.getMajorVersion(), indent); + str += _GenUtils.default.kvLine("Minor version", this.getMinorVersion(), indent); + str += _GenUtils.default.kvLine("Nonce", this.getNonce(), indent); + str += _GenUtils.default.kvLine("Miner tx hash", this.getMinerTxHash(), indent); + str += _GenUtils.default.kvLine("Num txs", this.getNumTxs(), indent); + str += _GenUtils.default.kvLine("Orphan status", this.getOrphanStatus(), indent); + str += _GenUtils.default.kvLine("Prev hash", this.getPrevHash(), indent); + str += _GenUtils.default.kvLine("Reward", this.getReward(), indent); + str += _GenUtils.default.kvLine("Pow hash", this.getPowHash(), indent); + return str[str.length - 1] === "\n" ? str.slice(0, str.length - 1) : str; // strip last newline + } +}exports.default = MoneroBlockHeader; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJNb25lcm9CbG9ja0hlYWRlciIsImNvbnN0cnVjdG9yIiwiaGVhZGVyIiwiT2JqZWN0IiwiYXNzaWduIiwiZGlmZmljdWx0eSIsInVuZGVmaW5lZCIsIkJpZ0ludCIsImN1bXVsYXRpdmVEaWZmaWN1bHR5IiwicmV3YXJkIiwiY29weSIsInRvSnNvbiIsImpzb24iLCJnZXREaWZmaWN1bHR5IiwidG9TdHJpbmciLCJnZXRDdW11bGF0aXZlRGlmZmljdWx0eSIsImdldFJld2FyZCIsImdldEhhc2giLCJoYXNoIiwic2V0SGFzaCIsImdldEhlaWdodCIsImhlaWdodCIsInNldEhlaWdodCIsImdldFRpbWVzdGFtcCIsInRpbWVzdGFtcCIsInNldFRpbWVzdGFtcCIsImdldFNpemUiLCJzaXplIiwic2V0U2l6ZSIsImdldFdlaWdodCIsIndlaWdodCIsInNldFdlaWdodCIsImdldExvbmdUZXJtV2VpZ2h0IiwibG9uZ1Rlcm1XZWlnaHQiLCJzZXRMb25nVGVybVdlaWdodCIsImdldERlcHRoIiwiZGVwdGgiLCJzZXREZXB0aCIsInNldERpZmZpY3VsdHkiLCJzZXRDdW11bGF0aXZlRGlmZmljdWx0eSIsImdldE1ham9yVmVyc2lvbiIsIm1ham9yVmVyc2lvbiIsInNldE1ham9yVmVyc2lvbiIsImdldE1pbm9yVmVyc2lvbiIsIm1pbm9yVmVyc2lvbiIsInNldE1pbm9yVmVyc2lvbiIsImdldE5vbmNlIiwibm9uY2UiLCJzZXROb25jZSIsImdldE1pbmVyVHhIYXNoIiwibWluZXJUeEhhc2giLCJzZXRNaW5lclR4SGFzaCIsImdldE51bVR4cyIsIm51bVR4cyIsInNldE51bVR4cyIsImdldE9ycGhhblN0YXR1cyIsIm9ycGhhblN0YXR1cyIsInNldE9ycGhhblN0YXR1cyIsImdldFByZXZIYXNoIiwicHJldkhhc2giLCJzZXRQcmV2SGFzaCIsInNldFJld2FyZCIsImdldFBvd0hhc2giLCJwb3dIYXNoIiwic2V0UG93SGFzaCIsIm1lcmdlIiwiYXNzZXJ0IiwiR2VuVXRpbHMiLCJyZWNvbmNpbGUiLCJyZXNvbHZlTWF4IiwiaW5kZW50Iiwic3RyIiwia3ZMaW5lIiwibGVuZ3RoIiwic2xpY2UiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2RhZW1vbi9tb2RlbC9Nb25lcm9CbG9ja0hlYWRlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi4vLi4vY29tbW9uL0dlblV0aWxzXCI7XG5cbi8qKlxuICogTW9kZWxzIGEgTW9uZXJvIGJsb2NrIGhlYWRlciB3aGljaCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgYmxvY2suXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0Jsb2NrSGVhZGVyIHtcblxuICBoYXNoOiBzdHJpbmc7XG4gIGhlaWdodDogbnVtYmVyO1xuICB0aW1lc3RhbXA6IG51bWJlcjtcbiAgc2l6ZTogbnVtYmVyO1xuICB3ZWlnaHQ6IG51bWJlcjtcbiAgbG9uZ1Rlcm1XZWlnaHQ6IG51bWJlcjtcbiAgZGVwdGg6IG51bWJlcjtcbiAgZGlmZmljdWx0eTogYmlnaW50O1xuICBjdW11bGF0aXZlRGlmZmljdWx0eTogYmlnaW50O1xuICBtYWpvclZlcnNpb246IG51bWJlcjtcbiAgbWlub3JWZXJzaW9uOiBudW1iZXI7XG4gIG5vbmNlOiBudW1iZXI7XG4gIG1pbmVyVHhIYXNoOiBzdHJpbmc7XG4gIG51bVR4czogbnVtYmVyO1xuICBvcnBoYW5TdGF0dXM6IGJvb2xlYW47XG4gIHByZXZIYXNoOiBzdHJpbmc7XG4gIHJld2FyZDogYmlnaW50O1xuICBwb3dIYXNoOiBzdHJpbmc7XG4gIFxuICBjb25zdHJ1Y3RvcihoZWFkZXI/OiBQYXJ0aWFsPE1vbmVyb0Jsb2NrSGVhZGVyPikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgaGVhZGVyKTtcblxuICAgIC8vIGRlc2VyaWFsaXplIGJpZ2ludHNcbiAgICBpZiAodGhpcy5kaWZmaWN1bHR5ICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHRoaXMuZGlmZmljdWx0eSAhPT0gXCJiaWdpbnRcIikgdGhpcy5kaWZmaWN1bHR5ID0gQmlnSW50KHRoaXMuZGlmZmljdWx0eSk7XG4gICAgaWYgKHRoaXMuY3VtdWxhdGl2ZURpZmZpY3VsdHkgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5jdW11bGF0aXZlRGlmZmljdWx0eSAhPT0gXCJiaWdpbnRcIikgdGhpcy5jdW11bGF0aXZlRGlmZmljdWx0eSA9IEJpZ0ludCh0aGlzLmN1bXVsYXRpdmVEaWZmaWN1bHR5KTtcbiAgICBpZiAodGhpcy5yZXdhcmQgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5yZXdhcmQgIT09IFwiYmlnaW50XCIpIHRoaXMucmV3YXJkID0gQmlnSW50KHRoaXMucmV3YXJkKTtcbiAgfVxuICBcbiAgY29weSgpOiBNb25lcm9CbG9ja0hlYWRlciB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9CbG9ja0hlYWRlcih0aGlzKTtcbiAgfVxuICBcbiAgdG9Kc29uKCkge1xuICAgIGxldCBqc29uOiBhbnkgPSBPYmplY3QuYXNzaWduKHt9LCB0aGlzKTtcbiAgICBpZiAodGhpcy5nZXREaWZmaWN1bHR5KCkgIT09IHVuZGVmaW5lZCkganNvbi5kaWZmaWN1bHR5ID0gdGhpcy5nZXREaWZmaWN1bHR5KCkudG9TdHJpbmcoKTtcbiAgICBpZiAodGhpcy5nZXRDdW11bGF0aXZlRGlmZmljdWx0eSgpICE9PSB1bmRlZmluZWQpIGpzb24uY3VtdWxhdGl2ZURpZmZpY3VsdHkgPSB0aGlzLmdldEN1bXVsYXRpdmVEaWZmaWN1bHR5KCkudG9TdHJpbmcoKTtcbiAgICBpZiAodGhpcy5nZXRSZXdhcmQoKSAhPT0gdW5kZWZpbmVkKSBqc29uLnJld2FyZCA9IHRoaXMuZ2V0UmV3YXJkKCkudG9TdHJpbmcoKTtcbiAgICByZXR1cm4ganNvbjtcbiAgfVxuICBcbiAgZ2V0SGFzaCgpIHtcbiAgICByZXR1cm4gdGhpcy5oYXNoO1xuICB9XG4gIFxuICBzZXRIYXNoKGhhc2g6IHN0cmluZykge1xuICAgIHRoaXMuaGFzaCA9IGhhc2g7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIGJsb2NrJ3MgaGVpZ2h0IHdoaWNoIGlzIHRoZSB0b3RhbCBudW1iZXIgb2YgYmxvY2tzIHRoYXQgaGF2ZSBvY2N1cnJlZCBiZWZvcmUuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtudW1iZXJ9IHRoZSBibG9jaydzIGhlaWdodFxuICAgKi9cbiAgZ2V0SGVpZ2h0KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuaGVpZ2h0O1xuICB9XG4gIFxuICAvKipcbiAgICogU2V0IHRoZSBibG9jaydzIGhlaWdodCB3aGljaCBpcyB0aGUgdG90YWwgbnVtYmVyIG9mIGJsb2NrcyB0aGF0IGhhdmUgb2NjdXJyZWQgYmVmb3JlLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCBpcyB0aGUgYmxvY2sncyBoZWlnaHQgdG8gc2V0XG4gICAqIEByZXR1cm4ge01vbmVyb0Jsb2NrSGVhZGVyfSBhIHJlZmVyZW5jZSB0byB0aGlzIGhlYWRlciBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldEhlaWdodChoZWlnaHQ6IG51bWJlcik6IE1vbmVyb0Jsb2NrSGVhZGVyIHtcbiAgICB0aGlzLmhlaWdodCA9IGhlaWdodDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0VGltZXN0YW1wKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMudGltZXN0YW1wO1xuICB9XG4gIFxuICBzZXRUaW1lc3RhbXAodGltZXN0YW1wKTogTW9uZXJvQmxvY2tIZWFkZXIge1xuICAgIHRoaXMudGltZXN0YW1wID0gdGltZXN0YW1wO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRTaXplKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuc2l6ZTtcbiAgfVxuICBcbiAgc2V0U2l6ZShzaXplOiBudW1iZXIpOiBNb25lcm9CbG9ja0hlYWRlciB7XG4gICAgdGhpcy5zaXplID0gc2l6ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0V2VpZ2h0KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMud2VpZ2h0O1xuICB9XG4gIFxuICBzZXRXZWlnaHQod2VpZ2h0OiBudW1iZXIpOiBNb25lcm9CbG9ja0hlYWRlciB7XG4gICAgdGhpcy53ZWlnaHQgPSB3ZWlnaHQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldExvbmdUZXJtV2VpZ2h0KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubG9uZ1Rlcm1XZWlnaHQ7XG4gIH1cbiAgXG4gIHNldExvbmdUZXJtV2VpZ2h0KGxvbmdUZXJtV2VpZ2h0OiBudW1iZXIpOiBNb25lcm9CbG9ja0hlYWRlciB7XG4gICAgdGhpcy5sb25nVGVybVdlaWdodCA9IGxvbmdUZXJtV2VpZ2h0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXREZXB0aCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmRlcHRoO1xuICB9XG4gIFxuICBzZXREZXB0aChkZXB0aDogbnVtYmVyKTogTW9uZXJvQmxvY2tIZWFkZXIge1xuICAgIHRoaXMuZGVwdGggPSBkZXB0aDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0RGlmZmljdWx0eSgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLmRpZmZpY3VsdHk7XG4gIH1cbiAgXG4gIHNldERpZmZpY3VsdHkoZGlmZmljdWx0eTogYmlnaW50KTogTW9uZXJvQmxvY2tIZWFkZXIge1xuICAgIHRoaXMuZGlmZmljdWx0eSA9IGRpZmZpY3VsdHk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEN1bXVsYXRpdmVEaWZmaWN1bHR5KCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMuY3VtdWxhdGl2ZURpZmZpY3VsdHk7XG4gIH1cbiAgXG4gIHNldEN1bXVsYXRpdmVEaWZmaWN1bHR5KGN1bXVsYXRpdmVEaWZmaWN1bHR5OiBiaWdpbnQpOiBNb25lcm9CbG9ja0hlYWRlciB7XG4gICAgdGhpcy5jdW11bGF0aXZlRGlmZmljdWx0eSA9IGN1bXVsYXRpdmVEaWZmaWN1bHR5O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRNYWpvclZlcnNpb24oKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5tYWpvclZlcnNpb247XG4gIH1cbiAgXG4gIHNldE1ham9yVmVyc2lvbihtYWpvclZlcnNpb246IG51bWJlcik6IE1vbmVyb0Jsb2NrSGVhZGVyIHtcbiAgICB0aGlzLm1ham9yVmVyc2lvbiA9IG1ham9yVmVyc2lvbjtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0TWlub3JWZXJzaW9uKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubWlub3JWZXJzaW9uO1xuICB9XG4gIFxuICBzZXRNaW5vclZlcnNpb24obWlub3JWZXJzaW9uOiBudW1iZXIpOiBNb25lcm9CbG9ja0hlYWRlciB7XG4gICAgdGhpcy5taW5vclZlcnNpb24gPSBtaW5vclZlcnNpb247XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldE5vbmNlKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubm9uY2U7XG4gIH1cbiAgXG4gIHNldE5vbmNlKG5vbmNlOiBudW1iZXIpOiBNb25lcm9CbG9ja0hlYWRlciB7XG4gICAgdGhpcy5ub25jZSA9IG5vbmNlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRNaW5lclR4SGFzaCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLm1pbmVyVHhIYXNoO1xuICB9XG4gIFxuICBzZXRNaW5lclR4SGFzaChtaW5lclR4SGFzaDogc3RyaW5nKTogTW9uZXJvQmxvY2tIZWFkZXIge1xuICAgIHRoaXMubWluZXJUeEhhc2ggPSBtaW5lclR4SGFzaDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0TnVtVHhzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtVHhzO1xuICB9XG4gIFxuICBzZXROdW1UeHMobnVtVHhzOiBudW1iZXIpOiBNb25lcm9CbG9ja0hlYWRlciB7XG4gICAgdGhpcy5udW1UeHMgPSBudW1UeHM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldE9ycGhhblN0YXR1cygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5vcnBoYW5TdGF0dXM7XG4gIH1cbiAgXG4gIHNldE9ycGhhblN0YXR1cyhvcnBoYW5TdGF0dXM6IGJvb2xlYW4pOiBNb25lcm9CbG9ja0hlYWRlciB7XG4gICAgdGhpcy5vcnBoYW5TdGF0dXMgPSBvcnBoYW5TdGF0dXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFByZXZIYXNoKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMucHJldkhhc2g7XG4gIH1cbiAgXG4gIHNldFByZXZIYXNoKHByZXZIYXNoOiBzdHJpbmcpOiBNb25lcm9CbG9ja0hlYWRlciB7XG4gICAgdGhpcy5wcmV2SGFzaCA9IHByZXZIYXNoO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRSZXdhcmQoKTogYmlnaW50IHtcbiAgICByZXR1cm4gdGhpcy5yZXdhcmQ7XG4gIH1cbiAgXG4gIHNldFJld2FyZChyZXdhcmQ6IGJpZ2ludCk6IE1vbmVyb0Jsb2NrSGVhZGVyIHtcbiAgICB0aGlzLnJld2FyZCA9IHJld2FyZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0UG93SGFzaCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnBvd0hhc2g7XG4gIH1cbiAgXG4gIHNldFBvd0hhc2gocG93SGFzaDogc3RyaW5nKTogTW9uZXJvQmxvY2tIZWFkZXIge1xuICAgIHRoaXMucG93SGFzaCA9IHBvd0hhc2g7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIG1lcmdlKGhlYWRlcjogTW9uZXJvQmxvY2tIZWFkZXIpOiBNb25lcm9CbG9ja0hlYWRlciB7XG4gICAgYXNzZXJ0KGhlYWRlciBpbnN0YW5jZW9mIE1vbmVyb0Jsb2NrSGVhZGVyKTtcbiAgICBpZiAodGhpcyA9PT0gaGVhZGVyKSByZXR1cm4gdGhpcztcbiAgICB0aGlzLnNldEhhc2goR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0SGFzaCgpLCBoZWFkZXIuZ2V0SGFzaCgpKSk7XG4gICAgdGhpcy5zZXRIZWlnaHQoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0SGVpZ2h0KCksIGhlYWRlci5nZXRIZWlnaHQoKSwge3Jlc29sdmVNYXg6IHRydWV9KSk7ICAvLyBoZWlnaHQgY2FuIGluY3JlYXNlXG4gICAgdGhpcy5zZXRUaW1lc3RhbXAoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0VGltZXN0YW1wKCksIGhlYWRlci5nZXRUaW1lc3RhbXAoKSwge3Jlc29sdmVNYXg6IHRydWV9KSk7ICAvLyBibG9jayB0aW1lc3RhbXAgY2FuIGluY3JlYXNlXG4gICAgdGhpcy5zZXRTaXplKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldFNpemUoKSwgaGVhZGVyLmdldFNpemUoKSkpO1xuICAgIHRoaXMuc2V0V2VpZ2h0KEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldFdlaWdodCgpLCBoZWFkZXIuZ2V0V2VpZ2h0KCkpKTtcbiAgICB0aGlzLnNldERlcHRoKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldERlcHRoKCksIGhlYWRlci5nZXREZXB0aCgpKSk7XG4gICAgdGhpcy5zZXREaWZmaWN1bHR5KEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldERpZmZpY3VsdHkoKSwgaGVhZGVyLmdldERpZmZpY3VsdHkoKSkpO1xuICAgIHRoaXMuc2V0Q3VtdWxhdGl2ZURpZmZpY3VsdHkoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0Q3VtdWxhdGl2ZURpZmZpY3VsdHkoKSwgaGVhZGVyLmdldEN1bXVsYXRpdmVEaWZmaWN1bHR5KCkpKTtcbiAgICB0aGlzLnNldE1ham9yVmVyc2lvbihHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRNYWpvclZlcnNpb24oKSwgaGVhZGVyLmdldE1ham9yVmVyc2lvbigpKSk7XG4gICAgdGhpcy5zZXRNaW5vclZlcnNpb24oR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0TWlub3JWZXJzaW9uKCksIGhlYWRlci5nZXRNaW5vclZlcnNpb24oKSkpO1xuICAgIHRoaXMuc2V0Tm9uY2UoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0Tm9uY2UoKSwgaGVhZGVyLmdldE5vbmNlKCkpKTtcbiAgICB0aGlzLnNldE1pbmVyVHhIYXNoKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldE1pbmVyVHhIYXNoKCksIGhlYWRlci5nZXRNaW5lclR4SGFzaCgpKSk7XG4gICAgdGhpcy5zZXROdW1UeHMoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0TnVtVHhzKCksIGhlYWRlci5nZXROdW1UeHMoKSkpO1xuICAgIHRoaXMuc2V0T3JwaGFuU3RhdHVzKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldE9ycGhhblN0YXR1cygpLCBoZWFkZXIuZ2V0T3JwaGFuU3RhdHVzKCkpKTtcbiAgICB0aGlzLnNldFByZXZIYXNoKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldFByZXZIYXNoKCksIGhlYWRlci5nZXRQcmV2SGFzaCgpKSk7XG4gICAgdGhpcy5zZXRSZXdhcmQoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0UmV3YXJkKCksIGhlYWRlci5nZXRSZXdhcmQoKSkpO1xuICAgIHRoaXMuc2V0UG93SGFzaChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRQb3dIYXNoKCksIGhlYWRlci5nZXRQb3dIYXNoKCkpKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgdG9TdHJpbmcoaW5kZW50ID0gMCkge1xuICAgIGxldCBzdHIgPSBcIlwiO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJIYXNoXCIsIHRoaXMuZ2V0SGFzaCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJIZWlnaHRcIiwgdGhpcy5nZXRIZWlnaHQoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiVGltZXN0YW1wXCIsIHRoaXMuZ2V0VGltZXN0YW1wKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlNpemVcIiwgdGhpcy5nZXRTaXplKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIldlaWdodFwiLCB0aGlzLmdldFdlaWdodCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJEZXB0aFwiLCB0aGlzLmdldERlcHRoKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIkRpZmZpY3VsdHlcIiwgdGhpcy5nZXREaWZmaWN1bHR5KCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIkN1bXVsYXRpdmUgZGlmZmljdWx0eVwiLCB0aGlzLmdldEN1bXVsYXRpdmVEaWZmaWN1bHR5KCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIk1ham9yIHZlcnNpb25cIiwgdGhpcy5nZXRNYWpvclZlcnNpb24oKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiTWlub3IgdmVyc2lvblwiLCB0aGlzLmdldE1pbm9yVmVyc2lvbigpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJOb25jZVwiLCB0aGlzLmdldE5vbmNlKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIk1pbmVyIHR4IGhhc2hcIiwgdGhpcy5nZXRNaW5lclR4SGFzaCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJOdW0gdHhzXCIsIHRoaXMuZ2V0TnVtVHhzKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIk9ycGhhbiBzdGF0dXNcIiwgdGhpcy5nZXRPcnBoYW5TdGF0dXMoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiUHJldiBoYXNoXCIsIHRoaXMuZ2V0UHJldkhhc2goKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiUmV3YXJkXCIsIHRoaXMuZ2V0UmV3YXJkKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlBvdyBoYXNoXCIsIHRoaXMuZ2V0UG93SGFzaCgpLCBpbmRlbnQpO1xuICAgIHJldHVybiBzdHJbc3RyLmxlbmd0aCAtIDFdID09PSBcIlxcblwiID8gc3RyLnNsaWNlKDAsIHN0ci5sZW5ndGggLSAxKSA6IHN0ciAgLy8gc3RyaXAgbGFzdCBuZXdsaW5lXG4gIH1cbn0iXSwibWFwcGluZ3MiOiJ5TEFBQSxJQUFBQSxPQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxTQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7O0FBRUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUUsaUJBQWlCLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQXFCckNDLFdBQVdBLENBQUNDLE1BQW1DLEVBQUU7SUFDL0NDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsTUFBTSxDQUFDOztJQUUzQjtJQUNBLElBQUksSUFBSSxDQUFDRyxVQUFVLEtBQUtDLFNBQVMsSUFBSSxPQUFPLElBQUksQ0FBQ0QsVUFBVSxLQUFLLFFBQVEsRUFBRSxJQUFJLENBQUNBLFVBQVUsR0FBR0UsTUFBTSxDQUFDLElBQUksQ0FBQ0YsVUFBVSxDQUFDO0lBQ25ILElBQUksSUFBSSxDQUFDRyxvQkFBb0IsS0FBS0YsU0FBUyxJQUFJLE9BQU8sSUFB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 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroBlockTemplate.d.ts b/dist/src/main/ts/daemon/model/MoneroBlockTemplate.d.ts new file mode 100644 index 000000000..d8d0933da --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroBlockTemplate.d.ts @@ -0,0 +1,37 @@ +/** + * Monero block template to mine. + */ +export default class MoneroBlockTemplate { + blockTemplateBlob: string; + blockHashingBlob: string; + difficulty: bigint; + expectedReward: bigint; + height: number; + prevId: string; + reservedOffset: number; + seedHeight: number; + seedHash: string; + nextSeedHash: string; + constructor(template?: Partial); + toJson(): any; + getBlockTemplateBlob(): string; + setBlockTemplateBlob(blockTemplateBlob: string): MoneroBlockTemplate; + getBlockHashingBlob(): string; + setBlockHashingBlob(blockHashingBlob: string): MoneroBlockTemplate; + getDifficulty(): bigint; + setDifficulty(difficulty: bigint): MoneroBlockTemplate; + getExpectedReward(): bigint; + setExpectedReward(expectedReward: bigint): MoneroBlockTemplate; + getHeight(): number; + setHeight(height: number): MoneroBlockTemplate; + getPrevHash(): string; + setPrevHash(prevId: string): MoneroBlockTemplate; + getReservedOffset(): number; + setReservedOffset(reservedOffset: number): MoneroBlockTemplate; + getSeedHeight(): number; + setSeedHeight(seedHeight: number): MoneroBlockTemplate; + getSeedHash(): string; + setSeedHash(seedHash: string): MoneroBlockTemplate; + getNextSeedHash(): string; + setNextSeedHash(nextSeedHash: string): MoneroBlockTemplate; +} diff --git a/dist/src/main/ts/daemon/model/MoneroBlockTemplate.js b/dist/src/main/ts/daemon/model/MoneroBlockTemplate.js new file mode 100644 index 000000000..b041f3161 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroBlockTemplate.js @@ -0,0 +1,120 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Monero block template to mine. + */ +class MoneroBlockTemplate { + + + + + + + + + + + + + constructor(template) { + Object.assign(this, template); + if (this.expectedReward !== undefined && typeof this.expectedReward !== "bigint") this.expectedReward = BigInt(this.expectedReward); + if (this.difficulty !== undefined && typeof this.difficulty !== "bigint") this.difficulty = BigInt(this.difficulty); + } + + toJson() { + let json = Object.assign({}, this); + if (this.getExpectedReward() !== undefined) json.expectedReward = this.getExpectedReward().toString(); + if (this.getDifficulty() !== undefined) json.difficulty = this.getDifficulty().toString(); + return json; + } + + getBlockTemplateBlob() { + return this.blockTemplateBlob; + } + + setBlockTemplateBlob(blockTemplateBlob) { + this.blockTemplateBlob = blockTemplateBlob; + return this; + } + + getBlockHashingBlob() { + return this.blockHashingBlob; + } + + setBlockHashingBlob(blockHashingBlob) { + this.blockHashingBlob = blockHashingBlob; + return this; + } + + getDifficulty() { + return this.difficulty; + } + + setDifficulty(difficulty) { + this.difficulty = difficulty; + return this; + } + + getExpectedReward() { + return this.expectedReward; + } + + setExpectedReward(expectedReward) { + this.expectedReward = expectedReward; + return this; + } + + getHeight() { + return this.height; + } + + setHeight(height) { + this.height = height; + return this; + } + + getPrevHash() { + return this.prevId; + } + + setPrevHash(prevId) { + this.prevId = prevId; + return this; + } + + getReservedOffset() { + return this.reservedOffset; + } + + setReservedOffset(reservedOffset) { + this.reservedOffset = reservedOffset; + return this; + } + + getSeedHeight() { + return this.height; + } + + setSeedHeight(seedHeight) { + this.seedHeight = seedHeight; + return this; + } + + getSeedHash() { + return this.seedHash; + } + + setSeedHash(seedHash) { + this.seedHash = seedHash; + return this; + } + + getNextSeedHash() { + return this.nextSeedHash; + } + + setNextSeedHash(nextSeedHash) { + this.nextSeedHash = nextSeedHash; + return this; + } +}exports.default = MoneroBlockTemplate; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9CbG9ja1RlbXBsYXRlIiwiY29uc3RydWN0b3IiLCJ0ZW1wbGF0ZSIsIk9iamVjdCIsImFzc2lnbiIsImV4cGVjdGVkUmV3YXJkIiwidW5kZWZpbmVkIiwiQmlnSW50IiwiZGlmZmljdWx0eSIsInRvSnNvbiIsImpzb24iLCJnZXRFeHBlY3RlZFJld2FyZCIsInRvU3RyaW5nIiwiZ2V0RGlmZmljdWx0eSIsImdldEJsb2NrVGVtcGxhdGVCbG9iIiwiYmxvY2tUZW1wbGF0ZUJsb2IiLCJzZXRCbG9ja1RlbXBsYXRlQmxvYiIsImdldEJsb2NrSGFzaGluZ0Jsb2IiLCJibG9ja0hhc2hpbmdCbG9iIiwic2V0QmxvY2tIYXNoaW5nQmxvYiIsInNldERpZmZpY3VsdHkiLCJzZXRFeHBlY3RlZFJld2FyZCIsImdldEhlaWdodCIsImhlaWdodCIsInNldEhlaWdodCIsImdldFByZXZIYXNoIiwicHJldklkIiwic2V0UHJldkhhc2giLCJnZXRSZXNlcnZlZE9mZnNldCIsInJlc2VydmVkT2Zmc2V0Iiwic2V0UmVzZXJ2ZWRPZmZzZXQiLCJnZXRTZWVkSGVpZ2h0Iiwic2V0U2VlZEhlaWdodCIsInNlZWRIZWlnaHQiLCJnZXRTZWVkSGFzaCIsInNlZWRIYXNoIiwic2V0U2VlZEhhc2giLCJnZXROZXh0U2VlZEhhc2giLCJuZXh0U2VlZEhhc2giLCJzZXROZXh0U2VlZEhhc2giLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2RhZW1vbi9tb2RlbC9Nb25lcm9CbG9ja1RlbXBsYXRlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTW9uZXJvIGJsb2NrIHRlbXBsYXRlIHRvIG1pbmUuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0Jsb2NrVGVtcGxhdGUge1xuXG4gIGJsb2NrVGVtcGxhdGVCbG9iOiBzdHJpbmc7XG4gIGJsb2NrSGFzaGluZ0Jsb2I6IHN0cmluZztcbiAgZGlmZmljdWx0eTogYmlnaW50O1xuICBleHBlY3RlZFJld2FyZDogYmlnaW50O1xuICBoZWlnaHQ6IG51bWJlcjtcbiAgcHJldklkOiBzdHJpbmc7XG4gIHJlc2VydmVkT2Zmc2V0OiBudW1iZXI7XG4gIHNlZWRIZWlnaHQ6IG51bWJlcjtcbiAgc2VlZEhhc2g6IHN0cmluZztcbiAgbmV4dFNlZWRIYXNoOiBzdHJpbmc7XG4gIFxuICBjb25zdHJ1Y3Rvcih0ZW1wbGF0ZT86IFBhcnRpYWw8TW9uZXJvQmxvY2tUZW1wbGF0ZT4pIHtcbiAgICBPYmplY3QuYXNzaWduKHRoaXMsIHRlbXBsYXRlKTtcbiAgICBpZiAodGhpcy5leHBlY3RlZFJld2FyZCAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLmV4cGVjdGVkUmV3YXJkICE9PSBcImJpZ2ludFwiKSB0aGlzLmV4cGVjdGVkUmV3YXJkID0gQmlnSW50KHRoaXMuZXhwZWN0ZWRSZXdhcmQpO1xuICAgIGlmICh0aGlzLmRpZmZpY3VsdHkgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5kaWZmaWN1bHR5ICE9PSBcImJpZ2ludFwiKSB0aGlzLmRpZmZpY3VsdHkgPSBCaWdJbnQodGhpcy5kaWZmaWN1bHR5KTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgbGV0IGpzb246IGFueSA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICAgIGlmICh0aGlzLmdldEV4cGVjdGVkUmV3YXJkKCkgIT09IHVuZGVmaW5lZCkganNvbi5leHBlY3RlZFJld2FyZCA9IHRoaXMuZ2V0RXhwZWN0ZWRSZXdhcmQoKS50b1N0cmluZygpO1xuICAgIGlmICh0aGlzLmdldERpZmZpY3VsdHkoKSAhPT0gdW5kZWZpbmVkKSBqc29uLmRpZmZpY3VsdHkgPSB0aGlzLmdldERpZmZpY3VsdHkoKS50b1N0cmluZygpO1xuICAgIHJldHVybiBqc29uO1xuICB9XG4gIFxuICBnZXRCbG9ja1RlbXBsYXRlQmxvYigpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmJsb2NrVGVtcGxhdGVCbG9iO1xuICB9XG4gIFxuICBzZXRCbG9ja1RlbXBsYXRlQmxvYihibG9ja1RlbXBsYXRlQmxvYjogc3RyaW5nKTogTW9uZXJvQmxvY2tUZW1wbGF0ZSB7XG4gICAgdGhpcy5ibG9ja1RlbXBsYXRlQmxvYiA9IGJsb2NrVGVtcGxhdGVCbG9iO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRCbG9ja0hhc2hpbmdCbG9iKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuYmxvY2tIYXNoaW5nQmxvYjtcbiAgfVxuICBcbiAgc2V0QmxvY2tIYXNoaW5nQmxvYihibG9ja0hhc2hpbmdCbG9iOiBzdHJpbmcpOiBNb25lcm9CbG9ja1RlbXBsYXRlIHtcbiAgICB0aGlzLmJsb2NrSGFzaGluZ0Jsb2IgPSBibG9ja0hhc2hpbmdCbG9iO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXREaWZmaWN1bHR5KCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMuZGlmZmljdWx0eTtcbiAgfVxuICBcbiAgc2V0RGlmZmljdWx0eShkaWZmaWN1bHR5OiBiaWdpbnQpOiBNb25lcm9CbG9ja1RlbXBsYXRlIHtcbiAgICB0aGlzLmRpZmZpY3VsdHkgPSBkaWZmaWN1bHR5O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRFeHBlY3RlZFJld2FyZCgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLmV4cGVjdGVkUmV3YXJkO1xuICB9XG4gIFxuICBzZXRFeHBlY3RlZFJld2FyZChleHBlY3RlZFJld2FyZDogYmlnaW50KTogTW9uZXJvQmxvY2tUZW1wbGF0ZSB7XG4gICAgdGhpcy5leHBlY3RlZFJld2FyZCA9IGV4cGVjdGVkUmV3YXJkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRIZWlnaHQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5oZWlnaHQ7XG4gIH1cbiAgXG4gIHNldEhlaWdodChoZWlnaHQ6IG51bWJlcik6IE1vbmVyb0Jsb2NrVGVtcGxhdGUge1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRQcmV2SGFzaCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnByZXZJZDtcbiAgfVxuICBcbiAgc2V0UHJldkhhc2gocHJldklkOiBzdHJpbmcpOiBNb25lcm9CbG9ja1RlbXBsYXRlIHtcbiAgICB0aGlzLnByZXZJZCA9IHByZXZJZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0UmVzZXJ2ZWRPZmZzZXQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5yZXNlcnZlZE9mZnNldDtcbiAgfVxuICBcbiAgc2V0UmVzZXJ2ZWRPZmZzZXQocmVzZXJ2ZWRPZmZzZXQ6IG51bWJlcik6IE1vbmVyb0Jsb2NrVGVtcGxhdGUge1xuICAgIHRoaXMucmVzZXJ2ZWRPZmZzZXQgPSByZXNlcnZlZE9mZnNldDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U2VlZEhlaWdodCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmhlaWdodDtcbiAgfVxuICBcbiAgc2V0U2VlZEhlaWdodChzZWVkSGVpZ2h0OiBudW1iZXIpOiBNb25lcm9CbG9ja1RlbXBsYXRlIHtcbiAgICB0aGlzLnNlZWRIZWlnaHQgPSBzZWVkSGVpZ2h0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRTZWVkSGFzaCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnNlZWRIYXNoO1xuICB9XG4gIFxuICBzZXRTZWVkSGFzaChzZWVkSGFzaDogc3RyaW5nKTogTW9uZXJvQmxvY2tUZW1wbGF0ZSB7XG4gICAgdGhpcy5zZWVkSGFzaCA9IHNlZWRIYXNoO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXROZXh0U2VlZEhhc2goKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5uZXh0U2VlZEhhc2hcbiAgfVxuICBcbiAgc2V0TmV4dFNlZWRIYXNoKG5leHRTZWVkSGFzaDogc3RyaW5nKTogTW9uZXJvQmxvY2tUZW1wbGF0ZSB7XG4gICAgdGhpcy5uZXh0U2VlZEhhc2ggPSBuZXh0U2VlZEhhc2g7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn0iXSwibWFwcGluZ3MiOiJxR0FBQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSxtQkFBbUIsQ0FBQzs7Ozs7Ozs7Ozs7OztFQWF2Q0MsV0FBV0EsQ0FBQ0MsUUFBdUMsRUFBRTtJQUNuREMsTUFBTSxDQUFDQyxNQUFNLENBQUMsSUFBSSxFQUFFRixRQUFRLENBQUM7SUFDN0IsSUFBSSxJQUFJLENBQUNHLGNBQWMsS0FBS0MsU0FBUyxJQUFJLE9BQU8sSUFBSSxDQUFDRCxjQUFjLEtBQUssUUFBUSxFQUFFLElBQUksQ0FBQ0EsY0FBYyxHQUFHRSxNQUFNLENBQUMsSUFBSSxDQUFDRixjQUFjLENBQUM7SUFDbkksSUFBSSxJQUFJLENBQUNHLFVBQVUsS0FBS0YsU0FBUyxJQUFJLE9BQU8sSUFBSSxDQUFDRSxVQUFVLEtBQUssUUFBUSxFQUFFLElBQUksQ0FBQ0EsVUFBVSxHQUFHRCxNQUFNLENBQUMsSUFBSSxDQUFDQyxVQUFVLENBQUM7RUFDckg7O0VBRUFDLE1BQU1BLENBQUEsRUFBUTtJQUNaLElBQUlDLElBQVMsR0FBR1AsTUFBTSxDQUFDQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQ3ZDLElBQUksSUFBSSxDQUFDTyxpQkFBaUIsQ0FBQyxDQUFDLEtBQUtMLFNBQVMsRUFBRUksSUFBSSxDQUFDTCxjQUFjLEdBQUcsSUFBSSxDQUFDTSxpQkFBaUIsQ0FBQyxDQUFDLENBQUNDLFFBQVEsQ0FBQyxDQUFDO0lBQ3JHLElBQUksSUFBSSxDQUFDQyxhQUFhLENBQUMsQ0FBQyxLQUFLUCxTQUFTLEVBQUVJLElBQUksQ0FBQ0YsVUFBVSxHQUFHLElBQUksQ0FBQ0ssYUFBYSxDQUFDLENBQUMsQ0FBQ0QsUUFBUSxDQUFDLENBQUM7SUFDekYsT0FBT0YsSUFBSTtFQUNiOztFQUVBSSxvQkFBb0JBLENBQUEsRUFBVztJQUM3QixPQUFPLElBQUksQ0FBQ0MsaUJBQWlCO0VBQy9COztFQUVBQyxvQkFBb0JBLENBQUNELGlCQUF5QixFQUF1QjtJQUNuRSxJQUFJLENBQUNBLGlCQUFpQixHQUFHQSxpQkFBaUI7SUFDMUMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLG1CQUFtQkEsQ0FBQSxFQUFXO0lBQzVCLE9BQU8sSUFBSSxDQUFDQyxnQkFBZ0I7RUFDOUI7O0VBRUFDLG1CQUFtQkEsQ0FBQ0QsZ0JBQXdCLEVBQXVCO0lBQ2pFLElBQUksQ0FBQ0EsZ0JBQWdCLEdBQUdBLGdCQUFnQjtJQUN4QyxPQUFPLElBQUk7RUFDYjs7RUFFQUwsYUFBYUEsQ0FBQSxFQUFXO0lBQ3RCLE9BQU8sSUFBSSxDQUFDTCxVQUFVO0VBQ3hCOztFQUVBWSxhQUFhQSxDQUFDWixVQUFrQixFQUF1QjtJQUNyRCxJQUFJLENBQUNBLFVBQVUsR0FBR0EsVUFBVTtJQUM1QixPQUFPLElBQUk7RUFDYjs7RUFFQUcsaUJBQWlCQSxDQUFBLEVBQVc7SUFDMUIsT0FBTyxJQUFJLENBQUNOLGNBQWM7RUFDNUI7O0VBRUFnQixpQkFBaUJBLENBQUNoQixjQUFzQixFQUF1QjtJQUM3RCxJQUFJLENBQUNBLGNBQWMsR0FBR0EsY0FBYztJQUNwQyxPQUFPLElBQUk7RUFDYjs7RUFFQWlCLFNBQVNBLENBQUEsRUFBVztJQUNsQixPQUFPLElBQUksQ0FBQ0MsTUFBTTtFQUNwQjs7RUFFQUMsU0FBU0EsQ0FBQ0QsTUFBYyxFQUF1QjtJQUM3QyxJQUFJLENBQUNBLE1BQU0sR0FBR0EsTUFBTTtJQUNwQixPQUFPLElBQUk7RUFDYjs7RUFFQUUsV0FBV0EsQ0FBQSxFQUFXO0lBQ3BCLE9BQU8sSUFBSSxDQUFDQyxNQUFNO0VBQ3BCOztFQUVBQyxXQUFXQSxDQUFDRCxNQUFjLEVBQXVCO0lBQy9DLElBQUksQ0FBQ0EsTUFBTSxHQUFHQSxNQUFNO0lBQ3BCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxpQkFBaUJBLENBQUEsRUFBVztJQUMxQixPQUFPLElBQUksQ0FBQ0MsY0FBYztFQUM1Qjs7RUFFQUMsaUJBQWlCQSxDQUFDRCxjQUFzQixFQUF1QjtJQUM3RCxJQUFJLENBQUNBLGNBQWMsR0FBR0EsY0FBYztJQUNwQyxPQUFPLElBQUk7RUFDYjs7RUFFQUUsYUFBYUEsQ0FBQSxFQUFXO0lBQ3RCLE9BQU8sSUFBSSxDQUFDUixNQUFNO0VBQ3BCOztFQUVBUyxhQUFhQSxDQUFDQyxVQUFrQixFQUF1QjtJQUNyRCxJQUFJLENBQUNBLFVBQVUsR0FBR0EsVUFBVTtJQUM1QixPQUFPLElBQUk7RUFDYjs7RUFFQUMsV0FBV0EsQ0FBQSxFQUFXO0lBQ3BCLE9BQU8sSUFBSSxDQUFDQyxRQUFRO0VBQ3RCOztFQUVBQyxXQUFXQSxDQUFDRCxRQUFnQixFQUF1QjtJQUNqRCxJQUFJLENBQUNBLFFBQVEsR0FBR0EsUUFBUTtJQUN4QixPQUFPLElBQUk7RUFDYjs7RUFFQUUsZUFBZUEsQ0FBQSxFQUFXO0lBQ3hCLE9BQU8sSUFBSSxDQUFDQyxZQUFZO0VBQzFCOztFQUVBQyxlQUFlQSxDQUFDRCxZQUFvQixFQUF1QjtJQUN6RCxJQUFJLENBQUNBLFlBQVksR0FBR0EsWUFBWTtJQUNoQyxPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNFLE9BQUEsQ0FBQUMsT0FBQSxHQUFBekMsbUJBQUEifQ== \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroConnectionSpan.d.ts b/dist/src/main/ts/daemon/model/MoneroConnectionSpan.d.ts new file mode 100644 index 000000000..4bc3fb615 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroConnectionSpan.d.ts @@ -0,0 +1,28 @@ +/** + * Monero daemon connection span. + */ +export default class MoneroConnectionSpan { + connectionId: string; + numBlocks: number; + remoteAddress: string; + rate: number; + speed: number; + size: number; + startHeight: number; + constructor(span?: any); + toJson(): any; + getConnectionId(): string; + setConnectionId(connectionId: string): MoneroConnectionSpan; + getNumBlocks(): number; + setNumBlocks(numBlocks: number): MoneroConnectionSpan; + getRemoteAddress(): string; + setRemoteAddress(remoteAddress: string): MoneroConnectionSpan; + getRate(): number; + setRate(rate: number): MoneroConnectionSpan; + getSpeed(): number; + setSpeed(speed: number): MoneroConnectionSpan; + getSize(): number; + setSize(size: number): MoneroConnectionSpan; + getStartHeight(): number; + setStartHeight(startHeight: number): MoneroConnectionSpan; +} diff --git a/dist/src/main/ts/daemon/model/MoneroConnectionSpan.js b/dist/src/main/ts/daemon/model/MoneroConnectionSpan.js new file mode 100644 index 000000000..be0ff7863 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroConnectionSpan.js @@ -0,0 +1,85 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Monero daemon connection span. + */ +class MoneroConnectionSpan { + + + + + + + + + + constructor(span) { + Object.assign(this, span); + } + + toJson() { + return Object.assign({}, this); + } + + getConnectionId() { + return this.connectionId; + } + + setConnectionId(connectionId) { + this.connectionId = connectionId; + return this; + } + + getNumBlocks() { + return this.numBlocks; + } + + setNumBlocks(numBlocks) { + this.numBlocks = numBlocks; + return this; + } + + getRemoteAddress() { + return this.remoteAddress; + } + + setRemoteAddress(remoteAddress) { + this.remoteAddress = remoteAddress; + return this; + } + + getRate() { + return this.rate; + } + + setRate(rate) { + this.rate = rate; + return this; + } + + getSpeed() { + return this.speed; + } + + setSpeed(speed) { + this.speed = speed; + return this; + } + + getSize() { + return this.size; + } + + setSize(size) { + this.size = size; + return this; + } + + getStartHeight() { + return this.startHeight; + } + + setStartHeight(startHeight) { + this.startHeight = startHeight; + return this; + } +}exports.default = MoneroConnectionSpan; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9Db25uZWN0aW9uU3BhbiIsImNvbnN0cnVjdG9yIiwic3BhbiIsIk9iamVjdCIsImFzc2lnbiIsInRvSnNvbiIsImdldENvbm5lY3Rpb25JZCIsImNvbm5lY3Rpb25JZCIsInNldENvbm5lY3Rpb25JZCIsImdldE51bUJsb2NrcyIsIm51bUJsb2NrcyIsInNldE51bUJsb2NrcyIsImdldFJlbW90ZUFkZHJlc3MiLCJyZW1vdGVBZGRyZXNzIiwic2V0UmVtb3RlQWRkcmVzcyIsImdldFJhdGUiLCJyYXRlIiwic2V0UmF0ZSIsImdldFNwZWVkIiwic3BlZWQiLCJzZXRTcGVlZCIsImdldFNpemUiLCJzaXplIiwic2V0U2l6ZSIsImdldFN0YXJ0SGVpZ2h0Iiwic3RhcnRIZWlnaHQiLCJzZXRTdGFydEhlaWdodCIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvZGFlbW9uL21vZGVsL01vbmVyb0Nvbm5lY3Rpb25TcGFuLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTW9uZXJvIGRhZW1vbiBjb25uZWN0aW9uIHNwYW4uXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0Nvbm5lY3Rpb25TcGFuIHtcblxuICBjb25uZWN0aW9uSWQ6IHN0cmluZztcbiAgbnVtQmxvY2tzOiBudW1iZXI7XG4gIHJlbW90ZUFkZHJlc3M6IHN0cmluZztcbiAgcmF0ZTogbnVtYmVyO1xuICBzcGVlZDogbnVtYmVyO1xuICBzaXplOiBudW1iZXI7XG4gIHN0YXJ0SGVpZ2h0OiBudW1iZXI7XG4gIFxuICBjb25zdHJ1Y3RvcihzcGFuPzogYW55KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCBzcGFuKTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICB9XG4gIFxuICBnZXRDb25uZWN0aW9uSWQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5jb25uZWN0aW9uSWQ7XG4gIH1cblxuICBzZXRDb25uZWN0aW9uSWQoY29ubmVjdGlvbklkOiBzdHJpbmcpOiBNb25lcm9Db25uZWN0aW9uU3BhbiB7XG4gICAgdGhpcy5jb25uZWN0aW9uSWQgPSBjb25uZWN0aW9uSWQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldE51bUJsb2NrcygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLm51bUJsb2NrcztcbiAgfVxuXG4gIHNldE51bUJsb2NrcyhudW1CbG9ja3M6IG51bWJlcik6IE1vbmVyb0Nvbm5lY3Rpb25TcGFuIHtcbiAgICB0aGlzLm51bUJsb2NrcyA9IG51bUJsb2NrcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0UmVtb3RlQWRkcmVzcygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnJlbW90ZUFkZHJlc3M7XG4gIH1cblxuICBzZXRSZW1vdGVBZGRyZXNzKHJlbW90ZUFkZHJlc3M6IHN0cmluZyk6IE1vbmVyb0Nvbm5lY3Rpb25TcGFuIHtcbiAgICB0aGlzLnJlbW90ZUFkZHJlc3MgPSByZW1vdGVBZGRyZXNzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRSYXRlKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMucmF0ZTtcbiAgfVxuXG4gIHNldFJhdGUocmF0ZTogbnVtYmVyKTogTW9uZXJvQ29ubmVjdGlvblNwYW4ge1xuICAgIHRoaXMucmF0ZSA9IHJhdGU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFNwZWVkKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuc3BlZWQ7XG4gIH1cblxuICBzZXRTcGVlZChzcGVlZDogbnVtYmVyKTogTW9uZXJvQ29ubmVjdGlvblNwYW4ge1xuICAgIHRoaXMuc3BlZWQgPSBzcGVlZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U2l6ZSgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnNpemU7XG4gIH1cbiAgXG4gIHNldFNpemUoc2l6ZTogbnVtYmVyKTogTW9uZXJvQ29ubmVjdGlvblNwYW4ge1xuICAgIHRoaXMuc2l6ZSA9IHNpemU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFN0YXJ0SGVpZ2h0KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuc3RhcnRIZWlnaHQ7XG4gIH1cbiAgXG4gIHNldFN0YXJ0SGVpZ2h0KHN0YXJ0SGVpZ2h0OiBudW1iZXIpOiBNb25lcm9Db25uZWN0aW9uU3BhbiB7XG4gICAgdGhpcy5zdGFydEhlaWdodCA9IHN0YXJ0SGVpZ2h0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJxR0FBQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSxvQkFBb0IsQ0FBQzs7Ozs7Ozs7OztFQVV4Q0MsV0FBV0EsQ0FBQ0MsSUFBVSxFQUFFO0lBQ3RCQyxNQUFNLENBQUNDLE1BQU0sQ0FBQyxJQUFJLEVBQUVGLElBQUksQ0FBQztFQUMzQjs7RUFFQUcsTUFBTUEsQ0FBQSxFQUFRO0lBQ1osT0FBT0YsTUFBTSxDQUFDQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO0VBQ2hDOztFQUVBRSxlQUFlQSxDQUFBLEVBQVc7SUFDeEIsT0FBTyxJQUFJLENBQUNDLFlBQVk7RUFDMUI7O0VBRUFDLGVBQWVBLENBQUNELFlBQW9CLEVBQXdCO0lBQzFELElBQUksQ0FBQ0EsWUFBWSxHQUFHQSxZQUFZO0lBQ2hDLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxZQUFZQSxDQUFBLEVBQVc7SUFDckIsT0FBTyxJQUFJLENBQUNDLFNBQVM7RUFDdkI7O0VBRUFDLFlBQVlBLENBQUNELFNBQWlCLEVBQXdCO0lBQ3BELElBQUksQ0FBQ0EsU0FBUyxHQUFHQSxTQUFTO0lBQzFCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxnQkFBZ0JBLENBQUEsRUFBVztJQUN6QixPQUFPLElBQUksQ0FBQ0MsYUFBYTtFQUMzQjs7RUFFQUMsZ0JBQWdCQSxDQUFDRCxhQUFxQixFQUF3QjtJQUM1RCxJQUFJLENBQUNBLGFBQWEsR0FBR0EsYUFBYTtJQUNsQyxPQUFPLElBQUk7RUFDYjs7RUFFQUUsT0FBT0EsQ0FBQSxFQUFXO0lBQ2hCLE9BQU8sSUFBSSxDQUFDQyxJQUFJO0VBQ2xCOztFQUVBQyxPQUFPQSxDQUFDRCxJQUFZLEVBQXdCO0lBQzFDLElBQUksQ0FBQ0EsSUFBSSxHQUFHQSxJQUFJO0lBQ2hCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxRQUFRQSxDQUFBLEVBQVc7SUFDakIsT0FBTyxJQUFJLENBQUNDLEtBQUs7RUFDbkI7O0VBRUFDLFFBQVFBLENBQUNELEtBQWEsRUFBd0I7SUFDNUMsSUFBSSxDQUFDQSxLQUFLLEdBQUdBLEtBQUs7SUFDbEIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLE9BQU9BLENBQUEsRUFBVztJQUNoQixPQUFPLElBQUksQ0FBQ0MsSUFBSTtFQUNsQjs7RUFFQUMsT0FBT0EsQ0FBQ0QsSUFBWSxFQUF3QjtJQUMxQyxJQUFJLENBQUNBLElBQUksR0FBR0EsSUFBSTtJQUNoQixPQUFPLElBQUk7RUFDYjs7RUFFQUUsY0FBY0EsQ0FBQSxFQUFXO0lBQ3ZCLE9BQU8sSUFBSSxDQUFDQyxXQUFXO0VBQ3pCOztFQUVBQyxjQUFjQSxDQUFDRCxXQUFtQixFQUF3QjtJQUN4RCxJQUFJLENBQUNBLFdBQVcsR0FBR0EsV0FBVztJQUM5QixPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNFLE9BQUEsQ0FBQUMsT0FBQSxHQUFBNUIsb0JBQUEifQ== \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroDaemonConfig.d.ts b/dist/src/main/ts/daemon/model/MoneroDaemonConfig.d.ts new file mode 100644 index 000000000..0a22de1eb --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroDaemonConfig.d.ts @@ -0,0 +1,34 @@ +import MoneroRpcConnection from "../../common/MoneroRpcConnection"; +/** + * Configuration to connect to monerod. + */ +export default class MoneroDaemonConfig { + /** Server config to monerod. */ + server: string | Partial; + /** Proxy requests to monerod to a worker (default true). */ + proxyToWorker: boolean; + /** Command to start monerod as a child process. */ + cmd: string[]; + /** Interval in milliseconds to poll the daemon for updates (default 20000). */ + pollInterval: number; + /** + * Construct a configuration to open or create a wallet. + * + * @param {Partial} [config] - MoneroDaemonConfig to construct from (optional) + * @param {string|Partial} [config.server] - uri or MoneroRpcConnection to the daemon (optional) + * @param {boolean} [config.proxyToWorker] - proxy daemon requests to a worker (default true) + * @param {string[]} [config.cmd] - command to start monerod (optional) + * @param {number} [config.pollInterval] - interval in milliseconds to poll the daemon for updates (default 20000) + */ + constructor(config?: Partial); + copy(): MoneroDaemonConfig; + toJson(): any; + getServer(): MoneroRpcConnection; + setServer(server: Partial | string): MoneroDaemonConfig; + getProxyToWorker(): boolean; + setProxyToWorker(proxyToWorker: boolean): MoneroDaemonConfig; + getCmd(): string[]; + setCmd(cmd: string[]): MoneroDaemonConfig; + getPollInterval(): number; + setPollInterval(pollInterval: number): MoneroDaemonConfig; +} diff --git a/dist/src/main/ts/daemon/model/MoneroDaemonConfig.js b/dist/src/main/ts/daemon/model/MoneroDaemonConfig.js new file mode 100644 index 000000000..2871c7723 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroDaemonConfig.js @@ -0,0 +1,82 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _MoneroRpcConnection = _interopRequireDefault(require("../../common/MoneroRpcConnection")); + +/** + * Configuration to connect to monerod. + */ +class MoneroDaemonConfig { + + /** Server config to monerod. */ + + + /** Proxy requests to monerod to a worker (default true). */ + + + /** Command to start monerod as a child process. */ + + + /** Interval in milliseconds to poll the daemon for updates (default 20000). */ + + + /** + * Construct a configuration to open or create a wallet. + * + * @param {Partial} [config] - MoneroDaemonConfig to construct from (optional) + * @param {string|Partial} [config.server] - uri or MoneroRpcConnection to the daemon (optional) + * @param {boolean} [config.proxyToWorker] - proxy daemon requests to a worker (default true) + * @param {string[]} [config.cmd] - command to start monerod (optional) + * @param {number} [config.pollInterval] - interval in milliseconds to poll the daemon for updates (default 20000) + */ + constructor(config) { + Object.assign(this, config); + if (this.server) this.setServer(this.server); + this.setProxyToWorker(this.proxyToWorker); + } + + copy() { + return new MoneroDaemonConfig(this); + } + + toJson() { + let json = Object.assign({}, this); + if (json.server) json.server = json.server.toJson(); + return json; + } + + getServer() { + return this.server; + } + + setServer(server) { + if (server && !(server instanceof _MoneroRpcConnection.default)) server = new _MoneroRpcConnection.default(server); + this.server = server; + return this; + } + + getProxyToWorker() { + return this.proxyToWorker; + } + + setProxyToWorker(proxyToWorker) { + this.proxyToWorker = proxyToWorker; + return this; + } + + getCmd() { + return this.cmd; + } + + setCmd(cmd) { + this.cmd = cmd; + return this; + } + + getPollInterval() { + return this.pollInterval; + } + + setPollInterval(pollInterval) { + this.pollInterval = pollInterval; + return this; + } +}exports.default = MoneroDaemonConfig; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfTW9uZXJvUnBjQ29ubmVjdGlvbiIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiTW9uZXJvRGFlbW9uQ29uZmlnIiwiY29uc3RydWN0b3IiLCJjb25maWciLCJPYmplY3QiLCJhc3NpZ24iLCJzZXJ2ZXIiLCJzZXRTZXJ2ZXIiLCJzZXRQcm94eVRvV29ya2VyIiwicHJveHlUb1dvcmtlciIsImNvcHkiLCJ0b0pzb24iLCJqc29uIiwiZ2V0U2VydmVyIiwiTW9uZXJvUnBjQ29ubmVjdGlvbiIsImdldFByb3h5VG9Xb3JrZXIiLCJnZXRDbWQiLCJjbWQiLCJzZXRDbWQiLCJnZXRQb2xsSW50ZXJ2YWwiLCJwb2xsSW50ZXJ2YWwiLCJzZXRQb2xsSW50ZXJ2YWwiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2RhZW1vbi9tb2RlbC9Nb25lcm9EYWVtb25Db25maWcudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IE1vbmVyb1JwY0Nvbm5lY3Rpb24gZnJvbSBcIi4uLy4uL2NvbW1vbi9Nb25lcm9ScGNDb25uZWN0aW9uXCI7XG5cbi8qKlxuICogQ29uZmlndXJhdGlvbiB0byBjb25uZWN0IHRvIG1vbmVyb2QuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0RhZW1vbkNvbmZpZyB7XG5cbiAgLyoqIFNlcnZlciBjb25maWcgdG8gbW9uZXJvZC4gKi9cbiAgc2VydmVyOiBzdHJpbmcgfCBQYXJ0aWFsPE1vbmVyb1JwY0Nvbm5lY3Rpb24+O1xuXG4gIC8qKiBQcm94eSByZXF1ZXN0cyB0byBtb25lcm9kIHRvIGEgd29ya2VyIChkZWZhdWx0IHRydWUpLiAqL1xuICBwcm94eVRvV29ya2VyOiBib29sZWFuO1xuXG4gIC8qKiBDb21tYW5kIHRvIHN0YXJ0IG1vbmVyb2QgYXMgYSBjaGlsZCBwcm9jZXNzLiAqL1xuICBjbWQ6IHN0cmluZ1tdO1xuXG4gIC8qKiBJbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgdG8gcG9sbCB0aGUgZGFlbW9uIGZvciB1cGRhdGVzIChkZWZhdWx0IDIwMDAwKS4gKi9cbiAgcG9sbEludGVydmFsOiBudW1iZXI7XG4gIFxuICAvKipcbiAgICogQ29uc3RydWN0IGEgY29uZmlndXJhdGlvbiB0byBvcGVuIG9yIGNyZWF0ZSBhIHdhbGxldC5cbiAgICogXG4gICAqIEBwYXJhbSB7UGFydGlhbDxNb25lcm9EYWVtb25Db25maWc+fSBbY29uZmlnXSAtIE1vbmVyb0RhZW1vbkNvbmZpZyB0byBjb25zdHJ1Y3QgZnJvbSAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7c3RyaW5nfFBhcnRpYWw8TW9uZXJvUnBjQ29ubmVjdGlvbj59IFtjb25maWcuc2VydmVyXSAtIHVyaSBvciBNb25lcm9ScGNDb25uZWN0aW9uIHRvIHRoZSBkYWVtb24gKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtjb25maWcucHJveHlUb1dvcmtlcl0gLSBwcm94eSBkYWVtb24gcmVxdWVzdHMgdG8gYSB3b3JrZXIgKGRlZmF1bHQgdHJ1ZSlcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gW2NvbmZpZy5jbWRdIC0gY29tbWFuZCB0byBzdGFydCBtb25lcm9kIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtjb25maWcucG9sbEludGVydmFsXSAtIGludGVydmFsIGluIG1pbGxpc2Vjb25kcyB0byBwb2xsIHRoZSBkYWVtb24gZm9yIHVwZGF0ZXMgKGRlZmF1bHQgMjAwMDApXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihjb25maWc/OiBQYXJ0aWFsPE1vbmVyb0RhZW1vbkNvbmZpZz4pIHtcbiAgICBPYmplY3QuYXNzaWduKHRoaXMsIGNvbmZpZyk7XG4gICAgaWYgKHRoaXMuc2VydmVyKSB0aGlzLnNldFNlcnZlcih0aGlzLnNlcnZlcik7XG4gICAgdGhpcy5zZXRQcm94eVRvV29ya2VyKHRoaXMucHJveHlUb1dvcmtlcik7XG4gIH1cblxuICBjb3B5KCk6IE1vbmVyb0RhZW1vbkNvbmZpZyB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9EYWVtb25Db25maWcodGhpcyk7XG4gIH1cbiAgXG4gIHRvSnNvbigpOiBhbnkge1xuICAgIGxldCBqc29uOiBhbnkgPSBPYmplY3QuYXNzaWduKHt9LCB0aGlzKTtcbiAgICBpZiAoanNvbi5zZXJ2ZXIpIGpzb24uc2VydmVyID0ganNvbi5zZXJ2ZXIudG9Kc29uKCk7XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIGdldFNlcnZlcigpOiBNb25lcm9ScGNDb25uZWN0aW9uIHtcbiAgICByZXR1cm4gdGhpcy5zZXJ2ZXIgYXMgTW9uZXJvUnBjQ29ubmVjdGlvbjtcbiAgfVxuICBcbiAgc2V0U2VydmVyKHNlcnZlcjogUGFydGlhbDxNb25lcm9ScGNDb25uZWN0aW9uPiB8IHN0cmluZyk6IE1vbmVyb0RhZW1vbkNvbmZpZyB7XG4gICAgaWYgKHNlcnZlciAmJiAhKHNlcnZlciBpbnN0YW5jZW9mIE1vbmVyb1JwY0Nvbm5lY3Rpb24pKSBzZXJ2ZXIgPSBuZXcgTW9uZXJvUnBjQ29ubmVjdGlvbihzZXJ2ZXIpO1xuICAgIHRoaXMuc2VydmVyID0gc2VydmVyIGFzIE1vbmVyb1JwY0Nvbm5lY3Rpb247XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFByb3h5VG9Xb3JrZXIoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMucHJveHlUb1dvcmtlcjtcbiAgfVxuICBcbiAgc2V0UHJveHlUb1dvcmtlcihwcm94eVRvV29ya2VyOiBib29sZWFuKTogTW9uZXJvRGFlbW9uQ29uZmlnIHtcbiAgICB0aGlzLnByb3h5VG9Xb3JrZXIgPSBwcm94eVRvV29ya2VyO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0Q21kKCk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gdGhpcy5jbWQ7XG4gIH1cblxuICBzZXRDbWQoY21kOiBzdHJpbmdbXSk6IE1vbmVyb0RhZW1vbkNvbmZpZyB7XG4gICAgdGhpcy5jbWQgPSBjbWQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRQb2xsSW50ZXJ2YWwoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5wb2xsSW50ZXJ2YWw7XG4gIH1cblxuICBzZXRQb2xsSW50ZXJ2YWwocG9sbEludGVydmFsOiBudW1iZXIpOiBNb25lcm9EYWVtb25Db25maWcge1xuICAgIHRoaXMucG9sbEludGVydmFsID0gcG9sbEludGVydmFsO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59Il0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsb0JBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTs7QUFFQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQyxrQkFBa0IsQ0FBQzs7RUFFdEM7OztFQUdBOzs7RUFHQTs7O0VBR0E7OztFQUdBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNFQyxXQUFXQSxDQUFDQyxNQUFvQyxFQUFFO0lBQ2hEQyxNQUFNLENBQUNDLE1BQU0sQ0FBQyxJQUFJLEVBQUVGLE1BQU0sQ0FBQztJQUMzQixJQUFJLElBQUksQ0FBQ0csTUFBTSxFQUFFLElBQUksQ0FBQ0MsU0FBUyxDQUFDLElBQUksQ0FBQ0QsTUFBTSxDQUFDO0lBQzVDLElBQUksQ0FBQ0UsZ0JBQWdCLENBQUMsSUFBSSxDQUFDQyxhQUFhLENBQUM7RUFDM0M7O0VBRUFDLElBQUlBLENBQUEsRUFBdUI7SUFDekIsT0FBTyxJQUFJVCxrQkFBa0IsQ0FBQyxJQUFJLENBQUM7RUFDckM7O0VBRUFVLE1BQU1BLENBQUEsRUFBUTtJQUNaLElBQUlDLElBQVMsR0FBR1IsTUFBTSxDQUFDQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQ3ZDLElBQUlPLElBQUksQ0FBQ04sTUFBTSxFQUFFTSxJQUFJLENBQUNOLE1BQU0sR0FBR00sSUFBSSxDQUFDTixNQUFNLENBQUNLLE1BQU0sQ0FBQyxDQUFDO0lBQ25ELE9BQU9DLElBQUk7RUFDYjs7RUFFQUMsU0FBU0EsQ0FBQSxFQUF3QjtJQUMvQixPQUFPLElBQUksQ0FBQ1AsTUFBTTtFQUNwQjs7RUFFQUMsU0FBU0EsQ0FBQ0QsTUFBNkMsRUFBc0I7SUFDM0UsSUFBSUEsTUFBTSxJQUFJLEVBQUVBLE1BQU0sWUFBWVEsNEJBQW1CLENBQUMsRUFBRVIsTUFBTSxHQUFHLElBQUlRLDRCQUFtQixDQUFDUixNQUFNLENBQUM7SUFDaEcsSUFBSSxDQUFDQSxNQUFNLEdBQUdBLE1BQTZCO0lBQzNDLE9BQU8sSUFBSTtFQUNiOztFQUVBUyxnQkFBZ0JBLENBQUEsRUFBWTtJQUMxQixPQUFPLElBQUksQ0FBQ04sYUFBYTtFQUMzQjs7RUFFQUQsZ0JBQWdCQSxDQUFDQyxhQUFzQixFQUFzQjtJQUMzRCxJQUFJLENBQUNBLGFBQWEsR0FBR0EsYUFBYTtJQUNsQyxPQUFPLElBQUk7RUFDYjs7RUFFQU8sTUFBTUEsQ0FBQSxFQUFhO0lBQ2pCLE9BQU8sSUFBSSxDQUFDQyxHQUFHO0VBQ2pCOztFQUVBQyxNQUFNQSxDQUFDRCxHQUFhLEVBQXNCO0lBQ3hDLElBQUksQ0FBQ0EsR0FBRyxHQUFHQSxHQUFHO0lBQ2QsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLGVBQWVBLENBQUEsRUFBVztJQUN4QixPQUFPLElBQUksQ0FBQ0MsWUFBWTtFQUMxQjs7RUFFQUMsZUFBZUEsQ0FBQ0QsWUFBb0IsRUFBc0I7SUFDeEQsSUFBSSxDQUFDQSxZQUFZLEdBQUdBLFlBQVk7SUFDaEMsT0FBTyxJQUFJO0VBQ2I7QUFDRixDQUFDRSxPQUFBLENBQUFDLE9BQUEsR0FBQXRCLGtCQUFBIn0= \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroDaemonInfo.d.ts b/dist/src/main/ts/daemon/model/MoneroDaemonInfo.d.ts new file mode 100644 index 000000000..aa2e4a7c9 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroDaemonInfo.d.ts @@ -0,0 +1,106 @@ +/** + * Monero daemon info. + */ +export default class MoneroDaemonInfo { + version: string; + numAltBlocks: number; + blockSizeLimit: number; + blockSizeMedian: number; + blockWeightLimit: number; + blockWeightMedian: number; + bootstrapDaemonAddress: string; + difficulty: bigint; + cumulativeDifficulty: bigint; + freeSpace: bigint; + numOfflinePeers: number; + numOnlinePeers: number; + height: number; + heightWithoutBootstrap: number; + networkType: string; + isOffline: boolean; + numIncomingConnections: number; + numOutgoingConnections: number; + numRpcConnections: number; + startTimestamp: number; + adjustedTimestamp: number; + target: number; + targetHeight: number; + topBlockHash: string; + numTxs: number; + numTxsPool: number; + wasBootstrapEverUsed: boolean; + databaseSize: number; + updateAvailable: boolean; + credits: bigint; + isBusySyncing: boolean; + isSynchronized: boolean; + isRestricted: boolean; + constructor(info?: Partial); + toJson(): any; + getVersion(): string; + setVersion(version: string): MoneroDaemonInfo; + getNumAltBlocks(): number; + setNumAltBlocks(numAltBlocks: number): MoneroDaemonInfo; + getBlockSizeLimit(): number; + setBlockSizeLimit(blockSizeLimit: number): MoneroDaemonInfo; + getBlockSizeMedian(): number; + setBlockSizeMedian(blockSizeMedian: number): MoneroDaemonInfo; + getBlockWeightLimit(): number; + setBlockWeightLimit(blockWeightLimit: number): MoneroDaemonInfo; + getBlockWeightMedian(): number; + setBlockWeightMedian(blockWeightMedian: number): MoneroDaemonInfo; + getBootstrapDaemonAddress(): string; + setBootstrapDaemonAddress(bootstrapDaemonAddress: any): MoneroDaemonInfo; + getDifficulty(): bigint; + setDifficulty(difficulty: bigint): MoneroDaemonInfo; + getCumulativeDifficulty(): bigint; + setCumulativeDifficulty(cumulativeDifficulty: bigint): MoneroDaemonInfo; + getFreeSpace(): bigint; + setFreeSpace(freeSpace: bigint): MoneroDaemonInfo; + getNumOfflinePeers(): number; + setNumOfflinePeers(numOfflinePeers: number): MoneroDaemonInfo; + getNumOnlinePeers(): number; + setNumOnlinePeers(numOnlinePeers: number): MoneroDaemonInfo; + getHeight(): number; + setHeight(height: number): MoneroDaemonInfo; + getHeightWithoutBootstrap(): number; + setHeightWithoutBootstrap(heightWithoutBootstrap: number): MoneroDaemonInfo; + getNetworkType(): string; + setNetworkType(networkType: string): this; + getIsOffline(): boolean; + setIsOffline(isOffline: boolean): MoneroDaemonInfo; + getNumIncomingConnections(): number; + setNumIncomingConnections(numIncomingConnections: number): MoneroDaemonInfo; + getNumOutgoingConnections(): number; + setNumOutgoingConnections(numOutgoingConnections: number): MoneroDaemonInfo; + getNumRpcConnections(): number; + setNumRpcConnections(numRpcConnections: number): MoneroDaemonInfo; + getStartTimestamp(): number; + setStartTimestamp(startTimestamp: number): MoneroDaemonInfo; + getAdjustedTimestamp(): number; + setAdjustedTimestamp(adjustedTimestamp: number): MoneroDaemonInfo; + getTarget(): number; + setTarget(target: number): MoneroDaemonInfo; + getTargetHeight(): number; + setTargetHeight(targetHeight: number): MoneroDaemonInfo; + getTopBlockHash(): string; + setTopBlockHash(topBlockHash: any): MoneroDaemonInfo; + getNumTxs(): number; + setNumTxs(numTxs: number): MoneroDaemonInfo; + getNumTxsPool(): number; + setNumTxsPool(numTxsPool: any): MoneroDaemonInfo; + getWasBootstrapEverUsed(): boolean; + setWasBootstrapEverUsed(wasBootstrapEverUsed: any): MoneroDaemonInfo; + getDatabaseSize(): number; + setDatabaseSize(databaseSize: number): MoneroDaemonInfo; + getUpdateAvailable(): boolean; + setUpdateAvailable(updateAvailable: boolean): MoneroDaemonInfo; + getCredits(): bigint; + setCredits(credits: bigint): MoneroDaemonInfo; + getIsBusySyncing(): boolean; + setIsBusySyncing(isBusySyncing: boolean): MoneroDaemonInfo; + getIsSynchronized(): boolean; + setIsSynchronized(isSynchronized: boolean): MoneroDaemonInfo; + getIsRestricted(): boolean; + setIsRestricted(isRestricted: boolean): MoneroDaemonInfo; +} diff --git a/dist/src/main/ts/daemon/model/MoneroDaemonInfo.js b/dist/src/main/ts/daemon/model/MoneroDaemonInfo.js new file mode 100644 index 000000000..fb0a1a553 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroDaemonInfo.js @@ -0,0 +1,354 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Monero daemon info. + */ +class MoneroDaemonInfo { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + constructor(info) { + Object.assign(this, info); + + // deserialize bigints + if (this.difficulty !== undefined && typeof this.difficulty !== "bigint") this.difficulty = BigInt(this.difficulty); + if (this.cumulativeDifficulty !== undefined && typeof this.cumulativeDifficulty !== "bigint") this.cumulativeDifficulty = BigInt(this.cumulativeDifficulty); + if (this.credits !== undefined && typeof this.credits !== "bigint") this.credits = BigInt(this.credits); + } + + toJson() { + let json = Object.assign([], this); + if (json.difficulty !== undefined) json.difficulty = json.difficulty.toString(); + if (json.cumulativeDifficulty !== undefined) json.cumulativeDifficulty = json.cumulativeDifficulty.toString(); + if (json.credits !== undefined) json.credits = json.credits.toString(); + return json; + } + + getVersion() { + return this.version; + } + + setVersion(version) { + this.version = version; + return this; + } + + getNumAltBlocks() { + return this.numAltBlocks; + } + + setNumAltBlocks(numAltBlocks) { + this.numAltBlocks = numAltBlocks; + return this; + } + + getBlockSizeLimit() { + return this.blockSizeLimit; + } + + setBlockSizeLimit(blockSizeLimit) { + this.blockSizeLimit = blockSizeLimit; + return this; + } + + getBlockSizeMedian() { + return this.blockSizeMedian; + } + + setBlockSizeMedian(blockSizeMedian) { + this.blockSizeMedian = blockSizeMedian; + return this; + } + + getBlockWeightLimit() { + return this.blockWeightLimit; + } + + setBlockWeightLimit(blockWeightLimit) { + this.blockWeightLimit = blockWeightLimit; + return this; + } + + getBlockWeightMedian() { + return this.blockWeightMedian; + } + + setBlockWeightMedian(blockWeightMedian) { + this.blockWeightMedian = blockWeightMedian; + return this; + } + + getBootstrapDaemonAddress() { + return this.bootstrapDaemonAddress; + } + + setBootstrapDaemonAddress(bootstrapDaemonAddress) { + this.bootstrapDaemonAddress = bootstrapDaemonAddress; + return this; + } + + getDifficulty() { + return this.difficulty; + } + + setDifficulty(difficulty) { + this.difficulty = difficulty; + return this; + } + + getCumulativeDifficulty() { + return this.cumulativeDifficulty; + } + + setCumulativeDifficulty(cumulativeDifficulty) { + this.cumulativeDifficulty = cumulativeDifficulty; + return this; + } + + getFreeSpace() { + return this.freeSpace; + } + + setFreeSpace(freeSpace) { + this.freeSpace = freeSpace; + return this; + } + + getNumOfflinePeers() { + return this.numOfflinePeers; + } + + setNumOfflinePeers(numOfflinePeers) { + this.numOfflinePeers = numOfflinePeers; + return this; + } + + getNumOnlinePeers() { + return this.numOnlinePeers; + } + + setNumOnlinePeers(numOnlinePeers) { + this.numOnlinePeers = numOnlinePeers; + return this; + } + + getHeight() { + return this.height; + } + + setHeight(height) { + this.height = height; + return this; + } + + getHeightWithoutBootstrap() { + return this.heightWithoutBootstrap; + } + + setHeightWithoutBootstrap(heightWithoutBootstrap) { + this.heightWithoutBootstrap = heightWithoutBootstrap; + return this; + } + + getNetworkType() { + return this.networkType; + } + + setNetworkType(networkType) { + this.networkType = networkType; + return this; + } + + getIsOffline() { + return this.isOffline; + } + + setIsOffline(isOffline) { + this.isOffline = isOffline; + return this; + } + + getNumIncomingConnections() { + return this.numIncomingConnections; + } + + setNumIncomingConnections(numIncomingConnections) { + this.numIncomingConnections = numIncomingConnections; + return this; + } + + getNumOutgoingConnections() { + return this.numOutgoingConnections; + } + + setNumOutgoingConnections(numOutgoingConnections) { + this.numOutgoingConnections = numOutgoingConnections; + return this; + } + + getNumRpcConnections() { + return this.numRpcConnections; + } + + setNumRpcConnections(numRpcConnections) { + this.numRpcConnections = numRpcConnections; + return this; + } + + getStartTimestamp() { + return this.startTimestamp; + } + + setStartTimestamp(startTimestamp) { + this.startTimestamp = startTimestamp; + return this; + } + + getAdjustedTimestamp() { + return this.adjustedTimestamp; + } + + setAdjustedTimestamp(adjustedTimestamp) { + this.adjustedTimestamp = adjustedTimestamp; + return this; + } + + getTarget() { + return this.target; + } + + setTarget(target) { + this.target = target; + return this; + } + + getTargetHeight() { + return this.targetHeight; + } + + setTargetHeight(targetHeight) { + this.targetHeight = targetHeight; + return this; + } + + getTopBlockHash() { + return this.topBlockHash; + } + + setTopBlockHash(topBlockHash) { + this.topBlockHash = topBlockHash; + return this; + } + + getNumTxs() { + return this.numTxs; + } + + setNumTxs(numTxs) { + this.numTxs = numTxs; + return this; + } + + getNumTxsPool() { + return this.numTxsPool; + } + + setNumTxsPool(numTxsPool) { + this.numTxsPool = numTxsPool; + return this; + } + + getWasBootstrapEverUsed() { + return this.wasBootstrapEverUsed; + } + + setWasBootstrapEverUsed(wasBootstrapEverUsed) { + this.wasBootstrapEverUsed = wasBootstrapEverUsed; + return this; + } + + getDatabaseSize() { + return this.databaseSize; + } + + setDatabaseSize(databaseSize) { + this.databaseSize = databaseSize; + return this; + } + + getUpdateAvailable() { + return this.updateAvailable; + } + + setUpdateAvailable(updateAvailable) { + this.updateAvailable = updateAvailable; + return this; + } + + getCredits() { + return this.credits; + } + + setCredits(credits) { + this.credits = credits; + return this; + } + + getIsBusySyncing() { + return this.isBusySyncing; + } + + setIsBusySyncing(isBusySyncing) { + this.isBusySyncing = isBusySyncing; + return this; + } + + getIsSynchronized() { + return this.isSynchronized; + } + + setIsSynchronized(isSynchronized) { + this.isSynchronized = isSynchronized; + return this; + } + + getIsRestricted() { + return this.isRestricted; + } + + setIsRestricted(isRestricted) { + this.isRestricted = isRestricted; + return this; + } +}exports.default = MoneroDaemonInfo; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9EYWVtb25JbmZvIiwiY29uc3RydWN0b3IiLCJpbmZvIiwiT2JqZWN0IiwiYXNzaWduIiwiZGlmZmljdWx0eSIsInVuZGVmaW5lZCIsIkJpZ0ludCIsImN1bXVsYXRpdmVEaWZmaWN1bHR5IiwiY3JlZGl0cyIsInRvSnNvbiIsImpzb24iLCJ0b1N0cmluZyIsImdldFZlcnNpb24iLCJ2ZXJzaW9uIiwic2V0VmVyc2lvbiIsImdldE51bUFsdEJsb2NrcyIsIm51bUFsdEJsb2NrcyIsInNldE51bUFsdEJsb2NrcyIsImdldEJsb2NrU2l6ZUxpbWl0IiwiYmxvY2tTaXplTGltaXQiLCJzZXRCbG9ja1NpemVMaW1pdCIsImdldEJsb2NrU2l6ZU1lZGlhbiIsImJsb2NrU2l6ZU1lZGlhbiIsInNldEJsb2NrU2l6ZU1lZGlhbiIsImdldEJsb2NrV2VpZ2h0TGltaXQiLCJibG9ja1dlaWdodExpbWl0Iiwic2V0QmxvY2tXZWlnaHRMaW1pdCIsImdldEJsb2NrV2VpZ2h0TWVkaWFuIiwiYmxvY2tXZWlnaHRNZWRpYW4iLCJzZXRCbG9ja1dlaWdodE1lZGlhbiIsImdldEJvb3RzdHJhcERhZW1vbkFkZHJlc3MiLCJib290c3RyYXBEYWVtb25BZGRyZXNzIiwic2V0Qm9vdHN0cmFwRGFlbW9uQWRkcmVzcyIsImdldERpZmZpY3VsdHkiLCJzZXREaWZmaWN1bHR5IiwiZ2V0Q3VtdWxhdGl2ZURpZmZpY3VsdHkiLCJzZXRDdW11bGF0aXZlRGlmZmljdWx0eSIsImdldEZyZWVTcGFjZSIsImZyZWVTcGFjZSIsInNldEZyZWVTcGFjZSIsImdldE51bU9mZmxpbmVQZWVycyIsIm51bU9mZmxpbmVQZWVycyIsInNldE51bU9mZmxpbmVQZWVycyIsImdldE51bU9ubGluZVBlZXJzIiwibnVtT25saW5lUGVlcnMiLCJzZXROdW1PbmxpbmVQZWVycyIsImdldEhlaWdodCIsImhlaWdodCIsInNldEhlaWdodCIsImdldEhlaWdodFdpdGhvdXRCb290c3RyYXAiLCJoZWlnaHRXaXRob3V0Qm9vdHN0cmFwIiwic2V0SGVpZ2h0V2l0aG91dEJvb3RzdHJhcCIsImdldE5ldHdvcmtUeXBlIiwibmV0d29ya1R5cGUiLCJzZXROZXR3b3JrVHlwZSIsImdldElzT2ZmbGluZSIsImlzT2ZmbGluZSIsInNldElzT2ZmbGluZSIsImdldE51bUluY29taW5nQ29ubmVjdGlvbnMiLCJudW1JbmNvbWluZ0Nvbm5lY3Rpb25zIiwic2V0TnVtSW5jb21pbmdDb25uZWN0aW9ucyIsImdldE51bU91dGdvaW5nQ29ubmVjdGlvbnMiLCJudW1PdXRnb2luZ0Nvbm5lY3Rpb25zIiwic2V0TnVtT3V0Z29pbmdDb25uZWN0aW9ucyIsImdldE51bVJwY0Nvbm5lY3Rpb25zIiwibnVtUnBjQ29ubmVjdGlvbnMiLCJzZXROdW1ScGNDb25uZWN0aW9ucyIsImdldFN0YXJ0VGltZXN0YW1wIiwic3RhcnRUaW1lc3RhbXAiLCJzZXRTdGFydFRpbWVzdGFtcCIsImdldEFkanVzdGVkVGltZXN0YW1wIiwiYWRqdXN0ZWRUaW1lc3RhbXAiLCJzZXRBZGp1c3RlZFRpbWVzdGFtcCIsImdldFRhcmdldCIsInRhcmdldCIsInNldFRhcmdldCIsImdldFRhcmdldEhlaWdodCIsInRhcmdldEhlaWdodCIsInNldFRhcmdldEhlaWdodCIsImdldFRvcEJsb2NrSGFzaCIsInRvcEJsb2NrSGFzaCIsInNldFRvcEJsb2NrSGFzaCIsImdldE51bVR4cyIsIm51bVR4cyIsInNldE51bVR4cyIsImdldE51bVR4c1Bvb2wiLCJudW1UeHNQb29sIiwic2V0TnVtVHhzUG9vbCIsImdldFdhc0Jvb3RzdHJhcEV2ZXJVc2VkIiwid2FzQm9vdHN0cmFwRXZlclVzZWQiLCJzZXRXYXNCb290c3RyYXBFdmVyVXNlZCIsImdldERhdGFiYXNlU2l6ZSIsImRhdGFiYXNlU2l6ZSIsInNldERhdGFiYXNlU2l6ZSIsImdldFVwZGF0ZUF2YWlsYWJsZSIsInVwZGF0ZUF2YWlsYWJsZSIsInNldFVwZGF0ZUF2YWlsYWJsZSIsImdldENyZWRpdHMiLCJzZXRDcmVkaXRzIiwiZ2V0SXNCdXN5U3luY2luZyIsImlzQnVzeVN5bmNpbmciLCJzZXRJc0J1c3lTeW5jaW5nIiwiZ2V0SXNTeW5jaHJvbml6ZWQiLCJpc1N5bmNocm9uaXplZCIsInNldElzU3luY2hyb25pemVkIiwiZ2V0SXNSZXN0cmljdGVkIiwiaXNSZXN0cmljdGVkIiwic2V0SXNSZXN0cmljdGVkIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9kYWVtb24vbW9kZWwvTW9uZXJvRGFlbW9uSW5mby50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1vbmVybyBkYWVtb24gaW5mby5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTW9uZXJvRGFlbW9uSW5mbyB7XG5cbiAgdmVyc2lvbjogc3RyaW5nO1xuICBudW1BbHRCbG9ja3M6IG51bWJlcjtcbiAgYmxvY2tTaXplTGltaXQ6IG51bWJlcjtcbiAgYmxvY2tTaXplTWVkaWFuOiBudW1iZXI7XG4gIGJsb2NrV2VpZ2h0TGltaXQ6IG51bWJlcjtcbiAgYmxvY2tXZWlnaHRNZWRpYW46IG51bWJlcjtcbiAgYm9vdHN0cmFwRGFlbW9uQWRkcmVzczogc3RyaW5nO1xuICBkaWZmaWN1bHR5OiBiaWdpbnQ7XG4gIGN1bXVsYXRpdmVEaWZmaWN1bHR5OiBiaWdpbnQ7XG4gIGZyZWVTcGFjZTogYmlnaW50O1xuICBudW1PZmZsaW5lUGVlcnM6IG51bWJlcjtcbiAgbnVtT25saW5lUGVlcnM6IG51bWJlcjtcbiAgaGVpZ2h0OiBudW1iZXI7XG4gIGhlaWdodFdpdGhvdXRCb290c3RyYXA6IG51bWJlcjtcbiAgbmV0d29ya1R5cGU6IHN0cmluZztcbiAgaXNPZmZsaW5lOiBib29sZWFuO1xuICBudW1JbmNvbWluZ0Nvbm5lY3Rpb25zOiBudW1iZXI7XG4gIG51bU91dGdvaW5nQ29ubmVjdGlvbnM6IG51bWJlcjtcbiAgbnVtUnBjQ29ubmVjdGlvbnM6IG51bWJlcjtcbiAgc3RhcnRUaW1lc3RhbXA6IG51bWJlcjtcbiAgYWRqdXN0ZWRUaW1lc3RhbXA6IG51bWJlcjtcbiAgdGFyZ2V0OiBudW1iZXI7XG4gIHRhcmdldEhlaWdodDogbnVtYmVyO1xuICB0b3BCbG9ja0hhc2g6IHN0cmluZztcbiAgbnVtVHhzOiBudW1iZXI7XG4gIG51bVR4c1Bvb2w6IG51bWJlcjtcbiAgd2FzQm9vdHN0cmFwRXZlclVzZWQ6IGJvb2xlYW47XG4gIGRhdGFiYXNlU2l6ZTogbnVtYmVyO1xuICB1cGRhdGVBdmFpbGFibGU6IGJvb2xlYW47XG4gIGNyZWRpdHM6IGJpZ2ludDtcbiAgaXNCdXN5U3luY2luZzogYm9vbGVhbjtcbiAgaXNTeW5jaHJvbml6ZWQ6IGJvb2xlYW47XG4gIGlzUmVzdHJpY3RlZDogYm9vbGVhbjtcbiAgXG4gIGNvbnN0cnVjdG9yKGluZm8/OiBQYXJ0aWFsPE1vbmVyb0RhZW1vbkluZm8+KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCBpbmZvKTtcblxuICAgIC8vIGRlc2VyaWFsaXplIGJpZ2ludHNcbiAgICBpZiAodGhpcy5kaWZmaWN1bHR5ICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHRoaXMuZGlmZmljdWx0eSAhPT0gXCJiaWdpbnRcIikgdGhpcy5kaWZmaWN1bHR5ID0gQmlnSW50KHRoaXMuZGlmZmljdWx0eSk7XG4gICAgaWYgKHRoaXMuY3VtdWxhdGl2ZURpZmZpY3VsdHkgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5jdW11bGF0aXZlRGlmZmljdWx0eSAhPT0gXCJiaWdpbnRcIikgdGhpcy5jdW11bGF0aXZlRGlmZmljdWx0eSA9IEJpZ0ludCh0aGlzLmN1bXVsYXRpdmVEaWZmaWN1bHR5KTtcbiAgICBpZiAodGhpcy5jcmVkaXRzICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHRoaXMuY3JlZGl0cyAhPT0gXCJiaWdpbnRcIikgdGhpcy5jcmVkaXRzID0gQmlnSW50KHRoaXMuY3JlZGl0cyk7XG4gIH1cbiAgXG4gIHRvSnNvbigpOiBhbnkge1xuICAgIGxldCBqc29uOiBhbnkgPSBPYmplY3QuYXNzaWduKFtdLCB0aGlzKTtcbiAgICBpZiAoanNvbi5kaWZmaWN1bHR5ICE9PSB1bmRlZmluZWQpIGpzb24uZGlmZmljdWx0eSA9IGpzb24uZGlmZmljdWx0eS50b1N0cmluZygpO1xuICAgIGlmIChqc29uLmN1bXVsYXRpdmVEaWZmaWN1bHR5ICE9PSB1bmRlZmluZWQpIGpzb24uY3VtdWxhdGl2ZURpZmZpY3VsdHkgPSBqc29uLmN1bXVsYXRpdmVEaWZmaWN1bHR5LnRvU3RyaW5nKCk7XG4gICAgaWYgKGpzb24uY3JlZGl0cyAhPT0gdW5kZWZpbmVkKSBqc29uLmNyZWRpdHMgPSBqc29uLmNyZWRpdHMudG9TdHJpbmcoKTtcbiAgICByZXR1cm4ganNvbjtcbiAgfVxuICBcbiAgZ2V0VmVyc2lvbigpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnZlcnNpb247XG4gIH1cbiAgXG4gIHNldFZlcnNpb24odmVyc2lvbjogc3RyaW5nKTogTW9uZXJvRGFlbW9uSW5mbyB7XG4gICAgdGhpcy52ZXJzaW9uID0gdmVyc2lvbjtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0TnVtQWx0QmxvY2tzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtQWx0QmxvY2tzO1xuICB9XG4gIFxuICBzZXROdW1BbHRCbG9ja3MobnVtQWx0QmxvY2tzOiBudW1iZXIpOiBNb25lcm9EYWVtb25JbmZvIHtcbiAgICB0aGlzLm51bUFsdEJsb2NrcyA9IG51bUFsdEJsb2NrcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0QmxvY2tTaXplTGltaXQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5ibG9ja1NpemVMaW1pdDtcbiAgfVxuICBcbiAgc2V0QmxvY2tTaXplTGltaXQoYmxvY2tTaXplTGltaXQ6IG51bWJlcik6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMuYmxvY2tTaXplTGltaXQgPSBibG9ja1NpemVMaW1pdDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0QmxvY2tTaXplTWVkaWFuKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuYmxvY2tTaXplTWVkaWFuO1xuICB9XG4gIFxuICBzZXRCbG9ja1NpemVNZWRpYW4oYmxvY2tTaXplTWVkaWFuOiBudW1iZXIpOiBNb25lcm9EYWVtb25JbmZvIHtcbiAgICB0aGlzLmJsb2NrU2l6ZU1lZGlhbiA9IGJsb2NrU2l6ZU1lZGlhbjtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0QmxvY2tXZWlnaHRMaW1pdCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmJsb2NrV2VpZ2h0TGltaXQ7XG4gIH1cbiAgXG4gIHNldEJsb2NrV2VpZ2h0TGltaXQoYmxvY2tXZWlnaHRMaW1pdDogbnVtYmVyKTogTW9uZXJvRGFlbW9uSW5mbyB7XG4gICAgdGhpcy5ibG9ja1dlaWdodExpbWl0ID0gYmxvY2tXZWlnaHRMaW1pdDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0QmxvY2tXZWlnaHRNZWRpYW4oKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5ibG9ja1dlaWdodE1lZGlhbjtcbiAgfVxuICBcbiAgc2V0QmxvY2tXZWlnaHRNZWRpYW4oYmxvY2tXZWlnaHRNZWRpYW46IG51bWJlcik6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMuYmxvY2tXZWlnaHRNZWRpYW4gPSBibG9ja1dlaWdodE1lZGlhbjtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0Qm9vdHN0cmFwRGFlbW9uQWRkcmVzcygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmJvb3RzdHJhcERhZW1vbkFkZHJlc3M7XG4gIH1cbiAgXG4gIHNldEJvb3RzdHJhcERhZW1vbkFkZHJlc3MoYm9vdHN0cmFwRGFlbW9uQWRkcmVzcyk6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMuYm9vdHN0cmFwRGFlbW9uQWRkcmVzcyA9IGJvb3RzdHJhcERhZW1vbkFkZHJlc3M7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldERpZmZpY3VsdHkoKTogYmlnaW50IHtcbiAgICByZXR1cm4gdGhpcy5kaWZmaWN1bHR5O1xuICB9XG4gIFxuICBzZXREaWZmaWN1bHR5KGRpZmZpY3VsdHk6IGJpZ2ludCk6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMuZGlmZmljdWx0eSA9IGRpZmZpY3VsdHk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEN1bXVsYXRpdmVEaWZmaWN1bHR5KCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMuY3VtdWxhdGl2ZURpZmZpY3VsdHk7XG4gIH1cbiAgXG4gIHNldEN1bXVsYXRpdmVEaWZmaWN1bHR5KGN1bXVsYXRpdmVEaWZmaWN1bHR5OiBiaWdpbnQpOiBNb25lcm9EYWVtb25JbmZvIHtcbiAgICB0aGlzLmN1bXVsYXRpdmVEaWZmaWN1bHR5ID0gY3VtdWxhdGl2ZURpZmZpY3VsdHk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEZyZWVTcGFjZSgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLmZyZWVTcGFjZTtcbiAgfVxuICBcbiAgc2V0RnJlZVNwYWNlKGZyZWVTcGFjZTogYmlnaW50KTogTW9uZXJvRGFlbW9uSW5mbyB7XG4gICAgdGhpcy5mcmVlU3BhY2UgPSBmcmVlU3BhY2U7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldE51bU9mZmxpbmVQZWVycygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLm51bU9mZmxpbmVQZWVycztcbiAgfVxuICBcbiAgc2V0TnVtT2ZmbGluZVBlZXJzKG51bU9mZmxpbmVQZWVyczogbnVtYmVyKTogTW9uZXJvRGFlbW9uSW5mbyB7XG4gICAgdGhpcy5udW1PZmZsaW5lUGVlcnMgPSBudW1PZmZsaW5lUGVlcnM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldE51bU9ubGluZVBlZXJzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtT25saW5lUGVlcnM7XG4gIH1cbiAgXG4gIHNldE51bU9ubGluZVBlZXJzKG51bU9ubGluZVBlZXJzOiBudW1iZXIpOiBNb25lcm9EYWVtb25JbmZvIHtcbiAgICB0aGlzLm51bU9ubGluZVBlZXJzID0gbnVtT25saW5lUGVlcnM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEhlaWdodCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmhlaWdodDtcbiAgfVxuICBcbiAgc2V0SGVpZ2h0KGhlaWdodDogbnVtYmVyKTogTW9uZXJvRGFlbW9uSW5mbyB7XG4gICAgdGhpcy5oZWlnaHQgPSBoZWlnaHQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEhlaWdodFdpdGhvdXRCb290c3RyYXAoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5oZWlnaHRXaXRob3V0Qm9vdHN0cmFwO1xuICB9XG4gIFxuICBzZXRIZWlnaHRXaXRob3V0Qm9vdHN0cmFwKGhlaWdodFdpdGhvdXRCb290c3RyYXA6IG51bWJlcik6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMuaGVpZ2h0V2l0aG91dEJvb3RzdHJhcCA9IGhlaWdodFdpdGhvdXRCb290c3RyYXA7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldE5ldHdvcmtUeXBlKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMubmV0d29ya1R5cGU7XG4gIH1cblxuICBzZXROZXR3b3JrVHlwZShuZXR3b3JrVHlwZTogc3RyaW5nKSB7XG4gICAgdGhpcy5uZXR3b3JrVHlwZSA9IG5ldHdvcmtUeXBlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0SXNPZmZsaW5lKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzT2ZmbGluZTtcbiAgfVxuICBcbiAgc2V0SXNPZmZsaW5lKGlzT2ZmbGluZTogYm9vbGVhbik6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMuaXNPZmZsaW5lID0gaXNPZmZsaW5lO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXROdW1JbmNvbWluZ0Nvbm5lY3Rpb25zKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtSW5jb21pbmdDb25uZWN0aW9ucztcbiAgfVxuICBcbiAgc2V0TnVtSW5jb21pbmdDb25uZWN0aW9ucyhudW1JbmNvbWluZ0Nvbm5lY3Rpb25zOiBudW1iZXIpOiBNb25lcm9EYWVtb25JbmZvIHtcbiAgICB0aGlzLm51bUluY29taW5nQ29ubmVjdGlvbnMgPSBudW1JbmNvbWluZ0Nvbm5lY3Rpb25zO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXROdW1PdXRnb2luZ0Nvbm5lY3Rpb25zKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtT3V0Z29pbmdDb25uZWN0aW9ucztcbiAgfVxuICBcbiAgc2V0TnVtT3V0Z29pbmdDb25uZWN0aW9ucyhudW1PdXRnb2luZ0Nvbm5lY3Rpb25zOiBudW1iZXIpOiBNb25lcm9EYWVtb25JbmZvIHtcbiAgICB0aGlzLm51bU91dGdvaW5nQ29ubmVjdGlvbnMgPSBudW1PdXRnb2luZ0Nvbm5lY3Rpb25zO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXROdW1ScGNDb25uZWN0aW9ucygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLm51bVJwY0Nvbm5lY3Rpb25zO1xuICB9XG4gIFxuICBzZXROdW1ScGNDb25uZWN0aW9ucyhudW1ScGNDb25uZWN0aW9uczogbnVtYmVyKTogTW9uZXJvRGFlbW9uSW5mbyB7XG4gICAgdGhpcy5udW1ScGNDb25uZWN0aW9ucyA9IG51bVJwY0Nvbm5lY3Rpb25zO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRTdGFydFRpbWVzdGFtcCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnN0YXJ0VGltZXN0YW1wO1xuICB9XG4gIFxuICBzZXRTdGFydFRpbWVzdGFtcChzdGFydFRpbWVzdGFtcDogbnVtYmVyKTogTW9uZXJvRGFlbW9uSW5mbyB7XG4gICAgdGhpcy5zdGFydFRpbWVzdGFtcCA9IHN0YXJ0VGltZXN0YW1wO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRBZGp1c3RlZFRpbWVzdGFtcCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmFkanVzdGVkVGltZXN0YW1wO1xuICB9XG4gIFxuICBzZXRBZGp1c3RlZFRpbWVzdGFtcChhZGp1c3RlZFRpbWVzdGFtcDogbnVtYmVyKTogTW9uZXJvRGFlbW9uSW5mbyB7XG4gICAgdGhpcy5hZGp1c3RlZFRpbWVzdGFtcCA9IGFkanVzdGVkVGltZXN0YW1wO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRUYXJnZXQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy50YXJnZXQ7XG4gIH1cbiAgXG4gIHNldFRhcmdldCh0YXJnZXQ6IG51bWJlcik6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMudGFyZ2V0ID0gdGFyZ2V0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRUYXJnZXRIZWlnaHQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy50YXJnZXRIZWlnaHQ7XG4gIH1cbiAgXG4gIHNldFRhcmdldEhlaWdodCh0YXJnZXRIZWlnaHQ6IG51bWJlcik6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMudGFyZ2V0SGVpZ2h0ID0gdGFyZ2V0SGVpZ2h0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRUb3BCbG9ja0hhc2goKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy50b3BCbG9ja0hhc2g7XG4gIH1cbiAgXG4gIHNldFRvcEJsb2NrSGFzaCh0b3BCbG9ja0hhc2gpOiBNb25lcm9EYWVtb25JbmZvIHtcbiAgICB0aGlzLnRvcEJsb2NrSGFzaCA9IHRvcEJsb2NrSGFzaDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0TnVtVHhzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtVHhzO1xuICB9XG4gIFxuICBzZXROdW1UeHMobnVtVHhzOiBudW1iZXIpOiBNb25lcm9EYWVtb25JbmZvIHtcbiAgICB0aGlzLm51bVR4cyA9IG51bVR4cztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0TnVtVHhzUG9vbCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLm51bVR4c1Bvb2w7XG4gIH1cbiAgXG4gIHNldE51bVR4c1Bvb2wobnVtVHhzUG9vbCk6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMubnVtVHhzUG9vbCA9IG51bVR4c1Bvb2w7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFdhc0Jvb3RzdHJhcEV2ZXJVc2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLndhc0Jvb3RzdHJhcEV2ZXJVc2VkO1xuICB9XG4gIFxuICBzZXRXYXNCb290c3RyYXBFdmVyVXNlZCh3YXNCb290c3RyYXBFdmVyVXNlZCk6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMud2FzQm9vdHN0cmFwRXZlclVzZWQgPSB3YXNCb290c3RyYXBFdmVyVXNlZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0RGF0YWJhc2VTaXplKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuZGF0YWJhc2VTaXplO1xuICB9XG4gIFxuICBzZXREYXRhYmFzZVNpemUoZGF0YWJhc2VTaXplOiBudW1iZXIpOiBNb25lcm9EYWVtb25JbmZvIHtcbiAgICB0aGlzLmRhdGFiYXNlU2l6ZSA9IGRhdGFiYXNlU2l6ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0VXBkYXRlQXZhaWxhYmxlKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnVwZGF0ZUF2YWlsYWJsZTtcbiAgfVxuICBcbiAgc2V0VXBkYXRlQXZhaWxhYmxlKHVwZGF0ZUF2YWlsYWJsZTogYm9vbGVhbik6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMudXBkYXRlQXZhaWxhYmxlID0gdXBkYXRlQXZhaWxhYmxlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRDcmVkaXRzKCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMuY3JlZGl0cztcbiAgfVxuICBcbiAgc2V0Q3JlZGl0cyhjcmVkaXRzOiBiaWdpbnQpOiBNb25lcm9EYWVtb25JbmZvIHtcbiAgICB0aGlzLmNyZWRpdHMgPSBjcmVkaXRzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRJc0J1c3lTeW5jaW5nKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzQnVzeVN5bmNpbmc7XG4gIH1cbiAgXG4gIHNldElzQnVzeVN5bmNpbmcoaXNCdXN5U3luY2luZzogYm9vbGVhbik6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMuaXNCdXN5U3luY2luZyA9IGlzQnVzeVN5bmNpbmc7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldElzU3luY2hyb25pemVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzU3luY2hyb25pemVkO1xuICB9XG4gIFxuICBzZXRJc1N5bmNocm9uaXplZChpc1N5bmNocm9uaXplZDogYm9vbGVhbik6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMuaXNTeW5jaHJvbml6ZWQgPSBpc1N5bmNocm9uaXplZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0SXNSZXN0cmljdGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzUmVzdHJpY3RlZDtcbiAgfVxuICBcbiAgc2V0SXNSZXN0cmljdGVkKGlzUmVzdHJpY3RlZDogYm9vbGVhbik6IE1vbmVyb0RhZW1vbkluZm8ge1xuICAgIHRoaXMuaXNSZXN0cmljdGVkID0gaXNSZXN0cmljdGVkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJxR0FBQTtBQUNBO0FBQ0E7QUFDZSxN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 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroDaemonListener.d.ts b/dist/src/main/ts/daemon/model/MoneroDaemonListener.d.ts new file mode 100644 index 000000000..adb27cac9 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroDaemonListener.d.ts @@ -0,0 +1,19 @@ +import MoneroBlockHeader from "./MoneroBlockHeader"; +/** + * Receives notifications as a daemon is updated. + */ +export default class MoneroDaemonListener { + protected lastHeader: MoneroBlockHeader; + /** + * Called when a new block is added to the chain. + * + * @param {MoneroBlockHeader} header - the header of the block added to the chain + */ + onBlockHeader(header: MoneroBlockHeader): Promise; + /** + * Get the last notified block header. + * + * @return {MoneroBlockHeader} the last notified block header + */ + getLastBlockHeader(): MoneroBlockHeader; +} diff --git a/dist/src/main/ts/daemon/model/MoneroDaemonListener.js b/dist/src/main/ts/daemon/model/MoneroDaemonListener.js new file mode 100644 index 000000000..0d0e8f8eb --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroDaemonListener.js @@ -0,0 +1,28 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; + +/** + * Receives notifications as a daemon is updated. + */ +class MoneroDaemonListener { + + + + /** + * Called when a new block is added to the chain. + * + * @param {MoneroBlockHeader} header - the header of the block added to the chain + */ + async onBlockHeader(header) { + this.lastHeader = header; + } + + /** + * Get the last notified block header. + * + * @return {MoneroBlockHeader} the last notified block header + */ + getLastBlockHeader() { + return this.lastHeader; + } +}exports.default = MoneroDaemonListener; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9EYWVtb25MaXN0ZW5lciIsIm9uQmxvY2tIZWFkZXIiLCJoZWFkZXIiLCJsYXN0SGVhZGVyIiwiZ2V0TGFzdEJsb2NrSGVhZGVyIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9kYWVtb24vbW9kZWwvTW9uZXJvRGFlbW9uTGlzdGVuZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IE1vbmVyb0Jsb2NrSGVhZGVyIGZyb20gXCIuL01vbmVyb0Jsb2NrSGVhZGVyXCI7XG5cbi8qKlxuICogUmVjZWl2ZXMgbm90aWZpY2F0aW9ucyBhcyBhIGRhZW1vbiBpcyB1cGRhdGVkLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9EYWVtb25MaXN0ZW5lciB7XG5cbiAgcHJvdGVjdGVkIGxhc3RIZWFkZXI6IE1vbmVyb0Jsb2NrSGVhZGVyO1xuICBcbiAgLyoqXG4gICAqIENhbGxlZCB3aGVuIGEgbmV3IGJsb2NrIGlzIGFkZGVkIHRvIHRoZSBjaGFpbi5cbiAgICogXG4gICAqIEBwYXJhbSB7TW9uZXJvQmxvY2tIZWFkZXJ9IGhlYWRlciAtIHRoZSBoZWFkZXIgb2YgdGhlIGJsb2NrIGFkZGVkIHRvIHRoZSBjaGFpblxuICAgKi9cbiAgYXN5bmMgb25CbG9ja0hlYWRlcihoZWFkZXI6IE1vbmVyb0Jsb2NrSGVhZGVyKSB7XG4gICAgdGhpcy5sYXN0SGVhZGVyID0gaGVhZGVyO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSBsYXN0IG5vdGlmaWVkIGJsb2NrIGhlYWRlci5cbiAgICogXG4gICAqIEByZXR1cm4ge01vbmVyb0Jsb2NrSGVhZGVyfSB0aGUgbGFzdCBub3RpZmllZCBibG9jayBoZWFkZXJcbiAgICovXG4gIGdldExhc3RCbG9ja0hlYWRlcigpOiBNb25lcm9CbG9ja0hlYWRlciB7XG4gICAgcmV0dXJuIHRoaXMubGFzdEhlYWRlcjtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOztBQUVBO0FBQ0E7QUFDQTtBQUNlLE1BQU1BLG9CQUFvQixDQUFDOzs7O0VBSXhDO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7RUFDRSxNQUFNQyxhQUFhQSxDQUFDQyxNQUF5QixFQUFFO0lBQzdDLElBQUksQ0FBQ0MsVUFBVSxHQUFHRCxNQUFNO0VBQzFCOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7RUFDRUUsa0JBQWtCQSxDQUFBLEVBQXNCO0lBQ3RDLE9BQU8sSUFBSSxDQUFDRCxVQUFVO0VBQ3hCO0FBQ0YsQ0FBQ0UsT0FBQSxDQUFBQyxPQUFBLEdBQUFOLG9CQUFBIn0= \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroDaemonSyncInfo.d.ts b/dist/src/main/ts/daemon/model/MoneroDaemonSyncInfo.d.ts new file mode 100644 index 000000000..421cd91c2 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroDaemonSyncInfo.d.ts @@ -0,0 +1,33 @@ +import MoneroConnectionSpan from "./MoneroConnectionSpan"; +import MoneroPeer from "./MoneroPeer"; +/** + * Models daemon synchronization information. + */ +export default class MoneroDaemonSyncInfo { + height: number; + peers: MoneroPeer[]; + spans: MoneroConnectionSpan[]; + targetHeight: number; + nextNeededPruningSeed: number; + overview: string; + credits: bigint; + topBlockHash: string; + constructor(info?: Partial); + toJson(): any; + getHeight(): number; + setHeight(height: number): MoneroDaemonSyncInfo; + getPeers(): MoneroPeer[]; + setPeers(peers: MoneroPeer[]): MoneroDaemonSyncInfo; + getSpans(): MoneroConnectionSpan[]; + setSpans(spans: MoneroConnectionSpan[]): MoneroDaemonSyncInfo; + getTargetHeight(): number; + setTargetHeight(targetHeight: number): MoneroDaemonSyncInfo; + getNextNeededPruningSeed(): number; + setNextNeededPruningSeed(nextNeededPruningSeed: number): MoneroDaemonSyncInfo; + getOverview(): string; + setOverview(overview: string): MoneroDaemonSyncInfo; + getCredits(): bigint; + setCredits(credits: bigint): MoneroDaemonSyncInfo; + getTopBlockHash(): string; + setTopBlockHash(topBlockHash: string): MoneroDaemonSyncInfo; +} diff --git a/dist/src/main/ts/daemon/model/MoneroDaemonSyncInfo.js b/dist/src/main/ts/daemon/model/MoneroDaemonSyncInfo.js new file mode 100644 index 000000000..d8ba51793 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroDaemonSyncInfo.js @@ -0,0 +1,127 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _MoneroConnectionSpan = _interopRequireDefault(require("./MoneroConnectionSpan")); +var _MoneroPeer = _interopRequireDefault(require("./MoneroPeer")); + +/** + * Models daemon synchronization information. + */ +class MoneroDaemonSyncInfo { + + + + + + + + + + + constructor(info) { + Object.assign(this, info); + + // deserialize bigints + if (this.credits !== undefined && typeof this.credits !== "bigint") this.credits = BigInt(this.credits); + + // copy peers + if (this.peers) { + for (let i = 0; i < this.peers.length; i++) { + this.peers[i] = new _MoneroPeer.default(this.peers[i]); + } + } + + // copy spans + if (this.spans) { + for (let i = 0; i < this.spans.length; i++) { + this.spans[i] = new _MoneroConnectionSpan.default(this.spans[i]); + } + } + } + + toJson() { + let json = Object.assign({}, this); + if (json.peers !== undefined) { + for (let i = 0; i < json.peers.length; i++) { + json.peers[i] = json.peers[i].toJson(); + } + } + if (json.spans !== undefined) { + for (let i = 0; i < json.spans.length; i++) { + json.spans[i] = json.spans[i].toJson(); + } + } + if (json.credits !== undefined) json.credits = json.credits.toString(); + return json; + } + + getHeight() { + return this.height; + } + + setHeight(height) { + this.height = height; + return this; + } + + getPeers() { + return this.peers; + } + + setPeers(peers) { + this.peers = peers; + return this; + } + + getSpans() { + return this.spans; + } + + setSpans(spans) { + this.spans = spans; + return this; + } + + getTargetHeight() { + return this.targetHeight; + } + + setTargetHeight(targetHeight) { + this.targetHeight = targetHeight; + return this; + } + + getNextNeededPruningSeed() { + return this.nextNeededPruningSeed; + } + + setNextNeededPruningSeed(nextNeededPruningSeed) { + this.nextNeededPruningSeed = nextNeededPruningSeed; + return this; + } + + getOverview() { + return this.overview; + } + + setOverview(overview) { + this.overview = overview; + return this; + } + + getCredits() { + return this.credits; + } + + setCredits(credits) { + this.credits = credits; + return this; + } + + getTopBlockHash() { + return this.topBlockHash; + } + + setTopBlockHash(topBlockHash) { + this.topBlockHash = topBlockHash; + return this; + } +}exports.default = MoneroDaemonSyncInfo; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfTW9uZXJvQ29ubmVjdGlvblNwYW4iLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9Nb25lcm9QZWVyIiwiTW9uZXJvRGFlbW9uU3luY0luZm8iLCJjb25zdHJ1Y3RvciIsImluZm8iLCJPYmplY3QiLCJhc3NpZ24iLCJjcmVkaXRzIiwidW5kZWZpbmVkIiwiQmlnSW50IiwicGVlcnMiLCJpIiwibGVuZ3RoIiwiTW9uZXJvUGVlciIsInNwYW5zIiwiTW9uZXJvQ29ubmVjdGlvblNwYW4iLCJ0b0pzb24iLCJqc29uIiwidG9TdHJpbmciLCJnZXRIZWlnaHQiLCJoZWlnaHQiLCJzZXRIZWlnaHQiLCJnZXRQZWVycyIsInNldFBlZXJzIiwiZ2V0U3BhbnMiLCJzZXRTcGFucyIsImdldFRhcmdldEhlaWdodCIsInRhcmdldEhlaWdodCIsInNldFRhcmdldEhlaWdodCIsImdldE5leHROZWVkZWRQcnVuaW5nU2VlZCIsIm5leHROZWVkZWRQcnVuaW5nU2VlZCIsInNldE5leHROZWVkZWRQcnVuaW5nU2VlZCIsImdldE92ZXJ2aWV3Iiwib3ZlcnZpZXciLCJzZXRPdmVydmlldyIsImdldENyZWRpdHMiLCJzZXRDcmVkaXRzIiwiZ2V0VG9wQmxvY2tIYXNoIiwidG9wQmxvY2tIYXNoIiwic2V0VG9wQmxvY2tIYXNoIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9kYWVtb24vbW9kZWwvTW9uZXJvRGFlbW9uU3luY0luZm8udHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IE1vbmVyb0Nvbm5lY3Rpb25TcGFuIGZyb20gXCIuL01vbmVyb0Nvbm5lY3Rpb25TcGFuXCI7XG5pbXBvcnQgTW9uZXJvUGVlciBmcm9tIFwiLi9Nb25lcm9QZWVyXCI7XG5cbi8qKlxuICogTW9kZWxzIGRhZW1vbiBzeW5jaHJvbml6YXRpb24gaW5mb3JtYXRpb24uXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0RhZW1vblN5bmNJbmZvIHtcblxuICBoZWlnaHQ6IG51bWJlcjtcbiAgcGVlcnM6IE1vbmVyb1BlZXJbXTtcbiAgc3BhbnM6IE1vbmVyb0Nvbm5lY3Rpb25TcGFuW107XG4gIHRhcmdldEhlaWdodDogbnVtYmVyO1xuICBuZXh0TmVlZGVkUHJ1bmluZ1NlZWQ6IG51bWJlcjtcbiAgb3ZlcnZpZXc6IHN0cmluZztcbiAgY3JlZGl0czogYmlnaW50O1xuICB0b3BCbG9ja0hhc2g6IHN0cmluZztcbiAgXG4gIGNvbnN0cnVjdG9yKGluZm8/OiBQYXJ0aWFsPE1vbmVyb0RhZW1vblN5bmNJbmZvPikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgaW5mbyk7XG5cbiAgICAvLyBkZXNlcmlhbGl6ZSBiaWdpbnRzXG4gICAgaWYgKHRoaXMuY3JlZGl0cyAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLmNyZWRpdHMgIT09IFwiYmlnaW50XCIpIHRoaXMuY3JlZGl0cyA9IEJpZ0ludCh0aGlzLmNyZWRpdHMpO1xuICAgIFxuICAgIC8vIGNvcHkgcGVlcnNcbiAgICBpZiAodGhpcy5wZWVycykge1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnBlZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRoaXMucGVlcnNbaV0gPSBuZXcgTW9uZXJvUGVlcih0aGlzLnBlZXJzW2ldKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBjb3B5IHNwYW5zXG4gICAgaWYgKHRoaXMuc3BhbnMpIHtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zcGFucy5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzLnNwYW5zW2ldID0gbmV3IE1vbmVyb0Nvbm5lY3Rpb25TcGFuKHRoaXMuc3BhbnNbaV0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICBcbiAgdG9Kc29uKCkge1xuICAgIGxldCBqc29uOiBhbnkgPSBPYmplY3QuYXNzaWduKHt9LCB0aGlzKTtcbiAgICBpZiAoanNvbi5wZWVycyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGpzb24ucGVlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAganNvbi5wZWVyc1tpXSA9IGpzb24ucGVlcnNbaV0udG9Kc29uKCk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChqc29uLnNwYW5zICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwganNvbi5zcGFucy5sZW5ndGg7IGkrKykge1xuICAgICAgICBqc29uLnNwYW5zW2ldID0ganNvbi5zcGFuc1tpXS50b0pzb24oKTtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGpzb24uY3JlZGl0cyAhPT0gdW5kZWZpbmVkKSBqc29uLmNyZWRpdHMgPSBqc29uLmNyZWRpdHMudG9TdHJpbmcoKTtcbiAgICByZXR1cm4ganNvbjtcbiAgfVxuICBcbiAgZ2V0SGVpZ2h0KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuaGVpZ2h0O1xuICB9XG4gIFxuICBzZXRIZWlnaHQoaGVpZ2h0OiBudW1iZXIpOiBNb25lcm9EYWVtb25TeW5jSW5mbyB7XG4gICAgdGhpcy5oZWlnaHQgPSBoZWlnaHQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFBlZXJzKCk6IE1vbmVyb1BlZXJbXSB7XG4gICAgcmV0dXJuIHRoaXMucGVlcnM7XG4gIH1cbiAgXG4gIHNldFBlZXJzKHBlZXJzOiBNb25lcm9QZWVyW10pOiBNb25lcm9EYWVtb25TeW5jSW5mbyB7XG4gICAgdGhpcy5wZWVycyA9IHBlZXJzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRTcGFucygpOiBNb25lcm9Db25uZWN0aW9uU3BhbltdIHtcbiAgICByZXR1cm4gdGhpcy5zcGFucztcbiAgfVxuICBcbiAgc2V0U3BhbnMoc3BhbnM6IE1vbmVyb0Nvbm5lY3Rpb25TcGFuW10pOiBNb25lcm9EYWVtb25TeW5jSW5mbyB7XG4gICAgdGhpcy5zcGFucyA9IHNwYW5zO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRUYXJnZXRIZWlnaHQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy50YXJnZXRIZWlnaHQ7XG4gIH1cbiAgXG4gIHNldFRhcmdldEhlaWdodCh0YXJnZXRIZWlnaHQ6IG51bWJlcik6IE1vbmVyb0RhZW1vblN5bmNJbmZvIHtcbiAgICB0aGlzLnRhcmdldEhlaWdodCA9IHRhcmdldEhlaWdodDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0TmV4dE5lZWRlZFBydW5pbmdTZWVkKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubmV4dE5lZWRlZFBydW5pbmdTZWVkO1xuICB9XG4gIFxuICBzZXROZXh0TmVlZGVkUHJ1bmluZ1NlZWQobmV4dE5lZWRlZFBydW5pbmdTZWVkOiBudW1iZXIpOiBNb25lcm9EYWVtb25TeW5jSW5mbyB7XG4gICAgdGhpcy5uZXh0TmVlZGVkUHJ1bmluZ1NlZWQgPSBuZXh0TmVlZGVkUHJ1bmluZ1NlZWQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldE92ZXJ2aWV3KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMub3ZlcnZpZXc7XG4gIH1cbiAgXG4gIHNldE92ZXJ2aWV3KG92ZXJ2aWV3OiBzdHJpbmcpOiBNb25lcm9EYWVtb25TeW5jSW5mbyB7XG4gICAgdGhpcy5vdmVydmlldyA9IG92ZXJ2aWV3O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRDcmVkaXRzKCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMuY3JlZGl0cztcbiAgfVxuICBcbiAgc2V0Q3JlZGl0cyhjcmVkaXRzOiBiaWdpbnQpOiBNb25lcm9EYWVtb25TeW5jSW5mbyB7XG4gICAgdGhpcy5jcmVkaXRzID0gY3JlZGl0cztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0VG9wQmxvY2tIYXNoKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMudG9wQmxvY2tIYXNoO1xuICB9XG4gIFxuICBzZXRUb3BCbG9ja0hhc2godG9wQmxvY2tIYXNoOiBzdHJpbmcpOiBNb25lcm9EYWVtb25TeW5jSW5mbyB7XG4gICAgdGhpcy50b3BCbG9ja0hhc2ggPSB0b3BCbG9ja0hhc2g7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLHFCQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxXQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7O0FBRUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUUsb0JBQW9CLENBQUM7Ozs7Ozs7Ozs7O0VBV3hDQyxXQUFXQSxDQUFDQyxJQUFvQyxFQUFFO0lBQ2hEQyxNQUFNLENBQUNDLE1BQU0sQ0FBQyxJQUFJLEVBQUVGLElBQUksQ0FBQzs7SUFFekI7SUFDQSxJQUFJLElBQUksQ0FBQ0csT0FBTyxLQUFLQyxTQUFTLElBQUksT0FBTyxJQUFJLENBQUNELE9BQU8sS0FBSyxRQUFRLEVBQUUsSUFBSSxDQUFDQSxPQUFPLEdBQUdFLE1BQU0sQ0FBQyxJQUFJLENBQUNGLE9BQU8sQ0FBQzs7SUFFdkc7SUFDQSxJQUFJLElBQUksQ0FBQ0csS0FBSyxFQUFFO01BQ2QsS0FBSyxJQUFJQyxDQUFDLEdBQUcsQ0FBQyxFQUFFQSxDQUFDLEdBQUcsSUFBSSxDQUFDRCxLQUFLLENBQUNFLE1BQU0sRUFBRUQsQ0FBQyxFQUFFLEVBQUU7UUFDMUMsSUFBSSxDQUFDRCxLQUFLLENBQUNDLENBQUMsQ0FBQyxHQUFHLElBQUlFLG1CQUFVLENBQUMsSUFBSSxDQUFDSCxLQUFLLENBQUNDLENBQUMsQ0FBQyxDQUFDO01BQy9DO0lBQ0Y7O0lBRUE7SUFDQSxJQUFJLElBQUksQ0FBQ0csS0FBSyxFQUFFO01BQ2QsS0FBSyxJQUFJSCxDQUFDLEdBQUcsQ0FBQyxFQUFFQSxDQUFDLEdBQUcsSUFBSSxDQUFDRyxLQUFLLENBQUNGLE1BQU0sRUFBRUQsQ0FBQyxFQUFFLEVBQUU7UUFDMUMsSUFBSSxDQUFDRyxLQUFLLENB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 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroDaemonUpdateCheckResult.d.ts b/dist/src/main/ts/daemon/model/MoneroDaemonUpdateCheckResult.d.ts new file mode 100644 index 000000000..8ccc05525 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroDaemonUpdateCheckResult.d.ts @@ -0,0 +1,46 @@ +/** + * Models the result of checking for a daemon update. + */ +export default class MoneroDaemonUpdateCheckResult { + isUpdateAvailable: boolean; + version: string; + hash: string; + autoUri: string; + userUri: string; + constructor(result?: MoneroDaemonUpdateCheckResult); + /** + * Indicates if an update is available. + * + * @return {boolean} true if an update is available, false otherwise + */ + getIsUpdateAvailable(): boolean; + setIsUpdateAvailable(isUpdateAvailable: boolean): MoneroDaemonUpdateCheckResult; + /** + * Get the update's version. + * + * @return {string} is the update's version + */ + getVersion(): string; + setVersion(version: string): MoneroDaemonUpdateCheckResult; + /** + * Get the update's hash. + * + * @return {string} is the update's hash + */ + getHash(): string; + setHash(hash: string): MoneroDaemonUpdateCheckResult; + /** + * Get the uri to automatically download the update. + * + * @return {string} is the uri to automatically download the update + */ + getAutoUri(): string; + setAutoUri(autoUri: string): MoneroDaemonUpdateCheckResult; + /** + * Get the uri to manually download the update. + * + * @return {string} is the uri to manually download the update + */ + getUserUri(): string; + setUserUri(userUri: string): MoneroDaemonUpdateCheckResult; +} diff --git a/dist/src/main/ts/daemon/model/MoneroDaemonUpdateCheckResult.js b/dist/src/main/ts/daemon/model/MoneroDaemonUpdateCheckResult.js new file mode 100644 index 000000000..27346edb7 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroDaemonUpdateCheckResult.js @@ -0,0 +1,86 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Models the result of checking for a daemon update. + */ +class MoneroDaemonUpdateCheckResult { + + + + + + + + constructor(result) { + Object.assign(this, result); + } + + /** + * Indicates if an update is available. + * + * @return {boolean} true if an update is available, false otherwise + */ + getIsUpdateAvailable() { + return this.isUpdateAvailable; + } + + setIsUpdateAvailable(isUpdateAvailable) { + this.isUpdateAvailable = isUpdateAvailable; + return this; + } + + /** + * Get the update's version. + * + * @return {string} is the update's version + */ + getVersion() { + return this.version; + } + + setVersion(version) { + this.version = version; + return this; + } + + /** + * Get the update's hash. + * + * @return {string} is the update's hash + */ + getHash() { + return this.hash; + } + + setHash(hash) { + this.hash = hash; + return this; + } + + /** + * Get the uri to automatically download the update. + * + * @return {string} is the uri to automatically download the update + */ + getAutoUri() { + return this.autoUri; + } + + setAutoUri(autoUri) { + this.autoUri = autoUri; + return this; + } + + /** + * Get the uri to manually download the update. + * + * @return {string} is the uri to manually download the update + */ + getUserUri() { + return this.userUri; + } + + setUserUri(userUri) { + this.userUri = userUri; + return this; + } +}exports.default = MoneroDaemonUpdateCheckResult; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9EYWVtb25VcGRhdGVDaGVja1Jlc3VsdCIsImNvbnN0cnVjdG9yIiwicmVzdWx0IiwiT2JqZWN0IiwiYXNzaWduIiwiZ2V0SXNVcGRhdGVBdmFpbGFibGUiLCJpc1VwZGF0ZUF2YWlsYWJsZSIsInNldElzVXBkYXRlQXZhaWxhYmxlIiwiZ2V0VmVyc2lvbiIsInZlcnNpb24iLCJzZXRWZXJzaW9uIiwiZ2V0SGFzaCIsImhhc2giLCJzZXRIYXNoIiwiZ2V0QXV0b1VyaSIsImF1dG9VcmkiLCJzZXRBdXRvVXJpIiwiZ2V0VXNlclVyaSIsInVzZXJVcmkiLCJzZXRVc2VyVXJpIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9kYWVtb24vbW9kZWwvTW9uZXJvRGFlbW9uVXBkYXRlQ2hlY2tSZXN1bHQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBNb2RlbHMgdGhlIHJlc3VsdCBvZiBjaGVja2luZyBmb3IgYSBkYWVtb24gdXBkYXRlLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9EYWVtb25VcGRhdGVDaGVja1Jlc3VsdCB7XG5cbiAgaXNVcGRhdGVBdmFpbGFibGU6IGJvb2xlYW47XG4gIHZlcnNpb246IHN0cmluZztcbiAgaGFzaDogc3RyaW5nO1xuICBhdXRvVXJpOiBzdHJpbmc7XG4gIHVzZXJVcmk6IHN0cmluZztcbiAgXG4gIGNvbnN0cnVjdG9yKHJlc3VsdD86IE1vbmVyb0RhZW1vblVwZGF0ZUNoZWNrUmVzdWx0KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCByZXN1bHQpO1xuICB9XG4gIFxuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIGFuIHVwZGF0ZSBpcyBhdmFpbGFibGUuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIGFuIHVwZGF0ZSBpcyBhdmFpbGFibGUsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgZ2V0SXNVcGRhdGVBdmFpbGFibGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNVcGRhdGVBdmFpbGFibGU7XG4gIH1cbiAgXG4gIHNldElzVXBkYXRlQXZhaWxhYmxlKGlzVXBkYXRlQXZhaWxhYmxlOiBib29sZWFuKTogTW9uZXJvRGFlbW9uVXBkYXRlQ2hlY2tSZXN1bHQge1xuICAgIHRoaXMuaXNVcGRhdGVBdmFpbGFibGUgPSBpc1VwZGF0ZUF2YWlsYWJsZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgdXBkYXRlJ3MgdmVyc2lvbi5cbiAgICogXG4gICAqIEByZXR1cm4ge3N0cmluZ30gaXMgdGhlIHVwZGF0ZSdzIHZlcnNpb25cbiAgICovXG4gIGdldFZlcnNpb24oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy52ZXJzaW9uO1xuICB9XG4gIFxuICBzZXRWZXJzaW9uKHZlcnNpb246IHN0cmluZyk6IE1vbmVyb0RhZW1vblVwZGF0ZUNoZWNrUmVzdWx0IHtcbiAgICB0aGlzLnZlcnNpb24gPSB2ZXJzaW9uO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSB1cGRhdGUncyBoYXNoLlxuICAgKiBcbiAgICogQHJldHVybiB7c3RyaW5nfSBpcyB0aGUgdXBkYXRlJ3MgaGFzaFxuICAgKi9cbiAgZ2V0SGFzaCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmhhc2g7XG4gIH1cbiAgXG4gIHNldEhhc2goaGFzaDogc3RyaW5nKTogTW9uZXJvRGFlbW9uVXBkYXRlQ2hlY2tSZXN1bHQge1xuICAgIHRoaXMuaGFzaCA9IGhhc2g7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIHVyaSB0byBhdXRvbWF0aWNhbGx5IGRvd25sb2FkIHRoZSB1cGRhdGUuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IGlzIHRoZSB1cmkgdG8gYXV0b21hdGljYWxseSBkb3dubG9hZCB0aGUgdXBkYXRlXG4gICAqL1xuICBnZXRBdXRvVXJpKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuYXV0b1VyaTtcbiAgfVxuICBcbiAgc2V0QXV0b1VyaShhdXRvVXJpOiBzdHJpbmcpOiBNb25lcm9EYWVtb25VcGRhdGVDaGVja1Jlc3VsdCB7XG4gICAgdGhpcy5hdXRvVXJpID0gYXV0b1VyaTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgdXJpIHRvIG1hbnVhbGx5IGRvd25sb2FkIHRoZSB1cGRhdGUuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IGlzIHRoZSB1cmkgdG8gbWFudWFsbHkgZG93bmxvYWQgdGhlIHVwZGF0ZVxuICAgKi9cbiAgZ2V0VXNlclVyaSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnVzZXJVcmk7XG4gIH1cbiAgXG4gIHNldFVzZXJVcmkodXNlclVyaTogc3RyaW5nKTogTW9uZXJvRGFlbW9uVXBkYXRlQ2hlY2tSZXN1bHQge1xuICAgIHRoaXMudXNlclVyaSA9IHVzZXJVcmk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn0iXSwibWFwcGluZ3MiOiJxR0FBQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSw2QkFBNkIsQ0FBQzs7Ozs7Ozs7RUFRakRDLFdBQVdBLENBQUNDLE1BQXNDLEVBQUU7SUFDbERDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsTUFBTSxDQUFDO0VBQzdCOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7RUFDRUcsb0JBQW9CQSxDQUFBLEVBQVk7SUFDOUIsT0FBTyxJQUFJLENBQUNDLGlCQUFpQjtFQUMvQjs7RUFFQUMsb0JBQW9CQSxDQUFDRCxpQkFBMEIsRUFBaUM7SUFDOUUsSUFBSSxDQUFDQSxpQkFBaUIsR0FBR0EsaUJBQWlCO0lBQzFDLE9BQU8sSUFBSTtFQUNiOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7RUFDRUUsVUFBVUEsQ0FBQSxFQUFXO0lBQ25CLE9BQU8sSUFBSSxDQUFDQyxPQUFPO0VBQ3JCOztFQUVBQyxVQUFVQSxDQUFDRCxPQUFlLEVBQWlDO0lBQ3pELElBQUksQ0FBQ0EsT0FBTyxHQUFHQSxPQUFPO0lBQ3RCLE9BQU8sSUFBSTtFQUNiOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7RUFDRUUsT0FBT0EsQ0FBQSxFQUFXO0lBQ2hCLE9BQU8sSUFBSSxDQUFDQyxJQUFJO0VBQ2xCOztFQUVBQyxPQUFPQSxDQUFDRCxJQUFZLEVBQWlDO0lBQ25ELElBQUksQ0FBQ0EsSUFBSSxHQUFHQSxJQUFJO0lBQ2hCLE9BQU8sSUFBSTtFQUNiOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7RUFDRUUsVUFBVUEsQ0FBQSxFQUFXO0lBQ25CLE9BQU8sSUFBSSxDQUFDQyxPQUFPO0VBQ3JCOztFQUVBQyxVQUFVQSxDQUFDRCxPQUFlLEVBQWlDO0lBQ3pELElBQUksQ0FBQ0EsT0FBTyxHQUFHQSxPQUFPO0lBQ3RCLE9BQU8sSUFBSTtFQUNiOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7RUFDRUUsVUFBVUEsQ0FBQSxFQUFXO0lBQ25CLE9BQU8sSUFBSSxDQUFDQyxPQUFPO0VBQ3JCOztFQUVBQyxVQUFVQSxDQUFDRCxPQUFlLEVBQWlDO0lBQ3pELElBQUksQ0FBQ0EsT0FBTyxHQUFHQSxPQUFPO0lBQ3RCLE9BQU8sSUFBSTtFQUNiO0FBQ0YsQ0FBQ0UsT0FBQSxDQUFBQyxPQUFBLEdBQUFyQiw2QkFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroDaemonUpdateDownloadResult.d.ts b/dist/src/main/ts/daemon/model/MoneroDaemonUpdateDownloadResult.d.ts new file mode 100644 index 000000000..6c465fe52 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroDaemonUpdateDownloadResult.d.ts @@ -0,0 +1,15 @@ +import MoneroDaemonUpdateCheckResult from "./MoneroDaemonUpdateCheckResult"; +/** + * Models the result of downloading an update. + */ +export default class MoneroDaemonUpdateDownloadResult extends MoneroDaemonUpdateCheckResult { + downloadPath: string; + constructor(state: MoneroDaemonUpdateDownloadResult); + /** + * Get the path the update was downloaded to. + * + * @return {string} is the path the update was downloaded to + */ + getDownloadPath(): string; + setDownloadPath(downloadPath: string): MoneroDaemonUpdateDownloadResult; +} diff --git a/dist/src/main/ts/daemon/model/MoneroDaemonUpdateDownloadResult.js b/dist/src/main/ts/daemon/model/MoneroDaemonUpdateDownloadResult.js new file mode 100644 index 000000000..c4c23f7bf --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroDaemonUpdateDownloadResult.js @@ -0,0 +1,28 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _MoneroDaemonUpdateCheckResult = _interopRequireDefault(require("./MoneroDaemonUpdateCheckResult")); + +/** + * Models the result of downloading an update. + */ +class MoneroDaemonUpdateDownloadResult extends _MoneroDaemonUpdateCheckResult.default { + + + + constructor(state) { + super(state); + } + + /** + * Get the path the update was downloaded to. + * + * @return {string} is the path the update was downloaded to + */ + getDownloadPath() { + return this.downloadPath; + } + + setDownloadPath(downloadPath) { + this.downloadPath = downloadPath; + return this; + } +}exports.default = MoneroDaemonUpdateDownloadResult; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfTW9uZXJvRGFlbW9uVXBkYXRlQ2hlY2tSZXN1bHQiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIk1vbmVyb0RhZW1vblVwZGF0ZURvd25sb2FkUmVzdWx0IiwiTW9uZXJvRGFlbW9uVXBkYXRlQ2hlY2tSZXN1bHQiLCJjb25zdHJ1Y3RvciIsInN0YXRlIiwiZ2V0RG93bmxvYWRQYXRoIiwiZG93bmxvYWRQYXRoIiwic2V0RG93bmxvYWRQYXRoIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9kYWVtb24vbW9kZWwvTW9uZXJvRGFlbW9uVXBkYXRlRG93bmxvYWRSZXN1bHQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IE1vbmVyb0RhZW1vblVwZGF0ZUNoZWNrUmVzdWx0IGZyb20gXCIuL01vbmVyb0RhZW1vblVwZGF0ZUNoZWNrUmVzdWx0XCI7XG5cbi8qKlxuICogTW9kZWxzIHRoZSByZXN1bHQgb2YgZG93bmxvYWRpbmcgYW4gdXBkYXRlLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9EYWVtb25VcGRhdGVEb3dubG9hZFJlc3VsdCBleHRlbmRzIE1vbmVyb0RhZW1vblVwZGF0ZUNoZWNrUmVzdWx0IHtcblxuICBkb3dubG9hZFBhdGg6IHN0cmluZztcbiAgXG4gIGNvbnN0cnVjdG9yKHN0YXRlOiBNb25lcm9EYWVtb25VcGRhdGVEb3dubG9hZFJlc3VsdCkge1xuICAgIHN1cGVyKHN0YXRlKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgcGF0aCB0aGUgdXBkYXRlIHdhcyBkb3dubG9hZGVkIHRvLlxuICAgKiBcbiAgICogQHJldHVybiB7c3RyaW5nfSBpcyB0aGUgcGF0aCB0aGUgdXBkYXRlIHdhcyBkb3dubG9hZGVkIHRvXG4gICAqL1xuICBnZXREb3dubG9hZFBhdGgoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5kb3dubG9hZFBhdGg7XG4gIH1cbiAgXG4gIHNldERvd25sb2FkUGF0aChkb3dubG9hZFBhdGg6IHN0cmluZyk6IE1vbmVyb0RhZW1vblVwZGF0ZURvd25sb2FkUmVzdWx0IHtcbiAgICB0aGlzLmRvd25sb2FkUGF0aCA9IGRvd25sb2FkUGF0aDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufSJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLDhCQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7O0FBRUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUMsZ0NBQWdDLFNBQVNDLHNDQUE2QixDQUFDOzs7O0VBSTFGQyxXQUFXQSxDQUFDQyxLQUF1QyxFQUFFO0lBQ25ELEtBQUssQ0FBQ0EsS0FBSyxDQUFDO0VBQ2Q7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtFQUNFQyxlQUFlQSxDQUFBLEVBQVc7SUFDeEIsT0FBTyxJQUFJLENBQUNDLFlBQVk7RUFDMUI7O0VBRUFDLGVBQWVBLENBQUNELFlBQW9CLEVBQW9DO0lBQ3RFLElBQUksQ0FBQ0EsWUFBWSxHQUFHQSxZQUFZO0lBQ2hDLE9BQU8sSUFBSTtFQUNiO0FBQ0YsQ0FBQ0UsT0FBQSxDQUFBQyxPQUFBLEdBQUFSLGdDQUFBIn0= \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroFeeEstimate.d.ts b/dist/src/main/ts/daemon/model/MoneroFeeEstimate.d.ts new file mode 100644 index 000000000..7706d60b2 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroFeeEstimate.d.ts @@ -0,0 +1,18 @@ +/** + * Models a Monero fee estimate. + */ +export default class MoneroFeeEstimate { + fee: bigint; + fees: bigint[]; + quantizationMask: bigint; + constructor(feeEstimate?: Partial); + getFee(): bigint; + setFee(fee: bigint): MoneroFeeEstimate; + getFees(): bigint[]; + setFees(fees: any): this; + getQuantizationMask(): bigint; + setQuantizationMask(quantizationMask: any): MoneroFeeEstimate; + copy(): MoneroFeeEstimate; + toJson(): any; + toString(indent?: number): string; +} diff --git a/dist/src/main/ts/daemon/model/MoneroFeeEstimate.js b/dist/src/main/ts/daemon/model/MoneroFeeEstimate.js new file mode 100644 index 000000000..22025c77c --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroFeeEstimate.js @@ -0,0 +1,73 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); + +/** + * Models a Monero fee estimate. + */ +class MoneroFeeEstimate { + + + + + + constructor(feeEstimate) { + Object.assign(this, feeEstimate); + + // deserialize + if (this.fee !== undefined && typeof this.fee !== "bigint") this.fee = BigInt(this.fee); + if (this.fees !== undefined) { + for (let i = 0; i < this.fees.length; i++) { + if (typeof this.fees[i] !== "bigint") this.fees[i] = BigInt(this.fees[i]); + } + } + if (this.quantizationMask !== undefined && typeof this.quantizationMask !== "bigint") this.quantizationMask = BigInt(this.quantizationMask); + } + + getFee() { + return this.fee; + } + + setFee(fee) { + this.fee = fee; + return this; + } + + getFees() { + return this.fees; + } + + setFees(fees) { + this.fees = fees; + return this; + } + + getQuantizationMask() { + return this.quantizationMask; + } + + setQuantizationMask(quantizationMask) { + this.quantizationMask = quantizationMask; + return this; + } + + copy() { + return new MoneroFeeEstimate(this); + } + + toJson() { + let json = Object.assign({}, this); + if (this.getFee()) json.fee = this.getFee().toString(); + if (this.getFees()) for (let i = 0; i < this.getFees().length; i++) json.fees[i] = this.getFees()[i].toString(); + if (this.getQuantizationMask()) json.quantizationMask = this.getQuantizationMask().toString(); + return json; + } + + toString(indent = 0) { + let str = ""; + let json = this.toJson(); + str += _GenUtils.default.kvLine("Fee", json.fee, indent); + str += _GenUtils.default.kvLine("Fees", json.fees, indent); + str += _GenUtils.default.kvLine("Quantization mask", json.quantizationMask, indent); + return str.slice(0, str.length - 1); // strip last newline + } +}exports.default = MoneroFeeEstimate; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfR2VuVXRpbHMiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIk1vbmVyb0ZlZUVzdGltYXRlIiwiY29uc3RydWN0b3IiLCJmZWVFc3RpbWF0ZSIsIk9iamVjdCIsImFzc2lnbiIsImZlZSIsInVuZGVmaW5lZCIsIkJpZ0ludCIsImZlZXMiLCJpIiwibGVuZ3RoIiwicXVhbnRpemF0aW9uTWFzayIsImdldEZlZSIsInNldEZlZSIsImdldEZlZXMiLCJzZXRGZWVzIiwiZ2V0UXVhbnRpemF0aW9uTWFzayIsInNldFF1YW50aXphdGlvbk1hc2siLCJjb3B5IiwidG9Kc29uIiwianNvbiIsInRvU3RyaW5nIiwiaW5kZW50Iiwic3RyIiwiR2VuVXRpbHMiLCJrdkxpbmUiLCJzbGljZSIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvZGFlbW9uL21vZGVsL01vbmVyb0ZlZUVzdGltYXRlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi4vLi4vY29tbW9uL0dlblV0aWxzXCI7XG5cbi8qKlxuICogTW9kZWxzIGEgTW9uZXJvIGZlZSBlc3RpbWF0ZS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTW9uZXJvRmVlRXN0aW1hdGUge1xuXG4gIGZlZTogYmlnaW50O1xuICBmZWVzOiBiaWdpbnRbXTtcbiAgcXVhbnRpemF0aW9uTWFzazogYmlnaW50O1xuICBcbiAgY29uc3RydWN0b3IoZmVlRXN0aW1hdGU/OiBQYXJ0aWFsPE1vbmVyb0ZlZUVzdGltYXRlPikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgZmVlRXN0aW1hdGUpO1xuICAgIFxuICAgIC8vIGRlc2VyaWFsaXplXG4gICAgaWYgKHRoaXMuZmVlICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHRoaXMuZmVlICE9PSBcImJpZ2ludFwiKSB0aGlzLmZlZSA9IEJpZ0ludCh0aGlzLmZlZSk7XG4gICAgaWYgKHRoaXMuZmVlcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuZmVlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAodHlwZW9mIHRoaXMuZmVlc1tpXSAhPT0gXCJiaWdpbnRcIikgdGhpcy5mZWVzW2ldID0gQmlnSW50KHRoaXMuZmVlc1tpXSk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmICh0aGlzLnF1YW50aXphdGlvbk1hc2sgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5xdWFudGl6YXRpb25NYXNrICE9PSBcImJpZ2ludFwiKSB0aGlzLnF1YW50aXphdGlvbk1hc2sgPSBCaWdJbnQodGhpcy5xdWFudGl6YXRpb25NYXNrKTtcbiAgfVxuXG4gIGdldEZlZSgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLmZlZTtcbiAgfVxuXG4gIHNldEZlZShmZWU6IGJpZ2ludCk6IE1vbmVyb0ZlZUVzdGltYXRlIHtcbiAgICB0aGlzLmZlZSA9IGZlZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldEZlZXMoKTogYmlnaW50W10ge1xuICAgIHJldHVybiB0aGlzLmZlZXM7XG4gIH1cblxuICBzZXRGZWVzKGZlZXMpIHtcbiAgICB0aGlzLmZlZXMgPSBmZWVzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRRdWFudGl6YXRpb25NYXNrKCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMucXVhbnRpemF0aW9uTWFzaztcbiAgfVxuXG4gIHNldFF1YW50aXphdGlvbk1hc2socXVhbnRpemF0aW9uTWFzayk6IE1vbmVyb0ZlZUVzdGltYXRlIHtcbiAgICB0aGlzLnF1YW50aXphdGlvbk1hc2sgPSBxdWFudGl6YXRpb25NYXNrO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBjb3B5KCk6IE1vbmVyb0ZlZUVzdGltYXRlIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb0ZlZUVzdGltYXRlKHRoaXMpO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICBsZXQganNvbjogYW55ID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcyk7XG4gICAgaWYgKHRoaXMuZ2V0RmVlKCkpIGpzb24uZmVlID0gdGhpcy5nZXRGZWUoKS50b1N0cmluZygpO1xuICAgIGlmICh0aGlzLmdldEZlZXMoKSkgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmdldEZlZXMoKS5sZW5ndGg7IGkrKykganNvbi5mZWVzW2ldID0gdGhpcy5nZXRGZWVzKClbaV0udG9TdHJpbmcoKTtcbiAgICBpZiAodGhpcy5nZXRRdWFudGl6YXRpb25NYXNrKCkpIGpzb24ucXVhbnRpemF0aW9uTWFzayA9IHRoaXMuZ2V0UXVhbnRpemF0aW9uTWFzaygpLnRvU3RyaW5nKCk7XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIHRvU3RyaW5nKGluZGVudCA9IDApIHtcbiAgICBsZXQgc3RyID0gXCJcIjtcbiAgICBsZXQganNvbiA9IHRoaXMudG9Kc29uKCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIkZlZVwiLCBqc29uLmZlZSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiRmVlc1wiLCBqc29uLmZlZXMsIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlF1YW50aXphdGlvbiBtYXNrXCIsIGpzb24ucXVhbnRpemF0aW9uTWFzaywgaW5kZW50KTtcbiAgICByZXR1cm4gc3RyLnNsaWNlKDAsIHN0ci5sZW5ndGggLSAxKTsgIC8vIHN0cmlwIGxhc3QgbmV3bGluZVxuICB9XG59Il0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsU0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBOztBQUVBO0FBQ0E7QUFDQTtBQUNlLE1BQU1DLGlCQUFpQixDQUFDOzs7Ozs7RUFNckNDLFdBQVdBLENBQUNDLFdBQXdDLEVBQUU7SUFDcERDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsV0FBVyxD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 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroHardForkInfo.d.ts b/dist/src/main/ts/daemon/model/MoneroHardForkInfo.d.ts new file mode 100644 index 000000000..70defc0b7 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroHardForkInfo.d.ts @@ -0,0 +1,37 @@ +/** + * Monero hard fork info. + */ +export default class MoneroHardForkInfo { + earliestHeight: number; + isEnabled: boolean; + state: string; + threshold: number; + version: number; + numVotes: number; + window: number; + voting: number; + credits: bigint; + topBlockHash: string; + constructor(info?: Partial); + toJson(): any; + getEarliestHeight(): number; + setEarliestHeight(earliestHeight: number): MoneroHardForkInfo; + getIsEnabled(): boolean; + setIsEnabled(isEnabled: boolean): MoneroHardForkInfo; + getState(): string; + setState(state: string): MoneroHardForkInfo; + getThreshold(): number; + setThreshold(threshold: number): MoneroHardForkInfo; + getVersion(): number; + setVersion(version: number): MoneroHardForkInfo; + getNumVotes(): number; + setNumVotes(numVotes: number): MoneroHardForkInfo; + getWindow(): number; + setWindow(window: number): MoneroHardForkInfo; + getVoting(): number; + setVoting(voting: number): MoneroHardForkInfo; + getCredits(): bigint; + setCredits(credits: bigint): MoneroHardForkInfo; + getTopBlockHash(): string; + setTopBlockHash(topBlockHash: string): MoneroHardForkInfo; +} diff --git a/dist/src/main/ts/daemon/model/MoneroHardForkInfo.js b/dist/src/main/ts/daemon/model/MoneroHardForkInfo.js new file mode 100644 index 000000000..6ccc79db5 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroHardForkInfo.js @@ -0,0 +1,118 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Monero hard fork info. + */ +class MoneroHardForkInfo { + + + + + + + + + + + + + constructor(info) { + Object.assign(this, info); + if (this.credits !== undefined && typeof this.credits !== "bigint") this.credits = BigInt(this.credits); + } + + toJson() { + let json = Object.assign({}, this); + if (json.credits !== undefined) json.credits = json.credits.toString(); + return json; + } + + getEarliestHeight() { + return this.earliestHeight; + } + + setEarliestHeight(earliestHeight) { + this.earliestHeight = earliestHeight; + return this; + } + + getIsEnabled() { + return this.isEnabled; + } + + setIsEnabled(isEnabled) { + this.isEnabled = isEnabled; + return this; + } + + getState() { + return this.state; + } + + setState(state) { + this.state = state; + return this; + } + + getThreshold() { + return this.threshold; + } + + setThreshold(threshold) { + this.threshold = threshold; + return this; + } + + getVersion() { + return this.version; + } + + setVersion(version) { + this.version = version; + return this; + } + + getNumVotes() { + return this.numVotes; + } + + setNumVotes(numVotes) { + this.numVotes = numVotes; + return this; + } + + getWindow() { + return this.window; + } + + setWindow(window) { + this.window = window; + return this; + } + + getVoting() { + return this.voting; + } + + setVoting(voting) { + this.voting = voting; + return this; + } + + getCredits() { + return this.credits; + } + + setCredits(credits) { + this.credits = credits; + return this; + } + + getTopBlockHash() { + return this.topBlockHash; + } + + setTopBlockHash(topBlockHash) { + this.topBlockHash = topBlockHash; + return this; + } +}exports.default = MoneroHardForkInfo; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9IYXJkRm9ya0luZm8iLCJjb25zdHJ1Y3RvciIsImluZm8iLCJPYmplY3QiLCJhc3NpZ24iLCJjcmVkaXRzIiwidW5kZWZpbmVkIiwiQmlnSW50IiwidG9Kc29uIiwianNvbiIsInRvU3RyaW5nIiwiZ2V0RWFybGllc3RIZWlnaHQiLCJlYXJsaWVzdEhlaWdodCIsInNldEVhcmxpZXN0SGVpZ2h0IiwiZ2V0SXNFbmFibGVkIiwiaXNFbmFibGVkIiwic2V0SXNFbmFibGVkIiwiZ2V0U3RhdGUiLCJzdGF0ZSIsInNldFN0YXRlIiwiZ2V0VGhyZXNob2xkIiwidGhyZXNob2xkIiwic2V0VGhyZXNob2xkIiwiZ2V0VmVyc2lvbiIsInZlcnNpb24iLCJzZXRWZXJzaW9uIiwiZ2V0TnVtVm90ZXMiLCJudW1Wb3RlcyIsInNldE51bVZvdGVzIiwiZ2V0V2luZG93Iiwid2luZG93Iiwic2V0V2luZG93IiwiZ2V0Vm90aW5nIiwidm90aW5nIiwic2V0Vm90aW5nIiwiZ2V0Q3JlZGl0cyIsInNldENyZWRpdHMiLCJnZXRUb3BCbG9ja0hhc2giLCJ0b3BCbG9ja0hhc2giLCJzZXRUb3BCbG9ja0hhc2giLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2RhZW1vbi9tb2RlbC9Nb25lcm9IYXJkRm9ya0luZm8udHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBNb25lcm8gaGFyZCBmb3JrIGluZm8uXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0hhcmRGb3JrSW5mbyB7XG5cbiAgZWFybGllc3RIZWlnaHQ6IG51bWJlcjtcbiAgaXNFbmFibGVkOiBib29sZWFuO1xuICBzdGF0ZTogc3RyaW5nO1xuICB0aHJlc2hvbGQ6IG51bWJlcjtcbiAgdmVyc2lvbjogbnVtYmVyO1xuICBudW1Wb3RlczogbnVtYmVyO1xuICB3aW5kb3c6IG51bWJlcjtcbiAgdm90aW5nOiBudW1iZXI7XG4gIGNyZWRpdHM6IGJpZ2ludDtcbiAgdG9wQmxvY2tIYXNoOiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3IoaW5mbz86IFBhcnRpYWw8TW9uZXJvSGFyZEZvcmtJbmZvPikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgaW5mbyk7XG4gICAgaWYgKHRoaXMuY3JlZGl0cyAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLmNyZWRpdHMgIT09IFwiYmlnaW50XCIpIHRoaXMuY3JlZGl0cyA9IEJpZ0ludCh0aGlzLmNyZWRpdHMpO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICBsZXQganNvbjogYW55ID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcyk7XG4gICAgaWYgKGpzb24uY3JlZGl0cyAhPT0gdW5kZWZpbmVkKSBqc29uLmNyZWRpdHMgPSBqc29uLmNyZWRpdHMudG9TdHJpbmcoKTtcbiAgICByZXR1cm4ganNvbjtcbiAgfVxuICBcbiAgZ2V0RWFybGllc3RIZWlnaHQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5lYXJsaWVzdEhlaWdodDtcbiAgfVxuXG4gIHNldEVhcmxpZXN0SGVpZ2h0KGVhcmxpZXN0SGVpZ2h0OiBudW1iZXIpOiBNb25lcm9IYXJkRm9ya0luZm8ge1xuICAgIHRoaXMuZWFybGllc3RIZWlnaHQgPSBlYXJsaWVzdEhlaWdodDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldElzRW5hYmxlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc0VuYWJsZWQ7XG4gIH1cblxuICBzZXRJc0VuYWJsZWQoaXNFbmFibGVkOiBib29sZWFuKTogTW9uZXJvSGFyZEZvcmtJbmZvIHtcbiAgICB0aGlzLmlzRW5hYmxlZCA9IGlzRW5hYmxlZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldFN0YXRlKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGU7XG4gIH1cblxuICBzZXRTdGF0ZShzdGF0ZTogc3RyaW5nKTogTW9uZXJvSGFyZEZvcmtJbmZvIHtcbiAgICB0aGlzLnN0YXRlID0gc3RhdGU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRUaHJlc2hvbGQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy50aHJlc2hvbGQ7XG4gIH1cblxuICBzZXRUaHJlc2hvbGQodGhyZXNob2xkOiBudW1iZXIpOiBNb25lcm9IYXJkRm9ya0luZm8ge1xuICAgIHRoaXMudGhyZXNob2xkID0gdGhyZXNob2xkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0VmVyc2lvbigpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnZlcnNpb247XG4gIH1cblxuICBzZXRWZXJzaW9uKHZlcnNpb246IG51bWJlcik6IE1vbmVyb0hhcmRGb3JrSW5mbyB7XG4gICAgdGhpcy52ZXJzaW9uID0gdmVyc2lvbjtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldE51bVZvdGVzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtVm90ZXM7XG4gIH1cblxuICBzZXROdW1Wb3RlcyhudW1Wb3RlczogbnVtYmVyKTogTW9uZXJvSGFyZEZvcmtJbmZvIHtcbiAgICB0aGlzLm51bVZvdGVzID0gbnVtVm90ZXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRXaW5kb3coKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy53aW5kb3c7XG4gIH1cblxuICBzZXRXaW5kb3cod2luZG93OiBudW1iZXIpOiBNb25lcm9IYXJkRm9ya0luZm8ge1xuICAgIHRoaXMud2luZG93ID0gd2luZG93O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0Vm90aW5nKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMudm90aW5nO1xuICB9XG5cbiAgc2V0Vm90aW5nKHZvdGluZzogbnVtYmVyKTogTW9uZXJvSGFyZEZvcmtJbmZvIHtcbiAgICB0aGlzLnZvdGluZyA9IHZvdGluZztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0Q3JlZGl0cygpOiBiaWdpbnR7XG4gICAgcmV0dXJuIHRoaXMuY3JlZGl0cztcbiAgfVxuICBcbiAgc2V0Q3JlZGl0cyhjcmVkaXRzOiBiaWdpbnQpOiBNb25lcm9IYXJkRm9ya0luZm8ge1xuICAgIHRoaXMuY3JlZGl0cyA9IGNyZWRpdHM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFRvcEJsb2NrSGFzaCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnRvcEJsb2NrSGFzaDtcbiAgfVxuICBcbiAgc2V0VG9wQmxvY2tIYXNoKHRvcEJsb2NrSGFzaDogc3RyaW5nKTogTW9uZXJvSGFyZEZvcmtJbmZvIHtcbiAgICB0aGlzLnRvcEJsb2NrSGFzaCA9IHRvcEJsb2NrSGFzaDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoicUdBQUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUEsa0JBQWtCLENBQUM7Ozs7Ozs7Ozs7Ozs7RUFhdENDLFdBQVdBLENBQUNDLElBQWtDLEVBQUU7SUFDOUNDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsSUFBSSxDQUFDO0lBQ3pCLElBQUksSUFBSSxDQUFDRyxPQUFPLEtBQUtDLFNBQVMsSUFBSSxPQUFPLElBQUksQ0FBQ0QsT0FBTyxLQUFLLFFBQVEsRUFBRSxJQUFJLENBQUNBLE9BQU8sR0FBR0UsTUFBTSxDQUFDLElBQUksQ0FBQ0YsT0FBTyxDQUFDO0VBQ3pHOztFQUVBRyxNQUFNQSxDQUFBLEVBQVE7SUFDWixJQUFJQyxJQUFTLEdBQUdOLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQztJQUN2QyxJQUFJSyxJQUFJLENBQUNKLE9BQU8sS0FBS0MsU0FBUyxFQUFFRyxJQUFJLENBQUNKLE9BQU8sR0FBR0ksSUFBSSxDQUFDSixPQUFPLENBQUNLLFFBQVEsQ0FBQyxDQUFDO0lBQ3RFLE9BQU9ELElBQUk7RUFDYjs7RUFFQUUsaUJBQWlCQSxDQUFBLEVBQVc7SUFDMUIsT0FBTyxJQUFJLENBQUNDLGNBQWM7RUFDNUI7O0VBRUFDLGlCQUFpQkEsQ0FBQ0QsY0FBc0IsRUFBc0I7SUFDNUQsSUFBSSxDQUFDQSxjQUFjLEdBQUdBLGNBQWM7SUFDcEMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLFlBQVlBLENBQUEsRUFBWTtJQUN0QixPQUFPLElBQUksQ0FBQ0MsU0FBUztFQUN2Qjs7RUFFQUMsWUFBWUEsQ0FBQ0QsU0FBa0IsRUFBc0I7SUFDbkQsSUFBSSxDQUFDQSxTQUFTLEdBQUdBLFNBQVM7SUFDMUIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLFFBQVFBLENBQUEsRUFBVztJQUNqQixPQUFPLElBQUksQ0FBQ0MsS0FBSztFQUNuQjs7RUFFQUMsUUFBUUEsQ0FBQ0QsS0FBYSxFQUFzQjtJQUMxQyxJQUFJLENBQUNBLEtBQUssR0FBR0EsS0FBSztJQUNsQixPQUFPLElBQUk7RUFDYjs7RUFFQUUsWUFBWUEsQ0FBQSxFQUFXO0lBQ3JCLE9BQU8sSUFBSSxDQUFDQyxTQUFTO0VBQ3ZCOztFQUVBQyxZQUFZQSxDQUFDRCxTQUFpQixFQUFzQjtJQUNsRCxJQUFJLENBQUNBLFNBQVMsR0FBR0EsU0FBUztJQUMxQixPQUFPLElBQUk7RUFDYjs7RUFFQUUsVUFBVUEsQ0FBQSxFQUFXO0lBQ25CLE9BQU8sSUFBSSxDQUFDQyxPQUFPO0VBQ3JCOztFQUVBQyxVQUFVQSxDQUFDRCxPQUFlLEVBQXNCO0lBQzlDLElBQUksQ0FBQ0EsT0FBTyxHQUFHQSxPQUFPO0lBQ3RCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxXQUFXQSxDQUFBLEVBQVc7SUFDcEIsT0FBTyxJQUFJLENBQUNDLFFBQVE7RUFDdEI7O0VBRUFDLFdBQVdBLENBQUNELFFBQWdCLEVBQXNCO0lBQ2hELElBQUksQ0FBQ0EsUUFBUSxHQUFHQSxRQUFRO0lBQ3hCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxTQUFTQSxDQUFBLEVBQVc7SUFDbEIsT0FBTyxJQUFJLENBQUNDLE1BQU07RUFDcEI7O0VBRUFDLFNBQVNBLENBQUNELE1BQWMsRUFBc0I7SUFDNUMsSUFBSSxDQUFDQSxNQUFNLEdBQUdBLE1BQU07SUFDcEIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLFNBQVNBLENBQUEsRUFBVztJQUNsQixPQUFPLElBQUksQ0FBQ0MsTUFBTTtFQUNwQjs7RUFFQUMsU0FBU0EsQ0FBQ0QsTUFBYyxFQUFzQjtJQUM1QyxJQUFJLENBQUNBLE1BQU0sR0FBR0EsTUFBTTtJQUNwQixPQUFPLElBQUk7RUFDYjs7RUFFQUUsVUFBVUEsQ0FBQSxFQUFVO0lBQ2xCLE9BQU8sSUFBSSxDQUFDOUIsT0FBTztFQUNyQjs7RUFFQStCLFVBQVVBLENBQUMvQixPQUFlLEVBQXNCO0lBQzlDLElBQUksQ0FBQ0EsT0FBTyxHQUFHQSxPQUFPO0lBQ3RCLE9BQU8sSUFBSTtFQUNiOztFQUVBZ0MsZUFBZUEsQ0FBQSxFQUFXO0lBQ3hCLE9BQU8sSUFBSSxDQUFDQyxZQUFZO0VBQzFCOztFQUVBQyxlQUFlQSxDQUFDRCxZQUFvQixFQUFzQjtJQUN4RCxJQUFJLENBQUNBLFlBQVksR0FBR0EsWUFBWTtJQUNoQyxPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNFLE9BQUEsQ0FBQUMsT0FBQSxHQUFBekMsa0JBQUEifQ== \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroKeyImage.d.ts b/dist/src/main/ts/daemon/model/MoneroKeyImage.d.ts new file mode 100644 index 000000000..719ded2ef --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroKeyImage.d.ts @@ -0,0 +1,22 @@ +/** + * Models a Monero key image. + */ +export default class MoneroKeyImage { + hex: string; + signature: string; + /** + * Construct the model. + * + * @param {string|Partial} [keyImageOrHex] is a MoneroKeyImage or hex string to initialize from (optional) + * @param {string} [signature] is the key image's signature + */ + constructor(hexOrKeyImage?: string | Partial, signature?: string); + getHex(): string; + setHex(hex: string): MoneroKeyImage; + getSignature(): string; + setSignature(signature: string): MoneroKeyImage; + copy(): MoneroKeyImage; + toJson(): {} & this; + merge(keyImage: MoneroKeyImage): MoneroKeyImage; + toString(indent?: number): string; +} diff --git a/dist/src/main/ts/daemon/model/MoneroKeyImage.js b/dist/src/main/ts/daemon/model/MoneroKeyImage.js new file mode 100644 index 000000000..9db8f22d4 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroKeyImage.js @@ -0,0 +1,69 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); + + +/** + * Models a Monero key image. + */ +class MoneroKeyImage { + + + + + /** + * Construct the model. + * + * @param {string|Partial} [keyImageOrHex] is a MoneroKeyImage or hex string to initialize from (optional) + * @param {string} [signature] is the key image's signature + */ + constructor(hexOrKeyImage, signature) { + if (typeof hexOrKeyImage === "string") { + this.setHex(hexOrKeyImage); + this.setSignature(signature); + } else { + Object.assign(this, hexOrKeyImage); + } + } + + getHex() { + return this.hex; + } + + setHex(hex) { + this.hex = hex; + return this; + } + + getSignature() { + return this.signature; + } + + setSignature(signature) { + this.signature = signature; + return this; + } + + copy() { + return new MoneroKeyImage(this); + } + + toJson() { + return Object.assign({}, this); + } + + merge(keyImage) { + (0, _assert.default)(keyImage instanceof MoneroKeyImage); + if (keyImage === this) return this; + this.setHex(_GenUtils.default.reconcile(this.getHex(), keyImage.getHex())); + this.setSignature(_GenUtils.default.reconcile(this.getSignature(), keyImage.getSignature())); + return this; + } + + toString(indent = 0) { + let str = ""; + str += _GenUtils.default.kvLine("Hex", this.getHex(), indent); + str += _GenUtils.default.kvLine("Signature", this.getSignature(), indent); + return str.slice(0, str.length - 1); // strip last newline + } +}exports.default = MoneroKeyImage; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJNb25lcm9LZXlJbWFnZSIsImNvbnN0cnVjdG9yIiwiaGV4T3JLZXlJbWFnZSIsInNpZ25hdHVyZSIsInNldEhleCIsInNldFNpZ25hdHVyZSIsIk9iamVjdCIsImFzc2lnbiIsImdldEhleCIsImhleCIsImdldFNpZ25hdHVyZSIsImNvcHkiLCJ0b0pzb24iLCJtZXJnZSIsImtleUltYWdlIiwiYXNzZXJ0IiwiR2VuVXRpbHMiLCJyZWNvbmNpbGUiLCJ0b1N0cmluZyIsImluZGVudCIsInN0ciIsImt2TGluZSIsInNsaWNlIiwibGVuZ3RoIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9kYWVtb24vbW9kZWwvTW9uZXJvS2V5SW1hZ2UudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgR2VuVXRpbHMgZnJvbSBcIi4uLy4uL2NvbW1vbi9HZW5VdGlsc1wiO1xuaW1wb3J0IE1vbmVyb0Vycm9yIGZyb20gXCIuLi8uLi9jb21tb24vTW9uZXJvRXJyb3JcIjtcblxuLyoqXG4gKiBNb2RlbHMgYSBNb25lcm8ga2V5IGltYWdlLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9LZXlJbWFnZSB7XG4gIFxuICBoZXg6IHN0cmluZztcbiAgc2lnbmF0dXJlOiBzdHJpbmc7XG4gIFxuICAvKipcbiAgICogQ29uc3RydWN0IHRoZSBtb2RlbC5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfFBhcnRpYWw8TW9uZXJvS2V5SW1hZ2U+fSBba2V5SW1hZ2VPckhleF0gaXMgYSBNb25lcm9LZXlJbWFnZSBvciBoZXggc3RyaW5nIHRvIGluaXRpYWxpemUgZnJvbSAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbc2lnbmF0dXJlXSBpcyB0aGUga2V5IGltYWdlJ3Mgc2lnbmF0dXJlXG4gICAqL1xuICBjb25zdHJ1Y3RvcihoZXhPcktleUltYWdlPzogc3RyaW5nIHwgUGFydGlhbDxNb25lcm9LZXlJbWFnZT4sIHNpZ25hdHVyZT86IHN0cmluZykge1xuICAgIGlmICh0eXBlb2YgaGV4T3JLZXlJbWFnZSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgdGhpcy5zZXRIZXgoaGV4T3JLZXlJbWFnZSk7XG4gICAgICB0aGlzLnNldFNpZ25hdHVyZShzaWduYXR1cmUpO1xuICAgIH0gZWxzZSB7XG4gICAgICBPYmplY3QuYXNzaWduKHRoaXMsIGhleE9yS2V5SW1hZ2UpO1xuICAgIH1cbiAgfVxuXG4gIGdldEhleCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmhleDtcbiAgfVxuXG4gIHNldEhleChoZXg6IHN0cmluZyk6IE1vbmVyb0tleUltYWdlIHtcbiAgICB0aGlzLmhleCA9IGhleDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldFNpZ25hdHVyZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnNpZ25hdHVyZTtcbiAgfVxuXG4gIHNldFNpZ25hdHVyZShzaWduYXR1cmU6IHN0cmluZyk6IE1vbmVyb0tleUltYWdlIHtcbiAgICB0aGlzLnNpZ25hdHVyZSA9IHNpZ25hdHVyZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgY29weSgpOiBNb25lcm9LZXlJbWFnZSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9LZXlJbWFnZSh0aGlzKTtcbiAgfVxuICBcbiAgdG9Kc29uKCkge1xuICAgIHJldHVybiBPYmplY3QuYXNzaWduKHt9LCB0aGlzKTtcbiAgfVxuICBcbiAgbWVyZ2Uoa2V5SW1hZ2U6IE1vbmVyb0tleUltYWdlKTogTW9uZXJvS2V5SW1hZ2Uge1xuICAgIGFzc2VydChrZXlJbWFnZSBpbnN0YW5jZW9mIE1vbmVyb0tleUltYWdlKTtcbiAgICBpZiAoa2V5SW1hZ2UgPT09IHRoaXMpIHJldHVybiB0aGlzO1xuICAgIHRoaXMuc2V0SGV4KEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldEhleCgpLCBrZXlJbWFnZS5nZXRIZXgoKSkpO1xuICAgIHRoaXMuc2V0U2lnbmF0dXJlKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldFNpZ25hdHVyZSgpLCBrZXlJbWFnZS5nZXRTaWduYXR1cmUoKSkpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICB0b1N0cmluZyhpbmRlbnQgPSAwKTogc3RyaW5nIHtcbiAgICBsZXQgc3RyID0gXCJcIjtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiSGV4XCIsIHRoaXMuZ2V0SGV4KCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlNpZ25hdHVyZVwiLCB0aGlzLmdldFNpZ25hdHVyZSgpLCBpbmRlbnQpO1xuICAgIHJldHVybiBzdHIuc2xpY2UoMCwgc3RyLmxlbmd0aCAtIDEpOyAgLy8gc3RyaXAgbGFzdCBuZXdsaW5lXG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFNBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ2UsTUFBTUUsY0FBYyxDQUFDOzs7OztFQUtsQztBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDRUMsV0FBV0EsQ0FBQ0MsYUFBZ0QsRUFBRUMsU0FBa0IsRUFBRTtJQUNoRixJQUFJLE9BQU9ELGFBQWEsS0FBSyxRQUFRLEVBQUU7TUFDckMsSUFBSSxDQUFDRSxNQUFNLENBQUNGLGFBQWEsQ0FBQztNQUMxQixJQUFJLENBQUNHLFlBQVksQ0FBQ0YsU0FBUyxDQUFDO0lBQzlCLENBQUMsTUFBTTtNQUNMRyxNQUFNLENBQUNDLE1BQU0sQ0FBQyxJQUFJLEVBQUVMLGFBQWEsQ0FBQztJQUNwQztFQUNGOztFQUVBTSxNQUFNQSxDQUFBLEVBQVc7SUFDZixPQUFPLElBQUksQ0FBQ0MsR0FBRztFQUNqQjs7RUFFQUwsTUFBTUEsQ0FBQ0ssR0FBVyxFQUFrQjtJQUNsQyxJQUFJLENBQUNBLEdBQUcsR0FBR0EsR0FBRztJQUNkLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxZQUFZQSxDQUFBLEVBQVc7SUFDckIsT0FBTyxJQUFJLENBQUNQLFNBQVM7RUFDdkI7O0VBRUFFLFlBQVlBLENBQUNGLFNBQWlCLEVBQWtCO0lBQzlDLElBQUksQ0FBQ0EsU0FBUyxHQUFHQSxTQUFTO0lBQzFCLE9BQU8sSUFBSTtFQUNiOztFQUVBUSxJQUFJQSxDQUFBLEVBQW1CO0lBQ3JCLE9BQU8sSUFBSVgsY0FBYyxDQUFDLElBQUksQ0FBQztFQUNqQzs7RUFFQVksTUFBTUEsQ0FBQSxFQUFHO0lBQ1AsT0FBT04sTUFBTSxDQUFDQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO0VBQ2hDOztFQUVBTSxLQUFLQSxDQUFDQyxRQUF3QixFQUFrQjtJQUM5QyxJQUFBQyxlQUFNLEVBQUNELFFBQVEsWUFBWWQsY0FBYyxDQUFDO0lBQzFDLElBQUljLFFBQVEsS0FBSyxJQUFJLEVBQUUsT0FBTyxJQUFJO0lBQ2xDLElBQUksQ0FBQ1YsTUFBTSxDQUFDWSxpQkFBUSxDQUFDQyxTQUFTLENBQUMsSUFBSSxDQUFDVCxNQUFNLENBQUMsQ0FBQyxFQUFFTSxRQUFRLENBQUNOLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNqRSxJQUFJLENBQUNILFlBQVksQ0FBQ1csaUJBQVEsQ0FBQ0MsU0FBUyxDQUFDLElBQUksQ0FBQ1AsWUFBWSxDQUFDLENBQUMsRUFBRUksUUFBUSxDQUFDSixZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbkYsT0FBTyxJQUFJO0VBQ2I7O0VBRUFRLFFBQVFBLENBQUNDLE1BQU0sR0FBRyxDQUFDLEVBQVU7SUFDM0IsSUFBSUMsR0FBRyxHQUFHLEVBQUU7SUFDWkEsR0FBRyxJQUFJSixpQkFBUSxDQUFDSyxNQUFNLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQ2IsTUFBTSxDQUFDLENBQUMsRUFBRVcsTUFBTSxDQUFDO0lBQ3BEQyxHQUFHLElBQUlKLGlCQUFRLENBQUNLLE1BQU0sQ0FBQyxXQUFXLEVBQUUsSUFBSSxDQUFDWCxZQUFZLENBQUMsQ0FBQyxFQUFFUyxNQUFNLENBQUM7SUFDaEUsT0FBT0MsR0FBRyxDQUFDRSxLQUFLLENBQUMsQ0FBQyxFQUFFRixHQUFHLENBQUNHLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFFO0VBQ3hDO0FBQ0YsQ0FBQ0MsT0FBQSxDQUFBQyxPQUFBLEdBQUF6QixjQUFBIn0= \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroKeyImageSpentStatus.d.ts b/dist/src/main/ts/daemon/model/MoneroKeyImageSpentStatus.d.ts new file mode 100644 index 000000000..fb4cca931 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroKeyImageSpentStatus.d.ts @@ -0,0 +1,20 @@ +/** + * Enumerates connection types. + * + * Based on enums.h in monero-project. + */ +declare enum MoneroKeyImageSpentStatus { + /** + * Key image is not spent (value=0). + */ + NOT_SPENT = 0, + /** + * Key image is confirmed (value=1). + */ + CONFIRMED = 1, + /** + * Key image is in the pool (value=2). + */ + TX_POOL = 2 +} +export default MoneroKeyImageSpentStatus; diff --git a/dist/src/main/ts/daemon/model/MoneroKeyImageSpentStatus.js b/dist/src/main/ts/daemon/model/MoneroKeyImageSpentStatus.js new file mode 100644 index 000000000..f1ab4f500 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroKeyImageSpentStatus.js @@ -0,0 +1,25 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Enumerates connection types. + * + * Based on enums.h in monero-project. + */var +MoneroKeyImageSpentStatus = /*#__PURE__*/function (MoneroKeyImageSpentStatus) {MoneroKeyImageSpentStatus[MoneroKeyImageSpentStatus["NOT_SPENT"] = 0] = "NOT_SPENT";MoneroKeyImageSpentStatus[MoneroKeyImageSpentStatus["CONFIRMED"] = 1] = "CONFIRMED";MoneroKeyImageSpentStatus[MoneroKeyImageSpentStatus["TX_POOL"] = 2] = "TX_POOL";return MoneroKeyImageSpentStatus;}(MoneroKeyImageSpentStatus || {});var _default = exports.default = + + + + + + + + + + + + + + + + + +MoneroKeyImageSpentStatus; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9LZXlJbWFnZVNwZW50U3RhdHVzIiwiX2RlZmF1bHQiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2RhZW1vbi9tb2RlbC9Nb25lcm9LZXlJbWFnZVNwZW50U3RhdHVzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRW51bWVyYXRlcyBjb25uZWN0aW9uIHR5cGVzLlxuICogXG4gKiBCYXNlZCBvbiBlbnVtcy5oIGluIG1vbmVyby1wcm9qZWN0LlxuICovXG5lbnVtIE1vbmVyb0tleUltYWdlU3BlbnRTdGF0dXMge1xuXG4gICAgLyoqXG4gICAgICogS2V5IGltYWdlIGlzIG5vdCBzcGVudCAodmFsdWU9MCkuXG4gICAgICovXG4gICAgTk9UX1NQRU5UID0gMCxcblxuICAgIC8qKlxuICAgICAqIEtleSBpbWFnZSBpcyBjb25maXJtZWQgKHZhbHVlPTEpLlxuICAgICAqL1xuICAgIENPTkZJUk1FRCA9IDEsXG5cbiAgICAvKipcbiAgICAgKiBLZXkgaW1hZ2UgaXMgaW4gdGhlIHBvb2wgKHZhbHVlPTIpLlxuICAgICAqL1xuICAgIFRYX1BPT0wgPSAyXG4gIH1cbiAgXG4gIGV4cG9ydCBkZWZhdWx0IE1vbmVyb0tleUltYWdlU3BlbnRTdGF0dXM7Il0sIm1hcHBpbmdzIjoicUdBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUpBO0FBS0tBLHlCQUF5QiwwQkFBekJBLHlCQUF5QixHQUF6QkEseUJBQXlCLENBQXpCQSx5QkFBeUIsaUNBQXpCQSx5QkFBeUIsQ0FBekJBLHlCQUF5QixpQ0FBekJBLHlCQUF5QixDQUF6QkEseUJBQXlCLG9DQUF6QkEseUJBQXlCLEdBQXpCQSx5QkFBeUIsWUFBQUMsUUFBQSxHQUFBQyxPQUFBLENBQUFDLE9BQUE7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQWtCYkgseUJBQXlCIn0= \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroMinerTxSum.d.ts b/dist/src/main/ts/daemon/model/MoneroMinerTxSum.d.ts new file mode 100644 index 000000000..db2953280 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroMinerTxSum.d.ts @@ -0,0 +1,13 @@ +/** + * Model for the summation of miner emissions and fees. + */ +export default class MoneroMinerTxSum { + emissionSum: bigint; + feeSum: bigint; + constructor(txSum?: Partial); + toJson(): any; + getEmissionSum(): bigint; + setEmissionSum(emissionSum: bigint): MoneroMinerTxSum; + getFeeSum(): bigint; + setFeeSum(feeSum: bigint): MoneroMinerTxSum; +} diff --git a/dist/src/main/ts/daemon/model/MoneroMinerTxSum.js b/dist/src/main/ts/daemon/model/MoneroMinerTxSum.js new file mode 100644 index 000000000..8b106df0d --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroMinerTxSum.js @@ -0,0 +1,42 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Model for the summation of miner emissions and fees. + */ +class MoneroMinerTxSum { + + + + + constructor(txSum) { + Object.assign(this, txSum); + + // deserialize bigints + if (this.emissionSum !== undefined && typeof this.emissionSum !== "bigint") this.emissionSum = BigInt(this.emissionSum); + if (this.feeSum !== undefined && typeof this.feeSum !== "bigint") this.feeSum = BigInt(this.feeSum); + } + + toJson() { + let json = Object.assign({}, this); + if (this.getEmissionSum() !== undefined) json.emissionSum = this.getEmissionSum().toString(); + if (this.getFeeSum() !== undefined) json.feeSum = this.getFeeSum().toString(); + return json; + } + + getEmissionSum() { + return this.emissionSum; + } + + setEmissionSum(emissionSum) { + this.emissionSum = emissionSum; + return this; + } + + getFeeSum() { + return this.feeSum; + } + + setFeeSum(feeSum) { + this.feeSum = feeSum; + return this; + } +}exports.default = MoneroMinerTxSum; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9NaW5lclR4U3VtIiwiY29uc3RydWN0b3IiLCJ0eFN1bSIsIk9iamVjdCIsImFzc2lnbiIsImVtaXNzaW9uU3VtIiwidW5kZWZpbmVkIiwiQmlnSW50IiwiZmVlU3VtIiwidG9Kc29uIiwianNvbiIsImdldEVtaXNzaW9uU3VtIiwidG9TdHJpbmciLCJnZXRGZWVTdW0iLCJzZXRFbWlzc2lvblN1bSIsInNldEZlZVN1bSIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvZGFlbW9uL21vZGVsL01vbmVyb01pbmVyVHhTdW0udHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBNb2RlbCBmb3IgdGhlIHN1bW1hdGlvbiBvZiBtaW5lciBlbWlzc2lvbnMgYW5kIGZlZXMuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb01pbmVyVHhTdW0ge1xuXG4gIGVtaXNzaW9uU3VtOiBiaWdpbnQ7XG4gIGZlZVN1bTogYmlnaW50O1xuICBcbiAgY29uc3RydWN0b3IodHhTdW0/OiBQYXJ0aWFsPE1vbmVyb01pbmVyVHhTdW0+KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCB0eFN1bSk7XG5cbiAgICAvLyBkZXNlcmlhbGl6ZSBiaWdpbnRzXG4gICAgaWYgKHRoaXMuZW1pc3Npb25TdW0gIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5lbWlzc2lvblN1bSAhPT0gXCJiaWdpbnRcIikgdGhpcy5lbWlzc2lvblN1bSA9IEJpZ0ludCh0aGlzLmVtaXNzaW9uU3VtKTtcbiAgICBpZiAodGhpcy5mZWVTdW0gIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5mZWVTdW0gIT09IFwiYmlnaW50XCIpIHRoaXMuZmVlU3VtID0gQmlnSW50KHRoaXMuZmVlU3VtKTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgbGV0IGpzb246IGFueSA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICAgIGlmICh0aGlzLmdldEVtaXNzaW9uU3VtKCkgIT09IHVuZGVmaW5lZCkganNvbi5lbWlzc2lvblN1bSA9IHRoaXMuZ2V0RW1pc3Npb25TdW0oKS50b1N0cmluZygpO1xuICAgIGlmICh0aGlzLmdldEZlZVN1bSgpICE9PSB1bmRlZmluZWQpIGpzb24uZmVlU3VtID0gdGhpcy5nZXRGZWVTdW0oKS50b1N0cmluZygpO1xuICAgIHJldHVybiBqc29uO1xuICB9XG4gIFxuICBnZXRFbWlzc2lvblN1bSgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLmVtaXNzaW9uU3VtO1xuICB9XG4gIFxuICBzZXRFbWlzc2lvblN1bShlbWlzc2lvblN1bTogYmlnaW50KTogTW9uZXJvTWluZXJUeFN1bSB7XG4gICAgdGhpcy5lbWlzc2lvblN1bSA9IGVtaXNzaW9uU3VtO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRGZWVTdW0oKTogYmlnaW50IHtcbiAgICByZXR1cm4gdGhpcy5mZWVTdW07XG4gIH1cbiAgXG4gIHNldEZlZVN1bShmZWVTdW06IGJpZ2ludCk6IE1vbmVyb01pbmVyVHhTdW0ge1xuICAgIHRoaXMuZmVlU3VtID0gZmVlU3VtO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59Il0sIm1hcHBpbmdzIjoicUdBQUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUEsZ0JBQWdCLENBQUM7Ozs7O0VBS3BDQyxXQUFXQSxDQUFDQyxLQUFpQyxFQUFFO0lBQzdDQyxNQUFNLENBQUNDLE1BQU0sQ0FBQyxJQUFJLEVBQUVGLEtBQUssQ0FBQzs7SUFFMUI7SUFDQSxJQUFJLElBQUksQ0FBQ0csV0FBVyxLQUFLQyxTQUFTLElBQUksT0FBTyxJQUFJLENBQUNELFdBQVcsS0FBSyxRQUFRLEVBQUUsSUFBSSxDQUFDQSxXQUFXLEdBQUdFLE1BQU0sQ0FBQyxJQUFJLENBQUNGLFdBQVcsQ0FBQztJQUN2SCxJQUFJLElBQUksQ0FBQ0csTUFBTSxLQUFLRixTQUFTLElBQUksT0FBTyxJQUFJLENBQUNFLE1BQU0sS0FBSyxRQUFRLEVBQUUsSUFBSSxDQUFDQSxNQUFNLEdBQUdELE1BQU0sQ0FBQyxJQUFJLENBQUNDLE1BQU0sQ0FBQztFQUNyRzs7RUFFQUMsTUFBTUEsQ0FBQSxFQUFRO0lBQ1osSUFBSUMsSUFBUyxHQUFHUCxNQUFNLENBQUNDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUM7SUFDdkMsSUFBSSxJQUFJLENBQUNPLGNBQWMsQ0FBQyxDQUFDLEtBQUtMLFNBQVMsRUFBRUksSUFBSSxDQUFDTCxXQUFXLEdBQUcsSUFBSSxDQUFDTSxjQUFjLENBQUMsQ0FBQyxDQUFDQyxRQUFRLENBQUMsQ0FBQztJQUM1RixJQUFJLElBQUksQ0FBQ0MsU0FBUyxDQUFDLENBQUMsS0FBS1AsU0FBUyxFQUFFSSxJQUFJLENBQUNGLE1BQU0sR0FBRyxJQUFJLENBQUNLLFNBQVMsQ0FBQyxDQUFDLENBQUNELFFBQVEsQ0FBQyxDQUFDO0lBQzdFLE9BQU9GLElBQUk7RUFDYjs7RUFFQUMsY0FBY0EsQ0FBQSxFQUFXO0lBQ3ZCLE9BQU8sSUFBSSxDQUFDTixXQUFXO0VBQ3pCOztFQUVBUyxjQUFjQSxDQUFDVCxXQUFtQixFQUFvQjtJQUNwRCxJQUFJLENBQUNBLFdBQVcsR0FBR0EsV0FBVztJQUM5QixPQUFPLElBQUk7RUFDYjs7RUFFQVEsU0FBU0EsQ0FBQSxFQUFXO0lBQ2xCLE9BQU8sSUFBSSxDQUFDTCxNQUFNO0VBQ3BCOztFQUVBTyxTQUFTQSxDQUFDUCxNQUFjLEVBQW9CO0lBQzFDLElBQUksQ0FBQ0EsTUFBTSxHQUFHQSxNQUFNO0lBQ3BCLE9BQU8sSUFBSTtFQUNiO0FBQ0YsQ0FBQ1EsT0FBQSxDQUFBQyxPQUFBLEdBQUFqQixnQkFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroMiningStatus.d.ts b/dist/src/main/ts/daemon/model/MoneroMiningStatus.d.ts new file mode 100644 index 000000000..f059790ba --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroMiningStatus.d.ts @@ -0,0 +1,22 @@ +/** + * Models daemon mining status. + */ +export default class MoneroMiningStatus { + isActive: boolean; + address: string; + speed: number; + numThreads: number; + isBackground: boolean; + constructor(status?: Partial); + toJson(): {} & this; + getIsActive(): boolean; + setIsActive(isActive: boolean): MoneroMiningStatus; + getAddress(): string; + setAddress(address: string): MoneroMiningStatus; + getSpeed(): number; + setSpeed(speed: number): MoneroMiningStatus; + getNumThreads(): number; + setNumThreads(numThreads: number): MoneroMiningStatus; + getIsBackground(): boolean; + setIsBackground(isBackground: boolean): MoneroMiningStatus; +} diff --git a/dist/src/main/ts/daemon/model/MoneroMiningStatus.js b/dist/src/main/ts/daemon/model/MoneroMiningStatus.js new file mode 100644 index 000000000..12de0f516 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroMiningStatus.js @@ -0,0 +1,65 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Models daemon mining status. + */ +class MoneroMiningStatus { + + + + + + + + constructor(status) { + Object.assign(this, status); + } + + toJson() { + return Object.assign({}, this); + } + + getIsActive() { + return this.isActive; + } + + setIsActive(isActive) { + this.isActive = isActive; + return this; + } + + getAddress() { + return this.address; + } + + setAddress(address) { + this.address = address; + return this; + } + + getSpeed() { + return this.speed; + } + + setSpeed(speed) { + this.speed = speed; + return this; + } + + getNumThreads() { + return this.numThreads; + } + + setNumThreads(numThreads) { + this.numThreads = numThreads; + return this; + } + + getIsBackground() { + return this.isBackground; + } + + setIsBackground(isBackground) { + this.isBackground = isBackground; + return this; + } +}exports.default = MoneroMiningStatus; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9NaW5pbmdTdGF0dXMiLCJjb25zdHJ1Y3RvciIsInN0YXR1cyIsIk9iamVjdCIsImFzc2lnbiIsInRvSnNvbiIsImdldElzQWN0aXZlIiwiaXNBY3RpdmUiLCJzZXRJc0FjdGl2ZSIsImdldEFkZHJlc3MiLCJhZGRyZXNzIiwic2V0QWRkcmVzcyIsImdldFNwZWVkIiwic3BlZWQiLCJzZXRTcGVlZCIsImdldE51bVRocmVhZHMiLCJudW1UaHJlYWRzIiwic2V0TnVtVGhyZWFkcyIsImdldElzQmFja2dyb3VuZCIsImlzQmFja2dyb3VuZCIsInNldElzQmFja2dyb3VuZCIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvZGFlbW9uL21vZGVsL01vbmVyb01pbmluZ1N0YXR1cy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1vZGVscyBkYWVtb24gbWluaW5nIHN0YXR1cy5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTW9uZXJvTWluaW5nU3RhdHVzIHtcblxuICBpc0FjdGl2ZTogYm9vbGVhbjtcbiAgYWRkcmVzczogc3RyaW5nO1xuICBzcGVlZDogbnVtYmVyO1xuICBudW1UaHJlYWRzOiBudW1iZXI7XG4gIGlzQmFja2dyb3VuZDogYm9vbGVhbjtcbiAgXG4gIGNvbnN0cnVjdG9yKHN0YXR1cz86IFBhcnRpYWw8TW9uZXJvTWluaW5nU3RhdHVzPikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgc3RhdHVzKTtcbiAgfVxuICBcbiAgdG9Kc29uKCkge1xuICAgIHJldHVybiBPYmplY3QuYXNzaWduKHt9LCB0aGlzKTtcbiAgfVxuICBcbiAgZ2V0SXNBY3RpdmUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNBY3RpdmU7XG4gIH1cbiAgXG4gIHNldElzQWN0aXZlKGlzQWN0aXZlOiBib29sZWFuKTogTW9uZXJvTWluaW5nU3RhdHVzIHtcbiAgICB0aGlzLmlzQWN0aXZlID0gaXNBY3RpdmU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEFkZHJlc3MoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5hZGRyZXNzO1xuICB9XG4gIFxuICBzZXRBZGRyZXNzKGFkZHJlc3M6IHN0cmluZyk6IE1vbmVyb01pbmluZ1N0YXR1cyB7XG4gICAgdGhpcy5hZGRyZXNzID0gYWRkcmVzcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U3BlZWQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5zcGVlZDtcbiAgfVxuICBcbiAgc2V0U3BlZWQoc3BlZWQ6IG51bWJlcik6IE1vbmVyb01pbmluZ1N0YXR1cyB7XG4gICAgdGhpcy5zcGVlZCA9IHNwZWVkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXROdW1UaHJlYWRzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtVGhyZWFkcztcbiAgfVxuICBcbiAgc2V0TnVtVGhyZWFkcyhudW1UaHJlYWRzOiBudW1iZXIpOiBNb25lcm9NaW5pbmdTdGF0dXMge1xuICAgIHRoaXMubnVtVGhyZWFkcyA9IG51bVRocmVhZHM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldElzQmFja2dyb3VuZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc0JhY2tncm91bmQ7XG4gIH1cbiAgXG4gIHNldElzQmFja2dyb3VuZChpc0JhY2tncm91bmQ6IGJvb2xlYW4pOiBNb25lcm9NaW5pbmdTdGF0dXMge1xuICAgIHRoaXMuaXNCYWNrZ3JvdW5kID0gaXNCYWNrZ3JvdW5kO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJxR0FBQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSxrQkFBa0IsQ0FBQzs7Ozs7Ozs7RUFRdENDLFdBQVdBLENBQUNDLE1BQW9DLEVBQUU7SUFDaERDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsTUFBTSxDQUFDO0VBQzdCOztFQUVBRyxNQUFNQSxDQUFBLEVBQUc7SUFDUCxPQUFPRixNQUFNLENBQUNDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUM7RUFDaEM7O0VBRUFFLFdBQVdBLENBQUEsRUFBWTtJQUNyQixPQUFPLElBQUksQ0FBQ0MsUUFBUTtFQUN0Qjs7RUFFQUMsV0FBV0EsQ0FBQ0QsUUFBaUIsRUFBc0I7SUFDakQsSUFBSSxDQUFDQSxRQUFRLEdBQUdBLFFBQVE7SUFDeEIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLFVBQVVBLENBQUEsRUFBVztJQUNuQixPQUFPLElBQUksQ0FBQ0MsT0FBTztFQUNyQjs7RUFFQUMsVUFBVUEsQ0FBQ0QsT0FBZSxFQUFzQjtJQUM5QyxJQUFJLENBQUNBLE9BQU8sR0FBR0EsT0FBTztJQUN0QixPQUFPLElBQUk7RUFDYjs7RUFFQUUsUUFBUUEsQ0FBQSxFQUFXO0lBQ2pCLE9BQU8sSUFBSSxDQUFDQyxLQUFLO0VBQ25COztFQUVBQyxRQUFRQSxDQUFDRCxLQUFhLEVBQXNCO0lBQzFDLElBQUksQ0FBQ0EsS0FBSyxHQUFHQSxLQUFLO0lBQ2xCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxhQUFhQSxDQUFBLEVBQVc7SUFDdEIsT0FBTyxJQUFJLENBQUNDLFVBQVU7RUFDeEI7O0VBRUFDLGFBQWFBLENBQUNELFVBQWtCLEVBQXNCO0lBQ3BELElBQUksQ0FBQ0EsVUFBVSxHQUFHQSxVQUFVO0lBQzVCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxlQUFlQSxDQUFBLEVBQVk7SUFDekIsT0FBTyxJQUFJLENBQUNDLFlBQVk7RUFDMUI7O0VBRUFDLGVBQWVBLENBQUNELFlBQXFCLEVBQXNCO0lBQ3pELElBQUksQ0FBQ0EsWUFBWSxHQUFHQSxZQUFZO0lBQ2hDLE9BQU8sSUFBSTtFQUNiO0FBQ0YsQ0FBQ0UsT0FBQSxDQUFBQyxPQUFBLEdBQUF0QixrQkFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroNetworkType.d.ts b/dist/src/main/ts/daemon/model/MoneroNetworkType.d.ts new file mode 100644 index 000000000..e803de067 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroNetworkType.d.ts @@ -0,0 +1,50 @@ +/** + * Defines the Monero network types (mainnet, testnet, and stagenet). + */ +export default class MoneroNetworkType { + /** + * Mainnet (value=0). + */ + static readonly MAINNET = 0; + /** + * Testnet (value=1). + */ + static readonly TESTNET = 1; + /** + * Stagnet (value=2). + */ + static readonly STAGENET = 2; + /** + * Validate and normalize the given network type. + * + * @param {MoneroNetworkType | number | string} networkType - the network type to validate and normalize + * @return {MoneroNetworkType} the given network type + */ + static from(networkType: MoneroNetworkType | number | string): MoneroNetworkType; + /** + * Validate the given network type. + * + * @param {MoneroNetworkType} networkType - the network type to validate as a numeric + */ + static validate(networkType: MoneroNetworkType | number | string): void; + /** + * Indicates if the given network type is valid or not. + * + * @param {MoneroNetworkType | number} networkType - the network type to validate as a numeric + * @return {boolean} true if the network type is valid, false otherwise + */ + static isValid(networkType: MoneroNetworkType | number | string): boolean; + /** + * Parse the given string as a network type. + * + * @param {string} networkTypeStr - "mainnet", "testnet", or "stagenet" (case insensitive) + * @return {MoneroNetworkType} the network type as a numeric + */ + static parse(networkTypeStr: string): MoneroNetworkType; + /** + * Get the network type in human-readable form. + * + * @return {string} the network type in human-readable form + */ + static toString(networkType: MoneroNetworkType | number): string; +} diff --git a/dist/src/main/ts/daemon/model/MoneroNetworkType.js b/dist/src/main/ts/daemon/model/MoneroNetworkType.js new file mode 100644 index 000000000..f16f7c59e --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroNetworkType.js @@ -0,0 +1,88 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _MoneroError = _interopRequireDefault(require("../../common/MoneroError")); + +/** + * Defines the Monero network types (mainnet, testnet, and stagenet). + */ +class MoneroNetworkType { + + /** + * Mainnet (value=0). + */ + static MAINNET = 0; + + /** + * Testnet (value=1). + */ + static TESTNET = 1; + + /** + * Stagnet (value=2). + */ + static STAGENET = 2; + + /** + * Validate and normalize the given network type. + * + * @param {MoneroNetworkType | number | string} networkType - the network type to validate and normalize + * @return {MoneroNetworkType} the given network type + */ + static from(networkType) { + if (typeof networkType === "string") return MoneroNetworkType.parse(networkType); + MoneroNetworkType.validate(networkType); + return networkType; + } + + /** + * Validate the given network type. + * + * @param {MoneroNetworkType} networkType - the network type to validate as a numeric + */ + static validate(networkType) { + if (typeof networkType === "string") MoneroNetworkType.parse(networkType);else + if (networkType !== 0 && networkType !== 1 && networkType !== 2) throw new _MoneroError.default("Network type is invalid: " + networkType); + } + + /** + * Indicates if the given network type is valid or not. + * + * @param {MoneroNetworkType | number} networkType - the network type to validate as a numeric + * @return {boolean} true if the network type is valid, false otherwise + */ + static isValid(networkType) { + try { + MoneroNetworkType.validate(networkType); + return true; + } catch (err) { + return false; + } + } + + /** + * Parse the given string as a network type. + * + * @param {string} networkTypeStr - "mainnet", "testnet", or "stagenet" (case insensitive) + * @return {MoneroNetworkType} the network type as a numeric + */ + static parse(networkTypeStr) { + let str = ("" + networkTypeStr).toLowerCase(); + switch (str) { + case "mainnet":return MoneroNetworkType.MAINNET; + case "testnet":return MoneroNetworkType.TESTNET; + case "stagenet":return MoneroNetworkType.STAGENET; + default:throw new _MoneroError.default("Invalid network type to parse: '" + networkTypeStr + "'"); + } + } + + /** + * Get the network type in human-readable form. + * + * @return {string} the network type in human-readable form + */ + static toString(networkType) { + if (networkType === 0) return "mainnet"; + if (networkType === 1) return "testnet"; + if (networkType === 2) return "stagenet"; + throw new _MoneroError.default("Invalid network type: " + networkType); + } +}exports.default = MoneroNetworkType; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfTW9uZXJvRXJyb3IiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIk1vbmVyb05ldHdvcmtUeXBlIiwiTUFJTk5FVCIsIlRFU1RORVQiLCJTVEFHRU5FVCIsImZyb20iLCJuZXR3b3JrVHlwZSIsInBhcnNlIiwidmFsaWRhdGUiLCJNb25lcm9FcnJvciIsImlzVmFsaWQiLCJlcnIiLCJuZXR3b3JrVHlwZVN0ciIsInN0ciIsInRvTG93ZXJDYXNlIiwidG9TdHJpbmciLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2RhZW1vbi9tb2RlbC9Nb25lcm9OZXR3b3JrVHlwZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgTW9uZXJvRXJyb3IgZnJvbSBcIi4uLy4uL2NvbW1vbi9Nb25lcm9FcnJvclwiO1xuXG4vKipcbiAqIERlZmluZXMgdGhlIE1vbmVybyBuZXR3b3JrIHR5cGVzIChtYWlubmV0LCB0ZXN0bmV0LCBhbmQgc3RhZ2VuZXQpLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9OZXR3b3JrVHlwZSB7XG5cbiAgLyoqXG4gICAqIE1haW5uZXQgKHZhbHVlPTApLlxuICAgKi9cbiAgc3RhdGljIHJlYWRvbmx5IE1BSU5ORVQgPSAwO1xuXG4gIC8qKlxuICAgKiBUZXN0bmV0ICh2YWx1ZT0xKS5cbiAgICovXG4gIHN0YXRpYyByZWFkb25seSBURVNUTkVUID0gMTtcblxuICAvKipcbiAgICogU3RhZ25ldCAodmFsdWU9MikuXG4gICAqL1xuICBzdGF0aWMgcmVhZG9ubHkgU1RBR0VORVQgPSAyO1xuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBhbmQgbm9ybWFsaXplIHRoZSBnaXZlbiBuZXR3b3JrIHR5cGUuXG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb05ldHdvcmtUeXBlIHwgbnVtYmVyIHwgc3RyaW5nfSBuZXR3b3JrVHlwZSAtIHRoZSBuZXR3b3JrIHR5cGUgdG8gdmFsaWRhdGUgYW5kIG5vcm1hbGl6ZVxuICAgKiBAcmV0dXJuIHtNb25lcm9OZXR3b3JrVHlwZX0gdGhlIGdpdmVuIG5ldHdvcmsgdHlwZVxuICAgKi9cbiAgICBzdGF0aWMgZnJvbShuZXR3b3JrVHlwZTogTW9uZXJvTmV0d29ya1R5cGUgfCBudW1iZXIgfCBzdHJpbmcpOiBNb25lcm9OZXR3b3JrVHlwZSB7XG4gICAgICBpZiAodHlwZW9mIG5ldHdvcmtUeXBlID09PSBcInN0cmluZ1wiKSByZXR1cm4gTW9uZXJvTmV0d29ya1R5cGUucGFyc2UobmV0d29ya1R5cGUpO1xuICAgICAgTW9uZXJvTmV0d29ya1R5cGUudmFsaWRhdGUobmV0d29ya1R5cGUpO1xuICAgICAgcmV0dXJuIG5ldHdvcmtUeXBlO1xuICAgIH1cbiAgXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGUgZ2l2ZW4gbmV0d29yayB0eXBlLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9OZXR3b3JrVHlwZX0gbmV0d29ya1R5cGUgLSB0aGUgbmV0d29yayB0eXBlIHRvIHZhbGlkYXRlIGFzIGEgbnVtZXJpY1xuICAgKi9cbiAgc3RhdGljIHZhbGlkYXRlKG5ldHdvcmtUeXBlOiBNb25lcm9OZXR3b3JrVHlwZSB8IG51bWJlciB8IHN0cmluZykge1xuICAgIGlmICh0eXBlb2YgbmV0d29ya1R5cGUgPT09IFwic3RyaW5nXCIpIE1vbmVyb05ldHdvcmtUeXBlLnBhcnNlKG5ldHdvcmtUeXBlKTtcbiAgICBlbHNlIGlmIChuZXR3b3JrVHlwZSAhPT0gMCAmJiBuZXR3b3JrVHlwZSAhPT0gMSAmJiBuZXR3b3JrVHlwZSAhPT0gMikgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTmV0d29yayB0eXBlIGlzIGludmFsaWQ6IFwiICsgbmV0d29ya1R5cGUpO1xuICB9XG4gIFxuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIHRoZSBnaXZlbiBuZXR3b3JrIHR5cGUgaXMgdmFsaWQgb3Igbm90LlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9OZXR3b3JrVHlwZSB8IG51bWJlcn0gbmV0d29ya1R5cGUgLSB0aGUgbmV0d29yayB0eXBlIHRvIHZhbGlkYXRlIGFzIGEgbnVtZXJpY1xuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHRoZSBuZXR3b3JrIHR5cGUgaXMgdmFsaWQsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgc3RhdGljIGlzVmFsaWQobmV0d29ya1R5cGU6IE1vbmVyb05ldHdvcmtUeXBlIHwgbnVtYmVyIHwgc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgdHJ5IHtcbiAgICAgIE1vbmVyb05ldHdvcmtUeXBlLnZhbGlkYXRlKG5ldHdvcmtUeXBlKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2goZXJyKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFBhcnNlIHRoZSBnaXZlbiBzdHJpbmcgYXMgYSBuZXR3b3JrIHR5cGUuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmV0d29ya1R5cGVTdHIgLSBcIm1haW5uZXRcIiwgXCJ0ZXN0bmV0XCIsIG9yIFwic3RhZ2VuZXRcIiAoY2FzZSBpbnNlbnNpdGl2ZSlcbiAgICogQHJldHVybiB7TW9uZXJvTmV0d29ya1R5cGV9IHRoZSBuZXR3b3JrIHR5cGUgYXMgYSBudW1lcmljXG4gICAqL1xuICBzdGF0aWMgcGFyc2UobmV0d29ya1R5cGVTdHI6IHN0cmluZyk6IE1vbmVyb05ldHdvcmtUeXBlIHtcbiAgICBsZXQgc3RyID0gKFwiXCIgKyBuZXR3b3JrVHlwZVN0cikudG9Mb3dlckNhc2UoKTtcbiAgICBzd2l0Y2ggKHN0cikge1xuICAgICAgY2FzZSBcIm1haW5uZXRcIjogcmV0dXJuIE1vbmVyb05ldHdvcmtUeXBlLk1BSU5ORVQ7XG4gICAgICBjYXNlIFwidGVzdG5ldFwiOiByZXR1cm4gTW9uZXJvTmV0d29ya1R5cGUuVEVTVE5FVDtcbiAgICAgIGNhc2UgXCJzdGFnZW5ldFwiOiByZXR1cm4gTW9uZXJvTmV0d29ya1R5cGUuU1RBR0VORVQ7XG4gICAgICBkZWZhdWx0OiB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJJbnZhbGlkIG5ldHdvcmsgdHlwZSB0byBwYXJzZTogJ1wiICsgbmV0d29ya1R5cGVTdHIgKyBcIidcIik7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgbmV0d29yayB0eXBlIGluIGh1bWFuLXJlYWRhYmxlIGZvcm0uXG4gICAqXG4gICAqIEByZXR1cm4ge3N0cmluZ30gdGhlIG5ldHdvcmsgdHlwZSBpbiBodW1hbi1yZWFkYWJsZSBmb3JtXG4gICAqL1xuICBzdGF0aWMgdG9TdHJpbmcobmV0d29ya1R5cGU6IE1vbmVyb05ldHdvcmtUeXBlIHwgbnVtYmVyKTogc3RyaW5nIHtcbiAgICBpZiAobmV0d29ya1R5cGUgPT09IDApIHJldHVybiBcIm1haW5uZXRcIjtcbiAgICBpZiAobmV0d29ya1R5cGUgPT09IDEpIHJldHVybiBcInRlc3RuZXRcIjtcbiAgICBpZiAobmV0d29ya1R5cGUgPT09IDIpIHJldHVybiBcInN0YWdlbmV0XCI7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiSW52YWxpZCBuZXR3b3JrIHR5cGU6IFwiICsgbmV0d29ya1R5cGUpO1xuICB9XG59Il0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsWUFBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBOztBQUVBO0FBQ0E7QUFDQTtBQUNlLE1BQU1DLGlCQUFpQixDQUFDOztFQUVyQztBQUNGO0FBQ0E7RUFDRSxPQUFnQkMsT0FBTyxHQUFHLENBQUM7O0VBRTNCO0FBQ0Y7QUFDQTtFQUNFLE9BQWdCQyxPQUFPLEdBQUcsQ0FBQzs7RUFFM0I7QUFDRjtBQUNBO0VBQ0UsT0FBZ0JDLFFBQVEsR0FBRyxDQUFDOztFQUU1QjtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDSSxPQUFPQyxJQUFJQSxDQUFDQyxXQUFnRCxFQUFxQjtJQUMvRSxJQUFJLE9BQU9BLFdBQVcsS0FBSyxRQUFRLEVBQUUsT0FBT0wsaUJBQWlCLENBQUNNLEtBQUssQ0FBQ0QsV0FBVyxDQUFDO0lBQ2hGTCxpQkFBaUIsQ0FBQ08sUUFBUSxDQUFDRixXQUFXLENBQUM7SUFDdkMsT0FBT0EsV0FBVztFQUNwQjs7RUFFRjtBQUNGO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsT0FBT0UsUUFBUUEsQ0FBQ0YsV0FBZ0QsRUFBRTtJQUNoRSxJQUFJLE9BQU9BLFdBQVcsS0FBSyxRQUFRLEVBQUVMLGlCQUFpQixDQUFDTSxLQUFLLENBQUNELFdBQVcsQ0FBQyxDQUFDO0lBQ3JFLElBQUlBLFdBQVcsS0FBSyxDQUFDLElBQUlBLFdBQVcsS0FBSyxDQUFDLElBQUlBLFdBQVcsS0FBSyxDQUFDLEVBQUUsTUFBTSxJQUFJRyxvQkFBVyxDQUFDLDJCQUEyQixHQUFHSCxXQUFXLENBQUM7RUFDeEk7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsT0FBT0ksT0FBT0EsQ0FBQ0osV0FBZ0QsRUFBVztJQUN4RSxJQUFJO01BQ0ZMLGlCQUFpQixDQUFDTyxRQUFRLENBQUNGLFdBQVcsQ0FBQztNQUN2QyxPQUFPLElBQUk7SUFDYixDQUFDLENBQUMsT0FBTUssR0FBRyxFQUFFO01BQ1gsT0FBTyxLQUFLO0lBQ2Q7RUFDRjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDRSxPQUFPSixLQUFLQSxDQUFDSyxjQUFzQixFQUFxQjtJQUN0RCxJQUFJQyxHQUFHLEdBQUcsQ0FBQyxFQUFFLEdBQUdELGNBQWMsRUFBRUUsV0FBVyxDQUFDLENBQUM7SUFDN0MsUUFBUUQsR0FBRztNQUNULEtBQUssU0FBUyxDQUFFLE9BQU9aLGlCQUFpQixDQUFDQyxPQUFPO01BQ2hELEtBQUssU0FBUyxDQUFFLE9BQU9ELGlCQUFpQixDQUFDRSxPQUFPO01BQ2hELEtBQUssVUFBVSxDQUFFLE9BQU9GLGlCQUFpQixDQUFDRyxRQUFRO01BQ2xELFFBQVMsTUFBTSxJQUFJSyxvQkFBVyxDQUFDLGtDQUFrQyxHQUFHRyxjQUFjLEdBQUcsR0FBRyxDQUFDO0lBQzNGO0VBQ0Y7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtFQUNFLE9BQU9HLFFBQVFBLENBQUNULFdBQXVDLEVBQVU7SUFDL0QsSUFBSUEsV0FBVyxLQUFLLENBQUMsRUFBRSxPQUFPLFNBQVM7SUFDdkMsSUFBSUEsV0FBVyxLQUFLLENBQUMsRUFBRSxPQUFPLFNBQVM7SUFDdkMsSUFBSUEsV0FBVyxLQUFLLENBQUMsRUFBRSxPQUFPLFVBQVU7SUFDeEMsTUFBTSxJQUFJRyxvQkFBVyxDQUFDLHdCQUF3QixHQUFHSCxXQUFXLENBQUM7RUFDL0Q7QUFDRixDQUFDVSxPQUFBLENBQUFDLE9BQUEsR0FBQWhCLGlCQUFBIn0= \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroOutput.d.ts b/dist/src/main/ts/daemon/model/MoneroOutput.d.ts new file mode 100644 index 000000000..e38d42568 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroOutput.d.ts @@ -0,0 +1,35 @@ +import MoneroKeyImage from "./MoneroKeyImage"; +import MoneroTx from "./MoneroTx"; +/** + * Models a Monero transaction output. + */ +export default class MoneroOutput { + tx: MoneroTx; + keyImage: Partial; + amount: bigint; + index: number; + ringOutputIndices: number[]; + stealthPublicKey: string; + /** + * Construct the model. + * + * @param {MoneroOutput} [output] is existing state to initialize from (optional) + */ + constructor(output?: Partial); + getTx(): MoneroTx; + setTx(tx: MoneroTx): MoneroOutput; + getKeyImage(): MoneroKeyImage; + setKeyImage(keyImage: MoneroKeyImage): MoneroOutput; + getAmount(): bigint; + setAmount(amount: bigint): MoneroOutput; + getIndex(): number; + setIndex(index: number): MoneroOutput; + getRingOutputIndices(): number[]; + setRingOutputIndices(ringOutputIndices: number[]): MoneroOutput; + getStealthPublicKey(): string; + setStealthPublicKey(stealthPublicKey: string): MoneroOutput; + copy(): MoneroOutput; + toJson(): any; + merge(output: MoneroOutput): MoneroOutput; + toString(indent?: number): string; +} diff --git a/dist/src/main/ts/daemon/model/MoneroOutput.js b/dist/src/main/ts/daemon/model/MoneroOutput.js new file mode 100644 index 000000000..342292642 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroOutput.js @@ -0,0 +1,129 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); + +var _MoneroKeyImage = _interopRequireDefault(require("./MoneroKeyImage")); + + +/** + * Models a Monero transaction output. + */ +class MoneroOutput { + + + + + + + + + /** + * Construct the model. + * + * @param {MoneroOutput} [output] is existing state to initialize from (optional) + */ + constructor(output) { + Object.assign(this, output); + + // deserialize fields if necessary + if (this.amount !== undefined && typeof this.amount !== "bigint") this.amount = BigInt(this.amount); + if (this.keyImage) this.keyImage = this.keyImage instanceof _MoneroKeyImage.default ? this.keyImage.copy() : new _MoneroKeyImage.default(this.keyImage); + } + + getTx() { + return this.tx; + } + + setTx(tx) { + this.tx = tx; + return this; + } + + getKeyImage() { + return this.keyImage; + } + + setKeyImage(keyImage) { + this.keyImage = keyImage === undefined ? undefined : keyImage instanceof _MoneroKeyImage.default ? keyImage : new _MoneroKeyImage.default(keyImage); + return this; + } + + getAmount() { + return this.amount; + } + + setAmount(amount) { + this.amount = amount; + return this; + } + + getIndex() { + return this.index; + } + + setIndex(index) { + this.index = index; + return this; + } + + getRingOutputIndices() { + return this.ringOutputIndices; + } + + setRingOutputIndices(ringOutputIndices) { + this.ringOutputIndices = ringOutputIndices; + return this; + } + + getStealthPublicKey() { + return this.stealthPublicKey; + } + + setStealthPublicKey(stealthPublicKey) { + this.stealthPublicKey = stealthPublicKey; + return this; + } + + copy() { + return new MoneroOutput(this); + } + + toJson() { + let json = Object.assign({}, this); + if (this.getAmount() !== undefined) json.amount = this.getAmount().toString(); + if (this.getKeyImage() !== undefined) json.keyImage = this.getKeyImage() ? this.getKeyImage().toJson() : undefined; + delete json.tx; + return json; + } + + merge(output) { + (0, _assert.default)(output instanceof MoneroOutput); + if (this === output) return this; + + // merge txs if they're different which comes back to merging outputs + if (this.getTx() !== output.getTx()) this.getTx().merge(output.getTx()); + + // otherwise merge output fields + else { + if (this.getKeyImage() === undefined) this.setKeyImage(output.getKeyImage());else + if (output.getKeyImage() !== undefined) this.getKeyImage().merge(output.getKeyImage()); + this.setAmount(_GenUtils.default.reconcile(this.getAmount(), output.getAmount())); + this.setIndex(_GenUtils.default.reconcile(this.getIndex(), output.getIndex())); + } + + return this; + } + + toString(indent = 0) { + let str = ""; + if (this.getKeyImage() !== undefined) { + str += _GenUtils.default.kvLine("Key image", "", indent); + str += this.getKeyImage().toString(indent + 1) + "\n"; + } + str += _GenUtils.default.kvLine("Amount", this.getAmount(), indent); + str += _GenUtils.default.kvLine("Index", this.getIndex(), indent); + str += _GenUtils.default.kvLine("Ring output indices", this.getRingOutputIndices(), indent); + str += _GenUtils.default.kvLine("Stealth public key", this.getStealthPublicKey(), indent); + return str === "" ? str : str.slice(0, str.length - 1); // strip last newline + } +}exports.default = MoneroOutput; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTW9uZXJvS2V5SW1hZ2UiLCJNb25lcm9PdXRwdXQiLCJjb25zdHJ1Y3RvciIsIm91dHB1dCIsIk9iamVjdCIsImFzc2lnbiIsImFtb3VudCIsInVuZGVmaW5lZCIsIkJpZ0ludCIsImtleUltYWdlIiwiTW9uZXJvS2V5SW1hZ2UiLCJjb3B5IiwiZ2V0VHgiLCJ0eCIsInNldFR4IiwiZ2V0S2V5SW1hZ2UiLCJzZXRLZXlJbWFnZSIsImdldEFtb3VudCIsInNldEFtb3VudCIsImdldEluZGV4IiwiaW5kZXgiLCJzZXRJbmRleCIsImdldFJpbmdPdXRwdXRJbmRpY2VzIiwicmluZ091dHB1dEluZGljZXMiLCJzZXRSaW5nT3V0cHV0SW5kaWNlcyIsImdldFN0ZWFsdGhQdWJsaWNLZXkiLCJzdGVhbHRoUHVibGljS2V5Iiwic2V0U3RlYWx0aFB1YmxpY0tleSIsInRvSnNvbiIsImpzb24iLCJ0b1N0cmluZyIsIm1lcmdlIiwiYXNzZXJ0IiwiR2VuVXRpbHMiLCJyZWNvbmNpbGUiLCJpbmRlbnQiLCJzdHIiLCJrdkxpbmUiLCJzbGljZSIsImxlbmd0aCIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvZGFlbW9uL21vZGVsL01vbmVyb091dHB1dC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi4vLi4vY29tbW9uL0dlblV0aWxzXCI7XG5pbXBvcnQgTW9uZXJvRXJyb3IgZnJvbSBcIi4uLy4uL2NvbW1vbi9Nb25lcm9FcnJvclwiO1xuaW1wb3J0IE1vbmVyb0tleUltYWdlIGZyb20gXCIuL01vbmVyb0tleUltYWdlXCI7XG5pbXBvcnQgTW9uZXJvVHggZnJvbSBcIi4vTW9uZXJvVHhcIjtcblxuLyoqXG4gKiBNb2RlbHMgYSBNb25lcm8gdHJhbnNhY3Rpb24gb3V0cHV0LlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9PdXRwdXQge1xuXG4gIHR4OiBNb25lcm9UeDtcbiAga2V5SW1hZ2U6IFBhcnRpYWw8TW9uZXJvS2V5SW1hZ2U+O1xuICBhbW91bnQ6IGJpZ2ludDtcbiAgaW5kZXg6IG51bWJlcjtcbiAgcmluZ091dHB1dEluZGljZXM6IG51bWJlcltdO1xuICBzdGVhbHRoUHVibGljS2V5OiBzdHJpbmc7XG4gIFxuICAvKipcbiAgICogQ29uc3RydWN0IHRoZSBtb2RlbC5cbiAgICogXG4gICAqIEBwYXJhbSB7TW9uZXJvT3V0cHV0fSBbb3V0cHV0XSBpcyBleGlzdGluZyBzdGF0ZSB0byBpbml0aWFsaXplIGZyb20gKG9wdGlvbmFsKVxuICAgKi9cbiAgY29uc3RydWN0b3Iob3V0cHV0PzogUGFydGlhbDxNb25lcm9PdXRwdXQ+KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCBvdXRwdXQpO1xuXG4gICAgLy8gZGVzZXJpYWxpemUgZmllbGRzIGlmIG5lY2Vzc2FyeVxuICAgIGlmICh0aGlzLmFtb3VudCAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLmFtb3VudCAhPT0gXCJiaWdpbnRcIikgdGhpcy5hbW91bnQgPSBCaWdJbnQodGhpcy5hbW91bnQpO1xuICAgIGlmICh0aGlzLmtleUltYWdlKSB0aGlzLmtleUltYWdlID0gdGhpcy5rZXlJbWFnZSBpbnN0YW5jZW9mIE1vbmVyb0tleUltYWdlID8gdGhpcy5rZXlJbWFnZS5jb3B5KCkgOiBuZXcgTW9uZXJvS2V5SW1hZ2UodGhpcy5rZXlJbWFnZSk7XG4gIH1cbiAgXG4gIGdldFR4KCk6IE1vbmVyb1R4IHtcbiAgICByZXR1cm4gdGhpcy50eDtcbiAgfVxuICBcbiAgc2V0VHgodHg6IE1vbmVyb1R4KTogTW9uZXJvT3V0cHV0IHtcbiAgICB0aGlzLnR4ID0gdHg7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEtleUltYWdlKCk6IE1vbmVyb0tleUltYWdlIHtcbiAgICByZXR1cm4gdGhpcy5rZXlJbWFnZSBhcyBNb25lcm9LZXlJbWFnZTtcbiAgfVxuXG4gIHNldEtleUltYWdlKGtleUltYWdlOiBNb25lcm9LZXlJbWFnZSk6IE1vbmVyb091dHB1dCB7XG4gICAgdGhpcy5rZXlJbWFnZSA9IGtleUltYWdlID09PSB1bmRlZmluZWQgPyB1bmRlZmluZWQgOiBrZXlJbWFnZSBpbnN0YW5jZW9mIE1vbmVyb0tleUltYWdlID8ga2V5SW1hZ2UgOiBuZXcgTW9uZXJvS2V5SW1hZ2Uoa2V5SW1hZ2UpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRBbW91bnQoKTogYmlnaW50IHtcbiAgICByZXR1cm4gdGhpcy5hbW91bnQ7XG4gIH1cblxuICBzZXRBbW91bnQoYW1vdW50OiBiaWdpbnQpOiBNb25lcm9PdXRwdXQge1xuICAgIHRoaXMuYW1vdW50ID0gYW1vdW50O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRJbmRleCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmluZGV4O1xuICB9XG4gIFxuICBzZXRJbmRleChpbmRleDogbnVtYmVyKTogTW9uZXJvT3V0cHV0IHtcbiAgICB0aGlzLmluZGV4ID0gaW5kZXg7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFJpbmdPdXRwdXRJbmRpY2VzKCk6IG51bWJlcltdIHtcbiAgICByZXR1cm4gdGhpcy5yaW5nT3V0cHV0SW5kaWNlcztcbiAgfVxuICBcbiAgc2V0UmluZ091dHB1dEluZGljZXMocmluZ091dHB1dEluZGljZXM6IG51bWJlcltdKTogTW9uZXJvT3V0cHV0IHtcbiAgICB0aGlzLnJpbmdPdXRwdXRJbmRpY2VzID0gcmluZ091dHB1dEluZGljZXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFN0ZWFsdGhQdWJsaWNLZXkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5zdGVhbHRoUHVibGljS2V5O1xuICB9XG4gIFxuICBzZXRTdGVhbHRoUHVibGljS2V5KHN0ZWFsdGhQdWJsaWNLZXk6IHN0cmluZyk6IE1vbmVyb091dHB1dCB7XG4gICAgdGhpcy5zdGVhbHRoUHVibGljS2V5ID0gc3RlYWx0aFB1YmxpY0tleTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgY29weSgpOiBNb25lcm9PdXRwdXQge1xuICAgIHJldHVybiBuZXcgTW9uZXJvT3V0cHV0KHRoaXMpO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICBsZXQganNvbjogYW55ID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcyk7XG4gICAgaWYgKHRoaXMuZ2V0QW1vdW50KCkgIT09IHVuZGVmaW5lZCkganNvbi5hbW91bnQgPSB0aGlzLmdldEFtb3VudCgpLnRvU3RyaW5nKCk7XG4gICAgaWYgKHRoaXMuZ2V0S2V5SW1hZ2UoKSAhPT0gdW5kZWZpbmVkKSBqc29uLmtleUltYWdlID0gdGhpcy5nZXRLZXlJbWFnZSgpID8gdGhpcy5nZXRLZXlJbWFnZSgpLnRvSnNvbigpIDogdW5kZWZpbmVkO1xuICAgIGRlbGV0ZSBqc29uLnR4O1xuICAgIHJldHVybiBqc29uO1xuICB9XG4gIFxuICBtZXJnZShvdXRwdXQ6IE1vbmVyb091dHB1dCk6IE1vbmVyb091dHB1dCB7XG4gICAgYXNzZXJ0KG91dHB1dCBpbnN0YW5jZW9mIE1vbmVyb091dHB1dCk7XG4gICAgaWYgKHRoaXMgPT09IG91dHB1dCkgcmV0dXJuIHRoaXM7XG4gICAgXG4gICAgLy8gbWVyZ2UgdHhzIGlmIHRoZXkncmUgZGlmZmVyZW50IHdoaWNoIGNvbWVzIGJhY2sgdG8gbWVyZ2luZyBvdXRwdXRzXG4gICAgaWYgKHRoaXMuZ2V0VHgoKSAhPT0gb3V0cHV0LmdldFR4KCkpIHRoaXMuZ2V0VHgoKS5tZXJnZShvdXRwdXQuZ2V0VHgoKSk7XG4gICAgXG4gICAgLy8gb3RoZXJ3aXNlIG1lcmdlIG91dHB1dCBmaWVsZHNcbiAgICBlbHNlIHtcbiAgICAgIGlmICh0aGlzLmdldEtleUltYWdlKCkgPT09IHVuZGVmaW5lZCkgdGhpcy5zZXRLZXlJbWFnZShvdXRwdXQuZ2V0S2V5SW1hZ2UoKSk7XG4gICAgICBlbHNlIGlmIChvdXRwdXQuZ2V0S2V5SW1hZ2UoKSAhPT0gdW5kZWZpbmVkKSB0aGlzLmdldEtleUltYWdlKCkubWVyZ2Uob3V0cHV0LmdldEtleUltYWdlKCkpO1xuICAgICAgdGhpcy5zZXRBbW91bnQoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0QW1vdW50KCksIG91dHB1dC5nZXRBbW91bnQoKSkpO1xuICAgICAgdGhpcy5zZXRJbmRleChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRJbmRleCgpLCBvdXRwdXQuZ2V0SW5kZXgoKSkpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICB0b1N0cmluZyhpbmRlbnQgPSAwKTogc3RyaW5nIHtcbiAgICBsZXQgc3RyID0gXCJcIjtcbiAgICBpZiAodGhpcy5nZXRLZXlJbWFnZSgpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJLZXkgaW1hZ2VcIiwgXCJcIiwgaW5kZW50KTtcbiAgICAgIHN0ciArPSB0aGlzLmdldEtleUltYWdlKCkudG9TdHJpbmcoaW5kZW50ICsgMSkgKyBcIlxcblwiO1xuICAgIH1cbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiQW1vdW50XCIsIHRoaXMuZ2V0QW1vdW50KCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIkluZGV4XCIsIHRoaXMuZ2V0SW5kZXgoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiUmluZyBvdXRwdXQgaW5kaWNlc1wiLCB0aGlzLmdldFJpbmdPdXRwdXRJbmRpY2VzKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlN0ZWFsdGggcHVibGljIGtleVwiLCB0aGlzLmdldFN0ZWFsdGhQdWJsaWNLZXkoKSwgaW5kZW50KTtcbiAgICByZXR1cm4gc3RyID09PSBcIlwiID8gc3RyIDogc3RyLnNsaWNlKDAsIHN0ci5sZW5ndGggLSAxKTsgIC8vIHN0cmlwIGxhc3QgbmV3bGluZVxuICB9XG59Il0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsT0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsU0FBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBOztBQUVBLElBQUFFLGVBQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ2UsTUFBTUcsWUFBWSxDQUFDOzs7Ozs7Ozs7RUFTaEM7QUFDRjtBQUNBO0FBQ0E7QUFDQTtFQUNFQyxXQUFXQSxDQUFDQyxNQUE4QixFQUFFO0lBQzFDQyxNQUFNLENBQUNDLE1BQU0sQ0FBQyxJQUFJLEVBQUVGLE1BQU0sQ0FBQzs7SUFFM0I7SUFDQSxJQUFJLElBQUksQ0FBQ0csTUFBTSxLQUFLQyxTQUFTLElBQUksT0FBTyxJQUFJLENBQUNELE1BQU0sS0FBSyxRQUFRLEVBQUUsSUFBSSxDQUFDQSxNQUFNLEdBQUdFLE1BQU0sQ0FBQyxJQUFJLENBQUNGLE1BQU0sQ0FBQztJQUNuRyxJQUFJLElBQUksQ0FBQ0csUUFBUSxFQUFFLElBQUksQ0FBQ0EsUUFBUSxHQUFHLElBQUksQ0FBQ0EsUUFBUSxZQUFZQyx1QkFBYyxHQUFHLElBQUksQ0FBQ0QsUUFBUSxDQUFDRSxJQUFJLENBQUMsQ0FBQyxHQUFHLElBQUlELHVCQUFjLENBQUMsSUFBSSxDQUFDRCxRQUFRLENBQUM7RUFDdkk7O0VBRUFHLEtBQUtBLENBQUEsRUFBYTtJQUNoQixPQUFPLElBQUksQ0FBQ0MsRUFBRTtFQUNoQjs7RUFFQUMsS0FBS0EsQ0FBQ0QsRUFBWSxFQUFnQjtJQUNoQyxJQUFJLENBQUNBLEVBQUUsR0FBR0EsRUFBRTtJQUNaLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxXQUFXQSxDQUFBLEVBQW1CO0lBQzVCLE9BQU8sSUFBSSxDQUFDTixRQUFRO0VBQ3RCOztF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 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroOutputHistogramEntry.d.ts b/dist/src/main/ts/daemon/model/MoneroOutputHistogramEntry.d.ts new file mode 100644 index 000000000..0ba527cbe --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroOutputHistogramEntry.d.ts @@ -0,0 +1,19 @@ +/** + * Entry in a Monero output histogram (see get_output_histogram of Daemon RPC documentation). + */ +export default class MoneroOutputHistogramEntry { + amount: bigint; + numInstances: number; + numUnlockedInstances: number; + numRecentInstances: number; + constructor(entry?: MoneroOutputHistogramEntry); + toJson(): any; + getAmount(): bigint; + setAmount(amount: bigint): MoneroOutputHistogramEntry; + getNumInstances(): number; + setNumInstances(numInstances: number): MoneroOutputHistogramEntry; + getNumUnlockedInstances(): number; + setNumUnlockedInstances(numUnlockedInstances: number): this; + getNumRecentInstances(): number; + setNumRecentInstances(numRecentInstances: number): MoneroOutputHistogramEntry; +} diff --git a/dist/src/main/ts/daemon/model/MoneroOutputHistogramEntry.js b/dist/src/main/ts/daemon/model/MoneroOutputHistogramEntry.js new file mode 100644 index 000000000..268902855 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroOutputHistogramEntry.js @@ -0,0 +1,58 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Entry in a Monero output histogram (see get_output_histogram of Daemon RPC documentation). + */ +class MoneroOutputHistogramEntry { + + + + + + + constructor(entry) { + Object.assign(this, entry); + if (this.amount !== undefined && typeof this.amount !== "bigint") this.amount = BigInt(this.amount); + } + + toJson() { + let json = Object.assign({}, this); + if (json.amount !== undefined) json.amount = json.amount.toString(); + return json; + } + + getAmount() { + return this.amount; + } + + setAmount(amount) { + this.amount = amount; + return this; + } + + getNumInstances() { + return this.numInstances; + } + + setNumInstances(numInstances) { + this.numInstances = numInstances; + return this; + } + + getNumUnlockedInstances() { + return this.numUnlockedInstances; + } + + setNumUnlockedInstances(numUnlockedInstances) { + this.numUnlockedInstances = numUnlockedInstances; + return this; + } + + getNumRecentInstances() { + return this.numRecentInstances; + } + + setNumRecentInstances(numRecentInstances) { + this.numRecentInstances = numRecentInstances; + return this; + } +}exports.default = MoneroOutputHistogramEntry; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9PdXRwdXRIaXN0b2dyYW1FbnRyeSIsImNvbnN0cnVjdG9yIiwiZW50cnkiLCJPYmplY3QiLCJhc3NpZ24iLCJhbW91bnQiLCJ1bmRlZmluZWQiLCJCaWdJbnQiLCJ0b0pzb24iLCJqc29uIiwidG9TdHJpbmciLCJnZXRBbW91bnQiLCJzZXRBbW91bnQiLCJnZXROdW1JbnN0YW5jZXMiLCJudW1JbnN0YW5jZXMiLCJzZXROdW1JbnN0YW5jZXMiLCJnZXROdW1VbmxvY2tlZEluc3RhbmNlcyIsIm51bVVubG9ja2VkSW5zdGFuY2VzIiwic2V0TnVtVW5sb2NrZWRJbnN0YW5jZXMiLCJnZXROdW1SZWNlbnRJbnN0YW5jZXMiLCJudW1SZWNlbnRJbnN0YW5jZXMiLCJzZXROdW1SZWNlbnRJbnN0YW5jZXMiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2RhZW1vbi9tb2RlbC9Nb25lcm9PdXRwdXRIaXN0b2dyYW1FbnRyeS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEVudHJ5IGluIGEgTW9uZXJvIG91dHB1dCBoaXN0b2dyYW0gKHNlZSBnZXRfb3V0cHV0X2hpc3RvZ3JhbSBvZiBEYWVtb24gUlBDIGRvY3VtZW50YXRpb24pLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9PdXRwdXRIaXN0b2dyYW1FbnRyeSB7XG5cbiAgYW1vdW50OiBiaWdpbnQ7XG4gIG51bUluc3RhbmNlczogbnVtYmVyO1xuICBudW1VbmxvY2tlZEluc3RhbmNlczogbnVtYmVyO1xuICBudW1SZWNlbnRJbnN0YW5jZXM6IG51bWJlcjtcbiAgXG4gIGNvbnN0cnVjdG9yKGVudHJ5PzogTW9uZXJvT3V0cHV0SGlzdG9ncmFtRW50cnkpIHtcbiAgICBPYmplY3QuYXNzaWduKHRoaXMsIGVudHJ5KTtcbiAgICBpZiAodGhpcy5hbW91bnQgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5hbW91bnQgIT09IFwiYmlnaW50XCIpIHRoaXMuYW1vdW50ID0gQmlnSW50KHRoaXMuYW1vdW50KTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgbGV0IGpzb246IGFueSA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICAgIGlmIChqc29uLmFtb3VudCAhPT0gdW5kZWZpbmVkKSBqc29uLmFtb3VudCA9IGpzb24uYW1vdW50LnRvU3RyaW5nKCk7XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIGdldEFtb3VudCgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLmFtb3VudDtcbiAgfVxuICBcbiAgc2V0QW1vdW50KGFtb3VudDogYmlnaW50KTogTW9uZXJvT3V0cHV0SGlzdG9ncmFtRW50cnkge1xuICAgIHRoaXMuYW1vdW50ID0gYW1vdW50O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0TnVtSW5zdGFuY2VzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtSW5zdGFuY2VzO1xuICB9XG5cbiAgc2V0TnVtSW5zdGFuY2VzKG51bUluc3RhbmNlczogbnVtYmVyKTogTW9uZXJvT3V0cHV0SGlzdG9ncmFtRW50cnkge1xuICAgIHRoaXMubnVtSW5zdGFuY2VzID0gbnVtSW5zdGFuY2VzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0TnVtVW5sb2NrZWRJbnN0YW5jZXMoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5udW1VbmxvY2tlZEluc3RhbmNlcztcbiAgfVxuXG4gIHNldE51bVVubG9ja2VkSW5zdGFuY2VzKG51bVVubG9ja2VkSW5zdGFuY2VzOiBudW1iZXIpIHtcbiAgICB0aGlzLm51bVVubG9ja2VkSW5zdGFuY2VzID0gbnVtVW5sb2NrZWRJbnN0YW5jZXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXROdW1SZWNlbnRJbnN0YW5jZXMoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5udW1SZWNlbnRJbnN0YW5jZXM7XG4gIH1cblxuICBzZXROdW1SZWNlbnRJbnN0YW5jZXMobnVtUmVjZW50SW5zdGFuY2VzOiBudW1iZXIpOiBNb25lcm9PdXRwdXRIaXN0b2dyYW1FbnRyeSB7XG4gICAgdGhpcy5udW1SZWNlbnRJbnN0YW5jZXMgPSBudW1SZWNlbnRJbnN0YW5jZXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InFHQUFBO0FBQ0E7QUFDQTtBQUNlLE1BQU1BLDBCQUEwQixDQUFDOzs7Ozs7O0VBTzlDQyxXQUFXQSxDQUFDQyxLQUFrQyxFQUFFO0lBQzlDQyxNQUFNLENBQUNDLE1BQU0sQ0FBQyxJQUFJLEVBQUVGLEtBQUssQ0FBQztJQUMxQixJQUFJLElBQUksQ0FBQ0csTUFBTSxLQUFLQyxTQUFTLElBQUksT0FBTyxJQUFJLENBQUNELE1BQU0sS0FBSyxRQUFRLEVBQUUsSUFBSSxDQUFDQSxNQUFNLEdBQUdFLE1BQU0sQ0FBQyxJQUFJLENBQUNGLE1BQU0sQ0FBQztFQUNyRzs7RUFFQUcsTUFBTUEsQ0FBQSxFQUFRO0lBQ1osSUFBSUMsSUFBUyxHQUFHTixNQUFNLENBQUNDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUM7SUFDdkMsSUFBSUssSUFBSSxDQUFDSixNQUFNLEtBQUtDLFNBQVMsRUFBRUcsSUFBSSxDQUFDSixNQUFNLEdBQUdJLElBQUksQ0FBQ0osTUFBTSxDQUFDSyxRQUFRLENBQUMsQ0FBQztJQUNuRSxPQUFPRCxJQUFJO0VBQ2I7O0VBRUFFLFNBQVNBLENBQUEsRUFBVztJQUNsQixPQUFPLElBQUksQ0FBQ04sTUFBTTtFQUNwQjs7RUFFQU8sU0FBU0EsQ0FBQ1AsTUFBYyxFQUE4QjtJQUNwRCxJQUFJLENBQUNBLE1BQU0sR0FBR0EsTUFBTTtJQUNwQixPQUFPLElBQUk7RUFDYjs7RUFFQVEsZUFBZUEsQ0FBQSxFQUFXO0lBQ3hCLE9BQU8sSUFBSSxDQUFDQyxZQUFZO0VBQzFCOztFQUVBQyxlQUFlQSxDQUFDRCxZQUFvQixFQUE4QjtJQUNoRSxJQUFJLENBQUNBLFlBQVksR0FBR0EsWUFBWTtJQUNoQyxPQUFPLElBQUk7RUFDYjs7RUFFQUUsdUJBQXVCQSxDQUFBLEVBQVc7SUFDaEMsT0FBTyxJQUFJLENBQUNDLG9CQUFvQjtFQUNsQzs7RUFFQUMsdUJBQXVCQSxDQUFDRCxvQkFBNEIsRUFBRTtJQUNwRCxJQUFJLENBQUNBLG9CQUFvQixHQUFHQSxvQkFBb0I7SUFDaEQsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLHFCQUFxQkEsQ0FBQSxFQUFXO0lBQzlCLE9BQU8sSUFBSSxDQUFDQyxrQkFBa0I7RUFDaEM7O0VBRUFDLHFCQUFxQkEsQ0FBQ0Qsa0JBQTBCLEVBQThCO0lBQzVFLElBQUksQ0FBQ0Esa0JBQWtCLEdBQUdBLGtCQUFrQjtJQUM1QyxPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNFLE9BQUEsQ0FBQUMsT0FBQSxHQUFBdkIsMEJBQUEifQ== \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroPeer.d.ts b/dist/src/main/ts/daemon/model/MoneroPeer.d.ts new file mode 100644 index 000000000..254404601 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroPeer.d.ts @@ -0,0 +1,89 @@ +import ConnectionType from "./ConnectionType"; +/** + * Models a peer to the daemon. + */ +export default class MoneroPeer { + id: string; + address: string; + host: string; + port: number; + isOnline: boolean; + lastSeenTimestamp: number; + pruningSeed: number; + rpcPort: number; + rpcCreditsPerHash: bigint; + avgDownload: number; + avgUpload: number; + currentDownload: number; + currentUpload: number; + height: number; + isIncoming: boolean; + liveTime: number; + isLocalIp: boolean; + isLocalHost: boolean; + numReceives: number; + numSends: number; + receiveIdleTime: number; + sendIdleTime: number; + state: string; + numSupportFlags: number; + type: ConnectionType; + constructor(peer?: MoneroPeer); + toJson(): any; + getId(): string; + setId(id: string): MoneroPeer; + getAddress(): string; + setAddress(address: string): MoneroPeer; + getHost(): string; + setHost(host: string): MoneroPeer; + getPort(): number; + setPort(port: number): MoneroPeer; + /** + * Indicates if the peer was online when last checked (aka "white listed" as + * opposed to "gray listed"). + * + * @return {boolean} true if peer was online when last checked, false otherwise + */ + getIsOnline(): boolean; + setIsOnline(isOnline: boolean): MoneroPeer; + getLastSeenTimestamp(): number; + setLastSeenTimestamp(lastSeenTimestamp: number): MoneroPeer; + getPruningSeed(): number; + setPruningSeed(pruningSeed: number): MoneroPeer; + getRpcPort(): number; + setRpcPort(rpcPort: number): MoneroPeer; + getRpcCreditsPerHash(): bigint; + setRpcCreditsPerHash(rpcCreditsPerHash: bigint): MoneroPeer; + getAvgDownload(): number; + setAvgDownload(avgDownload: number): MoneroPeer; + getAvgUpload(): number; + setAvgUpload(avgUpload: number): MoneroPeer; + getCurrentDownload(): number; + setCurrentDownload(currentDownload: number): MoneroPeer; + getCurrentUpload(): number; + setCurrentUpload(currentUpload: number): MoneroPeer; + getHeight(): number; + setHeight(height: number): MoneroPeer; + getIsIncoming(): boolean; + setIsIncoming(isIncoming: boolean): MoneroPeer; + getLiveTime(): number; + setLiveTime(liveTime: number): this; + getIsLocalIp(): boolean; + setIsLocalIp(isLocalIp: boolean): MoneroPeer; + getIsLocalHost(): boolean; + setIsLocalHost(isLocalHost: boolean): MoneroPeer; + getNumReceives(): number; + setNumReceives(numReceives: number): MoneroPeer; + getNumSends(): number; + setNumSends(numSends: number): MoneroPeer; + getReceiveIdleTime(): number; + setReceiveIdleTime(receiveIdleTime: number): MoneroPeer; + getSendIdleTime(): number; + setSendIdleTime(sendIdleTime: number): MoneroPeer; + getState(): string; + setState(state: string): MoneroPeer; + getNumSupportFlags(): number; + setNumSupportFlags(numSupportFlags: number): MoneroPeer; + getType(): ConnectionType; + setType(type: ConnectionType): MoneroPeer; +} diff --git a/dist/src/main/ts/daemon/model/MoneroPeer.js b/dist/src/main/ts/daemon/model/MoneroPeer.js new file mode 100644 index 000000000..b4ee74b2f --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroPeer.js @@ -0,0 +1,276 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; + +/** + * Models a peer to the daemon. + */ +class MoneroPeer { + + + + + + + + + + + + + + + + + + + + + + + + + + + + constructor(peer) { + Object.assign(this, peer); + if (this.rpcCreditsPerHash !== undefined && typeof this.rpcCreditsPerHash !== "bigint") this.rpcCreditsPerHash = BigInt(this.rpcCreditsPerHash); + } + + toJson() { + let json = Object.assign({}, this); + if (json.rpcCreditsPerHash !== undefined) json.rpcCreditsPerHash = json.rpcCreditsPerHash.toString(); + return json; + } + + getId() { + return this.id; + } + + setId(id) { + this.id = id; + return this; + } + + getAddress() { + return this.address; + } + + setAddress(address) { + this.address = address; + return this; + } + + getHost() { + return this.host; + } + + setHost(host) { + this.host = host; + return this; + } + + getPort() { + return this.port; + } + + setPort(port) { + this.port = port; + return this; + } + + /** + * Indicates if the peer was online when last checked (aka "white listed" as + * opposed to "gray listed"). + * + * @return {boolean} true if peer was online when last checked, false otherwise + */ + getIsOnline() { + return this.isOnline; + } + + setIsOnline(isOnline) { + this.isOnline = isOnline; + return this; + } + + getLastSeenTimestamp() { + return this.lastSeenTimestamp; + } + + setLastSeenTimestamp(lastSeenTimestamp) { + this.lastSeenTimestamp = lastSeenTimestamp; + return this; + } + + getPruningSeed() { + return this.pruningSeed; + } + + setPruningSeed(pruningSeed) { + this.pruningSeed = pruningSeed; + return this; + } + + getRpcPort() { + return this.rpcPort; + } + + setRpcPort(rpcPort) { + this.rpcPort = rpcPort; + return this; + } + + getRpcCreditsPerHash() { + return this.rpcCreditsPerHash; + } + + setRpcCreditsPerHash(rpcCreditsPerHash) { + this.rpcCreditsPerHash = rpcCreditsPerHash; + return this; + } + + getAvgDownload() { + return this.avgDownload; + } + + setAvgDownload(avgDownload) { + this.avgDownload = avgDownload; + return this; + } + + getAvgUpload() { + return this.avgUpload; + } + + setAvgUpload(avgUpload) { + this.avgUpload = avgUpload; + return this; + } + + getCurrentDownload() { + return this.currentDownload; + } + + setCurrentDownload(currentDownload) { + this.currentDownload = currentDownload; + return this; + } + + getCurrentUpload() { + return this.currentUpload; + } + + setCurrentUpload(currentUpload) { + this.currentUpload = currentUpload; + return this; + } + + getHeight() { + return this.height; + } + + setHeight(height) { + this.height = height; + return this; + } + + getIsIncoming() { + return this.isIncoming; + } + + setIsIncoming(isIncoming) { + this.isIncoming = isIncoming; + return this; + } + + getLiveTime() { + return this.liveTime; + } + + setLiveTime(liveTime) { + this.liveTime = liveTime; + return this; + } + + getIsLocalIp() { + return this.isLocalIp; + } + + setIsLocalIp(isLocalIp) { + this.isLocalIp = isLocalIp; + return this; + } + + getIsLocalHost() { + return this.isLocalHost; + } + + setIsLocalHost(isLocalHost) { + this.isLocalHost = isLocalHost; + return this; + } + + getNumReceives() { + return this.numReceives; + } + + setNumReceives(numReceives) { + this.numReceives = numReceives; + return this; + } + + getNumSends() { + return this.numSends; + } + + setNumSends(numSends) { + this.numSends = numSends; + return this; + } + + getReceiveIdleTime() { + return this.receiveIdleTime; + } + + setReceiveIdleTime(receiveIdleTime) { + this.receiveIdleTime = receiveIdleTime; + return this; + } + + getSendIdleTime() { + return this.sendIdleTime; + } + + setSendIdleTime(sendIdleTime) { + this.sendIdleTime = sendIdleTime; + return this; + } + + getState() { + return this.state; + } + + setState(state) { + this.state = state; + return this; + } + + getNumSupportFlags() { + return this.numSupportFlags; + } + + setNumSupportFlags(numSupportFlags) { + this.numSupportFlags = numSupportFlags; + return this; + } + + getType() { + return this.type; + } + + setType(type) { + this.type = type; + return this; + } +}exports.default = MoneroPeer; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9QZWVyIiwiY29uc3RydWN0b3IiLCJwZWVyIiwiT2JqZWN0IiwiYXNzaWduIiwicnBjQ3JlZGl0c1Blckhhc2giLCJ1bmRlZmluZWQiLCJCaWdJbnQiLCJ0b0pzb24iLCJqc29uIiwidG9TdHJpbmciLCJnZXRJZCIsImlkIiwic2V0SWQiLCJnZXRBZGRyZXNzIiwiYWRkcmVzcyIsInNldEFkZHJlc3MiLCJnZXRIb3N0IiwiaG9zdCIsInNldEhvc3QiLCJnZXRQb3J0IiwicG9ydCIsInNldFBvcnQiLCJnZXRJc09ubGluZSIsImlzT25saW5lIiwic2V0SXNPbmxpbmUiLCJnZXRMYXN0U2VlblRpbWVzdGFtcCIsImxhc3RTZWVuVGltZXN0YW1wIiwic2V0TGFzdFNlZW5UaW1lc3RhbXAiLCJnZXRQcnVuaW5nU2VlZCIsInBydW5pbmdTZWVkIiwic2V0UHJ1bmluZ1NlZWQiLCJnZXRScGNQb3J0IiwicnBjUG9ydCIsInNldFJwY1BvcnQiLCJnZXRScGNDcmVkaXRzUGVySGFzaCIsInNldFJwY0NyZWRpdHNQZXJIYXNoIiwiZ2V0QXZnRG93bmxvYWQiLCJhdmdEb3dubG9hZCIsInNldEF2Z0Rvd25sb2FkIiwiZ2V0QXZnVXBsb2FkIiwiYXZnVXBsb2FkIiwic2V0QXZnVXBsb2FkIiwiZ2V0Q3VycmVudERvd25sb2FkIiwiY3VycmVudERvd25sb2FkIiwic2V0Q3VycmVudERvd25sb2FkIiwiZ2V0Q3VycmVudFVwbG9hZCIsImN1cnJlbnRVcGxvYWQiLCJzZXRDdXJyZW50VXBsb2FkIiwiZ2V0SGVpZ2h0IiwiaGVpZ2h0Iiwic2V0SGVpZ2h0IiwiZ2V0SXNJbmNvbWluZyIsImlzSW5jb21pbmciLCJzZXRJc0luY29taW5nIiwiZ2V0TGl2ZVRpbWUiLCJsaXZlVGltZSIsInNldExpdmVUaW1lIiwiZ2V0SXNMb2NhbElwIiwiaXNMb2NhbElwIiwic2V0SXNMb2NhbElwIiwiZ2V0SXNMb2NhbEhvc3QiLCJpc0xvY2FsSG9zdCIsInNldElzTG9jYWxIb3N0IiwiZ2V0TnVtUmVjZWl2ZXMiLCJudW1SZWNlaXZlcyIsInNldE51bVJlY2VpdmVzIiwiZ2V0TnVtU2VuZHMiLCJudW1TZW5kcyIsInNldE51bVNlbmRzIiwiZ2V0UmVjZWl2ZUlkbGVUaW1lIiwicmVjZWl2ZUlkbGVUaW1lIiwic2V0UmVjZWl2ZUlkbGVUaW1lIiwiZ2V0U2VuZElkbGVUaW1lIiwic2VuZElkbGVUaW1lIiwic2V0U2VuZElkbGVUaW1lIiwiZ2V0U3RhdGUiLCJzdGF0ZSIsInNldFN0YXRlIiwiZ2V0TnVtU3VwcG9ydEZsYWdzIiwibnVtU3VwcG9ydEZsYWdzIiwic2V0TnVtU3VwcG9ydEZsYWdzIiwiZ2V0VHlwZSIsInR5cGUiLCJzZXRUeXBlIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9kYWVtb24vbW9kZWwvTW9uZXJvUGVlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQ29ubmVjdGlvblR5cGUgZnJvbSBcIi4vQ29ubmVjdGlvblR5cGVcIjtcblxuLyoqXG4gKiBNb2RlbHMgYSBwZWVyIHRvIHRoZSBkYWVtb24uXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb1BlZXIge1xuXG4gIGlkOiBzdHJpbmc7XG4gIGFkZHJlc3M6IHN0cmluZztcbiAgaG9zdDogc3RyaW5nO1xuICBwb3J0OiBudW1iZXI7XG4gIGlzT25saW5lOiBib29sZWFuO1xuICBsYXN0U2VlblRpbWVzdGFtcDogbnVtYmVyO1xuICBwcnVuaW5nU2VlZDogbnVtYmVyO1xuICBycGNQb3J0OiBudW1iZXI7XG4gIHJwY0NyZWRpdHNQZXJIYXNoOiBiaWdpbnQ7XG4gIGF2Z0Rvd25sb2FkOiBudW1iZXI7XG4gIGF2Z1VwbG9hZDogbnVtYmVyO1xuICBjdXJyZW50RG93bmxvYWQ6IG51bWJlcjtcbiAgY3VycmVudFVwbG9hZDogbnVtYmVyO1xuICBoZWlnaHQ6IG51bWJlcjtcbiAgaXNJbmNvbWluZzogYm9vbGVhbjtcbiAgbGl2ZVRpbWU6IG51bWJlcjtcbiAgaXNMb2NhbElwOiBib29sZWFuO1xuICBpc0xvY2FsSG9zdDogYm9vbGVhbjtcbiAgbnVtUmVjZWl2ZXM6IG51bWJlcjtcbiAgbnVtU2VuZHM6IG51bWJlcjtcbiAgcmVjZWl2ZUlkbGVUaW1lOiBudW1iZXI7XG4gIHNlbmRJZGxlVGltZTogbnVtYmVyO1xuICBzdGF0ZTogc3RyaW5nO1xuICBudW1TdXBwb3J0RmxhZ3M6IG51bWJlcjtcbiAgdHlwZTogQ29ubmVjdGlvblR5cGU7XG4gIFxuICBjb25zdHJ1Y3RvcihwZWVyPzogTW9uZXJvUGVlcikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgcGVlcik7XG4gICAgaWYgKHRoaXMucnBjQ3JlZGl0c1Blckhhc2ggIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5ycGNDcmVkaXRzUGVySGFzaCAhPT0gXCJiaWdpbnRcIikgdGhpcy5ycGNDcmVkaXRzUGVySGFzaCA9IEJpZ0ludCh0aGlzLnJwY0NyZWRpdHNQZXJIYXNoKTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgbGV0IGpzb246IGFueSA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICAgIGlmIChqc29uLnJwY0NyZWRpdHNQZXJIYXNoICE9PSB1bmRlZmluZWQpIGpzb24ucnBjQ3JlZGl0c1Blckhhc2ggPSBqc29uLnJwY0NyZWRpdHNQZXJIYXNoLnRvU3RyaW5nKCk7XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIGdldElkKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuaWQ7XG4gIH1cblxuICBzZXRJZChpZDogc3RyaW5nKTogTW9uZXJvUGVlciB7XG4gICAgdGhpcy5pZCA9IGlkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0QWRkcmVzcygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmFkZHJlc3M7XG4gIH1cblxuICBzZXRBZGRyZXNzKGFkZHJlc3M6IHN0cmluZyk6IE1vbmVyb1BlZXIge1xuICAgIHRoaXMuYWRkcmVzcyA9IGFkZHJlc3M7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRIb3N0KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuaG9zdDtcbiAgfVxuXG4gIHNldEhvc3QoaG9zdDogc3RyaW5nKTogTW9uZXJvUGVlciB7XG4gICAgdGhpcy5ob3N0ID0gaG9zdDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldFBvcnQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5wb3J0O1xuICB9XG5cbiAgc2V0UG9ydChwb3J0OiBudW1iZXIpOiBNb25lcm9QZWVyIHtcbiAgICB0aGlzLnBvcnQgPSBwb3J0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogSW5kaWNhdGVzIGlmIHRoZSBwZWVyIHdhcyBvbmxpbmUgd2hlbiBsYXN0IGNoZWNrZWQgKGFrYSBcIndoaXRlIGxpc3RlZFwiIGFzXG4gICAqIG9wcG9zZWQgdG8gXCJncmF5IGxpc3RlZFwiKS5cbiAgICogXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgcGVlciB3YXMgb25saW5lIHdoZW4gbGFzdCBjaGVja2VkLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIGdldElzT25saW5lKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzT25saW5lO1xuICB9XG4gIFxuICBzZXRJc09ubGluZShpc09ubGluZTogYm9vbGVhbik6IE1vbmVyb1BlZXIge1xuICAgIHRoaXMuaXNPbmxpbmUgPSBpc09ubGluZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0TGFzdFNlZW5UaW1lc3RhbXAoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5sYXN0U2VlblRpbWVzdGFtcDtcbiAgfVxuICBcbiAgc2V0TGFzdFNlZW5UaW1lc3RhbXAobGFzdFNlZW5UaW1lc3RhbXA6IG51bWJlcik6IE1vbmVyb1BlZXIge1xuICAgIHRoaXMubGFzdFNlZW5UaW1lc3RhbXAgPSBsYXN0U2VlblRpbWVzdGFtcDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0UHJ1bmluZ1NlZWQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5wcnVuaW5nU2VlZDtcbiAgfVxuICBcbiAgc2V0UHJ1bmluZ1NlZWQocHJ1bmluZ1NlZWQ6IG51bWJlcik6IE1vbmVyb1BlZXIge1xuICAgIHRoaXMucHJ1bmluZ1NlZWQgPSBwcnVuaW5nU2VlZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0UnBjUG9ydCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnJwY1BvcnQ7XG4gIH1cblxuICBzZXRScGNQb3J0KHJwY1BvcnQ6IG51bWJlcik6IE1vbmVyb1BlZXIge1xuICAgIHRoaXMucnBjUG9ydCA9IHJwY1BvcnQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFJwY0NyZWRpdHNQZXJIYXNoKCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMucnBjQ3JlZGl0c1Blckhhc2g7XG4gIH1cbiAgXG4gIHNldFJwY0NyZWRpdHNQZXJIYXNoKHJwY0NyZWRpdHNQZXJIYXNoOiBiaWdpbnQpOiBNb25lcm9QZWVyIHtcbiAgICB0aGlzLnJwY0NyZWRpdHNQZXJIYXNoID0gcnBjQ3JlZGl0c1Blckhhc2g7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEF2Z0Rvd25sb2FkKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuYXZnRG93bmxvYWQ7XG4gIH1cblxuICBzZXRBdmdEb3dubG9hZChhdmdEb3dubG9hZDogbnVtYmVyKTogTW9uZXJvUGVlciB7XG4gICAgdGhpcy5hdmdEb3dubG9hZCA9IGF2Z0Rvd25sb2FkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0QXZnVXBsb2FkKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuYXZnVXBsb2FkO1xuICB9XG5cbiAgc2V0QXZnVXBsb2FkKGF2Z1VwbG9hZDogbnVtYmVyKTogTW9uZXJvUGVlciB7XG4gICAgdGhpcy5hdmdVcGxvYWQgPSBhdmdVcGxvYWQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRDdXJyZW50RG93bmxvYWQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5jdXJyZW50RG93bmxvYWQ7XG4gIH1cblxuICBzZXRDdXJyZW50RG93bmxvYWQoY3VycmVudERvd25sb2FkOiBudW1iZXIpOiBNb25lcm9QZWVyIHtcbiAgICB0aGlzLmN1cnJlbnREb3dubG9hZCA9IGN1cnJlbnREb3dubG9hZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldEN1cnJlbnRVcGxvYWQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5jdXJyZW50VXBsb2FkO1xuICB9XG5cbiAgc2V0Q3VycmVudFVwbG9hZChjdXJyZW50VXBsb2FkOiBudW1iZXIpOiBNb25lcm9QZWVyIHtcbiAgICB0aGlzLmN1cnJlbnRVcGxvYWQgPSBjdXJyZW50VXBsb2FkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0SGVpZ2h0KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuaGVpZ2h0O1xuICB9XG5cbiAgc2V0SGVpZ2h0KGhlaWdodDogbnVtYmVyKTogTW9uZXJvUGVlciB7XG4gICAgdGhpcy5oZWlnaHQgPSBoZWlnaHQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRJc0luY29taW5nKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzSW5jb21pbmc7XG4gIH1cblxuICBzZXRJc0luY29taW5nKGlzSW5jb21pbmc6IGJvb2xlYW4pOiBNb25lcm9QZWVyIHtcbiAgICB0aGlzLmlzSW5jb21pbmcgPSBpc0luY29taW5nO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0TGl2ZVRpbWUoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5saXZlVGltZTtcbiAgfVxuXG4gIHNldExpdmVUaW1lKGxpdmVUaW1lOiBudW1iZXIpIHtcbiAgICB0aGlzLmxpdmVUaW1lID0gbGl2ZVRpbWU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRJc0xvY2FsSXAoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNMb2NhbElwO1xuICB9XG5cbiAgc2V0SXNMb2NhbElwKGlzTG9jYWxJcDogYm9vbGVhbik6IE1vbmVyb1BlZXIge1xuICAgIHRoaXMuaXNMb2NhbElwID0gaXNMb2NhbElwO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0SXNMb2NhbEhvc3QoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNMb2NhbEhvc3Q7XG4gIH1cblxuICBzZXRJc0xvY2FsSG9zdChpc0xvY2FsSG9zdDogYm9vbGVhbik6IE1vbmVyb1BlZXIge1xuICAgIHRoaXMuaXNMb2NhbEhvc3QgPSBpc0xvY2FsSG9zdDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldE51bVJlY2VpdmVzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtUmVjZWl2ZXM7XG4gIH1cblxuICBzZXROdW1SZWNlaXZlcyhudW1SZWNlaXZlczogbnVtYmVyKTogTW9uZXJvUGVlciB7XG4gICAgdGhpcy5udW1SZWNlaXZlcyA9IG51bVJlY2VpdmVzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0TnVtU2VuZHMoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5udW1TZW5kcztcbiAgfVxuXG4gIHNldE51bVNlbmRzKG51bVNlbmRzOiBudW1iZXIpOiBNb25lcm9QZWVyIHtcbiAgICB0aGlzLm51bVNlbmRzID0gbnVtU2VuZHM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRSZWNlaXZlSWRsZVRpbWUoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5yZWNlaXZlSWRsZVRpbWU7XG4gIH1cblxuICBzZXRSZWNlaXZlSWRsZVRpbWUocmVjZWl2ZUlkbGVUaW1lOiBudW1iZXIpOiBNb25lcm9QZWVyIHtcbiAgICB0aGlzLnJlY2VpdmVJZGxlVGltZSA9IHJlY2VpdmVJZGxlVGltZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldFNlbmRJZGxlVGltZSgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnNlbmRJZGxlVGltZTtcbiAgfVxuXG4gIHNldFNlbmRJZGxlVGltZShzZW5kSWRsZVRpbWU6IG51bWJlcik6IE1vbmVyb1BlZXIge1xuICAgIHRoaXMuc2VuZElkbGVUaW1lID0gc2VuZElkbGVUaW1lO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0U3RhdGUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0ZTtcbiAgfVxuXG4gIHNldFN0YXRlKHN0YXRlOiBzdHJpbmcpOiBNb25lcm9QZWVyIHtcbiAgICB0aGlzLnN0YXRlID0gc3RhdGU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXROdW1TdXBwb3J0RmxhZ3MoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5udW1TdXBwb3J0RmxhZ3M7XG4gIH1cblxuICBzZXROdW1TdXBwb3J0RmxhZ3MobnVtU3VwcG9ydEZsYWdzOiBudW1iZXIpOiBNb25lcm9QZWVyIHtcbiAgICB0aGlzLm51bVN1cHBvcnRGbGFncyA9IG51bVN1cHBvcnRGbGFncztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0VHlwZSgpOiBDb25uZWN0aW9uVHlwZSB7XG4gICAgcmV0dXJuIHRoaXMudHlwZTtcbiAgfVxuICBcbiAgc2V0VHlwZSh0eXBlOiBDb25uZWN0aW9uVHlwZSk6IE1vbmVyb1BlZXIge1xuICAgIHRoaXMudHlwZSA9IHR5cGU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7QUFFQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSxVQUFVLENBQUM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUE0QjlCQyxXQUFXQSxDQUFDQyxJQUFpQixFQUFFO0lBQzdCQyxNQUFNLENBQUNDLE1BQU0sQ0FBQyxJQUFJ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 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroPruneResult.d.ts b/dist/src/main/ts/daemon/model/MoneroPruneResult.d.ts new file mode 100644 index 000000000..3c4d54f02 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroPruneResult.d.ts @@ -0,0 +1,13 @@ +/** + * Result of pruning the blockchain. + */ +export default class MoneroPruneResult { + isPruned: boolean; + pruningSeed: number; + constructor(result?: Partial); + toJson(): any; + getIsPruned(): boolean; + setIsPruned(isPruned: boolean): MoneroPruneResult; + getPruningSeed(): number; + setPruningSeed(pruningSeed: number): MoneroPruneResult; +} diff --git a/dist/src/main/ts/daemon/model/MoneroPruneResult.js b/dist/src/main/ts/daemon/model/MoneroPruneResult.js new file mode 100644 index 000000000..606a0d34b --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroPruneResult.js @@ -0,0 +1,38 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Result of pruning the blockchain. + */ +class MoneroPruneResult { + + + + + constructor(result) { + Object.assign(this, result); + } + + toJson() { + let json = Object.assign({}, this); + if (this.getIsPruned()) json.isPruned = this.getIsPruned(); + if (this.getPruningSeed()) json.pruningSeed = this.getPruningSeed(); + return json; + } + + getIsPruned() { + return this.isPruned; + } + + setIsPruned(isPruned) { + this.isPruned = isPruned; + return this; + } + + getPruningSeed() { + return this.pruningSeed; + } + + setPruningSeed(pruningSeed) { + this.pruningSeed = pruningSeed; + return this; + } +}exports.default = MoneroPruneResult; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9QcnVuZVJlc3VsdCIsImNvbnN0cnVjdG9yIiwicmVzdWx0IiwiT2JqZWN0IiwiYXNzaWduIiwidG9Kc29uIiwianNvbiIsImdldElzUHJ1bmVkIiwiaXNQcnVuZWQiLCJnZXRQcnVuaW5nU2VlZCIsInBydW5pbmdTZWVkIiwic2V0SXNQcnVuZWQiLCJzZXRQcnVuaW5nU2VlZCIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvZGFlbW9uL21vZGVsL01vbmVyb1BydW5lUmVzdWx0LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUmVzdWx0IG9mIHBydW5pbmcgdGhlIGJsb2NrY2hhaW4uXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb1BydW5lUmVzdWx0IHtcblxuICBpc1BydW5lZDogYm9vbGVhbjtcbiAgcHJ1bmluZ1NlZWQ6IG51bWJlcjtcbiAgXG4gIGNvbnN0cnVjdG9yKHJlc3VsdD86IFBhcnRpYWw8TW9uZXJvUHJ1bmVSZXN1bHQ+KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCByZXN1bHQpO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICBsZXQganNvbiA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICAgIGlmICh0aGlzLmdldElzUHJ1bmVkKCkpIGpzb24uaXNQcnVuZWQgPSB0aGlzLmdldElzUHJ1bmVkKCk7XG4gICAgaWYgKHRoaXMuZ2V0UHJ1bmluZ1NlZWQoKSkganNvbi5wcnVuaW5nU2VlZCA9IHRoaXMuZ2V0UHJ1bmluZ1NlZWQoKTtcbiAgICByZXR1cm4ganNvbjtcbiAgfVxuICBcbiAgZ2V0SXNQcnVuZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNQcnVuZWQ7XG4gIH1cbiAgXG4gIHNldElzUHJ1bmVkKGlzUHJ1bmVkOiBib29sZWFuKTogTW9uZXJvUHJ1bmVSZXN1bHQge1xuICAgIHRoaXMuaXNQcnVuZWQgPSBpc1BydW5lZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0UHJ1bmluZ1NlZWQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5wcnVuaW5nU2VlZDtcbiAgfVxuICBcbiAgc2V0UHJ1bmluZ1NlZWQocHJ1bmluZ1NlZWQ6IG51bWJlcik6IE1vbmVyb1BydW5lUmVzdWx0IHtcbiAgICB0aGlzLnBydW5pbmdTZWVkID0gcHJ1bmluZ1NlZWQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InFHQUFBO0FBQ0E7QUFDQTtBQUNlLE1BQU1BLGlCQUFpQixDQUFDOzs7OztFQUtyQ0MsV0FBV0EsQ0FBQ0MsTUFBbUMsRUFBRTtJQUMvQ0MsTUFBTSxDQUFDQyxNQUFNLENBQUMsSUFBSSxFQUFFRixNQUFNLENBQUM7RUFDN0I7O0VBRUFHLE1BQU1BLENBQUEsRUFBUTtJQUNaLElBQUlDLElBQUksR0FBR0gsTUFBTSxDQUFDQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQ2xDLElBQUksSUFBSSxDQUFDRyxXQUFXLENBQUMsQ0FBQyxFQUFFRCxJQUFJLENBQUNFLFFBQVEsR0FBRyxJQUFJLENBQUNELFdBQVcsQ0FBQyxDQUFDO0lBQzFELElBQUksSUFBSSxDQUFDRSxjQUFjLENBQUMsQ0FBQyxFQUFFSCxJQUFJLENBQUNJLFdBQVcsR0FBRyxJQUFJLENBQUNELGNBQWMsQ0FBQyxDQUFDO0lBQ25FLE9BQU9ILElBQUk7RUFDYjs7RUFFQUMsV0FBV0EsQ0FBQSxFQUFZO0lBQ3JCLE9BQU8sSUFBSSxDQUFDQyxRQUFRO0VBQ3RCOztFQUVBRyxXQUFXQSxDQUFDSCxRQUFpQixFQUFxQjtJQUNoRCxJQUFJLENBQUNBLFFBQVEsR0FBR0EsUUFBUTtJQUN4QixPQUFPLElBQUk7RUFDYjs7RUFFQUMsY0FBY0EsQ0FBQSxFQUFXO0lBQ3ZCLE9BQU8sSUFBSSxDQUFDQyxXQUFXO0VBQ3pCOztFQUVBRSxjQUFjQSxDQUFDRixXQUFtQixFQUFxQjtJQUNyRCxJQUFJLENBQUNBLFdBQVcsR0FBR0EsV0FBVztJQUM5QixPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNHLE9BQUEsQ0FBQUMsT0FBQSxHQUFBZCxpQkFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroSubmitTxResult.d.ts b/dist/src/main/ts/daemon/model/MoneroSubmitTxResult.d.ts new file mode 100644 index 000000000..033c58b39 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroSubmitTxResult.d.ts @@ -0,0 +1,55 @@ +/** + * Models the result from submitting a tx to a daemon. + */ +export default class MoneroSubmitTxResult { + isGood: boolean; + isRelayed: boolean; + isDoubleSpendSeen: boolean; + isFeeTooLow: boolean; + isMixinTooLow: boolean; + hasInvalidInput: boolean; + hasInvalidOutput: boolean; + hasTooFewOutputs: boolean; + isOverspend: boolean; + reason: string; + isTooBig: boolean; + sanityCheckFailed: boolean; + credits: bigint; + topBlockHash: string; + isTxExtraTooBig: boolean; + isNonzeroUnlockTime: boolean; + constructor(result?: Partial); + toJson(): any; + getIsGood(): boolean; + setIsGood(isGood: boolean): MoneroSubmitTxResult; + getIsRelayed(): boolean; + setIsRelayed(isRelayed: boolean): this; + getIsDoubleSpendSeen(): boolean; + setIsDoubleSpendSeen(isDoubleSpendSeen: boolean): MoneroSubmitTxResult; + getIsFeeTooLow(): boolean; + setIsFeeTooLow(isFeeTooLow: boolean): MoneroSubmitTxResult; + getIsMixinTooLow(): boolean; + setIsMixinTooLow(isMixinTooLow: boolean): MoneroSubmitTxResult; + getHasInvalidInput(): boolean; + setHasInvalidInput(hasInvalidInput: boolean): MoneroSubmitTxResult; + getHasInvalidOutput(): boolean; + setHasInvalidOutput(hasInvalidOutput: boolean): MoneroSubmitTxResult; + getHasTooFewOutputs(): boolean; + setHasTooFewOutputs(hasTooFewOutputs: boolean): MoneroSubmitTxResult; + getIsOverspend(): boolean; + setIsOverspend(isOverspend: boolean): MoneroSubmitTxResult; + getReason(): string; + setReason(reason: any): MoneroSubmitTxResult; + getIsTooBig(): boolean; + setIsTooBig(isTooBig: boolean): this; + getSanityCheckFailed(): boolean; + setSanityCheckFailed(sanityCheckFailed: any): MoneroSubmitTxResult; + getCredits(): bigint; + setCredits(credits: any): MoneroSubmitTxResult; + getTopBlockHash(): string; + setTopBlockHash(topBlockHash: string): MoneroSubmitTxResult; + getIsTxExtraTooBig(): boolean; + setIsTxExtraTooBig(isTxExtraTooBig: boolean): MoneroSubmitTxResult; + getIsNonzeroUnlockTime(): boolean; + setIsNonzeroUnlockTime(isNonzeroUnlockTime: boolean): MoneroSubmitTxResult; +} diff --git a/dist/src/main/ts/daemon/model/MoneroSubmitTxResult.js b/dist/src/main/ts/daemon/model/MoneroSubmitTxResult.js new file mode 100644 index 000000000..c2bd76123 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroSubmitTxResult.js @@ -0,0 +1,178 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Models the result from submitting a tx to a daemon. + */ +class MoneroSubmitTxResult { + + + + + + + + + + + + + + + + + + + constructor(result) { + Object.assign(this, result); + if (this.credits !== undefined && typeof this.credits !== "bigint") this.credits = BigInt(this.credits); + } + + toJson() { + let json = Object.assign({}, this); + if (json.credits !== undefined) json.credits = json.credits.toString(); + return json; + } + + getIsGood() { + return this.isGood; + } + + setIsGood(isGood) { + this.isGood = isGood; + return this; + } + + getIsRelayed() { + return this.isRelayed; + } + + setIsRelayed(isRelayed) { + this.isRelayed = isRelayed; + return this; + } + + getIsDoubleSpendSeen() { + return this.isDoubleSpendSeen; + } + + setIsDoubleSpendSeen(isDoubleSpendSeen) { + this.isDoubleSpendSeen = isDoubleSpendSeen; + return this; + } + + getIsFeeTooLow() { + return this.isFeeTooLow; + } + + setIsFeeTooLow(isFeeTooLow) { + this.isFeeTooLow = isFeeTooLow; + return this; + } + + getIsMixinTooLow() { + return this.isMixinTooLow; + } + + setIsMixinTooLow(isMixinTooLow) { + this.isMixinTooLow = isMixinTooLow; + return this; + } + + getHasInvalidInput() { + return this.hasInvalidInput; + } + + setHasInvalidInput(hasInvalidInput) { + this.hasInvalidInput = hasInvalidInput; + return this; + } + + getHasInvalidOutput() { + return this.hasInvalidOutput; + } + + setHasInvalidOutput(hasInvalidOutput) { + this.hasInvalidOutput = hasInvalidOutput; + return this; + } + + getHasTooFewOutputs() { + return this.hasTooFewOutputs; + } + + setHasTooFewOutputs(hasTooFewOutputs) { + this.hasTooFewOutputs = hasTooFewOutputs; + return this; + } + + getIsOverspend() { + return this.isOverspend; + } + + setIsOverspend(isOverspend) { + this.isOverspend = isOverspend; + return this; + } + + getReason() { + return this.reason; + } + + setReason(reason) { + this.reason = reason; + return this; + } + + getIsTooBig() { + return this.isTooBig; + } + + setIsTooBig(isTooBig) { + this.isTooBig = isTooBig; + return this; + } + + getSanityCheckFailed() { + return this.sanityCheckFailed; + } + + setSanityCheckFailed(sanityCheckFailed) { + this.sanityCheckFailed = sanityCheckFailed; + return this; + } + + getCredits() { + return this.credits; + } + + setCredits(credits) { + this.credits = credits; + return this; + } + + getTopBlockHash() { + return this.topBlockHash; + } + + setTopBlockHash(topBlockHash) { + this.topBlockHash = topBlockHash; + return this; + } + + getIsTxExtraTooBig() { + return this.isTxExtraTooBig; + } + + setIsTxExtraTooBig(isTxExtraTooBig) { + this.isTxExtraTooBig = isTxExtraTooBig; + return this; + } + + getIsNonzeroUnlockTime() { + return this.isNonzeroUnlockTime; + } + + setIsNonzeroUnlockTime(isNonzeroUnlockTime) { + this.isNonzeroUnlockTime = isNonzeroUnlockTime; + return this; + } +}exports.default = MoneroSubmitTxResult; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9TdWJtaXRUeFJlc3VsdCIsImNvbnN0cnVjdG9yIiwicmVzdWx0IiwiT2JqZWN0IiwiYXNzaWduIiwiY3JlZGl0cyIsInVuZGVmaW5lZCIsIkJpZ0ludCIsInRvSnNvbiIsImpzb24iLCJ0b1N0cmluZyIsImdldElzR29vZCIsImlzR29vZCIsInNldElzR29vZCIsImdldElzUmVsYXllZCIsImlzUmVsYXllZCIsInNldElzUmVsYXllZCIsImdldElzRG91YmxlU3BlbmRTZWVuIiwiaXNEb3VibGVTcGVuZFNlZW4iLCJzZXRJc0RvdWJsZVNwZW5kU2VlbiIsImdldElzRmVlVG9vTG93IiwiaXNGZWVUb29Mb3ciLCJzZXRJc0ZlZVRvb0xvdyIsImdldElzTWl4aW5Ub29Mb3ciLCJpc01peGluVG9vTG93Iiwic2V0SXNNaXhpblRvb0xvdyIsImdldEhhc0ludmFsaWRJbnB1dCIsImhhc0ludmFsaWRJbnB1dCIsInNldEhhc0ludmFsaWRJbnB1dCIsImdldEhhc0ludmFsaWRPdXRwdXQiLCJoYXNJbnZhbGlkT3V0cHV0Iiwic2V0SGFzSW52YWxpZE91dHB1dCIsImdldEhhc1Rvb0Zld091dHB1dHMiLCJoYXNUb29GZXdPdXRwdXRzIiwic2V0SGFzVG9vRmV3T3V0cHV0cyIsImdldElzT3ZlcnNwZW5kIiwiaXNPdmVyc3BlbmQiLCJzZXRJc092ZXJzcGVuZCIsImdldFJlYXNvbiIsInJlYXNvbiIsInNldFJlYXNvbiIsImdldElzVG9vQmlnIiwiaXNUb29CaWciLCJzZXRJc1Rvb0JpZyIsImdldFNhbml0eUNoZWNrRmFpbGVkIiwic2FuaXR5Q2hlY2tGYWlsZWQiLCJzZXRTYW5pdHlDaGVja0ZhaWxlZCIsImdldENyZWRpdHMiLCJzZXRDcmVkaXRzIiwiZ2V0VG9wQmxvY2tIYXNoIiwidG9wQmxvY2tIYXNoIiwic2V0VG9wQmxvY2tIYXNoIiwiZ2V0SXNUeEV4dHJhVG9vQmlnIiwiaXNUeEV4dHJhVG9vQmlnIiwic2V0SXNUeEV4dHJhVG9vQmlnIiwiZ2V0SXNOb256ZXJvVW5sb2NrVGltZSIsImlzTm9uemVyb1VubG9ja1RpbWUiLCJzZXRJc05vbnplcm9VbmxvY2tUaW1lIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9kYWVtb24vbW9kZWwvTW9uZXJvU3VibWl0VHhSZXN1bHQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBNb2RlbHMgdGhlIHJlc3VsdCBmcm9tIHN1Ym1pdHRpbmcgYSB0eCB0byBhIGRhZW1vbi5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTW9uZXJvU3VibWl0VHhSZXN1bHQge1xuXG4gIGlzR29vZDogYm9vbGVhbjtcbiAgaXNSZWxheWVkOiBib29sZWFuO1xuICBpc0RvdWJsZVNwZW5kU2VlbjogYm9vbGVhbjtcbiAgaXNGZWVUb29Mb3c6IGJvb2xlYW47XG4gIGlzTWl4aW5Ub29Mb3c6IGJvb2xlYW47XG4gIGhhc0ludmFsaWRJbnB1dDogYm9vbGVhbjtcbiAgaGFzSW52YWxpZE91dHB1dDogYm9vbGVhbjtcbiAgaGFzVG9vRmV3T3V0cHV0czogYm9vbGVhbjtcbiAgaXNPdmVyc3BlbmQ6IGJvb2xlYW47XG4gIHJlYXNvbjogc3RyaW5nO1xuICBpc1Rvb0JpZzogYm9vbGVhbjtcbiAgc2FuaXR5Q2hlY2tGYWlsZWQ6IGJvb2xlYW47XG4gIGNyZWRpdHM6IGJpZ2ludDtcbiAgdG9wQmxvY2tIYXNoOiBzdHJpbmc7XG4gIGlzVHhFeHRyYVRvb0JpZzogYm9vbGVhbjtcbiAgaXNOb256ZXJvVW5sb2NrVGltZTogYm9vbGVhbjtcbiAgXG4gIGNvbnN0cnVjdG9yKHJlc3VsdD86IFBhcnRpYWw8TW9uZXJvU3VibWl0VHhSZXN1bHQ+KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCByZXN1bHQpO1xuICAgIGlmICh0aGlzLmNyZWRpdHMgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5jcmVkaXRzICE9PSBcImJpZ2ludFwiKSB0aGlzLmNyZWRpdHMgPSBCaWdJbnQodGhpcy5jcmVkaXRzKTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgbGV0IGpzb246IGFueSA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICAgIGlmIChqc29uLmNyZWRpdHMgIT09IHVuZGVmaW5lZCkganNvbi5jcmVkaXRzID0ganNvbi5jcmVkaXRzLnRvU3RyaW5nKCk7XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIGdldElzR29vZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc0dvb2Q7XG4gIH1cbiAgXG4gIHNldElzR29vZChpc0dvb2Q6IGJvb2xlYW4pOiBNb25lcm9TdWJtaXRUeFJlc3VsdCB7XG4gICAgdGhpcy5pc0dvb2QgPSBpc0dvb2Q7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldElzUmVsYXllZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc1JlbGF5ZWQ7XG4gIH1cbiAgXG4gIHNldElzUmVsYXllZChpc1JlbGF5ZWQ6IGJvb2xlYW4pIHtcbiAgICB0aGlzLmlzUmVsYXllZCA9IGlzUmVsYXllZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0SXNEb3VibGVTcGVuZFNlZW4oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNEb3VibGVTcGVuZFNlZW47XG4gIH1cbiAgXG4gIHNldElzRG91YmxlU3BlbmRTZWVuKGlzRG91YmxlU3BlbmRTZWVuOiBib29sZWFuKTogTW9uZXJvU3VibWl0VHhSZXN1bHQge1xuICAgIHRoaXMuaXNEb3VibGVTcGVuZFNlZW4gPSBpc0RvdWJsZVNwZW5kU2VlblxuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRJc0ZlZVRvb0xvdygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc0ZlZVRvb0xvdztcbiAgfVxuICBcbiAgc2V0SXNGZWVUb29Mb3coaXNGZWVUb29Mb3c6IGJvb2xlYW4pOiBNb25lcm9TdWJtaXRUeFJlc3VsdCB7XG4gICAgdGhpcy5pc0ZlZVRvb0xvdyA9IGlzRmVlVG9vTG93O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRJc01peGluVG9vTG93KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzTWl4aW5Ub29Mb3c7XG4gIH1cbiAgXG4gIHNldElzTWl4aW5Ub29Mb3coaXNNaXhpblRvb0xvdzogYm9vbGVhbik6IE1vbmVyb1N1Ym1pdFR4UmVzdWx0IHtcbiAgICB0aGlzLmlzTWl4aW5Ub29Mb3cgPSBpc01peGluVG9vTG93O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRIYXNJbnZhbGlkSW5wdXQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaGFzSW52YWxpZElucHV0O1xuICB9XG4gIFxuICBzZXRIYXNJbnZhbGlkSW5wdXQoaGFzSW52YWxpZElucHV0OiBib29sZWFuKTogTW9uZXJvU3VibWl0VHhSZXN1bHQge1xuICAgIHRoaXMuaGFzSW52YWxpZElucHV0ID0gaGFzSW52YWxpZElucHV0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRIYXNJbnZhbGlkT3V0cHV0KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmhhc0ludmFsaWRPdXRwdXQ7XG4gIH1cbiAgXG4gIHNldEhhc0ludmFsaWRPdXRwdXQoaGFzSW52YWxpZE91dHB1dDogYm9vbGVhbik6IE1vbmVyb1N1Ym1pdFR4UmVzdWx0IHtcbiAgICB0aGlzLmhhc0ludmFsaWRPdXRwdXQgPSBoYXNJbnZhbGlkT3V0cHV0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRIYXNUb29GZXdPdXRwdXRzKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmhhc1Rvb0Zld091dHB1dHM7XG4gIH1cbiAgXG4gIHNldEhhc1Rvb0Zld091dHB1dHMoaGFzVG9vRmV3T3V0cHV0czogYm9vbGVhbik6IE1vbmVyb1N1Ym1pdFR4UmVzdWx0IHtcbiAgICB0aGlzLmhhc1Rvb0Zld091dHB1dHMgPSBoYXNUb29GZXdPdXRwdXRzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRJc092ZXJzcGVuZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc092ZXJzcGVuZDtcbiAgfVxuICBcbiAgc2V0SXNPdmVyc3BlbmQoaXNPdmVyc3BlbmQ6IGJvb2xlYW4pOiBNb25lcm9TdWJtaXRUeFJlc3VsdCB7XG4gICAgdGhpcy5pc092ZXJzcGVuZCA9IGlzT3ZlcnNwZW5kO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRSZWFzb24oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5yZWFzb247XG4gIH1cbiAgXG4gIHNldFJlYXNvbihyZWFzb24pOiBNb25lcm9TdWJtaXRUeFJlc3VsdCB7XG4gICAgdGhpcy5yZWFzb24gPSByZWFzb247XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldElzVG9vQmlnKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzVG9vQmlnO1xuICB9XG4gIFxuICBzZXRJc1Rvb0JpZyhpc1Rvb0JpZzogYm9vbGVhbikge1xuICAgIHRoaXMuaXNUb29CaWcgPSBpc1Rvb0JpZztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U2FuaXR5Q2hlY2tGYWlsZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2FuaXR5Q2hlY2tGYWlsZWQ7XG4gIH1cbiAgXG4gIHNldFNhbml0eUNoZWNrRmFpbGVkKHNhbml0eUNoZWNrRmFpbGVkKTogTW9uZXJvU3VibWl0VHhSZXN1bHQge1xuICAgIHRoaXMuc2FuaXR5Q2hlY2tGYWlsZWQgPSBzYW5pdHlDaGVja0ZhaWxlZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0Q3JlZGl0cygpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLmNyZWRpdHM7XG4gIH1cbiAgXG4gIHNldENyZWRpdHMoY3JlZGl0cyk6IE1vbmVyb1N1Ym1pdFR4UmVzdWx0IHtcbiAgICB0aGlzLmNyZWRpdHMgPSBjcmVkaXRzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRUb3BCbG9ja0hhc2goKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy50b3BCbG9ja0hhc2g7XG4gIH1cbiAgXG4gIHNldFRvcEJsb2NrSGFzaCh0b3BCbG9ja0hhc2g6IHN0cmluZyk6IE1vbmVyb1N1Ym1pdFR4UmVzdWx0IHtcbiAgICB0aGlzLnRvcEJsb2NrSGFzaCA9IHRvcEJsb2NrSGFzaDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldElzVHhFeHRyYVRvb0JpZygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc1R4RXh0cmFUb29CaWc7XG4gIH1cbiAgXG4gIHNldElzVHhFeHRyYVRvb0JpZyhpc1R4RXh0cmFUb29CaWc6IGJvb2xlYW4pOiBNb25lcm9TdWJtaXRUeFJlc3VsdCB7XG4gICAgdGhpcy5pc1R4RXh0cmFUb29CaWcgPSBpc1R4RXh0cmFUb29CaWc7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRJc05vbnplcm9VbmxvY2tUaW1lKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzTm9uemVyb1VubG9ja1RpbWU7XG4gIH1cbiAgXG4gIHNldElzTm9uemVyb1VubG9ja1RpbWUoaXNOb256ZXJvVW5sb2NrVGltZTogYm9vbGVhbik6IE1vbmVyb1N1Ym1pdFR4UmVzdWx0IHtcbiAgICB0aGlzLmlzTm9uemVyb1VubG9ja1RpbWUgPSBpc05vbnplcm9VbmxvY2tUaW1lO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJxR0FBQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSxvQkFBb0IsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQW1CeENDLFdBQVdBLENBQUNDLE1BQXNDLEVBQUU7SUFDbERDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsTUFBTSxDQUFDO0lBQzNCLElBQUksSUFBSSxDQUFDRyxP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 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroTx.d.ts b/dist/src/main/ts/daemon/model/MoneroTx.d.ts new file mode 100644 index 000000000..105219e75 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroTx.d.ts @@ -0,0 +1,409 @@ +import MoneroBlock from "./MoneroBlock"; +import MoneroOutput from "./MoneroOutput"; +/** + * Represents a transaction on the Monero network. + */ +export default class MoneroTx { + static readonly DEFAULT_PAYMENT_ID = "0000000000000000"; + block: MoneroBlock; + hash: string; + version: number; + isMinerTx: boolean; + paymentId: string; + fee: bigint; + ringSize: number; + relay: boolean; + isRelayed: boolean; + isConfirmed: boolean; + inTxPool: boolean; + numConfirmations: number; + unlockTime: bigint; + lastRelayedTimestamp: number; + receivedTimestamp: number; + isDoubleSpendSeen: boolean; + key: string; + fullHex: string; + prunedHex: string; + prunableHex: string; + prunableHash: string; + size: number; + weight: number; + inputs: MoneroOutput[]; + outputs: MoneroOutput[]; + outputIndices: number[]; + metadata: string; + extra: Uint8Array; + rctSignatures: any; + rctSigPrunable: any; + isKeptByBlock: boolean; + isFailed: boolean; + lastFailedHeight: number; + lastFailedHash: string; + maxUsedBlockHeight: number; + maxUsedBlockHash: string; + signatures: string[]; + constructor(tx?: Partial); + /** + * @return {MoneroBlock} tx block + */ + getBlock(): MoneroBlock; + /** + * @param {MoneroBlock} block - tx block + * @return {MoneroTx} this tx for chaining + */ + setBlock(block: MoneroBlock): MoneroTx; + /** + * @return {number} tx height + */ + getHeight(): number; + /** + * @return {string} tx hash + */ + getHash(): string; + /** + * @param {string} hash - tx hash + * @return {MoneroTx} this tx for chaining + */ + setHash(hash: string): MoneroTx; + /** + * @return {number} tx version + */ + getVersion(): number; + /** + * @param {number} version - tx version + * @return {MoneroTx} this tx for chaining + */ + setVersion(version: number): MoneroTx; + /** + * @return {boolean} true if the tx is a miner tx, false otherwise + */ + getIsMinerTx(): boolean; + /** + * @param {boolean} miner - true if the tx is a miner tx, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsMinerTx(miner: boolean): MoneroTx; + /** + * @return {string} tx payment id + */ + getPaymentId(): string; + /** + * @param {string} paymentId - tx payment id + * @return {MoneroTx} this tx for chaining + */ + setPaymentId(paymentId: string): MoneroTx; + /** + * @return {bigint} tx fee + */ + getFee(): bigint; + /** + * @param {bigint} fee - tx fee + * @return {MoneroTx} this tx for chaining + */ + setFee(fee: bigint): MoneroTx; + /** + * @return {number} tx ring size + */ + getRingSize(): number; + /** + * @param {number} ringSize - tx ring size + * @return {MoneroTx} this tx for chaining + */ + setRingSize(ringSize: number): MoneroTx; + /** + * @return {boolean} true if the tx is set to be relayed, false otherwise + */ + getRelay(): boolean; + /** + * @param {boolean} relay - true if the tx is set to be relayed, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setRelay(relay: boolean): MoneroTx; + /** + * @return {boolean} true if the tx is relayed, false otherwise + */ + getIsRelayed(): boolean; + /** + * @param {boolean} isRelayed - true if the tx is relayed, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsRelayed(isRelayed: boolean): MoneroTx; + /** + * @return {boolean} true if the tx is confirmed, false otherwise + */ + getIsConfirmed(): boolean; + /** + * @param {boolean} isConfirmed - true if the tx is confirmed, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsConfirmed(isConfirmed: boolean): MoneroTx; + /** + * @return {boolean} true if the tx is in the memory pool, false otherwise + */ + getInTxPool(): boolean; + /** + * @param {boolean} inTxPool - true if the tx is in the memory pool, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setInTxPool(inTxPool: boolean): MoneroTx; + /** + * @return {number} number of block confirmations + */ + getNumConfirmations(): number; + /** + * @param {number} numConfirmations - number of block confirmations + * @return {MoneroTx} this tx for chaining + */ + setNumConfirmations(numConfirmations: number): MoneroTx; + /** + * Get the minimum height or timestamp for the transactions to unlock. + * + * @return {bigint} the minimum height or timestamp for the transaction to unlock + */ + getUnlockTime(): bigint; + setUnlockTime(unlockTime: bigint | string | number | undefined): MoneroTx; + /** + * @return {number} timestamp the tx was last relayed from the node + */ + getLastRelayedTimestamp(): number; + /** + * @param {number} lastRelayedTimestamp - timestamp the tx was last relayed from the node + * @return {MoneroTx} this tx for chaining + */ + setLastRelayedTimestamp(lastRelayedTimestamp: number): MoneroTx; + /** + * @return {number} timestamp the tx was received at the node + */ + getReceivedTimestamp(): number; + /** + * @param {number} receivedTimestamp - timestamp the tx was received at the node + * @return {MoneroTx} this tx for chaining + */ + setReceivedTimestamp(receivedTimestamp: number): MoneroTx; + /** + * @return {boolean} true if a double spend has been seen, false otherwise + */ + getIsDoubleSpendSeen(): boolean; + /** + * @param {boolean} isDoubleSpendSeen - true if a double spend has been seen, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsDoubleSpendSeen(isDoubleSpendSeen: boolean): MoneroTx; + /** + * @return {string} tx key + */ + getKey(): string; + /** + * @param {string} key - tx key + * @return {MoneroTx} this tx for chaining + */ + setKey(key: string): MoneroTx; + /** + * Get full transaction hex. Full hex = pruned hex + prunable hex. + * + * @return {string|undefined} full tx hex + */ + getFullHex(): string | undefined; + /** + * @param {string} fullHex - full tx hex + * @return {MoneroTx} this tx for chaining + */ + setFullHex(fullHex: string): MoneroTx; + /** + * Get pruned transaction hex. Full hex = pruned hex + prunable hex. + * + * @return {string} pruned tx hex + */ + getPrunedHex(): string; + /** + * @param {string} prunedHex - pruned tx hex + * @return {MoneroTx} this tx for chaining + */ + setPrunedHex(prunedHex: string): MoneroTx; + /** + * Get prunable transaction hex which is hex that is removed from a pruned + * transaction. Full hex = pruned hex + prunable hex. + * + * @return {string} prunable tx hex + */ + getPrunableHex(): string; + /** + * @param {string} prunableHex - prunable tx hex + * @return {MoneroTx} this tx for chaining + */ + setPrunableHex(prunableHex: string): MoneroTx; + /** + * @return {string} prunable tx hash + */ + getPrunableHash(): string; + /** + * @param {string} prunableHash - prunable tx hash + * @return {MoneroTx} this tx for chaining + */ + setPrunableHash(prunableHash: string): MoneroTx; + /** + * @return {number} tx size + */ + getSize(): number; + /** + * @param {number} size - tx size + * @return {MoneroTx} this tx for chaining + */ + setSize(size: number): MoneroTx; + /** + * @return {number} tx weight + */ + getWeight(): number; + /** + * @param {number} weight - tx weight + * @return {MoneroTx} this tx for chaining + */ + setWeight(weight: number): MoneroTx; + /** + * @return {MoneroOutput[]} tx inputs + */ + getInputs(): MoneroOutput[]; + /** + * @param {MoneroOutput[]} - tx inputs + * @return {MoneroTx} this tx for chaining + */ + setInputs(inputs: MoneroOutput[]): MoneroTx; + /** + * @return {MoneroOutput[]} tx outputs + */ + getOutputs(): MoneroOutput[]; + /** + * @param {MoneroOutput[]} outputs - tx outputs + * @return {MoneroTx} this tx for chaining + */ + setOutputs(outputs: MoneroOutput[]): MoneroTx; + /** + * @return {number[]} tx output indices + */ + getOutputIndices(): number[]; + /** + * @param {number[]} outputIndices - tx output indices + * @return {MoneroTx} this tx for chaining + */ + setOutputIndices(outputIndices: number[]): MoneroTx; + /** + * @return {string} tx metadata + */ + getMetadata(): string; + /** + * @param {string} metadata - tx metadata + * @return {MoneroTx} this tx for chaining + */ + setMetadata(metadata: string): MoneroTx; + /** + * @return {Uint8Array} tx extra + */ + getExtra(): Uint8Array; + /** + * @param {Uint8Array} extra - tx extra + * @return {MoneroTx} this tx for chaining + */ + setExtra(extra: Uint8Array): MoneroTx; + /** + * @return {any} RCT signatures + */ + getRctSignatures(): any; + /** + * @param {any} rctSignatures - RCT signatures + * @return {MoneroTx} this tx for chaining + */ + setRctSignatures(rctSignatures: any): MoneroTx; + /** + * @return {any} prunable RCT signature data + */ + getRctSigPrunable(): object; + /** + * @param {any} rctSigPrunable - prunable RCT signature data + * @return {MoneroTx} this tx for chaining + */ + setRctSigPrunable(rctSigPrunable: any): MoneroTx; + /** + * @return {boolean} true if kept by a block, false otherwise + */ + getIsKeptByBlock(): boolean; + /** + * @param {boolean} isKeptByBlock - true if kept by a block, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsKeptByBlock(isKeptByBlock: boolean): MoneroTx; + /** + * @return {boolean} true if the tx failed, false otherwise + */ + getIsFailed(): boolean; + /** + * @param {boolean} isFailed - true if the tx failed, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsFailed(isFailed: boolean): MoneroTx; + /** + * @return {number} block height of the last tx failure + */ + getLastFailedHeight(): number; + /** + * @param {number} lastFailedHeight - block height of the last tx failure + * @return {MoneroTx} this tx for chaining + */ + setLastFailedHeight(lastFailedHeight: number): MoneroTx; + /** + * @return {string} block hash of the last tx failure + */ + getLastFailedHash(): string; + /** + * @param {string} lastFailedHash - block hash of the last tx failure + * @return {MoneroTx} this tx for chaining + */ + setLastFailedHash(lastFailedHash: string): MoneroTx; + /** + * @return {number} max used block height + */ + getMaxUsedBlockHeight(): number; + /** + * @param {number} maxUsedBlockHeight - max used block height + * @return {MoneroTx} this tx for chaining + */ + setMaxUsedBlockHeight(maxUsedBlockHeight: number): MoneroTx; + /** + * @return {string} max used block hash + */ + getMaxUsedBlockHash(): string; + /** + * @param {string} maxUsedBlockHash - max used block hash + * @return {MoneroTx} this tx for chaining + */ + setMaxUsedBlockHash(maxUsedBlockHash: string): MoneroTx; + /** + * @return {string[]} tx signatures + */ + getSignatures(): string[]; + /** + * @param {string[]} signatures - tx signatures + * @return {MoneroTx} this tx for chaining + */ + setSignatures(signatures: string[]): MoneroTx; + /** + * @return {MoneroTx} a copy of this tx + */ + copy(): MoneroTx; + /** + * @return {any} json representation of this tx + */ + toJson(): any; + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * @param {MoneroTx} tx - the transaction to update this transaction with + * @return {MoneroTx} this for method chaining + */ + merge(tx: MoneroTx): MoneroTx; + /** + * @param {number} [indent] - starting indentation + * @return {string} string representation of this tx + */ + toString(indent?: number): string; +} diff --git a/dist/src/main/ts/daemon/model/MoneroTx.js b/dist/src/main/ts/daemon/model/MoneroTx.js new file mode 100644 index 000000000..f9a0c2d3d --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroTx.js @@ -0,0 +1,881 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); + +var _MoneroOutput = _interopRequireDefault(require("./MoneroOutput")); + +/** + * Represents a transaction on the Monero network. + */ +class MoneroTx { + + static DEFAULT_PAYMENT_ID = "0000000000000000"; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + constructor(tx) { + Object.assign(this, tx); + this.block = undefined; + + // deserialize extra + if (this.extra !== undefined) this.extra = new Uint8Array(this.extra); + + // deserialize bigints + if (this.fee !== undefined && typeof this.fee !== "bigint") this.fee = BigInt(this.fee); + if (this.unlockTime !== undefined && typeof this.unlockTime !== "bigint") this.unlockTime = BigInt(this.unlockTime); + + // copy inputs + if (this.inputs) { + this.inputs = this.inputs.slice(); + for (let i = 0; i < this.inputs.length; i++) { + this.inputs[i] = new _MoneroOutput.default(this.inputs[i]).setTx(this); + } + } + + // copy outputs + if (this.outputs) { + this.outputs = this.outputs.slice(); + for (let i = 0; i < this.outputs.length; i++) { + this.outputs[i] = new _MoneroOutput.default(this.outputs[i]).setTx(this); + } + } + } + + /** + * @return {MoneroBlock} tx block + */ + getBlock() { + return this.block; + } + + /** + * @param {MoneroBlock} block - tx block + * @return {MoneroTx} this tx for chaining + */ + setBlock(block) { + this.block = block; + return this; + } + + /** + * @return {number} tx height + */ + getHeight() { + return this.getBlock() === undefined ? undefined : this.getBlock().getHeight(); + } + + /** + * @return {string} tx hash + */ + getHash() { + return this.hash; + } + + /** + * @param {string} hash - tx hash + * @return {MoneroTx} this tx for chaining + */ + setHash(hash) { + this.hash = hash; + return this; + } + + /** + * @return {number} tx version + */ + getVersion() { + return this.version; + } + + /** + * @param {number} version - tx version + * @return {MoneroTx} this tx for chaining + */ + setVersion(version) { + this.version = version; + return this; + } + + /** + * @return {boolean} true if the tx is a miner tx, false otherwise + */ + getIsMinerTx() { + return this.isMinerTx; + } + + /** + * @param {boolean} miner - true if the tx is a miner tx, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsMinerTx(miner) { + this.isMinerTx = miner; + return this; + } + + /** + * @return {string} tx payment id + */ + getPaymentId() { + return this.paymentId; + } + + /** + * @param {string} paymentId - tx payment id + * @return {MoneroTx} this tx for chaining + */ + setPaymentId(paymentId) { + this.paymentId = paymentId; + return this; + } + + /** + * @return {bigint} tx fee + */ + getFee() { + return this.fee; + } + + /** + * @param {bigint} fee - tx fee + * @return {MoneroTx} this tx for chaining + */ + setFee(fee) { + this.fee = fee; + return this; + } + + /** + * @return {number} tx ring size + */ + getRingSize() { + return this.ringSize; + } + + /** + * @param {number} ringSize - tx ring size + * @return {MoneroTx} this tx for chaining + */ + setRingSize(ringSize) { + this.ringSize = ringSize; + return this; + } + + /** + * @return {boolean} true if the tx is set to be relayed, false otherwise + */ + getRelay() { + return this.relay; + } + + /** + * @param {boolean} relay - true if the tx is set to be relayed, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setRelay(relay) { + this.relay = relay; + return this; + } + + /** + * @return {boolean} true if the tx is relayed, false otherwise + */ + getIsRelayed() { + return this.isRelayed; + } + + /** + * @param {boolean} isRelayed - true if the tx is relayed, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsRelayed(isRelayed) { + this.isRelayed = isRelayed; + return this; + } + + /** + * @return {boolean} true if the tx is confirmed, false otherwise + */ + getIsConfirmed() { + return this.isConfirmed; + } + + /** + * @param {boolean} isConfirmed - true if the tx is confirmed, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsConfirmed(isConfirmed) { + this.isConfirmed = isConfirmed; + return this; + } + + /** + * @return {boolean} true if the tx is in the memory pool, false otherwise + */ + getInTxPool() { + return this.inTxPool; + } + + /** + * @param {boolean} inTxPool - true if the tx is in the memory pool, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setInTxPool(inTxPool) { + this.inTxPool = inTxPool; + return this; + } + + /** + * @return {number} number of block confirmations + */ + getNumConfirmations() { + return this.numConfirmations; + } + + /** + * @param {number} numConfirmations - number of block confirmations + * @return {MoneroTx} this tx for chaining + */ + setNumConfirmations(numConfirmations) { + this.numConfirmations = numConfirmations; + return this; + } + + /** + * Get the minimum height or timestamp for the transactions to unlock. + * + * @return {bigint} the minimum height or timestamp for the transaction to unlock + */ + getUnlockTime() { + return this.unlockTime; + } + + setUnlockTime(unlockTime) { + if (unlockTime !== undefined && typeof unlockTime !== "bigint") unlockTime = BigInt(unlockTime); + this.unlockTime = unlockTime; + return this; + } + + /** + * @return {number} timestamp the tx was last relayed from the node + */ + getLastRelayedTimestamp() { + return this.lastRelayedTimestamp; + } + + /** + * @param {number} lastRelayedTimestamp - timestamp the tx was last relayed from the node + * @return {MoneroTx} this tx for chaining + */ + setLastRelayedTimestamp(lastRelayedTimestamp) { + this.lastRelayedTimestamp = lastRelayedTimestamp; + return this; + } + + /** + * @return {number} timestamp the tx was received at the node + */ + getReceivedTimestamp() { + return this.receivedTimestamp; + } + + /** + * @param {number} receivedTimestamp - timestamp the tx was received at the node + * @return {MoneroTx} this tx for chaining + */ + setReceivedTimestamp(receivedTimestamp) { + this.receivedTimestamp = receivedTimestamp; + return this; + } + + /** + * @return {boolean} true if a double spend has been seen, false otherwise + */ + getIsDoubleSpendSeen() { + return this.isDoubleSpendSeen; + } + + /** + * @param {boolean} isDoubleSpendSeen - true if a double spend has been seen, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsDoubleSpendSeen(isDoubleSpendSeen) { + this.isDoubleSpendSeen = isDoubleSpendSeen; + return this; + } + + /** + * @return {string} tx key + */ + getKey() { + return this.key; + } + + /** + * @param {string} key - tx key + * @return {MoneroTx} this tx for chaining + */ + setKey(key) { + this.key = key; + return this; + } + + /** + * Get full transaction hex. Full hex = pruned hex + prunable hex. + * + * @return {string|undefined} full tx hex + */ + getFullHex() { + return this.fullHex; + } + + /** + * @param {string} fullHex - full tx hex + * @return {MoneroTx} this tx for chaining + */ + setFullHex(fullHex) { + this.fullHex = fullHex; + return this; + } + + /** + * Get pruned transaction hex. Full hex = pruned hex + prunable hex. + * + * @return {string} pruned tx hex + */ + getPrunedHex() { + return this.prunedHex; + } + + /** + * @param {string} prunedHex - pruned tx hex + * @return {MoneroTx} this tx for chaining + */ + setPrunedHex(prunedHex) { + this.prunedHex = prunedHex; + return this; + } + + /** + * Get prunable transaction hex which is hex that is removed from a pruned + * transaction. Full hex = pruned hex + prunable hex. + * + * @return {string} prunable tx hex + */ + getPrunableHex() { + return this.prunableHex; + } + + /** + * @param {string} prunableHex - prunable tx hex + * @return {MoneroTx} this tx for chaining + */ + setPrunableHex(prunableHex) { + this.prunableHex = prunableHex; + return this; + } + + /** + * @return {string} prunable tx hash + */ + getPrunableHash() { + return this.prunableHash; + } + + /** + * @param {string} prunableHash - prunable tx hash + * @return {MoneroTx} this tx for chaining + */ + setPrunableHash(prunableHash) { + this.prunableHash = prunableHash; + return this; + } + + /** + * @return {number} tx size + */ + getSize() { + return this.size; + } + + /** + * @param {number} size - tx size + * @return {MoneroTx} this tx for chaining + */ + setSize(size) { + this.size = size; + return this; + } + + /** + * @return {number} tx weight + */ + getWeight() { + return this.weight; + } + + /** + * @param {number} weight - tx weight + * @return {MoneroTx} this tx for chaining + */ + setWeight(weight) { + this.weight = weight; + return this; + } + + /** + * @return {MoneroOutput[]} tx inputs + */ + getInputs() { + return this.inputs; + } + + /** + * @param {MoneroOutput[]} - tx inputs + * @return {MoneroTx} this tx for chaining + */ + setInputs(inputs) { + this.inputs = inputs; + return this; + } + + /** + * @return {MoneroOutput[]} tx outputs + */ + getOutputs() { + return this.outputs; + } + + /** + * @param {MoneroOutput[]} outputs - tx outputs + * @return {MoneroTx} this tx for chaining + */ + setOutputs(outputs) { + this.outputs = outputs; + return this; + } + + /** + * @return {number[]} tx output indices + */ + getOutputIndices() { + return this.outputIndices; + } + + /** + * @param {number[]} outputIndices - tx output indices + * @return {MoneroTx} this tx for chaining + */ + setOutputIndices(outputIndices) { + this.outputIndices = outputIndices; + return this; + } + + /** + * @return {string} tx metadata + */ + getMetadata() { + return this.metadata; + } + + /** + * @param {string} metadata - tx metadata + * @return {MoneroTx} this tx for chaining + */ + setMetadata(metadata) { + this.metadata = metadata; + return this; + } + + /** + * @return {Uint8Array} tx extra + */ + getExtra() { + return this.extra; + } + + /** + * @param {Uint8Array} extra - tx extra + * @return {MoneroTx} this tx for chaining + */ + setExtra(extra) { + this.extra = extra; + return this; + } + + /** + * @return {any} RCT signatures + */ + getRctSignatures() { + return this.rctSignatures; + } + + /** + * @param {any} rctSignatures - RCT signatures + * @return {MoneroTx} this tx for chaining + */ + setRctSignatures(rctSignatures) { + this.rctSignatures = rctSignatures; + return this; + } + + /** + * @return {any} prunable RCT signature data + */ + getRctSigPrunable() { + return this.rctSigPrunable; + } + + /** + * @param {any} rctSigPrunable - prunable RCT signature data + * @return {MoneroTx} this tx for chaining + */ + setRctSigPrunable(rctSigPrunable) { + this.rctSigPrunable = rctSigPrunable; + return this; + } + + /** + * @return {boolean} true if kept by a block, false otherwise + */ + getIsKeptByBlock() { + return this.isKeptByBlock; + } + + /** + * @param {boolean} isKeptByBlock - true if kept by a block, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsKeptByBlock(isKeptByBlock) { + this.isKeptByBlock = isKeptByBlock; + return this; + } + + /** + * @return {boolean} true if the tx failed, false otherwise + */ + getIsFailed() { + return this.isFailed; + } + + /** + * @param {boolean} isFailed - true if the tx failed, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsFailed(isFailed) { + this.isFailed = isFailed; + return this; + } + + /** + * @return {number} block height of the last tx failure + */ + getLastFailedHeight() { + return this.lastFailedHeight; + } + + /** + * @param {number} lastFailedHeight - block height of the last tx failure + * @return {MoneroTx} this tx for chaining + */ + setLastFailedHeight(lastFailedHeight) { + this.lastFailedHeight = lastFailedHeight; + return this; + } + + /** + * @return {string} block hash of the last tx failure + */ + getLastFailedHash() { + return this.lastFailedHash; + } + + /** + * @param {string} lastFailedHash - block hash of the last tx failure + * @return {MoneroTx} this tx for chaining + */ + setLastFailedHash(lastFailedHash) { + this.lastFailedHash = lastFailedHash; + return this; + } + + /** + * @return {number} max used block height + */ + getMaxUsedBlockHeight() { + return this.maxUsedBlockHeight; + } + + /** + * @param {number} maxUsedBlockHeight - max used block height + * @return {MoneroTx} this tx for chaining + */ + setMaxUsedBlockHeight(maxUsedBlockHeight) { + this.maxUsedBlockHeight = maxUsedBlockHeight; + return this; + } + + /** + * @return {string} max used block hash + */ + getMaxUsedBlockHash() { + return this.maxUsedBlockHash; + } + + /** + * @param {string} maxUsedBlockHash - max used block hash + * @return {MoneroTx} this tx for chaining + */ + setMaxUsedBlockHash(maxUsedBlockHash) { + this.maxUsedBlockHash = maxUsedBlockHash; + return this; + } + + /** + * @return {string[]} tx signatures + */ + getSignatures() { + return this.signatures; + } + + /** + * @param {string[]} signatures - tx signatures + * @return {MoneroTx} this tx for chaining + */ + setSignatures(signatures) { + this.signatures = signatures; + return this; + } + + /** + * @return {MoneroTx} a copy of this tx + */ + copy() { + return new MoneroTx(this); + } + + /** + * @return {any} json representation of this tx + */ + toJson() { + let json = Object.assign({}, this); + if (this.getFee() !== undefined) json.fee = this.getFee().toString(); + if (this.getUnlockTime() !== undefined) json.unlockTime = this.getUnlockTime().toString(); + if (this.getInputs()) { + json.inputs = []; + for (let input of this.getInputs()) json.inputs.push(input.toJson()); + } + if (this.getOutputs()) { + json.outputs = []; + for (let output of this.getOutputs()) json.outputs.push(output.toJson()); + } + if (this.getExtra() !== undefined) json.extra = Array.from(this.getExtra(), (byte) => byte); + delete json.block; // do not serialize parent block + return json; + } + + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * @param {MoneroTx} tx - the transaction to update this transaction with + * @return {MoneroTx} this for method chaining + */ + merge(tx) { + (0, _assert.default)(tx instanceof MoneroTx); + if (this === tx) return this; + + // merge blocks if they're different + if (this.getBlock() !== tx.getBlock()) { + if (this.getBlock() === undefined) { + this.setBlock(tx.getBlock()); + this.getBlock().getTxs[this.getBlock().getTxs().indexOf(tx)] = this; // update block to point to this tx + } else if (tx.getBlock() !== undefined) { + this.getBlock().merge(tx.getBlock()); // comes back to merging txs + return this; + } + } + + // otherwise merge tx fields + this.setHash(_GenUtils.default.reconcile(this.getHash(), tx.getHash())); + this.setVersion(_GenUtils.default.reconcile(this.getVersion(), tx.getVersion())); + this.setPaymentId(_GenUtils.default.reconcile(this.getPaymentId(), tx.getPaymentId())); + this.setFee(_GenUtils.default.reconcile(this.getFee(), tx.getFee())); + this.setRingSize(_GenUtils.default.reconcile(this.getRingSize(), tx.getRingSize())); + this.setIsConfirmed(_GenUtils.default.reconcile(this.getIsConfirmed(), tx.getIsConfirmed(), { resolveTrue: true })); // tx can become confirmed + this.setIsMinerTx(_GenUtils.default.reconcile(this.getIsMinerTx(), tx.getIsMinerTx())); + this.setRelay(_GenUtils.default.reconcile(this.getRelay(), tx.getRelay(), { resolveTrue: true })); // tx can become relayed + this.setIsRelayed(_GenUtils.default.reconcile(this.getIsRelayed(), tx.getIsRelayed(), { resolveTrue: true })); // tx can become relayed + this.setIsDoubleSpendSeen(_GenUtils.default.reconcile(this.getIsDoubleSpendSeen(), tx.getIsDoubleSpendSeen(), { resolveTrue: true })); // double spend can become seen + this.setKey(_GenUtils.default.reconcile(this.getKey(), tx.getKey())); + this.setFullHex(_GenUtils.default.reconcile(this.getFullHex(), tx.getFullHex())); + this.setPrunedHex(_GenUtils.default.reconcile(this.getPrunedHex(), tx.getPrunedHex())); + this.setPrunableHex(_GenUtils.default.reconcile(this.getPrunableHex(), tx.getPrunableHex())); + this.setPrunableHash(_GenUtils.default.reconcile(this.getPrunableHash(), tx.getPrunableHash())); + this.setSize(_GenUtils.default.reconcile(this.getSize(), tx.getSize())); + this.setWeight(_GenUtils.default.reconcile(this.getWeight(), tx.getWeight())); + this.setOutputIndices(_GenUtils.default.reconcile(this.getOutputIndices(), tx.getOutputIndices())); + this.setMetadata(_GenUtils.default.reconcile(this.getMetadata(), tx.getMetadata())); + this.setExtra(_GenUtils.default.reconcile(this.getExtra(), tx.getExtra())); + this.setRctSignatures(_GenUtils.default.reconcile(this.getRctSignatures(), tx.getRctSignatures())); + this.setRctSigPrunable(_GenUtils.default.reconcile(this.getRctSigPrunable(), tx.getRctSigPrunable())); + this.setIsKeptByBlock(_GenUtils.default.reconcile(this.getIsKeptByBlock(), tx.getIsKeptByBlock())); + this.setIsFailed(_GenUtils.default.reconcile(this.getIsFailed(), tx.getIsFailed(), { resolveTrue: true })); + this.setLastFailedHeight(_GenUtils.default.reconcile(this.getLastFailedHeight(), tx.getLastFailedHeight())); + this.setLastFailedHash(_GenUtils.default.reconcile(this.getLastFailedHash(), tx.getLastFailedHash())); + this.setMaxUsedBlockHeight(_GenUtils.default.reconcile(this.getMaxUsedBlockHeight(), tx.getMaxUsedBlockHeight())); + this.setMaxUsedBlockHash(_GenUtils.default.reconcile(this.getMaxUsedBlockHash(), tx.getMaxUsedBlockHash())); + this.setSignatures(_GenUtils.default.reconcile(this.getSignatures(), tx.getSignatures())); + this.setUnlockTime(_GenUtils.default.reconcile(this.getUnlockTime(), tx.getUnlockTime())); + this.setNumConfirmations(_GenUtils.default.reconcile(this.getNumConfirmations(), tx.getNumConfirmations(), { resolveMax: true })); // num confirmations can increase + + // merge inputs + if (tx.getInputs()) { + for (let merger of tx.getInputs()) { + let merged = false; + merger.setTx(this); + if (!this.getInputs()) this.setInputs([]); + for (let mergee of this.getInputs()) { + if (mergee.getKeyImage().getHex() === merger.getKeyImage().getHex()) { + mergee.merge(merger); + merged = true; + break; + } + } + if (!merged) this.getInputs().push(merger); + } + } + + // merge outputs + if (tx.getOutputs()) { + for (let output of tx.getOutputs()) output.setTx(this); + if (!this.getOutputs()) this.setOutputs(tx.getOutputs());else + { + + // merge outputs if key image or stealth public key present, otherwise append + for (let merger of tx.getOutputs()) { + let merged = false; + merger.setTx(this); + for (let mergee of this.getOutputs()) { + if (merger.getKeyImage() && mergee.getKeyImage().getHex() === merger.getKeyImage().getHex() || + merger.getStealthPublicKey() && mergee.getStealthPublicKey() === merger.getStealthPublicKey()) { + mergee.merge(merger); + merged = true; + break; + } + } + if (!merged) this.getOutputs().push(merger); // append output + } + } + } + + // handle unrelayed -> relayed -> confirmed + if (this.getIsConfirmed()) { + this.setInTxPool(false); + this.setReceivedTimestamp(undefined); + this.setLastRelayedTimestamp(undefined); + } else { + this.setInTxPool(_GenUtils.default.reconcile(this.getInTxPool(), tx.getInTxPool(), { resolveTrue: true })); // unrelayed -> tx pool + this.setReceivedTimestamp(_GenUtils.default.reconcile(this.getReceivedTimestamp(), tx.getReceivedTimestamp(), { resolveMax: false })); // take earliest receive time + this.setLastRelayedTimestamp(_GenUtils.default.reconcile(this.getLastRelayedTimestamp(), tx.getLastRelayedTimestamp(), { resolveMax: true })); // take latest relay time + } + + return this; // for chaining + } + + /** + * @param {number} [indent] - starting indentation + * @return {string} string representation of this tx + */ + toString(indent = 0) { + let str = ""; + str += _GenUtils.default.getIndent(indent) + "=== TX ===\n"; + str += _GenUtils.default.kvLine("Tx hash", this.getHash(), indent); + str += _GenUtils.default.kvLine("Height", this.getHeight(), indent); + str += _GenUtils.default.kvLine("Version", this.getVersion(), indent); + str += _GenUtils.default.kvLine("Is miner tx", this.getIsMinerTx(), indent); + str += _GenUtils.default.kvLine("Payment ID", this.getPaymentId(), indent); + str += _GenUtils.default.kvLine("Fee", this.getFee(), indent); + str += _GenUtils.default.kvLine("Ring size", this.getRingSize(), indent); + str += _GenUtils.default.kvLine("Relay", this.getRelay(), indent); + str += _GenUtils.default.kvLine("Is relayed", this.getIsRelayed(), indent); + str += _GenUtils.default.kvLine("Is confirmed", this.getIsConfirmed(), indent); + str += _GenUtils.default.kvLine("In tx pool", this.getInTxPool(), indent); + str += _GenUtils.default.kvLine("Num confirmations", this.getNumConfirmations(), indent); + str += _GenUtils.default.kvLine("Unlock time", this.getUnlockTime(), indent); + str += _GenUtils.default.kvLine("Last relayed time", this.getLastRelayedTimestamp(), indent); + str += _GenUtils.default.kvLine("Received time", this.getReceivedTimestamp(), indent); + str += _GenUtils.default.kvLine("Is double spend", this.getIsDoubleSpendSeen(), indent); + str += _GenUtils.default.kvLine("Key", this.getKey(), indent); + str += _GenUtils.default.kvLine("Full hex", this.getFullHex(), indent); + str += _GenUtils.default.kvLine("Pruned hex", this.getPrunedHex(), indent); + str += _GenUtils.default.kvLine("Prunable hex", this.getPrunableHex(), indent); + str += _GenUtils.default.kvLine("Prunable hash", this.getPrunableHash(), indent); + str += _GenUtils.default.kvLine("Size", this.getSize(), indent); + str += _GenUtils.default.kvLine("Weight", this.getWeight(), indent); + str += _GenUtils.default.kvLine("Output indices", this.getOutputIndices(), indent); + str += _GenUtils.default.kvLine("Metadata", this.getMetadata(), indent); + str += _GenUtils.default.kvLine("Extra", this.getExtra(), indent); + str += _GenUtils.default.kvLine("RCT signatures", this.getRctSignatures(), indent); + str += _GenUtils.default.kvLine("RCT sig prunable", this.getRctSigPrunable(), indent); + str += _GenUtils.default.kvLine("Kept by block", this.getIsKeptByBlock(), indent); + str += _GenUtils.default.kvLine("Is failed", this.getIsFailed(), indent); + str += _GenUtils.default.kvLine("Last failed height", this.getLastFailedHeight(), indent); + str += _GenUtils.default.kvLine("Last failed hash", this.getLastFailedHash(), indent); + str += _GenUtils.default.kvLine("Max used block height", this.getMaxUsedBlockHeight(), indent); + str += _GenUtils.default.kvLine("Max used block hash", this.getMaxUsedBlockHash(), indent); + str += _GenUtils.default.kvLine("Signatures", this.getSignatures(), indent); + if (this.getInputs() !== undefined) { + str += _GenUtils.default.kvLine("Inputs", "", indent); + for (let i = 0; i < this.getInputs().length; i++) { + str += _GenUtils.default.kvLine(i + 1, "", indent + 1); + str += this.getInputs()[i].toString(indent + 2); + str += '\n'; + } + } + if (this.getOutputs() !== undefined) { + str += _GenUtils.default.kvLine("Outputs", "", indent); + for (let i = 0; i < this.getOutputs().length; i++) { + str += _GenUtils.default.kvLine(i + 1, "", indent + 1); + str += this.getOutputs()[i].toString(indent + 2); + str += '\n'; + } + } + return str.slice(0, str.length - 1); // strip last newline + } +}exports.default = MoneroTx; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTW9uZXJvT3V0cHV0IiwiTW9uZXJvVHgiLCJERUZBVUxUX1BBWU1FTlRfSUQiLCJjb25zdHJ1Y3RvciIsInR4IiwiT2JqZWN0IiwiYXNzaWduIiwiYmxvY2siLCJ1bmRlZmluZWQiLCJleHRyYSIsIlVpbnQ4QXJyYXkiLCJmZWUiLCJCaWdJbnQiLCJ1bmxvY2tUaW1lIiwiaW5wdXRzIiwic2xpY2UiLCJpIiwibGVuZ3RoIiwiTW9uZXJvT3V0cHV0Iiwic2V0VHgiLCJvdXRwdXRzIiwiZ2V0QmxvY2siLCJzZXRCbG9jayIsImdldEhlaWdodCIsImdldEhhc2giLCJoYXNoIiwic2V0SGFzaCIsImdldFZlcnNpb24iLCJ2ZXJzaW9uIiwic2V0VmVyc2lvbiIsImdldElzTWluZXJUeCIsImlzTWluZXJUeCIsInNldElzTWluZXJUeCIsIm1pbmVyIiwiZ2V0UGF5bWVudElkIiwicGF5bWVudElkIiwic2V0UGF5bWVudElkIiwiZ2V0RmVlIiwic2V0RmVlIiwiZ2V0UmluZ1NpemUiLCJyaW5nU2l6ZSIsInNldFJpbmdTaXplIiwiZ2V0UmVsYXkiLCJyZWxheSIsInNldFJlbGF5IiwiZ2V0SXNSZWxheWVkIiwiaXNSZWxheWVkIiwic2V0SXNSZWxheWVkIiwiZ2V0SXNDb25maXJtZWQiLCJpc0NvbmZpcm1lZCIsInNldElzQ29uZmlybWVkIiwiZ2V0SW5UeFBvb2wiLCJpblR4UG9vbCIsInNldEluVHhQb29sIiwiZ2V0TnVtQ29uZmlybWF0aW9ucyIsIm51bUNvbmZpcm1hdGlvbnMiLCJzZXROdW1Db25maXJtYXRpb25zIiwiZ2V0VW5sb2NrVGltZSIsInNldFVubG9ja1RpbWUiLCJnZXRMYXN0UmVsYXllZFRpbWVzdGFtcCIsImxhc3RSZWxheWVkVGltZXN0YW1wIiwic2V0TGFzdFJlbGF5ZWRUaW1lc3RhbXAiLCJnZXRSZWNlaXZlZFRpbWVzdGFtcCIsInJlY2VpdmVkVGltZXN0YW1wIiwic2V0UmVjZWl2ZWRUaW1lc3RhbXAiLCJnZXRJc0RvdWJsZVNwZW5kU2VlbiIsImlzRG91YmxlU3BlbmRTZWVuIiwic2V0SXNEb3VibGVTcGVuZFNlZW4iLCJnZXRLZXkiLCJrZXkiLCJzZXRLZXkiLCJnZXRGdWxsSGV4IiwiZnVsbEhleCIsInNldEZ1bGxIZXgiLCJnZXRQcnVuZWRIZXgiLCJwcnVuZWRIZXgiLCJzZXRQcnVuZWRIZXgiLCJnZXRQcnVuYWJsZUhleCIsInBydW5hYmxlSGV4Iiwic2V0UHJ1bmFibGVIZXgiLCJnZXRQcnVuYWJsZUhhc2giLCJwcnVuYWJsZUhhc2giLCJzZXRQcnVuYWJsZUhhc2giLCJnZXRTaXplIiwic2l6ZSIsInNldFNpemUiLCJnZXRXZWlnaHQiLCJ3ZWlnaHQiLCJzZXRXZWlnaHQiLCJnZXRJbnB1dHMiLCJzZXRJbnB1dHMiLCJnZXRPdXRwdXRzIiwic2V0T3V0cHV0cyIsImdldE91dHB1dEluZGljZXMiLCJvdXRwdXRJbmRpY2VzIiwic2V0T3V0cHV0SW5kaWNlcyIsImdldE1ldGFkYXRhIiwibWV0YWRhdGEiLCJzZXRNZXRhZGF0YSIsImdldEV4dHJhIiwic2V0RXh0cmEiLCJnZXRSY3RTaWduYXR1cmVzIiwicmN0U2lnbmF0dXJlcyIsInNldFJjdFNpZ25hdHVyZXMiLCJnZXRSY3RTaWdQcnVuYWJsZSIsInJjdFNpZ1BydW5hYmxlIiwic2V0UmN0U2lnUHJ1bmFibGUiLCJnZXRJc0tlcHRCeUJsb2NrIiwiaXNLZXB0QnlCbG9jayIsInNldElzS2VwdEJ5QmxvY2siLCJnZXRJc0ZhaWxlZCIsImlzRmFpbGVkIiwic2V0SXNGYWlsZWQiLCJnZXRMYXN0RmFpbGVkSGVpZ2h0IiwibGFzdEZhaWxlZEhlaWdodCIsInNldExhc3RGYWlsZWRIZWlnaHQiLCJnZXRMYXN0RmFpbGVkSGFzaCIsImxhc3RGYWlsZWRIYXNoIiwic2V0TGFzdEZhaWxlZEhhc2giLCJnZXRNYXhVc2VkQmxvY2tIZWlnaHQiLCJtYXhVc2VkQmxvY2tIZWlnaHQiLCJzZXRNYXhVc2VkQmxvY2tIZWlnaHQiLCJnZXRNYXhVc2VkQmxvY2tIYXNoIiwibWF4VXNlZEJsb2NrSGFzaCIsInNldE1heFVzZWRCbG9ja0hhc2giLCJnZXRTaWduYXR1cmVzIiwic2lnbmF0dXJlcyIsInNldFNpZ25hdHVyZXMiLCJjb3B5IiwidG9Kc29uIiwianNvbiIsInRvU3RyaW5nIiwiaW5wdXQiLCJwdXNoIiwib3V0cHV0IiwiQXJyYXkiLCJmcm9tIiwiYnl0ZSIsIm1lcmdlIiwiYXNzZXJ0IiwiZ2V0VHhzIiwiaW5kZXhPZiIsIkdlblV0aWxzIiwicmVjb25jaWxlIiwicmVzb2x2ZVRydWUiLCJyZXNvbHZlTWF4IiwibWVyZ2VyIiwibWVyZ2VkIiwibWVyZ2VlIiwiZ2V0S2V5SW1hZ2UiLCJnZXRIZXgiLCJnZXRTdGVhbHRoUHVibGljS2V5IiwiaW5kZW50Iiwic3RyIiwiZ2V0SW5kZW50Iiwia3ZMaW5lIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9kYWVtb24vbW9kZWwvTW9uZXJvVHgudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgR2VuVXRpbHMgZnJvbSBcIi4uLy4uL2NvbW1vbi9HZW5VdGlsc1wiO1xuaW1wb3J0IE1vbmVyb0Jsb2NrIGZyb20gXCIuL01vbmVyb0Jsb2NrXCI7XG5pbXBvcnQgTW9uZXJvT3V0cHV0IGZyb20gXCIuL01vbmVyb091dHB1dFwiO1xuXG4vKipcbiAqIFJlcHJlc2VudHMgYSB0cmFuc2FjdGlvbiBvbiB0aGUgTW9uZXJvIG5ldHdvcmsuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb1R4IHtcblxuICBzdGF0aWMgcmVhZG9ubHkgREVGQVVMVF9QQVlNRU5UX0lEID0gXCIwMDAwMDAwMDAwMDAwMDAwXCI7XG5cbiAgYmxvY2s6IE1vbmVyb0Jsb2NrO1xuICBoYXNoOiBzdHJpbmc7XG4gIHZlcnNpb246IG51bWJlcjtcbiAgaXNNaW5lclR4OiBib29sZWFuO1xuICBwYXltZW50SWQ6IHN0cmluZztcbiAgZmVlOiBiaWdpbnQ7XG4gIHJpbmdTaXplOiBudW1iZXI7XG4gIHJlbGF5OiBib29sZWFuO1xuICBpc1JlbGF5ZWQ6IGJvb2xlYW47XG4gIGlzQ29uZmlybWVkOiBib29sZWFuO1xuICBpblR4UG9vbDogYm9vbGVhbjtcbiAgbnVtQ29uZmlybWF0aW9uczogbnVtYmVyO1xuICB1bmxvY2tUaW1lOiBiaWdpbnQ7XG4gIGxhc3RSZWxheWVkVGltZXN0YW1wOiBudW1iZXI7XG4gIHJlY2VpdmVkVGltZXN0YW1wOiBudW1iZXI7XG4gIGlzRG91YmxlU3BlbmRTZWVuOiBib29sZWFuO1xuICBrZXk6IHN0cmluZztcbiAgZnVsbEhleDogc3RyaW5nO1xuICBwcnVuZWRIZXg6IHN0cmluZztcbiAgcHJ1bmFibGVIZXg6IHN0cmluZztcbiAgcHJ1bmFibGVIYXNoOiBzdHJpbmc7XG4gIHNpemU6IG51bWJlcjtcbiAgd2VpZ2h0OiBudW1iZXI7XG4gIGlucHV0czogTW9uZXJvT3V0cHV0W107XG4gIG91dHB1dHM6IE1vbmVyb091dHB1dFtdO1xuICBvdXRwdXRJbmRpY2VzOiBudW1iZXJbXTtcbiAgbWV0YWRhdGE6IHN0cmluZztcbiAgZXh0cmE6IFVpbnQ4QXJyYXk7XG4gIHJjdFNpZ25hdHVyZXM6IGFueTtcbiAgcmN0U2lnUHJ1bmFibGU6IGFueTtcbiAgaXNLZXB0QnlCbG9jazogYm9vbGVhbjtcbiAgaXNGYWlsZWQ6IGJvb2xlYW47XG4gIGxhc3RGYWlsZWRIZWlnaHQ6IG51bWJlcjtcbiAgbGFzdEZhaWxlZEhhc2g6IHN0cmluZztcbiAgbWF4VXNlZEJsb2NrSGVpZ2h0OiBudW1iZXI7XG4gIG1heFVzZWRCbG9ja0hhc2g6IHN0cmluZztcbiAgc2lnbmF0dXJlczogc3RyaW5nW107XG4gIFxuICBjb25zdHJ1Y3Rvcih0eD86IFBhcnRpYWw8TW9uZXJvVHg+KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCB0eCk7XG4gICAgdGhpcy5ibG9jayA9IHVuZGVmaW5lZDtcblxuICAgIC8vIGRlc2VyaWFsaXplIGV4dHJhXG4gICAgaWYgKHRoaXMuZXh0cmEgIT09IHVuZGVmaW5lZCkgdGhpcy5leHRyYSA9IG5ldyBVaW50OEFycmF5KHRoaXMuZXh0cmEpO1xuICAgIFxuICAgIC8vIGRlc2VyaWFsaXplIGJpZ2ludHNcbiAgICBpZiAodGhpcy5mZWUgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5mZWUgIT09IFwiYmlnaW50XCIpIHRoaXMuZmVlID0gQmlnSW50KHRoaXMuZmVlKTtcbiAgICBpZiAodGhpcy51bmxvY2tUaW1lICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHRoaXMudW5sb2NrVGltZSAhPT0gXCJiaWdpbnRcIikgdGhpcy51bmxvY2tUaW1lID0gQmlnSW50KHRoaXMudW5sb2NrVGltZSk7XG4gICAgXG4gICAgLy8gY29weSBpbnB1dHNcbiAgICBpZiAodGhpcy5pbnB1dHMpIHtcbiAgICAgIHRoaXMuaW5wdXRzID0gdGhpcy5pbnB1dHMuc2xpY2UoKTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5pbnB1dHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdGhpcy5pbnB1dHNbaV0gPSBuZXcgTW9uZXJvT3V0cHV0KHRoaXMuaW5wdXRzW2ldKS5zZXRUeCh0aGlzKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gY29weSBvdXRwdXRzXG4gICAgaWYgKHRoaXMub3V0cHV0cykge1xuICAgICAgdGhpcy5vdXRwdXRzID0gdGhpcy5vdXRwdXRzLnNsaWNlKCk7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMub3V0cHV0cy5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzLm91dHB1dHNbaV0gPSBuZXcgTW9uZXJvT3V0cHV0KHRoaXMub3V0cHV0c1tpXSkuc2V0VHgodGhpcyk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7TW9uZXJvQmxvY2t9IHR4IGJsb2NrXG4gICAqL1xuICBnZXRCbG9jaygpOiBNb25lcm9CbG9jayB7XG4gICAgcmV0dXJuIHRoaXMuYmxvY2s7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge01vbmVyb0Jsb2NrfSBibG9jayAtIHR4IGJsb2NrXG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0QmxvY2soYmxvY2s6IE1vbmVyb0Jsb2NrKTogTW9uZXJvVHgge1xuICAgIHRoaXMuYmxvY2sgPSBibG9jaztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEByZXR1cm4ge251bWJlcn0gdHggaGVpZ2h0XG4gICAqL1xuICBnZXRIZWlnaHQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5nZXRCbG9jaygpID09PSB1bmRlZmluZWQgPyB1bmRlZmluZWQgOiB0aGlzLmdldEJsb2NrKCkuZ2V0SGVpZ2h0KCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IHR4IGhhc2hcbiAgICovXG4gIGdldEhhc2goKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5oYXNoO1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IGhhc2ggLSB0eCBoYXNoXG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0SGFzaChoYXNoOiBzdHJpbmcpOiBNb25lcm9UeCB7XG4gICAgdGhpcy5oYXNoID0gaGFzaDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEByZXR1cm4ge251bWJlcn0gdHggdmVyc2lvblxuICAgKi9cbiAgZ2V0VmVyc2lvbigpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnZlcnNpb247XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlcn0gdmVyc2lvbiAtIHR4IHZlcnNpb25cbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRWZXJzaW9uKHZlcnNpb246IG51bWJlcik6IE1vbmVyb1R4IHtcbiAgICB0aGlzLnZlcnNpb24gPSB2ZXJzaW9uO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gdHJ1ZSBpZiB0aGUgdHggaXMgYSBtaW5lciB0eCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBnZXRJc01pbmVyVHgoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNNaW5lclR4O1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtib29sZWFufSBtaW5lciAtIHRydWUgaWYgdGhlIHR4IGlzIGEgbWluZXIgdHgsIGZhbHNlIG90aGVyd2lzZVxuICAgKiBAcmV0dXJuIHtNb25lcm9UeH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldElzTWluZXJUeChtaW5lcjogYm9vbGVhbik6IE1vbmVyb1R4IHtcbiAgICB0aGlzLmlzTWluZXJUeCA9IG1pbmVyO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7c3RyaW5nfSB0eCBwYXltZW50IGlkXG4gICAqL1xuICBnZXRQYXltZW50SWQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5wYXltZW50SWQ7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGF5bWVudElkIC0gdHggcGF5bWVudCBpZFxuICAgKiBAcmV0dXJuIHtNb25lcm9UeH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldFBheW1lbnRJZChwYXltZW50SWQ6IHN0cmluZyk6IE1vbmVyb1R4IHtcbiAgICB0aGlzLnBheW1lbnRJZCA9IHBheW1lbnRJZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEByZXR1cm4ge2JpZ2ludH0gdHggZmVlXG4gICAqL1xuICBnZXRGZWUoKTogYmlnaW50IHtcbiAgICByZXR1cm4gdGhpcy5mZWU7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge2JpZ2ludH0gZmVlIC0gdHggZmVlXG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0RmVlKGZlZTogYmlnaW50KTogTW9uZXJvVHgge1xuICAgIHRoaXMuZmVlID0gZmVlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7bnVtYmVyfSB0eCByaW5nIHNpemVcbiAgICovXG4gIGdldFJpbmdTaXplKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMucmluZ1NpemU7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlcn0gcmluZ1NpemUgLSB0eCByaW5nIHNpemVcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRSaW5nU2l6ZShyaW5nU2l6ZTogbnVtYmVyKTogTW9uZXJvVHgge1xuICAgIHRoaXMucmluZ1NpemUgPSByaW5nU2l6ZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgdGhlIHR4IGlzIHNldCB0byBiZSByZWxheWVkLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIGdldFJlbGF5KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnJlbGF5O1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtib29sZWFufSByZWxheSAtIHRydWUgaWYgdGhlIHR4IGlzIHNldCB0byBiZSByZWxheWVkLCBmYWxzZSBvdGhlcndpc2VcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRSZWxheShyZWxheTogYm9vbGVhbik6IE1vbmVyb1R4IHtcbiAgICB0aGlzLnJlbGF5ID0gcmVsYXk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHRoZSB0eCBpcyByZWxheWVkLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIGdldElzUmVsYXllZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc1JlbGF5ZWQ7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGlzUmVsYXllZCAtIHRydWUgaWYgdGhlIHR4IGlzIHJlbGF5ZWQsIGZhbHNlIG90aGVyd2lzZVxuICAgKiBAcmV0dXJuIHtNb25lcm9UeH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldElzUmVsYXllZChpc1JlbGF5ZWQ6IGJvb2xlYW4pOiBNb25lcm9UeCB7XG4gICAgdGhpcy5pc1JlbGF5ZWQgPSBpc1JlbGF5ZWQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHRoZSB0eCBpcyBjb25maXJtZWQsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgZ2V0SXNDb25maXJtZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNDb25maXJtZWQ7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGlzQ29uZmlybWVkIC0gdHJ1ZSBpZiB0aGUgdHggaXMgY29uZmlybWVkLCBmYWxzZSBvdGhlcndpc2VcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRJc0NvbmZpcm1lZChpc0NvbmZpcm1lZDogYm9vbGVhbik6IE1vbmVyb1R4IHtcbiAgICB0aGlzLmlzQ29uZmlybWVkID0gaXNDb25maXJtZWQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHRoZSB0eCBpcyBpbiB0aGUgbWVtb3J5IHBvb2wsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgZ2V0SW5UeFBvb2woKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaW5UeFBvb2w7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGluVHhQb29sIC0gdHJ1ZSBpZiB0aGUgdHggaXMgaW4gdGhlIG1lbW9yeSBwb29sLCBmYWxzZSBvdGhlcndpc2VcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRJblR4UG9vbChpblR4UG9vbDogYm9vbGVhbik6IE1vbmVyb1R4IHtcbiAgICB0aGlzLmluVHhQb29sID0gaW5UeFBvb2w7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtudW1iZXJ9IG51bWJlciBvZiBibG9jayBjb25maXJtYXRpb25zXG4gICAqL1xuICBnZXROdW1Db25maXJtYXRpb25zKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtQ29uZmlybWF0aW9ucztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBudW1Db25maXJtYXRpb25zIC0gbnVtYmVyIG9mIGJsb2NrIGNvbmZpcm1hdGlvbnNcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXROdW1Db25maXJtYXRpb25zKG51bUNvbmZpcm1hdGlvbnM6IG51bWJlcik6IE1vbmVyb1R4IHtcbiAgICB0aGlzLm51bUNvbmZpcm1hdGlvbnMgPSBudW1Db25maXJtYXRpb25zO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSBtaW5pbXVtIGhlaWdodCBvciB0aW1lc3RhbXAgZm9yIHRoZSB0cmFuc2FjdGlvbnMgdG8gdW5sb2NrLlxuICAgKiBcbiAgICogQHJldHVybiB7YmlnaW50fSB0aGUgbWluaW11bSBoZWlnaHQgb3IgdGltZXN0YW1wIGZvciB0aGUgdHJhbnNhY3Rpb24gdG8gdW5sb2NrXG4gICAqL1xuICBnZXRVbmxvY2tUaW1lKCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMudW5sb2NrVGltZTtcbiAgfVxuICBcbiAgc2V0VW5sb2NrVGltZSh1bmxvY2tUaW1lOiBiaWdpbnQgfCBzdHJpbmcgfCBudW1iZXIgfCB1bmRlZmluZWQpOiBNb25lcm9UeCB7XG4gICAgaWYgKHVubG9ja1RpbWUgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdW5sb2NrVGltZSAhPT0gXCJiaWdpbnRcIikgdW5sb2NrVGltZSA9IEJpZ0ludCh1bmxvY2tUaW1lKTtcbiAgICB0aGlzLnVubG9ja1RpbWUgPSB1bmxvY2tUaW1lIGFzIGJpZ2ludCB8IHVuZGVmaW5lZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEByZXR1cm4ge251bWJlcn0gdGltZXN0YW1wIHRoZSB0eCB3YXMgbGFzdCByZWxheWVkIGZyb20gdGhlIG5vZGVcbiAgICovXG4gIGdldExhc3RSZWxheWVkVGltZXN0YW1wKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubGFzdFJlbGF5ZWRUaW1lc3RhbXA7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlcn0gbGFzdFJlbGF5ZWRUaW1lc3RhbXAgLSB0aW1lc3RhbXAgdGhlIHR4IHdhcyBsYXN0IHJlbGF5ZWQgZnJvbSB0aGUgbm9kZVxuICAgKiBAcmV0dXJuIHtNb25lcm9UeH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldExhc3RSZWxheWVkVGltZXN0YW1wKGxhc3RSZWxheWVkVGltZXN0YW1wOiBudW1iZXIpOiBNb25lcm9UeCB7XG4gICAgdGhpcy5sYXN0UmVsYXllZFRpbWVzdGFtcCA9IGxhc3RSZWxheWVkVGltZXN0YW1wO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7bnVtYmVyfSB0aW1lc3RhbXAgdGhlIHR4IHdhcyByZWNlaXZlZCBhdCB0aGUgbm9kZVxuICAgKi9cbiAgZ2V0UmVjZWl2ZWRUaW1lc3RhbXAoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5yZWNlaXZlZFRpbWVzdGFtcDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBwYXJhbSB7bnVtYmVyfSByZWNlaXZlZFRpbWVzdGFtcCAtIHRpbWVzdGFtcCB0aGUgdHggd2FzIHJlY2VpdmVkIGF0IHRoZSBub2RlXG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0UmVjZWl2ZWRUaW1lc3RhbXAocmVjZWl2ZWRUaW1lc3RhbXA6IG51bWJlcik6IE1vbmVyb1R4IHtcbiAgICB0aGlzLnJlY2VpdmVkVGltZXN0YW1wID0gcmVjZWl2ZWRUaW1lc3RhbXA7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIGEgZG91YmxlIHNwZW5kIGhhcyBiZWVuIHNlZW4sIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgZ2V0SXNEb3VibGVTcGVuZFNlZW4oKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNEb3VibGVTcGVuZFNlZW47XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGlzRG91YmxlU3BlbmRTZWVuIC0gdHJ1ZSBpZiBhIGRvdWJsZSBzcGVuZCBoYXMgYmVlbiBzZWVuLCBmYWxzZSBvdGhlcndpc2VcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRJc0RvdWJsZVNwZW5kU2Vlbihpc0RvdWJsZVNwZW5kU2VlbjogYm9vbGVhbiApOiBNb25lcm9UeCB7XG4gICAgdGhpcy5pc0RvdWJsZVNwZW5kU2VlbiA9IGlzRG91YmxlU3BlbmRTZWVuO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7c3RyaW5nfSB0eCBrZXlcbiAgICovXG4gIGdldEtleSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmtleTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgLSB0eCBrZXlcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRLZXkoa2V5OiBzdHJpbmcpOiBNb25lcm9UeCB7XG4gICAgdGhpcy5rZXkgPSBrZXk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgZnVsbCB0cmFuc2FjdGlvbiBoZXguIEZ1bGwgaGV4ID0gcHJ1bmVkIGhleCArIHBydW5hYmxlIGhleC5cbiAgICogXG4gICAqIEByZXR1cm4ge3N0cmluZ3x1bmRlZmluZWR9IGZ1bGwgdHggaGV4XG4gICAqL1xuICBnZXRGdWxsSGV4KCk6IHN0cmluZ3x1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmZ1bGxIZXg7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZnVsbEhleCAtIGZ1bGwgdHggaGV4XG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0RnVsbEhleChmdWxsSGV4OiBzdHJpbmcpOiBNb25lcm9UeCB7XG4gICAgdGhpcy5mdWxsSGV4ID0gZnVsbEhleDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBwcnVuZWQgdHJhbnNhY3Rpb24gaGV4LiBGdWxsIGhleCA9IHBydW5lZCBoZXggKyBwcnVuYWJsZSBoZXguXG4gICAqIFxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IHBydW5lZCB0eCBoZXhcbiAgICovXG4gIGdldFBydW5lZEhleCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnBydW5lZEhleDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwcnVuZWRIZXggLSBwcnVuZWQgdHggaGV4XG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0UHJ1bmVkSGV4KHBydW5lZEhleDogc3RyaW5nKTogTW9uZXJvVHgge1xuICAgIHRoaXMucHJ1bmVkSGV4ID0gcHJ1bmVkSGV4O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHBydW5hYmxlIHRyYW5zYWN0aW9uIGhleCB3aGljaCBpcyBoZXggdGhhdCBpcyByZW1vdmVkIGZyb20gYSBwcnVuZWRcbiAgICogdHJhbnNhY3Rpb24uIEZ1bGwgaGV4ID0gcHJ1bmVkIGhleCArIHBydW5hYmxlIGhleC5cbiAgICogXG4gICAqIEByZXR1cm4ge3N0cmluZ30gcHJ1bmFibGUgdHggaGV4XG4gICAqL1xuICBnZXRQcnVuYWJsZUhleCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnBydW5hYmxlSGV4O1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBydW5hYmxlSGV4IC0gcHJ1bmFibGUgdHggaGV4XG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0UHJ1bmFibGVIZXgocHJ1bmFibGVIZXg6IHN0cmluZyk6IE1vbmVyb1R4IHtcbiAgICB0aGlzLnBydW5hYmxlSGV4ID0gcHJ1bmFibGVIZXg7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IHBydW5hYmxlIHR4IGhhc2hcbiAgICovXG4gIGdldFBydW5hYmxlSGFzaCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnBydW5hYmxlSGFzaDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwcnVuYWJsZUhhc2ggLSBwcnVuYWJsZSB0eCBoYXNoXG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0UHJ1bmFibGVIYXNoKHBydW5hYmxlSGFzaDogc3RyaW5nKTogTW9uZXJvVHgge1xuICAgIHRoaXMucHJ1bmFibGVIYXNoID0gcHJ1bmFibGVIYXNoO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7bnVtYmVyfSB0eCBzaXplXG4gICAqL1xuICBnZXRTaXplKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuc2l6ZTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzaXplIC0gdHggc2l6ZVxuICAgKiBAcmV0dXJuIHtNb25lcm9UeH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldFNpemUoc2l6ZTogbnVtYmVyKTogTW9uZXJvVHgge1xuICAgIHRoaXMuc2l6ZSA9IHNpemU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtudW1iZXJ9IHR4IHdlaWdodFxuICAgKi9cbiAgZ2V0V2VpZ2h0KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMud2VpZ2h0O1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtudW1iZXJ9IHdlaWdodCAtIHR4IHdlaWdodFxuICAgKiBAcmV0dXJuIHtNb25lcm9UeH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldFdlaWdodCh3ZWlnaHQ6IG51bWJlcik6IE1vbmVyb1R4IHtcbiAgICB0aGlzLndlaWdodCA9IHdlaWdodDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEByZXR1cm4ge01vbmVyb091dHB1dFtdfSB0eCBpbnB1dHNcbiAgICovXG4gIGdldElucHV0cygpOiBNb25lcm9PdXRwdXRbXSB7XG4gICAgcmV0dXJuIHRoaXMuaW5wdXRzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtNb25lcm9PdXRwdXRbXX0gLSB0eCBpbnB1dHNcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRJbnB1dHMoaW5wdXRzOiBNb25lcm9PdXRwdXRbXSk6IE1vbmVyb1R4IHtcbiAgICB0aGlzLmlucHV0cyA9IGlucHV0cztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEByZXR1cm4ge01vbmVyb091dHB1dFtdfSB0eCBvdXRwdXRzXG4gICAqL1xuICBnZXRPdXRwdXRzKCk6IE1vbmVyb091dHB1dFtdIHtcbiAgICByZXR1cm4gdGhpcy5vdXRwdXRzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtNb25lcm9PdXRwdXRbXX0gb3V0cHV0cyAtIHR4IG91dHB1dHNcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRPdXRwdXRzKG91dHB1dHM6IE1vbmVyb091dHB1dFtdKTogTW9uZXJvVHgge1xuICAgIHRoaXMub3V0cHV0cyA9IG91dHB1dHM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtudW1iZXJbXX0gdHggb3V0cHV0IGluZGljZXNcbiAgICovXG4gIGdldE91dHB1dEluZGljZXMoKTogbnVtYmVyW10ge1xuICAgIHJldHVybiB0aGlzLm91dHB1dEluZGljZXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlcltdfSBvdXRwdXRJbmRpY2VzIC0gdHggb3V0cHV0IGluZGljZXNcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRPdXRwdXRJbmRpY2VzKG91dHB1dEluZGljZXM6IG51bWJlcltdKTogTW9uZXJvVHgge1xuICAgIHRoaXMub3V0cHV0SW5kaWNlcyA9IG91dHB1dEluZGljZXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IHR4IG1ldGFkYXRhXG4gICAqL1xuICBnZXRNZXRhZGF0YSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLm1ldGFkYXRhO1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1ldGFkYXRhIC0gdHggbWV0YWRhdGFcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRNZXRhZGF0YShtZXRhZGF0YTogc3RyaW5nKTogTW9uZXJvVHgge1xuICAgIHRoaXMubWV0YWRhdGEgPSBtZXRhZGF0YTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEByZXR1cm4ge1VpbnQ4QXJyYXl9IHR4IGV4dHJhXG4gICAqL1xuICBnZXRFeHRyYSgpOiBVaW50OEFycmF5IHtcbiAgICByZXR1cm4gdGhpcy5leHRyYTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBwYXJhbSB7VWludDhBcnJheX0gZXh0cmEgLSB0eCBleHRyYVxuICAgKiBAcmV0dXJuIHtNb25lcm9UeH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldEV4dHJhKGV4dHJhOiBVaW50OEFycmF5KTogTW9uZXJvVHgge1xuICAgIHRoaXMuZXh0cmEgPSBleHRyYTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJuIHthbnl9IFJDVCBzaWduYXR1cmVzXG4gICAqL1xuICBnZXRSY3RTaWduYXR1cmVzKCk6IGFueSB7XG4gICAgcmV0dXJuIHRoaXMucmN0U2lnbmF0dXJlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge2FueX0gcmN0U2lnbmF0dXJlcyAtIFJDVCBzaWduYXR1cmVzXG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0UmN0U2lnbmF0dXJlcyhyY3RTaWduYXR1cmVzOiBhbnkpOiBNb25lcm9UeCB7XG4gICAgdGhpcy5yY3RTaWduYXR1cmVzID0gcmN0U2lnbmF0dXJlcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJuIHthbnl9IHBydW5hYmxlIFJDVCBzaWduYXR1cmUgZGF0YVxuICAgKi9cbiAgZ2V0UmN0U2lnUHJ1bmFibGUoKTogb2JqZWN0IHtcbiAgICByZXR1cm4gdGhpcy5yY3RTaWdQcnVuYWJsZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge2FueX0gcmN0U2lnUHJ1bmFibGUgLSBwcnVuYWJsZSBSQ1Qgc2lnbmF0dXJlIGRhdGFcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRSY3RTaWdQcnVuYWJsZShyY3RTaWdQcnVuYWJsZTogYW55KTogTW9uZXJvVHgge1xuICAgIHRoaXMucmN0U2lnUHJ1bmFibGUgPSByY3RTaWdQcnVuYWJsZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIGtlcHQgYnkgYSBibG9jaywgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBnZXRJc0tlcHRCeUJsb2NrKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzS2VwdEJ5QmxvY2s7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtib29sZWFufSBpc0tlcHRCeUJsb2NrIC0gdHJ1ZSBpZiBrZXB0IGJ5IGEgYmxvY2ssIGZhbHNlIG90aGVyd2lzZVxuICAgKiBAcmV0dXJuIHtNb25lcm9UeH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldElzS2VwdEJ5QmxvY2soaXNLZXB0QnlCbG9jazogYm9vbGVhbik6IE1vbmVyb1R4IHtcbiAgICB0aGlzLmlzS2VwdEJ5QmxvY2sgPSBpc0tlcHRCeUJsb2NrO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgdGhlIHR4IGZhaWxlZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBnZXRJc0ZhaWxlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc0ZhaWxlZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGlzRmFpbGVkIC0gdHJ1ZSBpZiB0aGUgdHggZmFpbGVkLCBmYWxzZSBvdGhlcndpc2VcbiAgICogQHJldHVybiB7TW9uZXJvVHh9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRJc0ZhaWxlZChpc0ZhaWxlZDogYm9vbGVhbik6IE1vbmVyb1R4IHtcbiAgICB0aGlzLmlzRmFpbGVkID0gaXNGYWlsZWQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQHJldHVybiB7bnVtYmVyfSBibG9jayBoZWlnaHQgb2YgdGhlIGxhc3QgdHggZmFpbHVyZVxuICAgKi9cbiAgZ2V0TGFzdEZhaWxlZEhlaWdodCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmxhc3RGYWlsZWRIZWlnaHQ7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtudW1iZXJ9IGxhc3RGYWlsZWRIZWlnaHQgLSBibG9jayBoZWlnaHQgb2YgdGhlIGxhc3QgdHggZmFpbHVyZVxuICAgKiBAcmV0dXJuIHtNb25lcm9UeH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldExhc3RGYWlsZWRIZWlnaHQobGFzdEZhaWxlZEhlaWdodDogbnVtYmVyKTogTW9uZXJvVHgge1xuICAgIHRoaXMubGFzdEZhaWxlZEhlaWdodCA9IGxhc3RGYWlsZWRIZWlnaHQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQHJldHVybiB7c3RyaW5nfSBibG9jayBoYXNoIG9mIHRoZSBsYXN0IHR4IGZhaWx1cmVcbiAgICovXG4gIGdldExhc3RGYWlsZWRIYXNoKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMubGFzdEZhaWxlZEhhc2g7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IGxhc3RGYWlsZWRIYXNoIC0gYmxvY2sgaGFzaCBvZiB0aGUgbGFzdCB0eCBmYWlsdXJlXG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0TGFzdEZhaWxlZEhhc2gobGFzdEZhaWxlZEhhc2g6IHN0cmluZyk6IE1vbmVyb1R4IHtcbiAgICB0aGlzLmxhc3RGYWlsZWRIYXNoID0gbGFzdEZhaWxlZEhhc2g7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQHJldHVybiB7bnVtYmVyfSBtYXggdXNlZCBibG9jayBoZWlnaHRcbiAgICovXG4gIGdldE1heFVzZWRCbG9ja0hlaWdodCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLm1heFVzZWRCbG9ja0hlaWdodDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlcn0gbWF4VXNlZEJsb2NrSGVpZ2h0IC0gbWF4IHVzZWQgYmxvY2sgaGVpZ2h0XG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0TWF4VXNlZEJsb2NrSGVpZ2h0KG1heFVzZWRCbG9ja0hlaWdodDogbnVtYmVyKTogTW9uZXJvVHgge1xuICAgIHRoaXMubWF4VXNlZEJsb2NrSGVpZ2h0ID0gbWF4VXNlZEJsb2NrSGVpZ2h0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm4ge3N0cmluZ30gbWF4IHVzZWQgYmxvY2sgaGFzaFxuICAgKi9cbiAgZ2V0TWF4VXNlZEJsb2NrSGFzaCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLm1heFVzZWRCbG9ja0hhc2g7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1heFVzZWRCbG9ja0hhc2ggLSBtYXggdXNlZCBibG9jayBoYXNoXG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0TWF4VXNlZEJsb2NrSGFzaChtYXhVc2VkQmxvY2tIYXNoOiBzdHJpbmcpOiBNb25lcm9UeCB7XG4gICAgdGhpcy5tYXhVc2VkQmxvY2tIYXNoID0gbWF4VXNlZEJsb2NrSGFzaDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtzdHJpbmdbXX0gdHggc2lnbmF0dXJlc1xuICAgKi9cbiAgZ2V0U2lnbmF0dXJlcygpOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIHRoaXMuc2lnbmF0dXJlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBzaWduYXR1cmVzIC0gdHggc2lnbmF0dXJlc1xuICAgKiBAcmV0dXJuIHtNb25lcm9UeH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldFNpZ25hdHVyZXMoc2lnbmF0dXJlczogc3RyaW5nW10pOiBNb25lcm9UeCB7XG4gICAgdGhpcy5zaWduYXR1cmVzID0gc2lnbmF0dXJlcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtNb25lcm9UeH0gYSBjb3B5IG9mIHRoaXMgdHhcbiAgICovXG4gIGNvcHkoKTogTW9uZXJvVHgge1xuICAgIHJldHVybiBuZXcgTW9uZXJvVHgodGhpcyk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHthbnl9IGpzb24gcmVwcmVzZW50YXRpb24gb2YgdGhpcyB0eFxuICAgKi9cbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgbGV0IGpzb246IGFueSA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICAgIGlmICh0aGlzLmdldEZlZSgpICE9PSB1bmRlZmluZWQpIGpzb24uZmVlID0gdGhpcy5nZXRGZWUoKS50b1N0cmluZygpO1xuICAgIGlmICh0aGlzLmdldFVubG9ja1RpbWUoKSAhPT0gdW5kZWZpbmVkKSBqc29uLnVubG9ja1RpbWUgPSB0aGlzLmdldFVubG9ja1RpbWUoKS50b1N0cmluZygpO1xuICAgIGlmICh0aGlzLmdldElucHV0cygpKSB7XG4gICAgICBqc29uLmlucHV0cyA9IFtdO1xuICAgICAgZm9yIChsZXQgaW5wdXQgb2YgdGhpcy5nZXRJbnB1dHMoKSkganNvbi5pbnB1dHMucHVzaChpbnB1dC50b0pzb24oKSk7XG4gICAgfVxuICAgIGlmICh0aGlzLmdldE91dHB1dHMoKSkge1xuICAgICAganNvbi5vdXRwdXRzID0gW107XG4gICAgICBmb3IgKGxldCBvdXRwdXQgb2YgdGhpcy5nZXRPdXRwdXRzKCkpIGpzb24ub3V0cHV0cy5wdXNoKG91dHB1dC50b0pzb24oKSk7XG4gICAgfVxuICAgIGlmICh0aGlzLmdldEV4dHJhKCkgIT09IHVuZGVmaW5lZCkganNvbi5leHRyYSA9IEFycmF5LmZyb20odGhpcy5nZXRFeHRyYSgpLCBieXRlID0+IGJ5dGUpO1xuICAgIGRlbGV0ZSBqc29uLmJsb2NrOyAgLy8gZG8gbm90IHNlcmlhbGl6ZSBwYXJlbnQgYmxvY2tcbiAgICByZXR1cm4ganNvbjtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFVwZGF0ZXMgdGhpcyB0cmFuc2FjdGlvbiBieSBtZXJnaW5nIHRoZSBsYXRlc3QgaW5mb3JtYXRpb24gZnJvbSB0aGUgZ2l2ZW5cbiAgICogdHJhbnNhY3Rpb24uXG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb1R4fSB0eCAtIHRoZSB0cmFuc2FjdGlvbiB0byB1cGRhdGUgdGhpcyB0cmFuc2FjdGlvbiB3aXRoXG4gICAqIEByZXR1cm4ge01vbmVyb1R4fSB0aGlzIGZvciBtZXRob2QgY2hhaW5pbmdcbiAgICovXG4gIG1lcmdlKHR4OiBNb25lcm9UeCk6IE1vbmVyb1R4IHtcbiAgICBhc3NlcnQodHggaW5zdGFuY2VvZiBNb25lcm9UeCk7XG4gICAgaWYgKHRoaXMgPT09IHR4KSByZXR1cm4gdGhpcztcbiAgICBcbiAgICAvLyBtZXJnZSBibG9ja3MgaWYgdGhleSdyZSBkaWZmZXJlbnRcbiAgICBpZiAodGhpcy5nZXRCbG9jaygpICE9PSB0eC5nZXRCbG9jaygpKSB7XG4gICAgICBpZiAodGhpcy5nZXRCbG9jaygpID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5zZXRCbG9jayh0eC5nZXRCbG9jaygpKTtcbiAgICAgICAgdGhpcy5nZXRCbG9jaygpLmdldFR4c1t0aGlzLmdldEJsb2NrKCkuZ2V0VHhzKCkuaW5kZXhPZih0eCldID0gdGhpczsgLy8gdXBkYXRlIGJsb2NrIHRvIHBvaW50IHRvIHRoaXMgdHhcbiAgICAgIH0gZWxzZSBpZiAodHguZ2V0QmxvY2soKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRoaXMuZ2V0QmxvY2soKS5tZXJnZSh0eC5nZXRCbG9jaygpKTsgLy8gY29tZXMgYmFjayB0byBtZXJnaW5nIHR4c1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gb3RoZXJ3aXNlIG1lcmdlIHR4IGZpZWxkc1xuICAgIHRoaXMuc2V0SGFzaChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRIYXNoKCksIHR4LmdldEhhc2goKSkpO1xuICAgIHRoaXMuc2V0VmVyc2lvbihHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRWZXJzaW9uKCksIHR4LmdldFZlcnNpb24oKSkpO1xuICAgIHRoaXMuc2V0UGF5bWVudElkKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldFBheW1lbnRJZCgpLCB0eC5nZXRQYXltZW50SWQoKSkpO1xuICAgIHRoaXMuc2V0RmVlKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldEZlZSgpLCB0eC5nZXRGZWUoKSkpO1xuICAgIHRoaXMuc2V0UmluZ1NpemUoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0UmluZ1NpemUoKSwgdHguZ2V0UmluZ1NpemUoKSkpO1xuICAgIHRoaXMuc2V0SXNDb25maXJtZWQoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0SXNDb25maXJtZWQoKSwgdHguZ2V0SXNDb25maXJtZWQoKSwge3Jlc29sdmVUcnVlOiB0cnVlfSkpOyAvLyB0eCBjYW4gYmVjb21lIGNvbmZpcm1lZFxuICAgIHRoaXMuc2V0SXNNaW5lclR4KEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldElzTWluZXJUeCgpLCB0eC5nZXRJc01pbmVyVHgoKSkpO1xuICAgIHRoaXMuc2V0UmVsYXkoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0UmVsYXkoKSwgdHguZ2V0UmVsYXkoKSwge3Jlc29sdmVUcnVlOiB0cnVlfSkpOyAgICAgICAvLyB0eCBjYW4gYmVjb21lIHJlbGF5ZWRcbiAgICB0aGlzLnNldElzUmVsYXllZChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRJc1JlbGF5ZWQoKSwgdHguZ2V0SXNSZWxheWVkKCksIHtyZXNvbHZlVHJ1ZTogdHJ1ZX0pKTsgLy8gdHggY2FuIGJlY29tZSByZWxheWVkXG4gICAgdGhpcy5zZXRJc0RvdWJsZVNwZW5kU2VlbihHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRJc0RvdWJsZVNwZW5kU2VlbigpLCB0eC5nZXRJc0RvdWJsZVNwZW5kU2VlbigpLCB7cmVzb2x2ZVRydWU6IHRydWV9KSk7IC8vIGRvdWJsZSBzcGVuZCBjYW4gYmVjb21lIHNlZW5cbiAgICB0aGlzLnNldEtleShHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRLZXkoKSwgdHguZ2V0S2V5KCkpKTtcbiAgICB0aGlzLnNldEZ1bGxIZXgoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0RnVsbEhleCgpLCB0eC5nZXRGdWxsSGV4KCkpKTtcbiAgICB0aGlzLnNldFBydW5lZEhleChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRQcnVuZWRIZXgoKSwgdHguZ2V0UHJ1bmVkSGV4KCkpKTtcbiAgICB0aGlzLnNldFBydW5hYmxlSGV4KEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldFBydW5hYmxlSGV4KCksIHR4LmdldFBydW5hYmxlSGV4KCkpKTtcbiAgICB0aGlzLnNldFBydW5hYmxlSGFzaChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRQcnVuYWJsZUhhc2goKSwgdHguZ2V0UHJ1bmFibGVIYXNoKCkpKTtcbiAgICB0aGlzLnNldFNpemUoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0U2l6ZSgpLCB0eC5nZXRTaXplKCkpKTtcbiAgICB0aGlzLnNldFdlaWdodChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRXZWlnaHQoKSwgdHguZ2V0V2VpZ2h0KCkpKTtcbiAgICB0aGlzLnNldE91dHB1dEluZGljZXMoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0T3V0cHV0SW5kaWNlcygpLCB0eC5nZXRPdXRwdXRJbmRpY2VzKCkpKTtcbiAgICB0aGlzLnNldE1ldGFkYXRhKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldE1ldGFkYXRhKCksIHR4LmdldE1ldGFkYXRhKCkpKTtcbiAgICB0aGlzLnNldEV4dHJhKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldEV4dHJhKCksIHR4LmdldEV4dHJhKCkpKTtcbiAgICB0aGlzLnNldFJjdFNpZ25hdHVyZXMoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0UmN0U2lnbmF0dXJlcygpLCB0eC5nZXRSY3RTaWduYXR1cmVzKCkpKTtcbiAgICB0aGlzLnNldFJjdFNpZ1BydW5hYmxlKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldFJjdFNpZ1BydW5hYmxlKCksIHR4LmdldFJjdFNpZ1BydW5hYmxlKCkpKTtcbiAgICB0aGlzLnNldElzS2VwdEJ5QmxvY2soR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0SXNLZXB0QnlCbG9jaygpLCB0eC5nZXRJc0tlcHRCeUJsb2NrKCkpKTtcbiAgICB0aGlzLnNldElzRmFpbGVkKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldElzRmFpbGVkKCksIHR4LmdldElzRmFpbGVkKCksIHtyZXNvbHZlVHJ1ZTogdHJ1ZX0pKTtcbiAgICB0aGlzLnNldExhc3RGYWlsZWRIZWlnaHQoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0TGFzdEZhaWxlZEhlaWdodCgpLCB0eC5nZXRMYXN0RmFpbGVkSGVpZ2h0KCkpKTtcbiAgICB0aGlzLnNldExhc3RGYWlsZWRIYXNoKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldExhc3RGYWlsZWRIYXNoKCksIHR4LmdldExhc3RGYWlsZWRIYXNoKCkpKTtcbiAgICB0aGlzLnNldE1heFVzZWRCbG9ja0hlaWdodChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRNYXhVc2VkQmxvY2tIZWlnaHQoKSwgdHguZ2V0TWF4VXNlZEJsb2NrSGVpZ2h0KCkpKTtcbiAgICB0aGlzLnNldE1heFVzZWRCbG9ja0hhc2goR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0TWF4VXNlZEJsb2NrSGFzaCgpLCB0eC5nZXRNYXhVc2VkQmxvY2tIYXNoKCkpKTtcbiAgICB0aGlzLnNldFNpZ25hdHVyZXMoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0U2lnbmF0dXJlcygpLCB0eC5nZXRTaWduYXR1cmVzKCkpKTtcbiAgICB0aGlzLnNldFVubG9ja1RpbWUoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0VW5sb2NrVGltZSgpLCB0eC5nZXRVbmxvY2tUaW1lKCkpKTtcbiAgICB0aGlzLnNldE51bUNvbmZpcm1hdGlvbnMoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0TnVtQ29uZmlybWF0aW9ucygpLCB0eC5nZXROdW1Db25maXJtYXRpb25zKCksIHtyZXNvbHZlTWF4OiB0cnVlfSkpOyAvLyBudW0gY29uZmlybWF0aW9ucyBjYW4gaW5jcmVhc2VcbiAgICBcbiAgICAvLyBtZXJnZSBpbnB1dHNcbiAgICBpZiAodHguZ2V0SW5wdXRzKCkpIHtcbiAgICAgIGZvciAobGV0IG1lcmdlciBvZiB0eC5nZXRJbnB1dHMoKSkge1xuICAgICAgICBsZXQgbWVyZ2VkID0gZmFsc2U7XG4gICAgICAgIG1lcmdlci5zZXRUeCh0aGlzKTtcbiAgICAgICAgaWYgKCF0aGlzLmdldElucHV0cygpKSB0aGlzLnNldElucHV0cyhbXSk7XG4gICAgICAgIGZvciAobGV0IG1lcmdlZSBvZiB0aGlzLmdldElucHV0cygpKSB7XG4gICAgICAgICAgaWYgKG1lcmdlZS5nZXRLZXlJbWFnZSgpLmdldEhleCgpID09PSBtZXJnZXIuZ2V0S2V5SW1hZ2UoKS5nZXRIZXgoKSkge1xuICAgICAgICAgICAgbWVyZ2VlLm1lcmdlKG1lcmdlcik7XG4gICAgICAgICAgICBtZXJnZWQgPSB0cnVlO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICghbWVyZ2VkKSB0aGlzLmdldElucHV0cygpLnB1c2gobWVyZ2VyKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gbWVyZ2Ugb3V0cHV0c1xuICAgIGlmICh0eC5nZXRPdXRwdXRzKCkpIHtcbiAgICAgIGZvciAobGV0IG91dHB1dCBvZiB0eC5nZXRPdXRwdXRzKCkpIG91dHB1dC5zZXRUeCh0aGlzKTtcbiAgICAgIGlmICghdGhpcy5nZXRPdXRwdXRzKCkpIHRoaXMuc2V0T3V0cHV0cyh0eC5nZXRPdXRwdXRzKCkpO1xuICAgICAgZWxzZSB7XG4gICAgICAgIFxuICAgICAgICAvLyBtZXJnZSBvdXRwdXRzIGlmIGtleSBpbWFnZSBvciBzdGVhbHRoIHB1YmxpYyBrZXkgcHJlc2VudCwgb3RoZXJ3aXNlIGFwcGVuZFxuICAgICAgICBmb3IgKGxldCBtZXJnZXIgb2YgdHguZ2V0T3V0cHV0cygpKSB7XG4gICAgICAgICAgbGV0IG1lcmdlZCA9IGZhbHNlO1xuICAgICAgICAgIG1lcmdlci5zZXRUeCh0aGlzKTtcbiAgICAgICAgICBmb3IgKGxldCBtZXJnZWUgb2YgdGhpcy5nZXRPdXRwdXRzKCkpIHtcbiAgICAgICAgICAgIGlmICgobWVyZ2VyLmdldEtleUltYWdlKCkgJiYgbWVyZ2VlLmdldEtleUltYWdlKCkuZ2V0SGV4KCkgPT09IG1lcmdlci5nZXRLZXlJbWFnZSgpLmdldEhleCgpKSB8fFxuICAgICAgICAgICAgICAgIChtZXJnZXIuZ2V0U3RlYWx0aFB1YmxpY0tleSgpICYmIG1lcmdlZS5nZXRTdGVhbHRoUHVibGljS2V5KCkgPT09IG1lcmdlci5nZXRTdGVhbHRoUHVibGljS2V5KCkpKSB7XG4gICAgICAgICAgICAgbWVyZ2VlLm1lcmdlKG1lcmdlcik7XG4gICAgICAgICAgICAgbWVyZ2VkID0gdHJ1ZTtcbiAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKCFtZXJnZWQpIHRoaXMuZ2V0T3V0cHV0cygpLnB1c2gobWVyZ2VyKTsgLy8gYXBwZW5kIG91dHB1dFxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIGhhbmRsZSB1bnJlbGF5ZWQgLT4gcmVsYXllZCAtPiBjb25maXJtZWRcbiAgICBpZiAodGhpcy5nZXRJc0NvbmZpcm1lZCgpKSB7XG4gICAgICB0aGlzLnNldEluVHhQb29sKGZhbHNlKTtcbiAgICAgIHRoaXMuc2V0UmVjZWl2ZWRUaW1lc3RhbXAodW5kZWZpbmVkKTtcbiAgICAgIHRoaXMuc2V0TGFzdFJlbGF5ZWRUaW1lc3RhbXAodW5kZWZpbmVkKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5zZXRJblR4UG9vbChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRJblR4UG9vbCgpLCB0eC5nZXRJblR4UG9vbCgpLCB7cmVzb2x2ZVRydWU6IHRydWV9KSk7IC8vIHVucmVsYXllZCAtPiB0eCBwb29sXG4gICAgICB0aGlzLnNldFJlY2VpdmVkVGltZXN0YW1wKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldFJlY2VpdmVkVGltZXN0YW1wKCksIHR4LmdldFJlY2VpdmVkVGltZXN0YW1wKCksIHtyZXNvbHZlTWF4OiBmYWxzZX0pKTsgLy8gdGFrZSBlYXJsaWVzdCByZWNlaXZlIHRpbWVcbiAgICAgIHRoaXMuc2V0TGFzdFJlbGF5ZWRUaW1lc3RhbXAoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0TGFzdFJlbGF5ZWRUaW1lc3RhbXAoKSwgdHguZ2V0TGFzdFJlbGF5ZWRUaW1lc3RhbXAoKSwge3Jlc29sdmVNYXg6IHRydWV9KSk7ICAvLyB0YWtlIGxhdGVzdCByZWxheSB0aW1lXG4gICAgfVxuICAgIFxuICAgIHJldHVybiB0aGlzOyAgLy8gZm9yIGNoYWluaW5nXG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2luZGVudF0gLSBzdGFydGluZyBpbmRlbnRhdGlvblxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGlzIHR4XG4gICAqL1xuICB0b1N0cmluZyhpbmRlbnQgPSAwKTogc3RyaW5nIHtcbiAgICBsZXQgc3RyID0gXCJcIjtcbiAgICBzdHIgKz0gR2VuVXRpbHMuZ2V0SW5kZW50KGluZGVudCkgKyBcIj09PSBUWCA9PT1cXG5cIjtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiVHggaGFzaFwiLCB0aGlzLmdldEhhc2goKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiSGVpZ2h0XCIsIHRoaXMuZ2V0SGVpZ2h0KCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlZlcnNpb25cIiwgdGhpcy5nZXRWZXJzaW9uKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIklzIG1pbmVyIHR4XCIsIHRoaXMuZ2V0SXNNaW5lclR4KCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlBheW1lbnQgSURcIiwgdGhpcy5nZXRQYXltZW50SWQoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiRmVlXCIsIHRoaXMuZ2V0RmVlKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlJpbmcgc2l6ZVwiLCB0aGlzLmdldFJpbmdTaXplKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlJlbGF5XCIsIHRoaXMuZ2V0UmVsYXkoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiSXMgcmVsYXllZFwiLCB0aGlzLmdldElzUmVsYXllZCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJJcyBjb25maXJtZWRcIiwgdGhpcy5nZXRJc0NvbmZpcm1lZCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJJbiB0eCBwb29sXCIsIHRoaXMuZ2V0SW5UeFBvb2woKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiTnVtIGNvbmZpcm1hdGlvbnNcIiwgdGhpcy5nZXROdW1Db25maXJtYXRpb25zKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlVubG9jayB0aW1lXCIsIHRoaXMuZ2V0VW5sb2NrVGltZSgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJMYXN0IHJlbGF5ZWQgdGltZVwiLCB0aGlzLmdldExhc3RSZWxheWVkVGltZXN0YW1wKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlJlY2VpdmVkIHRpbWVcIiwgdGhpcy5nZXRSZWNlaXZlZFRpbWVzdGFtcCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJJcyBkb3VibGUgc3BlbmRcIiwgdGhpcy5nZXRJc0RvdWJsZVNwZW5kU2VlbigpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJLZXlcIiwgdGhpcy5nZXRLZXkoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiRnVsbCBoZXhcIiwgdGhpcy5nZXRGdWxsSGV4KCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlBydW5lZCBoZXhcIiwgdGhpcy5nZXRQcnVuZWRIZXgoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiUHJ1bmFibGUgaGV4XCIsIHRoaXMuZ2V0UHJ1bmFibGVIZXgoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiUHJ1bmFibGUgaGFzaFwiLCB0aGlzLmdldFBydW5hYmxlSGFzaCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJTaXplXCIsIHRoaXMuZ2V0U2l6ZSgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJXZWlnaHRcIiwgdGhpcy5nZXRXZWlnaHQoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiT3V0cHV0IGluZGljZXNcIiwgdGhpcy5nZXRPdXRwdXRJbmRpY2VzKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIk1ldGFkYXRhXCIsIHRoaXMuZ2V0TWV0YWRhdGEoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiRXh0cmFcIiwgdGhpcy5nZXRFeHRyYSgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJSQ1Qgc2lnbmF0dXJlc1wiLCB0aGlzLmdldFJjdFNpZ25hdHVyZXMoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiUkNUIHNpZyBwcnVuYWJsZVwiLCB0aGlzLmdldFJjdFNpZ1BydW5hYmxlKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIktlcHQgYnkgYmxvY2tcIiwgdGhpcy5nZXRJc0tlcHRCeUJsb2NrKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIklzIGZhaWxlZFwiLCB0aGlzLmdldElzRmFpbGVkKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIkxhc3QgZmFpbGVkIGhlaWdodFwiLCB0aGlzLmdldExhc3RGYWlsZWRIZWlnaHQoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiTGFzdCBmYWlsZWQgaGFzaFwiLCB0aGlzLmdldExhc3RGYWlsZWRIYXNoKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIk1heCB1c2VkIGJsb2NrIGhlaWdodFwiLCB0aGlzLmdldE1heFVzZWRCbG9ja0hlaWdodCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJNYXggdXNlZCBibG9jayBoYXNoXCIsIHRoaXMuZ2V0TWF4VXNlZEJsb2NrSGFzaCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJTaWduYXR1cmVzXCIsIHRoaXMuZ2V0U2lnbmF0dXJlcygpLCBpbmRlbnQpO1xuICAgIGlmICh0aGlzLmdldElucHV0cygpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJJbnB1dHNcIiwgXCJcIiwgaW5kZW50KTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5nZXRJbnB1dHMoKS5sZW5ndGg7IGkrKykge1xuICAgICAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKGkgKyAxLCBcIlwiLCBpbmRlbnQgKyAxKTtcbiAgICAgICAgc3RyICs9IHRoaXMuZ2V0SW5wdXRzKClbaV0udG9TdHJpbmcoaW5kZW50ICsgMik7XG4gICAgICAgIHN0ciArPSAnXFxuJ1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAodGhpcy5nZXRPdXRwdXRzKCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIk91dHB1dHNcIiwgXCJcIiwgaW5kZW50KTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5nZXRPdXRwdXRzKCkubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShpICsgMSwgXCJcIiwgaW5kZW50ICsgMSk7XG4gICAgICAgIHN0ciArPSB0aGlzLmdldE91dHB1dHMoKVtpXS50b1N0cmluZyhpbmRlbnQgKyAyKTtcbiAgICAgICAgc3RyICs9ICdcXG4nXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBzdHIuc2xpY2UoMCwgc3RyLmxlbmd0aCAtIDEpOyAgLy8gc3RyaXAgbGFzdCBuZXdsaW5lXG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFNBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTs7QUFFQSxJQUFBRSxhQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7O0FBRUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUcsUUFBUSxDQUFDOztFQUU1QixPQUFnQkMsa0JBQWtCLEdBQUcsa0JBQWtCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBd0N2REMsV0FBV0EsQ0FBQ0MsRUFBc0IsRUFBRTtJQUNsQ0MsTUFBTSxDQUFDQyxNQUFNLENBQUMsSUFBSSxFQUFFRixFQUFFLENBQUM7SUFDdkIsSUFBSSxDQUFDRyxLQUFLLEdBQUdDLFNBQVM7O0lBRXRCO0lBQ0EsSUFBSSxJQUFJLENBQUNDLEtBQUssS0FBS0QsU0FBUyxFQUFFLElBQUksQ0FBQ0MsS0FBSyxHQUFHLElBQUlDLFVBQVUsQ0FBQyxJQUFJLENBQUNELEtBQUssQ0FBQzs7SUFFckU7SUFDQSxJQUFJLElBQUksQ0FBQ0UsR0FBRyxLQUFLSCxTQUFTLElBQUksT0FBTyxJQUFJLENBQUNHLEdBQUcsS0FBSyxRQUFRLEVBQUUsSUFBSSxDQUFDQSxHQUFHLEdBQUdDLE1BQU0sQ0FBQyxJQUFJLENBQUNELEdBQUcsQ0FBQztJQUN2RixJQUFJLElBQUksQ0FBQ0UsVUFBVSxLQUFLTCxTQUFTLElBQUksT0FBTyxJQUFJLENBQUNLLFVBQVUsS0FBSyxRQUFRLEVBQUUsSUFBSSxDQUFDQSxVQUFVLEdBQUdELE1BQU0sQ0FBQyxJQUFJLENBQUNDLFVBQVUsQ0FBQzs7SUFFbkg7SUFDQSxJQUFJLElBQUksQ0FBQ0MsTUFBTSxFQUFFO01BQ2YsSUFBSSxDQUFDQSxNQUFNLEdB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 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroTxPoolStats.d.ts b/dist/src/main/ts/daemon/model/MoneroTxPoolStats.d.ts new file mode 100644 index 000000000..a049fa6b4 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroTxPoolStats.d.ts @@ -0,0 +1,46 @@ +/** + * Models transaction pool statistics. + */ +export default class MoneroTxPoolStats { + numTxs: number; + numNotRelayed: number; + numFailing: number; + numDoubleSpends: number; + num10m: number; + feeTotal: bigint; + bytesMax: number; + bytesMed: number; + bytesMin: number; + bytesTotal: number; + histo: Map; + histo98pc: number; + oldestTimestamp: number; + constructor(stats?: Partial); + toJson(): any; + getNumTxs(): number; + setNumTxs(numTxs: number): MoneroTxPoolStats; + getNumNotRelayed(): number; + setNumNotRelayed(numNotRelayed: number): MoneroTxPoolStats; + getNumFailing(): number; + setNumFailing(numFailing: number): MoneroTxPoolStats; + getNumDoubleSpends(): number; + setNumDoubleSpends(numDoubleSpends: number): MoneroTxPoolStats; + getNum10m(): number; + setNum10m(num10m: any): MoneroTxPoolStats; + getFeeTotal(): bigint; + setFeeTotal(feeTotal: bigint): MoneroTxPoolStats; + getBytesMax(): number; + setBytesMax(bytesMax: number): MoneroTxPoolStats; + getBytesMed(): number; + setBytesMed(bytesMed: number): MoneroTxPoolStats; + getBytesMin(): number; + setBytesMin(bytesMin: number): MoneroTxPoolStats; + getBytesTotal(): number; + setBytesTotal(bytesTotal: number): MoneroTxPoolStats; + getHisto(): Map; + setHisto(histo: Map): MoneroTxPoolStats; + getHisto98pc(): number; + setHisto98pc(histo98pc: number): MoneroTxPoolStats; + getOldestTimestamp(): number; + setOldestTimestamp(oldestTimestamp: number): MoneroTxPoolStats; +} diff --git a/dist/src/main/ts/daemon/model/MoneroTxPoolStats.js b/dist/src/main/ts/daemon/model/MoneroTxPoolStats.js new file mode 100644 index 000000000..a8c1e9992 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroTxPoolStats.js @@ -0,0 +1,150 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Models transaction pool statistics. + */ +class MoneroTxPoolStats { + + + + + + + + + + + + + + + + constructor(stats) { + Object.assign(this, stats); + if (this.feeTotal !== undefined && typeof this.feeTotal !== "bigint") this.feeTotal = BigInt(this.feeTotal); + if (this.histo !== undefined && !(this.histo instanceof Map)) this.histo = new Map(JSON.parse(this.histo)); + } + + toJson() { + let json = Object.assign({}, this); + if (json.feeTotal) json.feeTotal = json.feeTotal.toString(); + if (json.histo) json.histo = JSON.stringify([...json.histo]); // convert map to array of key-value pairs then stringify + return json; + } + + getNumTxs() { + return this.numTxs; + } + + setNumTxs(numTxs) { + this.numTxs = numTxs; + return this; + } + + getNumNotRelayed() { + return this.numNotRelayed; + } + + setNumNotRelayed(numNotRelayed) { + this.numNotRelayed = numNotRelayed; + return this; + } + + getNumFailing() { + return this.numFailing; + } + + setNumFailing(numFailing) { + this.numFailing = numFailing; + return this; + } + + getNumDoubleSpends() { + return this.numDoubleSpends; + } + + setNumDoubleSpends(numDoubleSpends) { + this.numDoubleSpends = numDoubleSpends; + return this; + } + + getNum10m() { + return this.num10m; + } + + setNum10m(num10m) { + this.num10m = num10m; + return this; + } + + getFeeTotal() { + return this.feeTotal; + } + + setFeeTotal(feeTotal) { + this.feeTotal = feeTotal; + return this; + } + + getBytesMax() { + return this.bytesMax; + } + + setBytesMax(bytesMax) { + this.bytesMax = bytesMax; + return this; + } + + getBytesMed() { + return this.bytesMed; + } + + setBytesMed(bytesMed) { + this.bytesMed = bytesMed; + return this; + } + + getBytesMin() { + return this.bytesMin; + } + + setBytesMin(bytesMin) { + this.bytesMin = bytesMin; + return this; + } + + getBytesTotal() { + return this.bytesTotal; + } + + setBytesTotal(bytesTotal) { + this.bytesTotal = bytesTotal; + return this; + } + + getHisto() { + return this.histo; + } + + setHisto(histo) { + this.histo = histo; + return this; + } + + getHisto98pc() { + return this.histo98pc; + } + + setHisto98pc(histo98pc) { + this.histo98pc = histo98pc; + return this; + } + + getOldestTimestamp() { + return this.oldestTimestamp; + } + + setOldestTimestamp(oldestTimestamp) { + this.oldestTimestamp = oldestTimestamp; + return this; + } +}exports.default = MoneroTxPoolStats; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9UeFBvb2xTdGF0cyIsImNvbnN0cnVjdG9yIiwic3RhdHMiLCJPYmplY3QiLCJhc3NpZ24iLCJmZWVUb3RhbCIsInVuZGVmaW5lZCIsIkJpZ0ludCIsImhpc3RvIiwiTWFwIiwiSlNPTiIsInBhcnNlIiwidG9Kc29uIiwianNvbiIsInRvU3RyaW5nIiwic3RyaW5naWZ5IiwiZ2V0TnVtVHhzIiwibnVtVHhzIiwic2V0TnVtVHhzIiwiZ2V0TnVtTm90UmVsYXllZCIsIm51bU5vdFJlbGF5ZWQiLCJzZXROdW1Ob3RSZWxheWVkIiwiZ2V0TnVtRmFpbGluZyIsIm51bUZhaWxpbmciLCJzZXROdW1GYWlsaW5nIiwiZ2V0TnVtRG91YmxlU3BlbmRzIiwibnVtRG91YmxlU3BlbmRzIiwic2V0TnVtRG91YmxlU3BlbmRzIiwiZ2V0TnVtMTBtIiwibnVtMTBtIiwic2V0TnVtMTBtIiwiZ2V0RmVlVG90YWwiLCJzZXRGZWVUb3RhbCIsImdldEJ5dGVzTWF4IiwiYnl0ZXNNYXgiLCJzZXRCeXRlc01heCIsImdldEJ5dGVzTWVkIiwiYnl0ZXNNZWQiLCJzZXRCeXRlc01lZCIsImdldEJ5dGVzTWluIiwiYnl0ZXNNaW4iLCJzZXRCeXRlc01pbiIsImdldEJ5dGVzVG90YWwiLCJieXRlc1RvdGFsIiwic2V0Qnl0ZXNUb3RhbCIsImdldEhpc3RvIiwic2V0SGlzdG8iLCJnZXRIaXN0bzk4cGMiLCJoaXN0bzk4cGMiLCJzZXRIaXN0bzk4cGMiLCJnZXRPbGRlc3RUaW1lc3RhbXAiLCJvbGRlc3RUaW1lc3RhbXAiLCJzZXRPbGRlc3RUaW1lc3RhbXAiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL2RhZW1vbi9tb2RlbC9Nb25lcm9UeFBvb2xTdGF0cy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1vZGVscyB0cmFuc2FjdGlvbiBwb29sIHN0YXRpc3RpY3MuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb1R4UG9vbFN0YXRzIHtcblxuICBudW1UeHM6IG51bWJlcjtcbiAgbnVtTm90UmVsYXllZDogbnVtYmVyO1xuICBudW1GYWlsaW5nOiBudW1iZXI7XG4gIG51bURvdWJsZVNwZW5kczogbnVtYmVyO1xuICBudW0xMG06IG51bWJlcjtcbiAgZmVlVG90YWw6IGJpZ2ludDtcbiAgYnl0ZXNNYXg6IG51bWJlcjtcbiAgYnl0ZXNNZWQ6IG51bWJlcjtcbiAgYnl0ZXNNaW46IG51bWJlcjtcbiAgYnl0ZXNUb3RhbDogbnVtYmVyO1xuICBoaXN0bzogTWFwPG51bWJlciwgbnVtYmVyPjtcbiAgaGlzdG85OHBjOiBudW1iZXI7XG4gIG9sZGVzdFRpbWVzdGFtcDogbnVtYmVyO1xuICBcbiAgY29uc3RydWN0b3Ioc3RhdHM/OiBQYXJ0aWFsPE1vbmVyb1R4UG9vbFN0YXRzPikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgc3RhdHMpO1xuICAgIGlmICh0aGlzLmZlZVRvdGFsICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHRoaXMuZmVlVG90YWwgIT09IFwiYmlnaW50XCIpIHRoaXMuZmVlVG90YWwgPSBCaWdJbnQodGhpcy5mZWVUb3RhbCk7XG4gICAgaWYgKHRoaXMuaGlzdG8gIT09IHVuZGVmaW5lZCAmJiAhKHRoaXMuaGlzdG8gaW5zdGFuY2VvZiBNYXApKSB0aGlzLmhpc3RvID0gbmV3IE1hcChKU09OLnBhcnNlKHRoaXMuaGlzdG8pKTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgbGV0IGpzb246IGFueSA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICAgIGlmIChqc29uLmZlZVRvdGFsKSBqc29uLmZlZVRvdGFsID0ganNvbi5mZWVUb3RhbC50b1N0cmluZygpO1xuICAgIGlmIChqc29uLmhpc3RvKSBqc29uLmhpc3RvID0gSlNPTi5zdHJpbmdpZnkoWy4uLmpzb24uaGlzdG9dKTsgLy8gY29udmVydCBtYXAgdG8gYXJyYXkgb2Yga2V5LXZhbHVlIHBhaXJzIHRoZW4gc3RyaW5naWZ5XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIGdldE51bVR4cygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLm51bVR4cztcbiAgfVxuICBcbiAgc2V0TnVtVHhzKG51bVR4czogbnVtYmVyKTogTW9uZXJvVHhQb29sU3RhdHMge1xuICAgIHRoaXMubnVtVHhzID0gbnVtVHhzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXROdW1Ob3RSZWxheWVkKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtTm90UmVsYXllZDtcbiAgfVxuICBcbiAgc2V0TnVtTm90UmVsYXllZChudW1Ob3RSZWxheWVkOiBudW1iZXIpOiBNb25lcm9UeFBvb2xTdGF0cyB7XG4gICAgdGhpcy5udW1Ob3RSZWxheWVkID0gbnVtTm90UmVsYXllZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0TnVtRmFpbGluZygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLm51bUZhaWxpbmc7XG4gIH1cbiAgXG4gIHNldE51bUZhaWxpbmcobnVtRmFpbGluZzogbnVtYmVyKTogTW9uZXJvVHhQb29sU3RhdHMge1xuICAgIHRoaXMubnVtRmFpbGluZyA9IG51bUZhaWxpbmc7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldE51bURvdWJsZVNwZW5kcygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLm51bURvdWJsZVNwZW5kcztcbiAgfVxuICBcbiAgc2V0TnVtRG91YmxlU3BlbmRzKG51bURvdWJsZVNwZW5kczogbnVtYmVyKTogTW9uZXJvVHhQb29sU3RhdHMge1xuICAgIHRoaXMubnVtRG91YmxlU3BlbmRzID0gbnVtRG91YmxlU3BlbmRzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXROdW0xMG0oKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5udW0xMG07XG4gIH1cbiAgXG4gIHNldE51bTEwbShudW0xMG0pOiBNb25lcm9UeFBvb2xTdGF0cyB7XG4gICAgdGhpcy5udW0xMG0gPSBudW0xMG07XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEZlZVRvdGFsKCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMuZmVlVG90YWw7XG4gIH1cbiAgXG4gIHNldEZlZVRvdGFsKGZlZVRvdGFsOiBiaWdpbnQpOiBNb25lcm9UeFBvb2xTdGF0cyB7XG4gICAgdGhpcy5mZWVUb3RhbCA9IGZlZVRvdGFsO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRCeXRlc01heCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmJ5dGVzTWF4O1xuICB9XG4gIFxuICBzZXRCeXRlc01heChieXRlc01heDogbnVtYmVyKTogTW9uZXJvVHhQb29sU3RhdHMge1xuICAgIHRoaXMuYnl0ZXNNYXggPSBieXRlc01heDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0Qnl0ZXNNZWQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5ieXRlc01lZDtcbiAgfVxuICBcbiAgc2V0Qnl0ZXNNZWQoYnl0ZXNNZWQ6IG51bWJlcik6IE1vbmVyb1R4UG9vbFN0YXRzIHtcbiAgICB0aGlzLmJ5dGVzTWVkID0gYnl0ZXNNZWQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEJ5dGVzTWluKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuYnl0ZXNNaW47XG4gIH1cbiAgXG4gIHNldEJ5dGVzTWluKGJ5dGVzTWluOiBudW1iZXIpOiBNb25lcm9UeFBvb2xTdGF0cyB7XG4gICAgdGhpcy5ieXRlc01pbiA9IGJ5dGVzTWluO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRCeXRlc1RvdGFsKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuYnl0ZXNUb3RhbDtcbiAgfVxuICBcbiAgc2V0Qnl0ZXNUb3RhbChieXRlc1RvdGFsOiBudW1iZXIpOiBNb25lcm9UeFBvb2xTdGF0cyB7XG4gICAgdGhpcy5ieXRlc1RvdGFsID0gYnl0ZXNUb3RhbDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0SGlzdG8oKTogTWFwPG51bWJlciwgbnVtYmVyPiB7XG4gICAgcmV0dXJuIHRoaXMuaGlzdG87XG4gIH1cbiAgXG4gIHNldEhpc3RvKGhpc3RvOiBNYXA8bnVtYmVyLCBudW1iZXI+KTogTW9uZXJvVHhQb29sU3RhdHMge1xuICAgIHRoaXMuaGlzdG8gPSBoaXN0bztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0SGlzdG85OHBjKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuaGlzdG85OHBjO1xuICB9XG4gIFxuICBzZXRIaXN0bzk4cGMoaGlzdG85OHBjOiBudW1iZXIpOiBNb25lcm9UeFBvb2xTdGF0cyB7XG4gICAgdGhpcy5oaXN0bzk4cGMgPSBoaXN0bzk4cGM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldE9sZGVzdFRpbWVzdGFtcCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLm9sZGVzdFRpbWVzdGFtcDtcbiAgfVxuICBcbiAgc2V0T2xkZXN0VGltZXN0YW1wKG9sZGVzdFRpbWVzdGFtcDogbnVtYmVyKTogTW9uZXJvVHhQb29sU3RhdHMge1xuICAgIHRoaXMub2xkZXN0VGltZXN0YW1wID0gb2xkZXN0VGltZXN0YW1wO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJxR0FBQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSxpQkFBaUIsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7OztFQWdCckNDLFdBQVdBLENBQUNDLEtBQWtDLEVBQUU7SUFDOUNDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsS0FBSyxDQUFDO0lBQzFCLElBQUksSUFBSSxDQUFDRyxRQUFRLEtBQUtDLFNBQVMsSUFBSSxPQUFPLElBQUksQ0FBQ0QsUUFBUSxLQUFLLFFBQVEsRUFBRSxJQUFJLENBQUNBLFFBQVEsR0FBR0UsTUFBTSxDQUFDLElBQUksQ0FBQ0YsUUFBUSxDQUFDO0lBQzNHLElBQUksSUFBSSxDQUFDRyxLQUFLLEtBQUtGLFNBQVMsSUFBSSxFQUFFLElBQUksQ0FBQ0UsS0FBSyxZQUFZQyxHQUFHLENBQUMsRUFBRSxJQUFJLENBQUNELEtBQUssR0FBRyxJQUFJQyxHQUFHLENBQUNDLElBQUksQ0FBQ0MsS0FBSyxDQUFDLElBQUksQ0FBQ0gsS0FBSyxDQUFDLENBQUM7RUFDNUc7O0VBRUFJLE1BQU1BLENBQUEsRUFBUTtJQUNaLElBQUlDLElBQVMsR0FBR1YsTUFBTSxDQUFDQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQ3ZDLElBQUlTLElBQUksQ0FBQ1IsUUFBUSxFQUFFUSxJQUFJLENBQUNSLFFBQVEsR0FBR1EsSUFBSSxDQUFDUixRQUFRLENBQUNTLFFBQVEsQ0FBQyxDQUFDO0lBQzNELElBQUlELElBQUksQ0FBQ0wsS0FBSyxFQUFFSyxJQUFJLENBQUNMLEtBQUssR0FBR0UsSUFBSSxDQUFDSyxTQUFTLENBQUMsQ0FBQyxHQUFHRixJQUFJLENBQUNMLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5RCxPQUFPSyxJQUFJO0VBQ2I7O0VBRUFHLFNBQVNBLENBQUEsRUFBVztJQUNsQixPQUFPLElBQUksQ0FBQ0MsTUFBTTtFQUNwQjs7RUFFQUMsU0FBU0EsQ0FBQ0QsTUFBYyxFQUFxQjtJQUMzQyxJQUFJLENBQUNBLE1BQU0sR0FBR0EsTUFBTTtJQUNwQixPQUFPLElBQUk7RUFDYjs7RUFFQUUsZ0JBQWdCQSxDQUFBLEVBQVc7SUFDekIsT0FBTyxJQUFJLENBQUNDLGFBQWE7RUFDM0I7O0VBRUFDLGdCQUFnQkEsQ0FBQ0QsYUFBcUIsRUFBcUI7SUFDekQsSUFBSSxDQUFDQSxhQUFhLEdBQUdBLGFBQWE7SUFDbEMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLGFBQWFBLENBQUEsRUFBVztJQUN0QixPQUFPLElBQUksQ0FBQ0MsVUFBVTtFQUN4Qjs7RUFFQUMsYUFBYUEsQ0FBQ0QsVUFBa0IsRUFBcUI7SUFDbkQsSUFBSSxDQUFDQSxVQUFVLEdBQUdBLFVBQVU7SUFDNUIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLGtCQUFrQkEsQ0FBQSxFQUFXO0lBQzNCLE9BQU8sSUFBSSxDQUFDQyxlQUFlO0VBQzdCOztFQUVBQyxrQkFBa0JBLENBQUNELGVBQXVCLEVBQXFCO0lBQzdELElBQUksQ0FBQ0EsZUFBZSxHQUFHQSxlQUFlO0lBQ3RDLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxTQUFTQSxDQUFBLEVBQVc7SUFDbEIsT0FBTyxJQUFJLENBQUNDLE1BQU07RUFDcEI7O0VBRUFDLFNBQVNBLENBQUNELE1BQU0sRUFBcUI7SUFDbkMsSUFBSSxDQUFDQSxNQUFNLEdBQUdBLE1BQU07SUFDcEIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLFdBQVdBLENBQUEsRUFBVztJQUNwQixPQUFPLElBQUksQ0FBQzFCLFFBQVE7RUFDdEI7O0VBRUEyQixXQUFXQSxDQUFDM0IsUUFBZ0IsRUFBcUI7SUFDL0MsSUFBSSxDQUFDQSxRQUFRLEdBQUdBLFFBQVE7SUFDeEIsT0FBTyxJQUFJO0VBQ2I7O0VBRUE0QixXQUFXQSxDQUFBLEVBQVc7SUFDcEIsT0FBTyxJQUFJLENBQUNDLFFBQVE7RUFDdEI7O0VBRUFDLFdBQVdBLENBQUNELFFBQWdCLEVBQXFCO0lBQy9DLElBQUksQ0FBQ0EsUUFBUSxHQUFHQSxRQUFRO0lBQ3hCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxXQUFXQSxDQUFBLEVBQVc7SUFDcEIsT0FBTyxJQUFJLENBQUNDLFFBQVE7RUFDdEI7O0VBRUFDLFdBQVdBLENBQUNELFFBQWdCLEVBQXFCO0lBQy9DLElBQUksQ0FBQ0EsUUFBUSxHQUFHQSxRQUFRO0lBQ3hCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxXQUFXQSxDQUFBLEVBQVc7SUFDcEIsT0FBTyxJQUFJLENBQUNDLFFBQVE7RUFDdEI7O0VBRUFDLFdBQVdBLENBQUNELFFBQWdCLEVBQXFCO0lBQy9DLElBQUksQ0FBQ0EsUUFBUSxHQUFHQSxRQUFRO0lBQ3hCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxhQUFhQSxDQUFBLEVBQVc7SUFDdEIsT0FBTyxJQUFJLENBQUNDLFVBQVU7RUFDeEI7O0VBRUFDLGFBQWFBLENBQUNELFVBQWtCLEVBQXFCO0lBQ25ELElBQUksQ0FBQ0EsVUFBVSxHQUFHQSxVQUFVO0lBQzVCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxRQUFRQSxDQUFBLEVBQXdCO0lBQzlCLE9BQU8sSUFBSSxDQUFDckMsS0FBSztFQUNuQjs7RUFFQXNDLFFBQVFBLENBQUN0QyxLQUEwQixFQUFxQjtJQUN0RCxJQUFJLENBQUNBLEtBQUssR0FBR0EsS0FBSztJQUNsQixPQUFPLElBQUk7RUFDYjs7RUFFQXVDLFlBQVlBLENBQUEsRUFBVztJQUNyQixPQUFPLElBQUksQ0FBQ0MsU0FBUztFQUN2Qjs7RUFFQUMsWUFBWUEsQ0FBQ0QsU0FBaUIsRUFBcUI7SUFDakQsSUFBSSxDQUFDQSxTQUFTLEdBQUdBLFNBQVM7SUFDMUIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLGtCQUFrQkEsQ0FBQSxFQUFXO0lBQzNCLE9BQU8sSUFBSSxDQUFDQyxlQUFlO0VBQzdCOztFQUVBQyxrQkFBa0JBLENBQUNELGVBQXVCLEVBQXFCO0lBQzdELElBQUksQ0FBQ0EsZUFBZSxHQUFHQSxlQUFlO0lBQ3RDLE9BQU8sSUFBSTtFQUNiO0FBQ0YsQ0FBQ0UsT0FBQSxDQUFBQyxPQUFBLEdBQUF0RCxpQkFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/daemon/model/MoneroVersion.d.ts b/dist/src/main/ts/daemon/model/MoneroVersion.d.ts new file mode 100644 index 000000000..3149c5ad5 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroVersion.d.ts @@ -0,0 +1,14 @@ +/** + * Models a Monero version. + */ +export default class MoneroVersion { + number: number; + isRelease: boolean; + constructor(number: number, isRelease: boolean); + getNumber(): number; + setNumber(number: number): MoneroVersion; + getIsRelease(): boolean; + setIsRelease(isRelease: boolean): MoneroVersion; + copy(): MoneroVersion; + toJson(): any; +} diff --git a/dist/src/main/ts/daemon/model/MoneroVersion.js b/dist/src/main/ts/daemon/model/MoneroVersion.js new file mode 100644 index 000000000..de2cd9797 --- /dev/null +++ b/dist/src/main/ts/daemon/model/MoneroVersion.js @@ -0,0 +1,40 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Models a Monero version. + */ +class MoneroVersion { + + + + + constructor(number, isRelease) { + this.number = number; + this.isRelease = isRelease; + } + + getNumber() { + return this.number; + } + + setNumber(number) { + this.number = number; + return this; + } + + getIsRelease() { + return this.isRelease; + } + + setIsRelease(isRelease) { + this.isRelease = isRelease; + return this; + } + + copy() { + return new MoneroVersion(this.number, this.isRelease); + } + + toJson() { + return Object.assign({}, this); + } +}exports.default = MoneroVersion; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9WZXJzaW9uIiwiY29uc3RydWN0b3IiLCJudW1iZXIiLCJpc1JlbGVhc2UiLCJnZXROdW1iZXIiLCJzZXROdW1iZXIiLCJnZXRJc1JlbGVhc2UiLCJzZXRJc1JlbGVhc2UiLCJjb3B5IiwidG9Kc29uIiwiT2JqZWN0IiwiYXNzaWduIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy9kYWVtb24vbW9kZWwvTW9uZXJvVmVyc2lvbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1vZGVscyBhIE1vbmVybyB2ZXJzaW9uLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9WZXJzaW9uIHtcblxuICBudW1iZXI6IG51bWJlcjtcbiAgaXNSZWxlYXNlOiBib29sZWFuO1xuICBcbiAgY29uc3RydWN0b3IobnVtYmVyOiBudW1iZXIsIGlzUmVsZWFzZTogYm9vbGVhbikge1xuICAgIHRoaXMubnVtYmVyID0gbnVtYmVyO1xuICAgIHRoaXMuaXNSZWxlYXNlID0gaXNSZWxlYXNlO1xuICB9XG5cbiAgZ2V0TnVtYmVyKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtYmVyO1xuICB9XG5cbiAgc2V0TnVtYmVyKG51bWJlcjogbnVtYmVyKTogTW9uZXJvVmVyc2lvbiB7XG4gICAgdGhpcy5udW1iZXIgPSBudW1iZXI7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRJc1JlbGVhc2UoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNSZWxlYXNlO1xuICB9XG5cbiAgc2V0SXNSZWxlYXNlKGlzUmVsZWFzZTogYm9vbGVhbik6IE1vbmVyb1ZlcnNpb24ge1xuICAgIHRoaXMuaXNSZWxlYXNlID0gaXNSZWxlYXNlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBjb3B5KCk6IE1vbmVyb1ZlcnNpb24ge1xuICAgIHJldHVybiBuZXcgTW9uZXJvVmVyc2lvbih0aGlzLm51bWJlciwgdGhpcy5pc1JlbGVhc2UpO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7fSwgdGhpcyk7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InFHQUFBO0FBQ0E7QUFDQTtBQUNlLE1BQU1BLGFBQWEsQ0FBQzs7Ozs7RUFLakNDLFdBQVdBLENBQUNDLE1BQWMsRUFBRUMsU0FBa0IsRUFBRTtJQUM5QyxJQUFJLENBQUNELE1BQU0sR0FBR0EsTUFBTTtJQUNwQixJQUFJLENBQUNDLFNBQVMsR0FBR0EsU0FBUztFQUM1Qjs7RUFFQUMsU0FBU0EsQ0FBQSxFQUFXO0lBQ2xCLE9BQU8sSUFBSSxDQUFDRixNQUFNO0VBQ3BCOztFQUVBRyxTQUFTQSxDQUFDSCxNQUFjLEVBQWlCO0lBQ3ZDLElBQUksQ0FBQ0EsTUFBTSxHQUFHQSxNQUFNO0lBQ3BCLE9BQU8sSUFBSTtFQUNiOztFQUVBSSxZQUFZQSxDQUFBLEVBQVk7SUFDdEIsT0FBTyxJQUFJLENBQUNILFNBQVM7RUFDdkI7O0VBRUFJLFlBQVlBLENBQUNKLFNBQWtCLEVBQWlCO0lBQzlDLElBQUksQ0FBQ0EsU0FBUyxHQUFHQSxTQUFTO0lBQzFCLE9BQU8sSUFBSTtFQUNiOztFQUVBSyxJQUFJQSxDQUFBLEVBQWtCO0lBQ3BCLE9BQU8sSUFBSVIsYUFBYSxDQUFDLElBQUksQ0FBQ0UsTUFBTSxFQUFFLElBQUksQ0FBQ0MsU0FBUyxDQUFDO0VBQ3ZEOztFQUVBTSxNQUFNQSxDQUFBLEVBQVE7SUFDWixPQUFPQyxNQUFNLENBQUNDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUM7RUFDaEM7QUFDRixDQUFDQyxPQUFBLENBQUFDLE9BQUEsR0FBQWIsYUFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/MoneroWallet.d.ts b/dist/src/main/ts/wallet/MoneroWallet.d.ts new file mode 100644 index 000000000..a160e304b --- /dev/null +++ b/dist/src/main/ts/wallet/MoneroWallet.d.ts @@ -0,0 +1,1020 @@ +import MoneroAccount from "./model/MoneroAccount"; +import MoneroAccountTag from "./model/MoneroAccountTag"; +import MoneroAddressBookEntry from "./model/MoneroAddressBookEntry"; +import MoneroCheckReserve from "./model/MoneroCheckReserve"; +import MoneroCheckTx from "./model/MoneroCheckTx"; +import MoneroConnectionManager from "../common/MoneroConnectionManager"; +import MoneroConnectionManagerListener from "../common/MoneroConnectionManagerListener"; +import MoneroIncomingTransfer from "./model/MoneroIncomingTransfer"; +import MoneroIntegratedAddress from "./model/MoneroIntegratedAddress"; +import MoneroKeyImage from "../daemon/model/MoneroKeyImage"; +import MoneroKeyImageImportResult from "./model/MoneroKeyImageImportResult"; +import MoneroMessageSignatureResult from "./model/MoneroMessageSignatureResult"; +import MoneroMessageSignatureType from "./model/MoneroMessageSignatureType"; +import MoneroMultisigInfo from "./model/MoneroMultisigInfo"; +import MoneroMultisigInitResult from "./model/MoneroMultisigInitResult"; +import MoneroMultisigSignResult from "./model/MoneroMultisigSignResult"; +import MoneroOutputQuery from "./model/MoneroOutputQuery"; +import MoneroOutputWallet from "./model/MoneroOutputWallet"; +import MoneroOutgoingTransfer from "./model/MoneroOutgoingTransfer"; +import MoneroRpcConnection from "../common/MoneroRpcConnection"; +import MoneroSubaddress from "./model/MoneroSubaddress"; +import MoneroSyncResult from "./model/MoneroSyncResult"; +import MoneroTransfer from "./model/MoneroTransfer"; +import MoneroTransferQuery from "./model/MoneroTransferQuery"; +import MoneroTxConfig from "./model/MoneroTxConfig"; +import MoneroTxPriority from "./model/MoneroTxPriority"; +import MoneroTxQuery from "./model/MoneroTxQuery"; +import MoneroTxWallet from "./model/MoneroTxWallet"; +import MoneroTxSet from "./model/MoneroTxSet"; +import MoneroVersion from "../daemon/model/MoneroVersion"; +import MoneroWalletListener from "./model/MoneroWalletListener"; +/** + * Copyright (c) woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + * Monero wallet interface and default implementations. + * + * @interface + */ +export default class MoneroWallet { + static readonly DEFAULT_LANGUAGE = "English"; + protected connectionManager: MoneroConnectionManager; + protected connectionManagerListener: MoneroConnectionManagerListener; + protected listeners: MoneroWalletListener[]; + protected _isClosed: boolean; + /** + * Hidden constructor. + * + * @private + */ + constructor(); + /** + * Register a listener to receive wallet notifications. + * + * @param {MoneroWalletListener} listener - listener to receive wallet notifications + * @return {Promise} + */ + addListener(listener: MoneroWalletListener): Promise; + /** + * Unregister a listener to receive wallet notifications. + * + * @param {MoneroWalletListener} listener - listener to unregister + * @return {Promise} + */ + removeListener(listener: any): Promise; + /** + * Get the listeners registered with the wallet. + * + * @return {MoneroWalletListener[]} the registered listeners + */ + getListeners(): MoneroWalletListener[]; + /** + * Indicates if the wallet is view-only, meaning it does not have the private + * spend key and can therefore only observe incoming outputs. + * + * @return {Promise} true if the wallet is view-only, false otherwise + */ + isViewOnly(): Promise; + /** + * Set the wallet's daemon connection. + * + * @param {MoneroRpcConnection | string} [uriOrConnection] - daemon's URI or connection (defaults to offline) + * @return {Promise} + */ + setDaemonConnection(uriOrConnection?: MoneroRpcConnection | string): Promise; + /** + * Get the wallet's daemon connection. + * + * @return {Promise} the wallet's daemon connection + */ + getDaemonConnection(): Promise; + /** + * Set the wallet's daemon connection manager. + * + * @param {MoneroConnectionManager} connectionManager manages connections to monerod + * @return {Promise} + */ + setConnectionManager(connectionManager?: MoneroConnectionManager): Promise; + /** + * Get the wallet's daemon connection manager. + * + * @return {Promise} the wallet's daemon connection manager + */ + getConnectionManager(): Promise; + /** + * Indicates if the wallet is connected to daemon. + * + * @return {Promise} true if the wallet is connected to a daemon, false otherwise + */ + isConnectedToDaemon(): Promise; + /** + * Gets the version of the wallet. + * + * @return {Promise} the version of the wallet + */ + getVersion(): Promise; + /** + * Get the wallet's path. + * + * @return {Promise} the path the wallet can be opened with + */ + getPath(): Promise; + /** + * Get the wallet's mnemonic phrase or seed. + * + * @return {Promise} the wallet's mnemonic phrase or seed. + */ + getSeed(): Promise; + /** + * Get the language of the wallet's mnemonic phrase or seed. + * + * @return {Promise} the language of the wallet's mnemonic phrase or seed. + */ + getSeedLanguage(): Promise; + /** + * Get the wallet's private view key. + * + * @return {Promise} the wallet's private view key + */ + getPrivateViewKey(): Promise; + /** + * Get the wallet's private spend key. + * + * @return {Promise} the wallet's private spend key + */ + getPrivateSpendKey(): Promise; + /** + * Get the wallet's public view key. + * + * @return {Promise} the wallet's public view key + */ + getPublicViewKey(): Promise; + /** + * Get the wallet's public spend key. + * + * @return {Promise} the wallet's public spend key + */ + getPublicSpendKey(): Promise; + /** + * Get the wallet's primary address. + * + * @return {Promise} the wallet's primary address + */ + getPrimaryAddress(): Promise; + /** + * Get the address of a specific subaddress. + * + * @param {number} accountIdx - the account index of the address's subaddress + * @param {number} subaddressIdx - the subaddress index within the account + * @return {Promise} the receive address of the specified subaddress + */ + getAddress(accountIdx: number, subaddressIdx: number): Promise; + /** + * Get the account and subaddress index of the given address. + * + * @param {string} address - address to get the account and subaddress index from + * @return {Promise} the account and subaddress indices + */ + getAddressIndex(address: string): Promise; + /** + * Get an integrated address based on the given standard address and payment + * ID. Uses the wallet's primary address if an address is not given. + * Generates a random payment ID if a payment ID is not given. + * + * @param {string} standardAddress is the standard address to generate the integrated address from (wallet's primary address if undefined) + * @param {string} paymentId is the payment ID to generate an integrated address from (randomly generated if undefined) + * @return {Promise} the integrated address + */ + getIntegratedAddress(standardAddress?: string, paymentId?: string): Promise; + /** + * Decode an integrated address to get its standard address and payment id. + * + * @param {string} integratedAddress - integrated address to decode + * @return {Promise} the decoded integrated address including standard address and payment id + */ + decodeIntegratedAddress(integratedAddress: string): Promise; + /** + * Get the block height that the wallet is synced to. + * + * @return {Promise} the block height that the wallet is synced to + */ + getHeight(): Promise; + /** + * Get the blockchain's height. + * + * @return {Promise} the blockchain's height + */ + getDaemonHeight(): Promise; + /** + * Get the blockchain's height by date as a conservative estimate for scanning. + * + * @param {number} year - year of the height to get + * @param {number} month - month of the height to get as a number between 1 and 12 + * @param {number} day - day of the height to get as a number between 1 and 31 + * @return {Promise} the blockchain's approximate height at the given date + */ + getHeightByDate(year: number, month: number, day: number): Promise; + /** + * Synchronize the wallet with the daemon as a one-time synchronous process. + * + * @param {MoneroWalletListener|number} [listenerOrStartHeight] - listener xor start height (defaults to no sync listener, the last synced block) + * @param {number} [startHeight] - startHeight if not given in first arg (defaults to last synced block) + * @return {Promise} + */ + sync(listenerOrStartHeight?: MoneroWalletListener | number, startHeight?: number): Promise; + /** + * Start background synchronizing with a maximum period between syncs. + * + * @param {number} [syncPeriodInMs] - maximum period between syncs in milliseconds (default is wallet-specific) + * @return {Promise} + */ + startSyncing(syncPeriodInMs?: number): Promise; + /** + * Stop synchronizing the wallet with the daemon. + * + * @return {Promise} + */ + stopSyncing(): Promise; + /** + * Scan transactions by their hash/id. + * + * @param {string[]} txHashes - tx hashes to scan + * @return {Promise} + */ + scanTxs(txHashes: string[]): Promise; + /** + *

Rescan the blockchain for spent outputs.

+ * + *

Note: this can only be called with a trusted daemon.

+ * + *

Example use case: peer multisig hex is import when connected to an untrusted daemon, + * so the wallet will not rescan spent outputs. Then the wallet connects to a trusted + * daemon. This method should be manually invoked to rescan outputs.

+ * + * @return {Promise} + */ + rescanSpent(): Promise; + /** + *

Rescan the blockchain from scratch, losing any information which cannot be recovered from + * the blockchain itself.

+ * + *

WARNING: This method discards local wallet data like destination addresses, tx secret keys, + * tx notes, etc.

+ * + * @return {Promise} + */ + rescanBlockchain(): Promise; + /** + * Get the balance of the wallet, account, or subaddress. + * + * @param {number} [accountIdx] - index of the account to get the balance of (default all accounts) + * @param {number} [subaddressIdx] - index of the subaddress to get the balance of (default all subaddresses) + * @return {Promise} the balance of the wallet, account, or subaddress + */ + getBalance(accountIdx?: number, subaddressIdx?: number): Promise; + /** + * Get the unlocked balance of the wallet, account, or subaddress. + * + * @param {number} [accountIdx] - index of the account to get the unlocked balance of (optional) + * @param {number} [subaddressIdx] - index of the subaddress to get the unlocked balance of (optional) + * @return {Promise} the unlocked balance of the wallet, account, or subaddress + */ + getUnlockedBalance(accountIdx?: number, subaddressIdx?: number): Promise; + /** + * Get the number of blocks until the next and last funds unlock. Ignores txs with unlock time as timestamp. + * + * @return {Promise} the number of blocks until the next and last funds unlock in elements 0 and 1, respectively, or undefined if no balance + */ + getNumBlocksToUnlock(): Promise; + /** + * Get accounts with a given tag. + * + * @param {boolean} includeSubaddresses - include subaddresses if true + * @param {string} tag - tag for filtering accounts, all accounts if undefined + * @return {Promise} all accounts with the given tag + */ + getAccounts(includeSubaddresses?: boolean, tag?: string): Promise; + /** + * Get an account. + * + * @param {number} accountIdx - index of the account to get + * @param {boolean} includeSubaddresses - include subaddresses if true + * @return {Promise} the retrieved account + */ + getAccount(accountIdx: number, includeSubaddresses?: boolean): Promise; + /** + * Create a new account with a label for the first subaddress. + * + * @param {string} [label] - label for account's first subaddress (optional) + * @return {Promise} the created account + */ + createAccount(label?: string): Promise; + /** + * Set an account label. + * + * @param {number} accountIdx - index of the account to set the label for + * @param {string} label - the label to set + * @return {Promise} + */ + setAccountLabel(accountIdx: number, label: string): Promise; + /** + * Get subaddresses in an account. + * + * @param {number} accountIdx - account to get subaddresses within + * @param {number[]} [subaddressIndices] - indices of subaddresses to get (optional) + * @return {Promise} the retrieved subaddresses + */ + getSubaddresses(accountIdx: number, subaddressIndices?: number[]): Promise; + /** + * Get a subaddress. + * + * @param {number} accountIdx - index of the subaddress's account + * @param {number} subaddressIdx - index of the subaddress within the account + * @return {Promise} the retrieved subaddress + */ + getSubaddress(accountIdx: number, subaddressIdx: number): Promise; + /** + * Create a subaddress within an account. + * + * @param {number} accountIdx - index of the account to create the subaddress within + * @param {string} [label] - the label for the subaddress (optional) + * @return {Promise} the created subaddress + */ + createSubaddress(accountIdx: number, label?: string): Promise; + /** + * Set a subaddress label. + * + * @param {number} accountIdx - index of the account to set the label for + * @param {number} subaddressIdx - index of the subaddress to set the label for + * @param {Promise} label - the label to set + */ + setSubaddressLabel(accountIdx: number, subaddressIdx: number, label: string): Promise; + /** + * Get a wallet transaction by hash. + * + * @param {string} txHash - hash of a transaction to get + * @return {Promise } the identified transaction or undefined if not found + */ + getTx(txHash: string): Promise; + /** + *

Get wallet transactions. Wallet transactions contain one or more + * transfers that are either incoming or outgoing to the wallet.

+ * + *

Results can be filtered by passing a query object. Transactions must + * meet every criteria defined in the query in order to be returned. All + * criteria are optional and no filtering is applied when not defined.

+ * + * @param {string[] | MoneroTxQuery} [query] - configures the query (optional) + * @param {boolean} [query.isConfirmed] - get txs that are confirmed or not (optional) + * @param {boolean} [query.inTxPool] - get txs that are in the tx pool or not (optional) + * @param {boolean} [query.isRelayed] - get txs that are relayed or not (optional) + * @param {boolean} [query.isFailed] - get txs that are failed or not (optional) + * @param {boolean} [query.isMinerTx] - get miner txs or not (optional) + * @param {string} [query.hash] - get a tx with the hash (optional) + * @param {string[]} [query.hashes] - get txs with the hashes (optional) + * @param {string} [query.paymentId] - get transactions with the payment id (optional) + * @param {string[]} [query.paymentIds] - get transactions with the payment ids (optional) + * @param {boolean} [query.hasPaymentId] - get transactions with a payment id or not (optional) + * @param {number} [query.minHeight] - get txs with height >= the given height (optional) + * @param {number} [query.maxHeight] - get txs with height <= the given height (optional) + * @param {boolean} [query.isOutgoing] - get txs with an outgoing transfer or not (optional) + * @param {boolean} [query.isIncoming] - get txs with an incoming transfer or not (optional) + * @param {MoneroTransferQuery} [query.transferQuery] - get txs that have a transfer that meets this query (optional) + * @param {boolean} [query.includeOutputs] - specifies that tx outputs should be returned with tx results (optional) + * @return {Promise} wallet transactions per the configuration + */ + getTxs(query?: string[] | Partial): Promise; + /** + *

Get incoming and outgoing transfers to and from this wallet. An outgoing + * transfer represents a total amount sent from one or more subaddresses + * within an account to individual destination addresses, each with their + * own amount. An incoming transfer represents a total amount received into + * a subaddress within an account. Transfers belong to transactions which + * are stored on the blockchain.

+ * + *

Results can be filtered by passing a query object. Transfers must + * meet every criteria defined in the query in order to be returned. All + * criteria are optional and no filtering is applied when not defined.

+ * + * @param {MoneroTransferQuery} [query] - configures the query (optional) + * @param {boolean} [query.isOutgoing] - get transfers that are outgoing or not (optional) + * @param {boolean} [query.isIncoming] - get transfers that are incoming or not (optional) + * @param {string} [query.address] - wallet's address that a transfer either originated from (if outgoing) or is destined for (if incoming) (optional) + * @param {number} [query.accountIndex] - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific account index (optional) + * @param {number} [query.subaddressIndex] - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific subaddress index (optional) + * @param {int[]} [query.subaddressIndices] - get transfers that either originated from (if outgoing) or are destined for (if incoming) specific subaddress indices (optional) + * @param {bigint} [query.amount] - amount being transferred (optional) + * @param {MoneroDestination[] | MoneroDestinationModel[]} [query.destinations] - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional) + * @param {boolean} [query.hasDestinations] - get transfers that have destinations or not (optional) + * @param {MoneroTxQuery} [query.txQuery] - get transfers whose transaction meets this query (optional) + * @return {Promise} wallet transfers that meet the query + */ + getTransfers(query?: Partial): Promise; + /** + * Get incoming transfers. + * + * @param {Partial} [query] - configures the query (optional) + * @param {string} [query.address] - get incoming transfers to a specific address in the wallet (optional) + * @param {number} [query.accountIndex] - get incoming transfers to a specific account index (optional) + * @param {number} [query.subaddressIndex] - get incoming transfers to a specific subaddress index (optional) + * @param {int[]} [query.subaddressIndices] - get transfers destined for specific subaddress indices (optional) + * @param {bigint} [query.amount] - amount being transferred (optional) + * @param {MoneroTxQuery} [query.txQuery] - get transfers whose transaction meets this query (optional) + * @return {Promise} incoming transfers that meet the query + */ + getIncomingTransfers(query?: Partial): Promise; + /** + * Get outgoing transfers. + * + * @param {Partial} [query] - configures the query (optional) + * @param {string} [query.address] - get outgoing transfers from a specific address in the wallet (optional) + * @param {number} [query.accountIndex] - get outgoing transfers from a specific account index (optional) + * @param {number} [query.subaddressIndex] - get outgoing transfers from a specific subaddress index (optional) + * @param {int[]} [query.subaddressIndices] - get outgoing transfers from specific subaddress indices (optional) + * @param {bigint} [query.amount] - amount being transferred (optional) + * @param {MoneroDestination[] | MoneroDestinationModel[]} [query.destinations] - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional) + * @param {boolean} [query.hasDestinations] - get transfers that have destinations or not (optional) + * @param {MoneroTxQuery} [query.txQuery] - get transfers whose transaction meets this query (optional) + * @return {Promise} outgoing transfers that meet the query + */ + getOutgoingTransfers(query?: Partial): Promise; + /** + *

Get outputs created from previous transactions that belong to the wallet + * (i.e. that the wallet can spend one time). Outputs are part of + * transactions which are stored in blocks on the blockchain.

+ * + *

Results can be filtered by passing a query object. Outputs must + * meet every criteria defined in the query in order to be returned. All + * filtering is optional and no filtering is applied when not defined.

+ * + * @param {Parital} [query] - configures the query (optional) + * @param {number} [query.accountIndex] - get outputs associated with a specific account index (optional) + * @param {number} [query.subaddressIndex] - get outputs associated with a specific subaddress index (optional) + * @param {int[]} [query.subaddressIndices] - get outputs associated with specific subaddress indices (optional) + * @param {bigint} [query.amount] - get outputs with a specific amount (optional) + * @param {bigint} [query.minAmount] - get outputs greater than or equal to a minimum amount (optional) + * @param {bigint} [query.maxAmount] - get outputs less than or equal to a maximum amount (optional) + * @param {boolean} [query.isSpent] - get outputs that are spent or not (optional) + * @param {string|MoneroKeyImage} [query.keyImage] - get output with a key image or which matches fields defined in a MoneroKeyImage (optional) + * @param {MoneroTxQuery} [query.txQuery] - get outputs whose transaction meets this filter (optional) + * @return {Promise} the queried outputs + */ + getOutputs(query?: Partial): Promise; + /** + * Export outputs in hex format. + * + * @param {boolean} [all] - export all outputs if true, else export the outputs since the last export (default false) + * @return {Promise} outputs in hex format + */ + exportOutputs(all?: boolean): Promise; + /** + * Import outputs in hex format. + * + * @param {string} outputsHex - outputs in hex format + * @return {Promise} the number of outputs imported + */ + importOutputs(outputsHex: string): Promise; + /** + * Export signed key images. + * + * @param {boolean} [all] - export all key images if true, else export the key images since the last export (default false) + * @return {Promise} the wallet's signed key images + */ + exportKeyImages(all?: boolean): Promise; + /** + * Import signed key images and verify their spent status. + * + * @param {MoneroKeyImage[]} keyImages - images to import and verify (requires hex and signature) + * @return {Promise} results of the import + */ + importKeyImages(keyImages: MoneroKeyImage[]): Promise; + /** + * Get new key images from the last imported outputs. + * + * @return {Promise} the key images from the last imported outputs + */ + getNewKeyImagesFromLastImport(): Promise; + /** + * Freeze an output. + * + * @param {string} keyImage - key image of the output to freeze + * @return {Promise} + */ + freezeOutput(keyImage: string): Promise; + /** + * Thaw a frozen output. + * + * @param {string} keyImage - key image of the output to thaw + * @return {Promise} + */ + thawOutput(keyImage: string): Promise; + /** + * Check if an output is frozen. + * + * @param {string} keyImage - key image of the output to check if frozen + * @return {Promise} true if the output is frozen, false otherwise + */ + isOutputFrozen(keyImage: string): Promise; + /** + * Get the current default fee priority (unimportant, normal, elevated, etc). + * + * @return {Promise} the current fee priority + */ + getDefaultFeePriority(): Promise; + /** + * Create a transaction to transfer funds from this wallet. + * + * @param {MoneroTxConfig} config - configures the transaction to create (required) + * @param {string} config.address - single destination address (required unless `destinations` provided) + * @param {bigint|string} config.amount - single destination amount (required unless `destinations` provided) + * @param {number} config.accountIndex - source account index to transfer funds from (required) + * @param {number} [config.subaddressIndex] - source subaddress index to transfer funds from (optional) + * @param {number[]} [config.subaddressIndices] - source subaddress indices to transfer funds from (optional) + * @param {boolean} [config.relay] - relay the transaction to peers to commit to the blockchain (default false) + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided) + * @param {number[]} [config.subtractFeeFrom] - list of destination indices to split the transaction fee (optional) + * @param {string} [config.paymentId] - transaction payment ID (optional) + * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transaction to unlock (default 0) + * @return {Promise} the created transaction + */ + createTx(config: Partial): Promise; + /** + * Create one or more transactions to transfer funds from this wallet. + * + * @param {Partial} config - configures the transactions to create (required) + * @param {string} config.address - single destination address (required unless `destinations` provided) + * @param {bigint|string} config.amount - single destination amount (required unless `destinations` provided) + * @param {number} config.accountIndex - source account index to transfer funds from (required) + * @param {number} [config.subaddressIndex] - source subaddress index to transfer funds from (optional) + * @param {int[]} [config.subaddressIndices] - source subaddress indices to transfer funds from (optional) + * @param {boolean} [config.relay] - relay the transactions to peers to commit to the blockchain (default false) + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @param {MoneroDestination[] | MoneroDestinationModel[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided) + * @param {string} [config.paymentId] - transaction payment ID (optional) + * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transactions to unlock (default 0) + * @param {boolean} [config.canSplit] - allow funds to be transferred using multiple transactions (default true) + * @return {Promise} the created transactions + */ + createTxs(config: Partial): Promise; + /** + * Sweep an output by key image. + * + * @param {Partial} config - configures the transaction to create (required) + * @param {string} config.address - single destination address (required) + * @param {string} config.keyImage - key image to sweep (required) + * @param {boolean} [config.relay] - relay the transaction to peers to commit to the blockchain (default false) + * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transaction to unlock (default 0) + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @return {Promise} the created transaction + */ + sweepOutput(config: Partial): Promise; + /** + * Sweep all unlocked funds according to the given configuration. + * + * @param {Partial} config - configures the transactions to create (required) + * @param {string} config.address - single destination address (required) + * @param {number} [config.accountIndex] - source account index to sweep from (optional, defaults to all accounts) + * @param {number} [config.subaddressIndex] - source subaddress index to sweep from (optional, defaults to all subaddresses) + * @param {number[]} [config.subaddressIndices] - source subaddress indices to sweep from (optional) + * @param {boolean} [config.relay] - relay the transactions to peers to commit to the blockchain (default false) + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transactions to unlock (default 0) + * @param {boolean} [config.sweepEachSubaddress] - sweep each subaddress individually if true (default false) + * @return {Promise} the created transactions + */ + sweepUnlocked(config: Partial): Promise; + /** + *

Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

+ * + *

NOTE: Dust only exists pre RCT, so this method will throw "no dust to sweep" on new wallets.

+ * + * @param {boolean} [relay] - specifies if the resulting transaction should be relayed (default false) + * @return {Promise} the created transactions + */ + sweepDust(relay?: boolean): Promise; + /** + * Relay a previously created transaction. + * + * @param {(MoneroTxWallet | string)} txOrMetadata - transaction or its metadata to relay + * @return {Promise} the hash of the relayed tx + */ + relayTx(txOrMetadata: MoneroTxWallet | string): Promise; + /** + * Relay previously created transactions. + * + * @param {(MoneroTxWallet[] | string[])} txsOrMetadatas - transactions or their metadata to relay + * @return {Promise} the hashes of the relayed txs + */ + relayTxs(txsOrMetadatas: (MoneroTxWallet | string)[]): Promise; + /** + * Describe a tx set from unsigned tx hex. + * + * @param {string} unsignedTxHex - unsigned tx hex + * @return {Promise} the tx set containing structured transactions + */ + describeUnsignedTxSet(unsignedTxHex: string): Promise; + /** + * Describe a tx set from multisig tx hex. + * + * @param {string} multisigTxHex - multisig tx hex + * @return {Promise} the tx set containing structured transactions + */ + describeMultisigTxSet(multisigTxHex: string): Promise; + /** + * Describe a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions. + * + * @param {MoneroTxSet} txSet - a tx set containing unsigned or multisig tx hex + * @return {Promise} txSet - the tx set containing structured transactions + */ + describeTxSet(txSet: MoneroTxSet): Promise; + /** + * Sign unsigned transactions from a view-only wallet. + * + * @param {string} unsignedTxHex - unsigned transaction hex from when the transactions were created + * @return {Promise} the signed transaction set + */ + signTxs(unsignedTxHex: string): Promise; + /** + * Submit signed transactions from a view-only wallet. + * + * @param {string} signedTxHex - signed transaction hex from signTxs() + * @return {Promise} the resulting transaction hashes + */ + submitTxs(signedTxHex: string): Promise; + /** + * Sign a message. + * + * @param {string} message - the message to sign + * @param {MoneroMessageSignatureType} [signatureType] - sign with spend key or view key (default spend key) + * @param {number} [accountIdx] - the account index of the message signature (default 0) + * @param {number} [subaddressIdx] - the subaddress index of the message signature (default 0) + * @return {Promise} the signature + */ + signMessage(message: string, signatureType?: MoneroMessageSignatureType, accountIdx?: number, subaddressIdx?: number): Promise; + /** + * Verify a signature on a message. + * + * @param {string} message - signed message + * @param {string} address - signing address + * @param {string} signature - signature + * @return {Promise} true if the signature is good, false otherwise + */ + verifyMessage(message: string, address: string, signature: string): Promise; + /** + * Get a transaction's secret key from its hash. + * + * @param {string} txHash - transaction's hash + * @return {Promise} - transaction's secret key + */ + getTxKey(txHash: string): Promise; + /** + * Check a transaction in the blockchain with its secret key. + * + * @param {string} txHash - transaction to check + * @param {string} txKey - transaction's secret key + * @param {string} address - destination public address of the transaction + * @return {romise} the result of the check + */ + checkTxKey(txHash: string, txKey: string, address: string): Promise; + /** + * Get a transaction signature to prove it. + * + * @param {string} txHash - transaction to prove + * @param {string} address - destination public address of the transaction + * @param {string} [message] - message to include with the signature to further authenticate the proof (optional) + * @return {Promise} the transaction signature + */ + getTxProof(txHash: string, address: string, message?: string): Promise; + /** + * Prove a transaction by checking its signature. + * + * @param {string} txHash - transaction to prove + * @param {string} address - destination public address of the transaction + * @param {string | undefined} message - message included with the signature to further authenticate the proof + * @param {string} signature - transaction signature to confirm + * @return {Promise} the result of the check + */ + checkTxProof(txHash: string, address: string, message: string | undefined, signature: string): Promise; + /** + * Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address. + * + * @param {string} txHash - transaction to prove + * @param {string} [message] - message to include with the signature to further authenticate the proof (optional) + * @return {Promise} the transaction signature + */ + getSpendProof(txHash: string, message?: string): Promise; + /** + * Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address. + * + * @param {string} txHash - transaction to prove + * @param {string | undefined} message - message included with the signature to further authenticate the proof (optional) + * @param {string} signature - transaction signature to confirm + * @return {Promise} true if the signature is good, false otherwise + */ + checkSpendProof(txHash: string, message: string | undefined, signature: string): Promise; + /** + * Generate a signature to prove the entire balance of the wallet. + * + * @param {string} [message] - message included with the signature to further authenticate the proof (optional) + * @return {Promise} the reserve proof signature + */ + getReserveProofWallet(message?: string): Promise; + /** + * Generate a signature to prove an available amount in an account. + * + * @param {number} accountIdx - account to prove ownership of the amount + * @param {bigint} amount - minimum amount to prove as available in the account + * @param {string} [message] - message to include with the signature to further authenticate the proof (optional) + * @return {Promise} the reserve proof signature + */ + getReserveProofAccount(accountIdx: number, amount: bigint, message?: string): Promise; + /** + * Proves a wallet has a disposable reserve using a signature. + * + * @param {string} address - public wallet address + * @param {string | undefined} message - message included with the signature to further authenticate the proof (optional) + * @param {string} signature - reserve proof signature to check + * @return {Promise} the result of checking the signature proof + */ + checkReserveProof(address: string, message: string | undefined, signature: string): Promise; + /** + * Get a transaction note. + * + * @param {string} txHash - transaction to get the note of + * @return {Promise} the tx note + */ + getTxNote(txHash: string): Promise; + /** + * Get notes for multiple transactions. + * + * @param {string[]} txHashes - hashes of the transactions to get notes for + * @return {Promise} notes for the transactions + */ + getTxNotes(txHashes: string[]): Promise; + /** + * Set a note for a specific transaction. + * + * @param {string} txHash - hash of the transaction to set a note for + * @param {string} note - the transaction note + * @return {Promise} + */ + setTxNote(txHash: string, note: string): Promise; + /** + * Set notes for multiple transactions. + * + * @param {string[]} txHashes - transactions to set notes for + * @param {string[]} notes - notes to set for the transactions + * @return {Promise} + */ + setTxNotes(txHashes: string[], notes: string[]): Promise; + /** + * Get address book entries. + * + * @param {number[]} [entryIndices] - indices of the entries to get + * @return {Promise} the address book entries + */ + getAddressBookEntries(entryIndices?: number[]): Promise; + /** + * Add an address book entry. + * + * @param {string} address - entry address + * @param {string} [description] - entry description (optional) + * @return {Promise} the index of the added entry + */ + addAddressBookEntry(address: string, description?: string): Promise; + /** + * Edit an address book entry. + * + * @param {number} index - index of the address book entry to edit + * @param {boolean} setAddress - specifies if the address should be updated + * @param {string | undefined} address - updated address + * @param {boolean} setDescription - specifies if the description should be updated + * @param {string | undefined} description - updated description + * @return {Promise} + */ + editAddressBookEntry(index: number, setAddress: boolean, address: string | undefined, setDescription: boolean, description: string | undefined): Promise; + /** + * Delete an address book entry. + * + * @param {number} entryIdx - index of the entry to delete + * @return {Promise} + */ + deleteAddressBookEntry(entryIdx: number): Promise; + /** + * Tag accounts. + * + * @param {string} tag - tag to apply to the specified accounts + * @param {number[]} accountIndices - indices of the accounts to tag + * @return {Promise} + */ + tagAccounts(tag: string, accountIndices: number[]): Promise; + /** + * Untag accounts. + * + * @param {number[]} accountIndices - indices of the accounts to untag + * @return {Promise} + */ + untagAccounts(accountIndices: number[]): Promise; + /** + * Return all account tags. + * + * @return {Promise} the wallet's account tags + */ + getAccountTags(): Promise; + /** + * Sets a human-readable description for a tag. + * + * @param {string} tag - tag to set a description for + * @param {string} label - label to set for the tag + * @return {Promise} + */ + setAccountTagLabel(tag: string, label: string): Promise; + /** + * Creates a payment URI from a send configuration. + * + * @param {MoneroTxConfig} config - specifies configuration for a potential tx + * @return {Promise} the payment uri + */ + getPaymentUri(config: MoneroTxConfig): Promise; + /** + * Parses a payment URI to a tx config. + * + * @param {string} uri - payment uri to parse + * @return {Promise} the send configuration parsed from the uri + */ + parsePaymentUri(uri: string): Promise; + /** + * Get an attribute. + * + * @param {string} key - attribute to get the value of + * @return {Promise} the attribute's value + */ + getAttribute(key: string): Promise; + /** + * Set an arbitrary attribute. + * + * @param {string} key - attribute key + * @param {string} val - attribute value + * @return {Promise} + */ + setAttribute(key: string, val: string): Promise; + /** + * Start mining. + * + * @param {number} [numThreads] - number of threads created for mining (optional) + * @param {boolean} [backgroundMining] - specifies if mining should occur in the background (optional) + * @param {boolean} [ignoreBattery] - specifies if the battery should be ignored for mining (optional) + * @return {Promise} + */ + startMining(numThreads: number, backgroundMining?: boolean, ignoreBattery?: boolean): Promise; + /** + * Stop mining. + * + * @return {Promise} + */ + stopMining(): Promise; + /** + * Indicates if importing multisig data is needed for returning a correct balance. + * + * @return {Promise} true if importing multisig data is needed for returning a correct balance, false otherwise + */ + isMultisigImportNeeded(): Promise; + /** + * Indicates if this wallet is a multisig wallet. + * + * @return {Promise} true if this is a multisig wallet, false otherwise + */ + isMultisig(): Promise; + /** + * Get multisig info about this wallet. + * + * @return {Promise} multisig info about this wallet + */ + getMultisigInfo(): Promise; + /** + * Get multisig info as hex to share with participants to begin creating a + * multisig wallet. + * + * @return {Promise} this wallet's multisig hex to share with participants + */ + prepareMultisig(): Promise; + /** + * Make this wallet multisig by importing multisig hex from participants. + * + * @param {string[]} multisigHexes - multisig hex from each participant + * @param {number} threshold - number of signatures needed to sign transfers + * @param {string} password - wallet password + * @return {Promise} this wallet's multisig hex to share with participants + */ + makeMultisig(multisigHexes: string[], threshold: number, password: string): Promise; + /** + * Exchange multisig hex with participants in a M/N multisig wallet. + * + * This process must be repeated with participants exactly N-M times. + * + * @param {string[]} multisigHexes are multisig hex from each participant + * @param {string} password - wallet's password // TODO monero-project: redundant? wallet is created with password + * @return {Promise} the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done + */ + exchangeMultisigKeys(multisigHexes: string[], password: string): Promise; + /** + * Export this wallet's multisig info as hex for other participants. + * + * @return {Promise} this wallet's multisig info as hex for other participants + */ + exportMultisigHex(): Promise; + /** + * Import multisig info as hex from other participants. + * + * @param {string[]} multisigHexes - multisig hex from each participant + * @return {Promise} the number of outputs signed with the given multisig hex + */ + importMultisigHex(multisigHexes: string[]): Promise; + /** + * Sign multisig transactions from a multisig wallet. + * + * @param {string} multisigTxHex - unsigned multisig transactions as hex + * @return {MoneroMultisigSignResult} the result of signing the multisig transactions + */ + signMultisigTxHex(multisigTxHex: string): Promise; + /** + * Submit signed multisig transactions from a multisig wallet. + * + * @param {string} signedMultisigTxHex - signed multisig hex returned from signMultisigTxHex() + * @return {Promise} the resulting transaction hashes + */ + submitMultisigTxHex(signedMultisigTxHex: string): Promise; + /** + * Change the wallet password. + * + * @param {string} oldPassword - the wallet's old password + * @param {string} newPassword - the wallet's new password + * @return {Promise} + */ + changePassword(oldPassword: string, newPassword: string): Promise; + /** + * Save the wallet at its current path. + * + * @return {Promise} + */ + save(): Promise; + /** + * Optionally save then close the wallet. + * + * @param {boolean} [save] - specifies if the wallet should be saved before being closed (default false) + * @return {Promise} + */ + close(save?: boolean): Promise; + /** + * Indicates if this wallet is closed or not. + * + * @return {Promise} true if the wallet is closed, false otherwise + */ + isClosed(): Promise; + /** + * @private + */ + announceSyncProgress(height: number, startHeight: number, endHeight: number, percentDone: number, message: string): Promise; + /** + * @private + */ + announceNewBlock(height: number): Promise; + /** + * @private + */ + announceBalancesChanged(newBalance: bigint, newUnlockedBalance: bigint): Promise; + /** + * @private + */ + announceOutputReceived(output: MoneroOutputWallet): Promise; + /** + * @private + */ + announceOutputSpent(output: MoneroOutputWallet): Promise; + protected static normalizeTxQuery(query: any): MoneroTxQuery; + protected static normalizeTransferQuery(query: any): MoneroTransferQuery; + protected static normalizeOutputQuery(query: any): MoneroOutputQuery; + protected static normalizeCreateTxsConfig(config: any): MoneroTxConfig; + protected static normalizeSweepOutputConfig(config: any): MoneroTxConfig; + protected static normalizeSweepUnlockedConfig(config: any): MoneroTxConfig; +} diff --git a/dist/src/main/ts/wallet/MoneroWallet.js b/dist/src/main/ts/wallet/MoneroWallet.js new file mode 100644 index 000000000..de4ae327c --- /dev/null +++ b/dist/src/main/ts/wallet/MoneroWallet.js @@ -0,0 +1,1548 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); + + + + +var _MoneroBlock = _interopRequireDefault(require("../daemon/model/MoneroBlock")); + + + +var _MoneroConnectionManagerListener = _interopRequireDefault(require("../common/MoneroConnectionManagerListener")); +var _MoneroError = _interopRequireDefault(require("../common/MoneroError")); + + + + + +var _MoneroMessageSignatureType = _interopRequireDefault(require("./model/MoneroMessageSignatureType")); + + + +var _MoneroOutputQuery = _interopRequireDefault(require("./model/MoneroOutputQuery")); + + + + + + +var _MoneroTransferQuery = _interopRequireDefault(require("./model/MoneroTransferQuery")); +var _MoneroTxConfig = _interopRequireDefault(require("./model/MoneroTxConfig")); + +var _MoneroTxQuery = _interopRequireDefault(require("./model/MoneroTxQuery")); + +var _MoneroTxSet = _interopRequireDefault(require("./model/MoneroTxSet")); +var _MoneroUtils = _interopRequireDefault(require("../common/MoneroUtils")); + +var _MoneroWalletListener = _interopRequireDefault(require("./model/MoneroWalletListener")); + +/** + * Copyright (c) woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Monero wallet interface and default implementations. + * + * @interface + */ +class MoneroWallet { + + // static variables + static DEFAULT_LANGUAGE = "English"; + + // state variables + + + listeners = []; + _isClosed = false; + + /** + * Hidden constructor. + * + * @private + */ + constructor() { + + // no code needed + } + /** + * Register a listener to receive wallet notifications. + * + * @param {MoneroWalletListener} listener - listener to receive wallet notifications + * @return {Promise} + */ + async addListener(listener) { + (0, _assert.default)(listener instanceof _MoneroWalletListener.default, "Listener must be instance of MoneroWalletListener"); + this.listeners.push(listener); + } + + /** + * Unregister a listener to receive wallet notifications. + * + * @param {MoneroWalletListener} listener - listener to unregister + * @return {Promise} + */ + async removeListener(listener) { + let idx = this.listeners.indexOf(listener); + if (idx > -1) this.listeners.splice(idx, 1);else + throw new _MoneroError.default("Listener is not registered with wallet"); + } + + /** + * Get the listeners registered with the wallet. + * + * @return {MoneroWalletListener[]} the registered listeners + */ + getListeners() { + return this.listeners; + } + + /** + * Indicates if the wallet is view-only, meaning it does not have the private + * spend key and can therefore only observe incoming outputs. + * + * @return {Promise} true if the wallet is view-only, false otherwise + */ + async isViewOnly() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Set the wallet's daemon connection. + * + * @param {MoneroRpcConnection | string} [uriOrConnection] - daemon's URI or connection (defaults to offline) + * @return {Promise} + */ + async setDaemonConnection(uriOrConnection) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the wallet's daemon connection. + * + * @return {Promise} the wallet's daemon connection + */ + async getDaemonConnection() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Set the wallet's daemon connection manager. + * + * @param {MoneroConnectionManager} connectionManager manages connections to monerod + * @return {Promise} + */ + async setConnectionManager(connectionManager) { + if (this.connectionManager) this.connectionManager.removeListener(this.connectionManagerListener); + this.connectionManager = connectionManager; + if (!connectionManager) return; + let that = this; + if (!this.connectionManagerListener) this.connectionManagerListener = new class extends _MoneroConnectionManagerListener.default { + async onConnectionChanged(connection) { + await that.setDaemonConnection(connection); + } + }(); + connectionManager.addListener(this.connectionManagerListener); + await this.setDaemonConnection(connectionManager.getConnection()); + } + + /** + * Get the wallet's daemon connection manager. + * + * @return {Promise} the wallet's daemon connection manager + */ + async getConnectionManager() { + return this.connectionManager; + } + + /** + * Indicates if the wallet is connected to daemon. + * + * @return {Promise} true if the wallet is connected to a daemon, false otherwise + */ + async isConnectedToDaemon() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Gets the version of the wallet. + * + * @return {Promise} the version of the wallet + */ + async getVersion() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the wallet's path. + * + * @return {Promise} the path the wallet can be opened with + */ + async getPath() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the wallet's mnemonic phrase or seed. + * + * @return {Promise} the wallet's mnemonic phrase or seed. + */ + async getSeed() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the language of the wallet's mnemonic phrase or seed. + * + * @return {Promise} the language of the wallet's mnemonic phrase or seed. + */ + async getSeedLanguage() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the wallet's private view key. + * + * @return {Promise} the wallet's private view key + */ + async getPrivateViewKey() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the wallet's private spend key. + * + * @return {Promise} the wallet's private spend key + */ + async getPrivateSpendKey() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the wallet's public view key. + * + * @return {Promise} the wallet's public view key + */ + async getPublicViewKey() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the wallet's public spend key. + * + * @return {Promise} the wallet's public spend key + */ + async getPublicSpendKey() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the wallet's primary address. + * + * @return {Promise} the wallet's primary address + */ + async getPrimaryAddress() { + return await this.getAddress(0, 0); + } + + /** + * Get the address of a specific subaddress. + * + * @param {number} accountIdx - the account index of the address's subaddress + * @param {number} subaddressIdx - the subaddress index within the account + * @return {Promise} the receive address of the specified subaddress + */ + async getAddress(accountIdx, subaddressIdx) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the account and subaddress index of the given address. + * + * @param {string} address - address to get the account and subaddress index from + * @return {Promise} the account and subaddress indices + */ + async getAddressIndex(address) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get an integrated address based on the given standard address and payment + * ID. Uses the wallet's primary address if an address is not given. + * Generates a random payment ID if a payment ID is not given. + * + * @param {string} standardAddress is the standard address to generate the integrated address from (wallet's primary address if undefined) + * @param {string} paymentId is the payment ID to generate an integrated address from (randomly generated if undefined) + * @return {Promise} the integrated address + */ + async getIntegratedAddress(standardAddress, paymentId) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Decode an integrated address to get its standard address and payment id. + * + * @param {string} integratedAddress - integrated address to decode + * @return {Promise} the decoded integrated address including standard address and payment id + */ + async decodeIntegratedAddress(integratedAddress) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the block height that the wallet is synced to. + * + * @return {Promise} the block height that the wallet is synced to + */ + async getHeight() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the blockchain's height. + * + * @return {Promise} the blockchain's height + */ + async getDaemonHeight() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the blockchain's height by date as a conservative estimate for scanning. + * + * @param {number} year - year of the height to get + * @param {number} month - month of the height to get as a number between 1 and 12 + * @param {number} day - day of the height to get as a number between 1 and 31 + * @return {Promise} the blockchain's approximate height at the given date + */ + async getHeightByDate(year, month, day) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Synchronize the wallet with the daemon as a one-time synchronous process. + * + * @param {MoneroWalletListener|number} [listenerOrStartHeight] - listener xor start height (defaults to no sync listener, the last synced block) + * @param {number} [startHeight] - startHeight if not given in first arg (defaults to last synced block) + * @return {Promise} + */ + async sync(listenerOrStartHeight, startHeight) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Start background synchronizing with a maximum period between syncs. + * + * @param {number} [syncPeriodInMs] - maximum period between syncs in milliseconds (default is wallet-specific) + * @return {Promise} + */ + async startSyncing(syncPeriodInMs) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Stop synchronizing the wallet with the daemon. + * + * @return {Promise} + */ + async stopSyncing() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Scan transactions by their hash/id. + * + * @param {string[]} txHashes - tx hashes to scan + * @return {Promise} + */ + async scanTxs(txHashes) { + throw new _MoneroError.default("Not supported"); + } + + /** + *

Rescan the blockchain for spent outputs.

+ * + *

Note: this can only be called with a trusted daemon.

+ * + *

Example use case: peer multisig hex is import when connected to an untrusted daemon, + * so the wallet will not rescan spent outputs. Then the wallet connects to a trusted + * daemon. This method should be manually invoked to rescan outputs.

+ * + * @return {Promise} + */ + async rescanSpent() { + throw new _MoneroError.default("Not supported"); + } + + /** + *

Rescan the blockchain from scratch, losing any information which cannot be recovered from + * the blockchain itself.

+ * + *

WARNING: This method discards local wallet data like destination addresses, tx secret keys, + * tx notes, etc.

+ * + * @return {Promise} + */ + async rescanBlockchain() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the balance of the wallet, account, or subaddress. + * + * @param {number} [accountIdx] - index of the account to get the balance of (default all accounts) + * @param {number} [subaddressIdx] - index of the subaddress to get the balance of (default all subaddresses) + * @return {Promise} the balance of the wallet, account, or subaddress + */ + async getBalance(accountIdx, subaddressIdx) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the unlocked balance of the wallet, account, or subaddress. + * + * @param {number} [accountIdx] - index of the account to get the unlocked balance of (optional) + * @param {number} [subaddressIdx] - index of the subaddress to get the unlocked balance of (optional) + * @return {Promise} the unlocked balance of the wallet, account, or subaddress + */ + async getUnlockedBalance(accountIdx, subaddressIdx) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the number of blocks until the next and last funds unlock. Ignores txs with unlock time as timestamp. + * + * @return {Promise} the number of blocks until the next and last funds unlock in elements 0 and 1, respectively, or undefined if no balance + */ + async getNumBlocksToUnlock() { + + // get balances + let balance = await this.getBalance(); + if (balance === 0n) return [undefined, undefined]; // skip if no balance + let unlockedBalance = await this.getUnlockedBalance(); + + // compute number of blocks until next funds available + let txs; + let height; + let numBlocksToNextUnlock = undefined; + if (unlockedBalance > 0n) numBlocksToNextUnlock = 0;else + { + txs = await this.getTxs({ isLocked: true }); // get locked txs + height = await this.getHeight(); // get most recent height + for (let tx of txs) { + if (!tx.getIsConfirmed() && _MoneroUtils.default.isTimestamp(tx.getUnlockTime())) continue; + let numBlocksToUnlock = Math.max((tx.getIsConfirmed() ? tx.getHeight() : height) + 10, Number(tx.getUnlockTime())) - height; + numBlocksToNextUnlock = numBlocksToNextUnlock === undefined ? numBlocksToUnlock : Math.min(numBlocksToNextUnlock, numBlocksToUnlock); + } + } + + // compute number of blocks until all funds available + let numBlocksToLastUnlock = undefined; + if (balance === unlockedBalance) { + if (unlockedBalance > 0n) numBlocksToLastUnlock = 0; + } else { + if (!txs) { + txs = await this.getTxs({ isLocked: true }); // get locked txs + height = await this.getHeight(); // get most recent height + } + for (let tx of txs) { + if (!tx.getIsConfirmed() && _MoneroUtils.default.isTimestamp(tx.getUnlockTime())) continue; + let numBlocksToUnlock = Math.max((tx.getIsConfirmed() ? tx.getHeight() : height) + 10, Number(tx.getUnlockTime())) - height; + numBlocksToLastUnlock = numBlocksToLastUnlock === undefined ? numBlocksToUnlock : Math.max(numBlocksToLastUnlock, numBlocksToUnlock); + } + } + + return [numBlocksToNextUnlock, numBlocksToLastUnlock]; + } + + /** + * Get accounts with a given tag. + * + * @param {boolean} includeSubaddresses - include subaddresses if true + * @param {string} tag - tag for filtering accounts, all accounts if undefined + * @return {Promise} all accounts with the given tag + */ + async getAccounts(includeSubaddresses, tag) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get an account. + * + * @param {number} accountIdx - index of the account to get + * @param {boolean} includeSubaddresses - include subaddresses if true + * @return {Promise} the retrieved account + */ + async getAccount(accountIdx, includeSubaddresses) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Create a new account with a label for the first subaddress. + * + * @param {string} [label] - label for account's first subaddress (optional) + * @return {Promise} the created account + */ + async createAccount(label) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Set an account label. + * + * @param {number} accountIdx - index of the account to set the label for + * @param {string} label - the label to set + * @return {Promise} + */ + async setAccountLabel(accountIdx, label) { + await this.setSubaddressLabel(accountIdx, 0, label); + } + + /** + * Get subaddresses in an account. + * + * @param {number} accountIdx - account to get subaddresses within + * @param {number[]} [subaddressIndices] - indices of subaddresses to get (optional) + * @return {Promise} the retrieved subaddresses + */ + async getSubaddresses(accountIdx, subaddressIndices) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get a subaddress. + * + * @param {number} accountIdx - index of the subaddress's account + * @param {number} subaddressIdx - index of the subaddress within the account + * @return {Promise} the retrieved subaddress + */ + async getSubaddress(accountIdx, subaddressIdx) { + (0, _assert.default)(accountIdx >= 0); + (0, _assert.default)(subaddressIdx >= 0); + return (await this.getSubaddresses(accountIdx, [subaddressIdx]))[0]; + } + + /** + * Create a subaddress within an account. + * + * @param {number} accountIdx - index of the account to create the subaddress within + * @param {string} [label] - the label for the subaddress (optional) + * @return {Promise} the created subaddress + */ + async createSubaddress(accountIdx, label) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Set a subaddress label. + * + * @param {number} accountIdx - index of the account to set the label for + * @param {number} subaddressIdx - index of the subaddress to set the label for + * @param {Promise} label - the label to set + */ + async setSubaddressLabel(accountIdx, subaddressIdx, label) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get a wallet transaction by hash. + * + * @param {string} txHash - hash of a transaction to get + * @return {Promise } the identified transaction or undefined if not found + */ + async getTx(txHash) { + let txs = await this.getTxs([txHash]); + return txs.length === 0 ? undefined : txs[0]; + } + + /** + *

Get wallet transactions. Wallet transactions contain one or more + * transfers that are either incoming or outgoing to the wallet.

+ * + *

Results can be filtered by passing a query object. Transactions must + * meet every criteria defined in the query in order to be returned. All + * criteria are optional and no filtering is applied when not defined.

+ * + * @param {string[] | MoneroTxQuery} [query] - configures the query (optional) + * @param {boolean} [query.isConfirmed] - get txs that are confirmed or not (optional) + * @param {boolean} [query.inTxPool] - get txs that are in the tx pool or not (optional) + * @param {boolean} [query.isRelayed] - get txs that are relayed or not (optional) + * @param {boolean} [query.isFailed] - get txs that are failed or not (optional) + * @param {boolean} [query.isMinerTx] - get miner txs or not (optional) + * @param {string} [query.hash] - get a tx with the hash (optional) + * @param {string[]} [query.hashes] - get txs with the hashes (optional) + * @param {string} [query.paymentId] - get transactions with the payment id (optional) + * @param {string[]} [query.paymentIds] - get transactions with the payment ids (optional) + * @param {boolean} [query.hasPaymentId] - get transactions with a payment id or not (optional) + * @param {number} [query.minHeight] - get txs with height >= the given height (optional) + * @param {number} [query.maxHeight] - get txs with height <= the given height (optional) + * @param {boolean} [query.isOutgoing] - get txs with an outgoing transfer or not (optional) + * @param {boolean} [query.isIncoming] - get txs with an incoming transfer or not (optional) + * @param {MoneroTransferQuery} [query.transferQuery] - get txs that have a transfer that meets this query (optional) + * @param {boolean} [query.includeOutputs] - specifies that tx outputs should be returned with tx results (optional) + * @return {Promise} wallet transactions per the configuration + */ + async getTxs(query) { + throw new _MoneroError.default("Not supported"); + } + + /** + *

Get incoming and outgoing transfers to and from this wallet. An outgoing + * transfer represents a total amount sent from one or more subaddresses + * within an account to individual destination addresses, each with their + * own amount. An incoming transfer represents a total amount received into + * a subaddress within an account. Transfers belong to transactions which + * are stored on the blockchain.

+ * + *

Results can be filtered by passing a query object. Transfers must + * meet every criteria defined in the query in order to be returned. All + * criteria are optional and no filtering is applied when not defined.

+ * + * @param {MoneroTransferQuery} [query] - configures the query (optional) + * @param {boolean} [query.isOutgoing] - get transfers that are outgoing or not (optional) + * @param {boolean} [query.isIncoming] - get transfers that are incoming or not (optional) + * @param {string} [query.address] - wallet's address that a transfer either originated from (if outgoing) or is destined for (if incoming) (optional) + * @param {number} [query.accountIndex] - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific account index (optional) + * @param {number} [query.subaddressIndex] - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific subaddress index (optional) + * @param {int[]} [query.subaddressIndices] - get transfers that either originated from (if outgoing) or are destined for (if incoming) specific subaddress indices (optional) + * @param {bigint} [query.amount] - amount being transferred (optional) + * @param {MoneroDestination[] | MoneroDestinationModel[]} [query.destinations] - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional) + * @param {boolean} [query.hasDestinations] - get transfers that have destinations or not (optional) + * @param {MoneroTxQuery} [query.txQuery] - get transfers whose transaction meets this query (optional) + * @return {Promise} wallet transfers that meet the query + */ + async getTransfers(query) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get incoming transfers. + * + * @param {Partial} [query] - configures the query (optional) + * @param {string} [query.address] - get incoming transfers to a specific address in the wallet (optional) + * @param {number} [query.accountIndex] - get incoming transfers to a specific account index (optional) + * @param {number} [query.subaddressIndex] - get incoming transfers to a specific subaddress index (optional) + * @param {int[]} [query.subaddressIndices] - get transfers destined for specific subaddress indices (optional) + * @param {bigint} [query.amount] - amount being transferred (optional) + * @param {MoneroTxQuery} [query.txQuery] - get transfers whose transaction meets this query (optional) + * @return {Promise} incoming transfers that meet the query + */ + async getIncomingTransfers(query) { + const queryNormalized = MoneroWallet.normalizeTransferQuery(query); + if (queryNormalized.getIsIncoming() === false) throw new _MoneroError.default("Transfer query contradicts getting incoming transfers"); + queryNormalized.setIsIncoming(true); + return this.getTransfers(queryNormalized); + } + + /** + * Get outgoing transfers. + * + * @param {Partial} [query] - configures the query (optional) + * @param {string} [query.address] - get outgoing transfers from a specific address in the wallet (optional) + * @param {number} [query.accountIndex] - get outgoing transfers from a specific account index (optional) + * @param {number} [query.subaddressIndex] - get outgoing transfers from a specific subaddress index (optional) + * @param {int[]} [query.subaddressIndices] - get outgoing transfers from specific subaddress indices (optional) + * @param {bigint} [query.amount] - amount being transferred (optional) + * @param {MoneroDestination[] | MoneroDestinationModel[]} [query.destinations] - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional) + * @param {boolean} [query.hasDestinations] - get transfers that have destinations or not (optional) + * @param {MoneroTxQuery} [query.txQuery] - get transfers whose transaction meets this query (optional) + * @return {Promise} outgoing transfers that meet the query + */ + async getOutgoingTransfers(query) { + const queryNormalized = MoneroWallet.normalizeTransferQuery(query); + if (queryNormalized.getIsOutgoing() === false) throw new _MoneroError.default("Transfer query contradicts getting outgoing transfers"); + queryNormalized.setIsOutgoing(true); + return this.getTransfers(queryNormalized); + } + + /** + *

Get outputs created from previous transactions that belong to the wallet + * (i.e. that the wallet can spend one time). Outputs are part of + * transactions which are stored in blocks on the blockchain.

+ * + *

Results can be filtered by passing a query object. Outputs must + * meet every criteria defined in the query in order to be returned. All + * filtering is optional and no filtering is applied when not defined.

+ * + * @param {Parital} [query] - configures the query (optional) + * @param {number} [query.accountIndex] - get outputs associated with a specific account index (optional) + * @param {number} [query.subaddressIndex] - get outputs associated with a specific subaddress index (optional) + * @param {int[]} [query.subaddressIndices] - get outputs associated with specific subaddress indices (optional) + * @param {bigint} [query.amount] - get outputs with a specific amount (optional) + * @param {bigint} [query.minAmount] - get outputs greater than or equal to a minimum amount (optional) + * @param {bigint} [query.maxAmount] - get outputs less than or equal to a maximum amount (optional) + * @param {boolean} [query.isSpent] - get outputs that are spent or not (optional) + * @param {string|MoneroKeyImage} [query.keyImage] - get output with a key image or which matches fields defined in a MoneroKeyImage (optional) + * @param {MoneroTxQuery} [query.txQuery] - get outputs whose transaction meets this filter (optional) + * @return {Promise} the queried outputs + */ + async getOutputs(query) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Export outputs in hex format. + * + * @param {boolean} [all] - export all outputs if true, else export the outputs since the last export (default false) + * @return {Promise} outputs in hex format + */ + async exportOutputs(all = false) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Import outputs in hex format. + * + * @param {string} outputsHex - outputs in hex format + * @return {Promise} the number of outputs imported + */ + async importOutputs(outputsHex) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Export signed key images. + * + * @param {boolean} [all] - export all key images if true, else export the key images since the last export (default false) + * @return {Promise} the wallet's signed key images + */ + async exportKeyImages(all = false) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Import signed key images and verify their spent status. + * + * @param {MoneroKeyImage[]} keyImages - images to import and verify (requires hex and signature) + * @return {Promise} results of the import + */ + async importKeyImages(keyImages) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get new key images from the last imported outputs. + * + * @return {Promise} the key images from the last imported outputs + */ + async getNewKeyImagesFromLastImport() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Freeze an output. + * + * @param {string} keyImage - key image of the output to freeze + * @return {Promise} + */ + async freezeOutput(keyImage) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Thaw a frozen output. + * + * @param {string} keyImage - key image of the output to thaw + * @return {Promise} + */ + async thawOutput(keyImage) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Check if an output is frozen. + * + * @param {string} keyImage - key image of the output to check if frozen + * @return {Promise} true if the output is frozen, false otherwise + */ + async isOutputFrozen(keyImage) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get the current default fee priority (unimportant, normal, elevated, etc). + * + * @return {Promise} the current fee priority + */ + async getDefaultFeePriority() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Create a transaction to transfer funds from this wallet. + * + * @param {MoneroTxConfig} config - configures the transaction to create (required) + * @param {string} config.address - single destination address (required unless `destinations` provided) + * @param {bigint|string} config.amount - single destination amount (required unless `destinations` provided) + * @param {number} config.accountIndex - source account index to transfer funds from (required) + * @param {number} [config.subaddressIndex] - source subaddress index to transfer funds from (optional) + * @param {number[]} [config.subaddressIndices] - source subaddress indices to transfer funds from (optional) + * @param {boolean} [config.relay] - relay the transaction to peers to commit to the blockchain (default false) + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided) + * @param {number[]} [config.subtractFeeFrom] - list of destination indices to split the transaction fee (optional) + * @param {string} [config.paymentId] - transaction payment ID (optional) + * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transaction to unlock (default 0) + * @return {Promise} the created transaction + */ + async createTx(config) { + const configNormalized = MoneroWallet.normalizeCreateTxsConfig(config); + if (configNormalized.getCanSplit() !== undefined) _assert.default.equal(configNormalized.getCanSplit(), false, "Cannot split transactions using createTx(); use createTxs()"); + configNormalized.setCanSplit(false); + return (await this.createTxs(configNormalized))[0]; + } + + /** + * Create one or more transactions to transfer funds from this wallet. + * + * @param {Partial} config - configures the transactions to create (required) + * @param {string} config.address - single destination address (required unless `destinations` provided) + * @param {bigint|string} config.amount - single destination amount (required unless `destinations` provided) + * @param {number} config.accountIndex - source account index to transfer funds from (required) + * @param {number} [config.subaddressIndex] - source subaddress index to transfer funds from (optional) + * @param {int[]} [config.subaddressIndices] - source subaddress indices to transfer funds from (optional) + * @param {boolean} [config.relay] - relay the transactions to peers to commit to the blockchain (default false) + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @param {MoneroDestination[] | MoneroDestinationModel[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided) + * @param {string} [config.paymentId] - transaction payment ID (optional) + * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transactions to unlock (default 0) + * @param {boolean} [config.canSplit] - allow funds to be transferred using multiple transactions (default true) + * @return {Promise} the created transactions + */ + async createTxs(config) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Sweep an output by key image. + * + * @param {Partial} config - configures the transaction to create (required) + * @param {string} config.address - single destination address (required) + * @param {string} config.keyImage - key image to sweep (required) + * @param {boolean} [config.relay] - relay the transaction to peers to commit to the blockchain (default false) + * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transaction to unlock (default 0) + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @return {Promise} the created transaction + */ + async sweepOutput(config) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Sweep all unlocked funds according to the given configuration. + * + * @param {Partial} config - configures the transactions to create (required) + * @param {string} config.address - single destination address (required) + * @param {number} [config.accountIndex] - source account index to sweep from (optional, defaults to all accounts) + * @param {number} [config.subaddressIndex] - source subaddress index to sweep from (optional, defaults to all subaddresses) + * @param {number[]} [config.subaddressIndices] - source subaddress indices to sweep from (optional) + * @param {boolean} [config.relay] - relay the transactions to peers to commit to the blockchain (default false) + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transactions to unlock (default 0) + * @param {boolean} [config.sweepEachSubaddress] - sweep each subaddress individually if true (default false) + * @return {Promise} the created transactions + */ + async sweepUnlocked(config) { + throw new _MoneroError.default("Not supported"); + } + + /** + *

Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

+ * + *

NOTE: Dust only exists pre RCT, so this method will throw "no dust to sweep" on new wallets.

+ * + * @param {boolean} [relay] - specifies if the resulting transaction should be relayed (default false) + * @return {Promise} the created transactions + */ + async sweepDust(relay) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Relay a previously created transaction. + * + * @param {(MoneroTxWallet | string)} txOrMetadata - transaction or its metadata to relay + * @return {Promise} the hash of the relayed tx + */ + async relayTx(txOrMetadata) { + return (await this.relayTxs([txOrMetadata]))[0]; + } + + /** + * Relay previously created transactions. + * + * @param {(MoneroTxWallet[] | string[])} txsOrMetadatas - transactions or their metadata to relay + * @return {Promise} the hashes of the relayed txs + */ + async relayTxs(txsOrMetadatas) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Describe a tx set from unsigned tx hex. + * + * @param {string} unsignedTxHex - unsigned tx hex + * @return {Promise} the tx set containing structured transactions + */ + async describeUnsignedTxSet(unsignedTxHex) { + return this.describeTxSet(new _MoneroTxSet.default().setUnsignedTxHex(unsignedTxHex)); + } + + /** + * Describe a tx set from multisig tx hex. + * + * @param {string} multisigTxHex - multisig tx hex + * @return {Promise} the tx set containing structured transactions + */ + async describeMultisigTxSet(multisigTxHex) { + return this.describeTxSet(new _MoneroTxSet.default().setMultisigTxHex(multisigTxHex)); + } + + /** + * Describe a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions. + * + * @param {MoneroTxSet} txSet - a tx set containing unsigned or multisig tx hex + * @return {Promise} txSet - the tx set containing structured transactions + */ + async describeTxSet(txSet) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Sign unsigned transactions from a view-only wallet. + * + * @param {string} unsignedTxHex - unsigned transaction hex from when the transactions were created + * @return {Promise} the signed transaction set + */ + async signTxs(unsignedTxHex) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Submit signed transactions from a view-only wallet. + * + * @param {string} signedTxHex - signed transaction hex from signTxs() + * @return {Promise} the resulting transaction hashes + */ + async submitTxs(signedTxHex) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Sign a message. + * + * @param {string} message - the message to sign + * @param {MoneroMessageSignatureType} [signatureType] - sign with spend key or view key (default spend key) + * @param {number} [accountIdx] - the account index of the message signature (default 0) + * @param {number} [subaddressIdx] - the subaddress index of the message signature (default 0) + * @return {Promise} the signature + */ + async signMessage(message, signatureType = _MoneroMessageSignatureType.default.SIGN_WITH_SPEND_KEY, accountIdx = 0, subaddressIdx = 0) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Verify a signature on a message. + * + * @param {string} message - signed message + * @param {string} address - signing address + * @param {string} signature - signature + * @return {Promise} true if the signature is good, false otherwise + */ + async verifyMessage(message, address, signature) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get a transaction's secret key from its hash. + * + * @param {string} txHash - transaction's hash + * @return {Promise} - transaction's secret key + */ + async getTxKey(txHash) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Check a transaction in the blockchain with its secret key. + * + * @param {string} txHash - transaction to check + * @param {string} txKey - transaction's secret key + * @param {string} address - destination public address of the transaction + * @return {romise} the result of the check + */ + async checkTxKey(txHash, txKey, address) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get a transaction signature to prove it. + * + * @param {string} txHash - transaction to prove + * @param {string} address - destination public address of the transaction + * @param {string} [message] - message to include with the signature to further authenticate the proof (optional) + * @return {Promise} the transaction signature + */ + async getTxProof(txHash, address, message) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Prove a transaction by checking its signature. + * + * @param {string} txHash - transaction to prove + * @param {string} address - destination public address of the transaction + * @param {string | undefined} message - message included with the signature to further authenticate the proof + * @param {string} signature - transaction signature to confirm + * @return {Promise} the result of the check + */ + async checkTxProof(txHash, address, message, signature) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address. + * + * @param {string} txHash - transaction to prove + * @param {string} [message] - message to include with the signature to further authenticate the proof (optional) + * @return {Promise} the transaction signature + */ + async getSpendProof(txHash, message) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address. + * + * @param {string} txHash - transaction to prove + * @param {string | undefined} message - message included with the signature to further authenticate the proof (optional) + * @param {string} signature - transaction signature to confirm + * @return {Promise} true if the signature is good, false otherwise + */ + async checkSpendProof(txHash, message, signature) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Generate a signature to prove the entire balance of the wallet. + * + * @param {string} [message] - message included with the signature to further authenticate the proof (optional) + * @return {Promise} the reserve proof signature + */ + async getReserveProofWallet(message) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Generate a signature to prove an available amount in an account. + * + * @param {number} accountIdx - account to prove ownership of the amount + * @param {bigint} amount - minimum amount to prove as available in the account + * @param {string} [message] - message to include with the signature to further authenticate the proof (optional) + * @return {Promise} the reserve proof signature + */ + async getReserveProofAccount(accountIdx, amount, message) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Proves a wallet has a disposable reserve using a signature. + * + * @param {string} address - public wallet address + * @param {string | undefined} message - message included with the signature to further authenticate the proof (optional) + * @param {string} signature - reserve proof signature to check + * @return {Promise} the result of checking the signature proof + */ + async checkReserveProof(address, message, signature) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get a transaction note. + * + * @param {string} txHash - transaction to get the note of + * @return {Promise} the tx note + */ + async getTxNote(txHash) { + return (await this.getTxNotes([txHash]))[0]; + } + + /** + * Get notes for multiple transactions. + * + * @param {string[]} txHashes - hashes of the transactions to get notes for + * @return {Promise} notes for the transactions + */ + async getTxNotes(txHashes) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Set a note for a specific transaction. + * + * @param {string} txHash - hash of the transaction to set a note for + * @param {string} note - the transaction note + * @return {Promise} + */ + async setTxNote(txHash, note) { + await this.setTxNotes([txHash], [note]); + } + + /** + * Set notes for multiple transactions. + * + * @param {string[]} txHashes - transactions to set notes for + * @param {string[]} notes - notes to set for the transactions + * @return {Promise} + */ + async setTxNotes(txHashes, notes) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get address book entries. + * + * @param {number[]} [entryIndices] - indices of the entries to get + * @return {Promise} the address book entries + */ + async getAddressBookEntries(entryIndices) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Add an address book entry. + * + * @param {string} address - entry address + * @param {string} [description] - entry description (optional) + * @return {Promise} the index of the added entry + */ + async addAddressBookEntry(address, description) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Edit an address book entry. + * + * @param {number} index - index of the address book entry to edit + * @param {boolean} setAddress - specifies if the address should be updated + * @param {string | undefined} address - updated address + * @param {boolean} setDescription - specifies if the description should be updated + * @param {string | undefined} description - updated description + * @return {Promise} + */ + async editAddressBookEntry(index, setAddress, address, setDescription, description) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Delete an address book entry. + * + * @param {number} entryIdx - index of the entry to delete + * @return {Promise} + */ + async deleteAddressBookEntry(entryIdx) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Tag accounts. + * + * @param {string} tag - tag to apply to the specified accounts + * @param {number[]} accountIndices - indices of the accounts to tag + * @return {Promise} + */ + async tagAccounts(tag, accountIndices) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Untag accounts. + * + * @param {number[]} accountIndices - indices of the accounts to untag + * @return {Promise} + */ + async untagAccounts(accountIndices) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Return all account tags. + * + * @return {Promise} the wallet's account tags + */ + async getAccountTags() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Sets a human-readable description for a tag. + * + * @param {string} tag - tag to set a description for + * @param {string} label - label to set for the tag + * @return {Promise} + */ + async setAccountTagLabel(tag, label) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Creates a payment URI from a send configuration. + * + * @param {MoneroTxConfig} config - specifies configuration for a potential tx + * @return {Promise} the payment uri + */ + async getPaymentUri(config) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Parses a payment URI to a tx config. + * + * @param {string} uri - payment uri to parse + * @return {Promise} the send configuration parsed from the uri + */ + async parsePaymentUri(uri) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get an attribute. + * + * @param {string} key - attribute to get the value of + * @return {Promise} the attribute's value + */ + async getAttribute(key) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Set an arbitrary attribute. + * + * @param {string} key - attribute key + * @param {string} val - attribute value + * @return {Promise} + */ + async setAttribute(key, val) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Start mining. + * + * @param {number} [numThreads] - number of threads created for mining (optional) + * @param {boolean} [backgroundMining] - specifies if mining should occur in the background (optional) + * @param {boolean} [ignoreBattery] - specifies if the battery should be ignored for mining (optional) + * @return {Promise} + */ + async startMining(numThreads, backgroundMining, ignoreBattery) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Stop mining. + * + * @return {Promise} + */ + async stopMining() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Indicates if importing multisig data is needed for returning a correct balance. + * + * @return {Promise} true if importing multisig data is needed for returning a correct balance, false otherwise + */ + async isMultisigImportNeeded() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Indicates if this wallet is a multisig wallet. + * + * @return {Promise} true if this is a multisig wallet, false otherwise + */ + async isMultisig() { + return (await this.getMultisigInfo()).getIsMultisig(); + } + + /** + * Get multisig info about this wallet. + * + * @return {Promise} multisig info about this wallet + */ + async getMultisigInfo() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Get multisig info as hex to share with participants to begin creating a + * multisig wallet. + * + * @return {Promise} this wallet's multisig hex to share with participants + */ + async prepareMultisig() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Make this wallet multisig by importing multisig hex from participants. + * + * @param {string[]} multisigHexes - multisig hex from each participant + * @param {number} threshold - number of signatures needed to sign transfers + * @param {string} password - wallet password + * @return {Promise} this wallet's multisig hex to share with participants + */ + async makeMultisig(multisigHexes, threshold, password) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Exchange multisig hex with participants in a M/N multisig wallet. + * + * This process must be repeated with participants exactly N-M times. + * + * @param {string[]} multisigHexes are multisig hex from each participant + * @param {string} password - wallet's password // TODO monero-project: redundant? wallet is created with password + * @return {Promise} the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done + */ + async exchangeMultisigKeys(multisigHexes, password) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Export this wallet's multisig info as hex for other participants. + * + * @return {Promise} this wallet's multisig info as hex for other participants + */ + async exportMultisigHex() { + throw new _MoneroError.default("Not supported?"); + } + + /** + * Import multisig info as hex from other participants. + * + * @param {string[]} multisigHexes - multisig hex from each participant + * @return {Promise} the number of outputs signed with the given multisig hex + */ + async importMultisigHex(multisigHexes) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Sign multisig transactions from a multisig wallet. + * + * @param {string} multisigTxHex - unsigned multisig transactions as hex + * @return {MoneroMultisigSignResult} the result of signing the multisig transactions + */ + async signMultisigTxHex(multisigTxHex) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Submit signed multisig transactions from a multisig wallet. + * + * @param {string} signedMultisigTxHex - signed multisig hex returned from signMultisigTxHex() + * @return {Promise} the resulting transaction hashes + */ + async submitMultisigTxHex(signedMultisigTxHex) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Change the wallet password. + * + * @param {string} oldPassword - the wallet's old password + * @param {string} newPassword - the wallet's new password + * @return {Promise} + */ + async changePassword(oldPassword, newPassword) { + throw new _MoneroError.default("Not supported"); + } + + /** + * Save the wallet at its current path. + * + * @return {Promise} + */ + async save() { + throw new _MoneroError.default("Not supported"); + } + + /** + * Optionally save then close the wallet. + * + * @param {boolean} [save] - specifies if the wallet should be saved before being closed (default false) + * @return {Promise} + */ + async close(save = false) { + if (this.connectionManager) this.connectionManager.removeListener(this.connectionManagerListener); + this.connectionManager = undefined; + this.connectionManagerListener = undefined; + this.listeners.splice(0, this.listeners.length); + this._isClosed = true; + } + + /** + * Indicates if this wallet is closed or not. + * + * @return {Promise} true if the wallet is closed, false otherwise + */ + async isClosed() { + return this._isClosed; + } + + // -------------------------------- PRIVATE --------------------------------- + + /** + * @private + */ + async announceSyncProgress(height, startHeight, endHeight, percentDone, message) { + for (let listener of this.listeners) { + try { + await listener.onSyncProgress(height, startHeight, endHeight, percentDone, message); + } catch (err) { + console.error("Error calling listener on sync progress", err); + } + } + } + + /** + * @private + */ + async announceNewBlock(height) { + for (let listener of this.listeners) { + try { + await listener.onNewBlock(height); + } catch (err) { + console.error("Error calling listener on new block", err); + } + } + } + + /** + * @private + */ + async announceBalancesChanged(newBalance, newUnlockedBalance) { + for (let listener of this.listeners) { + try { + await listener.onBalancesChanged(newBalance, newUnlockedBalance); + } catch (err) { + console.error("Error calling listener on balances changed", err); + } + } + } + + /** + * @private + */ + async announceOutputReceived(output) { + for (let listener of this.listeners) { + try { + await listener.onOutputReceived(output); + } catch (err) { + console.error("Error calling listener on output received", err); + } + } + } + + /** + * @private + */ + async announceOutputSpent(output) { + for (let listener of this.listeners) { + try { + await listener.onOutputSpent(output); + } catch (err) { + console.error("Error calling listener on output spent", err); + } + } + } + + static normalizeTxQuery(query) { + if (query instanceof _MoneroTxQuery.default) query = query.copy();else + if (Array.isArray(query)) query = new _MoneroTxQuery.default().setHashes(query);else + { + query = Object.assign({}, query); + query = new _MoneroTxQuery.default(query); + } + if (query.getBlock() === undefined) query.setBlock(new _MoneroBlock.default().setTxs([query])); + if (query.getInputQuery()) query.getInputQuery().setTxQuery(query); + if (query.getOutputQuery()) query.getOutputQuery().setTxQuery(query); + return query; + } + + static normalizeTransferQuery(query) { + query = new _MoneroTransferQuery.default(query); + if (query.getTxQuery() !== undefined) { + let txQuery = query.getTxQuery().copy(); + query = txQuery.getTransferQuery(); + } + if (query.getTxQuery() === undefined) query.setTxQuery(new _MoneroTxQuery.default()); + query.getTxQuery().setTransferQuery(query); + if (query.getTxQuery().getBlock() === undefined) query.getTxQuery().setBlock(new _MoneroBlock.default().setTxs([query.getTxQuery()])); + return query; + } + + static normalizeOutputQuery(query) { + query = new _MoneroOutputQuery.default(query); + if (query.getTxQuery() !== undefined) { + let txQuery = query.getTxQuery().copy(); + query = txQuery.getOutputQuery(); + } + if (query.getTxQuery() === undefined) query.setTxQuery(new _MoneroTxQuery.default()); + query.getTxQuery().setOutputQuery(query); + if (query.getTxQuery().getBlock() === undefined) query.getTxQuery().setBlock(new _MoneroBlock.default().setTxs([query.getTxQuery()])); + return query; + } + + static normalizeCreateTxsConfig(config) { + if (config === undefined || !(config instanceof Object)) throw new _MoneroError.default("Must provide MoneroTxConfig or equivalent JS object"); + config = new _MoneroTxConfig.default(config); + (0, _assert.default)(config.getDestinations() && config.getDestinations().length > 0, "Must provide destinations"); + _assert.default.equal(config.getSweepEachSubaddress(), undefined); + _assert.default.equal(config.getBelowAmount(), undefined); + return config; + } + + static normalizeSweepOutputConfig(config) { + if (config === undefined || !(config instanceof Object)) throw new _MoneroError.default("Must provide MoneroTxConfig or equivalent JS object"); + config = new _MoneroTxConfig.default(config); + _assert.default.equal(config.getSweepEachSubaddress(), undefined); + _assert.default.equal(config.getBelowAmount(), undefined); + _assert.default.equal(config.getCanSplit(), undefined, "Cannot split transactions when sweeping an output"); + if (!config.getDestinations() || config.getDestinations().length !== 1 || !config.getDestinations()[0].getAddress()) throw new _MoneroError.default("Must provide exactly one destination address to sweep output to"); + if (config.getSubtractFeeFrom() && config.getSubtractFeeFrom().length > 0) throw new _MoneroError.default("Sweep transactions do not support subtracting fees from destinations"); + return config; + } + + static normalizeSweepUnlockedConfig(config) { + if (config === undefined || !(config instanceof Object)) throw new _MoneroError.default("Must provide MoneroTxConfig or equivalent JS object"); + config = new _MoneroTxConfig.default(config); + if (config.getDestinations() === undefined || config.getDestinations().length != 1) throw new _MoneroError.default("Must provide exactly one destination to sweep to"); + if (config.getDestinations()[0].getAddress() === undefined) throw new _MoneroError.default("Must provide destination address to sweep to"); + if (config.getDestinations()[0].getAmount() !== undefined) throw new _MoneroError.default("Cannot provide amount in sweep config"); + if (config.getKeyImage() !== undefined) throw new _MoneroError.default("Key image defined; use sweepOutput() to sweep an output by its key image"); + if (config.getSubaddressIndices() !== undefined && config.getSubaddressIndices().length === 0) config.setSubaddressIndices(undefined); + if (config.getAccountIndex() === undefined && config.getSubaddressIndices() !== undefined) throw new _MoneroError.default("Must provide account index if subaddress indices are provided"); + if (config.getSubtractFeeFrom() && config.getSubtractFeeFrom().length > 0) throw new _MoneroError.default("Sweep transactions do not support subtracting fees from destinations"); + return config; + } +}exports.default = MoneroWallet; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfTW9uZXJvQmxvY2siLCJfTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJMaXN0ZW5lciIsIl9Nb25lcm9FcnJvciIsIl9Nb25lcm9NZXNzYWdlU2lnbmF0dXJlVHlwZSIsIl9Nb25lcm9PdXRwdXRRdWVyeSIsIl9Nb25lcm9UcmFuc2ZlclF1ZXJ5IiwiX01vbmVyb1R4Q29uZmlnIiwiX01vbmVyb1R4UXVlcnkiLCJfTW9uZXJvVHhTZXQiLCJfTW9uZXJvVXRpbHMiLCJfTW9uZXJvV2FsbGV0TGlzdGVuZXIiLCJNb25lcm9XYWxsZXQiLCJERUZBVUxUX0xBTkdVQUdFIiwibGlzdGVuZXJzIiwiX2lzQ2xvc2VkIiwiY29uc3RydWN0b3IiLCJhZGRMaXN0ZW5lciIsImxpc3RlbmVyIiwiYXNzZXJ0IiwiTW9uZXJvV2FsbGV0TGlzdGVuZXIiLCJwdXNoIiwicmVtb3ZlTGlzdGVuZXIiLCJpZHgiLCJpbmRleE9mIiwic3BsaWNlIiwiTW9uZXJvRXJyb3IiLCJnZXRMaXN0ZW5lcnMiLCJpc1ZpZXdPbmx5Iiwic2V0RGFlbW9uQ29ubmVjdGlvbiIsInVyaU9yQ29ubmVjdGlvbiIsImdldERhZW1vbkNvbm5lY3Rpb24iLCJzZXRDb25uZWN0aW9uTWFuYWdlciIsImNvbm5lY3Rpb25NYW5hZ2VyIiwiY29ubmVjdGlvbk1hbmFnZXJMaXN0ZW5lciIsInRoYXQiLCJNb25lcm9Db25uZWN0aW9uTWFuYWdlckxpc3RlbmVyIiwib25Db25uZWN0aW9uQ2hhbmdlZCIsImNvbm5lY3Rpb24iLCJnZXRDb25uZWN0aW9uIiwiZ2V0Q29ubmVjdGlvbk1hbmFnZXIiLCJpc0Nvbm5lY3RlZFRvRGFlbW9uIiwiZ2V0VmVyc2lvbiIsImdldFBhdGgiLCJnZXRTZWVkIiwiZ2V0U2VlZExhbmd1YWdlIiwiZ2V0UHJpdmF0ZVZpZXdLZXkiLCJnZXRQcml2YXRlU3BlbmRLZXkiLCJnZXRQdWJsaWNWaWV3S2V5IiwiZ2V0UHVibGljU3BlbmRLZXkiLCJnZXRQcmltYXJ5QWRkcmVzcyIsImdldEFkZHJlc3MiLCJhY2NvdW50SWR4Iiwic3ViYWRkcmVzc0lkeCIsImdldEFkZHJlc3NJbmRleCIsImFkZHJlc3MiLCJnZXRJbnRlZ3JhdGVkQWRkcmVzcyIsInN0YW5kYXJkQWRkcmVzcyIsInBheW1lbnRJZCIsImRlY29kZUludGVncmF0ZWRBZGRyZXNzIiwiaW50ZWdyYXRlZEFkZHJlc3MiLCJnZXRIZWlnaHQiLCJnZXREYWVtb25IZWlnaHQiLCJnZXRIZWlnaHRCeURhdGUiLCJ5ZWFyIiwibW9udGgiLCJkYXkiLCJzeW5jIiwibGlzdGVuZXJPclN0YXJ0SGVpZ2h0Iiwic3RhcnRIZWlnaHQiLCJzdGFydFN5bmNpbmciLCJzeW5jUGVyaW9kSW5NcyIsInN0b3BTeW5jaW5nIiwic2NhblR4cyIsInR4SGFzaGVzIiwicmVzY2FuU3BlbnQiLCJyZXNjYW5CbG9ja2NoYWluIiwiZ2V0QmFsYW5jZSIsImdldFVubG9ja2VkQmFsYW5jZSIsImdldE51bUJsb2Nrc1RvVW5sb2NrIiwiYmFsYW5jZSIsInVuZGVmaW5lZCIsInVubG9ja2VkQmFsYW5jZSIsInR4cyIsImhlaWdodCIsIm51bUJsb2Nrc1RvTmV4dFVubG9jayIsImdldFR4cyIsImlzTG9ja2VkIiwidHgiLCJnZXRJc0NvbmZpcm1lZCIsIk1vbmVyb1V0aWxzIiwiaXNUaW1lc3RhbXAiLCJnZXRVbmxvY2tUaW1lIiwibnVtQmxvY2tzVG9VbmxvY2siLCJNYXRoIiwibWF4IiwiTnVtYmVyIiwibWluIiwibnVtQmxvY2tzVG9MYXN0VW5sb2NrIiwiZ2V0QWNjb3VudHMiLCJpbmNsdWRlU3ViYWRkcmVzc2VzIiwidGFnIiwiZ2V0QWNjb3VudCIsImNyZWF0ZUFjY291bnQiLCJsYWJlbCIsInNldEFjY291bnRMYWJlbCIsInNldFN1YmFkZHJlc3NMYWJlbCIsImdldFN1YmFkZHJlc3NlcyIsInN1YmFkZHJlc3NJbmRpY2VzIiwiZ2V0U3ViYWRkcmVzcyIsImNyZWF0ZVN1YmFkZHJlc3MiLCJnZXRUeCIsInR4SGFzaCIsImxlbmd0aCIsInF1ZXJ5IiwiZ2V0VHJhbnNmZXJzIiwiZ2V0SW5jb21pbmdUcmFuc2ZlcnMiLCJxdWVyeU5vcm1hbGl6ZWQiLCJub3JtYWxpemVUcmFuc2ZlclF1ZXJ5IiwiZ2V0SXNJbmNvbWluZyIsInNldElzSW5jb21pbmciLCJnZXRPdXRnb2luZ1RyYW5zZmVycyIsImdldElzT3V0Z29pbmciLCJzZXRJc091dGdvaW5nIiwiZ2V0T3V0cHV0cyIsImV4cG9ydE91dHB1dHMiLCJhbGwiLCJpbXBvcnRPdXRwdXRzIiwib3V0cHV0c0hleCIsImV4cG9ydEtleUltYWdlcyIsImltcG9ydEtleUltYWdlcyIsImtleUltYWdlcyIsImdldE5ld0tleUltYWdlc0Zyb21MYXN0SW1wb3J0IiwiZnJlZXplT3V0cHV0Iiwia2V5SW1hZ2UiLCJ0aGF3T3V0cHV0IiwiaXNPdXRwdXRGcm96ZW4iLCJnZXREZWZhdWx0RmVlUHJpb3JpdHkiLCJjcmVhdGVUeCIsImNvbmZpZyIsImNvbmZpZ05vcm1hbGl6ZWQiLCJub3JtYWxpemVDcmVhdGVUeHNDb25maWciLCJnZXRDYW5TcGxpdCIsImVxdWFsIiwic2V0Q2FuU3BsaXQiLCJjcmVhdGVUeHMiLCJzd2VlcE91dHB1dCIsInN3ZWVwVW5sb2NrZWQiLCJzd2VlcER1c3QiLCJyZWxheSIsInJlbGF5VHgiLCJ0eE9yTWV0YWRhdGEiLCJyZWxheVR4cyIsInR4c09yTWV0YWRhdGFzIiwiZGVzY3JpYmVVbnNpZ25lZFR4U2V0IiwidW5zaWduZWRUeEhleCIsImRlc2NyaWJlVHhTZXQiLCJNb25lcm9UeFNldCIsInNldFVuc2lnbmVkVHhIZXgiLCJkZXNjcmliZU11bHRpc2lnVHhTZXQiLCJtdWx0aXNpZ1R4SGV4Iiwic2V0TXVsdGlzaWdUeEhleCIsInR4U2V0Iiwic2lnblR4cyIsInN1Ym1pdFR4cyIsInNpZ25lZFR4SGV4Iiwic2lnbk1lc3NhZ2UiLCJtZXNzYWdlIiwic2lnbmF0dXJlVHlwZSIsIk1vbmVyb01lc3NhZ2VTaWduYXR1cmVUeXBlIiwiU0lHTl9XSVRIX1NQRU5EX0tFWSIsInZlcmlmeU1lc3NhZ2UiLCJzaWduYXR1cmUiLCJnZXRUeEtleSIsImNoZWNrVHhLZXkiLCJ0eEtleSIsImdldFR4UHJvb2YiLCJjaGVja1R4UHJvb2YiLCJnZXRTcGVuZFByb29mIiwiY2hlY2tTcGVuZFByb29mIiwiZ2V0UmVzZXJ2ZVByb29mV2FsbGV0IiwiZ2V0UmVzZXJ2ZVByb29mQWNjb3VudCIsImFtb3VudCIsImNoZWNrUmVzZXJ2ZVByb29mIiwiZ2V0VHhOb3RlIiwiZ2V0VHhOb3RlcyIsInNldFR4Tm90ZSIsIm5vdGUiLCJzZXRUeE5vdGVzIiwibm90ZXMiLCJnZXRBZGRyZXNzQm9va0VudHJpZXMiLCJlbnRyeUluZGljZXMiLCJhZGRBZGRyZXNzQm9va0VudHJ5IiwiZGVzY3JpcHRpb24iLCJlZGl0QWRkcmVzc0Jvb2tFbnRyeSIsImluZGV4Iiwic2V0QWRkcmVzcyIsInNldERlc2NyaXB0aW9uIiwiZGVsZXRlQWRkcmVzc0Jvb2tFbnRyeSIsImVudHJ5SWR4IiwidGFnQWNjb3VudHMiLCJhY2NvdW50SW5kaWNlcyIsInVudGFnQWNjb3VudHMiLCJnZXRBY2NvdW50VGFncyIsInNldEFjY291bnRUYWdMYWJlbCIsImdldFBheW1lbnRVcmkiLCJwYXJzZVBheW1lbnRVcmkiLCJ1cmkiLCJnZXRBdHRyaWJ1dGUiLCJrZXkiLCJzZXRBdHRyaWJ1dGUiLCJ2YWwiLCJzdGFydE1pbmluZyIsIm51bVRocmVhZHMiLCJiYWNrZ3JvdW5kTWluaW5nIiwiaWdub3JlQmF0dGVyeSIsInN0b3BNaW5pbmciLCJpc011bHRpc2lnSW1wb3J0TmVlZGVkIiwiaXNNdWx0aXNpZyIsImdldE11bHRpc2lnSW5mbyIsImdldElzTXVsdGlzaWciLCJwcmVwYXJlTXVsdGlzaWciLCJtYWtlTXVsdGlzaWciLCJtdWx0aXNpZ0hleGVzIiwidGhyZXNob2xkIiwicGFzc3dvcmQiLCJleGNoYW5nZU11bHRpc2lnS2V5cyIsImV4cG9ydE11bHRpc2lnSGV4IiwiaW1wb3J0TXVsdGlzaWdIZXgiLCJzaWduTXVsdGlzaWdUeEhleCIsInN1Ym1pdE11bHRpc2lnVHhIZXgiLCJzaWduZWRNdWx0aXNpZ1R4SGV4IiwiY2hhbmdlUGFzc3dvcmQiLCJvbGRQYXNzd29yZCIsIm5ld1Bhc3N3b3JkIiwic2F2ZSIsImNsb3NlIiwiaXNDbG9zZWQiLCJhbm5vdW5jZVN5bmNQcm9ncmVzcyIsImVuZEhlaWdodCIsInBlcmNlbnREb25lIiwib25TeW5jUHJvZ3Jlc3MiLCJlcnIiLCJjb25zb2xlIiwiZXJyb3IiLCJhbm5vdW5jZU5ld0Jsb2NrIiwib25OZXdCbG9jayIsImFubm91bmNlQmFsYW5jZXNDaGFuZ2VkIiwibmV3QmFsYW5jZSIsIm5ld1VubG9ja2VkQmFsYW5jZSIsIm9uQmFsYW5jZXNDaGFuZ2VkIiwiYW5ub3VuY2VPdXRwdXRSZWNlaXZlZCIsIm91dHB1dCIsIm9uT3V0cHV0UmVjZWl2ZWQiLCJhbm5vdW5jZU91dHB1dFNwZW50Iiwib25PdXRwdXRTcGVudCIsIm5vcm1hbGl6ZVR4UXVlcnkiLCJNb25lcm9UeFF1ZXJ5IiwiY29weSIsIkFycmF5IiwiaXNBcnJheSIsInNldEhhc2hlcyIsIk9iamVjdCIsImFzc2lnbiIsImdldEJsb2NrIiwic2V0QmxvY2siLCJNb25lcm9CbG9jayIsInNldFR4cyIsImdldElucHV0UXVlcnkiLCJzZXRUeFF1ZXJ5IiwiZ2V0T3V0cHV0UXVlcnkiLCJNb25lcm9UcmFuc2ZlclF1ZXJ5IiwiZ2V0VHhRdWVyeSIsInR4UXVlcnkiLCJnZXRUcmFuc2ZlclF1ZXJ5Iiwic2V0VHJhbnNmZXJRdWVyeSIsIm5vcm1hbGl6ZU91dHB1dFF1ZXJ5IiwiTW9uZXJvT3V0cHV0UXVlcnkiLCJzZXRPdXRwdXRRdWVyeSIsIk1vbmVyb1R4Q29uZmlnIiwiZ2V0RGVzdGluYXRpb25zIiwiZ2V0U3dlZXBFYWNoU3ViYWRkcmVzcyIsImdldEJlbG93QW1vdW50Iiwibm9ybWFsaXplU3dlZXBPdXRwdXRDb25maWciLCJnZXRTdWJ0cmFjdEZlZUZyb20iLCJub3JtYWxpemVTd2VlcFVubG9ja2VkQ29uZmlnIiwiZ2V0QW1vdW50IiwiZ2V0S2V5SW1hZ2UiLCJnZXRTdWJhZGRyZXNzSW5kaWNlcyIsInNldFN1YmFkZHJlc3NJbmRpY2VzIiwiZ2V0QWNjb3VudEluZGV4IiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy93YWxsZXQvTW9uZXJvV2FsbGV0LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IEdlblV0aWxzIGZyb20gXCIuLi9jb21tb24vR2VuVXRpbHNcIjtcbmltcG9ydCBNb25lcm9BY2NvdW50IGZyb20gXCIuL21vZGVsL01vbmVyb0FjY291bnRcIjtcbmltcG9ydCBNb25lcm9BY2NvdW50VGFnIGZyb20gXCIuL21vZGVsL01vbmVyb0FjY291bnRUYWdcIjtcbmltcG9ydCBNb25lcm9BZGRyZXNzQm9va0VudHJ5IGZyb20gXCIuL21vZGVsL01vbmVyb0FkZHJlc3NCb29rRW50cnlcIjtcbmltcG9ydCBNb25lcm9CbG9jayBmcm9tIFwiLi4vZGFlbW9uL21vZGVsL01vbmVyb0Jsb2NrXCI7XG5pbXBvcnQgTW9uZXJvQ2hlY2tSZXNlcnZlIGZyb20gXCIuL21vZGVsL01vbmVyb0NoZWNrUmVzZXJ2ZVwiO1xuaW1wb3J0IE1vbmVyb0NoZWNrVHggZnJvbSBcIi4vbW9kZWwvTW9uZXJvQ2hlY2tUeFwiO1xuaW1wb3J0IE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyIGZyb20gXCIuLi9jb21tb24vTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJcIjtcbmltcG9ydCBNb25lcm9Db25uZWN0aW9uTWFuYWdlckxpc3RlbmVyIGZyb20gXCIuLi9jb21tb24vTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJMaXN0ZW5lclwiO1xuaW1wb3J0IE1vbmVyb0Vycm9yIGZyb20gXCIuLi9jb21tb24vTW9uZXJvRXJyb3JcIjtcbmltcG9ydCBNb25lcm9JbmNvbWluZ1RyYW5zZmVyIGZyb20gXCIuL21vZGVsL01vbmVyb0luY29taW5nVHJhbnNmZXJcIjtcbmltcG9ydCBNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcyBmcm9tIFwiLi9tb2RlbC9Nb25lcm9JbnRlZ3JhdGVkQWRkcmVzc1wiO1xuaW1wb3J0IE1vbmVyb0tleUltYWdlIGZyb20gXCIuLi9kYWVtb24vbW9kZWwvTW9uZXJvS2V5SW1hZ2VcIjtcbmltcG9ydCBNb25lcm9LZXlJbWFnZUltcG9ydFJlc3VsdCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9LZXlJbWFnZUltcG9ydFJlc3VsdFwiO1xuaW1wb3J0IE1vbmVyb01lc3NhZ2VTaWduYXR1cmVSZXN1bHQgZnJvbSBcIi4vbW9kZWwvTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVJlc3VsdFwiO1xuaW1wb3J0IE1vbmVyb01lc3NhZ2VTaWduYXR1cmVUeXBlIGZyb20gXCIuL21vZGVsL01vbmVyb01lc3NhZ2VTaWduYXR1cmVUeXBlXCI7XG5pbXBvcnQgTW9uZXJvTXVsdGlzaWdJbmZvIGZyb20gXCIuL21vZGVsL01vbmVyb011bHRpc2lnSW5mb1wiO1xuaW1wb3J0IE1vbmVyb011bHRpc2lnSW5pdFJlc3VsdCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9NdWx0aXNpZ0luaXRSZXN1bHRcIjtcbmltcG9ydCBNb25lcm9NdWx0aXNpZ1NpZ25SZXN1bHQgZnJvbSBcIi4vbW9kZWwvTW9uZXJvTXVsdGlzaWdTaWduUmVzdWx0XCI7XG5pbXBvcnQgTW9uZXJvT3V0cHV0UXVlcnkgZnJvbSBcIi4vbW9kZWwvTW9uZXJvT3V0cHV0UXVlcnlcIjtcbmltcG9ydCBNb25lcm9PdXRwdXRXYWxsZXQgZnJvbSBcIi4vbW9kZWwvTW9uZXJvT3V0cHV0V2FsbGV0XCI7XG5pbXBvcnQgTW9uZXJvT3V0Z29pbmdUcmFuc2ZlciBmcm9tIFwiLi9tb2RlbC9Nb25lcm9PdXRnb2luZ1RyYW5zZmVyXCI7XG5pbXBvcnQgTW9uZXJvUnBjQ29ubmVjdGlvbiBmcm9tIFwiLi4vY29tbW9uL01vbmVyb1JwY0Nvbm5lY3Rpb25cIjtcbmltcG9ydCBNb25lcm9TdWJhZGRyZXNzIGZyb20gXCIuL21vZGVsL01vbmVyb1N1YmFkZHJlc3NcIjtcbmltcG9ydCBNb25lcm9TeW5jUmVzdWx0IGZyb20gXCIuL21vZGVsL01vbmVyb1N5bmNSZXN1bHRcIjtcbmltcG9ydCBNb25lcm9UcmFuc2ZlciBmcm9tIFwiLi9tb2RlbC9Nb25lcm9UcmFuc2ZlclwiO1xuaW1wb3J0IE1vbmVyb1RyYW5zZmVyUXVlcnkgZnJvbSBcIi4vbW9kZWwvTW9uZXJvVHJhbnNmZXJRdWVyeVwiO1xuaW1wb3J0IE1vbmVyb1R4Q29uZmlnIGZyb20gXCIuL21vZGVsL01vbmVyb1R4Q29uZmlnXCI7XG5pbXBvcnQgTW9uZXJvVHhQcmlvcml0eSBmcm9tIFwiLi9tb2RlbC9Nb25lcm9UeFByaW9yaXR5XCI7XG5pbXBvcnQgTW9uZXJvVHhRdWVyeSBmcm9tIFwiLi9tb2RlbC9Nb25lcm9UeFF1ZXJ5XCI7XG5pbXBvcnQgTW9uZXJvVHhXYWxsZXQgZnJvbSBcIi4vbW9kZWwvTW9uZXJvVHhXYWxsZXRcIjtcbmltcG9ydCBNb25lcm9UeFNldCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9UeFNldFwiO1xuaW1wb3J0IE1vbmVyb1V0aWxzIGZyb20gXCIuLi9jb21tb24vTW9uZXJvVXRpbHNcIjtcbmltcG9ydCBNb25lcm9WZXJzaW9uIGZyb20gXCIuLi9kYWVtb24vbW9kZWwvTW9uZXJvVmVyc2lvblwiO1xuaW1wb3J0IE1vbmVyb1dhbGxldExpc3RlbmVyIGZyb20gXCIuL21vZGVsL01vbmVyb1dhbGxldExpc3RlbmVyXCI7XG5cbi8qKlxuICogQ29weXJpZ2h0IChjKSB3b29kc2VyXG4gKlxuICogUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuICogb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxuICogaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0c1xuICogdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuICogY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXG4gKiBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuICpcbiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluIGFsbFxuICogY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbiAqXG4gKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4gKiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbiAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuICogQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuICogTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbiAqIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFXG4gKiBTT0ZUV0FSRS5cbiAqL1xuXG4vKipcbiAqIE1vbmVybyB3YWxsZXQgaW50ZXJmYWNlIGFuZCBkZWZhdWx0IGltcGxlbWVudGF0aW9ucy5cbiAqIFxuICogQGludGVyZmFjZVxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9XYWxsZXQge1xuXG4gIC8vIHN0YXRpYyB2YXJpYWJsZXNcbiAgc3RhdGljIHJlYWRvbmx5IERFRkFVTFRfTEFOR1VBR0UgPSBcIkVuZ2xpc2hcIjtcblxuICAvLyBzdGF0ZSB2YXJpYWJsZXNcbiAgcHJvdGVjdGVkIGNvbm5lY3Rpb25NYW5hZ2VyOiBNb25lcm9Db25uZWN0aW9uTWFuYWdlcjtcbiAgcHJvdGVjdGVkIGNvbm5lY3Rpb25NYW5hZ2VyTGlzdGVuZXI6IE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyTGlzdGVuZXI7XG4gIHByb3RlY3RlZCBsaXN0ZW5lcnM6IE1vbmVyb1dhbGxldExpc3RlbmVyW10gPSBbXTtcbiAgcHJvdGVjdGVkIF9pc0Nsb3NlZCA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBIaWRkZW4gY29uc3RydWN0b3IuXG4gICAqIFxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgLy8gbm8gY29kZSBuZWVkZWRcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJlZ2lzdGVyIGEgbGlzdGVuZXIgdG8gcmVjZWl2ZSB3YWxsZXQgbm90aWZpY2F0aW9ucy5cbiAgICogXG4gICAqIEBwYXJhbSB7TW9uZXJvV2FsbGV0TGlzdGVuZXJ9IGxpc3RlbmVyIC0gbGlzdGVuZXIgdG8gcmVjZWl2ZSB3YWxsZXQgbm90aWZpY2F0aW9uc1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgYWRkTGlzdGVuZXIobGlzdGVuZXI6IE1vbmVyb1dhbGxldExpc3RlbmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXNzZXJ0KGxpc3RlbmVyIGluc3RhbmNlb2YgTW9uZXJvV2FsbGV0TGlzdGVuZXIsIFwiTGlzdGVuZXIgbXVzdCBiZSBpbnN0YW5jZSBvZiBNb25lcm9XYWxsZXRMaXN0ZW5lclwiKTtcbiAgICB0aGlzLmxpc3RlbmVycy5wdXNoKGxpc3RlbmVyKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFVucmVnaXN0ZXIgYSBsaXN0ZW5lciB0byByZWNlaXZlIHdhbGxldCBub3RpZmljYXRpb25zLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9XYWxsZXRMaXN0ZW5lcn0gbGlzdGVuZXIgLSBsaXN0ZW5lciB0byB1bnJlZ2lzdGVyXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyByZW1vdmVMaXN0ZW5lcihsaXN0ZW5lcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGxldCBpZHggPSB0aGlzLmxpc3RlbmVycy5pbmRleE9mKGxpc3RlbmVyKTtcbiAgICBpZiAoaWR4ID4gLTEpIHRoaXMubGlzdGVuZXJzLnNwbGljZShpZHgsIDEpO1xuICAgIGVsc2UgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTGlzdGVuZXIgaXMgbm90IHJlZ2lzdGVyZWQgd2l0aCB3YWxsZXRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIGxpc3RlbmVycyByZWdpc3RlcmVkIHdpdGggdGhlIHdhbGxldC5cbiAgICogXG4gICAqIEByZXR1cm4ge01vbmVyb1dhbGxldExpc3RlbmVyW119IHRoZSByZWdpc3RlcmVkIGxpc3RlbmVyc1xuICAgKi9cbiAgZ2V0TGlzdGVuZXJzKCk6IE1vbmVyb1dhbGxldExpc3RlbmVyW10ge1xuICAgIHJldHVybiB0aGlzLmxpc3RlbmVycztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgd2FsbGV0IGlzIHZpZXctb25seSwgbWVhbmluZyBpdCBkb2VzIG5vdCBoYXZlIHRoZSBwcml2YXRlXG4gICAqIHNwZW5kIGtleSBhbmQgY2FuIHRoZXJlZm9yZSBvbmx5IG9ic2VydmUgaW5jb21pbmcgb3V0cHV0cy5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbGVhbj59IHRydWUgaWYgdGhlIHdhbGxldCBpcyB2aWV3LW9ubHksIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgYXN5bmMgaXNWaWV3T25seSgpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogU2V0IHRoZSB3YWxsZXQncyBkYWVtb24gY29ubmVjdGlvbi5cbiAgICogXG4gICAqIEBwYXJhbSB7TW9uZXJvUnBjQ29ubmVjdGlvbiB8IHN0cmluZ30gW3VyaU9yQ29ubmVjdGlvbl0gLSBkYWVtb24ncyBVUkkgb3IgY29ubmVjdGlvbiAoZGVmYXVsdHMgdG8gb2ZmbGluZSlcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHNldERhZW1vbkNvbm5lY3Rpb24odXJpT3JDb25uZWN0aW9uPzogTW9uZXJvUnBjQ29ubmVjdGlvbiB8IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIHdhbGxldCdzIGRhZW1vbiBjb25uZWN0aW9uLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9ScGNDb25uZWN0aW9uPn0gdGhlIHdhbGxldCdzIGRhZW1vbiBjb25uZWN0aW9uXG4gICAqL1xuICBhc3luYyBnZXREYWVtb25Db25uZWN0aW9uKCk6IFByb21pc2U8TW9uZXJvUnBjQ29ubmVjdGlvbj4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSB3YWxsZXQncyBkYWVtb24gY29ubmVjdGlvbiBtYW5hZ2VyLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9Db25uZWN0aW9uTWFuYWdlcn0gY29ubmVjdGlvbk1hbmFnZXIgbWFuYWdlcyBjb25uZWN0aW9ucyB0byBtb25lcm9kXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBzZXRDb25uZWN0aW9uTWFuYWdlcihjb25uZWN0aW9uTWFuYWdlcj86IE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuY29ubmVjdGlvbk1hbmFnZXIpIHRoaXMuY29ubmVjdGlvbk1hbmFnZXIucmVtb3ZlTGlzdGVuZXIodGhpcy5jb25uZWN0aW9uTWFuYWdlckxpc3RlbmVyKTtcbiAgICB0aGlzLmNvbm5lY3Rpb25NYW5hZ2VyID0gY29ubmVjdGlvbk1hbmFnZXI7XG4gICAgaWYgKCFjb25uZWN0aW9uTWFuYWdlcikgcmV0dXJuO1xuICAgIGxldCB0aGF0ID0gdGhpcztcbiAgICBpZiAoIXRoaXMuY29ubmVjdGlvbk1hbmFnZXJMaXN0ZW5lcikgdGhpcy5jb25uZWN0aW9uTWFuYWdlckxpc3RlbmVyID0gbmV3IGNsYXNzIGV4dGVuZHMgTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJMaXN0ZW5lciB7XG4gICAgICBhc3luYyBvbkNvbm5lY3Rpb25DaGFuZ2VkKGNvbm5lY3Rpb246IE1vbmVyb1JwY0Nvbm5lY3Rpb24gfCB1bmRlZmluZWQpIHtcbiAgICAgICAgYXdhaXQgdGhhdC5zZXREYWVtb25Db25uZWN0aW9uKGNvbm5lY3Rpb24pO1xuICAgICAgfVxuICAgIH07XG4gICAgY29ubmVjdGlvbk1hbmFnZXIuYWRkTGlzdGVuZXIodGhpcy5jb25uZWN0aW9uTWFuYWdlckxpc3RlbmVyKTtcbiAgICBhd2FpdCB0aGlzLnNldERhZW1vbkNvbm5lY3Rpb24oY29ubmVjdGlvbk1hbmFnZXIuZ2V0Q29ubmVjdGlvbigpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIHdhbGxldCdzIGRhZW1vbiBjb25uZWN0aW9uIG1hbmFnZXIuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyPn0gdGhlIHdhbGxldCdzIGRhZW1vbiBjb25uZWN0aW9uIG1hbmFnZXJcbiAgICovXG4gIGFzeW5jIGdldENvbm5lY3Rpb25NYW5hZ2VyKCk6IFByb21pc2U8TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXI+IHtcbiAgICByZXR1cm4gdGhpcy5jb25uZWN0aW9uTWFuYWdlcjtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgd2FsbGV0IGlzIGNvbm5lY3RlZCB0byBkYWVtb24uXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPGJvb2xlYW4+fSB0cnVlIGlmIHRoZSB3YWxsZXQgaXMgY29ubmVjdGVkIHRvIGEgZGFlbW9uLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIGFzeW5jIGlzQ29ubmVjdGVkVG9EYWVtb24oKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldHMgdGhlIHZlcnNpb24gb2YgdGhlIHdhbGxldC5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvVmVyc2lvbj59IHRoZSB2ZXJzaW9uIG9mIHRoZSB3YWxsZXRcbiAgICovXG4gIGFzeW5jIGdldFZlcnNpb24oKTogUHJvbWlzZTxNb25lcm9WZXJzaW9uPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgd2FsbGV0J3MgcGF0aC5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nPn0gdGhlIHBhdGggdGhlIHdhbGxldCBjYW4gYmUgb3BlbmVkIHdpdGhcbiAgICovXG4gIGFzeW5jIGdldFBhdGgoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSB3YWxsZXQncyBtbmVtb25pYyBwaHJhc2Ugb3Igc2VlZC5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nPn0gdGhlIHdhbGxldCdzIG1uZW1vbmljIHBocmFzZSBvciBzZWVkLlxuICAgKi9cbiAgYXN5bmMgZ2V0U2VlZCgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIGxhbmd1YWdlIG9mIHRoZSB3YWxsZXQncyBtbmVtb25pYyBwaHJhc2Ugb3Igc2VlZC5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nPn0gdGhlIGxhbmd1YWdlIG9mIHRoZSB3YWxsZXQncyBtbmVtb25pYyBwaHJhc2Ugb3Igc2VlZC5cbiAgICovXG4gIGFzeW5jIGdldFNlZWRMYW5ndWFnZSgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIHdhbGxldCdzIHByaXZhdGUgdmlldyBrZXkuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZz59IHRoZSB3YWxsZXQncyBwcml2YXRlIHZpZXcga2V5XG4gICAqL1xuICBhc3luYyBnZXRQcml2YXRlVmlld0tleSgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIHdhbGxldCdzIHByaXZhdGUgc3BlbmQga2V5LlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSB0aGUgd2FsbGV0J3MgcHJpdmF0ZSBzcGVuZCBrZXlcbiAgICovXG4gIGFzeW5jIGdldFByaXZhdGVTcGVuZEtleSgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIHdhbGxldCdzIHB1YmxpYyB2aWV3IGtleS5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nPn0gdGhlIHdhbGxldCdzIHB1YmxpYyB2aWV3IGtleVxuICAgKi9cbiAgYXN5bmMgZ2V0UHVibGljVmlld0tleSgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIHdhbGxldCdzIHB1YmxpYyBzcGVuZCBrZXkuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZz59IHRoZSB3YWxsZXQncyBwdWJsaWMgc3BlbmQga2V5XG4gICAqL1xuICBhc3luYyBnZXRQdWJsaWNTcGVuZEtleSgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgICBcbiAgLyoqXG4gICAqIEdldCB0aGUgd2FsbGV0J3MgcHJpbWFyeSBhZGRyZXNzLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSB0aGUgd2FsbGV0J3MgcHJpbWFyeSBhZGRyZXNzXG4gICAqL1xuICBhc3luYyBnZXRQcmltYXJ5QWRkcmVzcygpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiBhd2FpdCB0aGlzLmdldEFkZHJlc3MoMCwgMCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIGFkZHJlc3Mgb2YgYSBzcGVjaWZpYyBzdWJhZGRyZXNzLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IGFjY291bnRJZHggLSB0aGUgYWNjb3VudCBpbmRleCBvZiB0aGUgYWRkcmVzcydzIHN1YmFkZHJlc3NcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN1YmFkZHJlc3NJZHggLSB0aGUgc3ViYWRkcmVzcyBpbmRleCB3aXRoaW4gdGhlIGFjY291bnRcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSB0aGUgcmVjZWl2ZSBhZGRyZXNzIG9mIHRoZSBzcGVjaWZpZWQgc3ViYWRkcmVzc1xuICAgKi9cbiAgYXN5bmMgZ2V0QWRkcmVzcyhhY2NvdW50SWR4OiBudW1iZXIsIHN1YmFkZHJlc3NJZHg6IG51bWJlcik6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgYWNjb3VudCBhbmQgc3ViYWRkcmVzcyBpbmRleCBvZiB0aGUgZ2l2ZW4gYWRkcmVzcy5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzIC0gYWRkcmVzcyB0byBnZXQgdGhlIGFjY291bnQgYW5kIHN1YmFkZHJlc3MgaW5kZXggZnJvbVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb1N1YmFkZHJlc3M+fSB0aGUgYWNjb3VudCBhbmQgc3ViYWRkcmVzcyBpbmRpY2VzXG4gICAqL1xuICBhc3luYyBnZXRBZGRyZXNzSW5kZXgoYWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9TdWJhZGRyZXNzPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBhbiBpbnRlZ3JhdGVkIGFkZHJlc3MgYmFzZWQgb24gdGhlIGdpdmVuIHN0YW5kYXJkIGFkZHJlc3MgYW5kIHBheW1lbnRcbiAgICogSUQuIFVzZXMgdGhlIHdhbGxldCdzIHByaW1hcnkgYWRkcmVzcyBpZiBhbiBhZGRyZXNzIGlzIG5vdCBnaXZlbi5cbiAgICogR2VuZXJhdGVzIGEgcmFuZG9tIHBheW1lbnQgSUQgaWYgYSBwYXltZW50IElEIGlzIG5vdCBnaXZlbi5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzdGFuZGFyZEFkZHJlc3MgaXMgdGhlIHN0YW5kYXJkIGFkZHJlc3MgdG8gZ2VuZXJhdGUgdGhlIGludGVncmF0ZWQgYWRkcmVzcyBmcm9tICh3YWxsZXQncyBwcmltYXJ5IGFkZHJlc3MgaWYgdW5kZWZpbmVkKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGF5bWVudElkIGlzIHRoZSBwYXltZW50IElEIHRvIGdlbmVyYXRlIGFuIGludGVncmF0ZWQgYWRkcmVzcyBmcm9tIChyYW5kb21seSBnZW5lcmF0ZWQgaWYgdW5kZWZpbmVkKVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb0ludGVncmF0ZWRBZGRyZXNzPn0gdGhlIGludGVncmF0ZWQgYWRkcmVzc1xuICAgKi9cbiAgYXN5bmMgZ2V0SW50ZWdyYXRlZEFkZHJlc3Moc3RhbmRhcmRBZGRyZXNzPzogc3RyaW5nLCBwYXltZW50SWQ/OiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0ludGVncmF0ZWRBZGRyZXNzPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIERlY29kZSBhbiBpbnRlZ3JhdGVkIGFkZHJlc3MgdG8gZ2V0IGl0cyBzdGFuZGFyZCBhZGRyZXNzIGFuZCBwYXltZW50IGlkLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IGludGVncmF0ZWRBZGRyZXNzIC0gaW50ZWdyYXRlZCBhZGRyZXNzIHRvIGRlY29kZVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb0ludGVncmF0ZWRBZGRyZXNzPn0gdGhlIGRlY29kZWQgaW50ZWdyYXRlZCBhZGRyZXNzIGluY2x1ZGluZyBzdGFuZGFyZCBhZGRyZXNzIGFuZCBwYXltZW50IGlkXG4gICAqL1xuICBhc3luYyBkZWNvZGVJbnRlZ3JhdGVkQWRkcmVzcyhpbnRlZ3JhdGVkQWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIGJsb2NrIGhlaWdodCB0aGF0IHRoZSB3YWxsZXQgaXMgc3luY2VkIHRvLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxudW1iZXI+fSB0aGUgYmxvY2sgaGVpZ2h0IHRoYXQgdGhlIHdhbGxldCBpcyBzeW5jZWQgdG9cbiAgICovXG4gIGFzeW5jIGdldEhlaWdodCgpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIGJsb2NrY2hhaW4ncyBoZWlnaHQuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPG51bWJlcj59IHRoZSBibG9ja2NoYWluJ3MgaGVpZ2h0XG4gICAqL1xuICBhc3luYyBnZXREYWVtb25IZWlnaHQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSBibG9ja2NoYWluJ3MgaGVpZ2h0IGJ5IGRhdGUgYXMgYSBjb25zZXJ2YXRpdmUgZXN0aW1hdGUgZm9yIHNjYW5uaW5nLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IHllYXIgLSB5ZWFyIG9mIHRoZSBoZWlnaHQgdG8gZ2V0XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBtb250aCAtIG1vbnRoIG9mIHRoZSBoZWlnaHQgdG8gZ2V0IGFzIGEgbnVtYmVyIGJldHdlZW4gMSBhbmQgMTJcbiAgICogQHBhcmFtIHtudW1iZXJ9IGRheSAtIGRheSBvZiB0aGUgaGVpZ2h0IHRvIGdldCBhcyBhIG51bWJlciBiZXR3ZWVuIDEgYW5kIDMxXG4gICAqIEByZXR1cm4ge1Byb21pc2U8bnVtYmVyPn0gdGhlIGJsb2NrY2hhaW4ncyBhcHByb3hpbWF0ZSBoZWlnaHQgYXQgdGhlIGdpdmVuIGRhdGVcbiAgICovXG4gIGFzeW5jIGdldEhlaWdodEJ5RGF0ZSh5ZWFyOiBudW1iZXIsIG1vbnRoOiBudW1iZXIsIGRheTogbnVtYmVyKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogU3luY2hyb25pemUgdGhlIHdhbGxldCB3aXRoIHRoZSBkYWVtb24gYXMgYSBvbmUtdGltZSBzeW5jaHJvbm91cyBwcm9jZXNzLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9XYWxsZXRMaXN0ZW5lcnxudW1iZXJ9IFtsaXN0ZW5lck9yU3RhcnRIZWlnaHRdIC0gbGlzdGVuZXIgeG9yIHN0YXJ0IGhlaWdodCAoZGVmYXVsdHMgdG8gbm8gc3luYyBsaXN0ZW5lciwgdGhlIGxhc3Qgc3luY2VkIGJsb2NrKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXJ0SGVpZ2h0XSAtIHN0YXJ0SGVpZ2h0IGlmIG5vdCBnaXZlbiBpbiBmaXJzdCBhcmcgKGRlZmF1bHRzIHRvIGxhc3Qgc3luY2VkIGJsb2NrKVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgc3luYyhsaXN0ZW5lck9yU3RhcnRIZWlnaHQ/OiBNb25lcm9XYWxsZXRMaXN0ZW5lciB8IG51bWJlciwgc3RhcnRIZWlnaHQ/OiBudW1iZXIpOiBQcm9taXNlPE1vbmVyb1N5bmNSZXN1bHQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogU3RhcnQgYmFja2dyb3VuZCBzeW5jaHJvbml6aW5nIHdpdGggYSBtYXhpbXVtIHBlcmlvZCBiZXR3ZWVuIHN5bmNzLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtzeW5jUGVyaW9kSW5Nc10gLSBtYXhpbXVtIHBlcmlvZCBiZXR3ZWVuIHN5bmNzIGluIG1pbGxpc2Vjb25kcyAoZGVmYXVsdCBpcyB3YWxsZXQtc3BlY2lmaWMpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBzdGFydFN5bmNpbmcoc3luY1BlcmlvZEluTXM/OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogU3RvcCBzeW5jaHJvbml6aW5nIHRoZSB3YWxsZXQgd2l0aCB0aGUgZGFlbW9uLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHN0b3BTeW5jaW5nKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTY2FuIHRyYW5zYWN0aW9ucyBieSB0aGVpciBoYXNoL2lkLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gdHhIYXNoZXMgLSB0eCBoYXNoZXMgdG8gc2NhblxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgc2NhblR4cyh0eEhhc2hlczogc3RyaW5nW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogPHA+UmVzY2FuIHRoZSBibG9ja2NoYWluIGZvciBzcGVudCBvdXRwdXRzLjwvcD5cbiAgICogXG4gICAqIDxwPk5vdGU6IHRoaXMgY2FuIG9ubHkgYmUgY2FsbGVkIHdpdGggYSB0cnVzdGVkIGRhZW1vbi48L3A+XG4gICAqIFxuICAgKiA8cD5FeGFtcGxlIHVzZSBjYXNlOiBwZWVyIG11bHRpc2lnIGhleCBpcyBpbXBvcnQgd2hlbiBjb25uZWN0ZWQgdG8gYW4gdW50cnVzdGVkIGRhZW1vbixcbiAgICogc28gdGhlIHdhbGxldCB3aWxsIG5vdCByZXNjYW4gc3BlbnQgb3V0cHV0cy4gIFRoZW4gdGhlIHdhbGxldCBjb25uZWN0cyB0byBhIHRydXN0ZWRcbiAgICogZGFlbW9uLiAgVGhpcyBtZXRob2Qgc2hvdWxkIGJlIG1hbnVhbGx5IGludm9rZWQgdG8gcmVzY2FuIG91dHB1dHMuPC9wPlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHJlc2NhblNwZW50KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiA8cD5SZXNjYW4gdGhlIGJsb2NrY2hhaW4gZnJvbSBzY3JhdGNoLCBsb3NpbmcgYW55IGluZm9ybWF0aW9uIHdoaWNoIGNhbm5vdCBiZSByZWNvdmVyZWQgZnJvbVxuICAgKiB0aGUgYmxvY2tjaGFpbiBpdHNlbGYuPC9wPlxuICAgKiBcbiAgICogPHA+V0FSTklORzogVGhpcyBtZXRob2QgZGlzY2FyZHMgbG9jYWwgd2FsbGV0IGRhdGEgbGlrZSBkZXN0aW5hdGlvbiBhZGRyZXNzZXMsIHR4IHNlY3JldCBrZXlzLFxuICAgKiB0eCBub3RlcywgZXRjLjwvcD5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyByZXNjYW5CbG9ja2NoYWluKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIGJhbGFuY2Ugb2YgdGhlIHdhbGxldCwgYWNjb3VudCwgb3Igc3ViYWRkcmVzcy5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbYWNjb3VudElkeF0gLSBpbmRleCBvZiB0aGUgYWNjb3VudCB0byBnZXQgdGhlIGJhbGFuY2Ugb2YgKGRlZmF1bHQgYWxsIGFjY291bnRzKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW3N1YmFkZHJlc3NJZHhdIC0gaW5kZXggb2YgdGhlIHN1YmFkZHJlc3MgdG8gZ2V0IHRoZSBiYWxhbmNlIG9mIChkZWZhdWx0IGFsbCBzdWJhZGRyZXNzZXMpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8YmlnaW50Pn0gdGhlIGJhbGFuY2Ugb2YgdGhlIHdhbGxldCwgYWNjb3VudCwgb3Igc3ViYWRkcmVzc1xuICAgKi9cbiAgYXN5bmMgZ2V0QmFsYW5jZShhY2NvdW50SWR4PzogbnVtYmVyLCBzdWJhZGRyZXNzSWR4PzogbnVtYmVyKTogUHJvbWlzZTxiaWdpbnQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSB1bmxvY2tlZCBiYWxhbmNlIG9mIHRoZSB3YWxsZXQsIGFjY291bnQsIG9yIHN1YmFkZHJlc3MuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FjY291bnRJZHhdIC0gaW5kZXggb2YgdGhlIGFjY291bnQgdG8gZ2V0IHRoZSB1bmxvY2tlZCBiYWxhbmNlIG9mIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtzdWJhZGRyZXNzSWR4XSAtIGluZGV4IG9mIHRoZSBzdWJhZGRyZXNzIHRvIGdldCB0aGUgdW5sb2NrZWQgYmFsYW5jZSBvZiAob3B0aW9uYWwpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8YmlnaW50Pn0gdGhlIHVubG9ja2VkIGJhbGFuY2Ugb2YgdGhlIHdhbGxldCwgYWNjb3VudCwgb3Igc3ViYWRkcmVzc1xuICAgKi9cbiAgYXN5bmMgZ2V0VW5sb2NrZWRCYWxhbmNlKGFjY291bnRJZHg/OiBudW1iZXIsIHN1YmFkZHJlc3NJZHg/OiBudW1iZXIpOiBQcm9taXNlPGJpZ2ludD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIG51bWJlciBvZiBibG9ja3MgdW50aWwgdGhlIG5leHQgYW5kIGxhc3QgZnVuZHMgdW5sb2NrLiBJZ25vcmVzIHR4cyB3aXRoIHVubG9jayB0aW1lIGFzIHRpbWVzdGFtcC5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8bnVtYmVyW10+fSB0aGUgbnVtYmVyIG9mIGJsb2NrcyB1bnRpbCB0aGUgbmV4dCBhbmQgbGFzdCBmdW5kcyB1bmxvY2sgaW4gZWxlbWVudHMgMCBhbmQgMSwgcmVzcGVjdGl2ZWx5LCBvciB1bmRlZmluZWQgaWYgbm8gYmFsYW5jZVxuICAgKi9cbiAgYXN5bmMgZ2V0TnVtQmxvY2tzVG9VbmxvY2soKTogUHJvbWlzZTxudW1iZXJbXXx1bmRlZmluZWQ+IHtcbiAgICBcbiAgICAvLyBnZXQgYmFsYW5jZXNcbiAgICBsZXQgYmFsYW5jZSA9IGF3YWl0IHRoaXMuZ2V0QmFsYW5jZSgpO1xuICAgIGlmIChiYWxhbmNlID09PSAwbikgcmV0dXJuIFt1bmRlZmluZWQsIHVuZGVmaW5lZF07IC8vIHNraXAgaWYgbm8gYmFsYW5jZVxuICAgIGxldCB1bmxvY2tlZEJhbGFuY2UgPSBhd2FpdCB0aGlzLmdldFVubG9ja2VkQmFsYW5jZSgpO1xuICAgIFxuICAgIC8vIGNvbXB1dGUgbnVtYmVyIG9mIGJsb2NrcyB1bnRpbCBuZXh0IGZ1bmRzIGF2YWlsYWJsZVxuICAgIGxldCB0eHM6IE1vbmVyb1R4V2FsbGV0W107XG4gICAgbGV0IGhlaWdodDogbnVtYmVyO1xuICAgIGxldCBudW1CbG9ja3NUb05leHRVbmxvY2sgPSB1bmRlZmluZWQ7XG4gICAgaWYgKHVubG9ja2VkQmFsYW5jZSA+IDBuKSBudW1CbG9ja3NUb05leHRVbmxvY2sgPSAwO1xuICAgIGVsc2Uge1xuICAgICAgdHhzID0gYXdhaXQgdGhpcy5nZXRUeHMoe2lzTG9ja2VkOiB0cnVlfSk7IC8vIGdldCBsb2NrZWQgdHhzXG4gICAgICBoZWlnaHQgPSBhd2FpdCB0aGlzLmdldEhlaWdodCgpOyAvLyBnZXQgbW9zdCByZWNlbnQgaGVpZ2h0XG4gICAgICBmb3IgKGxldCB0eCBvZiB0eHMpIHtcbiAgICAgICAgaWYgKCF0eC5nZXRJc0NvbmZpcm1lZCgpICYmIE1vbmVyb1V0aWxzLmlzVGltZXN0YW1wKHR4LmdldFVubG9ja1RpbWUoKSkpIGNvbnRpbnVlO1xuICAgICAgICBsZXQgbnVtQmxvY2tzVG9VbmxvY2sgPSBNYXRoLm1heCgodHguZ2V0SXNDb25maXJtZWQoKSA/IHR4LmdldEhlaWdodCgpIDogaGVpZ2h0KSArIDEwLCBOdW1iZXIodHguZ2V0VW5sb2NrVGltZSgpKSkgLSBoZWlnaHQ7XG4gICAgICAgIG51bUJsb2Nrc1RvTmV4dFVubG9jayA9IG51bUJsb2Nrc1RvTmV4dFVubG9jayA9PT0gdW5kZWZpbmVkID8gbnVtQmxvY2tzVG9VbmxvY2sgOiBNYXRoLm1pbihudW1CbG9ja3NUb05leHRVbmxvY2ssIG51bUJsb2Nrc1RvVW5sb2NrKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gY29tcHV0ZSBudW1iZXIgb2YgYmxvY2tzIHVudGlsIGFsbCBmdW5kcyBhdmFpbGFibGVcbiAgICBsZXQgbnVtQmxvY2tzVG9MYXN0VW5sb2NrID0gdW5kZWZpbmVkO1xuICAgIGlmIChiYWxhbmNlID09PSB1bmxvY2tlZEJhbGFuY2UpIHtcbiAgICAgIGlmICh1bmxvY2tlZEJhbGFuY2UgPiAwbikgbnVtQmxvY2tzVG9MYXN0VW5sb2NrID0gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKCF0eHMpIHtcbiAgICAgICAgdHhzID0gYXdhaXQgdGhpcy5nZXRUeHMoe2lzTG9ja2VkOiB0cnVlfSk7IC8vIGdldCBsb2NrZWQgdHhzXG4gICAgICAgIGhlaWdodCA9IGF3YWl0IHRoaXMuZ2V0SGVpZ2h0KCk7IC8vIGdldCBtb3N0IHJlY2VudCBoZWlnaHRcbiAgICAgIH1cbiAgICAgIGZvciAobGV0IHR4IG9mIHR4cykge1xuICAgICAgICBpZiAoIXR4LmdldElzQ29uZmlybWVkKCkgJiYgTW9uZXJvVXRpbHMuaXNUaW1lc3RhbXAodHguZ2V0VW5sb2NrVGltZSgpKSkgY29udGludWU7XG4gICAgICAgIGxldCBudW1CbG9ja3NUb1VubG9jayA9IE1hdGgubWF4KCh0eC5nZXRJc0NvbmZpcm1lZCgpID8gdHguZ2V0SGVpZ2h0KCkgOiBoZWlnaHQpICsgMTAsIE51bWJlcih0eC5nZXRVbmxvY2tUaW1lKCkpKSAtIGhlaWdodDtcbiAgICAgICAgbnVtQmxvY2tzVG9MYXN0VW5sb2NrID0gbnVtQmxvY2tzVG9MYXN0VW5sb2NrID09PSB1bmRlZmluZWQgPyBudW1CbG9ja3NUb1VubG9jayA6IE1hdGgubWF4KG51bUJsb2Nrc1RvTGFzdFVubG9jaywgbnVtQmxvY2tzVG9VbmxvY2spO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICByZXR1cm4gW251bUJsb2Nrc1RvTmV4dFVubG9jaywgbnVtQmxvY2tzVG9MYXN0VW5sb2NrXTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBhY2NvdW50cyB3aXRoIGEgZ2l2ZW4gdGFnLlxuICAgKiBcbiAgICogQHBhcmFtIHtib29sZWFufSBpbmNsdWRlU3ViYWRkcmVzc2VzIC0gaW5jbHVkZSBzdWJhZGRyZXNzZXMgaWYgdHJ1ZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFnIC0gdGFnIGZvciBmaWx0ZXJpbmcgYWNjb3VudHMsIGFsbCBhY2NvdW50cyBpZiB1bmRlZmluZWRcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9BY2NvdW50W10+fSBhbGwgYWNjb3VudHMgd2l0aCB0aGUgZ2l2ZW4gdGFnXG4gICAqL1xuICBhc3luYyBnZXRBY2NvdW50cyhpbmNsdWRlU3ViYWRkcmVzc2VzPzogYm9vbGVhbiwgdGFnPzogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9BY2NvdW50W10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGFuIGFjY291bnQuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gYWNjb3VudElkeCAtIGluZGV4IG9mIHRoZSBhY2NvdW50IHRvIGdldFxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IGluY2x1ZGVTdWJhZGRyZXNzZXMgLSBpbmNsdWRlIHN1YmFkZHJlc3NlcyBpZiB0cnVlXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQWNjb3VudD59IHRoZSByZXRyaWV2ZWQgYWNjb3VudFxuICAgKi9cbiAgYXN5bmMgZ2V0QWNjb3VudChhY2NvdW50SWR4OiBudW1iZXIsIGluY2x1ZGVTdWJhZGRyZXNzZXM/OiBib29sZWFuKTogUHJvbWlzZTxNb25lcm9BY2NvdW50PiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIENyZWF0ZSBhIG5ldyBhY2NvdW50IHdpdGggYSBsYWJlbCBmb3IgdGhlIGZpcnN0IHN1YmFkZHJlc3MuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2xhYmVsXSAtIGxhYmVsIGZvciBhY2NvdW50J3MgZmlyc3Qgc3ViYWRkcmVzcyAob3B0aW9uYWwpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQWNjb3VudD59IHRoZSBjcmVhdGVkIGFjY291bnRcbiAgICovXG4gIGFzeW5jIGNyZWF0ZUFjY291bnQobGFiZWw/OiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0FjY291bnQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCBhbiBhY2NvdW50IGxhYmVsLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IGFjY291bnRJZHggLSBpbmRleCBvZiB0aGUgYWNjb3VudCB0byBzZXQgdGhlIGxhYmVsIGZvclxuICAgKiBAcGFyYW0ge3N0cmluZ30gbGFiZWwgLSB0aGUgbGFiZWwgdG8gc2V0XG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBzZXRBY2NvdW50TGFiZWwoYWNjb3VudElkeDogbnVtYmVyLCBsYWJlbDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5zZXRTdWJhZGRyZXNzTGFiZWwoYWNjb3VudElkeCwgMCwgbGFiZWwpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHN1YmFkZHJlc3NlcyBpbiBhbiBhY2NvdW50LlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IGFjY291bnRJZHggLSBhY2NvdW50IHRvIGdldCBzdWJhZGRyZXNzZXMgd2l0aGluXG4gICAqIEBwYXJhbSB7bnVtYmVyW119IFtzdWJhZGRyZXNzSW5kaWNlc10gLSBpbmRpY2VzIG9mIHN1YmFkZHJlc3NlcyB0byBnZXQgKG9wdGlvbmFsKVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb1N1YmFkZHJlc3NbXT59IHRoZSByZXRyaWV2ZWQgc3ViYWRkcmVzc2VzXG4gICAqL1xuICBhc3luYyBnZXRTdWJhZGRyZXNzZXMoYWNjb3VudElkeDogbnVtYmVyLCBzdWJhZGRyZXNzSW5kaWNlcz86IG51bWJlcltdKTogUHJvbWlzZTxNb25lcm9TdWJhZGRyZXNzW10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGEgc3ViYWRkcmVzcy5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBhY2NvdW50SWR4IC0gaW5kZXggb2YgdGhlIHN1YmFkZHJlc3MncyBhY2NvdW50XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzdWJhZGRyZXNzSWR4IC0gaW5kZXggb2YgdGhlIHN1YmFkZHJlc3Mgd2l0aGluIHRoZSBhY2NvdW50XG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvU3ViYWRkcmVzcz59IHRoZSByZXRyaWV2ZWQgc3ViYWRkcmVzc1xuICAgKi9cbiAgYXN5bmMgZ2V0U3ViYWRkcmVzcyhhY2NvdW50SWR4OiBudW1iZXIsIHN1YmFkZHJlc3NJZHg6IG51bWJlcik6IFByb21pc2U8TW9uZXJvU3ViYWRkcmVzcz4ge1xuICAgIGFzc2VydChhY2NvdW50SWR4ID49IDApO1xuICAgIGFzc2VydChzdWJhZGRyZXNzSWR4ID49IDApO1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5nZXRTdWJhZGRyZXNzZXMoYWNjb3VudElkeCwgW3N1YmFkZHJlc3NJZHhdKSlbMF07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBzdWJhZGRyZXNzIHdpdGhpbiBhbiBhY2NvdW50LlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IGFjY291bnRJZHggLSBpbmRleCBvZiB0aGUgYWNjb3VudCB0byBjcmVhdGUgdGhlIHN1YmFkZHJlc3Mgd2l0aGluXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbbGFiZWxdIC0gdGhlIGxhYmVsIGZvciB0aGUgc3ViYWRkcmVzcyAob3B0aW9uYWwpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvU3ViYWRkcmVzcz59IHRoZSBjcmVhdGVkIHN1YmFkZHJlc3NcbiAgICovXG4gIGFzeW5jIGNyZWF0ZVN1YmFkZHJlc3MoYWNjb3VudElkeDogbnVtYmVyLCBsYWJlbD86IHN0cmluZyk6IFByb21pc2U8TW9uZXJvU3ViYWRkcmVzcz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cblxuICAvKipcbiAgICogU2V0IGEgc3ViYWRkcmVzcyBsYWJlbC5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBhY2NvdW50SWR4IC0gaW5kZXggb2YgdGhlIGFjY291bnQgdG8gc2V0IHRoZSBsYWJlbCBmb3JcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN1YmFkZHJlc3NJZHggLSBpbmRleCBvZiB0aGUgc3ViYWRkcmVzcyB0byBzZXQgdGhlIGxhYmVsIGZvclxuICAgKiBAcGFyYW0ge1Byb21pc2U8c3RyaW5nPn0gbGFiZWwgLSB0aGUgbGFiZWwgdG8gc2V0XG4gICAqL1xuICBhc3luYyBzZXRTdWJhZGRyZXNzTGFiZWwoYWNjb3VudElkeDogbnVtYmVyLCBzdWJhZGRyZXNzSWR4OiBudW1iZXIsIGxhYmVsOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGEgd2FsbGV0IHRyYW5zYWN0aW9uIGJ5IGhhc2guXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHhIYXNoIC0gaGFzaCBvZiBhIHRyYW5zYWN0aW9uIHRvIGdldFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb1R4V2FsbGV0PiB9IHRoZSBpZGVudGlmaWVkIHRyYW5zYWN0aW9uIG9yIHVuZGVmaW5lZCBpZiBub3QgZm91bmRcbiAgICovXG4gIGFzeW5jIGdldFR4KHR4SGFzaDogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9UeFdhbGxldHx1bmRlZmluZWQ+IHtcbiAgICBsZXQgdHhzID0gYXdhaXQgdGhpcy5nZXRUeHMoW3R4SGFzaF0pO1xuICAgIHJldHVybiB0eHMubGVuZ3RoID09PSAwID8gdW5kZWZpbmVkIDogdHhzWzBdOyBcbiAgfVxuICBcbiAgLyoqXG4gICAqIDxwPkdldCB3YWxsZXQgdHJhbnNhY3Rpb25zLiAgV2FsbGV0IHRyYW5zYWN0aW9ucyBjb250YWluIG9uZSBvciBtb3JlXG4gICAqIHRyYW5zZmVycyB0aGF0IGFyZSBlaXRoZXIgaW5jb21pbmcgb3Igb3V0Z29pbmcgdG8gdGhlIHdhbGxldC48cD5cbiAgICogXG4gICAqIDxwPlJlc3VsdHMgY2FuIGJlIGZpbHRlcmVkIGJ5IHBhc3NpbmcgYSBxdWVyeSBvYmplY3QuICBUcmFuc2FjdGlvbnMgbXVzdFxuICAgKiBtZWV0IGV2ZXJ5IGNyaXRlcmlhIGRlZmluZWQgaW4gdGhlIHF1ZXJ5IGluIG9yZGVyIHRvIGJlIHJldHVybmVkLiAgQWxsXG4gICAqIGNyaXRlcmlhIGFyZSBvcHRpb25hbCBhbmQgbm8gZmlsdGVyaW5nIGlzIGFwcGxpZWQgd2hlbiBub3QgZGVmaW5lZC48L3A+XG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ1tdIHwgTW9uZXJvVHhRdWVyeX0gW3F1ZXJ5XSAtIGNvbmZpZ3VyZXMgdGhlIHF1ZXJ5IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtib29sZWFufSBbcXVlcnkuaXNDb25maXJtZWRdIC0gZ2V0IHR4cyB0aGF0IGFyZSBjb25maXJtZWQgb3Igbm90IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtib29sZWFufSBbcXVlcnkuaW5UeFBvb2xdIC0gZ2V0IHR4cyB0aGF0IGFyZSBpbiB0aGUgdHggcG9vbCBvciBub3QgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtxdWVyeS5pc1JlbGF5ZWRdIC0gZ2V0IHR4cyB0aGF0IGFyZSByZWxheWVkIG9yIG5vdCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3F1ZXJ5LmlzRmFpbGVkXSAtIGdldCB0eHMgdGhhdCBhcmUgZmFpbGVkIG9yIG5vdCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3F1ZXJ5LmlzTWluZXJUeF0gLSBnZXQgbWluZXIgdHhzIG9yIG5vdCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcXVlcnkuaGFzaF0gLSBnZXQgYSB0eCB3aXRoIHRoZSBoYXNoIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gW3F1ZXJ5Lmhhc2hlc10gLSBnZXQgdHhzIHdpdGggdGhlIGhhc2hlcyAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcXVlcnkucGF5bWVudElkXSAtIGdldCB0cmFuc2FjdGlvbnMgd2l0aCB0aGUgcGF5bWVudCBpZCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IFtxdWVyeS5wYXltZW50SWRzXSAtIGdldCB0cmFuc2FjdGlvbnMgd2l0aCB0aGUgcGF5bWVudCBpZHMgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtxdWVyeS5oYXNQYXltZW50SWRdIC0gZ2V0IHRyYW5zYWN0aW9ucyB3aXRoIGEgcGF5bWVudCBpZCBvciBub3QgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW3F1ZXJ5Lm1pbkhlaWdodF0gLSBnZXQgdHhzIHdpdGggaGVpZ2h0ID49IHRoZSBnaXZlbiBoZWlnaHQgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW3F1ZXJ5Lm1heEhlaWdodF0gLSBnZXQgdHhzIHdpdGggaGVpZ2h0IDw9IHRoZSBnaXZlbiBoZWlnaHQgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtxdWVyeS5pc091dGdvaW5nXSAtIGdldCB0eHMgd2l0aCBhbiBvdXRnb2luZyB0cmFuc2ZlciBvciBub3QgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtxdWVyeS5pc0luY29taW5nXSAtIGdldCB0eHMgd2l0aCBhbiBpbmNvbWluZyB0cmFuc2ZlciBvciBub3QgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge01vbmVyb1RyYW5zZmVyUXVlcnl9IFtxdWVyeS50cmFuc2ZlclF1ZXJ5XSAtIGdldCB0eHMgdGhhdCBoYXZlIGEgdHJhbnNmZXIgdGhhdCBtZWV0cyB0aGlzIHF1ZXJ5IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtib29sZWFufSBbcXVlcnkuaW5jbHVkZU91dHB1dHNdIC0gc3BlY2lmaWVzIHRoYXQgdHggb3V0cHV0cyBzaG91bGQgYmUgcmV0dXJuZWQgd2l0aCB0eCByZXN1bHRzIChvcHRpb25hbClcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9UeFdhbGxldFtdPn0gd2FsbGV0IHRyYW5zYWN0aW9ucyBwZXIgdGhlIGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIGFzeW5jIGdldFR4cyhxdWVyeT86IHN0cmluZ1tdIHwgUGFydGlhbDxNb25lcm9UeFF1ZXJ5Pik6IFByb21pc2U8TW9uZXJvVHhXYWxsZXRbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cblxuICAvKipcbiAgICogPHA+R2V0IGluY29taW5nIGFuZCBvdXRnb2luZyB0cmFuc2ZlcnMgdG8gYW5kIGZyb20gdGhpcyB3YWxsZXQuICBBbiBvdXRnb2luZ1xuICAgKiB0cmFuc2ZlciByZXByZXNlbnRzIGEgdG90YWwgYW1vdW50IHNlbnQgZnJvbSBvbmUgb3IgbW9yZSBzdWJhZGRyZXNzZXNcbiAgICogd2l0aGluIGFuIGFjY291bnQgdG8gaW5kaXZpZHVhbCBkZXN0aW5hdGlvbiBhZGRyZXNzZXMsIGVhY2ggd2l0aCB0aGVpclxuICAgKiBvd24gYW1vdW50LiAgQW4gaW5jb21pbmcgdHJhbnNmZXIgcmVwcmVzZW50cyBhIHRvdGFsIGFtb3VudCByZWNlaXZlZCBpbnRvXG4gICAqIGEgc3ViYWRkcmVzcyB3aXRoaW4gYW4gYWNjb3VudC4gIFRyYW5zZmVycyBiZWxvbmcgdG8gdHJhbnNhY3Rpb25zIHdoaWNoXG4gICAqIGFyZSBzdG9yZWQgb24gdGhlIGJsb2NrY2hhaW4uPC9wPlxuICAgKiBcbiAgICogPHA+UmVzdWx0cyBjYW4gYmUgZmlsdGVyZWQgYnkgcGFzc2luZyBhIHF1ZXJ5IG9iamVjdC4gIFRyYW5zZmVycyBtdXN0XG4gICAqIG1lZXQgZXZlcnkgY3JpdGVyaWEgZGVmaW5lZCBpbiB0aGUgcXVlcnkgaW4gb3JkZXIgdG8gYmUgcmV0dXJuZWQuICBBbGxcbiAgICogY3JpdGVyaWEgYXJlIG9wdGlvbmFsIGFuZCBubyBmaWx0ZXJpbmcgaXMgYXBwbGllZCB3aGVuIG5vdCBkZWZpbmVkLjwvcD5cbiAgICogXG4gICAqIEBwYXJhbSB7TW9uZXJvVHJhbnNmZXJRdWVyeX0gW3F1ZXJ5XSAtIGNvbmZpZ3VyZXMgdGhlIHF1ZXJ5IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtib29sZWFufSBbcXVlcnkuaXNPdXRnb2luZ10gLSBnZXQgdHJhbnNmZXJzIHRoYXQgYXJlIG91dGdvaW5nIG9yIG5vdCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3F1ZXJ5LmlzSW5jb21pbmddIC0gZ2V0IHRyYW5zZmVycyB0aGF0IGFyZSBpbmNvbWluZyBvciBub3QgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW3F1ZXJ5LmFkZHJlc3NdIC0gd2FsbGV0J3MgYWRkcmVzcyB0aGF0IGEgdHJhbnNmZXIgZWl0aGVyIG9yaWdpbmF0ZWQgZnJvbSAoaWYgb3V0Z29pbmcpIG9yIGlzIGRlc3RpbmVkIGZvciAoaWYgaW5jb21pbmcpIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtxdWVyeS5hY2NvdW50SW5kZXhdIC0gZ2V0IHRyYW5zZmVycyB0aGF0IGVpdGhlciBvcmlnaW5hdGVkIGZyb20gKGlmIG91dGdvaW5nKSBvciBhcmUgZGVzdGluZWQgZm9yIChpZiBpbmNvbWluZykgYSBzcGVjaWZpYyBhY2NvdW50IGluZGV4IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtxdWVyeS5zdWJhZGRyZXNzSW5kZXhdIC0gZ2V0IHRyYW5zZmVycyB0aGF0IGVpdGhlciBvcmlnaW5hdGVkIGZyb20gKGlmIG91dGdvaW5nKSBvciBhcmUgZGVzdGluZWQgZm9yIChpZiBpbmNvbWluZykgYSBzcGVjaWZpYyBzdWJhZGRyZXNzIGluZGV4IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtpbnRbXX0gW3F1ZXJ5LnN1YmFkZHJlc3NJbmRpY2VzXSAtIGdldCB0cmFuc2ZlcnMgdGhhdCBlaXRoZXIgb3JpZ2luYXRlZCBmcm9tIChpZiBvdXRnb2luZykgb3IgYXJlIGRlc3RpbmVkIGZvciAoaWYgaW5jb21pbmcpIHNwZWNpZmljIHN1YmFkZHJlc3MgaW5kaWNlcyAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7YmlnaW50fSBbcXVlcnkuYW1vdW50XSAtIGFtb3VudCBiZWluZyB0cmFuc2ZlcnJlZCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7TW9uZXJvRGVzdGluYXRpb25bXSB8IE1vbmVyb0Rlc3RpbmF0aW9uTW9kZWxbXX0gW3F1ZXJ5LmRlc3RpbmF0aW9uc10gLSBpbmRpdmlkdWFsIGRlc3RpbmF0aW9ucyBvZiBhbiBvdXRnb2luZyB0cmFuc2Zlciwgd2hpY2ggaXMgbG9jYWwgd2FsbGV0IGRhdGEgYW5kIE5PVCByZWNvdmVyYWJsZSBmcm9tIHRoZSBibG9ja2NoYWluIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtib29sZWFufSBbcXVlcnkuaGFzRGVzdGluYXRpb25zXSAtIGdldCB0cmFuc2ZlcnMgdGhhdCBoYXZlIGRlc3RpbmF0aW9ucyBvciBub3QgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge01vbmVyb1R4UXVlcnl9IFtxdWVyeS50eFF1ZXJ5XSAtIGdldCB0cmFuc2ZlcnMgd2hvc2UgdHJhbnNhY3Rpb24gbWVldHMgdGhpcyBxdWVyeSAob3B0aW9uYWwpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvVHJhbnNmZXJbXT59IHdhbGxldCB0cmFuc2ZlcnMgdGhhdCBtZWV0IHRoZSBxdWVyeVxuICAgKi9cbiAgYXN5bmMgZ2V0VHJhbnNmZXJzKHF1ZXJ5PzogUGFydGlhbDxNb25lcm9UcmFuc2ZlclF1ZXJ5Pik6IFByb21pc2U8TW9uZXJvVHJhbnNmZXJbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgaW5jb21pbmcgdHJhbnNmZXJzLlxuICAgKiBcbiAgICogQHBhcmFtIHtQYXJ0aWFsPE1vbmVyb1RyYW5zZmVyUXVlcnk+fSBbcXVlcnldIC0gY29uZmlndXJlcyB0aGUgcXVlcnkgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW3F1ZXJ5LmFkZHJlc3NdIC0gZ2V0IGluY29taW5nIHRyYW5zZmVycyB0byBhIHNwZWNpZmljIGFkZHJlc3MgaW4gdGhlIHdhbGxldCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbcXVlcnkuYWNjb3VudEluZGV4XSAtIGdldCBpbmNvbWluZyB0cmFuc2ZlcnMgdG8gYSBzcGVjaWZpYyBhY2NvdW50IGluZGV4IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtxdWVyeS5zdWJhZGRyZXNzSW5kZXhdIC0gZ2V0IGluY29taW5nIHRyYW5zZmVycyB0byBhIHNwZWNpZmljIHN1YmFkZHJlc3MgaW5kZXggKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2ludFtdfSBbcXVlcnkuc3ViYWRkcmVzc0luZGljZXNdIC0gZ2V0IHRyYW5zZmVycyBkZXN0aW5lZCBmb3Igc3BlY2lmaWMgc3ViYWRkcmVzcyBpbmRpY2VzIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtiaWdpbnR9IFtxdWVyeS5hbW91bnRdIC0gYW1vdW50IGJlaW5nIHRyYW5zZmVycmVkIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtNb25lcm9UeFF1ZXJ5fSBbcXVlcnkudHhRdWVyeV0gLSBnZXQgdHJhbnNmZXJzIHdob3NlIHRyYW5zYWN0aW9uIG1lZXRzIHRoaXMgcXVlcnkgKG9wdGlvbmFsKVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb0luY29taW5nVHJhbnNmZXJbXT59IGluY29taW5nIHRyYW5zZmVycyB0aGF0IG1lZXQgdGhlIHF1ZXJ5XG4gICAqL1xuICBhc3luYyBnZXRJbmNvbWluZ1RyYW5zZmVycyhxdWVyeT86IFBhcnRpYWw8TW9uZXJvVHJhbnNmZXJRdWVyeT4pOiBQcm9taXNlPE1vbmVyb0luY29taW5nVHJhbnNmZXJbXT4ge1xuICAgIGNvbnN0IHF1ZXJ5Tm9ybWFsaXplZDogTW9uZXJvVHJhbnNmZXJRdWVyeSA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVUcmFuc2ZlclF1ZXJ5KHF1ZXJ5KTtcbiAgICBpZiAocXVlcnlOb3JtYWxpemVkLmdldElzSW5jb21pbmcoKSA9PT0gZmFsc2UpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlRyYW5zZmVyIHF1ZXJ5IGNvbnRyYWRpY3RzIGdldHRpbmcgaW5jb21pbmcgdHJhbnNmZXJzXCIpO1xuICAgIHF1ZXJ5Tm9ybWFsaXplZC5zZXRJc0luY29taW5nKHRydWUpO1xuICAgIHJldHVybiB0aGlzLmdldFRyYW5zZmVycyhxdWVyeU5vcm1hbGl6ZWQpIGFzIHVua25vd24gYXMgTW9uZXJvSW5jb21pbmdUcmFuc2ZlcltdO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IG91dGdvaW5nIHRyYW5zZmVycy5cbiAgICogXG4gICAqIEBwYXJhbSB7UGFydGlhbDxNb25lcm9UcmFuc2ZlclF1ZXJ5Pn0gW3F1ZXJ5XSAtIGNvbmZpZ3VyZXMgdGhlIHF1ZXJ5IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtxdWVyeS5hZGRyZXNzXSAtIGdldCBvdXRnb2luZyB0cmFuc2ZlcnMgZnJvbSBhIHNwZWNpZmljIGFkZHJlc3MgaW4gdGhlIHdhbGxldCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbcXVlcnkuYWNjb3VudEluZGV4XSAtIGdldCBvdXRnb2luZyB0cmFuc2ZlcnMgZnJvbSBhIHNwZWNpZmljIGFjY291bnQgaW5kZXggKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW3F1ZXJ5LnN1YmFkZHJlc3NJbmRleF0gLSBnZXQgb3V0Z29pbmcgdHJhbnNmZXJzIGZyb20gYSBzcGVjaWZpYyBzdWJhZGRyZXNzIGluZGV4IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtpbnRbXX0gW3F1ZXJ5LnN1YmFkZHJlc3NJbmRpY2VzXSAtIGdldCBvdXRnb2luZyB0cmFuc2ZlcnMgZnJvbSBzcGVjaWZpYyBzdWJhZGRyZXNzIGluZGljZXMgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2JpZ2ludH0gW3F1ZXJ5LmFtb3VudF0gLSBhbW91bnQgYmVpbmcgdHJhbnNmZXJyZWQgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge01vbmVyb0Rlc3RpbmF0aW9uW10gfCBNb25lcm9EZXN0aW5hdGlvbk1vZGVsW119IFtxdWVyeS5kZXN0aW5hdGlvbnNdIC0gaW5kaXZpZHVhbCBkZXN0aW5hdGlvbnMgb2YgYW4gb3V0Z29pbmcgdHJhbnNmZXIsIHdoaWNoIGlzIGxvY2FsIHdhbGxldCBkYXRhIGFuZCBOT1QgcmVjb3ZlcmFibGUgZnJvbSB0aGUgYmxvY2tjaGFpbiAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3F1ZXJ5Lmhhc0Rlc3RpbmF0aW9uc10gLSBnZXQgdHJhbnNmZXJzIHRoYXQgaGF2ZSBkZXN0aW5hdGlvbnMgb3Igbm90IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtNb25lcm9UeFF1ZXJ5fSBbcXVlcnkudHhRdWVyeV0gLSBnZXQgdHJhbnNmZXJzIHdob3NlIHRyYW5zYWN0aW9uIG1lZXRzIHRoaXMgcXVlcnkgKG9wdGlvbmFsKVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb091dGdvaW5nVHJhbnNmZXJbXT59IG91dGdvaW5nIHRyYW5zZmVycyB0aGF0IG1lZXQgdGhlIHF1ZXJ5XG4gICAqL1xuICBhc3luYyBnZXRPdXRnb2luZ1RyYW5zZmVycyhxdWVyeT86IFBhcnRpYWw8TW9uZXJvVHJhbnNmZXJRdWVyeT4pOiBQcm9taXNlPE1vbmVyb091dGdvaW5nVHJhbnNmZXJbXT4ge1xuICAgIGNvbnN0IHF1ZXJ5Tm9ybWFsaXplZDogTW9uZXJvVHJhbnNmZXJRdWVyeSA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVUcmFuc2ZlclF1ZXJ5KHF1ZXJ5KTtcbiAgICBpZiAocXVlcnlOb3JtYWxpemVkLmdldElzT3V0Z29pbmcoKSA9PT0gZmFsc2UpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlRyYW5zZmVyIHF1ZXJ5IGNvbnRyYWRpY3RzIGdldHRpbmcgb3V0Z29pbmcgdHJhbnNmZXJzXCIpO1xuICAgIHF1ZXJ5Tm9ybWFsaXplZC5zZXRJc091dGdvaW5nKHRydWUpO1xuICAgIHJldHVybiB0aGlzLmdldFRyYW5zZmVycyhxdWVyeU5vcm1hbGl6ZWQpIGFzIHVua25vd24gYXMgTW9uZXJvT3V0Z29pbmdUcmFuc2ZlcltdO1xuICB9XG4gIFxuICAvKipcbiAgICogPHA+R2V0IG91dHB1dHMgY3JlYXRlZCBmcm9tIHByZXZpb3VzIHRyYW5zYWN0aW9ucyB0aGF0IGJlbG9uZyB0byB0aGUgd2FsbGV0XG4gICAqIChpLmUuIHRoYXQgdGhlIHdhbGxldCBjYW4gc3BlbmQgb25lIHRpbWUpLiAgT3V0cHV0cyBhcmUgcGFydCBvZlxuICAgKiB0cmFuc2FjdGlvbnMgd2hpY2ggYXJlIHN0b3JlZCBpbiBibG9ja3Mgb24gdGhlIGJsb2NrY2hhaW4uPC9wPlxuICAgKiBcbiAgICogPHA+UmVzdWx0cyBjYW4gYmUgZmlsdGVyZWQgYnkgcGFzc2luZyBhIHF1ZXJ5IG9iamVjdC4gIE91dHB1dHMgbXVzdFxuICAgKiBtZWV0IGV2ZXJ5IGNyaXRlcmlhIGRlZmluZWQgaW4gdGhlIHF1ZXJ5IGluIG9yZGVyIHRvIGJlIHJldHVybmVkLiAgQWxsXG4gICAqIGZpbHRlcmluZyBpcyBvcHRpb25hbCBhbmQgbm8gZmlsdGVyaW5nIGlzIGFwcGxpZWQgd2hlbiBub3QgZGVmaW5lZC48L3A+XG4gICAqIFxuICAgKiBAcGFyYW0ge1Bhcml0YWw8TW9uZXJvT3V0cHV0UXVlcnk+fSBbcXVlcnldIC0gY29uZmlndXJlcyB0aGUgcXVlcnkgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW3F1ZXJ5LmFjY291bnRJbmRleF0gLSBnZXQgb3V0cHV0cyBhc3NvY2lhdGVkIHdpdGggYSBzcGVjaWZpYyBhY2NvdW50IGluZGV4IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtxdWVyeS5zdWJhZGRyZXNzSW5kZXhdIC0gZ2V0IG91dHB1dHMgYXNzb2NpYXRlZCB3aXRoIGEgc3BlY2lmaWMgc3ViYWRkcmVzcyBpbmRleCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7aW50W119IFtxdWVyeS5zdWJhZGRyZXNzSW5kaWNlc10gLSBnZXQgb3V0cHV0cyBhc3NvY2lhdGVkIHdpdGggc3BlY2lmaWMgc3ViYWRkcmVzcyBpbmRpY2VzIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtiaWdpbnR9IFtxdWVyeS5hbW91bnRdIC0gZ2V0IG91dHB1dHMgd2l0aCBhIHNwZWNpZmljIGFtb3VudCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7YmlnaW50fSBbcXVlcnkubWluQW1vdW50XSAtIGdldCBvdXRwdXRzIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byBhIG1pbmltdW0gYW1vdW50IChvcHRpb25hbClcbiAgICogQHBhcmFtIHtiaWdpbnR9IFtxdWVyeS5tYXhBbW91bnRdIC0gZ2V0IG91dHB1dHMgbGVzcyB0aGFuIG9yIGVxdWFsIHRvIGEgbWF4aW11bSBhbW91bnQgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtxdWVyeS5pc1NwZW50XSAtIGdldCBvdXRwdXRzIHRoYXQgYXJlIHNwZW50IG9yIG5vdCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7c3RyaW5nfE1vbmVyb0tleUltYWdlfSBbcXVlcnkua2V5SW1hZ2VdIC0gZ2V0IG91dHB1dCB3aXRoIGEga2V5IGltYWdlIG9yIHdoaWNoIG1hdGNoZXMgZmllbGRzIGRlZmluZWQgaW4gYSBNb25lcm9LZXlJbWFnZSAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7TW9uZXJvVHhRdWVyeX0gW3F1ZXJ5LnR4UXVlcnldIC0gZ2V0IG91dHB1dHMgd2hvc2UgdHJhbnNhY3Rpb24gbWVldHMgdGhpcyBmaWx0ZXIgKG9wdGlvbmFsKVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb091dHB1dFdhbGxldFtdPn0gdGhlIHF1ZXJpZWQgb3V0cHV0c1xuICAgKi9cbiAgYXN5bmMgZ2V0T3V0cHV0cyhxdWVyeT86IFBhcnRpYWw8TW9uZXJvT3V0cHV0UXVlcnk+KTogUHJvbWlzZTxNb25lcm9PdXRwdXRXYWxsZXRbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBFeHBvcnQgb3V0cHV0cyBpbiBoZXggZm9ybWF0LlxuICAgKlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFthbGxdIC0gZXhwb3J0IGFsbCBvdXRwdXRzIGlmIHRydWUsIGVsc2UgZXhwb3J0IHRoZSBvdXRwdXRzIHNpbmNlIHRoZSBsYXN0IGV4cG9ydCAoZGVmYXVsdCBmYWxzZSlcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSBvdXRwdXRzIGluIGhleCBmb3JtYXRcbiAgICovXG4gIGFzeW5jIGV4cG9ydE91dHB1dHMoYWxsID0gZmFsc2UpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbXBvcnQgb3V0cHV0cyBpbiBoZXggZm9ybWF0LlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IG91dHB1dHNIZXggLSBvdXRwdXRzIGluIGhleCBmb3JtYXRcbiAgICogQHJldHVybiB7UHJvbWlzZTxudW1iZXI+fSB0aGUgbnVtYmVyIG9mIG91dHB1dHMgaW1wb3J0ZWRcbiAgICovXG4gIGFzeW5jIGltcG9ydE91dHB1dHMob3V0cHV0c0hleDogc3RyaW5nKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogRXhwb3J0IHNpZ25lZCBrZXkgaW1hZ2VzLlxuICAgKiBcbiAgICogQHBhcmFtIHtib29sZWFufSBbYWxsXSAtIGV4cG9ydCBhbGwga2V5IGltYWdlcyBpZiB0cnVlLCBlbHNlIGV4cG9ydCB0aGUga2V5IGltYWdlcyBzaW5jZSB0aGUgbGFzdCBleHBvcnQgKGRlZmF1bHQgZmFsc2UpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvS2V5SW1hZ2VbXT59IHRoZSB3YWxsZXQncyBzaWduZWQga2V5IGltYWdlc1xuICAgKi9cbiAgYXN5bmMgZXhwb3J0S2V5SW1hZ2VzKGFsbCA9IGZhbHNlKTogUHJvbWlzZTxNb25lcm9LZXlJbWFnZVtdPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEltcG9ydCBzaWduZWQga2V5IGltYWdlcyBhbmQgdmVyaWZ5IHRoZWlyIHNwZW50IHN0YXR1cy5cbiAgICogXG4gICAqIEBwYXJhbSB7TW9uZXJvS2V5SW1hZ2VbXX0ga2V5SW1hZ2VzIC0gaW1hZ2VzIHRvIGltcG9ydCBhbmQgdmVyaWZ5IChyZXF1aXJlcyBoZXggYW5kIHNpZ25hdHVyZSlcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9LZXlJbWFnZUltcG9ydFJlc3VsdD59IHJlc3VsdHMgb2YgdGhlIGltcG9ydFxuICAgKi9cbiAgYXN5bmMgaW1wb3J0S2V5SW1hZ2VzKGtleUltYWdlczogTW9uZXJvS2V5SW1hZ2VbXSk6IFByb21pc2U8TW9uZXJvS2V5SW1hZ2VJbXBvcnRSZXN1bHQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IG5ldyBrZXkgaW1hZ2VzIGZyb20gdGhlIGxhc3QgaW1wb3J0ZWQgb3V0cHV0cy5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvS2V5SW1hZ2VbXT59IHRoZSBrZXkgaW1hZ2VzIGZyb20gdGhlIGxhc3QgaW1wb3J0ZWQgb3V0cHV0c1xuICAgKi9cbiAgYXN5bmMgZ2V0TmV3S2V5SW1hZ2VzRnJvbUxhc3RJbXBvcnQoKTogUHJvbWlzZTxNb25lcm9LZXlJbWFnZVtdPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEZyZWV6ZSBhbiBvdXRwdXQuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5SW1hZ2UgLSBrZXkgaW1hZ2Ugb2YgdGhlIG91dHB1dCB0byBmcmVlemVcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIGZyZWV6ZU91dHB1dChrZXlJbWFnZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFRoYXcgYSBmcm96ZW4gb3V0cHV0LlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleUltYWdlIC0ga2V5IGltYWdlIG9mIHRoZSBvdXRwdXQgdG8gdGhhd1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgdGhhd091dHB1dChrZXlJbWFnZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIENoZWNrIGlmIGFuIG91dHB1dCBpcyBmcm96ZW4uXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5SW1hZ2UgLSBrZXkgaW1hZ2Ugb2YgdGhlIG91dHB1dCB0byBjaGVjayBpZiBmcm96ZW5cbiAgICogQHJldHVybiB7UHJvbWlzZTxib29sZWFuPn0gdHJ1ZSBpZiB0aGUgb3V0cHV0IGlzIGZyb3plbiwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBhc3luYyBpc091dHB1dEZyb3plbihrZXlJbWFnZTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGN1cnJlbnQgZGVmYXVsdCBmZWUgcHJpb3JpdHkgKHVuaW1wb3J0YW50LCBub3JtYWwsIGVsZXZhdGVkLCBldGMpLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9UeFByaW9yaXR5Pn0gdGhlIGN1cnJlbnQgZmVlIHByaW9yaXR5XG4gICAqL1xuICBhc3luYyBnZXREZWZhdWx0RmVlUHJpb3JpdHkoKTogUHJvbWlzZTxNb25lcm9UeFByaW9yaXR5PiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIENyZWF0ZSBhIHRyYW5zYWN0aW9uIHRvIHRyYW5zZmVyIGZ1bmRzIGZyb20gdGhpcyB3YWxsZXQuXG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb1R4Q29uZmlnfSBjb25maWcgLSBjb25maWd1cmVzIHRoZSB0cmFuc2FjdGlvbiB0byBjcmVhdGUgKHJlcXVpcmVkKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gY29uZmlnLmFkZHJlc3MgLSBzaW5nbGUgZGVzdGluYXRpb24gYWRkcmVzcyAocmVxdWlyZWQgdW5sZXNzIGBkZXN0aW5hdGlvbnNgIHByb3ZpZGVkKVxuICAgKiBAcGFyYW0ge2JpZ2ludHxzdHJpbmd9IGNvbmZpZy5hbW91bnQgLSBzaW5nbGUgZGVzdGluYXRpb24gYW1vdW50IChyZXF1aXJlZCB1bmxlc3MgYGRlc3RpbmF0aW9uc2AgcHJvdmlkZWQpXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBjb25maWcuYWNjb3VudEluZGV4IC0gc291cmNlIGFjY291bnQgaW5kZXggdG8gdHJhbnNmZXIgZnVuZHMgZnJvbSAocmVxdWlyZWQpXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbY29uZmlnLnN1YmFkZHJlc3NJbmRleF0gLSBzb3VyY2Ugc3ViYWRkcmVzcyBpbmRleCB0byB0cmFuc2ZlciBmdW5kcyBmcm9tIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtudW1iZXJbXX0gW2NvbmZpZy5zdWJhZGRyZXNzSW5kaWNlc10gLSBzb3VyY2Ugc3ViYWRkcmVzcyBpbmRpY2VzIHRvIHRyYW5zZmVyIGZ1bmRzIGZyb20gKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtjb25maWcucmVsYXldIC0gcmVsYXkgdGhlIHRyYW5zYWN0aW9uIHRvIHBlZXJzIHRvIGNvbW1pdCB0byB0aGUgYmxvY2tjaGFpbiAoZGVmYXVsdCBmYWxzZSlcbiAgICogQHBhcmFtIHtNb25lcm9UeFByaW9yaXR5fSBbY29uZmlnLnByaW9yaXR5XSAtIHRyYW5zYWN0aW9uIHByaW9yaXR5IChkZWZhdWx0IE1vbmVyb1R4UHJpb3JpdHkuTk9STUFMKVxuICAgKiBAcGFyYW0ge01vbmVyb0Rlc3RpbmF0aW9uW119IGNvbmZpZy5kZXN0aW5hdGlvbnMgLSBhZGRyZXNzZXMgYW5kIGFtb3VudHMgaW4gYSBtdWx0aS1kZXN0aW5hdGlvbiB0eCAocmVxdWlyZWQgdW5sZXNzIGBhZGRyZXNzYCBhbmQgYGFtb3VudGAgcHJvdmlkZWQpXG4gICAqIEBwYXJhbSB7bnVtYmVyW119IFtjb25maWcuc3VidHJhY3RGZWVGcm9tXSAtIGxpc3Qgb2YgZGVzdGluYXRpb24gaW5kaWNlcyB0byBzcGxpdCB0aGUgdHJhbnNhY3Rpb24gZmVlIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtjb25maWcucGF5bWVudElkXSAtIHRyYW5zYWN0aW9uIHBheW1lbnQgSUQgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2JpZ2ludHxzdHJpbmd9IFtjb25maWcudW5sb2NrVGltZV0gLSBtaW5pbXVtIGhlaWdodCBvciB0aW1lc3RhbXAgZm9yIHRoZSB0cmFuc2FjdGlvbiB0byB1bmxvY2sgKGRlZmF1bHQgMClcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9UeFdhbGxldD59IHRoZSBjcmVhdGVkIHRyYW5zYWN0aW9uXG4gICAqL1xuICBhc3luYyBjcmVhdGVUeChjb25maWc6IFBhcnRpYWw8TW9uZXJvVHhDb25maWc+KTogUHJvbWlzZTxNb25lcm9UeFdhbGxldD4ge1xuICAgIGNvbnN0IGNvbmZpZ05vcm1hbGl6ZWQ6IE1vbmVyb1R4Q29uZmlnID0gTW9uZXJvV2FsbGV0Lm5vcm1hbGl6ZUNyZWF0ZVR4c0NvbmZpZyhjb25maWcpO1xuICAgIGlmIChjb25maWdOb3JtYWxpemVkLmdldENhblNwbGl0KCkgIT09IHVuZGVmaW5lZCkgYXNzZXJ0LmVxdWFsKGNvbmZpZ05vcm1hbGl6ZWQuZ2V0Q2FuU3BsaXQoKSwgZmFsc2UsIFwiQ2Fubm90IHNwbGl0IHRyYW5zYWN0aW9ucyB1c2luZyBjcmVhdGVUeCgpOyB1c2UgY3JlYXRlVHhzKClcIik7XG4gICAgY29uZmlnTm9ybWFsaXplZC5zZXRDYW5TcGxpdChmYWxzZSk7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLmNyZWF0ZVR4cyhjb25maWdOb3JtYWxpemVkKSlbMF07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDcmVhdGUgb25lIG9yIG1vcmUgdHJhbnNhY3Rpb25zIHRvIHRyYW5zZmVyIGZ1bmRzIGZyb20gdGhpcyB3YWxsZXQuXG4gICAqIFxuICAgKiBAcGFyYW0ge1BhcnRpYWw8TW9uZXJvVHhDb25maWc+fSBjb25maWcgLSBjb25maWd1cmVzIHRoZSB0cmFuc2FjdGlvbnMgdG8gY3JlYXRlIChyZXF1aXJlZClcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZy5hZGRyZXNzIC0gc2luZ2xlIGRlc3RpbmF0aW9uIGFkZHJlc3MgKHJlcXVpcmVkIHVubGVzcyBgZGVzdGluYXRpb25zYCBwcm92aWRlZClcbiAgICogQHBhcmFtIHtiaWdpbnR8c3RyaW5nfSBjb25maWcuYW1vdW50IC0gc2luZ2xlIGRlc3RpbmF0aW9uIGFtb3VudCAocmVxdWlyZWQgdW5sZXNzIGBkZXN0aW5hdGlvbnNgIHByb3ZpZGVkKVxuICAgKiBAcGFyYW0ge251bWJlcn0gY29uZmlnLmFjY291bnRJbmRleCAtIHNvdXJjZSBhY2NvdW50IGluZGV4IHRvIHRyYW5zZmVyIGZ1bmRzIGZyb20gKHJlcXVpcmVkKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbmZpZy5zdWJhZGRyZXNzSW5kZXhdIC0gc291cmNlIHN1YmFkZHJlc3MgaW5kZXggdG8gdHJhbnNmZXIgZnVuZHMgZnJvbSAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7aW50W119IFtjb25maWcuc3ViYWRkcmVzc0luZGljZXNdIC0gc291cmNlIHN1YmFkZHJlc3MgaW5kaWNlcyB0byB0cmFuc2ZlciBmdW5kcyBmcm9tIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtib29sZWFufSBbY29uZmlnLnJlbGF5XSAtIHJlbGF5IHRoZSB0cmFuc2FjdGlvbnMgdG8gcGVlcnMgdG8gY29tbWl0IHRvIHRoZSBibG9ja2NoYWluIChkZWZhdWx0IGZhbHNlKVxuICAgKiBAcGFyYW0ge01vbmVyb1R4UHJpb3JpdHl9IFtjb25maWcucHJpb3JpdHldIC0gdHJhbnNhY3Rpb24gcHJpb3JpdHkgKGRlZmF1bHQgTW9uZXJvVHhQcmlvcml0eS5OT1JNQUwpXG4gICAqIEBwYXJhbSB7TW9uZXJvRGVzdGluYXRpb25bXSB8IE1vbmVyb0Rlc3RpbmF0aW9uTW9kZWxbXX0gY29uZmlnLmRlc3RpbmF0aW9ucyAtIGFkZHJlc3NlcyBhbmQgYW1vdW50cyBpbiBhIG11bHRpLWRlc3RpbmF0aW9uIHR4IChyZXF1aXJlZCB1bmxlc3MgYGFkZHJlc3NgIGFuZCBgYW1vdW50YCBwcm92aWRlZClcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtjb25maWcucGF5bWVudElkXSAtIHRyYW5zYWN0aW9uIHBheW1lbnQgSUQgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2JpZ2ludHxzdHJpbmd9IFtjb25maWcudW5sb2NrVGltZV0gLSBtaW5pbXVtIGhlaWdodCBvciB0aW1lc3RhbXAgZm9yIHRoZSB0cmFuc2FjdGlvbnMgdG8gdW5sb2NrIChkZWZhdWx0IDApXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2NvbmZpZy5jYW5TcGxpdF0gLSBhbGxvdyBmdW5kcyB0byBiZSB0cmFuc2ZlcnJlZCB1c2luZyBtdWx0aXBsZSB0cmFuc2FjdGlvbnMgKGRlZmF1bHQgdHJ1ZSlcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9UeFdhbGxldFtdPn0gdGhlIGNyZWF0ZWQgdHJhbnNhY3Rpb25zXG4gICAqL1xuICBhc3luYyBjcmVhdGVUeHMoY29uZmlnOiBQYXJ0aWFsPE1vbmVyb1R4Q29uZmlnPik6IFByb21pc2U8TW9uZXJvVHhXYWxsZXRbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTd2VlcCBhbiBvdXRwdXQgYnkga2V5IGltYWdlLlxuICAgKiBcbiAgICogQHBhcmFtIHtQYXJ0aWFsPE1vbmVyb1R4Q29uZmlnPn0gY29uZmlnIC0gY29uZmlndXJlcyB0aGUgdHJhbnNhY3Rpb24gdG8gY3JlYXRlIChyZXF1aXJlZClcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZy5hZGRyZXNzIC0gc2luZ2xlIGRlc3RpbmF0aW9uIGFkZHJlc3MgKHJlcXVpcmVkKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gY29uZmlnLmtleUltYWdlIC0ga2V5IGltYWdlIHRvIHN3ZWVwIChyZXF1aXJlZClcbiAgICogQHBhcmFtIHtib29sZWFufSBbY29uZmlnLnJlbGF5XSAtIHJlbGF5IHRoZSB0cmFuc2FjdGlvbiB0byBwZWVycyB0byBjb21taXQgdG8gdGhlIGJsb2NrY2hhaW4gKGRlZmF1bHQgZmFsc2UpXG4gICAqIEBwYXJhbSB7YmlnaW50fHN0cmluZ30gW2NvbmZpZy51bmxvY2tUaW1lXSAtIG1pbmltdW0gaGVpZ2h0IG9yIHRpbWVzdGFtcCBmb3IgdGhlIHRyYW5zYWN0aW9uIHRvIHVubG9jayAoZGVmYXVsdCAwKVxuICAgKiBAcGFyYW0ge01vbmVyb1R4UHJpb3JpdHl9IFtjb25maWcucHJpb3JpdHldIC0gdHJhbnNhY3Rpb24gcHJpb3JpdHkgKGRlZmF1bHQgTW9uZXJvVHhQcmlvcml0eS5OT1JNQUwpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvVHhXYWxsZXQ+fSB0aGUgY3JlYXRlZCB0cmFuc2FjdGlvblxuICAgKi9cbiAgYXN5bmMgc3dlZXBPdXRwdXQoY29uZmlnOiBQYXJ0aWFsPE1vbmVyb1R4Q29uZmlnPik6IFByb21pc2U8TW9uZXJvVHhXYWxsZXQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN3ZWVwIGFsbCB1bmxvY2tlZCBmdW5kcyBhY2NvcmRpbmcgdG8gdGhlIGdpdmVuIGNvbmZpZ3VyYXRpb24uXG4gICAqIFxuICAgKiBAcGFyYW0ge1BhcnRpYWw8TW9uZXJvVHhDb25maWc+fSBjb25maWcgLSBjb25maWd1cmVzIHRoZSB0cmFuc2FjdGlvbnMgdG8gY3JlYXRlIChyZXF1aXJlZClcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZy5hZGRyZXNzIC0gc2luZ2xlIGRlc3RpbmF0aW9uIGFkZHJlc3MgKHJlcXVpcmVkKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbmZpZy5hY2NvdW50SW5kZXhdIC0gc291cmNlIGFjY291bnQgaW5kZXggdG8gc3dlZXAgZnJvbSAob3B0aW9uYWwsIGRlZmF1bHRzIHRvIGFsbCBhY2NvdW50cylcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtjb25maWcuc3ViYWRkcmVzc0luZGV4XSAtIHNvdXJjZSBzdWJhZGRyZXNzIGluZGV4IHRvIHN3ZWVwIGZyb20gKG9wdGlvbmFsLCBkZWZhdWx0cyB0byBhbGwgc3ViYWRkcmVzc2VzKVxuICAgKiBAcGFyYW0ge251bWJlcltdfSBbY29uZmlnLnN1YmFkZHJlc3NJbmRpY2VzXSAtIHNvdXJjZSBzdWJhZGRyZXNzIGluZGljZXMgdG8gc3dlZXAgZnJvbSAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2NvbmZpZy5yZWxheV0gLSByZWxheSB0aGUgdHJhbnNhY3Rpb25zIHRvIHBlZXJzIHRvIGNvbW1pdCB0byB0aGUgYmxvY2tjaGFpbiAoZGVmYXVsdCBmYWxzZSlcbiAgICogQHBhcmFtIHtNb25lcm9UeFByaW9yaXR5fSBbY29uZmlnLnByaW9yaXR5XSAtIHRyYW5zYWN0aW9uIHByaW9yaXR5IChkZWZhdWx0IE1vbmVyb1R4UHJpb3JpdHkuTk9STUFMKVxuICAgKiBAcGFyYW0ge2JpZ2ludHxzdHJpbmd9IFtjb25maWcudW5sb2NrVGltZV0gLSBtaW5pbXVtIGhlaWdodCBvciB0aW1lc3RhbXAgZm9yIHRoZSB0cmFuc2FjdGlvbnMgdG8gdW5sb2NrIChkZWZhdWx0IDApXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2NvbmZpZy5zd2VlcEVhY2hTdWJhZGRyZXNzXSAtIHN3ZWVwIGVhY2ggc3ViYWRkcmVzcyBpbmRpdmlkdWFsbHkgaWYgdHJ1ZSAoZGVmYXVsdCBmYWxzZSlcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9UeFdhbGxldFtdPn0gdGhlIGNyZWF0ZWQgdHJhbnNhY3Rpb25zXG4gICAqL1xuICBhc3luYyBzd2VlcFVubG9ja2VkKGNvbmZpZzogUGFydGlhbDxNb25lcm9UeENvbmZpZz4pOiBQcm9taXNlPE1vbmVyb1R4V2FsbGV0W10+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogPHA+U3dlZXAgYWxsIHVubWl4YWJsZSBkdXN0IG91dHB1dHMgYmFjayB0byB0aGUgd2FsbGV0IHRvIG1ha2UgdGhlbSBlYXNpZXIgdG8gc3BlbmQgYW5kIG1peC48L3A+XG4gICAqIFxuICAgKiA8cD5OT1RFOiBEdXN0IG9ubHkgZXhpc3RzIHByZSBSQ1QsIHNvIHRoaXMgbWV0aG9kIHdpbGwgdGhyb3cgXCJubyBkdXN0IHRvIHN3ZWVwXCIgb24gbmV3IHdhbGxldHMuPC9wPlxuICAgKiBcbiAgICogQHBhcmFtIHtib29sZWFufSBbcmVsYXldIC0gc3BlY2lmaWVzIGlmIHRoZSByZXN1bHRpbmcgdHJhbnNhY3Rpb24gc2hvdWxkIGJlIHJlbGF5ZWQgKGRlZmF1bHQgZmFsc2UpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvVHhXYWxsZXRbXT59IHRoZSBjcmVhdGVkIHRyYW5zYWN0aW9uc1xuICAgKi9cbiAgYXN5bmMgc3dlZXBEdXN0KHJlbGF5PzogYm9vbGVhbik6IFByb21pc2U8TW9uZXJvVHhXYWxsZXRbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZWxheSBhIHByZXZpb3VzbHkgY3JlYXRlZCB0cmFuc2FjdGlvbi5cbiAgICogXG4gICAqIEBwYXJhbSB7KE1vbmVyb1R4V2FsbGV0IHwgc3RyaW5nKX0gdHhPck1ldGFkYXRhIC0gdHJhbnNhY3Rpb24gb3IgaXRzIG1ldGFkYXRhIHRvIHJlbGF5XG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nPn0gdGhlIGhhc2ggb2YgdGhlIHJlbGF5ZWQgdHhcbiAgICovXG4gIGFzeW5jIHJlbGF5VHgodHhPck1ldGFkYXRhOiBNb25lcm9UeFdhbGxldCB8IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLnJlbGF5VHhzKFt0eE9yTWV0YWRhdGFdKSlbMF07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZWxheSBwcmV2aW91c2x5IGNyZWF0ZWQgdHJhbnNhY3Rpb25zLlxuICAgKiBcbiAgICogQHBhcmFtIHsoTW9uZXJvVHhXYWxsZXRbXSB8IHN0cmluZ1tdKX0gdHhzT3JNZXRhZGF0YXMgLSB0cmFuc2FjdGlvbnMgb3IgdGhlaXIgbWV0YWRhdGEgdG8gcmVsYXlcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmdbXT59IHRoZSBoYXNoZXMgb2YgdGhlIHJlbGF5ZWQgdHhzXG4gICAqL1xuICBhc3luYyByZWxheVR4cyh0eHNPck1ldGFkYXRhczogKE1vbmVyb1R4V2FsbGV0IHwgc3RyaW5nKVtdKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBEZXNjcmliZSBhIHR4IHNldCBmcm9tIHVuc2lnbmVkIHR4IGhleC5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB1bnNpZ25lZFR4SGV4IC0gdW5zaWduZWQgdHggaGV4XG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvVHhTZXQ+fSB0aGUgdHggc2V0IGNvbnRhaW5pbmcgc3RydWN0dXJlZCB0cmFuc2FjdGlvbnNcbiAgICovXG4gIGFzeW5jIGRlc2NyaWJlVW5zaWduZWRUeFNldCh1bnNpZ25lZFR4SGV4OiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb1R4U2V0PiB7XG4gICAgcmV0dXJuIHRoaXMuZGVzY3JpYmVUeFNldChuZXcgTW9uZXJvVHhTZXQoKS5zZXRVbnNpZ25lZFR4SGV4KHVuc2lnbmVkVHhIZXgpKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIERlc2NyaWJlIGEgdHggc2V0IGZyb20gbXVsdGlzaWcgdHggaGV4LlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IG11bHRpc2lnVHhIZXggLSBtdWx0aXNpZyB0eCBoZXhcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9UeFNldD59IHRoZSB0eCBzZXQgY29udGFpbmluZyBzdHJ1Y3R1cmVkIHRyYW5zYWN0aW9uc1xuICAgKi9cbiAgYXN5bmMgZGVzY3JpYmVNdWx0aXNpZ1R4U2V0KG11bHRpc2lnVHhIZXg6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvVHhTZXQ+IHtcbiAgICByZXR1cm4gdGhpcy5kZXNjcmliZVR4U2V0KG5ldyBNb25lcm9UeFNldCgpLnNldE11bHRpc2lnVHhIZXgobXVsdGlzaWdUeEhleCkpO1xuICB9XG4gIFxuICAvKipcbiAgICogRGVzY3JpYmUgYSB0eCBzZXQgY29udGFpbmluZyB1bnNpZ25lZCBvciBtdWx0aXNpZyB0eCBoZXggdG8gYSBuZXcgdHggc2V0IGNvbnRhaW5pbmcgc3RydWN0dXJlZCB0cmFuc2FjdGlvbnMuXG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb1R4U2V0fSB0eFNldCAtIGEgdHggc2V0IGNvbnRhaW5pbmcgdW5zaWduZWQgb3IgbXVsdGlzaWcgdHggaGV4XG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvVHhTZXQ+fSB0eFNldCAtIHRoZSB0eCBzZXQgY29udGFpbmluZyBzdHJ1Y3R1cmVkIHRyYW5zYWN0aW9uc1xuICAgKi9cbiAgYXN5bmMgZGVzY3JpYmVUeFNldCh0eFNldDogTW9uZXJvVHhTZXQpOiBQcm9taXNlPE1vbmVyb1R4U2V0PiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFNpZ24gdW5zaWduZWQgdHJhbnNhY3Rpb25zIGZyb20gYSB2aWV3LW9ubHkgd2FsbGV0LlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVuc2lnbmVkVHhIZXggLSB1bnNpZ25lZCB0cmFuc2FjdGlvbiBoZXggZnJvbSB3aGVuIHRoZSB0cmFuc2FjdGlvbnMgd2VyZSBjcmVhdGVkXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvVHhTZXQ+fSB0aGUgc2lnbmVkIHRyYW5zYWN0aW9uIHNldFxuICAgKi9cbiAgYXN5bmMgc2lnblR4cyh1bnNpZ25lZFR4SGV4OiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb1R4U2V0PiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFN1Ym1pdCBzaWduZWQgdHJhbnNhY3Rpb25zIGZyb20gYSB2aWV3LW9ubHkgd2FsbGV0LlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNpZ25lZFR4SGV4IC0gc2lnbmVkIHRyYW5zYWN0aW9uIGhleCBmcm9tIHNpZ25UeHMoKVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZ1tdPn0gdGhlIHJlc3VsdGluZyB0cmFuc2FjdGlvbiBoYXNoZXNcbiAgICovXG4gIGFzeW5jIHN1Ym1pdFR4cyhzaWduZWRUeEhleDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTaWduIGEgbWVzc2FnZS5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gdGhlIG1lc3NhZ2UgdG8gc2lnblxuICAgKiBAcGFyYW0ge01vbmVyb01lc3NhZ2VTaWduYXR1cmVUeXBlfSBbc2lnbmF0dXJlVHlwZV0gLSBzaWduIHdpdGggc3BlbmQga2V5IG9yIHZpZXcga2V5IChkZWZhdWx0IHNwZW5kIGtleSlcbiAgICogQHBhcmFtIHtudW1iZXJ9IFthY2NvdW50SWR4XSAtIHRoZSBhY2NvdW50IGluZGV4IG9mIHRoZSBtZXNzYWdlIHNpZ25hdHVyZSAoZGVmYXVsdCAwKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW3N1YmFkZHJlc3NJZHhdIC0gdGhlIHN1YmFkZHJlc3MgaW5kZXggb2YgdGhlIG1lc3NhZ2Ugc2lnbmF0dXJlIChkZWZhdWx0IDApXG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nPn0gdGhlIHNpZ25hdHVyZVxuICAgKi9cbiAgYXN5bmMgc2lnbk1lc3NhZ2UobWVzc2FnZTogc3RyaW5nLCBzaWduYXR1cmVUeXBlID0gTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGUuU0lHTl9XSVRIX1NQRU5EX0tFWSwgYWNjb3VudElkeCA9IDAsIHN1YmFkZHJlc3NJZHggPSAwKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogVmVyaWZ5IGEgc2lnbmF0dXJlIG9uIGEgbWVzc2FnZS5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gc2lnbmVkIG1lc3NhZ2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFkZHJlc3MgLSBzaWduaW5nIGFkZHJlc3NcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNpZ25hdHVyZSAtIHNpZ25hdHVyZVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb01lc3NhZ2VTaWduYXR1cmVSZXN1bHQ+fSB0cnVlIGlmIHRoZSBzaWduYXR1cmUgaXMgZ29vZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBhc3luYyB2ZXJpZnlNZXNzYWdlKG1lc3NhZ2U6IHN0cmluZywgYWRkcmVzczogc3RyaW5nLCBzaWduYXR1cmU6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvTWVzc2FnZVNpZ25hdHVyZVJlc3VsdD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgYSB0cmFuc2FjdGlvbidzIHNlY3JldCBrZXkgZnJvbSBpdHMgaGFzaC5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0eEhhc2ggLSB0cmFuc2FjdGlvbidzIGhhc2hcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSAtIHRyYW5zYWN0aW9uJ3Mgc2VjcmV0IGtleVxuICAgKi9cbiAgYXN5bmMgZ2V0VHhLZXkodHhIYXNoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDaGVjayBhIHRyYW5zYWN0aW9uIGluIHRoZSBibG9ja2NoYWluIHdpdGggaXRzIHNlY3JldCBrZXkuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHhIYXNoIC0gdHJhbnNhY3Rpb24gdG8gY2hlY2tcbiAgICogQHBhcmFtIHtzdHJpbmd9IHR4S2V5IC0gdHJhbnNhY3Rpb24ncyBzZWNyZXQga2V5XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzIC0gZGVzdGluYXRpb24gcHVibGljIGFkZHJlc3Mgb2YgdGhlIHRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm4ge3JvbWlzZTxNb25lcm9DaGVja1R4Pn0gdGhlIHJlc3VsdCBvZiB0aGUgY2hlY2tcbiAgICovXG4gIGFzeW5jIGNoZWNrVHhLZXkodHhIYXNoOiBzdHJpbmcsIHR4S2V5OiBzdHJpbmcsIGFkZHJlc3M6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvQ2hlY2tUeD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgYSB0cmFuc2FjdGlvbiBzaWduYXR1cmUgdG8gcHJvdmUgaXQuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHhIYXNoIC0gdHJhbnNhY3Rpb24gdG8gcHJvdmVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFkZHJlc3MgLSBkZXN0aW5hdGlvbiBwdWJsaWMgYWRkcmVzcyBvZiB0aGUgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmd9IFttZXNzYWdlXSAtIG1lc3NhZ2UgdG8gaW5jbHVkZSB3aXRoIHRoZSBzaWduYXR1cmUgdG8gZnVydGhlciBhdXRoZW50aWNhdGUgdGhlIHByb29mIChvcHRpb25hbClcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSB0aGUgdHJhbnNhY3Rpb24gc2lnbmF0dXJlXG4gICAqL1xuICBhc3luYyBnZXRUeFByb29mKHR4SGFzaDogc3RyaW5nLCBhZGRyZXNzOiBzdHJpbmcsIG1lc3NhZ2U/OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBQcm92ZSBhIHRyYW5zYWN0aW9uIGJ5IGNoZWNraW5nIGl0cyBzaWduYXR1cmUuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHhIYXNoIC0gdHJhbnNhY3Rpb24gdG8gcHJvdmVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFkZHJlc3MgLSBkZXN0aW5hdGlvbiBwdWJsaWMgYWRkcmVzcyBvZiB0aGUgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmcgfCB1bmRlZmluZWR9IG1lc3NhZ2UgLSBtZXNzYWdlIGluY2x1ZGVkIHdpdGggdGhlIHNpZ25hdHVyZSB0byBmdXJ0aGVyIGF1dGhlbnRpY2F0ZSB0aGUgcHJvb2ZcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNpZ25hdHVyZSAgLSB0cmFuc2FjdGlvbiBzaWduYXR1cmUgdG8gY29uZmlybVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb0NoZWNrVHg+fSB0aGUgcmVzdWx0IG9mIHRoZSBjaGVja1xuICAgKi9cbiAgYXN5bmMgY2hlY2tUeFByb29mKHR4SGFzaDogc3RyaW5nLCBhZGRyZXNzOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZyB8IHVuZGVmaW5lZCwgc2lnbmF0dXJlOiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0NoZWNrVHg+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2VuZXJhdGUgYSBzaWduYXR1cmUgdG8gcHJvdmUgYSBzcGVuZC4gVW5saWtlIHByb3ZpbmcgYSB0cmFuc2FjdGlvbiwgaXQgZG9lcyBub3QgcmVxdWlyZSB0aGUgZGVzdGluYXRpb24gcHVibGljIGFkZHJlc3MuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHhIYXNoIC0gdHJhbnNhY3Rpb24gdG8gcHJvdmVcbiAgICogQHBhcmFtIHtzdHJpbmd9IFttZXNzYWdlXSAtIG1lc3NhZ2UgdG8gaW5jbHVkZSB3aXRoIHRoZSBzaWduYXR1cmUgdG8gZnVydGhlciBhdXRoZW50aWNhdGUgdGhlIHByb29mIChvcHRpb25hbClcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSB0aGUgdHJhbnNhY3Rpb24gc2lnbmF0dXJlXG4gICAqL1xuICBhc3luYyBnZXRTcGVuZFByb29mKHR4SGFzaDogc3RyaW5nLCBtZXNzYWdlPzogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogUHJvdmUgYSBzcGVuZCB1c2luZyBhIHNpZ25hdHVyZS4gVW5saWtlIHByb3ZpbmcgYSB0cmFuc2FjdGlvbiwgaXQgZG9lcyBub3QgcmVxdWlyZSB0aGUgZGVzdGluYXRpb24gcHVibGljIGFkZHJlc3MuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdHhIYXNoIC0gdHJhbnNhY3Rpb24gdG8gcHJvdmVcbiAgICogQHBhcmFtIHtzdHJpbmcgfCB1bmRlZmluZWR9IG1lc3NhZ2UgLSBtZXNzYWdlIGluY2x1ZGVkIHdpdGggdGhlIHNpZ25hdHVyZSB0byBmdXJ0aGVyIGF1dGhlbnRpY2F0ZSB0aGUgcHJvb2YgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gc2lnbmF0dXJlIC0gdHJhbnNhY3Rpb24gc2lnbmF0dXJlIHRvIGNvbmZpcm1cbiAgICogQHJldHVybiB7UHJvbWlzZTxib29sZWFuPn0gdHJ1ZSBpZiB0aGUgc2lnbmF0dXJlIGlzIGdvb2QsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgYXN5bmMgY2hlY2tTcGVuZFByb29mKHR4SGFzaDogc3RyaW5nLCBtZXNzYWdlOiBzdHJpbmcgfCB1bmRlZmluZWQsIHNpZ25hdHVyZTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdlbmVyYXRlIGEgc2lnbmF0dXJlIHRvIHByb3ZlIHRoZSBlbnRpcmUgYmFsYW5jZSBvZiB0aGUgd2FsbGV0LlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IFttZXNzYWdlXSAtIG1lc3NhZ2UgaW5jbHVkZWQgd2l0aCB0aGUgc2lnbmF0dXJlIHRvIGZ1cnRoZXIgYXV0aGVudGljYXRlIHRoZSBwcm9vZiAob3B0aW9uYWwpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nPn0gdGhlIHJlc2VydmUgcHJvb2Ygc2lnbmF0dXJlXG4gICAqL1xuICBhc3luYyBnZXRSZXNlcnZlUHJvb2ZXYWxsZXQobWVzc2FnZT86IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdlbmVyYXRlIGEgc2lnbmF0dXJlIHRvIHByb3ZlIGFuIGF2YWlsYWJsZSBhbW91bnQgaW4gYW4gYWNjb3VudC5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBhY2NvdW50SWR4IC0gYWNjb3VudCB0byBwcm92ZSBvd25lcnNoaXAgb2YgdGhlIGFtb3VudFxuICAgKiBAcGFyYW0ge2JpZ2ludH0gYW1vdW50IC0gbWluaW11bSBhbW91bnQgdG8gcHJvdmUgYXMgYXZhaWxhYmxlIGluIHRoZSBhY2NvdW50XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbbWVzc2FnZV0gLSBtZXNzYWdlIHRvIGluY2x1ZGUgd2l0aCB0aGUgc2lnbmF0dXJlIHRvIGZ1cnRoZXIgYXV0aGVudGljYXRlIHRoZSBwcm9vZiAob3B0aW9uYWwpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8c3RyaW5nPn0gdGhlIHJlc2VydmUgcHJvb2Ygc2lnbmF0dXJlXG4gICAqL1xuICBhc3luYyBnZXRSZXNlcnZlUHJvb2ZBY2NvdW50KGFjY291bnRJZHg6IG51bWJlciwgYW1vdW50OiBiaWdpbnQsIG1lc3NhZ2U/OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cblxuICAvKipcbiAgICogUHJvdmVzIGEgd2FsbGV0IGhhcyBhIGRpc3Bvc2FibGUgcmVzZXJ2ZSB1c2luZyBhIHNpZ25hdHVyZS5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhZGRyZXNzIC0gcHVibGljIHdhbGxldCBhZGRyZXNzXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgdW5kZWZpbmVkfSBtZXNzYWdlIC0gbWVzc2FnZSBpbmNsdWRlZCB3aXRoIHRoZSBzaWduYXR1cmUgdG8gZnVydGhlciBhdXRoZW50aWNhdGUgdGhlIHByb29mIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNpZ25hdHVyZSAtIHJlc2VydmUgcHJvb2Ygc2lnbmF0dXJlIHRvIGNoZWNrXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvQ2hlY2tSZXNlcnZlPn0gdGhlIHJlc3VsdCBvZiBjaGVja2luZyB0aGUgc2lnbmF0dXJlIHByb29mXG4gICAqL1xuICBhc3luYyBjaGVja1Jlc2VydmVQcm9vZihhZGRyZXNzOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZyB8IHVuZGVmaW5lZCwgc2lnbmF0dXJlOiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0NoZWNrUmVzZXJ2ZT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgYSB0cmFuc2FjdGlvbiBub3RlLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHR4SGFzaCAtIHRyYW5zYWN0aW9uIHRvIGdldCB0aGUgbm90ZSBvZlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZz59IHRoZSB0eCBub3RlXG4gICAqL1xuICBhc3luYyBnZXRUeE5vdGUodHhIYXNoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5nZXRUeE5vdGVzKFt0eEhhc2hdKSlbMF07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgbm90ZXMgZm9yIG11bHRpcGxlIHRyYW5zYWN0aW9ucy5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IHR4SGFzaGVzIC0gaGFzaGVzIG9mIHRoZSB0cmFuc2FjdGlvbnMgdG8gZ2V0IG5vdGVzIGZvclxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZ1tdPn0gbm90ZXMgZm9yIHRoZSB0cmFuc2FjdGlvbnNcbiAgICovXG4gIGFzeW5jIGdldFR4Tm90ZXModHhIYXNoZXM6IHN0cmluZ1tdKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZXQgYSBub3RlIGZvciBhIHNwZWNpZmljIHRyYW5zYWN0aW9uLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHR4SGFzaCAtIGhhc2ggb2YgdGhlIHRyYW5zYWN0aW9uIHRvIHNldCBhIG5vdGUgZm9yXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBub3RlIC0gdGhlIHRyYW5zYWN0aW9uIG5vdGVcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHNldFR4Tm90ZSh0eEhhc2g6IHN0cmluZywgbm90ZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5zZXRUeE5vdGVzKFt0eEhhc2hdLCBbbm90ZV0pO1xuICB9XG4gIFxuICAvKipcbiAgICogU2V0IG5vdGVzIGZvciBtdWx0aXBsZSB0cmFuc2FjdGlvbnMuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSB0eEhhc2hlcyAtIHRyYW5zYWN0aW9ucyB0byBzZXQgbm90ZXMgZm9yXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IG5vdGVzIC0gbm90ZXMgdG8gc2V0IGZvciB0aGUgdHJhbnNhY3Rpb25zXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBzZXRUeE5vdGVzKHR4SGFzaGVzOiBzdHJpbmdbXSwgbm90ZXM6IHN0cmluZ1tdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCBhZGRyZXNzIGJvb2sgZW50cmllcy5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyW119IFtlbnRyeUluZGljZXNdIC0gaW5kaWNlcyBvZiB0aGUgZW50cmllcyB0byBnZXRcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9BZGRyZXNzQm9va0VudHJ5W10+fSB0aGUgYWRkcmVzcyBib29rIGVudHJpZXNcbiAgICovXG4gIGFzeW5jIGdldEFkZHJlc3NCb29rRW50cmllcyhlbnRyeUluZGljZXM/OiBudW1iZXJbXSk6IFByb21pc2U8TW9uZXJvQWRkcmVzc0Jvb2tFbnRyeVtdPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEFkZCBhbiBhZGRyZXNzIGJvb2sgZW50cnkuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWRkcmVzcyAtIGVudHJ5IGFkZHJlc3NcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtkZXNjcmlwdGlvbl0gLSBlbnRyeSBkZXNjcmlwdGlvbiAob3B0aW9uYWwpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8bnVtYmVyPn0gdGhlIGluZGV4IG9mIHRoZSBhZGRlZCBlbnRyeVxuICAgKi9cbiAgYXN5bmMgYWRkQWRkcmVzc0Jvb2tFbnRyeShhZGRyZXNzOiBzdHJpbmcsIGRlc2NyaXB0aW9uPzogc3RyaW5nKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogRWRpdCBhbiBhZGRyZXNzIGJvb2sgZW50cnkuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gaW5kZXggLSBpbmRleCBvZiB0aGUgYWRkcmVzcyBib29rIGVudHJ5IHRvIGVkaXRcbiAgICogQHBhcmFtIHtib29sZWFufSBzZXRBZGRyZXNzIC0gc3BlY2lmaWVzIGlmIHRoZSBhZGRyZXNzIHNob3VsZCBiZSB1cGRhdGVkXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgdW5kZWZpbmVkfSBhZGRyZXNzIC0gdXBkYXRlZCBhZGRyZXNzXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc2V0RGVzY3JpcHRpb24gLSBzcGVjaWZpZXMgaWYgdGhlIGRlc2NyaXB0aW9uIHNob3VsZCBiZSB1cGRhdGVkXG4gICAqIEBwYXJhbSB7c3RyaW5nIHwgdW5kZWZpbmVkfSBkZXNjcmlwdGlvbiAtIHVwZGF0ZWQgZGVzY3JpcHRpb25cbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIGVkaXRBZGRyZXNzQm9va0VudHJ5KGluZGV4OiBudW1iZXIsIHNldEFkZHJlc3M6IGJvb2xlYW4sIGFkZHJlc3M6IHN0cmluZyB8IHVuZGVmaW5lZCwgc2V0RGVzY3JpcHRpb246IGJvb2xlYW4sIGRlc2NyaXB0aW9uOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogRGVsZXRlIGFuIGFkZHJlc3MgYm9vayBlbnRyeS5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBlbnRyeUlkeCAtIGluZGV4IG9mIHRoZSBlbnRyeSB0byBkZWxldGVcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIGRlbGV0ZUFkZHJlc3NCb29rRW50cnkoZW50cnlJZHg6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBUYWcgYWNjb3VudHMuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFnIC0gdGFnIHRvIGFwcGx5IHRvIHRoZSBzcGVjaWZpZWQgYWNjb3VudHNcbiAgICogQHBhcmFtIHtudW1iZXJbXX0gYWNjb3VudEluZGljZXMgLSBpbmRpY2VzIG9mIHRoZSBhY2NvdW50cyB0byB0YWdcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHRhZ0FjY291bnRzKHRhZzogc3RyaW5nLCBhY2NvdW50SW5kaWNlczogbnVtYmVyW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVudGFnIGFjY291bnRzLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJbXX0gYWNjb3VudEluZGljZXMgLSBpbmRpY2VzIG9mIHRoZSBhY2NvdW50cyB0byB1bnRhZ1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgdW50YWdBY2NvdW50cyhhY2NvdW50SW5kaWNlczogbnVtYmVyW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogUmV0dXJuIGFsbCBhY2NvdW50IHRhZ3MuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb0FjY291bnRUYWdbXT59IHRoZSB3YWxsZXQncyBhY2NvdW50IHRhZ3NcbiAgICovXG4gIGFzeW5jIGdldEFjY291bnRUYWdzKCk6IFByb21pc2U8TW9uZXJvQWNjb3VudFRhZ1tdPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXRzIGEgaHVtYW4tcmVhZGFibGUgZGVzY3JpcHRpb24gZm9yIGEgdGFnLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhZyAtIHRhZyB0byBzZXQgYSBkZXNjcmlwdGlvbiBmb3JcbiAgICogQHBhcmFtIHtzdHJpbmd9IGxhYmVsIC0gbGFiZWwgdG8gc2V0IGZvciB0aGUgdGFnXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBzZXRBY2NvdW50VGFnTGFiZWwodGFnOiBzdHJpbmcsIGxhYmVsOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogQ3JlYXRlcyBhIHBheW1lbnQgVVJJIGZyb20gYSBzZW5kIGNvbmZpZ3VyYXRpb24uXG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb1R4Q29uZmlnfSBjb25maWcgLSBzcGVjaWZpZXMgY29uZmlndXJhdGlvbiBmb3IgYSBwb3RlbnRpYWwgdHhcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSB0aGUgcGF5bWVudCB1cmlcbiAgICovXG4gIGFzeW5jIGdldFBheW1lbnRVcmkoY29uZmlnOiBNb25lcm9UeENvbmZpZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFBhcnNlcyBhIHBheW1lbnQgVVJJIHRvIGEgdHggY29uZmlnLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHVyaSAtIHBheW1lbnQgdXJpIHRvIHBhcnNlXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvVHhDb25maWc+fSB0aGUgc2VuZCBjb25maWd1cmF0aW9uIHBhcnNlZCBmcm9tIHRoZSB1cmlcbiAgICovXG4gIGFzeW5jIHBhcnNlUGF5bWVudFVyaSh1cmk6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvVHhDb25maWc+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IGFuIGF0dHJpYnV0ZS5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgLSBhdHRyaWJ1dGUgdG8gZ2V0IHRoZSB2YWx1ZSBvZlxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZz59IHRoZSBhdHRyaWJ1dGUncyB2YWx1ZVxuICAgKi9cbiAgYXN5bmMgZ2V0QXR0cmlidXRlKGtleTogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogU2V0IGFuIGFyYml0cmFyeSBhdHRyaWJ1dGUuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5IC0gYXR0cmlidXRlIGtleVxuICAgKiBAcGFyYW0ge3N0cmluZ30gdmFsIC0gYXR0cmlidXRlIHZhbHVlXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBzZXRBdHRyaWJ1dGUoa2V5OiBzdHJpbmcsIHZhbDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFN0YXJ0IG1pbmluZy5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbbnVtVGhyZWFkc10gLSBudW1iZXIgb2YgdGhyZWFkcyBjcmVhdGVkIGZvciBtaW5pbmcgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtiYWNrZ3JvdW5kTWluaW5nXSAtIHNwZWNpZmllcyBpZiBtaW5pbmcgc2hvdWxkIG9jY3VyIGluIHRoZSBiYWNrZ3JvdW5kIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtib29sZWFufSBbaWdub3JlQmF0dGVyeV0gLSBzcGVjaWZpZXMgaWYgdGhlIGJhdHRlcnkgc2hvdWxkIGJlIGlnbm9yZWQgZm9yIG1pbmluZyAob3B0aW9uYWwpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBzdGFydE1pbmluZyhudW1UaHJlYWRzOiBudW1iZXIsIGJhY2tncm91bmRNaW5pbmc/OiBib29sZWFuLCBpZ25vcmVCYXR0ZXJ5PzogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTdG9wIG1pbmluZy5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBzdG9wTWluaW5nKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgaW1wb3J0aW5nIG11bHRpc2lnIGRhdGEgaXMgbmVlZGVkIGZvciByZXR1cm5pbmcgYSBjb3JyZWN0IGJhbGFuY2UuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPGJvb2xlYW4+fSB0cnVlIGlmIGltcG9ydGluZyBtdWx0aXNpZyBkYXRhIGlzIG5lZWRlZCBmb3IgcmV0dXJuaW5nIGEgY29ycmVjdCBiYWxhbmNlLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIGFzeW5jIGlzTXVsdGlzaWdJbXBvcnROZWVkZWQoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGlzIHdhbGxldCBpcyBhIG11bHRpc2lnIHdhbGxldC5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbGVhbj59IHRydWUgaWYgdGhpcyBpcyBhIG11bHRpc2lnIHdhbGxldCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBhc3luYyBpc011bHRpc2lnKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5nZXRNdWx0aXNpZ0luZm8oKSkuZ2V0SXNNdWx0aXNpZygpO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IG11bHRpc2lnIGluZm8gYWJvdXQgdGhpcyB3YWxsZXQuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPE1vbmVyb011bHRpc2lnSW5mbz59IG11bHRpc2lnIGluZm8gYWJvdXQgdGhpcyB3YWxsZXRcbiAgICovXG4gIGFzeW5jIGdldE11bHRpc2lnSW5mbygpOiBQcm9taXNlPE1vbmVyb011bHRpc2lnSW5mbz4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgbXVsdGlzaWcgaW5mbyBhcyBoZXggdG8gc2hhcmUgd2l0aCBwYXJ0aWNpcGFudHMgdG8gYmVnaW4gY3JlYXRpbmcgYVxuICAgKiBtdWx0aXNpZyB3YWxsZXQuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZz59IHRoaXMgd2FsbGV0J3MgbXVsdGlzaWcgaGV4IHRvIHNoYXJlIHdpdGggcGFydGljaXBhbnRzXG4gICAqL1xuICBhc3luYyBwcmVwYXJlTXVsdGlzaWcoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogTWFrZSB0aGlzIHdhbGxldCBtdWx0aXNpZyBieSBpbXBvcnRpbmcgbXVsdGlzaWcgaGV4IGZyb20gcGFydGljaXBhbnRzLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gbXVsdGlzaWdIZXhlcyAtIG11bHRpc2lnIGhleCBmcm9tIGVhY2ggcGFydGljaXBhbnRcbiAgICogQHBhcmFtIHtudW1iZXJ9IHRocmVzaG9sZCAtIG51bWJlciBvZiBzaWduYXR1cmVzIG5lZWRlZCB0byBzaWduIHRyYW5zZmVyc1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFzc3dvcmQgLSB3YWxsZXQgcGFzc3dvcmRcbiAgICogQHJldHVybiB7UHJvbWlzZTxzdHJpbmc+fSB0aGlzIHdhbGxldCdzIG11bHRpc2lnIGhleCB0byBzaGFyZSB3aXRoIHBhcnRpY2lwYW50c1xuICAgKi9cbiAgYXN5bmMgbWFrZU11bHRpc2lnKG11bHRpc2lnSGV4ZXM6IHN0cmluZ1tdLCB0aHJlc2hvbGQ6IG51bWJlciwgcGFzc3dvcmQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEV4Y2hhbmdlIG11bHRpc2lnIGhleCB3aXRoIHBhcnRpY2lwYW50cyBpbiBhIE0vTiBtdWx0aXNpZyB3YWxsZXQuXG4gICAqIFxuICAgKiBUaGlzIHByb2Nlc3MgbXVzdCBiZSByZXBlYXRlZCB3aXRoIHBhcnRpY2lwYW50cyBleGFjdGx5IE4tTSB0aW1lcy5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IG11bHRpc2lnSGV4ZXMgYXJlIG11bHRpc2lnIGhleCBmcm9tIGVhY2ggcGFydGljaXBhbnRcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhc3N3b3JkIC0gd2FsbGV0J3MgcGFzc3dvcmQgLy8gVE9ETyBtb25lcm8tcHJvamVjdDogcmVkdW5kYW50PyB3YWxsZXQgaXMgY3JlYXRlZCB3aXRoIHBhc3N3b3JkXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvTXVsdGlzaWdJbml0UmVzdWx0Pn0gdGhlIHJlc3VsdCB3aGljaCBoYXMgdGhlIG11bHRpc2lnJ3MgYWRkcmVzcyB4b3IgdGhpcyB3YWxsZXQncyBtdWx0aXNpZyBoZXggdG8gc2hhcmUgd2l0aCBwYXJ0aWNpcGFudHMgaWZmIG5vdCBkb25lXG4gICAqL1xuICBhc3luYyBleGNoYW5nZU11bHRpc2lnS2V5cyhtdWx0aXNpZ0hleGVzOiBzdHJpbmdbXSwgcGFzc3dvcmQ6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvTXVsdGlzaWdJbml0UmVzdWx0PiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IHN1cHBvcnRlZFwiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEV4cG9ydCB0aGlzIHdhbGxldCdzIG11bHRpc2lnIGluZm8gYXMgaGV4IGZvciBvdGhlciBwYXJ0aWNpcGFudHMuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZz59IHRoaXMgd2FsbGV0J3MgbXVsdGlzaWcgaW5mbyBhcyBoZXggZm9yIG90aGVyIHBhcnRpY2lwYW50c1xuICAgKi9cbiAgYXN5bmMgZXhwb3J0TXVsdGlzaWdIZXgoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkP1wiKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEltcG9ydCBtdWx0aXNpZyBpbmZvIGFzIGhleCBmcm9tIG90aGVyIHBhcnRpY2lwYW50cy5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IG11bHRpc2lnSGV4ZXMgLSBtdWx0aXNpZyBoZXggZnJvbSBlYWNoIHBhcnRpY2lwYW50XG4gICAqIEByZXR1cm4ge1Byb21pc2U8bnVtYmVyPn0gdGhlIG51bWJlciBvZiBvdXRwdXRzIHNpZ25lZCB3aXRoIHRoZSBnaXZlbiBtdWx0aXNpZyBoZXhcbiAgICovXG4gIGFzeW5jIGltcG9ydE11bHRpc2lnSGV4KG11bHRpc2lnSGV4ZXM6IHN0cmluZ1tdKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJOb3Qgc3VwcG9ydGVkXCIpO1xuICB9XG4gIFxuICAvKipcbiAgICogU2lnbiBtdWx0aXNpZyB0cmFuc2FjdGlvbnMgZnJvbSBhIG11bHRpc2lnIHdhbGxldC5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtdWx0aXNpZ1R4SGV4IC0gdW5zaWduZWQgbXVsdGlzaWcgdHJhbnNhY3Rpb25zIGFzIGhleFxuICAgKiBAcmV0dXJuIHtNb25lcm9NdWx0aXNpZ1NpZ25SZXN1bHR9IHRoZSByZXN1bHQgb2Ygc2lnbmluZyB0aGUgbXVsdGlzaWcgdHJhbnNhY3Rpb25zXG4gICAqL1xuICBhc3luYyBzaWduTXVsdGlzaWdUeEhleChtdWx0aXNpZ1R4SGV4OiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb011bHRpc2lnU2lnblJlc3VsdD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTdWJtaXQgc2lnbmVkIG11bHRpc2lnIHRyYW5zYWN0aW9ucyBmcm9tIGEgbXVsdGlzaWcgd2FsbGV0LlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNpZ25lZE11bHRpc2lnVHhIZXggLSBzaWduZWQgbXVsdGlzaWcgaGV4IHJldHVybmVkIGZyb20gc2lnbk11bHRpc2lnVHhIZXgoKVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHN0cmluZ1tdPn0gdGhlIHJlc3VsdGluZyB0cmFuc2FjdGlvbiBoYXNoZXNcbiAgICovXG4gIGFzeW5jIHN1Ym1pdE11bHRpc2lnVHhIZXgoc2lnbmVkTXVsdGlzaWdUeEhleDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBDaGFuZ2UgdGhlIHdhbGxldCBwYXNzd29yZC5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBvbGRQYXNzd29yZCAtIHRoZSB3YWxsZXQncyBvbGQgcGFzc3dvcmRcbiAgICogQHBhcmFtIHtzdHJpbmd9IG5ld1Bhc3N3b3JkIC0gdGhlIHdhbGxldCdzIG5ldyBwYXNzd29yZFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgY2hhbmdlUGFzc3dvcmQob2xkUGFzc3dvcmQ6IHN0cmluZywgbmV3UGFzc3dvcmQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTYXZlIHRoZSB3YWxsZXQgYXQgaXRzIGN1cnJlbnQgcGF0aC5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBzYXZlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBPcHRpb25hbGx5IHNhdmUgdGhlbiBjbG9zZSB0aGUgd2FsbGV0LlxuICAgKlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtzYXZlXSAtIHNwZWNpZmllcyBpZiB0aGUgd2FsbGV0IHNob3VsZCBiZSBzYXZlZCBiZWZvcmUgYmVpbmcgY2xvc2VkIChkZWZhdWx0IGZhbHNlKVxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgY2xvc2Uoc2F2ZSA9IGZhbHNlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuY29ubmVjdGlvbk1hbmFnZXIpIHRoaXMuY29ubmVjdGlvbk1hbmFnZXIucmVtb3ZlTGlzdGVuZXIodGhpcy5jb25uZWN0aW9uTWFuYWdlckxpc3RlbmVyKTtcbiAgICB0aGlzLmNvbm5lY3Rpb25NYW5hZ2VyID0gdW5kZWZpbmVkO1xuICAgIHRoaXMuY29ubmVjdGlvbk1hbmFnZXJMaXN0ZW5lciA9IHVuZGVmaW5lZDtcbiAgICB0aGlzLmxpc3RlbmVycy5zcGxpY2UoMCwgdGhpcy5saXN0ZW5lcnMubGVuZ3RoKTtcbiAgICB0aGlzLl9pc0Nsb3NlZCA9IHRydWU7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhpcyB3YWxsZXQgaXMgY2xvc2VkIG9yIG5vdC5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbGVhbj59IHRydWUgaWYgdGhlIHdhbGxldCBpcyBjbG9zZWQsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgYXN5bmMgaXNDbG9zZWQoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMuX2lzQ2xvc2VkO1xuICB9XG4gIFxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBQUklWQVRFIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgYXN5bmMgYW5ub3VuY2VTeW5jUHJvZ3Jlc3MoaGVpZ2h0OiBudW1iZXIsIHN0YXJ0SGVpZ2h0OiBudW1iZXIsIGVuZEhlaWdodDogbnVtYmVyLCBwZXJjZW50RG9uZTogbnVtYmVyLCBtZXNzYWdlOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBmb3IgKGxldCBsaXN0ZW5lciBvZiB0aGlzLmxpc3RlbmVycykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgbGlzdGVuZXIub25TeW5jUHJvZ3Jlc3MoaGVpZ2h0LCBzdGFydEhlaWdodCwgZW5kSGVpZ2h0LCBwZXJjZW50RG9uZSwgbWVzc2FnZSk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIGNhbGxpbmcgbGlzdGVuZXIgb24gc3luYyBwcm9ncmVzc1wiLCBlcnIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgYXN5bmMgYW5ub3VuY2VOZXdCbG9jayhoZWlnaHQ6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGZvciAobGV0IGxpc3RlbmVyIG9mIHRoaXMubGlzdGVuZXJzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBsaXN0ZW5lci5vbk5ld0Jsb2NrKGhlaWdodCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIGNhbGxpbmcgbGlzdGVuZXIgb24gbmV3IGJsb2NrXCIsIGVycik7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBhc3luYyBhbm5vdW5jZUJhbGFuY2VzQ2hhbmdlZChuZXdCYWxhbmNlOiBiaWdpbnQsIG5ld1VubG9ja2VkQmFsYW5jZTogYmlnaW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgZm9yIChsZXQgbGlzdGVuZXIgb2YgdGhpcy5saXN0ZW5lcnMpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGxpc3RlbmVyLm9uQmFsYW5jZXNDaGFuZ2VkKG5ld0JhbGFuY2UsIG5ld1VubG9ja2VkQmFsYW5jZSk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIGNhbGxpbmcgbGlzdGVuZXIgb24gYmFsYW5jZXMgY2hhbmdlZFwiLCBlcnIpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgYXN5bmMgYW5ub3VuY2VPdXRwdXRSZWNlaXZlZChvdXRwdXQ6IE1vbmVyb091dHB1dFdhbGxldCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGZvciAobGV0IGxpc3RlbmVyIG9mIHRoaXMubGlzdGVuZXJzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBsaXN0ZW5lci5vbk91dHB1dFJlY2VpdmVkKG91dHB1dCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkVycm9yIGNhbGxpbmcgbGlzdGVuZXIgb24gb3V0cHV0IHJlY2VpdmVkXCIsIGVycik7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBhc3luYyBhbm5vdW5jZU91dHB1dFNwZW50KG91dHB1dDogTW9uZXJvT3V0cHV0V2FsbGV0KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgZm9yIChsZXQgbGlzdGVuZXIgb2YgdGhpcy5saXN0ZW5lcnMpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGxpc3RlbmVyLm9uT3V0cHV0U3BlbnQob3V0cHV0KTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgY2FsbGluZyBsaXN0ZW5lciBvbiBvdXRwdXQgc3BlbnRcIiwgZXJyKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgbm9ybWFsaXplVHhRdWVyeShxdWVyeSk6IE1vbmVyb1R4UXVlcnkge1xuICAgIGlmIChxdWVyeSBpbnN0YW5jZW9mIE1vbmVyb1R4UXVlcnkpIHF1ZXJ5ID0gcXVlcnkuY29weSgpO1xuICAgIGVsc2UgaWYgKEFycmF5LmlzQXJyYXkocXVlcnkpKSBxdWVyeSA9IG5ldyBNb25lcm9UeFF1ZXJ5KCkuc2V0SGFzaGVzKHF1ZXJ5KTtcbiAgICBlbHNlIHtcbiAgICAgIHF1ZXJ5ID0gT2JqZWN0LmFzc2lnbih7fSwgcXVlcnkpO1xuICAgICAgcXVlcnkgPSBuZXcgTW9uZXJvVHhRdWVyeShxdWVyeSk7XG4gICAgfVxuICAgIGlmIChxdWVyeS5nZXRCbG9jaygpID09PSB1bmRlZmluZWQpIHF1ZXJ5LnNldEJsb2NrKG5ldyBNb25lcm9CbG9jaygpLnNldFR4cyhbcXVlcnldKSk7XG4gICAgaWYgKHF1ZXJ5LmdldElucHV0UXVlcnkoKSkgcXVlcnkuZ2V0SW5wdXRRdWVyeSgpLnNldFR4UXVlcnkocXVlcnkpO1xuICAgIGlmIChxdWVyeS5nZXRPdXRwdXRRdWVyeSgpKSBxdWVyeS5nZXRPdXRwdXRRdWVyeSgpLnNldFR4UXVlcnkocXVlcnkpO1xuICAgIHJldHVybiBxdWVyeTtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIHN0YXRpYyBub3JtYWxpemVUcmFuc2ZlclF1ZXJ5KHF1ZXJ5KTogTW9uZXJvVHJhbnNmZXJRdWVyeSB7XG4gICAgcXVlcnkgPSBuZXcgTW9uZXJvVHJhbnNmZXJRdWVyeShxdWVyeSk7XG4gICAgaWYgKHF1ZXJ5LmdldFR4UXVlcnkoKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBsZXQgdHhRdWVyeSA9IHF1ZXJ5LmdldFR4UXVlcnkoKS5jb3B5KCk7XG4gICAgICBxdWVyeSA9IHR4UXVlcnkuZ2V0VHJhbnNmZXJRdWVyeSgpO1xuICAgIH1cbiAgICBpZiAocXVlcnkuZ2V0VHhRdWVyeSgpID09PSB1bmRlZmluZWQpIHF1ZXJ5LnNldFR4UXVlcnkobmV3IE1vbmVyb1R4UXVlcnkoKSk7XG4gICAgcXVlcnkuZ2V0VHhRdWVyeSgpLnNldFRyYW5zZmVyUXVlcnkocXVlcnkpO1xuICAgIGlmIChxdWVyeS5nZXRUeFF1ZXJ5KCkuZ2V0QmxvY2soKSA9PT0gdW5kZWZpbmVkKSBxdWVyeS5nZXRUeFF1ZXJ5KCkuc2V0QmxvY2sobmV3IE1vbmVyb0Jsb2NrKCkuc2V0VHhzKFtxdWVyeS5nZXRUeFF1ZXJ5KCldKSk7XG4gICAgcmV0dXJuIHF1ZXJ5O1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIG5vcm1hbGl6ZU91dHB1dFF1ZXJ5KHF1ZXJ5KTogTW9uZXJvT3V0cHV0UXVlcnkge1xuICAgIHF1ZXJ5ID0gbmV3IE1vbmVyb091dHB1dFF1ZXJ5KHF1ZXJ5KTtcbiAgICBpZiAocXVlcnkuZ2V0VHhRdWVyeSgpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGxldCB0eFF1ZXJ5ID0gcXVlcnkuZ2V0VHhRdWVyeSgpLmNvcHkoKTtcbiAgICAgIHF1ZXJ5ID0gdHhRdWVyeS5nZXRPdXRwdXRRdWVyeSgpO1xuICAgIH1cbiAgICBpZiAocXVlcnkuZ2V0VHhRdWVyeSgpID09PSB1bmRlZmluZWQpIHF1ZXJ5LnNldFR4UXVlcnkobmV3IE1vbmVyb1R4UXVlcnkoKSk7XG4gICAgcXVlcnkuZ2V0VHhRdWVyeSgpLnNldE91dHB1dFF1ZXJ5KHF1ZXJ5KTtcbiAgICBpZiAocXVlcnkuZ2V0VHhRdWVyeSgpLmdldEJsb2NrKCkgPT09IHVuZGVmaW5lZCkgcXVlcnkuZ2V0VHhRdWVyeSgpLnNldEJsb2NrKG5ldyBNb25lcm9CbG9jaygpLnNldFR4cyhbcXVlcnkuZ2V0VHhRdWVyeSgpXSkpO1xuICAgIHJldHVybiBxdWVyeTtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIHN0YXRpYyBub3JtYWxpemVDcmVhdGVUeHNDb25maWcoY29uZmlnKTogTW9uZXJvVHhDb25maWcge1xuICAgIGlmIChjb25maWcgPT09IHVuZGVmaW5lZCB8fCAhKGNvbmZpZyBpbnN0YW5jZW9mIE9iamVjdCkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk11c3QgcHJvdmlkZSBNb25lcm9UeENvbmZpZyBvciBlcXVpdmFsZW50IEpTIG9iamVjdFwiKTtcbiAgICBjb25maWcgPSBuZXcgTW9uZXJvVHhDb25maWcoY29uZmlnKTtcbiAgICBhc3NlcnQoY29uZmlnLmdldERlc3RpbmF0aW9ucygpICYmIGNvbmZpZy5nZXREZXN0aW5hdGlvbnMoKS5sZW5ndGggPiAwLCBcIk11c3QgcHJvdmlkZSBkZXN0aW5hdGlvbnNcIik7XG4gICAgYXNzZXJ0LmVxdWFsKGNvbmZpZy5nZXRTd2VlcEVhY2hTdWJhZGRyZXNzKCksIHVuZGVmaW5lZCk7XG4gICAgYXNzZXJ0LmVxdWFsKGNvbmZpZy5nZXRCZWxvd0Ftb3VudCgpLCB1bmRlZmluZWQpO1xuICAgIHJldHVybiBjb25maWc7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgbm9ybWFsaXplU3dlZXBPdXRwdXRDb25maWcoY29uZmlnKTogTW9uZXJvVHhDb25maWcge1xuICAgIGlmIChjb25maWcgPT09IHVuZGVmaW5lZCB8fCAhKGNvbmZpZyBpbnN0YW5jZW9mIE9iamVjdCkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk11c3QgcHJvdmlkZSBNb25lcm9UeENvbmZpZyBvciBlcXVpdmFsZW50IEpTIG9iamVjdFwiKTtcbiAgICBjb25maWcgPSBuZXcgTW9uZXJvVHhDb25maWcoY29uZmlnKTtcbiAgICBhc3NlcnQuZXF1YWwoY29uZmlnLmdldFN3ZWVwRWFjaFN1YmFkZHJlc3MoKSwgdW5kZWZpbmVkKTtcbiAgICBhc3NlcnQuZXF1YWwoY29uZmlnLmdldEJlbG93QW1vdW50KCksIHVuZGVmaW5lZCk7XG4gICAgYXNzZXJ0LmVxdWFsKGNvbmZpZy5nZXRDYW5TcGxpdCgpLCB1bmRlZmluZWQsIFwiQ2Fubm90IHNwbGl0IHRyYW5zYWN0aW9ucyB3aGVuIHN3ZWVwaW5nIGFuIG91dHB1dFwiKTtcbiAgICBpZiAoIWNvbmZpZy5nZXREZXN0aW5hdGlvbnMoKSB8fCBjb25maWcuZ2V0RGVzdGluYXRpb25zKCkubGVuZ3RoICE9PSAxIHx8ICFjb25maWcuZ2V0RGVzdGluYXRpb25zKClbMF0uZ2V0QWRkcmVzcygpKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJNdXN0IHByb3ZpZGUgZXhhY3RseSBvbmUgZGVzdGluYXRpb24gYWRkcmVzcyB0byBzd2VlcCBvdXRwdXQgdG9cIik7XG4gICAgaWYgKGNvbmZpZy5nZXRTdWJ0cmFjdEZlZUZyb20oKSAmJiBjb25maWcuZ2V0U3VidHJhY3RGZWVGcm9tKCkubGVuZ3RoID4gMCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3dlZXAgdHJhbnNhY3Rpb25zIGRvIG5vdCBzdXBwb3J0IHN1YnRyYWN0aW5nIGZlZXMgZnJvbSBkZXN0aW5hdGlvbnNcIik7XG4gICAgcmV0dXJuIGNvbmZpZzsgIFxuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIG5vcm1hbGl6ZVN3ZWVwVW5sb2NrZWRDb25maWcoY29uZmlnKTogTW9uZXJvVHhDb25maWcge1xuICAgIGlmIChjb25maWcgPT09IHVuZGVmaW5lZCB8fCAhKGNvbmZpZyBpbnN0YW5jZW9mIE9iamVjdCkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk11c3QgcHJvdmlkZSBNb25lcm9UeENvbmZpZyBvciBlcXVpdmFsZW50IEpTIG9iamVjdFwiKTtcbiAgICBjb25maWcgPSBuZXcgTW9uZXJvVHhDb25maWcoY29uZmlnKTtcbiAgICBpZiAoY29uZmlnLmdldERlc3RpbmF0aW9ucygpID09PSB1bmRlZmluZWQgfHwgY29uZmlnLmdldERlc3RpbmF0aW9ucygpLmxlbmd0aCAhPSAxKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJNdXN0IHByb3ZpZGUgZXhhY3RseSBvbmUgZGVzdGluYXRpb24gdG8gc3dlZXAgdG9cIik7XG4gICAgaWYgKGNvbmZpZy5nZXREZXN0aW5hdGlvbnMoKVswXS5nZXRBZGRyZXNzKCkgPT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTXVzdCBwcm92aWRlIGRlc3RpbmF0aW9uIGFkZHJlc3MgdG8gc3dlZXAgdG9cIik7XG4gICAgaWYgKGNvbmZpZy5nZXREZXN0aW5hdGlvbnMoKVswXS5nZXRBbW91bnQoKSAhPT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJDYW5ub3QgcHJvdmlkZSBhbW91bnQgaW4gc3dlZXAgY29uZmlnXCIpO1xuICAgIGlmIChjb25maWcuZ2V0S2V5SW1hZ2UoKSAhPT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJLZXkgaW1hZ2UgZGVmaW5lZDsgdXNlIHN3ZWVwT3V0cHV0KCkgdG8gc3dlZXAgYW4gb3V0cHV0IGJ5IGl0cyBrZXkgaW1hZ2VcIik7XG4gICAgaWYgKGNvbmZpZy5nZXRTdWJhZGRyZXNzSW5kaWNlcygpICE9PSB1bmRlZmluZWQgJiYgY29uZmlnLmdldFN1YmFkZHJlc3NJbmRpY2VzKCkubGVuZ3RoID09PSAwKSBjb25maWcuc2V0U3ViYWRkcmVzc0luZGljZXModW5kZWZpbmVkKTtcbiAgICBpZiAoY29uZmlnLmdldEFjY291bnRJbmRleCgpID09PSB1bmRlZmluZWQgJiYgY29uZmlnLmdldFN1YmFkZHJlc3NJbmRpY2VzKCkgIT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTXVzdCBwcm92aWRlIGFjY291bnQgaW5kZXggaWYgc3ViYWRkcmVzcyBpbmRpY2VzIGFyZSBwcm92aWRlZFwiKTtcbiAgICBpZiAoY29uZmlnLmdldFN1YnRyYWN0RmVlRnJvbSgpICYmIGNvbmZpZy5nZXRTdWJ0cmFjdEZlZUZyb20oKS5sZW5ndGggPiAwKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTd2VlcCB0cmFuc2FjdGlvbnMgZG8gbm90IHN1cHBvcnQgc3VidHJhY3RpbmcgZmVlcyBmcm9tIGRlc3RpbmF0aW9uc1wiKTtcbiAgICByZXR1cm4gY29uZmlnO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJ5TEFBQSxJQUFBQSxPQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7Ozs7O0FBS0EsSUFBQUMsWUFBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBOzs7O0FBSUEsSUFBQUUsZ0NBQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFHLFlBQUEsR0FBQUosc0JBQUEsQ0FBQUMsT0FBQTs7Ozs7O0FBTUEsSUFBQUksMkJBQUEsR0FBQUwsc0JBQUEsQ0FBQUMsT0FB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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/MoneroWalletFull.d.ts b/dist/src/main/ts/wallet/MoneroWalletFull.d.ts new file mode 100644 index 000000000..63374f1b9 --- /dev/null +++ b/dist/src/main/ts/wallet/MoneroWalletFull.d.ts @@ -0,0 +1,382 @@ +import TaskLooper from "../common/TaskLooper"; +import MoneroAccount from "./model/MoneroAccount"; +import MoneroAccountTag from "./model/MoneroAccountTag"; +import MoneroAddressBookEntry from "./model/MoneroAddressBookEntry"; +import MoneroCheckTx from "./model/MoneroCheckTx"; +import MoneroCheckReserve from "./model/MoneroCheckReserve"; +import MoneroIncomingTransfer from "./model/MoneroIncomingTransfer"; +import MoneroIntegratedAddress from "./model/MoneroIntegratedAddress"; +import MoneroKeyImage from "../daemon/model/MoneroKeyImage"; +import MoneroKeyImageImportResult from "./model/MoneroKeyImageImportResult"; +import MoneroMultisigInfo from "./model/MoneroMultisigInfo"; +import MoneroMultisigInitResult from "./model/MoneroMultisigInitResult"; +import MoneroMultisigSignResult from "./model/MoneroMultisigSignResult"; +import MoneroNetworkType from "../daemon/model/MoneroNetworkType"; +import MoneroOutputQuery from "./model/MoneroOutputQuery"; +import MoneroOutputWallet from "./model/MoneroOutputWallet"; +import MoneroRpcConnection from "../common/MoneroRpcConnection"; +import MoneroSubaddress from "./model/MoneroSubaddress"; +import MoneroSyncResult from "./model/MoneroSyncResult"; +import MoneroTransfer from "./model/MoneroTransfer"; +import MoneroTransferQuery from "./model/MoneroTransferQuery"; +import MoneroTxConfig from "./model/MoneroTxConfig"; +import MoneroTxPriority from "./model/MoneroTxPriority"; +import MoneroTxQuery from "./model/MoneroTxQuery"; +import MoneroTxSet from "./model/MoneroTxSet"; +import MoneroTxWallet from "./model/MoneroTxWallet"; +import MoneroWallet from "./MoneroWallet"; +import MoneroWalletConfig from "./model/MoneroWalletConfig"; +import { MoneroWalletKeys, MoneroWalletKeysProxy } from "./MoneroWalletKeys"; +import MoneroWalletListener from "./model/MoneroWalletListener"; +import MoneroMessageSignatureType from "./model/MoneroMessageSignatureType"; +import MoneroMessageSignatureResult from "./model/MoneroMessageSignatureResult"; +import MoneroVersion from "../daemon/model/MoneroVersion"; +/** + * Implements a Monero wallet using client-side WebAssembly bindings to monero-project's wallet2 in C++. + */ +export default class MoneroWalletFull extends MoneroWalletKeys { + protected static readonly DEFAULT_SYNC_PERIOD_IN_MS = 20000; + protected static FS: any; + protected path: string; + protected password: string; + protected listeners: MoneroWalletListener[]; + protected fs: any; + protected wasmListener: WalletWasmListener; + protected wasmListenerHandle: number; + protected rejectUnauthorized: boolean; + protected rejectUnauthorizedConfigId: string; + protected syncPeriodInMs: number; + protected syncLooper: TaskLooper; + protected browserMainPath: string; + /** + * Internal constructor which is given the memory address of a C++ wallet instance. + * + * This constructor should be called through static wallet creation utilities in this class. + * + * @param {number} cppAddress - address of the wallet instance in C++ + * @param {string} path - path of the wallet instance + * @param {string} password - password of the wallet instance + * @param {FileSystem} fs - node.js-compatible file system to read/write wallet files + * @param {boolean} rejectUnauthorized - specifies if unauthorized requests (e.g. self-signed certificates) should be rejected + * @param {string} rejectUnauthorizedFnId - unique identifier for http_client_wasm to query rejectUnauthorized + * @param {MoneroWalletFullProxy} walletProxy - proxy to invoke wallet operations in a web worker + * + * @private + */ + constructor(cppAddress: any, path: any, password: any, fs: any, rejectUnauthorized: any, rejectUnauthorizedFnId: any, walletProxy?: MoneroWalletFullProxy); + /** + * Check if a wallet exists at a given path. + * + * @param {string} path - path of the wallet on the file system + * @param {any} fs - file system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser) + * @return {boolean} true if a wallet exists at the given path, false otherwise + */ + static walletExists(path: any, fs: any): Promise; + static openWallet(config: Partial): Promise; + static createWallet(config: MoneroWalletConfig): Promise; + protected static createWalletFromSeed(config: MoneroWalletConfig): Promise; + protected static createWalletFromKeys(config: MoneroWalletConfig): Promise; + protected static createWalletRandom(config: MoneroWalletConfig): Promise; + static getSeedLanguages(): Promise; + static getFs(): any; + /** + * Get the maximum height of the peers the wallet's daemon is connected to. + * + * @return {Promise} the maximum height of the peers the wallet's daemon is connected to + */ + getDaemonMaxPeerHeight(): Promise; + /** + * Indicates if the wallet's daemon is synced with the network. + * + * @return {Promise} true if the daemon is synced with the network, false otherwise + */ + isDaemonSynced(): Promise; + /** + * Indicates if the wallet is synced with the daemon. + * + * @return {Promise} true if the wallet is synced with the daemon, false otherwise + */ + isSynced(): Promise; + /** + * Get the wallet's network type (mainnet, testnet, or stagenet). + * + * @return {Promise} the wallet's network type + */ + getNetworkType(): Promise; + /** + * Get the height of the first block that the wallet scans. + * + * @return {Promise} the height of the first block that the wallet scans + */ + getRestoreHeight(): Promise; + /** + * Set the height of the first block that the wallet scans. + * + * @param {number} restoreHeight - height of the first block that the wallet scans + * @return {Promise} + */ + setRestoreHeight(restoreHeight: number): Promise; + /** + * Move the wallet from its current path to the given path. + * + * @param {string} path - the wallet's destination path + * @return {Promise} + */ + moveTo(path: string): Promise; + addListener(listener: MoneroWalletListener): Promise; + removeListener(listener: any): Promise; + getListeners(): MoneroWalletListener[]; + setDaemonConnection(uriOrConnection?: MoneroRpcConnection | string): Promise; + getDaemonConnection(): Promise; + isConnectedToDaemon(): Promise; + getVersion(): Promise; + getPath(): Promise; + getIntegratedAddress(standardAddress?: string, paymentId?: string): Promise; + decodeIntegratedAddress(integratedAddress: string): Promise; + getHeight(): Promise; + getDaemonHeight(): Promise; + getHeightByDate(year: number, month: number, day: number): Promise; + /** + * Synchronize the wallet with the daemon as a one-time synchronous process. + * + * @param {MoneroWalletListener|number} [listenerOrStartHeight] - listener xor start height (defaults to no sync listener, the last synced block) + * @param {number} [startHeight] - startHeight if not given in first arg (defaults to last synced block) + * @param {boolean} [allowConcurrentCalls] - allow other wallet methods to be processed simultaneously during sync (default false)

WARNING: enabling this option will crash wallet execution if another call makes a simultaneous network request. TODO: possible to sync wasm network requests in http_client_wasm.cpp? + */ + sync(listenerOrStartHeight?: MoneroWalletListener | number, startHeight?: number, allowConcurrentCalls?: boolean): Promise; + startSyncing(syncPeriodInMs?: number): Promise; + stopSyncing(): Promise; + scanTxs(txHashes: string[]): Promise; + rescanSpent(): Promise; + rescanBlockchain(): Promise; + getBalance(accountIdx?: number, subaddressIdx?: number): Promise; + getUnlockedBalance(accountIdx?: number, subaddressIdx?: number): Promise; + getAccounts(includeSubaddresses?: boolean, tag?: string): Promise; + getAccount(accountIdx: number, includeSubaddresses?: boolean): Promise; + createAccount(label?: string): Promise; + getSubaddresses(accountIdx: number, subaddressIndices?: number[]): Promise; + createSubaddress(accountIdx: number, label?: string): Promise; + setSubaddressLabel(accountIdx: number, subaddressIdx: number, label: string): Promise; + getTxs(query?: string[] | Partial): Promise; + getTransfers(query?: Partial): Promise; + getOutputs(query?: Partial): Promise; + exportOutputs(all?: boolean): Promise; + importOutputs(outputsHex: string): Promise; + exportKeyImages(all?: boolean): Promise; + importKeyImages(keyImages: MoneroKeyImage[]): Promise; + getNewKeyImagesFromLastImport(): Promise; + freezeOutput(keyImage: string): Promise; + thawOutput(keyImage: string): Promise; + isOutputFrozen(keyImage: string): Promise; + getDefaultFeePriority(): Promise; + createTxs(config: Partial): Promise; + sweepOutput(config: Partial): Promise; + sweepUnlocked(config: Partial): Promise; + sweepDust(relay?: boolean): Promise; + relayTxs(txsOrMetadatas: (MoneroTxWallet | string)[]): Promise; + describeTxSet(txSet: MoneroTxSet): Promise; + signTxs(unsignedTxHex: string): Promise; + submitTxs(signedTxHex: string): Promise; + signMessage(message: string, signatureType?: MoneroMessageSignatureType, accountIdx?: number, subaddressIdx?: number): Promise; + verifyMessage(message: string, address: string, signature: string): Promise; + getTxKey(txHash: string): Promise; + checkTxKey(txHash: string, txKey: string, address: string): Promise; + getTxProof(txHash: string, address: string, message?: string): Promise; + checkTxProof(txHash: string, address: string, message: string | undefined, signature: string): Promise; + getSpendProof(txHash: string, message?: string): Promise; + checkSpendProof(txHash: string, message: string | undefined, signature: string): Promise; + getReserveProofWallet(message?: string): Promise; + getReserveProofAccount(accountIdx: number, amount: bigint, message?: string): Promise; + checkReserveProof(address: string, message: string | undefined, signature: string): Promise; + getTxNotes(txHashes: string[]): Promise; + setTxNotes(txHashes: string[], notes: string[]): Promise; + getAddressBookEntries(entryIndices?: number[]): Promise; + addAddressBookEntry(address: string, description?: string): Promise; + editAddressBookEntry(index: number, setAddress: boolean, address: string | undefined, setDescription: boolean, description: string | undefined): Promise; + deleteAddressBookEntry(entryIdx: number): Promise; + tagAccounts(tag: string, accountIndices: number[]): Promise; + untagAccounts(accountIndices: number[]): Promise; + getAccountTags(): Promise; + setAccountTagLabel(tag: string, label: string): Promise; + getPaymentUri(config: MoneroTxConfig): Promise; + parsePaymentUri(uri: string): Promise; + getAttribute(key: string): Promise; + setAttribute(key: string, val: string): Promise; + startMining(numThreads: number, backgroundMining?: boolean, ignoreBattery?: boolean): Promise; + stopMining(): Promise; + isMultisigImportNeeded(): Promise; + isMultisig(): Promise; + getMultisigInfo(): Promise; + prepareMultisig(): Promise; + makeMultisig(multisigHexes: string[], threshold: number, password: string): Promise; + exchangeMultisigKeys(multisigHexes: string[], password: string): Promise; + exportMultisigHex(): Promise; + importMultisigHex(multisigHexes: string[]): Promise; + signMultisigTxHex(multisigTxHex: string): Promise; + submitMultisigTxHex(signedMultisigTxHex: string): Promise; + /** + * Get the wallet's keys and cache data. + * + * @return {Promise} is the keys and cache data, respectively + */ + getData(): Promise; + changePassword(oldPassword: string, newPassword: string): Promise; + save(): Promise; + close(save?: boolean): Promise; + getNumBlocksToUnlock(): Promise; + getTx(txHash: string): Promise; + getIncomingTransfers(query: Partial): Promise; + getOutgoingTransfers(query: Partial): Promise; + createTx(config: Partial): Promise; + relayTx(txOrMetadata: MoneroTxWallet | string): Promise; + getTxNote(txHash: string): Promise; + setTxNote(txHash: string, note: string): Promise; + protected static openWalletData(config: Partial): Promise; + protected getWalletProxy(): MoneroWalletFullProxy; + protected backgroundSync(): Promise; + protected refreshListening(): Promise; + static sanitizeBlock(block: any): any; + static sanitizeTxWallet(tx: any): MoneroTxWallet; + static sanitizeAccount(account: any): any; + static deserializeBlocks(blocksJsonStr: any): any; + static deserializeTxs(query: any, blocksJsonStr: any): any[]; + static deserializeTransfers(query: any, blocksJsonStr: any): any[]; + static deserializeOutputs(query: any, blocksJsonStr: any): any[]; + /** + * Set the path of the wallet on the browser main thread if run as a worker. + * + * @param {string} browserMainPath - path of the wallet on the browser main thread + */ + protected setBrowserMainPath(browserMainPath: any): void; + static moveTo(path: any, wallet: any): Promise; + static save(wallet: any): Promise; +} +/** + * Implements a MoneroWallet by proxying requests to a worker which runs a full wallet. + * + * @private + */ +declare class MoneroWalletFullProxy extends MoneroWalletKeysProxy { + protected path: any; + protected fs: any; + protected wrappedListeners: any; + static openWalletData(config: Partial): Promise; + static createWallet(config: any): Promise; + /** + * Internal constructor which is given a worker to communicate with via messages. + * + * This method should not be called externally but should be called through + * static wallet creation utilities in this class. + * + * @param {string} walletId - identifies the wallet with the worker + * @param {Worker} worker - worker to communicate with via messages + */ + constructor(walletId: any, worker: any, path: any, fs: any); + getPath(): any; + getNetworkType(): Promise; + setSubaddressLabel(accountIdx: any, subaddressIdx: any, label: any): Promise; + setDaemonConnection(uriOrRpcConnection: any): Promise; + getDaemonConnection(): Promise; + isConnectedToDaemon(): Promise; + getRestoreHeight(): Promise; + setRestoreHeight(restoreHeight: any): Promise; + getDaemonHeight(): Promise; + getDaemonMaxPeerHeight(): Promise; + getHeightByDate(year: any, month: any, day: any): Promise; + isDaemonSynced(): Promise; + getHeight(): Promise; + addListener(listener: any): Promise; + removeListener(listener: any): Promise; + getListeners(): any[]; + isSynced(): Promise; + sync(listenerOrStartHeight?: MoneroWalletListener | number, startHeight?: number, allowConcurrentCalls?: boolean): Promise; + startSyncing(syncPeriodInMs: any): Promise; + stopSyncing(): Promise; + scanTxs(txHashes: any): Promise; + rescanSpent(): Promise; + rescanBlockchain(): Promise; + getBalance(accountIdx: any, subaddressIdx: any): Promise; + getUnlockedBalance(accountIdx: any, subaddressIdx: any): Promise; + getAccounts(includeSubaddresses: any, tag: any): Promise; + getAccount(accountIdx: any, includeSubaddresses: any): Promise; + createAccount(label: any): Promise; + getSubaddresses(accountIdx: any, subaddressIndices: any): Promise; + createSubaddress(accountIdx: any, label: any): Promise; + getTxs(query: any): Promise; + getTransfers(query: any): Promise; + getOutputs(query: any): Promise; + exportOutputs(all: any): Promise; + importOutputs(outputsHex: any): Promise; + exportKeyImages(all: any): Promise; + importKeyImages(keyImages: any): Promise; + getNewKeyImagesFromLastImport(): Promise; + freezeOutput(keyImage: any): Promise; + thawOutput(keyImage: any): Promise; + isOutputFrozen(keyImage: any): Promise; + getDefaultFeePriority(): Promise; + createTxs(config: any): Promise; + sweepOutput(config: any): Promise; + sweepUnlocked(config: any): Promise; + sweepDust(relay: any): Promise; + relayTxs(txsOrMetadatas: any): Promise; + describeTxSet(txSet: any): Promise; + signTxs(unsignedTxHex: any): Promise; + submitTxs(signedTxHex: any): Promise; + signMessage(message: any, signatureType: any, accountIdx: any, subaddressIdx: any): Promise; + verifyMessage(message: any, address: any, signature: any): Promise; + getTxKey(txHash: any): Promise; + checkTxKey(txHash: any, txKey: any, address: any): Promise; + getTxProof(txHash: any, address: any, message: any): Promise; + checkTxProof(txHash: any, address: any, message: any, signature: any): Promise; + getSpendProof(txHash: any, message: any): Promise; + checkSpendProof(txHash: any, message: any, signature: any): Promise; + getReserveProofWallet(message: any): Promise; + getReserveProofAccount(accountIdx: any, amount: any, message: any): Promise; + checkReserveProof(address: any, message: any, signature: any): Promise; + getTxNotes(txHashes: any): Promise; + setTxNotes(txHashes: any, notes: any): Promise; + getAddressBookEntries(entryIndices: any): Promise; + addAddressBookEntry(address: any, description: any): Promise; + editAddressBookEntry(index: any, setAddress: any, address: any, setDescription: any, description: any): Promise; + deleteAddressBookEntry(entryIdx: any): Promise; + tagAccounts(tag: any, accountIndices: any): Promise; + untagAccounts(accountIndices: any): Promise; + getAccountTags(): Promise; + setAccountTagLabel(tag: any, label: any): Promise; + getPaymentUri(config: any): Promise; + parsePaymentUri(uri: any): Promise; + getAttribute(key: any): Promise; + setAttribute(key: any, val: any): Promise; + startMining(numThreads: any, backgroundMining: any, ignoreBattery: any): Promise; + stopMining(): Promise; + isMultisigImportNeeded(): Promise; + isMultisig(): Promise; + getMultisigInfo(): Promise; + prepareMultisig(): Promise; + makeMultisig(multisigHexes: any, threshold: any, password: any): Promise; + exchangeMultisigKeys(multisigHexes: any, password: any): Promise; + exportMultisigHex(): Promise; + importMultisigHex(multisigHexes: any): Promise; + signMultisigTxHex(multisigTxHex: any): Promise; + submitMultisigTxHex(signedMultisigTxHex: any): Promise; + getData(): Promise; + moveTo(path: any): Promise; + changePassword(oldPassword: any, newPassword: any): Promise; + save(): Promise; + close(save: any): Promise; +} +/** + * Receives notifications directly from wasm c++. + * + * @private + */ +declare class WalletWasmListener { + protected wallet: MoneroWallet; + constructor(wallet: any); + onSyncProgress(height: any, startHeight: any, endHeight: any, percentDone: any, message: any): Promise; + onNewBlock(height: any): Promise; + onBalancesChanged(newBalanceStr: any, newUnlockedBalanceStr: any): Promise; + onOutputReceived(height: any, txHash: any, amountStr: any, accountIdx: any, subaddressIdx: any, version: any, unlockTime: any, isLocked: any): Promise; + onOutputSpent(height: any, txHash: any, amountStr: any, accountIdxStr: any, subaddressIdxStr: any, version: any, unlockTime: any, isLocked: any): Promise; +} +export {}; diff --git a/dist/src/main/ts/wallet/MoneroWalletFull.js b/dist/src/main/ts/wallet/MoneroWalletFull.js new file mode 100644 index 000000000..d564b611c --- /dev/null +++ b/dist/src/main/ts/wallet/MoneroWalletFull.js @@ -0,0 +1,2501 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _path = _interopRequireDefault(require("path")); +var _GenUtils = _interopRequireDefault(require("../common/GenUtils")); +var _LibraryUtils = _interopRequireDefault(require("../common/LibraryUtils")); +var _TaskLooper = _interopRequireDefault(require("../common/TaskLooper")); +var _MoneroAccount = _interopRequireDefault(require("./model/MoneroAccount")); +var _MoneroAccountTag = _interopRequireDefault(require("./model/MoneroAccountTag")); +var _MoneroAddressBookEntry = _interopRequireDefault(require("./model/MoneroAddressBookEntry")); +var _MoneroBlock = _interopRequireDefault(require("../daemon/model/MoneroBlock")); +var _MoneroCheckTx = _interopRequireDefault(require("./model/MoneroCheckTx")); +var _MoneroCheckReserve = _interopRequireDefault(require("./model/MoneroCheckReserve")); +var _MoneroDaemonRpc = _interopRequireDefault(require("../daemon/MoneroDaemonRpc")); +var _MoneroError = _interopRequireDefault(require("../common/MoneroError")); + +var _MoneroIntegratedAddress = _interopRequireDefault(require("./model/MoneroIntegratedAddress")); +var _MoneroKeyImage = _interopRequireDefault(require("../daemon/model/MoneroKeyImage")); +var _MoneroKeyImageImportResult = _interopRequireDefault(require("./model/MoneroKeyImageImportResult")); +var _MoneroMultisigInfo = _interopRequireDefault(require("./model/MoneroMultisigInfo")); +var _MoneroMultisigInitResult = _interopRequireDefault(require("./model/MoneroMultisigInitResult")); +var _MoneroMultisigSignResult = _interopRequireDefault(require("./model/MoneroMultisigSignResult")); +var _MoneroNetworkType = _interopRequireDefault(require("../daemon/model/MoneroNetworkType")); + +var _MoneroOutputWallet = _interopRequireDefault(require("./model/MoneroOutputWallet")); +var _MoneroRpcConnection = _interopRequireDefault(require("../common/MoneroRpcConnection")); +var _MoneroSubaddress = _interopRequireDefault(require("./model/MoneroSubaddress")); +var _MoneroSyncResult = _interopRequireDefault(require("./model/MoneroSyncResult")); + + +var _MoneroTxConfig = _interopRequireDefault(require("./model/MoneroTxConfig")); + + +var _MoneroTxSet = _interopRequireDefault(require("./model/MoneroTxSet")); + +var _MoneroTxWallet = _interopRequireDefault(require("./model/MoneroTxWallet")); +var _MoneroWallet = _interopRequireDefault(require("./MoneroWallet")); +var _MoneroWalletConfig = _interopRequireDefault(require("./model/MoneroWalletConfig")); +var _MoneroWalletKeys = require("./MoneroWalletKeys"); +var _MoneroWalletListener = _interopRequireDefault(require("./model/MoneroWalletListener")); +var _MoneroMessageSignatureType = _interopRequireDefault(require("./model/MoneroMessageSignatureType")); +var _MoneroMessageSignatureResult = _interopRequireDefault(require("./model/MoneroMessageSignatureResult")); + +var _fs = _interopRequireDefault(require("fs")); + +/** + * Implements a Monero wallet using client-side WebAssembly bindings to monero-project's wallet2 in C++. + */ +class MoneroWalletFull extends _MoneroWalletKeys.MoneroWalletKeys { + + // static variables + static DEFAULT_SYNC_PERIOD_IN_MS = 20000; + + + // instance variables + + + + + + + + + + + + + /** + * Internal constructor which is given the memory address of a C++ wallet instance. + * + * This constructor should be called through static wallet creation utilities in this class. + * + * @param {number} cppAddress - address of the wallet instance in C++ + * @param {string} path - path of the wallet instance + * @param {string} password - password of the wallet instance + * @param {FileSystem} fs - node.js-compatible file system to read/write wallet files + * @param {boolean} rejectUnauthorized - specifies if unauthorized requests (e.g. self-signed certificates) should be rejected + * @param {string} rejectUnauthorizedFnId - unique identifier for http_client_wasm to query rejectUnauthorized + * @param {MoneroWalletFullProxy} walletProxy - proxy to invoke wallet operations in a web worker + * + * @private + */ + constructor(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId, walletProxy) { + super(cppAddress, walletProxy); + if (walletProxy) return; + this.path = path; + this.password = password; + this.listeners = []; + this.fs = fs ? fs : path ? MoneroWalletFull.getFs() : undefined; + this._isClosed = false; + this.wasmListener = new WalletWasmListener(this); // receives notifications from wasm c++ + this.wasmListenerHandle = 0; // memory address of the wallet listener in c++ + this.rejectUnauthorized = rejectUnauthorized; + this.rejectUnauthorizedConfigId = rejectUnauthorizedFnId; + this.syncPeriodInMs = MoneroWalletFull.DEFAULT_SYNC_PERIOD_IN_MS; + _LibraryUtils.default.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => this.rejectUnauthorized); // register fn informing if unauthorized reqs should be rejected + } + + // --------------------------- STATIC UTILITIES ----------------------------- + + /** + * Check if a wallet exists at a given path. + * + * @param {string} path - path of the wallet on the file system + * @param {any} fs - file system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser) + * @return {boolean} true if a wallet exists at the given path, false otherwise + */ + static async walletExists(path, fs) { + (0, _assert.default)(path, "Must provide a path to look for a wallet"); + if (!fs) fs = MoneroWalletFull.getFs(); + if (!fs) throw new _MoneroError.default("Must provide file system to check if wallet exists"); + let exists = await _LibraryUtils.default.exists(fs, path + ".keys"); + _LibraryUtils.default.log(1, "Wallet exists at " + path + ": " + exists); + return exists; + } + + static async openWallet(config) { + + // validate config + config = new _MoneroWalletConfig.default(config); + if (config.getProxyToWorker() === undefined) config.setProxyToWorker(true); + if (config.getSeed() !== undefined) throw new _MoneroError.default("Cannot specify seed when opening wallet"); + if (config.getSeedOffset() !== undefined) throw new _MoneroError.default("Cannot specify seed offset when opening wallet"); + if (config.getPrimaryAddress() !== undefined) throw new _MoneroError.default("Cannot specify primary address when opening wallet"); + if (config.getPrivateViewKey() !== undefined) throw new _MoneroError.default("Cannot specify private view key when opening wallet"); + if (config.getPrivateSpendKey() !== undefined) throw new _MoneroError.default("Cannot specify private spend key when opening wallet"); + if (config.getRestoreHeight() !== undefined) throw new _MoneroError.default("Cannot specify restore height when opening wallet"); + if (config.getLanguage() !== undefined) throw new _MoneroError.default("Cannot specify language when opening wallet"); + if (config.getSaveCurrent() === true) throw new _MoneroError.default("Cannot save current wallet when opening full wallet"); + if (config.getFs() === undefined) config.setFs(MoneroWalletFull.getFs()); + + // set server from connection manager if provided + if (config.getConnectionManager()) { + if (config.getServer()) throw new _MoneroError.default("Wallet can be opened with a server or connection manager but not both"); + config.setServer(config.getConnectionManager().getConnection()); + } + + // read wallet data from disk unless provided + if (!config.getKeysData()) { + let fs = config.getFs(); + if (!fs) throw new _MoneroError.default("Must provide file system to read wallet data from"); + if (!(await this.walletExists(config.getPath(), fs))) throw new _MoneroError.default("Wallet does not exist at path: " + config.getPath()); + config.setKeysData(await fs.readFile(config.getPath() + ".keys")); + config.setCacheData((await _LibraryUtils.default.exists(fs, config.getPath())) ? await fs.readFile(config.getPath()) : ""); + } + + // open wallet from data + const wallet = await MoneroWalletFull.openWalletData(config); + + // set connection manager + await wallet.setConnectionManager(config.getConnectionManager()); + return wallet; + } + + static async createWallet(config) { + + // validate config + if (config === undefined) throw new _MoneroError.default("Must provide config to create wallet"); + if (config.getSeed() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) throw new _MoneroError.default("Wallet may be initialized with a seed or keys but not both"); + if (config.getNetworkType() === undefined) throw new _MoneroError.default("Must provide a networkType: 'mainnet', 'testnet' or 'stagenet'"); + _MoneroNetworkType.default.validate(config.getNetworkType()); + if (config.getSaveCurrent() === true) throw new _MoneroError.default("Cannot save current wallet when creating full WASM wallet"); + if (config.getPath() === undefined) config.setPath(""); + if (config.getPath() && (await MoneroWalletFull.walletExists(config.getPath(), config.getFs()))) throw new _MoneroError.default("Wallet already exists: " + config.getPath()); + if (config.getPassword() === undefined) config.setPassword(""); + + // set server from connection manager if provided + if (config.getConnectionManager()) { + if (config.getServer()) throw new _MoneroError.default("Wallet can be created with a server or connection manager but not both"); + config.setServer(config.getConnectionManager().getConnection()); + } + + // create proxied or local wallet + let wallet; + if (config.getProxyToWorker() === undefined) config.setProxyToWorker(true); + if (config.getProxyToWorker()) { + let walletProxy = await MoneroWalletFullProxy.createWallet(config); + wallet = new MoneroWalletFull(undefined, undefined, undefined, undefined, undefined, undefined, walletProxy); + } else { + if (config.getSeed() !== undefined) { + if (config.getLanguage() !== undefined) throw new _MoneroError.default("Cannot provide language when creating wallet from seed"); + wallet = await MoneroWalletFull.createWalletFromSeed(config); + } else if (config.getPrivateSpendKey() !== undefined || config.getPrimaryAddress() !== undefined) { + if (config.getSeedOffset() !== undefined) throw new _MoneroError.default("Cannot provide seedOffset when creating wallet from keys"); + wallet = await MoneroWalletFull.createWalletFromKeys(config); + } else { + if (config.getSeedOffset() !== undefined) throw new _MoneroError.default("Cannot provide seedOffset when creating random wallet"); + if (config.getRestoreHeight() !== undefined) throw new _MoneroError.default("Cannot provide restoreHeight when creating random wallet"); + wallet = await MoneroWalletFull.createWalletRandom(config); + } + } + + // set connection manager + await wallet.setConnectionManager(config.getConnectionManager()); + return wallet; + } + + static async createWalletFromSeed(config) { + + // validate and normalize params + let daemonConnection = config.getServer(); + let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true; + if (config.getRestoreHeight() === undefined) config.setRestoreHeight(0); + if (config.getSeedOffset() === undefined) config.setSeedOffset(""); + + // load full wasm module + let module = await _LibraryUtils.default.loadWasmModule(); + + // create wallet in queue + let wallet = await module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // register fn informing if unauthorized reqs should be rejected + let rejectUnauthorizedFnId = _GenUtils.default.getUUID(); + _LibraryUtils.default.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => rejectUnauthorized); + + // create wallet in wasm which invokes callback when done + module.create_full_wallet(JSON.stringify(config.toJson()), rejectUnauthorizedFnId, async (cppAddress) => { + if (typeof cppAddress === "string") reject(new _MoneroError.default(cppAddress));else + resolve(new MoneroWalletFull(cppAddress, config.getPath(), config.getPassword(), config.getFs(), config.getServer() ? config.getServer().getRejectUnauthorized() : undefined, rejectUnauthorizedFnId)); + }); + }); + }); + + // save wallet + if (config.getPath()) await wallet.save(); + return wallet; + } + + static async createWalletFromKeys(config) { + + // validate and normalize params + _MoneroNetworkType.default.validate(config.getNetworkType()); + if (config.getPrimaryAddress() === undefined) config.setPrimaryAddress(""); + if (config.getPrivateViewKey() === undefined) config.setPrivateViewKey(""); + if (config.getPrivateSpendKey() === undefined) config.setPrivateSpendKey(""); + let daemonConnection = config.getServer(); + let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true; + if (config.getRestoreHeight() === undefined) config.setRestoreHeight(0); + if (config.getLanguage() === undefined) config.setLanguage("English"); + + // load full wasm module + let module = await _LibraryUtils.default.loadWasmModule(); + + // create wallet in queue + let wallet = await module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // register fn informing if unauthorized reqs should be rejected + let rejectUnauthorizedFnId = _GenUtils.default.getUUID(); + _LibraryUtils.default.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => rejectUnauthorized); + + // create wallet in wasm which invokes callback when done + module.create_full_wallet(JSON.stringify(config.toJson()), rejectUnauthorizedFnId, async (cppAddress) => { + if (typeof cppAddress === "string") reject(new _MoneroError.default(cppAddress));else + resolve(new MoneroWalletFull(cppAddress, config.getPath(), config.getPassword(), config.getFs(), config.getServer() ? config.getServer().getRejectUnauthorized() : undefined, rejectUnauthorizedFnId)); + }); + }); + }); + + // save wallet + if (config.getPath()) await wallet.save(); + return wallet; + } + + static async createWalletRandom(config) { + + // validate and normalize params + if (config.getLanguage() === undefined) config.setLanguage("English"); + let daemonConnection = config.getServer(); + let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true; + + // load wasm module + let module = await _LibraryUtils.default.loadWasmModule(); + + // create wallet in queue + let wallet = await module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // register fn informing if unauthorized reqs should be rejected + let rejectUnauthorizedFnId = _GenUtils.default.getUUID(); + _LibraryUtils.default.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => rejectUnauthorized); + + // create wallet in wasm which invokes callback when done + module.create_full_wallet(JSON.stringify(config.toJson()), rejectUnauthorizedFnId, async (cppAddress) => { + if (typeof cppAddress === "string") reject(new _MoneroError.default(cppAddress));else + resolve(new MoneroWalletFull(cppAddress, config.getPath(), config.getPassword(), config.getFs(), config.getServer() ? config.getServer().getRejectUnauthorized() : undefined, rejectUnauthorizedFnId)); + }); + }); + }); + + // save wallet + if (config.getPath()) await wallet.save(); + return wallet; + } + + static async getSeedLanguages() { + let module = await _LibraryUtils.default.loadWasmModule(); + return module.queueTask(async () => { + return JSON.parse(module.get_keys_wallet_seed_languages()).languages; + }); + } + + static getFs() { + if (!MoneroWalletFull.FS) MoneroWalletFull.FS = _fs.default.promises; + return MoneroWalletFull.FS; + } + + // ------------ WALLET METHODS SPECIFIC TO WASM IMPLEMENTATION -------------- + + // TODO: move these to MoneroWallet.ts, others can be unsupported + + /** + * Get the maximum height of the peers the wallet's daemon is connected to. + * + * @return {Promise} the maximum height of the peers the wallet's daemon is connected to + */ + async getDaemonMaxPeerHeight() { + if (this.getWalletProxy()) return this.getWalletProxy().getDaemonMaxPeerHeight(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // call wasm which invokes callback when done + this.module.get_daemon_max_peer_height(this.cppAddress, (resp) => { + resolve(resp); + }); + }); + }); + } + + /** + * Indicates if the wallet's daemon is synced with the network. + * + * @return {Promise} true if the daemon is synced with the network, false otherwise + */ + async isDaemonSynced() { + if (this.getWalletProxy()) return this.getWalletProxy().isDaemonSynced(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // call wasm which invokes callback when done + this.module.is_daemon_synced(this.cppAddress, (resp) => { + resolve(resp); + }); + }); + }); + } + + /** + * Indicates if the wallet is synced with the daemon. + * + * @return {Promise} true if the wallet is synced with the daemon, false otherwise + */ + async isSynced() { + if (this.getWalletProxy()) return this.getWalletProxy().isSynced(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.is_synced(this.cppAddress, (resp) => { + resolve(resp); + }); + }); + }); + } + + /** + * Get the wallet's network type (mainnet, testnet, or stagenet). + * + * @return {Promise} the wallet's network type + */ + async getNetworkType() { + if (this.getWalletProxy()) return this.getWalletProxy().getNetworkType(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.get_network_type(this.cppAddress); + }); + } + + /** + * Get the height of the first block that the wallet scans. + * + * @return {Promise} the height of the first block that the wallet scans + */ + async getRestoreHeight() { + if (this.getWalletProxy()) return this.getWalletProxy().getRestoreHeight(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.get_restore_height(this.cppAddress); + }); + } + + /** + * Set the height of the first block that the wallet scans. + * + * @param {number} restoreHeight - height of the first block that the wallet scans + * @return {Promise} + */ + async setRestoreHeight(restoreHeight) { + if (this.getWalletProxy()) return this.getWalletProxy().setRestoreHeight(restoreHeight); + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.set_restore_height(this.cppAddress, restoreHeight); + }); + } + + /** + * Move the wallet from its current path to the given path. + * + * @param {string} path - the wallet's destination path + * @return {Promise} + */ + async moveTo(path) { + if (this.getWalletProxy()) return this.getWalletProxy().moveTo(path); + return MoneroWalletFull.moveTo(path, this); + } + + // -------------------------- COMMON WALLET METHODS ------------------------- + + async addListener(listener) { + if (this.getWalletProxy()) return this.getWalletProxy().addListener(listener); + await super.addListener(listener); + await this.refreshListening(); + } + + async removeListener(listener) { + if (this.getWalletProxy()) return this.getWalletProxy().removeListener(listener); + await super.removeListener(listener); + await this.refreshListening(); + } + + getListeners() { + if (this.getWalletProxy()) return this.getWalletProxy().getListeners(); + return super.getListeners(); + } + + async setDaemonConnection(uriOrConnection) { + if (this.getWalletProxy()) return this.getWalletProxy().setDaemonConnection(uriOrConnection); + + // normalize connection + let connection = !uriOrConnection ? undefined : uriOrConnection instanceof _MoneroRpcConnection.default ? uriOrConnection : new _MoneroRpcConnection.default(uriOrConnection); + let uri = connection && connection.getUri() ? connection.getUri() : ""; + let username = connection && connection.getUsername() ? connection.getUsername() : ""; + let password = connection && connection.getPassword() ? connection.getPassword() : ""; + let proxyUri = connection && connection.getProxyUri() ? connection.getProxyUri() : ""; + let rejectUnauthorized = connection ? connection.getRejectUnauthorized() : undefined; + this.rejectUnauthorized = rejectUnauthorized; // persist locally + + // set connection in queue + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.set_daemon_connection(this.cppAddress, uri, username, password, proxyUri, (resp) => { + resolve(); + }); + }); + }); + } + + async getDaemonConnection() { + if (this.getWalletProxy()) return this.getWalletProxy().getDaemonConnection(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + let connectionContainerStr = this.module.get_daemon_connection(this.cppAddress); + if (!connectionContainerStr) resolve(undefined);else + { + let jsonConnection = JSON.parse(connectionContainerStr); + resolve(new _MoneroRpcConnection.default({ uri: jsonConnection.uri, username: jsonConnection.username, password: jsonConnection.password, proxyUri: jsonConnection.proxyUri, rejectUnauthorized: this.rejectUnauthorized })); + } + }); + }); + } + + async isConnectedToDaemon() { + if (this.getWalletProxy()) return this.getWalletProxy().isConnectedToDaemon(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.is_connected_to_daemon(this.cppAddress, (resp) => { + resolve(resp); + }); + }); + }); + } + + async getVersion() { + if (this.getWalletProxy()) return this.getWalletProxy().getVersion(); + throw new _MoneroError.default("Not implemented"); + } + + async getPath() { + if (this.getWalletProxy()) return this.getWalletProxy().getPath(); + return this.path; + } + + async getIntegratedAddress(standardAddress, paymentId) { + if (this.getWalletProxy()) return this.getWalletProxy().getIntegratedAddress(standardAddress, paymentId); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { + let result = this.module.get_integrated_address(this.cppAddress, standardAddress ? standardAddress : "", paymentId ? paymentId : ""); + if (result.charAt(0) !== '{') throw new _MoneroError.default(result); + return new _MoneroIntegratedAddress.default(JSON.parse(result)); + } catch (err) { + if (err.message.includes("Invalid payment ID")) throw new _MoneroError.default("Invalid payment ID: " + paymentId); + throw new _MoneroError.default(err.message); + } + }); + } + + async decodeIntegratedAddress(integratedAddress) { + if (this.getWalletProxy()) return this.getWalletProxy().decodeIntegratedAddress(integratedAddress); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { + let result = this.module.decode_integrated_address(this.cppAddress, integratedAddress); + if (result.charAt(0) !== '{') throw new _MoneroError.default(result); + return new _MoneroIntegratedAddress.default(JSON.parse(result)); + } catch (err) { + throw new _MoneroError.default(err.message); + } + }); + } + + async getHeight() { + if (this.getWalletProxy()) return this.getWalletProxy().getHeight(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_height(this.cppAddress, (resp) => { + resolve(resp); + }); + }); + }); + } + + async getDaemonHeight() { + if (this.getWalletProxy()) return this.getWalletProxy().getDaemonHeight(); + if (!(await this.isConnectedToDaemon())) throw new _MoneroError.default("Wallet is not connected to daemon"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_daemon_height(this.cppAddress, (resp) => { + resolve(resp); + }); + }); + }); + } + + async getHeightByDate(year, month, day) { + if (this.getWalletProxy()) return this.getWalletProxy().getHeightByDate(year, month, day); + if (!(await this.isConnectedToDaemon())) throw new _MoneroError.default("Wallet is not connected to daemon"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_height_by_date(this.cppAddress, year, month, day, (resp) => { + if (typeof resp === "string") reject(new _MoneroError.default(resp));else + resolve(resp); + }); + }); + }); + } + + /** + * Synchronize the wallet with the daemon as a one-time synchronous process. + * + * @param {MoneroWalletListener|number} [listenerOrStartHeight] - listener xor start height (defaults to no sync listener, the last synced block) + * @param {number} [startHeight] - startHeight if not given in first arg (defaults to last synced block) + * @param {boolean} [allowConcurrentCalls] - allow other wallet methods to be processed simultaneously during sync (default false)

WARNING: enabling this option will crash wallet execution if another call makes a simultaneous network request. TODO: possible to sync wasm network requests in http_client_wasm.cpp? + */ + async sync(listenerOrStartHeight, startHeight, allowConcurrentCalls = false) { + if (this.getWalletProxy()) return this.getWalletProxy().sync(listenerOrStartHeight, startHeight, allowConcurrentCalls); + if (!(await this.isConnectedToDaemon())) throw new _MoneroError.default("Wallet is not connected to daemon"); + + // normalize params + startHeight = listenerOrStartHeight === undefined || listenerOrStartHeight instanceof _MoneroWalletListener.default ? startHeight : listenerOrStartHeight; + let listener = listenerOrStartHeight instanceof _MoneroWalletListener.default ? listenerOrStartHeight : undefined; + if (startHeight === undefined) startHeight = Math.max(await this.getHeight(), await this.getRestoreHeight()); + + // register listener if given + if (listener) await this.addListener(listener); + + // sync wallet + let err; + let result; + try { + let that = this; + result = await (allowConcurrentCalls ? syncWasm() : this.module.queueTask(async () => syncWasm())); + function syncWasm() { + that.assertNotClosed(); + return new Promise((resolve, reject) => { + + // sync wallet in wasm which invokes callback when done + that.module.sync(that.cppAddress, startHeight, async (resp) => { + if (resp.charAt(0) !== '{') reject(new _MoneroError.default(resp));else + { + let respJson = JSON.parse(resp); + resolve(new _MoneroSyncResult.default(respJson.numBlocksFetched, respJson.receivedMoney)); + } + }); + }); + } + } catch (e) { + err = e; + } + + // unregister listener + if (listener) await this.removeListener(listener); + + // throw error or return + if (err) throw err; + return result; + } + + async startSyncing(syncPeriodInMs) { + if (this.getWalletProxy()) return this.getWalletProxy().startSyncing(syncPeriodInMs); + if (!(await this.isConnectedToDaemon())) throw new _MoneroError.default("Wallet is not connected to daemon"); + this.syncPeriodInMs = syncPeriodInMs === undefined ? MoneroWalletFull.DEFAULT_SYNC_PERIOD_IN_MS : syncPeriodInMs; + if (!this.syncLooper) this.syncLooper = new _TaskLooper.default(async () => await this.backgroundSync()); + this.syncLooper.start(this.syncPeriodInMs); + } + + async stopSyncing() { + if (this.getWalletProxy()) return this.getWalletProxy().stopSyncing(); + this.assertNotClosed(); + if (this.syncLooper) this.syncLooper.stop(); + this.module.stop_syncing(this.cppAddress); // task is not queued so wallet stops immediately + } + + async scanTxs(txHashes) { + if (this.getWalletProxy()) return this.getWalletProxy().scanTxs(txHashes); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.scan_txs(this.cppAddress, JSON.stringify({ txHashes: txHashes }), (err) => { + if (err) reject(new _MoneroError.default(err));else + resolve(); + }); + }); + }); + } + + async rescanSpent() { + if (this.getWalletProxy()) return this.getWalletProxy().rescanSpent(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.rescan_spent(this.cppAddress, () => resolve()); + }); + }); + } + + async rescanBlockchain() { + if (this.getWalletProxy()) return this.getWalletProxy().rescanBlockchain(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.rescan_blockchain(this.cppAddress, () => resolve()); + }); + }); + } + + async getBalance(accountIdx, subaddressIdx) { + if (this.getWalletProxy()) return this.getWalletProxy().getBalance(accountIdx, subaddressIdx); + return this.module.queueTask(async () => { + this.assertNotClosed(); + + // get balance encoded in json string + let balanceStr; + if (accountIdx === undefined) { + (0, _assert.default)(subaddressIdx === undefined, "Subaddress index must be undefined if account index is undefined"); + balanceStr = this.module.get_balance_wallet(this.cppAddress); + } else if (subaddressIdx === undefined) { + balanceStr = this.module.get_balance_account(this.cppAddress, accountIdx); + } else { + balanceStr = this.module.get_balance_subaddress(this.cppAddress, accountIdx, subaddressIdx); + } + + // parse json string to bigint + return BigInt(JSON.parse(_GenUtils.default.stringifyBigInts(balanceStr)).balance); + }); + } + + async getUnlockedBalance(accountIdx, subaddressIdx) { + if (this.getWalletProxy()) return this.getWalletProxy().getUnlockedBalance(accountIdx, subaddressIdx); + return this.module.queueTask(async () => { + this.assertNotClosed(); + + // get balance encoded in json string + let unlockedBalanceStr; + if (accountIdx === undefined) { + (0, _assert.default)(subaddressIdx === undefined, "Subaddress index must be undefined if account index is undefined"); + unlockedBalanceStr = this.module.get_unlocked_balance_wallet(this.cppAddress); + } else if (subaddressIdx === undefined) { + unlockedBalanceStr = this.module.get_unlocked_balance_account(this.cppAddress, accountIdx); + } else { + unlockedBalanceStr = this.module.get_unlocked_balance_subaddress(this.cppAddress, accountIdx, subaddressIdx); + } + + // parse json string to bigint + return BigInt(JSON.parse(_GenUtils.default.stringifyBigInts(unlockedBalanceStr)).unlockedBalance); + }); + } + + async getAccounts(includeSubaddresses, tag) { + if (this.getWalletProxy()) return this.getWalletProxy().getAccounts(includeSubaddresses, tag); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let accountsStr = this.module.get_accounts(this.cppAddress, includeSubaddresses ? true : false, tag ? tag : ""); + let accounts = []; + for (let accountJson of JSON.parse(_GenUtils.default.stringifyBigInts(accountsStr)).accounts) { + accounts.push(MoneroWalletFull.sanitizeAccount(new _MoneroAccount.default(accountJson))); + } + return accounts; + }); + } + + async getAccount(accountIdx, includeSubaddresses) { + if (this.getWalletProxy()) return this.getWalletProxy().getAccount(accountIdx, includeSubaddresses); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let accountStr = this.module.get_account(this.cppAddress, accountIdx, includeSubaddresses ? true : false); + let accountJson = JSON.parse(_GenUtils.default.stringifyBigInts(accountStr)); + return MoneroWalletFull.sanitizeAccount(new _MoneroAccount.default(accountJson)); + }); + + } + + async createAccount(label) { + if (this.getWalletProxy()) return this.getWalletProxy().createAccount(label); + if (label === undefined) label = ""; + return this.module.queueTask(async () => { + this.assertNotClosed(); + let accountStr = this.module.create_account(this.cppAddress, label); + let accountJson = JSON.parse(_GenUtils.default.stringifyBigInts(accountStr)); + return MoneroWalletFull.sanitizeAccount(new _MoneroAccount.default(accountJson)); + }); + } + + async getSubaddresses(accountIdx, subaddressIndices) { + if (this.getWalletProxy()) return this.getWalletProxy().getSubaddresses(accountIdx, subaddressIndices); + let args = { accountIdx: accountIdx, subaddressIndices: subaddressIndices === undefined ? [] : _GenUtils.default.listify(subaddressIndices) }; + return this.module.queueTask(async () => { + this.assertNotClosed(); + let subaddressesJson = JSON.parse(_GenUtils.default.stringifyBigInts(this.module.get_subaddresses(this.cppAddress, JSON.stringify(args)))).subaddresses; + let subaddresses = []; + for (let subaddressJson of subaddressesJson) subaddresses.push(_MoneroWalletKeys.MoneroWalletKeys.sanitizeSubaddress(new _MoneroSubaddress.default(subaddressJson))); + return subaddresses; + }); + } + + async createSubaddress(accountIdx, label) { + if (this.getWalletProxy()) return this.getWalletProxy().createSubaddress(accountIdx, label); + if (label === undefined) label = ""; + return this.module.queueTask(async () => { + this.assertNotClosed(); + let subaddressStr = this.module.create_subaddress(this.cppAddress, accountIdx, label); + let subaddressJson = JSON.parse(_GenUtils.default.stringifyBigInts(subaddressStr)); + return _MoneroWalletKeys.MoneroWalletKeys.sanitizeSubaddress(new _MoneroSubaddress.default(subaddressJson)); + }); + } + + async setSubaddressLabel(accountIdx, subaddressIdx, label) { + if (this.getWalletProxy()) return this.getWalletProxy().setSubaddressLabel(accountIdx, subaddressIdx, label); + if (label === undefined) label = ""; + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.set_subaddress_label(this.cppAddress, accountIdx, subaddressIdx, label); + }); + } + + async getTxs(query) { + if (this.getWalletProxy()) return this.getWalletProxy().getTxs(query); + + // copy and normalize query up to block + const queryNormalized = query = _MoneroWallet.default.normalizeTxQuery(query); + + // schedule task + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // call wasm which invokes callback + this.module.get_txs(this.cppAddress, JSON.stringify(queryNormalized.getBlock().toJson()), (blocksJsonStr) => { + + // check for error + if (blocksJsonStr.charAt(0) !== '{') { + reject(new _MoneroError.default(blocksJsonStr)); + return; + } + + // resolve with deserialized txs + try { + resolve(MoneroWalletFull.deserializeTxs(queryNormalized, blocksJsonStr)); + } catch (err) { + reject(err); + } + }); + }); + }); + } + + async getTransfers(query) { + if (this.getWalletProxy()) return this.getWalletProxy().getTransfers(query); + + // copy and normalize query up to block + const queryNormalized = _MoneroWallet.default.normalizeTransferQuery(query); + + // return promise which resolves on callback + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // call wasm which invokes callback + this.module.get_transfers(this.cppAddress, JSON.stringify(queryNormalized.getTxQuery().getBlock().toJson()), (blocksJsonStr) => { + + // check for error + if (blocksJsonStr.charAt(0) !== '{') { + reject(new _MoneroError.default(blocksJsonStr)); + return; + } + + // resolve with deserialized transfers + try { + resolve(MoneroWalletFull.deserializeTransfers(queryNormalized, blocksJsonStr)); + } catch (err) { + reject(err); + } + }); + }); + }); + } + + async getOutputs(query) { + if (this.getWalletProxy()) return this.getWalletProxy().getOutputs(query); + + // copy and normalize query up to block + const queryNormalized = _MoneroWallet.default.normalizeOutputQuery(query); + + // return promise which resolves on callback + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // call wasm which invokes callback + this.module.get_outputs(this.cppAddress, JSON.stringify(queryNormalized.getTxQuery().getBlock().toJson()), (blocksJsonStr) => { + + // check for error + if (blocksJsonStr.charAt(0) !== '{') { + reject(new _MoneroError.default(blocksJsonStr)); + return; + } + + // resolve with deserialized outputs + try { + resolve(MoneroWalletFull.deserializeOutputs(queryNormalized, blocksJsonStr)); + } catch (err) { + reject(err); + } + }); + }); + }); + } + + async exportOutputs(all = false) { + if (this.getWalletProxy()) return this.getWalletProxy().exportOutputs(all); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.export_outputs(this.cppAddress, all, (outputsHex) => resolve(outputsHex)); + }); + }); + } + + async importOutputs(outputsHex) { + if (this.getWalletProxy()) return this.getWalletProxy().importOutputs(outputsHex); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.import_outputs(this.cppAddress, outputsHex, (numImported) => resolve(numImported)); + }); + }); + } + + async exportKeyImages(all = false) { + if (this.getWalletProxy()) return this.getWalletProxy().exportKeyImages(all); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.export_key_images(this.cppAddress, all, (keyImagesStr) => { + if (keyImagesStr.charAt(0) !== '{') reject(new _MoneroError.default(keyImagesStr)); // json expected, else error + else { + let keyImages = []; + for (let keyImageJson of JSON.parse(_GenUtils.default.stringifyBigInts(keyImagesStr)).keyImages) keyImages.push(new _MoneroKeyImage.default(keyImageJson)); + resolve(keyImages); + } + }); + }); + }); + } + + async importKeyImages(keyImages) { + if (this.getWalletProxy()) return this.getWalletProxy().importKeyImages(keyImages); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.import_key_images(this.cppAddress, JSON.stringify({ keyImages: keyImages.map((keyImage) => keyImage.toJson()) }), (keyImageImportResultStr) => { + if (keyImageImportResultStr.charAt(0) !== '{') reject(new _MoneroError.default(keyImageImportResultStr)); // json expected, else error + else resolve(new _MoneroKeyImageImportResult.default(JSON.parse(_GenUtils.default.stringifyBigInts(keyImageImportResultStr)))); + }); + }); + }); + } + + async getNewKeyImagesFromLastImport() { + if (this.getWalletProxy()) return this.getWalletProxy().getNewKeyImagesFromLastImport(); + throw new _MoneroError.default("Not implemented"); + } + + async freezeOutput(keyImage) { + if (this.getWalletProxy()) return this.getWalletProxy().freezeOutput(keyImage); + if (!keyImage) throw new _MoneroError.default("Must specify key image to freeze"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.freeze_output(this.cppAddress, keyImage, () => resolve()); + }); + }); + } + + async thawOutput(keyImage) { + if (this.getWalletProxy()) return this.getWalletProxy().thawOutput(keyImage); + if (!keyImage) throw new _MoneroError.default("Must specify key image to thaw"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.thaw_output(this.cppAddress, keyImage, () => resolve()); + }); + }); + } + + async isOutputFrozen(keyImage) { + if (this.getWalletProxy()) return this.getWalletProxy().isOutputFrozen(keyImage); + if (!keyImage) throw new _MoneroError.default("Must specify key image to check if frozen"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.is_output_frozen(this.cppAddress, keyImage, (result) => resolve(result)); + }); + }); + } + + async getDefaultFeePriority() { + if (this.getWalletProxy()) return this.getWalletProxy().getDefaultFeePriority(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_default_fee_priority(this.cppAddress, (result) => resolve(result)); + }); + }); + } + + async createTxs(config) { + if (this.getWalletProxy()) return this.getWalletProxy().createTxs(config); + + // validate, copy, and normalize config + const configNormalized = _MoneroWallet.default.normalizeCreateTxsConfig(config); + if (configNormalized.getCanSplit() === undefined) configNormalized.setCanSplit(true); + + // create txs in queue + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // create txs in wasm which invokes callback when done + this.module.create_txs(this.cppAddress, JSON.stringify(configNormalized.toJson()), (txSetJsonStr) => { + if (txSetJsonStr.charAt(0) !== '{') reject(new _MoneroError.default(txSetJsonStr)); // json expected, else error + else resolve(new _MoneroTxSet.default(JSON.parse(_GenUtils.default.stringifyBigInts(txSetJsonStr))).getTxs()); + }); + }); + }); + } + + async sweepOutput(config) { + if (this.getWalletProxy()) return this.getWalletProxy().sweepOutput(config); + + // normalize and validate config + const configNormalized = _MoneroWallet.default.normalizeSweepOutputConfig(config); + + // sweep output in queue + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // sweep output in wasm which invokes callback when done + this.module.sweep_output(this.cppAddress, JSON.stringify(configNormalized.toJson()), (txSetJsonStr) => { + if (txSetJsonStr.charAt(0) !== '{') reject(new _MoneroError.default(txSetJsonStr)); // json expected, else error + else resolve(new _MoneroTxSet.default(JSON.parse(_GenUtils.default.stringifyBigInts(txSetJsonStr))).getTxs()[0]); + }); + }); + }); + } + + async sweepUnlocked(config) { + if (this.getWalletProxy()) return this.getWalletProxy().sweepUnlocked(config); + + // validate and normalize config + const configNormalized = _MoneroWallet.default.normalizeSweepUnlockedConfig(config); + + // sweep unlocked in queue + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // sweep unlocked in wasm which invokes callback when done + this.module.sweep_unlocked(this.cppAddress, JSON.stringify(configNormalized.toJson()), (txSetsJson) => { + if (txSetsJson.charAt(0) !== '{') reject(new _MoneroError.default(txSetsJson)); // json expected, else error + else { + let txSets = []; + for (let txSetJson of JSON.parse(_GenUtils.default.stringifyBigInts(txSetsJson)).txSets) txSets.push(new _MoneroTxSet.default(txSetJson)); + let txs = []; + for (let txSet of txSets) for (let tx of txSet.getTxs()) txs.push(tx); + resolve(txs); + } + }); + }); + }); + } + + async sweepDust(relay) { + if (this.getWalletProxy()) return this.getWalletProxy().sweepDust(relay); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // call wasm which invokes callback when done + this.module.sweep_dust(this.cppAddress, relay, (txSetJsonStr) => { + if (txSetJsonStr.charAt(0) !== '{') reject(new _MoneroError.default(txSetJsonStr)); // json expected, else error + else { + let txSet = new _MoneroTxSet.default(JSON.parse(_GenUtils.default.stringifyBigInts(txSetJsonStr))); + if (txSet.getTxs() === undefined) txSet.setTxs([]); + resolve(txSet.getTxs()); + } + }); + }); + }); + } + + async relayTxs(txsOrMetadatas) { + if (this.getWalletProxy()) return this.getWalletProxy().relayTxs(txsOrMetadatas); + (0, _assert.default)(Array.isArray(txsOrMetadatas), "Must provide an array of txs or their metadata to relay"); + let txMetadatas = []; + for (let txOrMetadata of txsOrMetadatas) txMetadatas.push(txOrMetadata instanceof _MoneroTxWallet.default ? txOrMetadata.getMetadata() : txOrMetadata); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.relay_txs(this.cppAddress, JSON.stringify({ txMetadatas: txMetadatas }), (txHashesJson) => { + if (txHashesJson.charAt(0) !== '{') reject(new _MoneroError.default(txHashesJson));else + resolve(JSON.parse(txHashesJson).txHashes); + }); + }); + }); + } + + async describeTxSet(txSet) { + if (this.getWalletProxy()) return this.getWalletProxy().describeTxSet(txSet); + return this.module.queueTask(async () => { + this.assertNotClosed(); + txSet = new _MoneroTxSet.default({ unsignedTxHex: txSet.getUnsignedTxHex(), signedTxHex: txSet.getSignedTxHex(), multisigTxHex: txSet.getMultisigTxHex() }); + try {return new _MoneroTxSet.default(JSON.parse(_GenUtils.default.stringifyBigInts(this.module.describe_tx_set(this.cppAddress, JSON.stringify(txSet.toJson())))));} + catch (err) {throw new _MoneroError.default(this.module.get_exception_message(err));} + }); + } + + async signTxs(unsignedTxHex) { + if (this.getWalletProxy()) return this.getWalletProxy().signTxs(unsignedTxHex); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try {return new _MoneroTxSet.default(JSON.parse(_GenUtils.default.stringifyBigInts(this.module.sign_txs(this.cppAddress, unsignedTxHex))));} + catch (err) {throw new _MoneroError.default(this.module.get_exception_message(err));} + }); + } + + async submitTxs(signedTxHex) { + if (this.getWalletProxy()) return this.getWalletProxy().submitTxs(signedTxHex); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.submit_txs(this.cppAddress, signedTxHex, (resp) => { + if (resp.charAt(0) !== '{') reject(new _MoneroError.default(resp));else + resolve(JSON.parse(resp).txHashes); + }); + }); + }); + } + + async signMessage(message, signatureType = _MoneroMessageSignatureType.default.SIGN_WITH_SPEND_KEY, accountIdx = 0, subaddressIdx = 0) { + if (this.getWalletProxy()) return this.getWalletProxy().signMessage(message, signatureType, accountIdx, subaddressIdx); + + // assign defaults + signatureType = signatureType || _MoneroMessageSignatureType.default.SIGN_WITH_SPEND_KEY; + accountIdx = accountIdx || 0; + subaddressIdx = subaddressIdx || 0; + + // queue task to sign message + return this.module.queueTask(async () => { + this.assertNotClosed(); + try {return this.module.sign_message(this.cppAddress, message, signatureType === _MoneroMessageSignatureType.default.SIGN_WITH_SPEND_KEY ? 0 : 1, accountIdx, subaddressIdx);} + catch (err) {throw new _MoneroError.default(this.module.get_exception_message(err));} + }); + } + + async verifyMessage(message, address, signature) { + if (this.getWalletProxy()) return this.getWalletProxy().verifyMessage(message, address, signature); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let result; + try { + result = JSON.parse(this.module.verify_message(this.cppAddress, message, address, signature)); + } catch (err) { + result = { isGood: false }; + } + return new _MoneroMessageSignatureResult.default(result.isGood ? + { isGood: result.isGood, isOld: result.isOld, signatureType: result.signatureType === "spend" ? _MoneroMessageSignatureType.default.SIGN_WITH_SPEND_KEY : _MoneroMessageSignatureType.default.SIGN_WITH_VIEW_KEY, version: result.version } : + { isGood: false } + ); + }); + } + + async getTxKey(txHash) { + if (this.getWalletProxy()) return this.getWalletProxy().getTxKey(txHash); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try {return this.module.get_tx_key(this.cppAddress, txHash);} + catch (err) {throw new _MoneroError.default(this.module.get_exception_message(err));} + }); + } + + async checkTxKey(txHash, txKey, address) { + if (this.getWalletProxy()) return this.getWalletProxy().checkTxKey(txHash, txKey, address); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.check_tx_key(this.cppAddress, txHash, txKey, address, (respJsonStr) => { + if (respJsonStr.charAt(0) !== '{') reject(new _MoneroError.default(respJsonStr));else + resolve(new _MoneroCheckTx.default(JSON.parse(_GenUtils.default.stringifyBigInts(respJsonStr)))); + }); + }); + }); + } + + async getTxProof(txHash, address, message) { + if (this.getWalletProxy()) return this.getWalletProxy().getTxProof(txHash, address, message); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_tx_proof(this.cppAddress, txHash || "", address || "", message || "", (signature) => { + let errorKey = "error: "; + if (signature.indexOf(errorKey) === 0) reject(new _MoneroError.default(signature.substring(errorKey.length)));else + resolve(signature); + }); + }); + }); + } + + async checkTxProof(txHash, address, message, signature) { + if (this.getWalletProxy()) return this.getWalletProxy().checkTxProof(txHash, address, message, signature); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.check_tx_proof(this.cppAddress, txHash || "", address || "", message || "", signature || "", (respJsonStr) => { + if (respJsonStr.charAt(0) !== '{') reject(new _MoneroError.default(respJsonStr));else + resolve(new _MoneroCheckTx.default(JSON.parse(_GenUtils.default.stringifyBigInts(respJsonStr)))); + }); + }); + }); + } + + async getSpendProof(txHash, message) { + if (this.getWalletProxy()) return this.getWalletProxy().getSpendProof(txHash, message); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_spend_proof(this.cppAddress, txHash || "", message || "", (signature) => { + let errorKey = "error: "; + if (signature.indexOf(errorKey) === 0) reject(new _MoneroError.default(signature.substring(errorKey.length)));else + resolve(signature); + }); + }); + }); + } + + async checkSpendProof(txHash, message, signature) { + if (this.getWalletProxy()) return this.getWalletProxy().checkSpendProof(txHash, message, signature); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.check_spend_proof(this.cppAddress, txHash || "", message || "", signature || "", (resp) => { + typeof resp === "string" ? reject(new _MoneroError.default(resp)) : resolve(resp); + }); + }); + }); + } + + async getReserveProofWallet(message) { + if (this.getWalletProxy()) return this.getWalletProxy().getReserveProofWallet(message); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_reserve_proof_wallet(this.cppAddress, message, (signature) => { + let errorKey = "error: "; + if (signature.indexOf(errorKey) === 0) reject(new _MoneroError.default(signature.substring(errorKey.length), -1));else + resolve(signature); + }); + }); + }); + } + + async getReserveProofAccount(accountIdx, amount, message) { + if (this.getWalletProxy()) return this.getWalletProxy().getReserveProofAccount(accountIdx, amount, message); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_reserve_proof_account(this.cppAddress, accountIdx, amount.toString(), message, (signature) => { + let errorKey = "error: "; + if (signature.indexOf(errorKey) === 0) reject(new _MoneroError.default(signature.substring(errorKey.length), -1));else + resolve(signature); + }); + }); + }); + } + + async checkReserveProof(address, message, signature) { + if (this.getWalletProxy()) return this.getWalletProxy().checkReserveProof(address, message, signature); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.check_reserve_proof(this.cppAddress, address, message, signature, (respJsonStr) => { + if (respJsonStr.charAt(0) !== '{') reject(new _MoneroError.default(respJsonStr, -1));else + resolve(new _MoneroCheckReserve.default(JSON.parse(_GenUtils.default.stringifyBigInts(respJsonStr)))); + }); + }); + }); + } + + async getTxNotes(txHashes) { + if (this.getWalletProxy()) return this.getWalletProxy().getTxNotes(txHashes); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try {return JSON.parse(this.module.get_tx_notes(this.cppAddress, JSON.stringify({ txHashes: txHashes }))).txNotes;} + catch (err) {throw new _MoneroError.default(this.module.get_exception_message(err));} + }); + } + + async setTxNotes(txHashes, notes) { + if (this.getWalletProxy()) return this.getWalletProxy().setTxNotes(txHashes, notes); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try {this.module.set_tx_notes(this.cppAddress, JSON.stringify({ txHashes: txHashes, txNotes: notes }));} + catch (err) {throw new _MoneroError.default(this.module.get_exception_message(err));} + }); + } + + async getAddressBookEntries(entryIndices) { + if (this.getWalletProxy()) return this.getWalletProxy().getAddressBookEntries(entryIndices); + if (!entryIndices) entryIndices = []; + return this.module.queueTask(async () => { + this.assertNotClosed(); + let entries = []; + for (let entryJson of JSON.parse(this.module.get_address_book_entries(this.cppAddress, JSON.stringify({ entryIndices: entryIndices }))).entries) { + entries.push(new _MoneroAddressBookEntry.default(entryJson)); + } + return entries; + }); + } + + async addAddressBookEntry(address, description) { + if (this.getWalletProxy()) return this.getWalletProxy().addAddressBookEntry(address, description); + if (!address) address = ""; + if (!description) description = ""; + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.add_address_book_entry(this.cppAddress, address, description); + }); + } + + async editAddressBookEntry(index, setAddress, address, setDescription, description) { + if (this.getWalletProxy()) return this.getWalletProxy().editAddressBookEntry(index, setAddress, address, setDescription, description); + if (!setAddress) setAddress = false; + if (!address) address = ""; + if (!setDescription) setDescription = false; + if (!description) description = ""; + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.edit_address_book_entry(this.cppAddress, index, setAddress, address, setDescription, description); + }); + } + + async deleteAddressBookEntry(entryIdx) { + if (this.getWalletProxy()) return this.getWalletProxy().deleteAddressBookEntry(entryIdx); + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.delete_address_book_entry(this.cppAddress, entryIdx); + }); + } + + async tagAccounts(tag, accountIndices) { + if (this.getWalletProxy()) return this.getWalletProxy().tagAccounts(tag, accountIndices); + if (!tag) tag = ""; + if (!accountIndices) accountIndices = []; + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.tag_accounts(this.cppAddress, JSON.stringify({ tag: tag, accountIndices: accountIndices })); + }); + } + + async untagAccounts(accountIndices) { + if (this.getWalletProxy()) return this.getWalletProxy().untagAccounts(accountIndices); + if (!accountIndices) accountIndices = []; + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.tag_accounts(this.cppAddress, JSON.stringify({ accountIndices: accountIndices })); + }); + } + + async getAccountTags() { + if (this.getWalletProxy()) return this.getWalletProxy().getAccountTags(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let accountTags = []; + for (let accountTagJson of JSON.parse(this.module.get_account_tags(this.cppAddress)).accountTags) accountTags.push(new _MoneroAccountTag.default(accountTagJson)); + return accountTags; + }); + } + + async setAccountTagLabel(tag, label) { + if (this.getWalletProxy()) return this.getWalletProxy().setAccountTagLabel(tag, label); + if (!tag) tag = ""; + if (!label) label = ""; + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.set_account_tag_label(this.cppAddress, tag, label); + }); + } + + async getPaymentUri(config) { + if (this.getWalletProxy()) return this.getWalletProxy().getPaymentUri(config); + config = _MoneroWallet.default.normalizeCreateTxsConfig(config); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { + return this.module.get_payment_uri(this.cppAddress, JSON.stringify(config.toJson())); + } catch (err) { + throw new _MoneroError.default("Cannot make URI from supplied parameters"); + } + }); + } + + async parsePaymentUri(uri) { + if (this.getWalletProxy()) return this.getWalletProxy().parsePaymentUri(uri); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { + return new _MoneroTxConfig.default(JSON.parse(_GenUtils.default.stringifyBigInts(this.module.parse_payment_uri(this.cppAddress, uri)))); + } catch (err) { + throw new _MoneroError.default(err.message); + } + }); + } + + async getAttribute(key) { + if (this.getWalletProxy()) return this.getWalletProxy().getAttribute(key); + this.assertNotClosed(); + (0, _assert.default)(typeof key === "string", "Attribute key must be a string"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let value = this.module.get_attribute(this.cppAddress, key); + return value === "" ? null : value; + }); + } + + async setAttribute(key, val) { + if (this.getWalletProxy()) return this.getWalletProxy().setAttribute(key, val); + this.assertNotClosed(); + (0, _assert.default)(typeof key === "string", "Attribute key must be a string"); + (0, _assert.default)(typeof val === "string", "Attribute value must be a string"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.set_attribute(this.cppAddress, key, val); + }); + } + + async startMining(numThreads, backgroundMining, ignoreBattery) { + if (this.getWalletProxy()) return this.getWalletProxy().startMining(numThreads, backgroundMining, ignoreBattery); + this.assertNotClosed(); + let daemon = await _MoneroDaemonRpc.default.connectToDaemonRpc(await this.getDaemonConnection()); + await daemon.startMining(await this.getPrimaryAddress(), numThreads, backgroundMining, ignoreBattery); + } + + async stopMining() { + if (this.getWalletProxy()) return this.getWalletProxy().stopMining(); + this.assertNotClosed(); + let daemon = await _MoneroDaemonRpc.default.connectToDaemonRpc(await this.getDaemonConnection()); + await daemon.stopMining(); + } + + async isMultisigImportNeeded() { + if (this.getWalletProxy()) return this.getWalletProxy().isMultisigImportNeeded(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.is_multisig_import_needed(this.cppAddress); + }); + } + + async isMultisig() { + if (this.getWalletProxy()) return this.getWalletProxy().isMultisig(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.is_multisig(this.cppAddress); + }); + } + + async getMultisigInfo() { + if (this.getWalletProxy()) return this.getWalletProxy().getMultisigInfo(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new _MoneroMultisigInfo.default(JSON.parse(this.module.get_multisig_info(this.cppAddress))); + }); + } + + async prepareMultisig() { + if (this.getWalletProxy()) return this.getWalletProxy().prepareMultisig(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.prepare_multisig(this.cppAddress); + }); + } + + async makeMultisig(multisigHexes, threshold, password) { + if (this.getWalletProxy()) return this.getWalletProxy().makeMultisig(multisigHexes, threshold, password); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.make_multisig(this.cppAddress, JSON.stringify({ multisigHexes: multisigHexes, threshold: threshold, password: password }), (resp) => { + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) reject(new _MoneroError.default(resp.substring(errorKey.length)));else + resolve(resp); + }); + }); + }); + } + + async exchangeMultisigKeys(multisigHexes, password) { + if (this.getWalletProxy()) return this.getWalletProxy().exchangeMultisigKeys(multisigHexes, password); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.exchange_multisig_keys(this.cppAddress, JSON.stringify({ multisigHexes: multisigHexes, password: password }), (resp) => { + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) reject(new _MoneroError.default(resp.substring(errorKey.length)));else + resolve(new _MoneroMultisigInitResult.default(JSON.parse(resp))); + }); + }); + }); + } + + async exportMultisigHex() { + if (this.getWalletProxy()) return this.getWalletProxy().exportMultisigHex(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.export_multisig_hex(this.cppAddress); + }); + } + + async importMultisigHex(multisigHexes) { + if (this.getWalletProxy()) return this.getWalletProxy().importMultisigHex(multisigHexes); + if (!_GenUtils.default.isArray(multisigHexes)) throw new _MoneroError.default("Must provide string[] to importMultisigHex()"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.import_multisig_hex(this.cppAddress, JSON.stringify({ multisigHexes: multisigHexes }), (resp) => { + if (typeof resp === "string") reject(new _MoneroError.default(resp));else + resolve(resp); + }); + }); + }); + } + + async signMultisigTxHex(multisigTxHex) { + if (this.getWalletProxy()) return this.getWalletProxy().signMultisigTxHex(multisigTxHex); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.sign_multisig_tx_hex(this.cppAddress, multisigTxHex, (resp) => { + if (resp.charAt(0) !== '{') reject(new _MoneroError.default(resp));else + resolve(new _MoneroMultisigSignResult.default(JSON.parse(resp))); + }); + }); + }); + } + + async submitMultisigTxHex(signedMultisigTxHex) { + if (this.getWalletProxy()) return this.getWalletProxy().submitMultisigTxHex(signedMultisigTxHex); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.submit_multisig_tx_hex(this.cppAddress, signedMultisigTxHex, (resp) => { + if (resp.charAt(0) !== '{') reject(new _MoneroError.default(resp));else + resolve(JSON.parse(resp).txHashes); + }); + }); + }); + } + + /** + * Get the wallet's keys and cache data. + * + * @return {Promise} is the keys and cache data, respectively + */ + async getData() { + if (this.getWalletProxy()) return this.getWalletProxy().getData(); + + // queue call to wasm module + let viewOnly = await this.isViewOnly(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + + // store views in array + let views = []; + + // malloc cache buffer and get buffer location in c++ heap + let cacheBufferLoc = JSON.parse(this.module.get_cache_file_buffer(this.cppAddress)); + + // read binary data from heap to DataView + let view = new DataView(new ArrayBuffer(cacheBufferLoc.length)); + for (let i = 0; i < cacheBufferLoc.length; i++) { + view.setInt8(i, this.module.HEAPU8[cacheBufferLoc.pointer / Uint8Array.BYTES_PER_ELEMENT + i]); + } + + // free binary on heap + this.module._free(cacheBufferLoc.pointer); + + // write cache file + views.push(Buffer.from(view.buffer)); + + // malloc keys buffer and get buffer location in c++ heap + let keysBufferLoc = JSON.parse(this.module.get_keys_file_buffer(this.cppAddress, this.password, viewOnly)); + + // read binary data from heap to DataView + view = new DataView(new ArrayBuffer(keysBufferLoc.length)); + for (let i = 0; i < keysBufferLoc.length; i++) { + view.setInt8(i, this.module.HEAPU8[keysBufferLoc.pointer / Uint8Array.BYTES_PER_ELEMENT + i]); + } + + // free binary on heap + this.module._free(keysBufferLoc.pointer); + + // prepend keys file + views.unshift(Buffer.from(view.buffer)); + return views; + }); + } + + async changePassword(oldPassword, newPassword) { + if (this.getWalletProxy()) return this.getWalletProxy().changePassword(oldPassword, newPassword); + if (oldPassword !== this.password) throw new _MoneroError.default("Invalid original password."); // wallet2 verify_password loads from disk so verify password here + if (newPassword === undefined) newPassword = ""; + await this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.change_wallet_password(this.cppAddress, oldPassword, newPassword, (errMsg) => { + if (errMsg) reject(new _MoneroError.default(errMsg));else + resolve(); + }); + }); + }); + this.password = newPassword; + if (this.path) await this.save(); // auto save + } + + async save() { + if (this.getWalletProxy()) return this.getWalletProxy().save(); + return MoneroWalletFull.save(this); + } + + async close(save = false) { + if (this._isClosed) return; // no effect if closed + if (save) await this.save(); + if (this.getWalletProxy()) { + await this.getWalletProxy().close(false); + await super.close(); + return; + } + await this.refreshListening(); + await this.stopSyncing(); + await super.close(); + delete this.path; + delete this.password; + delete this.wasmListener; + _LibraryUtils.default.setRejectUnauthorizedFn(this.rejectUnauthorizedConfigId, undefined); // unregister fn informing if unauthorized reqs should be rejected + } + + // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS -------------- + + async getNumBlocksToUnlock() {return super.getNumBlocksToUnlock();} + async getTx(txHash) {return super.getTx(txHash);} + async getIncomingTransfers(query) {return super.getIncomingTransfers(query);} + async getOutgoingTransfers(query) {return super.getOutgoingTransfers(query);} + async createTx(config) {return super.createTx(config);} + async relayTx(txOrMetadata) {return super.relayTx(txOrMetadata);} + async getTxNote(txHash) {return super.getTxNote(txHash);} + async setTxNote(txHash, note) {return super.setTxNote(txHash, note);} + + // ---------------------------- PRIVATE HELPERS ---------------------------- + + static async openWalletData(config) { + if (config.proxyToWorker) { + let walletProxy = await MoneroWalletFullProxy.openWalletData(config); + return new MoneroWalletFull(undefined, undefined, undefined, undefined, undefined, undefined, walletProxy); + } + + // validate and normalize parameters + if (config.networkType === undefined) throw new _MoneroError.default("Must provide the wallet's network type"); + config.networkType = _MoneroNetworkType.default.from(config.networkType); + let daemonConnection = config.getServer(); + let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : ""; + let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : ""; + let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : ""; + let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true; + + // load wasm module + let module = await _LibraryUtils.default.loadWasmModule(); + + // open wallet in queue + return module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // register fn informing if unauthorized reqs should be rejected + let rejectUnauthorizedFnId = _GenUtils.default.getUUID(); + _LibraryUtils.default.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => rejectUnauthorized); + + // create wallet in wasm which invokes callback when done + module.open_wallet_full(config.password, config.networkType, config.keysData ?? "", config.cacheData ?? "", daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, (cppAddress) => { + if (typeof cppAddress === "string") reject(new _MoneroError.default(cppAddress));else + resolve(new MoneroWalletFull(cppAddress, config.path, config.password, config.fs, rejectUnauthorized, rejectUnauthorizedFnId)); + }); + }); + }); + } + + getWalletProxy() { + return super.getWalletProxy(); + } + + async backgroundSync() { + let label = this.path ? this.path : this.browserMainPath ? this.browserMainPath : "in-memory wallet"; // label for log + _LibraryUtils.default.log(1, "Background synchronizing " + label); + try {await this.sync();} + catch (err) {if (!this._isClosed) console.error("Failed to background synchronize " + label + ": " + err.message);} + } + + async refreshListening() { + let isEnabled = this.listeners.length > 0; + if (this.wasmListenerHandle === 0 && !isEnabled || this.wasmListenerHandle > 0 && isEnabled) return; // no difference + return this.module.queueTask(async () => { + return new Promise((resolve, reject) => { + this.module.set_listener( + this.cppAddress, + this.wasmListenerHandle, + (newListenerHandle) => { + if (typeof newListenerHandle === "string") reject(new _MoneroError.default(newListenerHandle));else + { + this.wasmListenerHandle = newListenerHandle; + resolve(); + } + }, + isEnabled ? async (height, startHeight, endHeight, percentDone, message) => await this.wasmListener.onSyncProgress(height, startHeight, endHeight, percentDone, message) : undefined, + isEnabled ? async (height) => await this.wasmListener.onNewBlock(height) : undefined, + isEnabled ? async (newBalanceStr, newUnlockedBalanceStr) => await this.wasmListener.onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) : undefined, + isEnabled ? async (height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockTime, isLocked) => await this.wasmListener.onOutputReceived(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockTime, isLocked) : undefined, + isEnabled ? async (height, txHash, amountStr, accountIdxStr, subaddressIdxStr, version, unlockTime, isLocked) => await this.wasmListener.onOutputSpent(height, txHash, amountStr, accountIdxStr, subaddressIdxStr, version, unlockTime, isLocked) : undefined + ); + }); + }); + } + + static sanitizeBlock(block) { + for (let tx of block.getTxs()) MoneroWalletFull.sanitizeTxWallet(tx); + return block; + } + + static sanitizeTxWallet(tx) { + (0, _assert.default)(tx instanceof _MoneroTxWallet.default); + return tx; + } + + static sanitizeAccount(account) { + if (account.getSubaddresses()) { + for (let subaddress of account.getSubaddresses()) _MoneroWalletKeys.MoneroWalletKeys.sanitizeSubaddress(subaddress); + } + return account; + } + + static deserializeBlocks(blocksJsonStr) { + let blocksJson = JSON.parse(_GenUtils.default.stringifyBigInts(blocksJsonStr)); + let deserializedBlocks = {}; + deserializedBlocks.blocks = []; + if (blocksJson.blocks) for (let blockJson of blocksJson.blocks) deserializedBlocks.blocks.push(MoneroWalletFull.sanitizeBlock(new _MoneroBlock.default(blockJson, _MoneroBlock.default.DeserializationType.TX_WALLET))); + return deserializedBlocks; + } + + static deserializeTxs(query, blocksJsonStr) { + + // deserialize blocks + let deserializedBlocks = MoneroWalletFull.deserializeBlocks(blocksJsonStr); + let blocks = deserializedBlocks.blocks; + + // collect txs + let txs = []; + for (let block of blocks) { + MoneroWalletFull.sanitizeBlock(block); + for (let tx of block.getTxs()) { + if (block.getHeight() === undefined) tx.setBlock(undefined); // dereference placeholder block for unconfirmed txs + txs.push(tx); + } + } + + // re-sort txs which is lost over wasm serialization // TODO: confirm that order is lost + if (query.getHashes() !== undefined) { + let txMap = new Map(); + for (let tx of txs) txMap[tx.getHash()] = tx; + let txsSorted = []; + for (let txHash of query.getHashes()) if (txMap[txHash] !== undefined) txsSorted.push(txMap[txHash]); + txs = txsSorted; + } + + return txs; + } + + static deserializeTransfers(query, blocksJsonStr) { + + // deserialize blocks + let deserializedBlocks = MoneroWalletFull.deserializeBlocks(blocksJsonStr); + let blocks = deserializedBlocks.blocks; + + // collect transfers + let transfers = []; + for (let block of blocks) { + for (let tx of block.getTxs()) { + if (block.getHeight() === undefined) tx.setBlock(undefined); // dereference placeholder block for unconfirmed txs + if (tx.getOutgoingTransfer() !== undefined) transfers.push(tx.getOutgoingTransfer()); + if (tx.getIncomingTransfers() !== undefined) { + for (let transfer of tx.getIncomingTransfers()) transfers.push(transfer); + } + } + } + + return transfers; + } + + static deserializeOutputs(query, blocksJsonStr) { + + // deserialize blocks + let deserializedBlocks = MoneroWalletFull.deserializeBlocks(blocksJsonStr); + let blocks = deserializedBlocks.blocks; + + // collect outputs + let outputs = []; + for (let block of blocks) { + for (let tx of block.getTxs()) { + for (let output of tx.getOutputs()) outputs.push(output); + } + } + + return outputs; + } + + /** + * Set the path of the wallet on the browser main thread if run as a worker. + * + * @param {string} browserMainPath - path of the wallet on the browser main thread + */ + setBrowserMainPath(browserMainPath) { + this.browserMainPath = browserMainPath; + } + + static async moveTo(path, wallet) { + + // save and return if same path + if (_path.default.normalize(wallet.path) === _path.default.normalize(path)) { + return wallet.save(); + } + + return _LibraryUtils.default.queueTask(async () => { + if (await wallet.isClosed()) throw new _MoneroError.default("Wallet is closed"); + if (!path) throw new _MoneroError.default("Must provide path of destination wallet"); + + // create destination directory if it doesn't exist + let walletDir = _path.default.dirname(path); + if (!(await _LibraryUtils.default.exists(wallet.fs, walletDir))) { + try {await wallet.fs.mkdir(walletDir);} + catch (err) {throw new _MoneroError.default("Destination path " + path + " does not exist and cannot be created: " + err.message);} + } + + // get wallet data + const data = await wallet.getData(); + + // write wallet files + await wallet.fs.writeFile(path + ".keys", data[0], "binary"); + await wallet.fs.writeFile(path, data[1], "binary"); + await wallet.fs.writeFile(path + ".address.txt", await wallet.getPrimaryAddress()); + let oldPath = wallet.path; + wallet.path = path; + + // delete old wallet files + if (oldPath) { + await wallet.fs.unlink(oldPath + ".address.txt"); + await wallet.fs.unlink(oldPath + ".keys"); + await wallet.fs.unlink(oldPath); + } + }); + } + + static async save(wallet) { + return _LibraryUtils.default.queueTask(async () => { + if (await wallet.isClosed()) throw new _MoneroError.default("Wallet is closed"); + + // path must be set + let path = await wallet.getPath(); + if (!path) throw new _MoneroError.default("Cannot save wallet because path is not set"); + + // get wallet data + const data = await wallet.getData(); + + // write wallet files to *.new + let pathNew = path + ".new"; + await wallet.fs.writeFile(pathNew + ".keys", data[0], "binary"); + await wallet.fs.writeFile(pathNew, data[1], "binary"); + await wallet.fs.writeFile(pathNew + ".address.txt", await wallet.getPrimaryAddress()); + + // replace old wallet files with new + await wallet.fs.rename(pathNew + ".keys", path + ".keys"); + await wallet.fs.rename(pathNew, path); + await wallet.fs.rename(pathNew + ".address.txt", path + ".address.txt"); + }); + } +} + +/** + * Implements a MoneroWallet by proxying requests to a worker which runs a full wallet. + * + * @private + */exports.default = MoneroWalletFull; +class MoneroWalletFullProxy extends _MoneroWalletKeys.MoneroWalletKeysProxy { + + // instance variables + + + + + // -------------------------- WALLET STATIC UTILS --------------------------- + + static async openWalletData(config) { + let walletId = _GenUtils.default.getUUID(); + if (config.password === undefined) config.password = ""; + let daemonConnection = config.getServer(); + await _LibraryUtils.default.invokeWorker(walletId, "openWalletData", [config.path, config.password, config.networkType, config.keysData, config.cacheData, daemonConnection ? daemonConnection.toJson() : undefined]); + let wallet = new MoneroWalletFullProxy(walletId, await _LibraryUtils.default.getWorker(), config.path, config.getFs()); + if (config.path) await wallet.save(); + return wallet; + } + + static async createWallet(config) { + if (config.getPath() && (await MoneroWalletFull.walletExists(config.getPath(), config.getFs()))) throw new _MoneroError.default("Wallet already exists: " + config.getPath()); + let walletId = _GenUtils.default.getUUID(); + await _LibraryUtils.default.invokeWorker(walletId, "createWalletFull", [config.toJson()]); + let wallet = new MoneroWalletFullProxy(walletId, await _LibraryUtils.default.getWorker(), config.getPath(), config.getFs()); + if (config.getPath()) await wallet.save(); + return wallet; + } + + // --------------------------- INSTANCE METHODS ---------------------------- + + /** + * Internal constructor which is given a worker to communicate with via messages. + * + * This method should not be called externally but should be called through + * static wallet creation utilities in this class. + * + * @param {string} walletId - identifies the wallet with the worker + * @param {Worker} worker - worker to communicate with via messages + */ + constructor(walletId, worker, path, fs) { + super(walletId, worker); + this.path = path; + this.fs = fs ? fs : path ? MoneroWalletFull.getFs() : undefined; + this.wrappedListeners = []; + } + + getPath() { + return this.path; + } + + async getNetworkType() { + return this.invokeWorker("getNetworkType"); + } + + async setSubaddressLabel(accountIdx, subaddressIdx, label) { + return this.invokeWorker("setSubaddressLabel", Array.from(arguments)); + } + + async setDaemonConnection(uriOrRpcConnection) { + if (!uriOrRpcConnection) await this.invokeWorker("setDaemonConnection");else + { + let connection = !uriOrRpcConnection ? undefined : uriOrRpcConnection instanceof _MoneroRpcConnection.default ? uriOrRpcConnection : new _MoneroRpcConnection.default(uriOrRpcConnection); + await this.invokeWorker("setDaemonConnection", connection ? connection.getConfig() : undefined); + } + } + + async getDaemonConnection() { + let rpcConfig = await this.invokeWorker("getDaemonConnection"); + return rpcConfig ? new _MoneroRpcConnection.default(rpcConfig) : undefined; + } + + async isConnectedToDaemon() { + return this.invokeWorker("isConnectedToDaemon"); + } + + async getRestoreHeight() { + return this.invokeWorker("getRestoreHeight"); + } + + async setRestoreHeight(restoreHeight) { + return this.invokeWorker("setRestoreHeight", [restoreHeight]); + } + + async getDaemonHeight() { + return this.invokeWorker("getDaemonHeight"); + } + + async getDaemonMaxPeerHeight() { + return this.invokeWorker("getDaemonMaxPeerHeight"); + } + + async getHeightByDate(year, month, day) { + return this.invokeWorker("getHeightByDate", [year, month, day]); + } + + async isDaemonSynced() { + return this.invokeWorker("isDaemonSynced"); + } + + async getHeight() { + return this.invokeWorker("getHeight"); + } + + async addListener(listener) { + let wrappedListener = new WalletWorkerListener(listener); + let listenerId = wrappedListener.getId(); + _LibraryUtils.default.addWorkerCallback(this.walletId, "onSyncProgress_" + listenerId, [wrappedListener.onSyncProgress, wrappedListener]); + _LibraryUtils.default.addWorkerCallback(this.walletId, "onNewBlock_" + listenerId, [wrappedListener.onNewBlock, wrappedListener]); + _LibraryUtils.default.addWorkerCallback(this.walletId, "onBalancesChanged_" + listenerId, [wrappedListener.onBalancesChanged, wrappedListener]); + _LibraryUtils.default.addWorkerCallback(this.walletId, "onOutputReceived_" + listenerId, [wrappedListener.onOutputReceived, wrappedListener]); + _LibraryUtils.default.addWorkerCallback(this.walletId, "onOutputSpent_" + listenerId, [wrappedListener.onOutputSpent, wrappedListener]); + this.wrappedListeners.push(wrappedListener); + return this.invokeWorker("addListener", [listenerId]); + } + + async removeListener(listener) { + for (let i = 0; i < this.wrappedListeners.length; i++) { + if (this.wrappedListeners[i].getListener() === listener) { + let listenerId = this.wrappedListeners[i].getId(); + await this.invokeWorker("removeListener", [listenerId]); + _LibraryUtils.default.removeWorkerCallback(this.walletId, "onSyncProgress_" + listenerId); + _LibraryUtils.default.removeWorkerCallback(this.walletId, "onNewBlock_" + listenerId); + _LibraryUtils.default.removeWorkerCallback(this.walletId, "onBalancesChanged_" + listenerId); + _LibraryUtils.default.removeWorkerCallback(this.walletId, "onOutputReceived_" + listenerId); + _LibraryUtils.default.removeWorkerCallback(this.walletId, "onOutputSpent_" + listenerId); + this.wrappedListeners.splice(i, 1); + return; + } + } + throw new _MoneroError.default("Listener is not registered with wallet"); + } + + getListeners() { + let listeners = []; + for (let wrappedListener of this.wrappedListeners) listeners.push(wrappedListener.getListener()); + return listeners; + } + + async isSynced() { + return this.invokeWorker("isSynced"); + } + + async sync(listenerOrStartHeight, startHeight, allowConcurrentCalls = false) { + + // normalize params + startHeight = listenerOrStartHeight instanceof _MoneroWalletListener.default ? startHeight : listenerOrStartHeight; + let listener = listenerOrStartHeight instanceof _MoneroWalletListener.default ? listenerOrStartHeight : undefined; + if (startHeight === undefined) startHeight = Math.max(await this.getHeight(), await this.getRestoreHeight()); + + // register listener if given + if (listener) await this.addListener(listener); + + // sync wallet in worker + let err; + let result; + try { + let resultJson = await this.invokeWorker("sync", [startHeight, allowConcurrentCalls]); + result = new _MoneroSyncResult.default(resultJson.numBlocksFetched, resultJson.receivedMoney); + } catch (e) { + err = e; + } + + // unregister listener + if (listener) await this.removeListener(listener); + + // throw error or return + if (err) throw err; + return result; + } + + async startSyncing(syncPeriodInMs) { + return this.invokeWorker("startSyncing", Array.from(arguments)); + } + + async stopSyncing() { + return this.invokeWorker("stopSyncing"); + } + + async scanTxs(txHashes) { + (0, _assert.default)(Array.isArray(txHashes), "Must provide an array of txs hashes to scan"); + return this.invokeWorker("scanTxs", [txHashes]); + } + + async rescanSpent() { + return this.invokeWorker("rescanSpent"); + } + + async rescanBlockchain() { + return this.invokeWorker("rescanBlockchain"); + } + + async getBalance(accountIdx, subaddressIdx) { + return BigInt(await this.invokeWorker("getBalance", Array.from(arguments))); + } + + async getUnlockedBalance(accountIdx, subaddressIdx) { + let unlockedBalanceStr = await this.invokeWorker("getUnlockedBalance", Array.from(arguments)); + return BigInt(unlockedBalanceStr); + } + + async getAccounts(includeSubaddresses, tag) { + let accounts = []; + for (let accountJson of await this.invokeWorker("getAccounts", Array.from(arguments))) { + accounts.push(MoneroWalletFull.sanitizeAccount(new _MoneroAccount.default(accountJson))); + } + return accounts; + } + + async getAccount(accountIdx, includeSubaddresses) { + let accountJson = await this.invokeWorker("getAccount", Array.from(arguments)); + return MoneroWalletFull.sanitizeAccount(new _MoneroAccount.default(accountJson)); + } + + async createAccount(label) { + let accountJson = await this.invokeWorker("createAccount", Array.from(arguments)); + return MoneroWalletFull.sanitizeAccount(new _MoneroAccount.default(accountJson)); + } + + async getSubaddresses(accountIdx, subaddressIndices) { + let subaddresses = []; + for (let subaddressJson of await this.invokeWorker("getSubaddresses", Array.from(arguments))) { + subaddresses.push(_MoneroWalletKeys.MoneroWalletKeys.sanitizeSubaddress(new _MoneroSubaddress.default(subaddressJson))); + } + return subaddresses; + } + + async createSubaddress(accountIdx, label) { + let subaddressJson = await this.invokeWorker("createSubaddress", Array.from(arguments)); + return _MoneroWalletKeys.MoneroWalletKeys.sanitizeSubaddress(new _MoneroSubaddress.default(subaddressJson)); + } + + async getTxs(query) { + query = _MoneroWallet.default.normalizeTxQuery(query); + let respJson = await this.invokeWorker("getTxs", [query.getBlock().toJson()]); + return MoneroWalletFull.deserializeTxs(query, JSON.stringify({ blocks: respJson.blocks })); // initialize txs from blocks json string TODO: this stringifies then utility parses, avoid + } + + async getTransfers(query) { + query = _MoneroWallet.default.normalizeTransferQuery(query); + let blockJsons = await this.invokeWorker("getTransfers", [query.getTxQuery().getBlock().toJson()]); + return MoneroWalletFull.deserializeTransfers(query, JSON.stringify({ blocks: blockJsons })); // initialize transfers from blocks json string TODO: this stringifies then utility parses, avoid + } + + async getOutputs(query) { + query = _MoneroWallet.default.normalizeOutputQuery(query); + let blockJsons = await this.invokeWorker("getOutputs", [query.getTxQuery().getBlock().toJson()]); + return MoneroWalletFull.deserializeOutputs(query, JSON.stringify({ blocks: blockJsons })); // initialize transfers from blocks json string TODO: this stringifies then utility parses, avoid + } + + async exportOutputs(all) { + return this.invokeWorker("exportOutputs", [all]); + } + + async importOutputs(outputsHex) { + return this.invokeWorker("importOutputs", [outputsHex]); + } + + async exportKeyImages(all) { + let keyImages = []; + for (let keyImageJson of await this.invokeWorker("getKeyImages", [all])) keyImages.push(new _MoneroKeyImage.default(keyImageJson)); + return keyImages; + } + + async importKeyImages(keyImages) { + let keyImagesJson = []; + for (let keyImage of keyImages) keyImagesJson.push(keyImage.toJson()); + return new _MoneroKeyImageImportResult.default(await this.invokeWorker("importKeyImages", [keyImagesJson])); + } + + async getNewKeyImagesFromLastImport() { + throw new _MoneroError.default("MoneroWalletFull.getNewKeyImagesFromLastImport() not implemented"); + } + + async freezeOutput(keyImage) { + return this.invokeWorker("freezeOutput", [keyImage]); + } + + async thawOutput(keyImage) { + return this.invokeWorker("thawOutput", [keyImage]); + } + + async isOutputFrozen(keyImage) { + return this.invokeWorker("isOutputFrozen", [keyImage]); + } + + async getDefaultFeePriority() { + return this.invokeWorker("getDefaultFeePriority"); + } + + async createTxs(config) { + config = _MoneroWallet.default.normalizeCreateTxsConfig(config); + let txSetJson = await this.invokeWorker("createTxs", [config.toJson()]); + return new _MoneroTxSet.default(txSetJson).getTxs(); + } + + async sweepOutput(config) { + config = _MoneroWallet.default.normalizeSweepOutputConfig(config); + let txSetJson = await this.invokeWorker("sweepOutput", [config.toJson()]); + return new _MoneroTxSet.default(txSetJson).getTxs()[0]; + } + + async sweepUnlocked(config) { + config = _MoneroWallet.default.normalizeSweepUnlockedConfig(config); + let txSetsJson = await this.invokeWorker("sweepUnlocked", [config.toJson()]); + let txs = []; + for (let txSetJson of txSetsJson) for (let tx of new _MoneroTxSet.default(txSetJson).getTxs()) txs.push(tx); + return txs; + } + + async sweepDust(relay) { + return new _MoneroTxSet.default(await this.invokeWorker("sweepDust", [relay])).getTxs() || []; + } + + async relayTxs(txsOrMetadatas) { + (0, _assert.default)(Array.isArray(txsOrMetadatas), "Must provide an array of txs or their metadata to relay"); + let txMetadatas = []; + for (let txOrMetadata of txsOrMetadatas) txMetadatas.push(txOrMetadata instanceof _MoneroTxWallet.default ? txOrMetadata.getMetadata() : txOrMetadata); + return this.invokeWorker("relayTxs", [txMetadatas]); + } + + async describeTxSet(txSet) { + return new _MoneroTxSet.default(await this.invokeWorker("describeTxSet", [txSet.toJson()])); + } + + async signTxs(unsignedTxHex) { + return new _MoneroTxSet.default(await this.invokeWorker("signTxs", Array.from(arguments))); + } + + async submitTxs(signedTxHex) { + return this.invokeWorker("submitTxs", Array.from(arguments)); + } + + async signMessage(message, signatureType, accountIdx, subaddressIdx) { + return this.invokeWorker("signMessage", Array.from(arguments)); + } + + async verifyMessage(message, address, signature) { + return new _MoneroMessageSignatureResult.default(await this.invokeWorker("verifyMessage", Array.from(arguments))); + } + + async getTxKey(txHash) { + return this.invokeWorker("getTxKey", Array.from(arguments)); + } + + async checkTxKey(txHash, txKey, address) { + return new _MoneroCheckTx.default(await this.invokeWorker("checkTxKey", Array.from(arguments))); + } + + async getTxProof(txHash, address, message) { + return this.invokeWorker("getTxProof", Array.from(arguments)); + } + + async checkTxProof(txHash, address, message, signature) { + return new _MoneroCheckTx.default(await this.invokeWorker("checkTxProof", Array.from(arguments))); + } + + async getSpendProof(txHash, message) { + return this.invokeWorker("getSpendProof", Array.from(arguments)); + } + + async checkSpendProof(txHash, message, signature) { + return this.invokeWorker("checkSpendProof", Array.from(arguments)); + } + + async getReserveProofWallet(message) { + return this.invokeWorker("getReserveProofWallet", Array.from(arguments)); + } + + async getReserveProofAccount(accountIdx, amount, message) { + try {return await this.invokeWorker("getReserveProofAccount", [accountIdx, amount.toString(), message]);} + catch (e) {throw new _MoneroError.default(e.message, -1);} + } + + async checkReserveProof(address, message, signature) { + try {return new _MoneroCheckReserve.default(await this.invokeWorker("checkReserveProof", Array.from(arguments)));} + catch (e) {throw new _MoneroError.default(e.message, -1);} + } + + async getTxNotes(txHashes) { + return this.invokeWorker("getTxNotes", Array.from(arguments)); + } + + async setTxNotes(txHashes, notes) { + return this.invokeWorker("setTxNotes", Array.from(arguments)); + } + + async getAddressBookEntries(entryIndices) { + if (!entryIndices) entryIndices = []; + let entries = []; + for (let entryJson of await this.invokeWorker("getAddressBookEntries", Array.from(arguments))) { + entries.push(new _MoneroAddressBookEntry.default(entryJson)); + } + return entries; + } + + async addAddressBookEntry(address, description) { + return this.invokeWorker("addAddressBookEntry", Array.from(arguments)); + } + + async editAddressBookEntry(index, setAddress, address, setDescription, description) { + return this.invokeWorker("editAddressBookEntry", Array.from(arguments)); + } + + async deleteAddressBookEntry(entryIdx) { + return this.invokeWorker("deleteAddressBookEntry", Array.from(arguments)); + } + + async tagAccounts(tag, accountIndices) { + return this.invokeWorker("tagAccounts", Array.from(arguments)); + } + + async untagAccounts(accountIndices) { + return this.invokeWorker("untagAccounts", Array.from(arguments)); + } + + async getAccountTags() { + return this.invokeWorker("getAccountTags", Array.from(arguments)); + } + + async setAccountTagLabel(tag, label) { + return this.invokeWorker("setAccountTagLabel", Array.from(arguments)); + } + + async getPaymentUri(config) { + config = _MoneroWallet.default.normalizeCreateTxsConfig(config); + return this.invokeWorker("getPaymentUri", [config.toJson()]); + } + + async parsePaymentUri(uri) { + return new _MoneroTxConfig.default(await this.invokeWorker("parsePaymentUri", Array.from(arguments))); + } + + async getAttribute(key) { + return this.invokeWorker("getAttribute", Array.from(arguments)); + } + + async setAttribute(key, val) { + return this.invokeWorker("setAttribute", Array.from(arguments)); + } + + async startMining(numThreads, backgroundMining, ignoreBattery) { + return this.invokeWorker("startMining", Array.from(arguments)); + } + + async stopMining() { + return this.invokeWorker("stopMining", Array.from(arguments)); + } + + async isMultisigImportNeeded() { + return this.invokeWorker("isMultisigImportNeeded"); + } + + async isMultisig() { + return this.invokeWorker("isMultisig"); + } + + async getMultisigInfo() { + return new _MoneroMultisigInfo.default(await this.invokeWorker("getMultisigInfo")); + } + + async prepareMultisig() { + return this.invokeWorker("prepareMultisig"); + } + + async makeMultisig(multisigHexes, threshold, password) { + return await this.invokeWorker("makeMultisig", Array.from(arguments)); + } + + async exchangeMultisigKeys(multisigHexes, password) { + return new _MoneroMultisigInitResult.default(await this.invokeWorker("exchangeMultisigKeys", Array.from(arguments))); + } + + async exportMultisigHex() { + return this.invokeWorker("exportMultisigHex"); + } + + async importMultisigHex(multisigHexes) { + return this.invokeWorker("importMultisigHex", Array.from(arguments)); + } + + async signMultisigTxHex(multisigTxHex) { + return new _MoneroMultisigSignResult.default(await this.invokeWorker("signMultisigTxHex", Array.from(arguments))); + } + + async submitMultisigTxHex(signedMultisigTxHex) { + return this.invokeWorker("submitMultisigTxHex", Array.from(arguments)); + } + + async getData() { + return this.invokeWorker("getData"); + } + + async moveTo(path) { + return MoneroWalletFull.moveTo(path, this); + } + + async changePassword(oldPassword, newPassword) { + await this.invokeWorker("changePassword", Array.from(arguments)); + if (this.path) await this.save(); // auto save + } + + async save() { + return MoneroWalletFull.save(this); + } + + async close(save) { + if (await this.isClosed()) return; + if (save) await this.save(); + while (this.wrappedListeners.length) await this.removeListener(this.wrappedListeners[0].getListener()); + await super.close(false); + } +} + +// -------------------------------- LISTENING --------------------------------- + +/** + * Receives notifications directly from wasm c++. + * + * @private + */ +class WalletWasmListener { + + + + constructor(wallet) { + this.wallet = wallet; + } + + async onSyncProgress(height, startHeight, endHeight, percentDone, message) { + await this.wallet.announceSyncProgress(height, startHeight, endHeight, percentDone, message); + } + + async onNewBlock(height) { + await this.wallet.announceNewBlock(height); + } + + async onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) { + await this.wallet.announceBalancesChanged(newBalanceStr, newUnlockedBalanceStr); + } + + async onOutputReceived(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockTime, isLocked) { + + // build received output + let output = new _MoneroOutputWallet.default(); + output.setAmount(BigInt(amountStr)); + output.setAccountIndex(accountIdx); + output.setSubaddressIndex(subaddressIdx); + let tx = new _MoneroTxWallet.default(); + tx.setHash(txHash); + tx.setVersion(version); + tx.setUnlockTime(unlockTime); + output.setTx(tx); + tx.setOutputs([output]); + tx.setIsIncoming(true); + tx.setIsLocked(isLocked); + if (height > 0) { + let block = new _MoneroBlock.default().setHeight(height); + block.setTxs([tx]); + tx.setBlock(block); + tx.setIsConfirmed(true); + tx.setInTxPool(false); + tx.setIsFailed(false); + } else { + tx.setIsConfirmed(false); + tx.setInTxPool(true); + } + + // announce output + await this.wallet.announceOutputReceived(output); + } + + async onOutputSpent(height, txHash, amountStr, accountIdxStr, subaddressIdxStr, version, unlockTime, isLocked) { + + // build spent output + let output = new _MoneroOutputWallet.default(); + output.setAmount(BigInt(amountStr)); + if (accountIdxStr) output.setAccountIndex(parseInt(accountIdxStr)); + if (subaddressIdxStr) output.setSubaddressIndex(parseInt(subaddressIdxStr)); + let tx = new _MoneroTxWallet.default(); + tx.setHash(txHash); + tx.setVersion(version); + tx.setUnlockTime(unlockTime); + tx.setIsLocked(isLocked); + output.setTx(tx); + tx.setInputs([output]); + if (height > 0) { + let block = new _MoneroBlock.default().setHeight(height); + block.setTxs([tx]); + tx.setBlock(block); + tx.setIsConfirmed(true); + tx.setInTxPool(false); + tx.setIsFailed(false); + } else { + tx.setIsConfirmed(false); + tx.setInTxPool(true); + } + + // announce output + await this.wallet.announceOutputSpent(output); + } +} + +/** + * Internal listener to bridge notifications to external listeners. + * + * @private + */ +class WalletWorkerListener { + + + + + constructor(listener) { + this.id = _GenUtils.default.getUUID(); + this.listener = listener; + } + + getId() { + return this.id; + } + + getListener() { + return this.listener; + } + + onSyncProgress(height, startHeight, endHeight, percentDone, message) { + this.listener.onSyncProgress(height, startHeight, endHeight, percentDone, message); + } + + async onNewBlock(height) { + await this.listener.onNewBlock(height); + } + + async onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) { + await this.listener.onBalancesChanged(BigInt(newBalanceStr), BigInt(newUnlockedBalanceStr)); + } + + async onOutputReceived(blockJson) { + let block = new _MoneroBlock.default(blockJson, _MoneroBlock.default.DeserializationType.TX_WALLET); + await this.listener.onOutputReceived(block.getTxs()[0].getOutputs()[0]); + } + + async onOutputSpent(blockJson) { + let block = new _MoneroBlock.default(blockJson, _MoneroBlock.default.DeserializationType.TX_WALLET); + await this.listener.onOutputSpent(block.getTxs()[0].getInputs()[0]); + } +} +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfcGF0aCIsIl9HZW5VdGlscyIsIl9MaWJyYXJ5VXRpbHMiLCJfVGFza0xvb3BlciIsIl9Nb25lcm9BY2NvdW50IiwiX01vbmVyb0FjY291bnRUYWciLCJfTW9uZXJvQWRkcmVzc0Jvb2tFbnRyeSIsIl9Nb25lcm9CbG9jayIsIl9Nb25lcm9DaGVja1R4IiwiX01vbmVyb0NoZWNrUmVzZXJ2ZSIsIl9Nb25lcm9EYWVtb25ScGMiLCJfTW9uZXJvRXJyb3IiLCJfTW9uZXJvSW50ZWdyYXRlZEFkZHJlc3MiLCJfTW9uZXJvS2V5SW1hZ2UiLCJfTW9uZXJvS2V5SW1hZ2VJbXBvcnRSZXN1bHQiLCJfTW9uZXJvTXVsdGlzaWdJbmZvIiwiX01vbmVyb011bHRpc2lnSW5pdFJlc3VsdCIsIl9Nb25lcm9NdWx0aXNpZ1NpZ25SZXN1bHQiLCJfTW9uZXJvTmV0d29ya1R5cGUiLCJfTW9uZXJvT3V0cHV0V2FsbGV0IiwiX01vbmVyb1JwY0Nvbm5lY3Rpb24iLCJfTW9uZXJvU3ViYWRkcmVzcyIsIl9Nb25lcm9TeW5jUmVzdWx0IiwiX01vbmVyb1R4Q29uZmlnIiwiX01vbmVyb1R4U2V0IiwiX01vbmVyb1R4V2FsbGV0IiwiX01vbmVyb1dhbGxldCIsIl9Nb25lcm9XYWxsZXRDb25maWciLCJfTW9uZXJvV2FsbGV0S2V5cyIsIl9Nb25lcm9XYWxsZXRMaXN0ZW5lciIsIl9Nb25lcm9NZXNzYWdlU2lnbmF0dXJlVHlwZSIsIl9Nb25lcm9NZXNzYWdlU2lnbmF0dXJlUmVzdWx0IiwiX2ZzIiwiTW9uZXJvV2FsbGV0RnVsbCIsIk1vbmVyb1dhbGxldEtleXMiLCJERUZBVUxUX1NZTkNfUEVSSU9EX0lOX01TIiwiY29uc3RydWN0b3IiLCJjcHBBZGRyZXNzIiwicGF0aCIsInBhc3N3b3JkIiwiZnMiLCJyZWplY3RVbmF1dGhvcml6ZWQiLCJyZWplY3RVbmF1dGhvcml6ZWRGbklkIiwid2FsbGV0UHJveHkiLCJsaXN0ZW5lcnMiLCJnZXRGcyIsInVuZGVmaW5lZCIsIl9pc0Nsb3NlZCIsIndhc21MaXN0ZW5lciIsIldhbGxldFdhc21MaXN0ZW5lciIsIndhc21MaXN0ZW5lckhhbmRsZSIsInJlamVjdFVuYXV0aG9yaXplZENvbmZpZ0lkIiwic3luY1BlcmlvZEluTXMiLCJMaWJyYXJ5VXRpbHMiLCJzZXRSZWplY3RVbmF1dGhvcml6ZWRGbiIsIndhbGxldEV4aXN0cyIsImFzc2VydCIsIk1vbmVyb0Vycm9yIiwiZXhpc3RzIiwibG9nIiwib3BlbldhbGxldCIsImNvbmZpZyIsIk1vbmVyb1dhbGxldENvbmZpZyIsImdldFByb3h5VG9Xb3JrZXIiLCJzZXRQcm94eVRvV29ya2VyIiwiZ2V0U2VlZCIsImdldFNlZWRPZmZzZXQiLCJnZXRQcmltYXJ5QWRkcmVzcyIsImdldFByaXZhdGVWaWV3S2V5IiwiZ2V0UHJpdmF0ZVNwZW5kS2V5IiwiZ2V0UmVzdG9yZUhlaWdodCIsImdldExhbmd1YWdlIiwiZ2V0U2F2ZUN1cnJlbnQiLCJzZXRGcyIsImdldENvbm5lY3Rpb25NYW5hZ2VyIiwiZ2V0U2VydmVyIiwic2V0U2VydmVyIiwiZ2V0Q29ubmVjdGlvbiIsImdldEtleXNEYXRhIiwiZ2V0UGF0aCIsInNldEtleXNEYXRhIiwicmVhZEZpbGUiLCJzZXRDYWNoZURhdGEiLCJ3YWxsZXQiLCJvcGVuV2FsbGV0RGF0YSIsInNldENvbm5lY3Rpb25NYW5hZ2VyIiwiY3JlYXRlV2FsbGV0IiwiZ2V0TmV0d29ya1R5cGUiLCJNb25lcm9OZXR3b3JrVHlwZSIsInZhbGlkYXRlIiwic2V0UGF0aCIsImdldFBhc3N3b3JkIiwic2V0UGFzc3dvcmQiLCJNb25lcm9XYWxsZXRGdWxsUHJveHkiLCJjcmVhdGVXYWxsZXRGcm9tU2VlZCIsImNyZWF0ZVdhbGxldEZyb21LZXlzIiwiY3JlYXRlV2FsbGV0UmFuZG9tIiwiZGFlbW9uQ29ubmVjdGlvbiIsImdldFJlamVjdFVuYXV0aG9yaXplZCIsInNldFJlc3RvcmVIZWlnaHQiLCJzZXRTZWVkT2Zmc2V0IiwibW9kdWxlIiwibG9hZFdhc21Nb2R1bGUiLCJxdWV1ZVRhc2siLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsIkdlblV0aWxzIiwiZ2V0VVVJRCIsImNyZWF0ZV9mdWxsX3dhbGxldCIsIkpTT04iLCJzdHJpbmdpZnkiLCJ0b0pzb24iLCJzYXZlIiwic2V0UHJpbWFyeUFkZHJlc3MiLCJzZXRQcml2YXRlVmlld0tleSIsInNldFByaXZhdGVTcGVuZEtleSIsInNldExhbmd1YWdlIiwiZ2V0U2VlZExhbmd1YWdlcyIsInBhcnNlIiwiZ2V0X2tleXNfd2FsbGV0X3NlZWRfbGFuZ3VhZ2VzIiwibGFuZ3VhZ2VzIiwiRlMiLCJwcm9taXNlcyIsImdldERhZW1vbk1heFBlZXJIZWlnaHQiLCJnZXRXYWxsZXRQcm94eSIsImFzc2VydE5vdENsb3NlZCIsImdldF9kYWVtb25fbWF4X3BlZXJfaGVpZ2h0IiwicmVzcCIsImlzRGFlbW9uU3luY2VkIiwiaXNfZGFlbW9uX3N5bmNlZCIsImlzU3luY2VkIiwiaXNfc3luY2VkIiwiZ2V0X25ldHdvcmtfdHlwZSIsImdldF9yZXN0b3JlX2hlaWdodCIsInJlc3RvcmVIZWlnaHQiLCJzZXRfcmVzdG9yZV9oZWlnaHQiLCJtb3ZlVG8iLCJhZGRMaXN0ZW5lciIsImxpc3RlbmVyIiwicmVmcmVzaExpc3RlbmluZyIsInJlbW92ZUxpc3RlbmVyIiwiZ2V0TGlzdGVuZXJzIiwic2V0RGFlbW9uQ29ubmVjdGlvbiIsInVyaU9yQ29ubmVjdGlvbiIsImNvbm5lY3Rpb24iLCJNb25lcm9ScGNDb25uZWN0aW9uIiwidXJpIiwiZ2V0VXJpIiwidXNlcm5hbWUiLCJnZXRVc2VybmFtZSIsInByb3h5VXJpIiwiZ2V0UHJveHlVcmkiLCJzZXRfZGFlbW9uX2Nvbm5lY3Rpb24iLCJnZXREYWVtb25Db25uZWN0aW9uIiwiY29ubmVjdGlvbkNvbnRhaW5lclN0ciIsImdldF9kYWVtb25fY29ubmVjdGlvbiIsImpzb25Db25uZWN0aW9uIiwiaXNDb25uZWN0ZWRUb0RhZW1vbiIsImlzX2Nvbm5lY3RlZF90b19kYWVtb24iLCJnZXRWZXJzaW9uIiwiZ2V0SW50ZWdyYXRlZEFkZHJlc3MiLCJzdGFuZGFyZEFkZHJlc3MiLCJwYXltZW50SWQiLCJyZXN1bHQiLCJnZXRfaW50ZWdyYXRlZF9hZGRyZXNzIiwiY2hhckF0IiwiTW9uZXJvSW50ZWdyYXRlZEFkZHJlc3MiLCJlcnIiLCJtZXNzYWdlIiwiaW5jbHVkZXMiLCJkZWNvZGVJbnRlZ3JhdGVkQWRkcmVzcyIsImludGVncmF0ZWRBZGRyZXNzIiwiZGVjb2RlX2ludGVncmF0ZWRfYWRkcmVzcyIsImdldEhlaWdodCIsImdldF9oZWlnaHQiLCJnZXREYWVtb25IZWlnaHQiLCJnZXRfZGFlbW9uX2hlaWdodCIsImdldEhlaWdodEJ5RGF0ZSIsInllYXIiLCJtb250aCIsImRheSIsImdldF9oZWlnaHRfYnlfZGF0ZSIsInN5bmMiLCJsaXN0ZW5lck9yU3RhcnRIZWlnaHQiLCJzdGFydEhlaWdodCIsImFsbG93Q29uY3VycmVudENhbGxzIiwiTW9uZXJvV2FsbGV0TGlzdGVuZXIiLCJNYXRoIiwibWF4IiwidGhhdCIsInN5bmNXYXNtIiwicmVzcEpzb24iLCJNb25lcm9TeW5jUmVzdWx0IiwibnVtQmxvY2tzRmV0Y2hlZCIsInJlY2VpdmVkTW9uZXkiLCJlIiwic3RhcnRTeW5jaW5nIiwic3luY0xvb3BlciIsIlRhc2tMb29wZXIiLCJiYWNrZ3JvdW5kU3luYyIsInN0YXJ0Iiwic3RvcFN5bmNpbmciLCJzdG9wIiwic3RvcF9zeW5jaW5nIiwic2NhblR4cyIsInR4SGFzaGVzIiwic2Nhbl90eHMiLCJyZXNjYW5TcGVudCIsInJlc2Nhbl9zcGVudCIsInJlc2NhbkJsb2NrY2hhaW4iLCJyZXNjYW5fYmxvY2tjaGFpbiIsImdldEJhbGFuY2UiLCJhY2NvdW50SWR4Iiwic3ViYWRkcmVzc0lkeCIsImJhbGFuY2VTdHIiLCJnZXRfYmFsYW5jZV93YWxsZXQiLCJnZXRfYmFsYW5jZV9hY2NvdW50IiwiZ2V0X2JhbGFuY2Vfc3ViYWRkcmVzcyIsIkJpZ0ludCIsInN0cmluZ2lmeUJpZ0ludHMiLCJiYWxhbmNlIiwiZ2V0VW5sb2NrZWRCYWxhbmNlIiwidW5sb2NrZWRCYWxhbmNlU3RyIiwiZ2V0X3VubG9ja2VkX2JhbGFuY2Vfd2FsbGV0IiwiZ2V0X3VubG9ja2VkX2JhbGFuY2VfYWNjb3VudCIsImdldF91bmxvY2tlZF9iYWxhbmNlX3N1YmFkZHJlc3MiLCJ1bmxvY2tlZEJhbGFuY2UiLCJnZXRBY2NvdW50cyIsImluY2x1ZGVTdWJhZGRyZXNzZXMiLCJ0YWciLCJhY2NvdW50c1N0ciIsImdldF9hY2NvdW50cyIsImFjY291bnRzIiwiYWNjb3VudEpzb24iLCJwdXNoIiwic2FuaXRpemVBY2NvdW50IiwiTW9uZXJvQWNjb3VudCIsImdldEFjY291bnQiLCJhY2NvdW50U3RyIiwiZ2V0X2FjY291bnQiLCJjcmVhdGVBY2NvdW50IiwibGFiZWwiLCJjcmVhdGVfYWNjb3VudCIsImdldFN1YmFkZHJlc3NlcyIsInN1YmFkZHJlc3NJbmRpY2VzIiwiYXJncyIsImxpc3RpZnkiLCJzdWJhZGRyZXNzZXNKc29uIiwiZ2V0X3N1YmFkZHJlc3NlcyIsInN1YmFkZHJlc3NlcyIsInN1YmFkZHJlc3NKc29uIiwic2FuaXRpemVTdWJhZGRyZXNzIiwiTW9uZXJvU3ViYWRkcmVzcyIsImNyZWF0ZVN1YmFkZHJlc3MiLCJzdWJhZGRyZXNzU3RyIiwiY3JlYXRlX3N1YmFkZHJlc3MiLCJzZXRTdWJhZGRyZXNzTGFiZWwiLCJzZXRfc3ViYWRkcmVzc19sYWJlbCIsImdldFR4cyIsInF1ZXJ5IiwicXVlcnlOb3JtYWxpemVkIiwiTW9uZXJvV2FsbGV0Iiwibm9ybWFsaXplVHhRdWVyeSIsImdldF90eHMiLCJnZXRCbG9jayIsImJsb2Nrc0pzb25TdHIiLCJkZXNlcmlhbGl6ZVR4cyIsImdldFRyYW5zZmVycyIsIm5vcm1hbGl6ZVRyYW5zZmVyUXVlcnkiLCJnZXRfdHJhbnNmZXJzIiwiZ2V0VHhRdWVyeSIsImRlc2VyaWFsaXplVHJhbnNmZXJzIiwiZ2V0T3V0cHV0cyIsIm5vcm1hbGl6ZU91dHB1dFF1ZXJ5IiwiZ2V0X291dHB1dHMiLCJkZXNlcmlhbGl6ZU91dHB1dHMiLCJleHBvcnRPdXRwdXRzIiwiYWxsIiwiZXhwb3J0X291dHB1dHMiLCJvdXRwdXRzSGV4IiwiaW1wb3J0T3V0cHV0cyIsImltcG9ydF9vdXRwdXRzIiwibnVtSW1wb3J0ZWQiLCJleHBvcnRLZXlJbWFnZXMiLCJleHBvcnRfa2V5X2ltYWdlcyIsImtleUltYWdlc1N0ciIsImtleUltYWdlcyIsImtleUltYWdlSnNvbiIsIk1vbmVyb0tleUltYWdlIiwiaW1wb3J0S2V5SW1hZ2VzIiwiaW1wb3J0X2tleV9pbWFnZXMiLCJtYXAiLCJrZXlJbWFnZSIsImtleUltYWdlSW1wb3J0UmVzdWx0U3RyIiwiTW9uZXJvS2V5SW1hZ2VJbXBvcnRSZXN1bHQiLCJnZXROZXdLZXlJbWFnZXNGcm9tTGFzdEltcG9ydCIsImZyZWV6ZU91dHB1dCIsImZyZWV6ZV9vdXRwdXQiLCJ0aGF3T3V0cHV0IiwidGhhd19vdXRwdXQiLCJpc091dHB1dEZyb3plbiIsImlzX291dHB1dF9mcm96ZW4iLCJnZXREZWZhdWx0RmVlUHJpb3JpdHkiLCJnZXRfZGVmYXVsdF9mZWVfcHJpb3JpdHkiLCJjcmVhdGVUeHMiLCJjb25maWdOb3JtYWxpemVkIiwibm9ybWFsaXplQ3JlYXRlVHhzQ29uZmlnIiwiZ2V0Q2FuU3BsaXQiLCJzZXRDYW5TcGxpdCIsImNyZWF0ZV90eHMiLCJ0eFNldEpzb25TdHIiLCJNb25lcm9UeFNldCIsInN3ZWVwT3V0cHV0Iiwibm9ybWFsaXplU3dlZXBPdXRwdXRDb25maWciLCJzd2VlcF9vdXRwdXQiLCJzd2VlcFVubG9ja2VkIiwibm9ybWFsaXplU3dlZXBVbmxvY2tlZENvbmZpZyIsInN3ZWVwX3VubG9ja2VkIiwidHhTZXRzSnNvbiIsInR4U2V0cyIsInR4U2V0SnNvbiIsInR4cyIsInR4U2V0IiwidHgiLCJzd2VlcER1c3QiLCJyZWxheSIsInN3ZWVwX2R1c3QiLCJzZXRUeHMiLCJyZWxheVR4cyIsInR4c09yTWV0YWRhdGFzIiwiQXJyYXkiLCJpc0FycmF5IiwidHhNZXRhZGF0YXMiLCJ0eE9yTWV0YWRhdGEiLCJNb25lcm9UeFdhbGxldCIsImdldE1ldGFkYXRhIiwicmVsYXlfdHhzIiwidHhIYXNoZXNKc29uIiwiZGVzY3JpYmVUeFNldCIsInVuc2lnbmVkVHhIZXgiLCJnZXRVbnNpZ25lZFR4SGV4Iiwic2lnbmVkVHhIZXgiLCJnZXRTaWduZWRUeEhleCIsIm11bHRpc2lnVHhIZXgiLCJnZXRNdWx0aXNpZ1R4SGV4IiwiZGVzY3JpYmVfdHhfc2V0IiwiZ2V0X2V4Y2VwdGlvbl9tZXNzYWdlIiwic2lnblR4cyIsInNpZ25fdHhzIiwic3VibWl0VHhzIiwic3VibWl0X3R4cyIsInNpZ25NZXNzYWdlIiwic2lnbmF0dXJlVHlwZSIsIk1vbmVyb01lc3NhZ2VTaWduYXR1cmVUeXBlIiwiU0lHTl9XSVRIX1NQRU5EX0tFWSIsInNpZ25fbWVzc2FnZSIsInZlcmlmeU1lc3NhZ2UiLCJhZGRyZXNzIiwic2lnbmF0dXJlIiwidmVyaWZ5X21lc3NhZ2UiLCJpc0dvb2QiLCJNb25lcm9NZXNzYWdlU2lnbmF0dXJlUmVzdWx0IiwiaXNPbGQiLCJTSUdOX1dJVEhfVklFV19LRVkiLCJ2ZXJzaW9uIiwiZ2V0VHhLZXkiLCJ0eEhhc2giLCJnZXRfdHhfa2V5IiwiY2hlY2tUeEtleSIsInR4S2V5IiwiY2hlY2tfdHhfa2V5IiwicmVzcEpzb25TdHIiLCJNb25lcm9DaGVja1R4IiwiZ2V0VHhQcm9vZiIsImdldF90eF9wcm9vZiIsImVycm9yS2V5IiwiaW5kZXhPZiIsInN1YnN0cmluZyIsImxlbmd0aCIsImNoZWNrVHhQcm9vZiIsImNoZWNrX3R4X3Byb29mIiwiZ2V0U3BlbmRQcm9vZiIsImdldF9zcGVuZF9wcm9vZiIsImNoZWNrU3BlbmRQcm9vZiIsImNoZWNrX3NwZW5kX3Byb29mIiwiZ2V0UmVzZXJ2ZVByb29mV2FsbGV0IiwiZ2V0X3Jlc2VydmVfcHJvb2Zfd2FsbGV0IiwiZ2V0UmVzZXJ2ZVByb29mQWNjb3VudCIsImFtb3VudCIsImdldF9yZXNlcnZlX3Byb29mX2FjY291bnQiLCJ0b1N0cmluZyIsImNoZWNrUmVzZXJ2ZVByb29mIiwiY2hlY2tfcmVzZXJ2ZV9wcm9vZiIsIk1vbmVyb0NoZWNrUmVzZXJ2ZSIsImdldFR4Tm90ZXMiLCJnZXRfdHhfbm90ZXMiLCJ0eE5vdGVzIiwic2V0VHhOb3RlcyIsIm5vdGVzIiwic2V0X3R4X25vdGVzIiwiZ2V0QWRkcmVzc0Jvb2tFbnRyaWVzIiwiZW50cnlJbmRpY2VzIiwiZW50cmllcyIsImVudHJ5SnNvbiIsImdldF9hZGRyZXNzX2Jvb2tfZW50cmllcyIsIk1vbmVyb0FkZHJlc3NCb29rRW50cnkiLCJhZGRBZGRyZXNzQm9va0VudHJ5IiwiZGVzY3JpcHRpb24iLCJhZGRfYWRkcmVzc19ib29rX2VudHJ5IiwiZWRpdEFkZHJlc3NCb29rRW50cnkiLCJpbmRleCIsInNldEFkZHJlc3MiLCJzZXREZXNjcmlwdGlvbiIsImVkaXRfYWRkcmVzc19ib29rX2VudHJ5IiwiZGVsZXRlQWRkcmVzc0Jvb2tFbnRyeSIsImVudHJ5SWR4IiwiZGVsZXRlX2FkZHJlc3NfYm9va19lbnRyeSIsInRhZ0FjY291bnRzIiwiYWNjb3VudEluZGljZXMiLCJ0YWdfYWNjb3VudHMiLCJ1bnRhZ0FjY291bnRzIiwiZ2V0QWNjb3VudFRhZ3MiLCJhY2NvdW50VGFncyIsImFjY291bnRUYWdKc29uIiwiZ2V0X2FjY291bnRfdGFncyIsIk1vbmVyb0FjY291bnRUYWciLCJzZXRBY2NvdW50VGFnTGFiZWwiLCJzZXRfYWNjb3VudF90YWdfbGFiZWwiLCJnZXRQYXltZW50VXJpIiwiZ2V0X3BheW1lbnRfdXJpIiwicGFyc2VQYXltZW50VXJpIiwiTW9uZXJvVHhDb25maWciLCJwYXJzZV9wYXltZW50X3VyaSIsImdldEF0dHJpYnV0ZSIsImtleSIsInZhbHVlIiwiZ2V0X2F0dHJpYnV0ZSIsInNldEF0dHJpYnV0ZSIsInZhbCIsInNldF9hdHRyaWJ1dGUiLCJzdGFydE1pbmluZyIsIm51bVRocmVhZHMiLCJiYWNrZ3JvdW5kTWluaW5nIiwiaWdub3JlQmF0dGVyeSIsImRhZW1vbiIsIk1vbmVyb0RhZW1vblJwYyIsImNvbm5lY3RUb0RhZW1vblJwYyIsInN0b3BNaW5pbmciLCJpc011bHRpc2lnSW1wb3J0TmVlZGVkIiwiaXNfbXVsdGlzaWdfaW1wb3J0X25lZWRlZCIsImlzTXVsdGlzaWciLCJpc19tdWx0aXNpZyIsImdldE11bHRpc2lnSW5mbyIsIk1vbmVyb011bHRpc2lnSW5mbyIsImdldF9tdWx0aXNpZ19pbmZvIiwicHJlcGFyZU11bHRpc2lnIiwicHJlcGFyZV9tdWx0aXNpZyIsIm1ha2VNdWx0aXNpZyIsIm11bHRpc2lnSGV4ZXMiLCJ0aHJlc2hvbGQiLCJtYWtlX211bHRpc2lnIiwiZXhjaGFuZ2VNdWx0aXNpZ0tleXMiLCJleGNoYW5nZV9tdWx0aXNpZ19rZXlzIiwiTW9uZXJvTXVsdGlzaWdJbml0UmVzdWx0IiwiZXhwb3J0TXVsdGlzaWdIZXgiLCJleHBvcnRfbXVsdGlzaWdfaGV4IiwiaW1wb3J0TXVsdGlzaWdIZXgiLCJpbXBvcnRfbXVsdGlzaWdfaGV4Iiwic2lnbk11bHRpc2lnVHhIZXgiLCJzaWduX211bHRpc2lnX3R4X2hleCIsIk1vbmVyb011bHRpc2lnU2lnblJlc3VsdCIsInN1Ym1pdE11bHRpc2lnVHhIZXgiLCJzaWduZWRNdWx0aXNpZ1R4SGV4Iiwic3VibWl0X211bHRpc2lnX3R4X2hleCIsImdldERhdGEiLCJ2aWV3T25seSIsImlzVmlld09ubHkiLCJ2aWV3cyIsImNhY2hlQnVmZmVyTG9jIiwiZ2V0X2NhY2hlX2ZpbGVfYnVmZmVyIiwidmlldyIsIkRhdGFWaWV3IiwiQXJyYXlCdWZmZXIiLCJpIiwic2V0SW50OCIsIkhFQVBVOCIsInBvaW50ZXIiLCJVaW50OEFycmF5IiwiQllURVNfUEVSX0VMRU1FTlQiLCJfZnJlZSIsIkJ1ZmZlciIsImZyb20iLCJidWZmZXIiLCJrZXlzQnVmZmVyTG9jIiwiZ2V0X2tleXNfZmlsZV9idWZmZXIiLCJ1bnNoaWZ0IiwiY2hhbmdlUGFzc3dvcmQiLCJvbGRQYXNzd29yZCIsIm5ld1Bhc3N3b3JkIiwiY2hhbmdlX3dhbGxldF9wYXNzd29yZCIsImVyck1zZyIsImNsb3NlIiwiZ2V0TnVtQmxvY2tzVG9VbmxvY2siLCJnZXRUeCIsImdldEluY29taW5nVHJhbnNmZXJzIiwiZ2V0T3V0Z29pbmdUcmFuc2ZlcnMiLCJjcmVhdGVUeCIsInJlbGF5VHgiLCJnZXRUeE5vdGUiLCJzZXRUeE5vdGUiLCJub3RlIiwicHJveHlUb1dvcmtlciIsIm5ldHdvcmtUeXBlIiwiZGFlbW9uVXJpIiwiZGFlbW9uVXNlcm5hbWUiLCJkYWVtb25QYXNzd29yZCIsIm9wZW5fd2FsbGV0X2Z1bGwiLCJrZXlzRGF0YSIsImNhY2hlRGF0YSIsImJyb3dzZXJNYWluUGF0aCIsImNvbnNvbGUiLCJlcnJvciIsImlzRW5hYmxlZCIsInNldF9saXN0ZW5lciIsIm5ld0xpc3RlbmVySGFuZGxlIiwiaGVpZ2h0IiwiZW5kSGVpZ2h0IiwicGVyY2VudERvbmUiLCJvblN5bmNQcm9ncmVzcyIsIm9uTmV3QmxvY2siLCJuZXdCYWxhbmNlU3RyIiwibmV3VW5sb2NrZWRCYWxhbmNlU3RyIiwib25CYWxhbmNlc0NoYW5nZWQiLCJhbW91bnRTdHIiLCJ1bmxvY2tUaW1lIiwiaXNMb2NrZWQiLCJvbk91dHB1dFJlY2VpdmVkIiwiYWNjb3VudElkeFN0ciIsInN1YmFkZHJlc3NJZHhTdHIiLCJvbk91dHB1dFNwZW50Iiwic2FuaXRpemVCbG9jayIsImJsb2NrIiwic2FuaXRpemVUeFdhbGxldCIsImFjY291bnQiLCJzdWJhZGRyZXNzIiwiZGVzZXJpYWxpemVCbG9ja3MiLCJibG9ja3NKc29uIiwiZGVzZXJpYWxpemVkQmxvY2tzIiwiYmxvY2tzIiwiYmxvY2tKc29uIiwiTW9uZXJvQmxvY2siLCJEZXNlcmlhbGl6YXRpb25UeXBlIiwiVFhfV0FMTEVUIiwic2V0QmxvY2siLCJnZXRIYXNoZXMiLCJ0eE1hcCIsIk1hcCIsImdldEhhc2giLCJ0eHNTb3J0ZWQiLCJ0cmFuc2ZlcnMiLCJnZXRPdXRnb2luZ1RyYW5zZmVyIiwidHJhbnNmZXIiLCJvdXRwdXRzIiwib3V0cHV0Iiwic2V0QnJvd3Nlck1haW5QYXRoIiwiUGF0aCIsIm5vcm1hbGl6ZSIsImlzQ2xvc2VkIiwid2FsbGV0RGlyIiwiZGlybmFtZSIsIm1rZGlyIiwiZGF0YSIsIndyaXRlRmlsZSIsIm9sZFBhdGgiLCJ1bmxpbmsiLCJwYXRoTmV3IiwicmVuYW1lIiwiZXhwb3J0cyIsImRlZmF1bHQiLCJNb25lcm9XYWxsZXRLZXlzUHJveHkiLCJ3YWxsZXRJZCIsImludm9rZVdvcmtlciIsImdldFdvcmtlciIsIndvcmtlciIsIndyYXBwZWRMaXN0ZW5lcnMiLCJhcmd1bWVudHMiLCJ1cmlPclJwY0Nvbm5lY3Rpb24iLCJnZXRDb25maWciLCJycGNDb25maWciLCJ3cmFwcGVkTGlzdGVuZXIiLCJXYWxsZXRXb3JrZXJMaXN0ZW5lciIsImxpc3RlbmVySWQiLCJnZXRJZCIsImFkZFdvcmtlckNhbGxiYWNrIiwiZ2V0TGlzdGVuZXIiLCJyZW1vdmVXb3JrZXJDYWxsYmFjayIsInNwbGljZSIsInJlc3VsdEpzb24iLCJibG9ja0pzb25zIiwia2V5SW1hZ2VzSnNvbiIsImFubm91bmNlU3luY1Byb2dyZXNzIiwiYW5ub3VuY2VOZXdCbG9jayIsImFubm91bmNlQmFsYW5jZXNDaGFuZ2VkIiwiTW9uZXJvT3V0cHV0V2FsbGV0Iiwic2V0QW1vdW50Iiwic2V0QWNjb3VudEluZGV4Iiwic2V0U3ViYWRkcmVzc0luZGV4Iiwic2V0SGFzaCIsInNldFZlcnNpb24iLCJzZXRVbmxvY2tUaW1lIiwic2V0VHgiLCJzZXRPdXRwdXRzIiwic2V0SXNJbmNvbWluZyIsInNldElzTG9ja2VkIiwic2V0SGVpZ2h0Iiwic2V0SXNDb25maXJtZWQiLCJzZXRJblR4UG9vbCIsInNldElzRmFpbGVkIiwiYW5ub3VuY2VPdXRwdXRSZWNlaXZlZCIsInBhcnNlSW50Iiwic2V0SW5wdXRzIiwiYW5ub3VuY2VPdXRwdXRTcGVudCIsImlkIiwiZ2V0SW5wdXRzIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvd2FsbGV0L01vbmVyb1dhbGxldEZ1bGwudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgUGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IEdlblV0aWxzIGZyb20gXCIuLi9jb21tb24vR2VuVXRpbHNcIjtcbmltcG9ydCBMaWJyYXJ5VXRpbHMgZnJvbSBcIi4uL2NvbW1vbi9MaWJyYXJ5VXRpbHNcIjtcbmltcG9ydCBUYXNrTG9vcGVyIGZyb20gXCIuLi9jb21tb24vVGFza0xvb3BlclwiO1xuaW1wb3J0IE1vbmVyb0FjY291bnQgZnJvbSBcIi4vbW9kZWwvTW9uZXJvQWNjb3VudFwiO1xuaW1wb3J0IE1vbmVyb0FjY291bnRUYWcgZnJvbSBcIi4vbW9kZWwvTW9uZXJvQWNjb3VudFRhZ1wiO1xuaW1wb3J0IE1vbmVyb0FkZHJlc3NCb29rRW50cnkgZnJvbSBcIi4vbW9kZWwvTW9uZXJvQWRkcmVzc0Jvb2tFbnRyeVwiO1xuaW1wb3J0IE1vbmVyb0Jsb2NrIGZyb20gXCIuLi9kYWVtb24vbW9kZWwvTW9uZXJvQmxvY2tcIjtcbmltcG9ydCBNb25lcm9DaGVja1R4IGZyb20gXCIuL21vZGVsL01vbmVyb0NoZWNrVHhcIjtcbmltcG9ydCBNb25lcm9DaGVja1Jlc2VydmUgZnJvbSBcIi4vbW9kZWwvTW9uZXJvQ2hlY2tSZXNlcnZlXCI7XG5pbXBvcnQgTW9uZXJvRGFlbW9uUnBjIGZyb20gXCIuLi9kYWVtb24vTW9uZXJvRGFlbW9uUnBjXCI7XG5pbXBvcnQgTW9uZXJvRXJyb3IgZnJvbSBcIi4uL2NvbW1vbi9Nb25lcm9FcnJvclwiO1xuaW1wb3J0IE1vbmVyb0luY29taW5nVHJhbnNmZXIgZnJvbSBcIi4vbW9kZWwvTW9uZXJvSW5jb21pbmdUcmFuc2ZlclwiO1xuaW1wb3J0IE1vbmVyb0ludGVncmF0ZWRBZGRyZXNzIGZyb20gXCIuL21vZGVsL01vbmVyb0ludGVncmF0ZWRBZGRyZXNzXCI7XG5pbXBvcnQgTW9uZXJvS2V5SW1hZ2UgZnJvbSBcIi4uL2RhZW1vbi9tb2RlbC9Nb25lcm9LZXlJbWFnZVwiO1xuaW1wb3J0IE1vbmVyb0tleUltYWdlSW1wb3J0UmVzdWx0IGZyb20gXCIuL21vZGVsL01vbmVyb0tleUltYWdlSW1wb3J0UmVzdWx0XCI7XG5pbXBvcnQgTW9uZXJvTXVsdGlzaWdJbmZvIGZyb20gXCIuL21vZGVsL01vbmVyb011bHRpc2lnSW5mb1wiO1xuaW1wb3J0IE1vbmVyb011bHRpc2lnSW5pdFJlc3VsdCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9NdWx0aXNpZ0luaXRSZXN1bHRcIjtcbmltcG9ydCBNb25lcm9NdWx0aXNpZ1NpZ25SZXN1bHQgZnJvbSBcIi4vbW9kZWwvTW9uZXJvTXVsdGlzaWdTaWduUmVzdWx0XCI7XG5pbXBvcnQgTW9uZXJvTmV0d29ya1R5cGUgZnJvbSBcIi4uL2RhZW1vbi9tb2RlbC9Nb25lcm9OZXR3b3JrVHlwZVwiO1xuaW1wb3J0IE1vbmVyb091dHB1dFF1ZXJ5IGZyb20gXCIuL21vZGVsL01vbmVyb091dHB1dFF1ZXJ5XCI7XG5pbXBvcnQgTW9uZXJvT3V0cHV0V2FsbGV0IGZyb20gXCIuL21vZGVsL01vbmVyb091dHB1dFdhbGxldFwiO1xuaW1wb3J0IE1vbmVyb1JwY0Nvbm5lY3Rpb24gZnJvbSBcIi4uL2NvbW1vbi9Nb25lcm9ScGNDb25uZWN0aW9uXCI7XG5pbXBvcnQgTW9uZXJvU3ViYWRkcmVzcyBmcm9tIFwiLi9tb2RlbC9Nb25lcm9TdWJhZGRyZXNzXCI7XG5pbXBvcnQgTW9uZXJvU3luY1Jlc3VsdCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9TeW5jUmVzdWx0XCI7XG5pbXBvcnQgTW9uZXJvVHJhbnNmZXIgZnJvbSBcIi4vbW9kZWwvTW9uZXJvVHJhbnNmZXJcIjtcbmltcG9ydCBNb25lcm9UcmFuc2ZlclF1ZXJ5IGZyb20gXCIuL21vZGVsL01vbmVyb1RyYW5zZmVyUXVlcnlcIjtcbmltcG9ydCBNb25lcm9UeENvbmZpZyBmcm9tIFwiLi9tb2RlbC9Nb25lcm9UeENvbmZpZ1wiO1xuaW1wb3J0IE1vbmVyb1R4UHJpb3JpdHkgZnJvbSBcIi4vbW9kZWwvTW9uZXJvVHhQcmlvcml0eVwiO1xuaW1wb3J0IE1vbmVyb1R4UXVlcnkgZnJvbSBcIi4vbW9kZWwvTW9uZXJvVHhRdWVyeVwiO1xuaW1wb3J0IE1vbmVyb1R4U2V0IGZyb20gXCIuL21vZGVsL01vbmVyb1R4U2V0XCI7XG5pbXBvcnQgTW9uZXJvVHggZnJvbSBcIi4uL2RhZW1vbi9tb2RlbC9Nb25lcm9UeFwiO1xuaW1wb3J0IE1vbmVyb1R4V2FsbGV0IGZyb20gXCIuL21vZGVsL01vbmVyb1R4V2FsbGV0XCI7XG5pbXBvcnQgTW9uZXJvV2FsbGV0IGZyb20gXCIuL01vbmVyb1dhbGxldFwiO1xuaW1wb3J0IE1vbmVyb1dhbGxldENvbmZpZyBmcm9tIFwiLi9tb2RlbC9Nb25lcm9XYWxsZXRDb25maWdcIjtcbmltcG9ydCB7IE1vbmVyb1dhbGxldEtleXMsIE1vbmVyb1dhbGxldEtleXNQcm94eSB9IGZyb20gXCIuL01vbmVyb1dhbGxldEtleXNcIjtcbmltcG9ydCBNb25lcm9XYWxsZXRMaXN0ZW5lciBmcm9tIFwiLi9tb2RlbC9Nb25lcm9XYWxsZXRMaXN0ZW5lclwiO1xuaW1wb3J0IE1vbmVyb01lc3NhZ2VTaWduYXR1cmVUeXBlIGZyb20gXCIuL21vZGVsL01vbmVyb01lc3NhZ2VTaWduYXR1cmVUeXBlXCI7XG5pbXBvcnQgTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVJlc3VsdCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9NZXNzYWdlU2lnbmF0dXJlUmVzdWx0XCI7XG5pbXBvcnQgTW9uZXJvVmVyc2lvbiBmcm9tIFwiLi4vZGFlbW9uL21vZGVsL01vbmVyb1ZlcnNpb25cIjtcbmltcG9ydCBmcyBmcm9tIFwiZnNcIjtcblxuLyoqXG4gKiBJbXBsZW1lbnRzIGEgTW9uZXJvIHdhbGxldCB1c2luZyBjbGllbnQtc2lkZSBXZWJBc3NlbWJseSBiaW5kaW5ncyB0byBtb25lcm8tcHJvamVjdCdzIHdhbGxldDIgaW4gQysrLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9XYWxsZXRGdWxsIGV4dGVuZHMgTW9uZXJvV2FsbGV0S2V5cyB7XG5cbiAgLy8gc3RhdGljIHZhcmlhYmxlc1xuICBwcm90ZWN0ZWQgc3RhdGljIHJlYWRvbmx5IERFRkFVTFRfU1lOQ19QRVJJT0RfSU5fTVMgPSAyMDAwMDtcbiAgcHJvdGVjdGVkIHN0YXRpYyBGUztcblxuICAvLyBpbnN0YW5jZSB2YXJpYWJsZXNcbiAgcHJvdGVjdGVkIHBhdGg6IHN0cmluZztcbiAgcHJvdGVjdGVkIHBhc3N3b3JkOiBzdHJpbmc7XG4gIHByb3RlY3RlZCBsaXN0ZW5lcnM6IE1vbmVyb1dhbGxldExpc3RlbmVyW107XG4gIHByb3RlY3RlZCBmczogYW55O1xuICBwcm90ZWN0ZWQgd2FzbUxpc3RlbmVyOiBXYWxsZXRXYXNtTGlzdGVuZXI7XG4gIHByb3RlY3RlZCB3YXNtTGlzdGVuZXJIYW5kbGU6IG51bWJlcjtcbiAgcHJvdGVjdGVkIHJlamVjdFVuYXV0aG9yaXplZDogYm9vbGVhbjtcbiAgcHJvdGVjdGVkIHJlamVjdFVuYXV0aG9yaXplZENvbmZpZ0lkOiBzdHJpbmc7XG4gIHByb3RlY3RlZCBzeW5jUGVyaW9kSW5NczogbnVtYmVyO1xuICBwcm90ZWN0ZWQgc3luY0xvb3BlcjogVGFza0xvb3BlcjtcbiAgcHJvdGVjdGVkIGJyb3dzZXJNYWluUGF0aDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBJbnRlcm5hbCBjb25zdHJ1Y3RvciB3aGljaCBpcyBnaXZlbiB0aGUgbWVtb3J5IGFkZHJlc3Mgb2YgYSBDKysgd2FsbGV0IGluc3RhbmNlLlxuICAgKiBcbiAgICogVGhpcyBjb25zdHJ1Y3RvciBzaG91bGQgYmUgY2FsbGVkIHRocm91Z2ggc3RhdGljIHdhbGxldCBjcmVhdGlvbiB1dGlsaXRpZXMgaW4gdGhpcyBjbGFzcy5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBjcHBBZGRyZXNzIC0gYWRkcmVzcyBvZiB0aGUgd2FsbGV0IGluc3RhbmNlIGluIEMrK1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIHBhdGggb2YgdGhlIHdhbGxldCBpbnN0YW5jZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGFzc3dvcmQgLSBwYXNzd29yZCBvZiB0aGUgd2FsbGV0IGluc3RhbmNlXG4gICAqIEBwYXJhbSB7RmlsZVN5c3RlbX0gZnMgLSBub2RlLmpzLWNvbXBhdGlibGUgZmlsZSBzeXN0ZW0gdG8gcmVhZC93cml0ZSB3YWxsZXQgZmlsZXNcbiAgICogQHBhcmFtIHtib29sZWFufSByZWplY3RVbmF1dGhvcml6ZWQgLSBzcGVjaWZpZXMgaWYgdW5hdXRob3JpemVkIHJlcXVlc3RzIChlLmcuIHNlbGYtc2lnbmVkIGNlcnRpZmljYXRlcykgc2hvdWxkIGJlIHJlamVjdGVkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWplY3RVbmF1dGhvcml6ZWRGbklkIC0gdW5pcXVlIGlkZW50aWZpZXIgZm9yIGh0dHBfY2xpZW50X3dhc20gdG8gcXVlcnkgcmVqZWN0VW5hdXRob3JpemVkXG4gICAqIEBwYXJhbSB7TW9uZXJvV2FsbGV0RnVsbFByb3h5fSB3YWxsZXRQcm94eSAtIHByb3h5IHRvIGludm9rZSB3YWxsZXQgb3BlcmF0aW9ucyBpbiBhIHdlYiB3b3JrZXJcbiAgICogXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBjb25zdHJ1Y3RvcihjcHBBZGRyZXNzLCBwYXRoLCBwYXNzd29yZCwgZnMsIHJlamVjdFVuYXV0aG9yaXplZCwgcmVqZWN0VW5hdXRob3JpemVkRm5JZCwgd2FsbGV0UHJveHk/OiBNb25lcm9XYWxsZXRGdWxsUHJveHkpIHtcbiAgICBzdXBlcihjcHBBZGRyZXNzLCB3YWxsZXRQcm94eSk7XG4gICAgaWYgKHdhbGxldFByb3h5KSByZXR1cm47XG4gICAgdGhpcy5wYXRoID0gcGF0aDtcbiAgICB0aGlzLnBhc3N3b3JkID0gcGFzc3dvcmQ7XG4gICAgdGhpcy5saXN0ZW5lcnMgPSBbXTtcbiAgICB0aGlzLmZzID0gZnMgPyBmcyA6IChwYXRoID8gTW9uZXJvV2FsbGV0RnVsbC5nZXRGcygpIDogdW5kZWZpbmVkKTtcbiAgICB0aGlzLl9pc0Nsb3NlZCA9IGZhbHNlO1xuICAgIHRoaXMud2FzbUxpc3RlbmVyID0gbmV3IFdhbGxldFdhc21MaXN0ZW5lcih0aGlzKTsgLy8gcmVjZWl2ZXMgbm90aWZpY2F0aW9ucyBmcm9tIHdhc20gYysrXG4gICAgdGhpcy53YXNtTGlzdGVuZXJIYW5kbGUgPSAwOyAgICAgICAgICAgICAgICAgICAgICAvLyBtZW1vcnkgYWRkcmVzcyBvZiB0aGUgd2FsbGV0IGxpc3RlbmVyIGluIGMrK1xuICAgIHRoaXMucmVqZWN0VW5hdXRob3JpemVkID0gcmVqZWN0VW5hdXRob3JpemVkO1xuICAgIHRoaXMucmVqZWN0VW5hdXRob3JpemVkQ29uZmlnSWQgPSByZWplY3RVbmF1dGhvcml6ZWRGbklkO1xuICAgIHRoaXMuc3luY1BlcmlvZEluTXMgPSBNb25lcm9XYWxsZXRGdWxsLkRFRkFVTFRfU1lOQ19QRVJJT0RfSU5fTVM7XG4gICAgTGlicmFyeVV0aWxzLnNldFJlamVjdFVuYXV0aG9yaXplZEZuKHJlamVjdFVuYXV0aG9yaXplZEZuSWQsICgpID0+IHRoaXMucmVqZWN0VW5hdXRob3JpemVkKTsgLy8gcmVnaXN0ZXIgZm4gaW5mb3JtaW5nIGlmIHVuYXV0aG9yaXplZCByZXFzIHNob3VsZCBiZSByZWplY3RlZFxuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIFNUQVRJQyBVVElMSVRJRVMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgXG4gIC8qKlxuICAgKiBDaGVjayBpZiBhIHdhbGxldCBleGlzdHMgYXQgYSBnaXZlbiBwYXRoLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBwYXRoIG9mIHRoZSB3YWxsZXQgb24gdGhlIGZpbGUgc3lzdGVtXG4gICAqIEBwYXJhbSB7YW55fSBmcyAtIGZpbGUgc3lzdGVtIGNvbXBhdGlibGUgd2l0aCBOb2RlLmpzIGBmcy5wcm9taXNlc2AgQVBJIChkZWZhdWx0cyB0byBkaXNrIG9yIGluLW1lbW9yeSBGUyBpZiBicm93c2VyKVxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIGEgd2FsbGV0IGV4aXN0cyBhdCB0aGUgZ2l2ZW4gcGF0aCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgd2FsbGV0RXhpc3RzKHBhdGgsIGZzKSB7XG4gICAgYXNzZXJ0KHBhdGgsIFwiTXVzdCBwcm92aWRlIGEgcGF0aCB0byBsb29rIGZvciBhIHdhbGxldFwiKTtcbiAgICBpZiAoIWZzKSBmcyA9IE1vbmVyb1dhbGxldEZ1bGwuZ2V0RnMoKTtcbiAgICBpZiAoIWZzKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJNdXN0IHByb3ZpZGUgZmlsZSBzeXN0ZW0gdG8gY2hlY2sgaWYgd2FsbGV0IGV4aXN0c1wiKTtcbiAgICBsZXQgZXhpc3RzID0gYXdhaXQgTGlicmFyeVV0aWxzLmV4aXN0cyhmcywgcGF0aCArIFwiLmtleXNcIik7XG4gICAgTGlicmFyeVV0aWxzLmxvZygxLCBcIldhbGxldCBleGlzdHMgYXQgXCIgKyBwYXRoICsgXCI6IFwiICsgZXhpc3RzKTtcbiAgICByZXR1cm4gZXhpc3RzO1xuICB9XG4gIFxuICBzdGF0aWMgYXN5bmMgb3BlbldhbGxldChjb25maWc6IFBhcnRpYWw8TW9uZXJvV2FsbGV0Q29uZmlnPikge1xuXG4gICAgLy8gdmFsaWRhdGUgY29uZmlnXG4gICAgY29uZmlnID0gbmV3IE1vbmVyb1dhbGxldENvbmZpZyhjb25maWcpO1xuICAgIGlmIChjb25maWcuZ2V0UHJveHlUb1dvcmtlcigpID09PSB1bmRlZmluZWQpIGNvbmZpZy5zZXRQcm94eVRvV29ya2VyKHRydWUpO1xuICAgIGlmIChjb25maWcuZ2V0U2VlZCgpICE9PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBzcGVjaWZ5IHNlZWQgd2hlbiBvcGVuaW5nIHdhbGxldFwiKTtcbiAgICBpZiAoY29uZmlnLmdldFNlZWRPZmZzZXQoKSAhPT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJDYW5ub3Qgc3BlY2lmeSBzZWVkIG9mZnNldCB3aGVuIG9wZW5pbmcgd2FsbGV0XCIpO1xuICAgIGlmIChjb25maWcuZ2V0UHJpbWFyeUFkZHJlc3MoKSAhPT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJDYW5ub3Qgc3BlY2lmeSBwcmltYXJ5IGFkZHJlc3Mgd2hlbiBvcGVuaW5nIHdhbGxldFwiKTtcbiAgICBpZiAoY29uZmlnLmdldFByaXZhdGVWaWV3S2V5KCkgIT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ2Fubm90IHNwZWNpZnkgcHJpdmF0ZSB2aWV3IGtleSB3aGVuIG9wZW5pbmcgd2FsbGV0XCIpO1xuICAgIGlmIChjb25maWcuZ2V0UHJpdmF0ZVNwZW5kS2V5KCkgIT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ2Fubm90IHNwZWNpZnkgcHJpdmF0ZSBzcGVuZCBrZXkgd2hlbiBvcGVuaW5nIHdhbGxldFwiKTtcbiAgICBpZiAoY29uZmlnLmdldFJlc3RvcmVIZWlnaHQoKSAhPT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJDYW5ub3Qgc3BlY2lmeSByZXN0b3JlIGhlaWdodCB3aGVuIG9wZW5pbmcgd2FsbGV0XCIpO1xuICAgIGlmIChjb25maWcuZ2V0TGFuZ3VhZ2UoKSAhPT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJDYW5ub3Qgc3BlY2lmeSBsYW5ndWFnZSB3aGVuIG9wZW5pbmcgd2FsbGV0XCIpO1xuICAgIGlmIChjb25maWcuZ2V0U2F2ZUN1cnJlbnQoKSA9PT0gdHJ1ZSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ2Fubm90IHNhdmUgY3VycmVudCB3YWxsZXQgd2hlbiBvcGVuaW5nIGZ1bGwgd2FsbGV0XCIpO1xuICAgIGlmIChjb25maWcuZ2V0RnMoKSA9PT0gdW5kZWZpbmVkKSBjb25maWcuc2V0RnMoTW9uZXJvV2FsbGV0RnVsbC5nZXRGcygpKTtcblxuICAgIC8vIHNldCBzZXJ2ZXIgZnJvbSBjb25uZWN0aW9uIG1hbmFnZXIgaWYgcHJvdmlkZWRcbiAgICBpZiAoY29uZmlnLmdldENvbm5lY3Rpb25NYW5hZ2VyKCkpIHtcbiAgICAgIGlmIChjb25maWcuZ2V0U2VydmVyKCkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIldhbGxldCBjYW4gYmUgb3BlbmVkIHdpdGggYSBzZXJ2ZXIgb3IgY29ubmVjdGlvbiBtYW5hZ2VyIGJ1dCBub3QgYm90aFwiKTtcbiAgICAgIGNvbmZpZy5zZXRTZXJ2ZXIoY29uZmlnLmdldENvbm5lY3Rpb25NYW5hZ2VyKCkuZ2V0Q29ubmVjdGlvbigpKTtcbiAgICB9XG5cbiAgICAvLyByZWFkIHdhbGxldCBkYXRhIGZyb20gZGlzayB1bmxlc3MgcHJvdmlkZWRcbiAgICBpZiAoIWNvbmZpZy5nZXRLZXlzRGF0YSgpKSB7XG4gICAgICBsZXQgZnMgPSBjb25maWcuZ2V0RnMoKTtcbiAgICAgIGlmICghZnMpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk11c3QgcHJvdmlkZSBmaWxlIHN5c3RlbSB0byByZWFkIHdhbGxldCBkYXRhIGZyb21cIik7XG4gICAgICBpZiAoIWF3YWl0IHRoaXMud2FsbGV0RXhpc3RzKGNvbmZpZy5nZXRQYXRoKCksIGZzKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiV2FsbGV0IGRvZXMgbm90IGV4aXN0IGF0IHBhdGg6IFwiICsgY29uZmlnLmdldFBhdGgoKSk7XG4gICAgICBjb25maWcuc2V0S2V5c0RhdGEoYXdhaXQgZnMucmVhZEZpbGUoY29uZmlnLmdldFBhdGgoKSArIFwiLmtleXNcIikpO1xuICAgICAgY29uZmlnLnNldENhY2hlRGF0YShhd2FpdCBMaWJyYXJ5VXRpbHMuZXhpc3RzKGZzLCBjb25maWcuZ2V0UGF0aCgpKSA/IGF3YWl0IGZzLnJlYWRGaWxlKGNvbmZpZy5nZXRQYXRoKCkpIDogXCJcIik7XG4gICAgfVxuXG4gICAgLy8gb3BlbiB3YWxsZXQgZnJvbSBkYXRhXG4gICAgY29uc3Qgd2FsbGV0ID0gYXdhaXQgTW9uZXJvV2FsbGV0RnVsbC5vcGVuV2FsbGV0RGF0YShjb25maWcpO1xuXG4gICAgLy8gc2V0IGNvbm5lY3Rpb24gbWFuYWdlclxuICAgIGF3YWl0IHdhbGxldC5zZXRDb25uZWN0aW9uTWFuYWdlcihjb25maWcuZ2V0Q29ubmVjdGlvbk1hbmFnZXIoKSk7XG4gICAgcmV0dXJuIHdhbGxldDtcbiAgfVxuICBcbiAgc3RhdGljIGFzeW5jIGNyZWF0ZVdhbGxldChjb25maWc6IE1vbmVyb1dhbGxldENvbmZpZyk6IFByb21pc2U8TW9uZXJvV2FsbGV0RnVsbD4ge1xuXG4gICAgLy8gdmFsaWRhdGUgY29uZmlnXG4gICAgaWYgKGNvbmZpZyA9PT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJNdXN0IHByb3ZpZGUgY29uZmlnIHRvIGNyZWF0ZSB3YWxsZXRcIik7XG4gICAgaWYgKGNvbmZpZy5nZXRTZWVkKCkgIT09IHVuZGVmaW5lZCAmJiAoY29uZmlnLmdldFByaW1hcnlBZGRyZXNzKCkgIT09IHVuZGVmaW5lZCB8fCBjb25maWcuZ2V0UHJpdmF0ZVZpZXdLZXkoKSAhPT0gdW5kZWZpbmVkIHx8IGNvbmZpZy5nZXRQcml2YXRlU3BlbmRLZXkoKSAhPT0gdW5kZWZpbmVkKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiV2FsbGV0IG1heSBiZSBpbml0aWFsaXplZCB3aXRoIGEgc2VlZCBvciBrZXlzIGJ1dCBub3QgYm90aFwiKTtcbiAgICBpZiAoY29uZmlnLmdldE5ldHdvcmtUeXBlKCkgPT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTXVzdCBwcm92aWRlIGEgbmV0d29ya1R5cGU6ICdtYWlubmV0JywgJ3Rlc3RuZXQnIG9yICdzdGFnZW5ldCdcIik7XG4gICAgTW9uZXJvTmV0d29ya1R5cGUudmFsaWRhdGUoY29uZmlnLmdldE5ldHdvcmtUeXBlKCkpO1xuICAgIGlmIChjb25maWcuZ2V0U2F2ZUN1cnJlbnQoKSA9PT0gdHJ1ZSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ2Fubm90IHNhdmUgY3VycmVudCB3YWxsZXQgd2hlbiBjcmVhdGluZyBmdWxsIFdBU00gd2FsbGV0XCIpO1xuICAgIGlmIChjb25maWcuZ2V0UGF0aCgpID09PSB1bmRlZmluZWQpIGNvbmZpZy5zZXRQYXRoKFwiXCIpO1xuICAgIGlmIChjb25maWcuZ2V0UGF0aCgpICYmIGF3YWl0IE1vbmVyb1dhbGxldEZ1bGwud2FsbGV0RXhpc3RzKGNvbmZpZy5nZXRQYXRoKCksIGNvbmZpZy5nZXRGcygpKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiV2FsbGV0IGFscmVhZHkgZXhpc3RzOiBcIiArIGNvbmZpZy5nZXRQYXRoKCkpO1xuICAgIGlmIChjb25maWcuZ2V0UGFzc3dvcmQoKSA9PT0gdW5kZWZpbmVkKSBjb25maWcuc2V0UGFzc3dvcmQoXCJcIik7XG5cbiAgICAvLyBzZXQgc2VydmVyIGZyb20gY29ubmVjdGlvbiBtYW5hZ2VyIGlmIHByb3ZpZGVkXG4gICAgaWYgKGNvbmZpZy5nZXRDb25uZWN0aW9uTWFuYWdlcigpKSB7XG4gICAgICBpZiAoY29uZmlnLmdldFNlcnZlcigpKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJXYWxsZXQgY2FuIGJlIGNyZWF0ZWQgd2l0aCBhIHNlcnZlciBvciBjb25uZWN0aW9uIG1hbmFnZXIgYnV0IG5vdCBib3RoXCIpO1xuICAgICAgY29uZmlnLnNldFNlcnZlcihjb25maWcuZ2V0Q29ubmVjdGlvbk1hbmFnZXIoKS5nZXRDb25uZWN0aW9uKCkpO1xuICAgIH1cblxuICAgIC8vIGNyZWF0ZSBwcm94aWVkIG9yIGxvY2FsIHdhbGxldFxuICAgIGxldCB3YWxsZXQ7XG4gICAgaWYgKGNvbmZpZy5nZXRQcm94eVRvV29ya2VyKCkgPT09IHVuZGVmaW5lZCkgY29uZmlnLnNldFByb3h5VG9Xb3JrZXIodHJ1ZSk7XG4gICAgaWYgKGNvbmZpZy5nZXRQcm94eVRvV29ya2VyKCkpIHtcbiAgICAgIGxldCB3YWxsZXRQcm94eSA9IGF3YWl0IE1vbmVyb1dhbGxldEZ1bGxQcm94eS5jcmVhdGVXYWxsZXQoY29uZmlnKTtcbiAgICAgIHdhbGxldCA9IG5ldyBNb25lcm9XYWxsZXRGdWxsKHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHdhbGxldFByb3h5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKGNvbmZpZy5nZXRTZWVkKCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBpZiAoY29uZmlnLmdldExhbmd1YWdlKCkgIT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ2Fubm90IHByb3ZpZGUgbGFuZ3VhZ2Ugd2hlbiBjcmVhdGluZyB3YWxsZXQgZnJvbSBzZWVkXCIpO1xuICAgICAgICB3YWxsZXQgPSBhd2FpdCBNb25lcm9XYWxsZXRGdWxsLmNyZWF0ZVdhbGxldEZyb21TZWVkKGNvbmZpZyk7XG4gICAgICB9IGVsc2UgaWYgKGNvbmZpZy5nZXRQcml2YXRlU3BlbmRLZXkoKSAhPT0gdW5kZWZpbmVkIHx8IGNvbmZpZy5nZXRQcmltYXJ5QWRkcmVzcygpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgaWYgKGNvbmZpZy5nZXRTZWVkT2Zmc2V0KCkgIT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ2Fubm90IHByb3ZpZGUgc2VlZE9mZnNldCB3aGVuIGNyZWF0aW5nIHdhbGxldCBmcm9tIGtleXNcIik7XG4gICAgICAgIHdhbGxldCA9IGF3YWl0IE1vbmVyb1dhbGxldEZ1bGwuY3JlYXRlV2FsbGV0RnJvbUtleXMoY29uZmlnKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChjb25maWcuZ2V0U2VlZE9mZnNldCgpICE9PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBwcm92aWRlIHNlZWRPZmZzZXQgd2hlbiBjcmVhdGluZyByYW5kb20gd2FsbGV0XCIpO1xuICAgICAgICBpZiAoY29uZmlnLmdldFJlc3RvcmVIZWlnaHQoKSAhPT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJDYW5ub3QgcHJvdmlkZSByZXN0b3JlSGVpZ2h0IHdoZW4gY3JlYXRpbmcgcmFuZG9tIHdhbGxldFwiKTtcbiAgICAgICAgd2FsbGV0ID0gYXdhaXQgTW9uZXJvV2FsbGV0RnVsbC5jcmVhdGVXYWxsZXRSYW5kb20oY29uZmlnKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gc2V0IGNvbm5lY3Rpb24gbWFuYWdlclxuICAgIGF3YWl0IHdhbGxldC5zZXRDb25uZWN0aW9uTWFuYWdlcihjb25maWcuZ2V0Q29ubmVjdGlvbk1hbmFnZXIoKSk7XG4gICAgcmV0dXJuIHdhbGxldDtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIHN0YXRpYyBhc3luYyBjcmVhdGVXYWxsZXRGcm9tU2VlZChjb25maWc6IE1vbmVyb1dhbGxldENvbmZpZyk6IFByb21pc2U8TW9uZXJvV2FsbGV0RnVsbD4ge1xuXG4gICAgLy8gdmFsaWRhdGUgYW5kIG5vcm1hbGl6ZSBwYXJhbXNcbiAgICBsZXQgZGFlbW9uQ29ubmVjdGlvbiA9IGNvbmZpZy5nZXRTZXJ2ZXIoKTtcbiAgICBsZXQgcmVqZWN0VW5hdXRob3JpemVkID0gZGFlbW9uQ29ubmVjdGlvbiA/IGRhZW1vbkNvbm5lY3Rpb24uZ2V0UmVqZWN0VW5hdXRob3JpemVkKCkgOiB0cnVlO1xuICAgIGlmIChjb25maWcuZ2V0UmVzdG9yZUhlaWdodCgpID09PSB1bmRlZmluZWQpIGNvbmZpZy5zZXRSZXN0b3JlSGVpZ2h0KDApO1xuICAgIGlmIChjb25maWcuZ2V0U2VlZE9mZnNldCgpID09PSB1bmRlZmluZWQpIGNvbmZpZy5zZXRTZWVkT2Zmc2V0KFwiXCIpO1xuICAgIFxuICAgIC8vIGxvYWQgZnVsbCB3YXNtIG1vZHVsZVxuICAgIGxldCBtb2R1bGUgPSBhd2FpdCBMaWJyYXJ5VXRpbHMubG9hZFdhc21Nb2R1bGUoKTtcbiAgICBcbiAgICAvLyBjcmVhdGUgd2FsbGV0IGluIHF1ZXVlXG4gICAgbGV0IHdhbGxldCA9IGF3YWl0IG1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcblxuICAgICAgICAvLyByZWdpc3RlciBmbiBpbmZvcm1pbmcgaWYgdW5hdXRob3JpemVkIHJlcXMgc2hvdWxkIGJlIHJlamVjdGVkXG4gICAgICAgIGxldCByZWplY3RVbmF1dGhvcml6ZWRGbklkID0gR2VuVXRpbHMuZ2V0VVVJRCgpO1xuICAgICAgICBMaWJyYXJ5VXRpbHMuc2V0UmVqZWN0VW5hdXRob3JpemVkRm4ocmVqZWN0VW5hdXRob3JpemVkRm5JZCwgKCkgPT4gcmVqZWN0VW5hdXRob3JpemVkKTtcbiAgICAgICAgXG4gICAgICAgIC8vIGNyZWF0ZSB3YWxsZXQgaW4gd2FzbSB3aGljaCBpbnZva2VzIGNhbGxiYWNrIHdoZW4gZG9uZVxuICAgICAgICBtb2R1bGUuY3JlYXRlX2Z1bGxfd2FsbGV0KEpTT04uc3RyaW5naWZ5KGNvbmZpZy50b0pzb24oKSksIHJlamVjdFVuYXV0aG9yaXplZEZuSWQsIGFzeW5jIChjcHBBZGRyZXNzKSA9PiB7XG4gICAgICAgICAgaWYgKHR5cGVvZiBjcHBBZGRyZXNzID09PSBcInN0cmluZ1wiKSByZWplY3QobmV3IE1vbmVyb0Vycm9yKGNwcEFkZHJlc3MpKTtcbiAgICAgICAgICBlbHNlIHJlc29sdmUobmV3IE1vbmVyb1dhbGxldEZ1bGwoY3BwQWRkcmVzcywgY29uZmlnLmdldFBhdGgoKSwgY29uZmlnLmdldFBhc3N3b3JkKCksIGNvbmZpZy5nZXRGcygpLCBjb25maWcuZ2V0U2VydmVyKCkgPyBjb25maWcuZ2V0U2VydmVyKCkuZ2V0UmVqZWN0VW5hdXRob3JpemVkKCkgOiB1bmRlZmluZWQsIHJlamVjdFVuYXV0aG9yaXplZEZuSWQpKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBcbiAgICAvLyBzYXZlIHdhbGxldFxuICAgIGlmIChjb25maWcuZ2V0UGF0aCgpKSBhd2FpdCB3YWxsZXQuc2F2ZSgpO1xuICAgIHJldHVybiB3YWxsZXQ7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgYXN5bmMgY3JlYXRlV2FsbGV0RnJvbUtleXMoY29uZmlnOiBNb25lcm9XYWxsZXRDb25maWcpOiBQcm9taXNlPE1vbmVyb1dhbGxldEZ1bGw+IHtcblxuICAgIC8vIHZhbGlkYXRlIGFuZCBub3JtYWxpemUgcGFyYW1zXG4gICAgTW9uZXJvTmV0d29ya1R5cGUudmFsaWRhdGUoY29uZmlnLmdldE5ldHdvcmtUeXBlKCkpO1xuICAgIGlmIChjb25maWcuZ2V0UHJpbWFyeUFkZHJlc3MoKSA9PT0gdW5kZWZpbmVkKSBjb25maWcuc2V0UHJpbWFyeUFkZHJlc3MoXCJcIik7XG4gICAgaWYgKGNvbmZpZy5nZXRQcml2YXRlVmlld0tleSgpID09PSB1bmRlZmluZWQpIGNvbmZpZy5zZXRQcml2YXRlVmlld0tleShcIlwiKTtcbiAgICBpZiAoY29uZmlnLmdldFByaXZhdGVTcGVuZEtleSgpID09PSB1bmRlZmluZWQpIGNvbmZpZy5zZXRQcml2YXRlU3BlbmRLZXkoXCJcIik7XG4gICAgbGV0IGRhZW1vbkNvbm5lY3Rpb24gPSBjb25maWcuZ2V0U2VydmVyKCk7XG4gICAgbGV0IHJlamVjdFVuYXV0aG9yaXplZCA9IGRhZW1vbkNvbm5lY3Rpb24gPyBkYWVtb25Db25uZWN0aW9uLmdldFJlamVjdFVuYXV0aG9yaXplZCgpIDogdHJ1ZTtcbiAgICBpZiAoY29uZmlnLmdldFJlc3RvcmVIZWlnaHQoKSA9PT0gdW5kZWZpbmVkKSBjb25maWcuc2V0UmVzdG9yZUhlaWdodCgwKTtcbiAgICBpZiAoY29uZmlnLmdldExhbmd1YWdlKCkgPT09IHVuZGVmaW5lZCkgY29uZmlnLnNldExhbmd1YWdlKFwiRW5nbGlzaFwiKTtcbiAgICBcbiAgICAvLyBsb2FkIGZ1bGwgd2FzbSBtb2R1bGVcbiAgICBsZXQgbW9kdWxlID0gYXdhaXQgTGlicmFyeVV0aWxzLmxvYWRXYXNtTW9kdWxlKCk7XG4gICAgXG4gICAgLy8gY3JlYXRlIHdhbGxldCBpbiBxdWV1ZVxuICAgIGxldCB3YWxsZXQgPSBhd2FpdCBtb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIFxuICAgICAgICAvLyByZWdpc3RlciBmbiBpbmZvcm1pbmcgaWYgdW5hdXRob3JpemVkIHJlcXMgc2hvdWxkIGJlIHJlamVjdGVkXG4gICAgICAgIGxldCByZWplY3RVbmF1dGhvcml6ZWRGbklkID0gR2VuVXRpbHMuZ2V0VVVJRCgpO1xuICAgICAgICBMaWJyYXJ5VXRpbHMuc2V0UmVqZWN0VW5hdXRob3JpemVkRm4ocmVqZWN0VW5hdXRob3JpemVkRm5JZCwgKCkgPT4gcmVqZWN0VW5hdXRob3JpemVkKTtcbiAgICAgICAgXG4gICAgICAgIC8vIGNyZWF0ZSB3YWxsZXQgaW4gd2FzbSB3aGljaCBpbnZva2VzIGNhbGxiYWNrIHdoZW4gZG9uZVxuICAgICAgICBtb2R1bGUuY3JlYXRlX2Z1bGxfd2FsbGV0KEpTT04uc3RyaW5naWZ5KGNvbmZpZy50b0pzb24oKSksIHJlamVjdFVuYXV0aG9yaXplZEZuSWQsIGFzeW5jIChjcHBBZGRyZXNzKSA9PiB7XG4gICAgICAgICAgaWYgKHR5cGVvZiBjcHBBZGRyZXNzID09PSBcInN0cmluZ1wiKSByZWplY3QobmV3IE1vbmVyb0Vycm9yKGNwcEFkZHJlc3MpKTtcbiAgICAgICAgICBlbHNlIHJlc29sdmUobmV3IE1vbmVyb1dhbGxldEZ1bGwoY3BwQWRkcmVzcywgY29uZmlnLmdldFBhdGgoKSwgY29uZmlnLmdldFBhc3N3b3JkKCksIGNvbmZpZy5nZXRGcygpLCBjb25maWcuZ2V0U2VydmVyKCkgPyBjb25maWcuZ2V0U2VydmVyKCkuZ2V0UmVqZWN0VW5hdXRob3JpemVkKCkgOiB1bmRlZmluZWQsIHJlamVjdFVuYXV0aG9yaXplZEZuSWQpKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBcbiAgICAvLyBzYXZlIHdhbGxldFxuICAgIGlmIChjb25maWcuZ2V0UGF0aCgpKSBhd2FpdCB3YWxsZXQuc2F2ZSgpO1xuICAgIHJldHVybiB3YWxsZXQ7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgYXN5bmMgY3JlYXRlV2FsbGV0UmFuZG9tKGNvbmZpZzogTW9uZXJvV2FsbGV0Q29uZmlnKTogUHJvbWlzZTxNb25lcm9XYWxsZXRGdWxsPiB7XG4gICAgXG4gICAgLy8gdmFsaWRhdGUgYW5kIG5vcm1hbGl6ZSBwYXJhbXNcbiAgICBpZiAoY29uZmlnLmdldExhbmd1YWdlKCkgPT09IHVuZGVmaW5lZCkgY29uZmlnLnNldExhbmd1YWdlKFwiRW5nbGlzaFwiKTtcbiAgICBsZXQgZGFlbW9uQ29ubmVjdGlvbiA9IGNvbmZpZy5nZXRTZXJ2ZXIoKTtcbiAgICBsZXQgcmVqZWN0VW5hdXRob3JpemVkID0gZGFlbW9uQ29ubmVjdGlvbiA/IGRhZW1vbkNvbm5lY3Rpb24uZ2V0UmVqZWN0VW5hdXRob3JpemVkKCkgOiB0cnVlO1xuICAgIFxuICAgIC8vIGxvYWQgd2FzbSBtb2R1bGVcbiAgICBsZXQgbW9kdWxlID0gYXdhaXQgTGlicmFyeVV0aWxzLmxvYWRXYXNtTW9kdWxlKCk7XG4gICAgXG4gICAgLy8gY3JlYXRlIHdhbGxldCBpbiBxdWV1ZVxuICAgIGxldCB3YWxsZXQgPSBhd2FpdCBtb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIFxuICAgICAgICAvLyByZWdpc3RlciBmbiBpbmZvcm1pbmcgaWYgdW5hdXRob3JpemVkIHJlcXMgc2hvdWxkIGJlIHJlamVjdGVkXG4gICAgICAgIGxldCByZWplY3RVbmF1dGhvcml6ZWRGbklkID0gR2VuVXRpbHMuZ2V0VVVJRCgpO1xuICAgICAgICBMaWJyYXJ5VXRpbHMuc2V0UmVqZWN0VW5hdXRob3JpemVkRm4ocmVqZWN0VW5hdXRob3JpemVkRm5JZCwgKCkgPT4gcmVqZWN0VW5hdXRob3JpemVkKTtcbiAgICAgIFxuICAgICAgICAvLyBjcmVhdGUgd2FsbGV0IGluIHdhc20gd2hpY2ggaW52b2tlcyBjYWxsYmFjayB3aGVuIGRvbmVcbiAgICAgICAgbW9kdWxlLmNyZWF0ZV9mdWxsX3dhbGxldChKU09OLnN0cmluZ2lmeShjb25maWcudG9Kc29uKCkpLCByZWplY3RVbmF1dGhvcml6ZWRGbklkLCBhc3luYyAoY3BwQWRkcmVzcykgPT4ge1xuICAgICAgICAgIGlmICh0eXBlb2YgY3BwQWRkcmVzcyA9PT0gXCJzdHJpbmdcIikgcmVqZWN0KG5ldyBNb25lcm9FcnJvcihjcHBBZGRyZXNzKSk7XG4gICAgICAgICAgZWxzZSByZXNvbHZlKG5ldyBNb25lcm9XYWxsZXRGdWxsKGNwcEFkZHJlc3MsIGNvbmZpZy5nZXRQYXRoKCksIGNvbmZpZy5nZXRQYXNzd29yZCgpLCBjb25maWcuZ2V0RnMoKSwgY29uZmlnLmdldFNlcnZlcigpID8gY29uZmlnLmdldFNlcnZlcigpLmdldFJlamVjdFVuYXV0aG9yaXplZCgpIDogdW5kZWZpbmVkLCByZWplY3RVbmF1dGhvcml6ZWRGbklkKSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gICAgXG4gICAgLy8gc2F2ZSB3YWxsZXRcbiAgICBpZiAoY29uZmlnLmdldFBhdGgoKSkgYXdhaXQgd2FsbGV0LnNhdmUoKTtcbiAgICByZXR1cm4gd2FsbGV0O1xuICB9XG4gIFxuICBzdGF0aWMgYXN5bmMgZ2V0U2VlZExhbmd1YWdlcygpIHtcbiAgICBsZXQgbW9kdWxlID0gYXdhaXQgTGlicmFyeVV0aWxzLmxvYWRXYXNtTW9kdWxlKCk7XG4gICAgcmV0dXJuIG1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgcmV0dXJuIEpTT04ucGFyc2UobW9kdWxlLmdldF9rZXlzX3dhbGxldF9zZWVkX2xhbmd1YWdlcygpKS5sYW5ndWFnZXM7XG4gICAgfSk7XG4gIH1cblxuICBzdGF0aWMgZ2V0RnMoKSB7XG4gICAgaWYgKCFNb25lcm9XYWxsZXRGdWxsLkZTKSBNb25lcm9XYWxsZXRGdWxsLkZTID0gZnMucHJvbWlzZXM7XG4gICAgcmV0dXJuIE1vbmVyb1dhbGxldEZ1bGwuRlM7XG4gIH1cbiAgXG4gIC8vIC0tLS0tLS0tLS0tLSBXQUxMRVQgTUVUSE9EUyBTUEVDSUZJQyBUTyBXQVNNIElNUExFTUVOVEFUSU9OIC0tLS0tLS0tLS0tLS0tXG5cbiAgLy8gVE9ETzogbW92ZSB0aGVzZSB0byBNb25lcm9XYWxsZXQudHMsIG90aGVycyBjYW4gYmUgdW5zdXBwb3J0ZWRcbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIG1heGltdW0gaGVpZ2h0IG9mIHRoZSBwZWVycyB0aGUgd2FsbGV0J3MgZGFlbW9uIGlzIGNvbm5lY3RlZCB0by5cbiAgICpcbiAgICogQHJldHVybiB7UHJvbWlzZTxudW1iZXI+fSB0aGUgbWF4aW11bSBoZWlnaHQgb2YgdGhlIHBlZXJzIHRoZSB3YWxsZXQncyBkYWVtb24gaXMgY29ubmVjdGVkIHRvXG4gICAqL1xuICBhc3luYyBnZXREYWVtb25NYXhQZWVySGVpZ2h0KCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXREYWVtb25NYXhQZWVySGVpZ2h0KCk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIFxuICAgICAgICAvLyBjYWxsIHdhc20gd2hpY2ggaW52b2tlcyBjYWxsYmFjayB3aGVuIGRvbmVcbiAgICAgICAgdGhpcy5tb2R1bGUuZ2V0X2RhZW1vbl9tYXhfcGVlcl9oZWlnaHQodGhpcy5jcHBBZGRyZXNzLCAocmVzcCkgPT4ge1xuICAgICAgICAgIHJlc29sdmUocmVzcCk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhlIHdhbGxldCdzIGRhZW1vbiBpcyBzeW5jZWQgd2l0aCB0aGUgbmV0d29yay5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Ym9vbGVhbj59IHRydWUgaWYgdGhlIGRhZW1vbiBpcyBzeW5jZWQgd2l0aCB0aGUgbmV0d29yaywgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBhc3luYyBpc0RhZW1vblN5bmNlZCgpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmlzRGFlbW9uU3luY2VkKCk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIFxuICAgICAgICAvLyBjYWxsIHdhc20gd2hpY2ggaW52b2tlcyBjYWxsYmFjayB3aGVuIGRvbmVcbiAgICAgICAgdGhpcy5tb2R1bGUuaXNfZGFlbW9uX3N5bmNlZCh0aGlzLmNwcEFkZHJlc3MsIChyZXNwKSA9PiB7XG4gICAgICAgICAgcmVzb2x2ZShyZXNwKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEluZGljYXRlcyBpZiB0aGUgd2FsbGV0IGlzIHN5bmNlZCB3aXRoIHRoZSBkYWVtb24uXG4gICAqIFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPGJvb2xlYW4+fSB0cnVlIGlmIHRoZSB3YWxsZXQgaXMgc3luY2VkIHdpdGggdGhlIGRhZW1vbiwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBhc3luYyBpc1N5bmNlZCgpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmlzU3luY2VkKCk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgdGhpcy5tb2R1bGUuaXNfc3luY2VkKHRoaXMuY3BwQWRkcmVzcywgKHJlc3ApID0+IHtcbiAgICAgICAgICByZXNvbHZlKHJlc3ApO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSB3YWxsZXQncyBuZXR3b3JrIHR5cGUgKG1haW5uZXQsIHRlc3RuZXQsIG9yIHN0YWdlbmV0KS5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8TW9uZXJvTmV0d29ya1R5cGU+fSB0aGUgd2FsbGV0J3MgbmV0d29yayB0eXBlXG4gICAqL1xuICBhc3luYyBnZXROZXR3b3JrVHlwZSgpOiBQcm9taXNlPE1vbmVyb05ldHdvcmtUeXBlPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXROZXR3b3JrVHlwZSgpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiB0aGlzLm1vZHVsZS5nZXRfbmV0d29ya190eXBlKHRoaXMuY3BwQWRkcmVzcyk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIGhlaWdodCBvZiB0aGUgZmlyc3QgYmxvY2sgdGhhdCB0aGUgd2FsbGV0IHNjYW5zLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTxudW1iZXI+fSB0aGUgaGVpZ2h0IG9mIHRoZSBmaXJzdCBibG9jayB0aGF0IHRoZSB3YWxsZXQgc2NhbnNcbiAgICovXG4gIGFzeW5jIGdldFJlc3RvcmVIZWlnaHQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldFJlc3RvcmVIZWlnaHQoKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gdGhpcy5tb2R1bGUuZ2V0X3Jlc3RvcmVfaGVpZ2h0KHRoaXMuY3BwQWRkcmVzcyk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZXQgdGhlIGhlaWdodCBvZiB0aGUgZmlyc3QgYmxvY2sgdGhhdCB0aGUgd2FsbGV0IHNjYW5zLlxuICAgKiBcbiAgICogQHBhcmFtIHtudW1iZXJ9IHJlc3RvcmVIZWlnaHQgLSBoZWlnaHQgb2YgdGhlIGZpcnN0IGJsb2NrIHRoYXQgdGhlIHdhbGxldCBzY2Fuc1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgc2V0UmVzdG9yZUhlaWdodChyZXN0b3JlSGVpZ2h0OiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLnNldFJlc3RvcmVIZWlnaHQocmVzdG9yZUhlaWdodCk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgdGhpcy5tb2R1bGUuc2V0X3Jlc3RvcmVfaGVpZ2h0KHRoaXMuY3BwQWRkcmVzcywgcmVzdG9yZUhlaWdodCk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBNb3ZlIHRoZSB3YWxsZXQgZnJvbSBpdHMgY3VycmVudCBwYXRoIHRvIHRoZSBnaXZlbiBwYXRoLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSB0aGUgd2FsbGV0J3MgZGVzdGluYXRpb24gcGF0aFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgbW92ZVRvKHBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkubW92ZVRvKHBhdGgpO1xuICAgIHJldHVybiBNb25lcm9XYWxsZXRGdWxsLm1vdmVUbyhwYXRoLCB0aGlzKTtcbiAgfVxuICBcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gQ09NTU9OIFdBTExFVCBNRVRIT0RTIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgXG4gIGFzeW5jIGFkZExpc3RlbmVyKGxpc3RlbmVyOiBNb25lcm9XYWxsZXRMaXN0ZW5lcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuYWRkTGlzdGVuZXIobGlzdGVuZXIpO1xuICAgIGF3YWl0IHN1cGVyLmFkZExpc3RlbmVyKGxpc3RlbmVyKTtcbiAgICBhd2FpdCB0aGlzLnJlZnJlc2hMaXN0ZW5pbmcoKTtcbiAgfVxuICBcbiAgYXN5bmMgcmVtb3ZlTGlzdGVuZXIobGlzdGVuZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLnJlbW92ZUxpc3RlbmVyKGxpc3RlbmVyKTtcbiAgICBhd2FpdCBzdXBlci5yZW1vdmVMaXN0ZW5lcihsaXN0ZW5lcik7XG4gICAgYXdhaXQgdGhpcy5yZWZyZXNoTGlzdGVuaW5nKCk7XG4gIH1cbiAgXG4gIGdldExpc3RlbmVycygpOiBNb25lcm9XYWxsZXRMaXN0ZW5lcltdIHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldExpc3RlbmVycygpO1xuICAgIHJldHVybiBzdXBlci5nZXRMaXN0ZW5lcnMoKTtcbiAgfVxuICBcbiAgYXN5bmMgc2V0RGFlbW9uQ29ubmVjdGlvbih1cmlPckNvbm5lY3Rpb24/OiBNb25lcm9ScGNDb25uZWN0aW9uIHwgc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5zZXREYWVtb25Db25uZWN0aW9uKHVyaU9yQ29ubmVjdGlvbik7XG4gICAgXG4gICAgLy8gbm9ybWFsaXplIGNvbm5lY3Rpb25cbiAgICBsZXQgY29ubmVjdGlvbiA9ICF1cmlPckNvbm5lY3Rpb24gPyB1bmRlZmluZWQgOiB1cmlPckNvbm5lY3Rpb24gaW5zdGFuY2VvZiBNb25lcm9ScGNDb25uZWN0aW9uID8gdXJpT3JDb25uZWN0aW9uIDogbmV3IE1vbmVyb1JwY0Nvbm5lY3Rpb24odXJpT3JDb25uZWN0aW9uKTtcbiAgICBsZXQgdXJpID0gY29ubmVjdGlvbiAmJiBjb25uZWN0aW9uLmdldFVyaSgpID8gY29ubmVjdGlvbi5nZXRVcmkoKSA6IFwiXCI7XG4gICAgbGV0IHVzZXJuYW1lID0gY29ubmVjdGlvbiAmJiBjb25uZWN0aW9uLmdldFVzZXJuYW1lKCkgPyBjb25uZWN0aW9uLmdldFVzZXJuYW1lKCkgOiBcIlwiO1xuICAgIGxldCBwYXNzd29yZCA9IGNvbm5lY3Rpb24gJiYgY29ubmVjdGlvbi5nZXRQYXNzd29yZCgpID8gY29ubmVjdGlvbi5nZXRQYXNzd29yZCgpIDogXCJcIjtcbiAgICBsZXQgcHJveHlVcmkgPSBjb25uZWN0aW9uICYmIGNvbm5lY3Rpb24uZ2V0UHJveHlVcmkoKSA/IGNvbm5lY3Rpb24uZ2V0UHJveHlVcmkoKSA6IFwiXCI7XG4gICAgbGV0IHJlamVjdFVuYXV0aG9yaXplZCA9IGNvbm5lY3Rpb24gPyBjb25uZWN0aW9uLmdldFJlamVjdFVuYXV0aG9yaXplZCgpIDogdW5kZWZpbmVkO1xuICAgIHRoaXMucmVqZWN0VW5hdXRob3JpemVkID0gcmVqZWN0VW5hdXRob3JpemVkOyAgLy8gcGVyc2lzdCBsb2NhbGx5XG4gICAgXG4gICAgLy8gc2V0IGNvbm5lY3Rpb24gaW4gcXVldWVcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5zZXRfZGFlbW9uX2Nvbm5lY3Rpb24odGhpcy5jcHBBZGRyZXNzLCB1cmksIHVzZXJuYW1lLCBwYXNzd29yZCwgcHJveHlVcmksIChyZXNwKSA9PiB7XG4gICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBnZXREYWVtb25Db25uZWN0aW9uKCk6IFByb21pc2U8TW9uZXJvUnBjQ29ubmVjdGlvbj4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuZ2V0RGFlbW9uQ29ubmVjdGlvbigpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGxldCBjb25uZWN0aW9uQ29udGFpbmVyU3RyID0gdGhpcy5tb2R1bGUuZ2V0X2RhZW1vbl9jb25uZWN0aW9uKHRoaXMuY3BwQWRkcmVzcyk7XG4gICAgICAgIGlmICghY29ubmVjdGlvbkNvbnRhaW5lclN0cikgcmVzb2x2ZSh1bmRlZmluZWQpO1xuICAgICAgICBlbHNlIHtcbiAgICAgICAgICBsZXQganNvbkNvbm5lY3Rpb24gPSBKU09OLnBhcnNlKGNvbm5lY3Rpb25Db250YWluZXJTdHIpO1xuICAgICAgICAgIHJlc29sdmUobmV3IE1vbmVyb1JwY0Nvbm5lY3Rpb24oe3VyaToganNvbkNvbm5lY3Rpb24udXJpLCB1c2VybmFtZToganNvbkNvbm5lY3Rpb24udXNlcm5hbWUsIHBhc3N3b3JkOiBqc29uQ29ubmVjdGlvbi5wYXNzd29yZCwgcHJveHlVcmk6IGpzb25Db25uZWN0aW9uLnByb3h5VXJpLCByZWplY3RVbmF1dGhvcml6ZWQ6IHRoaXMucmVqZWN0VW5hdXRob3JpemVkfSkpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgaXNDb25uZWN0ZWRUb0RhZW1vbigpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmlzQ29ubmVjdGVkVG9EYWVtb24oKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5pc19jb25uZWN0ZWRfdG9fZGFlbW9uKHRoaXMuY3BwQWRkcmVzcywgKHJlc3ApID0+IHtcbiAgICAgICAgICByZXNvbHZlKHJlc3ApO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBnZXRWZXJzaW9uKCk6IFByb21pc2U8TW9uZXJvVmVyc2lvbj4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuZ2V0VmVyc2lvbigpO1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vdCBpbXBsZW1lbnRlZFwiKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UGF0aCgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuZ2V0UGF0aCgpO1xuICAgIHJldHVybiB0aGlzLnBhdGg7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEludGVncmF0ZWRBZGRyZXNzKHN0YW5kYXJkQWRkcmVzcz86IHN0cmluZywgcGF5bWVudElkPzogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcz4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuZ2V0SW50ZWdyYXRlZEFkZHJlc3Moc3RhbmRhcmRBZGRyZXNzLCBwYXltZW50SWQpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGxldCByZXN1bHQgPSB0aGlzLm1vZHVsZS5nZXRfaW50ZWdyYXRlZF9hZGRyZXNzKHRoaXMuY3BwQWRkcmVzcywgc3RhbmRhcmRBZGRyZXNzID8gc3RhbmRhcmRBZGRyZXNzIDogXCJcIiwgcGF5bWVudElkID8gcGF5bWVudElkIDogXCJcIik7XG4gICAgICAgIGlmIChyZXN1bHQuY2hhckF0KDApICE9PSAneycpIHRocm93IG5ldyBNb25lcm9FcnJvcihyZXN1bHQpO1xuICAgICAgICByZXR1cm4gbmV3IE1vbmVyb0ludGVncmF0ZWRBZGRyZXNzKEpTT04ucGFyc2UocmVzdWx0KSk7XG4gICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICBpZiAoZXJyLm1lc3NhZ2UuaW5jbHVkZXMoXCJJbnZhbGlkIHBheW1lbnQgSURcIikpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkludmFsaWQgcGF5bWVudCBJRDogXCIgKyBwYXltZW50SWQpO1xuICAgICAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoZXJyLm1lc3NhZ2UpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBkZWNvZGVJbnRlZ3JhdGVkQWRkcmVzcyhpbnRlZ3JhdGVkQWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcz4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuZGVjb2RlSW50ZWdyYXRlZEFkZHJlc3MoaW50ZWdyYXRlZEFkZHJlc3MpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGxldCByZXN1bHQgPSB0aGlzLm1vZHVsZS5kZWNvZGVfaW50ZWdyYXRlZF9hZGRyZXNzKHRoaXMuY3BwQWRkcmVzcywgaW50ZWdyYXRlZEFkZHJlc3MpO1xuICAgICAgICBpZiAocmVzdWx0LmNoYXJBdCgwKSAhPT0gJ3snKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IocmVzdWx0KTtcbiAgICAgICAgcmV0dXJuIG5ldyBNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcyhKU09OLnBhcnNlKHJlc3VsdCkpO1xuICAgICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKGVyci5tZXNzYWdlKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0SGVpZ2h0KCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRIZWlnaHQoKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5nZXRfaGVpZ2h0KHRoaXMuY3BwQWRkcmVzcywgKHJlc3ApID0+IHtcbiAgICAgICAgICByZXNvbHZlKHJlc3ApO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBnZXREYWVtb25IZWlnaHQoKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldERhZW1vbkhlaWdodCgpO1xuICAgIGlmICghYXdhaXQgdGhpcy5pc0Nvbm5lY3RlZFRvRGFlbW9uKCkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIldhbGxldCBpcyBub3QgY29ubmVjdGVkIHRvIGRhZW1vblwiKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5nZXRfZGFlbW9uX2hlaWdodCh0aGlzLmNwcEFkZHJlc3MsIChyZXNwKSA9PiB7XG4gICAgICAgICAgcmVzb2x2ZShyZXNwKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0SGVpZ2h0QnlEYXRlKHllYXI6IG51bWJlciwgbW9udGg6IG51bWJlciwgZGF5OiBudW1iZXIpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuZ2V0SGVpZ2h0QnlEYXRlKHllYXIsIG1vbnRoLCBkYXkpO1xuICAgIGlmICghYXdhaXQgdGhpcy5pc0Nvbm5lY3RlZFRvRGFlbW9uKCkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIldhbGxldCBpcyBub3QgY29ubmVjdGVkIHRvIGRhZW1vblwiKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5nZXRfaGVpZ2h0X2J5X2RhdGUodGhpcy5jcHBBZGRyZXNzLCB5ZWFyLCBtb250aCwgZGF5LCAocmVzcCkgPT4ge1xuICAgICAgICAgIGlmICh0eXBlb2YgcmVzcCA9PT0gXCJzdHJpbmdcIikgcmVqZWN0KG5ldyBNb25lcm9FcnJvcihyZXNwKSk7XG4gICAgICAgICAgZWxzZSByZXNvbHZlKHJlc3ApO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICAvKipcbiAgICogU3luY2hyb25pemUgdGhlIHdhbGxldCB3aXRoIHRoZSBkYWVtb24gYXMgYSBvbmUtdGltZSBzeW5jaHJvbm91cyBwcm9jZXNzLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9XYWxsZXRMaXN0ZW5lcnxudW1iZXJ9IFtsaXN0ZW5lck9yU3RhcnRIZWlnaHRdIC0gbGlzdGVuZXIgeG9yIHN0YXJ0IGhlaWdodCAoZGVmYXVsdHMgdG8gbm8gc3luYyBsaXN0ZW5lciwgdGhlIGxhc3Qgc3luY2VkIGJsb2NrKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXJ0SGVpZ2h0XSAtIHN0YXJ0SGVpZ2h0IGlmIG5vdCBnaXZlbiBpbiBmaXJzdCBhcmcgKGRlZmF1bHRzIHRvIGxhc3Qgc3luY2VkIGJsb2NrKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFthbGxvd0NvbmN1cnJlbnRDYWxsc10gLSBhbGxvdyBvdGhlciB3YWxsZXQgbWV0aG9kcyB0byBiZSBwcm9jZXNzZWQgc2ltdWx0YW5lb3VzbHkgZHVyaW5nIHN5bmMgKGRlZmF1bHQgZmFsc2UpPGJyPjxicj48Yj5XQVJOSU5HPC9iPjogZW5hYmxpbmcgdGhpcyBvcHRpb24gd2lsbCBjcmFzaCB3YWxsZXQgZXhlY3V0aW9uIGlmIGFub3RoZXIgY2FsbCBtYWtlcyBhIHNpbXVsdGFuZW91cyBuZXR3b3JrIHJlcXVlc3QuIFRPRE86IHBvc3NpYmxlIHRvIHN5bmMgd2FzbSBuZXR3b3JrIHJlcXVlc3RzIGluIGh0dHBfY2xpZW50X3dhc20uY3BwPyBcbiAgICovXG4gIGFzeW5jIHN5bmMobGlzdGVuZXJPclN0YXJ0SGVpZ2h0PzogTW9uZXJvV2FsbGV0TGlzdGVuZXIgfCBudW1iZXIsIHN0YXJ0SGVpZ2h0PzogbnVtYmVyLCBhbGxvd0NvbmN1cnJlbnRDYWxscyA9IGZhbHNlKTogUHJvbWlzZTxNb25lcm9TeW5jUmVzdWx0PiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5zeW5jKGxpc3RlbmVyT3JTdGFydEhlaWdodCwgc3RhcnRIZWlnaHQsIGFsbG93Q29uY3VycmVudENhbGxzKTtcbiAgICBpZiAoIWF3YWl0IHRoaXMuaXNDb25uZWN0ZWRUb0RhZW1vbigpKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJXYWxsZXQgaXMgbm90IGNvbm5lY3RlZCB0byBkYWVtb25cIik7XG4gICAgXG4gICAgLy8gbm9ybWFsaXplIHBhcmFtc1xuICAgIHN0YXJ0SGVpZ2h0ID0gbGlzdGVuZXJPclN0YXJ0SGVpZ2h0ID09PSB1bmRlZmluZWQgfHwgbGlzdGVuZXJPclN0YXJ0SGVpZ2h0IGluc3RhbmNlb2YgTW9uZXJvV2FsbGV0TGlzdGVuZXIgPyBzdGFydEhlaWdodCA6IGxpc3RlbmVyT3JTdGFydEhlaWdodDtcbiAgICBsZXQgbGlzdGVuZXIgPSBsaXN0ZW5lck9yU3RhcnRIZWlnaHQgaW5zdGFuY2VvZiBNb25lcm9XYWxsZXRMaXN0ZW5lciA/IGxpc3RlbmVyT3JTdGFydEhlaWdodCA6IHVuZGVmaW5lZDtcbiAgICBpZiAoc3RhcnRIZWlnaHQgPT09IHVuZGVmaW5lZCkgc3RhcnRIZWlnaHQgPSBNYXRoLm1heChhd2FpdCB0aGlzLmdldEhlaWdodCgpLCBhd2FpdCB0aGlzLmdldFJlc3RvcmVIZWlnaHQoKSk7XG4gICAgXG4gICAgLy8gcmVnaXN0ZXIgbGlzdGVuZXIgaWYgZ2l2ZW5cbiAgICBpZiAobGlzdGVuZXIpIGF3YWl0IHRoaXMuYWRkTGlzdGVuZXIobGlzdGVuZXIpO1xuICAgIFxuICAgIC8vIHN5bmMgd2FsbGV0XG4gICAgbGV0IGVycjtcbiAgICBsZXQgcmVzdWx0O1xuICAgIHRyeSB7XG4gICAgICBsZXQgdGhhdCA9IHRoaXM7XG4gICAgICByZXN1bHQgPSBhd2FpdCAoYWxsb3dDb25jdXJyZW50Q2FsbHMgPyBzeW5jV2FzbSgpIDogdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHN5bmNXYXNtKCkpKTtcbiAgICAgIGZ1bmN0aW9uIHN5bmNXYXNtKCkge1xuICAgICAgICB0aGF0LmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBcbiAgICAgICAgICAvLyBzeW5jIHdhbGxldCBpbiB3YXNtIHdoaWNoIGludm9rZXMgY2FsbGJhY2sgd2hlbiBkb25lXG4gICAgICAgICAgdGhhdC5tb2R1bGUuc3luYyh0aGF0LmNwcEFkZHJlc3MsIHN0YXJ0SGVpZ2h0LCBhc3luYyAocmVzcCkgPT4ge1xuICAgICAgICAgICAgaWYgKHJlc3AuY2hhckF0KDApICE9PSAneycpIHJlamVjdChuZXcgTW9uZXJvRXJyb3IocmVzcCkpO1xuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgIGxldCByZXNwSnNvbiA9IEpTT04ucGFyc2UocmVzcCk7XG4gICAgICAgICAgICAgIHJlc29sdmUobmV3IE1vbmVyb1N5bmNSZXN1bHQocmVzcEpzb24ubnVtQmxvY2tzRmV0Y2hlZCwgcmVzcEpzb24ucmVjZWl2ZWRNb25leSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBlcnIgPSBlO1xuICAgIH1cbiAgICBcbiAgICAvLyB1bnJlZ2lzdGVyIGxpc3RlbmVyXG4gICAgaWYgKGxpc3RlbmVyKSBhd2FpdCB0aGlzLnJlbW92ZUxpc3RlbmVyKGxpc3RlbmVyKTtcbiAgICBcbiAgICAvLyB0aHJvdyBlcnJvciBvciByZXR1cm5cbiAgICBpZiAoZXJyKSB0aHJvdyBlcnI7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuICBcbiAgYXN5bmMgc3RhcnRTeW5jaW5nKHN5bmNQZXJpb2RJbk1zPzogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5zdGFydFN5bmNpbmcoc3luY1BlcmlvZEluTXMpO1xuICAgIGlmICghYXdhaXQgdGhpcy5pc0Nvbm5lY3RlZFRvRGFlbW9uKCkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIldhbGxldCBpcyBub3QgY29ubmVjdGVkIHRvIGRhZW1vblwiKTtcbiAgICB0aGlzLnN5bmNQZXJpb2RJbk1zID0gc3luY1BlcmlvZEluTXMgPT09IHVuZGVmaW5lZCA/IE1vbmVyb1dhbGxldEZ1bGwuREVGQVVMVF9TWU5DX1BFUklPRF9JTl9NUyA6IHN5bmNQZXJpb2RJbk1zO1xuICAgIGlmICghdGhpcy5zeW5jTG9vcGVyKSB0aGlzLnN5bmNMb29wZXIgPSBuZXcgVGFza0xvb3Blcihhc3luYyAoKSA9PiBhd2FpdCB0aGlzLmJhY2tncm91bmRTeW5jKCkpXG4gICAgdGhpcy5zeW5jTG9vcGVyLnN0YXJ0KHRoaXMuc3luY1BlcmlvZEluTXMpO1xuICB9XG4gICAgXG4gIGFzeW5jIHN0b3BTeW5jaW5nKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuc3RvcFN5bmNpbmcoKTtcbiAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgIGlmICh0aGlzLnN5bmNMb29wZXIpIHRoaXMuc3luY0xvb3Blci5zdG9wKCk7XG4gICAgdGhpcy5tb2R1bGUuc3RvcF9zeW5jaW5nKHRoaXMuY3BwQWRkcmVzcyk7IC8vIHRhc2sgaXMgbm90IHF1ZXVlZCBzbyB3YWxsZXQgc3RvcHMgaW1tZWRpYXRlbHlcbiAgfVxuICBcbiAgYXN5bmMgc2NhblR4cyh0eEhhc2hlczogc3RyaW5nW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLnNjYW5UeHModHhIYXNoZXMpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRoaXMubW9kdWxlLnNjYW5fdHhzKHRoaXMuY3BwQWRkcmVzcywgSlNPTi5zdHJpbmdpZnkoe3R4SGFzaGVzOiB0eEhhc2hlc30pLCAoZXJyKSA9PiB7XG4gICAgICAgICAgaWYgKGVycikgcmVqZWN0KG5ldyBNb25lcm9FcnJvcihlcnIpKTtcbiAgICAgICAgICBlbHNlIHJlc29sdmUoKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgcmVzY2FuU3BlbnQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5yZXNjYW5TcGVudCgpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRoaXMubW9kdWxlLnJlc2Nhbl9zcGVudCh0aGlzLmNwcEFkZHJlc3MsICgpID0+IHJlc29sdmUoKSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgcmVzY2FuQmxvY2tjaGFpbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLnJlc2NhbkJsb2NrY2hhaW4oKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5yZXNjYW5fYmxvY2tjaGFpbih0aGlzLmNwcEFkZHJlc3MsICgpID0+IHJlc29sdmUoKSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QmFsYW5jZShhY2NvdW50SWR4PzogbnVtYmVyLCBzdWJhZGRyZXNzSWR4PzogbnVtYmVyKTogUHJvbWlzZTxiaWdpbnQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldEJhbGFuY2UoYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgXG4gICAgICAvLyBnZXQgYmFsYW5jZSBlbmNvZGVkIGluIGpzb24gc3RyaW5nXG4gICAgICBsZXQgYmFsYW5jZVN0cjtcbiAgICAgIGlmIChhY2NvdW50SWR4ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgYXNzZXJ0KHN1YmFkZHJlc3NJZHggPT09IHVuZGVmaW5lZCwgXCJTdWJhZGRyZXNzIGluZGV4IG11c3QgYmUgdW5kZWZpbmVkIGlmIGFjY291bnQgaW5kZXggaXMgdW5kZWZpbmVkXCIpO1xuICAgICAgICBiYWxhbmNlU3RyID0gdGhpcy5tb2R1bGUuZ2V0X2JhbGFuY2Vfd2FsbGV0KHRoaXMuY3BwQWRkcmVzcyk7XG4gICAgICB9IGVsc2UgaWYgKHN1YmFkZHJlc3NJZHggPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBiYWxhbmNlU3RyID0gdGhpcy5tb2R1bGUuZ2V0X2JhbGFuY2VfYWNjb3VudCh0aGlzLmNwcEFkZHJlc3MsIGFjY291bnRJZHgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYmFsYW5jZVN0ciA9IHRoaXMubW9kdWxlLmdldF9iYWxhbmNlX3N1YmFkZHJlc3ModGhpcy5jcHBBZGRyZXNzLCBhY2NvdW50SWR4LCBzdWJhZGRyZXNzSWR4KTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gcGFyc2UganNvbiBzdHJpbmcgdG8gYmlnaW50XG4gICAgICByZXR1cm4gQmlnSW50KEpTT04ucGFyc2UoR2VuVXRpbHMuc3RyaW5naWZ5QmlnSW50cyhiYWxhbmNlU3RyKSkuYmFsYW5jZSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFVubG9ja2VkQmFsYW5jZShhY2NvdW50SWR4PzogbnVtYmVyLCBzdWJhZGRyZXNzSWR4PzogbnVtYmVyKTogUHJvbWlzZTxiaWdpbnQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldFVubG9ja2VkQmFsYW5jZShhY2NvdW50SWR4LCBzdWJhZGRyZXNzSWR4KTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICBcbiAgICAgIC8vIGdldCBiYWxhbmNlIGVuY29kZWQgaW4ganNvbiBzdHJpbmdcbiAgICAgIGxldCB1bmxvY2tlZEJhbGFuY2VTdHI7XG4gICAgICBpZiAoYWNjb3VudElkeCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGFzc2VydChzdWJhZGRyZXNzSWR4ID09PSB1bmRlZmluZWQsIFwiU3ViYWRkcmVzcyBpbmRleCBtdXN0IGJlIHVuZGVmaW5lZCBpZiBhY2NvdW50IGluZGV4IGlzIHVuZGVmaW5lZFwiKTtcbiAgICAgICAgdW5sb2NrZWRCYWxhbmNlU3RyID0gdGhpcy5tb2R1bGUuZ2V0X3VubG9ja2VkX2JhbGFuY2Vfd2FsbGV0KHRoaXMuY3BwQWRkcmVzcyk7XG4gICAgICB9IGVsc2UgaWYgKHN1YmFkZHJlc3NJZHggPT09IHVuZGVmaW5lZCkge1xuICAgICAgICB1bmxvY2tlZEJhbGFuY2VTdHIgPSB0aGlzLm1vZHVsZS5nZXRfdW5sb2NrZWRfYmFsYW5jZV9hY2NvdW50KHRoaXMuY3BwQWRkcmVzcywgYWNjb3VudElkeCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB1bmxvY2tlZEJhbGFuY2VTdHIgPSB0aGlzLm1vZHVsZS5nZXRfdW5sb2NrZWRfYmFsYW5jZV9zdWJhZGRyZXNzKHRoaXMuY3BwQWRkcmVzcywgYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIHBhcnNlIGpzb24gc3RyaW5nIHRvIGJpZ2ludFxuICAgICAgcmV0dXJuIEJpZ0ludChKU09OLnBhcnNlKEdlblV0aWxzLnN0cmluZ2lmeUJpZ0ludHModW5sb2NrZWRCYWxhbmNlU3RyKSkudW5sb2NrZWRCYWxhbmNlKTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QWNjb3VudHMoaW5jbHVkZVN1YmFkZHJlc3Nlcz86IGJvb2xlYW4sIHRhZz86IHN0cmluZyk6IFByb21pc2U8TW9uZXJvQWNjb3VudFtdPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRBY2NvdW50cyhpbmNsdWRlU3ViYWRkcmVzc2VzLCB0YWcpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIGxldCBhY2NvdW50c1N0ciA9IHRoaXMubW9kdWxlLmdldF9hY2NvdW50cyh0aGlzLmNwcEFkZHJlc3MsIGluY2x1ZGVTdWJhZGRyZXNzZXMgPyB0cnVlIDogZmFsc2UsIHRhZyA/IHRhZyA6IFwiXCIpO1xuICAgICAgbGV0IGFjY291bnRzID0gW107XG4gICAgICBmb3IgKGxldCBhY2NvdW50SnNvbiBvZiBKU09OLnBhcnNlKEdlblV0aWxzLnN0cmluZ2lmeUJpZ0ludHMoYWNjb3VudHNTdHIpKS5hY2NvdW50cykge1xuICAgICAgICBhY2NvdW50cy5wdXNoKE1vbmVyb1dhbGxldEZ1bGwuc2FuaXRpemVBY2NvdW50KG5ldyBNb25lcm9BY2NvdW50KGFjY291bnRKc29uKSkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGFjY291bnRzO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBnZXRBY2NvdW50KGFjY291bnRJZHg6IG51bWJlciwgaW5jbHVkZVN1YmFkZHJlc3Nlcz86IGJvb2xlYW4pOiBQcm9taXNlPE1vbmVyb0FjY291bnQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldEFjY291bnQoYWNjb3VudElkeCwgaW5jbHVkZVN1YmFkZHJlc3Nlcyk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgbGV0IGFjY291bnRTdHIgPSB0aGlzLm1vZHVsZS5nZXRfYWNjb3VudCh0aGlzLmNwcEFkZHJlc3MsIGFjY291bnRJZHgsIGluY2x1ZGVTdWJhZGRyZXNzZXMgPyB0cnVlIDogZmFsc2UpO1xuICAgICAgbGV0IGFjY291bnRKc29uID0gSlNPTi5wYXJzZShHZW5VdGlscy5zdHJpbmdpZnlCaWdJbnRzKGFjY291bnRTdHIpKTtcbiAgICAgIHJldHVybiBNb25lcm9XYWxsZXRGdWxsLnNhbml0aXplQWNjb3VudChuZXcgTW9uZXJvQWNjb3VudChhY2NvdW50SnNvbikpO1xuICAgIH0pO1xuXG4gIH1cbiAgXG4gIGFzeW5jIGNyZWF0ZUFjY291bnQobGFiZWw/OiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0FjY291bnQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmNyZWF0ZUFjY291bnQobGFiZWwpO1xuICAgIGlmIChsYWJlbCA9PT0gdW5kZWZpbmVkKSBsYWJlbCA9IFwiXCI7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgbGV0IGFjY291bnRTdHIgPSB0aGlzLm1vZHVsZS5jcmVhdGVfYWNjb3VudCh0aGlzLmNwcEFkZHJlc3MsIGxhYmVsKTtcbiAgICAgIGxldCBhY2NvdW50SnNvbiA9IEpTT04ucGFyc2UoR2VuVXRpbHMuc3RyaW5naWZ5QmlnSW50cyhhY2NvdW50U3RyKSk7XG4gICAgICByZXR1cm4gTW9uZXJvV2FsbGV0RnVsbC5zYW5pdGl6ZUFjY291bnQobmV3IE1vbmVyb0FjY291bnQoYWNjb3VudEpzb24pKTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0U3ViYWRkcmVzc2VzKGFjY291bnRJZHg6IG51bWJlciwgc3ViYWRkcmVzc0luZGljZXM/OiBudW1iZXJbXSk6IFByb21pc2U8TW9uZXJvU3ViYWRkcmVzc1tdPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRTdWJhZGRyZXNzZXMoYWNjb3VudElkeCwgc3ViYWRkcmVzc0luZGljZXMpO1xuICAgIGxldCBhcmdzID0ge2FjY291bnRJZHg6IGFjY291bnRJZHgsIHN1YmFkZHJlc3NJbmRpY2VzOiBzdWJhZGRyZXNzSW5kaWNlcyA9PT0gdW5kZWZpbmVkID8gW10gOiBHZW5VdGlscy5saXN0aWZ5KHN1YmFkZHJlc3NJbmRpY2VzKX07XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgbGV0IHN1YmFkZHJlc3Nlc0pzb24gPSBKU09OLnBhcnNlKEdlblV0aWxzLnN0cmluZ2lmeUJpZ0ludHModGhpcy5tb2R1bGUuZ2V0X3N1YmFkZHJlc3Nlcyh0aGlzLmNwcEFkZHJlc3MsIEpTT04uc3RyaW5naWZ5KGFyZ3MpKSkpLnN1YmFkZHJlc3NlcztcbiAgICAgIGxldCBzdWJhZGRyZXNzZXMgPSBbXTtcbiAgICAgIGZvciAobGV0IHN1YmFkZHJlc3NKc29uIG9mIHN1YmFkZHJlc3Nlc0pzb24pIHN1YmFkZHJlc3Nlcy5wdXNoKE1vbmVyb1dhbGxldEtleXMuc2FuaXRpemVTdWJhZGRyZXNzKG5ldyBNb25lcm9TdWJhZGRyZXNzKHN1YmFkZHJlc3NKc29uKSkpO1xuICAgICAgcmV0dXJuIHN1YmFkZHJlc3NlcztcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgY3JlYXRlU3ViYWRkcmVzcyhhY2NvdW50SWR4OiBudW1iZXIsIGxhYmVsPzogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9TdWJhZGRyZXNzPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5jcmVhdGVTdWJhZGRyZXNzKGFjY291bnRJZHgsIGxhYmVsKTtcbiAgICBpZiAobGFiZWwgPT09IHVuZGVmaW5lZCkgbGFiZWwgPSBcIlwiO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIGxldCBzdWJhZGRyZXNzU3RyID0gdGhpcy5tb2R1bGUuY3JlYXRlX3N1YmFkZHJlc3ModGhpcy5jcHBBZGRyZXNzLCBhY2NvdW50SWR4LCBsYWJlbCk7XG4gICAgICBsZXQgc3ViYWRkcmVzc0pzb24gPSBKU09OLnBhcnNlKEdlblV0aWxzLnN0cmluZ2lmeUJpZ0ludHMoc3ViYWRkcmVzc1N0cikpO1xuICAgICAgcmV0dXJuIE1vbmVyb1dhbGxldEtleXMuc2FuaXRpemVTdWJhZGRyZXNzKG5ldyBNb25lcm9TdWJhZGRyZXNzKHN1YmFkZHJlc3NKc29uKSk7XG4gICAgfSk7XG4gIH1cblxuICBhc3luYyBzZXRTdWJhZGRyZXNzTGFiZWwoYWNjb3VudElkeDogbnVtYmVyLCBzdWJhZGRyZXNzSWR4OiBudW1iZXIsIGxhYmVsOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLnNldFN1YmFkZHJlc3NMYWJlbChhY2NvdW50SWR4LCBzdWJhZGRyZXNzSWR4LCBsYWJlbCk7XG4gICAgaWYgKGxhYmVsID09PSB1bmRlZmluZWQpIGxhYmVsID0gXCJcIjtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICB0aGlzLm1vZHVsZS5zZXRfc3ViYWRkcmVzc19sYWJlbCh0aGlzLmNwcEFkZHJlc3MsIGFjY291bnRJZHgsIHN1YmFkZHJlc3NJZHgsIGxhYmVsKTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0VHhzKHF1ZXJ5Pzogc3RyaW5nW10gfCBQYXJ0aWFsPE1vbmVyb1R4UXVlcnk+KTogUHJvbWlzZTxNb25lcm9UeFdhbGxldFtdPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRUeHMocXVlcnkpO1xuXG4gICAgLy8gY29weSBhbmQgbm9ybWFsaXplIHF1ZXJ5IHVwIHRvIGJsb2NrXG4gICAgY29uc3QgcXVlcnlOb3JtYWxpemVkID0gcXVlcnkgPSBNb25lcm9XYWxsZXQubm9ybWFsaXplVHhRdWVyeShxdWVyeSk7XG4gICAgXG4gICAgLy8gc2NoZWR1bGUgdGFza1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIFxuICAgICAgICAvLyBjYWxsIHdhc20gd2hpY2ggaW52b2tlcyBjYWxsYmFja1xuICAgICAgICB0aGlzLm1vZHVsZS5nZXRfdHhzKHRoaXMuY3BwQWRkcmVzcywgSlNPTi5zdHJpbmdpZnkocXVlcnlOb3JtYWxpemVkLmdldEJsb2NrKCkudG9Kc29uKCkpLCAoYmxvY2tzSnNvblN0cikgPT4ge1xuICAgICAgICAgIFxuICAgICAgICAgIC8vIGNoZWNrIGZvciBlcnJvclxuICAgICAgICAgIGlmIChibG9ja3NKc29uU3RyLmNoYXJBdCgwKSAhPT0gJ3snKSB7XG4gICAgICAgICAgICByZWplY3QobmV3IE1vbmVyb0Vycm9yKGJsb2Nrc0pzb25TdHIpKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gcmVzb2x2ZSB3aXRoIGRlc2VyaWFsaXplZCB0eHNcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmVzb2x2ZShNb25lcm9XYWxsZXRGdWxsLmRlc2VyaWFsaXplVHhzKHF1ZXJ5Tm9ybWFsaXplZCwgYmxvY2tzSnNvblN0cikpO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBnZXRUcmFuc2ZlcnMocXVlcnk/OiBQYXJ0aWFsPE1vbmVyb1RyYW5zZmVyUXVlcnk+KTogUHJvbWlzZTxNb25lcm9UcmFuc2ZlcltdPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRUcmFuc2ZlcnMocXVlcnkpO1xuICAgIFxuICAgIC8vIGNvcHkgYW5kIG5vcm1hbGl6ZSBxdWVyeSB1cCB0byBibG9ja1xuICAgIGNvbnN0IHF1ZXJ5Tm9ybWFsaXplZCA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVUcmFuc2ZlclF1ZXJ5KHF1ZXJ5KTtcbiAgICBcbiAgICAvLyByZXR1cm4gcHJvbWlzZSB3aGljaCByZXNvbHZlcyBvbiBjYWxsYmFja1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIFxuICAgICAgICAvLyBjYWxsIHdhc20gd2hpY2ggaW52b2tlcyBjYWxsYmFja1xuICAgICAgICB0aGlzLm1vZHVsZS5nZXRfdHJhbnNmZXJzKHRoaXMuY3BwQWRkcmVzcywgSlNPTi5zdHJpbmdpZnkocXVlcnlOb3JtYWxpemVkLmdldFR4UXVlcnkoKS5nZXRCbG9jaygpLnRvSnNvbigpKSwgKGJsb2Nrc0pzb25TdHIpID0+IHtcbiAgICAgICAgICAgIFxuICAgICAgICAgIC8vIGNoZWNrIGZvciBlcnJvclxuICAgICAgICAgIGlmIChibG9ja3NKc29uU3RyLmNoYXJBdCgwKSAhPT0gJ3snKSB7XG4gICAgICAgICAgICByZWplY3QobmV3IE1vbmVyb0Vycm9yKGJsb2Nrc0pzb25TdHIpKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgIFxuICAgICAgICAgIC8vIHJlc29sdmUgd2l0aCBkZXNlcmlhbGl6ZWQgdHJhbnNmZXJzIFxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXNvbHZlKE1vbmVyb1dhbGxldEZ1bGwuZGVzZXJpYWxpemVUcmFuc2ZlcnMocXVlcnlOb3JtYWxpemVkLCBibG9ja3NKc29uU3RyKSk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICByZWplY3QoZXJyKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldE91dHB1dHMocXVlcnk/OiBQYXJ0aWFsPE1vbmVyb091dHB1dFF1ZXJ5Pik6IFByb21pc2U8TW9uZXJvT3V0cHV0V2FsbGV0W10+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldE91dHB1dHMocXVlcnkpO1xuICAgIFxuICAgIC8vIGNvcHkgYW5kIG5vcm1hbGl6ZSBxdWVyeSB1cCB0byBibG9ja1xuICAgIGNvbnN0IHF1ZXJ5Tm9ybWFsaXplZCA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVPdXRwdXRRdWVyeShxdWVyeSk7XG4gICAgXG4gICAgLy8gcmV0dXJuIHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgb24gY2FsbGJhY2tcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT57XG4gICAgICAgIFxuICAgICAgICAvLyBjYWxsIHdhc20gd2hpY2ggaW52b2tlcyBjYWxsYmFja1xuICAgICAgICB0aGlzLm1vZHVsZS5nZXRfb3V0cHV0cyh0aGlzLmNwcEFkZHJlc3MsIEpTT04uc3RyaW5naWZ5KHF1ZXJ5Tm9ybWFsaXplZC5nZXRUeFF1ZXJ5KCkuZ2V0QmxvY2soKS50b0pzb24oKSksIChibG9ja3NKc29uU3RyKSA9PiB7XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gY2hlY2sgZm9yIGVycm9yXG4gICAgICAgICAgaWYgKGJsb2Nrc0pzb25TdHIuY2hhckF0KDApICE9PSAneycpIHtcbiAgICAgICAgICAgIHJlamVjdChuZXcgTW9uZXJvRXJyb3IoYmxvY2tzSnNvblN0cikpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICBcbiAgICAgICAgICAvLyByZXNvbHZlIHdpdGggZGVzZXJpYWxpemVkIG91dHB1dHNcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmVzb2x2ZShNb25lcm9XYWxsZXRGdWxsLmRlc2VyaWFsaXplT3V0cHV0cyhxdWVyeU5vcm1hbGl6ZWQsIGJsb2Nrc0pzb25TdHIpKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIHJlamVjdChlcnIpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZXhwb3J0T3V0cHV0cyhhbGwgPSBmYWxzZSk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5leHBvcnRPdXRwdXRzKGFsbCk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgdGhpcy5tb2R1bGUuZXhwb3J0X291dHB1dHModGhpcy5jcHBBZGRyZXNzLCBhbGwsIChvdXRwdXRzSGV4KSA9PiByZXNvbHZlKG91dHB1dHNIZXgpKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBpbXBvcnRPdXRwdXRzKG91dHB1dHNIZXg6IHN0cmluZyk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5pbXBvcnRPdXRwdXRzKG91dHB1dHNIZXgpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRoaXMubW9kdWxlLmltcG9ydF9vdXRwdXRzKHRoaXMuY3BwQWRkcmVzcywgb3V0cHV0c0hleCwgKG51bUltcG9ydGVkKSA9PiByZXNvbHZlKG51bUltcG9ydGVkKSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZXhwb3J0S2V5SW1hZ2VzKGFsbCA9IGZhbHNlKTogUHJvbWlzZTxNb25lcm9LZXlJbWFnZVtdPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5leHBvcnRLZXlJbWFnZXMoYWxsKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5leHBvcnRfa2V5X2ltYWdlcyh0aGlzLmNwcEFkZHJlc3MsIGFsbCwgKGtleUltYWdlc1N0cikgPT4ge1xuICAgICAgICAgIGlmIChrZXlJbWFnZXNTdHIuY2hhckF0KDApICE9PSAneycpcmVqZWN0KG5ldyBNb25lcm9FcnJvcihrZXlJbWFnZXNTdHIpKTsgLy8ganNvbiBleHBlY3RlZCwgZWxzZSBlcnJvclxuICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgbGV0IGtleUltYWdlcyA9IFtdO1xuICAgICAgICAgICAgZm9yIChsZXQga2V5SW1hZ2VKc29uIG9mIEpTT04ucGFyc2UoR2VuVXRpbHMuc3RyaW5naWZ5QmlnSW50cyhrZXlJbWFnZXNTdHIpKS5rZXlJbWFnZXMpIGtleUltYWdlcy5wdXNoKG5ldyBNb25lcm9LZXlJbWFnZShrZXlJbWFnZUpzb24pKTtcbiAgICAgICAgICAgIHJlc29sdmUoa2V5SW1hZ2VzKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGltcG9ydEtleUltYWdlcyhrZXlJbWFnZXM6IE1vbmVyb0tleUltYWdlW10pOiBQcm9taXNlPE1vbmVyb0tleUltYWdlSW1wb3J0UmVzdWx0PiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5pbXBvcnRLZXlJbWFnZXMoa2V5SW1hZ2VzKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5pbXBvcnRfa2V5X2ltYWdlcyh0aGlzLmNwcEFkZHJlc3MsIEpTT04uc3RyaW5naWZ5KHtrZXlJbWFnZXM6IGtleUltYWdlcy5tYXAoa2V5SW1hZ2UgPT4ga2V5SW1hZ2UudG9Kc29uKCkpfSksIChrZXlJbWFnZUltcG9ydFJlc3VsdFN0cikgPT4ge1xuICAgICAgICAgIGlmIChrZXlJbWFnZUltcG9ydFJlc3VsdFN0ci5jaGFyQXQoMCkgIT09ICd7JykgcmVqZWN0KG5ldyBNb25lcm9FcnJvcihrZXlJbWFnZUltcG9ydFJlc3VsdFN0cikpOyAvLyBqc29uIGV4cGVjdGVkLCBlbHNlIGVycm9yXG4gICAgICAgICAgZWxzZSByZXNvbHZlKG5ldyBNb25lcm9LZXlJbWFnZUltcG9ydFJlc3VsdChKU09OLnBhcnNlKEdlblV0aWxzLnN0cmluZ2lmeUJpZ0ludHMoa2V5SW1hZ2VJbXBvcnRSZXN1bHRTdHIpKSkpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBnZXROZXdLZXlJbWFnZXNGcm9tTGFzdEltcG9ydCgpOiBQcm9taXNlPE1vbmVyb0tleUltYWdlW10+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldE5ld0tleUltYWdlc0Zyb21MYXN0SW1wb3J0KCk7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IGltcGxlbWVudGVkXCIpO1xuICB9XG4gIFxuICBhc3luYyBmcmVlemVPdXRwdXQoa2V5SW1hZ2U6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuZnJlZXplT3V0cHV0KGtleUltYWdlKTtcbiAgICBpZiAoIWtleUltYWdlKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJNdXN0IHNwZWNpZnkga2V5IGltYWdlIHRvIGZyZWV6ZVwiKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5mcmVlemVfb3V0cHV0KHRoaXMuY3BwQWRkcmVzcywga2V5SW1hZ2UsICgpID0+IHJlc29sdmUoKSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgdGhhd091dHB1dChrZXlJbWFnZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS50aGF3T3V0cHV0KGtleUltYWdlKTtcbiAgICBpZiAoIWtleUltYWdlKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJNdXN0IHNwZWNpZnkga2V5IGltYWdlIHRvIHRoYXdcIik7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgdGhpcy5tb2R1bGUudGhhd19vdXRwdXQodGhpcy5jcHBBZGRyZXNzLCBrZXlJbWFnZSwgKCkgPT4gcmVzb2x2ZSgpKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBpc091dHB1dEZyb3plbihrZXlJbWFnZTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5pc091dHB1dEZyb3plbihrZXlJbWFnZSk7XG4gICAgaWYgKCFrZXlJbWFnZSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTXVzdCBzcGVjaWZ5IGtleSBpbWFnZSB0byBjaGVjayBpZiBmcm96ZW5cIik7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgdGhpcy5tb2R1bGUuaXNfb3V0cHV0X2Zyb3plbih0aGlzLmNwcEFkZHJlc3MsIGtleUltYWdlLCAocmVzdWx0KSA9PiByZXNvbHZlKHJlc3VsdCkpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICBhc3luYyBnZXREZWZhdWx0RmVlUHJpb3JpdHkoKTogUHJvbWlzZTxNb25lcm9UeFByaW9yaXR5PiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXREZWZhdWx0RmVlUHJpb3JpdHkoKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5nZXRfZGVmYXVsdF9mZWVfcHJpb3JpdHkodGhpcy5jcHBBZGRyZXNzLCAocmVzdWx0KSA9PiByZXNvbHZlKHJlc3VsdCkpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGNyZWF0ZVR4cyhjb25maWc6IFBhcnRpYWw8TW9uZXJvVHhDb25maWc+KTogUHJvbWlzZTxNb25lcm9UeFdhbGxldFtdPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5jcmVhdGVUeHMoY29uZmlnKTtcbiAgICBcbiAgICAvLyB2YWxpZGF0ZSwgY29weSwgYW5kIG5vcm1hbGl6ZSBjb25maWdcbiAgICBjb25zdCBjb25maWdOb3JtYWxpemVkID0gTW9uZXJvV2FsbGV0Lm5vcm1hbGl6ZUNyZWF0ZVR4c0NvbmZpZyhjb25maWcpO1xuICAgIGlmIChjb25maWdOb3JtYWxpemVkLmdldENhblNwbGl0KCkgPT09IHVuZGVmaW5lZCkgY29uZmlnTm9ybWFsaXplZC5zZXRDYW5TcGxpdCh0cnVlKTtcbiAgICBcbiAgICAvLyBjcmVhdGUgdHhzIGluIHF1ZXVlXG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgXG4gICAgICAgIC8vIGNyZWF0ZSB0eHMgaW4gd2FzbSB3aGljaCBpbnZva2VzIGNhbGxiYWNrIHdoZW4gZG9uZVxuICAgICAgICB0aGlzLm1vZHVsZS5jcmVhdGVfdHhzKHRoaXMuY3BwQWRkcmVzcywgSlNPTi5zdHJpbmdpZnkoY29uZmlnTm9ybWFsaXplZC50b0pzb24oKSksICh0eFNldEpzb25TdHIpID0+IHtcbiAgICAgICAgICBpZiAodHhTZXRKc29uU3RyLmNoYXJBdCgwKSAhPT0gJ3snKSByZWplY3QobmV3IE1vbmVyb0Vycm9yKHR4U2V0SnNvblN0cikpOyAvLyBqc29uIGV4cGVjdGVkLCBlbHNlIGVycm9yXG4gICAgICAgICAgZWxzZSByZXNvbHZlKG5ldyBNb25lcm9UeFNldChKU09OLnBhcnNlKEdlblV0aWxzLnN0cmluZ2lmeUJpZ0ludHModHhTZXRKc29uU3RyKSkpLmdldFR4cygpKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgc3dlZXBPdXRwdXQoY29uZmlnOiBQYXJ0aWFsPE1vbmVyb1R4Q29uZmlnPik6IFByb21pc2U8TW9uZXJvVHhXYWxsZXQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLnN3ZWVwT3V0cHV0KGNvbmZpZyk7XG4gICAgXG4gICAgLy8gbm9ybWFsaXplIGFuZCB2YWxpZGF0ZSBjb25maWdcbiAgICBjb25zdCBjb25maWdOb3JtYWxpemVkID0gTW9uZXJvV2FsbGV0Lm5vcm1hbGl6ZVN3ZWVwT3V0cHV0Q29uZmlnKGNvbmZpZyk7XG4gICAgXG4gICAgLy8gc3dlZXAgb3V0cHV0IGluIHF1ZXVlXG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgXG4gICAgICAgIC8vIHN3ZWVwIG91dHB1dCBpbiB3YXNtIHdoaWNoIGludm9rZXMgY2FsbGJhY2sgd2hlbiBkb25lXG4gICAgICAgIHRoaXMubW9kdWxlLnN3ZWVwX291dHB1dCh0aGlzLmNwcEFkZHJlc3MsIEpTT04uc3RyaW5naWZ5KGNvbmZpZ05vcm1hbGl6ZWQudG9Kc29uKCkpLCAodHhTZXRKc29uU3RyKSA9PiB7XG4gICAgICAgICAgaWYgKHR4U2V0SnNvblN0ci5jaGFyQXQoMCkgIT09ICd7JykgcmVqZWN0KG5ldyBNb25lcm9FcnJvcih0eFNldEpzb25TdHIpKTsgLy8ganNvbiBleHBlY3RlZCwgZWxzZSBlcnJvclxuICAgICAgICAgIGVsc2UgcmVzb2x2ZShuZXcgTW9uZXJvVHhTZXQoSlNPTi5wYXJzZShHZW5VdGlscy5zdHJpbmdpZnlCaWdJbnRzKHR4U2V0SnNvblN0cikpKS5nZXRUeHMoKVswXSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cblxuICBhc3luYyBzd2VlcFVubG9ja2VkKGNvbmZpZzogUGFydGlhbDxNb25lcm9UeENvbmZpZz4pOiBQcm9taXNlPE1vbmVyb1R4V2FsbGV0W10+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLnN3ZWVwVW5sb2NrZWQoY29uZmlnKTtcbiAgICBcbiAgICAvLyB2YWxpZGF0ZSBhbmQgbm9ybWFsaXplIGNvbmZpZ1xuICAgIGNvbnN0IGNvbmZpZ05vcm1hbGl6ZWQgPSBNb25lcm9XYWxsZXQubm9ybWFsaXplU3dlZXBVbmxvY2tlZENvbmZpZyhjb25maWcpO1xuICAgIFxuICAgIC8vIHN3ZWVwIHVubG9ja2VkIGluIHF1ZXVlXG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgXG4gICAgICAgIC8vIHN3ZWVwIHVubG9ja2VkIGluIHdhc20gd2hpY2ggaW52b2tlcyBjYWxsYmFjayB3aGVuIGRvbmVcbiAgICAgICAgdGhpcy5tb2R1bGUuc3dlZXBfdW5sb2NrZWQodGhpcy5jcHBBZGRyZXNzLCBKU09OLnN0cmluZ2lmeShjb25maWdOb3JtYWxpemVkLnRvSnNvbigpKSwgKHR4U2V0c0pzb24pID0+IHtcbiAgICAgICAgICBpZiAodHhTZXRzSnNvbi5jaGFyQXQoMCkgIT09ICd7JykgcmVqZWN0KG5ldyBNb25lcm9FcnJvcih0eFNldHNKc29uKSk7IC8vIGpzb24gZXhwZWN0ZWQsIGVsc2UgZXJyb3JcbiAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGxldCB0eFNldHMgPSBbXTtcbiAgICAgICAgICAgIGZvciAobGV0IHR4U2V0SnNvbiBvZiBKU09OLnBhcnNlKEdlblV0aWxzLnN0cmluZ2lmeUJpZ0ludHModHhTZXRzSnNvbikpLnR4U2V0cykgdHhTZXRzLnB1c2gobmV3IE1vbmVyb1R4U2V0KHR4U2V0SnNvbikpO1xuICAgICAgICAgICAgbGV0IHR4cyA9IFtdO1xuICAgICAgICAgICAgZm9yIChsZXQgdHhTZXQgb2YgdHhTZXRzKSBmb3IgKGxldCB0eCBvZiB0eFNldC5nZXRUeHMoKSkgdHhzLnB1c2godHgpO1xuICAgICAgICAgICAgcmVzb2x2ZSh0eHMpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgc3dlZXBEdXN0KHJlbGF5PzogYm9vbGVhbik6IFByb21pc2U8TW9uZXJvVHhXYWxsZXRbXT4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuc3dlZXBEdXN0KHJlbGF5KTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBcbiAgICAgICAgLy8gY2FsbCB3YXNtIHdoaWNoIGludm9rZXMgY2FsbGJhY2sgd2hlbiBkb25lXG4gICAgICAgIHRoaXMubW9kdWxlLnN3ZWVwX2R1c3QodGhpcy5jcHBBZGRyZXNzLCByZWxheSwgKHR4U2V0SnNvblN0cikgPT4ge1xuICAgICAgICAgIGlmICh0eFNldEpzb25TdHIuY2hhckF0KDApICE9PSAneycpIHJlamVjdChuZXcgTW9uZXJvRXJyb3IodHhTZXRKc29uU3RyKSk7IC8vIGpzb24gZXhwZWN0ZWQsIGVsc2UgZXJyb3JcbiAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGxldCB0eFNldCA9IG5ldyBNb25lcm9UeFNldChKU09OLnBhcnNlKEdlblV0aWxzLnN0cmluZ2lmeUJpZ0ludHModHhTZXRKc29uU3RyKSkpO1xuICAgICAgICAgICAgaWYgKHR4U2V0LmdldFR4cygpID09PSB1bmRlZmluZWQpIHR4U2V0LnNldFR4cyhbXSk7XG4gICAgICAgICAgICByZXNvbHZlKHR4U2V0LmdldFR4cygpKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIHJlbGF5VHhzKHR4c09yTWV0YWRhdGFzOiAoTW9uZXJvVHhXYWxsZXQgfCBzdHJpbmcpW10pOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5yZWxheVR4cyh0eHNPck1ldGFkYXRhcyk7XG4gICAgYXNzZXJ0KEFycmF5LmlzQXJyYXkodHhzT3JNZXRhZGF0YXMpLCBcIk11c3QgcHJvdmlkZSBhbiBhcnJheSBvZiB0eHMgb3IgdGhlaXIgbWV0YWRhdGEgdG8gcmVsYXlcIik7XG4gICAgbGV0IHR4TWV0YWRhdGFzID0gW107XG4gICAgZm9yIChsZXQgdHhPck1ldGFkYXRhIG9mIHR4c09yTWV0YWRhdGFzKSB0eE1ldGFkYXRhcy5wdXNoKHR4T3JNZXRhZGF0YSBpbnN0YW5jZW9mIE1vbmVyb1R4V2FsbGV0ID8gdHhPck1ldGFkYXRhLmdldE1ldGFkYXRhKCkgOiB0eE9yTWV0YWRhdGEpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRoaXMubW9kdWxlLnJlbGF5X3R4cyh0aGlzLmNwcEFkZHJlc3MsIEpTT04uc3RyaW5naWZ5KHt0eE1ldGFkYXRhczogdHhNZXRhZGF0YXN9KSwgKHR4SGFzaGVzSnNvbikgPT4ge1xuICAgICAgICAgIGlmICh0eEhhc2hlc0pzb24uY2hhckF0KDApICE9PSAneycpIHJlamVjdChuZXcgTW9uZXJvRXJyb3IodHhIYXNoZXNKc29uKSk7XG4gICAgICAgICAgZWxzZSByZXNvbHZlKEpTT04ucGFyc2UodHhIYXNoZXNKc29uKS50eEhhc2hlcyk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGRlc2NyaWJlVHhTZXQodHhTZXQ6IE1vbmVyb1R4U2V0KTogUHJvbWlzZTxNb25lcm9UeFNldD4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuZGVzY3JpYmVUeFNldCh0eFNldCk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgdHhTZXQgPSBuZXcgTW9uZXJvVHhTZXQoe3Vuc2lnbmVkVHhIZXg6IHR4U2V0LmdldFVuc2lnbmVkVHhIZXgoKSwgc2lnbmVkVHhIZXg6IHR4U2V0LmdldFNpZ25lZFR4SGV4KCksIG11bHRpc2lnVHhIZXg6IHR4U2V0LmdldE11bHRpc2lnVHhIZXgoKX0pO1xuICAgICAgdHJ5IHsgcmV0dXJuIG5ldyBNb25lcm9UeFNldChKU09OLnBhcnNlKEdlblV0aWxzLnN0cmluZ2lmeUJpZ0ludHModGhpcy5tb2R1bGUuZGVzY3JpYmVfdHhfc2V0KHRoaXMuY3BwQWRkcmVzcywgSlNPTi5zdHJpbmdpZnkodHhTZXQudG9Kc29uKCkpKSkpKTsgfVxuICAgICAgY2F0Y2ggKGVycikgeyB0aHJvdyBuZXcgTW9uZXJvRXJyb3IodGhpcy5tb2R1bGUuZ2V0X2V4Y2VwdGlvbl9tZXNzYWdlKGVycikpOyB9XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIHNpZ25UeHModW5zaWduZWRUeEhleDogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9UeFNldD4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuc2lnblR4cyh1bnNpZ25lZFR4SGV4KTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICB0cnkgeyByZXR1cm4gbmV3IE1vbmVyb1R4U2V0KEpTT04ucGFyc2UoR2VuVXRpbHMuc3RyaW5naWZ5QmlnSW50cyh0aGlzLm1vZHVsZS5zaWduX3R4cyh0aGlzLmNwcEFkZHJlc3MsIHVuc2lnbmVkVHhIZXgpKSkpOyB9XG4gICAgICBjYXRjaCAoZXJyKSB7IHRocm93IG5ldyBNb25lcm9FcnJvcih0aGlzLm1vZHVsZS5nZXRfZXhjZXB0aW9uX21lc3NhZ2UoZXJyKSk7IH1cbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgc3VibWl0VHhzKHNpZ25lZFR4SGV4OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5zdWJtaXRUeHMoc2lnbmVkVHhIZXgpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRoaXMubW9kdWxlLnN1Ym1pdF90eHModGhpcy5jcHBBZGRyZXNzLCBzaWduZWRUeEhleCwgKHJlc3ApID0+IHtcbiAgICAgICAgICBpZiAocmVzcC5jaGFyQXQoMCkgIT09ICd7JykgcmVqZWN0KG5ldyBNb25lcm9FcnJvcihyZXNwKSk7XG4gICAgICAgICAgZWxzZSByZXNvbHZlKEpTT04ucGFyc2UocmVzcCkudHhIYXNoZXMpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBzaWduTWVzc2FnZShtZXNzYWdlOiBzdHJpbmcsIHNpZ25hdHVyZVR5cGUgPSBNb25lcm9NZXNzYWdlU2lnbmF0dXJlVHlwZS5TSUdOX1dJVEhfU1BFTkRfS0VZLCBhY2NvdW50SWR4ID0gMCwgc3ViYWRkcmVzc0lkeCA9IDApOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuc2lnbk1lc3NhZ2UobWVzc2FnZSwgc2lnbmF0dXJlVHlwZSwgYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCk7XG4gICAgXG4gICAgLy8gYXNzaWduIGRlZmF1bHRzXG4gICAgc2lnbmF0dXJlVHlwZSA9IHNpZ25hdHVyZVR5cGUgfHwgTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGUuU0lHTl9XSVRIX1NQRU5EX0tFWTtcbiAgICBhY2NvdW50SWR4ID0gYWNjb3VudElkeCB8fCAwO1xuICAgIHN1YmFkZHJlc3NJZHggPSBzdWJhZGRyZXNzSWR4IHx8IDA7XG4gICAgXG4gICAgLy8gcXVldWUgdGFzayB0byBzaWduIG1lc3NhZ2VcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICB0cnkgeyByZXR1cm4gdGhpcy5tb2R1bGUuc2lnbl9tZXNzYWdlKHRoaXMuY3BwQWRkcmVzcywgbWVzc2FnZSwgc2lnbmF0dXJlVHlwZSA9PT0gTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGUuU0lHTl9XSVRIX1NQRU5EX0tFWSA/IDAgOiAxLCBhY2NvdW50SWR4LCBzdWJhZGRyZXNzSWR4KTsgfVxuICAgICAgY2F0Y2ggKGVycikgeyB0aHJvdyBuZXcgTW9uZXJvRXJyb3IodGhpcy5tb2R1bGUuZ2V0X2V4Y2VwdGlvbl9tZXNzYWdlKGVycikpOyB9XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIHZlcmlmeU1lc3NhZ2UobWVzc2FnZTogc3RyaW5nLCBhZGRyZXNzOiBzdHJpbmcsIHNpZ25hdHVyZTogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9NZXNzYWdlU2lnbmF0dXJlUmVzdWx0PiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS52ZXJpZnlNZXNzYWdlKG1lc3NhZ2UsIGFkZHJlc3MsIHNpZ25hdHVyZSk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgbGV0IHJlc3VsdDtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJlc3VsdCA9IEpTT04ucGFyc2UodGhpcy5tb2R1bGUudmVyaWZ5X21lc3NhZ2UodGhpcy5jcHBBZGRyZXNzLCBtZXNzYWdlLCBhZGRyZXNzLCBzaWduYXR1cmUpKTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICByZXN1bHQgPSB7aXNHb29kOiBmYWxzZX07XG4gICAgICB9XG4gICAgICByZXR1cm4gbmV3IE1vbmVyb01lc3NhZ2VTaWduYXR1cmVSZXN1bHQocmVzdWx0LmlzR29vZCA/XG4gICAgICAgIHtpc0dvb2Q6IHJlc3VsdC5pc0dvb2QsIGlzT2xkOiByZXN1bHQuaXNPbGQsIHNpZ25hdHVyZVR5cGU6IHJlc3VsdC5zaWduYXR1cmVUeXBlID09PSBcInNwZW5kXCIgPyBNb25lcm9NZXNzYWdlU2lnbmF0dXJlVHlwZS5TSUdOX1dJVEhfU1BFTkRfS0VZIDogTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGUuU0lHTl9XSVRIX1ZJRVdfS0VZLCB2ZXJzaW9uOiByZXN1bHQudmVyc2lvbn0gOlxuICAgICAgICB7aXNHb29kOiBmYWxzZX1cbiAgICAgICk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFR4S2V5KHR4SGFzaDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldFR4S2V5KHR4SGFzaCk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgdHJ5IHsgcmV0dXJuIHRoaXMubW9kdWxlLmdldF90eF9rZXkodGhpcy5jcHBBZGRyZXNzLCB0eEhhc2gpOyB9XG4gICAgICBjYXRjaCAoZXJyKSB7IHRocm93IG5ldyBNb25lcm9FcnJvcih0aGlzLm1vZHVsZS5nZXRfZXhjZXB0aW9uX21lc3NhZ2UoZXJyKSk7IH1cbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgY2hlY2tUeEtleSh0eEhhc2g6IHN0cmluZywgdHhLZXk6IHN0cmluZywgYWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9DaGVja1R4PiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5jaGVja1R4S2V5KHR4SGFzaCwgdHhLZXksIGFkZHJlc3MpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTsgXG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5jaGVja190eF9rZXkodGhpcy5jcHBBZGRyZXNzLCB0eEhhc2gsIHR4S2V5LCBhZGRyZXNzLCAocmVzcEpzb25TdHIpID0+IHtcbiAgICAgICAgICBpZiAocmVzcEpzb25TdHIuY2hhckF0KDApICE9PSAneycpIHJlamVjdChuZXcgTW9uZXJvRXJyb3IocmVzcEpzb25TdHIpKTtcbiAgICAgICAgICBlbHNlIHJlc29sdmUobmV3IE1vbmVyb0NoZWNrVHgoSlNPTi5wYXJzZShHZW5VdGlscy5zdHJpbmdpZnlCaWdJbnRzKHJlc3BKc29uU3RyKSkpKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0VHhQcm9vZih0eEhhc2g6IHN0cmluZywgYWRkcmVzczogc3RyaW5nLCBtZXNzYWdlPzogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldFR4UHJvb2YodHhIYXNoLCBhZGRyZXNzLCBtZXNzYWdlKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5nZXRfdHhfcHJvb2YodGhpcy5jcHBBZGRyZXNzLCB0eEhhc2ggfHwgXCJcIiwgYWRkcmVzcyB8fCBcIlwiLCBtZXNzYWdlIHx8IFwiXCIsIChzaWduYXR1cmUpID0+IHtcbiAgICAgICAgICBsZXQgZXJyb3JLZXkgPSBcImVycm9yOiBcIjtcbiAgICAgICAgICBpZiAoc2lnbmF0dXJlLmluZGV4T2YoZXJyb3JLZXkpID09PSAwKSByZWplY3QobmV3IE1vbmVyb0Vycm9yKHNpZ25hdHVyZS5zdWJzdHJpbmcoZXJyb3JLZXkubGVuZ3RoKSkpO1xuICAgICAgICAgIGVsc2UgcmVzb2x2ZShzaWduYXR1cmUpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBjaGVja1R4UHJvb2YodHhIYXNoOiBzdHJpbmcsIGFkZHJlc3M6IHN0cmluZywgbWVzc2FnZTogc3RyaW5nIHwgdW5kZWZpbmVkLCBzaWduYXR1cmU6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvQ2hlY2tUeD4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuY2hlY2tUeFByb29mKHR4SGFzaCwgYWRkcmVzcywgbWVzc2FnZSwgc2lnbmF0dXJlKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7IFxuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgdGhpcy5tb2R1bGUuY2hlY2tfdHhfcHJvb2YodGhpcy5jcHBBZGRyZXNzLCB0eEhhc2ggfHwgXCJcIiwgYWRkcmVzcyB8fCBcIlwiLCBtZXNzYWdlIHx8IFwiXCIsIHNpZ25hdHVyZSB8fCBcIlwiLCAocmVzcEpzb25TdHIpID0+IHtcbiAgICAgICAgICBpZiAocmVzcEpzb25TdHIuY2hhckF0KDApICE9PSAneycpIHJlamVjdChuZXcgTW9uZXJvRXJyb3IocmVzcEpzb25TdHIpKTtcbiAgICAgICAgICBlbHNlIHJlc29sdmUobmV3IE1vbmVyb0NoZWNrVHgoSlNPTi5wYXJzZShHZW5VdGlscy5zdHJpbmdpZnlCaWdJbnRzKHJlc3BKc29uU3RyKSkpKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0U3BlbmRQcm9vZih0eEhhc2g6IHN0cmluZywgbWVzc2FnZT86IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRTcGVuZFByb29mKHR4SGFzaCwgbWVzc2FnZSk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgdGhpcy5tb2R1bGUuZ2V0X3NwZW5kX3Byb29mKHRoaXMuY3BwQWRkcmVzcywgdHhIYXNoIHx8IFwiXCIsIG1lc3NhZ2UgfHwgXCJcIiwgKHNpZ25hdHVyZSkgPT4ge1xuICAgICAgICAgIGxldCBlcnJvcktleSA9IFwiZXJyb3I6IFwiO1xuICAgICAgICAgIGlmIChzaWduYXR1cmUuaW5kZXhPZihlcnJvcktleSkgPT09IDApIHJlamVjdChuZXcgTW9uZXJvRXJyb3Ioc2lnbmF0dXJlLnN1YnN0cmluZyhlcnJvcktleS5sZW5ndGgpKSk7XG4gICAgICAgICAgZWxzZSByZXNvbHZlKHNpZ25hdHVyZSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGNoZWNrU3BlbmRQcm9vZih0eEhhc2g6IHN0cmluZywgbWVzc2FnZTogc3RyaW5nIHwgdW5kZWZpbmVkLCBzaWduYXR1cmU6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuY2hlY2tTcGVuZFByb29mKHR4SGFzaCwgbWVzc2FnZSwgc2lnbmF0dXJlKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7IFxuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgdGhpcy5tb2R1bGUuY2hlY2tfc3BlbmRfcHJvb2YodGhpcy5jcHBBZGRyZXNzLCB0eEhhc2ggfHwgXCJcIiwgbWVzc2FnZSB8fCBcIlwiLCBzaWduYXR1cmUgfHwgXCJcIiwgKHJlc3ApID0+IHtcbiAgICAgICAgICB0eXBlb2YgcmVzcCA9PT0gXCJzdHJpbmdcIiA/IHJlamVjdChuZXcgTW9uZXJvRXJyb3IocmVzcCkpIDogcmVzb2x2ZShyZXNwKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UmVzZXJ2ZVByb29mV2FsbGV0KG1lc3NhZ2U/OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuZ2V0UmVzZXJ2ZVByb29mV2FsbGV0KG1lc3NhZ2UpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRoaXMubW9kdWxlLmdldF9yZXNlcnZlX3Byb29mX3dhbGxldCh0aGlzLmNwcEFkZHJlc3MsIG1lc3NhZ2UsIChzaWduYXR1cmUpID0+IHtcbiAgICAgICAgICBsZXQgZXJyb3JLZXkgPSBcImVycm9yOiBcIjtcbiAgICAgICAgICBpZiAoc2lnbmF0dXJlLmluZGV4T2YoZXJyb3JLZXkpID09PSAwKSByZWplY3QobmV3IE1vbmVyb0Vycm9yKHNpZ25hdHVyZS5zdWJzdHJpbmcoZXJyb3JLZXkubGVuZ3RoKSwgLTEpKTtcbiAgICAgICAgICBlbHNlIHJlc29sdmUoc2lnbmF0dXJlKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UmVzZXJ2ZVByb29mQWNjb3VudChhY2NvdW50SWR4OiBudW1iZXIsIGFtb3VudDogYmlnaW50LCBtZXNzYWdlPzogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldFJlc2VydmVQcm9vZkFjY291bnQoYWNjb3VudElkeCwgYW1vdW50LCBtZXNzYWdlKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5nZXRfcmVzZXJ2ZV9wcm9vZl9hY2NvdW50KHRoaXMuY3BwQWRkcmVzcywgYWNjb3VudElkeCwgYW1vdW50LnRvU3RyaW5nKCksIG1lc3NhZ2UsIChzaWduYXR1cmUpID0+IHtcbiAgICAgICAgICBsZXQgZXJyb3JLZXkgPSBcImVycm9yOiBcIjtcbiAgICAgICAgICBpZiAoc2lnbmF0dXJlLmluZGV4T2YoZXJyb3JLZXkpID09PSAwKSByZWplY3QobmV3IE1vbmVyb0Vycm9yKHNpZ25hdHVyZS5zdWJzdHJpbmcoZXJyb3JLZXkubGVuZ3RoKSwgLTEpKTtcbiAgICAgICAgICBlbHNlIHJlc29sdmUoc2lnbmF0dXJlKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIGNoZWNrUmVzZXJ2ZVByb29mKGFkZHJlc3M6IHN0cmluZywgbWVzc2FnZTogc3RyaW5nIHwgdW5kZWZpbmVkLCBzaWduYXR1cmU6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvQ2hlY2tSZXNlcnZlPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5jaGVja1Jlc2VydmVQcm9vZihhZGRyZXNzLCBtZXNzYWdlLCBzaWduYXR1cmUpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTsgXG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5jaGVja19yZXNlcnZlX3Byb29mKHRoaXMuY3BwQWRkcmVzcywgYWRkcmVzcywgbWVzc2FnZSwgc2lnbmF0dXJlLCAocmVzcEpzb25TdHIpID0+IHtcbiAgICAgICAgICBpZiAocmVzcEpzb25TdHIuY2hhckF0KDApICE9PSAneycpIHJlamVjdChuZXcgTW9uZXJvRXJyb3IocmVzcEpzb25TdHIsIC0xKSk7XG4gICAgICAgICAgZWxzZSByZXNvbHZlKG5ldyBNb25lcm9DaGVja1Jlc2VydmUoSlNPTi5wYXJzZShHZW5VdGlscy5zdHJpbmdpZnlCaWdJbnRzKHJlc3BKc29uU3RyKSkpKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0VHhOb3Rlcyh0eEhhc2hlczogc3RyaW5nW10pOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRUeE5vdGVzKHR4SGFzaGVzKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICB0cnkgeyByZXR1cm4gSlNPTi5wYXJzZSh0aGlzLm1vZHVsZS5nZXRfdHhfbm90ZXModGhpcy5jcHBBZGRyZXNzLCBKU09OLnN0cmluZ2lmeSh7dHhIYXNoZXM6IHR4SGFzaGVzfSkpKS50eE5vdGVzOyB9XG4gICAgICBjYXRjaCAoZXJyKSB7IHRocm93IG5ldyBNb25lcm9FcnJvcih0aGlzLm1vZHVsZS5nZXRfZXhjZXB0aW9uX21lc3NhZ2UoZXJyKSk7IH1cbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgc2V0VHhOb3Rlcyh0eEhhc2hlczogc3RyaW5nW10sIG5vdGVzOiBzdHJpbmdbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuc2V0VHhOb3Rlcyh0eEhhc2hlcywgbm90ZXMpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHRyeSB7IHRoaXMubW9kdWxlLnNldF90eF9ub3Rlcyh0aGlzLmNwcEFkZHJlc3MsIEpTT04uc3RyaW5naWZ5KHt0eEhhc2hlczogdHhIYXNoZXMsIHR4Tm90ZXM6IG5vdGVzfSkpOyB9XG4gICAgICBjYXRjaCAoZXJyKSB7IHRocm93IG5ldyBNb25lcm9FcnJvcih0aGlzLm1vZHVsZS5nZXRfZXhjZXB0aW9uX21lc3NhZ2UoZXJyKSk7IH1cbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QWRkcmVzc0Jvb2tFbnRyaWVzKGVudHJ5SW5kaWNlcz86IG51bWJlcltdKTogUHJvbWlzZTxNb25lcm9BZGRyZXNzQm9va0VudHJ5W10+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldEFkZHJlc3NCb29rRW50cmllcyhlbnRyeUluZGljZXMpO1xuICAgIGlmICghZW50cnlJbmRpY2VzKSBlbnRyeUluZGljZXMgPSBbXTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICBsZXQgZW50cmllcyA9IFtdO1xuICAgICAgZm9yIChsZXQgZW50cnlKc29uIG9mIEpTT04ucGFyc2UodGhpcy5tb2R1bGUuZ2V0X2FkZHJlc3NfYm9va19lbnRyaWVzKHRoaXMuY3BwQWRkcmVzcywgSlNPTi5zdHJpbmdpZnkoe2VudHJ5SW5kaWNlczogZW50cnlJbmRpY2VzfSkpKS5lbnRyaWVzKSB7XG4gICAgICAgIGVudHJpZXMucHVzaChuZXcgTW9uZXJvQWRkcmVzc0Jvb2tFbnRyeShlbnRyeUpzb24pKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBlbnRyaWVzO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBhZGRBZGRyZXNzQm9va0VudHJ5KGFkZHJlc3M6IHN0cmluZywgZGVzY3JpcHRpb24/OiBzdHJpbmcpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuYWRkQWRkcmVzc0Jvb2tFbnRyeShhZGRyZXNzLCBkZXNjcmlwdGlvbik7XG4gICAgaWYgKCFhZGRyZXNzKSBhZGRyZXNzID0gXCJcIjtcbiAgICBpZiAoIWRlc2NyaXB0aW9uKSBkZXNjcmlwdGlvbiA9IFwiXCI7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIHRoaXMubW9kdWxlLmFkZF9hZGRyZXNzX2Jvb2tfZW50cnkodGhpcy5jcHBBZGRyZXNzLCBhZGRyZXNzLCBkZXNjcmlwdGlvbik7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGVkaXRBZGRyZXNzQm9va0VudHJ5KGluZGV4OiBudW1iZXIsIHNldEFkZHJlc3M6IGJvb2xlYW4sIGFkZHJlc3M6IHN0cmluZyB8IHVuZGVmaW5lZCwgc2V0RGVzY3JpcHRpb246IGJvb2xlYW4sIGRlc2NyaXB0aW9uOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmVkaXRBZGRyZXNzQm9va0VudHJ5KGluZGV4LCBzZXRBZGRyZXNzLCBhZGRyZXNzLCBzZXREZXNjcmlwdGlvbiwgZGVzY3JpcHRpb24pO1xuICAgIGlmICghc2V0QWRkcmVzcykgc2V0QWRkcmVzcyA9IGZhbHNlO1xuICAgIGlmICghYWRkcmVzcykgYWRkcmVzcyA9IFwiXCI7XG4gICAgaWYgKCFzZXREZXNjcmlwdGlvbikgc2V0RGVzY3JpcHRpb24gPSBmYWxzZTtcbiAgICBpZiAoIWRlc2NyaXB0aW9uKSBkZXNjcmlwdGlvbiA9IFwiXCI7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgdGhpcy5tb2R1bGUuZWRpdF9hZGRyZXNzX2Jvb2tfZW50cnkodGhpcy5jcHBBZGRyZXNzLCBpbmRleCwgc2V0QWRkcmVzcywgYWRkcmVzcywgc2V0RGVzY3JpcHRpb24sIGRlc2NyaXB0aW9uKTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZGVsZXRlQWRkcmVzc0Jvb2tFbnRyeShlbnRyeUlkeDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5kZWxldGVBZGRyZXNzQm9va0VudHJ5KGVudHJ5SWR4KTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICB0aGlzLm1vZHVsZS5kZWxldGVfYWRkcmVzc19ib29rX2VudHJ5KHRoaXMuY3BwQWRkcmVzcywgZW50cnlJZHgpO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyB0YWdBY2NvdW50cyh0YWc6IHN0cmluZywgYWNjb3VudEluZGljZXM6IG51bWJlcltdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS50YWdBY2NvdW50cyh0YWcsIGFjY291bnRJbmRpY2VzKTtcbiAgICBpZiAoIXRhZykgdGFnID0gXCJcIjtcbiAgICBpZiAoIWFjY291bnRJbmRpY2VzKSBhY2NvdW50SW5kaWNlcyA9IFtdO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHRoaXMubW9kdWxlLnRhZ19hY2NvdW50cyh0aGlzLmNwcEFkZHJlc3MsIEpTT04uc3RyaW5naWZ5KHt0YWc6IHRhZywgYWNjb3VudEluZGljZXM6IGFjY291bnRJbmRpY2VzfSkpO1xuICAgIH0pO1xuICB9XG5cbiAgYXN5bmMgdW50YWdBY2NvdW50cyhhY2NvdW50SW5kaWNlczogbnVtYmVyW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLnVudGFnQWNjb3VudHMoYWNjb3VudEluZGljZXMpO1xuICAgIGlmICghYWNjb3VudEluZGljZXMpIGFjY291bnRJbmRpY2VzID0gW107XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgdGhpcy5tb2R1bGUudGFnX2FjY291bnRzKHRoaXMuY3BwQWRkcmVzcywgSlNPTi5zdHJpbmdpZnkoe2FjY291bnRJbmRpY2VzOiBhY2NvdW50SW5kaWNlc30pKTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QWNjb3VudFRhZ3MoKTogUHJvbWlzZTxNb25lcm9BY2NvdW50VGFnW10+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldEFjY291bnRUYWdzKCk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgbGV0IGFjY291bnRUYWdzID0gW107XG4gICAgICBmb3IgKGxldCBhY2NvdW50VGFnSnNvbiBvZiBKU09OLnBhcnNlKHRoaXMubW9kdWxlLmdldF9hY2NvdW50X3RhZ3ModGhpcy5jcHBBZGRyZXNzKSkuYWNjb3VudFRhZ3MpIGFjY291bnRUYWdzLnB1c2gobmV3IE1vbmVyb0FjY291bnRUYWcoYWNjb3VudFRhZ0pzb24pKTtcbiAgICAgIHJldHVybiBhY2NvdW50VGFncztcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIHNldEFjY291bnRUYWdMYWJlbCh0YWc6IHN0cmluZywgbGFiZWw6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuc2V0QWNjb3VudFRhZ0xhYmVsKHRhZywgbGFiZWwpO1xuICAgIGlmICghdGFnKSB0YWcgPSBcIlwiO1xuICAgIGlmICghbGFiZWwpIGxhYmVsID0gXCJcIjtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICB0aGlzLm1vZHVsZS5zZXRfYWNjb3VudF90YWdfbGFiZWwodGhpcy5jcHBBZGRyZXNzLCB0YWcsIGxhYmVsKTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UGF5bWVudFVyaShjb25maWc6IE1vbmVyb1R4Q29uZmlnKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldFBheW1lbnRVcmkoY29uZmlnKTtcbiAgICBjb25maWcgPSBNb25lcm9XYWxsZXQubm9ybWFsaXplQ3JlYXRlVHhzQ29uZmlnKGNvbmZpZyk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIHRoaXMubW9kdWxlLmdldF9wYXltZW50X3VyaSh0aGlzLmNwcEFkZHJlc3MsIEpTT04uc3RyaW5naWZ5KGNvbmZpZy50b0pzb24oKSkpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBtYWtlIFVSSSBmcm9tIHN1cHBsaWVkIHBhcmFtZXRlcnNcIik7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIHBhcnNlUGF5bWVudFVyaSh1cmk6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvVHhDb25maWc+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLnBhcnNlUGF5bWVudFVyaSh1cmkpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBuZXcgTW9uZXJvVHhDb25maWcoSlNPTi5wYXJzZShHZW5VdGlscy5zdHJpbmdpZnlCaWdJbnRzKHRoaXMubW9kdWxlLnBhcnNlX3BheW1lbnRfdXJpKHRoaXMuY3BwQWRkcmVzcywgdXJpKSkpKTtcbiAgICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihlcnIubWVzc2FnZSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEF0dHJpYnV0ZShrZXk6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRBdHRyaWJ1dGUoa2V5KTtcbiAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgIGFzc2VydCh0eXBlb2Yga2V5ID09PSBcInN0cmluZ1wiLCBcIkF0dHJpYnV0ZSBrZXkgbXVzdCBiZSBhIHN0cmluZ1wiKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICBsZXQgdmFsdWUgPSB0aGlzLm1vZHVsZS5nZXRfYXR0cmlidXRlKHRoaXMuY3BwQWRkcmVzcywga2V5KTtcbiAgICAgIHJldHVybiB2YWx1ZSA9PT0gXCJcIiA/IG51bGwgOiB2YWx1ZTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgc2V0QXR0cmlidXRlKGtleTogc3RyaW5nLCB2YWw6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuc2V0QXR0cmlidXRlKGtleSwgdmFsKTtcbiAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgIGFzc2VydCh0eXBlb2Yga2V5ID09PSBcInN0cmluZ1wiLCBcIkF0dHJpYnV0ZSBrZXkgbXVzdCBiZSBhIHN0cmluZ1wiKTtcbiAgICBhc3NlcnQodHlwZW9mIHZhbCA9PT0gXCJzdHJpbmdcIiwgXCJBdHRyaWJ1dGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZ1wiKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICB0aGlzLm1vZHVsZS5zZXRfYXR0cmlidXRlKHRoaXMuY3BwQWRkcmVzcywga2V5LCB2YWwpO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBzdGFydE1pbmluZyhudW1UaHJlYWRzOiBudW1iZXIsIGJhY2tncm91bmRNaW5pbmc/OiBib29sZWFuLCBpZ25vcmVCYXR0ZXJ5PzogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuc3RhcnRNaW5pbmcobnVtVGhyZWFkcywgYmFja2dyb3VuZE1pbmluZywgaWdub3JlQmF0dGVyeSk7XG4gICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICBsZXQgZGFlbW9uID0gYXdhaXQgTW9uZXJvRGFlbW9uUnBjLmNvbm5lY3RUb0RhZW1vblJwYyhhd2FpdCB0aGlzLmdldERhZW1vbkNvbm5lY3Rpb24oKSk7XG4gICAgYXdhaXQgZGFlbW9uLnN0YXJ0TWluaW5nKGF3YWl0IHRoaXMuZ2V0UHJpbWFyeUFkZHJlc3MoKSwgbnVtVGhyZWFkcywgYmFja2dyb3VuZE1pbmluZywgaWdub3JlQmF0dGVyeSk7XG4gIH1cbiAgXG4gIGFzeW5jIHN0b3BNaW5pbmcoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5zdG9wTWluaW5nKCk7XG4gICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICBsZXQgZGFlbW9uID0gYXdhaXQgTW9uZXJvRGFlbW9uUnBjLmNvbm5lY3RUb0RhZW1vblJwYyhhd2FpdCB0aGlzLmdldERhZW1vbkNvbm5lY3Rpb24oKSk7XG4gICAgYXdhaXQgZGFlbW9uLnN0b3BNaW5pbmcoKTtcbiAgfVxuICBcbiAgYXN5bmMgaXNNdWx0aXNpZ0ltcG9ydE5lZWRlZCgpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmlzTXVsdGlzaWdJbXBvcnROZWVkZWQoKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gdGhpcy5tb2R1bGUuaXNfbXVsdGlzaWdfaW1wb3J0X25lZWRlZCh0aGlzLmNwcEFkZHJlc3MpO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBpc011bHRpc2lnKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuaXNNdWx0aXNpZygpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiB0aGlzLm1vZHVsZS5pc19tdWx0aXNpZyh0aGlzLmNwcEFkZHJlc3MpO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBnZXRNdWx0aXNpZ0luZm8oKTogUHJvbWlzZTxNb25lcm9NdWx0aXNpZ0luZm8+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldE11bHRpc2lnSW5mbygpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgTW9uZXJvTXVsdGlzaWdJbmZvKEpTT04ucGFyc2UodGhpcy5tb2R1bGUuZ2V0X211bHRpc2lnX2luZm8odGhpcy5jcHBBZGRyZXNzKSkpO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBwcmVwYXJlTXVsdGlzaWcoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLnByZXBhcmVNdWx0aXNpZygpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiB0aGlzLm1vZHVsZS5wcmVwYXJlX211bHRpc2lnKHRoaXMuY3BwQWRkcmVzcyk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIG1ha2VNdWx0aXNpZyhtdWx0aXNpZ0hleGVzOiBzdHJpbmdbXSwgdGhyZXNob2xkOiBudW1iZXIsIHBhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkubWFrZU11bHRpc2lnKG11bHRpc2lnSGV4ZXMsIHRocmVzaG9sZCwgcGFzc3dvcmQpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRoaXMubW9kdWxlLm1ha2VfbXVsdGlzaWcodGhpcy5jcHBBZGRyZXNzLCBKU09OLnN0cmluZ2lmeSh7bXVsdGlzaWdIZXhlczogbXVsdGlzaWdIZXhlcywgdGhyZXNob2xkOiB0aHJlc2hvbGQsIHBhc3N3b3JkOiBwYXNzd29yZH0pLCAocmVzcCkgPT4ge1xuICAgICAgICAgIGxldCBlcnJvcktleSA9IFwiZXJyb3I6IFwiO1xuICAgICAgICAgIGlmIChyZXNwLmluZGV4T2YoZXJyb3JLZXkpID09PSAwKSByZWplY3QobmV3IE1vbmVyb0Vycm9yKHJlc3Auc3Vic3RyaW5nKGVycm9yS2V5Lmxlbmd0aCkpKTtcbiAgICAgICAgICBlbHNlIHJlc29sdmUocmVzcCk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGV4Y2hhbmdlTXVsdGlzaWdLZXlzKG11bHRpc2lnSGV4ZXM6IHN0cmluZ1tdLCBwYXNzd29yZDogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9NdWx0aXNpZ0luaXRSZXN1bHQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmV4Y2hhbmdlTXVsdGlzaWdLZXlzKG11bHRpc2lnSGV4ZXMsIHBhc3N3b3JkKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5leGNoYW5nZV9tdWx0aXNpZ19rZXlzKHRoaXMuY3BwQWRkcmVzcywgSlNPTi5zdHJpbmdpZnkoe211bHRpc2lnSGV4ZXM6IG11bHRpc2lnSGV4ZXMsIHBhc3N3b3JkOiBwYXNzd29yZH0pLCAocmVzcCkgPT4ge1xuICAgICAgICAgIGxldCBlcnJvcktleSA9IFwiZXJyb3I6IFwiO1xuICAgICAgICAgIGlmIChyZXNwLmluZGV4T2YoZXJyb3JLZXkpID09PSAwKSByZWplY3QobmV3IE1vbmVyb0Vycm9yKHJlc3Auc3Vic3RyaW5nKGVycm9yS2V5Lmxlbmd0aCkpKTtcbiAgICAgICAgICBlbHNlIHJlc29sdmUobmV3IE1vbmVyb011bHRpc2lnSW5pdFJlc3VsdChKU09OLnBhcnNlKHJlc3ApKSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGV4cG9ydE11bHRpc2lnSGV4KCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5leHBvcnRNdWx0aXNpZ0hleCgpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiB0aGlzLm1vZHVsZS5leHBvcnRfbXVsdGlzaWdfaGV4KHRoaXMuY3BwQWRkcmVzcyk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGltcG9ydE11bHRpc2lnSGV4KG11bHRpc2lnSGV4ZXM6IHN0cmluZ1tdKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmltcG9ydE11bHRpc2lnSGV4KG11bHRpc2lnSGV4ZXMpO1xuICAgIGlmICghR2VuVXRpbHMuaXNBcnJheShtdWx0aXNpZ0hleGVzKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTXVzdCBwcm92aWRlIHN0cmluZ1tdIHRvIGltcG9ydE11bHRpc2lnSGV4KClcIilcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICB0aGlzLm1vZHVsZS5pbXBvcnRfbXVsdGlzaWdfaGV4KHRoaXMuY3BwQWRkcmVzcywgSlNPTi5zdHJpbmdpZnkoe211bHRpc2lnSGV4ZXM6IG11bHRpc2lnSGV4ZXN9KSwgKHJlc3ApID0+IHtcbiAgICAgICAgICBpZiAodHlwZW9mIHJlc3AgPT09IFwic3RyaW5nXCIpIHJlamVjdChuZXcgTW9uZXJvRXJyb3IocmVzcCkpO1xuICAgICAgICAgIGVsc2UgcmVzb2x2ZShyZXNwKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgc2lnbk11bHRpc2lnVHhIZXgobXVsdGlzaWdUeEhleDogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9NdWx0aXNpZ1NpZ25SZXN1bHQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLnNpZ25NdWx0aXNpZ1R4SGV4KG11bHRpc2lnVHhIZXgpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRoaXMubW9kdWxlLnNpZ25fbXVsdGlzaWdfdHhfaGV4KHRoaXMuY3BwQWRkcmVzcywgbXVsdGlzaWdUeEhleCwgKHJlc3ApID0+IHtcbiAgICAgICAgICBpZiAocmVzcC5jaGFyQXQoMCkgIT09ICd7JykgcmVqZWN0KG5ldyBNb25lcm9FcnJvcihyZXNwKSk7XG4gICAgICAgICAgZWxzZSByZXNvbHZlKG5ldyBNb25lcm9NdWx0aXNpZ1NpZ25SZXN1bHQoSlNPTi5wYXJzZShyZXNwKSkpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBzdWJtaXRNdWx0aXNpZ1R4SGV4KHNpZ25lZE11bHRpc2lnVHhIZXg6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLnN1Ym1pdE11bHRpc2lnVHhIZXgoc2lnbmVkTXVsdGlzaWdUeEhleCk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgdGhpcy5tb2R1bGUuc3VibWl0X211bHRpc2lnX3R4X2hleCh0aGlzLmNwcEFkZHJlc3MsIHNpZ25lZE11bHRpc2lnVHhIZXgsIChyZXNwKSA9PiB7XG4gICAgICAgICAgaWYgKHJlc3AuY2hhckF0KDApICE9PSAneycpIHJlamVjdChuZXcgTW9uZXJvRXJyb3IocmVzcCkpO1xuICAgICAgICAgIGVsc2UgcmVzb2x2ZShKU09OLnBhcnNlKHJlc3ApLnR4SGFzaGVzKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgd2FsbGV0J3Mga2V5cyBhbmQgY2FjaGUgZGF0YS5cbiAgICogXG4gICAqIEByZXR1cm4ge1Byb21pc2U8RGF0YVZpZXdbXT59IGlzIHRoZSBrZXlzIGFuZCBjYWNoZSBkYXRhLCByZXNwZWN0aXZlbHlcbiAgICovXG4gIGFzeW5jIGdldERhdGEoKTogUHJvbWlzZTxEYXRhVmlld1tdPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXREYXRhKCk7XG4gICAgXG4gICAgLy8gcXVldWUgY2FsbCB0byB3YXNtIG1vZHVsZVxuICAgIGxldCB2aWV3T25seSA9IGF3YWl0IHRoaXMuaXNWaWV3T25seSgpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIFxuICAgICAgLy8gc3RvcmUgdmlld3MgaW4gYXJyYXlcbiAgICAgIGxldCB2aWV3cyA9IFtdO1xuICAgICAgXG4gICAgICAvLyBtYWxsb2MgY2FjaGUgYnVmZmVyIGFuZCBnZXQgYnVmZmVyIGxvY2F0aW9uIGluIGMrKyBoZWFwXG4gICAgICBsZXQgY2FjaGVCdWZmZXJMb2MgPSBKU09OLnBhcnNlKHRoaXMubW9kdWxlLmdldF9jYWNoZV9maWxlX2J1ZmZlcih0aGlzLmNwcEFkZHJlc3MpKTtcbiAgICAgIFxuICAgICAgLy8gcmVhZCBiaW5hcnkgZGF0YSBmcm9tIGhlYXAgdG8gRGF0YVZpZXdcbiAgICAgIGxldCB2aWV3ID0gbmV3IERhdGFWaWV3KG5ldyBBcnJheUJ1ZmZlcihjYWNoZUJ1ZmZlckxvYy5sZW5ndGgpKTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2FjaGVCdWZmZXJMb2MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmlldy5zZXRJbnQ4KGksIHRoaXMubW9kdWxlLkhFQVBVOFtjYWNoZUJ1ZmZlckxvYy5wb2ludGVyIC8gVWludDhBcnJheS5CWVRFU19QRVJfRUxFTUVOVCArIGldKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gZnJlZSBiaW5hcnkgb24gaGVhcFxuICAgICAgdGhpcy5tb2R1bGUuX2ZyZWUoY2FjaGVCdWZmZXJMb2MucG9pbnRlcik7XG4gICAgICBcbiAgICAgIC8vIHdyaXRlIGNhY2hlIGZpbGVcbiAgICAgIHZpZXdzLnB1c2goQnVmZmVyLmZyb20odmlldy5idWZmZXIpKTtcbiAgICAgIFxuICAgICAgLy8gbWFsbG9jIGtleXMgYnVmZmVyIGFuZCBnZXQgYnVmZmVyIGxvY2F0aW9uIGluIGMrKyBoZWFwXG4gICAgICBsZXQga2V5c0J1ZmZlckxvYyA9IEpTT04ucGFyc2UodGhpcy5tb2R1bGUuZ2V0X2tleXNfZmlsZV9idWZmZXIodGhpcy5jcHBBZGRyZXNzLCB0aGlzLnBhc3N3b3JkLCB2aWV3T25seSkpO1xuICAgICAgXG4gICAgICAvLyByZWFkIGJpbmFyeSBkYXRhIGZyb20gaGVhcCB0byBEYXRhVmlld1xuICAgICAgdmlldyA9IG5ldyBEYXRhVmlldyhuZXcgQXJyYXlCdWZmZXIoa2V5c0J1ZmZlckxvYy5sZW5ndGgpKTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwga2V5c0J1ZmZlckxvYy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2aWV3LnNldEludDgoaSwgdGhpcy5tb2R1bGUuSEVBUFU4W2tleXNCdWZmZXJMb2MucG9pbnRlciAvIFVpbnQ4QXJyYXkuQllURVNfUEVSX0VMRU1FTlQgKyBpXSk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIGZyZWUgYmluYXJ5IG9uIGhlYXBcbiAgICAgIHRoaXMubW9kdWxlLl9mcmVlKGtleXNCdWZmZXJMb2MucG9pbnRlcik7XG4gICAgICBcbiAgICAgIC8vIHByZXBlbmQga2V5cyBmaWxlXG4gICAgICB2aWV3cy51bnNoaWZ0KEJ1ZmZlci5mcm9tKHZpZXcuYnVmZmVyKSk7XG4gICAgICByZXR1cm4gdmlld3M7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGNoYW5nZVBhc3N3b3JkKG9sZFBhc3N3b3JkOiBzdHJpbmcsIG5ld1Bhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmNoYW5nZVBhc3N3b3JkKG9sZFBhc3N3b3JkLCBuZXdQYXNzd29yZCk7XG4gICAgaWYgKG9sZFBhc3N3b3JkICE9PSB0aGlzLnBhc3N3b3JkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJJbnZhbGlkIG9yaWdpbmFsIHBhc3N3b3JkLlwiKTsgLy8gd2FsbGV0MiB2ZXJpZnlfcGFzc3dvcmQgbG9hZHMgZnJvbSBkaXNrIHNvIHZlcmlmeSBwYXNzd29yZCBoZXJlXG4gICAgaWYgKG5ld1Bhc3N3b3JkID09PSB1bmRlZmluZWQpIG5ld1Bhc3N3b3JkID0gXCJcIjtcbiAgICBhd2FpdCB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRoaXMubW9kdWxlLmNoYW5nZV93YWxsZXRfcGFzc3dvcmQodGhpcy5jcHBBZGRyZXNzLCBvbGRQYXNzd29yZCwgbmV3UGFzc3dvcmQsIChlcnJNc2cpID0+IHtcbiAgICAgICAgICBpZiAoZXJyTXNnKSByZWplY3QobmV3IE1vbmVyb0Vycm9yKGVyck1zZykpO1xuICAgICAgICAgIGVsc2UgcmVzb2x2ZSgpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIHRoaXMucGFzc3dvcmQgPSBuZXdQYXNzd29yZDtcbiAgICBpZiAodGhpcy5wYXRoKSBhd2FpdCB0aGlzLnNhdmUoKTsgLy8gYXV0byBzYXZlXG4gIH1cbiAgXG4gIGFzeW5jIHNhdmUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5zYXZlKCk7XG4gICAgcmV0dXJuIE1vbmVyb1dhbGxldEZ1bGwuc2F2ZSh0aGlzKTtcbiAgfVxuICBcbiAgYXN5bmMgY2xvc2Uoc2F2ZSA9IGZhbHNlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuX2lzQ2xvc2VkKSByZXR1cm47IC8vIG5vIGVmZmVjdCBpZiBjbG9zZWRcbiAgICBpZiAoc2F2ZSkgYXdhaXQgdGhpcy5zYXZlKCk7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkge1xuICAgICAgYXdhaXQgdGhpcy5nZXRXYWxsZXRQcm94eSgpLmNsb3NlKGZhbHNlKTtcbiAgICAgIGF3YWl0IHN1cGVyLmNsb3NlKCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGF3YWl0IHRoaXMucmVmcmVzaExpc3RlbmluZygpO1xuICAgIGF3YWl0IHRoaXMuc3RvcFN5bmNpbmcoKTtcbiAgICBhd2FpdCBzdXBlci5jbG9zZSgpO1xuICAgIGRlbGV0ZSB0aGlzLnBhdGg7XG4gICAgZGVsZXRlIHRoaXMucGFzc3dvcmQ7XG4gICAgZGVsZXRlIHRoaXMud2FzbUxpc3RlbmVyO1xuICAgIExpYnJhcnlVdGlscy5zZXRSZWplY3RVbmF1dGhvcml6ZWRGbih0aGlzLnJlamVjdFVuYXV0aG9yaXplZENvbmZpZ0lkLCB1bmRlZmluZWQpOyAvLyB1bnJlZ2lzdGVyIGZuIGluZm9ybWluZyBpZiB1bmF1dGhvcml6ZWQgcmVxcyBzaG91bGQgYmUgcmVqZWN0ZWRcbiAgfVxuICBcbiAgLy8gLS0tLS0tLS0tLS0gQUREIEpTRE9DIEZPUiBTVVBQT1JURUQgREVGQVVMVCBJTVBMRU1FTlRBVElPTlMgLS0tLS0tLS0tLS0tLS1cbiAgXG4gIGFzeW5jIGdldE51bUJsb2Nrc1RvVW5sb2NrKCk6IFByb21pc2U8bnVtYmVyW118dW5kZWZpbmVkPiB7IHJldHVybiBzdXBlci5nZXROdW1CbG9ja3NUb1VubG9jaygpOyB9XG4gIGFzeW5jIGdldFR4KHR4SGFzaDogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9UeFdhbGxldHx1bmRlZmluZWQ+IHsgcmV0dXJuIHN1cGVyLmdldFR4KHR4SGFzaCk7IH1cbiAgYXN5bmMgZ2V0SW5jb21pbmdUcmFuc2ZlcnMocXVlcnk6IFBhcnRpYWw8TW9uZXJvVHJhbnNmZXJRdWVyeT4pOiBQcm9taXNlPE1vbmVyb0luY29taW5nVHJhbnNmZXJbXT4geyByZXR1cm4gc3VwZXIuZ2V0SW5jb21pbmdUcmFuc2ZlcnMocXVlcnkpOyB9XG4gIGFzeW5jIGdldE91dGdvaW5nVHJhbnNmZXJzKHF1ZXJ5OiBQYXJ0aWFsPE1vbmVyb1RyYW5zZmVyUXVlcnk+KSB7IHJldHVybiBzdXBlci5nZXRPdXRnb2luZ1RyYW5zZmVycyhxdWVyeSk7IH1cbiAgYXN5bmMgY3JlYXRlVHgoY29uZmlnOiBQYXJ0aWFsPE1vbmVyb1R4Q29uZmlnPik6IFByb21pc2U8TW9uZXJvVHhXYWxsZXQ+IHsgcmV0dXJuIHN1cGVyLmNyZWF0ZVR4KGNvbmZpZyk7IH1cbiAgYXN5bmMgcmVsYXlUeCh0eE9yTWV0YWRhdGE6IE1vbmVyb1R4V2FsbGV0IHwgc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHsgcmV0dXJuIHN1cGVyLnJlbGF5VHgodHhPck1ldGFkYXRhKTsgfVxuICBhc3luYyBnZXRUeE5vdGUodHhIYXNoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4geyByZXR1cm4gc3VwZXIuZ2V0VHhOb3RlKHR4SGFzaCk7IH1cbiAgYXN5bmMgc2V0VHhOb3RlKHR4SGFzaDogc3RyaW5nLCBub3RlOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHsgcmV0dXJuIHN1cGVyLnNldFR4Tm90ZSh0eEhhc2gsIG5vdGUpOyB9XG4gIFxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIFBSSVZBVEUgSEVMUEVSUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgcHJvdGVjdGVkIHN0YXRpYyBhc3luYyBvcGVuV2FsbGV0RGF0YShjb25maWc6IFBhcnRpYWw8TW9uZXJvV2FsbGV0Q29uZmlnPikge1xuICAgIGlmIChjb25maWcucHJveHlUb1dvcmtlcikge1xuICAgICAgbGV0IHdhbGxldFByb3h5ID0gYXdhaXQgTW9uZXJvV2FsbGV0RnVsbFByb3h5Lm9wZW5XYWxsZXREYXRhKGNvbmZpZyk7XG4gICAgICByZXR1cm4gbmV3IE1vbmVyb1dhbGxldEZ1bGwodW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgd2FsbGV0UHJveHkpO1xuICAgIH1cbiAgICBcbiAgICAvLyB2YWxpZGF0ZSBhbmQgbm9ybWFsaXplIHBhcmFtZXRlcnNcbiAgICBpZiAoY29uZmlnLm5ldHdvcmtUeXBlID09PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk11c3QgcHJvdmlkZSB0aGUgd2FsbGV0J3MgbmV0d29yayB0eXBlXCIpO1xuICAgIGNvbmZpZy5uZXR3b3JrVHlwZSA9IE1vbmVyb05ldHdvcmtUeXBlLmZyb20oY29uZmlnLm5ldHdvcmtUeXBlKTtcbiAgICBsZXQgZGFlbW9uQ29ubmVjdGlvbiA9IGNvbmZpZy5nZXRTZXJ2ZXIoKTtcbiAgICBsZXQgZGFlbW9uVXJpID0gZGFlbW9uQ29ubmVjdGlvbiAmJiBkYWVtb25Db25uZWN0aW9uLmdldFVyaSgpID8gZGFlbW9uQ29ubmVjdGlvbi5nZXRVcmkoKSA6IFwiXCI7XG4gICAgbGV0IGRhZW1vblVzZXJuYW1lID0gZGFlbW9uQ29ubmVjdGlvbiAmJiBkYWVtb25Db25uZWN0aW9uLmdldFVzZXJuYW1lKCkgPyBkYWVtb25Db25uZWN0aW9uLmdldFVzZXJuYW1lKCkgOiBcIlwiO1xuICAgIGxldCBkYWVtb25QYXNzd29yZCA9IGRhZW1vbkNvbm5lY3Rpb24gJiYgZGFlbW9uQ29ubmVjdGlvbi5nZXRQYXNzd29yZCgpID8gZGFlbW9uQ29ubmVjdGlvbi5nZXRQYXNzd29yZCgpIDogXCJcIjtcbiAgICBsZXQgcmVqZWN0VW5hdXRob3JpemVkID0gZGFlbW9uQ29ubmVjdGlvbiA/IGRhZW1vbkNvbm5lY3Rpb24uZ2V0UmVqZWN0VW5hdXRob3JpemVkKCkgOiB0cnVlO1xuICAgIFxuICAgIC8vIGxvYWQgd2FzbSBtb2R1bGVcbiAgICBsZXQgbW9kdWxlID0gYXdhaXQgTGlicmFyeVV0aWxzLmxvYWRXYXNtTW9kdWxlKCk7XG4gICAgXG4gICAgLy8gb3BlbiB3YWxsZXQgaW4gcXVldWVcbiAgICByZXR1cm4gbW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBcbiAgICAgICAgLy8gcmVnaXN0ZXIgZm4gaW5mb3JtaW5nIGlmIHVuYXV0aG9yaXplZCByZXFzIHNob3VsZCBiZSByZWplY3RlZFxuICAgICAgICBsZXQgcmVqZWN0VW5hdXRob3JpemVkRm5JZCA9IEdlblV0aWxzLmdldFVVSUQoKTtcbiAgICAgICAgTGlicmFyeVV0aWxzLnNldFJlamVjdFVuYXV0aG9yaXplZEZuKHJlamVjdFVuYXV0aG9yaXplZEZuSWQsICgpID0+IHJlamVjdFVuYXV0aG9yaXplZCk7XG4gICAgICBcbiAgICAgICAgLy8gY3JlYXRlIHdhbGxldCBpbiB3YXNtIHdoaWNoIGludm9rZXMgY2FsbGJhY2sgd2hlbiBkb25lXG4gICAgICAgIG1vZHVsZS5vcGVuX3dhbGxldF9mdWxsKGNvbmZpZy5wYXNzd29yZCwgY29uZmlnLm5ldHdvcmtUeXBlLCBjb25maWcua2V5c0RhdGEgPz8gXCJcIiwgY29uZmlnLmNhY2hlRGF0YSA/PyBcIlwiLCBkYWVtb25VcmksIGRhZW1vblVzZXJuYW1lLCBkYWVtb25QYXNzd29yZCwgcmVqZWN0VW5hdXRob3JpemVkRm5JZCwgKGNwcEFkZHJlc3MpID0+IHtcbiAgICAgICAgICBpZiAodHlwZW9mIGNwcEFkZHJlc3MgPT09IFwic3RyaW5nXCIpIHJlamVjdChuZXcgTW9uZXJvRXJyb3IoY3BwQWRkcmVzcykpO1xuICAgICAgICAgIGVsc2UgcmVzb2x2ZShuZXcgTW9uZXJvV2FsbGV0RnVsbChjcHBBZGRyZXNzLCBjb25maWcucGF0aCwgY29uZmlnLnBhc3N3b3JkLCBjb25maWcuZnMsIHJlamVjdFVuYXV0aG9yaXplZCwgcmVqZWN0VW5hdXRob3JpemVkRm5JZCkpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldFdhbGxldFByb3h5KCk6IE1vbmVyb1dhbGxldEZ1bGxQcm94eSB7XG4gICAgcmV0dXJuIHN1cGVyLmdldFdhbGxldFByb3h5KCkgYXMgTW9uZXJvV2FsbGV0RnVsbFByb3h5O1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgYXN5bmMgYmFja2dyb3VuZFN5bmMoKSB7XG4gICAgbGV0IGxhYmVsID0gdGhpcy5wYXRoID8gdGhpcy5wYXRoIDogKHRoaXMuYnJvd3Nlck1haW5QYXRoID8gdGhpcy5icm93c2VyTWFpblBhdGggOiBcImluLW1lbW9yeSB3YWxsZXRcIik7IC8vIGxhYmVsIGZvciBsb2dcbiAgICBMaWJyYXJ5VXRpbHMubG9nKDEsIFwiQmFja2dyb3VuZCBzeW5jaHJvbml6aW5nIFwiICsgbGFiZWwpO1xuICAgIHRyeSB7IGF3YWl0IHRoaXMuc3luYygpOyB9XG4gICAgY2F0Y2ggKGVycjogYW55KSB7IGlmICghdGhpcy5faXNDbG9zZWQpIGNvbnNvbGUuZXJyb3IoXCJGYWlsZWQgdG8gYmFja2dyb3VuZCBzeW5jaHJvbml6ZSBcIiArIGxhYmVsICsgXCI6IFwiICsgZXJyLm1lc3NhZ2UpOyB9XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBhc3luYyByZWZyZXNoTGlzdGVuaW5nKCkge1xuICAgIGxldCBpc0VuYWJsZWQgPSB0aGlzLmxpc3RlbmVycy5sZW5ndGggPiAwO1xuICAgIGlmICh0aGlzLndhc21MaXN0ZW5lckhhbmRsZSA9PT0gMCAmJiAhaXNFbmFibGVkIHx8IHRoaXMud2FzbUxpc3RlbmVySGFuZGxlID4gMCAmJiBpc0VuYWJsZWQpIHJldHVybjsgLy8gbm8gZGlmZmVyZW5jZVxuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgdGhpcy5tb2R1bGUuc2V0X2xpc3RlbmVyKFxuICAgICAgICAgIHRoaXMuY3BwQWRkcmVzcyxcbiAgICAgICAgICB0aGlzLndhc21MaXN0ZW5lckhhbmRsZSxcbiAgICAgICAgICAgIG5ld0xpc3RlbmVySGFuZGxlID0+IHtcbiAgICAgICAgICAgICAgaWYgKHR5cGVvZiBuZXdMaXN0ZW5lckhhbmRsZSA9PT0gXCJzdHJpbmdcIikgcmVqZWN0KG5ldyBNb25lcm9FcnJvcihuZXdMaXN0ZW5lckhhbmRsZSkpO1xuICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLndhc21MaXN0ZW5lckhhbmRsZSA9IG5ld0xpc3RlbmVySGFuZGxlO1xuICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGlzRW5hYmxlZCA/IGFzeW5jIChoZWlnaHQsIHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQsIHBlcmNlbnREb25lLCBtZXNzYWdlKSA9PiBhd2FpdCB0aGlzLndhc21MaXN0ZW5lci5vblN5bmNQcm9ncmVzcyhoZWlnaHQsIHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQsIHBlcmNlbnREb25lLCBtZXNzYWdlKSA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGlzRW5hYmxlZCA/IGFzeW5jIChoZWlnaHQpID0+IGF3YWl0IHRoaXMud2FzbUxpc3RlbmVyLm9uTmV3QmxvY2soaGVpZ2h0KSA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGlzRW5hYmxlZCA/IGFzeW5jIChuZXdCYWxhbmNlU3RyLCBuZXdVbmxvY2tlZEJhbGFuY2VTdHIpID0+IGF3YWl0IHRoaXMud2FzbUxpc3RlbmVyLm9uQmFsYW5jZXNDaGFuZ2VkKG5ld0JhbGFuY2VTdHIsIG5ld1VubG9ja2VkQmFsYW5jZVN0cikgOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBpc0VuYWJsZWQgPyBhc3luYyAoaGVpZ2h0LCB0eEhhc2gsIGFtb3VudFN0ciwgYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCwgdmVyc2lvbiwgdW5sb2NrVGltZSwgaXNMb2NrZWQpID0+IGF3YWl0IHRoaXMud2FzbUxpc3RlbmVyLm9uT3V0cHV0UmVjZWl2ZWQoaGVpZ2h0LCB0eEhhc2gsIGFtb3VudFN0ciwgYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCwgdmVyc2lvbiwgdW5sb2NrVGltZSwgaXNMb2NrZWQpIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgaXNFbmFibGVkID8gYXN5bmMgKGhlaWdodCwgdHhIYXNoLCBhbW91bnRTdHIsIGFjY291bnRJZHhTdHIsIHN1YmFkZHJlc3NJZHhTdHIsIHZlcnNpb24sIHVubG9ja1RpbWUsIGlzTG9ja2VkKSA9PiBhd2FpdCB0aGlzLndhc21MaXN0ZW5lci5vbk91dHB1dFNwZW50KGhlaWdodCwgdHhIYXNoLCBhbW91bnRTdHIsIGFjY291bnRJZHhTdHIsIHN1YmFkZHJlc3NJZHhTdHIsIHZlcnNpb24sIHVubG9ja1RpbWUsIGlzTG9ja2VkKSA6IHVuZGVmaW5lZCxcbiAgICAgICAgKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICBzdGF0aWMgc2FuaXRpemVCbG9jayhibG9jaykge1xuICAgIGZvciAobGV0IHR4IG9mIGJsb2NrLmdldFR4cygpKSBNb25lcm9XYWxsZXRGdWxsLnNhbml0aXplVHhXYWxsZXQodHgpO1xuICAgIHJldHVybiBibG9jaztcbiAgfVxuICBcbiAgc3RhdGljIHNhbml0aXplVHhXYWxsZXQodHgpIHtcbiAgICBhc3NlcnQodHggaW5zdGFuY2VvZiBNb25lcm9UeFdhbGxldCk7XG4gICAgcmV0dXJuIHR4O1xuICB9XG4gIFxuICBzdGF0aWMgc2FuaXRpemVBY2NvdW50KGFjY291bnQpIHtcbiAgICBpZiAoYWNjb3VudC5nZXRTdWJhZGRyZXNzZXMoKSkge1xuICAgICAgZm9yIChsZXQgc3ViYWRkcmVzcyBvZiBhY2NvdW50LmdldFN1YmFkZHJlc3NlcygpKSBNb25lcm9XYWxsZXRLZXlzLnNhbml0aXplU3ViYWRkcmVzcyhzdWJhZGRyZXNzKTtcbiAgICB9XG4gICAgcmV0dXJuIGFjY291bnQ7XG4gIH1cbiAgXG4gIHN0YXRpYyBkZXNlcmlhbGl6ZUJsb2NrcyhibG9ja3NKc29uU3RyKSB7XG4gICAgbGV0IGJsb2Nrc0pzb24gPSBKU09OLnBhcnNlKEdlblV0aWxzLnN0cmluZ2lmeUJpZ0ludHMoYmxvY2tzSnNvblN0cikpO1xuICAgIGxldCBkZXNlcmlhbGl6ZWRCbG9ja3M6IGFueSA9IHt9O1xuICAgIGRlc2VyaWFsaXplZEJsb2Nrcy5ibG9ja3MgPSBbXTtcbiAgICBpZiAoYmxvY2tzSnNvbi5ibG9ja3MpIGZvciAobGV0IGJsb2NrSnNvbiBvZiBibG9ja3NKc29uLmJsb2NrcykgZGVzZXJpYWxpemVkQmxvY2tzLmJsb2Nrcy5wdXNoKE1vbmVyb1dhbGxldEZ1bGwuc2FuaXRpemVCbG9jayhuZXcgTW9uZXJvQmxvY2soYmxvY2tKc29uLCBNb25lcm9CbG9jay5EZXNlcmlhbGl6YXRpb25UeXBlLlRYX1dBTExFVCkpKTtcbiAgICByZXR1cm4gZGVzZXJpYWxpemVkQmxvY2tzO1xuICB9XG4gIFxuICBzdGF0aWMgZGVzZXJpYWxpemVUeHMocXVlcnksIGJsb2Nrc0pzb25TdHIpIHtcbiAgICBcbiAgICAvLyBkZXNlcmlhbGl6ZSBibG9ja3NcbiAgICBsZXQgZGVzZXJpYWxpemVkQmxvY2tzID0gTW9uZXJvV2FsbGV0RnVsbC5kZXNlcmlhbGl6ZUJsb2NrcyhibG9ja3NKc29uU3RyKTtcbiAgICBsZXQgYmxvY2tzID0gZGVzZXJpYWxpemVkQmxvY2tzLmJsb2NrcztcbiAgICBcbiAgICAvLyBjb2xsZWN0IHR4c1xuICAgIGxldCB0eHMgPSBbXTtcbiAgICBmb3IgKGxldCBibG9jayBvZiBibG9ja3MpIHtcbiAgICAgIE1vbmVyb1dhbGxldEZ1bGwuc2FuaXRpemVCbG9jayhibG9jayk7XG4gICAgICBmb3IgKGxldCB0eCBvZiBibG9jay5nZXRUeHMoKSkge1xuICAgICAgICBpZiAoYmxvY2suZ2V0SGVpZ2h0KCkgPT09IHVuZGVmaW5lZCkgdHguc2V0QmxvY2sodW5kZWZpbmVkKTsgLy8gZGVyZWZlcmVuY2UgcGxhY2Vob2xkZXIgYmxvY2sgZm9yIHVuY29uZmlybWVkIHR4c1xuICAgICAgICB0eHMucHVzaCh0eCk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIHJlLXNvcnQgdHhzIHdoaWNoIGlzIGxvc3Qgb3ZlciB3YXNtIHNlcmlhbGl6YXRpb24gIC8vIFRPRE86IGNvbmZpcm0gdGhhdCBvcmRlciBpcyBsb3N0XG4gICAgaWYgKHF1ZXJ5LmdldEhhc2hlcygpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGxldCB0eE1hcCA9IG5ldyBNYXAoKTtcbiAgICAgIGZvciAobGV0IHR4IG9mIHR4cykgdHhNYXBbdHguZ2V0SGFzaCgpXSA9IHR4O1xuICAgICAgbGV0IHR4c1NvcnRlZCA9IFtdO1xuICAgICAgZm9yIChsZXQgdHhIYXNoIG9mIHF1ZXJ5LmdldEhhc2hlcygpKSBpZiAodHhNYXBbdHhIYXNoXSAhPT0gdW5kZWZpbmVkKSB0eHNTb3J0ZWQucHVzaCh0eE1hcFt0eEhhc2hdKTtcbiAgICAgIHR4cyA9IHR4c1NvcnRlZDtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHR4cztcbiAgfVxuICBcbiAgc3RhdGljIGRlc2VyaWFsaXplVHJhbnNmZXJzKHF1ZXJ5LCBibG9ja3NKc29uU3RyKSB7XG4gICAgXG4gICAgLy8gZGVzZXJpYWxpemUgYmxvY2tzXG4gICAgbGV0IGRlc2VyaWFsaXplZEJsb2NrcyA9IE1vbmVyb1dhbGxldEZ1bGwuZGVzZXJpYWxpemVCbG9ja3MoYmxvY2tzSnNvblN0cik7XG4gICAgbGV0IGJsb2NrcyA9IGRlc2VyaWFsaXplZEJsb2Nrcy5ibG9ja3M7XG4gICAgXG4gICAgLy8gY29sbGVjdCB0cmFuc2ZlcnNcbiAgICBsZXQgdHJhbnNmZXJzID0gW107XG4gICAgZm9yIChsZXQgYmxvY2sgb2YgYmxvY2tzKSB7XG4gICAgICBmb3IgKGxldCB0eCBvZiBibG9jay5nZXRUeHMoKSkge1xuICAgICAgICBpZiAoYmxvY2suZ2V0SGVpZ2h0KCkgPT09IHVuZGVmaW5lZCkgdHguc2V0QmxvY2sodW5kZWZpbmVkKTsgLy8gZGVyZWZlcmVuY2UgcGxhY2Vob2xkZXIgYmxvY2sgZm9yIHVuY29uZmlybWVkIHR4c1xuICAgICAgICBpZiAodHguZ2V0T3V0Z29pbmdUcmFuc2ZlcigpICE9PSB1bmRlZmluZWQpIHRyYW5zZmVycy5wdXNoKHR4LmdldE91dGdvaW5nVHJhbnNmZXIoKSk7XG4gICAgICAgIGlmICh0eC5nZXRJbmNvbWluZ1RyYW5zZmVycygpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBmb3IgKGxldCB0cmFuc2ZlciBvZiB0eC5nZXRJbmNvbWluZ1RyYW5zZmVycygpKSB0cmFuc2ZlcnMucHVzaCh0cmFuc2Zlcik7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHRyYW5zZmVycztcbiAgfVxuICBcbiAgc3RhdGljIGRlc2VyaWFsaXplT3V0cHV0cyhxdWVyeSwgYmxvY2tzSnNvblN0cikge1xuICAgIFxuICAgIC8vIGRlc2VyaWFsaXplIGJsb2Nrc1xuICAgIGxldCBkZXNlcmlhbGl6ZWRCbG9ja3MgPSBNb25lcm9XYWxsZXRGdWxsLmRlc2VyaWFsaXplQmxvY2tzKGJsb2Nrc0pzb25TdHIpO1xuICAgIGxldCBibG9ja3MgPSBkZXNlcmlhbGl6ZWRCbG9ja3MuYmxvY2tzO1xuICAgIFxuICAgIC8vIGNvbGxlY3Qgb3V0cHV0c1xuICAgIGxldCBvdXRwdXRzID0gW107XG4gICAgZm9yIChsZXQgYmxvY2sgb2YgYmxvY2tzKSB7XG4gICAgICBmb3IgKGxldCB0eCBvZiBibG9jay5nZXRUeHMoKSkge1xuICAgICAgICBmb3IgKGxldCBvdXRwdXQgb2YgdHguZ2V0T3V0cHV0cygpKSBvdXRwdXRzLnB1c2gob3V0cHV0KTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIG91dHB1dHM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZXQgdGhlIHBhdGggb2YgdGhlIHdhbGxldCBvbiB0aGUgYnJvd3NlciBtYWluIHRocmVhZCBpZiBydW4gYXMgYSB3b3JrZXIuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYnJvd3Nlck1haW5QYXRoIC0gcGF0aCBvZiB0aGUgd2FsbGV0IG9uIHRoZSBicm93c2VyIG1haW4gdGhyZWFkXG4gICAqL1xuICBwcm90ZWN0ZWQgc2V0QnJvd3Nlck1haW5QYXRoKGJyb3dzZXJNYWluUGF0aCkge1xuICAgIHRoaXMuYnJvd3Nlck1haW5QYXRoID0gYnJvd3Nlck1haW5QYXRoO1xuICB9XG4gIFxuICBzdGF0aWMgYXN5bmMgbW92ZVRvKHBhdGgsIHdhbGxldCkge1xuXG4gICAgLy8gc2F2ZSBhbmQgcmV0dXJuIGlmIHNhbWUgcGF0aFxuICAgIGlmIChQYXRoLm5vcm1hbGl6ZSh3YWxsZXQucGF0aCkgPT09IFBhdGgubm9ybWFsaXplKHBhdGgpKSB7XG4gICAgICByZXR1cm4gd2FsbGV0LnNhdmUoKTtcbiAgICB9XG5cbiAgICByZXR1cm4gTGlicmFyeVV0aWxzLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICBpZiAoYXdhaXQgd2FsbGV0LmlzQ2xvc2VkKCkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIldhbGxldCBpcyBjbG9zZWRcIik7XG4gICAgICBpZiAoIXBhdGgpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk11c3QgcHJvdmlkZSBwYXRoIG9mIGRlc3RpbmF0aW9uIHdhbGxldFwiKTtcblxuICAgICAgLy8gY3JlYXRlIGRlc3RpbmF0aW9uIGRpcmVjdG9yeSBpZiBpdCBkb2Vzbid0IGV4aXN0XG4gICAgICBsZXQgd2FsbGV0RGlyID0gUGF0aC5kaXJuYW1lKHBhdGgpO1xuICAgICAgaWYgKCFhd2FpdCBMaWJyYXJ5VXRpbHMuZXhpc3RzKHdhbGxldC5mcywgd2FsbGV0RGlyKSkge1xuICAgICAgICB0cnkgeyBhd2FpdCB3YWxsZXQuZnMubWtkaXIod2FsbGV0RGlyKTsgfVxuICAgICAgICBjYXRjaCAoZXJyOiBhbnkpIHsgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiRGVzdGluYXRpb24gcGF0aCBcIiArIHBhdGggKyBcIiBkb2VzIG5vdCBleGlzdCBhbmQgY2Fubm90IGJlIGNyZWF0ZWQ6IFwiICsgZXJyLm1lc3NhZ2UpOyB9XG4gICAgICB9XG5cbiAgICAgIC8vIGdldCB3YWxsZXQgZGF0YVxuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IHdhbGxldC5nZXREYXRhKCk7XG5cbiAgICAgIC8vIHdyaXRlIHdhbGxldCBmaWxlc1xuICAgICAgYXdhaXQgd2FsbGV0LmZzLndyaXRlRmlsZShwYXRoICsgXCIua2V5c1wiLCBkYXRhWzBdLCBcImJpbmFyeVwiKTtcbiAgICAgIGF3YWl0IHdhbGxldC5mcy53cml0ZUZpbGUocGF0aCwgZGF0YVsxXSwgXCJiaW5hcnlcIik7XG4gICAgICBhd2FpdCB3YWxsZXQuZnMud3JpdGVGaWxlKHBhdGggKyBcIi5hZGRyZXNzLnR4dFwiLCBhd2FpdCB3YWxsZXQuZ2V0UHJpbWFyeUFkZHJlc3MoKSk7XG4gICAgICBsZXQgb2xkUGF0aCA9IHdhbGxldC5wYXRoO1xuICAgICAgd2FsbGV0LnBhdGggPSBwYXRoO1xuXG4gICAgICAvLyBkZWxldGUgb2xkIHdhbGxldCBmaWxlc1xuICAgICAgaWYgKG9sZFBhdGgpIHtcbiAgICAgICAgYXdhaXQgd2FsbGV0LmZzLnVubGluayhvbGRQYXRoICsgXCIuYWRkcmVzcy50eHRcIik7XG4gICAgICAgIGF3YWl0IHdhbGxldC5mcy51bmxpbmsob2xkUGF0aCArIFwiLmtleXNcIik7XG4gICAgICAgIGF3YWl0IHdhbGxldC5mcy51bmxpbmsob2xkUGF0aCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cbiAgXG4gIHN0YXRpYyBhc3luYyBzYXZlKHdhbGxldDogYW55KSB7XG4gICAgcmV0dXJuIExpYnJhcnlVdGlscy5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgaWYgKGF3YWl0IHdhbGxldC5pc0Nsb3NlZCgpKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJXYWxsZXQgaXMgY2xvc2VkXCIpO1xuXG4gICAgICAvLyBwYXRoIG11c3QgYmUgc2V0XG4gICAgICBsZXQgcGF0aCA9IGF3YWl0IHdhbGxldC5nZXRQYXRoKCk7XG4gICAgICBpZiAoIXBhdGgpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBzYXZlIHdhbGxldCBiZWNhdXNlIHBhdGggaXMgbm90IHNldFwiKTtcblxuICAgICAgLy8gZ2V0IHdhbGxldCBkYXRhXG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgd2FsbGV0LmdldERhdGEoKTtcblxuICAgICAgLy8gd3JpdGUgd2FsbGV0IGZpbGVzIHRvICoubmV3XG4gICAgICBsZXQgcGF0aE5ldyA9IHBhdGggKyBcIi5uZXdcIjtcbiAgICAgIGF3YWl0IHdhbGxldC5mcy53cml0ZUZpbGUocGF0aE5ldyArIFwiLmtleXNcIiwgZGF0YVswXSwgXCJiaW5hcnlcIik7XG4gICAgICBhd2FpdCB3YWxsZXQuZnMud3JpdGVGaWxlKHBhdGhOZXcsIGRhdGFbMV0sIFwiYmluYXJ5XCIpO1xuICAgICAgYXdhaXQgd2FsbGV0LmZzLndyaXRlRmlsZShwYXRoTmV3ICsgXCIuYWRkcmVzcy50eHRcIiwgYXdhaXQgd2FsbGV0LmdldFByaW1hcnlBZGRyZXNzKCkpO1xuXG4gICAgICAvLyByZXBsYWNlIG9sZCB3YWxsZXQgZmlsZXMgd2l0aCBuZXdcbiAgICAgIGF3YWl0IHdhbGxldC5mcy5yZW5hbWUocGF0aE5ldyArIFwiLmtleXNcIiwgcGF0aCArIFwiLmtleXNcIik7XG4gICAgICBhd2FpdCB3YWxsZXQuZnMucmVuYW1lKHBhdGhOZXcsIHBhdGgpO1xuICAgICAgYXdhaXQgd2FsbGV0LmZzLnJlbmFtZShwYXRoTmV3ICsgXCIuYWRkcmVzcy50eHRcIiwgcGF0aCArIFwiLmFkZHJlc3MudHh0XCIpO1xuICAgIH0pO1xuICB9XG59XG5cbi8qKlxuICogSW1wbGVtZW50cyBhIE1vbmVyb1dhbGxldCBieSBwcm94eWluZyByZXF1ZXN0cyB0byBhIHdvcmtlciB3aGljaCBydW5zIGEgZnVsbCB3YWxsZXQuXG4gKiBcbiAqIEBwcml2YXRlXG4gKi9cbmNsYXNzIE1vbmVyb1dhbGxldEZ1bGxQcm94eSBleHRlbmRzIE1vbmVyb1dhbGxldEtleXNQcm94eSB7XG5cbiAgLy8gaW5zdGFuY2UgdmFyaWFibGVzXG4gIHByb3RlY3RlZCBwYXRoOiBhbnk7XG4gIHByb3RlY3RlZCBmczogYW55O1xuICBwcm90ZWN0ZWQgd3JhcHBlZExpc3RlbmVyczogYW55O1xuICBcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gV0FMTEVUIFNUQVRJQyBVVElMUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgXG4gIHN0YXRpYyBhc3luYyBvcGVuV2FsbGV0RGF0YShjb25maWc6IFBhcnRpYWw8TW9uZXJvV2FsbGV0Q29uZmlnPikge1xuICAgIGxldCB3YWxsZXRJZCA9IEdlblV0aWxzLmdldFVVSUQoKTtcbiAgICBpZiAoY29uZmlnLnBhc3N3b3JkID09PSB1bmRlZmluZWQpIGNvbmZpZy5wYXNzd29yZCA9IFwiXCI7XG4gICAgbGV0IGRhZW1vbkNvbm5lY3Rpb24gPSBjb25maWcuZ2V0U2VydmVyKCk7XG4gICAgYXdhaXQgTGlicmFyeVV0aWxzLmludm9rZVdvcmtlcih3YWxsZXRJZCwgXCJvcGVuV2FsbGV0RGF0YVwiLCBbY29uZmlnLnBhdGgsIGNvbmZpZy5wYXNzd29yZCwgY29uZmlnLm5ldHdvcmtUeXBlLCBjb25maWcua2V5c0RhdGEsIGNvbmZpZy5jYWNoZURhdGEsIGRhZW1vbkNvbm5lY3Rpb24gPyBkYWVtb25Db25uZWN0aW9uLnRvSnNvbigpIDogdW5kZWZpbmVkXSk7XG4gICAgbGV0IHdhbGxldCA9IG5ldyBNb25lcm9XYWxsZXRGdWxsUHJveHkod2FsbGV0SWQsIGF3YWl0IExpYnJhcnlVdGlscy5nZXRXb3JrZXIoKSwgY29uZmlnLnBhdGgsIGNvbmZpZy5nZXRGcygpKTtcbiAgICBpZiAoY29uZmlnLnBhdGgpIGF3YWl0IHdhbGxldC5zYXZlKCk7XG4gICAgcmV0dXJuIHdhbGxldDtcbiAgfVxuICBcbiAgc3RhdGljIGFzeW5jIGNyZWF0ZVdhbGxldChjb25maWcpIHtcbiAgICBpZiAoY29uZmlnLmdldFBhdGgoKSAmJiBhd2FpdCBNb25lcm9XYWxsZXRGdWxsLndhbGxldEV4aXN0cyhjb25maWcuZ2V0UGF0aCgpLCBjb25maWcuZ2V0RnMoKSkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIldhbGxldCBhbHJlYWR5IGV4aXN0czogXCIgKyBjb25maWcuZ2V0UGF0aCgpKTtcbiAgICBsZXQgd2FsbGV0SWQgPSBHZW5VdGlscy5nZXRVVUlEKCk7XG4gICAgYXdhaXQgTGlicmFyeVV0aWxzLmludm9rZVdvcmtlcih3YWxsZXRJZCwgXCJjcmVhdGVXYWxsZXRGdWxsXCIsIFtjb25maWcudG9Kc29uKCldKTtcbiAgICBsZXQgd2FsbGV0ID0gbmV3IE1vbmVyb1dhbGxldEZ1bGxQcm94eSh3YWxsZXRJZCwgYXdhaXQgTGlicmFyeVV0aWxzLmdldFdvcmtlcigpLCBjb25maWcuZ2V0UGF0aCgpLCBjb25maWcuZ2V0RnMoKSk7XG4gICAgaWYgKGNvbmZpZy5nZXRQYXRoKCkpIGF3YWl0IHdhbGxldC5zYXZlKCk7XG4gICAgcmV0dXJuIHdhbGxldDtcbiAgfVxuICBcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIElOU1RBTkNFIE1FVEhPRFMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICBcbiAgLyoqXG4gICAqIEludGVybmFsIGNvbnN0cnVjdG9yIHdoaWNoIGlzIGdpdmVuIGEgd29ya2VyIHRvIGNvbW11bmljYXRlIHdpdGggdmlhIG1lc3NhZ2VzLlxuICAgKiBcbiAgICogVGhpcyBtZXRob2Qgc2hvdWxkIG5vdCBiZSBjYWxsZWQgZXh0ZXJuYWxseSBidXQgc2hvdWxkIGJlIGNhbGxlZCB0aHJvdWdoXG4gICAqIHN0YXRpYyB3YWxsZXQgY3JlYXRpb24gdXRpbGl0aWVzIGluIHRoaXMgY2xhc3MuXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gd2FsbGV0SWQgLSBpZGVudGlmaWVzIHRoZSB3YWxsZXQgd2l0aCB0aGUgd29ya2VyXG4gICAqIEBwYXJhbSB7V29ya2VyfSB3b3JrZXIgLSB3b3JrZXIgdG8gY29tbXVuaWNhdGUgd2l0aCB2aWEgbWVzc2FnZXNcbiAgICovXG4gIGNvbnN0cnVjdG9yKHdhbGxldElkLCB3b3JrZXIsIHBhdGgsIGZzKSB7XG4gICAgc3VwZXIod2FsbGV0SWQsIHdvcmtlcik7XG4gICAgdGhpcy5wYXRoID0gcGF0aDtcbiAgICB0aGlzLmZzID0gZnMgPyBmcyA6IChwYXRoID8gTW9uZXJvV2FsbGV0RnVsbC5nZXRGcygpIDogdW5kZWZpbmVkKTtcbiAgICB0aGlzLndyYXBwZWRMaXN0ZW5lcnMgPSBbXTtcbiAgfVxuXG4gIGdldFBhdGgoKSB7XG4gICAgcmV0dXJuIHRoaXMucGF0aDtcbiAgfVxuXG4gIGFzeW5jIGdldE5ldHdvcmtUeXBlKCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImdldE5ldHdvcmtUeXBlXCIpO1xuICB9XG4gIFxuICBhc3luYyBzZXRTdWJhZGRyZXNzTGFiZWwoYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCwgbGFiZWwpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJzZXRTdWJhZGRyZXNzTGFiZWxcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKSBhcyBQcm9taXNlPHZvaWQ+O1xuICB9XG4gIFxuICBhc3luYyBzZXREYWVtb25Db25uZWN0aW9uKHVyaU9yUnBjQ29ubmVjdGlvbikge1xuICAgIGlmICghdXJpT3JScGNDb25uZWN0aW9uKSBhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcInNldERhZW1vbkNvbm5lY3Rpb25cIik7XG4gICAgZWxzZSB7XG4gICAgICBsZXQgY29ubmVjdGlvbiA9ICF1cmlPclJwY0Nvbm5lY3Rpb24gPyB1bmRlZmluZWQgOiB1cmlPclJwY0Nvbm5lY3Rpb24gaW5zdGFuY2VvZiBNb25lcm9ScGNDb25uZWN0aW9uID8gdXJpT3JScGNDb25uZWN0aW9uIDogbmV3IE1vbmVyb1JwY0Nvbm5lY3Rpb24odXJpT3JScGNDb25uZWN0aW9uKTtcbiAgICAgIGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwic2V0RGFlbW9uQ29ubmVjdGlvblwiLCBjb25uZWN0aW9uID8gY29ubmVjdGlvbi5nZXRDb25maWcoKSA6IHVuZGVmaW5lZCk7XG4gICAgfVxuICB9XG4gIFxuICBhc3luYyBnZXREYWVtb25Db25uZWN0aW9uKCkge1xuICAgIGxldCBycGNDb25maWcgPSBhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImdldERhZW1vbkNvbm5lY3Rpb25cIik7XG4gICAgcmV0dXJuIHJwY0NvbmZpZyA/IG5ldyBNb25lcm9ScGNDb25uZWN0aW9uKHJwY0NvbmZpZykgOiB1bmRlZmluZWQ7XG4gIH1cbiAgXG4gIGFzeW5jIGlzQ29ubmVjdGVkVG9EYWVtb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiaXNDb25uZWN0ZWRUb0RhZW1vblwiKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UmVzdG9yZUhlaWdodCgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRSZXN0b3JlSGVpZ2h0XCIpO1xuICB9XG4gIFxuICBhc3luYyBzZXRSZXN0b3JlSGVpZ2h0KHJlc3RvcmVIZWlnaHQpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJzZXRSZXN0b3JlSGVpZ2h0XCIsIFtyZXN0b3JlSGVpZ2h0XSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldERhZW1vbkhlaWdodCgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXREYWVtb25IZWlnaHRcIik7XG4gIH1cbiAgXG4gIGFzeW5jIGdldERhZW1vbk1heFBlZXJIZWlnaHQoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZ2V0RGFlbW9uTWF4UGVlckhlaWdodFwiKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0SGVpZ2h0QnlEYXRlKHllYXIsIG1vbnRoLCBkYXkpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRIZWlnaHRCeURhdGVcIiwgW3llYXIsIG1vbnRoLCBkYXldKTtcbiAgfVxuICBcbiAgYXN5bmMgaXNEYWVtb25TeW5jZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiaXNEYWVtb25TeW5jZWRcIik7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEhlaWdodCgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRIZWlnaHRcIik7XG4gIH1cbiAgXG4gIGFzeW5jIGFkZExpc3RlbmVyKGxpc3RlbmVyKSB7XG4gICAgbGV0IHdyYXBwZWRMaXN0ZW5lciA9IG5ldyBXYWxsZXRXb3JrZXJMaXN0ZW5lcihsaXN0ZW5lcik7XG4gICAgbGV0IGxpc3RlbmVySWQgPSB3cmFwcGVkTGlzdGVuZXIuZ2V0SWQoKTtcbiAgICBMaWJyYXJ5VXRpbHMuYWRkV29ya2VyQ2FsbGJhY2sodGhpcy53YWxsZXRJZCwgXCJvblN5bmNQcm9ncmVzc19cIiArIGxpc3RlbmVySWQsIFt3cmFwcGVkTGlzdGVuZXIub25TeW5jUHJvZ3Jlc3MsIHdyYXBwZWRMaXN0ZW5lcl0pO1xuICAgIExpYnJhcnlVdGlscy5hZGRXb3JrZXJDYWxsYmFjayh0aGlzLndhbGxldElkLCBcIm9uTmV3QmxvY2tfXCIgKyBsaXN0ZW5lcklkLCBbd3JhcHBlZExpc3RlbmVyLm9uTmV3QmxvY2ssIHdyYXBwZWRMaXN0ZW5lcl0pO1xuICAgIExpYnJhcnlVdGlscy5hZGRXb3JrZXJDYWxsYmFjayh0aGlzLndhbGxldElkLCBcIm9uQmFsYW5jZXNDaGFuZ2VkX1wiICsgbGlzdGVuZXJJZCwgW3dyYXBwZWRMaXN0ZW5lci5vbkJhbGFuY2VzQ2hhbmdlZCwgd3JhcHBlZExpc3RlbmVyXSk7XG4gICAgTGlicmFyeVV0aWxzLmFkZFdvcmtlckNhbGxiYWNrKHRoaXMud2FsbGV0SWQsIFwib25PdXRwdXRSZWNlaXZlZF9cIiArIGxpc3RlbmVySWQsIFt3cmFwcGVkTGlzdGVuZXIub25PdXRwdXRSZWNlaXZlZCwgd3JhcHBlZExpc3RlbmVyXSk7XG4gICAgTGlicmFyeVV0aWxzLmFkZFdvcmtlckNhbGxiYWNrKHRoaXMud2FsbGV0SWQsIFwib25PdXRwdXRTcGVudF9cIiArIGxpc3RlbmVySWQsIFt3cmFwcGVkTGlzdGVuZXIub25PdXRwdXRTcGVudCwgd3JhcHBlZExpc3RlbmVyXSk7XG4gICAgdGhpcy53cmFwcGVkTGlzdGVuZXJzLnB1c2god3JhcHBlZExpc3RlbmVyKTtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJhZGRMaXN0ZW5lclwiLCBbbGlzdGVuZXJJZF0pO1xuICB9XG4gIFxuICBhc3luYyByZW1vdmVMaXN0ZW5lcihsaXN0ZW5lcikge1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy53cmFwcGVkTGlzdGVuZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAodGhpcy53cmFwcGVkTGlzdGVuZXJzW2ldLmdldExpc3RlbmVyKCkgPT09IGxpc3RlbmVyKSB7XG4gICAgICAgIGxldCBsaXN0ZW5lcklkID0gdGhpcy53cmFwcGVkTGlzdGVuZXJzW2ldLmdldElkKCk7XG4gICAgICAgIGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwicmVtb3ZlTGlzdGVuZXJcIiwgW2xpc3RlbmVySWRdKTtcbiAgICAgICAgTGlicmFyeVV0aWxzLnJlbW92ZVdvcmtlckNhbGxiYWNrKHRoaXMud2FsbGV0SWQsIFwib25TeW5jUHJvZ3Jlc3NfXCIgKyBsaXN0ZW5lcklkKTtcbiAgICAgICAgTGlicmFyeVV0aWxzLnJlbW92ZVdvcmtlckNhbGxiYWNrKHRoaXMud2FsbGV0SWQsIFwib25OZXdCbG9ja19cIiArIGxpc3RlbmVySWQpO1xuICAgICAgICBMaWJyYXJ5VXRpbHMucmVtb3ZlV29ya2VyQ2FsbGJhY2sodGhpcy53YWxsZXRJZCwgXCJvbkJhbGFuY2VzQ2hhbmdlZF9cIiArIGxpc3RlbmVySWQpO1xuICAgICAgICBMaWJyYXJ5VXRpbHMucmVtb3ZlV29ya2VyQ2FsbGJhY2sodGhpcy53YWxsZXRJZCwgXCJvbk91dHB1dFJlY2VpdmVkX1wiICsgbGlzdGVuZXJJZCk7XG4gICAgICAgIExpYnJhcnlVdGlscy5yZW1vdmVXb3JrZXJDYWxsYmFjayh0aGlzLndhbGxldElkLCBcIm9uT3V0cHV0U3BlbnRfXCIgKyBsaXN0ZW5lcklkKTtcbiAgICAgICAgdGhpcy53cmFwcGVkTGlzdGVuZXJzLnNwbGljZShpLCAxKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJMaXN0ZW5lciBpcyBub3QgcmVnaXN0ZXJlZCB3aXRoIHdhbGxldFwiKTtcbiAgfVxuICBcbiAgZ2V0TGlzdGVuZXJzKCkge1xuICAgIGxldCBsaXN0ZW5lcnMgPSBbXTtcbiAgICBmb3IgKGxldCB3cmFwcGVkTGlzdGVuZXIgb2YgdGhpcy53cmFwcGVkTGlzdGVuZXJzKSBsaXN0ZW5lcnMucHVzaCh3cmFwcGVkTGlzdGVuZXIuZ2V0TGlzdGVuZXIoKSk7XG4gICAgcmV0dXJuIGxpc3RlbmVycztcbiAgfVxuICBcbiAgYXN5bmMgaXNTeW5jZWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiaXNTeW5jZWRcIik7XG4gIH1cbiAgXG4gIGFzeW5jIHN5bmMobGlzdGVuZXJPclN0YXJ0SGVpZ2h0PzogTW9uZXJvV2FsbGV0TGlzdGVuZXIgfCBudW1iZXIsIHN0YXJ0SGVpZ2h0PzogbnVtYmVyLCBhbGxvd0NvbmN1cnJlbnRDYWxscyA9IGZhbHNlKTogUHJvbWlzZTxNb25lcm9TeW5jUmVzdWx0PiB7XG4gICAgXG4gICAgLy8gbm9ybWFsaXplIHBhcmFtc1xuICAgIHN0YXJ0SGVpZ2h0ID0gbGlzdGVuZXJPclN0YXJ0SGVpZ2h0IGluc3RhbmNlb2YgTW9uZXJvV2FsbGV0TGlzdGVuZXIgPyBzdGFydEhlaWdodCA6IGxpc3RlbmVyT3JTdGFydEhlaWdodDtcbiAgICBsZXQgbGlzdGVuZXIgPSBsaXN0ZW5lck9yU3RhcnRIZWlnaHQgaW5zdGFuY2VvZiBNb25lcm9XYWxsZXRMaXN0ZW5lciA/IGxpc3RlbmVyT3JTdGFydEhlaWdodCA6IHVuZGVmaW5lZDtcbiAgICBpZiAoc3RhcnRIZWlnaHQgPT09IHVuZGVmaW5lZCkgc3RhcnRIZWlnaHQgPSBNYXRoLm1heChhd2FpdCB0aGlzLmdldEhlaWdodCgpLCBhd2FpdCB0aGlzLmdldFJlc3RvcmVIZWlnaHQoKSk7XG4gICAgXG4gICAgLy8gcmVnaXN0ZXIgbGlzdGVuZXIgaWYgZ2l2ZW5cbiAgICBpZiAobGlzdGVuZXIpIGF3YWl0IHRoaXMuYWRkTGlzdGVuZXIobGlzdGVuZXIpO1xuICAgIFxuICAgIC8vIHN5bmMgd2FsbGV0IGluIHdvcmtlciBcbiAgICBsZXQgZXJyO1xuICAgIGxldCByZXN1bHQ7XG4gICAgdHJ5IHtcbiAgICAgIGxldCByZXN1bHRKc29uID0gYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJzeW5jXCIsIFtzdGFydEhlaWdodCwgYWxsb3dDb25jdXJyZW50Q2FsbHNdKTtcbiAgICAgIHJlc3VsdCA9IG5ldyBNb25lcm9TeW5jUmVzdWx0KHJlc3VsdEpzb24ubnVtQmxvY2tzRmV0Y2hlZCwgcmVzdWx0SnNvbi5yZWNlaXZlZE1vbmV5KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBlcnIgPSBlO1xuICAgIH1cbiAgICBcbiAgICAvLyB1bnJlZ2lzdGVyIGxpc3RlbmVyXG4gICAgaWYgKGxpc3RlbmVyKSBhd2FpdCB0aGlzLnJlbW92ZUxpc3RlbmVyKGxpc3RlbmVyKTtcbiAgICBcbiAgICAvLyB0aHJvdyBlcnJvciBvciByZXR1cm5cbiAgICBpZiAoZXJyKSB0aHJvdyBlcnI7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuICBcbiAgYXN5bmMgc3RhcnRTeW5jaW5nKHN5bmNQZXJpb2RJbk1zKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwic3RhcnRTeW5jaW5nXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgICBcbiAgYXN5bmMgc3RvcFN5bmNpbmcoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwic3RvcFN5bmNpbmdcIik7XG4gIH1cbiAgXG4gIGFzeW5jIHNjYW5UeHModHhIYXNoZXMpIHtcbiAgICBhc3NlcnQoQXJyYXkuaXNBcnJheSh0eEhhc2hlcyksIFwiTXVzdCBwcm92aWRlIGFuIGFycmF5IG9mIHR4cyBoYXNoZXMgdG8gc2NhblwiKTtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJzY2FuVHhzXCIsIFt0eEhhc2hlc10pO1xuICB9XG4gIFxuICBhc3luYyByZXNjYW5TcGVudCgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJyZXNjYW5TcGVudFwiKTtcbiAgfVxuICAgIFxuICBhc3luYyByZXNjYW5CbG9ja2NoYWluKCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcInJlc2NhbkJsb2NrY2hhaW5cIik7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEJhbGFuY2UoYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCkge1xuICAgIHJldHVybiBCaWdJbnQoYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRCYWxhbmNlXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSkpO1xuICB9XG4gIFxuICBhc3luYyBnZXRVbmxvY2tlZEJhbGFuY2UoYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCkge1xuICAgIGxldCB1bmxvY2tlZEJhbGFuY2VTdHIgPSBhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImdldFVubG9ja2VkQmFsYW5jZVwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICAgIHJldHVybiBCaWdJbnQodW5sb2NrZWRCYWxhbmNlU3RyKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QWNjb3VudHMoaW5jbHVkZVN1YmFkZHJlc3NlcywgdGFnKSB7XG4gICAgbGV0IGFjY291bnRzID0gW107XG4gICAgZm9yIChsZXQgYWNjb3VudEpzb24gb2YgKGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZ2V0QWNjb3VudHNcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKSkpIHtcbiAgICAgIGFjY291bnRzLnB1c2goTW9uZXJvV2FsbGV0RnVsbC5zYW5pdGl6ZUFjY291bnQobmV3IE1vbmVyb0FjY291bnQoYWNjb3VudEpzb24pKSk7XG4gICAgfVxuICAgIHJldHVybiBhY2NvdW50cztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QWNjb3VudChhY2NvdW50SWR4LCBpbmNsdWRlU3ViYWRkcmVzc2VzKSB7XG4gICAgbGV0IGFjY291bnRKc29uID0gYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRBY2NvdW50XCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gICAgcmV0dXJuIE1vbmVyb1dhbGxldEZ1bGwuc2FuaXRpemVBY2NvdW50KG5ldyBNb25lcm9BY2NvdW50KGFjY291bnRKc29uKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGNyZWF0ZUFjY291bnQobGFiZWwpIHtcbiAgICBsZXQgYWNjb3VudEpzb24gPSBhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImNyZWF0ZUFjY291bnRcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKTtcbiAgICByZXR1cm4gTW9uZXJvV2FsbGV0RnVsbC5zYW5pdGl6ZUFjY291bnQobmV3IE1vbmVyb0FjY291bnQoYWNjb3VudEpzb24pKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0U3ViYWRkcmVzc2VzKGFjY291bnRJZHgsIHN1YmFkZHJlc3NJbmRpY2VzKSB7XG4gICAgbGV0IHN1YmFkZHJlc3NlcyA9IFtdO1xuICAgIGZvciAobGV0IHN1YmFkZHJlc3NKc29uIG9mIChhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImdldFN1YmFkZHJlc3Nlc1wiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpKSkge1xuICAgICAgc3ViYWRkcmVzc2VzLnB1c2goTW9uZXJvV2FsbGV0S2V5cy5zYW5pdGl6ZVN1YmFkZHJlc3MobmV3IE1vbmVyb1N1YmFkZHJlc3Moc3ViYWRkcmVzc0pzb24pKSk7XG4gICAgfVxuICAgIHJldHVybiBzdWJhZGRyZXNzZXM7XG4gIH1cbiAgXG4gIGFzeW5jIGNyZWF0ZVN1YmFkZHJlc3MoYWNjb3VudElkeCwgbGFiZWwpIHtcbiAgICBsZXQgc3ViYWRkcmVzc0pzb24gPSBhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImNyZWF0ZVN1YmFkZHJlc3NcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKTtcbiAgICByZXR1cm4gTW9uZXJvV2FsbGV0S2V5cy5zYW5pdGl6ZVN1YmFkZHJlc3MobmV3IE1vbmVyb1N1YmFkZHJlc3Moc3ViYWRkcmVzc0pzb24pKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0VHhzKHF1ZXJ5KSB7XG4gICAgcXVlcnkgPSBNb25lcm9XYWxsZXQubm9ybWFsaXplVHhRdWVyeShxdWVyeSk7XG4gICAgbGV0IHJlc3BKc29uID0gYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRUeHNcIiwgW3F1ZXJ5LmdldEJsb2NrKCkudG9Kc29uKCldKTtcbiAgICByZXR1cm4gTW9uZXJvV2FsbGV0RnVsbC5kZXNlcmlhbGl6ZVR4cyhxdWVyeSwgSlNPTi5zdHJpbmdpZnkoe2Jsb2NrczogcmVzcEpzb24uYmxvY2tzfSkpOyAvLyBpbml0aWFsaXplIHR4cyBmcm9tIGJsb2NrcyBqc29uIHN0cmluZyBUT0RPOiB0aGlzIHN0cmluZ2lmaWVzIHRoZW4gdXRpbGl0eSBwYXJzZXMsIGF2b2lkXG4gIH1cbiAgXG4gIGFzeW5jIGdldFRyYW5zZmVycyhxdWVyeSkge1xuICAgIHF1ZXJ5ID0gTW9uZXJvV2FsbGV0Lm5vcm1hbGl6ZVRyYW5zZmVyUXVlcnkocXVlcnkpO1xuICAgIGxldCBibG9ja0pzb25zID0gYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRUcmFuc2ZlcnNcIiwgW3F1ZXJ5LmdldFR4UXVlcnkoKS5nZXRCbG9jaygpLnRvSnNvbigpXSk7XG4gICAgcmV0dXJuIE1vbmVyb1dhbGxldEZ1bGwuZGVzZXJpYWxpemVUcmFuc2ZlcnMocXVlcnksIEpTT04uc3RyaW5naWZ5KHtibG9ja3M6IGJsb2NrSnNvbnN9KSk7IC8vIGluaXRpYWxpemUgdHJhbnNmZXJzIGZyb20gYmxvY2tzIGpzb24gc3RyaW5nIFRPRE86IHRoaXMgc3RyaW5naWZpZXMgdGhlbiB1dGlsaXR5IHBhcnNlcywgYXZvaWRcbiAgfVxuICBcbiAgYXN5bmMgZ2V0T3V0cHV0cyhxdWVyeSkge1xuICAgIHF1ZXJ5ID0gTW9uZXJvV2FsbGV0Lm5vcm1hbGl6ZU91dHB1dFF1ZXJ5KHF1ZXJ5KTtcbiAgICBsZXQgYmxvY2tKc29ucyA9IGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZ2V0T3V0cHV0c1wiLCBbcXVlcnkuZ2V0VHhRdWVyeSgpLmdldEJsb2NrKCkudG9Kc29uKCldKTtcbiAgICByZXR1cm4gTW9uZXJvV2FsbGV0RnVsbC5kZXNlcmlhbGl6ZU91dHB1dHMocXVlcnksIEpTT04uc3RyaW5naWZ5KHtibG9ja3M6IGJsb2NrSnNvbnN9KSk7IC8vIGluaXRpYWxpemUgdHJhbnNmZXJzIGZyb20gYmxvY2tzIGpzb24gc3RyaW5nIFRPRE86IHRoaXMgc3RyaW5naWZpZXMgdGhlbiB1dGlsaXR5IHBhcnNlcywgYXZvaWRcbiAgfVxuICBcbiAgYXN5bmMgZXhwb3J0T3V0cHV0cyhhbGwpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJleHBvcnRPdXRwdXRzXCIsIFthbGxdKTtcbiAgfVxuICBcbiAgYXN5bmMgaW1wb3J0T3V0cHV0cyhvdXRwdXRzSGV4KSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiaW1wb3J0T3V0cHV0c1wiLCBbb3V0cHV0c0hleF0pO1xuICB9XG4gIFxuICBhc3luYyBleHBvcnRLZXlJbWFnZXMoYWxsKSB7XG4gICAgbGV0IGtleUltYWdlcyA9IFtdO1xuICAgIGZvciAobGV0IGtleUltYWdlSnNvbiBvZiBhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImdldEtleUltYWdlc1wiLCBbYWxsXSkpIGtleUltYWdlcy5wdXNoKG5ldyBNb25lcm9LZXlJbWFnZShrZXlJbWFnZUpzb24pKTtcbiAgICByZXR1cm4ga2V5SW1hZ2VzO1xuICB9XG4gIFxuICBhc3luYyBpbXBvcnRLZXlJbWFnZXMoa2V5SW1hZ2VzKSB7XG4gICAgbGV0IGtleUltYWdlc0pzb24gPSBbXTtcbiAgICBmb3IgKGxldCBrZXlJbWFnZSBvZiBrZXlJbWFnZXMpIGtleUltYWdlc0pzb24ucHVzaChrZXlJbWFnZS50b0pzb24oKSk7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9LZXlJbWFnZUltcG9ydFJlc3VsdChhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImltcG9ydEtleUltYWdlc1wiLCBba2V5SW1hZ2VzSnNvbl0pKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0TmV3S2V5SW1hZ2VzRnJvbUxhc3RJbXBvcnQoKTogUHJvbWlzZTxNb25lcm9LZXlJbWFnZVtdPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTW9uZXJvV2FsbGV0RnVsbC5nZXROZXdLZXlJbWFnZXNGcm9tTGFzdEltcG9ydCgpIG5vdCBpbXBsZW1lbnRlZFwiKTtcbiAgfVxuICBcbiAgYXN5bmMgZnJlZXplT3V0cHV0KGtleUltYWdlKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZnJlZXplT3V0cHV0XCIsIFtrZXlJbWFnZV0pO1xuICB9XG4gIFxuICBhc3luYyB0aGF3T3V0cHV0KGtleUltYWdlKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwidGhhd091dHB1dFwiLCBba2V5SW1hZ2VdKTtcbiAgfVxuICBcbiAgYXN5bmMgaXNPdXRwdXRGcm96ZW4oa2V5SW1hZ2UpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJpc091dHB1dEZyb3plblwiLCBba2V5SW1hZ2VdKTtcbiAgfVxuXG4gIGFzeW5jIGdldERlZmF1bHRGZWVQcmlvcml0eSgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXREZWZhdWx0RmVlUHJpb3JpdHlcIik7XG4gIH1cbiAgXG4gIGFzeW5jIGNyZWF0ZVR4cyhjb25maWcpIHtcbiAgICBjb25maWcgPSBNb25lcm9XYWxsZXQubm9ybWFsaXplQ3JlYXRlVHhzQ29uZmlnKGNvbmZpZyk7XG4gICAgbGV0IHR4U2V0SnNvbiA9IGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiY3JlYXRlVHhzXCIsIFtjb25maWcudG9Kc29uKCldKTtcbiAgICByZXR1cm4gbmV3IE1vbmVyb1R4U2V0KHR4U2V0SnNvbikuZ2V0VHhzKCk7XG4gIH1cbiAgXG4gIGFzeW5jIHN3ZWVwT3V0cHV0KGNvbmZpZykge1xuICAgIGNvbmZpZyA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVTd2VlcE91dHB1dENvbmZpZyhjb25maWcpO1xuICAgIGxldCB0eFNldEpzb24gPSBhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcInN3ZWVwT3V0cHV0XCIsIFtjb25maWcudG9Kc29uKCldKTtcbiAgICByZXR1cm4gbmV3IE1vbmVyb1R4U2V0KHR4U2V0SnNvbikuZ2V0VHhzKClbMF07XG4gIH1cblxuICBhc3luYyBzd2VlcFVubG9ja2VkKGNvbmZpZykge1xuICAgIGNvbmZpZyA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVTd2VlcFVubG9ja2VkQ29uZmlnKGNvbmZpZyk7XG4gICAgbGV0IHR4U2V0c0pzb24gPSBhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcInN3ZWVwVW5sb2NrZWRcIiwgW2NvbmZpZy50b0pzb24oKV0pO1xuICAgIGxldCB0eHMgPSBbXTtcbiAgICBmb3IgKGxldCB0eFNldEpzb24gb2YgdHhTZXRzSnNvbikgZm9yIChsZXQgdHggb2YgbmV3IE1vbmVyb1R4U2V0KHR4U2V0SnNvbikuZ2V0VHhzKCkpIHR4cy5wdXNoKHR4KTtcbiAgICByZXR1cm4gdHhzO1xuICB9XG4gIFxuICBhc3luYyBzd2VlcER1c3QocmVsYXkpIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb1R4U2V0KGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwic3dlZXBEdXN0XCIsIFtyZWxheV0pKS5nZXRUeHMoKSB8fCBbXTtcbiAgfVxuICBcbiAgYXN5bmMgcmVsYXlUeHModHhzT3JNZXRhZGF0YXMpIHtcbiAgICBhc3NlcnQoQXJyYXkuaXNBcnJheSh0eHNPck1ldGFkYXRhcyksIFwiTXVzdCBwcm92aWRlIGFuIGFycmF5IG9mIHR4cyBvciB0aGVpciBtZXRhZGF0YSB0byByZWxheVwiKTtcbiAgICBsZXQgdHhNZXRhZGF0YXMgPSBbXTtcbiAgICBmb3IgKGxldCB0eE9yTWV0YWRhdGEgb2YgdHhzT3JNZXRhZGF0YXMpIHR4TWV0YWRhdGFzLnB1c2godHhPck1ldGFkYXRhIGluc3RhbmNlb2YgTW9uZXJvVHhXYWxsZXQgPyB0eE9yTWV0YWRhdGEuZ2V0TWV0YWRhdGEoKSA6IHR4T3JNZXRhZGF0YSk7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwicmVsYXlUeHNcIiwgW3R4TWV0YWRhdGFzXSk7XG4gIH1cbiAgXG4gIGFzeW5jIGRlc2NyaWJlVHhTZXQodHhTZXQpIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb1R4U2V0KGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZGVzY3JpYmVUeFNldFwiLCBbdHhTZXQudG9Kc29uKCldKSk7XG4gIH1cbiAgXG4gIGFzeW5jIHNpZ25UeHModW5zaWduZWRUeEhleCkge1xuICAgIHJldHVybiBuZXcgTW9uZXJvVHhTZXQoYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJzaWduVHhzXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSkpO1xuICB9XG4gIFxuICBhc3luYyBzdWJtaXRUeHMoc2lnbmVkVHhIZXgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJzdWJtaXRUeHNcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKTtcbiAgfVxuICBcbiAgYXN5bmMgc2lnbk1lc3NhZ2UobWVzc2FnZSwgc2lnbmF0dXJlVHlwZSwgYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcInNpZ25NZXNzYWdlXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIHZlcmlmeU1lc3NhZ2UobWVzc2FnZSwgYWRkcmVzcywgc2lnbmF0dXJlKSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9NZXNzYWdlU2lnbmF0dXJlUmVzdWx0KGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwidmVyaWZ5TWVzc2FnZVwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0VHhLZXkodHhIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZ2V0VHhLZXlcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKTtcbiAgfVxuICBcbiAgYXN5bmMgY2hlY2tUeEtleSh0eEhhc2gsIHR4S2V5LCBhZGRyZXNzKSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9DaGVja1R4KGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiY2hlY2tUeEtleVwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0VHhQcm9vZih0eEhhc2gsIGFkZHJlc3MsIG1lc3NhZ2UpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRUeFByb29mXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGNoZWNrVHhQcm9vZih0eEhhc2gsIGFkZHJlc3MsIG1lc3NhZ2UsIHNpZ25hdHVyZSkge1xuICAgIHJldHVybiBuZXcgTW9uZXJvQ2hlY2tUeChhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImNoZWNrVHhQcm9vZlwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0U3BlbmRQcm9vZih0eEhhc2gsIG1lc3NhZ2UpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRTcGVuZFByb29mXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGNoZWNrU3BlbmRQcm9vZih0eEhhc2gsIG1lc3NhZ2UsIHNpZ25hdHVyZSkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImNoZWNrU3BlbmRQcm9vZlwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyBnZXRSZXNlcnZlUHJvb2ZXYWxsZXQobWVzc2FnZSkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImdldFJlc2VydmVQcm9vZldhbGxldFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyBnZXRSZXNlcnZlUHJvb2ZBY2NvdW50KGFjY291bnRJZHgsIGFtb3VudCwgbWVzc2FnZSkge1xuICAgIHRyeSB7IHJldHVybiBhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImdldFJlc2VydmVQcm9vZkFjY291bnRcIiwgW2FjY291bnRJZHgsIGFtb3VudC50b1N0cmluZygpLCBtZXNzYWdlXSk7IH1cbiAgICBjYXRjaCAoZTogYW55KSB7IHRocm93IG5ldyBNb25lcm9FcnJvcihlLm1lc3NhZ2UsIC0xKTsgfVxuICB9XG5cbiAgYXN5bmMgY2hlY2tSZXNlcnZlUHJvb2YoYWRkcmVzcywgbWVzc2FnZSwgc2lnbmF0dXJlKSB7XG4gICAgdHJ5IHsgcmV0dXJuIG5ldyBNb25lcm9DaGVja1Jlc2VydmUoYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJjaGVja1Jlc2VydmVQcm9vZlwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpKTsgfVxuICAgIGNhdGNoIChlOiBhbnkpIHsgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKGUubWVzc2FnZSwgLTEpOyB9XG4gIH1cbiAgXG4gIGFzeW5jIGdldFR4Tm90ZXModHhIYXNoZXMpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRUeE5vdGVzXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIHNldFR4Tm90ZXModHhIYXNoZXMsIG5vdGVzKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwic2V0VHhOb3Rlc1wiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyBnZXRBZGRyZXNzQm9va0VudHJpZXMoZW50cnlJbmRpY2VzKSB7XG4gICAgaWYgKCFlbnRyeUluZGljZXMpIGVudHJ5SW5kaWNlcyA9IFtdO1xuICAgIGxldCBlbnRyaWVzID0gW107XG4gICAgZm9yIChsZXQgZW50cnlKc29uIG9mIGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZ2V0QWRkcmVzc0Jvb2tFbnRyaWVzXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSkpIHtcbiAgICAgIGVudHJpZXMucHVzaChuZXcgTW9uZXJvQWRkcmVzc0Jvb2tFbnRyeShlbnRyeUpzb24pKTtcbiAgICB9XG4gICAgcmV0dXJuIGVudHJpZXM7XG4gIH1cbiAgXG4gIGFzeW5jIGFkZEFkZHJlc3NCb29rRW50cnkoYWRkcmVzcywgZGVzY3JpcHRpb24pIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJhZGRBZGRyZXNzQm9va0VudHJ5XCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGVkaXRBZGRyZXNzQm9va0VudHJ5KGluZGV4LCBzZXRBZGRyZXNzLCBhZGRyZXNzLCBzZXREZXNjcmlwdGlvbiwgZGVzY3JpcHRpb24pIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJlZGl0QWRkcmVzc0Jvb2tFbnRyeVwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyBkZWxldGVBZGRyZXNzQm9va0VudHJ5KGVudHJ5SWR4KSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZGVsZXRlQWRkcmVzc0Jvb2tFbnRyeVwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyB0YWdBY2NvdW50cyh0YWcsIGFjY291bnRJbmRpY2VzKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwidGFnQWNjb3VudHNcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKTtcbiAgfVxuXG4gIGFzeW5jIHVudGFnQWNjb3VudHMoYWNjb3VudEluZGljZXMpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJ1bnRhZ0FjY291bnRzXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEFjY291bnRUYWdzKCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImdldEFjY291bnRUYWdzXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cblxuICBhc3luYyBzZXRBY2NvdW50VGFnTGFiZWwodGFnLCBsYWJlbCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcInNldEFjY291bnRUYWdMYWJlbFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyBnZXRQYXltZW50VXJpKGNvbmZpZykge1xuICAgIGNvbmZpZyA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVDcmVhdGVUeHNDb25maWcoY29uZmlnKTtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRQYXltZW50VXJpXCIsIFtjb25maWcudG9Kc29uKCldKTtcbiAgfVxuICBcbiAgYXN5bmMgcGFyc2VQYXltZW50VXJpKHVyaSkge1xuICAgIHJldHVybiBuZXcgTW9uZXJvVHhDb25maWcoYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJwYXJzZVBheW1lbnRVcmlcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEF0dHJpYnV0ZShrZXkpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRBdHRyaWJ1dGVcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKTtcbiAgfVxuICBcbiAgYXN5bmMgc2V0QXR0cmlidXRlKGtleSwgdmFsKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwic2V0QXR0cmlidXRlXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIHN0YXJ0TWluaW5nKG51bVRocmVhZHMsIGJhY2tncm91bmRNaW5pbmcsIGlnbm9yZUJhdHRlcnkpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJzdGFydE1pbmluZ1wiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyBzdG9wTWluaW5nKCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcInN0b3BNaW5pbmdcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKTtcbiAgfVxuICBcbiAgYXN5bmMgaXNNdWx0aXNpZ0ltcG9ydE5lZWRlZCgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJpc011bHRpc2lnSW1wb3J0TmVlZGVkXCIpO1xuICB9XG4gIFxuICBhc3luYyBpc011bHRpc2lnKCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImlzTXVsdGlzaWdcIik7XG4gIH1cbiAgXG4gIGFzeW5jIGdldE11bHRpc2lnSW5mbygpIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb011bHRpc2lnSW5mbyhhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImdldE11bHRpc2lnSW5mb1wiKSk7XG4gIH1cbiAgXG4gIGFzeW5jIHByZXBhcmVNdWx0aXNpZygpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJwcmVwYXJlTXVsdGlzaWdcIik7XG4gIH1cbiAgXG4gIGFzeW5jIG1ha2VNdWx0aXNpZyhtdWx0aXNpZ0hleGVzLCB0aHJlc2hvbGQsIHBhc3N3b3JkKSB7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwibWFrZU11bHRpc2lnXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGV4Y2hhbmdlTXVsdGlzaWdLZXlzKG11bHRpc2lnSGV4ZXMsIHBhc3N3b3JkKSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9NdWx0aXNpZ0luaXRSZXN1bHQoYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJleGNoYW5nZU11bHRpc2lnS2V5c1wiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpKTtcbiAgfVxuICBcbiAgYXN5bmMgZXhwb3J0TXVsdGlzaWdIZXgoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZXhwb3J0TXVsdGlzaWdIZXhcIik7XG4gIH1cbiAgXG4gIGFzeW5jIGltcG9ydE11bHRpc2lnSGV4KG11bHRpc2lnSGV4ZXMpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJpbXBvcnRNdWx0aXNpZ0hleFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyBzaWduTXVsdGlzaWdUeEhleChtdWx0aXNpZ1R4SGV4KSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9NdWx0aXNpZ1NpZ25SZXN1bHQoYXdhaXQgdGhpcy5pbnZva2VXb3JrZXIoXCJzaWduTXVsdGlzaWdUeEhleFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpKTtcbiAgfVxuICBcbiAgYXN5bmMgc3VibWl0TXVsdGlzaWdUeEhleChzaWduZWRNdWx0aXNpZ1R4SGV4KSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwic3VibWl0TXVsdGlzaWdUeEhleFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICB9XG4gIFxuICBhc3luYyBnZXREYXRhKCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImdldERhdGFcIik7XG4gIH1cbiAgXG4gIGFzeW5jIG1vdmVUbyhwYXRoKSB7XG4gICAgcmV0dXJuIE1vbmVyb1dhbGxldEZ1bGwubW92ZVRvKHBhdGgsIHRoaXMpO1xuICB9XG4gIFxuICBhc3luYyBjaGFuZ2VQYXNzd29yZChvbGRQYXNzd29yZCwgbmV3UGFzc3dvcmQpIHtcbiAgICBhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImNoYW5nZVBhc3N3b3JkXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSk7XG4gICAgaWYgKHRoaXMucGF0aCkgYXdhaXQgdGhpcy5zYXZlKCk7IC8vIGF1dG8gc2F2ZVxuICB9XG4gIFxuICBhc3luYyBzYXZlKCkge1xuICAgIHJldHVybiBNb25lcm9XYWxsZXRGdWxsLnNhdmUodGhpcyk7XG4gIH1cblxuICBhc3luYyBjbG9zZShzYXZlKSB7XG4gICAgaWYgKGF3YWl0IHRoaXMuaXNDbG9zZWQoKSkgcmV0dXJuO1xuICAgIGlmIChzYXZlKSBhd2FpdCB0aGlzLnNhdmUoKTtcbiAgICB3aGlsZSAodGhpcy53cmFwcGVkTGlzdGVuZXJzLmxlbmd0aCkgYXdhaXQgdGhpcy5yZW1vdmVMaXN0ZW5lcih0aGlzLndyYXBwZWRMaXN0ZW5lcnNbMF0uZ2V0TGlzdGVuZXIoKSk7XG4gICAgYXdhaXQgc3VwZXIuY2xvc2UoZmFsc2UpO1xuICB9XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIExJU1RFTklORyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqXG4gKiBSZWNlaXZlcyBub3RpZmljYXRpb25zIGRpcmVjdGx5IGZyb20gd2FzbSBjKysuXG4gKiBcbiAqIEBwcml2YXRlXG4gKi9cbmNsYXNzIFdhbGxldFdhc21MaXN0ZW5lciB7XG5cbiAgcHJvdGVjdGVkIHdhbGxldDogTW9uZXJvV2FsbGV0O1xuICBcbiAgY29uc3RydWN0b3Iod2FsbGV0KSB7XG4gICAgdGhpcy53YWxsZXQgPSB3YWxsZXQ7XG4gIH1cbiAgXG4gIGFzeW5jIG9uU3luY1Byb2dyZXNzKGhlaWdodCwgc3RhcnRIZWlnaHQsIGVuZEhlaWdodCwgcGVyY2VudERvbmUsIG1lc3NhZ2UpIHtcbiAgICBhd2FpdCB0aGlzLndhbGxldC5hbm5vdW5jZVN5bmNQcm9ncmVzcyhoZWlnaHQsIHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQsIHBlcmNlbnREb25lLCBtZXNzYWdlKTtcbiAgfVxuICBcbiAgYXN5bmMgb25OZXdCbG9jayhoZWlnaHQpIHtcbiAgICBhd2FpdCB0aGlzLndhbGxldC5hbm5vdW5jZU5ld0Jsb2NrKGhlaWdodCk7XG4gIH1cbiAgXG4gIGFzeW5jIG9uQmFsYW5jZXNDaGFuZ2VkKG5ld0JhbGFuY2VTdHIsIG5ld1VubG9ja2VkQmFsYW5jZVN0cikge1xuICAgIGF3YWl0IHRoaXMud2FsbGV0LmFubm91bmNlQmFsYW5jZXNDaGFuZ2VkKG5ld0JhbGFuY2VTdHIsIG5ld1VubG9ja2VkQmFsYW5jZVN0cik7XG4gIH1cbiAgXG4gIGFzeW5jIG9uT3V0cHV0UmVjZWl2ZWQoaGVpZ2h0LCB0eEhhc2gsIGFtb3VudFN0ciwgYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCwgdmVyc2lvbiwgdW5sb2NrVGltZSwgaXNMb2NrZWQpIHtcbiAgICBcbiAgICAvLyBidWlsZCByZWNlaXZlZCBvdXRwdXRcbiAgICBsZXQgb3V0cHV0ID0gbmV3IE1vbmVyb091dHB1dFdhbGxldCgpO1xuICAgIG91dHB1dC5zZXRBbW91bnQoQmlnSW50KGFtb3VudFN0cikpO1xuICAgIG91dHB1dC5zZXRBY2NvdW50SW5kZXgoYWNjb3VudElkeCk7XG4gICAgb3V0cHV0LnNldFN1YmFkZHJlc3NJbmRleChzdWJhZGRyZXNzSWR4KTtcbiAgICBsZXQgdHggPSBuZXcgTW9uZXJvVHhXYWxsZXQoKTtcbiAgICB0eC5zZXRIYXNoKHR4SGFzaCk7XG4gICAgdHguc2V0VmVyc2lvbih2ZXJzaW9uKTtcbiAgICB0eC5zZXRVbmxvY2tUaW1lKHVubG9ja1RpbWUpO1xuICAgIG91dHB1dC5zZXRUeCh0eCk7XG4gICAgdHguc2V0T3V0cHV0cyhbb3V0cHV0XSk7XG4gICAgdHguc2V0SXNJbmNvbWluZyh0cnVlKTtcbiAgICB0eC5zZXRJc0xvY2tlZChpc0xvY2tlZCk7XG4gICAgaWYgKGhlaWdodCA+IDApIHtcbiAgICAgIGxldCBibG9jayA9IG5ldyBNb25lcm9CbG9jaygpLnNldEhlaWdodChoZWlnaHQpO1xuICAgICAgYmxvY2suc2V0VHhzKFt0eCBhcyBNb25lcm9UeF0pO1xuICAgICAgdHguc2V0QmxvY2soYmxvY2spO1xuICAgICAgdHguc2V0SXNDb25maXJtZWQodHJ1ZSk7XG4gICAgICB0eC5zZXRJblR4UG9vbChmYWxzZSk7XG4gICAgICB0eC5zZXRJc0ZhaWxlZChmYWxzZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHR4LnNldElzQ29uZmlybWVkKGZhbHNlKTtcbiAgICAgIHR4LnNldEluVHhQb29sKHRydWUpO1xuICAgIH1cbiAgICBcbiAgICAvLyBhbm5vdW5jZSBvdXRwdXRcbiAgICBhd2FpdCB0aGlzLndhbGxldC5hbm5vdW5jZU91dHB1dFJlY2VpdmVkKG91dHB1dCk7XG4gIH1cbiAgXG4gIGFzeW5jIG9uT3V0cHV0U3BlbnQoaGVpZ2h0LCB0eEhhc2gsIGFtb3VudFN0ciwgYWNjb3VudElkeFN0ciwgc3ViYWRkcmVzc0lkeFN0ciwgdmVyc2lvbiwgdW5sb2NrVGltZSwgaXNMb2NrZWQpIHtcbiAgICBcbiAgICAvLyBidWlsZCBzcGVudCBvdXRwdXRcbiAgICBsZXQgb3V0cHV0ID0gbmV3IE1vbmVyb091dHB1dFdhbGxldCgpO1xuICAgIG91dHB1dC5zZXRBbW91bnQoQmlnSW50KGFtb3VudFN0cikpO1xuICAgIGlmIChhY2NvdW50SWR4U3RyKSBvdXRwdXQuc2V0QWNjb3VudEluZGV4KHBhcnNlSW50KGFjY291bnRJZHhTdHIpKTtcbiAgICBpZiAoc3ViYWRkcmVzc0lkeFN0cikgb3V0cHV0LnNldFN1YmFkZHJlc3NJbmRleChwYXJzZUludChzdWJhZGRyZXNzSWR4U3RyKSk7XG4gICAgbGV0IHR4ID0gbmV3IE1vbmVyb1R4V2FsbGV0KCk7XG4gICAgdHguc2V0SGFzaCh0eEhhc2gpO1xuICAgIHR4LnNldFZlcnNpb24odmVyc2lvbik7XG4gICAgdHguc2V0VW5sb2NrVGltZSh1bmxvY2tUaW1lKTtcbiAgICB0eC5zZXRJc0xvY2tlZChpc0xvY2tlZCk7XG4gICAgb3V0cHV0LnNldFR4KHR4KTtcbiAgICB0eC5zZXRJbnB1dHMoW291dHB1dF0pO1xuICAgIGlmIChoZWlnaHQgPiAwKSB7XG4gICAgICBsZXQgYmxvY2sgPSBuZXcgTW9uZXJvQmxvY2soKS5zZXRIZWlnaHQoaGVpZ2h0KTtcbiAgICAgIGJsb2NrLnNldFR4cyhbdHhdKTtcbiAgICAgIHR4LnNldEJsb2NrKGJsb2NrKTtcbiAgICAgIHR4LnNldElzQ29uZmlybWVkKHRydWUpO1xuICAgICAgdHguc2V0SW5UeFBvb2woZmFsc2UpO1xuICAgICAgdHguc2V0SXNGYWlsZWQoZmFsc2UpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0eC5zZXRJc0NvbmZpcm1lZChmYWxzZSk7XG4gICAgICB0eC5zZXRJblR4UG9vbCh0cnVlKTtcbiAgICB9XG4gICAgXG4gICAgLy8gYW5ub3VuY2Ugb3V0cHV0XG4gICAgYXdhaXQgdGhpcy53YWxsZXQuYW5ub3VuY2VPdXRwdXRTcGVudChvdXRwdXQpO1xuICB9XG59XG5cbi8qKlxuICogSW50ZXJuYWwgbGlzdGVuZXIgdG8gYnJpZGdlIG5vdGlmaWNhdGlvbnMgdG8gZXh0ZXJuYWwgbGlzdGVuZXJzLlxuICogXG4gKiBAcHJpdmF0ZVxuICovXG5jbGFzcyBXYWxsZXRXb3JrZXJMaXN0ZW5lciB7XG5cbiAgcHJvdGVjdGVkIGlkOiBhbnk7XG4gIHByb3RlY3RlZCBsaXN0ZW5lcjogYW55O1xuICBcbiAgY29uc3RydWN0b3IobGlzdGVuZXIpIHtcbiAgICB0aGlzLmlkID0gR2VuVXRpbHMuZ2V0VVVJRCgpO1xuICAgIHRoaXMubGlzdGVuZXIgPSBsaXN0ZW5lcjtcbiAgfVxuICBcbiAgZ2V0SWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuaWQ7XG4gIH1cbiAgXG4gIGdldExpc3RlbmVyKCkge1xuICAgIHJldHVybiB0aGlzLmxpc3RlbmVyO1xuICB9XG4gIFxuICBvblN5bmNQcm9ncmVzcyhoZWlnaHQsIHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQsIHBlcmNlbnREb25lLCBtZXNzYWdlKSB7XG4gICAgdGhpcy5saXN0ZW5lci5vblN5bmNQcm9ncmVzcyhoZWlnaHQsIHN0YXJ0SGVpZ2h0LCBlbmRIZWlnaHQsIHBlcmNlbnREb25lLCBtZXNzYWdlKTtcbiAgfVxuXG4gIGFzeW5jIG9uTmV3QmxvY2soaGVpZ2h0KSB7XG4gICAgYXdhaXQgdGhpcy5saXN0ZW5lci5vbk5ld0Jsb2NrKGhlaWdodCk7XG4gIH1cbiAgXG4gIGFzeW5jIG9uQmFsYW5jZXNDaGFuZ2VkKG5ld0JhbGFuY2VTdHIsIG5ld1VubG9ja2VkQmFsYW5jZVN0cikge1xuICAgIGF3YWl0IHRoaXMubGlzdGVuZXIub25CYWxhbmNlc0NoYW5nZWQoQmlnSW50KG5ld0JhbGFuY2VTdHIpLCBCaWdJbnQobmV3VW5sb2NrZWRCYWxhbmNlU3RyKSk7XG4gIH1cblxuICBhc3luYyBvbk91dHB1dFJlY2VpdmVkKGJsb2NrSnNvbikge1xuICAgIGxldCBibG9jayA9IG5ldyBNb25lcm9CbG9jayhibG9ja0pzb24sIE1vbmVyb0Jsb2NrLkRlc2VyaWFsaXphdGlvblR5cGUuVFhfV0FMTEVUKTtcbiAgICBhd2FpdCB0aGlzLmxpc3RlbmVyLm9uT3V0cHV0UmVjZWl2ZWQoYmxvY2suZ2V0VHhzKClbMF0uZ2V0T3V0cHV0cygpWzBdKTtcbiAgfVxuICBcbiAgYXN5bmMgb25PdXRwdXRTcGVudChibG9ja0pzb24pIHtcbiAgICBsZXQgYmxvY2sgPSBuZXcgTW9uZXJvQmxvY2soYmxvY2tKc29uLCBNb25lcm9CbG9jay5EZXNlcmlhbGl6YXRpb25UeXBlLlRYX1dBTExFVCk7XG4gICAgYXdhaXQgdGhpcy5saXN0ZW5lci5vbk91dHB1dFNwZW50KGJsb2NrLmdldFR4cygpWzBdLmdldElucHV0cygpWzBdKTtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsT0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsS0FBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUUsU0FBQSxHQUFBSCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUcsYUFBQSxHQUFBSixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUksV0FBQSxHQUFBTCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUssY0FBQSxHQUFBTixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQU0saUJBQUEsR0FBQVAsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFPLHVCQUFBLEdBQUFSLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBUSxZQUFBLEdBQUFULHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBUyxjQUFBLEdBQUFWLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBVSxtQkFBQSxHQUFBWCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQVcsZ0JBQUEsR0FBQVosc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFZLFlBQUEsR0FBQWIsc0JBQUEsQ0FBQUMsT0FBQTs7QUFFQSxJQUFBYSx3QkFBQSxHQUFBZCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQWMsZUFBQSxH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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/MoneroWalletKeys.d.ts b/dist/src/main/ts/wallet/MoneroWalletKeys.d.ts new file mode 100644 index 000000000..ccaec6d63 --- /dev/null +++ b/dist/src/main/ts/wallet/MoneroWalletKeys.d.ts @@ -0,0 +1,119 @@ +import MoneroAccount from "./model/MoneroAccount"; +import MoneroIntegratedAddress from "./model/MoneroIntegratedAddress"; +import MoneroSubaddress from "./model/MoneroSubaddress"; +import MoneroVersion from "../daemon/model/MoneroVersion"; +import MoneroWallet from "./MoneroWallet"; +import MoneroWalletConfig from "./model/MoneroWalletConfig"; +/** + * Implements a MoneroWallet which only manages keys using WebAssembly. + */ +export declare class MoneroWalletKeys extends MoneroWallet { + protected cppAddress: string; + protected module: any; + protected walletProxy: MoneroWalletKeysProxy; + /** + *

Create a wallet using WebAssembly bindings to monero-project.

+ * + *

Example:

+ * + * + * let wallet = await MoneroWalletKeys.createWallet({
+ *    password: "abc123",
+ *    networkType: MoneroNetworkType.STAGENET,
+ *    seed: "coexist igloo pamphlet lagoon..."
+ * }); + *
+ * + * @param {MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object + * @param {string|number} config.networkType - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) + * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given) + * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed phrase + * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys) + * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional) + * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional) + * @param {string} [config.language] - language of the wallet's seed (defaults to "English" or auto-detected) + * @return {MoneroWalletKeys} the created wallet + */ + static createWallet(config: Partial): Promise; + protected static createWalletRandom(config: Partial): Promise; + protected static createWalletFromSeed(config: Partial): Promise; + protected static createWalletFromKeys(config: Partial): Promise; + static getSeedLanguages(): Promise; + /** + * Internal constructor which is given the memory address of a C++ wallet + * instance. + * + * This method should not be called externally but should be called through + * static wallet creation utilities in this class. + * + * @param {number} cppAddress - address of the wallet instance in C++ + * @param {MoneroWalletKeysProxy} walletProxy - proxy + * + * @private + */ + constructor(cppAddress: any, walletProxy?: MoneroWalletKeysProxy); + isViewOnly(): Promise; + isConnectedToDaemon(): Promise; + getVersion(): Promise; + /** + * @ignore + */ + getPath(): Promise; + getSeed(): Promise; + getSeedLanguage(): Promise; + getPrivateSpendKey(): Promise; + getPrivateViewKey(): Promise; + getPublicViewKey(): Promise; + getPublicSpendKey(): Promise; + getAddress(accountIdx: number, subaddressIdx: number): Promise; + getAddressIndex(address: string): Promise; + getAccounts(includeSubaddresses?: boolean, tag?: string): Promise; + close(save?: boolean): Promise; + isClosed(): Promise; + getPrimaryAddress(): Promise; + getSubaddress(accountIdx: number, subaddressIdx: number): Promise; + static sanitizeSubaddress(subaddress: any): any; + protected assertNotClosed(): void; + protected getWalletProxy(): MoneroWalletKeysProxy; +} +/** + * Implements a MoneroWallet by proxying requests to a worker which runs a keys-only wallet. + * + * TODO: sort these methods according to master sort in MoneroWallet.ts + * TODO: probably only allow one listener to worker then propogate to registered listeners for performance + * + * @private + */ +export declare class MoneroWalletKeysProxy extends MoneroWallet { + protected walletId: string; + protected worker: Worker; + static createWallet(config: any): Promise; + /** + * Internal constructor which is given a worker to communicate with via messages. + * + * This method should not be called externally but should be called through + * static wallet creation utilities in this class. + * + * @param {string} walletId - identifies the wallet with the worker + * @param {Worker} worker - worker to communicate with via messages + * + * @protected + */ + constructor(walletId: any, worker: any); + isViewOnly(): Promise; + getVersion(): Promise; + getSeed(): Promise; + getSeedLanguage(): Promise; + getSeedLanguages(): Promise; + getPrivateSpendKey(): Promise; + getPrivateViewKey(): Promise; + getPublicViewKey(): Promise; + getPublicSpendKey(): Promise; + getAddress(accountIdx: any, subaddressIdx: any): Promise; + getAddressIndex(address: any): Promise; + getIntegratedAddress(standardAddress: any, paymentId: any): Promise; + decodeIntegratedAddress(integratedAddress: any): Promise; + close(save: any): Promise; + isClosed(): Promise; + protected invokeWorker(fnName: string, args?: any): Promise; +} diff --git a/dist/src/main/ts/wallet/MoneroWalletKeys.js b/dist/src/main/ts/wallet/MoneroWalletKeys.js new file mode 100644 index 000000000..d7d66f201 --- /dev/null +++ b/dist/src/main/ts/wallet/MoneroWalletKeys.js @@ -0,0 +1,473 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.MoneroWalletKeysProxy = exports.MoneroWalletKeys = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../common/GenUtils")); +var _LibraryUtils = _interopRequireDefault(require("../common/LibraryUtils")); + +var _MoneroError = _interopRequireDefault(require("../common/MoneroError")); +var _MoneroIntegratedAddress = _interopRequireDefault(require("./model/MoneroIntegratedAddress")); +var _MoneroNetworkType = _interopRequireDefault(require("../daemon/model/MoneroNetworkType")); +var _MoneroSubaddress = _interopRequireDefault(require("./model/MoneroSubaddress")); +var _MoneroVersion = _interopRequireDefault(require("../daemon/model/MoneroVersion")); +var _MoneroWallet = _interopRequireDefault(require("./MoneroWallet")); +var _MoneroWalletConfig = _interopRequireDefault(require("./model/MoneroWalletConfig")); + + +/** + * Implements a MoneroWallet which only manages keys using WebAssembly. + */ +class MoneroWalletKeys extends _MoneroWallet.default { + + // instance variables + + + + + // --------------------------- STATIC UTILITIES ----------------------------- + + /** + *

Create a wallet using WebAssembly bindings to monero-project.

+ * + *

Example:

+ * + * + * let wallet = await MoneroWalletKeys.createWallet({
+ *    password: "abc123",
+ *    networkType: MoneroNetworkType.STAGENET,
+ *    seed: "coexist igloo pamphlet lagoon..."
+ * }); + *
+ * + * @param {MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object + * @param {string|number} config.networkType - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) + * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given) + * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed phrase + * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys) + * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional) + * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional) + * @param {string} [config.language] - language of the wallet's seed (defaults to "English" or auto-detected) + * @return {MoneroWalletKeys} the created wallet + */ + static async createWallet(config) { + + // normalize and validate config + if (config === undefined) throw new _MoneroError.default("Must provide config to create wallet"); + config = config instanceof _MoneroWalletConfig.default ? config : new _MoneroWalletConfig.default(config); + if (config.getSeed() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) { + throw new _MoneroError.default("Wallet may be initialized with a seed or keys but not both"); + } + if (config.getNetworkType() === undefined) throw new _MoneroError.default("Must provide a networkType: 'mainnet', 'testnet' or 'stagenet'"); + if (config.getSaveCurrent() === true) throw new _MoneroError.default("Cannot save current wallet when creating keys-only wallet"); + + // initialize proxied wallet if configured + if (config.getProxyToWorker() === undefined) config.setProxyToWorker(true); + if (config.getProxyToWorker()) { + let walletProxy = await MoneroWalletKeysProxy.createWallet(config);; + return new MoneroWalletKeys(undefined, walletProxy); + } + + // disallow server connection + if (config.getServer() !== undefined) throw new _MoneroError.default("Cannot initialize keys wallet with server connection"); + + // create wallet + if (config.getSeed() !== undefined) return MoneroWalletKeys.createWalletFromSeed(config);else + if (config.getPrivateSpendKey() !== undefined || config.getPrimaryAddress() !== undefined) return MoneroWalletKeys.createWalletFromKeys(config);else + return MoneroWalletKeys.createWalletRandom(config); + } + + static async createWalletRandom(config) { + + // validate and sanitize params + config = config.copy(); + if (config.getSeedOffset() !== undefined) throw new _MoneroError.default("Cannot provide seedOffset when creating random wallet"); + if (config.getRestoreHeight() !== undefined) throw new _MoneroError.default("Cannot provide restoreHeight when creating random wallet"); + _MoneroNetworkType.default.validate(config.getNetworkType()); + if (config.getLanguage() === undefined) config.setLanguage("English"); + + // load wasm module + let module = await _LibraryUtils.default.loadWasmModule(); + + // queue call to wasm module + return module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // create wallet in wasm which invokes callback when done + module.create_keys_wallet_random(JSON.stringify(config.toJson()), (cppAddress) => { + if (typeof cppAddress === "string") reject(new _MoneroError.default(cppAddress));else + resolve(new MoneroWalletKeys(cppAddress)); + }); + }); + }); + } + + static async createWalletFromSeed(config) { + + // validate and sanitize params + _MoneroNetworkType.default.validate(config.getNetworkType()); + if (config.getSeed() === undefined) throw Error("Must define seed to create wallet from"); + if (config.getSeedOffset() === undefined) config.setSeedOffset(""); + if (config.getLanguage() !== undefined) throw new _MoneroError.default("Cannot provide language when creating wallet from seed"); + + // load wasm module + let module = await _LibraryUtils.default.loadWasmModule(); + + // queue call to wasm module + return module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // create wallet in wasm which invokes callback when done + module.create_keys_wallet_from_seed(JSON.stringify(config.toJson()), (cppAddress) => { + if (typeof cppAddress === "string") reject(new _MoneroError.default(cppAddress));else + resolve(new MoneroWalletKeys(cppAddress)); + }); + }); + }); + } + + static async createWalletFromKeys(config) { + + // validate and sanitize params + if (config.getSeedOffset() !== undefined) throw new _MoneroError.default("Cannot provide seedOffset when creating wallet from keys"); + _MoneroNetworkType.default.validate(config.getNetworkType()); + if (config.getPrimaryAddress() === undefined) config.setPrimaryAddress(""); + if (config.getPrivateViewKey() === undefined) config.setPrivateViewKey(""); + if (config.getPrivateSpendKey() === undefined) config.setPrivateSpendKey(""); + if (config.getLanguage() === undefined) config.setLanguage("English"); + + // load wasm module + let module = await _LibraryUtils.default.loadWasmModule(); + + // queue call to wasm module + return module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // create wallet in wasm which invokes callback when done + module.create_keys_wallet_from_keys(JSON.stringify(config.toJson()), (cppAddress) => { + if (typeof cppAddress === "string") reject(new _MoneroError.default(cppAddress));else + resolve(new MoneroWalletKeys(cppAddress)); + }); + }); + }); + } + + static async getSeedLanguages() { + let module = await _LibraryUtils.default.loadWasmModule(); + return module.queueTask(async () => { + return JSON.parse(module.get_keys_wallet_seed_languages()).languages; + }); + } + + // --------------------------- INSTANCE METHODS ----------------------------- + + /** + * Internal constructor which is given the memory address of a C++ wallet + * instance. + * + * This method should not be called externally but should be called through + * static wallet creation utilities in this class. + * + * @param {number} cppAddress - address of the wallet instance in C++ + * @param {MoneroWalletKeysProxy} walletProxy - proxy + * + * @private + */ + constructor(cppAddress, walletProxy) { + super(); + if (!cppAddress && !walletProxy) throw new _MoneroError.default("Must provide cppAddress or walletProxy"); + if (walletProxy) this.walletProxy = walletProxy;else + { + this.cppAddress = cppAddress; + this.module = _LibraryUtils.default.getWasmModule(); + if (!this.module.create_full_wallet) throw new _MoneroError.default("WASM module not loaded - create wallet instance using static utilities"); // static utilites pre-load wasm module + } + } + + async isViewOnly() { + if (this.getWalletProxy()) return this.getWalletProxy().isViewOnly(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.is_view_only(this.cppAddress); + }); + } + + async isConnectedToDaemon() { + if (this.getWalletProxy()) return this.getWalletProxy().isConnectedToDaemon(); + return false; + } + + async getVersion() { + if (this.getWalletProxy()) return this.getWalletProxy().getVersion(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let versionStr = this.module.get_version(this.cppAddress); + let versionJson = JSON.parse(versionStr); + return new _MoneroVersion.default(versionJson.number, versionJson.isRelease); + }); + } + + /** + * @ignore + */ + getPath() { + throw new _MoneroError.default("MoneroWalletKeys does not support a persisted path"); + } + + async getSeed() { + if (this.getWalletProxy()) return this.getWalletProxy().getSeed(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_seed(this.cppAddress); + const errorStr = "error: "; + if (resp.indexOf(errorStr) === 0) throw new _MoneroError.default(resp.substring(errorStr.length)); + return resp ? resp : undefined; + }); + } + + async getSeedLanguage() { + if (this.getWalletProxy()) return this.getWalletProxy().getSeedLanguage(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_seed_language(this.cppAddress); + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) throw new _MoneroError.default(resp.substring(errorKey.length)); + return resp ? resp : undefined; + }); + } + + async getPrivateSpendKey() { + if (this.getWalletProxy()) return this.getWalletProxy().getPrivateSpendKey(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_private_spend_key(this.cppAddress); + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) throw new _MoneroError.default(resp.substring(errorKey.length)); + return resp ? resp : undefined; + }); + } + + async getPrivateViewKey() { + if (this.getWalletProxy()) return this.getWalletProxy().getPrivateViewKey(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_private_view_key(this.cppAddress); + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) throw new _MoneroError.default(resp.substring(errorKey.length)); + return resp ? resp : undefined; + }); + } + + async getPublicViewKey() { + if (this.getWalletProxy()) return this.getWalletProxy().getPublicViewKey(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_public_view_key(this.cppAddress); + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) throw new _MoneroError.default(resp.substring(errorKey.length)); + return resp ? resp : undefined; + }); + } + + async getPublicSpendKey() { + if (this.getWalletProxy()) return this.getWalletProxy().getPublicSpendKey(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_public_spend_key(this.cppAddress); + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) throw new _MoneroError.default(resp.substring(errorKey.length)); + return resp ? resp : undefined; + }); + } + + async getAddress(accountIdx, subaddressIdx) { + if (this.getWalletProxy()) return this.getWalletProxy().getAddress(accountIdx, subaddressIdx); + (0, _assert.default)(typeof accountIdx === "number"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.get_address(this.cppAddress, accountIdx, subaddressIdx); + }); + } + + async getAddressIndex(address) { + if (this.getWalletProxy()) return this.getWalletProxy().getAddressIndex(address); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_address_index(this.cppAddress, address); + if (resp.charAt(0) !== '{') throw new _MoneroError.default(resp); + return new _MoneroSubaddress.default(JSON.parse(resp)); + }); + } + + async getAccounts(includeSubaddresses, tag) { + if (this.getWalletProxy()) return this.getWalletProxy().getAccounts(); + throw new _MoneroError.default("MoneroWalletKeys does not support getting an enumerable set of accounts; query specific accounts"); + } + + // getIntegratedAddress(paymentId) // TODO + // decodeIntegratedAddress + + async close(save = false) { + if (this._isClosed) return; // no effect if closed + if (this.getWalletProxy()) { + await this.getWalletProxy().close(save); + await super.close(); + this._isClosed = true; + return; + } + + // save wallet if requested + if (save) await this.save(); + + // close super + await super.close(); + this._isClosed = true; + + // queue task to use wasm module + return this.module.queueTask(async () => { + return new Promise((resolve, reject) => { + if (this._isClosed) { + resolve(undefined); + return; + } + + // close wallet in wasm and invoke callback when done + this.module.close(this.cppAddress, false, async () => {// saving handled external to webassembly + delete this.cppAddress; + this._isClosed = true; + resolve(); + }); + }); + }); + } + + async isClosed() { + return this._isClosed; + } + + // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS -------------- + + async getPrimaryAddress() {return super.getPrimaryAddress();} + async getSubaddress(accountIdx, subaddressIdx) {return super.getSubaddress(accountIdx, subaddressIdx);} + + // ----------------------------- PRIVATE HELPERS ---------------------------- + + static sanitizeSubaddress(subaddress) { + if (subaddress.getLabel() === "") subaddress.setLabel(undefined); + return subaddress; + } + + assertNotClosed() { + if (this._isClosed) throw new _MoneroError.default("Wallet is closed"); + } + + getWalletProxy() { + this.assertNotClosed(); + return this.walletProxy; + } +} + +/** + * Implements a MoneroWallet by proxying requests to a worker which runs a keys-only wallet. + * + * TODO: sort these methods according to master sort in MoneroWallet.ts + * TODO: probably only allow one listener to worker then propogate to registered listeners for performance + * + * @private + */exports.MoneroWalletKeys = MoneroWalletKeys; +class MoneroWalletKeysProxy extends _MoneroWallet.default { + + // state variables + + + + // -------------------------- WALLET STATIC UTILS --------------------------- + + static async createWallet(config) { + let walletId = _GenUtils.default.getUUID(); + await _LibraryUtils.default.invokeWorker(walletId, "createWalletKeys", [config.toJson()]); + return new MoneroWalletKeysProxy(walletId, await _LibraryUtils.default.getWorker()); + } + + // --------------------------- INSTANCE METHODS ---------------------------- + + /** + * Internal constructor which is given a worker to communicate with via messages. + * + * This method should not be called externally but should be called through + * static wallet creation utilities in this class. + * + * @param {string} walletId - identifies the wallet with the worker + * @param {Worker} worker - worker to communicate with via messages + * + * @protected + */ + constructor(walletId, worker) { + super(); + this.walletId = walletId; + this.worker = worker; + } + + async isViewOnly() { + return this.invokeWorker("isViewOnly"); + } + + async getVersion() { + throw new _MoneroError.default("Not implemented"); + } + + async getSeed() { + return this.invokeWorker("getSeed"); + } + + async getSeedLanguage() { + return this.invokeWorker("getSeedLanguage"); + } + + async getSeedLanguages() { + return this.invokeWorker("getSeedLanguages"); + } + + async getPrivateSpendKey() { + return this.invokeWorker("getPrivateSpendKey"); + } + + async getPrivateViewKey() { + return this.invokeWorker("getPrivateViewKey"); + } + + async getPublicViewKey() { + return this.invokeWorker("getPublicViewKey"); + } + + async getPublicSpendKey() { + return this.invokeWorker("getPublicSpendKey"); + } + + async getAddress(accountIdx, subaddressIdx) { + return this.invokeWorker("getAddress", Array.from(arguments)); + } + + async getAddressIndex(address) { + let subaddressJson = await this.invokeWorker("getAddressIndex", Array.from(arguments)); + return MoneroWalletKeys.sanitizeSubaddress(new _MoneroSubaddress.default(subaddressJson)); + } + + async getIntegratedAddress(standardAddress, paymentId) { + return new _MoneroIntegratedAddress.default(await this.invokeWorker("getIntegratedAddress", Array.from(arguments))); + } + + async decodeIntegratedAddress(integratedAddress) { + return new _MoneroIntegratedAddress.default(await this.invokeWorker("decodeIntegratedAddress", Array.from(arguments))); + } + + async close(save) { + await this.invokeWorker("close", Array.from(arguments)); + _LibraryUtils.default.removeWorkerObject(this.walletId); + } + + async isClosed() { + return this.invokeWorker("isClosed"); + } + + async invokeWorker(fnName, args) { + return await _LibraryUtils.default.invokeWorker(this.walletId, fnName, args); + } +}exports.MoneroWalletKeysProxy = MoneroWalletKeysProxy; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTGlicmFyeVV0aWxzIiwiX01vbmVyb0Vycm9yIiwiX01vbmVyb0ludGVncmF0ZWRBZGRyZXNzIiwiX01vbmVyb05ldHdvcmtUeXBlIiwiX01vbmVyb1N1YmFkZHJlc3MiLCJfTW9uZXJvVmVyc2lvbiIsIl9Nb25lcm9XYWxsZXQiLCJfTW9uZXJvV2FsbGV0Q29uZmlnIiwiTW9uZXJvV2FsbGV0S2V5cyIsIk1vbmVyb1dhbGxldCIsImNyZWF0ZVdhbGxldCIsImNvbmZpZyIsInVuZGVmaW5lZCIsIk1vbmVyb0Vycm9yIiwiTW9uZXJvV2FsbGV0Q29uZmlnIiwiZ2V0U2VlZCIsImdldFByaW1hcnlBZGRyZXNzIiwiZ2V0UHJpdmF0ZVZpZXdLZXkiLCJnZXRQcml2YXRlU3BlbmRLZXkiLCJnZXROZXR3b3JrVHlwZSIsImdldFNhdmVDdXJyZW50IiwiZ2V0UHJveHlUb1dvcmtlciIsInNldFByb3h5VG9Xb3JrZXIiLCJ3YWxsZXRQcm94eSIsIk1vbmVyb1dhbGxldEtleXNQcm94eSIsImdldFNlcnZlciIsImNyZWF0ZVdhbGxldEZyb21TZWVkIiwiY3JlYXRlV2FsbGV0RnJvbUtleXMiLCJjcmVhdGVXYWxsZXRSYW5kb20iLCJjb3B5IiwiZ2V0U2VlZE9mZnNldCIsImdldFJlc3RvcmVIZWlnaHQiLCJNb25lcm9OZXR3b3JrVHlwZSIsInZhbGlkYXRlIiwiZ2V0TGFuZ3VhZ2UiLCJzZXRMYW5ndWFnZSIsIm1vZHVsZSIsIkxpYnJhcnlVdGlscyIsImxvYWRXYXNtTW9kdWxlIiwicXVldWVUYXNrIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJjcmVhdGVfa2V5c193YWxsZXRfcmFuZG9tIiwiSlNPTiIsInN0cmluZ2lmeSIsInRvSnNvbiIsImNwcEFkZHJlc3MiLCJFcnJvciIsInNldFNlZWRPZmZzZXQiLCJjcmVhdGVfa2V5c193YWxsZXRfZnJvbV9zZWVkIiwic2V0UHJpbWFyeUFkZHJlc3MiLCJzZXRQcml2YXRlVmlld0tleSIsInNldFByaXZhdGVTcGVuZEtleSIsImNyZWF0ZV9rZXlzX3dhbGxldF9mcm9tX2tleXMiLCJnZXRTZWVkTGFuZ3VhZ2VzIiwicGFyc2UiLCJnZXRfa2V5c193YWxsZXRfc2VlZF9sYW5ndWFnZXMiLCJsYW5ndWFnZXMiLCJjb25zdHJ1Y3RvciIsImdldFdhc21Nb2R1bGUiLCJjcmVhdGVfZnVsbF93YWxsZXQiLCJpc1ZpZXdPbmx5IiwiZ2V0V2FsbGV0UHJveHkiLCJhc3NlcnROb3RDbG9zZWQiLCJpc192aWV3X29ubHkiLCJpc0Nvbm5lY3RlZFRvRGFlbW9uIiwiZ2V0VmVyc2lvbiIsInZlcnNpb25TdHIiLCJnZXRfdmVyc2lvbiIsInZlcnNpb25Kc29uIiwiTW9uZXJvVmVyc2lvbiIsIm51bWJlciIsImlzUmVsZWFzZSIsImdldFBhdGgiLCJyZXNwIiwiZ2V0X3NlZWQiLCJlcnJvclN0ciIsImluZGV4T2YiLCJzdWJzdHJpbmciLCJsZW5ndGgiLCJnZXRTZWVkTGFuZ3VhZ2UiLCJnZXRfc2VlZF9sYW5ndWFnZSIsImVycm9yS2V5IiwiZ2V0X3ByaXZhdGVfc3BlbmRfa2V5IiwiZ2V0X3ByaXZhdGVfdmlld19rZXkiLCJnZXRQdWJsaWNWaWV3S2V5IiwiZ2V0X3B1YmxpY192aWV3X2tleSIsImdldFB1YmxpY1NwZW5kS2V5IiwiZ2V0X3B1YmxpY19zcGVuZF9rZXkiLCJnZXRBZGRyZXNzIiwiYWNjb3VudElkeCIsInN1YmFkZHJlc3NJZHgiLCJhc3NlcnQiLCJnZXRfYWRkcmVzcyIsImdldEFkZHJlc3NJbmRleCIsImFkZHJlc3MiLCJnZXRfYWRkcmVzc19pbmRleCIsImNoYXJBdCIsIk1vbmVyb1N1YmFkZHJlc3MiLCJnZXRBY2NvdW50cyIsImluY2x1ZGVTdWJhZGRyZXNzZXMiLCJ0YWciLCJjbG9zZSIsInNhdmUiLCJfaXNDbG9zZWQiLCJpc0Nsb3NlZCIsImdldFN1YmFkZHJlc3MiLCJzYW5pdGl6ZVN1YmFkZHJlc3MiLCJzdWJhZGRyZXNzIiwiZ2V0TGFiZWwiLCJzZXRMYWJlbCIsImV4cG9ydHMiLCJ3YWxsZXRJZCIsIkdlblV0aWxzIiwiZ2V0VVVJRCIsImludm9rZVdvcmtlciIsImdldFdvcmtlciIsIndvcmtlciIsIkFycmF5IiwiZnJvbSIsImFyZ3VtZW50cyIsInN1YmFkZHJlc3NKc29uIiwiZ2V0SW50ZWdyYXRlZEFkZHJlc3MiLCJzdGFuZGFyZEFkZHJlc3MiLCJwYXltZW50SWQiLCJNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcyIsImRlY29kZUludGVncmF0ZWRBZGRyZXNzIiwiaW50ZWdyYXRlZEFkZHJlc3MiLCJyZW1vdmVXb3JrZXJPYmplY3QiLCJmbk5hbWUiLCJhcmdzIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvd2FsbGV0L01vbmVyb1dhbGxldEtleXMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgR2VuVXRpbHMgZnJvbSBcIi4uL2NvbW1vbi9HZW5VdGlsc1wiO1xuaW1wb3J0IExpYnJhcnlVdGlscyBmcm9tIFwiLi4vY29tbW9uL0xpYnJhcnlVdGlsc1wiO1xuaW1wb3J0IE1vbmVyb0FjY291bnQgZnJvbSBcIi4vbW9kZWwvTW9uZXJvQWNjb3VudFwiO1xuaW1wb3J0IE1vbmVyb0Vycm9yIGZyb20gXCIuLi9jb21tb24vTW9uZXJvRXJyb3JcIjtcbmltcG9ydCBNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcyBmcm9tIFwiLi9tb2RlbC9Nb25lcm9JbnRlZ3JhdGVkQWRkcmVzc1wiO1xuaW1wb3J0IE1vbmVyb05ldHdvcmtUeXBlIGZyb20gXCIuLi9kYWVtb24vbW9kZWwvTW9uZXJvTmV0d29ya1R5cGVcIjtcbmltcG9ydCBNb25lcm9TdWJhZGRyZXNzIGZyb20gXCIuL21vZGVsL01vbmVyb1N1YmFkZHJlc3NcIjtcbmltcG9ydCBNb25lcm9WZXJzaW9uIGZyb20gXCIuLi9kYWVtb24vbW9kZWwvTW9uZXJvVmVyc2lvblwiO1xuaW1wb3J0IE1vbmVyb1dhbGxldCBmcm9tIFwiLi9Nb25lcm9XYWxsZXRcIjtcbmltcG9ydCBNb25lcm9XYWxsZXRDb25maWcgZnJvbSBcIi4vbW9kZWwvTW9uZXJvV2FsbGV0Q29uZmlnXCI7XG5pbXBvcnQgTW9uZXJvV2FsbGV0TGlzdGVuZXIgZnJvbSBcIi4vbW9kZWwvTW9uZXJvV2FsbGV0TGlzdGVuZXJcIjtcblxuLyoqXG4gKiBJbXBsZW1lbnRzIGEgTW9uZXJvV2FsbGV0IHdoaWNoIG9ubHkgbWFuYWdlcyBrZXlzIHVzaW5nIFdlYkFzc2VtYmx5LlxuICovXG5leHBvcnQgY2xhc3MgTW9uZXJvV2FsbGV0S2V5cyBleHRlbmRzIE1vbmVyb1dhbGxldCB7XG5cbiAgLy8gaW5zdGFuY2UgdmFyaWFibGVzXG4gIHByb3RlY3RlZCBjcHBBZGRyZXNzOiBzdHJpbmc7XG4gIHByb3RlY3RlZCBtb2R1bGU6IGFueTtcbiAgcHJvdGVjdGVkIHdhbGxldFByb3h5OiBNb25lcm9XYWxsZXRLZXlzUHJveHk7XG4gIFxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gU1RBVElDIFVUSUxJVElFUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICBcbiAgLyoqXG4gICAqIDxwPkNyZWF0ZSBhIHdhbGxldCB1c2luZyBXZWJBc3NlbWJseSBiaW5kaW5ncyB0byBtb25lcm8tcHJvamVjdC48L3A+XG4gICAqIFxuICAgKiA8cD5FeGFtcGxlOjwvcD5cbiAgICogXG4gICAqIDxjb2RlPlxuICAgKiBsZXQgd2FsbGV0ID0gYXdhaXQgTW9uZXJvV2FsbGV0S2V5cy5jcmVhdGVXYWxsZXQoezxicj5cbiAgICogJm5ic3A7Jm5ic3A7IHBhc3N3b3JkOiBcImFiYzEyM1wiLDxicj5cbiAgICogJm5ic3A7Jm5ic3A7IG5ldHdvcmtUeXBlOiBNb25lcm9OZXR3b3JrVHlwZS5TVEFHRU5FVCw8YnI+XG4gICAqICZuYnNwOyZuYnNwOyBzZWVkOiBcImNvZXhpc3QgaWdsb28gcGFtcGhsZXQgbGFnb29uLi4uXCI8YnI+XG4gICAqIH0pO1xuICAgKiA8L2NvZGU+XG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb1dhbGxldENvbmZpZ30gY29uZmlnIC0gTW9uZXJvV2FsbGV0Q29uZmlnIG9yIGVxdWl2YWxlbnQgY29uZmlnIG9iamVjdFxuICAgKiBAcGFyYW0ge3N0cmluZ3xudW1iZXJ9IGNvbmZpZy5uZXR3b3JrVHlwZSAtIG5ldHdvcmsgdHlwZSBvZiB0aGUgd2FsbGV0IHRvIGNyZWF0ZSAob25lIG9mIFwibWFpbm5ldFwiLCBcInRlc3RuZXRcIiwgXCJzdGFnZW5ldFwiIG9yIE1vbmVyb05ldHdvcmtUeXBlLk1BSU5ORVR8VEVTVE5FVHxTVEFHRU5FVClcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtjb25maWcuc2VlZF0gLSBzZWVkIG9mIHRoZSB3YWxsZXQgdG8gY3JlYXRlIChvcHRpb25hbCwgcmFuZG9tIHdhbGxldCBjcmVhdGVkIGlmIG5laXRoZXIgc2VlZCBub3Iga2V5cyBnaXZlbilcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtjb25maWcuc2VlZE9mZnNldF0gLSB0aGUgb2Zmc2V0IHVzZWQgdG8gZGVyaXZlIGEgbmV3IHNlZWQgZnJvbSB0aGUgZ2l2ZW4gc2VlZCB0byByZWNvdmVyIGEgc2VjcmV0IHdhbGxldCBmcm9tIHRoZSBzZWVkIHBocmFzZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2NvbmZpZy5wcmltYXJ5QWRkcmVzc10gLSBwcmltYXJ5IGFkZHJlc3Mgb2YgdGhlIHdhbGxldCB0byBjcmVhdGUgKG9ubHkgcHJvdmlkZSBpZiByZXN0b3JpbmcgZnJvbSBrZXlzKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2NvbmZpZy5wcml2YXRlVmlld0tleV0gLSBwcml2YXRlIHZpZXcga2V5IG9mIHRoZSB3YWxsZXQgdG8gY3JlYXRlIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtjb25maWcucHJpdmF0ZVNwZW5kS2V5XSAtIHByaXZhdGUgc3BlbmQga2V5IG9mIHRoZSB3YWxsZXQgdG8gY3JlYXRlIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtjb25maWcubGFuZ3VhZ2VdIC0gbGFuZ3VhZ2Ugb2YgdGhlIHdhbGxldCdzIHNlZWQgKGRlZmF1bHRzIHRvIFwiRW5nbGlzaFwiIG9yIGF1dG8tZGV0ZWN0ZWQpXG4gICAqIEByZXR1cm4ge01vbmVyb1dhbGxldEtleXN9IHRoZSBjcmVhdGVkIHdhbGxldFxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGNyZWF0ZVdhbGxldChjb25maWc6IFBhcnRpYWw8TW9uZXJvV2FsbGV0Q29uZmlnPikge1xuICAgIFxuICAgIC8vIG5vcm1hbGl6ZSBhbmQgdmFsaWRhdGUgY29uZmlnXG4gICAgaWYgKGNvbmZpZyA9PT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJNdXN0IHByb3ZpZGUgY29uZmlnIHRvIGNyZWF0ZSB3YWxsZXRcIik7XG4gICAgY29uZmlnID0gY29uZmlnIGluc3RhbmNlb2YgTW9uZXJvV2FsbGV0Q29uZmlnID8gY29uZmlnIDogbmV3IE1vbmVyb1dhbGxldENvbmZpZyhjb25maWcpO1xuICAgIGlmIChjb25maWcuZ2V0U2VlZCgpICE9PSB1bmRlZmluZWQgJiYgKGNvbmZpZy5nZXRQcmltYXJ5QWRkcmVzcygpICE9PSB1bmRlZmluZWQgfHwgY29uZmlnLmdldFByaXZhdGVWaWV3S2V5KCkgIT09IHVuZGVmaW5lZCB8fCBjb25maWcuZ2V0UHJpdmF0ZVNwZW5kS2V5KCkgIT09IHVuZGVmaW5lZCkpIHtcbiAgICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIldhbGxldCBtYXkgYmUgaW5pdGlhbGl6ZWQgd2l0aCBhIHNlZWQgb3Iga2V5cyBidXQgbm90IGJvdGhcIik7XG4gICAgfVxuICAgIGlmIChjb25maWcuZ2V0TmV0d29ya1R5cGUoKSA9PT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJNdXN0IHByb3ZpZGUgYSBuZXR3b3JrVHlwZTogJ21haW5uZXQnLCAndGVzdG5ldCcgb3IgJ3N0YWdlbmV0J1wiKTtcbiAgICBpZiAoY29uZmlnLmdldFNhdmVDdXJyZW50KCkgPT09IHRydWUpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBzYXZlIGN1cnJlbnQgd2FsbGV0IHdoZW4gY3JlYXRpbmcga2V5cy1vbmx5IHdhbGxldFwiKTtcblxuICAgIC8vIGluaXRpYWxpemUgcHJveGllZCB3YWxsZXQgaWYgY29uZmlndXJlZFxuICAgIGlmIChjb25maWcuZ2V0UHJveHlUb1dvcmtlcigpID09PSB1bmRlZmluZWQpIGNvbmZpZy5zZXRQcm94eVRvV29ya2VyKHRydWUpO1xuICAgIGlmIChjb25maWcuZ2V0UHJveHlUb1dvcmtlcigpKSB7XG4gICAgICBsZXQgd2FsbGV0UHJveHkgPSBhd2FpdCBNb25lcm9XYWxsZXRLZXlzUHJveHkuY3JlYXRlV2FsbGV0KGNvbmZpZyk7O1xuICAgICAgcmV0dXJuIG5ldyBNb25lcm9XYWxsZXRLZXlzKHVuZGVmaW5lZCwgd2FsbGV0UHJveHkpO1xuICAgIH1cblxuICAgIC8vIGRpc2FsbG93IHNlcnZlciBjb25uZWN0aW9uXG4gICAgaWYgKGNvbmZpZy5nZXRTZXJ2ZXIoKSAhPT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJDYW5ub3QgaW5pdGlhbGl6ZSBrZXlzIHdhbGxldCB3aXRoIHNlcnZlciBjb25uZWN0aW9uXCIpO1xuICAgIFxuICAgIC8vIGNyZWF0ZSB3YWxsZXRcbiAgICBpZiAoY29uZmlnLmdldFNlZWQoKSAhPT0gdW5kZWZpbmVkKSByZXR1cm4gTW9uZXJvV2FsbGV0S2V5cy5jcmVhdGVXYWxsZXRGcm9tU2VlZChjb25maWcpO1xuICAgIGVsc2UgaWYgKGNvbmZpZy5nZXRQcml2YXRlU3BlbmRLZXkoKSAhPT0gdW5kZWZpbmVkIHx8IGNvbmZpZy5nZXRQcmltYXJ5QWRkcmVzcygpICE9PSB1bmRlZmluZWQpIHJldHVybiBNb25lcm9XYWxsZXRLZXlzLmNyZWF0ZVdhbGxldEZyb21LZXlzKGNvbmZpZyk7XG4gICAgZWxzZSByZXR1cm4gTW9uZXJvV2FsbGV0S2V5cy5jcmVhdGVXYWxsZXRSYW5kb20oY29uZmlnKTtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIHN0YXRpYyBhc3luYyBjcmVhdGVXYWxsZXRSYW5kb20oY29uZmlnOiBQYXJ0aWFsPE1vbmVyb1dhbGxldENvbmZpZz4pIHtcblxuICAgIC8vIHZhbGlkYXRlIGFuZCBzYW5pdGl6ZSBwYXJhbXNcbiAgICBjb25maWcgPSBjb25maWcuY29weSgpO1xuICAgIGlmIChjb25maWcuZ2V0U2VlZE9mZnNldCgpICE9PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBwcm92aWRlIHNlZWRPZmZzZXQgd2hlbiBjcmVhdGluZyByYW5kb20gd2FsbGV0XCIpO1xuICAgIGlmIChjb25maWcuZ2V0UmVzdG9yZUhlaWdodCgpICE9PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBwcm92aWRlIHJlc3RvcmVIZWlnaHQgd2hlbiBjcmVhdGluZyByYW5kb20gd2FsbGV0XCIpO1xuICAgIE1vbmVyb05ldHdvcmtUeXBlLnZhbGlkYXRlKGNvbmZpZy5nZXROZXR3b3JrVHlwZSgpKTtcbiAgICBpZiAoY29uZmlnLmdldExhbmd1YWdlKCkgPT09IHVuZGVmaW5lZCkgY29uZmlnLnNldExhbmd1YWdlKFwiRW5nbGlzaFwiKTtcbiAgICBcbiAgICAvLyBsb2FkIHdhc20gbW9kdWxlXG4gICAgbGV0IG1vZHVsZSA9IGF3YWl0IExpYnJhcnlVdGlscy5sb2FkV2FzbU1vZHVsZSgpO1xuICAgIFxuICAgIC8vIHF1ZXVlIGNhbGwgdG8gd2FzbSBtb2R1bGVcbiAgICByZXR1cm4gbW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBcbiAgICAgICAgLy8gY3JlYXRlIHdhbGxldCBpbiB3YXNtIHdoaWNoIGludm9rZXMgY2FsbGJhY2sgd2hlbiBkb25lXG4gICAgICAgIG1vZHVsZS5jcmVhdGVfa2V5c193YWxsZXRfcmFuZG9tKEpTT04uc3RyaW5naWZ5KGNvbmZpZy50b0pzb24oKSksIChjcHBBZGRyZXNzKSA9PiB7XG4gICAgICAgICAgaWYgKHR5cGVvZiBjcHBBZGRyZXNzID09PSBcInN0cmluZ1wiKSByZWplY3QobmV3IE1vbmVyb0Vycm9yKGNwcEFkZHJlc3MpKTtcbiAgICAgICAgICBlbHNlIHJlc29sdmUobmV3IE1vbmVyb1dhbGxldEtleXMoY3BwQWRkcmVzcykpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGFzeW5jIGNyZWF0ZVdhbGxldEZyb21TZWVkKGNvbmZpZzogUGFydGlhbDxNb25lcm9XYWxsZXRDb25maWc+KSB7XG4gICAgXG4gICAgLy8gdmFsaWRhdGUgYW5kIHNhbml0aXplIHBhcmFtc1xuICAgIE1vbmVyb05ldHdvcmtUeXBlLnZhbGlkYXRlKGNvbmZpZy5nZXROZXR3b3JrVHlwZSgpKTtcbiAgICBpZiAoY29uZmlnLmdldFNlZWQoKSA9PT0gdW5kZWZpbmVkKSB0aHJvdyBFcnJvcihcIk11c3QgZGVmaW5lIHNlZWQgdG8gY3JlYXRlIHdhbGxldCBmcm9tXCIpO1xuICAgIGlmIChjb25maWcuZ2V0U2VlZE9mZnNldCgpID09PSB1bmRlZmluZWQpIGNvbmZpZy5zZXRTZWVkT2Zmc2V0KFwiXCIpO1xuICAgIGlmIChjb25maWcuZ2V0TGFuZ3VhZ2UoKSAhPT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJDYW5ub3QgcHJvdmlkZSBsYW5ndWFnZSB3aGVuIGNyZWF0aW5nIHdhbGxldCBmcm9tIHNlZWRcIik7XG4gICAgXG4gICAgLy8gbG9hZCB3YXNtIG1vZHVsZVxuICAgIGxldCBtb2R1bGUgPSBhd2FpdCBMaWJyYXJ5VXRpbHMubG9hZFdhc21Nb2R1bGUoKTtcbiAgICBcbiAgICAvLyBxdWV1ZSBjYWxsIHRvIHdhc20gbW9kdWxlXG4gICAgcmV0dXJuIG1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcblxuICAgICAgICAvLyBjcmVhdGUgd2FsbGV0IGluIHdhc20gd2hpY2ggaW52b2tlcyBjYWxsYmFjayB3aGVuIGRvbmVcbiAgICAgICAgbW9kdWxlLmNyZWF0ZV9rZXlzX3dhbGxldF9mcm9tX3NlZWQoSlNPTi5zdHJpbmdpZnkoY29uZmlnLnRvSnNvbigpKSwgKGNwcEFkZHJlc3MpID0+IHtcbiAgICAgICAgICBpZiAodHlwZW9mIGNwcEFkZHJlc3MgPT09IFwic3RyaW5nXCIpIHJlamVjdChuZXcgTW9uZXJvRXJyb3IoY3BwQWRkcmVzcykpO1xuICAgICAgICAgIGVsc2UgcmVzb2x2ZShuZXcgTW9uZXJvV2FsbGV0S2V5cyhjcHBBZGRyZXNzKSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgYXN5bmMgY3JlYXRlV2FsbGV0RnJvbUtleXMoY29uZmlnOiBQYXJ0aWFsPE1vbmVyb1dhbGxldENvbmZpZz4pIHtcbiAgICBcbiAgICAvLyB2YWxpZGF0ZSBhbmQgc2FuaXRpemUgcGFyYW1zXG4gICAgaWYgKGNvbmZpZy5nZXRTZWVkT2Zmc2V0KCkgIT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ2Fubm90IHByb3ZpZGUgc2VlZE9mZnNldCB3aGVuIGNyZWF0aW5nIHdhbGxldCBmcm9tIGtleXNcIik7XG4gICAgTW9uZXJvTmV0d29ya1R5cGUudmFsaWRhdGUoY29uZmlnLmdldE5ldHdvcmtUeXBlKCkpO1xuICAgIGlmIChjb25maWcuZ2V0UHJpbWFyeUFkZHJlc3MoKSA9PT0gdW5kZWZpbmVkKSBjb25maWcuc2V0UHJpbWFyeUFkZHJlc3MoXCJcIik7XG4gICAgaWYgKGNvbmZpZy5nZXRQcml2YXRlVmlld0tleSgpID09PSB1bmRlZmluZWQpIGNvbmZpZy5zZXRQcml2YXRlVmlld0tleShcIlwiKTtcbiAgICBpZiAoY29uZmlnLmdldFByaXZhdGVTcGVuZEtleSgpID09PSB1bmRlZmluZWQpIGNvbmZpZy5zZXRQcml2YXRlU3BlbmRLZXkoXCJcIik7XG4gICAgaWYgKGNvbmZpZy5nZXRMYW5ndWFnZSgpID09PSB1bmRlZmluZWQpIGNvbmZpZy5zZXRMYW5ndWFnZShcIkVuZ2xpc2hcIik7XG4gICAgXG4gICAgLy8gbG9hZCB3YXNtIG1vZHVsZVxuICAgIGxldCBtb2R1bGUgPSBhd2FpdCBMaWJyYXJ5VXRpbHMubG9hZFdhc21Nb2R1bGUoKTtcbiAgICBcbiAgICAvLyBxdWV1ZSBjYWxsIHRvIHdhc20gbW9kdWxlXG4gICAgcmV0dXJuIG1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgXG4gICAgICAgIC8vIGNyZWF0ZSB3YWxsZXQgaW4gd2FzbSB3aGljaCBpbnZva2VzIGNhbGxiYWNrIHdoZW4gZG9uZVxuICAgICAgICBtb2R1bGUuY3JlYXRlX2tleXNfd2FsbGV0X2Zyb21fa2V5cyhKU09OLnN0cmluZ2lmeShjb25maWcudG9Kc29uKCkpLCAoY3BwQWRkcmVzcykgPT4ge1xuICAgICAgICAgIGlmICh0eXBlb2YgY3BwQWRkcmVzcyA9PT0gXCJzdHJpbmdcIikgcmVqZWN0KG5ldyBNb25lcm9FcnJvcihjcHBBZGRyZXNzKSk7XG4gICAgICAgICAgZWxzZSByZXNvbHZlKG5ldyBNb25lcm9XYWxsZXRLZXlzKGNwcEFkZHJlc3MpKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBcbiAgc3RhdGljIGFzeW5jIGdldFNlZWRMYW5ndWFnZXMoKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIGxldCBtb2R1bGUgPSBhd2FpdCBMaWJyYXJ5VXRpbHMubG9hZFdhc21Nb2R1bGUoKTtcbiAgICByZXR1cm4gbW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICByZXR1cm4gSlNPTi5wYXJzZShtb2R1bGUuZ2V0X2tleXNfd2FsbGV0X3NlZWRfbGFuZ3VhZ2VzKCkpLmxhbmd1YWdlcztcbiAgICB9KTtcbiAgfVxuICBcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIElOU1RBTkNFIE1FVEhPRFMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgXG4gIC8qKlxuICAgKiBJbnRlcm5hbCBjb25zdHJ1Y3RvciB3aGljaCBpcyBnaXZlbiB0aGUgbWVtb3J5IGFkZHJlc3Mgb2YgYSBDKysgd2FsbGV0XG4gICAqIGluc3RhbmNlLlxuICAgKiBcbiAgICogVGhpcyBtZXRob2Qgc2hvdWxkIG5vdCBiZSBjYWxsZWQgZXh0ZXJuYWxseSBidXQgc2hvdWxkIGJlIGNhbGxlZCB0aHJvdWdoXG4gICAqIHN0YXRpYyB3YWxsZXQgY3JlYXRpb24gdXRpbGl0aWVzIGluIHRoaXMgY2xhc3MuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gY3BwQWRkcmVzcyAtIGFkZHJlc3Mgb2YgdGhlIHdhbGxldCBpbnN0YW5jZSBpbiBDKytcbiAgICogQHBhcmFtIHtNb25lcm9XYWxsZXRLZXlzUHJveHl9IHdhbGxldFByb3h5IC0gcHJveHlcbiAgICogXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBjb25zdHJ1Y3RvcihjcHBBZGRyZXNzLCB3YWxsZXRQcm94eT86IE1vbmVyb1dhbGxldEtleXNQcm94eSkge1xuICAgIHN1cGVyKCk7XG4gICAgaWYgKCFjcHBBZGRyZXNzICYmICF3YWxsZXRQcm94eSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTXVzdCBwcm92aWRlIGNwcEFkZHJlc3Mgb3Igd2FsbGV0UHJveHlcIik7XG4gICAgaWYgKHdhbGxldFByb3h5KSB0aGlzLndhbGxldFByb3h5ID0gd2FsbGV0UHJveHk7XG4gICAgZWxzZSB7XG4gICAgICB0aGlzLmNwcEFkZHJlc3MgPSBjcHBBZGRyZXNzO1xuICAgICAgdGhpcy5tb2R1bGUgPSBMaWJyYXJ5VXRpbHMuZ2V0V2FzbU1vZHVsZSgpO1xuICAgICAgaWYgKCF0aGlzLm1vZHVsZS5jcmVhdGVfZnVsbF93YWxsZXQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIldBU00gbW9kdWxlIG5vdCBsb2FkZWQgLSBjcmVhdGUgd2FsbGV0IGluc3RhbmNlIHVzaW5nIHN0YXRpYyB1dGlsaXRpZXNcIik7ICAvLyBzdGF0aWMgdXRpbGl0ZXMgcHJlLWxvYWQgd2FzbSBtb2R1bGVcbiAgICB9XG4gIH1cbiAgXG4gIGFzeW5jIGlzVmlld09ubHkoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5pc1ZpZXdPbmx5KCk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgcmV0dXJuIHRoaXMubW9kdWxlLmlzX3ZpZXdfb25seSh0aGlzLmNwcEFkZHJlc3MpO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBpc0Nvbm5lY3RlZFRvRGFlbW9uKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuaXNDb25uZWN0ZWRUb0RhZW1vbigpO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGFzeW5jIGdldFZlcnNpb24oKTogUHJvbWlzZTxNb25lcm9WZXJzaW9uPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRWZXJzaW9uKCk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgbGV0IHZlcnNpb25TdHIgPSB0aGlzLm1vZHVsZS5nZXRfdmVyc2lvbih0aGlzLmNwcEFkZHJlc3MpO1xuICAgICAgbGV0IHZlcnNpb25Kc29uID0gSlNPTi5wYXJzZSh2ZXJzaW9uU3RyKTtcbiAgICAgIHJldHVybiBuZXcgTW9uZXJvVmVyc2lvbih2ZXJzaW9uSnNvbi5udW1iZXIsIHZlcnNpb25Kc29uLmlzUmVsZWFzZSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAaWdub3JlXG4gICAqL1xuICBnZXRQYXRoKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTW9uZXJvV2FsbGV0S2V5cyBkb2VzIG5vdCBzdXBwb3J0IGEgcGVyc2lzdGVkIHBhdGhcIik7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFNlZWQoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldFNlZWQoKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICBsZXQgcmVzcCA9IHRoaXMubW9kdWxlLmdldF9zZWVkKHRoaXMuY3BwQWRkcmVzcyk7XG4gICAgICBjb25zdCBlcnJvclN0ciA9IFwiZXJyb3I6IFwiO1xuICAgICAgaWYgKHJlc3AuaW5kZXhPZihlcnJvclN0cikgPT09IDApIHRocm93IG5ldyBNb25lcm9FcnJvcihyZXNwLnN1YnN0cmluZyhlcnJvclN0ci5sZW5ndGgpKTtcbiAgICAgIHJldHVybiByZXNwID8gcmVzcCA6IHVuZGVmaW5lZDtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0U2VlZExhbmd1YWdlKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRTZWVkTGFuZ3VhZ2UoKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICBsZXQgcmVzcCA9IHRoaXMubW9kdWxlLmdldF9zZWVkX2xhbmd1YWdlKHRoaXMuY3BwQWRkcmVzcyk7XG4gICAgICBsZXQgZXJyb3JLZXkgPSBcImVycm9yOiBcIjtcbiAgICAgIGlmIChyZXNwLmluZGV4T2YoZXJyb3JLZXkpID09PSAwKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IocmVzcC5zdWJzdHJpbmcoZXJyb3JLZXkubGVuZ3RoKSk7XG4gICAgICByZXR1cm4gcmVzcCA/IHJlc3AgOiB1bmRlZmluZWQ7XG4gICAgfSk7XG4gIH1cblxuICBhc3luYyBnZXRQcml2YXRlU3BlbmRLZXkoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSByZXR1cm4gdGhpcy5nZXRXYWxsZXRQcm94eSgpLmdldFByaXZhdGVTcGVuZEtleSgpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIGxldCByZXNwID0gdGhpcy5tb2R1bGUuZ2V0X3ByaXZhdGVfc3BlbmRfa2V5KHRoaXMuY3BwQWRkcmVzcyk7XG4gICAgICBsZXQgZXJyb3JLZXkgPSBcImVycm9yOiBcIjtcbiAgICAgIGlmIChyZXNwLmluZGV4T2YoZXJyb3JLZXkpID09PSAwKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IocmVzcC5zdWJzdHJpbmcoZXJyb3JLZXkubGVuZ3RoKSk7XG4gICAgICByZXR1cm4gcmVzcCA/IHJlc3AgOiB1bmRlZmluZWQ7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFByaXZhdGVWaWV3S2V5KCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRQcml2YXRlVmlld0tleSgpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIGxldCByZXNwID0gdGhpcy5tb2R1bGUuZ2V0X3ByaXZhdGVfdmlld19rZXkodGhpcy5jcHBBZGRyZXNzKTtcbiAgICAgIGxldCBlcnJvcktleSA9IFwiZXJyb3I6IFwiO1xuICAgICAgaWYgKHJlc3AuaW5kZXhPZihlcnJvcktleSkgPT09IDApIHRocm93IG5ldyBNb25lcm9FcnJvcihyZXNwLnN1YnN0cmluZyhlcnJvcktleS5sZW5ndGgpKTtcbiAgICAgIHJldHVybiByZXNwID8gcmVzcCA6IHVuZGVmaW5lZDtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UHVibGljVmlld0tleSgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuZ2V0UHVibGljVmlld0tleSgpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIGxldCByZXNwID0gdGhpcy5tb2R1bGUuZ2V0X3B1YmxpY192aWV3X2tleSh0aGlzLmNwcEFkZHJlc3MpO1xuICAgICAgbGV0IGVycm9yS2V5ID0gXCJlcnJvcjogXCI7XG4gICAgICBpZiAocmVzcC5pbmRleE9mKGVycm9yS2V5KSA9PT0gMCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKHJlc3Auc3Vic3RyaW5nKGVycm9yS2V5Lmxlbmd0aCkpO1xuICAgICAgcmV0dXJuIHJlc3AgPyByZXNwIDogdW5kZWZpbmVkO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBnZXRQdWJsaWNTcGVuZEtleSgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuZ2V0UHVibGljU3BlbmRLZXkoKTtcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHRoaXMuYXNzZXJ0Tm90Q2xvc2VkKCk7XG4gICAgICBsZXQgcmVzcCA9IHRoaXMubW9kdWxlLmdldF9wdWJsaWNfc3BlbmRfa2V5KHRoaXMuY3BwQWRkcmVzcyk7XG4gICAgICBsZXQgZXJyb3JLZXkgPSBcImVycm9yOiBcIjtcbiAgICAgIGlmIChyZXNwLmluZGV4T2YoZXJyb3JLZXkpID09PSAwKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IocmVzcC5zdWJzdHJpbmcoZXJyb3JLZXkubGVuZ3RoKSk7XG4gICAgICByZXR1cm4gcmVzcCA/IHJlc3AgOiB1bmRlZmluZWQ7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEFkZHJlc3MoYWNjb3VudElkeDogbnVtYmVyLCBzdWJhZGRyZXNzSWR4OiBudW1iZXIpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGlmICh0aGlzLmdldFdhbGxldFByb3h5KCkpIHJldHVybiB0aGlzLmdldFdhbGxldFByb3h5KCkuZ2V0QWRkcmVzcyhhY2NvdW50SWR4LCBzdWJhZGRyZXNzSWR4KTtcbiAgICBhc3NlcnQodHlwZW9mIGFjY291bnRJZHggPT09IFwibnVtYmVyXCIpO1xuICAgIHJldHVybiB0aGlzLm1vZHVsZS5xdWV1ZVRhc2soYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICAgIHJldHVybiB0aGlzLm1vZHVsZS5nZXRfYWRkcmVzcyh0aGlzLmNwcEFkZHJlc3MsIGFjY291bnRJZHgsIHN1YmFkZHJlc3NJZHgpO1xuICAgIH0pO1xuICB9XG4gIFxuICBhc3luYyBnZXRBZGRyZXNzSW5kZXgoYWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9TdWJhZGRyZXNzPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRBZGRyZXNzSW5kZXgoYWRkcmVzcyk7XG4gICAgcmV0dXJuIHRoaXMubW9kdWxlLnF1ZXVlVGFzayhhc3luYyAoKSA9PiB7XG4gICAgICB0aGlzLmFzc2VydE5vdENsb3NlZCgpO1xuICAgICAgbGV0IHJlc3AgPSB0aGlzLm1vZHVsZS5nZXRfYWRkcmVzc19pbmRleCh0aGlzLmNwcEFkZHJlc3MsIGFkZHJlc3MpO1xuICAgICAgaWYgKHJlc3AuY2hhckF0KDApICE9PSAneycpIHRocm93IG5ldyBNb25lcm9FcnJvcihyZXNwKTtcbiAgICAgIHJldHVybiBuZXcgTW9uZXJvU3ViYWRkcmVzcyhKU09OLnBhcnNlKHJlc3ApKTtcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0QWNjb3VudHMoaW5jbHVkZVN1YmFkZHJlc3Nlcz86IGJvb2xlYW4sIHRhZz86IHN0cmluZyk6IFByb21pc2U8TW9uZXJvQWNjb3VudFtdPiB7XG4gICAgaWYgKHRoaXMuZ2V0V2FsbGV0UHJveHkoKSkgcmV0dXJuIHRoaXMuZ2V0V2FsbGV0UHJveHkoKS5nZXRBY2NvdW50cygpO1xuICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk1vbmVyb1dhbGxldEtleXMgZG9lcyBub3Qgc3VwcG9ydCBnZXR0aW5nIGFuIGVudW1lcmFibGUgc2V0IG9mIGFjY291bnRzOyBxdWVyeSBzcGVjaWZpYyBhY2NvdW50c1wiKTtcbiAgfVxuICBcbiAgLy8gZ2V0SW50ZWdyYXRlZEFkZHJlc3MocGF5bWVudElkKSAgLy8gVE9ET1xuICAvLyBkZWNvZGVJbnRlZ3JhdGVkQWRkcmVzc1xuICBcbiAgYXN5bmMgY2xvc2Uoc2F2ZSA9IGZhbHNlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuX2lzQ2xvc2VkKSByZXR1cm47IC8vIG5vIGVmZmVjdCBpZiBjbG9zZWRcbiAgICBpZiAodGhpcy5nZXRXYWxsZXRQcm94eSgpKSB7XG4gICAgICBhd2FpdCB0aGlzLmdldFdhbGxldFByb3h5KCkuY2xvc2Uoc2F2ZSk7XG4gICAgICBhd2FpdCBzdXBlci5jbG9zZSgpO1xuICAgICAgdGhpcy5faXNDbG9zZWQgPSB0cnVlO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBcbiAgICAvLyBzYXZlIHdhbGxldCBpZiByZXF1ZXN0ZWRcbiAgICBpZiAoc2F2ZSkgYXdhaXQgdGhpcy5zYXZlKCk7XG5cbiAgICAvLyBjbG9zZSBzdXBlclxuICAgIGF3YWl0IHN1cGVyLmNsb3NlKCk7XG4gICAgdGhpcy5faXNDbG9zZWQgPSB0cnVlO1xuXG4gICAgLy8gcXVldWUgdGFzayB0byB1c2Ugd2FzbSBtb2R1bGVcbiAgICByZXR1cm4gdGhpcy5tb2R1bGUucXVldWVUYXNrKGFzeW5jICgpID0+IHtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGlmICh0aGlzLl9pc0Nsb3NlZCkge1xuICAgICAgICAgIHJlc29sdmUodW5kZWZpbmVkKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIGNsb3NlIHdhbGxldCBpbiB3YXNtIGFuZCBpbnZva2UgY2FsbGJhY2sgd2hlbiBkb25lXG4gICAgICAgIHRoaXMubW9kdWxlLmNsb3NlKHRoaXMuY3BwQWRkcmVzcywgZmFsc2UsIGFzeW5jICgpID0+IHsgLy8gc2F2aW5nIGhhbmRsZWQgZXh0ZXJuYWwgdG8gd2ViYXNzZW1ibHlcbiAgICAgICAgICBkZWxldGUgdGhpcy5jcHBBZGRyZXNzO1xuICAgICAgICAgIHRoaXMuX2lzQ2xvc2VkID0gdHJ1ZTtcbiAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH1cbiAgXG4gIGFzeW5jIGlzQ2xvc2VkKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHJldHVybiB0aGlzLl9pc0Nsb3NlZDtcbiAgfVxuICBcbiAgLy8gLS0tLS0tLS0tLS0gQUREIEpTRE9DIEZPUiBTVVBQT1JURUQgREVGQVVMVCBJTVBMRU1FTlRBVElPTlMgLS0tLS0tLS0tLS0tLS1cbiAgXG4gIGFzeW5jIGdldFByaW1hcnlBZGRyZXNzKCk6IFByb21pc2U8c3RyaW5nPiB7IHJldHVybiBzdXBlci5nZXRQcmltYXJ5QWRkcmVzcygpOyB9XG4gIGFzeW5jIGdldFN1YmFkZHJlc3MoYWNjb3VudElkeDogbnVtYmVyLCBzdWJhZGRyZXNzSWR4OiBudW1iZXIpOiBQcm9taXNlPE1vbmVyb1N1YmFkZHJlc3M+IHsgcmV0dXJuIHN1cGVyLmdldFN1YmFkZHJlc3MoYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCk7IH1cbiAgXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIFBSSVZBVEUgSEVMUEVSUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgc3RhdGljIHNhbml0aXplU3ViYWRkcmVzcyhzdWJhZGRyZXNzKSB7XG4gICAgaWYgKHN1YmFkZHJlc3MuZ2V0TGFiZWwoKSA9PT0gXCJcIikgc3ViYWRkcmVzcy5zZXRMYWJlbCh1bmRlZmluZWQpO1xuICAgIHJldHVybiBzdWJhZGRyZXNzXG4gIH1cbiAgXG4gIHByb3RlY3RlZCBhc3NlcnROb3RDbG9zZWQoKSB7XG4gICAgaWYgKHRoaXMuX2lzQ2xvc2VkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJXYWxsZXQgaXMgY2xvc2VkXCIpO1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldFdhbGxldFByb3h5KCk6IE1vbmVyb1dhbGxldEtleXNQcm94eSB7XG4gICAgdGhpcy5hc3NlcnROb3RDbG9zZWQoKTtcbiAgICByZXR1cm4gdGhpcy53YWxsZXRQcm94eTtcbiAgfVxufVxuXG4vKipcbiAqIEltcGxlbWVudHMgYSBNb25lcm9XYWxsZXQgYnkgcHJveHlpbmcgcmVxdWVzdHMgdG8gYSB3b3JrZXIgd2hpY2ggcnVucyBhIGtleXMtb25seSB3YWxsZXQuXG4gKiBcbiAqIFRPRE86IHNvcnQgdGhlc2UgbWV0aG9kcyBhY2NvcmRpbmcgdG8gbWFzdGVyIHNvcnQgaW4gTW9uZXJvV2FsbGV0LnRzXG4gKiBUT0RPOiBwcm9iYWJseSBvbmx5IGFsbG93IG9uZSBsaXN0ZW5lciB0byB3b3JrZXIgdGhlbiBwcm9wb2dhdGUgdG8gcmVnaXN0ZXJlZCBsaXN0ZW5lcnMgZm9yIHBlcmZvcm1hbmNlXG4gKiBcbiAqIEBwcml2YXRlXG4gKi9cbmV4cG9ydCBjbGFzcyBNb25lcm9XYWxsZXRLZXlzUHJveHkgZXh0ZW5kcyBNb25lcm9XYWxsZXQge1xuXG4gIC8vIHN0YXRlIHZhcmlhYmxlc1xuICBwcm90ZWN0ZWQgd2FsbGV0SWQ6IHN0cmluZztcbiAgcHJvdGVjdGVkIHdvcmtlcjogV29ya2VyO1xuICBcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gV0FMTEVUIFNUQVRJQyBVVElMUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgXG4gIHN0YXRpYyBhc3luYyBjcmVhdGVXYWxsZXQoY29uZmlnKSB7XG4gICAgbGV0IHdhbGxldElkID0gR2VuVXRpbHMuZ2V0VVVJRCgpO1xuICAgIGF3YWl0IExpYnJhcnlVdGlscy5pbnZva2VXb3JrZXIod2FsbGV0SWQsIFwiY3JlYXRlV2FsbGV0S2V5c1wiLCBbY29uZmlnLnRvSnNvbigpXSk7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9XYWxsZXRLZXlzUHJveHkod2FsbGV0SWQsIGF3YWl0IExpYnJhcnlVdGlscy5nZXRXb3JrZXIoKSk7XG4gIH1cbiAgXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBJTlNUQU5DRSBNRVRIT0RTIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgXG4gIC8qKlxuICAgKiBJbnRlcm5hbCBjb25zdHJ1Y3RvciB3aGljaCBpcyBnaXZlbiBhIHdvcmtlciB0byBjb21tdW5pY2F0ZSB3aXRoIHZpYSBtZXNzYWdlcy5cbiAgICogXG4gICAqIFRoaXMgbWV0aG9kIHNob3VsZCBub3QgYmUgY2FsbGVkIGV4dGVybmFsbHkgYnV0IHNob3VsZCBiZSBjYWxsZWQgdGhyb3VnaFxuICAgKiBzdGF0aWMgd2FsbGV0IGNyZWF0aW9uIHV0aWxpdGllcyBpbiB0aGlzIGNsYXNzLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd9IHdhbGxldElkIC0gaWRlbnRpZmllcyB0aGUgd2FsbGV0IHdpdGggdGhlIHdvcmtlclxuICAgKiBAcGFyYW0ge1dvcmtlcn0gd29ya2VyIC0gd29ya2VyIHRvIGNvbW11bmljYXRlIHdpdGggdmlhIG1lc3NhZ2VzXG4gICAqIFxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih3YWxsZXRJZCwgd29ya2VyKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLndhbGxldElkID0gd2FsbGV0SWQ7XG4gICAgdGhpcy53b3JrZXIgPSB3b3JrZXI7XG4gIH1cbiAgXG4gIGFzeW5jIGlzVmlld09ubHkoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiaXNWaWV3T25seVwiKTtcbiAgfVxuXG4gIGFzeW5jIGdldFZlcnNpb24oKTogUHJvbWlzZTxNb25lcm9WZXJzaW9uPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTm90IGltcGxlbWVudGVkXCIpO1xuICB9XG5cbiAgYXN5bmMgZ2V0U2VlZCgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRTZWVkXCIpIGFzIFByb21pc2U8c3RyaW5nPjtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0U2VlZExhbmd1YWdlKCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImdldFNlZWRMYW5ndWFnZVwiKSBhcyBQcm9taXNlPHN0cmluZz47XG4gIH1cbiAgXG4gIGFzeW5jIGdldFNlZWRMYW5ndWFnZXMoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZ2V0U2VlZExhbmd1YWdlc1wiKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UHJpdmF0ZVNwZW5kS2V5KCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImdldFByaXZhdGVTcGVuZEtleVwiKSBhcyBQcm9taXNlPHN0cmluZz47XG4gIH1cbiAgXG4gIGFzeW5jIGdldFByaXZhdGVWaWV3S2V5KCkge1xuICAgIHJldHVybiB0aGlzLmludm9rZVdvcmtlcihcImdldFByaXZhdGVWaWV3S2V5XCIpIGFzIFByb21pc2U8c3RyaW5nPjtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UHVibGljVmlld0tleSgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRQdWJsaWNWaWV3S2V5XCIpIGFzIFByb21pc2U8c3RyaW5nPjtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UHVibGljU3BlbmRLZXkoKSB7XG4gICAgcmV0dXJuIHRoaXMuaW52b2tlV29ya2VyKFwiZ2V0UHVibGljU3BlbmRLZXlcIikgYXMgUHJvbWlzZTxzdHJpbmc+O1xuICB9XG4gIFxuICBhc3luYyBnZXRBZGRyZXNzKGFjY291bnRJZHgsIHN1YmFkZHJlc3NJZHgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJnZXRBZGRyZXNzXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSkgYXMgUHJvbWlzZTxzdHJpbmc+O1xuICB9XG5cbiAgYXN5bmMgZ2V0QWRkcmVzc0luZGV4KGFkZHJlc3MpIHtcbiAgICBsZXQgc3ViYWRkcmVzc0pzb24gPSBhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImdldEFkZHJlc3NJbmRleFwiLCBBcnJheS5mcm9tKGFyZ3VtZW50cykpO1xuICAgIHJldHVybiBNb25lcm9XYWxsZXRLZXlzLnNhbml0aXplU3ViYWRkcmVzcyhuZXcgTW9uZXJvU3ViYWRkcmVzcyhzdWJhZGRyZXNzSnNvbikpO1xuICB9XG5cbiAgYXN5bmMgZ2V0SW50ZWdyYXRlZEFkZHJlc3Moc3RhbmRhcmRBZGRyZXNzLCBwYXltZW50SWQpIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb0ludGVncmF0ZWRBZGRyZXNzKGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiZ2V0SW50ZWdyYXRlZEFkZHJlc3NcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKSk7XG4gIH1cbiAgXG4gIGFzeW5jIGRlY29kZUludGVncmF0ZWRBZGRyZXNzKGludGVncmF0ZWRBZGRyZXNzKSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcyhhd2FpdCB0aGlzLmludm9rZVdvcmtlcihcImRlY29kZUludGVncmF0ZWRBZGRyZXNzXCIsIEFycmF5LmZyb20oYXJndW1lbnRzKSkpO1xuICB9XG5cbiAgYXN5bmMgY2xvc2Uoc2F2ZSkge1xuICAgIGF3YWl0IHRoaXMuaW52b2tlV29ya2VyKFwiY2xvc2VcIiwgQXJyYXkuZnJvbShhcmd1bWVudHMpKTtcbiAgICBMaWJyYXJ5VXRpbHMucmVtb3ZlV29ya2VyT2JqZWN0KHRoaXMud2FsbGV0SWQpO1xuICB9XG4gIFxuICBhc3luYyBpc0Nsb3NlZCgpIHtcbiAgICByZXR1cm4gdGhpcy5pbnZva2VXb3JrZXIoXCJpc0Nsb3NlZFwiKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBpbnZva2VXb3JrZXIoZm5OYW1lOiBzdHJpbmcsIGFyZ3M/OiBhbnkpOiBQcm9taXNlPGFueT4ge1xuICAgIHJldHVybiBhd2FpdCBMaWJyYXJ5VXRpbHMuaW52b2tlV29ya2VyKHRoaXMud2FsbGV0SWQsIGZuTmFtZSwgYXJncyk7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6ImtPQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFNBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLGFBQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTs7QUFFQSxJQUFBRyxZQUFBLEdBQUFKLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBSSx3QkFBQSxHQUFBTCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUssa0JB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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/MoneroWalletRpc.d.ts b/dist/src/main/ts/wallet/MoneroWalletRpc.d.ts new file mode 100644 index 000000000..33fe16777 --- /dev/null +++ b/dist/src/main/ts/wallet/MoneroWalletRpc.d.ts @@ -0,0 +1,431 @@ +/// +import TaskLooper from "../common/TaskLooper"; +import MoneroAccount from "./model/MoneroAccount"; +import MoneroAccountTag from "./model/MoneroAccountTag"; +import MoneroAddressBookEntry from "./model/MoneroAddressBookEntry"; +import MoneroCheckReserve from "./model/MoneroCheckReserve"; +import MoneroCheckTx from "./model/MoneroCheckTx"; +import MoneroIncomingTransfer from "./model/MoneroIncomingTransfer"; +import MoneroIntegratedAddress from "./model/MoneroIntegratedAddress"; +import MoneroKeyImage from "../daemon/model/MoneroKeyImage"; +import MoneroKeyImageImportResult from "./model/MoneroKeyImageImportResult"; +import MoneroMultisigInfo from "./model/MoneroMultisigInfo"; +import MoneroMultisigInitResult from "./model/MoneroMultisigInitResult"; +import MoneroMultisigSignResult from "./model/MoneroMultisigSignResult"; +import MoneroOutgoingTransfer from "./model/MoneroOutgoingTransfer"; +import MoneroOutputQuery from "./model/MoneroOutputQuery"; +import MoneroOutputWallet from "./model/MoneroOutputWallet"; +import MoneroRpcConnection from "../common/MoneroRpcConnection"; +import MoneroSubaddress from "./model/MoneroSubaddress"; +import MoneroSyncResult from "./model/MoneroSyncResult"; +import MoneroTransfer from "./model/MoneroTransfer"; +import MoneroTransferQuery from "./model/MoneroTransferQuery"; +import MoneroTxConfig from "./model/MoneroTxConfig"; +import MoneroTxPriority from "./model/MoneroTxPriority"; +import MoneroTxQuery from "./model/MoneroTxQuery"; +import MoneroTxSet from "./model/MoneroTxSet"; +import MoneroTxWallet from "./model/MoneroTxWallet"; +import MoneroVersion from "../daemon/model/MoneroVersion"; +import MoneroWallet from "./MoneroWallet"; +import MoneroWalletConfig from "./model/MoneroWalletConfig"; +import MoneroWalletListener from "./model/MoneroWalletListener"; +import MoneroMessageSignatureType from "./model/MoneroMessageSignatureType"; +import MoneroMessageSignatureResult from "./model/MoneroMessageSignatureResult"; +import SslOptions from "../common/SslOptions"; +import { ChildProcess } from "child_process"; +/** + * Copyright (c) woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +/** + * Implements a MoneroWallet as a client of monero-wallet-rpc. + * + * @implements {MoneroWallet} + */ +export default class MoneroWalletRpc extends MoneroWallet { + protected static readonly DEFAULT_SYNC_PERIOD_IN_MS = 20000; + protected config: Partial; + protected addressCache: any; + protected syncPeriodInMs: number; + protected listeners: MoneroWalletListener[]; + protected process: any; + protected path: string; + protected daemonConnection: MoneroRpcConnection; + protected walletPoller: WalletPoller; + /** @private */ + constructor(config: MoneroWalletConfig); + /** + * Get the internal process running monero-wallet-rpc. + * + * @return {ChildProcess} the process running monero-wallet-rpc, undefined if not created from new process + */ + getProcess(): ChildProcess; + /** + * Stop the internal process running monero-wallet-rpc, if applicable. + * + * @param {boolean} force specifies if the process should be destroyed forcibly (default false) + * @return {Promise} the exit code from stopping the process + */ + stopProcess(force?: boolean): Promise; + /** + * Get the wallet's RPC connection. + * + * @return {MoneroRpcConnection | undefined} the wallet's rpc connection + */ + getRpcConnection(): MoneroRpcConnection | undefined; + /** + *

Open an existing wallet on the monero-wallet-rpc server.

+ * + *

Example:

+ * + * + * let wallet = new MoneroWalletRpc("http://localhost:38084", "rpc_user", "abc123");
+ * await wallet.openWallet("mywallet1", "supersecretpassword");
+ *
+ * await wallet.openWallet({
+ *    path: "mywallet2",
+ *    password: "supersecretpassword",
+ *    server: "http://locahost:38081", // or object with uri, username, password, etc
+ *    rejectUnauthorized: false
+ * });
+ *
+ * + * @param {string|MoneroWalletConfig} pathOrConfig - the wallet's name or configuration to open + * @param {string} pathOrConfig.path - path of the wallet to create (optional, in-memory wallet if not given) + * @param {string} pathOrConfig.password - password of the wallet to create + * @param {string|Partial} pathOrConfig.server - uri or MoneroRpcConnection of a daemon to use (optional, monero-wallet-rpc usually started with daemon config) + * @param {string} [password] the wallet's password + * @return {Promise} this wallet client + */ + openWallet(pathOrConfig: string | Partial, password?: string): Promise; + /** + *

Create and open a wallet on the monero-wallet-rpc server.

+ * + *

Example:

+ * + * + * // construct client to monero-wallet-rpc
+ * let walletRpc = new MoneroWalletRpc("http://localhost:38084", "rpc_user", "abc123");

+ * + * // create and open wallet on monero-wallet-rpc
+ * await walletRpc.createWallet({
+ *    path: "mywallet",
+ *    password: "abc123",
+ *    seed: "coexist igloo pamphlet lagoon...",
+ *    restoreHeight: 1543218l
+ * }); + *
+ * + * @param {Partial} config - MoneroWalletConfig or equivalent JS object + * @param {string} [config.path] - path of the wallet to create (optional, in-memory wallet if not given) + * @param {string} [config.password] - password of the wallet to create + * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given) + * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed + * @param {boolean} [config.isMultisig] - restore multisig wallet from seed + * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys) + * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional) + * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional) + * @param {number} [config.restoreHeight] - block height to start scanning from (defaults to 0 unless generating random wallet) + * @param {string} [config.language] - language of the wallet's mnemonic phrase or seed (defaults to "English" or auto-detected) + * @param {MoneroRpcConnection} [config.server] - MoneroRpcConnection to a monero daemon (optional)
+ * @param {string} [config.serverUri] - uri of a daemon to use (optional, monero-wallet-rpc usually started with daemon config) + * @param {string} [config.serverUsername] - username to authenticate with the daemon (optional) + * @param {string} [config.serverPassword] - password to authenticate with the daemon (optional) + * @param {MoneroConnectionManager} [config.connectionManager] - manage connections to monerod (optional) + * @param {boolean} [config.rejectUnauthorized] - reject self-signed server certificates if true (defaults to true) + * @param {MoneroRpcConnection} [config.server] - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional) + * @param {boolean} [config.saveCurrent] - specifies if the current RPC wallet should be saved before being closed (default true) + * @return {MoneroWalletRpc} this wallet client + */ + createWallet(config: Partial): Promise; + protected createWalletRandom(config: MoneroWalletConfig): Promise; + protected createWalletFromSeed(config: MoneroWalletConfig): Promise; + protected createWalletFromKeys(config: MoneroWalletConfig): Promise; + protected handleCreateWalletError(name: any, err: any): void; + isViewOnly(): Promise; + /** + * Set the wallet's daemon connection. + * + * @param {string|MoneroRpcConnection} [uriOrConnection] - the daemon's URI or connection (defaults to offline) + * @param {boolean} isTrusted - indicates if the daemon in trusted + * @param {SslOptions} sslOptions - custom SSL configuration + */ + setDaemonConnection(uriOrConnection?: MoneroRpcConnection | string, isTrusted?: boolean, sslOptions?: SslOptions): Promise; + getDaemonConnection(): Promise; + /** + * Get the total and unlocked balances in a single request. + * + * @param {number} [accountIdx] account index + * @param {number} [subaddressIdx] subaddress index + * @return {Promise} is the total and unlocked balances in an array, respectively + */ + getBalances(accountIdx?: number, subaddressIdx?: number): Promise; + addListener(listener: MoneroWalletListener): Promise; + removeListener(listener: any): Promise; + isConnectedToDaemon(): Promise; + getVersion(): Promise; + getPath(): Promise; + getSeed(): Promise; + getSeedLanguage(): Promise; + /** + * Get a list of available languages for the wallet's seed. + * + * @return {string[]} the available languages for the wallet's seed. + */ + getSeedLanguages(): Promise; + getPrivateViewKey(): Promise; + getPrivateSpendKey(): Promise; + getAddress(accountIdx: number, subaddressIdx: number): Promise; + getAddressIndex(address: string): Promise; + getIntegratedAddress(standardAddress?: string, paymentId?: string): Promise; + decodeIntegratedAddress(integratedAddress: string): Promise; + getHeight(): Promise; + getDaemonHeight(): Promise; + getHeightByDate(year: number, month: number, day: number): Promise; + sync(listenerOrStartHeight?: MoneroWalletListener | number, startHeight?: number): Promise; + startSyncing(syncPeriodInMs?: number): Promise; + getSyncPeriodInMs(): number; + stopSyncing(): Promise; + scanTxs(txHashes: string[]): Promise; + rescanSpent(): Promise; + rescanBlockchain(): Promise; + getBalance(accountIdx?: number, subaddressIdx?: number): Promise; + getUnlockedBalance(accountIdx?: number, subaddressIdx?: number): Promise; + getAccounts(includeSubaddresses?: boolean, tag?: string, skipBalances?: boolean): Promise; + getAccount(accountIdx: number, includeSubaddresses?: boolean, skipBalances?: boolean): Promise; + createAccount(label?: string): Promise; + getSubaddresses(accountIdx: number, subaddressIndices?: number[], skipBalances?: boolean): Promise; + getSubaddress(accountIdx: number, subaddressIdx: number, skipBalances?: boolean): Promise; + createSubaddress(accountIdx: number, label?: string): Promise; + setSubaddressLabel(accountIdx: number, subaddressIdx: number, label: string): Promise; + getTxs(query?: string[] | Partial): Promise; + getTransfers(query?: Partial): Promise; + getOutputs(query?: Partial): Promise; + exportOutputs(all?: boolean): Promise; + importOutputs(outputsHex: string): Promise; + exportKeyImages(all?: boolean): Promise; + importKeyImages(keyImages: MoneroKeyImage[]): Promise; + getNewKeyImagesFromLastImport(): Promise; + freezeOutput(keyImage: string): Promise; + thawOutput(keyImage: string): Promise; + isOutputFrozen(keyImage: string): Promise; + getDefaultFeePriority(): Promise; + createTxs(config: Partial): Promise; + sweepOutput(config: Partial): Promise; + sweepUnlocked(config: Partial): Promise; + sweepDust(relay?: boolean): Promise; + relayTxs(txsOrMetadatas: (MoneroTxWallet | string)[]): Promise; + describeTxSet(txSet: MoneroTxSet): Promise; + signTxs(unsignedTxHex: string): Promise; + submitTxs(signedTxHex: string): Promise; + signMessage(message: string, signatureType?: MoneroMessageSignatureType, accountIdx?: number, subaddressIdx?: number): Promise; + verifyMessage(message: string, address: string, signature: string): Promise; + getTxKey(txHash: string): Promise; + checkTxKey(txHash: string, txKey: string, address: string): Promise; + getTxProof(txHash: string, address: string, message?: string): Promise; + checkTxProof(txHash: string, address: string, message: string | undefined, signature: string): Promise; + getSpendProof(txHash: string, message?: string): Promise; + checkSpendProof(txHash: string, message: string | undefined, signature: string): Promise; + getReserveProofWallet(message?: string): Promise; + getReserveProofAccount(accountIdx: number, amount: bigint, message?: string): Promise; + checkReserveProof(address: string, message: string | undefined, signature: string): Promise; + getTxNotes(txHashes: string[]): Promise; + setTxNotes(txHashes: string[], notes: string[]): Promise; + getAddressBookEntries(entryIndices?: number[]): Promise; + addAddressBookEntry(address: string, description?: string): Promise; + editAddressBookEntry(index: number, setAddress: boolean, address: string | undefined, setDescription: boolean, description: string | undefined): Promise; + deleteAddressBookEntry(entryIdx: number): Promise; + tagAccounts(tag: any, accountIndices: any): Promise; + untagAccounts(accountIndices: number[]): Promise; + getAccountTags(): Promise; + setAccountTagLabel(tag: string, label: string): Promise; + getPaymentUri(config: MoneroTxConfig): Promise; + parsePaymentUri(uri: string): Promise; + getAttribute(key: string): Promise; + setAttribute(key: string, val: string): Promise; + startMining(numThreads: number, backgroundMining?: boolean, ignoreBattery?: boolean): Promise; + stopMining(): Promise; + isMultisigImportNeeded(): Promise; + getMultisigInfo(): Promise; + prepareMultisig(): Promise; + makeMultisig(multisigHexes: string[], threshold: number, password: string): Promise; + exchangeMultisigKeys(multisigHexes: string[], password: string): Promise; + exportMultisigHex(): Promise; + importMultisigHex(multisigHexes: string[]): Promise; + signMultisigTxHex(multisigTxHex: string): Promise; + submitMultisigTxHex(signedMultisigTxHex: string): Promise; + changePassword(oldPassword: string, newPassword: string): Promise; + save(): Promise; + close(save?: boolean): Promise; + isClosed(): Promise; + /** + * Save and close the current wallet and stop the RPC server. + * + * @return {Promise} + */ + stop(): Promise; + getNumBlocksToUnlock(): Promise; + getTx(txHash: string): Promise; + getIncomingTransfers(query: Partial): Promise; + getOutgoingTransfers(query: Partial): Promise; + createTx(config: Partial): Promise; + relayTx(txOrMetadata: MoneroTxWallet | string): Promise; + getTxNote(txHash: string): Promise; + setTxNote(txHash: string, note: string): Promise; + static connectToWalletRpc(uriOrConfig: string | Partial | Partial | string[], username?: string, password?: string): Promise; + protected static startWalletRpcProcess(config: Partial): Promise; + protected clear(): Promise; + protected getAccountIndices(getSubaddressIndices?: any): Promise>; + protected getSubaddressIndices(accountIdx: any): Promise; + protected getTransfersAux(query: MoneroTransferQuery): Promise; + protected getOutputsAux(query: any): Promise; + /** + * Common method to get key images. + * + * @param all - pecifies to get all xor only new images from last import + * @return {MoneroKeyImage[]} are the key images + */ + protected rpcExportKeyImages(all: any): Promise; + protected rpcSweepAccount(config: MoneroTxConfig): Promise; + protected refreshListening(): void; + /** + * Poll if listening. + */ + protected poll(): Promise; + protected static normalizeConfig(uriOrConfig: string | Partial | Partial | string[], username?: string, password?: string): MoneroWalletConfig; + /** + * Remove criteria which requires looking up other transfers/outputs to + * fulfill query. + * + * @param {MoneroTxQuery} query - the query to decontextualize + * @return {MoneroTxQuery} a reference to the query for convenience + */ + protected static decontextualize(query: any): any; + protected static isContextual(query: any): boolean; + protected static convertRpcAccount(rpcAccount: any): MoneroAccount; + protected static convertRpcSubaddress(rpcSubaddress: any): MoneroSubaddress; + /** + * Initializes a sent transaction. + * + * TODO: remove copyDestinations after >18.3.1 when subtractFeeFrom fully supported + * + * @param {MoneroTxConfig} config - send config + * @param {MoneroTxWallet} [tx] - existing transaction to initialize (optional) + * @param {boolean} copyDestinations - copies config destinations if true + * @return {MoneroTxWallet} is the initialized send tx + */ + protected static initSentTxWallet(config: Partial, tx: any, copyDestinations: any): any; + /** + * Initializes a tx set from a RPC map excluding txs. + * + * @param rpcMap - map to initialize the tx set from + * @return MoneroTxSet - initialized tx set + * @return the resulting tx set + */ + protected static convertRpcTxSet(rpcMap: any): MoneroTxSet; + /** + * Initializes a MoneroTxSet from a list of rpc txs. + * + * @param rpcTxs - rpc txs to initialize the set from + * @param txs - existing txs to further initialize (optional) + * @param config - tx config + * @return the converted tx set + */ + protected static convertRpcSentTxsToTxSet(rpcTxs: any, txs?: any, config?: any): MoneroTxSet; + /** + * Converts a rpc tx with a transfer to a tx set with a tx and transfer. + * + * @param rpcTx - rpc tx to build from + * @param tx - existing tx to continue initializing (optional) + * @param isOutgoing - specifies if the tx is outgoing if true, incoming if false, or decodes from type if undefined + * @param config - tx config + * @return the initialized tx set with a tx + */ + protected static convertRpcTxToTxSet(rpcTx: any, tx: any, isOutgoing: any, config: any): MoneroTxSet; + /** + * Builds a MoneroTxWallet from a RPC tx. + * + * @param rpcTx - rpc tx to build from + * @param tx - existing tx to continue initializing (optional) + * @param isOutgoing - specifies if the tx is outgoing if true, incoming if false, or decodes from type if undefined + * @param config - tx config + * @return {MoneroTxWallet} is the initialized tx + */ + protected static convertRpcTxWithTransfer(rpcTx: any, tx?: any, isOutgoing?: any, config?: any): any; + protected static convertRpcTxWalletWithOutput(rpcOutput: any): MoneroTxWallet; + protected static convertRpcDescribeTransfer(rpcDescribeTransferResult: any): MoneroTxSet; + /** + * Decodes a "type" from monero-wallet-rpc to initialize type and state + * fields in the given transaction. + * + * TODO: these should be safe set + * + * @param rpcType is the type to decode + * @param tx is the transaction to decode known fields to + * @return {boolean} true if the rpc type indicates outgoing xor incoming + */ + protected static decodeRpcType(rpcType: any, tx: any): any; + /** + * Merges a transaction into a unique set of transactions. + * + * @param {MoneroTxWallet} tx - the transaction to merge into the existing txs + * @param {Object} txMap - maps tx hashes to txs + * @param {Object} blockMap - maps block heights to blocks + */ + protected static mergeTx(tx: any, txMap: any, blockMap: any): void; + /** + * Compares two transactions by their height. + */ + protected static compareTxsByHeight(tx1: any, tx2: any): number; + /** + * Compares two transfers by ascending account and subaddress indices. + */ + static compareIncomingTransfers(t1: any, t2: any): number; + /** + * Compares two outputs by ascending account and subaddress indices. + */ + protected static compareOutputs(o1: any, o2: any): any; +} +/** + * Polls monero-wallet-rpc to provide listener notifications. + * + * @private + */ +declare class WalletPoller { + isPolling: boolean; + protected wallet: MoneroWalletRpc; + protected looper: TaskLooper; + protected prevLockedTxs: any; + protected prevUnconfirmedNotifications: any; + protected prevConfirmedNotifications: any; + protected threadPool: any; + protected numPolling: any; + protected prevHeight: any; + protected prevBalances: any; + constructor(wallet: any); + setIsPolling(isPolling: any): void; + setPeriodInMs(periodInMs: any): void; + poll(): Promise; + protected onNewBlock(height: any): Promise; + protected notifyOutputs(tx: any): Promise; + protected getTx(txs: any, txHash: any): any; + protected checkForChangedBalances(): Promise; +} +export {}; diff --git a/dist/src/main/ts/wallet/MoneroWalletRpc.js b/dist/src/main/ts/wallet/MoneroWalletRpc.js new file mode 100644 index 000000000..17d2bf3b5 --- /dev/null +++ b/dist/src/main/ts/wallet/MoneroWalletRpc.js @@ -0,0 +1,2584 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../common/GenUtils")); +var _LibraryUtils = _interopRequireDefault(require("../common/LibraryUtils")); +var _TaskLooper = _interopRequireDefault(require("../common/TaskLooper")); +var _MoneroAccount = _interopRequireDefault(require("./model/MoneroAccount")); +var _MoneroAccountTag = _interopRequireDefault(require("./model/MoneroAccountTag")); +var _MoneroAddressBookEntry = _interopRequireDefault(require("./model/MoneroAddressBookEntry")); +var _MoneroBlock = _interopRequireDefault(require("../daemon/model/MoneroBlock")); +var _MoneroBlockHeader = _interopRequireDefault(require("../daemon/model/MoneroBlockHeader")); +var _MoneroCheckReserve = _interopRequireDefault(require("./model/MoneroCheckReserve")); +var _MoneroCheckTx = _interopRequireDefault(require("./model/MoneroCheckTx")); +var _MoneroDestination = _interopRequireDefault(require("./model/MoneroDestination")); +var _MoneroError = _interopRequireDefault(require("../common/MoneroError")); +var _MoneroIncomingTransfer = _interopRequireDefault(require("./model/MoneroIncomingTransfer")); +var _MoneroIntegratedAddress = _interopRequireDefault(require("./model/MoneroIntegratedAddress")); +var _MoneroKeyImage = _interopRequireDefault(require("../daemon/model/MoneroKeyImage")); +var _MoneroKeyImageImportResult = _interopRequireDefault(require("./model/MoneroKeyImageImportResult")); +var _MoneroMultisigInfo = _interopRequireDefault(require("./model/MoneroMultisigInfo")); +var _MoneroMultisigInitResult = _interopRequireDefault(require("./model/MoneroMultisigInitResult")); +var _MoneroMultisigSignResult = _interopRequireDefault(require("./model/MoneroMultisigSignResult")); +var _MoneroOutgoingTransfer = _interopRequireDefault(require("./model/MoneroOutgoingTransfer")); +var _MoneroOutputQuery = _interopRequireDefault(require("./model/MoneroOutputQuery")); +var _MoneroOutputWallet = _interopRequireDefault(require("./model/MoneroOutputWallet")); +var _MoneroRpcConnection = _interopRequireDefault(require("../common/MoneroRpcConnection")); +var _MoneroRpcError = _interopRequireDefault(require("../common/MoneroRpcError")); +var _MoneroSubaddress = _interopRequireDefault(require("./model/MoneroSubaddress")); +var _MoneroSyncResult = _interopRequireDefault(require("./model/MoneroSyncResult")); + +var _MoneroTransferQuery = _interopRequireDefault(require("./model/MoneroTransferQuery")); + +var _MoneroTxConfig = _interopRequireDefault(require("./model/MoneroTxConfig")); + +var _MoneroTxQuery = _interopRequireDefault(require("./model/MoneroTxQuery")); +var _MoneroTxSet = _interopRequireDefault(require("./model/MoneroTxSet")); +var _MoneroTxWallet = _interopRequireDefault(require("./model/MoneroTxWallet")); +var _MoneroUtils = _interopRequireDefault(require("../common/MoneroUtils")); +var _MoneroVersion = _interopRequireDefault(require("../daemon/model/MoneroVersion")); +var _MoneroWallet = _interopRequireDefault(require("./MoneroWallet")); +var _MoneroWalletConfig = _interopRequireDefault(require("./model/MoneroWalletConfig")); +var _MoneroWalletListener = _interopRequireDefault(require("./model/MoneroWalletListener")); +var _MoneroMessageSignatureType = _interopRequireDefault(require("./model/MoneroMessageSignatureType")); +var _MoneroMessageSignatureResult = _interopRequireDefault(require("./model/MoneroMessageSignatureResult")); +var _ThreadPool = _interopRequireDefault(require("../common/ThreadPool")); +var _SslOptions = _interopRequireDefault(require("../common/SslOptions"));function _getRequireWildcardCache(nodeInterop) {if (typeof WeakMap !== "function") return null;var cacheBabelInterop = new WeakMap();var cacheNodeInterop = new WeakMap();return (_getRequireWildcardCache = function (nodeInterop) {return nodeInterop ? cacheNodeInterop : cacheBabelInterop;})(nodeInterop);}function _interopRequireWildcard(obj, nodeInterop) {if (!nodeInterop && obj && obj.__esModule) {return obj;}if (obj === null || typeof obj !== "object" && typeof obj !== "function") {return { default: obj };}var cache = _getRequireWildcardCache(nodeInterop);if (cache && cache.has(obj)) {return cache.get(obj);}var newObj = {};var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;for (var key in obj) {if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;if (desc && (desc.get || desc.set)) {Object.defineProperty(newObj, key, desc);} else {newObj[key] = obj[key];}}}newObj.default = obj;if (cache) {cache.set(obj, newObj);}return newObj;} + + +/** + * Copyright (c) woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Implements a MoneroWallet as a client of monero-wallet-rpc. + * + * @implements {MoneroWallet} + */ +class MoneroWalletRpc extends _MoneroWallet.default { + + // static variables + static DEFAULT_SYNC_PERIOD_IN_MS = 20000; // default period between syncs in ms (defined by DEFAULT_AUTO_REFRESH_PERIOD in wallet_rpc_server.cpp) + + // instance variables + + + + + + + + + + /** @private */ + constructor(config) { + super(); + this.config = config; + this.addressCache = {}; // avoid unecessary requests for addresses + this.syncPeriodInMs = MoneroWalletRpc.DEFAULT_SYNC_PERIOD_IN_MS; + } + + // --------------------------- RPC WALLET METHODS --------------------------- + + /** + * Get the internal process running monero-wallet-rpc. + * + * @return {ChildProcess} the process running monero-wallet-rpc, undefined if not created from new process + */ + getProcess() { + return this.process; + } + + /** + * Stop the internal process running monero-wallet-rpc, if applicable. + * + * @param {boolean} force specifies if the process should be destroyed forcibly (default false) + * @return {Promise} the exit code from stopping the process + */ + async stopProcess(force = false) { + if (this.process === undefined) throw new _MoneroError.default("MoneroWalletRpc instance not created from new process"); + let listenersCopy = _GenUtils.default.copyArray(this.getListeners()); + for (let listener of listenersCopy) await this.removeListener(listener); + return _GenUtils.default.killProcess(this.process, force ? "SIGKILL" : undefined); + } + + /** + * Get the wallet's RPC connection. + * + * @return {MoneroRpcConnection | undefined} the wallet's rpc connection + */ + getRpcConnection() { + return this.config.getServer(); + } + + /** + *

Open an existing wallet on the monero-wallet-rpc server.

+ * + *

Example:

+ * + * + * let wallet = new MoneroWalletRpc("http://localhost:38084", "rpc_user", "abc123");
+ * await wallet.openWallet("mywallet1", "supersecretpassword");
+ *
+ * await wallet.openWallet({
+ *    path: "mywallet2",
+ *    password: "supersecretpassword",
+ *    server: "http://locahost:38081", // or object with uri, username, password, etc
+ *    rejectUnauthorized: false
+ * });
+ *
+ * + * @param {string|MoneroWalletConfig} pathOrConfig - the wallet's name or configuration to open + * @param {string} pathOrConfig.path - path of the wallet to create (optional, in-memory wallet if not given) + * @param {string} pathOrConfig.password - password of the wallet to create + * @param {string|Partial} pathOrConfig.server - uri or MoneroRpcConnection of a daemon to use (optional, monero-wallet-rpc usually started with daemon config) + * @param {string} [password] the wallet's password + * @return {Promise} this wallet client + */ + async openWallet(pathOrConfig, password) { + + // normalize and validate config + let config = new _MoneroWalletConfig.default(typeof pathOrConfig === "string" ? { path: pathOrConfig, password: password ? password : "" } : pathOrConfig); + // TODO: ensure other fields uninitialized? + + // open wallet on rpc server + if (!config.getPath()) throw new _MoneroError.default("Must provide name of wallet to open"); + await this.config.getServer().sendJsonRequest("open_wallet", { filename: config.getPath(), password: config.getPassword() }); + await this.clear(); + this.path = config.getPath(); + + // set connection manager or server + if (config.getConnectionManager() != null) { + if (config.getServer()) throw new _MoneroError.default("Wallet can be opened with a server or connection manager but not both"); + await this.setConnectionManager(config.getConnectionManager()); + } else if (config.getServer() != null) { + await this.setDaemonConnection(config.getServer()); + } + + return this; + } + + /** + *

Create and open a wallet on the monero-wallet-rpc server.

+ * + *

Example:

+ * + * + * // construct client to monero-wallet-rpc
+ * let walletRpc = new MoneroWalletRpc("http://localhost:38084", "rpc_user", "abc123");

+ * + * // create and open wallet on monero-wallet-rpc
+ * await walletRpc.createWallet({
+ *    path: "mywallet",
+ *    password: "abc123",
+ *    seed: "coexist igloo pamphlet lagoon...",
+ *    restoreHeight: 1543218l
+ * }); + *
+ * + * @param {Partial} config - MoneroWalletConfig or equivalent JS object + * @param {string} [config.path] - path of the wallet to create (optional, in-memory wallet if not given) + * @param {string} [config.password] - password of the wallet to create + * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given) + * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed + * @param {boolean} [config.isMultisig] - restore multisig wallet from seed + * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys) + * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional) + * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional) + * @param {number} [config.restoreHeight] - block height to start scanning from (defaults to 0 unless generating random wallet) + * @param {string} [config.language] - language of the wallet's mnemonic phrase or seed (defaults to "English" or auto-detected) + * @param {MoneroRpcConnection} [config.server] - MoneroRpcConnection to a monero daemon (optional)
+ * @param {string} [config.serverUri] - uri of a daemon to use (optional, monero-wallet-rpc usually started with daemon config) + * @param {string} [config.serverUsername] - username to authenticate with the daemon (optional) + * @param {string} [config.serverPassword] - password to authenticate with the daemon (optional) + * @param {MoneroConnectionManager} [config.connectionManager] - manage connections to monerod (optional) + * @param {boolean} [config.rejectUnauthorized] - reject self-signed server certificates if true (defaults to true) + * @param {MoneroRpcConnection} [config.server] - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional) + * @param {boolean} [config.saveCurrent] - specifies if the current RPC wallet should be saved before being closed (default true) + * @return {MoneroWalletRpc} this wallet client + */ + async createWallet(config) { + + // normalize and validate config + if (config === undefined) throw new _MoneroError.default("Must provide config to create wallet"); + const configNormalized = new _MoneroWalletConfig.default(config); + if (configNormalized.getSeed() !== undefined && (configNormalized.getPrimaryAddress() !== undefined || configNormalized.getPrivateViewKey() !== undefined || configNormalized.getPrivateSpendKey() !== undefined)) { + throw new _MoneroError.default("Wallet can be initialized with a seed or keys but not both"); + } + if (configNormalized.getNetworkType() !== undefined) throw new _MoneroError.default("Cannot provide networkType when creating RPC wallet because server's network type is already set"); + if (configNormalized.getAccountLookahead() !== undefined || configNormalized.getSubaddressLookahead() !== undefined) throw new _MoneroError.default("monero-wallet-rpc does not support creating wallets with subaddress lookahead over rpc"); + if (configNormalized.getPassword() === undefined) configNormalized.setPassword(""); + + // set server from connection manager if provided + if (configNormalized.getConnectionManager()) { + if (configNormalized.getServer()) throw new _MoneroError.default("Wallet can be created with a server or connection manager but not both"); + configNormalized.setServer(config.getConnectionManager().getConnection()); + } + + // create wallet + if (configNormalized.getSeed() !== undefined) await this.createWalletFromSeed(configNormalized);else + if (configNormalized.getPrivateSpendKey() !== undefined || configNormalized.getPrimaryAddress() !== undefined) await this.createWalletFromKeys(configNormalized);else + await this.createWalletRandom(configNormalized); + + // set connection manager or server + if (configNormalized.getConnectionManager()) { + await this.setConnectionManager(configNormalized.getConnectionManager()); + } else if (configNormalized.getServer()) { + await this.setDaemonConnection(configNormalized.getServer()); + } + + return this; + } + + async createWalletRandom(config) { + if (config.getSeedOffset() !== undefined) throw new _MoneroError.default("Cannot provide seedOffset when creating random wallet"); + if (config.getRestoreHeight() !== undefined) throw new _MoneroError.default("Cannot provide restoreHeight when creating random wallet"); + if (config.getSaveCurrent() === false) throw new _MoneroError.default("Current wallet is saved automatically when creating random wallet"); + if (!config.getPath()) throw new _MoneroError.default("Name is not initialized"); + if (!config.getLanguage()) config.setLanguage(_MoneroWallet.default.DEFAULT_LANGUAGE); + let params = { filename: config.getPath(), password: config.getPassword(), language: config.getLanguage() }; + try { + await this.config.getServer().sendJsonRequest("create_wallet", params); + } catch (err) { + this.handleCreateWalletError(config.getPath(), err); + } + await this.clear(); + this.path = config.getPath(); + return this; + } + + async createWalletFromSeed(config) { + try { + await this.config.getServer().sendJsonRequest("restore_deterministic_wallet", { + filename: config.getPath(), + password: config.getPassword(), + seed: config.getSeed(), + seed_offset: config.getSeedOffset(), + enable_multisig_experimental: config.getIsMultisig(), + restore_height: config.getRestoreHeight(), + language: config.getLanguage(), + autosave_current: config.getSaveCurrent() + }); + } catch (err) { + this.handleCreateWalletError(config.getPath(), err); + } + await this.clear(); + this.path = config.getPath(); + return this; + } + + async createWalletFromKeys(config) { + if (config.getSeedOffset() !== undefined) throw new _MoneroError.default("Cannot provide seedOffset when creating wallet from keys"); + if (config.getRestoreHeight() === undefined) config.setRestoreHeight(0); + if (config.getLanguage() === undefined) config.setLanguage(_MoneroWallet.default.DEFAULT_LANGUAGE); + try { + await this.config.getServer().sendJsonRequest("generate_from_keys", { + filename: config.getPath(), + password: config.getPassword(), + address: config.getPrimaryAddress(), + viewkey: config.getPrivateViewKey(), + spendkey: config.getPrivateSpendKey(), + restore_height: config.getRestoreHeight(), + autosave_current: config.getSaveCurrent() + }); + } catch (err) { + this.handleCreateWalletError(config.getPath(), err); + } + await this.clear(); + this.path = config.getPath(); + return this; + } + + handleCreateWalletError(name, err) { + if (err.message) { + if (err.message.toLowerCase().includes("already exists")) throw new _MoneroRpcError.default("Wallet already exists: " + name, err.getCode(), err.getRpcMethod(), err.getRpcParams()); + if (err.message.toLowerCase().includes("word list failed verification")) throw new _MoneroRpcError.default("Invalid mnemonic", err.getCode(), err.getRpcMethod(), err.getRpcParams()); + } + throw err; + } + + async isViewOnly() { + try { + await this.config.getServer().sendJsonRequest("query_key", { key_type: "mnemonic" }); + return false; // key retrieval succeeds if not view only + } catch (e) { + if (e.getCode() === -29) return true; // wallet is view only + if (e.getCode() === -1) return false; // wallet is offline but not view only + throw e; + } + } + + /** + * Set the wallet's daemon connection. + * + * @param {string|MoneroRpcConnection} [uriOrConnection] - the daemon's URI or connection (defaults to offline) + * @param {boolean} isTrusted - indicates if the daemon in trusted + * @param {SslOptions} sslOptions - custom SSL configuration + */ + async setDaemonConnection(uriOrConnection, isTrusted, sslOptions) { + let connection = !uriOrConnection ? undefined : uriOrConnection instanceof _MoneroRpcConnection.default ? uriOrConnection : new _MoneroRpcConnection.default(uriOrConnection); + if (!sslOptions) sslOptions = new _SslOptions.default(); + let params = {}; + params.address = connection ? connection.getUri() : "bad_uri"; // TODO monero-wallet-rpc: bad daemon uri necessary for offline? + params.username = connection ? connection.getUsername() : ""; + params.password = connection ? connection.getPassword() : ""; + params.trusted = isTrusted; + params.ssl_support = "autodetect"; + params.ssl_private_key_path = sslOptions.getPrivateKeyPath(); + params.ssl_certificate_path = sslOptions.getCertificatePath(); + params.ssl_ca_file = sslOptions.getCertificateAuthorityFile(); + params.ssl_allowed_fingerprints = sslOptions.getAllowedFingerprints(); + params.ssl_allow_any_cert = sslOptions.getAllowAnyCert(); + params.proxy = connection ? connection.getProxyUri() : ""; + await this.config.getServer().sendJsonRequest("set_daemon", params); + this.daemonConnection = connection; + } + + async getDaemonConnection() { + return this.daemonConnection; + } + + /** + * Get the total and unlocked balances in a single request. + * + * @param {number} [accountIdx] account index + * @param {number} [subaddressIdx] subaddress index + * @return {Promise} is the total and unlocked balances in an array, respectively + */ + async getBalances(accountIdx, subaddressIdx) { + if (accountIdx === undefined) { + _assert.default.equal(subaddressIdx, undefined, "Must provide account index with subaddress index"); + let balance = BigInt(0); + let unlockedBalance = BigInt(0); + for (let account of await this.getAccounts()) { + balance = balance + account.getBalance(); + unlockedBalance = unlockedBalance + account.getUnlockedBalance(); + } + return [balance, unlockedBalance]; + } else { + let params = { account_index: accountIdx, address_indices: subaddressIdx === undefined ? undefined : [subaddressIdx] }; + let resp = await this.config.getServer().sendJsonRequest("get_balance", params); + if (subaddressIdx === undefined) return [BigInt(resp.result.balance), BigInt(resp.result.unlocked_balance)];else + return [BigInt(resp.result.per_subaddress[0].balance), BigInt(resp.result.per_subaddress[0].unlocked_balance)]; + } + } + + // -------------------------- COMMON WALLET METHODS ------------------------- + + async addListener(listener) { + await super.addListener(listener); + this.refreshListening(); + } + + async removeListener(listener) { + await super.removeListener(listener); + this.refreshListening(); + } + + async isConnectedToDaemon() { + try { + await this.checkReserveProof(await this.getPrimaryAddress(), "", ""); // TODO (monero-project): provide better way to know if wallet rpc is connected to daemon + throw new _MoneroError.default("check reserve expected to fail"); + } catch (e) { + return e.message.indexOf("Failed to connect to daemon") < 0; + } + } + + async getVersion() { + let resp = await this.config.getServer().sendJsonRequest("get_version"); + return new _MoneroVersion.default(resp.result.version, resp.result.release); + } + + async getPath() { + return this.path; + } + + async getSeed() { + let resp = await this.config.getServer().sendJsonRequest("query_key", { key_type: "mnemonic" }); + return resp.result.key; + } + + async getSeedLanguage() { + if ((await this.getSeed()) === undefined) return undefined; + throw new _MoneroError.default("MoneroWalletRpc.getSeedLanguage() not supported"); + } + + /** + * Get a list of available languages for the wallet's seed. + * + * @return {string[]} the available languages for the wallet's seed. + */ + async getSeedLanguages() { + return (await this.config.getServer().sendJsonRequest("get_languages")).result.languages; + } + + async getPrivateViewKey() { + let resp = await this.config.getServer().sendJsonRequest("query_key", { key_type: "view_key" }); + return resp.result.key; + } + + async getPrivateSpendKey() { + let resp = await this.config.getServer().sendJsonRequest("query_key", { key_type: "spend_key" }); + return resp.result.key; + } + + async getAddress(accountIdx, subaddressIdx) { + let subaddressMap = this.addressCache[accountIdx]; + if (!subaddressMap) { + await this.getSubaddresses(accountIdx, undefined, true); // cache's all addresses at this account + return this.getAddress(accountIdx, subaddressIdx); // recursive call uses cache + } + let address = subaddressMap[subaddressIdx]; + if (!address) { + await this.getSubaddresses(accountIdx, undefined, true); // cache's all addresses at this account + return this.addressCache[accountIdx][subaddressIdx]; + } + return address; + } + + // TODO: use cache + async getAddressIndex(address) { + + // fetch result and normalize error if address does not belong to the wallet + let resp; + try { + resp = await this.config.getServer().sendJsonRequest("get_address_index", { address: address }); + } catch (e) { + if (e.getCode() === -2) throw new _MoneroError.default(e.message); + throw e; + } + + // convert rpc response + let subaddress = new _MoneroSubaddress.default({ address: address }); + subaddress.setAccountIndex(resp.result.index.major); + subaddress.setIndex(resp.result.index.minor); + return subaddress; + } + + async getIntegratedAddress(standardAddress, paymentId) { + try { + let integratedAddressStr = (await this.config.getServer().sendJsonRequest("make_integrated_address", { standard_address: standardAddress, payment_id: paymentId })).result.integrated_address; + return await this.decodeIntegratedAddress(integratedAddressStr); + } catch (e) { + if (e.message.includes("Invalid payment ID")) throw new _MoneroError.default("Invalid payment ID: " + paymentId); + throw e; + } + } + + async decodeIntegratedAddress(integratedAddress) { + let resp = await this.config.getServer().sendJsonRequest("split_integrated_address", { integrated_address: integratedAddress }); + return new _MoneroIntegratedAddress.default().setStandardAddress(resp.result.standard_address).setPaymentId(resp.result.payment_id).setIntegratedAddress(integratedAddress); + } + + async getHeight() { + return (await this.config.getServer().sendJsonRequest("get_height")).result.height; + } + + async getDaemonHeight() { + throw new _MoneroError.default("monero-wallet-rpc does not support getting the chain height"); + } + + async getHeightByDate(year, month, day) { + throw new _MoneroError.default("monero-wallet-rpc does not support getting a height by date"); + } + + async sync(listenerOrStartHeight, startHeight) { + (0, _assert.default)(!(listenerOrStartHeight instanceof _MoneroWalletListener.default), "Monero Wallet RPC does not support reporting sync progress"); + try { + let resp = await this.config.getServer().sendJsonRequest("refresh", { start_height: startHeight }); + await this.poll(); + return new _MoneroSyncResult.default(resp.result.blocks_fetched, resp.result.received_money); + } catch (err) { + if (err.message === "no connection to daemon") throw new _MoneroError.default("Wallet is not connected to daemon"); + throw err; + } + } + + async startSyncing(syncPeriodInMs) { + + // convert ms to seconds for rpc parameter + let syncPeriodInSeconds = Math.round((syncPeriodInMs === undefined ? MoneroWalletRpc.DEFAULT_SYNC_PERIOD_IN_MS : syncPeriodInMs) / 1000); + + // send rpc request + await this.config.getServer().sendJsonRequest("auto_refresh", { + enable: true, + period: syncPeriodInSeconds + }); + + // update sync period for poller + this.syncPeriodInMs = syncPeriodInSeconds * 1000; + if (this.walletPoller !== undefined) this.walletPoller.setPeriodInMs(this.syncPeriodInMs); + + // poll if listening + await this.poll(); + } + + getSyncPeriodInMs() { + return this.syncPeriodInMs; + } + + async stopSyncing() { + return this.config.getServer().sendJsonRequest("auto_refresh", { enable: false }); + } + + async scanTxs(txHashes) { + if (!txHashes || !txHashes.length) throw new _MoneroError.default("No tx hashes given to scan"); + await this.config.getServer().sendJsonRequest("scan_tx", { txids: txHashes }); + await this.poll(); + } + + async rescanSpent() { + await this.config.getServer().sendJsonRequest("rescan_spent", undefined); + } + + async rescanBlockchain() { + await this.config.getServer().sendJsonRequest("rescan_blockchain", undefined); + } + + async getBalance(accountIdx, subaddressIdx) { + return (await this.getBalances(accountIdx, subaddressIdx))[0]; + } + + async getUnlockedBalance(accountIdx, subaddressIdx) { + return (await this.getBalances(accountIdx, subaddressIdx))[1]; + } + + async getAccounts(includeSubaddresses, tag, skipBalances) { + + // fetch accounts from rpc + let resp = await this.config.getServer().sendJsonRequest("get_accounts", { tag: tag }); + + // build account objects and fetch subaddresses per account using get_address + // TODO monero-wallet-rpc: get_address should support all_accounts so not called once per account + let accounts = []; + for (let rpcAccount of resp.result.subaddress_accounts) { + let account = MoneroWalletRpc.convertRpcAccount(rpcAccount); + if (includeSubaddresses) account.setSubaddresses(await this.getSubaddresses(account.getIndex(), undefined, true)); + accounts.push(account); + } + + // fetch and merge fields from get_balance across all accounts + if (includeSubaddresses && !skipBalances) { + + // these fields are not initialized if subaddress is unused and therefore not returned from `get_balance` + for (let account of accounts) { + for (let subaddress of account.getSubaddresses()) { + subaddress.setBalance(BigInt(0)); + subaddress.setUnlockedBalance(BigInt(0)); + subaddress.setNumUnspentOutputs(0); + subaddress.setNumBlocksToUnlock(0); + } + } + + // fetch and merge info from get_balance + resp = await this.config.getServer().sendJsonRequest("get_balance", { all_accounts: true }); + if (resp.result.per_subaddress) { + for (let rpcSubaddress of resp.result.per_subaddress) { + let subaddress = MoneroWalletRpc.convertRpcSubaddress(rpcSubaddress); + + // merge info + let account = accounts[subaddress.getAccountIndex()]; + _assert.default.equal(subaddress.getAccountIndex(), account.getIndex(), "RPC accounts are out of order"); // would need to switch lookup to loop + let tgtSubaddress = account.getSubaddresses()[subaddress.getIndex()]; + _assert.default.equal(subaddress.getIndex(), tgtSubaddress.getIndex(), "RPC subaddresses are out of order"); + if (subaddress.getBalance() !== undefined) tgtSubaddress.setBalance(subaddress.getBalance()); + if (subaddress.getUnlockedBalance() !== undefined) tgtSubaddress.setUnlockedBalance(subaddress.getUnlockedBalance()); + if (subaddress.getNumUnspentOutputs() !== undefined) tgtSubaddress.setNumUnspentOutputs(subaddress.getNumUnspentOutputs()); + } + } + } + + return accounts; + } + + // TODO: getAccountByIndex(), getAccountByTag() + async getAccount(accountIdx, includeSubaddresses, skipBalances) { + (0, _assert.default)(accountIdx >= 0); + for (let account of await this.getAccounts()) { + if (account.getIndex() === accountIdx) { + if (includeSubaddresses) account.setSubaddresses(await this.getSubaddresses(accountIdx, undefined, skipBalances)); + return account; + } + } + throw new Error("Account with index " + accountIdx + " does not exist"); + } + + async createAccount(label) { + label = label ? label : undefined; + let resp = await this.config.getServer().sendJsonRequest("create_account", { label: label }); + return new _MoneroAccount.default({ + index: resp.result.account_index, + primaryAddress: resp.result.address, + label: label, + balance: BigInt(0), + unlockedBalance: BigInt(0) + }); + } + + async getSubaddresses(accountIdx, subaddressIndices, skipBalances) { + + // fetch subaddresses + let params = {}; + params.account_index = accountIdx; + if (subaddressIndices) params.address_index = _GenUtils.default.listify(subaddressIndices); + let resp = await this.config.getServer().sendJsonRequest("get_address", params); + + // initialize subaddresses + let subaddresses = []; + for (let rpcSubaddress of resp.result.addresses) { + let subaddress = MoneroWalletRpc.convertRpcSubaddress(rpcSubaddress); + subaddress.setAccountIndex(accountIdx); + subaddresses.push(subaddress); + } + + // fetch and initialize subaddress balances + if (!skipBalances) { + + // these fields are not initialized if subaddress is unused and therefore not returned from `get_balance` + for (let subaddress of subaddresses) { + subaddress.setBalance(BigInt(0)); + subaddress.setUnlockedBalance(BigInt(0)); + subaddress.setNumUnspentOutputs(0); + subaddress.setNumBlocksToUnlock(0); + } + + // fetch and initialize balances + resp = await this.config.getServer().sendJsonRequest("get_balance", params); + if (resp.result.per_subaddress) { + for (let rpcSubaddress of resp.result.per_subaddress) { + let subaddress = MoneroWalletRpc.convertRpcSubaddress(rpcSubaddress); + + // transfer info to existing subaddress object + for (let tgtSubaddress of subaddresses) { + if (tgtSubaddress.getIndex() !== subaddress.getIndex()) continue; // skip to subaddress with same index + if (subaddress.getBalance() !== undefined) tgtSubaddress.setBalance(subaddress.getBalance()); + if (subaddress.getUnlockedBalance() !== undefined) tgtSubaddress.setUnlockedBalance(subaddress.getUnlockedBalance()); + if (subaddress.getNumUnspentOutputs() !== undefined) tgtSubaddress.setNumUnspentOutputs(subaddress.getNumUnspentOutputs()); + if (subaddress.getNumBlocksToUnlock() !== undefined) tgtSubaddress.setNumBlocksToUnlock(subaddress.getNumBlocksToUnlock()); + } + } + } + } + + // cache addresses + let subaddressMap = this.addressCache[accountIdx]; + if (!subaddressMap) { + subaddressMap = {}; + this.addressCache[accountIdx] = subaddressMap; + } + for (let subaddress of subaddresses) { + subaddressMap[subaddress.getIndex()] = subaddress.getAddress(); + } + + // return results + return subaddresses; + } + + async getSubaddress(accountIdx, subaddressIdx, skipBalances) { + (0, _assert.default)(accountIdx >= 0); + (0, _assert.default)(subaddressIdx >= 0); + return (await this.getSubaddresses(accountIdx, [subaddressIdx], skipBalances))[0]; + } + + async createSubaddress(accountIdx, label) { + + // send request + let resp = await this.config.getServer().sendJsonRequest("create_address", { account_index: accountIdx, label: label }); + + // build subaddress object + let subaddress = new _MoneroSubaddress.default(); + subaddress.setAccountIndex(accountIdx); + subaddress.setIndex(resp.result.address_index); + subaddress.setAddress(resp.result.address); + subaddress.setLabel(label ? label : undefined); + subaddress.setBalance(BigInt(0)); + subaddress.setUnlockedBalance(BigInt(0)); + subaddress.setNumUnspentOutputs(0); + subaddress.setIsUsed(false); + subaddress.setNumBlocksToUnlock(0); + return subaddress; + } + + async setSubaddressLabel(accountIdx, subaddressIdx, label) { + await this.config.getServer().sendJsonRequest("label_address", { index: { major: accountIdx, minor: subaddressIdx }, label: label }); + } + + async getTxs(query) { + + // copy query + const queryNormalized = _MoneroWallet.default.normalizeTxQuery(query); + + // temporarily disable transfer and output queries in order to collect all tx information + let transferQuery = queryNormalized.getTransferQuery(); + let inputQuery = queryNormalized.getInputQuery(); + let outputQuery = queryNormalized.getOutputQuery(); + queryNormalized.setTransferQuery(undefined); + queryNormalized.setInputQuery(undefined); + queryNormalized.setOutputQuery(undefined); + + // fetch all transfers that meet tx query + let transfers = await this.getTransfersAux(new _MoneroTransferQuery.default().setTxQuery(MoneroWalletRpc.decontextualize(queryNormalized.copy()))); + + // collect unique txs from transfers while retaining order + let txs = []; + let txsSet = new Set(); + for (let transfer of transfers) { + if (!txsSet.has(transfer.getTx())) { + txs.push(transfer.getTx()); + txsSet.add(transfer.getTx()); + } + } + + // cache types into maps for merging and lookup + let txMap = {}; + let blockMap = {}; + for (let tx of txs) { + MoneroWalletRpc.mergeTx(tx, txMap, blockMap); + } + + // fetch and merge outputs if requested + if (queryNormalized.getIncludeOutputs() || outputQuery) { + + // fetch outputs + let outputQueryAux = (outputQuery ? outputQuery.copy() : new _MoneroOutputQuery.default()).setTxQuery(MoneroWalletRpc.decontextualize(queryNormalized.copy())); + let outputs = await this.getOutputsAux(outputQueryAux); + + // merge output txs one time while retaining order + let outputTxs = []; + for (let output of outputs) { + if (!outputTxs.includes(output.getTx())) { + MoneroWalletRpc.mergeTx(output.getTx(), txMap, blockMap); + outputTxs.push(output.getTx()); + } + } + } + + // restore transfer and output queries + queryNormalized.setTransferQuery(transferQuery); + queryNormalized.setInputQuery(inputQuery); + queryNormalized.setOutputQuery(outputQuery); + + // filter txs that don't meet transfer query + let txsQueried = []; + for (let tx of txs) { + if (queryNormalized.meetsCriteria(tx)) txsQueried.push(tx);else + if (tx.getBlock() !== undefined) tx.getBlock().getTxs().splice(tx.getBlock().getTxs().indexOf(tx), 1); + } + txs = txsQueried; + + // special case: re-fetch txs if inconsistency caused by needing to make multiple rpc calls + for (let tx of txs) { + if (tx.getIsConfirmed() && tx.getBlock() === undefined || !tx.getIsConfirmed() && tx.getBlock() !== undefined) { + console.error("Inconsistency detected building txs from multiple rpc calls, re-fetching txs"); + return this.getTxs(queryNormalized); + } + } + + // order txs if tx hashes given then return + if (queryNormalized.getHashes() && queryNormalized.getHashes().length > 0) { + let txsById = new Map(); // store txs in temporary map for sorting + for (let tx of txs) txsById.set(tx.getHash(), tx); + let orderedTxs = []; + for (let hash of queryNormalized.getHashes()) if (txsById.get(hash)) orderedTxs.push(txsById.get(hash)); + txs = orderedTxs; + } + return txs; + } + + async getTransfers(query) { + + // copy and normalize query up to block + const queryNormalized = _MoneroWallet.default.normalizeTransferQuery(query); + + // get transfers directly if query does not require tx context (other transfers, outputs) + if (!MoneroWalletRpc.isContextual(queryNormalized)) return this.getTransfersAux(queryNormalized); + + // otherwise get txs with full models to fulfill query + let transfers = []; + for (let tx of await this.getTxs(queryNormalized.getTxQuery())) { + for (let transfer of tx.filterTransfers(queryNormalized)) { + transfers.push(transfer); + } + } + + return transfers; + } + + async getOutputs(query) { + + // copy and normalize query up to block + const queryNormalized = _MoneroWallet.default.normalizeOutputQuery(query); + + // get outputs directly if query does not require tx context (other outputs, transfers) + if (!MoneroWalletRpc.isContextual(queryNormalized)) return this.getOutputsAux(queryNormalized); + + // otherwise get txs with full models to fulfill query + let outputs = []; + for (let tx of await this.getTxs(queryNormalized.getTxQuery())) { + for (let output of tx.filterOutputs(queryNormalized)) { + outputs.push(output); + } + } + + return outputs; + } + + async exportOutputs(all = false) { + return (await this.config.getServer().sendJsonRequest("export_outputs", { all: all })).result.outputs_data_hex; + } + + async importOutputs(outputsHex) { + let resp = await this.config.getServer().sendJsonRequest("import_outputs", { outputs_data_hex: outputsHex }); + return resp.result.num_imported; + } + + async exportKeyImages(all = false) { + return await this.rpcExportKeyImages(all); + } + + async importKeyImages(keyImages) { + + // convert key images to rpc parameter + let rpcKeyImages = keyImages.map((keyImage) => ({ key_image: keyImage.getHex(), signature: keyImage.getSignature() })); + + // send request + let resp = await this.config.getServer().sendJsonRequest("import_key_images", { signed_key_images: rpcKeyImages }); + + // build and return result + let importResult = new _MoneroKeyImageImportResult.default(); + importResult.setHeight(resp.result.height); + importResult.setSpentAmount(BigInt(resp.result.spent)); + importResult.setUnspentAmount(BigInt(resp.result.unspent)); + return importResult; + } + + async getNewKeyImagesFromLastImport() { + return await this.rpcExportKeyImages(false); + } + + async freezeOutput(keyImage) { + return this.config.getServer().sendJsonRequest("freeze", { key_image: keyImage }); + } + + async thawOutput(keyImage) { + return this.config.getServer().sendJsonRequest("thaw", { key_image: keyImage }); + } + + async isOutputFrozen(keyImage) { + let resp = await this.config.getServer().sendJsonRequest("frozen", { key_image: keyImage }); + return resp.result.frozen === true; + } + + async getDefaultFeePriority() { + let resp = await this.config.getServer().sendJsonRequest("get_default_fee_priority"); + return resp.result.priority; + } + + async createTxs(config) { + + // validate, copy, and normalize config + const configNormalized = _MoneroWallet.default.normalizeCreateTxsConfig(config); + if (configNormalized.getCanSplit() === undefined) configNormalized.setCanSplit(true); + if (configNormalized.getRelay() === true && (await this.isMultisig())) throw new _MoneroError.default("Cannot relay multisig transaction until co-signed"); + + // determine account and subaddresses to send from + let accountIdx = configNormalized.getAccountIndex(); + if (accountIdx === undefined) throw new _MoneroError.default("Must provide the account index to send from"); + let subaddressIndices = configNormalized.getSubaddressIndices() === undefined ? undefined : configNormalized.getSubaddressIndices().slice(0); // fetch all or copy given indices + + // build config parameters + let params = {}; + params.destinations = []; + for (let destination of configNormalized.getDestinations()) { + (0, _assert.default)(destination.getAddress(), "Destination address is not defined"); + (0, _assert.default)(destination.getAmount(), "Destination amount is not defined"); + params.destinations.push({ address: destination.getAddress(), amount: destination.getAmount().toString() }); + } + if (configNormalized.getSubtractFeeFrom()) params.subtract_fee_from_outputs = configNormalized.getSubtractFeeFrom(); + params.account_index = accountIdx; + params.subaddr_indices = subaddressIndices; + params.payment_id = configNormalized.getPaymentId(); + params.do_not_relay = configNormalized.getRelay() !== true; + (0, _assert.default)(configNormalized.getPriority() === undefined || configNormalized.getPriority() >= 0 && configNormalized.getPriority() <= 3); + params.priority = configNormalized.getPriority(); + params.get_tx_hex = true; + params.get_tx_metadata = true; + if (configNormalized.getCanSplit()) params.get_tx_keys = true; // param to get tx key(s) depends if split + else params.get_tx_key = true; + + // cannot apply subtractFeeFrom with `transfer_split` call + if (configNormalized.getCanSplit() && configNormalized.getSubtractFeeFrom() && configNormalized.getSubtractFeeFrom().length > 0) { + throw new _MoneroError.default("subtractfeefrom transfers cannot be split over multiple transactions yet"); + } + + // send request + let result; + try { + let resp = await this.config.getServer().sendJsonRequest(configNormalized.getCanSplit() ? "transfer_split" : "transfer", params); + result = resp.result; + } catch (err) { + if (err.message.indexOf("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS") > -1) throw new _MoneroError.default("Invalid destination address"); + throw err; + } + + // pre-initialize txs iff present. multisig and view-only wallets will have tx set without transactions + let txs; + let numTxs = configNormalized.getCanSplit() ? result.fee_list !== undefined ? result.fee_list.length : 0 : result.fee !== undefined ? 1 : 0; + if (numTxs > 0) txs = []; + let copyDestinations = numTxs === 1; + for (let i = 0; i < numTxs; i++) { + let tx = new _MoneroTxWallet.default(); + MoneroWalletRpc.initSentTxWallet(configNormalized, tx, copyDestinations); + tx.getOutgoingTransfer().setAccountIndex(accountIdx); + if (subaddressIndices !== undefined && subaddressIndices.length === 1) tx.getOutgoingTransfer().setSubaddressIndices(subaddressIndices); + txs.push(tx); + } + + // notify of changes + if (configNormalized.getRelay()) await this.poll(); + + // initialize tx set from rpc response with pre-initialized txs + if (configNormalized.getCanSplit()) return MoneroWalletRpc.convertRpcSentTxsToTxSet(result, txs, configNormalized).getTxs();else + return MoneroWalletRpc.convertRpcTxToTxSet(result, txs === undefined ? undefined : txs[0], true, configNormalized).getTxs(); + } + + async sweepOutput(config) { + + // normalize and validate config + config = _MoneroWallet.default.normalizeSweepOutputConfig(config); + + // build request parameters + let params = {}; + params.address = config.getDestinations()[0].getAddress(); + params.account_index = config.getAccountIndex(); + params.subaddr_indices = config.getSubaddressIndices(); + params.key_image = config.getKeyImage(); + params.do_not_relay = config.getRelay() !== true; + (0, _assert.default)(config.getPriority() === undefined || config.getPriority() >= 0 && config.getPriority() <= 3); + params.priority = config.getPriority(); + params.payment_id = config.getPaymentId(); + params.get_tx_key = true; + params.get_tx_hex = true; + params.get_tx_metadata = true; + + // send request + let resp = await this.config.getServer().sendJsonRequest("sweep_single", params); + let result = resp.result; + + // notify of changes + if (config.getRelay()) await this.poll(); + + // build and return tx + let tx = MoneroWalletRpc.initSentTxWallet(config, undefined, true); + MoneroWalletRpc.convertRpcTxToTxSet(result, tx, true, config); + tx.getOutgoingTransfer().getDestinations()[0].setAmount(tx.getOutgoingTransfer().getAmount()); // initialize destination amount + return tx; + } + + async sweepUnlocked(config) { + + // validate and normalize config + const configNormalized = _MoneroWallet.default.normalizeSweepUnlockedConfig(config); + + // determine account and subaddress indices to sweep; default to all with unlocked balance if not specified + let indices = new Map(); // maps each account index to subaddress indices to sweep + if (configNormalized.getAccountIndex() !== undefined) { + if (configNormalized.getSubaddressIndices() !== undefined) { + indices.set(configNormalized.getAccountIndex(), configNormalized.getSubaddressIndices()); + } else { + let subaddressIndices = []; + indices.set(configNormalized.getAccountIndex(), subaddressIndices); + for (let subaddress of await this.getSubaddresses(configNormalized.getAccountIndex())) { + if (subaddress.getUnlockedBalance() > 0n) subaddressIndices.push(subaddress.getIndex()); + } + } + } else { + let accounts = await this.getAccounts(true); + for (let account of accounts) { + if (account.getUnlockedBalance() > 0n) { + let subaddressIndices = []; + indices.set(account.getIndex(), subaddressIndices); + for (let subaddress of account.getSubaddresses()) { + if (subaddress.getUnlockedBalance() > 0n) subaddressIndices.push(subaddress.getIndex()); + } + } + } + } + + // sweep from each account and collect resulting tx sets + let txs = []; + for (let accountIdx of indices.keys()) { + + // copy and modify the original config + let copy = configNormalized.copy(); + copy.setAccountIndex(accountIdx); + copy.setSweepEachSubaddress(false); + + // sweep all subaddresses together // TODO monero-project: can this reveal outputs belong to the same wallet? + if (copy.getSweepEachSubaddress() !== true) { + copy.setSubaddressIndices(indices.get(accountIdx)); + for (let tx of await this.rpcSweepAccount(copy)) txs.push(tx); + } + + // otherwise sweep each subaddress individually + else { + for (let subaddressIdx of indices.get(accountIdx)) { + copy.setSubaddressIndices([subaddressIdx]); + for (let tx of await this.rpcSweepAccount(copy)) txs.push(tx); + } + } + } + + // notify of changes + if (configNormalized.getRelay()) await this.poll(); + return txs; + } + + async sweepDust(relay) { + if (relay === undefined) relay = false; + let resp = await this.config.getServer().sendJsonRequest("sweep_dust", { do_not_relay: !relay }); + if (relay) await this.poll(); + let result = resp.result; + let txSet = MoneroWalletRpc.convertRpcSentTxsToTxSet(result); + if (txSet.getTxs() === undefined) return []; + for (let tx of txSet.getTxs()) { + tx.setIsRelayed(!relay); + tx.setInTxPool(tx.getIsRelayed()); + } + return txSet.getTxs(); + } + + async relayTxs(txsOrMetadatas) { + (0, _assert.default)(Array.isArray(txsOrMetadatas), "Must provide an array of txs or their metadata to relay"); + let txHashes = []; + for (let txOrMetadata of txsOrMetadatas) { + let metadata = txOrMetadata instanceof _MoneroTxWallet.default ? txOrMetadata.getMetadata() : txOrMetadata; + let resp = await this.config.getServer().sendJsonRequest("relay_tx", { hex: metadata }); + txHashes.push(resp.result.tx_hash); + } + await this.poll(); // notify of changes + return txHashes; + } + + async describeTxSet(txSet) { + let resp = await this.config.getServer().sendJsonRequest("describe_transfer", { + unsigned_txset: txSet.getUnsignedTxHex(), + multisig_txset: txSet.getMultisigTxHex() + }); + return MoneroWalletRpc.convertRpcDescribeTransfer(resp.result); + } + + async signTxs(unsignedTxHex) { + let resp = await this.config.getServer().sendJsonRequest("sign_transfer", { + unsigned_txset: unsignedTxHex, + export_raw: false + }); + await this.poll(); + return MoneroWalletRpc.convertRpcSentTxsToTxSet(resp.result); + } + + async submitTxs(signedTxHex) { + let resp = await this.config.getServer().sendJsonRequest("submit_transfer", { + tx_data_hex: signedTxHex + }); + await this.poll(); + return resp.result.tx_hash_list; + } + + async signMessage(message, signatureType = _MoneroMessageSignatureType.default.SIGN_WITH_SPEND_KEY, accountIdx = 0, subaddressIdx = 0) { + let resp = await this.config.getServer().sendJsonRequest("sign", { + data: message, + signature_type: signatureType === _MoneroMessageSignatureType.default.SIGN_WITH_SPEND_KEY ? "spend" : "view", + account_index: accountIdx, + address_index: subaddressIdx + }); + return resp.result.signature; + } + + async verifyMessage(message, address, signature) { + try { + let resp = await this.config.getServer().sendJsonRequest("verify", { data: message, address: address, signature: signature }); + let result = resp.result; + return new _MoneroMessageSignatureResult.default( + result.good ? { isGood: result.good, isOld: result.old, signatureType: result.signature_type === "view" ? _MoneroMessageSignatureType.default.SIGN_WITH_VIEW_KEY : _MoneroMessageSignatureType.default.SIGN_WITH_SPEND_KEY, version: result.version } : { isGood: false } + ); + } catch (e) { + if (e.getCode() === -2) return new _MoneroMessageSignatureResult.default({ isGood: false }); + throw e; + } + } + + async getTxKey(txHash) { + try { + return (await this.config.getServer().sendJsonRequest("get_tx_key", { txid: txHash })).result.tx_key; + } catch (e) { + if (e instanceof _MoneroRpcError.default && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new _MoneroRpcError.default("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message + throw e; + } + } + + async checkTxKey(txHash, txKey, address) { + try { + + // send request + let resp = await this.config.getServer().sendJsonRequest("check_tx_key", { txid: txHash, tx_key: txKey, address: address }); + + // interpret result + let check = new _MoneroCheckTx.default(); + check.setIsGood(true); + check.setNumConfirmations(resp.result.confirmations); + check.setInTxPool(resp.result.in_pool); + check.setReceivedAmount(BigInt(resp.result.received)); + return check; + } catch (e) { + if (e instanceof _MoneroRpcError.default && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new _MoneroRpcError.default("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message + throw e; + } + } + + async getTxProof(txHash, address, message) { + try { + let resp = await this.config.getServer().sendJsonRequest("get_tx_proof", { txid: txHash, address: address, message: message }); + return resp.result.signature; + } catch (e) { + if (e instanceof _MoneroRpcError.default && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new _MoneroRpcError.default("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message + throw e; + } + } + + async checkTxProof(txHash, address, message, signature) { + try { + + // send request + let resp = await this.config.getServer().sendJsonRequest("check_tx_proof", { + txid: txHash, + address: address, + message: message, + signature: signature + }); + + // interpret response + let isGood = resp.result.good; + let check = new _MoneroCheckTx.default(); + check.setIsGood(isGood); + if (isGood) { + check.setNumConfirmations(resp.result.confirmations); + check.setInTxPool(resp.result.in_pool); + check.setReceivedAmount(BigInt(resp.result.received)); + } + return check; + } catch (e) { + if (e instanceof _MoneroRpcError.default && e.getCode() === -1 && e.message === "basic_string") e = new _MoneroRpcError.default("Must provide signature to check tx proof", -1); + if (e instanceof _MoneroRpcError.default && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new _MoneroRpcError.default("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); + throw e; + } + } + + async getSpendProof(txHash, message) { + try { + let resp = await this.config.getServer().sendJsonRequest("get_spend_proof", { txid: txHash, message: message }); + return resp.result.signature; + } catch (e) { + if (e instanceof _MoneroRpcError.default && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new _MoneroRpcError.default("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message + throw e; + } + } + + async checkSpendProof(txHash, message, signature) { + try { + let resp = await this.config.getServer().sendJsonRequest("check_spend_proof", { + txid: txHash, + message: message, + signature: signature + }); + return resp.result.good; + } catch (e) { + if (e instanceof _MoneroRpcError.default && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new _MoneroRpcError.default("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message + throw e; + } + } + + async getReserveProofWallet(message) { + let resp = await this.config.getServer().sendJsonRequest("get_reserve_proof", { + all: true, + message: message + }); + return resp.result.signature; + } + + async getReserveProofAccount(accountIdx, amount, message) { + let resp = await this.config.getServer().sendJsonRequest("get_reserve_proof", { + account_index: accountIdx, + amount: amount.toString(), + message: message + }); + return resp.result.signature; + } + + async checkReserveProof(address, message, signature) { + + // send request + let resp = await this.config.getServer().sendJsonRequest("check_reserve_proof", { + address: address, + message: message, + signature: signature + }); + + // interpret results + let isGood = resp.result.good; + let check = new _MoneroCheckReserve.default(); + check.setIsGood(isGood); + if (isGood) { + check.setUnconfirmedSpentAmount(BigInt(resp.result.spent)); + check.setTotalAmount(BigInt(resp.result.total)); + } + return check; + } + + async getTxNotes(txHashes) { + return (await this.config.getServer().sendJsonRequest("get_tx_notes", { txids: txHashes })).result.notes; + } + + async setTxNotes(txHashes, notes) { + await this.config.getServer().sendJsonRequest("set_tx_notes", { txids: txHashes, notes: notes }); + } + + async getAddressBookEntries(entryIndices) { + let resp = await this.config.getServer().sendJsonRequest("get_address_book", { entries: entryIndices }); + if (!resp.result.entries) return []; + let entries = []; + for (let rpcEntry of resp.result.entries) { + entries.push(new _MoneroAddressBookEntry.default().setIndex(rpcEntry.index).setAddress(rpcEntry.address).setDescription(rpcEntry.description).setPaymentId(rpcEntry.payment_id)); + } + return entries; + } + + async addAddressBookEntry(address, description) { + let resp = await this.config.getServer().sendJsonRequest("add_address_book", { address: address, description: description }); + return resp.result.index; + } + + async editAddressBookEntry(index, setAddress, address, setDescription, description) { + let resp = await this.config.getServer().sendJsonRequest("edit_address_book", { + index: index, + set_address: setAddress, + address: address, + set_description: setDescription, + description: description + }); + } + + async deleteAddressBookEntry(entryIdx) { + await this.config.getServer().sendJsonRequest("delete_address_book", { index: entryIdx }); + } + + async tagAccounts(tag, accountIndices) { + await this.config.getServer().sendJsonRequest("tag_accounts", { tag: tag, accounts: accountIndices }); + } + + async untagAccounts(accountIndices) { + await this.config.getServer().sendJsonRequest("untag_accounts", { accounts: accountIndices }); + } + + async getAccountTags() { + let tags = []; + let resp = await this.config.getServer().sendJsonRequest("get_account_tags"); + if (resp.result.account_tags) { + for (let rpcAccountTag of resp.result.account_tags) { + tags.push(new _MoneroAccountTag.default({ + tag: rpcAccountTag.tag ? rpcAccountTag.tag : undefined, + label: rpcAccountTag.label ? rpcAccountTag.label : undefined, + accountIndices: rpcAccountTag.accounts + })); + } + } + return tags; + } + + async setAccountTagLabel(tag, label) { + await this.config.getServer().sendJsonRequest("set_account_tag_description", { tag: tag, description: label }); + } + + async getPaymentUri(config) { + config = _MoneroWallet.default.normalizeCreateTxsConfig(config); + let resp = await this.config.getServer().sendJsonRequest("make_uri", { + address: config.getDestinations()[0].getAddress(), + amount: config.getDestinations()[0].getAmount() ? config.getDestinations()[0].getAmount().toString() : undefined, + payment_id: config.getPaymentId(), + recipient_name: config.getRecipientName(), + tx_description: config.getNote() + }); + return resp.result.uri; + } + + async parsePaymentUri(uri) { + (0, _assert.default)(uri, "Must provide URI to parse"); + let resp = await this.config.getServer().sendJsonRequest("parse_uri", { uri: uri }); + let config = new _MoneroTxConfig.default({ address: resp.result.uri.address, amount: BigInt(resp.result.uri.amount) }); + config.setPaymentId(resp.result.uri.payment_id); + config.setRecipientName(resp.result.uri.recipient_name); + config.setNote(resp.result.uri.tx_description); + if ("" === config.getDestinations()[0].getAddress()) config.getDestinations()[0].setAddress(undefined); + if ("" === config.getPaymentId()) config.setPaymentId(undefined); + if ("" === config.getRecipientName()) config.setRecipientName(undefined); + if ("" === config.getNote()) config.setNote(undefined); + return config; + } + + async getAttribute(key) { + try { + let resp = await this.config.getServer().sendJsonRequest("get_attribute", { key: key }); + return resp.result.value === "" ? undefined : resp.result.value; + } catch (e) { + if (e instanceof _MoneroRpcError.default && e.getCode() === -45) return undefined; + throw e; + } + } + + async setAttribute(key, val) { + await this.config.getServer().sendJsonRequest("set_attribute", { key: key, value: val }); + } + + async startMining(numThreads, backgroundMining, ignoreBattery) { + await this.config.getServer().sendJsonRequest("start_mining", { + threads_count: numThreads, + do_background_mining: backgroundMining, + ignore_battery: ignoreBattery + }); + } + + async stopMining() { + await this.config.getServer().sendJsonRequest("stop_mining"); + } + + async isMultisigImportNeeded() { + let resp = await this.config.getServer().sendJsonRequest("get_balance"); + return resp.result.multisig_import_needed === true; + } + + async getMultisigInfo() { + let resp = await this.config.getServer().sendJsonRequest("is_multisig"); + let result = resp.result; + let info = new _MoneroMultisigInfo.default(); + info.setIsMultisig(result.multisig); + info.setIsReady(result.ready); + info.setThreshold(result.threshold); + info.setNumParticipants(result.total); + return info; + } + + async prepareMultisig() { + let resp = await this.config.getServer().sendJsonRequest("prepare_multisig", { enable_multisig_experimental: true }); + this.addressCache = {}; + let result = resp.result; + return result.multisig_info; + } + + async makeMultisig(multisigHexes, threshold, password) { + let resp = await this.config.getServer().sendJsonRequest("make_multisig", { + multisig_info: multisigHexes, + threshold: threshold, + password: password + }); + this.addressCache = {}; + return resp.result.multisig_info; + } + + async exchangeMultisigKeys(multisigHexes, password) { + let resp = await this.config.getServer().sendJsonRequest("exchange_multisig_keys", { multisig_info: multisigHexes, password: password }); + this.addressCache = {}; + let msResult = new _MoneroMultisigInitResult.default(); + msResult.setAddress(resp.result.address); + msResult.setMultisigHex(resp.result.multisig_info); + if (msResult.getAddress().length === 0) msResult.setAddress(undefined); + if (msResult.getMultisigHex().length === 0) msResult.setMultisigHex(undefined); + return msResult; + } + + async exportMultisigHex() { + let resp = await this.config.getServer().sendJsonRequest("export_multisig_info"); + return resp.result.info; + } + + async importMultisigHex(multisigHexes) { + if (!_GenUtils.default.isArray(multisigHexes)) throw new _MoneroError.default("Must provide string[] to importMultisigHex()"); + let resp = await this.config.getServer().sendJsonRequest("import_multisig_info", { info: multisigHexes }); + return resp.result.n_outputs; + } + + async signMultisigTxHex(multisigTxHex) { + let resp = await this.config.getServer().sendJsonRequest("sign_multisig", { tx_data_hex: multisigTxHex }); + let result = resp.result; + let signResult = new _MoneroMultisigSignResult.default(); + signResult.setSignedMultisigTxHex(result.tx_data_hex); + signResult.setTxHashes(result.tx_hash_list); + return signResult; + } + + async submitMultisigTxHex(signedMultisigTxHex) { + let resp = await this.config.getServer().sendJsonRequest("submit_multisig", { tx_data_hex: signedMultisigTxHex }); + return resp.result.tx_hash_list; + } + + async changePassword(oldPassword, newPassword) { + return this.config.getServer().sendJsonRequest("change_wallet_password", { old_password: oldPassword || "", new_password: newPassword || "" }); + } + + async save() { + await this.config.getServer().sendJsonRequest("store"); + } + + async close(save = false) { + await super.close(save); + if (save === undefined) save = false; + await this.clear(); + await this.config.getServer().sendJsonRequest("close_wallet", { autosave_current: save }); + } + + async isClosed() { + try { + await this.getPrimaryAddress(); + } catch (e) { + return e instanceof _MoneroRpcError.default && e.getCode() === -13 && e.message.indexOf("No wallet file") > -1; + } + return false; + } + + /** + * Save and close the current wallet and stop the RPC server. + * + * @return {Promise} + */ + async stop() { + await this.clear(); + await this.config.getServer().sendJsonRequest("stop_wallet"); + } + + // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS -------------- + + async getNumBlocksToUnlock() {return super.getNumBlocksToUnlock();} + async getTx(txHash) {return super.getTx(txHash);} + async getIncomingTransfers(query) {return super.getIncomingTransfers(query);} + async getOutgoingTransfers(query) {return super.getOutgoingTransfers(query);} + async createTx(config) {return super.createTx(config);} + async relayTx(txOrMetadata) {return super.relayTx(txOrMetadata);} + async getTxNote(txHash) {return super.getTxNote(txHash);} + async setTxNote(txHash, note) {return super.setTxNote(txHash, note);} + + // -------------------------------- PRIVATE --------------------------------- + + static async connectToWalletRpc(uriOrConfig, username, password) { + let config = MoneroWalletRpc.normalizeConfig(uriOrConfig, username, password); + if (config.cmd) return MoneroWalletRpc.startWalletRpcProcess(config);else + return new MoneroWalletRpc(config); + } + + static async startWalletRpcProcess(config) { + (0, _assert.default)(_GenUtils.default.isArray(config.cmd), "Must provide string array with command line parameters"); + + // start process + let child_process = await Promise.resolve().then(() => _interopRequireWildcard(require("child_process"))); + const childProcess = child_process.spawn(config.cmd[0], config.cmd.slice(1), { + env: { ...process.env, LANG: 'en_US.UTF-8' } // scrape output in english + }); + childProcess.stdout.setEncoding('utf8'); + childProcess.stderr.setEncoding('utf8'); + + // return promise which resolves after starting monero-wallet-rpc + let uri; + let that = this; + let output = ""; + try { + return await new Promise(function (resolve, reject) { + + // handle stdout + childProcess.stdout.on('data', async function (data) { + let line = data.toString(); + _LibraryUtils.default.log(2, line); + output += line + '\n'; // capture output in case of error + + // extract uri from e.g. "I Binding on 127.0.0.1 (IPv4):38085" + let uriLineContains = "Binding on "; + let uriLineContainsIdx = line.indexOf(uriLineContains); + if (uriLineContainsIdx >= 0) { + let host = line.substring(uriLineContainsIdx + uriLineContains.length, line.lastIndexOf(' ')); + let unformattedLine = line.replace(/\u001b\[.*?m/g, '').trim(); // remove color formatting + let port = unformattedLine.substring(unformattedLine.lastIndexOf(':') + 1); + let sslIdx = config.cmd.indexOf("--rpc-ssl"); + let sslEnabled = sslIdx >= 0 ? "enabled" == config.cmd[sslIdx + 1].toLowerCase() : false; + uri = (sslEnabled ? "https" : "http") + "://" + host + ":" + port; + } + + // read success message + if (line.indexOf("Starting wallet RPC server") >= 0) { + + // get username and password from params + let userPassIdx = config.cmd.indexOf("--rpc-login"); + let userPass = userPassIdx >= 0 ? config.cmd[userPassIdx + 1] : undefined; + let username = userPass === undefined ? undefined : userPass.substring(0, userPass.indexOf(':')); + let password = userPass === undefined ? undefined : userPass.substring(userPass.indexOf(':') + 1); + + // create client connected to internal process + config = config.copy().setServer({ uri: uri, username: username, password: password, rejectUnauthorized: config.getServer() ? config.getServer().getRejectUnauthorized() : undefined }); + config.cmd = undefined; + let wallet = await MoneroWalletRpc.connectToWalletRpc(config); + wallet.process = childProcess; + + // resolve promise with client connected to internal process + this.isResolved = true; + resolve(wallet); + } + }); + + // handle stderr + childProcess.stderr.on('data', function (data) { + if (_LibraryUtils.default.getLogLevel() >= 2) console.error(data); + }); + + // handle exit + childProcess.on("exit", function (code) { + if (!this.isResolved) reject(new _MoneroError.default("monero-wallet-rpc process terminated with exit code " + code + (output ? ":\n\n" + output : ""))); + }); + + // handle error + childProcess.on("error", function (err) { + if (err.message.indexOf("ENOENT") >= 0) reject(new _MoneroError.default("monero-wallet-rpc does not exist at path '" + config.cmd[0] + "'")); + if (!this.isResolved) reject(err); + }); + + // handle uncaught exception + childProcess.on("uncaughtException", function (err, origin) { + console.error("Uncaught exception in monero-wallet-rpc process: " + err.message); + console.error(origin); + if (!this.isResolved) reject(err); + }); + }); + } catch (err) { + throw new _MoneroError.default(err.message); + } + } + + async clear() { + this.refreshListening(); + delete this.addressCache; + this.addressCache = {}; + this.path = undefined; + } + + async getAccountIndices(getSubaddressIndices) { + let indices = new Map(); + for (let account of await this.getAccounts()) { + indices.set(account.getIndex(), getSubaddressIndices ? await this.getSubaddressIndices(account.getIndex()) : undefined); + } + return indices; + } + + async getSubaddressIndices(accountIdx) { + let subaddressIndices = []; + let resp = await this.config.getServer().sendJsonRequest("get_address", { account_index: accountIdx }); + for (let address of resp.result.addresses) subaddressIndices.push(address.address_index); + return subaddressIndices; + } + + async getTransfersAux(query) { + + // build params for get_transfers rpc call + let txQuery = query.getTxQuery(); + let canBeConfirmed = txQuery.getIsConfirmed() !== false && txQuery.getInTxPool() !== true && txQuery.getIsFailed() !== true && txQuery.getIsRelayed() !== false; + let canBeInTxPool = txQuery.getIsConfirmed() !== true && txQuery.getInTxPool() !== false && txQuery.getIsFailed() !== true && txQuery.getHeight() === undefined && txQuery.getMaxHeight() === undefined && txQuery.getIsLocked() !== false; + let canBeIncoming = query.getIsIncoming() !== false && query.getIsOutgoing() !== true && query.getHasDestinations() !== true; + let canBeOutgoing = query.getIsOutgoing() !== false && query.getIsIncoming() !== true; + + // check if fetching pool txs contradicted by configuration + if (txQuery.getInTxPool() === true && !canBeInTxPool) { + throw new _MoneroError.default("Cannot fetch pool transactions because it contradicts configuration"); + } + + let params = {}; + params.in = canBeIncoming && canBeConfirmed; + params.out = canBeOutgoing && canBeConfirmed; + params.pool = canBeIncoming && canBeInTxPool; + params.pending = canBeOutgoing && canBeInTxPool; + params.failed = txQuery.getIsFailed() !== false && txQuery.getIsConfirmed() !== true && txQuery.getInTxPool() != true; + if (txQuery.getMinHeight() !== undefined) { + if (txQuery.getMinHeight() > 0) params.min_height = txQuery.getMinHeight() - 1; // TODO monero-project: wallet2::get_payments() min_height is exclusive, so manually offset to match intended range (issues #5751, #5598) + else params.min_height = txQuery.getMinHeight(); + } + if (txQuery.getMaxHeight() !== undefined) params.max_height = txQuery.getMaxHeight(); + params.filter_by_height = txQuery.getMinHeight() !== undefined || txQuery.getMaxHeight() !== undefined; + if (query.getAccountIndex() === undefined) { + (0, _assert.default)(query.getSubaddressIndex() === undefined && query.getSubaddressIndices() === undefined, "Query specifies a subaddress index but not an account index"); + params.all_accounts = true; + } else { + params.account_index = query.getAccountIndex(); + + // set subaddress indices param + let subaddressIndices = new Set(); + if (query.getSubaddressIndex() !== undefined) subaddressIndices.add(query.getSubaddressIndex()); + if (query.getSubaddressIndices() !== undefined) query.getSubaddressIndices().map((subaddressIdx) => subaddressIndices.add(subaddressIdx)); + if (subaddressIndices.size) params.subaddr_indices = Array.from(subaddressIndices); + } + + // cache unique txs and blocks + let txMap = {}; + let blockMap = {}; + + // build txs using `get_transfers` + let resp = await this.config.getServer().sendJsonRequest("get_transfers", params); + for (let key of Object.keys(resp.result)) { + for (let rpcTx of resp.result[key]) { + //if (rpcTx.txid === query.debugTxId) console.log(rpcTx); + let tx = MoneroWalletRpc.convertRpcTxWithTransfer(rpcTx); + if (tx.getIsConfirmed()) (0, _assert.default)(tx.getBlock().getTxs().indexOf(tx) > -1); + + // replace transfer amount with destination sum + // TODO monero-wallet-rpc: confirmed tx from/to same account has amount 0 but cached transfers + if (tx.getOutgoingTransfer() !== undefined && tx.getIsRelayed() && !tx.getIsFailed() && + tx.getOutgoingTransfer().getDestinations() && tx.getOutgoingAmount() === 0n) { + let outgoingTransfer = tx.getOutgoingTransfer(); + let transferTotal = BigInt(0); + for (let destination of outgoingTransfer.getDestinations()) transferTotal = transferTotal + destination.getAmount(); + tx.getOutgoingTransfer().setAmount(transferTotal); + } + + // merge tx + MoneroWalletRpc.mergeTx(tx, txMap, blockMap); + } + } + + // sort txs by block height + let txs = Object.values(txMap); + txs.sort(MoneroWalletRpc.compareTxsByHeight); + + // filter and return transfers + let transfers = []; + for (let tx of txs) { + + // tx is not incoming/outgoing unless already set + if (tx.getIsIncoming() === undefined) tx.setIsIncoming(false); + if (tx.getIsOutgoing() === undefined) tx.setIsOutgoing(false); + + // sort incoming transfers + if (tx.getIncomingTransfers() !== undefined) tx.getIncomingTransfers().sort(MoneroWalletRpc.compareIncomingTransfers); + + // collect queried transfers, erase if excluded + for (let transfer of tx.filterTransfers(query)) { + transfers.push(transfer); + } + + // remove txs without requested transfer + if (tx.getBlock() !== undefined && tx.getOutgoingTransfer() === undefined && tx.getIncomingTransfers() === undefined) { + tx.getBlock().getTxs().splice(tx.getBlock().getTxs().indexOf(tx), 1); + } + } + + return transfers; + } + + async getOutputsAux(query) { + + // determine account and subaddress indices to be queried + let indices = new Map(); + if (query.getAccountIndex() !== undefined) { + let subaddressIndices = new Set(); + if (query.getSubaddressIndex() !== undefined) subaddressIndices.add(query.getSubaddressIndex()); + if (query.getSubaddressIndices() !== undefined) query.getSubaddressIndices().map((subaddressIdx) => subaddressIndices.add(subaddressIdx)); + indices.set(query.getAccountIndex(), subaddressIndices.size ? Array.from(subaddressIndices) : undefined); // undefined will fetch from all subaddresses + } else { + _assert.default.equal(query.getSubaddressIndex(), undefined, "Query specifies a subaddress index but not an account index"); + (0, _assert.default)(query.getSubaddressIndices() === undefined || query.getSubaddressIndices().length === 0, "Query specifies subaddress indices but not an account index"); + indices = await this.getAccountIndices(); // fetch all account indices without subaddresses + } + + // cache unique txs and blocks + let txMap = {}; + let blockMap = {}; + + // collect txs with outputs for each indicated account using `incoming_transfers` rpc call + let params = {}; + params.transfer_type = query.getIsSpent() === true ? "unavailable" : query.getIsSpent() === false ? "available" : "all"; + params.verbose = true; + for (let accountIdx of indices.keys()) { + + // send request + params.account_index = accountIdx; + params.subaddr_indices = indices.get(accountIdx); + let resp = await this.config.getServer().sendJsonRequest("incoming_transfers", params); + + // convert response to txs with outputs and merge + if (resp.result.transfers === undefined) continue; + for (let rpcOutput of resp.result.transfers) { + let tx = MoneroWalletRpc.convertRpcTxWalletWithOutput(rpcOutput); + MoneroWalletRpc.mergeTx(tx, txMap, blockMap); + } + } + + // sort txs by block height + let txs = Object.values(txMap); + txs.sort(MoneroWalletRpc.compareTxsByHeight); + + // collect queried outputs + let outputs = []; + for (let tx of txs) { + + // sort outputs + if (tx.getOutputs() !== undefined) tx.getOutputs().sort(MoneroWalletRpc.compareOutputs); + + // collect queried outputs, erase if excluded + for (let output of tx.filterOutputs(query)) outputs.push(output); + + // remove excluded txs from block + if (tx.getOutputs() === undefined && tx.getBlock() !== undefined) { + tx.getBlock().getTxs().splice(tx.getBlock().getTxs().indexOf(tx), 1); + } + } + return outputs; + } + + /** + * Common method to get key images. + * + * @param all - pecifies to get all xor only new images from last import + * @return {MoneroKeyImage[]} are the key images + */ + async rpcExportKeyImages(all) { + let resp = await this.config.getServer().sendJsonRequest("export_key_images", { all: all }); + if (!resp.result.signed_key_images) return []; + return resp.result.signed_key_images.map((rpcImage) => new _MoneroKeyImage.default(rpcImage.key_image, rpcImage.signature)); + } + + async rpcSweepAccount(config) { + + // validate config + if (config === undefined) throw new _MoneroError.default("Must provide sweep config"); + if (config.getAccountIndex() === undefined) throw new _MoneroError.default("Must provide an account index to sweep from"); + if (config.getDestinations() === undefined || config.getDestinations().length != 1) throw new _MoneroError.default("Must provide exactly one destination to sweep to"); + if (config.getDestinations()[0].getAddress() === undefined) throw new _MoneroError.default("Must provide destination address to sweep to"); + if (config.getDestinations()[0].getAmount() !== undefined) throw new _MoneroError.default("Cannot specify amount in sweep config"); + if (config.getKeyImage() !== undefined) throw new _MoneroError.default("Key image defined; use sweepOutput() to sweep an output by its key image"); + if (config.getSubaddressIndices() !== undefined && config.getSubaddressIndices().length === 0) throw new _MoneroError.default("Empty list given for subaddresses indices to sweep"); + if (config.getSweepEachSubaddress()) throw new _MoneroError.default("Cannot sweep each subaddress with RPC `sweep_all`"); + if (config.getSubtractFeeFrom() !== undefined && config.getSubtractFeeFrom().length > 0) throw new _MoneroError.default("Sweeping output does not support subtracting fees from destinations"); + + // sweep from all subaddresses if not otherwise defined + if (config.getSubaddressIndices() === undefined) { + config.setSubaddressIndices([]); + for (let subaddress of await this.getSubaddresses(config.getAccountIndex())) { + config.getSubaddressIndices().push(subaddress.getIndex()); + } + } + if (config.getSubaddressIndices().length === 0) throw new _MoneroError.default("No subaddresses to sweep from"); + + // common config params + let params = {}; + let relay = config.getRelay() === true; + params.account_index = config.getAccountIndex(); + params.subaddr_indices = config.getSubaddressIndices(); + params.address = config.getDestinations()[0].getAddress(); + (0, _assert.default)(config.getPriority() === undefined || config.getPriority() >= 0 && config.getPriority() <= 3); + params.priority = config.getPriority(); + params.payment_id = config.getPaymentId(); + params.do_not_relay = !relay; + params.below_amount = config.getBelowAmount(); + params.get_tx_keys = true; + params.get_tx_hex = true; + params.get_tx_metadata = true; + + // invoke wallet rpc `sweep_all` + let resp = await this.config.getServer().sendJsonRequest("sweep_all", params); + let result = resp.result; + + // initialize txs from response + let txSet = MoneroWalletRpc.convertRpcSentTxsToTxSet(result, undefined, config); + + // initialize remaining known fields + for (let tx of txSet.getTxs()) { + tx.setIsLocked(true); + tx.setIsConfirmed(false); + tx.setNumConfirmations(0); + tx.setRelay(relay); + tx.setInTxPool(relay); + tx.setIsRelayed(relay); + tx.setIsMinerTx(false); + tx.setIsFailed(false); + let transfer = tx.getOutgoingTransfer(); + transfer.setAccountIndex(config.getAccountIndex()); + if (config.getSubaddressIndices().length === 1) transfer.setSubaddressIndices(config.getSubaddressIndices()); + let destination = new _MoneroDestination.default(config.getDestinations()[0].getAddress(), BigInt(transfer.getAmount())); + transfer.setDestinations([destination]); + tx.setOutgoingTransfer(transfer); + tx.setPaymentId(config.getPaymentId()); + if (tx.getUnlockTime() === undefined) tx.setUnlockTime(0n); + if (tx.getRelay()) { + if (tx.getLastRelayedTimestamp() === undefined) tx.setLastRelayedTimestamp(+new Date().getTime()); // TODO (monero-wallet-rpc): provide timestamp on response; unconfirmed timestamps vary + if (tx.getIsDoubleSpendSeen() === undefined) tx.setIsDoubleSpendSeen(false); + } + } + return txSet.getTxs(); + } + + refreshListening() { + if (this.walletPoller == undefined && this.listeners.length) this.walletPoller = new WalletPoller(this); + if (this.walletPoller !== undefined) this.walletPoller.setIsPolling(this.listeners.length > 0); + } + + /** + * Poll if listening. + */ + async poll() { + if (this.walletPoller !== undefined && this.walletPoller.isPolling) await this.walletPoller.poll(); + } + + // ---------------------------- PRIVATE STATIC ------------------------------ + + static normalizeConfig(uriOrConfig, username, password) { + let config = undefined; + if (typeof uriOrConfig === "string" || uriOrConfig.uri) config = new _MoneroWalletConfig.default({ server: new _MoneroRpcConnection.default(uriOrConfig, username, password) });else + if (_GenUtils.default.isArray(uriOrConfig)) config = new _MoneroWalletConfig.default({ cmd: uriOrConfig });else + config = new _MoneroWalletConfig.default(uriOrConfig); + if (config.proxyToWorker === undefined) config.proxyToWorker = true; + return config; + } + + /** + * Remove criteria which requires looking up other transfers/outputs to + * fulfill query. + * + * @param {MoneroTxQuery} query - the query to decontextualize + * @return {MoneroTxQuery} a reference to the query for convenience + */ + static decontextualize(query) { + query.setIsIncoming(undefined); + query.setIsOutgoing(undefined); + query.setTransferQuery(undefined); + query.setInputQuery(undefined); + query.setOutputQuery(undefined); + return query; + } + + static isContextual(query) { + if (!query) return false; + if (!query.getTxQuery()) return false; + if (query.getTxQuery().getIsIncoming() !== undefined) return true; // requires getting other transfers + if (query.getTxQuery().getIsOutgoing() !== undefined) return true; + if (query instanceof _MoneroTransferQuery.default) { + if (query.getTxQuery().getOutputQuery() !== undefined) return true; // requires getting other outputs + } else if (query instanceof _MoneroOutputQuery.default) { + if (query.getTxQuery().getTransferQuery() !== undefined) return true; // requires getting other transfers + } else { + throw new _MoneroError.default("query must be tx or transfer query"); + } + return false; + } + + static convertRpcAccount(rpcAccount) { + let account = new _MoneroAccount.default(); + for (let key of Object.keys(rpcAccount)) { + let val = rpcAccount[key]; + if (key === "account_index") account.setIndex(val);else + if (key === "balance") account.setBalance(BigInt(val));else + if (key === "unlocked_balance") account.setUnlockedBalance(BigInt(val));else + if (key === "base_address") account.setPrimaryAddress(val);else + if (key === "tag") account.setTag(val);else + if (key === "label") {} // label belongs to first subaddress + else console.log("WARNING: ignoring unexpected account field: " + key + ": " + val); + } + if ("" === account.getTag()) account.setTag(undefined); + return account; + } + + static convertRpcSubaddress(rpcSubaddress) { + let subaddress = new _MoneroSubaddress.default(); + for (let key of Object.keys(rpcSubaddress)) { + let val = rpcSubaddress[key]; + if (key === "account_index") subaddress.setAccountIndex(val);else + if (key === "address_index") subaddress.setIndex(val);else + if (key === "address") subaddress.setAddress(val);else + if (key === "balance") subaddress.setBalance(BigInt(val));else + if (key === "unlocked_balance") subaddress.setUnlockedBalance(BigInt(val));else + if (key === "num_unspent_outputs") subaddress.setNumUnspentOutputs(val);else + if (key === "label") {if (val) subaddress.setLabel(val);} else + if (key === "used") subaddress.setIsUsed(val);else + if (key === "blocks_to_unlock") subaddress.setNumBlocksToUnlock(val);else + if (key == "time_to_unlock") {} // ignoring + else console.log("WARNING: ignoring unexpected subaddress field: " + key + ": " + val); + } + return subaddress; + } + + /** + * Initializes a sent transaction. + * + * TODO: remove copyDestinations after >18.3.1 when subtractFeeFrom fully supported + * + * @param {MoneroTxConfig} config - send config + * @param {MoneroTxWallet} [tx] - existing transaction to initialize (optional) + * @param {boolean} copyDestinations - copies config destinations if true + * @return {MoneroTxWallet} is the initialized send tx + */ + static initSentTxWallet(config, tx, copyDestinations) { + if (!tx) tx = new _MoneroTxWallet.default(); + let relay = config.getRelay() === true; + tx.setIsOutgoing(true); + tx.setIsConfirmed(false); + tx.setNumConfirmations(0); + tx.setInTxPool(relay); + tx.setRelay(relay); + tx.setIsRelayed(relay); + tx.setIsMinerTx(false); + tx.setIsFailed(false); + tx.setIsLocked(true); + tx.setRingSize(_MoneroUtils.default.RING_SIZE); + let transfer = new _MoneroOutgoingTransfer.default(); + transfer.setTx(tx); + if (config.getSubaddressIndices() && config.getSubaddressIndices().length === 1) transfer.setSubaddressIndices(config.getSubaddressIndices().slice(0)); // we know src subaddress indices iff config specifies 1 + if (copyDestinations) { + let destCopies = []; + for (let dest of config.getDestinations()) destCopies.push(dest.copy()); + transfer.setDestinations(destCopies); + } + tx.setOutgoingTransfer(transfer); + tx.setPaymentId(config.getPaymentId()); + if (tx.getUnlockTime() === undefined) tx.setUnlockTime(0n); + if (config.getRelay()) { + if (tx.getLastRelayedTimestamp() === undefined) tx.setLastRelayedTimestamp(+new Date().getTime()); // TODO (monero-wallet-rpc): provide timestamp on response; unconfirmed timestamps vary + if (tx.getIsDoubleSpendSeen() === undefined) tx.setIsDoubleSpendSeen(false); + } + return tx; + } + + /** + * Initializes a tx set from a RPC map excluding txs. + * + * @param rpcMap - map to initialize the tx set from + * @return MoneroTxSet - initialized tx set + * @return the resulting tx set + */ + static convertRpcTxSet(rpcMap) { + let txSet = new _MoneroTxSet.default(); + txSet.setMultisigTxHex(rpcMap.multisig_txset); + txSet.setUnsignedTxHex(rpcMap.unsigned_txset); + txSet.setSignedTxHex(rpcMap.signed_txset); + if (txSet.getMultisigTxHex() !== undefined && txSet.getMultisigTxHex().length === 0) txSet.setMultisigTxHex(undefined); + if (txSet.getUnsignedTxHex() !== undefined && txSet.getUnsignedTxHex().length === 0) txSet.setUnsignedTxHex(undefined); + if (txSet.getSignedTxHex() !== undefined && txSet.getSignedTxHex().length === 0) txSet.setSignedTxHex(undefined); + return txSet; + } + + /** + * Initializes a MoneroTxSet from a list of rpc txs. + * + * @param rpcTxs - rpc txs to initialize the set from + * @param txs - existing txs to further initialize (optional) + * @param config - tx config + * @return the converted tx set + */ + static convertRpcSentTxsToTxSet(rpcTxs, txs, config) { + + // build shared tx set + let txSet = MoneroWalletRpc.convertRpcTxSet(rpcTxs); + + // get number of txs + let numTxs = rpcTxs.fee_list ? rpcTxs.fee_list.length : rpcTxs.tx_hash_list ? rpcTxs.tx_hash_list.length : 0; + + // done if rpc response contains no txs + if (numTxs === 0) { + _assert.default.equal(txs, undefined); + return txSet; + } + + // initialize txs if none given + if (txs) txSet.setTxs(txs);else + { + txs = []; + for (let i = 0; i < numTxs; i++) txs.push(new _MoneroTxWallet.default()); + } + for (let tx of txs) { + tx.setTxSet(txSet); + tx.setIsOutgoing(true); + } + txSet.setTxs(txs); + + // initialize txs from rpc lists + for (let key of Object.keys(rpcTxs)) { + let val = rpcTxs[key]; + if (key === "tx_hash_list") for (let i = 0; i < val.length; i++) txs[i].setHash(val[i]);else + if (key === "tx_key_list") for (let i = 0; i < val.length; i++) txs[i].setKey(val[i]);else + if (key === "tx_blob_list") for (let i = 0; i < val.length; i++) txs[i].setFullHex(val[i]);else + if (key === "tx_metadata_list") for (let i = 0; i < val.length; i++) txs[i].setMetadata(val[i]);else + if (key === "fee_list") for (let i = 0; i < val.length; i++) txs[i].setFee(BigInt(val[i]));else + if (key === "weight_list") for (let i = 0; i < val.length; i++) txs[i].setWeight(val[i]);else + if (key === "amount_list") { + for (let i = 0; i < val.length; i++) { + if (txs[i].getOutgoingTransfer() == undefined) txs[i].setOutgoingTransfer(new _MoneroOutgoingTransfer.default().setTx(txs[i])); + txs[i].getOutgoingTransfer().setAmount(BigInt(val[i])); + } + } else + if (key === "multisig_txset" || key === "unsigned_txset" || key === "signed_txset") {} // handled elsewhere + else if (key === "spent_key_images_list") { + let inputKeyImagesList = val; + for (let i = 0; i < inputKeyImagesList.length; i++) { + _GenUtils.default.assertTrue(txs[i].getInputs() === undefined); + txs[i].setInputs([]); + for (let inputKeyImage of inputKeyImagesList[i]["key_images"]) { + txs[i].getInputs().push(new _MoneroOutputWallet.default().setKeyImage(new _MoneroKeyImage.default().setHex(inputKeyImage)).setTx(txs[i])); + } + } + } else + if (key === "amounts_by_dest_list") { + let amountsByDestList = val; + let destinationIdx = 0; + for (let txIdx = 0; txIdx < amountsByDestList.length; txIdx++) { + let amountsByDest = amountsByDestList[txIdx]["amounts"]; + if (txs[txIdx].getOutgoingTransfer() === undefined) txs[txIdx].setOutgoingTransfer(new _MoneroOutgoingTransfer.default().setTx(txs[txIdx])); + txs[txIdx].getOutgoingTransfer().setDestinations([]); + for (let amount of amountsByDest) { + if (config.getDestinations().length === 1) txs[txIdx].getOutgoingTransfer().getDestinations().push(new _MoneroDestination.default(config.getDestinations()[0].getAddress(), BigInt(amount))); // sweeping can create multiple txs with one address + else txs[txIdx].getOutgoingTransfer().getDestinations().push(new _MoneroDestination.default(config.getDestinations()[destinationIdx++].getAddress(), BigInt(amount))); + } + } + } else + console.log("WARNING: ignoring unexpected transaction field: " + key + ": " + val); + } + + return txSet; + } + + /** + * Converts a rpc tx with a transfer to a tx set with a tx and transfer. + * + * @param rpcTx - rpc tx to build from + * @param tx - existing tx to continue initializing (optional) + * @param isOutgoing - specifies if the tx is outgoing if true, incoming if false, or decodes from type if undefined + * @param config - tx config + * @return the initialized tx set with a tx + */ + static convertRpcTxToTxSet(rpcTx, tx, isOutgoing, config) { + let txSet = MoneroWalletRpc.convertRpcTxSet(rpcTx); + txSet.setTxs([MoneroWalletRpc.convertRpcTxWithTransfer(rpcTx, tx, isOutgoing, config).setTxSet(txSet)]); + return txSet; + } + + /** + * Builds a MoneroTxWallet from a RPC tx. + * + * @param rpcTx - rpc tx to build from + * @param tx - existing tx to continue initializing (optional) + * @param isOutgoing - specifies if the tx is outgoing if true, incoming if false, or decodes from type if undefined + * @param config - tx config + * @return {MoneroTxWallet} is the initialized tx + */ + static convertRpcTxWithTransfer(rpcTx, tx, isOutgoing, config) {// TODO: change everything to safe set + + // initialize tx to return + if (!tx) tx = new _MoneroTxWallet.default(); + + // initialize tx state from rpc type + if (rpcTx.type !== undefined) isOutgoing = MoneroWalletRpc.decodeRpcType(rpcTx.type, tx);else + _assert.default.equal(typeof isOutgoing, "boolean", "Must indicate if tx is outgoing (true) xor incoming (false) since unknown"); + + // TODO: safe set + // initialize remaining fields TODO: seems this should be part of common function with DaemonRpc.convertRpcTx + let header; + let transfer; + for (let key of Object.keys(rpcTx)) { + let val = rpcTx[key]; + if (key === "txid") tx.setHash(val);else + if (key === "tx_hash") tx.setHash(val);else + if (key === "fee") tx.setFee(BigInt(val));else + if (key === "note") {if (val) tx.setNote(val);} else + if (key === "tx_key") tx.setKey(val);else + if (key === "type") {} // type already handled + else if (key === "tx_size") tx.setSize(val);else + if (key === "unlock_time") tx.setUnlockTime(val);else + if (key === "weight") tx.setWeight(val);else + if (key === "locked") tx.setIsLocked(val);else + if (key === "tx_blob") tx.setFullHex(val);else + if (key === "tx_metadata") tx.setMetadata(val);else + if (key === "double_spend_seen") tx.setIsDoubleSpendSeen(val);else + if (key === "block_height" || key === "height") { + if (tx.getIsConfirmed()) { + if (!header) header = new _MoneroBlockHeader.default(); + header.setHeight(val); + } + } else + if (key === "timestamp") { + if (tx.getIsConfirmed()) { + if (!header) header = new _MoneroBlockHeader.default(); + header.setTimestamp(val); + } else { + + // timestamp of unconfirmed tx is current request time + }} else + if (key === "confirmations") tx.setNumConfirmations(val);else + if (key === "suggested_confirmations_threshold") { + if (transfer === undefined) transfer = (isOutgoing ? new _MoneroOutgoingTransfer.default() : new _MoneroIncomingTransfer.default()).setTx(tx); + if (!isOutgoing) transfer.setNumSuggestedConfirmations(val); + } else + if (key === "amount") { + if (transfer === undefined) transfer = (isOutgoing ? new _MoneroOutgoingTransfer.default() : new _MoneroIncomingTransfer.default()).setTx(tx); + transfer.setAmount(BigInt(val)); + } else + if (key === "amounts") {} // ignoring, amounts sum to amount + else if (key === "address") { + if (!isOutgoing) { + if (!transfer) transfer = new _MoneroIncomingTransfer.default().setTx(tx); + transfer.setAddress(val); + } + } else + if (key === "payment_id") { + if ("" !== val && _MoneroTxWallet.default.DEFAULT_PAYMENT_ID !== val) tx.setPaymentId(val); // default is undefined + } else + if (key === "subaddr_index") (0, _assert.default)(rpcTx.subaddr_indices); // handled by subaddr_indices + else if (key === "subaddr_indices") { + if (!transfer) transfer = (isOutgoing ? new _MoneroOutgoingTransfer.default() : new _MoneroIncomingTransfer.default()).setTx(tx); + let rpcIndices = val; + transfer.setAccountIndex(rpcIndices[0].major); + if (isOutgoing) { + let subaddressIndices = []; + for (let rpcIndex of rpcIndices) subaddressIndices.push(rpcIndex.minor); + transfer.setSubaddressIndices(subaddressIndices); + } else { + _assert.default.equal(rpcIndices.length, 1); + transfer.setSubaddressIndex(rpcIndices[0].minor); + } + } else + if (key === "destinations" || key == "recipients") { + (0, _assert.default)(isOutgoing); + let destinations = []; + for (let rpcDestination of val) { + let destination = new _MoneroDestination.default(); + destinations.push(destination); + for (let destinationKey of Object.keys(rpcDestination)) { + if (destinationKey === "address") destination.setAddress(rpcDestination[destinationKey]);else + if (destinationKey === "amount") destination.setAmount(BigInt(rpcDestination[destinationKey]));else + throw new _MoneroError.default("Unrecognized transaction destination field: " + destinationKey); + } + } + if (transfer === undefined) transfer = new _MoneroOutgoingTransfer.default({ tx: tx }); + transfer.setDestinations(destinations); + } else + if (key === "multisig_txset" && val !== undefined) {} // handled elsewhere; this method only builds a tx wallet + else if (key === "unsigned_txset" && val !== undefined) {} // handled elsewhere; this method only builds a tx wallet + else if (key === "amount_in") tx.setInputSum(BigInt(val));else + if (key === "amount_out") tx.setOutputSum(BigInt(val));else + if (key === "change_address") tx.setChangeAddress(val === "" ? undefined : val);else + if (key === "change_amount") tx.setChangeAmount(BigInt(val));else + if (key === "dummy_outputs") tx.setNumDummyOutputs(val);else + if (key === "extra") tx.setExtraHex(val);else + if (key === "ring_size") tx.setRingSize(val);else + if (key === "spent_key_images") { + let inputKeyImages = val.key_images; + _GenUtils.default.assertTrue(tx.getInputs() === undefined); + tx.setInputs([]); + for (let inputKeyImage of inputKeyImages) { + tx.getInputs().push(new _MoneroOutputWallet.default().setKeyImage(new _MoneroKeyImage.default().setHex(inputKeyImage)).setTx(tx)); + } + } else + if (key === "amounts_by_dest") { + _GenUtils.default.assertTrue(isOutgoing); + let amountsByDest = val.amounts; + _assert.default.equal(config.getDestinations().length, amountsByDest.length); + if (transfer === undefined) transfer = new _MoneroOutgoingTransfer.default().setTx(tx); + transfer.setDestinations([]); + for (let i = 0; i < config.getDestinations().length; i++) { + transfer.getDestinations().push(new _MoneroDestination.default(config.getDestinations()[i].getAddress(), BigInt(amountsByDest[i]))); + } + } else + console.log("WARNING: ignoring unexpected transaction field with transfer: " + key + ": " + val); + } + + // link block and tx + if (header) tx.setBlock(new _MoneroBlock.default(header).setTxs([tx])); + + // initialize final fields + if (transfer) { + if (tx.getIsConfirmed() === undefined) tx.setIsConfirmed(false); + if (!transfer.getTx().getIsConfirmed()) tx.setNumConfirmations(0); + if (isOutgoing) { + tx.setIsOutgoing(true); + if (tx.getOutgoingTransfer()) { + if (transfer.getDestinations()) tx.getOutgoingTransfer().setDestinations(undefined); // overwrite to avoid reconcile error TODO: remove after >18.3.1 when amounts_by_dest supported + tx.getOutgoingTransfer().merge(transfer); + } else + tx.setOutgoingTransfer(transfer); + } else { + tx.setIsIncoming(true); + tx.setIncomingTransfers([transfer]); + } + } + + // return initialized transaction + return tx; + } + + static convertRpcTxWalletWithOutput(rpcOutput) { + + // initialize tx + let tx = new _MoneroTxWallet.default(); + tx.setIsConfirmed(true); + tx.setIsRelayed(true); + tx.setIsFailed(false); + + // initialize output + let output = new _MoneroOutputWallet.default({ tx: tx }); + for (let key of Object.keys(rpcOutput)) { + let val = rpcOutput[key]; + if (key === "amount") output.setAmount(BigInt(val));else + if (key === "spent") output.setIsSpent(val);else + if (key === "key_image") {if ("" !== val) output.setKeyImage(new _MoneroKeyImage.default(val));} else + if (key === "global_index") output.setIndex(val);else + if (key === "tx_hash") tx.setHash(val);else + if (key === "unlocked") tx.setIsLocked(!val);else + if (key === "frozen") output.setIsFrozen(val);else + if (key === "pubkey") output.setStealthPublicKey(val);else + if (key === "subaddr_index") { + output.setAccountIndex(val.major); + output.setSubaddressIndex(val.minor); + } else + if (key === "block_height") tx.setBlock(new _MoneroBlock.default().setHeight(val).setTxs([tx]));else + console.log("WARNING: ignoring unexpected transaction field: " + key + ": " + val); + } + + // initialize tx with output + tx.setOutputs([output]); + return tx; + } + + static convertRpcDescribeTransfer(rpcDescribeTransferResult) { + let txSet = new _MoneroTxSet.default(); + for (let key of Object.keys(rpcDescribeTransferResult)) { + let val = rpcDescribeTransferResult[key]; + if (key === "desc") { + txSet.setTxs([]); + for (let txMap of val) { + let tx = MoneroWalletRpc.convertRpcTxWithTransfer(txMap, undefined, true); + tx.setTxSet(txSet); + txSet.getTxs().push(tx); + } + } else + if (key === "summary") {} // TODO: support tx set summary fields? + else console.log("WARNING: ignoring unexpected descdribe transfer field: " + key + ": " + val); + } + return txSet; + } + + /** + * Decodes a "type" from monero-wallet-rpc to initialize type and state + * fields in the given transaction. + * + * TODO: these should be safe set + * + * @param rpcType is the type to decode + * @param tx is the transaction to decode known fields to + * @return {boolean} true if the rpc type indicates outgoing xor incoming + */ + static decodeRpcType(rpcType, tx) { + let isOutgoing; + if (rpcType === "in") { + isOutgoing = false; + tx.setIsConfirmed(true); + tx.setInTxPool(false); + tx.setIsRelayed(true); + tx.setRelay(true); + tx.setIsFailed(false); + tx.setIsMinerTx(false); + } else if (rpcType === "out") { + isOutgoing = true; + tx.setIsConfirmed(true); + tx.setInTxPool(false); + tx.setIsRelayed(true); + tx.setRelay(true); + tx.setIsFailed(false); + tx.setIsMinerTx(false); + } else if (rpcType === "pool") { + isOutgoing = false; + tx.setIsConfirmed(false); + tx.setInTxPool(true); + tx.setIsRelayed(true); + tx.setRelay(true); + tx.setIsFailed(false); + tx.setIsMinerTx(false); // TODO: but could it be? + } else if (rpcType === "pending") { + isOutgoing = true; + tx.setIsConfirmed(false); + tx.setInTxPool(true); + tx.setIsRelayed(true); + tx.setRelay(true); + tx.setIsFailed(false); + tx.setIsMinerTx(false); + } else if (rpcType === "block") { + isOutgoing = false; + tx.setIsConfirmed(true); + tx.setInTxPool(false); + tx.setIsRelayed(true); + tx.setRelay(true); + tx.setIsFailed(false); + tx.setIsMinerTx(true); + } else if (rpcType === "failed") { + isOutgoing = true; + tx.setIsConfirmed(false); + tx.setInTxPool(false); + tx.setIsRelayed(true); + tx.setRelay(true); + tx.setIsFailed(true); + tx.setIsMinerTx(false); + } else { + throw new _MoneroError.default("Unrecognized transfer type: " + rpcType); + } + return isOutgoing; + } + + /** + * Merges a transaction into a unique set of transactions. + * + * @param {MoneroTxWallet} tx - the transaction to merge into the existing txs + * @param {Object} txMap - maps tx hashes to txs + * @param {Object} blockMap - maps block heights to blocks + */ + static mergeTx(tx, txMap, blockMap) { + (0, _assert.default)(tx.getHash() !== undefined); + + // merge tx + let aTx = txMap[tx.getHash()]; + if (aTx === undefined) txMap[tx.getHash()] = tx; // cache new tx + else aTx.merge(tx); // merge with existing tx + + // merge tx's block if confirmed + if (tx.getHeight() !== undefined) { + let aBlock = blockMap[tx.getHeight()]; + if (aBlock === undefined) blockMap[tx.getHeight()] = tx.getBlock(); // cache new block + else aBlock.merge(tx.getBlock()); // merge with existing block + } + } + + /** + * Compares two transactions by their height. + */ + static compareTxsByHeight(tx1, tx2) { + if (tx1.getHeight() === undefined && tx2.getHeight() === undefined) return 0; // both unconfirmed + else if (tx1.getHeight() === undefined) return 1; // tx1 is unconfirmed + else if (tx2.getHeight() === undefined) return -1; // tx2 is unconfirmed + let diff = tx1.getHeight() - tx2.getHeight(); + if (diff !== 0) return diff; + return tx1.getBlock().getTxs().indexOf(tx1) - tx2.getBlock().getTxs().indexOf(tx2); // txs are in the same block so retain their original order + } + + /** + * Compares two transfers by ascending account and subaddress indices. + */ + static compareIncomingTransfers(t1, t2) { + if (t1.getAccountIndex() < t2.getAccountIndex()) return -1;else + if (t1.getAccountIndex() === t2.getAccountIndex()) return t1.getSubaddressIndex() - t2.getSubaddressIndex(); + return 1; + } + + /** + * Compares two outputs by ascending account and subaddress indices. + */ + static compareOutputs(o1, o2) { + + // compare by height + let heightComparison = MoneroWalletRpc.compareTxsByHeight(o1.getTx(), o2.getTx()); + if (heightComparison !== 0) return heightComparison; + + // compare by account index, subaddress index, output index, then key image hex + let compare = o1.getAccountIndex() - o2.getAccountIndex(); + if (compare !== 0) return compare; + compare = o1.getSubaddressIndex() - o2.getSubaddressIndex(); + if (compare !== 0) return compare; + compare = o1.getIndex() - o2.getIndex(); + if (compare !== 0) return compare; + return o1.getKeyImage().getHex().localeCompare(o2.getKeyImage().getHex()); + } +} + +/** + * Polls monero-wallet-rpc to provide listener notifications. + * + * @private + */exports.default = MoneroWalletRpc; +class WalletPoller { + + // instance variables + + + + + + + + + + + + constructor(wallet) { + let that = this; + this.wallet = wallet; + this.looper = new _TaskLooper.default(async function () {await that.poll();}); + this.prevLockedTxs = []; + this.prevUnconfirmedNotifications = new Set(); // tx hashes of previous notifications + this.prevConfirmedNotifications = new Set(); // tx hashes of previously confirmed but not yet unlocked notifications + this.threadPool = new _ThreadPool.default(1); // synchronize polls + this.numPolling = 0; + } + + setIsPolling(isPolling) { + this.isPolling = isPolling; + if (isPolling) this.looper.start(this.wallet.getSyncPeriodInMs());else + this.looper.stop(); + } + + setPeriodInMs(periodInMs) { + this.looper.setPeriodInMs(periodInMs); + } + + async poll() { + + // skip if next poll is queued + if (this.numPolling > 1) return; + this.numPolling++; + + // synchronize polls + let that = this; + return this.threadPool.submit(async function () { + try { + + // skip if wallet is closed + if (await that.wallet.isClosed()) { + that.numPolling--; + return; + } + + // take initial snapshot + if (that.prevBalances === undefined) { + that.prevHeight = await that.wallet.getHeight(); + that.prevLockedTxs = await that.wallet.getTxs(new _MoneroTxQuery.default().setIsLocked(true)); + that.prevBalances = await that.wallet.getBalances(); + that.numPolling--; + return; + } + + // announce height changes + let height = await that.wallet.getHeight(); + if (that.prevHeight !== height) { + for (let i = that.prevHeight; i < height; i++) await that.onNewBlock(i); + that.prevHeight = height; + } + + // get locked txs for comparison to previous + let minHeight = Math.max(0, height - 70); // only monitor recent txs + let lockedTxs = await that.wallet.getTxs(new _MoneroTxQuery.default().setIsLocked(true).setMinHeight(minHeight).setIncludeOutputs(true)); + + // collect hashes of txs no longer locked + let noLongerLockedHashes = []; + for (let prevLockedTx of that.prevLockedTxs) { + if (that.getTx(lockedTxs, prevLockedTx.getHash()) === undefined) { + noLongerLockedHashes.push(prevLockedTx.getHash()); + } + } + + // save locked txs for next comparison + that.prevLockedTxs = lockedTxs; + + // fetch txs which are no longer locked + let unlockedTxs = noLongerLockedHashes.length === 0 ? [] : await that.wallet.getTxs(new _MoneroTxQuery.default().setIsLocked(false).setMinHeight(minHeight).setHashes(noLongerLockedHashes).setIncludeOutputs(true)); + + // announce new unconfirmed and confirmed outputs + for (let lockedTx of lockedTxs) { + let searchSet = lockedTx.getIsConfirmed() ? that.prevConfirmedNotifications : that.prevUnconfirmedNotifications; + let unannounced = !searchSet.has(lockedTx.getHash()); + searchSet.add(lockedTx.getHash()); + if (unannounced) await that.notifyOutputs(lockedTx); + } + + // announce new unlocked outputs + for (let unlockedTx of unlockedTxs) { + that.prevUnconfirmedNotifications.delete(unlockedTx.getHash()); + that.prevConfirmedNotifications.delete(unlockedTx.getHash()); + await that.notifyOutputs(unlockedTx); + } + + // announce balance changes + await that.checkForChangedBalances(); + that.numPolling--; + } catch (err) { + that.numPolling--; + console.error("Failed to background poll wallet '" + (await that.wallet.getPath()) + "': " + err.message); + } + }); + } + + async onNewBlock(height) { + await this.wallet.announceNewBlock(height); + } + + async notifyOutputs(tx) { + + // notify spent outputs // TODO (monero-project): monero-wallet-rpc does not allow scrape of tx inputs so providing one input with outgoing amount + if (tx.getOutgoingTransfer() !== undefined) { + (0, _assert.default)(tx.getInputs() === undefined); + let output = new _MoneroOutputWallet.default(). + setAmount(tx.getOutgoingTransfer().getAmount() + tx.getFee()). + setAccountIndex(tx.getOutgoingTransfer().getAccountIndex()). + setSubaddressIndex(tx.getOutgoingTransfer().getSubaddressIndices().length === 1 ? tx.getOutgoingTransfer().getSubaddressIndices()[0] : undefined) // initialize if transfer sourced from single subaddress + .setTx(tx); + tx.setInputs([output]); + await this.wallet.announceOutputSpent(output); + } + + // notify received outputs + if (tx.getIncomingTransfers() !== undefined) { + if (tx.getOutputs() !== undefined && tx.getOutputs().length > 0) {// TODO (monero-project): outputs only returned for confirmed txs + for (let output of tx.getOutputs()) { + await this.wallet.announceOutputReceived(output); + } + } else {// TODO (monero-project): monero-wallet-rpc does not allow scrape of unconfirmed received outputs so using incoming transfer values + let outputs = []; + for (let transfer of tx.getIncomingTransfers()) { + outputs.push(new _MoneroOutputWallet.default(). + setAccountIndex(transfer.getAccountIndex()). + setSubaddressIndex(transfer.getSubaddressIndex()). + setAmount(transfer.getAmount()). + setTx(tx)); + } + tx.setOutputs(outputs); + for (let output of tx.getOutputs()) { + await this.wallet.announceOutputReceived(output); + } + } + } + } + + getTx(txs, txHash) { + for (let tx of txs) if (txHash === tx.getHash()) return tx; + return undefined; + } + + async checkForChangedBalances() { + let balances = await this.wallet.getBalances(); + if (balances[0] !== this.prevBalances[0] || balances[1] !== this.prevBalances[1]) { + this.prevBalances = balances; + await this.wallet.announceBalancesChanged(balances[0], balances[1]); + return true; + } + return false; + } +} +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTGlicmFyeVV0aWxzIiwiX1Rhc2tMb29wZXIiLCJfTW9uZXJvQWNjb3VudCIsIl9Nb25lcm9BY2NvdW50VGFnIiwiX01vbmVyb0FkZHJlc3NCb29rRW50cnkiLCJfTW9uZXJvQmxvY2siLCJfTW9uZXJvQmxvY2tIZWFkZXIiLCJfTW9uZXJvQ2hlY2tSZXNlcnZlIiwiX01vbmVyb0NoZWNrVHgiLCJfTW9uZXJvRGVzdGluYXRpb24iLCJfTW9uZXJvRXJyb3IiLCJfTW9uZXJvSW5jb21pbmdUcmFuc2ZlciIsIl9Nb25lcm9JbnRlZ3JhdGVkQWRkcmVzcyIsIl9Nb25lcm9LZXlJbWFnZSIsIl9Nb25lcm9LZXlJbWFnZUltcG9ydFJlc3VsdCIsIl9Nb25lcm9NdWx0aXNpZ0luZm8iLCJfTW9uZXJvTXVsdGlzaWdJbml0UmVzdWx0IiwiX01vbmVyb011bHRpc2lnU2lnblJlc3VsdCIsIl9Nb25lcm9PdXRnb2luZ1RyYW5zZmVyIiwiX01vbmVyb091dHB1dFF1ZXJ5IiwiX01vbmVyb091dHB1dFdhbGxldCIsIl9Nb25lcm9ScGNDb25uZWN0aW9uIiwiX01vbmVyb1JwY0Vycm9yIiwiX01vbmVyb1N1YmFkZHJlc3MiLCJfTW9uZXJvU3luY1Jlc3VsdCIsIl9Nb25lcm9UcmFuc2ZlclF1ZXJ5IiwiX01vbmVyb1R4Q29uZmlnIiwiX01vbmVyb1R4UXVlcnkiLCJfTW9uZXJvVHhTZXQiLCJfTW9uZXJvVHhXYWxsZXQiLCJfTW9uZXJvVXRpbHMiLCJfTW9uZXJvVmVyc2lvbiIsIl9Nb25lcm9XYWxsZXQiLCJfTW9uZXJvV2FsbGV0Q29uZmlnIiwiX01vbmVyb1dhbGxldExpc3RlbmVyIiwiX01vbmVyb01lc3NhZ2VTaWduYXR1cmVUeXBlIiwiX01vbmVyb01lc3NhZ2VTaWduYXR1cmVSZXN1bHQiLCJfVGhyZWFkUG9vbCIsIl9Tc2xPcHRpb25zIiwiX2dldFJlcXVpcmVXaWxkY2FyZENhY2hlIiwibm9kZUludGVyb3AiLCJXZWFrTWFwIiwiY2FjaGVCYWJlbEludGVyb3AiLCJjYWNoZU5vZGVJbnRlcm9wIiwiX2ludGVyb3BSZXF1aXJlV2lsZGNhcmQiLCJvYmoiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImNhY2hlIiwiaGFzIiwiZ2V0IiwibmV3T2JqIiwiaGFzUHJvcGVydHlEZXNjcmlwdG9yIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJrZXkiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJkZXNjIiwic2V0IiwiTW9uZXJvV2FsbGV0UnBjIiwiTW9uZXJvV2FsbGV0IiwiREVGQVVMVF9TWU5DX1BFUklPRF9JTl9NUyIsImNvbnN0cnVjdG9yIiwiY29uZmlnIiwiYWRkcmVzc0NhY2hlIiwic3luY1BlcmlvZEluTXMiLCJnZXRQcm9jZXNzIiwicHJvY2VzcyIsInN0b3BQcm9jZXNzIiwiZm9yY2UiLCJ1bmRlZmluZWQiLCJNb25lcm9FcnJvciIsImxpc3RlbmVyc0NvcHkiLCJHZW5VdGlscyIsImNvcHlBcnJheSIsImdldExpc3RlbmVycyIsImxpc3RlbmVyIiwicmVtb3ZlTGlzdGVuZXIiLCJraWxsUHJvY2VzcyIsImdldFJwY0Nvbm5lY3Rpb24iLCJnZXRTZXJ2ZXIiLCJvcGVuV2FsbGV0IiwicGF0aE9yQ29uZmlnIiwicGFzc3dvcmQiLCJNb25lcm9XYWxsZXRDb25maWciLCJwYXRoIiwiZ2V0UGF0aCIsInNlbmRKc29uUmVxdWVzdCIsImZpbGVuYW1lIiwiZ2V0UGFzc3dvcmQiLCJjbGVhciIsImdldENvbm5lY3Rpb25NYW5hZ2VyIiwic2V0Q29ubmVjdGlvbk1hbmFnZXIiLCJzZXREYWVtb25Db25uZWN0aW9uIiwiY3JlYXRlV2FsbGV0IiwiY29uZmlnTm9ybWFsaXplZCIsImdldFNlZWQiLCJnZXRQcmltYXJ5QWRkcmVzcyIsImdldFByaXZhdGVWaWV3S2V5IiwiZ2V0UHJpdmF0ZVNwZW5kS2V5IiwiZ2V0TmV0d29ya1R5cGUiLCJnZXRBY2NvdW50TG9va2FoZWFkIiwiZ2V0U3ViYWRkcmVzc0xvb2thaGVhZCIsInNldFBhc3N3b3JkIiwic2V0U2VydmVyIiwiZ2V0Q29ubmVjdGlvbiIsImNyZWF0ZVdhbGxldEZyb21TZWVkIiwiY3JlYXRlV2FsbGV0RnJvbUtleXMiLCJjcmVhdGVXYWxsZXRSYW5kb20iLCJnZXRTZWVkT2Zmc2V0IiwiZ2V0UmVzdG9yZUhlaWdodCIsImdldFNhdmVDdXJyZW50IiwiZ2V0TGFuZ3VhZ2UiLCJzZXRMYW5ndWFnZSIsIkRFRkFVTFRfTEFOR1VBR0UiLCJwYXJhbXMiLCJsYW5ndWFnZSIsImVyciIsImhhbmRsZUNyZWF0ZVdhbGxldEVycm9yIiwic2VlZCIsInNlZWRfb2Zmc2V0IiwiZW5hYmxlX211bHRpc2lnX2V4cGVyaW1lbnRhbCIsImdldElzTXVsdGlzaWciLCJyZXN0b3JlX2hlaWdodCIsImF1dG9zYXZlX2N1cnJlbnQiLCJzZXRSZXN0b3JlSGVpZ2h0IiwiYWRkcmVzcyIsInZpZXdrZXkiLCJzcGVuZGtleSIsIm5hbWUiLCJtZXNzYWdlIiwidG9Mb3dlckNhc2UiLCJpbmNsdWRlcyIsIk1vbmVyb1JwY0Vycm9yIiwiZ2V0Q29kZSIsImdldFJwY01ldGhvZCIsImdldFJwY1BhcmFtcyIsImlzVmlld09ubHkiLCJrZXlfdHlwZSIsImUiLCJ1cmlPckNvbm5lY3Rpb24iLCJpc1RydXN0ZWQiLCJzc2xPcHRpb25zIiwiY29ubmVjdGlvbiIsIk1vbmVyb1JwY0Nvbm5lY3Rpb24iLCJTc2xPcHRpb25zIiwiZ2V0VXJpIiwidXNlcm5hbWUiLCJnZXRVc2VybmFtZSIsInRydXN0ZWQiLCJzc2xfc3VwcG9ydCIsInNzbF9wcml2YXRlX2tleV9wYXRoIiwiZ2V0UHJpdmF0ZUtleVBhdGgiLCJzc2xfY2VydGlmaWNhdGVfcGF0aCIsImdldENlcnRpZmljYXRlUGF0aCIsInNzbF9jYV9maWxlIiwiZ2V0Q2VydGlmaWNhdGVBdXRob3JpdHlGaWxlIiwic3NsX2FsbG93ZWRfZmluZ2VycHJpbnRzIiwiZ2V0QWxsb3dlZEZpbmdlcnByaW50cyIsInNzbF9hbGxvd19hbnlfY2VydCIsImdldEFsbG93QW55Q2VydCIsInByb3h5IiwiZ2V0UHJveHlVcmkiLCJkYWVtb25Db25uZWN0aW9uIiwiZ2V0RGFlbW9uQ29ubmVjdGlvbiIsImdldEJhbGFuY2VzIiwiYWNjb3VudElkeCIsInN1YmFkZHJlc3NJZHgiLCJhc3NlcnQiLCJlcXVhbCIsImJhbGFuY2UiLCJCaWdJbnQiLCJ1bmxvY2tlZEJhbGFuY2UiLCJhY2NvdW50IiwiZ2V0QWNjb3VudHMiLCJnZXRCYWxhbmNlIiwiZ2V0VW5sb2NrZWRCYWxhbmNlIiwiYWNjb3VudF9pbmRleCIsImFkZHJlc3NfaW5kaWNlcyIsInJlc3AiLCJyZXN1bHQiLCJ1bmxvY2tlZF9iYWxhbmNlIiwicGVyX3N1YmFkZHJlc3MiLCJhZGRMaXN0ZW5lciIsInJlZnJlc2hMaXN0ZW5pbmciLCJpc0Nvbm5lY3RlZFRvRGFlbW9uIiwiY2hlY2tSZXNlcnZlUHJvb2YiLCJpbmRleE9mIiwiZ2V0VmVyc2lvbiIsIk1vbmVyb1ZlcnNpb24iLCJ2ZXJzaW9uIiwicmVsZWFzZSIsImdldFNlZWRMYW5ndWFnZSIsImdldFNlZWRMYW5ndWFnZXMiLCJsYW5ndWFnZXMiLCJnZXRBZGRyZXNzIiwic3ViYWRkcmVzc01hcCIsImdldFN1YmFkZHJlc3NlcyIsImdldEFkZHJlc3NJbmRleCIsInN1YmFkZHJlc3MiLCJNb25lcm9TdWJhZGRyZXNzIiwic2V0QWNjb3VudEluZGV4IiwiaW5kZXgiLCJtYWpvciIsInNldEluZGV4IiwibWlub3IiLCJnZXRJbnRlZ3JhdGVkQWRkcmVzcyIsInN0YW5kYXJkQWRkcmVzcyIsInBheW1lbnRJZCIsImludGVncmF0ZWRBZGRyZXNzU3RyIiwic3RhbmRhcmRfYWRkcmVzcyIsInBheW1lbnRfaWQiLCJpbnRlZ3JhdGVkX2FkZHJlc3MiLCJkZWNvZGVJbnRlZ3JhdGVkQWRkcmVzcyIsImludGVncmF0ZWRBZGRyZXNzIiwiTW9uZXJvSW50ZWdyYXRlZEFkZHJlc3MiLCJzZXRTdGFuZGFyZEFkZHJlc3MiLCJzZXRQYXltZW50SWQiLCJzZXRJbnRlZ3JhdGVkQWRkcmVzcyIsImdldEhlaWdodCIsImhlaWdodCIsImdldERhZW1vbkhlaWdodCIsImdldEhlaWdodEJ5RGF0ZSIsInllYXIiLCJtb250aCIsImRheSIsInN5bmMiLCJsaXN0ZW5lck9yU3RhcnRIZWlnaHQiLCJzdGFydEhlaWdodCIsIk1vbmVyb1dhbGxldExpc3RlbmVyIiwic3RhcnRfaGVpZ2h0IiwicG9sbCIsIk1vbmVyb1N5bmNSZXN1bHQiLCJibG9ja3NfZmV0Y2hlZCIsInJlY2VpdmVkX21vbmV5Iiwic3RhcnRTeW5jaW5nIiwic3luY1BlcmlvZEluU2Vjb25kcyIsIk1hdGgiLCJyb3VuZCIsImVuYWJsZSIsInBlcmlvZCIsIndhbGxldFBvbGxlciIsInNldFBlcmlvZEluTXMiLCJnZXRTeW5jUGVyaW9kSW5NcyIsInN0b3BTeW5jaW5nIiwic2NhblR4cyIsInR4SGFzaGVzIiwibGVuZ3RoIiwidHhpZHMiLCJyZXNjYW5TcGVudCIsInJlc2NhbkJsb2NrY2hhaW4iLCJpbmNsdWRlU3ViYWRkcmVzc2VzIiwidGFnIiwic2tpcEJhbGFuY2VzIiwiYWNjb3VudHMiLCJycGNBY2NvdW50Iiwic3ViYWRkcmVzc19hY2NvdW50cyIsImNvbnZlcnRScGNBY2NvdW50Iiwic2V0U3ViYWRkcmVzc2VzIiwiZ2V0SW5kZXgiLCJwdXNoIiwic2V0QmFsYW5jZSIsInNldFVubG9ja2VkQmFsYW5jZSIsInNldE51bVVuc3BlbnRPdXRwdXRzIiwic2V0TnVtQmxvY2tzVG9VbmxvY2siLCJhbGxfYWNjb3VudHMiLCJycGNTdWJhZGRyZXNzIiwiY29udmVydFJwY1N1YmFkZHJlc3MiLCJnZXRBY2NvdW50SW5kZXgiLCJ0Z3RTdWJhZGRyZXNzIiwiZ2V0TnVtVW5zcGVudE91dHB1dHMiLCJnZXRBY2NvdW50IiwiRXJyb3IiLCJjcmVhdGVBY2NvdW50IiwibGFiZWwiLCJNb25lcm9BY2NvdW50IiwicHJpbWFyeUFkZHJlc3MiLCJzdWJhZGRyZXNzSW5kaWNlcyIsImFkZHJlc3NfaW5kZXgiLCJsaXN0aWZ5Iiwic3ViYWRkcmVzc2VzIiwiYWRkcmVzc2VzIiwiZ2V0TnVtQmxvY2tzVG9VbmxvY2siLCJnZXRTdWJhZGRyZXNzIiwiY3JlYXRlU3ViYWRkcmVzcyIsInNldEFkZHJlc3MiLCJzZXRMYWJlbCIsInNldElzVXNlZCIsInNldFN1YmFkZHJlc3NMYWJlbCIsImdldFR4cyIsInF1ZXJ5IiwicXVlcnlOb3JtYWxpemVkIiwibm9ybWFsaXplVHhRdWVyeSIsInRyYW5zZmVyUXVlcnkiLCJnZXRUcmFuc2ZlclF1ZXJ5IiwiaW5wdXRRdWVyeSIsImdldElucHV0UXVlcnkiLCJvdXRwdXRRdWVyeSIsImdldE91dHB1dFF1ZXJ5Iiwic2V0VHJhbnNmZXJRdWVyeSIsInNldElucHV0UXVlcnkiLCJzZXRPdXRwdXRRdWVyeSIsInRyYW5zZmVycyIsImdldFRyYW5zZmVyc0F1eCIsIk1vbmVyb1RyYW5zZmVyUXVlcnkiLCJzZXRUeFF1ZXJ5IiwiZGVjb250ZXh0dWFsaXplIiwiY29weSIsInR4cyIsInR4c1NldCIsIlNldCIsInRyYW5zZmVyIiwiZ2V0VHgiLCJhZGQiLCJ0eE1hcCIsImJsb2NrTWFwIiwidHgiLCJtZXJnZVR4IiwiZ2V0SW5jbHVkZU91dHB1dHMiLCJvdXRwdXRRdWVyeUF1eCIsIk1vbmVyb091dHB1dFF1ZXJ5Iiwib3V0cHV0cyIsImdldE91dHB1dHNBdXgiLCJvdXRwdXRUeHMiLCJvdXRwdXQiLCJ0eHNRdWVyaWVkIiwibWVldHNDcml0ZXJpYSIsImdldEJsb2NrIiwic3BsaWNlIiwiZ2V0SXNDb25maXJtZWQiLCJjb25zb2xlIiwiZXJyb3IiLCJnZXRIYXNoZXMiLCJ0eHNCeUlkIiwiTWFwIiwiZ2V0SGFzaCIsIm9yZGVyZWRUeHMiLCJoYXNoIiwiZ2V0VHJhbnNmZXJzIiwibm9ybWFsaXplVHJhbnNmZXJRdWVyeSIsImlzQ29udGV4dHVhbCIsImdldFR4UXVlcnkiLCJmaWx0ZXJUcmFuc2ZlcnMiLCJnZXRPdXRwdXRzIiwibm9ybWFsaXplT3V0cHV0UXVlcnkiLCJmaWx0ZXJPdXRwdXRzIiwiZXhwb3J0T3V0cHV0cyIsImFsbCIsIm91dHB1dHNfZGF0YV9oZXgiLCJpbXBvcnRPdXRwdXRzIiwib3V0cHV0c0hleCIsIm51bV9pbXBvcnRlZCIsImV4cG9ydEtleUltYWdlcyIsInJwY0V4cG9ydEtleUltYWdlcyIsImltcG9ydEtleUltYWdlcyIsImtleUltYWdlcyIsInJwY0tleUltYWdlcyIsIm1hcCIsImtleUltYWdlIiwia2V5X2ltYWdlIiwiZ2V0SGV4Iiwic2lnbmF0dXJlIiwiZ2V0U2lnbmF0dXJlIiwic2lnbmVkX2tleV9pbWFnZXMiLCJpbXBvcnRSZXN1bHQiLCJNb25lcm9LZXlJbWFnZUltcG9ydFJlc3VsdCIsInNldEhlaWdodCIsInNldFNwZW50QW1vdW50Iiwic3BlbnQiLCJzZXRVbnNwZW50QW1vdW50IiwidW5zcGVudCIsImdldE5ld0tleUltYWdlc0Zyb21MYXN0SW1wb3J0IiwiZnJlZXplT3V0cHV0IiwidGhhd091dHB1dCIsImlzT3V0cHV0RnJvemVuIiwiZnJvemVuIiwiZ2V0RGVmYXVsdEZlZVByaW9yaXR5IiwicHJpb3JpdHkiLCJjcmVhdGVUeHMiLCJub3JtYWxpemVDcmVhdGVUeHNDb25maWciLCJnZXRDYW5TcGxpdCIsInNldENhblNwbGl0IiwiZ2V0UmVsYXkiLCJpc011bHRpc2lnIiwiZ2V0U3ViYWRkcmVzc0luZGljZXMiLCJzbGljZSIsImRlc3RpbmF0aW9ucyIsImRlc3RpbmF0aW9uIiwiZ2V0RGVzdGluYXRpb25zIiwiZ2V0QW1vdW50IiwiYW1vdW50IiwidG9TdHJpbmciLCJnZXRTdWJ0cmFjdEZlZUZyb20iLCJzdWJ0cmFjdF9mZWVfZnJvbV9vdXRwdXRzIiwic3ViYWRkcl9pbmRpY2VzIiwiZ2V0UGF5bWVudElkIiwiZG9fbm90X3JlbGF5IiwiZ2V0UHJpb3JpdHkiLCJnZXRfdHhfaGV4IiwiZ2V0X3R4X21ldGFkYXRhIiwiZ2V0X3R4X2tleXMiLCJnZXRfdHhfa2V5IiwibnVtVHhzIiwiZmVlX2xpc3QiLCJmZWUiLCJjb3B5RGVzdGluYXRpb25zIiwiaSIsIk1vbmVyb1R4V2FsbGV0IiwiaW5pdFNlbnRUeFdhbGxldCIsImdldE91dGdvaW5nVHJhbnNmZXIiLCJzZXRTdWJhZGRyZXNzSW5kaWNlcyIsImNvbnZlcnRScGNTZW50VHhzVG9UeFNldCIsImNvbnZlcnRScGNUeFRvVHhTZXQiLCJzd2VlcE91dHB1dCIsIm5vcm1hbGl6ZVN3ZWVwT3V0cHV0Q29uZmlnIiwiZ2V0S2V5SW1hZ2UiLCJzZXRBbW91bnQiLCJzd2VlcFVubG9ja2VkIiwibm9ybWFsaXplU3dlZXBVbmxvY2tlZENvbmZpZyIsImluZGljZXMiLCJrZXlzIiwic2V0U3dlZXBFYWNoU3ViYWRkcmVzcyIsImdldFN3ZWVwRWFjaFN1YmFkZHJlc3MiLCJycGNTd2VlcEFjY291bnQiLCJzd2VlcER1c3QiLCJyZWxheSIsInR4U2V0Iiwic2V0SXNSZWxheWVkIiwic2V0SW5UeFBvb2wiLCJnZXRJc1JlbGF5ZWQiLCJyZWxheVR4cyIsInR4c09yTWV0YWRhdGFzIiwiQXJyYXkiLCJpc0FycmF5IiwidHhPck1ldGFkYXRhIiwibWV0YWRhdGEiLCJnZXRNZXRhZGF0YSIsImhleCIsInR4X2hhc2giLCJkZXNjcmliZVR4U2V0IiwidW5zaWduZWRfdHhzZXQiLCJnZXRVbnNpZ25lZFR4SGV4IiwibXVsdGlzaWdfdHhzZXQiLCJnZXRNdWx0aXNpZ1R4SGV4IiwiY29udmVydFJwY0Rlc2NyaWJlVHJhbnNmZXIiLCJzaWduVHhzIiwidW5zaWduZWRUeEhleCIsImV4cG9ydF9yYXciLCJzdWJtaXRUeHMiLCJzaWduZWRUeEhleCIsInR4X2RhdGFfaGV4IiwidHhfaGFzaF9saXN0Iiwic2lnbk1lc3NhZ2UiLCJzaWduYXR1cmVUeXBlIiwiTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGUiLCJTSUdOX1dJVEhfU1BFTkRfS0VZIiwiZGF0YSIsInNpZ25hdHVyZV90eXBlIiwidmVyaWZ5TWVzc2FnZSIsIk1vbmVyb01lc3NhZ2VTaWduYXR1cmVSZXN1bHQiLCJnb29kIiwiaXNHb29kIiwiaXNPbGQiLCJvbGQiLCJTSUdOX1dJVEhfVklFV19LRVkiLCJnZXRUeEtleSIsInR4SGFzaCIsInR4aWQiLCJ0eF9rZXkiLCJjaGVja1R4S2V5IiwidHhLZXkiLCJjaGVjayIsIk1vbmVyb0NoZWNrVHgiLCJzZXRJc0dvb2QiLCJzZXROdW1Db25maXJtYXRpb25zIiwiY29uZmlybWF0aW9ucyIsImluX3Bvb2wiLCJzZXRSZWNlaXZlZEFtb3VudCIsInJlY2VpdmVkIiwiZ2V0VHhQcm9vZiIsImNoZWNrVHhQcm9vZiIsImdldFNwZW5kUHJvb2YiLCJjaGVja1NwZW5kUHJvb2YiLCJnZXRSZXNlcnZlUHJvb2ZXYWxsZXQiLCJnZXRSZXNlcnZlUHJvb2ZBY2NvdW50IiwiTW9uZXJvQ2hlY2tSZXNlcnZlIiwic2V0VW5jb25maXJtZWRTcGVudEFtb3VudCIsInNldFRvdGFsQW1vdW50IiwidG90YWwiLCJnZXRUeE5vdGVzIiwibm90ZXMiLCJzZXRUeE5vdGVzIiwiZ2V0QWRkcmVzc0Jvb2tFbnRyaWVzIiwiZW50cnlJbmRpY2VzIiwiZW50cmllcyIsInJwY0VudHJ5IiwiTW9uZXJvQWRkcmVzc0Jvb2tFbnRyeSIsInNldERlc2NyaXB0aW9uIiwiZGVzY3JpcHRpb24iLCJhZGRBZGRyZXNzQm9va0VudHJ5IiwiZWRpdEFkZHJlc3NCb29rRW50cnkiLCJzZXRfYWRkcmVzcyIsInNldF9kZXNjcmlwdGlvbiIsImRlbGV0ZUFkZHJlc3NCb29rRW50cnkiLCJlbnRyeUlkeCIsInRhZ0FjY291bnRzIiwiYWNjb3VudEluZGljZXMiLCJ1bnRhZ0FjY291bnRzIiwiZ2V0QWNjb3VudFRhZ3MiLCJ0YWdzIiwiYWNjb3VudF90YWdzIiwicnBjQWNjb3VudFRhZyIsIk1vbmVyb0FjY291bnRUYWciLCJzZXRBY2NvdW50VGFnTGFiZWwiLCJnZXRQYXltZW50VXJpIiwicmVjaXBpZW50X25hbWUiLCJnZXRSZWNpcGllbnROYW1lIiwidHhfZGVzY3JpcHRpb24iLCJnZXROb3RlIiwidXJpIiwicGFyc2VQYXltZW50VXJpIiwiTW9uZXJvVHhDb25maWciLCJzZXRSZWNpcGllbnROYW1lIiwic2V0Tm90ZSIsImdldEF0dHJpYnV0ZSIsInZhbHVlIiwic2V0QXR0cmlidXRlIiwidmFsIiwic3RhcnRNaW5pbmciLCJudW1UaHJlYWRzIiwiYmFja2dyb3VuZE1pbmluZyIsImlnbm9yZUJhdHRlcnkiLCJ0aHJlYWRzX2NvdW50IiwiZG9fYmFja2dyb3VuZF9taW5pbmciLCJpZ25vcmVfYmF0dGVyeSIsInN0b3BNaW5pbmciLCJpc011bHRpc2lnSW1wb3J0TmVlZGVkIiwibXVsdGlzaWdfaW1wb3J0X25lZWRlZCIsImdldE11bHRpc2lnSW5mbyIsImluZm8iLCJNb25lcm9NdWx0aXNpZ0luZm8iLCJzZXRJc011bHRpc2lnIiwibXVsdGlzaWciLCJzZXRJc1JlYWR5IiwicmVhZHkiLCJzZXRUaHJlc2hvbGQiLCJ0aHJlc2hvbGQiLCJzZXROdW1QYXJ0aWNpcGFudHMiLCJwcmVwYXJlTXVsdGlzaWciLCJtdWx0aXNpZ19pbmZvIiwibWFrZU11bHRpc2lnIiwibXVsdGlzaWdIZXhlcyIsImV4Y2hhbmdlTXVsdGlzaWdLZXlzIiwibXNSZXN1bHQiLCJNb25lcm9NdWx0aXNpZ0luaXRSZXN1bHQiLCJzZXRNdWx0aXNpZ0hleCIsImdldE11bHRpc2lnSGV4IiwiZXhwb3J0TXVsdGlzaWdIZXgiLCJpbXBvcnRNdWx0aXNpZ0hleCIsIm5fb3V0cHV0cyIsInNpZ25NdWx0aXNpZ1R4SGV4IiwibXVsdGlzaWdUeEhleCIsInNpZ25SZXN1bHQiLCJNb25lcm9NdWx0aXNpZ1NpZ25SZXN1bHQiLCJzZXRTaWduZWRNdWx0aXNpZ1R4SGV4Iiwic2V0VHhIYXNoZXMiLCJzdWJtaXRNdWx0aXNpZ1R4SGV4Iiwic2lnbmVkTXVsdGlzaWdUeEhleCIsImNoYW5nZVBhc3N3b3JkIiwib2xkUGFzc3dvcmQiLCJuZXdQYXNzd29yZCIsIm9sZF9wYXNzd29yZCIsIm5ld19wYXNzd29yZCIsInNhdmUiLCJjbG9zZSIsImlzQ2xvc2VkIiwic3RvcCIsImdldEluY29taW5nVHJhbnNmZXJzIiwiZ2V0T3V0Z29pbmdUcmFuc2ZlcnMiLCJjcmVhdGVUeCIsInJlbGF5VHgiLCJnZXRUeE5vdGUiLCJzZXRUeE5vdGUiLCJub3RlIiwiY29ubmVjdFRvV2FsbGV0UnBjIiwidXJpT3JDb25maWciLCJub3JtYWxpemVDb25maWciLCJjbWQiLCJzdGFydFdhbGxldFJwY1Byb2Nlc3MiLCJjaGlsZF9wcm9jZXNzIiwiUHJvbWlzZSIsInJlc29sdmUiLCJ0aGVuIiwiY2hpbGRQcm9jZXNzIiwic3Bhd24iLCJlbnYiLCJMQU5HIiwic3Rkb3V0Iiwic2V0RW5jb2RpbmciLCJzdGRlcnIiLCJ0aGF0IiwicmVqZWN0Iiwib24iLCJsaW5lIiwiTGlicmFyeVV0aWxzIiwibG9nIiwidXJpTGluZUNvbnRhaW5zIiwidXJpTGluZUNvbnRhaW5zSWR4IiwiaG9zdCIsInN1YnN0cmluZyIsImxhc3RJbmRleE9mIiwidW5mb3JtYXR0ZWRMaW5lIiwicmVwbGFjZSIsInRyaW0iLCJwb3J0Iiwic3NsSWR4Iiwic3NsRW5hYmxlZCIsInVzZXJQYXNzSWR4IiwidXNlclBhc3MiLCJyZWplY3RVbmF1dGhvcml6ZWQiLCJnZXRSZWplY3RVbmF1dGhvcml6ZWQiLCJ3YWxsZXQiLCJpc1Jlc29sdmVkIiwiZ2V0TG9nTGV2ZWwiLCJjb2RlIiwib3JpZ2luIiwiZ2V0QWNjb3VudEluZGljZXMiLCJ0eFF1ZXJ5IiwiY2FuQmVDb25maXJtZWQiLCJnZXRJblR4UG9vbCIsImdldElzRmFpbGVkIiwiY2FuQmVJblR4UG9vbCIsImdldE1heEhlaWdodCIsImdldElzTG9ja2VkIiwiY2FuQmVJbmNvbWluZyIsImdldElzSW5jb21pbmciLCJnZXRJc091dGdvaW5nIiwiZ2V0SGFzRGVzdGluYXRpb25zIiwiY2FuQmVPdXRnb2luZyIsImluIiwib3V0IiwicG9vbCIsInBlbmRpbmciLCJmYWlsZWQiLCJnZXRNaW5IZWlnaHQiLCJtaW5faGVpZ2h0IiwibWF4X2hlaWdodCIsImZpbHRlcl9ieV9oZWlnaHQiLCJnZXRTdWJhZGRyZXNzSW5kZXgiLCJzaXplIiwiZnJvbSIsInJwY1R4IiwiY29udmVydFJwY1R4V2l0aFRyYW5zZmVyIiwiZ2V0T3V0Z29pbmdBbW91bnQiLCJvdXRnb2luZ1RyYW5zZmVyIiwidHJhbnNmZXJUb3RhbCIsInZhbHVlcyIsInNvcnQiLCJjb21wYXJlVHhzQnlIZWlnaHQiLCJzZXRJc0luY29taW5nIiwic2V0SXNPdXRnb2luZyIsImNvbXBhcmVJbmNvbWluZ1RyYW5zZmVycyIsInRyYW5zZmVyX3R5cGUiLCJnZXRJc1NwZW50IiwidmVyYm9zZSIsInJwY091dHB1dCIsImNvbnZlcnRScGNUeFdhbGxldFdpdGhPdXRwdXQiLCJjb21wYXJlT3V0cHV0cyIsInJwY0ltYWdlIiwiTW9uZXJvS2V5SW1hZ2UiLCJiZWxvd19hbW91bnQiLCJnZXRCZWxvd0Ftb3VudCIsInNldElzTG9ja2VkIiwic2V0SXNDb25maXJtZWQiLCJzZXRSZWxheSIsInNldElzTWluZXJUeCIsInNldElzRmFpbGVkIiwiTW9uZXJvRGVzdGluYXRpb24iLCJzZXREZXN0aW5hdGlvbnMiLCJzZXRPdXRnb2luZ1RyYW5zZmVyIiwiZ2V0VW5sb2NrVGltZSIsInNldFVubG9ja1RpbWUiLCJnZXRMYXN0UmVsYXllZFRpbWVzdGFtcCIsInNldExhc3RSZWxheWVkVGltZXN0YW1wIiwiRGF0ZSIsImdldFRpbWUiLCJnZXRJc0RvdWJsZVNwZW5kU2VlbiIsInNldElzRG91YmxlU3BlbmRTZWVuIiwibGlzdGVuZXJzIiwiV2FsbGV0UG9sbGVyIiwic2V0SXNQb2xsaW5nIiwiaXNQb2xsaW5nIiwic2VydmVyIiwicHJveHlUb1dvcmtlciIsInNldFByaW1hcnlBZGRyZXNzIiwic2V0VGFnIiwiZ2V0VGFnIiwic2V0UmluZ1NpemUiLCJNb25lcm9VdGlscyIsIlJJTkdfU0laRSIsIk1vbmVyb091dGdvaW5nVHJhbnNmZXIiLCJzZXRUeCIsImRlc3RDb3BpZXMiLCJkZXN0IiwiY29udmVydFJwY1R4U2V0IiwicnBjTWFwIiwiTW9uZXJvVHhTZXQiLCJzZXRNdWx0aXNpZ1R4SGV4Iiwic2V0VW5zaWduZWRUeEhleCIsInNldFNpZ25lZFR4SGV4Iiwic2lnbmVkX3R4c2V0IiwiZ2V0U2lnbmVkVHhIZXgiLCJycGNUeHMiLCJzZXRUeHMiLCJzZXRUeFNldCIsInNldEhhc2giLCJzZXRLZXkiLCJzZXRGdWxsSGV4Iiwic2V0TWV0YWRhdGEiLCJzZXRGZWUiLCJzZXRXZWlnaHQiLCJpbnB1dEtleUltYWdlc0xpc3QiLCJhc3NlcnRUcnVlIiwiZ2V0SW5wdXRzIiwic2V0SW5wdXRzIiwiaW5wdXRLZXlJbWFnZSIsIk1vbmVyb091dHB1dFdhbGxldCIsInNldEtleUltYWdlIiwic2V0SGV4IiwiYW1vdW50c0J5RGVzdExpc3QiLCJkZXN0aW5hdGlvbklkeCIsInR4SWR4IiwiYW1vdW50c0J5RGVzdCIsImlzT3V0Z29pbmciLCJ0eXBlIiwiZGVjb2RlUnBjVHlwZSIsImhlYWRlciIsInNldFNpemUiLCJNb25lcm9CbG9ja0hlYWRlciIsInNldFRpbWVzdGFtcCIsIk1vbmVyb0luY29taW5nVHJhbnNmZXIiLCJzZXROdW1TdWdnZXN0ZWRDb25maXJtYXRpb25zIiwiREVGQVVMVF9QQVlNRU5UX0lEIiwicnBjSW5kaWNlcyIsInJwY0luZGV4Iiwic2V0U3ViYWRkcmVzc0luZGV4IiwicnBjRGVzdGluYXRpb24iLCJkZXN0aW5hdGlvbktleSIsInNldElucHV0U3VtIiwic2V0T3V0cHV0U3VtIiwic2V0Q2hhbmdlQWRkcmVzcyIsInNldENoYW5nZUFtb3VudCIsInNldE51bUR1bW15T3V0cHV0cyIsInNldEV4dHJhSGV4IiwiaW5wdXRLZXlJbWFnZXMiLCJrZXlfaW1hZ2VzIiwiYW1vdW50cyIsInNldEJsb2NrIiwiTW9uZXJvQmxvY2siLCJtZXJnZSIsInNldEluY29taW5nVHJhbnNmZXJzIiwic2V0SXNTcGVudCIsInNldElzRnJvemVuIiwic2V0U3RlYWx0aFB1YmxpY0tleSIsInNldE91dHB1dHMiLCJycGNEZXNjcmliZVRyYW5zZmVyUmVzdWx0IiwicnBjVHlwZSIsImFUeCIsImFCbG9jayIsInR4MSIsInR4MiIsImRpZmYiLCJ0MSIsInQyIiwibzEiLCJvMiIsImhlaWdodENvbXBhcmlzb24iLCJjb21wYXJlIiwibG9jYWxlQ29tcGFyZSIsImV4cG9ydHMiLCJsb29wZXIiLCJUYXNrTG9vcGVyIiwicHJldkxvY2tlZFR4cyIsInByZXZVbmNvbmZpcm1lZE5vdGlmaWNhdGlvbnMiLCJwcmV2Q29uZmlybWVkTm90aWZpY2F0aW9ucyIsInRocmVhZFBvb2wiLCJUaHJlYWRQb29sIiwibnVtUG9sbGluZyIsInN0YXJ0IiwicGVyaW9kSW5NcyIsInN1Ym1pdCIsInByZXZCYWxhbmNlcyIsInByZXZIZWlnaHQiLCJNb25lcm9UeFF1ZXJ5Iiwib25OZXdCbG9jayIsIm1pbkhlaWdodCIsIm1heCIsImxvY2tlZFR4cyIsInNldE1pbkhlaWdodCIsInNldEluY2x1ZGVPdXRwdXRzIiwibm9Mb25nZXJMb2NrZWRIYXNoZXMiLCJwcmV2TG9ja2VkVHgiLCJ1bmxvY2tlZFR4cyIsInNldEhhc2hlcyIsImxvY2tlZFR4Iiwic2VhcmNoU2V0IiwidW5hbm5vdW5jZWQiLCJub3RpZnlPdXRwdXRzIiwidW5sb2NrZWRUeCIsImRlbGV0ZSIsImNoZWNrRm9yQ2hhbmdlZEJhbGFuY2VzIiwiYW5ub3VuY2VOZXdCbG9jayIsImdldEZlZSIsImFubm91bmNlT3V0cHV0U3BlbnQiLCJhbm5vdW5jZU91dHB1dFJlY2VpdmVkIiwiYmFsYW5jZXMiLCJhbm5vdW5jZUJhbGFuY2VzQ2hhbmdlZCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9Nb25lcm9XYWxsZXRScGMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGFzc2VydCBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQgR2VuVXRpbHMgZnJvbSBcIi4uL2NvbW1vbi9HZW5VdGlsc1wiO1xuaW1wb3J0IExpYnJhcnlVdGlscyBmcm9tIFwiLi4vY29tbW9uL0xpYnJhcnlVdGlsc1wiO1xuaW1wb3J0IFRhc2tMb29wZXIgZnJvbSBcIi4uL2NvbW1vbi9UYXNrTG9vcGVyXCI7XG5pbXBvcnQgTW9uZXJvQWNjb3VudCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9BY2NvdW50XCI7XG5pbXBvcnQgTW9uZXJvQWNjb3VudFRhZyBmcm9tIFwiLi9tb2RlbC9Nb25lcm9BY2NvdW50VGFnXCI7XG5pbXBvcnQgTW9uZXJvQWRkcmVzc0Jvb2tFbnRyeSBmcm9tIFwiLi9tb2RlbC9Nb25lcm9BZGRyZXNzQm9va0VudHJ5XCI7XG5pbXBvcnQgTW9uZXJvQmxvY2sgZnJvbSBcIi4uL2RhZW1vbi9tb2RlbC9Nb25lcm9CbG9ja1wiO1xuaW1wb3J0IE1vbmVyb0Jsb2NrSGVhZGVyIGZyb20gXCIuLi9kYWVtb24vbW9kZWwvTW9uZXJvQmxvY2tIZWFkZXJcIjtcbmltcG9ydCBNb25lcm9DaGVja1Jlc2VydmUgZnJvbSBcIi4vbW9kZWwvTW9uZXJvQ2hlY2tSZXNlcnZlXCI7XG5pbXBvcnQgTW9uZXJvQ2hlY2tUeCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9DaGVja1R4XCI7XG5pbXBvcnQgTW9uZXJvRGVzdGluYXRpb24gZnJvbSBcIi4vbW9kZWwvTW9uZXJvRGVzdGluYXRpb25cIjtcbmltcG9ydCBNb25lcm9FcnJvciBmcm9tIFwiLi4vY29tbW9uL01vbmVyb0Vycm9yXCI7XG5pbXBvcnQgTW9uZXJvSW5jb21pbmdUcmFuc2ZlciBmcm9tIFwiLi9tb2RlbC9Nb25lcm9JbmNvbWluZ1RyYW5zZmVyXCI7XG5pbXBvcnQgTW9uZXJvSW50ZWdyYXRlZEFkZHJlc3MgZnJvbSBcIi4vbW9kZWwvTW9uZXJvSW50ZWdyYXRlZEFkZHJlc3NcIjtcbmltcG9ydCBNb25lcm9LZXlJbWFnZSBmcm9tIFwiLi4vZGFlbW9uL21vZGVsL01vbmVyb0tleUltYWdlXCI7XG5pbXBvcnQgTW9uZXJvS2V5SW1hZ2VJbXBvcnRSZXN1bHQgZnJvbSBcIi4vbW9kZWwvTW9uZXJvS2V5SW1hZ2VJbXBvcnRSZXN1bHRcIjtcbmltcG9ydCBNb25lcm9NdWx0aXNpZ0luZm8gZnJvbSBcIi4vbW9kZWwvTW9uZXJvTXVsdGlzaWdJbmZvXCI7XG5pbXBvcnQgTW9uZXJvTXVsdGlzaWdJbml0UmVzdWx0IGZyb20gXCIuL21vZGVsL01vbmVyb011bHRpc2lnSW5pdFJlc3VsdFwiO1xuaW1wb3J0IE1vbmVyb011bHRpc2lnU2lnblJlc3VsdCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9NdWx0aXNpZ1NpZ25SZXN1bHRcIjtcbmltcG9ydCBNb25lcm9PdXRnb2luZ1RyYW5zZmVyIGZyb20gXCIuL21vZGVsL01vbmVyb091dGdvaW5nVHJhbnNmZXJcIjtcbmltcG9ydCBNb25lcm9PdXRwdXRRdWVyeSBmcm9tIFwiLi9tb2RlbC9Nb25lcm9PdXRwdXRRdWVyeVwiO1xuaW1wb3J0IE1vbmVyb091dHB1dFdhbGxldCBmcm9tIFwiLi9tb2RlbC9Nb25lcm9PdXRwdXRXYWxsZXRcIjtcbmltcG9ydCBNb25lcm9ScGNDb25uZWN0aW9uIGZyb20gXCIuLi9jb21tb24vTW9uZXJvUnBjQ29ubmVjdGlvblwiO1xuaW1wb3J0IE1vbmVyb1JwY0Vycm9yIGZyb20gXCIuLi9jb21tb24vTW9uZXJvUnBjRXJyb3JcIjtcbmltcG9ydCBNb25lcm9TdWJhZGRyZXNzIGZyb20gXCIuL21vZGVsL01vbmVyb1N1YmFkZHJlc3NcIjtcbmltcG9ydCBNb25lcm9TeW5jUmVzdWx0IGZyb20gXCIuL21vZGVsL01vbmVyb1N5bmNSZXN1bHRcIjtcbmltcG9ydCBNb25lcm9UcmFuc2ZlciBmcm9tIFwiLi9tb2RlbC9Nb25lcm9UcmFuc2ZlclwiO1xuaW1wb3J0IE1vbmVyb1RyYW5zZmVyUXVlcnkgZnJvbSBcIi4vbW9kZWwvTW9uZXJvVHJhbnNmZXJRdWVyeVwiO1xuaW1wb3J0IE1vbmVyb1R4IGZyb20gXCIuLi9kYWVtb24vbW9kZWwvTW9uZXJvVHhcIjtcbmltcG9ydCBNb25lcm9UeENvbmZpZyBmcm9tIFwiLi9tb2RlbC9Nb25lcm9UeENvbmZpZ1wiO1xuaW1wb3J0IE1vbmVyb1R4UHJpb3JpdHkgZnJvbSBcIi4vbW9kZWwvTW9uZXJvVHhQcmlvcml0eVwiO1xuaW1wb3J0IE1vbmVyb1R4UXVlcnkgZnJvbSBcIi4vbW9kZWwvTW9uZXJvVHhRdWVyeVwiO1xuaW1wb3J0IE1vbmVyb1R4U2V0IGZyb20gXCIuL21vZGVsL01vbmVyb1R4U2V0XCI7XG5pbXBvcnQgTW9uZXJvVHhXYWxsZXQgZnJvbSBcIi4vbW9kZWwvTW9uZXJvVHhXYWxsZXRcIjtcbmltcG9ydCBNb25lcm9VdGlscyBmcm9tIFwiLi4vY29tbW9uL01vbmVyb1V0aWxzXCI7XG5pbXBvcnQgTW9uZXJvVmVyc2lvbiBmcm9tIFwiLi4vZGFlbW9uL21vZGVsL01vbmVyb1ZlcnNpb25cIjtcbmltcG9ydCBNb25lcm9XYWxsZXQgZnJvbSBcIi4vTW9uZXJvV2FsbGV0XCI7XG5pbXBvcnQgTW9uZXJvV2FsbGV0Q29uZmlnIGZyb20gXCIuL21vZGVsL01vbmVyb1dhbGxldENvbmZpZ1wiO1xuaW1wb3J0IE1vbmVyb1dhbGxldExpc3RlbmVyIGZyb20gXCIuL21vZGVsL01vbmVyb1dhbGxldExpc3RlbmVyXCI7XG5pbXBvcnQgTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGUgZnJvbSBcIi4vbW9kZWwvTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGVcIjtcbmltcG9ydCBNb25lcm9NZXNzYWdlU2lnbmF0dXJlUmVzdWx0IGZyb20gXCIuL21vZGVsL01vbmVyb01lc3NhZ2VTaWduYXR1cmVSZXN1bHRcIjtcbmltcG9ydCBUaHJlYWRQb29sIGZyb20gXCIuLi9jb21tb24vVGhyZWFkUG9vbFwiO1xuaW1wb3J0IFNzbE9wdGlvbnMgZnJvbSBcIi4uL2NvbW1vbi9Tc2xPcHRpb25zXCI7XG5pbXBvcnQgeyBDaGlsZFByb2Nlc3MgfSBmcm9tIFwiY2hpbGRfcHJvY2Vzc1wiO1xuXG4vKipcbiAqIENvcHlyaWdodCAoYykgd29vZHNlclxuICpcbiAqIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbiAqIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbiAqIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbiAqIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbiAqIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuICogZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbiAqXG4gKiBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGxcbiAqIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4gKlxuICogVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuICogSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4gKiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbiAqIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbiAqIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4gKiBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRVxuICogU09GVFdBUkUuXG4gKi9cblxuLyoqXG4gKiBJbXBsZW1lbnRzIGEgTW9uZXJvV2FsbGV0IGFzIGEgY2xpZW50IG9mIG1vbmVyby13YWxsZXQtcnBjLlxuICogXG4gKiBAaW1wbGVtZW50cyB7TW9uZXJvV2FsbGV0fVxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9XYWxsZXRScGMgZXh0ZW5kcyBNb25lcm9XYWxsZXQge1xuXG4gIC8vIHN0YXRpYyB2YXJpYWJsZXNcbiAgcHJvdGVjdGVkIHN0YXRpYyByZWFkb25seSBERUZBVUxUX1NZTkNfUEVSSU9EX0lOX01TID0gMjAwMDA7IC8vIGRlZmF1bHQgcGVyaW9kIGJldHdlZW4gc3luY3MgaW4gbXMgKGRlZmluZWQgYnkgREVGQVVMVF9BVVRPX1JFRlJFU0hfUEVSSU9EIGluIHdhbGxldF9ycGNfc2VydmVyLmNwcClcblxuICAvLyBpbnN0YW5jZSB2YXJpYWJsZXNcbiAgcHJvdGVjdGVkIGNvbmZpZzogUGFydGlhbDxNb25lcm9XYWxsZXRDb25maWc+O1xuICBwcm90ZWN0ZWQgYWRkcmVzc0NhY2hlOiBhbnk7XG4gIHByb3RlY3RlZCBzeW5jUGVyaW9kSW5NczogbnVtYmVyO1xuICBwcm90ZWN0ZWQgbGlzdGVuZXJzOiBNb25lcm9XYWxsZXRMaXN0ZW5lcltdO1xuICBwcm90ZWN0ZWQgcHJvY2VzczogYW55O1xuICBwcm90ZWN0ZWQgcGF0aDogc3RyaW5nO1xuICBwcm90ZWN0ZWQgZGFlbW9uQ29ubmVjdGlvbjogTW9uZXJvUnBjQ29ubmVjdGlvbjtcbiAgcHJvdGVjdGVkIHdhbGxldFBvbGxlcjogV2FsbGV0UG9sbGVyO1xuICBcbiAgLyoqIEBwcml2YXRlICovXG4gIGNvbnN0cnVjdG9yKGNvbmZpZzogTW9uZXJvV2FsbGV0Q29uZmlnKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICB0aGlzLmFkZHJlc3NDYWNoZSA9IHt9OyAvLyBhdm9pZCB1bmVjZXNzYXJ5IHJlcXVlc3RzIGZvciBhZGRyZXNzZXNcbiAgICB0aGlzLnN5bmNQZXJpb2RJbk1zID0gTW9uZXJvV2FsbGV0UnBjLkRFRkFVTFRfU1lOQ19QRVJJT0RfSU5fTVM7XG4gIH1cbiAgXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBSUEMgV0FMTEVUIE1FVEhPRFMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIFxuICAvKipcbiAgICogR2V0IHRoZSBpbnRlcm5hbCBwcm9jZXNzIHJ1bm5pbmcgbW9uZXJvLXdhbGxldC1ycGMuXG4gICAqIFxuICAgKiBAcmV0dXJuIHtDaGlsZFByb2Nlc3N9IHRoZSBwcm9jZXNzIHJ1bm5pbmcgbW9uZXJvLXdhbGxldC1ycGMsIHVuZGVmaW5lZCBpZiBub3QgY3JlYXRlZCBmcm9tIG5ldyBwcm9jZXNzXG4gICAqL1xuICBnZXRQcm9jZXNzKCk6IENoaWxkUHJvY2VzcyB7XG4gICAgcmV0dXJuIHRoaXMucHJvY2VzcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIFN0b3AgdGhlIGludGVybmFsIHByb2Nlc3MgcnVubmluZyBtb25lcm8td2FsbGV0LXJwYywgaWYgYXBwbGljYWJsZS5cbiAgICogXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gZm9yY2Ugc3BlY2lmaWVzIGlmIHRoZSBwcm9jZXNzIHNob3VsZCBiZSBkZXN0cm95ZWQgZm9yY2libHkgKGRlZmF1bHQgZmFsc2UpXG4gICAqIEByZXR1cm4ge1Byb21pc2U8bnVtYmVyIHwgdW5kZWZpbmVkPn0gdGhlIGV4aXQgY29kZSBmcm9tIHN0b3BwaW5nIHRoZSBwcm9jZXNzXG4gICAqL1xuICBhc3luYyBzdG9wUHJvY2Vzcyhmb3JjZSA9IGZhbHNlKTogUHJvbWlzZTxudW1iZXIgfCB1bmRlZmluZWQ+ICB7XG4gICAgaWYgKHRoaXMucHJvY2VzcyA9PT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJNb25lcm9XYWxsZXRScGMgaW5zdGFuY2Ugbm90IGNyZWF0ZWQgZnJvbSBuZXcgcHJvY2Vzc1wiKTtcbiAgICBsZXQgbGlzdGVuZXJzQ29weSA9IEdlblV0aWxzLmNvcHlBcnJheSh0aGlzLmdldExpc3RlbmVycygpKTtcbiAgICBmb3IgKGxldCBsaXN0ZW5lciBvZiBsaXN0ZW5lcnNDb3B5KSBhd2FpdCB0aGlzLnJlbW92ZUxpc3RlbmVyKGxpc3RlbmVyKTtcbiAgICByZXR1cm4gR2VuVXRpbHMua2lsbFByb2Nlc3ModGhpcy5wcm9jZXNzLCBmb3JjZSA/IFwiU0lHS0lMTFwiIDogdW5kZWZpbmVkKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEdldCB0aGUgd2FsbGV0J3MgUlBDIGNvbm5lY3Rpb24uXG4gICAqIFxuICAgKiBAcmV0dXJuIHtNb25lcm9ScGNDb25uZWN0aW9uIHwgdW5kZWZpbmVkfSB0aGUgd2FsbGV0J3MgcnBjIGNvbm5lY3Rpb25cbiAgICovXG4gIGdldFJwY0Nvbm5lY3Rpb24oKTogTW9uZXJvUnBjQ29ubmVjdGlvbiB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuY29uZmlnLmdldFNlcnZlcigpO1xuICB9XG4gIFxuICAvKipcbiAgICogPHA+T3BlbiBhbiBleGlzdGluZyB3YWxsZXQgb24gdGhlIG1vbmVyby13YWxsZXQtcnBjIHNlcnZlci48L3A+XG4gICAqIFxuICAgKiA8cD5FeGFtcGxlOjxwPlxuICAgKiBcbiAgICogPGNvZGU+XG4gICAqIGxldCB3YWxsZXQgPSBuZXcgTW9uZXJvV2FsbGV0UnBjKFwiaHR0cDovL2xvY2FsaG9zdDozODA4NFwiLCBcInJwY191c2VyXCIsIFwiYWJjMTIzXCIpOzxicj5cbiAgICogYXdhaXQgd2FsbGV0Lm9wZW5XYWxsZXQoXCJteXdhbGxldDFcIiwgXCJzdXBlcnNlY3JldHBhc3N3b3JkXCIpOzxicj5cbiAgICogPGJyPlxuICAgKiBhd2FpdCB3YWxsZXQub3BlbldhbGxldCh7PGJyPlxuICAgKiAmbmJzcDsmbmJzcDsgcGF0aDogXCJteXdhbGxldDJcIiw8YnI+XG4gICAqICZuYnNwOyZuYnNwOyBwYXNzd29yZDogXCJzdXBlcnNlY3JldHBhc3N3b3JkXCIsPGJyPlxuICAgKiAmbmJzcDsmbmJzcDsgc2VydmVyOiBcImh0dHA6Ly9sb2NhaG9zdDozODA4MVwiLCAvLyBvciBvYmplY3Qgd2l0aCB1cmksIHVzZXJuYW1lLCBwYXNzd29yZCwgZXRjIDxicj5cbiAgICogJm5ic3A7Jm5ic3A7IHJlamVjdFVuYXV0aG9yaXplZDogZmFsc2U8YnI+XG4gICAqIH0pOzxicj5cbiAgICogPC9jb2RlPlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd8TW9uZXJvV2FsbGV0Q29uZmlnfSBwYXRoT3JDb25maWcgIC0gdGhlIHdhbGxldCdzIG5hbWUgb3IgY29uZmlndXJhdGlvbiB0byBvcGVuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoT3JDb25maWcucGF0aCAtIHBhdGggb2YgdGhlIHdhbGxldCB0byBjcmVhdGUgKG9wdGlvbmFsLCBpbi1tZW1vcnkgd2FsbGV0IGlmIG5vdCBnaXZlbilcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhdGhPckNvbmZpZy5wYXNzd29yZCAtIHBhc3N3b3JkIG9mIHRoZSB3YWxsZXQgdG8gY3JlYXRlXG4gICAqIEBwYXJhbSB7c3RyaW5nfFBhcnRpYWw8TW9uZXJvUnBjQ29ubmVjdGlvbj59IHBhdGhPckNvbmZpZy5zZXJ2ZXIgLSB1cmkgb3IgTW9uZXJvUnBjQ29ubmVjdGlvbiBvZiBhIGRhZW1vbiB0byB1c2UgKG9wdGlvbmFsLCBtb25lcm8td2FsbGV0LXJwYyB1c3VhbGx5IHN0YXJ0ZWQgd2l0aCBkYWVtb24gY29uZmlnKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW3Bhc3N3b3JkXSB0aGUgd2FsbGV0J3MgcGFzc3dvcmRcbiAgICogQHJldHVybiB7UHJvbWlzZTxNb25lcm9XYWxsZXRScGM+fSB0aGlzIHdhbGxldCBjbGllbnRcbiAgICovXG4gIGFzeW5jIG9wZW5XYWxsZXQocGF0aE9yQ29uZmlnOiBzdHJpbmcgfCBQYXJ0aWFsPE1vbmVyb1dhbGxldENvbmZpZz4sIHBhc3N3b3JkPzogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9XYWxsZXRScGM+IHtcbiAgICBcbiAgICAvLyBub3JtYWxpemUgYW5kIHZhbGlkYXRlIGNvbmZpZ1xuICAgIGxldCBjb25maWcgPSBuZXcgTW9uZXJvV2FsbGV0Q29uZmlnKHR5cGVvZiBwYXRoT3JDb25maWcgPT09IFwic3RyaW5nXCIgPyB7cGF0aDogcGF0aE9yQ29uZmlnLCBwYXNzd29yZDogcGFzc3dvcmQgPyBwYXNzd29yZCA6IFwiXCJ9IDogcGF0aE9yQ29uZmlnKTtcbiAgICAvLyBUT0RPOiBlbnN1cmUgb3RoZXIgZmllbGRzIHVuaW5pdGlhbGl6ZWQ/XG4gICAgXG4gICAgLy8gb3BlbiB3YWxsZXQgb24gcnBjIHNlcnZlclxuICAgIGlmICghY29uZmlnLmdldFBhdGgoKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTXVzdCBwcm92aWRlIG5hbWUgb2Ygd2FsbGV0IHRvIG9wZW5cIik7XG4gICAgYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwib3Blbl93YWxsZXRcIiwge2ZpbGVuYW1lOiBjb25maWcuZ2V0UGF0aCgpLCBwYXNzd29yZDogY29uZmlnLmdldFBhc3N3b3JkKCl9KTtcbiAgICBhd2FpdCB0aGlzLmNsZWFyKCk7XG4gICAgdGhpcy5wYXRoID0gY29uZmlnLmdldFBhdGgoKTtcblxuICAgIC8vIHNldCBjb25uZWN0aW9uIG1hbmFnZXIgb3Igc2VydmVyXG4gICAgaWYgKGNvbmZpZy5nZXRDb25uZWN0aW9uTWFuYWdlcigpICE9IG51bGwpIHtcbiAgICAgIGlmIChjb25maWcuZ2V0U2VydmVyKCkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIldhbGxldCBjYW4gYmUgb3BlbmVkIHdpdGggYSBzZXJ2ZXIgb3IgY29ubmVjdGlvbiBtYW5hZ2VyIGJ1dCBub3QgYm90aFwiKTtcbiAgICAgIGF3YWl0IHRoaXMuc2V0Q29ubmVjdGlvbk1hbmFnZXIoY29uZmlnLmdldENvbm5lY3Rpb25NYW5hZ2VyKCkpO1xuICAgIH0gZWxzZSBpZiAoY29uZmlnLmdldFNlcnZlcigpICE9IG51bGwpIHtcbiAgICAgIGF3YWl0IHRoaXMuc2V0RGFlbW9uQ29ubmVjdGlvbihjb25maWcuZ2V0U2VydmVyKCkpO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIDxwPkNyZWF0ZSBhbmQgb3BlbiBhIHdhbGxldCBvbiB0aGUgbW9uZXJvLXdhbGxldC1ycGMgc2VydmVyLjxwPlxuICAgKiBcbiAgICogPHA+RXhhbXBsZTo8cD5cbiAgICogXG4gICAqIDxjb2RlPlxuICAgKiAmc29sOyZzb2w7IGNvbnN0cnVjdCBjbGllbnQgdG8gbW9uZXJvLXdhbGxldC1ycGM8YnI+XG4gICAqIGxldCB3YWxsZXRScGMgPSBuZXcgTW9uZXJvV2FsbGV0UnBjKFwiaHR0cDovL2xvY2FsaG9zdDozODA4NFwiLCBcInJwY191c2VyXCIsIFwiYWJjMTIzXCIpOzxicj48YnI+XG4gICAqIFxuICAgKiAmc29sOyZzb2w7IGNyZWF0ZSBhbmQgb3BlbiB3YWxsZXQgb24gbW9uZXJvLXdhbGxldC1ycGM8YnI+XG4gICAqIGF3YWl0IHdhbGxldFJwYy5jcmVhdGVXYWxsZXQoezxicj5cbiAgICogJm5ic3A7Jm5ic3A7IHBhdGg6IFwibXl3YWxsZXRcIiw8YnI+XG4gICAqICZuYnNwOyZuYnNwOyBwYXNzd29yZDogXCJhYmMxMjNcIiw8YnI+XG4gICAqICZuYnNwOyZuYnNwOyBzZWVkOiBcImNvZXhpc3QgaWdsb28gcGFtcGhsZXQgbGFnb29uLi4uXCIsPGJyPlxuICAgKiAmbmJzcDsmbmJzcDsgcmVzdG9yZUhlaWdodDogMTU0MzIxOGw8YnI+XG4gICAqIH0pO1xuICAgKiAgPC9jb2RlPlxuICAgKiBcbiAgICogQHBhcmFtIHtQYXJ0aWFsPE1vbmVyb1dhbGxldENvbmZpZz59IGNvbmZpZyAtIE1vbmVyb1dhbGxldENvbmZpZyBvciBlcXVpdmFsZW50IEpTIG9iamVjdFxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2NvbmZpZy5wYXRoXSAtIHBhdGggb2YgdGhlIHdhbGxldCB0byBjcmVhdGUgKG9wdGlvbmFsLCBpbi1tZW1vcnkgd2FsbGV0IGlmIG5vdCBnaXZlbilcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtjb25maWcucGFzc3dvcmRdIC0gcGFzc3dvcmQgb2YgdGhlIHdhbGxldCB0byBjcmVhdGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtjb25maWcuc2VlZF0gLSBzZWVkIG9mIHRoZSB3YWxsZXQgdG8gY3JlYXRlIChvcHRpb25hbCwgcmFuZG9tIHdhbGxldCBjcmVhdGVkIGlmIG5laXRoZXIgc2VlZCBub3Iga2V5cyBnaXZlbilcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtjb25maWcuc2VlZE9mZnNldF0gLSB0aGUgb2Zmc2V0IHVzZWQgdG8gZGVyaXZlIGEgbmV3IHNlZWQgZnJvbSB0aGUgZ2l2ZW4gc2VlZCB0byByZWNvdmVyIGEgc2VjcmV0IHdhbGxldCBmcm9tIHRoZSBzZWVkXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2NvbmZpZy5pc011bHRpc2lnXSAtIHJlc3RvcmUgbXVsdGlzaWcgd2FsbGV0IGZyb20gc2VlZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2NvbmZpZy5wcmltYXJ5QWRkcmVzc10gLSBwcmltYXJ5IGFkZHJlc3Mgb2YgdGhlIHdhbGxldCB0byBjcmVhdGUgKG9ubHkgcHJvdmlkZSBpZiByZXN0b3JpbmcgZnJvbSBrZXlzKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2NvbmZpZy5wcml2YXRlVmlld0tleV0gLSBwcml2YXRlIHZpZXcga2V5IG9mIHRoZSB3YWxsZXQgdG8gY3JlYXRlIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtjb25maWcucHJpdmF0ZVNwZW5kS2V5XSAtIHByaXZhdGUgc3BlbmQga2V5IG9mIHRoZSB3YWxsZXQgdG8gY3JlYXRlIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtjb25maWcucmVzdG9yZUhlaWdodF0gLSBibG9jayBoZWlnaHQgdG8gc3RhcnQgc2Nhbm5pbmcgZnJvbSAoZGVmYXVsdHMgdG8gMCB1bmxlc3MgZ2VuZXJhdGluZyByYW5kb20gd2FsbGV0KVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2NvbmZpZy5sYW5ndWFnZV0gLSBsYW5ndWFnZSBvZiB0aGUgd2FsbGV0J3MgbW5lbW9uaWMgcGhyYXNlIG9yIHNlZWQgKGRlZmF1bHRzIHRvIFwiRW5nbGlzaFwiIG9yIGF1dG8tZGV0ZWN0ZWQpXG4gICAqIEBwYXJhbSB7TW9uZXJvUnBjQ29ubmVjdGlvbn0gW2NvbmZpZy5zZXJ2ZXJdIC0gTW9uZXJvUnBjQ29ubmVjdGlvbiB0byBhIG1vbmVybyBkYWVtb24gKG9wdGlvbmFsKTxicj5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFtjb25maWcuc2VydmVyVXJpXSAtIHVyaSBvZiBhIGRhZW1vbiB0byB1c2UgKG9wdGlvbmFsLCBtb25lcm8td2FsbGV0LXJwYyB1c3VhbGx5IHN0YXJ0ZWQgd2l0aCBkYWVtb24gY29uZmlnKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2NvbmZpZy5zZXJ2ZXJVc2VybmFtZV0gLSB1c2VybmFtZSB0byBhdXRoZW50aWNhdGUgd2l0aCB0aGUgZGFlbW9uIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtjb25maWcuc2VydmVyUGFzc3dvcmRdIC0gcGFzc3dvcmQgdG8gYXV0aGVudGljYXRlIHdpdGggdGhlIGRhZW1vbiAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7TW9uZXJvQ29ubmVjdGlvbk1hbmFnZXJ9IFtjb25maWcuY29ubmVjdGlvbk1hbmFnZXJdIC0gbWFuYWdlIGNvbm5lY3Rpb25zIHRvIG1vbmVyb2QgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtjb25maWcucmVqZWN0VW5hdXRob3JpemVkXSAtIHJlamVjdCBzZWxmLXNpZ25lZCBzZXJ2ZXIgY2VydGlmaWNhdGVzIGlmIHRydWUgKGRlZmF1bHRzIHRvIHRydWUpXG4gICAqIEBwYXJhbSB7TW9uZXJvUnBjQ29ubmVjdGlvbn0gW2NvbmZpZy5zZXJ2ZXJdIC0gTW9uZXJvUnBjQ29ubmVjdGlvbiBvciBlcXVpdmFsZW50IEpTIG9iamVjdCBwcm92aWRpbmcgZGFlbW9uIGNvbmZpZ3VyYXRpb24gKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtjb25maWcuc2F2ZUN1cnJlbnRdIC0gc3BlY2lmaWVzIGlmIHRoZSBjdXJyZW50IFJQQyB3YWxsZXQgc2hvdWxkIGJlIHNhdmVkIGJlZm9yZSBiZWluZyBjbG9zZWQgKGRlZmF1bHQgdHJ1ZSlcbiAgICogQHJldHVybiB7TW9uZXJvV2FsbGV0UnBjfSB0aGlzIHdhbGxldCBjbGllbnRcbiAgICovXG4gIGFzeW5jIGNyZWF0ZVdhbGxldChjb25maWc6IFBhcnRpYWw8TW9uZXJvV2FsbGV0Q29uZmlnPik6IFByb21pc2U8TW9uZXJvV2FsbGV0UnBjPiB7XG4gICAgXG4gICAgLy8gbm9ybWFsaXplIGFuZCB2YWxpZGF0ZSBjb25maWdcbiAgICBpZiAoY29uZmlnID09PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk11c3QgcHJvdmlkZSBjb25maWcgdG8gY3JlYXRlIHdhbGxldFwiKTtcbiAgICBjb25zdCBjb25maWdOb3JtYWxpemVkID0gbmV3IE1vbmVyb1dhbGxldENvbmZpZyhjb25maWcpO1xuICAgIGlmIChjb25maWdOb3JtYWxpemVkLmdldFNlZWQoKSAhPT0gdW5kZWZpbmVkICYmIChjb25maWdOb3JtYWxpemVkLmdldFByaW1hcnlBZGRyZXNzKCkgIT09IHVuZGVmaW5lZCB8fCBjb25maWdOb3JtYWxpemVkLmdldFByaXZhdGVWaWV3S2V5KCkgIT09IHVuZGVmaW5lZCB8fCBjb25maWdOb3JtYWxpemVkLmdldFByaXZhdGVTcGVuZEtleSgpICE9PSB1bmRlZmluZWQpKSB7XG4gICAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJXYWxsZXQgY2FuIGJlIGluaXRpYWxpemVkIHdpdGggYSBzZWVkIG9yIGtleXMgYnV0IG5vdCBib3RoXCIpO1xuICAgIH1cbiAgICBpZiAoY29uZmlnTm9ybWFsaXplZC5nZXROZXR3b3JrVHlwZSgpICE9PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBwcm92aWRlIG5ldHdvcmtUeXBlIHdoZW4gY3JlYXRpbmcgUlBDIHdhbGxldCBiZWNhdXNlIHNlcnZlcidzIG5ldHdvcmsgdHlwZSBpcyBhbHJlYWR5IHNldFwiKTtcbiAgICBpZiAoY29uZmlnTm9ybWFsaXplZC5nZXRBY2NvdW50TG9va2FoZWFkKCkgIT09IHVuZGVmaW5lZCB8fCBjb25maWdOb3JtYWxpemVkLmdldFN1YmFkZHJlc3NMb29rYWhlYWQoKSAhPT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJtb25lcm8td2FsbGV0LXJwYyBkb2VzIG5vdCBzdXBwb3J0IGNyZWF0aW5nIHdhbGxldHMgd2l0aCBzdWJhZGRyZXNzIGxvb2thaGVhZCBvdmVyIHJwY1wiKTtcbiAgICBpZiAoY29uZmlnTm9ybWFsaXplZC5nZXRQYXNzd29yZCgpID09PSB1bmRlZmluZWQpIGNvbmZpZ05vcm1hbGl6ZWQuc2V0UGFzc3dvcmQoXCJcIik7XG5cbiAgICAvLyBzZXQgc2VydmVyIGZyb20gY29ubmVjdGlvbiBtYW5hZ2VyIGlmIHByb3ZpZGVkXG4gICAgaWYgKGNvbmZpZ05vcm1hbGl6ZWQuZ2V0Q29ubmVjdGlvbk1hbmFnZXIoKSkge1xuICAgICAgaWYgKGNvbmZpZ05vcm1hbGl6ZWQuZ2V0U2VydmVyKCkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIldhbGxldCBjYW4gYmUgY3JlYXRlZCB3aXRoIGEgc2VydmVyIG9yIGNvbm5lY3Rpb24gbWFuYWdlciBidXQgbm90IGJvdGhcIik7XG4gICAgICBjb25maWdOb3JtYWxpemVkLnNldFNlcnZlcihjb25maWcuZ2V0Q29ubmVjdGlvbk1hbmFnZXIoKS5nZXRDb25uZWN0aW9uKCkpO1xuICAgIH1cblxuICAgIC8vIGNyZWF0ZSB3YWxsZXRcbiAgICBpZiAoY29uZmlnTm9ybWFsaXplZC5nZXRTZWVkKCkgIT09IHVuZGVmaW5lZCkgYXdhaXQgdGhpcy5jcmVhdGVXYWxsZXRGcm9tU2VlZChjb25maWdOb3JtYWxpemVkKTtcbiAgICBlbHNlIGlmIChjb25maWdOb3JtYWxpemVkLmdldFByaXZhdGVTcGVuZEtleSgpICE9PSB1bmRlZmluZWQgfHwgY29uZmlnTm9ybWFsaXplZC5nZXRQcmltYXJ5QWRkcmVzcygpICE9PSB1bmRlZmluZWQpIGF3YWl0IHRoaXMuY3JlYXRlV2FsbGV0RnJvbUtleXMoY29uZmlnTm9ybWFsaXplZCk7XG4gICAgZWxzZSBhd2FpdCB0aGlzLmNyZWF0ZVdhbGxldFJhbmRvbShjb25maWdOb3JtYWxpemVkKTtcblxuICAgIC8vIHNldCBjb25uZWN0aW9uIG1hbmFnZXIgb3Igc2VydmVyXG4gICAgaWYgKGNvbmZpZ05vcm1hbGl6ZWQuZ2V0Q29ubmVjdGlvbk1hbmFnZXIoKSkge1xuICAgICAgYXdhaXQgdGhpcy5zZXRDb25uZWN0aW9uTWFuYWdlcihjb25maWdOb3JtYWxpemVkLmdldENvbm5lY3Rpb25NYW5hZ2VyKCkpO1xuICAgIH0gZWxzZSBpZiAoY29uZmlnTm9ybWFsaXplZC5nZXRTZXJ2ZXIoKSkge1xuICAgICAgYXdhaXQgdGhpcy5zZXREYWVtb25Db25uZWN0aW9uKGNvbmZpZ05vcm1hbGl6ZWQuZ2V0U2VydmVyKCkpO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgcHJvdGVjdGVkIGFzeW5jIGNyZWF0ZVdhbGxldFJhbmRvbShjb25maWc6IE1vbmVyb1dhbGxldENvbmZpZykge1xuICAgIGlmIChjb25maWcuZ2V0U2VlZE9mZnNldCgpICE9PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBwcm92aWRlIHNlZWRPZmZzZXQgd2hlbiBjcmVhdGluZyByYW5kb20gd2FsbGV0XCIpO1xuICAgIGlmIChjb25maWcuZ2V0UmVzdG9yZUhlaWdodCgpICE9PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBwcm92aWRlIHJlc3RvcmVIZWlnaHQgd2hlbiBjcmVhdGluZyByYW5kb20gd2FsbGV0XCIpO1xuICAgIGlmIChjb25maWcuZ2V0U2F2ZUN1cnJlbnQoKSA9PT0gZmFsc2UpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkN1cnJlbnQgd2FsbGV0IGlzIHNhdmVkIGF1dG9tYXRpY2FsbHkgd2hlbiBjcmVhdGluZyByYW5kb20gd2FsbGV0XCIpO1xuICAgIGlmICghY29uZmlnLmdldFBhdGgoKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTmFtZSBpcyBub3QgaW5pdGlhbGl6ZWRcIik7XG4gICAgaWYgKCFjb25maWcuZ2V0TGFuZ3VhZ2UoKSkgY29uZmlnLnNldExhbmd1YWdlKE1vbmVyb1dhbGxldC5ERUZBVUxUX0xBTkdVQUdFKTtcbiAgICBsZXQgcGFyYW1zID0geyBmaWxlbmFtZTogY29uZmlnLmdldFBhdGgoKSwgcGFzc3dvcmQ6IGNvbmZpZy5nZXRQYXNzd29yZCgpLCBsYW5ndWFnZTogY29uZmlnLmdldExhbmd1YWdlKCkgfTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiY3JlYXRlX3dhbGxldFwiLCBwYXJhbXMpO1xuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICB0aGlzLmhhbmRsZUNyZWF0ZVdhbGxldEVycm9yKGNvbmZpZy5nZXRQYXRoKCksIGVycik7XG4gICAgfVxuICAgIGF3YWl0IHRoaXMuY2xlYXIoKTtcbiAgICB0aGlzLnBhdGggPSBjb25maWcuZ2V0UGF0aCgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgYXN5bmMgY3JlYXRlV2FsbGV0RnJvbVNlZWQoY29uZmlnOiBNb25lcm9XYWxsZXRDb25maWcpIHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwicmVzdG9yZV9kZXRlcm1pbmlzdGljX3dhbGxldFwiLCB7XG4gICAgICAgIGZpbGVuYW1lOiBjb25maWcuZ2V0UGF0aCgpLFxuICAgICAgICBwYXNzd29yZDogY29uZmlnLmdldFBhc3N3b3JkKCksXG4gICAgICAgIHNlZWQ6IGNvbmZpZy5nZXRTZWVkKCksXG4gICAgICAgIHNlZWRfb2Zmc2V0OiBjb25maWcuZ2V0U2VlZE9mZnNldCgpLFxuICAgICAgICBlbmFibGVfbXVsdGlzaWdfZXhwZXJpbWVudGFsOiBjb25maWcuZ2V0SXNNdWx0aXNpZygpLFxuICAgICAgICByZXN0b3JlX2hlaWdodDogY29uZmlnLmdldFJlc3RvcmVIZWlnaHQoKSxcbiAgICAgICAgbGFuZ3VhZ2U6IGNvbmZpZy5nZXRMYW5ndWFnZSgpLFxuICAgICAgICBhdXRvc2F2ZV9jdXJyZW50OiBjb25maWcuZ2V0U2F2ZUN1cnJlbnQoKVxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgIHRoaXMuaGFuZGxlQ3JlYXRlV2FsbGV0RXJyb3IoY29uZmlnLmdldFBhdGgoKSwgZXJyKTtcbiAgICB9XG4gICAgYXdhaXQgdGhpcy5jbGVhcigpO1xuICAgIHRoaXMucGF0aCA9IGNvbmZpZy5nZXRQYXRoKCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBhc3luYyBjcmVhdGVXYWxsZXRGcm9tS2V5cyhjb25maWc6IE1vbmVyb1dhbGxldENvbmZpZykge1xuICAgIGlmIChjb25maWcuZ2V0U2VlZE9mZnNldCgpICE9PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBwcm92aWRlIHNlZWRPZmZzZXQgd2hlbiBjcmVhdGluZyB3YWxsZXQgZnJvbSBrZXlzXCIpO1xuICAgIGlmIChjb25maWcuZ2V0UmVzdG9yZUhlaWdodCgpID09PSB1bmRlZmluZWQpIGNvbmZpZy5zZXRSZXN0b3JlSGVpZ2h0KDApO1xuICAgIGlmIChjb25maWcuZ2V0TGFuZ3VhZ2UoKSA9PT0gdW5kZWZpbmVkKSBjb25maWcuc2V0TGFuZ3VhZ2UoTW9uZXJvV2FsbGV0LkRFRkFVTFRfTEFOR1VBR0UpO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJnZW5lcmF0ZV9mcm9tX2tleXNcIiwge1xuICAgICAgICBmaWxlbmFtZTogY29uZmlnLmdldFBhdGgoKSxcbiAgICAgICAgcGFzc3dvcmQ6IGNvbmZpZy5nZXRQYXNzd29yZCgpLFxuICAgICAgICBhZGRyZXNzOiBjb25maWcuZ2V0UHJpbWFyeUFkZHJlc3MoKSxcbiAgICAgICAgdmlld2tleTogY29uZmlnLmdldFByaXZhdGVWaWV3S2V5KCksXG4gICAgICAgIHNwZW5ka2V5OiBjb25maWcuZ2V0UHJpdmF0ZVNwZW5kS2V5KCksXG4gICAgICAgIHJlc3RvcmVfaGVpZ2h0OiBjb25maWcuZ2V0UmVzdG9yZUhlaWdodCgpLFxuICAgICAgICBhdXRvc2F2ZV9jdXJyZW50OiBjb25maWcuZ2V0U2F2ZUN1cnJlbnQoKVxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyOiBhbnkpIHtcbiAgICAgIHRoaXMuaGFuZGxlQ3JlYXRlV2FsbGV0RXJyb3IoY29uZmlnLmdldFBhdGgoKSwgZXJyKTtcbiAgICB9XG4gICAgYXdhaXQgdGhpcy5jbGVhcigpO1xuICAgIHRoaXMucGF0aCA9IGNvbmZpZy5nZXRQYXRoKCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBoYW5kbGVDcmVhdGVXYWxsZXRFcnJvcihuYW1lLCBlcnIpIHtcbiAgICBpZiAoZXJyLm1lc3NhZ2UpIHtcbiAgICAgIGlmIChlcnIubWVzc2FnZS50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKFwiYWxyZWFkeSBleGlzdHNcIikpIHRocm93IG5ldyBNb25lcm9ScGNFcnJvcihcIldhbGxldCBhbHJlYWR5IGV4aXN0czogXCIgKyBuYW1lLCBlcnIuZ2V0Q29kZSgpLCBlcnIuZ2V0UnBjTWV0aG9kKCksIGVyci5nZXRScGNQYXJhbXMoKSk7XG4gICAgICBpZiAoZXJyLm1lc3NhZ2UudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhcIndvcmQgbGlzdCBmYWlsZWQgdmVyaWZpY2F0aW9uXCIpKSB0aHJvdyBuZXcgTW9uZXJvUnBjRXJyb3IoXCJJbnZhbGlkIG1uZW1vbmljXCIsIGVyci5nZXRDb2RlKCksIGVyci5nZXRScGNNZXRob2QoKSwgZXJyLmdldFJwY1BhcmFtcygpKTtcbiAgICB9XG4gICAgdGhyb3cgZXJyO1xuICB9XG4gIFxuICBhc3luYyBpc1ZpZXdPbmx5KCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJxdWVyeV9rZXlcIiwge2tleV90eXBlOiBcIm1uZW1vbmljXCJ9KTtcbiAgICAgIHJldHVybiBmYWxzZTsgLy8ga2V5IHJldHJpZXZhbCBzdWNjZWVkcyBpZiBub3QgdmlldyBvbmx5XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICBpZiAoZS5nZXRDb2RlKCkgPT09IC0yOSkgcmV0dXJuIHRydWU7ICAvLyB3YWxsZXQgaXMgdmlldyBvbmx5XG4gICAgICBpZiAoZS5nZXRDb2RlKCkgPT09IC0xKSByZXR1cm4gZmFsc2U7ICAvLyB3YWxsZXQgaXMgb2ZmbGluZSBidXQgbm90IHZpZXcgb25seVxuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZXQgdGhlIHdhbGxldCdzIGRhZW1vbiBjb25uZWN0aW9uLlxuICAgKiBcbiAgICogQHBhcmFtIHtzdHJpbmd8TW9uZXJvUnBjQ29ubmVjdGlvbn0gW3VyaU9yQ29ubmVjdGlvbl0gLSB0aGUgZGFlbW9uJ3MgVVJJIG9yIGNvbm5lY3Rpb24gKGRlZmF1bHRzIHRvIG9mZmxpbmUpXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gaXNUcnVzdGVkIC0gaW5kaWNhdGVzIGlmIHRoZSBkYWVtb24gaW4gdHJ1c3RlZFxuICAgKiBAcGFyYW0ge1NzbE9wdGlvbnN9IHNzbE9wdGlvbnMgLSBjdXN0b20gU1NMIGNvbmZpZ3VyYXRpb25cbiAgICovXG4gIGFzeW5jIHNldERhZW1vbkNvbm5lY3Rpb24odXJpT3JDb25uZWN0aW9uPzogTW9uZXJvUnBjQ29ubmVjdGlvbiB8IHN0cmluZywgaXNUcnVzdGVkPzogYm9vbGVhbiwgc3NsT3B0aW9ucz86IFNzbE9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBsZXQgY29ubmVjdGlvbiA9ICF1cmlPckNvbm5lY3Rpb24gPyB1bmRlZmluZWQgOiB1cmlPckNvbm5lY3Rpb24gaW5zdGFuY2VvZiBNb25lcm9ScGNDb25uZWN0aW9uID8gdXJpT3JDb25uZWN0aW9uIDogbmV3IE1vbmVyb1JwY0Nvbm5lY3Rpb24odXJpT3JDb25uZWN0aW9uKTtcbiAgICBpZiAoIXNzbE9wdGlvbnMpIHNzbE9wdGlvbnMgPSBuZXcgU3NsT3B0aW9ucygpO1xuICAgIGxldCBwYXJhbXM6IGFueSA9IHt9O1xuICAgIHBhcmFtcy5hZGRyZXNzID0gY29ubmVjdGlvbiA/IGNvbm5lY3Rpb24uZ2V0VXJpKCkgOiBcImJhZF91cmlcIjsgLy8gVE9ETyBtb25lcm8td2FsbGV0LXJwYzogYmFkIGRhZW1vbiB1cmkgbmVjZXNzYXJ5IGZvciBvZmZsaW5lP1xuICAgIHBhcmFtcy51c2VybmFtZSA9IGNvbm5lY3Rpb24gPyBjb25uZWN0aW9uLmdldFVzZXJuYW1lKCkgOiBcIlwiO1xuICAgIHBhcmFtcy5wYXNzd29yZCA9IGNvbm5lY3Rpb24gPyBjb25uZWN0aW9uLmdldFBhc3N3b3JkKCkgOiBcIlwiO1xuICAgIHBhcmFtcy50cnVzdGVkID0gaXNUcnVzdGVkO1xuICAgIHBhcmFtcy5zc2xfc3VwcG9ydCA9IFwiYXV0b2RldGVjdFwiO1xuICAgIHBhcmFtcy5zc2xfcHJpdmF0ZV9rZXlfcGF0aCA9IHNzbE9wdGlvbnMuZ2V0UHJpdmF0ZUtleVBhdGgoKTtcbiAgICBwYXJhbXMuc3NsX2NlcnRpZmljYXRlX3BhdGggID0gc3NsT3B0aW9ucy5nZXRDZXJ0aWZpY2F0ZVBhdGgoKTtcbiAgICBwYXJhbXMuc3NsX2NhX2ZpbGUgPSBzc2xPcHRpb25zLmdldENlcnRpZmljYXRlQXV0aG9yaXR5RmlsZSgpO1xuICAgIHBhcmFtcy5zc2xfYWxsb3dlZF9maW5nZXJwcmludHMgPSBzc2xPcHRpb25zLmdldEFsbG93ZWRGaW5nZXJwcmludHMoKTtcbiAgICBwYXJhbXMuc3NsX2FsbG93X2FueV9jZXJ0ID0gc3NsT3B0aW9ucy5nZXRBbGxvd0FueUNlcnQoKTtcbiAgICBwYXJhbXMucHJveHkgPSBjb25uZWN0aW9uID8gY29ubmVjdGlvbi5nZXRQcm94eVVyaSgpIDogXCJcIjtcbiAgICBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJzZXRfZGFlbW9uXCIsIHBhcmFtcyk7XG4gICAgdGhpcy5kYWVtb25Db25uZWN0aW9uID0gY29ubmVjdGlvbjtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0RGFlbW9uQ29ubmVjdGlvbigpOiBQcm9taXNlPE1vbmVyb1JwY0Nvbm5lY3Rpb24+IHtcbiAgICByZXR1cm4gdGhpcy5kYWVtb25Db25uZWN0aW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgdG90YWwgYW5kIHVubG9ja2VkIGJhbGFuY2VzIGluIGEgc2luZ2xlIHJlcXVlc3QuXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FjY291bnRJZHhdIGFjY291bnQgaW5kZXhcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtzdWJhZGRyZXNzSWR4XSBzdWJhZGRyZXNzIGluZGV4XG4gICAqIEByZXR1cm4ge1Byb21pc2U8YmlnaW50W10+fSBpcyB0aGUgdG90YWwgYW5kIHVubG9ja2VkIGJhbGFuY2VzIGluIGFuIGFycmF5LCByZXNwZWN0aXZlbHlcbiAgICovXG4gIGFzeW5jIGdldEJhbGFuY2VzKGFjY291bnRJZHg/OiBudW1iZXIsIHN1YmFkZHJlc3NJZHg/OiBudW1iZXIpOiBQcm9taXNlPGJpZ2ludFtdPiB7XG4gICAgaWYgKGFjY291bnRJZHggPT09IHVuZGVmaW5lZCkge1xuICAgICAgYXNzZXJ0LmVxdWFsKHN1YmFkZHJlc3NJZHgsIHVuZGVmaW5lZCwgXCJNdXN0IHByb3ZpZGUgYWNjb3VudCBpbmRleCB3aXRoIHN1YmFkZHJlc3MgaW5kZXhcIik7XG4gICAgICBsZXQgYmFsYW5jZSA9IEJpZ0ludCgwKTtcbiAgICAgIGxldCB1bmxvY2tlZEJhbGFuY2UgPSBCaWdJbnQoMCk7XG4gICAgICBmb3IgKGxldCBhY2NvdW50IG9mIGF3YWl0IHRoaXMuZ2V0QWNjb3VudHMoKSkge1xuICAgICAgICBiYWxhbmNlID0gYmFsYW5jZSArIGFjY291bnQuZ2V0QmFsYW5jZSgpO1xuICAgICAgICB1bmxvY2tlZEJhbGFuY2UgPSB1bmxvY2tlZEJhbGFuY2UgKyBhY2NvdW50LmdldFVubG9ja2VkQmFsYW5jZSgpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIFtiYWxhbmNlLCB1bmxvY2tlZEJhbGFuY2VdO1xuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgcGFyYW1zID0ge2FjY291bnRfaW5kZXg6IGFjY291bnRJZHgsIGFkZHJlc3NfaW5kaWNlczogc3ViYWRkcmVzc0lkeCA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogW3N1YmFkZHJlc3NJZHhdfTtcbiAgICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2JhbGFuY2VcIiwgcGFyYW1zKTtcbiAgICAgIGlmIChzdWJhZGRyZXNzSWR4ID09PSB1bmRlZmluZWQpIHJldHVybiBbQmlnSW50KHJlc3AucmVzdWx0LmJhbGFuY2UpLCBCaWdJbnQocmVzcC5yZXN1bHQudW5sb2NrZWRfYmFsYW5jZSldO1xuICAgICAgZWxzZSByZXR1cm4gW0JpZ0ludChyZXNwLnJlc3VsdC5wZXJfc3ViYWRkcmVzc1swXS5iYWxhbmNlKSwgQmlnSW50KHJlc3AucmVzdWx0LnBlcl9zdWJhZGRyZXNzWzBdLnVubG9ja2VkX2JhbGFuY2UpXTtcbiAgICB9XG4gIH1cbiAgXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIENPTU1PTiBXQUxMRVQgTUVUSE9EUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIFxuICBhc3luYyBhZGRMaXN0ZW5lcihsaXN0ZW5lcjogTW9uZXJvV2FsbGV0TGlzdGVuZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCBzdXBlci5hZGRMaXN0ZW5lcihsaXN0ZW5lcik7XG4gICAgdGhpcy5yZWZyZXNoTGlzdGVuaW5nKCk7XG4gIH1cbiAgXG4gIGFzeW5jIHJlbW92ZUxpc3RlbmVyKGxpc3RlbmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgc3VwZXIucmVtb3ZlTGlzdGVuZXIobGlzdGVuZXIpO1xuICAgIHRoaXMucmVmcmVzaExpc3RlbmluZygpO1xuICB9XG4gIFxuICBhc3luYyBpc0Nvbm5lY3RlZFRvRGFlbW9uKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLmNoZWNrUmVzZXJ2ZVByb29mKGF3YWl0IHRoaXMuZ2V0UHJpbWFyeUFkZHJlc3MoKSwgXCJcIiwgXCJcIik7IC8vIFRPRE8gKG1vbmVyby1wcm9qZWN0KTogcHJvdmlkZSBiZXR0ZXIgd2F5IHRvIGtub3cgaWYgd2FsbGV0IHJwYyBpcyBjb25uZWN0ZWQgdG8gZGFlbW9uXG4gICAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJjaGVjayByZXNlcnZlIGV4cGVjdGVkIHRvIGZhaWxcIik7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICByZXR1cm4gZS5tZXNzYWdlLmluZGV4T2YoXCJGYWlsZWQgdG8gY29ubmVjdCB0byBkYWVtb25cIikgPCAwO1xuICAgIH1cbiAgfVxuICBcbiAgYXN5bmMgZ2V0VmVyc2lvbigpOiBQcm9taXNlPE1vbmVyb1ZlcnNpb24+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF92ZXJzaW9uXCIpO1xuICAgIHJldHVybiBuZXcgTW9uZXJvVmVyc2lvbihyZXNwLnJlc3VsdC52ZXJzaW9uLCByZXNwLnJlc3VsdC5yZWxlYXNlKTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UGF0aCgpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHJldHVybiB0aGlzLnBhdGg7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFNlZWQoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcInF1ZXJ5X2tleVwiLCB7IGtleV90eXBlOiBcIm1uZW1vbmljXCIgfSk7XG4gICAgcmV0dXJuIHJlc3AucmVzdWx0LmtleTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0U2VlZExhbmd1YWdlKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgaWYgKGF3YWl0IHRoaXMuZ2V0U2VlZCgpID09PSB1bmRlZmluZWQpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTW9uZXJvV2FsbGV0UnBjLmdldFNlZWRMYW5ndWFnZSgpIG5vdCBzdXBwb3J0ZWRcIik7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGEgbGlzdCBvZiBhdmFpbGFibGUgbGFuZ3VhZ2VzIGZvciB0aGUgd2FsbGV0J3Mgc2VlZC5cbiAgICogXG4gICAqIEByZXR1cm4ge3N0cmluZ1tdfSB0aGUgYXZhaWxhYmxlIGxhbmd1YWdlcyBmb3IgdGhlIHdhbGxldCdzIHNlZWQuXG4gICAqL1xuICBhc3luYyBnZXRTZWVkTGFuZ3VhZ2VzKCkge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2xhbmd1YWdlc1wiKSkucmVzdWx0Lmxhbmd1YWdlcztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UHJpdmF0ZVZpZXdLZXkoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcInF1ZXJ5X2tleVwiLCB7IGtleV90eXBlOiBcInZpZXdfa2V5XCIgfSk7XG4gICAgcmV0dXJuIHJlc3AucmVzdWx0LmtleTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UHJpdmF0ZVNwZW5kS2V5KCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJxdWVyeV9rZXlcIiwgeyBrZXlfdHlwZTogXCJzcGVuZF9rZXlcIiB9KTtcbiAgICByZXR1cm4gcmVzcC5yZXN1bHQua2V5O1xuICB9XG4gIFxuICBhc3luYyBnZXRBZGRyZXNzKGFjY291bnRJZHg6IG51bWJlciwgc3ViYWRkcmVzc0lkeDogbnVtYmVyKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBsZXQgc3ViYWRkcmVzc01hcCA9IHRoaXMuYWRkcmVzc0NhY2hlW2FjY291bnRJZHhdO1xuICAgIGlmICghc3ViYWRkcmVzc01hcCkge1xuICAgICAgYXdhaXQgdGhpcy5nZXRTdWJhZGRyZXNzZXMoYWNjb3VudElkeCwgdW5kZWZpbmVkLCB0cnVlKTsgIC8vIGNhY2hlJ3MgYWxsIGFkZHJlc3NlcyBhdCB0aGlzIGFjY291bnRcbiAgICAgIHJldHVybiB0aGlzLmdldEFkZHJlc3MoYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCk7ICAgICAgICAvLyByZWN1cnNpdmUgY2FsbCB1c2VzIGNhY2hlXG4gICAgfVxuICAgIGxldCBhZGRyZXNzID0gc3ViYWRkcmVzc01hcFtzdWJhZGRyZXNzSWR4XTtcbiAgICBpZiAoIWFkZHJlc3MpIHtcbiAgICAgIGF3YWl0IHRoaXMuZ2V0U3ViYWRkcmVzc2VzKGFjY291bnRJZHgsIHVuZGVmaW5lZCwgdHJ1ZSk7ICAvLyBjYWNoZSdzIGFsbCBhZGRyZXNzZXMgYXQgdGhpcyBhY2NvdW50XG4gICAgICByZXR1cm4gdGhpcy5hZGRyZXNzQ2FjaGVbYWNjb3VudElkeF1bc3ViYWRkcmVzc0lkeF07XG4gICAgfVxuICAgIHJldHVybiBhZGRyZXNzO1xuICB9XG4gIFxuICAvLyBUT0RPOiB1c2UgY2FjaGVcbiAgYXN5bmMgZ2V0QWRkcmVzc0luZGV4KGFkZHJlc3M6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvU3ViYWRkcmVzcz4ge1xuICAgIFxuICAgIC8vIGZldGNoIHJlc3VsdCBhbmQgbm9ybWFsaXplIGVycm9yIGlmIGFkZHJlc3MgZG9lcyBub3QgYmVsb25nIHRvIHRoZSB3YWxsZXRcbiAgICBsZXQgcmVzcDtcbiAgICB0cnkge1xuICAgICAgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF9hZGRyZXNzX2luZGV4XCIsIHthZGRyZXNzOiBhZGRyZXNzfSk7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICBpZiAoZS5nZXRDb2RlKCkgPT09IC0yKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoZS5tZXNzYWdlKTtcbiAgICAgIHRocm93IGU7XG4gICAgfVxuICAgIFxuICAgIC8vIGNvbnZlcnQgcnBjIHJlc3BvbnNlXG4gICAgbGV0IHN1YmFkZHJlc3MgPSBuZXcgTW9uZXJvU3ViYWRkcmVzcyh7YWRkcmVzczogYWRkcmVzc30pO1xuICAgIHN1YmFkZHJlc3Muc2V0QWNjb3VudEluZGV4KHJlc3AucmVzdWx0LmluZGV4Lm1ham9yKTtcbiAgICBzdWJhZGRyZXNzLnNldEluZGV4KHJlc3AucmVzdWx0LmluZGV4Lm1pbm9yKTtcbiAgICByZXR1cm4gc3ViYWRkcmVzcztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0SW50ZWdyYXRlZEFkZHJlc3Moc3RhbmRhcmRBZGRyZXNzPzogc3RyaW5nLCBwYXltZW50SWQ/OiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0ludGVncmF0ZWRBZGRyZXNzPiB7XG4gICAgdHJ5IHtcbiAgICAgIGxldCBpbnRlZ3JhdGVkQWRkcmVzc1N0ciA9IChhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJtYWtlX2ludGVncmF0ZWRfYWRkcmVzc1wiLCB7c3RhbmRhcmRfYWRkcmVzczogc3RhbmRhcmRBZGRyZXNzLCBwYXltZW50X2lkOiBwYXltZW50SWR9KSkucmVzdWx0LmludGVncmF0ZWRfYWRkcmVzcztcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLmRlY29kZUludGVncmF0ZWRBZGRyZXNzKGludGVncmF0ZWRBZGRyZXNzU3RyKTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIGlmIChlLm1lc3NhZ2UuaW5jbHVkZXMoXCJJbnZhbGlkIHBheW1lbnQgSURcIikpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkludmFsaWQgcGF5bWVudCBJRDogXCIgKyBwYXltZW50SWQpO1xuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gIH1cbiAgXG4gIGFzeW5jIGRlY29kZUludGVncmF0ZWRBZGRyZXNzKGludGVncmF0ZWRBZGRyZXNzOiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0ludGVncmF0ZWRBZGRyZXNzPiB7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJzcGxpdF9pbnRlZ3JhdGVkX2FkZHJlc3NcIiwge2ludGVncmF0ZWRfYWRkcmVzczogaW50ZWdyYXRlZEFkZHJlc3N9KTtcbiAgICByZXR1cm4gbmV3IE1vbmVyb0ludGVncmF0ZWRBZGRyZXNzKCkuc2V0U3RhbmRhcmRBZGRyZXNzKHJlc3AucmVzdWx0LnN0YW5kYXJkX2FkZHJlc3MpLnNldFBheW1lbnRJZChyZXNwLnJlc3VsdC5wYXltZW50X2lkKS5zZXRJbnRlZ3JhdGVkQWRkcmVzcyhpbnRlZ3JhdGVkQWRkcmVzcyk7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEhlaWdodCgpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2hlaWdodFwiKSkucmVzdWx0LmhlaWdodDtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0RGFlbW9uSGVpZ2h0KCk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwibW9uZXJvLXdhbGxldC1ycGMgZG9lcyBub3Qgc3VwcG9ydCBnZXR0aW5nIHRoZSBjaGFpbiBoZWlnaHRcIik7XG4gIH1cbiAgXG4gIGFzeW5jIGdldEhlaWdodEJ5RGF0ZSh5ZWFyOiBudW1iZXIsIG1vbnRoOiBudW1iZXIsIGRheTogbnVtYmVyKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJtb25lcm8td2FsbGV0LXJwYyBkb2VzIG5vdCBzdXBwb3J0IGdldHRpbmcgYSBoZWlnaHQgYnkgZGF0ZVwiKTtcbiAgfVxuICBcbiAgYXN5bmMgc3luYyhsaXN0ZW5lck9yU3RhcnRIZWlnaHQ/OiBNb25lcm9XYWxsZXRMaXN0ZW5lciB8IG51bWJlciwgc3RhcnRIZWlnaHQ/OiBudW1iZXIpOiBQcm9taXNlPE1vbmVyb1N5bmNSZXN1bHQ+IHtcbiAgICBhc3NlcnQoIShsaXN0ZW5lck9yU3RhcnRIZWlnaHQgaW5zdGFuY2VvZiBNb25lcm9XYWxsZXRMaXN0ZW5lciksIFwiTW9uZXJvIFdhbGxldCBSUEMgZG9lcyBub3Qgc3VwcG9ydCByZXBvcnRpbmcgc3luYyBwcm9ncmVzc1wiKTtcbiAgICB0cnkge1xuICAgICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJyZWZyZXNoXCIsIHtzdGFydF9oZWlnaHQ6IHN0YXJ0SGVpZ2h0fSk7XG4gICAgICBhd2FpdCB0aGlzLnBvbGwoKTtcbiAgICAgIHJldHVybiBuZXcgTW9uZXJvU3luY1Jlc3VsdChyZXNwLnJlc3VsdC5ibG9ja3NfZmV0Y2hlZCwgcmVzcC5yZXN1bHQucmVjZWl2ZWRfbW9uZXkpO1xuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICBpZiAoZXJyLm1lc3NhZ2UgPT09IFwibm8gY29ubmVjdGlvbiB0byBkYWVtb25cIikgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiV2FsbGV0IGlzIG5vdCBjb25uZWN0ZWQgdG8gZGFlbW9uXCIpO1xuICAgICAgdGhyb3cgZXJyO1xuICAgIH1cbiAgfVxuICBcbiAgYXN5bmMgc3RhcnRTeW5jaW5nKHN5bmNQZXJpb2RJbk1zPzogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgXG4gICAgLy8gY29udmVydCBtcyB0byBzZWNvbmRzIGZvciBycGMgcGFyYW1ldGVyXG4gICAgbGV0IHN5bmNQZXJpb2RJblNlY29uZHMgPSBNYXRoLnJvdW5kKChzeW5jUGVyaW9kSW5NcyA9PT0gdW5kZWZpbmVkID8gTW9uZXJvV2FsbGV0UnBjLkRFRkFVTFRfU1lOQ19QRVJJT0RfSU5fTVMgOiBzeW5jUGVyaW9kSW5NcykgLyAxMDAwKTtcbiAgICBcbiAgICAvLyBzZW5kIHJwYyByZXF1ZXN0XG4gICAgYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiYXV0b19yZWZyZXNoXCIsIHtcbiAgICAgIGVuYWJsZTogdHJ1ZSxcbiAgICAgIHBlcmlvZDogc3luY1BlcmlvZEluU2Vjb25kc1xuICAgIH0pO1xuICAgIFxuICAgIC8vIHVwZGF0ZSBzeW5jIHBlcmlvZCBmb3IgcG9sbGVyXG4gICAgdGhpcy5zeW5jUGVyaW9kSW5NcyA9IHN5bmNQZXJpb2RJblNlY29uZHMgKiAxMDAwO1xuICAgIGlmICh0aGlzLndhbGxldFBvbGxlciAhPT0gdW5kZWZpbmVkKSB0aGlzLndhbGxldFBvbGxlci5zZXRQZXJpb2RJbk1zKHRoaXMuc3luY1BlcmlvZEluTXMpO1xuICAgIFxuICAgIC8vIHBvbGwgaWYgbGlzdGVuaW5nXG4gICAgYXdhaXQgdGhpcy5wb2xsKCk7XG4gIH1cblxuICBnZXRTeW5jUGVyaW9kSW5NcygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnN5bmNQZXJpb2RJbk1zO1xuICB9XG4gIFxuICBhc3luYyBzdG9wU3luY2luZygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiYXV0b19yZWZyZXNoXCIsIHsgZW5hYmxlOiBmYWxzZSB9KTtcbiAgfVxuICBcbiAgYXN5bmMgc2NhblR4cyh0eEhhc2hlczogc3RyaW5nW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXR4SGFzaGVzIHx8ICF0eEhhc2hlcy5sZW5ndGgpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vIHR4IGhhc2hlcyBnaXZlbiB0byBzY2FuXCIpO1xuICAgIGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcInNjYW5fdHhcIiwge3R4aWRzOiB0eEhhc2hlc30pO1xuICAgIGF3YWl0IHRoaXMucG9sbCgpO1xuICB9XG4gIFxuICBhc3luYyByZXNjYW5TcGVudCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJyZXNjYW5fc3BlbnRcIiwgdW5kZWZpbmVkKTtcbiAgfVxuICBcbiAgYXN5bmMgcmVzY2FuQmxvY2tjaGFpbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJyZXNjYW5fYmxvY2tjaGFpblwiLCB1bmRlZmluZWQpO1xuICB9XG4gIFxuICBhc3luYyBnZXRCYWxhbmNlKGFjY291bnRJZHg/OiBudW1iZXIsIHN1YmFkZHJlc3NJZHg/OiBudW1iZXIpOiBQcm9taXNlPGJpZ2ludD4ge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5nZXRCYWxhbmNlcyhhY2NvdW50SWR4LCBzdWJhZGRyZXNzSWR4KSlbMF07XG4gIH1cbiAgXG4gIGFzeW5jIGdldFVubG9ja2VkQmFsYW5jZShhY2NvdW50SWR4PzogbnVtYmVyLCBzdWJhZGRyZXNzSWR4PzogbnVtYmVyKTogUHJvbWlzZTxiaWdpbnQ+IHtcbiAgICByZXR1cm4gKGF3YWl0IHRoaXMuZ2V0QmFsYW5jZXMoYWNjb3VudElkeCwgc3ViYWRkcmVzc0lkeCkpWzFdO1xuICB9XG4gIFxuICBhc3luYyBnZXRBY2NvdW50cyhpbmNsdWRlU3ViYWRkcmVzc2VzPzogYm9vbGVhbiwgdGFnPzogc3RyaW5nLCBza2lwQmFsYW5jZXM/OiBib29sZWFuKTogUHJvbWlzZTxNb25lcm9BY2NvdW50W10+IHtcbiAgICBcbiAgICAvLyBmZXRjaCBhY2NvdW50cyBmcm9tIHJwY1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2FjY291bnRzXCIsIHt0YWc6IHRhZ30pO1xuICAgIFxuICAgIC8vIGJ1aWxkIGFjY291bnQgb2JqZWN0cyBhbmQgZmV0Y2ggc3ViYWRkcmVzc2VzIHBlciBhY2NvdW50IHVzaW5nIGdldF9hZGRyZXNzXG4gICAgLy8gVE9ETyBtb25lcm8td2FsbGV0LXJwYzogZ2V0X2FkZHJlc3Mgc2hvdWxkIHN1cHBvcnQgYWxsX2FjY291bnRzIHNvIG5vdCBjYWxsZWQgb25jZSBwZXIgYWNjb3VudFxuICAgIGxldCBhY2NvdW50czogTW9uZXJvQWNjb3VudFtdID0gW107XG4gICAgZm9yIChsZXQgcnBjQWNjb3VudCBvZiByZXNwLnJlc3VsdC5zdWJhZGRyZXNzX2FjY291bnRzKSB7XG4gICAgICBsZXQgYWNjb3VudCA9IE1vbmVyb1dhbGxldFJwYy5jb252ZXJ0UnBjQWNjb3VudChycGNBY2NvdW50KTtcbiAgICAgIGlmIChpbmNsdWRlU3ViYWRkcmVzc2VzKSBhY2NvdW50LnNldFN1YmFkZHJlc3Nlcyhhd2FpdCB0aGlzLmdldFN1YmFkZHJlc3NlcyhhY2NvdW50LmdldEluZGV4KCksIHVuZGVmaW5lZCwgdHJ1ZSkpO1xuICAgICAgYWNjb3VudHMucHVzaChhY2NvdW50KTtcbiAgICB9XG4gICAgXG4gICAgLy8gZmV0Y2ggYW5kIG1lcmdlIGZpZWxkcyBmcm9tIGdldF9iYWxhbmNlIGFjcm9zcyBhbGwgYWNjb3VudHNcbiAgICBpZiAoaW5jbHVkZVN1YmFkZHJlc3NlcyAmJiAhc2tpcEJhbGFuY2VzKSB7XG4gICAgICBcbiAgICAgIC8vIHRoZXNlIGZpZWxkcyBhcmUgbm90IGluaXRpYWxpemVkIGlmIHN1YmFkZHJlc3MgaXMgdW51c2VkIGFuZCB0aGVyZWZvcmUgbm90IHJldHVybmVkIGZyb20gYGdldF9iYWxhbmNlYFxuICAgICAgZm9yIChsZXQgYWNjb3VudCBvZiBhY2NvdW50cykge1xuICAgICAgICBmb3IgKGxldCBzdWJhZGRyZXNzIG9mIGFjY291bnQuZ2V0U3ViYWRkcmVzc2VzKCkpIHtcbiAgICAgICAgICBzdWJhZGRyZXNzLnNldEJhbGFuY2UoQmlnSW50KDApKTtcbiAgICAgICAgICBzdWJhZGRyZXNzLnNldFVubG9ja2VkQmFsYW5jZShCaWdJbnQoMCkpO1xuICAgICAgICAgIHN1YmFkZHJlc3Muc2V0TnVtVW5zcGVudE91dHB1dHMoMCk7XG4gICAgICAgICAgc3ViYWRkcmVzcy5zZXROdW1CbG9ja3NUb1VubG9jaygwKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBmZXRjaCBhbmQgbWVyZ2UgaW5mbyBmcm9tIGdldF9iYWxhbmNlXG4gICAgICByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2JhbGFuY2VcIiwge2FsbF9hY2NvdW50czogdHJ1ZX0pO1xuICAgICAgaWYgKHJlc3AucmVzdWx0LnBlcl9zdWJhZGRyZXNzKSB7XG4gICAgICAgIGZvciAobGV0IHJwY1N1YmFkZHJlc3Mgb2YgcmVzcC5yZXN1bHQucGVyX3N1YmFkZHJlc3MpIHtcbiAgICAgICAgICBsZXQgc3ViYWRkcmVzcyA9IE1vbmVyb1dhbGxldFJwYy5jb252ZXJ0UnBjU3ViYWRkcmVzcyhycGNTdWJhZGRyZXNzKTtcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBtZXJnZSBpbmZvXG4gICAgICAgICAgbGV0IGFjY291bnQgPSBhY2NvdW50c1tzdWJhZGRyZXNzLmdldEFjY291bnRJbmRleCgpXTtcbiAgICAgICAgICBhc3NlcnQuZXF1YWwoc3ViYWRkcmVzcy5nZXRBY2NvdW50SW5kZXgoKSwgYWNjb3VudC5nZXRJbmRleCgpLCBcIlJQQyBhY2NvdW50cyBhcmUgb3V0IG9mIG9yZGVyXCIpOyAgLy8gd291bGQgbmVlZCB0byBzd2l0Y2ggbG9va3VwIHRvIGxvb3BcbiAgICAgICAgICBsZXQgdGd0U3ViYWRkcmVzcyA9IGFjY291bnQuZ2V0U3ViYWRkcmVzc2VzKClbc3ViYWRkcmVzcy5nZXRJbmRleCgpXTtcbiAgICAgICAgICBhc3NlcnQuZXF1YWwoc3ViYWRkcmVzcy5nZXRJbmRleCgpLCB0Z3RTdWJhZGRyZXNzLmdldEluZGV4KCksIFwiUlBDIHN1YmFkZHJlc3NlcyBhcmUgb3V0IG9mIG9yZGVyXCIpO1xuICAgICAgICAgIGlmIChzdWJhZGRyZXNzLmdldEJhbGFuY2UoKSAhPT0gdW5kZWZpbmVkKSB0Z3RTdWJhZGRyZXNzLnNldEJhbGFuY2Uoc3ViYWRkcmVzcy5nZXRCYWxhbmNlKCkpO1xuICAgICAgICAgIGlmIChzdWJhZGRyZXNzLmdldFVubG9ja2VkQmFsYW5jZSgpICE9PSB1bmRlZmluZWQpIHRndFN1YmFkZHJlc3Muc2V0VW5sb2NrZWRCYWxhbmNlKHN1YmFkZHJlc3MuZ2V0VW5sb2NrZWRCYWxhbmNlKCkpO1xuICAgICAgICAgIGlmIChzdWJhZGRyZXNzLmdldE51bVVuc3BlbnRPdXRwdXRzKCkgIT09IHVuZGVmaW5lZCkgdGd0U3ViYWRkcmVzcy5zZXROdW1VbnNwZW50T3V0cHV0cyhzdWJhZGRyZXNzLmdldE51bVVuc3BlbnRPdXRwdXRzKCkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBhY2NvdW50cztcbiAgfVxuICBcbiAgLy8gVE9ETzogZ2V0QWNjb3VudEJ5SW5kZXgoKSwgZ2V0QWNjb3VudEJ5VGFnKClcbiAgYXN5bmMgZ2V0QWNjb3VudChhY2NvdW50SWR4OiBudW1iZXIsIGluY2x1ZGVTdWJhZGRyZXNzZXM/OiBib29sZWFuLCBza2lwQmFsYW5jZXM/OiBib29sZWFuKTogUHJvbWlzZTxNb25lcm9BY2NvdW50PiB7XG4gICAgYXNzZXJ0KGFjY291bnRJZHggPj0gMCk7XG4gICAgZm9yIChsZXQgYWNjb3VudCBvZiBhd2FpdCB0aGlzLmdldEFjY291bnRzKCkpIHtcbiAgICAgIGlmIChhY2NvdW50LmdldEluZGV4KCkgPT09IGFjY291bnRJZHgpIHtcbiAgICAgICAgaWYgKGluY2x1ZGVTdWJhZGRyZXNzZXMpIGFjY291bnQuc2V0U3ViYWRkcmVzc2VzKGF3YWl0IHRoaXMuZ2V0U3ViYWRkcmVzc2VzKGFjY291bnRJZHgsIHVuZGVmaW5lZCwgc2tpcEJhbGFuY2VzKSk7XG4gICAgICAgIHJldHVybiBhY2NvdW50O1xuICAgICAgfVxuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJBY2NvdW50IHdpdGggaW5kZXggXCIgKyBhY2NvdW50SWR4ICsgXCIgZG9lcyBub3QgZXhpc3RcIik7XG4gIH1cblxuICBhc3luYyBjcmVhdGVBY2NvdW50KGxhYmVsPzogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9BY2NvdW50PiB7XG4gICAgbGFiZWwgPSBsYWJlbCA/IGxhYmVsIDogdW5kZWZpbmVkO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiY3JlYXRlX2FjY291bnRcIiwge2xhYmVsOiBsYWJlbH0pO1xuICAgIHJldHVybiBuZXcgTW9uZXJvQWNjb3VudCh7XG4gICAgICBpbmRleDogcmVzcC5yZXN1bHQuYWNjb3VudF9pbmRleCxcbiAgICAgIHByaW1hcnlBZGRyZXNzOiByZXNwLnJlc3VsdC5hZGRyZXNzLFxuICAgICAgbGFiZWw6IGxhYmVsLFxuICAgICAgYmFsYW5jZTogQmlnSW50KDApLFxuICAgICAgdW5sb2NrZWRCYWxhbmNlOiBCaWdJbnQoMClcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIGdldFN1YmFkZHJlc3NlcyhhY2NvdW50SWR4OiBudW1iZXIsIHN1YmFkZHJlc3NJbmRpY2VzPzogbnVtYmVyW10sIHNraXBCYWxhbmNlcz86IGJvb2xlYW4pOiBQcm9taXNlPE1vbmVyb1N1YmFkZHJlc3NbXT4ge1xuICAgIFxuICAgIC8vIGZldGNoIHN1YmFkZHJlc3Nlc1xuICAgIGxldCBwYXJhbXM6IGFueSA9IHt9O1xuICAgIHBhcmFtcy5hY2NvdW50X2luZGV4ID0gYWNjb3VudElkeDtcbiAgICBpZiAoc3ViYWRkcmVzc0luZGljZXMpIHBhcmFtcy5hZGRyZXNzX2luZGV4ID0gR2VuVXRpbHMubGlzdGlmeShzdWJhZGRyZXNzSW5kaWNlcyk7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJnZXRfYWRkcmVzc1wiLCBwYXJhbXMpO1xuICAgIFxuICAgIC8vIGluaXRpYWxpemUgc3ViYWRkcmVzc2VzXG4gICAgbGV0IHN1YmFkZHJlc3NlcyA9IFtdO1xuICAgIGZvciAobGV0IHJwY1N1YmFkZHJlc3Mgb2YgcmVzcC5yZXN1bHQuYWRkcmVzc2VzKSB7XG4gICAgICBsZXQgc3ViYWRkcmVzcyA9IE1vbmVyb1dhbGxldFJwYy5jb252ZXJ0UnBjU3ViYWRkcmVzcyhycGNTdWJhZGRyZXNzKTtcbiAgICAgIHN1YmFkZHJlc3Muc2V0QWNjb3VudEluZGV4KGFjY291bnRJZHgpO1xuICAgICAgc3ViYWRkcmVzc2VzLnB1c2goc3ViYWRkcmVzcyk7XG4gICAgfVxuICAgIFxuICAgIC8vIGZldGNoIGFuZCBpbml0aWFsaXplIHN1YmFkZHJlc3MgYmFsYW5jZXNcbiAgICBpZiAoIXNraXBCYWxhbmNlcykge1xuICAgICAgXG4gICAgICAvLyB0aGVzZSBmaWVsZHMgYXJlIG5vdCBpbml0aWFsaXplZCBpZiBzdWJhZGRyZXNzIGlzIHVudXNlZCBhbmQgdGhlcmVmb3JlIG5vdCByZXR1cm5lZCBmcm9tIGBnZXRfYmFsYW5jZWBcbiAgICAgIGZvciAobGV0IHN1YmFkZHJlc3Mgb2Ygc3ViYWRkcmVzc2VzKSB7XG4gICAgICAgIHN1YmFkZHJlc3Muc2V0QmFsYW5jZShCaWdJbnQoMCkpO1xuICAgICAgICBzdWJhZGRyZXNzLnNldFVubG9ja2VkQmFsYW5jZShCaWdJbnQoMCkpO1xuICAgICAgICBzdWJhZGRyZXNzLnNldE51bVVuc3BlbnRPdXRwdXRzKDApO1xuICAgICAgICBzdWJhZGRyZXNzLnNldE51bUJsb2Nrc1RvVW5sb2NrKDApO1xuICAgICAgfVxuXG4gICAgICAvLyBmZXRjaCBhbmQgaW5pdGlhbGl6ZSBiYWxhbmNlc1xuICAgICAgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF9iYWxhbmNlXCIsIHBhcmFtcyk7XG4gICAgICBpZiAocmVzcC5yZXN1bHQucGVyX3N1YmFkZHJlc3MpIHtcbiAgICAgICAgZm9yIChsZXQgcnBjU3ViYWRkcmVzcyBvZiByZXNwLnJlc3VsdC5wZXJfc3ViYWRkcmVzcykge1xuICAgICAgICAgIGxldCBzdWJhZGRyZXNzID0gTW9uZXJvV2FsbGV0UnBjLmNvbnZlcnRScGNTdWJhZGRyZXNzKHJwY1N1YmFkZHJlc3MpO1xuICAgICAgICAgIFxuICAgICAgICAgIC8vIHRyYW5zZmVyIGluZm8gdG8gZXhpc3Rpbmcgc3ViYWRkcmVzcyBvYmplY3RcbiAgICAgICAgICBmb3IgKGxldCB0Z3RTdWJhZGRyZXNzIG9mIHN1YmFkZHJlc3Nlcykge1xuICAgICAgICAgICAgaWYgKHRndFN1YmFkZHJlc3MuZ2V0SW5kZXgoKSAhPT0gc3ViYWRkcmVzcy5nZXRJbmRleCgpKSBjb250aW51ZTsgLy8gc2tpcCB0byBzdWJhZGRyZXNzIHdpdGggc2FtZSBpbmRleFxuICAgICAgICAgICAgaWYgKHN1YmFkZHJlc3MuZ2V0QmFsYW5jZSgpICE9PSB1bmRlZmluZWQpIHRndFN1YmFkZHJlc3Muc2V0QmFsYW5jZShzdWJhZGRyZXNzLmdldEJhbGFuY2UoKSk7XG4gICAgICAgICAgICBpZiAoc3ViYWRkcmVzcy5nZXRVbmxvY2tlZEJhbGFuY2UoKSAhPT0gdW5kZWZpbmVkKSB0Z3RTdWJhZGRyZXNzLnNldFVubG9ja2VkQmFsYW5jZShzdWJhZGRyZXNzLmdldFVubG9ja2VkQmFsYW5jZSgpKTtcbiAgICAgICAgICAgIGlmIChzdWJhZGRyZXNzLmdldE51bVVuc3BlbnRPdXRwdXRzKCkgIT09IHVuZGVmaW5lZCkgdGd0U3ViYWRkcmVzcy5zZXROdW1VbnNwZW50T3V0cHV0cyhzdWJhZGRyZXNzLmdldE51bVVuc3BlbnRPdXRwdXRzKCkpO1xuICAgICAgICAgICAgaWYgKHN1YmFkZHJlc3MuZ2V0TnVtQmxvY2tzVG9VbmxvY2soKSAhPT0gdW5kZWZpbmVkKSB0Z3RTdWJhZGRyZXNzLnNldE51bUJsb2Nrc1RvVW5sb2NrKHN1YmFkZHJlc3MuZ2V0TnVtQmxvY2tzVG9VbmxvY2soKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIGNhY2hlIGFkZHJlc3Nlc1xuICAgIGxldCBzdWJhZGRyZXNzTWFwID0gdGhpcy5hZGRyZXNzQ2FjaGVbYWNjb3VudElkeF07XG4gICAgaWYgKCFzdWJhZGRyZXNzTWFwKSB7XG4gICAgICBzdWJhZGRyZXNzTWFwID0ge307XG4gICAgICB0aGlzLmFkZHJlc3NDYWNoZVthY2NvdW50SWR4XSA9IHN1YmFkZHJlc3NNYXA7XG4gICAgfVxuICAgIGZvciAobGV0IHN1YmFkZHJlc3Mgb2Ygc3ViYWRkcmVzc2VzKSB7XG4gICAgICBzdWJhZGRyZXNzTWFwW3N1YmFkZHJlc3MuZ2V0SW5kZXgoKV0gPSBzdWJhZGRyZXNzLmdldEFkZHJlc3MoKTtcbiAgICB9XG4gICAgXG4gICAgLy8gcmV0dXJuIHJlc3VsdHNcbiAgICByZXR1cm4gc3ViYWRkcmVzc2VzO1xuICB9XG5cbiAgYXN5bmMgZ2V0U3ViYWRkcmVzcyhhY2NvdW50SWR4OiBudW1iZXIsIHN1YmFkZHJlc3NJZHg6IG51bWJlciwgc2tpcEJhbGFuY2VzPzogYm9vbGVhbik6IFByb21pc2U8TW9uZXJvU3ViYWRkcmVzcz4ge1xuICAgIGFzc2VydChhY2NvdW50SWR4ID49IDApO1xuICAgIGFzc2VydChzdWJhZGRyZXNzSWR4ID49IDApO1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5nZXRTdWJhZGRyZXNzZXMoYWNjb3VudElkeCwgW3N1YmFkZHJlc3NJZHhdLCBza2lwQmFsYW5jZXMpKVswXTtcbiAgfVxuXG4gIGFzeW5jIGNyZWF0ZVN1YmFkZHJlc3MoYWNjb3VudElkeDogbnVtYmVyLCBsYWJlbD86IHN0cmluZyk6IFByb21pc2U8TW9uZXJvU3ViYWRkcmVzcz4ge1xuICAgIFxuICAgIC8vIHNlbmQgcmVxdWVzdFxuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiY3JlYXRlX2FkZHJlc3NcIiwge2FjY291bnRfaW5kZXg6IGFjY291bnRJZHgsIGxhYmVsOiBsYWJlbH0pO1xuICAgIFxuICAgIC8vIGJ1aWxkIHN1YmFkZHJlc3Mgb2JqZWN0XG4gICAgbGV0IHN1YmFkZHJlc3MgPSBuZXcgTW9uZXJvU3ViYWRkcmVzcygpO1xuICAgIHN1YmFkZHJlc3Muc2V0QWNjb3VudEluZGV4KGFjY291bnRJZHgpO1xuICAgIHN1YmFkZHJlc3Muc2V0SW5kZXgocmVzcC5yZXN1bHQuYWRkcmVzc19pbmRleCk7XG4gICAgc3ViYWRkcmVzcy5zZXRBZGRyZXNzKHJlc3AucmVzdWx0LmFkZHJlc3MpO1xuICAgIHN1YmFkZHJlc3Muc2V0TGFiZWwobGFiZWwgPyBsYWJlbCA6IHVuZGVmaW5lZCk7XG4gICAgc3ViYWRkcmVzcy5zZXRCYWxhbmNlKEJpZ0ludCgwKSk7XG4gICAgc3ViYWRkcmVzcy5zZXRVbmxvY2tlZEJhbGFuY2UoQmlnSW50KDApKTtcbiAgICBzdWJhZGRyZXNzLnNldE51bVVuc3BlbnRPdXRwdXRzKDApO1xuICAgIHN1YmFkZHJlc3Muc2V0SXNVc2VkKGZhbHNlKTtcbiAgICBzdWJhZGRyZXNzLnNldE51bUJsb2Nrc1RvVW5sb2NrKDApO1xuICAgIHJldHVybiBzdWJhZGRyZXNzO1xuICB9XG5cbiAgYXN5bmMgc2V0U3ViYWRkcmVzc0xhYmVsKGFjY291bnRJZHg6IG51bWJlciwgc3ViYWRkcmVzc0lkeDogbnVtYmVyLCBsYWJlbDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwibGFiZWxfYWRkcmVzc1wiLCB7aW5kZXg6IHttYWpvcjogYWNjb3VudElkeCwgbWlub3I6IHN1YmFkZHJlc3NJZHh9LCBsYWJlbDogbGFiZWx9KTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0VHhzKHF1ZXJ5Pzogc3RyaW5nW10gfCBQYXJ0aWFsPE1vbmVyb1R4UXVlcnk+KTogUHJvbWlzZTxNb25lcm9UeFdhbGxldFtdPiB7XG4gICAgXG4gICAgLy8gY29weSBxdWVyeVxuICAgIGNvbnN0IHF1ZXJ5Tm9ybWFsaXplZCA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVUeFF1ZXJ5KHF1ZXJ5KTtcbiAgICBcbiAgICAvLyB0ZW1wb3JhcmlseSBkaXNhYmxlIHRyYW5zZmVyIGFuZCBvdXRwdXQgcXVlcmllcyBpbiBvcmRlciB0byBjb2xsZWN0IGFsbCB0eCBpbmZvcm1hdGlvblxuICAgIGxldCB0cmFuc2ZlclF1ZXJ5ID0gcXVlcnlOb3JtYWxpemVkLmdldFRyYW5zZmVyUXVlcnkoKTtcbiAgICBsZXQgaW5wdXRRdWVyeSA9IHF1ZXJ5Tm9ybWFsaXplZC5nZXRJbnB1dFF1ZXJ5KCk7XG4gICAgbGV0IG91dHB1dFF1ZXJ5ID0gcXVlcnlOb3JtYWxpemVkLmdldE91dHB1dFF1ZXJ5KCk7XG4gICAgcXVlcnlOb3JtYWxpemVkLnNldFRyYW5zZmVyUXVlcnkodW5kZWZpbmVkKTtcbiAgICBxdWVyeU5vcm1hbGl6ZWQuc2V0SW5wdXRRdWVyeSh1bmRlZmluZWQpO1xuICAgIHF1ZXJ5Tm9ybWFsaXplZC5zZXRPdXRwdXRRdWVyeSh1bmRlZmluZWQpO1xuICAgIFxuICAgIC8vIGZldGNoIGFsbCB0cmFuc2ZlcnMgdGhhdCBtZWV0IHR4IHF1ZXJ5XG4gICAgbGV0IHRyYW5zZmVycyA9IGF3YWl0IHRoaXMuZ2V0VHJhbnNmZXJzQXV4KG5ldyBNb25lcm9UcmFuc2ZlclF1ZXJ5KCkuc2V0VHhRdWVyeShNb25lcm9XYWxsZXRScGMuZGVjb250ZXh0dWFsaXplKHF1ZXJ5Tm9ybWFsaXplZC5jb3B5KCkpKSk7XG4gICAgXG4gICAgLy8gY29sbGVjdCB1bmlxdWUgdHhzIGZyb20gdHJhbnNmZXJzIHdoaWxlIHJldGFpbmluZyBvcmRlclxuICAgIGxldCB0eHMgPSBbXTtcbiAgICBsZXQgdHhzU2V0ID0gbmV3IFNldCgpO1xuICAgIGZvciAobGV0IHRyYW5zZmVyIG9mIHRyYW5zZmVycykge1xuICAgICAgaWYgKCF0eHNTZXQuaGFzKHRyYW5zZmVyLmdldFR4KCkpKSB7XG4gICAgICAgIHR4cy5wdXNoKHRyYW5zZmVyLmdldFR4KCkpO1xuICAgICAgICB0eHNTZXQuYWRkKHRyYW5zZmVyLmdldFR4KCkpO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBjYWNoZSB0eXBlcyBpbnRvIG1hcHMgZm9yIG1lcmdpbmcgYW5kIGxvb2t1cFxuICAgIGxldCB0eE1hcCA9IHt9O1xuICAgIGxldCBibG9ja01hcCA9IHt9O1xuICAgIGZvciAobGV0IHR4IG9mIHR4cykge1xuICAgICAgTW9uZXJvV2FsbGV0UnBjLm1lcmdlVHgodHgsIHR4TWFwLCBibG9ja01hcCk7XG4gICAgfVxuICAgIFxuICAgIC8vIGZldGNoIGFuZCBtZXJnZSBvdXRwdXRzIGlmIHJlcXVlc3RlZFxuICAgIGlmIChxdWVyeU5vcm1hbGl6ZWQuZ2V0SW5jbHVkZU91dHB1dHMoKSB8fCBvdXRwdXRRdWVyeSkge1xuICAgICAgICBcbiAgICAgIC8vIGZldGNoIG91dHB1dHNcbiAgICAgIGxldCBvdXRwdXRRdWVyeUF1eCA9IChvdXRwdXRRdWVyeSA/IG91dHB1dFF1ZXJ5LmNvcHkoKSA6IG5ldyBNb25lcm9PdXRwdXRRdWVyeSgpKS5zZXRUeFF1ZXJ5KE1vbmVyb1dhbGxldFJwYy5kZWNvbnRleHR1YWxpemUocXVlcnlOb3JtYWxpemVkLmNvcHkoKSkpO1xuICAgICAgbGV0IG91dHB1dHMgPSBhd2FpdCB0aGlzLmdldE91dHB1dHNBdXgob3V0cHV0UXVlcnlBdXgpO1xuICAgICAgXG4gICAgICAvLyBtZXJnZSBvdXRwdXQgdHhzIG9uZSB0aW1lIHdoaWxlIHJldGFpbmluZyBvcmRlclxuICAgICAgbGV0IG91dHB1dFR4cyA9IFtdO1xuICAgICAgZm9yIChsZXQgb3V0cHV0IG9mIG91dHB1dHMpIHtcbiAgICAgICAgaWYgKCFvdXRwdXRUeHMuaW5jbHVkZXMob3V0cHV0LmdldFR4KCkpKSB7XG4gICAgICAgICAgTW9uZXJvV2FsbGV0UnBjLm1lcmdlVHgob3V0cHV0LmdldFR4KCksIHR4TWFwLCBibG9ja01hcCk7XG4gICAgICAgICAgb3V0cHV0VHhzLnB1c2gob3V0cHV0LmdldFR4KCkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIHJlc3RvcmUgdHJhbnNmZXIgYW5kIG91dHB1dCBxdWVyaWVzXG4gICAgcXVlcnlOb3JtYWxpemVkLnNldFRyYW5zZmVyUXVlcnkodHJhbnNmZXJRdWVyeSk7XG4gICAgcXVlcnlOb3JtYWxpemVkLnNldElucHV0UXVlcnkoaW5wdXRRdWVyeSk7XG4gICAgcXVlcnlOb3JtYWxpemVkLnNldE91dHB1dFF1ZXJ5KG91dHB1dFF1ZXJ5KTtcbiAgICBcbiAgICAvLyBmaWx0ZXIgdHhzIHRoYXQgZG9uJ3QgbWVldCB0cmFuc2ZlciBxdWVyeVxuICAgIGxldCB0eHNRdWVyaWVkID0gW107XG4gICAgZm9yIChsZXQgdHggb2YgdHhzKSB7XG4gICAgICBpZiAocXVlcnlOb3JtYWxpemVkLm1lZXRzQ3JpdGVyaWEodHgpKSB0eHNRdWVyaWVkLnB1c2godHgpO1xuICAgICAgZWxzZSBpZiAodHguZ2V0QmxvY2soKSAhPT0gdW5kZWZpbmVkKSB0eC5nZXRCbG9jaygpLmdldFR4cygpLnNwbGljZSh0eC5nZXRCbG9jaygpLmdldFR4cygpLmluZGV4T2YodHgpLCAxKTtcbiAgICB9XG4gICAgdHhzID0gdHhzUXVlcmllZDtcbiAgICBcbiAgICAvLyBzcGVjaWFsIGNhc2U6IHJlLWZldGNoIHR4cyBpZiBpbmNvbnNpc3RlbmN5IGNhdXNlZCBieSBuZWVkaW5nIHRvIG1ha2UgbXVsdGlwbGUgcnBjIGNhbGxzXG4gICAgZm9yIChsZXQgdHggb2YgdHhzKSB7XG4gICAgICBpZiAodHguZ2V0SXNDb25maXJtZWQoKSAmJiB0eC5nZXRCbG9jaygpID09PSB1bmRlZmluZWQgfHwgIXR4LmdldElzQ29uZmlybWVkKCkgJiYgdHguZ2V0QmxvY2soKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJJbmNvbnNpc3RlbmN5IGRldGVjdGVkIGJ1aWxkaW5nIHR4cyBmcm9tIG11bHRpcGxlIHJwYyBjYWxscywgcmUtZmV0Y2hpbmcgdHhzXCIpO1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRUeHMocXVlcnlOb3JtYWxpemVkKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gb3JkZXIgdHhzIGlmIHR4IGhhc2hlcyBnaXZlbiB0aGVuIHJldHVyblxuICAgIGlmIChxdWVyeU5vcm1hbGl6ZWQuZ2V0SGFzaGVzKCkgJiYgcXVlcnlOb3JtYWxpemVkLmdldEhhc2hlcygpLmxlbmd0aCA+IDApIHtcbiAgICAgIGxldCB0eHNCeUlkID0gbmV3IE1hcCgpICAvLyBzdG9yZSB0eHMgaW4gdGVtcG9yYXJ5IG1hcCBmb3Igc29ydGluZ1xuICAgICAgZm9yIChsZXQgdHggb2YgdHhzKSB0eHNCeUlkLnNldCh0eC5nZXRIYXNoKCksIHR4KTtcbiAgICAgIGxldCBvcmRlcmVkVHhzID0gW107XG4gICAgICBmb3IgKGxldCBoYXNoIG9mIHF1ZXJ5Tm9ybWFsaXplZC5nZXRIYXNoZXMoKSkgaWYgKHR4c0J5SWQuZ2V0KGhhc2gpKSBvcmRlcmVkVHhzLnB1c2godHhzQnlJZC5nZXQoaGFzaCkpO1xuICAgICAgdHhzID0gb3JkZXJlZFR4cztcbiAgICB9XG4gICAgcmV0dXJuIHR4cztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0VHJhbnNmZXJzKHF1ZXJ5PzogUGFydGlhbDxNb25lcm9UcmFuc2ZlclF1ZXJ5Pik6IFByb21pc2U8TW9uZXJvVHJhbnNmZXJbXT4ge1xuICAgIFxuICAgIC8vIGNvcHkgYW5kIG5vcm1hbGl6ZSBxdWVyeSB1cCB0byBibG9ja1xuICAgIGNvbnN0IHF1ZXJ5Tm9ybWFsaXplZCA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVUcmFuc2ZlclF1ZXJ5KHF1ZXJ5KTtcbiAgICBcbiAgICAvLyBnZXQgdHJhbnNmZXJzIGRpcmVjdGx5IGlmIHF1ZXJ5IGRvZXMgbm90IHJlcXVpcmUgdHggY29udGV4dCAob3RoZXIgdHJhbnNmZXJzLCBvdXRwdXRzKVxuICAgIGlmICghTW9uZXJvV2FsbGV0UnBjLmlzQ29udGV4dHVhbChxdWVyeU5vcm1hbGl6ZWQpKSByZXR1cm4gdGhpcy5nZXRUcmFuc2ZlcnNBdXgocXVlcnlOb3JtYWxpemVkKTtcbiAgICBcbiAgICAvLyBvdGhlcndpc2UgZ2V0IHR4cyB3aXRoIGZ1bGwgbW9kZWxzIHRvIGZ1bGZpbGwgcXVlcnlcbiAgICBsZXQgdHJhbnNmZXJzID0gW107XG4gICAgZm9yIChsZXQgdHggb2YgYXdhaXQgdGhpcy5nZXRUeHMocXVlcnlOb3JtYWxpemVkLmdldFR4UXVlcnkoKSkpIHtcbiAgICAgIGZvciAobGV0IHRyYW5zZmVyIG9mIHR4LmZpbHRlclRyYW5zZmVycyhxdWVyeU5vcm1hbGl6ZWQpKSB7XG4gICAgICAgIHRyYW5zZmVycy5wdXNoKHRyYW5zZmVyKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHRyYW5zZmVycztcbiAgfVxuICBcbiAgYXN5bmMgZ2V0T3V0cHV0cyhxdWVyeT86IFBhcnRpYWw8TW9uZXJvT3V0cHV0UXVlcnk+KTogUHJvbWlzZTxNb25lcm9PdXRwdXRXYWxsZXRbXT4ge1xuICAgIFxuICAgIC8vIGNvcHkgYW5kIG5vcm1hbGl6ZSBxdWVyeSB1cCB0byBibG9ja1xuICAgIGNvbnN0IHF1ZXJ5Tm9ybWFsaXplZCA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVPdXRwdXRRdWVyeShxdWVyeSk7XG4gICAgXG4gICAgLy8gZ2V0IG91dHB1dHMgZGlyZWN0bHkgaWYgcXVlcnkgZG9lcyBub3QgcmVxdWlyZSB0eCBjb250ZXh0IChvdGhlciBvdXRwdXRzLCB0cmFuc2ZlcnMpXG4gICAgaWYgKCFNb25lcm9XYWxsZXRScGMuaXNDb250ZXh0dWFsKHF1ZXJ5Tm9ybWFsaXplZCkpIHJldHVybiB0aGlzLmdldE91dHB1dHNBdXgocXVlcnlOb3JtYWxpemVkKTtcbiAgICBcbiAgICAvLyBvdGhlcndpc2UgZ2V0IHR4cyB3aXRoIGZ1bGwgbW9kZWxzIHRvIGZ1bGZpbGwgcXVlcnlcbiAgICBsZXQgb3V0cHV0cyA9IFtdO1xuICAgIGZvciAobGV0IHR4IG9mIGF3YWl0IHRoaXMuZ2V0VHhzKHF1ZXJ5Tm9ybWFsaXplZC5nZXRUeFF1ZXJ5KCkpKSB7XG4gICAgICBmb3IgKGxldCBvdXRwdXQgb2YgdHguZmlsdGVyT3V0cHV0cyhxdWVyeU5vcm1hbGl6ZWQpKSB7XG4gICAgICAgIG91dHB1dHMucHVzaChvdXRwdXQpO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICByZXR1cm4gb3V0cHV0cztcbiAgfVxuICBcbiAgYXN5bmMgZXhwb3J0T3V0cHV0cyhhbGwgPSBmYWxzZSk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgcmV0dXJuIChhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJleHBvcnRfb3V0cHV0c1wiLCB7YWxsOiBhbGx9KSkucmVzdWx0Lm91dHB1dHNfZGF0YV9oZXg7XG4gIH1cbiAgXG4gIGFzeW5jIGltcG9ydE91dHB1dHMob3V0cHV0c0hleDogc3RyaW5nKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImltcG9ydF9vdXRwdXRzXCIsIHtvdXRwdXRzX2RhdGFfaGV4OiBvdXRwdXRzSGV4fSk7XG4gICAgcmV0dXJuIHJlc3AucmVzdWx0Lm51bV9pbXBvcnRlZDtcbiAgfVxuICBcbiAgYXN5bmMgZXhwb3J0S2V5SW1hZ2VzKGFsbCA9IGZhbHNlKTogUHJvbWlzZTxNb25lcm9LZXlJbWFnZVtdPiB7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMucnBjRXhwb3J0S2V5SW1hZ2VzKGFsbCk7XG4gIH1cbiAgXG4gIGFzeW5jIGltcG9ydEtleUltYWdlcyhrZXlJbWFnZXM6IE1vbmVyb0tleUltYWdlW10pOiBQcm9taXNlPE1vbmVyb0tleUltYWdlSW1wb3J0UmVzdWx0PiB7XG4gICAgXG4gICAgLy8gY29udmVydCBrZXkgaW1hZ2VzIHRvIHJwYyBwYXJhbWV0ZXJcbiAgICBsZXQgcnBjS2V5SW1hZ2VzID0ga2V5SW1hZ2VzLm1hcChrZXlJbWFnZSA9PiAoe2tleV9pbWFnZToga2V5SW1hZ2UuZ2V0SGV4KCksIHNpZ25hdHVyZToga2V5SW1hZ2UuZ2V0U2lnbmF0dXJlKCl9KSk7XG4gICAgXG4gICAgLy8gc2VuZCByZXF1ZXN0XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJpbXBvcnRfa2V5X2ltYWdlc1wiLCB7c2lnbmVkX2tleV9pbWFnZXM6IHJwY0tleUltYWdlc30pO1xuICAgIFxuICAgIC8vIGJ1aWxkIGFuZCByZXR1cm4gcmVzdWx0XG4gICAgbGV0IGltcG9ydFJlc3VsdCA9IG5ldyBNb25lcm9LZXlJbWFnZUltcG9ydFJlc3VsdCgpO1xuICAgIGltcG9ydFJlc3VsdC5zZXRIZWlnaHQocmVzcC5yZXN1bHQuaGVpZ2h0KTtcbiAgICBpbXBvcnRSZXN1bHQuc2V0U3BlbnRBbW91bnQoQmlnSW50KHJlc3AucmVzdWx0LnNwZW50KSk7XG4gICAgaW1wb3J0UmVzdWx0LnNldFVuc3BlbnRBbW91bnQoQmlnSW50KHJlc3AucmVzdWx0LnVuc3BlbnQpKTtcbiAgICByZXR1cm4gaW1wb3J0UmVzdWx0O1xuICB9XG4gIFxuICBhc3luYyBnZXROZXdLZXlJbWFnZXNGcm9tTGFzdEltcG9ydCgpOiBQcm9taXNlPE1vbmVyb0tleUltYWdlW10+IHtcbiAgICByZXR1cm4gYXdhaXQgdGhpcy5ycGNFeHBvcnRLZXlJbWFnZXMoZmFsc2UpO1xuICB9XG4gIFxuICBhc3luYyBmcmVlemVPdXRwdXQoa2V5SW1hZ2U6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJmcmVlemVcIiwge2tleV9pbWFnZToga2V5SW1hZ2V9KTtcbiAgfVxuICBcbiAgYXN5bmMgdGhhd091dHB1dChrZXlJbWFnZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcInRoYXdcIiwge2tleV9pbWFnZToga2V5SW1hZ2V9KTtcbiAgfVxuICBcbiAgYXN5bmMgaXNPdXRwdXRGcm96ZW4oa2V5SW1hZ2U6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZnJvemVuXCIsIHtrZXlfaW1hZ2U6IGtleUltYWdlfSk7XG4gICAgcmV0dXJuIHJlc3AucmVzdWx0LmZyb3plbiA9PT0gdHJ1ZTtcbiAgfVxuXG4gIGFzeW5jIGdldERlZmF1bHRGZWVQcmlvcml0eSgpOiBQcm9taXNlPE1vbmVyb1R4UHJpb3JpdHk+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF9kZWZhdWx0X2ZlZV9wcmlvcml0eVwiKTtcbiAgICByZXR1cm4gcmVzcC5yZXN1bHQucHJpb3JpdHk7XG4gIH1cbiAgXG4gIGFzeW5jIGNyZWF0ZVR4cyhjb25maWc6IFBhcnRpYWw8TW9uZXJvVHhDb25maWc+KTogUHJvbWlzZTxNb25lcm9UeFdhbGxldFtdPiB7XG4gICAgXG4gICAgLy8gdmFsaWRhdGUsIGNvcHksIGFuZCBub3JtYWxpemUgY29uZmlnXG4gICAgY29uc3QgY29uZmlnTm9ybWFsaXplZCA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVDcmVhdGVUeHNDb25maWcoY29uZmlnKTtcbiAgICBpZiAoY29uZmlnTm9ybWFsaXplZC5nZXRDYW5TcGxpdCgpID09PSB1bmRlZmluZWQpIGNvbmZpZ05vcm1hbGl6ZWQuc2V0Q2FuU3BsaXQodHJ1ZSk7XG4gICAgaWYgKGNvbmZpZ05vcm1hbGl6ZWQuZ2V0UmVsYXkoKSA9PT0gdHJ1ZSAmJiBhd2FpdCB0aGlzLmlzTXVsdGlzaWcoKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ2Fubm90IHJlbGF5IG11bHRpc2lnIHRyYW5zYWN0aW9uIHVudGlsIGNvLXNpZ25lZFwiKTtcblxuICAgIC8vIGRldGVybWluZSBhY2NvdW50IGFuZCBzdWJhZGRyZXNzZXMgdG8gc2VuZCBmcm9tXG4gICAgbGV0IGFjY291bnRJZHggPSBjb25maWdOb3JtYWxpemVkLmdldEFjY291bnRJbmRleCgpO1xuICAgIGlmIChhY2NvdW50SWR4ID09PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk11c3QgcHJvdmlkZSB0aGUgYWNjb3VudCBpbmRleCB0byBzZW5kIGZyb21cIik7XG4gICAgbGV0IHN1YmFkZHJlc3NJbmRpY2VzID0gY29uZmlnTm9ybWFsaXplZC5nZXRTdWJhZGRyZXNzSW5kaWNlcygpID09PSB1bmRlZmluZWQgPyB1bmRlZmluZWQgOiBjb25maWdOb3JtYWxpemVkLmdldFN1YmFkZHJlc3NJbmRpY2VzKCkuc2xpY2UoMCk7IC8vIGZldGNoIGFsbCBvciBjb3B5IGdpdmVuIGluZGljZXNcbiAgICBcbiAgICAvLyBidWlsZCBjb25maWcgcGFyYW1ldGVyc1xuICAgIGxldCBwYXJhbXM6IGFueSA9IHt9O1xuICAgIHBhcmFtcy5kZXN0aW5hdGlvbnMgPSBbXTtcbiAgICBmb3IgKGxldCBkZXN0aW5hdGlvbiBvZiBjb25maWdOb3JtYWxpemVkLmdldERlc3RpbmF0aW9ucygpKSB7XG4gICAgICBhc3NlcnQoZGVzdGluYXRpb24uZ2V0QWRkcmVzcygpLCBcIkRlc3RpbmF0aW9uIGFkZHJlc3MgaXMgbm90IGRlZmluZWRcIik7XG4gICAgICBhc3NlcnQoZGVzdGluYXRpb24uZ2V0QW1vdW50KCksIFwiRGVzdGluYXRpb24gYW1vdW50IGlzIG5vdCBkZWZpbmVkXCIpO1xuICAgICAgcGFyYW1zLmRlc3RpbmF0aW9ucy5wdXNoKHsgYWRkcmVzczogZGVzdGluYXRpb24uZ2V0QWRkcmVzcygpLCBhbW91bnQ6IGRlc3RpbmF0aW9uLmdldEFtb3VudCgpLnRvU3RyaW5nKCkgfSk7XG4gICAgfVxuICAgIGlmIChjb25maWdOb3JtYWxpemVkLmdldFN1YnRyYWN0RmVlRnJvbSgpKSBwYXJhbXMuc3VidHJhY3RfZmVlX2Zyb21fb3V0cHV0cyA9IGNvbmZpZ05vcm1hbGl6ZWQuZ2V0U3VidHJhY3RGZWVGcm9tKCk7XG4gICAgcGFyYW1zLmFjY291bnRfaW5kZXggPSBhY2NvdW50SWR4O1xuICAgIHBhcmFtcy5zdWJhZGRyX2luZGljZXMgPSBzdWJhZGRyZXNzSW5kaWNlcztcbiAgICBwYXJhbXMucGF5bWVudF9pZCA9IGNvbmZpZ05vcm1hbGl6ZWQuZ2V0UGF5bWVudElkKCk7XG4gICAgcGFyYW1zLmRvX25vdF9yZWxheSA9IGNvbmZpZ05vcm1hbGl6ZWQuZ2V0UmVsYXkoKSAhPT0gdHJ1ZTtcbiAgICBhc3NlcnQoY29uZmlnTm9ybWFsaXplZC5nZXRQcmlvcml0eSgpID09PSB1bmRlZmluZWQgfHwgY29uZmlnTm9ybWFsaXplZC5nZXRQcmlvcml0eSgpID49IDAgJiYgY29uZmlnTm9ybWFsaXplZC5nZXRQcmlvcml0eSgpIDw9IDMpO1xuICAgIHBhcmFtcy5wcmlvcml0eSA9IGNvbmZpZ05vcm1hbGl6ZWQuZ2V0UHJpb3JpdHkoKTtcbiAgICBwYXJhbXMuZ2V0X3R4X2hleCA9IHRydWU7XG4gICAgcGFyYW1zLmdldF90eF9tZXRhZGF0YSA9IHRydWU7XG4gICAgaWYgKGNvbmZpZ05vcm1hbGl6ZWQuZ2V0Q2FuU3BsaXQoKSkgcGFyYW1zLmdldF90eF9rZXlzID0gdHJ1ZTsgLy8gcGFyYW0gdG8gZ2V0IHR4IGtleShzKSBkZXBlbmRzIGlmIHNwbGl0XG4gICAgZWxzZSBwYXJhbXMuZ2V0X3R4X2tleSA9IHRydWU7XG5cbiAgICAvLyBjYW5ub3QgYXBwbHkgc3VidHJhY3RGZWVGcm9tIHdpdGggYHRyYW5zZmVyX3NwbGl0YCBjYWxsXG4gICAgaWYgKGNvbmZpZ05vcm1hbGl6ZWQuZ2V0Q2FuU3BsaXQoKSAmJiBjb25maWdOb3JtYWxpemVkLmdldFN1YnRyYWN0RmVlRnJvbSgpICYmIGNvbmZpZ05vcm1hbGl6ZWQuZ2V0U3VidHJhY3RGZWVGcm9tKCkubGVuZ3RoID4gMCkge1xuICAgICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwic3VidHJhY3RmZWVmcm9tIHRyYW5zZmVycyBjYW5ub3QgYmUgc3BsaXQgb3ZlciBtdWx0aXBsZSB0cmFuc2FjdGlvbnMgeWV0XCIpO1xuICAgIH1cbiAgICBcbiAgICAvLyBzZW5kIHJlcXVlc3RcbiAgICBsZXQgcmVzdWx0O1xuICAgIHRyeSB7XG4gICAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChjb25maWdOb3JtYWxpemVkLmdldENhblNwbGl0KCkgPyBcInRyYW5zZmVyX3NwbGl0XCIgOiBcInRyYW5zZmVyXCIsIHBhcmFtcyk7XG4gICAgICByZXN1bHQgPSByZXNwLnJlc3VsdDtcbiAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgaWYgKGVyci5tZXNzYWdlLmluZGV4T2YoXCJXQUxMRVRfUlBDX0VSUk9SX0NPREVfV1JPTkdfQUREUkVTU1wiKSA+IC0xKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJJbnZhbGlkIGRlc3RpbmF0aW9uIGFkZHJlc3NcIik7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfVxuICAgIFxuICAgIC8vIHByZS1pbml0aWFsaXplIHR4cyBpZmYgcHJlc2VudC4gbXVsdGlzaWcgYW5kIHZpZXctb25seSB3YWxsZXRzIHdpbGwgaGF2ZSB0eCBzZXQgd2l0aG91dCB0cmFuc2FjdGlvbnNcbiAgICBsZXQgdHhzO1xuICAgIGxldCBudW1UeHMgPSBjb25maWdOb3JtYWxpemVkLmdldENhblNwbGl0KCkgPyAocmVzdWx0LmZlZV9saXN0ICE9PSB1bmRlZmluZWQgPyByZXN1bHQuZmVlX2xpc3QubGVuZ3RoIDogMCkgOiAocmVzdWx0LmZlZSAhPT0gdW5kZWZpbmVkID8gMSA6IDApO1xuICAgIGlmIChudW1UeHMgPiAwKSB0eHMgPSBbXTtcbiAgICBsZXQgY29weURlc3RpbmF0aW9ucyA9IG51bVR4cyA9PT0gMTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG51bVR4czsgaSsrKSB7XG4gICAgICBsZXQgdHggPSBuZXcgTW9uZXJvVHhXYWxsZXQoKTtcbiAgICAgIE1vbmVyb1dhbGxldFJwYy5pbml0U2VudFR4V2FsbGV0KGNvbmZpZ05vcm1hbGl6ZWQsIHR4LCBjb3B5RGVzdGluYXRpb25zKTtcbiAgICAgIHR4LmdldE91dGdvaW5nVHJhbnNmZXIoKS5zZXRBY2NvdW50SW5kZXgoYWNjb3VudElkeCk7XG4gICAgICBpZiAoc3ViYWRkcmVzc0luZGljZXMgIT09IHVuZGVmaW5lZCAmJiBzdWJhZGRyZXNzSW5kaWNlcy5sZW5ndGggPT09IDEpIHR4LmdldE91dGdvaW5nVHJhbnNmZXIoKS5zZXRTdWJhZGRyZXNzSW5kaWNlcyhzdWJhZGRyZXNzSW5kaWNlcyk7XG4gICAgICB0eHMucHVzaCh0eCk7XG4gICAgfVxuICAgIFxuICAgIC8vIG5vdGlmeSBvZiBjaGFuZ2VzXG4gICAgaWYgKGNvbmZpZ05vcm1hbGl6ZWQuZ2V0UmVsYXkoKSkgYXdhaXQgdGhpcy5wb2xsKCk7XG4gICAgXG4gICAgLy8gaW5pdGlhbGl6ZSB0eCBzZXQgZnJvbSBycGMgcmVzcG9uc2Ugd2l0aCBwcmUtaW5pdGlhbGl6ZWQgdHhzXG4gICAgaWYgKGNvbmZpZ05vcm1hbGl6ZWQuZ2V0Q2FuU3BsaXQoKSkgcmV0dXJuIE1vbmVyb1dhbGxldFJwYy5jb252ZXJ0UnBjU2VudFR4c1RvVHhTZXQocmVzdWx0LCB0eHMsIGNvbmZpZ05vcm1hbGl6ZWQpLmdldFR4cygpO1xuICAgIGVsc2UgcmV0dXJuIE1vbmVyb1dhbGxldFJwYy5jb252ZXJ0UnBjVHhUb1R4U2V0KHJlc3VsdCwgdHhzID09PSB1bmRlZmluZWQgPyB1bmRlZmluZWQgOiB0eHNbMF0sIHRydWUsIGNvbmZpZ05vcm1hbGl6ZWQpLmdldFR4cygpO1xuICB9XG4gIFxuICBhc3luYyBzd2VlcE91dHB1dChjb25maWc6IFBhcnRpYWw8TW9uZXJvVHhDb25maWc+KTogUHJvbWlzZTxNb25lcm9UeFdhbGxldD4ge1xuICAgIFxuICAgIC8vIG5vcm1hbGl6ZSBhbmQgdmFsaWRhdGUgY29uZmlnXG4gICAgY29uZmlnID0gTW9uZXJvV2FsbGV0Lm5vcm1hbGl6ZVN3ZWVwT3V0cHV0Q29uZmlnKGNvbmZpZyk7XG4gICAgXG4gICAgLy8gYnVpbGQgcmVxdWVzdCBwYXJhbWV0ZXJzXG4gICAgbGV0IHBhcmFtczogYW55ID0ge307XG4gICAgcGFyYW1zLmFkZHJlc3MgPSBjb25maWcuZ2V0RGVzdGluYXRpb25zKClbMF0uZ2V0QWRkcmVzcygpO1xuICAgIHBhcmFtcy5hY2NvdW50X2luZGV4ID0gY29uZmlnLmdldEFjY291bnRJbmRleCgpO1xuICAgIHBhcmFtcy5zdWJhZGRyX2luZGljZXMgPSBjb25maWcuZ2V0U3ViYWRkcmVzc0luZGljZXMoKTtcbiAgICBwYXJhbXMua2V5X2ltYWdlID0gY29uZmlnLmdldEtleUltYWdlKCk7XG4gICAgcGFyYW1zLmRvX25vdF9yZWxheSA9IGNvbmZpZy5nZXRSZWxheSgpICE9PSB0cnVlO1xuICAgIGFzc2VydChjb25maWcuZ2V0UHJpb3JpdHkoKSA9PT0gdW5kZWZpbmVkIHx8IGNvbmZpZy5nZXRQcmlvcml0eSgpID49IDAgJiYgY29uZmlnLmdldFByaW9yaXR5KCkgPD0gMyk7XG4gICAgcGFyYW1zLnByaW9yaXR5ID0gY29uZmlnLmdldFByaW9yaXR5KCk7XG4gICAgcGFyYW1zLnBheW1lbnRfaWQgPSBjb25maWcuZ2V0UGF5bWVudElkKCk7XG4gICAgcGFyYW1zLmdldF90eF9rZXkgPSB0cnVlO1xuICAgIHBhcmFtcy5nZXRfdHhfaGV4ID0gdHJ1ZTtcbiAgICBwYXJhbXMuZ2V0X3R4X21ldGFkYXRhID0gdHJ1ZTtcbiAgICBcbiAgICAvLyBzZW5kIHJlcXVlc3RcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcInN3ZWVwX3NpbmdsZVwiLCBwYXJhbXMpO1xuICAgIGxldCByZXN1bHQgPSByZXNwLnJlc3VsdDtcbiAgICBcbiAgICAvLyBub3RpZnkgb2YgY2hhbmdlc1xuICAgIGlmIChjb25maWcuZ2V0UmVsYXkoKSkgYXdhaXQgdGhpcy5wb2xsKCk7XG4gICAgXG4gICAgLy8gYnVpbGQgYW5kIHJldHVybiB0eFxuICAgIGxldCB0eCA9IE1vbmVyb1dhbGxldFJwYy5pbml0U2VudFR4V2FsbGV0KGNvbmZpZywgdW5kZWZpbmVkLCB0cnVlKTtcbiAgICBNb25lcm9XYWxsZXRScGMuY29udmVydFJwY1R4VG9UeFNldChyZXN1bHQsIHR4LCB0cnVlLCBjb25maWcpO1xuICAgIHR4LmdldE91dGdvaW5nVHJhbnNmZXIoKS5nZXREZXN0aW5hdGlvbnMoKVswXS5zZXRBbW91bnQodHguZ2V0T3V0Z29pbmdUcmFuc2ZlcigpLmdldEFtb3VudCgpKTsgLy8gaW5pdGlhbGl6ZSBkZXN0aW5hdGlvbiBhbW91bnRcbiAgICByZXR1cm4gdHg7XG4gIH1cbiAgXG4gIGFzeW5jIHN3ZWVwVW5sb2NrZWQoY29uZmlnOiBQYXJ0aWFsPE1vbmVyb1R4Q29uZmlnPik6IFByb21pc2U8TW9uZXJvVHhXYWxsZXRbXT4ge1xuICAgIFxuICAgIC8vIHZhbGlkYXRlIGFuZCBub3JtYWxpemUgY29uZmlnXG4gICAgY29uc3QgY29uZmlnTm9ybWFsaXplZCA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVTd2VlcFVubG9ja2VkQ29uZmlnKGNvbmZpZyk7XG4gICAgXG4gICAgLy8gZGV0ZXJtaW5lIGFjY291bnQgYW5kIHN1YmFkZHJlc3MgaW5kaWNlcyB0byBzd2VlcDsgZGVmYXVsdCB0byBhbGwgd2l0aCB1bmxvY2tlZCBiYWxhbmNlIGlmIG5vdCBzcGVjaWZpZWRcbiAgICBsZXQgaW5kaWNlcyA9IG5ldyBNYXAoKTsgIC8vIG1hcHMgZWFjaCBhY2NvdW50IGluZGV4IHRvIHN1YmFkZHJlc3MgaW5kaWNlcyB0byBzd2VlcFxuICAgIGlmIChjb25maWdOb3JtYWxpemVkLmdldEFjY291bnRJbmRleCgpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmIChjb25maWdOb3JtYWxpemVkLmdldFN1YmFkZHJlc3NJbmRpY2VzKCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBpbmRpY2VzLnNldChjb25maWdOb3JtYWxpemVkLmdldEFjY291bnRJbmRleCgpLCBjb25maWdOb3JtYWxpemVkLmdldFN1YmFkZHJlc3NJbmRpY2VzKCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IHN1YmFkZHJlc3NJbmRpY2VzID0gW107XG4gICAgICAgIGluZGljZXMuc2V0KGNvbmZpZ05vcm1hbGl6ZWQuZ2V0QWNjb3VudEluZGV4KCksIHN1YmFkZHJlc3NJbmRpY2VzKTtcbiAgICAgICAgZm9yIChsZXQgc3ViYWRkcmVzcyBvZiBhd2FpdCB0aGlzLmdldFN1YmFkZHJlc3Nlcyhjb25maWdOb3JtYWxpemVkLmdldEFjY291bnRJbmRleCgpKSkge1xuICAgICAgICAgIGlmIChzdWJhZGRyZXNzLmdldFVubG9ja2VkQmFsYW5jZSgpID4gMG4pIHN1YmFkZHJlc3NJbmRpY2VzLnB1c2goc3ViYWRkcmVzcy5nZXRJbmRleCgpKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBsZXQgYWNjb3VudHMgPSBhd2FpdCB0aGlzLmdldEFjY291bnRzKHRydWUpO1xuICAgICAgZm9yIChsZXQgYWNjb3VudCBvZiBhY2NvdW50cykge1xuICAgICAgICBpZiAoYWNjb3VudC5nZXRVbmxvY2tlZEJhbGFuY2UoKSA+IDBuKSB7XG4gICAgICAgICAgbGV0IHN1YmFkZHJlc3NJbmRpY2VzID0gW107XG4gICAgICAgICAgaW5kaWNlcy5zZXQoYWNjb3VudC5nZXRJbmRleCgpLCBzdWJhZGRyZXNzSW5kaWNlcyk7XG4gICAgICAgICAgZm9yIChsZXQgc3ViYWRkcmVzcyBvZiBhY2NvdW50LmdldFN1YmFkZHJlc3NlcygpKSB7XG4gICAgICAgICAgICBpZiAoc3ViYWRkcmVzcy5nZXRVbmxvY2tlZEJhbGFuY2UoKSA+IDBuKSBzdWJhZGRyZXNzSW5kaWNlcy5wdXNoKHN1YmFkZHJlc3MuZ2V0SW5kZXgoKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIHN3ZWVwIGZyb20gZWFjaCBhY2NvdW50IGFuZCBjb2xsZWN0IHJlc3VsdGluZyB0eCBzZXRzXG4gICAgbGV0IHR4cyA9IFtdO1xuICAgIGZvciAobGV0IGFjY291bnRJZHggb2YgaW5kaWNlcy5rZXlzKCkpIHtcbiAgICAgIFxuICAgICAgLy8gY29weSBhbmQgbW9kaWZ5IHRoZSBvcmlnaW5hbCBjb25maWdcbiAgICAgIGxldCBjb3B5ID0gY29uZmlnTm9ybWFsaXplZC5jb3B5KCk7XG4gICAgICBjb3B5LnNldEFjY291bnRJbmRleChhY2NvdW50SWR4KTtcbiAgICAgIGNvcHkuc2V0U3dlZXBFYWNoU3ViYWRkcmVzcyhmYWxzZSk7XG4gICAgICBcbiAgICAgIC8vIHN3ZWVwIGFsbCBzdWJhZGRyZXNzZXMgdG9nZXRoZXIgIC8vIFRPRE8gbW9uZXJvLXByb2plY3Q6IGNhbiB0aGlzIHJldmVhbCBvdXRwdXRzIGJlbG9uZyB0byB0aGUgc2FtZSB3YWxsZXQ/XG4gICAgICBpZiAoY29weS5nZXRTd2VlcEVhY2hTdWJhZGRyZXNzKCkgIT09IHRydWUpIHtcbiAgICAgICAgY29weS5zZXRTdWJhZGRyZXNzSW5kaWNlcyhpbmRpY2VzLmdldChhY2NvdW50SWR4KSk7XG4gICAgICAgIGZvciAobGV0IHR4IG9mIGF3YWl0IHRoaXMucnBjU3dlZXBBY2NvdW50KGNvcHkpKSB0eHMucHVzaCh0eCk7XG4gICAgICB9XG4gICAgICBcbiAgICAgIC8vIG90aGVyd2lzZSBzd2VlcCBlYWNoIHN1YmFkZHJlc3MgaW5kaXZpZHVhbGx5XG4gICAgICBlbHNlIHtcbiAgICAgICAgZm9yIChsZXQgc3ViYWRkcmVzc0lkeCBvZiBpbmRpY2VzLmdldChhY2NvdW50SWR4KSkge1xuICAgICAgICAgIGNvcHkuc2V0U3ViYWRkcmVzc0luZGljZXMoW3N1YmFkZHJlc3NJZHhdKTtcbiAgICAgICAgICBmb3IgKGxldCB0eCBvZiBhd2FpdCB0aGlzLnJwY1N3ZWVwQWNjb3VudChjb3B5KSkgdHhzLnB1c2godHgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIG5vdGlmeSBvZiBjaGFuZ2VzXG4gICAgaWYgKGNvbmZpZ05vcm1hbGl6ZWQuZ2V0UmVsYXkoKSkgYXdhaXQgdGhpcy5wb2xsKCk7XG4gICAgcmV0dXJuIHR4cztcbiAgfVxuICBcbiAgYXN5bmMgc3dlZXBEdXN0KHJlbGF5PzogYm9vbGVhbik6IFByb21pc2U8TW9uZXJvVHhXYWxsZXRbXT4ge1xuICAgIGlmIChyZWxheSA9PT0gdW5kZWZpbmVkKSByZWxheSA9IGZhbHNlO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwic3dlZXBfZHVzdFwiLCB7ZG9fbm90X3JlbGF5OiAhcmVsYXl9KTtcbiAgICBpZiAocmVsYXkpIGF3YWl0IHRoaXMucG9sbCgpO1xuICAgIGxldCByZXN1bHQgPSByZXNwLnJlc3VsdDtcbiAgICBsZXQgdHhTZXQgPSBNb25lcm9XYWxsZXRScGMuY29udmVydFJwY1NlbnRUeHNUb1R4U2V0KHJlc3VsdCk7XG4gICAgaWYgKHR4U2V0LmdldFR4cygpID09PSB1bmRlZmluZWQpIHJldHVybiBbXTtcbiAgICBmb3IgKGxldCB0eCBvZiB0eFNldC5nZXRUeHMoKSkge1xuICAgICAgdHguc2V0SXNSZWxheWVkKCFyZWxheSk7XG4gICAgICB0eC5zZXRJblR4UG9vbCh0eC5nZXRJc1JlbGF5ZWQoKSk7XG4gICAgfVxuICAgIHJldHVybiB0eFNldC5nZXRUeHMoKTtcbiAgfVxuICBcbiAgYXN5bmMgcmVsYXlUeHModHhzT3JNZXRhZGF0YXM6IChNb25lcm9UeFdhbGxldCB8IHN0cmluZylbXSk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICBhc3NlcnQoQXJyYXkuaXNBcnJheSh0eHNPck1ldGFkYXRhcyksIFwiTXVzdCBwcm92aWRlIGFuIGFycmF5IG9mIHR4cyBvciB0aGVpciBtZXRhZGF0YSB0byByZWxheVwiKTtcbiAgICBsZXQgdHhIYXNoZXMgPSBbXTtcbiAgICBmb3IgKGxldCB0eE9yTWV0YWRhdGEgb2YgdHhzT3JNZXRhZGF0YXMpIHtcbiAgICAgIGxldCBtZXRhZGF0YSA9IHR4T3JNZXRhZGF0YSBpbnN0YW5jZW9mIE1vbmVyb1R4V2FsbGV0ID8gdHhPck1ldGFkYXRhLmdldE1ldGFkYXRhKCkgOiB0eE9yTWV0YWRhdGE7XG4gICAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcInJlbGF5X3R4XCIsIHsgaGV4OiBtZXRhZGF0YSB9KTtcbiAgICAgIHR4SGFzaGVzLnB1c2gocmVzcC5yZXN1bHQudHhfaGFzaCk7XG4gICAgfVxuICAgIGF3YWl0IHRoaXMucG9sbCgpOyAvLyBub3RpZnkgb2YgY2hhbmdlc1xuICAgIHJldHVybiB0eEhhc2hlcztcbiAgfVxuICBcbiAgYXN5bmMgZGVzY3JpYmVUeFNldCh0eFNldDogTW9uZXJvVHhTZXQpOiBQcm9taXNlPE1vbmVyb1R4U2V0PiB7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJkZXNjcmliZV90cmFuc2ZlclwiLCB7XG4gICAgICB1bnNpZ25lZF90eHNldDogdHhTZXQuZ2V0VW5zaWduZWRUeEhleCgpLFxuICAgICAgbXVsdGlzaWdfdHhzZXQ6IHR4U2V0LmdldE11bHRpc2lnVHhIZXgoKVxuICAgIH0pO1xuICAgIHJldHVybiBNb25lcm9XYWxsZXRScGMuY29udmVydFJwY0Rlc2NyaWJlVHJhbnNmZXIocmVzcC5yZXN1bHQpO1xuICB9XG4gIFxuICBhc3luYyBzaWduVHhzKHVuc2lnbmVkVHhIZXg6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvVHhTZXQ+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcInNpZ25fdHJhbnNmZXJcIiwge1xuICAgICAgdW5zaWduZWRfdHhzZXQ6IHVuc2lnbmVkVHhIZXgsXG4gICAgICBleHBvcnRfcmF3OiBmYWxzZVxuICAgIH0pO1xuICAgIGF3YWl0IHRoaXMucG9sbCgpO1xuICAgIHJldHVybiBNb25lcm9XYWxsZXRScGMuY29udmVydFJwY1NlbnRUeHNUb1R4U2V0KHJlc3AucmVzdWx0KTtcbiAgfVxuICBcbiAgYXN5bmMgc3VibWl0VHhzKHNpZ25lZFR4SGV4OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJzdWJtaXRfdHJhbnNmZXJcIiwge1xuICAgICAgdHhfZGF0YV9oZXg6IHNpZ25lZFR4SGV4XG4gICAgfSk7XG4gICAgYXdhaXQgdGhpcy5wb2xsKCk7XG4gICAgcmV0dXJuIHJlc3AucmVzdWx0LnR4X2hhc2hfbGlzdDtcbiAgfVxuICBcbiAgYXN5bmMgc2lnbk1lc3NhZ2UobWVzc2FnZTogc3RyaW5nLCBzaWduYXR1cmVUeXBlID0gTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGUuU0lHTl9XSVRIX1NQRU5EX0tFWSwgYWNjb3VudElkeCA9IDAsIHN1YmFkZHJlc3NJZHggPSAwKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcInNpZ25cIiwge1xuICAgICAgICBkYXRhOiBtZXNzYWdlLFxuICAgICAgICBzaWduYXR1cmVfdHlwZTogc2lnbmF0dXJlVHlwZSA9PT0gTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGUuU0lHTl9XSVRIX1NQRU5EX0tFWSA/IFwic3BlbmRcIiA6IFwidmlld1wiLFxuICAgICAgICBhY2NvdW50X2luZGV4OiBhY2NvdW50SWR4LFxuICAgICAgICBhZGRyZXNzX2luZGV4OiBzdWJhZGRyZXNzSWR4XG4gICAgfSk7XG4gICAgcmV0dXJuIHJlc3AucmVzdWx0LnNpZ25hdHVyZTtcbiAgfVxuICBcbiAgYXN5bmMgdmVyaWZ5TWVzc2FnZShtZXNzYWdlOiBzdHJpbmcsIGFkZHJlc3M6IHN0cmluZywgc2lnbmF0dXJlOiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb01lc3NhZ2VTaWduYXR1cmVSZXN1bHQ+IHtcbiAgICB0cnkge1xuICAgICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJ2ZXJpZnlcIiwge2RhdGE6IG1lc3NhZ2UsIGFkZHJlc3M6IGFkZHJlc3MsIHNpZ25hdHVyZTogc2lnbmF0dXJlfSk7XG4gICAgICBsZXQgcmVzdWx0ID0gcmVzcC5yZXN1bHQ7XG4gICAgICByZXR1cm4gbmV3IE1vbmVyb01lc3NhZ2VTaWduYXR1cmVSZXN1bHQoXG4gICAgICAgIHJlc3VsdC5nb29kID8ge2lzR29vZDogcmVzdWx0Lmdvb2QsIGlzT2xkOiByZXN1bHQub2xkLCBzaWduYXR1cmVUeXBlOiByZXN1bHQuc2lnbmF0dXJlX3R5cGUgPT09IFwidmlld1wiID8gTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGUuU0lHTl9XSVRIX1ZJRVdfS0VZIDogTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGUuU0lHTl9XSVRIX1NQRU5EX0tFWSwgdmVyc2lvbjogcmVzdWx0LnZlcnNpb259IDoge2lzR29vZDogZmFsc2V9XG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgaWYgKGUuZ2V0Q29kZSgpID09PSAtMikgcmV0dXJuIG5ldyBNb25lcm9NZXNzYWdlU2lnbmF0dXJlUmVzdWx0KHtpc0dvb2Q6IGZhbHNlfSk7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgfVxuICBcbiAgYXN5bmMgZ2V0VHhLZXkodHhIYXNoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gKGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF90eF9rZXlcIiwge3R4aWQ6IHR4SGFzaH0pKS5yZXN1bHQudHhfa2V5O1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgaWYgKGUgaW5zdGFuY2VvZiBNb25lcm9ScGNFcnJvciAmJiBlLmdldENvZGUoKSA9PT0gLTggJiYgZS5tZXNzYWdlLmluY2x1ZGVzKFwiVFggSUQgaGFzIGludmFsaWQgZm9ybWF0XCIpKSBlID0gbmV3IE1vbmVyb1JwY0Vycm9yKFwiVFggaGFzaCBoYXMgaW52YWxpZCBmb3JtYXRcIiwgZS5nZXRDb2RlKCksIGUuZ2V0UnBjTWV0aG9kKCksIGUuZ2V0UnBjUGFyYW1zKCkpOyAgLy8gbm9ybWFsaXplIGVycm9yIG1lc3NhZ2VcbiAgICAgIHRocm93IGU7XG4gICAgfVxuICB9XG4gIFxuICBhc3luYyBjaGVja1R4S2V5KHR4SGFzaDogc3RyaW5nLCB0eEtleTogc3RyaW5nLCBhZGRyZXNzOiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0NoZWNrVHg+IHtcbiAgICB0cnkge1xuICAgICAgXG4gICAgICAvLyBzZW5kIHJlcXVlc3RcbiAgICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiY2hlY2tfdHhfa2V5XCIsIHt0eGlkOiB0eEhhc2gsIHR4X2tleTogdHhLZXksIGFkZHJlc3M6IGFkZHJlc3N9KTtcbiAgICAgIFxuICAgICAgLy8gaW50ZXJwcmV0IHJlc3VsdFxuICAgICAgbGV0IGNoZWNrID0gbmV3IE1vbmVyb0NoZWNrVHgoKTtcbiAgICAgIGNoZWNrLnNldElzR29vZCh0cnVlKTtcbiAgICAgIGNoZWNrLnNldE51bUNvbmZpcm1hdGlvbnMocmVzcC5yZXN1bHQuY29uZmlybWF0aW9ucyk7XG4gICAgICBjaGVjay5zZXRJblR4UG9vbChyZXNwLnJlc3VsdC5pbl9wb29sKTtcbiAgICAgIGNoZWNrLnNldFJlY2VpdmVkQW1vdW50KEJpZ0ludChyZXNwLnJlc3VsdC5yZWNlaXZlZCkpO1xuICAgICAgcmV0dXJuIGNoZWNrO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgaWYgKGUgaW5zdGFuY2VvZiBNb25lcm9ScGNFcnJvciAmJiBlLmdldENvZGUoKSA9PT0gLTggJiYgZS5tZXNzYWdlLmluY2x1ZGVzKFwiVFggSUQgaGFzIGludmFsaWQgZm9ybWF0XCIpKSBlID0gbmV3IE1vbmVyb1JwY0Vycm9yKFwiVFggaGFzaCBoYXMgaW52YWxpZCBmb3JtYXRcIiwgZS5nZXRDb2RlKCksIGUuZ2V0UnBjTWV0aG9kKCksIGUuZ2V0UnBjUGFyYW1zKCkpOyAgLy8gbm9ybWFsaXplIGVycm9yIG1lc3NhZ2VcbiAgICAgIHRocm93IGU7XG4gICAgfVxuICB9XG4gIFxuICBhc3luYyBnZXRUeFByb29mKHR4SGFzaDogc3RyaW5nLCBhZGRyZXNzOiBzdHJpbmcsIG1lc3NhZ2U/OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRyeSB7XG4gICAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF90eF9wcm9vZlwiLCB7dHhpZDogdHhIYXNoLCBhZGRyZXNzOiBhZGRyZXNzLCBtZXNzYWdlOiBtZXNzYWdlfSk7XG4gICAgICByZXR1cm4gcmVzcC5yZXN1bHQuc2lnbmF0dXJlO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgaWYgKGUgaW5zdGFuY2VvZiBNb25lcm9ScGNFcnJvciAmJiBlLmdldENvZGUoKSA9PT0gLTggJiYgZS5tZXNzYWdlLmluY2x1ZGVzKFwiVFggSUQgaGFzIGludmFsaWQgZm9ybWF0XCIpKSBlID0gbmV3IE1vbmVyb1JwY0Vycm9yKFwiVFggaGFzaCBoYXMgaW52YWxpZCBmb3JtYXRcIiwgZS5nZXRDb2RlKCksIGUuZ2V0UnBjTWV0aG9kKCksIGUuZ2V0UnBjUGFyYW1zKCkpOyAgLy8gbm9ybWFsaXplIGVycm9yIG1lc3NhZ2VcbiAgICAgIHRocm93IGU7XG4gICAgfVxuICB9XG4gIFxuICBhc3luYyBjaGVja1R4UHJvb2YodHhIYXNoOiBzdHJpbmcsIGFkZHJlc3M6IHN0cmluZywgbWVzc2FnZTogc3RyaW5nIHwgdW5kZWZpbmVkLCBzaWduYXR1cmU6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvQ2hlY2tUeD4ge1xuICAgIHRyeSB7XG4gICAgICBcbiAgICAgIC8vIHNlbmQgcmVxdWVzdFxuICAgICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJjaGVja190eF9wcm9vZlwiLCB7XG4gICAgICAgIHR4aWQ6IHR4SGFzaCxcbiAgICAgICAgYWRkcmVzczogYWRkcmVzcyxcbiAgICAgICAgbWVzc2FnZTogbWVzc2FnZSxcbiAgICAgICAgc2lnbmF0dXJlOiBzaWduYXR1cmVcbiAgICAgIH0pO1xuICAgICAgXG4gICAgICAvLyBpbnRlcnByZXQgcmVzcG9uc2VcbiAgICAgIGxldCBpc0dvb2QgPSByZXNwLnJlc3VsdC5nb29kO1xuICAgICAgbGV0IGNoZWNrID0gbmV3IE1vbmVyb0NoZWNrVHgoKTtcbiAgICAgIGNoZWNrLnNldElzR29vZChpc0dvb2QpO1xuICAgICAgaWYgKGlzR29vZCkge1xuICAgICAgICBjaGVjay5zZXROdW1Db25maXJtYXRpb25zKHJlc3AucmVzdWx0LmNvbmZpcm1hdGlvbnMpO1xuICAgICAgICBjaGVjay5zZXRJblR4UG9vbChyZXNwLnJlc3VsdC5pbl9wb29sKTtcbiAgICAgICAgY2hlY2suc2V0UmVjZWl2ZWRBbW91bnQoQmlnSW50KHJlc3AucmVzdWx0LnJlY2VpdmVkKSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gY2hlY2s7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICBpZiAoZSBpbnN0YW5jZW9mIE1vbmVyb1JwY0Vycm9yICYmIGUuZ2V0Q29kZSgpID09PSAtMSAmJiBlLm1lc3NhZ2UgPT09IFwiYmFzaWNfc3RyaW5nXCIpIGUgPSBuZXcgTW9uZXJvUnBjRXJyb3IoXCJNdXN0IHByb3ZpZGUgc2lnbmF0dXJlIHRvIGNoZWNrIHR4IHByb29mXCIsIC0xKTtcbiAgICAgIGlmIChlIGluc3RhbmNlb2YgTW9uZXJvUnBjRXJyb3IgJiYgZS5nZXRDb2RlKCkgPT09IC04ICYmIGUubWVzc2FnZS5pbmNsdWRlcyhcIlRYIElEIGhhcyBpbnZhbGlkIGZvcm1hdFwiKSkgZSA9IG5ldyBNb25lcm9ScGNFcnJvcihcIlRYIGhhc2ggaGFzIGludmFsaWQgZm9ybWF0XCIsIGUuZ2V0Q29kZSgpLCBlLmdldFJwY01ldGhvZCgpLCBlLmdldFJwY1BhcmFtcygpKTtcbiAgICAgIHRocm93IGU7XG4gICAgfVxuICB9XG4gIFxuICBhc3luYyBnZXRTcGVuZFByb29mKHR4SGFzaDogc3RyaW5nLCBtZXNzYWdlPzogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICB0cnkge1xuICAgICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJnZXRfc3BlbmRfcHJvb2ZcIiwge3R4aWQ6IHR4SGFzaCwgbWVzc2FnZTogbWVzc2FnZX0pO1xuICAgICAgcmV0dXJuIHJlc3AucmVzdWx0LnNpZ25hdHVyZTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIGlmIChlIGluc3RhbmNlb2YgTW9uZXJvUnBjRXJyb3IgJiYgZS5nZXRDb2RlKCkgPT09IC04ICYmIGUubWVzc2FnZS5pbmNsdWRlcyhcIlRYIElEIGhhcyBpbnZhbGlkIGZvcm1hdFwiKSkgZSA9IG5ldyBNb25lcm9ScGNFcnJvcihcIlRYIGhhc2ggaGFzIGludmFsaWQgZm9ybWF0XCIsIGUuZ2V0Q29kZSgpLCBlLmdldFJwY01ldGhvZCgpLCBlLmdldFJwY1BhcmFtcygpKTsgIC8vIG5vcm1hbGl6ZSBlcnJvciBtZXNzYWdlXG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgfVxuICBcbiAgYXN5bmMgY2hlY2tTcGVuZFByb29mKHR4SGFzaDogc3RyaW5nLCBtZXNzYWdlOiBzdHJpbmcgfCB1bmRlZmluZWQsIHNpZ25hdHVyZTogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdHJ5IHtcbiAgICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiY2hlY2tfc3BlbmRfcHJvb2ZcIiwge1xuICAgICAgICB0eGlkOiB0eEhhc2gsXG4gICAgICAgIG1lc3NhZ2U6IG1lc3NhZ2UsXG4gICAgICAgIHNpZ25hdHVyZTogc2lnbmF0dXJlXG4gICAgICB9KTtcbiAgICAgIHJldHVybiByZXNwLnJlc3VsdC5nb29kO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgaWYgKGUgaW5zdGFuY2VvZiBNb25lcm9ScGNFcnJvciAmJiBlLmdldENvZGUoKSA9PT0gLTggJiYgZS5tZXNzYWdlLmluY2x1ZGVzKFwiVFggSUQgaGFzIGludmFsaWQgZm9ybWF0XCIpKSBlID0gbmV3IE1vbmVyb1JwY0Vycm9yKFwiVFggaGFzaCBoYXMgaW52YWxpZCBmb3JtYXRcIiwgZS5nZXRDb2RlKCksIGUuZ2V0UnBjTWV0aG9kKCksIGUuZ2V0UnBjUGFyYW1zKCkpOyAgLy8gbm9ybWFsaXplIGVycm9yIG1lc3NhZ2VcbiAgICAgIHRocm93IGU7XG4gICAgfVxuICB9XG4gIFxuICBhc3luYyBnZXRSZXNlcnZlUHJvb2ZXYWxsZXQobWVzc2FnZT86IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJnZXRfcmVzZXJ2ZV9wcm9vZlwiLCB7XG4gICAgICBhbGw6IHRydWUsXG4gICAgICBtZXNzYWdlOiBtZXNzYWdlXG4gICAgfSk7XG4gICAgcmV0dXJuIHJlc3AucmVzdWx0LnNpZ25hdHVyZTtcbiAgfVxuICBcbiAgYXN5bmMgZ2V0UmVzZXJ2ZVByb29mQWNjb3VudChhY2NvdW50SWR4OiBudW1iZXIsIGFtb3VudDogYmlnaW50LCBtZXNzYWdlPzogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF9yZXNlcnZlX3Byb29mXCIsIHtcbiAgICAgIGFjY291bnRfaW5kZXg6IGFjY291bnRJZHgsXG4gICAgICBhbW91bnQ6IGFtb3VudC50b1N0cmluZygpLFxuICAgICAgbWVzc2FnZTogbWVzc2FnZVxuICAgIH0pO1xuICAgIHJldHVybiByZXNwLnJlc3VsdC5zaWduYXR1cmU7XG4gIH1cblxuICBhc3luYyBjaGVja1Jlc2VydmVQcm9vZihhZGRyZXNzOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZyB8IHVuZGVmaW5lZCwgc2lnbmF0dXJlOiBzdHJpbmcpOiBQcm9taXNlPE1vbmVyb0NoZWNrUmVzZXJ2ZT4ge1xuICAgIFxuICAgIC8vIHNlbmQgcmVxdWVzdFxuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiY2hlY2tfcmVzZXJ2ZV9wcm9vZlwiLCB7XG4gICAgICBhZGRyZXNzOiBhZGRyZXNzLFxuICAgICAgbWVzc2FnZTogbWVzc2FnZSxcbiAgICAgIHNpZ25hdHVyZTogc2lnbmF0dXJlXG4gICAgfSk7XG4gICAgXG4gICAgLy8gaW50ZXJwcmV0IHJlc3VsdHNcbiAgICBsZXQgaXNHb29kID0gcmVzcC5yZXN1bHQuZ29vZDtcbiAgICBsZXQgY2hlY2sgPSBuZXcgTW9uZXJvQ2hlY2tSZXNlcnZlKCk7XG4gICAgY2hlY2suc2V0SXNHb29kKGlzR29vZCk7XG4gICAgaWYgKGlzR29vZCkge1xuICAgICAgY2hlY2suc2V0VW5jb25maXJtZWRTcGVudEFtb3VudChCaWdJbnQocmVzcC5yZXN1bHQuc3BlbnQpKTtcbiAgICAgIGNoZWNrLnNldFRvdGFsQW1vdW50KEJpZ0ludChyZXNwLnJlc3VsdC50b3RhbCkpO1xuICAgIH1cbiAgICByZXR1cm4gY2hlY2s7XG4gIH1cbiAgXG4gIGFzeW5jIGdldFR4Tm90ZXModHhIYXNoZXM6IHN0cmluZ1tdKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIHJldHVybiAoYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X3R4X25vdGVzXCIsIHt0eGlkczogdHhIYXNoZXN9KSkucmVzdWx0Lm5vdGVzO1xuICB9XG4gIFxuICBhc3luYyBzZXRUeE5vdGVzKHR4SGFzaGVzOiBzdHJpbmdbXSwgbm90ZXM6IHN0cmluZ1tdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwic2V0X3R4X25vdGVzXCIsIHt0eGlkczogdHhIYXNoZXMsIG5vdGVzOiBub3Rlc30pO1xuICB9XG4gIFxuICBhc3luYyBnZXRBZGRyZXNzQm9va0VudHJpZXMoZW50cnlJbmRpY2VzPzogbnVtYmVyW10pOiBQcm9taXNlPE1vbmVyb0FkZHJlc3NCb29rRW50cnlbXT4ge1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2FkZHJlc3NfYm9va1wiLCB7ZW50cmllczogZW50cnlJbmRpY2VzfSk7XG4gICAgaWYgKCFyZXNwLnJlc3VsdC5lbnRyaWVzKSByZXR1cm4gW107XG4gICAgbGV0IGVudHJpZXMgPSBbXTtcbiAgICBmb3IgKGxldCBycGNFbnRyeSBvZiByZXNwLnJlc3VsdC5lbnRyaWVzKSB7XG4gICAgICBlbnRyaWVzLnB1c2gobmV3IE1vbmVyb0FkZHJlc3NCb29rRW50cnkoKS5zZXRJbmRleChycGNFbnRyeS5pbmRleCkuc2V0QWRkcmVzcyhycGNFbnRyeS5hZGRyZXNzKS5zZXREZXNjcmlwdGlvbihycGNFbnRyeS5kZXNjcmlwdGlvbikuc2V0UGF5bWVudElkKHJwY0VudHJ5LnBheW1lbnRfaWQpKTtcbiAgICB9XG4gICAgcmV0dXJuIGVudHJpZXM7XG4gIH1cbiAgXG4gIGFzeW5jIGFkZEFkZHJlc3NCb29rRW50cnkoYWRkcmVzczogc3RyaW5nLCBkZXNjcmlwdGlvbj86IHN0cmluZyk6IFByb21pc2U8bnVtYmVyPiB7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJhZGRfYWRkcmVzc19ib29rXCIsIHthZGRyZXNzOiBhZGRyZXNzLCBkZXNjcmlwdGlvbjogZGVzY3JpcHRpb259KTtcbiAgICByZXR1cm4gcmVzcC5yZXN1bHQuaW5kZXg7XG4gIH1cbiAgXG4gIGFzeW5jIGVkaXRBZGRyZXNzQm9va0VudHJ5KGluZGV4OiBudW1iZXIsIHNldEFkZHJlc3M6IGJvb2xlYW4sIGFkZHJlc3M6IHN0cmluZyB8IHVuZGVmaW5lZCwgc2V0RGVzY3JpcHRpb246IGJvb2xlYW4sIGRlc2NyaXB0aW9uOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImVkaXRfYWRkcmVzc19ib29rXCIsIHtcbiAgICAgIGluZGV4OiBpbmRleCxcbiAgICAgIHNldF9hZGRyZXNzOiBzZXRBZGRyZXNzLFxuICAgICAgYWRkcmVzczogYWRkcmVzcyxcbiAgICAgIHNldF9kZXNjcmlwdGlvbjogc2V0RGVzY3JpcHRpb24sXG4gICAgICBkZXNjcmlwdGlvbjogZGVzY3JpcHRpb25cbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgZGVsZXRlQWRkcmVzc0Jvb2tFbnRyeShlbnRyeUlkeDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZGVsZXRlX2FkZHJlc3NfYm9va1wiLCB7aW5kZXg6IGVudHJ5SWR4fSk7XG4gIH1cbiAgXG4gIGFzeW5jIHRhZ0FjY291bnRzKHRhZywgYWNjb3VudEluZGljZXMpIHtcbiAgICBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJ0YWdfYWNjb3VudHNcIiwge3RhZzogdGFnLCBhY2NvdW50czogYWNjb3VudEluZGljZXN9KTtcbiAgfVxuXG4gIGFzeW5jIHVudGFnQWNjb3VudHMoYWNjb3VudEluZGljZXM6IG51bWJlcltdKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwidW50YWdfYWNjb3VudHNcIiwge2FjY291bnRzOiBhY2NvdW50SW5kaWNlc30pO1xuICB9XG5cbiAgYXN5bmMgZ2V0QWNjb3VudFRhZ3MoKTogUHJvbWlzZTxNb25lcm9BY2NvdW50VGFnW10+IHtcbiAgICBsZXQgdGFncyA9IFtdO1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X2FjY291bnRfdGFnc1wiKTtcbiAgICBpZiAocmVzcC5yZXN1bHQuYWNjb3VudF90YWdzKSB7XG4gICAgICBmb3IgKGxldCBycGNBY2NvdW50VGFnIG9mIHJlc3AucmVzdWx0LmFjY291bnRfdGFncykge1xuICAgICAgICB0YWdzLnB1c2gobmV3IE1vbmVyb0FjY291bnRUYWcoe1xuICAgICAgICAgIHRhZzogcnBjQWNjb3VudFRhZy50YWcgPyBycGNBY2NvdW50VGFnLnRhZyA6IHVuZGVmaW5lZCxcbiAgICAgICAgICBsYWJlbDogcnBjQWNjb3VudFRhZy5sYWJlbCA/IHJwY0FjY291bnRUYWcubGFiZWwgOiB1bmRlZmluZWQsXG4gICAgICAgICAgYWNjb3VudEluZGljZXM6IHJwY0FjY291bnRUYWcuYWNjb3VudHNcbiAgICAgICAgfSkpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGFncztcbiAgfVxuXG4gIGFzeW5jIHNldEFjY291bnRUYWdMYWJlbCh0YWc6IHN0cmluZywgbGFiZWw6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcInNldF9hY2NvdW50X3RhZ19kZXNjcmlwdGlvblwiLCB7dGFnOiB0YWcsIGRlc2NyaXB0aW9uOiBsYWJlbH0pO1xuICB9XG4gIFxuICBhc3luYyBnZXRQYXltZW50VXJpKGNvbmZpZzogTW9uZXJvVHhDb25maWcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbmZpZyA9IE1vbmVyb1dhbGxldC5ub3JtYWxpemVDcmVhdGVUeHNDb25maWcoY29uZmlnKTtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcIm1ha2VfdXJpXCIsIHtcbiAgICAgIGFkZHJlc3M6IGNvbmZpZy5nZXREZXN0aW5hdGlvbnMoKVswXS5nZXRBZGRyZXNzKCksXG4gICAgICBhbW91bnQ6IGNvbmZpZy5nZXREZXN0aW5hdGlvbnMoKVswXS5nZXRBbW91bnQoKSA/IGNvbmZpZy5nZXREZXN0aW5hdGlvbnMoKVswXS5nZXRBbW91bnQoKS50b1N0cmluZygpIDogdW5kZWZpbmVkLFxuICAgICAgcGF5bWVudF9pZDogY29uZmlnLmdldFBheW1lbnRJZCgpLFxuICAgICAgcmVjaXBpZW50X25hbWU6IGNvbmZpZy5nZXRSZWNpcGllbnROYW1lKCksXG4gICAgICB0eF9kZXNjcmlwdGlvbjogY29uZmlnLmdldE5vdGUoKVxuICAgIH0pO1xuICAgIHJldHVybiByZXNwLnJlc3VsdC51cmk7XG4gIH1cbiAgXG4gIGFzeW5jIHBhcnNlUGF5bWVudFVyaSh1cmk6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvVHhDb25maWc+IHtcbiAgICBhc3NlcnQodXJpLCBcIk11c3QgcHJvdmlkZSBVUkkgdG8gcGFyc2VcIik7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJwYXJzZV91cmlcIiwge3VyaTogdXJpfSk7XG4gICAgbGV0IGNvbmZpZyA9IG5ldyBNb25lcm9UeENvbmZpZyh7YWRkcmVzczogcmVzcC5yZXN1bHQudXJpLmFkZHJlc3MsIGFtb3VudDogQmlnSW50KHJlc3AucmVzdWx0LnVyaS5hbW91bnQpfSk7XG4gICAgY29uZmlnLnNldFBheW1lbnRJZChyZXNwLnJlc3VsdC51cmkucGF5bWVudF9pZCk7XG4gICAgY29uZmlnLnNldFJlY2lwaWVudE5hbWUocmVzcC5yZXN1bHQudXJpLnJlY2lwaWVudF9uYW1lKTtcbiAgICBjb25maWcuc2V0Tm90ZShyZXNwLnJlc3VsdC51cmkudHhfZGVzY3JpcHRpb24pO1xuICAgIGlmIChcIlwiID09PSBjb25maWcuZ2V0RGVzdGluYXRpb25zKClbMF0uZ2V0QWRkcmVzcygpKSBjb25maWcuZ2V0RGVzdGluYXRpb25zKClbMF0uc2V0QWRkcmVzcyh1bmRlZmluZWQpO1xuICAgIGlmIChcIlwiID09PSBjb25maWcuZ2V0UGF5bWVudElkKCkpIGNvbmZpZy5zZXRQYXltZW50SWQodW5kZWZpbmVkKTtcbiAgICBpZiAoXCJcIiA9PT0gY29uZmlnLmdldFJlY2lwaWVudE5hbWUoKSkgY29uZmlnLnNldFJlY2lwaWVudE5hbWUodW5kZWZpbmVkKTtcbiAgICBpZiAoXCJcIiA9PT0gY29uZmlnLmdldE5vdGUoKSkgY29uZmlnLnNldE5vdGUodW5kZWZpbmVkKTtcbiAgICByZXR1cm4gY29uZmlnO1xuICB9XG4gIFxuICBhc3luYyBnZXRBdHRyaWJ1dGUoa2V5OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHRyeSB7XG4gICAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF9hdHRyaWJ1dGVcIiwge2tleToga2V5fSk7XG4gICAgICByZXR1cm4gcmVzcC5yZXN1bHQudmFsdWUgPT09IFwiXCIgPyB1bmRlZmluZWQgOiByZXNwLnJlc3VsdC52YWx1ZTtcbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIGlmIChlIGluc3RhbmNlb2YgTW9uZXJvUnBjRXJyb3IgJiYgZS5nZXRDb2RlKCkgPT09IC00NSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIHRocm93IGU7XG4gICAgfVxuICB9XG4gIFxuICBhc3luYyBzZXRBdHRyaWJ1dGUoa2V5OiBzdHJpbmcsIHZhbDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwic2V0X2F0dHJpYnV0ZVwiLCB7a2V5OiBrZXksIHZhbHVlOiB2YWx9KTtcbiAgfVxuICBcbiAgYXN5bmMgc3RhcnRNaW5pbmcobnVtVGhyZWFkczogbnVtYmVyLCBiYWNrZ3JvdW5kTWluaW5nPzogYm9vbGVhbiwgaWdub3JlQmF0dGVyeT86IGJvb2xlYW4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJzdGFydF9taW5pbmdcIiwge1xuICAgICAgdGhyZWFkc19jb3VudDogbnVtVGhyZWFkcyxcbiAgICAgIGRvX2JhY2tncm91bmRfbWluaW5nOiBiYWNrZ3JvdW5kTWluaW5nLFxuICAgICAgaWdub3JlX2JhdHRlcnk6IGlnbm9yZUJhdHRlcnlcbiAgICB9KTtcbiAgfVxuICBcbiAgYXN5bmMgc3RvcE1pbmluZygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJzdG9wX21pbmluZ1wiKTtcbiAgfVxuICBcbiAgYXN5bmMgaXNNdWx0aXNpZ0ltcG9ydE5lZWRlZCgpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF9iYWxhbmNlXCIpO1xuICAgIHJldHVybiByZXNwLnJlc3VsdC5tdWx0aXNpZ19pbXBvcnRfbmVlZGVkID09PSB0cnVlO1xuICB9XG4gIFxuICBhc3luYyBnZXRNdWx0aXNpZ0luZm8oKTogUHJvbWlzZTxNb25lcm9NdWx0aXNpZ0luZm8+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImlzX211bHRpc2lnXCIpO1xuICAgIGxldCByZXN1bHQgPSByZXNwLnJlc3VsdDtcbiAgICBsZXQgaW5mbyA9IG5ldyBNb25lcm9NdWx0aXNpZ0luZm8oKTtcbiAgICBpbmZvLnNldElzTXVsdGlzaWcocmVzdWx0Lm11bHRpc2lnKTtcbiAgICBpbmZvLnNldElzUmVhZHkocmVzdWx0LnJlYWR5KTtcbiAgICBpbmZvLnNldFRocmVzaG9sZChyZXN1bHQudGhyZXNob2xkKTtcbiAgICBpbmZvLnNldE51bVBhcnRpY2lwYW50cyhyZXN1bHQudG90YWwpO1xuICAgIHJldHVybiBpbmZvO1xuICB9XG4gIFxuICBhc3luYyBwcmVwYXJlTXVsdGlzaWcoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcInByZXBhcmVfbXVsdGlzaWdcIiwge2VuYWJsZV9tdWx0aXNpZ19leHBlcmltZW50YWw6IHRydWV9KTtcbiAgICB0aGlzLmFkZHJlc3NDYWNoZSA9IHt9O1xuICAgIGxldCByZXN1bHQgPSByZXNwLnJlc3VsdDtcbiAgICByZXR1cm4gcmVzdWx0Lm11bHRpc2lnX2luZm87XG4gIH1cbiAgXG4gIGFzeW5jIG1ha2VNdWx0aXNpZyhtdWx0aXNpZ0hleGVzOiBzdHJpbmdbXSwgdGhyZXNob2xkOiBudW1iZXIsIHBhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwibWFrZV9tdWx0aXNpZ1wiLCB7XG4gICAgICBtdWx0aXNpZ19pbmZvOiBtdWx0aXNpZ0hleGVzLFxuICAgICAgdGhyZXNob2xkOiB0aHJlc2hvbGQsXG4gICAgICBwYXNzd29yZDogcGFzc3dvcmRcbiAgICB9KTtcbiAgICB0aGlzLmFkZHJlc3NDYWNoZSA9IHt9O1xuICAgIHJldHVybiByZXNwLnJlc3VsdC5tdWx0aXNpZ19pbmZvO1xuICB9XG4gIFxuICBhc3luYyBleGNoYW5nZU11bHRpc2lnS2V5cyhtdWx0aXNpZ0hleGVzOiBzdHJpbmdbXSwgcGFzc3dvcmQ6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvTXVsdGlzaWdJbml0UmVzdWx0PiB7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJleGNoYW5nZV9tdWx0aXNpZ19rZXlzXCIsIHttdWx0aXNpZ19pbmZvOiBtdWx0aXNpZ0hleGVzLCBwYXNzd29yZDogcGFzc3dvcmR9KTtcbiAgICB0aGlzLmFkZHJlc3NDYWNoZSA9IHt9O1xuICAgIGxldCBtc1Jlc3VsdCA9IG5ldyBNb25lcm9NdWx0aXNpZ0luaXRSZXN1bHQoKTtcbiAgICBtc1Jlc3VsdC5zZXRBZGRyZXNzKHJlc3AucmVzdWx0LmFkZHJlc3MpO1xuICAgIG1zUmVzdWx0LnNldE11bHRpc2lnSGV4KHJlc3AucmVzdWx0Lm11bHRpc2lnX2luZm8pO1xuICAgIGlmIChtc1Jlc3VsdC5nZXRBZGRyZXNzKCkubGVuZ3RoID09PSAwKSBtc1Jlc3VsdC5zZXRBZGRyZXNzKHVuZGVmaW5lZCk7XG4gICAgaWYgKG1zUmVzdWx0LmdldE11bHRpc2lnSGV4KCkubGVuZ3RoID09PSAwKSBtc1Jlc3VsdC5zZXRNdWx0aXNpZ0hleCh1bmRlZmluZWQpO1xuICAgIHJldHVybiBtc1Jlc3VsdDtcbiAgfVxuICBcbiAgYXN5bmMgZXhwb3J0TXVsdGlzaWdIZXgoKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImV4cG9ydF9tdWx0aXNpZ19pbmZvXCIpO1xuICAgIHJldHVybiByZXNwLnJlc3VsdC5pbmZvO1xuICB9XG5cbiAgYXN5bmMgaW1wb3J0TXVsdGlzaWdIZXgobXVsdGlzaWdIZXhlczogc3RyaW5nW10pOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGlmICghR2VuVXRpbHMuaXNBcnJheShtdWx0aXNpZ0hleGVzKSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTXVzdCBwcm92aWRlIHN0cmluZ1tdIHRvIGltcG9ydE11bHRpc2lnSGV4KClcIilcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImltcG9ydF9tdWx0aXNpZ19pbmZvXCIsIHtpbmZvOiBtdWx0aXNpZ0hleGVzfSk7XG4gICAgcmV0dXJuIHJlc3AucmVzdWx0Lm5fb3V0cHV0cztcbiAgfVxuXG4gIGFzeW5jIHNpZ25NdWx0aXNpZ1R4SGV4KG11bHRpc2lnVHhIZXg6IHN0cmluZyk6IFByb21pc2U8TW9uZXJvTXVsdGlzaWdTaWduUmVzdWx0PiB7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJzaWduX211bHRpc2lnXCIsIHt0eF9kYXRhX2hleDogbXVsdGlzaWdUeEhleH0pO1xuICAgIGxldCByZXN1bHQgPSByZXNwLnJlc3VsdDtcbiAgICBsZXQgc2lnblJlc3VsdCA9IG5ldyBNb25lcm9NdWx0aXNpZ1NpZ25SZXN1bHQoKTtcbiAgICBzaWduUmVzdWx0LnNldFNpZ25lZE11bHRpc2lnVHhIZXgocmVzdWx0LnR4X2RhdGFfaGV4KTtcbiAgICBzaWduUmVzdWx0LnNldFR4SGFzaGVzKHJlc3VsdC50eF9oYXNoX2xpc3QpO1xuICAgIHJldHVybiBzaWduUmVzdWx0O1xuICB9XG5cbiAgYXN5bmMgc3VibWl0TXVsdGlzaWdUeEhleChzaWduZWRNdWx0aXNpZ1R4SGV4OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJzdWJtaXRfbXVsdGlzaWdcIiwge3R4X2RhdGFfaGV4OiBzaWduZWRNdWx0aXNpZ1R4SGV4fSk7XG4gICAgcmV0dXJuIHJlc3AucmVzdWx0LnR4X2hhc2hfbGlzdDtcbiAgfVxuICBcbiAgYXN5bmMgY2hhbmdlUGFzc3dvcmQob2xkUGFzc3dvcmQ6IHN0cmluZywgbmV3UGFzc3dvcmQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJjaGFuZ2Vfd2FsbGV0X3Bhc3N3b3JkXCIsIHtvbGRfcGFzc3dvcmQ6IG9sZFBhc3N3b3JkIHx8IFwiXCIsIG5ld19wYXNzd29yZDogbmV3UGFzc3dvcmQgfHwgXCJcIn0pO1xuICB9XG4gIFxuICBhc3luYyBzYXZlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcInN0b3JlXCIpO1xuICB9XG4gIFxuICBhc3luYyBjbG9zZShzYXZlID0gZmFsc2UpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCBzdXBlci5jbG9zZShzYXZlKTtcbiAgICBpZiAoc2F2ZSA9PT0gdW5kZWZpbmVkKSBzYXZlID0gZmFsc2U7XG4gICAgYXdhaXQgdGhpcy5jbGVhcigpO1xuICAgIGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImNsb3NlX3dhbGxldFwiLCB7YXV0b3NhdmVfY3VycmVudDogc2F2ZX0pO1xuICB9XG4gIFxuICBhc3luYyBpc0Nsb3NlZCgpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5nZXRQcmltYXJ5QWRkcmVzcygpO1xuICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgcmV0dXJuIGUgaW5zdGFuY2VvZiBNb25lcm9ScGNFcnJvciAmJiBlLmdldENvZGUoKSA9PT0gLTEzICYmIGUubWVzc2FnZS5pbmRleE9mKFwiTm8gd2FsbGV0IGZpbGVcIikgPiAtMTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIFxuICAvKipcbiAgICogU2F2ZSBhbmQgY2xvc2UgdGhlIGN1cnJlbnQgd2FsbGV0IGFuZCBzdG9wIHRoZSBSUEMgc2VydmVyLlxuICAgKiBcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIHN0b3AoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgdGhpcy5jbGVhcigpO1xuICAgIGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcInN0b3Bfd2FsbGV0XCIpO1xuICB9XG4gIFxuICAvLyAtLS0tLS0tLS0tLSBBREQgSlNET0MgRk9SIFNVUFBPUlRFRCBERUZBVUxUIElNUExFTUVOVEFUSU9OUyAtLS0tLS0tLS0tLS0tLVxuXG4gIGFzeW5jIGdldE51bUJsb2Nrc1RvVW5sb2NrKCk6IFByb21pc2U8bnVtYmVyW118dW5kZWZpbmVkPiB7IHJldHVybiBzdXBlci5nZXROdW1CbG9ja3NUb1VubG9jaygpOyB9XG4gIGFzeW5jIGdldFR4KHR4SGFzaDogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9UeFdhbGxldHx1bmRlZmluZWQ+IHsgcmV0dXJuIHN1cGVyLmdldFR4KHR4SGFzaCk7IH1cbiAgYXN5bmMgZ2V0SW5jb21pbmdUcmFuc2ZlcnMocXVlcnk6IFBhcnRpYWw8TW9uZXJvVHJhbnNmZXJRdWVyeT4pOiBQcm9taXNlPE1vbmVyb0luY29taW5nVHJhbnNmZXJbXT4geyByZXR1cm4gc3VwZXIuZ2V0SW5jb21pbmdUcmFuc2ZlcnMocXVlcnkpOyB9XG4gIGFzeW5jIGdldE91dGdvaW5nVHJhbnNmZXJzKHF1ZXJ5OiBQYXJ0aWFsPE1vbmVyb1RyYW5zZmVyUXVlcnk+KSB7IHJldHVybiBzdXBlci5nZXRPdXRnb2luZ1RyYW5zZmVycyhxdWVyeSk7IH1cbiAgYXN5bmMgY3JlYXRlVHgoY29uZmlnOiBQYXJ0aWFsPE1vbmVyb1R4Q29uZmlnPik6IFByb21pc2U8TW9uZXJvVHhXYWxsZXQ+IHsgcmV0dXJuIHN1cGVyLmNyZWF0ZVR4KGNvbmZpZyk7IH1cbiAgYXN5bmMgcmVsYXlUeCh0eE9yTWV0YWRhdGE6IE1vbmVyb1R4V2FsbGV0IHwgc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHsgcmV0dXJuIHN1cGVyLnJlbGF5VHgodHhPck1ldGFkYXRhKTsgfVxuICBhc3luYyBnZXRUeE5vdGUodHhIYXNoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4geyByZXR1cm4gc3VwZXIuZ2V0VHhOb3RlKHR4SGFzaCk7IH1cbiAgYXN5bmMgc2V0VHhOb3RlKHR4SGFzaDogc3RyaW5nLCBub3RlOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHsgcmV0dXJuIHN1cGVyLnNldFR4Tm90ZSh0eEhhc2gsIG5vdGUpOyB9XG4gIFxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSBQUklWQVRFIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIHN0YXRpYyBhc3luYyBjb25uZWN0VG9XYWxsZXRScGModXJpT3JDb25maWc6IHN0cmluZyB8IFBhcnRpYWw8TW9uZXJvUnBjQ29ubmVjdGlvbj4gfCBQYXJ0aWFsPE1vbmVyb1dhbGxldENvbmZpZz4gfCBzdHJpbmdbXSwgdXNlcm5hbWU/OiBzdHJpbmcsIHBhc3N3b3JkPzogc3RyaW5nKTogUHJvbWlzZTxNb25lcm9XYWxsZXRScGM+IHtcbiAgICBsZXQgY29uZmlnID0gTW9uZXJvV2FsbGV0UnBjLm5vcm1hbGl6ZUNvbmZpZyh1cmlPckNvbmZpZywgdXNlcm5hbWUsIHBhc3N3b3JkKTtcbiAgICBpZiAoY29uZmlnLmNtZCkgcmV0dXJuIE1vbmVyb1dhbGxldFJwYy5zdGFydFdhbGxldFJwY1Byb2Nlc3MoY29uZmlnKTtcbiAgICBlbHNlIHJldHVybiBuZXcgTW9uZXJvV2FsbGV0UnBjKGNvbmZpZyk7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBzdGF0aWMgYXN5bmMgc3RhcnRXYWxsZXRScGNQcm9jZXNzKGNvbmZpZzogUGFydGlhbDxNb25lcm9XYWxsZXRDb25maWc+KTogUHJvbWlzZTxNb25lcm9XYWxsZXRScGM+IHtcbiAgICBhc3NlcnQoR2VuVXRpbHMuaXNBcnJheShjb25maWcuY21kKSwgXCJNdXN0IHByb3ZpZGUgc3RyaW5nIGFycmF5IHdpdGggY29tbWFuZCBsaW5lIHBhcmFtZXRlcnNcIik7XG4gICAgXG4gICAgLy8gc3RhcnQgcHJvY2Vzc1xuICAgIGxldCBjaGlsZF9wcm9jZXNzID0gYXdhaXQgaW1wb3J0KFwiY2hpbGRfcHJvY2Vzc1wiKTtcbiAgICBjb25zdCBjaGlsZFByb2Nlc3MgPSBjaGlsZF9wcm9jZXNzLnNwYXduKGNvbmZpZy5jbWRbMF0sIGNvbmZpZy5jbWQuc2xpY2UoMSksIHtcbiAgICAgIGVudjogeyAuLi5wcm9jZXNzLmVudiwgTEFORzogJ2VuX1VTLlVURi04JyB9IC8vIHNjcmFwZSBvdXRwdXQgaW4gZW5nbGlzaFxuICAgIH0pO1xuICAgIGNoaWxkUHJvY2Vzcy5zdGRvdXQuc2V0RW5jb2RpbmcoJ3V0ZjgnKTtcbiAgICBjaGlsZFByb2Nlc3Muc3RkZXJyLnNldEVuY29kaW5nKCd1dGY4Jyk7XG4gICAgXG4gICAgLy8gcmV0dXJuIHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgYWZ0ZXIgc3RhcnRpbmcgbW9uZXJvLXdhbGxldC1ycGNcbiAgICBsZXQgdXJpO1xuICAgIGxldCB0aGF0ID0gdGhpcztcbiAgICBsZXQgb3V0cHV0ID0gXCJcIjtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IG5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUsIHJlamVjdCkge1xuICAgICAgXG4gICAgICAgIC8vIGhhbmRsZSBzdGRvdXRcbiAgICAgICAgY2hpbGRQcm9jZXNzLnN0ZG91dC5vbignZGF0YScsIGFzeW5jIGZ1bmN0aW9uKGRhdGEpIHtcbiAgICAgICAgICBsZXQgbGluZSA9IGRhdGEudG9TdHJpbmcoKTtcbiAgICAgICAgICBMaWJyYXJ5VXRpbHMubG9nKDIsIGxpbmUpO1xuICAgICAgICAgIG91dHB1dCArPSBsaW5lICsgJ1xcbic7IC8vIGNhcHR1cmUgb3V0cHV0IGluIGNhc2Ugb2YgZXJyb3JcbiAgICAgICAgICBcbiAgICAgICAgICAvLyBleHRyYWN0IHVyaSBmcm9tIGUuZy4gXCJJIEJpbmRpbmcgb24gMTI3LjAuMC4xIChJUHY0KTozODA4NVwiXG4gICAgICAgICAgbGV0IHVyaUxpbmVDb250YWlucyA9IFwiQmluZGluZyBvbiBcIjtcbiAgICAgICAgICBsZXQgdXJpTGluZUNvbnRhaW5zSWR4ID0gbGluZS5pbmRleE9mKHVyaUxpbmVDb250YWlucyk7XG4gICAgICAgICAgaWYgKHVyaUxpbmVDb250YWluc0lkeCA+PSAwKSB7XG4gICAgICAgICAgICBsZXQgaG9zdCA9IGxpbmUuc3Vic3RyaW5nKHVyaUxpbmVDb250YWluc0lkeCArIHVyaUxpbmVDb250YWlucy5sZW5ndGgsIGxpbmUubGFzdEluZGV4T2YoJyAnKSk7XG4gICAgICAgICAgICBsZXQgdW5mb3JtYXR0ZWRMaW5lID0gbGluZS5yZXBsYWNlKC9cXHUwMDFiXFxbLio/bS9nLCAnJykudHJpbSgpOyAvLyByZW1vdmUgY29sb3IgZm9ybWF0dGluZ1xuICAgICAgICAgICAgbGV0IHBvcnQgPSB1bmZvcm1hdHRlZExpbmUuc3Vic3RyaW5nKHVuZm9ybWF0dGVkTGluZS5sYXN0SW5kZXhPZignOicpICsgMSk7XG4gICAgICAgICAgICBsZXQgc3NsSWR4ID0gY29uZmlnLmNtZC5pbmRleE9mKFwiLS1ycGMtc3NsXCIpO1xuICAgICAgICAgICAgbGV0IHNzbEVuYWJsZWQgPSBzc2xJZHggPj0gMCA/IFwiZW5hYmxlZFwiID09IGNvbmZpZy5jbWRbc3NsSWR4ICsgMV0udG9Mb3dlckNhc2UoKSA6IGZhbHNlO1xuICAgICAgICAgICAgdXJpID0gKHNzbEVuYWJsZWQgPyBcImh0dHBzXCIgOiBcImh0dHBcIikgKyBcIjovL1wiICsgaG9zdCArIFwiOlwiICsgcG9ydDtcbiAgICAgICAgICB9XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gcmVhZCBzdWNjZXNzIG1lc3NhZ2VcbiAgICAgICAgICBpZiAobGluZS5pbmRleE9mKFwiU3RhcnRpbmcgd2FsbGV0IFJQQyBzZXJ2ZXJcIikgPj0gMCkge1xuICAgICAgICAgICAgXG4gICAgICAgICAgICAvLyBnZXQgdXNlcm5hbWUgYW5kIHBhc3N3b3JkIGZyb20gcGFyYW1zXG4gICAgICAgICAgICBsZXQgdXNlclBhc3NJZHggPSBjb25maWcuY21kLmluZGV4T2YoXCItLXJwYy1sb2dpblwiKTtcbiAgICAgICAgICAgIGxldCB1c2VyUGFzcyA9IHVzZXJQYXNzSWR4ID49IDAgPyBjb25maWcuY21kW3VzZXJQYXNzSWR4ICsgMV0gOiB1bmRlZmluZWQ7XG4gICAgICAgICAgICBsZXQgdXNlcm5hbWUgPSB1c2VyUGFzcyA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogdXNlclBhc3Muc3Vic3RyaW5nKDAsIHVzZXJQYXNzLmluZGV4T2YoJzonKSk7XG4gICAgICAgICAgICBsZXQgcGFzc3dvcmQgPSB1c2VyUGFzcyA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogdXNlclBhc3Muc3Vic3RyaW5nKHVzZXJQYXNzLmluZGV4T2YoJzonKSArIDEpO1xuICAgICAgICAgICAgXG4gICAgICAgICAgICAvLyBjcmVhdGUgY2xpZW50IGNvbm5lY3RlZCB0byBpbnRlcm5hbCBwcm9jZXNzXG4gICAgICAgICAgICBjb25maWcgPSBjb25maWcuY29weSgpLnNldFNlcnZlcih7dXJpOiB1cmksIHVzZXJuYW1lOiB1c2VybmFtZSwgcGFzc3dvcmQ6IHBhc3N3b3JkLCByZWplY3RVbmF1dGhvcml6ZWQ6IGNvbmZpZy5nZXRTZXJ2ZXIoKSA/IGNvbmZpZy5nZXRTZXJ2ZXIoKS5nZXRSZWplY3RVbmF1dGhvcml6ZWQoKSA6IHVuZGVmaW5lZH0pO1xuICAgICAgICAgICAgY29uZmlnLmNtZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIGxldCB3YWxsZXQgPSBhd2FpdCBNb25lcm9XYWxsZXRScGMuY29ubmVjdFRvV2FsbGV0UnBjKGNvbmZpZyk7XG4gICAgICAgICAgICB3YWxsZXQucHJvY2VzcyA9IGNoaWxkUHJvY2VzcztcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgLy8gcmVzb2x2ZSBwcm9taXNlIHdpdGggY2xpZW50IGNvbm5lY3RlZCB0byBpbnRlcm5hbCBwcm9jZXNzIFxuICAgICAgICAgICAgdGhpcy5pc1Jlc29sdmVkID0gdHJ1ZTtcbiAgICAgICAgICAgIHJlc29sdmUod2FsbGV0KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBcbiAgICAgICAgLy8gaGFuZGxlIHN0ZGVyclxuICAgICAgICBjaGlsZFByb2Nlc3Muc3RkZXJyLm9uKCdkYXRhJywgZnVuY3Rpb24oZGF0YSkge1xuICAgICAgICAgIGlmIChMaWJyYXJ5VXRpbHMuZ2V0TG9nTGV2ZWwoKSA+PSAyKSBjb25zb2xlLmVycm9yKGRhdGEpO1xuICAgICAgICB9KTtcbiAgICAgICAgXG4gICAgICAgIC8vIGhhbmRsZSBleGl0XG4gICAgICAgIGNoaWxkUHJvY2Vzcy5vbihcImV4aXRcIiwgZnVuY3Rpb24oY29kZSkge1xuICAgICAgICAgIGlmICghdGhpcy5pc1Jlc29sdmVkKSByZWplY3QobmV3IE1vbmVyb0Vycm9yKFwibW9uZXJvLXdhbGxldC1ycGMgcHJvY2VzcyB0ZXJtaW5hdGVkIHdpdGggZXhpdCBjb2RlIFwiICsgY29kZSArIChvdXRwdXQgPyBcIjpcXG5cXG5cIiArIG91dHB1dCA6IFwiXCIpKSk7XG4gICAgICAgIH0pO1xuICAgICAgICBcbiAgICAgICAgLy8gaGFuZGxlIGVycm9yXG4gICAgICAgIGNoaWxkUHJvY2Vzcy5vbihcImVycm9yXCIsIGZ1bmN0aW9uKGVycikge1xuICAgICAgICAgIGlmIChlcnIubWVzc2FnZS5pbmRleE9mKFwiRU5PRU5UXCIpID49IDApIHJlamVjdChuZXcgTW9uZXJvRXJyb3IoXCJtb25lcm8td2FsbGV0LXJwYyBkb2VzIG5vdCBleGlzdCBhdCBwYXRoICdcIiArIGNvbmZpZy5jbWRbMF0gKyBcIidcIikpO1xuICAgICAgICAgIGlmICghdGhpcy5pc1Jlc29sdmVkKSByZWplY3QoZXJyKTtcbiAgICAgICAgfSk7XG4gICAgICAgIFxuICAgICAgICAvLyBoYW5kbGUgdW5jYXVnaHQgZXhjZXB0aW9uXG4gICAgICAgIGNoaWxkUHJvY2Vzcy5vbihcInVuY2F1Z2h0RXhjZXB0aW9uXCIsIGZ1bmN0aW9uKGVyciwgb3JpZ2luKSB7XG4gICAgICAgICAgY29uc29sZS5lcnJvcihcIlVuY2F1Z2h0IGV4Y2VwdGlvbiBpbiBtb25lcm8td2FsbGV0LXJwYyBwcm9jZXNzOiBcIiArIGVyci5tZXNzYWdlKTtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKG9yaWdpbik7XG4gICAgICAgICAgaWYgKCF0aGlzLmlzUmVzb2x2ZWQpIHJlamVjdChlcnIpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycjogYW55KSB7XG4gICAgICB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoZXJyLm1lc3NhZ2UpO1xuICAgIH1cbiAgfVxuICBcbiAgcHJvdGVjdGVkIGFzeW5jIGNsZWFyKCkge1xuICAgIHRoaXMucmVmcmVzaExpc3RlbmluZygpO1xuICAgIGRlbGV0ZSB0aGlzLmFkZHJlc3NDYWNoZTtcbiAgICB0aGlzLmFkZHJlc3NDYWNoZSA9IHt9O1xuICAgIHRoaXMucGF0aCA9IHVuZGVmaW5lZDtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIGFzeW5jIGdldEFjY291bnRJbmRpY2VzKGdldFN1YmFkZHJlc3NJbmRpY2VzPzogYW55KSB7XG4gICAgbGV0IGluZGljZXMgPSBuZXcgTWFwKCk7XG4gICAgZm9yIChsZXQgYWNjb3VudCBvZiBhd2FpdCB0aGlzLmdldEFjY291bnRzKCkpIHtcbiAgICAgIGluZGljZXMuc2V0KGFjY291bnQuZ2V0SW5kZXgoKSwgZ2V0U3ViYWRkcmVzc0luZGljZXMgPyBhd2FpdCB0aGlzLmdldFN1YmFkZHJlc3NJbmRpY2VzKGFjY291bnQuZ2V0SW5kZXgoKSkgOiB1bmRlZmluZWQpO1xuICAgIH1cbiAgICByZXR1cm4gaW5kaWNlcztcbiAgfVxuICBcbiAgcHJvdGVjdGVkIGFzeW5jIGdldFN1YmFkZHJlc3NJbmRpY2VzKGFjY291bnRJZHgpIHtcbiAgICBsZXQgc3ViYWRkcmVzc0luZGljZXMgPSBbXTtcbiAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImdldF9hZGRyZXNzXCIsIHthY2NvdW50X2luZGV4OiBhY2NvdW50SWR4fSk7XG4gICAgZm9yIChsZXQgYWRkcmVzcyBvZiByZXNwLnJlc3VsdC5hZGRyZXNzZXMpIHN1YmFkZHJlc3NJbmRpY2VzLnB1c2goYWRkcmVzcy5hZGRyZXNzX2luZGV4KTtcbiAgICByZXR1cm4gc3ViYWRkcmVzc0luZGljZXM7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBhc3luYyBnZXRUcmFuc2ZlcnNBdXgocXVlcnk6IE1vbmVyb1RyYW5zZmVyUXVlcnkpIHtcbiAgICBcbiAgICAvLyBidWlsZCBwYXJhbXMgZm9yIGdldF90cmFuc2ZlcnMgcnBjIGNhbGxcbiAgICBsZXQgdHhRdWVyeSA9IHF1ZXJ5LmdldFR4UXVlcnkoKTtcbiAgICBsZXQgY2FuQmVDb25maXJtZWQgPSB0eFF1ZXJ5LmdldElzQ29uZmlybWVkKCkgIT09IGZhbHNlICYmIHR4UXVlcnkuZ2V0SW5UeFBvb2woKSAhPT0gdHJ1ZSAmJiB0eFF1ZXJ5LmdldElzRmFpbGVkKCkgIT09IHRydWUgJiYgdHhRdWVyeS5nZXRJc1JlbGF5ZWQoKSAhPT0gZmFsc2U7XG4gICAgbGV0IGNhbkJlSW5UeFBvb2wgPSB0eFF1ZXJ5LmdldElzQ29uZmlybWVkKCkgIT09IHRydWUgJiYgdHhRdWVyeS5nZXRJblR4UG9vbCgpICE9PSBmYWxzZSAmJiB0eFF1ZXJ5LmdldElzRmFpbGVkKCkgIT09IHRydWUgJiYgdHhRdWVyeS5nZXRIZWlnaHQoKSA9PT0gdW5kZWZpbmVkICYmIHR4UXVlcnkuZ2V0TWF4SGVpZ2h0KCkgPT09IHVuZGVmaW5lZCAmJiB0eFF1ZXJ5LmdldElzTG9ja2VkKCkgIT09IGZhbHNlO1xuICAgIGxldCBjYW5CZUluY29taW5nID0gcXVlcnkuZ2V0SXNJbmNvbWluZygpICE9PSBmYWxzZSAmJiBxdWVyeS5nZXRJc091dGdvaW5nKCkgIT09IHRydWUgJiYgcXVlcnkuZ2V0SGFzRGVzdGluYXRpb25zKCkgIT09IHRydWU7XG4gICAgbGV0IGNhbkJlT3V0Z29pbmcgPSBxdWVyeS5nZXRJc091dGdvaW5nKCkgIT09IGZhbHNlICYmIHF1ZXJ5LmdldElzSW5jb21pbmcoKSAhPT0gdHJ1ZTtcblxuICAgIC8vIGNoZWNrIGlmIGZldGNoaW5nIHBvb2wgdHhzIGNvbnRyYWRpY3RlZCBieSBjb25maWd1cmF0aW9uXG4gICAgaWYgKHR4UXVlcnkuZ2V0SW5UeFBvb2woKSA9PT0gdHJ1ZSAmJiAhY2FuQmVJblR4UG9vbCkge1xuICAgICAgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ2Fubm90IGZldGNoIHBvb2wgdHJhbnNhY3Rpb25zIGJlY2F1c2UgaXQgY29udHJhZGljdHMgY29uZmlndXJhdGlvblwiKTtcbiAgICB9XG5cbiAgICBsZXQgcGFyYW1zOiBhbnkgPSB7fTtcbiAgICBwYXJhbXMuaW4gPSBjYW5CZUluY29taW5nICYmIGNhbkJlQ29uZmlybWVkO1xuICAgIHBhcmFtcy5vdXQgPSBjYW5CZU91dGdvaW5nICYmIGNhbkJlQ29uZmlybWVkO1xuICAgIHBhcmFtcy5wb29sID0gY2FuQmVJbmNvbWluZyAmJiBjYW5CZUluVHhQb29sO1xuICAgIHBhcmFtcy5wZW5kaW5nID0gY2FuQmVPdXRnb2luZyAmJiBjYW5CZUluVHhQb29sO1xuICAgIHBhcmFtcy5mYWlsZWQgPSB0eFF1ZXJ5LmdldElzRmFpbGVkKCkgIT09IGZhbHNlICYmIHR4UXVlcnkuZ2V0SXNDb25maXJtZWQoKSAhPT0gdHJ1ZSAmJiB0eFF1ZXJ5LmdldEluVHhQb29sKCkgIT0gdHJ1ZTtcbiAgICBpZiAodHhRdWVyeS5nZXRNaW5IZWlnaHQoKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBpZiAodHhRdWVyeS5nZXRNaW5IZWlnaHQoKSA+IDApIHBhcmFtcy5taW5faGVpZ2h0ID0gdHhRdWVyeS5nZXRNaW5IZWlnaHQoKSAtIDE7IC8vIFRPRE8gbW9uZXJvLXByb2plY3Q6IHdhbGxldDI6OmdldF9wYXltZW50cygpIG1pbl9oZWlnaHQgaXMgZXhjbHVzaXZlLCBzbyBtYW51YWxseSBvZmZzZXQgdG8gbWF0Y2ggaW50ZW5kZWQgcmFuZ2UgKGlzc3VlcyAjNTc1MSwgIzU1OTgpXG4gICAgICBlbHNlIHBhcmFtcy5taW5faGVpZ2h0ID0gdHhRdWVyeS5nZXRNaW5IZWlnaHQoKTtcbiAgICB9XG4gICAgaWYgKHR4UXVlcnkuZ2V0TWF4SGVpZ2h0KCkgIT09IHVuZGVmaW5lZCkgcGFyYW1zLm1heF9oZWlnaHQgPSB0eFF1ZXJ5LmdldE1heEhlaWdodCgpO1xuICAgIHBhcmFtcy5maWx0ZXJfYnlfaGVpZ2h0ID0gdHhRdWVyeS5nZXRNaW5IZWlnaHQoKSAhPT0gdW5kZWZpbmVkIHx8IHR4UXVlcnkuZ2V0TWF4SGVpZ2h0KCkgIT09IHVuZGVmaW5lZDtcbiAgICBpZiAocXVlcnkuZ2V0QWNjb3VudEluZGV4KCkgPT09IHVuZGVmaW5lZCkge1xuICAgICAgYXNzZXJ0KHF1ZXJ5LmdldFN1YmFkZHJlc3NJbmRleCgpID09PSB1bmRlZmluZWQgJiYgcXVlcnkuZ2V0U3ViYWRkcmVzc0luZGljZXMoKSA9PT0gdW5kZWZpbmVkLCBcIlF1ZXJ5IHNwZWNpZmllcyBhIHN1YmFkZHJlc3MgaW5kZXggYnV0IG5vdCBhbiBhY2NvdW50IGluZGV4XCIpO1xuICAgICAgcGFyYW1zLmFsbF9hY2NvdW50cyA9IHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHBhcmFtcy5hY2NvdW50X2luZGV4ID0gcXVlcnkuZ2V0QWNjb3VudEluZGV4KCk7XG4gICAgICBcbiAgICAgIC8vIHNldCBzdWJhZGRyZXNzIGluZGljZXMgcGFyYW1cbiAgICAgIGxldCBzdWJhZGRyZXNzSW5kaWNlcyA9IG5ldyBTZXQoKTtcbiAgICAgIGlmIChxdWVyeS5nZXRTdWJhZGRyZXNzSW5kZXgoKSAhPT0gdW5kZWZpbmVkKSBzdWJhZGRyZXNzSW5kaWNlcy5hZGQocXVlcnkuZ2V0U3ViYWRkcmVzc0luZGV4KCkpO1xuICAgICAgaWYgKHF1ZXJ5LmdldFN1YmFkZHJlc3NJbmRpY2VzKCkgIT09IHVuZGVmaW5lZCkgcXVlcnkuZ2V0U3ViYWRkcmVzc0luZGljZXMoKS5tYXAoc3ViYWRkcmVzc0lkeCA9PiBzdWJhZGRyZXNzSW5kaWNlcy5hZGQoc3ViYWRkcmVzc0lkeCkpO1xuICAgICAgaWYgKHN1YmFkZHJlc3NJbmRpY2VzLnNpemUpIHBhcmFtcy5zdWJhZGRyX2luZGljZXMgPSBBcnJheS5mcm9tKHN1YmFkZHJlc3NJbmRpY2VzKTtcbiAgICB9XG4gICAgXG4gICAgLy8gY2FjaGUgdW5pcXVlIHR4cyBhbmQgYmxvY2tzXG4gICAgbGV0IHR4TWFwID0ge307XG4gICAgbGV0IGJsb2NrTWFwID0ge307XG4gICAgXG4gICAgLy8gYnVpbGQgdHhzIHVzaW5nIGBnZXRfdHJhbnNmZXJzYFxuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZ2V0X3RyYW5zZmVyc1wiLCBwYXJhbXMpO1xuICAgIGZvciAobGV0IGtleSBvZiBPYmplY3Qua2V5cyhyZXNwLnJlc3VsdCkpIHtcbiAgICAgIGZvciAobGV0IHJwY1R4IG9mIHJlc3AucmVzdWx0W2tleV0pIHtcbiAgICAgICAgLy9pZiAocnBjVHgudHhpZCA9PT0gcXVlcnkuZGVidWdUeElkKSBjb25zb2xlLmxvZyhycGNUeCk7XG4gICAgICAgIGxldCB0eCA9IE1vbmVyb1dhbGxldFJwYy5jb252ZXJ0UnBjVHhXaXRoVHJhbnNmZXIocnBjVHgpO1xuICAgICAgICBpZiAodHguZ2V0SXNDb25maXJtZWQoKSkgYXNzZXJ0KHR4LmdldEJsb2NrKCkuZ2V0VHhzKCkuaW5kZXhPZih0eCkgPiAtMSk7XG4gICAgICAgIFxuICAgICAgICAvLyByZXBsYWNlIHRyYW5zZmVyIGFtb3VudCB3aXRoIGRlc3RpbmF0aW9uIHN1bVxuICAgICAgICAvLyBUT0RPIG1vbmVyby13YWxsZXQtcnBjOiBjb25maXJtZWQgdHggZnJvbS90byBzYW1lIGFjY291bnQgaGFzIGFtb3VudCAwIGJ1dCBjYWNoZWQgdHJhbnNmZXJzXG4gICAgICAgIGlmICh0eC5nZXRPdXRnb2luZ1RyYW5zZmVyKCkgIT09IHVuZGVmaW5lZCAmJiB0eC5nZXRJc1JlbGF5ZWQoKSAmJiAhdHguZ2V0SXNGYWlsZWQoKSAmJlxuICAgICAgICAgICAgdHguZ2V0T3V0Z29pbmdUcmFuc2ZlcigpLmdldERlc3RpbmF0aW9ucygpICYmIHR4LmdldE91dGdvaW5nQW1vdW50KCkgPT09IDBuKSB7XG4gICAgICAgICAgbGV0IG91dGdvaW5nVHJhbnNmZXIgPSB0eC5nZXRPdXRnb2luZ1RyYW5zZmVyKCk7XG4gICAgICAgICAgbGV0IHRyYW5zZmVyVG90YWwgPSBCaWdJbnQoMCk7XG4gICAgICAgICAgZm9yIChsZXQgZGVzdGluYXRpb24gb2Ygb3V0Z29pbmdUcmFuc2Zlci5nZXREZXN0aW5hdGlvbnMoKSkgdHJhbnNmZXJUb3RhbCA9IHRyYW5zZmVyVG90YWwgKyBkZXN0aW5hdGlvbi5nZXRBbW91bnQoKTtcbiAgICAgICAgICB0eC5nZXRPdXRnb2luZ1RyYW5zZmVyKCkuc2V0QW1vdW50KHRyYW5zZmVyVG90YWwpO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBtZXJnZSB0eFxuICAgICAgICBNb25lcm9XYWxsZXRScGMubWVyZ2VUeCh0eCwgdHhNYXAsIGJsb2NrTWFwKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gc29ydCB0eHMgYnkgYmxvY2sgaGVpZ2h0XG4gICAgbGV0IHR4czogTW9uZXJvVHhXYWxsZXRbXSA9IE9iamVjdC52YWx1ZXModHhNYXApO1xuICAgIHR4cy5zb3J0KE1vbmVyb1dhbGxldFJwYy5jb21wYXJlVHhzQnlIZWlnaHQpO1xuICAgIFxuICAgIC8vIGZpbHRlciBhbmQgcmV0dXJuIHRyYW5zZmVyc1xuICAgIGxldCB0cmFuc2ZlcnMgPSBbXTtcbiAgICBmb3IgKGxldCB0eCBvZiB0eHMpIHtcbiAgICAgIFxuICAgICAgLy8gdHggaXMgbm90IGluY29taW5nL291dGdvaW5nIHVubGVzcyBhbHJlYWR5IHNldFxuICAgICAgaWYgKHR4LmdldElzSW5jb21pbmcoKSA9PT0gdW5kZWZpbmVkKSB0eC5zZXRJc0luY29taW5nKGZhbHNlKTtcbiAgICAgIGlmICh0eC5nZXRJc091dGdvaW5nKCkgPT09IHVuZGVmaW5lZCkgdHguc2V0SXNPdXRnb2luZyhmYWxzZSk7XG4gICAgICBcbiAgICAgIC8vIHNvcnQgaW5jb21pbmcgdHJhbnNmZXJzXG4gICAgICBpZiAodHguZ2V0SW5jb21pbmdUcmFuc2ZlcnMoKSAhPT0gdW5kZWZpbmVkKSB0eC5nZXRJbmNvbWluZ1RyYW5zZmVycygpLnNvcnQoTW9uZXJvV2FsbGV0UnBjLmNvbXBhcmVJbmNvbWluZ1RyYW5zZmVycyk7XG4gICAgICBcbiAgICAgIC8vIGNvbGxlY3QgcXVlcmllZCB0cmFuc2ZlcnMsIGVyYXNlIGlmIGV4Y2x1ZGVkXG4gICAgICBmb3IgKGxldCB0cmFuc2ZlciBvZiB0eC5maWx0ZXJUcmFuc2ZlcnMocXVlcnkpKSB7XG4gICAgICAgIHRyYW5zZmVycy5wdXNoKHRyYW5zZmVyKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gcmVtb3ZlIHR4cyB3aXRob3V0IHJlcXVlc3RlZCB0cmFuc2ZlclxuICAgICAgaWYgKHR4LmdldEJsb2NrKCkgIT09IHVuZGVmaW5lZCAmJiB0eC5nZXRPdXRnb2luZ1RyYW5zZmVyKCkgPT09IHVuZGVmaW5lZCAmJiB0eC5nZXRJbmNvbWluZ1RyYW5zZmVycygpID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdHguZ2V0QmxvY2soKS5nZXRUeHMoKS5zcGxpY2UodHguZ2V0QmxvY2soKS5nZXRUeHMoKS5pbmRleE9mKHR4KSwgMSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHJldHVybiB0cmFuc2ZlcnM7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBhc3luYyBnZXRPdXRwdXRzQXV4KHF1ZXJ5KSB7XG4gICAgXG4gICAgLy8gZGV0ZXJtaW5lIGFjY291bnQgYW5kIHN1YmFkZHJlc3MgaW5kaWNlcyB0byBiZSBxdWVyaWVkXG4gICAgbGV0IGluZGljZXMgPSBuZXcgTWFwKCk7XG4gICAgaWYgKHF1ZXJ5LmdldEFjY291bnRJbmRleCgpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGxldCBzdWJhZGRyZXNzSW5kaWNlcyA9IG5ldyBTZXQoKTtcbiAgICAgIGlmIChxdWVyeS5nZXRTdWJhZGRyZXNzSW5kZXgoKSAhPT0gdW5kZWZpbmVkKSBzdWJhZGRyZXNzSW5kaWNlcy5hZGQocXVlcnkuZ2V0U3ViYWRkcmVzc0luZGV4KCkpO1xuICAgICAgaWYgKHF1ZXJ5LmdldFN1YmFkZHJlc3NJbmRpY2VzKCkgIT09IHVuZGVmaW5lZCkgcXVlcnkuZ2V0U3ViYWRkcmVzc0luZGljZXMoKS5tYXAoc3ViYWRkcmVzc0lkeCA9PiBzdWJhZGRyZXNzSW5kaWNlcy5hZGQoc3ViYWRkcmVzc0lkeCkpO1xuICAgICAgaW5kaWNlcy5zZXQocXVlcnkuZ2V0QWNjb3VudEluZGV4KCksIHN1YmFkZHJlc3NJbmRpY2VzLnNpemUgPyBBcnJheS5mcm9tKHN1YmFkZHJlc3NJbmRpY2VzKSA6IHVuZGVmaW5lZCk7ICAvLyB1bmRlZmluZWQgd2lsbCBmZXRjaCBmcm9tIGFsbCBzdWJhZGRyZXNzZXNcbiAgICB9IGVsc2Uge1xuICAgICAgYXNzZXJ0LmVxdWFsKHF1ZXJ5LmdldFN1YmFkZHJlc3NJbmRleCgpLCB1bmRlZmluZWQsIFwiUXVlcnkgc3BlY2lmaWVzIGEgc3ViYWRkcmVzcyBpbmRleCBidXQgbm90IGFuIGFjY291bnQgaW5kZXhcIilcbiAgICAgIGFzc2VydChxdWVyeS5nZXRTdWJhZGRyZXNzSW5kaWNlcygpID09PSB1bmRlZmluZWQgfHwgcXVlcnkuZ2V0U3ViYWRkcmVzc0luZGljZXMoKS5sZW5ndGggPT09IDAsIFwiUXVlcnkgc3BlY2lmaWVzIHN1YmFkZHJlc3MgaW5kaWNlcyBidXQgbm90IGFuIGFjY291bnQgaW5kZXhcIik7XG4gICAgICBpbmRpY2VzID0gYXdhaXQgdGhpcy5nZXRBY2NvdW50SW5kaWNlcygpOyAgLy8gZmV0Y2ggYWxsIGFjY291bnQgaW5kaWNlcyB3aXRob3V0IHN1YmFkZHJlc3Nlc1xuICAgIH1cbiAgICBcbiAgICAvLyBjYWNoZSB1bmlxdWUgdHhzIGFuZCBibG9ja3NcbiAgICBsZXQgdHhNYXAgPSB7fTtcbiAgICBsZXQgYmxvY2tNYXAgPSB7fTtcbiAgICBcbiAgICAvLyBjb2xsZWN0IHR4cyB3aXRoIG91dHB1dHMgZm9yIGVhY2ggaW5kaWNhdGVkIGFjY291bnQgdXNpbmcgYGluY29taW5nX3RyYW5zZmVyc2AgcnBjIGNhbGxcbiAgICBsZXQgcGFyYW1zOiBhbnkgPSB7fTtcbiAgICBwYXJhbXMudHJhbnNmZXJfdHlwZSA9IHF1ZXJ5LmdldElzU3BlbnQoKSA9PT0gdHJ1ZSA/IFwidW5hdmFpbGFibGVcIiA6IHF1ZXJ5LmdldElzU3BlbnQoKSA9PT0gZmFsc2UgPyBcImF2YWlsYWJsZVwiIDogXCJhbGxcIjtcbiAgICBwYXJhbXMudmVyYm9zZSA9IHRydWU7XG4gICAgZm9yIChsZXQgYWNjb3VudElkeCBvZiBpbmRpY2VzLmtleXMoKSkge1xuICAgIFxuICAgICAgLy8gc2VuZCByZXF1ZXN0XG4gICAgICBwYXJhbXMuYWNjb3VudF9pbmRleCA9IGFjY291bnRJZHg7XG4gICAgICBwYXJhbXMuc3ViYWRkcl9pbmRpY2VzID0gaW5kaWNlcy5nZXQoYWNjb3VudElkeCk7XG4gICAgICBsZXQgcmVzcCA9IGF3YWl0IHRoaXMuY29uZmlnLmdldFNlcnZlcigpLnNlbmRKc29uUmVxdWVzdChcImluY29taW5nX3RyYW5zZmVyc1wiLCBwYXJhbXMpO1xuICAgICAgXG4gICAgICAvLyBjb252ZXJ0IHJlc3BvbnNlIHRvIHR4cyB3aXRoIG91dHB1dHMgYW5kIG1lcmdlXG4gICAgICBpZiAocmVzcC5yZXN1bHQudHJhbnNmZXJzID09PSB1bmRlZmluZWQpIGNvbnRpbnVlO1xuICAgICAgZm9yIChsZXQgcnBjT3V0cHV0IG9mIHJlc3AucmVzdWx0LnRyYW5zZmVycykge1xuICAgICAgICBsZXQgdHggPSBNb25lcm9XYWxsZXRScGMuY29udmVydFJwY1R4V2FsbGV0V2l0aE91dHB1dChycGNPdXRwdXQpO1xuICAgICAgICBNb25lcm9XYWxsZXRScGMubWVyZ2VUeCh0eCwgdHhNYXAsIGJsb2NrTWFwKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gc29ydCB0eHMgYnkgYmxvY2sgaGVpZ2h0XG4gICAgbGV0IHR4czogTW9uZXJvVHhXYWxsZXRbXSA9IE9iamVjdC52YWx1ZXModHhNYXApO1xuICAgIHR4cy5zb3J0KE1vbmVyb1dhbGxldFJwYy5jb21wYXJlVHhzQnlIZWlnaHQpO1xuICAgIFxuICAgIC8vIGNvbGxlY3QgcXVlcmllZCBvdXRwdXRzXG4gICAgbGV0IG91dHB1dHMgPSBbXTtcbiAgICBmb3IgKGxldCB0eCBvZiB0eHMpIHtcbiAgICAgIFxuICAgICAgLy8gc29ydCBvdXRwdXRzXG4gICAgICBpZiAodHguZ2V0T3V0cHV0cygpICE9PSB1bmRlZmluZWQpIHR4LmdldE91dHB1dHMoKS5zb3J0KE1vbmVyb1dhbGxldFJwYy5jb21wYXJlT3V0cHV0cyk7XG4gICAgICBcbiAgICAgIC8vIGNvbGxlY3QgcXVlcmllZCBvdXRwdXRzLCBlcmFzZSBpZiBleGNsdWRlZFxuICAgICAgZm9yIChsZXQgb3V0cHV0IG9mIHR4LmZpbHRlck91dHB1dHMocXVlcnkpKSBvdXRwdXRzLnB1c2gob3V0cHV0KTtcbiAgICAgIFxuICAgICAgLy8gcmVtb3ZlIGV4Y2x1ZGVkIHR4cyBmcm9tIGJsb2NrXG4gICAgICBpZiAodHguZ2V0T3V0cHV0cygpID09PSB1bmRlZmluZWQgJiYgdHguZ2V0QmxvY2soKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHR4LmdldEJsb2NrKCkuZ2V0VHhzKCkuc3BsaWNlKHR4LmdldEJsb2NrKCkuZ2V0VHhzKCkuaW5kZXhPZih0eCksIDEpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gb3V0cHV0cztcbiAgfVxuICBcbiAgLyoqXG4gICAqIENvbW1vbiBtZXRob2QgdG8gZ2V0IGtleSBpbWFnZXMuXG4gICAqIFxuICAgKiBAcGFyYW0gYWxsIC0gcGVjaWZpZXMgdG8gZ2V0IGFsbCB4b3Igb25seSBuZXcgaW1hZ2VzIGZyb20gbGFzdCBpbXBvcnRcbiAgICogQHJldHVybiB7TW9uZXJvS2V5SW1hZ2VbXX0gYXJlIHRoZSBrZXkgaW1hZ2VzXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgcnBjRXhwb3J0S2V5SW1hZ2VzKGFsbCkge1xuICAgIGxldCByZXNwID0gYXdhaXQgdGhpcy5jb25maWcuZ2V0U2VydmVyKCkuc2VuZEpzb25SZXF1ZXN0KFwiZXhwb3J0X2tleV9pbWFnZXNcIiwge2FsbDogYWxsfSk7XG4gICAgaWYgKCFyZXNwLnJlc3VsdC5zaWduZWRfa2V5X2ltYWdlcykgcmV0dXJuIFtdO1xuICAgIHJldHVybiByZXNwLnJlc3VsdC5zaWduZWRfa2V5X2ltYWdlcy5tYXAocnBjSW1hZ2UgPT4gbmV3IE1vbmVyb0tleUltYWdlKHJwY0ltYWdlLmtleV9pbWFnZSwgcnBjSW1hZ2Uuc2lnbmF0dXJlKSk7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBhc3luYyBycGNTd2VlcEFjY291bnQoY29uZmlnOiBNb25lcm9UeENvbmZpZykge1xuICAgIFxuICAgIC8vIHZhbGlkYXRlIGNvbmZpZ1xuICAgIGlmIChjb25maWcgPT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTXVzdCBwcm92aWRlIHN3ZWVwIGNvbmZpZ1wiKTtcbiAgICBpZiAoY29uZmlnLmdldEFjY291bnRJbmRleCgpID09PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk11c3QgcHJvdmlkZSBhbiBhY2NvdW50IGluZGV4IHRvIHN3ZWVwIGZyb21cIik7XG4gICAgaWYgKGNvbmZpZy5nZXREZXN0aW5hdGlvbnMoKSA9PT0gdW5kZWZpbmVkIHx8IGNvbmZpZy5nZXREZXN0aW5hdGlvbnMoKS5sZW5ndGggIT0gMSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiTXVzdCBwcm92aWRlIGV4YWN0bHkgb25lIGRlc3RpbmF0aW9uIHRvIHN3ZWVwIHRvXCIpO1xuICAgIGlmIChjb25maWcuZ2V0RGVzdGluYXRpb25zKClbMF0uZ2V0QWRkcmVzcygpID09PSB1bmRlZmluZWQpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk11c3QgcHJvdmlkZSBkZXN0aW5hdGlvbiBhZGRyZXNzIHRvIHN3ZWVwIHRvXCIpO1xuICAgIGlmIChjb25maWcuZ2V0RGVzdGluYXRpb25zKClbMF0uZ2V0QW1vdW50KCkgIT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ2Fubm90IHNwZWNpZnkgYW1vdW50IGluIHN3ZWVwIGNvbmZpZ1wiKTtcbiAgICBpZiAoY29uZmlnLmdldEtleUltYWdlKCkgIT09IHVuZGVmaW5lZCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiS2V5IGltYWdlIGRlZmluZWQ7IHVzZSBzd2VlcE91dHB1dCgpIHRvIHN3ZWVwIGFuIG91dHB1dCBieSBpdHMga2V5IGltYWdlXCIpO1xuICAgIGlmIChjb25maWcuZ2V0U3ViYWRkcmVzc0luZGljZXMoKSAhPT0gdW5kZWZpbmVkICYmIGNvbmZpZy5nZXRTdWJhZGRyZXNzSW5kaWNlcygpLmxlbmd0aCA9PT0gMCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiRW1wdHkgbGlzdCBnaXZlbiBmb3Igc3ViYWRkcmVzc2VzIGluZGljZXMgdG8gc3dlZXBcIik7XG4gICAgaWYgKGNvbmZpZy5nZXRTd2VlcEVhY2hTdWJhZGRyZXNzKCkpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBzd2VlcCBlYWNoIHN1YmFkZHJlc3Mgd2l0aCBSUEMgYHN3ZWVwX2FsbGBcIik7XG4gICAgaWYgKGNvbmZpZy5nZXRTdWJ0cmFjdEZlZUZyb20oKSAhPT0gdW5kZWZpbmVkICYmIGNvbmZpZy5nZXRTdWJ0cmFjdEZlZUZyb20oKS5sZW5ndGggPiAwKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTd2VlcGluZyBvdXRwdXQgZG9lcyBub3Qgc3VwcG9ydCBzdWJ0cmFjdGluZyBmZWVzIGZyb20gZGVzdGluYXRpb25zXCIpO1xuICAgIFxuICAgIC8vIHN3ZWVwIGZyb20gYWxsIHN1YmFkZHJlc3NlcyBpZiBub3Qgb3RoZXJ3aXNlIGRlZmluZWRcbiAgICBpZiAoY29uZmlnLmdldFN1YmFkZHJlc3NJbmRpY2VzKCkgPT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uZmlnLnNldFN1YmFkZHJlc3NJbmRpY2VzKFtdKTtcbiAgICAgIGZvciAobGV0IHN1YmFkZHJlc3Mgb2YgYXdhaXQgdGhpcy5nZXRTdWJhZGRyZXNzZXMoY29uZmlnLmdldEFjY291bnRJbmRleCgpKSkge1xuICAgICAgICBjb25maWcuZ2V0U3ViYWRkcmVzc0luZGljZXMoKS5wdXNoKHN1YmFkZHJlc3MuZ2V0SW5kZXgoKSk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChjb25maWcuZ2V0U3ViYWRkcmVzc0luZGljZXMoKS5sZW5ndGggPT09IDApIHRocm93IG5ldyBNb25lcm9FcnJvcihcIk5vIHN1YmFkZHJlc3NlcyB0byBzd2VlcCBmcm9tXCIpO1xuICAgIFxuICAgIC8vIGNvbW1vbiBjb25maWcgcGFyYW1zXG4gICAgbGV0IHBhcmFtczogYW55ID0ge307XG4gICAgbGV0IHJlbGF5ID0gY29uZmlnLmdldFJlbGF5KCkgPT09IHRydWU7XG4gICAgcGFyYW1zLmFjY291bnRfaW5kZXggPSBjb25maWcuZ2V0QWNjb3VudEluZGV4KCk7XG4gICAgcGFyYW1zLnN1YmFkZHJfaW5kaWNlcyA9IGNvbmZpZy5nZXRTdWJhZGRyZXNzSW5kaWNlcygpO1xuICAgIHBhcmFtcy5hZGRyZXNzID0gY29uZmlnLmdldERlc3RpbmF0aW9ucygpWzBdLmdldEFkZHJlc3MoKTtcbiAgICBhc3NlcnQoY29uZmlnLmdldFByaW9yaXR5KCkgPT09IHVuZGVmaW5lZCB8fCBjb25maWcuZ2V0UHJpb3JpdHkoKSA+PSAwICYmIGNvbmZpZy5nZXRQcmlvcml0eSgpIDw9IDMpO1xuICAgIHBhcmFtcy5wcmlvcml0eSA9IGNvbmZpZy5nZXRQcmlvcml0eSgpO1xuICAgIHBhcmFtcy5wYXltZW50X2lkID0gY29uZmlnLmdldFBheW1lbnRJZCgpO1xuICAgIHBhcmFtcy5kb19ub3RfcmVsYXkgPSAhcmVsYXk7XG4gICAgcGFyYW1zLmJlbG93X2Ftb3VudCA9IGNvbmZpZy5nZXRCZWxvd0Ftb3VudCgpO1xuICAgIHBhcmFtcy5nZXRfdHhfa2V5cyA9IHRydWU7XG4gICAgcGFyYW1zLmdldF90eF9oZXggPSB0cnVlO1xuICAgIHBhcmFtcy5nZXRfdHhfbWV0YWRhdGEgPSB0cnVlO1xuICAgIFxuICAgIC8vIGludm9rZSB3YWxsZXQgcnBjIGBzd2VlcF9hbGxgXG4gICAgbGV0IHJlc3AgPSBhd2FpdCB0aGlzLmNvbmZpZy5nZXRTZXJ2ZXIoKS5zZW5kSnNvblJlcXVlc3QoXCJzd2VlcF9hbGxcIiwgcGFyYW1zKTtcbiAgICBsZXQgcmVzdWx0ID0gcmVzcC5yZXN1bHQ7XG4gICAgXG4gICAgLy8gaW5pdGlhbGl6ZSB0eHMgZnJvbSByZXNwb25zZVxuICAgIGxldCB0eFNldCA9IE1vbmVyb1dhbGxldFJwYy5jb252ZXJ0UnBjU2VudFR4c1RvVHhTZXQocmVzdWx0LCB1bmRlZmluZWQsIGNvbmZpZyk7XG4gICAgXG4gICAgLy8gaW5pdGlhbGl6ZSByZW1haW5pbmcga25vd24gZmllbGRzXG4gICAgZm9yIChsZXQgdHggb2YgdHhTZXQuZ2V0VHhzKCkpIHtcbiAgICAgIHR4LnNldElzTG9ja2VkKHRydWUpO1xuICAgICAgdHguc2V0SXNDb25maXJtZWQoZmFsc2UpO1xuICAgICAgdHguc2V0TnVtQ29uZmlybWF0aW9ucygwKTtcbiAgICAgIHR4LnNldFJlbGF5KHJlbGF5KTtcbiAgICAgIHR4LnNldEluVHhQb29sKHJlbGF5KTtcbiAgICAgIHR4LnNldElzUmVsYXllZChyZWxheSk7XG4gICAgICB0eC5zZXRJc01pbmVyVHgoZmFsc2UpO1xuICAgICAgdHguc2V0SXNGYWlsZWQoZmFsc2UpO1xuICAgICAgbGV0IHRyYW5zZmVyID0gdHguZ2V0T3V0Z29pbmdUcmFuc2ZlcigpO1xuICAgICAgdHJhbnNmZXIuc2V0QWNjb3VudEluZGV4KGNvbmZpZy5nZXRBY2NvdW50SW5kZXgoKSk7XG4gICAgICBpZiAoY29uZmlnLmdldFN1YmFkZHJlc3NJbmRpY2VzKCkubGVuZ3RoID09PSAxKSB0cmFuc2Zlci5zZXRTdWJhZGRyZXNzSW5kaWNlcyhjb25maWcuZ2V0U3ViYWRkcmVzc0luZGljZXMoKSk7XG4gICAgICBsZXQgZGVzdGluYXRpb24gPSBuZXcgTW9uZXJvRGVzdGluYXRpb24oY29uZmlnLmdldERlc3RpbmF0aW9ucygpWzBdLmdldEFkZHJlc3MoKSwgQmlnSW50KHRyYW5zZmVyLmdldEFtb3VudCgpKSk7XG4gICAgICB0cmFuc2Zlci5zZXREZXN0aW5hdGlvbnMoW2Rlc3RpbmF0aW9uXSk7XG4gICAgICB0eC5zZXRPdXRnb2luZ1RyYW5zZmVyKHRyYW5zZmVyKTtcbiAgICAgIHR4LnNldFBheW1lbnRJZChjb25maWcuZ2V0UGF5bWVudElkKCkpO1xuICAgICAgaWYgKHR4LmdldFVubG9ja1RpbWUoKSA9PT0gdW5kZWZpbmVkKSB0eC5zZXRVbmxvY2tUaW1lKDBuKTtcbiAgICAgIGlmICh0eC5nZXRSZWxheSgpKSB7XG4gICAgICAgIGlmICh0eC5nZXRMYXN0UmVsYXllZFRpbWVzdGFtcCgpID09PSB1bmRlZmluZWQpIHR4LnNldExhc3RSZWxheWVkVGltZXN0YW1wKCtuZXcgRGF0ZSgpLmdldFRpbWUoKSk7ICAvLyBUT0RPIChtb25lcm8td2FsbGV0LXJwYyk6IHByb3ZpZGUgdGltZXN0YW1wIG9uIHJlc3BvbnNlOyB1bmNvbmZpcm1lZCB0aW1lc3RhbXBzIHZhcnlcbiAgICAgICAgaWYgKHR4LmdldElzRG91YmxlU3BlbmRTZWVuKCkgPT09IHVuZGVmaW5lZCkgdHguc2V0SXNEb3VibGVTcGVuZFNlZW4oZmFsc2UpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHhTZXQuZ2V0VHhzKCk7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCByZWZyZXNoTGlzdGVuaW5nKCkge1xuICAgIGlmICh0aGlzLndhbGxldFBvbGxlciA9PSB1bmRlZmluZWQgJiYgdGhpcy5saXN0ZW5lcnMubGVuZ3RoKSB0aGlzLndhbGxldFBvbGxlciA9IG5ldyBXYWxsZXRQb2xsZXIodGhpcyk7XG4gICAgaWYgKHRoaXMud2FsbGV0UG9sbGVyICE9PSB1bmRlZmluZWQpIHRoaXMud2FsbGV0UG9sbGVyLnNldElzUG9sbGluZyh0aGlzLmxpc3RlbmVycy5sZW5ndGggPiAwKTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFBvbGwgaWYgbGlzdGVuaW5nLlxuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIHBvbGwoKSB7XG4gICAgaWYgKHRoaXMud2FsbGV0UG9sbGVyICE9PSB1bmRlZmluZWQgJiYgdGhpcy53YWxsZXRQb2xsZXIuaXNQb2xsaW5nKSBhd2FpdCB0aGlzLndhbGxldFBvbGxlci5wb2xsKCk7XG4gIH1cbiAgXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gUFJJVkFURSBTVEFUSUMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIG5vcm1hbGl6ZUNvbmZpZyh1cmlPckNvbmZpZzogc3RyaW5nIHwgUGFydGlhbDxNb25lcm9ScGNDb25uZWN0aW9uPiB8IFBhcnRpYWw8TW9uZXJvV2FsbGV0Q29uZmlnPiB8IHN0cmluZ1tdLCB1c2VybmFtZT86IHN0cmluZywgcGFzc3dvcmQ/OiBzdHJpbmcpOiBNb25lcm9XYWxsZXRDb25maWcge1xuICAgIGxldCBjb25maWc6IHVuZGVmaW5lZCB8IFBhcnRpYWw8TW9uZXJvV2FsbGV0Q29uZmlnPiA9IHVuZGVmaW5lZDtcbiAgICBpZiAodHlwZW9mIHVyaU9yQ29uZmlnID09PSBcInN0cmluZ1wiIHx8ICh1cmlPckNvbmZpZyBhcyBQYXJ0aWFsPE1vbmVyb1JwY0Nvbm5lY3Rpb24+KS51cmkpIGNvbmZpZyA9IG5ldyBNb25lcm9XYWxsZXRDb25maWcoe3NlcnZlcjogbmV3IE1vbmVyb1JwY0Nvbm5lY3Rpb24odXJpT3JDb25maWcgYXMgc3RyaW5nIHwgUGFydGlhbDxNb25lcm9ScGNDb25uZWN0aW9uPiwgdXNlcm5hbWUsIHBhc3N3b3JkKX0pO1xuICAgIGVsc2UgaWYgKEdlblV0aWxzLmlzQXJyYXkodXJpT3JDb25maWcpKSBjb25maWcgPSBuZXcgTW9uZXJvV2FsbGV0Q29uZmlnKHtjbWQ6IHVyaU9yQ29uZmlnIGFzIHN0cmluZ1tdfSk7XG4gICAgZWxzZSBjb25maWcgPSBuZXcgTW9uZXJvV2FsbGV0Q29uZmlnKHVyaU9yQ29uZmlnIGFzIFBhcnRpYWw8TW9uZXJvV2FsbGV0Q29uZmlnPik7XG4gICAgaWYgKGNvbmZpZy5wcm94eVRvV29ya2VyID09PSB1bmRlZmluZWQpIGNvbmZpZy5wcm94eVRvV29ya2VyID0gdHJ1ZTtcbiAgICByZXR1cm4gY29uZmlnIGFzIE1vbmVyb1dhbGxldENvbmZpZztcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJlbW92ZSBjcml0ZXJpYSB3aGljaCByZXF1aXJlcyBsb29raW5nIHVwIG90aGVyIHRyYW5zZmVycy9vdXRwdXRzIHRvXG4gICAqIGZ1bGZpbGwgcXVlcnkuXG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb1R4UXVlcnl9IHF1ZXJ5IC0gdGhlIHF1ZXJ5IHRvIGRlY29udGV4dHVhbGl6ZVxuICAgKiBAcmV0dXJuIHtNb25lcm9UeFF1ZXJ5fSBhIHJlZmVyZW5jZSB0byB0aGUgcXVlcnkgZm9yIGNvbnZlbmllbmNlXG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIGRlY29udGV4dHVhbGl6ZShxdWVyeSkge1xuICAgIHF1ZXJ5LnNldElzSW5jb21pbmcodW5kZWZpbmVkKTtcbiAgICBxdWVyeS5zZXRJc091dGdvaW5nKHVuZGVmaW5lZCk7XG4gICAgcXVlcnkuc2V0VHJhbnNmZXJRdWVyeSh1bmRlZmluZWQpO1xuICAgIHF1ZXJ5LnNldElucHV0UXVlcnkodW5kZWZpbmVkKTtcbiAgICBxdWVyeS5zZXRPdXRwdXRRdWVyeSh1bmRlZmluZWQpO1xuICAgIHJldHVybiBxdWVyeTtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIHN0YXRpYyBpc0NvbnRleHR1YWwocXVlcnkpIHtcbiAgICBpZiAoIXF1ZXJ5KSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKCFxdWVyeS5nZXRUeFF1ZXJ5KCkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAocXVlcnkuZ2V0VHhRdWVyeSgpLmdldElzSW5jb21pbmcoKSAhPT0gdW5kZWZpbmVkKSByZXR1cm4gdHJ1ZTsgLy8gcmVxdWlyZXMgZ2V0dGluZyBvdGhlciB0cmFuc2ZlcnNcbiAgICBpZiAocXVlcnkuZ2V0VHhRdWVyeSgpLmdldElzT3V0Z29pbmcoKSAhPT0gdW5kZWZpbmVkKSByZXR1cm4gdHJ1ZTtcbiAgICBpZiAocXVlcnkgaW5zdGFuY2VvZiBNb25lcm9UcmFuc2ZlclF1ZXJ5KSB7XG4gICAgICBpZiAocXVlcnkuZ2V0VHhRdWVyeSgpLmdldE91dHB1dFF1ZXJ5KCkgIT09IHVuZGVmaW5lZCkgcmV0dXJuIHRydWU7IC8vIHJlcXVpcmVzIGdldHRpbmcgb3RoZXIgb3V0cHV0c1xuICAgIH0gZWxzZSBpZiAocXVlcnkgaW5zdGFuY2VvZiBNb25lcm9PdXRwdXRRdWVyeSkge1xuICAgICAgaWYgKHF1ZXJ5LmdldFR4UXVlcnkoKS5nZXRUcmFuc2ZlclF1ZXJ5KCkgIT09IHVuZGVmaW5lZCkgcmV0dXJuIHRydWU7IC8vIHJlcXVpcmVzIGdldHRpbmcgb3RoZXIgdHJhbnNmZXJzXG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcInF1ZXJ5IG11c3QgYmUgdHggb3IgdHJhbnNmZXIgcXVlcnlcIik7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIHN0YXRpYyBjb252ZXJ0UnBjQWNjb3VudChycGNBY2NvdW50KSB7XG4gICAgbGV0IGFjY291bnQgPSBuZXcgTW9uZXJvQWNjb3VudCgpO1xuICAgIGZvciAobGV0IGtleSBvZiBPYmplY3Qua2V5cyhycGNBY2NvdW50KSkge1xuICAgICAgbGV0IHZhbCA9IHJwY0FjY291bnRba2V5XTtcbiAgICAgIGlmIChrZXkgPT09IFwiYWNjb3VudF9pbmRleFwiKSBhY2NvdW50LnNldEluZGV4KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYmFsYW5jZVwiKSBhY2NvdW50LnNldEJhbGFuY2UoQmlnSW50KHZhbCkpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInVubG9ja2VkX2JhbGFuY2VcIikgYWNjb3VudC5zZXRVbmxvY2tlZEJhbGFuY2UoQmlnSW50KHZhbCkpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImJhc2VfYWRkcmVzc1wiKSBhY2NvdW50LnNldFByaW1hcnlBZGRyZXNzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidGFnXCIpIGFjY291bnQuc2V0VGFnKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwibGFiZWxcIikgeyB9IC8vIGxhYmVsIGJlbG9uZ3MgdG8gZmlyc3Qgc3ViYWRkcmVzc1xuICAgICAgZWxzZSBjb25zb2xlLmxvZyhcIldBUk5JTkc6IGlnbm9yaW5nIHVuZXhwZWN0ZWQgYWNjb3VudCBmaWVsZDogXCIgKyBrZXkgKyBcIjogXCIgKyB2YWwpO1xuICAgIH1cbiAgICBpZiAoXCJcIiA9PT0gYWNjb3VudC5nZXRUYWcoKSkgYWNjb3VudC5zZXRUYWcodW5kZWZpbmVkKTtcbiAgICByZXR1cm4gYWNjb3VudDtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIHN0YXRpYyBjb252ZXJ0UnBjU3ViYWRkcmVzcyhycGNTdWJhZGRyZXNzKSB7XG4gICAgbGV0IHN1YmFkZHJlc3MgPSBuZXcgTW9uZXJvU3ViYWRkcmVzcygpO1xuICAgIGZvciAobGV0IGtleSBvZiBPYmplY3Qua2V5cyhycGNTdWJhZGRyZXNzKSkge1xuICAgICAgbGV0IHZhbCA9IHJwY1N1YmFkZHJlc3Nba2V5XTtcbiAgICAgIGlmIChrZXkgPT09IFwiYWNjb3VudF9pbmRleFwiKSBzdWJhZGRyZXNzLnNldEFjY291bnRJbmRleCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImFkZHJlc3NfaW5kZXhcIikgc3ViYWRkcmVzcy5zZXRJbmRleCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImFkZHJlc3NcIikgc3ViYWRkcmVzcy5zZXRBZGRyZXNzKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYmFsYW5jZVwiKSBzdWJhZGRyZXNzLnNldEJhbGFuY2UoQmlnSW50KHZhbCkpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInVubG9ja2VkX2JhbGFuY2VcIikgc3ViYWRkcmVzcy5zZXRVbmxvY2tlZEJhbGFuY2UoQmlnSW50KHZhbCkpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIm51bV91bnNwZW50X291dHB1dHNcIikgc3ViYWRkcmVzcy5zZXROdW1VbnNwZW50T3V0cHV0cyh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImxhYmVsXCIpIHsgaWYgKHZhbCkgc3ViYWRkcmVzcy5zZXRMYWJlbCh2YWwpOyB9XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidXNlZFwiKSBzdWJhZGRyZXNzLnNldElzVXNlZCh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImJsb2Nrc190b191bmxvY2tcIikgc3ViYWRkcmVzcy5zZXROdW1CbG9ja3NUb1VubG9jayh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09IFwidGltZV90b191bmxvY2tcIikge30gIC8vIGlnbm9yaW5nXG4gICAgICBlbHNlIGNvbnNvbGUubG9nKFwiV0FSTklORzogaWdub3JpbmcgdW5leHBlY3RlZCBzdWJhZGRyZXNzIGZpZWxkOiBcIiArIGtleSArIFwiOiBcIiArIHZhbCk7XG4gICAgfVxuICAgIHJldHVybiBzdWJhZGRyZXNzO1xuICB9XG4gIFxuICAvKipcbiAgICogSW5pdGlhbGl6ZXMgYSBzZW50IHRyYW5zYWN0aW9uLlxuICAgKiBcbiAgICogVE9ETzogcmVtb3ZlIGNvcHlEZXN0aW5hdGlvbnMgYWZ0ZXIgPjE4LjMuMSB3aGVuIHN1YnRyYWN0RmVlRnJvbSBmdWxseSBzdXBwb3J0ZWRcbiAgICogXG4gICAqIEBwYXJhbSB7TW9uZXJvVHhDb25maWd9IGNvbmZpZyAtIHNlbmQgY29uZmlnXG4gICAqIEBwYXJhbSB7TW9uZXJvVHhXYWxsZXR9IFt0eF0gLSBleGlzdGluZyB0cmFuc2FjdGlvbiB0byBpbml0aWFsaXplIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtib29sZWFufSBjb3B5RGVzdGluYXRpb25zIC0gY29waWVzIGNvbmZpZyBkZXN0aW5hdGlvbnMgaWYgdHJ1ZVxuICAgKiBAcmV0dXJuIHtNb25lcm9UeFdhbGxldH0gaXMgdGhlIGluaXRpYWxpemVkIHNlbmQgdHhcbiAgICovXG4gIHByb3RlY3RlZCBzdGF0aWMgaW5pdFNlbnRUeFdhbGxldChjb25maWc6IFBhcnRpYWw8TW9uZXJvVHhDb25maWc+LCB0eCwgY29weURlc3RpbmF0aW9ucykge1xuICAgIGlmICghdHgpIHR4ID0gbmV3IE1vbmVyb1R4V2FsbGV0KCk7XG4gICAgbGV0IHJlbGF5ID0gY29uZmlnLmdldFJlbGF5KCkgPT09IHRydWU7XG4gICAgdHguc2V0SXNPdXRnb2luZyh0cnVlKTtcbiAgICB0eC5zZXRJc0NvbmZpcm1lZChmYWxzZSk7XG4gICAgdHguc2V0TnVtQ29uZmlybWF0aW9ucygwKTtcbiAgICB0eC5zZXRJblR4UG9vbChyZWxheSk7XG4gICAgdHguc2V0UmVsYXkocmVsYXkpO1xuICAgIHR4LnNldElzUmVsYXllZChyZWxheSk7XG4gICAgdHguc2V0SXNNaW5lclR4KGZhbHNlKTtcbiAgICB0eC5zZXRJc0ZhaWxlZChmYWxzZSk7XG4gICAgdHguc2V0SXNMb2NrZWQodHJ1ZSk7XG4gICAgdHguc2V0UmluZ1NpemUoTW9uZXJvVXRpbHMuUklOR19TSVpFKTtcbiAgICBsZXQgdHJhbnNmZXIgPSBuZXcgTW9uZXJvT3V0Z29pbmdUcmFuc2ZlcigpO1xuICAgIHRyYW5zZmVyLnNldFR4KHR4KTtcbiAgICBpZiAoY29uZmlnLmdldFN1YmFkZHJlc3NJbmRpY2VzKCkgJiYgY29uZmlnLmdldFN1YmFkZHJlc3NJbmRpY2VzKCkubGVuZ3RoID09PSAxKSB0cmFuc2Zlci5zZXRTdWJhZGRyZXNzSW5kaWNlcyhjb25maWcuZ2V0U3ViYWRkcmVzc0luZGljZXMoKS5zbGljZSgwKSk7IC8vIHdlIGtub3cgc3JjIHN1YmFkZHJlc3MgaW5kaWNlcyBpZmYgY29uZmlnIHNwZWNpZmllcyAxXG4gICAgaWYgKGNvcHlEZXN0aW5hdGlvbnMpIHtcbiAgICAgIGxldCBkZXN0Q29waWVzID0gW107XG4gICAgICBmb3IgKGxldCBkZXN0IG9mIGNvbmZpZy5nZXREZXN0aW5hdGlvbnMoKSkgZGVzdENvcGllcy5wdXNoKGRlc3QuY29weSgpKTtcbiAgICAgIHRyYW5zZmVyLnNldERlc3RpbmF0aW9ucyhkZXN0Q29waWVzKTtcbiAgICB9XG4gICAgdHguc2V0T3V0Z29pbmdUcmFuc2Zlcih0cmFuc2Zlcik7XG4gICAgdHguc2V0UGF5bWVudElkKGNvbmZpZy5nZXRQYXltZW50SWQoKSk7XG4gICAgaWYgKHR4LmdldFVubG9ja1RpbWUoKSA9PT0gdW5kZWZpbmVkKSB0eC5zZXRVbmxvY2tUaW1lKDBuKTtcbiAgICBpZiAoY29uZmlnLmdldFJlbGF5KCkpIHtcbiAgICAgIGlmICh0eC5nZXRMYXN0UmVsYXllZFRpbWVzdGFtcCgpID09PSB1bmRlZmluZWQpIHR4LnNldExhc3RSZWxheWVkVGltZXN0YW1wKCtuZXcgRGF0ZSgpLmdldFRpbWUoKSk7ICAvLyBUT0RPIChtb25lcm8td2FsbGV0LXJwYyk6IHByb3ZpZGUgdGltZXN0YW1wIG9uIHJlc3BvbnNlOyB1bmNvbmZpcm1lZCB0aW1lc3RhbXBzIHZhcnlcbiAgICAgIGlmICh0eC5nZXRJc0RvdWJsZVNwZW5kU2VlbigpID09PSB1bmRlZmluZWQpIHR4LnNldElzRG91YmxlU3BlbmRTZWVuKGZhbHNlKTtcbiAgICB9XG4gICAgcmV0dXJuIHR4O1xuICB9XG4gIFxuICAvKipcbiAgICogSW5pdGlhbGl6ZXMgYSB0eCBzZXQgZnJvbSBhIFJQQyBtYXAgZXhjbHVkaW5nIHR4cy5cbiAgICogXG4gICAqIEBwYXJhbSBycGNNYXAgLSBtYXAgdG8gaW5pdGlhbGl6ZSB0aGUgdHggc2V0IGZyb21cbiAgICogQHJldHVybiBNb25lcm9UeFNldCAtIGluaXRpYWxpemVkIHR4IHNldFxuICAgKiBAcmV0dXJuIHRoZSByZXN1bHRpbmcgdHggc2V0XG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNUeFNldChycGNNYXApIHtcbiAgICBsZXQgdHhTZXQgPSBuZXcgTW9uZXJvVHhTZXQoKTtcbiAgICB0eFNldC5zZXRNdWx0aXNpZ1R4SGV4KHJwY01hcC5tdWx0aXNpZ190eHNldCk7XG4gICAgdHhTZXQuc2V0VW5zaWduZWRUeEhleChycGNNYXAudW5zaWduZWRfdHhzZXQpO1xuICAgIHR4U2V0LnNldFNpZ25lZFR4SGV4KHJwY01hcC5zaWduZWRfdHhzZXQpO1xuICAgIGlmICh0eFNldC5nZXRNdWx0aXNpZ1R4SGV4KCkgIT09IHVuZGVmaW5lZCAmJiB0eFNldC5nZXRNdWx0aXNpZ1R4SGV4KCkubGVuZ3RoID09PSAwKSB0eFNldC5zZXRNdWx0aXNpZ1R4SGV4KHVuZGVmaW5lZCk7XG4gICAgaWYgKHR4U2V0LmdldFVuc2lnbmVkVHhIZXgoKSAhPT0gdW5kZWZpbmVkICYmIHR4U2V0LmdldFVuc2lnbmVkVHhIZXgoKS5sZW5ndGggPT09IDApIHR4U2V0LnNldFVuc2lnbmVkVHhIZXgodW5kZWZpbmVkKTtcbiAgICBpZiAodHhTZXQuZ2V0U2lnbmVkVHhIZXgoKSAhPT0gdW5kZWZpbmVkICYmIHR4U2V0LmdldFNpZ25lZFR4SGV4KCkubGVuZ3RoID09PSAwKSB0eFNldC5zZXRTaWduZWRUeEhleCh1bmRlZmluZWQpO1xuICAgIHJldHVybiB0eFNldDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEluaXRpYWxpemVzIGEgTW9uZXJvVHhTZXQgZnJvbSBhIGxpc3Qgb2YgcnBjIHR4cy5cbiAgICogXG4gICAqIEBwYXJhbSBycGNUeHMgLSBycGMgdHhzIHRvIGluaXRpYWxpemUgdGhlIHNldCBmcm9tXG4gICAqIEBwYXJhbSB0eHMgLSBleGlzdGluZyB0eHMgdG8gZnVydGhlciBpbml0aWFsaXplIChvcHRpb25hbClcbiAgICogQHBhcmFtIGNvbmZpZyAtIHR4IGNvbmZpZ1xuICAgKiBAcmV0dXJuIHRoZSBjb252ZXJ0ZWQgdHggc2V0XG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNTZW50VHhzVG9UeFNldChycGNUeHM6IGFueSwgdHhzPzogYW55LCBjb25maWc/OiBhbnkpIHtcbiAgICBcbiAgICAvLyBidWlsZCBzaGFyZWQgdHggc2V0XG4gICAgbGV0IHR4U2V0ID0gTW9uZXJvV2FsbGV0UnBjLmNvbnZlcnRScGNUeFNldChycGNUeHMpO1xuXG4gICAgLy8gZ2V0IG51bWJlciBvZiB0eHNcbiAgICBsZXQgbnVtVHhzID0gcnBjVHhzLmZlZV9saXN0ID8gcnBjVHhzLmZlZV9saXN0Lmxlbmd0aCA6IHJwY1R4cy50eF9oYXNoX2xpc3QgPyBycGNUeHMudHhfaGFzaF9saXN0Lmxlbmd0aCA6IDA7XG4gICAgXG4gICAgLy8gZG9uZSBpZiBycGMgcmVzcG9uc2UgY29udGFpbnMgbm8gdHhzXG4gICAgaWYgKG51bVR4cyA9PT0gMCkge1xuICAgICAgYXNzZXJ0LmVxdWFsKHR4cywgdW5kZWZpbmVkKTtcbiAgICAgIHJldHVybiB0eFNldDtcbiAgICB9XG4gICAgXG4gICAgLy8gaW5pdGlhbGl6ZSB0eHMgaWYgbm9uZSBnaXZlblxuICAgIGlmICh0eHMpIHR4U2V0LnNldFR4cyh0eHMpO1xuICAgIGVsc2Uge1xuICAgICAgdHhzID0gW107XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG51bVR4czsgaSsrKSB0eHMucHVzaChuZXcgTW9uZXJvVHhXYWxsZXQoKSk7XG4gICAgfVxuICAgIGZvciAobGV0IHR4IG9mIHR4cykge1xuICAgICAgdHguc2V0VHhTZXQodHhTZXQpO1xuICAgICAgdHguc2V0SXNPdXRnb2luZyh0cnVlKTtcbiAgICB9XG4gICAgdHhTZXQuc2V0VHhzKHR4cyk7XG4gICAgXG4gICAgLy8gaW5pdGlhbGl6ZSB0eHMgZnJvbSBycGMgbGlzdHNcbiAgICBmb3IgKGxldCBrZXkgb2YgT2JqZWN0LmtleXMocnBjVHhzKSkge1xuICAgICAgbGV0IHZhbCA9IHJwY1R4c1trZXldO1xuICAgICAgaWYgKGtleSA9PT0gXCJ0eF9oYXNoX2xpc3RcIikgZm9yIChsZXQgaSA9IDA7IGkgPCB2YWwubGVuZ3RoOyBpKyspIHR4c1tpXS5zZXRIYXNoKHZhbFtpXSk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidHhfa2V5X2xpc3RcIikgZm9yIChsZXQgaSA9IDA7IGkgPCB2YWwubGVuZ3RoOyBpKyspIHR4c1tpXS5zZXRLZXkodmFsW2ldKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0eF9ibG9iX2xpc3RcIikgZm9yIChsZXQgaSA9IDA7IGkgPCB2YWwubGVuZ3RoOyBpKyspIHR4c1tpXS5zZXRGdWxsSGV4KHZhbFtpXSk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidHhfbWV0YWRhdGFfbGlzdFwiKSBmb3IgKGxldCBpID0gMDsgaSA8IHZhbC5sZW5ndGg7IGkrKykgdHhzW2ldLnNldE1ldGFkYXRhKHZhbFtpXSk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiZmVlX2xpc3RcIikgZm9yIChsZXQgaSA9IDA7IGkgPCB2YWwubGVuZ3RoOyBpKyspIHR4c1tpXS5zZXRGZWUoQmlnSW50KHZhbFtpXSkpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIndlaWdodF9saXN0XCIpIGZvciAobGV0IGkgPSAwOyBpIDwgdmFsLmxlbmd0aDsgaSsrKSB0eHNbaV0uc2V0V2VpZ2h0KHZhbFtpXSk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYW1vdW50X2xpc3RcIikge1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHZhbC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIGlmICh0eHNbaV0uZ2V0T3V0Z29pbmdUcmFuc2ZlcigpID09IHVuZGVmaW5lZCkgdHhzW2ldLnNldE91dGdvaW5nVHJhbnNmZXIobmV3IE1vbmVyb091dGdvaW5nVHJhbnNmZXIoKS5zZXRUeCh0eHNbaV0pKTtcbiAgICAgICAgICB0eHNbaV0uZ2V0T3V0Z29pbmdUcmFuc2ZlcigpLnNldEFtb3VudChCaWdJbnQodmFsW2ldKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJtdWx0aXNpZ190eHNldFwiIHx8IGtleSA9PT0gXCJ1bnNpZ25lZF90eHNldFwiIHx8IGtleSA9PT0gXCJzaWduZWRfdHhzZXRcIikge30gLy8gaGFuZGxlZCBlbHNld2hlcmVcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJzcGVudF9rZXlfaW1hZ2VzX2xpc3RcIikge1xuICAgICAgICBsZXQgaW5wdXRLZXlJbWFnZXNMaXN0ID0gdmFsO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGlucHV0S2V5SW1hZ2VzTGlzdC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIEdlblV0aWxzLmFzc2VydFRydWUodHhzW2ldLmdldElucHV0cygpID09PSB1bmRlZmluZWQpO1xuICAgICAgICAgIHR4c1tpXS5zZXRJbnB1dHMoW10pO1xuICAgICAgICAgIGZvciAobGV0IGlucHV0S2V5SW1hZ2Ugb2YgaW5wdXRLZXlJbWFnZXNMaXN0W2ldW1wia2V5X2ltYWdlc1wiXSkge1xuICAgICAgICAgICAgdHhzW2ldLmdldElucHV0cygpLnB1c2gobmV3IE1vbmVyb091dHB1dFdhbGxldCgpLnNldEtleUltYWdlKG5ldyBNb25lcm9LZXlJbWFnZSgpLnNldEhleChpbnB1dEtleUltYWdlKSkuc2V0VHgodHhzW2ldKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYW1vdW50c19ieV9kZXN0X2xpc3RcIikge1xuICAgICAgICBsZXQgYW1vdW50c0J5RGVzdExpc3QgPSB2YWw7XG4gICAgICAgIGxldCBkZXN0aW5hdGlvbklkeCA9IDA7XG4gICAgICAgIGZvciAobGV0IHR4SWR4ID0gMDsgdHhJZHggPCBhbW91bnRzQnlEZXN0TGlzdC5sZW5ndGg7IHR4SWR4KyspIHtcbiAgICAgICAgICBsZXQgYW1vdW50c0J5RGVzdCA9IGFtb3VudHNCeURlc3RMaXN0W3R4SWR4XVtcImFtb3VudHNcIl07XG4gICAgICAgICAgaWYgKHR4c1t0eElkeF0uZ2V0T3V0Z29pbmdUcmFuc2ZlcigpID09PSB1bmRlZmluZWQpIHR4c1t0eElkeF0uc2V0T3V0Z29pbmdUcmFuc2ZlcihuZXcgTW9uZXJvT3V0Z29pbmdUcmFuc2ZlcigpLnNldFR4KHR4c1t0eElkeF0pKTtcbiAgICAgICAgICB0eHNbdHhJZHhdLmdldE91dGdvaW5nVHJhbnNmZXIoKS5zZXREZXN0aW5hdGlvbnMoW10pO1xuICAgICAgICAgIGZvciAobGV0IGFtb3VudCBvZiBhbW91bnRzQnlEZXN0KSB7XG4gICAgICAgICAgICBpZiAoY29uZmlnLmdldERlc3RpbmF0aW9ucygpLmxlbmd0aCA9PT0gMSkgdHhzW3R4SWR4XS5nZXRPdXRnb2luZ1RyYW5zZmVyKCkuZ2V0RGVzdGluYXRpb25zKCkucHVzaChuZXcgTW9uZXJvRGVzdGluYXRpb24oY29uZmlnLmdldERlc3RpbmF0aW9ucygpWzBdLmdldEFkZHJlc3MoKSwgQmlnSW50KGFtb3VudCkpKTsgLy8gc3dlZXBpbmcgY2FuIGNyZWF0ZSBtdWx0aXBsZSB0eHMgd2l0aCBvbmUgYWRkcmVzc1xuICAgICAgICAgICAgZWxzZSB0eHNbdHhJZHhdLmdldE91dGdvaW5nVHJhbnNmZXIoKS5nZXREZXN0aW5hdGlvbnMoKS5wdXNoKG5ldyBNb25lcm9EZXN0aW5hdGlvbihjb25maWcuZ2V0RGVzdGluYXRpb25zKClbZGVzdGluYXRpb25JZHgrK10uZ2V0QWRkcmVzcygpLCBCaWdJbnQoYW1vdW50KSkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZWxzZSBjb25zb2xlLmxvZyhcIldBUk5JTkc6IGlnbm9yaW5nIHVuZXhwZWN0ZWQgdHJhbnNhY3Rpb24gZmllbGQ6IFwiICsga2V5ICsgXCI6IFwiICsgdmFsKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHR4U2V0O1xuICB9XG4gIFxuICAvKipcbiAgICogQ29udmVydHMgYSBycGMgdHggd2l0aCBhIHRyYW5zZmVyIHRvIGEgdHggc2V0IHdpdGggYSB0eCBhbmQgdHJhbnNmZXIuXG4gICAqIFxuICAgKiBAcGFyYW0gcnBjVHggLSBycGMgdHggdG8gYnVpbGQgZnJvbVxuICAgKiBAcGFyYW0gdHggLSBleGlzdGluZyB0eCB0byBjb250aW51ZSBpbml0aWFsaXppbmcgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0gaXNPdXRnb2luZyAtIHNwZWNpZmllcyBpZiB0aGUgdHggaXMgb3V0Z29pbmcgaWYgdHJ1ZSwgaW5jb21pbmcgaWYgZmFsc2UsIG9yIGRlY29kZXMgZnJvbSB0eXBlIGlmIHVuZGVmaW5lZFxuICAgKiBAcGFyYW0gY29uZmlnIC0gdHggY29uZmlnXG4gICAqIEByZXR1cm4gdGhlIGluaXRpYWxpemVkIHR4IHNldCB3aXRoIGEgdHhcbiAgICovXG4gIHByb3RlY3RlZCBzdGF0aWMgY29udmVydFJwY1R4VG9UeFNldChycGNUeCwgdHgsIGlzT3V0Z29pbmcsIGNvbmZpZykge1xuICAgIGxldCB0eFNldCA9IE1vbmVyb1dhbGxldFJwYy5jb252ZXJ0UnBjVHhTZXQocnBjVHgpO1xuICAgIHR4U2V0LnNldFR4cyhbTW9uZXJvV2FsbGV0UnBjLmNvbnZlcnRScGNUeFdpdGhUcmFuc2ZlcihycGNUeCwgdHgsIGlzT3V0Z29pbmcsIGNvbmZpZykuc2V0VHhTZXQodHhTZXQpXSk7XG4gICAgcmV0dXJuIHR4U2V0O1xuICB9XG4gIFxuICAvKipcbiAgICogQnVpbGRzIGEgTW9uZXJvVHhXYWxsZXQgZnJvbSBhIFJQQyB0eC5cbiAgICogXG4gICAqIEBwYXJhbSBycGNUeCAtIHJwYyB0eCB0byBidWlsZCBmcm9tXG4gICAqIEBwYXJhbSB0eCAtIGV4aXN0aW5nIHR4IHRvIGNvbnRpbnVlIGluaXRpYWxpemluZyAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSBpc091dGdvaW5nIC0gc3BlY2lmaWVzIGlmIHRoZSB0eCBpcyBvdXRnb2luZyBpZiB0cnVlLCBpbmNvbWluZyBpZiBmYWxzZSwgb3IgZGVjb2RlcyBmcm9tIHR5cGUgaWYgdW5kZWZpbmVkXG4gICAqIEBwYXJhbSBjb25maWcgLSB0eCBjb25maWdcbiAgICogQHJldHVybiB7TW9uZXJvVHhXYWxsZXR9IGlzIHRoZSBpbml0aWFsaXplZCB0eFxuICAgKi9cbiAgcHJvdGVjdGVkIHN0YXRpYyBjb252ZXJ0UnBjVHhXaXRoVHJhbnNmZXIocnBjVHg6IGFueSwgdHg/OiBhbnksIGlzT3V0Z29pbmc/OiBhbnksIGNvbmZpZz86IGFueSkgeyAgLy8gVE9ETzogY2hhbmdlIGV2ZXJ5dGhpbmcgdG8gc2FmZSBzZXRcbiAgICAgICAgXG4gICAgLy8gaW5pdGlhbGl6ZSB0eCB0byByZXR1cm5cbiAgICBpZiAoIXR4KSB0eCA9IG5ldyBNb25lcm9UeFdhbGxldCgpO1xuICAgIFxuICAgIC8vIGluaXRpYWxpemUgdHggc3RhdGUgZnJvbSBycGMgdHlwZVxuICAgIGlmIChycGNUeC50eXBlICE9PSB1bmRlZmluZWQpIGlzT3V0Z29pbmcgPSBNb25lcm9XYWxsZXRScGMuZGVjb2RlUnBjVHlwZShycGNUeC50eXBlLCB0eCk7XG4gICAgZWxzZSBhc3NlcnQuZXF1YWwodHlwZW9mIGlzT3V0Z29pbmcsIFwiYm9vbGVhblwiLCBcIk11c3QgaW5kaWNhdGUgaWYgdHggaXMgb3V0Z29pbmcgKHRydWUpIHhvciBpbmNvbWluZyAoZmFsc2UpIHNpbmNlIHVua25vd25cIik7XG4gICAgXG4gICAgLy8gVE9ETzogc2FmZSBzZXRcbiAgICAvLyBpbml0aWFsaXplIHJlbWFpbmluZyBmaWVsZHMgIFRPRE86IHNlZW1zIHRoaXMgc2hvdWxkIGJlIHBhcnQgb2YgY29tbW9uIGZ1bmN0aW9uIHdpdGggRGFlbW9uUnBjLmNvbnZlcnRScGNUeFxuICAgIGxldCBoZWFkZXI7XG4gICAgbGV0IHRyYW5zZmVyO1xuICAgIGZvciAobGV0IGtleSBvZiBPYmplY3Qua2V5cyhycGNUeCkpIHtcbiAgICAgIGxldCB2YWwgPSBycGNUeFtrZXldO1xuICAgICAgaWYgKGtleSA9PT0gXCJ0eGlkXCIpIHR4LnNldEhhc2godmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0eF9oYXNoXCIpIHR4LnNldEhhc2godmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJmZWVcIikgdHguc2V0RmVlKEJpZ0ludCh2YWwpKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJub3RlXCIpIHsgaWYgKHZhbCkgdHguc2V0Tm90ZSh2YWwpOyB9XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidHhfa2V5XCIpIHR4LnNldEtleSh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInR5cGVcIikgeyB9IC8vIHR5cGUgYWxyZWFkeSBoYW5kbGVkXG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidHhfc2l6ZVwiKSB0eC5zZXRTaXplKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidW5sb2NrX3RpbWVcIikgdHguc2V0VW5sb2NrVGltZSh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIndlaWdodFwiKSB0eC5zZXRXZWlnaHQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJsb2NrZWRcIikgdHguc2V0SXNMb2NrZWQodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0eF9ibG9iXCIpIHR4LnNldEZ1bGxIZXgodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0eF9tZXRhZGF0YVwiKSB0eC5zZXRNZXRhZGF0YSh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImRvdWJsZV9zcGVuZF9zZWVuXCIpIHR4LnNldElzRG91YmxlU3BlbmRTZWVuKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYmxvY2tfaGVpZ2h0XCIgfHwga2V5ID09PSBcImhlaWdodFwiKSB7XG4gICAgICAgIGlmICh0eC5nZXRJc0NvbmZpcm1lZCgpKSB7XG4gICAgICAgICAgaWYgKCFoZWFkZXIpIGhlYWRlciA9IG5ldyBNb25lcm9CbG9ja0hlYWRlcigpO1xuICAgICAgICAgIGhlYWRlci5zZXRIZWlnaHQodmFsKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInRpbWVzdGFtcFwiKSB7XG4gICAgICAgIGlmICh0eC5nZXRJc0NvbmZpcm1lZCgpKSB7XG4gICAgICAgICAgaWYgKCFoZWFkZXIpIGhlYWRlciA9IG5ldyBNb25lcm9CbG9ja0hlYWRlcigpO1xuICAgICAgICAgIGhlYWRlci5zZXRUaW1lc3RhbXAodmFsKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyB0aW1lc3RhbXAgb2YgdW5jb25maXJtZWQgdHggaXMgY3VycmVudCByZXF1ZXN0IHRpbWVcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImNvbmZpcm1hdGlvbnNcIikgdHguc2V0TnVtQ29uZmlybWF0aW9ucyh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInN1Z2dlc3RlZF9jb25maXJtYXRpb25zX3RocmVzaG9sZFwiKSB7XG4gICAgICAgIGlmICh0cmFuc2ZlciA9PT0gdW5kZWZpbmVkKSB0cmFuc2ZlciA9IChpc091dGdvaW5nID8gbmV3IE1vbmVyb091dGdvaW5nVHJhbnNmZXIoKSA6IG5ldyBNb25lcm9JbmNvbWluZ1RyYW5zZmVyKCkpLnNldFR4KHR4KTtcbiAgICAgICAgaWYgKCFpc091dGdvaW5nKSB0cmFuc2Zlci5zZXROdW1TdWdnZXN0ZWRDb25maXJtYXRpb25zKHZhbCk7XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYW1vdW50XCIpIHtcbiAgICAgICAgaWYgKHRyYW5zZmVyID09PSB1bmRlZmluZWQpIHRyYW5zZmVyID0gKGlzT3V0Z29pbmcgPyBuZXcgTW9uZXJvT3V0Z29pbmdUcmFuc2ZlcigpIDogbmV3IE1vbmVyb0luY29taW5nVHJhbnNmZXIoKSkuc2V0VHgodHgpO1xuICAgICAgICB0cmFuc2Zlci5zZXRBbW91bnQoQmlnSW50KHZhbCkpO1xuICAgICAgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImFtb3VudHNcIikge30gIC8vIGlnbm9yaW5nLCBhbW91bnRzIHN1bSB0byBhbW91bnRcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJhZGRyZXNzXCIpIHtcbiAgICAgICAgaWYgKCFpc091dGdvaW5nKSB7XG4gICAgICAgICAgaWYgKCF0cmFuc2ZlcikgdHJhbnNmZXIgPSBuZXcgTW9uZXJvSW5jb21pbmdUcmFuc2ZlcigpLnNldFR4KHR4KTtcbiAgICAgICAgICB0cmFuc2Zlci5zZXRBZGRyZXNzKHZhbCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJwYXltZW50X2lkXCIpIHtcbiAgICAgICAgaWYgKFwiXCIgIT09IHZhbCAmJiBNb25lcm9UeFdhbGxldC5ERUZBVUxUX1BBWU1FTlRfSUQgIT09IHZhbCkgdHguc2V0UGF5bWVudElkKHZhbCk7ICAvLyBkZWZhdWx0IGlzIHVuZGVmaW5lZFxuICAgICAgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInN1YmFkZHJfaW5kZXhcIikgYXNzZXJ0KHJwY1R4LnN1YmFkZHJfaW5kaWNlcyk7ICAvLyBoYW5kbGVkIGJ5IHN1YmFkZHJfaW5kaWNlc1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInN1YmFkZHJfaW5kaWNlc1wiKSB7XG4gICAgICAgIGlmICghdHJhbnNmZXIpIHRyYW5zZmVyID0gKGlzT3V0Z29pbmcgPyBuZXcgTW9uZXJvT3V0Z29pbmdUcmFuc2ZlcigpIDogbmV3IE1vbmVyb0luY29taW5nVHJhbnNmZXIoKSkuc2V0VHgodHgpO1xuICAgICAgICBsZXQgcnBjSW5kaWNlcyA9IHZhbDtcbiAgICAgICAgdHJhbnNmZXIuc2V0QWNjb3VudEluZGV4KHJwY0luZGljZXNbMF0ubWFqb3IpO1xuICAgICAgICBpZiAoaXNPdXRnb2luZykge1xuICAgICAgICAgIGxldCBzdWJhZGRyZXNzSW5kaWNlcyA9IFtdO1xuICAgICAgICAgIGZvciAobGV0IHJwY0luZGV4IG9mIHJwY0luZGljZXMpIHN1YmFkZHJlc3NJbmRpY2VzLnB1c2gocnBjSW5kZXgubWlub3IpO1xuICAgICAgICAgIHRyYW5zZmVyLnNldFN1YmFkZHJlc3NJbmRpY2VzKHN1YmFkZHJlc3NJbmRpY2VzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBhc3NlcnQuZXF1YWwocnBjSW5kaWNlcy5sZW5ndGgsIDEpO1xuICAgICAgICAgIHRyYW5zZmVyLnNldFN1YmFkZHJlc3NJbmRleChycGNJbmRpY2VzWzBdLm1pbm9yKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImRlc3RpbmF0aW9uc1wiIHx8IGtleSA9PSBcInJlY2lwaWVudHNcIikge1xuICAgICAgICBhc3NlcnQoaXNPdXRnb2luZyk7XG4gICAgICAgIGxldCBkZXN0aW5hdGlvbnMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgcnBjRGVzdGluYXRpb24gb2YgdmFsKSB7XG4gICAgICAgICAgbGV0IGRlc3RpbmF0aW9uID0gbmV3IE1vbmVyb0Rlc3RpbmF0aW9uKCk7XG4gICAgICAgICAgZGVzdGluYXRpb25zLnB1c2goZGVzdGluYXRpb24pO1xuICAgICAgICAgIGZvciAobGV0IGRlc3RpbmF0aW9uS2V5IG9mIE9iamVjdC5rZXlzKHJwY0Rlc3RpbmF0aW9uKSkge1xuICAgICAgICAgICAgaWYgKGRlc3RpbmF0aW9uS2V5ID09PSBcImFkZHJlc3NcIikgZGVzdGluYXRpb24uc2V0QWRkcmVzcyhycGNEZXN0aW5hdGlvbltkZXN0aW5hdGlvbktleV0pO1xuICAgICAgICAgICAgZWxzZSBpZiAoZGVzdGluYXRpb25LZXkgPT09IFwiYW1vdW50XCIpIGRlc3RpbmF0aW9uLnNldEFtb3VudChCaWdJbnQocnBjRGVzdGluYXRpb25bZGVzdGluYXRpb25LZXldKSk7XG4gICAgICAgICAgICBlbHNlIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlVucmVjb2duaXplZCB0cmFuc2FjdGlvbiBkZXN0aW5hdGlvbiBmaWVsZDogXCIgKyBkZXN0aW5hdGlvbktleSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICh0cmFuc2ZlciA9PT0gdW5kZWZpbmVkKSB0cmFuc2ZlciA9IG5ldyBNb25lcm9PdXRnb2luZ1RyYW5zZmVyKHt0eDogdHh9KTtcbiAgICAgICAgdHJhbnNmZXIuc2V0RGVzdGluYXRpb25zKGRlc3RpbmF0aW9ucyk7XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwibXVsdGlzaWdfdHhzZXRcIiAmJiB2YWwgIT09IHVuZGVmaW5lZCkge30gLy8gaGFuZGxlZCBlbHNld2hlcmU7IHRoaXMgbWV0aG9kIG9ubHkgYnVpbGRzIGEgdHggd2FsbGV0XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwidW5zaWduZWRfdHhzZXRcIiAmJiB2YWwgIT09IHVuZGVmaW5lZCkge30gLy8gaGFuZGxlZCBlbHNld2hlcmU7IHRoaXMgbWV0aG9kIG9ubHkgYnVpbGRzIGEgdHggd2FsbGV0XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYW1vdW50X2luXCIpIHR4LnNldElucHV0U3VtKEJpZ0ludCh2YWwpKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJhbW91bnRfb3V0XCIpIHR4LnNldE91dHB1dFN1bShCaWdJbnQodmFsKSk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiY2hhbmdlX2FkZHJlc3NcIikgdHguc2V0Q2hhbmdlQWRkcmVzcyh2YWwgPT09IFwiXCIgPyB1bmRlZmluZWQgOiB2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImNoYW5nZV9hbW91bnRcIikgdHguc2V0Q2hhbmdlQW1vdW50KEJpZ0ludCh2YWwpKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJkdW1teV9vdXRwdXRzXCIpIHR4LnNldE51bUR1bW15T3V0cHV0cyh2YWwpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImV4dHJhXCIpIHR4LnNldEV4dHJhSGV4KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicmluZ19zaXplXCIpIHR4LnNldFJpbmdTaXplKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwic3BlbnRfa2V5X2ltYWdlc1wiKSB7XG4gICAgICAgIGxldCBpbnB1dEtleUltYWdlcyA9IHZhbC5rZXlfaW1hZ2VzO1xuICAgICAgICBHZW5VdGlscy5hc3NlcnRUcnVlKHR4LmdldElucHV0cygpID09PSB1bmRlZmluZWQpO1xuICAgICAgICB0eC5zZXRJbnB1dHMoW10pO1xuICAgICAgICBmb3IgKGxldCBpbnB1dEtleUltYWdlIG9mIGlucHV0S2V5SW1hZ2VzKSB7XG4gICAgICAgICAgdHguZ2V0SW5wdXRzKCkucHVzaChuZXcgTW9uZXJvT3V0cHV0V2FsbGV0KCkuc2V0S2V5SW1hZ2UobmV3IE1vbmVyb0tleUltYWdlKCkuc2V0SGV4KGlucHV0S2V5SW1hZ2UpKS5zZXRUeCh0eCkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwiYW1vdW50c19ieV9kZXN0XCIpIHtcbiAgICAgICAgR2VuVXRpbHMuYXNzZXJ0VHJ1ZShpc091dGdvaW5nKTtcbiAgICAgICAgbGV0IGFtb3VudHNCeURlc3QgPSB2YWwuYW1vdW50cztcbiAgICAgICAgYXNzZXJ0LmVxdWFsKGNvbmZpZy5nZXREZXN0aW5hdGlvbnMoKS5sZW5ndGgsIGFtb3VudHNCeURlc3QubGVuZ3RoKTtcbiAgICAgICAgaWYgKHRyYW5zZmVyID09PSB1bmRlZmluZWQpIHRyYW5zZmVyID0gbmV3IE1vbmVyb091dGdvaW5nVHJhbnNmZXIoKS5zZXRUeCh0eCk7XG4gICAgICAgIHRyYW5zZmVyLnNldERlc3RpbmF0aW9ucyhbXSk7XG4gICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY29uZmlnLmdldERlc3RpbmF0aW9ucygpLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgdHJhbnNmZXIuZ2V0RGVzdGluYXRpb25zKCkucHVzaChuZXcgTW9uZXJvRGVzdGluYXRpb24oY29uZmlnLmdldERlc3RpbmF0aW9ucygpW2ldLmdldEFkZHJlc3MoKSwgQmlnSW50KGFtb3VudHNCeURlc3RbaV0pKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGVsc2UgY29uc29sZS5sb2coXCJXQVJOSU5HOiBpZ25vcmluZyB1bmV4cGVjdGVkIHRyYW5zYWN0aW9uIGZpZWxkIHdpdGggdHJhbnNmZXI6IFwiICsga2V5ICsgXCI6IFwiICsgdmFsKTtcbiAgICB9XG4gICAgXG4gICAgLy8gbGluayBibG9jayBhbmQgdHhcbiAgICBpZiAoaGVhZGVyKSB0eC5zZXRCbG9jayhuZXcgTW9uZXJvQmxvY2soaGVhZGVyKS5zZXRUeHMoW3R4XSkpO1xuICAgIFxuICAgIC8vIGluaXRpYWxpemUgZmluYWwgZmllbGRzXG4gICAgaWYgKHRyYW5zZmVyKSB7XG4gICAgICBpZiAodHguZ2V0SXNDb25maXJtZWQoKSA9PT0gdW5kZWZpbmVkKSB0eC5zZXRJc0NvbmZpcm1lZChmYWxzZSk7XG4gICAgICBpZiAoIXRyYW5zZmVyLmdldFR4KCkuZ2V0SXNDb25maXJtZWQoKSkgdHguc2V0TnVtQ29uZmlybWF0aW9ucygwKTtcbiAgICAgIGlmIChpc091dGdvaW5nKSB7XG4gICAgICAgIHR4LnNldElzT3V0Z29pbmcodHJ1ZSk7XG4gICAgICAgIGlmICh0eC5nZXRPdXRnb2luZ1RyYW5zZmVyKCkpIHtcbiAgICAgICAgICBpZiAodHJhbnNmZXIuZ2V0RGVzdGluYXRpb25zKCkpIHR4LmdldE91dGdvaW5nVHJhbnNmZXIoKS5zZXREZXN0aW5hdGlvbnModW5kZWZpbmVkKTsgLy8gb3ZlcndyaXRlIHRvIGF2b2lkIHJlY29uY2lsZSBlcnJvciBUT0RPOiByZW1vdmUgYWZ0ZXIgPjE4LjMuMSB3aGVuIGFtb3VudHNfYnlfZGVzdCBzdXBwb3J0ZWRcbiAgICAgICAgICB0eC5nZXRPdXRnb2luZ1RyYW5zZmVyKCkubWVyZ2UodHJhbnNmZXIpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgdHguc2V0T3V0Z29pbmdUcmFuc2Zlcih0cmFuc2Zlcik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0eC5zZXRJc0luY29taW5nKHRydWUpO1xuICAgICAgICB0eC5zZXRJbmNvbWluZ1RyYW5zZmVycyhbdHJhbnNmZXJdKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gcmV0dXJuIGluaXRpYWxpemVkIHRyYW5zYWN0aW9uXG4gICAgcmV0dXJuIHR4O1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNUeFdhbGxldFdpdGhPdXRwdXQocnBjT3V0cHV0KSB7XG4gICAgXG4gICAgLy8gaW5pdGlhbGl6ZSB0eFxuICAgIGxldCB0eCA9IG5ldyBNb25lcm9UeFdhbGxldCgpO1xuICAgIHR4LnNldElzQ29uZmlybWVkKHRydWUpO1xuICAgIHR4LnNldElzUmVsYXllZCh0cnVlKTtcbiAgICB0eC5zZXRJc0ZhaWxlZChmYWxzZSk7XG4gICAgXG4gICAgLy8gaW5pdGlhbGl6ZSBvdXRwdXRcbiAgICBsZXQgb3V0cHV0ID0gbmV3IE1vbmVyb091dHB1dFdhbGxldCh7dHg6IHR4fSk7XG4gICAgZm9yIChsZXQga2V5IG9mIE9iamVjdC5rZXlzKHJwY091dHB1dCkpIHtcbiAgICAgIGxldCB2YWwgPSBycGNPdXRwdXRba2V5XTtcbiAgICAgIGlmIChrZXkgPT09IFwiYW1vdW50XCIpIG91dHB1dC5zZXRBbW91bnQoQmlnSW50KHZhbCkpO1xuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInNwZW50XCIpIG91dHB1dC5zZXRJc1NwZW50KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwia2V5X2ltYWdlXCIpIHsgaWYgKFwiXCIgIT09IHZhbCkgb3V0cHV0LnNldEtleUltYWdlKG5ldyBNb25lcm9LZXlJbWFnZSh2YWwpKTsgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImdsb2JhbF9pbmRleFwiKSBvdXRwdXQuc2V0SW5kZXgodmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ0eF9oYXNoXCIpIHR4LnNldEhhc2godmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJ1bmxvY2tlZFwiKSB0eC5zZXRJc0xvY2tlZCghdmFsKTtcbiAgICAgIGVsc2UgaWYgKGtleSA9PT0gXCJmcm96ZW5cIikgb3V0cHV0LnNldElzRnJvemVuKHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwicHVia2V5XCIpIG91dHB1dC5zZXRTdGVhbHRoUHVibGljS2V5KHZhbCk7XG4gICAgICBlbHNlIGlmIChrZXkgPT09IFwic3ViYWRkcl9pbmRleFwiKSB7XG4gICAgICAgIG91dHB1dC5zZXRBY2NvdW50SW5kZXgodmFsLm1ham9yKTtcbiAgICAgICAgb3V0cHV0LnNldFN1YmFkZHJlc3NJbmRleCh2YWwubWlub3IpO1xuICAgICAgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcImJsb2NrX2hlaWdodFwiKSB0eC5zZXRCbG9jaygobmV3IE1vbmVyb0Jsb2NrKCkuc2V0SGVpZ2h0KHZhbCkgYXMgTW9uZXJvQmxvY2spLnNldFR4cyhbdHggYXMgTW9uZXJvVHhdKSk7XG4gICAgICBlbHNlIGNvbnNvbGUubG9nKFwiV0FSTklORzogaWdub3JpbmcgdW5leHBlY3RlZCB0cmFuc2FjdGlvbiBmaWVsZDogXCIgKyBrZXkgKyBcIjogXCIgKyB2YWwpO1xuICAgIH1cbiAgICBcbiAgICAvLyBpbml0aWFsaXplIHR4IHdpdGggb3V0cHV0XG4gICAgdHguc2V0T3V0cHV0cyhbb3V0cHV0XSk7XG4gICAgcmV0dXJuIHR4O1xuICB9XG4gIFxuICBwcm90ZWN0ZWQgc3RhdGljIGNvbnZlcnRScGNEZXNjcmliZVRyYW5zZmVyKHJwY0Rlc2NyaWJlVHJhbnNmZXJSZXN1bHQpIHtcbiAgICBsZXQgdHhTZXQgPSBuZXcgTW9uZXJvVHhTZXQoKTtcbiAgICBmb3IgKGxldCBrZXkgb2YgT2JqZWN0LmtleXMocnBjRGVzY3JpYmVUcmFuc2ZlclJlc3VsdCkpIHtcbiAgICAgIGxldCB2YWwgPSBycGNEZXNjcmliZVRyYW5zZmVyUmVzdWx0W2tleV07XG4gICAgICBpZiAoa2V5ID09PSBcImRlc2NcIikge1xuICAgICAgICB0eFNldC5zZXRUeHMoW10pO1xuICAgICAgICBmb3IgKGxldCB0eE1hcCBvZiB2YWwpIHtcbiAgICAgICAgICBsZXQgdHggPSBNb25lcm9XYWxsZXRScGMuY29udmVydFJwY1R4V2l0aFRyYW5zZmVyKHR4TWFwLCB1bmRlZmluZWQsIHRydWUpO1xuICAgICAgICAgIHR4LnNldFR4U2V0KHR4U2V0KTtcbiAgICAgICAgICB0eFNldC5nZXRUeHMoKS5wdXNoKHR4KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZWxzZSBpZiAoa2V5ID09PSBcInN1bW1hcnlcIikgeyB9IC8vIFRPRE86IHN1cHBvcnQgdHggc2V0IHN1bW1hcnkgZmllbGRzP1xuICAgICAgZWxzZSBjb25zb2xlLmxvZyhcIldBUk5JTkc6IGlnbm9yaW5nIHVuZXhwZWN0ZWQgZGVzY2RyaWJlIHRyYW5zZmVyIGZpZWxkOiBcIiArIGtleSArIFwiOiBcIiArIHZhbCk7XG4gICAgfVxuICAgIHJldHVybiB0eFNldDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIERlY29kZXMgYSBcInR5cGVcIiBmcm9tIG1vbmVyby13YWxsZXQtcnBjIHRvIGluaXRpYWxpemUgdHlwZSBhbmQgc3RhdGVcbiAgICogZmllbGRzIGluIHRoZSBnaXZlbiB0cmFuc2FjdGlvbi5cbiAgICogXG4gICAqIFRPRE86IHRoZXNlIHNob3VsZCBiZSBzYWZlIHNldFxuICAgKiBcbiAgICogQHBhcmFtIHJwY1R5cGUgaXMgdGhlIHR5cGUgdG8gZGVjb2RlXG4gICAqIEBwYXJhbSB0eCBpcyB0aGUgdHJhbnNhY3Rpb24gdG8gZGVjb2RlIGtub3duIGZpZWxkcyB0b1xuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHRoZSBycGMgdHlwZSBpbmRpY2F0ZXMgb3V0Z29pbmcgeG9yIGluY29taW5nXG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIGRlY29kZVJwY1R5cGUocnBjVHlwZSwgdHgpIHtcbiAgICBsZXQgaXNPdXRnb2luZztcbiAgICBpZiAocnBjVHlwZSA9PT0gXCJpblwiKSB7XG4gICAgICBpc091dGdvaW5nID0gZmFsc2U7XG4gICAgICB0eC5zZXRJc0NvbmZpcm1lZCh0cnVlKTtcbiAgICAgIHR4LnNldEluVHhQb29sKGZhbHNlKTtcbiAgICAgIHR4LnNldElzUmVsYXllZCh0cnVlKTtcbiAgICAgIHR4LnNldFJlbGF5KHRydWUpO1xuICAgICAgdHguc2V0SXNGYWlsZWQoZmFsc2UpO1xuICAgICAgdHguc2V0SXNNaW5lclR4KGZhbHNlKTtcbiAgICB9IGVsc2UgaWYgKHJwY1R5cGUgPT09IFwib3V0XCIpIHtcbiAgICAgIGlzT3V0Z29pbmcgPSB0cnVlO1xuICAgICAgdHguc2V0SXNDb25maXJtZWQodHJ1ZSk7XG4gICAgICB0eC5zZXRJblR4UG9vbChmYWxzZSk7XG4gICAgICB0eC5zZXRJc1JlbGF5ZWQodHJ1ZSk7XG4gICAgICB0eC5zZXRSZWxheSh0cnVlKTtcbiAgICAgIHR4LnNldElzRmFpbGVkKGZhbHNlKTtcbiAgICAgIHR4LnNldElzTWluZXJUeChmYWxzZSk7XG4gICAgfSBlbHNlIGlmIChycGNUeXBlID09PSBcInBvb2xcIikge1xuICAgICAgaXNPdXRnb2luZyA9IGZhbHNlO1xuICAgICAgdHguc2V0SXNDb25maXJtZWQoZmFsc2UpO1xuICAgICAgdHguc2V0SW5UeFBvb2wodHJ1ZSk7XG4gICAgICB0eC5zZXRJc1JlbGF5ZWQodHJ1ZSk7XG4gICAgICB0eC5zZXRSZWxheSh0cnVlKTtcbiAgICAgIHR4LnNldElzRmFpbGVkKGZhbHNlKTtcbiAgICAgIHR4LnNldElzTWluZXJUeChmYWxzZSk7ICAvLyBUT0RPOiBidXQgY291bGQgaXQgYmU/XG4gICAgfSBlbHNlIGlmIChycGNUeXBlID09PSBcInBlbmRpbmdcIikge1xuICAgICAgaXNPdXRnb2luZyA9IHRydWU7XG4gICAgICB0eC5zZXRJc0NvbmZpcm1lZChmYWxzZSk7XG4gICAgICB0eC5zZXRJblR4UG9vbCh0cnVlKTtcbiAgICAgIHR4LnNldElzUmVsYXllZCh0cnVlKTtcbiAgICAgIHR4LnNldFJlbGF5KHRydWUpO1xuICAgICAgdHguc2V0SXNGYWlsZWQoZmFsc2UpO1xuICAgICAgdHguc2V0SXNNaW5lclR4KGZhbHNlKTtcbiAgICB9IGVsc2UgaWYgKHJwY1R5cGUgPT09IFwiYmxvY2tcIikge1xuICAgICAgaXNPdXRnb2luZyA9IGZhbHNlO1xuICAgICAgdHguc2V0SXNDb25maXJtZWQodHJ1ZSk7XG4gICAgICB0eC5zZXRJblR4UG9vbChmYWxzZSk7XG4gICAgICB0eC5zZXRJc1JlbGF5ZWQodHJ1ZSk7XG4gICAgICB0eC5zZXRSZWxheSh0cnVlKTtcbiAgICAgIHR4LnNldElzRmFpbGVkKGZhbHNlKTtcbiAgICAgIHR4LnNldElzTWluZXJUeCh0cnVlKTtcbiAgICB9IGVsc2UgaWYgKHJwY1R5cGUgPT09IFwiZmFpbGVkXCIpIHtcbiAgICAgIGlzT3V0Z29pbmcgPSB0cnVlO1xuICAgICAgdHguc2V0SXNDb25maXJtZWQoZmFsc2UpO1xuICAgICAgdHguc2V0SW5UeFBvb2woZmFsc2UpO1xuICAgICAgdHguc2V0SXNSZWxheWVkKHRydWUpO1xuICAgICAgdHguc2V0UmVsYXkodHJ1ZSk7XG4gICAgICB0eC5zZXRJc0ZhaWxlZCh0cnVlKTtcbiAgICAgIHR4LnNldElzTWluZXJUeChmYWxzZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBNb25lcm9FcnJvcihcIlVucmVjb2duaXplZCB0cmFuc2ZlciB0eXBlOiBcIiArIHJwY1R5cGUpO1xuICAgIH1cbiAgICByZXR1cm4gaXNPdXRnb2luZztcbiAgfVxuICBcbiAgLyoqXG4gICAqIE1lcmdlcyBhIHRyYW5zYWN0aW9uIGludG8gYSB1bmlxdWUgc2V0IG9mIHRyYW5zYWN0aW9ucy5cbiAgICpcbiAgICogQHBhcmFtIHtNb25lcm9UeFdhbGxldH0gdHggLSB0aGUgdHJhbnNhY3Rpb24gdG8gbWVyZ2UgaW50byB0aGUgZXhpc3RpbmcgdHhzXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB0eE1hcCAtIG1hcHMgdHggaGFzaGVzIHRvIHR4c1xuICAgKiBAcGFyYW0ge09iamVjdH0gYmxvY2tNYXAgLSBtYXBzIGJsb2NrIGhlaWdodHMgdG8gYmxvY2tzXG4gICAqL1xuICBwcm90ZWN0ZWQgc3RhdGljIG1lcmdlVHgodHgsIHR4TWFwLCBibG9ja01hcCkge1xuICAgIGFzc2VydCh0eC5nZXRIYXNoKCkgIT09IHVuZGVmaW5lZCk7XG4gICAgXG4gICAgLy8gbWVyZ2UgdHhcbiAgICBsZXQgYVR4ID0gdHhNYXBbdHguZ2V0SGFzaCgpXTtcbiAgICBpZiAoYVR4ID09PSB1bmRlZmluZWQpIHR4TWFwW3R4LmdldEhhc2goKV0gPSB0eDsgLy8gY2FjaGUgbmV3IHR4XG4gICAgZWxzZSBhVHgubWVyZ2UodHgpOyAvLyBtZXJnZSB3aXRoIGV4aXN0aW5nIHR4XG4gICAgXG4gICAgLy8gbWVyZ2UgdHgncyBibG9jayBpZiBjb25maXJtZWRcbiAgICBpZiAodHguZ2V0SGVpZ2h0KCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgbGV0IGFCbG9jayA9IGJsb2NrTWFwW3R4LmdldEhlaWdodCgpXTtcbiAgICAgIGlmIChhQmxvY2sgPT09IHVuZGVmaW5lZCkgYmxvY2tNYXBbdHguZ2V0SGVpZ2h0KCldID0gdHguZ2V0QmxvY2soKTsgLy8gY2FjaGUgbmV3IGJsb2NrXG4gICAgICBlbHNlIGFCbG9jay5tZXJnZSh0eC5nZXRCbG9jaygpKTsgLy8gbWVyZ2Ugd2l0aCBleGlzdGluZyBibG9ja1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIENvbXBhcmVzIHR3byB0cmFuc2FjdGlvbnMgYnkgdGhlaXIgaGVpZ2h0LlxuICAgKi9cbiAgcHJvdGVjdGVkIHN0YXRpYyBjb21wYXJlVHhzQnlIZWlnaHQodHgxLCB0eDIpIHtcbiAgICBpZiAodHgxLmdldEhlaWdodCgpID09PSB1bmRlZmluZWQgJiYgdHgyLmdldEhlaWdodCgpID09PSB1bmRlZmluZWQpIHJldHVybiAwOyAvLyBib3RoIHVuY29uZmlybWVkXG4gICAgZWxzZSBpZiAodHgxLmdldEhlaWdodCgpID09PSB1bmRlZmluZWQpIHJldHVybiAxOyAgIC8vIHR4MSBpcyB1bmNvbmZpcm1lZFxuICAgIGVsc2UgaWYgKHR4Mi5nZXRIZWlnaHQoKSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gLTE7ICAvLyB0eDIgaXMgdW5jb25maXJtZWRcbiAgICBsZXQgZGlmZiA9IHR4MS5nZXRIZWlnaHQoKSAtIHR4Mi5nZXRIZWlnaHQoKTtcbiAgICBpZiAoZGlmZiAhPT0gMCkgcmV0dXJuIGRpZmY7XG4gICAgcmV0dXJuIHR4MS5nZXRCbG9jaygpLmdldFR4cygpLmluZGV4T2YodHgxKSAtIHR4Mi5nZXRCbG9jaygpLmdldFR4cygpLmluZGV4T2YodHgyKTsgLy8gdHhzIGFyZSBpbiB0aGUgc2FtZSBibG9jayBzbyByZXRhaW4gdGhlaXIgb3JpZ2luYWwgb3JkZXJcbiAgfVxuICBcbiAgLyoqXG4gICAqIENvbXBhcmVzIHR3byB0cmFuc2ZlcnMgYnkgYXNjZW5kaW5nIGFjY291bnQgYW5kIHN1YmFkZHJlc3MgaW5kaWNlcy5cbiAgICovXG4gIHN0YXRpYyBjb21wYXJlSW5jb21pbmdUcmFuc2ZlcnModDEsIHQyKSB7XG4gICAgaWYgKHQxLmdldEFjY291bnRJbmRleCgpIDwgdDIuZ2V0QWNjb3VudEluZGV4KCkpIHJldHVybiAtMTtcbiAgICBlbHNlIGlmICh0MS5nZXRBY2NvdW50SW5kZXgoKSA9PT0gdDIuZ2V0QWNjb3VudEluZGV4KCkpIHJldHVybiB0MS5nZXRTdWJhZGRyZXNzSW5kZXgoKSAtIHQyLmdldFN1YmFkZHJlc3NJbmRleCgpO1xuICAgIHJldHVybiAxO1xuICB9XG4gIFxuICAvKipcbiAgICogQ29tcGFyZXMgdHdvIG91dHB1dHMgYnkgYXNjZW5kaW5nIGFjY291bnQgYW5kIHN1YmFkZHJlc3MgaW5kaWNlcy5cbiAgICovXG4gIHByb3RlY3RlZCBzdGF0aWMgY29tcGFyZU91dHB1dHMobzEsIG8yKSB7XG4gICAgXG4gICAgLy8gY29tcGFyZSBieSBoZWlnaHRcbiAgICBsZXQgaGVpZ2h0Q29tcGFyaXNvbiA9IE1vbmVyb1dhbGxldFJwYy5jb21wYXJlVHhzQnlIZWlnaHQobzEuZ2V0VHgoKSwgbzIuZ2V0VHgoKSk7XG4gICAgaWYgKGhlaWdodENvbXBhcmlzb24gIT09IDApIHJldHVybiBoZWlnaHRDb21wYXJpc29uO1xuICAgIFxuICAgIC8vIGNvbXBhcmUgYnkgYWNjb3VudCBpbmRleCwgc3ViYWRkcmVzcyBpbmRleCwgb3V0cHV0IGluZGV4LCB0aGVuIGtleSBpbWFnZSBoZXhcbiAgICBsZXQgY29tcGFyZSA9IG8xLmdldEFjY291bnRJbmRleCgpIC0gbzIuZ2V0QWNjb3VudEluZGV4KCk7XG4gICAgaWYgKGNvbXBhcmUgIT09IDApIHJldHVybiBjb21wYXJlO1xuICAgIGNvbXBhcmUgPSBvMS5nZXRTdWJhZGRyZXNzSW5kZXgoKSAtIG8yLmdldFN1YmFkZHJlc3NJbmRleCgpO1xuICAgIGlmIChjb21wYXJlICE9PSAwKSByZXR1cm4gY29tcGFyZTtcbiAgICBjb21wYXJlID0gbzEuZ2V0SW5kZXgoKSAtIG8yLmdldEluZGV4KCk7XG4gICAgaWYgKGNvbXBhcmUgIT09IDApIHJldHVybiBjb21wYXJlO1xuICAgIHJldHVybiBvMS5nZXRLZXlJbWFnZSgpLmdldEhleCgpLmxvY2FsZUNvbXBhcmUobzIuZ2V0S2V5SW1hZ2UoKS5nZXRIZXgoKSk7XG4gIH1cbn1cblxuLyoqXG4gKiBQb2xscyBtb25lcm8td2FsbGV0LXJwYyB0byBwcm92aWRlIGxpc3RlbmVyIG5vdGlmaWNhdGlvbnMuXG4gKiBcbiAqIEBwcml2YXRlXG4gKi9cbmNsYXNzIFdhbGxldFBvbGxlciB7XG5cbiAgLy8gaW5zdGFuY2UgdmFyaWFibGVzXG4gIGlzUG9sbGluZzogYm9vbGVhbjtcbiAgcHJvdGVjdGVkIHdhbGxldDogTW9uZXJvV2FsbGV0UnBjO1xuICBwcm90ZWN0ZWQgbG9vcGVyOiBUYXNrTG9vcGVyO1xuICBwcm90ZWN0ZWQgcHJldkxvY2tlZFR4czogYW55O1xuICBwcm90ZWN0ZWQgcHJldlVuY29uZmlybWVkTm90aWZpY2F0aW9uczogYW55O1xuICBwcm90ZWN0ZWQgcHJldkNvbmZpcm1lZE5vdGlmaWNhdGlvbnM6IGFueTtcbiAgcHJvdGVjdGVkIHRocmVhZFBvb2w6IGFueTtcbiAgcHJvdGVjdGVkIG51bVBvbGxpbmc6IGFueTtcbiAgcHJvdGVjdGVkIHByZXZIZWlnaHQ6IGFueTtcbiAgcHJvdGVjdGVkIHByZXZCYWxhbmNlczogYW55O1xuICBcbiAgY29uc3RydWN0b3Iod2FsbGV0KSB7XG4gICAgbGV0IHRoYXQgPSB0aGlzO1xuICAgIHRoaXMud2FsbGV0ID0gd2FsbGV0O1xuICAgIHRoaXMubG9vcGVyID0gbmV3IFRhc2tMb29wZXIoYXN5bmMgZnVuY3Rpb24oKSB7IGF3YWl0IHRoYXQucG9sbCgpOyB9KTtcbiAgICB0aGlzLnByZXZMb2NrZWRUeHMgPSBbXTtcbiAgICB0aGlzLnByZXZVbmNvbmZpcm1lZE5vdGlmaWNhdGlvbnMgPSBuZXcgU2V0KCk7IC8vIHR4IGhhc2hlcyBvZiBwcmV2aW91cyBub3RpZmljYXRpb25zXG4gICAgdGhpcy5wcmV2Q29uZmlybWVkTm90aWZpY2F0aW9ucyA9IG5ldyBTZXQoKTsgLy8gdHggaGFzaGVzIG9mIHByZXZpb3VzbHkgY29uZmlybWVkIGJ1dCBub3QgeWV0IHVubG9ja2VkIG5vdGlmaWNhdGlvbnNcbiAgICB0aGlzLnRocmVhZFBvb2wgPSBuZXcgVGhyZWFkUG9vbCgxKTsgLy8gc3luY2hyb25pemUgcG9sbHNcbiAgICB0aGlzLm51bVBvbGxpbmcgPSAwO1xuICB9XG4gIFxuICBzZXRJc1BvbGxpbmcoaXNQb2xsaW5nKSB7XG4gICAgdGhpcy5pc1BvbGxpbmcgPSBpc1BvbGxpbmc7XG4gICAgaWYgKGlzUG9sbGluZykgdGhpcy5sb29wZXIuc3RhcnQodGhpcy53YWxsZXQuZ2V0U3luY1BlcmlvZEluTXMoKSk7XG4gICAgZWxzZSB0aGlzLmxvb3Blci5zdG9wKCk7XG4gIH1cbiAgXG4gIHNldFBlcmlvZEluTXMocGVyaW9kSW5Ncykge1xuICAgIHRoaXMubG9vcGVyLnNldFBlcmlvZEluTXMocGVyaW9kSW5Ncyk7XG4gIH1cbiAgXG4gIGFzeW5jIHBvbGwoKSB7XG5cbiAgICAvLyBza2lwIGlmIG5leHQgcG9sbCBpcyBxdWV1ZWRcbiAgICBpZiAodGhpcy5udW1Qb2xsaW5nID4gMSkgcmV0dXJuO1xuICAgIHRoaXMubnVtUG9sbGluZysrO1xuICAgIFxuICAgIC8vIHN5bmNocm9uaXplIHBvbGxzXG4gICAgbGV0IHRoYXQgPSB0aGlzO1xuICAgIHJldHVybiB0aGlzLnRocmVhZFBvb2wuc3VibWl0KGFzeW5jIGZ1bmN0aW9uKCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgXG4gICAgICAgIC8vIHNraXAgaWYgd2FsbGV0IGlzIGNsb3NlZFxuICAgICAgICBpZiAoYXdhaXQgdGhhdC53YWxsZXQuaXNDbG9zZWQoKSkge1xuICAgICAgICAgIHRoYXQubnVtUG9sbGluZy0tO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgLy8gdGFrZSBpbml0aWFsIHNuYXBzaG90XG4gICAgICAgIGlmICh0aGF0LnByZXZCYWxhbmNlcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgdGhhdC5wcmV2SGVpZ2h0ID0gYXdhaXQgdGhhdC53YWxsZXQuZ2V0SGVpZ2h0KCk7XG4gICAgICAgICAgdGhhdC5wcmV2TG9ja2VkVHhzID0gYXdhaXQgdGhhdC53YWxsZXQuZ2V0VHhzKG5ldyBNb25lcm9UeFF1ZXJ5KCkuc2V0SXNMb2NrZWQodHJ1ZSkpO1xuICAgICAgICAgIHRoYXQucHJldkJhbGFuY2VzID0gYXdhaXQgdGhhdC53YWxsZXQuZ2V0QmFsYW5jZXMoKTtcbiAgICAgICAgICB0aGF0Lm51bVBvbGxpbmctLTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIGFubm91bmNlIGhlaWdodCBjaGFuZ2VzXG4gICAgICAgIGxldCBoZWlnaHQgPSBhd2FpdCB0aGF0LndhbGxldC5nZXRIZWlnaHQoKTtcbiAgICAgICAgaWYgKHRoYXQucHJldkhlaWdodCAhPT0gaGVpZ2h0KSB7XG4gICAgICAgICAgZm9yIChsZXQgaSA9IHRoYXQucHJldkhlaWdodDsgaSA8IGhlaWdodDsgaSsrKSBhd2FpdCB0aGF0Lm9uTmV3QmxvY2soaSk7XG4gICAgICAgICAgdGhhdC5wcmV2SGVpZ2h0ID0gaGVpZ2h0O1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBnZXQgbG9ja2VkIHR4cyBmb3IgY29tcGFyaXNvbiB0byBwcmV2aW91c1xuICAgICAgICBsZXQgbWluSGVpZ2h0ID0gTWF0aC5tYXgoMCwgaGVpZ2h0IC0gNzApOyAvLyBvbmx5IG1vbml0b3IgcmVjZW50IHR4c1xuICAgICAgICBsZXQgbG9ja2VkVHhzID0gYXdhaXQgdGhhdC53YWxsZXQuZ2V0VHhzKG5ldyBNb25lcm9UeFF1ZXJ5KCkuc2V0SXNMb2NrZWQodHJ1ZSkuc2V0TWluSGVpZ2h0KG1pbkhlaWdodCkuc2V0SW5jbHVkZU91dHB1dHModHJ1ZSkpO1xuICAgICAgICBcbiAgICAgICAgLy8gY29sbGVjdCBoYXNoZXMgb2YgdHhzIG5vIGxvbmdlciBsb2NrZWRcbiAgICAgICAgbGV0IG5vTG9uZ2VyTG9ja2VkSGFzaGVzID0gW107XG4gICAgICAgIGZvciAobGV0IHByZXZMb2NrZWRUeCBvZiB0aGF0LnByZXZMb2NrZWRUeHMpIHtcbiAgICAgICAgICBpZiAodGhhdC5nZXRUeChsb2NrZWRUeHMsIHByZXZMb2NrZWRUeC5nZXRIYXNoKCkpID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIG5vTG9uZ2VyTG9ja2VkSGFzaGVzLnB1c2gocHJldkxvY2tlZFR4LmdldEhhc2goKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBzYXZlIGxvY2tlZCB0eHMgZm9yIG5leHQgY29tcGFyaXNvblxuICAgICAgICB0aGF0LnByZXZMb2NrZWRUeHMgPSBsb2NrZWRUeHM7XG4gICAgICAgIFxuICAgICAgICAvLyBmZXRjaCB0eHMgd2hpY2ggYXJlIG5vIGxvbmdlciBsb2NrZWRcbiAgICAgICAgbGV0IHVubG9ja2VkVHhzID0gbm9Mb25nZXJMb2NrZWRIYXNoZXMubGVuZ3RoID09PSAwID8gW10gOiBhd2FpdCB0aGF0LndhbGxldC5nZXRUeHMobmV3IE1vbmVyb1R4UXVlcnkoKS5zZXRJc0xvY2tlZChmYWxzZSkuc2V0TWluSGVpZ2h0KG1pbkhlaWdodCkuc2V0SGFzaGVzKG5vTG9uZ2VyTG9ja2VkSGFzaGVzKS5zZXRJbmNsdWRlT3V0cHV0cyh0cnVlKSk7XG4gICAgICAgICBcbiAgICAgICAgLy8gYW5ub3VuY2UgbmV3IHVuY29uZmlybWVkIGFuZCBjb25maXJtZWQgb3V0cHV0c1xuICAgICAgICBmb3IgKGxldCBsb2NrZWRUeCBvZiBsb2NrZWRUeHMpIHtcbiAgICAgICAgICBsZXQgc2VhcmNoU2V0ID0gbG9ja2VkVHguZ2V0SXNDb25maXJtZWQoKSA/IHRoYXQucHJldkNvbmZpcm1lZE5vdGlmaWNhdGlvbnMgOiB0aGF0LnByZXZVbmNvbmZpcm1lZE5vdGlmaWNhdGlvbnM7XG4gICAgICAgICAgbGV0IHVuYW5ub3VuY2VkID0gIXNlYXJjaFNldC5oYXMobG9ja2VkVHguZ2V0SGFzaCgpKTtcbiAgICAgICAgICBzZWFyY2hTZXQuYWRkKGxvY2tlZFR4LmdldEhhc2goKSk7XG4gICAgICAgICAgaWYgKHVuYW5ub3VuY2VkKSBhd2FpdCB0aGF0Lm5vdGlmeU91dHB1dHMobG9ja2VkVHgpO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBhbm5vdW5jZSBuZXcgdW5sb2NrZWQgb3V0cHV0c1xuICAgICAgICBmb3IgKGxldCB1bmxvY2tlZFR4IG9mIHVubG9ja2VkVHhzKSB7XG4gICAgICAgICAgdGhhdC5wcmV2VW5jb25maXJtZWROb3RpZmljYXRpb25zLmRlbGV0ZSh1bmxvY2tlZFR4LmdldEhhc2goKSk7XG4gICAgICAgICAgdGhhdC5wcmV2Q29uZmlybWVkTm90aWZpY2F0aW9ucy5kZWxldGUodW5sb2NrZWRUeC5nZXRIYXNoKCkpO1xuICAgICAgICAgIGF3YWl0IHRoYXQubm90aWZ5T3V0cHV0cyh1bmxvY2tlZFR4KTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgLy8gYW5ub3VuY2UgYmFsYW5jZSBjaGFuZ2VzXG4gICAgICAgIGF3YWl0IHRoYXQuY2hlY2tGb3JDaGFuZ2VkQmFsYW5jZXMoKTtcbiAgICAgICAgdGhhdC5udW1Qb2xsaW5nLS07XG4gICAgICB9IGNhdGNoIChlcnI6IGFueSkge1xuICAgICAgICB0aGF0Lm51bVBvbGxpbmctLTtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkZhaWxlZCB0byBiYWNrZ3JvdW5kIHBvbGwgd2FsbGV0ICdcIiArIGF3YWl0IHRoYXQud2FsbGV0LmdldFBhdGgoKSArIFwiJzogXCIgKyBlcnIubWVzc2FnZSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBhc3luYyBvbk5ld0Jsb2NrKGhlaWdodCkge1xuICAgIGF3YWl0IHRoaXMud2FsbGV0LmFubm91bmNlTmV3QmxvY2soaGVpZ2h0KTtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIGFzeW5jIG5vdGlmeU91dHB1dHModHgpIHtcbiAgXG4gICAgLy8gbm90aWZ5IHNwZW50IG91dHB1dHMgLy8gVE9ETyAobW9uZXJvLXByb2plY3QpOiBtb25lcm8td2FsbGV0LXJwYyBkb2VzIG5vdCBhbGxvdyBzY3JhcGUgb2YgdHggaW5wdXRzIHNvIHByb3ZpZGluZyBvbmUgaW5wdXQgd2l0aCBvdXRnb2luZyBhbW91bnRcbiAgICBpZiAodHguZ2V0T3V0Z29pbmdUcmFuc2ZlcigpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGFzc2VydCh0eC5nZXRJbnB1dHMoKSA9PT0gdW5kZWZpbmVkKTtcbiAgICAgIGxldCBvdXRwdXQgPSBuZXcgTW9uZXJvT3V0cHV0V2FsbGV0KClcbiAgICAgICAgICAuc2V0QW1vdW50KHR4LmdldE91dGdvaW5nVHJhbnNmZXIoKS5nZXRBbW91bnQoKSArIHR4LmdldEZlZSgpKVxuICAgICAgICAgIC5zZXRBY2NvdW50SW5kZXgodHguZ2V0T3V0Z29pbmdUcmFuc2ZlcigpLmdldEFjY291bnRJbmRleCgpKVxuICAgICAgICAgIC5zZXRTdWJhZGRyZXNzSW5kZXgodHguZ2V0T3V0Z29pbmdUcmFuc2ZlcigpLmdldFN1YmFkZHJlc3NJbmRpY2VzKCkubGVuZ3RoID09PSAxID8gdHguZ2V0T3V0Z29pbmdUcmFuc2ZlcigpLmdldFN1YmFkZHJlc3NJbmRpY2VzKClbMF0gOiB1bmRlZmluZWQpIC8vIGluaXRpYWxpemUgaWYgdHJhbnNmZXIgc291cmNlZCBmcm9tIHNpbmdsZSBzdWJhZGRyZXNzXG4gICAgICAgICAgLnNldFR4KHR4KTtcbiAgICAgIHR4LnNldElucHV0cyhbb3V0cHV0XSk7XG4gICAgICBhd2FpdCB0aGlzLndhbGxldC5hbm5vdW5jZU91dHB1dFNwZW50KG91dHB1dCk7XG4gICAgfVxuICAgIFxuICAgIC8vIG5vdGlmeSByZWNlaXZlZCBvdXRwdXRzXG4gICAgaWYgKHR4LmdldEluY29taW5nVHJhbnNmZXJzKCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgaWYgKHR4LmdldE91dHB1dHMoKSAhPT0gdW5kZWZpbmVkICYmIHR4LmdldE91dHB1dHMoKS5sZW5ndGggPiAwKSB7IC8vIFRPRE8gKG1vbmVyby1wcm9qZWN0KTogb3V0cHV0cyBvbmx5IHJldHVybmVkIGZvciBjb25maXJtZWQgdHhzXG4gICAgICAgIGZvciAobGV0IG91dHB1dCBvZiB0eC5nZXRPdXRwdXRzKCkpIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLndhbGxldC5hbm5vdW5jZU91dHB1dFJlY2VpdmVkKG91dHB1dCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7IC8vIFRPRE8gKG1vbmVyby1wcm9qZWN0KTogbW9uZXJvLXdhbGxldC1ycGMgZG9lcyBub3QgYWxsb3cgc2NyYXBlIG9mIHVuY29uZmlybWVkIHJlY2VpdmVkIG91dHB1dHMgc28gdXNpbmcgaW5jb21pbmcgdHJhbnNmZXIgdmFsdWVzXG4gICAgICAgIGxldCBvdXRwdXRzID0gW107XG4gICAgICAgIGZvciAobGV0IHRyYW5zZmVyIG9mIHR4LmdldEluY29taW5nVHJhbnNmZXJzKCkpIHtcbiAgICAgICAgICBvdXRwdXRzLnB1c2gobmV3IE1vbmVyb091dHB1dFdhbGxldCgpXG4gICAgICAgICAgICAgIC5zZXRBY2NvdW50SW5kZXgodHJhbnNmZXIuZ2V0QWNjb3VudEluZGV4KCkpXG4gICAgICAgICAgICAgIC5zZXRTdWJhZGRyZXNzSW5kZXgodHJhbnNmZXIuZ2V0U3ViYWRkcmVzc0luZGV4KCkpXG4gICAgICAgICAgICAgIC5zZXRBbW91bnQodHJhbnNmZXIuZ2V0QW1vdW50KCkpXG4gICAgICAgICAgICAgIC5zZXRUeCh0eCkpO1xuICAgICAgICB9XG4gICAgICAgIHR4LnNldE91dHB1dHMob3V0cHV0cyk7XG4gICAgICAgIGZvciAobGV0IG91dHB1dCBvZiB0eC5nZXRPdXRwdXRzKCkpIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLndhbGxldC5hbm5vdW5jZU91dHB1dFJlY2VpdmVkKG91dHB1dCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgXG4gIHByb3RlY3RlZCBnZXRUeCh0eHMsIHR4SGFzaCkge1xuICAgIGZvciAobGV0IHR4IG9mIHR4cykgaWYgKHR4SGFzaCA9PT0gdHguZ2V0SGFzaCgpKSByZXR1cm4gdHg7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICBcbiAgcHJvdGVjdGVkIGFzeW5jIGNoZWNrRm9yQ2hhbmdlZEJhbGFuY2VzKCkge1xuICAgIGxldCBiYWxhbmNlcyA9IGF3YWl0IHRoaXMud2FsbGV0LmdldEJhbGFuY2VzKCk7XG4gICAgaWYgKGJhbGFuY2VzWzBdICE9PSB0aGlzLnByZXZCYWxhbmNlc1swXSB8fCBiYWxhbmNlc1sxXSAhPT0gdGhpcy5wcmV2QmFsYW5jZXNbMV0pIHtcbiAgICAgIHRoaXMucHJldkJhbGFuY2VzID0gYmFsYW5jZXM7XG4gICAgICBhd2FpdCB0aGlzLndhbGxldC5hbm5vdW5jZUJhbGFuY2VzQ2hhbmdlZChiYWxhbmNlc1swXSwgYmFsYW5jZXNbMV0pO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsT0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsU0FBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUUsYUFBQSxHQUFBSCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUcsV0FBQSxHQUFBSixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUksY0FBQSxHQUFBTCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUssaUJBQUEsR0FBQU4sc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFNLHVCQUFBLEdBQUFQLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBTyxZQUFBLEdBQUFSLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBUSxrQkFBQSxHQUFBVCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQVMsbUJBQUEsR0FBQVYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFVLGNBQUEsR0FBQVgsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFXLGtCQUFBLEdBQUFaLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBWSxZQUFBLEdBQUFiLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBYSx1QkFBQSxHQUFBZCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQWMsd0JBQUEsR0FBQWYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFlLGVBQUEsR0FBQWhCLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBZ0IsMkJBQUEsR0FBQWpCLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBaUIsbUJBQUEsR0FBQWxCLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBa0IseUJBQUEsR0FBQW5CLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBbUIseUJBQUEsR0FBQXBCLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBb0IsdUJBQUEsR0FBQXJCLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBcUIsa0JBQUEsR0FBQXRCLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBc0IsbUJBQUEsR0FBQXZCLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBdUIsb0JBQUEsR0FBQXhCLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBd0IsZUFBQSxHQUFBekIsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUF5QixpQkFBQSxHQUFBMUIsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUEwQixpQkFBQSxHQUFBM0Isc0JBQUEsQ0FBQUMsT0FBQTs7QUFFQSxJQUFBMkIsb0JBQUEsR0FBQTVCLHNCQUFBLENBQUFDLE9BQUE7O0FBRUEsSUFBQTRCLGVBQUEsR0FBQTdCLHNCQUFBLENBQUFDLE9BQUE7O0FBRUEsSUFBQTZCLGNBQUEsR0FBQTlCLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBOEIsWUFBQSxHQUFBL0Isc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUErQixlQUFBLEdBQUFoQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQWdDLFlBQUEsR0FBQWpDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBaUMsY0FBQSxHQUFBbEMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFrQyxhQUFBLEdBQUFuQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQW1DLG1CQUFBLEdBQUFwQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQW9DLHFCQUFBLEdBQUFyQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQXFDLDJCQUFBLEdBQUF0QyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQXNDLDZCQUFBLEdBQUF2QyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQXVDLFdBQUEsR0FBQXhDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBd0MsV0FBQSxHQUFBekMsc0JBQUEsQ0FBQUMsT0FBQSwwQkFBOEMsU0FBQXlDLHlCQUFBQyxXQUFBLGNBQUFDLE9BQUEsaUNBQUFDLGlCQUFBLE9BQUFELE9BQUEsT0FBQUUsZ0JBQUEsT0FBQUYsT0FBQSxXQUFBRix3QkFBQSxZQUFBQSxDQUFBQyxXQUFBLFVBQUFBLFdBQUEsR0FBQUcsZ0JBQUEsR0FBQUQsaUJBQUEsSUFBQUYsV0FBQSxZQUFBSSx3QkFBQUMsR0FBQSxFQUFBTCxXQUFBLFFBQUFBLFdBQUEsSUFBQUssR0FBQSxJQUFBQSxHQUFBLENBQUFDLFVBQUEsVUFBQUQsR0FBQSxNQUFBQSxHQUFBLG9CQUFBQSxHQUFBLHdCQUFBQSxHQUFBLDJCQUFBRSxPQUFBLEVBQUFGLEdBQUEsUUFBQUcsS0FBQSxHQUFBVCx3QkFBQSxDQUFBQyxXQUFBLE1BQUFRLEtBQUEsSUFBQUEsS0FBQSxDQUFBQyxHQUFBLENBQUFKLEdBQUEsV0FBQUcsS0FBQSxDQUFBRSxHQUFBLENBQUFMLEdBQUEsT0FBQU0sTUFBQSxVQUFBQyxxQkFBQSxHQUFBQyxNQUFBLENBQUFDLGNBQUEsSUFBQUQsTUFBQSxDQUFBRSx3QkFBQSxVQUFBQyxHQUFBLElBQUFYLEdBQUEsT0FBQVcsR0FBQSxrQkFBQUgsTUFBQSxDQUFBSSxTQUFBLENBQUFDLGNBQUEsQ0FBQUMsSUFBQSxDQUFBZCxHQUFBLEVBQUFXLEdBQUEsUUFBQUksSUFBQSxHQUFBUixxQkFBQSxHQUFBQyxNQUFBLENBQUFFLHdCQUFBLENBQUFWLEdBQUEsRUFBQVcsR0FBQSxhQUFBSSxJQUFBLEtBQUFBLElBQUEsQ0FBQVYsR0FBQSxJQUFBVSxJQUFBLENBQUFDLEdBQUEsSUFBQVIsTUFBQSxDQUFBQyxjQUFBLENBQUFILE1BQUEsRUFBQUssR0FBQSxFQUFBSSxJQUFBLFVBQUFULE1BQUEsQ0FBQUssR0FBQSxJQUFBWCxHQUFBLENBQUFXLEdBQUEsS0FBQUwsTUFBQSxDQUFBSixPQUFBLEdBQUFGLEdBQUEsS0FBQUcsS0FBQSxHQUFBQSxLQUFBLENBQUFhLEdBQUEsQ0FBQWhCLEdBQUEsRUFBQU0sTUFBQSxVQUFBQSxNQUFBOzs7QUFHOUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDZSxNQUFNVyxlQUFlLFNBQVNDLHFCQUFZLENBQUM7O0VBRXhEO0VBQ0EsT0FBMEJDLHlCQUF5QixHQUFHLEtBQUssQ0FBQyxDQUFDOztFQUU3RDs7Ozs7Ozs7OztFQVVBO0VBQ0FDLFdBQVdBLENBQUNDLE1BQTBCLEVBQUU7SUFDdEMsS0FBSyxDQUFDLENBQUM7SUFDUCxJQUFJLENBQUNBLE1BQU0sR0FBR0EsTUFBTTtJQUNwQixJQUFJLENBQUNDLFlBQVksR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLElBQUksQ0FBQ0MsY0FBYyxHQUFHTixlQUFlLENBQUNFLHlCQUF5QjtFQUNqRTs7RUFFQTs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0VBQ0VLLFVBQVVBLENBQUEsRUFBaUI7SUFDekIsT0FBTyxJQUFJLENBQUNDLE9BQU87RUFDckI7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsTUFBTUMsV0FBV0EsQ0FBQ0MsS0FBSyxHQUFHLEtBQUssRUFBZ0M7SUFDN0QsSUFBSSxJQUFJLENBQUNGLE9BQU8sS0FBS0csU0FBUyxFQUFFLE1BQU0sSUFBSUMsb0JBQVcsQ0FBQyx1REFBdUQsQ0FBQztJQUM5RyxJQUFJQyxhQUFhLEdBQUdDLGlCQUFRLENBQUNDLFNBQVMsQ0FBQyxJQUFJLENBQUNDLFlBQVksQ0FBQyxDQUFDLENBQUM7SUFDM0QsS0FBSyxJQUFJQyxRQUFRLElBQUlKLGFBQWEsRUFBRSxNQUFNLElBQUksQ0FBQ0ssY0FBYyxDQUFDRCxRQUFRLENBQUM7SUFDdkUsT0FBT0gsaUJBQVEsQ0FBQ0ssV0FBVyxDQUFDLElBQUksQ0FBQ1gsT0FBTyxFQUFFRSxLQUFLLEdBQUcsU0FBUyxHQUFHQyxTQUFTLENBQUM7RUFDMUU7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtFQUNFUyxnQkFBZ0JBLENBQUEsRUFBb0M7SUFDbEQsT0FBTyxJQUFJLENBQUNoQixNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQztFQUNoQzs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDRSxNQUFNQyxVQUFVQSxDQUFDQyxZQUFrRCxFQUFFQyxRQUFpQixFQUE0Qjs7SUFFaEg7SUFDQSxJQUFJcEIsTUFBTSxHQUFHLElBQUlxQiwyQkFBa0IsQ0FBQyxPQUFPRixZQUFZLEtBQUssUUFBUSxHQUFHLEVBQUNHLElBQUksRUFBRUgsWUFBWSxFQUFFQyxRQUFRLEVBQUVBLFFBQVEsR0FBR0EsUUFBUSxHQUFHLEVBQUUsRUFBQyxHQUFHRCxZQUFZLENBQUM7SUFDL0k7O0lBRUE7SUFDQSxJQUFJLENBQUNuQixNQUFNLENBQUN1QixPQUFPLENBQUMsQ0FBQyxFQUFFLE1BQU0sSUFBSWYsb0JBQVcsQ0FBQyxxQ0FBcUMsQ0FBQztJQUNuRixNQUFNLElBQUksQ0FBQ1IsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLGFBQWEsRUFBRSxFQUFDQyxRQUFRLEVBQUV6QixNQUFNLENBQUN1QixPQUFPLENBQUMsQ0FBQyxFQUFFSCxRQUFRLEVBQUVwQixNQUFNLENBQUMwQixXQUFXLENBQUMsQ0FBQyxFQUFDLENBQUM7SUFDMUgsTUFBTSxJQUFJLENBQUNDLEtBQUssQ0FBQyxDQUFDO0lBQ2xCLElBQUksQ0FBQ0wsSUFBSSxHQUFHdEIsTUFBTSxDQUFDdUIsT0FBTyxDQUFDLENBQUM7O0lBRTVCO0lBQ0EsSUFBSXZCLE1BQU0sQ0FBQzRCLG9CQUFvQixDQUFDLENBQUMsSUFBSSxJQUFJLEVBQUU7TUFDekMsSUFBSTVCLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxJQUFJVCxvQkFBVyxDQUFDLHVFQUF1RSxDQUFDO01BQ3RILE1BQU0sSUFBSSxDQUFDcUIsb0JBQW9CLENBQUM3QixNQUFNLENBQUM0QixvQkFBb0IsQ0FBQyxDQUFDLENBQUM7SUFDaEUsQ0FBQyxNQUFNLElBQUk1QixNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxJQUFJLElBQUksRUFBRTtNQUNyQyxNQUFNLElBQUksQ0FBQ2EsbUJBQW1CLENBQUM5QixNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQ3BEOztJQUVBLE9BQU8sSUFBSTtFQUNiOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNFLE1BQU1jLFlBQVlBLENBQUMvQixNQUFtQyxFQUE0Qjs7SUFFaEY7SUFDQSxJQUFJQSxNQUFNLEtBQUtPLFNBQVMsRUFBRSxNQUFNLElBQUlDLG9CQUFXLENBQUMsc0NBQXNDLENBQUM7SUFDdkYsTUFBTXdCLGdCQUFnQixHQUFHLElBQUlYLDJCQUFrQixDQUFDckIsTUFBTSxDQUFDO0lBQ3ZELElBQUlnQyxnQkFBZ0IsQ0FBQ0MsT0FBTyxDQUFDLENBQUMsS0FBSzFCLFNBQVMsS0FBS3lCLGdCQUFnQixDQUFDRSxpQkFBaUIsQ0FBQyxDQUFDLEtBQUszQixTQUFTLElBQUl5QixnQkFBZ0IsQ0FBQ0csaUJBQWlCLENBQUMsQ0FBQyxLQUFLNUIsU0FBUyxJQUFJeUIsZ0JBQWdCLENBQUNJLGtCQUFrQixDQUFDLENBQUMsS0FBSzdCLFNBQVMsQ0FBQyxFQUFFO01BQ2pOLE1BQU0sSUFBSUMsb0JBQVcsQ0FBQyw0REFBNEQsQ0FBQztJQUNyRjtJQUNBLElBQUl3QixnQkFBZ0IsQ0FBQ0ssY0FBYyxDQUFDLENBQUMsS0FBSzlCLFNBQVMsRUFBRSxNQUFNLElBQUlDLG9CQUFXLENBQUMsa0dBQWtHLENBQUM7SUFDOUssSUFBSXdCLGdCQUFnQixDQUFDTSxtQkFBbUIsQ0FBQyxDQUFDLEtBQUsvQixTQUFTLElBQUl5QixnQkFBZ0IsQ0FBQ08sc0JBQXNCLENBQUMsQ0FBQyxLQUFLaEMsU0FBUyxFQUFFLE1BQU0sSUFBSUMsb0JBQVcsQ0FBQyx3RkFBd0YsQ0FBQztJQUNwTyxJQUFJd0IsZ0JBQWdCLENBQUNOLFdBQVcsQ0FBQyxDQUFDLEtBQUtuQixTQUFTLEVBQUV5QixnQkFBZ0IsQ0FBQ1EsV0FBVyxDQUFDLEVBQUUsQ0FBQzs7SUFFbEY7SUFDQSxJQUFJUixnQkFBZ0IsQ0FBQ0osb0JBQW9CLENBQUMsQ0FBQyxFQUFFO01BQzNDLElBQUlJLGdCQUFnQixDQUFDZixTQUFTLENBQUMsQ0FBQyxFQUFFLE1BQU0sSUFBSVQsb0JBQVcsQ0FBQyx3RUFBd0UsQ0FBQztNQUNqSXdCLGdCQUFnQixDQUFDUyxTQUFTLENBQUN6QyxNQUFNLENBQUM0QixvQkFBb0IsQ0FBQyxDQUFDLENBQUNjLGFBQWEsQ0FBQyxDQUFDLENBQUM7SUFDM0U7O0lBRUE7SUFDQSxJQUFJVixnQkFBZ0IsQ0FBQ0MsT0FBTyxDQUFDLENBQUMsS0FBSzFCLFNBQVMsRUFBRSxNQUFNLElBQUksQ0FBQ29DLG9CQUFvQixDQUFDWCxnQkFBZ0IsQ0FBQyxDQUFDO0lBQzNGLElBQUlBLGdCQUFnQixDQUFDSSxrQkFBa0IsQ0FBQyxDQUFDLEtBQUs3QixTQUFTLElBQUl5QixnQkFBZ0IsQ0FBQ0UsaUJBQWlCLENBQUMsQ0FBQyxLQUFLM0IsU0FBUyxFQUFFLE1BQU0sSUFBSSxDQUFDcUMsb0JBQW9CLENBQUNaLGdCQUFnQixDQUFDLENBQUM7SUFDakssTUFBTSxJQUFJLENBQUNhLGtCQUFrQixDQUFDYixnQkFBZ0IsQ0FBQzs7SUFFcEQ7SUFDQSxJQUFJQSxnQkFBZ0IsQ0FBQ0osb0JBQW9CLENBQUMsQ0FBQyxFQUFFO01BQzNDLE1BQU0sSUFBSSxDQUFDQyxvQkFBb0IsQ0FBQ0csZ0JBQWdCLENBQUNKLG9CQUFvQixDQUFDLENBQUMsQ0FBQztJQUMxRSxDQUFDLE1BQU0sSUFBSUksZ0JBQWdCLENBQUNmLFNBQVMsQ0FBQyxDQUFDLEVBQUU7TUFDdkMsTUFBTSxJQUFJLENBQUNhLG1CQUFtQixDQUFDRSxnQkFBZ0IsQ0FBQ2YsU0FBUyxDQUFDLENBQUMsQ0FBQztJQUM5RDs7SUFFQSxPQUFPLElBQUk7RUFDYjs7RUFFQSxNQUFnQjRCLGtCQUFrQkEsQ0FBQzdDLE1BQTBCLEVBQUU7SUFDN0QsSUFBSUEsTUFBTSxDQUFDOEMsYUFBYSxDQUFDLENBQUMsS0FBS3ZDLFNBQVMsRUFBRSxNQUFNLElBQUlDLG9CQUFXLENBQUMsdURBQXVELENBQUM7SUFDeEgsSUFBSVIsTUFBTSxDQUFDK0MsZ0JBQWdCLENBQUMsQ0FBQyxLQUFLeEMsU0FBUyxFQUFFLE1BQU0sSUFBSUMsb0JBQVcsQ0FBQywwREFBMEQsQ0FBQztJQUM5SCxJQUFJUixNQUFNLENBQUNnRCxjQUFjLENBQUMsQ0FBQyxLQUFLLEtBQUssRUFBRSxNQUFNLElBQUl4QyxvQkFBVyxDQUFDLG1FQUFtRSxDQUFDO0lBQ2pJLElBQUksQ0FBQ1IsTUFBTSxDQUFDdUIsT0FBTyxDQUFDLENBQUMsRUFBRSxNQUFNLElBQUlmLG9CQUFXLENBQUMseUJBQXlCLENBQUM7SUFDdkUsSUFBSSxDQUFDUixNQUFNLENBQUNpRCxXQUFXLENBQUMsQ0FBQyxFQUFFakQsTUFBTSxDQUFDa0QsV0FBVyxDQUFDckQscUJBQVksQ0FBQ3NELGdCQUFnQixDQUFDO0lBQzVFLElBQUlDLE1BQU0sR0FBRyxFQUFFM0IsUUFBUSxFQUFFekIsTUFBTSxDQUFDdUIsT0FBTyxDQUFDLENBQUMsRUFBRUgsUUFBUSxFQUFFcEIsTUFBTSxDQUFDMEIsV0FBVyxDQUFDLENBQUMsRUFBRTJCLFFBQVEsRUFBRXJELE1BQU0sQ0FBQ2lELFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMzRyxJQUFJO01BQ0YsTUFBTSxJQUFJLENBQUNqRCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsZUFBZSxFQUFFNEIsTUFBTSxDQUFDO0lBQ3hFLENBQUMsQ0FBQyxPQUFPRSxHQUFRLEVBQUU7TUFDakIsSUFBSSxDQUFDQyx1QkFBdUIsQ0FBQ3ZELE1BQU0sQ0FBQ3VCLE9BQU8sQ0FBQyxDQUFDLEVBQUUrQixHQUFHLENBQUM7SUFDckQ7SUFDQSxNQUFNLElBQUksQ0FBQzNCLEtBQUssQ0FBQyxDQUFDO0lBQ2xCLElBQUksQ0FBQ0wsSUFBSSxHQUFHdEIsTUFBTSxDQUFDdUIsT0FBTyxDQUFDLENBQUM7SUFDNUIsT0FBTyxJQUFJO0VBQ2I7O0VBRUEsTUFBZ0JvQixvQkFBb0JBLENBQUMzQyxNQUEwQixFQUFFO0lBQy9ELElBQUk7TUFDRixNQUFNLElBQUksQ0FBQ0EsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLDhCQUE4QixFQUFFO1FBQzVFQyxRQUFRLEVBQUV6QixNQUFNLENBQUN1QixPQUFPLENBQUMsQ0FBQztRQUMxQkgsUUFBUSxFQUFFcEIsTUFBTSxDQUFDMEIsV0FBVyxDQUFDLENBQUM7UUFDOUI4QixJQUFJLEVBQUV4RCxNQUFNLENBQUNpQyxPQUFPLENBQUMsQ0FBQztRQUN0QndCLFdBQVcsRUFBRXpELE1BQU0sQ0FBQzhDLGFBQWEsQ0FBQyxDQUFDO1FBQ25DWSw0QkFBNEIsRUFBRTFELE1BQU0sQ0FBQzJELGFBQWEsQ0FBQyxDQUFDO1FBQ3BEQyxjQUFjLEVBQUU1RCxNQUFNLENBQUMrQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3pDTSxRQUFRLEVBQUVyRCxNQUFNLENBQUNpRCxXQUFXLENBQUMsQ0FBQztRQUM5QlksZ0JBQWdCLEVBQUU3RCxNQUFNLENBQUNnRCxjQUFjLENBQUM7TUFDMUMsQ0FBQyxDQUFDO0lBQ0osQ0FBQyxDQUFDLE9BQU9NLEdBQVEsRUFBRTtNQUNqQixJQUFJLENBQUNDLHVCQUF1QixDQUFDdkQsTUFBTSxDQUFDdUIsT0FBTyxDQUFDLENBQUMsRUFBRStCLEdBQUcsQ0FBQztJQUNyRDtJQUNBLE1BQU0sSUFBSSxDQUFDM0IsS0FBSyxDQUFDLENBQUM7SUFDbEIsSUFBSSxDQUFDTCxJQUFJLEdBQUd0QixNQUFNLENBQUN1QixPQUFPLENBQUMsQ0FBQztJQUM1QixPQUFPLElBQUk7RUFDYjs7RUFFQSxNQUFnQnFCLG9CQUFvQkEsQ0FBQzVDLE1BQTBCLEVBQUU7SUFDL0QsSUFBSUEsTUFBTSxDQUFDOEMsYUFBYSxDQUFDLENBQUMsS0FBS3ZDLFNBQVMsRUFBRSxNQUFNLElBQUlDLG9CQUFXLENBQUMsMERBQTBELENBQUM7SUFDM0gsSUFBSVIsTUFBTSxDQUFDK0MsZ0JBQWdCLENBQUMsQ0FBQyxLQUFLeEMsU0FBUyxFQUFFUCxNQUFNLENBQUM4RCxnQkFBZ0IsQ0FBQyxDQUFDLENBQUM7SUFDdkUsSUFBSTlELE1BQU0sQ0FBQ2lELFdBQVcsQ0FBQyxDQUFDLEtBQUsxQyxTQUFTLEVBQUVQLE1BQU0sQ0FBQ2tELFdBQVcsQ0FBQ3JELHFCQUFZLENBQUNzRCxnQkFBZ0IsQ0FBQztJQUN6RixJQUFJO01BQ0YsTUFBTSxJQUFJLENBQUNuRCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsb0JBQW9CLEVBQUU7UUFDbEVDLFFBQVEsRUFBRXpCLE1BQU0sQ0FBQ3VCLE9BQU8sQ0FBQyxDQUFDO1FBQzFCSCxRQUFRLEVBQUVwQixNQUFNLENBQUMwQixXQUFXLENBQUMsQ0FBQztRQUM5QnFDLE9BQU8sRUFBRS9ELE1BQU0sQ0FBQ2tDLGlCQUFpQixDQUFDLENBQUM7UUFDbkM4QixPQUFPLEVBQUVoRSxNQUFNLENBQUNtQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQ25DOEIsUUFBUSxFQUFFakUsTUFBTSxDQUFDb0Msa0JBQWtCLENBQUMsQ0FBQztRQUNyQ3dCLGNBQWMsRUFBRTVELE1BQU0sQ0FBQytDLGdCQUFnQixDQUFDLENBQUM7UUFDekNjLGdCQUFnQixFQUFFN0QsTUFBTSxDQUFDZ0QsY0FBYyxDQUFDO01BQzFDLENBQUMsQ0FBQztJQUNKLENBQUMsQ0FBQyxPQUFPTSxHQUFRLEVBQUU7TUFDakIsSUFBSSxDQUFDQyx1QkFBdUIsQ0FBQ3ZELE1BQU0sQ0FBQ3VCLE9BQU8sQ0FBQyxDQUFDLEVBQUUrQixHQUFHLENBQUM7SUFDckQ7SUFDQSxNQUFNLElBQUksQ0FBQzNCLEtBQUssQ0FBQyxDQUFDO0lBQ2xCLElBQUksQ0FBQ0wsSUFBSSxHQUFHdEIsTUFBTSxDQUFDdUIsT0FBTyxDQUFDLENBQUM7SUFDNUIsT0FBTyxJQUFJO0VBQ2I7O0VBRVVnQyx1QkFBdUJBLENBQUNXLElBQUksRUFBRVosR0FBRyxFQUFFO0lBQzNDLElBQUlBLEdBQUcsQ0FBQ2EsT0FBTyxFQUFFO01BQ2YsSUFBSWIsR0FBRyxDQUFDYSxPQUFPLENBQUNDLFdBQVcsQ0FBQyxDQUFDLENBQUNDLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLE1BQU0sSUFBSUMsdUJBQWMsQ0FBQyx5QkFBeUIsR0FBR0osSUFBSSxFQUFFWixHQUFHLENBQUNpQixPQUFPLENBQUMsQ0FBQyxFQUFFakIsR0FBRyxDQUFDa0IsWUFBWSxDQUFDLENBQUMsRUFBRWxCLEdBQUcsQ0FBQ21CLFlBQVksQ0FBQyxDQUFDLENBQUM7TUFDM0ssSUFBSW5CLEdBQUcsQ0FBQ2EsT0FBTyxDQUFDQyxXQUFXLENBQUMsQ0FBQyxDQUFDQyxRQUFRLENBQUMsK0JBQStCLENBQUMsRUFBRSxNQUFNLElBQUlDLHVCQUFjLENBQUMsa0JBQWtCLEVBQUVoQixHQUFHLENBQUNpQixPQUFPLENBQUMsQ0FBQyxFQUFFakIsR0FBRyxDQUFDa0IsWUFBWSxDQUFDLENBQUMsRUFBRWxCLEdBQUcsQ0FBQ21CLFlBQVksQ0FBQyxDQUFDLENBQUM7SUFDOUs7SUFDQSxNQUFNbkIsR0FBRztFQUNYOztFQUVBLE1BQU1vQixVQUFVQSxDQUFBLEVBQXFCO0lBQ25DLElBQUk7TUFDRixNQUFNLElBQUksQ0FBQzFFLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxXQUFXLEVBQUUsRUFBQ21ELFFBQVEsRUFBRSxVQUFVLEVBQUMsQ0FBQztNQUNsRixPQUFPLEtBQUssQ0FBQyxDQUFDO0lBQ2hCLENBQUMsQ0FBQyxPQUFPQyxDQUFNLEVBQUU7TUFDZixJQUFJQSxDQUFDLENBQUNMLE9BQU8sQ0FBQyxDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUUsT0FBTyxJQUFJLENBQUMsQ0FBRTtNQUN2QyxJQUFJSyxDQUFDLENBQUNMLE9BQU8sQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsT0FBTyxLQUFLLENBQUMsQ0FBRTtNQUN2QyxNQUFNSyxDQUFDO0lBQ1Q7RUFDRjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNFLE1BQU05QyxtQkFBbUJBLENBQUMrQyxlQUE4QyxFQUFFQyxTQUFtQixFQUFFQyxVQUF1QixFQUFpQjtJQUNySSxJQUFJQyxVQUFVLEdBQUcsQ0FBQ0gsZUFBZSxHQUFHdEUsU0FBUyxHQUFHc0UsZUFBZSxZQUFZSSw0QkFBbUIsR0FBR0osZUFBZSxHQUFHLElBQUlJLDRCQUFtQixDQUFDSixlQUFlLENBQUM7SUFDM0osSUFBSSxDQUFDRSxVQUFVLEVBQUVBLFVBQVUsR0FBRyxJQUFJRyxtQkFBVSxDQUFDLENBQUM7SUFDOUMsSUFBSTlCLE1BQVcsR0FBRyxDQUFDLENBQUM7SUFDcEJBLE1BQU0sQ0FBQ1csT0FBTyxHQUFHaUIsVUFBVSxHQUFHQSxVQUFVLENBQUNHLE1BQU0sQ0FBQyxDQUFDLEdBQUcsU0FBUyxDQUFDLENBQUM7SUFDL0QvQixNQUFNLENBQUNnQyxRQUFRLEdBQUdKLFVBQVUsR0FBR0EsVUFBVSxDQUFDSyxXQUFXLENBQUMsQ0FBQyxHQUFHLEVBQUU7SUFDNURqQyxNQUFNLENBQUNoQyxRQUFRLEdBQUc0RCxVQUFVLEdBQUdBLFVBQVUsQ0FBQ3RELFdBQVcsQ0FBQyxDQUFDLEdBQUcsRUFBRTtJQUM1RDBCLE1BQU0sQ0FBQ2tDLE9BQU8sR0FBR1IsU0FBUztJQUMxQjFCLE1BQU0sQ0FBQ21DLFdBQVcsR0FBRyxZQUFZO0lBQ2pDbkMsTUFBTSxDQUFDb0Msb0JBQW9CLEdBQUdULFVBQVUsQ0FBQ1UsaUJBQWlCLENBQUMsQ0FBQztJQUM1RHJDLE1BQU0sQ0FBQ3NDLG9CQUFvQixHQUFJWCxVQUFVLENBQUNZLGtCQUFrQixDQUFDLENBQUM7SUFDOUR2QyxNQUFNLENBQUN3QyxXQUFXLEdBQUdiLFVBQVUsQ0FBQ2MsMkJBQTJCLENBQUMsQ0FBQztJQUM3RHpDLE1BQU0sQ0FBQzBDLHdCQUF3QixHQUFHZixVQUFVLENBQUNnQixzQkFBc0IsQ0FBQyxDQUFDO0lBQ3JFM0MsTUFBTSxDQUFDNEMsa0JBQWtCLEdBQUdqQixVQUFVLENBQUNrQixlQUFlLENBQUMsQ0FBQztJQUN4RDdDLE1BQU0sQ0FBQzhDLEtBQUssR0FBR2xCLFVBQVUsR0FBR0EsVUFBVSxDQUFDbUIsV0FBVyxDQUFDLENBQUMsR0FBRyxFQUFFO0lBQ3pELE1BQU0sSUFBSSxDQUFDbkcsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLFlBQVksRUFBRTRCLE1BQU0sQ0FBQztJQUNuRSxJQUFJLENBQUNnRCxnQkFBZ0IsR0FBR3BCLFVBQVU7RUFDcEM7O0VBRUEsTUFBTXFCLG1CQUFtQkEsQ0FBQSxFQUFpQztJQUN4RCxPQUFPLElBQUksQ0FBQ0QsZ0JBQWdCO0VBQzlCOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsTUFBTUUsV0FBV0EsQ0FBQ0MsVUFBbUIsRUFBRUMsYUFBc0IsRUFBcUI7SUFDaEYsSUFBSUQsVUFBVSxLQUFLaEcsU0FBUyxFQUFFO01BQzVCa0csZUFBTSxDQUFDQyxLQUFLLENBQUNGLGFBQWEsRUFBRWpHLFNBQVMsRUFBRSxrREFBa0QsQ0FBQztNQUMxRixJQUFJb0csT0FBTyxHQUFHQyxNQUFNLENBQUMsQ0FBQyxDQUFDO01BQ3ZCLElBQUlDLGVBQWUsR0FBR0QsTUFBTSxDQUFDLENBQUMsQ0FBQztNQUMvQixLQUFLLElBQUlFLE9BQU8sSUFBSSxNQUFNLElBQUksQ0FBQ0MsV0FBVyxDQUFDLENBQUMsRUFBRTtRQUM1Q0osT0FBTyxHQUFHQSxPQUFPLEdBQUdHLE9BQU8sQ0FBQ0UsVUFBVSxDQUFDLENBQUM7UUFDeENILGVBQWUsR0FBR0EsZUFBZSxHQUFHQyxPQUFPLENBQUNHLGtCQUFrQixDQUFDLENBQUM7TUFDbEU7TUFDQSxPQUFPLENBQUNOLE9BQU8sRUFBRUUsZUFBZSxDQUFDO0lBQ25DLENBQUMsTUFBTTtNQUNMLElBQUl6RCxNQUFNLEdBQUcsRUFBQzhELGFBQWEsRUFBRVgsVUFBVSxFQUFFWSxlQUFlLEVBQUVYLGFBQWEsS0FBS2pHLFNBQVMsR0FBR0EsU0FBUyxHQUFHLENBQUNpRyxhQUFhLENBQUMsRUFBQztNQUNwSCxJQUFJWSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsYUFBYSxFQUFFNEIsTUFBTSxDQUFDO01BQy9FLElBQUlvRCxhQUFhLEtBQUtqRyxTQUFTLEVBQUUsT0FBTyxDQUFDcUcsTUFBTSxDQUFDUSxJQUFJLENBQUNDLE1BQU0sQ0FBQ1YsT0FBTyxDQUFDLEVBQUVDLE1BQU0sQ0FBQ1EsSUFBSSxDQUFDQyxNQUFNLENBQUNDLGdCQUFnQixDQUFDLENBQUMsQ0FBQztNQUN2RyxPQUFPLENBQUNWLE1BQU0sQ0FBQ1EsSUFBSSxDQUFDQyxNQUFNLENBQUNFLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQ1osT0FBTyxDQUFDLEVBQUVDLE1BQU0sQ0FBQ1EsSUFBSSxDQUFDQyxNQUFNLENBQUNFLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQ0QsZ0JBQWdCLENBQUMsQ0FBQztJQUNySDtFQUNGOztFQUVBOztFQUVBLE1BQU1FLFdBQVdBLENBQUMzRyxRQUE4QixFQUFpQjtJQUMvRCxNQUFNLEtBQUssQ0FBQzJHLFdBQVcsQ0FBQzNHLFFBQVEsQ0FBQztJQUNqQyxJQUFJLENBQUM0RyxnQkFBZ0IsQ0FBQyxDQUFDO0VBQ3pCOztFQUVBLE1BQU0zRyxjQUFjQSxDQUFDRCxRQUFRLEVBQWlCO0lBQzVDLE1BQU0sS0FBSyxDQUFDQyxjQUFjLENBQUNELFFBQVEsQ0FBQztJQUNwQyxJQUFJLENBQUM0RyxnQkFBZ0IsQ0FBQyxDQUFDO0VBQ3pCOztFQUVBLE1BQU1DLG1CQUFtQkEsQ0FBQSxFQUFxQjtJQUM1QyxJQUFJO01BQ0YsTUFBTSxJQUFJLENBQUNDLGlCQUFpQixDQUFDLE1BQU0sSUFBSSxDQUFDekYsaUJBQWlCLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO01BQ3RFLE1BQU0sSUFBSTFCLG9CQUFXLENBQUMsZ0NBQWdDLENBQUM7SUFDekQsQ0FBQyxDQUFDLE9BQU9vRSxDQUFNLEVBQUU7TUFDZixPQUFPQSxDQUFDLENBQUNULE9BQU8sQ0FBQ3lELE9BQU8sQ0FBQyw2QkFBNkIsQ0FBQyxHQUFHLENBQUM7SUFDN0Q7RUFDRjs7RUFFQSxNQUFNQyxVQUFVQSxDQUFBLEVBQTJCO0lBQ3pDLElBQUlULElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxhQUFhLENBQUM7SUFDdkUsT0FBTyxJQUFJc0csc0JBQWEsQ0FBQ1YsSUFBSSxDQUFDQyxNQUFNLENBQUNVLE9BQU8sRUFBRVgsSUFBSSxDQUFDQyxNQUFNLENBQUNXLE9BQU8sQ0FBQztFQUNwRTs7RUFFQSxNQUFNekcsT0FBT0EsQ0FBQSxFQUFvQjtJQUMvQixPQUFPLElBQUksQ0FBQ0QsSUFBSTtFQUNsQjs7RUFFQSxNQUFNVyxPQUFPQSxDQUFBLEVBQW9CO0lBQy9CLElBQUltRixJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsV0FBVyxFQUFFLEVBQUVtRCxRQUFRLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQztJQUMvRixPQUFPeUMsSUFBSSxDQUFDQyxNQUFNLENBQUMvSCxHQUFHO0VBQ3hCOztFQUVBLE1BQU0ySSxlQUFlQSxDQUFBLEVBQW9CO0lBQ3ZDLElBQUksT0FBTSxJQUFJLENBQUNoRyxPQUFPLENBQUMsQ0FBQyxNQUFLMUIsU0FBUyxFQUFFLE9BQU9BLFNBQVM7SUFDeEQsTUFBTSxJQUFJQyxvQkFBVyxDQUFDLGlEQUFpRCxDQUFDO0VBQzFFOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7RUFDRSxNQUFNMEgsZ0JBQWdCQSxDQUFBLEVBQUc7SUFDdkIsT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDbEksTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLGVBQWUsQ0FBQyxFQUFFNkYsTUFBTSxDQUFDYyxTQUFTO0VBQzFGOztFQUVBLE1BQU1oRyxpQkFBaUJBLENBQUEsRUFBb0I7SUFDekMsSUFBSWlGLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxXQUFXLEVBQUUsRUFBRW1ELFFBQVEsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQy9GLE9BQU95QyxJQUFJLENBQUNDLE1BQU0sQ0FBQy9ILEdBQUc7RUFDeEI7O0VBRUEsTUFBTThDLGtCQUFrQkEsQ0FBQSxFQUFvQjtJQUMxQyxJQUFJZ0YsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLFdBQVcsRUFBRSxFQUFFbUQsUUFBUSxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUM7SUFDaEcsT0FBT3lDLElBQUksQ0FBQ0MsTUFBTSxDQUFDL0gsR0FBRztFQUN4Qjs7RUFFQSxNQUFNOEksVUFBVUEsQ0FBQzdCLFVBQWtCLEVBQUVDLGFBQXFCLEVBQW1CO0lBQzNFLElBQUk2QixhQUFhLEdBQUcsSUFBSSxDQUFDcEksWUFBWSxDQUFDc0csVUFBVSxDQUFDO0lBQ2pELElBQUksQ0FBQzhCLGFBQWEsRUFBRTtNQUNsQixNQUFNLElBQUksQ0FBQ0MsZUFBZSxDQUFDL0IsVUFBVSxFQUFFaEcsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUU7TUFDMUQsT0FBTyxJQUFJLENBQUM2SCxVQUFVLENBQUM3QixVQUFVLEVBQUVDLGFBQWEsQ0FBQyxDQUFDLENBQVE7SUFDNUQ7SUFDQSxJQUFJekMsT0FBTyxHQUFHc0UsYUFBYSxDQUFDN0IsYUFBYSxDQUFDO0lBQzFDLElBQUksQ0FBQ3pDLE9BQU8sRUFBRTtNQUNaLE1BQU0sSUFBSSxDQUFDdUUsZUFBZSxDQUFDL0IsVUFBVSxFQUFFaEcsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUU7TUFDMUQsT0FBTyxJQUFJLENBQUNOLFlBQVksQ0FBQ3NHLFVBQVUsQ0FBQyxDQUFDQyxhQUFhLENBQUM7SUFDckQ7SUFDQSxPQUFPekMsT0FBTztFQUNoQjs7RUFFQTtFQUNBLE1BQU13RSxlQUFlQSxDQUFDeEUsT0FBZSxFQUE2Qjs7SUFFaEU7SUFDQSxJQUFJcUQsSUFBSTtJQUNSLElBQUk7TUFDRkEsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLG1CQUFtQixFQUFFLEVBQUN1QyxPQUFPLEVBQUVBLE9BQU8sRUFBQyxDQUFDO0lBQy9GLENBQUMsQ0FBQyxPQUFPYSxDQUFNLEVBQUU7TUFDZixJQUFJQSxDQUFDLENBQUNMLE9BQU8sQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsTUFBTSxJQUFJL0Qsb0JBQVcsQ0FBQ29FLENBQUMsQ0FBQ1QsT0FBTyxDQUFDO01BQ3hELE1BQU1TLENBQUM7SUFDVDs7SUFFQTtJQUNBLElBQUk0RCxVQUFVLEdBQUcsSUFBSUMseUJBQWdCLENBQUMsRUFBQzFFLE9BQU8sRUFBRUEsT0FBTyxFQUFDLENBQUM7SUFDekR5RSxVQUFVLENBQUNFLGVBQWUsQ0FBQ3RCLElBQUksQ0FBQ0MsTUFBTSxDQUFDc0IsS0FBSyxDQUFDQyxLQUFLLENBQUM7SUFDbkRKLFVBQVUsQ0FBQ0ssUUFBUSxDQUFDekIsSUFBSSxDQUFDQyxNQUFNLENBQUNzQixLQUFLLENBQUNHLEtBQUssQ0FBQztJQUM1QyxPQUFPTixVQUFVO0VBQ25COztFQUVBLE1BQU1PLG9CQUFvQkEsQ0FBQ0MsZUFBd0IsRUFBRUMsU0FBa0IsRUFBb0M7SUFDekcsSUFBSTtNQUNGLElBQUlDLG9CQUFvQixHQUFHLENBQUMsTUFBTSxJQUFJLENBQUNsSixNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMseUJBQXlCLEVBQUUsRUFBQzJILGdCQUFnQixFQUFFSCxlQUFlLEVBQUVJLFVBQVUsRUFBRUgsU0FBUyxFQUFDLENBQUMsRUFBRTVCLE1BQU0sQ0FBQ2dDLGtCQUFrQjtNQUMzTCxPQUFPLE1BQU0sSUFBSSxDQUFDQyx1QkFBdUIsQ0FBQ0osb0JBQW9CLENBQUM7SUFDakUsQ0FBQyxDQUFDLE9BQU90RSxDQUFNLEVBQUU7TUFDZixJQUFJQSxDQUFDLENBQUNULE9BQU8sQ0FBQ0UsUUFBUSxDQUFDLG9CQUFvQixDQUFDLEVBQUUsTUFBTSxJQUFJN0Qsb0JBQVcsQ0FBQyxzQkFBc0IsR0FBR3lJLFNBQVMsQ0FBQztNQUN2RyxNQUFNckUsQ0FBQztJQUNUO0VBQ0Y7O0VBRUEsTUFBTTBFLHVCQUF1QkEsQ0FBQ0MsaUJBQXlCLEVBQW9DO0lBQ3pGLElBQUluQyxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsMEJBQTBCLEVBQUUsRUFBQzZILGtCQUFrQixFQUFFRSxpQkFBaUIsRUFBQyxDQUFDO0lBQzdILE9BQU8sSUFBSUMsZ0NBQXVCLENBQUMsQ0FBQyxDQUFDQyxrQkFBa0IsQ0FBQ3JDLElBQUksQ0FBQ0MsTUFBTSxDQUFDOEIsZ0JBQWdCLENBQUMsQ0FBQ08sWUFBWSxDQUFDdEMsSUFBSSxDQUFDQyxNQUFNLENBQUMrQixVQUFVLENBQUMsQ0FBQ08sb0JBQW9CLENBQUNKLGlCQUFpQixDQUFDO0VBQ3BLOztFQUVBLE1BQU1LLFNBQVNBLENBQUEsRUFBb0I7SUFDakMsT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDNUosTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLFlBQVksQ0FBQyxFQUFFNkYsTUFBTSxDQUFDd0MsTUFBTTtFQUNwRjs7RUFFQSxNQUFNQyxlQUFlQSxDQUFBLEVBQW9CO0lBQ3ZDLE1BQU0sSUFBSXRKLG9CQUFXLENBQUMsNkRBQTZELENBQUM7RUFDdEY7O0VBRUEsTUFBTXVKLGVBQWVBLENBQUNDLElBQVksRUFBRUMsS0FBYSxFQUFFQyxHQUFXLEVBQW1CO0lBQy9FLE1BQU0sSUFBSTFKLG9CQUFXLENBQUMsNkRBQTZELENBQUM7RUFDdEY7O0VBRUEsTUFBTTJKLElBQUlBLENBQUNDLHFCQUFxRCxFQUFFQyxXQUFvQixFQUE2QjtJQUNqSCxJQUFBNUQsZUFBTSxFQUFDLEVBQUUyRCxxQkFBcUIsWUFBWUUsNkJBQW9CLENBQUMsRUFBRSw0REFBNEQsQ0FBQztJQUM5SCxJQUFJO01BQ0YsSUFBSWxELElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxTQUFTLEVBQUUsRUFBQytJLFlBQVksRUFBRUYsV0FBVyxFQUFDLENBQUM7TUFDaEcsTUFBTSxJQUFJLENBQUNHLElBQUksQ0FBQyxDQUFDO01BQ2pCLE9BQU8sSUFBSUMseUJBQWdCLENBQUNyRCxJQUFJLENBQUNDLE1BQU0sQ0FBQ3FELGNBQWMsRUFBRXRELElBQUksQ0FBQ0MsTUFBTSxDQUFDc0QsY0FBYyxDQUFDO0lBQ3JGLENBQUMsQ0FBQyxPQUFPckgsR0FBUSxFQUFFO01BQ2pCLElBQUlBLEdBQUcsQ0FBQ2EsT0FBTyxLQUFLLHlCQUF5QixFQUFFLE1BQU0sSUFBSTNELG9CQUFXLENBQUMsbUNBQW1DLENBQUM7TUFDekcsTUFBTThDLEdBQUc7SUFDWDtFQUNGOztFQUVBLE1BQU1zSCxZQUFZQSxDQUFDMUssY0FBdUIsRUFBaUI7O0lBRXpEO0lBQ0EsSUFBSTJLLG1CQUFtQixHQUFHQyxJQUFJLENBQUNDLEtBQUssQ0FBQyxDQUFDN0ssY0FBYyxLQUFLSyxTQUFTLEdBQUdYLGVBQWUsQ0FBQ0UseUJBQXlCLEdBQUdJLGNBQWMsSUFBSSxJQUFJLENBQUM7O0lBRXhJO0lBQ0EsTUFBTSxJQUFJLENBQUNGLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxjQUFjLEVBQUU7TUFDNUR3SixNQUFNLEVBQUUsSUFBSTtNQUNaQyxNQUFNLEVBQUVKO0lBQ1YsQ0FBQyxDQUFDOztJQUVGO0lBQ0EsSUFBSSxDQUFDM0ssY0FBYyxHQUFHMkssbUJBQW1CLEdBQUcsSUFBSTtJQUNoRCxJQUFJLElBQUksQ0FBQ0ssWUFBWSxLQUFLM0ssU0FBUyxFQUFFLElBQUksQ0FBQzJLLFlBQVksQ0FBQ0MsYUFBYSxDQUFDLElBQUksQ0FBQ2pMLGNBQWMsQ0FBQzs7SUFFekY7SUFDQSxNQUFNLElBQUksQ0FBQ3NLLElBQUksQ0FBQyxDQUFDO0VBQ25COztFQUVBWSxpQkFBaUJBLENBQUEsRUFBVztJQUMxQixPQUFPLElBQUksQ0FBQ2xMLGNBQWM7RUFDNUI7O0VBRUEsTUFBTW1MLFdBQVdBLENBQUEsRUFBa0I7SUFDakMsT0FBTyxJQUFJLENBQUNyTCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsY0FBYyxFQUFFLEVBQUV3SixNQUFNLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztFQUNuRjs7RUFFQSxNQUFNTSxPQUFPQSxDQUFDQyxRQUFrQixFQUFpQjtJQUMvQyxJQUFJLENBQUNBLFFBQVEsSUFBSSxDQUFDQSxRQUFRLENBQUNDLE1BQU0sRUFBRSxNQUFNLElBQUloTCxvQkFBVyxDQUFDLDRCQUE0QixDQUFDO0lBQ3RGLE1BQU0sSUFBSSxDQUFDUixNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsU0FBUyxFQUFFLEVBQUNpSyxLQUFLLEVBQUVGLFFBQVEsRUFBQyxDQUFDO0lBQzNFLE1BQU0sSUFBSSxDQUFDZixJQUFJLENBQUMsQ0FBQztFQUNuQjs7RUFFQSxNQUFNa0IsV0FBV0EsQ0FBQSxFQUFrQjtJQUNqQyxNQUFNLElBQUksQ0FBQzFMLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxjQUFjLEVBQUVqQixTQUFTLENBQUM7RUFDMUU7O0VBRUEsTUFBTW9MLGdCQUFnQkEsQ0FBQSxFQUFrQjtJQUN0QyxNQUFNLElBQUksQ0FBQzNMLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxtQkFBbUIsRUFBRWpCLFNBQVMsQ0FBQztFQUMvRTs7RUFFQSxNQUFNeUcsVUFBVUEsQ0FBQ1QsVUFBbUIsRUFBRUMsYUFBc0IsRUFBbUI7SUFDN0UsT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDRixXQUFXLENBQUNDLFVBQVUsRUFBRUMsYUFBYSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0VBQy9EOztFQUVBLE1BQU1TLGtCQUFrQkEsQ0FBQ1YsVUFBbUIsRUFBRUMsYUFBc0IsRUFBbUI7SUFDckYsT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDRixXQUFXLENBQUNDLFVBQVUsRUFBRUMsYUFBYSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0VBQy9EOztFQUVBLE1BQU1PLFdBQVdBLENBQUM2RSxtQkFBNkIsRUFBRUMsR0FBWSxFQUFFQyxZQUFzQixFQUE0Qjs7SUFFL0c7SUFDQSxJQUFJMUUsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLGNBQWMsRUFBRSxFQUFDcUssR0FBRyxFQUFFQSxHQUFHLEVBQUMsQ0FBQzs7SUFFcEY7SUFDQTtJQUNBLElBQUlFLFFBQXlCLEdBQUcsRUFBRTtJQUNsQyxLQUFLLElBQUlDLFVBQVUsSUFBSTVFLElBQUksQ0FBQ0MsTUFBTSxDQUFDNEUsbUJBQW1CLEVBQUU7TUFDdEQsSUFBSW5GLE9BQU8sR0FBR2xILGVBQWUsQ0FBQ3NNLGlCQUFpQixDQUFDRixVQUFVLENBQUM7TUFDM0QsSUFBSUosbUJBQW1CLEVBQUU5RSxPQUFPLENBQUNxRixlQUFlLENBQUMsTUFBTSxJQUFJLENBQUM3RCxlQUFlLENBQUN4QixPQUFPLENBQUNzRixRQUFRLENBQUMsQ0FBQyxFQUFFN0wsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDO01BQ2pId0wsUUFBUSxDQUFDTSxJQUFJLENBQUN2RixPQUFPLENBQUM7SUFDeEI7O0lBRUE7SUFDQSxJQUFJOEUsbUJBQW1CLElBQUksQ0FBQ0UsWUFBWSxFQUFFOztNQUV4QztNQUNBLEtBQUssSUFBSWhGLE9BQU8sSUFBSWlGLFFBQVEsRUFBRTtRQUM1QixLQUFLLElBQUl2RCxVQUFVLElBQUkxQixPQUFPLENBQUN3QixlQUFlLENBQUMsQ0FBQyxFQUFFO1VBQ2hERSxVQUFVLENBQUM4RCxVQUFVLENBQUMxRixNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7VUFDaEM0QixVQUFVLENBQUMrRCxrQkFBa0IsQ0FBQzNGLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztVQUN4QzRCLFVBQVUsQ0FBQ2dFLG9CQUFvQixDQUFDLENBQUMsQ0FBQztVQUNsQ2hFLFVBQVUsQ0FBQ2lFLG9CQUFvQixDQUFDLENBQUMsQ0FBQztRQUNwQztNQUNGOztNQUVBO01BQ0FyRixJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsYUFBYSxFQUFFLEVBQUNrTCxZQUFZLEVBQUUsSUFBSSxFQUFDLENBQUM7TUFDekYsSUFBSXRGLElBQUksQ0FBQ0MsTUFBTSxDQUFDRSxjQUFjLEVBQUU7UUFDOUIsS0FBSyxJQUFJb0YsYUFBYSxJQUFJdkYsSUFBSSxDQUFDQyxNQUFNLENBQUNFLGNBQWMsRUFBRTtVQUNwRCxJQUFJaUIsVUFBVSxHQUFHNUksZUFBZSxDQUFDZ04sb0JBQW9CLENBQUNELGFBQWEsQ0FBQzs7VUFFcEU7VUFDQSxJQUFJN0YsT0FBTyxHQUFHaUYsUUFBUSxDQUFDdkQsVUFBVSxDQUFDcUUsZUFBZSxDQUFDLENBQUMsQ0FBQztVQUNwRHBHLGVBQU0sQ0FBQ0MsS0FBSyxDQUFDOEIsVUFBVSxDQUFDcUUsZUFBZSxDQUFDLENBQUMsRUFBRS9GLE9BQU8sQ0FBQ3NGLFFBQVEsQ0FBQyxDQUFDLEVBQUUsK0JBQStCLENBQUMsQ0FBQyxDQUFFO1VBQ2xHLElBQUlVLGFBQWEsR0FBR2hHLE9BQU8sQ0FBQ3dCLGVBQWUsQ0FBQyxDQUFDLENBQUNFLFVBQVUsQ0FBQzRELFFBQVEsQ0FBQyxDQUFDLENBQUM7VUFDcEUzRixlQUFNLENBQUNDLEtBQUssQ0FBQzhCLFVBQVUsQ0FBQzRELFFBQVEsQ0FBQyxDQUFDLEVBQUVVLGFBQWEsQ0FBQ1YsUUFBUSxDQUFDLENBQUMsRUFBRSxtQ0FBbUMsQ0FBQztVQUNsRyxJQUFJNUQsVUFBVSxDQUFDeEIsVUFBVSxDQUFDLENBQUMsS0FBS3pHLFNBQVMsRUFBRXVNLGFBQWEsQ0FBQ1IsVUFBVSxDQUFDOUQsVUFBVSxDQUFDeEIsVUFBVSxDQUFDLENBQUMsQ0FBQztVQUM1RixJQUFJd0IsVUFBVSxDQUFDdkIsa0JBQWtCLENBQUMsQ0FBQyxLQUFLMUcsU0FBUyxFQUFFdU0sYUFBYSxDQUFDUCxrQkFBa0IsQ0FBQy9ELFVBQVUsQ0FBQ3ZCLGtCQUFrQixDQUFDLENBQUMsQ0FBQztVQUNwSCxJQUFJdUIsVUFBVSxDQUFDdUUsb0JBQW9CLENBQUMsQ0FBQyxLQUFLeE0sU0FBUyxFQUFFdU0sYUFBYSxDQUFDTixvQkFBb0IsQ0FBQ2hFLFVBQVUsQ0FBQ3VFLG9CQUFvQixDQUFDLENBQUMsQ0FBQztRQUM1SDtNQUNGO0lBQ0Y7O0lBRUEsT0FBT2hCLFFBQVE7RUFDakI7O0VBRUE7RUFDQSxNQUFNaUIsVUFBVUEsQ0FBQ3pHLFVBQWtCLEVBQUVxRixtQkFBNkIsRUFBRUUsWUFBc0IsRUFBMEI7SUFDbEgsSUFBQXJGLGVBQU0sRUFBQ0YsVUFBVSxJQUFJLENBQUMsQ0FBQztJQUN2QixLQUFLLElBQUlPLE9BQU8sSUFBSSxNQUFNLElBQUksQ0FBQ0MsV0FBVyxDQUFDLENBQUMsRUFBRTtNQUM1QyxJQUFJRCxPQUFPLENBQUNzRixRQUFRLENBQUMsQ0FBQyxLQUFLN0YsVUFBVSxFQUFFO1FBQ3JDLElBQUlxRixtQkFBbUIsRUFBRTlFLE9BQU8sQ0FBQ3FGLGVBQWUsQ0FBQyxNQUFNLElBQUksQ0FBQzdELGVBQWUsQ0FBQy9CLFVBQVUsRUFBRWhHLFNBQVMsRUFBRXVMLFlBQVksQ0FBQyxDQUFDO1FBQ2pILE9BQU9oRixPQUFPO01BQ2hCO0lBQ0Y7SUFDQSxNQUFNLElBQUltRyxLQUFLLENBQUMscUJBQXFCLEdBQUcxRyxVQUFVLEdBQUcsaUJBQWlCLENBQUM7RUFDekU7O0VBRUEsTUFBTTJHLGFBQWFBLENBQUNDLEtBQWMsRUFBMEI7SUFDMURBLEtBQUssR0FBR0EsS0FBSyxHQUFHQSxLQUFLLEdBQUc1TSxTQUFTO0lBQ2pDLElBQUk2RyxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsZ0JBQWdCLEVBQUUsRUFBQzJMLEtBQUssRUFBRUEsS0FBSyxFQUFDLENBQUM7SUFDMUYsT0FBTyxJQUFJQyxzQkFBYSxDQUFDO01BQ3ZCekUsS0FBSyxFQUFFdkIsSUFBSSxDQUFDQyxNQUFNLENBQUNILGFBQWE7TUFDaENtRyxjQUFjLEVBQUVqRyxJQUFJLENBQUNDLE1BQU0sQ0FBQ3RELE9BQU87TUFDbkNvSixLQUFLLEVBQUVBLEtBQUs7TUFDWnhHLE9BQU8sRUFBRUMsTUFBTSxDQUFDLENBQUMsQ0FBQztNQUNsQkMsZUFBZSxFQUFFRCxNQUFNLENBQUMsQ0FBQztJQUMzQixDQUFDLENBQUM7RUFDSjs7RUFFQSxNQUFNMEIsZUFBZUEsQ0FBQy9CLFVBQWtCLEVBQUUrRyxpQkFBNEIsRUFBRXhCLFlBQXNCLEVBQStCOztJQUUzSDtJQUNBLElBQUkxSSxNQUFXLEdBQUcsQ0FBQyxDQUFDO0lBQ3BCQSxNQUFNLENBQUM4RCxhQUFhLEdBQUdYLFVBQVU7SUFDakMsSUFBSStHLGlCQUFpQixFQUFFbEssTUFBTSxDQUFDbUssYUFBYSxHQUFHN00saUJBQVEsQ0FBQzhNLE9BQU8sQ0FBQ0YsaUJBQWlCLENBQUM7SUFDakYsSUFBSWxHLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxhQUFhLEVBQUU0QixNQUFNLENBQUM7O0lBRS9FO0lBQ0EsSUFBSXFLLFlBQVksR0FBRyxFQUFFO0lBQ3JCLEtBQUssSUFBSWQsYUFBYSxJQUFJdkYsSUFBSSxDQUFDQyxNQUFNLENBQUNxRyxTQUFTLEVBQUU7TUFDL0MsSUFBSWxGLFVBQVUsR0FBRzVJLGVBQWUsQ0FBQ2dOLG9CQUFvQixDQUFDRCxhQUFhLENBQUM7TUFDcEVuRSxVQUFVLENBQUNFLGVBQWUsQ0FBQ25DLFVBQVUsQ0FBQztNQUN0Q2tILFlBQVksQ0FBQ3BCLElBQUksQ0FBQzdELFVBQVUsQ0FBQztJQUMvQjs7SUFFQTtJQUNBLElBQUksQ0FBQ3NELFlBQVksRUFBRTs7TUFFakI7TUFDQSxLQUFLLElBQUl0RCxVQUFVLElBQUlpRixZQUFZLEVBQUU7UUFDbkNqRixVQUFVLENBQUM4RCxVQUFVLENBQUMxRixNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDaEM0QixVQUFVLENBQUMrRCxrQkFBa0IsQ0FBQzNGLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN4QzRCLFVBQVUsQ0FBQ2dFLG9CQUFvQixDQUFDLENBQUMsQ0FBQztRQUNsQ2hFLFVBQVUsQ0FBQ2lFLG9CQUFvQixDQUFDLENBQUMsQ0FBQztNQUNwQzs7TUFFQTtNQUNBckYsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLGFBQWEsRUFBRTRCLE1BQU0sQ0FBQztNQUMzRSxJQUFJZ0UsSUFBSSxDQUFDQyxNQUFNLENBQUNFLGNBQWMsRUFBRTtRQUM5QixLQUFLLElBQUlvRixhQUFhLElBQUl2RixJQUFJLENBQUNDLE1BQU0sQ0FBQ0UsY0FBYyxFQUFFO1VBQ3BELElBQUlpQixVQUFVLEdBQUc1SSxlQUFlLENBQUNnTixvQkFBb0IsQ0FBQ0QsYUFBYSxDQUFDOztVQUVwRTtVQUNBLEtBQUssSUFBSUcsYUFBYSxJQUFJVyxZQUFZLEVBQUU7WUFDdEMsSUFBSVgsYUFBYSxDQUFDVixRQUFRLENBQUMsQ0FBQyxLQUFLNUQsVUFBVSxDQUFDNEQsUUFBUSxDQUFDLENBQUMsRUFBRSxTQUFTLENBQUM7WUFDbEUsSUFBSTVELFVBQVUsQ0FBQ3hCLFVBQVUsQ0FBQyxDQUFDLEtBQUt6RyxTQUFTLEVBQUV1TSxhQUFhLENBQUNSLFVBQVUsQ0FBQzlELFVBQVUsQ0FBQ3hCLFVBQVUsQ0FBQyxDQUFDLENBQUM7WUFDNUYsSUFBSXdCLFVBQVUsQ0FBQ3ZCLGtCQUFrQixDQUFDLENBQUMsS0FBSzFHLFNBQVMsRUFBRXVNLGFBQWEsQ0FBQ1Asa0JBQWtCLENBQUMvRCxVQUFVLENBQUN2QixrQkFBa0IsQ0FBQyxDQUFDLENBQUM7WUFDcEgsSUFBSXVCLFVBQVUsQ0FBQ3VFLG9CQUFvQixDQUFDLENBQUMsS0FBS3hNLFNBQVMsRUFBRXVNLGFBQWEsQ0FBQ04sb0JBQW9CLENBQUNoRSxVQUFVLENBQUN1RSxvQkFBb0IsQ0FBQyxDQUFDLENBQUM7WUFDMUgsSUFBSXZFLFVBQVUsQ0FBQ21GLG9CQUFvQixDQUFDLENBQUMsS0FBS3BOLFNBQVMsRUFBRXVNLGFBQWEsQ0FBQ0wsb0JBQW9CLENBQUNqRSxVQUFVLENBQUNtRixvQkFBb0IsQ0FBQyxDQUFDLENBQUM7VUFDNUg7UUFDRjtNQUNGO0lBQ0Y7O0lBRUE7SUFDQSxJQUFJdEYsYUFBYSxHQUFHLElBQUksQ0FBQ3BJLFlBQVksQ0FBQ3NHLFVBQVUsQ0FBQztJQUNqRCxJQUFJLENBQUM4QixhQUFhLEVBQUU7TUFDbEJBLGFBQWEsR0FBRyxDQUFDLENBQUM7TUFDbEIsSUFBSSxDQUFDcEksWUFBWSxDQUFDc0csVUFBVSxDQUFDLEdBQUc4QixhQUFhO0lBQy9DO0lBQ0EsS0FBSyxJQUFJRyxVQUFVLElBQUlpRixZQUFZLEVBQUU7TUFDbkNwRixhQUFhLENBQUNHLFVBQVUsQ0FBQzRELFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBRzVELFVBQVUsQ0FBQ0osVUFBVSxDQUFDLENBQUM7SUFDaEU7O0lBRUE7SUFDQSxPQUFPcUYsWUFBWTtFQUNyQjs7RUFFQSxNQUFNRyxhQUFhQSxDQUFDckgsVUFBa0IsRUFBRUMsYUFBcUIsRUFBRXNGLFlBQXNCLEVBQTZCO0lBQ2hILElBQUFyRixlQUFNLEVBQUNGLFVBQVUsSUFBSSxDQUFDLENBQUM7SUFDdkIsSUFBQUUsZUFBTSxFQUFDRCxhQUFhLElBQUksQ0FBQyxDQUFDO0lBQzFCLE9BQU8sQ0FBQyxNQUFNLElBQUksQ0FBQzhCLGVBQWUsQ0FBQy9CLFVBQVUsRUFBRSxDQUFDQyxhQUFhLENBQUMsRUFBRXNGLFlBQVksQ0FBQyxFQUFFLENBQUMsQ0FBQztFQUNuRjs7RUFFQSxNQUFNK0IsZ0JBQWdCQSxDQUFDdEgsVUFBa0IsRUFBRTRHLEtBQWMsRUFBNkI7O0lBRXBGO0lBQ0EsSUFBSS9GLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxnQkFBZ0IsRUFBRSxFQUFDMEYsYUFBYSxFQUFFWCxVQUFVLEVBQUU0RyxLQUFLLEVBQUVBLEtBQUssRUFBQyxDQUFDOztJQUVySDtJQUNBLElBQUkzRSxVQUFVLEdBQUcsSUFBSUMseUJBQWdCLENBQUMsQ0FBQztJQUN2Q0QsVUFBVSxDQUFDRSxlQUFlLENBQUNuQyxVQUFVLENBQUM7SUFDdENpQyxVQUFVLENBQUNLLFFBQVEsQ0FBQ3pCLElBQUksQ0FBQ0MsTUFBTSxDQUFDa0csYUFBYSxDQUFDO0lBQzlDL0UsVUFBVSxDQUFDc0YsVUFBVSxDQUFDMUcsSUFBSSxDQUFDQyxNQUFNLENBQUN0RCxPQUFPLENBQUM7SUFDMUN5RSxVQUFVLENBQUN1RixRQUFRLENBQUNaLEtBQUssR0FBR0EsS0FBSyxHQUFHNU0sU0FBUyxDQUFDO0lBQzlDaUksVUFBVSxDQUFDOEQsVUFBVSxDQUFDMUYsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2hDNEIsVUFBVSxDQUFDK0Qsa0JBQWtCLENBQUMzRixNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDeEM0QixVQUFVLENBQUNnRSxvQkFBb0IsQ0FBQyxDQUFDLENBQUM7SUFDbENoRSxVQUFVLENBQUN3RixTQUFTLENBQUMsS0FBSyxDQUFDO0lBQzNCeEYsVUFBVSxDQUFDaUUsb0JBQW9CLENBQUMsQ0FBQyxDQUFDO0lBQ2xDLE9BQU9qRSxVQUFVO0VBQ25COztFQUVBLE1BQU15RixrQkFBa0JBLENBQUMxSCxVQUFrQixFQUFFQyxhQUFxQixFQUFFMkcsS0FBYSxFQUFpQjtJQUNoRyxNQUFNLElBQUksQ0FBQ25OLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxlQUFlLEVBQUUsRUFBQ21ILEtBQUssRUFBRSxFQUFDQyxLQUFLLEVBQUVyQyxVQUFVLEVBQUV1QyxLQUFLLEVBQUV0QyxhQUFhLEVBQUMsRUFBRTJHLEtBQUssRUFBRUEsS0FBSyxFQUFDLENBQUM7RUFDbEk7O0VBRUEsTUFBTWUsTUFBTUEsQ0FBQ0MsS0FBeUMsRUFBNkI7O0lBRWpGO0lBQ0EsTUFBTUMsZUFBZSxHQUFHdk8scUJBQVksQ0FBQ3dPLGdCQUFnQixDQUFDRixLQUFLLENBQUM7O0lBRTVEO0lBQ0EsSUFBSUcsYUFBYSxHQUFHRixlQUFlLENBQUNHLGdCQUFnQixDQUFDLENBQUM7SUFDdEQsSUFBSUMsVUFBVSxHQUFHSixlQUFlLENBQUNLLGFBQWEsQ0FBQyxDQUFDO0lBQ2hELElBQUlDLFdBQVcsR0FBR04sZUFBZSxDQUFDTyxjQUFjLENBQUMsQ0FBQztJQUNsRFAsZUFBZSxDQUFDUSxnQkFBZ0IsQ0FBQ3JPLFNBQVMsQ0FBQztJQUMzQzZOLGVBQWUsQ0FBQ1MsYUFBYSxDQUFDdE8sU0FBUyxDQUFDO0lBQ3hDNk4sZUFBZSxDQUFDVSxjQUFjLENBQUN2TyxTQUFTLENBQUM7O0lBRXpDO0lBQ0EsSUFBSXdPLFNBQVMsR0FBRyxNQUFNLElBQUksQ0FBQ0MsZUFBZSxDQUFDLElBQUlDLDRCQUFtQixDQUFDLENBQUMsQ0FBQ0MsVUFBVSxDQUFDdFAsZUFBZSxDQUFDdVAsZUFBZSxDQUFDZixlQUFlLENBQUNnQixJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7SUFFekk7SUFDQSxJQUFJQyxHQUFHLEdBQUcsRUFBRTtJQUNaLElBQUlDLE1BQU0sR0FBRyxJQUFJQyxHQUFHLENBQUMsQ0FBQztJQUN0QixLQUFLLElBQUlDLFFBQVEsSUFBSVQsU0FBUyxFQUFFO01BQzlCLElBQUksQ0FBQ08sTUFBTSxDQUFDdlEsR0FBRyxDQUFDeVEsUUFBUSxDQUFDQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUU7UUFDakNKLEdBQUcsQ0FBQ2hELElBQUksQ0FBQ21ELFFBQVEsQ0FBQ0MsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUMxQkgsTUFBTSxDQUFDSSxHQUFHLENBQUNGLFFBQVEsQ0FBQ0MsS0FBSyxDQUFDLENBQUMsQ0FBQztNQUM5QjtJQUNGOztJQUVBO0lBQ0EsSUFBSUUsS0FBSyxHQUFHLENBQUMsQ0FBQztJQUNkLElBQUlDLFFBQVEsR0FBRyxDQUFDLENBQUM7SUFDakIsS0FBSyxJQUFJQyxFQUFFLElBQUlSLEdBQUcsRUFBRTtNQUNsQnpQLGVBQWUsQ0FBQ2tRLE9BQU8sQ0FBQ0QsRUFBRSxFQUFFRixLQUFLLEVBQUVDLFFBQVEsQ0FBQztJQUM5Qzs7SUFFQTtJQUNBLElBQUl4QixlQUFlLENBQUMyQixpQkFBaUIsQ0FBQyxDQUFDLElBQUlyQixXQUFXLEVBQUU7O01BRXREO01BQ0EsSUFBSXNCLGNBQWMsR0FBRyxDQUFDdEIsV0FBVyxHQUFHQSxXQUFXLENBQUNVLElBQUksQ0FBQyxDQUFDLEdBQUcsSUFBSWEsMEJBQWlCLENBQUMsQ0FBQyxFQUFFZixVQUFVLENBQUN0UCxlQUFlLENBQUN1UCxlQUFlLENBQUNmLGVBQWUsQ0FBQ2dCLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUNySixJQUFJYyxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUNDLGFBQWEsQ0FBQ0gsY0FBYyxDQUFDOztNQUV0RDtNQUNBLElBQUlJLFNBQVMsR0FBRyxFQUFFO01BQ2xCLEtBQUssSUFBSUMsTUFBTSxJQUFJSCxPQUFPLEVBQUU7UUFDMUIsSUFBSSxDQUFDRSxTQUFTLENBQUMvTCxRQUFRLENBQUNnTSxNQUFNLENBQUNaLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRTtVQUN2QzdQLGVBQWUsQ0FBQ2tRLE9BQU8sQ0FBQ08sTUFBTSxDQUFDWixLQUFLLENBQUMsQ0FBQyxFQUFFRSxLQUFLLEVBQUVDLFFBQVEsQ0FBQztVQUN4RFEsU0FBUyxDQUFDL0QsSUFBSSxDQUFDZ0UsTUFBTSxDQUFDWixLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ2hDO01BQ0Y7SUFDRjs7SUFFQTtJQUNBckIsZUFBZSxDQUFDUSxnQkFBZ0IsQ0FBQ04sYUFBYSxDQUFDO0lBQy9DRixlQUFlLENBQUNTLGFBQWEsQ0FBQ0wsVUFBVSxDQUFDO0lBQ3pDSixlQUFlLENBQUNVLGNBQWMsQ0FBQ0osV0FBVyxDQUFDOztJQUUzQztJQUNBLElBQUk0QixVQUFVLEdBQUcsRUFBRTtJQUNuQixLQUFLLElBQUlULEVBQUUsSUFBSVIsR0FBRyxFQUFFO01BQ2xCLElBQUlqQixlQUFlLENBQUNtQyxhQUFhLENBQUNWLEVBQUUsQ0FBQyxFQUFFUyxVQUFVLENBQUNqRSxJQUFJLENBQUN3RCxFQUFFLENBQUMsQ0FBQztNQUN0RCxJQUFJQSxFQUFFLENBQUNXLFFBQVEsQ0FBQyxDQUFDLEtBQUtqUSxTQUFTLEVBQUVzUCxFQUFFLENBQUNXLFFBQVEsQ0FBQyxDQUFDLENBQUN0QyxNQUFNLENBQUMsQ0FBQyxDQUFDdUMsTUFBTSxDQUFDWixFQUFFLENBQUNXLFFBQVEsQ0FBQyxDQUFDLENBQUN0QyxNQUFNLENBQUMsQ0FBQyxDQUFDdEcsT0FBTyxDQUFDaUksRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzVHO0lBQ0FSLEdBQUcsR0FBR2lCLFVBQVU7O0lBRWhCO0lBQ0EsS0FBSyxJQUFJVCxFQUFFLElBQUlSLEdBQUcsRUFBRTtNQUNsQixJQUFJUSxFQUFFLENBQUNhLGNBQWMsQ0FBQyxDQUFDLElBQUliLEVBQUUsQ0FBQ1csUUFBUSxDQUFDLENBQUMsS0FBS2pRLFNBQVMsSUFBSSxDQUFDc1AsRUFBRSxDQUFDYSxjQUFjLENBQUMsQ0FBQyxJQUFJYixFQUFFLENBQUNXLFFBQVEsQ0FBQyxDQUFDLEtBQUtqUSxTQUFTLEVBQUU7UUFDN0dvUSxPQUFPLENBQUNDLEtBQUssQ0FBQyw4RUFBOEUsQ0FBQztRQUM3RixPQUFPLElBQUksQ0FBQzFDLE1BQU0sQ0FBQ0UsZUFBZSxDQUFDO01BQ3JDO0lBQ0Y7O0lBRUE7SUFDQSxJQUFJQSxlQUFlLENBQUN5QyxTQUFTLENBQUMsQ0FBQyxJQUFJekMsZUFBZSxDQUFDeUMsU0FBUyxDQUFDLENBQUMsQ0FBQ3JGLE1BQU0sR0FBRyxDQUFDLEVBQUU7TUFDekUsSUFBSXNGLE9BQU8sR0FBRyxJQUFJQyxHQUFHLENBQUMsQ0FBQyxFQUFFO01BQ3pCLEtBQUssSUFBSWxCLEVBQUUsSUFBSVIsR0FBRyxFQUFFeUIsT0FBTyxDQUFDblIsR0FBRyxDQUFDa1EsRUFBRSxDQUFDbUIsT0FBTyxDQUFDLENBQUMsRUFBRW5CLEVBQUUsQ0FBQztNQUNqRCxJQUFJb0IsVUFBVSxHQUFHLEVBQUU7TUFDbkIsS0FBSyxJQUFJQyxJQUFJLElBQUk5QyxlQUFlLENBQUN5QyxTQUFTLENBQUMsQ0FBQyxFQUFFLElBQUlDLE9BQU8sQ0FBQzlSLEdBQUcsQ0FBQ2tTLElBQUksQ0FBQyxFQUFFRCxVQUFVLENBQUM1RSxJQUFJLENBQUN5RSxPQUFPLENBQUM5UixHQUFHLENBQUNrUyxJQUFJLENBQUMsQ0FBQztNQUN2RzdCLEdBQUcsR0FBRzRCLFVBQVU7SUFDbEI7SUFDQSxPQUFPNUIsR0FBRztFQUNaOztFQUVBLE1BQU04QixZQUFZQSxDQUFDaEQsS0FBb0MsRUFBNkI7O0lBRWxGO0lBQ0EsTUFBTUMsZUFBZSxHQUFHdk8scUJBQVksQ0FBQ3VSLHNCQUFzQixDQUFDakQsS0FBSyxDQUFDOztJQUVsRTtJQUNBLElBQUksQ0FBQ3ZPLGVBQWUsQ0FBQ3lSLFlBQVksQ0FBQ2pELGVBQWUsQ0FBQyxFQUFFLE9BQU8sSUFBSSxDQUFDWSxlQUFlLENBQUNaLGVBQWUsQ0FBQzs7SUFFaEc7SUFDQSxJQUFJVyxTQUFTLEdBQUcsRUFBRTtJQUNsQixLQUFLLElBQUljLEVBQUUsSUFBSSxNQUFNLElBQUksQ0FBQzNCLE1BQU0sQ0FBQ0UsZUFBZSxDQUFDa0QsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFO01BQzlELEtBQUssSUFBSTlCLFFBQVEsSUFBSUssRUFBRSxDQUFDMEIsZUFBZSxDQUFDbkQsZUFBZSxDQUFDLEVBQUU7UUFDeERXLFNBQVMsQ0FBQzFDLElBQUksQ0FBQ21ELFFBQVEsQ0FBQztNQUMxQjtJQUNGOztJQUVBLE9BQU9ULFNBQVM7RUFDbEI7O0VBRUEsTUFBTXlDLFVBQVVBLENBQUNyRCxLQUFrQyxFQUFpQzs7SUFFbEY7SUFDQSxNQUFNQyxlQUFlLEdBQUd2TyxxQkFBWSxDQUFDNFIsb0JBQW9CLENBQUN0RCxLQUFLLENBQUM7O0lBRWhFO0lBQ0EsSUFBSSxDQUFDdk8sZUFBZSxDQUFDeVIsWUFBWSxDQUFDakQsZUFBZSxDQUFDLEVBQUUsT0FBTyxJQUFJLENBQUMrQixhQUFhLENBQUMvQixlQUFlLENBQUM7O0lBRTlGO0lBQ0EsSUFBSThCLE9BQU8sR0FBRyxFQUFFO0lBQ2hCLEtBQUssSUFBSUwsRUFBRSxJQUFJLE1BQU0sSUFBSSxDQUFDM0IsTUFBTSxDQUFDRSxlQUFlLENBQUNrRCxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQUU7TUFDOUQsS0FBSyxJQUFJakIsTUFBTSxJQUFJUixFQUFFLENBQUM2QixhQUFhLENBQUN0RCxlQUFlLENBQUMsRUFBRTtRQUNwRDhCLE9BQU8sQ0FBQzdELElBQUksQ0FBQ2dFLE1BQU0sQ0FBQztNQUN0QjtJQUNGOztJQUVBLE9BQU9ILE9BQU87RUFDaEI7O0VBRUEsTUFBTXlCLGFBQWFBLENBQUNDLEdBQUcsR0FBRyxLQUFLLEVBQW1CO0lBQ2hELE9BQU8sQ0FBQyxNQUFNLElBQUksQ0FBQzVSLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxnQkFBZ0IsRUFBRSxFQUFDb1EsR0FBRyxFQUFFQSxHQUFHLEVBQUMsQ0FBQyxFQUFFdkssTUFBTSxDQUFDd0ssZ0JBQWdCO0VBQzlHOztFQUVBLE1BQU1DLGFBQWFBLENBQUNDLFVBQWtCLEVBQW1CO0lBQ3ZELElBQUkzSyxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsZ0JBQWdCLEVBQUUsRUFBQ3FRLGdCQUFnQixFQUFFRSxVQUFVLEVBQUMsQ0FBQztJQUMxRyxPQUFPM0ssSUFBSSxDQUFDQyxNQUFNLENBQUMySyxZQUFZO0VBQ2pDOztFQUVBLE1BQU1DLGVBQWVBLENBQUNMLEdBQUcsR0FBRyxLQUFLLEVBQTZCO0lBQzVELE9BQU8sTUFBTSxJQUFJLENBQUNNLGtCQUFrQixDQUFDTixHQUFHLENBQUM7RUFDM0M7O0VBRUEsTUFBTU8sZUFBZUEsQ0FBQ0MsU0FBMkIsRUFBdUM7O0lBRXRGO0lBQ0EsSUFBSUMsWUFBWSxHQUFHRCxTQUFTLENBQUNFLEdBQUcsQ0FBQyxDQUFBQyxRQUFRLE1BQUssRUFBQ0MsU0FBUyxFQUFFRCxRQUFRLENBQUNFLE1BQU0sQ0FBQyxDQUFDLEVBQUVDLFNBQVMsRUFBRUgsUUFBUSxDQUFDSSxZQUFZLENBQUMsQ0FBQyxFQUFDLENBQUMsQ0FBQzs7SUFFbEg7SUFDQSxJQUFJdkwsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLG1CQUFtQixFQUFFLEVBQUNvUixpQkFBaUIsRUFBRVAsWUFBWSxFQUFDLENBQUM7O0lBRWhIO0lBQ0EsSUFBSVEsWUFBWSxHQUFHLElBQUlDLG1DQUEwQixDQUFDLENBQUM7SUFDbkRELFlBQVksQ0FBQ0UsU0FBUyxDQUFDM0wsSUFBSSxDQUFDQyxNQUFNLENBQUN3QyxNQUFNLENBQUM7SUFDMUNnSixZQUFZLENBQUNHLGNBQWMsQ0FBQ3BNLE1BQU0sQ0FBQ1EsSUFBSSxDQUFDQyxNQUFNLENBQUM0TCxLQUFLLENBQUMsQ0FBQztJQUN0REosWUFBWSxDQUFDSyxnQkFBZ0IsQ0FBQ3RNLE1BQU0sQ0FBQ1EsSUFBSSxDQUFDQyxNQUFNLENBQUM4TCxPQUFPLENBQUMsQ0FBQztJQUMxRCxPQUFPTixZQUFZO0VBQ3JCOztFQUVBLE1BQU1PLDZCQUE2QkEsQ0FBQSxFQUE4QjtJQUMvRCxPQUFPLE1BQU0sSUFBSSxDQUFDbEIsa0JBQWtCLENBQUMsS0FBSyxDQUFDO0VBQzdDOztFQUVBLE1BQU1tQixZQUFZQSxDQUFDZCxRQUFnQixFQUFpQjtJQUNsRCxPQUFPLElBQUksQ0FBQ3ZTLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxRQUFRLEVBQUUsRUFBQ2dSLFNBQVMsRUFBRUQsUUFBUSxFQUFDLENBQUM7RUFDakY7O0VBRUEsTUFBTWUsVUFBVUEsQ0FBQ2YsUUFBZ0IsRUFBaUI7SUFDaEQsT0FBTyxJQUFJLENBQUN2UyxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsTUFBTSxFQUFFLEVBQUNnUixTQUFTLEVBQUVELFFBQVEsRUFBQyxDQUFDO0VBQy9FOztFQUVBLE1BQU1nQixjQUFjQSxDQUFDaEIsUUFBZ0IsRUFBb0I7SUFDdkQsSUFBSW5MLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxRQUFRLEVBQUUsRUFBQ2dSLFNBQVMsRUFBRUQsUUFBUSxFQUFDLENBQUM7SUFDekYsT0FBT25MLElBQUksQ0FBQ0MsTUFBTSxDQUFDbU0sTUFBTSxLQUFLLElBQUk7RUFDcEM7O0VBRUEsTUFBTUMscUJBQXFCQSxDQUFBLEVBQThCO0lBQ3ZELElBQUlyTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsMEJBQTBCLENBQUM7SUFDcEYsT0FBTzRGLElBQUksQ0FBQ0MsTUFBTSxDQUFDcU0sUUFBUTtFQUM3Qjs7RUFFQSxNQUFNQyxTQUFTQSxDQUFDM1QsTUFBK0IsRUFBNkI7O0lBRTFFO0lBQ0EsTUFBTWdDLGdCQUFnQixHQUFHbkMscUJBQVksQ0FBQytULHdCQUF3QixDQUFDNVQsTUFBTSxDQUFDO0lBQ3RFLElBQUlnQyxnQkFBZ0IsQ0FBQzZSLFdBQVcsQ0FBQyxDQUFDLEtBQUt0VCxTQUFTLEVBQUV5QixnQkFBZ0IsQ0FBQzhSLFdBQVcsQ0FBQyxJQUFJLENBQUM7SUFDcEYsSUFBSTlSLGdCQUFnQixDQUFDK1IsUUFBUSxDQUFDLENBQUMsS0FBSyxJQUFJLEtBQUksTUFBTSxJQUFJLENBQUNDLFVBQVUsQ0FBQyxDQUFDLEdBQUUsTUFBTSxJQUFJeFQsb0JBQVcsQ0FBQyxtREFBbUQsQ0FBQzs7SUFFL0k7SUFDQSxJQUFJK0YsVUFBVSxHQUFHdkUsZ0JBQWdCLENBQUM2SyxlQUFlLENBQUMsQ0FBQztJQUNuRCxJQUFJdEcsVUFBVSxLQUFLaEcsU0FBUyxFQUFFLE1BQU0sSUFBSUMsb0JBQVcsQ0FBQyw2Q0FBNkMsQ0FBQztJQUNsRyxJQUFJOE0saUJBQWlCLEdBQUd0TCxnQkFBZ0IsQ0FBQ2lTLG9CQUFvQixDQUFDLENBQUMsS0FBSzFULFNBQVMsR0FBR0EsU0FBUyxHQUFHeUIsZ0JBQWdCLENBQUNpUyxvQkFBb0IsQ0FBQyxDQUFDLENBQUNDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDOztJQUU5STtJQUNBLElBQUk5USxNQUFXLEdBQUcsQ0FBQyxDQUFDO0lBQ3BCQSxNQUFNLENBQUMrUSxZQUFZLEdBQUcsRUFBRTtJQUN4QixLQUFLLElBQUlDLFdBQVcsSUFBSXBTLGdCQUFnQixDQUFDcVMsZUFBZSxDQUFDLENBQUMsRUFBRTtNQUMxRCxJQUFBNU4sZUFBTSxFQUFDMk4sV0FBVyxDQUFDaE0sVUFBVSxDQUFDLENBQUMsRUFBRSxvQ0FBb0MsQ0FBQztNQUN0RSxJQUFBM0IsZUFBTSxFQUFDMk4sV0FBVyxDQUFDRSxTQUFTLENBQUMsQ0FBQyxFQUFFLG1DQUFtQyxDQUFDO01BQ3BFbFIsTUFBTSxDQUFDK1EsWUFBWSxDQUFDOUgsSUFBSSxDQUFDLEVBQUV0SSxPQUFPLEVBQUVxUSxXQUFXLENBQUNoTSxVQUFVLENBQUMsQ0FBQyxFQUFFbU0sTUFBTSxFQUFFSCxXQUFXLENBQUNFLFNBQVMsQ0FBQyxDQUFDLENBQUNFLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzdHO0lBQ0EsSUFBSXhTLGdCQUFnQixDQUFDeVMsa0JBQWtCLENBQUMsQ0FBQyxFQUFFclIsTUFBTSxDQUFDc1IseUJBQXlCLEdBQUcxUyxnQkFBZ0IsQ0FBQ3lTLGtCQUFrQixDQUFDLENBQUM7SUFDbkhyUixNQUFNLENBQUM4RCxhQUFhLEdBQUdYLFVBQVU7SUFDakNuRCxNQUFNLENBQUN1UixlQUFlLEdBQUdySCxpQkFBaUI7SUFDMUNsSyxNQUFNLENBQUNnRyxVQUFVLEdBQUdwSCxnQkFBZ0IsQ0FBQzRTLFlBQVksQ0FBQyxDQUFDO0lBQ25EeFIsTUFBTSxDQUFDeVIsWUFBWSxHQUFHN1MsZ0JBQWdCLENBQUMrUixRQUFRLENBQUMsQ0FBQyxLQUFLLElBQUk7SUFDMUQsSUFBQXROLGVBQU0sRUFBQ3pFLGdCQUFnQixDQUFDOFMsV0FBVyxDQUFDLENBQUMsS0FBS3ZVLFNBQVMsSUFBSXlCLGdCQUFnQixDQUFDOFMsV0FBVyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUk5UyxnQkFBZ0IsQ0FBQzhTLFdBQVcsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2xJMVIsTUFBTSxDQUFDc1EsUUFBUSxHQUFHMVIsZ0JBQWdCLENBQUM4UyxXQUFXLENBQUMsQ0FBQztJQUNoRDFSLE1BQU0sQ0FBQzJSLFVBQVUsR0FBRyxJQUFJO0lBQ3hCM1IsTUFBTSxDQUFDNFIsZUFBZSxHQUFHLElBQUk7SUFDN0IsSUFBSWhULGdCQUFnQixDQUFDNlIsV0FBVyxDQUFDLENBQUMsRUFBRXpRLE1BQU0sQ0FBQzZSLFdBQVcsR0FBRyxJQUFJLENBQUMsQ0FBQztJQUFBLEtBQzFEN1IsTUFBTSxDQUFDOFIsVUFBVSxHQUFHLElBQUk7O0lBRTdCO0lBQ0EsSUFBSWxULGdCQUFnQixDQUFDNlIsV0FBVyxDQUFDLENBQUMsSUFBSTdSLGdCQUFnQixDQUFDeVMsa0JBQWtCLENBQUMsQ0FBQyxJQUFJelMsZ0JBQWdCLENBQUN5UyxrQkFBa0IsQ0FBQyxDQUFDLENBQUNqSixNQUFNLEdBQUcsQ0FBQyxFQUFFO01BQy9ILE1BQU0sSUFBSWhMLG9CQUFXLENBQUMsMEVBQTBFLENBQUM7SUFDbkc7O0lBRUE7SUFDQSxJQUFJNkcsTUFBTTtJQUNWLElBQUk7TUFDRixJQUFJRCxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUNRLGdCQUFnQixDQUFDNlIsV0FBVyxDQUFDLENBQUMsR0FBRyxnQkFBZ0IsR0FBRyxVQUFVLEVBQUV6USxNQUFNLENBQUM7TUFDaElpRSxNQUFNLEdBQUdELElBQUksQ0FBQ0MsTUFBTTtJQUN0QixDQUFDLENBQUMsT0FBTy9ELEdBQVEsRUFBRTtNQUNqQixJQUFJQSxHQUFHLENBQUNhLE9BQU8sQ0FBQ3lELE9BQU8sQ0FBQyxxQ0FBcUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLE1BQU0sSUFBSXBILG9CQUFXLENBQUMsNkJBQTZCLENBQUM7TUFDekgsTUFBTThDLEdBQUc7SUFDWDs7SUFFQTtJQUNBLElBQUkrTCxHQUFHO0lBQ1AsSUFBSThGLE1BQU0sR0FBR25ULGdCQUFnQixDQUFDNlIsV0FBVyxDQUFDLENBQUMsR0FBSXhNLE1BQU0sQ0FBQytOLFFBQVEsS0FBSzdVLFNBQVMsR0FBRzhHLE1BQU0sQ0FBQytOLFFBQVEsQ0FBQzVKLE1BQU0sR0FBRyxDQUFDLEdBQUtuRSxNQUFNLENBQUNnTyxHQUFHLEtBQUs5VSxTQUFTLEdBQUcsQ0FBQyxHQUFHLENBQUU7SUFDL0ksSUFBSTRVLE1BQU0sR0FBRyxDQUFDLEVBQUU5RixHQUFHLEdBQUcsRUFBRTtJQUN4QixJQUFJaUcsZ0JBQWdCLEdBQUdILE1BQU0sS0FBSyxDQUFDO0lBQ25DLEtBQUssSUFBSUksQ0FBQyxHQUFHLENBQUMsRUFBRUEsQ0FBQyxHQUFHSixNQUFNLEVBQUVJLENBQUMsRUFBRSxFQUFFO01BQy9CLElBQUkxRixFQUFFLEdBQUcsSUFBSTJGLHVCQUFjLENBQUMsQ0FBQztNQUM3QjVWLGVBQWUsQ0FBQzZWLGdCQUFnQixDQUFDelQsZ0JBQWdCLEVBQUU2TixFQUFFLEVBQUV5RixnQkFBZ0IsQ0FBQztNQUN4RXpGLEVBQUUsQ0FBQzZGLG1CQUFtQixDQUFDLENBQUMsQ0FBQ2hOLGVBQWUsQ0FBQ25DLFVBQVUsQ0FBQztNQUNwRCxJQUFJK0csaUJBQWlCLEtBQUsvTSxTQUFTLElBQUkrTSxpQkFBaUIsQ0FBQzlCLE1BQU0sS0FBSyxDQUFDLEVBQUVxRSxFQUFFLENBQUM2RixtQkFBbUIsQ0FBQyxDQUFDLENBQUNDLG9CQUFvQixDQUFDckksaUJBQWlCLENBQUM7TUFDdkkrQixHQUFHLENBQUNoRCxJQUFJLENBQUN3RCxFQUFFLENBQUM7SUFDZDs7SUFFQTtJQUNBLElBQUk3TixnQkFBZ0IsQ0FBQytSLFFBQVEsQ0FBQyxDQUFDLEVBQUUsTUFBTSxJQUFJLENBQUN2SixJQUFJLENBQUMsQ0FBQzs7SUFFbEQ7SUFDQSxJQUFJeEksZ0JBQWdCLENBQUM2UixXQUFXLENBQUMsQ0FBQyxFQUFFLE9BQU9qVSxlQUFlLENBQUNnVyx3QkFBd0IsQ0FBQ3ZPLE1BQU0sRUFBRWdJLEdBQUcsRUFBRXJOLGdCQUFnQixDQUFDLENBQUNrTSxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQ3ZILE9BQU90TyxlQUFlLENBQUNpVyxtQkFBbUIsQ0FBQ3hPLE1BQU0sRUFBRWdJLEdBQUcsS0FBSzlPLFNBQVMsR0FBR0EsU0FBUyxHQUFHOE8sR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRXJOLGdCQUFnQixDQUFDLENBQUNrTSxNQUFNLENBQUMsQ0FBQztFQUNsSTs7RUFFQSxNQUFNNEgsV0FBV0EsQ0FBQzlWLE1BQStCLEVBQTJCOztJQUUxRTtJQUNBQSxNQUFNLEdBQUdILHFCQUFZLENBQUNrVywwQkFBMEIsQ0FBQy9WLE1BQU0sQ0FBQzs7SUFFeEQ7SUFDQSxJQUFJb0QsTUFBVyxHQUFHLENBQUMsQ0FBQztJQUNwQkEsTUFBTSxDQUFDVyxPQUFPLEdBQUcvRCxNQUFNLENBQUNxVSxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDak0sVUFBVSxDQUFDLENBQUM7SUFDekRoRixNQUFNLENBQUM4RCxhQUFhLEdBQUdsSCxNQUFNLENBQUM2TSxlQUFlLENBQUMsQ0FBQztJQUMvQ3pKLE1BQU0sQ0FBQ3VSLGVBQWUsR0FBRzNVLE1BQU0sQ0FBQ2lVLG9CQUFvQixDQUFDLENBQUM7SUFDdEQ3USxNQUFNLENBQUNvUCxTQUFTLEdBQUd4UyxNQUFNLENBQUNnVyxXQUFXLENBQUMsQ0FBQztJQUN2QzVTLE1BQU0sQ0FBQ3lSLFlBQVksR0FBRzdVLE1BQU0sQ0FBQytULFFBQVEsQ0FBQyxDQUFDLEtBQUssSUFBSTtJQUNoRCxJQUFBdE4sZUFBTSxFQUFDekcsTUFBTSxDQUFDOFUsV0FBVyxDQUFDLENBQUMsS0FBS3ZVLFNBQVMsSUFBSVAsTUFBTSxDQUFDOFUsV0FBVyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUk5VSxNQUFNLENBQUM4VSxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNwRzFSLE1BQU0sQ0FBQ3NRLFFBQVEsR0FBRzFULE1BQU0sQ0FBQzhVLFdBQVcsQ0FBQyxDQUFDO0lBQ3RDMVIsTUFBTSxDQUFDZ0csVUFBVSxHQUFHcEosTUFBTSxDQUFDNFUsWUFBWSxDQUFDLENBQUM7SUFDekN4UixNQUFNLENBQUM4UixVQUFVLEdBQUcsSUFBSTtJQUN4QjlSLE1BQU0sQ0FBQzJSLFVBQVUsR0FBRyxJQUFJO0lBQ3hCM1IsTUFBTSxDQUFDNFIsZUFBZSxHQUFHLElBQUk7O0lBRTdCO0lBQ0EsSUFBSTVOLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxjQUFjLEVBQUU0QixNQUFNLENBQUM7SUFDaEYsSUFBSWlFLE1BQU0sR0FBR0QsSUFBSSxDQUFDQyxNQUFNOztJQUV4QjtJQUNBLElBQUlySCxNQUFNLENBQUMrVCxRQUFRLENBQUMsQ0FBQyxFQUFFLE1BQU0sSUFBSSxDQUFDdkosSUFBSSxDQUFDLENBQUM7O0lBRXhDO0lBQ0EsSUFBSXFGLEVBQUUsR0FBR2pRLGVBQWUsQ0FBQzZWLGdCQUFnQixDQUFDelYsTUFBTSxFQUFFTyxTQUFTLEVBQUUsSUFBSSxDQUFDO0lBQ2xFWCxlQUFlLENBQUNpVyxtQkFBbUIsQ0FBQ3hPLE1BQU0sRUFBRXdJLEVBQUUsRUFBRSxJQUFJLEVBQUU3UCxNQUFNLENBQUM7SUFDN0Q2UCxFQUFFLENBQUM2RixtQkFBbUIsQ0FBQyxDQUFDLENBQUNyQixlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDNEIsU0FBUyxDQUFDcEcsRUFBRSxDQUFDNkYsbUJBQW1CLENBQUMsQ0FBQyxDQUFDcEIsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0YsT0FBT3pFLEVBQUU7RUFDWDs7RUFFQSxNQUFNcUcsYUFBYUEsQ0FBQ2xXLE1BQStCLEVBQTZCOztJQUU5RTtJQUNBLE1BQU1nQyxnQkFBZ0IsR0FBR25DLHFCQUFZLENBQUNzVyw0QkFBNEIsQ0FBQ25XLE1BQU0sQ0FBQzs7SUFFMUU7SUFDQSxJQUFJb1csT0FBTyxHQUFHLElBQUlyRixHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUU7SUFDMUIsSUFBSS9PLGdCQUFnQixDQUFDNkssZUFBZSxDQUFDLENBQUMsS0FBS3RNLFNBQVMsRUFBRTtNQUNwRCxJQUFJeUIsZ0JBQWdCLENBQUNpUyxvQkFBb0IsQ0FBQyxDQUFDLEtBQUsxVCxTQUFTLEVBQUU7UUFDekQ2VixPQUFPLENBQUN6VyxHQUFHLENBQUNxQyxnQkFBZ0IsQ0FBQzZLLGVBQWUsQ0FBQyxDQUFDLEVBQUU3SyxnQkFBZ0IsQ0FBQ2lTLG9CQUFvQixDQUFDLENBQUMsQ0FBQztNQUMxRixDQUFDLE1BQU07UUFDTCxJQUFJM0csaUJBQWlCLEdBQUcsRUFBRTtRQUMxQjhJLE9BQU8sQ0FBQ3pXLEdBQUcsQ0FBQ3FDLGdCQUFnQixDQUFDNkssZUFBZSxDQUFDLENBQUMsRUFBRVMsaUJBQWlCLENBQUM7UUFDbEUsS0FBSyxJQUFJOUUsVUFBVSxJQUFJLE1BQU0sSUFBSSxDQUFDRixlQUFlLENBQUN0RyxnQkFBZ0IsQ0FBQzZLLGVBQWUsQ0FBQyxDQUFDLENBQUMsRUFBRTtVQUNyRixJQUFJckUsVUFBVSxDQUFDdkIsa0JBQWtCLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRXFHLGlCQUFpQixDQUFDakIsSUFBSSxDQUFDN0QsVUFBVSxDQUFDNEQsUUFBUSxDQUFDLENBQUMsQ0FBQztRQUN6RjtNQUNGO0lBQ0YsQ0FBQyxNQUFNO01BQ0wsSUFBSUwsUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDaEYsV0FBVyxDQUFDLElBQUksQ0FBQztNQUMzQyxLQUFLLElBQUlELE9BQU8sSUFBSWlGLFFBQVEsRUFBRTtRQUM1QixJQUFJakYsT0FBTyxDQUFDRyxrQkFBa0IsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFO1VBQ3JDLElBQUlxRyxpQkFBaUIsR0FBRyxFQUFFO1VBQzFCOEksT0FBTyxDQUFDelcsR0FBRyxDQUFDbUgsT0FBTyxDQUFDc0YsUUFBUSxDQUFDLENBQUMsRUFBRWtCLGlCQUFpQixDQUFDO1VBQ2xELEtBQUssSUFBSTlFLFVBQVUsSUFBSTFCLE9BQU8sQ0FBQ3dCLGVBQWUsQ0FBQyxDQUFDLEVBQUU7WUFDaEQsSUFBSUUsVUFBVSxDQUFDdkIsa0JBQWtCLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRXFHLGlCQUFpQixDQUFDakIsSUFBSSxDQUFDN0QsVUFBVSxDQUFDNEQsUUFBUSxDQUFDLENBQUMsQ0FBQztVQUN6RjtRQUNGO01BQ0Y7SUFDRjs7SUFFQTtJQUNBLElBQUlpRCxHQUFHLEdBQUcsRUFBRTtJQUNaLEtBQUssSUFBSTlJLFVBQVUsSUFBSTZQLE9BQU8sQ0FBQ0MsSUFBSSxDQUFDLENBQUMsRUFBRTs7TUFFckM7TUFDQSxJQUFJakgsSUFBSSxHQUFHcE4sZ0JBQWdCLENBQUNvTixJQUFJLENBQUMsQ0FBQztNQUNsQ0EsSUFBSSxDQUFDMUcsZUFBZSxDQUFDbkMsVUFBVSxDQUFDO01BQ2hDNkksSUFBSSxDQUFDa0gsc0JBQXNCLENBQUMsS0FBSyxDQUFDOztNQUVsQztNQUNBLElBQUlsSCxJQUFJLENBQUNtSCxzQkFBc0IsQ0FBQyxDQUFDLEtBQUssSUFBSSxFQUFFO1FBQzFDbkgsSUFBSSxDQUFDdUcsb0JBQW9CLENBQUNTLE9BQU8sQ0FBQ3BYLEdBQUcsQ0FBQ3VILFVBQVUsQ0FBQyxDQUFDO1FBQ2xELEtBQUssSUFBSXNKLEVBQUUsSUFBSSxNQUFNLElBQUksQ0FBQzJHLGVBQWUsQ0FBQ3BILElBQUksQ0FBQyxFQUFFQyxHQUFHLENBQUNoRCxJQUFJLENBQUN3RCxFQUFFLENBQUM7TUFDL0Q7O01BRUE7TUFBQSxLQUNLO1FBQ0gsS0FBSyxJQUFJckosYUFBYSxJQUFJNFAsT0FBTyxDQUFDcFgsR0FBRyxDQUFDdUgsVUFBVSxDQUFDLEVBQUU7VUFDakQ2SSxJQUFJLENBQUN1RyxvQkFBb0IsQ0FBQyxDQUFDblAsYUFBYSxDQUFDLENBQUM7VUFDMUMsS0FBSyxJQUFJcUosRUFBRSxJQUFJLE1BQU0sSUFBSSxDQUFDMkcsZUFBZSxDQUFDcEgsSUFBSSxDQUFDLEVBQUVDLEdBQUcsQ0FBQ2hELElBQUksQ0FBQ3dELEVBQUUsQ0FBQztRQUMvRDtNQUNGO0lBQ0Y7O0lBRUE7SUFDQSxJQUFJN04sZ0JBQWdCLENBQUMrUixRQUFRLENBQUMsQ0FBQyxFQUFFLE1BQU0sSUFBSSxDQUFDdkosSUFBSSxDQUFDLENBQUM7SUFDbEQsT0FBTzZFLEdBQUc7RUFDWjs7RUFFQSxNQUFNb0gsU0FBU0EsQ0FBQ0MsS0FBZSxFQUE2QjtJQUMxRCxJQUFJQSxLQUFLLEtBQUtuVyxTQUFTLEVBQUVtVyxLQUFLLEdBQUcsS0FBSztJQUN0QyxJQUFJdFAsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLFlBQVksRUFBRSxFQUFDcVQsWUFBWSxFQUFFLENBQUM2QixLQUFLLEVBQUMsQ0FBQztJQUM5RixJQUFJQSxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUNsTSxJQUFJLENBQUMsQ0FBQztJQUM1QixJQUFJbkQsTUFBTSxHQUFHRCxJQUFJLENBQUNDLE1BQU07SUFDeEIsSUFBSXNQLEtBQUssR0FBRy9XLGVBQWUsQ0FBQ2dXLHdCQUF3QixDQUFDdk8sTUFBTSxDQUFDO0lBQzVELElBQUlzUCxLQUFLLENBQUN6SSxNQUFNLENBQUMsQ0FBQyxLQUFLM04sU0FBUyxFQUFFLE9BQU8sRUFBRTtJQUMzQyxLQUFLLElBQUlzUCxFQUFFLElBQUk4RyxLQUFLLENBQUN6SSxNQUFNLENBQUMsQ0FBQyxFQUFFO01BQzdCMkIsRUFBRSxDQUFDK0csWUFBWSxDQUFDLENBQUNGLEtBQUssQ0FBQztNQUN2QjdHLEVBQUUsQ0FBQ2dILFdBQVcsQ0FBQ2hILEVBQUUsQ0FBQ2lILFlBQVksQ0FBQyxDQUFDLENBQUM7SUFDbkM7SUFDQSxPQUFPSCxLQUFLLENBQUN6SSxNQUFNLENBQUMsQ0FBQztFQUN2Qjs7RUFFQSxNQUFNNkksUUFBUUEsQ0FBQ0MsY0FBMkMsRUFBcUI7SUFDN0UsSUFBQXZRLGVBQU0sRUFBQ3dRLEtBQUssQ0FBQ0MsT0FBTyxDQUFDRixjQUFjLENBQUMsRUFBRSx5REFBeUQsQ0FBQztJQUNoRyxJQUFJekwsUUFBUSxHQUFHLEVBQUU7SUFDakIsS0FBSyxJQUFJNEwsWUFBWSxJQUFJSCxjQUFjLEVBQUU7TUFDdkMsSUFBSUksUUFBUSxHQUFHRCxZQUFZLFlBQVkzQix1QkFBYyxHQUFHMkIsWUFBWSxDQUFDRSxXQUFXLENBQUMsQ0FBQyxHQUFHRixZQUFZO01BQ2pHLElBQUkvUCxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsVUFBVSxFQUFFLEVBQUU4VixHQUFHLEVBQUVGLFFBQVEsQ0FBQyxDQUFDLENBQUM7TUFDdkY3TCxRQUFRLENBQUNjLElBQUksQ0FBQ2pGLElBQUksQ0FBQ0MsTUFBTSxDQUFDa1EsT0FBTyxDQUFDO0lBQ3BDO0lBQ0EsTUFBTSxJQUFJLENBQUMvTSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbkIsT0FBT2UsUUFBUTtFQUNqQjs7RUFFQSxNQUFNaU0sYUFBYUEsQ0FBQ2IsS0FBa0IsRUFBd0I7SUFDNUQsSUFBSXZQLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxtQkFBbUIsRUFBRTtNQUM1RWlXLGNBQWMsRUFBRWQsS0FBSyxDQUFDZSxnQkFBZ0IsQ0FBQyxDQUFDO01BQ3hDQyxjQUFjLEVBQUVoQixLQUFLLENBQUNpQixnQkFBZ0IsQ0FBQztJQUN6QyxDQUFDLENBQUM7SUFDRixPQUFPaFksZUFBZSxDQUFDaVksMEJBQTBCLENBQUN6USxJQUFJLENBQUNDLE1BQU0sQ0FBQztFQUNoRTs7RUFFQSxNQUFNeVEsT0FBT0EsQ0FBQ0MsYUFBcUIsRUFBd0I7SUFDekQsSUFBSTNRLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxlQUFlLEVBQUU7TUFDeEVpVyxjQUFjLEVBQUVNLGFBQWE7TUFDN0JDLFVBQVUsRUFBRTtJQUNkLENBQUMsQ0FBQztJQUNGLE1BQU0sSUFBSSxDQUFDeE4sSUFBSSxDQUFDLENBQUM7SUFDakIsT0FBTzVLLGVBQWUsQ0FBQ2dXLHdCQUF3QixDQUFDeE8sSUFBSSxDQUFDQyxNQUFNLENBQUM7RUFDOUQ7O0VBRUEsTUFBTTRRLFNBQVNBLENBQUNDLFdBQW1CLEVBQXFCO0lBQ3RELElBQUk5USxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsaUJBQWlCLEVBQUU7TUFDMUUyVyxXQUFXLEVBQUVEO0lBQ2YsQ0FBQyxDQUFDO0lBQ0YsTUFBTSxJQUFJLENBQUMxTixJQUFJLENBQUMsQ0FBQztJQUNqQixPQUFPcEQsSUFBSSxDQUFDQyxNQUFNLENBQUMrUSxZQUFZO0VBQ2pDOztFQUVBLE1BQU1DLFdBQVdBLENBQUNsVSxPQUFlLEVBQUVtVSxhQUFhLEdBQUdDLG1DQUEwQixDQUFDQyxtQkFBbUIsRUFBRWpTLFVBQVUsR0FBRyxDQUFDLEVBQUVDLGFBQWEsR0FBRyxDQUFDLEVBQW1CO0lBQ3JKLElBQUlZLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxNQUFNLEVBQUU7TUFDN0RpWCxJQUFJLEVBQUV0VSxPQUFPO01BQ2J1VSxjQUFjLEVBQUVKLGFBQWEsS0FBS0MsbUNBQTBCLENBQUNDLG1CQUFtQixHQUFHLE9BQU8sR0FBRyxNQUFNO01BQ25HdFIsYUFBYSxFQUFFWCxVQUFVO01BQ3pCZ0gsYUFBYSxFQUFFL0c7SUFDbkIsQ0FBQyxDQUFDO0lBQ0YsT0FBT1ksSUFBSSxDQUFDQyxNQUFNLENBQUNxTCxTQUFTO0VBQzlCOztFQUVBLE1BQU1pRyxhQUFhQSxDQUFDeFUsT0FBZSxFQUFFSixPQUFlLEVBQUUyTyxTQUFpQixFQUF5QztJQUM5RyxJQUFJO01BQ0YsSUFBSXRMLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxRQUFRLEVBQUUsRUFBQ2lYLElBQUksRUFBRXRVLE9BQU8sRUFBRUosT0FBTyxFQUFFQSxPQUFPLEVBQUUyTyxTQUFTLEVBQUVBLFNBQVMsRUFBQyxDQUFDO01BQzNILElBQUlyTCxNQUFNLEdBQUdELElBQUksQ0FBQ0MsTUFBTTtNQUN4QixPQUFPLElBQUl1UixxQ0FBNEI7UUFDckN2UixNQUFNLENBQUN3UixJQUFJLEdBQUcsRUFBQ0MsTUFBTSxFQUFFelIsTUFBTSxDQUFDd1IsSUFBSSxFQUFFRSxLQUFLLEVBQUUxUixNQUFNLENBQUMyUixHQUFHLEVBQUVWLGFBQWEsRUFBRWpSLE1BQU0sQ0FBQ3FSLGNBQWMsS0FBSyxNQUFNLEdBQUdILG1DQUEwQixDQUFDVSxrQkFBa0IsR0FBR1YsbUNBQTBCLENBQUNDLG1CQUFtQixFQUFFelEsT0FBTyxFQUFFVixNQUFNLENBQUNVLE9BQU8sRUFBQyxHQUFHLEVBQUMrUSxNQUFNLEVBQUUsS0FBSztNQUNwUCxDQUFDO0lBQ0gsQ0FBQyxDQUFDLE9BQU9sVSxDQUFNLEVBQUU7TUFDZixJQUFJQSxDQUFDLENBQUNMLE9BQU8sQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsT0FBTyxJQUFJcVUscUNBQTRCLENBQUMsRUFBQ0UsTUFBTSxFQUFFLEtBQUssRUFBQyxDQUFDO01BQ2hGLE1BQU1sVSxDQUFDO0lBQ1Q7RUFDRjs7RUFFQSxNQUFNc1UsUUFBUUEsQ0FBQ0MsTUFBYyxFQUFtQjtJQUM5QyxJQUFJO01BQ0YsT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDblosTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLFlBQVksRUFBRSxFQUFDNFgsSUFBSSxFQUFFRCxNQUFNLEVBQUMsQ0FBQyxFQUFFOVIsTUFBTSxDQUFDZ1MsTUFBTTtJQUNwRyxDQUFDLENBQUMsT0FBT3pVLENBQU0sRUFBRTtNQUNmLElBQUlBLENBQUMsWUFBWU4sdUJBQWMsSUFBSU0sQ0FBQyxDQUFDTCxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJSyxDQUFDLENBQUNULE9BQU8sQ0FBQ0UsUUFBUSxDQUFDLDBCQUEwQixDQUFDLEVBQUVPLENBQUMsR0FBRyxJQUFJTix1QkFBYyxDQUFDLDRCQUE0QixFQUFFTSxDQUFDLENBQUNMLE9BQU8sQ0FBQyxDQUFDLEVBQUVLLENBQUMsQ0FBQ0osWUFBWSxDQUFDLENBQUMsRUFBRUksQ0FBQyxDQUFDSCxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBRTtNQUNqTixNQUFNRyxDQUFDO0lBQ1Q7RUFDRjs7RUFFQSxNQUFNMFUsVUFBVUEsQ0FBQ0gsTUFBYyxFQUFFSSxLQUFhLEVBQUV4VixPQUFlLEVBQTBCO0lBQ3ZGLElBQUk7O01BRUY7TUFDQSxJQUFJcUQsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLGNBQWMsRUFBRSxFQUFDNFgsSUFBSSxFQUFFRCxNQUFNLEVBQUVFLE1BQU0sRUFBRUUsS0FBSyxFQUFFeFYsT0FBTyxFQUFFQSxPQUFPLEVBQUMsQ0FBQzs7TUFFekg7TUFDQSxJQUFJeVYsS0FBSyxHQUFHLElBQUlDLHNCQUFhLENBQUMsQ0FBQztNQUMvQkQsS0FBSyxDQUFDRSxTQUFTLENBQUMsSUFBSSxDQUFDO01BQ3JCRixLQUFLLENBQUNHLG1CQUFtQixDQUFDdlMsSUFBSSxDQUFDQyxNQUFNLENBQUN1UyxhQUFhLENBQUM7TUFDcERKLEtBQUssQ0FBQzNDLFdBQVcsQ0FBQ3pQLElBQUksQ0FBQ0MsTUFBTSxDQUFDd1MsT0FBTyxDQUFDO01BQ3RDTCxLQUFLLENBQUNNLGlCQUFpQixDQUFDbFQsTUFBTSxDQUFDUSxJQUFJLENBQUNDLE1BQU0sQ0FBQzBTLFFBQVEsQ0FBQyxDQUFDO01BQ3JELE9BQU9QLEtBQUs7SUFDZCxDQUFDLENBQUMsT0FBTzVVLENBQU0sRUFBRTtNQUNmLElBQUlBLENBQUMsWUFBWU4sdUJBQWMsSUFBSU0sQ0FBQyxDQUFDTCxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJSyxDQUFDLENBQUNULE9BQU8sQ0FBQ0UsUUFBUSxDQUFDLDBCQUEwQixDQUFDLEVBQUVPLENBQUMsR0FBRyxJQUFJTix1QkFBYyxDQUFDLDRCQUE0QixFQUFFTSxDQUFDLENBQUNMLE9BQU8sQ0FBQyxDQUFDLEVBQUVLLENBQUMsQ0FBQ0osWUFBWSxDQUFDLENBQUMsRUFBRUksQ0FBQyxDQUFDSCxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBRTtNQUNqTixNQUFNRyxDQUFDO0lBQ1Q7RUFDRjs7RUFFQSxNQUFNb1YsVUFBVUEsQ0FBQ2IsTUFBYyxFQUFFcFYsT0FBZSxFQUFFSSxPQUFnQixFQUFtQjtJQUNuRixJQUFJO01BQ0YsSUFBSWlELElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxjQUFjLEVBQUUsRUFBQzRYLElBQUksRUFBRUQsTUFBTSxFQUFFcFYsT0FBTyxFQUFFQSxPQUFPLEVBQUVJLE9BQU8sRUFBRUEsT0FBTyxFQUFDLENBQUM7TUFDNUgsT0FBT2lELElBQUksQ0FBQ0MsTUFBTSxDQUFDcUwsU0FBUztJQUM5QixDQUFDLENBQUMsT0FBTzlOLENBQU0sRUFBRTtNQUNmLElBQUlBLENBQUMsWUFBWU4sdUJBQWMsSUFBSU0sQ0FBQyxDQUFDTCxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJSyxDQUFDLENBQUNULE9BQU8sQ0FBQ0UsUUFBUSxDQUFDLDBCQUEwQixDQUFDLEVBQUVPLENBQUMsR0FBRyxJQUFJTix1QkFBYyxDQUFDLDRCQUE0QixFQUFFTSxDQUFDLENBQUNMLE9BQU8sQ0FBQyxDQUFDLEVBQUVLLENBQUMsQ0FBQ0osWUFBWSxDQUFDLENBQUMsRUFBRUksQ0FBQyxDQUFDSCxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBRTtNQUNqTixNQUFNRyxDQUFDO0lBQ1Q7RUFDRjs7RUFFQSxNQUFNcVYsWUFBWUEsQ0FBQ2QsTUFBYyxFQUFFcFYsT0FBZSxFQUFFSSxPQUEyQixFQUFFdU8sU0FBaUIsRUFBMEI7SUFDMUgsSUFBSTs7TUFFRjtNQUNBLElBQUl0TCxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsZ0JBQWdCLEVBQUU7UUFDekU0WCxJQUFJLEVBQUVELE1BQU07UUFDWnBWLE9BQU8sRUFBRUEsT0FBTztRQUNoQkksT0FBTyxFQUFFQSxPQUFPO1FBQ2hCdU8sU0FBUyxFQUFFQTtNQUNiLENBQUMsQ0FBQzs7TUFFRjtNQUNBLElBQUlvRyxNQUFNLEdBQUcxUixJQUFJLENBQUNDLE1BQU0sQ0FBQ3dSLElBQUk7TUFDN0IsSUFBSVcsS0FBSyxHQUFHLElBQUlDLHNCQUFhLENBQUMsQ0FBQztNQUMvQkQsS0FBSyxDQUFDRSxTQUFTLENBQUNaLE1BQU0sQ0FBQztNQUN2QixJQUFJQSxNQUFNLEVBQUU7UUFDVlUsS0FBSyxDQUFDRyxtQkFBbUIsQ0FBQ3ZTLElBQUksQ0FBQ0MsTUFBTSxDQUFDdVMsYUFBYSxDQUFDO1FBQ3BESixLQUFLLENBQUMzQyxXQUFXLENBQUN6UCxJQUFJLENBQUNDLE1BQU0sQ0FBQ3dTLE9BQU8sQ0FBQztRQUN0Q0wsS0FBSyxDQUFDTSxpQkFBaUIsQ0FBQ2xULE1BQU0sQ0FBQ1EsSUFBSSxDQUFDQyxNQUFNLENBQUMwUyxRQUFRLENBQUMsQ0FBQztNQUN2RDtNQUNBLE9BQU9QLEtBQUs7SUFDZCxDQUFDLENBQUMsT0FBTzVVLENBQU0sRUFBRTtNQUNmLElBQUlBLENBQUMsWUFBWU4sdUJBQWMsSUFBSU0sQ0FBQyxDQUFDTCxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJSyxDQUFDLENBQUNULE9BQU8sS0FBSyxjQUFjLEVBQUVTLENBQUMsR0FBRyxJQUFJTix1QkFBYyxDQUFDLDBDQUEwQyxFQUFFLENBQUMsQ0FBQyxDQUFDO01BQzdKLElBQUlNLENBQUMsWUFBWU4sdUJBQWMsSUFBSU0sQ0FBQyxDQUFDTCxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJSyxDQUFDLENBQUNULE9BQU8sQ0FBQ0UsUUFBUSxDQUFDLDBCQUEwQixDQUFDLEVBQUVPLENBQUMsR0FBRyxJQUFJTix1QkFBYyxDQUFDLDRCQUE0QixFQUFFTSxDQUFDLENBQUNMLE9BQU8sQ0FBQyxDQUFDLEVBQUVLLENBQUMsQ0FBQ0osWUFBWSxDQUFDLENBQUMsRUFBRUksQ0FBQyxDQUFDSCxZQUFZLENBQUMsQ0FBQyxDQUFDO01BQzlNLE1BQU1HLENBQUM7SUFDVDtFQUNGOztFQUVBLE1BQU1zVixhQUFhQSxDQUFDZixNQUFjLEVBQUVoVixPQUFnQixFQUFtQjtJQUNyRSxJQUFJO01BQ0YsSUFBSWlELElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxpQkFBaUIsRUFBRSxFQUFDNFgsSUFBSSxFQUFFRCxNQUFNLEVBQUVoVixPQUFPLEVBQUVBLE9BQU8sRUFBQyxDQUFDO01BQzdHLE9BQU9pRCxJQUFJLENBQUNDLE1BQU0sQ0FBQ3FMLFNBQVM7SUFDOUIsQ0FBQyxDQUFDLE9BQU85TixDQUFNLEVBQUU7TUFDZixJQUFJQSxDQUFDLFlBQVlOLHVCQUFjLElBQUlNLENBQUMsQ0FBQ0wsT0FBTyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSUssQ0FBQyxDQUFDVCxPQUFPLENBQUNFLFFBQVEsQ0FBQywwQkFBMEIsQ0FBQyxFQUFFTyxDQUFDLEdBQUcsSUFBSU4sdUJBQWMsQ0FBQyw0QkFBNEIsRUFBRU0sQ0FBQyxDQUFDTCxPQUFPLENBQUMsQ0FBQyxFQUFFSyxDQUFDLENBQUNKLFlBQVksQ0FBQyxDQUFDLEVBQUVJLENBQUMsQ0FBQ0gsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUU7TUFDak4sTUFBTUcsQ0FBQztJQUNUO0VBQ0Y7O0VBRUEsTUFBTXVWLGVBQWVBLENBQUNoQixNQUFjLEVBQUVoVixPQUEyQixFQUFFdU8sU0FBaUIsRUFBb0I7SUFDdEcsSUFBSTtNQUNGLElBQUl0TCxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsbUJBQW1CLEVBQUU7UUFDNUU0WCxJQUFJLEVBQUVELE1BQU07UUFDWmhWLE9BQU8sRUFBRUEsT0FBTztRQUNoQnVPLFNBQVMsRUFBRUE7TUFDYixDQUFDLENBQUM7TUFDRixPQUFPdEwsSUFBSSxDQUFDQyxNQUFNLENBQUN3UixJQUFJO0lBQ3pCLENBQUMsQ0FBQyxPQUFPalUsQ0FBTSxFQUFFO01BQ2YsSUFBSUEsQ0FBQyxZQUFZTix1QkFBYyxJQUFJTSxDQUFDLENBQUNMLE9BQU8sQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUlLLENBQUMsQ0FBQ1QsT0FBTyxDQUFDRSxRQUFRLENBQUMsMEJBQTBCLENBQUMsRUFBRU8sQ0FBQyxHQUFHLElBQUlOLHVCQUFjLENBQUMsNEJBQTRCLEVBQUVNLENBQUMsQ0FBQ0wsT0FBTyxDQUFDLENBQUMsRUFBRUssQ0FBQyxDQUFDSixZQUFZLENBQUMsQ0FBQyxFQUFFSSxDQUFDLENBQUNILFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFFO01BQ2pOLE1BQU1HLENBQUM7SUFDVDtFQUNGOztFQUVBLE1BQU13VixxQkFBcUJBLENBQUNqVyxPQUFnQixFQUFtQjtJQUM3RCxJQUFJaUQsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLG1CQUFtQixFQUFFO01BQzVFb1EsR0FBRyxFQUFFLElBQUk7TUFDVHpOLE9BQU8sRUFBRUE7SUFDWCxDQUFDLENBQUM7SUFDRixPQUFPaUQsSUFBSSxDQUFDQyxNQUFNLENBQUNxTCxTQUFTO0VBQzlCOztFQUVBLE1BQU0ySCxzQkFBc0JBLENBQUM5VCxVQUFrQixFQUFFZ08sTUFBYyxFQUFFcFEsT0FBZ0IsRUFBbUI7SUFDbEcsSUFBSWlELElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxtQkFBbUIsRUFBRTtNQUM1RTBGLGFBQWEsRUFBRVgsVUFBVTtNQUN6QmdPLE1BQU0sRUFBRUEsTUFBTSxDQUFDQyxRQUFRLENBQUMsQ0FBQztNQUN6QnJRLE9BQU8sRUFBRUE7SUFDWCxDQUFDLENBQUM7SUFDRixPQUFPaUQsSUFBSSxDQUFDQyxNQUFNLENBQUNxTCxTQUFTO0VBQzlCOztFQUVBLE1BQU0vSyxpQkFBaUJBLENBQUM1RCxPQUFlLEVBQUVJLE9BQTJCLEVBQUV1TyxTQUFpQixFQUErQjs7SUFFcEg7SUFDQSxJQUFJdEwsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLHFCQUFxQixFQUFFO01BQzlFdUMsT0FBTyxFQUFFQSxPQUFPO01BQ2hCSSxPQUFPLEVBQUVBLE9BQU87TUFDaEJ1TyxTQUFTLEVBQUVBO0lBQ2IsQ0FBQyxDQUFDOztJQUVGO0lBQ0EsSUFBSW9HLE1BQU0sR0FBRzFSLElBQUksQ0FBQ0MsTUFBTSxDQUFDd1IsSUFBSTtJQUM3QixJQUFJVyxLQUFLLEdBQUcsSUFBSWMsMkJBQWtCLENBQUMsQ0FBQztJQUNwQ2QsS0FBSyxDQUFDRSxTQUFTLENBQUNaLE1BQU0sQ0FBQztJQUN2QixJQUFJQSxNQUFNLEVBQUU7TUFDVlUsS0FBSyxDQUFDZSx5QkFBeUIsQ0FBQzNULE1BQU0sQ0FBQ1EsSUFBSSxDQUFDQyxNQUFNLENBQUM0TCxLQUFLLENBQUMsQ0FBQztNQUMxRHVHLEtBQUssQ0FBQ2dCLGNBQWMsQ0FBQzVULE1BQU0sQ0FBQ1EsSUFBSSxDQUFDQyxNQUFNLENBQUNvVCxLQUFLLENBQUMsQ0FBQztJQUNqRDtJQUNBLE9BQU9qQixLQUFLO0VBQ2Q7O0VBRUEsTUFBTWtCLFVBQVVBLENBQUNuUCxRQUFrQixFQUFxQjtJQUN0RCxPQUFPLENBQUMsTUFBTSxJQUFJLENBQUN2TCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsY0FBYyxFQUFFLEVBQUNpSyxLQUFLLEVBQUVGLFFBQVEsRUFBQyxDQUFDLEVBQUVsRSxNQUFNLENBQUNzVCxLQUFLO0VBQ3hHOztFQUVBLE1BQU1DLFVBQVVBLENBQUNyUCxRQUFrQixFQUFFb1AsS0FBZSxFQUFpQjtJQUNuRSxNQUFNLElBQUksQ0FBQzNhLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxjQUFjLEVBQUUsRUFBQ2lLLEtBQUssRUFBRUYsUUFBUSxFQUFFb1AsS0FBSyxFQUFFQSxLQUFLLEVBQUMsQ0FBQztFQUNoRzs7RUFFQSxNQUFNRSxxQkFBcUJBLENBQUNDLFlBQXVCLEVBQXFDO0lBQ3RGLElBQUkxVCxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsa0JBQWtCLEVBQUUsRUFBQ3VaLE9BQU8sRUFBRUQsWUFBWSxFQUFDLENBQUM7SUFDckcsSUFBSSxDQUFDMVQsSUFBSSxDQUFDQyxNQUFNLENBQUMwVCxPQUFPLEVBQUUsT0FBTyxFQUFFO0lBQ25DLElBQUlBLE9BQU8sR0FBRyxFQUFFO0lBQ2hCLEtBQUssSUFBSUMsUUFBUSxJQUFJNVQsSUFBSSxDQUFDQyxNQUFNLENBQUMwVCxPQUFPLEVBQUU7TUFDeENBLE9BQU8sQ0FBQzFPLElBQUksQ0FBQyxJQUFJNE8sK0JBQXNCLENBQUMsQ0FBQyxDQUFDcFMsUUFBUSxDQUFDbVMsUUFBUSxDQUFDclMsS0FBSyxDQUFDLENBQUNtRixVQUFVLENBQUNrTixRQUFRLENBQUNqWCxPQUFPLENBQUMsQ0FBQ21YLGNBQWMsQ0FBQ0YsUUFBUSxDQUFDRyxXQUFXLENBQUMsQ0FBQ3pSLFlBQVksQ0FBQ3NSLFFBQVEsQ0FBQzVSLFVBQVUsQ0FBQyxDQUFDO0lBQ3pLO0lBQ0EsT0FBTzJSLE9BQU87RUFDaEI7O0VBRUEsTUFBTUssbUJBQW1CQSxDQUFDclgsT0FBZSxFQUFFb1gsV0FBb0IsRUFBbUI7SUFDaEYsSUFBSS9ULElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxrQkFBa0IsRUFBRSxFQUFDdUMsT0FBTyxFQUFFQSxPQUFPLEVBQUVvWCxXQUFXLEVBQUVBLFdBQVcsRUFBQyxDQUFDO0lBQzFILE9BQU8vVCxJQUFJLENBQUNDLE1BQU0sQ0FBQ3NCLEtBQUs7RUFDMUI7O0VBRUEsTUFBTTBTLG9CQUFvQkEsQ0FBQzFTLEtBQWEsRUFBRW1GLFVBQW1CLEVBQUUvSixPQUEyQixFQUFFbVgsY0FBdUIsRUFBRUMsV0FBK0IsRUFBaUI7SUFDbkssSUFBSS9ULElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxtQkFBbUIsRUFBRTtNQUM1RW1ILEtBQUssRUFBRUEsS0FBSztNQUNaMlMsV0FBVyxFQUFFeE4sVUFBVTtNQUN2Qi9KLE9BQU8sRUFBRUEsT0FBTztNQUNoQndYLGVBQWUsRUFBRUwsY0FBYztNQUMvQkMsV0FBVyxFQUFFQTtJQUNmLENBQUMsQ0FBQztFQUNKOztFQUVBLE1BQU1LLHNCQUFzQkEsQ0FBQ0MsUUFBZ0IsRUFBaUI7SUFDNUQsTUFBTSxJQUFJLENBQUN6YixNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMscUJBQXFCLEVBQUUsRUFBQ21ILEtBQUssRUFBRThTLFFBQVEsRUFBQyxDQUFDO0VBQ3pGOztFQUVBLE1BQU1DLFdBQVdBLENBQUM3UCxHQUFHLEVBQUU4UCxjQUFjLEVBQUU7SUFDckMsTUFBTSxJQUFJLENBQUMzYixNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsY0FBYyxFQUFFLEVBQUNxSyxHQUFHLEVBQUVBLEdBQUcsRUFBRUUsUUFBUSxFQUFFNFAsY0FBYyxFQUFDLENBQUM7RUFDckc7O0VBRUEsTUFBTUMsYUFBYUEsQ0FBQ0QsY0FBd0IsRUFBaUI7SUFDM0QsTUFBTSxJQUFJLENBQUMzYixNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsZ0JBQWdCLEVBQUUsRUFBQ3VLLFFBQVEsRUFBRTRQLGNBQWMsRUFBQyxDQUFDO0VBQzdGOztFQUVBLE1BQU1FLGNBQWNBLENBQUEsRUFBZ0M7SUFDbEQsSUFBSUMsSUFBSSxHQUFHLEVBQUU7SUFDYixJQUFJMVUsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLGtCQUFrQixDQUFDO0lBQzVFLElBQUk0RixJQUFJLENBQUNDLE1BQU0sQ0FBQzBVLFlBQVksRUFBRTtNQUM1QixLQUFLLElBQUlDLGFBQWEsSUFBSTVVLElBQUksQ0FBQ0MsTUFBTSxDQUFDMFUsWUFBWSxFQUFFO1FBQ2xERCxJQUFJLENBQUN6UCxJQUFJLENBQUMsSUFBSTRQLHlCQUFnQixDQUFDO1VBQzdCcFEsR0FBRyxFQUFFbVEsYUFBYSxDQUFDblEsR0FBRyxHQUFHbVEsYUFBYSxDQUFDblEsR0FBRyxHQUFHdEwsU0FBUztVQUN0RDRNLEtBQUssRUFBRTZPLGFBQWEsQ0FBQzdPLEtBQUssR0FBRzZPLGFBQWEsQ0FBQzdPLEtBQUssR0FBRzVNLFNBQVM7VUFDNURvYixjQUFjLEVBQUVLLGFBQWEsQ0FBQ2pRO1FBQ2hDLENBQUMsQ0FBQyxDQUFDO01BQ0w7SUFDRjtJQUNBLE9BQU8rUCxJQUFJO0VBQ2I7O0VBRUEsTUFBTUksa0JBQWtCQSxDQUFDclEsR0FBVyxFQUFFc0IsS0FBYSxFQUFpQjtJQUNsRSxNQUFNLElBQUksQ0FBQ25OLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyw2QkFBNkIsRUFBRSxFQUFDcUssR0FBRyxFQUFFQSxHQUFHLEVBQUVzUCxXQUFXLEVBQUVoTyxLQUFLLEVBQUMsQ0FBQztFQUM5Rzs7RUFFQSxNQUFNZ1AsYUFBYUEsQ0FBQ25jLE1BQXNCLEVBQW1CO0lBQzNEQSxNQUFNLEdBQUdILHFCQUFZLENBQUMrVCx3QkFBd0IsQ0FBQzVULE1BQU0sQ0FBQztJQUN0RCxJQUFJb0gsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLFVBQVUsRUFBRTtNQUNuRXVDLE9BQU8sRUFBRS9ELE1BQU0sQ0FBQ3FVLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUNqTSxVQUFVLENBQUMsQ0FBQztNQUNqRG1NLE1BQU0sRUFBRXZVLE1BQU0sQ0FBQ3FVLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUNDLFNBQVMsQ0FBQyxDQUFDLEdBQUd0VSxNQUFNLENBQUNxVSxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDQyxTQUFTLENBQUMsQ0FBQyxDQUFDRSxRQUFRLENBQUMsQ0FBQyxHQUFHalUsU0FBUztNQUNoSDZJLFVBQVUsRUFBRXBKLE1BQU0sQ0FBQzRVLFlBQVksQ0FBQyxDQUFDO01BQ2pDd0gsY0FBYyxFQUFFcGMsTUFBTSxDQUFDcWMsZ0JBQWdCLENBQUMsQ0FBQztNQUN6Q0MsY0FBYyxFQUFFdGMsTUFBTSxDQUFDdWMsT0FBTyxDQUFDO0lBQ2pDLENBQUMsQ0FBQztJQUNGLE9BQU9uVixJQUFJLENBQUNDLE1BQU0sQ0FBQ21WLEdBQUc7RUFDeEI7O0VBRUEsTUFBTUMsZUFBZUEsQ0FBQ0QsR0FBVyxFQUEyQjtJQUMxRCxJQUFBL1YsZUFBTSxFQUFDK1YsR0FBRyxFQUFFLDJCQUEyQixDQUFDO0lBQ3hDLElBQUlwVixJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsV0FBVyxFQUFFLEVBQUNnYixHQUFHLEVBQUVBLEdBQUcsRUFBQyxDQUFDO0lBQ2pGLElBQUl4YyxNQUFNLEdBQUcsSUFBSTBjLHVCQUFjLENBQUMsRUFBQzNZLE9BQU8sRUFBRXFELElBQUksQ0FBQ0MsTUFBTSxDQUFDbVYsR0FBRyxDQUFDelksT0FBTyxFQUFFd1EsTUFBTSxFQUFFM04sTUFBTSxDQUFDUSxJQUFJLENBQUNDLE1BQU0sQ0FBQ21WLEdBQUcsQ0FBQ2pJLE1BQU0sQ0FBQyxFQUFDLENBQUM7SUFDM0d2VSxNQUFNLENBQUMwSixZQUFZLENBQUN0QyxJQUFJLENBQUNDLE1BQU0sQ0FBQ21WLEdBQUcsQ0FBQ3BULFVBQVUsQ0FBQztJQUMvQ3BKLE1BQU0sQ0FBQzJjLGdCQUFnQixDQUFDdlYsSUFBSSxDQUFDQyxNQUFNLENBQUNtVixHQUFHLENBQUNKLGNBQWMsQ0FBQztJQUN2RHBjLE1BQU0sQ0FBQzRjLE9BQU8sQ0FBQ3hWLElBQUksQ0FBQ0MsTUFBTSxDQUFDbVYsR0FBRyxDQUFDRixjQUFjLENBQUM7SUFDOUMsSUFBSSxFQUFFLEtBQUt0YyxNQUFNLENBQUNxVSxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDak0sVUFBVSxDQUFDLENBQUMsRUFBRXBJLE1BQU0sQ0FBQ3FVLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUN2RyxVQUFVLENBQUN2TixTQUFTLENBQUM7SUFDdEcsSUFBSSxFQUFFLEtBQUtQLE1BQU0sQ0FBQzRVLFlBQVksQ0FBQyxDQUFDLEVBQUU1VSxNQUFNLENBQUMwSixZQUFZLENBQUNuSixTQUFTLENBQUM7SUFDaEUsSUFBSSxFQUFFLEtBQUtQLE1BQU0sQ0FBQ3FjLGdCQUFnQixDQUFDLENBQUMsRUFBRXJjLE1BQU0sQ0FBQzJjLGdCQUFnQixDQUFDcGMsU0FBUyxDQUFDO0lBQ3hFLElBQUksRUFBRSxLQUFLUCxNQUFNLENBQUN1YyxPQUFPLENBQUMsQ0FBQyxFQUFFdmMsTUFBTSxDQUFDNGMsT0FBTyxDQUFDcmMsU0FBUyxDQUFDO0lBQ3RELE9BQU9QLE1BQU07RUFDZjs7RUFFQSxNQUFNNmMsWUFBWUEsQ0FBQ3ZkLEdBQVcsRUFBbUI7SUFDL0MsSUFBSTtNQUNGLElBQUk4SCxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsZUFBZSxFQUFFLEVBQUNsQyxHQUFHLEVBQUVBLEdBQUcsRUFBQyxDQUFDO01BQ3JGLE9BQU84SCxJQUFJLENBQUNDLE1BQU0sQ0FBQ3lWLEtBQUssS0FBSyxFQUFFLEdBQUd2YyxTQUFTLEdBQUc2RyxJQUFJLENBQUNDLE1BQU0sQ0FBQ3lWLEtBQUs7SUFDakUsQ0FBQyxDQUFDLE9BQU9sWSxDQUFNLEVBQUU7TUFDZixJQUFJQSxDQUFDLFlBQVlOLHVCQUFjLElBQUlNLENBQUMsQ0FBQ0wsT0FBTyxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUUsRUFBRSxPQUFPaEUsU0FBUztNQUN4RSxNQUFNcUUsQ0FBQztJQUNUO0VBQ0Y7O0VBRUEsTUFBTW1ZLFlBQVlBLENBQUN6ZCxHQUFXLEVBQUUwZCxHQUFXLEVBQWlCO0lBQzFELE1BQU0sSUFBSSxDQUFDaGQsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLGVBQWUsRUFBRSxFQUFDbEMsR0FBRyxFQUFFQSxHQUFHLEVBQUV3ZCxLQUFLLEVBQUVFLEdBQUcsRUFBQyxDQUFDO0VBQ3hGOztFQUVBLE1BQU1DLFdBQVdBLENBQUNDLFVBQWtCLEVBQUVDLGdCQUEwQixFQUFFQyxhQUF1QixFQUFpQjtJQUN4RyxNQUFNLElBQUksQ0FBQ3BkLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxjQUFjLEVBQUU7TUFDNUQ2YixhQUFhLEVBQUVILFVBQVU7TUFDekJJLG9CQUFvQixFQUFFSCxnQkFBZ0I7TUFDdENJLGNBQWMsRUFBRUg7SUFDbEIsQ0FBQyxDQUFDO0VBQ0o7O0VBRUEsTUFBTUksVUFBVUEsQ0FBQSxFQUFrQjtJQUNoQyxNQUFNLElBQUksQ0FBQ3hkLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxhQUFhLENBQUM7RUFDOUQ7O0VBRUEsTUFBTWljLHNCQUFzQkEsQ0FBQSxFQUFxQjtJQUMvQyxJQUFJclcsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLGFBQWEsQ0FBQztJQUN2RSxPQUFPNEYsSUFBSSxDQUFDQyxNQUFNLENBQUNxVyxzQkFBc0IsS0FBSyxJQUFJO0VBQ3BEOztFQUVBLE1BQU1DLGVBQWVBLENBQUEsRUFBZ0M7SUFDbkQsSUFBSXZXLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxhQUFhLENBQUM7SUFDdkUsSUFBSTZGLE1BQU0sR0FBR0QsSUFBSSxDQUFDQyxNQUFNO0lBQ3hCLElBQUl1VyxJQUFJLEdBQUcsSUFBSUMsMkJBQWtCLENBQUMsQ0FBQztJQUNuQ0QsSUFBSSxDQUFDRSxhQUFhLENBQUN6VyxNQUFNLENBQUMwVyxRQUFRLENBQUM7SUFDbkNILElBQUksQ0FBQ0ksVUFBVSxDQUFDM1csTUFBTSxDQUFDNFcsS0FBSyxDQUFDO0lBQzdCTCxJQUFJLENBQUNNLFlBQVksQ0FBQzdXLE1BQU0sQ0FBQzhXLFNBQVMsQ0FBQztJQUNuQ1AsSUFBSSxDQUFDUSxrQkFBa0IsQ0FBQy9XLE1BQU0sQ0FBQ29ULEtBQUssQ0FBQztJQUNyQyxPQUFPbUQsSUFBSTtFQUNiOztFQUVBLE1BQU1TLGVBQWVBLENBQUEsRUFBb0I7SUFDdkMsSUFBSWpYLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxrQkFBa0IsRUFBRSxFQUFDa0MsNEJBQTRCLEVBQUUsSUFBSSxFQUFDLENBQUM7SUFDbEgsSUFBSSxDQUFDekQsWUFBWSxHQUFHLENBQUMsQ0FBQztJQUN0QixJQUFJb0gsTUFBTSxHQUFHRCxJQUFJLENBQUNDLE1BQU07SUFDeEIsT0FBT0EsTUFBTSxDQUFDaVgsYUFBYTtFQUM3Qjs7RUFFQSxNQUFNQyxZQUFZQSxDQUFDQyxhQUF1QixFQUFFTCxTQUFpQixFQUFFL2MsUUFBZ0IsRUFBbUI7SUFDaEcsSUFBSWdHLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxlQUFlLEVBQUU7TUFDeEU4YyxhQUFhLEVBQUVFLGFBQWE7TUFDNUJMLFNBQVMsRUFBRUEsU0FBUztNQUNwQi9jLFFBQVEsRUFBRUE7SUFDWixDQUFDLENBQUM7SUFDRixJQUFJLENBQUNuQixZQUFZLEdBQUcsQ0FBQyxDQUFDO0lBQ3RCLE9BQU9tSCxJQUFJLENBQUNDLE1BQU0sQ0FBQ2lYLGFBQWE7RUFDbEM7O0VBRUEsTUFBTUcsb0JBQW9CQSxDQUFDRCxhQUF1QixFQUFFcGQsUUFBZ0IsRUFBcUM7SUFDdkcsSUFBSWdHLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyx3QkFBd0IsRUFBRSxFQUFDOGMsYUFBYSxFQUFFRSxhQUFhLEVBQUVwZCxRQUFRLEVBQUVBLFFBQVEsRUFBQyxDQUFDO0lBQ3RJLElBQUksQ0FBQ25CLFlBQVksR0FBRyxDQUFDLENBQUM7SUFDdEIsSUFBSXllLFFBQVEsR0FBRyxJQUFJQyxpQ0FBd0IsQ0FBQyxDQUFDO0lBQzdDRCxRQUFRLENBQUM1USxVQUFVLENBQUMxRyxJQUFJLENBQUNDLE1BQU0sQ0FBQ3RELE9BQU8sQ0FBQztJQUN4QzJhLFFBQVEsQ0FBQ0UsY0FBYyxDQUFDeFgsSUFBSSxDQUFDQyxNQUFNLENBQUNpWCxhQUFhLENBQUM7SUFDbEQsSUFBSUksUUFBUSxDQUFDdFcsVUFBVSxDQUFDLENBQUMsQ0FBQ29ELE1BQU0sS0FBSyxDQUFDLEVBQUVrVCxRQUFRLENBQUM1USxVQUFVLENBQUN2TixTQUFTLENBQUM7SUFDdEUsSUFBSW1lLFFBQVEsQ0FBQ0csY0FBYyxDQUFDLENBQUMsQ0FBQ3JULE1BQU0sS0FBSyxDQUFDLEVBQUVrVCxRQUFRLENBQUNFLGNBQWMsQ0FBQ3JlLFNBQVMsQ0FBQztJQUM5RSxPQUFPbWUsUUFBUTtFQUNqQjs7RUFFQSxNQUFNSSxpQkFBaUJBLENBQUEsRUFBb0I7SUFDekMsSUFBSTFYLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxzQkFBc0IsQ0FBQztJQUNoRixPQUFPNEYsSUFBSSxDQUFDQyxNQUFNLENBQUN1VyxJQUFJO0VBQ3pCOztFQUVBLE1BQU1tQixpQkFBaUJBLENBQUNQLGFBQXVCLEVBQW1CO0lBQ2hFLElBQUksQ0FBQzlkLGlCQUFRLENBQUN3VyxPQUFPLENBQUNzSCxhQUFhLENBQUMsRUFBRSxNQUFNLElBQUloZSxvQkFBVyxDQUFDLDhDQUE4QyxDQUFDO0lBQzNHLElBQUk0RyxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsc0JBQXNCLEVBQUUsRUFBQ29jLElBQUksRUFBRVksYUFBYSxFQUFDLENBQUM7SUFDdkcsT0FBT3BYLElBQUksQ0FBQ0MsTUFBTSxDQUFDMlgsU0FBUztFQUM5Qjs7RUFFQSxNQUFNQyxpQkFBaUJBLENBQUNDLGFBQXFCLEVBQXFDO0lBQ2hGLElBQUk5WCxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsZUFBZSxFQUFFLEVBQUMyVyxXQUFXLEVBQUUrRyxhQUFhLEVBQUMsQ0FBQztJQUN2RyxJQUFJN1gsTUFBTSxHQUFHRCxJQUFJLENBQUNDLE1BQU07SUFDeEIsSUFBSThYLFVBQVUsR0FBRyxJQUFJQyxpQ0FBd0IsQ0FBQyxDQUFDO0lBQy9DRCxVQUFVLENBQUNFLHNCQUFzQixDQUFDaFksTUFBTSxDQUFDOFEsV0FBVyxDQUFDO0lBQ3JEZ0gsVUFBVSxDQUFDRyxXQUFXLENBQUNqWSxNQUFNLENBQUMrUSxZQUFZLENBQUM7SUFDM0MsT0FBTytHLFVBQVU7RUFDbkI7O0VBRUEsTUFBTUksbUJBQW1CQSxDQUFDQyxtQkFBMkIsRUFBcUI7SUFDeEUsSUFBSXBZLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxpQkFBaUIsRUFBRSxFQUFDMlcsV0FBVyxFQUFFcUgsbUJBQW1CLEVBQUMsQ0FBQztJQUMvRyxPQUFPcFksSUFBSSxDQUFDQyxNQUFNLENBQUMrUSxZQUFZO0VBQ2pDOztFQUVBLE1BQU1xSCxjQUFjQSxDQUFDQyxXQUFtQixFQUFFQyxXQUFtQixFQUFpQjtJQUM1RSxPQUFPLElBQUksQ0FBQzNmLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyx3QkFBd0IsRUFBRSxFQUFDb2UsWUFBWSxFQUFFRixXQUFXLElBQUksRUFBRSxFQUFFRyxZQUFZLEVBQUVGLFdBQVcsSUFBSSxFQUFFLEVBQUMsQ0FBQztFQUM5STs7RUFFQSxNQUFNRyxJQUFJQSxDQUFBLEVBQWtCO0lBQzFCLE1BQU0sSUFBSSxDQUFDOWYsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLE9BQU8sQ0FBQztFQUN4RDs7RUFFQSxNQUFNdWUsS0FBS0EsQ0FBQ0QsSUFBSSxHQUFHLEtBQUssRUFBaUI7SUFDdkMsTUFBTSxLQUFLLENBQUNDLEtBQUssQ0FBQ0QsSUFBSSxDQUFDO0lBQ3ZCLElBQUlBLElBQUksS0FBS3ZmLFNBQVMsRUFBRXVmLElBQUksR0FBRyxLQUFLO0lBQ3BDLE1BQU0sSUFBSSxDQUFDbmUsS0FBSyxDQUFDLENBQUM7SUFDbEIsTUFBTSxJQUFJLENBQUMzQixNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsY0FBYyxFQUFFLEVBQUNxQyxnQkFBZ0IsRUFBRWljLElBQUksRUFBQyxDQUFDO0VBQ3pGOztFQUVBLE1BQU1FLFFBQVFBLENBQUEsRUFBcUI7SUFDakMsSUFBSTtNQUNGLE1BQU0sSUFBSSxDQUFDOWQsaUJBQWlCLENBQUMsQ0FBQztJQUNoQyxDQUFDLENBQUMsT0FBTzBDLENBQU0sRUFBRTtNQUNmLE9BQU9BLENBQUMsWUFBWU4sdUJBQWMsSUFBSU0sQ0FBQyxDQUFDTCxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBRSxJQUFJSyxDQUFDLENBQUNULE9BQU8sQ0FBQ3lELE9BQU8sQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN2RztJQUNBLE9BQU8sS0FBSztFQUNkOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7RUFDRSxNQUFNcVksSUFBSUEsQ0FBQSxFQUFrQjtJQUMxQixNQUFNLElBQUksQ0FBQ3RlLEtBQUssQ0FBQyxDQUFDO0lBQ2xCLE1BQU0sSUFBSSxDQUFDM0IsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLGFBQWEsQ0FBQztFQUM5RDs7RUFFQTs7RUFFQSxNQUFNbU0sb0JBQW9CQSxDQUFBLEVBQWdDLENBQUUsT0FBTyxLQUFLLENBQUNBLG9CQUFvQixDQUFDLENBQUMsQ0FBRTtFQUNqRyxNQUFNOEIsS0FBS0EsQ0FBQzBKLE1BQWMsRUFBcUMsQ0FBRSxPQUFPLEtBQUssQ0FBQzFKLEtBQUssQ0FBQzBKLE1BQU0sQ0FBQyxDQUFFO0VBQzdGLE1BQU0rRyxvQkFBb0JBLENBQUMvUixLQUFtQyxFQUFxQyxDQUFFLE9BQU8sS0FBSyxDQUFDK1Isb0JBQW9CLENBQUMvUixLQUFLLENBQUMsQ0FBRTtFQUMvSSxNQUFNZ1Msb0JBQW9CQSxDQUFDaFMsS0FBbUMsRUFBRSxDQUFFLE9BQU8sS0FBSyxDQUFDZ1Msb0JBQW9CLENBQUNoUyxLQUFLLENBQUMsQ0FBRTtFQUM1RyxNQUFNaVMsUUFBUUEsQ0FBQ3BnQixNQUErQixFQUEyQixDQUFFLE9BQU8sS0FBSyxDQUFDb2dCLFFBQVEsQ0FBQ3BnQixNQUFNLENBQUMsQ0FBRTtFQUMxRyxNQUFNcWdCLE9BQU9BLENBQUNsSixZQUFxQyxFQUFtQixDQUFFLE9BQU8sS0FBSyxDQUFDa0osT0FBTyxDQUFDbEosWUFBWSxDQUFDLENBQUU7RUFDNUcsTUFBTW1KLFNBQVNBLENBQUNuSCxNQUFjLEVBQW1CLENBQUUsT0FBTyxLQUFLLENBQUNtSCxTQUFTLENBQUNuSCxNQUFNLENBQUMsQ0FBRTtFQUNuRixNQUFNb0gsU0FBU0EsQ0FBQ3BILE1BQWMsRUFBRXFILElBQVksRUFBaUIsQ0FBRSxPQUFPLEtBQUssQ0FBQ0QsU0FBUyxDQUFDcEgsTUFBTSxFQUFFcUgsSUFBSSxDQUFDLENBQUU7O0VBRXJHOztFQUVBLGFBQWFDLGtCQUFrQkEsQ0FBQ0MsV0FBMkYsRUFBRXRiLFFBQWlCLEVBQUVoRSxRQUFpQixFQUE0QjtJQUMzTCxJQUFJcEIsTUFBTSxHQUFHSixlQUFlLENBQUMrZ0IsZUFBZSxDQUFDRCxXQUFXLEVBQUV0YixRQUFRLEVBQUVoRSxRQUFRLENBQUM7SUFDN0UsSUFBSXBCLE1BQU0sQ0FBQzRnQixHQUFHLEVBQUUsT0FBT2hoQixlQUFlLENBQUNpaEIscUJBQXFCLENBQUM3Z0IsTUFBTSxDQUFDLENBQUM7SUFDaEUsT0FBTyxJQUFJSixlQUFlLENBQUNJLE1BQU0sQ0FBQztFQUN6Qzs7RUFFQSxhQUF1QjZnQixxQkFBcUJBLENBQUM3Z0IsTUFBbUMsRUFBNEI7SUFDMUcsSUFBQXlHLGVBQU0sRUFBQy9GLGlCQUFRLENBQUN3VyxPQUFPLENBQUNsWCxNQUFNLENBQUM0Z0IsR0FBRyxDQUFDLEVBQUUsd0RBQXdELENBQUM7O0lBRTlGO0lBQ0EsSUFBSUUsYUFBYSxHQUFHLE1BQUFDLE9BQUEsQ0FBQUMsT0FBQSxHQUFBQyxJQUFBLE9BQUF2aUIsdUJBQUEsQ0FBQTlDLE9BQUEsQ0FBYSxlQUFlLEdBQUM7SUFDakQsTUFBTXNsQixZQUFZLEdBQUdKLGFBQWEsQ0FBQ0ssS0FBSyxDQUFDbmhCLE1BQU0sQ0FBQzRnQixHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUU1Z0IsTUFBTSxDQUFDNGdCLEdBQUcsQ0FBQzFNLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRTtNQUMzRWtOLEdBQUcsRUFBRSxFQUFFLEdBQUdoaEIsT0FBTyxDQUFDZ2hCLEdBQUcsRUFBRUMsSUFBSSxFQUFFLGFBQWEsQ0FBQyxDQUFDLENBQUM7SUFDL0MsQ0FBQyxDQUFDO0lBQ0ZILFlBQVksQ0FBQ0ksTUFBTSxDQUFDQyxXQUFXLENBQUMsTUFBTSxDQUFDO0lBQ3ZDTCxZQUFZLENBQUNNLE1BQU0sQ0FBQ0QsV0FBVyxDQUFDLE1BQU0sQ0FBQzs7SUFFdkM7SUFDQSxJQUFJL0UsR0FBRztJQUNQLElBQUlpRixJQUFJLEdBQUcsSUFBSTtJQUNmLElBQUlwUixNQUFNLEdBQUcsRUFBRTtJQUNmLElBQUk7TUFDRixPQUFPLE1BQU0sSUFBSTBRLE9BQU8sQ0FBQyxVQUFTQyxPQUFPLEVBQUVVLE1BQU0sRUFBRTs7UUFFakQ7UUFDQVIsWUFBWSxDQUFDSSxNQUFNLENBQUNLLEVBQUUsQ0FBQyxNQUFNLEVBQUUsZ0JBQWVsSixJQUFJLEVBQUU7VUFDbEQsSUFBSW1KLElBQUksR0FBR25KLElBQUksQ0FBQ2pFLFFBQVEsQ0FBQyxDQUFDO1VBQzFCcU4scUJBQVksQ0FBQ0MsR0FBRyxDQUFDLENBQUMsRUFBRUYsSUFBSSxDQUFDO1VBQ3pCdlIsTUFBTSxJQUFJdVIsSUFBSSxHQUFHLElBQUksQ0FBQyxDQUFDOztVQUV2QjtVQUNBLElBQUlHLGVBQWUsR0FBRyxhQUFhO1VBQ25DLElBQUlDLGtCQUFrQixHQUFHSixJQUFJLENBQUNoYSxPQUFPLENBQUNtYSxlQUFlLENBQUM7VUFDdEQsSUFBSUMsa0JBQWtCLElBQUksQ0FBQyxFQUFFO1lBQzNCLElBQUlDLElBQUksR0FBR0wsSUFBSSxDQUFDTSxTQUFTLENBQUNGLGtCQUFrQixHQUFHRCxlQUFlLENBQUN2VyxNQUFNLEVBQUVvVyxJQUFJLENBQUNPLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUM3RixJQUFJQyxlQUFlLEdBQUdSLElBQUksQ0FBQ1MsT0FBTyxDQUFDLGVBQWUsRUFBRSxFQUFFLENBQUMsQ0FBQ0MsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2hFLElBQUlDLElBQUksR0FBR0gsZUFBZSxDQUFDRixTQUFTLENBQUNFLGVBQWUsQ0FBQ0QsV0FBVyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUMxRSxJQUFJSyxNQUFNLEdBQUd4aUIsTUFBTSxDQUFDNGdCLEdBQUcsQ0FBQ2haLE9BQU8sQ0FBQyxXQUFXLENBQUM7WUFDNUMsSUFBSTZhLFVBQVUsR0FBR0QsTUFBTSxJQUFJLENBQUMsR0FBRyxTQUFTLElBQUl4aUIsTUFBTSxDQUFDNGdCLEdBQUcsQ0FBQzRCLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQ3BlLFdBQVcsQ0FBQyxDQUFDLEdBQUcsS0FBSztZQUN4Rm9ZLEdBQUcsR0FBRyxDQUFDaUcsVUFBVSxHQUFHLE9BQU8sR0FBRyxNQUFNLElBQUksS0FBSyxHQUFHUixJQUFJLEdBQUcsR0FBRyxHQUFHTSxJQUFJO1VBQ25FOztVQUVBO1VBQ0EsSUFBSVgsSUFBSSxDQUFDaGEsT0FBTyxDQUFDLDRCQUE0QixDQUFDLElBQUksQ0FBQyxFQUFFOztZQUVuRDtZQUNBLElBQUk4YSxXQUFXLEdBQUcxaUIsTUFBTSxDQUFDNGdCLEdBQUcsQ0FBQ2haLE9BQU8sQ0FBQyxhQUFhLENBQUM7WUFDbkQsSUFBSSthLFFBQVEsR0FBR0QsV0FBVyxJQUFJLENBQUMsR0FBRzFpQixNQUFNLENBQUM0Z0IsR0FBRyxDQUFDOEIsV0FBVyxHQUFHLENBQUMsQ0FBQyxHQUFHbmlCLFNBQVM7WUFDekUsSUFBSTZFLFFBQVEsR0FBR3VkLFFBQVEsS0FBS3BpQixTQUFTLEdBQUdBLFNBQVMsR0FBR29pQixRQUFRLENBQUNULFNBQVMsQ0FBQyxDQUFDLEVBQUVTLFFBQVEsQ0FBQy9hLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNoRyxJQUFJeEcsUUFBUSxHQUFHdWhCLFFBQVEsS0FBS3BpQixTQUFTLEdBQUdBLFNBQVMsR0FBR29pQixRQUFRLENBQUNULFNBQVMsQ0FBQ1MsUUFBUSxDQUFDL2EsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQzs7WUFFakc7WUFDQTVILE1BQU0sR0FBR0EsTUFBTSxDQUFDb1AsSUFBSSxDQUFDLENBQUMsQ0FBQzNNLFNBQVMsQ0FBQyxFQUFDK1osR0FBRyxFQUFFQSxHQUFHLEVBQUVwWCxRQUFRLEVBQUVBLFFBQVEsRUFBRWhFLFFBQVEsRUFBRUEsUUFBUSxFQUFFd2hCLGtCQUFrQixFQUFFNWlCLE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLEdBQUdqQixNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDNGhCLHFCQUFxQixDQUFDLENBQUMsR0FBR3RpQixTQUFTLEVBQUMsQ0FBQztZQUNyTFAsTUFBTSxDQUFDNGdCLEdBQUcsR0FBR3JnQixTQUFTO1lBQ3RCLElBQUl1aUIsTUFBTSxHQUFHLE1BQU1sakIsZUFBZSxDQUFDNmdCLGtCQUFrQixDQUFDemdCLE1BQU0sQ0FBQztZQUM3RDhpQixNQUFNLENBQUMxaUIsT0FBTyxHQUFHOGdCLFlBQVk7O1lBRTdCO1lBQ0EsSUFBSSxDQUFDNkIsVUFBVSxHQUFHLElBQUk7WUFDdEIvQixPQUFPLENBQUM4QixNQUFNLENBQUM7VUFDakI7UUFDRixDQUFDLENBQUM7O1FBRUY7UUFDQTVCLFlBQVksQ0FBQ00sTUFBTSxDQUFDRyxFQUFFLENBQUMsTUFBTSxFQUFFLFVBQVNsSixJQUFJLEVBQUU7VUFDNUMsSUFBSW9KLHFCQUFZLENBQUNtQixXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRXJTLE9BQU8sQ0FBQ0MsS0FBSyxDQUFDNkgsSUFBSSxDQUFDO1FBQzFELENBQUMsQ0FBQzs7UUFFRjtRQUNBeUksWUFBWSxDQUFDUyxFQUFFLENBQUMsTUFBTSxFQUFFLFVBQVNzQixJQUFJLEVBQUU7VUFDckMsSUFBSSxDQUFDLElBQUksQ0FBQ0YsVUFBVSxFQUFFckIsTUFBTSxDQUFDLElBQUlsaEIsb0JBQVcsQ0FBQyxzREFBc0QsR0FBR3lpQixJQUFJLElBQUk1UyxNQUFNLEdBQUcsT0FBTyxHQUFHQSxNQUFNLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNqSixDQUFDLENBQUM7O1FBRUY7UUFDQTZRLFlBQVksQ0FBQ1MsRUFBRSxDQUFDLE9BQU8sRUFBRSxVQUFTcmUsR0FBRyxFQUFFO1VBQ3JDLElBQUlBLEdBQUcsQ0FBQ2EsT0FBTyxDQUFDeUQsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRThaLE1BQU0sQ0FBQyxJQUFJbGhCLG9CQUFXLENBQUMsNENBQTRDLEdBQUdSLE1BQU0sQ0FBQzRnQixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUM7VUFDbkksSUFBSSxDQUFDLElBQUksQ0FBQ21DLFVBQVUsRUFBRXJCLE1BQU0sQ0FBQ3BlLEdBQUcsQ0FBQztRQUNuQyxDQUFDLENBQUM7O1FBRUY7UUFDQTRkLFlBQVksQ0FBQ1MsRUFBRSxDQUFDLG1CQUFtQixFQUFFLFVBQVNyZSxHQUFHLEVBQUU0ZixNQUFNLEVBQUU7VUFDekR2UyxPQUFPLENBQUNDLEtBQUssQ0FBQyxtREFBbUQsR0FBR3ROLEdBQUcsQ0FBQ2EsT0FBTyxDQUFDO1VBQ2hGd00sT0FBTyxDQUFDQyxLQUFLLENBQUNzUyxNQUFNLENBQUM7VUFDckIsSUFBSSxDQUFDLElBQUksQ0FBQ0gsVUFBVSxFQUFFckIsTUFBTSxDQUFDcGUsR0FBRyxDQUFDO1FBQ25DLENBQUMsQ0FBQztNQUNKLENBQUMsQ0FBQztJQUNKLENBQUMsQ0FBQyxPQUFPQSxHQUFRLEVBQUU7TUFDakIsTUFBTSxJQUFJOUMsb0JBQVcsQ0FBQzhDLEdBQUcsQ0FBQ2EsT0FBTyxDQUFDO0lBQ3BDO0VBQ0Y7O0VBRUEsTUFBZ0J4QyxLQUFLQSxDQUFBLEVBQUc7SUFDdEIsSUFBSSxDQUFDOEYsZ0JBQWdCLENBQUMsQ0FBQztJQUN2QixPQUFPLElBQUksQ0FBQ3hILFlBQVk7SUFDeEIsSUFBSSxDQUFDQSxZQUFZLEdBQUcsQ0FBQyxDQUFDO0lBQ3RCLElBQUksQ0FBQ3FCLElBQUksR0FBR2YsU0FBUztFQUN2Qjs7RUFFQSxNQUFnQjRpQixpQkFBaUJBLENBQUNsUCxvQkFBMEIsRUFBRTtJQUM1RCxJQUFJbUMsT0FBTyxHQUFHLElBQUlyRixHQUFHLENBQUMsQ0FBQztJQUN2QixLQUFLLElBQUlqSyxPQUFPLElBQUksTUFBTSxJQUFJLENBQUNDLFdBQVcsQ0FBQyxDQUFDLEVBQUU7TUFDNUNxUCxPQUFPLENBQUN6VyxHQUFHLENBQUNtSCxPQUFPLENBQUNzRixRQUFRLENBQUMsQ0FBQyxFQUFFNkgsb0JBQW9CLEdBQUcsTUFBTSxJQUFJLENBQUNBLG9CQUFvQixDQUFDbk4sT0FBTyxDQUFDc0YsUUFBUSxDQUFDLENBQUMsQ0FBQyxHQUFHN0wsU0FBUyxDQUFDO0lBQ3pIO0lBQ0EsT0FBTzZWLE9BQU87RUFDaEI7O0VBRUEsTUFBZ0JuQyxvQkFBb0JBLENBQUMxTixVQUFVLEVBQUU7SUFDL0MsSUFBSStHLGlCQUFpQixHQUFHLEVBQUU7SUFDMUIsSUFBSWxHLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQ3BILE1BQU0sQ0FBQ2lCLFNBQVMsQ0FBQyxDQUFDLENBQUNPLGVBQWUsQ0FBQyxhQUFhLEVBQUUsRUFBQzBGLGFBQWEsRUFBRVgsVUFBVSxFQUFDLENBQUM7SUFDcEcsS0FBSyxJQUFJeEMsT0FBTyxJQUFJcUQsSUFBSSxDQUFDQyxNQUFNLENBQUNxRyxTQUFTLEVBQUVKLGlCQUFpQixDQUFDakIsSUFBSSxDQUFDdEksT0FBTyxDQUFDd0osYUFBYSxDQUFDO0lBQ3hGLE9BQU9ELGlCQUFpQjtFQUMxQjs7RUFFQSxNQUFnQjBCLGVBQWVBLENBQUNiLEtBQTBCLEVBQUU7O0lBRTFEO0lBQ0EsSUFBSWlWLE9BQU8sR0FBR2pWLEtBQUssQ0FBQ21ELFVBQVUsQ0FBQyxDQUFDO0lBQ2hDLElBQUkrUixjQUFjLEdBQUdELE9BQU8sQ0FBQzFTLGNBQWMsQ0FBQyxDQUFDLEtBQUssS0FBSyxJQUFJMFMsT0FBTyxDQUFDRSxXQUFXLENBQUMsQ0FBQyxLQUFLLElBQUksSUFBSUYsT0FBTyxDQUFDRyxXQUFXLENBQUMsQ0FBQyxLQUFLLElBQUksSUFBSUgsT0FBTyxDQUFDdE0sWUFBWSxDQUFDLENBQUMsS0FBSyxLQUFLO0lBQy9KLElBQUkwTSxhQUFhLEdBQUdKLE9BQU8sQ0FBQzFTLGNBQWMsQ0FBQyxDQUFDLEtBQUssSUFBSSxJQUFJMFMsT0FBTyxDQUFDRSxXQUFXLENBQUMsQ0FBQyxLQUFLLEtBQUssSUFBSUYsT0FBTyxDQUFDRyxXQUFXLENBQUMsQ0FBQyxLQUFLLElBQUksSUFBSUgsT0FBTyxDQUFDeFosU0FBUyxDQUFDLENBQUMsS0FBS3JKLFNBQVMsSUFBSTZpQixPQUFPLENBQUNLLFlBQVksQ0FBQyxDQUFDLEtBQUtsakIsU0FBUyxJQUFJNmlCLE9BQU8sQ0FBQ00sV0FBVyxDQUFDLENBQUMsS0FBSyxLQUFLO0lBQzFPLElBQUlDLGFBQWEsR0FBR3hWLEtBQUssQ0FBQ3lWLGFBQWEsQ0FBQyxDQUFDLEtBQUssS0FBSyxJQUFJelYsS0FBSyxDQUFDMFYsYUFBYSxDQUFDLENBQUMsS0FBSyxJQUFJLElBQUkxVixLQUFLLENBQUMyVixrQkFBa0IsQ0FBQyxDQUFDLEtBQUssSUFBSTtJQUM1SCxJQUFJQyxhQUFhLEdBQUc1VixLQUFLLENBQUMwVixhQUFhLENBQUMsQ0FBQyxLQUFLLEtBQUssSUFBSTFWLEtBQUssQ0FBQ3lWLGFBQWEsQ0FBQyxDQUFDLEtBQUssSUFBSTs7SUFFckY7SUFDQSxJQUFJUixPQUFPLENBQUNFLFdBQVcsQ0FBQyxDQUFDLEtBQUssSUFBSSxJQUFJLENBQUNFLGFBQWEsRUFBRTtNQUNwRCxNQUFNLElBQUloakIsb0JBQVcsQ0FBQyxxRUFBcUUsQ0FBQztJQUM5Rjs7SUFFQSxJQUFJNEMsTUFBVyxHQUFHLENBQUMsQ0FBQztJQUNwQkEsTUFBTSxDQUFDNGdCLEVBQUUsR0FBR0wsYUFBYSxJQUFJTixjQUFjO0lBQzNDamdCLE1BQU0sQ0FBQzZnQixHQUFHLEdBQUdGLGFBQWEsSUFBSVYsY0FBYztJQUM1Q2pnQixNQUFNLENBQUM4Z0IsSUFBSSxHQUFHUCxhQUFhLElBQUlILGFBQWE7SUFDNUNwZ0IsTUFBTSxDQUFDK2dCLE9BQU8sR0FBR0osYUFBYSxJQUFJUCxhQUFhO0lBQy9DcGdCLE1BQU0sQ0FBQ2doQixNQUFNLEdBQUdoQixPQUFPLENBQUNHLFdBQVcsQ0FBQyxDQUFDLEtBQUssS0FBSyxJQUFJSCxPQUFPLENBQUMxUyxjQUFjLENBQUMsQ0FBQyxLQUFLLElBQUksSUFBSTBTLE9BQU8sQ0FBQ0UsV0FBVyxDQUFDLENBQUMsSUFBSSxJQUFJO0lBQ3JILElBQUlGLE9BQU8sQ0FBQ2lCLFlBQVksQ0FBQyxDQUFDLEtBQUs5akIsU0FBUyxFQUFFO01BQ3hDLElBQUk2aUIsT0FBTyxDQUFDaUIsWUFBWSxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUVqaEIsTUFBTSxDQUFDa2hCLFVBQVUsR0FBR2xCLE9BQU8sQ0FBQ2lCLFlBQVksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7TUFBQSxLQUMzRWpoQixNQUFNLENBQUNraEIsVUFBVSxHQUFHbEIsT0FBTyxDQUFDaUIsWUFBWSxDQUFDLENBQUM7SUFDakQ7SUFDQSxJQUFJakIsT0FBTyxDQUFDSyxZQUFZLENBQUMsQ0FBQyxLQUFLbGpCLFNBQVMsRUFBRTZDLE1BQU0sQ0FBQ21oQixVQUFVLEdBQUduQixPQUFPLENBQUNLLFlBQVksQ0FBQyxDQUFDO0lBQ3BGcmdCLE1BQU0sQ0FBQ29oQixnQkFBZ0IsR0FBR3BCLE9BQU8sQ0FBQ2lCLFlBQVksQ0FBQyxDQUFDLEtBQUs5akIsU0FBUyxJQUFJNmlCLE9BQU8sQ0FBQ0ssWUFBWSxDQUFDLENBQUMsS0FBS2xqQixTQUFTO0lBQ3RHLElBQUk0TixLQUFLLENBQUN0QixlQUFlLENBQUMsQ0FBQyxLQUFLdE0sU0FBUyxFQUFFO01BQ3pDLElBQUFrRyxlQUFNLEVBQUMwSCxLQUFLLENBQUNzVyxrQkFBa0IsQ0FBQyxDQUFDLEtBQUtsa0IsU0FBUyxJQUFJNE4sS0FBSyxDQUFDOEYsb0JBQW9CLENBQUMsQ0FBQyxLQUFLMVQsU0FBUyxFQUFFLDZEQUE2RCxDQUFDO01BQzdKNkMsTUFBTSxDQUFDc0osWUFBWSxHQUFHLElBQUk7SUFDNUIsQ0FBQyxNQUFNO01BQ0x0SixNQUFNLENBQUM4RCxhQUFhLEdBQUdpSCxLQUFLLENBQUN0QixlQUFlLENBQUMsQ0FBQzs7TUFFOUM7TUFDQSxJQUFJUyxpQkFBaUIsR0FBRyxJQUFJaUMsR0FBRyxDQUFDLENBQUM7TUFDakMsSUFBSXBCLEtBQUssQ0FBQ3NXLGtCQUFrQixDQUFDLENBQUMsS0FBS2xrQixTQUFTLEVBQUUrTSxpQkFBaUIsQ0FBQ29DLEdBQUcsQ0FBQ3ZCLEtBQUssQ0FBQ3NXLGtCQUFrQixDQUFDLENBQUMsQ0FBQztNQUMvRixJQUFJdFcsS0FBSyxDQUFDOEYsb0JBQW9CLENBQUMsQ0FBQyxLQUFLMVQsU0FBUyxFQUFFNE4sS0FBSyxDQUFDOEYsb0JBQW9CLENBQUMsQ0FBQyxDQUFDM0IsR0FBRyxDQUFDLENBQUE5TCxhQUFhLEtBQUk4RyxpQkFBaUIsQ0FBQ29DLEdBQUcsQ0FBQ2xKLGFBQWEsQ0FBQyxDQUFDO01BQ3ZJLElBQUk4RyxpQkFBaUIsQ0FBQ29YLElBQUksRUFBRXRoQixNQUFNLENBQUN1UixlQUFlLEdBQUdzQyxLQUFLLENBQUMwTixJQUFJLENBQUNyWCxpQkFBaUIsQ0FBQztJQUNwRjs7SUFFQTtJQUNBLElBQUlxQyxLQUFLLEdBQUcsQ0FBQyxDQUFDO0lBQ2QsSUFBSUMsUUFBUSxHQUFHLENBQUMsQ0FBQzs7SUFFakI7SUFDQSxJQUFJeEksSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDcEgsTUFBTSxDQUFDaUIsU0FBUyxDQUFDLENBQUMsQ0FBQ08sZUFBZSxDQUFDLGVBQWUsRUFBRTRCLE1BQU0sQ0FBQztJQUNqRixLQUFLLElBQUk5RCxHQUFHLElBQUlILE1BQU0sQ0FBQ2tYLElBQUksQ0FBQ2pQLElBQUksQ0FBQ0MsTUFBTSxDQUFDLEVBQUU7TUFDeEMsS0FBSyxJQUFJdWQsS0FBSyxJQUFJeGQsSUFBSSxDQUFDQyxNQUFNLENBQUMvSCxHQUFHLENBQUMsRUFBRTtRQUNsQztRQUNBLElBQUl1USxFQUFFLEdBQUdqUSxlQUFlLENBQUNpbEIsd0JBQXdCLENBQUNELEtBQUssQ0FBQztRQUN4RCxJQUFJL1UsRUFBRSxDQUFDYSxjQUFjLENBQUMsQ0FBQyxFQUFFLElBQUFqSyxlQUFNLEVBQUNvSixFQUFFLENBQUNXLFFBQVEsQ0FBQyxDQUFDLENBQUN0QyxNQUFNLENBQUMsQ0FBQyxDQUFDdEcsT0FBTyxDQUFDaUksRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7O1FBRXhFO1FBQ0E7UUFDQSxJQUFJQSxFQUFFLENBQUM2RixtQkFBbUIsQ0FBQyxDQUFDLEtBQUtuVixTQUFTLElBQUlzUCxFQUFFLENBQUNpSCxZQUFZLENBQUMsQ0FBQyxJQUFJLENBQUNqSCxFQUFFLENBQUMwVCxXQUFXLENBQUMsQ0FBQztRQUNoRjFULEVBQUUsQ0FBQzZGLG1CQUFtQixDQUFDLENBQUMsQ0FBQ3JCLGVBQWUsQ0FBQyxDQUFDLElBQUl4RSxFQUFFLENBQUNpVixpQkFBaUIsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFO1VBQy9FLElBQUlDLGdCQUFnQixHQUFHbFYsRUFBRSxDQUFDNkYsbUJBQW1CLENBQUMsQ0FBQztVQUMvQyxJQUFJc1AsYUFBYSxHQUFHcGUsTUFBTSxDQUFDLENBQUMsQ0FBQztVQUM3QixLQUFLLElBQUl3TixXQUFXLElBQUkyUSxnQkFBZ0IsQ0FBQzFRLGVBQWUsQ0FBQyxDQUFDLEVBQUUyUSxhQUFhLEdBQUdBLGFBQWEsR0FBRzVRLFdBQVcsQ0FBQ0UsU0FBUyxDQUFDLENBQUM7VUFDbkh6RSxFQUFFLENBQUM2RixtQkFBbUIsQ0FBQyxDQUFDLENBQUNPLFNBQVMsQ0FBQytPLGFBQWEsQ0FBQztRQUNuRDs7UUFFQTtRQUNBcGxCLGVBQWUsQ0FBQ2tRLE9BQU8sQ0FBQ0QsRUFBRSxFQUFFRixLQUFLLEVBQUVDLFFBQVEsQ0FBQztNQUM5QztJQUNGOztJQUVBO0lBQ0EsSUFBSVAsR0FBcUIsR0FBR2xRLE1BQU0sQ0FBQzhsQixNQUFNLENBQUN0VixLQUFLLENBQUM7SUFDaEROLEdBQUcsQ0FBQzZWLElBQUksQ0FBQ3RsQixlQUFlLENBQUN1bEIsa0JBQWtCLENBQUM7O0lBRTVDO0lBQ0EsSUFBSXBXLFNBQVMsR0FBRyxFQUFFO0lBQ2xCLEtBQUssSUFBSWMsRUFBRSxJQUFJUixHQUFHLEVBQUU7O01BRWxCO01BQ0EsSUFBSVEsRUFBRSxDQUFDK1QsYUFBYSxDQUFDLENBQUMsS0FBS3JqQixTQUFTLEVBQUVzUCxFQUFFLENBQUN1VixhQUFhLENBQUMsS0FBSyxDQUFDO01BQzdELElBQUl2VixFQUFFLENBQUNnVSxhQUFhLENBQUMsQ0FBQyxLQUFLdGpCLFNBQVMsRUFBRXNQLEVBQUUsQ0FBQ3dWLGFBQWEsQ0FBQyxLQUFLLENBQUM7O01BRTdEO01BQ0EsSUFBSXhWLEVBQUUsQ0FBQ3FRLG9CQUFvQixDQUFDLENBQUMsS0FBSzNmLFNBQVMsRUFBRXNQLEVBQUUsQ0FBQ3FRLG9CQUFvQixDQUFDLENBQUMsQ0FBQ2dGLElBQUksQ0FBQ3RsQixlQUFlLENBQUMwbEIsd0JBQXdCLENBQUM7O01BRXJIO01BQ0EsS0FBSyxJQUFJOVYsUUFBUSxJQUFJSyxFQUFFLENBQUMwQixlQUFlLENBQUNwRCxLQUFLLENBQUMsRUFBRTtRQUM5Q1ksU0FBUyxDQUFDMUMsSUFBSSxDQUFDbUQsUUFBUSxDQUFDO01BQzFCOztNQUVBO01BQ0EsSUFBSUssRUFBRSxDQUFDVyxRQUFRLENBQUMsQ0FBQyxLQUFLalEsU0FBUyxJQUFJc1AsRUFBRSxDQUFDNkYsbUJBQW1CLENBQUMsQ0FBQyxLQUFLblYsU0FBUyxJQUFJc1AsRUFBRSxDQUFDcVEsb0JBQW9CLENBQUMsQ0FBQyxLQUFLM2YsU0FBUyxFQUFFO1FBQ3BIc1AsRUFBRSxDQUFDVyxRQUFRLENBQUMsQ0FBQyxDQUFDdEMsTUFBTSxDQUFDLENBQUMsQ0FBQ3VDLE1BQU0sQ0FBQ1osRUFBRSxDQUFDVyxRQUFRLENBQUMsQ0FBQyxDQUFDdEMsTUFBTSxDQUFDLENBQUMsQ0FBQ3RHLE9BQU8sQ0FBQ2lJLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztNQUN0RTtJQUNGOztJQUVBLE9BQU9kLFNBQVM7RUFDbEI7O0VBRUEsTUFBZ0JvQixhQUFhQSxDQUFDaEMsS0FBSyxFQUFFOztJQUVuQztJQUNBLElBQUlpSSxPQUFPLEdBQUcsSUFBSXJGLEdBQUcsQ0FBQyxDQUFDO0lBQ3ZCLElBQUk1QyxLQUFLLENBQUN0QixlQUFlLENBQUMsQ0FBQyxLQUFLdE0sU0FBUyxFQUFFO01BQ3pDLElBQUkrTSxpQkFBaUIsR0FBRyxJQUFJaUMsR0FBRyxDQUFDLENBQUM7TUFDakMsSUFBSXBCLEtBQUssQ0FBQ3NXLGtCQUFrQixDQUFDLENBQUMsS0FBS2xrQixTQUFTLEVBQUUrTSxpQkFBaUIsQ0FBQ29DLEdBQUcsQ0FBQ3ZCLEtBQUssQ0FBQ3NXLGtCQUFrQixDQUFDLENBQUMsQ0FBQztNQUMvRixJQUFJdFcsS0FBSyxDQUFDOEYsb0JBQW9CLENBQUMsQ0FBQyxLQUFLMVQsU0FBUyxFQUFFNE4sS0FBSyxDQUFDOEYsb0JBQW9CLENBQUMsQ0FBQyxDQUFDM0IsR0FBRyxDQUFDLENBQUE5TCxhQUFhLEtBQUk4RyxpQkFBaUIsQ0FBQ29DLEdBQUcsQ0FBQ2xKLGFBQWEsQ0FBQyxDQUFDO01BQ3ZJNFAsT0FBTyxDQUFDelcsR0FBRyxDQUFDd08sS0FBSyxDQUFDdEIsZUFBZSxDQUFDLENBQUMsRUFBRVMsaUJBQWlCLENBQUNvWCxJQUFJLEdBQUd6TixLQUFLLENBQUMwTixJQUFJLENBQUNyWCxpQkFBaUIsQ0FBQyxHQUFHL00sU0FBUyxDQUFDLENBQUMsQ0FBRTtJQUM3RyxDQUFDLE1BQU07TUFDTGtHLGVBQU0sQ0FBQ0MsS0FBSyxDQUFDeUgsS0FBSyxDQUFDc1csa0JBQWtCLENBQUMsQ0FBQyxFQUFFbGtCLFNBQVMsRUFBRSw2REFBNkQsQ0FBQztNQUNsSCxJQUFBa0csZUFBTSxFQUFDMEgsS0FBSyxDQUFDOEYsb0JBQW9CLENBQUMsQ0FBQyxLQUFLMVQsU0FBUyxJQUFJNE4sS0FBSyxDQUFDOEYsb0JBQW9CLENBQUMsQ0FBQyxDQUFDekksTUFBTSxLQUFLLENBQUMsRUFBRSw2REFBNkQsQ0FBQztNQUM5SjRLLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQytNLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxDQUFFO0lBQzdDOztJQUVBO0lBQ0EsSUFBSXhULEtBQUssR0FBRyxDQUFDLENBQUM7SUFDZCxJQUFJQyxRQUFRLEdBQUcsQ0FBQyxDQUFDOztJQUVqQjtJQUNBLElBQUl4TSxNQUFXLEdBQUcsQ0FBQyxDQUFDO0lBQ3BCQSxNQUFNLENBQUNtaUIsYUFBYSxHQUFHcFgsS0FBSyxDQUFDcVgsVUFBVSxDQUFDLENBQUMsS0FBSyxJQUFJLEdBQUcsYUFBYSxHQUFHclgsS0FBSyxDQUFDcVgsVUFBVSxDQUFDLENBQUMsS0FBSyxLQUFLLEdBQUcsV0FBVyxHQUFHLEtBQUs7SUFDdkhwaUIsTUFBTSxDQUFDcWlCLE9BQU8sR0FBRyxJQUFJO0lBQ3JCLEtBQUssSUFBSWxmLFVBQVUsSUFBSTZQLE9BQU8sQ0FBQ0MsSUFBSSxDQUFDLENBQUMsRUFBRTs7TUFFckM7TUFDQWpULE1BQU0sQ0FBQzhELGFBQWEsR0FBR1gsVUFBVTtNQUNqQ25ELE1BQU0sQ0FBQ3VSLGVBQWUsR0FBR3lCLE9BQU8sQ0FBQ3BYLEdBQUcsQ0FBQ3VILFVBQVUsQ0FBQztNQUNoRCxJQUFJYSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsb0JBQW9CLEVBQUU0QixNQUFNLENBQUM7O01BRXRGO01BQ0EsSUFBSWdFLElBQUksQ0FBQ0MsTUFBTSxDQUFDMEgsU0FBUyxLQUFLeE8sU0FBUyxFQUFFO01BQ3pDLEtBQUssSUFBSW1sQixTQUFTLElBQUl0ZSxJQUFJLENBQUNDLE1BQU0sQ0FBQzBILFNBQVMsRUFBRTtRQUMzQyxJQUFJYyxFQUFFLEdBQUdqUSxlQUFlLENBQUMrbEIsNEJBQTRCLENBQUNELFNBQVMsQ0FBQztRQUNoRTlsQixlQUFlLENBQUNrUSxPQUFPLENBQUNELEVBQUUsRUFBRUYsS0FBSyxFQUFFQyxRQUFRLENBQUM7TUFDOUM7SUFDRjs7SUFFQTtJQUNBLElBQUlQLEdBQXFCLEdBQUdsUSxNQUFNLENBQUM4bEIsTUFBTSxDQUFDdFYsS0FBSyxDQUFDO0lBQ2hETixHQUFHLENBQUM2VixJQUFJLENBQUN0bEIsZUFBZSxDQUFDdWxCLGtCQUFrQixDQUFDOztJQUU1QztJQUNBLElBQUlqVixPQUFPLEdBQUcsRUFBRTtJQUNoQixLQUFLLElBQUlMLEVBQUUsSUFBSVIsR0FBRyxFQUFFOztNQUVsQjtNQUNBLElBQUlRLEVBQUUsQ0FBQzJCLFVBQVUsQ0FBQyxDQUFDLEtBQUtqUixTQUFTLEVBQUVzUCxFQUFFLENBQUMyQixVQUFVLENBQUMsQ0FBQyxDQUFDMFQsSUFBSSxDQUFDdGxCLGVBQWUsQ0FBQ2dtQixjQUFjLENBQUM7O01BRXZGO01BQ0EsS0FBSyxJQUFJdlYsTUFBTSxJQUFJUixFQUFFLENBQUM2QixhQUFhLENBQUN2RCxLQUFLLENBQUMsRUFBRStCLE9BQU8sQ0FBQzdELElBQUksQ0FBQ2dFLE1BQU0sQ0FBQzs7TUFFaEU7TUFDQSxJQUFJUixFQUFFLENBQUMyQixVQUFVLENBQUMsQ0FBQyxLQUFLalIsU0FBUyxJQUFJc1AsRUFBRSxDQUFDVyxRQUFRLENBQUMsQ0FBQyxLQUFLalEsU0FBUyxFQUFFO1FBQ2hFc1AsRUFBRSxDQUFDVyxRQUFRLENBQUMsQ0FBQyxDQUFDdEMsTUFBTSxDQUFDLENBQUMsQ0FBQ3VDLE1BQU0sQ0FBQ1osRUFBRSxDQUFDVyxRQUFRLENBQUMsQ0FBQyxDQUFDdEMsTUFBTSxDQUFDLENBQUMsQ0FBQ3RHLE9BQU8sQ0FBQ2lJLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztNQUN0RTtJQUNGO0lBQ0EsT0FBT0ssT0FBTztFQUNoQjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDRSxNQUFnQmdDLGtCQUFrQkEsQ0FBQ04sR0FBRyxFQUFFO0lBQ3RDLElBQUl4SyxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsbUJBQW1CLEVBQUUsRUFBQ29RLEdBQUcsRUFBRUEsR0FBRyxFQUFDLENBQUM7SUFDekYsSUFBSSxDQUFDeEssSUFBSSxDQUFDQyxNQUFNLENBQUN1TCxpQkFBaUIsRUFBRSxPQUFPLEVBQUU7SUFDN0MsT0FBT3hMLElBQUksQ0FBQ0MsTUFBTSxDQUFDdUwsaUJBQWlCLENBQUNOLEdBQUcsQ0FBQyxDQUFBdVQsUUFBUSxLQUFJLElBQUlDLHVCQUFjLENBQUNELFFBQVEsQ0FBQ3JULFNBQVMsRUFBRXFULFFBQVEsQ0FBQ25ULFNBQVMsQ0FBQyxDQUFDO0VBQ2xIOztFQUVBLE1BQWdCOEQsZUFBZUEsQ0FBQ3hXLE1BQXNCLEVBQUU7O0lBRXREO0lBQ0EsSUFBSUEsTUFBTSxLQUFLTyxTQUFTLEVBQUUsTUFBTSxJQUFJQyxvQkFBVyxDQUFDLDJCQUEyQixDQUFDO0lBQzVFLElBQUlSLE1BQU0sQ0FBQzZNLGVBQWUsQ0FBQyxDQUFDLEtBQUt0TSxTQUFTLEVBQUUsTUFBTSxJQUFJQyxvQkFBVyxDQUFDLDZDQUE2QyxDQUFDO0lBQ2hILElBQUlSLE1BQU0sQ0FBQ3FVLGVBQWUsQ0FBQyxDQUFDLEtBQUs5VCxTQUFTLElBQUlQLE1BQU0sQ0FBQ3FVLGVBQWUsQ0FBQyxDQUFDLENBQUM3SSxNQUFNLElBQUksQ0FBQyxFQUFFLE1BQU0sSUFBSWhMLG9CQUFXLENBQUMsa0RBQWtELENBQUM7SUFDN0osSUFBSVIsTUFBTSxDQUFDcVUsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQ2pNLFVBQVUsQ0FBQyxDQUFDLEtBQUs3SCxTQUFTLEVBQUUsTUFBTSxJQUFJQyxvQkFBVyxDQUFDLDhDQUE4QyxDQUFDO0lBQ2pJLElBQUlSLE1BQU0sQ0FBQ3FVLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUNDLFNBQVMsQ0FBQyxDQUFDLEtBQUsvVCxTQUFTLEVBQUUsTUFBTSxJQUFJQyxvQkFBVyxDQUFDLHVDQUF1QyxDQUFDO0lBQ3pILElBQUlSLE1BQU0sQ0FBQ2dXLFdBQVcsQ0FBQyxDQUFDLEtBQUt6VixTQUFTLEVBQUUsTUFBTSxJQUFJQyxvQkFBVyxDQUFDLDBFQUEwRSxDQUFDO0lBQ3pJLElBQUlSLE1BQU0sQ0FBQ2lVLG9CQUFvQixDQUFDLENBQUMsS0FBSzFULFNBQVMsSUFBSVAsTUFBTSxDQUFDaVUsb0JBQW9CLENBQUMsQ0FBQyxDQUFDekksTUFBTSxLQUFLLENBQUMsRUFBRSxNQUFNLElBQUloTCxvQkFBVyxDQUFDLG9EQUFvRCxDQUFDO0lBQzFLLElBQUlSLE1BQU0sQ0FBQ3VXLHNCQUFzQixDQUFDLENBQUMsRUFBRSxNQUFNLElBQUkvVixvQkFBVyxDQUFDLG1EQUFtRCxDQUFDO0lBQy9HLElBQUlSLE1BQU0sQ0FBQ3lVLGtCQUFrQixDQUFDLENBQUMsS0FBS2xVLFNBQVMsSUFBSVAsTUFBTSxDQUFDeVUsa0JBQWtCLENBQUMsQ0FBQyxDQUFDakosTUFBTSxHQUFHLENBQUMsRUFBRSxNQUFNLElBQUloTCxvQkFBVyxDQUFDLHFFQUFxRSxDQUFDOztJQUVyTDtJQUNBLElBQUlSLE1BQU0sQ0FBQ2lVLG9CQUFvQixDQUFDLENBQUMsS0FBSzFULFNBQVMsRUFBRTtNQUMvQ1AsTUFBTSxDQUFDMlYsb0JBQW9CLENBQUMsRUFBRSxDQUFDO01BQy9CLEtBQUssSUFBSW5OLFVBQVUsSUFBSSxNQUFNLElBQUksQ0FBQ0YsZUFBZSxDQUFDdEksTUFBTSxDQUFDNk0sZUFBZSxDQUFDLENBQUMsQ0FBQyxFQUFFO1FBQzNFN00sTUFBTSxDQUFDaVUsb0JBQW9CLENBQUMsQ0FBQyxDQUFDNUgsSUFBSSxDQUFDN0QsVUFBVSxDQUFDNEQsUUFBUSxDQUFDLENBQUMsQ0FBQztNQUMzRDtJQUNGO0lBQ0EsSUFBSXBNLE1BQU0sQ0FBQ2lVLG9CQUFvQixDQUFDLENBQUMsQ0FBQ3pJLE1BQU0sS0FBSyxDQUFDLEVBQUUsTUFBTSxJQUFJaEwsb0JBQVcsQ0FBQywrQkFBK0IsQ0FBQzs7SUFFdEc7SUFDQSxJQUFJNEMsTUFBVyxHQUFHLENBQUMsQ0FBQztJQUNwQixJQUFJc1QsS0FBSyxHQUFHMVcsTUFBTSxDQUFDK1QsUUFBUSxDQUFDLENBQUMsS0FBSyxJQUFJO0lBQ3RDM1EsTUFBTSxDQUFDOEQsYUFBYSxHQUFHbEgsTUFBTSxDQUFDNk0sZUFBZSxDQUFDLENBQUM7SUFDL0N6SixNQUFNLENBQUN1UixlQUFlLEdBQUczVSxNQUFNLENBQUNpVSxvQkFBb0IsQ0FBQyxDQUFDO0lBQ3REN1EsTUFBTSxDQUFDVyxPQUFPLEdBQUcvRCxNQUFNLENBQUNxVSxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDak0sVUFBVSxDQUFDLENBQUM7SUFDekQsSUFBQTNCLGVBQU0sRUFBQ3pHLE1BQU0sQ0FBQzhVLFdBQVcsQ0FBQyxDQUFDLEtBQUt2VSxTQUFTLElBQUlQLE1BQU0sQ0FBQzhVLFdBQVcsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJOVUsTUFBTSxDQUFDOFUsV0FBVyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDcEcxUixNQUFNLENBQUNzUSxRQUFRLEdBQUcxVCxNQUFNLENBQUM4VSxXQUFXLENBQUMsQ0FBQztJQUN0QzFSLE1BQU0sQ0FBQ2dHLFVBQVUsR0FBR3BKLE1BQU0sQ0FBQzRVLFlBQVksQ0FBQyxDQUFDO0lBQ3pDeFIsTUFBTSxDQUFDeVIsWUFBWSxHQUFHLENBQUM2QixLQUFLO0lBQzVCdFQsTUFBTSxDQUFDMmlCLFlBQVksR0FBRy9sQixNQUFNLENBQUNnbUIsY0FBYyxDQUFDLENBQUM7SUFDN0M1aUIsTUFBTSxDQUFDNlIsV0FBVyxHQUFHLElBQUk7SUFDekI3UixNQUFNLENBQUMyUixVQUFVLEdBQUcsSUFBSTtJQUN4QjNSLE1BQU0sQ0FBQzRSLGVBQWUsR0FBRyxJQUFJOztJQUU3QjtJQUNBLElBQUk1TixJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUNwSCxNQUFNLENBQUNpQixTQUFTLENBQUMsQ0FBQyxDQUFDTyxlQUFlLENBQUMsV0FBVyxFQUFFNEIsTUFBTSxDQUFDO0lBQzdFLElBQUlpRSxNQUFNLEdBQUdELElBQUksQ0FBQ0MsTUFBTTs7SUFFeEI7SUFDQSxJQUFJc1AsS0FBSyxHQUFHL1csZUFBZSxDQUFDZ1csd0JBQXdCLENBQUN2TyxNQUFNLEVBQUU5RyxTQUFTLEVBQUVQLE1BQU0sQ0FBQzs7SUFFL0U7SUFDQSxLQUFLLElBQUk2UCxFQUFFLElBQUk4RyxLQUFLLENBQUN6SSxNQUFNLENBQUMsQ0FBQyxFQUFFO01BQzdCMkIsRUFBRSxDQUFDb1csV0FBVyxDQUFDLElBQUksQ0FBQztNQUNwQnBXLEVBQUUsQ0FBQ3FXLGNBQWMsQ0FBQyxLQUFLLENBQUM7TUFDeEJyVyxFQUFFLENBQUM4SixtQkFBbUIsQ0FBQyxDQUFDLENBQUM7TUFDekI5SixFQUFFLENBQUNzVyxRQUFRLENBQUN6UCxLQUFLLENBQUM7TUFDbEI3RyxFQUFFLENBQUNnSCxXQUFXLENBQUNILEtBQUssQ0FBQztNQUNyQjdHLEVBQUUsQ0FBQytHLFlBQVksQ0FBQ0YsS0FBSyxDQUFDO01BQ3RCN0csRUFBRSxDQUFDdVcsWUFBWSxDQUFDLEtBQUssQ0FBQztNQUN0QnZXLEVBQUUsQ0FBQ3dXLFdBQVcsQ0FBQyxLQUFLLENBQUM7TUFDckIsSUFBSTdXLFFBQVEsR0FBR0ssRUFBRSxDQUFDNkYsbUJBQW1CLENBQUMsQ0FBQztNQUN2Q2xHLFFBQVEsQ0FBQzlHLGVBQWUsQ0FBQzFJLE1BQU0sQ0FBQzZNLGVBQWUsQ0FBQyxDQUFDLENBQUM7TUFDbEQsSUFBSTdNLE1BQU0sQ0FBQ2lVLG9CQUFvQixDQUFDLENBQUMsQ0FBQ3pJLE1BQU0sS0FBSyxDQUFDLEVBQUVnRSxRQUFRLENBQUNtRyxvQkFBb0IsQ0FBQzNWLE1BQU0sQ0FBQ2lVLG9CQUFvQixDQUFDLENBQUMsQ0FBQztNQUM1RyxJQUFJRyxXQUFXLEdBQUcsSUFBSWtTLDBCQUFpQixDQUFDdG1CLE1BQU0sQ0FBQ3FVLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUNqTSxVQUFVLENBQUMsQ0FBQyxFQUFFeEIsTUFBTSxDQUFDNEksUUFBUSxDQUFDOEUsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQy9HOUUsUUFBUSxDQUFDK1csZUFBZSxDQUFDLENBQUNuUyxXQUFXLENBQUMsQ0FBQztNQUN2Q3ZFLEVBQUUsQ0FBQzJXLG1CQUFtQixDQUFDaFgsUUFBUSxDQUFDO01BQ2hDSyxFQUFFLENBQUNuRyxZQUFZLENBQUMxSixNQUFNLENBQUM0VSxZQUFZLENBQUMsQ0FBQyxDQUFDO01BQ3RDLElBQUkvRSxFQUFFLENBQUM0VyxhQUFhLENBQUMsQ0FBQyxLQUFLbG1CLFNBQVMsRUFBRXNQLEVBQUUsQ0FBQzZXLGFBQWEsQ0FBQyxFQUFFLENBQUM7TUFDMUQsSUFBSTdXLEVBQUUsQ0FBQ2tFLFFBQVEsQ0FBQyxDQUFDLEVBQUU7UUFDakIsSUFBSWxFLEVBQUUsQ0FBQzhXLHVCQUF1QixDQUFDLENBQUMsS0FBS3BtQixTQUFTLEVBQUVzUCxFQUFFLENBQUMrVyx1QkFBdUIsQ0FBQyxDQUFDLElBQUlDLElBQUksQ0FBQyxDQUFDLENBQUNDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFFO1FBQ3BHLElBQUlqWCxFQUFFLENBQUNrWCxvQkFBb0IsQ0FBQyxDQUFDLEtBQUt4bUIsU0FBUyxFQUFFc1AsRUFBRSxDQUFDbVgsb0JBQW9CLENBQUMsS0FBSyxDQUFDO01BQzdFO0lBQ0Y7SUFDQSxPQUFPclEsS0FBSyxDQUFDekksTUFBTSxDQUFDLENBQUM7RUFDdkI7O0VBRVV6RyxnQkFBZ0JBLENBQUEsRUFBRztJQUMzQixJQUFJLElBQUksQ0FBQ3lELFlBQVksSUFBSTNLLFNBQVMsSUFBSSxJQUFJLENBQUMwbUIsU0FBUyxDQUFDemIsTUFBTSxFQUFFLElBQUksQ0FBQ04sWUFBWSxHQUFHLElBQUlnYyxZQUFZLENBQUMsSUFBSSxDQUFDO0lBQ3ZHLElBQUksSUFBSSxDQUFDaGMsWUFBWSxLQUFLM0ssU0FBUyxFQUFFLElBQUksQ0FBQzJLLFlBQVksQ0FBQ2ljLFlBQVksQ0FBQyxJQUFJLENBQUNGLFNBQVMsQ0FBQ3piLE1BQU0sR0FBRyxDQUFDLENBQUM7RUFDaEc7O0VBRUE7QUFDRjtBQUNBO0VBQ0UsTUFBZ0JoQixJQUFJQSxDQUFBLEVBQUc7SUFDckIsSUFBSSxJQUFJLENBQUNVLFlBQVksS0FBSzNLLFNBQVMsSUFBSSxJQUFJLENBQUMySyxZQUFZLENBQUNrYyxTQUFTLEVBQUUsTUFBTSxJQUFJLENBQUNsYyxZQUFZLENBQUNWLElBQUksQ0FBQyxDQUFDO0VBQ3BHOztFQUVBOztFQUVBLE9BQWlCbVcsZUFBZUEsQ0FBQ0QsV0FBMkYsRUFBRXRiLFFBQWlCLEVBQUVoRSxRQUFpQixFQUFzQjtJQUN0TCxJQUFJcEIsTUFBK0MsR0FBR08sU0FBUztJQUMvRCxJQUFJLE9BQU9tZ0IsV0FBVyxLQUFLLFFBQVEsSUFBS0EsV0FBVyxDQUFrQ2xFLEdBQUcsRUFBRXhjLE1BQU0sR0FBRyxJQUFJcUIsMkJBQWtCLENBQUMsRUFBQ2dtQixNQUFNLEVBQUUsSUFBSXBpQiw0QkFBbUIsQ0FBQ3liLFdBQVcsRUFBMkN0YixRQUFRLEVBQUVoRSxRQUFRLENBQUMsRUFBQyxDQUFDLENBQUM7SUFDbE8sSUFBSVYsaUJBQVEsQ0FBQ3dXLE9BQU8sQ0FBQ3dKLFdBQVcsQ0FBQyxFQUFFMWdCLE1BQU0sR0FBRyxJQUFJcUIsMkJBQWtCLENBQUMsRUFBQ3VmLEdBQUcsRUFBRUYsV0FBdUIsRUFBQyxDQUFDLENBQUM7SUFDbkcxZ0IsTUFBTSxHQUFHLElBQUlxQiwyQkFBa0IsQ0FBQ3FmLFdBQTBDLENBQUM7SUFDaEYsSUFBSTFnQixNQUFNLENBQUNzbkIsYUFBYSxLQUFLL21CLFNBQVMsRUFBRVAsTUFBTSxDQUFDc25CLGFBQWEsR0FBRyxJQUFJO0lBQ25FLE9BQU90bkIsTUFBTTtFQUNmOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsT0FBaUJtUCxlQUFlQSxDQUFDaEIsS0FBSyxFQUFFO0lBQ3RDQSxLQUFLLENBQUNpWCxhQUFhLENBQUM3a0IsU0FBUyxDQUFDO0lBQzlCNE4sS0FBSyxDQUFDa1gsYUFBYSxDQUFDOWtCLFNBQVMsQ0FBQztJQUM5QjROLEtBQUssQ0FBQ1MsZ0JBQWdCLENBQUNyTyxTQUFTLENBQUM7SUFDakM0TixLQUFLLENBQUNVLGFBQWEsQ0FBQ3RPLFNBQVMsQ0FBQztJQUM5QjROLEtBQUssQ0FBQ1csY0FBYyxDQUFDdk8sU0FBUyxDQUFDO0lBQy9CLE9BQU80TixLQUFLO0VBQ2Q7O0VBRUEsT0FBaUJrRCxZQUFZQSxDQUFDbEQsS0FBSyxFQUFFO0lBQ25DLElBQUksQ0FBQ0EsS0FBSyxFQUFFLE9BQU8sS0FBSztJQUN4QixJQUFJLENBQUNBLEtBQUssQ0FBQ21ELFVBQVUsQ0FBQyxDQUFDLEVBQUUsT0FBTyxLQUFLO0lBQ3JDLElBQUluRCxLQUFLLENBQUNtRCxVQUFVLENBQUMsQ0FBQyxDQUFDc1MsYUFBYSxDQUFDLENBQUMsS0FBS3JqQixTQUFTLEVBQUUsT0FBTyxJQUFJLENBQUMsQ0FBQztJQUNuRSxJQUFJNE4sS0FBSyxDQUFDbUQsVUFBVSxDQUFDLENBQUMsQ0FBQ3VTLGFBQWEsQ0FBQyxDQUFDLEtBQUt0akIsU0FBUyxFQUFFLE9BQU8sSUFBSTtJQUNqRSxJQUFJNE4sS0FBSyxZQUFZYyw0QkFBbUIsRUFBRTtNQUN4QyxJQUFJZCxLQUFLLENBQUNtRCxVQUFVLENBQUMsQ0FBQyxDQUFDM0MsY0FBYyxDQUFDLENBQUMsS0FBS3BPLFNBQVMsRUFBRSxPQUFPLElBQUksQ0FBQyxDQUFDO0lBQ3RFLENBQUMsTUFBTSxJQUFJNE4sS0FBSyxZQUFZOEIsMEJBQWlCLEVBQUU7TUFDN0MsSUFBSTlCLEtBQUssQ0FBQ21ELFVBQVUsQ0FBQyxDQUFDLENBQUMvQyxnQkFBZ0IsQ0FBQyxDQUFDLEtBQUtoTyxTQUFTLEVBQUUsT0FBTyxJQUFJLENBQUMsQ0FBQztJQUN4RSxDQUFDLE1BQU07TUFDTCxNQUFNLElBQUlDLG9CQUFXLENBQUMsb0NBQW9DLENBQUM7SUFDN0Q7SUFDQSxPQUFPLEtBQUs7RUFDZDs7RUFFQSxPQUFpQjBMLGlCQUFpQkEsQ0FBQ0YsVUFBVSxFQUFFO0lBQzdDLElBQUlsRixPQUFPLEdBQUcsSUFBSXNHLHNCQUFhLENBQUMsQ0FBQztJQUNqQyxLQUFLLElBQUk5TixHQUFHLElBQUlILE1BQU0sQ0FBQ2tYLElBQUksQ0FBQ3JLLFVBQVUsQ0FBQyxFQUFFO01BQ3ZDLElBQUlnUixHQUFHLEdBQUdoUixVQUFVLENBQUMxTSxHQUFHLENBQUM7TUFDekIsSUFBSUEsR0FBRyxLQUFLLGVBQWUsRUFBRXdILE9BQU8sQ0FBQytCLFFBQVEsQ0FBQ21VLEdBQUcsQ0FBQyxDQUFDO01BQzlDLElBQUkxZCxHQUFHLEtBQUssU0FBUyxFQUFFd0gsT0FBTyxDQUFDd0YsVUFBVSxDQUFDMUYsTUFBTSxDQUFDb1csR0FBRyxDQUFDLENBQUMsQ0FBQztNQUN2RCxJQUFJMWQsR0FBRyxLQUFLLGtCQUFrQixFQUFFd0gsT0FBTyxDQUFDeUYsa0JBQWtCLENBQUMzRixNQUFNLENBQUNvVyxHQUFHLENBQUMsQ0FBQyxDQUFDO01BQ3hFLElBQUkxZCxHQUFHLEtBQUssY0FBYyxFQUFFd0gsT0FBTyxDQUFDeWdCLGlCQUFpQixDQUFDdkssR0FBRyxDQUFDLENBQUM7TUFDM0QsSUFBSTFkLEdBQUcsS0FBSyxLQUFLLEVBQUV3SCxPQUFPLENBQUMwZ0IsTUFBTSxDQUFDeEssR0FBRyxDQUFDLENBQUM7TUFDdkMsSUFBSTFkLEdBQUcsS0FBSyxPQUFPLEVBQUUsQ0FBRSxDQUFDLENBQUM7TUFBQSxLQUN6QnFSLE9BQU8sQ0FBQ21SLEdBQUcsQ0FBQyw4Q0FBOEMsR0FBR3hpQixHQUFHLEdBQUcsSUFBSSxHQUFHMGQsR0FBRyxDQUFDO0lBQ3JGO0lBQ0EsSUFBSSxFQUFFLEtBQUtsVyxPQUFPLENBQUMyZ0IsTUFBTSxDQUFDLENBQUMsRUFBRTNnQixPQUFPLENBQUMwZ0IsTUFBTSxDQUFDam5CLFNBQVMsQ0FBQztJQUN0RCxPQUFPdUcsT0FBTztFQUNoQjs7RUFFQSxPQUFpQjhGLG9CQUFvQkEsQ0FBQ0QsYUFBYSxFQUFFO0lBQ25ELElBQUluRSxVQUFVLEdBQUcsSUFBSUMseUJBQWdCLENBQUMsQ0FBQztJQUN2QyxLQUFLLElBQUluSixHQUFHLElBQUlILE1BQU0sQ0FBQ2tYLElBQUksQ0FBQzFKLGFBQWEsQ0FBQyxFQUFFO01BQzFDLElBQUlxUSxHQUFHLEdBQUdyUSxhQUFhLENBQUNyTixHQUFHLENBQUM7TUFDNUIsSUFBSUEsR0FBRyxLQUFLLGVBQWUsRUFBRWtKLFVBQVUsQ0FBQ0UsZUFBZSxDQUFDc1UsR0FBRyxDQUFDLENBQUM7TUFDeEQsSUFBSTFkLEdBQUcsS0FBSyxlQUFlLEVBQUVrSixVQUFVLENBQUNLLFFBQVEsQ0FBQ21VLEdBQUcsQ0FBQyxDQUFDO01BQ3RELElBQUkxZCxHQUFHLEtBQUssU0FBUyxFQUFFa0osVUFBVSxDQUFDc0YsVUFBVSxDQUFDa1AsR0FBRyxDQUFDLENBQUM7TUFDbEQsSUFBSTFkLEdBQUcsS0FBSyxTQUFTLEVBQUVrSixVQUFVLENBQUM4RCxVQUFVLENBQUMxRixNQUFNLENBQUNvVyxHQUFHLENBQUMsQ0FBQyxDQUFDO01BQzFELElBQUkxZCxHQUFHLEtBQUssa0JBQWtCLEVBQUVrSixVQUFVLENBQUMrRCxrQkFBa0IsQ0FBQzNGLE1BQU0sQ0FBQ29XLEdBQUcsQ0FBQyxDQUFDLENBQUM7TUFDM0UsSUFBSTFkLEdBQUcsS0FBSyxxQkFBcUIsRUFBRWtKLFVBQVUsQ0FBQ2dFLG9CQUFvQixDQUFDd1EsR0FBRyxDQUFDLENBQUM7TUFDeEUsSUFBSTFkLEdBQUcsS0FBSyxPQUFPLEVBQUUsQ0FBRSxJQUFJMGQsR0FBRyxFQUFFeFUsVUFBVSxDQUFDdUYsUUFBUSxDQUFDaVAsR0FBRyxDQUFDLENBQUUsQ0FBQztNQUMzRCxJQUFJMWQsR0FBRyxLQUFLLE1BQU0sRUFBRWtKLFVBQVUsQ0FBQ3dGLFNBQVMsQ0FBQ2dQLEdBQUcsQ0FBQyxDQUFDO01BQzlDLElBQUkxZCxHQUFHLEtBQUssa0JBQWtCLEVBQUVrSixVQUFVLENBQUNpRSxvQkFBb0IsQ0FBQ3VRLEdBQUcsQ0FBQyxDQUFDO01BQ3JFLElBQUkxZCxHQUFHLElBQUksZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDLENBQUU7TUFBQSxLQUNqQ3FSLE9BQU8sQ0FBQ21SLEdBQUcsQ0FBQyxpREFBaUQsR0FBR3hpQixHQUFHLEdBQUcsSUFBSSxHQUFHMGQsR0FBRyxDQUFDO0lBQ3hGO0lBQ0EsT0FBT3hVLFVBQVU7RUFDbkI7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDRSxPQUFpQmlOLGdCQUFnQkEsQ0FBQ3pWLE1BQStCLEVBQUU2UCxFQUFFLEVBQUV5RixnQkFBZ0IsRUFBRTtJQUN2RixJQUFJLENBQUN6RixFQUFFLEVBQUVBLEVBQUUsR0FBRyxJQUFJMkYsdUJBQWMsQ0FBQyxDQUFDO0lBQ2xDLElBQUlrQixLQUFLLEdBQUcxVyxNQUFNLENBQUMrVCxRQUFRLENBQUMsQ0FBQyxLQUFLLElBQUk7SUFDdENsRSxFQUFFLENBQUN3VixhQUFhLENBQUMsSUFBSSxDQUFDO0lBQ3RCeFYsRUFBRSxDQUFDcVcsY0FBYyxDQUFDLEtBQUssQ0FBQztJQUN4QnJXLEVBQUUsQ0FBQzhKLG1CQUFtQixDQUFDLENBQUMsQ0FBQztJQUN6QjlKLEVBQUUsQ0FBQ2dILFdBQVcsQ0FBQ0gsS0FBSyxDQUFDO0lBQ3JCN0csRUFBRSxDQUFDc1csUUFBUSxDQUFDelAsS0FBSyxDQUFDO0lBQ2xCN0csRUFBRSxDQUFDK0csWUFBWSxDQUFDRixLQUFLLENBQUM7SUFDdEI3RyxFQUFFLENBQUN1VyxZQUFZLENBQUMsS0FBSyxDQUFDO0lBQ3RCdlcsRUFBRSxDQUFDd1csV0FBVyxDQUFDLEtBQUssQ0FBQztJQUNyQnhXLEVBQUUsQ0FBQ29XLFdBQVcsQ0FBQyxJQUFJLENBQUM7SUFDcEJwVyxFQUFFLENBQUM2WCxXQUFXLENBQUNDLG9CQUFXLENBQUNDLFNBQVMsQ0FBQztJQUNyQyxJQUFJcFksUUFBUSxHQUFHLElBQUlxWSwrQkFBc0IsQ0FBQyxDQUFDO0lBQzNDclksUUFBUSxDQUFDc1ksS0FBSyxDQUFDalksRUFBRSxDQUFDO0lBQ2xCLElBQUk3UCxNQUFNLENBQUNpVSxvQkFBb0IsQ0FBQyxDQUFDLElBQUlqVSxNQUFNLENBQUNpVSxvQkFBb0IsQ0FBQyxDQUFDLENBQUN6SSxNQUFNLEtBQUssQ0FBQyxFQUFFZ0UsUUFBUSxDQUFDbUcsb0JBQW9CLENBQUMzVixNQUFNLENBQUNpVSxvQkFBb0IsQ0FBQyxDQUFDLENBQUNDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDeEosSUFBSW9CLGdCQUFnQixFQUFFO01BQ3BCLElBQUl5UyxVQUFVLEdBQUcsRUFBRTtNQUNuQixLQUFLLElBQUlDLElBQUksSUFBSWhvQixNQUFNLENBQUNxVSxlQUFlLENBQUMsQ0FBQyxFQUFFMFQsVUFBVSxDQUFDMWIsSUFBSSxDQUFDMmIsSUFBSSxDQUFDNVksSUFBSSxDQUFDLENBQUMsQ0FBQztNQUN2RUksUUFBUSxDQUFDK1csZUFBZSxDQUFDd0IsVUFBVSxDQUFDO0lBQ3RDO0lBQ0FsWSxFQUFFLENBQUMyVyxtQkFBbUIsQ0FBQ2hYLFFBQVEsQ0FBQztJQUNoQ0ssRUFBRSxDQUFDbkcsWUFBWSxDQUFDMUosTUFBTSxDQUFDNFUsWUFBWSxDQUFDLENBQUMsQ0FBQztJQUN0QyxJQUFJL0UsRUFBRSxDQUFDNFcsYUFBYSxDQUFDLENBQUMsS0FBS2xtQixTQUFTLEVBQUVzUCxFQUFFLENBQUM2VyxhQUFhLENBQUMsRUFBRSxDQUFDO0lBQzFELElBQUkxbUIsTUFBTSxDQUFDK1QsUUFBUSxDQUFDLENBQUMsRUFBRTtNQUNyQixJQUFJbEUsRUFBRSxDQUFDOFcsdUJBQXVCLENBQUMsQ0FBQyxLQUFLcG1CLFNBQVMsRUFBRXNQLEVBQUUsQ0FBQytXLHVCQUF1QixDQUFDLENBQUMsSUFBSUMsSUFBSSxDQUFDLENBQUMsQ0FBQ0MsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUU7TUFDcEcsSUFBSWpYLEVBQUUsQ0FBQ2tYLG9CQUFvQixDQUFDLENBQUMsS0FBS3htQixTQUFTLEVBQUVzUCxFQUFFLENBQUNtWCxvQkFBb0IsQ0FBQyxLQUFLLENBQUM7SUFDN0U7SUFDQSxPQUFPblgsRUFBRTtFQUNYOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsT0FBaUJvWSxlQUFlQSxDQUFDQyxNQUFNLEVBQUU7SUFDdkMsSUFBSXZSLEtBQUssR0FBRyxJQUFJd1Isb0JBQVcsQ0FBQyxDQUFDO0lBQzdCeFIsS0FBSyxDQUFDeVIsZ0JBQWdCLENBQUNGLE1BQU0sQ0FBQ3ZRLGNBQWMsQ0FBQztJQUM3Q2hCLEtBQUssQ0FBQzBSLGdCQUFnQixDQUFDSCxNQUFNLENBQUN6USxjQUFjLENBQUM7SUFDN0NkLEtBQUssQ0FBQzJSLGNBQWMsQ0FBQ0osTUFBTSxDQUFDSyxZQUFZLENBQUM7SUFDekMsSUFBSTVSLEtBQUssQ0FBQ2lCLGdCQUFnQixDQUFDLENBQUMsS0FBS3JYLFNBQVMsSUFBSW9XLEtBQUssQ0FBQ2lCLGdCQUFnQixDQUFDLENBQUMsQ0FBQ3BNLE1BQU0sS0FBSyxDQUFDLEVBQUVtTCxLQUFLLENBQUN5UixnQkFBZ0IsQ0FBQzduQixTQUFTLENBQUM7SUFDdEgsSUFBSW9XLEtBQUssQ0FBQ2UsZ0JBQWdCLENBQUMsQ0FBQyxLQUFLblgsU0FBUyxJQUFJb1csS0FBSyxDQUFDZSxnQkFBZ0IsQ0FBQyxDQUFDLENBQUNsTSxNQUFNLEtBQUssQ0FBQyxFQUFFbUwsS0FBSyxDQUFDMFIsZ0JBQWdCLENBQUM5bkIsU0FBUyxDQUFDO0lBQ3RILElBQUlvVyxLQUFLLENBQUM2UixjQUFjLENBQUMsQ0FBQyxLQUFLam9CLFNBQVMsSUFBSW9XLEtBQUssQ0FBQzZSLGNBQWMsQ0FBQyxDQUFDLENBQUNoZCxNQUFNLEtBQUssQ0FBQyxFQUFFbUwsS0FBSyxDQUFDMlIsY0FBYyxDQUFDL25CLFNBQVMsQ0FBQztJQUNoSCxPQUFPb1csS0FBSztFQUNkOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDRSxPQUFpQmYsd0JBQXdCQSxDQUFDNlMsTUFBVyxFQUFFcFosR0FBUyxFQUFFclAsTUFBWSxFQUFFOztJQUU5RTtJQUNBLElBQUkyVyxLQUFLLEdBQUcvVyxlQUFlLENBQUNxb0IsZUFBZSxDQUFDUSxNQUFNLENBQUM7O0lBRW5EO0lBQ0EsSUFBSXRULE1BQU0sR0FBR3NULE1BQU0sQ0FBQ3JULFFBQVEsR0FBR3FULE1BQU0sQ0FBQ3JULFFBQVEsQ0FBQzVKLE1BQU0sR0FBR2lkLE1BQU0sQ0FBQ3JRLFlBQVksR0FBR3FRLE1BQU0sQ0FBQ3JRLFlBQVksQ0FBQzVNLE1BQU0sR0FBRyxDQUFDOztJQUU1RztJQUNBLElBQUkySixNQUFNLEtBQUssQ0FBQyxFQUFFO01BQ2hCMU8sZUFBTSxDQUFDQyxLQUFLLENBQUMySSxHQUFHLEVBQUU5TyxTQUFTLENBQUM7TUFDNUIsT0FBT29XLEtBQUs7SUFDZDs7SUFFQTtJQUNBLElBQUl0SCxHQUFHLEVBQUVzSCxLQUFLLENBQUMrUixNQUFNLENBQUNyWixHQUFHLENBQUMsQ0FBQztJQUN0QjtNQUNIQSxHQUFHLEdBQUcsRUFBRTtNQUNSLEtBQUssSUFBSWtHLENBQUMsR0FBRyxDQUFDLEVBQUVBLENBQUMsR0FBR0osTUFBTSxFQUFFSSxDQUFDLEVBQUUsRUFBRWxHLEdBQUcsQ0FBQ2hELElBQUksQ0FBQyxJQUFJbUosdUJBQWMsQ0FBQyxDQUFDLENBQUM7SUFDakU7SUFDQSxLQUFLLElBQUkzRixFQUFFLElBQUlSLEdBQUcsRUFBRTtNQUNsQlEsRUFBRSxDQUFDOFksUUFBUSxDQUFDaFMsS0FBSyxDQUFDO01BQ2xCOUcsRUFBRSxDQUFDd1YsYUFBYSxDQUFDLElBQUksQ0FBQztJQUN4QjtJQUNBMU8sS0FBSyxDQUFDK1IsTUFBTSxDQUFDclosR0FBRyxDQUFDOztJQUVqQjtJQUNBLEtBQUssSUFBSS9QLEdBQUcsSUFBSUgsTUFBTSxDQUFDa1gsSUFBSSxDQUFDb1MsTUFBTSxDQUFDLEVBQUU7TUFDbkMsSUFBSXpMLEdBQUcsR0FBR3lMLE1BQU0sQ0FBQ25wQixHQUFHLENBQUM7TUFDckIsSUFBSUEsR0FBRyxLQUFLLGNBQWMsRUFBRSxLQUFLLElBQUlpVyxDQUFDLEdBQUcsQ0FBQyxFQUFFQSxDQUFDLEdBQUd5SCxHQUFHLENBQUN4UixNQUFNLEVBQUUrSixDQUFDLEVBQUUsRUFBRWxHLEdBQUcsQ0FBQ2tHLENBQUMsQ0FBQyxDQUFDcVQsT0FBTyxDQUFDNUwsR0FBRyxDQUFDekgsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUNuRixJQUFJalcsR0FBRyxLQUFLLGFBQWEsRUFBRSxLQUFLLElBQUlpVyxDQUFDLEdBQUcsQ0FBQyxFQUFFQSxDQUFDLEdBQUd5SCxHQUFHLENBQUN4UixNQUFNLEVBQUUrSixDQUFDLEVBQUUsRUFBRWxHLEdBQUcsQ0FBQ2tHLENBQUMsQ0FBQyxDQUFDc1QsTUFBTSxDQUFDN0wsR0FBRyxDQUFDekgsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUN0RixJQUFJalcsR0FBRyxLQUFLLGNBQWMsRUFBRSxLQUFLLElBQUlpVyxDQUFDLEdBQUcsQ0FBQyxFQUFFQSxDQUFDLEdBQUd5SCxHQUFHLENBQUN4UixNQUFNLEVBQUUrSixDQUFDLEVBQUUsRUFBRWxHLEdBQUcsQ0FBQ2tHLENBQUMsQ0FBQyxDQUFDdVQsVUFBVSxDQUFDOUwsR0FBRyxDQUFDekgsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUMzRixJQUFJalcsR0FBRyxLQUFLLGtCQUFrQixFQUFFLEtBQUssSUFBSWlXLENBQUMsR0FBRyxDQUFDLEVBQUVBLENBQUMsR0FBR3lILEdBQUcsQ0FBQ3hSLE1BQU0sRUFBRStKLENBQUMsRUFBRSxFQUFFbEcsR0FBRyxDQUFDa0csQ0FBQyxDQUFDLENBQUN3VCxXQUFXLENBQUMvTCxHQUFHLENBQUN6SCxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQ2hHLElBQUlqVyxHQUFHLEtBQUssVUFBVSxFQUFFLEtBQUssSUFBSWlXLENBQUMsR0FBRyxDQUFDLEVBQUVBLENBQUMsR0FBR3lILEdBQUcsQ0FBQ3hSLE1BQU0sRUFBRStKLENBQUMsRUFBRSxFQUFFbEcsR0FBRyxDQUFDa0csQ0FBQyxDQUFDLENBQUN5VCxNQUFNLENBQUNwaUIsTUFBTSxDQUFDb1csR0FBRyxDQUFDekgsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQzNGLElBQUlqVyxHQUFHLEtBQUssYUFBYSxFQUFFLEtBQUssSUFBSWlXLENBQUMsR0FBRyxDQUFDLEVBQUVBLENBQUMsR0FBR3lILEdBQUcsQ0FBQ3hSLE1BQU0sRUFBRStKLENBQUMsRUFBRSxFQUFFbEcsR0FBRyxDQUFDa0csQ0FBQyxDQUFDLENBQUMwVCxTQUFTLENBQUNqTSxHQUFHLENBQUN6SCxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQ3pGLElBQUlqVyxHQUFHLEtBQUssYUFBYSxFQUFFO1FBQzlCLEtBQUssSUFBSWlXLENBQUMsR0FBRyxDQUFDLEVBQUVBLENBQUMsR0FBR3lILEdBQUcsQ0FBQ3hSLE1BQU0sRUFBRStKLENBQUMsRUFBRSxFQUFFO1VBQ25DLElBQUlsRyxHQUFHLENBQUNrRyxDQUFDLENBQUMsQ0FBQ0csbUJBQW1CLENBQUMsQ0FBQyxJQUFJblYsU0FBUyxFQUFFOE8sR0FBRyxDQUFDa0csQ0FBQyxDQUFDLENBQUNpUixtQkFBbUIsQ0FBQyxJQUFJcUIsK0JBQXNCLENBQUMsQ0FBQyxDQUFDQyxLQUFLLENBQUN6WSxHQUFHLENBQUNrRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1VBQ3JIbEcsR0FBRyxDQUFDa0csQ0FBQyxDQUFDLENBQUNHLG1CQUFtQixDQUFDLENBQUMsQ0FBQ08sU0FBUyxDQUFDclAsTUFBTSxDQUFDb1csR0FBRyxDQUFDekgsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN4RDtNQUNGLENBQUM7TUFDSSxJQUFJalcsR0FBRyxLQUFLLGdCQUFnQixJQUFJQSxHQUFHLEtBQUssZ0JBQWdCLElBQUlBLEdBQUcsS0FBSyxjQUFjLEVBQUUsQ0FBQyxDQUFDLENBQUM7TUFBQSxLQUN2RixJQUFJQSxHQUFHLEtBQUssdUJBQXVCLEVBQUU7UUFDeEMsSUFBSTRwQixrQkFBa0IsR0FBR2xNLEdBQUc7UUFDNUIsS0FBSyxJQUFJekgsQ0FBQyxHQUFHLENBQUMsRUFBRUEsQ0FBQyxHQUFHMlQsa0JBQWtCLENBQUMxZCxNQUFNLEVBQUUrSixDQUFDLEVBQUUsRUFBRTtVQUNsRDdVLGlCQUFRLENBQUN5b0IsVUFBVSxDQUFDOVosR0FBRyxDQUFDa0csQ0FBQyxDQUFDLENBQUM2VCxTQUFTLENBQUMsQ0FBQyxLQUFLN29CLFNBQVMsQ0FBQztVQUNyRDhPLEdBQUcsQ0FBQ2tHLENBQUMsQ0FBQyxDQUFDOFQsU0FBUyxDQUFDLEVBQUUsQ0FBQztVQUNwQixLQUFLLElBQUlDLGFBQWEsSUFBSUosa0JBQWtCLENBQUMzVCxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsRUFBRTtZQUM3RGxHLEdBQUcsQ0FBQ2tHLENBQUMsQ0FBQyxDQUFDNlQsU0FBUyxDQUFDLENBQUMsQ0FBQy9jLElBQUksQ0FBQyxJQUFJa2QsMkJBQWtCLENBQUMsQ0FBQyxDQUFDQyxXQUFXLENBQUMsSUFBSTFELHVCQUFjLENBQUMsQ0FBQyxDQUFDMkQsTUFBTSxDQUFDSCxhQUFhLENBQUMsQ0FBQyxDQUFDeEIsS0FBSyxDQUFDelksR0FBRyxDQUFDa0csQ0FBQyxDQUFDLENBQUMsQ0FBQztVQUN6SDtRQUNGO01BQ0YsQ0FBQztNQUNJLElBQUlqVyxHQUFHLEtBQUssc0JBQXNCLEVBQUU7UUFDdkMsSUFBSW9xQixpQkFBaUIsR0FBRzFNLEdBQUc7UUFDM0IsSUFBSTJNLGNBQWMsR0FBRyxDQUFDO1FBQ3RCLEtBQUssSUFBSUMsS0FBSyxHQUFHLENBQUMsRUFBRUEsS0FBSyxHQUFHRixpQkFBaUIsQ0FBQ2xlLE1BQU0sRUFBRW9lLEtBQUssRUFBRSxFQUFFO1VBQzdELElBQUlDLGFBQWEsR0FBR0gsaUJBQWlCLENBQUNFLEtBQUssQ0FBQyxDQUFDLFNBQVMsQ0FBQztVQUN2RCxJQUFJdmEsR0FBRyxDQUFDdWEsS0FBSyxDQUFDLENBQUNsVSxtQkFBbUIsQ0FBQyxDQUFDLEtBQUtuVixTQUFTLEVBQUU4TyxHQUFHLENBQUN1YSxLQUFLLENBQUMsQ0FBQ3BELG1CQUFtQixDQUFDLElBQUlxQiwrQkFBc0IsQ0FBQyxDQUFDLENBQUNDLEtBQUssQ0FBQ3pZLEdBQUcsQ0FBQ3VhLEtBQUssQ0FBQyxDQUFDLENBQUM7VUFDbEl2YSxHQUFHLENBQUN1YSxLQUFLLENBQUMsQ0FBQ2xVLG1CQUFtQixDQUFDLENBQUMsQ0FBQzZRLGVBQWUsQ0FBQyxFQUFFLENBQUM7VUFDcEQsS0FBSyxJQUFJaFMsTUFBTSxJQUFJc1YsYUFBYSxFQUFFO1lBQ2hDLElBQUk3cEIsTUFBTSxDQUFDcVUsZUFBZSxDQUFDLENBQUMsQ0FBQzdJLE1BQU0sS0FBSyxDQUFDLEVBQUU2RCxHQUFHLENBQUN1YSxLQUFLLENBQUMsQ0FBQ2xVLG1CQUFtQixDQUFDLENBQUMsQ0FBQ3JCLGVBQWUsQ0FBQyxDQUFDLENBQUNoSSxJQUFJLENBQUMsSUFBSWlhLDBCQUFpQixDQUFDdG1CLE1BQU0sQ0FBQ3FVLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUNqTSxVQUFVLENBQUMsQ0FBQyxFQUFFeEIsTUFBTSxDQUFDMk4sTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFBQSxLQUNoTGxGLEdBQUcsQ0FBQ3VhLEtBQUssQ0FBQyxDQUFDbFUsbUJBQW1CLENBQUMsQ0FBQyxDQUFDckIsZUFBZSxDQUFDLENBQUMsQ0FBQ2hJLElBQUksQ0FBQyxJQUFJaWEsMEJBQWlCLENBQUN0bUIsTUFBTSxDQUFDcVUsZUFBZSxDQUFDLENBQUMsQ0FBQ3NWLGNBQWMsRUFBRSxDQUFDLENBQUN2aEIsVUFBVSxDQUFDLENBQUMsRUFBRXhCLE1BQU0sQ0FBQzJOLE1BQU0sQ0FBQyxDQUFDLENBQUM7VUFDOUo7UUFDRjtNQUNGLENBQUM7TUFDSTVELE9BQU8sQ0FBQ21SLEdBQUcsQ0FBQyxrREFBa0QsR0FBR3hpQixHQUFHLEdBQUcsSUFBSSxHQUFHMGQsR0FBRyxDQUFDO0lBQ3pGOztJQUVBLE9BQU9yRyxLQUFLO0VBQ2Q7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsT0FBaUJkLG1CQUFtQkEsQ0FBQytPLEtBQUssRUFBRS9VLEVBQUUsRUFBRWlhLFVBQVUsRUFBRTlwQixNQUFNLEVBQUU7SUFDbEUsSUFBSTJXLEtBQUssR0FBRy9XLGVBQWUsQ0FBQ3FvQixlQUFlLENBQUNyRCxLQUFLLENBQUM7SUFDbERqTyxLQUFLLENBQUMrUixNQUFNLENBQUMsQ0FBQzlvQixlQUFlLENBQUNpbEIsd0JBQXdCLENBQUNELEtBQUssRUFBRS9VLEVBQUUsRUFBRWlhLFVBQVUsRUFBRTlwQixNQUFNLENBQUMsQ0FBQzJvQixRQUFRLENBQUNoUyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ3ZHLE9BQU9BLEtBQUs7RUFDZDs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDRSxPQUFpQmtPLHdCQUF3QkEsQ0FBQ0QsS0FBVSxFQUFFL1UsRUFBUSxFQUFFaWEsVUFBZ0IsRUFBRTlwQixNQUFZLEVBQUUsQ0FBRzs7SUFFakc7SUFDQSxJQUFJLENBQUM2UCxFQUFFLEVBQUVBLEVBQUUsR0FBRyxJQUFJMkYsdUJBQWMsQ0FBQyxDQUFDOztJQUVsQztJQUNBLElBQUlvUCxLQUFLLENBQUNtRixJQUFJLEtBQUt4cEIsU0FBUyxFQUFFdXBCLFVBQVUsR0FBR2xxQixlQUFlLENBQUNvcUIsYUFBYSxDQUFDcEYsS0FBSyxDQUFDbUYsSUFBSSxFQUFFbGEsRUFBRSxDQUFDLENBQUM7SUFDcEZwSixlQUFNLENBQUNDLEtBQUssQ0FBQyxPQUFPb2pCLFVBQVUsRUFBRSxTQUFTLEVBQUUsMkVBQTJFLENBQUM7O0lBRTVIO0lBQ0E7SUFDQSxJQUFJRyxNQUFNO0lBQ1YsSUFBSXphLFFBQVE7SUFDWixLQUFLLElBQUlsUSxHQUFHLElBQUlILE1BQU0sQ0FBQ2tYLElBQUksQ0FBQ3VPLEtBQUssQ0FBQyxFQUFFO01BQ2xDLElBQUk1SCxHQUFHLEdBQUc0SCxLQUFLLENBQUN0bEIsR0FBRyxDQUFDO01BQ3BCLElBQUlBLEdBQUcsS0FBSyxNQUFNLEVBQUV1USxFQUFFLENBQUMrWSxPQUFPLENBQUM1TCxHQUFHLENBQUMsQ0FBQztNQUMvQixJQUFJMWQsR0FBRyxLQUFLLFNBQVMsRUFBRXVRLEVBQUUsQ0FBQytZLE9BQU8sQ0FBQzVMLEdBQUcsQ0FBQyxDQUFDO01BQ3ZDLElBQUkxZCxHQUFHLEtBQUssS0FBSyxFQUFFdVEsRUFBRSxDQUFDbVosTUFBTSxDQUFDcGlCLE1BQU0sQ0FBQ29XLEdBQUcsQ0FBQyxDQUFDLENBQUM7TUFDMUMsSUFBSTFkLEdBQUcsS0FBSyxNQUFNLEVBQUUsQ0FBRSxJQUFJMGQsR0FBRyxFQUFFbk4sRUFBRSxDQUFDK00sT0FBTyxDQUFDSSxHQUFHLENBQUMsQ0FBRSxDQUFDO01BQ2pELElBQUkxZCxHQUFHLEtBQUssUUFBUSxFQUFFdVEsRUFBRSxDQUFDZ1osTUFBTSxDQUFDN0wsR0FBRyxDQUFDLENBQUM7TUFDckMsSUFBSTFkLEdBQUcsS0FBSyxNQUFNLEVBQUUsQ0FBRSxDQUFDLENBQUM7TUFBQSxLQUN4QixJQUFJQSxHQUFHLEtBQUssU0FBUyxFQUFFdVEsRUFBRSxDQUFDcWEsT0FBTyxDQUFDbE4sR0FBRyxDQUFDLENBQUM7TUFDdkMsSUFBSTFkLEdBQUcsS0FBSyxhQUFhLEVBQUV1USxFQUFFLENBQUM2VyxhQUFhLENBQUMxSixHQUFHLENBQUMsQ0FBQztNQUNqRCxJQUFJMWQsR0FBRyxLQUFLLFFBQVEsRUFBRXVRLEVBQUUsQ0FBQ29aLFNBQVMsQ0FBQ2pNLEdBQUcsQ0FBQyxDQUFDO01BQ3hDLElBQUkxZCxHQUFHLEtBQUssUUFBUSxFQUFFdVEsRUFBRSxDQUFDb1csV0FBVyxDQUFDakosR0FBRyxDQUFDLENBQUM7TUFDMUMsSUFBSTFkLEdBQUcsS0FBSyxTQUFTLEVBQUV1USxFQUFFLENBQUNpWixVQUFVLENBQUM5TCxHQUFHLENBQUMsQ0FBQztNQUMxQyxJQUFJMWQsR0FBRyxLQUFLLGFBQWEsRUFBRXVRLEVBQUUsQ0FBQ2taLFdBQVcsQ0FBQy9MLEdBQUcsQ0FBQyxDQUFDO01BQy9DLElBQUkxZCxHQUFHLEtBQUssbUJBQW1CLEVBQUV1USxFQUFFLENBQUNtWCxvQkFBb0IsQ0FBQ2hLLEdBQUcsQ0FBQyxDQUFDO01BQzlELElBQUkxZCxHQUFHLEtBQUssY0FBYyxJQUFJQSxHQUFHLEtBQUssUUFBUSxFQUFFO1FBQ25ELElBQUl1USxFQUFFLENBQUNhLGNBQWMsQ0FBQyxDQUFDLEVBQUU7VUFDdkIsSUFBSSxDQUFDdVosTUFBTSxFQUFFQSxNQUFNLEdBQUcsSUFBSUUsMEJBQWlCLENBQUMsQ0FBQztVQUM3Q0YsTUFBTSxDQUFDbFgsU0FBUyxDQUFDaUssR0FBRyxDQUFDO1FBQ3ZCO01BQ0YsQ0FBQztNQUNJLElBQUkxZCxHQUFHLEtBQUssV0FBVyxFQUFFO1FBQzVCLElBQUl1USxFQUFFLENBQUNhLGNBQWMsQ0FBQyxDQUFDLEVBQUU7VUFDdkIsSUFBSSxDQUFDdVosTUFBTSxFQUFFQSxNQUFNLEdBQUcsSUFBSUUsMEJBQWlCLENBQUMsQ0FBQztVQUM3Q0YsTUFBTSxDQUFDRyxZQUFZLENBQUNwTixHQUFHLENBQUM7UUFDMUIsQ0FBQyxNQUFNOztVQUNMO1FBQUEsQ0FFSixDQUFDO01BQ0ksSUFBSTFkLEdBQUcsS0FBSyxlQUFlLEVBQUV1USxFQUFFLENBQUM4SixtQkFBbUIsQ0FBQ3FELEdBQUcsQ0FBQyxDQUFDO01BQ3pELElBQUkxZCxHQUFHLEtBQUssbUNBQW1DLEVBQUU7UUFDcEQsSUFBSWtRLFFBQVEsS0FBS2pQLFNBQVMsRUFBRWlQLFFBQVEsR0FBRyxDQUFDc2EsVUFBVSxHQUFHLElBQUlqQywrQkFBc0IsQ0FBQyxDQUFDLEdBQUcsSUFBSXdDLCtCQUFzQixDQUFDLENBQUMsRUFBRXZDLEtBQUssQ0FBQ2pZLEVBQUUsQ0FBQztRQUMzSCxJQUFJLENBQUNpYSxVQUFVLEVBQUV0YSxRQUFRLENBQUM4YSw0QkFBNEIsQ0FBQ3ROLEdBQUcsQ0FBQztNQUM3RCxDQUFDO01BQ0ksSUFBSTFkLEdBQUcsS0FBSyxRQUFRLEVBQUU7UUFDekIsSUFBSWtRLFFBQVEsS0FBS2pQLFNBQVMsRUFBRWlQLFFBQVEsR0FBRyxDQUFDc2EsVUFBVSxHQUFHLElBQUlqQywrQkFBc0IsQ0FBQyxDQUFDLEdBQUcsSUFBSXdDLCtCQUFzQixDQUFDLENBQUMsRUFBRXZDLEtBQUssQ0FBQ2pZLEVBQUUsQ0FBQztRQUMzSEwsUUFBUSxDQUFDeUcsU0FBUyxDQUFDclAsTUFBTSxDQUFDb1csR0FBRyxDQUFDLENBQUM7TUFDakMsQ0FBQztNQUNJLElBQUkxZCxHQUFHLEtBQUssU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFFO01BQUEsS0FDM0IsSUFBSUEsR0FBRyxLQUFLLFNBQVMsRUFBRTtRQUMxQixJQUFJLENBQUN3cUIsVUFBVSxFQUFFO1VBQ2YsSUFBSSxDQUFDdGEsUUFBUSxFQUFFQSxRQUFRLEdBQUcsSUFBSTZhLCtCQUFzQixDQUFDLENBQUMsQ0FBQ3ZDLEtBQUssQ0FBQ2pZLEVBQUUsQ0FBQztVQUNoRUwsUUFBUSxDQUFDMUIsVUFBVSxDQUFDa1AsR0FBRyxDQUFDO1FBQzFCO01BQ0YsQ0FBQztNQUNJLElBQUkxZCxHQUFHLEtBQUssWUFBWSxFQUFFO1FBQzdCLElBQUksRUFBRSxLQUFLMGQsR0FBRyxJQUFJeEgsdUJBQWMsQ0FBQytVLGtCQUFrQixLQUFLdk4sR0FBRyxFQUFFbk4sRUFBRSxDQUFDbkcsWUFBWSxDQUFDc1QsR0FBRyxDQUFDLENBQUMsQ0FBRTtNQUN0RixDQUFDO01BQ0ksSUFBSTFkLEdBQUcsS0FBSyxlQUFlLEVBQUUsSUFBQW1ILGVBQU0sRUFBQ21lLEtBQUssQ0FBQ2pRLGVBQWUsQ0FBQyxDQUFDLENBQUU7TUFBQSxLQUM3RCxJQUFJclYsR0FBRyxLQUFLLGlCQUFpQixFQUFFO1FBQ2xDLElBQUksQ0FBQ2tRLFFBQVEsRUFBRUEsUUFBUSxHQUFHLENBQUNzYSxVQUFVLEdBQUcsSUFBSWpDLCtCQUFzQixDQUFDLENBQUMsR0FBRyxJQUFJd0MsK0JBQXNCLENBQUMsQ0FBQyxFQUFFdkMsS0FBSyxDQUFDalksRUFBRSxDQUFDO1FBQzlHLElBQUkyYSxVQUFVLEdBQUd4TixHQUFHO1FBQ3BCeE4sUUFBUSxDQUFDOUcsZUFBZSxDQUFDOGhCLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQzVoQixLQUFLLENBQUM7UUFDN0MsSUFBSWtoQixVQUFVLEVBQUU7VUFDZCxJQUFJeGMsaUJBQWlCLEdBQUcsRUFBRTtVQUMxQixLQUFLLElBQUltZCxRQUFRLElBQUlELFVBQVUsRUFBRWxkLGlCQUFpQixDQUFDakIsSUFBSSxDQUFDb2UsUUFBUSxDQUFDM2hCLEtBQUssQ0FBQztVQUN2RTBHLFFBQVEsQ0FBQ21HLG9CQUFvQixDQUFDckksaUJBQWlCLENBQUM7UUFDbEQsQ0FBQyxNQUFNO1VBQ0w3RyxlQUFNLENBQUNDLEtBQUssQ0FBQzhqQixVQUFVLENBQUNoZixNQUFNLEVBQUUsQ0FBQyxDQUFDO1VBQ2xDZ0UsUUFBUSxDQUFDa2Isa0JBQWtCLENBQUNGLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQzFoQixLQUFLLENBQUM7UUFDbEQ7TUFDRixDQUFDO01BQ0ksSUFBSXhKLEdBQUcsS0FBSyxjQUFjLElBQUlBLEdBQUcsSUFBSSxZQUFZLEVBQUU7UUFDdEQsSUFBQW1ILGVBQU0sRUFBQ3FqQixVQUFVLENBQUM7UUFDbEIsSUFBSTNWLFlBQVksR0FBRyxFQUFFO1FBQ3JCLEtBQUssSUFBSXdXLGNBQWMsSUFBSTNOLEdBQUcsRUFBRTtVQUM5QixJQUFJNUksV0FBVyxHQUFHLElBQUlrUywwQkFBaUIsQ0FBQyxDQUFDO1VBQ3pDblMsWUFBWSxDQUFDOUgsSUFBSSxDQUFDK0gsV0FBVyxDQUFDO1VBQzlCLEtBQUssSUFBSXdXLGNBQWMsSUFBSXpyQixNQUFNLENBQUNrWCxJQUFJLENBQUNzVSxjQUFjLENBQUMsRUFBRTtZQUN0RCxJQUFJQyxjQUFjLEtBQUssU0FBUyxFQUFFeFcsV0FBVyxDQUFDdEcsVUFBVSxDQUFDNmMsY0FBYyxDQUFDQyxjQUFjLENBQUMsQ0FBQyxDQUFDO1lBQ3BGLElBQUlBLGNBQWMsS0FBSyxRQUFRLEVBQUV4VyxXQUFXLENBQUM2QixTQUFTLENBQUNyUCxNQUFNLENBQUMrakIsY0FBYyxDQUFDQyxjQUFjLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDL0YsTUFBTSxJQUFJcHFCLG9CQUFXLENBQUMsOENBQThDLEdBQUdvcUIsY0FBYyxDQUFDO1VBQzdGO1FBQ0Y7UUFDQSxJQUFJcGIsUUFBUSxLQUFLalAsU0FBUyxFQUFFaVAsUUFBUSxHQUFHLElBQUlxWSwrQkFBc0IsQ0FBQyxFQUFDaFksRUFBRSxFQUFFQSxFQUFFLEVBQUMsQ0FBQztRQUMzRUwsUUFBUSxDQUFDK1csZUFBZSxDQUFDcFMsWUFBWSxDQUFDO01BQ3hDLENBQUM7TUFDSSxJQUFJN1UsR0FBRyxLQUFLLGdCQUFnQixJQUFJMGQsR0FBRyxLQUFLemMsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDO01BQUEsS0FDdEQsSUFBSWpCLEdBQUcsS0FBSyxnQkFBZ0IsSUFBSTBkLEdBQUcsS0FBS3pjLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQztNQUFBLEtBQ3RELElBQUlqQixHQUFHLEtBQUssV0FBVyxFQUFFdVEsRUFBRSxDQUFDZ2IsV0FBVyxDQUFDamtCLE1BQU0sQ0FBQ29XLEdBQUcsQ0FBQyxDQUFDLENBQUM7TUFDckQsSUFBSTFkLEdBQUcsS0FBSyxZQUFZLEVBQUV1USxFQUFFLENBQUNpYixZQUFZLENBQUNsa0IsTUFBTSxDQUFDb1csR0FBRyxDQUFDLENBQUMsQ0FBQztNQUN2RCxJQUFJMWQsR0FBRyxLQUFLLGdCQUFnQixFQUFFdVEsRUFBRSxDQUFDa2IsZ0JBQWdCLENBQUMvTixHQUFHLEtBQUssRUFBRSxHQUFHemMsU0FBUyxHQUFHeWMsR0FBRyxDQUFDLENBQUM7TUFDaEYsSUFBSTFkLEdBQUcsS0FBSyxlQUFlLEVBQUV1USxFQUFFLENBQUNtYixlQUFlLENBQUNwa0IsTUFBTSxDQUFDb1csR0FBRyxDQUFDLENBQUMsQ0FBQztNQUM3RCxJQUFJMWQsR0FBRyxLQUFLLGVBQWUsRUFBRXVRLEVBQUUsQ0FBQ29iLGtCQUFrQixDQUFDak8sR0FBRyxDQUFDLENBQUM7TUFDeEQsSUFBSTFkLEdBQUcsS0FBSyxPQUFPLEVBQUV1USxFQUFFLENBQUNxYixXQUFXLENBQUNsTyxHQUFHLENBQUMsQ0FBQztNQUN6QyxJQUFJMWQsR0FBRyxLQUFLLFdBQVcsRUFBRXVRLEVBQUUsQ0FBQzZYLFdBQVcsQ0FBQzFLLEdBQUcsQ0FBQyxDQUFDO01BQzdDLElBQUkxZCxHQUFHLEtBQUssa0JBQWtCLEVBQUU7UUFDbkMsSUFBSTZyQixjQUFjLEdBQUduTyxHQUFHLENBQUNvTyxVQUFVO1FBQ25DMXFCLGlCQUFRLENBQUN5b0IsVUFBVSxDQUFDdFosRUFBRSxDQUFDdVosU0FBUyxDQUFDLENBQUMsS0FBSzdvQixTQUFTLENBQUM7UUFDakRzUCxFQUFFLENBQUN3WixTQUFTLENBQUMsRUFBRSxDQUFDO1FBQ2hCLEtBQUssSUFBSUMsYUFBYSxJQUFJNkIsY0FBYyxFQUFFO1VBQ3hDdGIsRUFBRSxDQUFDdVosU0FBUyxDQUFDLENBQUMsQ0FBQy9jLElBQUksQ0FBQyxJQUFJa2QsMkJBQWtCLENBQUMsQ0FBQyxDQUFDQyxXQUFXLENBQUMsSUFBSTFELHVCQUFjLENBQUMsQ0FBQyxDQUFDMkQsTUFBTSxDQUFDSCxhQUFhLENBQUMsQ0FBQyxDQUFDeEIsS0FBSyxDQUFDalksRUFBRSxDQUFDLENBQUM7UUFDakg7TUFDRixDQUFDO01BQ0ksSUFBSXZRLEdBQUcsS0FBSyxpQkFBaUIsRUFBRTtRQUNsQ29CLGlCQUFRLENBQUN5b0IsVUFBVSxDQUFDVyxVQUFVLENBQUM7UUFDL0IsSUFBSUQsYUFBYSxHQUFHN00sR0FBRyxDQUFDcU8sT0FBTztRQUMvQjVrQixlQUFNLENBQUNDLEtBQUssQ0FBQzFHLE1BQU0sQ0FBQ3FVLGVBQWUsQ0FBQyxDQUFDLENBQUM3SSxNQUFNLEVBQUVxZSxhQUFhLENBQUNyZSxNQUFNLENBQUM7UUFDbkUsSUFBSWdFLFFBQVEsS0FBS2pQLFNBQVMsRUFBRWlQLFFBQVEsR0FBRyxJQUFJcVksK0JBQXNCLENBQUMsQ0FBQyxDQUFDQyxLQUFLLENBQUNqWSxFQUFFLENBQUM7UUFDN0VMLFFBQVEsQ0FBQytXLGVBQWUsQ0FBQyxFQUFFLENBQUM7UUFDNUIsS0FBSyxJQUFJaFIsQ0FBQyxHQUFHLENBQUMsRUFBRUEsQ0FBQyxHQUFHdlYsTUFBTSxDQUFDcVUsZUFBZSxDQUFDLENBQUMsQ0FBQzdJLE1BQU0sRUFBRStKLENBQUMsRUFBRSxFQUFFO1VBQ3hEL0YsUUFBUSxDQUFDNkUsZUFBZSxDQUFDLENBQUMsQ0FBQ2hJLElBQUksQ0FBQyxJQUFJaWEsMEJBQWlCLENBQUN0bUIsTUFBTSxDQUFDcVUsZUFBZSxDQUFDLENBQUMsQ0FBQ2tCLENBQUMsQ0FBQyxDQUFDbk4sVUFBVSxDQUFDLENBQUMsRUFBRXhCLE1BQU0sQ0FBQ2lqQixhQUFhLENBQUN0VSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDNUg7TUFDRixDQUFDO01BQ0k1RSxPQUFPLENBQUNtUixHQUFHLENBQUMsZ0VBQWdFLEdBQUd4aUIsR0FBRyxHQUFHLElBQUksR0FBRzBkLEdBQUcsQ0FBQztJQUN2Rzs7SUFFQTtJQUNBLElBQUlpTixNQUFNLEVBQUVwYSxFQUFFLENBQUN5YixRQUFRLENBQUMsSUFBSUMsb0JBQVcsQ0FBQ3RCLE1BQU0sQ0FBQyxDQUFDdkIsTUFBTSxDQUFDLENBQUM3WSxFQUFFLENBQUMsQ0FBQyxDQUFDOztJQUU3RDtJQUNBLElBQUlMLFFBQVEsRUFBRTtNQUNaLElBQUlLLEVBQUUsQ0FBQ2EsY0FBYyxDQUFDLENBQUMsS0FBS25RLFNBQVMsRUFBRXNQLEVBQUUsQ0FBQ3FXLGNBQWMsQ0FBQyxLQUFLLENBQUM7TUFDL0QsSUFBSSxDQUFDMVcsUUFBUSxDQUFDQyxLQUFLLENBQUMsQ0FBQyxDQUFDaUIsY0FBYyxDQUFDLENBQUMsRUFBRWIsRUFBRSxDQUFDOEosbUJBQW1CLENBQUMsQ0FBQyxDQUFDO01BQ2pFLElBQUltUSxVQUFVLEVBQUU7UUFDZGphLEVBQUUsQ0FBQ3dWLGFBQWEsQ0FBQyxJQUFJLENBQUM7UUFDdEIsSUFBSXhWLEVBQUUsQ0FBQzZGLG1CQUFtQixDQUFDLENBQUMsRUFBRTtVQUM1QixJQUFJbEcsUUFBUSxDQUFDNkUsZUFBZSxDQUFDLENBQUMsRUFBRXhFLEVBQUUsQ0FBQzZGLG1CQUFtQixDQUFDLENBQUMsQ0FBQzZRLGVBQWUsQ0FBQ2htQixTQUFTLENBQUMsQ0FBQyxDQUFDO1VBQ3JGc1AsRUFBRSxDQUFDNkYsbUJBQW1CLENBQUMsQ0FBQyxDQUFDOFYsS0FBSyxDQUFDaGMsUUFBUSxDQUFDO1FBQzFDLENBQUM7UUFDSUssRUFBRSxDQUFDMlcsbUJBQW1CLENBQUNoWCxRQUFRLENBQUM7TUFDdkMsQ0FBQyxNQUFNO1FBQ0xLLEVBQUUsQ0FBQ3VWLGFBQWEsQ0FBQyxJQUFJLENBQUM7UUFDdEJ2VixFQUFFLENBQUM0YixvQkFBb0IsQ0FBQyxDQUFDamMsUUFBUSxDQUFDLENBQUM7TUFDckM7SUFDRjs7SUFFQTtJQUNBLE9BQU9LLEVBQUU7RUFDWDs7RUFFQSxPQUFpQjhWLDRCQUE0QkEsQ0FBQ0QsU0FBUyxFQUFFOztJQUV2RDtJQUNBLElBQUk3VixFQUFFLEdBQUcsSUFBSTJGLHVCQUFjLENBQUMsQ0FBQztJQUM3QjNGLEVBQUUsQ0FBQ3FXLGNBQWMsQ0FBQyxJQUFJLENBQUM7SUFDdkJyVyxFQUFFLENBQUMrRyxZQUFZLENBQUMsSUFBSSxDQUFDO0lBQ3JCL0csRUFBRSxDQUFDd1csV0FBVyxDQUFDLEtBQUssQ0FBQzs7SUFFckI7SUFDQSxJQUFJaFcsTUFBTSxHQUFHLElBQUlrWiwyQkFBa0IsQ0FBQyxFQUFDMVosRUFBRSxFQUFFQSxFQUFFLEVBQUMsQ0FBQztJQUM3QyxLQUFLLElBQUl2USxHQUFHLElBQUlILE1BQU0sQ0FBQ2tYLElBQUksQ0FBQ3FQLFNBQVMsQ0FBQyxFQUFFO01BQ3RDLElBQUkxSSxHQUFHLEdBQUcwSSxTQUFTLENBQUNwbUIsR0FBRyxDQUFDO01BQ3hCLElBQUlBLEdBQUcsS0FBSyxRQUFRLEVBQUUrUSxNQUFNLENBQUM0RixTQUFTLENBQUNyUCxNQUFNLENBQUNvVyxHQUFHLENBQUMsQ0FBQyxDQUFDO01BQy9DLElBQUkxZCxHQUFHLEtBQUssT0FBTyxFQUFFK1EsTUFBTSxDQUFDcWIsVUFBVSxDQUFDMU8sR0FBRyxDQUFDLENBQUM7TUFDNUMsSUFBSTFkLEdBQUcsS0FBSyxXQUFXLEVBQUUsQ0FBRSxJQUFJLEVBQUUsS0FBSzBkLEdBQUcsRUFBRTNNLE1BQU0sQ0FBQ21aLFdBQVcsQ0FBQyxJQUFJMUQsdUJBQWMsQ0FBQzlJLEdBQUcsQ0FBQyxDQUFDLENBQUUsQ0FBQztNQUN6RixJQUFJMWQsR0FBRyxLQUFLLGNBQWMsRUFBRStRLE1BQU0sQ0FBQ3hILFFBQVEsQ0FBQ21VLEdBQUcsQ0FBQyxDQUFDO01BQ2pELElBQUkxZCxHQUFHLEtBQUssU0FBUyxFQUFFdVEsRUFBRSxDQUFDK1ksT0FBTyxDQUFDNUwsR0FBRyxDQUFDLENBQUM7TUFDdkMsSUFBSTFkLEdBQUcsS0FBSyxVQUFVLEVBQUV1USxFQUFFLENBQUNvVyxXQUFXLENBQUMsQ0FBQ2pKLEdBQUcsQ0FBQyxDQUFDO01BQzdDLElBQUkxZCxHQUFHLEtBQUssUUFBUSxFQUFFK1EsTUFBTSxDQUFDc2IsV0FBVyxDQUFDM08sR0FBRyxDQUFDLENBQUM7TUFDOUMsSUFBSTFkLEdBQUcsS0FBSyxRQUFRLEVBQUUrUSxNQUFNLENBQUN1YixtQkFBbUIsQ0FBQzVPLEdBQUcsQ0FBQyxDQUFDO01BQ3RELElBQUkxZCxHQUFHLEtBQUssZUFBZSxFQUFFO1FBQ2hDK1EsTUFBTSxDQUFDM0gsZUFBZSxDQUFDc1UsR0FBRyxDQUFDcFUsS0FBSyxDQUFDO1FBQ2pDeUgsTUFBTSxDQUFDcWEsa0JBQWtCLENBQUMxTixHQUFHLENBQUNsVSxLQUFLLENBQUM7TUFDdEMsQ0FBQztNQUNJLElBQUl4SixHQUFHLEtBQUssY0FBYyxFQUFFdVEsRUFBRSxDQUFDeWIsUUFBUSxDQUFFLElBQUlDLG9CQUFXLENBQUMsQ0FBQyxDQUFDeFksU0FBUyxDQUFDaUssR0FBRyxDQUFDLENBQWlCMEwsTUFBTSxDQUFDLENBQUM3WSxFQUFFLENBQWEsQ0FBQyxDQUFDLENBQUM7TUFDcEhjLE9BQU8sQ0FBQ21SLEdBQUcsQ0FBQyxrREFBa0QsR0FBR3hpQixHQUFHLEdBQUcsSUFBSSxHQUFHMGQsR0FBRyxDQUFDO0lBQ3pGOztJQUVBO0lBQ0FuTixFQUFFLENBQUNnYyxVQUFVLENBQUMsQ0FBQ3hiLE1BQU0sQ0FBQyxDQUFDO0lBQ3ZCLE9BQU9SLEVBQUU7RUFDWDs7RUFFQSxPQUFpQmdJLDBCQUEwQkEsQ0FBQ2lVLHlCQUF5QixFQUFFO0lBQ3JFLElBQUluVixLQUFLLEdBQUcsSUFBSXdSLG9CQUFXLENBQUMsQ0FBQztJQUM3QixLQUFLLElBQUk3b0IsR0FBRyxJQUFJSCxNQUFNLENBQUNrWCxJQUFJLENBQUN5Vix5QkFBeUIsQ0FBQyxFQUFFO01BQ3RELElBQUk5TyxHQUFHLEdBQUc4Tyx5QkFBeUIsQ0FBQ3hzQixHQUFHLENBQUM7TUFDeEMsSUFBSUEsR0FBRyxLQUFLLE1BQU0sRUFBRTtRQUNsQnFYLEtBQUssQ0FBQytSLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFDaEIsS0FBSyxJQUFJL1ksS0FBSyxJQUFJcU4sR0FBRyxFQUFFO1VBQ3JCLElBQUluTixFQUFFLEdBQUdqUSxlQUFlLENBQUNpbEIsd0JBQXdCLENBQUNsVixLQUFLLEVBQUVwUCxTQUFTLEVBQUUsSUFBSSxDQUFDO1VBQ3pFc1AsRUFBRSxDQUFDOFksUUFBUSxDQUFDaFMsS0FBSyxDQUFDO1VBQ2xCQSxLQUFLLENBQUN6SSxNQUFNLENBQUMsQ0FBQyxDQUFDN0IsSUFBSSxDQUFDd0QsRUFBRSxDQUFDO1FBQ3pCO01BQ0YsQ0FBQztNQUNJLElBQUl2USxHQUFHLEtBQUssU0FBUyxFQUFFLENBQUUsQ0FBQyxDQUFDO01BQUEsS0FDM0JxUixPQUFPLENBQUNtUixHQUFHLENBQUMseURBQXlELEdBQUd4aUIsR0FBRyxHQUFHLElBQUksR0FBRzBkLEdBQUcsQ0FBQztJQUNoRztJQUNBLE9BQU9yRyxLQUFLO0VBQ2Q7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDRSxPQUFpQnFULGFBQWFBLENBQUMrQixPQUFPLEVBQUVsYyxFQUFFLEVBQUU7SUFDMUMsSUFBSWlhLFVBQVU7SUFDZCxJQUFJaUMsT0FBTyxLQUFLLElBQUksRUFBRTtNQUNwQmpDLFVBQVUsR0FBRyxLQUFLO01BQ2xCamEsRUFBRSxDQUFDcVcsY0FBYyxDQUFDLElBQUksQ0FBQztNQUN2QnJXLEVBQUUsQ0FBQ2dILFdBQVcsQ0FBQyxLQUFLLENBQUM7TUFDckJoSCxFQUFFLENBQUMrRyxZQUFZLENBQUMsSUFBSSxDQUFDO01BQ3JCL0csRUFBRSxDQUFDc1csUUFBUSxDQUFDLElBQUksQ0FBQztNQUNqQnRXLEVBQUUsQ0FBQ3dXLFdBQVcsQ0FBQyxLQUFLLENBQUM7TUFDckJ4VyxFQUFFLENBQUN1VyxZQUFZLENBQUMsS0FBSyxDQUFDO0lBQ3hCLENBQUMsTUFBTSxJQUFJMkYsT0FBTyxLQUFLLEtBQUssRUFBRTtNQUM1QmpDLFVBQVUsR0FBRyxJQUFJO01BQ2pCamEsRUFBRSxDQUFDcVcsY0FBYyxDQUFDLElBQUksQ0FBQztNQUN2QnJXLEVBQUUsQ0FBQ2dILFdBQVcsQ0FBQyxLQUFLLENBQUM7TUFDckJoSCxFQUFFLENBQUMrRyxZQUFZLENBQUMsSUFBSSxDQUFDO01BQ3JCL0csRUFBRSxDQUFDc1csUUFBUSxDQUFDLElBQUksQ0FBQztNQUNqQnRXLEVBQUUsQ0FBQ3dXLFdBQVcsQ0FBQyxLQUFLLENBQUM7TUFDckJ4VyxFQUFFLENBQUN1VyxZQUFZLENBQUMsS0FBSyxDQUFDO0lBQ3hCLENBQUMsTUFBTSxJQUFJMkYsT0FBTyxLQUFLLE1BQU0sRUFBRTtNQUM3QmpDLFVBQVUsR0FBRyxLQUFLO01BQ2xCamEsRUFBRSxDQUFDcVcsY0FBYyxDQUFDLEtBQUssQ0FBQztNQUN4QnJXLEVBQUUsQ0FBQ2dILFdBQVcsQ0FBQyxJQUFJLENBQUM7TUFDcEJoSCxFQUFFLENBQUMrRyxZQUFZLENBQUMsSUFBSSxDQUFDO01BQ3JCL0csRUFBRSxDQUFDc1csUUFBUSxDQUFDLElBQUksQ0FBQztNQUNqQnRXLEVBQUUsQ0FBQ3dXLFdBQVcsQ0FBQyxLQUFLLENBQUM7TUFDckJ4VyxFQUFFLENBQUN1VyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBRTtJQUMzQixDQUFDLE1BQU0sSUFBSTJGLE9BQU8sS0FBSyxTQUFTLEVBQUU7TUFDaENqQyxVQUFVLEdBQUcsSUFBSTtNQUNqQmphLEVBQUUsQ0FBQ3FXLGNBQWMsQ0FBQyxLQUFLLENBQUM7TUFDeEJyVyxFQUFFLENBQUNnSCxXQUFXLENBQUMsSUFBSSxDQUFDO01BQ3BCaEgsRUFBRSxDQUFDK0csWUFBWSxDQUFDLElBQUksQ0FBQztNQUNyQi9HLEVBQUUsQ0FBQ3NXLFFBQVEsQ0FBQyxJQUFJLENBQUM7TUFDakJ0VyxFQUFFLENBQUN3VyxXQUFXLENBQUMsS0FBSyxDQUFDO01BQ3JCeFcsRUFBRSxDQUFDdVcsWUFBWSxDQUFDLEtBQUssQ0FBQztJQUN4QixDQUFDLE1BQU0sSUFBSTJGLE9BQU8sS0FBSyxPQUFPLEVBQUU7TUFDOUJqQyxVQUFVLEdBQUcsS0FBSztNQUNsQmphLEVBQUUsQ0FBQ3FXLGNBQWMsQ0FBQyxJQUFJLENBQUM7TUFDdkJyVyxFQUFFLENBQUNnSCxXQUFXLENBQUMsS0FBSyxDQUFDO01BQ3JCaEgsRUFBRSxDQUFDK0csWUFBWSxDQUFDLElBQUksQ0FBQztNQUNyQi9HLEVBQUUsQ0FBQ3NXLFFBQVEsQ0FBQyxJQUFJLENBQUM7TUFDakJ0VyxFQUFFLENBQUN3VyxXQUFXLENBQUMsS0FBSyxDQUFDO01BQ3JCeFcsRUFBRSxDQUFDdVcsWUFBWSxDQUFDLElBQUksQ0FBQztJQUN2QixDQUFDLE1BQU0sSUFBSTJGLE9BQU8sS0FBSyxRQUFRLEVBQUU7TUFDL0JqQyxVQUFVLEdBQUcsSUFBSTtNQUNqQmphLEVBQUUsQ0FBQ3FXLGNBQWMsQ0FBQyxLQUFLLENBQUM7TUFDeEJyVyxFQUFFLENBQUNnSCxXQUFXLENBQUMsS0FBSyxDQUFDO01BQ3JCaEgsRUFBRSxDQUFDK0csWUFBWSxDQUFDLElBQUksQ0FBQztNQUNyQi9HLEVBQUUsQ0FBQ3NXLFFBQVEsQ0FBQyxJQUFJLENBQUM7TUFDakJ0VyxFQUFFLENBQUN3VyxXQUFXLENBQUMsSUFBSSxDQUFDO01BQ3BCeFcsRUFBRSxDQUFDdVcsWUFBWSxDQUFDLEtBQUssQ0FBQztJQUN4QixDQUFDLE1BQU07TUFDTCxNQUFNLElBQUk1bEIsb0JBQVcsQ0FBQyw4QkFBOEIsR0FBR3VyQixPQUFPLENBQUM7SUFDakU7SUFDQSxPQUFPakMsVUFBVTtFQUNuQjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNFLE9BQWlCaGEsT0FBT0EsQ0FBQ0QsRUFBRSxFQUFFRixLQUFLLEVBQUVDLFFBQVEsRUFBRTtJQUM1QyxJQUFBbkosZUFBTSxFQUFDb0osRUFBRSxDQUFDbUIsT0FBTyxDQUFDLENBQUMsS0FBS3pRLFNBQVMsQ0FBQzs7SUFFbEM7SUFDQSxJQUFJeXJCLEdBQUcsR0FBR3JjLEtBQUssQ0FBQ0UsRUFBRSxDQUFDbUIsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUM3QixJQUFJZ2IsR0FBRyxLQUFLenJCLFNBQVMsRUFBRW9QLEtBQUssQ0FBQ0UsRUFBRSxDQUFDbUIsT0FBTyxDQUFDLENBQUMsQ0FBQyxHQUFHbkIsRUFBRSxDQUFDLENBQUM7SUFBQSxLQUM1Q21jLEdBQUcsQ0FBQ1IsS0FBSyxDQUFDM2IsRUFBRSxDQUFDLENBQUMsQ0FBQzs7SUFFcEI7SUFDQSxJQUFJQSxFQUFFLENBQUNqRyxTQUFTLENBQUMsQ0FBQyxLQUFLckosU0FBUyxFQUFFO01BQ2hDLElBQUkwckIsTUFBTSxHQUFHcmMsUUFBUSxDQUFDQyxFQUFFLENBQUNqRyxTQUFTLENBQUMsQ0FBQyxDQUFDO01BQ3JDLElBQUlxaUIsTUFBTSxLQUFLMXJCLFNBQVMsRUFBRXFQLFFBQVEsQ0FBQ0MsRUFBRSxDQUFDakcsU0FBUyxDQUFDLENBQUMsQ0FBQyxHQUFHaUcsRUFBRSxDQUFDVyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7TUFBQSxLQUMvRHliLE1BQU0sQ0FBQ1QsS0FBSyxDQUFDM2IsRUFBRSxDQUFDVyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNwQztFQUNGOztFQUVBO0FBQ0Y7QUFDQTtFQUNFLE9BQWlCMlUsa0JBQWtCQSxDQUFDK0csR0FBRyxFQUFFQyxHQUFHLEVBQUU7SUFDNUMsSUFBSUQsR0FBRyxDQUFDdGlCLFNBQVMsQ0FBQyxDQUFDLEtBQUtySixTQUFTLElBQUk0ckIsR0FBRyxDQUFDdmlCLFNBQVMsQ0FBQyxDQUFDLEtBQUtySixTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUFBLEtBQ3pFLElBQUkyckIsR0FBRyxDQUFDdGlCLFNBQVMsQ0FBQyxDQUFDLEtBQUtySixTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBRztJQUFBLEtBQy9DLElBQUk0ckIsR0FBRyxDQUFDdmlCLFNBQVMsQ0FBQyxDQUFDLEtBQUtySixTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFFO0lBQ3BELElBQUk2ckIsSUFBSSxHQUFHRixHQUFHLENBQUN0aUIsU0FBUyxDQUFDLENBQUMsR0FBR3VpQixHQUFHLENBQUN2aUIsU0FBUyxDQUFDLENBQUM7SUFDNUMsSUFBSXdpQixJQUFJLEtBQUssQ0FBQyxFQUFFLE9BQU9BLElBQUk7SUFDM0IsT0FBT0YsR0FBRyxDQUFDMWIsUUFBUSxDQUFDLENBQUMsQ0FBQ3RDLE1BQU0sQ0FBQyxDQUFDLENBQUN0RyxPQUFPLENBQUNza0IsR0FBRyxDQUFDLEdBQUdDLEdBQUcsQ0FBQzNiLFFBQVEsQ0FBQyxDQUFDLENBQUN0QyxNQUFNLENBQUMsQ0FBQyxDQUFDdEcsT0FBTyxDQUFDdWtCLEdBQUcsQ0FBQyxDQUFDLENBQUM7RUFDdEY7O0VBRUE7QUFDRjtBQUNBO0VBQ0UsT0FBTzdHLHdCQUF3QkEsQ0FBQytHLEVBQUUsRUFBRUMsRUFBRSxFQUFFO0lBQ3RDLElBQUlELEVBQUUsQ0FBQ3hmLGVBQWUsQ0FBQyxDQUFDLEdBQUd5ZixFQUFFLENBQUN6ZixlQUFlLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDdEQsSUFBSXdmLEVBQUUsQ0FBQ3hmLGVBQWUsQ0FBQyxDQUFDLEtBQUt5ZixFQUFFLENBQUN6ZixlQUFlLENBQUMsQ0FBQyxFQUFFLE9BQU93ZixFQUFFLENBQUM1SCxrQkFBa0IsQ0FBQyxDQUFDLEdBQUc2SCxFQUFFLENBQUM3SCxrQkFBa0IsQ0FBQyxDQUFDO0lBQ2hILE9BQU8sQ0FBQztFQUNWOztFQUVBO0FBQ0Y7QUFDQTtFQUNFLE9BQWlCbUIsY0FBY0EsQ0FBQzJHLEVBQUUsRUFBRUMsRUFBRSxFQUFFOztJQUV0QztJQUNBLElBQUlDLGdCQUFnQixHQUFHN3NCLGVBQWUsQ0FBQ3VsQixrQkFBa0IsQ0FBQ29ILEVBQUUsQ0FBQzljLEtBQUssQ0FBQyxDQUFDLEVBQUUrYyxFQUFFLENBQUMvYyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ2pGLElBQUlnZCxnQkFBZ0IsS0FBSyxDQUFDLEVBQUUsT0FBT0EsZ0JBQWdCOztJQUVuRDtJQUNBLElBQUlDLE9BQU8sR0FBR0gsRUFBRSxDQUFDMWYsZUFBZSxDQUFDLENBQUMsR0FBRzJmLEVBQUUsQ0FBQzNmLGVBQWUsQ0FBQyxDQUFDO0lBQ3pELElBQUk2ZixPQUFPLEtBQUssQ0FBQyxFQUFFLE9BQU9BLE9BQU87SUFDakNBLE9BQU8sR0FBR0gsRUFBRSxDQUFDOUgsa0JBQWtCLENBQUMsQ0FBQyxHQUFHK0gsRUFBRSxDQUFDL0gsa0JBQWtCLENBQUMsQ0FBQztJQUMzRCxJQUFJaUksT0FBTyxLQUFLLENBQUMsRUFBRSxPQUFPQSxPQUFPO0lBQ2pDQSxPQUFPLEdBQUdILEVBQUUsQ0FBQ25nQixRQUFRLENBQUMsQ0FBQyxHQUFHb2dCLEVBQUUsQ0FBQ3BnQixRQUFRLENBQUMsQ0FBQztJQUN2QyxJQUFJc2dCLE9BQU8sS0FBSyxDQUFDLEVBQUUsT0FBT0EsT0FBTztJQUNqQyxPQUFPSCxFQUFFLENBQUN2VyxXQUFXLENBQUMsQ0FBQyxDQUFDdkQsTUFBTSxDQUFDLENBQUMsQ0FBQ2thLGFBQWEsQ0FBQ0gsRUFBRSxDQUFDeFcsV0FBVyxDQUFDLENBQUMsQ0FBQ3ZELE1BQU0sQ0FBQyxDQUFDLENBQUM7RUFDM0U7QUFDRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBSkFtYSxPQUFBLENBQUEvdEIsT0FBQSxHQUFBZSxlQUFBO0FBS0EsTUFBTXNuQixZQUFZLENBQUM7O0VBRWpCOzs7Ozs7Ozs7Ozs7RUFZQW5uQixXQUFXQSxDQUFDK2lCLE1BQU0sRUFBRTtJQUNsQixJQUFJckIsSUFBSSxHQUFHLElBQUk7SUFDZixJQUFJLENBQUNxQixNQUFNLEdBQUdBLE1BQU07SUFDcEIsSUFBSSxDQUFDK0osTUFBTSxHQUFHLElBQUlDLG1CQUFVLENBQUMsa0JBQWlCLENBQUUsTUFBTXJMLElBQUksQ0FBQ2pYLElBQUksQ0FBQyxDQUFDLENBQUUsQ0FBQyxDQUFDO0lBQ3JFLElBQUksQ0FBQ3VpQixhQUFhLEdBQUcsRUFBRTtJQUN2QixJQUFJLENBQUNDLDRCQUE0QixHQUFHLElBQUl6ZCxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDL0MsSUFBSSxDQUFDMGQsMEJBQTBCLEdBQUcsSUFBSTFkLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM3QyxJQUFJLENBQUMyZCxVQUFVLEdBQUcsSUFBSUMsbUJBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JDLElBQUksQ0FBQ0MsVUFBVSxHQUFHLENBQUM7RUFDckI7O0VBRUFqRyxZQUFZQSxDQUFDQyxTQUFTLEVBQUU7SUFDdEIsSUFBSSxDQUFDQSxTQUFTLEdBQUdBLFNBQVM7SUFDMUIsSUFBSUEsU0FBUyxFQUFFLElBQUksQ0FBQ3lGLE1BQU0sQ0FBQ1EsS0FBSyxDQUFDLElBQUksQ0FBQ3ZLLE1BQU0sQ0FBQzFYLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzdELElBQUksQ0FBQ3loQixNQUFNLENBQUM1TSxJQUFJLENBQUMsQ0FBQztFQUN6Qjs7RUFFQTlVLGFBQWFBLENBQUNtaUIsVUFBVSxFQUFFO0lBQ3hCLElBQUksQ0FBQ1QsTUFBTSxDQUFDMWhCLGFBQWEsQ0FBQ21pQixVQUFVLENBQUM7RUFDdkM7O0VBRUEsTUFBTTlpQixJQUFJQSxDQUFBLEVBQUc7O0lBRVg7SUFDQSxJQUFJLElBQUksQ0FBQzRpQixVQUFVLEdBQUcsQ0FBQyxFQUFFO0lBQ3pCLElBQUksQ0FBQ0EsVUFBVSxFQUFFOztJQUVqQjtJQUNBLElBQUkzTCxJQUFJLEdBQUcsSUFBSTtJQUNmLE9BQU8sSUFBSSxDQUFDeUwsVUFBVSxDQUFDSyxNQUFNLENBQUMsa0JBQWlCO01BQzdDLElBQUk7O1FBRUY7UUFDQSxJQUFJLE1BQU05TCxJQUFJLENBQUNxQixNQUFNLENBQUM5QyxRQUFRLENBQUMsQ0FBQyxFQUFFO1VBQ2hDeUIsSUFBSSxDQUFDMkwsVUFBVSxFQUFFO1VBQ2pCO1FBQ0Y7O1FBRUE7UUFDQSxJQUFJM0wsSUFBSSxDQUFDK0wsWUFBWSxLQUFLanRCLFNBQVMsRUFBRTtVQUNuQ2toQixJQUFJLENBQUNnTSxVQUFVLEdBQUcsTUFBTWhNLElBQUksQ0FBQ3FCLE1BQU0sQ0FBQ2xaLFNBQVMsQ0FBQyxDQUFDO1VBQy9DNlgsSUFBSSxDQUFDc0wsYUFBYSxHQUFHLE1BQU10TCxJQUFJLENBQUNxQixNQUFNLENBQUM1VSxNQUFNLENBQUMsSUFBSXdmLHNCQUFhLENBQUMsQ0FBQyxDQUFDekgsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDO1VBQ3BGeEUsSUFBSSxDQUFDK0wsWUFBWSxHQUFHLE1BQU0vTCxJQUFJLENBQUNxQixNQUFNLENBQUN4YyxXQUFXLENBQUMsQ0FBQztVQUNuRG1iLElBQUksQ0FBQzJMLFVBQVUsRUFBRTtVQUNqQjtRQUNGOztRQUVBO1FBQ0EsSUFBSXZqQixNQUFNLEdBQUcsTUFBTTRYLElBQUksQ0FBQ3FCLE1BQU0sQ0FBQ2xaLFNBQVMsQ0FBQyxDQUFDO1FBQzFDLElBQUk2WCxJQUFJLENBQUNnTSxVQUFVLEtBQUs1akIsTUFBTSxFQUFFO1VBQzlCLEtBQUssSUFBSTBMLENBQUMsR0FBR2tNLElBQUksQ0FBQ2dNLFVBQVUsRUFBRWxZLENBQUMsR0FBRzFMLE1BQU0sRUFBRTBMLENBQUMsRUFBRSxFQUFFLE1BQU1rTSxJQUFJLENBQUNrTSxVQUFVLENBQUNwWSxDQUFDLENBQUM7VUFDdkVrTSxJQUFJLENBQUNnTSxVQUFVLEdBQUc1akIsTUFBTTtRQUMxQjs7UUFFQTtRQUNBLElBQUkrakIsU0FBUyxHQUFHOWlCLElBQUksQ0FBQytpQixHQUFHLENBQUMsQ0FBQyxFQUFFaGtCLE1BQU0sR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzFDLElBQUlpa0IsU0FBUyxHQUFHLE1BQU1yTSxJQUFJLENBQUNxQixNQUFNLENBQUM1VSxNQUFNLENBQUMsSUFBSXdmLHNCQUFhLENBQUMsQ0FBQyxDQUFDekgsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDOEgsWUFBWSxDQUFDSCxTQUFTLENBQUMsQ0FBQ0ksaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUM7O1FBRS9IO1FBQ0EsSUFBSUMsb0JBQW9CLEdBQUcsRUFBRTtRQUM3QixLQUFLLElBQUlDLFlBQVksSUFBSXpNLElBQUksQ0FBQ3NMLGFBQWEsRUFBRTtVQUMzQyxJQUFJdEwsSUFBSSxDQUFDaFMsS0FBSyxDQUFDcWUsU0FBUyxFQUFFSSxZQUFZLENBQUNsZCxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUt6USxTQUFTLEVBQUU7WUFDL0QwdEIsb0JBQW9CLENBQUM1aEIsSUFBSSxDQUFDNmhCLFlBQVksQ0FBQ2xkLE9BQU8sQ0FBQyxDQUFDLENBQUM7VUFDbkQ7UUFDRjs7UUFFQTtRQUNBeVEsSUFBSSxDQUFDc0wsYUFBYSxHQUFHZSxTQUFTOztRQUU5QjtRQUNBLElBQUlLLFdBQVcsR0FBR0Ysb0JBQW9CLENBQUN6aUIsTUFBTSxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQUcsTUFBTWlXLElBQUksQ0FBQ3FCLE1BQU0sQ0FBQzVVLE1BQU0sQ0FBQyxJQUFJd2Ysc0JBQWEsQ0FBQyxDQUFDLENBQUN6SCxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUM4SCxZQUFZLENBQUNILFNBQVMsQ0FBQyxDQUFDUSxTQUFTLENBQUNILG9CQUFvQixDQUFDLENBQUNELGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDOztRQUUzTTtRQUNBLEtBQUssSUFBSUssUUFBUSxJQUFJUCxTQUFTLEVBQUU7VUFDOUIsSUFBSVEsU0FBUyxHQUFHRCxRQUFRLENBQUMzZCxjQUFjLENBQUMsQ0FBQyxHQUFHK1EsSUFBSSxDQUFDd0wsMEJBQTBCLEdBQUd4TCxJQUFJLENBQUN1TCw0QkFBNEI7VUFDL0csSUFBSXVCLFdBQVcsR0FBRyxDQUFDRCxTQUFTLENBQUN2dkIsR0FBRyxDQUFDc3ZCLFFBQVEsQ0FBQ3JkLE9BQU8sQ0FBQyxDQUFDLENBQUM7VUFDcERzZCxTQUFTLENBQUM1ZSxHQUFHLENBQUMyZSxRQUFRLENBQUNyZCxPQUFPLENBQUMsQ0FBQyxDQUFDO1VBQ2pDLElBQUl1ZCxXQUFXLEVBQUUsTUFBTTlNLElBQUksQ0FBQytNLGFBQWEsQ0FBQ0gsUUFBUSxDQUFDO1FBQ3JEOztRQUVBO1FBQ0EsS0FBSyxJQUFJSSxVQUFVLElBQUlOLFdBQVcsRUFBRTtVQUNsQzFNLElBQUksQ0FBQ3VMLDRCQUE0QixDQUFDMEIsTUFBTSxDQUFDRCxVQUFVLENBQUN6ZCxPQUFPLENBQUMsQ0FBQyxDQUFDO1VBQzlEeVEsSUFBSSxDQUFDd0wsMEJBQTBCLENBQUN5QixNQUFNLENBQUNELFVBQVUsQ0FBQ3pkLE9BQU8sQ0FBQyxDQUFDLENBQUM7VUFDNUQsTUFBTXlRLElBQUksQ0FBQytNLGFBQWEsQ0FBQ0MsVUFBVSxDQUFDO1FBQ3RDOztRQUVBO1FBQ0EsTUFBTWhOLElBQUksQ0FBQ2tOLHVCQUF1QixDQUFDLENBQUM7UUFDcENsTixJQUFJLENBQUMyTCxVQUFVLEVBQUU7TUFDbkIsQ0FBQyxDQUFDLE9BQU85cEIsR0FBUSxFQUFFO1FBQ2pCbWUsSUFBSSxDQUFDMkwsVUFBVSxFQUFFO1FBQ2pCemMsT0FBTyxDQUFDQyxLQUFLLENBQUMsb0NBQW9DLElBQUcsTUFBTTZRLElBQUksQ0FBQ3FCLE1BQU0sQ0FBQ3ZoQixPQUFPLENBQUMsQ0FBQyxJQUFHLEtBQUssR0FBRytCLEdBQUcsQ0FBQ2EsT0FBTyxDQUFDO01BQ3pHO0lBQ0YsQ0FBQyxDQUFDO0VBQ0o7O0VBRUEsTUFBZ0J3cEIsVUFBVUEsQ0FBQzlqQixNQUFNLEVBQUU7SUFDakMsTUFBTSxJQUFJLENBQUNpWixNQUFNLENBQUM4TCxnQkFBZ0IsQ0FBQy9rQixNQUFNLENBQUM7RUFDNUM7O0VBRUEsTUFBZ0Iya0IsYUFBYUEsQ0FBQzNlLEVBQUUsRUFBRTs7SUFFaEM7SUFDQSxJQUFJQSxFQUFFLENBQUM2RixtQkFBbUIsQ0FBQyxDQUFDLEtBQUtuVixTQUFTLEVBQUU7TUFDMUMsSUFBQWtHLGVBQU0sRUFBQ29KLEVBQUUsQ0FBQ3VaLFNBQVMsQ0FBQyxDQUFDLEtBQUs3b0IsU0FBUyxDQUFDO01BQ3BDLElBQUk4UCxNQUFNLEdBQUcsSUFBSWtaLDJCQUFrQixDQUFDLENBQUM7TUFDaEN0VCxTQUFTLENBQUNwRyxFQUFFLENBQUM2RixtQkFBbUIsQ0FBQyxDQUFDLENBQUNwQixTQUFTLENBQUMsQ0FBQyxHQUFHekUsRUFBRSxDQUFDZ2YsTUFBTSxDQUFDLENBQUMsQ0FBQztNQUM3RG5tQixlQUFlLENBQUNtSCxFQUFFLENBQUM2RixtQkFBbUIsQ0FBQyxDQUFDLENBQUM3SSxlQUFlLENBQUMsQ0FBQyxDQUFDO01BQzNENmQsa0JBQWtCLENBQUM3YSxFQUFFLENBQUM2RixtQkFBbUIsQ0FBQyxDQUFDLENBQUN6QixvQkFBb0IsQ0FBQyxDQUFDLENBQUN6SSxNQUFNLEtBQUssQ0FBQyxHQUFHcUUsRUFBRSxDQUFDNkYsbUJBQW1CLENBQUMsQ0FBQyxDQUFDekIsb0JBQW9CLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHMVQsU0FBUyxDQUFDLENBQUM7TUFBQSxDQUNsSnVuQixLQUFLLENBQUNqWSxFQUFFLENBQUM7TUFDZEEsRUFBRSxDQUFDd1osU0FBUyxDQUFDLENBQUNoWixNQUFNLENBQUMsQ0FBQztNQUN0QixNQUFNLElBQUksQ0FBQ3lTLE1BQU0sQ0FBQ2dNLG1CQUFtQixDQUFDemUsTUFBTSxDQUFDO0lBQy9DOztJQUVBO0lBQ0EsSUFBSVIsRUFBRSxDQUFDcVEsb0JBQW9CLENBQUMsQ0FBQyxLQUFLM2YsU0FBUyxFQUFFO01BQzNDLElBQUlzUCxFQUFFLENBQUMyQixVQUFVLENBQUMsQ0FBQyxLQUFLalIsU0FBUyxJQUFJc1AsRUFBRSxDQUFDMkIsVUFBVSxDQUFDLENBQUMsQ0FBQ2hHLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBRTtRQUNqRSxLQUFLLElBQUk2RSxNQUFNLElBQUlSLEVBQUUsQ0FBQzJCLFVBQVUsQ0FBQyxDQUFDLEVBQUU7VUFDbEMsTUFBTSxJQUFJLENBQUNzUixNQUFNLENBQUNpTSxzQkFBc0IsQ0FBQzFlLE1BQU0sQ0FBQztRQUNsRDtNQUNGLENBQUMsTUFBTSxDQUFFO1FBQ1AsSUFBSUgsT0FBTyxHQUFHLEVBQUU7UUFDaEIsS0FBSyxJQUFJVixRQUFRLElBQUlLLEVBQUUsQ0FBQ3FRLG9CQUFvQixDQUFDLENBQUMsRUFBRTtVQUM5Q2hRLE9BQU8sQ0FBQzdELElBQUksQ0FBQyxJQUFJa2QsMkJBQWtCLENBQUMsQ0FBQztVQUNoQzdnQixlQUFlLENBQUM4RyxRQUFRLENBQUMzQyxlQUFlLENBQUMsQ0FBQyxDQUFDO1VBQzNDNmQsa0JBQWtCLENBQUNsYixRQUFRLENBQUNpVixrQkFBa0IsQ0FBQyxDQUFDLENBQUM7VUFDakR4TyxTQUFTLENBQUN6RyxRQUFRLENBQUM4RSxTQUFTLENBQUMsQ0FBQyxDQUFDO1VBQy9Cd1QsS0FBSyxDQUFDalksRUFBRSxDQUFDLENBQUM7UUFDakI7UUFDQUEsRUFBRSxDQUFDZ2MsVUFBVSxDQUFDM2IsT0FBTyxDQUFDO1FBQ3RCLEtBQUssSUFBSUcsTUFBTSxJQUFJUixFQUFFLENBQUMyQixVQUFVLENBQUMsQ0FBQyxFQUFFO1VBQ2xDLE1BQU0sSUFBSSxDQUFDc1IsTUFBTSxDQUFDaU0sc0JBQXNCLENBQUMxZSxNQUFNLENBQUM7UUFDbEQ7TUFDRjtJQUNGO0VBQ0Y7O0VBRVVaLEtBQUtBLENBQUNKLEdBQUcsRUFBRThKLE1BQU0sRUFBRTtJQUMzQixLQUFLLElBQUl0SixFQUFFLElBQUlSLEdBQUcsRUFBRSxJQUFJOEosTUFBTSxLQUFLdEosRUFBRSxDQUFDbUIsT0FBTyxDQUFDLENBQUMsRUFBRSxPQUFPbkIsRUFBRTtJQUMxRCxPQUFPdFAsU0FBUztFQUNsQjs7RUFFQSxNQUFnQm91Qix1QkFBdUJBLENBQUEsRUFBRztJQUN4QyxJQUFJSyxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUNsTSxNQUFNLENBQUN4YyxXQUFXLENBQUMsQ0FBQztJQUM5QyxJQUFJMG9CLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUN4QixZQUFZLENBQUMsQ0FBQyxDQUFDLElBQUl3QixRQUFRLENBQUMsQ0FBQyxDQUFDLEtBQUssSUFBSSxDQUFDeEIsWUFBWSxDQUFDLENBQUMsQ0FBQyxFQUFFO01BQ2hGLElBQUksQ0FBQ0EsWUFBWSxHQUFHd0IsUUFBUTtNQUM1QixNQUFNLElBQUksQ0FBQ2xNLE1BQU0sQ0FBQ21NLHVCQUF1QixDQUFDRCxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUVBLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUNuRSxPQUFPLElBQUk7SUFDYjtJQUNBLE9BQU8sS0FBSztFQUNkO0FBQ0YifQ== \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroAccount.d.ts b/dist/src/main/ts/wallet/model/MoneroAccount.d.ts new file mode 100644 index 000000000..aa18358cf --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroAccount.d.ts @@ -0,0 +1,30 @@ +import MoneroSubaddress from "./MoneroSubaddress"; +/** + * Monero account model. + */ +export default class MoneroAccount { + index: number; + primaryAddress: string; + balance: bigint; + unlockedBalance: bigint; + label: string; + tag: string; + subaddresses: MoneroSubaddress[]; + constructor(account?: Partial); + toJson(): any; + getIndex(): number; + setIndex(index: number): MoneroAccount; + getPrimaryAddress(): string; + setPrimaryAddress(primaryAddress: string): MoneroAccount; + getBalance(): bigint; + setBalance(balance: bigint): MoneroAccount; + getUnlockedBalance(): bigint; + setUnlockedBalance(unlockedBalance: bigint): MoneroAccount; + getLabel(): string; + setLabel(label: string): MoneroAccount; + getTag(): string; + setTag(tag: string): MoneroAccount; + getSubaddresses(): MoneroSubaddress[]; + setSubaddresses(subaddresses: MoneroSubaddress[]): MoneroAccount; + toString(indent?: number): string; +} diff --git a/dist/src/main/ts/wallet/model/MoneroAccount.js b/dist/src/main/ts/wallet/model/MoneroAccount.js new file mode 100644 index 000000000..b9a9069b9 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroAccount.js @@ -0,0 +1,132 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); +var _MoneroSubaddress = _interopRequireDefault(require("./MoneroSubaddress")); + +/** + * Monero account model. + */ +class MoneroAccount { + + + + + + + + + + constructor(account) { + Object.assign(this, account); + + // deserialize balances + if (this.balance !== undefined && typeof this.balance !== "bigint") this.balance = BigInt(this.balance); + if (this.unlockedBalance !== undefined && typeof this.unlockedBalance !== "bigint") this.unlockedBalance = BigInt(this.unlockedBalance); + + // copy subaddresses + if (this.subaddresses) { + for (let i = 0; i < this.subaddresses.length; i++) { + this.subaddresses[i] = new _MoneroSubaddress.default(this.subaddresses[i]); + } + } + } + + toJson() { + let json = Object.assign({}, this); + if (json.balance !== undefined) json.balance = json.balance.toString(); + if (json.unlockedBalance !== undefined) json.unlockedBalance = json.unlockedBalance.toString(); + if (json.subaddresses !== undefined) { + for (let i = 0; i < json.subaddresses.length; i++) { + json.subaddresses[i] = json.subaddresses[i].toJson(); + } + } + return json; + } + + getIndex() { + return this.index; + } + + setIndex(index) { + this.index = index; + return this; + } + + getPrimaryAddress() { + return this.primaryAddress; + } + + setPrimaryAddress(primaryAddress) { + this.primaryAddress = primaryAddress; + return this; + } + + getBalance() { + return this.balance; + } + + setBalance(balance) { + this.balance = balance; + return this; + } + + getUnlockedBalance() { + return this.unlockedBalance; + } + + setUnlockedBalance(unlockedBalance) { + this.unlockedBalance = unlockedBalance; + return this; + } + + getLabel() { + return this.label; + } + + setLabel(label) { + this.label = label; + return this; + } + + getTag() { + return this.tag; + } + + setTag(tag) { + this.tag = tag; + return this; + } + + getSubaddresses() { + return this.subaddresses; + } + + setSubaddresses(subaddresses) { + (0, _assert.default)(subaddresses === undefined || Array.isArray(subaddresses), "Given subaddresses must be undefined or an array of subaddresses"); + this.subaddresses = subaddresses; + if (subaddresses) { + for (let subaddress of subaddresses) { + subaddress.setAccountIndex(this.index); + } + } + return this; + } + + toString(indent = 0) { + let str = ""; + str += _GenUtils.default.kvLine("Index", this.getIndex(), indent); + str += _GenUtils.default.kvLine("Primary address", this.getPrimaryAddress(), indent); + str += _GenUtils.default.kvLine("Balance", this.getBalance(), indent); + str += _GenUtils.default.kvLine("Unlocked balance", this.getUnlockedBalance(), indent); + str += _GenUtils.default.kvLine("Label", this.getTag(), indent); + str += _GenUtils.default.kvLine("Tag", this.getTag(), indent); + if (this.getSubaddresses() !== undefined) { + str += _GenUtils.default.kvLine("Subaddresses", "", indent); + for (let i = 0; i < this.getSubaddresses().length; i++) { + str += _GenUtils.default.kvLine(i + 1, "", indent + 1); + str += this.getSubaddresses()[i].toString(indent + 2) + "\n"; + } + } + return str.slice(0, str.length - 1); // strip last newline + } +}exports.default = MoneroAccount; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTW9uZXJvU3ViYWRkcmVzcyIsIk1vbmVyb0FjY291bnQiLCJjb25zdHJ1Y3RvciIsImFjY291bnQiLCJPYmplY3QiLCJhc3NpZ24iLCJiYWxhbmNlIiwidW5kZWZpbmVkIiwiQmlnSW50IiwidW5sb2NrZWRCYWxhbmNlIiwic3ViYWRkcmVzc2VzIiwiaSIsImxlbmd0aCIsIk1vbmVyb1N1YmFkZHJlc3MiLCJ0b0pzb24iLCJqc29uIiwidG9TdHJpbmciLCJnZXRJbmRleCIsImluZGV4Iiwic2V0SW5kZXgiLCJnZXRQcmltYXJ5QWRkcmVzcyIsInByaW1hcnlBZGRyZXNzIiwic2V0UHJpbWFyeUFkZHJlc3MiLCJnZXRCYWxhbmNlIiwic2V0QmFsYW5jZSIsImdldFVubG9ja2VkQmFsYW5jZSIsInNldFVubG9ja2VkQmFsYW5jZSIsImdldExhYmVsIiwibGFiZWwiLCJzZXRMYWJlbCIsImdldFRhZyIsInRhZyIsInNldFRhZyIsImdldFN1YmFkZHJlc3NlcyIsInNldFN1YmFkZHJlc3NlcyIsImFzc2VydCIsIkFycmF5IiwiaXNBcnJheSIsInN1YmFkZHJlc3MiLCJzZXRBY2NvdW50SW5kZXgiLCJpbmRlbnQiLCJzdHIiLCJHZW5VdGlscyIsImt2TGluZSIsInNsaWNlIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy93YWxsZXQvbW9kZWwvTW9uZXJvQWNjb3VudC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi4vLi4vY29tbW9uL0dlblV0aWxzXCI7XG5pbXBvcnQgTW9uZXJvU3ViYWRkcmVzcyBmcm9tIFwiLi9Nb25lcm9TdWJhZGRyZXNzXCI7XG5cbi8qKlxuICogTW9uZXJvIGFjY291bnQgbW9kZWwuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0FjY291bnQge1xuXG4gIGluZGV4OiBudW1iZXI7XG4gIHByaW1hcnlBZGRyZXNzOiBzdHJpbmc7XG4gIGJhbGFuY2U6IGJpZ2ludDtcbiAgdW5sb2NrZWRCYWxhbmNlOiBiaWdpbnQ7XG4gIGxhYmVsOiBzdHJpbmc7XG4gIHRhZzogc3RyaW5nO1xuICBzdWJhZGRyZXNzZXM6IE1vbmVyb1N1YmFkZHJlc3NbXTtcbiAgXG4gIGNvbnN0cnVjdG9yKGFjY291bnQ/OiBQYXJ0aWFsPE1vbmVyb0FjY291bnQ+KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCBhY2NvdW50KTtcblxuICAgIC8vIGRlc2VyaWFsaXplIGJhbGFuY2VzXG4gICAgaWYgKHRoaXMuYmFsYW5jZSAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLmJhbGFuY2UgIT09IFwiYmlnaW50XCIpIHRoaXMuYmFsYW5jZSA9IEJpZ0ludCh0aGlzLmJhbGFuY2UpO1xuICAgIGlmICh0aGlzLnVubG9ja2VkQmFsYW5jZSAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLnVubG9ja2VkQmFsYW5jZSAhPT0gXCJiaWdpbnRcIikgdGhpcy51bmxvY2tlZEJhbGFuY2UgPSBCaWdJbnQodGhpcy51bmxvY2tlZEJhbGFuY2UpO1xuXG4gICAgLy8gY29weSBzdWJhZGRyZXNzZXNcbiAgICBpZiAodGhpcy5zdWJhZGRyZXNzZXMpIHtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5zdWJhZGRyZXNzZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdGhpcy5zdWJhZGRyZXNzZXNbaV0gPSBuZXcgTW9uZXJvU3ViYWRkcmVzcyh0aGlzLnN1YmFkZHJlc3Nlc1tpXSk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICBsZXQganNvbjogYW55ID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcyk7XG4gICAgaWYgKGpzb24uYmFsYW5jZSAhPT0gdW5kZWZpbmVkKSBqc29uLmJhbGFuY2UgPSBqc29uLmJhbGFuY2UudG9TdHJpbmcoKTtcbiAgICBpZiAoanNvbi51bmxvY2tlZEJhbGFuY2UgIT09IHVuZGVmaW5lZCkganNvbi51bmxvY2tlZEJhbGFuY2UgPSBqc29uLnVubG9ja2VkQmFsYW5jZS50b1N0cmluZygpO1xuICAgIGlmIChqc29uLnN1YmFkZHJlc3NlcyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGpzb24uc3ViYWRkcmVzc2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGpzb24uc3ViYWRkcmVzc2VzW2ldID0ganNvbi5zdWJhZGRyZXNzZXNbaV0udG9Kc29uKCk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBqc29uO1xuICB9XG4gIFxuICBnZXRJbmRleCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmluZGV4O1xuICB9XG4gIFxuICBzZXRJbmRleChpbmRleDogbnVtYmVyKTogTW9uZXJvQWNjb3VudCB7XG4gICAgdGhpcy5pbmRleCA9IGluZGV4O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRQcmltYXJ5QWRkcmVzcygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnByaW1hcnlBZGRyZXNzO1xuICB9XG5cbiAgc2V0UHJpbWFyeUFkZHJlc3MocHJpbWFyeUFkZHJlc3M6IHN0cmluZyk6IE1vbmVyb0FjY291bnQge1xuICAgIHRoaXMucHJpbWFyeUFkZHJlc3MgPSBwcmltYXJ5QWRkcmVzcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0QmFsYW5jZSgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLmJhbGFuY2U7XG4gIH1cbiAgXG4gIHNldEJhbGFuY2UoYmFsYW5jZTogYmlnaW50KTogTW9uZXJvQWNjb3VudCB7XG4gICAgdGhpcy5iYWxhbmNlID0gYmFsYW5jZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0VW5sb2NrZWRCYWxhbmNlKCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMudW5sb2NrZWRCYWxhbmNlO1xuICB9XG4gIFxuICBzZXRVbmxvY2tlZEJhbGFuY2UodW5sb2NrZWRCYWxhbmNlOiBiaWdpbnQpOiBNb25lcm9BY2NvdW50IHtcbiAgICB0aGlzLnVubG9ja2VkQmFsYW5jZSA9IHVubG9ja2VkQmFsYW5jZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldExhYmVsKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMubGFiZWw7XG4gIH1cbiAgXG4gIHNldExhYmVsKGxhYmVsOiBzdHJpbmcpOiBNb25lcm9BY2NvdW50IHtcbiAgICB0aGlzLmxhYmVsID0gbGFiZWw7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFRhZygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnRhZztcbiAgfVxuICBcbiAgc2V0VGFnKHRhZzogc3RyaW5nKTogTW9uZXJvQWNjb3VudCB7XG4gICAgdGhpcy50YWcgPSB0YWc7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFN1YmFkZHJlc3NlcygpOiBNb25lcm9TdWJhZGRyZXNzW10ge1xuICAgIHJldHVybiB0aGlzLnN1YmFkZHJlc3NlcztcbiAgfVxuICBcbiAgc2V0U3ViYWRkcmVzc2VzKHN1YmFkZHJlc3NlczogTW9uZXJvU3ViYWRkcmVzc1tdKTogTW9uZXJvQWNjb3VudCAge1xuICAgIGFzc2VydChzdWJhZGRyZXNzZXMgPT09IHVuZGVmaW5lZCB8fCBBcnJheS5pc0FycmF5KHN1YmFkZHJlc3NlcyksIFwiR2l2ZW4gc3ViYWRkcmVzc2VzIG11c3QgYmUgdW5kZWZpbmVkIG9yIGFuIGFycmF5IG9mIHN1YmFkZHJlc3Nlc1wiKTtcbiAgICB0aGlzLnN1YmFkZHJlc3NlcyA9IHN1YmFkZHJlc3NlcztcbiAgICBpZiAoc3ViYWRkcmVzc2VzKSB7XG4gICAgICBmb3IgKGxldCBzdWJhZGRyZXNzIG9mIHN1YmFkZHJlc3Nlcykge1xuICAgICAgICBzdWJhZGRyZXNzLnNldEFjY291bnRJbmRleCh0aGlzLmluZGV4KTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHRvU3RyaW5nKGluZGVudCA9IDApOiBzdHJpbmcge1xuICAgIGxldCBzdHIgPSBcIlwiO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJJbmRleFwiLCB0aGlzLmdldEluZGV4KCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlByaW1hcnkgYWRkcmVzc1wiLCB0aGlzLmdldFByaW1hcnlBZGRyZXNzKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIkJhbGFuY2VcIiwgdGhpcy5nZXRCYWxhbmNlKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlVubG9ja2VkIGJhbGFuY2VcIiwgdGhpcy5nZXRVbmxvY2tlZEJhbGFuY2UoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiTGFiZWxcIiwgdGhpcy5nZXRUYWcoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiVGFnXCIsIHRoaXMuZ2V0VGFnKCksIGluZGVudCk7XG4gICAgaWYgKHRoaXMuZ2V0U3ViYWRkcmVzc2VzKCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlN1YmFkZHJlc3Nlc1wiLCBcIlwiLCBpbmRlbnQpXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuZ2V0U3ViYWRkcmVzc2VzKCkubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShpICsgMSwgXCJcIiwgaW5kZW50ICsgMSk7XG4gICAgICAgIHN0ciArPSB0aGlzLmdldFN1YmFkZHJlc3NlcygpW2ldLnRvU3RyaW5nKGluZGVudCArIDIpICsgXCJcXG5cIjtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHN0ci5zbGljZSgwLCBzdHIubGVuZ3RoIC0gMSk7ICAvLyBzdHJpcCBsYXN0IG5ld2xpbmVcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsT0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsU0FBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUUsaUJBQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTs7QUFFQTtBQUNBO0FBQ0E7QUFDZSxNQUFNRyxhQUFhLENBQUM7Ozs7Ozs7Ozs7RUFVakNDLFdBQVdBLENBQUNDLE9BQWdDLEVBQUU7SUFDNUNDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsT0FBTyxDQUFDOztJQUU1QjtJQUNBLElBQUksSUFBSSxDQUFDRyxPQUFPLEtBQUtDLFNBQVMsSUFBSSxPQUFPLElBQUksQ0FBQ0QsT0FBTyxLQUFLLFFBQVEsRUFBRSxJQUFJLENBQUNBLE9BQU8sR0FBR0UsTUFBTSxDQUFDLElBQUksQ0FBQ0YsT0FBTyxDQUFDO0lBQ3ZHLElBQUksSUFBSSxDQUFDRyxlQUFlLEtBQUtGLFNBQVMsSUFBSSxPQUFPLElBQUksQ0FBQ0UsZUFBZSxLQUFLLFFBQVEsRUFBRSxJQUFJLENBQUNBLGVBQWUsR0FBR0QsTUFBTSxDQUFDLElBQUksQ0FBQ0MsZUFBZSxDQUFDOztJQUV2STtJQUNBLElBQUksSUFBSSxDQUFDQyxZQUFZLEVBQUU7TUFDckIsS0FBSyxJQUFJQyxDQUFDLEdBQUcsQ0FBQyxFQUFFQSxDQUFDLEdBQUcsSUFBSSxDQUFDRCxZQUFZLENBQUNFLE1BQU0sRUFBRUQsQ0FBQyxFQUFFLEVBQUU7UUFDakQsSUFBSSxDQUFDRCxZQUFZLENBQUNDLENBQUMsQ0FBQyxHQUFHLElBQUlFLHlCQUFnQixDQUFDLElBQUksQ0FBQ0gsWUFBWSxDQUFDQyxDQUFDLENBQUMsQ0FBQztNQUNuRTtJQUNGO0VBQ0Y7O0VBRUFHLE1BQU1BLENBQUEsRUFBUTtJQUNaLElBQUlDLElBQVMsR0FBR1gsTUFBTSxD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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroAccountTag.d.ts b/dist/src/main/ts/wallet/model/MoneroAccountTag.d.ts new file mode 100644 index 000000000..fefd665d9 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroAccountTag.d.ts @@ -0,0 +1,15 @@ +/** + * Represents an account tag. + */ +export default class MoneroAccountTag { + tag: string; + label: string; + accountIndices: number[]; + constructor(accountTag?: Partial); + getTag(): string; + setTag(tag: string): MoneroAccountTag; + getLabel(): string; + setLabel(label: string): MoneroAccountTag; + getAccountIndices(): number[]; + setAccountIndices(accountIndices: number[]): MoneroAccountTag; +} diff --git a/dist/src/main/ts/wallet/model/MoneroAccountTag.js b/dist/src/main/ts/wallet/model/MoneroAccountTag.js new file mode 100644 index 000000000..66c5b2e54 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroAccountTag.js @@ -0,0 +1,41 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Represents an account tag. + */ +class MoneroAccountTag { + + + + + + constructor(accountTag) { + Object.assign(this, accountTag); + } + + getTag() { + return this.tag; + } + + setTag(tag) { + this.tag = tag; + return this; + } + + getLabel() { + return this.label; + } + + setLabel(label) { + this.label = label; + return this; + } + + getAccountIndices() { + return this.accountIndices; + } + + setAccountIndices(accountIndices) { + this.accountIndices = accountIndices; + return this; + } +}exports.default = MoneroAccountTag; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9BY2NvdW50VGFnIiwiY29uc3RydWN0b3IiLCJhY2NvdW50VGFnIiwiT2JqZWN0IiwiYXNzaWduIiwiZ2V0VGFnIiwidGFnIiwic2V0VGFnIiwiZ2V0TGFiZWwiLCJsYWJlbCIsInNldExhYmVsIiwiZ2V0QWNjb3VudEluZGljZXMiLCJhY2NvdW50SW5kaWNlcyIsInNldEFjY291bnRJbmRpY2VzIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy93YWxsZXQvbW9kZWwvTW9uZXJvQWNjb3VudFRhZy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFJlcHJlc2VudHMgYW4gYWNjb3VudCB0YWcuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0FjY291bnRUYWcge1xuXG4gIHRhZzogc3RyaW5nO1xuICBsYWJlbDogc3RyaW5nO1xuICBhY2NvdW50SW5kaWNlczogbnVtYmVyW107XG4gIFxuICBjb25zdHJ1Y3RvcihhY2NvdW50VGFnPzogUGFydGlhbDxNb25lcm9BY2NvdW50VGFnPikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgYWNjb3VudFRhZyk7XG4gIH1cbiAgXG4gIGdldFRhZygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnRhZztcbiAgfVxuICBcbiAgc2V0VGFnKHRhZzogc3RyaW5nKTogTW9uZXJvQWNjb3VudFRhZyB7XG4gICAgdGhpcy50YWcgPSB0YWc7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldExhYmVsKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMubGFiZWw7XG4gIH1cbiAgXG4gIHNldExhYmVsKGxhYmVsOiBzdHJpbmcpOiBNb25lcm9BY2NvdW50VGFnIHtcbiAgICB0aGlzLmxhYmVsID0gbGFiZWw7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEFjY291bnRJbmRpY2VzKCk6IG51bWJlcltdIHtcbiAgICByZXR1cm4gdGhpcy5hY2NvdW50SW5kaWNlcztcbiAgfVxuICBcbiAgc2V0QWNjb3VudEluZGljZXMoYWNjb3VudEluZGljZXM6IG51bWJlcltdKTogTW9uZXJvQWNjb3VudFRhZyB7XG4gICAgdGhpcy5hY2NvdW50SW5kaWNlcyA9IGFjY291bnRJbmRpY2VzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJxR0FBQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSxnQkFBZ0IsQ0FBQzs7Ozs7O0VBTXBDQyxXQUFXQSxDQUFDQyxVQUFzQyxFQUFFO0lBQ2xEQyxNQUFNLENBQUNDLE1BQU0sQ0FBQyxJQUFJLEVBQUVGLFVBQVUsQ0FBQztFQUNqQzs7RUFFQUcsTUFBTUEsQ0FBQSxFQUFXO0lBQ2YsT0FBTyxJQUFJLENBQUNDLEdBQUc7RUFDakI7O0VBRUFDLE1BQU1BLENBQUNELEdBQVcsRUFBb0I7SUFDcEMsSUFBSSxDQUFDQSxHQUFHLEdBQUdBLEdBQUc7SUFDZCxPQUFPLElBQUk7RUFDYjs7RUFFQUUsUUFBUUEsQ0FBQSxFQUFXO0lBQ2pCLE9BQU8sSUFBSSxDQUFDQyxLQUFLO0VBQ25COztFQUVBQyxRQUFRQSxDQUFDRCxLQUFhLEVBQW9CO0lBQ3hDLElBQUksQ0FBQ0EsS0FBSyxHQUFHQSxLQUFLO0lBQ2xCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxpQkFBaUJBLENBQUEsRUFBYTtJQUM1QixPQUFPLElBQUksQ0FBQ0MsY0FBYztFQUM1Qjs7RUFFQUMsaUJBQWlCQSxDQUFDRCxjQUF3QixFQUFvQjtJQUM1RCxJQUFJLENBQUNBLGNBQWMsR0FBR0EsY0FBYztJQUNwQyxPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNFLE9BQUEsQ0FBQUMsT0FBQSxHQUFBZixnQkFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroAddressBookEntry.d.ts b/dist/src/main/ts/wallet/model/MoneroAddressBookEntry.d.ts new file mode 100644 index 000000000..10dcc47a7 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroAddressBookEntry.d.ts @@ -0,0 +1,19 @@ +/** + * Monero address book entry model + */ +export default class MoneroAddressBookEntry { + index: number; + address: string; + description: string; + paymentId: string; + constructor(entry?: Partial); + toJson(): any; + getIndex(): number; + setIndex(index: number): MoneroAddressBookEntry; + getAddress(): string; + setAddress(address: string): MoneroAddressBookEntry; + getDescription(): string; + setDescription(description: string): MoneroAddressBookEntry; + getPaymentId(): string; + setPaymentId(paymentId: string): MoneroAddressBookEntry; +} diff --git a/dist/src/main/ts/wallet/model/MoneroAddressBookEntry.js b/dist/src/main/ts/wallet/model/MoneroAddressBookEntry.js new file mode 100644 index 000000000..c030d38b9 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroAddressBookEntry.js @@ -0,0 +1,55 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Monero address book entry model + */ +class MoneroAddressBookEntry { + + + + + + + constructor(entry) { + Object.assign(this, entry); + } + + toJson() { + return Object.assign({}, this); + } + + getIndex() { + return this.index; + } + + setIndex(index) { + this.index = index; + return this; + } + + getAddress() { + return this.address; + } + + setAddress(address) { + this.address = address; + return this; + } + + getDescription() { + return this.description; + } + + setDescription(description) { + this.description = description; + return this; + } + + getPaymentId() { + return this.paymentId; + } + + setPaymentId(paymentId) { + this.paymentId = paymentId; + return this; + } +}exports.default = MoneroAddressBookEntry; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9BZGRyZXNzQm9va0VudHJ5IiwiY29uc3RydWN0b3IiLCJlbnRyeSIsIk9iamVjdCIsImFzc2lnbiIsInRvSnNvbiIsImdldEluZGV4IiwiaW5kZXgiLCJzZXRJbmRleCIsImdldEFkZHJlc3MiLCJhZGRyZXNzIiwic2V0QWRkcmVzcyIsImdldERlc2NyaXB0aW9uIiwiZGVzY3JpcHRpb24iLCJzZXREZXNjcmlwdGlvbiIsImdldFBheW1lbnRJZCIsInBheW1lbnRJZCIsInNldFBheW1lbnRJZCIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvd2FsbGV0L21vZGVsL01vbmVyb0FkZHJlc3NCb29rRW50cnkudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBNb25lcm8gYWRkcmVzcyBib29rIGVudHJ5IG1vZGVsXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0FkZHJlc3NCb29rRW50cnkge1xuXG4gIGluZGV4OiBudW1iZXI7XG4gIGFkZHJlc3M6IHN0cmluZztcbiAgZGVzY3JpcHRpb246IHN0cmluZztcbiAgcGF5bWVudElkOiBzdHJpbmc7XG4gIFxuICBjb25zdHJ1Y3RvcihlbnRyeT86IFBhcnRpYWw8TW9uZXJvQWRkcmVzc0Jvb2tFbnRyeT4pIHtcbiAgICBPYmplY3QuYXNzaWduKHRoaXMsIGVudHJ5KTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICB9XG4gIFxuICBnZXRJbmRleCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmluZGV4O1xuICB9XG4gIFxuICBzZXRJbmRleChpbmRleDogbnVtYmVyKTogTW9uZXJvQWRkcmVzc0Jvb2tFbnRyeSB7XG4gICAgdGhpcy5pbmRleCA9IGluZGV4O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRBZGRyZXNzKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuYWRkcmVzcztcbiAgfVxuICBcbiAgc2V0QWRkcmVzcyhhZGRyZXNzOiBzdHJpbmcpOiBNb25lcm9BZGRyZXNzQm9va0VudHJ5IHtcbiAgICB0aGlzLmFkZHJlc3MgPSBhZGRyZXNzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXREZXNjcmlwdGlvbigpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmRlc2NyaXB0aW9uO1xuICB9XG4gIFxuICBzZXREZXNjcmlwdGlvbihkZXNjcmlwdGlvbjogc3RyaW5nKTogTW9uZXJvQWRkcmVzc0Jvb2tFbnRyeSB7XG4gICAgdGhpcy5kZXNjcmlwdGlvbiA9IGRlc2NyaXB0aW9uO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRQYXltZW50SWQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5wYXltZW50SWQ7XG4gIH1cbiAgXG4gIHNldFBheW1lbnRJZChwYXltZW50SWQ6IHN0cmluZyk6IE1vbmVyb0FkZHJlc3NCb29rRW50cnkge1xuICAgIHRoaXMucGF5bWVudElkID0gcGF5bWVudElkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJxR0FBQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSxzQkFBc0IsQ0FBQzs7Ozs7OztFQU8xQ0MsV0FBV0EsQ0FBQ0MsS0FBdUMsRUFBRTtJQUNuREMsTUFBTSxDQUFDQyxNQUFNLENBQUMsSUFBSSxFQUFFRixLQUFLLENBQUM7RUFDNUI7O0VBRUFHLE1BQU1BLENBQUEsRUFBUTtJQUNaLE9BQU9GLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQztFQUNoQzs7RUFFQUUsUUFBUUEsQ0FBQSxFQUFXO0lBQ2pCLE9BQU8sSUFBSSxDQUFDQyxLQUFLO0VBQ25COztFQUVBQyxRQUFRQSxDQUFDRCxLQUFhLEVBQTBCO0lBQzlDLElBQUksQ0FBQ0EsS0FBSyxHQUFHQSxLQUFLO0lBQ2xCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxVQUFVQSxDQUFBLEVBQVc7SUFDbkIsT0FBTyxJQUFJLENBQUNDLE9BQU87RUFDckI7O0VBRUFDLFVBQVVBLENBQUNELE9BQWUsRUFBMEI7SUFDbEQsSUFBSSxDQUFDQSxPQUFPLEdBQUdBLE9BQU87SUFDdEIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLGNBQWNBLENBQUEsRUFBVztJQUN2QixPQUFPLElBQUksQ0FBQ0MsV0FBVztFQUN6Qjs7RUFFQUMsY0FBY0EsQ0FBQ0QsV0FBbUIsRUFBMEI7SUFDMUQsSUFBSSxDQUFDQSxXQUFXLEdBQUdBLFdBQVc7SUFDOUIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLFlBQVlBLENBQUEsRUFBVztJQUNyQixPQUFPLElBQUksQ0FBQ0MsU0FBUztFQUN2Qjs7RUFFQUMsWUFBWUEsQ0FBQ0QsU0FBaUIsRUFBMEI7SUFDdEQsSUFBSSxDQUFDQSxTQUFTLEdBQUdBLFNBQVM7SUFDMUIsT0FBTyxJQUFJO0VBQ2I7QUFDRixDQUFDRSxPQUFBLENBQUFDLE9BQUEsR0FBQW5CLHNCQUFBIn0= \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroCheck.d.ts b/dist/src/main/ts/wallet/model/MoneroCheck.d.ts new file mode 100644 index 000000000..b9213577c --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroCheck.d.ts @@ -0,0 +1,9 @@ +/** + * Base class for results from checking a transaction or reserve proof. + */ +export default class MoneroCheck { + isGood?: boolean; + constructor(check?: Partial); + getIsGood(): boolean; + setIsGood(isGood: boolean): MoneroCheck; +} diff --git a/dist/src/main/ts/wallet/model/MoneroCheck.js b/dist/src/main/ts/wallet/model/MoneroCheck.js new file mode 100644 index 000000000..0ec9c9918 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroCheck.js @@ -0,0 +1,21 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Base class for results from checking a transaction or reserve proof. + */ +class MoneroCheck { + + + + constructor(check) { + Object.assign(this, check); + } + + getIsGood() { + return this.isGood; + } + + setIsGood(isGood) { + this.isGood = isGood; + return this; + } +}exports.default = MoneroCheck; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9DaGVjayIsImNvbnN0cnVjdG9yIiwiY2hlY2siLCJPYmplY3QiLCJhc3NpZ24iLCJnZXRJc0dvb2QiLCJpc0dvb2QiLCJzZXRJc0dvb2QiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9DaGVjay50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEJhc2UgY2xhc3MgZm9yIHJlc3VsdHMgZnJvbSBjaGVja2luZyBhIHRyYW5zYWN0aW9uIG9yIHJlc2VydmUgcHJvb2YuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0NoZWNrIHtcblxuICBpc0dvb2Q/OiBib29sZWFuO1xuICBcbiAgY29uc3RydWN0b3IoY2hlY2s/OiBQYXJ0aWFsPE1vbmVyb0NoZWNrPikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgY2hlY2spO1xuICB9XG5cbiAgZ2V0SXNHb29kKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzR29vZDtcbiAgfVxuXG4gIHNldElzR29vZChpc0dvb2Q6IGJvb2xlYW4pOiBNb25lcm9DaGVjayB7XG4gICAgdGhpcy5pc0dvb2QgPSBpc0dvb2Q7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InFHQUFBO0FBQ0E7QUFDQTtBQUNlLE1BQU1BLFdBQVcsQ0FBQzs7OztFQUkvQkMsV0FBV0EsQ0FBQ0MsS0FBNEIsRUFBRTtJQUN4Q0MsTUFBTSxDQUFDQyxNQUFNLENBQUMsSUFBSSxFQUFFRixLQUFLLENBQUM7RUFDNUI7O0VBRUFHLFNBQVNBLENBQUEsRUFBWTtJQUNuQixPQUFPLElBQUksQ0FBQ0MsTUFBTTtFQUNwQjs7RUFFQUMsU0FBU0EsQ0FBQ0QsTUFBZSxFQUFlO0lBQ3RDLElBQUksQ0FBQ0EsTUFBTSxHQUFHQSxNQUFNO0lBQ3BCLE9BQU8sSUFBSTtFQUNiO0FBQ0YsQ0FBQ0UsT0FBQSxDQUFBQyxPQUFBLEdBQUFULFdBQUEifQ== \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroCheckReserve.d.ts b/dist/src/main/ts/wallet/model/MoneroCheckReserve.d.ts new file mode 100644 index 000000000..9e5d333fe --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroCheckReserve.d.ts @@ -0,0 +1,14 @@ +import MoneroCheck from "./MoneroCheck"; +/** + * Results from checking a reserve proof. + */ +export default class MoneroCheckReserve extends MoneroCheck { + totalAmount: bigint; + unconfirmedSpentAmount: bigint; + constructor(check?: Partial); + toJson(): any; + getTotalAmount(): bigint; + setTotalAmount(totalAmount: bigint): MoneroCheckReserve; + getUnconfirmedSpentAmount(): bigint; + setUnconfirmedSpentAmount(unconfirmedSpentAmount: bigint): MoneroCheckReserve; +} diff --git a/dist/src/main/ts/wallet/model/MoneroCheckReserve.js b/dist/src/main/ts/wallet/model/MoneroCheckReserve.js new file mode 100644 index 000000000..8c1068e0b --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroCheckReserve.js @@ -0,0 +1,42 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _MoneroCheck = _interopRequireDefault(require("./MoneroCheck")); + +/** + * Results from checking a reserve proof. + */ +class MoneroCheckReserve extends _MoneroCheck.default { + + + + + constructor(check) { + super(check); + if (this.totalAmount !== undefined && typeof this.totalAmount !== "bigint") this.totalAmount = BigInt(this.totalAmount); + if (this.unconfirmedSpentAmount !== undefined && typeof this.unconfirmedSpentAmount !== "bigint") this.unconfirmedSpentAmount = BigInt(this.unconfirmedSpentAmount); + } + + toJson() { + let json = Object.assign({}, this); + if (this.getTotalAmount() !== undefined) json.totalAmount = this.getTotalAmount().toString(); + if (this.getUnconfirmedSpentAmount() !== undefined) json.unconfirmedSpentAmount = this.getUnconfirmedSpentAmount().toString(); + return json; + } + + getTotalAmount() { + return this.totalAmount; + } + + setTotalAmount(totalAmount) { + this.totalAmount = totalAmount; + return this; + } + + getUnconfirmedSpentAmount() { + return this.unconfirmedSpentAmount; + } + + setUnconfirmedSpentAmount(unconfirmedSpentAmount) { + this.unconfirmedSpentAmount = unconfirmedSpentAmount; + return this; + } +}exports.default = MoneroCheckReserve; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfTW9uZXJvQ2hlY2siLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIk1vbmVyb0NoZWNrUmVzZXJ2ZSIsIk1vbmVyb0NoZWNrIiwiY29uc3RydWN0b3IiLCJjaGVjayIsInRvdGFsQW1vdW50IiwidW5kZWZpbmVkIiwiQmlnSW50IiwidW5jb25maXJtZWRTcGVudEFtb3VudCIsInRvSnNvbiIsImpzb24iLCJPYmplY3QiLCJhc3NpZ24iLCJnZXRUb3RhbEFtb3VudCIsInRvU3RyaW5nIiwiZ2V0VW5jb25maXJtZWRTcGVudEFtb3VudCIsInNldFRvdGFsQW1vdW50Iiwic2V0VW5jb25maXJtZWRTcGVudEFtb3VudCIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvd2FsbGV0L21vZGVsL01vbmVyb0NoZWNrUmVzZXJ2ZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgTW9uZXJvQ2hlY2sgZnJvbSBcIi4vTW9uZXJvQ2hlY2tcIjtcblxuLyoqXG4gKiBSZXN1bHRzIGZyb20gY2hlY2tpbmcgYSByZXNlcnZlIHByb29mLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9DaGVja1Jlc2VydmUgZXh0ZW5kcyBNb25lcm9DaGVjayB7XG4gIFxuICB0b3RhbEFtb3VudDogYmlnaW50O1xuICB1bmNvbmZpcm1lZFNwZW50QW1vdW50OiBiaWdpbnQ7XG4gIFxuICBjb25zdHJ1Y3RvcihjaGVjaz86IFBhcnRpYWw8TW9uZXJvQ2hlY2tSZXNlcnZlPikge1xuICAgIHN1cGVyKGNoZWNrKTtcbiAgICBpZiAodGhpcy50b3RhbEFtb3VudCAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLnRvdGFsQW1vdW50ICE9PSBcImJpZ2ludFwiKSB0aGlzLnRvdGFsQW1vdW50ID0gQmlnSW50KHRoaXMudG90YWxBbW91bnQpO1xuICAgIGlmICh0aGlzLnVuY29uZmlybWVkU3BlbnRBbW91bnQgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy51bmNvbmZpcm1lZFNwZW50QW1vdW50ICE9PSBcImJpZ2ludFwiKSB0aGlzLnVuY29uZmlybWVkU3BlbnRBbW91bnQgPSBCaWdJbnQodGhpcy51bmNvbmZpcm1lZFNwZW50QW1vdW50KTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgbGV0IGpzb246IGFueSA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICAgIGlmICh0aGlzLmdldFRvdGFsQW1vdW50KCkgIT09IHVuZGVmaW5lZCkganNvbi50b3RhbEFtb3VudCA9IHRoaXMuZ2V0VG90YWxBbW91bnQoKS50b1N0cmluZygpO1xuICAgIGlmICh0aGlzLmdldFVuY29uZmlybWVkU3BlbnRBbW91bnQoKSAhPT0gdW5kZWZpbmVkKSBqc29uLnVuY29uZmlybWVkU3BlbnRBbW91bnQgPSB0aGlzLmdldFVuY29uZmlybWVkU3BlbnRBbW91bnQoKS50b1N0cmluZygpO1xuICAgIHJldHVybiBqc29uO1xuICB9XG4gIFxuICBnZXRUb3RhbEFtb3VudCgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLnRvdGFsQW1vdW50O1xuICB9XG5cbiAgc2V0VG90YWxBbW91bnQodG90YWxBbW91bnQ6IGJpZ2ludCk6IE1vbmVyb0NoZWNrUmVzZXJ2ZSB7XG4gICAgdGhpcy50b3RhbEFtb3VudCA9IHRvdGFsQW1vdW50O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRVbmNvbmZpcm1lZFNwZW50QW1vdW50KCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMudW5jb25maXJtZWRTcGVudEFtb3VudDtcbiAgfVxuXG4gIHNldFVuY29uZmlybWVkU3BlbnRBbW91bnQodW5jb25maXJtZWRTcGVudEFtb3VudDogYmlnaW50KTogTW9uZXJvQ2hlY2tSZXNlcnZlIHtcbiAgICB0aGlzLnVuY29uZmlybWVkU3BlbnRBbW91bnQgPSB1bmNvbmZpcm1lZFNwZW50QW1vdW50O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59Il0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsWUFBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBOztBQUVBO0FBQ0E7QUFDQTtBQUNlLE1BQU1DLGtCQUFrQixTQUFTQyxvQkFBVyxDQUFDOzs7OztFQUsxREMsV0FBV0EsQ0FBQ0MsS0FBbUMsRUFBRTtJQUMvQyxLQUFLLENBQUNBLEtBQUssQ0FBQztJQUNaLElBQUksSUFBSSxDQUFDQyxXQUFXLEtBQUtDLFNBQVMsSUFBSSxPQUFPLElBQUksQ0FBQ0QsV0FBVyxLQUFLLFFBQVEsRUFBRSxJQUFJLENBQUNBLFdBQVcsR0FBR0UsTUFBTSxDQUFDLElBQUksQ0FBQ0YsV0FBVyxDQUFDO0lBQ3ZILElBQUksSUFBSSxDQUFDRyxzQkFBc0IsS0FBS0YsU0FBUyxJQUFJLE9BQU8sSUFBSSxDQUFDRSxzQkFBc0IsS0FBSyxRQUFRLEVBQUUsSUFBSSxDQUFDQSxzQkFBc0IsR0FBR0QsTUFBTSxDQUFDLElBQUksQ0FBQ0Msc0JBQXNCLENBQUM7RUFDcks7O0VBRUFDLE1BQU1BLENBQUEsRUFBUTtJQUNaLElBQUlDLElBQVMsR0FBR0MsTUFBTSxDQUFDQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQ3ZDLElBQUksSUFBSSxDQUFDQyxjQUFjLENBQUMsQ0FBQyxLQUFLUCxTQUFTLEVBQUVJLElBQUksQ0FBQ0wsV0FBVyxHQUFHLElBQUksQ0FBQ1EsY0FBYyxDQUFDLENBQUMsQ0FBQ0MsUUFBUSxDQUFDLENBQUM7SUFDNUYsSUFBSSxJQUFJLENBQUNDLHlCQUF5QixDQUFDLENBQUMsS0FBS1QsU0FBUyxFQUFFSSxJQUFJLENBQUNGLHNCQUFzQixHQUFHLElBQUksQ0FBQ08seUJBQXlCLENBQUMsQ0FBQyxDQUFDRCxRQUFRLENBQUMsQ0FBQztJQUM3SCxPQUFPSixJQUFJO0VBQ2I7O0VBRUFHLGNBQWNBLENBQUEsRUFBVztJQUN2QixPQUFPLElBQUksQ0FBQ1IsV0FBVztFQUN6Qjs7RUFFQVcsY0FBY0EsQ0FBQ1gsV0FBbUIsRUFBc0I7SUFDdEQsSUFBSSxDQUFDQSxXQUFXLEdBQUdBLFdBQVc7SUFDOUIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFVLHlCQUF5QkEsQ0FBQSxFQUFXO0lBQ2xDLE9BQU8sSUFBSSxDQUFDUCxzQkFBc0I7RUFDcEM7O0VBRUFTLHlCQUF5QkEsQ0FBQ1Qsc0JBQThCLEVBQXNCO0lBQzVFLElBQUksQ0FBQ0Esc0JBQXNCLEdBQUdBLHNCQUFzQjtJQUNwRCxPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNVLE9BQUEsQ0FBQUMsT0FBQSxHQUFBbEIsa0JBQUEifQ== \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroCheckTx.d.ts b/dist/src/main/ts/wallet/model/MoneroCheckTx.d.ts new file mode 100644 index 000000000..9db5319b7 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroCheckTx.d.ts @@ -0,0 +1,17 @@ +import MoneroCheck from "./MoneroCheck"; +/** + * Results from checking a transaction key. + */ +export default class MoneroCheckTx extends MoneroCheck { + inTxPool: boolean; + numConfirmations: number; + receivedAmount: bigint; + constructor(check?: Partial); + toJson(): any; + getInTxPool(): boolean; + setInTxPool(inTxPool: boolean): MoneroCheckTx; + getNumConfirmations(): number; + setNumConfirmations(numConfirmations: number): MoneroCheckTx; + getReceivedAmount(): bigint; + setReceivedAmount(receivedAmount: bigint): MoneroCheckTx; +} diff --git a/dist/src/main/ts/wallet/model/MoneroCheckTx.js b/dist/src/main/ts/wallet/model/MoneroCheckTx.js new file mode 100644 index 000000000..970275198 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroCheckTx.js @@ -0,0 +1,50 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _MoneroCheck = _interopRequireDefault(require("./MoneroCheck")); + +/** + * Results from checking a transaction key. + */ +class MoneroCheckTx extends _MoneroCheck.default { + + + + + + constructor(check) { + super(check); + if (this.receivedAmount !== undefined && typeof this.receivedAmount !== "bigint") this.receivedAmount = BigInt(this.receivedAmount); + } + + toJson() { + let json = Object.assign({}, this); + if (this.getReceivedAmount() !== undefined) json.receivedAmount = this.getReceivedAmount().toString(); + return json; + } + + getInTxPool() { + return this.inTxPool; + } + + setInTxPool(inTxPool) { + this.inTxPool = inTxPool; + return this; + } + + getNumConfirmations() { + return this.numConfirmations; + } + + setNumConfirmations(numConfirmations) { + this.numConfirmations = numConfirmations; + return this; + } + + getReceivedAmount() { + return this.receivedAmount; + } + + setReceivedAmount(receivedAmount) { + this.receivedAmount = receivedAmount; + return this; + } +}exports.default = MoneroCheckTx; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfTW9uZXJvQ2hlY2siLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIk1vbmVyb0NoZWNrVHgiLCJNb25lcm9DaGVjayIsImNvbnN0cnVjdG9yIiwiY2hlY2siLCJyZWNlaXZlZEFtb3VudCIsInVuZGVmaW5lZCIsIkJpZ0ludCIsInRvSnNvbiIsImpzb24iLCJPYmplY3QiLCJhc3NpZ24iLCJnZXRSZWNlaXZlZEFtb3VudCIsInRvU3RyaW5nIiwiZ2V0SW5UeFBvb2wiLCJpblR4UG9vbCIsInNldEluVHhQb29sIiwiZ2V0TnVtQ29uZmlybWF0aW9ucyIsIm51bUNvbmZpcm1hdGlvbnMiLCJzZXROdW1Db25maXJtYXRpb25zIiwic2V0UmVjZWl2ZWRBbW91bnQiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9DaGVja1R4LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBNb25lcm9DaGVjayBmcm9tIFwiLi9Nb25lcm9DaGVja1wiO1xuXG4vKipcbiAqIFJlc3VsdHMgZnJvbSBjaGVja2luZyBhIHRyYW5zYWN0aW9uIGtleS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTW9uZXJvQ2hlY2tUeCBleHRlbmRzIE1vbmVyb0NoZWNrIHtcblxuICBpblR4UG9vbDogYm9vbGVhbjtcbiAgbnVtQ29uZmlybWF0aW9uczogbnVtYmVyO1xuICByZWNlaXZlZEFtb3VudDogYmlnaW50O1xuICBcbiAgY29uc3RydWN0b3IoY2hlY2s/OiBQYXJ0aWFsPE1vbmVyb0NoZWNrVHg+KSB7XG4gICAgc3VwZXIoY2hlY2spO1xuICAgIGlmICh0aGlzLnJlY2VpdmVkQW1vdW50ICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHRoaXMucmVjZWl2ZWRBbW91bnQgIT09IFwiYmlnaW50XCIpIHRoaXMucmVjZWl2ZWRBbW91bnQgPSBCaWdJbnQodGhpcy5yZWNlaXZlZEFtb3VudCk7XG4gIH1cbiAgXG4gIHRvSnNvbigpOiBhbnkge1xuICAgIGxldCBqc29uOiBhbnkgPSBPYmplY3QuYXNzaWduKHt9LCB0aGlzKTtcbiAgICBpZiAodGhpcy5nZXRSZWNlaXZlZEFtb3VudCgpICE9PSB1bmRlZmluZWQpIGpzb24ucmVjZWl2ZWRBbW91bnQgPSB0aGlzLmdldFJlY2VpdmVkQW1vdW50KCkudG9TdHJpbmcoKTtcbiAgICByZXR1cm4ganNvbjtcbiAgfVxuXG4gIGdldEluVHhQb29sKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmluVHhQb29sO1xuICB9XG4gIFxuICBzZXRJblR4UG9vbChpblR4UG9vbDogYm9vbGVhbik6IE1vbmVyb0NoZWNrVHgge1xuICAgIHRoaXMuaW5UeFBvb2wgPSBpblR4UG9vbDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0TnVtQ29uZmlybWF0aW9ucygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLm51bUNvbmZpcm1hdGlvbnM7XG4gIH1cbiAgXG4gIHNldE51bUNvbmZpcm1hdGlvbnMobnVtQ29uZmlybWF0aW9uczogbnVtYmVyKTogTW9uZXJvQ2hlY2tUeCB7XG4gICAgdGhpcy5udW1Db25maXJtYXRpb25zID0gbnVtQ29uZmlybWF0aW9ucztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0UmVjZWl2ZWRBbW91bnQoKTogYmlnaW50IHtcbiAgICByZXR1cm4gdGhpcy5yZWNlaXZlZEFtb3VudDtcbiAgfVxuICBcbiAgc2V0UmVjZWl2ZWRBbW91bnQocmVjZWl2ZWRBbW91bnQ6IGJpZ2ludCk6IE1vbmVyb0NoZWNrVHgge1xuICAgIHRoaXMucmVjZWl2ZWRBbW91bnQgPSByZWNlaXZlZEFtb3VudDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsWUFBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBOztBQUVBO0FBQ0E7QUFDQTtBQUNlLE1BQU1DLGFBQWEsU0FBU0Msb0JBQVcsQ0FBQzs7Ozs7O0VBTXJEQyxXQUFXQSxDQUFDQyxLQUE4QixFQUFFO0lBQzFDLEtBQUssQ0FBQ0EsS0FBSyxDQUFDO0lBQ1osSUFBSSxJQUFJLENBQUNDLGNBQWMsS0FBS0MsU0FBUyxJQUFJLE9BQU8sSUFBSSxDQUFDRCxjQUFjLEtBQUssUUFBUSxFQUFFLElBQUksQ0FBQ0EsY0FBYyxHQUFHRSxNQUFNLENBQUMsSUFBSSxDQUFDRixjQUFjLENBQUM7RUFDckk7O0VBRUFHLE1BQU1BLENBQUEsRUFBUTtJQUNaLElBQUlDLElBQVMsR0FBR0MsTUFBTSxDQUFDQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQ3ZDLElBQUksSUFBSSxDQUFDQyxpQkFBaUIsQ0FBQyxDQUFDLEtBQUtOLFNBQVMsRUFBRUcsSUFBSSxDQUFDSixjQUFjLEdBQUcsSUFBSSxDQUFDTyxpQkFBaUIsQ0FBQyxDQUFDLENBQUNDLFFBQVEsQ0FBQyxDQUFDO0lBQ3JHLE9BQU9KLElBQUk7RUFDYjs7RUFFQUssV0FBV0EsQ0FBQSxFQUFZO0lBQ3JCLE9BQU8sSUFBSSxDQUFDQyxRQUFRO0VBQ3RCOztFQUVBQyxXQUFXQSxDQUFDRCxRQUFpQixFQUFpQjtJQUM1QyxJQUFJLENBQUNBLFFBQVEsR0FBR0EsUUFBUTtJQUN4QixPQUFPLElBQUk7RUFDYjs7RUFFQUUsbUJBQW1CQSxDQUFBLEVBQVc7SUFDNUIsT0FBTyxJQUFJLENBQUNDLGdCQUFnQjtFQUM5Qjs7RUFFQUMsbUJBQW1CQSxDQUFDRCxnQkFBd0IsRUFBaUI7SUFDM0QsSUFBSSxDQUFDQSxnQkFBZ0IsR0FBR0EsZ0JBQWdCO0lBQ3hDLE9BQU8sSUFBSTtFQUNiOztFQUVBTixpQkFBaUJBLENBQUEsRUFBVztJQUMxQixPQUFPLElBQUksQ0FBQ1AsY0FBYztFQUM1Qjs7RUFFQWUsaUJBQWlCQSxDQUFDZixjQUFzQixFQUFpQjtJQUN2RCxJQUFJLENBQUNBLGNBQWMsR0FBR0EsY0FBYztJQUNwQyxPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNnQixPQUFBLENBQUFDLE9BQUEsR0FBQXJCLGFBQUEifQ== \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroDestination.d.ts b/dist/src/main/ts/wallet/model/MoneroDestination.d.ts new file mode 100644 index 000000000..15c6125a1 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroDestination.d.ts @@ -0,0 +1,23 @@ +/** + * Models an outgoing transfer destination. + */ +export default class MoneroDestination { + /** Destination address to send funds to. */ + address: string; + /** Amount to send to destination address. */ + amount: bigint; + /** + * Construct a destination to send funds to. + * + * @param {Partial|string} destinationOrAddress is a MoneroDestination or hex string to initialize from (optional) + * @param {bigint} [amount] - the destination amount + */ + constructor(destinationOrAddress?: Partial | string, amount?: bigint); + getAddress(): string; + setAddress(address: string | undefined): MoneroDestination; + getAmount(): bigint; + setAmount(amount: bigint): MoneroDestination; + copy(): MoneroDestination; + toJson(): any; + toString(indent?: number): string; +} diff --git a/dist/src/main/ts/wallet/model/MoneroDestination.js b/dist/src/main/ts/wallet/model/MoneroDestination.js new file mode 100644 index 000000000..6818bafda --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroDestination.js @@ -0,0 +1,71 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); +var _MoneroError = _interopRequireDefault(require("../../common/MoneroError")); + +/** + * Models an outgoing transfer destination. + */ +class MoneroDestination { + + /** Destination address to send funds to. */ + + + /** Amount to send to destination address. */ + + + /** + * Construct a destination to send funds to. + * + * @param {Partial|string} destinationOrAddress is a MoneroDestination or hex string to initialize from (optional) + * @param {bigint} [amount] - the destination amount + */ + constructor(destinationOrAddress, amount) { + if (typeof destinationOrAddress === "string") { + this.setAddress(destinationOrAddress); + this.setAmount(amount); + } else { + if (amount !== undefined) throw new Error("Amount parameter must be undefined when initializing a MoneroDestination from a MoneroDestination"); + Object.assign(this, destinationOrAddress); + if (this.amount && typeof this.amount !== "bigint") this.amount = BigInt(this.amount); + } + } + + getAddress() { + return this.address; + } + + setAddress(address) { + this.address = address; + return this; + } + + getAmount() { + return this.amount; + } + + setAmount(amount) { + if (amount !== undefined && typeof amount !== "bigint") { + if (typeof amount === "number") throw new _MoneroError.default("Destination amount must be BigInt or string"); + try {amount = BigInt(amount);} + catch (err) {throw new _MoneroError.default("Invalid destination amount: " + amount);} + } + this.amount = amount; + return this; + } + + copy() { + return new MoneroDestination(this); + } + + toJson() { + let json = Object.assign({}, this); + if (this.getAmount() !== undefined) json.amount = this.getAmount().toString(); + return json; + } + + toString(indent = 0) { + let str = _GenUtils.default.kvLine("Address", this.getAddress(), indent); + str += _GenUtils.default.kvLine("Amount", this.getAmount() ? this.getAmount().toString() : undefined, indent); + return str.slice(0, str.length - 1); // strip last newline + } +}exports.default = MoneroDestination; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfR2VuVXRpbHMiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9Nb25lcm9FcnJvciIsIk1vbmVyb0Rlc3RpbmF0aW9uIiwiY29uc3RydWN0b3IiLCJkZXN0aW5hdGlvbk9yQWRkcmVzcyIsImFtb3VudCIsInNldEFkZHJlc3MiLCJzZXRBbW91bnQiLCJ1bmRlZmluZWQiLCJFcnJvciIsIk9iamVjdCIsImFzc2lnbiIsIkJpZ0ludCIsImdldEFkZHJlc3MiLCJhZGRyZXNzIiwiZ2V0QW1vdW50IiwiTW9uZXJvRXJyb3IiLCJlcnIiLCJjb3B5IiwidG9Kc29uIiwianNvbiIsInRvU3RyaW5nIiwiaW5kZW50Iiwic3RyIiwiR2VuVXRpbHMiLCJrdkxpbmUiLCJzbGljZSIsImxlbmd0aCIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvd2FsbGV0L21vZGVsL01vbmVyb0Rlc3RpbmF0aW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi4vLi4vY29tbW9uL0dlblV0aWxzXCI7XG5pbXBvcnQgTW9uZXJvRXJyb3IgZnJvbSBcIi4uLy4uL2NvbW1vbi9Nb25lcm9FcnJvclwiO1xuXG4vKipcbiAqIE1vZGVscyBhbiBvdXRnb2luZyB0cmFuc2ZlciBkZXN0aW5hdGlvbi5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTW9uZXJvRGVzdGluYXRpb24ge1xuXG4gIC8qKiBEZXN0aW5hdGlvbiBhZGRyZXNzIHRvIHNlbmQgZnVuZHMgdG8uICovXG4gIGFkZHJlc3M6IHN0cmluZztcblxuICAvKiogQW1vdW50IHRvIHNlbmQgdG8gZGVzdGluYXRpb24gYWRkcmVzcy4gKi9cbiAgYW1vdW50OiBiaWdpbnQ7XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdCBhIGRlc3RpbmF0aW9uIHRvIHNlbmQgZnVuZHMgdG8uXG4gICAqIFxuICAgKiBAcGFyYW0ge1BhcnRpYWw8TW9uZXJvRGVzdGluYXRpb24+fHN0cmluZ30gZGVzdGluYXRpb25PckFkZHJlc3MgaXMgYSBNb25lcm9EZXN0aW5hdGlvbiBvciBoZXggc3RyaW5nIHRvIGluaXRpYWxpemUgZnJvbSAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7YmlnaW50fSBbYW1vdW50XSAtIHRoZSBkZXN0aW5hdGlvbiBhbW91bnRcbiAgICovXG4gIGNvbnN0cnVjdG9yKGRlc3RpbmF0aW9uT3JBZGRyZXNzPzogUGFydGlhbDxNb25lcm9EZXN0aW5hdGlvbj4gfCBzdHJpbmcsIGFtb3VudD86IGJpZ2ludCkge1xuICAgIGlmICh0eXBlb2YgZGVzdGluYXRpb25PckFkZHJlc3MgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgIHRoaXMuc2V0QWRkcmVzcyhkZXN0aW5hdGlvbk9yQWRkcmVzcyk7XG4gICAgICB0aGlzLnNldEFtb3VudChhbW91bnQpO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoYW1vdW50ICE9PSB1bmRlZmluZWQpIHRocm93IG5ldyBFcnJvcihcIkFtb3VudCBwYXJhbWV0ZXIgbXVzdCBiZSB1bmRlZmluZWQgd2hlbiBpbml0aWFsaXppbmcgYSBNb25lcm9EZXN0aW5hdGlvbiBmcm9tIGEgTW9uZXJvRGVzdGluYXRpb25cIilcbiAgICAgIE9iamVjdC5hc3NpZ24odGhpcywgZGVzdGluYXRpb25PckFkZHJlc3MpO1xuICAgICAgaWYgKHRoaXMuYW1vdW50ICYmIHR5cGVvZiB0aGlzLmFtb3VudCAhPT0gXCJiaWdpbnRcIikgdGhpcy5hbW91bnQgPSBCaWdJbnQodGhpcy5hbW91bnQpO1xuICAgIH1cbiAgfVxuICBcbiAgZ2V0QWRkcmVzcygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmFkZHJlc3M7XG4gIH1cblxuICBzZXRBZGRyZXNzKGFkZHJlc3M6IHN0cmluZyB8IHVuZGVmaW5lZCk6IE1vbmVyb0Rlc3RpbmF0aW9uIHtcbiAgICB0aGlzLmFkZHJlc3MgPSBhZGRyZXNzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRBbW91bnQoKTogYmlnaW50IHtcbiAgICByZXR1cm4gdGhpcy5hbW91bnQ7XG4gIH1cblxuICBzZXRBbW91bnQoYW1vdW50OiBiaWdpbnQpOiBNb25lcm9EZXN0aW5hdGlvbiB7XG4gICAgaWYgKGFtb3VudCAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiBhbW91bnQgIT09IFwiYmlnaW50XCIpIHtcbiAgICAgIGlmICh0eXBlb2YgYW1vdW50ID09PSBcIm51bWJlclwiKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJEZXN0aW5hdGlvbiBhbW91bnQgbXVzdCBiZSBCaWdJbnQgb3Igc3RyaW5nXCIpO1xuICAgICAgdHJ5IHsgYW1vdW50ID0gQmlnSW50KGFtb3VudCk7IH1cbiAgICAgIGNhdGNoIChlcnIpIHsgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiSW52YWxpZCBkZXN0aW5hdGlvbiBhbW91bnQ6IFwiICsgYW1vdW50KTsgfVxuICAgIH1cbiAgICB0aGlzLmFtb3VudCA9IGFtb3VudDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGNvcHkoKTogTW9uZXJvRGVzdGluYXRpb24ge1xuICAgIHJldHVybiBuZXcgTW9uZXJvRGVzdGluYXRpb24odGhpcyk7XG4gIH1cbiAgXG4gIHRvSnNvbigpOiBhbnkge1xuICAgIGxldCBqc29uOiBhbnkgPSBPYmplY3QuYXNzaWduKHt9LCB0aGlzKTtcbiAgICBpZiAodGhpcy5nZXRBbW91bnQoKSAhPT0gdW5kZWZpbmVkKSBqc29uLmFtb3VudCA9IHRoaXMuZ2V0QW1vdW50KCkudG9TdHJpbmcoKTtcbiAgICByZXR1cm4ganNvbjtcbiAgfVxuICBcbiAgdG9TdHJpbmcoaW5kZW50ID0gMCk6IHN0cmluZyB7XG4gICAgbGV0IHN0ciA9IEdlblV0aWxzLmt2TGluZShcIkFkZHJlc3NcIiwgdGhpcy5nZXRBZGRyZXNzKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIkFtb3VudFwiLCB0aGlzLmdldEFtb3VudCgpID8gdGhpcy5nZXRBbW91bnQoKS50b1N0cmluZygpIDogdW5kZWZpbmVkLCBpbmRlbnQpO1xuICAgIHJldHVybiBzdHIuc2xpY2UoMCwgc3RyLmxlbmd0aCAtIDEpOyAgLy8gc3RyaXAgbGFzdCBuZXdsaW5lXG4gIH1cbn0iXSwibWFwcGluZ3MiOiJ5TEFBQSxJQUFBQSxTQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxZQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7O0FBRUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUUsaUJBQWlCLENBQUM7O0VBRXJDOzs7RUFHQTs7O0VBR0E7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0VDLFdBQVdBLENBQUNDLG9CQUEwRCxFQUFFQyxNQUFlLEVBQUU7SUFDdkYsSUFBSSxPQUFPRCxvQkFBb0IsS0FBSyxRQUFRLEVBQUU7TUFDNUMsSUFBSSxDQUFDRSxVQUFVLENBQUNGLG9CQUFvQixDQUFDO01BQ3JDLElBQUksQ0FBQ0csU0FBUyxDQUFDRixNQUFNLENBQUM7SUFDeEIsQ0FBQyxNQUFNO01BQ0wsSUFBSUEsTUFBTSxLQUFLRyxTQUFTLEVBQUUsTUFBTSxJQUFJQyxLQUFLLENBQUMsbUdBQW1HLENBQUM7TUFDOUlDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRVAsb0JBQW9CLENBQUM7TUFDekMsSUFBSSxJQUFJLENBQUNDLE1BQU0sSUFBSSxPQUFPLElBQUksQ0FBQ0EsTUFBTSxLQUFLLFFBQVEsRUFBRSxJQUFJLENBQUNBLE1BQU0sR0FBR08sTUFBTSxDQUFDLElBQUksQ0FBQ1AsTUFBTSxDQUFDO0lBQ3ZGO0VBQ0Y7O0VBRUFRLFVBQVVBLENBQUEsRUFBVztJQUNuQixPQUFPLElBQUksQ0FBQ0MsT0FBTztFQUNyQjs7RUFFQVIsVUFBVUEsQ0FBQ1EsT0FBMkIsRUFBcUI7SUFDekQsSUFBSSxDQUFDQSxPQUFPLEdBQUdBLE9BQU87SUFDdEIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFDLFNBQVNBLENBQUEsRUFBVztJQUNsQixPQUFPLElBQUksQ0FBQ1YsTUFBTTtFQUNwQjs7RUFFQUUsU0FBU0EsQ0FBQ0YsTUFBYyxFQUFxQjtJQUMzQyxJQUFJQSxNQUFNLEtBQUtHLFNBQVMsSUFBSSxPQUFPSCxNQUFNLEtBQUssUUFBUSxFQUFFO01BQ3RELElBQUksT0FBT0EsTUFBTSxLQUFLLFFBQVEsRUFBRSxNQUFNLElBQUlXLG9CQUFXLENBQUMsNkNBQTZDLENBQUM7TUFDcEcsSUFBSSxDQUFFWCxNQUFNLEdBQUdPLE1BQU0sQ0FBQ1AsTUFBTSxDQUFDLENBQUU7TUFDL0IsT0FBT1ksR0FBRyxFQUFFLENBQUUsTUFBTSxJQUFJRCxvQkFBVyxDQUFDLDhCQUE4QixHQUFHWCxNQUFNLENBQUMsQ0FBRTtJQUNoRjtJQUNBLElBQUksQ0FBQ0EsTUFBTSxHQUFHQSxNQUFNO0lBQ3BCLE9BQU8sSUFBSTtFQUNiOztFQUVBYSxJQUFJQSxDQUFBLEVBQXNCO0lBQ3hCLE9BQU8sSUFBSWhCLGlCQUFpQixDQUFDLElBQUksQ0FBQztFQUNwQzs7RUFFQWlCLE1BQU1BLENBQUEsRUFBUTtJQUNaLElBQUlDLElBQVMsR0FBR1YsTUFBTSxDQUFDQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQ3ZDLElBQUksSUFBSSxDQUFDSSxTQUFTLENBQUMsQ0FBQyxLQUFLUCxTQUFTLEVBQUVZLElBQUksQ0FBQ2YsTUFBTSxHQUFHLElBQUksQ0FBQ1UsU0FBUyxDQUFDLENBQUMsQ0FBQ00sUUFBUSxDQUFDLENBQUM7SUFDN0UsT0FBT0QsSUFBSTtFQUNiOztFQUVBQyxRQUFRQSxDQUFDQyxNQUFNLEdBQUcsQ0FBQyxFQUFVO0lBQzNCLElBQUlDLEdBQUcsR0FBR0MsaUJBQVEsQ0FBQ0MsTUFBTSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUNaLFVBQVUsQ0FBQyxDQUFDLEVBQUVTLE1BQU0sQ0FBQztJQUMvREMsR0FBRyxJQUFJQyxpQkFBUSxDQUFDQyxNQUFNLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQ1YsU0FBUyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUNBLFNBQVMsQ0FBQyxDQUFDLENBQUNNLFFBQVEsQ0FBQyxDQUFDLEdBQUdiLFNBQVMsRUFBRWMsTUFBTSxDQUFDO0lBQ3BHLE9BQU9DLEdBQUcsQ0FBQ0csS0FBSyxDQUFDLENBQUMsRUFBRUgsR0FBRyxDQUFDSSxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBRTtFQUN4QztBQUNGLENBQUNDLE9BQUEsQ0FBQUMsT0FBQSxHQUFBM0IsaUJBQUEifQ== \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroIncomingTransfer.d.ts b/dist/src/main/ts/wallet/model/MoneroIncomingTransfer.d.ts new file mode 100644 index 000000000..ce75f5a66 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroIncomingTransfer.d.ts @@ -0,0 +1,47 @@ +import MoneroTransfer from "./MoneroTransfer"; +import MoneroTxWallet from "./MoneroTxWallet"; +/** + * Models an incoming transfer of funds to the wallet. + */ +export default class MoneroIncomingTransfer extends MoneroTransfer { + subaddressIndex: number; + address: string; + numSuggestedConfirmations: number; + /** + * Construct the transfer. + * + * @param {MoneroTransfer} [transfer] is existing state to initialize from (optional) + */ + constructor(transfer?: Partial); + getIsIncoming(): boolean; + getSubaddressIndex(): number; + setSubaddressIndex(subaddressIndex: number): MoneroIncomingTransfer; + getAddress(): string; + setAddress(address: string): MoneroIncomingTransfer; + /** + * Return how many confirmations till it's not economically worth re-writing the chain. + * That is, the number of confirmations before the transaction is highly unlikely to be + * double spent or overwritten and may be considered settled, e.g. for a merchant to trust + * as finalized. + * + * @return {number} is the number of confirmations before it's not worth rewriting the chain + */ + getNumSuggestedConfirmations(): number; + setNumSuggestedConfirmations(numSuggestedConfirmations: number): MoneroIncomingTransfer; + copy(): MoneroIncomingTransfer; + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * Merging can modify or build references to the transfer given so it + * should not be re-used or it should be copied before calling this method. + * + * @param {MoneroIncomingTransfer} transfer is the transfer to merge into this one + * @return {MoneroIncomingTransfer} + */ + merge(transfer: MoneroIncomingTransfer): MoneroIncomingTransfer; + toString(indent?: number): string; + setTx(tx: MoneroTxWallet): MoneroIncomingTransfer; + setAmount(amount: bigint): MoneroIncomingTransfer; + setAccountIndex(accountIndex: number): MoneroIncomingTransfer; +} diff --git a/dist/src/main/ts/wallet/model/MoneroIncomingTransfer.js b/dist/src/main/ts/wallet/model/MoneroIncomingTransfer.js new file mode 100644 index 000000000..d656d41ef --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroIncomingTransfer.js @@ -0,0 +1,112 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); +var _MoneroTransfer = _interopRequireDefault(require("./MoneroTransfer")); + + +/** + * Models an incoming transfer of funds to the wallet. + */ +class MoneroIncomingTransfer extends _MoneroTransfer.default { + + + + + + /** + * Construct the transfer. + * + * @param {MoneroTransfer} [transfer] is existing state to initialize from (optional) + */ + constructor(transfer) { + super(transfer); + } + + getIsIncoming() { + return true; + } + + getSubaddressIndex() { + return this.subaddressIndex; + } + + setSubaddressIndex(subaddressIndex) { + this.subaddressIndex = subaddressIndex; + return this; + } + + getAddress() { + return this.address; + } + + setAddress(address) { + this.address = address; + return this; + } + + /** + * Return how many confirmations till it's not economically worth re-writing the chain. + * That is, the number of confirmations before the transaction is highly unlikely to be + * double spent or overwritten and may be considered settled, e.g. for a merchant to trust + * as finalized. + * + * @return {number} is the number of confirmations before it's not worth rewriting the chain + */ + getNumSuggestedConfirmations() { + return this.numSuggestedConfirmations; + } + + setNumSuggestedConfirmations(numSuggestedConfirmations) { + this.numSuggestedConfirmations = numSuggestedConfirmations; + return this; + } + + copy() { + return new MoneroIncomingTransfer(this.toJson()); + } + + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * Merging can modify or build references to the transfer given so it + * should not be re-used or it should be copied before calling this method. + * + * @param {MoneroIncomingTransfer} transfer is the transfer to merge into this one + * @return {MoneroIncomingTransfer} + */ + merge(transfer) { + super.merge(transfer); + (0, _assert.default)(transfer instanceof MoneroIncomingTransfer); + if (this === transfer) return this; + this.setSubaddressIndex(_GenUtils.default.reconcile(this.getSubaddressIndex(), transfer.getSubaddressIndex())); + this.setAddress(_GenUtils.default.reconcile(this.getAddress(), transfer.getAddress())); + this.setNumSuggestedConfirmations(_GenUtils.default.reconcile(this.getNumSuggestedConfirmations(), transfer.getNumSuggestedConfirmations(), { resolveMax: false })); + return this; + } + + toString(indent = 0) { + let str = super.toString(indent) + "\n"; + str += _GenUtils.default.kvLine("Subaddress index", this.getSubaddressIndex(), indent); + str += _GenUtils.default.kvLine("Address", this.getAddress(), indent); + str += _GenUtils.default.kvLine("Num suggested confirmations", this.getNumSuggestedConfirmations(), indent); + return str.slice(0, str.length - 1); // strip last newline + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setTx(tx) { + super.setTx(tx); + return this; + } + + setAmount(amount) { + super.setAmount(amount); + return this; + } + + setAccountIndex(accountIndex) { + super.setAccountIndex(accountIndex); + return this; + } +}exports.default = MoneroIncomingTransfer; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTW9uZXJvVHJhbnNmZXIiLCJNb25lcm9JbmNvbWluZ1RyYW5zZmVyIiwiTW9uZXJvVHJhbnNmZXIiLCJjb25zdHJ1Y3RvciIsInRyYW5zZmVyIiwiZ2V0SXNJbmNvbWluZyIsImdldFN1YmFkZHJlc3NJbmRleCIsInN1YmFkZHJlc3NJbmRleCIsInNldFN1YmFkZHJlc3NJbmRleCIsImdldEFkZHJlc3MiLCJhZGRyZXNzIiwic2V0QWRkcmVzcyIsImdldE51bVN1Z2dlc3RlZENvbmZpcm1hdGlvbnMiLCJudW1TdWdnZXN0ZWRDb25maXJtYXRpb25zIiwic2V0TnVtU3VnZ2VzdGVkQ29uZmlybWF0aW9ucyIsImNvcHkiLCJ0b0pzb24iLCJtZXJnZSIsImFzc2VydCIsIkdlblV0aWxzIiwicmVjb25jaWxlIiwicmVzb2x2ZU1heCIsInRvU3RyaW5nIiwiaW5kZW50Iiwic3RyIiwia3ZMaW5lIiwic2xpY2UiLCJsZW5ndGgiLCJzZXRUeCIsInR4Iiwic2V0QW1vdW50IiwiYW1vdW50Iiwic2V0QWNjb3VudEluZGV4IiwiYWNjb3VudEluZGV4IiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy93YWxsZXQvbW9kZWwvTW9uZXJvSW5jb21pbmdUcmFuc2Zlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi4vLi4vY29tbW9uL0dlblV0aWxzXCI7XG5pbXBvcnQgTW9uZXJvVHJhbnNmZXIgZnJvbSBcIi4vTW9uZXJvVHJhbnNmZXJcIjtcbmltcG9ydCBNb25lcm9UeFdhbGxldCBmcm9tIFwiLi9Nb25lcm9UeFdhbGxldFwiO1xuXG4vKipcbiAqIE1vZGVscyBhbiBpbmNvbWluZyB0cmFuc2ZlciBvZiBmdW5kcyB0byB0aGUgd2FsbGV0LlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9JbmNvbWluZ1RyYW5zZmVyIGV4dGVuZHMgTW9uZXJvVHJhbnNmZXIge1xuXG4gIHN1YmFkZHJlc3NJbmRleDogbnVtYmVyO1xuICBhZGRyZXNzOiBzdHJpbmc7XG4gIG51bVN1Z2dlc3RlZENvbmZpcm1hdGlvbnM6IG51bWJlcjtcbiAgXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3QgdGhlIHRyYW5zZmVyLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9UcmFuc2Zlcn0gW3RyYW5zZmVyXSBpcyBleGlzdGluZyBzdGF0ZSB0byBpbml0aWFsaXplIGZyb20gKG9wdGlvbmFsKVxuICAgKi9cbiAgY29uc3RydWN0b3IodHJhbnNmZXI/OiBQYXJ0aWFsPE1vbmVyb0luY29taW5nVHJhbnNmZXI+KSB7XG4gICAgc3VwZXIodHJhbnNmZXIpO1xuICB9XG4gIFxuICBnZXRJc0luY29taW5nKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIFxuICBnZXRTdWJhZGRyZXNzSW5kZXgoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5zdWJhZGRyZXNzSW5kZXg7XG4gIH1cbiAgXG4gIHNldFN1YmFkZHJlc3NJbmRleChzdWJhZGRyZXNzSW5kZXg6IG51bWJlcik6IE1vbmVyb0luY29taW5nVHJhbnNmZXIge1xuICAgIHRoaXMuc3ViYWRkcmVzc0luZGV4ID0gc3ViYWRkcmVzc0luZGV4O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRBZGRyZXNzKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuYWRkcmVzcztcbiAgfVxuXG4gIHNldEFkZHJlc3MoYWRkcmVzczogc3RyaW5nKTogTW9uZXJvSW5jb21pbmdUcmFuc2ZlciB7XG4gICAgdGhpcy5hZGRyZXNzID0gYWRkcmVzcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJldHVybiBob3cgbWFueSBjb25maXJtYXRpb25zIHRpbGwgaXQncyBub3QgZWNvbm9taWNhbGx5IHdvcnRoIHJlLXdyaXRpbmcgdGhlIGNoYWluLlxuICAgKiBUaGF0IGlzLCB0aGUgbnVtYmVyIG9mIGNvbmZpcm1hdGlvbnMgYmVmb3JlIHRoZSB0cmFuc2FjdGlvbiBpcyBoaWdobHkgdW5saWtlbHkgdG8gYmVcbiAgICogZG91YmxlIHNwZW50IG9yIG92ZXJ3cml0dGVuIGFuZCBtYXkgYmUgY29uc2lkZXJlZCBzZXR0bGVkLCBlLmcuIGZvciBhIG1lcmNoYW50IHRvIHRydXN0XG4gICAqIGFzIGZpbmFsaXplZC5cbiAgICogXG4gICAqIEByZXR1cm4ge251bWJlcn0gaXMgdGhlIG51bWJlciBvZiBjb25maXJtYXRpb25zIGJlZm9yZSBpdCdzIG5vdCB3b3J0aCByZXdyaXRpbmcgdGhlIGNoYWluXG4gICAqL1xuICBnZXROdW1TdWdnZXN0ZWRDb25maXJtYXRpb25zKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtU3VnZ2VzdGVkQ29uZmlybWF0aW9ucztcbiAgfVxuICBcbiAgc2V0TnVtU3VnZ2VzdGVkQ29uZmlybWF0aW9ucyhudW1TdWdnZXN0ZWRDb25maXJtYXRpb25zOiBudW1iZXIpOiBNb25lcm9JbmNvbWluZ1RyYW5zZmVyIHtcbiAgICB0aGlzLm51bVN1Z2dlc3RlZENvbmZpcm1hdGlvbnMgPSBudW1TdWdnZXN0ZWRDb25maXJtYXRpb25zO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgY29weSgpOiBNb25lcm9JbmNvbWluZ1RyYW5zZmVyIHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb0luY29taW5nVHJhbnNmZXIodGhpcy50b0pzb24oKSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBVcGRhdGVzIHRoaXMgdHJhbnNhY3Rpb24gYnkgbWVyZ2luZyB0aGUgbGF0ZXN0IGluZm9ybWF0aW9uIGZyb20gdGhlIGdpdmVuXG4gICAqIHRyYW5zYWN0aW9uLlxuICAgKiBcbiAgICogTWVyZ2luZyBjYW4gbW9kaWZ5IG9yIGJ1aWxkIHJlZmVyZW5jZXMgdG8gdGhlIHRyYW5zZmVyIGdpdmVuIHNvIGl0XG4gICAqIHNob3VsZCBub3QgYmUgcmUtdXNlZCBvciBpdCBzaG91bGQgYmUgY29waWVkIGJlZm9yZSBjYWxsaW5nIHRoaXMgbWV0aG9kLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9JbmNvbWluZ1RyYW5zZmVyfSB0cmFuc2ZlciBpcyB0aGUgdHJhbnNmZXIgdG8gbWVyZ2UgaW50byB0aGlzIG9uZVxuICAgKiBAcmV0dXJuIHtNb25lcm9JbmNvbWluZ1RyYW5zZmVyfVxuICAgKi9cbiAgbWVyZ2UodHJhbnNmZXI6IE1vbmVyb0luY29taW5nVHJhbnNmZXIpOiBNb25lcm9JbmNvbWluZ1RyYW5zZmVyIHtcbiAgICBzdXBlci5tZXJnZSh0cmFuc2Zlcik7XG4gICAgYXNzZXJ0KHRyYW5zZmVyIGluc3RhbmNlb2YgTW9uZXJvSW5jb21pbmdUcmFuc2Zlcik7XG4gICAgaWYgKHRoaXMgPT09IHRyYW5zZmVyKSByZXR1cm4gdGhpcztcbiAgICB0aGlzLnNldFN1YmFkZHJlc3NJbmRleChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRTdWJhZGRyZXNzSW5kZXgoKSwgdHJhbnNmZXIuZ2V0U3ViYWRkcmVzc0luZGV4KCkpKTtcbiAgICB0aGlzLnNldEFkZHJlc3MoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0QWRkcmVzcygpLCB0cmFuc2Zlci5nZXRBZGRyZXNzKCkpKTtcbiAgICB0aGlzLnNldE51bVN1Z2dlc3RlZENvbmZpcm1hdGlvbnMoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0TnVtU3VnZ2VzdGVkQ29uZmlybWF0aW9ucygpLCB0cmFuc2Zlci5nZXROdW1TdWdnZXN0ZWRDb25maXJtYXRpb25zKCksIHtyZXNvbHZlTWF4OiBmYWxzZX0pKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgdG9TdHJpbmcoaW5kZW50ID0gMCkge1xuICAgIGxldCBzdHIgPSBzdXBlci50b1N0cmluZyhpbmRlbnQpICsgXCJcXG5cIjtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiU3ViYWRkcmVzcyBpbmRleFwiLCB0aGlzLmdldFN1YmFkZHJlc3NJbmRleCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJBZGRyZXNzXCIsIHRoaXMuZ2V0QWRkcmVzcygpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJOdW0gc3VnZ2VzdGVkIGNvbmZpcm1hdGlvbnNcIiwgdGhpcy5nZXROdW1TdWdnZXN0ZWRDb25maXJtYXRpb25zKCksIGluZGVudCk7XG4gICAgcmV0dXJuIHN0ci5zbGljZSgwLCBzdHIubGVuZ3RoIC0gMSk7ICAvLyBzdHJpcCBsYXN0IG5ld2xpbmVcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tIE9WRVJSSURFIENPVkFSSUFOVCBSRVRVUk4gVFlQRVMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgc2V0VHgodHg6IE1vbmVyb1R4V2FsbGV0KTogTW9uZXJvSW5jb21pbmdUcmFuc2ZlciB7XG4gICAgc3VwZXIuc2V0VHgodHgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBzZXRBbW91bnQoYW1vdW50OiBiaWdpbnQpOiBNb25lcm9JbmNvbWluZ1RyYW5zZmVyIHtcbiAgICBzdXBlci5zZXRBbW91bnQoYW1vdW50KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgc2V0QWNjb3VudEluZGV4KGFjY291bnRJbmRleDogbnVtYmVyKTogTW9uZXJvSW5jb21pbmdUcmFuc2ZlciB7XG4gICAgc3VwZXIuc2V0QWNjb3VudEluZGV4KGFjY291bnRJbmRleCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFNBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLGVBQUEsR0FBQUgs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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroIntegratedAddress.d.ts b/dist/src/main/ts/wallet/model/MoneroIntegratedAddress.d.ts new file mode 100644 index 000000000..e1985aaff --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroIntegratedAddress.d.ts @@ -0,0 +1,17 @@ +/** + * Monero integrated address model. + */ +export default class MoneroIntegratedAddress { + standardAddress: string; + paymentId: string; + integratedAddress: string; + constructor(integratedAddress?: Partial); + toJson(): any; + getStandardAddress(): string; + setStandardAddress(standardAddress: string): MoneroIntegratedAddress; + getPaymentId(): string; + setPaymentId(paymentId: string): MoneroIntegratedAddress; + getIntegratedAddress(): string; + setIntegratedAddress(integratedAddress: string): MoneroIntegratedAddress; + toString(): string; +} diff --git a/dist/src/main/ts/wallet/model/MoneroIntegratedAddress.js b/dist/src/main/ts/wallet/model/MoneroIntegratedAddress.js new file mode 100644 index 000000000..b013e0849 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroIntegratedAddress.js @@ -0,0 +1,49 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Monero integrated address model. + */ +class MoneroIntegratedAddress { + + + + + + constructor(integratedAddress) { + Object.assign(this, integratedAddress); + } + + toJson() { + return Object.assign({}, this); + } + + getStandardAddress() { + return this.standardAddress; + } + + setStandardAddress(standardAddress) { + this.standardAddress = standardAddress; + return this; + } + + getPaymentId() { + return this.paymentId; + } + + setPaymentId(paymentId) { + this.paymentId = paymentId; + return this; + } + + getIntegratedAddress() { + return this.integratedAddress; + } + + setIntegratedAddress(integratedAddress) { + this.integratedAddress = integratedAddress; + return this; + } + + toString() { + return this.integratedAddress; + } +}exports.default = MoneroIntegratedAddress; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcyIsImNvbnN0cnVjdG9yIiwiaW50ZWdyYXRlZEFkZHJlc3MiLCJPYmplY3QiLCJhc3NpZ24iLCJ0b0pzb24iLCJnZXRTdGFuZGFyZEFkZHJlc3MiLCJzdGFuZGFyZEFkZHJlc3MiLCJzZXRTdGFuZGFyZEFkZHJlc3MiLCJnZXRQYXltZW50SWQiLCJwYXltZW50SWQiLCJzZXRQYXltZW50SWQiLCJnZXRJbnRlZ3JhdGVkQWRkcmVzcyIsInNldEludGVncmF0ZWRBZGRyZXNzIiwidG9TdHJpbmciLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9JbnRlZ3JhdGVkQWRkcmVzcy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1vbmVybyBpbnRlZ3JhdGVkIGFkZHJlc3MgbW9kZWwuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb0ludGVncmF0ZWRBZGRyZXNzIHtcbiAgXG4gIHN0YW5kYXJkQWRkcmVzczogc3RyaW5nO1xuICBwYXltZW50SWQ6IHN0cmluZztcbiAgaW50ZWdyYXRlZEFkZHJlc3M6IHN0cmluZztcbiAgXG4gIGNvbnN0cnVjdG9yKGludGVncmF0ZWRBZGRyZXNzPzogUGFydGlhbDxNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcz4pIHtcbiAgICBPYmplY3QuYXNzaWduKHRoaXMsIGludGVncmF0ZWRBZGRyZXNzKTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICB9XG5cbiAgZ2V0U3RhbmRhcmRBZGRyZXNzKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuc3RhbmRhcmRBZGRyZXNzO1xuICB9XG4gIFxuICBzZXRTdGFuZGFyZEFkZHJlc3Moc3RhbmRhcmRBZGRyZXNzOiBzdHJpbmcpOiBNb25lcm9JbnRlZ3JhdGVkQWRkcmVzcyB7XG4gICAgdGhpcy5zdGFuZGFyZEFkZHJlc3MgPSBzdGFuZGFyZEFkZHJlc3M7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFBheW1lbnRJZCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnBheW1lbnRJZDtcbiAgfVxuICBcbiAgc2V0UGF5bWVudElkKHBheW1lbnRJZDogc3RyaW5nKTogTW9uZXJvSW50ZWdyYXRlZEFkZHJlc3Mge1xuICAgIHRoaXMucGF5bWVudElkID0gcGF5bWVudElkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRJbnRlZ3JhdGVkQWRkcmVzcygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmludGVncmF0ZWRBZGRyZXNzO1xuICB9XG4gIFxuICBzZXRJbnRlZ3JhdGVkQWRkcmVzcyhpbnRlZ3JhdGVkQWRkcmVzczogc3RyaW5nKTogTW9uZXJvSW50ZWdyYXRlZEFkZHJlc3Mge1xuICAgIHRoaXMuaW50ZWdyYXRlZEFkZHJlc3MgPSBpbnRlZ3JhdGVkQWRkcmVzcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgdG9TdHJpbmcoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5pbnRlZ3JhdGVkQWRkcmVzcztcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoicUdBQUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUEsdUJBQXVCLENBQUM7Ozs7OztFQU0zQ0MsV0FBV0EsQ0FBQ0MsaUJBQW9ELEVBQUU7SUFDaEVDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsaUJBQWlCLENBQUM7RUFDeEM7O0VBRUFHLE1BQU1BLENBQUEsRUFBUTtJQUNaLE9BQU9GLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQztFQUNoQzs7RUFFQUUsa0JBQWtCQSxDQUFBLEVBQVc7SUFDM0IsT0FBTyxJQUFJLENBQUNDLGVBQWU7RUFDN0I7O0VBRUFDLGtCQUFrQkEsQ0FBQ0QsZUFBdUIsRUFBMkI7SUFDbkUsSUFBSSxDQUFDQSxlQUFlLEdBQUdBLGVBQWU7SUFDdEMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLFlBQVlBLENBQUEsRUFBVztJQUNyQixPQUFPLElBQUksQ0FBQ0MsU0FBUztFQUN2Qjs7RUFFQUMsWUFBWUEsQ0FBQ0QsU0FBaUIsRUFBMkI7SUFDdkQsSUFBSSxDQUFDQSxTQUFTLEdBQUdBLFNBQVM7SUFDMUIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLG9CQUFvQkEsQ0FBQSxFQUFXO0lBQzdCLE9BQU8sSUFBSSxDQUFDVixpQkFBaUI7RUFDL0I7O0VBRUFXLG9CQUFvQkEsQ0FBQ1gsaUJBQXlCLEVBQTJCO0lBQ3ZFLElBQUksQ0FBQ0EsaUJBQWlCLEdBQUdBLGlCQUFpQjtJQUMxQyxPQUFPLElBQUk7RUFDYjs7RUFFQVksUUFBUUEsQ0FBQSxFQUFXO0lBQ2pCLE9BQU8sSUFBSSxDQUFDWixpQkFBaUI7RUFDL0I7QUFDRixDQUFDYSxPQUFBLENBQUFDLE9BQUEsR0FBQWhCLHVCQUFBIn0= \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroKeyImageImportResult.d.ts b/dist/src/main/ts/wallet/model/MoneroKeyImageImportResult.d.ts new file mode 100644 index 000000000..7a4530fef --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroKeyImageImportResult.d.ts @@ -0,0 +1,16 @@ +/** + * Models results from importing key images. + */ +export default class MoneroKeyImageImportResult { + height: number; + spentAmount: bigint; + unspentAmount: bigint; + constructor(result?: Partial); + toJson(): any; + getHeight(): number; + setHeight(height: number): MoneroKeyImageImportResult; + getSpentAmount(): bigint; + setSpentAmount(spentAmount: bigint): MoneroKeyImageImportResult; + getUnspentAmount(): bigint; + setUnspentAmount(unspentAmount: bigint): MoneroKeyImageImportResult; +} diff --git a/dist/src/main/ts/wallet/model/MoneroKeyImageImportResult.js b/dist/src/main/ts/wallet/model/MoneroKeyImageImportResult.js new file mode 100644 index 000000000..c203cf472 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroKeyImageImportResult.js @@ -0,0 +1,50 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Models results from importing key images. + */ +class MoneroKeyImageImportResult { + + + + + + constructor(result) { + Object.assign(this, result); + if (this.spentAmount !== undefined && typeof this.spentAmount !== "bigint") this.spentAmount = BigInt(this.spentAmount); + if (this.unspentAmount !== undefined && typeof this.unspentAmount !== "bigint") this.unspentAmount = BigInt(this.unspentAmount); + } + + toJson() { + let json = Object.assign({}, this); + if (this.getSpentAmount() !== undefined) json.spentAmount = this.getSpentAmount().toString(); + if (this.getUnspentAmount() !== undefined) json.unspentAmount = this.getUnspentAmount().toString(); + return json; + } + + getHeight() { + return this.height; + } + + setHeight(height) { + this.height = height; + return this; + } + + getSpentAmount() { + return this.spentAmount; + } + + setSpentAmount(spentAmount) { + this.spentAmount = spentAmount; + return this; + } + + getUnspentAmount() { + return this.unspentAmount; + } + + setUnspentAmount(unspentAmount) { + this.unspentAmount = unspentAmount; + return this; + } +}exports.default = MoneroKeyImageImportResult; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9LZXlJbWFnZUltcG9ydFJlc3VsdCIsImNvbnN0cnVjdG9yIiwicmVzdWx0IiwiT2JqZWN0IiwiYXNzaWduIiwic3BlbnRBbW91bnQiLCJ1bmRlZmluZWQiLCJCaWdJbnQiLCJ1bnNwZW50QW1vdW50IiwidG9Kc29uIiwianNvbiIsImdldFNwZW50QW1vdW50IiwidG9TdHJpbmciLCJnZXRVbnNwZW50QW1vdW50IiwiZ2V0SGVpZ2h0IiwiaGVpZ2h0Iiwic2V0SGVpZ2h0Iiwic2V0U3BlbnRBbW91bnQiLCJzZXRVbnNwZW50QW1vdW50IiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy93YWxsZXQvbW9kZWwvTW9uZXJvS2V5SW1hZ2VJbXBvcnRSZXN1bHQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBNb2RlbHMgcmVzdWx0cyBmcm9tIGltcG9ydGluZyBrZXkgaW1hZ2VzLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9LZXlJbWFnZUltcG9ydFJlc3VsdCB7XG5cbiAgaGVpZ2h0OiBudW1iZXI7XG4gIHNwZW50QW1vdW50OiBiaWdpbnQ7XG4gIHVuc3BlbnRBbW91bnQ6IGJpZ2ludDtcbiAgXG4gIGNvbnN0cnVjdG9yKHJlc3VsdD86IFBhcnRpYWw8TW9uZXJvS2V5SW1hZ2VJbXBvcnRSZXN1bHQ+KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCByZXN1bHQpO1xuICAgIGlmICh0aGlzLnNwZW50QW1vdW50ICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHRoaXMuc3BlbnRBbW91bnQgIT09IFwiYmlnaW50XCIpIHRoaXMuc3BlbnRBbW91bnQgPSBCaWdJbnQodGhpcy5zcGVudEFtb3VudCk7XG4gICAgaWYgKHRoaXMudW5zcGVudEFtb3VudCAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLnVuc3BlbnRBbW91bnQgIT09IFwiYmlnaW50XCIpIHRoaXMudW5zcGVudEFtb3VudCA9IEJpZ0ludCh0aGlzLnVuc3BlbnRBbW91bnQpO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICBsZXQganNvbjogYW55ID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcyk7XG4gICAgaWYgKHRoaXMuZ2V0U3BlbnRBbW91bnQoKSAhPT0gdW5kZWZpbmVkKSBqc29uLnNwZW50QW1vdW50ID0gdGhpcy5nZXRTcGVudEFtb3VudCgpLnRvU3RyaW5nKCk7XG4gICAgaWYgKHRoaXMuZ2V0VW5zcGVudEFtb3VudCgpICE9PSB1bmRlZmluZWQpIGpzb24udW5zcGVudEFtb3VudCA9IHRoaXMuZ2V0VW5zcGVudEFtb3VudCgpLnRvU3RyaW5nKCk7XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIGdldEhlaWdodCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmhlaWdodDtcbiAgfVxuICBcbiAgc2V0SGVpZ2h0KGhlaWdodDogbnVtYmVyKTogTW9uZXJvS2V5SW1hZ2VJbXBvcnRSZXN1bHQge1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRTcGVudEFtb3VudCgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLnNwZW50QW1vdW50O1xuICB9XG4gIFxuICBzZXRTcGVudEFtb3VudChzcGVudEFtb3VudDogYmlnaW50KTogTW9uZXJvS2V5SW1hZ2VJbXBvcnRSZXN1bHQge1xuICAgIHRoaXMuc3BlbnRBbW91bnQgPSBzcGVudEFtb3VudDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0VW5zcGVudEFtb3VudCgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLnVuc3BlbnRBbW91bnQ7XG4gIH1cbiAgXG4gIHNldFVuc3BlbnRBbW91bnQodW5zcGVudEFtb3VudDogYmlnaW50KTogTW9uZXJvS2V5SW1hZ2VJbXBvcnRSZXN1bHQge1xuICAgIHRoaXMudW5zcGVudEFtb3VudCA9IHVuc3BlbnRBbW91bnQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InFHQUFBO0FBQ0E7QUFDQTtBQUNlLE1BQU1BLDBCQUEwQixDQUFDOzs7Ozs7RUFNOUNDLFdBQVdBLENBQUNDLE1BQTRDLEVBQUU7SUFDeERDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsTUFBTSxDQUFDO0lBQzNCLElBQUksSUFBSSxDQUFDRyxXQUFXLEtBQUtDLFNBQVMsSUFBSSxPQUFPLElBQUksQ0FBQ0QsV0FBVyxLQUFLLFFBQVEsRUFBRSxJQUFJLENBQUNBLFdBQVcsR0FBR0UsTUFBTSxDQUFDLElBQUksQ0FBQ0YsV0FBVyxDQUFDO0lBQ3ZILElBQUksSUFBSSxDQUFDRyxhQUFhLEtBQUtGLFNBQVMsSUFBSSxPQUFPLElBQUksQ0FBQ0UsYUFBYSxLQUFLLFFBQVEsRUFBRSxJQUFJLENBQUNBLGFBQWEsR0FBR0QsTUFBTSxDQUFDLElBQUksQ0FBQ0MsYUFBYSxDQUFDO0VBQ2pJOztFQUVBQyxNQUFNQSxDQUFBLEVBQVE7SUFDWixJQUFJQyxJQUFTLEdBQUdQLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQztJQUN2QyxJQUFJLElBQUksQ0FBQ08sY0FBYyxDQUFDLENBQUMsS0FBS0wsU0FBUyxFQUFFSSxJQUFJLENBQUNMLFdBQVcsR0FBRyxJQUFJLENBQUNNLGNBQWMsQ0FBQyxDQUFDLENBQUNDLFFBQVEsQ0FBQyxDQUFDO0lBQzVGLElBQUksSUFBSSxDQUFDQyxnQkFBZ0IsQ0FBQyxDQUFDLEtBQUtQLFNBQVMsRUFBRUksSUFBSSxDQUFDRixhQUFhLEdBQUcsSUFBSSxDQUFDSyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUNELFFBQVEsQ0FBQyxDQUFDO0lBQ2xHLE9BQU9GLElBQUk7RUFDYjs7RUFFQUksU0FBU0EsQ0FBQSxFQUFXO0lBQ2xCLE9BQU8sSUFBSSxDQUFDQyxNQUFNO0VBQ3BCOztFQUVBQyxTQUFTQSxDQUFDRCxNQUFjLEVBQThCO0lBQ3BELElBQUksQ0FBQ0EsTUFBTSxHQUFHQSxNQUFNO0lBQ3BCLE9BQU8sSUFBSTtFQUNiOztFQUVBSixjQUFjQSxDQUFBLEVBQVc7SUFDdkIsT0FBTyxJQUFJLENBQUNOLFdBQVc7RUFDekI7O0VBRUFZLGNBQWNBLENBQUNaLFdBQW1CLEVBQThCO0lBQzlELElBQUksQ0FBQ0EsV0FBVyxHQUFHQSxXQUFXO0lBQzlCLE9BQU8sSUFBSTtFQUNiOztFQUVBUSxnQkFBZ0JBLENBQUEsRUFBVztJQUN6QixPQUFPLElBQUksQ0FBQ0wsYUFBYTtFQUMzQjs7RUFFQVUsZ0JBQWdCQSxDQUFDVixhQUFxQixFQUE4QjtJQUNsRSxJQUFJLENBQUNBLGFBQWEsR0FBR0EsYUFBYTtJQUNsQyxPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNXLE9BQUEsQ0FBQUMsT0FBQSxHQUFBcEIsMEJBQUEifQ== \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroMessageSignatureResult.d.ts b/dist/src/main/ts/wallet/model/MoneroMessageSignatureResult.d.ts new file mode 100644 index 000000000..48cb16e30 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroMessageSignatureResult.d.ts @@ -0,0 +1,20 @@ +import MoneroMessageSignatureType from "./MoneroMessageSignatureType"; +/** + * Message signature verification result. + */ +export default class MoneroMessageSignatureResult { + isGood: boolean; + isOld: boolean; + signatureType: MoneroMessageSignatureType; + version: number; + constructor(result?: Partial); + toJson(): any; + getIsGood(): boolean; + setIsGood(isGood: boolean): MoneroMessageSignatureResult; + getIsOld(): boolean; + setIsOld(isOld: boolean): MoneroMessageSignatureResult; + getSignatureType(): MoneroMessageSignatureType; + setSignatureType(signatureType: MoneroMessageSignatureType): MoneroMessageSignatureResult; + getVersion(): number; + setVersion(version: number): MoneroMessageSignatureResult; +} diff --git a/dist/src/main/ts/wallet/model/MoneroMessageSignatureResult.js b/dist/src/main/ts/wallet/model/MoneroMessageSignatureResult.js new file mode 100644 index 000000000..4526a83bd --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroMessageSignatureResult.js @@ -0,0 +1,58 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; + +/** + * Message signature verification result. + */ +class MoneroMessageSignatureResult { + + + + + + + constructor(result) { + Object.assign(this, result); + } + + toJson() { + return Object.assign({}, this); + } + + getIsGood() { + return this.isGood; + } + + setIsGood(isGood) { + this.isGood = isGood; + return this; + } + + getIsOld() { + return this.isOld; + } + + setIsOld(isOld) { + this.isOld = isOld; + return this; + } + + getSignatureType() { + return this.signatureType; + } + + setSignatureType(signatureType) { + this.signatureType = signatureType; + return this; + } + + getVersion() { + return this.version; + } + + setVersion(version) { + this.version = version; + return this; + } + +}exports.default = MoneroMessageSignatureResult; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9NZXNzYWdlU2lnbmF0dXJlUmVzdWx0IiwiY29uc3RydWN0b3IiLCJyZXN1bHQiLCJPYmplY3QiLCJhc3NpZ24iLCJ0b0pzb24iLCJnZXRJc0dvb2QiLCJpc0dvb2QiLCJzZXRJc0dvb2QiLCJnZXRJc09sZCIsImlzT2xkIiwic2V0SXNPbGQiLCJnZXRTaWduYXR1cmVUeXBlIiwic2lnbmF0dXJlVHlwZSIsInNldFNpZ25hdHVyZVR5cGUiLCJnZXRWZXJzaW9uIiwidmVyc2lvbiIsInNldFZlcnNpb24iLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9NZXNzYWdlU2lnbmF0dXJlUmVzdWx0LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBNb25lcm9NZXNzYWdlU2lnbmF0dXJlVHlwZSBmcm9tIFwiLi9Nb25lcm9NZXNzYWdlU2lnbmF0dXJlVHlwZVwiO1xuXG4vKipcbiAqIE1lc3NhZ2Ugc2lnbmF0dXJlIHZlcmlmaWNhdGlvbiByZXN1bHQuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb01lc3NhZ2VTaWduYXR1cmVSZXN1bHQge1xuXG4gIGlzR29vZDogYm9vbGVhbjtcbiAgaXNPbGQ6IGJvb2xlYW47XG4gIHNpZ25hdHVyZVR5cGU6IE1vbmVyb01lc3NhZ2VTaWduYXR1cmVUeXBlO1xuICB2ZXJzaW9uOiBudW1iZXI7XG4gIFxuICBjb25zdHJ1Y3RvcihyZXN1bHQ/OiBQYXJ0aWFsPE1vbmVyb01lc3NhZ2VTaWduYXR1cmVSZXN1bHQ+KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCByZXN1bHQpO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICByZXR1cm4gT2JqZWN0LmFzc2lnbih7fSwgdGhpcyk7XG4gIH1cblxuICBnZXRJc0dvb2QoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNHb29kO1xuICB9XG5cbiAgc2V0SXNHb29kKGlzR29vZDogYm9vbGVhbik6IE1vbmVyb01lc3NhZ2VTaWduYXR1cmVSZXN1bHQge1xuICAgIHRoaXMuaXNHb29kID0gaXNHb29kO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRJc09sZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc09sZDtcbiAgfVxuXG4gIHNldElzT2xkKGlzT2xkOiBib29sZWFuKTogTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVJlc3VsdCB7XG4gICAgdGhpcy5pc09sZCA9IGlzT2xkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRTaWduYXR1cmVUeXBlKCk6IE1vbmVyb01lc3NhZ2VTaWduYXR1cmVUeXBlIHtcbiAgICByZXR1cm4gdGhpcy5zaWduYXR1cmVUeXBlO1xuICB9XG5cbiAgc2V0U2lnbmF0dXJlVHlwZShzaWduYXR1cmVUeXBlOiBNb25lcm9NZXNzYWdlU2lnbmF0dXJlVHlwZSk6IE1vbmVyb01lc3NhZ2VTaWduYXR1cmVSZXN1bHQge1xuICAgIHRoaXMuc2lnbmF0dXJlVHlwZSA9IHNpZ25hdHVyZVR5cGU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFZlcnNpb24oKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy52ZXJzaW9uO1xuICB9XG5cbiAgc2V0VmVyc2lvbih2ZXJzaW9uOiBudW1iZXIpOiBNb25lcm9NZXNzYWdlU2lnbmF0dXJlUmVzdWx0IHtcbiAgICB0aGlzLnZlcnNpb24gPSB2ZXJzaW9uO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbn0iXSwibWFwcGluZ3MiOiI7O0FBRUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUEsNEJBQTRCLENBQUM7Ozs7Ozs7RUFPaERDLFdBQVdBLENBQUNDLE1BQThDLEVBQUU7SUFDMURDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsTUFBTSxDQUFDO0VBQzdCOztFQUVBRyxNQUFNQSxDQUFBLEVBQVE7SUFDWixPQUFPRixNQUFNLENBQUNDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUM7RUFDaEM7O0VBRUFFLFNBQVNBLENBQUEsRUFBWTtJQUNuQixPQUFPLElBQUksQ0FBQ0MsTUFBTTtFQUNwQjs7RUFFQUMsU0FBU0EsQ0FBQ0QsTUFBZSxFQUFnQztJQUN2RCxJQUFJLENBQUNBLE1BQU0sR0FBR0EsTUFBTTtJQUNwQixPQUFPLElBQUk7RUFDYjs7RUFFQUUsUUFBUUEsQ0FBQSxFQUFZO0lBQ2xCLE9BQU8sSUFBSSxDQUFDQyxLQUFLO0VBQ25COztFQUVBQyxRQUFRQSxDQUFDRCxLQUFjLEVBQWdDO0lBQ3JELElBQUksQ0FBQ0EsS0FBSyxHQUFHQSxLQUFLO0lBQ2xCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxnQkFBZ0JBLENBQUEsRUFBK0I7SUFDN0MsT0FBTyxJQUFJLENBQUNDLGFBQWE7RUFDM0I7O0VBRUFDLGdCQUFnQkEsQ0FBQ0QsYUFBeUMsRUFBZ0M7SUFDeEYsSUFBSSxDQUFDQSxhQUFhLEdBQUdBLGFBQWE7SUFDbEMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLFVBQVVBLENBQUEsRUFBVztJQUNuQixPQUFPLElBQUksQ0FBQ0MsT0FBTztFQUNyQjs7RUFFQUMsVUFBVUEsQ0FBQ0QsT0FBZSxFQUFnQztJQUN4RCxJQUFJLENBQUNBLE9BQU8sR0FBR0EsT0FBTztJQUN0QixPQUFPLElBQUk7RUFDYjs7QUFFRixDQUFDRSxPQUFBLENBQUFDLE9BQUEsR0FBQW5CLDRCQUFBIn0= \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroMessageSignatureType.d.ts b/dist/src/main/ts/wallet/model/MoneroMessageSignatureType.d.ts new file mode 100644 index 000000000..9b1fe5e70 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroMessageSignatureType.d.ts @@ -0,0 +1,14 @@ +/** + * Enumerate message signature types. + */ +declare enum MoneroMessageSignatureType { + /** + * Sign with spend key (value=0). + */ + SIGN_WITH_SPEND_KEY = 0, + /** + * Sign with the view key (value=1). + */ + SIGN_WITH_VIEW_KEY = 1 +} +export default MoneroMessageSignatureType; diff --git a/dist/src/main/ts/wallet/model/MoneroMessageSignatureType.js b/dist/src/main/ts/wallet/model/MoneroMessageSignatureType.js new file mode 100644 index 000000000..7123d84f8 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroMessageSignatureType.js @@ -0,0 +1,18 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Enumerate message signature types. + */var +MoneroMessageSignatureType = /*#__PURE__*/function (MoneroMessageSignatureType) {MoneroMessageSignatureType[MoneroMessageSignatureType["SIGN_WITH_SPEND_KEY"] = 0] = "SIGN_WITH_SPEND_KEY";MoneroMessageSignatureType[MoneroMessageSignatureType["SIGN_WITH_VIEW_KEY"] = 1] = "SIGN_WITH_VIEW_KEY";return MoneroMessageSignatureType;}(MoneroMessageSignatureType || {});var _default = exports.default = + + + + + + + + + + + + +MoneroMessageSignatureType; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9NZXNzYWdlU2lnbmF0dXJlVHlwZSIsIl9kZWZhdWx0IiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy93YWxsZXQvbW9kZWwvTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBFbnVtZXJhdGUgbWVzc2FnZSBzaWduYXR1cmUgdHlwZXMuXG4gKi9cbmVudW0gTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGUge1xuXG4gICAgLyoqXG4gICAgICogU2lnbiB3aXRoIHNwZW5kIGtleSAodmFsdWU9MCkuXG4gICAgICovXG4gICAgU0lHTl9XSVRIX1NQRU5EX0tFWSA9IDAsXG5cbiAgICAvKipcbiAgICAgKiBTaWduIHdpdGggdGhlIHZpZXcga2V5ICh2YWx1ZT0xKS5cbiAgICAgKi9cbiAgICBTSUdOX1dJVEhfVklFV19LRVkgPSAxXG59XG4gIFxuZXhwb3J0IGRlZmF1bHQgTW9uZXJvTWVzc2FnZVNpZ25hdHVyZVR5cGU7Il0sIm1hcHBpbmdzIjoicUdBQUE7QUFDQTtBQUNBLEdBRkE7QUFHS0EsMEJBQTBCLDBCQUExQkEsMEJBQTBCLEdBQTFCQSwwQkFBMEIsQ0FBMUJBLDBCQUEwQixxREFBMUJBLDBCQUEwQixDQUExQkEsMEJBQTBCLDBEQUExQkEsMEJBQTBCLEdBQTFCQSwwQkFBMEIsWUFBQUMsUUFBQSxHQUFBQyxPQUFBLENBQUFDLE9BQUE7Ozs7Ozs7Ozs7Ozs7QUFhaEJILDBCQUEwQiJ9 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroMultisigInfo.d.ts b/dist/src/main/ts/wallet/model/MoneroMultisigInfo.d.ts new file mode 100644 index 000000000..941e1285b --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroMultisigInfo.d.ts @@ -0,0 +1,19 @@ +/** + * Models information about a multisig wallet. + */ +export default class MoneroMultisigInfo { + isMultisig: boolean; + isReady: boolean; + threshold: number; + numParticipants: number; + constructor(multisigInfo?: Partial); + toJson(): any; + getIsMultisig(): boolean; + setIsMultisig(isMultisig: boolean): MoneroMultisigInfo; + getIsReady(): boolean; + setIsReady(isReady: boolean): MoneroMultisigInfo; + getThreshold(): number; + setThreshold(threshold: number): MoneroMultisigInfo; + getNumParticipants(): number; + setNumParticipants(numParticipants: number): MoneroMultisigInfo; +} diff --git a/dist/src/main/ts/wallet/model/MoneroMultisigInfo.js b/dist/src/main/ts/wallet/model/MoneroMultisigInfo.js new file mode 100644 index 000000000..c626fb675 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroMultisigInfo.js @@ -0,0 +1,55 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Models information about a multisig wallet. + */ +class MoneroMultisigInfo { + + + + + + + constructor(multisigInfo) { + Object.assign(this, multisigInfo); + } + + toJson() { + return Object.assign({}, this); + } + + getIsMultisig() { + return this.isMultisig; + } + + setIsMultisig(isMultisig) { + this.isMultisig = isMultisig; + return this; + } + + getIsReady() { + return this.isReady; + } + + setIsReady(isReady) { + this.isReady = isReady; + return this; + } + + getThreshold() { + return this.threshold; + } + + setThreshold(threshold) { + this.threshold = threshold; + return this; + } + + getNumParticipants() { + return this.numParticipants; + } + + setNumParticipants(numParticipants) { + this.numParticipants = numParticipants; + return this; + } +}exports.default = MoneroMultisigInfo; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9NdWx0aXNpZ0luZm8iLCJjb25zdHJ1Y3RvciIsIm11bHRpc2lnSW5mbyIsIk9iamVjdCIsImFzc2lnbiIsInRvSnNvbiIsImdldElzTXVsdGlzaWciLCJpc011bHRpc2lnIiwic2V0SXNNdWx0aXNpZyIsImdldElzUmVhZHkiLCJpc1JlYWR5Iiwic2V0SXNSZWFkeSIsImdldFRocmVzaG9sZCIsInRocmVzaG9sZCIsInNldFRocmVzaG9sZCIsImdldE51bVBhcnRpY2lwYW50cyIsIm51bVBhcnRpY2lwYW50cyIsInNldE51bVBhcnRpY2lwYW50cyIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvd2FsbGV0L21vZGVsL01vbmVyb011bHRpc2lnSW5mby50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1vZGVscyBpbmZvcm1hdGlvbiBhYm91dCBhIG11bHRpc2lnIHdhbGxldC5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTW9uZXJvTXVsdGlzaWdJbmZvIHtcblxuICBpc011bHRpc2lnOiBib29sZWFuO1xuICBpc1JlYWR5OiBib29sZWFuO1xuICB0aHJlc2hvbGQ6IG51bWJlcjtcbiAgbnVtUGFydGljaXBhbnRzOiBudW1iZXI7XG4gIFxuICBjb25zdHJ1Y3RvcihtdWx0aXNpZ0luZm8/OiBQYXJ0aWFsPE1vbmVyb011bHRpc2lnSW5mbz4pIHtcbiAgICBPYmplY3QuYXNzaWduKHRoaXMsIG11bHRpc2lnSW5mbyk7XG4gIH1cbiAgXG4gIHRvSnNvbigpOiBhbnkge1xuICAgIHJldHVybiBPYmplY3QuYXNzaWduKHt9LCB0aGlzKTtcbiAgfVxuICBcbiAgZ2V0SXNNdWx0aXNpZygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc011bHRpc2lnO1xuICB9XG4gIFxuICBzZXRJc011bHRpc2lnKGlzTXVsdGlzaWc6IGJvb2xlYW4pOiBNb25lcm9NdWx0aXNpZ0luZm8ge1xuICAgIHRoaXMuaXNNdWx0aXNpZyA9IGlzTXVsdGlzaWc7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldElzUmVhZHkoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNSZWFkeTtcbiAgfVxuICBcbiAgc2V0SXNSZWFkeShpc1JlYWR5OiBib29sZWFuKTogTW9uZXJvTXVsdGlzaWdJbmZvIHtcbiAgICB0aGlzLmlzUmVhZHkgPSBpc1JlYWR5O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRUaHJlc2hvbGQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy50aHJlc2hvbGQ7XG4gIH1cbiAgXG4gIHNldFRocmVzaG9sZCh0aHJlc2hvbGQ6IG51bWJlcik6IE1vbmVyb011bHRpc2lnSW5mbyB7XG4gICAgdGhpcy50aHJlc2hvbGQgPSB0aHJlc2hvbGQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldE51bVBhcnRpY2lwYW50cygpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLm51bVBhcnRpY2lwYW50cztcbiAgfVxuICBcbiAgc2V0TnVtUGFydGljaXBhbnRzKG51bVBhcnRpY2lwYW50czogbnVtYmVyKTogTW9uZXJvTXVsdGlzaWdJbmZvIHtcbiAgICB0aGlzLm51bVBhcnRpY2lwYW50cyA9IG51bVBhcnRpY2lwYW50cztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoicUdBQUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUEsa0JBQWtCLENBQUM7Ozs7Ozs7RUFPdENDLFdBQVdBLENBQUNDLFlBQTBDLEVBQUU7SUFDdERDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsWUFBWSxDQUFDO0VBQ25DOztFQUVBRyxNQUFNQSxDQUFBLEVBQVE7SUFDWixPQUFPRixNQUFNLENBQUNDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUM7RUFDaEM7O0VBRUFFLGFBQWFBLENBQUEsRUFBWTtJQUN2QixPQUFPLElBQUksQ0FBQ0MsVUFBVTtFQUN4Qjs7RUFFQUMsYUFBYUEsQ0FBQ0QsVUFBbUIsRUFBc0I7SUFDckQsSUFBSSxDQUFDQSxVQUFVLEdBQUdBLFVBQVU7SUFDNUIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLFVBQVVBLENBQUEsRUFBWTtJQUNwQixPQUFPLElBQUksQ0FBQ0MsT0FBTztFQUNyQjs7RUFFQUMsVUFBVUEsQ0FBQ0QsT0FBZ0IsRUFBc0I7SUFDL0MsSUFBSSxDQUFDQSxPQUFPLEdBQUdBLE9BQU87SUFDdEIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLFlBQVlBLENBQUEsRUFBVztJQUNyQixPQUFPLElBQUksQ0FBQ0MsU0FBUztFQUN2Qjs7RUFFQUMsWUFBWUEsQ0FBQ0QsU0FBaUIsRUFBc0I7SUFDbEQsSUFBSSxDQUFDQSxTQUFTLEdBQUdBLFNBQVM7SUFDMUIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLGtCQUFrQkEsQ0FBQSxFQUFXO0lBQzNCLE9BQU8sSUFBSSxDQUFDQyxlQUFlO0VBQzdCOztFQUVBQyxrQkFBa0JBLENBQUNELGVBQXVCLEVBQXNCO0lBQzlELElBQUksQ0FBQ0EsZUFBZSxHQUFHQSxlQUFlO0lBQ3RDLE9BQU8sSUFBSTtFQUNiO0FBQ0YsQ0FBQ0UsT0FBQSxDQUFBQyxPQUFBLEdBQUFuQixrQkFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroMultisigInitResult.d.ts b/dist/src/main/ts/wallet/model/MoneroMultisigInitResult.d.ts new file mode 100644 index 000000000..98ebb3fb3 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroMultisigInitResult.d.ts @@ -0,0 +1,15 @@ +/** + * Models the result of initializing a multisig wallet which results in the + * multisig wallet's address xor another multisig hex to share with + * participants to create the wallet. + */ +export default class MoneroMultisigInitResult { + address: string; + multisigHex: string; + constructor(result?: Partial); + toJson(): any; + getAddress(): string; + setAddress(address: string): MoneroMultisigInitResult; + getMultisigHex(): string; + setMultisigHex(multisigHex: string): MoneroMultisigInitResult; +} diff --git a/dist/src/main/ts/wallet/model/MoneroMultisigInitResult.js b/dist/src/main/ts/wallet/model/MoneroMultisigInitResult.js new file mode 100644 index 000000000..87b52e0c5 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroMultisigInitResult.js @@ -0,0 +1,37 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Models the result of initializing a multisig wallet which results in the + * multisig wallet's address xor another multisig hex to share with + * participants to create the wallet. + */ +class MoneroMultisigInitResult { + + + + + constructor(result) { + Object.assign(this, result); + } + + toJson() { + return Object.assign({}, this); + } + + getAddress() { + return this.address; + } + + setAddress(address) { + this.address = address; + return this; + } + + getMultisigHex() { + return this.multisigHex; + } + + setMultisigHex(multisigHex) { + this.multisigHex = multisigHex; + return this; + } +}exports.default = MoneroMultisigInitResult; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9NdWx0aXNpZ0luaXRSZXN1bHQiLCJjb25zdHJ1Y3RvciIsInJlc3VsdCIsIk9iamVjdCIsImFzc2lnbiIsInRvSnNvbiIsImdldEFkZHJlc3MiLCJhZGRyZXNzIiwic2V0QWRkcmVzcyIsImdldE11bHRpc2lnSGV4IiwibXVsdGlzaWdIZXgiLCJzZXRNdWx0aXNpZ0hleCIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvd2FsbGV0L21vZGVsL01vbmVyb011bHRpc2lnSW5pdFJlc3VsdC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE1vZGVscyB0aGUgcmVzdWx0IG9mIGluaXRpYWxpemluZyBhIG11bHRpc2lnIHdhbGxldCB3aGljaCByZXN1bHRzIGluIHRoZVxuICogbXVsdGlzaWcgd2FsbGV0J3MgYWRkcmVzcyB4b3IgYW5vdGhlciBtdWx0aXNpZyBoZXggdG8gc2hhcmUgd2l0aFxuICogcGFydGljaXBhbnRzIHRvIGNyZWF0ZSB0aGUgd2FsbGV0LlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9NdWx0aXNpZ0luaXRSZXN1bHQge1xuXG4gIGFkZHJlc3M6IHN0cmluZztcbiAgbXVsdGlzaWdIZXg6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihyZXN1bHQ/OiBQYXJ0aWFsPE1vbmVyb011bHRpc2lnSW5pdFJlc3VsdD4pIHtcbiAgICBPYmplY3QuYXNzaWduKHRoaXMsIHJlc3VsdCk7XG4gIH1cbiAgXG4gIHRvSnNvbigpOiBhbnkge1xuICAgIHJldHVybiBPYmplY3QuYXNzaWduKHt9LCB0aGlzKTtcbiAgfVxuICBcbiAgZ2V0QWRkcmVzcygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmFkZHJlc3M7XG4gIH1cbiAgXG4gIHNldEFkZHJlc3MoYWRkcmVzczogc3RyaW5nKTogTW9uZXJvTXVsdGlzaWdJbml0UmVzdWx0IHtcbiAgICB0aGlzLmFkZHJlc3MgPSBhZGRyZXNzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRNdWx0aXNpZ0hleCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLm11bHRpc2lnSGV4O1xuICB9XG4gIFxuICBzZXRNdWx0aXNpZ0hleChtdWx0aXNpZ0hleDogc3RyaW5nKTogTW9uZXJvTXVsdGlzaWdJbml0UmVzdWx0IHtcbiAgICB0aGlzLm11bHRpc2lnSGV4ID0gbXVsdGlzaWdIZXg7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InFHQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSx3QkFBd0IsQ0FBQzs7Ozs7RUFLNUNDLFdBQVdBLENBQUNDLE1BQTBDLEVBQUU7SUFDdERDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsTUFBTSxDQUFDO0VBQzdCOztFQUVBRyxNQUFNQSxDQUFBLEVBQVE7SUFDWixPQUFPRixNQUFNLENBQUNDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUM7RUFDaEM7O0VBRUFFLFVBQVVBLENBQUEsRUFBVztJQUNuQixPQUFPLElBQUksQ0FBQ0MsT0FBTztFQUNyQjs7RUFFQUMsVUFBVUEsQ0FBQ0QsT0FBZSxFQUE0QjtJQUNwRCxJQUFJLENBQUNBLE9BQU8sR0FBR0EsT0FBTztJQUN0QixPQUFPLElBQUk7RUFDYjs7RUFFQUUsY0FBY0EsQ0FBQSxFQUFXO0lBQ3ZCLE9BQU8sSUFBSSxDQUFDQyxXQUFXO0VBQ3pCOztFQUVBQyxjQUFjQSxDQUFDRCxXQUFtQixFQUE0QjtJQUM1RCxJQUFJLENBQUNBLFdBQVcsR0FBR0EsV0FBVztJQUM5QixPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNFLE9BQUEsQ0FBQUMsT0FBQSxHQUFBYix3QkFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroMultisigSignResult.d.ts b/dist/src/main/ts/wallet/model/MoneroMultisigSignResult.d.ts new file mode 100644 index 000000000..02cf180df --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroMultisigSignResult.d.ts @@ -0,0 +1,13 @@ +/** + * Models the result of signing multisig tx hex. + */ +export default class MoneroMultisigSignResult { + signedMultisigTxHex: string; + txHashes: string[]; + constructor(result?: Partial); + toJson(): any; + getSignedMultisigTxHex(): string; + setSignedMultisigTxHex(signedTxMultisigHex: string): MoneroMultisigSignResult; + getTxHashes(): string[]; + setTxHashes(txHashes: string[]): MoneroMultisigSignResult; +} diff --git a/dist/src/main/ts/wallet/model/MoneroMultisigSignResult.js b/dist/src/main/ts/wallet/model/MoneroMultisigSignResult.js new file mode 100644 index 000000000..5bc596bda --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroMultisigSignResult.js @@ -0,0 +1,35 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Models the result of signing multisig tx hex. + */ +class MoneroMultisigSignResult { + + + + + constructor(result) { + Object.assign(this, result); + } + + toJson() { + return Object.assign({}, this); + } + + getSignedMultisigTxHex() { + return this.signedMultisigTxHex; + } + + setSignedMultisigTxHex(signedTxMultisigHex) { + this.signedMultisigTxHex = signedTxMultisigHex; + return this; + } + + getTxHashes() { + return this.txHashes; + } + + setTxHashes(txHashes) { + this.txHashes = txHashes; + return this; + } +}exports.default = MoneroMultisigSignResult; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9NdWx0aXNpZ1NpZ25SZXN1bHQiLCJjb25zdHJ1Y3RvciIsInJlc3VsdCIsIk9iamVjdCIsImFzc2lnbiIsInRvSnNvbiIsImdldFNpZ25lZE11bHRpc2lnVHhIZXgiLCJzaWduZWRNdWx0aXNpZ1R4SGV4Iiwic2V0U2lnbmVkTXVsdGlzaWdUeEhleCIsInNpZ25lZFR4TXVsdGlzaWdIZXgiLCJnZXRUeEhhc2hlcyIsInR4SGFzaGVzIiwic2V0VHhIYXNoZXMiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9NdWx0aXNpZ1NpZ25SZXN1bHQudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBNb2RlbHMgdGhlIHJlc3VsdCBvZiBzaWduaW5nIG11bHRpc2lnIHR4IGhleC5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTW9uZXJvTXVsdGlzaWdTaWduUmVzdWx0IHtcblxuICBzaWduZWRNdWx0aXNpZ1R4SGV4OiBzdHJpbmc7XG4gIHR4SGFzaGVzOiBzdHJpbmdbXTtcbiAgXG4gIGNvbnN0cnVjdG9yKHJlc3VsdD86IFBhcnRpYWw8TW9uZXJvTXVsdGlzaWdTaWduUmVzdWx0Pikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgcmVzdWx0KTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgcmV0dXJuIE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICB9XG4gIFxuICBnZXRTaWduZWRNdWx0aXNpZ1R4SGV4KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuc2lnbmVkTXVsdGlzaWdUeEhleDtcbiAgfVxuXG4gIHNldFNpZ25lZE11bHRpc2lnVHhIZXgoc2lnbmVkVHhNdWx0aXNpZ0hleDogc3RyaW5nKTogTW9uZXJvTXVsdGlzaWdTaWduUmVzdWx0IHtcbiAgICB0aGlzLnNpZ25lZE11bHRpc2lnVHhIZXggPSBzaWduZWRUeE11bHRpc2lnSGV4O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0VHhIYXNoZXMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiB0aGlzLnR4SGFzaGVzO1xuICB9XG5cbiAgc2V0VHhIYXNoZXModHhIYXNoZXM6IHN0cmluZ1tdKTogTW9uZXJvTXVsdGlzaWdTaWduUmVzdWx0IHtcbiAgICB0aGlzLnR4SGFzaGVzID0gdHhIYXNoZXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InFHQUFBO0FBQ0E7QUFDQTtBQUNlLE1BQU1BLHdCQUF3QixDQUFDOzs7OztFQUs1Q0MsV0FBV0EsQ0FBQ0MsTUFBMEMsRUFBRTtJQUN0REMsTUFBTSxDQUFDQyxNQUFNLENBQUMsSUFBSSxFQUFFRixNQUFNLENBQUM7RUFDN0I7O0VBRUFHLE1BQU1BLENBQUEsRUFBUTtJQUNaLE9BQU9GLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQztFQUNoQzs7RUFFQUUsc0JBQXNCQSxDQUFBLEVBQVc7SUFDL0IsT0FBTyxJQUFJLENBQUNDLG1CQUFtQjtFQUNqQzs7RUFFQUMsc0JBQXNCQSxDQUFDQyxtQkFBMkIsRUFBNEI7SUFDNUUsSUFBSSxDQUFDRixtQkFBbUIsR0FBR0UsbUJBQW1CO0lBQzlDLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxXQUFXQSxDQUFBLEVBQWE7SUFDdEIsT0FBTyxJQUFJLENBQUNDLFFBQVE7RUFDdEI7O0VBRUFDLFdBQVdBLENBQUNELFFBQWtCLEVBQTRCO0lBQ3hELElBQUksQ0FBQ0EsUUFBUSxHQUFHQSxRQUFRO0lBQ3hCLE9BQU8sSUFBSTtFQUNiO0FBQ0YsQ0FBQ0UsT0FBQSxDQUFBQyxPQUFBLEdBQUFkLHdCQUFBIn0= \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroOutgoingTransfer.d.ts b/dist/src/main/ts/wallet/model/MoneroOutgoingTransfer.d.ts new file mode 100644 index 000000000..80d8e60b1 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroOutgoingTransfer.d.ts @@ -0,0 +1,40 @@ +import MoneroDestination from "./MoneroDestination"; +import MoneroTransfer from "./MoneroTransfer"; +import MoneroTxWallet from "./MoneroTxWallet"; +/** + * Models an outgoing transfer of funds from the wallet. + */ +export default class MoneroOutgoingTransfer extends MoneroTransfer { + subaddressIndices: number[]; + addresses: string[]; + destinations: MoneroDestination[]; + /** + * Construct the model. + * + * @param {MoneroOutgoingTranser [transfer] existing state to initialize from (optional) + */ + constructor(transfer?: Partial); + getIsIncoming(): boolean; + getSubaddressIndices(): number[]; + setSubaddressIndices(subaddressIndices: number[]): MoneroOutgoingTransfer; + getAddresses(): string[]; + setAddresses(addresses: string[]): MoneroOutgoingTransfer; + getDestinations(): MoneroDestination[]; + setDestinations(destinations: MoneroDestination[]): MoneroOutgoingTransfer; + copy(): MoneroOutgoingTransfer; + toJson(): any; + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * Merging can modify or build references to the transfer given so it + * should not be re-used or it should be copied before calling this method. + * + * @param transfer is the transfer to merge into this one + */ + merge(transfer: MoneroOutgoingTransfer): MoneroOutgoingTransfer; + toString(indent?: number): string; + setTx(tx: MoneroTxWallet): MoneroOutgoingTransfer; + setAmount(amount: bigint): MoneroOutgoingTransfer; + setAccountIndex(accountIndex: number): MoneroOutgoingTransfer; +} diff --git a/dist/src/main/ts/wallet/model/MoneroOutgoingTransfer.js b/dist/src/main/ts/wallet/model/MoneroOutgoingTransfer.js new file mode 100644 index 000000000..e23e256ac --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroOutgoingTransfer.js @@ -0,0 +1,128 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); +var _MoneroDestination = _interopRequireDefault(require("./MoneroDestination")); +var _MoneroTransfer = _interopRequireDefault(require("./MoneroTransfer")); + + +/** + * Models an outgoing transfer of funds from the wallet. + */ +class MoneroOutgoingTransfer extends _MoneroTransfer.default { + + + + + + /** + * Construct the model. + * + * @param {MoneroOutgoingTranser [transfer] existing state to initialize from (optional) + */ + constructor(transfer) { + super(transfer); + + // copy destinations + if (this.destinations) { + this.destinations = this.destinations.slice(); + for (let i = 0; i < this.destinations.length; i++) { + this.destinations[i] = new _MoneroDestination.default(this.destinations[i]); + } + } + } + + getIsIncoming() { + return false; + } + + getSubaddressIndices() { + return this.subaddressIndices; + } + + setSubaddressIndices(subaddressIndices) { + this.subaddressIndices = subaddressIndices; + return this; + } + + getAddresses() { + return this.addresses; + } + + setAddresses(addresses) { + this.addresses = addresses; + return this; + } + + getDestinations() { + return this.destinations; + } + + setDestinations(destinations) { + this.destinations = destinations; + return this; + } + + copy() { + return new MoneroOutgoingTransfer(this); + } + + toJson() { + let json = Object.assign({}, this, super.toJson()); // merge json onto inherited state + if (this.getDestinations() !== undefined) { + json.destinations = []; + for (let destination of this.getDestinations()) json.destinations.push(destination.toJson()); + } + delete json.tx; // parent tx is not serialized + return json; + } + + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * Merging can modify or build references to the transfer given so it + * should not be re-used or it should be copied before calling this method. + * + * @param transfer is the transfer to merge into this one + */ + merge(transfer) { + super.merge(transfer); + (0, _assert.default)(transfer instanceof MoneroOutgoingTransfer); + if (this === transfer) return this; + this.setSubaddressIndices(_GenUtils.default.reconcile(this.getSubaddressIndices(), transfer.getSubaddressIndices())); + this.setAddresses(_GenUtils.default.reconcile(this.getAddresses(), transfer.getAddresses())); + this.setDestinations(_GenUtils.default.reconcile(this.getDestinations(), transfer.getDestinations())); + return this; + } + + toString(indent = 0) { + let str = super.toString(indent) + "\n"; + str += _GenUtils.default.kvLine("Subaddress indices", this.getSubaddressIndices(), indent); + str += _GenUtils.default.kvLine("Addresses", this.getAddresses(), indent); + if (this.getDestinations() !== undefined) { + str += _GenUtils.default.kvLine("Destinations", "", indent); + for (let i = 0; i < this.getDestinations().length; i++) { + str += _GenUtils.default.kvLine(i + 1, "", indent + 1); + str += this.getDestinations()[i].toString(indent + 2) + "\n"; + } + } + return str.slice(0, str.length - 1); // strip last newline + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setTx(tx) { + super.setTx(tx); + return this; + } + + setAmount(amount) { + super.setAmount(amount); + return this; + } + + setAccountIndex(accountIndex) { + super.setAccountIndex(accountIndex); + return this; + } +}exports.default = MoneroOutgoingTransfer; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTW9uZXJvRGVzdGluYXRpb24iLCJfTW9uZXJvVHJhbnNmZXIiLCJNb25lcm9PdXRnb2luZ1RyYW5zZmVyIiwiTW9uZXJvVHJhbnNmZXIiLCJjb25zdHJ1Y3RvciIsInRyYW5zZmVyIiwiZGVzdGluYXRpb25zIiwic2xpY2UiLCJpIiwibGVuZ3RoIiwiTW9uZXJvRGVzdGluYXRpb24iLCJnZXRJc0luY29taW5nIiwiZ2V0U3ViYWRkcmVzc0luZGljZXMiLCJzdWJhZGRyZXNzSW5kaWNlcyIsInNldFN1YmFkZHJlc3NJbmRpY2VzIiwiZ2V0QWRkcmVzc2VzIiwiYWRkcmVzc2VzIiwic2V0QWRkcmVzc2VzIiwiZ2V0RGVzdGluYXRpb25zIiwic2V0RGVzdGluYXRpb25zIiwiY29weSIsInRvSnNvbiIsImpzb24iLCJPYmplY3QiLCJhc3NpZ24iLCJ1bmRlZmluZWQiLCJkZXN0aW5hdGlvbiIsInB1c2giLCJ0eCIsIm1lcmdlIiwiYXNzZXJ0IiwiR2VuVXRpbHMiLCJyZWNvbmNpbGUiLCJ0b1N0cmluZyIsImluZGVudCIsInN0ciIsImt2TGluZSIsInNldFR4Iiwic2V0QW1vdW50IiwiYW1vdW50Iiwic2V0QWNjb3VudEluZGV4IiwiYWNjb3VudEluZGV4IiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy93YWxsZXQvbW9kZWwvTW9uZXJvT3V0Z29pbmdUcmFuc2Zlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi4vLi4vY29tbW9uL0dlblV0aWxzXCI7XG5pbXBvcnQgTW9uZXJvRGVzdGluYXRpb24gZnJvbSBcIi4vTW9uZXJvRGVzdGluYXRpb25cIjtcbmltcG9ydCBNb25lcm9UcmFuc2ZlciBmcm9tIFwiLi9Nb25lcm9UcmFuc2ZlclwiO1xuaW1wb3J0IE1vbmVyb1R4V2FsbGV0IGZyb20gXCIuL01vbmVyb1R4V2FsbGV0XCI7XG5cbi8qKlxuICogTW9kZWxzIGFuIG91dGdvaW5nIHRyYW5zZmVyIG9mIGZ1bmRzIGZyb20gdGhlIHdhbGxldC5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTW9uZXJvT3V0Z29pbmdUcmFuc2ZlciBleHRlbmRzIE1vbmVyb1RyYW5zZmVyIHtcblxuICBzdWJhZGRyZXNzSW5kaWNlczogbnVtYmVyW107XG4gIGFkZHJlc3Nlczogc3RyaW5nW107XG4gIGRlc3RpbmF0aW9uczogTW9uZXJvRGVzdGluYXRpb25bXTtcblxuICAvKipcbiAgICogQ29uc3RydWN0IHRoZSBtb2RlbC5cbiAgICogXG4gICAqIEBwYXJhbSB7TW9uZXJvT3V0Z29pbmdUcmFuc2VyIFt0cmFuc2Zlcl0gZXhpc3Rpbmcgc3RhdGUgdG8gaW5pdGlhbGl6ZSBmcm9tIChvcHRpb25hbClcbiAgICovXG4gIGNvbnN0cnVjdG9yKHRyYW5zZmVyPzogUGFydGlhbDxNb25lcm9PdXRnb2luZ1RyYW5zZmVyPikge1xuICAgIHN1cGVyKHRyYW5zZmVyKTtcbiAgICBcbiAgICAvLyBjb3B5IGRlc3RpbmF0aW9uc1xuICAgIGlmICh0aGlzLmRlc3RpbmF0aW9ucykge1xuICAgICAgdGhpcy5kZXN0aW5hdGlvbnMgPSB0aGlzLmRlc3RpbmF0aW9ucy5zbGljZSgpO1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmRlc3RpbmF0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzLmRlc3RpbmF0aW9uc1tpXSA9IG5ldyBNb25lcm9EZXN0aW5hdGlvbih0aGlzLmRlc3RpbmF0aW9uc1tpXSk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIFxuICBnZXRJc0luY29taW5nKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBcbiAgZ2V0U3ViYWRkcmVzc0luZGljZXMoKTogbnVtYmVyW10ge1xuICAgIHJldHVybiB0aGlzLnN1YmFkZHJlc3NJbmRpY2VzO1xuICB9XG5cbiAgc2V0U3ViYWRkcmVzc0luZGljZXMoc3ViYWRkcmVzc0luZGljZXM6IG51bWJlcltdKTogTW9uZXJvT3V0Z29pbmdUcmFuc2ZlciB7XG4gICAgdGhpcy5zdWJhZGRyZXNzSW5kaWNlcyA9IHN1YmFkZHJlc3NJbmRpY2VzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRBZGRyZXNzZXMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiB0aGlzLmFkZHJlc3NlcztcbiAgfVxuXG4gIHNldEFkZHJlc3NlcyhhZGRyZXNzZXM6IHN0cmluZ1tdKTogTW9uZXJvT3V0Z29pbmdUcmFuc2ZlciB7XG4gICAgdGhpcy5hZGRyZXNzZXMgPSBhZGRyZXNzZXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXREZXN0aW5hdGlvbnMoKTogTW9uZXJvRGVzdGluYXRpb25bXSB7XG4gICAgcmV0dXJuIHRoaXMuZGVzdGluYXRpb25zO1xuICB9XG4gIFxuICBzZXREZXN0aW5hdGlvbnMoZGVzdGluYXRpb25zOiBNb25lcm9EZXN0aW5hdGlvbltdKTogTW9uZXJvT3V0Z29pbmdUcmFuc2ZlciB7XG4gICAgdGhpcy5kZXN0aW5hdGlvbnMgPSBkZXN0aW5hdGlvbnM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGNvcHkoKTogTW9uZXJvT3V0Z29pbmdUcmFuc2ZlciB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9PdXRnb2luZ1RyYW5zZmVyKHRoaXMpO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICBsZXQganNvbiA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMsIHN1cGVyLnRvSnNvbigpKTsgLy8gbWVyZ2UganNvbiBvbnRvIGluaGVyaXRlZCBzdGF0ZVxuICAgIGlmICh0aGlzLmdldERlc3RpbmF0aW9ucygpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGpzb24uZGVzdGluYXRpb25zID0gW107XG4gICAgICBmb3IgKGxldCBkZXN0aW5hdGlvbiBvZiB0aGlzLmdldERlc3RpbmF0aW9ucygpKSBqc29uLmRlc3RpbmF0aW9ucy5wdXNoKGRlc3RpbmF0aW9uLnRvSnNvbigpKTtcbiAgICB9XG4gICAgZGVsZXRlIGpzb24udHg7IC8vIHBhcmVudCB0eCBpcyBub3Qgc2VyaWFsaXplZFxuICAgIHJldHVybiBqc29uO1xuICB9XG4gIFxuICAvKipcbiAgICogVXBkYXRlcyB0aGlzIHRyYW5zYWN0aW9uIGJ5IG1lcmdpbmcgdGhlIGxhdGVzdCBpbmZvcm1hdGlvbiBmcm9tIHRoZSBnaXZlblxuICAgKiB0cmFuc2FjdGlvbi5cbiAgICogXG4gICAqIE1lcmdpbmcgY2FuIG1vZGlmeSBvciBidWlsZCByZWZlcmVuY2VzIHRvIHRoZSB0cmFuc2ZlciBnaXZlbiBzbyBpdFxuICAgKiBzaG91bGQgbm90IGJlIHJlLXVzZWQgb3IgaXQgc2hvdWxkIGJlIGNvcGllZCBiZWZvcmUgY2FsbGluZyB0aGlzIG1ldGhvZC5cbiAgICogXG4gICAqIEBwYXJhbSB0cmFuc2ZlciBpcyB0aGUgdHJhbnNmZXIgdG8gbWVyZ2UgaW50byB0aGlzIG9uZVxuICAgKi9cbiAgbWVyZ2UodHJhbnNmZXI6IE1vbmVyb091dGdvaW5nVHJhbnNmZXIpOiBNb25lcm9PdXRnb2luZ1RyYW5zZmVyIHtcbiAgICBzdXBlci5tZXJnZSh0cmFuc2Zlcik7XG4gICAgYXNzZXJ0KHRyYW5zZmVyIGluc3RhbmNlb2YgTW9uZXJvT3V0Z29pbmdUcmFuc2Zlcik7XG4gICAgaWYgKHRoaXMgPT09IHRyYW5zZmVyKSByZXR1cm4gdGhpcztcbiAgICB0aGlzLnNldFN1YmFkZHJlc3NJbmRpY2VzKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldFN1YmFkZHJlc3NJbmRpY2VzKCksIHRyYW5zZmVyLmdldFN1YmFkZHJlc3NJbmRpY2VzKCkpKTtcbiAgICB0aGlzLnNldEFkZHJlc3NlcyhHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRBZGRyZXNzZXMoKSwgdHJhbnNmZXIuZ2V0QWRkcmVzc2VzKCkpKTtcbiAgICB0aGlzLnNldERlc3RpbmF0aW9ucyhHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXREZXN0aW5hdGlvbnMoKSwgdHJhbnNmZXIuZ2V0RGVzdGluYXRpb25zKCkpKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHRvU3RyaW5nKGluZGVudCA9IDApOiBzdHJpbmcge1xuICAgIGxldCBzdHIgPSBzdXBlci50b1N0cmluZyhpbmRlbnQpICsgXCJcXG5cIjtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiU3ViYWRkcmVzcyBpbmRpY2VzXCIsIHRoaXMuZ2V0U3ViYWRkcmVzc0luZGljZXMoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiQWRkcmVzc2VzXCIsIHRoaXMuZ2V0QWRkcmVzc2VzKCksIGluZGVudCk7XG4gICAgaWYgKHRoaXMuZ2V0RGVzdGluYXRpb25zKCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIkRlc3RpbmF0aW9uc1wiLCBcIlwiLCBpbmRlbnQpO1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmdldERlc3RpbmF0aW9ucygpLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoaSArIDEsIFwiXCIsIGluZGVudCArIDEpO1xuICAgICAgICBzdHIgKz0gdGhpcy5nZXREZXN0aW5hdGlvbnMoKVtpXS50b1N0cmluZyhpbmRlbnQgKyAyKSArIFwiXFxuXCI7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBzdHIuc2xpY2UoMCwgc3RyLmxlbmd0aCAtIDEpOyAgLy8gc3RyaXAgbGFzdCBuZXdsaW5lXG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLSBPVkVSUklERSBDT1ZBUklBTlQgUkVUVVJOIFRZUEVTIC0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIHNldFR4KHR4OiBNb25lcm9UeFdhbGxldCk6IE1vbmVyb091dGdvaW5nVHJhbnNmZXIge1xuICAgIHN1cGVyLnNldFR4KHR4KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldEFtb3VudChhbW91bnQ6IGJpZ2ludCk6IE1vbmVyb091dGdvaW5nVHJhbnNmZXIge1xuICAgIHN1cGVyLnNldEFtb3VudChhbW91bnQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0QWNjb3VudEluZGV4KGFjY291bnRJbmRleDogbnVtYmVyKTogTW9uZXJvT3V0Z29pbmdUcmFuc2ZlciB7XG4gICAgc3VwZXIuc2V0QWNjb3VudEluZGV4KGFjY291bnRJbmRleCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFNBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLGtCQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRyxlQUFBLEdBQUFKLHNCQUFBLENBQUFDLE9BQUE7OztBQUdBO0FBQ0E7QUFDQTtBQUNlLE1BQU1JLHNCQUFzQixTQUFTQyx1QkFBYyxDQUFDOzs7Ozs7RUFNakU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtFQUNFQyxXQUFXQSxDQUFDQyxRQUEwQyxFQUFFO0lBQ3RELEtBQUssQ0FBQ0EsUUFBUSxDQUFDOztJQUVmO0lBQ0EsSUFBSSxJQUFJLENBQUNDLFlBQVksRUFBRTtNQUNyQixJQUFJLENBQUNBLFlBQVksR0FBRyxJQUFJLENBQUNBLFlBQVksQ0FBQ0MsS0FBSyxDQUFDLENBQUM7TUFDN0MsS0FBSyxJQUFJQyxDQUFDLEdBQUcsQ0FBQyxFQUFFQSxDQUFDLEdBQUcsSUFBSSxDQUFDRixZQUFZLENBQUNHLE1BQU0sRUFBRUQsQ0FBQyxFQUFFLEVBQUU7UUFDakQsSUFBSSxDQUFDRixZQUFZLENBQUNFLENBQUMsQ0FBQyxHQUFHLElBQUlFLDBCQUFpQixDQUFD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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroOutputQuery.d.ts b/dist/src/main/ts/wallet/model/MoneroOutputQuery.d.ts new file mode 100644 index 000000000..3b17ae8e1 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroOutputQuery.d.ts @@ -0,0 +1,66 @@ +import MoneroKeyImage from "../../daemon/model/MoneroKeyImage"; +import MoneroOutputWallet from "./MoneroOutputWallet"; +import MoneroTx from "../../daemon/model/MoneroTx"; +import MoneroTxQuery from "./MoneroTxQuery"; +/** + * Configuration to query wallet outputs. + */ +export default class MoneroOutputQuery extends MoneroOutputWallet { + minAmount: bigint; + maxAmount: bigint; + txQuery: Partial; + subaddressIndices: number[]; + /** + *

Construct the output query.

+ * + *

Example:

+ * + * + * // get available outputs in account 0 with a minimum amount
+ * let outputs = await wallet.getOutputs({
+ *    isSpent: false,
+ *    isLocked: false,
+ *    accountIndex: 0,
+ *    minAmount: 750000n
+ * }); + *
+ * + *

All configuration is optional. All outputs are returned except those that don't meet criteria defined in this query.

+ * + * @param {MoneroOutputQuery} [config] - output query configuration (optional) + * @param {number} config.accountIndex - get outputs in this account index + * @param {number} config.subaddressIndex - get outputs in this subaddress index + * @param {number[]} config.subaddressIndices - get outputs in these subaddress indices + * @param {bigint} config.amount - get outputs with this amount + * @param {bigint} config.minAmount - get outputs with amount greater than or equal to this amount + * @param {bigint} config.maxAmount - get outputs with amount less than or equal to this amount + * @param {boolean} config.isSpent - get spent xor unspent outputs + * @param {boolean} config.isFrozen - get frozen xor thawed outputs + * @param {MoneroKeyImage} config.keyImage - get outputs with a key image matching fields defined in this key image + * @param {string} config.keyImage.hex - get outputs with this key image hex + * @param {string} config.keyImage.signature - get outputs with this key image signature + * @param {MoneroTxQuery} config.txQuery - get outputs whose tx match this tx query + */ + constructor(query?: Partial); + copy(): MoneroOutputQuery; + toJson(): any; + getMinAmount(): bigint; + setMinAmount(minAmount: bigint): MoneroOutputQuery; + getMaxAmount(): bigint; + setMaxAmount(maxAmount: bigint): MoneroOutputQuery; + getTxQuery(): MoneroTxQuery; + setTxQuery(txQuery: MoneroTxQuery): MoneroOutputQuery; + getSubaddressIndices(): number[]; + setSubaddressIndices(subaddressIndices: number[]): MoneroOutputQuery; + meetsCriteria(output: MoneroOutputWallet, queryParent?: boolean): boolean; + setTx(tx: MoneroTx): MoneroOutputQuery; + setAccountIndex(accountIndex: number): MoneroOutputQuery; + setSubaddressIndex(subaddressIndex: number): MoneroOutputQuery; + setIsSpent(isSpent: boolean): MoneroOutputQuery; + setIsFrozen(isFrozen: boolean): MoneroOutputQuery; + setKeyImage(keyImage: MoneroKeyImage): MoneroOutputQuery; + setAmount(amount: bigint): MoneroOutputQuery; + setIndex(index: number): MoneroOutputQuery; + setRingOutputIndices(ringOutputIndices: number[]): MoneroOutputQuery; + setStealthPublicKey(stealthPublicKey: string): MoneroOutputQuery; +} diff --git a/dist/src/main/ts/wallet/model/MoneroOutputQuery.js b/dist/src/main/ts/wallet/model/MoneroOutputQuery.js new file mode 100644 index 000000000..751f6a14a --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroOutputQuery.js @@ -0,0 +1,190 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _MoneroError = _interopRequireDefault(require("../../common/MoneroError")); + +var _MoneroOutputWallet = _interopRequireDefault(require("./MoneroOutputWallet")); + + +var _MoneroTxQuery = _interopRequireDefault(require("./MoneroTxQuery")); + +/** + * Configuration to query wallet outputs. + */ +class MoneroOutputQuery extends _MoneroOutputWallet.default { + + + + + + + /** + *

Construct the output query.

+ * + *

Example:

+ * + * + * // get available outputs in account 0 with a minimum amount
+ * let outputs = await wallet.getOutputs({
+ *    isSpent: false,
+ *    isLocked: false,
+ *    accountIndex: 0,
+ *    minAmount: 750000n
+ * }); + *
+ * + *

All configuration is optional. All outputs are returned except those that don't meet criteria defined in this query.

+ * + * @param {MoneroOutputQuery} [config] - output query configuration (optional) + * @param {number} config.accountIndex - get outputs in this account index + * @param {number} config.subaddressIndex - get outputs in this subaddress index + * @param {number[]} config.subaddressIndices - get outputs in these subaddress indices + * @param {bigint} config.amount - get outputs with this amount + * @param {bigint} config.minAmount - get outputs with amount greater than or equal to this amount + * @param {bigint} config.maxAmount - get outputs with amount less than or equal to this amount + * @param {boolean} config.isSpent - get spent xor unspent outputs + * @param {boolean} config.isFrozen - get frozen xor thawed outputs + * @param {MoneroKeyImage} config.keyImage - get outputs with a key image matching fields defined in this key image + * @param {string} config.keyImage.hex - get outputs with this key image hex + * @param {string} config.keyImage.signature - get outputs with this key image signature + * @param {MoneroTxQuery} config.txQuery - get outputs whose tx match this tx query + */ + constructor(query) { + super(query); + if (this.minAmount !== undefined && typeof this.minAmount !== "bigint") this.minAmount = BigInt(this.minAmount); + if (this.maxAmount !== undefined && typeof this.maxAmount !== "bigint") this.maxAmount = BigInt(this.maxAmount); + if (this.txQuery && !(this.txQuery instanceof _MoneroTxQuery.default)) this.txQuery = new _MoneroTxQuery.default(this.txQuery); + if (this.txQuery) this.txQuery.setOutputQuery(this); + if (this.isLocked !== undefined) throw new _MoneroError.default("isLocked must be part of tx query, not output query"); + } + + copy() { + return new MoneroOutputQuery(this); + } + + toJson() { + let json = Object.assign({}, this, super.toJson()); + if (this.getMinAmount() !== undefined) json.minAmount = this.getMinAmount().toString(); + if (this.getMaxAmount() !== undefined) json.maxAmount = this.getMaxAmount().toString(); + delete json.txQuery; + return json; + } + + getMinAmount() { + return this.minAmount; + } + + setMinAmount(minAmount) { + this.minAmount = minAmount; + return this; + } + + getMaxAmount() { + return this.maxAmount; + } + + setMaxAmount(maxAmount) { + this.maxAmount = maxAmount; + return this; + } + + getTxQuery() { + return this.txQuery; + } + + setTxQuery(txQuery) { + this.txQuery = txQuery === undefined ? undefined : txQuery instanceof _MoneroTxQuery.default ? txQuery : new _MoneroTxQuery.default(txQuery); + if (txQuery) this.txQuery.outputQuery = this; + return this; + } + + getSubaddressIndices() { + return this.subaddressIndices; + } + + setSubaddressIndices(subaddressIndices) { + this.subaddressIndices = subaddressIndices; + return this; + } + + meetsCriteria(output, queryParent = true) { + if (!(output instanceof _MoneroOutputWallet.default)) throw new Error("Output not given to MoneroOutputQuery.meetsCriteria(output)"); + + // filter on output + if (this.getAccountIndex() !== undefined && this.getAccountIndex() !== output.getAccountIndex()) return false; + if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() !== output.getSubaddressIndex()) return false; + if (this.getAmount() !== undefined && this.getAmount() !== output.getAmount()) return false; + if (this.getIsSpent() !== undefined && this.getIsSpent() !== output.getIsSpent()) return false; + if (this.getIsFrozen() !== undefined && this.getIsFrozen() !== output.getIsFrozen()) return false; + + // filter on output's key image + if (this.getKeyImage() !== undefined) { + if (output.getKeyImage() === undefined) return false; + if (this.getKeyImage().getHex() !== undefined && this.getKeyImage().getHex() !== output.getKeyImage().getHex()) return false; + if (this.getKeyImage().getSignature() !== undefined && this.getKeyImage().getSignature() !== output.getKeyImage().getSignature()) return false; + } + + // filter on extensions + if (this.getSubaddressIndices() !== undefined && !this.getSubaddressIndices().includes(output.getSubaddressIndex())) return false; + + // filter with tx query + if (this.getTxQuery() && !this.getTxQuery().meetsCriteria(output.getTx(), false)) return false; + + // filter on remaining fields + if (this.getMinAmount() !== undefined && (output.getAmount() === undefined || output.getAmount() < this.getMinAmount())) return false; + if (this.getMaxAmount() !== undefined && (output.getAmount() === undefined || output.getAmount() > this.getMaxAmount())) return false; + + // output meets query + return true; + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setTx(tx) { + super.setTx(tx); + return this; + } + + setAccountIndex(accountIndex) { + super.setAccountIndex(accountIndex); + return this; + } + + setSubaddressIndex(subaddressIndex) { + super.setSubaddressIndex(subaddressIndex); + return this; + } + + setIsSpent(isSpent) { + super.setIsSpent(isSpent); + return this; + } + + setIsFrozen(isFrozen) { + super.setIsFrozen(isFrozen); + return this; + } + + setKeyImage(keyImage) { + super.setKeyImage(keyImage); + return this; + } + + setAmount(amount) { + super.setAmount(amount); + return this; + } + + setIndex(index) { + super.setIndex(index); + return this; + } + + setRingOutputIndices(ringOutputIndices) { + super.setRingOutputIndices(ringOutputIndices); + return this; + } + + setStealthPublicKey(stealthPublicKey) { + super.setStealthPublicKey(stealthPublicKey); + return this; + } +}exports.default = MoneroOutputQuery; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfTW9uZXJvRXJyb3IiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9Nb25lcm9PdXRwdXRXYWxsZXQiLCJfTW9uZXJvVHhRdWVyeSIsIk1vbmVyb091dHB1dFF1ZXJ5IiwiTW9uZXJvT3V0cHV0V2FsbGV0IiwiY29uc3RydWN0b3IiLCJxdWVyeSIsIm1pbkFtb3VudCIsInVuZGVmaW5lZCIsIkJpZ0ludCIsIm1heEFtb3VudCIsInR4UXVlcnkiLCJNb25lcm9UeFF1ZXJ5Iiwic2V0T3V0cHV0UXVlcnkiLCJpc0xvY2tlZCIsIk1vbmVyb0Vycm9yIiwiY29weSIsInRvSnNvbiIsImpzb24iLCJPYmplY3QiLCJhc3NpZ24iLCJnZXRNaW5BbW91bnQiLCJ0b1N0cmluZyIsImdldE1heEFtb3VudCIsInNldE1pbkFtb3VudCIsInNldE1heEFtb3VudCIsImdldFR4UXVlcnkiLCJzZXRUeFF1ZXJ5Iiwib3V0cHV0UXVlcnkiLCJnZXRTdWJhZGRyZXNzSW5kaWNlcyIsInN1YmFkZHJlc3NJbmRpY2VzIiwic2V0U3ViYWRkcmVzc0luZGljZXMiLCJtZWV0c0NyaXRlcmlhIiwib3V0cHV0IiwicXVlcnlQYXJlbnQiLCJFcnJvciIsImdldEFjY291bnRJbmRleCIsImdldFN1YmFkZHJlc3NJbmRleCIsImdldEFtb3VudCIsImdldElzU3BlbnQiLCJnZXRJc0Zyb3plbiIsImdldEtleUltYWdlIiwiZ2V0SGV4IiwiZ2V0U2lnbmF0dXJlIiwiaW5jbHVkZXMiLCJnZXRUeCIsInNldFR4IiwidHgiLCJzZXRBY2NvdW50SW5kZXgiLCJhY2NvdW50SW5kZXgiLCJzZXRTdWJhZGRyZXNzSW5kZXgiLCJzdWJhZGRyZXNzSW5kZXgiLCJzZXRJc1NwZW50IiwiaXNTcGVudCIsInNldElzRnJvemVuIiwiaXNGcm96ZW4iLCJzZXRLZXlJbWFnZSIsImtleUltYWdlIiwic2V0QW1vdW50IiwiYW1vdW50Iiwic2V0SW5kZXgiLCJpbmRleCIsInNldFJpbmdPdXRwdXRJbmRpY2VzIiwicmluZ091dHB1dEluZGljZXMiLCJzZXRTdGVhbHRoUHVibGljS2V5Iiwic3RlYWx0aFB1YmxpY0tleSIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvd2FsbGV0L21vZGVsL01vbmVyb091dHB1dFF1ZXJ5LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBNb25lcm9FcnJvciBmcm9tIFwiLi4vLi4vY29tbW9uL01vbmVyb0Vycm9yXCI7XG5pbXBvcnQgTW9uZXJvS2V5SW1hZ2UgZnJvbSBcIi4uLy4uL2RhZW1vbi9tb2RlbC9Nb25lcm9LZXlJbWFnZVwiO1xuaW1wb3J0IE1vbmVyb091dHB1dFdhbGxldCBmcm9tIFwiLi9Nb25lcm9PdXRwdXRXYWxsZXRcIjtcbmltcG9ydCBNb25lcm9UeCBmcm9tIFwiLi4vLi4vZGFlbW9uL21vZGVsL01vbmVyb1R4XCI7XG5pbXBvcnQgTW9uZXJvVHhXYWxsZXQgZnJvbSBcIi4vTW9uZXJvVHhXYWxsZXRcIjtcbmltcG9ydCBNb25lcm9UeFF1ZXJ5IGZyb20gXCIuL01vbmVyb1R4UXVlcnlcIjtcblxuLyoqXG4gKiBDb25maWd1cmF0aW9uIHRvIHF1ZXJ5IHdhbGxldCBvdXRwdXRzLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9PdXRwdXRRdWVyeSBleHRlbmRzIE1vbmVyb091dHB1dFdhbGxldCB7XG5cbiAgbWluQW1vdW50OiBiaWdpbnQ7XG4gIG1heEFtb3VudDogYmlnaW50O1xuICB0eFF1ZXJ5OiBQYXJ0aWFsPE1vbmVyb1R4UXVlcnk+O1xuICBzdWJhZGRyZXNzSW5kaWNlczogbnVtYmVyW107XG5cbiAgLyoqXG4gICAqIDxwPkNvbnN0cnVjdCB0aGUgb3V0cHV0IHF1ZXJ5LjwvcD5cbiAgICogXG4gICAqIDxwPkV4YW1wbGU6PC9wPlxuICAgKiBcbiAgICogPGNvZGU+XG4gICAqICZzb2w7JnNvbDsgZ2V0IGF2YWlsYWJsZSBvdXRwdXRzIGluIGFjY291bnQgMCB3aXRoIGEgbWluaW11bSBhbW91bnQ8YnI+XG4gICAqIGxldCBvdXRwdXRzID0gYXdhaXQgd2FsbGV0LmdldE91dHB1dHMoezxicj5cbiAgICogJm5ic3A7Jm5ic3A7IGlzU3BlbnQ6IGZhbHNlLDxicj5cbiAgICogJm5ic3A7Jm5ic3A7IGlzTG9ja2VkOiBmYWxzZSw8YnI+XG4gICAqICZuYnNwOyZuYnNwOyBhY2NvdW50SW5kZXg6IDAsPGJyPlxuICAgKiAmbmJzcDsmbmJzcDsgbWluQW1vdW50OiA3NTAwMDBuPGJyPlxuICAgKiB9KTtcbiAgICogPC9jb2RlPlxuICAgKiBcbiAgICogPHA+QWxsIGNvbmZpZ3VyYXRpb24gaXMgb3B0aW9uYWwuICBBbGwgb3V0cHV0cyBhcmUgcmV0dXJuZWQgZXhjZXB0IHRob3NlIHRoYXQgZG9uJ3QgbWVldCBjcml0ZXJpYSBkZWZpbmVkIGluIHRoaXMgcXVlcnkuPC9wPlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9PdXRwdXRRdWVyeX0gW2NvbmZpZ10gLSBvdXRwdXQgcXVlcnkgY29uZmlndXJhdGlvbiAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBjb25maWcuYWNjb3VudEluZGV4IC0gZ2V0IG91dHB1dHMgaW4gdGhpcyBhY2NvdW50IGluZGV4XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBjb25maWcuc3ViYWRkcmVzc0luZGV4IC0gZ2V0IG91dHB1dHMgaW4gdGhpcyBzdWJhZGRyZXNzIGluZGV4XG4gICAqIEBwYXJhbSB7bnVtYmVyW119IGNvbmZpZy5zdWJhZGRyZXNzSW5kaWNlcyAtIGdldCBvdXRwdXRzIGluIHRoZXNlIHN1YmFkZHJlc3MgaW5kaWNlc1xuICAgKiBAcGFyYW0ge2JpZ2ludH0gY29uZmlnLmFtb3VudCAtIGdldCBvdXRwdXRzIHdpdGggdGhpcyBhbW91bnRcbiAgICogQHBhcmFtIHtiaWdpbnR9IGNvbmZpZy5taW5BbW91bnQgLSBnZXQgb3V0cHV0cyB3aXRoIGFtb3VudCBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gdGhpcyBhbW91bnRcbiAgICogQHBhcmFtIHtiaWdpbnR9IGNvbmZpZy5tYXhBbW91bnQgLSBnZXQgb3V0cHV0cyB3aXRoIGFtb3VudCBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gdGhpcyBhbW91bnRcbiAgICogQHBhcmFtIHtib29sZWFufSBjb25maWcuaXNTcGVudCAtIGdldCBzcGVudCB4b3IgdW5zcGVudCBvdXRwdXRzXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gY29uZmlnLmlzRnJvemVuIC0gZ2V0IGZyb3plbiB4b3IgdGhhd2VkIG91dHB1dHNcbiAgICogQHBhcmFtIHtNb25lcm9LZXlJbWFnZX0gY29uZmlnLmtleUltYWdlIC0gZ2V0IG91dHB1dHMgd2l0aCBhIGtleSBpbWFnZSBtYXRjaGluZyBmaWVsZHMgZGVmaW5lZCBpbiB0aGlzIGtleSBpbWFnZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gY29uZmlnLmtleUltYWdlLmhleCAtIGdldCBvdXRwdXRzIHdpdGggdGhpcyBrZXkgaW1hZ2UgaGV4XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25maWcua2V5SW1hZ2Uuc2lnbmF0dXJlIC0gZ2V0IG91dHB1dHMgd2l0aCB0aGlzIGtleSBpbWFnZSBzaWduYXR1cmVcbiAgICogQHBhcmFtIHtNb25lcm9UeFF1ZXJ5fSBjb25maWcudHhRdWVyeSAtIGdldCBvdXRwdXRzIHdob3NlIHR4IG1hdGNoIHRoaXMgdHggcXVlcnlcbiAgICovXG4gIGNvbnN0cnVjdG9yKHF1ZXJ5PzogUGFydGlhbDxNb25lcm9PdXRwdXRRdWVyeT4pIHtcbiAgICBzdXBlcihxdWVyeSk7XG4gICAgaWYgKHRoaXMubWluQW1vdW50ICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHRoaXMubWluQW1vdW50ICE9PSBcImJpZ2ludFwiKSB0aGlzLm1pbkFtb3VudCA9IEJpZ0ludCh0aGlzLm1pbkFtb3VudCk7XG4gICAgaWYgKHRoaXMubWF4QW1vdW50ICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHRoaXMubWF4QW1vdW50ICE9PSBcImJpZ2ludFwiKSB0aGlzLm1heEFtb3VudCA9IEJpZ0ludCh0aGlzLm1heEFtb3VudCk7XG4gICAgaWYgKHRoaXMudHhRdWVyeSAmJiAhKHRoaXMudHhRdWVyeSBpbnN0YW5jZW9mIE1vbmVyb1R4UXVlcnkpKSB0aGlzLnR4UXVlcnkgPSBuZXcgTW9uZXJvVHhRdWVyeSh0aGlzLnR4UXVlcnkpO1xuICAgIGlmICh0aGlzLnR4UXVlcnkpIHRoaXMudHhRdWVyeS5zZXRPdXRwdXRRdWVyeSh0aGlzKTtcbiAgICBpZiAodGhpcy5pc0xvY2tlZCAhPT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJpc0xvY2tlZCBtdXN0IGJlIHBhcnQgb2YgdHggcXVlcnksIG5vdCBvdXRwdXQgcXVlcnlcIik7XG4gIH1cbiAgXG4gIGNvcHkoKTogTW9uZXJvT3V0cHV0UXVlcnkge1xuICAgIHJldHVybiBuZXcgTW9uZXJvT3V0cHV0UXVlcnkodGhpcyk7XG4gIH1cbiAgXG4gIHRvSnNvbigpOiBhbnkge1xuICAgIGxldCBqc29uID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcywgc3VwZXIudG9Kc29uKCkpO1xuICAgIGlmICh0aGlzLmdldE1pbkFtb3VudCgpICE9PSB1bmRlZmluZWQpIGpzb24ubWluQW1vdW50ID0gdGhpcy5nZXRNaW5BbW91bnQoKS50b1N0cmluZygpO1xuICAgIGlmICh0aGlzLmdldE1heEFtb3VudCgpICE9PSB1bmRlZmluZWQpIGpzb24ubWF4QW1vdW50ID0gdGhpcy5nZXRNYXhBbW91bnQoKS50b1N0cmluZygpO1xuICAgIGRlbGV0ZSBqc29uLnR4UXVlcnk7XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIGdldE1pbkFtb3VudCgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLm1pbkFtb3VudDtcbiAgfVxuXG4gIHNldE1pbkFtb3VudChtaW5BbW91bnQ6IGJpZ2ludCk6IE1vbmVyb091dHB1dFF1ZXJ5IHtcbiAgICB0aGlzLm1pbkFtb3VudCA9IG1pbkFtb3VudDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldE1heEFtb3VudCgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLm1heEFtb3VudDtcbiAgfVxuXG4gIHNldE1heEFtb3VudChtYXhBbW91bnQ6IGJpZ2ludCk6IE1vbmVyb091dHB1dFF1ZXJ5IHtcbiAgICB0aGlzLm1heEFtb3VudCA9IG1heEFtb3VudDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0VHhRdWVyeSgpOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICByZXR1cm4gdGhpcy50eFF1ZXJ5IGFzIE1vbmVyb1R4UXVlcnk7XG4gIH1cbiAgXG4gIHNldFR4UXVlcnkodHhRdWVyeTogTW9uZXJvVHhRdWVyeSk6IE1vbmVyb091dHB1dFF1ZXJ5IHtcbiAgICB0aGlzLnR4UXVlcnkgPSB0eFF1ZXJ5ID09PSB1bmRlZmluZWQgPyB1bmRlZmluZWQgOiB0eFF1ZXJ5IGluc3RhbmNlb2YgTW9uZXJvVHhRdWVyeSA/IHR4UXVlcnkgOiBuZXcgTW9uZXJvVHhRdWVyeSh0eFF1ZXJ5KTtcbiAgICBpZiAodHhRdWVyeSkgdGhpcy50eFF1ZXJ5Lm91dHB1dFF1ZXJ5ID0gdGhpcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U3ViYWRkcmVzc0luZGljZXMoKTogbnVtYmVyW10ge1xuICAgIHJldHVybiB0aGlzLnN1YmFkZHJlc3NJbmRpY2VzO1xuICB9XG4gIFxuICBzZXRTdWJhZGRyZXNzSW5kaWNlcyhzdWJhZGRyZXNzSW5kaWNlczogbnVtYmVyW10pOiBNb25lcm9PdXRwdXRRdWVyeSB7XG4gICAgdGhpcy5zdWJhZGRyZXNzSW5kaWNlcyA9IHN1YmFkZHJlc3NJbmRpY2VzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBtZWV0c0NyaXRlcmlhKG91dHB1dDogTW9uZXJvT3V0cHV0V2FsbGV0LCBxdWVyeVBhcmVudCA9IHRydWUpOiBib29sZWFuIHtcbiAgICBpZiAoIShvdXRwdXQgaW5zdGFuY2VvZiBNb25lcm9PdXRwdXRXYWxsZXQpKSB0aHJvdyBuZXcgRXJyb3IoXCJPdXRwdXQgbm90IGdpdmVuIHRvIE1vbmVyb091dHB1dFF1ZXJ5Lm1lZXRzQ3JpdGVyaWEob3V0cHV0KVwiKTtcbiAgICBcbiAgICAvLyBmaWx0ZXIgb24gb3V0cHV0XG4gICAgaWYgKHRoaXMuZ2V0QWNjb3VudEluZGV4KCkgIT09IHVuZGVmaW5lZCAmJiB0aGlzLmdldEFjY291bnRJbmRleCgpICE9PSBvdXRwdXQuZ2V0QWNjb3VudEluZGV4KCkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAodGhpcy5nZXRTdWJhZGRyZXNzSW5kZXgoKSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuZ2V0U3ViYWRkcmVzc0luZGV4KCkgIT09IG91dHB1dC5nZXRTdWJhZGRyZXNzSW5kZXgoKSkgcmV0dXJuIGZhbHNlO1xuICAgIGlmICh0aGlzLmdldEFtb3VudCgpICE9PSB1bmRlZmluZWQgJiYgdGhpcy5nZXRBbW91bnQoKSAhPT0gb3V0cHV0LmdldEFtb3VudCgpKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKHRoaXMuZ2V0SXNTcGVudCgpICE9PSB1bmRlZmluZWQgJiYgdGhpcy5nZXRJc1NwZW50KCkgIT09IG91dHB1dC5nZXRJc1NwZW50KCkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAodGhpcy5nZXRJc0Zyb3plbigpICE9PSB1bmRlZmluZWQgJiYgdGhpcy5nZXRJc0Zyb3plbigpICE9PSBvdXRwdXQuZ2V0SXNGcm96ZW4oKSkgcmV0dXJuIGZhbHNlO1xuICAgIFxuICAgIC8vIGZpbHRlciBvbiBvdXRwdXQncyBrZXkgaW1hZ2VcbiAgICBpZiAodGhpcy5nZXRLZXlJbWFnZSgpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmIChvdXRwdXQuZ2V0S2V5SW1hZ2UoKSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gZmFsc2U7XG4gICAgICBpZiAodGhpcy5nZXRLZXlJbWFnZSgpLmdldEhleCgpICE9PSB1bmRlZmluZWQgJiYgdGhpcy5nZXRLZXlJbWFnZSgpLmdldEhleCgpICE9PSBvdXRwdXQuZ2V0S2V5SW1hZ2UoKS5nZXRIZXgoKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgaWYgKHRoaXMuZ2V0S2V5SW1hZ2UoKS5nZXRTaWduYXR1cmUoKSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuZ2V0S2V5SW1hZ2UoKS5nZXRTaWduYXR1cmUoKSAhPT0gb3V0cHV0LmdldEtleUltYWdlKCkuZ2V0U2lnbmF0dXJlKCkpIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgXG4gICAgLy8gZmlsdGVyIG9uIGV4dGVuc2lvbnNcbiAgICBpZiAodGhpcy5nZXRTdWJhZGRyZXNzSW5kaWNlcygpICE9PSB1bmRlZmluZWQgJiYgIXRoaXMuZ2V0U3ViYWRkcmVzc0luZGljZXMoKS5pbmNsdWRlcyhvdXRwdXQuZ2V0U3ViYWRkcmVzc0luZGV4KCkpKSByZXR1cm4gZmFsc2U7XG4gICAgXG4gICAgLy8gZmlsdGVyIHdpdGggdHggcXVlcnlcbiAgICBpZiAodGhpcy5nZXRUeFF1ZXJ5KCkgJiYgIXRoaXMuZ2V0VHhRdWVyeSgpLm1lZXRzQ3JpdGVyaWEob3V0cHV0LmdldFR4KCkgYXMgTW9uZXJvVHhXYWxsZXQsIGZhbHNlKSkgcmV0dXJuIGZhbHNlO1xuICAgIFxuICAgIC8vIGZpbHRlciBvbiByZW1haW5pbmcgZmllbGRzXG4gICAgaWYgKHRoaXMuZ2V0TWluQW1vdW50KCkgIT09IHVuZGVmaW5lZCAmJiAob3V0cHV0LmdldEFtb3VudCgpID09PSB1bmRlZmluZWQgfHwgb3V0cHV0LmdldEFtb3VudCgpIDwgdGhpcy5nZXRNaW5BbW91bnQoKSkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAodGhpcy5nZXRNYXhBbW91bnQoKSAhPT0gdW5kZWZpbmVkICYmIChvdXRwdXQuZ2V0QW1vdW50KCkgPT09IHVuZGVmaW5lZCB8fCBvdXRwdXQuZ2V0QW1vdW50KCkgPiB0aGlzLmdldE1heEFtb3VudCgpKSkgcmV0dXJuIGZhbHNlO1xuICAgIFxuICAgIC8vIG91dHB1dCBtZWV0cyBxdWVyeVxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0gT1ZFUlJJREUgQ09WQVJJQU5UIFJFVFVSTiBUWVBFUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICBzZXRUeCh0eDogTW9uZXJvVHgpOiBNb25lcm9PdXRwdXRRdWVyeSB7XG4gICAgc3VwZXIuc2V0VHgodHgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0QWNjb3VudEluZGV4KGFjY291bnRJbmRleDogbnVtYmVyKTogTW9uZXJvT3V0cHV0UXVlcnkge1xuICAgIHN1cGVyLnNldEFjY291bnRJbmRleChhY2NvdW50SW5kZXgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0U3ViYWRkcmVzc0luZGV4KHN1YmFkZHJlc3NJbmRleDogbnVtYmVyKTogTW9uZXJvT3V0cHV0UXVlcnkge1xuICAgIHN1cGVyLnNldFN1YmFkZHJlc3NJbmRleChzdWJhZGRyZXNzSW5kZXgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0SXNTcGVudChpc1NwZW50OiBib29sZWFuKTogTW9uZXJvT3V0cHV0UXVlcnkge1xuICAgIHN1cGVyLnNldElzU3BlbnQoaXNTcGVudCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHNldElzRnJvemVuKGlzRnJvemVuOiBib29sZWFuKTogTW9uZXJvT3V0cHV0UXVlcnkge1xuICAgIHN1cGVyLnNldElzRnJvemVuKGlzRnJvemVuKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgc2V0S2V5SW1hZ2Uoa2V5SW1hZ2U6IE1vbmVyb0tleUltYWdlKTogTW9uZXJvT3V0cHV0UXVlcnkge1xuICAgIHN1cGVyLnNldEtleUltYWdlKGtleUltYWdlKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldEFtb3VudChhbW91bnQ6IGJpZ2ludCk6IE1vbmVyb091dHB1dFF1ZXJ5IHtcbiAgICBzdXBlci5zZXRBbW91bnQoYW1vdW50KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldEluZGV4KGluZGV4OiBudW1iZXIpOiBNb25lcm9PdXRwdXRRdWVyeSB7XG4gICAgc3VwZXIuc2V0SW5kZXgoaW5kZXgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0UmluZ091dHB1dEluZGljZXMocmluZ091dHB1dEluZGljZXM6IG51bWJlcltdKTogTW9uZXJvT3V0cHV0UXVlcnkge1xuICAgIHN1cGVyLnNldFJpbmdPdXRwdXRJbmRpY2VzKHJpbmdPdXRwdXRJbmRpY2VzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldFN0ZWFsdGhQdWJsaWNLZXkoc3RlYWx0aFB1YmxpY0tleTogc3RyaW5nKTogTW9uZXJvT3V0cHV0UXVlcnkge1xuICAgIHN1cGVyLnNldFN0ZWFsdGhQdWJsaWNLZXkoc3RlYWx0aFB1YmxpY0tleSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLFlBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTs7QUFFQSxJQUFBQyxtQkFBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBOzs7QUFHQSxJQUFBRSxjQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7O0FBRUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUcsaUJBQWlCLFNBQVNDLDJCQUFrQixDQUFDOzs7Ozs7O0VBT2hFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0VDLFdBQVdBLENBQUNDLEtBQWtDLEVBQUU7SUFDOUMsS0FBSyxDQUFDQSxLQUFLLENBQUM7SUFDWixJQUFJLElBQUksQ0FBQ0MsU0FBUyxLQUFLQyxTQUFTLElBQUksT0FBTyxJQUFJLENBQUNELFNBQVMsS0FBSyxRQUFRLEVBQUUs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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroOutputWallet.d.ts b/dist/src/main/ts/wallet/model/MoneroOutputWallet.d.ts new file mode 100644 index 000000000..603483b04 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroOutputWallet.d.ts @@ -0,0 +1,55 @@ +import MoneroKeyImage from "../../daemon/model/MoneroKeyImage"; +import MoneroOutput from "../../daemon/model/MoneroOutput"; +import MoneroTx from "../../daemon/model/MoneroTx"; +import MoneroTxWallet from "./MoneroTxWallet"; +/** + * Models a Monero output with wallet extensions. + */ +export default class MoneroOutputWallet extends MoneroOutput { + accountIndex: number; + subaddressIndex: number; + isSpent: boolean; + isFrozen: boolean; + isLocked: boolean; + /** + * Construct the model. + * + * @param {MoneroOutputWallet} [output] is existing state to initialize from (optional) + */ + constructor(output?: Partial); + getTx(): MoneroTxWallet; + setTx(tx: MoneroTx): MoneroOutputWallet; + getAccountIndex(): number; + setAccountIndex(accountIndex: number): MoneroOutputWallet; + getSubaddressIndex(): number; + setSubaddressIndex(subaddressIndex: number): MoneroOutputWallet; + getIsSpent(): boolean; + setIsSpent(isSpent: boolean): MoneroOutputWallet; + /** + * Indicates if this output has been deemed 'malicious' and will therefore + * not be spent by the wallet. + * + * @return Boolean is whether or not this output is frozen + */ + getIsFrozen(): boolean; + setIsFrozen(isFrozen: boolean): MoneroOutputWallet; + getIsLocked(): boolean; + copy(): MoneroOutputWallet; + toJson(): any; + /** + * Updates this output by merging the latest information from the given + * output. + * + * Merging can modify or build references to the output given so it + * should not be re-used or it should be copied before calling this method. + * + * @param output is the output to merge into this one + */ + merge(output: MoneroOutputWallet): MoneroOutputWallet; + toString(indent?: number): string; + setKeyImage(keyImage: MoneroKeyImage): MoneroOutputWallet; + setAmount(amount: bigint): MoneroOutputWallet; + setIndex(index: number): MoneroOutputWallet; + setRingOutputIndices(ringOutputIndices: number[]): MoneroOutputWallet; + setStealthPublicKey(stealthPublicKey: string): MoneroOutputWallet; +} diff --git a/dist/src/main/ts/wallet/model/MoneroOutputWallet.js b/dist/src/main/ts/wallet/model/MoneroOutputWallet.js new file mode 100644 index 000000000..d01ccb1db --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroOutputWallet.js @@ -0,0 +1,152 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); +var _MoneroError = _interopRequireDefault(require("../../common/MoneroError")); + +var _MoneroOutput = _interopRequireDefault(require("../../daemon/model/MoneroOutput")); + +var _MoneroTxWallet = _interopRequireDefault(require("./MoneroTxWallet")); + +/** + * Models a Monero output with wallet extensions. + */ +class MoneroOutputWallet extends _MoneroOutput.default { + + + + + + + + /** + * Construct the model. + * + * @param {MoneroOutputWallet} [output] is existing state to initialize from (optional) + */ + constructor(output) { + super(output); + } + + getTx() { + return super.getTx(); + } + + setTx(tx) { + if (tx !== undefined && !(tx instanceof _MoneroTxWallet.default)) throw new _MoneroError.default("Wallet output's transaction must be of type MoneroTxWallet"); + super.setTx(tx); + return this; + } + + getAccountIndex() { + return this.accountIndex; + } + + setAccountIndex(accountIndex) { + this.accountIndex = accountIndex; + return this; + } + + getSubaddressIndex() { + return this.subaddressIndex; + } + + setSubaddressIndex(subaddressIndex) { + this.subaddressIndex = subaddressIndex; + return this; + } + + getIsSpent() { + return this.isSpent; + } + + setIsSpent(isSpent) { + this.isSpent = isSpent; + return this; + } + + /** + * Indicates if this output has been deemed 'malicious' and will therefore + * not be spent by the wallet. + * + * @return Boolean is whether or not this output is frozen + */ + getIsFrozen() { + return this.isFrozen; + } + + setIsFrozen(isFrozen) { + this.isFrozen = isFrozen; + return this; + } + + getIsLocked() { + if (this.getTx() === undefined) return undefined; + return this.getTx().getIsLocked(); + } + + copy() { + return new MoneroOutputWallet(this.toJson()); + } + + toJson() { + let json = Object.assign({}, this, super.toJson()); + delete json.tx; + return json; + } + + /** + * Updates this output by merging the latest information from the given + * output. + * + * Merging can modify or build references to the output given so it + * should not be re-used or it should be copied before calling this method. + * + * @param output is the output to merge into this one + */ + merge(output) { + (0, _assert.default)(output instanceof MoneroOutputWallet); + if (this === output) return; + super.merge(output); + this.setAccountIndex(_GenUtils.default.reconcile(this.getAccountIndex(), output.getAccountIndex())); + this.setSubaddressIndex(_GenUtils.default.reconcile(this.getSubaddressIndex(), output.getSubaddressIndex())); + this.setIsSpent(_GenUtils.default.reconcile(this.getIsSpent(), output.getIsSpent(), { resolveTrue: true })); // output can become spent + this.setIsFrozen(_GenUtils.default.reconcile(this.getIsFrozen(), output.getIsFrozen())); + return this; + } + + toString(indent = 0) { + let str = super.toString(indent) + "\n"; + str += _GenUtils.default.kvLine("Account index", this.getAccountIndex(), indent); + str += _GenUtils.default.kvLine("Subaddress index", this.getSubaddressIndex(), indent); + str += _GenUtils.default.kvLine("Is spent", this.getIsSpent(), indent); + str += _GenUtils.default.kvLine("Is frozen", this.getIsFrozen(), indent); + return str.slice(0, str.length - 1); // strip last newline + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setKeyImage(keyImage) { + super.setKeyImage(keyImage); + return this; + } + + setAmount(amount) { + super.setAmount(amount); + return this; + } + + setIndex(index) { + super.setIndex(index); + return this; + } + + setRingOutputIndices(ringOutputIndices) { + super.setRingOutputIndices(ringOutputIndices); + return this; + } + + setStealthPublicKey(stealthPublicKey) { + super.setStealthPublicKey(stealthPublicKey); + return this; + } +}exports.default = MoneroOutputWallet; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTW9uZXJvRXJyb3IiLCJfTW9uZXJvT3V0cHV0IiwiX01vbmVyb1R4V2FsbGV0IiwiTW9uZXJvT3V0cHV0V2FsbGV0IiwiTW9uZXJvT3V0cHV0IiwiY29uc3RydWN0b3IiLCJvdXRwdXQiLCJnZXRUeCIsInNldFR4IiwidHgiLCJ1bmRlZmluZWQiLCJNb25lcm9UeFdhbGxldCIsIk1vbmVyb0Vycm9yIiwiZ2V0QWNjb3VudEluZGV4IiwiYWNjb3VudEluZGV4Iiwic2V0QWNjb3VudEluZGV4IiwiZ2V0U3ViYWRkcmVzc0luZGV4Iiwic3ViYWRkcmVzc0luZGV4Iiwic2V0U3ViYWRkcmVzc0luZGV4IiwiZ2V0SXNTcGVudCIsImlzU3BlbnQiLCJzZXRJc1NwZW50IiwiZ2V0SXNGcm96ZW4iLCJpc0Zyb3plbiIsInNldElzRnJvemVuIiwiZ2V0SXNMb2NrZWQiLCJjb3B5IiwidG9Kc29uIiwianNvbiIsIk9iamVjdCIsImFzc2lnbiIsIm1lcmdlIiwiYXNzZXJ0IiwiR2VuVXRpbHMiLCJyZWNvbmNpbGUiLCJyZXNvbHZlVHJ1ZSIsInRvU3RyaW5nIiwiaW5kZW50Iiwic3RyIiwia3ZMaW5lIiwic2xpY2UiLCJsZW5ndGgiLCJzZXRLZXlJbWFnZSIsImtleUltYWdlIiwic2V0QW1vdW50IiwiYW1vdW50Iiwic2V0SW5kZXgiLCJpbmRleCIsInNldFJpbmdPdXRwdXRJbmRpY2VzIiwicmluZ091dHB1dEluZGljZXMiLCJzZXRTdGVhbHRoUHVibGljS2V5Iiwic3RlYWx0aFB1YmxpY0tleSIsImV4cG9ydHMiLCJkZWZhdWx0Il0sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21haW4vdHMvd2FsbGV0L21vZGVsL01vbmVyb091dHB1dFdhbGxldC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi4vLi4vY29tbW9uL0dlblV0aWxzXCI7XG5pbXBvcnQgTW9uZXJvRXJyb3IgZnJvbSBcIi4uLy4uL2NvbW1vbi9Nb25lcm9FcnJvclwiO1xuaW1wb3J0IE1vbmVyb0tleUltYWdlIGZyb20gXCIuLi8uLi9kYWVtb24vbW9kZWwvTW9uZXJvS2V5SW1hZ2VcIjtcbmltcG9ydCBNb25lcm9PdXRwdXQgZnJvbSBcIi4uLy4uL2RhZW1vbi9tb2RlbC9Nb25lcm9PdXRwdXRcIjtcbmltcG9ydCBNb25lcm9UeCBmcm9tIFwiLi4vLi4vZGFlbW9uL21vZGVsL01vbmVyb1R4XCI7XG5pbXBvcnQgTW9uZXJvVHhXYWxsZXQgZnJvbSBcIi4vTW9uZXJvVHhXYWxsZXRcIjtcblxuLyoqXG4gKiBNb2RlbHMgYSBNb25lcm8gb3V0cHV0IHdpdGggd2FsbGV0IGV4dGVuc2lvbnMuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb091dHB1dFdhbGxldCBleHRlbmRzIE1vbmVyb091dHB1dCB7XG5cbiAgYWNjb3VudEluZGV4OiBudW1iZXI7XG4gIHN1YmFkZHJlc3NJbmRleDogbnVtYmVyO1xuICBpc1NwZW50OiBib29sZWFuO1xuICBpc0Zyb3plbjogYm9vbGVhbjtcbiAgaXNMb2NrZWQ6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdCB0aGUgbW9kZWwuXG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb091dHB1dFdhbGxldH0gW291dHB1dF0gaXMgZXhpc3Rpbmcgc3RhdGUgdG8gaW5pdGlhbGl6ZSBmcm9tIChvcHRpb25hbClcbiAgICovXG4gIGNvbnN0cnVjdG9yKG91dHB1dD86IFBhcnRpYWw8TW9uZXJvT3V0cHV0V2FsbGV0Pikge1xuICAgIHN1cGVyKG91dHB1dCk7XG4gIH1cblxuICBnZXRUeCgpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgcmV0dXJuIHN1cGVyLmdldFR4KCkgYXMgTW9uZXJvVHhXYWxsZXQ7XG4gIH1cbiAgXG4gIHNldFR4KHR4OiBNb25lcm9UeCk6IE1vbmVyb091dHB1dFdhbGxldCB7XG4gICAgaWYgKHR4ICE9PSB1bmRlZmluZWQgJiYgISh0eCBpbnN0YW5jZW9mIE1vbmVyb1R4V2FsbGV0KSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiV2FsbGV0IG91dHB1dCdzIHRyYW5zYWN0aW9uIG11c3QgYmUgb2YgdHlwZSBNb25lcm9UeFdhbGxldFwiKTtcbiAgICBzdXBlci5zZXRUeCh0eCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEFjY291bnRJbmRleCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmFjY291bnRJbmRleDtcbiAgfVxuXG4gIHNldEFjY291bnRJbmRleChhY2NvdW50SW5kZXg6IG51bWJlcik6IE1vbmVyb091dHB1dFdhbGxldCB7XG4gICAgdGhpcy5hY2NvdW50SW5kZXggPSBhY2NvdW50SW5kZXg7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRTdWJhZGRyZXNzSW5kZXgoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5zdWJhZGRyZXNzSW5kZXg7XG4gIH1cblxuICBzZXRTdWJhZGRyZXNzSW5kZXgoc3ViYWRkcmVzc0luZGV4OiBudW1iZXIpOiBNb25lcm9PdXRwdXRXYWxsZXQge1xuICAgIHRoaXMuc3ViYWRkcmVzc0luZGV4ID0gc3ViYWRkcmVzc0luZGV4O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRJc1NwZW50KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzU3BlbnQ7XG4gIH1cblxuICBzZXRJc1NwZW50KGlzU3BlbnQ6IGJvb2xlYW4pOiBNb25lcm9PdXRwdXRXYWxsZXQge1xuICAgIHRoaXMuaXNTcGVudCA9IGlzU3BlbnQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBJbmRpY2F0ZXMgaWYgdGhpcyBvdXRwdXQgaGFzIGJlZW4gZGVlbWVkICdtYWxpY2lvdXMnIGFuZCB3aWxsIHRoZXJlZm9yZVxuICAgKiBub3QgYmUgc3BlbnQgYnkgdGhlIHdhbGxldC5cbiAgICogXG4gICAqIEByZXR1cm4gQm9vbGVhbiBpcyB3aGV0aGVyIG9yIG5vdCB0aGlzIG91dHB1dCBpcyBmcm96ZW5cbiAgICovXG4gIGdldElzRnJvemVuKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzRnJvemVuO1xuICB9XG5cbiAgc2V0SXNGcm96ZW4oaXNGcm96ZW46IGJvb2xlYW4pOiBNb25lcm9PdXRwdXRXYWxsZXQge1xuICAgIHRoaXMuaXNGcm96ZW4gPSBpc0Zyb3plbjtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0SXNMb2NrZWQoKTogYm9vbGVhbiB7XG4gICAgaWYgKHRoaXMuZ2V0VHgoKSA9PT0gdW5kZWZpbmVkKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIHJldHVybiAodGhpcy5nZXRUeCgpIGFzIE1vbmVyb1R4V2FsbGV0KS5nZXRJc0xvY2tlZCgpO1xuICB9XG4gIFxuICBjb3B5KCk6IE1vbmVyb091dHB1dFdhbGxldCB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9PdXRwdXRXYWxsZXQodGhpcy50b0pzb24oKSk7XG4gIH1cbiAgXG4gIHRvSnNvbigpOiBhbnkge1xuICAgIGxldCBqc29uOiBhbnkgPSBPYmplY3QuYXNzaWduKHt9LCB0aGlzLCBzdXBlci50b0pzb24oKSk7XG4gICAgZGVsZXRlIGpzb24udHg7XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBVcGRhdGVzIHRoaXMgb3V0cHV0IGJ5IG1lcmdpbmcgdGhlIGxhdGVzdCBpbmZvcm1hdGlvbiBmcm9tIHRoZSBnaXZlblxuICAgKiBvdXRwdXQuXG4gICAqIFxuICAgKiBNZXJnaW5nIGNhbiBtb2RpZnkgb3IgYnVpbGQgcmVmZXJlbmNlcyB0byB0aGUgb3V0cHV0IGdpdmVuIHNvIGl0XG4gICAqIHNob3VsZCBub3QgYmUgcmUtdXNlZCBvciBpdCBzaG91bGQgYmUgY29waWVkIGJlZm9yZSBjYWxsaW5nIHRoaXMgbWV0aG9kLlxuICAgKiBcbiAgICogQHBhcmFtIG91dHB1dCBpcyB0aGUgb3V0cHV0IHRvIG1lcmdlIGludG8gdGhpcyBvbmVcbiAgICovXG4gIG1lcmdlKG91dHB1dDogTW9uZXJvT3V0cHV0V2FsbGV0KTogTW9uZXJvT3V0cHV0V2FsbGV0IHtcbiAgICBhc3NlcnQob3V0cHV0IGluc3RhbmNlb2YgTW9uZXJvT3V0cHV0V2FsbGV0KTtcbiAgICBpZiAodGhpcyA9PT0gb3V0cHV0KSByZXR1cm47XG4gICAgc3VwZXIubWVyZ2Uob3V0cHV0KTtcbiAgICB0aGlzLnNldEFjY291bnRJbmRleChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRBY2NvdW50SW5kZXgoKSwgb3V0cHV0LmdldEFjY291bnRJbmRleCgpKSk7XG4gICAgdGhpcy5zZXRTdWJhZGRyZXNzSW5kZXgoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0U3ViYWRkcmVzc0luZGV4KCksIG91dHB1dC5nZXRTdWJhZGRyZXNzSW5kZXgoKSkpO1xuICAgIHRoaXMuc2V0SXNTcGVudChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRJc1NwZW50KCksIG91dHB1dC5nZXRJc1NwZW50KCksIHtyZXNvbHZlVHJ1ZTogdHJ1ZX0pKTsgLy8gb3V0cHV0IGNhbiBiZWNvbWUgc3BlbnRcbiAgICB0aGlzLnNldElzRnJvemVuKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldElzRnJvemVuKCksIG91dHB1dC5nZXRJc0Zyb3plbigpKSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHRvU3RyaW5nKGluZGVudCA9IDApOiBzdHJpbmcge1xuICAgIGxldCBzdHIgPSBzdXBlci50b1N0cmluZyhpbmRlbnQpICsgXCJcXG5cIlxuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJBY2NvdW50IGluZGV4XCIsIHRoaXMuZ2V0QWNjb3VudEluZGV4KCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIlN1YmFkZHJlc3MgaW5kZXhcIiwgdGhpcy5nZXRTdWJhZGRyZXNzSW5kZXgoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiSXMgc3BlbnRcIiwgdGhpcy5nZXRJc1NwZW50KCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIklzIGZyb3plblwiLCB0aGlzLmdldElzRnJvemVuKCksIGluZGVudCk7XG4gICAgcmV0dXJuIHN0ci5zbGljZSgwLCBzdHIubGVuZ3RoIC0gMSk7ICAvLyBzdHJpcCBsYXN0IG5ld2xpbmVcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tIE9WRVJSSURFIENPVkFSSUFOVCBSRVRVUk4gVFlQRVMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgc2V0S2V5SW1hZ2Uoa2V5SW1hZ2U6IE1vbmVyb0tleUltYWdlKTogTW9uZXJvT3V0cHV0V2FsbGV0IHtcbiAgICBzdXBlci5zZXRLZXlJbWFnZShrZXlJbWFnZSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHNldEFtb3VudChhbW91bnQ6IGJpZ2ludCk6IE1vbmVyb091dHB1dFdhbGxldCB7XG4gICAgc3VwZXIuc2V0QW1vdW50KGFtb3VudCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHNldEluZGV4KGluZGV4OiBudW1iZXIpOiBNb25lcm9PdXRwdXRXYWxsZXQge1xuICAgIHN1cGVyLnNldEluZGV4KGluZGV4KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgc2V0UmluZ091dHB1dEluZGljZXMocmluZ091dHB1dEluZGljZXM6IG51bWJlcltdKTogTW9uZXJvT3V0cHV0V2FsbGV0IHtcbiAgICBzdXBlci5zZXRSaW5nT3V0cHV0SW5kaWNlcyhyaW5nT3V0cHV0SW5kaWNlcyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHNldFN0ZWFsdGhQdWJsaWNLZXkoc3RlYWx0aFB1YmxpY0tleTogc3RyaW5nKTogTW9uZXJvT3V0cHV0V2FsbGV0IHtcbiAgICBzdXBlci5zZXRTdGVhbHRoUHVibGljS2V5KHN0ZWFsdGhQdWJsaWNLZXkpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJ5TEFBQSxJQUFBQSxPQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxTQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRSxZQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7O0FBRUEsSUFBQUcsYUFBQSxHQUFBSixzQkFBQSxDQUFBQyxPQUFBOztBQUVBLElBQUFJLGVBQUEsR0FBQUwsc0JBQUEsQ0FBQUMsT0FBQTs7QUFFQTtBQUNBO0FBQ0E7QUFDZSxNQUFNSyxrQkFBa0IsU0FBU0MscUJBQVksQ0FBQzs7Ozs7Ozs7RUFRM0Q7QUFDRjtBQUNBO0FBQ0E7QUFDQTtFQUNFQyxXQUFXQSxDQUFDQyxNQUFvQyxFQUFFO0lBQ2hELEtBQUssQ0FBQ0EsTUFBTSxDQUFDO0VBQ2Y7O0VBRUFDLEtBQUtBLENBQUEsRUFBbUI7SUFDdEIsT0FBTyxLQUFLLENBQUNBLEtBQUssQ0FBQyxDQUFDO0VBQ3RCOztFQUVBQyxLQUFLQSxDQUFDQyxFQUFZLEVBQXNCO0lBQ3RDLElBQUlBLEVBQUUsS0FBS0MsU0FBUyxJQUFJLEVBQUVELEVBQUUsWUFBWUUsdUJBQWMsQ0FBQyxFQUFFLE1BQU0sSUFBSUMsb0JBQVcsQ0FBQyw0REFBNEQsQ0FBQztJQUM1SSxLQUFLLENBQUNKLEtBQUssQ0FBQ0MsRUFBRSxDQUFDO0lBQ2YsT0FBTyxJQUFJO0VBQ2I7O0VBRUFJLGVBQWVBLENBQUEsRUFBVztJQUN4QixPQUFPLElBQUksQ0FBQ0MsWUFBWTtFQUMxQjs7RUFFQUMsZUFBZUEsQ0FBQ0QsWUFBb0IsRUFBc0I7SUFDeEQsSUFBSSxDQUFDQSxZQUFZLEdBQUdBLFlBQVk7SUFDaEMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLGtCQUFrQkEsQ0FBQSxFQUFXO0lBQzNCLE9BQU8sSUFBSSxDQUFDQyxlQUFlO0VBQzdCOztFQUVBQyxr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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroSubaddress.d.ts b/dist/src/main/ts/wallet/model/MoneroSubaddress.d.ts new file mode 100644 index 000000000..7057c4802 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroSubaddress.d.ts @@ -0,0 +1,35 @@ +/** + * Monero subaddress model. + */ +export default class MoneroSubaddress { + accountIndex: number; + index: number; + address: string; + label: string; + balance: bigint; + unlockedBalance: bigint; + numUnspentOutputs: number; + isUsed: boolean; + numBlocksToUnlock: number; + constructor(subaddress?: Partial); + toJson(): any; + getAccountIndex(): number; + setAccountIndex(accountIndex: number): MoneroSubaddress; + getIndex(): number; + setIndex(index: number): MoneroSubaddress; + getAddress(): string; + setAddress(address: string): MoneroSubaddress; + getLabel(): string; + setLabel(label: string): MoneroSubaddress; + getBalance(): bigint; + setBalance(balance: bigint): MoneroSubaddress; + getUnlockedBalance(): bigint; + setUnlockedBalance(unlockedBalance: bigint): MoneroSubaddress; + getNumUnspentOutputs(): number; + setNumUnspentOutputs(numUnspentOutputs: number): MoneroSubaddress; + getIsUsed(): boolean; + setIsUsed(isUsed: boolean): MoneroSubaddress; + getNumBlocksToUnlock(): number; + setNumBlocksToUnlock(numBlocksToUnlock: number): MoneroSubaddress; + toString(indent?: number): string; +} diff --git a/dist/src/main/ts/wallet/model/MoneroSubaddress.js b/dist/src/main/ts/wallet/model/MoneroSubaddress.js new file mode 100644 index 000000000..8ead37cdb --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroSubaddress.js @@ -0,0 +1,126 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); + +/** + * Monero subaddress model. + */ +class MoneroSubaddress { + + + + + + + + + + + + constructor(subaddress) { + Object.assign(this, subaddress); + if (this.balance !== undefined && typeof this.balance !== "bigint") this.balance = BigInt(this.balance); + if (this.unlockedBalance !== undefined && typeof this.unlockedBalance !== "bigint") this.unlockedBalance = BigInt(this.unlockedBalance); + } + + toJson() { + let json = Object.assign({}, this); + if (json.balance !== undefined) json.balance = json.balance.toString(); + if (json.unlockedBalance !== undefined) json.unlockedBalance = json.unlockedBalance.toString(); + return json; + } + + getAccountIndex() { + return this.accountIndex; + } + + setAccountIndex(accountIndex) { + this.accountIndex = accountIndex; + return this; + } + + getIndex() { + return this.index; + } + + setIndex(index) { + this.index = index; + return this; + } + + getAddress() { + return this.address; + } + + setAddress(address) { + this.address = address; + return this; + } + + getLabel() { + return this.label; + } + + setLabel(label) { + this.label = label; + return this; + } + + getBalance() { + return this.balance; + } + + setBalance(balance) { + this.balance = balance; + return this; + } + + getUnlockedBalance() { + return this.unlockedBalance; + } + + setUnlockedBalance(unlockedBalance) { + this.unlockedBalance = unlockedBalance; + return this; + } + + getNumUnspentOutputs() { + return this.numUnspentOutputs; + } + + setNumUnspentOutputs(numUnspentOutputs) { + this.numUnspentOutputs = numUnspentOutputs; + return this; + } + + getIsUsed() { + return this.isUsed; + } + + setIsUsed(isUsed) { + this.isUsed = isUsed; + return this; + } + + getNumBlocksToUnlock() { + return this.numBlocksToUnlock; + } + + setNumBlocksToUnlock(numBlocksToUnlock) { + this.numBlocksToUnlock = numBlocksToUnlock; + return this; + } + + toString(indent = 0) { + let str = ""; + str += _GenUtils.default.kvLine("Account index", this.getAccountIndex(), indent); + str += _GenUtils.default.kvLine("Subaddress index", this.getIndex(), indent); + str += _GenUtils.default.kvLine("Address", this.getAddress(), indent); + str += _GenUtils.default.kvLine("Label", this.getLabel(), indent); + str += _GenUtils.default.kvLine("Balance", this.getBalance(), indent); + str += _GenUtils.default.kvLine("Unlocked balance", this.getUnlockedBalance(), indent); + str += _GenUtils.default.kvLine("Num unspent outputs", this.getNumUnspentOutputs(), indent); + str += _GenUtils.default.kvLine("Is used", this.getIsUsed(), indent); + str += _GenUtils.default.kvLine("Num blocks to unlock", this.getNumBlocksToUnlock(), indent); + return str.slice(0, str.length - 1); // strip last newline + } +}exports.default = MoneroSubaddress; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfR2VuVXRpbHMiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIk1vbmVyb1N1YmFkZHJlc3MiLCJjb25zdHJ1Y3RvciIsInN1YmFkZHJlc3MiLCJPYmplY3QiLCJhc3NpZ24iLCJiYWxhbmNlIiwidW5kZWZpbmVkIiwiQmlnSW50IiwidW5sb2NrZWRCYWxhbmNlIiwidG9Kc29uIiwianNvbiIsInRvU3RyaW5nIiwiZ2V0QWNjb3VudEluZGV4IiwiYWNjb3VudEluZGV4Iiwic2V0QWNjb3VudEluZGV4IiwiZ2V0SW5kZXgiLCJpbmRleCIsInNldEluZGV4IiwiZ2V0QWRkcmVzcyIsImFkZHJlc3MiLCJzZXRBZGRyZXNzIiwiZ2V0TGFiZWwiLCJsYWJlbCIsInNldExhYmVsIiwiZ2V0QmFsYW5jZSIsInNldEJhbGFuY2UiLCJnZXRVbmxvY2tlZEJhbGFuY2UiLCJzZXRVbmxvY2tlZEJhbGFuY2UiLCJnZXROdW1VbnNwZW50T3V0cHV0cyIsIm51bVVuc3BlbnRPdXRwdXRzIiwic2V0TnVtVW5zcGVudE91dHB1dHMiLCJnZXRJc1VzZWQiLCJpc1VzZWQiLCJzZXRJc1VzZWQiLCJnZXROdW1CbG9ja3NUb1VubG9jayIsIm51bUJsb2Nrc1RvVW5sb2NrIiwic2V0TnVtQmxvY2tzVG9VbmxvY2siLCJpbmRlbnQiLCJzdHIiLCJHZW5VdGlscyIsImt2TGluZSIsInNsaWNlIiwibGVuZ3RoIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy93YWxsZXQvbW9kZWwvTW9uZXJvU3ViYWRkcmVzcy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgR2VuVXRpbHMgZnJvbSBcIi4uLy4uL2NvbW1vbi9HZW5VdGlsc1wiO1xuXG4vKipcbiAqIE1vbmVybyBzdWJhZGRyZXNzIG1vZGVsLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9TdWJhZGRyZXNzIHtcblxuICBhY2NvdW50SW5kZXg6IG51bWJlcjtcbiAgaW5kZXg6IG51bWJlcjtcbiAgYWRkcmVzczogc3RyaW5nO1xuICBsYWJlbDogc3RyaW5nO1xuICBiYWxhbmNlOiBiaWdpbnQ7XG4gIHVubG9ja2VkQmFsYW5jZTogYmlnaW50O1xuICBudW1VbnNwZW50T3V0cHV0czogbnVtYmVyO1xuICBpc1VzZWQ6IGJvb2xlYW47XG4gIG51bUJsb2Nrc1RvVW5sb2NrOiBudW1iZXI7XG4gIFxuICBjb25zdHJ1Y3RvcihzdWJhZGRyZXNzPzogUGFydGlhbDxNb25lcm9TdWJhZGRyZXNzPikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgc3ViYWRkcmVzcyk7XG4gICAgaWYgKHRoaXMuYmFsYW5jZSAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLmJhbGFuY2UgIT09IFwiYmlnaW50XCIpIHRoaXMuYmFsYW5jZSA9IEJpZ0ludCh0aGlzLmJhbGFuY2UpO1xuICAgIGlmICh0aGlzLnVubG9ja2VkQmFsYW5jZSAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLnVubG9ja2VkQmFsYW5jZSAhPT0gXCJiaWdpbnRcIikgdGhpcy51bmxvY2tlZEJhbGFuY2UgPSBCaWdJbnQodGhpcy51bmxvY2tlZEJhbGFuY2UpO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICBsZXQganNvbjogYW55ID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcyk7XG4gICAgaWYgKGpzb24uYmFsYW5jZSAhPT0gdW5kZWZpbmVkKSBqc29uLmJhbGFuY2UgPSBqc29uLmJhbGFuY2UudG9TdHJpbmcoKTtcbiAgICBpZiAoanNvbi51bmxvY2tlZEJhbGFuY2UgIT09IHVuZGVmaW5lZCkganNvbi51bmxvY2tlZEJhbGFuY2UgPSBqc29uLnVubG9ja2VkQmFsYW5jZS50b1N0cmluZygpO1xuICAgIHJldHVybiBqc29uO1xuICB9XG4gIFxuICBnZXRBY2NvdW50SW5kZXgoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5hY2NvdW50SW5kZXg7XG4gIH1cblxuICBzZXRBY2NvdW50SW5kZXgoYWNjb3VudEluZGV4OiBudW1iZXIpOiBNb25lcm9TdWJhZGRyZXNzIHtcbiAgICB0aGlzLmFjY291bnRJbmRleCA9IGFjY291bnRJbmRleDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldEluZGV4KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuaW5kZXg7XG4gIH1cblxuICBzZXRJbmRleChpbmRleDogbnVtYmVyKTogTW9uZXJvU3ViYWRkcmVzcyB7XG4gICAgdGhpcy5pbmRleCA9IGluZGV4O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRBZGRyZXNzKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuYWRkcmVzcztcbiAgfVxuXG4gIHNldEFkZHJlc3MoYWRkcmVzczogc3RyaW5nKTogTW9uZXJvU3ViYWRkcmVzcyB7XG4gICAgdGhpcy5hZGRyZXNzID0gYWRkcmVzcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldExhYmVsKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMubGFiZWw7XG4gIH1cblxuICBzZXRMYWJlbChsYWJlbDogc3RyaW5nKTogTW9uZXJvU3ViYWRkcmVzcyB7XG4gICAgdGhpcy5sYWJlbCA9IGxhYmVsO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0QmFsYW5jZSgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLmJhbGFuY2U7XG4gIH1cblxuICBzZXRCYWxhbmNlKGJhbGFuY2U6IGJpZ2ludCk6IE1vbmVyb1N1YmFkZHJlc3Mge1xuICAgIHRoaXMuYmFsYW5jZSA9IGJhbGFuY2U7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRVbmxvY2tlZEJhbGFuY2UoKTogYmlnaW50IHtcbiAgICByZXR1cm4gdGhpcy51bmxvY2tlZEJhbGFuY2U7XG4gIH1cblxuICBzZXRVbmxvY2tlZEJhbGFuY2UodW5sb2NrZWRCYWxhbmNlOiBiaWdpbnQpOiBNb25lcm9TdWJhZGRyZXNzIHtcbiAgICB0aGlzLnVubG9ja2VkQmFsYW5jZSA9IHVubG9ja2VkQmFsYW5jZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldE51bVVuc3BlbnRPdXRwdXRzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtVW5zcGVudE91dHB1dHM7XG4gIH1cblxuICBzZXROdW1VbnNwZW50T3V0cHV0cyhudW1VbnNwZW50T3V0cHV0czogbnVtYmVyKTogTW9uZXJvU3ViYWRkcmVzcyB7XG4gICAgdGhpcy5udW1VbnNwZW50T3V0cHV0cyA9IG51bVVuc3BlbnRPdXRwdXRzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0SXNVc2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzVXNlZDtcbiAgfVxuXG4gIHNldElzVXNlZChpc1VzZWQ6IGJvb2xlYW4pOiBNb25lcm9TdWJhZGRyZXNzIHtcbiAgICB0aGlzLmlzVXNlZCA9IGlzVXNlZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGdldE51bUJsb2Nrc1RvVW5sb2NrKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtQmxvY2tzVG9VbmxvY2s7XG4gIH1cblxuICBzZXROdW1CbG9ja3NUb1VubG9jayhudW1CbG9ja3NUb1VubG9jazogbnVtYmVyKTogTW9uZXJvU3ViYWRkcmVzcyB7XG4gICAgdGhpcy5udW1CbG9ja3NUb1VubG9jayA9IG51bUJsb2Nrc1RvVW5sb2NrO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICB0b1N0cmluZyhpbmRlbnQgPSAwKTogc3RyaW5nIHtcbiAgICBsZXQgc3RyID0gXCJcIjtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiQWNjb3VudCBpbmRleFwiLCB0aGlzLmdldEFjY291bnRJbmRleCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJTdWJhZGRyZXNzIGluZGV4XCIsIHRoaXMuZ2V0SW5kZXgoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiQWRkcmVzc1wiLCB0aGlzLmdldEFkZHJlc3MoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiTGFiZWxcIiwgdGhpcy5nZXRMYWJlbCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJCYWxhbmNlXCIsIHRoaXMuZ2V0QmFsYW5jZSgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJVbmxvY2tlZCBiYWxhbmNlXCIsIHRoaXMuZ2V0VW5sb2NrZWRCYWxhbmNlKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIk51bSB1bnNwZW50IG91dHB1dHNcIiwgdGhpcy5nZXROdW1VbnNwZW50T3V0cHV0cygpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJJcyB1c2VkXCIsIHRoaXMuZ2V0SXNVc2VkKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIk51bSBibG9ja3MgdG8gdW5sb2NrXCIsIHRoaXMuZ2V0TnVtQmxvY2tzVG9VbmxvY2soKSwgaW5kZW50KTtcbiAgICByZXR1cm4gc3RyLnNsaWNlKDAsIHN0ci5sZW5ndGggLSAxKTsgIC8vIHN0cmlwIGxhc3QgbmV3bGluZVxuICB9XG59XG4iXSwibWFwcGluZ3MiOiJ5TEFBQSxJQUFBQSxTQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7O0FBRUE7QUFDQTtBQUNBO0FBQ2UsTUFBTUMsZ0JBQWdCLENBQUM7Ozs7Ozs7Ozs7OztFQVlwQ0MsV0FBV0EsQ0FBQ0MsVUFBc0MsRUFBRTtJQUNsREMsTUFBTSxDQUFDQyxNQUFNLENBQUMsSUFBSSxFQUFFRixVQUFVLENBQUM7SUFDL0IsSUFBSSxJQUFJLENBQUNHLE9BQU8sS0FBS0MsU0FBUyxJQUFJLE9BQU8sSUFBSSxDQUFDRCxPQUFPLEtBQUssUUFBUSxFQUFFLElBQUksQ0FBQ0EsT0FBTyxHQUFHRSxNQUFNLENB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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroSyncResult.d.ts b/dist/src/main/ts/wallet/model/MoneroSyncResult.d.ts new file mode 100644 index 000000000..e707e8029 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroSyncResult.d.ts @@ -0,0 +1,12 @@ +/** + * Result from syncing a Monero wallet. + */ +export default class MoneroSyncResult { + numBlocksFetched: number; + receivedMoney: bigint; + constructor(numBlocksFetched: number, receivedMoney: bigint); + getNumBlocksFetched(): number; + setNumBlocksFetched(numBlocksFetched: number): MoneroSyncResult; + getReceivedMoney(): bigint; + setReceivedMoney(receivedMoney: bigint): MoneroSyncResult; +} diff --git a/dist/src/main/ts/wallet/model/MoneroSyncResult.js b/dist/src/main/ts/wallet/model/MoneroSyncResult.js new file mode 100644 index 000000000..8b26763a8 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroSyncResult.js @@ -0,0 +1,32 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Result from syncing a Monero wallet. + */ +class MoneroSyncResult { + + + + + constructor(numBlocksFetched, receivedMoney) { + this.setNumBlocksFetched(numBlocksFetched); + this.setReceivedMoney(receivedMoney); + } + + getNumBlocksFetched() { + return this.numBlocksFetched; + } + + setNumBlocksFetched(numBlocksFetched) { + this.numBlocksFetched = numBlocksFetched; + return this; + } + + getReceivedMoney() { + return this.receivedMoney; + } + + setReceivedMoney(receivedMoney) { + this.receivedMoney = receivedMoney; + return this; + } +}exports.default = MoneroSyncResult; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9TeW5jUmVzdWx0IiwiY29uc3RydWN0b3IiLCJudW1CbG9ja3NGZXRjaGVkIiwicmVjZWl2ZWRNb25leSIsInNldE51bUJsb2Nrc0ZldGNoZWQiLCJzZXRSZWNlaXZlZE1vbmV5IiwiZ2V0TnVtQmxvY2tzRmV0Y2hlZCIsImdldFJlY2VpdmVkTW9uZXkiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9TeW5jUmVzdWx0LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUmVzdWx0IGZyb20gc3luY2luZyBhIE1vbmVybyB3YWxsZXQuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb1N5bmNSZXN1bHQge1xuXG4gIG51bUJsb2Nrc0ZldGNoZWQ6IG51bWJlcjtcbiAgcmVjZWl2ZWRNb25leTogYmlnaW50O1xuICBcbiAgY29uc3RydWN0b3IobnVtQmxvY2tzRmV0Y2hlZDogbnVtYmVyLCByZWNlaXZlZE1vbmV5OiBiaWdpbnQpIHtcbiAgICB0aGlzLnNldE51bUJsb2Nrc0ZldGNoZWQobnVtQmxvY2tzRmV0Y2hlZCk7XG4gICAgdGhpcy5zZXRSZWNlaXZlZE1vbmV5KHJlY2VpdmVkTW9uZXkpO1xuICB9XG4gIFxuICBnZXROdW1CbG9ja3NGZXRjaGVkKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubnVtQmxvY2tzRmV0Y2hlZDtcbiAgfVxuICBcbiAgc2V0TnVtQmxvY2tzRmV0Y2hlZChudW1CbG9ja3NGZXRjaGVkOiBudW1iZXIpOiBNb25lcm9TeW5jUmVzdWx0IHtcbiAgICB0aGlzLm51bUJsb2Nrc0ZldGNoZWQgPSBudW1CbG9ja3NGZXRjaGVkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRSZWNlaXZlZE1vbmV5KCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMucmVjZWl2ZWRNb25leTtcbiAgfVxuICBcbiAgc2V0UmVjZWl2ZWRNb25leShyZWNlaXZlZE1vbmV5OiBiaWdpbnQpOiBNb25lcm9TeW5jUmVzdWx0IHtcbiAgICB0aGlzLnJlY2VpdmVkTW9uZXkgPSByZWNlaXZlZE1vbmV5O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJxR0FBQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSxnQkFBZ0IsQ0FBQzs7Ozs7RUFLcENDLFdBQVdBLENBQUNDLGdCQUF3QixFQUFFQyxhQUFxQixFQUFFO0lBQzNELElBQUksQ0FBQ0MsbUJBQW1CLENBQUNGLGdCQUFnQixDQUFDO0lBQzFDLElBQUksQ0FBQ0csZ0JBQWdCLENBQUNGLGFBQWEsQ0FBQztFQUN0Qzs7RUFFQUcsbUJBQW1CQSxDQUFBLEVBQVc7SUFDNUIsT0FBTyxJQUFJLENBQUNKLGdCQUFnQjtFQUM5Qjs7RUFFQUUsbUJBQW1CQSxDQUFDRixnQkFBd0IsRUFBb0I7SUFDOUQsSUFBSSxDQUFDQSxnQkFBZ0IsR0FBR0EsZ0JBQWdCO0lBQ3hDLE9BQU8sSUFBSTtFQUNiOztFQUVBSyxnQkFBZ0JBLENBQUEsRUFBVztJQUN6QixPQUFPLElBQUksQ0FBQ0osYUFBYTtFQUMzQjs7RUFFQUUsZ0JBQWdCQSxDQUFDRixhQUFxQixFQUFvQjtJQUN4RCxJQUFJLENBQUNBLGFBQWEsR0FBR0EsYUFBYTtJQUNsQyxPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNLLE9BQUEsQ0FBQUMsT0FBQSxHQUFBVCxnQkFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroTransfer.d.ts b/dist/src/main/ts/wallet/model/MoneroTransfer.d.ts new file mode 100644 index 000000000..29ac93590 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTransfer.d.ts @@ -0,0 +1,38 @@ +import MoneroTxWallet from "./MoneroTxWallet"; +/** + * Models a base transfer of funds to or from the wallet. + */ +export default class MoneroTransfer { + tx: MoneroTxWallet; + accountIndex: number; + amount: bigint; + /** + * Construct the transfer. + * + * @param {Partial} transfer existing state to initialize from (optional) + */ + constructor(transfer: Partial); + copy(): MoneroTransfer; + toJson(): any; + getTx(): MoneroTxWallet; + setTx(tx: MoneroTxWallet): MoneroTransfer; + getIsOutgoing(): boolean; + getIsIncoming(): boolean; + getAccountIndex(): number; + setAccountIndex(accountIndex: number): MoneroTransfer; + getAmount(): bigint; + setAmount(amount: bigint): MoneroTransfer; + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * Merging can modify or build references to the transfer given so it + * should not be re-used or it should be copied before calling this method. + * + * @param transfer is the transfer to merge into this one + * @return {MoneroTransfer} the merged transfer + */ + merge(transfer: MoneroTransfer): MoneroTransfer; + toString(indent?: number): string; + protected validate(): void; +} diff --git a/dist/src/main/ts/wallet/model/MoneroTransfer.js b/dist/src/main/ts/wallet/model/MoneroTransfer.js new file mode 100644 index 000000000..00b99a010 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTransfer.js @@ -0,0 +1,120 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); +var _MoneroError = _interopRequireDefault(require("../../common/MoneroError")); + + +/** + * Models a base transfer of funds to or from the wallet. + */ +class MoneroTransfer { + + + + + + /** + * Construct the transfer. + * + * @param {Partial} transfer existing state to initialize from (optional) + */ + constructor(transfer) { + Object.assign(this, transfer); + if (this.amount !== undefined && typeof this.amount !== "bigint") this.amount = BigInt(this.amount); + this.validate(); + } + + copy() { + return new MoneroTransfer(this); + } + + toJson() { + let json = Object.assign({}, this); + if (this.getAmount() !== undefined) json.amount = this.getAmount().toString(); + delete json.tx; // parent tx is not serialized + return json; + } + + getTx() { + return this.tx; + } + + setTx(tx) { + this.tx = tx; + return this; + } + + getIsOutgoing() { + let isIncoming = this.getIsIncoming(); + (0, _assert.default)(typeof isIncoming === "boolean"); + return !isIncoming; + } + + getIsIncoming() { + throw new Error("Subclass must implement"); + } + + getAccountIndex() { + return this.accountIndex; + } + + setAccountIndex(accountIndex) { + this.accountIndex = accountIndex; + this.validate(); + return this; + } + + getAmount() { + return this.amount; + } + + setAmount(amount) { + this.amount = amount; + return this; + } + + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * Merging can modify or build references to the transfer given so it + * should not be re-used or it should be copied before calling this method. + * + * @param transfer is the transfer to merge into this one + * @return {MoneroTransfer} the merged transfer + */ + merge(transfer) { + (0, _assert.default)(transfer instanceof MoneroTransfer); + if (this === transfer) return this; + + // merge transactions if they're different which comes back to merging transfers + if (this.getTx() !== transfer.getTx()) { + this.getTx().merge(transfer.getTx()); + return this; + } + + // otherwise merge transfer fields + this.setAccountIndex(_GenUtils.default.reconcile(this.getAccountIndex(), transfer.getAccountIndex())); + + // TODO monero-project: failed tx in pool (after testUpdateLockedDifferentAccounts()) causes non-originating saved wallets to return duplicate incoming transfers but one has amount of 0 + if (this.getAmount() !== undefined && transfer.getAmount() !== undefined && this.getAmount() !== transfer.getAmount() && (this.getAmount() === 0n || transfer.getAmount() === 0n)) { + console.warn("monero-project returning transfers with 0 amount/numSuggestedConfirmations"); + } else { + this.setAmount(_GenUtils.default.reconcile(this.getAmount(), transfer.getAmount())); + } + + return this; + } + + toString(indent = 0) { + let str = ""; + str += _GenUtils.default.kvLine("Is incoming", this.getIsIncoming(), indent); + str += _GenUtils.default.kvLine("Account index", this.getAccountIndex(), indent); + str += _GenUtils.default.kvLine("Amount", this.getAmount() ? this.getAmount().toString() : undefined, indent); + return str === "" ? str : str.slice(0, str.length - 1); // strip last newline + } + + validate() { + if (this.getAccountIndex() !== undefined && this.getAccountIndex() < 0) throw new _MoneroError.default("Account index must be >= 0"); + } +}exports.default = MoneroTransfer; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTW9uZXJvRXJyb3IiLCJNb25lcm9UcmFuc2ZlciIsImNvbnN0cnVjdG9yIiwidHJhbnNmZXIiLCJPYmplY3QiLCJhc3NpZ24iLCJhbW91bnQiLCJ1bmRlZmluZWQiLCJCaWdJbnQiLCJ2YWxpZGF0ZSIsImNvcHkiLCJ0b0pzb24iLCJqc29uIiwiZ2V0QW1vdW50IiwidG9TdHJpbmciLCJ0eCIsImdldFR4Iiwic2V0VHgiLCJnZXRJc091dGdvaW5nIiwiaXNJbmNvbWluZyIsImdldElzSW5jb21pbmciLCJhc3NlcnQiLCJFcnJvciIsImdldEFjY291bnRJbmRleCIsImFjY291bnRJbmRleCIsInNldEFjY291bnRJbmRleCIsInNldEFtb3VudCIsIm1lcmdlIiwiR2VuVXRpbHMiLCJyZWNvbmNpbGUiLCJjb25zb2xlIiwid2FybiIsImluZGVudCIsInN0ciIsImt2TGluZSIsInNsaWNlIiwibGVuZ3RoIiwiTW9uZXJvRXJyb3IiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9UcmFuc2Zlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi4vLi4vY29tbW9uL0dlblV0aWxzXCI7XG5pbXBvcnQgTW9uZXJvRXJyb3IgZnJvbSBcIi4uLy4uL2NvbW1vbi9Nb25lcm9FcnJvclwiO1xuaW1wb3J0IE1vbmVyb1R4V2FsbGV0IGZyb20gXCIuL01vbmVyb1R4V2FsbGV0XCI7XG5cbi8qKlxuICogTW9kZWxzIGEgYmFzZSB0cmFuc2ZlciBvZiBmdW5kcyB0byBvciBmcm9tIHRoZSB3YWxsZXQuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb1RyYW5zZmVyIHtcblxuICB0eDogTW9uZXJvVHhXYWxsZXQ7XG4gIGFjY291bnRJbmRleDogbnVtYmVyO1xuICBhbW91bnQ6IGJpZ2ludDtcbiAgXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3QgdGhlIHRyYW5zZmVyLlxuICAgKiBcbiAgICogQHBhcmFtIHtQYXJ0aWFsPE1vbmVyb1RyYW5zZmVyPn0gdHJhbnNmZXIgZXhpc3Rpbmcgc3RhdGUgdG8gaW5pdGlhbGl6ZSBmcm9tIChvcHRpb25hbClcbiAgICovXG4gIGNvbnN0cnVjdG9yKHRyYW5zZmVyOiBQYXJ0aWFsPE1vbmVyb1RyYW5zZmVyPikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgdHJhbnNmZXIpO1xuICAgIGlmICh0aGlzLmFtb3VudCAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLmFtb3VudCAhPT0gXCJiaWdpbnRcIikgdGhpcy5hbW91bnQgPSBCaWdJbnQodGhpcy5hbW91bnQpO1xuICAgIHRoaXMudmFsaWRhdGUoKTtcbiAgfVxuICBcbiAgY29weSgpOiBNb25lcm9UcmFuc2ZlciB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9UcmFuc2Zlcih0aGlzKTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgbGV0IGpzb246IGFueSA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMpO1xuICAgIGlmICh0aGlzLmdldEFtb3VudCgpICE9PSB1bmRlZmluZWQpIGpzb24uYW1vdW50ID0gdGhpcy5nZXRBbW91bnQoKS50b1N0cmluZygpXG4gICAgZGVsZXRlIGpzb24udHg7IC8vIHBhcmVudCB0eCBpcyBub3Qgc2VyaWFsaXplZFxuICAgIHJldHVybiBqc29uO1xuICB9XG4gIFxuICBnZXRUeCgpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgcmV0dXJuIHRoaXMudHg7XG4gIH1cbiAgXG4gIHNldFR4KHR4OiBNb25lcm9UeFdhbGxldCk6IE1vbmVyb1RyYW5zZmVyIHtcbiAgICB0aGlzLnR4ID0gdHg7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldElzT3V0Z29pbmcoKTogYm9vbGVhbiB7XG4gICAgbGV0IGlzSW5jb21pbmcgPSB0aGlzLmdldElzSW5jb21pbmcoKTtcbiAgICBhc3NlcnQodHlwZW9mIGlzSW5jb21pbmcgPT09IFwiYm9vbGVhblwiKTtcbiAgICByZXR1cm4gIWlzSW5jb21pbmc7XG4gIH1cbiAgXG4gIGdldElzSW5jb21pbmcoKTogYm9vbGVhbiB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiU3ViY2xhc3MgbXVzdCBpbXBsZW1lbnRcIik7XG4gIH1cblxuICBnZXRBY2NvdW50SW5kZXgoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5hY2NvdW50SW5kZXg7XG4gIH1cblxuICBzZXRBY2NvdW50SW5kZXgoYWNjb3VudEluZGV4OiBudW1iZXIpOiBNb25lcm9UcmFuc2ZlciB7XG4gICAgdGhpcy5hY2NvdW50SW5kZXggPSBhY2NvdW50SW5kZXg7XG4gICAgdGhpcy52YWxpZGF0ZSgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgZ2V0QW1vdW50KCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMuYW1vdW50O1xuICB9XG5cbiAgc2V0QW1vdW50KGFtb3VudDogYmlnaW50KTogTW9uZXJvVHJhbnNmZXIge1xuICAgIHRoaXMuYW1vdW50ID0gYW1vdW50O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogVXBkYXRlcyB0aGlzIHRyYW5zYWN0aW9uIGJ5IG1lcmdpbmcgdGhlIGxhdGVzdCBpbmZvcm1hdGlvbiBmcm9tIHRoZSBnaXZlblxuICAgKiB0cmFuc2FjdGlvbi5cbiAgICogXG4gICAqIE1lcmdpbmcgY2FuIG1vZGlmeSBvciBidWlsZCByZWZlcmVuY2VzIHRvIHRoZSB0cmFuc2ZlciBnaXZlbiBzbyBpdFxuICAgKiBzaG91bGQgbm90IGJlIHJlLXVzZWQgb3IgaXQgc2hvdWxkIGJlIGNvcGllZCBiZWZvcmUgY2FsbGluZyB0aGlzIG1ldGhvZC5cbiAgICogXG4gICAqIEBwYXJhbSB0cmFuc2ZlciBpcyB0aGUgdHJhbnNmZXIgdG8gbWVyZ2UgaW50byB0aGlzIG9uZVxuICAgKiBAcmV0dXJuIHtNb25lcm9UcmFuc2Zlcn0gdGhlIG1lcmdlZCB0cmFuc2ZlclxuICAgKi9cbiAgbWVyZ2UodHJhbnNmZXI6IE1vbmVyb1RyYW5zZmVyKTogTW9uZXJvVHJhbnNmZXIge1xuICAgIGFzc2VydCh0cmFuc2ZlciBpbnN0YW5jZW9mIE1vbmVyb1RyYW5zZmVyKTtcbiAgICBpZiAodGhpcyA9PT0gdHJhbnNmZXIpIHJldHVybiB0aGlzO1xuICAgIFxuICAgIC8vIG1lcmdlIHRyYW5zYWN0aW9ucyBpZiB0aGV5J3JlIGRpZmZlcmVudCB3aGljaCBjb21lcyBiYWNrIHRvIG1lcmdpbmcgdHJhbnNmZXJzXG4gICAgaWYgKHRoaXMuZ2V0VHgoKSAhPT0gdHJhbnNmZXIuZ2V0VHgoKSkge1xuICAgICAgdGhpcy5nZXRUeCgpLm1lcmdlKHRyYW5zZmVyLmdldFR4KCkpO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuICAgIFxuICAgIC8vIG90aGVyd2lzZSBtZXJnZSB0cmFuc2ZlciBmaWVsZHNcbiAgICB0aGlzLnNldEFjY291bnRJbmRleChHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRBY2NvdW50SW5kZXgoKSwgdHJhbnNmZXIuZ2V0QWNjb3VudEluZGV4KCkpKTtcbiAgICBcbiAgICAvLyBUT0RPIG1vbmVyby1wcm9qZWN0OiBmYWlsZWQgdHggaW4gcG9vbCAoYWZ0ZXIgdGVzdFVwZGF0ZUxvY2tlZERpZmZlcmVudEFjY291bnRzKCkpIGNhdXNlcyBub24tb3JpZ2luYXRpbmcgc2F2ZWQgd2FsbGV0cyB0byByZXR1cm4gZHVwbGljYXRlIGluY29taW5nIHRyYW5zZmVycyBidXQgb25lIGhhcyBhbW91bnQgb2YgMFxuICAgIGlmICh0aGlzLmdldEFtb3VudCgpICE9PSB1bmRlZmluZWQgJiYgdHJhbnNmZXIuZ2V0QW1vdW50KCkgIT09IHVuZGVmaW5lZCAmJiB0aGlzLmdldEFtb3VudCgpICE9PSB0cmFuc2Zlci5nZXRBbW91bnQoKSAmJiAodGhpcy5nZXRBbW91bnQoKSA9PT0gMG4gfHwgdHJhbnNmZXIuZ2V0QW1vdW50KCkgPT09IDBuKSkge1xuICAgICAgY29uc29sZS53YXJuKFwibW9uZXJvLXByb2plY3QgcmV0dXJuaW5nIHRyYW5zZmVycyB3aXRoIDAgYW1vdW50L251bVN1Z2dlc3RlZENvbmZpcm1hdGlvbnNcIik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuc2V0QW1vdW50KEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldEFtb3VudCgpLCB0cmFuc2Zlci5nZXRBbW91bnQoKSkpO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgdG9TdHJpbmcoaW5kZW50ID0gMCk6IHN0cmluZyB7XG4gICAgbGV0IHN0ciA9IFwiXCI7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIklzIGluY29taW5nXCIsIHRoaXMuZ2V0SXNJbmNvbWluZygpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJBY2NvdW50IGluZGV4XCIsIHRoaXMuZ2V0QWNjb3VudEluZGV4KCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIkFtb3VudFwiLCB0aGlzLmdldEFtb3VudCgpID8gdGhpcy5nZXRBbW91bnQoKS50b1N0cmluZygpIDogdW5kZWZpbmVkLCBpbmRlbnQpO1xuICAgIHJldHVybiBzdHIgPT09IFwiXCIgPyBzdHIgOiAgc3RyLnNsaWNlKDAsIHN0ci5sZW5ndGggLSAxKTsgIC8vIHN0cmlwIGxhc3QgbmV3bGluZVxuICB9XG4gIFxuICBwcm90ZWN0ZWQgdmFsaWRhdGUoKSB7XG4gICAgaWYgKHRoaXMuZ2V0QWNjb3VudEluZGV4KCkgIT09IHVuZGVmaW5lZCAmJiB0aGlzLmdldEFjY291bnRJbmRleCgpIDwgMCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQWNjb3VudCBpbmRleCBtdXN0IGJlID49IDBcIik7XG4g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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroTransferQuery.d.ts b/dist/src/main/ts/wallet/model/MoneroTransferQuery.d.ts new file mode 100644 index 000000000..9771825a9 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTransferQuery.d.ts @@ -0,0 +1,77 @@ +import MoneroDestination from "./MoneroDestination"; +import MoneroTransfer from "./MoneroTransfer"; +import MoneroTxWallet from "./MoneroTxWallet"; +import MoneroTxQuery from "./MoneroTxQuery"; +/** + * Configuration to query wallet transfers. + */ +export default class MoneroTransferQuery extends MoneroTransfer { + txQuery: Partial; + isIncoming: boolean; + address: string; + addresses: string[]; + subaddressIndex: number; + subaddressIndices: number[]; + destinations: MoneroDestination[]; + hasDestinations: boolean; + /** + *

Construct the transfer query.

+ * + *

Example:

+ * + * + * // get incoming transfers to account 0, subaddress 1
+ * let transfers = await wallet.getTransfers({
+ *    accountIndex: 0,
+ *    subaddressIndex: 0
+ * }); + *
+ * + *

All configuration is optional. All transfers are returned except those that don't meet criteria defined in this query.

+ * + * @param {Partial} [query] - transfer query configuration (optional) + * @param {bigint} query.amount - get transfers with this amount + * @param {number} query.accountIndex - get transfers to/from this account index + * @param {number} query.subaddressIndex - get transfers to/from this subaddress index + * @param {number[]} query.subaddressIndices - get transfers to/from these subaddress indices + * @param {string} query.address - get transfers to/from this wallet address + * @param {string[]} query.addresses - get transfers to/from these wallet addresses + * @param {boolean} query.isIncoming - get transfers which are incoming if true + * @param {boolean} query.isOutgoing - get transfers which are outgoing if true + * @param {boolean} query.hasDestinations - get transfers with known destinations if true (destinations are only stored locally with the wallet) + * @param {MoneroTxQuery} query.txQuery - get transfers whose tx match this tx query + */ + constructor(query?: Partial); + copy(): MoneroTransferQuery; + toJson(): any; + getTxQuery(): MoneroTxQuery; + setTxQuery(txQuery: MoneroTxQuery): MoneroTransferQuery; + getIsIncoming(): boolean; + setIsIncoming(isIncoming: boolean): MoneroTransferQuery; + getIsOutgoing(): boolean; + setIsOutgoing(isOutgoing: boolean): MoneroTransferQuery; + getAddress(): string; + setAddress(address: string): MoneroTransferQuery; + getAddresses(): string[]; + setAddresses(addresses: string[]): MoneroTransferQuery; + getSubaddressIndex(): number; + setSubaddressIndex(subaddressIndex: number): MoneroTransferQuery; + getSubaddressIndices(): number[]; + setSubaddressIndices(subaddressIndices: number[]): MoneroTransferQuery; + getDestinations(): MoneroDestination[]; + setDestinations(destinations: MoneroDestination[]): this; + getHasDestinations(): boolean; + setHasDestinations(hasDestinations: boolean): MoneroTransferQuery; + /** + * Convenience method to query outputs by the locked state of their tx. + * + * @param isLocked specifies if the output's tx must be locked or unlocked (optional) + * @return {MoneroOutputQuery} this query for chaining + */ + setIsLocked(isLocked: boolean): MoneroTransferQuery; + meetsCriteria(transfer: MoneroTransfer, queryParent?: boolean): boolean; + validate(): void; + setTx(tx: MoneroTxWallet): MoneroTransferQuery; + setAmount(amount: bigint): MoneroTransferQuery; + setAccountIndex(accountIndex: number): MoneroTransferQuery; +} diff --git a/dist/src/main/ts/wallet/model/MoneroTransferQuery.js b/dist/src/main/ts/wallet/model/MoneroTransferQuery.js new file mode 100644 index 000000000..b260ada99 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTransferQuery.js @@ -0,0 +1,242 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; + +var _MoneroIncomingTransfer = _interopRequireDefault(require("./MoneroIncomingTransfer")); +var _MoneroOutgoingTransfer = _interopRequireDefault(require("./MoneroOutgoingTransfer")); +var _MoneroTransfer = _interopRequireDefault(require("./MoneroTransfer")); + +var _MoneroTxQuery = _interopRequireDefault(require("./MoneroTxQuery")); +var _MoneroError = _interopRequireDefault(require("../../common/MoneroError")); + +/** + * Configuration to query wallet transfers. + */ +class MoneroTransferQuery extends _MoneroTransfer.default { + + + + + + + + + + + /** + *

Construct the transfer query.

+ * + *

Example:

+ * + * + * // get incoming transfers to account 0, subaddress 1
+ * let transfers = await wallet.getTransfers({
+ *    accountIndex: 0,
+ *    subaddressIndex: 0
+ * }); + *
+ * + *

All configuration is optional. All transfers are returned except those that don't meet criteria defined in this query.

+ * + * @param {Partial} [query] - transfer query configuration (optional) + * @param {bigint} query.amount - get transfers with this amount + * @param {number} query.accountIndex - get transfers to/from this account index + * @param {number} query.subaddressIndex - get transfers to/from this subaddress index + * @param {number[]} query.subaddressIndices - get transfers to/from these subaddress indices + * @param {string} query.address - get transfers to/from this wallet address + * @param {string[]} query.addresses - get transfers to/from these wallet addresses + * @param {boolean} query.isIncoming - get transfers which are incoming if true + * @param {boolean} query.isOutgoing - get transfers which are outgoing if true + * @param {boolean} query.hasDestinations - get transfers with known destinations if true (destinations are only stored locally with the wallet) + * @param {MoneroTxQuery} query.txQuery - get transfers whose tx match this tx query + */ + constructor(query) { + super(query); + if (this.txQuery && !(this.txQuery instanceof _MoneroTxQuery.default)) this.txQuery = new _MoneroTxQuery.default(this.txQuery); + if (this.txQuery) this.txQuery.setTransferQuery(this); + + // alias isOutgoing to isIncoming + if (this.isOutgoing !== undefined) this.isIncoming = !this.isOutgoing; + this.validate(); + } + + copy() { + return new MoneroTransferQuery(this); + } + + toJson() { + let json = Object.assign({}, this, super.toJson()); + delete json.txQuery; + return json; + } + + getTxQuery() { + return this.txQuery; + } + + setTxQuery(txQuery) { + this.txQuery = txQuery; + if (txQuery) txQuery.setTransferQuery(this); + return this; + } + + getIsIncoming() { + return this.isIncoming; + } + + setIsIncoming(isIncoming) { + this.isIncoming = isIncoming; + return this; + } + + getIsOutgoing() { + return this.isIncoming === undefined ? undefined : !this.isIncoming; + } + + setIsOutgoing(isOutgoing) { + this.isIncoming = isOutgoing === undefined ? undefined : !isOutgoing; + return this; + } + + getAddress() { + return this.address; + } + + setAddress(address) { + this.address = address; + return this; + } + + getAddresses() { + return this.addresses; + } + + setAddresses(addresses) { + this.addresses = addresses; + return this; + } + + getSubaddressIndex() { + return this.subaddressIndex; + } + + setSubaddressIndex(subaddressIndex) { + this.subaddressIndex = subaddressIndex; + this.validate(); + return this; + } + + getSubaddressIndices() { + return this.subaddressIndices; + } + + setSubaddressIndices(subaddressIndices) { + this.subaddressIndices = subaddressIndices; + this.validate(); + return this; + } + + getDestinations() { + return this.destinations; + } + + setDestinations(destinations) { + this.destinations = destinations; + return this; + } + + getHasDestinations() { + return this.hasDestinations; + } + + setHasDestinations(hasDestinations) { + this.hasDestinations = hasDestinations; + return this; + } + + /** + * Convenience method to query outputs by the locked state of their tx. + * + * @param isLocked specifies if the output's tx must be locked or unlocked (optional) + * @return {MoneroOutputQuery} this query for chaining + */ + setIsLocked(isLocked) { + if (this.txQuery === undefined) this.txQuery = new _MoneroTxQuery.default(); + this.getTxQuery().setIsLocked(isLocked); + return this; + } + + meetsCriteria(transfer, queryParent = true) { + if (!(transfer instanceof _MoneroTransfer.default)) throw new Error("Transfer not given to MoneroTransferQuery.meetsCriteria(transfer)"); + + // filter on common fields + if (this.getIsIncoming() !== undefined && this.getIsIncoming() !== transfer.getIsIncoming()) return false; + if (this.getIsOutgoing() !== undefined && this.getIsOutgoing() !== transfer.getIsOutgoing()) return false; + if (this.getAmount() !== undefined && this.getAmount() !== transfer.getAmount()) return false; + if (this.getAccountIndex() !== undefined && this.getAccountIndex() !== transfer.getAccountIndex()) return false; + + // filter on incoming fields + if (transfer instanceof _MoneroIncomingTransfer.default) { + if (this.getHasDestinations() !== undefined) return false; + if (this.getAddress() !== undefined && this.getAddress() !== transfer.getAddress()) return false; + if (this.getAddresses() !== undefined && !this.getAddresses().includes(transfer.getAddress())) return false; + if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() !== transfer.getSubaddressIndex()) return false; + if (this.getSubaddressIndices() !== undefined && !this.getSubaddressIndices().includes(transfer.getSubaddressIndex())) return false; + } + + // filter on outgoing fields + else if (transfer instanceof _MoneroOutgoingTransfer.default) { + + // filter on addresses which must have overlap + if (this.getAddress() !== undefined && (transfer.getAddresses() === undefined || !transfer.getAddresses().includes(this.getAddress()))) return false; // TODO: will filter all transfers that don't contain addresses (outgoing txs might not have this field initialized) + if (this.getAddresses() !== undefined) { + if (!transfer.getAddresses()) return false; + if (!this.getAddresses().some((address) => transfer.getAddresses().includes(address))) return false; + } + + // filter on subaddress indices + if (this.getSubaddressIndex() !== undefined && (transfer.getSubaddressIndices() === undefined || !transfer.getSubaddressIndices().includes(this.getSubaddressIndex()))) return false; + if (this.getSubaddressIndices() !== undefined) { + if (!transfer.getSubaddressIndices()) return false; + if (!this.getSubaddressIndices().some((subaddressIdx) => transfer.getSubaddressIndices().includes(subaddressIdx))) return false; + } + + // filter on having destinations + if (this.getHasDestinations() !== undefined) { + if (this.getHasDestinations() && transfer.getDestinations() === undefined) return false; + if (!this.getHasDestinations() && transfer.getDestinations() !== undefined) return false; + } + + // filter on destinations TODO: start with test for this + // if (this.getDestionations() !== undefined && this.getDestionations() !== transfer.getDestionations()) return false; + } + + // otherwise invalid type + else throw new Error("Transfer must be MoneroIncomingTransfer or MoneroOutgoingTransfer"); + + // filter with tx filter + if (queryParent && this.getTxQuery() !== undefined && !this.getTxQuery().meetsCriteria(transfer.getTx())) return false; + return true; + } + + validate() { + if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() < 0) throw new _MoneroError.default("Subaddress index must be >= 0"); + if (this.getSubaddressIndices() !== undefined) for (let subaddressIdx of this.getSubaddressIndices()) if (subaddressIdx < 0) throw new _MoneroError.default("Subaddress indices must be >= 0"); + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setTx(tx) { + super.setTx(tx); + return this; + } + + setAmount(amount) { + super.setAmount(amount); + return this; + } + + setAccountIndex(accountIndex) { + super.setAccountIndex(accountIndex); + return this; + } +}exports.default = MoneroTransferQuery; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfTW9uZXJvSW5jb21pbmdUcmFuc2ZlciIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX01vbmVyb091dGdvaW5nVHJhbnNmZXIiLCJfTW9uZXJvVHJhbnNmZXIiLCJfTW9uZXJvVHhRdWVyeSIsIl9Nb25lcm9FcnJvciIsIk1vbmVyb1RyYW5zZmVyUXVlcnkiLCJNb25lcm9UcmFuc2ZlciIsImNvbnN0cnVjdG9yIiwicXVlcnkiLCJ0eFF1ZXJ5IiwiTW9uZXJvVHhRdWVyeSIsInNldFRyYW5zZmVyUXVlcnkiLCJpc091dGdvaW5nIiwidW5kZWZpbmVkIiwiaXNJbmNvbWluZyIsInZhbGlkYXRlIiwiY29weSIsInRvSnNvbiIsImpzb24iLCJPYmplY3QiLCJhc3NpZ24iLCJnZXRUeFF1ZXJ5Iiwic2V0VHhRdWVyeSIsImdldElzSW5jb21pbmciLCJzZXRJc0luY29taW5nIiwiZ2V0SXNPdXRnb2luZyIsInNldElzT3V0Z29pbmciLCJnZXRBZGRyZXNzIiwiYWRkcmVzcyIsInNldEFkZHJlc3MiLCJnZXRBZGRyZXNzZXMiLCJhZGRyZXNzZXMiLCJzZXRBZGRyZXNzZXMiLCJnZXRTdWJhZGRyZXNzSW5kZXgiLCJzdWJhZGRyZXNzSW5kZXgiLCJzZXRTdWJhZGRyZXNzSW5kZXgiLCJnZXRTdWJhZGRyZXNzSW5kaWNlcyIsInN1YmFkZHJlc3NJbmRpY2VzIiwic2V0U3ViYWRkcmVzc0luZGljZXMiLCJnZXREZXN0aW5hdGlvbnMiLCJkZXN0aW5hdGlvbnMiLCJzZXREZXN0aW5hdGlvbnMiLCJnZXRIYXNEZXN0aW5hdGlvbnMiLCJoYXNEZXN0aW5hdGlvbnMiLCJzZXRIYXNEZXN0aW5hdGlvbnMiLCJzZXRJc0xvY2tlZCIsImlzTG9ja2VkIiwibWVldHNDcml0ZXJpYSIsInRyYW5zZmVyIiwicXVlcnlQYXJlbnQiLCJFcnJvciIsImdldEFtb3VudCIsImdldEFjY291bnRJbmRleCIsIk1vbmVyb0luY29taW5nVHJhbnNmZXIiLCJpbmNsdWRlcyIsIk1vbmVyb091dGdvaW5nVHJhbnNmZXIiLCJzb21lIiwic3ViYWRkcmVzc0lkeCIsImdldFR4IiwiTW9uZXJvRXJyb3IiLCJzZXRUeCIsInR4Iiwic2V0QW1vdW50IiwiYW1vdW50Iiwic2V0QWNjb3VudEluZGV4IiwiYWNjb3VudEluZGV4IiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy93YWxsZXQvbW9kZWwvTW9uZXJvVHJhbnNmZXJRdWVyeS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgR2VuVXRpbHMgZnJvbSBcIi4uLy4uL2NvbW1vbi9HZW5VdGlsc1wiO1xuaW1wb3J0IE1vbmVyb0Rlc3RpbmF0aW9uIGZyb20gXCIuL01vbmVyb0Rlc3RpbmF0aW9uXCI7XG5pbXBvcnQgTW9uZXJvSW5jb21pbmdUcmFuc2ZlciBmcm9tIFwiLi9Nb25lcm9JbmNvbWluZ1RyYW5zZmVyXCI7XG5pbXBvcnQgTW9uZXJvT3V0Z29pbmdUcmFuc2ZlciBmcm9tIFwiLi9Nb25lcm9PdXRnb2luZ1RyYW5zZmVyXCI7XG5pbXBvcnQgTW9uZXJvVHJhbnNmZXIgZnJvbSBcIi4vTW9uZXJvVHJhbnNmZXJcIjtcbmltcG9ydCBNb25lcm9UeFdhbGxldCBmcm9tIFwiLi9Nb25lcm9UeFdhbGxldFwiO1xuaW1wb3J0IE1vbmVyb1R4UXVlcnkgZnJvbSBcIi4vTW9uZXJvVHhRdWVyeVwiO1xuaW1wb3J0IE1vbmVyb0Vycm9yIGZyb20gXCIuLi8uLi9jb21tb24vTW9uZXJvRXJyb3JcIjtcblxuLyoqXG4gKiBDb25maWd1cmF0aW9uIHRvIHF1ZXJ5IHdhbGxldCB0cmFuc2ZlcnMuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb1RyYW5zZmVyUXVlcnkgZXh0ZW5kcyBNb25lcm9UcmFuc2ZlciB7XG5cbiAgdHhRdWVyeTogUGFydGlhbDxNb25lcm9UeFF1ZXJ5PjtcbiAgaXNJbmNvbWluZzogYm9vbGVhbjtcbiAgYWRkcmVzczogc3RyaW5nO1xuICBhZGRyZXNzZXM6IHN0cmluZ1tdO1xuICBzdWJhZGRyZXNzSW5kZXg6IG51bWJlcjtcbiAgc3ViYWRkcmVzc0luZGljZXM6IG51bWJlcltdO1xuICBkZXN0aW5hdGlvbnM6IE1vbmVyb0Rlc3RpbmF0aW9uW107XG4gIGhhc0Rlc3RpbmF0aW9uczogYm9vbGVhbjtcbiAgXG4gIC8qKlxuICAgKiA8cD5Db25zdHJ1Y3QgdGhlIHRyYW5zZmVyIHF1ZXJ5LjwvcD5cbiAgICogXG4gICAqIDxwPkV4YW1wbGU6PC9wPlxuICAgKiBcbiAgICogPGNvZGU+XG4gICAqICZzb2w7JnNvbDsgZ2V0IGluY29taW5nIHRyYW5zZmVycyB0byBhY2NvdW50IDAsIHN1YmFkZHJlc3MgMTxicj5cbiAgICogbGV0IHRyYW5zZmVycyA9IGF3YWl0IHdhbGxldC5nZXRUcmFuc2ZlcnMoezxicj5cbiAgICogJm5ic3A7Jm5ic3A7IGFjY291bnRJbmRleDogMCw8YnI+XG4gICAqICZuYnNwOyZuYnNwOyBzdWJhZGRyZXNzSW5kZXg6IDA8YnI+XG4gICAqIH0pO1xuICAgKiA8L2NvZGU+XG4gICAqIFxuICAgKiA8cD5BbGwgY29uZmlndXJhdGlvbiBpcyBvcHRpb25hbC4gIEFsbCB0cmFuc2ZlcnMgYXJlIHJldHVybmVkIGV4Y2VwdCB0aG9zZSB0aGF0IGRvbid0IG1lZXQgY3JpdGVyaWEgZGVmaW5lZCBpbiB0aGlzIHF1ZXJ5LjwvcD5cbiAgICogXG4gICAqIEBwYXJhbSB7UGFydGlhbDxNb25lcm9UcmFuc2ZlclF1ZXJ5Pn0gW3F1ZXJ5XSAtIHRyYW5zZmVyIHF1ZXJ5IGNvbmZpZ3VyYXRpb24gKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2JpZ2ludH0gcXVlcnkuYW1vdW50IC0gZ2V0IHRyYW5zZmVycyB3aXRoIHRoaXMgYW1vdW50XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBxdWVyeS5hY2NvdW50SW5kZXggLSBnZXQgdHJhbnNmZXJzIHRvL2Zyb20gdGhpcyBhY2NvdW50IGluZGV4XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBxdWVyeS5zdWJhZGRyZXNzSW5kZXggLSBnZXQgdHJhbnNmZXJzIHRvL2Zyb20gdGhpcyBzdWJhZGRyZXNzIGluZGV4XG4gICAqIEBwYXJhbSB7bnVtYmVyW119IHF1ZXJ5LnN1YmFkZHJlc3NJbmRpY2VzIC0gZ2V0IHRyYW5zZmVycyB0by9mcm9tIHRoZXNlIHN1YmFkZHJlc3MgaW5kaWNlc1xuICAgKiBAcGFyYW0ge3N0cmluZ30gcXVlcnkuYWRkcmVzcyAtIGdldCB0cmFuc2ZlcnMgdG8vZnJvbSB0aGlzIHdhbGxldCBhZGRyZXNzXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IHF1ZXJ5LmFkZHJlc3NlcyAtIGdldCB0cmFuc2ZlcnMgdG8vZnJvbSB0aGVzZSB3YWxsZXQgYWRkcmVzc2VzXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gcXVlcnkuaXNJbmNvbWluZyAtIGdldCB0cmFuc2ZlcnMgd2hpY2ggYXJlIGluY29taW5nIGlmIHRydWVcbiAgICogQHBhcmFtIHtib29sZWFufSBxdWVyeS5pc091dGdvaW5nIC0gZ2V0IHRyYW5zZmVycyB3aGljaCBhcmUgb3V0Z29pbmcgaWYgdHJ1ZVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHF1ZXJ5Lmhhc0Rlc3RpbmF0aW9ucyAtIGdldCB0cmFuc2ZlcnMgd2l0aCBrbm93biBkZXN0aW5hdGlvbnMgaWYgdHJ1ZSAoZGVzdGluYXRpb25zIGFyZSBvbmx5IHN0b3JlZCBsb2NhbGx5IHdpdGggdGhlIHdhbGxldClcbiAgICogQHBhcmFtIHtNb25lcm9UeFF1ZXJ5fSBxdWVyeS50eFF1ZXJ5IC0gZ2V0IHRyYW5zZmVycyB3aG9zZSB0eCBtYXRjaCB0aGlzIHR4IHF1ZXJ5XG4gICAqL1xuICBjb25zdHJ1Y3RvcihxdWVyeT86IFBhcnRpYWw8TW9uZXJvVHJhbnNmZXJRdWVyeT4pIHtcbiAgICBzdXBlcihxdWVyeSk7XG4gICAgaWYgKHRoaXMudHhRdWVyeSAmJiAhKHRoaXMudHhRdWVyeSBpbnN0YW5jZW9mIE1vbmVyb1R4UXVlcnkpKSB0aGlzLnR4UXVlcnkgPSBuZXcgTW9uZXJvVHhRdWVyeSh0aGlzLnR4UXVlcnkpO1xuICAgIGlmICh0aGlzLnR4UXVlcnkpIHRoaXMudHhRdWVyeS5zZXRUcmFuc2ZlclF1ZXJ5KHRoaXMpO1xuXG4gICAgLy8gYWxpYXMgaXNPdXRnb2luZyB0byBpc0luY29taW5nXG4gICAgaWYgKCh0aGlzIGFzIGFueSkuaXNPdXRnb2luZyAhPT0gdW5kZWZpbmVkKSB0aGlzLmlzSW5jb21pbmcgPSAhKHRoaXMgYXMgYW55KS5pc091dGdvaW5nO1xuICAgIHRoaXMudmFsaWRhdGUoKTtcbiAgfVxuICBcbiAgY29weSgpOiBNb25lcm9UcmFuc2ZlclF1ZXJ5IHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb1RyYW5zZmVyUXVlcnkodGhpcyk7XG4gIH1cbiAgXG4gIHRvSnNvbigpOiBhbnkge1xuICAgIGxldCBqc29uID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcywgc3VwZXIudG9Kc29uKCkpO1xuICAgIGRlbGV0ZSBqc29uLnR4UXVlcnk7XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIGdldFR4UXVlcnkoKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgcmV0dXJuIHRoaXMudHhRdWVyeSBhcyBNb25lcm9UeFF1ZXJ5O1xuICB9XG4gIFxuICBzZXRUeFF1ZXJ5KHR4UXVlcnk6IE1vbmVyb1R4UXVlcnkpOiBNb25lcm9UcmFuc2ZlclF1ZXJ5IHtcbiAgICB0aGlzLnR4UXVlcnkgPSB0eFF1ZXJ5O1xuICAgIGlmICh0eFF1ZXJ5KSB0eFF1ZXJ5LnNldFRyYW5zZmVyUXVlcnkodGhpcyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldElzSW5jb21pbmcoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNJbmNvbWluZztcbiAgfVxuXG4gIHNldElzSW5jb21pbmcoaXNJbmNvbWluZzogYm9vbGVhbik6IE1vbmVyb1RyYW5zZmVyUXVlcnkge1xuICAgIHRoaXMuaXNJbmNvbWluZyA9IGlzSW5jb21pbmc7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldElzT3V0Z29pbmcoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNJbmNvbWluZyA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogIXRoaXMuaXNJbmNvbWluZztcbiAgfVxuICBcbiAgc2V0SXNPdXRnb2luZyhpc091dGdvaW5nOiBib29sZWFuKTogTW9uZXJvVHJhbnNmZXJRdWVyeSB7XG4gICAgdGhpcy5pc0luY29taW5nID0gaXNPdXRnb2luZyA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogIWlzT3V0Z29pbmc7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEFkZHJlc3MoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5hZGRyZXNzO1xuICB9XG5cbiAgc2V0QWRkcmVzcyhhZGRyZXNzOiBzdHJpbmcpOiBNb25lcm9UcmFuc2ZlclF1ZXJ5IHtcbiAgICB0aGlzLmFkZHJlc3MgPSBhZGRyZXNzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRBZGRyZXNzZXMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiB0aGlzLmFkZHJlc3NlcztcbiAgfVxuXG4gIHNldEFkZHJlc3NlcyhhZGRyZXNzZXM6IHN0cmluZ1tdKTogTW9uZXJvVHJhbnNmZXJRdWVyeSB7XG4gICAgdGhpcy5hZGRyZXNzZXMgPSBhZGRyZXNzZXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFN1YmFkZHJlc3NJbmRleCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnN1YmFkZHJlc3NJbmRleDtcbiAgfVxuICBcbiAgc2V0U3ViYWRkcmVzc0luZGV4KHN1YmFkZHJlc3NJbmRleDogbnVtYmVyKTogTW9uZXJvVHJhbnNmZXJRdWVyeSB7XG4gICAgdGhpcy5zdWJhZGRyZXNzSW5kZXggPSBzdWJhZGRyZXNzSW5kZXg7XG4gICAgdGhpcy52YWxpZGF0ZSgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRTdWJhZGRyZXNzSW5kaWNlcygpOiBudW1iZXJbXSB7XG4gICAgcmV0dXJuIHRoaXMuc3ViYWRkcmVzc0luZGljZXM7XG4gIH1cbiAgXG4gIHNldFN1YmFkZHJlc3NJbmRpY2VzKHN1YmFkZHJlc3NJbmRpY2VzOiBudW1iZXJbXSk6IE1vbmVyb1RyYW5zZmVyUXVlcnkge1xuICAgIHRoaXMuc3ViYWRkcmVzc0luZGljZXMgPSBzdWJhZGRyZXNzSW5kaWNlcztcbiAgICB0aGlzLnZhbGlkYXRlKCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldERlc3RpbmF0aW9ucygpOiBNb25lcm9EZXN0aW5hdGlvbltdIHtcbiAgICByZXR1cm4gdGhpcy5kZXN0aW5hdGlvbnM7XG4gIH1cbiAgXG4gIHNldERlc3RpbmF0aW9ucyhkZXN0aW5hdGlvbnM6IE1vbmVyb0Rlc3RpbmF0aW9uW10pIHtcbiAgICB0aGlzLmRlc3RpbmF0aW9ucyA9IGRlc3RpbmF0aW9ucztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0SGFzRGVzdGluYXRpb25zKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmhhc0Rlc3RpbmF0aW9ucztcbiAgfVxuICBcbiAgc2V0SGFzRGVzdGluYXRpb25zKGhhc0Rlc3RpbmF0aW9uczogYm9vbGVhbik6IE1vbmVyb1RyYW5zZmVyUXVlcnkge1xuICAgIHRoaXMuaGFzRGVzdGluYXRpb25zID0gaGFzRGVzdGluYXRpb25zO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogQ29udmVuaWVuY2UgbWV0aG9kIHRvIHF1ZXJ5IG91dHB1dHMgYnkgdGhlIGxvY2tlZCBzdGF0ZSBvZiB0aGVpciB0eC5cbiAgICogXG4gICAqIEBwYXJhbSBpc0xvY2tlZCBzcGVjaWZpZXMgaWYgdGhlIG91dHB1dCdzIHR4IG11c3QgYmUgbG9ja2VkIG9yIHVubG9ja2VkIChvcHRpb25hbClcbiAgICogQHJldHVybiB7TW9uZXJvT3V0cHV0UXVlcnl9IHRoaXMgcXVlcnkgZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRJc0xvY2tlZChpc0xvY2tlZDogYm9vbGVhbik6IE1vbmVyb1RyYW5zZmVyUXVlcnkge1xuICAgIGlmICh0aGlzLnR4UXVlcnkgPT09IHVuZGVmaW5lZCkgdGhpcy50eFF1ZXJ5ID0gbmV3IE1vbmVyb1R4UXVlcnkoKTtcbiAgICB0aGlzLmdldFR4UXVlcnkoKS5zZXRJc0xvY2tlZChpc0xvY2tlZCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIG1lZXRzQ3JpdGVyaWEodHJhbnNmZXI6IE1vbmVyb1RyYW5zZmVyLCBxdWVyeVBhcmVudCA9IHRydWUpOiBib29sZWFuIHtcbiAgICBpZiAoISh0cmFuc2ZlciBpbnN0YW5jZW9mIE1vbmVyb1RyYW5zZmVyKSkgdGhyb3cgbmV3IEVycm9yKFwiVHJhbnNmZXIgbm90IGdpdmVuIHRvIE1vbmVyb1RyYW5zZmVyUXVlcnkubWVldHNDcml0ZXJpYSh0cmFuc2ZlcilcIik7XG4gICAgXG4gICAgLy8gZmlsdGVyIG9uIGNvbW1vbiBmaWVsZHNcbiAgICBpZiAodGhpcy5nZXRJc0luY29taW5nKCkgIT09IHVuZGVmaW5lZCAmJiB0aGlzLmdldElzSW5jb21pbmcoKSAhPT0gdHJhbnNmZXIuZ2V0SXNJbmNvbWluZygpKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKHRoaXMuZ2V0SXNPdXRnb2luZygpICE9PSB1bmRlZmluZWQgJiYgdGhpcy5nZXRJc091dGdvaW5nKCkgIT09IHRyYW5zZmVyLmdldElzT3V0Z29pbmcoKSkgcmV0dXJuIGZhbHNlO1xuICAgIGlmICh0aGlzLmdldEFtb3VudCgpICE9PSB1bmRlZmluZWQgJiYgdGhpcy5nZXRBbW91bnQoKSAhPT0gdHJhbnNmZXIuZ2V0QW1vdW50KCkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAodGhpcy5nZXRBY2NvdW50SW5kZXgoKSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuZ2V0QWNjb3VudEluZGV4KCkgIT09IHRyYW5zZmVyLmdldEFjY291bnRJbmRleCgpKSByZXR1cm4gZmFsc2U7XG4gICAgXG4gICAgLy8gZmlsdGVyIG9uIGluY29taW5nIGZpZWxkc1xuICAgIGlmICh0cmFuc2ZlciBpbnN0YW5jZW9mIE1vbmVyb0luY29taW5nVHJhbnNmZXIpIHtcbiAgICAgIGlmICh0aGlzLmdldEhhc0Rlc3RpbmF0aW9ucygpICE9PSB1bmRlZmluZWQpIHJldHVybiBmYWxzZTtcbiAgICAgIGlmICh0aGlzLmdldEFkZHJlc3MoKSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuZ2V0QWRkcmVzcygpICE9PSB0cmFuc2Zlci5nZXRBZGRyZXNzKCkpIHJldHVybiBmYWxzZTtcbiAgICAgIGlmICh0aGlzLmdldEFkZHJlc3NlcygpICE9PSB1bmRlZmluZWQgJiYgIXRoaXMuZ2V0QWRkcmVzc2VzKCkuaW5jbHVkZXModHJhbnNmZXIuZ2V0QWRkcmVzcygpKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgaWYgKHRoaXMuZ2V0U3ViYWRkcmVzc0luZGV4KCkgIT09IHVuZGVmaW5lZCAmJiB0aGlzLmdldFN1YmFkZHJlc3NJbmRleCgpICE9PSB0cmFuc2Zlci5nZXRTdWJhZGRyZXNzSW5kZXgoKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgaWYgKHRoaXMuZ2V0U3ViYWRkcmVzc0luZGljZXMoKSAhPT0gdW5kZWZpbmVkICYmICF0aGlzLmdldFN1YmFkZHJlc3NJbmRpY2VzKCkuaW5jbHVkZXModHJhbnNmZXIuZ2V0U3ViYWRkcmVzc0luZGV4KCkpKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gZmlsdGVyIG9uIG91dGdvaW5nIGZpZWxkc1xuICAgIGVsc2UgaWYgKHRyYW5zZmVyIGluc3RhbmNlb2YgTW9uZXJvT3V0Z29pbmdUcmFuc2Zlcikge1xuICAgICAgXG4gICAgICAvLyBmaWx0ZXIgb24gYWRkcmVzc2VzIHdoaWNoIG11c3QgaGF2ZSBvdmVybGFwXG4gICAgICBpZiAodGhpcy5nZXRBZGRyZXNzKCkgIT09IHVuZGVmaW5lZCAmJiAodHJhbnNmZXIuZ2V0QWRkcmVzc2VzKCkgPT09IHVuZGVmaW5lZCB8fCAhdHJhbnNmZXIuZ2V0QWRkcmVzc2VzKCkuaW5jbHVkZXModGhpcy5nZXRBZGRyZXNzKCkpKSkgcmV0dXJuIGZhbHNlOyAgIC8vIFRPRE86IHdpbGwgZmlsdGVyIGFsbCB0cmFuc2ZlcnMgdGhhdCBkb24ndCBjb250YWluIGFkZHJlc3NlcyAob3V0Z29pbmcgdHhzIG1pZ2h0IG5vdCBoYXZlIHRoaXMgZmllbGQgaW5pdGlhbGl6ZWQpXG4gICAgICBpZiAodGhpcy5nZXRBZGRyZXNzZXMoKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGlmICghdHJhbnNmZXIuZ2V0QWRkcmVzc2VzKCkpIHJldHVybiBmYWxzZTtcbiAgICAgICAgaWYgKCF0aGlzLmdldEFkZHJlc3NlcygpLnNvbWUoYWRkcmVzcyA9PiB0cmFuc2Zlci5nZXRBZGRyZXNzZXMoKS5pbmNsdWRlcyhhZGRyZXNzKSkpIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gZmlsdGVyIG9uIHN1YmFkZHJlc3MgaW5kaWNlc1xuICAgICAgaWYgKHRoaXMuZ2V0U3ViYWRkcmVzc0luZGV4KCkgIT09IHVuZGVmaW5lZCAmJiAodHJhbnNmZXIuZ2V0U3ViYWRkcmVzc0luZGljZXMoKSA9PT0gdW5kZWZpbmVkIHx8ICF0cmFuc2Zlci5nZXRTdWJhZGRyZXNzSW5kaWNlcygpLmluY2x1ZGVzKHRoaXMuZ2V0U3ViYWRkcmVzc0luZGV4KCkpKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgaWYgKHRoaXMuZ2V0U3ViYWRkcmVzc0luZGljZXMoKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGlmICghdHJhbnNmZXIuZ2V0U3ViYWRkcmVzc0luZGljZXMoKSkgcmV0dXJuIGZhbHNlO1xuICAgICAgICBpZiAoIXRoaXMuZ2V0U3ViYWRkcmVzc0luZGljZXMoKS5zb21lKHN1YmFkZHJlc3NJZHggPT4gdHJhbnNmZXIuZ2V0U3ViYWRkcmVzc0luZGljZXMoKS5pbmNsdWRlcyhzdWJhZGRyZXNzSWR4KSkpIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgLy8gZmlsdGVyIG9uIGhhdmluZyBkZXN0aW5hdGlvbnNcbiAgICAgIGlmICh0aGlzLmdldEhhc0Rlc3RpbmF0aW9ucygpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgaWYgKHRoaXMuZ2V0SGFzRGVzdGluYXRpb25zKCkgJiYgdHJhbnNmZXIuZ2V0RGVzdGluYXRpb25zKCkgPT09IHVuZGVmaW5lZCkgcmV0dXJuIGZhbHNlO1xuICAgICAgICBpZiAoIXRoaXMuZ2V0SGFzRGVzdGluYXRpb25zKCkgJiYgdHJhbnNmZXIuZ2V0RGVzdGluYXRpb25zKCkgIT09IHVuZGVmaW5lZCkgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBmaWx0ZXIgb24gZGVzdGluYXRpb25zIFRPRE86IHN0YXJ0IHdpdGggdGVzdCBmb3IgdGhpc1xuLy8gICAgaWYgKHRoaXMuZ2V0RGVzdGlvbmF0aW9ucygpICE9PSB1bmRlZmluZWQgJiYgdGhpcy5nZXREZXN0aW9uYXRpb25zKCkgIT09IHRyYW5zZmVyLmdldERlc3Rpb25hdGlvbnMoKSkgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBcbiAgICAvLyBvdGhlcndpc2UgaW52YWxpZCB0eXBlXG4gICAgZWxzZSB0aHJvdyBuZXcgRXJyb3IoXCJUcmFuc2ZlciBtdXN0IGJlIE1vbmVyb0luY29taW5nVHJhbnNmZXIgb3IgTW9uZXJvT3V0Z29pbmdUcmFuc2ZlclwiKTtcbiAgICBcbiAgICAvLyBmaWx0ZXIgd2l0aCB0eCBmaWx0ZXJcbiAgICBpZiAocXVlcnlQYXJlbnQgJiYgdGhpcy5nZXRUeFF1ZXJ5KCkgIT09IHVuZGVmaW5lZCAmJiAhdGhpcy5nZXRUeFF1ZXJ5KCkubWVldHNDcml0ZXJpYSh0cmFuc2Zlci5nZXRUeCgpKSkgcmV0dXJuIGZhbHNlOyAgICBcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICBcbiAgdmFsaWRhdGUoKSB7XG4gICAgaWYgKHRoaXMuZ2V0U3ViYWRkcmVzc0luZGV4KCkgIT09IHVuZGVmaW5lZCAmJiB0aGlzLmdldFN1YmFkZHJlc3NJbmRleCgpIDwgMCkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiU3ViYWRkcmVzcyBpbmRleCBtdXN0IGJlID49IDBcIik7XG4gICAgaWYgKHRoaXMuZ2V0U3ViYWRkcmVzc0luZGljZXMoKSAhPT0gdW5kZWZpbmVkKSBmb3IgKGxldCBzdWJhZGRyZXNzSWR4IG9mIHRoaXMuZ2V0U3ViYWRkcmVzc0luZGljZXMoKSkgaWYgKHN1YmFkZHJlc3NJZHggPCAwKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJTdWJhZGRyZXNzIGluZGljZXMgbXVzdCBiZSA+PSAwXCIpO1xuICB9XG5cbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLSBPVkVSUklERSBDT1ZBUklBTlQgUkVUVVJOIFRZUEVTIC0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gICAgc2V0VHgodHg6IE1vbmVyb1R4V2FsbGV0KTogTW9uZXJvVHJhbnNmZXJRdWVyeSB7XG4gICAgICBzdXBlci5zZXRUeCh0eCk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG4gIFxuICAgIHNldEFtb3VudChhbW91bnQ6IGJpZ2ludCk6IE1vbmVyb1RyYW5zZmVyUXVlcnkge1xuICAgICAgc3VwZXIuc2V0QW1vdW50KGFtb3VudCk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG4gIFxuICAgIHNldEFjY291bnRJbmRleChhY2NvdW50SW5kZXg6IG51bWJlcik6IE1vbmVyb1RyYW5zZmVyUXVlcnkge1xuICAgICAgc3VwZXIuc2V0QWNjb3VudEluZGV4KGFjY291bnRJbmRleCk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG59XG4iXSwibWFwcGluZ3MiOiI7O0FBRUEsSUFBQUEsdUJBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLHVCQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRSxlQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7O0FBRUEsSUFB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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroTxConfig.d.ts b/dist/src/main/ts/wallet/model/MoneroTxConfig.d.ts new file mode 100644 index 000000000..7fd2dbf03 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTxConfig.d.ts @@ -0,0 +1,145 @@ +import MoneroDestination from "./MoneroDestination"; +import MoneroTxPriority from "./MoneroTxPriority"; +/** + * Configures a transaction to send, sweep, or create a payment URI. + */ +export default class MoneroTxConfig { + /** Single destination address (required unless `destinations` provided). */ + address: string; + /** Single destination amount (required unless `destinations provided). */ + amount: bigint; + /** Source account index to transfer funds from (required unless sweeping key image). */ + accountIndex: number; + /** Source subaddress index to send funds from (default all). */ + subaddressIndex: number; + /** Source subaddresses to send funds from (default all). */ + subaddressIndices: number[]; + /** Relay the transaction to peers to commit to the blockchain if true (default false). */ + relay: boolean; + /** Transaction priority to adjust the miner fee (default MoneroTxPriority.NORMAL). */ + priority: MoneroTxPriority; + /** Multiple destinations to send funds to, if applicable. */ + destinations: Partial[]; + /** List of destination indices to split the miner fee (optional). */ + subtractFeeFrom: number[]; + /** Payment ID for the transaction. */ + paymentId: string; + /** Miner fee (calculated automatically). */ + fee: bigint; + /** Transaction note saved locally with the wallet (optional). */ + note: string; + /** Recipient name saved locally with the wallet (optional). */ + recipientName: string; + /** Allow funds to be transferred using multiple transactions if necessary (default false). */ + canSplit: boolean; + /** For sweep requests, include outputs below this amount when sweeping wallet, account, subaddress, or all unlocked funds. */ + belowAmount: bigint; + /** For sweep requests, sweep each subaddress individually instead of together if true. */ + sweepEachSubaddress: boolean; + /** For sweep requests, key image of the output to sweep. */ + keyImage: string; + /** + *

Generic request to transfer funds from a wallet.

+ * + *

Example:

+ * + * + * let config1 = new MoneroTxConfig({
+ *    accountIndex: 0,
+ *    address: "59aZULsUF3YN...",
+ *    amount: 500000n,
+ *    priority: MoneroTxPriority.NORMAL,
+ *    relay: true
+ * }); + *
+ * + * @param {Partial} [config] - configures the transaction to create (optional) + * @param {string} [config.address] - single destination address + * @param {bigint} [config.amount] - single destination amount + * @param {number} [config.accountIndex] - source account index to transfer funds from + * @param {number} [config.subaddressIndex] - source subaddress index to transfer funds from + * @param {number[]} [config.subaddressIndices] - source subaddress indices to transfer funds from + * @param {boolean} [config.relay] - relay the transaction to peers to commit to the blockchain + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @param {MoneroDestination[]} [config.destinations] - addresses and amounts in a multi-destination tx + * @param {number[]} [config.subtractFeeFrom] - list of destination indices to split the transaction fee + * @param {string} [config.paymentId] - transaction payment ID + * @param {bigint} [config.unlockTime] - minimum height or timestamp for the transaction to unlock (default 0) + * @param {string} [config.note] - transaction note saved locally with the wallet + * @param {string} [config.recipientName] - recipient name saved locally with the wallet + * @param {boolean} [config.canSplit] - allow funds to be transferred using multiple transactions + * @param {bigint} [config.belowAmount] - for sweep requests, include outputs below this amount when sweeping wallet, account, subaddress, or all unlocked funds + * @param {boolean} [config.sweepEachSubaddress] - for sweep requests, sweep each subaddress individually instead of together if true + * @param {string} [config.keyImage] - key image to sweep (ignored except in sweepOutput() requests) + */ + constructor(config?: Partial); + copy(): MoneroTxConfig; + toJson(): any; + /** + * Set the address of a single-destination configuration. + * + * @param {string} address - the address to set for the single destination + * @return {MoneroTxConfig} this configuration for chaining + */ + setAddress(address: string): MoneroTxConfig; + /** + * Get the address of a single-destination configuration. + * + * @return {string} the address of the single destination + */ + getAddress(): string; + /** + * Set the amount of a single-destination configuration. + * + * @param {bigint} amount - the amount to set for the single destination + * @return {MoneroTxConfig} this configuration for chaining + */ + setAmount(amount: bigint): MoneroTxConfig; + /** + * Get the amount of a single-destination configuration. + * + * @return {bigint} the amount of the single destination + */ + getAmount(): bigint; + addDestination(destinationOrAddress: MoneroDestination | string, amount?: bigint): MoneroTxConfig; + getDestinations(): MoneroDestination[]; + setDestinations(destinations: MoneroDestination[]): MoneroTxConfig; + setDestination(destination: MoneroDestination): MoneroTxConfig; + getSubtractFeeFrom(): number[]; + setSubtractFeeFrom(destinationIndices: number[]): MoneroTxConfig; + getPaymentId(): string; + setPaymentId(paymentId: string): MoneroTxConfig; + getPriority(): number; + setPriority(priority: number): MoneroTxConfig; + getFee(): bigint; + setFee(fee: bigint): MoneroTxConfig; + getAccountIndex(): number; + setAccountIndex(accountIndex: number): MoneroTxConfig; + setSubaddressIndex(subaddressIndex: number): MoneroTxConfig; + getSubaddressIndices(): number[]; + setSubaddressIndices(subaddressIndices: number[]): MoneroTxConfig; + getRelay(): boolean; + setRelay(relay: boolean): MoneroTxConfig; + getCanSplit(): boolean; + setCanSplit(canSplit: boolean): MoneroTxConfig; + getNote(): string; + setNote(note: string): MoneroTxConfig; + getRecipientName(): string; + setRecipientName(recipientName: string): MoneroTxConfig; + getBelowAmount(): bigint; + setBelowAmount(belowAmount: any): this; + getSweepEachSubaddress(): boolean; + setSweepEachSubaddress(sweepEachSubaddress: any): this; + /** + * Get the key image hex of the output to sweep. + * + * return {string} is the key image hex of the output to sweep + */ + getKeyImage(): string; + /** + * Set the key image hex of the output to sweep. + * + * @param {string} keyImage is the key image hex of the output to sweep + */ + setKeyImage(keyImage: any): this; +} diff --git a/dist/src/main/ts/wallet/model/MoneroTxConfig.js b/dist/src/main/ts/wallet/model/MoneroTxConfig.js new file mode 100644 index 000000000..4739c9e70 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTxConfig.js @@ -0,0 +1,350 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _MoneroDestination = _interopRequireDefault(require("./MoneroDestination")); +var _MoneroError = _interopRequireDefault(require("../../common/MoneroError")); + + +/** + * Configures a transaction to send, sweep, or create a payment URI. + */ +class MoneroTxConfig { + + /** Single destination address (required unless `destinations` provided). */ + + + /** Single destination amount (required unless `destinations provided). */ + + + /** Source account index to transfer funds from (required unless sweeping key image). */ + + + /** Source subaddress index to send funds from (default all). */ + + + /** Source subaddresses to send funds from (default all). */ + + + /** Relay the transaction to peers to commit to the blockchain if true (default false). */ + + + /** Transaction priority to adjust the miner fee (default MoneroTxPriority.NORMAL). */ + + + /** Multiple destinations to send funds to, if applicable. */ + + + /** List of destination indices to split the miner fee (optional). */ + + + /** Payment ID for the transaction. */ + + + /** Miner fee (calculated automatically). */ + + + /** Transaction note saved locally with the wallet (optional). */ + + + /** Recipient name saved locally with the wallet (optional). */ + + + /** Allow funds to be transferred using multiple transactions if necessary (default false). */ + + + /** For sweep requests, include outputs below this amount when sweeping wallet, account, subaddress, or all unlocked funds. */ + + + /** For sweep requests, sweep each subaddress individually instead of together if true. */ + + + /** For sweep requests, key image of the output to sweep. */ + + + /** + *

Generic request to transfer funds from a wallet.

+ * + *

Example:

+ * + * + * let config1 = new MoneroTxConfig({
+ *    accountIndex: 0,
+ *    address: "59aZULsUF3YN...",
+ *    amount: 500000n,
+ *    priority: MoneroTxPriority.NORMAL,
+ *    relay: true
+ * }); + *
+ * + * @param {Partial} [config] - configures the transaction to create (optional) + * @param {string} [config.address] - single destination address + * @param {bigint} [config.amount] - single destination amount + * @param {number} [config.accountIndex] - source account index to transfer funds from + * @param {number} [config.subaddressIndex] - source subaddress index to transfer funds from + * @param {number[]} [config.subaddressIndices] - source subaddress indices to transfer funds from + * @param {boolean} [config.relay] - relay the transaction to peers to commit to the blockchain + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @param {MoneroDestination[]} [config.destinations] - addresses and amounts in a multi-destination tx + * @param {number[]} [config.subtractFeeFrom] - list of destination indices to split the transaction fee + * @param {string} [config.paymentId] - transaction payment ID + * @param {bigint} [config.unlockTime] - minimum height or timestamp for the transaction to unlock (default 0) + * @param {string} [config.note] - transaction note saved locally with the wallet + * @param {string} [config.recipientName] - recipient name saved locally with the wallet + * @param {boolean} [config.canSplit] - allow funds to be transferred using multiple transactions + * @param {bigint} [config.belowAmount] - for sweep requests, include outputs below this amount when sweeping wallet, account, subaddress, or all unlocked funds + * @param {boolean} [config.sweepEachSubaddress] - for sweep requests, sweep each subaddress individually instead of together if true + * @param {string} [config.keyImage] - key image to sweep (ignored except in sweepOutput() requests) + */ + constructor(config) { + Object.assign(this, config); + + // deserialize bigints + if (this.amount !== undefined && typeof this.amount !== "bigint") this.amount = BigInt(this.amount); + if (this.fee !== undefined && typeof this.fee !== "bigint") this.fee = BigInt(this.fee); + if (this.belowAmount !== undefined && typeof this.belowAmount !== "bigint") this.belowAmount = BigInt(this.belowAmount); + + // copy destinations + if (this.destinations) { + (0, _assert.default)(this.address === undefined && this.amount === undefined, "Tx configuration may specify destinations or an address/amount but not both"); + this.setDestinations(this.destinations.map((destination) => new _MoneroDestination.default(destination))); + } + + // alias 'address' and 'amount' to single destination to support e.g. createTx({address: "..."}) + if (this.address || this.amount) { + (0, _assert.default)(!this.destinations, "Tx configuration may specify destinations or an address/amount but not both"); + this.setAddress(this.address); + this.setAmount(this.amount); + delete this.address; + delete this.amount; + } + + // alias 'subaddressIndex' to subaddress indices + if (this.subaddressIndex !== undefined) { + this.setSubaddressIndices([this.subaddressIndex]); + delete this.subaddressIndex; + } + } + + copy() { + return new MoneroTxConfig(this); + } + + toJson() { + let json = Object.assign({}, this); // copy state + if (this.getDestinations() !== undefined) { + json.destinations = []; + for (let destination of this.getDestinations()) json.destinations.push(destination.toJson()); + } + if (this.getFee()) json.fee = this.getFee().toString(); + if (this.getBelowAmount()) json.belowAmount = this.getBelowAmount().toString(); + return json; + } + + /** + * Set the address of a single-destination configuration. + * + * @param {string} address - the address to set for the single destination + * @return {MoneroTxConfig} this configuration for chaining + */ + setAddress(address) { + if (this.destinations !== undefined && this.destinations.length > 1) throw new _MoneroError.default("Cannot set address because MoneroTxConfig already has multiple destinations"); + if (this.destinations === undefined || this.destinations.length === 0) this.addDestination(new _MoneroDestination.default(address));else + this.destinations[0].setAddress(address); + return this; + } + + /** + * Get the address of a single-destination configuration. + * + * @return {string} the address of the single destination + */ + getAddress() { + if (this.destinations === undefined || this.destinations.length !== 1) throw new _MoneroError.default("Cannot get address because MoneroTxConfig does not have exactly one destination"); + return this.destinations[0].getAddress(); + } + + /** + * Set the amount of a single-destination configuration. + * + * @param {bigint} amount - the amount to set for the single destination + * @return {MoneroTxConfig} this configuration for chaining + */ + setAmount(amount) { + if (amount !== undefined && typeof this.amount !== "bigint") { + if (typeof amount === "number") throw new _MoneroError.default("Destination amount must be bigint or string"); + try {amount = BigInt(amount);} + catch (err) {throw new _MoneroError.default("Invalid destination amount: " + amount);} + } + if (this.destinations !== undefined && this.destinations.length > 1) throw new _MoneroError.default("Cannot set amount because MoneroTxConfig already has multiple destinations"); + if (this.destinations === undefined || this.destinations.length === 0) this.addDestination(new _MoneroDestination.default(undefined, amount));else + this.destinations[0].setAmount(amount); + return this; + } + + /** + * Get the amount of a single-destination configuration. + * + * @return {bigint} the amount of the single destination + */ + getAmount() { + if (this.destinations === undefined || this.destinations.length !== 1) throw new _MoneroError.default("Cannot get amount because MoneroTxConfig does not have exactly one destination"); + return this.destinations[0].getAmount(); + } + + addDestination(destinationOrAddress, amount) { + if (typeof destinationOrAddress === "string") return this.addDestination(new _MoneroDestination.default(destinationOrAddress, amount)); + (0, _assert.default)(destinationOrAddress instanceof _MoneroDestination.default); + if (this.destinations === undefined) this.destinations = []; + this.destinations.push(destinationOrAddress); + return this; + } + + getDestinations() { + return this.destinations; + } + + setDestinations(destinations) { + if (arguments.length > 1) destinations = Array.from(arguments); + this.destinations = destinations; + return this; + } + + setDestination(destination) { + return this.setDestinations(destination ? [destination] : undefined); + } + + getSubtractFeeFrom() { + return this.subtractFeeFrom; + } + + setSubtractFeeFrom(destinationIndices) { + if (arguments.length > 1) destinationIndices = Array.from(arguments); + this.subtractFeeFrom = destinationIndices; + return this; + } + + getPaymentId() { + return this.paymentId; + } + + setPaymentId(paymentId) { + this.paymentId = paymentId; + return this; + } + + getPriority() { + return this.priority; + } + + setPriority(priority) { + this.priority = priority; + return this; + } + + getFee() { + return this.fee; + } + + setFee(fee) { + this.fee = fee; + return this; + } + + getAccountIndex() { + return this.accountIndex; + } + + setAccountIndex(accountIndex) { + this.accountIndex = accountIndex; + return this; + } + + setSubaddressIndex(subaddressIndex) { + this.setSubaddressIndices([subaddressIndex]); + return this; + } + + getSubaddressIndices() { + return this.subaddressIndices; + } + + setSubaddressIndices(subaddressIndices) { + if (arguments.length > 1) subaddressIndices = Array.from(arguments); + this.subaddressIndices = subaddressIndices; + return this; + } + + getRelay() { + return this.relay; + } + + setRelay(relay) { + this.relay = relay; + return this; + } + + getCanSplit() { + return this.canSplit; + } + + setCanSplit(canSplit) { + this.canSplit = canSplit; + return this; + } + + getNote() { + return this.note; + } + + setNote(note) { + this.note = note; + return this; + } + + getRecipientName() { + return this.recipientName; + } + + setRecipientName(recipientName) { + this.recipientName = recipientName; + return this; + } + + // --------------------------- SPECIFIC TO SWEEP ---------------------------- + + getBelowAmount() { + return this.belowAmount; + } + + setBelowAmount(belowAmount) { + this.belowAmount = belowAmount; + return this; + } + + getSweepEachSubaddress() { + return this.sweepEachSubaddress; + } + + setSweepEachSubaddress(sweepEachSubaddress) { + this.sweepEachSubaddress = sweepEachSubaddress; + return this; + } + + /** + * Get the key image hex of the output to sweep. + * + * return {string} is the key image hex of the output to sweep + */ + getKeyImage() { + return this.keyImage; + } + + /** + * Set the key image hex of the output to sweep. + * + * @param {string} keyImage is the key image hex of the output to sweep + */ + setKeyImage(keyImage) { + this.keyImage = keyImage; + return this; + } +}exports.default = MoneroTxConfig; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfTW9uZXJvRGVzdGluYXRpb24iLCJfTW9uZXJvRXJyb3IiLCJNb25lcm9UeENvbmZpZyIsImNvbnN0cnVjdG9yIiwiY29uZmlnIiwiT2JqZWN0IiwiYXNzaWduIiwiYW1vdW50IiwidW5kZWZpbmVkIiwiQmlnSW50IiwiZmVlIiwiYmVsb3dBbW91bnQiLCJkZXN0aW5hdGlvbnMiLCJhc3NlcnQiLCJhZGRyZXNzIiwic2V0RGVzdGluYXRpb25zIiwibWFwIiwiZGVzdGluYXRpb24iLCJNb25lcm9EZXN0aW5hdGlvbiIsInNldEFkZHJlc3MiLCJzZXRBbW91bnQiLCJzdWJhZGRyZXNzSW5kZXgiLCJzZXRTdWJhZGRyZXNzSW5kaWNlcyIsImNvcHkiLCJ0b0pzb24iLCJqc29uIiwiZ2V0RGVzdGluYXRpb25zIiwicHVzaCIsImdldEZlZSIsInRvU3RyaW5nIiwiZ2V0QmVsb3dBbW91bnQiLCJsZW5ndGgiLCJNb25lcm9FcnJvciIsImFkZERlc3RpbmF0aW9uIiwiZ2V0QWRkcmVzcyIsImVyciIsImdldEFtb3VudCIsImRlc3RpbmF0aW9uT3JBZGRyZXNzIiwiYXJndW1lbnRzIiwiQXJyYXkiLCJmcm9tIiwic2V0RGVzdGluYXRpb24iLCJnZXRTdWJ0cmFjdEZlZUZyb20iLCJzdWJ0cmFjdEZlZUZyb20iLCJzZXRTdWJ0cmFjdEZlZUZyb20iLCJkZXN0aW5hdGlvbkluZGljZXMiLCJnZXRQYXltZW50SWQiLCJwYXltZW50SWQiLCJzZXRQYXltZW50SWQiLCJnZXRQcmlvcml0eSIsInByaW9yaXR5Iiwic2V0UHJpb3JpdHkiLCJzZXRGZWUiLCJnZXRBY2NvdW50SW5kZXgiLCJhY2NvdW50SW5kZXgiLCJzZXRBY2NvdW50SW5kZXgiLCJzZXRTdWJhZGRyZXNzSW5kZXgiLCJnZXRTdWJhZGRyZXNzSW5kaWNlcyIsInN1YmFkZHJlc3NJbmRpY2VzIiwiZ2V0UmVsYXkiLCJyZWxheSIsInNldFJlbGF5IiwiZ2V0Q2FuU3BsaXQiLCJjYW5TcGxpdCIsInNldENhblNwbGl0IiwiZ2V0Tm90ZSIsIm5vdGUiLCJzZXROb3RlIiwiZ2V0UmVjaXBpZW50TmFtZSIsInJlY2lwaWVudE5hbWUiLCJzZXRSZWNpcGllbnROYW1lIiwic2V0QmVsb3dBbW91bnQiLCJnZXRTd2VlcEVhY2hTdWJhZGRyZXNzIiwic3dlZXBFYWNoU3ViYWRkcmVzcyIsInNldFN3ZWVwRWFjaFN1YmFkZHJlc3MiLCJnZXRLZXlJbWFnZSIsImtleUltYWdlIiwic2V0S2V5SW1hZ2UiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9UeENvbmZpZy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBNb25lcm9EZXN0aW5hdGlvbiBmcm9tIFwiLi9Nb25lcm9EZXN0aW5hdGlvblwiO1xuaW1wb3J0IE1vbmVyb0Vycm9yIGZyb20gXCIuLi8uLi9jb21tb24vTW9uZXJvRXJyb3JcIjtcbmltcG9ydCBNb25lcm9UeFByaW9yaXR5IGZyb20gXCIuL01vbmVyb1R4UHJpb3JpdHlcIjtcblxuLyoqXG4gKiBDb25maWd1cmVzIGEgdHJhbnNhY3Rpb24gdG8gc2VuZCwgc3dlZXAsIG9yIGNyZWF0ZSBhIHBheW1lbnQgVVJJLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9UeENvbmZpZyB7XG5cbiAgLyoqIFNpbmdsZSBkZXN0aW5hdGlvbiBhZGRyZXNzIChyZXF1aXJlZCB1bmxlc3MgYGRlc3RpbmF0aW9uc2AgcHJvdmlkZWQpLiAqL1xuICBhZGRyZXNzOiBzdHJpbmc7XG5cbiAgLyoqIFNpbmdsZSBkZXN0aW5hdGlvbiBhbW91bnQgKHJlcXVpcmVkIHVubGVzcyBgZGVzdGluYXRpb25zIHByb3ZpZGVkKS4gKi9cbiAgYW1vdW50OiBiaWdpbnQ7XG5cbiAgLyoqIFNvdXJjZSBhY2NvdW50IGluZGV4IHRvIHRyYW5zZmVyIGZ1bmRzIGZyb20gKHJlcXVpcmVkIHVubGVzcyBzd2VlcGluZyBrZXkgaW1hZ2UpLiAqL1xuICBhY2NvdW50SW5kZXg6IG51bWJlcjtcblxuICAvKiogU291cmNlIHN1YmFkZHJlc3MgaW5kZXggdG8gc2VuZCBmdW5kcyBmcm9tIChkZWZhdWx0IGFsbCkuICovXG4gIHN1YmFkZHJlc3NJbmRleDogbnVtYmVyO1xuXG4gIC8qKiBTb3VyY2Ugc3ViYWRkcmVzc2VzIHRvIHNlbmQgZnVuZHMgZnJvbSAoZGVmYXVsdCBhbGwpLiAqL1xuICBzdWJhZGRyZXNzSW5kaWNlczogbnVtYmVyW107XG5cbiAgLyoqIFJlbGF5IHRoZSB0cmFuc2FjdGlvbiB0byBwZWVycyB0byBjb21taXQgdG8gdGhlIGJsb2NrY2hhaW4gaWYgdHJ1ZSAoZGVmYXVsdCBmYWxzZSkuICovXG4gIHJlbGF5OiBib29sZWFuO1xuXG4gIC8qKiBUcmFuc2FjdGlvbiBwcmlvcml0eSB0byBhZGp1c3QgdGhlIG1pbmVyIGZlZSAoZGVmYXVsdCBNb25lcm9UeFByaW9yaXR5Lk5PUk1BTCkuICovXG4gIHByaW9yaXR5OiBNb25lcm9UeFByaW9yaXR5O1xuXG4gIC8qKiBNdWx0aXBsZSBkZXN0aW5hdGlvbnMgdG8gc2VuZCBmdW5kcyB0bywgaWYgYXBwbGljYWJsZS4gKi9cbiAgZGVzdGluYXRpb25zOiBQYXJ0aWFsPE1vbmVyb0Rlc3RpbmF0aW9uPltdO1xuXG4gIC8qKiBMaXN0IG9mIGRlc3RpbmF0aW9uIGluZGljZXMgdG8gc3BsaXQgdGhlIG1pbmVyIGZlZSAob3B0aW9uYWwpLiAqL1xuICBzdWJ0cmFjdEZlZUZyb206IG51bWJlcltdO1xuXG4gIC8qKiBQYXltZW50IElEIGZvciB0aGUgdHJhbnNhY3Rpb24uICovXG4gIHBheW1lbnRJZDogc3RyaW5nO1xuXG4gIC8qKiBNaW5lciBmZWUgKGNhbGN1bGF0ZWQgYXV0b21hdGljYWxseSkuICovXG4gIGZlZTogYmlnaW50O1xuXG4gIC8qKiBUcmFuc2FjdGlvbiBub3RlIHNhdmVkIGxvY2FsbHkgd2l0aCB0aGUgd2FsbGV0IChvcHRpb25hbCkuICovXG4gIG5vdGU6IHN0cmluZztcblxuICAvKiogUmVjaXBpZW50IG5hbWUgc2F2ZWQgbG9jYWxseSB3aXRoIHRoZSB3YWxsZXQgKG9wdGlvbmFsKS4gKi9cbiAgcmVjaXBpZW50TmFtZTogc3RyaW5nO1xuXG4gIC8qKiBBbGxvdyBmdW5kcyB0byBiZSB0cmFuc2ZlcnJlZCB1c2luZyBtdWx0aXBsZSB0cmFuc2FjdGlvbnMgaWYgbmVjZXNzYXJ5IChkZWZhdWx0IGZhbHNlKS4gKi9cbiAgY2FuU3BsaXQ6IGJvb2xlYW47XG5cbiAgLyoqIEZvciBzd2VlcCByZXF1ZXN0cywgaW5jbHVkZSBvdXRwdXRzIGJlbG93IHRoaXMgYW1vdW50IHdoZW4gc3dlZXBpbmcgd2FsbGV0LCBhY2NvdW50LCBzdWJhZGRyZXNzLCBvciBhbGwgdW5sb2NrZWQgZnVuZHMuICovXG4gIGJlbG93QW1vdW50OiBiaWdpbnQ7XG5cbiAgLyoqIEZvciBzd2VlcCByZXF1ZXN0cywgc3dlZXAgZWFjaCBzdWJhZGRyZXNzIGluZGl2aWR1YWxseSBpbnN0ZWFkIG9mIHRvZ2V0aGVyIGlmIHRydWUuICovXG4gIHN3ZWVwRWFjaFN1YmFkZHJlc3M6IGJvb2xlYW47XG5cbiAgLyoqIEZvciBzd2VlcCByZXF1ZXN0cywga2V5IGltYWdlIG9mIHRoZSBvdXRwdXQgdG8gc3dlZXAuICovXG4gIGtleUltYWdlOiBzdHJpbmc7XG4gIFxuICAvKipcbiAgICogPHA+R2VuZXJpYyByZXF1ZXN0IHRvIHRyYW5zZmVyIGZ1bmRzIGZyb20gYSB3YWxsZXQuPC9wPlxuICAgKiBcbiAgICogPHA+RXhhbXBsZTo8L3A+XG4gICAqIFxuICAgKiA8Y29kZT5cbiAgICogbGV0IGNvbmZpZzEgPSBuZXcgTW9uZXJvVHhDb25maWcoezxicj5cbiAgICogJm5ic3A7Jm5ic3A7IGFjY291bnRJbmRleDogMCw8YnI+XG4gICAqICZuYnNwOyZuYnNwOyBhZGRyZXNzOiBcIjU5YVpVTHNVRjNZTi4uLlwiLDxicj5cbiAgICogJm5ic3A7Jm5ic3A7IGFtb3VudDogNTAwMDAwbiw8YnI+XG4gICAqICZuYnNwOyZuYnNwOyBwcmlvcml0eTogTW9uZXJvVHhQcmlvcml0eS5OT1JNQUwsPGJyPlxuICAgKiAmbmJzcDsmbmJzcDsgcmVsYXk6IHRydWU8YnI+XG4gICAqIH0pO1xuICAgKiA8L2NvZGU+XG4gICAqIFxuICAgKiBAcGFyYW0ge1BhcnRpYWw8TW9uZXJvVHhDb25maWc+fSBbY29uZmlnXSAtIGNvbmZpZ3VyZXMgdGhlIHRyYW5zYWN0aW9uIHRvIGNyZWF0ZSAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbY29uZmlnLmFkZHJlc3NdIC0gc2luZ2xlIGRlc3RpbmF0aW9uIGFkZHJlc3NcbiAgICogQHBhcmFtIHtiaWdpbnR9IFtjb25maWcuYW1vdW50XSAtIHNpbmdsZSBkZXN0aW5hdGlvbiBhbW91bnRcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtjb25maWcuYWNjb3VudEluZGV4XSAtIHNvdXJjZSBhY2NvdW50IGluZGV4IHRvIHRyYW5zZmVyIGZ1bmRzIGZyb21cbiAgICogQHBhcmFtIHtudW1iZXJ9IFtjb25maWcuc3ViYWRkcmVzc0luZGV4XSAtIHNvdXJjZSBzdWJhZGRyZXNzIGluZGV4IHRvIHRyYW5zZmVyIGZ1bmRzIGZyb21cbiAgICogQHBhcmFtIHtudW1iZXJbXX0gW2NvbmZpZy5zdWJhZGRyZXNzSW5kaWNlc10gLSBzb3VyY2Ugc3ViYWRkcmVzcyBpbmRpY2VzIHRvIHRyYW5zZmVyIGZ1bmRzIGZyb21cbiAgICogQHBhcmFtIHtib29sZWFufSBbY29uZmlnLnJlbGF5XSAtIHJlbGF5IHRoZSB0cmFuc2FjdGlvbiB0byBwZWVycyB0byBjb21taXQgdG8gdGhlIGJsb2NrY2hhaW5cbiAgICogQHBhcmFtIHtNb25lcm9UeFByaW9yaXR5fSBbY29uZmlnLnByaW9yaXR5XSAtIHRyYW5zYWN0aW9uIHByaW9yaXR5IChkZWZhdWx0IE1vbmVyb1R4UHJpb3JpdHkuTk9STUFMKVxuICAgKiBAcGFyYW0ge01vbmVyb0Rlc3RpbmF0aW9uW119IFtjb25maWcuZGVzdGluYXRpb25zXSAtIGFkZHJlc3NlcyBhbmQgYW1vdW50cyBpbiBhIG11bHRpLWRlc3RpbmF0aW9uIHR4XG4gICAqIEBwYXJhbSB7bnVtYmVyW119IFtjb25maWcuc3VidHJhY3RGZWVGcm9tXSAtIGxpc3Qgb2YgZGVzdGluYXRpb24gaW5kaWNlcyB0byBzcGxpdCB0aGUgdHJhbnNhY3Rpb24gZmVlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbY29uZmlnLnBheW1lbnRJZF0gLSB0cmFuc2FjdGlvbiBwYXltZW50IElEXG4gICAqIEBwYXJhbSB7YmlnaW50fSBbY29uZmlnLnVubG9ja1RpbWVdIC0gbWluaW11bSBoZWlnaHQgb3IgdGltZXN0YW1wIGZvciB0aGUgdHJhbnNhY3Rpb24gdG8gdW5sb2NrIChkZWZhdWx0IDApXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbY29uZmlnLm5vdGVdIC0gdHJhbnNhY3Rpb24gbm90ZSBzYXZlZCBsb2NhbGx5IHdpdGggdGhlIHdhbGxldFxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2NvbmZpZy5yZWNpcGllbnROYW1lXSAtIHJlY2lwaWVudCBuYW1lIHNhdmVkIGxvY2FsbHkgd2l0aCB0aGUgd2FsbGV0XG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2NvbmZpZy5jYW5TcGxpdF0gLSBhbGxvdyBmdW5kcyB0byBiZSB0cmFuc2ZlcnJlZCB1c2luZyBtdWx0aXBsZSB0cmFuc2FjdGlvbnNcbiAgICogQHBhcmFtIHtiaWdpbnR9IFtjb25maWcuYmVsb3dBbW91bnRdIC0gZm9yIHN3ZWVwIHJlcXVlc3RzLCBpbmNsdWRlIG91dHB1dHMgYmVsb3cgdGhpcyBhbW91bnQgd2hlbiBzd2VlcGluZyB3YWxsZXQsIGFjY291bnQsIHN1YmFkZHJlc3MsIG9yIGFsbCB1bmxvY2tlZCBmdW5kcyBcbiAgICogQHBhcmFtIHtib29sZWFufSBbY29uZmlnLnN3ZWVwRWFjaFN1YmFkZHJlc3NdIC0gZm9yIHN3ZWVwIHJlcXVlc3RzLCBzd2VlcCBlYWNoIHN1YmFkZHJlc3MgaW5kaXZpZHVhbGx5IGluc3RlYWQgb2YgdG9nZXRoZXIgaWYgdHJ1ZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2NvbmZpZy5rZXlJbWFnZV0gLSBrZXkgaW1hZ2UgdG8gc3dlZXAgKGlnbm9yZWQgZXhjZXB0IGluIHN3ZWVwT3V0cHV0KCkgcmVxdWVzdHMpXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihjb25maWc/OiBQYXJ0aWFsPE1vbmVyb1R4Q29uZmlnPikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgY29uZmlnKTtcblxuICAgIC8vIGRlc2VyaWFsaXplIGJpZ2ludHNcbiAgICBpZiAodGhpcy5hbW91bnQgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5hbW91bnQgIT09IFwiYmlnaW50XCIpIHRoaXMuYW1vdW50ID0gQmlnSW50KHRoaXMuYW1vdW50KTtcbiAgICBpZiAodGhpcy5mZWUgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5mZWUgIT09IFwiYmlnaW50XCIpIHRoaXMuZmVlID0gQmlnSW50KHRoaXMuZmVlKTtcbiAgICBpZiAodGhpcy5iZWxvd0Ftb3VudCAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLmJlbG93QW1vdW50ICE9PSBcImJpZ2ludFwiKSB0aGlzLmJlbG93QW1vdW50ID0gQmlnSW50KHRoaXMuYmVsb3dBbW91bnQpO1xuXG4gICAgLy8gY29weSBkZXN0aW5hdGlvbnNcbiAgICBpZiAodGhpcy5kZXN0aW5hdGlvbnMpIHtcbiAgICAgIGFzc2VydCh0aGlzLmFkZHJlc3MgPT09IHVuZGVmaW5lZCAmJiB0aGlzLmFtb3VudCA9PT0gdW5kZWZpbmVkLCBcIlR4IGNvbmZpZ3VyYXRpb24gbWF5IHNwZWNpZnkgZGVzdGluYXRpb25zIG9yIGFuIGFkZHJlc3MvYW1vdW50IGJ1dCBub3QgYm90aFwiKTtcbiAgICAgIHRoaXMuc2V0RGVzdGluYXRpb25zKHRoaXMuZGVzdGluYXRpb25zLm1hcChkZXN0aW5hdGlvbiA9PiBuZXcgTW9uZXJvRGVzdGluYXRpb24oZGVzdGluYXRpb24pKSk7XG4gICAgfVxuICAgIFxuICAgIC8vIGFsaWFzICdhZGRyZXNzJyBhbmQgJ2Ftb3VudCcgdG8gc2luZ2xlIGRlc3RpbmF0aW9uIHRvIHN1cHBvcnQgZS5nLiBjcmVhdGVUeCh7YWRkcmVzczogXCIuLi5cIn0pXG4gICAgaWYgKHRoaXMuYWRkcmVzcyB8fCB0aGlzLmFtb3VudCkge1xuICAgICAgYXNzZXJ0KCF0aGlzLmRlc3RpbmF0aW9ucywgXCJUeCBjb25maWd1cmF0aW9uIG1heSBzcGVjaWZ5IGRlc3RpbmF0aW9ucyBvciBhbiBhZGRyZXNzL2Ftb3VudCBidXQgbm90IGJvdGhcIik7XG4gICAgICB0aGlzLnNldEFkZHJlc3ModGhpcy5hZGRyZXNzKTtcbiAgICAgIHRoaXMuc2V0QW1vdW50KHRoaXMuYW1vdW50KTtcbiAgICAgIGRlbGV0ZSB0aGlzLmFkZHJlc3M7XG4gICAgICBkZWxldGUgdGhpcy5hbW91bnQ7XG4gICAgfVxuICAgIFxuICAgIC8vIGFsaWFzICdzdWJhZGRyZXNzSW5kZXgnIHRvIHN1YmFkZHJlc3MgaW5kaWNlc1xuICAgIGlmICh0aGlzLnN1YmFkZHJlc3NJbmRleCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLnNldFN1YmFkZHJlc3NJbmRpY2VzKFt0aGlzLnN1YmFkZHJlc3NJbmRleF0pO1xuICAgICAgZGVsZXRlIHRoaXMuc3ViYWRkcmVzc0luZGV4O1xuICAgIH1cbiAgfVxuICBcbiAgY29weSgpOiBNb25lcm9UeENvbmZpZyB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9UeENvbmZpZyh0aGlzKTtcbiAgfVxuICBcbiAgdG9Kc29uKCk6IGFueSB7XG4gICAgbGV0IGpzb246IGFueSA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMpOyAvLyBjb3B5IHN0YXRlXG4gICAgaWYgKHRoaXMuZ2V0RGVzdGluYXRpb25zKCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAganNvbi5kZXN0aW5hdGlvbnMgPSBbXTtcbiAgICAgIGZvciAobGV0IGRlc3RpbmF0aW9uIG9mIHRoaXMuZ2V0RGVzdGluYXRpb25zKCkpIGpzb24uZGVzdGluYXRpb25zLnB1c2goZGVzdGluYXRpb24udG9Kc29uKCkpO1xuICAgIH1cbiAgICBpZiAodGhpcy5nZXRGZWUoKSkganNvbi5mZWUgPSB0aGlzLmdldEZlZSgpLnRvU3RyaW5nKCk7XG4gICAgaWYgKHRoaXMuZ2V0QmVsb3dBbW91bnQoKSkganNvbi5iZWxvd0Ftb3VudCA9IHRoaXMuZ2V0QmVsb3dBbW91bnQoKS50b1N0cmluZygpO1xuICAgIHJldHVybiBqc29uO1xuICB9XG4gIFxuICAvKipcbiAgICogU2V0IHRoZSBhZGRyZXNzIG9mIGEgc2luZ2xlLWRlc3RpbmF0aW9uIGNvbmZpZ3VyYXRpb24uXG4gICAqIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWRkcmVzcyAtIHRoZSBhZGRyZXNzIHRvIHNldCBmb3IgdGhlIHNpbmdsZSBkZXN0aW5hdGlvblxuICAgKiBAcmV0dXJuIHtNb25lcm9UeENvbmZpZ30gdGhpcyBjb25maWd1cmF0aW9uIGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0QWRkcmVzcyhhZGRyZXNzOiBzdHJpbmcpOiBNb25lcm9UeENvbmZpZyB7XG4gICAgaWYgKHRoaXMuZGVzdGluYXRpb25zICE9PSB1bmRlZmluZWQgJiYgdGhpcy5kZXN0aW5hdGlvbnMubGVuZ3RoID4gMSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiQ2Fubm90IHNldCBhZGRyZXNzIGJlY2F1c2UgTW9uZXJvVHhDb25maWcgYWxyZWFkeSBoYXMgbXVsdGlwbGUgZGVzdGluYXRpb25zXCIpO1xuICAgIGlmICh0aGlzLmRlc3RpbmF0aW9ucyA9PT0gdW5kZWZpbmVkIHx8IHRoaXMuZGVzdGluYXRpb25zLmxlbmd0aCA9PT0gMCkgdGhpcy5hZGREZXN0aW5hdGlvbihuZXcgTW9uZXJvRGVzdGluYXRpb24oYWRkcmVzcykpO1xuICAgIGVsc2UgKHRoaXMuZGVzdGluYXRpb25zWzBdIGFzIE1vbmVyb0Rlc3RpbmF0aW9uKS5zZXRBZGRyZXNzKGFkZHJlc3MpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSBhZGRyZXNzIG9mIGEgc2luZ2xlLWRlc3RpbmF0aW9uIGNvbmZpZ3VyYXRpb24uXG4gICAqIFxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IHRoZSBhZGRyZXNzIG9mIHRoZSBzaW5nbGUgZGVzdGluYXRpb25cbiAgICovXG4gIGdldEFkZHJlc3MoKTogc3RyaW5nIHtcbiAgICBpZiAodGhpcy5kZXN0aW5hdGlvbnMgPT09IHVuZGVmaW5lZCB8fCB0aGlzLmRlc3RpbmF0aW9ucy5sZW5ndGggIT09IDEpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBnZXQgYWRkcmVzcyBiZWNhdXNlIE1vbmVyb1R4Q29uZmlnIGRvZXMgbm90IGhhdmUgZXhhY3RseSBvbmUgZGVzdGluYXRpb25cIik7XG4gICAgcmV0dXJuICh0aGlzLmRlc3RpbmF0aW9uc1swXSBhcyBNb25lcm9EZXN0aW5hdGlvbikuZ2V0QWRkcmVzcygpO1xuICB9XG4gIFxuICAvKipcbiAgICogU2V0IHRoZSBhbW91bnQgb2YgYSBzaW5nbGUtZGVzdGluYXRpb24gY29uZmlndXJhdGlvbi5cbiAgICogXG4gICAqIEBwYXJhbSB7YmlnaW50fSBhbW91bnQgLSB0aGUgYW1vdW50IHRvIHNldCBmb3IgdGhlIHNpbmdsZSBkZXN0aW5hdGlvblxuICAgKiBAcmV0dXJuIHtNb25lcm9UeENvbmZpZ30gdGhpcyBjb25maWd1cmF0aW9uIGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0QW1vdW50KGFtb3VudDogYmlnaW50KTogTW9uZXJvVHhDb25maWcge1xuICAgIGlmIChhbW91bnQgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdGhpcy5hbW91bnQgIT09IFwiYmlnaW50XCIpIHtcbiAgICAgIGlmICh0eXBlb2YgYW1vdW50ID09PSBcIm51bWJlclwiKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJEZXN0aW5hdGlvbiBhbW91bnQgbXVzdCBiZSBiaWdpbnQgb3Igc3RyaW5nXCIpO1xuICAgICAgdHJ5IHsgYW1vdW50ID0gQmlnSW50KGFtb3VudCk7IH1cbiAgICAgIGNhdGNoIChlcnIpIHsgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiSW52YWxpZCBkZXN0aW5hdGlvbiBhbW91bnQ6IFwiICsgYW1vdW50KTsgfVxuICAgIH1cbiAgICBpZiAodGhpcy5kZXN0aW5hdGlvbnMgIT09IHVuZGVmaW5lZCAmJiB0aGlzLmRlc3RpbmF0aW9ucy5sZW5ndGggPiAxKSB0aHJvdyBuZXcgTW9uZXJvRXJyb3IoXCJDYW5ub3Qgc2V0IGFtb3VudCBiZWNhdXNlIE1vbmVyb1R4Q29uZmlnIGFscmVhZHkgaGFzIG11bHRpcGxlIGRlc3RpbmF0aW9uc1wiKTtcbiAgICBpZiAodGhpcy5kZXN0aW5hdGlvbnMgPT09IHVuZGVmaW5lZCB8fCB0aGlzLmRlc3RpbmF0aW9ucy5sZW5ndGggPT09IDApIHRoaXMuYWRkRGVzdGluYXRpb24obmV3IE1vbmVyb0Rlc3RpbmF0aW9uKHVuZGVmaW5lZCwgYW1vdW50KSk7XG4gICAgZWxzZSAodGhpcy5kZXN0aW5hdGlvbnNbMF0gYXMgTW9uZXJvRGVzdGluYXRpb24pLnNldEFtb3VudChhbW91bnQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSBhbW91bnQgb2YgYSBzaW5nbGUtZGVzdGluYXRpb24gY29uZmlndXJhdGlvbi5cbiAgICogXG4gICAqIEByZXR1cm4ge2JpZ2ludH0gdGhlIGFtb3VudCBvZiB0aGUgc2luZ2xlIGRlc3RpbmF0aW9uXG4gICAqL1xuICBnZXRBbW91bnQoKTogYmlnaW50IHtcbiAgICBpZiAodGhpcy5kZXN0aW5hdGlvbnMgPT09IHVuZGVmaW5lZCB8fCB0aGlzLmRlc3RpbmF0aW9ucy5sZW5ndGggIT09IDEpIHRocm93IG5ldyBNb25lcm9FcnJvcihcIkNhbm5vdCBnZXQgYW1vdW50IGJlY2F1c2UgTW9uZXJvVHhDb25maWcgZG9lcyBub3QgaGF2ZSBleGFjdGx5IG9uZSBkZXN0aW5hdGlvblwiKTtcbiAgICByZXR1cm4gKHRoaXMuZGVzdGluYXRpb25zWzBdIGFzIE1vbmVyb0Rlc3RpbmF0aW9uKS5nZXRBbW91bnQoKTtcbiAgfVxuICBcbiAgYWRkRGVzdGluYXRpb24oZGVzdGluYXRpb25PckFkZHJlc3M6IE1vbmVyb0Rlc3RpbmF0aW9uIHwgc3RyaW5nLCBhbW91bnQ/OiBiaWdpbnQpOiBNb25lcm9UeENvbmZpZyB7XG4gICAgaWYgKHR5cGVvZiBkZXN0aW5hdGlvbk9yQWRkcmVzcyA9PT0gXCJzdHJpbmdcIikgcmV0dXJuIHRoaXMuYWRkRGVzdGluYXRpb24obmV3IE1vbmVyb0Rlc3RpbmF0aW9uKGRlc3RpbmF0aW9uT3JBZGRyZXNzLCBhbW91bnQpKTtcbiAgICBhc3NlcnQoZGVzdGluYXRpb25PckFkZHJlc3MgaW5zdGFuY2VvZiBNb25lcm9EZXN0aW5hdGlvbik7XG4gICAgaWYgKHRoaXMuZGVzdGluYXRpb25zID09PSB1bmRlZmluZWQpIHRoaXMuZGVzdGluYXRpb25zID0gW107XG4gICAgdGhpcy5kZXN0aW5hdGlvbnMucHVzaChkZXN0aW5hdGlvbk9yQWRkcmVzcyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldERlc3RpbmF0aW9ucygpOiBNb25lcm9EZXN0aW5hdGlvbltdIHtcbiAgICByZXR1cm4gdGhpcy5kZXN0aW5hdGlvbnMgYXMgTW9uZXJvRGVzdGluYXRpb25bXTtcbiAgfVxuICBcbiAgc2V0RGVzdGluYXRpb25zKGRlc3RpbmF0aW9uczogTW9uZXJvRGVzdGluYXRpb25bXSk6IE1vbmVyb1R4Q29uZmlnIHtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIGRlc3RpbmF0aW9ucyA9IEFycmF5LmZyb20oYXJndW1lbnRzKTtcbiAgICB0aGlzLmRlc3RpbmF0aW9ucyA9IGRlc3RpbmF0aW9ucztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgc2V0RGVzdGluYXRpb24oZGVzdGluYXRpb246IE1vbmVyb0Rlc3RpbmF0aW9uKTogTW9uZXJvVHhDb25maWcge1xuICAgIHJldHVybiB0aGlzLnNldERlc3RpbmF0aW9ucyhkZXN0aW5hdGlvbiA/IFtkZXN0aW5hdGlvbl0gOiB1bmRlZmluZWQpO1xuICB9XG5cbiAgZ2V0U3VidHJhY3RGZWVGcm9tKCk6IG51bWJlcltdIHtcbiAgICByZXR1cm4gdGhpcy5zdWJ0cmFjdEZlZUZyb207XG4gIH1cblxuICBzZXRTdWJ0cmFjdEZlZUZyb20oZGVzdGluYXRpb25JbmRpY2VzOiBudW1iZXJbXSk6IE1vbmVyb1R4Q29uZmlnIHtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIGRlc3RpbmF0aW9uSW5kaWNlcyA9IEFycmF5LmZyb20oYXJndW1lbnRzKTtcbiAgICB0aGlzLnN1YnRyYWN0RmVlRnJvbSA9IGRlc3RpbmF0aW9uSW5kaWNlcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0UGF5bWVudElkKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMucGF5bWVudElkO1xuICB9XG4gIFxuICBzZXRQYXltZW50SWQocGF5bWVudElkOiBzdHJpbmcpOiBNb25lcm9UeENvbmZpZyB7XG4gICAgdGhpcy5wYXltZW50SWQgPSBwYXltZW50SWQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFByaW9yaXR5KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMucHJpb3JpdHk7XG4gIH1cbiAgXG4gIHNldFByaW9yaXR5KHByaW9yaXR5OiBudW1iZXIpOiBNb25lcm9UeENvbmZpZyB7XG4gICAgdGhpcy5wcmlvcml0eSA9IHByaW9yaXR5O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRGZWUoKTogYmlnaW50IHtcbiAgICByZXR1cm4gdGhpcy5mZWU7XG4gIH1cbiAgXG4gIHNldEZlZShmZWU6IGJpZ2ludCk6IE1vbmVyb1R4Q29uZmlnIHtcbiAgICB0aGlzLmZlZSA9IGZlZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0QWNjb3VudEluZGV4KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuYWNjb3VudEluZGV4O1xuICB9XG4gIFxuICBzZXRBY2NvdW50SW5kZXgoYWNjb3VudEluZGV4OiBudW1iZXIpOiBNb25lcm9UeENvbmZpZyB7XG4gICAgdGhpcy5hY2NvdW50SW5kZXggPSBhY2NvdW50SW5kZXg7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHNldFN1YmFkZHJlc3NJbmRleChzdWJhZGRyZXNzSW5kZXg6IG51bWJlcik6IE1vbmVyb1R4Q29uZmlnIHtcbiAgICB0aGlzLnNldFN1YmFkZHJlc3NJbmRpY2VzKFtzdWJhZGRyZXNzSW5kZXhdKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U3ViYWRkcmVzc0luZGljZXMoKTogbnVtYmVyW10ge1xuICAgIHJldHVybiB0aGlzLnN1YmFkZHJlc3NJbmRpY2VzO1xuICB9XG4gIFxuICBzZXRTdWJhZGRyZXNzSW5kaWNlcyhzdWJhZGRyZXNzSW5kaWNlczogbnVtYmVyW10pOiBNb25lcm9UeENvbmZpZyB7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSBzdWJhZGRyZXNzSW5kaWNlcyA9IEFycmF5LmZyb20oYXJndW1lbnRzKTtcbiAgICB0aGlzLnN1YmFkZHJlc3NJbmRpY2VzID0gc3ViYWRkcmVzc0luZGljZXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFJlbGF5KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLnJlbGF5O1xuICB9XG4gIFxuICBzZXRSZWxheShyZWxheTogYm9vbGVhbik6IE1vbmVyb1R4Q29uZmlnIHtcbiAgICB0aGlzLnJlbGF5ID0gcmVsYXk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldENhblNwbGl0KCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmNhblNwbGl0O1xuICB9XG4gIFxuICBzZXRDYW5TcGxpdChjYW5TcGxpdDogYm9vbGVhbik6IE1vbmVyb1R4Q29uZmlnIHtcbiAgICB0aGlzLmNhblNwbGl0ID0gY2FuU3BsaXQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldE5vdGUoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5ub3RlO1xuICB9XG4gIFxuICBzZXROb3RlKG5vdGU6IHN0cmluZyk6IE1vbmVyb1R4Q29uZmlnIHtcbiAgICB0aGlzLm5vdGUgPSBub3RlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRSZWNpcGllbnROYW1lKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMucmVjaXBpZW50TmFtZTtcbiAgfVxuICBcbiAgc2V0UmVjaXBpZW50TmFtZShyZWNpcGllbnROYW1lOiBzdHJpbmcpOiBNb25lcm9UeENvbmZpZyB7XG4gICAgdGhpcy5yZWNpcGllbnROYW1lID0gcmVjaXBpZW50TmFtZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIFNQRUNJRklDIFRPIFNXRUVQIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgXG4gIGdldEJlbG93QW1vdW50KCkge1xuICAgIHJldHVybiB0aGlzLmJlbG93QW1vdW50O1xuICB9XG4gIFxuICBzZXRCZWxvd0Ftb3VudChiZWxvd0Ftb3VudCkge1xuICAgIHRoaXMuYmVsb3dBbW91bnQgPSBiZWxvd0Ftb3VudDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U3dlZXBFYWNoU3ViYWRkcmVzcygpIHtcbiAgICByZXR1cm4gdGhpcy5zd2VlcEVhY2hTdWJhZGRyZXNzO1xuICB9XG4gIFxuICBzZXRTd2VlcEVhY2hTdWJhZGRyZXNzKHN3ZWVwRWFjaFN1YmFkZHJlc3MpIHtcbiAgICB0aGlzLnN3ZWVwRWFjaFN1YmFkZHJlc3MgPSBzd2VlcEVhY2hTdWJhZGRyZXNzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogR2V0IHRoZSBrZXkgaW1hZ2UgaGV4IG9mIHRoZSBvdXRwdXQgdG8gc3dlZXAuXG4gICAqIFxuICAgKiByZXR1cm4ge3N0cmluZ30gaXMgdGhlIGtleSBpbWFnZSBoZXggb2YgdGhlIG91dHB1dCB0byBzd2VlcFxuICAgKi9cbiAgZ2V0S2V5SW1hZ2UoKSB7XG4gICAgcmV0dXJuIHRoaXMua2V5SW1hZ2U7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZXQgdGhlIGtleSBpbWFnZSBoZXggb2YgdGhlIG91dHB1dCB0byBzd2VlcC5cbiAgICogXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBrZXlJbWFnZSBpcyB0aGUga2V5IGltYWdlIGhleCBvZiB0aGUgb3V0cHV0IHRvIHN3ZWVwXG4gICAqL1xuICBzZXRLZXlJbWFnZShrZXlJbWFnZSkge1xuICAgIHRoaXMua2V5SW1hZ2UgPSBrZXlJbWFnZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoieUxBQUEsSUFBQUEsT0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsa0JBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFFLFlBQUEsR0FBQUgsc0JBQUEsQ0FBQUMsT0FBQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ2UsTUFBTUcsY0FBYyxDQUFDOztFQUVsQzs7O0VBR0E7OztFQUdBOzs7RUFHQTs7O0VBR0E7OztFQUdBOzs7RUFHQTs7O0VBR0E7OztFQUdBOzs7RUFHQTs7O0VBR0E7OztFQUdBOzs7RUFHQTs7O0VBR0E7OztFQUdBOzs7RUFHQTs7O0VBR0E7OztFQUdBO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroTxPriority.d.ts b/dist/src/main/ts/wallet/model/MoneroTxPriority.d.ts new file mode 100644 index 000000000..b761d1bfb --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTxPriority.d.ts @@ -0,0 +1,22 @@ +/** + * Enumerates send priorities. + */ +declare enum MoneroTxPriority { + /** + * Default priority (i.e. normal) (value=0). + */ + DEFAULT = 0, + /** + * Unimportant priority (value=1). + */ + UNIMPORTANT = 1, + /** + * Normal priority (value=2). + */ + NORMAL = 2, + /** + * Elevated priority (value=3). + */ + ELEVATED = 3 +} +export default MoneroTxPriority; diff --git a/dist/src/main/ts/wallet/model/MoneroTxPriority.js b/dist/src/main/ts/wallet/model/MoneroTxPriority.js new file mode 100644 index 000000000..e66230ff6 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTxPriority.js @@ -0,0 +1,28 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; /** + * Enumerates send priorities. + */var +MoneroTxPriority = /*#__PURE__*/function (MoneroTxPriority) {MoneroTxPriority[MoneroTxPriority["DEFAULT"] = 0] = "DEFAULT";MoneroTxPriority[MoneroTxPriority["UNIMPORTANT"] = 1] = "UNIMPORTANT";MoneroTxPriority[MoneroTxPriority["NORMAL"] = 2] = "NORMAL";MoneroTxPriority[MoneroTxPriority["ELEVATED"] = 3] = "ELEVATED";return MoneroTxPriority;}(MoneroTxPriority || {});var _default = exports.default = + + + + + + + + + + + + + + + + + + + + + + +MoneroTxPriority; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9UeFByaW9yaXR5IiwiX2RlZmF1bHQiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9UeFByaW9yaXR5LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRW51bWVyYXRlcyBzZW5kIHByaW9yaXRpZXMuXG4gKi9cbmVudW0gTW9uZXJvVHhQcmlvcml0eSB7XG5cbiAgICAvKipcbiAgICAgKiBEZWZhdWx0IHByaW9yaXR5IChpLmUuIG5vcm1hbCkgKHZhbHVlPTApLlxuICAgICAqL1xuICAgREVGQVVMVCA9IDAsXG5cbiAgICAvKipcbiAgICAgKiBVbmltcG9ydGFudCBwcmlvcml0eSAodmFsdWU9MSkuXG4gICAgICovXG4gICAgVU5JTVBPUlRBTlQgPSAxLFxuXG4gICAgLyoqXG4gICAgICogTm9ybWFsIHByaW9yaXR5ICh2YWx1ZT0yKS5cbiAgICAgKi9cbiAgICBOT1JNQUwgPSAyLFxuXG4gICAgLyoqXG4gICAgICogRWxldmF0ZWQgcHJpb3JpdHkgKHZhbHVlPTMpLlxuICAgICAqL1xuICAgIEVMRVZBVEVEID0gM1xufVxuXG5leHBvcnQgZGVmYXVsdCBNb25lcm9UeFByaW9yaXR5OyJdLCJtYXBwaW5ncyI6InFHQUFBO0FBQ0E7QUFDQSxHQUZBO0FBR0tBLGdCQUFnQiwwQkFBaEJBLGdCQUFnQixHQUFoQkEsZ0JBQWdCLENBQWhCQSxnQkFBZ0IsNkJBQWhCQSxnQkFBZ0IsQ0FBaEJBLGdCQUFnQixxQ0FBaEJBLGdCQUFnQixDQUFoQkEsZ0JBQWdCLDJCQUFoQkEsZ0JBQWdCLENBQWhCQSxnQkFBZ0Isc0NBQWhCQSxnQkFBZ0IsR0FBaEJBLGdCQUFnQixZQUFBQyxRQUFBLEdBQUFDLE9BQUEsQ0FBQUMsT0FBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUF1Qk5ILGdCQUFnQiJ9 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroTxQuery.d.ts b/dist/src/main/ts/wallet/model/MoneroTxQuery.d.ts new file mode 100644 index 000000000..bdd3e9ffc --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTxQuery.d.ts @@ -0,0 +1,144 @@ +import MoneroBlock from "../../daemon/model/MoneroBlock"; +import MoneroOutput from "../../daemon/model/MoneroOutput"; +import MoneroIncomingTransfer from "./MoneroIncomingTransfer"; +import MoneroOutgoingTransfer from "./MoneroOutgoingTransfer"; +import MoneroOutputQuery from "./MoneroOutputQuery"; +import MoneroTransferQuery from "./MoneroTransferQuery"; +import MoneroTxSet from "./MoneroTxSet"; +import MoneroTxWallet from "./MoneroTxWallet"; +/** + *

Configuration to query transactions.

+ */ +export default class MoneroTxQuery extends MoneroTxWallet { + hash: string; + hashes: string[]; + height: number; + minHeight: number; + maxHeight: number; + includeOutputs: boolean; + isConfirmed: boolean; + inTxPool: boolean; + relay: boolean; + isRelayed: boolean; + isFailed: boolean; + isMinerTx: boolean; + isLocked: boolean; + isIncoming: boolean; + isOutgoing: boolean; + paymentId: string; + paymentIds: string[]; + hasPaymentId: boolean; + transferQuery: Partial; + inputQuery: Partial; + outputQuery: Partial; + /** + *

Construct the transaction query.

+ * + *

Example:

+ * + * + * // get transactions with unlocked incoming transfers to account 0
+ * let txs = await wallet.getTxs({
+ *    isLocked: false,
+ *    transferQuery: {
+ *      isIncoming: true,
+ *      accountIndex: 0
+ *    }
+ * }); + *
+ * + *

All configuration is optional. All transactions are returned except those that don't meet criteria defined in this query.

+ * + * @param {MoneroTxQuery} [query] - tx query configuration + * @param {string} [query.hash] - get a tx with this hash + * @param {string[]} [query.txHashes] - get txs with these hashes + * @param {number} [query.height] - get txs with this height + * @param {number} [query.minHeight] - get txs with height greater than or equal to this height + * @param {number} [query.maxHeight] - get txs with height less than or equal to this height + * @param {boolean} [query.isConfirmed] - get confirmed or unconfirmed txs + * @param {boolean} [query.inTxPool] - get txs in or out of the tx pool + * @param {boolean} [query.relay] - get txs with the same relay status + * @param {boolean} [query.isRelayed] - get relayed or non-relayed txs + * @param {boolean} [query.isFailed] - get failed or non-failed txs + * @param {boolean} [query.isMinerTx] - get miner or non-miner txs + * @param {boolean} [query.isLocked] - get locked or unlocked txs + * @param {boolean} [query.isIncoming] - get txs with or without incoming transfers + * @param {boolean} [query.isOutgoing] - get txs with or without outgoing transfers + * @param {string} [query.paymentId] - get txs with this payment ID + * @param {string} [query.paymentIds] - get txs with a payment ID among these payment IDs + * @param {boolean} [query.hasPaymentId] - get txs with or without payment IDs + * @param {Partial} [query.transferQuery] - get txs with transfers matching this transfer query + * @param {Partial} [query.inputQuery] - get txs with inputs matching this input query + * @param {Partial} [query.outputQuery] - get txs with outputs matching this output query + */ + constructor(query?: Partial); + copy(): MoneroTxQuery; + toJson(): any; + getIsIncoming(): boolean; + setIsIncoming(isIncoming: boolean): MoneroTxQuery; + getIsOutgoing(): boolean; + setIsOutgoing(isOutgoing: boolean): MoneroTxQuery; + getHashes(): string[]; + setHashes(hashes: string[]): MoneroTxQuery; + setHash(hash: string): MoneroTxQuery; + getHasPaymentId(): boolean; + setHasPaymentId(hasPaymentId: boolean): MoneroTxQuery; + getPaymentIds(): string[]; + setPaymentIds(paymentIds: string[]): MoneroTxQuery; + setPaymentId(paymentId: string): MoneroTxQuery; + getHeight(): number; + setHeight(height: number): MoneroTxQuery; + getMinHeight(): number; + setMinHeight(minHeight: number): MoneroTxQuery; + getMaxHeight(): number; + setMaxHeight(maxHeight: number): MoneroTxQuery; + getIncludeOutputs(): boolean; + setIncludeOutputs(includeOutputs: boolean): MoneroTxQuery; + getTransferQuery(): MoneroTransferQuery; + setTransferQuery(transferQuery: MoneroTransferQuery): MoneroTxQuery; + getInputQuery(): MoneroOutputQuery; + setInputQuery(inputQuery: MoneroOutputQuery): MoneroTxQuery; + getOutputQuery(): MoneroOutputQuery; + setOutputQuery(outputQuery: MoneroOutputQuery): MoneroTxQuery; + meetsCriteria(tx: MoneroTxWallet, queryChildren?: boolean): boolean; + setIncomingTransfers(incomingTransfers: MoneroIncomingTransfer[]): MoneroTxQuery; + setOutgoingTransfer(outgoingTransfer: MoneroOutgoingTransfer): MoneroTxQuery; + setOutputs(outputs: MoneroOutput[]): MoneroTxQuery; + setNote(note: string): MoneroTxQuery; + setIsLocked(isLocked: boolean): MoneroTxQuery; + setBlock(block: MoneroBlock): MoneroTxQuery; + setVersion(version: number): MoneroTxQuery; + setIsMinerTx(isMinerTx: boolean): MoneroTxQuery; + setFee(fee: bigint): MoneroTxQuery; + setRingSize(ringSize: number): MoneroTxQuery; + setRelay(relay: boolean): MoneroTxQuery; + setIsRelayed(isRelayed: boolean): MoneroTxQuery; + setIsConfirmed(isConfirmed: boolean): MoneroTxQuery; + setInTxPool(inTxPool: boolean): MoneroTxQuery; + setNumConfirmations(numConfirmations: number): MoneroTxQuery; + setUnlockTime(unlockTime: bigint): MoneroTxQuery; + setLastRelayedTimestamp(lastRelayedTimestamp: number): MoneroTxQuery; + setReceivedTimestamp(receivedTimestamp: number): MoneroTxQuery; + setIsDoubleSpendSeen(isDoubleSpendSeen: boolean): MoneroTxQuery; + setKey(key: string): MoneroTxQuery; + setFullHex(hex: string): MoneroTxQuery; + setPrunedHex(prunedHex: string): MoneroTxQuery; + setPrunableHex(prunableHex: string): MoneroTxQuery; + setPrunableHash(prunableHash: string): MoneroTxQuery; + setSize(size: number): MoneroTxQuery; + setWeight(weight: number): MoneroTxQuery; + setInputs(inputs: MoneroOutput[]): MoneroTxQuery; + setOutputIndices(outputIndices: number[]): MoneroTxQuery; + setMetadata(metadata: string): MoneroTxQuery; + setTxSet(txSet: MoneroTxSet): MoneroTxQuery; + setExtra(extra: Uint8Array): MoneroTxQuery; + setRctSignatures(rctSignatures: any): MoneroTxQuery; + setRctSigPrunable(rctSigPrunable: any): MoneroTxQuery; + setIsKeptByBlock(isKeptByBlock: boolean): MoneroTxQuery; + setIsFailed(isFailed: boolean): MoneroTxQuery; + setLastFailedHeight(lastFailedHeight: number): MoneroTxQuery; + setLastFailedHash(lastFailedId: string): MoneroTxQuery; + setMaxUsedBlockHeight(maxUsedBlockHeight: number): MoneroTxQuery; + setMaxUsedBlockHash(maxUsedBlockId: string): MoneroTxQuery; + setSignatures(signatures: string[]): MoneroTxQuery; +} diff --git a/dist/src/main/ts/wallet/model/MoneroTxQuery.js b/dist/src/main/ts/wallet/model/MoneroTxQuery.js new file mode 100644 index 000000000..d668b54f5 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTxQuery.js @@ -0,0 +1,525 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); + + + + +var _MoneroOutputQuery = _interopRequireDefault(require("./MoneroOutputQuery")); +var _MoneroTransferQuery = _interopRequireDefault(require("./MoneroTransferQuery")); + +var _MoneroTxWallet = _interopRequireDefault(require("./MoneroTxWallet")); + +/** + *

Configuration to query transactions.

+ */ +class MoneroTxQuery extends _MoneroTxWallet.default { + + + + + + + + + + + + + + + + + + + + + + + + /** + *

Construct the transaction query.

+ * + *

Example:

+ * + * + * // get transactions with unlocked incoming transfers to account 0
+ * let txs = await wallet.getTxs({
+ *    isLocked: false,
+ *    transferQuery: {
+ *      isIncoming: true,
+ *      accountIndex: 0
+ *    }
+ * }); + *
+ * + *

All configuration is optional. All transactions are returned except those that don't meet criteria defined in this query.

+ * + * @param {MoneroTxQuery} [query] - tx query configuration + * @param {string} [query.hash] - get a tx with this hash + * @param {string[]} [query.txHashes] - get txs with these hashes + * @param {number} [query.height] - get txs with this height + * @param {number} [query.minHeight] - get txs with height greater than or equal to this height + * @param {number} [query.maxHeight] - get txs with height less than or equal to this height + * @param {boolean} [query.isConfirmed] - get confirmed or unconfirmed txs + * @param {boolean} [query.inTxPool] - get txs in or out of the tx pool + * @param {boolean} [query.relay] - get txs with the same relay status + * @param {boolean} [query.isRelayed] - get relayed or non-relayed txs + * @param {boolean} [query.isFailed] - get failed or non-failed txs + * @param {boolean} [query.isMinerTx] - get miner or non-miner txs + * @param {boolean} [query.isLocked] - get locked or unlocked txs + * @param {boolean} [query.isIncoming] - get txs with or without incoming transfers + * @param {boolean} [query.isOutgoing] - get txs with or without outgoing transfers + * @param {string} [query.paymentId] - get txs with this payment ID + * @param {string} [query.paymentIds] - get txs with a payment ID among these payment IDs + * @param {boolean} [query.hasPaymentId] - get txs with or without payment IDs + * @param {Partial} [query.transferQuery] - get txs with transfers matching this transfer query + * @param {Partial} [query.inputQuery] - get txs with inputs matching this input query + * @param {Partial} [query.outputQuery] - get txs with outputs matching this output query + */ + constructor(query) { + super(query); + + // copy queries + if (this.transferQuery) this.transferQuery = new _MoneroTransferQuery.default(this.transferQuery); + if (this.inputQuery) this.inputQuery = new _MoneroOutputQuery.default(this.inputQuery); + if (this.outputQuery) this.outputQuery = new _MoneroOutputQuery.default(this.outputQuery); + + // link cycles + if (this.transferQuery) this.getTransferQuery().setTxQuery(this); + if (this.inputQuery) this.getInputQuery().setTxQuery(this); + if (this.outputQuery) this.getOutputQuery().setTxQuery(this); + + // alias 'hash' to hashes + if (this.hash) { + this.setHashes([this.hash]); + delete this.hash; + } + } + + copy() { + return new MoneroTxQuery(this); + } + + toJson() { + let json = Object.assign({}, this, super.toJson()); // merge json onto inherited state + if (this.getTransferQuery() !== undefined) json.transferQuery = this.getTransferQuery().toJson(); + if (this.getInputQuery() !== undefined) json.inputQuery = this.getInputQuery().toJson(); + if (this.getOutputQuery() !== undefined) json.outputQuery = this.getOutputQuery().toJson(); + delete json.block; // do not serialize parent block + return json; + } + + getIsIncoming() { + return this.isIncoming; + } + + setIsIncoming(isIncoming) { + this.isIncoming = isIncoming; + return this; + } + + getIsOutgoing() { + return this.isOutgoing; + } + + setIsOutgoing(isOutgoing) { + this.isOutgoing = isOutgoing; + return this; + } + + getHashes() { + return this.hashes; + } + + setHashes(hashes) { + this.hashes = hashes; + return this; + } + + setHash(hash) { + if (hash === undefined) return this.setHashes(undefined); + (0, _assert.default)(typeof hash === "string"); + return this.setHashes([hash]); + } + + getHasPaymentId() { + return this.hasPaymentId; + } + + setHasPaymentId(hasPaymentId) { + this.hasPaymentId = hasPaymentId; + return this; + } + + getPaymentIds() { + return this.paymentIds; + } + + setPaymentIds(paymentIds) { + this.paymentIds = paymentIds; + return this; + } + + setPaymentId(paymentId) { + if (paymentId === undefined) return this.setPaymentIds(undefined); + (0, _assert.default)(typeof paymentId === "string"); + return this.setPaymentIds([paymentId]); + } + + getHeight() { + return this.height; + } + + setHeight(height) { + this.height = height; + return this; + } + + getMinHeight() { + return this.minHeight; + } + + setMinHeight(minHeight) { + this.minHeight = minHeight; + return this; + } + + getMaxHeight() { + return this.maxHeight; + } + + setMaxHeight(maxHeight) { + this.maxHeight = maxHeight; + return this; + } + + getIncludeOutputs() { + return this.includeOutputs; + } + + setIncludeOutputs(includeOutputs) { + this.includeOutputs = includeOutputs; + return this; + } + + getTransferQuery() { + return this.transferQuery; + } + + setTransferQuery(transferQuery) { + this.transferQuery = transferQuery === undefined ? undefined : transferQuery instanceof _MoneroTransferQuery.default ? transferQuery : new _MoneroTransferQuery.default(transferQuery); + if (transferQuery) this.transferQuery.txQuery = this; + return this; + } + + getInputQuery() { + return this.inputQuery; + } + + setInputQuery(inputQuery) { + this.inputQuery = inputQuery; + if (inputQuery) inputQuery.txQuery = this; + return this; + } + + getOutputQuery() { + return this.outputQuery; + } + + setOutputQuery(outputQuery) { + this.outputQuery = outputQuery === undefined ? undefined : outputQuery instanceof _MoneroOutputQuery.default ? outputQuery : new _MoneroOutputQuery.default(outputQuery); + if (outputQuery) this.outputQuery.txQuery = this; + return this; + } + + meetsCriteria(tx, queryChildren) { + if (!(tx instanceof _MoneroTxWallet.default)) throw new Error("Tx not given to MoneroTxQuery.meetsCriteria(tx)"); + if (queryChildren === undefined) queryChildren = true; + + // filter on tx + if (this.getHash() !== undefined && this.getHash() !== tx.getHash()) return false; + if (this.getPaymentId() !== undefined && this.getPaymentId() !== tx.getPaymentId()) return false; + if (this.getIsConfirmed() !== undefined && this.getIsConfirmed() !== tx.getIsConfirmed()) return false; + if (this.getInTxPool() !== undefined && this.getInTxPool() !== tx.getInTxPool()) return false; + if (this.getRelay() !== undefined && this.getRelay() !== tx.getRelay()) return false; + if (this.getIsRelayed() !== undefined && this.getIsRelayed() !== tx.getIsRelayed()) return false; + if (this.getIsFailed() !== undefined && this.getIsFailed() !== tx.getIsFailed()) return false; + if (this.getIsMinerTx() !== undefined && this.getIsMinerTx() !== tx.getIsMinerTx()) return false; + if (this.getIsLocked() !== undefined && this.getIsLocked() !== tx.getIsLocked()) return false; + + // filter on having a payment id + if (this.getHasPaymentId() !== undefined) { + if (this.getHasPaymentId() && tx.getPaymentId() === undefined) return false; + if (!this.getHasPaymentId() && tx.getPaymentId() !== undefined) return false; + } + + // filter on incoming + if (this.getIsIncoming() !== undefined) { + if (this.getIsIncoming() && !tx.getIsIncoming()) return false; + if (!this.getIsIncoming() && tx.getIsIncoming()) return false; + } + + // filter on outgoing + if (this.getIsOutgoing() !== undefined) { + if (this.getIsOutgoing() && !tx.getIsOutgoing()) return false; + if (!this.getIsOutgoing() && tx.getIsOutgoing()) return false; + } + + // filter on remaining fields + let txHeight = tx.getBlock() === undefined ? undefined : tx.getBlock().getHeight(); + if (this.getHashes() !== undefined && !this.getHashes().includes(tx.getHash())) return false; + if (this.getPaymentIds() !== undefined && !this.getPaymentIds().includes(tx.getPaymentId())) return false; + if (this.getHeight() !== undefined && (txHeight === undefined || txHeight !== this.getHeight())) return false; + if (this.getMinHeight() !== undefined && txHeight !== undefined && txHeight < this.getMinHeight()) return false; // do not filter unconfirmed + if (this.getMaxHeight() !== undefined && (txHeight === undefined || txHeight > this.getMaxHeight())) return false; + // TODO: filtering not complete + + // done if not querying transfers or outputs + if (!queryChildren) return true; + + // at least one transfer must meet transfer filter if defined + if (this.getTransferQuery() !== undefined) { + let matchFound = false; + if (tx.getOutgoingTransfer() && this.getTransferQuery().meetsCriteria(tx.getOutgoingTransfer(), false)) matchFound = true;else + if (tx.getIncomingTransfers()) { + for (let incomingTransfer of tx.getIncomingTransfers()) { + if (this.getTransferQuery().meetsCriteria(incomingTransfer, false)) { + matchFound = true; + break; + } + } + } + if (!matchFound) return false; + } + + // at least one input must meet input query if defined + if (this.getInputQuery() !== undefined) { + if (tx.getInputs() === undefined || tx.getInputs().length === 0) return false; + let matchFound = false; + for (let input of tx.getInputsWallet()) { + if (this.getInputQuery().meetsCriteria(input, false)) { + matchFound = true; + break; + } + } + if (!matchFound) return false; + } + + // at least one output must meet output query if defined + if (this.getOutputQuery() !== undefined) { + if (tx.getOutputs() === undefined || tx.getOutputs().length === 0) return false; + let matchFound = false; + for (let output of tx.getOutputsWallet()) { + if (this.getOutputQuery().meetsCriteria(output, false)) { + matchFound = true; + break; + } + } + if (!matchFound) return false; + } + + return true; // transaction meets filter criteria + } + + // ------------------- OVERRIDE CO-VARIANT RETURN TYPES --------------------- + + setIncomingTransfers(incomingTransfers) { + super.setIncomingTransfers(incomingTransfers); + return this; + } + + setOutgoingTransfer(outgoingTransfer) { + super.setOutgoingTransfer(outgoingTransfer); + return this; + } + + setOutputs(outputs) { + super.setOutputs(outputs); + return this; + } + + setNote(note) { + super.setNote(note); + return this; + } + + setIsLocked(isLocked) { + super.setIsLocked(isLocked); + return this; + } + + setBlock(block) { + super.setBlock(block); + return this; + } + + setVersion(version) { + super.setVersion(version); + return this; + } + + setIsMinerTx(isMinerTx) { + super.setIsMinerTx(isMinerTx); + return this; + } + + setFee(fee) { + super.setFee(fee); + return this; + } + + setRingSize(ringSize) { + super.setRingSize(ringSize); + return this; + } + + setRelay(relay) { + super.setRelay(relay); + return this; + } + + setIsRelayed(isRelayed) { + super.setIsRelayed(isRelayed); + return this; + } + + setIsConfirmed(isConfirmed) { + super.setIsConfirmed(isConfirmed); + return this; + } + + setInTxPool(inTxPool) { + super.setInTxPool(inTxPool); + return this; + } + + setNumConfirmations(numConfirmations) { + super.setNumConfirmations(numConfirmations); + return this; + } + + setUnlockTime(unlockTime) { + super.setUnlockTime(unlockTime); + return this; + } + + setLastRelayedTimestamp(lastRelayedTimestamp) { + super.setLastRelayedTimestamp(lastRelayedTimestamp); + return this; + } + + setReceivedTimestamp(receivedTimestamp) { + super.setReceivedTimestamp(receivedTimestamp); + return this; + } + + setIsDoubleSpendSeen(isDoubleSpendSeen) { + super.setIsDoubleSpendSeen(isDoubleSpendSeen); + return this; + } + + setKey(key) { + super.setKey(key); + return this; + } + + setFullHex(hex) { + super.setFullHex(hex); + return this; + } + + setPrunedHex(prunedHex) { + super.setPrunedHex(prunedHex); + return this; + } + + setPrunableHex(prunableHex) { + super.setPrunableHex(prunableHex); + return this; + } + + setPrunableHash(prunableHash) { + super.setPrunableHash(prunableHash); + return this; + } + + setSize(size) { + super.setSize(size); + return this; + } + + setWeight(weight) { + super.setWeight(weight); + return this; + } + + setInputs(inputs) { + super.setInputs(inputs); + return this; + } + + setOutputIndices(outputIndices) { + super.setOutputIndices(outputIndices); + return this; + } + + setMetadata(metadata) { + super.setMetadata(metadata); + return this; + } + + setTxSet(txSet) { + super.setTxSet(txSet); + return this; + } + + setExtra(extra) { + super.setExtra(extra); + return this; + } + + setRctSignatures(rctSignatures) { + super.setRctSignatures(rctSignatures); + return this; + } + + setRctSigPrunable(rctSigPrunable) { + super.setRctSigPrunable(rctSigPrunable); + return this; + } + + setIsKeptByBlock(isKeptByBlock) { + super.setIsKeptByBlock(isKeptByBlock); + return this; + } + + setIsFailed(isFailed) { + super.setIsFailed(isFailed); + return this; + } + + setLastFailedHeight(lastFailedHeight) { + super.setLastFailedHeight(lastFailedHeight); + return this; + } + + setLastFailedHash(lastFailedId) { + super.setLastFailedHash(lastFailedId); + return this; + } + + setMaxUsedBlockHeight(maxUsedBlockHeight) { + super.setMaxUsedBlockHeight(maxUsedBlockHeight); + return this; + } + + setMaxUsedBlockHash(maxUsedBlockId) { + super.setMaxUsedBlockHash(maxUsedBlockId); + return this; + } + + setSignatures(signatures) { + super.setSignatures(signatures); + return this; + } +}exports.default = MoneroTxQuery; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfTW9uZXJvT3V0cHV0UXVlcnkiLCJfTW9uZXJvVHJhbnNmZXJRdWVyeSIsIl9Nb25lcm9UeFdhbGxldCIsIk1vbmVyb1R4UXVlcnkiLCJNb25lcm9UeFdhbGxldCIsImNvbnN0cnVjdG9yIiwicXVlcnkiLCJ0cmFuc2ZlclF1ZXJ5IiwiTW9uZXJvVHJhbnNmZXJRdWVyeSIsImlucHV0UXVlcnkiLCJNb25lcm9PdXRwdXRRdWVyeSIsIm91dHB1dFF1ZXJ5IiwiZ2V0VHJhbnNmZXJRdWVyeSIsInNldFR4UXVlcnkiLCJnZXRJbnB1dFF1ZXJ5IiwiZ2V0T3V0cHV0UXVlcnkiLCJoYXNoIiwic2V0SGFzaGVzIiwiY29weSIsInRvSnNvbiIsImpzb24iLCJPYmplY3QiLCJhc3NpZ24iLCJ1bmRlZmluZWQiLCJibG9jayIsImdldElzSW5jb21pbmciLCJpc0luY29taW5nIiwic2V0SXNJbmNvbWluZyIsImdldElzT3V0Z29pbmciLCJpc091dGdvaW5nIiwic2V0SXNPdXRnb2luZyIsImdldEhhc2hlcyIsImhhc2hlcyIsInNldEhhc2giLCJhc3NlcnQiLCJnZXRIYXNQYXltZW50SWQiLCJoYXNQYXltZW50SWQiLCJzZXRIYXNQYXltZW50SWQiLCJnZXRQYXltZW50SWRzIiwicGF5bWVudElkcyIsInNldFBheW1lbnRJZHMiLCJzZXRQYXltZW50SWQiLCJwYXltZW50SWQiLCJnZXRIZWlnaHQiLCJoZWlnaHQiLCJzZXRIZWlnaHQiLCJnZXRNaW5IZWlnaHQiLCJtaW5IZWlnaHQiLCJzZXRNaW5IZWlnaHQiLCJnZXRNYXhIZWlnaHQiLCJtYXhIZWlnaHQiLCJzZXRNYXhIZWlnaHQiLCJnZXRJbmNsdWRlT3V0cHV0cyIsImluY2x1ZGVPdXRwdXRzIiwic2V0SW5jbHVkZU91dHB1dHMiLCJzZXRUcmFuc2ZlclF1ZXJ5IiwidHhRdWVyeSIsInNldElucHV0UXVlcnkiLCJzZXRPdXRwdXRRdWVyeSIsIm1lZXRzQ3JpdGVyaWEiLCJ0eCIsInF1ZXJ5Q2hpbGRyZW4iLCJFcnJvciIsImdldEhhc2giLCJnZXRQYXltZW50SWQiLCJnZXRJc0NvbmZpcm1lZCIsImdldEluVHhQb29sIiwiZ2V0UmVsYXkiLCJnZXRJc1JlbGF5ZWQiLCJnZXRJc0ZhaWxlZCIsImdldElzTWluZXJUeCIsImdldElzTG9ja2VkIiwidHhIZWlnaHQiLCJnZXRCbG9jayIsImluY2x1ZGVzIiwibWF0Y2hGb3VuZCIsImdldE91dGdvaW5nVHJhbnNmZXIiLCJnZXRJbmNvbWluZ1RyYW5zZmVycyIsImluY29taW5nVHJhbnNmZXIiLCJnZXRJbnB1dHMiLCJsZW5ndGgiLCJpbnB1dCIsImdldElucHV0c1dhbGxldCIsImdldE91dHB1dHMiLCJvdXRwdXQiLCJnZXRPdXRwdXRzV2FsbGV0Iiwic2V0SW5jb21pbmdUcmFuc2ZlcnMiLCJpbmNvbWluZ1RyYW5zZmVycyIsInNldE91dGdvaW5nVHJhbnNmZXIiLCJvdXRnb2luZ1RyYW5zZmVyIiwic2V0T3V0cHV0cyIsIm91dHB1dHMiLCJzZXROb3RlIiwibm90ZSIsInNldElzTG9ja2VkIiwiaXNMb2NrZWQiLCJzZXRCbG9jayIsInNldFZlcnNpb24iLCJ2ZXJzaW9uIiwic2V0SXNNaW5lclR4IiwiaXNNaW5lclR4Iiwic2V0RmVlIiwiZmVlIiwic2V0UmluZ1NpemUiLCJyaW5nU2l6ZSIsInNldFJlbGF5IiwicmVsYXkiLCJzZXRJc1JlbGF5ZWQiLCJpc1JlbGF5ZWQiLCJzZXRJc0NvbmZpcm1lZCIsImlzQ29uZmlybWVkIiwic2V0SW5UeFBvb2wiLCJpblR4UG9vbCIsInNldE51bUNvbmZpcm1hdGlvbnMiLCJudW1Db25maXJtYXRpb25zIiwic2V0VW5sb2NrVGltZSIsInVubG9ja1RpbWUiLCJzZXRMYXN0UmVsYXllZFRpbWVzdGFtcCIsImxhc3RSZWxheWVkVGltZXN0YW1wIiwic2V0UmVjZWl2ZWRUaW1lc3RhbXAiLCJyZWNlaXZlZFRpbWVzdGFtcCIsInNldElzRG91YmxlU3BlbmRTZWVuIiwiaXNEb3VibGVTcGVuZFNlZW4iLCJzZXRLZXkiLCJrZXkiLCJzZXRGdWxsSGV4IiwiaGV4Iiwic2V0UHJ1bmVkSGV4IiwicHJ1bmVkSGV4Iiwic2V0UHJ1bmFibGVIZXgiLCJwcnVuYWJsZUhleCIsInNldFBydW5hYmxlSGFzaCIsInBydW5hYmxlSGFzaCIsInNldFNpemUiLCJzaXplIiwic2V0V2VpZ2h0Iiwid2VpZ2h0Iiwic2V0SW5wdXRzIiwiaW5wdXRzIiwic2V0T3V0cHV0SW5kaWNlcyIsIm91dHB1dEluZGljZXMiLCJzZXRNZXRhZGF0YSIsIm1ldGFkYXRhIiwic2V0VHhTZXQiLCJ0eFNldCIsInNldEV4dHJhIiwiZXh0cmEiLCJzZXRSY3RTaWduYXR1cmVzIiwicmN0U2lnbmF0dXJlcyIsInNldFJjdFNpZ1BydW5hYmxlIiwicmN0U2lnUHJ1bmFibGUiLCJzZXRJc0tlcHRCeUJsb2NrIiwiaXNLZXB0QnlCbG9jayIsInNldElzRmFpbGVkIiwiaXNGYWlsZWQiLCJzZXRMYXN0RmFpbGVkSGVpZ2h0IiwibGFzdEZhaWxlZEhlaWdodCIsInNldExhc3RGYWlsZWRIYXNoIiwibGFzdEZhaWxlZElkIiwic2V0TWF4VXNlZEJsb2NrSGVpZ2h0IiwibWF4VXNlZEJsb2NrSGVpZ2h0Iiwic2V0TWF4VXNlZEJsb2NrSGFzaCIsIm1heFVzZWRCbG9ja0lkIiwic2V0U2lnbmF0dXJlcyIsInNpZ25hdHVyZXMiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9UeFF1ZXJ5LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiO1xuaW1wb3J0IE1vbmVyb0Jsb2NrIGZyb20gXCIuLi8uLi9kYWVtb24vbW9kZWwvTW9uZXJvQmxvY2tcIjtcbmltcG9ydCBNb25lcm9PdXRwdXQgZnJvbSBcIi4uLy4uL2RhZW1vbi9tb2RlbC9Nb25lcm9PdXRwdXRcIjtcbmltcG9ydCBNb25lcm9JbmNvbWluZ1RyYW5zZmVyIGZyb20gXCIuL01vbmVyb0luY29taW5nVHJhbnNmZXJcIjtcbmltcG9ydCBNb25lcm9PdXRnb2luZ1RyYW5zZmVyIGZyb20gXCIuL01vbmVyb091dGdvaW5nVHJhbnNmZXJcIjtcbmltcG9ydCBNb25lcm9PdXRwdXRRdWVyeSBmcm9tIFwiLi9Nb25lcm9PdXRwdXRRdWVyeVwiO1xuaW1wb3J0IE1vbmVyb1RyYW5zZmVyUXVlcnkgZnJvbSBcIi4vTW9uZXJvVHJhbnNmZXJRdWVyeVwiO1xuaW1wb3J0IE1vbmVyb1R4U2V0IGZyb20gXCIuL01vbmVyb1R4U2V0XCI7XG5pbXBvcnQgTW9uZXJvVHhXYWxsZXQgZnJvbSBcIi4vTW9uZXJvVHhXYWxsZXRcIjtcblxuLyoqXG4gKiA8cD5Db25maWd1cmF0aW9uIHRvIHF1ZXJ5IHRyYW5zYWN0aW9ucy48L3A+XG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb1R4UXVlcnkgZXh0ZW5kcyBNb25lcm9UeFdhbGxldCB7XG5cbiAgaGFzaDogc3RyaW5nO1xuICBoYXNoZXM6IHN0cmluZ1tdO1xuICBoZWlnaHQ6IG51bWJlcjtcbiAgbWluSGVpZ2h0OiBudW1iZXI7XG4gIG1heEhlaWdodDogbnVtYmVyO1xuICBpbmNsdWRlT3V0cHV0czogYm9vbGVhbjtcbiAgaXNDb25maXJtZWQ6IGJvb2xlYW47XG4gIGluVHhQb29sOiBib29sZWFuO1xuICByZWxheTogYm9vbGVhbjtcbiAgaXNSZWxheWVkOiBib29sZWFuO1xuICBpc0ZhaWxlZDogYm9vbGVhbjtcbiAgaXNNaW5lclR4OiBib29sZWFuO1xuICBpc0xvY2tlZDogYm9vbGVhbjtcbiAgaXNJbmNvbWluZzogYm9vbGVhbjtcbiAgaXNPdXRnb2luZzogYm9vbGVhbjtcbiAgcGF5bWVudElkOiBzdHJpbmc7XG4gIHBheW1lbnRJZHM6IHN0cmluZ1tdO1xuICBoYXNQYXltZW50SWQ6IGJvb2xlYW47XG4gIHRyYW5zZmVyUXVlcnk6IFBhcnRpYWw8TW9uZXJvVHJhbnNmZXJRdWVyeT47XG4gIGlucHV0UXVlcnk6IFBhcnRpYWw8TW9uZXJvT3V0cHV0UXVlcnk+O1xuICBvdXRwdXRRdWVyeTogUGFydGlhbDxNb25lcm9PdXRwdXRRdWVyeT47XG5cbiAgLyoqXG4gICAqIDxwPkNvbnN0cnVjdCB0aGUgdHJhbnNhY3Rpb24gcXVlcnkuPC9wPlxuICAgKiBcbiAgICogPHA+RXhhbXBsZTo8L3A+XG4gICAqIFxuICAgKiA8Y29kZT5cbiAgICogJnNvbDsmc29sOyBnZXQgdHJhbnNhY3Rpb25zIHdpdGggdW5sb2NrZWQgaW5jb21pbmcgdHJhbnNmZXJzIHRvIGFjY291bnQgMDxicj5cbiAgICogbGV0IHR4cyA9IGF3YWl0IHdhbGxldC5nZXRUeHMoezxicj5cbiAgICogJm5ic3A7Jm5ic3A7IGlzTG9ja2VkOiBmYWxzZSw8YnI+XG4gICAqICZuYnNwOyZuYnNwOyB0cmFuc2ZlclF1ZXJ5OiB7PGJyPlxuICAgKiAmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgaXNJbmNvbWluZzogdHJ1ZSw8YnI+XG4gICAqICZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyBhY2NvdW50SW5kZXg6IDA8YnI+XG4gICAqICZuYnNwOyZuYnNwOyB9PGJyPlxuICAgKiB9KTtcbiAgICogPC9jb2RlPlxuICAgKiBcbiAgICogPHA+QWxsIGNvbmZpZ3VyYXRpb24gaXMgb3B0aW9uYWwuICBBbGwgdHJhbnNhY3Rpb25zIGFyZSByZXR1cm5lZCBleGNlcHQgdGhvc2UgdGhhdCBkb24ndCBtZWV0IGNyaXRlcmlhIGRlZmluZWQgaW4gdGhpcyBxdWVyeS48L3A+XG4gICAqIFxuICAgKiBAcGFyYW0ge01vbmVyb1R4UXVlcnl9IFtxdWVyeV0gLSB0eCBxdWVyeSBjb25maWd1cmF0aW9uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcXVlcnkuaGFzaF0gLSBnZXQgYSB0eCB3aXRoIHRoaXMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBbcXVlcnkudHhIYXNoZXNdIC0gZ2V0IHR4cyB3aXRoIHRoZXNlIGhhc2hlc1xuICAgKiBAcGFyYW0ge251bWJlcn0gW3F1ZXJ5LmhlaWdodF0gLSBnZXQgdHhzIHdpdGggdGhpcyBoZWlnaHRcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtxdWVyeS5taW5IZWlnaHRdIC0gZ2V0IHR4cyB3aXRoIGhlaWdodCBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gdGhpcyBoZWlnaHRcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtxdWVyeS5tYXhIZWlnaHRdIC0gZ2V0IHR4cyB3aXRoIGhlaWdodCBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gdGhpcyBoZWlnaHRcbiAgICogQHBhcmFtIHtib29sZWFufSBbcXVlcnkuaXNDb25maXJtZWRdIC0gZ2V0IGNvbmZpcm1lZCBvciB1bmNvbmZpcm1lZCB0eHNcbiAgICogQHBhcmFtIHtib29sZWFufSBbcXVlcnkuaW5UeFBvb2xdIC0gZ2V0IHR4cyBpbiBvciBvdXQgb2YgdGhlIHR4IHBvb2xcbiAgICogQHBhcmFtIHtib29sZWFufSBbcXVlcnkucmVsYXldIC0gZ2V0IHR4cyB3aXRoIHRoZSBzYW1lIHJlbGF5IHN0YXR1c1xuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtxdWVyeS5pc1JlbGF5ZWRdIC0gZ2V0IHJlbGF5ZWQgb3Igbm9uLXJlbGF5ZWQgdHhzXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3F1ZXJ5LmlzRmFpbGVkXSAtIGdldCBmYWlsZWQgb3Igbm9uLWZhaWxlZCB0eHNcbiAgICogQHBhcmFtIHtib29sZWFufSBbcXVlcnkuaXNNaW5lclR4XSAtIGdldCBtaW5lciBvciBub24tbWluZXIgdHhzXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3F1ZXJ5LmlzTG9ja2VkXSAtIGdldCBsb2NrZWQgb3IgdW5sb2NrZWQgdHhzXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3F1ZXJ5LmlzSW5jb21pbmddIC0gZ2V0IHR4cyB3aXRoIG9yIHdpdGhvdXQgaW5jb21pbmcgdHJhbnNmZXJzXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3F1ZXJ5LmlzT3V0Z29pbmddIC0gZ2V0IHR4cyB3aXRoIG9yIHdpdGhvdXQgb3V0Z29pbmcgdHJhbnNmZXJzXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcXVlcnkucGF5bWVudElkXSAtIGdldCB0eHMgd2l0aCB0aGlzIHBheW1lbnQgSURcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtxdWVyeS5wYXltZW50SWRzXSAtIGdldCB0eHMgd2l0aCBhIHBheW1lbnQgSUQgYW1vbmcgdGhlc2UgcGF5bWVudCBJRHNcbiAgICogQHBhcmFtIHtib29sZWFufSBbcXVlcnkuaGFzUGF5bWVudElkXSAtIGdldCB0eHMgd2l0aCBvciB3aXRob3V0IHBheW1lbnQgSURzXG4gICAqIEBwYXJhbSB7UGFydGlhbDxNb25lcm9UcmFuc2ZlclF1ZXJ5Pn0gW3F1ZXJ5LnRyYW5zZmVyUXVlcnldIC0gZ2V0IHR4cyB3aXRoIHRyYW5zZmVycyBtYXRjaGluZyB0aGlzIHRyYW5zZmVyIHF1ZXJ5XG4gICAqIEBwYXJhbSB7UGFydGlhbDxNb25lcm9PdXRwdXRRdWVyeT59IFtxdWVyeS5pbnB1dFF1ZXJ5XSAtIGdldCB0eHMgd2l0aCBpbnB1dHMgbWF0Y2hpbmcgdGhpcyBpbnB1dCBxdWVyeVxuICAgKiBAcGFyYW0ge1BhcnRpYWw8TW9uZXJvT3V0cHV0UXVlcnk+fSBbcXVlcnkub3V0cHV0UXVlcnldIC0gZ2V0IHR4cyB3aXRoIG91dHB1dHMgbWF0Y2hpbmcgdGhpcyBvdXRwdXQgcXVlcnlcbiAgICovXG4gIGNvbnN0cnVjdG9yKHF1ZXJ5PzogUGFydGlhbDxNb25lcm9UeFF1ZXJ5Pikge1xuICAgIHN1cGVyKHF1ZXJ5KTtcbiAgICBcbiAgICAvLyBjb3B5IHF1ZXJpZXNcbiAgICBpZiAodGhpcy50cmFuc2ZlclF1ZXJ5KSB0aGlzLnRyYW5zZmVyUXVlcnkgPSBuZXcgTW9uZXJvVHJhbnNmZXJRdWVyeSh0aGlzLnRyYW5zZmVyUXVlcnkpO1xuICAgIGlmICh0aGlzLmlucHV0UXVlcnkpIHRoaXMuaW5wdXRRdWVyeSA9IG5ldyBNb25lcm9PdXRwdXRRdWVyeSh0aGlzLmlucHV0UXVlcnkpO1xuICAgIGlmICh0aGlzLm91dHB1dFF1ZXJ5KSB0aGlzLm91dHB1dFF1ZXJ5ID0gbmV3IE1vbmVyb091dHB1dFF1ZXJ5KHRoaXMub3V0cHV0UXVlcnkpO1xuICAgIFxuICAgIC8vIGxpbmsgY3ljbGVzXG4gICAgaWYgKHRoaXMudHJhbnNmZXJRdWVyeSkgdGhpcy5nZXRUcmFuc2ZlclF1ZXJ5KCkuc2V0VHhRdWVyeSh0aGlzKTtcbiAgICBpZiAodGhpcy5pbnB1dFF1ZXJ5KSB0aGlzLmdldElucHV0UXVlcnkoKS5zZXRUeFF1ZXJ5KHRoaXMpO1xuICAgIGlmICh0aGlzLm91dHB1dFF1ZXJ5KSB0aGlzLmdldE91dHB1dFF1ZXJ5KCkuc2V0VHhRdWVyeSh0aGlzKTtcbiAgICBcbiAgICAvLyBhbGlhcyAnaGFzaCcgdG8gaGFzaGVzXG4gICAgaWYgKHRoaXMuaGFzaCkge1xuICAgICAgdGhpcy5zZXRIYXNoZXMoW3RoaXMuaGFzaF0pO1xuICAgICAgZGVsZXRlIHRoaXMuaGFzaDtcbiAgICB9XG4gIH1cbiAgXG4gIGNvcHkoKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgcmV0dXJuIG5ldyBNb25lcm9UeFF1ZXJ5KHRoaXMpO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICBsZXQganNvbiA9IE9iamVjdC5hc3NpZ24oe30sIHRoaXMsIHN1cGVyLnRvSnNvbigpKTsgLy8gbWVyZ2UganNvbiBvbnRvIGluaGVyaXRlZCBzdGF0ZVxuICAgIGlmICh0aGlzLmdldFRyYW5zZmVyUXVlcnkoKSAhPT0gdW5kZWZpbmVkKSBqc29uLnRyYW5zZmVyUXVlcnkgPSB0aGlzLmdldFRyYW5zZmVyUXVlcnkoKS50b0pzb24oKTtcbiAgICBpZiAodGhpcy5nZXRJbnB1dFF1ZXJ5KCkgIT09IHVuZGVmaW5lZCkganNvbi5pbnB1dFF1ZXJ5ID0gdGhpcy5nZXRJbnB1dFF1ZXJ5KCkudG9Kc29uKCk7XG4gICAgaWYgKHRoaXMuZ2V0T3V0cHV0UXVlcnkoKSAhPT0gdW5kZWZpbmVkKSBqc29uLm91dHB1dFF1ZXJ5ID0gdGhpcy5nZXRPdXRwdXRRdWVyeSgpLnRvSnNvbigpO1xuICAgIGRlbGV0ZSBqc29uLmJsb2NrOyAgLy8gZG8gbm90IHNlcmlhbGl6ZSBwYXJlbnQgYmxvY2tcbiAgICByZXR1cm4ganNvbjtcbiAgfVxuICBcbiAgZ2V0SXNJbmNvbWluZygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc0luY29taW5nO1xuICB9XG4gIFxuICBzZXRJc0luY29taW5nKGlzSW5jb21pbmc6IGJvb2xlYW4pOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICB0aGlzLmlzSW5jb21pbmcgPSBpc0luY29taW5nO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRJc091dGdvaW5nKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzT3V0Z29pbmc7XG4gIH1cbiAgXG4gIHNldElzT3V0Z29pbmcoaXNPdXRnb2luZzogYm9vbGVhbik6IE1vbmVyb1R4UXVlcnkge1xuICAgIHRoaXMuaXNPdXRnb2luZyA9IGlzT3V0Z29pbmc7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRIYXNoZXMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiB0aGlzLmhhc2hlcztcbiAgfVxuXG4gIHNldEhhc2hlcyhoYXNoZXM6IHN0cmluZ1tdKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgdGhpcy5oYXNoZXMgPSBoYXNoZXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHNldEhhc2goaGFzaDogc3RyaW5nKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgaWYgKGhhc2ggPT09IHVuZGVmaW5lZCkgcmV0dXJuIHRoaXMuc2V0SGFzaGVzKHVuZGVmaW5lZCk7XG4gICAgYXNzZXJ0KHR5cGVvZiBoYXNoID09PSBcInN0cmluZ1wiKTtcbiAgICByZXR1cm4gdGhpcy5zZXRIYXNoZXMoW2hhc2hdKTtcbiAgfVxuICBcbiAgZ2V0SGFzUGF5bWVudElkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmhhc1BheW1lbnRJZDtcbiAgfVxuICBcbiAgc2V0SGFzUGF5bWVudElkKGhhc1BheW1lbnRJZDogYm9vbGVhbik6IE1vbmVyb1R4UXVlcnkge1xuICAgIHRoaXMuaGFzUGF5bWVudElkID0gaGFzUGF5bWVudElkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRQYXltZW50SWRzKCk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gdGhpcy5wYXltZW50SWRzO1xuICB9XG5cbiAgc2V0UGF5bWVudElkcyhwYXltZW50SWRzOiBzdHJpbmdbXSk6IE1vbmVyb1R4UXVlcnkge1xuICAgIHRoaXMucGF5bWVudElkcyA9IHBheW1lbnRJZHM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHNldFBheW1lbnRJZChwYXltZW50SWQ6IHN0cmluZyk6IE1vbmVyb1R4UXVlcnkge1xuICAgIGlmIChwYXltZW50SWQgPT09IHVuZGVmaW5lZCkgcmV0dXJuIHRoaXMuc2V0UGF5bWVudElkcyh1bmRlZmluZWQpO1xuICAgIGFzc2VydCh0eXBlb2YgcGF5bWVudElkID09PSBcInN0cmluZ1wiKTtcbiAgICByZXR1cm4gdGhpcy5zZXRQYXltZW50SWRzKFtwYXltZW50SWRdKTtcbiAgfVxuICBcbiAgZ2V0SGVpZ2h0KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuaGVpZ2h0O1xuICB9XG4gIFxuICBzZXRIZWlnaHQoaGVpZ2h0OiBudW1iZXIpOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICB0aGlzLmhlaWdodCA9IGhlaWdodDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0TWluSGVpZ2h0KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubWluSGVpZ2h0O1xuICB9XG5cbiAgc2V0TWluSGVpZ2h0KG1pbkhlaWdodDogbnVtYmVyKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgdGhpcy5taW5IZWlnaHQgPSBtaW5IZWlnaHQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRNYXhIZWlnaHQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5tYXhIZWlnaHQ7XG4gIH1cblxuICBzZXRNYXhIZWlnaHQobWF4SGVpZ2h0OiBudW1iZXIpOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICB0aGlzLm1heEhlaWdodCA9IG1heEhlaWdodDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0SW5jbHVkZU91dHB1dHMoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaW5jbHVkZU91dHB1dHM7XG4gIH1cblxuICBzZXRJbmNsdWRlT3V0cHV0cyhpbmNsdWRlT3V0cHV0czogYm9vbGVhbik6IE1vbmVyb1R4UXVlcnkge1xuICAgIHRoaXMuaW5jbHVkZU91dHB1dHMgPSBpbmNsdWRlT3V0cHV0cztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0VHJhbnNmZXJRdWVyeSgpOiBNb25lcm9UcmFuc2ZlclF1ZXJ5IHtcbiAgICByZXR1cm4gdGhpcy50cmFuc2ZlclF1ZXJ5IGFzIE1vbmVyb1RyYW5zZmVyUXVlcnlcbiAgfVxuICBcbiAgc2V0VHJhbnNmZXJRdWVyeSh0cmFuc2ZlclF1ZXJ5OiBNb25lcm9UcmFuc2ZlclF1ZXJ5KTogTW9uZXJvVHhRdWVyeSB7XG4gICAgdGhpcy50cmFuc2ZlclF1ZXJ5ID0gdHJhbnNmZXJRdWVyeSA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogdHJhbnNmZXJRdWVyeSBpbnN0YW5jZW9mIE1vbmVyb1RyYW5zZmVyUXVlcnkgPyB0cmFuc2ZlclF1ZXJ5IDogbmV3IE1vbmVyb1RyYW5zZmVyUXVlcnkodHJhbnNmZXJRdWVyeSk7XG4gICAgaWYgKHRyYW5zZmVyUXVlcnkpIHRoaXMudHJhbnNmZXJRdWVyeS50eFF1ZXJ5ID0gdGhpcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0SW5wdXRRdWVyeSgpOiBNb25lcm9PdXRwdXRRdWVyeSB7XG4gICAgcmV0dXJuIHRoaXMuaW5wdXRRdWVyeSBhcyBNb25lcm9PdXRwdXRRdWVyeTtcbiAgfVxuICBcbiAgc2V0SW5wdXRRdWVyeShpbnB1dFF1ZXJ5OiBNb25lcm9PdXRwdXRRdWVyeSk6IE1vbmVyb1R4UXVlcnkge1xuICAgIHRoaXMuaW5wdXRRdWVyeSA9IGlucHV0UXVlcnk7XG4gICAgaWYgKGlucHV0UXVlcnkpIGlucHV0UXVlcnkudHhRdWVyeSA9IHRoaXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldE91dHB1dFF1ZXJ5KCk6IE1vbmVyb091dHB1dFF1ZXJ5IHtcbiAgICByZXR1cm4gdGhpcy5vdXRwdXRRdWVyeSBhcyBNb25lcm9PdXRwdXRRdWVyeTtcbiAgfVxuICBcbiAgc2V0T3V0cHV0UXVlcnkob3V0cHV0UXVlcnk6IE1vbmVyb091dHB1dFF1ZXJ5KTogTW9uZXJvVHhRdWVyeSB7XG4gICAgdGhpcy5vdXRwdXRRdWVyeSA9IG91dHB1dFF1ZXJ5ID09PSB1bmRlZmluZWQgPyB1bmRlZmluZWQgOiBvdXRwdXRRdWVyeSBpbnN0YW5jZW9mIE1vbmVyb091dHB1dFF1ZXJ5ID8gb3V0cHV0UXVlcnkgOiBuZXcgTW9uZXJvT3V0cHV0UXVlcnkob3V0cHV0UXVlcnkpO1xuICAgIGlmIChvdXRwdXRRdWVyeSkgdGhpcy5vdXRwdXRRdWVyeS50eFF1ZXJ5ID0gdGhpcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgbWVldHNDcml0ZXJpYSh0eDogTW9uZXJvVHhXYWxsZXQsIHF1ZXJ5Q2hpbGRyZW4/OiBib29sZWFuKTogYm9vbGVhbiB7XG4gICAgaWYgKCEodHggaW5zdGFuY2VvZiBNb25lcm9UeFdhbGxldCkpIHRocm93IG5ldyBFcnJvcihcIlR4IG5vdCBnaXZlbiB0byBNb25lcm9UeFF1ZXJ5Lm1lZXRzQ3JpdGVyaWEodHgpXCIpO1xuICAgIGlmIChxdWVyeUNoaWxkcmVuID09PSB1bmRlZmluZWQpIHF1ZXJ5Q2hpbGRyZW4gPSB0cnVlO1xuICAgIFxuICAgIC8vIGZpbHRlciBvbiB0eFxuICAgIGlmICh0aGlzLmdldEhhc2goKSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuZ2V0SGFzaCgpICE9PSB0eC5nZXRIYXNoKCkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAodGhpcy5nZXRQYXltZW50SWQoKSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuZ2V0UGF5bWVudElkKCkgIT09IHR4LmdldFBheW1lbnRJZCgpKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKHRoaXMuZ2V0SXNDb25maXJtZWQoKSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuZ2V0SXNDb25maXJtZWQoKSAhPT0gdHguZ2V0SXNDb25maXJtZWQoKSkgcmV0dXJuIGZhbHNlO1xuICAgIGlmICh0aGlzLmdldEluVHhQb29sKCkgIT09IHVuZGVmaW5lZCAmJiB0aGlzLmdldEluVHhQb29sKCkgIT09IHR4LmdldEluVHhQb29sKCkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAodGhpcy5nZXRSZWxheSgpICE9PSB1bmRlZmluZWQgJiYgdGhpcy5nZXRSZWxheSgpICE9PSB0eC5nZXRSZWxheSgpKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKHRoaXMuZ2V0SXNSZWxheWVkKCkgIT09IHVuZGVmaW5lZCAmJiB0aGlzLmdldElzUmVsYXllZCgpICE9PSB0eC5nZXRJc1JlbGF5ZWQoKSkgcmV0dXJuIGZhbHNlO1xuICAgIGlmICh0aGlzLmdldElzRmFpbGVkKCkgIT09IHVuZGVmaW5lZCAmJiB0aGlzLmdldElzRmFpbGVkKCkgIT09IHR4LmdldElzRmFpbGVkKCkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAodGhpcy5nZXRJc01pbmVyVHgoKSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuZ2V0SXNNaW5lclR4KCkgIT09IHR4LmdldElzTWluZXJUeCgpKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKHRoaXMuZ2V0SXNMb2NrZWQoKSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuZ2V0SXNMb2NrZWQoKSAhPT0gdHguZ2V0SXNMb2NrZWQoKSkgcmV0dXJuIGZhbHNlO1xuICAgIFxuICAgIC8vIGZpbHRlciBvbiBoYXZpbmcgYSBwYXltZW50IGlkXG4gICAgaWYgKHRoaXMuZ2V0SGFzUGF5bWVudElkKCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgaWYgKHRoaXMuZ2V0SGFzUGF5bWVudElkKCkgJiYgdHguZ2V0UGF5bWVudElkKCkgPT09IHVuZGVmaW5lZCkgcmV0dXJuIGZhbHNlO1xuICAgICAgaWYgKCF0aGlzLmdldEhhc1BheW1lbnRJZCgpICYmIHR4LmdldFBheW1lbnRJZCgpICE9PSB1bmRlZmluZWQpIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgXG4gICAgLy8gZmlsdGVyIG9uIGluY29taW5nXG4gICAgaWYgKHRoaXMuZ2V0SXNJbmNvbWluZygpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmICh0aGlzLmdldElzSW5jb21pbmcoKSAmJiAhdHguZ2V0SXNJbmNvbWluZygpKSByZXR1cm4gZmFsc2U7XG4gICAgICBpZiAoIXRoaXMuZ2V0SXNJbmNvbWluZygpICYmIHR4LmdldElzSW5jb21pbmcoKSkgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBcbiAgICAvLyBmaWx0ZXIgb24gb3V0Z29pbmdcbiAgICBpZiAodGhpcy5nZXRJc091dGdvaW5nKCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgaWYgKHRoaXMuZ2V0SXNPdXRnb2luZygpICYmICF0eC5nZXRJc091dGdvaW5nKCkpIHJldHVybiBmYWxzZTtcbiAgICAgIGlmICghdGhpcy5nZXRJc091dGdvaW5nKCkgJiYgdHguZ2V0SXNPdXRnb2luZygpKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIFxuICAgIC8vIGZpbHRlciBvbiByZW1haW5pbmcgZmllbGRzXG4gICAgbGV0IHR4SGVpZ2h0ID0gdHguZ2V0QmxvY2soKSA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogdHguZ2V0QmxvY2soKS5nZXRIZWlnaHQoKTtcbiAgICBpZiAodGhpcy5nZXRIYXNoZXMoKSAhPT0gdW5kZWZpbmVkICYmICF0aGlzLmdldEhhc2hlcygpLmluY2x1ZGVzKHR4LmdldEhhc2goKSkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAodGhpcy5nZXRQYXltZW50SWRzKCkgIT09IHVuZGVmaW5lZCAmJiAhdGhpcy5nZXRQYXltZW50SWRzKCkuaW5jbHVkZXModHguZ2V0UGF5bWVudElkKCkpKSByZXR1cm4gZmFsc2U7XG4gICAgaWYgKHRoaXMuZ2V0SGVpZ2h0KCkgIT09IHVuZGVmaW5lZCAmJiAodHhIZWlnaHQgPT09IHVuZGVmaW5lZCB8fCB0eEhlaWdodCAhPT0gdGhpcy5nZXRIZWlnaHQoKSkpIHJldHVybiBmYWxzZTtcbiAgICBpZiAodGhpcy5nZXRNaW5IZWlnaHQoKSAhPT0gdW5kZWZpbmVkICYmIHR4SGVpZ2h0ICE9PSB1bmRlZmluZWQgJiYgdHhIZWlnaHQgPCB0aGlzLmdldE1pbkhlaWdodCgpKSByZXR1cm4gZmFsc2U7IC8vIGRvIG5vdCBmaWx0ZXIgdW5jb25maXJtZWRcbiAgICBpZiAodGhpcy5nZXRNYXhIZWlnaHQoKSAhPT0gdW5kZWZpbmVkICYmICh0eEhlaWdodCA9PT0gdW5kZWZpbmVkIHx8IHR4SGVpZ2h0ID4gdGhpcy5nZXRNYXhIZWlnaHQoKSkpIHJldHVybiBmYWxzZTtcbiAgICAvLyBUT0RPOiBmaWx0ZXJpbmcgbm90IGNvbXBsZXRlXG4gICAgXG4gICAgLy8gZG9uZSBpZiBub3QgcXVlcnlpbmcgdHJhbnNmZXJzIG9yIG91dHB1dHNcbiAgICBpZiAoIXF1ZXJ5Q2hpbGRyZW4pIHJldHVybiB0cnVlO1xuICAgIFxuICAgIC8vIGF0IGxlYXN0IG9uZSB0cmFuc2ZlciBtdXN0IG1lZXQgdHJhbnNmZXIgZmlsdGVyIGlmIGRlZmluZWRcbiAgICBpZiAodGhpcy5nZXRUcmFuc2ZlclF1ZXJ5KCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgbGV0IG1hdGNoRm91bmQgPSBmYWxzZTtcbiAgICAgIGlmICh0eC5nZXRPdXRnb2luZ1RyYW5zZmVyKCkgJiYgdGhpcy5nZXRUcmFuc2ZlclF1ZXJ5KCkubWVldHNDcml0ZXJpYSh0eC5nZXRPdXRnb2luZ1RyYW5zZmVyKCksIGZhbHNlKSkgbWF0Y2hGb3VuZCA9IHRydWU7XG4gICAgICBlbHNlIGlmICh0eC5nZXRJbmNvbWluZ1RyYW5zZmVycygpKSB7XG4gICAgICAgIGZvciAobGV0IGluY29taW5nVHJhbnNmZXIgb2YgdHguZ2V0SW5jb21pbmdUcmFuc2ZlcnMoKSkge1xuICAgICAgICAgIGlmICh0aGlzLmdldFRyYW5zZmVyUXVlcnkoKS5tZWV0c0NyaXRlcmlhKGluY29taW5nVHJhbnNmZXIsIGZhbHNlKSkge1xuICAgICAgICAgICAgbWF0Y2hGb3VuZCA9IHRydWU7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmICghbWF0Y2hGb3VuZCkgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBcbiAgICAvLyBhdCBsZWFzdCBvbmUgaW5wdXQgbXVzdCBtZWV0IGlucHV0IHF1ZXJ5IGlmIGRlZmluZWRcbiAgICBpZiAodGhpcy5nZXRJbnB1dFF1ZXJ5KCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgaWYgKHR4LmdldElucHV0cygpID09PSB1bmRlZmluZWQgfHwgdHguZ2V0SW5wdXRzKCkubGVuZ3RoID09PSAwKSByZXR1cm4gZmFsc2U7XG4gICAgICBsZXQgbWF0Y2hGb3VuZCA9IGZhbHNlO1xuICAgICAgZm9yIChsZXQgaW5wdXQgb2YgdHguZ2V0SW5wdXRzV2FsbGV0KCkpIHtcbiAgICAgICAgaWYgKHRoaXMuZ2V0SW5wdXRRdWVyeSgpLm1lZXRzQ3JpdGVyaWEoaW5wdXQsIGZhbHNlKSkge1xuICAgICAgICAgIG1hdGNoRm91bmQgPSB0cnVlO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoIW1hdGNoRm91bmQpIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgXG4gICAgLy8gYXQgbGVhc3Qgb25lIG91dHB1dCBtdXN0IG1lZXQgb3V0cHV0IHF1ZXJ5IGlmIGRlZmluZWRcbiAgICBpZiAodGhpcy5nZXRPdXRwdXRRdWVyeSgpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmICh0eC5nZXRPdXRwdXRzKCkgPT09IHVuZGVmaW5lZCB8fCB0eC5nZXRPdXRwdXRzKCkubGVuZ3RoID09PSAwKSByZXR1cm4gZmFsc2U7XG4gICAgICBsZXQgbWF0Y2hGb3VuZCA9IGZhbHNlO1xuICAgICAgZm9yIChsZXQgb3V0cHV0IG9mIHR4LmdldE91dHB1dHNXYWxsZXQoKSkge1xuICAgICAgICBpZiAodGhpcy5nZXRPdXRwdXRRdWVyeSgpLm1lZXRzQ3JpdGVyaWEob3V0cHV0LCBmYWxzZSkpIHtcbiAgICAgICAgICBtYXRjaEZvdW5kID0gdHJ1ZTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKCFtYXRjaEZvdW5kKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIFxuICAgIHJldHVybiB0cnVlOyAgLy8gdHJhbnNhY3Rpb24gbWVldHMgZmlsdGVyIGNyaXRlcmlhXG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tIE9WRVJSSURFIENPLVZBUklBTlQgUkVUVVJOIFRZUEVTIC0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIHNldEluY29taW5nVHJhbnNmZXJzKGluY29taW5nVHJhbnNmZXJzOiBNb25lcm9JbmNvbWluZ1RyYW5zZmVyW10pOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICBzdXBlci5zZXRJbmNvbWluZ1RyYW5zZmVycyhpbmNvbWluZ1RyYW5zZmVycyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRPdXRnb2luZ1RyYW5zZmVyKG91dGdvaW5nVHJhbnNmZXI6IE1vbmVyb091dGdvaW5nVHJhbnNmZXIpOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICBzdXBlci5zZXRPdXRnb2luZ1RyYW5zZmVyKG91dGdvaW5nVHJhbnNmZXIpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0T3V0cHV0cyhvdXRwdXRzOiBNb25lcm9PdXRwdXRbXSk6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldE91dHB1dHMob3V0cHV0cyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXROb3RlKG5vdGU6IHN0cmluZyk6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldE5vdGUobm90ZSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIHNldElzTG9ja2VkKGlzTG9ja2VkOiBib29sZWFuKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0SXNMb2NrZWQoaXNMb2NrZWQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0QmxvY2soYmxvY2s6IE1vbmVyb0Jsb2NrKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0QmxvY2soYmxvY2spO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBzZXRWZXJzaW9uKHZlcnNpb246IG51bWJlcik6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldFZlcnNpb24odmVyc2lvbik7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRJc01pbmVyVHgoaXNNaW5lclR4OiBib29sZWFuKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0SXNNaW5lclR4KGlzTWluZXJUeCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRGZWUoZmVlOiBiaWdpbnQpOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICBzdXBlci5zZXRGZWUoZmVlKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldFJpbmdTaXplKHJpbmdTaXplOiBudW1iZXIpOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICBzdXBlci5zZXRSaW5nU2l6ZShyaW5nU2l6ZSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRSZWxheShyZWxheTogYm9vbGVhbik6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldFJlbGF5KHJlbGF5KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldElzUmVsYXllZChpc1JlbGF5ZWQ6IGJvb2xlYW4pOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICBzdXBlci5zZXRJc1JlbGF5ZWQoaXNSZWxheWVkKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldElzQ29uZmlybWVkKGlzQ29uZmlybWVkOiBib29sZWFuKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0SXNDb25maXJtZWQoaXNDb25maXJtZWQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0SW5UeFBvb2woaW5UeFBvb2w6IGJvb2xlYW4pOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICBzdXBlci5zZXRJblR4UG9vbChpblR4UG9vbCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXROdW1Db25maXJtYXRpb25zKG51bUNvbmZpcm1hdGlvbnM6IG51bWJlcik6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldE51bUNvbmZpcm1hdGlvbnMobnVtQ29uZmlybWF0aW9ucyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRVbmxvY2tUaW1lKHVubG9ja1RpbWU6IGJpZ2ludCk6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldFVubG9ja1RpbWUodW5sb2NrVGltZSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRMYXN0UmVsYXllZFRpbWVzdGFtcChsYXN0UmVsYXllZFRpbWVzdGFtcDogbnVtYmVyKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0TGFzdFJlbGF5ZWRUaW1lc3RhbXAobGFzdFJlbGF5ZWRUaW1lc3RhbXApO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0UmVjZWl2ZWRUaW1lc3RhbXAocmVjZWl2ZWRUaW1lc3RhbXA6IG51bWJlcik6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldFJlY2VpdmVkVGltZXN0YW1wKHJlY2VpdmVkVGltZXN0YW1wKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldElzRG91YmxlU3BlbmRTZWVuKGlzRG91YmxlU3BlbmRTZWVuOiBib29sZWFuKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0SXNEb3VibGVTcGVuZFNlZW4oaXNEb3VibGVTcGVuZFNlZW4pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0S2V5KGtleTogc3RyaW5nKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0S2V5KGtleSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRGdWxsSGV4KGhleDogc3RyaW5nKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0RnVsbEhleChoZXgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0UHJ1bmVkSGV4KHBydW5lZEhleDogc3RyaW5nKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0UHJ1bmVkSGV4KHBydW5lZEhleCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRQcnVuYWJsZUhleChwcnVuYWJsZUhleDogc3RyaW5nKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0UHJ1bmFibGVIZXgocHJ1bmFibGVIZXgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0UHJ1bmFibGVIYXNoKHBydW5hYmxlSGFzaDogc3RyaW5nKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0UHJ1bmFibGVIYXNoKHBydW5hYmxlSGFzaCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRTaXplKHNpemU6IG51bWJlcik6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldFNpemUoc2l6ZSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRXZWlnaHQod2VpZ2h0OiBudW1iZXIpOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICBzdXBlci5zZXRXZWlnaHQod2VpZ2h0KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldElucHV0cyhpbnB1dHM6IE1vbmVyb091dHB1dFtdKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0SW5wdXRzKGlucHV0cyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRPdXRwdXRJbmRpY2VzKG91dHB1dEluZGljZXM6IG51bWJlcltdKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0T3V0cHV0SW5kaWNlcyhvdXRwdXRJbmRpY2VzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldE1ldGFkYXRhKG1ldGFkYXRhOiBzdHJpbmcpOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICBzdXBlci5zZXRNZXRhZGF0YShtZXRhZGF0YSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRUeFNldCh0eFNldDogTW9uZXJvVHhTZXQpOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICBzdXBlci5zZXRUeFNldCh0eFNldCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRFeHRyYShleHRyYTogVWludDhBcnJheSk6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldEV4dHJhKGV4dHJhKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldFJjdFNpZ25hdHVyZXMocmN0U2lnbmF0dXJlczogYW55KTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0UmN0U2lnbmF0dXJlcyhyY3RTaWduYXR1cmVzKVxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0UmN0U2lnUHJ1bmFibGUocmN0U2lnUHJ1bmFibGU6IGFueSk6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldFJjdFNpZ1BydW5hYmxlKHJjdFNpZ1BydW5hYmxlKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldElzS2VwdEJ5QmxvY2soaXNLZXB0QnlCbG9jazogYm9vbGVhbik6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldElzS2VwdEJ5QmxvY2soaXNLZXB0QnlCbG9jaylcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldElzRmFpbGVkKGlzRmFpbGVkOiBib29sZWFuKTogTW9uZXJvVHhRdWVyeSB7XG4gICAgc3VwZXIuc2V0SXNGYWlsZWQoaXNGYWlsZWQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBzZXRMYXN0RmFpbGVkSGVpZ2h0KGxhc3RGYWlsZWRIZWlnaHQ6IG51bWJlcik6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldExhc3RGYWlsZWRIZWlnaHQobGFzdEZhaWxlZEhlaWdodCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRMYXN0RmFpbGVkSGFzaChsYXN0RmFpbGVkSWQ6IHN0cmluZyk6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldExhc3RGYWlsZWRIYXNoKGxhc3RGYWlsZWRJZCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRNYXhVc2VkQmxvY2tIZWlnaHQobWF4VXNlZEJsb2NrSGVpZ2h0OiBudW1iZXIpOiBNb25lcm9UeFF1ZXJ5IHtcbiAgICBzdXBlci5zZXRNYXhVc2VkQmxvY2tIZWlnaHQobWF4VXNlZEJsb2NrSGVpZ2h0KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldE1heFVzZWRCbG9ja0hhc2gobWF4VXNlZEJsb2NrSWQ6IHN0cmluZyk6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldE1heFVzZWRCbG9ja0hhc2gobWF4VXNlZEJsb2NrSWQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0U2lnbmF0dXJlcyhzaWduYXR1cmVzOiBzdHJpbmdbXSk6IE1vbmVyb1R4UXVlcnkge1xuICAgIHN1cGVyLnNldFNpZ25hdHVyZXMoc2lnbmF0dXJlcyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTs7Ozs7QUFLQSxJQUFBQyxrQkFBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBO0FB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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroTxSet.d.ts b/dist/src/main/ts/wallet/model/MoneroTxSet.d.ts new file mode 100644 index 000000000..6a4e52cea --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTxSet.d.ts @@ -0,0 +1,27 @@ +import MoneroTxWallet from "./MoneroTxWallet"; +/** + * Groups transactions who share common hex data which is needed in order to + * sign and submit the transactions. + * + * For example, multisig transactions created from createTxs() share a common + * hex string which is needed in order to sign and submit the multisig + * transactions. + */ +export default class MoneroTxSet { + txs: MoneroTxWallet[]; + multisigTxHex: string; + unsignedTxHex: string; + signedTxHex: string; + constructor(txSet?: Partial); + toJson(): {} & this; + getTxs(): MoneroTxWallet[]; + setTxs(txs: any): this; + getMultisigTxHex(): string; + setMultisigTxHex(multisigTxHex: any): this; + getUnsignedTxHex(): string; + setUnsignedTxHex(unsignedTxHex: any): this; + getSignedTxHex(): string; + setSignedTxHex(signedTxHex: any): this; + merge(txSet: any): this; + toString(indent?: number): string; +} diff --git a/dist/src/main/ts/wallet/model/MoneroTxSet.js b/dist/src/main/ts/wallet/model/MoneroTxSet.js new file mode 100644 index 000000000..7bba157ee --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTxSet.js @@ -0,0 +1,112 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); +var _MoneroTxWallet = _interopRequireDefault(require("./MoneroTxWallet")); +var _MoneroUtils = _interopRequireDefault(require("../../common/MoneroUtils")); + +/** + * Groups transactions who share common hex data which is needed in order to + * sign and submit the transactions. + * + * For example, multisig transactions created from createTxs() share a common + * hex string which is needed in order to sign and submit the multisig + * transactions. + */ +class MoneroTxSet { + + + + + + + constructor(txSet) { + Object.assign(this, txSet); + + // copy txs + if (this.txs) { + for (let i = 0; i < this.txs.length; i++) { + this.txs[i] = new _MoneroTxWallet.default(this.txs[i]); + this.txs[i].setTxSet(this); + } + } + } + + toJson() { + let json = Object.assign({}, this); // copy state + if (this.getTxs() !== undefined) { + json.txs = []; + for (let tx of this.getTxs()) json.txs.push(tx.toJson()); + } + return json; + } + + getTxs() { + return this.txs; + } + + setTxs(txs) { + this.txs = txs; + return this; + } + + getMultisigTxHex() { + return this.multisigTxHex; + } + + setMultisigTxHex(multisigTxHex) { + this.multisigTxHex = multisigTxHex; + return this; + } + + getUnsignedTxHex() { + return this.unsignedTxHex; + } + + setUnsignedTxHex(unsignedTxHex) { + this.unsignedTxHex = unsignedTxHex; + return this; + } + + getSignedTxHex() { + return this.signedTxHex; + } + + setSignedTxHex(signedTxHex) { + this.signedTxHex = signedTxHex; + return this; + } + + merge(txSet) { + (0, _assert.default)(txSet instanceof MoneroTxSet); + if (this === txSet) return this; + + // merge sets + this.setMultisigTxHex(_GenUtils.default.reconcile(this.getMultisigTxHex(), txSet.getMultisigTxHex())); + this.setUnsignedTxHex(_GenUtils.default.reconcile(this.getUnsignedTxHex(), txSet.getUnsignedTxHex())); + this.setSignedTxHex(_GenUtils.default.reconcile(this.getSignedTxHex(), txSet.getSignedTxHex())); + + // merge txs + if (txSet.getTxs() !== undefined) { + for (let tx of txSet.getTxs()) { + tx.setTxSet(this); + _MoneroUtils.default.mergeTx(this.getTxs(), tx); + } + } + + return this; + } + + toString(indent = 0) { + let str = ""; + str += _GenUtils.default.kvLine("Multisig tx hex: ", this.getMultisigTxHex(), indent); + str += _GenUtils.default.kvLine("Unsigned tx hex: ", this.getUnsignedTxHex(), indent); + str += _GenUtils.default.kvLine("Signed tx hex: ", this.getSignedTxHex(), indent); + if (this.getTxs() !== undefined) { + str += _GenUtils.default.kvLine("Txs", "", indent); + for (let tx of this.getTxs()) { + str += tx.toString(indent + 1) + "\n"; + } + } + return str; + } +}exports.default = MoneroTxSet; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTW9uZXJvVHhXYWxsZXQiLCJfTW9uZXJvVXRpbHMiLCJNb25lcm9UeFNldCIsImNvbnN0cnVjdG9yIiwidHhTZXQiLCJPYmplY3QiLCJhc3NpZ24iLCJ0eHMiLCJpIiwibGVuZ3RoIiwiTW9uZXJvVHhXYWxsZXQiLCJzZXRUeFNldCIsInRvSnNvbiIsImpzb24iLCJnZXRUeHMiLCJ1bmRlZmluZWQiLCJ0eCIsInB1c2giLCJzZXRUeHMiLCJnZXRNdWx0aXNpZ1R4SGV4IiwibXVsdGlzaWdUeEhleCIsInNldE11bHRpc2lnVHhIZXgiLCJnZXRVbnNpZ25lZFR4SGV4IiwidW5zaWduZWRUeEhleCIsInNldFVuc2lnbmVkVHhIZXgiLCJnZXRTaWduZWRUeEhleCIsInNpZ25lZFR4SGV4Iiwic2V0U2lnbmVkVHhIZXgiLCJtZXJnZSIsImFzc2VydCIsIkdlblV0aWxzIiwicmVjb25jaWxlIiwiTW9uZXJvVXRpbHMiLCJtZXJnZVR4IiwidG9TdHJpbmciLCJpbmRlbnQiLCJzdHIiLCJrdkxpbmUiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9UeFNldC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi4vLi4vY29tbW9uL0dlblV0aWxzXCI7XG5pbXBvcnQgTW9uZXJvVHhXYWxsZXQgZnJvbSBcIi4vTW9uZXJvVHhXYWxsZXRcIjtcbmltcG9ydCBNb25lcm9VdGlscyBmcm9tIFwiLi4vLi4vY29tbW9uL01vbmVyb1V0aWxzXCI7XG5cbi8qKlxuICogR3JvdXBzIHRyYW5zYWN0aW9ucyB3aG8gc2hhcmUgY29tbW9uIGhleCBkYXRhIHdoaWNoIGlzIG5lZWRlZCBpbiBvcmRlciB0b1xuICogc2lnbiBhbmQgc3VibWl0IHRoZSB0cmFuc2FjdGlvbnMuXG4gKiBcbiAqIEZvciBleGFtcGxlLCBtdWx0aXNpZyB0cmFuc2FjdGlvbnMgY3JlYXRlZCBmcm9tIGNyZWF0ZVR4cygpIHNoYXJlIGEgY29tbW9uXG4gKiBoZXggc3RyaW5nIHdoaWNoIGlzIG5lZWRlZCBpbiBvcmRlciB0byBzaWduIGFuZCBzdWJtaXQgdGhlIG11bHRpc2lnXG4gKiB0cmFuc2FjdGlvbnMuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1vbmVyb1R4U2V0IHtcblxuICB0eHM6IE1vbmVyb1R4V2FsbGV0W107XG4gIG11bHRpc2lnVHhIZXg6IHN0cmluZztcbiAgdW5zaWduZWRUeEhleDogc3RyaW5nO1xuICBzaWduZWRUeEhleDogc3RyaW5nO1xuICBcbiAgY29uc3RydWN0b3IodHhTZXQ/OiBQYXJ0aWFsPE1vbmVyb1R4U2V0Pikge1xuICAgIE9iamVjdC5hc3NpZ24odGhpcywgdHhTZXQpO1xuICAgIFxuICAgIC8vIGNvcHkgdHhzXG4gICAgaWYgKHRoaXMudHhzKSB7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMudHhzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRoaXMudHhzW2ldID0gbmV3IE1vbmVyb1R4V2FsbGV0KHRoaXMudHhzW2ldKTtcbiAgICAgICAgdGhpcy50eHNbaV0uc2V0VHhTZXQodGhpcyk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIFxuICB0b0pzb24oKSB7XG4gICAgbGV0IGpzb24gPSBPYmplY3QuYXNzaWduKHt9LCB0aGlzKTsgLy8gY29weSBzdGF0ZVxuICAgIGlmICh0aGlzLmdldFR4cygpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGpzb24udHhzID0gW107XG4gICAgICBmb3IgKGxldCB0eCBvZiB0aGlzLmdldFR4cygpKSBqc29uLnR4cy5wdXNoKHR4LnRvSnNvbigpKTtcbiAgICB9XG4gICAgcmV0dXJuIGpzb247XG4gIH1cblxuICBnZXRUeHMoKSB7XG4gICAgcmV0dXJuIHRoaXMudHhzO1xuICB9XG5cbiAgc2V0VHhzKHR4cykge1xuICAgIHRoaXMudHhzID0gdHhzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRNdWx0aXNpZ1R4SGV4KCkge1xuICAgIHJldHVybiB0aGlzLm11bHRpc2lnVHhIZXg7XG4gIH1cbiAgXG4gIHNldE11bHRpc2lnVHhIZXgobXVsdGlzaWdUeEhleCkge1xuICAgIHRoaXMubXVsdGlzaWdUeEhleCA9IG11bHRpc2lnVHhIZXg7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFVuc2lnbmVkVHhIZXgoKSB7XG4gICAgcmV0dXJuIHRoaXMudW5zaWduZWRUeEhleDtcbiAgfVxuICBcbiAgc2V0VW5zaWduZWRUeEhleCh1bnNpZ25lZFR4SGV4KSB7XG4gICAgdGhpcy51bnNpZ25lZFR4SGV4ID0gdW5zaWduZWRUeEhleDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U2lnbmVkVHhIZXgoKSB7XG4gICAgcmV0dXJuIHRoaXMuc2lnbmVkVHhIZXg7XG4gIH1cbiAgXG4gIHNldFNpZ25lZFR4SGV4KHNpZ25lZFR4SGV4KSB7XG4gICAgdGhpcy5zaWduZWRUeEhleCA9IHNpZ25lZFR4SGV4O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBtZXJnZSh0eFNldCkge1xuICAgIGFzc2VydCh0eFNldCBpbnN0YW5jZW9mIE1vbmVyb1R4U2V0KTtcbiAgICBpZiAodGhpcyA9PT0gdHhTZXQpIHJldHVybiB0aGlzO1xuICAgIFxuICAgIC8vIG1lcmdlIHNldHNcbiAgICB0aGlzLnNldE11bHRpc2lnVHhIZXgoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0TXVsdGlzaWdUeEhleCgpLCB0eFNldC5nZXRNdWx0aXNpZ1R4SGV4KCkpKTtcbiAgICB0aGlzLnNldFVuc2lnbmVkVHhIZXgoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0VW5zaWduZWRUeEhleCgpLCB0eFNldC5nZXRVbnNpZ25lZFR4SGV4KCkpKTtcbiAgICB0aGlzLnNldFNpZ25lZFR4SGV4KEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldFNpZ25lZFR4SGV4KCksIHR4U2V0LmdldFNpZ25lZFR4SGV4KCkpKTtcbiAgICBcbiAgICAvLyBtZXJnZSB0eHNcbiAgICBpZiAodHhTZXQuZ2V0VHhzKCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgZm9yIChsZXQgdHggb2YgdHhTZXQuZ2V0VHhzKCkpIHtcbiAgICAgICAgdHguc2V0VHhTZXQodGhpcyk7XG4gICAgICAgIE1vbmVyb1V0aWxzLm1lcmdlVHgodGhpcy5nZXRUeHMoKSwgdHgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICB0b1N0cmluZyhpbmRlbnQgPSAwKSB7XG4gICAgbGV0IHN0ciA9IFwiXCI7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIk11bHRpc2lnIHR4IGhleDogXCIsIHRoaXMuZ2V0TXVsdGlzaWdUeEhleCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJVbnNpZ25lZCB0eCBoZXg6IFwiLCB0aGlzLmdldFVuc2lnbmVkVHhIZXgoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiU2lnbmVkIHR4IGhleDogXCIsIHRoaXMuZ2V0U2lnbmVkVHhIZXgoKSwgaW5kZW50KTtcbiAgICBpZiAodGhpcy5nZXRUeHMoKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiVHhzXCIsIFwiXCIsIGluZGVudCk7XG4gICAgICBmb3IgKGxldCB0eCBvZiB0aGlzLmdldFR4cygpKSB7XG4gICAgICAgIHN0ciArPSB0eC50b1N0cmluZyhpbmRlbnQgKyAxKSArIFwiXFxuXCI7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBzdHI7XG4gIH1cbn0iXSwibWFwcGluZ3MiOiJ5TEFBQSxJQUFBQSxPQUFBLEdBQUFDLHNC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 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroTxWallet.d.ts b/dist/src/main/ts/wallet/model/MoneroTxWallet.d.ts new file mode 100644 index 000000000..127275e44 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTxWallet.d.ts @@ -0,0 +1,256 @@ +import MoneroBlock from "../../daemon/model/MoneroBlock"; +import MoneroIncomingTransfer from "./MoneroIncomingTransfer"; +import MoneroOutgoingTransfer from "./MoneroOutgoingTransfer"; +import MoneroOutputQuery from "./MoneroOutputQuery"; +import MoneroOutput from "../../daemon/model/MoneroOutput"; +import MoneroOutputWallet from "./MoneroOutputWallet"; +import MoneroTransfer from "./MoneroTransfer"; +import MoneroTransferQuery from "./MoneroTransferQuery"; +import MoneroTx from "../../daemon/model/MoneroTx"; +import MoneroTxSet from "./MoneroTxSet"; +/** + * Models a Monero transaction with wallet extensions. + */ +export default class MoneroTxWallet extends MoneroTx { + txSet: MoneroTxSet; + isIncoming: boolean; + isOutgoing: boolean; + incomingTransfers: MoneroIncomingTransfer[]; + outgoingTransfer: MoneroOutgoingTransfer; + note: string; + isLocked: boolean; + inputSum: bigint; + outputSum: bigint; + changeAddress: string; + changeAmount: bigint; + numDummyOutputs: number; + extraHex: string; + /** + * Construct the model. + * + * @param {Partial} [tx] is existing state to initialize from (optional) + */ + constructor(tx?: Partial); + /** + * @return {any} json representation of this tx + */ + toJson(): any; + /** + * @return {MoneroTxSet} tx set containing txs + */ + getTxSet(): MoneroTxSet; + /** + * @param {MoneroTxSet} txSet - tx set containing txs + * @return {MoneroTxWallet} this tx for chaining + */ + setTxSet(txSet: MoneroTxSet): MoneroTxWallet; + /** + * @return {boolean} true if the tx has incoming funds, false otherwise + */ + getIsIncoming(): boolean; + /** + * @param {boolean} isIncoming - true if the tx has incoming funds, false otherwise + * @return {MoneroTxWallet} this tx for chaining + */ + setIsIncoming(isIncoming: boolean): MoneroTxWallet; + /** + * @return {boolean} true if the tx has outgoing funds, false otherwise + */ + getIsOutgoing(): boolean; + /** + * @param {boolean} isOutgoing - true if the tx has outgoing funds, false otherwise + * @return {MoneroTxWallet} this tx for chaining + */ + setIsOutgoing(isOutgoing: boolean): MoneroTxWallet; + /** + * @return {bigint} amount received in the tx + */ + getIncomingAmount(): bigint; + /** + * @return {bigint} amount spent in the tx + */ + getOutgoingAmount(): bigint; + /** + * @param {MoneroTransferQuery} [transferQuery] - query to get specific transfers + * @return {MoneroTransfer[]} transfers matching the query + */ + getTransfers(transferQuery?: MoneroTransferQuery): MoneroTransfer[]; + /** + * @param {MoneroTransferQuery} transferQuery - query to keep only specific transfers + * @return {MoneroTransfer[]} remaining transfers matching the query + */ + filterTransfers(transferQuery: MoneroTransferQuery): MoneroTransfer[]; + /** + * @return {MoneroIncomingTransfer[]} incoming transfers + */ + getIncomingTransfers(): MoneroIncomingTransfer[]; + /** + * @param {MoneroIncomingTransfer[]} incomingTransfers - incoming transfers + * @return {MoneroTxWallet} this tx for chaining + */ + setIncomingTransfers(incomingTransfers: MoneroIncomingTransfer[]): MoneroTxWallet; + /** + * @return {MoneroOutgoingTransfer} outgoing transfers + */ + getOutgoingTransfer(): MoneroOutgoingTransfer; + /** + * @param {MoneroOutgoingTransfer} outgoingTransfer - outgoing transfer + * @return {MoneroTxWallet} this tx for chaining + */ + setOutgoingTransfer(outgoingTransfer: MoneroOutgoingTransfer): MoneroTxWallet; + /** + * @param {MoneroOutputWallet[]} outputQuery - query to get specific inputs + * @return {MoneroOutputWallet[]} inputs matching the query + */ + getInputsWallet(outputQuery?: MoneroOutputQuery): MoneroOutputWallet[]; + /** + * @param {MoneroOutputWallet[]} inputs - tx inputs + * @return {MoneroTxWallet} this tx for chaining + */ + setInputsWallet(inputs: MoneroOutputWallet[]): MoneroTxWallet; + /** + * @param {MoneroOutputQuery} [outputQuery] - query to get specific outputs + * @return {MoneroOutputWallet[]} outputs matching the query + */ + getOutputsWallet(outputQuery?: MoneroOutputQuery): MoneroOutputWallet[]; + /** + * @param {MoneroOutputWallet[]} outputs - tx outputs + * @return {MoneroTxWallet} this tx for chaining + */ + setOutputsWallet(outputs: MoneroOutputWallet[]): MoneroTxWallet; + /** + * @param {MoneroOutputQuery} outputQuery - query to keep only specific outputs + * @return {MoneroTransfer[]} remaining outputs matching the query + */ + filterOutputs(outputQuery: MoneroOutputQuery): MoneroTransfer[]; + /** + * @return {string} tx note + */ + getNote(): string; + /** + * @param {string} note - tx note + * @return {MoneroTxWallet} this tx for chaining + */ + setNote(note: string): MoneroTxWallet; + /** + * @return {boolean} true if the tx is locked, false otherwise + */ + getIsLocked(): boolean; + /** + * @param {boolean} isLocked - true if the tx is locked, false otherwise + * @return {MoneroTxWallet} this tx for chaining + */ + setIsLocked(isLocked: boolean): MoneroTxWallet; + /** + * @return {bigint} sum of tx inputs + */ + getInputSum(): bigint; + /** + * @param {bigint} inputSum - sum of tx inputs + * @return {MoneroTxWallet} this tx for chaining + */ + setInputSum(inputSum: bigint): MoneroTxWallet; + /** + * @return {bigint} sum of tx outputs + */ + getOutputSum(): bigint; + /** + * @param {bigint} outputSum - sum of tx outputs + * @return {MoneroTxWallet} this tx for chaining + */ + setOutputSum(outputSum: bigint): MoneroTxWallet; + /** + * @return {string} change address + */ + getChangeAddress(): string; + /** + * @param {string} changeAddress - change address + * @return {MoneroTxWallet} this tx for chaining + */ + setChangeAddress(changeAddress: string): MoneroTxWallet; + /** + * @return {bigint} change amount + */ + getChangeAmount(): bigint; + /** + * @param {bigint} changeAmount - change amount + * @return {MoneroTxWallet} this tx for chaining + */ + setChangeAmount(changeAmount: bigint): MoneroTxWallet; + /** + * @return {number} number of dummy outputs + */ + getNumDummyOutputs(): number; + /** + * @param {number} numDummyOutputs - number of dummy outputs + * @return {MoneroTxWallet} this tx for chaining + */ + setNumDummyOutputs(numDummyOutputs: number): MoneroTxWallet; + /** + * @return {string} tx extra as hex + */ + getExtraHex(): string; + /** + * @param {string} extraHex - tx extra as hex + * @return {MoneroTxWallet} this tx for chaining + */ + setExtraHex(extraHex: string): MoneroTxWallet; + /** + * @return {MoneroTxWallet} a copy of this tx + */ + copy(): MoneroTxWallet; + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * Merging can modify or build references to the transaction given so it + * should not be re-used or it should be copied before calling this method. + * + * @param {MoneroTxWallet} tx - the transaction to merge into this transaction + */ + merge(tx: MoneroTxWallet): MoneroTxWallet; + /** + * @param {number} [indent] - starting indentation + * @param {boolean} [oneLine] - string is one line if true, multiple lines if false + * @return {string} string representation of this tx + */ + toString(indent?: number, oneLine?: boolean): string; + protected static mergeIncomingTransfer(transfers: any, transfer: any): void; + setBlock(block: MoneroBlock): MoneroTxWallet; + setHash(hash: string): MoneroTxWallet; + setVersion(version: number): MoneroTxWallet; + setIsMinerTx(isMinerTx: boolean): MoneroTxWallet; + setPaymentId(paymentId: string): MoneroTxWallet; + setFee(fee: bigint): MoneroTxWallet; + setRingSize(ringSize: number): MoneroTxWallet; + setRelay(relay: boolean): MoneroTxWallet; + setIsRelayed(isRelayed: boolean): MoneroTxWallet; + setIsConfirmed(isConfirmed: boolean): MoneroTxWallet; + setInTxPool(inTxPool: boolean): MoneroTxWallet; + setNumConfirmations(numConfirmations: number): MoneroTxWallet; + setUnlockTime(unlockTime: bigint): MoneroTxWallet; + setLastRelayedTimestamp(lastRelayedTimestamp: number): MoneroTxWallet; + setReceivedTimestamp(receivedTimestamp: number): MoneroTxWallet; + setIsDoubleSpendSeen(isDoubleSpendSeen: boolean): MoneroTxWallet; + setKey(key: string): MoneroTxWallet; + setFullHex(fullHex: string): MoneroTxWallet; + setPrunedHex(prunedHex: string): MoneroTxWallet; + setPrunableHex(prunableHex: string): MoneroTxWallet; + setPrunableHash(prunableHash: string): MoneroTxWallet; + setSize(size: number): MoneroTxWallet; + setWeight(weight: number): MoneroTxWallet; + setInputs(inputs: MoneroOutput[]): MoneroTxWallet; + setOutputs(outputs: MoneroOutput[]): MoneroTxWallet; + setOutputIndices(outputIndices: number[]): MoneroTxWallet; + setMetadata(metadata: string): MoneroTxWallet; + setExtra(extra: Uint8Array): MoneroTxWallet; + setRctSignatures(rctSignatures: any): MoneroTxWallet; + setRctSigPrunable(rctSigPrunable: any): MoneroTxWallet; + setIsKeptByBlock(isKeptByBlock: boolean): MoneroTxWallet; + setIsFailed(isFailed: boolean): MoneroTxWallet; + setLastFailedHeight(lastFailedHeight: number): MoneroTxWallet; + setLastFailedHash(lastFailedHash: string): MoneroTxWallet; + setMaxUsedBlockHeight(maxUsedBlockHeight: number): MoneroTxWallet; + setMaxUsedBlockHash(maxUsedBlockHash: string): MoneroTxWallet; + setSignatures(signatures: string[]): MoneroTxWallet; +} diff --git a/dist/src/main/ts/wallet/model/MoneroTxWallet.js b/dist/src/main/ts/wallet/model/MoneroTxWallet.js new file mode 100644 index 000000000..e27fd78ce --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroTxWallet.js @@ -0,0 +1,747 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0;var _assert = _interopRequireDefault(require("assert")); +var _GenUtils = _interopRequireDefault(require("../../common/GenUtils")); + +var _MoneroError = _interopRequireDefault(require("../../common/MoneroError")); +var _MoneroIncomingTransfer = _interopRequireDefault(require("./MoneroIncomingTransfer")); +var _MoneroOutgoingTransfer = _interopRequireDefault(require("./MoneroOutgoingTransfer")); + + +var _MoneroOutputWallet = _interopRequireDefault(require("./MoneroOutputWallet")); + + +var _MoneroTx = _interopRequireDefault(require("../../daemon/model/MoneroTx")); +var _MoneroTxSet = _interopRequireDefault(require("./MoneroTxSet")); + +/** + * Models a Monero transaction with wallet extensions. + */ +class MoneroTxWallet extends _MoneroTx.default { + + + + + + + + + + + + + + + + /** + * Construct the model. + * + * @param {Partial} [tx] is existing state to initialize from (optional) + */ + constructor(tx) { + super(tx); + this.setTxSet(this.getTxSet()); // preserve reference to tx set + + // copy incoming transfers + if (this.incomingTransfers) { + this.incomingTransfers = this.incomingTransfers.slice(); + for (let i = 0; i < this.incomingTransfers.length; i++) { + this.incomingTransfers[i] = new _MoneroIncomingTransfer.default(this.incomingTransfers[i]).setTx(this); + } + } + + // copy outgoing transfer + if (this.outgoingTransfer) { + this.outgoingTransfer = new _MoneroOutgoingTransfer.default(this.outgoingTransfer).setTx(this); + } + + // copy inputs + if (this.inputs) { + this.inputs = this.inputs.slice(); + for (let i = 0; i < this.inputs.length; i++) { + this.inputs[i] = new _MoneroOutputWallet.default(this.inputs[i]).setTx(this); + } + } + + // copy outputs + if (this.outputs) { + this.outputs = this.outputs.slice(); + for (let i = 0; i < this.outputs.length; i++) { + this.outputs[i] = new _MoneroOutputWallet.default(this.outputs[i]).setTx(this); + } + } + + // deserialize bigints + if (this.inputSum !== undefined && typeof this.inputSum !== "bigint") this.inputSum = BigInt(this.inputSum); + if (this.outputSum !== undefined && typeof this.outputSum !== "bigint") this.outputSum = BigInt(this.outputSum); + if (this.changeAmount !== undefined && typeof this.changeAmount !== "bigint") this.changeAmount = BigInt(this.changeAmount); + } + + /** + * @return {any} json representation of this tx + */ + toJson() { + let json = Object.assign({}, this, super.toJson()); // merge json onto inherited state + if (this.getIncomingTransfers() !== undefined) { + json.incomingTransfers = []; + for (let incomingTransfer of this.getIncomingTransfers()) json.incomingTransfers.push(incomingTransfer.toJson()); + } + if (this.getOutgoingTransfer() !== undefined) json.outgoingTransfer = this.getOutgoingTransfer().toJson(); + if (this.getInputSum() !== undefined) json.inputSum = this.getInputSum().toString(); + if (this.getOutputSum() !== undefined) json.outputSum = this.getOutputSum().toString(); + if (this.getChangeAmount() !== undefined) json.changeAmount = this.getChangeAmount().toString(); + delete json.block; // do not serialize parent block + delete json.txSet; // do not serialize parent tx set + return json; + } + + /** + * @return {MoneroTxSet} tx set containing txs + */ + getTxSet() { + return this.txSet; + } + + /** + * @param {MoneroTxSet} txSet - tx set containing txs + * @return {MoneroTxWallet} this tx for chaining + */ + setTxSet(txSet) { + this.txSet = txSet; + return this; + } + + /** + * @return {boolean} true if the tx has incoming funds, false otherwise + */ + getIsIncoming() { + return this.isIncoming; + } + + /** + * @param {boolean} isIncoming - true if the tx has incoming funds, false otherwise + * @return {MoneroTxWallet} this tx for chaining + */ + setIsIncoming(isIncoming) { + this.isIncoming = isIncoming; + return this; + } + + /** + * @return {boolean} true if the tx has outgoing funds, false otherwise + */ + getIsOutgoing() { + return this.isOutgoing; + } + + /** + * @param {boolean} isOutgoing - true if the tx has outgoing funds, false otherwise + * @return {MoneroTxWallet} this tx for chaining + */ + setIsOutgoing(isOutgoing) { + this.isOutgoing = isOutgoing; + return this; + } + + /** + * @return {bigint} amount received in the tx + */ + getIncomingAmount() { + if (this.getIncomingTransfers() === undefined) return undefined; + let incomingAmt = 0n; + for (let transfer of this.getIncomingTransfers()) incomingAmt = incomingAmt + transfer.getAmount(); + return incomingAmt; + } + + /** + * @return {bigint} amount spent in the tx + */ + getOutgoingAmount() { + return this.getOutgoingTransfer() ? this.getOutgoingTransfer().getAmount() : undefined; + } + + /** + * @param {MoneroTransferQuery} [transferQuery] - query to get specific transfers + * @return {MoneroTransfer[]} transfers matching the query + */ + getTransfers(transferQuery) { + let transfers = []; + if (this.getOutgoingTransfer() && (!transferQuery || transferQuery.meetsCriteria(this.getOutgoingTransfer()))) transfers.push(this.getOutgoingTransfer()); + if (this.getIncomingTransfers() !== undefined) { + for (let transfer of this.getIncomingTransfers()) { + if (!transferQuery || transferQuery.meetsCriteria(transfer)) transfers.push(transfer); + } + } + return transfers; + } + + /** + * @param {MoneroTransferQuery} transferQuery - query to keep only specific transfers + * @return {MoneroTransfer[]} remaining transfers matching the query + */ + filterTransfers(transferQuery) { + let transfers = []; + + // collect outgoing transfer or erase if filtered + if (this.getOutgoingTransfer() && (!transferQuery || transferQuery.meetsCriteria(this.getOutgoingTransfer()))) transfers.push(this.getOutgoingTransfer());else + this.setOutgoingTransfer(undefined); + + // collect incoming transfers or erase if filtered + if (this.getIncomingTransfers() !== undefined) { + let toRemoves = []; + for (let transfer of this.getIncomingTransfers()) { + if (transferQuery.meetsCriteria(transfer)) transfers.push(transfer);else + toRemoves.push(transfer); + } + this.setIncomingTransfers(this.getIncomingTransfers().filter(function (transfer) { + return !toRemoves.includes(transfer); + })); + if (this.getIncomingTransfers().length === 0) this.setIncomingTransfers(undefined); + } + + return transfers; + } + + /** + * @return {MoneroIncomingTransfer[]} incoming transfers + */ + getIncomingTransfers() { + return this.incomingTransfers; + } + + /** + * @param {MoneroIncomingTransfer[]} incomingTransfers - incoming transfers + * @return {MoneroTxWallet} this tx for chaining + */ + setIncomingTransfers(incomingTransfers) { + this.incomingTransfers = incomingTransfers; + return this; + } + + /** + * @return {MoneroOutgoingTransfer} outgoing transfers + */ + getOutgoingTransfer() { + return this.outgoingTransfer; + } + + /** + * @param {MoneroOutgoingTransfer} outgoingTransfer - outgoing transfer + * @return {MoneroTxWallet} this tx for chaining + */ + setOutgoingTransfer(outgoingTransfer) { + this.outgoingTransfer = outgoingTransfer; + return this; + } + + /** + * @param {MoneroOutputWallet[]} outputQuery - query to get specific inputs + * @return {MoneroOutputWallet[]} inputs matching the query + */ + getInputsWallet(outputQuery) { + let inputs = []; + for (let output of super.getInputs()) if (!outputQuery || outputQuery.meetsCriteria(output)) inputs.push(output); + return inputs; + } + + /** + * @param {MoneroOutputWallet[]} inputs - tx inputs + * @return {MoneroTxWallet} this tx for chaining + */ + setInputsWallet(inputs) { + + // validate that all inputs are wallet inputs + if (inputs) { + for (let output of inputs) { + if (!(output instanceof _MoneroOutputWallet.default)) throw new _MoneroError.default("Wallet transaction inputs must be of type MoneroOutputWallet"); + } + } + super.setInputs(inputs); + return this; + } + + /** + * @param {MoneroOutputQuery} [outputQuery] - query to get specific outputs + * @return {MoneroOutputWallet[]} outputs matching the query + */ + getOutputsWallet(outputQuery) { + let outputs = []; + for (let output of super.getOutputs()) if (!outputQuery || outputQuery.meetsCriteria(output)) outputs.push(output); + return outputs; + } + + /** + * @param {MoneroOutputWallet[]} outputs - tx outputs + * @return {MoneroTxWallet} this tx for chaining + */ + setOutputsWallet(outputs) { + + // validate that all outputs are wallet outputs + if (outputs) { + for (let output of outputs) { + if (!(output instanceof _MoneroOutputWallet.default)) throw new _MoneroError.default("Wallet transaction outputs must be of type MoneroOutputWallet"); + } + } + super.setOutputs(outputs); + return this; + } + + /** + * @param {MoneroOutputQuery} outputQuery - query to keep only specific outputs + * @return {MoneroTransfer[]} remaining outputs matching the query + */ + filterOutputs(outputQuery) { + let outputs = []; + if (super.getOutputs()) { + let toRemoves = []; + for (let output of super.getOutputs()) { + if (!outputQuery || outputQuery.meetsCriteria(output)) outputs.push(output);else + toRemoves.push(output); + } + this.setOutputs(super.getOutputs().filter(function (output) { + return !toRemoves.includes(output); + })); + if (this.getOutputs().length === 0) this.setOutputs(undefined); + } + return outputs; + } + + /** + * @return {string} tx note + */ + getNote() { + return this.note; + } + + /** + * @param {string} note - tx note + * @return {MoneroTxWallet} this tx for chaining + */ + setNote(note) { + this.note = note; + return this; + } + + /** + * @return {boolean} true if the tx is locked, false otherwise + */ + getIsLocked() { + return this.isLocked; + } + + /** + * @param {boolean} isLocked - true if the tx is locked, false otherwise + * @return {MoneroTxWallet} this tx for chaining + */ + setIsLocked(isLocked) { + this.isLocked = isLocked; + return this; + } + + /** + * @return {bigint} sum of tx inputs + */ + getInputSum() { + return this.inputSum; + } + + /** + * @param {bigint} inputSum - sum of tx inputs + * @return {MoneroTxWallet} this tx for chaining + */ + setInputSum(inputSum) { + this.inputSum = inputSum; + return this; + } + + /** + * @return {bigint} sum of tx outputs + */ + getOutputSum() { + return this.outputSum; + } + + /** + * @param {bigint} outputSum - sum of tx outputs + * @return {MoneroTxWallet} this tx for chaining + */ + setOutputSum(outputSum) { + this.outputSum = outputSum; + return this; + } + + /** + * @return {string} change address + */ + getChangeAddress() { + return this.changeAddress; + } + + /** + * @param {string} changeAddress - change address + * @return {MoneroTxWallet} this tx for chaining + */ + setChangeAddress(changeAddress) { + this.changeAddress = changeAddress; + return this; + } + + /** + * @return {bigint} change amount + */ + getChangeAmount() { + return this.changeAmount; + } + + /** + * @param {bigint} changeAmount - change amount + * @return {MoneroTxWallet} this tx for chaining + */ + setChangeAmount(changeAmount) { + this.changeAmount = changeAmount; + return this; + } + + /** + * @return {number} number of dummy outputs + */ + getNumDummyOutputs() { + return this.numDummyOutputs; + } + + /** + * @param {number} numDummyOutputs - number of dummy outputs + * @return {MoneroTxWallet} this tx for chaining + */ + setNumDummyOutputs(numDummyOutputs) { + this.numDummyOutputs = numDummyOutputs; + return this; + } + + /** + * @return {string} tx extra as hex + */ + getExtraHex() { + return this.extraHex; + } + + /** + * @param {string} extraHex - tx extra as hex + * @return {MoneroTxWallet} this tx for chaining + */ + setExtraHex(extraHex) { + this.extraHex = extraHex; + return this; + } + + /** + * @return {MoneroTxWallet} a copy of this tx + */ + copy() { + return new MoneroTxWallet(this); + } + + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * Merging can modify or build references to the transaction given so it + * should not be re-used or it should be copied before calling this method. + * + * @param {MoneroTxWallet} tx - the transaction to merge into this transaction + */ + merge(tx) { + (0, _assert.default)(tx instanceof MoneroTxWallet); + if (this === tx) return this; + + // merge base classes + super.merge(tx); + + // merge tx set if they're different which comes back to merging txs + //import MoneroTxSet from "./MoneroTxSet"; + if (this.getTxSet() !== tx.getTxSet()) { + if (this.getTxSet() == undefined) { + this.setTxSet(new _MoneroTxSet.default().setTxs([this])); + } + if (tx.getTxSet() === undefined) { + tx.setTxSet(new _MoneroTxSet.default().setTxs([tx])); + } + this.getTxSet().merge(tx.getTxSet()); + return this; + } + + // merge incoming transfers + if (tx.getIncomingTransfers()) { + if (this.getIncomingTransfers() === undefined) this.setIncomingTransfers([]); + for (let transfer of tx.getIncomingTransfers()) { + transfer.setTx(this); + MoneroTxWallet.mergeIncomingTransfer(this.getIncomingTransfers(), transfer); + } + } + + // merge outgoing transfer + if (tx.getOutgoingTransfer()) { + tx.getOutgoingTransfer().setTx(this); + if (this.getOutgoingTransfer() === undefined) this.setOutgoingTransfer(tx.getOutgoingTransfer());else + this.getOutgoingTransfer().merge(tx.getOutgoingTransfer()); + } + + // merge simple extensions + this.setIsIncoming(_GenUtils.default.reconcile(this.getIsIncoming(), tx.getIsIncoming(), { resolveTrue: true })); // outputs seen on confirmation + this.setIsOutgoing(_GenUtils.default.reconcile(this.getIsOutgoing(), tx.getIsOutgoing())); + this.setNote(_GenUtils.default.reconcile(this.getNote(), tx.getNote())); + this.setIsLocked(_GenUtils.default.reconcile(this.getIsLocked(), tx.getIsLocked(), { resolveTrue: false })); // tx can become unlocked + this.setInputSum(_GenUtils.default.reconcile(this.getInputSum(), tx.getInputSum())); + this.setOutputSum(_GenUtils.default.reconcile(this.getOutputSum(), tx.getOutputSum())); + this.setChangeAddress(_GenUtils.default.reconcile(this.getChangeAddress(), tx.getChangeAddress())); + this.setChangeAmount(_GenUtils.default.reconcile(this.getChangeAmount(), tx.getChangeAmount())); + this.setNumDummyOutputs(_GenUtils.default.reconcile(this.getNumDummyOutputs(), tx.getNumDummyOutputs())); + this.setExtraHex(_GenUtils.default.reconcile(this.getExtraHex(), tx.getExtraHex())); + + return this; // for chaining + } + + /** + * @param {number} [indent] - starting indentation + * @param {boolean} [oneLine] - string is one line if true, multiple lines if false + * @return {string} string representation of this tx + */ + toString(indent = 0, oneLine = false) { + let str = ""; + + // represent tx with one line string + // TODO: proper csv export + if (oneLine) { + str += this.getHash() + ", "; + str += (this.getIsConfirmed() ? this.getBlock().getTimestamp() : this.getReceivedTimestamp()) + ", "; + str += this.getIsConfirmed() + ", "; + str += (this.getOutgoingAmount() ? this.getOutgoingAmount().toString() : "") + ", "; + str += this.getIncomingAmount() ? this.getIncomingAmount().toString() : ""; + return str; + } + + // otherwise stringify all fields + str += super.toString(indent) + "\n"; + str += _GenUtils.default.kvLine("Is incoming", this.getIsIncoming(), indent); + str += _GenUtils.default.kvLine("Incoming amount", this.getIncomingAmount(), indent); + if (this.getIncomingTransfers() !== undefined) { + str += _GenUtils.default.kvLine("Incoming transfers", "", indent); + for (let i = 0; i < this.getIncomingTransfers().length; i++) { + str += _GenUtils.default.kvLine(i + 1, "", indent + 1); + str += this.getIncomingTransfers()[i].toString(indent + 2) + "\n"; + } + } + str += _GenUtils.default.kvLine("Is outgoing", this.getIsOutgoing(), indent); + str += _GenUtils.default.kvLine("Outgoing amount", this.getOutgoingAmount(), indent); + if (this.getOutgoingTransfer() !== undefined) { + str += _GenUtils.default.kvLine("Outgoing transfer", "", indent); + str += this.getOutgoingTransfer().toString(indent + 1) + "\n"; + } + str += _GenUtils.default.kvLine("Note", this.getNote(), indent); + str += _GenUtils.default.kvLine("Is locked", this.getIsLocked(), indent); + str += _GenUtils.default.kvLine("Input sum", this.getInputSum(), indent); + str += _GenUtils.default.kvLine("Output sum", this.getOutputSum(), indent); + str += _GenUtils.default.kvLine("Change address", this.getChangeAddress(), indent); + str += _GenUtils.default.kvLine("Change amount", this.getChangeAmount(), indent); + str += _GenUtils.default.kvLine("Num dummy outputs", this.getNumDummyOutputs(), indent); + str += _GenUtils.default.kvLine("Extra hex", this.getExtraHex(), indent); + return str.slice(0, str.length - 1); // strip last newline + } + + // private helper to merge transfers + static mergeIncomingTransfer(transfers, transfer) { + for (let aTransfer of transfers) { + if (aTransfer.getAccountIndex() === transfer.getAccountIndex() && aTransfer.getSubaddressIndex() === transfer.getSubaddressIndex()) { + aTransfer.merge(transfer); + return; + } + } + transfers.push(transfer); + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setBlock(block) { + super.setBlock(block); + return this; + } + + setHash(hash) { + super.setHash(hash); + return this; + } + + setVersion(version) { + super.setVersion(version); + return this; + } + + setIsMinerTx(isMinerTx) { + super.setIsMinerTx(isMinerTx); + return this; + } + + setPaymentId(paymentId) { + super.setPaymentId(paymentId); + return this; + } + + setFee(fee) { + super.setFee(fee); + return this; + } + + setRingSize(ringSize) { + super.setRingSize(ringSize); + return this; + } + + setRelay(relay) { + super.setRelay(relay); + return this; + } + + setIsRelayed(isRelayed) { + super.setIsRelayed(isRelayed); + return this; + } + + setIsConfirmed(isConfirmed) { + super.setIsConfirmed(isConfirmed); + return this; + } + + setInTxPool(inTxPool) { + super.setInTxPool(inTxPool); + return this; + } + + setNumConfirmations(numConfirmations) { + super.setNumConfirmations(numConfirmations); + return this; + } + + setUnlockTime(unlockTime) { + super.setUnlockTime(unlockTime); + return this; + } + + setLastRelayedTimestamp(lastRelayedTimestamp) { + super.setLastRelayedTimestamp(lastRelayedTimestamp); + return this; + } + + setReceivedTimestamp(receivedTimestamp) { + super.setReceivedTimestamp(receivedTimestamp); + return this; + } + + setIsDoubleSpendSeen(isDoubleSpendSeen) { + super.setIsDoubleSpendSeen(isDoubleSpendSeen); + return this; + } + + setKey(key) { + super.setKey(key); + return this; + } + + setFullHex(fullHex) { + super.setFullHex(fullHex); + return this; + } + + setPrunedHex(prunedHex) { + super.setPrunedHex(prunedHex); + return this; + } + + setPrunableHex(prunableHex) { + super.setPrunableHex(prunableHex); + return this; + } + + setPrunableHash(prunableHash) { + super.setPrunableHash(prunableHash); + return this; + } + + setSize(size) { + super.setSize(size); + return this; + } + + setWeight(weight) { + super.setWeight(weight); + return this; + } + + setInputs(inputs) { + super.setInputs(inputs); + return this; + } + + setOutputs(outputs) { + super.setOutputs(outputs); + return this; + } + + setOutputIndices(outputIndices) { + super.setOutputIndices(outputIndices); + return this; + } + + setMetadata(metadata) { + super.setMetadata(metadata); + return this; + } + + setExtra(extra) { + super.setExtra(extra); + return this; + } + + setRctSignatures(rctSignatures) { + super.setRctSignatures(rctSignatures); + return this; + } + + setRctSigPrunable(rctSigPrunable) { + super.setRctSigPrunable(rctSigPrunable); + return this; + } + + setIsKeptByBlock(isKeptByBlock) { + super.setIsKeptByBlock(isKeptByBlock); + return this; + } + + setIsFailed(isFailed) { + super.setIsFailed(isFailed); + return this; + } + + setLastFailedHeight(lastFailedHeight) { + super.setLastFailedHeight(lastFailedHeight); + return this; + } + + setLastFailedHash(lastFailedHash) { + super.setLastFailedHash(lastFailedHash); + return this; + } + + setMaxUsedBlockHeight(maxUsedBlockHeight) { + super.setMaxUsedBlockHeight(maxUsedBlockHeight); + return this; + } + + setMaxUsedBlockHash(maxUsedBlockHash) { + super.setMaxUsedBlockHash(maxUsedBlockHash); + return this; + } + + setSignatures(signatures) { + super.setSignatures(signatures); + return this; + } +}exports.default = MoneroTxWallet; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfYXNzZXJ0IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfR2VuVXRpbHMiLCJfTW9uZXJvRXJyb3IiLCJfTW9uZXJvSW5jb21pbmdUcmFuc2ZlciIsIl9Nb25lcm9PdXRnb2luZ1RyYW5zZmVyIiwiX01vbmVyb091dHB1dFdhbGxldCIsIl9Nb25lcm9UeCIsIl9Nb25lcm9UeFNldCIsIk1vbmVyb1R4V2FsbGV0IiwiTW9uZXJvVHgiLCJjb25zdHJ1Y3RvciIsInR4Iiwic2V0VHhTZXQiLCJnZXRUeFNldCIsImluY29taW5nVHJhbnNmZXJzIiwic2xpY2UiLCJpIiwibGVuZ3RoIiwiTW9uZXJvSW5jb21pbmdUcmFuc2ZlciIsInNldFR4Iiwib3V0Z29pbmdUcmFuc2ZlciIsIk1vbmVyb091dGdvaW5nVHJhbnNmZXIiLCJpbnB1dHMiLCJNb25lcm9PdXRwdXRXYWxsZXQiLCJvdXRwdXRzIiwiaW5wdXRTdW0iLCJ1bmRlZmluZWQiLCJCaWdJbnQiLCJvdXRwdXRTdW0iLCJjaGFuZ2VBbW91bnQiLCJ0b0pzb24iLCJqc29uIiwiT2JqZWN0IiwiYXNzaWduIiwiZ2V0SW5jb21pbmdUcmFuc2ZlcnMiLCJpbmNvbWluZ1RyYW5zZmVyIiwicHVzaCIsImdldE91dGdvaW5nVHJhbnNmZXIiLCJnZXRJbnB1dFN1bSIsInRvU3RyaW5nIiwiZ2V0T3V0cHV0U3VtIiwiZ2V0Q2hhbmdlQW1vdW50IiwiYmxvY2siLCJ0eFNldCIsImdldElzSW5jb21pbmciLCJpc0luY29taW5nIiwic2V0SXNJbmNvbWluZyIsImdldElzT3V0Z29pbmciLCJpc091dGdvaW5nIiwic2V0SXNPdXRnb2luZyIsImdldEluY29taW5nQW1vdW50IiwiaW5jb21pbmdBbXQiLCJ0cmFuc2ZlciIsImdldEFtb3VudCIsImdldE91dGdvaW5nQW1vdW50IiwiZ2V0VHJhbnNmZXJzIiwidHJhbnNmZXJRdWVyeSIsInRyYW5zZmVycyIsIm1lZXRzQ3JpdGVyaWEiLCJmaWx0ZXJUcmFuc2ZlcnMiLCJzZXRPdXRnb2luZ1RyYW5zZmVyIiwidG9SZW1vdmVzIiwic2V0SW5jb21pbmdUcmFuc2ZlcnMiLCJmaWx0ZXIiLCJpbmNsdWRlcyIsImdldElucHV0c1dhbGxldCIsIm91dHB1dFF1ZXJ5Iiwib3V0cHV0IiwiZ2V0SW5wdXRzIiwic2V0SW5wdXRzV2FsbGV0IiwiTW9uZXJvRXJyb3IiLCJzZXRJbnB1dHMiLCJnZXRPdXRwdXRzV2FsbGV0IiwiZ2V0T3V0cHV0cyIsInNldE91dHB1dHNXYWxsZXQiLCJzZXRPdXRwdXRzIiwiZmlsdGVyT3V0cHV0cyIsImdldE5vdGUiLCJub3RlIiwic2V0Tm90ZSIsImdldElzTG9ja2VkIiwiaXNMb2NrZWQiLCJzZXRJc0xvY2tlZCIsInNldElucHV0U3VtIiwic2V0T3V0cHV0U3VtIiwiZ2V0Q2hhbmdlQWRkcmVzcyIsImNoYW5nZUFkZHJlc3MiLCJzZXRDaGFuZ2VBZGRyZXNzIiwic2V0Q2hhbmdlQW1vdW50IiwiZ2V0TnVtRHVtbXlPdXRwdXRzIiwibnVtRHVtbXlPdXRwdXRzIiwic2V0TnVtRHVtbXlPdXRwdXRzIiwiZ2V0RXh0cmFIZXgiLCJleHRyYUhleCIsInNldEV4dHJhSGV4IiwiY29weSIsIm1lcmdlIiwiYXNzZXJ0IiwiTW9uZXJvVHhTZXQiLCJzZXRUeHMiLCJtZXJnZUluY29taW5nVHJhbnNmZXIiLCJHZW5VdGlscyIsInJlY29uY2lsZSIsInJlc29sdmVUcnVlIiwiaW5kZW50Iiwib25lTGluZSIsInN0ciIsImdldEhhc2giLCJnZXRJc0NvbmZpcm1lZCIsImdldEJsb2NrIiwiZ2V0VGltZXN0YW1wIiwiZ2V0UmVjZWl2ZWRUaW1lc3RhbXAiLCJrdkxpbmUiLCJhVHJhbnNmZXIiLCJnZXRBY2NvdW50SW5kZXgiLCJnZXRTdWJhZGRyZXNzSW5kZXgiLCJzZXRCbG9jayIsInNldEhhc2giLCJoYXNoIiwic2V0VmVyc2lvbiIsInZlcnNpb24iLCJzZXRJc01pbmVyVHgiLCJpc01pbmVyVHgiLCJzZXRQYXltZW50SWQiLCJwYXltZW50SWQiLCJzZXRGZWUiLCJmZWUiLCJzZXRSaW5nU2l6ZSIsInJpbmdTaXplIiwic2V0UmVsYXkiLCJyZWxheSIsInNldElzUmVsYXllZCIsImlzUmVsYXllZCIsInNldElzQ29uZmlybWVkIiwiaXNDb25maXJtZWQiLCJzZXRJblR4UG9vbCIsImluVHhQb29sIiwic2V0TnVtQ29uZmlybWF0aW9ucyIsIm51bUNvbmZpcm1hdGlvbnMiLCJzZXRVbmxvY2tUaW1lIiwidW5sb2NrVGltZSIsInNldExhc3RSZWxheWVkVGltZXN0YW1wIiwibGFzdFJlbGF5ZWRUaW1lc3RhbXAiLCJzZXRSZWNlaXZlZFRpbWVzdGFtcCIsInJlY2VpdmVkVGltZXN0YW1wIiwic2V0SXNEb3VibGVTcGVuZFNlZW4iLCJpc0RvdWJsZVNwZW5kU2VlbiIsInNldEtleSIsImtleSIsInNldEZ1bGxIZXgiLCJmdWxsSGV4Iiwic2V0UHJ1bmVkSGV4IiwicHJ1bmVkSGV4Iiwic2V0UHJ1bmFibGVIZXgiLCJwcnVuYWJsZUhleCIsInNldFBydW5hYmxlSGFzaCIsInBydW5hYmxlSGFzaCIsInNldFNpemUiLCJzaXplIiwic2V0V2VpZ2h0Iiwid2VpZ2h0Iiwic2V0T3V0cHV0SW5kaWNlcyIsIm91dHB1dEluZGljZXMiLCJzZXRNZXRhZGF0YSIsIm1ldGFkYXRhIiwic2V0RXh0cmEiLCJleHRyYSIsInNldFJjdFNpZ25hdHVyZXMiLCJyY3RTaWduYXR1cmVzIiwic2V0UmN0U2lnUHJ1bmFibGUiLCJyY3RTaWdQcnVuYWJsZSIsInNldElzS2VwdEJ5QmxvY2siLCJpc0tlcHRCeUJsb2NrIiwic2V0SXNGYWlsZWQiLCJpc0ZhaWxlZCIsInNldExhc3RGYWlsZWRIZWlnaHQiLCJsYXN0RmFpbGVkSGVpZ2h0Iiwic2V0TGFzdEZhaWxlZEhhc2giLCJsYXN0RmFpbGVkSGFzaCIsInNldE1heFVzZWRCbG9ja0hlaWdodCIsIm1heFVzZWRCbG9ja0hlaWdodCIsInNldE1heFVzZWRCbG9ja0hhc2giLCJtYXhVc2VkQmxvY2tIYXNoIiwic2V0U2lnbmF0dXJlcyIsInNpZ25hdHVyZXMiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9UeFdhbGxldC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCBHZW5VdGlscyBmcm9tIFwiLi4vLi4vY29tbW9uL0dlblV0aWxzXCI7XG5pbXBvcnQgTW9uZXJvQmxvY2sgZnJvbSBcIi4uLy4uL2RhZW1vbi9tb2RlbC9Nb25lcm9CbG9ja1wiO1xuaW1wb3J0IE1vbmVyb0Vycm9yIGZyb20gXCIuLi8uLi9jb21tb24vTW9uZXJvRXJyb3JcIjtcbmltcG9ydCBNb25lcm9JbmNvbWluZ1RyYW5zZmVyIGZyb20gXCIuL01vbmVyb0luY29taW5nVHJhbnNmZXJcIjtcbmltcG9ydCBNb25lcm9PdXRnb2luZ1RyYW5zZmVyIGZyb20gXCIuL01vbmVyb091dGdvaW5nVHJhbnNmZXJcIjtcbmltcG9ydCBNb25lcm9PdXRwdXRRdWVyeSBmcm9tIFwiLi9Nb25lcm9PdXRwdXRRdWVyeVwiO1xuaW1wb3J0IE1vbmVyb091dHB1dCBmcm9tIFwiLi4vLi4vZGFlbW9uL21vZGVsL01vbmVyb091dHB1dFwiO1xuaW1wb3J0IE1vbmVyb091dHB1dFdhbGxldCBmcm9tIFwiLi9Nb25lcm9PdXRwdXRXYWxsZXRcIjtcbmltcG9ydCBNb25lcm9UcmFuc2ZlciBmcm9tIFwiLi9Nb25lcm9UcmFuc2ZlclwiO1xuaW1wb3J0IE1vbmVyb1RyYW5zZmVyUXVlcnkgZnJvbSBcIi4vTW9uZXJvVHJhbnNmZXJRdWVyeVwiO1xuaW1wb3J0IE1vbmVyb1R4IGZyb20gXCIuLi8uLi9kYWVtb24vbW9kZWwvTW9uZXJvVHhcIjtcbmltcG9ydCBNb25lcm9UeFNldCBmcm9tIFwiLi9Nb25lcm9UeFNldFwiO1xuXG4vKipcbiAqIE1vZGVscyBhIE1vbmVybyB0cmFuc2FjdGlvbiB3aXRoIHdhbGxldCBleHRlbnNpb25zLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9UeFdhbGxldCBleHRlbmRzIE1vbmVyb1R4IHtcblxuICB0eFNldDogTW9uZXJvVHhTZXQ7XG4gIGlzSW5jb21pbmc6IGJvb2xlYW47XG4gIGlzT3V0Z29pbmc6IGJvb2xlYW47XG4gIGluY29taW5nVHJhbnNmZXJzOiBNb25lcm9JbmNvbWluZ1RyYW5zZmVyW107XG4gIG91dGdvaW5nVHJhbnNmZXI6IE1vbmVyb091dGdvaW5nVHJhbnNmZXI7XG4gIG5vdGU6IHN0cmluZztcbiAgaXNMb2NrZWQ6IGJvb2xlYW47XG4gIGlucHV0U3VtOiBiaWdpbnQ7XG4gIG91dHB1dFN1bTogYmlnaW50O1xuICBjaGFuZ2VBZGRyZXNzOiBzdHJpbmc7XG4gIGNoYW5nZUFtb3VudDogYmlnaW50O1xuICBudW1EdW1teU91dHB1dHM6IG51bWJlcjtcbiAgZXh0cmFIZXg6IHN0cmluZztcbiAgXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3QgdGhlIG1vZGVsLlxuICAgKiBcbiAgICogQHBhcmFtIHtQYXJ0aWFsPE1vbmVyb1R4V2FsbGV0Pn0gW3R4XSBpcyBleGlzdGluZyBzdGF0ZSB0byBpbml0aWFsaXplIGZyb20gKG9wdGlvbmFsKVxuICAgKi9cbiAgY29uc3RydWN0b3IodHg/OiBQYXJ0aWFsPE1vbmVyb1R4V2FsbGV0Pikge1xuICAgIHN1cGVyKHR4KTtcbiAgICB0aGlzLnNldFR4U2V0KHRoaXMuZ2V0VHhTZXQoKSk7IC8vIHByZXNlcnZlIHJlZmVyZW5jZSB0byB0eCBzZXRcbiAgICBcbiAgICAvLyBjb3B5IGluY29taW5nIHRyYW5zZmVyc1xuICAgIGlmICh0aGlzLmluY29taW5nVHJhbnNmZXJzKSB7XG4gICAgICB0aGlzLmluY29taW5nVHJhbnNmZXJzID0gdGhpcy5pbmNvbWluZ1RyYW5zZmVycy5zbGljZSgpO1xuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmluY29taW5nVHJhbnNmZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRoaXMuaW5jb21pbmdUcmFuc2ZlcnNbaV0gPSBuZXcgTW9uZXJvSW5jb21pbmdUcmFuc2Zlcih0aGlzLmluY29taW5nVHJhbnNmZXJzW2ldKS5zZXRUeCh0aGlzKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gY29weSBvdXRnb2luZyB0cmFuc2ZlclxuICAgIGlmICh0aGlzLm91dGdvaW5nVHJhbnNmZXIpIHtcbiAgICAgIHRoaXMub3V0Z29pbmdUcmFuc2ZlciA9IG5ldyBNb25lcm9PdXRnb2luZ1RyYW5zZmVyKHRoaXMub3V0Z29pbmdUcmFuc2Zlcikuc2V0VHgodGhpcyk7XG4gICAgfVxuICAgIFxuICAgIC8vIGNvcHkgaW5wdXRzXG4gICAgaWYgKHRoaXMuaW5wdXRzKSB7XG4gICAgICB0aGlzLmlucHV0cyA9IHRoaXMuaW5wdXRzLnNsaWNlKCk7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuaW5wdXRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRoaXMuaW5wdXRzW2ldID0gbmV3IE1vbmVyb091dHB1dFdhbGxldCh0aGlzLmlucHV0c1tpXSBhcyBNb25lcm9PdXRwdXRXYWxsZXQpLnNldFR4KHRoaXMpO1xuICAgICAgfVxuICAgIH1cbiAgICBcbiAgICAvLyBjb3B5IG91dHB1dHNcbiAgICBpZiAodGhpcy5vdXRwdXRzKSB7XG4gICAgICB0aGlzLm91dHB1dHMgPSB0aGlzLm91dHB1dHMuc2xpY2UoKTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5vdXRwdXRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRoaXMub3V0cHV0c1tpXSA9IG5ldyBNb25lcm9PdXRwdXRXYWxsZXQodGhpcy5vdXRwdXRzW2ldIGFzIE1vbmVyb091dHB1dFdhbGxldCkuc2V0VHgodGhpcyk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIGRlc2VyaWFsaXplIGJpZ2ludHNcbiAgICBpZiAodGhpcy5pbnB1dFN1bSAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLmlucHV0U3VtICE9PSBcImJpZ2ludFwiKSB0aGlzLmlucHV0U3VtID0gQmlnSW50KHRoaXMuaW5wdXRTdW0pO1xuICAgIGlmICh0aGlzLm91dHB1dFN1bSAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLm91dHB1dFN1bSAhPT0gXCJiaWdpbnRcIikgdGhpcy5vdXRwdXRTdW0gPSBCaWdJbnQodGhpcy5vdXRwdXRTdW0pO1xuICAgIGlmICh0aGlzLmNoYW5nZUFtb3VudCAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0aGlzLmNoYW5nZUFtb3VudCAhPT0gXCJiaWdpbnRcIikgdGhpcy5jaGFuZ2VBbW91bnQgPSBCaWdJbnQodGhpcy5jaGFuZ2VBbW91bnQpO1xuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7YW55fSBqc29uIHJlcHJlc2VudGF0aW9uIG9mIHRoaXMgdHhcbiAgICovXG4gIHRvSnNvbigpOiBhbnkge1xuICAgIGxldCBqc29uID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcywgc3VwZXIudG9Kc29uKCkpOyAvLyBtZXJnZSBqc29uIG9udG8gaW5oZXJpdGVkIHN0YXRlXG4gICAgaWYgKHRoaXMuZ2V0SW5jb21pbmdUcmFuc2ZlcnMoKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBqc29uLmluY29taW5nVHJhbnNmZXJzID0gW107XG4gICAgICBmb3IgKGxldCBpbmNvbWluZ1RyYW5zZmVyIG9mIHRoaXMuZ2V0SW5jb21pbmdUcmFuc2ZlcnMoKSkganNvbi5pbmNvbWluZ1RyYW5zZmVycy5wdXNoKGluY29taW5nVHJhbnNmZXIudG9Kc29uKCkpO1xuICAgIH1cbiAgICBpZiAodGhpcy5nZXRPdXRnb2luZ1RyYW5zZmVyKCkgIT09IHVuZGVmaW5lZCkganNvbi5vdXRnb2luZ1RyYW5zZmVyID0gdGhpcy5nZXRPdXRnb2luZ1RyYW5zZmVyKCkudG9Kc29uKCk7XG4gICAgaWYgKHRoaXMuZ2V0SW5wdXRTdW0oKSAhPT0gdW5kZWZpbmVkKSBqc29uLmlucHV0U3VtID0gdGhpcy5nZXRJbnB1dFN1bSgpLnRvU3RyaW5nKCk7XG4gICAgaWYgKHRoaXMuZ2V0T3V0cHV0U3VtKCkgIT09IHVuZGVmaW5lZCkganNvbi5vdXRwdXRTdW0gPSB0aGlzLmdldE91dHB1dFN1bSgpLnRvU3RyaW5nKCk7XG4gICAgaWYgKHRoaXMuZ2V0Q2hhbmdlQW1vdW50KCkgIT09IHVuZGVmaW5lZCkganNvbi5jaGFuZ2VBbW91bnQgPSB0aGlzLmdldENoYW5nZUFtb3VudCgpLnRvU3RyaW5nKCk7XG4gICAgZGVsZXRlIGpzb24uYmxvY2s7ICAvLyBkbyBub3Qgc2VyaWFsaXplIHBhcmVudCBibG9ja1xuICAgIGRlbGV0ZSBqc29uLnR4U2V0OyAgLy8gZG8gbm90IHNlcmlhbGl6ZSBwYXJlbnQgdHggc2V0XG4gICAgcmV0dXJuIGpzb247XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtNb25lcm9UeFNldH0gdHggc2V0IGNvbnRhaW5pbmcgdHhzXG4gICAqL1xuICBnZXRUeFNldCgpOiBNb25lcm9UeFNldCB7XG4gICAgcmV0dXJuIHRoaXMudHhTZXQ7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtNb25lcm9UeFNldH0gdHhTZXQgLSB0eCBzZXQgY29udGFpbmluZyB0eHNcbiAgICogQHJldHVybiB7TW9uZXJvVHhXYWxsZXR9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRUeFNldCh0eFNldDogTW9uZXJvVHhTZXQpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgdGhpcy50eFNldCA9IHR4U2V0O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IHRydWUgaWYgdGhlIHR4IGhhcyBpbmNvbWluZyBmdW5kcywgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICBnZXRJc0luY29taW5nKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzSW5jb21pbmc7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtib29sZWFufSBpc0luY29taW5nIC0gdHJ1ZSBpZiB0aGUgdHggaGFzIGluY29taW5nIGZ1bmRzLCBmYWxzZSBvdGhlcndpc2VcbiAgICogQHJldHVybiB7TW9uZXJvVHhXYWxsZXR9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRJc0luY29taW5nKGlzSW5jb21pbmc6IGJvb2xlYW4pOiBNb25lcm9UeFdhbGxldCB7XG4gICAgdGhpcy5pc0luY29taW5nID0gaXNJbmNvbWluZztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtib29sZWFufSB0cnVlIGlmIHRoZSB0eCBoYXMgb3V0Z29pbmcgZnVuZHMsIGZhbHNlIG90aGVyd2lzZVxuICAgKi9cbiAgZ2V0SXNPdXRnb2luZygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5pc091dGdvaW5nO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gaXNPdXRnb2luZyAtIHRydWUgaWYgdGhlIHR4IGhhcyBvdXRnb2luZyBmdW5kcywgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqIEByZXR1cm4ge01vbmVyb1R4V2FsbGV0fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0SXNPdXRnb2luZyhpc091dGdvaW5nOiBib29sZWFuKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHRoaXMuaXNPdXRnb2luZyA9IGlzT3V0Z29pbmc7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQHJldHVybiB7YmlnaW50fSBhbW91bnQgcmVjZWl2ZWQgaW4gdGhlIHR4XG4gICAqL1xuICBnZXRJbmNvbWluZ0Ftb3VudCgpOiBiaWdpbnQge1xuICAgIGlmICh0aGlzLmdldEluY29taW5nVHJhbnNmZXJzKCkgPT09IHVuZGVmaW5lZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICBsZXQgaW5jb21pbmdBbXQgPSAwbjtcbiAgICBmb3IgKGxldCB0cmFuc2ZlciBvZiB0aGlzLmdldEluY29taW5nVHJhbnNmZXJzKCkpIGluY29taW5nQW10ID0gaW5jb21pbmdBbXQgKyB0cmFuc2Zlci5nZXRBbW91bnQoKTtcbiAgICByZXR1cm4gaW5jb21pbmdBbXQ7XG4gIH1cblxuICAvKipcbiAgICogQHJldHVybiB7YmlnaW50fSBhbW91bnQgc3BlbnQgaW4gdGhlIHR4XG4gICAqL1xuICBnZXRPdXRnb2luZ0Ftb3VudCgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLmdldE91dGdvaW5nVHJhbnNmZXIoKSA/IHRoaXMuZ2V0T3V0Z29pbmdUcmFuc2ZlcigpLmdldEFtb3VudCgpIDogdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7TW9uZXJvVHJhbnNmZXJRdWVyeX0gW3RyYW5zZmVyUXVlcnldIC0gcXVlcnkgdG8gZ2V0IHNwZWNpZmljIHRyYW5zZmVyc1xuICAgKiBAcmV0dXJuIHtNb25lcm9UcmFuc2ZlcltdfSB0cmFuc2ZlcnMgbWF0Y2hpbmcgdGhlIHF1ZXJ5XG4gICAqL1xuICBnZXRUcmFuc2ZlcnModHJhbnNmZXJRdWVyeT86IE1vbmVyb1RyYW5zZmVyUXVlcnkpOiBNb25lcm9UcmFuc2ZlcltdIHtcbiAgICBsZXQgdHJhbnNmZXJzID0gW107XG4gICAgaWYgKHRoaXMuZ2V0T3V0Z29pbmdUcmFuc2ZlcigpICYmICghdHJhbnNmZXJRdWVyeSB8fCB0cmFuc2ZlclF1ZXJ5Lm1lZXRzQ3JpdGVyaWEodGhpcy5nZXRPdXRnb2luZ1RyYW5zZmVyKCkpKSkgdHJhbnNmZXJzLnB1c2godGhpcy5nZXRPdXRnb2luZ1RyYW5zZmVyKCkpO1xuICAgIGlmICh0aGlzLmdldEluY29taW5nVHJhbnNmZXJzKCkgIT09IHVuZGVmaW5lZCkge1xuICAgICAgZm9yIChsZXQgdHJhbnNmZXIgb2YgdGhpcy5nZXRJbmNvbWluZ1RyYW5zZmVycygpKSB7XG4gICAgICAgIGlmICghdHJhbnNmZXJRdWVyeSB8fCB0cmFuc2ZlclF1ZXJ5Lm1lZXRzQ3JpdGVyaWEodHJhbnNmZXIpKSB0cmFuc2ZlcnMucHVzaCh0cmFuc2Zlcik7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cmFuc2ZlcnM7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtNb25lcm9UcmFuc2ZlclF1ZXJ5fSB0cmFuc2ZlclF1ZXJ5IC0gcXVlcnkgdG8ga2VlcCBvbmx5IHNwZWNpZmljIHRyYW5zZmVyc1xuICAgKiBAcmV0dXJuIHtNb25lcm9UcmFuc2ZlcltdfSByZW1haW5pbmcgdHJhbnNmZXJzIG1hdGNoaW5nIHRoZSBxdWVyeVxuICAgKi9cbiAgZmlsdGVyVHJhbnNmZXJzKHRyYW5zZmVyUXVlcnk6IE1vbmVyb1RyYW5zZmVyUXVlcnkpOiBNb25lcm9UcmFuc2ZlcltdIHtcbiAgICBsZXQgdHJhbnNmZXJzID0gW107XG4gICAgXG4gICAgLy8gY29sbGVjdCBvdXRnb2luZyB0cmFuc2ZlciBvciBlcmFzZSBpZiBmaWx0ZXJlZFxuICAgIGlmICh0aGlzLmdldE91dGdvaW5nVHJhbnNmZXIoKSAmJiAoIXRyYW5zZmVyUXVlcnkgfHwgdHJhbnNmZXJRdWVyeS5tZWV0c0NyaXRlcmlhKHRoaXMuZ2V0T3V0Z29pbmdUcmFuc2ZlcigpKSkpIHRyYW5zZmVycy5wdXNoKHRoaXMuZ2V0T3V0Z29pbmdUcmFuc2ZlcigpKTtcbiAgICBlbHNlIHRoaXMuc2V0T3V0Z29pbmdUcmFuc2Zlcih1bmRlZmluZWQpO1xuICAgIFxuICAgIC8vIGNvbGxlY3QgaW5jb21pbmcgdHJhbnNmZXJzIG9yIGVyYXNlIGlmIGZpbHRlcmVkXG4gICAgaWYgKHRoaXMuZ2V0SW5jb21pbmdUcmFuc2ZlcnMoKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBsZXQgdG9SZW1vdmVzID0gW107XG4gICAgICBmb3IgKGxldCB0cmFuc2ZlciBvZiB0aGlzLmdldEluY29taW5nVHJhbnNmZXJzKCkpIHtcbiAgICAgICAgaWYgKHRyYW5zZmVyUXVlcnkubWVldHNDcml0ZXJpYSh0cmFuc2ZlcikpIHRyYW5zZmVycy5wdXNoKHRyYW5zZmVyKTtcbiAgICAgICAgZWxzZSB0b1JlbW92ZXMucHVzaCh0cmFuc2Zlcik7XG4gICAgICB9XG4gICAgICB0aGlzLnNldEluY29taW5nVHJhbnNmZXJzKHRoaXMuZ2V0SW5jb21pbmdUcmFuc2ZlcnMoKS5maWx0ZXIoZnVuY3Rpb24odHJhbnNmZXIpIHtcbiAgICAgICAgcmV0dXJuICF0b1JlbW92ZXMuaW5jbHVkZXModHJhbnNmZXIpO1xuICAgICAgfSkpO1xuICAgICAgaWYgKHRoaXMuZ2V0SW5jb21pbmdUcmFuc2ZlcnMoKS5sZW5ndGggPT09IDApIHRoaXMuc2V0SW5jb21pbmdUcmFuc2ZlcnModW5kZWZpbmVkKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHRyYW5zZmVycztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEByZXR1cm4ge01vbmVyb0luY29taW5nVHJhbnNmZXJbXX0gaW5jb21pbmcgdHJhbnNmZXJzXG4gICAqL1xuICBnZXRJbmNvbWluZ1RyYW5zZmVycygpOiBNb25lcm9JbmNvbWluZ1RyYW5zZmVyW10ge1xuICAgIHJldHVybiB0aGlzLmluY29taW5nVHJhbnNmZXJzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtNb25lcm9JbmNvbWluZ1RyYW5zZmVyW119IGluY29taW5nVHJhbnNmZXJzIC0gaW5jb21pbmcgdHJhbnNmZXJzXG4gICAqIEByZXR1cm4ge01vbmVyb1R4V2FsbGV0fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0SW5jb21pbmdUcmFuc2ZlcnMoaW5jb21pbmdUcmFuc2ZlcnM6IE1vbmVyb0luY29taW5nVHJhbnNmZXJbXSk6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICB0aGlzLmluY29taW5nVHJhbnNmZXJzID0gaW5jb21pbmdUcmFuc2ZlcnM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtNb25lcm9PdXRnb2luZ1RyYW5zZmVyfSBvdXRnb2luZyB0cmFuc2ZlcnNcbiAgICovXG4gIGdldE91dGdvaW5nVHJhbnNmZXIoKTogTW9uZXJvT3V0Z29pbmdUcmFuc2ZlciB7XG4gICAgcmV0dXJuIHRoaXMub3V0Z29pbmdUcmFuc2ZlcjtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBwYXJhbSB7TW9uZXJvT3V0Z29pbmdUcmFuc2Zlcn0gb3V0Z29pbmdUcmFuc2ZlciAtIG91dGdvaW5nIHRyYW5zZmVyXG4gICAqIEByZXR1cm4ge01vbmVyb1R4V2FsbGV0fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0T3V0Z29pbmdUcmFuc2ZlcihvdXRnb2luZ1RyYW5zZmVyOiBNb25lcm9PdXRnb2luZ1RyYW5zZmVyKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHRoaXMub3V0Z29pbmdUcmFuc2ZlciA9IG91dGdvaW5nVHJhbnNmZXI7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtNb25lcm9PdXRwdXRXYWxsZXRbXX0gb3V0cHV0UXVlcnkgLSBxdWVyeSB0byBnZXQgc3BlY2lmaWMgaW5wdXRzXG4gICAqIEByZXR1cm4ge01vbmVyb091dHB1dFdhbGxldFtdfSBpbnB1dHMgbWF0Y2hpbmcgdGhlIHF1ZXJ5XG4gICAqL1xuICBnZXRJbnB1dHNXYWxsZXQob3V0cHV0UXVlcnk/OiBNb25lcm9PdXRwdXRRdWVyeSk6IE1vbmVyb091dHB1dFdhbGxldFtdIHtcbiAgICBsZXQgaW5wdXRzOiBNb25lcm9PdXRwdXRXYWxsZXRbXSA9IFtdO1xuICAgIGZvciAobGV0IG91dHB1dCBvZiBzdXBlci5nZXRJbnB1dHMoKSkgaWYgKCFvdXRwdXRRdWVyeSB8fCBvdXRwdXRRdWVyeS5tZWV0c0NyaXRlcmlhKG91dHB1dCBhcyBNb25lcm9PdXRwdXRXYWxsZXQpKSBpbnB1dHMucHVzaChvdXRwdXQgYXMgTW9uZXJvT3V0cHV0V2FsbGV0KTtcbiAgICByZXR1cm4gaW5wdXRzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7TW9uZXJvT3V0cHV0V2FsbGV0W119IGlucHV0cyAtIHR4IGlucHV0c1xuICAgKiBAcmV0dXJuIHtNb25lcm9UeFdhbGxldH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldElucHV0c1dhbGxldChpbnB1dHM6IE1vbmVyb091dHB1dFdhbGxldFtdKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIFxuICAgIC8vIHZhbGlkYXRlIHRoYXQgYWxsIGlucHV0cyBhcmUgd2FsbGV0IGlucHV0c1xuICAgIGlmIChpbnB1dHMpIHtcbiAgICAgIGZvciAobGV0IG91dHB1dCBvZiBpbnB1dHMpIHtcbiAgICAgICAgaWYgKCEob3V0cHV0IGluc3RhbmNlb2YgTW9uZXJvT3V0cHV0V2FsbGV0KSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiV2FsbGV0IHRyYW5zYWN0aW9uIGlucHV0cyBtdXN0IGJlIG9mIHR5cGUgTW9uZXJvT3V0cHV0V2FsbGV0XCIpO1xuICAgICAgfVxuICAgIH1cbiAgICBzdXBlci5zZXRJbnB1dHMoaW5wdXRzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBwYXJhbSB7TW9uZXJvT3V0cHV0UXVlcnl9IFtvdXRwdXRRdWVyeV0gLSBxdWVyeSB0byBnZXQgc3BlY2lmaWMgb3V0cHV0c1xuICAgKiBAcmV0dXJuIHtNb25lcm9PdXRwdXRXYWxsZXRbXX0gb3V0cHV0cyBtYXRjaGluZyB0aGUgcXVlcnlcbiAgICovXG4gIGdldE91dHB1dHNXYWxsZXQob3V0cHV0UXVlcnk/OiBNb25lcm9PdXRwdXRRdWVyeSk6IE1vbmVyb091dHB1dFdhbGxldFtdIHtcbiAgICBsZXQgb3V0cHV0cyA9IFtdO1xuICAgIGZvciAobGV0IG91dHB1dCBvZiBzdXBlci5nZXRPdXRwdXRzKCkpIGlmICghb3V0cHV0UXVlcnkgfHwgb3V0cHV0UXVlcnkubWVldHNDcml0ZXJpYShvdXRwdXQgYXMgTW9uZXJvT3V0cHV0V2FsbGV0KSkgb3V0cHV0cy5wdXNoKG91dHB1dCk7XG4gICAgcmV0dXJuIG91dHB1dHM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge01vbmVyb091dHB1dFdhbGxldFtdfSBvdXRwdXRzIC0gdHggb3V0cHV0c1xuICAgKiBAcmV0dXJuIHtNb25lcm9UeFdhbGxldH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldE91dHB1dHNXYWxsZXQob3V0cHV0czogTW9uZXJvT3V0cHV0V2FsbGV0W10pOiBNb25lcm9UeFdhbGxldCB7XG4gICAgXG4gICAgLy8gdmFsaWRhdGUgdGhhdCBhbGwgb3V0cHV0cyBhcmUgd2FsbGV0IG91dHB1dHNcbiAgICBpZiAob3V0cHV0cykge1xuICAgICAgZm9yIChsZXQgb3V0cHV0IG9mIG91dHB1dHMpIHtcbiAgICAgICAgaWYgKCEob3V0cHV0IGluc3RhbmNlb2YgTW9uZXJvT3V0cHV0V2FsbGV0KSkgdGhyb3cgbmV3IE1vbmVyb0Vycm9yKFwiV2FsbGV0IHRyYW5zYWN0aW9uIG91dHB1dHMgbXVzdCBiZSBvZiB0eXBlIE1vbmVyb091dHB1dFdhbGxldFwiKTtcbiAgICAgIH1cbiAgICB9XG4gICAgc3VwZXIuc2V0T3V0cHV0cyhvdXRwdXRzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBwYXJhbSB7TW9uZXJvT3V0cHV0UXVlcnl9IG91dHB1dFF1ZXJ5IC0gcXVlcnkgdG8ga2VlcCBvbmx5IHNwZWNpZmljIG91dHB1dHNcbiAgICogQHJldHVybiB7TW9uZXJvVHJhbnNmZXJbXX0gcmVtYWluaW5nIG91dHB1dHMgbWF0Y2hpbmcgdGhlIHF1ZXJ5XG4gICAqL1xuICBmaWx0ZXJPdXRwdXRzKG91dHB1dFF1ZXJ5OiBNb25lcm9PdXRwdXRRdWVyeSk6IE1vbmVyb1RyYW5zZmVyW10ge1xuICAgIGxldCBvdXRwdXRzID0gW107XG4gICAgaWYgKHN1cGVyLmdldE91dHB1dHMoKSkge1xuICAgICAgbGV0IHRvUmVtb3ZlcyA9IFtdO1xuICAgICAgZm9yIChsZXQgb3V0cHV0IG9mIHN1cGVyLmdldE91dHB1dHMoKSkge1xuICAgICAgICBpZiAoIW91dHB1dFF1ZXJ5IHx8IG91dHB1dFF1ZXJ5Lm1lZXRzQ3JpdGVyaWEob3V0cHV0IGFzIE1vbmVyb091dHB1dFdhbGxldCkpIG91dHB1dHMucHVzaChvdXRwdXQpO1xuICAgICAgICBlbHNlIHRvUmVtb3Zlcy5wdXNoKG91dHB1dCk7XG4gICAgICB9XG4gICAgICB0aGlzLnNldE91dHB1dHMoc3VwZXIuZ2V0T3V0cHV0cygpLmZpbHRlcihmdW5jdGlvbihvdXRwdXQpIHtcbiAgICAgICAgcmV0dXJuICF0b1JlbW92ZXMuaW5jbHVkZXMob3V0cHV0KTtcbiAgICAgIH0pKTtcbiAgICAgIGlmICh0aGlzLmdldE91dHB1dHMoKS5sZW5ndGggPT09IDApIHRoaXMuc2V0T3V0cHV0cyh1bmRlZmluZWQpO1xuICAgIH1cbiAgICByZXR1cm4gb3V0cHV0cztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEByZXR1cm4ge3N0cmluZ30gdHggbm90ZVxuICAgKi9cbiAgZ2V0Tm90ZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLm5vdGU7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbm90ZSAtIHR4IG5vdGVcbiAgICogQHJldHVybiB7TW9uZXJvVHhXYWxsZXR9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXROb3RlKG5vdGU6IHN0cmluZyk6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICB0aGlzLm5vdGUgPSBub3RlO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gdHJ1ZSBpZiB0aGUgdHggaXMgbG9ja2VkLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIGdldElzTG9ja2VkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzTG9ja2VkO1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtib29sZWFufSBpc0xvY2tlZCAtIHRydWUgaWYgdGhlIHR4IGlzIGxvY2tlZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqIEByZXR1cm4ge01vbmVyb1R4V2FsbGV0fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0SXNMb2NrZWQoaXNMb2NrZWQ6IGJvb2xlYW4pOiBNb25lcm9UeFdhbGxldCB7XG4gICAgdGhpcy5pc0xvY2tlZCA9IGlzTG9ja2VkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7YmlnaW50fSBzdW0gb2YgdHggaW5wdXRzXG4gICAqL1xuICBnZXRJbnB1dFN1bSgpOiBiaWdpbnQge1xuICAgIHJldHVybiB0aGlzLmlucHV0U3VtO1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtiaWdpbnR9IGlucHV0U3VtIC0gc3VtIG9mIHR4IGlucHV0c1xuICAgKiBAcmV0dXJuIHtNb25lcm9UeFdhbGxldH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldElucHV0U3VtKGlucHV0U3VtOiBiaWdpbnQpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgdGhpcy5pbnB1dFN1bSA9IGlucHV0U3VtO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7YmlnaW50fSBzdW0gb2YgdHggb3V0cHV0c1xuICAgKi9cbiAgZ2V0T3V0cHV0U3VtKCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMub3V0cHV0U3VtO1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtiaWdpbnR9IG91dHB1dFN1bSAtIHN1bSBvZiB0eCBvdXRwdXRzXG4gICAqIEByZXR1cm4ge01vbmVyb1R4V2FsbGV0fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0T3V0cHV0U3VtKG91dHB1dFN1bTogYmlnaW50KTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHRoaXMub3V0cHV0U3VtID0gb3V0cHV0U3VtO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7c3RyaW5nfSBjaGFuZ2UgYWRkcmVzc1xuICAgKi9cbiAgZ2V0Q2hhbmdlQWRkcmVzcygpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLmNoYW5nZUFkZHJlc3M7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gY2hhbmdlQWRkcmVzcyAtIGNoYW5nZSBhZGRyZXNzXG4gICAqIEByZXR1cm4ge01vbmVyb1R4V2FsbGV0fSB0aGlzIHR4IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgc2V0Q2hhbmdlQWRkcmVzcyhjaGFuZ2VBZGRyZXNzOiBzdHJpbmcpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgdGhpcy5jaGFuZ2VBZGRyZXNzID0gY2hhbmdlQWRkcmVzcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIEByZXR1cm4ge2JpZ2ludH0gY2hhbmdlIGFtb3VudFxuICAgKi9cbiAgZ2V0Q2hhbmdlQW1vdW50KCk6IGJpZ2ludCB7XG4gICAgcmV0dXJuIHRoaXMuY2hhbmdlQW1vdW50O1xuICB9XG4gIFxuICAvKipcbiAgICogQHBhcmFtIHtiaWdpbnR9IGNoYW5nZUFtb3VudCAtIGNoYW5nZSBhbW91bnRcbiAgICogQHJldHVybiB7TW9uZXJvVHhXYWxsZXR9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXRDaGFuZ2VBbW91bnQoY2hhbmdlQW1vdW50OiBiaWdpbnQpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgdGhpcy5jaGFuZ2VBbW91bnQgPSBjaGFuZ2VBbW91bnQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtudW1iZXJ9IG51bWJlciBvZiBkdW1teSBvdXRwdXRzXG4gICAqL1xuICBnZXROdW1EdW1teU91dHB1dHMoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5udW1EdW1teU91dHB1dHM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlcn0gbnVtRHVtbXlPdXRwdXRzIC0gbnVtYmVyIG9mIGR1bW15IG91dHB1dHNcbiAgICogQHJldHVybiB7TW9uZXJvVHhXYWxsZXR9IHRoaXMgdHggZm9yIGNoYWluaW5nXG4gICAqL1xuICBzZXROdW1EdW1teU91dHB1dHMobnVtRHVtbXlPdXRwdXRzOiBudW1iZXIpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgdGhpcy5udW1EdW1teU91dHB1dHMgPSBudW1EdW1teU91dHB1dHM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IHR4IGV4dHJhIGFzIGhleFxuICAgKi9cbiAgZ2V0RXh0cmFIZXgoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5leHRyYUhleDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBleHRyYUhleCAtIHR4IGV4dHJhIGFzIGhleFxuICAgKiBAcmV0dXJuIHtNb25lcm9UeFdhbGxldH0gdGhpcyB0eCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHNldEV4dHJhSGV4KGV4dHJhSGV4OiBzdHJpbmcpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgdGhpcy5leHRyYUhleCA9IGV4dHJhSGV4O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICAvKipcbiAgICogQHJldHVybiB7TW9uZXJvVHhXYWxsZXR9IGEgY29weSBvZiB0aGlzIHR4XG4gICAqL1xuICBjb3B5KCk6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICByZXR1cm4gbmV3IE1vbmVyb1R4V2FsbGV0KHRoaXMpO1xuICB9XG4gIFxuICAvKipcbiAgICogVXBkYXRlcyB0aGlzIHRyYW5zYWN0aW9uIGJ5IG1lcmdpbmcgdGhlIGxhdGVzdCBpbmZvcm1hdGlvbiBmcm9tIHRoZSBnaXZlblxuICAgKiB0cmFuc2FjdGlvbi5cbiAgICogXG4gICAqIE1lcmdpbmcgY2FuIG1vZGlmeSBvciBidWlsZCByZWZlcmVuY2VzIHRvIHRoZSB0cmFuc2FjdGlvbiBnaXZlbiBzbyBpdFxuICAgKiBzaG91bGQgbm90IGJlIHJlLXVzZWQgb3IgaXQgc2hvdWxkIGJlIGNvcGllZCBiZWZvcmUgY2FsbGluZyB0aGlzIG1ldGhvZC5cbiAgICogXG4gICAqIEBwYXJhbSB7TW9uZXJvVHhXYWxsZXR9IHR4IC0gdGhlIHRyYW5zYWN0aW9uIHRvIG1lcmdlIGludG8gdGhpcyB0cmFuc2FjdGlvblxuICAgKi9cbiAgbWVyZ2UodHg6IE1vbmVyb1R4V2FsbGV0KTogTW9uZXJvVHhXYWxsZXQge1xuICAgIGFzc2VydCh0eCBpbnN0YW5jZW9mIE1vbmVyb1R4V2FsbGV0KTtcbiAgICBpZiAodGhpcyA9PT0gdHgpIHJldHVybiB0aGlzO1xuICAgIFxuICAgIC8vIG1lcmdlIGJhc2UgY2xhc3Nlc1xuICAgIHN1cGVyLm1lcmdlKHR4KTtcbiAgICBcbiAgICAvLyBtZXJnZSB0eCBzZXQgaWYgdGhleSdyZSBkaWZmZXJlbnQgd2hpY2ggY29tZXMgYmFjayB0byBtZXJnaW5nIHR4c1xuICAgIC8vaW1wb3J0IE1vbmVyb1R4U2V0IGZyb20gXCIuL01vbmVyb1R4U2V0XCI7XG4gICAgaWYgKHRoaXMuZ2V0VHhTZXQoKSAhPT0gdHguZ2V0VHhTZXQoKSkge1xuICAgICAgaWYgKHRoaXMuZ2V0VHhTZXQoKSA9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5zZXRUeFNldChuZXcgTW9uZXJvVHhTZXQoKS5zZXRUeHMoW3RoaXNdKSk7XG4gICAgICB9XG4gICAgICBpZiAodHguZ2V0VHhTZXQoKSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHR4LnNldFR4U2V0KG5ldyBNb25lcm9UeFNldCgpLnNldFR4cyhbdHhdKSk7XG4gICAgICB9XG4gICAgICB0aGlzLmdldFR4U2V0KCkubWVyZ2UodHguZ2V0VHhTZXQoKSk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG4gICAgXG4gICAgLy8gbWVyZ2UgaW5jb21pbmcgdHJhbnNmZXJzXG4gICAgaWYgKHR4LmdldEluY29taW5nVHJhbnNmZXJzKCkpIHtcbiAgICAgIGlmICh0aGlzLmdldEluY29taW5nVHJhbnNmZXJzKCkgPT09IHVuZGVmaW5lZCkgdGhpcy5zZXRJbmNvbWluZ1RyYW5zZmVycyhbXSk7XG4gICAgICBmb3IgKGxldCB0cmFuc2ZlciBvZiB0eC5nZXRJbmNvbWluZ1RyYW5zZmVycygpKSB7XG4gICAgICAgIHRyYW5zZmVyLnNldFR4KHRoaXMpO1xuICAgICAgICBNb25lcm9UeFdhbGxldC5tZXJnZUluY29taW5nVHJhbnNmZXIodGhpcy5nZXRJbmNvbWluZ1RyYW5zZmVycygpLCB0cmFuc2Zlcik7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIG1lcmdlIG91dGdvaW5nIHRyYW5zZmVyXG4gICAgaWYgKHR4LmdldE91dGdvaW5nVHJhbnNmZXIoKSkge1xuICAgICAgdHguZ2V0T3V0Z29pbmdUcmFuc2ZlcigpLnNldFR4KHRoaXMpO1xuICAgICAgaWYgKHRoaXMuZ2V0T3V0Z29pbmdUcmFuc2ZlcigpID09PSB1bmRlZmluZWQpIHRoaXMuc2V0T3V0Z29pbmdUcmFuc2Zlcih0eC5nZXRPdXRnb2luZ1RyYW5zZmVyKCkpO1xuICAgICAgZWxzZSB0aGlzLmdldE91dGdvaW5nVHJhbnNmZXIoKS5tZXJnZSh0eC5nZXRPdXRnb2luZ1RyYW5zZmVyKCkpO1xuICAgIH1cbiAgICBcbiAgICAvLyBtZXJnZSBzaW1wbGUgZXh0ZW5zaW9uc1xuICAgIHRoaXMuc2V0SXNJbmNvbWluZyhHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRJc0luY29taW5nKCksIHR4LmdldElzSW5jb21pbmcoKSwge3Jlc29sdmVUcnVlOiB0cnVlfSkpOyAgLy8gb3V0cHV0cyBzZWVuIG9uIGNvbmZpcm1hdGlvblxuICAgIHRoaXMuc2V0SXNPdXRnb2luZyhHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRJc091dGdvaW5nKCksIHR4LmdldElzT3V0Z29pbmcoKSkpO1xuICAgIHRoaXMuc2V0Tm90ZShHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXROb3RlKCksIHR4LmdldE5vdGUoKSkpO1xuICAgIHRoaXMuc2V0SXNMb2NrZWQoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0SXNMb2NrZWQoKSwgdHguZ2V0SXNMb2NrZWQoKSwge3Jlc29sdmVUcnVlOiBmYWxzZX0pKTsgLy8gdHggY2FuIGJlY29tZSB1bmxvY2tlZFxuICAgIHRoaXMuc2V0SW5wdXRTdW0oR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0SW5wdXRTdW0oKSwgdHguZ2V0SW5wdXRTdW0oKSkpO1xuICAgIHRoaXMuc2V0T3V0cHV0U3VtKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldE91dHB1dFN1bSgpLCB0eC5nZXRPdXRwdXRTdW0oKSkpO1xuICAgIHRoaXMuc2V0Q2hhbmdlQWRkcmVzcyhHZW5VdGlscy5yZWNvbmNpbGUodGhpcy5nZXRDaGFuZ2VBZGRyZXNzKCksIHR4LmdldENoYW5nZUFkZHJlc3MoKSkpO1xuICAgIHRoaXMuc2V0Q2hhbmdlQW1vdW50KEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldENoYW5nZUFtb3VudCgpLCB0eC5nZXRDaGFuZ2VBbW91bnQoKSkpO1xuICAgIHRoaXMuc2V0TnVtRHVtbXlPdXRwdXRzKEdlblV0aWxzLnJlY29uY2lsZSh0aGlzLmdldE51bUR1bW15T3V0cHV0cygpLCB0eC5nZXROdW1EdW1teU91dHB1dHMoKSkpO1xuICAgIHRoaXMuc2V0RXh0cmFIZXgoR2VuVXRpbHMucmVjb25jaWxlKHRoaXMuZ2V0RXh0cmFIZXgoKSwgdHguZ2V0RXh0cmFIZXgoKSkpO1xuICAgIFxuICAgIHJldHVybiB0aGlzOyAgLy8gZm9yIGNoYWluaW5nXG4gIH1cbiAgXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2luZGVudF0gLSBzdGFydGluZyBpbmRlbnRhdGlvblxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvbmVMaW5lXSAtIHN0cmluZyBpcyBvbmUgbGluZSBpZiB0cnVlLCBtdWx0aXBsZSBsaW5lcyBpZiBmYWxzZVxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGlzIHR4XG4gICAqL1xuICB0b1N0cmluZyhpbmRlbnQgPSAwLCBvbmVMaW5lID0gZmFsc2UpOiBzdHJpbmcge1xuICAgIGxldCBzdHIgPSBcIlwiO1xuICAgIFxuICAgIC8vIHJlcHJlc2VudCB0eCB3aXRoIG9uZSBsaW5lIHN0cmluZ1xuICAgIC8vIFRPRE86IHByb3BlciBjc3YgZXhwb3J0XG4gICAgaWYgKG9uZUxpbmUpIHtcbiAgICAgIHN0ciArPSB0aGlzLmdldEhhc2goKSArIFwiLCBcIjtcbiAgICAgIHN0ciArPSAodGhpcy5nZXRJc0NvbmZpcm1lZCgpID8gdGhpcy5nZXRCbG9jaygpLmdldFRpbWVzdGFtcCgpIDogdGhpcy5nZXRSZWNlaXZlZFRpbWVzdGFtcCgpKSArIFwiLCBcIjtcbiAgICAgIHN0ciArPSB0aGlzLmdldElzQ29uZmlybWVkKCkgKyBcIiwgXCI7XG4gICAgICBzdHIgKz0gKHRoaXMuZ2V0T3V0Z29pbmdBbW91bnQoKSA/IHRoaXMuZ2V0T3V0Z29pbmdBbW91bnQoKS50b1N0cmluZygpIDogXCJcIikgKyBcIiwgXCI7XG4gICAgICBzdHIgKz0gdGhpcy5nZXRJbmNvbWluZ0Ftb3VudCgpID8gdGhpcy5nZXRJbmNvbWluZ0Ftb3VudCgpLnRvU3RyaW5nKCkgOiBcIlwiO1xuICAgICAgcmV0dXJuIHN0cjtcbiAgICB9XG4gICAgXG4gICAgLy8gb3RoZXJ3aXNlIHN0cmluZ2lmeSBhbGwgZmllbGRzXG4gICAgc3RyICs9IHN1cGVyLnRvU3RyaW5nKGluZGVudCkgKyBcIlxcblwiO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJJcyBpbmNvbWluZ1wiLCB0aGlzLmdldElzSW5jb21pbmcoKSwgaW5kZW50KTtcbiAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiSW5jb21pbmcgYW1vdW50XCIsIHRoaXMuZ2V0SW5jb21pbmdBbW91bnQoKSwgaW5kZW50KTtcbiAgICBpZiAodGhpcy5nZXRJbmNvbWluZ1RyYW5zZmVycygpICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJJbmNvbWluZyB0cmFuc2ZlcnNcIiwgXCJcIiwgaW5kZW50KTtcbiAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5nZXRJbmNvbWluZ1RyYW5zZmVycygpLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoaSArIDEsIFwiXCIsIGluZGVudCArIDEpO1xuICAgICAgICBzdHIgKz0gdGhpcy5nZXRJbmNvbWluZ1RyYW5zZmVycygpW2ldLnRvU3RyaW5nKGluZGVudCArIDIpICsgXCJcXG5cIjtcbiAgICAgIH1cbiAgICB9XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIklzIG91dGdvaW5nXCIsIHRoaXMuZ2V0SXNPdXRnb2luZygpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJPdXRnb2luZyBhbW91bnRcIiwgdGhpcy5nZXRPdXRnb2luZ0Ftb3VudCgpLCBpbmRlbnQpO1xuICAgIGlmICh0aGlzLmdldE91dGdvaW5nVHJhbnNmZXIoKSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBzdHIgKz0gR2VuVXRpbHMua3ZMaW5lKFwiT3V0Z29pbmcgdHJhbnNmZXJcIiwgXCJcIiwgaW5kZW50KTtcbiAgICAgIHN0ciArPSB0aGlzLmdldE91dGdvaW5nVHJhbnNmZXIoKS50b1N0cmluZyhpbmRlbnQgKyAxKSArIFwiXFxuXCI7XG4gICAgfVxuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJOb3RlXCIsIHRoaXMuZ2V0Tm90ZSgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJJcyBsb2NrZWRcIiwgdGhpcy5nZXRJc0xvY2tlZCgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJJbnB1dCBzdW1cIiwgdGhpcy5nZXRJbnB1dFN1bSgpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJPdXRwdXQgc3VtXCIsIHRoaXMuZ2V0T3V0cHV0U3VtKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIkNoYW5nZSBhZGRyZXNzXCIsIHRoaXMuZ2V0Q2hhbmdlQWRkcmVzcygpLCBpbmRlbnQpO1xuICAgIHN0ciArPSBHZW5VdGlscy5rdkxpbmUoXCJDaGFuZ2UgYW1vdW50XCIsIHRoaXMuZ2V0Q2hhbmdlQW1vdW50KCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIk51bSBkdW1teSBvdXRwdXRzXCIsIHRoaXMuZ2V0TnVtRHVtbXlPdXRwdXRzKCksIGluZGVudCk7XG4gICAgc3RyICs9IEdlblV0aWxzLmt2TGluZShcIkV4dHJhIGhleFwiLCB0aGlzLmdldEV4dHJhSGV4KCksIGluZGVudCk7XG4gICAgcmV0dXJuIHN0ci5zbGljZSgwLCBzdHIubGVuZ3RoIC0gMSk7ICAvLyBzdHJpcCBsYXN0IG5ld2xpbmVcbiAgfVxuICBcbiAgLy8gcHJpdmF0ZSBoZWxwZXIgdG8gbWVyZ2UgdHJhbnNmZXJzXG4gIHByb3RlY3RlZCBzdGF0aWMgbWVyZ2VJbmNvbWluZ1RyYW5zZmVyKHRyYW5zZmVycywgdHJhbnNmZXIpIHtcbiAgICBmb3IgKGxldCBhVHJhbnNmZXIgb2YgdHJhbnNmZXJzKSB7XG4gICAgICBpZiAoYVRyYW5zZmVyLmdldEFjY291bnRJbmRleCgpID09PSB0cmFuc2Zlci5nZXRBY2NvdW50SW5kZXgoKSAmJiBhVHJhbnNmZXIuZ2V0U3ViYWRkcmVzc0luZGV4KCkgPT09IHRyYW5zZmVyLmdldFN1YmFkZHJlc3NJbmRleCgpKSB7XG4gICAgICAgIGFUcmFuc2Zlci5tZXJnZSh0cmFuc2Zlcik7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG4gICAgdHJhbnNmZXJzLnB1c2godHJhbnNmZXIpO1xuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0gT1ZFUlJJREUgQ09WQVJJQU5UIFJFVFVSTiBUWVBFUyAtLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICBzZXRCbG9jayhibG9jazogTW9uZXJvQmxvY2spOiBNb25lcm9UeFdhbGxldCB7XG4gICAgc3VwZXIuc2V0QmxvY2soYmxvY2spO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0SGFzaChoYXNoOiBzdHJpbmcpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgc3VwZXIuc2V0SGFzaChoYXNoKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldFZlcnNpb24odmVyc2lvbjogbnVtYmVyKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldFZlcnNpb24odmVyc2lvbik7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRJc01pbmVyVHgoaXNNaW5lclR4OiBib29sZWFuKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldElzTWluZXJUeChpc01pbmVyVHgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0UGF5bWVudElkKHBheW1lbnRJZDogc3RyaW5nKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldFBheW1lbnRJZChwYXltZW50SWQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0RmVlKGZlZTogYmlnaW50KTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldEZlZShmZWUpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0UmluZ1NpemUocmluZ1NpemU6IG51bWJlcik6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICBzdXBlci5zZXRSaW5nU2l6ZShyaW5nU2l6ZSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRSZWxheShyZWxheTogYm9vbGVhbik6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICBzdXBlci5zZXRSZWxheShyZWxheSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRJc1JlbGF5ZWQoaXNSZWxheWVkOiBib29sZWFuKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldElzUmVsYXllZChpc1JlbGF5ZWQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0SXNDb25maXJtZWQoaXNDb25maXJtZWQ6IGJvb2xlYW4pOiBNb25lcm9UeFdhbGxldCB7XG4gICAgc3VwZXIuc2V0SXNDb25maXJtZWQoaXNDb25maXJtZWQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0SW5UeFBvb2woaW5UeFBvb2w6IGJvb2xlYW4pOiBNb25lcm9UeFdhbGxldCB7XG4gICAgc3VwZXIuc2V0SW5UeFBvb2woaW5UeFBvb2wpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0TnVtQ29uZmlybWF0aW9ucyhudW1Db25maXJtYXRpb25zOiBudW1iZXIpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgc3VwZXIuc2V0TnVtQ29uZmlybWF0aW9ucyhudW1Db25maXJtYXRpb25zKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldFVubG9ja1RpbWUodW5sb2NrVGltZTogYmlnaW50KTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldFVubG9ja1RpbWUodW5sb2NrVGltZSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRMYXN0UmVsYXllZFRpbWVzdGFtcChsYXN0UmVsYXllZFRpbWVzdGFtcDogbnVtYmVyKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldExhc3RSZWxheWVkVGltZXN0YW1wKGxhc3RSZWxheWVkVGltZXN0YW1wKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldFJlY2VpdmVkVGltZXN0YW1wKHJlY2VpdmVkVGltZXN0YW1wOiBudW1iZXIpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgc3VwZXIuc2V0UmVjZWl2ZWRUaW1lc3RhbXAocmVjZWl2ZWRUaW1lc3RhbXApO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0SXNEb3VibGVTcGVuZFNlZW4oaXNEb3VibGVTcGVuZFNlZW46IGJvb2xlYW4pOiBNb25lcm9UeFdhbGxldCB7XG4gICAgc3VwZXIuc2V0SXNEb3VibGVTcGVuZFNlZW4oaXNEb3VibGVTcGVuZFNlZW4pO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0S2V5KGtleTogc3RyaW5nKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldEtleShrZXkpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0RnVsbEhleChmdWxsSGV4OiBzdHJpbmcpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgc3VwZXIuc2V0RnVsbEhleChmdWxsSGV4KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldFBydW5lZEhleChwcnVuZWRIZXg6IHN0cmluZyk6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICBzdXBlci5zZXRQcnVuZWRIZXgocHJ1bmVkSGV4KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldFBydW5hYmxlSGV4KHBydW5hYmxlSGV4OiBzdHJpbmcpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgc3VwZXIuc2V0UHJ1bmFibGVIZXgocHJ1bmFibGVIZXgpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0UHJ1bmFibGVIYXNoKHBydW5hYmxlSGFzaDogc3RyaW5nKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldFBydW5hYmxlSGFzaChwcnVuYWJsZUhhc2gpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0U2l6ZShzaXplOiBudW1iZXIpOiBNb25lcm9UeFdhbGxldCB7XG4gICAgc3VwZXIuc2V0U2l6ZShzaXplKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldFdlaWdodCh3ZWlnaHQ6IG51bWJlcik6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICBzdXBlci5zZXRXZWlnaHQod2VpZ2h0KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldElucHV0cyhpbnB1dHM6IE1vbmVyb091dHB1dFtdKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldElucHV0cyhpbnB1dHMpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0T3V0cHV0cyhvdXRwdXRzOiBNb25lcm9PdXRwdXRbXSk6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICBzdXBlci5zZXRPdXRwdXRzKG91dHB1dHMpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0T3V0cHV0SW5kaWNlcyhvdXRwdXRJbmRpY2VzOiBudW1iZXJbXSk6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICBzdXBlci5zZXRPdXRwdXRJbmRpY2VzKG91dHB1dEluZGljZXMpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0TWV0YWRhdGEobWV0YWRhdGE6IHN0cmluZyk6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICBzdXBlci5zZXRNZXRhZGF0YShtZXRhZGF0YSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRFeHRyYShleHRyYTogVWludDhBcnJheSk6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICBzdXBlci5zZXRFeHRyYShleHRyYSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRSY3RTaWduYXR1cmVzKHJjdFNpZ25hdHVyZXM6IGFueSk6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICBzdXBlci5zZXRSY3RTaWduYXR1cmVzKHJjdFNpZ25hdHVyZXMpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgc2V0UmN0U2lnUHJ1bmFibGUocmN0U2lnUHJ1bmFibGU6IGFueSk6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICBzdXBlci5zZXRSY3RTaWdQcnVuYWJsZShyY3RTaWdQcnVuYWJsZSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRJc0tlcHRCeUJsb2NrKGlzS2VwdEJ5QmxvY2s6IGJvb2xlYW4pOiBNb25lcm9UeFdhbGxldCB7XG4gICAgc3VwZXIuc2V0SXNLZXB0QnlCbG9jayhpc0tlcHRCeUJsb2NrKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldElzRmFpbGVkKGlzRmFpbGVkOiBib29sZWFuKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldElzRmFpbGVkKGlzRmFpbGVkKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldExhc3RGYWlsZWRIZWlnaHQobGFzdEZhaWxlZEhlaWdodDogbnVtYmVyKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldExhc3RGYWlsZWRIZWlnaHQobGFzdEZhaWxlZEhlaWdodCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRMYXN0RmFpbGVkSGFzaChsYXN0RmFpbGVkSGFzaDogc3RyaW5nKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldExhc3RGYWlsZWRIYXNoKGxhc3RGYWlsZWRIYXNoKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldE1heFVzZWRCbG9ja0hlaWdodChtYXhVc2VkQmxvY2tIZWlnaHQ6IG51bWJlcik6IE1vbmVyb1R4V2FsbGV0IHtcbiAgICBzdXBlci5zZXRNYXhVc2VkQmxvY2tIZWlnaHQobWF4VXNlZEJsb2NrSGVpZ2h0KTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIHNldE1heFVzZWRCbG9ja0hhc2gobWF4VXNlZEJsb2NrSGFzaDogc3RyaW5nKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldE1heFVzZWRCbG9ja0hhc2gobWF4VXNlZEJsb2NrSGFzaCk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBzZXRTaWduYXR1cmVzKHNpZ25hdHVyZXM6IHN0cmluZ1tdKTogTW9uZXJvVHhXYWxsZXQge1xuICAgIHN1cGVyLnNldFNpZ25hdHVyZXMoc2lnbmF0dXJlcyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cbiJdLCJtYXBwaW5ncyI6InlMQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFNBQUEsR0FBQUYsc0JBQUEsQ0FBQUMsT0FBQTs7QUFFQSxJQUFBRSxZQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRyx1QkFBQSxHQUFBSixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUksdUJBQUEsR0FBQUwsc0JBQUEsQ0FBQUMsT0FBQTs7O0FBR0EsSUFBQUssbUJBQUEsR0FBQU4sc0JBQUEsQ0FBQUMsT0FBQTs7O0FBR0EsSUFBQU0sU0FBQSxHQUFBUCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQU8sWUFBQSxHQUFBUixzQkFBQSxDQUFBQyxPQUFBOztBQUVBO0FBQ0E7QUFDQTtBQUNlLE1BQU1RLGNBQWMsU0FBU0MsaUJBQVEsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7OztFQWdCbkQ7QUFDRjtBQUNBO0FBQ0E7QUFDQTtFQUNFQyxXQUFXQSxDQUFDQyxFQUE0QixFQUFFO0lBQ3hDLEtBQUssQ0FBQ0EsRUFBRSxDQUFDO0lBQ1QsSUFBSSxDQUFDQyxRQUFRLENBQUMsSUFBSSxDQUFDQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7SUFFaEM7SUFDQSxJQUFJLElBQUksQ0FBQ0MsaUJBQWlCLEVBQUU7TUFDMUIsSUFBSSxDQUFDQSxpQkFBaUIsR0FBRyxJQUFJLENBQUNBLGlCQUFpQixDQUFDQyxLQUFLLENBQUMsQ0FBQztNQUN2RCxLQUFLLElBQUlDLENBQUMsR0FBRyxDQUFDLEVBQUVBLENBQUMsR0FBRyxJQUFJLENBQUNGLGlCQUFpQixDQUFDRyxNQUFNLEVBQUVELENBQUMsRUFBRSxFQUFFO1FBQ3RELElBQUksQ0FBQ0YsaUJBQWlCLENBQUNFLENBQUMsQ0FBQyxHQUFHLElBQUlFLCtCQUFzQixDQUFDLElBQUksQ0FBQ0osaUJBQWlCLENBQUNFLENBQUMsQ0FBQyxDQUFDLENBQUNHLEtBQUssQ0FBQyxJQUFJLENBQUM7TUFDL0Y7SUFDRjs7SUFFQTtJQUNBLElBQUksSUFBSSxDQUFDQyxnQkFBZ0IsRUFBRTtNQUN6QixJQUFJLENBQUNBLGdCQUFnQixHQUFHLElBQUlDLCtCQUFzQixDQUFDLElBQUksQ0FBQ0QsZ0JBQWdCLENBQUMsQ0FBQ0QsS0FBSyxDQUFDLElBQUksQ0FBQztJQUN2Rjs7SUFFQTtJQUNBLElBQUksSUFBSSxDQUFDRyxNQUFNLEVBQUU7TUFDZixJQUFJLENBQUNBLE1BQU0sR0FBRyxJQUFJLENBQUNBLE1BQU0sQ0FBQ1AsS0FBSyxDQUFDLENBQUM7TUFDakMsS0FBSyxJQUFJQyxDQUFDLEdBQUcsQ0FBQyxFQUFFQSxDQUFDLEdBQUcsSUFBSSxDQUFDTSxNQUFNLENBQUNMLE1BQU0sRUFBRUQsQ0FBQyxFQUFFLEVBQUU7UUFDM0MsSUFBSSxDQUFDTSxNQUFNLENBQUNOLENBQUMsQ0FBQyxHQUFHLElBQUlPLDJCQUFrQixDQUFDLElBQUksQ0FBQ0QsTUFBTSxDQUFDTixDQUFDLENBQXVCLENBQUMsQ0FBQ0csS0FBSyxDQUFDLElBQUksQ0FBQztNQUMzRjtJQUNGOztJQUVBO0lBQ0EsSUFBSSxJQUFJLENBQUNLLE9BQU8sRUFBRTtNQUNoQixJQUFJLENBQUNBLE9BQU8sR0FBRyxJQUFJLENBQUNBLE9BQU8sQ0FBQ1QsS0FBSyxDQUFDLENBQUM7TUFDbkMsS0FBSyxJQUFJQyxDQUFDLEdBQUcsQ0FBQyxFQUFFQSxDQUFDLEdBQUcsSUFBSSxDQUFDUSxPQUFPLENBQUNQLE1BQU0sRUFBRUQsQ0FBQyxFQUFFLEVBQUU7UUFDNUMsSUFBSSxDQUFDUSxPQUFPLENBQUNSLENBQUMsQ0FBQyxHQUFHLElBQUlPLDJCQUFrQixDQUFDLElBQUksQ0FBQ0MsT0FBTyxDQUFDUixDQUFDLENBQXVCLENBQUMsQ0FBQ0csS0FBSyxDQUFDLElBQUksQ0FBQztNQUM3RjtJQUNGOztJQUVBO0lBQ0EsSUFBSSxJQUFJLENBQUNNLFFBQVEsS0FBS0MsU0FBUyxJQUFJLE9BQU8sSUFBSSxDQUFDRCxRQUFRLEtBQUssUUFBUSxFQUFFLElBQUksQ0FBQ0EsUUFBUSxHQUFHRSxNQUFNLENBQUMsSUFBSSxDQUFDRixRQUFRLENBQUM7SUFDM0csSUFBSSxJQUFJLENBQUNHLFNBQVMsS0FBS0YsU0FBUyxJQUFJLE9BQU8sSUFBSSxDQUFDRSxTQUFTLEtBQUssUUFBUSxFQUFFLElBQUksQ0FBQ0EsU0FBUyxHQUFHRCxNQUFNLENBQUMsSUFBSSxDQUFDQyxTQUFTLENBQUM7SUFDL0csSUFBSSxJQUFJLENBQUNDLFlBQVksS0FBS0gsU0FBUyxJQUFJLE9BQU8sSUFBSSxDQUFDRyxZQUFZLEtBQUssUUFBUSxFQUFFLElBQUksQ0FBQ0EsWUFBWSxHQUFHRixNQUFNLENBQUMsSUFBSSxDQUFDRSxZQUFZLENBQUM7RUFDN0g7O0VBRUE7QUFDRjtBQUNBO0VBQ0VDLE1BQU1BLENBQUEsRUFBUTtJQUNaLElBQUlDLElBQUksR0FBR0MsTUFBTSxDQUFDQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQ0gsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDcEQsSUFBSSxJQUFJLENBQUNJLG9CQUFvQixDQUFDLENBQUMsS0FBS1IsU0FBUyxFQUFFO01BQzdDSyxJQUFJLENBQUNqQixpQkFBaUIsR0FBRyxFQUFFO01BQzNCLEtBQUssSUFBSXFCLGdCQUFnQixJQUFJLElBQUksQ0FBQ0Qsb0JBQW9CLENBQUMsQ0FBQyxFQUFFSCxJQUFJLENBQUNqQixpQkFBaUIsQ0FBQ3NCLElBQUksQ0FBQ0QsZ0JBQWdCLENBQUNMLE1BQU0sQ0FBQyxDQUFDLENBQUM7SUFDbEg7SUFDQSxJQUFJLElBQUksQ0FBQ08sbUJBQW1CLENBQUMsQ0FBQyxLQUFLWCxTQUFTLEVBQUVLLElBQUksQ0FBQ1gsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDaUIsbUJBQW1CLENBQUMsQ0FBQyxDQUFDUCxNQUFNLENBQUMsQ0FBQztJQUN6RyxJQUFJLElBQUksQ0FBQ1EsV0FBVyxDQUFDLENBQUMsS0FBS1osU0FBUyxFQUFFSyxJQUFJLENBQUNOLFFBQVEsR0FBRyxJQUFJLENBQUNhLFdBQVcsQ0FBQyxDQUFDLENBQUNDLFFBQVEsQ0FBQyxDQUFDO0lBQ25GLElBQUksSUFBSSxDQUFDQyxZQUFZLENBQUMsQ0FBQyxLQUFLZCxTQUFTLEVBQUVLLElBQUksQ0FBQ0gsU0FBUyxHQUFHLElBQUksQ0FBQ1ksWUFBWSxDQUFDLENBQUMsQ0FBQ0QsUUFBUSxDQUFDLENBQUM7SUFDdEYsSUFBSSxJQUFJLENBQUNFLGVBQWUsQ0FBQyxDQUFDLEtBQUtmLFNBQVMsRUFBRUssSUFBSSxDQUFDRixZQUFZLEdBQUcsSUFBSSxDQUFDWSxlQUFlLENBQUMsQ0FBQyxDQUFDRixRQUFRLENBQUMsQ0FBQztJQUMvRixPQUFPUixJQUFJLENBQUNXLEtBQUssQ0FBQyxDQUFFO0lBQ3BCLE9BQU9YLElBQUksQ0FBQ1ksS0FBSyxDQUFDLENBQUU7SUFDcEIsT0FBT1osSUFBSTtFQUNiOztFQUVBO0FBQ0Y7QUFDQTtFQUNFbEIsUUFBUUEsQ0FBQSxFQUFnQjtJQUN0QixPQUFPLElBQUksQ0FBQzhCLEtBQUs7RUFDbkI7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7RUFDRS9CLFFBQVFBLENBQUMrQixLQUFrQixFQUFrQjtJQUMzQyxJQUFJLENBQUNBLEtBQUssR0FBR0EsS0FBSztJQUNsQixPQUFPLElBQUk7RUFDYjs7RUFFQTtBQUNGO0FBQ0E7RUFDRUMsYUFBYUEsQ0FBQSxFQUFZO0lBQ3ZCLE9BQU8sSUFBSSxDQUFDQyxVQUFVO0VBQ3hCOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0VBQ0VDLGFBQWFBLENBQUNELFVBQW1CLEVBQWtCO0lBQ2pELElBQUksQ0FBQ0EsVUFBVSxHQUFHQSxVQUFVO0lBQzVCLE9BQU8sSUFBSTtFQUNiOztFQUVBO0FBQ0Y7QUFDQTtFQUNFRSxhQUFhQSxDQUFBLEVBQVk7SUFDdkIsT0FBTyxJQUFJLENBQUNDLFVBQVU7RUFDeEI7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7RUFDRUMsYUFBYUEsQ0FBQ0QsVUFBbUIsRUFBa0I7SUFDakQsSUFBSSxDQUFDQSxVQUFVLEdBQUdBLFVBQVU7SUFDNUIsT0FBTyxJQUFJO0VBQ2I7O0VBRUE7QUFDRjtBQUNBO0VBQ0VFLGlCQUFpQkEsQ0FBQSxFQUFXO0lBQzFCLElBQUksSUFBSSxDQUFDaEIsb0JBQW9CLENBQUMsQ0FBQyxLQUFLUixTQUFTLEVBQUUsT0FBT0EsU0FBUztJQUMvRCxJQUFJeUIsV0FBVyxHQUFHLEVBQUU7SUFDcEIsS0FBSyxJQUFJQyxRQUFRLElBQUksSUFBSSxDQUFDbEIsb0JBQW9CLENBQUMsQ0FBQyxFQUFFaUIsV0FBVyxHQUFHQSxXQUFXLEdBQUdDLFFBQVEsQ0FBQ0MsU0FBUyxDQUFDLENBQUM7SUFDbEcsT0FBT0YsV0FBVztFQUNwQjs7RUFFQTtBQUNGO0FBQ0E7RUFDRUcsaUJBQWlCQSxDQUFBLEVBQVc7SUFDMUIsT0FBTyxJQUFJLENBQUNqQixtQkFBbUIsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDQSxtQkFBbUIsQ0FBQyxDQUFDLENBQUNnQixTQUFTLENBQUMsQ0FBQyxHQUFHM0IsU0FBUztFQUN4Rjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtFQUNFNkIsWUFBWUEsQ0FBQ0MsYUFBbUMsRUFBb0I7SUFDbEUsSUFBSUMsU0FBUyxHQUFHLEVBQUU7SUFDbEIsSUFBSSxJQUFJLENBQUNwQixtQkFBbUIsQ0FBQyxDQUFDLEtBQUssQ0FBQ21CLGFBQWEsSUFBSUEsYUFBYSxDQUFDRSxhQUFhLENBQUMsSUFBSSxDQUFDckIsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRW9CLFNBQVMsQ0FBQ3JCLElBQUksQ0FBQyxJQUFJLENBQUNDLG1CQUFtQixDQUFDLENBQUMsQ0FBQztJQUN6SixJQUFJLElBQUksQ0FBQ0gsb0JBQW9CLENBQUMsQ0FBQyxLQUFLUixTQUFTLEVBQUU7TUFDN0MsS0FBSyxJQUFJMEIsUUFBUSxJQUFJLElBQUksQ0FBQ2xCLG9CQUFvQixDQUFDLENBQUMsRUFBRTtRQUNoRCxJQUFJLENBQUNzQixhQUFhLElBQUlBLGFBQWEsQ0FBQ0UsYUFBYSxDQUFDTixRQUFRLENBQUMsRUFBRUssU0FBUyxDQUFDckIsSUFBSSxDQUFDZ0IsUUFBUSxDQUFDO01BQ3ZGO0lBQ0Y7SUFDQSxPQUFPSyxTQUFTO0VBQ2xCOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0VBQ0VFLGVBQWVBLENBQUNILGFBQWtDLEVBQW9CO0lBQ3BFLElBQUlDLFNBQVMsR0FBRyxFQUFFOztJQUVsQjtJQUNBLElBQUksSUFBSSxDQUFDcEIsbUJBQW1CLENBQUMsQ0FBQyxLQUFLLENBQUNtQixhQUFhLElBQUlBLGFBQWEsQ0FBQ0UsYUFBYSxDQUFDLElBQUksQ0FBQ3JCLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUVvQixTQUFTLENBQUNyQixJQUFJLENBQUMsSUFBSSxDQUFDQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNySixJQUFJLENBQUN1QixtQkFBbUIsQ0FBQ2xDLFNBQVMsQ0FBQzs7SUFFeEM7SUFDQSxJQUFJLElBQUksQ0FBQ1Esb0JBQW9CLENBQUMsQ0FBQyxLQUFLUixTQUFTLEVBQUU7TUFDN0MsSUFBSW1DLFNBQVMsR0FBRyxFQUFFO01BQ2xCLEtBQUssSUFBSVQsUUFBUSxJQUFJLElBQUksQ0FBQ2xCLG9CQUFvQixDQUFDLENBQUMsRUFBRTtRQUNoRCxJQUFJc0IsYUFBYSxDQUFDRSxhQUFhLENBQUNOLFFBQVEsQ0FBQyxFQUFFSyxTQUFTLENBQUNyQixJQUFJLENBQUNnQixRQUFRLENBQUMsQ0FBQztRQUMvRFMsU0FBUyxDQUFDekIsSUFBSSxDQUFDZ0IsUUFBUSxDQUFDO01BQy9CO01BQ0EsSUFBSSxDQUFDVSxvQkFBb0IsQ0FBQyxJQUFJLENBQUM1QixvQkFBb0IsQ0FBQyxDQUFDLENBQUM2QixNQUFNLENBQUMsVUFBU1gsUUFBUSxFQUFFO1FBQzlFLE9BQU8sQ0FBQ1MsU0FBUyxDQUFDRyxRQUFRLENBQUNaLFFBQVEsQ0FBQztNQUN0QyxDQUFDLENBQUMsQ0FBQztNQUNILElBQUksSUFBSSxDQUFDbEIsb0JBQW9CLENBQUMsQ0FBQyxDQUFDakIsTUFBTSxLQUFLLENBQUMsRUFBRSxJQUFJLENBQUM2QyxvQkFBb0IsQ0FBQ3BDLFNBQVMsQ0FBQztJQUNwRjs7SUFFQSxPQUFPK0IsU0FBUztFQUNsQjs7RUFFQTtBQUNGO0FBQ0E7RUFDRXZCLG9CQUFvQkEsQ0FBQSxFQUE2QjtJQUMvQyxPQUFPLElBQUksQ0FBQ3BCLGlCQUFpQjtFQUMvQjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtFQUNFZ0Qsb0JBQW9CQSxDQUFDaEQsaUJBQTJDLEVBQWtCO0lBQ2hGLElBQUksQ0FBQ0EsaUJBQWlCLEdBQUdBLGlCQUFpQjtJQUMxQyxPQUFPLElBQUk7RUFDYjs7RUFFQTtBQUNGO0FBQ0E7RUFDRXVCLG1CQUFtQkEsQ0FBQSxFQUEyQjtJQUM1QyxPQUFPLElBQUksQ0FBQ2pCLGdCQUFnQjtFQUM5Qjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtFQUNFd0MsbUJBQW1CQSxDQUFDeEMsZ0JBQXdDLEVBQWtCO0lBQzVFLElBQUksQ0FBQ0EsZ0JBQWdCLEdBQUdBLGdCQUFnQjtJQUN4QyxPQUFPLElBQUk7RUFDYjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtFQUNFNkMsZUFBZUEsQ0FBQ0MsV0FBK0IsRUFBd0I7SUFDckUsSUFBSTVDLE1BQTRCLEdBQUcsRUFBRTtJQUNyQyxLQUFLLElBQUk2QyxNQUFNLElBQUksS0FBSyxDQUFDQyxTQUFTLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQ0YsV0FBVyxJQUFJQSxXQUFXLENBQUNSLGFBQWEsQ0FBQ1MsTUFBNEIsQ0FBQyxFQUFFN0MsTUFBTSxDQUFDYyxJQUFJLENBQUMrQixNQUE0QixDQUFDO0lBQzVKLE9BQU83QyxNQUFNO0VBQ2Y7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7RUFDRStDLGVBQWVBLENBQUMvQyxNQUE0QixFQUFrQjs7SUFFNUQ7SUFDQSxJQUFJQSxNQUFNLEVBQUU7TUFDVixLQUFLLElBQUk2QyxNQUFNLElBQUk3QyxNQUFNLEVBQUU7UUFDekIsSUFBSSxFQUFFNkMsTUFBTSxZQUFZNUMsMkJBQWtCLENBQUMsRUFBRSxNQUFNLElBQUkrQyxvQkFBVyxDQUFDLDhEQUE4RCxDQUFDO01BQ3BJO0lBQ0Y7SUFDQSxLQUFLLENBQUNDLFNBQVMsQ0FBQ2pELE1BQU0sQ0FBQztJQUN2QixPQUFPLElBQUk7RUFDYjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtFQUNFa0QsZ0JBQWdCQSxDQUFDTixXQUErQixFQUF3QjtJQUN0RSxJQUFJMUMsT0FBTyxHQUFHLEVBQUU7SUFDaEIsS0FBSyxJQUFJMkMsTUFBTSxJQUFJLEtBQUssQ0FBQ00sVUFBVSxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUNQLFdBQVcsSUFBSUEsV0FBVyxDQUFDUixhQUFhLENBQUNTLE1BQTRCLENBQUMsRUFBRTNDLE9BQU8sQ0FBQ1ksSUFBSSxDQUFDK0IsTUFBTSxDQUFDO0lBQ3hJLE9BQU8zQyxPQUFPO0VBQ2hCOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0VBQ0VrRCxnQkFBZ0JBLENBQUNsRCxPQUE2QixFQUFrQjs7SUFFOUQ7SUFDQSxJQUFJQSxPQUFPLEVBQUU7TUFDWCxLQUFLLElBQUkyQyxNQUFNLElBQUkzQyxPQUFPLEVBQUU7UUFDMUIsSUFBSSxFQUFFMkMsTUFBTSxZQUFZNUMsMkJBQWtCLENBQUMsRUFBRSxNQUFNLElBQUkrQyxvQkFBVyxDQUFDLCtEQUErRCxDQUFDO01BQ3JJO0lBQ0Y7SUFDQSxLQUFLLENBQUNLLFVBQVUsQ0FBQ25ELE9BQU8sQ0FBQztJQUN6QixPQUFPLElBQUk7RUFDYjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtFQUNFb0QsYUFBYUEsQ0FBQ1YsV0FBOEIsRUFBb0I7SUFDOUQsSUFBSTFDLE9BQU8sR0FBRyxFQUFFO0lBQ2hCLElBQUksS0FBSyxDQUFDaUQsVUFBVSxDQUFDLENBQUMsRUFBRTtNQUN0QixJQUFJWixTQUFTLEdBQUcsRUFBRTtNQUNsQixLQUFLLElBQUlNLE1BQU0sSUFBSSxLQUFLLENBQUNNLFVBQVUsQ0FBQyxDQUFDLEVBQUU7UUFDckMsSUFBSSxDQUFDUCxXQUFXLElBQUlBLFdBQVcsQ0FBQ1IsYUFBYSxDQUFDUyxNQUE0QixDQUFDLEVBQUUzQyxPQUFPLENBQUNZLElBQUksQ0FBQytCLE1BQU0sQ0FBQyxDQUFDO1FBQzdGTixTQUFTLENBQUN6QixJQUFJLENBQUMrQixNQUFNLENBQUM7TUFDN0I7TUFDQSxJQUFJLENBQUNRLFVBQVUsQ0FBQyxLQUFLLENBQUNGLFVBQVUsQ0FBQyxDQUFDLENBQUNWLE1BQU0sQ0FBQyxVQUFTSSxNQUFNLEVBQUU7UUFDekQsT0FBTyxDQUFDTixTQUFTLENBQUNHLFFBQVEsQ0FBQ0csTUFBTSxDQUFDO01BQ3BDLENBQUMsQ0FBQyxDQUFDO01BQ0gsSUFBSSxJQUFJLENBQUNNLFVBQVUsQ0FBQyxDQUFDLENBQUN4RCxNQUFNLEtBQUssQ0FBQyxFQUFFLElBQUksQ0FBQzBELFVBQVUsQ0FBQ2pELFNBQVMsQ0FBQztJQUNoRTtJQUNBLE9BQU9GLE9BQU87RUFDaEI7O0VBRUE7QUFDRjtBQUNBO0VBQ0VxRCxPQUFPQSxDQUFBLEVBQVc7SUFDaEIsT0FBTyxJQUFJLENBQUNDLElBQUk7RUFDbEI7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7RUFDRUMsT0FBT0EsQ0FBQ0QsSUFBWSxFQUFrQjtJQUNwQyxJQUFJLENBQUNBLElBQUksR0FBR0EsSUFBSTtJQUNoQixPQUFPLElBQUk7RUFDYjs7RUFFQTtBQUNGO0FBQ0E7RUFDRUUsV0FBV0EsQ0FBQSxFQUFZO0lBQ3JCLE9BQU8sSUFBSSxDQUFDQyxRQUFRO0VBQ3RCOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0VBQ0VDLFdBQVdBLENBQUNELFFBQWlCLEVBQWtCO0lBQzdDLElBQUksQ0FBQ0EsUUFBUSxHQUFHQSxRQUFRO0lBQ3hCLE9BQU8sSUFBSTtFQUNiOztFQUVBO0FBQ0Y7QUFDQTtFQUNFM0MsV0FBV0EsQ0FBQSxFQUFXO0lBQ3BCLE9BQU8sSUFBSSxDQUFDYixRQUFRO0VBQ3RCOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0VBQ0UwRCxXQUFXQSxDQUFDMUQsUUFBZ0IsRUFBa0I7SUFDNUMsSUFBSSxDQUFDQSxRQUFRLEdBQUdBLFFBQVE7SUFDeEIsT0FBTyxJQUFJO0VBQ2I7O0VBRUE7QUFDRjtBQUNBO0VBQ0VlLFlBQVlBLENBQUEsRUFBVztJQUNyQixPQUFPLElBQUksQ0FBQ1osU0FBUztFQUN2Qjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtFQUNFd0QsWUFBWUEsQ0FBQ3hELFNBQWlCLEVBQWtCO0lBQzlDLElBQUksQ0FBQ0EsU0FBUyxHQUFHQSxTQUFTO0lBQzFCLE9BQU8sSUFBSTtFQUNiOztFQUVBO0FBQ0Y7QUFDQTtFQUNFeUQsZ0JBQWdCQSxDQUFBLEVBQVc7SUFDekIsT0FBTyxJQUFJLENBQUNDLGFBQWE7RUFDM0I7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7RUFDRUMsZ0JBQWdCQSxDQUFDRCxhQUFxQixFQUFrQjtJQUN0RCxJQUFJLENBQUNBLGFBQWEsR0FBR0EsYUFBYTtJQUNsQyxPQUFPLElBQUk7RUFDYjs7RUFFQTtBQUNGO0FBQ0E7RUFDRTdDLGVBQWVBLENBQUEsRUFBVztJQUN4QixPQUFPLElBQUksQ0FBQ1osWUFBWTtFQUMxQjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtFQUNFMkQsZUFBZUEsQ0FBQzNELFlBQW9CLEVBQWtCO0lBQ3BELElBQUksQ0FBQ0EsWUFBWSxHQUFHQSxZQUFZO0lBQ2hDLE9BQU8sSUFBSTtFQUNiOztFQUVBO0FBQ0Y7QUFDQTtFQUNFNEQsa0JBQWtCQSxDQUFBLEVBQVc7SUFDM0IsT0FBTyxJQUFJLENBQUNDLGVBQWU7RUFDN0I7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7RUFDRUMsa0JBQWtCQSxDQUFDRCxlQUF1QixFQUFrQjtJQUMxRCxJQUFJLENBQUNBLGVBQWUsR0FBR0EsZUFBZTtJQUN0QyxPQUFPLElBQUk7RUFDYjs7RUFFQTtBQUNGO0FBQ0E7RUFDRUUsV0FBV0EsQ0FBQSxFQUFXO0lBQ3BCLE9BQU8sSUFBSSxDQUFDQyxRQUFRO0VBQ3RCOztFQUVBO0FBQ0Y7QUFDQTtBQUNBO0VBQ0VDLFdBQVdBLENBQUNELFFBQWdCLEVBQWtCO0lBQzVDLElBQUksQ0FBQ0EsUUFBUSxHQUFHQSxRQUFRO0lBQ3hCLE9BQU8sSUFBSTtFQUNiOztFQUVBO0FBQ0Y7QUFDQTtFQUNFRSxJQUFJQSxDQUFBLEVBQW1CO0lBQ3JCLE9BQU8sSUFBSXZGLGNBQWMsQ0FBQyxJQUFJLENBQUM7RUFDakM7O0VBRUE7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0V3RixLQUFLQSxDQUFDckYsRUFBa0IsRUFBa0I7SUFDeEMsSUFBQXNGLGVBQU0sRUFBQ3RGLEVBQUUsWUFBWUgsY0FBYyxDQUFDO0lBQ3BDLElBQUksSUFBSSxLQUFLRyxFQUFFLEVBQUUsT0FBTyxJQUFJOztJQUU1QjtJQUNBLEtBQUssQ0FBQ3FGLEtBQUssQ0FBQ3JGLEVBQUUsQ0FBQzs7SUFFZjtJQUNBO0lBQ0EsSUFBSSxJQUFJLENBQUNFLFFBQVEsQ0FBQyxDQUFDLEtBQUtGLEVBQUUsQ0FBQ0UsUUFBUSxDQUFDLENBQUMsRUFBRTtNQUNyQyxJQUFJLElBQUksQ0FBQ0EsUUFBUSxDQUFDLENBQUMsSUFBSWEsU0FBUyxFQUFFO1FBQ2hDLElBQUksQ0FBQ2QsUUFBUSxDQUFDLElBQUlzRixvQkFBVyxDQUFDLENBQUMsQ0FBQ0MsTUFBTSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztNQUNqRDtNQUNBLElBQUl4RixFQUFFLENBQUNFLFFBQVEsQ0FBQyxDQUFDLEtBQUthLFNBQVMsRUFBRTtRQUMvQmYsRUFBRSxDQUFDQyxRQUFRLENBQUMsSUFBSXNGLG9CQUFXLENBQUMsQ0FBQyxDQUFDQyxNQUFNLENBQUMsQ0FBQ3hGLEVBQUUsQ0FBQyxDQUFDLENBQUM7TUFDN0M7TUFDQSxJQUFJLENBQUNFLFFBQVEsQ0FBQyxDQUFDLENBQUNtRixLQUFLLENBQUNyRixFQUFFLENBQUNFLFFBQVEsQ0FBQyxDQUFDLENBQUM7TUFDcEMsT0FBTyxJQUFJO0lBQ2I7O0lBRUE7SUFDQSxJQUFJRixFQUFFLENBQUN1QixvQkFBb0IsQ0FBQyxDQUFDLEVBQUU7TUFDN0IsSUFBSSxJQUFJLENBQUNBLG9CQUFvQixDQUFDLENBQUMsS0FBS1IsU0FBUyxFQUFFLElBQUksQ0FBQ29DLG9CQUFvQixDQUFDLEVBQUUsQ0FBQztNQUM1RSxLQUFLLElBQUlWLFFBQVEsSUFBSXpDLEVBQUUsQ0FBQ3VCLG9CQUFvQixDQUFDLENBQUMsRUFBRTtRQUM5Q2tCLFFBQVEsQ0FBQ2pDLEtBQUssQ0FBQyxJQUFJLENBQUM7UUFDcEJYLGNBQWMsQ0FBQzRGLHFCQUFxQixDQUFDLElBQUksQ0FBQ2xFLG9CQUFvQixDQUFDLENBQUMsRUFBRWtCLFFBQVEsQ0FBQztNQUM3RTtJQUNGOztJQUVBO0lBQ0EsSUFBSXpDLEVBQUUsQ0FBQzBCLG1CQUFtQixDQUFDLENBQUMsRUFBRTtNQUM1QjFCLEVBQUUsQ0FBQzBCLG1CQUFtQixDQUFDLENBQUMsQ0FBQ2xCLEtBQUssQ0FBQyxJQUFJLENBQUM7TUFDcEMsSUFBSSxJQUFJLENBQUNrQixtQkFBbUIsQ0FBQyxDQUFDLEtBQUtYLFNBQVMsRUFBRSxJQUFJLENBQUNrQyxtQkFBbUIsQ0FBQ2pELEVBQUUsQ0FBQzBCLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxDQUFDO01BQzVGLElBQUksQ0FBQ0EsbUJBQW1CLENBQUMsQ0FBQyxDQUFDMkQsS0FBSyxDQUFDckYsRUFBRSxDQUFDMEIsbUJBQW1CLENBQUMsQ0FBQyxDQUFDO0lBQ2pFOztJQUVBO0lBQ0EsSUFBSSxDQUFDUyxhQUFhLENBQUN1RCxpQkFBUSxDQUFDQyxTQUFTLENBQUMsSUFBSSxDQUFDMUQsYUFBYSxDQUFDLENBQUMsRUFBRWpDLEVBQUUsQ0FBQ2lDLGFBQWEsQ0FBQyxDQUFDLEVBQUUsRUFBQzJELFdBQVcsRUFBRSxJQUFJLEVBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBRTtJQUN4RyxJQUFJLENBQUN0RCxhQUFhLENBQUNvRCxpQkFBUSxDQUFDQyxTQUFTLENBQUMsSUFBSSxDQUFDdkQsYUFBYSxDQUFDLENBQUMsRUFBRXBDLEVBQUUsQ0FBQ29DLGFBQWEsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNoRixJQUFJLENBQUNnQyxPQUFPLENBQUNzQixpQkFBUSxDQUFDQyxTQUFTLENBQUMsSUFBSSxDQUFDekIsT0FBTyxDQUFDLENBQUMsRUFBRWxFLEVBQUUsQ0FBQ2tFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5RCxJQUFJLENBQUNLLFdBQVcsQ0FBQ21CLGlCQUFRLENBQUNDLFNBQVMsQ0FBQyxJQUFJLENBQUN0QixXQUFXLENBQUMsQ0FBQyxFQUFFckUsRUFBRSxDQUFDcUUsV0FBVyxDQUFDLENBQUMsRUFBRSxFQUFDdUIsV0FBVyxFQUFFLEtBQUssRUFBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2xHLElBQUksQ0FBQ3BCLFdBQVcsQ0FBQ2tCLGlCQUFRLENBQUNDLFNBQVMsQ0FBQyxJQUFJLENBQUNoRSxXQUFXLENBQUMsQ0FBQyxFQUFFM0IsRUFBRSxDQUFDMkIsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzFFLElBQUksQ0FBQzhDLFlBQVksQ0FBQ2lCLGlCQUFRLENBQUNDLFNBQVMsQ0FBQyxJQUFJLENBQUM5RCxZQUFZLENBQUMsQ0FBQyxFQUFFN0IsRUFBRSxDQUFDNkIsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzdFLElBQUksQ0FBQytDLGdCQUFnQixDQUFDYyxpQkFBUSxDQUFDQyxTQUFTLENBQUMsSUFBSSxDQUFDakIsZ0JBQWdCLENBQUMsQ0FBQyxFQUFFMUUsRUFBRSxDQUFDMEUsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDekYsSUFBSSxDQUFDRyxlQUFlLENBQUNhLGlCQUFRLENBQUNDLFNBQVMsQ0FBQyxJQUFJLENBQUM3RCxlQUFlLENBQUMsQ0FBQyxFQUFFOUIsRUFBRSxDQUFDOEIsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RGLElBQUksQ0FBQ2tELGtCQUFrQixDQUFDVSxpQkFBUSxDQUFDQyxTQUFTLENBQUMsSUFBSSxDQUFDYixrQkFBa0IsQ0FBQyxDQUFDLEVBQUU5RSxFQUFFLENBQUM4RSxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMvRixJQUFJLENBQUNLLFdBQVcsQ0FBQ08saUJBQVEsQ0FBQ0MsU0FBUyxDQUFDLElBQUksQ0FBQ1YsV0FBVyxDQUFDLENBQUMsRUFBRWpGLEVBQUUsQ0FBQ2lGLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7SUFFMUUsT0FBTyxJQUFJLENBQUMsQ0FBRTtFQUNoQjs7RUFFQTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0VBQ0VyRCxRQUFRQSxDQUFDaUUsTUFBTSxHQUFHLENBQUMsRUFBRUMsT0FBTyxHQUFHLEtBQUssRUFBVTtJQUM1QyxJQUFJQyxHQUFHLEdBQUcsRUFBRTs7SUFFWjtJQUNBO0lBQ0EsSUFBSUQsT0FBTyxFQUFFO01BQ1hDLEdBQUcsSUFBSSxJQUFJLENBQUNDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsSUFBSTtNQUM1QkQsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDRSxjQUFjLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQ0MsUUFBUSxDQUFDLENBQUMsQ0FBQ0MsWUFBWSxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUNDLG9CQUFvQixDQUFDLENBQUMsSUFBSSxJQUFJO01BQ3BHTCxHQUFHLElBQUksSUFBSSxDQUFDRSxjQUFjLENBQUMsQ0FBQyxHQUFHLElBQUk7TUFDbkNGLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQ3BELGlCQUFpQixDQUFDLENBQUMsR0FBRyxJQUFJLENBQUNBLGlCQUFpQixDQUFDLENBQUMsQ0FBQ2YsUUFBUSxDQUFDLENBQUMsR0FBRyxFQUFFLElBQUksSUFBSTtNQUNuRm1FLEdBQUcsSUFBSSxJQUFJLENBQUN4RCxpQkFBaUIsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDQSxpQkFBaUIsQ0FBQyxDQUFDLENBQUNYLFFBQVEsQ0FBQyxDQUFDLEdBQUcsRUFBRTtNQUMxRSxPQUFPbUUsR0FBRztJQUNaOztJQUVBO0lBQ0FBLEdBQUcsSUFBSSxLQUFLLENBQUNuRSxRQUFRLENBQUNpRSxNQUFNLENBQUMsR0FBRyxJQUFJO0lBQ3BDRSxHQUFHLElBQUlMLGlCQUFRLENBQUNXLE1BQU0sQ0FBQyxhQUFhLEVBQUUsSUFBSSxDQUFDcEUsYUFBYSxDQUFDLENBQUMsRUFBRTRELE1BQU0sQ0FBQztJQUNuRUUsR0FBRyxJQUFJTCxpQkFBUSxDQUFDVyxNQUFNLENBQUMsaUJBQWlCLEVBQUUsSUFBSSxDQUFDOUQsaUJBQWlCLENBQUMsQ0FBQyxFQUFFc0QsTUFBTSxDQUFDO0lBQzNFLElBQUksSUFBSSxDQUFDdEUsb0JBQW9CLENBQUMsQ0FBQyxLQUFLUixTQUFTLEVBQUU7TUFDN0NnRixHQUFHLElBQUlMLGlCQUFRLENBQUNXLE1BQU0sQ0FBQyxvQkFBb0IsRUFBRSxFQUFFLEVBQUVSLE1BQU0sQ0FBQztNQUN4RCxLQUFLLElBQUl4RixDQUFDLEdBQUcsQ0FBQyxFQUFFQSxDQUFDLEdBQUcsSUFBSSxDQUFDa0Isb0JBQW9CLENBQUMsQ0FBQyxDQUFDakIsTUFBTSxFQUFFRCxDQUFDLEVBQUUsRUFBRTtRQUMzRDBGLEdBQUcsSUFBSUwsaUJBQVEsQ0FBQ1csTUFBTSxDQUFDaEcsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEVBQUV3RixNQUFNLEdBQUcsQ0FBQyxDQUFDO1FBQzdDRSxHQUFHLElBQUksSUFBSSxDQUFDeEUsb0JBQW9CLENBQUMsQ0FBQyxDQUFDbEIsQ0FBQyxDQUFDLENBQUN1QixRQUFRLENBQUNpRSxNQUFNLEdBQUcsQ0FBQyxDQUFDLEdBQUcsSUFBSTtNQUNuRTtJQUNGO0lBQ0FFLEdBQUcsSUFBSUwsaUJBQVEsQ0FBQ1csTUFBTSxDQUFDLGFBQWEsRUFBRSxJQUFJLENBQUNqRSxhQUFhLENBQUMsQ0FBQyxFQUFFeUQsTUFBTSxDQUFDO0lBQ25FRSxHQUFHLElBQUlMLGlCQUFRLENBQUNXLE1BQU0sQ0FBQyxpQkFBaUIsRUFBRSxJQUFJLENBQUMxRCxpQkFBaUIsQ0FBQyxDQUFDLEVBQUVrRCxNQUFNLENBQUM7SUFDM0UsSUFBSSxJQUFJLENBQUNuRSxtQkFBbUIsQ0FBQyxDQUFDLEtBQUtYLFNBQVMsRUFBRTtNQUM1Q2dGLEdBQUcsSUFBSUwsaUJBQVEsQ0FBQ1csTUFBTSxDQUFDLG1CQUFtQixFQUFFLEVBQUUsRUFBRVIsTUFBTSxDQUFDO01BQ3ZERSxHQUFHLElBQUksSUFBSSxDQUFDckUsbUJBQW1CLENBQUMsQ0FBQyxDQUFDRSxRQUFRLENBQUNpRSxNQUFNLEdBQUcsQ0FBQyxDQUFDLEdBQUcsSUFBSTtJQUMvRDtJQUNBRSxHQUFHLElBQUlMLGlCQUFRLENBQUNXLE1BQU0sQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDbkMsT0FBTyxDQUFDLENBQUMsRUFBRTJCLE1BQU0sQ0FBQztJQUN0REUsR0FBRyxJQUFJTCxpQkFBUSxDQUFDVyxNQUFNLENBQUMsV0FBVyxFQUFFLElBQUksQ0FBQ2hDLFdBQVcsQ0FBQyxDQUFDLEVBQUV3QixNQUFNLENBQUM7SUFDL0RFLEdBQUcsSUFBSUwsaUJBQVEsQ0FBQ1csTUFBTSxDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUMxRSxXQUFXLENBQUMsQ0FBQyxFQUFFa0UsTUFBTSxDQUFDO0lBQy9ERSxHQUFHLElBQUlMLGlCQUFRLENBQUNXLE1BQU0sQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUFDeEUsWUFBWSxDQUFDLENBQUMsRUFBRWdFLE1BQU0sQ0FBQztJQUNqRUUsR0FBRyxJQUFJTCxpQkFBUSxDQUFDVyxNQUFNLENBQUMsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDM0IsZ0JBQWdCLENBQUMsQ0FBQyxFQUFFbUIsTUFBTSxDQUFDO0lBQ3pFRSxHQUFHLElBQUlMLGlCQUFRLENBQUNXLE1BQU0sQ0FBQyxlQUFlLEVBQUUsSUFBSSxDQUFDdkUsZUFBZSxDQUFDLENBQUMsRUFBRStELE1BQU0sQ0FBQztJQUN2RUUsR0FBRyxJQUFJTCxpQkFBUSxDQUFDVyxNQUFNLENBQUMsbUJBQW1CLEVBQUUsSUFBSSxDQUFDdkIsa0JBQWtCLENBQUMsQ0FBQyxFQUFFZSxNQUFNLENBQUM7SUFDOUVFLEdBQUcsSUFBSUwsaUJBQVEsQ0FBQ1csTUFBTSxDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUNwQixXQUFXLENBQUMsQ0FBQyxFQUFFWSxNQUFNLENBQUM7SUFDL0QsT0FBT0UsR0FBRyxDQUFDM0YsS0FBSyxDQUFDLENBQUMsRUFBRTJGLEdBQUcsQ0FBQ3pGLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFFO0VBQ3hDOztFQUVBO0VBQ0EsT0FBaUJtRixxQkFBcUJBLENBQUMzQyxTQUFTLEVBQUVMLFFBQVEsRUFBRTtJQUMxRCxLQUFLLElBQUk2RCxTQUFTLElBQUl4RCxTQUFTLEVBQUU7TUFDL0IsSUFBSXdELFNBQVMsQ0FBQ0MsZUFBZSxDQUFDLENBQUMsS0FBSzlELFFBQVEsQ0FBQzhELGVBQWUsQ0FBQyxDQUFDLElBQUlELFNBQVMsQ0FBQ0Usa0JBQWtCLENBQUMsQ0FBQyxLQUFLL0QsUUFBUSxDQUFDK0Qsa0JBQWtCLENBQUMsQ0FBQyxFQUFFO1FBQ2xJRixTQUFTLENBQUNqQixLQUFLLENBQUM1QyxRQUFRLENBQUM7UUFDekI7TUFDRjtJQUNGO0lBQ0FLLFNBQVMsQ0FBQ3JCLElBQUksQ0FBQ2dCLFFBQVEsQ0FBQztFQUMxQjs7RUFFQTs7RUFFQWdFLFFBQVFBLENBQUMxRSxLQUFrQixFQUFrQjtJQUMzQyxLQUFLLENBQUMwRSxRQUFRLENBQUMxRSxLQUFLLENBQUM7SUFDckIsT0FBTyxJQUFJO0VBQ2I7O0VBRUEyRSxPQUFPQSxDQUFDQyxJQUFZLEVBQWtCO0lBQ3BDLEtBQUssQ0FBQ0QsT0FBTyxDQUFDQyxJQUFJLENBQUM7SUFDbkIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFDLFVBQVVBLENBQUNDLE9BQWUsRUFBa0I7SUFDMUMsS0FBSyxDQUFDRCxVQUFVLENBQUNDLE9BQU8sQ0FBQztJQUN6QixPQUFPLElBQUk7RUFDYjs7RUFFQUMsWUFBWUEsQ0FBQ0MsU0FBa0IsRUFBa0I7SUFDL0MsS0FBSyxDQUFDRCxZQUFZLENBQUNDLFNBQVMsQ0FBQztJQUM3QixPQUFPLElBQUk7RUFDYjs7RUFFQUMsWUFBWUEsQ0FBQ0MsU0FBaUIsRUFBa0I7SUFDOUMsS0FBSyxDQUFDRCxZQUFZLENBQUNDLFNBQVMsQ0FBQztJQUM3QixPQUFPLElBQUk7RUFDYjs7RUFFQUMsTUFBTUEsQ0FBQ0MsR0FBVyxFQUFrQjtJQUNsQyxLQUFLLENBQUNELE1BQU0sQ0FBQ0MsR0FBRyxDQUFDO0lBQ2pCLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxXQUFXQSxDQUFDQyxRQUFnQixFQUFrQjtJQUM1QyxLQUFLLENBQUNELFdBQVcsQ0FBQ0MsUUFBUSxDQUFDO0lBQzNCLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxRQUFRQSxDQUFDQyxLQUFjLEVBQWtCO0lBQ3ZDLEtBQUssQ0FBQ0QsUUFBUSxDQUFDQyxLQUFLLENBQUM7SUFDckIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFDLFlBQVlBLENBQUNDLFNBQWtCLEVBQWtCO0lBQy9DLEtBQUssQ0FBQ0QsWUFBWSxDQUFDQyxTQUFTLENBQUM7SUFDN0IsT0FBTyxJQUFJO0VBQ2I7O0VBRUFDLGNBQWNBLENBQUNDLFdBQW9CLEVBQWtCO0lBQ25ELEtBQUssQ0FBQ0QsY0FBYyxDQUFDQyxXQUFXLENBQUM7SUFDakMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFDLFdBQVdBLENBQUNDLFFBQWlCLEVBQWtCO0lBQzdDLEtBQUssQ0FBQ0QsV0FBVyxDQUFDQyxRQUFRLENBQUM7SUFDM0IsT0FBTyxJQUFJO0VBQ2I7O0VBRUFDLG1CQUFtQkEsQ0FBQ0MsZ0JBQXdCLEVBQWtCO0lBQzVELEtBQUssQ0FBQ0QsbUJBQW1CLENBQUNDLGdCQUFnQixDQUFDO0lBQzNDLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxhQUFhQSxDQUFDQyxVQUFrQixFQUFrQjtJQUNoRCxLQUFLLENBQUNELGFBQWEsQ0FBQ0MsVUFBVSxDQUFDO0lBQy9CLE9BQU8sSUFBSTtFQUNiOztFQUVBQyx1QkFBdUJBLENBQUNDLG9CQUE0QixFQUFrQjtJQUNwRSxLQUFLLENBQUNELHVCQUF1QixDQUFDQyxvQkFBb0IsQ0FBQztJQUNuRCxPQUFPLElBQUk7RUFDYjs7RUFFQUMsb0JBQW9CQSxDQUFDQyxpQkFBeUIsRUFBa0I7SUFDOUQsS0FBSyxDQUFDRCxvQkFBb0IsQ0FBQ0MsaUJBQWlCLENBQUM7SUFDN0MsT0FBTyxJQUFJO0VBQ2I7O0VBRUFDLG9CQUFvQkEsQ0FBQ0MsaUJBQTBCLEVBQWtCO0lBQy9ELEtBQUssQ0FBQ0Qsb0JBQW9CLENBQUNDLGlCQUFpQixDQUFDO0lBQzdDLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxNQUFNQSxDQUFDQyxHQUFXLEVBQWtCO0lBQ2xDLEtBQUssQ0FBQ0QsTUFBTSxDQUFDQyxHQUFHLENBQUM7SUFDakIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFDLFVBQVVBLENBQUNDLE9BQWUsRUFBa0I7SUFDMUMsS0FBSyxDQUFDRCxVQUFVLENBQUNDLE9BQU8sQ0FBQztJQUN6QixPQUFPLElBQUk7RUFDYjs7RUFFQUMsWUFBWUEsQ0FBQ0MsU0FBaUIsRUFBa0I7SUFDOUMsS0FBSyxDQUFDRCxZQUFZLENBQUNDLFNBQVMsQ0FBQztJQUM3QixPQUFPLElBQUk7RUFDYjs7RUFFQUMsY0FBY0EsQ0FBQ0MsV0FBbUIsRUFBa0I7SUFDbEQsS0FBSyxDQUFDRCxjQUFjLENBQUNDLFdBQVcsQ0FBQztJQUNqQyxPQUFPLElBQUk7RUFDYjs7RUFFQUMsZUFBZUEsQ0FBQ0MsWUFBb0IsRUFBa0I7SUFDcEQsS0FBSyxDQUFDRCxlQUFlLENBQUNDLFlBQVksQ0FBQztJQUNuQyxPQUFPLElBQUk7RUFDYjs7RUFFQUMsT0FBT0EsQ0FBQ0MsSUFBWSxFQUFrQjtJQUNwQyxLQUFLLENBQUNELE9BQU8sQ0FBQ0MsSUFBSSxDQUFDO0lBQ25CLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxTQUFTQSxDQUFDQyxNQUFjLEVBQWtCO0lBQ3hDLEtBQUssQ0FBQ0QsU0FBUyxDQUFDQyxNQUFNLENBQUM7SUFDdkIsT0FBTyxJQUFJO0VBQ2I7O0VBRUF6RixTQUFTQSxDQUFDakQsTUFBc0IsRUFBa0I7SUFDaEQsS0FBSyxDQUFDaUQsU0FBUyxDQUFDakQsTUFBTSxDQUFDO0lBQ3ZCLE9BQU8sSUFBSTtFQUNiOztFQUVBcUQsVUFBVUEsQ0FBQ25ELE9BQXVCLEVBQWtCO0lBQ2xELEtBQUssQ0FBQ21ELFVBQVUsQ0FBQ25ELE9BQU8sQ0FBQztJQUN6QixPQUFPLElBQUk7RUFDYjs7RUFFQXlJLGdCQUFnQkEsQ0FBQ0MsYUFBdUIsRUFBa0I7SUFDeEQsS0FBSyxDQUFDRCxnQkFBZ0IsQ0FBQ0MsYUFBYSxDQUFDO0lBQ3JDLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxXQUFXQSxDQUFDQyxRQUFnQixFQUFrQjtJQUM1QyxLQUFLLENBQUNELFdBQVcsQ0FBQ0MsUUFBUSxDQUFDO0lBQzNCLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxRQUFRQSxDQUFDQyxLQUFpQixFQUFrQjtJQUMxQyxLQUFLLENBQUNELFFBQVEsQ0FBQ0MsS0FBSyxDQUFDO0lBQ3JCLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxnQkFBZ0JBLENBQUNDLGFBQWtCLEVBQWtCO0lBQ25ELEtBQUssQ0FBQ0QsZ0JBQWdCLENBQUNDLGFBQWEsQ0FBQztJQUNyQyxPQUFPLElBQUk7RUFDYjs7RUFFQUMsaUJBQWlCQSxDQUFDQyxjQUFtQixFQUFrQjtJQUNyRCxLQUFLLENBQUNELGlCQUFpQixDQUFDQyxjQUFjLENBQUM7SUFDdkMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFDLGdCQUFnQkEsQ0FBQ0MsYUFBc0IsRUFBa0I7SUFDdkQsS0FBSyxDQUFDRCxnQkFBZ0IsQ0FBQ0MsYUFBYSxDQUFDO0lBQ3JDLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxXQUFXQSxDQUFDQyxRQUFpQixFQUFrQjtJQUM3QyxLQUFLLENBQUNELFdBQVcsQ0FBQ0MsUUFBUSxDQUFDO0lBQzNCLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxtQkFBbUJBLENBQUNDLGdCQUF3QixFQUFrQjtJQUM1RCxLQUFLLENBQUNELG1CQUFtQixDQUFDQyxnQkFBZ0IsQ0FBQztJQUMzQyxPQUFPLElBQUk7RUFDYjs7RUFFQUMsaUJBQWlCQSxDQUFDQyxjQUFzQixFQUFrQjtJQUN4RCxLQUFLLENBQUNELGlCQUFpQixDQUFDQyxjQUFjLENBQUM7SUFDdkMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFDLHFCQUFxQkEsQ0FBQ0Msa0JBQTBCLEVBQWtCO0lBQ2hFLEtBQUssQ0FBQ0QscUJBQXFCLENBQUNDLGtCQUFrQixDQUFDO0lBQy9DLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxtQkFBbUJBLENBQUNDLGdCQUF3QixFQUFrQjtJQUM1RCxLQUFLLENBQUNELG1CQUFtQixDQUFDQyxnQkFBZ0IsQ0FBQztJQUMzQyxPQUFPLElBQUk7RUFDYjs7RUFFQUMsYUFBYUEsQ0FBQ0MsVUFBb0IsRUFBa0I7SUFDbEQsS0FBSyxDQUFDRCxhQUFhLENBQUNDLFVBQVUsQ0FBQztJQUMvQixPQUFPLElBQUk7RUFDYjtBQUNGLENBQUNDLE9BQUEsQ0FBQUMsT0FBQSxHQUFBbEwsY0FBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroWalletConfig.d.ts b/dist/src/main/ts/wallet/model/MoneroWalletConfig.d.ts new file mode 100644 index 000000000..538f3ce0d --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroWalletConfig.d.ts @@ -0,0 +1,122 @@ +import MoneroConnectionManager from "../../common/MoneroConnectionManager"; +import MoneroNetworkType from "../../daemon/model/MoneroNetworkType"; +import MoneroRpcConnection from "../../common/MoneroRpcConnection"; +/** + * Configuration to create a Monero wallet. + */ +export default class MoneroWalletConfig { + /** Path to the wallet to open or create. */ + path: string; + /** Password of the wallet to open or create. */ + password: string; + /** Network type of the wallet to open or create. */ + networkType: MoneroNetworkType; + /** Server config to monerod or monero-wallet-rpc. */ + server: string | Partial; + /** Govern the wallet's server connection. */ + connectionManager: MoneroConnectionManager; + /** Seed of the wallet to ceate (random wallet created if neither seed nor keys given). */ + seed: string; + /** Offset to derive a new seed from the given seed to recover a secret wallet. */ + seedOffset: string; + /** Indicates if the wallet seed is multisig. */ + isMultisig: boolean; + /** Primary address of the wallet to create (only provide if restoring from keys). */ + primaryAddress: string; + /** Private view key of the wallet to create. */ + privateViewKey: string; + /** Private spend key of the wallet to create. */ + privateSpendKey: string; + /** Block height to start scanning from (defaults to 0 unless generating random wallet). */ + restoreHeight: number; + /** Language of the wallet's seed phrase (defaults to "English" or auto-detected). */ + language: string; + /** Specifies if the currently open RPC wallet should be saved before being closed. */ + saveCurrent: boolean; + /** Proxies wallet operations to a worker in order to not block the main thread (default true). */ + proxyToWorker: boolean; + /** File system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser). */ + fs: any; + /** Wallet keys data to open. */ + keysData: Uint8Array; + /** Wallet cache data to open. */ + cacheData: Uint8Array; + /** Number of accounts to scan (optional). */ + accountLookahead: number; + /** Number of subaddresses to scan per account (optional). */ + subaddressLookahead: number; + /** Command to start monero-wallet-rpc as a child process. */ + cmd: string[]; + /** + * Construct a configuration to open or create a wallet. + * + * @param {Partial} [config] - MoneroWalletConfig or equivalent config object + * @param {string} [config.path] - path of the wallet to open or create + * @param {string} [config.password] - password of the wallet to open + * @param {string|number} [config.networkType] - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) + * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given) + * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed phrase + * @param {boolean} [config.isMultisig] - restore multisig wallet from seed + * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys) + * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional) + * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional) + * @param {number} [config.restoreHeight] - block height to start scanning from (defaults to 0 unless generating random wallet) + * @param {string} [config.language] - language of the wallet's seed phrase (defaults to "English" or auto-detected) + * @param {number} [config.accountLookahead] - number of accounts to scan (optional) + * @param {number} [config.subaddressLookahead] - number of subaddresses to scan per account (optional) + * @param {string|Partial} [config.server] - uri or MoneroRpcConnection to the wallet's server (optional) + * @param {MoneroConnectionManager} [config.connectionManager] - manage connections to monerod (optional) + * @param {boolean} [config.rejectUnauthorized] - reject self-signed server certificates if true (default true) + * @param {Uint8Array} [config.keysData] - wallet keys data to open (optional) + * @param {Uint8Array} [config.cacheData] - wallet cache data to open (optional) + * @param {boolean} [config.proxyToWorker] - proxies wallet operations to a worker in order to not block the main thread (default true) + * @param {any} [config.fs] - file system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser) + * @param {boolean} [config.saveCurrent] - specifies if the current RPC wallet should be saved before being closed + * @param {number} [config.accountLookahead] - number of accounts to scan (optional) + * @param {number} [config.subaddressLookahead] - number of subaddresses to scan per account (optional) + * @param {string[]} [config.cmd] - command to start wallet daemon (optional) + */ + constructor(config?: Partial); + copy(): MoneroWalletConfig; + toJson(): any; + getPath(): string; + setPath(path: string): MoneroWalletConfig; + getPassword(): string; + setPassword(password: any): MoneroWalletConfig; + getNetworkType(): MoneroNetworkType; + setNetworkType(networkTypeOrStr: MoneroNetworkType | string): MoneroWalletConfig; + getServer(): MoneroRpcConnection; + setServer(server: Partial | string): MoneroWalletConfig; + getConnectionManager(): MoneroConnectionManager; + setConnectionManager(connectionManager: MoneroConnectionManager): MoneroWalletConfig; + getSeed(): string; + setSeed(seed: string): MoneroWalletConfig; + getSeedOffset(): string; + setSeedOffset(seedOffset: string): MoneroWalletConfig; + getIsMultisig(): boolean; + setIsMultisig(isMultisig: boolean): MoneroWalletConfig; + getPrimaryAddress(): string; + setPrimaryAddress(primaryAddress: string): this; + getPrivateViewKey(): string; + setPrivateViewKey(privateViewKey: any): MoneroWalletConfig; + getPrivateSpendKey(): string; + setPrivateSpendKey(privateSpendKey: string): MoneroWalletConfig; + getRestoreHeight(): number; + setRestoreHeight(restoreHeight: number): MoneroWalletConfig; + getLanguage(): string; + setLanguage(language: string): MoneroWalletConfig; + getSaveCurrent(): boolean; + setSaveCurrent(saveCurrent: boolean): MoneroWalletConfig; + getProxyToWorker(): boolean; + setProxyToWorker(proxyToWorker: boolean): MoneroWalletConfig; + getFs(): any; + setFs(fs: any): this; + getKeysData(): Uint8Array; + setKeysData(keysData: Uint8Array): MoneroWalletConfig; + getCacheData(): Uint8Array; + setCacheData(cacheData: Uint8Array): MoneroWalletConfig; + getAccountLookahead(): number; + setAccountLookahead(accountLookahead: number): MoneroWalletConfig; + getSubaddressLookahead(): number; + setSubaddressLookahead(subaddressLookahead: number): MoneroWalletConfig; +} diff --git a/dist/src/main/ts/wallet/model/MoneroWalletConfig.js b/dist/src/main/ts/wallet/model/MoneroWalletConfig.js new file mode 100644 index 000000000..3b9ec8f6f --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroWalletConfig.js @@ -0,0 +1,305 @@ +"use strict";var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; +var _MoneroNetworkType = _interopRequireDefault(require("../../daemon/model/MoneroNetworkType")); +var _MoneroRpcConnection = _interopRequireDefault(require("../../common/MoneroRpcConnection")); + + +/** + * Configuration to create a Monero wallet. + */ +class MoneroWalletConfig { + + /** Path to the wallet to open or create. */ + + + /** Password of the wallet to open or create. */ + + + /** Network type of the wallet to open or create. */ + + + /** Server config to monerod or monero-wallet-rpc. */ + + + /** Govern the wallet's server connection. */ + + + /** Seed of the wallet to ceate (random wallet created if neither seed nor keys given). */ + + + /** Offset to derive a new seed from the given seed to recover a secret wallet. */ + + + /** Indicates if the wallet seed is multisig. */ + + + /** Primary address of the wallet to create (only provide if restoring from keys). */ + + + /** Private view key of the wallet to create. */ + + + /** Private spend key of the wallet to create. */ + + + /** Block height to start scanning from (defaults to 0 unless generating random wallet). */ + + + /** Language of the wallet's seed phrase (defaults to "English" or auto-detected). */ + + + /** Specifies if the currently open RPC wallet should be saved before being closed. */ + + + /** Proxies wallet operations to a worker in order to not block the main thread (default true). */ + + + /** File system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser). */ + + + /** Wallet keys data to open. */ + + + /** Wallet cache data to open. */ + + + /** Number of accounts to scan (optional). */ + + + /** Number of subaddresses to scan per account (optional). */ + + + /** Command to start monero-wallet-rpc as a child process. */ + + + /** + * Construct a configuration to open or create a wallet. + * + * @param {Partial} [config] - MoneroWalletConfig or equivalent config object + * @param {string} [config.path] - path of the wallet to open or create + * @param {string} [config.password] - password of the wallet to open + * @param {string|number} [config.networkType] - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) + * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given) + * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed phrase + * @param {boolean} [config.isMultisig] - restore multisig wallet from seed + * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys) + * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional) + * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional) + * @param {number} [config.restoreHeight] - block height to start scanning from (defaults to 0 unless generating random wallet) + * @param {string} [config.language] - language of the wallet's seed phrase (defaults to "English" or auto-detected) + * @param {number} [config.accountLookahead] - number of accounts to scan (optional) + * @param {number} [config.subaddressLookahead] - number of subaddresses to scan per account (optional) + * @param {string|Partial} [config.server] - uri or MoneroRpcConnection to the wallet's server (optional) + * @param {MoneroConnectionManager} [config.connectionManager] - manage connections to monerod (optional) + * @param {boolean} [config.rejectUnauthorized] - reject self-signed server certificates if true (default true) + * @param {Uint8Array} [config.keysData] - wallet keys data to open (optional) + * @param {Uint8Array} [config.cacheData] - wallet cache data to open (optional) + * @param {boolean} [config.proxyToWorker] - proxies wallet operations to a worker in order to not block the main thread (default true) + * @param {any} [config.fs] - file system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser) + * @param {boolean} [config.saveCurrent] - specifies if the current RPC wallet should be saved before being closed + * @param {number} [config.accountLookahead] - number of accounts to scan (optional) + * @param {number} [config.subaddressLookahead] - number of subaddresses to scan per account (optional) + * @param {string[]} [config.cmd] - command to start wallet daemon (optional) + */ + constructor(config) { + Object.assign(this, config); + + // normalize config + if (this.server) this.setServer(this.server); + this.setProxyToWorker(this.proxyToWorker); + if (this.networkType !== undefined) this.networkType = _MoneroNetworkType.default.from(this.networkType); + } + + copy() { + return new MoneroWalletConfig(this); + } + + toJson() { + let json = Object.assign({}, this); + if (json.server) json.server = json.server.toJson(); + json.fs = undefined; + json.connectionManager = undefined; + return json; + } + + getPath() { + return this.path; + } + + setPath(path) { + this.path = path; + return this; + } + + getPassword() { + return this.password; + } + + setPassword(password) { + this.password = password; + return this; + } + + getNetworkType() { + return this.networkType; + } + + setNetworkType(networkTypeOrStr) { + this.networkType = networkTypeOrStr === undefined ? undefined : _MoneroNetworkType.default.from(networkTypeOrStr); + return this; + } + + getServer() { + return this.server; + } + + setServer(server) { + if (server && !(server instanceof _MoneroRpcConnection.default)) server = new _MoneroRpcConnection.default(server); + this.server = server; + return this; + } + + getConnectionManager() { + return this.connectionManager; + } + + setConnectionManager(connectionManager) { + this.connectionManager = connectionManager; + return this; + } + + getSeed() { + return this.seed; + } + + setSeed(seed) { + this.seed = seed; + return this; + } + + getSeedOffset() { + return this.seedOffset; + } + + setSeedOffset(seedOffset) { + this.seedOffset = seedOffset; + return this; + } + + getIsMultisig() { + return this.isMultisig; + } + + setIsMultisig(isMultisig) { + this.isMultisig = isMultisig; + return this; + } + + getPrimaryAddress() { + return this.primaryAddress; + } + + setPrimaryAddress(primaryAddress) { + this.primaryAddress = primaryAddress; + return this; + } + + getPrivateViewKey() { + return this.privateViewKey; + } + + setPrivateViewKey(privateViewKey) { + this.privateViewKey = privateViewKey; + return this; + } + + getPrivateSpendKey() { + return this.privateSpendKey; + } + + setPrivateSpendKey(privateSpendKey) { + this.privateSpendKey = privateSpendKey; + return this; + } + + getRestoreHeight() { + return this.restoreHeight; + } + + setRestoreHeight(restoreHeight) { + this.restoreHeight = restoreHeight; + return this; + } + + getLanguage() { + return this.language; + } + + setLanguage(language) { + this.language = language; + return this; + } + + getSaveCurrent() { + return this.saveCurrent; + } + + setSaveCurrent(saveCurrent) { + this.saveCurrent = saveCurrent; + return this; + } + + getProxyToWorker() { + return this.proxyToWorker; + } + + setProxyToWorker(proxyToWorker) { + this.proxyToWorker = proxyToWorker; + return this; + } + + getFs() { + return this.fs; + } + + setFs(fs) { + this.fs = fs; + return this; + } + + getKeysData() { + return this.keysData; + } + + setKeysData(keysData) { + this.keysData = keysData; + return this; + } + + getCacheData() { + return this.cacheData; + } + + setCacheData(cacheData) { + this.cacheData = cacheData; + return this; + } + + getAccountLookahead() { + return this.accountLookahead; + } + + setAccountLookahead(accountLookahead) { + this.accountLookahead = accountLookahead; + return this; + } + + getSubaddressLookahead() { + return this.subaddressLookahead; + } + + setSubaddressLookahead(subaddressLookahead) { + this.subaddressLookahead = subaddressLookahead; + return this; + } +}exports.default = MoneroWalletConfig; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfTW9uZXJvTmV0d29ya1R5cGUiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9Nb25lcm9ScGNDb25uZWN0aW9uIiwiTW9uZXJvV2FsbGV0Q29uZmlnIiwiY29uc3RydWN0b3IiLCJjb25maWciLCJPYmplY3QiLCJhc3NpZ24iLCJzZXJ2ZXIiLCJzZXRTZXJ2ZXIiLCJzZXRQcm94eVRvV29ya2VyIiwicHJveHlUb1dvcmtlciIsIm5ldHdvcmtUeXBlIiwidW5kZWZpbmVkIiwiTW9uZXJvTmV0d29ya1R5cGUiLCJmcm9tIiwiY29weSIsInRvSnNvbiIsImpzb24iLCJmcyIsImNvbm5lY3Rpb25NYW5hZ2VyIiwiZ2V0UGF0aCIsInBhdGgiLCJzZXRQYXRoIiwiZ2V0UGFzc3dvcmQiLCJwYXNzd29yZCIsInNldFBhc3N3b3JkIiwiZ2V0TmV0d29ya1R5cGUiLCJzZXROZXR3b3JrVHlwZSIsIm5ldHdvcmtUeXBlT3JTdHIiLCJnZXRTZXJ2ZXIiLCJNb25lcm9ScGNDb25uZWN0aW9uIiwiZ2V0Q29ubmVjdGlvbk1hbmFnZXIiLCJzZXRDb25uZWN0aW9uTWFuYWdlciIsImdldFNlZWQiLCJzZWVkIiwic2V0U2VlZCIsImdldFNlZWRPZmZzZXQiLCJzZWVkT2Zmc2V0Iiwic2V0U2VlZE9mZnNldCIsImdldElzTXVsdGlzaWciLCJpc011bHRpc2lnIiwic2V0SXNNdWx0aXNpZyIsImdldFByaW1hcnlBZGRyZXNzIiwicHJpbWFyeUFkZHJlc3MiLCJzZXRQcmltYXJ5QWRkcmVzcyIsImdldFByaXZhdGVWaWV3S2V5IiwicHJpdmF0ZVZpZXdLZXkiLCJzZXRQcml2YXRlVmlld0tleSIsImdldFByaXZhdGVTcGVuZEtleSIsInByaXZhdGVTcGVuZEtleSIsInNldFByaXZhdGVTcGVuZEtleSIsImdldFJlc3RvcmVIZWlnaHQiLCJyZXN0b3JlSGVpZ2h0Iiwic2V0UmVzdG9yZUhlaWdodCIsImdldExhbmd1YWdlIiwibGFuZ3VhZ2UiLCJzZXRMYW5ndWFnZSIsImdldFNhdmVDdXJyZW50Iiwic2F2ZUN1cnJlbnQiLCJzZXRTYXZlQ3VycmVudCIsImdldFByb3h5VG9Xb3JrZXIiLCJnZXRGcyIsInNldEZzIiwiZ2V0S2V5c0RhdGEiLCJrZXlzRGF0YSIsInNldEtleXNEYXRhIiwiZ2V0Q2FjaGVEYXRhIiwiY2FjaGVEYXRhIiwic2V0Q2FjaGVEYXRhIiwiZ2V0QWNjb3VudExvb2thaGVhZCIsImFjY291bnRMb29rYWhlYWQiLCJzZXRBY2NvdW50TG9va2FoZWFkIiwiZ2V0U3ViYWRkcmVzc0xvb2thaGVhZCIsInN1YmFkZHJlc3NMb29rYWhlYWQiLCJzZXRTdWJhZGRyZXNzTG9va2FoZWFkIiwiZXhwb3J0cyIsImRlZmF1bHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbWFpbi90cy93YWxsZXQvbW9kZWwvTW9uZXJvV2FsbGV0Q29uZmlnLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBNb25lcm9Db25uZWN0aW9uTWFuYWdlciBmcm9tIFwiLi4vLi4vY29tbW9uL01vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyXCI7XG5pbXBvcnQgTW9uZXJvTmV0d29ya1R5cGUgZnJvbSBcIi4uLy4uL2RhZW1vbi9tb2RlbC9Nb25lcm9OZXR3b3JrVHlwZVwiO1xuaW1wb3J0IE1vbmVyb1JwY0Nvbm5lY3Rpb24gZnJvbSBcIi4uLy4uL2NvbW1vbi9Nb25lcm9ScGNDb25uZWN0aW9uXCI7XG5pbXBvcnQgTW9uZXJvVXRpbHMgZnJvbSBcIi4uLy4uL2NvbW1vbi9Nb25lcm9VdGlsc1wiO1xuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gdG8gY3JlYXRlIGEgTW9uZXJvIHdhbGxldC5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTW9uZXJvV2FsbGV0Q29uZmlnIHtcblxuICAvKiogUGF0aCB0byB0aGUgd2FsbGV0IHRvIG9wZW4gb3IgY3JlYXRlLiAqL1xuICBwYXRoOiBzdHJpbmc7XG5cbiAgLyoqIFBhc3N3b3JkIG9mIHRoZSB3YWxsZXQgdG8gb3BlbiBvciBjcmVhdGUuICovXG4gIHBhc3N3b3JkOiBzdHJpbmc7XG5cbiAgLyoqIE5ldHdvcmsgdHlwZSBvZiB0aGUgd2FsbGV0IHRvIG9wZW4gb3IgY3JlYXRlLiAqL1xuICBuZXR3b3JrVHlwZTogTW9uZXJvTmV0d29ya1R5cGU7XG5cbiAgLyoqIFNlcnZlciBjb25maWcgdG8gbW9uZXJvZCBvciBtb25lcm8td2FsbGV0LXJwYy4gKi9cbiAgc2VydmVyOiBzdHJpbmcgfCBQYXJ0aWFsPE1vbmVyb1JwY0Nvbm5lY3Rpb24+O1xuXG4gIC8qKiBHb3Zlcm4gdGhlIHdhbGxldCdzIHNlcnZlciBjb25uZWN0aW9uLiAqL1xuICBjb25uZWN0aW9uTWFuYWdlcjogTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXI7XG5cbiAgLyoqIFNlZWQgb2YgdGhlIHdhbGxldCB0byBjZWF0ZSAocmFuZG9tIHdhbGxldCBjcmVhdGVkIGlmIG5laXRoZXIgc2VlZCBub3Iga2V5cyBnaXZlbikuICovXG4gIHNlZWQ6IHN0cmluZztcblxuICAvKiogT2Zmc2V0IHRvIGRlcml2ZSBhIG5ldyBzZWVkIGZyb20gdGhlIGdpdmVuIHNlZWQgdG8gcmVjb3ZlciBhIHNlY3JldCB3YWxsZXQuICovXG4gIHNlZWRPZmZzZXQ6IHN0cmluZztcblxuICAvKiogSW5kaWNhdGVzIGlmIHRoZSB3YWxsZXQgc2VlZCBpcyBtdWx0aXNpZy4gKi9cbiAgaXNNdWx0aXNpZzogYm9vbGVhbjtcblxuICAvKiogUHJpbWFyeSBhZGRyZXNzIG9mIHRoZSB3YWxsZXQgdG8gY3JlYXRlIChvbmx5IHByb3ZpZGUgaWYgcmVzdG9yaW5nIGZyb20ga2V5cykuICovXG4gIHByaW1hcnlBZGRyZXNzOiBzdHJpbmc7XG5cbiAgLyoqIFByaXZhdGUgdmlldyBrZXkgb2YgdGhlIHdhbGxldCB0byBjcmVhdGUuICovXG4gIHByaXZhdGVWaWV3S2V5OiBzdHJpbmc7XG5cbiAgLyoqIFByaXZhdGUgc3BlbmQga2V5IG9mIHRoZSB3YWxsZXQgdG8gY3JlYXRlLiAqL1xuICBwcml2YXRlU3BlbmRLZXk6IHN0cmluZztcblxuICAvKiogQmxvY2sgaGVpZ2h0IHRvIHN0YXJ0IHNjYW5uaW5nIGZyb20gKGRlZmF1bHRzIHRvIDAgdW5sZXNzIGdlbmVyYXRpbmcgcmFuZG9tIHdhbGxldCkuICovXG4gIHJlc3RvcmVIZWlnaHQ6IG51bWJlcjtcblxuICAvKiogTGFuZ3VhZ2Ugb2YgdGhlIHdhbGxldCdzIHNlZWQgcGhyYXNlIChkZWZhdWx0cyB0byBcIkVuZ2xpc2hcIiBvciBhdXRvLWRldGVjdGVkKS4gKi9cbiAgbGFuZ3VhZ2U6IHN0cmluZztcblxuICAvKiogU3BlY2lmaWVzIGlmIHRoZSBjdXJyZW50bHkgb3BlbiBSUEMgd2FsbGV0IHNob3VsZCBiZSBzYXZlZCBiZWZvcmUgYmVpbmcgY2xvc2VkLiAqL1xuICBzYXZlQ3VycmVudDogYm9vbGVhbjtcblxuICAvKiogUHJveGllcyB3YWxsZXQgb3BlcmF0aW9ucyB0byBhIHdvcmtlciBpbiBvcmRlciB0byBub3QgYmxvY2sgdGhlIG1haW4gdGhyZWFkIChkZWZhdWx0IHRydWUpLiAqL1xuICBwcm94eVRvV29ya2VyOiBib29sZWFuO1xuXG4gIC8qKiBGaWxlIHN5c3RlbSBjb21wYXRpYmxlIHdpdGggTm9kZS5qcyBgZnMucHJvbWlzZXNgIEFQSSAoZGVmYXVsdHMgdG8gZGlzayBvciBpbi1tZW1vcnkgRlMgaWYgYnJvd3NlcikuICovXG4gIGZzOiBhbnk7XG5cbiAgLyoqIFdhbGxldCBrZXlzIGRhdGEgdG8gb3Blbi4gKi9cbiAga2V5c0RhdGE6IFVpbnQ4QXJyYXk7XG5cbiAgLyoqIFdhbGxldCBjYWNoZSBkYXRhIHRvIG9wZW4uICovXG4gIGNhY2hlRGF0YTogVWludDhBcnJheTtcblxuICAvKiogTnVtYmVyIG9mIGFjY291bnRzIHRvIHNjYW4gKG9wdGlvbmFsKS4gKi9cbiAgYWNjb3VudExvb2thaGVhZDogbnVtYmVyO1xuXG4gIC8qKiBOdW1iZXIgb2Ygc3ViYWRkcmVzc2VzIHRvIHNjYW4gcGVyIGFjY291bnQgKG9wdGlvbmFsKS4gKi9cbiAgc3ViYWRkcmVzc0xvb2thaGVhZDogbnVtYmVyO1xuXG4gIC8qKiBDb21tYW5kIHRvIHN0YXJ0IG1vbmVyby13YWxsZXQtcnBjIGFzIGEgY2hpbGQgcHJvY2Vzcy4gKi9cbiAgY21kOiBzdHJpbmdbXTtcbiAgXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3QgYSBjb25maWd1cmF0aW9uIHRvIG9wZW4gb3IgY3JlYXRlIGEgd2FsbGV0LlxuICAgKiBcbiAgICogQHBhcmFtIHtQYXJ0aWFsPE1vbmVyb1dhbGxldENvbmZpZz59IFtjb25maWddIC0gTW9uZXJvV2FsbGV0Q29uZmlnIG9yIGVxdWl2YWxlbnQgY29uZmlnIG9iamVjdFxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2NvbmZpZy5wYXRoXSAtIHBhdGggb2YgdGhlIHdhbGxldCB0byBvcGVuIG9yIGNyZWF0ZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2NvbmZpZy5wYXNzd29yZF0gLSBwYXNzd29yZCBvZiB0aGUgd2FsbGV0IHRvIG9wZW5cbiAgICogQHBhcmFtIHtzdHJpbmd8bnVtYmVyfSBbY29uZmlnLm5ldHdvcmtUeXBlXSAtIG5ldHdvcmsgdHlwZSBvZiB0aGUgd2FsbGV0IHRvIG9wZW4gKG9uZSBvZiBcIm1haW5uZXRcIiwgXCJ0ZXN0bmV0XCIsIFwic3RhZ2VuZXRcIiBvciBNb25lcm9OZXR3b3JrVHlwZS5NQUlOTkVUfFRFU1RORVR8U1RBR0VORVQpXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbY29uZmlnLnNlZWRdIC0gc2VlZCBvZiB0aGUgd2FsbGV0IHRvIGNyZWF0ZSAob3B0aW9uYWwsIHJhbmRvbSB3YWxsZXQgY3JlYXRlZCBpZiBuZWl0aGVyIHNlZWQgbm9yIGtleXMgZ2l2ZW4pXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbY29uZmlnLnNlZWRPZmZzZXRdIC0gdGhlIG9mZnNldCB1c2VkIHRvIGRlcml2ZSBhIG5ldyBzZWVkIGZyb20gdGhlIGdpdmVuIHNlZWQgdG8gcmVjb3ZlciBhIHNlY3JldCB3YWxsZXQgZnJvbSB0aGUgc2VlZCBwaHJhc2VcbiAgICogQHBhcmFtIHtib29sZWFufSBbY29uZmlnLmlzTXVsdGlzaWddIC0gcmVzdG9yZSBtdWx0aXNpZyB3YWxsZXQgZnJvbSBzZWVkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbY29uZmlnLnByaW1hcnlBZGRyZXNzXSAtIHByaW1hcnkgYWRkcmVzcyBvZiB0aGUgd2FsbGV0IHRvIGNyZWF0ZSAob25seSBwcm92aWRlIGlmIHJlc3RvcmluZyBmcm9tIGtleXMpXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbY29uZmlnLnByaXZhdGVWaWV3S2V5XSAtIHByaXZhdGUgdmlldyBrZXkgb2YgdGhlIHdhbGxldCB0byBjcmVhdGUgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2NvbmZpZy5wcml2YXRlU3BlbmRLZXldIC0gcHJpdmF0ZSBzcGVuZCBrZXkgb2YgdGhlIHdhbGxldCB0byBjcmVhdGUgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbmZpZy5yZXN0b3JlSGVpZ2h0XSAtIGJsb2NrIGhlaWdodCB0byBzdGFydCBzY2FubmluZyBmcm9tIChkZWZhdWx0cyB0byAwIHVubGVzcyBnZW5lcmF0aW5nIHJhbmRvbSB3YWxsZXQpXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbY29uZmlnLmxhbmd1YWdlXSAtIGxhbmd1YWdlIG9mIHRoZSB3YWxsZXQncyBzZWVkIHBocmFzZSAoZGVmYXVsdHMgdG8gXCJFbmdsaXNoXCIgb3IgYXV0by1kZXRlY3RlZClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtjb25maWcuYWNjb3VudExvb2thaGVhZF0gLSAgbnVtYmVyIG9mIGFjY291bnRzIHRvIHNjYW4gKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbmZpZy5zdWJhZGRyZXNzTG9va2FoZWFkXSAtIG51bWJlciBvZiBzdWJhZGRyZXNzZXMgdG8gc2NhbiBwZXIgYWNjb3VudCAob3B0aW9uYWwpXG4gICAqIEBwYXJhbSB7c3RyaW5nfFBhcnRpYWw8TW9uZXJvUnBjQ29ubmVjdGlvbj59IFtjb25maWcuc2VydmVyXSAtIHVyaSBvciBNb25lcm9ScGNDb25uZWN0aW9uIHRvIHRoZSB3YWxsZXQncyBzZXJ2ZXIgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge01vbmVyb0Nvbm5lY3Rpb25NYW5hZ2VyfSBbY29uZmlnLmNvbm5lY3Rpb25NYW5hZ2VyXSAtIG1hbmFnZSBjb25uZWN0aW9ucyB0byBtb25lcm9kIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtib29sZWFufSBbY29uZmlnLnJlamVjdFVuYXV0aG9yaXplZF0gLSByZWplY3Qgc2VsZi1zaWduZWQgc2VydmVyIGNlcnRpZmljYXRlcyBpZiB0cnVlIChkZWZhdWx0IHRydWUpXG4gICAqIEBwYXJhbSB7VWludDhBcnJheX0gW2NvbmZpZy5rZXlzRGF0YV0gLSB3YWxsZXQga2V5cyBkYXRhIHRvIG9wZW4gKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge1VpbnQ4QXJyYXl9IFtjb25maWcuY2FjaGVEYXRhXSAtIHdhbGxldCBjYWNoZSBkYXRhIHRvIG9wZW4gKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtjb25maWcucHJveHlUb1dvcmtlcl0gLSBwcm94aWVzIHdhbGxldCBvcGVyYXRpb25zIHRvIGEgd29ya2VyIGluIG9yZGVyIHRvIG5vdCBibG9jayB0aGUgbWFpbiB0aHJlYWQgKGRlZmF1bHQgdHJ1ZSlcbiAgICogQHBhcmFtIHthbnl9IFtjb25maWcuZnNdIC0gZmlsZSBzeXN0ZW0gY29tcGF0aWJsZSB3aXRoIE5vZGUuanMgYGZzLnByb21pc2VzYCBBUEkgKGRlZmF1bHRzIHRvIGRpc2sgb3IgaW4tbWVtb3J5IEZTIGlmIGJyb3dzZXIpXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2NvbmZpZy5zYXZlQ3VycmVudF0gLSBzcGVjaWZpZXMgaWYgdGhlIGN1cnJlbnQgUlBDIHdhbGxldCBzaG91bGQgYmUgc2F2ZWQgYmVmb3JlIGJlaW5nIGNsb3NlZFxuICAgKiBAcGFyYW0ge251bWJlcn0gW2NvbmZpZy5hY2NvdW50TG9va2FoZWFkXSAtIG51bWJlciBvZiBhY2NvdW50cyB0byBzY2FuIChvcHRpb25hbClcbiAgICogQHBhcmFtIHtudW1iZXJ9IFtjb25maWcuc3ViYWRkcmVzc0xvb2thaGVhZF0gLSBudW1iZXIgb2Ygc3ViYWRkcmVzc2VzIHRvIHNjYW4gcGVyIGFjY291bnQgKG9wdGlvbmFsKVxuICAgKiBAcGFyYW0ge3N0cmluZ1tdfSBbY29uZmlnLmNtZF0gLSBjb21tYW5kIHRvIHN0YXJ0IHdhbGxldCBkYWVtb24gKG9wdGlvbmFsKVxuICAgKi9cbiAgY29uc3RydWN0b3IoY29uZmlnPzogUGFydGlhbDxNb25lcm9XYWxsZXRDb25maWc+KSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCBjb25maWcpO1xuXG4gICAgLy8gbm9ybWFsaXplIGNvbmZpZ1xuICAgIGlmICh0aGlzLnNlcnZlcikgdGhpcy5zZXRTZXJ2ZXIodGhpcy5zZXJ2ZXIpO1xuICAgIHRoaXMuc2V0UHJveHlUb1dvcmtlcih0aGlzLnByb3h5VG9Xb3JrZXIpO1xuICAgIGlmICh0aGlzLm5ldHdvcmtUeXBlICE9PSB1bmRlZmluZWQpIHRoaXMubmV0d29ya1R5cGUgPSBNb25lcm9OZXR3b3JrVHlwZS5mcm9tKHRoaXMubmV0d29ya1R5cGUpO1xuICB9XG5cbiAgY29weSgpOiBNb25lcm9XYWxsZXRDb25maWcge1xuICAgIHJldHVybiBuZXcgTW9uZXJvV2FsbGV0Q29uZmlnKHRoaXMpO1xuICB9XG4gIFxuICB0b0pzb24oKTogYW55IHtcbiAgICBsZXQganNvbjogYW55ID0gT2JqZWN0LmFzc2lnbih7fSwgdGhpcyk7XG4gICAgaWYgKGpzb24uc2VydmVyKSBqc29uLnNlcnZlciA9IGpzb24uc2VydmVyLnRvSnNvbigpO1xuICAgIGpzb24uZnMgPSB1bmRlZmluZWQ7XG4gICAganNvbi5jb25uZWN0aW9uTWFuYWdlciA9IHVuZGVmaW5lZDtcbiAgICByZXR1cm4ganNvbjtcbiAgfVxuICBcbiAgZ2V0UGF0aCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnBhdGg7XG4gIH1cbiAgXG4gIHNldFBhdGgocGF0aDogc3RyaW5nKTogTW9uZXJvV2FsbGV0Q29uZmlnIHtcbiAgICB0aGlzLnBhdGggPSBwYXRoO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRQYXNzd29yZCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnBhc3N3b3JkO1xuICB9XG4gIFxuICBzZXRQYXNzd29yZChwYXNzd29yZCk6IE1vbmVyb1dhbGxldENvbmZpZyB7XG4gICAgdGhpcy5wYXNzd29yZCA9IHBhc3N3b3JkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXROZXR3b3JrVHlwZSgpOiBNb25lcm9OZXR3b3JrVHlwZSB7XG4gICAgcmV0dXJuIHRoaXMubmV0d29ya1R5cGU7XG4gIH1cbiAgXG4gIHNldE5ldHdvcmtUeXBlKG5ldHdvcmtUeXBlT3JTdHI6IE1vbmVyb05ldHdvcmtUeXBlIHwgc3RyaW5nKTogTW9uZXJvV2FsbGV0Q29uZmlnIHtcbiAgICB0aGlzLm5ldHdvcmtUeXBlID0gbmV0d29ya1R5cGVPclN0ciA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogTW9uZXJvTmV0d29ya1R5cGUuZnJvbShuZXR3b3JrVHlwZU9yU3RyKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U2VydmVyKCk6IE1vbmVyb1JwY0Nvbm5lY3Rpb24ge1xuICAgIHJldHVybiB0aGlzLnNlcnZlciBhcyBNb25lcm9ScGNDb25uZWN0aW9uO1xuICB9XG4gIFxuICBzZXRTZXJ2ZXIoc2VydmVyOiBQYXJ0aWFsPE1vbmVyb1JwY0Nvbm5lY3Rpb24+IHwgc3RyaW5nKTogTW9uZXJvV2FsbGV0Q29uZmlnIHtcbiAgICBpZiAoc2VydmVyICYmICEoc2VydmVyIGluc3RhbmNlb2YgTW9uZXJvUnBjQ29ubmVjdGlvbikpIHNlcnZlciA9IG5ldyBNb25lcm9ScGNDb25uZWN0aW9uKHNlcnZlcik7XG4gICAgdGhpcy5zZXJ2ZXIgPSBzZXJ2ZXIgYXMgTW9uZXJvUnBjQ29ubmVjdGlvbjtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0Q29ubmVjdGlvbk1hbmFnZXIoKTogTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIge1xuICAgIHJldHVybiB0aGlzLmNvbm5lY3Rpb25NYW5hZ2VyO1xuICB9XG4gIFxuICBzZXRDb25uZWN0aW9uTWFuYWdlcihjb25uZWN0aW9uTWFuYWdlcjogTW9uZXJvQ29ubmVjdGlvbk1hbmFnZXIpOiBNb25lcm9XYWxsZXRDb25maWcge1xuICAgIHRoaXMuY29ubmVjdGlvbk1hbmFnZXIgPSBjb25uZWN0aW9uTWFuYWdlcjtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U2VlZCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLnNlZWQ7XG4gIH1cbiAgXG4gIHNldFNlZWQoc2VlZDogc3RyaW5nKTogTW9uZXJvV2FsbGV0Q29uZmlnIHtcbiAgICB0aGlzLnNlZWQgPSBzZWVkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRTZWVkT2Zmc2V0KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuc2VlZE9mZnNldDtcbiAgfVxuICBcbiAgc2V0U2VlZE9mZnNldChzZWVkT2Zmc2V0OiBzdHJpbmcpOiBNb25lcm9XYWxsZXRDb25maWcge1xuICAgIHRoaXMuc2VlZE9mZnNldCA9IHNlZWRPZmZzZXQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBnZXRJc011bHRpc2lnKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzTXVsdGlzaWc7XG4gIH1cbiAgXG4gIHNldElzTXVsdGlzaWcoaXNNdWx0aXNpZzogYm9vbGVhbik6IE1vbmVyb1dhbGxldENvbmZpZyB7XG4gICAgdGhpcy5pc011bHRpc2lnID0gaXNNdWx0aXNpZztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0UHJpbWFyeUFkZHJlc3MoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5wcmltYXJ5QWRkcmVzcztcbiAgfVxuICBcbiAgc2V0UHJpbWFyeUFkZHJlc3MocHJpbWFyeUFkZHJlc3M6IHN0cmluZykge1xuICAgIHRoaXMucHJpbWFyeUFkZHJlc3MgPSBwcmltYXJ5QWRkcmVzcztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0UHJpdmF0ZVZpZXdLZXkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5wcml2YXRlVmlld0tleTtcbiAgfVxuICBcbiAgc2V0UHJpdmF0ZVZpZXdLZXkocHJpdmF0ZVZpZXdLZXkpOiBNb25lcm9XYWxsZXRDb25maWcge1xuICAgIHRoaXMucHJpdmF0ZVZpZXdLZXkgPSBwcml2YXRlVmlld0tleTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0UHJpdmF0ZVNwZW5kS2V5KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMucHJpdmF0ZVNwZW5kS2V5O1xuICB9XG4gIFxuICBzZXRQcml2YXRlU3BlbmRLZXkocHJpdmF0ZVNwZW5kS2V5OiBzdHJpbmcpOiBNb25lcm9XYWxsZXRDb25maWcge1xuICAgIHRoaXMucHJpdmF0ZVNwZW5kS2V5ID0gcHJpdmF0ZVNwZW5kS2V5O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRSZXN0b3JlSGVpZ2h0KCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMucmVzdG9yZUhlaWdodDtcbiAgfVxuICBcbiAgc2V0UmVzdG9yZUhlaWdodChyZXN0b3JlSGVpZ2h0OiBudW1iZXIpOiBNb25lcm9XYWxsZXRDb25maWcge1xuICAgIHRoaXMucmVzdG9yZUhlaWdodCA9IHJlc3RvcmVIZWlnaHQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldExhbmd1YWdlKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMubGFuZ3VhZ2U7XG4gIH1cbiAgXG4gIHNldExhbmd1YWdlKGxhbmd1YWdlOiBzdHJpbmcpOiBNb25lcm9XYWxsZXRDb25maWcge1xuICAgIHRoaXMubGFuZ3VhZ2UgPSBsYW5ndWFnZTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U2F2ZUN1cnJlbnQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuc2F2ZUN1cnJlbnQ7XG4gIH1cbiAgXG4gIHNldFNhdmVDdXJyZW50KHNhdmVDdXJyZW50OiBib29sZWFuKTogTW9uZXJvV2FsbGV0Q29uZmlnIHtcbiAgICB0aGlzLnNhdmVDdXJyZW50ID0gc2F2ZUN1cnJlbnQ7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldFByb3h5VG9Xb3JrZXIoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMucHJveHlUb1dvcmtlcjtcbiAgfVxuICBcbiAgc2V0UHJveHlUb1dvcmtlcihwcm94eVRvV29ya2VyOiBib29sZWFuKTogTW9uZXJvV2FsbGV0Q29uZmlnIHtcbiAgICB0aGlzLnByb3h5VG9Xb3JrZXIgPSBwcm94eVRvV29ya2VyO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRGcygpOiBhbnkge1xuICAgIHJldHVybiB0aGlzLmZzO1xuICB9XG4gIFxuICBzZXRGcyhmczogYW55KSB7XG4gICAgdGhpcy5mcyA9IGZzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG4gIFxuICBnZXRLZXlzRGF0YSgpOiBVaW50OEFycmF5IHtcbiAgICByZXR1cm4gdGhpcy5rZXlzRGF0YTtcbiAgfVxuICBcbiAgc2V0S2V5c0RhdGEoa2V5c0RhdGE6IFVpbnQ4QXJyYXkpOiBNb25lcm9XYWxsZXRDb25maWcge1xuICAgIHRoaXMua2V5c0RhdGEgPSBrZXlzRGF0YTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0Q2FjaGVEYXRhKCk6IFVpbnQ4QXJyYXkge1xuICAgIHJldHVybiB0aGlzLmNhY2hlRGF0YTtcbiAgfVxuICBcbiAgc2V0Q2FjaGVEYXRhKGNhY2hlRGF0YTogVWludDhBcnJheSk6IE1vbmVyb1dhbGxldENvbmZpZyB7XG4gICAgdGhpcy5jYWNoZURhdGEgPSBjYWNoZURhdGE7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgXG4gIGdldEFjY291bnRMb29rYWhlYWQoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5hY2NvdW50TG9va2FoZWFkO1xuICB9XG4gIFxuICBzZXRBY2NvdW50TG9va2FoZWFkKGFjY291bnRMb29rYWhlYWQ6IG51bWJlcik6IE1vbmVyb1dhbGxldENvbmZpZyB7XG4gICAgdGhpcy5hY2NvdW50TG9va2FoZWFkID0gYWNjb3VudExvb2thaGVhZDtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBcbiAgZ2V0U3ViYWRkcmVzc0xvb2thaGVhZCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnN1YmFkZHJlc3NMb29rYWhlYWQ7XG4gIH1cbiAgXG4gIHNldFN1YmFkZHJlc3NMb29rYWhlYWQoc3ViYWRkcmVzc0xvb2thaGVhZDogbnVtYmVyKTogTW9uZXJvV2FsbGV0Q29uZmlnIHtcbiAgICB0aGlzLnN1YmFkZHJlc3NMb29rYWhlYWQgPSBzdWJhZGRyZXNzTG9va2FoZWFkO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59Il0sIm1hcHBpbmdzIjoiO0FBQ0EsSUFBQUEsa0JBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLG9CQUFBLEdBQUFGLHNCQUFBLENBQUFDLE9BQUE7OztBQUdBO0FBQ0E7QUFDQTtBQUNlLE1BQU1FLGtCQUFrQixDQUFDOztFQUV0Qzs7O0VBR0E7OztFQUdBOzs7RUFHQTs7O0VBR0E7OztFQUdBOzs7RUFHQTs7O0VBR0E7OztFQUdBOzs7RUFHQTs7O0VBR0E7OztFQUdBOzs7RUFHQTs7O0VBR0E7OztFQUdBOzs7RUFHQTs7O0VBR0E7OztFQUdBOzs7RUFHQTs7O0VBR0E7OztFQUdBOzs7RUFHQTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0VDLFdBQVdBLENBQUNDLE1BQW9DLEVBQUU7SUFDaERDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDLElBQUksRUFBRUYsTUFBTSxDQUFDOztJQUUzQjtJQUNBLElBQUksSUFBSSxDQUFDRyxNQUFNLEVBQUUsSUFBSSxDQUFDQyxTQUFTLENBQUMsSUFBSSxDQUFDRCxNQUFNLENBQUM7SUFDNUMsSUFBSSxDQUFDRSxnQkFBZ0IsQ0FBQyxJQUFJLENBQUNDLGFBQWEsQ0FBQztJQUN6QyxJQUFJLElBQUksQ0FBQ0MsV0FBVyxLQUFLQyxTQUFTLEVBQUUsSUFBSSxDQUFDRCxXQUFXLEdBQUdFLDBCQUFpQixDQUFDQyxJQUFJLENBQUMsSUFBSSxDQUFDSCxXQUFXLENBQUM7RUFDakc7O0VBRUFJLElBQUlBLENBQUEsRUFBdUI7SUFDekIsT0FBTyxJQUFJYixrQkFBa0IsQ0FBQyxJQUFJLENBQUM7RUFDckM7O0VBRUFjLE1BQU1BLENBQUEsRUFBUTtJQUNaLElBQUlDLElBQVMsR0FBR1osTUFBTSxDQUFDQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQ3ZDLElBQUlXLElBQUksQ0FBQ1YsTUFBTSxFQUFFVSxJQUFJLENBQUNWLE1BQU0sR0FBR1UsSUFBSSxDQUFDVixNQUFNLENBQUNTLE1BQU0sQ0FBQyxDQUFDO0lBQ25EQyxJQUFJLENBQUNDLEVBQUUsR0FBR04sU0FBUztJQUNuQkssSUFBSSxDQUFDRSxpQkFBaUIsR0FBR1AsU0FBUztJQUNsQyxPQUFPSyxJQUFJO0VBQ2I7O0VBRUFHLE9BQU9BLENBQUEsRUFBVztJQUNoQixPQUFPLElBQUksQ0FBQ0MsSUFBSTtFQUNsQjs7RUFFQUMsT0FBT0EsQ0FBQ0QsSUFBWSxFQUFzQjtJQUN4QyxJQUFJLENBQUNBLElBQUksR0FBR0EsSUFBSTtJQUNoQixPQUFPLElBQUk7RUFDYjs7RUFFQUUsV0FBV0EsQ0FBQSxFQUFXO0lBQ3BCLE9BQU8sSUFBSSxDQUFDQyxRQUFRO0VBQ3RCOztFQUVBQyxXQUFXQSxDQUFDRCxRQUFRLEVBQXNCO0lBQ3hDLElBQUksQ0FBQ0EsUUFBUSxHQUFHQSxRQUFRO0lBQ3hCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxjQUFjQSxDQUFBLEVBQXNCO0lBQ2xDLE9BQU8sSUFBSSxDQUFDZixXQUFXO0VBQ3pCOztFQUVBZ0IsY0FBY0EsQ0FBQ0MsZ0JBQTRDLEVBQXNCO0lBQy9FLElBQUksQ0FBQ2pCLFdBQVcsR0FBR2lCLGdCQUFnQixLQUFLaEIsU0FBUyxHQUFHQSxTQUFTLEdBQUdDLDBCQUFpQixDQUFDQyxJQUFJLENBQUNjLGdCQUFnQixDQUFDO0lBQ3hHLE9BQU8sSUFBSTtFQUNiOztFQUVBQyxTQUFTQSxDQUFBLEVBQXdCO0lBQy9CLE9BQU8sSUFBSSxDQUFDdEIsTUFBTTtFQUNwQjs7RUFFQUMsU0FBU0EsQ0FBQ0QsTUFBNkMsRUFBc0I7SUFDM0UsSUFBSUEsTUFBTSxJQUFJLEVBQUVBLE1BQU0sWUFBWXVCLDRCQUFtQixDQUFDLEVBQUV2QixNQUFNLEdBQUcsSUFBSXVCLDRCQUFtQixDQUFDdkIsTUFBTSxDQUFDO0lBQ2hHLElBQUksQ0FBQ0EsTUFBTSxHQUFHQSxNQUE2QjtJQUMzQyxPQUFPLElBQUk7RUFDYjs7RUFFQXdCLG9CQUFvQkEsQ0FBQSxFQUE0QjtJQUM5QyxPQUFPLElBQUksQ0FBQ1osaUJBQWlCO0VBQy9COztFQUVBYSxvQkFBb0JBLENBQUNiLGlCQUEwQyxFQUFzQjtJQUNuRixJQUFJLENBQUNBLGlCQUFpQixHQUFHQSxpQkFBaUI7SUFDMUMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFjLE9BQU9BLENBQUEsRUFBVztJQUNoQixPQUFPLElBQUksQ0FBQ0MsSUFBSTtFQUNsQjs7RUFFQUMsT0FBT0EsQ0FBQ0QsSUFBWSxFQUFzQjtJQUN4QyxJQUFJLENBQUNBLElBQUksR0FBR0EsSUFBSTtJQUNoQixPQUFPLElBQUk7RUFDYjs7RUFFQUUsYUFBYUEsQ0FBQSxFQUFXO0lBQ3RCLE9BQU8sSUFBSSxDQUFDQyxVQUFVO0VBQ3hCOztFQUVBQyxhQUFhQSxDQUFDRCxVQUFrQixFQUFzQjtJQUNwRCxJQUFJLENBQUNBLFVBQVUsR0FBR0EsVUFBVTtJQUM1QixPQUFPLElBQUk7RUFDYjs7RUFFQUUsYUFBYUEsQ0FBQSxFQUFZO0lBQ3ZCLE9BQU8sSUFBSSxDQUFDQyxVQUFVO0VBQ3hCOztFQUVBQyxhQUFhQSxDQUFDRCxVQUFtQixFQUFzQjtJQUNyRCxJQUFJLENBQUNBLFVBQVUsR0FBR0EsVUFBVTtJQUM1QixPQUFPLElBQUk7RUFDYjs7RUFFQUUsaUJBQWlCQSxDQUFBLEVBQVc7SUFDMUIsT0FBTyxJQUFJLENBQUNDLGNBQWM7RUFDNUI7O0VBRUFDLGlCQUFpQkEsQ0FBQ0QsY0FBc0IsRUFBRTtJQUN4QyxJQUFJLENBQUNBLGNBQWMsR0FBR0EsY0FBYztJQUNwQyxPQUFPLElBQUk7RUFDYjs7RUFFQUUsaUJBQWlCQSxDQUFBLEVBQVc7SUFDMUIsT0FBTyxJQUFJLENBQUNDLGNBQWM7RUFDNUI7O0VBRUFDLGlCQUFpQkEsQ0FBQ0QsY0FBYyxFQUFzQjtJQUNwRCxJQUFJLENBQUNBLGNBQWMsR0FBR0EsY0FBYztJQUNwQyxPQUFPLElBQUk7RUFDYjs7RUFFQUUsa0JBQWtCQSxDQUFBLEVBQVc7SUFDM0IsT0FBTyxJQUFJLENBQUNDLGVBQWU7RUFDN0I7O0VBRUFDLGtCQUFrQkEsQ0FBQ0QsZUFBdUIsRUFBc0I7SUFDOUQsSUFBSSxDQUFDQSxlQUFlLEdBQUdBLGVBQWU7SUFDdEMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLGdCQUFnQkEsQ0FBQSxFQUFXO0lBQ3pCLE9BQU8sSUFBSSxDQUFDQyxhQUFhO0VBQzNCOztFQUVBQyxnQkFBZ0JBLENBQUNELGFBQXFCLEVBQXNCO0lBQzFELElBQUksQ0FBQ0EsYUFBYSxHQUFHQSxhQUFhO0lBQ2xDLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxXQUFXQSxDQUFBLEVBQVc7SUFDcEIsT0FBTyxJQUFJLENBQUNDLFFBQVE7RUFDdEI7O0VBRUFDLFdBQVdBLENBQUNELFFBQWdCLEVBQXNCO0lBQ2hELElBQUksQ0FBQ0EsUUFBUSxHQUFHQSxRQUFRO0lBQ3hCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxjQUFjQSxDQUFBLEVBQVk7SUFDeEIsT0FBTyxJQUFJLENBQUNDLFdBQVc7RUFDekI7O0VBRUFDLGNBQWNBLENBQUNELFdBQW9CLEVBQXNCO0lBQ3ZELElBQUksQ0FBQ0EsV0FBVyxHQUFHQSxXQUFXO0lBQzlCLE9BQU8sSUFBSTtFQUNiOztFQUVBRSxnQkFBZ0JBLENBQUEsRUFBWTtJQUMxQixPQUFPLElBQUksQ0FBQ2xELGFBQWE7RUFDM0I7O0VBRUFELGdCQUFnQkEsQ0FBQ0MsYUFBc0IsRUFBc0I7SUFDM0QsSUFBSSxDQUFDQSxhQUFhLEdBQUdBLGFBQWE7SUFDbEMsT0FBTyxJQUFJO0VBQ2I7O0VBRUFtRCxLQUFLQSxDQUFBLEVBQVE7SUFDWCxPQUFPLElBQUksQ0FBQzNDLEVBQUU7RUFDaEI7O0VBRUE0QyxLQUFLQSxDQUFDNUMsRUFBTyxFQUFFO0lBQ2IsSUFBSSxDQUFDQSxFQUFFLEdBQUdBLEVBQUU7SUFDWixPQUFPLElBQUk7RUFDYjs7RUFFQTZDLFdBQVdBLENBQUEsRUFBZTtJQUN4QixPQUFPLElBQUksQ0FBQ0MsUUFBUTtFQUN0Qjs7RUFFQUMsV0FBV0EsQ0FBQ0QsUUFBb0IsRUFBc0I7SUFDcEQsSUFBSSxDQUFDQSxRQUFRLEdBQUdBLFFBQVE7SUFDeEIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLFlBQVlBLENBQUEsRUFBZTtJQUN6QixPQUFPLElBQUksQ0FBQ0MsU0FBUztFQUN2Qjs7RUFFQUMsWUFBWUEsQ0FBQ0QsU0FBcUIsRUFBc0I7SUFDdEQsSUFBSSxDQUFDQSxTQUFTLEdBQUdBLFNBQVM7SUFDMUIsT0FBTyxJQUFJO0VBQ2I7O0VBRUFFLG1CQUFtQkEsQ0FBQSxFQUFXO0lBQzVCLE9BQU8sSUFBSSxDQUFDQyxnQkFBZ0I7RUFDOUI7O0VBRUFDLG1CQUFtQkEsQ0FBQ0QsZ0JBQXdCLEVBQXNCO0lBQ2hFLElBQUksQ0FBQ0EsZ0JBQWdCLEdBQUdBLGdCQUFnQjtJQUN4QyxPQUFPLElBQUk7RUFDYjs7RUFFQUUsc0JBQXNCQSxDQUFBLEVBQVc7SUFDL0IsT0FBTyxJQUFJLENBQUNDLG1CQUFtQjtFQUNqQzs7RUFFQUMsc0JBQXNCQSxDQUFDRCxtQkFBMkIsRUFBc0I7SUFDdEUsSUFBSSxDQUFDQSxtQkFBbUIsR0FBR0EsbUJBQW1CO0lBQzlDLE9BQU8sSUFBSTtFQUNiO0FBQ0YsQ0FBQ0UsT0FBQSxDQUFBQyxPQUFBLEdBQUExRSxrQkFBQSJ9 \ No newline at end of file diff --git a/dist/src/main/ts/wallet/model/MoneroWalletListener.d.ts b/dist/src/main/ts/wallet/model/MoneroWalletListener.d.ts new file mode 100644 index 000000000..69da1edbc --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroWalletListener.d.ts @@ -0,0 +1,51 @@ +import MoneroOutputWallet from "./MoneroOutputWallet"; +/** + * Default wallet listener which takes no action on notifications. + */ +export default class MoneroWalletListener { + /** + * Invoked as the wallet is synchronized. + * + * @param {number} height - height of the synced block + * @param {number} startHeight - starting height of the sync request + * @param {number} endHeight - ending height of the sync request + * @param {number} percentDone - sync progress as a percentage + * @param {string} message - human-readable description of the current progress + * @return {Promise} + */ + onSyncProgress(height: number, startHeight: number, endHeight: number, percentDone: number, message: string): Promise; + /** + * Invoked when a new block is added to the chain. + * + * @param {number} height - the height of the new block (i.e. the number of blocks before it). + * @return {Promise} + */ + onNewBlock(height: number): Promise; + /** + * Invoked when the wallet's balances change. + * + * @param {bigint} newBalance - new wallet balance + * @param {bigint} newUnlockedBalance - new unlocked wallet balance + * @return {Promise} + */ + onBalancesChanged(newBalance: bigint, newUnlockedBalance: bigint): Promise; + /** + * Invoked 3 times per received output: once when unconfirmed, once when confirmed, and + * once when unlocked. + * + * The notified output includes basic fields only, so the output or its transaction should be fetched to get all available fields. + * + * @param {MoneroOutputWallet} output - the received output + * @return {Promise} + */ + onOutputReceived(output: MoneroOutputWallet): Promise; + /** + * Invoked twice per spent output: once when confirmed and once when unlocked. + * + * The notified output includes basic fields only, so the output or its transaction should be fetched to get all available fields. + * + * @param {MoneroOutputWallet} output - the spent output + * @return {Promise} + */ + onOutputSpent(output: any): Promise; +} diff --git a/dist/src/main/ts/wallet/model/MoneroWalletListener.js b/dist/src/main/ts/wallet/model/MoneroWalletListener.js new file mode 100644 index 000000000..41419ef52 --- /dev/null +++ b/dist/src/main/ts/wallet/model/MoneroWalletListener.js @@ -0,0 +1,58 @@ +"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.default = void 0; + +/** + * Default wallet listener which takes no action on notifications. + */ +class MoneroWalletListener { + + /** + * Invoked as the wallet is synchronized. + * + * @param {number} height - height of the synced block + * @param {number} startHeight - starting height of the sync request + * @param {number} endHeight - ending height of the sync request + * @param {number} percentDone - sync progress as a percentage + * @param {string} message - human-readable description of the current progress + * @return {Promise} + */ + async onSyncProgress(height, startHeight, endHeight, percentDone, message) {} + + /** + * Invoked when a new block is added to the chain. + * + * @param {number} height - the height of the new block (i.e. the number of blocks before it). + * @return {Promise} + */ + async onNewBlock(height) {} + + /** + * Invoked when the wallet's balances change. + * + * @param {bigint} newBalance - new wallet balance + * @param {bigint} newUnlockedBalance - new unlocked wallet balance + * @return {Promise} + */ + async onBalancesChanged(newBalance, newUnlockedBalance) {} + + /** + * Invoked 3 times per received output: once when unconfirmed, once when confirmed, and + * once when unlocked. + * + * The notified output includes basic fields only, so the output or its transaction should be fetched to get all available fields. + * + * @param {MoneroOutputWallet} output - the received output + * @return {Promise} + */ + async onOutputReceived(output) {} + + /** + * Invoked twice per spent output: once when confirmed and once when unlocked. + * + * The notified output includes basic fields only, so the output or its transaction should be fetched to get all available fields. + * + * @param {MoneroOutputWallet} output - the spent output + * @return {Promise} + */ + async onOutputSpent(output) {} +}exports.default = MoneroWalletListener; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb25lcm9XYWxsZXRMaXN0ZW5lciIsIm9uU3luY1Byb2dyZXNzIiwiaGVpZ2h0Iiwic3RhcnRIZWlnaHQiLCJlbmRIZWlnaHQiLCJwZXJjZW50RG9uZSIsIm1lc3NhZ2UiLCJvbk5ld0Jsb2NrIiwib25CYWxhbmNlc0NoYW5nZWQiLCJuZXdCYWxhbmNlIiwibmV3VW5sb2NrZWRCYWxhbmNlIiwib25PdXRwdXRSZWNlaXZlZCIsIm91dHB1dCIsIm9uT3V0cHV0U3BlbnQiLCJleHBvcnRzIiwiZGVmYXVsdCJdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9tYWluL3RzL3dhbGxldC9tb2RlbC9Nb25lcm9XYWxsZXRMaXN0ZW5lci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgTW9uZXJvT3V0cHV0V2FsbGV0IGZyb20gXCIuL01vbmVyb091dHB1dFdhbGxldFwiO1xuXG4vKipcbiAqIERlZmF1bHQgd2FsbGV0IGxpc3RlbmVyIHdoaWNoIHRha2VzIG5vIGFjdGlvbiBvbiBub3RpZmljYXRpb25zLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBNb25lcm9XYWxsZXRMaXN0ZW5lciB7XG4gIFxuICAvKipcbiAgICogSW52b2tlZCBhcyB0aGUgd2FsbGV0IGlzIHN5bmNocm9uaXplZC5cbiAgICogXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBoZWlnaHQgb2YgdGhlIHN5bmNlZCBibG9jayBcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXJ0SGVpZ2h0IC0gc3RhcnRpbmcgaGVpZ2h0IG9mIHRoZSBzeW5jIHJlcXVlc3RcbiAgICogQHBhcmFtIHtudW1iZXJ9IGVuZEhlaWdodCAtIGVuZGluZyBoZWlnaHQgb2YgdGhlIHN5bmMgcmVxdWVzdFxuICAgKiBAcGFyYW0ge251bWJlcn0gcGVyY2VudERvbmUgLSBzeW5jIHByb2dyZXNzIGFzIGEgcGVyY2VudGFnZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIGh1bWFuLXJlYWRhYmxlIGRlc2NyaXB0aW9uIG9mIHRoZSBjdXJyZW50IHByb2dyZXNzXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBvblN5bmNQcm9ncmVzcyhoZWlnaHQ6IG51bWJlciwgc3RhcnRIZWlnaHQ6IG51bWJlciwgZW5kSGVpZ2h0OiBudW1iZXIsIHBlcmNlbnREb25lOiBudW1iZXIsIG1lc3NhZ2U6IHN0cmluZykgeyB9XG5cbiAgLyoqXG4gICAqIEludm9rZWQgd2hlbiBhIG5ldyBibG9jayBpcyBhZGRlZCB0byB0aGUgY2hhaW4uXG4gICAqIFxuICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gdGhlIGhlaWdodCBvZiB0aGUgbmV3IGJsb2NrIChpLmUuIHRoZSBudW1iZXIgb2YgYmxvY2tzIGJlZm9yZSBpdCkuXG4gICAqIEByZXR1cm4ge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBvbk5ld0Jsb2NrKGhlaWdodDogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7IH1cbiAgXG4gIC8qKlxuICAgKiBJbnZva2VkIHdoZW4gdGhlIHdhbGxldCdzIGJhbGFuY2VzIGNoYW5nZS5cbiAgICogXG4gICAqIEBwYXJhbSB7YmlnaW50fSBuZXdCYWxhbmNlIC0gbmV3IHdhbGxldCBiYWxhbmNlXG4gICAqIEBwYXJhbSB7YmlnaW50fSBuZXdVbmxvY2tlZEJhbGFuY2UgLSBuZXcgdW5sb2NrZWQgd2FsbGV0IGJhbGFuY2VcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIG9uQmFsYW5jZXNDaGFuZ2VkKG5ld0JhbGFuY2U6IGJpZ2ludCwgbmV3VW5sb2NrZWRCYWxhbmNlOiBiaWdpbnQpOiBQcm9taXNlPHZvaWQ+IHsgfVxuXG4gIC8qKlxuICAgKiBJbnZva2VkIDMgdGltZXMgcGVyIHJlY2VpdmVkIG91dHB1dDogb25jZSB3aGVuIHVuY29uZmlybWVkLCBvbmNlIHdoZW4gY29uZmlybWVkLCBhbmRcbiAgICogb25jZSB3aGVuIHVubG9ja2VkLlxuICAgKiBcbiAgICogVGhlIG5vdGlmaWVkIG91dHB1dCBpbmNsdWRlcyBiYXNpYyBmaWVsZHMgb25seSwgc28gdGhlIG91dHB1dCBvciBpdHMgdHJhbnNhY3Rpb24gc2hvdWxkIGJlIGZldGNoZWQgdG8gZ2V0IGFsbCBhdmFpbGFibGUgZmllbGRzLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9PdXRwdXRXYWxsZXR9IG91dHB1dCAtIHRoZSByZWNlaXZlZCBvdXRwdXRcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIG9uT3V0cHV0UmVjZWl2ZWQob3V0cHV0OiBNb25lcm9PdXRwdXRXYWxsZXQpOiBQcm9taXNlPHZvaWQ+IHsgfVxuICBcbiAgLyoqXG4gICAqIEludm9rZWQgdHdpY2UgcGVyIHNwZW50IG91dHB1dDogb25jZSB3aGVuIGNvbmZpcm1lZCBhbmQgb25jZSB3aGVuIHVubG9ja2VkLlxuICAgKiBcbiAgICogVGhlIG5vdGlmaWVkIG91dHB1dCBpbmNsdWRlcyBiYXNpYyBmaWVsZHMgb25seSwgc28gdGhlIG91dHB1dCBvciBpdHMgdHJhbnNhY3Rpb24gc2hvdWxkIGJlIGZldGNoZWQgdG8gZ2V0IGFsbCBhdmFpbGFibGUgZmllbGRzLlxuICAgKiBcbiAgICogQHBhcmFtIHtNb25lcm9PdXRwdXRXYWxsZXR9IG91dHB1dCAtIHRoZSBzcGVudCBvdXRwdXRcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn1cbiAgICovXG4gIGFzeW5jIG9uT3V0cHV0U3BlbnQob3V0cHV0KTogUHJvbWlzZTx2b2lkPiB7IH1cbn1cbiJdLCJtYXBwaW5ncyI6Ijs7QUFFQTtBQUNBO0FBQ0E7QUFDZSxNQUFNQSxvQkFBb0IsQ0FBQzs7RUFFeEM7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDRSxNQUFNQyxjQUFjQSxDQUFDQyxNQUFjLEVBQUVDLFdBQW1CLEVBQUVDLFNBQWlCLEVBQUVDLFdBQW1CLEVBQUVDLE9BQWUsRUFBRSxDQUFFOztFQUVySDtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7RUFDRSxNQUFNQyxVQUFVQSxDQUFDTCxNQUFjLEVBQWlCLENBQUU7O0VBRWxEO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsTUFBTU0saUJBQWlCQSxDQUFDQyxVQUFrQixFQUFFQyxrQkFBMEIsRUFBaUIsQ0FBRTs7RUFFekY7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsTUFBTUMsZ0JBQWdCQSxDQUFDQyxNQUEwQixFQUFpQixDQUFFOztFQUVwRTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsTUFBTUMsYUFBYUEsQ0FBQ0QsTUFBTSxFQUFpQixDQUFFO0FBQy9DLENBQUNFLE9BQUEsQ0FBQUMsT0FBQSxHQUFBZixvQkFBQSJ9 \ No newline at end of file diff --git a/docs/ConnectionType.html b/docs/ConnectionType.html deleted file mode 100644 index 9fa8a1049..000000000 --- a/docs/ConnectionType.html +++ /dev/null @@ -1,656 +0,0 @@ - - - - - JSDoc: Class: ConnectionType - - - - - - - - - - -
- -

Class: ConnectionType

- - - - - - -
- -
- -

ConnectionType

- -
Enumerates connection types. - -Based on enums.h in monero-project.
- - -
- -
-
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -

Members

- - - -

(static) I2P

- - - - -
- I2P connection type (value=4). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(static) INVALID

- - - - -
- Invalid connection type (value=0). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(static) IPV4

- - - - -
- IPV4 connection type (value=1). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(static) IPV6

- - - - -
- IPV6 connection type (value=2). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(static) TOR

- - - - -
- TOR connection type (value=3). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - -

Methods

- - - - - - - -

(static) isValid()

- - - - - - -
- Indicates if the given connection type is valid or not. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) validate()

- - - - - - -
- Asserts that the given connection type is valid. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/GenUtils.html b/docs/GenUtils.html deleted file mode 100644 index d7f66aad1..000000000 --- a/docs/GenUtils.html +++ /dev/null @@ -1,13785 +0,0 @@ - - - - - JSDoc: Class: GenUtils - - - - - - - - - - -
- -

Class: GenUtils

- - - - - - -
- -
- -

GenUtils()

- -
Collection of general purpose utilities. - -TODO: could pull in assert and remove these asserts -TODO: needs cleanup as ES6+ utility class
- - -
- -
-
- - - - -

Constructor

- - - -

new GenUtils()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(static) arrayContains(arr, obj, compareByReference)

- - - - - - -
- Indicates if the given array contains the given object. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arr - - -Array.<object> - - - - array that may or may not contain the object
obj - - -object - - - - object to check for inclusion in the array
compareByReference - - -boolean - - - - compare strictly by reference, forgoing deep equality check
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the array contains the object, false otherwise -
- - - - - - - - - - - - - - - -

(static) arraysEqual(arr1, arr2)

- - - - - - -
- Determines if two arrays are equal. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arr1 - - is an array to compare
arr2 - - is an array to compare
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the arrays are equal, false otherwise -
- - - - - - - - - - - - - - - -

(static) arrToCsv(arr)

- - - - - - -
- Converts the given array to a CSV string. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arr - - is a 2-dimensional array of strings
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the CSV string -
- - - - - - - - - - - - - - - -

(static) assertArray(arg, msg)

- - - - - - -
- Asserts that the given argument is an array. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert as an array
msg - - is the message to throw if the argument is not an array
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertBase58(arg, msg)

- - - - - - -
- Asserts that the given argument is base58. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert as base58
msg - - is the message to throw if the argument is not base58
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertBase64(arg, msg)

- - - - - - -
- Asserts that the given argument is base64. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert as base64
msg - - is the message to throw if the argument is not base64
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertBoolean(arg, msg)

- - - - - - -
- Asserts that the given argument is a boolean. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert as a boolean
msg - - is the message to throw if the argument is not a boolean
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertDefined(arg, msg)

- - - - - - -
- Asserts that the given argument is defined. Throws an exception if undefined. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert defined
msg - - is the message to throw if arg is undefined (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertEquals(arg1, arg2, msg)

- - - - - - -
- Asserts that the given arguments are equal. Throws an exception if not equal. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg1 - - is an argument to assert as equal
arg2 - - is an argument to assert as equal
msg - - is the message to throw if the arguments are not equal
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertFalse(bool, msg)

- - - - - - -
- Asserts that the given boolean is false. Throws an exception if not a boolean or true. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
bool - - is the boolean to assert false
msg - - is the message to throw if bool is true (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertFunction(arg, msg)

- - - - - - -
- Asserts that the given argument is a static. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert as a static
msg - - is the message to throw if the argument is not a static
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertHex(arg, msg)

- - - - - - -
- Asserts that the given argument is hex. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert as hex
msg - - is the message to throw if the argument is not hex
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertInitialized(arg, msg)

- - - - - - -
- Asserts that the given argument is initialized. Throws an exception if not initialized. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert as initialized
msg - - is the message to throw if arg is not initialized (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertInt(arg, msg)

- - - - - - -
- Asserts that the given argument is an integer. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert as an integer
msg - - is the message to throw if the argument is not an integer
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertNotEquals(arg1, arg2, msg)

- - - - - - -
- Asserts that the given arguments are not equal. Throws an exception if equal. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg1 - - is an argument to assert as not equal
arg2 - - is an argument to assert as not equal
msg - - is the message to throw if the arguments are equal
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertNotNull(arg, msg)

- - - - - - -
- Asserts that the given argument is not null. Throws an exception if null. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert not null
msg - - is the message to throw if arg is null (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertNull(arg, msg)

- - - - - - -
- Asserts that the given argument is null. Throws an exception if not null. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert null
msg - - is the message to throw if arg is not null (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertNumber(arg, msg)

- - - - - - -
- Asserts that the given argument is a number. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert as a number
msg - - is the message to throw if the argument is not a number
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertObject(arg, obj, msg)

- - - - - - -
- Asserts that the given argument is an object with the given name. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to test
obj - - is an object to assert arg instanceof obj (optional)
msg - - is the message to throw if the argument is not the specified object
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertString(arg, msg)

- - - - - - -
- Asserts that the given argument is a string. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert as a string
msg - - is the message to throw if the argument is not a string
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertTrue(bool, msg)

- - - - - - -
- Asserts that the given boolean is true. Throws an exception if not a boolean or false. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
bool - - is the boolean to assert true
msg - - is the message to throw if bool is false (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertUndefined(arg, msg)

- - - - - - -
- Asserts that the given argument is undefined. Throws an exception if defined. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert undefined
msg - - is the message to throw if arg is defined (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) assertUninitialized(arg, msg)

- - - - - - -
- Asserts that the given argument is uninitialized. Throws an exception if initialized. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to assert as uninitialized
msg - - is the message to throw if arg is initialized (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) buildHtmlDocument(content)

- - - - - - -
- Manually builds an HTML document string. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
content - - specifies optional document content - content.div is a pre-existing div to stringify and add to the body - content.title is the title of the new tab - content.dependencyPaths specifies paths to js, css, or img paths - content.internalCss is css to embed in the html document - content.metas are meta elements with keys/values to include
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- str is the document string -
- - - - - - - - - - - - - - - -

(static) copyArray(arr)

- - - - - - -
- Copies the given array. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arr - - is the array to copy
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- a copy of the given array -
- - - - - - - - - - - - - - - -

(static) copyProperties(obj)

- - - - - - -
- Copies properties in the given object to a new object. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
obj - - is object to copy properties for
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- a new object with properties copied from the given object -
- - - - - - - - - - - - - - - -

(static) countNonWhitespaceCharacters(str)

- - - - - - -
- Counts the number of non-whitespace characters in the given string. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - is the string to count the number of non-whitespace characters in
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- int is the number of non-whitespace characters in the given string -
- - - - - - - - - - - - - - - -

(static) csvToArr(csv)

- - - - - - -
- Converts a CSV string to a 2-dimensional array of strings. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
csv - - is the CSV string to convert
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- a 2-dimensional array of strings -
- - - - - - - - - - - - - - - -

(static) deleteProperties(obj)

- - - - - - -
- Deletes all properties in the given object. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
obj - - is the object to delete properties from
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) deleteUndefinedKeys(obj)

- - - - - - -
- Deletes properties from the object that are undefined. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
obj - - is the object to delete undefined keys from
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) equals(arg1, arg2)

- - - - - - -
- Determines if two arguments are deep equal. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg1 - - is an argument to compare
arg2 - - is an argument to compare
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the arguments are deep equals, false otherwise -
- - - - - - - - - - - - - - - -

(static) fail(msg)

- - - - - - -
- Throws an exception with the given message. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
msg - - defines the message to throw the exception with (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) getCombinations(arr, combinationSize)

- - - - - - -
- Returns combinations of the given array of the given size. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arr - - is the array to get combinations from
combinationSize - - specifies the size of each combination
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) getDownloadableA(name, contents)

- - - - - - -
- Gets an 'a' element that is downloadable when clicked. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - is the name of the file to download
contents - - are the string contents of the file to download
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- 'a' dom element with downloadable file -
- - - - - - - - - - - - - - - -

(static) getIEVersion()

- - - - - - -
- Gets the IE version number. - -Credit: https://stackoverflow.com/questions/19999388/check-if-user-is-using-ie-with-jquery/21712356#21712356 -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the IE version number of null if not IE -
- - - - - - - - - - - - - - - -

(static) getImages(paths, onDone(err,)

- - - - - - -
- Fetches the given list of images. - -Prerequisite: async.js. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
paths - - are the paths to the images to fetch
onDone(err, - - images) is called when done
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) getIndent(length) → {string}

- - - - - - -
- Returns a string indentation of the given length; -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
length - - is the length of the indentation
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is an indentation string of the given length -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(static) getIndices(size)

- - - - - - -
- Returns an array of indices of the given size. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
size - - specifies the size to get indices for
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- array of the given size with indices starting at 0 -
- - - - - - - - - - - - - - - -

(static) getInternalStyleSheet()

- - - - - - -
- Returns the document's first stylesheet which has no href. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- StyleSheet is the internal stylesheet -
- - - - - - - - - - - - - - - -

(static) getInternalStyleSheetText()

- - - - - - -
- Returns the document's internal stylesheet as text. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- str is the document's internal stylesheet -
- - - - - - - - - - - - - - - -

(static) getLines(str, string[)

- - - - - - -
- Returns lines separated by newlines from the given string. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - is the string to get lines from
string[ - - are the lines separated by newlines within the string
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) getOuterHtml(node)

- - - - - - -
- Returns the given node's outer HTML. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
node - - is the node to get outer HTML for
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the outer HTML of the given node -
- - - - - - - - - - - - - - - -

(static) getParameterByName(name, url)

- - - - - - -
- Gets a parameter value. - -Credit: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
name - - is the name of the parameter to get the value of
url - - is a URL to get the parameter from, uses the window's current href if not given
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the parameter's value -
- - - - - - - - - - - - - - - -

(static) getPowerSet(arr)

- - - - - - -
- Returns the power set of the given array. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arr - - is the array to get the power set of
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- [][] is the power set of the given array -
- - - - - - - - - - - - - - - -

(static) getPowerSetOfLength(arr, size)

- - - - - - -
- Returns the power set of the given array whose elements are the given size. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arr - - is the array to get the power set of
size - - is the required size of the elements within the power set -returns [][] is the power set of the given array whose elements are the given size
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) getRandomInt(min, max)

- - - - - - -
- Gets a non-cryptographically secure random number within a given range. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
min - - is the minimum range of the int to generate, inclusive
max - - is the maximum range of the int to generate, inclusive - -Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) getRandomInts(min, max, count)

- - - - - - -
- Gets random ints. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
min - - is the minimum range of the ints to generate, inclusive
max - - is the maximum range of the ints to generate, inclusive
count - - is the number of random ints to get
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) getUniqueRandomInts(min, max, count)

- - - - - - -
- Gets a given number of unique random ints within a range. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
min - - is the minimum range of the ints to generate, inclusive
max - - is the maximum range of the ints to generate, inclusive
count - - is the number of unique random ints to get
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) getUUID()

- - - - - - -
- Generates a v4 UUID. - -Source: https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) getWhitespaceTokens(str)

- - - - - - -
- Returns tokens separated by whitespace from the given string. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - is the string to get tokens from
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- string[] are the tokens separated by whitespace within the string -
- - - - - - - - - - - - - - - -

(static) hasWhitespace(str)

- - - - - - -
- Indicates if the given string contains whitespace. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - is the string to test
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the string contains whitespace, false otherwise -
- - - - - - - - - - - - - - - -

(static) imgToDataUrl(img, quality)

- - - - - - -
- Converts the given image to a base64 encoded data url. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
img - - is the image to convert
quality - - is a number between 0 and 1 specifying the image quality
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) inheritsFrom(child, parent)

- - - - - - -
- Sets the child's prototype to the parent's prototype. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
child - - is the child class
parent - - is the parent class
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) initPolyfills()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) invoke()

- - - - - - -
- Invokes functions with arguments. - -arguments[0] is assumed to be an array of functions to invoke -arguments[1...n] are args to invoke the functions with -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) isArray(arg)

- - - - - - -
- Indicates if the given argument is an array. - -TODO: remove this entirely since just a direct wrapper? -TODO: this method returns true for object -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to test as being an array
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the argument is an array, false otherwise -
- - - - - - - - - - - - - - - -

(static) isBase32()

- - - - - - -
- Determines if the given string is base32. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) isBase58()

- - - - - - -
- Determines if the given string is base58. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) isBase64()

- - - - - - -
- Determines if the given string is base64. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) isBoolean(arg)

- - - - - - -
- Determines if the given argument is a boolean. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to test as being a boolean
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the argument is a boolean, false otherwise -
- - - - - - - - - - - - - - - -

(static) isBrowser() → {boolean}

- - - - - - -
- Indicates if the current environment is a browser. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the environment is a browser, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(static) isCsvFile(file)

- - - - - - -
- Determines if the given file is a csv file. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
file - - is a file
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given file is a csv file, false otherwise -
- - - - - - - - - - - - - - - -

(static) isDefined(arg)

- - - - - - -
- Indicates if the given argument is defined. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the arg to test
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given arg is defined, false otherwise -
- - - - - - - - - - - - - - - -

(static) isFirefox() → {boolean}

- - - - - - -
- Indicates if the current environment is a firefox-based browser. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the environment is a firefox-based browser, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(static) isFunction(arg)

- - - - - - -
- Determines if the given argument is a static. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to test as being a static
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the argument is a static, false otherwise -
- - - - - - - - - - - - - - - -

(static) isHex(str)

- - - - - - -
- Indicates if the given argument is a hexidemal string. - -Credit: https://github.com/roryrjb/is-hex/blob/master/is-hex.js. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - is the string to test
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given string is hexidecimal, false otherwise -
- - - - - - - - - - - - - - - -

(static) isImageAccessible(url, timeout, onDone(bool))

- - - - - - -
- Determines if the image at the given URL is accessible. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
url - - is the url to an image
timeout - - is the maximum time to wait
onDone(bool) - - when the image is determined to be accessible or not
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) isInitialized(arg)

- - - - - - -
- Indicates if the given arg is initialized. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the arg to test
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given arg is initialized, false otherwise -
- - - - - - - - - - - - - - - -

(static) isInt(arg)

- - - - - - -
- Indicates if the given argument is an integer. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to test
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given argument is an integer, false otherwise -
- - - - - - - - - - - - - - - -

(static) isJsonFile(file)

- - - - - - -
- Determines if the given file is a json file. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
file - - is a file
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given file is a json file, false otherwise -
- - - - - - - - - - - - - - - -

(static) isLowerCase(str, true)

- - - - - - -
- Determines if all alphabet characters in the given string are lower case. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - is the string to test
true - - if the string is lower case, false otherwise
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) isNewline(char)

- - - - - - -
- Indicates if the given character is a newline. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
char - - is the character to test
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given character is a newline, false otherwise -
- - - - - - - - - - - - - - - -

(static) isNumber(arg)

- - - - - - -
- Indicates if the given argument is a number. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to test
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the argument is a number, false otherwise -
- - - - - - - - - - - - - - - -

(static) isObject(arg, obj)

- - - - - - -
- Indicates if the given argument is an object and optionally if it has the given constructor name. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to test
obj - - is an object to test arg instanceof obj (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given argument is an object and optionally has the given constructor name -
- - - - - - - - - - - - - - - -

(static) isString(arg)

- - - - - - -
- Indicates if the given argument is a string. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the argument to test as being a string
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the argument is a string, false otherwise -
- - - - - - - - - - - - - - - -

(static) isTxtFile(file)

- - - - - - -
- Determines if the given file is a txt file. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
file - - is a file
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given file is a txt file, false otherwise -
- - - - - - - - - - - - - - - -

(static) isUndefined(arg)

- - - - - - -
- Indicates if the given argument is undefined. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the arg to test
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given arg is undefined, false otherwise -
- - - - - - - - - - - - - - - -

(static) isUninitialized(arg)

- - - - - - -
- Indicates if the given arg is uninitialized. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arg - - is the arg to test
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given arg is uninitialized, false otherwise -
- - - - - - - - - - - - - - - -

(static) isUpperCase(str)

- - - - - - -
- Determines if all alphabet characters in the given string are upper case. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - is the string to test
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the string is upper case, false otherwise -
- - - - - - - - - - - - - - - -

(static) isWhitespace(char)

- - - - - - -
- Indicates if the given character is whitespace. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
char - - is the character to test
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given character is whitespace, false otherwise -
- - - - - - - - - - - - - - - -

(static) isZipFile(file)

- - - - - - -
- Determines if the given file is a zip file. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
file - - is a file
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the given file is a zip file, false otherwise -
- - - - - - - - - - - - - - - -

(static) kvLine(key, value, indent, newline, ignoreUndefined) → {string}

- - - - - - -
- Returns a human-friendly key value line. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
key - - - - is the key
value - - - - is the value
indent - - - - 0 - - indents the line
newline - - - - true - - specifies if the string should be terminated with a newline or not
ignoreUndefined - - - - true - - specifies if undefined values should return an empty string
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is the human-friendly key value line -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(static) listify(arrOrElem)

- - - - - - -
- Listifies the given argument. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arrOrElem - - is an array or an element in the array
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- an array which is the given arg if it's an array or an array with the given arg as an element -
- - - - - - - - - - - - - - - -

(static) newWindow(content, onLoad(err,)

- - - - - - -
- Opens the given div in a new window. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
content - - specifies optional window content - content.div is a pre-existing div to stringify and add to the body - content.title is the title of the new tab - content.dependencyPaths specifies paths to js, css, or img paths - content.internalCss is css to embed in the html document - content.metas are meta elements with keys/values to include
onLoad(err, - - window) is invoked with a reference to the window when available
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) objectsEqual(map1, map2)

- - - - - - -
- Determines if two objects are deep equal. - -Undefined values are considered equal to non-existent keys. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
map1 - - is a map to compare
map2 - - is a map to compare
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the maps have identical keys and values, false otherwise -
- - - - - - - - - - - - - - - -

(static) reconcile(val1, val2, config, errMsg)

- - - - - - -
- Reconciles two values. - -TODO: remove custom error message -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
val1 - - is a value to reconcile
val2 - - is a value to reconcile
config - - specifies reconciliation configuration - config.resolveDefined uses defined value if true or undefined, undefined if false - config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined - config.resolveMax uses max over min if true, min over max if false, must be equal if undefined
errMsg - - is the error message to throw if the values cannot be reconciled (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the reconciled value if reconcilable, throws error otherwise -
- - - - - - - - - - - - - - - -

(static) remove(arr, val)

- - - - - - -
- Removes every instance of the given value from the given array. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arr - - is the array to remove the value from
val - - is the value to remove from the array
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the value is found and removed, false otherwise -
- - - - - - - - - - - - - - - -

(static) safeSet(obj, getFn, setFn, val, config, errMsg)

- - - - - - -
- Sets the given value ensuring a previous value is not overwritten. - -TODO: remove for portability because function passing not supported in other languages, use reconcile only -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
obj - - is the object to invoke the getter and setter on
getFn - - gets the current value
setFn - - sets the current value
val - - is the value to set iff it does not overwrite a previous value
config - - specifies reconciliation configuration - config.resolveDefined uses defined value if true or undefined, undefined if false - config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined - config.resolveMax uses max over min if true, min over max if false, must be equal if undefined
errMsg - - is the error message to throw if the values cannot be reconciled (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) shuffle()

- - - - - - -
- Randomize array element order in-place using Durstenfeld shuffle algorithm. - -Credit: https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) sort(the)

- - - - - - -
- Sorts an array by natural ordering. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
the - - array to sort
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) strContains(str, substring)

- - - - - - -
- Indicates if the given string contains the given substring. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - is the string to search for a substring
substring - - is the substring to searchin within the string
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the substring is within the string, false otherwise -
- - - - - - - - - - - - - - - -

(static) stringifyBIs(str) → {string}

- - - - - - -
- Replace big integers (16 or more consecutive digits) with strings in order -to preserve numeric precision. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
str - - -string - - - - is the string to be modified
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the modified string with big numbers converted to strings -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(static) toLowerCaseArray(arr)

- - - - - - -
- Returns a copy of the given array where each element is lowercase. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arr - - is the array to convert to lowercase
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- a copy of the given array where each element is lowercase -
- - - - - - - - - - - - - - - -

(static) toUniqueArray(arr)

- - - - - - -
- Returns a new array containing unique elements of the given array. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
arr - - is the array to return unique elements from
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- a new array with the given array's unique elements -
- - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/HttpClient.html b/docs/HttpClient.html deleted file mode 100644 index 049c9f1ed..000000000 --- a/docs/HttpClient.html +++ /dev/null @@ -1,740 +0,0 @@ - - - - - JSDoc: Class: HttpClient - - - - - - - - - - -
- -

Class: HttpClient

- - - - - - -
- -
- -

HttpClient

- -
Handle HTTP requests with a uniform interface.
- - -
- -
-
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(static) digestAuthRequest()

- - - - - - -
- Modification of digest auth request by @inorganik. - -Dependent on CryptoJS MD5 hashing: http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5.js - -MIT licensed. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async, static) request(request) → {object|string|object|Uint8Array|number|number|object}

- - - - - - -
-

Make a HTTP request.

-

- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
request - - -object - - - - configures the request to make -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
method - - -string - - - - HTTP method ("GET", "PUT", "POST", "DELETE", etc)
uri - - -string - - - - uri to request
body - - -string -| - -object -| - -Uint8Array - - - - request body
username - - -string - - - - username to authenticate the request (optional)
password - - -string - - - - password to authenticate the request (optional)
headers - - -object - - - - headers to add to the request (optional)
requestApi - - -string - - - - one of "fetch" or "xhr" (default "fetch")
resolveWithFullResponse - - -boolean - - - - return full response if true, else body only (default false)
rejectUnauthorized - - -boolean - - - - whether or not to reject self-signed certificates (default true)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
-
    -
  • -
    - response - the response object -
    - - - -
    -
    - Type -
    -
    - -object - - -
    -
    -
  • - -
  • -
    - response.body - the response body -
    - - - -
    -
    - Type -
    -
    - -string -| - -object -| - -Uint8Array - - -
    -
    -
  • - -
  • -
    - response.statusCode - the response code -
    - - - -
    -
    - Type -
    -
    - -number - - -
    -
    -
  • - -
  • -
    - response.statusText - the response message -
    - - - -
    -
    - Type -
    -
    - -number - - -
    -
    -
  • - -
  • -
    - response.headers - the response headers -
    - - - -
    -
    - Type -
    -
    - -object - - -
    -
    -
  • -
- - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/LibraryUtils.html b/docs/LibraryUtils.html deleted file mode 100644 index 864c3cc5c..000000000 --- a/docs/LibraryUtils.html +++ /dev/null @@ -1,1155 +0,0 @@ - - - - - JSDoc: Class: LibraryUtils - - - - - - - - - - -
- -

Class: LibraryUtils

- - - - - - -
- -
- -

LibraryUtils

- -
Collection of helper utilities for the library.
- - -
- -
-
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(async, static) getWasmMemoryUsed() → {int}

- - - - - - -
- Get the total memory used by WebAssembly. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the total memory used by WebAssembly -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(static) getWasmModule()

- - - - - - -
- Get the WebAssembly module in the current context (nodejs, browser main thread or worker). -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) getWorker() → {Worker}

- - - - - - -
- Get a singleton instance of a web worker to share. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- a worker to share among wallet instances -
- - - -
-
- Type -
-
- -Worker - - -
-
- - - - - - - - - - - - - -

(async, static) invokeWorker(identifies, fnName, args) → {Promise}

- - - - - - -
- Invoke a web worker function and get the result with error handling. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
identifies - - -objectId - - - - the worker object to invoke
fnName - - -string - - - - is the name of the function to invoke
args - - -Array.<Object> - - - - are function arguments to invoke with
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- resolves with response payload from the worker or an error -
- - - -
-
- Type -
-
- -Promise - - -
-
- - - - - - - - - - - - - -

(static) isRejectUnauthorized(fnId)

- - - - - - -
- Indicate if unauthorized requests should be rejected. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
fnId - - -string - - - - uniquely identifies the function
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async, static) loadCoreModule()

- - - - - - -
- Load the WebAssembly core module with caching. - -The core module is a superset of the keys module and overrides it. - -TODO: this is separate static function from loadKeysModule() because webpack cannot bundle WebWorker using runtime param for conditional import -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async, static) loadKeysModule()

- - - - - - -
- Load the WebAssembly keys module with caching. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) setRejectUnauthorizedFn(fnId, fn)

- - - - - - -
- Register a function by id which informs if unauthorized requests (e.g. -self-signed certificates) should be rejected. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
fnId - - -string - - - - unique identifier for the function
fn - - -function - - - - function to inform if unauthorized requests should be rejected
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroAccount.html b/docs/MoneroAccount.html deleted file mode 100644 index d05e454f8..000000000 --- a/docs/MoneroAccount.html +++ /dev/null @@ -1,1350 +0,0 @@ - - - - - JSDoc: Class: MoneroAccount - - - - - - - - - - -
- -

Class: MoneroAccount

- - - - - - -
- -
- -

MoneroAccount()

- -
Monero account model.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroAccount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getBalance()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrimaryAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSubaddresses()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTag()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getUnlockedBalance()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBalance()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrimaryAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSubaddresses()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTag()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setUnlockedBalance()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroAccountTag.html b/docs/MoneroAccountTag.html deleted file mode 100644 index 8feed0df7..000000000 --- a/docs/MoneroAccountTag.html +++ /dev/null @@ -1,678 +0,0 @@ - - - - - JSDoc: Class: MoneroAccountTag - - - - - - - - - - -
- -

Class: MoneroAccountTag

- - - - - - -
- -
- -

MoneroAccountTag()

- -
Represents an account tag.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroAccountTag()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getAccountIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLabel()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTag()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAccountIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLabel()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTag()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroAddressBookEntry.html b/docs/MoneroAddressBookEntry.html deleted file mode 100644 index ed173ad6b..000000000 --- a/docs/MoneroAddressBookEntry.html +++ /dev/null @@ -1,930 +0,0 @@ - - - - - JSDoc: Class: MoneroAddressBookEntry - - - - - - - - - - -
- -

Class: MoneroAddressBookEntry

- - - - - - -
- -
- -

MoneroAddressBookEntry()

- -
Monero address book entry model
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroAddressBookEntry()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDescription()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDescription()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroAltChain.html b/docs/MoneroAltChain.html deleted file mode 100644 index 8f63870bc..000000000 --- a/docs/MoneroAltChain.html +++ /dev/null @@ -1,1098 +0,0 @@ - - - - - JSDoc: Class: MoneroAltChain - - - - - - - - - - -
- -

Class: MoneroAltChain

- - - - - - -
- -
- -

MoneroAltChain()

- -
Models an alternative chain seen by the node.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroAltChain()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getBlockHashes()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLength()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMainChainParentBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBlockHashes()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLength()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMainChainParentBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroBan.html b/docs/MoneroBan.html deleted file mode 100644 index 80ff45c9a..000000000 --- a/docs/MoneroBan.html +++ /dev/null @@ -1,930 +0,0 @@ - - - - - JSDoc: Class: MoneroBan - - - - - - - - - - -
- -

Class: MoneroBan

- - - - - - -
- -
- -

MoneroBan()

- -
Monero banhammer.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroBan()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getHost()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getIp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSeconds()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isBanned()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHost()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsBanned()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSeconds()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroBlock.html b/docs/MoneroBlock.html deleted file mode 100644 index 6086ba8a4..000000000 --- a/docs/MoneroBlock.html +++ /dev/null @@ -1,4600 +0,0 @@ - - - - - JSDoc: Class: MoneroBlock - - - - - - - - - - -
- -

Class: MoneroBlock

- - - - - - -
- -
- -

MoneroBlock(state, txType)

- -
Models a Monero block in the blockchain.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroBlock(state, txType)

- - - - - - -
- Construct the model. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
state - - -MoneroBlock -| - -MoneroBlockHeader -| - -object - - - - is existing state to initialize from (optional)
txType - - -MoneroBlock.DeserializationType - - - - informs the tx deserialization type (MoneroTx, MoneroTxWallet, MoneroTxQuery)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - - - - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getCumulativeDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDepth()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHeight() → {number}

- - - - - - -
- Return the block's height which is the total number of blocks that have occurred before. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the block's height -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

getHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLongTermWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMajorVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMinerTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMinerTxHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMinorVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNonce()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumTxs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOrphanStatus()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPowHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrevHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getReward()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTxHashes()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTxs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCumulativeDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDepth()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHeight(height) → {MoneroBlockHeader}

- - - - - - -
- Set the block's height which is the total number of blocks that have occurred before. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
height - - -number - - - - is the block's height to set
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- a reference to this header for chaining -
- - - -
-
- Type -
-
- -MoneroBlockHeader - - -
-
- - - - - - - - - - - - - -

setHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLongTermWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMajorVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMinerTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMinerTxHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMinorVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNonce()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumTxs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOrphanStatus()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPowHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrevHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setReward()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTxHashes()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTxs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroBlockHeader.html b/docs/MoneroBlockHeader.html deleted file mode 100644 index 212a107da..000000000 --- a/docs/MoneroBlockHeader.html +++ /dev/null @@ -1,3691 +0,0 @@ - - - - - JSDoc: Class: MoneroBlockHeader - - - - - - - - - - -
- -

Class: MoneroBlockHeader

- - - - - - -
- -
- -

MoneroBlockHeader(state)

- -
Models a Monero block header which contains information about the block.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroBlockHeader(state)

- - - - - - -
- Construct the model. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
state - - -MoneroBlockHeader -| - -object - - - - is existing state to initialize from (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getCumulativeDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDepth()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHeight() → {number}

- - - - - - -
- Return the block's height which is the total number of blocks that have occurred before. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the block's height -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

getLongTermWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMajorVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMinerTxHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMinorVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNonce()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumTxs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOrphanStatus()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPowHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrevHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getReward()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCumulativeDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDepth()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHeight(height) → {MoneroBlockHeader}

- - - - - - -
- Set the block's height which is the total number of blocks that have occurred before. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
height - - -number - - - - is the block's height to set
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- a reference to this header for chaining -
- - - -
-
- Type -
-
- -MoneroBlockHeader - - -
-
- - - - - - - - - - - - - -

setLongTermWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMajorVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMinerTxHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMinorVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNonce()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumTxs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOrphanStatus()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPowHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrevHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setReward()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroBlockTemplate.html b/docs/MoneroBlockTemplate.html deleted file mode 100644 index 5bca174da..000000000 --- a/docs/MoneroBlockTemplate.html +++ /dev/null @@ -1,2022 +0,0 @@ - - - - - JSDoc: Class: MoneroBlockTemplate - - - - - - - - - - -
- -

Class: MoneroBlockTemplate

- - - - - - -
- -
- -

MoneroBlockTemplate()

- -
Monero block template to mine.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroBlockTemplate()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getBlockHashingBlob()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getBlockTemplateBlob()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getExpectedReward()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNextSeedHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrevHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getReservedOffset()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSeedHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSeedHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBlockHashingBlob()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBlockTemplateBlob()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setExpectedReward()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNextSeedHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrevHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setReservedOffset()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSeedHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSeedHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroCheck.html b/docs/MoneroCheck.html deleted file mode 100644 index 3f8043f47..000000000 --- a/docs/MoneroCheck.html +++ /dev/null @@ -1,342 +0,0 @@ - - - - - JSDoc: Class: MoneroCheck - - - - - - - - - - -
- -

Class: MoneroCheck

- - - - - - -
- -
- -

MoneroCheck()

- -
Base class for results from checking a transaction or reserve proof.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroCheck()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

isGood()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsGood()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroCheckReserve.html b/docs/MoneroCheckReserve.html deleted file mode 100644 index 8ceea47b4..000000000 --- a/docs/MoneroCheckReserve.html +++ /dev/null @@ -1,783 +0,0 @@ - - - - - JSDoc: Class: MoneroCheckReserve - - - - - - - - - - -
- -

Class: MoneroCheckReserve

- - - - - - -
- -
- -

MoneroCheckReserve()

- -
Results from checking a reserve proof.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroCheckReserve()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - - - - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getTotalAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getUnconfirmedSpentAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isGood()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsGood()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTotalAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setUnconfirmedSpentAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroCheckTx.html b/docs/MoneroCheckTx.html deleted file mode 100644 index e0fdfa16e..000000000 --- a/docs/MoneroCheckTx.html +++ /dev/null @@ -1,951 +0,0 @@ - - - - - JSDoc: Class: MoneroCheckTx - - - - - - - - - - -
- -

Class: MoneroCheckTx

- - - - - - -
- -
- -

MoneroCheckTx()

- -
Results from checking a transaction key.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroCheckTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - - - - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getNumConfirmations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getReceivedAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

inTxPool()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isGood()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setInTxPool()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsGood()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumConfirmations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setReceivedAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroDaemon.html b/docs/MoneroDaemon.html deleted file mode 100644 index 7f7a1db02..000000000 --- a/docs/MoneroDaemon.html +++ /dev/null @@ -1,9655 +0,0 @@ - - - - - JSDoc: Interface: MoneroDaemon - - - - - - - - - - -
- -

Interface: MoneroDaemon

- - - - - - -
- -
- -

MoneroDaemon

- -
Monero daemon interface and default implementations.
- - -
- -
-
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(static) parseNetworkType(network) → {MoneroNetworkType}

- - - - - - -
- Parses a network string to an enumerated type. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
network - - -string - - - - network string to parse
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- enumerated network type -
- - - -
-
- Type -
-
- -MoneroNetworkType - - -
-
- - - - - - - - - - - - - -

(async) addBlockListener(listener)

- - - - - - -
- Register a listener to be notified when blocks are added to the chain. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
listener - - -function - - - - invoked with MoneroBlockHeaders as blocks are added to the chain
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) checkForUpdate() → {MoneroDaemonUpdateCheckResult}

- - - - - - -
- Check for update. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result -
- - - -
-
- Type -
-
- -MoneroDaemonUpdateCheckResult - - -
-
- - - - - - - - - - - - - -

(async) downloadUpdate(path) → {MoneroDaemonUpdateDownloadResult}

- - - - - - -
- Download an update. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
path - - -string - - - - path to download the update (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result -
- - - -
-
- Type -
-
- -MoneroDaemonUpdateDownloadResult - - -
-
- - - - - - - - - - - - - -

(async) flushTxPool(hashes)

- - - - - - -
- Flush transactions from the tx pool. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
hashes - - -string -| - -Array.<string> - - - - specific transactions to flush (defaults to all)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) getAltBlockHashes() → {Array.<string>}

- - - - - - -
- Get known block hashes which are not on the main chain. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- known block hashes which are not on the main chain -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) getAltChains() → {Array.<MoneroAltChain>}

- - - - - - -
- Get alternative chains seen by the node. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- alternative chains -
- - - -
-
- Type -
-
- -Array.<MoneroAltChain> - - -
-
- - - - - - - - - - - - - -

(async) getBlockByHash(blockHash) → {MoneroBlock}

- - - - - - -
- Get a block by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blockHash - - -string - - - - hash of the block to get
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- with the given hash -
- - - -
-
- Type -
-
- -MoneroBlock - - -
-
- - - - - - - - - - - - - -

(async) getBlockByHeight(height) → {MoneroBlock}

- - - - - - -
- Get a block by height. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
height - - -int - - - - height of the block to get
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- with the given height -
- - - -
-
- Type -
-
- -MoneroBlock - - -
-
- - - - - - - - - - - - - -

(async) getBlockHash(height) → {string}

- - - - - - -
- Get a block's hash by its height. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
height - - -int - - - - height of the block hash to get
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the block's hash at the given height -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getBlockHashes(blockHashes, startHeight) → {Array.<string>}

- - - - - - -
- Get block hashes as a binary request to the daemon. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blockHashes - - -Array.<string> - - - - specify block hashes to fetch; first 10 blocks hash goes - sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 - and so on, and the last one is always genesis block
startHeight - - -int - - - - starting height of block hashes to return
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- requested block hashes -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) getBlockHeaderByHash(blockHash) → {MoneroBlockHeader}

- - - - - - -
- Get a block header by its hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blockHash - - -string - - - - hash of the block to get the header of
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- block's header -
- - - -
-
- Type -
-
- -MoneroBlockHeader - - -
-
- - - - - - - - - - - - - -

(async) getBlockHeaderByHeight(height) → {MoneroBlockHeader}

- - - - - - -
- Get a block header by its height. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
height - - -int - - - - height of the block to get the header of
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- block's header -
- - - -
-
- Type -
-
- -MoneroBlockHeader - - -
-
- - - - - - - - - - - - - -

(async) getBlockHeadersByRange(startHeight, endHeight) → {Array.<MoneroBlockHeader>}

- - - - - - -
- Get block headers for the given range. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
startHeight - - -int - - - - start height lower bound inclusive (optional)
endHeight - - -int - - - - end height upper bound inclusive (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- for the given range -
- - - -
-
- Type -
-
- -Array.<MoneroBlockHeader> - - -
-
- - - - - - - - - - - - - -

(async) getBlocksByHash(blockHashes, startHeight, prune) → {Array.<MoneroBlock>}

- - - - - - -
- Get blocks by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blockHashes - - -Array.<string> - - - - array of hashes; first 10 blocks hashes goes sequential, - next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, - and the last one is always genesis block
startHeight - - -int - - - - start height to get blocks by hash
prune - - -boolean - - - - specifies if returned blocks should be pruned (defaults to false) // TODO: test default
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- retrieved blocks -
- - - -
-
- Type -
-
- -Array.<MoneroBlock> - - -
-
- - - - - - - - - - - - - -

(async) getBlocksByHeight(heights) → {Array.<MoneroBlock>}

- - - - - - -
- Get blocks at the given heights. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
heights - - -Array.<int> - - - - heights of the blocks to get
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are blocks at the given heights -
- - - -
-
- Type -
-
- -Array.<MoneroBlock> - - -
-
- - - - - - - - - - - - - -

(async) getBlocksByRange(startHeight, endHeight) → {Array.<MoneroBlock>}

- - - - - - -
- Get blocks in the given height range. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
startHeight - - -int - - - - start height lower bound inclusive (optional)
endHeight - - -int - - - - end height upper bound inclusive (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are blocks in the given height range -
- - - -
-
- Type -
-
- -Array.<MoneroBlock> - - -
-
- - - - - - - - - - - - - -

(async) getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) → {Array.<MoneroBlock>}

- - - - - - -
- Get blocks in the given height range as chunked requests so that each request is -not too big. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
startHeight - - -int - - - - start height lower bound inclusive (optional)
endHeight - - -int - - - - end height upper bound inclusive (optional)
maxChunkSize - - -int - - - - maximum chunk size in any one request (default 3,000,000 bytes)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- blocks in the given height range -
- - - -
-
- Type -
-
- -Array.<MoneroBlock> - - -
-
- - - - - - - - - - - - - -

(async) getBlockTemplate(walletAddress, reserveSize) → {MoneroBlockTemplate}

- - - - - - -
- Get a block template for mining a new block. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
walletAddress - - -string - - - - address of the wallet to receive miner transactions if block is successfully mined
reserveSize - - -int - - - - reserve size (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is a block template for mining a new block -
- - - -
-
- Type -
-
- -MoneroBlockTemplate - - -
-
- - - - - - - - - - - - - -

(async) getConnections() → {Array.<MoneroDaemonConnection>}

- - - - - - -
- Get incoming and outgoing connections to the node. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- daemon's peer connections -
- - - -
-
- Type -
-
- -Array.<MoneroDaemonConnection> - - -
-
- - - - - - - - - - - - - -

(async) getDownloadLimit() → {int}

- - - - - - -
- Get the download bandwidth limit. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- download bandwidth limit -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) getFeeEstimate(graceBlocks) → {BigInteger}

- - - - - - -
- Get the fee estimate per kB. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
graceBlocks - - -int - - - - TODO
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- fee estimate per kB. -
- - - -
-
- Type -
-
- -BigInteger - - -
-
- - - - - - - - - - - - - -

(async) getHardForkInfo() → {MoneroHardForkInfo}

- - - - - - -
- Look up information regarding hard fork voting and readiness. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- contains hard fork information -
- - - -
-
- Type -
-
- -MoneroHardForkInfo - - -
-
- - - - - - - - - - - - - -

(async) getHeight() → {int}

- - - - - - -
- Get the number of blocks in the longest chain known to the node. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the number of blocks -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) getInfo() → {MoneroDaemonInfo}

- - - - - - -
- Get general information about the state of the node and the network. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is general information about the node and network -
- - - -
-
- Type -
-
- -MoneroDaemonInfo - - -
-
- - - - - - - - - - - - - -

(async) getKeyImageSpentStatus(keyImage) → {MoneroKeyImageSpentStatus}

- - - - - - -
- Get the spent status of the given key image. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyImage - - -string - - - - key image hex to get the status of
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- status of the key image -
- - - -
-
- Type -
-
- -MoneroKeyImageSpentStatus - - -
-
- - - - - - - - - - - - - -

(async) getKeyImageSpentStatuses(keyImages) → {Array.<MoneroKeyImageSpentStatus>}

- - - - - - -
- Get the spent status of each given key image. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyImages - - -Array.<string> - - - - are hex key images to get the statuses of
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- status for each key image -
- - - -
-
- Type -
-
- -Array.<MoneroKeyImageSpentStatus> - - -
-
- - - - - - - - - - - - - -

(async) getKnownPeers() → {Array.<MoneroDaemonPeer>}

- - - - - - -
- Get known peers including their last known online status. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- known peers -
- - - -
-
- Type -
-
- -Array.<MoneroDaemonPeer> - - -
-
- - - - - - - - - - - - - -

(async) getLastBlockHeader() → {MoneroBlockHeader}

- - - - - - -
- Get the last block's header. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- last block's header -
- - - -
-
- Type -
-
- -MoneroBlockHeader - - -
-
- - - - - - - - - - - - - -

(async) getMinerTxSum(height, numBlocks) → {MoneroMinerTxSum}

- - - - - - -
- Gets the total emissions and fees from the genesis block to the current height. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
height - - -int - - - - height to start computing the miner sum
numBlocks - - -int - - - - number of blocks to include in the sum
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- encapsulates the total emissions and fees since the genesis block -
- - - -
-
- Type -
-
- -MoneroMinerTxSum - - -
-
- - - - - - - - - - - - - -

(async) getMiningStatus() → {MoneroMiningStatus}

- - - - - - -
- Get the daemon's mining status. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- daemon's mining status -
- - - -
-
- Type -
-
- -MoneroMiningStatus - - -
-
- - - - - - - - - - - - - -

(async) getNextBlockHeader() → {MoneroBlockHeader}

- - - - - - -
- Get the header of the next block added to the chain. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- header of the next block added to the chain -
- - - -
-
- Type -
-
- -MoneroBlockHeader - - -
-
- - - - - - - - - - - - - -

(async) getOutputDistribution(amounts, cumulative, startHeight, endHeight) → {Array.<MoneroOutputDistributionEntry>}

- - - - - - -
- Creates an output distribution. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
amounts - - -Array.<BigInteger> - - - - amounts of outputs to make the distribution with
cumulative - - -boolean - - - - specifies if the results should be cumulative (defaults to TODO)
startHeight - - -int - - - - start height lower bound inclusive (optional)
endHeight - - -int - - - - end height upper bound inclusive (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are entries meeting the parameters -
- - - -
-
- Type -
-
- -Array.<MoneroOutputDistributionEntry> - - -
-
- - - - - - - - - - - - - -

(async) getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) → {Array.<MoneroOutputHistogramEntry>}

- - - - - - -
- Get a histogram of output amounts. For all amounts (possibly filtered by -parameters), gives the number of outputs on the chain for that amount. -RingCT outputs counts as 0 amount. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
amounts - - -Array.<BigInteger> - - - - amounts of outputs to make the histogram with
minCount - - -int - - - - TODO
maxCount - - -int - - - - TODO
isUnlocked - - -boolean - - - - makes a histogram with outputs with the specified lock state
recentCutoff - - -int - - - - TODO
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are entries meeting the parameters -
- - - -
-
- Type -
-
- -Array.<MoneroOutputHistogramEntry> - - -
-
- - - - - - - - - - - - - -

(async) getOutputs(outputs) → {Array.<MoneroOutput>}

- - - - - - -
- Get outputs identified by a list of output amounts and indices as a binary -request. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
outputs - - -Array.<MoneroOutput> - - - - identify each output by amount and index
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- identified outputs -
- - - -
-
- Type -
-
- -Array.<MoneroOutput> - - -
-
- - - - - - - - - - - - - -

(async) getPeerBans() → {Array.<MoneroBan>}

- - - - - - -
- Get peer bans. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- entries about banned peers -
- - - -
-
- Type -
-
- -Array.<MoneroBan> - - -
-
- - - - - - - - - - - - - -

(async) getSyncInfo() → {MoneroDaemonSyncInfo}

- - - - - - -
- Get synchronization information. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- contains sync information -
- - - -
-
- Type -
-
- -MoneroDaemonSyncInfo - - -
-
- - - - - - - - - - - - - -

(async) getTx(txHash, prune) → {MoneroTx}

- - - - - - -
- Get a transaction by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
txHash - - -string - - - - - - hash of the transaction to get
prune - - -boolean - - - - - - false - - specifies if the returned tx should be pruned (defaults to false)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- transaction with the given hash -
- - - -
-
- Type -
-
- -MoneroTx - - -
-
- - - - - - - - - - - - - -

(async) getTxHex(txHash, prune) → {string}

- - - - - - -
- Get a transaction hex by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
txHash - - -string - - - - - - hash of the transaction to get hex from
prune - - -boolean - - - - - - false - - specifies if the returned tx hex should be pruned (defaults to false)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- tx hex with the given hash -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getTxHexes(txHashes, prune) → {Array.<string>}

- - - - - - -
- Get transaction hexes by hashes. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
txHashes - - -Array.<string> - - - - - - hashes of transactions to get hexes from
prune - - -boolean - - - - - - false - - specifies if the returned tx hexes should be pruned (defaults to false)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- tx hexes -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) getTxPool() → {Array.<MoneroTx>}

- - - - - - -
- Get valid transactions seen by the node but not yet mined into a block, as well -as spent key image information for the tx pool. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are transactions in the transaction pool -
- - - -
-
- Type -
-
- -Array.<MoneroTx> - - -
-
- - - - - - - - - - - - - -

(async) getTxPoolBacklog() → {Array.<MoneroTxBacklogEntry>}

- - - - - - -
- Get all transaction pool backlog. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- backlog entries -
- - - -
-
- Type -
-
- -Array.<MoneroTxBacklogEntry> - - -
-
- - - - - - - - - - - - - -

(async) getTxPoolHashes() → {Array.<string>}

- - - - - - -
- Get hashes of transactions in the transaction pool. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are hashes of transactions in the transaction pool -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) getTxPoolStats() → {MoneroTxPoolStats}

- - - - - - -
- Get transaction pool statistics. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- contains statistics about the transaction pool -
- - - -
-
- Type -
-
- -MoneroTxPoolStats - - -
-
- - - - - - - - - - - - - -

(async) getTxs(txHashes, prune) → {Array.<MoneroTx>}

- - - - - - -
- Get transactions by hashes. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
txHashes - - -Array.<string> - - - - - - hashes of transactions to get
prune - - -boolean - - - - - - false - - specifies if the returned txs should be pruned (defaults to false)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- transactions with the given hashes -
- - - -
-
- Type -
-
- -Array.<MoneroTx> - - -
-
- - - - - - - - - - - - - -

(async) getUploadLimit() → {int}

- - - - - - -
- Get the upload bandwidth limit. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- upload bandwidth limit -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) getVersion() → {MoneroVersion}

- - - - - - -
- Gets the version of the daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the version of the daemon -
- - - -
-
- Type -
-
- -MoneroVersion - - -
-
- - - - - - - - - - - - - -

(async) isConnected() → {boolean}

- - - - - - -
- Indicates if the client is connected to the daemon via RPC. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the client is connected to the daemon, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isTrusted() → {boolean}

- - - - - - -
- Indicates if the daemon is trusted xor untrusted. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the daemon is trusted, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) relayTxByHash(txHash)

- - - - - - -
- Relays a transaction by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - hash of the transaction to relay
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) relayTxsByHash(txHashes)

- - - - - - -
- Relays transactions by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHashes - - -Array.<string> - - - - hashes of the transactinos to relay
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) removeBlockListener(listener)

- - - - - - -
- Unregister a listener to be notified when blocks are added to the chain. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
listener - - -function - - - - previously registered listener to be unregistered
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) resetDownloadLimit() → {int}

- - - - - - -
- Reset the download bandwidth limit. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- download bandwidth limit after resetting -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) resetUploadLimit() → {int}

- - - - - - -
- Reset the upload bandwidth limit. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- upload bandwidth limit after resetting -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) setDownloadLimit(limit) → {int}

- - - - - - -
- Set the download bandwidth limit. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
limit - - -int - - - - download limit to set (-1 to reset to default)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- new download limit after setting -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) setIncomingPeerLimit(limit)

- - - - - - -
- Limit number of incoming peers. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
limit - - -int - - - - maximum number of incoming peers
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setOutgoingPeerLimit(limit)

- - - - - - -
- Limit number of outgoing peers. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
limit - - -int - - - - maximum number of outgoing peers
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setPeerBan(ban)

- - - - - - -
- Ban a peer node. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
ban - - -MoneroBan - - - - contains information about a node to ban
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setPeerBans(bans)

- - - - - - -
- Ban peers nodes. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
bans - - -Array.<MoneroBan> - - - - specify which peers to ban
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setUploadLimit(limit) → {int}

- - - - - - -
- Set the upload bandwidth limit. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
limit - - upload limit to set (-1 to reset to default)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- new upload limit after setting -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) startMining(address, numThreads, isBackground, ignoreBattery)

- - - - - - -
- Start mining. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - address given miner rewards if the daemon mines a block
numThreads - - -integer - - - - number of mining threads to run
isBackground - - -boolean - - - - specifies if the miner should run in the background or not
ignoreBattery - - -boolean - - - - specifies if the battery state (e.g. on laptop) should be ignored or not
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) stop()

- - - - - - -
- Safely disconnect and shut down the daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) stopMining()

- - - - - - -
- Stop mining. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) submitBlock(blockBlob)

- - - - - - -
- Submit a mined block to the network. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blockBlob - - -string - - - - mined block to submit
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) submitBlocks(blockBlobs)

- - - - - - -
- Submit mined blocks to the network. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blockBlobs - - -Array.<string> - - - - mined blocks to submit
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) submitTxHex(txHex, doNotRelay) → {MoneroSubmitTxResult}

- - - - - - -
- Submits a transaction to the daemon's pool. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHex - - -string - - - - raw transaction hex to submit
doNotRelay - - -boolean - - - - specifies if the tx should be relayed (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- contains submission results -
- - - -
-
- Type -
-
- -MoneroSubmitTxResult - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroDaemonConnection.html b/docs/MoneroDaemonConnection.html deleted file mode 100644 index 49db02e91..000000000 --- a/docs/MoneroDaemonConnection.html +++ /dev/null @@ -1,3282 +0,0 @@ - - - - - JSDoc: Class: MoneroDaemonConnection - - - - - - - - - - -
- -

Class: MoneroDaemonConnection

- - - - - - -
- -
- -

MoneroDaemonConnection()

- -
Monero daemon connection.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroDaemonConnection()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getAvgDownload()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAvgUpload()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getCurrentDownload()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getCurrentUpload()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLiveTime()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumReceives()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumSends()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumSupportFlags()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPeer()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getReceiveIdleTime()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSendIdleTime()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getState()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getType()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isIncoming()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isLocalHost()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isLocalIp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAvgDownload()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAvgUpload()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCurrentDownload()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCurrentUpload()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsIncoming()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsLocalHost()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsLocalIp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLiveTime()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumReceives()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumSends()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumSupportFlags()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPeer()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setReceiveIdleTime()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSendIdleTime()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setState()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setType()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroDaemonConnectionSpan.html b/docs/MoneroDaemonConnectionSpan.html deleted file mode 100644 index b74595026..000000000 --- a/docs/MoneroDaemonConnectionSpan.html +++ /dev/null @@ -1,1434 +0,0 @@ - - - - - JSDoc: Class: MoneroDaemonConnectionSpan - - - - - - - - - - -
- -

Class: MoneroDaemonConnectionSpan

- - - - - - -
- -
- -

MoneroDaemonConnectionSpan()

- -
Monero daemon connection span.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroDaemonConnectionSpan()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getConnectionId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumBlocks()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRate()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRemoteAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSpeed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getStartHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setConnectionId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumBlocks()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRate()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRemoteAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSpeed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setStartHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroDaemonInfo.html b/docs/MoneroDaemonInfo.html deleted file mode 100644 index acf750daa..000000000 --- a/docs/MoneroDaemonInfo.html +++ /dev/null @@ -1,5130 +0,0 @@ - - - - - JSDoc: Class: MoneroDaemonInfo - - - - - - - - - - -
- -

Class: MoneroDaemonInfo

- - - - - - -
- -
- -

MoneroDaemonInfo()

- -
Monero daemon info.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroDaemonInfo()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getBlockSizeLimit()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getBlockSizeMedian()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getBlockWeightLimit()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getBlockWeightMedian()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getBootstrapDaemonAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getCredits()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getCumulativeDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDatabaseSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getFreeSpace()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHeightWithoutBootstrap()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNetworkType()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumAltBlocks()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumIncomingConnections()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumOfflinePeers()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumOnlinePeers()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumOutgoingConnections()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumRpcConnections()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumTxs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumTxsPool()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getStartTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTarget()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTargetHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTopBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getUpdateAvailable()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getWasBootstrapEverUsed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isOffline()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBlockSizeLimit()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBlockSizeMedian()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBlockWeightLimit()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBlockWeightMedian()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBootstrapDaemonAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCredits()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCumulativeDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDatabaseSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDifficulty()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setFreeSpace()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHeightWithoutBootstrap()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsOffline()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNetworkType()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumAltBlocks()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumIncomingConnections()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumOfflinePeers()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumOnlinePeers()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumOutgoingConnections()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumRpcConnections()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumTxs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumTxsPool()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setStartTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTarget()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTargetHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTopBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setUpdateAvailable()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setWasBootstrapEverUsed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroDaemonPeer.html b/docs/MoneroDaemonPeer.html deleted file mode 100644 index ffd12334a..000000000 --- a/docs/MoneroDaemonPeer.html +++ /dev/null @@ -1,1797 +0,0 @@ - - - - - JSDoc: Class: MoneroDaemonPeer - - - - - - - - - - -
- -

Class: MoneroDaemonPeer

- - - - - - -
- -
- -

MoneroDaemonPeer()

- -
Models a peer to the daemon.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroDaemonPeer()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHost()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLastSeenTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPort()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPruningSeed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRpcCreditsPerHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRpcPort()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isOnline() → {boolean}

- - - - - - -
- Indicates if the peer was online when last checked (aka "white listed" as -opposed to "gray listed"). -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if peer was online when last checked, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

setAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHost()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsOnline()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLastSeenTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPort()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPruningSeed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRpcCreditsPerHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRpcPort()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroDaemonRpc.html b/docs/MoneroDaemonRpc.html deleted file mode 100644 index 3b1960c6f..000000000 --- a/docs/MoneroDaemonRpc.html +++ /dev/null @@ -1,9740 +0,0 @@ - - - - - JSDoc: Class: MoneroDaemonRpc - - - - - - - - - - -
- -

Class: MoneroDaemonRpc

- - - - - - -
- -
- -

MoneroDaemonRpc(uriOrConfigOrConnection, username, password, rejectUnauthorized, pollInterval, proxyToWorker)

- -
Implements a MoneroDaemon as a client of monero-daemon-rpc.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroDaemonRpc(uriOrConfigOrConnection, username, password, rejectUnauthorized, pollInterval, proxyToWorker)

- - - - - - -
-

Construct a daemon RPC client.

- -

Examples:

- - -let daemon = new MoneroDaemonRpc("http://localhost:38081", "superuser", "abctesting123");

- -let daemon = new MoneroDaemonRpc({
-   uri: "http://localhost:38081",
-   username: "superuser",
-   password: "abctesting123"
-}); -
-

- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uriOrConfigOrConnection - - -string -| - -object -| - -MoneroRpcConnection - - - - uri of monero-daemon-rpc or JS config object or MoneroRpcConnection -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uri - - -string - - - - uri of monero-daemon-rpc
username - - -string - - - - username to authenticate with monero-daemon-rpc (optional)
password - - -string - - - - password to authenticate with monero-daemon-rpc (optional)
rejectUnauthorized - - -boolean - - - - rejects self-signed certificates if true (default true)
pollInterval - - -number - - - - poll interval to query for updates in ms (default 5000)
proxyToWorker - - -boolean - - - - run the daemon client in a web worker if true (default true if browser, false otherwise)
- -
username - - -string - - - - username to authenticate with monero-daemon-rpc (optional)
password - - -string - - - - password to authenticate with monero-daemon-rpc (optional)
rejectUnauthorized - - -boolean - - - - rejects self-signed certificates if true (default true)
pollInterval - - -number - - - - poll interval to query for updates in ms (default 5000)
proxyToWorker - - -boolean - - - - runs the daemon client in a web worker if true (default true if browser, false otherwise)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(async) addBlockListener(listener)

- - - - - - -
- Register a listener to be notified when blocks are added to the chain. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
listener - - -function - - - - invoked with MoneroBlockHeaders as blocks are added to the chain
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) checkForUpdate() → {MoneroDaemonUpdateCheckResult}

- - - - - - -
- Check for update. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result -
- - - -
-
- Type -
-
- -MoneroDaemonUpdateCheckResult - - -
-
- - - - - - - - - - - - - -

(async) downloadUpdate(path) → {MoneroDaemonUpdateDownloadResult}

- - - - - - -
- Download an update. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
path - - -string - - - - path to download the update (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result -
- - - -
-
- Type -
-
- -MoneroDaemonUpdateDownloadResult - - -
-
- - - - - - - - - - - - - -

(async) flushTxPool(hashes)

- - - - - - -
- Flush transactions from the tx pool. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
hashes - - -string -| - -Array.<string> - - - - specific transactions to flush (defaults to all)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) getAltBlockHashes() → {Array.<string>}

- - - - - - -
- Get known block hashes which are not on the main chain. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- known block hashes which are not on the main chain -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) getAltChains() → {Array.<MoneroAltChain>}

- - - - - - -
- Get alternative chains seen by the node. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- alternative chains -
- - - -
-
- Type -
-
- -Array.<MoneroAltChain> - - -
-
- - - - - - - - - - - - - -

(async) getBlockByHash(blockHash) → {MoneroBlock}

- - - - - - -
- Get a block by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blockHash - - -string - - - - hash of the block to get
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- with the given hash -
- - - -
-
- Type -
-
- -MoneroBlock - - -
-
- - - - - - - - - - - - - -

(async) getBlockByHeight(height) → {MoneroBlock}

- - - - - - -
- Get a block by height. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
height - - -int - - - - height of the block to get
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- with the given height -
- - - -
-
- Type -
-
- -MoneroBlock - - -
-
- - - - - - - - - - - - - -

(async) getBlockHash(height) → {string}

- - - - - - -
- Get a block's hash by its height. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
height - - -int - - - - height of the block hash to get
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the block's hash at the given height -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getBlockHeaderByHash(blockHash) → {MoneroBlockHeader}

- - - - - - -
- Get a block header by its hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blockHash - - -string - - - - hash of the block to get the header of
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- block's header -
- - - -
-
- Type -
-
- -MoneroBlockHeader - - -
-
- - - - - - - - - - - - - -

(async) getBlockHeaderByHeight(height) → {MoneroBlockHeader}

- - - - - - -
- Get a block header by its height. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
height - - -int - - - - height of the block to get the header of
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- block's header -
- - - -
-
- Type -
-
- -MoneroBlockHeader - - -
-
- - - - - - - - - - - - - -

(async) getBlockHeadersByRange(startHeight, endHeight) → {Array.<MoneroBlockHeader>}

- - - - - - -
- Get block headers for the given range. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
startHeight - - -int - - - - start height lower bound inclusive (optional)
endHeight - - -int - - - - end height upper bound inclusive (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- for the given range -
- - - -
-
- Type -
-
- -Array.<MoneroBlockHeader> - - -
-
- - - - - - - - - - - - - -

(async) getBlocksByHeight(heights) → {Array.<MoneroBlock>}

- - - - - - -
- Get blocks at the given heights. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
heights - - -Array.<int> - - - - heights of the blocks to get
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are blocks at the given heights -
- - - -
-
- Type -
-
- -Array.<MoneroBlock> - - -
-
- - - - - - - - - - - - - -

(async) getBlocksByRange(startHeight, endHeight) → {Array.<MoneroBlock>}

- - - - - - -
- Get blocks in the given height range. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
startHeight - - -int - - - - start height lower bound inclusive (optional)
endHeight - - -int - - - - end height upper bound inclusive (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are blocks in the given height range -
- - - -
-
- Type -
-
- -Array.<MoneroBlock> - - -
-
- - - - - - - - - - - - - -

(async) getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) → {Array.<MoneroBlock>}

- - - - - - -
- Get blocks in the given height range as chunked requests so that each request is -not too big. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
startHeight - - -int - - - - start height lower bound inclusive (optional)
endHeight - - -int - - - - end height upper bound inclusive (optional)
maxChunkSize - - -int - - - - maximum chunk size in any one request (default 3,000,000 bytes)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- blocks in the given height range -
- - - -
-
- Type -
-
- -Array.<MoneroBlock> - - -
-
- - - - - - - - - - - - - -

(async) getBlockTemplate(walletAddress, reserveSize) → {MoneroBlockTemplate}

- - - - - - -
- Get a block template for mining a new block. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
walletAddress - - -string - - - - address of the wallet to receive miner transactions if block is successfully mined
reserveSize - - -int - - - - reserve size (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is a block template for mining a new block -
- - - -
-
- Type -
-
- -MoneroBlockTemplate - - -
-
- - - - - - - - - - - - - -

(async) getConnections() → {Array.<MoneroDaemonConnection>}

- - - - - - -
- Get incoming and outgoing connections to the node. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- daemon's peer connections -
- - - -
-
- Type -
-
- -Array.<MoneroDaemonConnection> - - -
-
- - - - - - - - - - - - - -

(async) getDownloadLimit() → {int}

- - - - - - -
- Get the download bandwidth limit. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- download bandwidth limit -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) getFeeEstimate(graceBlocks) → {BigInteger}

- - - - - - -
- Get the fee estimate per kB. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
graceBlocks - - -int - - - - TODO
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- fee estimate per kB. -
- - - -
-
- Type -
-
- -BigInteger - - -
-
- - - - - - - - - - - - - -

(async) getHardForkInfo() → {MoneroHardForkInfo}

- - - - - - -
- Look up information regarding hard fork voting and readiness. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- contains hard fork information -
- - - -
-
- Type -
-
- -MoneroHardForkInfo - - -
-
- - - - - - - - - - - - - -

(async) getHeight() → {int}

- - - - - - -
- Get the number of blocks in the longest chain known to the node. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the number of blocks -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) getInfo() → {MoneroDaemonInfo}

- - - - - - -
- Get general information about the state of the node and the network. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is general information about the node and network -
- - - -
-
- Type -
-
- -MoneroDaemonInfo - - -
-
- - - - - - - - - - - - - -

(async) getKeyImageSpentStatus(keyImage) → {MoneroKeyImageSpentStatus}

- - - - - - -
- Get the spent status of the given key image. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyImage - - -string - - - - key image hex to get the status of
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- status of the key image -
- - - -
-
- Type -
-
- -MoneroKeyImageSpentStatus - - -
-
- - - - - - - - - - - - - -

(async) getKeyImageSpentStatuses(keyImages) → {Array.<MoneroKeyImageSpentStatus>}

- - - - - - -
- Get the spent status of each given key image. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyImages - - -Array.<string> - - - - are hex key images to get the statuses of
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- status for each key image -
- - - -
-
- Type -
-
- -Array.<MoneroKeyImageSpentStatus> - - -
-
- - - - - - - - - - - - - -

(async) getKnownPeers() → {Array.<MoneroDaemonPeer>}

- - - - - - -
- Get known peers including their last known online status. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- known peers -
- - - -
-
- Type -
-
- -Array.<MoneroDaemonPeer> - - -
-
- - - - - - - - - - - - - -

(async) getLastBlockHeader() → {MoneroBlockHeader}

- - - - - - -
- Get the last block's header. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- last block's header -
- - - -
-
- Type -
-
- -MoneroBlockHeader - - -
-
- - - - - - - - - - - - - -

(async) getMinerTxSum(height, numBlocks) → {MoneroMinerTxSum}

- - - - - - -
- Gets the total emissions and fees from the genesis block to the current height. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
height - - -int - - - - height to start computing the miner sum
numBlocks - - -int - - - - number of blocks to include in the sum
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- encapsulates the total emissions and fees since the genesis block -
- - - -
-
- Type -
-
- -MoneroMinerTxSum - - -
-
- - - - - - - - - - - - - -

(async) getMiningStatus() → {MoneroMiningStatus}

- - - - - - -
- Get the daemon's mining status. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- daemon's mining status -
- - - -
-
- Type -
-
- -MoneroMiningStatus - - -
-
- - - - - - - - - - - - - -

(async) getNextBlockHeader() → {MoneroBlockHeader}

- - - - - - -
- Get the header of the next block added to the chain. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- header of the next block added to the chain -
- - - -
-
- Type -
-
- -MoneroBlockHeader - - -
-
- - - - - - - - - - - - - -

(async) getOutputDistribution(amounts, cumulative, startHeight, endHeight) → {Array.<MoneroOutputDistributionEntry>}

- - - - - - -
- Creates an output distribution. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
amounts - - -Array.<BigInteger> - - - - amounts of outputs to make the distribution with
cumulative - - -boolean - - - - specifies if the results should be cumulative (defaults to TODO)
startHeight - - -int - - - - start height lower bound inclusive (optional)
endHeight - - -int - - - - end height upper bound inclusive (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are entries meeting the parameters -
- - - -
-
- Type -
-
- -Array.<MoneroOutputDistributionEntry> - - -
-
- - - - - - - - - - - - - -

(async) getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) → {Array.<MoneroOutputHistogramEntry>}

- - - - - - -
- Get a histogram of output amounts. For all amounts (possibly filtered by -parameters), gives the number of outputs on the chain for that amount. -RingCT outputs counts as 0 amount. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
amounts - - -Array.<BigInteger> - - - - amounts of outputs to make the histogram with
minCount - - -int - - - - TODO
maxCount - - -int - - - - TODO
isUnlocked - - -boolean - - - - makes a histogram with outputs with the specified lock state
recentCutoff - - -int - - - - TODO
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are entries meeting the parameters -
- - - -
-
- Type -
-
- -Array.<MoneroOutputHistogramEntry> - - -
-
- - - - - - - - - - - - - -

(async) getPeerBans() → {Array.<MoneroBan>}

- - - - - - -
- Get peer bans. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- entries about banned peers -
- - - -
-
- Type -
-
- -Array.<MoneroBan> - - -
-
- - - - - - - - - - - - - -

(async) getRpcConnection() → {MoneroRpcConnection}

- - - - - - -
- Get the daemon's RPC connection. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the daemon's rpc connection -
- - - -
-
- Type -
-
- -MoneroRpcConnection - - -
-
- - - - - - - - - - - - - -

(async) getSyncInfo() → {MoneroDaemonSyncInfo}

- - - - - - -
- Get synchronization information. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- contains sync information -
- - - -
-
- Type -
-
- -MoneroDaemonSyncInfo - - -
-
- - - - - - - - - - - - - -

(async) getTx(txHash, prune) → {MoneroTx}

- - - - - - -
- Get a transaction by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
txHash - - -string - - - - - - hash of the transaction to get
prune - - -boolean - - - - - - false - - specifies if the returned tx should be pruned (defaults to false)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- transaction with the given hash -
- - - -
-
- Type -
-
- -MoneroTx - - -
-
- - - - - - - - - - - - - -

(async) getTxHex(txHash, prune) → {string}

- - - - - - -
- Get a transaction hex by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
txHash - - -string - - - - - - hash of the transaction to get hex from
prune - - -boolean - - - - - - false - - specifies if the returned tx hex should be pruned (defaults to false)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- tx hex with the given hash -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getTxHexes(txHashes, prune) → {Array.<string>}

- - - - - - -
- Get transaction hexes by hashes. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
txHashes - - -Array.<string> - - - - - - hashes of transactions to get hexes from
prune - - -boolean - - - - - - false - - specifies if the returned tx hexes should be pruned (defaults to false)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- tx hexes -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) getTxPool() → {Array.<MoneroTx>}

- - - - - - -
- Get valid transactions seen by the node but not yet mined into a block, as well -as spent key image information for the tx pool. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are transactions in the transaction pool -
- - - -
-
- Type -
-
- -Array.<MoneroTx> - - -
-
- - - - - - - - - - - - - -

(async) getTxPoolBacklog() → {Array.<MoneroTxBacklogEntry>}

- - - - - - -
- Get all transaction pool backlog. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- backlog entries -
- - - -
-
- Type -
-
- -Array.<MoneroTxBacklogEntry> - - -
-
- - - - - - - - - - - - - -

(async) getTxPoolHashes() → {Array.<string>}

- - - - - - -
- Get hashes of transactions in the transaction pool. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are hashes of transactions in the transaction pool -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) getTxPoolStats() → {MoneroTxPoolStats}

- - - - - - -
- Get transaction pool statistics. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- contains statistics about the transaction pool -
- - - -
-
- Type -
-
- -MoneroTxPoolStats - - -
-
- - - - - - - - - - - - - -

(async) getTxs(txHashes, prune) → {Array.<MoneroTx>}

- - - - - - -
- Get transactions by hashes. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDefaultDescription
txHashes - - -Array.<string> - - - - - - hashes of transactions to get
prune - - -boolean - - - - - - false - - specifies if the returned txs should be pruned (defaults to false)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- transactions with the given hashes -
- - - -
-
- Type -
-
- -Array.<MoneroTx> - - -
-
- - - - - - - - - - - - - -

(async) getUploadLimit() → {int}

- - - - - - -
- Get the upload bandwidth limit. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- upload bandwidth limit -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) getVersion() → {MoneroVersion}

- - - - - - -
- Gets the version of the daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the version of the daemon -
- - - -
-
- Type -
-
- -MoneroVersion - - -
-
- - - - - - - - - - - - - -

(async) isConnected() → {boolean}

- - - - - - -
- Indicates if the client is connected to the daemon via RPC. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the client is connected to the daemon, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isTrusted() → {boolean}

- - - - - - -
- Indicates if the daemon is trusted xor untrusted. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the daemon is trusted, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) relayTxsByHash(txHashes)

- - - - - - -
- Relays transactions by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHashes - - -Array.<string> - - - - hashes of the transactinos to relay
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) removeBlockListener(listener)

- - - - - - -
- Unregister a listener to be notified when blocks are added to the chain. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
listener - - -function - - - - previously registered listener to be unregistered
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) resetDownloadLimit() → {int}

- - - - - - -
- Reset the download bandwidth limit. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- download bandwidth limit after resetting -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) resetUploadLimit() → {int}

- - - - - - -
- Reset the upload bandwidth limit. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- upload bandwidth limit after resetting -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) setDownloadLimit(limit) → {int}

- - - - - - -
- Set the download bandwidth limit. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
limit - - -int - - - - download limit to set (-1 to reset to default)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- new download limit after setting -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) setIncomingPeerLimit(limit)

- - - - - - -
- Limit number of incoming peers. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
limit - - -int - - - - maximum number of incoming peers
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setOutgoingPeerLimit(limit)

- - - - - - -
- Limit number of outgoing peers. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
limit - - -int - - - - maximum number of outgoing peers
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setPeerBan(ban)

- - - - - - -
- Ban a peer node. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
ban - - -MoneroBan - - - - contains information about a node to ban
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setPeerBans(bans)

- - - - - - -
- Ban peers nodes. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
bans - - -Array.<MoneroBan> - - - - specify which peers to ban
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setUploadLimit(limit) → {int}

- - - - - - -
- Set the upload bandwidth limit. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
limit - - upload limit to set (-1 to reset to default)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- new upload limit after setting -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) startMining(address, numThreads, isBackground, ignoreBattery)

- - - - - - -
- Start mining. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - address given miner rewards if the daemon mines a block
numThreads - - -integer - - - - number of mining threads to run
isBackground - - -boolean - - - - specifies if the miner should run in the background or not
ignoreBattery - - -boolean - - - - specifies if the battery state (e.g. on laptop) should be ignored or not
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) stop()

- - - - - - -
- Safely disconnect and shut down the daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) stopMining()

- - - - - - -
- Stop mining. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) submitBlock(blockBlob)

- - - - - - -
- Submit a mined block to the network. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blockBlob - - -string - - - - mined block to submit
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) submitBlocks(blockBlobs)

- - - - - - -
- Submit mined blocks to the network. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
blockBlobs - - -Array.<string> - - - - mined blocks to submit
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) submitTxHex(txHex, doNotRelay) → {MoneroSubmitTxResult}

- - - - - - -
- Submits a transaction to the daemon's pool. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHex - - -string - - - - raw transaction hex to submit
doNotRelay - - -boolean - - - - specifies if the tx should be relayed (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- contains submission results -
- - - -
-
- Type -
-
- -MoneroSubmitTxResult - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroDaemonSyncInfo.html b/docs/MoneroDaemonSyncInfo.html deleted file mode 100644 index 8c1f19012..000000000 --- a/docs/MoneroDaemonSyncInfo.html +++ /dev/null @@ -1,1602 +0,0 @@ - - - - - JSDoc: Class: MoneroDaemonSyncInfo - - - - - - - - - - -
- -

Class: MoneroDaemonSyncInfo

- - - - - - -
- -
- -

MoneroDaemonSyncInfo()

- -
Models daemon synchronization information.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroDaemonSyncInfo()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getConnections()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getCredits()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNextNeededPruningSeed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOverview()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSpans()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTargetHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTopBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setConnections()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCredits()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNextNeededPruningSeed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOverview()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSpans()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTargetHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTopBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroDaemonUpdateCheckResult.html b/docs/MoneroDaemonUpdateCheckResult.html deleted file mode 100644 index f577e379a..000000000 --- a/docs/MoneroDaemonUpdateCheckResult.html +++ /dev/null @@ -1,1197 +0,0 @@ - - - - - JSDoc: Class: MoneroDaemonUpdateCheckResult - - - - - - - - - - -
- -

Class: MoneroDaemonUpdateCheckResult

- - - - - - -
- -
- -

MoneroDaemonUpdateCheckResult(is)

- -
Models the result of checking for a daemon update.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroDaemonUpdateCheckResult(is)

- - - - - - -
- Deep copy constructor. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
is - - -MoneroDaemonUpdateCheckResult - - - - an existing result to deep copy from
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getAutoUri() → {string}

- - - - - - -
- Get the uri to automatically download the update. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is the uri to automatically download the update -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getHash() → {string}

- - - - - - -
- Get the update's hash. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is the update's hash -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getUserUri() → {string}

- - - - - - -
- Get the uri to manually download the update. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is the uri to manually download the update -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getVersion() → {string}

- - - - - - -
- Get the update's version. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is the update's version -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

isUpdateAvailable() → {boolean}

- - - - - - -
- Indicates if an update is available. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if an update is available, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

setAutoUri()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsUpdateAvailable()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setUserUri()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroDaemonUpdateDownloadResult.html b/docs/MoneroDaemonUpdateDownloadResult.html deleted file mode 100644 index 0ff98a697..000000000 --- a/docs/MoneroDaemonUpdateDownloadResult.html +++ /dev/null @@ -1,421 +0,0 @@ - - - - - JSDoc: Class: MoneroDaemonUpdateDownloadResult - - - - - - - - - - -
- -

Class: MoneroDaemonUpdateDownloadResult

- - - - - - -
- -
- -

MoneroDaemonUpdateDownloadResult(is)

- -
Models the result of downloading an update.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroDaemonUpdateDownloadResult(is)

- - - - - - -
- Construct a download result. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
is - - -MoneroDaemonUpdateCheckResult - - - - an existing result to copy from
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getDownloadPath() → {string}

- - - - - - -
- Get the path the update was downloaded to. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is the path the update was downloaded to -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

setDownloadPath()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroDestination.html b/docs/MoneroDestination.html deleted file mode 100644 index 5b36985b8..000000000 --- a/docs/MoneroDestination.html +++ /dev/null @@ -1,847 +0,0 @@ - - - - - JSDoc: Class: MoneroDestination - - - - - - - - - - -
- -

Class: MoneroDestination

- - - - - - -
- -
- -

MoneroDestination(stateOrAddress, amount)

- -
Models an outgoing transfer destination.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroDestination(stateOrAddress, amount)

- - - - - - -
- Construct the model. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
stateOrAddress - - -MoneroDestination -| - -object -| - -string - - - - is a MoneroDestination, JS object, or hex string to initialize from (optional)
amount - - -BigInteger -| - -string - - - - the destination amount
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroError.html b/docs/MoneroError.html deleted file mode 100644 index 2965d641c..000000000 --- a/docs/MoneroError.html +++ /dev/null @@ -1,418 +0,0 @@ - - - - - JSDoc: Class: MoneroError - - - - - - - - - - -
- -

Class: MoneroError

- - - - - - -
- -
- -

MoneroError(message, code)

- -
Exception when interacting with a Monero wallet or daemon.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroError(message, code)

- - - - - - -
- Constructs the error. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
message - - -string - - - - is a human-readable message of the error
code - - -int - - - - is the error code (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getCode()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroHardForkInfo.html b/docs/MoneroHardForkInfo.html deleted file mode 100644 index d61dd9113..000000000 --- a/docs/MoneroHardForkInfo.html +++ /dev/null @@ -1,1938 +0,0 @@ - - - - - JSDoc: Class: MoneroHardForkInfo - - - - - - - - - - -
- -

Class: MoneroHardForkInfo

- - - - - - -
- -
- -

MoneroHardForkInfo()

- -
Monero hard fork info.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroHardForkInfo()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getCredits()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getEarliestHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumVotes()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getState()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getThreshold()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTopBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getVoting()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getWindow()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isEnabled()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCredits()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setEarliestHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsEnabled()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumVotes()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setState()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setThreshold()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTopBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setVoting()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setWindow()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroIncomingTransfer.html b/docs/MoneroIncomingTransfer.html deleted file mode 100644 index 73e9c8886..000000000 --- a/docs/MoneroIncomingTransfer.html +++ /dev/null @@ -1,1988 +0,0 @@ - - - - - JSDoc: Class: MoneroIncomingTransfer - - - - - - - - - - -
- -

Class: MoneroIncomingTransfer

- - - - - - -
- -
- -

MoneroIncomingTransfer(state)

- -
Models an incoming transfer of funds to the wallet.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroIncomingTransfer(state)

- - - - - - -
- Construct the model. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
state - - -MoneroTransfer -| - -object - - - - is existing state to initialize from (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - - - - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumSuggestedConfirmations() → {number}

- - - - - - -
- Return how many confirmations till it's not economically worth re-writing the chain. -That is, the number of confirmations before the transaction is highly unlikely to be -double spent or overwritten and may be considered settled, e.g. for a merchant to trust -as finalized. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is the number of confirmations before it's not worth rewriting the chain -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

getSubaddressIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isIncoming()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isOutgoing()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge(transfer)

- - - - - - -
- Updates this transaction by merging the latest information from the given -transaction. - -Merging can modify or build references to the transfer given so it -should not be re-used or it should be copied before calling this method. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
transfer - - -MoneroIncomingTransfer - - - - is the transfer to merge into this one
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumSuggestedConfirmations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSubaddressIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroIntegratedAddress.html b/docs/MoneroIntegratedAddress.html deleted file mode 100644 index 2f91d4f7e..000000000 --- a/docs/MoneroIntegratedAddress.html +++ /dev/null @@ -1,846 +0,0 @@ - - - - - JSDoc: Class: MoneroIntegratedAddress - - - - - - - - - - -
- -

Class: MoneroIntegratedAddress

- - - - - - -
- -
- -

MoneroIntegratedAddress()

- -
Monero integrated address model.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroIntegratedAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getIntegratedAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getStandardAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIntegratedAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setStandardAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroKeyImage.html b/docs/MoneroKeyImage.html deleted file mode 100644 index c2e8fffcc..000000000 --- a/docs/MoneroKeyImage.html +++ /dev/null @@ -1,928 +0,0 @@ - - - - - JSDoc: Class: MoneroKeyImage - - - - - - - - - - -
- -

Class: MoneroKeyImage

- - - - - - -
- -
- -

MoneroKeyImage(stateOrHex, signature)

- -
Models a Monero key image.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroKeyImage(stateOrHex, signature)

- - - - - - -
- Construct the model. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
stateOrHex - - -MoneroKeyImage -| - -object -| - -string - - - - is a MoneroKeyImage, JS object, or hex string to initialize from (optional)
signature - - -string - - - - is the key image's signature
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSignature()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSignature()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroKeyImageImportResult.html b/docs/MoneroKeyImageImportResult.html deleted file mode 100644 index 3c16a4aa6..000000000 --- a/docs/MoneroKeyImageImportResult.html +++ /dev/null @@ -1,762 +0,0 @@ - - - - - JSDoc: Class: MoneroKeyImageImportResult - - - - - - - - - - -
- -

Class: MoneroKeyImageImportResult

- - - - - - -
- -
- -

MoneroKeyImageImportResult()

- -
Models results from importing key images.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroKeyImageImportResult()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSpentAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getUnspentAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSpentAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setUnspentAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroKeyImageSpentStatus.html b/docs/MoneroKeyImageSpentStatus.html deleted file mode 100644 index 0177679aa..000000000 --- a/docs/MoneroKeyImageSpentStatus.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - - JSDoc: Class: MoneroKeyImageSpentStatus - - - - - - - - - - -
- -

Class: MoneroKeyImageSpentStatus

- - - - - - -
- -
- -

MoneroKeyImageSpentStatus

- -
Enumerate key image spent statuses.
- - -
- -
-
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -

Members

- - - -

(static) CONFIRMED

- - - - -
- Key image is confirmed (value=1). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(static) NOT_SPENT

- - - - -
- Key image is not spent (value=0). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(static) TX_POOL

- - - - -
- Key image is in the pool (value=2). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroMinerTxSum.html b/docs/MoneroMinerTxSum.html deleted file mode 100644 index 256acea01..000000000 --- a/docs/MoneroMinerTxSum.html +++ /dev/null @@ -1,594 +0,0 @@ - - - - - JSDoc: Class: MoneroMinerTxSum - - - - - - - - - - -
- -

Class: MoneroMinerTxSum

- - - - - - -
- -
- -

MoneroMinerTxSum()

- -
Model for the summation of miner emissions and fees.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroMinerTxSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getEmissionSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getFeeSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setEmissionSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setFeeSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroMiningStatus.html b/docs/MoneroMiningStatus.html deleted file mode 100644 index 4c49b4a01..000000000 --- a/docs/MoneroMiningStatus.html +++ /dev/null @@ -1,1098 +0,0 @@ - - - - - JSDoc: Class: MoneroMiningStatus - - - - - - - - - - -
- -

Class: MoneroMiningStatus

- - - - - - -
- -
- -

MoneroMiningStatus()

- -
Models daemon mining status.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroMiningStatus()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumThreads()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSpeed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isActive()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isBackground()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsActive()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsBackground()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumThreads()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSpeed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroMultisigInfo.html b/docs/MoneroMultisigInfo.html deleted file mode 100644 index 2ed4ae267..000000000 --- a/docs/MoneroMultisigInfo.html +++ /dev/null @@ -1,930 +0,0 @@ - - - - - JSDoc: Class: MoneroMultisigInfo - - - - - - - - - - -
- -

Class: MoneroMultisigInfo

- - - - - - -
- -
- -

MoneroMultisigInfo()

- -
Models information about a multisig wallet.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroMultisigInfo()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getNumParticipants()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getThreshold()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isMultisig()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isReady()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsMultisig()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsReady()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumParticipants()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setThreshold()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroMultisigInitResult.html b/docs/MoneroMultisigInitResult.html deleted file mode 100644 index 569fe188f..000000000 --- a/docs/MoneroMultisigInitResult.html +++ /dev/null @@ -1,596 +0,0 @@ - - - - - JSDoc: Class: MoneroMultisigInitResult - - - - - - - - - - -
- -

Class: MoneroMultisigInitResult

- - - - - - -
- -
- -

MoneroMultisigInitResult()

- -
Models the result of initializing a multisig wallet which results in the -multisig wallet's address xor another multisig hex to share with -participants to create the wallet.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroMultisigInitResult()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMultisigHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMultisigHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroMultisigSignResult.html b/docs/MoneroMultisigSignResult.html deleted file mode 100644 index 2323bc4d7..000000000 --- a/docs/MoneroMultisigSignResult.html +++ /dev/null @@ -1,594 +0,0 @@ - - - - - JSDoc: Class: MoneroMultisigSignResult - - - - - - - - - - -
- -

Class: MoneroMultisigSignResult

- - - - - - -
- -
- -

MoneroMultisigSignResult()

- -
Models the result of signing multisig tx hex.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroMultisigSignResult()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getSignedMultisigTxHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTxHashes()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSignedMultisigTxHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTxHashes()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroNetworkType.html b/docs/MoneroNetworkType.html deleted file mode 100644 index 13e1a3253..000000000 --- a/docs/MoneroNetworkType.html +++ /dev/null @@ -1,809 +0,0 @@ - - - - - JSDoc: Class: MoneroNetworkType - - - - - - - - - - -
- -

Class: MoneroNetworkType

- - - - - - -
- -
- -

MoneroNetworkType

- -
Defines the Monero network types (mainnet, testnet, and stagenet).
- - -
- -
-
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -

Members

- - - -

(static) MAINNET

- - - - -
- Mainnet (value=0). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(static) STAGENET

- - - - -
- Stagnet (value=2). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(static) TESTNET

- - - - -
- Testnet (value=1). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - -

Methods

- - - - - - - -

(static) isValid(networkType) → {boolean}

- - - - - - -
- Indicates if the given network type is valid or not. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
networkType - - -int - - - - the network type to validate as a numeric
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the network type is valid, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(static) parse(networkTypeStr) → {int}

- - - - - - -
- Parse the given string as a network type. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
networkTypeStr - - -string - - - - "mainnet", "testnet", or "stagenet" (case insensitive)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the network type as a numeric -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(static) validate(networkType)

- - - - - - -
- Asserts that the given network type is valid. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
networkType - - -int - - - - the network type to validate as a numeric
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroOutgoingTransfer.html b/docs/MoneroOutgoingTransfer.html deleted file mode 100644 index 4de56e16d..000000000 --- a/docs/MoneroOutgoingTransfer.html +++ /dev/null @@ -1,1865 +0,0 @@ - - - - - JSDoc: Class: MoneroOutgoingTransfer - - - - - - - - - - -
- -

Class: MoneroOutgoingTransfer

- - - - - - -
- -
- -

MoneroOutgoingTransfer(state)

- -
Models an outgoing transfer of funds from the wallet.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroOutgoingTransfer(state)

- - - - - - -
- Construct the model. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
state - - -MoneroOutgoingTranser -| - -object - - - - is existing state to initialize from (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - - - - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAddresses()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDestinations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSubaddressIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isIncoming()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isOutgoing()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge(transfer)

- - - - - - -
- Updates this transaction by merging the latest information from the given -transaction. - -Merging can modify or build references to the transfer given so it -should not be re-used or it should be copied before calling this method. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
transfer - - is the transfer to merge into this one
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAddresses()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDestinations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSubaddressIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroOutput.html b/docs/MoneroOutput.html deleted file mode 100644 index b84955ef3..000000000 --- a/docs/MoneroOutput.html +++ /dev/null @@ -1,1574 +0,0 @@ - - - - - JSDoc: Class: MoneroOutput - - - - - - - - - - -
- -

Class: MoneroOutput

- - - - - - -
- -
- -

MoneroOutput(state)

- -
Models a Monero transaction output.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroOutput(state)

- - - - - - -
- Construct the model. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
state - - -MoneroOutput -| - -object - - - - is existing state to initialize from (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getKeyImage()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRingOutputIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getStealthPublicKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setKeyImage()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRingOutputIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setStealthPublicKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroOutputHistogramEntry.html b/docs/MoneroOutputHistogramEntry.html deleted file mode 100644 index 2dba6cfd6..000000000 --- a/docs/MoneroOutputHistogramEntry.html +++ /dev/null @@ -1,930 +0,0 @@ - - - - - JSDoc: Class: MoneroOutputHistogramEntry - - - - - - - - - - -
- -

Class: MoneroOutputHistogramEntry

- - - - - - -
- -
- -

MoneroOutputHistogramEntry()

- -
Entry in a Monero output histogram (see get_output_histogram of Daemon RPC documentation).
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroOutputHistogramEntry()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumInstances()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumRecentInstances()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumUnlockedInstances()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumInstances()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumRecentInstances()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumUnlockedInstances()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroOutputQuery.html b/docs/MoneroOutputQuery.html deleted file mode 100644 index 676af3e60..000000000 --- a/docs/MoneroOutputQuery.html +++ /dev/null @@ -1,3802 +0,0 @@ - - - - - JSDoc: Class: MoneroOutputQuery - - - - - - - - - - -
- -

Class: MoneroOutputQuery

- - - - - - -
- -
- -

MoneroOutputQuery(config)

- -
Configuration to query wallet outputs.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroOutputQuery(config)

- - - - - - -
-

Construct the output query.

- -

Example:

- - -// get available outputs in account 0 with a minimum amount
-let outputs = await wallet.getOutputs({
-   isSpent: false,
-   isLocked: false,
-   accountIndex: 0,
-   minAmount: new BigInteger("750000")
-}); -
- -

All configuration is optional. All outputs are returned except those that don't meet criteria defined in this query.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -object - - - - output query configuration (optional) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIndex - - -int - - - - get outputs in this account index
subaddressIndex - - -int - - - - get outputs in this subaddress index
subaddressIndices - - -Array.<int> - - - - get outputs in these subaddress indices
amount - - -BigInteger - - - - get outputs with this amount
minAmount - - -BigInteger - - - - get outputs with amount greater than or equal to this amount
maxAmount - - -BigInteger - - - - get outputs with amount less than or equal to this amount
isLocked - - -boolean - - - - get locked xor unlocked outputs
isSpent - - -boolean - - - - get spent xor unspent outputs
keyImage - - -object -| - -MoneroKeyImage - - - - get outputs with a key image matching fields defined in this key image -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
hex - - -string - - - - get outputs with this key image hex
signature - - -string - - - - get outputs with this key image signature
- -
txQuery - - -object -| - -MoneroTxQuery - - - - get outputs whose tx match this tx query
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - - - - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getKeyImage()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMaxAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMinAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRingOutputIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getStealthPublicKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSubaddressIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSubaddressIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTxQuery()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isFrozen()

- - - - - - -
- Indicates if this output has been deemed 'malicious' and will therefore -not be spent by the wallet. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Boolean is whether or not this output is frozen -
- - - - - - - - - - - - - - - -

isLocked()

- - - - - - -
- Indicates if the this query will fetch locked outputs, unlocked outputs, or both (null). -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if locked outputs queried, false of unlocked outputs queried, undefined if both -
- - - - - - - - - - - - - - - -

isSpent()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

meetsCriteria()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge(output)

- - - - - - -
- Updates this output by merging the latest information from the given -output. - -Merging can modify or build references to the output given so it -should not be re-used or it should be copied before calling this method. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
output - - is the output to merge into this one
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsFrozen()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsLocked(isLocked) → {MoneroOutputQuery}

- - - - - - -
- Convenience method to query outputs by the locked state of their tx. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
isLocked - - specifies if the output's tx must be locked or unlocked (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- this query for chaining -
- - - -
-
- Type -
-
- -MoneroOutputQuery - - -
-
- - - - - - - - - - - - - -

setIsSpent()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setKeyImage()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMaxAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMinAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRingOutputIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setStealthPublicKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSubaddressIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSubaddressIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTxQuery()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroOutputWallet.html b/docs/MoneroOutputWallet.html deleted file mode 100644 index 0a29c24b3..000000000 --- a/docs/MoneroOutputWallet.html +++ /dev/null @@ -1,2488 +0,0 @@ - - - - - JSDoc: Class: MoneroOutputWallet - - - - - - - - - - -
- -

Class: MoneroOutputWallet

- - - - - - -
- -
- -

MoneroOutputWallet(state)

- -
Models a Monero output with wallet extensions.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroOutputWallet(state)

- - - - - - -
- Construct the model. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
state - - -MoneroOutputWallet -| - -object - - - - is existing state to initialize from (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - - - - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getKeyImage()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRingOutputIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getStealthPublicKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSubaddressIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isFrozen()

- - - - - - -
- Indicates if this output has been deemed 'malicious' and will therefore -not be spent by the wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Boolean is whether or not this output is frozen -
- - - - - - - - - - - - - - - -

isLocked()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isSpent()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge(output)

- - - - - - -
- Updates this output by merging the latest information from the given -output. - -Merging can modify or build references to the output given so it -should not be re-used or it should be copied before calling this method. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
output - - is the output to merge into this one
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsFrozen()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsSpent()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setKeyImage()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRingOutputIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setStealthPublicKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSubaddressIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroRpcConnection.html b/docs/MoneroRpcConnection.html deleted file mode 100644 index 975143e2c..000000000 --- a/docs/MoneroRpcConnection.html +++ /dev/null @@ -1,1323 +0,0 @@ - - - - - JSDoc: Class: MoneroRpcConnection - - - - - - - - - - -
- -

Class: MoneroRpcConnection

- - - - - - -
- -
- -

MoneroRpcConnection(uriOrConfigOrConnection, username, password, rejectUnauthorized)

- -
Maintains a connection and sends requests to a Monero RPC API.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroRpcConnection(uriOrConfigOrConnection, username, password, rejectUnauthorized)

- - - - - - -
-

Construct a RPC connection.

- -

Examples:

- - -let connection1 = new MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123")

- -let connection2 = new MoneroRpcConnection({
-   uri: http://localhost:38081,
-   username: "daemon_user",
-   password: "daemon_password_123",
-   rejectUnauthorized: false // accept self-signed certificates e.g. for local development
-}); -
-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uriOrConfigOrConnection - - -string -| - -object -| - -MoneroRpcConnection - - - - RPC endpoint URI, MoneroRpcConnection, or equivalent JS object -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uri - - -string - - - - URI of the RPC endpoint
username - - -string - - - - username to authenticate with the RPC endpoint (optional)
password - - -string - - - - password to authenticate with the RPC endpoint (optional)
rejectUnauthorized - - -boolean - - - - rejects self-signed certificates if true (default true)
- -
username - - -string - - - - username to authenticate with the RPC endpoint (optional)
password - - -string - - - - password to authenticate with the RPC endpoint (optional)
rejectUnauthorized - - -boolean - - - - reject self-signed certificates if true (default true)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -

Members

- - - -

(static) DEFAULT_CONFIG

- - - - -
- Default RPC configuration. -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - -

Methods

- - - - - - - -

getConfig()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPassword()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRejectUnauthorized()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getUri()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getUsername()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) sendBinaryRequest(path)

- - - - - - -
- Sends a binary RPC request. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
path - - is the path of the binary RPC method to invoke
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- a Uint8Array with the binary response -
- - - - - - - - - - - - - - - -

(async) sendJsonRequest(method, params) → {object}

- - - - - - -
- Sends a JSON RPC request. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
method - - is the JSON RPC method to invoke
params - - are request parameters
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is the response map -
- - - -
-
- Type -
-
- -object - - -
-
- - - - - - - - - - - - - -

(async) sendPathRequest()

- - - - - - -
- Sends a RPC request to the given path and with the given paramters. - -E.g. "/get_transactions" with params -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroRpcError.html b/docs/MoneroRpcError.html deleted file mode 100644 index b38d19325..000000000 --- a/docs/MoneroRpcError.html +++ /dev/null @@ -1,548 +0,0 @@ - - - - - JSDoc: Class: MoneroRpcError - - - - - - - - - - -
- -

Class: MoneroRpcError

- - - - - - -
- -
- -

MoneroRpcError(rpcDescription, rpcCode, rpcMethod, rpcParams)

- -
Error when interacting with Monero RPC.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroRpcError(rpcDescription, rpcCode, rpcMethod, rpcParams)

- - - - - - -
- Constructs the error. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
rpcDescription - - -string - - - - is a description of the error from rpc
rpcCode - - -int - - - - is the error code from rpc
rpcMethod - - -string - - - - is the rpc method invoked
rpcParams - - -object - - - - are parameters sent with the rpc request
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getRpcMethod()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRpcParams()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroSubaddress.html b/docs/MoneroSubaddress.html deleted file mode 100644 index 878115932..000000000 --- a/docs/MoneroSubaddress.html +++ /dev/null @@ -1,1854 +0,0 @@ - - - - - JSDoc: Class: MoneroSubaddress - - - - - - - - - - -
- -

Class: MoneroSubaddress

- - - - - - -
- -
- -

MoneroSubaddress()

- -
Monero subaddress model.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroSubaddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getBalance()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLabel()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumBlocksToUnlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumUnspentOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getUnlockedBalance()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isUsed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBalance()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsUsed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLabel()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumBlocksToUnlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumUnspentOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setUnlockedBalance()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroSubmitTxResult.html b/docs/MoneroSubmitTxResult.html deleted file mode 100644 index 7d914a8e6..000000000 --- a/docs/MoneroSubmitTxResult.html +++ /dev/null @@ -1,2610 +0,0 @@ - - - - - JSDoc: Class: MoneroSubmitTxResult - - - - - - - - - - -
- -

Class: MoneroSubmitTxResult

- - - - - - -
- -
- -

MoneroSubmitTxResult()

- -
Models the result from submitting a tx to a daemon.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroSubmitTxResult()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getCredits()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getReason()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSanityCheckFailed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTopBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

hasInvalidInput()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

hasInvalidOutput()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

hasTooFewOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isDoubleSpendSeen()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isFeeTooLow()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isGood()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isMixinTooLow()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isOverspend()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isRelayed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isTooBig()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCredits()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHasInvalidInput()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHasInvalidOutput()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHasTooFewOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsDoubleSpend()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsFeeTooLow()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsGood()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsMixinTooLow()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsOverspend()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsRelayed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsTooBig()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setReason()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSanityCheckFailed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTopBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroSyncResult.html b/docs/MoneroSyncResult.html deleted file mode 100644 index 9a911b962..000000000 --- a/docs/MoneroSyncResult.html +++ /dev/null @@ -1,510 +0,0 @@ - - - - - JSDoc: Class: MoneroSyncResult - - - - - - - - - - -
- -

Class: MoneroSyncResult

- - - - - - -
- -
- -

MoneroSyncResult()

- -
Result from syncing a Monero wallet.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroSyncResult()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getNumBlocksFetched()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getReceivedMoney()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumBlocksFetched()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setReceivedMoney()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroTransfer.html b/docs/MoneroTransfer.html deleted file mode 100644 index a26e5a5bb..000000000 --- a/docs/MoneroTransfer.html +++ /dev/null @@ -1,1312 +0,0 @@ - - - - - JSDoc: Class: MoneroTransfer - - - - - - - - - - -
- -

Class: MoneroTransfer

- - - - - - -
- -
- -

MoneroTransfer(state)

- -
Models a base transfer of funds to or from the wallet.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroTransfer(state)

- - - - - - -
- Construct the model. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
state - - -MoneroTransfer -| - -object - - - - is existing state to initialize from (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isIncoming()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isOutgoing()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge(transfer) → {MoneroTransfer}

- - - - - - -
- Updates this transaction by merging the latest information from the given -transaction. - -Merging can modify or build references to the transfer given so it -should not be re-used or it should be copied before calling this method. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
transfer - - is the transfer to merge into this one
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the merged transfer -
- - - -
-
- Type -
-
- -MoneroTransfer - - -
-
- - - - - - - - - - - - - -

setAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroTransferQuery.html b/docs/MoneroTransferQuery.html deleted file mode 100644 index 2a09bde3f..000000000 --- a/docs/MoneroTransferQuery.html +++ /dev/null @@ -1,3233 +0,0 @@ - - - - - JSDoc: Class: MoneroTransferQuery - - - - - - - - - - -
- -

Class: MoneroTransferQuery

- - - - - - -
- -
- -

MoneroTransferQuery(config)

- -
Configuration to query wallet transfers.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroTransferQuery(config)

- - - - - - -
-

Construct the transfer query.

- -

Example:

- - -// get incoming transfers to account 0, subaddress 1
-let transfers = await wallet.getTransfers({
-   accountIndex: 0,
-   subaddressIndex: 0
-}); -
- -

All configuration is optional. All transfers are returned except those that don't meet criteria defined in this query.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -object - - - - transfer query configuration (optional) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
amount - - -BigInteger - - - - get transfers with this amount
accountIndex - - -int - - - - get transfers to/from this account index
subaddressIndex - - -int - - - - get transfers to/from this subaddress index
subaddressIndices - - -Array.<int> - - - - get transfers to/from these subaddress indices
address - - -string - - - - get transfers to/from this wallet address
addresses - - -Array.<string> - - - - get transfers to/from these wallet addresses
isIncoming - - -boolean - - - - get transfers which are incoming if true
isOutgoing - - -boolean - - - - get transfers which are outgoing if true
hasDestinations - - -boolean - - - - get transfers with known destinations if true (destinations are only stored locally with the wallet)
txQuery - - -object -| - -MoneroTxQuery - - - - get transfers whose tx match this tx query
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - - - - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAddresses()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDestinations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSubaddressIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSubaddressIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTxQuery()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

hasDestinations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isIncoming()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isOutgoing()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

meetsCriteria()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge(transfer) → {MoneroTransfer}

- - - - - - -
- Updates this transaction by merging the latest information from the given -transaction. - -Merging can modify or build references to the transfer given so it -should not be re-used or it should be copied before calling this method. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
transfer - - is the transfer to merge into this one
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the merged transfer -
- - - -
-
- Type -
-
- -MoneroTransfer - - -
-
- - - - - - - - - - - - - -

setAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAddresses()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDestinations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHasDestinations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsIncoming()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsLocked(isLocked) → {MoneroOutputQuery}

- - - - - - -
- Convenience method to query outputs by the locked state of their tx. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
isLocked - - specifies if the output's tx must be locked or unlocked (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- this query for chaining -
- - - -
-
- Type -
-
- -MoneroOutputQuery - - -
-
- - - - - - - - - - - - - -

setIsOutgoing()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSubaddressIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSubaddressIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTxQuery()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroTx.html b/docs/MoneroTx.html deleted file mode 100644 index 4d65c8b35..000000000 --- a/docs/MoneroTx.html +++ /dev/null @@ -1,7016 +0,0 @@ - - - - - JSDoc: Class: MoneroTx - - - - - - - - - - -
- -

Class: MoneroTx

- - - - - - -
- -
- -

MoneroTx(state)

- -
Represents a transaction on the Monero network.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroTx(state)

- - - - - - -
- Construct the model. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
state - - -MoneroTx -| - -object - - - - is existing state to initialize from (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getBlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getExtra()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getFee()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getFullHex() → {string}

- - - - - - -
- Get full transaction hex. Full hex = pruned hex + prunable hex. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is full transaction hex -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getInputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLastFailedHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLastFailedHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLastRelayedTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMaxUsedBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMaxUsedBlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMetadata()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumConfirmations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutputIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrunableHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrunableHex() → {string}

- - - - - - -
- Get prunable transaction hex which is hex that is removed from a pruned -transaction. Full hex = pruned hex + prunable hex. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is the prunable transaction hex -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getPrunedHex() → {string}

- - - - - - -
- Get pruned transaction hex. Full hex = pruned hex + prunable hex. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is pruned transaction hex -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getRctSignatures()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRctSigPrunable()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getReceivedTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRelay()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRingSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSignatures()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getUnlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

inTxPool()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isConfirmed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isDoubleSpendSeen()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isFailed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isKeptByBlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isMinerTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isRelayed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge(tx) → {MoneroTx}

- - - - - - -
- Updates this transaction by merging the latest information from the given -transaction. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tx - - is the transaction to update this transaction with
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- this for method chaining -
- - - -
-
- Type -
-
- -MoneroTx - - -
-
- - - - - - - - - - - - - -

setBlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setExtra()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setFee()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setFullHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setInputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setInTxPool()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsConfirmed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsDoubleSpend()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsFailed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsKeptByBlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsMinerTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsRelayed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLastFailedHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLastFailedHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLastRelayedTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMaxUsedBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMaxUsedBlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMetadata()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumConfirmations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOutputIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrunableHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrunableHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrunedHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRctSignatures()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRctSigPrunable()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setReceivedTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRelay()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRingSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSignatures()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setUnlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroTxConfig.html b/docs/MoneroTxConfig.html deleted file mode 100644 index 0805609ef..000000000 --- a/docs/MoneroTxConfig.html +++ /dev/null @@ -1,4005 +0,0 @@ - - - - - JSDoc: Class: MoneroTxConfig - - - - - - - - - - -
- -

Class: MoneroTxConfig

- - - - - - -
- -
- -

MoneroTxConfig(config)

- -
Configures a transaction to send, sweep, or create a payment URI.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroTxConfig(config)

- - - - - - -
-

Generic request to transfer funds from a wallet.

- -

Examples:

- - -let config1 = new MoneroTxConfig({
-   accountIndex: 0,
-   address: "59aZULsUF3YN...",
-   amount: new BigInteger("500000"),
-   priority: MoneroTxPriority.NORMAL,
-   relay: true
-});

-
-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig -| - -object - - - - configures the transaction to create (optional) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address
amount - - -BigInteger - - - - single destination amount
accountIndex - - -int - - - - source account index to transfer funds from
subaddressIndex - - -int - - - - source subaddress index to transfer funds from
subaddressIndices - - -Array.<int> - - - - source subaddress indices to transfer funds from
relay - - -boolean - - - - relay the transaction to peers to commit to the blockchain
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
destinations - - -Array.<MoneroDestination> - - - - addresses and amounts in a multi-destination tx
paymentId - - -string - - - - transaction payment ID
unlockHeight - - -int - - - - minimum height for the transaction to unlock (default 0)
note - - -string - - - - transaction note saved locally with the wallet
recipientName - - -string - - - - recipient name saved locally with the wallet
canSplit - - -boolean - - - - allow funds to be transferred using multiple transactions
belowAmount - - -BigInteger - - - - for sweep requests, include outputs below this amount when sweeping wallet, account, subaddress, or all unlocked funds
sweepEachSubaddress - - -boolean - - - - for sweep requests, sweep each subaddress individually instead of together if true
keyImage - - -string - - - - key image to sweep (ignored except in sweepOutput() requests)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

addDestination()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAddress() → {string}

- - - - - - -
- Get the address of a single-destination configuration. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the address of the single destination -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getAmount() → {BigInteger}

- - - - - - -
- Get the amount of a single-destination configuration. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the amount of the single destination -
- - - -
-
- Type -
-
- -BigInteger - - -
-
- - - - - - - - - - - - - -

getBelowAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getCanSplit()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getDestinations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getFee()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getKeyImage()

- - - - - - -
- Get the key image hex of the output to sweep. - -return {string} is the key image hex of the output to sweep -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNote()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPriority()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRecipientName()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRelay()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSubaddressIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSweepEachSubaddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getUnlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAccountIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAddress(address) → {MoneroTxConfig}

- - - - - - -
- Set the address of a single-destination configuration. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - the address to set for the single destination
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- this configuration for chaining -
- - - -
-
- Type -
-
- -MoneroTxConfig - - -
-
- - - - - - - - - - - - - -

setAmount(amount) → {MoneroTxConfig}

- - - - - - -
- Set the amount of a single-destination configuration. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
amount - - -BigInteger - - - - the amount to set for the single destination
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- this configuration for chaining -
- - - -
-
- Type -
-
- -MoneroTxConfig - - -
-
- - - - - - - - - - - - - -

setBelowAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCanSplit()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDestination()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setDestinations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setFee()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setKeyImage(keyImage)

- - - - - - -
- Set the key image hex of the output to sweep. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyImage - - -string - - - - is the key image hex of the output to sweep
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNote()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPriority()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRecipientName()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRelay()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSubaddressIndex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSubaddressIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSweepEachSubaddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setUnlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroTxPoolStats.html b/docs/MoneroTxPoolStats.html deleted file mode 100644 index f487864ab..000000000 --- a/docs/MoneroTxPoolStats.html +++ /dev/null @@ -1,2442 +0,0 @@ - - - - - JSDoc: Class: MoneroTxPoolStats - - - - - - - - - - -
- -

Class: MoneroTxPoolStats

- - - - - - -
- -
- -

MoneroTxPoolStats()

- -
Models transaction pool statistics.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroTxPoolStats()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getBytesMax()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getBytesMed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getBytesMin()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getBytesTotal()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getFeeTotal()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHisto()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHisto98pc()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNum10m()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumDoubleSpends()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumFailing()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumNotRelayed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumTxs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOldestTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBytesMax()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBytesMed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBytesMin()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBytesTotal()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setFeeTotal()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHisto()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHisto98pc()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNum10m()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumDoubleSpends()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumFailing()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumNotRelayed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumTxs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOldestTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroTxPriority.html b/docs/MoneroTxPriority.html deleted file mode 100644 index 0dacdce4a..000000000 --- a/docs/MoneroTxPriority.html +++ /dev/null @@ -1,412 +0,0 @@ - - - - - JSDoc: Class: MoneroTxPriority - - - - - - - - - - -
- -

Class: MoneroTxPriority

- - - - - - -
- -
- -

MoneroTxPriority

- -
Enumerates send priorities.
- - -
- -
-
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - -

Members

- - - -

(static) DEFAULT

- - - - -
- Default priority (i.e. normal) (value=0). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(static) ELEVATED

- - - - -
- Elevated priority (value=3). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(static) NORMAL

- - - - -
- Normal priority (value=2). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - -

(static) UNIMPORTANT

- - - - -
- Unimportant priority (value=1). -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroTxQuery.html b/docs/MoneroTxQuery.html deleted file mode 100644 index 194093181..000000000 --- a/docs/MoneroTxQuery.html +++ /dev/null @@ -1,12155 +0,0 @@ - - - - - JSDoc: Class: MoneroTxQuery - - - - - - - - - - -
- -

Class: MoneroTxQuery

- - - - - - -
- -
- -

MoneroTxQuery(config)

- -

Configuration to query transactions.

- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroTxQuery(config)

- - - - - - -
-

Construct the transaction query.

- -

Example:

- - -// get transactions with unlocked incoming transfers to account 0
-let txs = await wallet.getTxs({
-   isLocked: false,
-   transferQuery: {
-     isIncoming: true,
-     accountIndex: 0
-   }
-}); -
- -

All configuration is optional. All transactions are returned except those that don't meet criteria defined in this query.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -object - - - - tx query configuration -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
hash - - -string - - - - get a tx with this hash
txHashes - - -Array.<string> - - - - get txs with these hashes
height - - -int - - - - get txs with this height
minHeight - - -int - - - - get txs with height greater than or equal to this height
maxHeight - - -int - - - - get txs with height less than or equal to this height
isConfirmed - - -boolean - - - - get confirmed or unconfirmed txs
inTxPool - - -boolean - - - - get txs in or out of the tx pool
relay - - -boolean - - - - get txs with the same relay status
isRelayed - - -boolean - - - - get relayed or non-relayed txs
isFailed - - -boolean - - - - get failed or non-failed txs
isMinerTx - - -boolean - - - - get miner or non-miner txs
isLocked - - -boolean - - - - get locked or unlocked txs
isIncoming - - -boolean - - - - get txs with or without incoming transfers
isOutgoing - - -boolean - - - - get txs with or without outgoing transfers
paymentId - - -string - - - - get txs with this payment ID
paymentIds - - -string - - - - get txs with a payment ID among these payment IDs
hasPaymentId - - -boolean - - - - get txs with or without payment IDs
transferQuery - - -object -| - -MoneroTransferQuery - - - - get txs with transfers matching this transfer query
outputQuery - - -object -| - -MoneroOutputQuery - - - - get txs with outputs matching this output query
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - - - - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

filterOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

filterTransfers()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getBlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getChangeAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getChangeAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getExtra()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getExtraHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getFee()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getFullHex() → {string}

- - - - - - -
- Get full transaction hex. Full hex = pruned hex + prunable hex. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is full transaction hex -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHashes()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getIncludeOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getIncomingAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getIncomingTransfers()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getInputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getInputSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLastFailedHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLastFailedHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLastRelayedTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMaxHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMaxUsedBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMaxUsedBlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMetadata()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMinHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNote()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumConfirmations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumDummyOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutgoingAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutgoingTransfer()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutputIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutputQuery()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutputSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPaymentIds()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrunableHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrunableHex() → {string}

- - - - - - -
- Get prunable transaction hex which is hex that is removed from a pruned -transaction. Full hex = pruned hex + prunable hex. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is the prunable transaction hex -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getPrunedHex() → {string}

- - - - - - -
- Get pruned transaction hex. Full hex = pruned hex + prunable hex. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is pruned transaction hex -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getRctSignatures()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRctSigPrunable()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getReceivedTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRelay()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRingSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSignatures()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTransferQuery()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTransfers()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTxSet()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getUnlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

hasPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

inTxPool()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isConfirmed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isDoubleSpendSeen()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isFailed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isIncoming()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isKeptByBlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isLocked()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isMinerTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isOutgoing()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isRelayed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

meetsCriteria()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge(tx)

- - - - - - -
- Updates this transaction by merging the latest information from the given -transaction. - -Merging can modify or build references to the transaction given so it -should not be re-used or it should be copied before calling this method. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tx - - is the transaction to merge into this transaction
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setChangeAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setChangeAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setExtra()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setExtraHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setFee()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setFullHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHashes()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHasPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIncludeOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIncomingTransfers()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setInputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setInputSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setInTxPool()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsConfirmed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsDoubleSpend()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsFailed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsIncoming()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsKeptByBlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsLocked()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsMinerTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsOutgoing()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsRelayed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLastFailedHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLastFailedHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLastRelayedTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMaxHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMaxUsedBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMaxUsedBlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMetadata()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMinHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNote()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumConfirmations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumDummyOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOutgoingTransfer()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOutputIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOutputQuery()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOutputSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPaymentIds()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrunableHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrunableHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrunedHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRctSignatures()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRctSigPrunable()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setReceivedTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRelay()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRingSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSignatures()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTransferQuery()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTxSet()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setUnlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroTxSet.html b/docs/MoneroTxSet.html deleted file mode 100644 index cc77d7373..000000000 --- a/docs/MoneroTxSet.html +++ /dev/null @@ -1,1103 +0,0 @@ - - - - - JSDoc: Class: MoneroTxSet - - - - - - - - - - -
- -

Class: MoneroTxSet

- - - - - - -
- -
- -

MoneroTxSet()

- -
Groups transactions who share common hex data which is needed in order to -sign and submit the transactions. - -For example, multisig transactions created from createTxs() share a common -hex string which is needed in order to sign and submit the multisig -transactions.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroTxSet()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getMultisigTxHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSignedTxHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTxs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getUnsignedTxHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMultisigTxHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSignedTxHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTxs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setUnsignedTxHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroTxWallet.html b/docs/MoneroTxWallet.html deleted file mode 100644 index 183eaffb3..000000000 --- a/docs/MoneroTxWallet.html +++ /dev/null @@ -1,10007 +0,0 @@ - - - - - JSDoc: Class: MoneroTxWallet - - - - - - - - - - -
- -

Class: MoneroTxWallet

- - - - - - -
- -
- -

MoneroTxWallet(state)

- -
Models a Monero transaction with wallet extensions.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroTxWallet(state)

- - - - - - -
- Construct the model. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
state - - -MoneroTxWallet -| - -object - - - - is existing state to initialize from (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - - - - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

filterOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

filterTransfers()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getBlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getChangeAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getChangeAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getExtra()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getExtraHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getFee()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getFullHex() → {string}

- - - - - - -
- Get full transaction hex. Full hex = pruned hex + prunable hex. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is full transaction hex -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getIncomingAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getIncomingTransfers()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getInputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getInputSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLastFailedHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLastFailedHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLastRelayedTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMaxUsedBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMaxUsedBlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMetadata()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNote()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumConfirmations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumDummyOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutgoingAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutgoingTransfer()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutputIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getOutputSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrunableHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrunableHex() → {string}

- - - - - - -
- Get prunable transaction hex which is hex that is removed from a pruned -transaction. Full hex = pruned hex + prunable hex. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is the prunable transaction hex -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getPrunedHex() → {string}

- - - - - - -
- Get pruned transaction hex. Full hex = pruned hex + prunable hex. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is pruned transaction hex -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

getRctSignatures()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRctSigPrunable()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getReceivedTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRelay()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRingSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSignatures()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTransfers()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getTxSet()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getUnlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

inTxPool()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isConfirmed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isDoubleSpendSeen()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isFailed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isIncoming()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isKeptByBlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isLocked()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isMinerTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isOutgoing()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isRelayed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

merge(tx)

- - - - - - -
- Updates this transaction by merging the latest information from the given -transaction. - -Merging can modify or build references to the transaction given so it -should not be re-used or it should be copied before calling this method. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tx - - is the transaction to merge into this transaction
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setBlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setChangeAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setChangeAmount()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setExtra()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setExtraHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setFee()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setFullHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIncomingTransfers()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setInputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setInputSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setInTxPool()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsConfirmed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsDoubleSpend()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsFailed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsIncoming()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsKeptByBlock()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsLocked()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsMinerTx()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsOutgoing()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsRelayed()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLastFailedHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLastFailedHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLastRelayedTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMaxUsedBlockHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMaxUsedBlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMetadata()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNote()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumConfirmations()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumDummyOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOutgoingTransfer()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOutputIndices()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOutputs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setOutputSum()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrunableHash()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrunableHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrunedHex()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRctSignatures()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRctSigPrunable()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setReceivedTimestamp()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRelay()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRingSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSignatures()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSize()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setTxSet()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setUnlockHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setVersion()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setWeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toString()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroUtils.html b/docs/MoneroUtils.html deleted file mode 100644 index 7b8b8e745..000000000 --- a/docs/MoneroUtils.html +++ /dev/null @@ -1,1803 +0,0 @@ - - - - - JSDoc: Class: MoneroUtils - - - - - - - - - - -
- -

Class: MoneroUtils

- - - - - - -
- -
- -

MoneroUtils

- -
Collection of Monero utilities.
- - -
- -
-
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(static) binaryBlocksToJson(uint8arr)

- - - - - - -
- Converts the binary response from daemon RPC block retrieval to JSON. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uint8arr - - is the binary response from daemon RPC when getting blocks
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- a JSON object with the blocks data -
- - - - - - - - - - - - - - - -

(static) binaryToJson(uint8arr)

- - - - - - -
- Converts the given portable storage binary to JSON. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uint8arr - - is a Uint8Array with binary data in Monero's portable storage format
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- a JSON object converted from the binary data -
- - - - - - - - - - - - - - - -

(static) getLastTxPubKey(txExtra)

- - - - - - -
- Decodes tx extra according to https://cryptonote.org/cns/cns005.txt and -returns the last tx pub key. - -TODO: use c++ bridge for this -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txExtra - - is an array of tx extra bytes
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the last pub key as a hexidecimal string -
- - - - - - - - - - - - - - - -

(static) isValidAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) isValidPaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) jsonToBinary(json)

- - - - - - -
- Converts the given JSON to a binary Uint8Array using Monero's portable storage format. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
json - - is the json to convert to binary
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- Uint8Array is the json converted to portable storage binary -
- - - - - - - - - - - - - - - -

(static) mergeTx(txs, tx)

- - - - - - -
- Merges a transaction into a list of existing transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txs - - are existing transactions to merge into
tx - - is the transaction to merge into the list
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) paymentIdsEqual(paymentId1, paymentId2)

- - - - - - -
- Determines if two payment ids are functionally equal. - -For example, 03284e41c342f032 and 03284e41c342f032000000000000000000000000000000000000000000000000 are considered equal. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
paymentId1 - - is a payment id to compare
paymentId2 - - is a payment id to compare
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the payment ids are equal, false otherwise -
- - - - - - - - - - - - - - - -

(static) validateAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) validateMnemonic()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) validatePaymentId()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) validatePrivateSpendKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) validatePrivateViewKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) validatePublicSpendKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(static) validatePublicViewKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroVersion.html b/docs/MoneroVersion.html deleted file mode 100644 index be76f17ba..000000000 --- a/docs/MoneroVersion.html +++ /dev/null @@ -1,744 +0,0 @@ - - - - - JSDoc: Class: MoneroVersion - - - - - - - - - - -
- -

Class: MoneroVersion

- - - - - - -
- -
- -

MoneroVersion(number, isRelease)

- -
Models a Monero version.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroVersion(number, isRelease)

- - - - - - -
- Construct the model. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
number - - is the version number
isRelease - - indicates if this version is a release
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

copy()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNumber()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

isRelease()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setIsRelease()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNumber()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroWallet.html b/docs/MoneroWallet.html deleted file mode 100644 index ca8bf1533..000000000 --- a/docs/MoneroWallet.html +++ /dev/null @@ -1,16355 +0,0 @@ - - - - - JSDoc: Interface: MoneroWallet - - - - - - - - - - -
- -

Interface: MoneroWallet

- - - - - - -
- -
- -

MoneroWallet

- -
Monero wallet interface and default implementations.
- - -
- -
-
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(async) addAddressBookEntry(address, description) → {int}

- - - - - - -
- Add an address book entry. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - entry address
description - - -string - - - - entry description (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the index of the added entry -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) checkReserveProof(address, message, signature) → {MoneroCheckReserve}

- - - - - - -
- Proves a wallet has a disposable reserve using a signature. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - public wallet address
message - - -string - - - - message included with the signature to further authenticate the proof (optional)
signature - - -string - - - - reserve proof signature to check
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result of checking the signature proof -
- - - -
-
- Type -
-
- -MoneroCheckReserve - - -
-
- - - - - - - - - - - - - -

(async) checkSpendProof(txHash, message, signature) → {boolean}

- - - - - - -
- Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to prove
message - - -string - - - - message included with the signature to further authenticate the proof (optional)
signature - - -string - - - - transaction signature to confirm
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the signature is good, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) checkTxKey(txHash, txKey, address) → {MoneroCheckTx}

- - - - - - -
- Check a transaction in the blockchain with its secret key. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to check
txKey - - -string - - - - transaction's secret key
address - - -string - - - - destination public address of the transaction
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result of the check -
- - - -
-
- Type -
-
- -MoneroCheckTx - - -
-
- - - - - - - - - - - - - -

(async) checkTxProof(txHash, address, message, signature) → {MoneroCheckTx}

- - - - - - -
- Prove a transaction by checking its signature. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to prove
address - - -string - - - - destination public address of the transaction
message - - -string - - - - message included with the signature to further authenticate the proof (optional)
signature - - -string - - - - transaction signature to confirm
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result of the check -
- - - -
-
- Type -
-
- -MoneroCheckTx - - -
-
- - - - - - - - - - - - - -

(async) close(save)

- - - - - - -
- Optionally save then close the wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
save - - -boolean - - - - specifies if the wallet should be saved before being closed (default false)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) createAccount(label) → {MoneroAccount}

- - - - - - -
- Create a new account with a label for the first subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
label - - -string - - - - label for account's first subaddress (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created account -
- - - -
-
- Type -
-
- -MoneroAccount - - -
-
- - - - - - - - - - - - - -

(async) createPaymentUri(config) → {string}

- - - - - - -
- Creates a payment URI from a send configuration. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig - - - - specifies configuration for a potential tx
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the payment uri -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) createSubaddress(accountIdx, label) → {MoneroSubaddress}

- - - - - - -
- Create a subaddress within an account. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the account to create the subaddress within
label - - -string - - - - the label for the subaddress (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created subaddress -
- - - -
-
- Type -
-
- -MoneroSubaddress - - -
-
- - - - - - - - - - - - - -

(async) createTx(config) → {MoneroTxWallet}

- - - - - - -
- Create a transaction to transfer funds from this wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig -| - -object - - - - configures the transaction to create (required) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address (required unless `destinations` provided)
amount - - -BigInteger -| - -string - - - - single destination amount (required unless `destinations` provided)
accountIndex - - -int - - - - source account index to transfer funds from (required)
subaddressIndex - - -int - - - - source subaddress index to transfer funds from (optional)
subaddressIndices - - -Array.<int> - - - - source subaddress indices to transfer funds from (optional)
relay - - -boolean - - - - relay the transaction to peers to commit to the blockchain (default false)
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
destinations - - -Array.<MoneroDestination> - - - - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided)
paymentId - - -string - - - - transaction payment ID (optional)
unlockHeight - - -int - - - - minimum height for the transaction to unlock (default 0)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transaction -
- - - -
-
- Type -
-
- -MoneroTxWallet - - -
-
- - - - - - - - - - - - - -

(async) createTxs(config) → {Array.<MoneroTxWallet>}

- - - - - - -
- Create one or more transactions to transfer funds from this wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig -| - -object - - - - configures the transactions to create (required) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address (required unless `destinations` provided)
amount - - -BigInteger -| - -string - - - - single destination amount (required unless `destinations` provided)
accountIndex - - -int - - - - source account index to transfer funds from (required)
subaddressIndex - - -int - - - - source subaddress index to transfer funds from (optional)
subaddressIndices - - -Array.<int> - - - - source subaddress indices to transfer funds from (optional)
relay - - -boolean - - - - relay the transactions to peers to commit to the blockchain (default false)
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
destinations - - -Array.<MoneroDestination> - - - - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided)
paymentId - - -string - - - - transaction payment ID (optional)
unlockHeight - - -int - - - - minimum height for the transactions to unlock (default 0)
canSplit - - -boolean - - - - allow funds to be transferred using multiple transactions (default true)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transactions -
- - - -
-
- Type -
-
- -Array.<MoneroTxWallet> - - -
-
- - - - - - - - - - - - - -

(async) decodeIntegratedAddress(integratedAddress) → {MoneroIntegratedAddress}

- - - - - - -
- Decode an integrated address to get its standard address and payment id. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
integratedAddress - - -string - - - - integrated address to decode
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the decoded integrated address including standard address and payment id -
- - - -
-
- Type -
-
- -MoneroIntegratedAddress - - -
-
- - - - - - - - - - - - - -

(async) deleteAddressBookEntry(entryIdx)

- - - - - - -
- Delete an address book entry. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
entryIdx - - -int - - - - index of the entry to delete
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) editAddressBookEntry(index, setAddress, address, setDescription, description)

- - - - - - -
- Edit an address book entry. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
index - - -number - - - - index of the address book entry to edit
setAddress - - -boolean - - - - specifies if the address should be updated
address - - -string - - - - updated address
setDescription - - -boolean - - - - specifies if the description should be updated
description - - -string - - - - updated description
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) exchangeMultisigKeys(multisigHexes, password) → {MoneroMultisigInitResult}

- - - - - - -
- Exchange multisig hex with participants in a M/N multisig wallet. - -This process must be repeated with participants exactly N-M times. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
multisigHexes - - -Array.<string> - - - - are multisig hex from each participant
password - - -string - - - - wallet's password // TODO monero core: redundant? wallet is created with password
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done -
- - - -
-
- Type -
-
- -MoneroMultisigInitResult - - -
-
- - - - - - - - - - - - - -

(async) getAccount(accountIdx, includeSubaddresses) → {MoneroAccount}

- - - - - - -
- Get an account. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the account to get
includeSubaddresses - - -boolean - - - - include subaddresses if true
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the retrieved account -
- - - -
-
- Type -
-
- -MoneroAccount - - -
-
- - - - - - - - - - - - - -

(async) getAccounts(includeSubaddresses, tag) → {Array.<MoneroAccount>}

- - - - - - -
- Get accounts with a given tag. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
includeSubaddresses - - -boolean - - - - include subaddresses if true
tag - - -string - - - - tag for filtering accounts, all accounts if undefined
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- all accounts with the given tag -
- - - -
-
- Type -
-
- -Array.<MoneroAccount> - - -
-
- - - - - - - - - - - - - -

(async) getAccountTags() → {Array.<MoneroAccountTag>}

- - - - - - -
- Return all account tags. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's account tags -
- - - -
-
- Type -
-
- -Array.<MoneroAccountTag> - - -
-
- - - - - - - - - - - - - -

(async) getAddress(accountIdx, subaddressIdx) → {string}

- - - - - - -
- Get the address of a specific subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - the account index of the address's subaddress
subaddressIdx - - -int - - - - the subaddress index within the account
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the receive address of the specified subaddress -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getAddressBookEntries(entryIndices) → {Array.<MoneroAddressBookEntry>}

- - - - - - -
- Get address book entries. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
entryIndices - - -Array.<int> - - - - indices of the entries to get
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the address book entries -
- - - -
-
- Type -
-
- -Array.<MoneroAddressBookEntry> - - -
-
- - - - - - - - - - - - - -

(async) getAddressIndex(address) → {MoneroSubaddress}

- - - - - - -
- Get the account and subaddress index of the given address. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - address to get the account and subaddress index from
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the account and subaddress indices -
- - - -
-
- Type -
-
- -MoneroSubaddress - - -
-
- - - - - - - - - - - - - -

(async) getAttribute(key) → {string}

- - - - - - -
- Get an attribute. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
key - - -string - - - - attribute to get the value of
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the attribute's value -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getBalance(accountIdx, subaddressIdx) → {BigInteger}

- - - - - - -
- Get the balance of the wallet, account, or subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the account to get the balance of (optional)
subaddressIdx - - -int - - - - index of the subaddress to get the balance of (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the balance of the wallet, account, or subaddress -
- - - -
-
- Type -
-
- -BigInteger - - -
-
- - - - - - - - - - - - - -

(async) getDaemonConnection() → {MoneroRpcConnection}

- - - - - - -
- Get the wallet's daemon connection. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's daemon connection -
- - - -
-
- Type -
-
- -MoneroRpcConnection - - -
-
- - - - - - - - - - - - - -

(async) getDaemonHeight() → {int}

- - - - - - -
- Get the blockchain's height. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the blockchain's height -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) getHeight() → {int}

- - - - - - -
- Get the height of the last block processed by the wallet (its index + 1). -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the height of the last block processed by the wallet -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) getHeightByDate(year, month, day)

- - - - - - -
- Get the blockchain's height by date as a conservative estimate for scanning. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
year - - -int - - - - year of the height to get
month - - -int - - - - month of the height to get as a number between 1 and 12
day - - -int - - - - day of the height to get as a number between 1 and 31
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the blockchain's approximate height at the given date -
- - - - - - - - - - - - - - - -

(async) getIncomingTransfers(query) → {Array.<MoneroIncomingTransfer>}

- - - - - - -
- Get all of the wallet's incoming transfers. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - passed to getTransfers() with isIncoming=true
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's incoming transfers -
- - - -
-
- Type -
-
- -Array.<MoneroIncomingTransfer> - - -
-
- - - - - - - - - - - - - -

(async) getIntegratedAddress(paymentId) → {MoneroIntegratedAddress}

- - - - - - -
- Get an integrated address based on this wallet's primary address and the -given payment ID. Generates a random payment ID if none is given. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
paymentId - - -string - - - - payment ID to generate an integrated address from (randomly generated if undefined)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the integrated address -
- - - -
-
- Type -
-
- -MoneroIntegratedAddress - - -
-
- - - - - - - - - - - - - -

(async) getKeyImages() → {Array.<MoneroKeyImage>}

- - - - - - -
- Get all signed key images. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's signed key images -
- - - -
-
- Type -
-
- -Array.<MoneroKeyImage> - - -
-
- - - - - - - - - - - - - -

(async) getMnemonic() → {string}

- - - - - - -
- Get the wallet's mnemonic phrase derived from the seed. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's mnemonic phrase -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getMnemonicLanguage() → {string}

- - - - - - -
- Get the language of the wallet's mnemonic phrase. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the language of the wallet's mnemonic phrase -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getMultisigHex() → {string}

- - - - - - -
- Export this wallet's multisig info as hex for other participants. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- this wallet's multisig info as hex for other participants -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getMultisigInfo() → {MoneroMultisigInfo}

- - - - - - -
- Get multisig info about this wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- multisig info about this wallet -
- - - -
-
- Type -
-
- -MoneroMultisigInfo - - -
-
- - - - - - - - - - - - - -

(async) getNewKeyImagesFromLastImport() → {Array.<MoneroKeyImage>}

- - - - - - -
- Get new key images from the last imported outputs. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the key images from the last imported outputs -
- - - -
-
- Type -
-
- -Array.<MoneroKeyImage> - - -
-
- - - - - - - - - - - - - -

(async) getOutgoingTransfers(query) → {Array.<MoneroOutgoingTransfer>}

- - - - - - -
- Get all of the wallet's outgoing transfers. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - passed to getTransfers() with isOutgoing=true
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's outgoing transfers -
- - - -
-
- Type -
-
- -Array.<MoneroOutgoingTransfer> - - -
-
- - - - - - - - - - - - - -

(async) getOutputs(query) → {Array.<MoneroOutputWallet>}

- - - - - - -
-

Get outputs created from previous transactions that belong to the wallet -(i.e. that the wallet can spend one time). Outputs are part of -transactions which are stored in blocks on the blockchain.

- -

Results can be filtered by passing a query object. Outputs must -meet every criteria defined in the query in order to be returned. All -filtering is optional and no filtering is applied when not defined.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - -MoneroOutputQuery -| - -object - - - - configures the query (optional) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIndex - - -int - - - - get outputs associated with a specific account index (optional)
subaddressIndex - - -int - - - - get outputs associated with a specific subaddress index (optional)
subaddressIndices - - -Array.<int> - - - - get outputs associated with specific subaddress indices (optional)
amount - - -BigInteger - - - - get outputs with a specific amount (optional)
minAmount - - -BigInteger - - - - get outputs greater than or equal to a minimum amount (optional)
maxAmount - - -BigInteger - - - - get outputs less than or equal to a maximum amount (optional)
isSpent - - -boolean - - - - get outputs that are spent or not (optional)
keyImage - - -string -| - -MoneroKeyImage - - - - get output with a key image or which matches fields defined in a MoneroKeyImage (optional)
txQuery - - -MoneroTxQuery - - - - get outputs whose transaction meets this filter (optional)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are queried outputs -
- - - -
-
- Type -
-
- -Array.<MoneroOutputWallet> - - -
-
- - - - - - - - - - - - - -

(async) getOutputsHex() → {string}

- - - - - - -
- Export all outputs in hex format. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- all outputs in hex format, undefined if no outputs -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPath() → {string}

- - - - - - -
- Get the wallet's path. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the path the wallet can be opened with -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPrimaryAddress() → {string}

- - - - - - -
- Get the wallet's primary address. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's primary address -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPrivateSpendKey() → {string}

- - - - - - -
- Get the wallet's private spend key. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's private spend key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPrivateViewKey() → {string}

- - - - - - -
- Get the wallet's private view key. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's private view key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPublicSpendKey() → {string}

- - - - - - -
- Get the wallet's public spend key. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's public spend key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPublicViewKey() → {string}

- - - - - - -
- Get the wallet's public view key. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's public view key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getReserveProofAccount(accountIdx, amount, message) → {string}

- - - - - - -
- Generate a signature to prove an available amount in an account. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - account to prove ownership of the amount
amount - - -BigInteger - - - - minimum amount to prove as available in the account
message - - -string - - - - message to include with the signature to further authenticate the proof (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the reserve proof signature -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getReserveProofWallet(message)

- - - - - - -
- Generate a signature to prove the entire balance of the wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
message - - message included with the signature to further authenticate the proof (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the reserve proof signature -
- - - - - - - - - - - - - - - -

(async) getSpendProof(txHash, message) → {string}

- - - - - - -
- Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to prove
message - - -string - - - - message to include with the signature to further authenticate the proof (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the transaction signature -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getSubaddress(accountIdx, subaddressIdx) → {MoneroSubaddress}

- - - - - - -
- Get a subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the subaddress's account
subaddressIdx - - -int - - - - index of the subaddress within the account
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the retrieved subaddress -
- - - -
-
- Type -
-
- -MoneroSubaddress - - -
-
- - - - - - - - - - - - - -

(async) getSubaddresses(accountIdx, subaddressIndices) → {Array.<MoneroSubaddress>}

- - - - - - -
- Get subaddresses in an account. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - account to get subaddresses within
subaddressIndices - - -Array.<int> - - - - indices of subaddresses to get (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the retrieved subaddresses -
- - - -
-
- Type -
-
- -Array.<MoneroSubaddress> - - -
-
- - - - - - - - - - - - - -

(async) getTransfers(query) → {Array.<MoneroTransfer>}

- - - - - - -
-

Get incoming and outgoing transfers to and from this wallet. An outgoing -transfer represents a total amount sent from one or more subaddresses -within an account to individual destination addresses, each with their -own amount. An incoming transfer represents a total amount received into -a subaddress within an account. Transfers belong to transactions which -are stored on the blockchain.

- -

Results can be filtered by passing a query object. Transfers must -meet every criteria defined in the query in order to be returned. All -criteria are optional and no filtering is applied when not defined.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - -MoneroTransferQuery -| - -object - - - - configures the query (optional) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
isOutgoing - - -boolean - - - - get transfers that are outgoing or not (optional)
isIncoming - - -boolean - - - - get transfers that are incoming or not (optional)
address - - -string - - - - wallet's address that a transfer either originated from (if outgoing) or is destined for (if incoming) (optional)
accountIndex - - -int - - - - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific account index (optional)
subaddressIndex - - -int - - - - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific subaddress index (optional)
subaddressIndices - - -Array.<int> - - - - get transfers that either originated from (if outgoing) or are destined for (if incoming) specific subaddress indices (optional)
amount - - -BigInteger - - - - amount being transferred (optional)
destinations - - -Array.<MoneroDestination> - - - - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional)
hasDestinations - - -boolean - - - - get transfers that have destinations or not (optional)
txQuery - - -MoneroTxQuery - - - - get transfers whose transaction meets this query (optional)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are wallet transfers per the configuration -
- - - -
-
- Type -
-
- -Array.<MoneroTransfer> - - -
-
- - - - - - - - - - - - - -

(async) getTx(txHash) → {MoneroTxWallet}

- - - - - - -
- Get a wallet transaction by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - hash of a transaction to get
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the identified transactions -
- - - -
-
- Type -
-
- -MoneroTxWallet - - -
-
- - - - - - - - - - - - - -

(async) getTxKey(txHash) → {string}

- - - - - - -
- Get a transaction's secret key from its hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction's hash
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- - transaction's secret key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getTxNote(txHash) → {string}

- - - - - - -
- Get a transaction note. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to get the note of
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the tx note -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getTxNotes(txHashes) → {Array.<string>}

- - - - - - -
- Get notes for multiple transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHashes - - -Array.<string> - - - - hashes of the transactions to get notes for
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- notes for the transactions -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) getTxProof(txHash, address, message) → {string}

- - - - - - -
- Get a transaction signature to prove it. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to prove
address - - -string - - - - destination public address of the transaction
message - - -string - - - - message to include with the signature to further authenticate the proof (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the transaction signature -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getTxs(query, missingTxHashes) → {Array.<MoneroTxWallet>}

- - - - - - -
-

Get wallet transactions. Wallet transactions contain one or more -transfers that are either incoming or outgoing to the wallet.

- -

Results can be filtered by passing a query object. Transactions must -meet every criteria defined in the query in order to be returned. All -criteria are optional and no filtering is applied when not defined.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - -MoneroTxQuery -| - -Array.<string> -| - -object - - - - configures the query (optional) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
isConfirmed - - -boolean - - - - get txs that are confirmed or not (optional)
inTxPool - - -boolean - - - - get txs that are in the tx pool or not (optional)
isRelayed - - -boolean - - - - get txs that are relayed or not (optional)
isFailed - - -boolean - - - - get txs that are failed or not (optional)
isMinerTx - - -boolean - - - - get miner txs or not (optional)
hash - - -string - - - - get a tx with the hash (optional)
hashes - - -Array.<string> - - - - get txs with the hashes (optional)
paymentId - - -string - - - - get transactions with the payment id (optional)
paymentIds - - -Array.<string> - - - - get transactions with the payment ids (optional)
hasPaymentId - - -boolean - - - - get transactions with a payment id or not (optional)
minHeight - - -int - - - - get txs with height >= the given height (optional)
maxHeight - - -int - - - - get txs with height <= the given height (optional)
isOutgoing - - -boolean - - - - get txs with an outgoing transfer or not (optional)
isIncoming - - -boolean - - - - get txs with an incoming transfer or not (optional)
transferQuery - - -MoneroTransferQuery - - - - get txs that have a transfer that meets this query (optional)
includeOutputs - - -boolean - - - - specifies that tx outputs should be returned with tx results (optional)
- -
missingTxHashes - - -Array.<string> - - - - populated with hashes of unfound or unmet transactions that were queried by hash (throws error if undefined and queried transaction hashes are unfound or unmet)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- wallet transactions per the configuration -
- - - -
-
- Type -
-
- -Array.<MoneroTxWallet> - - -
-
- - - - - - - - - - - - - -

(async) getUnlockedBalance(accountIdx, subaddressIdx) → {BigInteger}

- - - - - - -
- Get the unlocked balance of the wallet, account, or subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the account to get the unlocked balance of (optional)
subaddressIdx - - -int - - - - index of the subaddress to get the unlocked balance of (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the unlocked balance of the wallet, account, or subaddress -
- - - -
-
- Type -
-
- -BigInteger - - -
-
- - - - - - - - - - - - - -

(async) getVersion() → {MoneroVersion}

- - - - - - -
- Gets the version of the wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the version of the wallet -
- - - -
-
- Type -
-
- -MoneroVersion - - -
-
- - - - - - - - - - - - - -

(async) importKeyImages(keyImages) → {MoneroKeyImageImportResult}

- - - - - - -
- Import signed key images and verify their spent status. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyImages - - -Array.<MoneroKeyImage> - - - - images to import and verify (requires hex and signature)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- results of the import -
- - - -
-
- Type -
-
- -MoneroKeyImageImportResult - - -
-
- - - - - - - - - - - - - -

(async) importMultisigHex(multisigHexes) → {int}

- - - - - - -
- Import multisig info as hex from other participants. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
multisigHexes - - -Array.<string> - - - - multisig hex from each participant
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the number of outputs signed with the given multisig hex -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) importOutputsHex(outputsHex) → {int}

- - - - - - -
- Import outputs in hex format. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
outputsHex - - -string - - - - outputs in hex format
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the number of outputs imported -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) isClosed() → {boolean}

- - - - - - -
- Indicates if this wallet is closed or not. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is closed, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isConnected() → {boolean}

- - - - - - -
- Indicates if the wallet is connected to daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is connected to a daemon, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isMultisig() → {boolean}

- - - - - - -
- Indicates if this wallet is a multisig wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if this is a multisig wallet, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isMultisigImportNeeded() → {boolean}

- - - - - - -
- Indicates if importing multisig data is needed for returning a correct balance. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if importing multisig data is needed for returning a correct balance, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isViewOnly() → {bool}

- - - - - - -
- Indicates if the wallet is view-only, meaning it does have the private -spend key and can therefore only observe incoming outputs. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is view-only, false otherwise -
- - - -
-
- Type -
-
- -bool - - -
-
- - - - - - - - - - - - - -

(async) makeMultisig(multisigHexes, threshold, password) → {MoneroMultisigInitResult}

- - - - - - -
- Make this wallet multisig by importing multisig hex from participants. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
multisigHexes - - -Array.<String> - - - - multisig hex from each participant
threshold - - -int - - - - number of signatures needed to sign transfers
password - - -string - - - - wallet password
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not N/N -
- - - -
-
- Type -
-
- -MoneroMultisigInitResult - - -
-
- - - - - - - - - - - - - -

(async) parsePaymentUri(uri) → {MoneroTxConfig}

- - - - - - -
- Parses a payment URI to a tx config. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uri - - -string - - - - payment uri to parse
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the send configuration parsed from the uri -
- - - -
-
- Type -
-
- -MoneroTxConfig - - -
-
- - - - - - - - - - - - - -

(async) parseTxSet(txSet) → {MoneroTxSet}

- - - - - - -
- Parse a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txSet - - -MoneroTxSet - - - - a tx set containing unsigned or multisig tx hex
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the parsed tx set containing structured transactions -
- - - -
-
- Type -
-
- -MoneroTxSet - - -
-
- - - - - - - - - - - - - -

(async) prepareMultisig() → {string}

- - - - - - -
- Get multisig info as hex to share with participants to begin creating a -multisig wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- this wallet's multisig hex to share with participants -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) relayTx(txOrMetadata) → {string}

- - - - - - -
- Relay a previously created transaction. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txOrMetadata - - -MoneroTxWallet -| - -string - - - - transaction or its metadata to relay
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the hash of the relayed tx -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) relayTxs(txsOrMetadatas) → {Array.<string>}

- - - - - - -
- Relay previously created transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txsOrMetadatas - - -Array.<MoneroTxWallet> -| - -Array.<string> - - - - transactions or their metadata to relay
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the hashes of the relayed txs -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) rescanBlockchain()

- - - - - - -
-

Rescan the blockchain from scratch, losing any information which cannot be recovered from -the blockchain itself.

- -

WARNING: This method discards local wallet data like destination addresses, tx secret keys, -tx notes, etc.

-
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) rescanSpent()

- - - - - - -
-

Rescan the blockchain for spent outputs.

- -

Note: this can only be called with a trusted daemon.

- -

Example use case: peer multisig hex is import when connected to an untrusted daemon, -so the wallet will not rescan spent outputs. Then the wallet connects to a trusted -daemon. This method should be manually invoked to rescan outputs.

-
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

save()

- - - - - - -
- Save the wallet at its current path. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setAccountTagLabel(tag, label)

- - - - - - -
- Sets a human-readable description for a tag. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tag - - -string - - - - tag to set a description for
label - - -string - - - - label to set for the tag
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setAttribute(key, val)

- - - - - - -
- Set an arbitrary attribute. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
key - - -string - - - - attribute key
val - - -string - - - - attribute value
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setDaemonConnection(uriOrConnection, username, password)

- - - - - - -
- Set the wallet's daemon connection. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uriOrConnection - - -string -| - -MoneroRpcConnection - - - - daemon's URI or connection (defaults to offline)
username - - -string - - - - username to authenticate with the daemon (optional)
password - - -string - - - - password to authenticate with the daemon (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setTxNote(txHash, note)

- - - - - - -
- Set a note for a specific transaction. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - hash of the transaction to set a note for
note - - -string - - - - the transaction note
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setTxNotes(txHashes, notes)

- - - - - - -
- Set notes for multiple transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHashes - - -Array.<string> - - - - transactions to set notes for
notes - - -Array.<string> - - - - notes to set for the transactions
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) signMessage(msg) → {string}

- - - - - - -
- Sign a message. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
msg - - -string - - - - message to sign
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the signature -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) signMultisigTxHex(multisigTxHex) → {MoneroMultisigSignResult}

- - - - - - -
- Sign multisig transactions from a multisig wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
multisigTxHex - - -string - - - - unsigned multisig transactions as hex
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result of signing the multisig transactions -
- - - -
-
- Type -
-
- -MoneroMultisigSignResult - - -
-
- - - - - - - - - - - - - -

(async) signTxs(unsignedTxHex) → {string}

- - - - - - -
- Sign unsigned transactions from a view-only wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
unsignedTxHex - - -string - - - - unsigned transaction hex from when the transactions were created
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the signed transaction hex -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) startMining(numThreads, backgroundMining, ignoreBattery)

- - - - - - -
- Start mining. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
numThreads - - -int - - - - number of threads created for mining (optional)
backgroundMining - - -boolean - - - - specifies if mining should occur in the background (optional)
ignoreBattery - - -boolean - - - - specifies if the battery should be ignored for mining (optional)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) startSyncing()

- - - - - - -
- Start an asynchronous thread to continuously synchronize the wallet with the daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) stopMining()

- - - - - - -
- Stop mining. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) stopSyncing()

- - - - - - -
- Stop synchronizing the wallet with the daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) submitMultisigTxHex(signedMultisigTxHex) → {Array.<string>}

- - - - - - -
- Submit signed multisig transactions from a multisig wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
signedMultisigTxHex - - -string - - - - signed multisig hex returned from signMultisigTxHex()
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the resulting transaction hashes -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) submitTxs(signedTxHex) → {Array.<string>}

- - - - - - -
- Submit signed transactions from a view-only wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
signedTxHex - - -string - - - - signed transaction hex from signTxs()
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the resulting transaction hashes -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) sweepDust(relay) → {Array.<MoneroTxWallet>}

- - - - - - -
-

Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

- -

NOTE: Dust only exists pre RCT, so this method will throw "no dust to sweep" on new wallets.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
relay - - -boolean - - - - specifies if the resulting transaction should be relayed (default false)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transactions -
- - - -
-
- Type -
-
- -Array.<MoneroTxWallet> - - -
-
- - - - - - - - - - - - - -

(async) sweepOutput(config) → {MoneroTxWallet}

- - - - - - -
- Sweep an output by key image. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig - - - - configures the transaction to create (required) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address (required)
keyImage - - -string - - - - key image to sweep (required)
relay - - -boolean - - - - relay the transaction to peers to commit to the blockchain (default false)
unlockHeight - - -int - - - - minimum height for the transaction to unlock (default 0)
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transaction -
- - - -
-
- Type -
-
- -MoneroTxWallet - - -
-
- - - - - - - - - - - - - -

(async) sweepUnlocked(config) → {Array.<MoneroTxWallet>}

- - - - - - -
- Sweep all unlocked funds according to the given configuration. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig -| - -object - - - - configures the transactions to create (required) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address (required)
accountIndex - - -int - - - - source account index to sweep from from (required)
subaddressIndex - - -int - - - - source subaddress index to sweep from (optional)
subaddressIndices - - -Array.<int> - - - - source subaddress indices to sweep from (optional)
relay - - -boolean - - - - relay the transactions to peers to commit to the blockchain (default false)
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
unlockHeight - - -int - - - - minimum height for the transactions to unlock (default 0)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transactions -
- - - -
-
- Type -
-
- -Array.<MoneroTxWallet> - - -
-
- - - - - - - - - - - - - -

(async) sync(listenerOrStartHeight, startHeight)

- - - - - - -
- Synchronize the wallet with the daemon as a one-time synchronous process. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
listenerOrStartHeight - - -MoneroWalletListener -| - -number - - - - listener xor start height (defaults to no sync listener, the last synced block)
startHeight - - -number - - - - startHeight if not given in first arg (defaults to last synced block)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) tagAccounts(tag, accountIndices)

- - - - - - -
- Tag accounts. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tag - - -string - - - - tag to apply to the specified accounts
accountIndices - - -Array.<int> - - - - indices of the accounts to tag
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) untagAccounts(accountIndices)

- - - - - - -
- Untag accounts. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIndices - - -Array.<int> - - - - indices of the accounts to untag
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) verifyMessage(msg, address, signature) → {boolean}

- - - - - - -
- Verify a signature on a message. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
msg - - -string - - - - signed message
address - - -string - - - - signing address
signature - - -string - - - - signature
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the signature is good, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroWalletConfig.html b/docs/MoneroWalletConfig.html deleted file mode 100644 index bb475ad9e..000000000 --- a/docs/MoneroWalletConfig.html +++ /dev/null @@ -1,4005 +0,0 @@ - - - - - JSDoc: Class: MoneroWalletConfig - - - - - - - - - - -
- -

Class: MoneroWalletConfig

- - - - - - -
- -
- -

MoneroWalletConfig(config)

- -
Configuration to create a Monero wallet.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroWalletConfig(config)

- - - - - - -
- Construct a configuration to open or create a wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -object -| - -MoneroWalletConfig - - - - MoneroWalletConfig or equivalent config object -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
path - - -string - - - - path of the wallet to open or create
password - - -string - - - - password of the wallet to open
networkType - - -string -| - -number - - - - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
serverUri - - -string - - - - uri of the wallet's server (optional)
serverUsername - - -string - - - - username of the wallet's server (optional)
serverPassword - - -string - - - - password of the wallet's server (optional)
rejectUnauthorized - - -boolean - - - - reject self-signed server certificates if true (defaults to true)
server - - -MoneroRpcConnection -| - -object - - - - MoneroRpcConnection or equivalent JS object configuring the server connection (optional)
keysData - - -Uint8Array - - - - wallet keys data to open (optional)
cacheData - - -Uint8Array - - - - wallet cache data to open (optional)
proxyToWorker - - -boolean - - - - proxies wallet operations to a web worker in order to not block the browser's main thread (default: false)
fs - - -fs - - - - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
saveCurrent - - -boolean - - - - specifies if the current RPC wallet should be saved before being closed
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getCacheData()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getFs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getKeysData()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getLanguage()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getMnemonic()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getNetworkType()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPassword()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPath()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrimaryAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrivateSpendKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrivateViewKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getProxyToWorker()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRejectUnauthorized()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getRestoreHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSaveCurrent()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getSeedOffset()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getServer()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getServerPassword()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getServerUri()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getServerUsername()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCacheData()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setFs()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setKeysData()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setLanguage()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setMnemonic()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setNetworkType()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPassword()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPath()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrimaryAddress()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrivateSpendKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrivateViewKey()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setProxyToWorker()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRejectUnauthorized()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setRestoreHeight()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSaveCurrent()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setSeedOffset()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setServer()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setServerPassword()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setServerUri()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setServerUsername()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

toJson()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroWalletKeys.html b/docs/MoneroWalletKeys.html deleted file mode 100644 index 0791c9438..000000000 --- a/docs/MoneroWalletKeys.html +++ /dev/null @@ -1,2782 +0,0 @@ - - - - - JSDoc: Class: MoneroWalletKeys - - - - - - - - - - -
- -

Class: MoneroWalletKeys

- - - - - - -
- -
- -

MoneroWalletKeys

- -
Implements a MoneroWallet which only manages keys using WebAssembly.
- - -
- -
-
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(async, static) createWallet(config) → {MoneroWalletKeys}

- - - - - - -
-

Create a wallet using WebAssembly bindings to monero-core.

- -

Example:

- - -let wallet = await MoneroWalletKeys.createWallet({
-   password: "abc123",
-   networkType: MoneroNetworkType.STAGENET,
-   mnemonic: "coexist igloo pamphlet lagoon..."
-}); -
-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroWalletConfig -| - -object - - - - MoneroWalletConfig or equivalent config object -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
networkType - - -string -| - -number - - - - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
mnemonic - - -string - - - - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)
seedOffset - - -string - - - - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase
primaryAddress - - -string - - - - primary address of the wallet to create (only provide if restoring from keys)
privateViewKey - - -string - - - - private view key of the wallet to create (optional)
privateSpendKey - - -string - - - - private spend key of the wallet to create (optional)
language - - -string - - - - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created wallet -
- - - -
-
- Type -
-
- -MoneroWalletKeys - - -
-
- - - - - - - - - - - - - -

(async, static) getMnemonicLanguages()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) close(save)

- - - - - - -
- Optionally save then close the wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
save - - -boolean - - - - specifies if the wallet should be saved before being closed (default false)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAccounts(includeSubaddresses, tag) → {Array.<MoneroAccount>}

- - - - - - -
- Get accounts with a given tag. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
includeSubaddresses - - -boolean - - - - include subaddresses if true
tag - - -string - - - - tag for filtering accounts, all accounts if undefined
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- all accounts with the given tag -
- - - -
-
- Type -
-
- -Array.<MoneroAccount> - - -
-
- - - - - - - - - - - - - -

(async) getAddress(accountIdx, subaddressIdx) → {string}

- - - - - - -
- Get the address of a specific subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - the account index of the address's subaddress
subaddressIdx - - -int - - - - the subaddress index within the account
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the receive address of the specified subaddress -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getAddressIndex(address) → {MoneroSubaddress}

- - - - - - -
- Get the account and subaddress index of the given address. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - address to get the account and subaddress index from
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the account and subaddress indices -
- - - -
-
- Type -
-
- -MoneroSubaddress - - -
-
- - - - - - - - - - - - - -

(async) getMnemonic() → {string}

- - - - - - -
- Get the wallet's mnemonic phrase derived from the seed. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's mnemonic phrase -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getMnemonicLanguage() → {string}

- - - - - - -
- Get the language of the wallet's mnemonic phrase. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the language of the wallet's mnemonic phrase -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPrimaryAddress() → {string}

- - - - - - -
- Get the wallet's primary address. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's primary address -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPrivateSpendKey() → {string}

- - - - - - -
- Get the wallet's private spend key. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's private spend key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPrivateViewKey() → {string}

- - - - - - -
- Get the wallet's private view key. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's private view key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPublicSpendKey() → {string}

- - - - - - -
- Get the wallet's public spend key. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's public spend key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPublicViewKey() → {string}

- - - - - - -
- Get the wallet's public view key. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's public view key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getSubaddress(accountIdx, subaddressIdx) → {MoneroSubaddress}

- - - - - - -
- Get a subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the subaddress's account
subaddressIdx - - -int - - - - index of the subaddress within the account
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the retrieved subaddress -
- - - -
-
- Type -
-
- -MoneroSubaddress - - -
-
- - - - - - - - - - - - - -

(async) getVersion() → {MoneroVersion}

- - - - - - -
- Gets the version of the wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the version of the wallet -
- - - -
-
- Type -
-
- -MoneroVersion - - -
-
- - - - - - - - - - - - - -

(async) isClosed() → {boolean}

- - - - - - -
- Indicates if this wallet is closed or not. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is closed, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isConnected() → {boolean}

- - - - - - -
- Indicates if the wallet is connected to daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is connected to a daemon, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isViewOnly() → {bool}

- - - - - - -
- Indicates if the wallet is view-only, meaning it does have the private -spend key and can therefore only observe incoming outputs. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is view-only, false otherwise -
- - - -
-
- Type -
-
- -bool - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroWalletListener.html b/docs/MoneroWalletListener.html deleted file mode 100644 index 4d4d56093..000000000 --- a/docs/MoneroWalletListener.html +++ /dev/null @@ -1,975 +0,0 @@ - - - - - JSDoc: Class: MoneroWalletListener - - - - - - - - - - -
- -

Class: MoneroWalletListener

- - - - - - -
- -
- -

MoneroWalletListener()

- -
Default wallet listener which takes no action on notifications.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroWalletListener()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

onBalancesChanged(newBalance, newUnlockedBalance)

- - - - - - -
- Invoked when the wallet's balances change. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
newBalance - - -BigInteger - - - - new wallet balance
newUnlockedBalance - - -BigInteger - - - - new unlocked wallet balance
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

onNewBlock(height)

- - - - - - -
- Invoked when a new block is added to the chain. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
height - - -int - - - - the height of the block added to the chain
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

onOutputReceived(output)

- - - - - - -
- Invoked when the wallet receives an unconfirmed output, when the output is confirmed, -and when the output is unlocked. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
output - - -MoneroOutputWallet - - - - the received output
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

onOutputSpent(output)

- - - - - - -
- Invoked when the wallet spends an output. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
output - - -MoneroOutputWallet - - - - the spent output
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

onSyncProgress(height, startHeight, endHeight, percentDone, message)

- - - - - - -
- Invoked as the wallet is synchronized. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
height - - -number - - - - height of the synced block
startHeight - - -number - - - - starting height of the sync request
endHeight - - -number - - - - ending height of the sync request
percentDone - - -number - - - - sync progress as a percentage
message - - -string - - - - human-readable description of the current progress
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroWalletRpc.html b/docs/MoneroWalletRpc.html deleted file mode 100644 index 20738987d..000000000 --- a/docs/MoneroWalletRpc.html +++ /dev/null @@ -1,17974 +0,0 @@ - - - - - JSDoc: Class: MoneroWalletRpc - - - - - - - - - - -
- -

Class: MoneroWalletRpc

- - - - - - -
- -
- -

MoneroWalletRpc(uriOrConfigOrConnection, username, password, rejectUnauthorized)

- -
Implements a MoneroWallet as a client of monero-wallet-rpc.
- - -
- -
-
- - - - -

Constructor

- - - -

new MoneroWalletRpc(uriOrConfigOrConnection, username, password, rejectUnauthorized)

- - - - - - -
-

Construct a wallet RPC client.

- -

Examples:

- - -let walletRpc = new MoneroWalletRpc("http://localhost:38081", "superuser", "abctesting123");

- -let walletRpc = new MoneroWalletRpc({
-   uri: "http://localhost:38081",
-   username: "superuser",
-   password: "abctesting123",
-   rejectUnauthorized: false // e.g. local development
-}); -
-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uriOrConfigOrConnection - - -string -| - -object -| - -MoneroRpcConnection - - - - uri of monero-wallet-rpc or JS config object or MoneroRpcConnection -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uri - - -string - - - - uri of monero-wallet-rpc
username - - -string - - - - username to authenticate with monero-wallet-rpc (optional)
password - - -string - - - - password to authenticate with monero-wallet-rpc (optional)
rejectUnauthorized - - -boolean - - - - rejects self-signed certificates if true (default true)
- -
username - - -string - - - - username to authenticate with monero-wallet-rpc (optional)
password - - -string - - - - password to authenticate with monero-wallet-rpc (optional)
rejectUnauthorized - - -boolean - - - - rejects self-signed certificates if true (default true)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(async) addAddressBookEntry(address, description) → {int}

- - - - - - -
- Add an address book entry. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - entry address
description - - -string - - - - entry description (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the index of the added entry -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) checkReserveProof(address, message, signature) → {MoneroCheckReserve}

- - - - - - -
- Proves a wallet has a disposable reserve using a signature. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - public wallet address
message - - -string - - - - message included with the signature to further authenticate the proof (optional)
signature - - -string - - - - reserve proof signature to check
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result of checking the signature proof -
- - - -
-
- Type -
-
- -MoneroCheckReserve - - -
-
- - - - - - - - - - - - - -

(async) checkSpendProof(txHash, message, signature) → {boolean}

- - - - - - -
- Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to prove
message - - -string - - - - message included with the signature to further authenticate the proof (optional)
signature - - -string - - - - transaction signature to confirm
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the signature is good, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) checkTxKey(txHash, txKey, address) → {MoneroCheckTx}

- - - - - - -
- Check a transaction in the blockchain with its secret key. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to check
txKey - - -string - - - - transaction's secret key
address - - -string - - - - destination public address of the transaction
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result of the check -
- - - -
-
- Type -
-
- -MoneroCheckTx - - -
-
- - - - - - - - - - - - - -

(async) checkTxProof(txHash, address, message, signature) → {MoneroCheckTx}

- - - - - - -
- Prove a transaction by checking its signature. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to prove
address - - -string - - - - destination public address of the transaction
message - - -string - - - - message included with the signature to further authenticate the proof (optional)
signature - - -string - - - - transaction signature to confirm
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result of the check -
- - - -
-
- Type -
-
- -MoneroCheckTx - - -
-
- - - - - - - - - - - - - -

(async) close(save)

- - - - - - -
- Optionally save then close the wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
save - - -boolean - - - - specifies if the wallet should be saved before being closed (default false)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) createAccount(label) → {MoneroAccount}

- - - - - - -
- Create a new account with a label for the first subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
label - - -string - - - - label for account's first subaddress (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created account -
- - - -
-
- Type -
-
- -MoneroAccount - - -
-
- - - - - - - - - - - - - -

(async) createPaymentUri(config) → {string}

- - - - - - -
- Creates a payment URI from a send configuration. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig - - - - specifies configuration for a potential tx
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the payment uri -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) createSubaddress(accountIdx, label) → {MoneroSubaddress}

- - - - - - -
- Create a subaddress within an account. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the account to create the subaddress within
label - - -string - - - - the label for the subaddress (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created subaddress -
- - - -
-
- Type -
-
- -MoneroSubaddress - - -
-
- - - - - - - - - - - - - -

(async) createTx(config) → {MoneroTxWallet}

- - - - - - -
- Create a transaction to transfer funds from this wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig -| - -object - - - - configures the transaction to create (required) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address (required unless `destinations` provided)
amount - - -BigInteger -| - -string - - - - single destination amount (required unless `destinations` provided)
accountIndex - - -int - - - - source account index to transfer funds from (required)
subaddressIndex - - -int - - - - source subaddress index to transfer funds from (optional)
subaddressIndices - - -Array.<int> - - - - source subaddress indices to transfer funds from (optional)
relay - - -boolean - - - - relay the transaction to peers to commit to the blockchain (default false)
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
destinations - - -Array.<MoneroDestination> - - - - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided)
paymentId - - -string - - - - transaction payment ID (optional)
unlockHeight - - -int - - - - minimum height for the transaction to unlock (default 0)
- -
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transaction -
- - - -
-
- Type -
-
- -MoneroTxWallet - - -
-
- - - - - - - - - - - - - -

(async) createTxs(config) → {Array.<MoneroTxWallet>}

- - - - - - -
- Create one or more transactions to transfer funds from this wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig -| - -object - - - - configures the transactions to create (required) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address (required unless `destinations` provided)
amount - - -BigInteger -| - -string - - - - single destination amount (required unless `destinations` provided)
accountIndex - - -int - - - - source account index to transfer funds from (required)
subaddressIndex - - -int - - - - source subaddress index to transfer funds from (optional)
subaddressIndices - - -Array.<int> - - - - source subaddress indices to transfer funds from (optional)
relay - - -boolean - - - - relay the transactions to peers to commit to the blockchain (default false)
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
destinations - - -Array.<MoneroDestination> - - - - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided)
paymentId - - -string - - - - transaction payment ID (optional)
unlockHeight - - -int - - - - minimum height for the transactions to unlock (default 0)
canSplit - - -boolean - - - - allow funds to be transferred using multiple transactions (default true)
- -
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transactions -
- - - -
-
- Type -
-
- -Array.<MoneroTxWallet> - - -
-
- - - - - - - - - - - - - -

(async) createWallet(config)

- - - - - - -
-

Create and open a wallet on the monero-wallet-rpc server.

- -

Example:

- - -// construct client to monero-wallet-rpc
-let walletRpc = new MoneroWalletRpc("http://localhost:38083", "rpc_user", "abc123");

- -// create and open wallet on monero-wallet-rpc
-await walletRpc.createWallet({
-   path: "mywallet",
-   password: "abc123",
-   mnemonic: "coexist igloo pamphlet lagoon...",
-   restoreHeight: 1543218l
-}); -
-

- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -object -| - -MoneroWalletConfig - - - - MoneroWalletConfig or equivalent JS object -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
path - - -string - - - - path of the wallet to create (optional, in-memory wallet if not given)
password - - -string - - - - password of the wallet to create
mnemonic - - -string - - - - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)
seedOffset - - -string - - - - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase
primaryAddress - - -string - - - - primary address of the wallet to create (only provide if restoring from keys)
privateViewKey - - -string - - - - private view key of the wallet to create (optional)
privateSpendKey - - -string - - - - private spend key of the wallet to create (optional)
restoreHeight - - -number - - - - block height to start scanning from (defaults to 0 unless generating random wallet)
language - - -string - - - - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected)
serverUri - - -string - - - - uri of a daemon to use (optional, monero-wallet-rpc usually started with daemon config)
serverUsername - - -string - - - - username to authenticate with the daemon (optional)
serverPassword - - -string - - - - password to authenticate with the daemon (optional)
rejectUnauthorized - - -boolean - - - - reject self-signed server certificates if true (defaults to true)
server - - -MoneroRpcConnection -| - -object - - - - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional)
saveCurrent - - -boolean - - - - specifies if the current RPC wallet should be saved before being closed (default true)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) decodeIntegratedAddress(integratedAddress) → {MoneroIntegratedAddress}

- - - - - - -
- Decode an integrated address to get its standard address and payment id. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
integratedAddress - - -string - - - - integrated address to decode
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the decoded integrated address including standard address and payment id -
- - - -
-
- Type -
-
- -MoneroIntegratedAddress - - -
-
- - - - - - - - - - - - - -

(async) deleteAddressBookEntry(entryIdx)

- - - - - - -
- Delete an address book entry. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
entryIdx - - -int - - - - index of the entry to delete
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) editAddressBookEntry(index, setAddress, address, setDescription, description)

- - - - - - -
- Edit an address book entry. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
index - - -number - - - - index of the address book entry to edit
setAddress - - -boolean - - - - specifies if the address should be updated
address - - -string - - - - updated address
setDescription - - -boolean - - - - specifies if the description should be updated
description - - -string - - - - updated description
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) exchangeMultisigKeys(multisigHexes, password) → {MoneroMultisigInitResult}

- - - - - - -
- Exchange multisig hex with participants in a M/N multisig wallet. - -This process must be repeated with participants exactly N-M times. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
multisigHexes - - -Array.<string> - - - - are multisig hex from each participant
password - - -string - - - - wallet's password // TODO monero core: redundant? wallet is created with password
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done -
- - - -
-
- Type -
-
- -MoneroMultisigInitResult - - -
-
- - - - - - - - - - - - - -

(async) getAccount(accountIdx, includeSubaddresses) → {MoneroAccount}

- - - - - - -
- Get an account. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the account to get
includeSubaddresses - - -boolean - - - - include subaddresses if true
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the retrieved account -
- - - -
-
- Type -
-
- -MoneroAccount - - -
-
- - - - - - - - - - - - - -

(async) getAccounts(includeSubaddresses, tag) → {Array.<MoneroAccount>}

- - - - - - -
- Get accounts with a given tag. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
includeSubaddresses - - -boolean - - - - include subaddresses if true
tag - - -string - - - - tag for filtering accounts, all accounts if undefined
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- all accounts with the given tag -
- - - -
-
- Type -
-
- -Array.<MoneroAccount> - - -
-
- - - - - - - - - - - - - -

(async) getAccountTags() → {Array.<MoneroAccountTag>}

- - - - - - -
- Return all account tags. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's account tags -
- - - -
-
- Type -
-
- -Array.<MoneroAccountTag> - - -
-
- - - - - - - - - - - - - -

(async) getAddress(accountIdx, subaddressIdx) → {string}

- - - - - - -
- Get the address of a specific subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - the account index of the address's subaddress
subaddressIdx - - -int - - - - the subaddress index within the account
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the receive address of the specified subaddress -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getAddressBookEntries(entryIndices) → {Array.<MoneroAddressBookEntry>}

- - - - - - -
- Get address book entries. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
entryIndices - - -Array.<int> - - - - indices of the entries to get
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the address book entries -
- - - -
-
- Type -
-
- -Array.<MoneroAddressBookEntry> - - -
-
- - - - - - - - - - - - - -

(async) getAddressIndex(address) → {MoneroSubaddress}

- - - - - - -
- Get the account and subaddress index of the given address. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - address to get the account and subaddress index from
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the account and subaddress indices -
- - - -
-
- Type -
-
- -MoneroSubaddress - - -
-
- - - - - - - - - - - - - -

(async) getAttribute(key) → {string}

- - - - - - -
- Get an attribute. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
key - - -string - - - - attribute to get the value of
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the attribute's value -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getBalance(accountIdx, subaddressIdx) → {BigInteger}

- - - - - - -
- Get the balance of the wallet, account, or subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the account to get the balance of (optional)
subaddressIdx - - -int - - - - index of the subaddress to get the balance of (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the balance of the wallet, account, or subaddress -
- - - -
-
- Type -
-
- -BigInteger - - -
-
- - - - - - - - - - - - - -

(async) getDaemonConnection() → {MoneroRpcConnection}

- - - - - - -
- Get the wallet's daemon connection. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's daemon connection -
- - - -
-
- Type -
-
- -MoneroRpcConnection - - -
-
- - - - - - - - - - - - - -

(async) getDaemonHeight() → {int}

- - - - - - -
- Get the blockchain's height. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the blockchain's height -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) getHeight() → {int}

- - - - - - -
- Get the height of the last block processed by the wallet (its index + 1). -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the height of the last block processed by the wallet -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) getHeightByDate(year, month, day)

- - - - - - -
- Get the blockchain's height by date as a conservative estimate for scanning. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
year - - -int - - - - year of the height to get
month - - -int - - - - month of the height to get as a number between 1 and 12
day - - -int - - - - day of the height to get as a number between 1 and 31
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the blockchain's approximate height at the given date -
- - - - - - - - - - - - - - - -

(async) getIncomingTransfers(query) → {Array.<MoneroIncomingTransfer>}

- - - - - - -
- Get all of the wallet's incoming transfers. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - passed to getTransfers() with isIncoming=true
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's incoming transfers -
- - - -
-
- Type -
-
- -Array.<MoneroIncomingTransfer> - - -
-
- - - - - - - - - - - - - -

(async) getIntegratedAddress(paymentId) → {MoneroIntegratedAddress}

- - - - - - -
- Get an integrated address based on this wallet's primary address and the -given payment ID. Generates a random payment ID if none is given. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
paymentId - - -string - - - - payment ID to generate an integrated address from (randomly generated if undefined)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the integrated address -
- - - -
-
- Type -
-
- -MoneroIntegratedAddress - - -
-
- - - - - - - - - - - - - -

(async) getKeyImages() → {Array.<MoneroKeyImage>}

- - - - - - -
- Get all signed key images. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's signed key images -
- - - -
-
- Type -
-
- -Array.<MoneroKeyImage> - - -
-
- - - - - - - - - - - - - -

(async) getMnemonic() → {string}

- - - - - - -
- Get the wallet's mnemonic phrase derived from the seed. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's mnemonic phrase -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getMnemonicLanguage() → {string}

- - - - - - -
- Get the language of the wallet's mnemonic phrase. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the language of the wallet's mnemonic phrase -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getMnemonicLanguages() → {Array.<string>}

- - - - - - -
- Get a list of available languages for the wallet's mnemonic phrase. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the available languages for the wallet's mnemonic phrase -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) getMultisigHex() → {string}

- - - - - - -
- Export this wallet's multisig info as hex for other participants. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- this wallet's multisig info as hex for other participants -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getMultisigInfo() → {MoneroMultisigInfo}

- - - - - - -
- Get multisig info about this wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- multisig info about this wallet -
- - - -
-
- Type -
-
- -MoneroMultisigInfo - - -
-
- - - - - - - - - - - - - -

(async) getNewKeyImagesFromLastImport() → {Array.<MoneroKeyImage>}

- - - - - - -
- Get new key images from the last imported outputs. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the key images from the last imported outputs -
- - - -
-
- Type -
-
- -Array.<MoneroKeyImage> - - -
-
- - - - - - - - - - - - - -

(async) getOutgoingTransfers(query) → {Array.<MoneroOutgoingTransfer>}

- - - - - - -
- Get all of the wallet's outgoing transfers. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - passed to getTransfers() with isOutgoing=true
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's outgoing transfers -
- - - -
-
- Type -
-
- -Array.<MoneroOutgoingTransfer> - - -
-
- - - - - - - - - - - - - -

(async) getOutputs(query) → {Array.<MoneroOutputWallet>}

- - - - - - -
-

Get outputs created from previous transactions that belong to the wallet -(i.e. that the wallet can spend one time). Outputs are part of -transactions which are stored in blocks on the blockchain.

- -

Results can be filtered by passing a query object. Outputs must -meet every criteria defined in the query in order to be returned. All -filtering is optional and no filtering is applied when not defined.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - -MoneroOutputQuery -| - -object - - - - configures the query (optional) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIndex - - -int - - - - get outputs associated with a specific account index (optional)
subaddressIndex - - -int - - - - get outputs associated with a specific subaddress index (optional)
subaddressIndices - - -Array.<int> - - - - get outputs associated with specific subaddress indices (optional)
amount - - -BigInteger - - - - get outputs with a specific amount (optional)
minAmount - - -BigInteger - - - - get outputs greater than or equal to a minimum amount (optional)
maxAmount - - -BigInteger - - - - get outputs less than or equal to a maximum amount (optional)
isSpent - - -boolean - - - - get outputs that are spent or not (optional)
keyImage - - -string -| - -MoneroKeyImage - - - - get output with a key image or which matches fields defined in a MoneroKeyImage (optional)
txQuery - - -MoneroTxQuery - - - - get outputs whose transaction meets this filter (optional)
- -
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are queried outputs -
- - - -
-
- Type -
-
- -Array.<MoneroOutputWallet> - - -
-
- - - - - - - - - - - - - -

(async) getOutputsHex() → {string}

- - - - - - -
- Export all outputs in hex format. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- all outputs in hex format, undefined if no outputs -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPath() → {string}

- - - - - - -
- Get the wallet's path. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the path the wallet can be opened with -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPrivateSpendKey() → {string}

- - - - - - -
- Get the wallet's private spend key. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's private spend key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPrivateViewKey() → {string}

- - - - - - -
- Get the wallet's private view key. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's private view key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getReserveProofAccount(accountIdx, amount, message) → {string}

- - - - - - -
- Generate a signature to prove an available amount in an account. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - account to prove ownership of the amount
amount - - -BigInteger - - - - minimum amount to prove as available in the account
message - - -string - - - - message to include with the signature to further authenticate the proof (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the reserve proof signature -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getReserveProofWallet(message)

- - - - - - -
- Generate a signature to prove the entire balance of the wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
message - - message included with the signature to further authenticate the proof (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the reserve proof signature -
- - - - - - - - - - - - - - - -

(async) getRpcConnection() → {MoneroWalletRpc}

- - - - - - -
- Get the wallet's RPC connection. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's rpc connection -
- - - -
-
- Type -
-
- -MoneroWalletRpc - - -
-
- - - - - - - - - - - - - -

(async) getSpendProof(txHash, message) → {string}

- - - - - - -
- Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to prove
message - - -string - - - - message to include with the signature to further authenticate the proof (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the transaction signature -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getSubaddress(accountIdx, subaddressIdx) → {MoneroSubaddress}

- - - - - - -
- Get a subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the subaddress's account
subaddressIdx - - -int - - - - index of the subaddress within the account
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the retrieved subaddress -
- - - -
-
- Type -
-
- -MoneroSubaddress - - -
-
- - - - - - - - - - - - - -

(async) getSubaddresses(accountIdx, subaddressIndices) → {Array.<MoneroSubaddress>}

- - - - - - -
- Get subaddresses in an account. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - account to get subaddresses within
subaddressIndices - - -Array.<int> - - - - indices of subaddresses to get (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the retrieved subaddresses -
- - - -
-
- Type -
-
- -Array.<MoneroSubaddress> - - -
-
- - - - - - - - - - - - - -

(async) getTransfers(query) → {Array.<MoneroTransfer>}

- - - - - - -
-

Get incoming and outgoing transfers to and from this wallet. An outgoing -transfer represents a total amount sent from one or more subaddresses -within an account to individual destination addresses, each with their -own amount. An incoming transfer represents a total amount received into -a subaddress within an account. Transfers belong to transactions which -are stored on the blockchain.

- -

Results can be filtered by passing a query object. Transfers must -meet every criteria defined in the query in order to be returned. All -criteria are optional and no filtering is applied when not defined.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - -MoneroTransferQuery -| - -object - - - - configures the query (optional) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
isOutgoing - - -boolean - - - - get transfers that are outgoing or not (optional)
isIncoming - - -boolean - - - - get transfers that are incoming or not (optional)
address - - -string - - - - wallet's address that a transfer either originated from (if outgoing) or is destined for (if incoming) (optional)
accountIndex - - -int - - - - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific account index (optional)
subaddressIndex - - -int - - - - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific subaddress index (optional)
subaddressIndices - - -Array.<int> - - - - get transfers that either originated from (if outgoing) or are destined for (if incoming) specific subaddress indices (optional)
amount - - -BigInteger - - - - amount being transferred (optional)
destinations - - -Array.<MoneroDestination> - - - - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional)
hasDestinations - - -boolean - - - - get transfers that have destinations or not (optional)
txQuery - - -MoneroTxQuery - - - - get transfers whose transaction meets this query (optional)
- -
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are wallet transfers per the configuration -
- - - -
-
- Type -
-
- -Array.<MoneroTransfer> - - -
-
- - - - - - - - - - - - - -

(async) getTx(txHash) → {MoneroTxWallet}

- - - - - - -
- Get a wallet transaction by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - hash of a transaction to get
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the identified transactions -
- - - -
-
- Type -
-
- -MoneroTxWallet - - -
-
- - - - - - - - - - - - - -

(async) getTxKey(txHash) → {string}

- - - - - - -
- Get a transaction's secret key from its hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction's hash
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- - transaction's secret key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getTxNote(txHash) → {string}

- - - - - - -
- Get a transaction note. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to get the note of
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the tx note -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getTxNotes(txHashes) → {Array.<string>}

- - - - - - -
- Get notes for multiple transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHashes - - -Array.<string> - - - - hashes of the transactions to get notes for
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- notes for the transactions -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) getTxProof(txHash, address, message) → {string}

- - - - - - -
- Get a transaction signature to prove it. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to prove
address - - -string - - - - destination public address of the transaction
message - - -string - - - - message to include with the signature to further authenticate the proof (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the transaction signature -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getTxs(query, missingTxHashes) → {Array.<MoneroTxWallet>}

- - - - - - -
-

Get wallet transactions. Wallet transactions contain one or more -transfers that are either incoming or outgoing to the wallet.

- -

Results can be filtered by passing a query object. Transactions must -meet every criteria defined in the query in order to be returned. All -criteria are optional and no filtering is applied when not defined.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - -MoneroTxQuery -| - -Array.<string> -| - -object - - - - configures the query (optional) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
isConfirmed - - -boolean - - - - get txs that are confirmed or not (optional)
inTxPool - - -boolean - - - - get txs that are in the tx pool or not (optional)
isRelayed - - -boolean - - - - get txs that are relayed or not (optional)
isFailed - - -boolean - - - - get txs that are failed or not (optional)
isMinerTx - - -boolean - - - - get miner txs or not (optional)
hash - - -string - - - - get a tx with the hash (optional)
hashes - - -Array.<string> - - - - get txs with the hashes (optional)
paymentId - - -string - - - - get transactions with the payment id (optional)
paymentIds - - -Array.<string> - - - - get transactions with the payment ids (optional)
hasPaymentId - - -boolean - - - - get transactions with a payment id or not (optional)
minHeight - - -int - - - - get txs with height >= the given height (optional)
maxHeight - - -int - - - - get txs with height <= the given height (optional)
isOutgoing - - -boolean - - - - get txs with an outgoing transfer or not (optional)
isIncoming - - -boolean - - - - get txs with an incoming transfer or not (optional)
transferQuery - - -MoneroTransferQuery - - - - get txs that have a transfer that meets this query (optional)
includeOutputs - - -boolean - - - - specifies that tx outputs should be returned with tx results (optional)
- -
missingTxHashes - - -Array.<string> - - - - populated with hashes of unfound or unmet transactions that were queried by hash (throws error if undefined and queried transaction hashes are unfound or unmet)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- wallet transactions per the configuration -
- - - -
-
- Type -
-
- -Array.<MoneroTxWallet> - - -
-
- - - - - - - - - - - - - -

(async) getUnlockedBalance(accountIdx, subaddressIdx) → {BigInteger}

- - - - - - -
- Get the unlocked balance of the wallet, account, or subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the account to get the unlocked balance of (optional)
subaddressIdx - - -int - - - - index of the subaddress to get the unlocked balance of (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the unlocked balance of the wallet, account, or subaddress -
- - - -
-
- Type -
-
- -BigInteger - - -
-
- - - - - - - - - - - - - -

(async) getVersion() → {MoneroVersion}

- - - - - - -
- Gets the version of the wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the version of the wallet -
- - - -
-
- Type -
-
- -MoneroVersion - - -
-
- - - - - - - - - - - - - -

(async) importKeyImages(keyImages) → {MoneroKeyImageImportResult}

- - - - - - -
- Import signed key images and verify their spent status. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyImages - - -Array.<MoneroKeyImage> - - - - images to import and verify (requires hex and signature)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- results of the import -
- - - -
-
- Type -
-
- -MoneroKeyImageImportResult - - -
-
- - - - - - - - - - - - - -

(async) importMultisigHex(multisigHexes) → {int}

- - - - - - -
- Import multisig info as hex from other participants. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
multisigHexes - - -Array.<string> - - - - multisig hex from each participant
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the number of outputs signed with the given multisig hex -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) importOutputsHex(outputsHex) → {int}

- - - - - - -
- Import outputs in hex format. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
outputsHex - - -string - - - - outputs in hex format
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the number of outputs imported -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) isClosed() → {boolean}

- - - - - - -
- Indicates if this wallet is closed or not. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is closed, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isConnected() → {boolean}

- - - - - - -
- Indicates if the wallet is connected to daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is connected to a daemon, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isMultisigImportNeeded() → {boolean}

- - - - - - -
- Indicates if importing multisig data is needed for returning a correct balance. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if importing multisig data is needed for returning a correct balance, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isViewOnly() → {bool}

- - - - - - -
- Indicates if the wallet is view-only, meaning it does have the private -spend key and can therefore only observe incoming outputs. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is view-only, false otherwise -
- - - -
-
- Type -
-
- -bool - - -
-
- - - - - - - - - - - - - -

(async) makeMultisig(multisigHexes, threshold, password) → {MoneroMultisigInitResult}

- - - - - - -
- Make this wallet multisig by importing multisig hex from participants. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
multisigHexes - - -Array.<String> - - - - multisig hex from each participant
threshold - - -int - - - - number of signatures needed to sign transfers
password - - -string - - - - wallet password
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not N/N -
- - - -
-
- Type -
-
- -MoneroMultisigInitResult - - -
-
- - - - - - - - - - - - - -

(async) openWallet(pathOrConfig, password)

- - - - - - -
-

Open an existing wallet on the monero-wallet-rpc server.

- -

Example:

- - -let wallet = new MoneroWalletRpc("http://localhost:38083", "rpc_user", "abc123");
-await wallet.openWallet("mywallet1", "supersecretpassword");
-await wallet.openWallet({
-   path: "mywallet2",
-   password: "supersecretpassword",
-   serverUri: "http://locahost:38081",
-   rejectUnauthorized: false
-});
-
-

- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
pathOrConfig - - -string -| - -object -| - -MoneroWalletConfig - - - - the wallet's name or configuration to open -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
path - - -string - - - - path of the wallet to create (optional, in-memory wallet if not given)
password - - -string - - - - password of the wallet to create
serverUri - - -string - - - - uri of a daemon to use (optional, monero-wallet-rpc usually started with daemon config)
serverUsername - - -string - - - - username to authenticate with the daemon (optional)
serverPassword - - -string - - - - password to authenticate with the daemon (optional)
rejectUnauthorized - - -boolean - - - - reject self-signed server certificates if true (defaults to true)
server - - -MoneroRpcConnection -| - -object - - - - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional)
- -
password - - -string - - - - is the wallet's password
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) parsePaymentUri(uri) → {MoneroTxConfig}

- - - - - - -
- Parses a payment URI to a tx config. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uri - - -string - - - - payment uri to parse
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the send configuration parsed from the uri -
- - - -
-
- Type -
-
- -MoneroTxConfig - - -
-
- - - - - - - - - - - - - -

(async) parseTxSet(txSet) → {MoneroTxSet}

- - - - - - -
- Parse a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txSet - - -MoneroTxSet - - - - a tx set containing unsigned or multisig tx hex
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the parsed tx set containing structured transactions -
- - - -
-
- Type -
-
- -MoneroTxSet - - -
-
- - - - - - - - - - - - - -

(async) prepareMultisig() → {string}

- - - - - - -
- Get multisig info as hex to share with participants to begin creating a -multisig wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- this wallet's multisig hex to share with participants -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) relayTx(txOrMetadata) → {string}

- - - - - - -
- Relay a previously created transaction. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txOrMetadata - - -MoneroTxWallet -| - -string - - - - transaction or its metadata to relay
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the hash of the relayed tx -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) relayTxs(txsOrMetadatas) → {Array.<string>}

- - - - - - -
- Relay previously created transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txsOrMetadatas - - -Array.<MoneroTxWallet> -| - -Array.<string> - - - - transactions or their metadata to relay
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the hashes of the relayed txs -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) rescanBlockchain()

- - - - - - -
-

Rescan the blockchain from scratch, losing any information which cannot be recovered from -the blockchain itself.

- -

WARNING: This method discards local wallet data like destination addresses, tx secret keys, -tx notes, etc.

-
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) rescanSpent()

- - - - - - -
-

Rescan the blockchain for spent outputs.

- -

Note: this can only be called with a trusted daemon.

- -

Example use case: peer multisig hex is import when connected to an untrusted daemon, -so the wallet will not rescan spent outputs. Then the wallet connects to a trusted -daemon. This method should be manually invoked to rescan outputs.

-
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) save()

- - - - - - -
- Save the wallet at its current path. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setAccountTagLabel(tag, label)

- - - - - - -
- Sets a human-readable description for a tag. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tag - - -string - - - - tag to set a description for
label - - -string - - - - label to set for the tag
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setAttribute(key, val)

- - - - - - -
- Set an arbitrary attribute. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
key - - -string - - - - attribute key
val - - -string - - - - attribute value
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setDaemonConnection(uriOrConnection, isTrusted, sslOptions)

- - - - - - -
- Set the wallet's daemon connection. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uriOrConnection - - -string -| - -MoneroRpcConnection - - - - the daemon's URI or connection (defaults to offline)
isTrusted - - -boolean - - - - indicates if the daemon in trusted
sslOptions - - -SslOptions - - - - custom SSL configuration
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setTxNote(txHash, note)

- - - - - - -
- Set a note for a specific transaction. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - hash of the transaction to set a note for
note - - -string - - - - the transaction note
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setTxNotes(txHashes, notes)

- - - - - - -
- Set notes for multiple transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHashes - - -Array.<string> - - - - transactions to set notes for
notes - - -Array.<string> - - - - notes to set for the transactions
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) signMessage(msg) → {string}

- - - - - - -
- Sign a message. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
msg - - -string - - - - message to sign
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the signature -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) signMultisigTxHex(multisigTxHex) → {MoneroMultisigSignResult}

- - - - - - -
- Sign multisig transactions from a multisig wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
multisigTxHex - - -string - - - - unsigned multisig transactions as hex
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result of signing the multisig transactions -
- - - -
-
- Type -
-
- -MoneroMultisigSignResult - - -
-
- - - - - - - - - - - - - -

(async) signTxs(unsignedTxHex) → {string}

- - - - - - -
- Sign unsigned transactions from a view-only wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
unsignedTxHex - - -string - - - - unsigned transaction hex from when the transactions were created
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the signed transaction hex -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) startMining(numThreads, backgroundMining, ignoreBattery)

- - - - - - -
- Start mining. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
numThreads - - -int - - - - number of threads created for mining (optional)
backgroundMining - - -boolean - - - - specifies if mining should occur in the background (optional)
ignoreBattery - - -boolean - - - - specifies if the battery should be ignored for mining (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) startSyncing()

- - - - - - -
- Start an asynchronous thread to continuously synchronize the wallet with the daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) stop()

- - - - - - -
- Save and close the current wallet and stop the RPC server. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) stopMining()

- - - - - - -
- Stop mining. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) submitMultisigTxHex(signedMultisigTxHex) → {Array.<string>}

- - - - - - -
- Submit signed multisig transactions from a multisig wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
signedMultisigTxHex - - -string - - - - signed multisig hex returned from signMultisigTxHex()
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the resulting transaction hashes -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) submitTxs(signedTxHex) → {Array.<string>}

- - - - - - -
- Submit signed transactions from a view-only wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
signedTxHex - - -string - - - - signed transaction hex from signTxs()
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the resulting transaction hashes -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) sweepDust(relay) → {Array.<MoneroTxWallet>}

- - - - - - -
-

Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

- -

NOTE: Dust only exists pre RCT, so this method will throw "no dust to sweep" on new wallets.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
relay - - -boolean - - - - specifies if the resulting transaction should be relayed (default false)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transactions -
- - - -
-
- Type -
-
- -Array.<MoneroTxWallet> - - -
-
- - - - - - - - - - - - - -

(async) sweepOutput(config) → {MoneroTxWallet}

- - - - - - -
- Sweep an output by key image. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig - - - - configures the transaction to create (required) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address (required)
keyImage - - -string - - - - key image to sweep (required)
relay - - -boolean - - - - relay the transaction to peers to commit to the blockchain (default false)
unlockHeight - - -int - - - - minimum height for the transaction to unlock (default 0)
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
- -
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transaction -
- - - -
-
- Type -
-
- -MoneroTxWallet - - -
-
- - - - - - - - - - - - - -

(async) sweepUnlocked(config) → {Array.<MoneroTxWallet>}

- - - - - - -
- Sweep all unlocked funds according to the given configuration. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig -| - -object - - - - configures the transactions to create (required) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address (required)
accountIndex - - -int - - - - source account index to sweep from from (required)
subaddressIndex - - -int - - - - source subaddress index to sweep from (optional)
subaddressIndices - - -Array.<int> - - - - source subaddress indices to sweep from (optional)
relay - - -boolean - - - - relay the transactions to peers to commit to the blockchain (default false)
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
unlockHeight - - -int - - - - minimum height for the transactions to unlock (default 0)
- -
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transactions -
- - - -
-
- Type -
-
- -Array.<MoneroTxWallet> - - -
-
- - - - - - - - - - - - - -

(async) sync(listenerOrStartHeight, startHeight)

- - - - - - -
- Synchronize the wallet with the daemon as a one-time synchronous process. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
listenerOrStartHeight - - -MoneroWalletListener -| - -number - - - - listener xor start height (defaults to no sync listener, the last synced block)
startHeight - - -number - - - - startHeight if not given in first arg (defaults to last synced block)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) tagAccounts(tag, accountIndices)

- - - - - - -
- Tag accounts. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tag - - -string - - - - tag to apply to the specified accounts
accountIndices - - -Array.<int> - - - - indices of the accounts to tag
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) untagAccounts(accountIndices)

- - - - - - -
- Untag accounts. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIndices - - -Array.<int> - - - - indices of the accounts to untag
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) verifyMessage(msg, address, signature) → {boolean}

- - - - - - -
- Verify a signature on a message. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
msg - - -string - - - - signed message
address - - -string - - - - signing address
signature - - -string - - - - signature
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the signature is good, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/MoneroWalletWasm.html b/docs/MoneroWalletWasm.html deleted file mode 100644 index f7bc1c797..000000000 --- a/docs/MoneroWalletWasm.html +++ /dev/null @@ -1,19977 +0,0 @@ - - - - - JSDoc: Class: MoneroWalletWasm - - - - - - - - - - -
- -

Class: MoneroWalletWasm

- - - - - - -
- -
- -

MoneroWalletWasm

- -
Implements a MoneroWallet using WebAssembly bindings to monero-project's wallet2.
- - -
- -
-
- - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - -

Extends

- - - - - - - - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

(async, static) createWallet(config) → {MoneroWalletWasm}

- - - - - - -
-

Create a wallet using WebAssembly bindings to wallet2.h.

- -

Example:

- - -let wallet = await MoneroWalletWasm.createWallet({
-   path: "./test_wallets/wallet1", // leave blank for in-memory wallet
-   password: "supersecretpassword",
-   networkType: MoneroNetworkType.STAGENET,
-   mnemonic: "coexist igloo pamphlet lagoon...",
-   restoreHeight: 1543218,
-   server: new MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123"),
-}); -
-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -object -| - -MoneroWalletConfig - - - - MoneroWalletConfig or equivalent config object -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
path - - -string - - - - path of the wallet to create (optional, in-memory wallet if not given)
password - - -string - - - - password of the wallet to create
networkType - - -string -| - -number - - - - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
mnemonic - - -string - - - - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)
seedOffset - - -string - - - - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase
primaryAddress - - -string - - - - primary address of the wallet to create (only provide if restoring from keys)
privateViewKey - - -string - - - - private view key of the wallet to create (optional)
privateSpendKey - - -string - - - - private spend key of the wallet to create (optional)
restoreHeight - - -number - - - - block height to start scanning from (defaults to 0 unless generating random wallet)
language - - -string - - - - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected)
serverUri - - -string - - - - uri of the wallet's daemon (optional)
serverUsername - - -string - - - - username to authenticate with the daemon (optional)
serverPassword - - -string - - - - password to authenticate with the daemon (optional)
rejectUnauthorized - - -boolean - - - - reject self-signed server certificates if true (defaults to true)
server - - -MoneroRpcConnection -| - -object - - - - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional)
proxyToWorker - - -boolean - - - - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)
fs - - -fs - - - - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created wallet -
- - - -
-
- Type -
-
- -MoneroWalletWasm - - -
-
- - - - - - - - - - - - - -

(async, static) getMnemonicLanguages()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async, static) openWallet(configOrPath, password, networkType, daemonUriOrConnection, proxyToWorker, fs) → {MoneroWalletWasm}

- - - - - - -
-

Open an existing wallet using WebAssembly bindings to wallet2.h.

- -

Examples:

- - -let wallet1 = await MoneroWalletWasm.openWallet(
-   "./wallets/wallet1",
-   "supersecretpassword",
-   MoneroNetworkType.STAGENET,
-   "http://localhost:38081" // daemon uri
-);

- -let wallet2 = await MoneroWalletWasm.openWallet({
-   path: "./wallets/wallet2",
-   password: "supersecretpassword",
-   networkType: MoneroNetworkType.STAGENET,
-   serverUri: "http://localhost:38081", // daemon configuration
-   serverUsername: "superuser",
-   serverPassword: "abctesting123"
-}); -
-

- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
configOrPath - - -MoneroWalletConfig -| - -object -| - -string - - - - MoneroWalletConfig or equivalent config object or a path to a wallet to open -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
path - - -string - - - - path of the wallet to open (optional if 'keysData' provided)
password - - -string - - - - password of the wallet to open
networkType - - -string -| - -number - - - - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
keysData - - -Uint8Array - - - - wallet keys data to open (optional if path provided)
cacheData - - -Uint8Array - - - - wallet cache data to open (optional)
serverUri - - -string - - - - uri of the wallet's daemon (optional)
serverUsername - - -string - - - - username to authenticate with the daemon (optional)
serverPassword - - -string - - - - password to authenticate with the daemon (optional)
rejectUnauthorized - - -boolean - - - - reject self-signed server certificates if true (defaults to true)
server - - -MoneroRpcConnection -| - -object - - - - MoneroRpcConnection or equivalent JS object configuring the daemon connection (optional)
proxyToWorker - - -boolean - - - - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)
fs - - -fs - - - - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
- -
password - - -string - - - - password of the wallet to open
networkType - - -string -| - -number - - - - network type of the wallet to open
daemonUriOrConnection - - -string -| - -MoneroRpcConnection - - - - daemon URI or MoneroRpcConnection
proxyToWorker - - -boolean - - - - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)
fs - - -fs - - - - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the opened wallet -
- - - -
-
- Type -
-
- -MoneroWalletWasm - - -
-
- - - - - - - - - - - - - -

(async, static) walletExists(path, fs) → {boolean}

- - - - - - -
- Check if a wallet exists at a given path. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
path - - -string - - - - path of the wallet on the file system
fs - - -fs - - - - Node.js compatible file system to use (optional, defaults to disk if nodejs)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if a wallet exists at the given path, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) addAddressBookEntry(address, description) → {int}

- - - - - - -
- Add an address book entry. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - entry address
description - - -string - - - - entry description (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the index of the added entry -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) addListener(listener)

- - - - - - -
- Register a listener to receive wallet notifications. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
listener - - -MoneroWalletListener - - - - listener to receive wallet notifications
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) checkReserveProof(address, message, signature) → {MoneroCheckReserve}

- - - - - - -
- Proves a wallet has a disposable reserve using a signature. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - public wallet address
message - - -string - - - - message included with the signature to further authenticate the proof (optional)
signature - - -string - - - - reserve proof signature to check
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result of checking the signature proof -
- - - -
-
- Type -
-
- -MoneroCheckReserve - - -
-
- - - - - - - - - - - - - -

(async) checkSpendProof(txHash, message, signature) → {boolean}

- - - - - - -
- Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to prove
message - - -string - - - - message included with the signature to further authenticate the proof (optional)
signature - - -string - - - - transaction signature to confirm
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the signature is good, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) checkTxKey(txHash, txKey, address) → {MoneroCheckTx}

- - - - - - -
- Check a transaction in the blockchain with its secret key. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to check
txKey - - -string - - - - transaction's secret key
address - - -string - - - - destination public address of the transaction
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result of the check -
- - - -
-
- Type -
-
- -MoneroCheckTx - - -
-
- - - - - - - - - - - - - -

(async) checkTxProof(txHash, address, message, signature) → {MoneroCheckTx}

- - - - - - -
- Prove a transaction by checking its signature. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to prove
address - - -string - - - - destination public address of the transaction
message - - -string - - - - message included with the signature to further authenticate the proof (optional)
signature - - -string - - - - transaction signature to confirm
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result of the check -
- - - -
-
- Type -
-
- -MoneroCheckTx - - -
-
- - - - - - - - - - - - - -

(async) close(save)

- - - - - - -
- Optionally save then close the wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
save - - -boolean - - - - specifies if the wallet should be saved before being closed (default false)
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) createAccount(label) → {MoneroAccount}

- - - - - - -
- Create a new account with a label for the first subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
label - - -string - - - - label for account's first subaddress (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created account -
- - - -
-
- Type -
-
- -MoneroAccount - - -
-
- - - - - - - - - - - - - -

(async) createPaymentUri(config) → {string}

- - - - - - -
- Creates a payment URI from a send configuration. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig - - - - specifies configuration for a potential tx
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the payment uri -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) createSubaddress(accountIdx, label) → {MoneroSubaddress}

- - - - - - -
- Create a subaddress within an account. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the account to create the subaddress within
label - - -string - - - - the label for the subaddress (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created subaddress -
- - - -
-
- Type -
-
- -MoneroSubaddress - - -
-
- - - - - - - - - - - - - -

(async) createTx(config) → {MoneroTxWallet}

- - - - - - -
- Create a transaction to transfer funds from this wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig -| - -object - - - - configures the transaction to create (required) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address (required unless `destinations` provided)
amount - - -BigInteger -| - -string - - - - single destination amount (required unless `destinations` provided)
accountIndex - - -int - - - - source account index to transfer funds from (required)
subaddressIndex - - -int - - - - source subaddress index to transfer funds from (optional)
subaddressIndices - - -Array.<int> - - - - source subaddress indices to transfer funds from (optional)
relay - - -boolean - - - - relay the transaction to peers to commit to the blockchain (default false)
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
destinations - - -Array.<MoneroDestination> - - - - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided)
paymentId - - -string - - - - transaction payment ID (optional)
unlockHeight - - -int - - - - minimum height for the transaction to unlock (default 0)
- -
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transaction -
- - - -
-
- Type -
-
- -MoneroTxWallet - - -
-
- - - - - - - - - - - - - -

(async) createTxs(config) → {Array.<MoneroTxWallet>}

- - - - - - -
- Create one or more transactions to transfer funds from this wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig -| - -object - - - - configures the transactions to create (required) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address (required unless `destinations` provided)
amount - - -BigInteger -| - -string - - - - single destination amount (required unless `destinations` provided)
accountIndex - - -int - - - - source account index to transfer funds from (required)
subaddressIndex - - -int - - - - source subaddress index to transfer funds from (optional)
subaddressIndices - - -Array.<int> - - - - source subaddress indices to transfer funds from (optional)
relay - - -boolean - - - - relay the transactions to peers to commit to the blockchain (default false)
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
destinations - - -Array.<MoneroDestination> - - - - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided)
paymentId - - -string - - - - transaction payment ID (optional)
unlockHeight - - -int - - - - minimum height for the transactions to unlock (default 0)
canSplit - - -boolean - - - - allow funds to be transferred using multiple transactions (default true)
- -
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transactions -
- - - -
-
- Type -
-
- -Array.<MoneroTxWallet> - - -
-
- - - - - - - - - - - - - -

(async) decodeIntegratedAddress(integratedAddress) → {MoneroIntegratedAddress}

- - - - - - -
- Decode an integrated address to get its standard address and payment id. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
integratedAddress - - -string - - - - integrated address to decode
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the decoded integrated address including standard address and payment id -
- - - -
-
- Type -
-
- -MoneroIntegratedAddress - - -
-
- - - - - - - - - - - - - -

(async) deleteAddressBookEntry(entryIdx)

- - - - - - -
- Delete an address book entry. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
entryIdx - - -int - - - - index of the entry to delete
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) editAddressBookEntry(index, setAddress, address, setDescription, description)

- - - - - - -
- Edit an address book entry. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
index - - -number - - - - index of the address book entry to edit
setAddress - - -boolean - - - - specifies if the address should be updated
address - - -string - - - - updated address
setDescription - - -boolean - - - - specifies if the description should be updated
description - - -string - - - - updated description
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) exchangeMultisigKeys(multisigHexes, password) → {MoneroMultisigInitResult}

- - - - - - -
- Exchange multisig hex with participants in a M/N multisig wallet. - -This process must be repeated with participants exactly N-M times. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
multisigHexes - - -Array.<string> - - - - are multisig hex from each participant
password - - -string - - - - wallet's password // TODO monero core: redundant? wallet is created with password
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done -
- - - -
-
- Type -
-
- -MoneroMultisigInitResult - - -
-
- - - - - - - - - - - - - -

(async) getAccount(accountIdx, includeSubaddresses) → {MoneroAccount}

- - - - - - -
- Get an account. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the account to get
includeSubaddresses - - -boolean - - - - include subaddresses if true
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the retrieved account -
- - - -
-
- Type -
-
- -MoneroAccount - - -
-
- - - - - - - - - - - - - -

(async) getAccounts(includeSubaddresses, tag) → {Array.<MoneroAccount>}

- - - - - - -
- Get accounts with a given tag. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
includeSubaddresses - - -boolean - - - - include subaddresses if true
tag - - -string - - - - tag for filtering accounts, all accounts if undefined
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- all accounts with the given tag -
- - - -
-
- Type -
-
- -Array.<MoneroAccount> - - -
-
- - - - - - - - - - - - - -

(async) getAccountTags() → {Array.<MoneroAccountTag>}

- - - - - - -
- Return all account tags. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's account tags -
- - - -
-
- Type -
-
- -Array.<MoneroAccountTag> - - -
-
- - - - - - - - - - - - - -

(async) getAddress(accountIdx, subaddressIdx) → {string}

- - - - - - -
- Get the address of a specific subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - the account index of the address's subaddress
subaddressIdx - - -int - - - - the subaddress index within the account
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the receive address of the specified subaddress -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getAddressBookEntries(entryIndices) → {Array.<MoneroAddressBookEntry>}

- - - - - - -
- Get address book entries. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
entryIndices - - -Array.<int> - - - - indices of the entries to get
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the address book entries -
- - - -
-
- Type -
-
- -Array.<MoneroAddressBookEntry> - - -
-
- - - - - - - - - - - - - -

(async) getAddressIndex(address) → {MoneroSubaddress}

- - - - - - -
- Get the account and subaddress index of the given address. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - address to get the account and subaddress index from
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the account and subaddress indices -
- - - -
-
- Type -
-
- -MoneroSubaddress - - -
-
- - - - - - - - - - - - - -

(async) getAttribute(key) → {string}

- - - - - - -
- Get an attribute. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
key - - -string - - - - attribute to get the value of
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the attribute's value -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getBalance(accountIdx, subaddressIdx) → {BigInteger}

- - - - - - -
- Get the balance of the wallet, account, or subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the account to get the balance of (optional)
subaddressIdx - - -int - - - - index of the subaddress to get the balance of (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the balance of the wallet, account, or subaddress -
- - - -
-
- Type -
-
- -BigInteger - - -
-
- - - - - - - - - - - - - -

(async) getDaemonConnection() → {MoneroRpcConnection}

- - - - - - -
- Get the wallet's daemon connection. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's daemon connection -
- - - -
-
- Type -
-
- -MoneroRpcConnection - - -
-
- - - - - - - - - - - - - -

(async) getDaemonHeight() → {int}

- - - - - - -
- Get the blockchain's height. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the blockchain's height -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) getDaemonMaxPeerHeight() → {number}

- - - - - - -
- Get the maximum height of the peers the wallet's daemon is connected to. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the maximum height of the peers the wallet's daemon is connected to -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

(async) getData() → {Array.<DataView>}

- - - - - - -
- Get the wallet's keys and cache data. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- is the keys and cache data respectively -
- - - -
-
- Type -
-
- -Array.<DataView> - - -
-
- - - - - - - - - - - - - -

(async) getHeight() → {int}

- - - - - - -
- Get the height of the last block processed by the wallet (its index + 1). -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the height of the last block processed by the wallet -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) getHeightByDate(year, month, day)

- - - - - - -
- Get the blockchain's height by date as a conservative estimate for scanning. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
year - - -int - - - - year of the height to get
month - - -int - - - - month of the height to get as a number between 1 and 12
day - - -int - - - - day of the height to get as a number between 1 and 31
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the blockchain's approximate height at the given date -
- - - - - - - - - - - - - - - -

(async) getIncomingTransfers(query) → {Array.<MoneroIncomingTransfer>}

- - - - - - -
- Get all of the wallet's incoming transfers. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - passed to getTransfers() with isIncoming=true
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's incoming transfers -
- - - -
-
- Type -
-
- -Array.<MoneroIncomingTransfer> - - -
-
- - - - - - - - - - - - - -

(async) getIntegratedAddress(paymentId) → {MoneroIntegratedAddress}

- - - - - - -
- Get an integrated address based on this wallet's primary address and the -given payment ID. Generates a random payment ID if none is given. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
paymentId - - -string - - - - payment ID to generate an integrated address from (randomly generated if undefined)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the integrated address -
- - - -
-
- Type -
-
- -MoneroIntegratedAddress - - -
-
- - - - - - - - - - - - - -

(async) getKeyImages() → {Array.<MoneroKeyImage>}

- - - - - - -
- Get all signed key images. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's signed key images -
- - - -
-
- Type -
-
- -Array.<MoneroKeyImage> - - -
-
- - - - - - - - - - - - - -

getListeners() → {Array.<MoneroWalletListener>}

- - - - - - -
- Get the listeners registered with the wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the registered listeners -
- - - -
-
- Type -
-
- -Array.<MoneroWalletListener> - - -
-
- - - - - - - - - - - - - -

(async) getMnemonic() → {string}

- - - - - - -
- Get the wallet's mnemonic phrase derived from the seed. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's mnemonic phrase -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getMnemonicLanguage() → {string}

- - - - - - -
- Get the language of the wallet's mnemonic phrase. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the language of the wallet's mnemonic phrase -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getMultisigHex() → {string}

- - - - - - -
- Export this wallet's multisig info as hex for other participants. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- this wallet's multisig info as hex for other participants -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getMultisigInfo() → {MoneroMultisigInfo}

- - - - - - -
- Get multisig info about this wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- multisig info about this wallet -
- - - -
-
- Type -
-
- -MoneroMultisigInfo - - -
-
- - - - - - - - - - - - - -

(async) getNetworkType() → {MoneroNetworkType}

- - - - - - -
- Get the wallet's network type (mainnet, testnet, or stagenet). -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's network type -
- - - -
-
- Type -
-
- -MoneroNetworkType - - -
-
- - - - - - - - - - - - - -

(async) getNewKeyImagesFromLastImport() → {Array.<MoneroKeyImage>}

- - - - - - -
- Get new key images from the last imported outputs. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the key images from the last imported outputs -
- - - -
-
- Type -
-
- -Array.<MoneroKeyImage> - - -
-
- - - - - - - - - - - - - -

(async) getOutgoingTransfers(query) → {Array.<MoneroOutgoingTransfer>}

- - - - - - -
- Get all of the wallet's outgoing transfers. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - passed to getTransfers() with isOutgoing=true
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's outgoing transfers -
- - - -
-
- Type -
-
- -Array.<MoneroOutgoingTransfer> - - -
-
- - - - - - - - - - - - - -

(async) getOutputs(query) → {Array.<MoneroOutputWallet>}

- - - - - - -
-

Get outputs created from previous transactions that belong to the wallet -(i.e. that the wallet can spend one time). Outputs are part of -transactions which are stored in blocks on the blockchain.

- -

Results can be filtered by passing a query object. Outputs must -meet every criteria defined in the query in order to be returned. All -filtering is optional and no filtering is applied when not defined.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - -MoneroOutputQuery -| - -object - - - - configures the query (optional) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIndex - - -int - - - - get outputs associated with a specific account index (optional)
subaddressIndex - - -int - - - - get outputs associated with a specific subaddress index (optional)
subaddressIndices - - -Array.<int> - - - - get outputs associated with specific subaddress indices (optional)
amount - - -BigInteger - - - - get outputs with a specific amount (optional)
minAmount - - -BigInteger - - - - get outputs greater than or equal to a minimum amount (optional)
maxAmount - - -BigInteger - - - - get outputs less than or equal to a maximum amount (optional)
isSpent - - -boolean - - - - get outputs that are spent or not (optional)
keyImage - - -string -| - -MoneroKeyImage - - - - get output with a key image or which matches fields defined in a MoneroKeyImage (optional)
txQuery - - -MoneroTxQuery - - - - get outputs whose transaction meets this filter (optional)
- -
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are queried outputs -
- - - -
-
- Type -
-
- -Array.<MoneroOutputWallet> - - -
-
- - - - - - - - - - - - - -

(async) getOutputsHex() → {string}

- - - - - - -
- Export all outputs in hex format. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- all outputs in hex format, undefined if no outputs -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPath() → {string}

- - - - - - -
- Get the wallet's path. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
  • - MoneroWalletKeys#getPath -
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the path the wallet can be opened with -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPrimaryAddress() → {string}

- - - - - - -
- Get the wallet's primary address. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's primary address -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPrivateSpendKey() → {string}

- - - - - - -
- Get the wallet's private spend key. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's private spend key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPrivateViewKey() → {string}

- - - - - - -
- Get the wallet's private view key. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's private view key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPublicSpendKey() → {string}

- - - - - - -
- Get the wallet's public spend key. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's public spend key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getPublicViewKey() → {string}

- - - - - - -
- Get the wallet's public view key. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet's public view key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getReserveProofAccount(accountIdx, amount, message) → {string}

- - - - - - -
- Generate a signature to prove an available amount in an account. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - account to prove ownership of the amount
amount - - -BigInteger - - - - minimum amount to prove as available in the account
message - - -string - - - - message to include with the signature to further authenticate the proof (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the reserve proof signature -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getReserveProofWallet(message)

- - - - - - -
- Generate a signature to prove the entire balance of the wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
message - - message included with the signature to further authenticate the proof (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the reserve proof signature -
- - - - - - - - - - - - - - - -

(async) getSpendProof(txHash, message) → {string}

- - - - - - -
- Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to prove
message - - -string - - - - message to include with the signature to further authenticate the proof (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the transaction signature -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getSubaddress(accountIdx, subaddressIdx) → {MoneroSubaddress}

- - - - - - -
- Get a subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the subaddress's account
subaddressIdx - - -int - - - - index of the subaddress within the account
- - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the retrieved subaddress -
- - - -
-
- Type -
-
- -MoneroSubaddress - - -
-
- - - - - - - - - - - - - -

(async) getSubaddresses(accountIdx, subaddressIndices) → {Array.<MoneroSubaddress>}

- - - - - - -
- Get subaddresses in an account. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - account to get subaddresses within
subaddressIndices - - -Array.<int> - - - - indices of subaddresses to get (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the retrieved subaddresses -
- - - -
-
- Type -
-
- -Array.<MoneroSubaddress> - - -
-
- - - - - - - - - - - - - -

(async) getSyncHeight() → {number}

- - - - - - -
- Get the height of the first block that the wallet scans. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the height of the first block that the wallet scans -
- - - -
-
- Type -
-
- -number - - -
-
- - - - - - - - - - - - - -

(async) getTransfers(query) → {Array.<MoneroTransfer>}

- - - - - - -
-

Get incoming and outgoing transfers to and from this wallet. An outgoing -transfer represents a total amount sent from one or more subaddresses -within an account to individual destination addresses, each with their -own amount. An incoming transfer represents a total amount received into -a subaddress within an account. Transfers belong to transactions which -are stored on the blockchain.

- -

Results can be filtered by passing a query object. Transfers must -meet every criteria defined in the query in order to be returned. All -criteria are optional and no filtering is applied when not defined.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - -MoneroTransferQuery -| - -object - - - - configures the query (optional) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
isOutgoing - - -boolean - - - - get transfers that are outgoing or not (optional)
isIncoming - - -boolean - - - - get transfers that are incoming or not (optional)
address - - -string - - - - wallet's address that a transfer either originated from (if outgoing) or is destined for (if incoming) (optional)
accountIndex - - -int - - - - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific account index (optional)
subaddressIndex - - -int - - - - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific subaddress index (optional)
subaddressIndices - - -Array.<int> - - - - get transfers that either originated from (if outgoing) or are destined for (if incoming) specific subaddress indices (optional)
amount - - -BigInteger - - - - amount being transferred (optional)
destinations - - -Array.<MoneroDestination> - - - - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional)
hasDestinations - - -boolean - - - - get transfers that have destinations or not (optional)
txQuery - - -MoneroTxQuery - - - - get transfers whose transaction meets this query (optional)
- -
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- are wallet transfers per the configuration -
- - - -
-
- Type -
-
- -Array.<MoneroTransfer> - - -
-
- - - - - - - - - - - - - -

(async) getTx(txHash) → {MoneroTxWallet}

- - - - - - -
- Get a wallet transaction by hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - hash of a transaction to get
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the identified transactions -
- - - -
-
- Type -
-
- -MoneroTxWallet - - -
-
- - - - - - - - - - - - - -

(async) getTxKey(txHash) → {string}

- - - - - - -
- Get a transaction's secret key from its hash. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction's hash
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- - transaction's secret key -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getTxNote(txHash) → {string}

- - - - - - -
- Get a transaction note. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to get the note of
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the tx note -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getTxNotes(txHashes) → {Array.<string>}

- - - - - - -
- Get notes for multiple transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHashes - - -Array.<string> - - - - hashes of the transactions to get notes for
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- notes for the transactions -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) getTxProof(txHash, address, message) → {string}

- - - - - - -
- Get a transaction signature to prove it. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - transaction to prove
address - - -string - - - - destination public address of the transaction
message - - -string - - - - message to include with the signature to further authenticate the proof (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the transaction signature -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) getTxs(query, missingTxHashes) → {Array.<MoneroTxWallet>}

- - - - - - -
-

Get wallet transactions. Wallet transactions contain one or more -transfers that are either incoming or outgoing to the wallet.

- -

Results can be filtered by passing a query object. Transactions must -meet every criteria defined in the query in order to be returned. All -criteria are optional and no filtering is applied when not defined.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
query - - -MoneroTxQuery -| - -Array.<string> -| - -object - - - - configures the query (optional) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
isConfirmed - - -boolean - - - - get txs that are confirmed or not (optional)
inTxPool - - -boolean - - - - get txs that are in the tx pool or not (optional)
isRelayed - - -boolean - - - - get txs that are relayed or not (optional)
isFailed - - -boolean - - - - get txs that are failed or not (optional)
isMinerTx - - -boolean - - - - get miner txs or not (optional)
hash - - -string - - - - get a tx with the hash (optional)
hashes - - -Array.<string> - - - - get txs with the hashes (optional)
paymentId - - -string - - - - get transactions with the payment id (optional)
paymentIds - - -Array.<string> - - - - get transactions with the payment ids (optional)
hasPaymentId - - -boolean - - - - get transactions with a payment id or not (optional)
minHeight - - -int - - - - get txs with height >= the given height (optional)
maxHeight - - -int - - - - get txs with height <= the given height (optional)
isOutgoing - - -boolean - - - - get txs with an outgoing transfer or not (optional)
isIncoming - - -boolean - - - - get txs with an incoming transfer or not (optional)
transferQuery - - -MoneroTransferQuery - - - - get txs that have a transfer that meets this query (optional)
includeOutputs - - -boolean - - - - specifies that tx outputs should be returned with tx results (optional)
- -
missingTxHashes - - -Array.<string> - - - - populated with hashes of unfound or unmet transactions that were queried by hash (throws error if undefined and queried transaction hashes are unfound or unmet)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- wallet transactions per the configuration -
- - - -
-
- Type -
-
- -Array.<MoneroTxWallet> - - -
-
- - - - - - - - - - - - - -

(async) getUnlockedBalance(accountIdx, subaddressIdx) → {BigInteger}

- - - - - - -
- Get the unlocked balance of the wallet, account, or subaddress. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIdx - - -int - - - - index of the account to get the unlocked balance of (optional)
subaddressIdx - - -int - - - - index of the subaddress to get the unlocked balance of (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the unlocked balance of the wallet, account, or subaddress -
- - - -
-
- Type -
-
- -BigInteger - - -
-
- - - - - - - - - - - - - -

(async) getVersion() → {MoneroVersion}

- - - - - - -
- Gets the version of the wallet. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the version of the wallet -
- - - -
-
- Type -
-
- -MoneroVersion - - -
-
- - - - - - - - - - - - - -

(async) importKeyImages(keyImages) → {MoneroKeyImageImportResult}

- - - - - - -
- Import signed key images and verify their spent status. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
keyImages - - -Array.<MoneroKeyImage> - - - - images to import and verify (requires hex and signature)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- results of the import -
- - - -
-
- Type -
-
- -MoneroKeyImageImportResult - - -
-
- - - - - - - - - - - - - -

(async) importMultisigHex(multisigHexes) → {int}

- - - - - - -
- Import multisig info as hex from other participants. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
multisigHexes - - -Array.<string> - - - - multisig hex from each participant
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the number of outputs signed with the given multisig hex -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) importOutputsHex(outputsHex) → {int}

- - - - - - -
- Import outputs in hex format. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
outputsHex - - -string - - - - outputs in hex format
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the number of outputs imported -
- - - -
-
- Type -
-
- -int - - -
-
- - - - - - - - - - - - - -

(async) isClosed() → {boolean}

- - - - - - -
- Indicates if this wallet is closed or not. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is closed, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isConnected() → {boolean}

- - - - - - -
- Indicates if the wallet is connected to daemon. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is connected to a daemon, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isDaemonSynced() → {boolean}

- - - - - - -
- Indicates if the wallet's daemon is synced with the network. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the daemon is synced with the network, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isMultisig() → {boolean}

- - - - - - -
- Indicates if this wallet is a multisig wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if this is a multisig wallet, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isMultisigImportNeeded() → {boolean}

- - - - - - -
- Indicates if importing multisig data is needed for returning a correct balance. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if importing multisig data is needed for returning a correct balance, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isSynced() → {boolean}

- - - - - - -
- Indicates if the wallet is synced with the daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is synced with the daemon, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -

(async) isViewOnly() → {bool}

- - - - - - -
- Indicates if the wallet is view-only, meaning it does have the private -spend key and can therefore only observe incoming outputs. -
- - - - - - - - - - - - - -
- - - - - - - - -
Overrides:
-
- - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the wallet is view-only, false otherwise -
- - - -
-
- Type -
-
- -bool - - -
-
- - - - - - - - - - - - - -

(async) makeMultisig(multisigHexes, threshold, password) → {MoneroMultisigInitResult}

- - - - - - -
- Make this wallet multisig by importing multisig hex from participants. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
multisigHexes - - -Array.<String> - - - - multisig hex from each participant
threshold - - -int - - - - number of signatures needed to sign transfers
password - - -string - - - - wallet password
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not N/N -
- - - -
-
- Type -
-
- -MoneroMultisigInitResult - - -
-
- - - - - - - - - - - - - -

(async) moveTo(path, password)

- - - - - - -
- Move the wallet from its current path to the given path. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
path - - -string - - - - is the new wallet's path
password - - -string - - - - is the new wallet's password
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) parsePaymentUri(uri) → {MoneroTxConfig}

- - - - - - -
- Parses a payment URI to a tx config. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uri - - -string - - - - payment uri to parse
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the send configuration parsed from the uri -
- - - -
-
- Type -
-
- -MoneroTxConfig - - -
-
- - - - - - - - - - - - - -

(async) parseTxSet(txSet) → {MoneroTxSet}

- - - - - - -
- Parse a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txSet - - -MoneroTxSet - - - - a tx set containing unsigned or multisig tx hex
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the parsed tx set containing structured transactions -
- - - -
-
- Type -
-
- -MoneroTxSet - - -
-
- - - - - - - - - - - - - -

(async) prepareMultisig() → {string}

- - - - - - -
- Get multisig info as hex to share with participants to begin creating a -multisig wallet. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- this wallet's multisig hex to share with participants -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) relayTx(txOrMetadata) → {string}

- - - - - - -
- Relay a previously created transaction. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txOrMetadata - - -MoneroTxWallet -| - -string - - - - transaction or its metadata to relay
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the hash of the relayed tx -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) relayTxs(txsOrMetadatas) → {Array.<string>}

- - - - - - -
- Relay previously created transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txsOrMetadatas - - -Array.<MoneroTxWallet> -| - -Array.<string> - - - - transactions or their metadata to relay
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the hashes of the relayed txs -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) removeListener(listener)

- - - - - - -
- Unregister a listener to receive wallet notifications. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
listener - - -MoneroWalletListener - - - - listener to unregister
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) rescanBlockchain()

- - - - - - -
-

Rescan the blockchain from scratch, losing any information which cannot be recovered from -the blockchain itself.

- -

WARNING: This method discards local wallet data like destination addresses, tx secret keys, -tx notes, etc.

-
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) rescanSpent()

- - - - - - -
-

Rescan the blockchain for spent outputs.

- -

Note: this can only be called with a trusted daemon.

- -

Example use case: peer multisig hex is import when connected to an untrusted daemon, -so the wallet will not rescan spent outputs. Then the wallet connects to a trusted -daemon. This method should be manually invoked to rescan outputs.

-
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) save()

- - - - - - -
- Save the wallet at its current path. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setAccountTagLabel(tag, label)

- - - - - - -
- Sets a human-readable description for a tag. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tag - - -string - - - - tag to set a description for
label - - -string - - - - label to set for the tag
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setAttribute(key, val)

- - - - - - -
- Set an arbitrary attribute. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
key - - -string - - - - attribute key
val - - -string - - - - attribute value
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setDaemonConnection(uriOrConnection, username, password)

- - - - - - -
- Set the wallet's daemon connection. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uriOrConnection - - -string -| - -MoneroRpcConnection - - - - daemon's URI or connection (defaults to offline)
username - - -string - - - - username to authenticate with the daemon (optional)
password - - -string - - - - password to authenticate with the daemon (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setSyncHeight(syncHeight)

- - - - - - -
- Set the height of the first block that the wallet scans. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
syncHeight - - -number - - - - height of the first block that the wallet scans
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setTxNote(txHash, note)

- - - - - - -
- Set a note for a specific transaction. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHash - - -string - - - - hash of the transaction to set a note for
note - - -string - - - - the transaction note
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) setTxNotes(txHashes, notes)

- - - - - - -
- Set notes for multiple transactions. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
txHashes - - -Array.<string> - - - - transactions to set notes for
notes - - -Array.<string> - - - - notes to set for the transactions
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) signMessage(msg) → {string}

- - - - - - -
- Sign a message. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
msg - - -string - - - - message to sign
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the signature -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) signMultisigTxHex(multisigTxHex) → {MoneroMultisigSignResult}

- - - - - - -
- Sign multisig transactions from a multisig wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
multisigTxHex - - -string - - - - unsigned multisig transactions as hex
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the result of signing the multisig transactions -
- - - -
-
- Type -
-
- -MoneroMultisigSignResult - - -
-
- - - - - - - - - - - - - -

(async) signTxs(unsignedTxHex) → {string}

- - - - - - -
- Sign unsigned transactions from a view-only wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
unsignedTxHex - - -string - - - - unsigned transaction hex from when the transactions were created
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the signed transaction hex -
- - - -
-
- Type -
-
- -string - - -
-
- - - - - - - - - - - - - -

(async) startMining(numThreads, backgroundMining, ignoreBattery)

- - - - - - -
- Start mining. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
numThreads - - -int - - - - number of threads created for mining (optional)
backgroundMining - - -boolean - - - - specifies if mining should occur in the background (optional)
ignoreBattery - - -boolean - - - - specifies if the battery should be ignored for mining (optional)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) startSyncing()

- - - - - - -
- Start an asynchronous thread to continuously synchronize the wallet with the daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) stopMining()

- - - - - - -
- Stop mining. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) stopSyncing()

- - - - - - -
- Stop synchronizing the wallet with the daemon. -
- - - - - - - - - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) submitMultisigTxHex(signedMultisigTxHex) → {Array.<string>}

- - - - - - -
- Submit signed multisig transactions from a multisig wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
signedMultisigTxHex - - -string - - - - signed multisig hex returned from signMultisigTxHex()
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the resulting transaction hashes -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) submitTxs(signedTxHex) → {Array.<string>}

- - - - - - -
- Submit signed transactions from a view-only wallet. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
signedTxHex - - -string - - - - signed transaction hex from signTxs()
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the resulting transaction hashes -
- - - -
-
- Type -
-
- -Array.<string> - - -
-
- - - - - - - - - - - - - -

(async) sweepDust(relay) → {Array.<MoneroTxWallet>}

- - - - - - -
-

Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

- -

NOTE: Dust only exists pre RCT, so this method will throw "no dust to sweep" on new wallets.

-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
relay - - -boolean - - - - specifies if the resulting transaction should be relayed (default false)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transactions -
- - - -
-
- Type -
-
- -Array.<MoneroTxWallet> - - -
-
- - - - - - - - - - - - - -

(async) sweepOutput(config) → {MoneroTxWallet}

- - - - - - -
- Sweep an output by key image. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig - - - - configures the transaction to create (required) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address (required)
keyImage - - -string - - - - key image to sweep (required)
relay - - -boolean - - - - relay the transaction to peers to commit to the blockchain (default false)
unlockHeight - - -int - - - - minimum height for the transaction to unlock (default 0)
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
- -
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transaction -
- - - -
-
- Type -
-
- -MoneroTxWallet - - -
-
- - - - - - - - - - - - - -

(async) sweepUnlocked(config) → {Array.<MoneroTxWallet>}

- - - - - - -
- Sweep all unlocked funds according to the given configuration. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroTxConfig -| - -object - - - - configures the transactions to create (required) -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
address - - -string - - - - single destination address (required)
accountIndex - - -int - - - - source account index to sweep from from (required)
subaddressIndex - - -int - - - - source subaddress index to sweep from (optional)
subaddressIndices - - -Array.<int> - - - - source subaddress indices to sweep from (optional)
relay - - -boolean - - - - relay the transactions to peers to commit to the blockchain (default false)
priority - - -MoneroTxPriority - - - - transaction priority (default MoneroTxPriority.NORMAL)
unlockHeight - - -int - - - - minimum height for the transactions to unlock (default 0)
- -
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created transactions -
- - - -
-
- Type -
-
- -Array.<MoneroTxWallet> - - -
-
- - - - - - - - - - - - - -

(async) sync(listenerOrStartHeight, startHeight)

- - - - - - -
- Synchronize the wallet with the daemon as a one-time synchronous process. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
listenerOrStartHeight - - -MoneroWalletListener -| - -number - - - - listener xor start height (defaults to no sync listener, the last synced block)
startHeight - - -number - - - - startHeight if not given in first arg (defaults to last synced block)
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) tagAccounts(tag, accountIndices)

- - - - - - -
- Tag accounts. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
tag - - -string - - - - tag to apply to the specified accounts
accountIndices - - -Array.<int> - - - - indices of the accounts to tag
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) untagAccounts(accountIndices)

- - - - - - -
- Untag accounts. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
accountIndices - - -Array.<int> - - - - indices of the accounts to untag
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

(async) verifyMessage(msg, address, signature) → {boolean}

- - - - - - -
- Verify a signature on a message. -
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
msg - - -string - - - - signed message
address - - -string - - - - signing address
signature - - -string - - - - signature
- - - - - - -
- - - - - - - - - - - - -
Implements:
-
- - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- true if the signature is good, false otherwise -
- - - -
-
- Type -
-
- -boolean - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/SslOptions.html b/docs/SslOptions.html deleted file mode 100644 index daab2cc9e..000000000 --- a/docs/SslOptions.html +++ /dev/null @@ -1,1014 +0,0 @@ - - - - - JSDoc: Class: SslOptions - - - - - - - - - - -
- -

Class: SslOptions

- - - - - - -
- -
- -

SslOptions()

- -
SSL options for remote endpoints.
- - -
- -
-
- - - - -

Constructor

- - - -

new SslOptions()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

getAllowAnyCert()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getAllowedFingerprints()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getCertificateAuthorityFile()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getCertificatePath()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

getPrivateKeyPath()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAllowAnyCert()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setAllowedFingerprints()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCertificateAuthorityFile()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setCertificatePath()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -

setPrivateKeyPath()

- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/bounties.md b/docs/bounties.md new file mode 100644 index 000000000..430671620 --- /dev/null +++ b/docs/bounties.md @@ -0,0 +1,17 @@ +## Bounties + +Bounties are used to incentivize development and reward contributors. + +To receive a bounty, you agree to these conditions: + +- Your changes must follow the existing coding conventions. +- Bounties will be set and awarded in XMR. +- The issues eligible for a bounty are labelled '💰bounty' and have the amount of the bounty specified in the title in this form: `[$200]` if in dollars or `[1 XMR]` if in Monero. +- An issue is considered resolved when the patch(es) proposed by the contributor is/are merged in the appropriate repository according to terms of the issue. Pull requests to monero-project must be merged into the release branch to be considered final. +- The first person who resolves an issue in its entirety will receive the entire amount of the bounty. +- If the issue is resolved collaboratively by more than one person, the reward will be distributed among the contributors at our discretion. +- Let the Maintainers know if you intend to work on a bounty, so that the issue can be assigned to you. Being assigned to an issue doesn't make that issue resolvable only by the assignee. It's meant to avoid duplication of efforts and not to discourage collective works. +- After the issue is resolved, contact the maintainers and claim your bounty (remember to provide them with a Monero address). +- If the bounty is in dollars, the contributor will receive the amount in Monero according to the value of XMR at the moment the issue was practically resolved, so in the moment the maintainers accept the last patch resolving the issue. + +We want to keep the system simple and flexible, but we will add new rules or edit existing ones if necessary. diff --git a/docs/developer_guide/connection_manager.md b/docs/developer_guide/connection_manager.md new file mode 100644 index 000000000..002fb80df --- /dev/null +++ b/docs/developer_guide/connection_manager.md @@ -0,0 +1,57 @@ +# Connection Manager + +Wallets can connect to a single Monero daemon or use a connection manager to automatically select the best connection among multiple daemons. Using a connection manager, wallets can automatically switch to a better connection if the current connection becomes disconnected or slow. + +The following code demonstrates how to use monero-ts's connection manager to manage daemon or wallet RPC connections. + +See [MoneroConnectionManager](https://woodser.github.io/monero-ts/typedocs/classes/MoneroConnectionManager.html) or [TestMoneroConnectionManager.ts](https://github.com/woodser/monero-ts/blob/master/src/test/TestMoneroConnectionManager.ts) for more detail. + +```typescript +// import monero-ts (or import types individually) +import moneroTs from "monero-ts"; + +// create connection manager +let connectionManager = new moneroTs.MoneroConnectionManager(); + +// add managed connections with priorities +await connectionManager.addConnection({uri: "http://localhost:28081", priority: 1}); // use localhost as first priority +await connectionManager.addConnection("http://example.com"); // default priority is prioritized last + +// set current connection +await connectionManager.setConnection({uri: "http://foo.bar", username: "admin", password: "password"}); // connection is added if new + +// create or open wallet governed by connection manager +let walletFull = await moneroTs.createWalletFull({ + path: "sample_wallet_full", + password: "supersecretpassword123", + networkType: moneroTs.MoneroNetworkType.TESTNET, + seed: "hefty value scenic...", + restoreHeight: 573936, + connectionManager: connectionManager +}); + +// check connection status +await connectionManager.checkConnection(); + +// receive notifications of any changes to current connection +connectionManager.addListener(new class extends moneroTs.MoneroConnectionManagerListener { + async onConnectionChanged(connection: moneroTs.MoneroRpcConnection) { + console.log("Connection changed to: " + connection); + } +}); + +// check connections every 10 seconds (in order of priority) and switch to the best +connectionManager.startPolling(10000); + +// get best available connection in order of priority then response time +let bestConnection = await connectionManager.getBestAvailableConnection(); + +// check status of all connections +await connectionManager.checkConnections(); + +// get connections in order of current connection, online status from last check, priority, and name +let connections = connectionManager.getConnections(); + +// clear connection manager +await connectionManager.clear(); +``` \ No newline at end of file diff --git a/docs/developer_guide/creating_wallets.md b/docs/developer_guide/creating_wallets.md index 037c2c5d2..68cf026e0 100644 --- a/docs/developer_guide/creating_wallets.md +++ b/docs/developer_guide/creating_wallets.md @@ -10,21 +10,18 @@ Three types of wallets can be created: This example creates a client connected to monero-wallet-rpc then creates a wallet. -See [MoneroWalletRpc.createWallet()](https://moneroecosystem.org/monero-javascript/MoneroWalletRpc.html#createWallet) for all options. - -```javascript -// import library -let monerojs = require("monero-javascript"); +See [MoneroWalletRpc.createWallet()](https://woodser.github.io/monero-ts/typedocs/classes/MoneroWalletRpc.html#createWallet) for all options. +```typescript // create a client connected to monero-wallet-rpc -let walletRpc = monerojs.connectToWalletRpc("http://localhost:38081", "superuser", "abctesting123"); +let walletRpc = await moneroTs.connectToWalletRpc("http://localhost:38081", "superuser", "abctesting123"); // create a wallet on monero-wallet-rpc await walletRpc.createWallet({ path: "mywallet", password: "supersecretpassword", - mnemonic: "coexist igloo pamphlet lagoon...", - restoreHeight: 1543218l + seed: "coexist igloo pamphlet lagoon...", + restoreHeight: 1543218 }); ``` @@ -32,22 +29,21 @@ await walletRpc.createWallet({ This example creates a wallet using WebAssembly bindings to [wallet2.h](https://github.com/monero-project/monero/blob/master/src/wallet/wallet2.h). -See [MoneroWalletWasm.createWallet()](https://moneroecosystem.org/monero-javascript/MoneroWalletWasm.html#createWallet) for all options. - -```javascript -// import library -let monerojs = require("monero-javascript"); +See [MoneroWalletFull.createWallet()](https://woodser.github.io/monero-ts/typedocs/classes/MoneroWalletFull.html#createWallet) for all options. +```typescript // create wallet using WebAssembly -let wallet = await monerojs.createWalletWasm({ +let wallet = await moneroTs.createWalletFull({ path: "./test_wallets/wallet1", // leave blank for in-memory wallet password: "supersecretpassword", - networkType: "stagenet", - mnemonic: "coexist igloo pamphlet lagoon...", + networkType: moneroTs.MoneroNetworkType.STAGENET + seed: "coexist igloo pamphlet lagoon...", restoreHeight: 1543218, - serverUri: "http://localhost:38081", - serverUsername: "daemon_user", - serverPassword: "daemon_password_123" + server: { + uri: "http://localhost:38081", + username: "daemon_user", + password: "daemon_password_123" + } }); ``` @@ -55,16 +51,13 @@ let wallet = await monerojs.createWalletWasm({ This example creates a keys-only wallet using WebAssembly bindings to monero-project/monero. -See [MoneroWalletKeys.createWallet()](https://moneroecosystem.org/monero-javascript/MoneroWalletKeys.html#createWallet) for all options. - -```javascript -// import library -let monerojs = require("monero-javascript"); +See [MoneroWalletKeys.createWallet()](https://woodser.github.io/monero-ts/typedocs/classes/MoneroWalletKeys.html#createWallet) for all options. +```typescript // create keys-only wallet -let wallet = await monerojs.createWalletKeys({ +let wallet = await moneroTs.createWalletKeys({ password: "abc123", - networkType: MoneroNetworkType.STAGENET, - mnemonic: "coexist igloo pamphlet lagoon..." + networkType: moneroTs.MoneroNetworkType.STAGENET, + seed: "coexist igloo pamphlet lagoon..." }); ``` \ No newline at end of file diff --git a/docs/developer_guide/data_model.md b/docs/developer_guide/data_model.md index 9f8d0caae..cbcab3731 100644 --- a/docs/developer_guide/data_model.md +++ b/docs/developer_guide/data_model.md @@ -2,11 +2,11 @@ ## Overview -This section introduces the data model used in monero-javascript. Refer to the [API specification](https://moneroecosystem.org/monero-java/monero-spec.pdf) or [JSDocs](https://moneroecosystem.org/monero-javascript/MoneroTxWallet.html) for more information. +This section introduces the data model used in monero-ts. Refer to the [API specification](https://woodser.github.io/monero-java/monero-spec.pdf) or [JSDocs](https://woodser.github.io/monero-ts/typedocs/classes/MoneroTxWallet.html) for more information.


- Blocks have transactions which can have incoming transfers, an outgoing transfer, and outputs. + Blocks have transactions which can have incoming transfers, an outgoing transfer, and outputs.

## JSON diff --git a/docs/developer_guide/getting_started_p1.md b/docs/developer_guide/getting_started_p1.md index 039b19893..65e7da00b 100644 --- a/docs/developer_guide/getting_started_p1.md +++ b/docs/developer_guide/getting_started_p1.md @@ -1,44 +1,44 @@ # Getting started part 1: creating a Node.js application -## What is monero-javascript? +## What is monero-ts? -monero-javascript is a JavaScript library for producing Monero applications. The library conforms to a [model and API specification](https://moneroecosystem.org/monero-java/monero-spec.pdf) which aims to be an intuitive and robust interface to [monero-project/monero](https://github.com/monero-project/monero). +monero-ts is a TypeScript library for producing Monero applications. The library conforms to a [model and API specification](https://woodser.github.io/monero-java/monero-spec.pdf) which aims to be an intuitive and robust interface to [monero-project/monero](https://github.com/monero-project/monero). -In addition to RPC wallet and daemon server queries, monero-javascript can perform native wallet operations through WebAssembly (Wasm). The Wasm wallet enables developers to build trustless, client-side applications by eliminating the need to communicate with a RPC wallet server intermediary. +In addition to RPC wallet and daemon server queries, monero-ts can perform native wallet operations through WebAssembly (Wasm). The Wasm wallet enables developers to build trustless, client-side applications by eliminating the need to communicate with a RPC wallet server intermediary.


- monero-javascript uses Monero through three channels: RPC wallet servers, RPC daemon servers, and Wasm wallets. + monero-ts uses Monero through three channels: RPC wallet servers, RPC daemon servers, and Wasm wallets.

## Initial Setup ### Install Node.js and the Node package manager (npm) -Node.js and npm need to be installed before using the monero-javascript library. See the ["Node.js and npm"](installing_prerequisites.md#nodejs-and-npm) section of the prerequisite installation guide for instructions to download and install Node.js and npm. +Node.js and npm need to be installed before using the monero-ts library. See the ["Node.js and npm"](installing_prerequisites.md#nodejs-and-npm) section of the prerequisite installation guide for instructions to download and install Node.js and npm. ### Create a new Node.js project 1. Create project directory: `mkdir ~/git/offline_wallet_generator && cd ~/git/offline_wallet_generator` 2. Initialize the new project: `npm init -y` -3. Install the monero-javascript library: `npm install --save monero-javascript` +3. Install the monero-ts library: `npm install --save monero-ts` -## Write a monero-javascript program +## Write a monero-ts program ### The offline wallet generator -An offline wallet generator creates and displays a new, random wallet address along with that address's associated view key, spend key, and mnemonic phrase. An offline wallet generator only needs to produce and display these wallet attributes; it does not need to communicate with a Monero network, transfer XMR, or track a wallet's balance or outputs. +An offline wallet generator creates and displays a new, random wallet address along with that address's associated view key, spend key, and seed phrase. An offline wallet generator only needs to produce and display these wallet attributes; it does not need to communicate with a Monero network, transfer XMR, or track a wallet's balance or outputs. -monero-javascript's keys-only wallet meets these requirements and is ideal for a monero-javascript-based offline wallet generator. The keys-only wallet is a minimal Wasm wallet implementation that only provides a wallet's _static_ attributes. It cannot initiate transfers, report its balance, or communicate with a Monero network. +monero-ts's keys-only wallet meets these requirements and is ideal for a monero-ts-based offline wallet generator. The keys-only wallet is a minimal Wasm wallet implementation that only provides a wallet's _static_ attributes. It cannot initiate transfers, report its balance, or communicate with a Monero network. The keys-only wallet has a file size just under 1/5 that of a standard Wasm wallet, allowing it to load more quickly. -### Write the essential monero-javascript code +### Write the essential monero-ts code Open your preferred text editor or IDE and copy the following code to a new, blank file: -``` -const monerojs = require("monero-javascript"); +```typescript +import moneroTs from "monero-ts"; main(); async function main() { @@ -47,60 +47,60 @@ async function main() { ``` Note the program's two components: -1. A "require" statement to import the monero-javascript library: -`const monerojs = require("monero-javascript");` -2. An asynchronous "main" function so that calls to monero-javascript can be "awaited" (most calls are asynchronous): +1. An "import" statement to import the monero-ts library: +`import moneroTs from "monero-ts";` +2. An asynchronous "main" function so that calls to monero-ts can be "awaited" (most calls are asynchronous): `async function main() {}` ### Building a keys-only wallet -monero-javscript implements keys-only wallets in the [MoneroWalletKeys](https://moneroecosystem.org/monero-javascript/MoneroWalletKeys.html) class. You can create a random keys-only wallet as follows: -``` +monero-javscript implements keys-only wallets in the [MoneroWalletKeys](https://woodser.github.io/monero-ts/typedocs/classes/MoneroWalletKeys.html) class. You can create a random keys-only wallet as follows: +```typescript // create a random keys-only (offline) stagenet wallet -let monerojs = require("monero-javascript"); -let keysOnlyWallet = await monerojs.createWalletKeys({networkType: "stagenet", language: "English"}); +import moneroTs from "monero-ts"; +let keysOnlyWallet = await moneroTs.createWalletKeys({networkType: moneroTs.MoneroNetworkType.STAGENET, language: "English"}); ``` -Wallets are created with a [MoneroWalletConfig](https://moneroecosystem.org/monero-javascript/MoneroWalletConfig) or equivalent JSON object. The monero-javascript library will create or restore a wallet based on attributes defined in the configuration or throw an error if any attributes are invalid. For example, a configuration that defines a view key but not a spend key will prompt the library to create a view-only wallet. The configuration object in the offline wallet generator code above contains no keys, so monero-javascript generates a new, random wallet rather than restoring an existing wallet. +Wallets are created with a [MoneroWalletConfig](https://woodser.github.io/monero-ts/typedocs/classes/MoneroWalletConfig) or equivalent JSON object. The monero-ts library will create or restore a wallet based on attributes defined in the configuration or throw an error if any attributes are invalid. For example, a configuration that defines a view key but not a spend key will prompt the library to create a view-only wallet. The configuration object in the offline wallet generator code above contains no keys, so monero-ts generates a new, random wallet rather than restoring an existing wallet. The offline wallet generator displays four basic wallet attributes: -* The mnemonic phrase +* The seed phrase * The primary address * The spend key * The view key Wallet getters are used to obtain wallet attributes and log them to the console: -``` -console.log("Mnemonic phrase: " + await walletKeys.getMnemonic()); -console.log("Address: " + await walletKeys.getAddress(0,0)); // get address of account 0, subaddress 0 +```typescript +console.log("Seed phrase: " + await walletKeys.getSeed()); +console.log("Address: " + await walletKeys.getAddress(0, 0)); // get address of account 0, subaddress 0 console.log("Spend key: " + await walletKeys.getPrivateSpendKey()); console.log("View key: " + await walletKeys.getPrivateViewKey()); ``` The finished program should match the following: -``` -const monerojs = require("monero-javascript"); +```typescript +import moneroTs from "monero-ts"; main(); async function main() { // create a random keys-only (offline) stagenet wallet - let walletKeys = await monerojs.createWalletKeys({networkType: "stagenet", language: "English"}); + let walletKeys = await moneroTs.createWalletKeys({networkType: moneroTs.MoneroNetworkType.STAGENET, language: "English"}); // print wallet attributes - console.log("Mnemonic phrase: " + await walletKeys.getMnemonic()); - console.log("Address: " + await walletKeys.getAddress(0,0)); // get address of account 0, subaddress 0 + console.log("Seed phrase: " + await walletKeys.getSeed()); + console.log("Address: " + await walletKeys.getAddress(0, 0)); // get address of account 0, subaddress 0 console.log("Spend key: " + await walletKeys.getPrivateSpendKey()); console.log("View key: " + await walletKeys.getPrivateViewKey()); } ``` -Save the file as "offline_wallet_generator.js" and run the program with Node.js: +Save the file as "offline_wallet_generator.ts" and run the program with Node.js: -`node offline_wallet_generator.js` +`node offline_wallet_generator.ts` The output should look similar to the following: ``` -Mnemonic phrase: darted oatmeal toenail launching frown empty agenda apply unnoticed blip waist ashtray threaten deftly sawmill rotate skirting origin ahead obtains makeup bakery bounced dagger apply +Seed phrase: darted oatmeal toenail launching frown empty agenda apply unnoticed blip waist ashtray threaten deftly sawmill rotate skirting origin ahead obtains makeup bakery bounced dagger apply Address: 5ATdKTGQpETCHbBHgDhwd1Wi7oo52PVZYjk2ucf5fnkn9T5yKau2UXkbm7Mo23SAx4MRdyvAaVq75LY9EjSPQnorCGebFqg Spend key: 7bf64c44ecb5ecf02261e6d721d6201d138d0891f0fcf4d613dc27ec84bc070e View key: b4e167b76888bf6ad4c1ab23b4d1bb2e57e7c082ac96478bcda4a9af7fd19507 @@ -108,4 +108,4 @@ View key: b4e167b76888bf6ad4c1ab23b4d1bb2e57e7c082ac96478bcda4a9af7fd19507 ## The next step -Continue to [Getting started part 2: creating a web application](getting_started_p2.md) to learn how to write client-side web browser applications with monero-javascript. +Continue to [Getting started part 2: creating a web application](getting_started_p2.md) to learn how to write client-side web browser applications with monero-ts. diff --git a/docs/developer_guide/getting_started_p2.md b/docs/developer_guide/getting_started_p2.md index 8cb7e0c1c..9a77ba648 100644 --- a/docs/developer_guide/getting_started_p2.md +++ b/docs/developer_guide/getting_started_p2.md @@ -1,17 +1,17 @@ # Getting started part 2: creating a web application -_Note: Though it is not strictly necessary, we recommend reading [part 1 of the monero-javascript getting started guide](getting_started_p1.md) before learning about monero-javascript web application development._ +_Note: Though it is not strictly necessary, we recommend reading [part 1 of the monero-ts getting started guide](getting_started_p1.md) before learning about monero-ts web application development._ ## Overview -This guide describes a convenient method for downloading, building, and launching monero-javascript sample web applications in an application server. The guide also explains how to convert the offline wallet generator from [part 1 of the getting started guide](getting_started_p1.md) to a web browser application. +This guide describes a convenient method for downloading, building, and launching monero-ts sample web applications in an application server. The guide also explains how to convert the offline wallet generator from [part 1 of the getting started guide](getting_started_p1.md) to a web browser application. This guide is divided into three sections: -1. [Creating a monero-javascript web application project](#creating-a-monero-javascript-web-application-project): A walkthrough of how to download and run the monero-javascript web application starter script, which automatically downloads, builds, and launches monero-javascript sample web applications in an application server. +1. [Creating a monero-ts web application project](#creating-a-monero-ts-web-application-project): A walkthrough of how to download and run the monero-ts web application starter script, which automatically downloads, builds, and launches monero-ts sample web applications in an application server. 2. [Modifying the offline wallet generator to display in a browser](#modifying-the-offline-wallet-generator-to-display-in-a-browser): Explains how to modify the offline wallet generator to display wallet attributes to an HTML page rather than the console. 3. [Running the application on your own application server](#running-the-application-on-your-own-application-server): Describes how to run the web application on your own application server rather than the built-in Python server. -## Creating a monero-javascript web application project +## Creating a monero-ts web application project ### Required software @@ -23,26 +23,26 @@ _Note: These are already installed if you followed [part 1 of the getting starte ### Configuring the project directory -A script is available to automatically download, build, and launch sample monero-javascript web applications in an application server. To download and run the script: +A script is available to automatically download, build, and launch sample monero-ts web applications in an application server. To download and run the script: -1. Create a new folder to contain the project: `mkdir ~/monero-javascript-sample-web-apps` -2. Enter the new directory: `cd ~/monero-javascript-sample-web-apps` -3. Download and run the web app starter script: `bash <(curl -sL https://raw.githubusercontent.com/woodser/xmr-sample-app/master/bin/web_template_script.sh)` +1. Create a new folder to contain the project: `mkdir ~/monero-ts-sample-web-apps` +2. Enter the new directory: `cd ~/monero-ts-sample-web-apps` +3. Download and run the web app starter script: `bash <(curl -sL https://raw.githubusercontent.com/woodser/xmr-sample-webpack/master/bin/web_template_script.sh)` -Alternatively, you can [manually download](https://raw.githubusercontent.com/woodser/xmr-sample-app/master/bin/web_template_script.sh) the script then run it. +Alternatively, you can [manually download](https://raw.githubusercontent.com/woodser/xmr-sample-webpack/master/bin/web_template_script.sh) the script then run it. The script configures a project folder and serves sample web applications on port 9100. Open a web browser and navigate to http://localhost:9100 for links to the applications: -* "Offline wallet generator" shows off the final result of following this guide. To view the complete offline wallet generator code as a functioning web application, see "src/offline_wallet_generator.html" and "src/offline_wallet_generator.js". -* "Sample code" demonstrates a handful of common monero-javascript operations. Open the developer console to see the application's output. +* "Offline wallet generator" shows off the final result of following this guide. To view the complete offline wallet generator code as a functioning web application, see "src/offline_wallet_generator.html" and "src/offline_wallet_generator.ts". +* "Sample code" demonstrates a handful of common monero-ts operations. Open the developer console to see the application's output. _Note: In order for the server to reflect changes to source files, you need to stop it by pressing "ctrl-c" in the terminal where the server is running and then rebuild the application and restart the server by typing: `./bin/build_browser_app.sh`._ ## Modifying the offline wallet generator to display in a browser 1. Navigate to the "./src/" directory. -2. Delete the files "offline_wallet_generator.html" and "offline_wallet_generator.js". We'll be rewriting them from scratch. +2. Delete the files "offline_wallet_generator.html" and "offline_wallet_generator.ts". We'll be rewriting them from scratch. 3. Create the file "offline_wallet_generator.html" and insert the following: - ``` + ```html @@ -56,22 +56,22 @@ _Note: In order for the server to reflect changes to source files, you need to s ``` Take note of the line with the `` + `` This line will tell the browser to run your offline wallet generator program. 4. Save the file. -5. While still in the "src" directory, create the file "offline_wallet_generator.js" and insert the following from [part 1 of this guide](getting_started_p1.md): - ``` - const monerojs = require("monero-javascript"); +5. While still in the "src" directory, create the file "offline_wallet_generator.ts" and insert the following from [part 1 of this guide](getting_started_p1.md): + ```typescript + import moneroTs from "monero-ts"; main(); async function main() { // create a random keys-only (offline) stagenet wallet - let walletKeys = await monerojs.createWalletKeys({networkType: "stagenet", language: "English"}); + let walletKeys = await moneroTs.createWalletKeys({networkType: moneroTs.MoneroNetworkType.STAGENET, language: "English"}); // print wallet attributes - console.log("Mnemonic phrase: " + await walletKeys.getMnemonic()); - console.log("Address: " + await walletKeys.getAddress(0,0)); // get address of account 0, subaddress 0 + console.log("Seed phrase: " + await walletKeys.getSeed()); + console.log("Address: " + await walletKeys.getAddress(0, 0)); // get address of account 0, subaddress 0 console.log("Spend key: " + await walletKeys.getPrivateSpendKey()); console.log("View key: " + await walletKeys.getPrivateViewKey()); } @@ -91,29 +91,29 @@ The wallet generator is now _technically_ running on a server, but the typical e Add "div" elements between the opening and closing "body" tags to display each wallet attribute: -``` +```html
-
+
``` ### Assigning wallet attributes to display in the browser -Open offline_wallet_generator.js and find the lines that the print the wallet attributes to the console: +Open offline_wallet_generator.ts and find the lines that the print the wallet attributes to the console: -``` -console.log("Mnemonic phrase: " + await walletKeys.getMnemonic()); -console.log("Address: " + await walletKeys.getAddress(0,0)); // get address of account 0, subaddress 0 +```typescript +console.log("Seed phrase: " + await walletKeys.getSeed()); +console.log("Address: " + await walletKeys.getAddress(0, 0)); // get address of account 0, subaddress 0 console.log("Spend key: " + await walletKeys.getPrivateSpendKey()); console.log("View key: " + await walletKeys.getPrivateViewKey()); ``` Modify these lines to assign each string to its corresponding div element in index.html instead: -``` +```html // print the wallet's attributes in the browser window -document.getElementById("wallet_mnemonic_phrase").innerHTML = "Mnemonic phrase: " + await walletKeys.getMnemonic(); +document.getElementById("wallet_seed_phrase").innerHTML = "Seed phrase: " + await walletKeys.getSeed(); document.getElementById("wallet_address").innerHTML = "Address: " + await walletKeys.getAddress(0, 0); // get address of account 0, subaddress 0 document.getElementById("wallet_spend_key").innerHTML = "Spend key: " + await walletKeys.getPrivateSpendKey(); document.getElementById("wallet_view_key").innerHTML = "View key: " + await walletKeys.getPrivateViewKey(); @@ -123,7 +123,7 @@ The final HTML and JavaScript files should match the following: ### offline_wallet_generator.html -``` +```html @@ -133,7 +133,7 @@ The final HTML and JavaScript files should match the following:
-
+
@@ -141,26 +141,26 @@ The final HTML and JavaScript files should match the following: ``` -### offline_wallet_generator.js +### offline_wallet_generator.ts -``` -const monerojs = require("monero-javascript"); +```typescript +import moneroTs from "monero-ts"; main(); async function main() { // create a random keys-only (offline) stagenet wallet - let walletKeys = await monerojs.createWalletKeys({networkType: "stagenet", language: "English"}); + let walletKeys = await moneroTs.createWalletKeys({networkType: moneroTs.MoneroNetworkType.STAGENET, language: "English"}); // print the wallet's attributes in the browser window - document.getElementById("wallet_mnemonic_phrase").innerHTML = "Mnemonic phrase: " + await walletKeys.getMnemonic(); + document.getElementById("wallet_seed_phrase").innerHTML = "Seed phrase: " + await walletKeys.getSeed(); document.getElementById("wallet_address").innerHTML = "Address: " + await walletKeys.getAddress(0, 0); // get address at account 0, subaddress 0 document.getElementById("wallet_spend_key").innerHTML = "Spend key: " + await walletKeys.getPrivateSpendKey(); document.getElementById("wallet_view_key").innerHTML = "View key: " + await walletKeys.getPrivateViewKey(); } ``` -Run `./bin/build_browser_app.sh` to rebuild the application and launch the server, then point your browser to http://localhost:9100/offline_wallet_generator.html. You should see the wallet's address, mnemonic phrase, spend key, and view key displayed in the browser window. +Run `./bin/build_browser_app.sh` to rebuild the application and launch the server, then point your browser to http://localhost:9100/offline_wallet_generator.html. You should see the wallet's address, seed phrase, spend key, and view key displayed in the browser window. ## Running the application on your own application server @@ -170,7 +170,7 @@ For example, to host the application on a standard apache server: `cp ./browser_ ## Additional resources -Read through the rest of the developer guides to learn more about using monero-javascript: +Read through the rest of the developer guides to learn more about using monero-ts: * [Creating wallets](./creating_wallets.md) * [The data model: blocks, transactions, transfers, and outputs](./data_model.md) diff --git a/docs/developer_guide/https_and_self_signed_certificates.md b/docs/developer_guide/https_and_self_signed_certificates.md index ae75559c7..0ecd0dc5a 100644 --- a/docs/developer_guide/https_and_self_signed_certificates.md +++ b/docs/developer_guide/https_and_self_signed_certificates.md @@ -15,6 +15,8 @@ ## Enable SSL in web application 1. Change RPC URIs to "https://..." 2. Generate certificates for localhost web app (set password, use defaults except common name "localhost"), e.g.: `openssl req -x509 -newkey rsa:4096 -keyout localhost-key.pem -out localhost-cert.pem -days 365` + Note: dev certificates are already committed to src/test/browser with password `abctesting123` 3. Modify run_server.py to use generated certificates by uncommenting commented lines -4. Test in Chrome: chrome://flags/#allow-insecure-localhost, set "Allow invalid certificates for resources loaded from localhost." to "Enabled" -5. Test in Firefox: authenticate with https://localhost:38081/json_rpc and https://localhost:38083/json_rpc first, then access https://localhost:9100/ \ No newline at end of file +4. Run ./bin/start_browser_test_server.sh and enter certificate password +5. Test in Chrome: chrome://flags/#allow-insecure-localhost, set "Allow invalid certificates for resources loaded from localhost." to "Enabled" +6. Test in Firefox: authenticate with https://localhost:38081/json_rpc and https://localhost:38083/json_rpc first, then access https://localhost:9100/ \ No newline at end of file diff --git a/docs/developer_guide/installing_prerequisites.md b/docs/developer_guide/installing_prerequisites.md index dac962b17..2630ddd3f 100644 --- a/docs/developer_guide/installing_prerequisites.md +++ b/docs/developer_guide/installing_prerequisites.md @@ -4,9 +4,9 @@ JavaScript is designed to run client-side in web browsers, so JavaScript programs cannot run as standalone or server-side applications out of the box. Node.js solves this limitation by providing a runtime environment, allowing JavaScript programs to execute outside of a web browser. -[Part 1 of the monero-javascript "getting started" guide](getting_started_p1.md) illustrates the use of Node.js to run a monero-javascript program in a unix terminal, so you need to install it to follow the guide. +[Part 1 of the monero-ts "getting started" guide](getting_started_p1.md) illustrates the use of Node.js to run a monero-ts program in a unix terminal, so you need to install it to follow the guide. -In addition, Node.js includes the Node Package Manger (npm). npm installs Node modules including the monero-javascript module, which is required to use the monero-javascript library. +In addition, Node.js includes the Node Package Manger (npm). npm installs Node modules including the monero-ts module, which is required to use the monero-ts library. To install Node.js and npm: ### Debian/Ubuntu: diff --git a/docs/developer_guide/multisig_wallets.md b/docs/developer_guide/multisig_wallets.md index 8dfc5555c..2cf7e8de1 100644 --- a/docs/developer_guide/multisig_wallets.md +++ b/docs/developer_guide/multisig_wallets.md @@ -2,21 +2,22 @@ The following is an example of creating multisig wallets. -For a full example of creating and sending funds from multisig wallets, see [this test](https://github.com/monero-ecosystem/monero-javascript/blob/80d89aae145d675c61d2a7f4c4769a749b5984f7/src/test/TestMoneroWalletCommon.js#L3549). +For a full example of creating and sending funds from multisig wallets, see "Supports multisig wallets" in [TestMoneroWalletCommon.ts](https://github.com/woodser/monero-ts/blob/master/src/test/TestMoneroWalletCommon.ts). + +```typescript +import moneroTs from "monero-ts"; -```javascript // create multisig wallets which require 3 out of 5 participants to send funds let M = 3; let N = 5; // create participating wallets using RPC or WebAssembly -const monerojs = require("monero-javascript"); let wallets = [] for (let i = 0; i < N; i++) { - wallets.push(await monerojs.createWalletWasm({ + wallets.push(await moneroTs.createWalletFull({ path: "./test_wallets/multisig_participant_" + (i + 1), password: "supersecretpassword123", - networkType: "stagenet" + networkType: moneroTs.MoneroNetworkType.STAGENET })); } @@ -24,47 +25,45 @@ for (let i = 0; i < N; i++) { let preparedMultisigHexes = [] for (let wallet of wallets) preparedMultisigHexes.push(await wallet.prepareMultisig()); -// make each wallet multsig and collect results +// make each wallet multisig and collect results let madeMultisigHexes = []; for (let i = 0; i < wallets.length; i++) { - + // collect prepared multisig hexes from wallet's peers let peerMultisigHexes = []; for (let j = 0; j < wallets.length; j++) if (j !== i) peerMultisigHexes.push(preparedMultisigHexes[j]); // make wallet multisig and collect result hex - let result = await wallets[i].makeMultisig(peerMultisigHexes, M, TestUtils.WALLET_PASSWORD); - madeMultisigHexes.push(result.getMultisigHex()); + let multisigHex = await wallets[i].makeMultisig(peerMultisigHexes, M, TestUtils.WALLET_PASSWORD); + madeMultisigHexes.push(multisigHex); } -// if wallet is not N/N, exchange multisig keys N-M times -if (M !== N) { - let multisigHexes = madeMultisigHexes; - for (let i = 0; i < N - M; i++) { - - // exchange multisig keys among participants and collect results for next round if applicable - let resultMultisigHexes = []; - for (let wallet of wallets) { - - // import the multisig hex of other participants and collect results - let result = await wallet.exchangeMultisigKeys(multisigHexes, TestUtils.WALLET_PASSWORD); - resultMultisigHexes.push(result.getMultisigHex()); - } - - // use resulting multisig hex for next round of exchange if applicable - multisigHexes = resultMultisigHexes; +// exchange multisig keys N - M + 1 times +let multisigHexes = madeMultisigHexes; +for (let i = 0; i < N - M + 1; i++) { + + // exchange multisig keys among participants and collect results for next round if applicable + let resultMultisigHexes = []; + for (let wallet of wallets) { + + // import the multisig hex of other participants and collect results + let result = await wallet.exchangeMultisigKeys(multisigHexes, TestUtils.WALLET_PASSWORD); + resultMultisigHexes.push(result.getMultisigHex()); } + + // use resulting multisig hex for next round of exchange if applicable + multisigHexes = resultMultisigHexes; } // wallets are now multisig for (let wallet of wallets) { let primaryAddress = await wallet.getAddress(0, 0); - MoneroUtils.validateAddress(primaryAddress, await wallet.getNetworkType()); + await MoneroUtils.validateAddress(primaryAddress, await wallet.getNetworkType()); let info = await wallet.getMultisigInfo(); assert(info.isMultisig()); assert(info.isReady()); assert.equal(info.getThreshold(), M); assert.equal(info.getNumParticipants(), N); - await wallet.close(); + await wallet.close(true); } ``` \ No newline at end of file diff --git a/docs/developer_guide/query_data_model.md b/docs/developer_guide/query_data_model.md index b8f2c2cc3..80e5632c4 100644 --- a/docs/developer_guide/query_data_model.md +++ b/docs/developer_guide/query_data_model.md @@ -4,21 +4,21 @@ Wallet [transactions, transfers, and outputs](data_model.md) can be queried by t ## Getting transactions with queries -See [MoneroWallet.getTxs()](https://moneroecosystem.org/monero-javascript/MoneroWallet.html#getTxs) for all query options. +See [MoneroWallet.getTxs()](https://woodser.github.io/monero-ts/typedocs/classes/MoneroWallet.html#getTxs) for all query options. -```javascript +```typescript // get a transaction by hash let tx = await wallet.getTx("48db7afb1e9eecb11303d4f49c955ffdee2ffc2fa513b8f05da35ff537744096"); ``` -```javascript +```typescript // get unconfirmed transactions let txs = await wallet.getTxs({ isConfirmed: false }); ``` -```javascript +```typescript // get transactions since height 582106 with incoming transfers to // account 0, subaddress 0 let txs = await wallet.getTxs({ @@ -31,7 +31,7 @@ let txs = await wallet.getTxs({ }); ``` -```javascript +```typescript // get transactions with available outputs let txs = await wallet.getTxs({ isLocked: false, @@ -43,14 +43,14 @@ let txs = await wallet.getTxs({ ## Getting transfers with queries -See [MoneroWallet.getTransfers()](https://moneroecosystem.org/monero-javascript/MoneroWallet.html#getTransfers) for all query options. +See [MoneroWallet.getTransfers()](https://woodser.github.io/monero-ts/typedocs/classes/MoneroWallet.html#getTransfers) for all query options. -```javascript +```typescript // get all transfers let transfers = await wallet.getTransfers(); ``` -```javascript +```typescript // get incoming transfers to account 0, subaddress 1 let transfers = await wallet.getTransfers({ isIncoming: true, @@ -59,7 +59,7 @@ let transfers = await wallet.getTransfers({ }); ``` -```javascript +```typescript // get transfers in the tx pool let transfers = await wallet.getTransfers({ txQuery: { @@ -68,10 +68,10 @@ let transfers = await wallet.getTransfers({ }); ``` -```javascript +```typescript // get confirmed outgoing transfers since a block height let transfers = await wallet.getTransfers({ - isOutgoing: true, + isIncoming: false, txQuery: { isConfirmed: true, minHeight: 582106, @@ -81,14 +81,14 @@ let transfers = await wallet.getTransfers({ ## Getting outputs with queries -See [MoneroWallet.getOutputs()](https://moneroecosystem.org/monero-javascript/MoneroWallet.html#getOutputs) for all query options. +See [MoneroWallet.getOutputs()](https://woodser.github.io/monero-ts/typedocs/classes/MoneroWallet.html#getOutputs) for all query options. -```javascript +```typescript // get all outputs let outputs = await wallet.getOutputs(); ``` -```javascript +```typescript // get outputs available to be spent let outputs = await wallet.getOutputs({ isSpent: false, @@ -98,13 +98,23 @@ let outputs = await wallet.getOutputs({ }); ``` -```javascript +```typescript +// get outputs by amount +outputs = await wallet.getOutputs({ + amount: 250000000000n +}); +``` + +```typescript // get outputs received to a specific subaddress let outputs = await wallet.getOutputs({ accountIndex: 0, subaddressIndex: 1 }); +``` +```typescript +// get outputs by their key image hex let keyImage = outputs[0].getKeyImage().getHex(); outputs = await wallet.getOutputs({ keyImage: keyImage diff --git a/docs/developer_guide/sending_funds.md b/docs/developer_guide/sending_funds.md index bed294ef7..eebccb3e8 100644 --- a/docs/developer_guide/sending_funds.md +++ b/docs/developer_guide/sending_funds.md @@ -1,13 +1,13 @@ # Sending funds -The following are examples of sending funds using monero-javascript. +The following are examples of sending funds using monero-ts. See [MoneroTxConfig](https://woodser.github.io/monero-ts/typedocs/classes/MoneroTxConfig.html) for all options. -```javascript +```typescript // create a transaction to send funds to an address, but do not relay let tx = await wallet.createTx({ accountIndex: 0, // source account to send funds from address: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", - amount: "1000000000000" // send 1 XMR (denominated in atomic units) + amount: 1000000000000n // send 1 XMR (denominated in atomic units) }); // can confirm with the user @@ -17,17 +17,17 @@ let fee = tx.getFee(); // "Are you sure you want to send... ?" let hash = await wallet.relayTx(tx); ``` -```javascript +```typescript // send funds to a single destination let tx = await wallet.createTx({ accountIndex: 0, // source account to send funds from address: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", - amount: "1000000000000", // send 1 XMR (denominated in atomic units) + amount: 1000000000000n, // send 1 XMR (denominated in atomic units) relay: true // relay the transaction to the network }); ``` -```javascript +```typescript // send funds from a specific subaddress to multiple destinations, // allowing transfers to be split across multiple transactions if needed let txs = await wallet.createTxs({ @@ -35,17 +35,17 @@ let txs = await wallet.createTxs({ subaddressIndex: 1, // source subaddress to send funds from destinations: [{ address: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", - amount: "500000000000", // send 0.5 XMR (denominated in atomic units) + amount: 500000000000n, // send 0.5 XMR (denominated in atomic units) }, { address: "52f7hei1UMrbvYUNtDMKZJMQjcfVyufYnezER8wVK271VmGbzE2kN7cMMG6qFjrb6Ub6qPkNt815a98kJmo874qG9GYZKD5", - amount: "500000000000", // send 0.5 XMR (denominated in atomic units) + amount: 500000000000n, // send 0.5 XMR (denominated in atomic units) }], priority: MoneroTxPriority.IMPORTANT, relay: true // relay the transaction to the network }); ``` -```javascript +```typescript // sweep an output let tx = await wallet.sweepOutput({ address: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", @@ -54,7 +54,7 @@ let tx = await wallet.sweepOutput({ }); ``` -```javascript +```typescript // sweep all unlocked funds in a wallet let txs = await wallet.sweepUnlocked({ address: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", @@ -62,7 +62,7 @@ let txs = await wallet.sweepUnlocked({ }); ``` -```javascript +```typescript // sweep unlocked funds in an account let txs = await wallet.sweepUnlocked({ accountIndex: 0, @@ -71,7 +71,7 @@ let txs = await wallet.sweepUnlocked({ }); ``` -```javascript +```typescript // sweep unlocked funds in a subaddress let txs = await wallet.sweepUnlocked({ accountIndex: 0, diff --git a/docs/developer_guide/view_only_offline.md b/docs/developer_guide/view_only_offline.md index ac3d7849f..dd4ffca35 100644 --- a/docs/developer_guide/view_only_offline.md +++ b/docs/developer_guide/view_only_offline.md @@ -17,13 +17,13 @@ To sign and submit transactions using view-only and offline wallets: The following code demonstrates creating, signing, and submitting transactions using view-only and offline wallets: -```javascript -const monerojs = require("monero-javascript"); +```typescript +import moneroTs from "monero-ts"; // create and sync view-only wallet without spend key -let viewOnlyWallet = await monerojs.createWalletWasm({ +let viewOnlyWallet = await moneroTs.createWalletFull({ path: "my_view_only_wallet", - networkType: "stagenet", + networkType: moneroTs.MoneroNetworkType.STAGENET, primaryAddress: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", privateViewKey: "03d463f03ae547b11dfdf194a07ff82c14a3c6a3de559bd89c9a5e8dc5e9ae02", restoreHeight: 573936, @@ -32,20 +32,20 @@ let viewOnlyWallet = await monerojs.createWalletWasm({ await viewOnlyWallet.sync(); // create offline wallet -let offlineWallet = await monerojs.createWalletWasm({ +let offlineWallet = await moneroTs.createWalletFull({ path: "my_offline_wallet", - networkType: "stagenet", - mnemonic: "spying swept ashtray going hence jester swagger cease spying unusual..." + networkType: moneroTs.MoneroNetworkType.STAGENET, + seed: "spying swept ashtray going hence jester swagger cease spying unusual..." }); // export outputs from view-only wallet -let outputsHex = await viewOnlyWallet.getOutputsHex(); +let outputsHex = await viewOnlyWallet.exportOutputs(); // import outputs to offline wallet -await offlineWallet.importOutputsHex(outputsHex); +await offlineWallet.importOutputs(outputsHex); // export key images from offline wallet -let keyImages = await offlineWallet.getKeyImages(); +let keyImages = await offlineWallet.exportKeyImages(); // import key images to view-only wallet await viewOnlyWallet.importKeyImages(keyImages); @@ -54,16 +54,16 @@ await viewOnlyWallet.importKeyImages(keyImages); let unsignedTx = await viewOnlyWallet.createTx({ accountIndex: 0, address: "56j5AskbiNeeb2UAnS85qpey93GYs4VWB78hazZKGdsKCGHvEXUD6nuMQqXaiiY8SwMWsmtAEXS9kA2ko7hgNtGHKsEWyhv", - amount: "250000000000" // 0.25 XMR + amount: 250000000000n // 0.25 XMR }); -// parse unsigned tx set to confirm details -let parsedTxSet = await offlineWallet.parseTxSet(unsignedTx.getTxSet()); -let fee = parsedTxSet.getTxs()[0].getFee(); // "Are you sure you want to send... ?" +// describe unsigned tx set to confirm details +let describedTxSet = await offlineWallet.describeTxSet(unsignedTx.getTxSet()); +let fee = describedTxSet.getTxs()[0].getFee(); // "Are you sure you want to send... ?" // sign tx using offline wallet -let signedTxHex = await offlineWallet.signTxs(unsignedTx.getTxSet().getUnsignedTxHex()); +let signedTxSet = await offlineWallet.signTxs(unsignedTx.getTxSet().getUnsignedTxHex()); // submit signed tx using view-only wallet -let txHashes = await viewOnlyWallet.submitTxs(signedTxHex); +let txHashes = await viewOnlyWallet.submitTxs(signedTxSet.getSignedTxHex()); ``` \ No newline at end of file diff --git a/docs/fonts/OpenSans-Bold-webfont.eot b/docs/fonts/OpenSans-Bold-webfont.eot deleted file mode 100644 index 5d20d9163..000000000 Binary files a/docs/fonts/OpenSans-Bold-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-Bold-webfont.svg b/docs/fonts/OpenSans-Bold-webfont.svg deleted file mode 100644 index 3ed7be4bc..000000000 --- a/docs/fonts/OpenSans-Bold-webfont.svg +++ /dev/null @@ -1,1830 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-Bold-webfont.woff b/docs/fonts/OpenSans-Bold-webfont.woff deleted file mode 100644 index 1205787b0..000000000 Binary files a/docs/fonts/OpenSans-Bold-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.eot b/docs/fonts/OpenSans-BoldItalic-webfont.eot deleted file mode 100644 index 1f639a15f..000000000 Binary files a/docs/fonts/OpenSans-BoldItalic-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.svg b/docs/fonts/OpenSans-BoldItalic-webfont.svg deleted file mode 100644 index 6a2607b9d..000000000 --- a/docs/fonts/OpenSans-BoldItalic-webfont.svg +++ /dev/null @@ -1,1830 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-BoldItalic-webfont.woff b/docs/fonts/OpenSans-BoldItalic-webfont.woff deleted file mode 100644 index ed760c062..000000000 Binary files a/docs/fonts/OpenSans-BoldItalic-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-Italic-webfont.eot b/docs/fonts/OpenSans-Italic-webfont.eot deleted file mode 100644 index 0c8a0ae06..000000000 Binary files a/docs/fonts/OpenSans-Italic-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-Italic-webfont.svg b/docs/fonts/OpenSans-Italic-webfont.svg deleted file mode 100644 index e1075dcc2..000000000 --- a/docs/fonts/OpenSans-Italic-webfont.svg +++ /dev/null @@ -1,1830 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-Italic-webfont.woff b/docs/fonts/OpenSans-Italic-webfont.woff deleted file mode 100644 index ff652e643..000000000 Binary files a/docs/fonts/OpenSans-Italic-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-Light-webfont.eot b/docs/fonts/OpenSans-Light-webfont.eot deleted file mode 100644 index 14868406a..000000000 Binary files a/docs/fonts/OpenSans-Light-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-Light-webfont.svg b/docs/fonts/OpenSans-Light-webfont.svg deleted file mode 100644 index 11a472ca8..000000000 --- a/docs/fonts/OpenSans-Light-webfont.svg +++ /dev/null @@ -1,1831 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-Light-webfont.woff b/docs/fonts/OpenSans-Light-webfont.woff deleted file mode 100644 index e78607481..000000000 Binary files a/docs/fonts/OpenSans-Light-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-LightItalic-webfont.eot b/docs/fonts/OpenSans-LightItalic-webfont.eot deleted file mode 100644 index 8f445929f..000000000 Binary files a/docs/fonts/OpenSans-LightItalic-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-LightItalic-webfont.svg b/docs/fonts/OpenSans-LightItalic-webfont.svg deleted file mode 100644 index 431d7e354..000000000 --- a/docs/fonts/OpenSans-LightItalic-webfont.svg +++ /dev/null @@ -1,1835 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-LightItalic-webfont.woff b/docs/fonts/OpenSans-LightItalic-webfont.woff deleted file mode 100644 index 43e8b9e6c..000000000 Binary files a/docs/fonts/OpenSans-LightItalic-webfont.woff and /dev/null differ diff --git a/docs/fonts/OpenSans-Regular-webfont.eot b/docs/fonts/OpenSans-Regular-webfont.eot deleted file mode 100644 index 6bbc3cf58..000000000 Binary files a/docs/fonts/OpenSans-Regular-webfont.eot and /dev/null differ diff --git a/docs/fonts/OpenSans-Regular-webfont.svg b/docs/fonts/OpenSans-Regular-webfont.svg deleted file mode 100644 index 25a395234..000000000 --- a/docs/fonts/OpenSans-Regular-webfont.svg +++ /dev/null @@ -1,1831 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/fonts/OpenSans-Regular-webfont.woff b/docs/fonts/OpenSans-Regular-webfont.woff deleted file mode 100644 index e231183dc..000000000 Binary files a/docs/fonts/OpenSans-Regular-webfont.woff and /dev/null differ diff --git a/docs/global.html b/docs/global.html deleted file mode 100644 index 0c6d6ef9c..000000000 --- a/docs/global.html +++ /dev/null @@ -1,2524 +0,0 @@ - - - - - JSDoc: Global - - - - - - - - - - -
- -

Global

- - - - - - -
- -
- -

- - -
- -
-
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - - - - - - - - - - - -

Methods

- - - - - - - -

connectToDaemonRpc(uriOrConfigOrConnection, username, password, rejectUnauthorized, pollInterval, proxyToWorker) → {MoneroDaemonRpc}

- - - - - - -
-

Create a client connected to monero-daemon-rpc.

- -

Examples:

- - -let daemon = monerojs.connectToDaemonRpc("http://localhost:38081", "superuser", "abctesting123");

- -let daemon = monerojs.connectToDaemonRpc({
-   uri: "http://localhost:38081",
-   username: "superuser",
-   password: "abctesting123"
-}); -
-

- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uriOrConfigOrConnection - - -string -| - -object -| - -MoneroRpcConnection - - - - uri of monero-daemon-rpc or JS config object or MoneroRpcConnection -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uri - - -string - - - - uri of monero-daemon-rpc
username - - -string - - - - username to authenticate with monero-daemon-rpc (optional)
password - - -string - - - - password to authenticate with monero-daemon-rpc (optional)
rejectUnauthorized - - -boolean - - - - rejects self-signed certificates if true (default true)
pollInterval - - -number - - - - poll interval to query for updates in ms (default 5000)
proxyToWorker - - -boolean - - - - run the daemon client in a web worker if true (default true if browser, false otherwise)
- -
username - - -string - - - - username to authenticate with monero-daemon-rpc (optional)
password - - -string - - - - password to authenticate with monero-daemon-rpc (optional)
rejectUnauthorized - - -boolean - - - - rejects self-signed certificates if true (default true)
pollInterval - - -number - - - - poll interval to query for updates in ms (default 5000)
proxyToWorker - - -boolean - - - - runs the daemon client in a web worker if true (default true if browser, false otherwise)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the daemon RPC client -
- - - -
-
- Type -
-
- -MoneroDaemonRpc - - -
-
- - - - - - - - - - - - - -

connectToWalletRpc(uriOrConfigOrConnection, username, password, rejectUnauthorized) → {MoneroWalletRpc}

- - - - - - -
-

Create a client connected to monero-wallet-rpc.

- -

Examples:

- - -let walletRpc = monerojs.connectToWalletRpc("http://localhost:38081", "superuser", "abctesting123");

- -let walletRpc = monerojs.connectToWalletRpc({
-   uri: "http://localhost:38081",
-   username: "superuser",
-   password: "abctesting123",
-   rejectUnauthorized: false // e.g. local development
-}); -
-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uriOrConfigOrConnection - - -string -| - -object -| - -MoneroRpcConnection - - - - uri of monero-wallet-rpc or JS config object or MoneroRpcConnection -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
uri - - -string - - - - uri of monero-wallet-rpc
username - - -string - - - - username to authenticate with monero-wallet-rpc (optional)
password - - -string - - - - password to authenticate with monero-wallet-rpc (optional)
rejectUnauthorized - - -boolean - - - - rejects self-signed certificates if true (default true)
- -
username - - -string - - - - username to authenticate with monero-wallet-rpc (optional)
password - - -string - - - - password to authenticate with monero-wallet-rpc (optional)
rejectUnauthorized - - -boolean - - - - rejects self-signed certificates if true (default true)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the wallet RPC client -
- - - -
-
- Type -
-
- -MoneroWalletRpc - - -
-
- - - - - - - - - - - - - -

createWalletKeys(config) → {MoneroWalletKeys}

- - - - - - -
-

Create a wallet using WebAssembly bindings to monero-core.

- -

Example:

- - -let wallet = await monerojs.createWalletKeys({
-   password: "abc123",
-   networkType: MoneroNetworkType.STAGENET,
-   mnemonic: "coexist igloo pamphlet lagoon..."
-}); -
-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -MoneroWalletConfig -| - -object - - - - MoneroWalletConfig or equivalent config object -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
networkType - - -string -| - -number - - - - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
mnemonic - - -string - - - - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)
seedOffset - - -string - - - - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase
primaryAddress - - -string - - - - primary address of the wallet to create (only provide if restoring from keys)
privateViewKey - - -string - - - - private view key of the wallet to create (optional)
privateSpendKey - - -string - - - - private spend key of the wallet to create (optional)
language - - -string - - - - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created wallet -
- - - -
-
- Type -
-
- -MoneroWalletKeys - - -
-
- - - - - - - - - - - - - -

createWalletWasm(config) → {MoneroWalletWasm}

- - - - - - -
-

Create a wallet using WebAssembly bindings to monero-core.

- -

Example:

- - -let wallet = await monerojs.createWalletWasm({
-   path: "./test_wallets/wallet1", // leave blank for in-memory wallet
-   password: "supersecretpassword",
-   networkType: MoneroNetworkType.STAGENET,
-   mnemonic: "coexist igloo pamphlet lagoon...",
-   restoreHeight: 1543218,
-   server: new monerojs.MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123"),
-}); -
-
- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
config - - -object -| - -MoneroWalletConfig - - - - MoneroWalletConfig or equivalent config object -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
path - - -string - - - - path of the wallet to create (optional, in-memory wallet if not given)
password - - -string - - - - password of the wallet to create
networkType - - -string -| - -number - - - - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
mnemonic - - -string - - - - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)
seedOffset - - -string - - - - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase
primaryAddress - - -string - - - - primary address of the wallet to create (only provide if restoring from keys)
privateViewKey - - -string - - - - private view key of the wallet to create (optional)
privateSpendKey - - -string - - - - private spend key of the wallet to create (optional)
restoreHeight - - -number - - - - block height to start scanning frsom (defaults to 0 unless generating random wallet)
language - - -string - - - - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected)
serverUri - - -string - - - - uri of the wallet's daemon (optional)
serverUsername - - -string - - - - username to authenticate with the daemon (optional)
serverPassword - - -string - - - - password to authenticate with the daemon (optional)
rejectUnauthorized - - -boolean - - - - reject self-signed server certificates if true (defaults to true)
server - - -MoneroRpcConnection -| - -object - - - - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional)
proxyToWorker - - -boolean - - - - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)
fs - - -fs - - - - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
- -
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the created wallet -
- - - -
-
- Type -
-
- -MoneroWalletWasm - - -
-
- - - - - - - - - - - - - -

openWalletWasm(configOrPath, password, networkType, daemonUriOrConnection, proxyToWorker, fs) → {MoneroWalletWasm}

- - - - - - -
-

Open an existing wallet using WebAssembly bindings to monero-core.

- -

Examples:

- - -let wallet1 = await monerojs.openWalletWasm(
-   "./wallets/wallet1",
-   "supersecretpassword",
-   MoneroNetworkType.STAGENET,
-   "http://localhost:38081" // daemon uri
-);

- -let wallet2 = await monerojs.openWalletWasm({
-   path: "./wallets/wallet2",
-   password: "supersecretpassword",
-   networkType: MoneroNetworkType.STAGENET,
-   serverUri: "http://localhost:38081", // daemon configuration
-   serverUsername: "superuser",
-   serverPassword: "abctesting123"
-}); -
-

- - - - - - - - - -
Parameters:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
configOrPath - - -MoneroWalletConfig -| - -object -| - -string - - - - MoneroWalletConfig or equivalent config object or a path to a wallet to open -
Properties
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameTypeDescription
path - - -string - - - - path of the wallet to open (optional if 'keysData' provided)
password - - -string - - - - password of the wallet to open
networkType - - -string -| - -number - - - - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
keysData - - -Uint8Array - - - - wallet keys data to open (optional if path provided)
cacheData - - -Uint8Array - - - - wallet cache data to open (optional)
serverUri - - -string - - - - uri of the wallet's daemon (optional)
serverUsername - - -string - - - - username to authenticate with the daemon (optional)
serverPassword - - -string - - - - password to authenticate with the daemon (optional)
rejectUnauthorized - - -boolean - - - - reject self-signed server certificates if true (defaults to true)
server - - -MoneroRpcConnection -| - -object - - - - MoneroRpcConnection or equivalent JS object configuring the daemon connection (optional)
proxyToWorker - - -boolean - - - - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)
fs - - -fs - - - - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
- -
password - - -string - - - - password of the wallet to open
networkType - - -string -| - -number - - - - network type of the wallet to open
daemonUriOrConnection - - -string -| - -MoneroRpcConnection - - - - daemon URI or MoneroRpcConnection
proxyToWorker - - -boolean - - - - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)
fs - - -fs - - - - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
- - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Source:
-
- - - - - - - -
- - - - - - - - - - - - - - - -
Returns:
- - -
- the opened wallet -
- - - -
-
- Type -
-
- -MoneroWalletWasm - - -
-
- - - - - - - - - - - - - -
- -
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/img/architecture.drawio b/docs/img/architecture.drawio index 5fa3c87dd..02c8f1e97 100644 --- a/docs/img/architecture.drawio +++ b/docs/img/architecture.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/docs/img/architecture.png b/docs/img/architecture.png index f53083a1b..8333e400f 100644 Binary files a/docs/img/architecture.png and b/docs/img/architecture.png differ diff --git a/docs/img/data_model.png b/docs/img/data_model.png index 2707dad76..c19d76c63 100644 Binary files a/docs/img/data_model.png and b/docs/img/data_model.png differ diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 066396a93..000000000 --- a/docs/index.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - - JSDoc: Home - - - - - - - - - - -
- -

Home

- - - - - - - - -

- - - - - - - - - - - - - - - - - - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - \ No newline at end of file diff --git a/docs/index.js.html b/docs/index.js.html deleted file mode 100644 index 97bf679cc..000000000 --- a/docs/index.js.html +++ /dev/null @@ -1,304 +0,0 @@ - - - - - JSDoc: Source: index.js - - - - - - - - - - -
- -

Source: index.js

- - - - - - -
-
-
'use strict'
-
-/**
- * Export all library models.
- * 
- * See the full model specification: http://moneroecosystem.org/monero-java/monero-spec.pdf
- */
-module.exports = {};
-
-// export common models
-module.exports.GenUtils = require("./src/main/js/common/GenUtils");
-module.exports.BigInteger = require("./src/main/js/common/biginteger").BigInteger;
-module.exports.Filter = require("./src/main/js/common/Filter");
-module.exports.MoneroError = require("./src/main/js/common/MoneroError");
-module.exports.HttpClient = require("./src/main/js/common/HttpClient");
-module.exports.LibraryUtils = require("./src/main/js/common/LibraryUtils");
-module.exports.MoneroRpcConnection = require("./src/main/js/common/MoneroRpcConnection");
-module.exports.MoneroRpcError = require("./src/main/js/common/MoneroRpcError");
-module.exports.SslOptions = require("./src/main/js/common/SslOptions");
-
-// export daemon models
-module.exports.ConnectionType = require("./src/main/js/daemon/model/ConnectionType");
-module.exports.MoneroAltChain = require("./src/main/js/daemon/model/MoneroAltChain");
-module.exports.MoneroBan = require("./src/main/js/daemon/model/MoneroBan");
-module.exports.MoneroBlockHeader = require("./src/main/js/daemon/model/MoneroBlockHeader");
-module.exports.MoneroBlock = require("./src/main/js/daemon/model/MoneroBlock");
-module.exports.MoneroBlockTemplate = require("./src/main/js/daemon/model/MoneroBlockTemplate");
-module.exports.MoneroDaemonConnection = require("./src/main/js/daemon/model/MoneroDaemonConnection");
-module.exports.MoneroDaemonConnectionSpan = require("./src/main/js/daemon/model/MoneroDaemonConnectionSpan");
-module.exports.MoneroDaemonInfo = require("./src/main/js/daemon/model/MoneroDaemonInfo");
-module.exports.MoneroDaemonPeer = require("./src/main/js/daemon/model/MoneroDaemonPeer");
-module.exports.MoneroDaemonSyncInfo = require("./src/main/js/daemon/model/MoneroDaemonSyncInfo");
-module.exports.MoneroDaemonUpdateCheckResult = require("./src/main/js/daemon/model/MoneroDaemonUpdateCheckResult");
-module.exports.MoneroDaemonUpdateDownloadResult = require("./src/main/js/daemon/model/MoneroDaemonUpdateDownloadResult");
-module.exports.MoneroHardForkInfo = require("./src/main/js/daemon/model/MoneroHardForkInfo");
-module.exports.MoneroKeyImage = require("./src/main/js/daemon/model/MoneroKeyImage");
-module.exports.MoneroKeyImageSpentStatus = require("./src/main/js/daemon/model/MoneroKeyImageSpentStatus");
-module.exports.MoneroMinerTxSum = require("./src/main/js/daemon/model/MoneroMinerTxSum");
-module.exports.MoneroMiningStatus = require("./src/main/js/daemon/model/MoneroMiningStatus");
-module.exports.MoneroNetworkType = require("./src/main/js/daemon/model/MoneroNetworkType");
-module.exports.MoneroOutput = require("./src/main/js/daemon/model/MoneroOutput");
-module.exports.MoneroOutputHistogramEntry = require("./src/main/js/daemon/model/MoneroOutputHistogramEntry");
-module.exports.MoneroSubmitTxResult = require("./src/main/js/daemon/model/MoneroSubmitTxResult");
-module.exports.MoneroTx = require("./src/main/js/daemon/model/MoneroTx");
-module.exports.MoneroTxPoolStats = require("./src/main/js/daemon/model/MoneroTxPoolStats");
-module.exports.MoneroVersion = require("./src/main/js/daemon/model/MoneroVersion");
-
-// export wallet models
-module.exports.MoneroAccount = require("./src/main/js/wallet/model/MoneroAccount");
-module.exports.MoneroAccountTag = require("./src/main/js/wallet/model/MoneroAccountTag");
-module.exports.MoneroAddressBookEntry = require("./src/main/js/wallet/model/MoneroAddressBookEntry");
-module.exports.MoneroCheck = require("./src/main/js/wallet/model/MoneroCheck");
-module.exports.MoneroCheckReserve = require("./src/main/js/wallet/model/MoneroCheckReserve");
-module.exports.MoneroCheckTx = require("./src/main/js/wallet/model/MoneroCheckTx");
-module.exports.MoneroDestination = require("./src/main/js/wallet/model/MoneroDestination");
-module.exports.MoneroIntegratedAddress = require("./src/main/js/wallet/model/MoneroIntegratedAddress");
-module.exports.MoneroKeyImageImportResult = require("./src/main/js/wallet/model/MoneroKeyImageImportResult");
-module.exports.MoneroMultisigInfo = require("./src/main/js/wallet/model/MoneroMultisigInfo");
-module.exports.MoneroMultisigInitResult = require("./src/main/js/wallet/model/MoneroMultisigInitResult");
-module.exports.MoneroMultisigSignResult = require("./src/main/js/wallet/model/MoneroMultisigSignResult");
-module.exports.MoneroOutputWallet = require("./src/main/js/wallet/model/MoneroOutputWallet");
-module.exports.MoneroOutputQuery = require("./src/main/js/wallet/model/MoneroOutputQuery");
-module.exports.MoneroTxPriority = require("./src/main/js/wallet/model/MoneroTxPriority");
-module.exports.MoneroTxConfig = require("./src/main/js/wallet/model/MoneroTxConfig");
-module.exports.MoneroSubaddress = require("./src/main/js/wallet/model/MoneroSubaddress");
-module.exports.MoneroSyncResult = require("./src/main/js/wallet/model/MoneroSyncResult");
-module.exports.MoneroTransfer = require("./src/main/js/wallet/model/MoneroTransfer");
-module.exports.MoneroIncomingTransfer = require("./src/main/js/wallet/model/MoneroIncomingTransfer");
-module.exports.MoneroOutgoingTransfer = require("./src/main/js/wallet/model/MoneroOutgoingTransfer");
-module.exports.MoneroTransferQuery = require("./src/main/js/wallet/model/MoneroTransferQuery");
-module.exports.MoneroTxSet = require("./src/main/js/wallet/model/MoneroTxSet");
-module.exports.MoneroTxWallet = require("./src/main/js/wallet/model/MoneroTxWallet");
-module.exports.MoneroTxQuery = require("./src/main/js/wallet/model/MoneroTxQuery");
-module.exports.MoneroWalletListener = require("./src/main/js/wallet/model/MoneroWalletListener");
-module.exports.MoneroWalletConfig = require("./src/main/js/wallet/model/MoneroWalletConfig");
-
-// export daemon, wallet, and utils classes
-module.exports.MoneroUtils = require("./src/main/js/common/MoneroUtils");
-module.exports.MoneroDaemon = require("./src/main/js/daemon/MoneroDaemon");
-module.exports.MoneroWallet = require("./src/main/js/wallet/MoneroWallet");
-module.exports.MoneroDaemonRpc = require("./src/main/js/daemon/MoneroDaemonRpc");
-module.exports.MoneroWalletRpc = require("./src/main/js/wallet/MoneroWalletRpc");
-module.exports.MoneroWalletKeys = require("./src/main/js/wallet/MoneroWalletKeys");
-module.exports.MoneroWalletWasm = require("./src/main/js/wallet/MoneroWalletWasm");
-
-// ---------------------------- GLOBAL FUNCTIONS ------------------------------
-
-/**
- * <p>Create a client connected to monero-daemon-rpc.<p>
- * 
- * <p>Examples:<p>
- * 
- * <code>
- * let daemon = monerojs.connectToDaemonRpc("http://localhost:38081", "superuser", "abctesting123");<br><br>
- * 
- * let daemon = monerojs.connectToDaemonRpc({<br>
- * &nbsp;&nbsp; uri: "http://localhost:38081",<br>
- * &nbsp;&nbsp; username: "superuser",<br>
- * &nbsp;&nbsp; password: "abctesting123"<br>
- * });
- * </code>
- * 
- * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - uri of monero-daemon-rpc or JS config object or MoneroRpcConnection
- * @param {string} uriOrConfigOrConnection.uri - uri of monero-daemon-rpc
- * @param {string} uriOrConfigOrConnection.username - username to authenticate with monero-daemon-rpc (optional)
- * @param {string} uriOrConfigOrConnection.password - password to authenticate with monero-daemon-rpc (optional)
- * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true)
- * @param {number} uriOrConfigOrConnection.pollInterval - poll interval to query for updates in ms (default 5000)
- * @param {boolean} uriOrConfigOrConnection.proxyToWorker - run the daemon client in a web worker if true (default true if browser, false otherwise)
- * @param {string} username - username to authenticate with monero-daemon-rpc (optional)
- * @param {string} password - password to authenticate with monero-daemon-rpc (optional)
- * @param {boolean} rejectUnauthorized - rejects self-signed certificates if true (default true)
- * @param {number} pollInterval - poll interval to query for updates in ms (default 5000)
- * @param {boolean} proxyToWorker - runs the daemon client in a web worker if true (default true if browser, false otherwise)
- * @return {MoneroDaemonRpc} the daemon RPC client
- */
-module.exports.connectToDaemonRpc = function() { return new module.exports.MoneroDaemonRpc(...arguments); }
-
-/**
- * <p>Create a client connected to monero-wallet-rpc.</p>
- * 
- * <p>Examples:</p>
- * 
- * <code>
- * let walletRpc = monerojs.connectToWalletRpc("http://localhost:38081", "superuser", "abctesting123");<br><br>
- * 
- * let walletRpc = monerojs.connectToWalletRpc({<br>
- * &nbsp;&nbsp; uri: "http://localhost:38081",<br>
- * &nbsp;&nbsp; username: "superuser",<br>
- * &nbsp;&nbsp; password: "abctesting123",<br>
- * &nbsp;&nbsp; rejectUnauthorized: false // e.g. local development<br>
- * });
- * </code>
- * 
- * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - uri of monero-wallet-rpc or JS config object or MoneroRpcConnection
- * @param {string} uriOrConfigOrConnection.uri - uri of monero-wallet-rpc
- * @param {string} uriOrConfigOrConnection.username - username to authenticate with monero-wallet-rpc (optional)
- * @param {string} uriOrConfigOrConnection.password - password to authenticate with monero-wallet-rpc (optional)
- * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true)
- * @param {string} username - username to authenticate with monero-wallet-rpc (optional)
- * @param {string} password - password to authenticate with monero-wallet-rpc (optional)
- * @param {boolean} rejectUnauthorized - rejects self-signed certificates if true (default true)
- * @return {MoneroWalletRpc} the wallet RPC client
- */
-module.exports.connectToWalletRpc = function() { return new module.exports.MoneroWalletRpc(...arguments); }
-
-/**
- * <p>Create a wallet using WebAssembly bindings to monero-core.<p>
- * 
- * <p>Example:</p>
- * 
- * <code>
- * let wallet = await monerojs.createWalletWasm({<br>
- * &nbsp;&nbsp; path: "./test_wallets/wallet1", // leave blank for in-memory wallet<br>
- * &nbsp;&nbsp; password: "supersecretpassword",<br>
- * &nbsp;&nbsp; networkType: MoneroNetworkType.STAGENET,<br>
- * &nbsp;&nbsp; mnemonic: "coexist igloo pamphlet lagoon...",<br>
- * &nbsp;&nbsp; restoreHeight: 1543218,<br>
- * &nbsp;&nbsp; server: new monerojs.MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123"),<br>
- * });
- * </code>
- * 
- * @param {object|MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object
- * @param {string} config.path - path of the wallet to create (optional, in-memory wallet if not given)
- * @param {string} config.password - password of the wallet to create
- * @param {string|number} config.networkType - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
- * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)
- * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase
- * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys)
- * @param {string} config.privateViewKey - private view key of the wallet to create (optional)
- * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional)
- * @param {number} config.restoreHeight - block height to start scanning frsom (defaults to 0 unless generating random wallet)
- * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected)
- * @param {string} config.serverUri - uri of the wallet's daemon (optional)
- * @param {string} config.serverUsername - username to authenticate with the daemon (optional)
- * @param {string} config.serverPassword - password to authenticate with the daemon (optional)
- * @param {boolean} config.rejectUnauthorized - reject self-signed server certificates if true (defaults to true)
- * @param {MoneroRpcConnection|object} config.server - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional)
- * @param {boolean} config.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)
- * @param {fs} config.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
- * @return {MoneroWalletWasm} the created wallet
- */
-module.exports.createWalletWasm = function() { return module.exports.MoneroWalletWasm.createWallet(...arguments); }
-
-/**
- * <p>Open an existing wallet using WebAssembly bindings to monero-core.</p>
- * 
- * <p>Examples:<p>
- * 
- * <code>
- * let wallet1 = await monerojs.openWalletWasm(<br>
- * &nbsp;&nbsp; "./wallets/wallet1",<br>
- * &nbsp;&nbsp; "supersecretpassword",<br>
- * &nbsp;&nbsp; MoneroNetworkType.STAGENET,<br>
- * &nbsp;&nbsp; "http://localhost:38081" // daemon uri<br>
- * );<br><br>
- * 
- * let wallet2 = await monerojs.openWalletWasm({<br>
- * &nbsp;&nbsp; path: "./wallets/wallet2",<br>
- * &nbsp;&nbsp; password: "supersecretpassword",<br>
- * &nbsp;&nbsp; networkType: MoneroNetworkType.STAGENET,<br>
- * &nbsp;&nbsp; serverUri: "http://localhost:38081", // daemon configuration<br>
- * &nbsp;&nbsp; serverUsername: "superuser",<br>
- * &nbsp;&nbsp; serverPassword: "abctesting123"<br>
- * });
- * </code>
- * 
- * @param {MoneroWalletConfig|object|string} configOrPath - MoneroWalletConfig or equivalent config object or a path to a wallet to open
- * @param {string} configOrPath.path - path of the wallet to open (optional if 'keysData' provided)
- * @param {string} configOrPath.password - password of the wallet to open
- * @param {string|number} configOrPath.networkType - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
- * @param {Uint8Array} configOrPath.keysData - wallet keys data to open (optional if path provided)
- * @param {Uint8Array} configOrPath.cacheData - wallet cache data to open (optional)
- * @param {string} configOrPath.serverUri - uri of the wallet's daemon (optional)
- * @param {string} configOrPath.serverUsername - username to authenticate with the daemon (optional)
- * @param {string} configOrPath.serverPassword - password to authenticate with the daemon (optional)
- * @param {boolean} configOrPath.rejectUnauthorized - reject self-signed server certificates if true (defaults to true)
- * @param {MoneroRpcConnection|object} configOrPath.server - MoneroRpcConnection or equivalent JS object configuring the daemon connection (optional)
- * @param {boolean} configOrPath.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)
- * @param {fs} configOrPath.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
- * @param {string} password - password of the wallet to open
- * @param {string|number} networkType - network type of the wallet to open
- * @param {string|MoneroRpcConnection} daemonUriOrConnection - daemon URI or MoneroRpcConnection
- * @param {boolean} proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)
- * @param {fs} fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
- * @return {MoneroWalletWasm} the opened wallet
- */
-module.exports.openWalletWasm = function() { return module.exports.MoneroWalletWasm.openWallet(...arguments); }
-
-/**
- * <p>Create a wallet using WebAssembly bindings to monero-core.</p>
- * 
- * <p>Example:</p>
- * 
- * <code>
- * let wallet = await monerojs.createWalletKeys({<br>
- * &nbsp;&nbsp; password: "abc123",<br>
- * &nbsp;&nbsp; networkType: MoneroNetworkType.STAGENET,<br>
- * &nbsp;&nbsp; mnemonic: "coexist igloo pamphlet lagoon..."<br>
- * });
- * </code>
- * 
- * @param {MoneroWalletConfig|object} config - MoneroWalletConfig or equivalent config object
- * @param {string|number} config.networkType - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
- * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)
- * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase
- * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys)
- * @param {string} config.privateViewKey - private view key of the wallet to create (optional)
- * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional)
- * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected)
- * @return {MoneroWalletKeys} the created wallet
- */
-module.exports.createWalletKeys = function() { return module.exports.MoneroWalletKeys.createWallet(...arguments); }
-
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/scripts/linenumber.js b/docs/scripts/linenumber.js deleted file mode 100644 index 4354785ce..000000000 --- a/docs/scripts/linenumber.js +++ /dev/null @@ -1,25 +0,0 @@ -/*global document */ -(() => { - const source = document.getElementsByClassName('prettyprint source linenums'); - let i = 0; - let lineNumber = 0; - let lineId; - let lines; - let totalLines; - let anchorHash; - - if (source && source[0]) { - anchorHash = document.location.hash.substring(1); - lines = source[0].getElementsByTagName('li'); - totalLines = lines.length; - - for (; i < totalLines; i++) { - lineNumber++; - lineId = `line${lineNumber}`; - lines[i].id = lineId; - if (lineId === anchorHash) { - lines[i].className += ' selected'; - } - } - } -})(); diff --git a/docs/scripts/prettify/Apache-License-2.0.txt b/docs/scripts/prettify/Apache-License-2.0.txt deleted file mode 100644 index d64569567..000000000 --- a/docs/scripts/prettify/Apache-License-2.0.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/docs/scripts/prettify/lang-css.js b/docs/scripts/prettify/lang-css.js deleted file mode 100644 index 041e1f590..000000000 --- a/docs/scripts/prettify/lang-css.js +++ /dev/null @@ -1,2 +0,0 @@ -PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", -/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); diff --git a/docs/scripts/prettify/prettify.js b/docs/scripts/prettify/prettify.js deleted file mode 100644 index eef5ad7e6..000000000 --- a/docs/scripts/prettify/prettify.js +++ /dev/null @@ -1,28 +0,0 @@ -var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; -(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= -[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), -l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, -q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, -q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, -"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), -a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} -for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], -"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], -H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], -J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ -I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), -["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", -/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), -["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", -hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= -!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p - - - - JSDoc: Source: src/main/js/common/Filter.js - - - - - - - - - - -
- -

Source: src/main/js/common/Filter.js

- - - - - - -
-
-
/**
- * Base filter.
- * 
- * @private
- */
-class Filter {
-  
-  /**
-   * Indicates if the given value meets the criteria of this filter.
-   * 
-   * @param val is the value to test
-   * @return true if the value meets the criteria of this filter, false otherwise
-   */
-  meetsCriteria(val) {
-    throw new Error("Subclass must implement");
-  }
-  
-  /**
-   * Returns a new array comprised of elements from the given array that meet
-   * the filter's criteria.
-   * 
-   * @param filter implements meetsCriteria(elem) to filter the given array
-   * @param array is the array to apply the filter to
-   * @return the new array of filtered elements
-   */
-  static apply(filter, array) {
-    return array.filter(elem => filter.meetsCriteria(elem));
-  }
-}
-
-module.exports = Filter;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_common_GenUtils.js.html b/docs/src_main_js_common_GenUtils.js.html deleted file mode 100644 index 4dd79576d..000000000 --- a/docs/src_main_js_common_GenUtils.js.html +++ /dev/null @@ -1,1529 +0,0 @@ - - - - - JSDoc: Source: src/main/js/common/GenUtils.js - - - - - - - - - - -
- -

Source: src/main/js/common/GenUtils.js

- - - - - - -
-
-
const assert = require("assert");
-const BigInteger = require("./biginteger").BigInteger;
-
-/**
- * MIT License
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- * 
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/**
- * Collection of general purpose utilities.
- * 
- * TODO: could pull in assert and remove these asserts
- * TODO: needs cleanup as ES6+ utility class
- */
-class GenUtils {
-  
-  /**
-   * Indicates if the given argument is defined.
-   * 
-   * @param arg is the arg to test
-   * @returns true if the given arg is defined, false otherwise
-   */
-  static isDefined(arg) {
-    return typeof arg !== 'undefined';
-  }
-
-  /**
-   * Indicates if the given argument is undefined.
-   * 
-   * @param arg is the arg to test
-   * @returns true if the given arg is undefined, false otherwise
-   */
-  static isUndefined(arg) {
-    return typeof arg === 'undefined';
-  }
-
-  /**
-   * Indicates if the given arg is initialized.
-   * 
-   * @param arg is the arg to test
-   * @returns true if the given arg is initialized, false otherwise
-   */
-  static isInitialized(arg) {
-    return arg !== undefined && arg !== null;
-  }
-
-  /**
-   * Indicates if the given arg is uninitialized.
-   * 
-   * @param arg is the arg to test
-   * @returns true if the given arg is uninitialized, false otherwise
-   */
-  static isUninitialized(arg) {
-    if (!arg) return true;
-    return false;
-  }
-
-  /**
-   * Indicates if the given argument is a number.
-   * 
-   * @param arg is the argument to test
-   * @returns true if the argument is a number, false otherwise
-   */
-  static isNumber(arg) {
-    return !isNaN(parseFloat(arg)) && isFinite(arg);
-  }
-
-  /**
-   * Indicates if the given argument is an integer.
-   * 
-   * @param arg is the argument to test
-   * @returns true if the given argument is an integer, false otherwise
-   */
-  static isInt(arg) {
-    return arg === parseInt(Number(arg)) && !isNaN(arg) && !isNaN(parseInt(arg, 10));
-  }
-
-  /**
-   * Indicates if the given argument is an array.
-   * 
-   * TODO: remove this entirely since just a direct wrapper?
-   * TODO: this method returns true for object
-   * 
-   * @param arg is the argument to test as being an array
-   * @returns true if the argument is an array, false otherwise
-   */
-  static isArray(arg) {
-    return Array.isArray(arg);
-  }
-
-  /**
-   * Indicates if the given argument is a string.
-   * 
-   * @param arg is the argument to test as being a string
-   * @returns true if the argument is a string, false otherwise
-   */
-  static isString(arg) {
-    return typeof arg === 'string';
-  }
-
-  /**
-   * Determines if the given argument is a boolean.
-   * 
-   * @param arg is the argument to test as being a boolean
-   * @returns true if the argument is a boolean, false otherwise
-   */
-  static isBoolean(arg) {
-    return typeof(arg) == typeof(true);
-  }
-
-  /**
-   * Determines if the given argument is a static.
-   * 
-   * @param arg is the argument to test as being a static
-   * @returns true if the argument is a static, false otherwise
-   */
-  static isFunction(arg) {
-    return typeof arg === "static";
-  }
-
-  /**
-   * Indicates if the given argument is an object and optionally if it has the given constructor name.
-   * 
-   * @param arg is the argument to test
-   * @param obj is an object to test arg instanceof obj (optional)
-   * @returns true if the given argument is an object and optionally has the given constructor name
-   */
-  static isObject(arg, obj) {
-    if (!arg) return false;
-    if (typeof arg !== 'object') return false;
-    if (obj && !(arg instanceof obj)) return false;
-    return true;
-  }
-
-  /**
-   * Determines if all alphabet characters in the given string are upper case.
-   * 
-   * @param str is the string to test
-   * @returns true if the string is upper case, false otherwise
-   */
-  static isUpperCase(str) {
-    return str.toUpperCase() === str;
-  }
-
-  /**
-   * Determines if all alphabet characters in the given string are lower case.
-   * 
-   * @param str is the string to test
-   * @param true if the string is lower case, false otherwise
-   */
-  static isLowerCase(str) {
-    return str.toLowerCase() === str;
-  }
-
-  /**
-   * Asserts that the given argument is hex.
-   * 
-   * @param arg is the argument to assert as hex
-   * @param msg is the message to throw if the argument is not hex
-   */
-  static assertHex(str, msg) {
-    GenUtils.assertTrue(isHex(str), msg ? msg : "Argument asserted as hex but is not hex");
-  }
-
-  /**
-   * Indicates if the given argument is a hexidemal string.
-   * 
-   * Credit: https://github.com/roryrjb/is-hex/blob/master/is-hex.js.
-   * 
-   * @param str is the string to test
-   * @returns true if the given string is hexidecimal, false otherwise
-   */
-  static isHex(arg) {
-    if (typeof arg !== 'string') return false;
-    if (arg.length === 0) return false;
-    return (arg.match(/([0-9]|[a-f])/gim) || []).length === arg.length;
-  }
-
-  /**
-   * Determines if the given string is base32.
-   */
-  static isBase32(str) {
-    if (typeof str !== 'string') return false;
-    GenUtils.assertTrue(str.length > 0, "Cannot determine if empty string is base32");
-    return /^[ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]+$/.test(str);
-  }
-
-  /**
-   * Asserts that the given argument is base58.
-   * 
-   * @param arg is the argument to assert as base58
-   * @param msg is the message to throw if the argument is not base58
-   */
-  static assertBase58(str, msg) {
-    GenUtils.assertTrue(isBase58(str), msg ? msg : "Argument asserted as base58 but is not base58");
-  }
-
-  /**
-   * Determines if the given string is base58.
-   */
-  static isBase58(str) {
-    if (typeof str !== 'string') return false;
-    GenUtils.assertTrue(str.length > 0, "Cannot determine if empty string is base58");
-    return /^[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$/.test(str);
-  }
-
-  /**
-   * Asserts that the given argument is base64.
-   * 
-   * @param arg is the argument to assert as base64
-   * @param msg is the message to throw if the argument is not base64
-   */
-  static assertBase64(str, msg) {
-    GenUtils.assertTrue(isBase64(str), msg ? msg : "Argument asserted as base64 but is not base64");
-  }
-
-  /**
-   * Determines if the given string is base64.
-   */
-  static isBase64(str) {
-    if (typeof str !== 'string') return false;
-    GenUtils.assertTrue(str.length > 0, "Cannot determine if empty string is base64");
-    try {
-      return btoa(atob(str)) == str;
-    } catch (err) {
-      return false;
-    }
-  }
-
-  /**
-   * Throws an exception with the given message.
-   * 
-   * @param msg defines the message to throw the exception with (optional)
-   */
-  static fail(msg) {
-    throw new Error(msg ? msg : "Failure (no message)");
-  }
-
-  /**
-   * Asserts that the given boolean is true.  Throws an exception if not a boolean or false.
-   * 
-   * @param bool is the boolean to assert true
-   * @param msg is the message to throw if bool is false (optional)
-   */
-  static assertTrue(bool, msg) {
-    if (typeof bool !== 'boolean') throw new Error("Argument is not a boolean");
-    if (!bool) throw new Error(msg ? msg : "Boolean asserted as true but was false");
-  }
-
-  /**
-   * Asserts that the given boolean is false.  Throws an exception if not a boolean or true.
-   * 
-   * @param bool is the boolean to assert false
-   * @param msg is the message to throw if bool is true (optional)
-   */
-  static assertFalse(bool, msg) {
-    if (typeof bool !== 'boolean') throw new Error("Argument is not a boolean");
-    if (bool) throw new Error(msg ? msg : "Boolean asserted as false but was true");
-  }
-
-  /**
-   * Asserts that the given argument is null.  Throws an exception if not null.
-   * 
-   * @param arg is the argument to assert null
-   * @param msg is the message to throw if arg is not null (optional)
-   */
-  static assertNull(arg, msg) {
-    if (arg !== null) throw new Error(msg ? msg : "Argument asserted as null but was not null: " + arg);
-  }
-
-  /**
-   * Asserts that the given argument is not null.  Throws an exception if null.
-   * 
-   * @param arg is the argument to assert not null
-   * @param msg is the message to throw if arg is null (optional)
-   */
-  static assertNotNull(arg, msg) {
-    if (arg === null) throw new Error(msg ? msg : "Argument asserted as not null but was null");
-  }
-
-  /**
-   * Asserts that the given argument is defined.  Throws an exception if undefined.
-   * 
-   * @param arg is the argument to assert defined
-   * @param msg is the message to throw if arg is undefined (optional)
-   */
-  static assertDefined(arg, msg) {
-    if (GenUtils.isUndefined(arg)) throw new Error(msg ? msg : "Argument asserted as defined but was undefined");
-  }
-
-  /**
-   * Asserts that the given argument is undefined.  Throws an exception if defined.
-   * 
-   * @param arg is the argument to assert undefined
-   * @param msg is the message to throw if arg is defined (optional)
-   */
-  static assertUndefined(arg, msg) {
-    if (GenUtils.isDefined(arg)) throw new Error(msg ? msg : "Argument asserted as undefined but was defined: " + arg);
-  }
-
-  /**
-   * Asserts that the given argument is initialized.  Throws an exception if not initialized.
-   * 
-   * @param arg is the argument to assert as initialized
-   * @param msg is the message to throw if arg is not initialized (optional)
-   */
-  static assertInitialized(arg, msg) {
-    if (GenUtils.isUninitialized(arg)) {
-      throw new Error(msg ? msg : "Argument asserted as initialized but was " + arg);
-    }
-  }
-
-  /**
-   * Asserts that the given argument is uninitialized.  Throws an exception if initialized.
-   * 
-   * @param arg is the argument to assert as uninitialized
-   * @param msg is the message to throw if arg is initialized (optional)
-   */
-  static assertUninitialized(arg, msg) {
-    if (GenUtils.isInitialized(arg)) throw new Error(msg ? msg : "Argument asserted as uninitialized but was initialized");
-  }
-
-  /**
-   * Asserts that the given arguments are equal.  Throws an exception if not equal.
-   * 
-   * @param arg1 is an argument to assert as equal
-   * @param arg2 is an argument to assert as equal
-   * @param msg is the message to throw if the arguments are not equal
-   */
-  static assertEquals(arg1, arg2, msg) {
-    GenUtils.assertTrue(equals(arg1, arg2), msg ? msg : "Arguments asserted as equal but are not equal: " + arg1 + " vs " + arg2);
-  }
-
-  /**
-   * Asserts that the given arguments are not equal.  Throws an exception if equal.
-   * 
-   * @param arg1 is an argument to assert as not equal
-   * @param arg2 is an argument to assert as not equal
-   * @param msg is the message to throw if the arguments are equal
-   */
-  static assertNotEquals(arg1, arg2, msg) {
-    if (arg1 === arg2) throw new Error(msg ? msg : "Arguments asserted as not equal but are equal: " + arg1 + " vs " + arg2);
-  }
-
-  /**
-   * Asserts that the given argument is an integer.
-   * 
-   * @param arg is the argument to assert as an integer
-   * @param msg is the message to throw if the argument is not an integer
-   */
-  static assertInt(arg, msg) {
-    if (!GenUtils.isInt(arg)) throw new Error(msg ? msg : "Argument asserted as an integer but is not an integer");
-  }
-
-  /**
-   * Asserts that the given argument is a number.
-   * 
-   * @param arg is the argument to assert as a number
-   * @param msg is the message to throw if the argument is not a number
-   */
-  static assertNumber(arg, msg) {
-    if (!GenUtils.isNumber(arg)) throw new Error(msg ? msg : "Argument asserted as a number but is not a number");
-  }
-
-  /**
-   * Asserts that the given argument is a boolean.
-   * 
-   * @param arg is the argument to assert as a boolean
-   * @param msg is the message to throw if the argument is not a boolean
-   */
-  static assertBoolean(arg, msg) {
-    if (!GenUtils.isBoolean(arg)) throw new Error(msg ? msg : "Argument asserted as a boolean but is not a boolean");
-  }
-
-  /**
-   * Asserts that the given argument is a string.
-   * 
-   * @param arg is the argument to assert as a string
-   * @param msg is the message to throw if the argument is not a string
-   */
-  static assertString(arg, msg) {
-    if (!GenUtils.isString(arg)) throw new Error(msg ? msg : "Argument asserted as a string but is not a string: " + arg);
-  }
-
-  /**
-   * Asserts that the given argument is an array.
-   * 
-   * @param arg is the argument to assert as an array
-   * @param msg is the message to throw if the argument is not an array
-   */
-  static assertArray(arg, msg) {
-    if (!GenUtils.isArray(arg)) throw new Error(msg ? msg : "Argument asserted as an array but is not an array");
-  }
-
-  /**
-   * Asserts that the given argument is a static.
-   * 
-   * @param arg is the argument to assert as a static
-   * @param msg is the message to throw if the argument is not a static
-   */
-  static assertFunction(arg, msg) {
-    if (!GenUtils.isFunction(arg)) throw new Error(msg ? msg : "Argument asserted as a static but is not a static");
-  }
-
-  /**
-   * Asserts that the given argument is an object with the given name.
-   * 
-   * @param arg is the argument to test
-   * @param obj is an object to assert arg instanceof obj (optional)
-   * @param msg is the message to throw if the argument is not the specified object
-   */
-  static assertObject(arg, obj, msg) {
-    GenUtils.assertInitialized(arg, msg);
-    if (obj) {
-      if (!isObject(arg, obj)) throw new Error(msg ? msg : "Argument asserted as object '" + obj.name + "' but was not");
-    } else {
-      if (!isObject(arg)) throw new Error(msg ? msg : "Argument asserted as object but was not");
-    }
-  }
-
-  /**
-   * Sets the child's prototype to the parent's prototype.
-   * 
-   * @param child is the child class
-   * @param parent is the parent class
-   */
-  static inheritsFrom(child, parent) {
-    child.prototype = Object.create(parent.prototype);
-    child.prototype.constructor = child;
-  }
-
-  /**
-   * Invokes functions with arguments.
-   * 
-   * arguments[0] is assumed to be an array of functions to invoke
-   * arguments[1...n] are args to invoke the functions with
-   */
-  static invoke() {
-    let fns = arguments[0];
-    let args = [];
-    for (let i = 1; i < arguments.length; i++) args.push(arguments[i]);
-    for (let i = 0; i < fns.length; i++) {
-      assertFunction(fns[i], "Functions[" + i + "] is not a static");
-      fns[i].apply(null, args);
-    }
-  }
-
-  /**
-   * Returns the power set of the given array.
-   * 
-   * @param arr is the array to get the power set of
-   * @returns [][] is the power set of the given array
-   */
-  static getPowerSet(arr) {
-    let fn = function(n, src, got, all) {
-      if (n == 0) {
-        if (got.length > 0) {
-          all[all.length] = got;
-        }
-        return;
-      }
-      for (let j = 0; j < src.length; j++) {
-        fn(n - 1, src.slice(j + 1), got.concat([ src[j] ]), all);
-      }
-      return;
-    }
-    let all = [];
-    all.push([]);
-    for (let i = 0; i < arr.length; i++) {
-      fn(i, arr, [], all);
-    }
-    all.push(arr);
-    return all;
-  }
-
-  /**
-   * Returns the power set of the given array whose elements are the given size.
-   * 
-   * @param arr is the array to get the power set of
-   * @param size is the required size of the elements within the power set
-   * returns [][] is the power set of the given array whose elements are the given size 
-   */
-  static getPowerSetOfLength(arr, size) {
-    assertInitialized(arr);
-    assertInitialized(size);
-    GenUtils.assertTrue(size >= 1);
-    let powerSet = getPowerSet(arr);
-    let powerSetOfLength = [];
-    for (let i = 0; i < powerSet.length; i++) {
-      if (powerSet[i].length === size) {
-        powerSetOfLength.push(powerSet[i]);
-      }
-    }
-    return powerSetOfLength;
-  }
-
-  /**
-   * Returns an array of indices of the given size.
-   * 
-   * @param size specifies the size to get indices for
-   * @returns array of the given size with indices starting at 0
-   */
-  static getIndices(size) {
-    let indices = [];
-    for (let i = 0; i < size; i++) {
-      indices.push(i);
-    }
-    return indices;
-  }
-
-  /**
-   * Returns a new array containing unique elements of the given array.
-   * 
-   * @param arr is the array to return unique elements from
-   * @returns a new array with the given array's unique elements
-   */
-  static toUniqueArray(arr) {
-    return arr.filter(function(value, index, self) {
-      return self.indexOf(value) === index;
-    });
-  }
-
-  /**
-   * Copies the given array.
-   * 
-   * @param arr is the array to copy
-   * @returns a copy of the given array
-   */
-  static copyArray(arr) {
-    GenUtils.assertArray(arr);
-    let copy = [];
-    for (let i = 0; i < arr.length; i++) copy.push(arr[i]);
-    return copy;
-  }
-  
-  /**
-   * Removes every instance of the given value from the given array.
-   * 
-   * @param arr is the array to remove the value from
-   * @param val is the value to remove from the array
-   * @returns true if the value is found and removed, false otherwise
-   */
-  static remove(arr, val) {
-    let found = false;
-    for (let i = arr.length - 1; i >= 0; i--) {
-      if (arr[i] === val) {
-        arr.splice(i, 1);
-        found = true;
-        i--;
-      }
-    }
-    return found;
-  }
-
-  /**
-   * Returns a copy of the given array where each element is lowercase.
-   * 
-   * @param arr is the array to convert to lowercase
-   * @returns a copy of the given array where each element is lowercase
-   */
-  static toLowerCaseArray(arr) {
-    let arr2 = [];
-    for (let i = 0; i < arr.length; i++) {
-      arr2.push(arr[i].toLowerCase());
-    }
-    return arr2;
-  }
-
-  /**
-   * Listifies the given argument.
-   * 
-   * @param arrOrElem is an array or an element in the array
-   * @returns an array which is the given arg if it's an array or an array with the given arg as an element
-   */
-  static listify(arrOrElem) {
-    return GenUtils.isArray(arrOrElem) ? arrOrElem : [arrOrElem];
-  }
-
-  /**
-   * Indicates if the given array contains the given object.
-   * 
-   * @param {object[]} arr - array that may or may not contain the object
-   * @param {object} obj - object to check for inclusion in the array
-   * @param {boolean} compareByReference - compare strictly by reference, forgoing deep equality check
-   * @returns true if the array contains the object, false otherwise
-   */
-  static arrayContains(arr, obj, compareByReference) {
-    GenUtils.assertTrue(GenUtils.isArray(arr));
-    for (let i = 0; i < arr.length; i++) {
-      if (arr[i] === obj) return true;
-      if (!compareByReference && GenUtils.equals(arr[i], obj)) return true;
-    }
-    return false;
-  }
-
-  /**
-   * Indicates if the given string contains the given substring.
-   * 
-   * @param str is the string to search for a substring
-   * @param substring is the substring to searchin within the string
-   * @returns true if the substring is within the string, false otherwise
-   */
-  static strContains(str, substring) {
-    return str.indexOf(substring) > -1;
-  }
-
-  /**
-   * Determines if two arrays are equal.
-   * 
-   * @param arr1 is an array to compare
-   * @param arr2 is an array to compare
-   * @returns true if the arrays are equal, false otherwise
-   */
-  static arraysEqual(arr1, arr2) {
-    if (arr1 === arr2) return true;
-    if (arr1 == null && arr2 == null) return true;
-    if (arr1 == null || arr2 == null) return false;
-    if (typeof arr1 === 'undefined' && typeof arr2 === 'undefined') return true;
-    if (typeof arr1 === 'undefined' || typeof arr2 === 'undefined') return false;
-    if (!GenUtils.isArray(arr1)) throw new Error("First argument is not an array");
-    if (!GenUtils.isArray(arr2)) throw new Error("Second argument is not an array");
-    if (arr1.length != arr2.length) return false;
-    for (let i = 0; i < arr1.length; ++i) {
-      if (!GenUtils.equals(arr1[i], arr2[i])) return false;
-    }
-    return true;
-  }
-
-  /**
-   * Determines if two arguments are deep equal.
-   * 
-   * @param arg1 is an argument to compare
-   * @param arg2 is an argument to compare
-   * @returns true if the arguments are deep equals, false otherwise
-   */
-  static equals(arg1, arg2) {
-    if (GenUtils.isArray(arg1) && GenUtils.isArray(arg2)) return GenUtils.arraysEqual(arg1, arg2);
-    if (GenUtils.isObject(arg1) && GenUtils.isObject(arg2)) return GenUtils.objectsEqual(arg1, arg2);
-    return arg1 === arg2;
-  }
-  
-  /**
-   * Determines if two objects are deep equal.
-   * 
-   * Undefined values are considered equal to non-existent keys.
-   * 
-   * @param map1 is a map to compare
-   * @param map2 is a map to compare
-   * @returns true if the maps have identical keys and values, false otherwise
-   */
-  static objectsEqual(map1, map2) {
-    let keys1 = Object.keys(map1);
-    let keys2 = Object.keys(map2);
-    
-    // compare each key1 to keys2
-    for (let key1 of keys1) {
-      let found = false;
-      for (let key2 of keys2) {
-        if (key1 === key2) {
-          if (!GenUtils.equals(map1[key1], map2[key2])) return false;
-          found = true;
-          break;
-        }
-      }
-      if (!found && map1[key1] !== undefined) return false; // allows undefined values to equal non-existent keys
-    }
-    
-    // compare each key2 to keys1
-    for (let key2 of keys2) {
-      let found = false;
-      for (let key1 of keys1) {
-        if (key1 === key2) {
-          found = true; // no need to re-compare which was done earlier
-          break;
-        }
-      }
-      if (!found && map2[key2] !== undefined) return false; // allows undefined values to equal non-existent keys
-    }
-    return true;
-    
-    // TODO: support strict option?
-//    if (strict) {
-//      let keys1 = Object.keys(map1);
-//      if (keys1.length !== Object.keys(map2).length) return false;
-//      for (let i = 0; i < keys1.length; i++) {
-//        let key = Object.keys(map1)[i];
-//        if (!GenUtils.equals(map1[key], map2[key])) return false;
-//      }
-//    }
-  }
-  
-  /**
-   * Deletes properties from the object that are undefined.
-   * 
-   * @param obj is the object to delete undefined keys from
-   */
-  static deleteUndefinedKeys(obj) {
-    for (let key of Object.keys(obj)) {
-      if (obj[key] === undefined) delete obj[key];
-    }
-  }
-
-  /**
-   * Returns combinations of the given array of the given size.
-   * 
-   * @param arr is the array to get combinations from
-   * @param combinationSize specifies the size of each combination
-   */
-  static getCombinations(arr, combinationSize) {
-    
-    // validate input
-    assertInitialized(arr);
-    assertInitialized(combinationSize);
-    GenUtils.assertTrue(combinationSize >= 1);
-    
-    // get combinations of array indices of the given size
-    let indexCombinations = getPowerSetOfLength(getIndices(arr.length), combinationSize);
-    
-    // collect combinations from each combination of array indices
-    let combinations = [];
-    for (let indexCombinationsIdx = 0; indexCombinationsIdx < indexCombinations.length; indexCombinationsIdx++) {
-      
-      // get combination of array indices
-      let indexCombination = indexCombinations[indexCombinationsIdx];
-      
-      // build combination from array
-      let combination = [];
-      for (let indexCombinationIdx = 0; indexCombinationIdx < indexCombination.length; indexCombinationIdx++) {
-        combination.push(arr[indexCombination[indexCombinationIdx]]);
-      }
-      
-      // add to combinations
-      combinations.push(combination);
-    }
-    
-    return combinations;
-  }
-
-  /**
-   * Gets an 'a' element that is downloadable when clicked.
-   * 
-   * @param name is the name of the file to download
-   * @param contents are the string contents of the file to download
-   * @returns 'a' dom element with downloadable file
-   */
-  static getDownloadableA(name, contents) {
-    let a = window.document.createElement('a');
-    a.href = window.URL.createObjectURL(new Blob([contents], {type: 'text/plain'}));
-    a.download = name;
-    a.target="_blank";
-    a.innerHTML = name;
-    return a;
-  }
-
-  /**
-   * Returns the given node's outer HTML.
-   * 
-   * @param node is the node to get outer HTML for
-   * @returns the outer HTML of the given node
-   */
-  static getOuterHtml(node) {
-    return $('<div>').append($(node).clone()).html();
-  }
-
-  /**
-   * Copies properties in the given object to a new object.
-   * 
-   * @param obj is object to copy properties for
-   * @returns a new object with properties copied from the given object
-   */
-  static copyProperties(obj) {
-    return JSON.parse(JSON.stringify(obj))
-  }
-
-  /**
-   * Deletes all properties in the given object.
-   * 
-   * @param obj is the object to delete properties from
-   */
-  static deleteProperties(obj) {
-    let props = [];
-    for (let prop in obj) props.push(prop); // TODO: if (obj.hasOwnProperty(prop)) { ...
-    for (i = 0; i < props.length; i++) delete obj[props[i].toString()];
-  }
-
-  /**
-   * Converts a CSV string to a 2-dimensional array of strings.
-   * 
-   * @param csv is the CSV string to convert
-   * @returns a 2-dimensional array of strings
-   */
-  static csvToArr(csv) {
-    return $.csv.toArrays(csv);
-  }
-
-  /**
-   * Converts the given array to a CSV string.
-   * 
-   * @param arr is a 2-dimensional array of strings
-   * @returns the CSV string
-   */
-  static arrToCsv(arr) {
-    return $.csv.fromObjects(arr, {headers: false});
-  }
-
-  /**
-   * Indicates if the given string contains whitespace.
-   * 
-   * @param str is the string to test
-   * @returns true if the string contains whitespace, false otherwise
-   */
-  static hasWhitespace(str) {
-    return /\s/g.test(str);
-  }
-
-  /**
-   * Indicates if the given character is whitespace.
-   * 
-   * @param char is the character to test
-   * @returns true if the given character is whitespace, false otherwise
-   */
-  static isWhitespace(char) {
-    return /\s/.test(char);
-  }
-
-  /**
-   * Indicates if the given character is a newline.
-   * 
-   * @param char is the character to test
-   * @returns true if the given character is a newline, false otherwise
-   */
-  static isNewline(char) {
-    return char === '\n' || char === '\r';
-  }
-
-  /**
-   * Counts the number of non-whitespace characters in the given string.
-   * 
-   * @param str is the string to count the number of non-whitespace characters in
-   * @returns int is the number of non-whitespace characters in the given string
-   */
-  static countNonWhitespaceCharacters(str) {
-    let count = 0;
-    for (let i = 0; i < str.length; i++) {
-      if (!isWhitespace(str.charAt(i))) count++;
-    }
-    return count;
-  }
-
-  /**
-   * Returns tokens separated by whitespace from the given string.
-   * 
-   * @param str is the string to get tokens from
-   * @returns string[] are the tokens separated by whitespace within the string
-   */
-  static getWhitespaceTokens(str) {
-    return str.match(/\S+/g);
-  }
-
-  /**
-   * Returns lines separated by newlines from the given string.
-   * 
-   * @param str is the string to get lines from
-   * @param string[] are the lines separated by newlines within the string
-   */
-  static getLines(str) {
-    return str.match(/[^\r\n]+/g);
-  }
-
-  /**
-   * Returns the document's first stylesheet which has no href.
-   * 
-   * @returns StyleSheet is the internal stylesheet
-   */
-  static getInternalStyleSheet() {
-    for (let i = 0; i < document.styleSheets.length; i++) {
-      let styleSheet = document.styleSheets[i];
-      if (!styleSheet.href) return styleSheet;
-    }
-    return null;
-  }
-
-  /**
-   * Returns the document's internal stylesheet as text.
-   * 
-   * @returns str is the document's internal stylesheet
-   */
-  static getInternalStyleSheetText() {
-    let internalCss = "";
-    let internalStyleSheet = getInternalStyleSheet();
-    if (!internalStyleSheet) return null;
-    for (let i = 0; i < internalStyleSheet.cssRules.length; i++) {
-      internalCss += internalStyleSheet.cssRules[i].cssText + "\n";
-    }
-    return internalCss;
-  }
-
-  /**
-   * Manually builds an HTML document string.
-   * 
-   * @param content specifies optional document content
-   *        content.div is a pre-existing div to stringify and add to the body
-   *        content.title is the title of the new tab
-   *        content.dependencyPaths specifies paths to js, css, or img paths
-   *        content.internalCss is css to embed in the html document
-   *        content.metas are meta elements with keys/values to include
-   * @returns str is the document string
-   */
-  static buildHtmlDocument(content) {
-    let str = "<!DOCTYPE HTML>";
-    str += "<html><head>";
-    
-    // add metas
-    if (content.metas) {
-      let metas = listify(content.metas);
-      for (let i = 0; i < metas.length; i++) {
-        let meta = metas[i];
-        let elem = document.createElement("meta");
-        for (let prop in meta) {
-          if (meta.hasOwnProperty(prop)) {
-            elem.setAttribute(prop.toString(), meta[prop.toString()]);
-          }
-        }
-        str += elem.outerHTML;
-      }
-    }
-    
-    // add title and internal css
-    str += content.title ? "<title>" + content.title + "</title>" : "";
-    str += content.internalCss ? "<style>" + content.internalCss + "</style>" : "";
-    
-    // add dependency paths
-    if (content.dependencyPaths) {
-      let dependencyPaths = listify(content.dependencyPaths);
-      for (let i = 0; i < dependencyPaths.length; i++) {
-        let dependencyPath = dependencyPaths[i];
-        if (dependencyPath.endsWith(".js")) str += "<script src='" + dependencyPath + "'></script>";
-        else if (dependencyPath.endsWith(".css")) str += "<link rel='stylesheet' type='text/css' href='" + dependencyPath + "'/>";
-        else if (dependencyPath.endsWith(".png") || dependencyPath.endsWith(".img"))  str += "<img src='" + dependencyPath + "'>";
-        else throw new Error("Unrecognized dependency path extension: " + dependencyPath);      
-      }
-    }
-    str += "</head><body>";
-    if (content.div) str += $("<div>").append(content.div.clone()).html();  // add cloned div as string
-    str += "</body></html>";
-    return str;
-  }
-
-  /**
-   * Opens the given div in a new window.
-   * 
-   * @param content specifies optional window content
-   *        content.div is a pre-existing div to stringify and add to the body
-   *        content.title is the title of the new tab
-   *        content.dependencyPaths specifies paths to js, css, or img paths
-   *        content.internalCss is css to embed in the html document
-   *        content.metas are meta elements with keys/values to include
-   * @param onLoad(err, window) is invoked with a reference to the window when available
-   */
-  static newWindow(content, onLoad) {
-    let onLoadCalled = false;
-    let w = window.open();
-    if (!isInitialized(w) || !isInitialized(w.document)) {
-      onLoadOnce(new Error("Could not get window reference"));
-      return;
-    }
-    w.opener = null;
-    w.document.write(buildHtmlDocument(content));
-    w.addEventListener('load', function() {
-      onLoadOnce(null, w);
-    });
-    w.document.close();
-    
-    // prevents onLoad() from being called multiple times
-    function onLoadOnce(err, window) {
-      if (onLoadCalled) return;
-      onLoadCalled = true;
-      if (onLoad) onLoad(err, window);
-    }
-  }
-
-  /**
-   * Converts the given image to a base64 encoded data url.
-   * 
-   * @param img is the image to convert
-   * @param quality is a number between 0 and 1 specifying the image quality
-   */
-  static imgToDataUrl(img, quality) {
-    let canvas = document.createElement('canvas');
-    canvas.height = img.naturalHeight;
-    canvas.width = img.naturalWidth;
-    let context = canvas.getContext('2d');
-    context.drawImage(img, 0, 0);
-    return canvas.toDataURL(quality);
-  }
-
-  /**
-   * Determines if the image at the given URL is accessible.
-   * 
-   * @param url is the url to an image
-   * @param timeout is the maximum time to wait
-   * @param onDone(bool) when the image is determined to be accessible or not
-   */
-  static isImageAccessible(url, timeout, onDone) {
-    
-    // track return so it only executes once
-    let returned = false;
-    
-    // attempt to load favicon
-    let img = new Image();
-    img.onload = onResponse;
-    img.onerror = onResponse;
-    img.src = url + "?" + (+new Date()); // trigger image load with cache buster
-    
-    // nest failure timeouts to give response a chance when browser is under load
-    setTimeout(function() {
-      setImmediate(function() {
-        setImmediate(function() {
-          setImmediate(function() {
-            if (!returned) {
-              returned = true;
-              onDone(false);
-            }
-          });
-        });
-      });
-    }, timeout);
-    
-    function onResponse(e) {
-      if (returned) return;
-      returned = true;
-      if (typeof e === 'undefined' || e.type === "error") onDone(false);
-      else onDone(true);
-    }
-  }
-
-  /**
-   * Determines if the given file is a zip file.
-   * 
-   * @param file is a file
-   * @returns true if the given file is a zip file, false otherwise
-   */
-  static isZipFile(file) {
-    return file.name.endsWith(".zip") || file.type === 'application/zip';
-  }
-
-  /**
-   * Determines if the given file is a json file.
-   * 
-   * @param file is a file
-   * @returns true if the given file is a json file, false otherwise
-   */
-  static isJsonFile(file) {
-    return file.name.endsWith(".json") || file.type === 'application/json';
-  }
-
-  /**
-   * Determines if the given file is a csv file.
-   * 
-   * @param file is a file
-   * @returns true if the given file is a csv file, false otherwise
-   */
-  static isCsvFile(file) {
-    return file.name.endsWith(".csv") || file.type === 'text/csv';
-  }
-
-  /**
-   * Determines if the given file is a txt file.
-   * 
-   * @param file is a file
-   * @returns true if the given file is a txt file, false otherwise
-   */
-  static isTxtFile(file) {
-    return file.name.endsWith(".txt") || file.type === 'text/plain';
-  }
-
-  /**
-   * Fetches the given list of images.
-   * 
-   * Prerequisite: async.js.
-   * 
-   * @param paths are the paths to the images to fetch
-   * @param onDone(err, images) is called when done
-   */
-  static getImages(paths, onDone) {
-    
-    // listify paths
-    if (!GenUtils.isArray(paths)) {
-      GenUtils.assertTrue(isString(paths));
-      paths = [paths];
-    }
-    
-    // collect functions to fetch images
-    let funcs = [];
-    for (let i = 0; i < paths.length; i++) {
-      funcs.push(loadFunc(paths[i]));
-    }
-    
-    // fetch in parallel
-    async.parallel(funcs, onDone);
-    
-    // callback static to fetch a single image
-    function loadFunc(path) {
-      return function(onDone) {
-        let img = new Image();
-        img.onload = function() { onDone(null, img); }
-        img.onerror = function() { onDone(new Error("Cannot load image: " + path)); }
-        img.src = path;
-      }
-    }
-  }
-  
-  /**
-   * Returns a string indentation of the given length;
-   * 
-   * @param length is the length of the indentation
-   * @returns {string} is an indentation string of the given length
-   */
-  static getIndent(length) {
-    let str = "";
-    for (let i = 0; i < length; i++) str += '  '; // two spaces
-    return str;
-  }
-  
-  static initPolyfills() {
-    
-    // Polyfill Object.assign()
-    // Credit: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
-    if (typeof Object.assign != 'static') {
-      // Must be writable: true, enumerable: false, configurable: true
-      Object.defineProperty(Object, "assign", {
-        value: function assign(target, varArgs) { // .length of static is 2
-          'use strict';
-          if (target == null) { // TypeError if undefined or null
-            throw new TypeError('Cannot convert undefined or null to object');
-          }
-
-          let to = Object(target);
-
-          for (let index = 1; index < arguments.length; index++) {
-            let nextSource = arguments[index];
-
-            if (nextSource != null) { // Skip over if undefined or null
-              for (let nextKey in nextSource) {
-                // Avoid bugs when hasOwnProperty is shadowed
-                if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
-                  to[nextKey] = nextSource[nextKey];
-                }
-              }
-            }
-          }
-          return to;
-        },
-        writable: true,
-        configurable: true
-      });
-    }
-    
-    /**
-     * Polyfill str.replaceAt(idx, replacement).
-     */
-    String.prototype.replaceAt=function(idx, replacement) {
-      return this.substr(0, idx) + replacement + this.substr(idx + replacement.length);
-    }
-
-    /**
-     * Polyfill str.startsWith(searchString, position).
-     * 
-     * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith#Polyfill
-     */
-    String.prototype.startsWith = function(searchString, position) {
-      return this.substr(position || 0, searchString.length) === searchString;
-    };
-
-    /**
-     * Polyfill str.endsWith(searchString, position).
-     * 
-     * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith#Polyfill
-     */
-    String.prototype.endsWith = function(searchString, position) {
-      if (!(position < this.length)) position = this.length;  // works better than >= because it compensates for NaN
-      else position |= 0; // round position
-      return this.substr(position - searchString.length, searchString.length) === searchString;
-    }
-
-    /**
-     * Removes the given value from the array.
-     * 
-     * @returns true if the value was found and removed, false otherwise
-     */
-    Array.prototype.removeVal = function(val) {
-      var found = false;
-      for (var i = 0; i < this.length; i++) {
-        if (this[i] == val) {    
-          found = true;
-          this.splice(i, 1);
-          i--;
-        }
-      }
-      return found;;
-    };
-  }
-
-  /**
-   * Generates a v4 UUID.
-   * 
-   * Source: https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
-   */
-  static getUUID() {
-    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
-      let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
-      return v.toString(16);
-    });
-  }
-  
-  /**
-   * Indicates if the current environment is a browser.
-   * 
-   * @return {boolean} true if the environment is a browser, false otherwise
-   */
-  static isBrowser() {
-    let isWorker = typeof importScripts === 'function';
-    let isBrowserMain = new Function("try {return this===window;}catch(e){return false;}")();
-    return isWorker || isBrowserMain;
-  }
-  
-  /**
-   * Indicates if the current environment is a firefox-based browser.
-   * 
-   * @return {boolean} true if the environment is a firefox-based browser, false otherwise
-   */
-  static isFirefox() {
-    return this.isBrowser() && navigator.userAgent.indexOf("Firefox") > 0;
-  }
-
-  /**
-   * Gets the IE version number.
-   * 
-   * Credit: https://stackoverflow.com/questions/19999388/check-if-user-is-using-ie-with-jquery/21712356#21712356
-   * 
-   * @returns the IE version number of null if not IE
-   */
-  static getIEVersion() {
-    let ua = window.navigator.userAgent;
-
-    let msie = ua.indexOf('MSIE ');
-    if (msie > 0) {
-        // IE 10 or older => return version number
-        return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
-    }
-
-    let trident = ua.indexOf('Trident/');
-    if (trident > 0) {
-        // IE 11 => return version number
-        let rv = ua.indexOf('rv:');
-        return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
-    }
-
-    let edge = ua.indexOf('Edge/');
-    if (edge > 0) {
-       // Edge (IE 12+) => return version number
-       return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
-    }
-
-    // other browser
-    return null;
-  }
-
-  /**
-   * Gets a parameter value.
-   * 
-   * Credit: https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
-   * 
-   * @param name is the name of the parameter to get the value of
-   * @param url is a URL to get the parameter from, uses the window's current href if not given
-   * @returns the parameter's value
-   */
-  static getParameterByName(name, url) {
-    if (!url) url = window.location.href;
-    name = name.replace(/[\[\]]/g, "\\$&");
-    let regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), results = regex.exec(url);
-    if (!results) return null;
-    if (!results[2]) return '';
-    return decodeURIComponent(results[2].replace(/\+/g, " "));
-  }
-  
-  /**
-   * Gets a non-cryptographically secure random number within a given range.
-   * 
-   * @param min is the minimum range of the int to generate, inclusive
-   * @param max is the maximum range of the int to generate, inclusive
-   * 
-   * Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
-   */
-  static getRandomInt(min, max) {
-    min = Math.ceil(min);
-    max = Math.floor(max);
-    return Math.floor(Math.random() * (max - min + 1)) + min;
-  }
-  
-  /**
-   * Gets random ints.
-   * 
-   * @param min is the minimum range of the ints to generate, inclusive
-   * @param max is the maximum range of the ints to generate, inclusive
-   * @param count is the number of random ints to get
-   */
-  static getRandomInts(min, max, count) {
-    GenUtils.assertTrue(typeof count === "number");
-    let ints = [];
-    for (let i = 0; i < count; i++) ints.push(GenUtils.getRandomInt(min, max));
-    return ints;
-  }
-  
-  /**
-   * Gets a given number of unique random ints within a range.
-   * 
-   * @param min is the minimum range of the ints to generate, inclusive
-   * @param max is the maximum range of the ints to generate, inclusive
-   * @param count is the number of unique random ints to get
-   */
-  static getUniqueRandomInts(min, max, count) {
-    let ints = [];
-    GenUtils.assertTrue(count >= 0);
-    GenUtils.assertTrue(max - min + 1 >= count);
-    while (ints.length < count) {
-      let randomInt = GenUtils.getRandomInt(min, max);
-      if (!ints.includes(randomInt)) ints.push(randomInt);
-    }
-    return ints;
-  }
-  
-  /**
-   * Randomize array element order in-place using Durstenfeld shuffle algorithm.
-   * 
-   * Credit: https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
-   */
-  static shuffle(array) {
-    for (var i = array.length - 1; i > 0; i--) {
-      var j = Math.floor(Math.random() * (i + 1));
-      var temp = array[i];
-      array[i] = array[j];
-      array[j] = temp;
-    }
-  }
-  
-  /**
-   * Sorts an array by natural ordering.
-   * 
-   * @param the array to sort
-   */
-  static sort(array) {
-    array.sort((a, b) => a === b ? 0 : a > b ? 1 : -1);
-  }
-  
-  /**
-   * Sets the given value ensuring a previous value is not overwritten.
-   * 
-   * TODO: remove for portability because function passing not supported in other languages, use reconcile only
-   * 
-   * @param obj is the object to invoke the getter and setter on
-   * @param getFn gets the current value
-   * @param setFn sets the current value
-   * @param val is the value to set iff it does not overwrite a previous value
-   * @param config specifies reconciliation configuration
-   *        config.resolveDefined uses defined value if true or undefined, undefined if false
-   *        config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined
-   *        config.resolveMax uses max over min if true, min over max if false, must be equal if undefined
-   * @param errMsg is the error message to throw if the values cannot be reconciled (optional)
-   */
-  static safeSet(obj, getFn, setFn, val, config, errMsg) {
-    let curVal = getFn.call(obj);
-    let reconciledVal = GenUtils.reconcile(curVal, val, config, errMsg);
-    if (curVal !== reconciledVal) setFn.call(obj, reconciledVal);
-  }
-  
-  /**
-   * Reconciles two values.
-   * 
-   * TODO: remove custom error message
-   * 
-   * @param val1 is a value to reconcile
-   * @param val2 is a value to reconcile
-   * @param config specifies reconciliation configuration
-   *        config.resolveDefined uses defined value if true or undefined, undefined if false
-   *        config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined
-   *        config.resolveMax uses max over min if true, min over max if false, must be equal if undefined
-   * @param errMsg is the error message to throw if the values cannot be reconciled (optional)
-   * @returns the reconciled value if reconcilable, throws error otherwise
-   */
-  static reconcile(val1, val2, config, errMsg) {
-    
-    // check for equality
-    if (val1 === val2) return val1;
-    
-    // check for BigInteger equality
-    let comparison; // save comparison for later if applicable
-    if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
-      comparison = val1.compare(val2);  
-      if (comparison === 0) return val1;
-    }
-    
-    // resolve one value defined
-    if (val1 === undefined || val2 === undefined) {
-      if (config && config.resolveDefined === false) return undefined;  // use undefined
-      else return val1 === undefined ? val2 : val1;  // use defined value
-    }
-    
-    // resolve different booleans
-    if (config && config.resolveTrue !== undefined && typeof val1 === "boolean" && typeof val2 === "boolean") {
-      assert.equal(typeof config.resolveTrue, "boolean");
-      return config.resolveTrue;
-    }
-    
-    // resolve different numbers
-    if (config && config.resolveMax !== undefined) {
-      assert.equal(typeof config.resolveMax, "boolean");
-      
-      // resolve js numbers
-      if (typeof val1 === "number" && typeof val2 === "number") {
-        return config.resolveMax ? Math.max(val1, val2) : Math.min(val1, val2);
-      }
-      
-      // resolve BigIntegers
-      if (val1 instanceof BigInteger && val2 instanceof BigInteger) {
-        return config.resolveMax ? (comparison < 0 ? val2 : val1) : (comparison < 0 ? val1 : val2);
-      }
-    }
-    
-    // assert deep equality
-    assert.deepEqual(val1, val2, errMsg ? errMsg : "Cannot reconcile values " + val1 + " and " + val2 + " with config: " + JSON.stringify(config));
-    return val1;
-  }
-  
-  /**
-   * Returns a human-friendly key value line.
-   * 
-   * @param key is the key
-   * @param value is the value
-   * @param indent indents the line
-   * @param newline specifies if the string should be terminated with a newline or not
-   * @param ignoreUndefined specifies if undefined values should return an empty string
-   * @returns {string} is the human-friendly key value line
-   */
-  static kvLine(key, value, indent = 0, newline = true, ignoreUndefined = true) {
-    if (value === undefined && ignoreUndefined) return "";
-    return GenUtils.getIndent(indent) + key + ": " + value + (newline ? '\n' : "");
-  }
-  
-  /**
-   * Replace big integers (16 or more consecutive digits) with strings in order
-   * to preserve numeric precision.
-   * 
-   * @param {string} str is the string to be modified
-   * @return {string} the modified string with big numbers converted to strings
-   */
-  static stringifyBIs(str) {
-    return str.replace(/("[^"]*"\s*:\s*)(\d{16,})/g, '$1"$2"');
-  }
-}
-
-module.exports = GenUtils;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_common_HttpClient.js.html b/docs/src_main_js_common_HttpClient.js.html deleted file mode 100644 index c9851c2eb..000000000 --- a/docs/src_main_js_common_HttpClient.js.html +++ /dev/null @@ -1,533 +0,0 @@ - - - - - JSDoc: Source: src/main/js/common/HttpClient.js - - - - - - - - - - -
- -

Source: src/main/js/common/HttpClient.js

- - - - - - -
-
-
const MoneroUtils = require("./MoneroUtils");
-const PromiseThrottle = require("promise-throttle");
-const Request = require("request-promise");
-
-/**
- * Handle HTTP requests with a uniform interface.
- * 
- * @hideconstructor
- */
-class HttpClient {
-  
-  /**
-   * <p>Make a HTTP request.<p>
-   * 
-   * @param {object} request - configures the request to make
-   * @param {string} request.method - HTTP method ("GET", "PUT", "POST", "DELETE", etc)
-   * @param {string} request.uri - uri to request
-   * @param {string|object|Uint8Array} request.body - request body
-   * @param {string} request.username - username to authenticate the request (optional)
-   * @param {string} request.password - password to authenticate the request (optional)
-   * @param {object} request.headers - headers to add to the request (optional)
-   * @param {string} request.requestApi - one of "fetch" or "xhr" (default "fetch")
-   * @param {boolean} request.resolveWithFullResponse - return full response if true, else body only (default false)
-   * @param {boolean} request.rejectUnauthorized - whether or not to reject self-signed certificates (default true)
-   * @returns {object} response - the response object
-   * @returns {string|object|Uint8Array} response.body - the response body
-   * @returns {number} response.statusCode - the response code
-   * @returns {number} response.statusText - the response message
-   * @returns {object} response.headers - the response headers
-   */
-  static async request(request) {
-    
-    // assign defaults
-    request = Object.assign(HttpClient.DEFAULT_REQUEST, request);
-    
-    // validate request
-    try { new URL(request.uri); } catch (e) { throw new Error("Invalid request URL: " + request.uri); }
-    if (request.body && !(typeof request.body === "string" || typeof request.body === "object")) {
-      throw new Error("Request body type is not string or object");
-    }
-    
-    // initialize promise throttle one time
-    if (!HttpClient.PROMISE_THROTTLE) {
-      HttpClient.PROMISE_THROTTLE = new PromiseThrottle({
-        requestsPerSecond: MoneroUtils.MAX_REQUESTS_PER_SECOND,
-        promiseImplementation: Promise
-      });
-    }
-    
-    // request using fetch or xhr
-    return request.requestApi === "fetch" ? HttpClient._requestFetch(request) : HttpClient._requestXhr(request);
-  }
-  
-  // ----------------------------- PRIVATE HELPERS ----------------------------
-  
-  static async _requestFetch(req) {
-    
-    // build request options
-    let opts = {
-      method: req.method,
-      uri: req.uri,
-      body: req.body,
-      agent: req.uri.startsWith("https") ? HttpClient._getHttpsAgent() : HttpClient._getHttpAgent(),
-      rejectUnauthorized: req.rejectUnauthorized,
-      resolveWithFullResponse: req.resolveWithFullResponse,
-      requestCert: true // TODO: part of config?
-    };
-    if (req.username) {
-      opts.forever = true;
-      opts.auth = {
-        user: req.username,
-        pass: req.password,
-        sendImmediately: false
-      }
-    }
-    if (req.body instanceof Uint8Array) opts.encoding = null;
-    
-    // queue and throttle request to execute in serial and rate limited
-    let resp = await HttpClient._queueTask(async function() {
-      return HttpClient.PROMISE_THROTTLE.add(function(opts) { return Request(opts); }.bind(this, opts));
-    });
-    
-    // normalize response
-    let normalizedResponse = {};
-    if (req.resolveWithFullResponse) {
-      normalizedResponse.statusCode = resp.statusCode;
-      normalizedResponse.statusText = resp.statusMessage;
-      normalizedResponse.headers = resp.headers;
-      normalizedResponse.body = resp.body;
-    } else {
-      normalizedResponse.body = resp;
-    }
-    return normalizedResponse;
-  }
-  
-  static async _requestXhr(req) {
-    if (req.headers) throw new Error("Custom headers not implemented in XHR request");  // TODO
-    
-    // collect params from request which change on await
-    let method = req.method;
-    let uri = req.uri;
-    let username = req.username;
-    let password = req.password;
-    let body = req.body;
-    let isBinary = body instanceof Uint8Array;
-    
-    // queue and throttle request to execute in serial and rate limited
-    let resp = await HttpClient._queueTask(async function() {
-      return HttpClient.PROMISE_THROTTLE.add(function() {
-        return new Promise(function(resolve, reject) {
-          let digestAuthRequest = new HttpClient.digestAuthRequest(method, uri, username, password);
-          digestAuthRequest.request(function(resp) {
-            resolve(resp);
-          }, function(resp) {
-            if (resp.status) resolve(resp);
-            else reject(new Error("Request failed without response: " + method + " " + uri));
-          }, body);
-        });
-      }.bind(this));
-    });
-    
-    // normalize response
-    let normalizedResponse = {};
-    normalizedResponse.statusCode = resp.status;
-    normalizedResponse.statusText = resp.statusText;
-    normalizedResponse.headers = HttpClient._parseXhrResponseHeaders(resp.getAllResponseHeaders());
-    normalizedResponse.body = isBinary ? new Uint8Array(resp.response) : resp.response;
-    if (normalizedResponse.body instanceof ArrayBuffer) normalizedResponse.body = new Uint8Array(normalizedResponse.body);  // handle empty binary request
-    return normalizedResponse;
-  }
-  
-  /**
-   * Executes given tasks serially (first in, first out).
-   * 
-   * @param {function} asyncFn is an asynchronous function to execute after previously given tasks
-   */
-  static async _queueTask(asyncFn) {
-    
-    // initialize task queue one time
-    if (!HttpClient.TASK_QUEUE) {
-      const async = require("async");
-      HttpClient.TASK_QUEUE = async.queue(function(asyncFn, callback) {
-        if (asyncFn.then) asyncFn.then(resp => { callback(resp); }).catch(err => { callback(undefined, err); });
-        else asyncFn().then(resp => { callback(resp); }).catch(err => { callback(undefined, err); });
-      }, 1);
-    }
-    
-    // return promise which resolves when task is executed
-    return new Promise(function(resolve, reject) {
-      HttpClient.TASK_QUEUE.push(asyncFn, function(resp, err) {
-        if (err !== undefined) reject(err);
-        else resolve(resp);
-      });
-    });
-  }
-  
-  /**
-   * Get a singleton instance of an HTTP client to share.
-   * 
-   * @return {http.Agent} a shared agent for network requests among library instances
-   */
-  static _getHttpAgent() {
-    if (!HttpClient.HTTP_AGENT) {
-      let http = require('http');
-      HttpClient.HTTP_AGENT = new http.Agent({keepAlive: true});
-    }
-    return HttpClient.HTTP_AGENT;
-  }
-  
-  /**
-   * Get a singleton instance of an HTTPS client to share.
-   * 
-   * @return {https.Agent} a shared agent for network requests among library instances
-   */
-  static _getHttpsAgent() {
-    if (!HttpClient.HTTPS_AGENT) {
-      let https = require('https');
-      HttpClient.HTTPS_AGENT = new https.Agent({keepAlive: true});
-    }
-    return HttpClient.HTTPS_AGENT;
-  }
-  
-  
-  static _parseXhrResponseHeaders(headersStr) {
-    let headerMap = {};
-    let headers = headersStr.trim().split(/[\r\n]+/);
-    for (let header of headers) {
-      let headerVals = header.split(": ");
-      headerMap[headerVals[0]] = headerVals[1];
-    }
-    return headerMap;
-  }
-}
-
-// default request config
-HttpClient.DEFAULT_REQUEST = {
-  method: "GET",
-  requestApi: "fetch",
-  resolveWithFullResponse: false,
-  rejectUnauthorized: true
-}
-
-/**
- * Modification of digest auth request by @inorganik.
- * 
- * Dependent on CryptoJS MD5 hashing: http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5.js
- * 
- * MIT licensed.
- */
-HttpClient.digestAuthRequest = function(method, url, username, password) {
-  var self = this;
-
-  if (typeof CryptoJS === 'undefined' && typeof require === 'function') {
-    var CryptoJS = require('crypto-js');
-  }
-
-  this.scheme = null; // we just echo the scheme, to allow for 'Digest', 'X-Digest', 'JDigest' etc
-  this.nonce = null; // server issued nonce
-  this.realm = null; // server issued realm
-  this.qop = null; // "quality of protection" - '' or 'auth' or 'auth-int'
-  this.response = null; // hashed response to server challenge
-  this.opaque = null; // hashed response to server challenge
-  this.nc = 1; // nonce count - increments with each request used with the same nonce
-  this.cnonce = null; // client nonce
-
-  // settings
-  this.timeout = 60000; // timeout
-  this.loggingOn = false; // toggle console logging
-
-  // determine if a post, so that request will send data
-  this.post = false;
-  if (method.toLowerCase() === 'post' || method.toLowerCase() === 'put') {
-    this.post = true;
-  }
-
-  // start here
-  // successFn - will be passed JSON data
-  // errorFn - will be passed the failed authenticatedRequest
-  // data - optional, for POSTS
-  this.request = function(successFn, errorFn, data) {
-    
-    // stringify json
-    if (data) {
-      try {
-        self.data = data instanceof Uint8Array || typeof data === "string" ? data : JSON.stringify(data);
-      } catch (e) {
-        console.error(e);
-        throw e;
-      }
-    }
-    self.successFn = successFn;
-    self.errorFn = errorFn;
-
-    if (!self.nonce) {
-      self.makeUnauthenticatedRequest(self.data);
-    } else {
-      self.makeAuthenticatedRequest();
-    }
-  }
-  this.makeUnauthenticatedRequest = function(data) {
-    self.firstRequest = new XMLHttpRequest();
-    self.firstRequest.open(method, url, true);
-    self.firstRequest.timeout = self.timeout;
-    // if we are posting, add appropriate headers
-    if (self.post && data) {
-      if (typeof data === "string") {
-        self.firstRequest.setRequestHeader('Content-type', 'text/plain');
-      } else {
-        self.firstRequest.responseType = "arraybuffer";
-      }
-    }
-
-    self.firstRequest.onreadystatechange = function() {
-
-      // 2: received headers,  3: loading, 4: done
-      if (self.firstRequest.readyState === 2) {
-
-        var responseHeaders = self.firstRequest.getAllResponseHeaders();
-        responseHeaders = responseHeaders.split('\n');
-        // get authenticate header
-        var digestHeaders;
-        for(var i = 0; i < responseHeaders.length; i++) {
-          if (responseHeaders[i].match(/www-authenticate/i) != null) {
-            digestHeaders = responseHeaders[i];
-          }
-        }
-
-        if (digestHeaders != null) {
-          // parse auth header and get digest auth keys
-          digestHeaders = digestHeaders.slice(digestHeaders.indexOf(':') + 1, -1);
-          digestHeaders = digestHeaders.split(',');
-          self.scheme = digestHeaders[0].split(/\s/)[1];
-          for (var i = 0; i < digestHeaders.length; i++) {
-            var equalIndex = digestHeaders[i].indexOf('='),
-              key = digestHeaders[i].substring(0, equalIndex),
-              val = digestHeaders[i].substring(equalIndex + 1);
-            val = val.replace(/['"]+/g, '');
-            // find realm
-            if (key.match(/realm/i) != null) {
-              self.realm = val;
-            }
-            // find nonce
-            if (key.match(/nonce/i) != null) {
-              self.nonce = val;
-            }
-            // find opaque
-            if (key.match(/opaque/i) != null) {
-              self.opaque = val;
-            }
-            // find QOP
-            if (key.match(/qop/i) != null) {
-              self.qop = val;
-            }
-          }
-          // client generated keys
-          self.cnonce = self.generateCnonce();
-          self.nc++;
-          // if logging, show headers received:
-          self.log('received headers:');
-          self.log('  realm: '+self.realm);
-          self.log('  nonce: '+self.nonce);
-          self.log('  opaque: '+self.opaque);
-          self.log('  qop: '+self.qop);
-          // now we can make an authenticated request
-          self.makeAuthenticatedRequest();
-        }
-      }
-      if (self.firstRequest.readyState === 4) {
-        if (self.firstRequest.status === 200) {
-          self.log('Authentication not required for '+url);
-          if (data instanceof Uint8Array) {
-            console.log("BINARY RESPONSE 1");
-            self.successFn(self.firstRequest);
-          } else {
-            if (self.firstRequest.responseText !== 'undefined') {
-              if (self.firstRequest.responseText.length > 0) {
-                // If JSON, parse and return object
-                if (self.isJson(self.firstRequest.responseText)) {  // TODO: redundant
-                  self.successFn(self.firstRequest);
-                } else {
-                  self.successFn(self.firstRequest);
-                }
-              }
-            } else {
-              self.successFn();
-            }
-          }
-        }
-      }
-    }
-    // send
-    if (self.post) {
-      // in case digest auth not required
-      self.firstRequest.send(self.data);
-    } else {
-      self.firstRequest.send();
-    }
-    self.log('Unauthenticated request to '+url);
-
-    // handle error
-    self.firstRequest.onerror = function() {
-      if (self.firstRequest.status !== 401) {
-        self.log('Error ('+self.firstRequest.status+') on unauthenticated request to '+url);
-        self.errorFn(self.firstRequest);
-      }
-    }
-  }
-  this.makeAuthenticatedRequest= function() {
-
-    self.response = self.formulateResponse();
-    self.authenticatedRequest = new XMLHttpRequest();
-    self.authenticatedRequest.open(method, url, true);
-    self.authenticatedRequest.timeout = self.timeout;
-    var digestAuthHeader = self.scheme+' '+
-      'username="'+username+'", '+
-      'realm="'+self.realm+'", '+
-      'nonce="'+self.nonce+'", '+
-      'uri="'+url+'", '+
-      'response="'+self.response+'", '+
-      'opaque="'+self.opaque+'", '+
-      'qop='+self.qop+', '+
-      'nc='+('00000000' + self.nc).slice(-8)+', '+
-      'cnonce="'+self.cnonce+'"';
-    self.authenticatedRequest.setRequestHeader('Authorization', digestAuthHeader);
-    self.log('digest auth header response to be sent:');
-    self.log(digestAuthHeader);
-    // if we are posting, add appropriate headers
-    if (self.post && self.data) {
-      if (typeof self.data === "string") {
-        self.authenticatedRequest.setRequestHeader('Content-type', 'text/plain');
-      } else {
-        self.authenticatedRequest.responseType = "arraybuffer";        
-      }
-    }
-    self.authenticatedRequest.onload = function() {
-      // success
-      if (self.authenticatedRequest.status >= 200 && self.authenticatedRequest.status < 400) {
-        // increment nonce count
-        self.nc++;
-        // return data
-        if (self.data instanceof Uint8Array) {
-          self.successFn(self.authenticatedRequest);
-        } else {
-          if (self.authenticatedRequest.responseText !== 'undefined' && self.authenticatedRequest.responseText.length > 0 ) {
-            // If JSON, parse and return object
-            if (self.isJson(self.authenticatedRequest.responseText)) {  // TODO: redundant from not parsing
-              self.successFn(self.authenticatedRequest);
-            } else {
-              self.successFn(self.authenticatedRequest);
-            }
-          } else {
-           self.successFn();
-          }
-        }
-      }
-      // failure
-      else {
-        self.nonce = null;
-        self.errorFn(self.authenticatedRequest);
-      }
-    }
-    // handle errors
-    self.authenticatedRequest.onerror = function() {
-      self.log('Error ('+self.authenticatedRequest.status+') on authenticated request to '+url);
-      self.nonce = null;
-      self.errorFn(self.authenticatedRequest);
-    };
-    // send
-    if (self.post) {
-      self.authenticatedRequest.send(self.data);
-    } else {
-      self.authenticatedRequest.send();
-    }
-    self.log('Authenticated request to '+url);
-  }
-  // hash response based on server challenge
-  this.formulateResponse = function() {
-    var HA1 = CryptoJS.MD5(username+':'+self.realm+':'+password).toString();
-    var HA2 = CryptoJS.MD5(method+':'+url).toString();
-    var response = CryptoJS.MD5(HA1+':'+
-      self.nonce+':'+
-      ('00000000' + self.nc).slice(-8)+':'+
-      self.cnonce+':'+
-      self.qop+':'+
-      HA2).toString();
-    return response;
-  }
-  // generate 16 char client nonce
-  this.generateCnonce = function() {
-    var characters = 'abcdef0123456789';
-    var token = '';
-    for (var i = 0; i < 16; i++) {
-      var randNum = Math.round(Math.random() * characters.length);
-      token += characters.substr(randNum, 1);
-    }
-    return token;
-  }
-  this.abort = function() {
-    self.log('[digestAuthRequest] Aborted request to '+url);
-    if (self.firstRequest != null) {
-      if (self.firstRequest.readyState != 4) self.firstRequest.abort();
-    }
-    if (self.authenticatedRequest != null) {
-      if (self.authenticatedRequest.readyState != 4) self.authenticatedRequest.abort();
-    }
-  }
-  this.isJson = function(str) {
-    try {
-      JSON.parse(str);
-    } catch (e) {
-      return false;
-    }
-    return true;
-  }
-  this.log = function(str) {
-    if (self.loggingOn) {
-      console.log('[digestAuthRequest] '+str);
-    }
-  }
-  this.version = function() { return '0.8.0' }
-}
-
-module.exports = HttpClient;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_common_LibraryUtils.js.html b/docs/src_main_js_common_LibraryUtils.js.html deleted file mode 100644 index 2ad3ffa44..000000000 --- a/docs/src_main_js_common_LibraryUtils.js.html +++ /dev/null @@ -1,226 +0,0 @@ - - - - - JSDoc: Source: src/main/js/common/LibraryUtils.js - - - - - - - - - - -
- -

Source: src/main/js/common/LibraryUtils.js

- - - - - - -
-
-
const assert = require("assert");
-const GenUtils = require("./GenUtils");
-const MoneroError = require("./MoneroError");
-
-/**
- * Collection of helper utilities for the library.
- * 
- * @hideconstructor
- */
-class LibraryUtils {
-  
-  /**
-   * Get the total memory used by WebAssembly.
-   * 
-   * @return {int} the total memory used by WebAssembly
-   */
-  static async getWasmMemoryUsed() {
-    let total = 0;
-    if (LibraryUtils.WORKER) total += await LibraryUtils.invokeWorker(GenUtils.getUUID(), "getWasmMemoryUsed", []);
-    if (LibraryUtils.getWasmModule() && LibraryUtils.getWasmModule().HEAP8) total += LibraryUtils.getWasmModule().HEAP8.length;
-    return total;
-  }
-  
-  /**
-   * Get the WebAssembly module in the current context (nodejs, browser main thread or worker).
-   */
-  static getWasmModule() {
-    return LibraryUtils.WASM_MODULE;
-  }
-  
-  /**
-   * Load the WebAssembly keys module with caching.
-   */
-  static async loadKeysModule() {
-    
-    // use cache if suitable, core module supersedes keys module because it is superset
-    if (LibraryUtils.WASM_MODULE) return LibraryUtils.WASM_MODULE;
-    
-    // load module
-    delete LibraryUtils.WASM_MODULE;
-    LibraryUtils.WASM_MODULE = require("../../../../dist/monero_core_keys")();
-    return new Promise(function(resolve, reject) {
-      LibraryUtils.WASM_MODULE.then(module => {
-        LibraryUtils.WASM_MODULE = module
-        delete LibraryUtils.WASM_MODULE.then;
-        LibraryUtils._initWasmModule(LibraryUtils.WASM_MODULE);
-        resolve(LibraryUtils.WASM_MODULE);
-      });
-    });
-  }
-  
-  /**
-   * Load the WebAssembly core module with caching.
-   * 
-   * The core module is a superset of the keys module and overrides it.
-   * 
-   * TODO: this is separate static function from loadKeysModule() because webpack cannot bundle WebWorker using runtime param for conditional import
-   */
-  static async loadCoreModule() {
-    
-    // use cache if suitable, core module supersedes keys module because it is superset
-    if (LibraryUtils.WASM_MODULE && LibraryUtils.CORE_LOADED) return LibraryUtils.WASM_MODULE;
-    
-    // load module
-    delete LibraryUtils.WASM_MODULE;
-    LibraryUtils.WASM_MODULE = require("../../../../dist/monero_core")();
-    return new Promise(function(resolve, reject) {
-      LibraryUtils.WASM_MODULE.then(module => {
-        LibraryUtils.WASM_MODULE = module
-        delete LibraryUtils.WASM_MODULE.then;
-        LibraryUtils.CORE_LOADED = true;
-        LibraryUtils._initWasmModule(LibraryUtils.WASM_MODULE);
-        resolve(LibraryUtils.WASM_MODULE);
-      });
-    });
-  }
-  
-  /**
-   * Private helper to initialize the wasm module with data structures to synchronize access.
-   */
-  static _initWasmModule(wasmModule) {
-    
-    // initialize data structure to synchronize access to wasm module
-    const async = require("async");
-    wasmModule.taskQueue = async.queue(function(asyncFn, callback) {
-      if (asyncFn.then) asyncFn.then(resp => { callback(resp); }).catch(err => { callback(undefined, err); });
-      else asyncFn().then(resp => { callback(resp); }).catch(err => { callback(undefined, err); });
-    }, 1);
-    
-    // initialize method to synchronize access to wasm module
-    wasmModule.queueTask = async function(asyncFn) {
-      return new Promise(function(resolve, reject) {
-        wasmModule.taskQueue.push(asyncFn, function(resp, err) {
-          if (err !== undefined) reject(err);
-          else resolve(resp);
-        });
-      });
-    }
-  }
-  
-  /**
-   * Register a function by id which informs if unauthorized requests (e.g.
-   * self-signed certificates) should be rejected.
-   * 
-   * @param {string} fnId - unique identifier for the function
-   * @param {function} fn - function to inform if unauthorized requests should be rejected
-   */
-  static setRejectUnauthorizedFn(fnId, fn) {
-    if (!LibraryUtils.REJECT_UNAUTHORIZED_FNS) LibraryUtils.REJECT_UNAUTHORIZED_FNS = [];
-    if (fn === undefined) delete LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId];
-    else LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId] = fn;
-  }
-  
-  /**
-   * Indicate if unauthorized requests should be rejected.
-   * 
-   * @param {string} fnId - uniquely identifies the function
-   */
-  static isRejectUnauthorized(fnId) {
-    if (!LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId]) throw new Error("No function registered with id " + fnId + " to inform if unauthorized reqs should be rejected");
-    return LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId]();
-  }
-  
-  /**
-   * Get a singleton instance of a web worker to share.
-   * 
-   * @return {Worker} a worker to share among wallet instances
-   */
-  static getWorker() {
-    
-    // one time initialization
-    if (!LibraryUtils.WORKER) {
-      LibraryUtils.WORKER = new Worker("MoneroWebWorker.dist.js");
-      LibraryUtils.WORKER_OBJECTS = {};  // store per object running in the worker
-      
-      // catch worker messages
-      LibraryUtils.WORKER.onmessage = function(e) {
-        
-        // lookup object id, callback function, and this arg
-        let thisArg = null;
-        let callbackFn = LibraryUtils.WORKER_OBJECTS[e.data[0]].callbacks[e.data[1]]; // look up by object id then by function name
-        if (callbackFn === undefined) throw new Error("No worker callback function defined for key '" + e.data[1] + "'");
-        if (callbackFn instanceof Array) {  // this arg may be stored with callback function
-          thisArg = callbackFn[1];
-          callbackFn = callbackFn[0];
-        }
-        
-        // invoke callback function with this arg and arguments
-        callbackFn.apply(thisArg, e.data.slice(2));
-      }
-    }
-    return LibraryUtils.WORKER;
-  }
-  
-  /**
-   * Invoke a web worker function and get the result with error handling.
-   * 
-   * @param {objectId} identifies the worker object to invoke
-   * @param {string} fnName is the name of the function to invoke
-   * @param {Object[]} args are function arguments to invoke with
-   * @return {Promise} resolves with response payload from the worker or an error
-   */
-  static async invokeWorker(objectId, fnName, args) {
-    assert(fnName.length >= 2);
-    let worker = LibraryUtils.getWorker();
-    if (!LibraryUtils.WORKER_OBJECTS[objectId]) LibraryUtils.WORKER_OBJECTS[objectId] = {callbacks: {}};
-    return new Promise(function(resolve, reject) {
-      LibraryUtils.WORKER_OBJECTS[objectId].callbacks["on" + fnName.charAt(0).toUpperCase() + fnName.substring(1)] = function(resp) {  // TODO: this defines function once per callback
-        resp ? (resp.error ? reject(new MoneroError(resp.error)) : resolve(resp.result)) : resolve();
-      };
-      worker.postMessage([objectId, fnName].concat(args === undefined ? [] : GenUtils.listify(args)));
-    });
-  }
-}
-
-module.exports = LibraryUtils;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_common_MoneroError.js.html b/docs/src_main_js_common_MoneroError.js.html deleted file mode 100644 index acc6b817e..000000000 --- a/docs/src_main_js_common_MoneroError.js.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - - JSDoc: Source: src/main/js/common/MoneroError.js - - - - - - - - - - -
- -

Source: src/main/js/common/MoneroError.js

- - - - - - -
-
-
/**
- * Exception when interacting with a Monero wallet or daemon.
- */
-class MoneroError extends Error {
-  
-  /**
-   * Constructs the error.
-   * 
-   * @param {string} message is a human-readable message of the error
-   * @param {int} code is the error code (optional)
-   */
-  constructor(message, code) {
-    super(message);
-    this.code = code;
-  }
-  
-  getCode() {
-    return this.code;
-  }
-  
-  toString() {
-    if (this.message === undefined && this.getCode() === undefined) return super.message;
-    let str = "";
-    if (this.getCode() !== undefined) str += this.getCode() + ": ";
-    str += this.message;
-    return str;
-  }
-}
-
-module.exports = MoneroError;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_common_MoneroRpcConnection.js.html b/docs/src_main_js_common_MoneroRpcConnection.js.html deleted file mode 100644 index 48a4a803d..000000000 --- a/docs/src_main_js_common_MoneroRpcConnection.js.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - - JSDoc: Source: src/main/js/common/MoneroRpcConnection.js - - - - - - - - - - -
- -

Source: src/main/js/common/MoneroRpcConnection.js

- - - - - - -
-
-
const GenUtils = require("./GenUtils");
-const HttpClient = require("./HttpClient");
-const LibraryUtils = require("./LibraryUtils");
-const MoneroError = require("../common/MoneroError");
-const MoneroRpcError = require("../common/MoneroRpcError");
-const MoneroUtils = require("./MoneroUtils");
-
-/**
- * Maintains a connection and sends requests to a Monero RPC API.
- */
-class MoneroRpcConnection {
-  
-  /**
-   * <p>Construct a RPC connection.</p>
-   * 
-   * <p>Examples:</p>
-   * 
-   * <code>
-   * let connection1 = new MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123")<br><br>
-   * 
-   * let connection2 = new MoneroRpcConnection({<br>
-   * &nbsp;&nbsp; uri: http://localhost:38081,<br>
-   * &nbsp;&nbsp; username: "daemon_user",<br>
-   * &nbsp;&nbsp; password: "daemon_password_123",<br>
-   * &nbsp;&nbsp; rejectUnauthorized: false // accept self-signed certificates e.g. for local development<br>
-   * });
-   * </code>
-   * 
-   * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - RPC endpoint URI, MoneroRpcConnection, or equivalent JS object
-   * @param {string} uriOrConfigOrConnection.uri - URI of the RPC endpoint
-   * @param {string} uriOrConfigOrConnection.username - username to authenticate with the RPC endpoint (optional)
-   * @param {string} uriOrConfigOrConnection.password - password to authenticate with the RPC endpoint (optional)
-   * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true)
-   * @param {string} username - username to authenticate with the RPC endpoint (optional)
-   * @param {string} password - password to authenticate with the RPC endpoint (optional)
-   * @param {boolean} rejectUnauthorized - reject self-signed certificates if true (default true)
-   */
-  constructor(uriOrConfigOrConnection, username, password, rejectUnauthorized) {
-    
-    // validate and normalize config
-    if (typeof uriOrConfigOrConnection === "string") {
-      this.config = {uri: uriOrConfigOrConnection};
-      if (username !== undefined) this.config.username = username;
-      if (password !== undefined) this.config.password = password;
-      if (rejectUnauthorized !== undefined) this.config.rejectUnauthorized = rejectUnauthorized;
-    } else if (typeof uriOrConfigOrConnection === "object") {
-      if (username !== undefined || password !== undefined || rejectUnauthorized !== undefined) throw new MoneroError("Can provide config object or params but not both");
-      if (uriOrConfigOrConnection instanceof MoneroRpcConnection) this.config = Object.assign({}, uriOrConfigOrConnection.getConfig());
-      else this.config = Object.assign({}, uriOrConfigOrConnection);
-    } else if (uriOrConfigOrConnection !== undefined) {
-      throw new MoneroError("Invalid configuration to MoneroRpcConnection; must be string or MoneroRpcConnection or equivalent JS object");
-    }
-    
-    // merge default config
-    this.config = Object.assign({}, MoneroRpcConnection.DEFAULT_CONFIG, this.config);
-    
-    // standardize uri
-    if (this.config.uri) this.config.uri = this.config.uri.replace(/\/$/, ""); // strip trailing slash
-    
-    // fail with friendly message if using old api
-    if (this.config.user || this.config.pass) throw new MoneroError("Authentication fields 'user' and 'pass' have been renamed to 'username' and 'password'.  Please update to the new api");
-  }
-  
-  getUri() {
-    return this.config.uri;
-  }
-  
-  getUsername() {
-    return this.config.username;
-  }
-  
-  getPassword() {
-    return this.config.password;
-  }
-  
-  getRejectUnauthorized() {
-    return this.config.rejectUnauthorized;
-  }
-  
-  getConfig() {
-    return this.config;
-  }
-  
-  /**
-   * Sends a JSON RPC request.
-   * 
-   * @param method is the JSON RPC method to invoke
-   * @param params are request parameters
-   * @return {object} is the response map
-   */
-  async sendJsonRequest(method, params) {
-    //console.log("sendJsonRequest(" + method + ", " + JSON.stringify(params) + ")");
-    
-    try {
-      // tx config
-      let resp = await HttpClient.request({
-        method: "POST",
-        uri: this.getUri() + '/json_rpc',
-        username: this.getUsername(),
-        password: this.getPassword(),
-        body: JSON.stringify({  // body is stringified so text/plain is returned so BigIntegers are preserved
-          id: "0",
-          jsonrpc: "2.0",
-          method: method,
-          params: params
-        }),
-        rejectUnauthorized: this.config.rejectUnauthorized,
-        requestApi: GenUtils.isFirefox() ? "xhr" : "fetch"  // firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1491010
-      });
-      
-      // process response
-      resp = JSON.parse(resp.body.replace(/("[^"]*"\s*:\s*)(\d{16,})/g, '$1"$2"'));  // replace 16 or more digits with strings and parse
-      if (resp.error) throw new MoneroRpcError(resp.error.message, resp.error.code, method, params);
-      return resp;
-    } catch (e) {
-      if (e instanceof MoneroRpcError) throw e;
-      else throw new MoneroRpcError(e, undefined, method, params);
-    }
-  }
-  
-  /**
-   * Sends a RPC request to the given path and with the given paramters.
-   * 
-   * E.g. "/get_transactions" with params
-   */
-  async sendPathRequest(path, params) {
-    //console.log("sendPathRequest(" + path + ", " + JSON.stringify(params) + ")");
-    
-    try {
-      // tx config
-      let resp = await HttpClient.request({
-        method: "POST",
-        uri: this.getUri() + '/' + path,
-        username: this.getUsername(),
-        password: this.getPassword(),
-        body: JSON.stringify(params),  // body is stringified so text/plain is returned so BigIntegers are preserved
-        rejectUnauthorized: this.config.rejectUnauthorized,
-        requestApi: GenUtils.isFirefox() ? "xhr" : "fetch"
-      });
-      
-      // process response
-      resp = JSON.parse(resp.body.replace(/("[^"]*"\s*:\s*)(\d{16,})/g, '$1"$2"'));  // replace 16 or more digits with strings and parse
-      if (typeof resp === "string") resp = JSON.parse(resp);  // TODO: some responses returned as strings?
-      if (resp.error) throw new MoneroRpcError(resp.error.message, resp.error.code, path, params);
-      return resp;
-    } catch (e) {
-      if (e instanceof MoneroRpcError) throw e;
-      else throw new MoneroRpcError(e, undefined, path, params);
-    }
-  }
-  
-  /**
-   * Sends a binary RPC request.
-   * 
-   * @param path is the path of the binary RPC method to invoke
-   * @paramm params are the request parameters
-   * @return a Uint8Array with the binary response
-   */
-  async sendBinaryRequest(path, params) {
-    //console.log("sendBinaryRequest(" + path + ", " + JSON.stringify(params) + ")");
-    
-    // load wasm module
-    await LibraryUtils.loadKeysModule();
-    
-    // serialize params
-    let paramsBin = MoneroUtils.jsonToBinary(params);
-    
-    try {
-      // tx config
-      let resp = await HttpClient.request({
-        method: "POST",
-        uri: this.getUri() + '/' + path,
-        username: this.getUsername(),
-        password: this.getPassword(),
-        body: paramsBin,
-        rejectUnauthorized: this.config.rejectUnauthorized,
-        requestApi: GenUtils.isFirefox() ? "xhr" : "fetch"
-      });
-      
-      // process response
-      resp = resp.body;
-      if (!(resp instanceof Uint8Array)) {
-        console.error("resp is not uint8array");
-        console.error(resp);
-      }
-      if (resp.error) throw new MoneroRpcError(resp.error.message, resp.error.code, path, params);
-      return resp;
-    } catch (e) {
-      if (e instanceof MoneroRpcError) throw e;
-      else throw new MoneroRpcError(e, undefined, path, params);
-    }
-  }
-}
-
-
-/**
- * Default RPC configuration.
- */
-MoneroRpcConnection.DEFAULT_CONFIG = {
-    uri: undefined,
-    username: undefined,
-    password: undefined,
-    rejectUnauthorized: true  // reject self-signed certificates if true
-}
-
-MoneroRpcConnection.SUPPORTED_FIELDS = ["uri", "username", "password", "rejectUnauthorized"];
-
-module.exports = MoneroRpcConnection;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_common_MoneroRpcError.js.html b/docs/src_main_js_common_MoneroRpcError.js.html deleted file mode 100644 index c9c13f02b..000000000 --- a/docs/src_main_js_common_MoneroRpcError.js.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - JSDoc: Source: src/main/js/common/MoneroRpcError.js - - - - - - - - - - -
- -

Source: src/main/js/common/MoneroRpcError.js

- - - - - - -
-
-
const MoneroError = require("./MoneroError");
-
-/**
- * Error when interacting with Monero RPC.
- */
-class MoneroRpcError extends MoneroError {
-  
-  /**
-   * Constructs the error.
-   * 
-   * @param {string} rpcDescription is a description of the error from rpc
-   * @param {int} rpcCode is the error code from rpc
-   * @param {string} rpcMethod is the rpc method invoked
-   * @param {object} rpcParams are parameters sent with the rpc request
-   */
-  constructor(rpcDescription, rpcCode, rpcMethod, rpcParams) {
-    super(rpcDescription, rpcCode);
-    this.rpcMethod = rpcMethod;
-    this.rpcParams = rpcParams;
-  }
-  
-  getRpcMethod() {
-    return this.rpcMethod;
-  }
-  
-  getRpcParams() {
-    return this.rpcParams;
-  }
-  
-  toString() {
-    let str = super.toString();
-    if (this.rpcMethod || this.rpcParams) str += "\nRequest: '" + this.rpcMethod + "' with params: " + (typeof this.rpcParams === "object" ? JSON.stringify(this.rpcParams) : this.rpcParams);
-    return str;
-  }
-}
-
-module.exports = MoneroRpcError;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_common_MoneroUtils.js.html b/docs/src_main_js_common_MoneroUtils.js.html deleted file mode 100644 index fdd64c278..000000000 --- a/docs/src_main_js_common_MoneroUtils.js.html +++ /dev/null @@ -1,288 +0,0 @@ - - - - - JSDoc: Source: src/main/js/common/MoneroUtils.js - - - - - - - - - - -
- -

Source: src/main/js/common/MoneroUtils.js

- - - - - - -
-
-
const assert = require("assert");
-const GenUtils = require("./GenUtils");
-const LibraryUtils = require("./LibraryUtils");
-const MoneroError = require("./MoneroError");
-
-/**
- * Collection of Monero utilities.
- * 
- * @hideconstructor
- */
-class MoneroUtils {
-  
-  // TODO: improve validation
-  static validateMnemonic(mnemonic) {
-    assert(mnemonic, "Mnemonic phrase is not initialized");
-    let words = mnemonic.split(" ");
-    if (words.length !== MoneroUtils.NUM_MNEMONIC_WORDS) throw new Error("Mnemonic phrase is " + words.length + " words but must be " + MoneroUtils.NUM_MNEMONIC_WORDS);
-  }
-  
-  // TODO: improve validation
-  static validatePrivateViewKey(privateViewKey) {
-    assert(typeof privateViewKey === "string");
-    assert(privateViewKey.length === 64);
-  }
-  
-  // TODO: improve validation
-  static validatePrivateSpendKey(privateSpendKey) {
-    assert(typeof privateSpendKey === "string");
-    assert(privateSpendKey.length === 64);
-  }
-  
-  // TODO: improve validation
-  static validatePublicViewKey(publicViewKey) {
-    assert(typeof publicViewKey === "string");
-    assert(publicViewKey.length === 64);
-  }
-  
-  // TODO: improve validation
-  static validatePublicSpendKey(publicSpendKey) {
-    assert(typeof publicSpendKey === "string");
-    assert(publicSpendKey.length === 64);
-  }
-  
-  // TODO: improve validation, will require knowing network type
-  static isValidAddress(address) {
-    try {
-      MoneroUtils.validateAddress(address);
-      return true;
-    } catch (e) {
-      return false;
-    }
-  }
-  
-  static validateAddress(address) {
-    assert(typeof address === "string", "Address is not string");
-    assert(address.length > 0, "Address is empty");
-    assert(GenUtils.isBase58(address), "Address is not base 58");
-  }
-  
-  static isValidPaymentId(paymentId) {
-    try {
-      MoneroUtils.validatePaymentId(paymentId);
-      return true;
-    } catch (e) {
-      return false;
-    }
-  }
-  
-  // TODO: beef this up
-  static validatePaymentId(paymentId) {
-    assert.equal(typeof paymentId, "string");
-    assert(paymentId.length === 16 || paymentId.length === 64);
-  }
-    
-  /**
-   * Decodes tx extra according to https://cryptonote.org/cns/cns005.txt and
-   * returns the last tx pub key.
-   * 
-   * TODO: use c++ bridge for this
-   * 
-   * @param txExtra is an array of tx extra bytes
-   * @return the last pub key as a hexidecimal string
-   */
-  static getLastTxPubKey(txExtra) {
-    let lastPubKeyIdx;
-    for (let i = 0; i < txExtra.length; i++) {
-      let tag = txExtra[i];
-      if (tag === 0 || tag === 2) {
-        i += 1 + txExtra[i + 1];  // advance to next tag
-      } else if (tag === 1) {
-        lastPubKeyIdx = i + 1;
-        i += 1 + 32;              // advance to next tag
-      } else throw new Error("Invalid sub-field tag: " + tag);
-    }
-    return Buffer.from(new Uint8Array(txExtra.slice(lastPubKeyIdx, lastPubKeyIdx + 32))).toString("hex");
-  }
-  
-  /**
-   * Determines if two payment ids are functionally equal.
-   * 
-   * For example, 03284e41c342f032 and 03284e41c342f032000000000000000000000000000000000000000000000000 are considered equal.
-   * 
-   * @param paymentId1 is a payment id to compare
-   * @param paymentId2 is a payment id to compare
-   * @return true if the payment ids are equal, false otherwise
-   */
-  static paymentIdsEqual(paymentId1, paymentId2) {
-    let maxLength = Math.max(paymentId1.length, paymentId2.length);
-    for (let i = 0; i < maxLength; i++) {
-      if (i < paymentId1.length && i < paymentId2.length && paymentId1[i] !== paymentId2[i]) return false;
-      if (i >= paymentId1.length && paymentId2[i] !== '0') return false;
-      if (i >= paymentId2.length && paymentId1[i] !== '0') return false;
-    }
-    return true;
-  }
-  
-  /**
-   * Merges a transaction into a list of existing transactions.
-   * 
-   * @param txs are existing transactions to merge into
-   * @param tx is the transaction to merge into the list
-   */
-  static mergeTx(txs, tx) {
-    for (let aTx of txs) {
-      if (aTx.getHash() === tx.getHash()) {
-        aTx.merge(tx);
-        return;
-      }
-    }
-    txs.push(tx);
-  }
-  
-  /**
-   * Converts the given JSON to a binary Uint8Array using Monero's portable storage format.
-   * 
-   * @param json is the json to convert to binary
-   * @returns Uint8Array is the json converted to portable storage binary
-   */
-  static jsonToBinary(json) {
-    
-    // wasm module must be pre-loaded
-    if (LibraryUtils.getWasmModule() === undefined) throw MoneroError("WASM module is not loaded; call 'await LibraryUtils.loadKeysModule()' to load");
-    
-    // serialize json to binary which is stored in c++ heap
-    let binMemInfoStr = LibraryUtils.getWasmModule().malloc_binary_from_json(JSON.stringify(json));
-    
-    // sanitize binary memory address info
-    let binMemInfo = JSON.parse(binMemInfoStr);
-    binMemInfo.ptr = parseInt(binMemInfo.ptr);
-    binMemInfo.length = parseInt(binMemInfo.length);
-    
-    // read binary data from heap to Uint8Array
-    let view = new Uint8Array(binMemInfo.length);
-    for (let i = 0; i < binMemInfo.length; i++) {
-      view[i] = LibraryUtils.getWasmModule().HEAPU8[binMemInfo.ptr / Uint8Array.BYTES_PER_ELEMENT + i];
-    }
-    
-    // free binary on heap
-    LibraryUtils.getWasmModule()._free(binMemInfo.ptr);
-    
-    // return json from binary data
-    return view;
-  }
-  
-  /**
-   * Converts the given portable storage binary to JSON.
-   * 
-   * @param uint8arr is a Uint8Array with binary data in Monero's portable storage format
-   * @returns a JSON object converted from the binary data
-   */
-  static binaryToJson(uint8arr) {
-    
-    // wasm module must be pre-loaded
-    if (LibraryUtils.getWasmModule() === undefined) throw MoneroError("WASM module is not loaded; call 'await LibraryUtils.loadKeysModule()' to load");
-    
-    // allocate space in c++ heap for binary
-    let ptr = LibraryUtils.getWasmModule()._malloc(uint8arr.length * uint8arr.BYTES_PER_ELEMENT);
-    let heap = new Uint8Array(LibraryUtils.getWasmModule().HEAPU8.buffer, ptr, uint8arr.length * uint8arr.BYTES_PER_ELEMENT);
-    if (ptr !== heap.byteOffset) throw new Error("Memory ptr !== heap.byteOffset"); // should be equal
-    
-    // write binary to heap
-    heap.set(new Uint8Array(uint8arr.buffer));
-    
-    // create object with binary memory address info
-    let binMemInfo = { ptr: ptr, length: uint8arr.length  }
-
-    // convert binary to json str
-    const ret_string = LibraryUtils.getWasmModule().binary_to_json(JSON.stringify(binMemInfo));
-    
-    // free binary on heap
-    LibraryUtils.getWasmModule()._free(ptr);
-    
-    // parse and return json
-    return JSON.parse(ret_string);
-  }
-  
-  /**
-   * Converts the binary response from daemon RPC block retrieval to JSON.
-   * 
-   * @param uint8arr is the binary response from daemon RPC when getting blocks
-   * @returns a JSON object with the blocks data
-   */
-  static binaryBlocksToJson(uint8arr) {
-    
-    // wasm module must be pre-loaded
-    if (LibraryUtils.getWasmModule() === undefined) throw MoneroError("WASM module is not loaded; call 'await LibraryUtils.loadKeysModule()' to load");
-    
-    // allocate space in c++ heap for binary
-    let ptr = LibraryUtils.getWasmModule()._malloc(uint8arr.length * uint8arr.BYTES_PER_ELEMENT);
-    let heap = new Uint8Array(LibraryUtils.getWasmModule().HEAPU8.buffer, ptr, uint8arr.length * uint8arr.BYTES_PER_ELEMENT);
-    if (ptr !== heap.byteOffset) throw new Error("Memory ptr !== heap.byteOffset"); // should be equal
-    
-    // write binary to heap
-    heap.set(new Uint8Array(uint8arr.buffer));
-    
-    // create object with binary memory address info
-    let binMemInfo = { ptr: ptr, length: uint8arr.length  }
-
-    // convert binary to json str
-    const json_str = LibraryUtils.getWasmModule().binary_blocks_to_json(JSON.stringify(binMemInfo));
-    
-    // free memory
-    LibraryUtils.getWasmModule()._free(ptr);
-    
-    // parse result to json
-    let json = JSON.parse(json_str);                                          // parsing json gives arrays of block and tx strings
-    json.blocks = json.blocks.map(blockStr => JSON.parse(blockStr));          // replace block strings with parsed blocks
-    json.txs = json.txs.map(txs => txs ? txs.map(tx => JSON.parse(tx.replace(",", "{") + "}")) : []); // modify tx string to proper json and parse // TODO: more efficient way than this json manipulation?
-    return json;
-  }
-}
-
-MoneroUtils.NUM_MNEMONIC_WORDS = 25;
-MoneroUtils.WALLET_REFRESH_RATE = 10000;  // 10 seconds
-MoneroUtils.RING_SIZE = 12;
-MoneroUtils.MAX_REQUESTS_PER_SECOND = 50;
-
-module.exports = MoneroUtils;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_common_MoneroWebWorker.js.html b/docs/src_main_js_common_MoneroWebWorker.js.html deleted file mode 100644 index 003fb98e3..000000000 --- a/docs/src_main_js_common_MoneroWebWorker.js.html +++ /dev/null @@ -1,977 +0,0 @@ - - - - - JSDoc: Source: src/main/js/common/MoneroWebWorker.js - - - - - - - - - - -
- -

Source: src/main/js/common/MoneroWebWorker.js

- - - - - - -
-
-
const assert = require("assert");
-const GenUtils = require("./GenUtils");
-const LibraryUtils = require("./LibraryUtils");
-const MoneroBan = require("../daemon/model/MoneroBan");
-const MoneroBlock = require("../daemon/model/MoneroBlock");
-const MoneroDaemonRpc = require("../daemon/MoneroDaemonRpc");
-const MoneroError = require("./MoneroError");
-const MoneroKeyImage = require("../daemon/model/MoneroKeyImage");
-const MoneroRpcConnection = require("./MoneroRpcConnection");
-const MoneroTxConfig = require("../wallet/model/MoneroTxConfig");
-const MoneroTxSet = require("../wallet/model/MoneroTxSet");
-const MoneroUtils = require("./MoneroUtils");
-const MoneroWalletListener = require("../wallet/model/MoneroWalletListener");
-const MoneroWalletWasm = require("../wallet/MoneroWalletWasm");
-
-/**
- * Web worker to manage a daemon and wasm wallet off the main thread with messages.
- * 
- * Required message format: e.data[0] = object id, e.data[1] = function name, e.data[2+] = function args
- *
- * This file must be browserified and placed in the web app root.
- * 
- * @private
- */
-onmessage = async function(e) {
-  
-  // initialize one time
-  await self.initOneTime();
-  
-  // validate params
-  let objectId = e.data[0];
-  let fnName = e.data[1];
-  assert(objectId, "Must provide object id to apply function to");
-  assert(fnName.length >= 2, "Must provide a function name with length >= 2");
-  if (!self[fnName]) throw new Error("Method '" + fnName + "' is not registered with worker");
-  e.data.splice(1, 1); // remove function name
-  
-  // execute worker function and post result to callback
-  let callbackFn = "on" + fnName.charAt(0).toUpperCase() + fnName.substring(1);
-  try {
-    postMessage([objectId, callbackFn, {result: await self[fnName].apply(null, e.data)}]);
-  } catch (e) {
-    postMessage([objectId, callbackFn, {error: e.message}]);
-  }
-}
-
-self.initOneTime = async function() {
-  if (!self.isInitialized) {
-    self.WORKER_OBJECTS = {};
-    self.isInitialized = true;
-  }
-}
-
-// --------------------------- STATIC UTILITIES -------------------------------
-
-self.getWasmMemoryUsed = async function(objectId) {	// TODO: object id not needed for static utilites, using throwaway uuid
-  return LibraryUtils.getWasmModule() && LibraryUtils.getWasmModule().HEAP8 ? LibraryUtils.getWasmModule().HEAP8.length : undefined;
-}
-
-// ---------------------------- DAEMON METHODS --------------------------------
-
-self.connectDaemonRpc = async function(daemonId, config) {
-  self.WORKER_OBJECTS[daemonId] = new MoneroDaemonRpc(config);
-}
-
-self.daemonGetRpcConnection = async function(daemonId) {
-  let connection = await self.WORKER_OBJECTS[daemonId].getRpcConnection();
-  return connection ? connection.getConfig() : undefined;
-}
-
-self.daemonIsConnected = async function(daemonId) {
-  return self.WORKER_OBJECTS[daemonId].isConnected();
-}
-
-self.daemonGetVersion = async function(daemonId) {
-  return (await self.WORKER_OBJECTS[daemonId].getVersion()).toJson();
-}
-
-self.daemonIsTrusted = async function(daemonId) {
-  return self.WORKER_OBJECTS[daemonId].isTrusted();
-}
-
-self.daemonGetHeight = async function(daemonId) {
-  return self.WORKER_OBJECTS[daemonId].getHeight();
-}
-
-self.daemonGetBlockHash = async function(daemonId, height) {
-  return self.WORKER_OBJECTS[daemonId].getBlockHash(height);
-}
-
-self.daemonGetBlockTemplate = async function(daemonId, walletAddress, reserveSize) {
-  return (await self.WORKER_OBJECTS[daemonId].getBlockTemplate(walletAddress, reserveSize)).toJson();
-}
-
-self.daemonGetLastBlockHeader = async function(daemonId) {
-  return (await self.WORKER_OBJECTS[daemonId].getLastBlockHeader()).toJson();
-}
-
-self.daemonGetBlockHeaderByHash = async function(daemonId, hash) {
-  return (await self.WORKER_OBJECTS[daemonId].getBlockHeaderByHash(hash)).toJson();
-}
-
-self.daemonGetBlockHeaderByHeight = async function(daemonId, height) {
-  return (await self.WORKER_OBJECTS[daemonId].getBlockHeaderByHeight(height)).toJson();
-}
-
-self.daemonGetBlockHeadersByRange = async function(daemonId, startHeight, endHeight) {
-  let blockHeadersJson = [];
-  for (let blockHeader of await self.WORKER_OBJECTS[daemonId].getBlockHeadersByRange(startHeight, endHeight)) blockHeadersJson.push(blockHeader.toJson());
-  return blockHeadersJson;
-}
-
-self.daemonGetBlockByHash = async function(daemonId, blockHash) {
-  return (await self.WORKER_OBJECTS[daemonId].getBlockByHash(blockHash)).toJson();
-}
-
-self.daemonGetBlocksByHash = async function(daemonId, blockHashes, startHeight, prune) {
-  let blocksJson = [];
-  for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByHash(blockHashes, startHeight, prune)) blocksJson.push(block.toJson());
-  return blocksJson;
-}
-
-self.daemonGetBlockByHeight = async function(daemonId, height) {
-  return (await self.WORKER_OBJECTS[daemonId].getBlockByHeight(height)).toJson();
-}
-
-self.daemonGetBlocksByHeight = async function(daemonId, heights) {
-  let blocksJson = [];
-  for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByHeight(heights)) blocksJson.push(block.toJson());
-  return blocksJson;
-}
-
-self.daemonGetBlocksByRange = async function(daemonId, startHeight, endHeight) {
-  let blocksJson = [];
-  for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByRange(startHeight, endHeight)) blocksJson.push(block.toJson());
-  return blocksJson;
-}
-
-self.daemonGetBlocksByRangeChunked = async function(daemonId, startHeight, endHeight, maxChunkSize) {
-  let blocksJson = [];
-  for (let block of await self.WORKER_OBJECTS[daemonId].getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize)) blocksJson.push(block.toJson());
-  return blocksJson;
-}
-
-self.daemonGetBlockHashes = async function(daemonId, blockHashes, startHeight) {
-  throw new Error("worker.getBlockHashes not implemented");
-}
-
-// TODO: factor common code with self.getTxs()
-self.daemonGetTxs = async function(daemonId, txHashes, prune) {
-  
-  // get txs
-  let txs = await self.WORKER_OBJECTS[daemonId].getTxs(txHashes, prune);
-  
-  // collect unique blocks to preserve model relationships as trees (based on monero_wasm_bridge.cpp::get_txs)
-  let blocks = [];
-  let unconfirmedBlock = undefined
-  let seenBlocks = new Set();
-  for (let tx of txs) {
-    if (!tx.getBlock()) {
-      if (!unconfirmedBlock) unconfirmedBlock = new MoneroBlock().setTxs([]);
-      tx.setBlock(unconfirmedBlock);
-      unconfirmedBlock.getTxs().push(tx);
-    }
-    if (!seenBlocks.has(tx.getBlock())) {
-      seenBlocks.add(tx.getBlock());
-      blocks.push(tx.getBlock());
-    }
-  }
-  
-  // serialize blocks to json
-  for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson();
-  return blocks;
-}
-
-self.daemonGetTxHexes = async function(daemonId, txHashes, prune) {
-  return self.WORKER_OBJECTS[daemonId].getTxHexes(txHashes, prune);
-}
-
-self.daemonGetMinerTxSum = async function(daemonId, height, numBlocks) {
-  return (await self.WORKER_OBJECTS[daemonId].getMinerTxSum(height, numBlocks)).toJson();
-}
-
-self.daemonGetFeeEstimate = async function(daemonId, graceBlocks) {
-  return (await self.WORKER_OBJECTS[daemonId].getFeeEstimate(graceBlocks)).toString();
-}
-
-self.daemonSubmitTxHex = async function(daemonId, txHex, doNotRelay) {
-  return (await self.WORKER_OBJECTS[daemonId].submitTxHex(txHex, doNotRelay)).toJson();
-}
-
-self.daemonRelayTxsByHash = async function(daemonId, txHashes) {
-  return self.WORKER_OBJECTS[daemonId].relayTxsByHash(txHashes);
-}
-
-self.daemonGetTxPool = async function(daemonId) {
-  let txs = await self.WORKER_OBJECTS[daemonId].getTxPool();
-  let block = new MoneroBlock().setTxs(txs);
-  for (let tx of txs) tx.setBlock(block)
-  return block.toJson();
-}
-
-self.daemonGetTxPoolHashes = async function(daemonId) {
-  return self.WORKER_OBJECTS[daemonId].getTxPoolHashes();
-}
-
-//async getTxPoolBacklog() {
-//  throw new MoneroError("Not implemented");
-//}
-
-self.daemonGetTxPoolStats = async function(daemonId) {
-  return (await self.WORKER_OBJECTS[daemonId].getTxPoolStats()).toJson();
-}
-
-self.daemonFlushTxPool = async function(daemonId, hashes) {
-  return self.WORKER_OBJECTS[daemonId].flushTxPool(hashes);
-}
-
-self.daemonGetKeyImageSpentStatuses = async function(daemonId, keyImages) {
-  return self.WORKER_OBJECTS[daemonId].getKeyImageSpentStatuses(keyImages);
-}
-
-//
-//async getOutputs(outputs) {
-//  throw new MoneroError("Not implemented");
-//}
-
-self.daemonGetOutputHistogram = async function(daemonId, amounts, minCount, maxCount, isUnlocked, recentCutoff) {
-  let entriesJson = [];
-  for (let entry of await self.WORKER_OBJECTS[daemonId].getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff)) {
-    entriesJson.push(entry.toJson());
-  }
-  return entriesJson;
-}
-
-//
-//async getOutputDistribution(amounts, cumulative, startHeight, endHeight) {
-//  throw new MoneroError("Not implemented");
-//}
-
-self.daemonGetInfo = async function(daemonId) {
-  return (await self.WORKER_OBJECTS[daemonId].getInfo()).toJson();
-}
-
-self.daemonGetSyncInfo = async function(daemonId) {
-  return (await self.WORKER_OBJECTS[daemonId].getSyncInfo()).toJson();
-}
-
-self.daemonGetHardForkInfo = async function(daemonId) {
-  return (await self.WORKER_OBJECTS[daemonId].getHardForkInfo()).toJson();
-}
-
-self.daemonGetAltChains = async function(daemonId) {
-  let altChainsJson = [];
-  for (let altChain of await self.WORKER_OBJECTS[daemonId].getAltChains()) altChainsJson.push(altChain.toJson());
-  return altChainsJson;
-}
-
-self.daemonGetAltBlockHashes = async function(daemonId) {
-  return self.WORKER_OBJECTS[daemonId].getAltBlockHashes();
-}
-
-self.daemonGetDownloadLimit = async function(daemonId) {
-  return self.WORKER_OBJECTS[daemonId].getDownloadLimit();
-}
-
-self.daemonSetDownloadLimit = async function(daemonId, limit) {
-  return self.WORKER_OBJECTS[daemonId].setDownloadLimit(limit);
-}
-
-self.daemonResetDownloadLimit = async function(daemonId) {
-  return self.WORKER_OBJECTS[daemonId].resetDownloadLimit();
-}
-
-self.daemonGetUploadLimit = async function(daemonId) {
-  return self.WORKER_OBJECTS[daemonId].getUploadLimit();
-}
-
-self.daemonSetUploadLimit = async function(daemonId, limit) {
-  return self.WORKER_OBJECTS[daemonId].setUploadLimit(limit);
-}
-
-self.daemonResetUploadLimit = async function(daemonId) {
-  return self.WORKER_OBJECTS[daemonId].resetUploadLimit();
-}
-
-self.daemonGetKnownPeers = async function(daemonId) {
-  let peersJson = [];
-  for (let peer of await self.WORKER_OBJECTS[daemonId].getKnownPeers()) peersJson.push(peer.toJson());
-  return peersJson;
-}
-
-self.daemonGetConnections = async function(daemonId) {
-  let connectionsJson = [];
-  for (let connection of await self.WORKER_OBJECTS[daemonId].getConnections()) connectionsJson.push(connection.toJson());
-  return connectionsJson;
-}
-
-self.daemonSetOutgoingPeerLimit = async function(daemonId, limit) {
-  return self.WORKER_OBJECTS[daemonId].setOutgoingPeerLimit(limit);
-}
-
-self.daemonSetIncomingPeerLimit = async function(daemonId, limit) {
-  return self.WORKER_OBJECTS[daemonId].setIncomingPeerLimit(limit);
-}
-
-self.daemonGetPeerBans = async function(daemonId) {
-  let bansJson = [];
-  for (let ban of await self.WORKER_OBJECTS[daemonId].getPeerBans()) bansJson.push(ban.toJson());
-  return bansJson;
-}
-
-self.daemonSetPeerBans = async function(daemonId, bansJson) {
-  let bans = [];
-  for (let banJson of bansJson) bans.push(new MoneroBan(banJson));
-  return self.WORKER_OBJECTS[daemonId].setPeerBans(bans);
-}
-
-self.daemonStartMining = async function(daemonId, address, numThreads, isBackground, ignoreBattery) {
-  return self.WORKER_OBJECTS[daemonId].startMining(address, numThreads, isBackground, ignoreBattery);
-}
-
-self.daemonStopMining = async function(daemonId) {
-  return self.WORKER_OBJECTS[daemonId].stopMining();
-}
-
-self.daemonGetMiningStatus = async function(daemonId) {
-  return (await self.WORKER_OBJECTS[daemonId].getMiningStatus()).toJson();
-}
-
-//
-//async submitBlocks(blockBlobs) {
-//  throw new MoneroError("Not implemented");
-//}
-//
-//async checkForUpdate() {
-//  throw new MoneroError("Not implemented");
-//}
-//
-//async downloadUpdate(path) {
-//  throw new MoneroError("Not implemented");
-//}
-
-self.daemonStop = async function(daemonId) {
-  return self.WORKER_OBJECTS[daemonId].stop();
-}
-
-self.daemonGetNextBlockHeader = async function(daemonId) {
-  return (await self.WORKER_OBJECTS[daemonId].getNextBlockHeader()).toJson();
-}
-
-self.daemonAddBlockListener = async function(daemonId, listenerId) {
-  let listener = function(blockHeader) {
-    self.postMessage([daemonId, "onNewBlockHeader_" + listenerId, blockHeader.toJson()]);
-  }
-  if (!self.daemonListeners) self.daemonListeners = {};
-  self.daemonListeners[listenerId] = listener;
-  await self.WORKER_OBJECTS[daemonId].addBlockListener(listener);
-}
-
-self.daemonRemoveBlockListener = async function(daemonId, listenerId) {
-  if (!self.daemonListeners[listenerId]) throw new MoneroError("No daemon worker listener registered with id: " + listenerId);
-  await self.WORKER_OBJECTS[daemonId].removeBlockListener(self.daemonListeners[listenerId]);
-  delete self.daemonListeners[listenerId];
-}
-
-//------------------------------ WALLET METHODS -------------------------------
-
-self.openWalletData = async function(walletId, path, password, networkType, keysData, cacheData, daemonUriOrConfig) {
-  let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined;
-  self.WORKER_OBJECTS[walletId] = await MoneroWalletWasm.openWallet({path: "", password: password, networkType: networkType, keysData: keysData, cacheData: cacheData, server: daemonConnection, proxyToWorker: false});
-  self.WORKER_OBJECTS[walletId]._setBrowserMainPath(path);
-}
-
-self._createWalletRandom = async function(walletId, path, password, networkType, daemonUriOrConfig, language) {
-  let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined;
-  self.WORKER_OBJECTS[walletId] = await MoneroWalletWasm._createWalletRandom("", password, networkType, daemonConnection, language, false);
-  self.WORKER_OBJECTS[walletId]._setBrowserMainPath(path);
-}
-
-self._createWalletFromMnemonic = async function(walletId, path, password, networkType, mnemonic, daemonUriOrConfig, restoreHeight, seedOffset) {
-  let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined;
-  self.WORKER_OBJECTS[walletId] = await MoneroWalletWasm._createWalletFromMnemonic("", password, networkType, mnemonic, daemonConnection, restoreHeight, seedOffset, false);
-  self.WORKER_OBJECTS[walletId]._setBrowserMainPath(path);
-}
-
-self._createWalletFromKeys = async function(walletId, path, password, networkType, address, viewKey, spendKey, daemonUriOrConfig, restoreHeight, language) {
-  let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined;
-  self.WORKER_OBJECTS[walletId] = await MoneroWalletWasm._createWalletFromKeys("", password, networkType, address, viewKey, spendKey, daemonConnection, restoreHeight, language, false);
-  self.WORKER_OBJECTS[walletId]._setBrowserMainPath(path);
-}
-
-self.isViewOnly = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].isViewOnly();
-}
-
-self.getNetworkType = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getNetworkType();
-}
-
-//
-//async getVersion() {
-//  throw new Error("Not implemented");
-//}
-
-self.getMnemonic = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getMnemonic();
-}
-
-self.getMnemonicLanguage = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getMnemonicLanguage();
-}
-
-self.getMnemonicLanguages = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getMnemonicLanguages();
-}
-
-self.getPrivateSpendKey = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getPrivateSpendKey();
-}
-
-self.getPrivateViewKey = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getPrivateViewKey();
-}
-
-self.getPublicViewKey = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getPublicViewKey();
-}
-
-self.getPublicSpendKey = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getPublicSpendKey();
-}
-
-self.getAddress = async function(walletId, accountIdx, subaddressIdx) {
-  return self.WORKER_OBJECTS[walletId].getAddress(accountIdx, subaddressIdx);
-}
-
-self.getAddressIndex = async function(walletId, address) {
-  return (await self.WORKER_OBJECTS[walletId].getAddressIndex(address)).toJson();
-}
-
-self.getIntegratedAddress = async function(walletId, paymentId) {
-  return (await self.WORKER_OBJECTS[walletId].getIntegratedAddress(paymentId)).toJson();
-}
-
-self.decodeIntegratedAddress = async function(walletId, integratedAddress) {
-  return (await self.WORKER_OBJECTS[walletId].decodeIntegratedAddress(integratedAddress)).toJson();
-}
-
-self.setDaemonConnection = async function(walletId, config) {
-  return self.WORKER_OBJECTS[walletId].setDaemonConnection(config ? new MoneroRpcConnection(config) : undefined);
-}
-
-self.getDaemonConnection = async function(walletId) {
-  let connection = await self.WORKER_OBJECTS[walletId].getDaemonConnection();
-  return connection ? connection.getConfig() : undefined;
-}
-
-self.isConnected = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].isConnected();
-}
-
-self.getSyncHeight = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getSyncHeight();
-}
-
-self.setSyncHeight = async function(walletId, syncHeight) {
-  return self.WORKER_OBJECTS[walletId].setSyncHeight(syncHeight);
-}
-
-self.getDaemonHeight = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getDaemonHeight();
-}
-
-self.getDaemonMaxPeerHeight = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getDaemonMaxPeerHeight()
-}
-
-self.getHeightByDate = async function(walletId, year, month, day) {
-  return self.WORKER_OBJECTS[walletId].getHeightByDate(year, month, day);
-}
-
-self.isDaemonSynced = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].isDaemonSynced();
-}
-
-self.getHeight = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getHeight();
-}
-
-self.addListener = async function(walletId, listenerId) {
-  
-  /**
-   * Internal listener to bridge notifications to external listeners.
-   * 
-   * TODO: MoneroWalletListener is not defined until scripts imported
-   * 
-   * @private
-   */
-  class WalletWorkerHelperListener extends MoneroWalletListener {
-    
-    constructor(walletId, id, worker) {
-      super();
-      this.walletId = walletId;
-      this.id = id;
-      this.worker = worker;
-    }
-    
-    getId() {
-      return this.id;
-    }
-    
-    onSyncProgress(height, startHeight, endHeight, percentDone, message) {
-      this.worker.postMessage([this.walletId, "onSyncProgress_" + this.getId(), height, startHeight, endHeight, percentDone, message]);
-    }
-
-    onNewBlock(height) { 
-      this.worker.postMessage([this.walletId, "onNewBlock_" + this.getId(), height]);
-    }
-    
-    onBalancesChanged(newBalance, newUnlockedBalance) {
-      this.worker.postMessage([this.walletId, "onBalancesChanged_" + this.getId(), newBalance.toString(), newUnlockedBalance.toString()]);
-    }
-
-    onOutputReceived(output) {
-      let block = output.getTx().getBlock();
-      if (block === undefined) block = new MoneroBlock().setTxs([output.getTx()]);
-      this.worker.postMessage([this.walletId, "onOutputReceived_" + this.getId(), block.toJson()]);  // serialize from root block
-    }
-    
-    onOutputSpent(output) {
-      let block = output.getTx().getBlock();
-      if (block === undefined) block = new MoneroBlock().setTxs([output.getTx()]);
-      this.worker.postMessage([this.walletId, "onOutputSpent_" + this.getId(), block.toJson()]);     // serialize from root block
-    }
-  }
-  
-  let listener = new WalletWorkerHelperListener(walletId, listenerId, self);
-  if (!self.listeners) self.listeners = [];
-  self.listeners.push(listener);
-  await self.WORKER_OBJECTS[walletId].addListener(listener);
-}
-
-self.removeListener = async function(walletId, listenerId) {
-  for (let i = 0; i < self.listeners.length; i++) {
-    if (self.listeners[i].getId() !== listenerId) continue;
-    await self.WORKER_OBJECTS[walletId].removeListener(self.listeners[i]);
-    self.listeners.splice(i, 1);
-    return;
-  }
-  throw new MoneroError("Listener is not registered with wallet");
-}
-
-self.isSynced = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].isSynced();
-}
-
-self.sync = async function(walletId, startHeight) {
-  return await self.WORKER_OBJECTS[walletId].sync(startHeight);
-}
-
-self.startSyncing = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].startSyncing();
-}
-
-self.stopSyncing = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].stopSyncing();
-}
-
-self.rescanSpent = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].rescanSpent();
-}
-
-self.rescanBlockchain = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].rescanBlockchain();
-}
-
-self.getBalance = async function(walletId, accountIdx, subaddressIdx) {
-  return (await self.WORKER_OBJECTS[walletId].getBalance(accountIdx, subaddressIdx)).toString();
-}
-
-self.getUnlockedBalance = async function(walletId, accountIdx, subaddressIdx) {
-  return (await self.WORKER_OBJECTS[walletId].getUnlockedBalance(accountIdx, subaddressIdx)).toString();
-}
-
-self.getAccounts = async function(walletId, includeSubaddresses, tag) {
-  let accountJsons = [];
-  for (let account of await self.WORKER_OBJECTS[walletId].getAccounts(includeSubaddresses, tag)) accountJsons.push(account.toJson());
-  return accountJsons;
-}
-
-self.getAccount = async function(walletId, accountIdx, includeSubaddresses) {
-  return (await self.WORKER_OBJECTS[walletId].getAccount(accountIdx, includeSubaddresses)).toJson();
-}
-
-self.createAccount = async function(walletId, label) {
-  return (await self.WORKER_OBJECTS[walletId].createAccount(label)).toJson();
-}
-
-self.getSubaddresses = async function(walletId, accountIdx, subaddressIndices) {
-  let subaddressJsons = [];
-  for (let subaddress of await self.WORKER_OBJECTS[walletId].getSubaddresses(accountIdx, subaddressIndices)) subaddressJsons.push(subaddress.toJson());
-  return subaddressJsons;
-}
-
-self.createSubaddress = async function(walletId, accountIdx, label) {
-  return (await self.WORKER_OBJECTS[walletId].createSubaddress(accountIdx, label)).toJson();
-}
-
-// TODO: easier or more efficient way than serializing from root blocks?
-self.getTxs = async function(walletId, blockJsonQuery) {
-  
-  // deserialize query which is json string rooted at block
-  let query = new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0];
-  
-  // get txs
-  let txs = await self.WORKER_OBJECTS[walletId].getTxs(query);
-  
-  // collect unique blocks to preserve model relationships as trees (based on monero_wasm_bridge.cpp::get_txs)
-  let seenBlocks = new Set();
-  let unconfirmedBlock = undefined;
-  let blocks = [];
-  for (let tx of txs) {
-    if (!tx.getBlock()) {
-      if (!unconfirmedBlock) unconfirmedBlock = new MoneroBlock().setTxs([]);
-      tx.setBlock(unconfirmedBlock);
-      unconfirmedBlock.getTxs().push(tx);
-    }
-    if (!seenBlocks.has(tx.getBlock())) {
-      seenBlocks.add(tx.getBlock());
-      blocks.push(tx.getBlock());
-    }
-  }
-  
-  // serialize blocks to json
-  for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson();
-  return blocks;
-}
-
-self.getTransfers = async function(walletId, blockJsonQuery) {
-  
-  // deserialize query which is json string rooted at block
-  let query = new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0].getTransferQuery();
-  
-  // get transfers
-  let transfers = await self.WORKER_OBJECTS[walletId].getTransfers(query);
-  
-  // collect unique blocks to preserve model relationships as tree
-  let unconfirmedBlock = undefined;
-  let blocks = [];
-  let seenBlocks = new Set();
-  for (let transfer of transfers) {
-    let tx = transfer.getTx();
-    if (!tx.getBlock()) {
-      if (!unconfirmedBlock) unconfirmedBlock = new MoneroBlock().setTxs([]);
-      tx.setBlock(unconfirmedBlock);
-      unconfirmedBlock.getTxs().push(tx);
-    }
-    if (!seenBlocks.has(tx.getBlock())) {
-      seenBlocks.add(tx.getBlock());
-      blocks.push(tx.getBlock());
-    }
-  }
-  
-  // serialize blocks to json
-  for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson();
-  return blocks;
-}
-
-self.getOutputs = async function(walletId, blockJsonQuery) {
-
-  // deserialize query which is json string rooted at block
-  let query = new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0].getOutputQuery();
-  
-  // get outputs
-  let outputs = await self.WORKER_OBJECTS[walletId].getOutputs(query);
-  
-  // collect unique blocks to preserve model relationships as tree
-  let unconfirmedBlock = undefined;
-  let blocks = [];
-  let seenBlocks = new Set();
-  for (let output of outputs) {
-    let tx = output.getTx();
-    if (!tx.getBlock()) {
-      if (!unconfirmedBlock) unconfirmedBlock = new MoneroBlock().setTxs([]);
-      tx.setBlock(unconfirmedBlock);
-      unconfirmedBlock.getTxs().push(tx);
-    }
-    if (!seenBlocks.has(tx.getBlock())) {
-      seenBlocks.add(tx.getBlock());
-      blocks.push(tx.getBlock());
-    }
-  }
-  
-  // serialize blocks to json
-  for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson();
-  return blocks;
-}
-
-self.getOutputsHex = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getOutputsHex();
-}
-
-self.importOutputsHex = async function(walletId, outputsHex) {
-  return self.WORKER_OBJECTS[walletId].importOutputsHex(outputsHex);
-}
-
-self.getKeyImages = async function(walletId) {
-  let keyImagesJson = [];
-  for (let keyImage of await self.WORKER_OBJECTS[walletId].getKeyImages()) keyImagesJson.push(keyImage.toJson());
-  return keyImagesJson;
-}
-
-self.importKeyImages = async function(walletId, keyImagesJson) {
-  let keyImages = [];
-  for (let keyImageJson of keyImagesJson) keyImages.push(new MoneroKeyImage(keyImageJson));
-  return (await self.WORKER_OBJECTS[walletId].importKeyImages(keyImages)).toJson();
-}
-
-//async getNewKeyImagesFromLastImport() {
-//  throw new MoneroError("Not implemented");
-//}
-
-self.createTxs = async function(walletId, config) {
-  if (typeof config === "object") config = new MoneroTxConfig(config);
-  let txs = await self.WORKER_OBJECTS[walletId].createTxs(config);
-  return txs[0].getTxSet().toJson();
-}
-
-self.sweepOutput = async function(walletId, config) {
-  if (typeof config === "object") config = new MoneroTxConfig(config);
-  let tx = await self.WORKER_OBJECTS[walletId].sweepOutput(config);
-  return tx.getTxSet().toJson();
-}
-
-self.sweepUnlocked = async function(walletId, config) {
-  if (typeof config === "object") config = new MoneroTxConfig(config);
-  let txs = await self.WORKER_OBJECTS[walletId].sweepUnlocked(config);
-  let txSets = [];
-  for (let tx of txs) if (!GenUtils.arrayContains(txSets, tx.getTxSet())) txSets.push(tx.getTxSet());
-  let txSetsJson = [];
-  for (let txSet of txSets) txSetsJson.push(txSet.toJson());
-  return txSetsJson;
-}
-
-self.sweepDust = async function(walletId, relay) {
-  let txs = await self.WORKER_OBJECTS[walletId].sweepDust(relay);
-  return txs[0].getTxSet().toJson();
-}
-
-self.relayTxs = async function(walletId, txMetadatas) {
-  return self.WORKER_OBJECTS[walletId].relayTxs(txMetadatas);
-}
-
-self.parseTxSet = async function(walletId, txSetJson) {
-  return (await self.WORKER_OBJECTS[walletId].parseTxSet(new MoneroTxSet(txSetJson))).toJson();
-}
-
-self.signTxs = async function(walletId, unsignedTxHex) {
-  return self.WORKER_OBJECTS[walletId].signTxs(unsignedTxHex);
-}
-
-self.submitTxs = async function(walletId, signedTxHex) {
-  return self.WORKER_OBJECTS[walletId].submitTxs(signedTxHex);
-}
-
-self.signMessage = async function(walletId, message) {
-  return self.WORKER_OBJECTS[walletId].signMessage(message);
-}
-
-self.verifyMessage = async function(walletId, message, address, signature) {
-  return self.WORKER_OBJECTS[walletId].verifyMessage(message, address, signature);
-}
-
-self.getTxKey = async function(walletId, txHash) {
-  return self.WORKER_OBJECTS[walletId].getTxKey(txHash);
-}
-
-self.checkTxKey = async function(walletId, txHash, txKey, address) {
-  return (await self.WORKER_OBJECTS[walletId].checkTxKey(txHash, txKey, address)).toJson();
-}
-
-self.getTxProof = async function(walletId, txHash, address, message) {
-  return self.WORKER_OBJECTS[walletId].getTxProof(txHash, address, message);
-}
-
-self.checkTxProof = async function(walletId, txHash, address, message, signature) {
-  return (self.WORKER_OBJECTS[walletId].checkTxProof(txHash, address, message, signature)).toJson();
-}
-
-self.getSpendProof = async function(walletId, txHash, message) {
-  return self.WORKER_OBJECTS[walletId].getSpendProof(txHash, message);
-}
-
-self.checkSpendProof = async function(walletId, txHash, message, signature) {
-  return self.WORKER_OBJECTS[walletId].checkSpendProof(txHash, message, signature);
-}
-
-self.getReserveProofWallet = async function(walletId, message) {
-  return self.WORKER_OBJECTS[walletId].getReserveProofWallet(message);
-}
-
-self.getReserveProofAccount = async function(walletId, accountIdx, amount, message) {
-  return self.WORKER_OBJECTS[walletId].getReserveProofAccount(accountIdx, amount, message);
-}
-
-self.checkReserveProof = async function(walletId, address, message, signature) {
-  return (await self.WORKER_OBJECTS[walletId].checkReserveProof(address, message, signature)).toJson();
-}
-
-self.getTxNotes = async function(walletId, txHashes) {
-  return self.WORKER_OBJECTS[walletId].getTxNotes(txHashes);
-}
-
-self.setTxNotes = async function(walletId, txHashes, txNotes) {
-  return self.WORKER_OBJECTS[walletId].setTxNotes(txHashes, txNotes);
-}
-
-self.getAddressBookEntries = async function(walletId, entryIndices) {
-  let entriesJson = [];
-  for (let entry of await self.WORKER_OBJECTS[walletId].getAddressBookEntries(entryIndices)) entriesJson.push(entry.toJson());
-  return entriesJson;
-}
-
-self.addAddressBookEntry = async function(walletId, address, description) {
-  return self.WORKER_OBJECTS[walletId].addAddressBookEntry(address, description);
-}
-
-self.editAddressBookEntry = async function(walletId, index, setAddress, address, setDescription, description) {
-  return self.WORKER_OBJECTS[walletId].editAddressBookEntry(index, setAddress, address, setDescription, description);
-}
-
-self.deleteAddressBookEntry = async function(walletId, index) {
-  return self.WORKER_OBJECTS[walletId].deleteAddressBookEntry(index);
-}
-
-self.tagAccounts = async function(walletId, tag, accountIndices) {
-  throw new Error("Not implemented");
-}
-
-self.untagAccounts = async function(walletId, accountIndices) {
-  throw new Error("Not implemented");
-}
-
-self.getAccountTags = async function(walletId) {
-  throw new Error("Not implemented");
-}
-
-self.setAccountTagLabel = async function(walletId, tag, label) {
-  throw new Error("Not implemented");
-}
-
-self.createPaymentUri = async function(walletId, configJson) {
-  return self.WORKER_OBJECTS[walletId].createPaymentUri(new MoneroTxConfig(configJson));
-}
-
-self.parsePaymentUri = async function(walletId, uri) {
-  return (await self.WORKER_OBJECTS[walletId].parsePaymentUri(uri)).toJson();
-}
-
-self.getAttribute = async function(walletId, key) {
-  return self.WORKER_OBJECTS[walletId].getAttribute(key);
-}
-
-self.setAttribute = async function(walletId, key, value) {
-  return self.WORKER_OBJECTS[walletId].setAttribute(key, value);
-}
-
-self.startMining = async function(walletId, numThreads, backgroundMining, ignoreBattery) {
-  return self.WORKER_OBJECTS[walletId].startMining(numThreads, backgroundMining, ignoreBattery);
-}
-
-self.stopMining = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].stopMining();
-}
-
-self.isMultisigImportNeeded = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].isMultisigImportNeeded();
-}
-
-self.isMultisig = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].isMultisig();
-}
-
-self.getMultisigInfo = async function(walletId) {
-  return (await self.WORKER_OBJECTS[walletId].getMultisigInfo()).toJson();
-}
-
-self.prepareMultisig = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].prepareMultisig();
-}
-
-self.makeMultisig = async function(walletId, multisigHexes, threshold, password) {
-  return (await self.WORKER_OBJECTS[walletId].makeMultisig(multisigHexes, threshold, password)).toJson();
-}
-
-self.exchangeMultisigKeys = async function(walletId, multisigHexes, password) {
-  return (await self.WORKER_OBJECTS[walletId].exchangeMultisigKeys(multisigHexes, password)).toJson();
-}
-
-self.getMultisigHex = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getMultisigHex();
-}
-
-self.importMultisigHex = async function(walletId, multisigHexes) {
-  return self.WORKER_OBJECTS[walletId].importMultisigHex(multisigHexes);
-}
-
-self.signMultisigTxHex = async function(walletId, multisigTxHex) {
-  return (await self.WORKER_OBJECTS[walletId].signMultisigTxHex(multisigTxHex)).toJson();
-}
-
-self.submitMultisigTxHex = async function(walletId, signedMultisigTxHex) {
-  return self.WORKER_OBJECTS[walletId].submitMultisigTxHex(signedMultisigTxHex);
-}
-
-self.getData = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].getData();
-}
-
-self.isClosed = async function(walletId) {
-  return self.WORKER_OBJECTS[walletId].isClosed();
-}
-
-self.close = async function(walletId, save) {
-  return self.WORKER_OBJECTS[walletId].close(save); // TODO: remove listeners and delete wallet from WORKER_OBJECTS
-}
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_common_SslOptions.js.html b/docs/src_main_js_common_SslOptions.js.html deleted file mode 100644 index 0851d9f30..000000000 --- a/docs/src_main_js_common_SslOptions.js.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - - JSDoc: Source: src/main/js/common/SslOptions.js - - - - - - - - - - -
- -

Source: src/main/js/common/SslOptions.js

- - - - - - -
-
-
/**
- * SSL options for remote endpoints.
- */
-class SslOptions {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-  }
-  
-  getPrivateKeyPath() {
-    return this.state.privateKeyPath;
-  }
-  
-  setPrivateKeyPath(privateKeyPath) {
-    this.state.privateKeyPath = privateKeyPath;
-    return this;
-  }
-  
-  getCertificatePath() {
-    return this.state.certificatePath;
-  }
-  
-  setCertificatePath(certificatePath) {
-    this.state.certificatePath = certificatePath;
-    return this;
-  }
-  
-  getCertificateAuthorityFile() {
-    return this.state.certificateAuthorityFile;
-  }
-  
-  setCertificateAuthorityFile(certificateAuthorityFile) {
-    this.state.certificateAuthorityFile = certificateAuthorityFile;
-    return this;
-  }
-  
-  getAllowedFingerprints() {
-    return this.state.allowedFingerprints;
-  }
-  
-  setAllowedFingerprints(allowedFingerprints) {
-    this.state.allowedFingerprints = allowedFingerprints;
-    return this;
-  }
-  
-  getAllowAnyCert() {
-    return this.state.allowAnyCert;
-  }
-  
-  setAllowAnyCert(allowAnyCert) {
-    this.state.allowAnyCert = allowAnyCert;
-    return this;
-  }
-}
-
-module.exports = SslOptions;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_common_biginteger.js.html b/docs/src_main_js_common_biginteger.js.html deleted file mode 100644 index 4e0ede533..000000000 --- a/docs/src_main_js_common_biginteger.js.html +++ /dev/null @@ -1,1686 +0,0 @@ - - - - - JSDoc: Source: src/main/js/common/biginteger.js - - - - - - - - - - -
- -

Source: src/main/js/common/biginteger.js

- - - - - - -
-
-
/*
-	JavaScript BigInteger library version 0.9.1
-	http://silentmatt.com/biginteger/
-
-	Copyright (c) 2009 Matthew Crumley <email@matthewcrumley.com>
-	Copyright (c) 2010,2011 by John Tobey <John.Tobey@gmail.com>
-	Licensed under the MIT license.
-
-	Support for arbitrary internal representation base was added by
-	Vitaly Magerya.
-*/
-/*
-
-This file has been modified by Paul Shapiro:
-
-1. to bring in the function lowVal which was written by Lucas Jones
-2. to expose CONSTRUCT
-
-*/
-/*
-	File: biginteger.js
-
-	Exports:
-
-		<BigInteger>
-*/
-(function(exports) {
-"use strict";
-/*
-	Class: BigInteger
-	An arbitrarily-large integer.
-
-	<BigInteger> objects should be considered immutable. None of the "built-in"
-	methods modify *this* or their arguments. All properties should be
-	considered private.
-
-	All the methods of <BigInteger> instances can be called "statically". The
-	static versions are convenient if you don't already have a <BigInteger>
-	object.
-
-	As an example, these calls are equivalent.
-
-	> BigInteger(4).multiply(5); // returns BigInteger(20);
-	> BigInteger.multiply(4, 5); // returns BigInteger(20);
-
-	> var a = 42;
-	> var a = BigInteger.toJSValue("0b101010"); // Not completely useless...
-*/
-
-var CONSTRUCT = {}; // Unique token to call "private" version of constructor
-
-/*
-	Constructor: BigInteger()
-	Convert a value to a <BigInteger>.
-
-	Although <BigInteger()> is the constructor for <BigInteger> objects, it is
-	best not to call it as a constructor. If *n* is a <BigInteger> object, it is
-	simply returned as-is. Otherwise, <BigInteger()> is equivalent to <parse>
-	without a radix argument.
-
-	> var n0 = BigInteger();	  // Same as <BigInteger.ZERO>
-	> var n1 = BigInteger("123"); // Create a new <BigInteger> with value 123
-	> var n2 = BigInteger(123);   // Create a new <BigInteger> with value 123
-	> var n3 = BigInteger(n2);	// Return n2, unchanged
-
-	The constructor form only takes an array and a sign. *n* must be an
-	array of numbers in little-endian order, where each digit is between 0
-	and BigInteger.base.  The second parameter sets the sign: -1 for
-	negative, +1 for positive, or 0 for zero. The array is *not copied and
-	may be modified*. If the array contains only zeros, the sign parameter
-	is ignored and is forced to zero.
-
-	> new BigInteger([5], -1): create a new BigInteger with value -5
-
-	Parameters:
-
-		n - Value to convert to a <BigInteger>.
-
-	Returns:
-
-		A <BigInteger> value.
-
-	See Also:
-
-		<parse>, <BigInteger>
-*/
-function BigInteger(n, s, token) {
-	if (token !== CONSTRUCT) {
-		if (n instanceof BigInteger) {
-			return n;
-		}
-		else if (typeof n === "undefined") {
-			return ZERO;
-		}
-		return BigInteger.parse(n);
-	}
-
-	n = n || [];  // Provide the nullary constructor for subclasses.
-	while (n.length && !n[n.length - 1]) {
-		--n.length;
-	}
-	this._d = n;
-	this._s = n.length ? (s || 1) : 0;
-}
-BigInteger.CONSTRUCT = CONSTRUCT; // added by PS to actually use the constructor
-
-BigInteger._construct = function(n, s) {
-	return new BigInteger(n, s, CONSTRUCT);
-};
-
-// Base-10 speedup hacks in parse, toString, exp10 and log functions
-// require base to be a power of 10. 10^7 is the largest such power
-// that won't cause a precision loss when digits are multiplied.
-var BigInteger_base = 10000000;
-var BigInteger_base_log10 = 7;
-
-BigInteger.base = BigInteger_base;
-BigInteger.base_log10 = BigInteger_base_log10;
-
-var ZERO = new BigInteger([], 0, CONSTRUCT);
-// Constant: ZERO
-// <BigInteger> 0.
-BigInteger.ZERO = ZERO;
-
-var ONE = new BigInteger([1], 1, CONSTRUCT);
-// Constant: ONE
-// <BigInteger> 1.
-BigInteger.ONE = ONE;
-
-var M_ONE = new BigInteger(ONE._d, -1, CONSTRUCT);
-// Constant: M_ONE
-// <BigInteger> -1.
-BigInteger.M_ONE = M_ONE;
-
-// Constant: _0
-// Shortcut for <ZERO>.
-BigInteger._0 = ZERO;
-
-// Constant: _1
-// Shortcut for <ONE>.
-BigInteger._1 = ONE;
-
-/*
-	Constant: small
-	Array of <BigIntegers> from 0 to 36.
-
-	These are used internally for parsing, but useful when you need a "small"
-	<BigInteger>.
-
-	See Also:
-
-		<ZERO>, <ONE>, <_0>, <_1>
-*/
-BigInteger.small = [
-	ZERO,
-	ONE,
-	/* Assuming BigInteger_base > 36 */
-	new BigInteger( [2], 1, CONSTRUCT),
-	new BigInteger( [3], 1, CONSTRUCT),
-	new BigInteger( [4], 1, CONSTRUCT),
-	new BigInteger( [5], 1, CONSTRUCT),
-	new BigInteger( [6], 1, CONSTRUCT),
-	new BigInteger( [7], 1, CONSTRUCT),
-	new BigInteger( [8], 1, CONSTRUCT),
-	new BigInteger( [9], 1, CONSTRUCT),
-	new BigInteger([10], 1, CONSTRUCT),
-	new BigInteger([11], 1, CONSTRUCT),
-	new BigInteger([12], 1, CONSTRUCT),
-	new BigInteger([13], 1, CONSTRUCT),
-	new BigInteger([14], 1, CONSTRUCT),
-	new BigInteger([15], 1, CONSTRUCT),
-	new BigInteger([16], 1, CONSTRUCT),
-	new BigInteger([17], 1, CONSTRUCT),
-	new BigInteger([18], 1, CONSTRUCT),
-	new BigInteger([19], 1, CONSTRUCT),
-	new BigInteger([20], 1, CONSTRUCT),
-	new BigInteger([21], 1, CONSTRUCT),
-	new BigInteger([22], 1, CONSTRUCT),
-	new BigInteger([23], 1, CONSTRUCT),
-	new BigInteger([24], 1, CONSTRUCT),
-	new BigInteger([25], 1, CONSTRUCT),
-	new BigInteger([26], 1, CONSTRUCT),
-	new BigInteger([27], 1, CONSTRUCT),
-	new BigInteger([28], 1, CONSTRUCT),
-	new BigInteger([29], 1, CONSTRUCT),
-	new BigInteger([30], 1, CONSTRUCT),
-	new BigInteger([31], 1, CONSTRUCT),
-	new BigInteger([32], 1, CONSTRUCT),
-	new BigInteger([33], 1, CONSTRUCT),
-	new BigInteger([34], 1, CONSTRUCT),
-	new BigInteger([35], 1, CONSTRUCT),
-	new BigInteger([36], 1, CONSTRUCT)
-];
-
-// Used for parsing/radix conversion
-BigInteger.digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
-
-/*
-	Method: toString
-	Convert a <BigInteger> to a string.
-
-	When *base* is greater than 10, letters are upper case.
-
-	Parameters:
-
-		base - Optional base to represent the number in (default is base 10).
-			   Must be between 2 and 36 inclusive, or an Error will be thrown.
-
-	Returns:
-
-		The string representation of the <BigInteger>.
-*/
-BigInteger.prototype.toString = function(base) {
-	base = +base || 10;
-	if (base < 2 || base > 36) {
-		throw new Error("illegal radix " + base + ".");
-	}
-	if (this._s === 0) {
-		return "0";
-	}
-	if (base === 10) {
-		var str = this._s < 0 ? "-" : "";
-		str += this._d[this._d.length - 1].toString();
-		for (var i = this._d.length - 2; i >= 0; i--) {
-			var group = this._d[i].toString();
-			while (group.length < BigInteger_base_log10) group = '0' + group;
-			str += group;
-		}
-		return str;
-	}
-	else {
-		var numerals = BigInteger.digits;
-		base = BigInteger.small[base];
-		var sign = this._s;
-
-		var n = this.abs();
-		var digits = [];
-		var digit;
-
-		while (n._s !== 0) {
-			var divmod = n.divRem(base);
-			n = divmod[0];
-			digit = divmod[1];
-			// TODO: This could be changed to unshift instead of reversing at the end.
-			// Benchmark both to compare speeds.
-			digits.push(numerals[digit.valueOf()]);
-		}
-		return (sign < 0 ? "-" : "") + digits.reverse().join("");
-	}
-};
-
-// Verify strings for parsing
-BigInteger.radixRegex = [
-	/^$/,
-	/^$/,
-	/^[01]*$/,
-	/^[012]*$/,
-	/^[0-3]*$/,
-	/^[0-4]*$/,
-	/^[0-5]*$/,
-	/^[0-6]*$/,
-	/^[0-7]*$/,
-	/^[0-8]*$/,
-	/^[0-9]*$/,
-	/^[0-9aA]*$/,
-	/^[0-9abAB]*$/,
-	/^[0-9abcABC]*$/,
-	/^[0-9a-dA-D]*$/,
-	/^[0-9a-eA-E]*$/,
-	/^[0-9a-fA-F]*$/,
-	/^[0-9a-gA-G]*$/,
-	/^[0-9a-hA-H]*$/,
-	/^[0-9a-iA-I]*$/,
-	/^[0-9a-jA-J]*$/,
-	/^[0-9a-kA-K]*$/,
-	/^[0-9a-lA-L]*$/,
-	/^[0-9a-mA-M]*$/,
-	/^[0-9a-nA-N]*$/,
-	/^[0-9a-oA-O]*$/,
-	/^[0-9a-pA-P]*$/,
-	/^[0-9a-qA-Q]*$/,
-	/^[0-9a-rA-R]*$/,
-	/^[0-9a-sA-S]*$/,
-	/^[0-9a-tA-T]*$/,
-	/^[0-9a-uA-U]*$/,
-	/^[0-9a-vA-V]*$/,
-	/^[0-9a-wA-W]*$/,
-	/^[0-9a-xA-X]*$/,
-	/^[0-9a-yA-Y]*$/,
-	/^[0-9a-zA-Z]*$/
-];
-
-/*
-	Function: parse
-	Parse a string into a <BigInteger>.
-
-	*base* is optional but, if provided, must be from 2 to 36 inclusive. If
-	*base* is not provided, it will be guessed based on the leading characters
-	of *s* as follows:
-
-	- "0x" or "0X": *base* = 16
-	- "0c" or "0C": *base* = 8
-	- "0b" or "0B": *base* = 2
-	- else: *base* = 10
-
-	If no base is provided, or *base* is 10, the number can be in exponential
-	form. For example, these are all valid:
-
-	> BigInteger.parse("1e9");			  // Same as "1000000000"
-	> BigInteger.parse("1.234*10^3");	   // Same as 1234
-	> BigInteger.parse("56789 * 10 ** -2"); // Same as 567
-
-	If any characters fall outside the range defined by the radix, an exception
-	will be thrown.
-
-	Parameters:
-
-		s - The string to parse.
-		base - Optional radix (default is to guess based on *s*).
-
-	Returns:
-
-		a <BigInteger> instance.
-*/
-BigInteger.parse = function(s, base) {
-	// Expands a number in exponential form to decimal form.
-	// expandExponential("-13.441*10^5") === "1344100";
-	// expandExponential("1.12300e-1") === "0.112300";
-	// expandExponential(1000000000000000000000000000000) === "1000000000000000000000000000000";
-	function expandExponential(str) {
-		str = str.replace(/\s*[*xX]\s*10\s*(\^|\*\*)\s*/, "e");
-
-		return str.replace(/^([+\-])?(\d+)\.?(\d*)[eE]([+\-]?\d+)$/, function(x, s, n, f, c) {
-			c = +c;
-			var l = c < 0;
-			var i = n.length + c;
-			x = (l ? n : f).length;
-			c = ((c = Math.abs(c)) >= x ? c - x + l : 0);
-			var z = (new Array(c + 1)).join("0");
-			var r = n + f;
-			return (s || "") + (l ? r = z + r : r += z).substr(0, i += l ? z.length : 0) + (i < r.length ? "." + r.substr(i) : "");
-		});
-	}
-
-	s = s.toString();
-	if (typeof base === "undefined" || +base === 10) {
-		s = expandExponential(s);
-	}
-
-	var prefixRE;
-	if (typeof base === "undefined") {
-		prefixRE = '0[xcb]';
-	}
-	else if (base == 16) {
-		prefixRE = '0x';
-	}
-	else if (base == 8) {
-		prefixRE = '0c';
-	}
-	else if (base == 2) {
-		prefixRE = '0b';
-	}
-	else {
-		prefixRE = '';
-	}
-	var parts = new RegExp('^([+\\-]?)(' + prefixRE + ')?([0-9a-z]*)(?:\\.\\d*)?$', 'i').exec(s);
-	if (parts) {
-		var sign = parts[1] || "+";
-		var baseSection = parts[2] || "";
-		var digits = parts[3] || "";
-
-		if (typeof base === "undefined") {
-			// Guess base
-			if (baseSection === "0x" || baseSection === "0X") { // Hex
-				base = 16;
-			}
-			else if (baseSection === "0c" || baseSection === "0C") { // Octal
-				base = 8;
-			}
-			else if (baseSection === "0b" || baseSection === "0B") { // Binary
-				base = 2;
-			}
-			else {
-				base = 10;
-			}
-		}
-		else if (base < 2 || base > 36) {
-			throw new Error("Illegal radix " + base + ".");
-		}
-
-		base = +base;
-
-		// Check for digits outside the range
-		if (!(BigInteger.radixRegex[base].test(digits))) {
-			throw new Error("Bad digit for radix " + base);
-		}
-
-		// Strip leading zeros, and convert to array
-		digits = digits.replace(/^0+/, "").split("");
-		if (digits.length === 0) {
-			return ZERO;
-		}
-
-		// Get the sign (we know it's not zero)
-		sign = (sign === "-") ? -1 : 1;
-
-		// Optimize 10
-		if (base == 10) {
-			var d = [];
-			while (digits.length >= BigInteger_base_log10) {
-				d.push(parseInt(digits.splice(digits.length-BigInteger.base_log10, BigInteger.base_log10).join(''), 10));
-			}
-			d.push(parseInt(digits.join(''), 10));
-			return new BigInteger(d, sign, CONSTRUCT);
-		}
-
-		// Do the conversion
-		var d = ZERO;
-		base = BigInteger.small[base];
-		var small = BigInteger.small;
-		for (var i = 0; i < digits.length; i++) {
-			d = d.multiply(base).add(small[parseInt(digits[i], 36)]);
-		}
-		return new BigInteger(d._d, sign, CONSTRUCT);
-	}
-	else {
-		throw new Error("Invalid BigInteger format: " + s);
-	}
-};
-
-/*
-	Function: add
-	Add two <BigIntegers>.
-
-	Parameters:
-
-		n - The number to add to *this*. Will be converted to a <BigInteger>.
-
-	Returns:
-
-		The numbers added together.
-
-	See Also:
-
-		<subtract>, <multiply>, <quotient>, <next>
-*/
-BigInteger.prototype.add = function(n) {
-	if (this._s === 0) {
-		return BigInteger(n);
-	}
-
-	n = BigInteger(n);
-	if (n._s === 0) {
-		return this;
-	}
-	if (this._s !== n._s) {
-		n = n.negate();
-		return this.subtract(n);
-	}
-
-	var a = this._d;
-	var b = n._d;
-	var al = a.length;
-	var bl = b.length;
-	var sum = new Array(Math.max(al, bl) + 1);
-	var size = Math.min(al, bl);
-	var carry = 0;
-	var digit;
-
-	for (var i = 0; i < size; i++) {
-		digit = a[i] + b[i] + carry;
-		sum[i] = digit % BigInteger_base;
-		carry = (digit / BigInteger_base) | 0;
-	}
-	if (bl > al) {
-		a = b;
-		al = bl;
-	}
-	for (i = size; carry && i < al; i++) {
-		digit = a[i] + carry;
-		sum[i] = digit % BigInteger_base;
-		carry = (digit / BigInteger_base) | 0;
-	}
-	if (carry) {
-		sum[i] = carry;
-	}
-
-	for ( ; i < al; i++) {
-		sum[i] = a[i];
-	}
-
-	return new BigInteger(sum, this._s, CONSTRUCT);
-};
-
-/*
-	Function: negate
-	Get the additive inverse of a <BigInteger>.
-
-	Returns:
-
-		A <BigInteger> with the same magnatude, but with the opposite sign.
-
-	See Also:
-
-		<abs>
-*/
-BigInteger.prototype.negate = function() {
-	return new BigInteger(this._d, (-this._s) | 0, CONSTRUCT);
-};
-
-/*
-	Function: abs
-	Get the absolute value of a <BigInteger>.
-
-	Returns:
-
-		A <BigInteger> with the same magnatude, but always positive (or zero).
-
-	See Also:
-
-		<negate>
-*/
-BigInteger.prototype.abs = function() {
-	return (this._s < 0) ? this.negate() : this;
-};
-
-/*
-	Function: subtract
-	Subtract two <BigIntegers>.
-
-	Parameters:
-
-		n - The number to subtract from *this*. Will be converted to a <BigInteger>.
-
-	Returns:
-
-		The *n* subtracted from *this*.
-
-	See Also:
-
-		<add>, <multiply>, <quotient>, <prev>
-*/
-BigInteger.prototype.subtract = function(n) {
-	if (this._s === 0) {
-		return BigInteger(n).negate();
-	}
-
-	n = BigInteger(n);
-	if (n._s === 0) {
-		return this;
-	}
-	if (this._s !== n._s) {
-		n = n.negate();
-		return this.add(n);
-	}
-
-	var m = this;
-	// negative - negative => -|a| - -|b| => -|a| + |b| => |b| - |a|
-	if (this._s < 0) {
-		m = new BigInteger(n._d, 1, CONSTRUCT);
-		n = new BigInteger(this._d, 1, CONSTRUCT);
-	}
-
-	// Both are positive => a - b
-	var sign = m.compareAbs(n);
-	if (sign === 0) {
-		return ZERO;
-	}
-	else if (sign < 0) {
-		// swap m and n
-		var t = n;
-		n = m;
-		m = t;
-	}
-
-	// a > b
-	var a = m._d;
-	var b = n._d;
-	var al = a.length;
-	var bl = b.length;
-	var diff = new Array(al); // al >= bl since a > b
-	var borrow = 0;
-	var i;
-	var digit;
-
-	for (i = 0; i < bl; i++) {
-		digit = a[i] - borrow - b[i];
-		if (digit < 0) {
-			digit += BigInteger_base;
-			borrow = 1;
-		}
-		else {
-			borrow = 0;
-		}
-		diff[i] = digit;
-	}
-	for (i = bl; i < al; i++) {
-		digit = a[i] - borrow;
-		if (digit < 0) {
-			digit += BigInteger_base;
-		}
-		else {
-			diff[i++] = digit;
-			break;
-		}
-		diff[i] = digit;
-	}
-	for ( ; i < al; i++) {
-		diff[i] = a[i];
-	}
-
-	return new BigInteger(diff, sign, CONSTRUCT);
-};
-
-(function() {
-	function addOne(n, sign) {
-		var a = n._d;
-		var sum = a.slice();
-		var carry = true;
-		var i = 0;
-
-		while (true) {
-			var digit = (a[i] || 0) + 1;
-			sum[i] = digit % BigInteger_base;
-			if (digit <= BigInteger_base - 1) {
-				break;
-			}
-			++i;
-		}
-
-		return new BigInteger(sum, sign, CONSTRUCT);
-	}
-
-	function subtractOne(n, sign) {
-		var a = n._d;
-		var sum = a.slice();
-		var borrow = true;
-		var i = 0;
-
-		while (true) {
-			var digit = (a[i] || 0) - 1;
-			if (digit < 0) {
-				sum[i] = digit + BigInteger_base;
-			}
-			else {
-				sum[i] = digit;
-				break;
-			}
-			++i;
-		}
-
-		return new BigInteger(sum, sign, CONSTRUCT);
-	}
-
-	/*
-		Function: next
-		Get the next <BigInteger> (add one).
-
-		Returns:
-
-			*this* + 1.
-
-		See Also:
-
-			<add>, <prev>
-	*/
-	BigInteger.prototype.next = function() {
-		switch (this._s) {
-		case 0:
-			return ONE;
-		case -1:
-			return subtractOne(this, -1);
-		// case 1:
-		default:
-			return addOne(this, 1);
-		}
-	};
-
-	/*
-		Function: prev
-		Get the previous <BigInteger> (subtract one).
-
-		Returns:
-
-			*this* - 1.
-
-		See Also:
-
-			<next>, <subtract>
-	*/
-	BigInteger.prototype.prev = function() {
-		switch (this._s) {
-		case 0:
-			return M_ONE;
-		case -1:
-			return addOne(this, -1);
-		// case 1:
-		default:
-			return subtractOne(this, 1);
-		}
-	};
-})();
-
-/*
-	Function: compareAbs
-	Compare the absolute value of two <BigIntegers>.
-
-	Calling <compareAbs> is faster than calling <abs> twice, then <compare>.
-
-	Parameters:
-
-		n - The number to compare to *this*. Will be converted to a <BigInteger>.
-
-	Returns:
-
-		-1, 0, or +1 if *|this|* is less than, equal to, or greater than *|n|*.
-
-	See Also:
-
-		<compare>, <abs>
-*/
-BigInteger.prototype.compareAbs = function(n) {
-	if (this === n) {
-		return 0;
-	}
-
-	if (!(n instanceof BigInteger)) {
-		if (!isFinite(n)) {
-			return(isNaN(n) ? n : -1);
-		}
-		n = BigInteger(n);
-	}
-
-	if (this._s === 0) {
-		return (n._s !== 0) ? -1 : 0;
-	}
-	if (n._s === 0) {
-		return 1;
-	}
-
-	var l = this._d.length;
-	var nl = n._d.length;
-	if (l < nl) {
-		return -1;
-	}
-	else if (l > nl) {
-		return 1;
-	}
-
-	var a = this._d;
-	var b = n._d;
-	for (var i = l-1; i >= 0; i--) {
-		if (a[i] !== b[i]) {
-			return a[i] < b[i] ? -1 : 1;
-		}
-	}
-
-	return 0;
-};
-
-/*
-	Function: compare
-	Compare two <BigIntegers>.
-
-	Parameters:
-
-		n - The number to compare to *this*. Will be converted to a <BigInteger>.
-
-	Returns:
-
-		-1, 0, or +1 if *this* is less than, equal to, or greater than *n*.
-
-	See Also:
-
-		<compareAbs>, <isPositive>, <isNegative>, <isUnit>
-*/
-BigInteger.prototype.compare = function(n) {
-	if (this === n) {
-		return 0;
-	}
-
-	n = BigInteger(n);
-
-	if (this._s === 0) {
-		return -n._s;
-	}
-
-	if (this._s === n._s) { // both positive or both negative
-		var cmp = this.compareAbs(n);
-		return cmp * this._s;
-	}
-	else {
-		return this._s;
-	}
-};
-
-/*
-	Function: isUnit
-	Return true iff *this* is either 1 or -1.
-
-	Returns:
-
-		true if *this* compares equal to <BigInteger.ONE> or <BigInteger.M_ONE>.
-
-	See Also:
-
-		<isZero>, <isNegative>, <isPositive>, <compareAbs>, <compare>,
-		<BigInteger.ONE>, <BigInteger.M_ONE>
-*/
-BigInteger.prototype.isUnit = function() {
-	return this === ONE ||
-		this === M_ONE ||
-		(this._d.length === 1 && this._d[0] === 1);
-};
-
-/*
-	Function: multiply
-	Multiply two <BigIntegers>.
-
-	Parameters:
-
-		n - The number to multiply *this* by. Will be converted to a
-		<BigInteger>.
-
-	Returns:
-
-		The numbers multiplied together.
-
-	See Also:
-
-		<add>, <subtract>, <quotient>, <square>
-*/
-BigInteger.prototype.multiply = function(n) {
-	// TODO: Consider adding Karatsuba multiplication for large numbers
-	if (this._s === 0) {
-		return ZERO;
-	}
-
-	n = BigInteger(n);
-	if (n._s === 0) {
-		return ZERO;
-	}
-	if (this.isUnit()) {
-		if (this._s < 0) {
-			return n.negate();
-		}
-		return n;
-	}
-	if (n.isUnit()) {
-		if (n._s < 0) {
-			return this.negate();
-		}
-		return this;
-	}
-	if (this === n) {
-		return this.square();
-	}
-
-	var r = (this._d.length >= n._d.length);
-	var a = (r ? this : n)._d; // a will be longer than b
-	var b = (r ? n : this)._d;
-	var al = a.length;
-	var bl = b.length;
-
-	var pl = al + bl;
-	var partial = new Array(pl);
-	var i;
-	for (i = 0; i < pl; i++) {
-		partial[i] = 0;
-	}
-
-	for (i = 0; i < bl; i++) {
-		var carry = 0;
-		var bi = b[i];
-		var jlimit = al + i;
-		var digit;
-		for (var j = i; j < jlimit; j++) {
-			digit = partial[j] + bi * a[j - i] + carry;
-			carry = (digit / BigInteger_base) | 0;
-			partial[j] = (digit % BigInteger_base) | 0;
-		}
-		if (carry) {
-			digit = partial[j] + carry;
-			carry = (digit / BigInteger_base) | 0;
-			partial[j] = digit % BigInteger_base;
-		}
-	}
-	return new BigInteger(partial, this._s * n._s, CONSTRUCT);
-};
-
-// Multiply a BigInteger by a single-digit native number
-// Assumes that this and n are >= 0
-// This is not really intended to be used outside the library itself
-BigInteger.prototype.multiplySingleDigit = function(n) {
-	if (n === 0 || this._s === 0) {
-		return ZERO;
-	}
-	if (n === 1) {
-		return this;
-	}
-
-	var digit;
-	if (this._d.length === 1) {
-		digit = this._d[0] * n;
-		if (digit >= BigInteger_base) {
-			return new BigInteger([(digit % BigInteger_base)|0,
-					(digit / BigInteger_base)|0], 1, CONSTRUCT);
-		}
-		return new BigInteger([digit], 1, CONSTRUCT);
-	}
-
-	if (n === 2) {
-		return this.add(this);
-	}
-	if (this.isUnit()) {
-		return new BigInteger([n], 1, CONSTRUCT);
-	}
-
-	var a = this._d;
-	var al = a.length;
-
-	var pl = al + 1;
-	var partial = new Array(pl);
-	for (var i = 0; i < pl; i++) {
-		partial[i] = 0;
-	}
-
-	var carry = 0;
-	for (var j = 0; j < al; j++) {
-		digit = n * a[j] + carry;
-		carry = (digit / BigInteger_base) | 0;
-		partial[j] = (digit % BigInteger_base) | 0;
-	}
-	if (carry) {
-		partial[j] = carry;
-	}
-
-	return new BigInteger(partial, 1, CONSTRUCT);
-};
-
-/*
-	Function: square
-	Multiply a <BigInteger> by itself.
-
-	This is slightly faster than regular multiplication, since it removes the
-	duplicated multiplcations.
-
-	Returns:
-
-		> this.multiply(this)
-
-	See Also:
-		<multiply>
-*/
-BigInteger.prototype.square = function() {
-	// Normally, squaring a 10-digit number would take 100 multiplications.
-	// Of these 10 are unique diagonals, of the remaining 90 (100-10), 45 are repeated.
-	// This procedure saves (N*(N-1))/2 multiplications, (e.g., 45 of 100 multiplies).
-	// Based on code by Gary Darby, Intellitech Systems Inc., www.DelphiForFun.org
-
-	if (this._s === 0) {
-		return ZERO;
-	}
-	if (this.isUnit()) {
-		return ONE;
-	}
-
-	var digits = this._d;
-	var length = digits.length;
-	var imult1 = new Array(length + length + 1);
-	var product, carry, k;
-	var i;
-
-	// Calculate diagonal
-	for (i = 0; i < length; i++) {
-		k = i * 2;
-		product = digits[i] * digits[i];
-		carry = (product / BigInteger_base) | 0;
-		imult1[k] = product % BigInteger_base;
-		imult1[k + 1] = carry;
-	}
-
-	// Calculate repeating part
-	for (i = 0; i < length; i++) {
-		carry = 0;
-		k = i * 2 + 1;
-		for (var j = i + 1; j < length; j++, k++) {
-			product = digits[j] * digits[i] * 2 + imult1[k] + carry;
-			carry = (product / BigInteger_base) | 0;
-			imult1[k] = product % BigInteger_base;
-		}
-		k = length + i;
-		var digit = carry + imult1[k];
-		carry = (digit / BigInteger_base) | 0;
-		imult1[k] = digit % BigInteger_base;
-		imult1[k + 1] += carry;
-	}
-
-	return new BigInteger(imult1, 1, CONSTRUCT);
-};
-
-/*
-	Function: quotient
-	Divide two <BigIntegers> and truncate towards zero.
-
-	<quotient> throws an exception if *n* is zero.
-
-	Parameters:
-
-		n - The number to divide *this* by. Will be converted to a <BigInteger>.
-
-	Returns:
-
-		The *this* / *n*, truncated to an integer.
-
-	See Also:
-
-		<add>, <subtract>, <multiply>, <divRem>, <remainder>
-*/
-BigInteger.prototype.quotient = function(n) {
-	return this.divRem(n)[0];
-};
-
-/*
-	Function: divide
-	Deprecated synonym for <quotient>.
-*/
-BigInteger.prototype.divide = BigInteger.prototype.quotient;
-
-/*
-	Function: remainder
-	Calculate the remainder of two <BigIntegers>.
-
-	<remainder> throws an exception if *n* is zero.
-
-	Parameters:
-
-		n - The remainder after *this* is divided *this* by *n*. Will be
-			converted to a <BigInteger>.
-
-	Returns:
-
-		*this* % *n*.
-
-	See Also:
-
-		<divRem>, <quotient>
-*/
-BigInteger.prototype.remainder = function(n) {
-	return this.divRem(n)[1];
-};
-
-/*
-	Function: divRem
-	Calculate the integer quotient and remainder of two <BigIntegers>.
-
-	<divRem> throws an exception if *n* is zero.
-
-	Parameters:
-
-		n - The number to divide *this* by. Will be converted to a <BigInteger>.
-
-	Returns:
-
-		A two-element array containing the quotient and the remainder.
-
-		> a.divRem(b)
-
-		is exactly equivalent to
-
-		> [a.quotient(b), a.remainder(b)]
-
-		except it is faster, because they are calculated at the same time.
-
-	See Also:
-
-		<quotient>, <remainder>
-*/
-BigInteger.prototype.divRem = function(n) {
-	n = BigInteger(n);
-	if (n._s === 0) {
-		throw new Error("Divide by zero");
-	}
-	if (this._s === 0) {
-		return [ZERO, ZERO];
-	}
-	if (n._d.length === 1) {
-		return this.divRemSmall(n._s * n._d[0]);
-	}
-
-	// Test for easy cases -- |n1| <= |n2|
-	switch (this.compareAbs(n)) {
-	case 0: // n1 == n2
-		return [this._s === n._s ? ONE : M_ONE, ZERO];
-	case -1: // |n1| < |n2|
-		return [ZERO, this];
-	}
-
-	var sign = this._s * n._s;
-	var a = n.abs();
-	var b_digits = this._d;
-	var b_index = b_digits.length;
-	var digits = n._d.length;
-	var quot = [];
-	var guess;
-
-	var part = new BigInteger([], 0, CONSTRUCT);
-
-	while (b_index) {
-		part._d.unshift(b_digits[--b_index]);
-		part = new BigInteger(part._d, 1, CONSTRUCT);
-
-		if (part.compareAbs(n) < 0) {
-			quot.push(0);
-			continue;
-		}
-		if (part._s === 0) {
-			guess = 0;
-		}
-		else {
-			var xlen = part._d.length, ylen = a._d.length;
-			var highx = part._d[xlen-1]*BigInteger_base + part._d[xlen-2];
-			var highy = a._d[ylen-1]*BigInteger_base + a._d[ylen-2];
-			if (part._d.length > a._d.length) {
-				// The length of part._d can either match a._d length,
-				// or exceed it by one.
-				highx = (highx+1)*BigInteger_base;
-			}
-			guess = Math.ceil(highx/highy);
-		}
-		do {
-			var check = a.multiplySingleDigit(guess);
-			if (check.compareAbs(part) <= 0) {
-				break;
-			}
-			guess--;
-		} while (guess);
-
-		quot.push(guess);
-		if (!guess) {
-			continue;
-		}
-		var diff = part.subtract(check);
-		part._d = diff._d.slice();
-	}
-
-	return [new BigInteger(quot.reverse(), sign, CONSTRUCT),
-		   new BigInteger(part._d, this._s, CONSTRUCT)];
-};
-
-// Throws an exception if n is outside of (-BigInteger.base, -1] or
-// [1, BigInteger.base).  It's not necessary to call this, since the
-// other division functions will call it if they are able to.
-BigInteger.prototype.divRemSmall = function(n) {
-	var r;
-	n = +n;
-	if (n === 0) {
-		throw new Error("Divide by zero");
-	}
-
-	var n_s = n < 0 ? -1 : 1;
-	var sign = this._s * n_s;
-	n = Math.abs(n);
-
-	if (n < 1 || n >= BigInteger_base) {
-		throw new Error("Argument out of range");
-	}
-
-	if (this._s === 0) {
-		return [ZERO, ZERO];
-	}
-
-	if (n === 1 || n === -1) {
-		return [(sign === 1) ? this.abs() : new BigInteger(this._d, sign, CONSTRUCT), ZERO];
-	}
-
-	// 2 <= n < BigInteger_base
-
-	// divide a single digit by a single digit
-	if (this._d.length === 1) {
-		var q = new BigInteger([(this._d[0] / n) | 0], 1, CONSTRUCT);
-		r = new BigInteger([(this._d[0] % n) | 0], 1, CONSTRUCT);
-		if (sign < 0) {
-			q = q.negate();
-		}
-		if (this._s < 0) {
-			r = r.negate();
-		}
-		return [q, r];
-	}
-
-	var digits = this._d.slice();
-	var quot = new Array(digits.length);
-	var part = 0;
-	var diff = 0;
-	var i = 0;
-	var guess;
-
-	while (digits.length) {
-		part = part * BigInteger_base + digits[digits.length - 1];
-		if (part < n) {
-			quot[i++] = 0;
-			digits.pop();
-			diff = BigInteger_base * diff + part;
-			continue;
-		}
-		if (part === 0) {
-			guess = 0;
-		}
-		else {
-			guess = (part / n) | 0;
-		}
-
-		var check = n * guess;
-		diff = part - check;
-		quot[i++] = guess;
-		if (!guess) {
-			digits.pop();
-			continue;
-		}
-
-		digits.pop();
-		part = diff;
-	}
-
-	r = new BigInteger([diff], 1, CONSTRUCT);
-	if (this._s < 0) {
-		r = r.negate();
-	}
-	return [new BigInteger(quot.reverse(), sign, CONSTRUCT), r];
-};
-
-/*
-	Function: isEven
-	Return true iff *this* is divisible by two.
-
-	Note that <BigInteger.ZERO> is even.
-
-	Returns:
-
-		true if *this* is even, false otherwise.
-
-	See Also:
-
-		<isOdd>
-*/
-BigInteger.prototype.isEven = function() {
-	var digits = this._d;
-	return this._s === 0 || digits.length === 0 || (digits[0] % 2) === 0;
-};
-
-/*
-	Function: isOdd
-	Return true iff *this* is not divisible by two.
-
-	Returns:
-
-		true if *this* is odd, false otherwise.
-
-	See Also:
-
-		<isEven>
-*/
-BigInteger.prototype.isOdd = function() {
-	return !this.isEven();
-};
-
-/*
-	Function: sign
-	Get the sign of a <BigInteger>.
-
-	Returns:
-
-		* -1 if *this* < 0
-		* 0 if *this* == 0
-		* +1 if *this* > 0
-
-	See Also:
-
-		<isZero>, <isPositive>, <isNegative>, <compare>, <BigInteger.ZERO>
-*/
-BigInteger.prototype.sign = function() {
-	return this._s;
-};
-
-/*
-	Function: isPositive
-	Return true iff *this* > 0.
-
-	Returns:
-
-		true if *this*.compare(<BigInteger.ZERO>) == 1.
-
-	See Also:
-
-		<sign>, <isZero>, <isNegative>, <isUnit>, <compare>, <BigInteger.ZERO>
-*/
-BigInteger.prototype.isPositive = function() {
-	return this._s > 0;
-};
-
-/*
-	Function: isNegative
-	Return true iff *this* < 0.
-
-	Returns:
-
-		true if *this*.compare(<BigInteger.ZERO>) == -1.
-
-	See Also:
-
-		<sign>, <isPositive>, <isZero>, <isUnit>, <compare>, <BigInteger.ZERO>
-*/
-BigInteger.prototype.isNegative = function() {
-	return this._s < 0;
-};
-
-/*
-	Function: isZero
-	Return true iff *this* == 0.
-
-	Returns:
-
-		true if *this*.compare(<BigInteger.ZERO>) == 0.
-
-	See Also:
-
-		<sign>, <isPositive>, <isNegative>, <isUnit>, <BigInteger.ZERO>
-*/
-BigInteger.prototype.isZero = function() {
-	return this._s === 0;
-};
-
-/*
-	Function: exp10
-	Multiply a <BigInteger> by a power of 10.
-
-	This is equivalent to, but faster than
-
-	> if (n >= 0) {
-	>	 return this.multiply(BigInteger("1e" + n));
-	> }
-	> else { // n <= 0
-	>	 return this.quotient(BigInteger("1e" + -n));
-	> }
-
-	Parameters:
-
-		n - The power of 10 to multiply *this* by. *n* is converted to a
-		javascipt number and must be no greater than <BigInteger.MAX_EXP>
-		(0x7FFFFFFF), or an exception will be thrown.
-
-	Returns:
-
-		*this* * (10 ** *n*), truncated to an integer if necessary.
-
-	See Also:
-
-		<pow>, <multiply>
-*/
-BigInteger.prototype.exp10 = function(n) {
-	n = +n;
-	if (n === 0) {
-		return this;
-	}
-	if (Math.abs(n) > Number(MAX_EXP)) {
-		throw new Error("exponent too large in BigInteger.exp10");
-	}
-	// Optimization for this == 0. This also keeps us from having to trim zeros in the positive n case
-	if (this._s === 0) {
-		return ZERO;
-	}
-	if (n > 0) {
-		var k = new BigInteger(this._d.slice(), this._s, CONSTRUCT);
-
-		for (; n >= BigInteger_base_log10; n -= BigInteger_base_log10) {
-			k._d.unshift(0);
-		}
-		if (n == 0)
-			return k;
-		k._s = 1;
-		k = k.multiplySingleDigit(Math.pow(10, n));
-		return (this._s < 0 ? k.negate() : k);
-	} else if (-n >= this._d.length*BigInteger_base_log10) {
-		return ZERO;
-	} else {
-		var k = new BigInteger(this._d.slice(), this._s, CONSTRUCT);
-
-		for (n = -n; n >= BigInteger_base_log10; n -= BigInteger_base_log10) {
-			k._d.shift();
-		}
-		return (n == 0) ? k : k.divRemSmall(Math.pow(10, n))[0];
-	}
-};
-
-/*
-	Function: pow
-	Raise a <BigInteger> to a power.
-
-	In this implementation, 0**0 is 1.
-
-	Parameters:
-
-		n - The exponent to raise *this* by. *n* must be no greater than
-		<BigInteger.MAX_EXP> (0x7FFFFFFF), or an exception will be thrown.
-
-	Returns:
-
-		*this* raised to the *nth* power.
-
-	See Also:
-
-		<modPow>
-*/
-BigInteger.prototype.pow = function(n) {
-	if (this.isUnit()) {
-		if (this._s > 0) {
-			return this;
-		}
-		else {
-			return BigInteger(n).isOdd() ? this : this.negate();
-		}
-	}
-
-	n = BigInteger(n);
-	if (n._s === 0) {
-		return ONE;
-	}
-	else if (n._s < 0) {
-		if (this._s === 0) {
-			throw new Error("Divide by zero");
-		}
-		else {
-			return ZERO;
-		}
-	}
-	if (this._s === 0) {
-		return ZERO;
-	}
-	if (n.isUnit()) {
-		return this;
-	}
-
-	if (n.compareAbs(MAX_EXP) > 0) {
-		throw new Error("exponent too large in BigInteger.pow");
-	}
-	var x = this;
-	var aux = ONE;
-	var two = BigInteger.small[2];
-
-	while (n.isPositive()) {
-		if (n.isOdd()) {
-			aux = aux.multiply(x);
-			if (n.isUnit()) {
-				return aux;
-			}
-		}
-		x = x.square();
-		n = n.quotient(two);
-	}
-
-	return aux;
-};
-
-/*
-	Function: modPow
-	Raise a <BigInteger> to a power (mod m).
-
-	Because it is reduced by a modulus, <modPow> is not limited by
-	<BigInteger.MAX_EXP> like <pow>.
-
-	Parameters:
-
-		exponent - The exponent to raise *this* by. Must be positive.
-		modulus - The modulus.
-
-	Returns:
-
-		*this* ^ *exponent* (mod *modulus*).
-
-	See Also:
-
-		<pow>, <mod>
-*/
-BigInteger.prototype.modPow = function(exponent, modulus) {
-	var result = ONE;
-	var base = this;
-
-	while (exponent.isPositive()) {
-		if (exponent.isOdd()) {
-			result = result.multiply(base).remainder(modulus);
-		}
-
-		exponent = exponent.quotient(BigInteger.small[2]);
-		if (exponent.isPositive()) {
-			base = base.square().remainder(modulus);
-		}
-	}
-
-	return result;
-};
-
-/*
-	Function: log
-	Get the natural logarithm of a <BigInteger> as a native JavaScript number.
-
-	This is equivalent to
-
-	> Math.log(this.toJSValue())
-
-	but handles values outside of the native number range.
-
-	Returns:
-
-		log( *this* )
-
-	See Also:
-
-		<toJSValue>
-*/
-BigInteger.prototype.log = function() {
-	switch (this._s) {
-	case 0:	 return -Infinity;
-	case -1: return NaN;
-	default: // Fall through.
-	}
-
-	var l = this._d.length;
-
-	if (l*BigInteger_base_log10 < 30) {
-		return Math.log(this.valueOf());
-	}
-
-	var N = Math.ceil(30/BigInteger_base_log10);
-	var firstNdigits = this._d.slice(l - N);
-	return Math.log((new BigInteger(firstNdigits, 1, CONSTRUCT)).valueOf()) + (l - N) * Math.log(BigInteger_base);
-};
-
-/*
-	Function: valueOf
-	Convert a <BigInteger> to a native JavaScript integer.
-
-	This is called automatically by JavaScipt to convert a <BigInteger> to a
-	native value.
-
-	Returns:
-
-		> parseInt(this.toString(), 10)
-
-	See Also:
-
-		<toString>, <toJSValue>
-*/
-BigInteger.prototype.valueOf = function() {
-	return parseInt(this.toString(), 10);
-};
-
-/*
-	Function: toJSValue
-	Convert a <BigInteger> to a native JavaScript integer.
-
-	This is the same as valueOf, but more explicitly named.
-
-	Returns:
-
-		> parseInt(this.toString(), 10)
-
-	See Also:
-
-		<toString>, <valueOf>
-*/
-BigInteger.prototype.toJSValue = function() {
-	return parseInt(this.toString(), 10);
-};
-
-/*
-	Function: lowVal
-	Author: Lucas Jones
-*/
-BigInteger.prototype.lowVal = function () {
-	return this._d[0] || 0;
-};
-
-var MAX_EXP = BigInteger(0x7FFFFFFF);
-// Constant: MAX_EXP
-// The largest exponent allowed in <pow> and <exp10> (0x7FFFFFFF or 2147483647).
-BigInteger.MAX_EXP = MAX_EXP;
-
-(function() {
-	function makeUnary(fn) {
-		return function(a) {
-			return fn.call(BigInteger(a));
-		};
-	}
-
-	function makeBinary(fn) {
-		return function(a, b) {
-			return fn.call(BigInteger(a), BigInteger(b));
-		};
-	}
-
-	function makeTrinary(fn) {
-		return function(a, b, c) {
-			return fn.call(BigInteger(a), BigInteger(b), BigInteger(c));
-		};
-	}
-
-	(function() {
-		var i, fn;
-		var unary = "toJSValue,isEven,isOdd,sign,isZero,isNegative,abs,isUnit,square,negate,isPositive,toString,next,prev,log".split(",");
-		var binary = "compare,remainder,divRem,subtract,add,quotient,divide,multiply,pow,compareAbs".split(",");
-		var trinary = ["modPow"];
-
-		for (i = 0; i < unary.length; i++) {
-			fn = unary[i];
-			BigInteger[fn] = makeUnary(BigInteger.prototype[fn]);
-		}
-
-		for (i = 0; i < binary.length; i++) {
-			fn = binary[i];
-			BigInteger[fn] = makeBinary(BigInteger.prototype[fn]);
-		}
-
-		for (i = 0; i < trinary.length; i++) {
-			fn = trinary[i];
-			BigInteger[fn] = makeTrinary(BigInteger.prototype[fn]);
-		}
-
-		BigInteger.exp10 = function(x, n) {
-			return BigInteger(x).exp10(n);
-		};
-	})();
-})();
-
-exports.BigInteger = BigInteger;
-})(typeof exports !== 'undefined' ? exports : this);
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_MoneroDaemon.js.html b/docs/src_main_js_daemon_MoneroDaemon.js.html deleted file mode 100644 index b5e01b1fa..000000000 --- a/docs/src_main_js_daemon_MoneroDaemon.js.html +++ /dev/null @@ -1,740 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/MoneroDaemon.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/MoneroDaemon.js

- - - - - - -
-
-
/**
- * Copyright (c) woodser
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/**
- * Monero daemon interface and default implementations.
- * 
- * @interface
- */
-class MoneroDaemon {
-  
-  /**
-   * Indicates if the client is connected to the daemon via RPC.
-   * 
-   * @return {boolean} true if the client is connected to the daemon, false otherwise
-   */
-  async isConnected() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Gets the version of the daemon.
-   * 
-   * @return {MoneroVersion} the version of the daemon
-   */
-  async getVersion() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Indicates if the daemon is trusted xor untrusted.
-   * 
-   * @return {boolean} true if the daemon is trusted, false otherwise
-   */
-  async isTrusted() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get the number of blocks in the longest chain known to the node.
-   * 
-   * @return {int} the number of blocks
-   */
-  async getHeight() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get a block's hash by its height.
-   * 
-   * @param {int} height - height of the block hash to get
-   * @return {string} the block's hash at the given height
-   */
-  async getBlockHash(height) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get a block template for mining a new block.
-   * 
-   * @param {string} walletAddress - address of the wallet to receive miner transactions if block is successfully mined
-   * @param {int} reserveSize - reserve size (optional)
-   * @return {MoneroBlockTemplate} is a block template for mining a new block
-   */
-  async getBlockTemplate(walletAddress, reserveSize) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get the last block's header.
-   * 
-   * @return {MoneroBlockHeader} last block's header
-   */
-  async getLastBlockHeader() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get a block header by its hash.
-   * 
-   * @param {string} blockHash - hash of the block to get the header of
-   * @return {MoneroBlockHeader} block's header
-   */
-  async getBlockHeaderByHash(blockHash) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get a block header by its height.
-   * 
-   * @param {int} height - height of the block to get the header of
-   * @return {MoneroBlockHeader} block's header
-   */
-  async getBlockHeaderByHeight(height) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get block headers for the given range.
-   * 
-   * @param {int} startHeight - start height lower bound inclusive (optional)
-   * @param {int} endHeight - end height upper bound inclusive (optional)
-   * @return {MoneroBlockHeader[]} for the given range
-   */
-  async getBlockHeadersByRange(startHeight, endHeight) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get a block by hash.
-   * 
-   * @param {string} blockHash - hash of the block to get
-   * @return {MoneroBlock} with the given hash
-   */
-  async getBlockByHash(blockHash) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get blocks by hash.
-   * 
-   * @param {string[]} blockHashes - array of hashes; first 10 blocks hashes goes sequential,
-   *        next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on,
-   *        and the last one is always genesis block
-   * @param {int} startHeight - start height to get blocks by hash
-   * @param {boolean} prune - specifies if returned blocks should be pruned (defaults to false)  // TODO: test default
-   * @return {MoneroBlock[]} retrieved blocks
-   */
-  async getBlocksByHash(blockHashes, startHeight, prune) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get a block by height.
-   * 
-   * @param {int} height - height of the block to get
-   * @return {MoneroBlock} with the given height
-   */
-  async getBlockByHeight(height) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get blocks at the given heights.
-   * 
-   * @param {int[]} heights - heights of the blocks to get
-   * @return {MoneroBlock[]} are blocks at the given heights
-   */
-  async getBlocksByHeight(heights) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get blocks in the given height range.
-   * 
-   * @param {int} startHeight - start height lower bound inclusive (optional)
-   * @param {int} endHeight - end height upper bound inclusive (optional)
-   * @return {MoneroBlock[]} are blocks in the given height range
-   */
-  async getBlocksByRange(startHeight, endHeight) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get blocks in the given height range as chunked requests so that each request is
-   * not too big.
-   * 
-   * @param {int} startHeight - start height lower bound inclusive (optional)
-   * @param {int} endHeight - end height upper bound inclusive (optional)
-   * @param {int} maxChunkSize - maximum chunk size in any one request (default 3,000,000 bytes)
-   * @return {MoneroBlock[]} blocks in the given height range
-   */
-  async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get block hashes as a binary request to the daemon.
-   * 
-   * @param {string[]} blockHashes - specify block hashes to fetch; first 10 blocks hash goes
-   *        sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64
-   *        and so on, and the last one is always genesis block
-   * @param {int} startHeight - starting height of block hashes to return
-   * @return {string[]} requested block hashes     
-   */
-  async getBlockHashes(blockHashes, startHeight) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get a transaction by hash.
-   * 
-   * @param {string} txHash - hash of the transaction to get
-   * @param {boolean} prune - specifies if the returned tx should be pruned (defaults to false)
-   * @return {MoneroTx} transaction with the given hash
-   */
-  async getTx(txHash, prune = false) {
-    return (await this.getTxs([txHash], prune))[0];
-  }
-  
-  /**
-   * Get transactions by hashes.
-   * 
-   * @param {string[]} txHashes - hashes of transactions to get
-   * @param {boolean} prune - specifies if the returned txs should be pruned (defaults to false)
-   * @return {MoneroTx[]} transactions with the given hashes
-   */
-  async getTxs(txHashes, prune = false) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get a transaction hex by hash.
-   * 
-   * @param {string} txHash - hash of the transaction to get hex from
-   * @param {boolean} prune - specifies if the returned tx hex should be pruned (defaults to false)
-   * @return {string} tx hex with the given hash
-   */
-  async getTxHex(txHash, prune = false) {
-    return (await this.getTxHexes([txHash], prune))[0];
-  }
-  
-  /**
-   * Get transaction hexes by hashes.
-   * 
-   * @param {string[]} txHashes - hashes of transactions to get hexes from
-   * @param {boolean} prune - specifies if the returned tx hexes should be pruned (defaults to false)
-   * @return {string[]} tx hexes
-   */
-  async getTxHexes(txHashes, prune = false) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Gets the total emissions and fees from the genesis block to the current height.
-   * 
-   * @param {int} height - height to start computing the miner sum
-   * @param {int} numBlocks - number of blocks to include in the sum
-   * @return {MoneroMinerTxSum} encapsulates the total emissions and fees since the genesis block
-   */
-  async getMinerTxSum(height, numBlocks) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get the fee estimate per kB.
-   * 
-   * @param {int} graceBlocks TODO
-   * @return {BigInteger} fee estimate per kB.
-   */
-  async getFeeEstimate(graceBlocks) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Submits a transaction to the daemon's pool.
-   * 
-   * @param {string} txHex - raw transaction hex to submit
-   * @param {boolean} doNotRelay specifies if the tx should be relayed (optional)
-   * @return {MoneroSubmitTxResult} contains submission results
-   */
-  async submitTxHex(txHex, doNotRelay) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Relays a transaction by hash.
-   * 
-   * @param {string} txHash - hash of the transaction to relay
-   */
-  async relayTxByHash(txHash) {
-    const assert = require("assert");
-    assert.equal(typeof txHash, "string", "Must provide a transaction hash");
-    await this.relayTxsByHash([txHash]);
-  }
-  
-  /**
-   * Relays transactions by hash.
-   * 
-   * @param {string[]} txHashes - hashes of the transactinos to relay
-   */
-  async relayTxsByHash(txHashes) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get valid transactions seen by the node but not yet mined into a block, as well
-   * as spent key image information for the tx pool.
-   * 
-   * @return {MoneroTx[]} are transactions in the transaction pool
-   */
-  async getTxPool() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get hashes of transactions in the transaction pool.
-   * 
-   * @return {string[]} are hashes of transactions in the transaction pool
-   */
-  async getTxPoolHashes() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get all transaction pool backlog.
-   * 
-   * @return {MoneroTxBacklogEntry[]} backlog entries 
-   */
-  async getTxPoolBacklog() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get transaction pool statistics.
-   * 
-   * @return {MoneroTxPoolStats} contains statistics about the transaction pool
-   */
-  async getTxPoolStats() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Flush transactions from the tx pool.
-   * 
-   * @param {(string|string[])} hashes - specific transactions to flush (defaults to all)
-   */
-  async flushTxPool(hashes) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get the spent status of the given key image.
-   * 
-   * @param {string} keyImage - key image hex to get the status of
-   * @return {MoneroKeyImageSpentStatus} status of the key image
-   */
-  async getKeyImageSpentStatus(keyImage) {
-    return (await this.getKeyImageSpentStatuses([keyImage]))[0];
-  }
-  
-  /**
-   * Get the spent status of each given key image.
-   * 
-   * @param {string[]} keyImages are hex key images to get the statuses of
-   * @return {MoneroKeyImageSpentStatus[]} status for each key image
-   */
-  async getKeyImageSpentStatuses(keyImages) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get outputs identified by a list of output amounts and indices as a binary
-   * request.
-   * 
-   * @param {MoneroOutput[]} outputs - identify each output by amount and index
-   * @return {MoneroOutput[]} identified outputs
-   */
-  async getOutputs(outputs) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get a histogram of output amounts. For all amounts (possibly filtered by
-   * parameters), gives the number of outputs on the chain for that amount.
-   * RingCT outputs counts as 0 amount.
-   * 
-   * @param {BigInteger[]} amounts - amounts of outputs to make the histogram with
-   * @param {int} minCount - TODO
-   * @param {int} maxCount - TODO
-   * @param {boolean} isUnlocked - makes a histogram with outputs with the specified lock state
-   * @param {int} recentCutoff - TODO
-   * @return {MoneroOutputHistogramEntry[]} are entries meeting the parameters
-   */
-  async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Creates an output distribution.
-   * 
-   * @param {BigInteger[]} amounts - amounts of outputs to make the distribution with
-   * @param {boolean} cumulative - specifies if the results should be cumulative (defaults to TODO)
-   * @param {int} startHeight - start height lower bound inclusive (optional)
-   * @param {int} endHeight - end height upper bound inclusive (optional)
-   * @return {MoneroOutputDistributionEntry[]} are entries meeting the parameters
-   */
-  async getOutputDistribution(amounts, cumulative, startHeight, endHeight) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get general information about the state of the node and the network.
-   * 
-   * @return {MoneroDaemonInfo} is general information about the node and network
-   */
-  async getInfo() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get synchronization information.
-   * 
-   * @return {MoneroDaemonSyncInfo} contains sync information
-   */
-  async getSyncInfo() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Look up information regarding hard fork voting and readiness.
-   * 
-   * @return {MoneroHardForkInfo} contains hard fork information
-   */
-  async getHardForkInfo() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get alternative chains seen by the node.
-   * 
-   * @return {MoneroAltChain[]} alternative chains
-   */
-  async getAltChains() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get known block hashes which are not on the main chain.
-   * 
-   * @return {string[]} known block hashes which are not on the main chain
-   */
-  async getAltBlockHashes() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get the download bandwidth limit.
-   * 
-   * @return {int} download bandwidth limit
-   */
-  async getDownloadLimit() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Set the download bandwidth limit.
-   * 
-   * @param {int} limit - download limit to set (-1 to reset to default)
-   * @return {int} new download limit after setting
-   */
-  async setDownloadLimit(limit) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Reset the download bandwidth limit.
-   * 
-   * @return {int} download bandwidth limit after resetting
-   */
-  async resetDownloadLimit() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get the upload bandwidth limit.
-   * 
-   * @return {int} upload bandwidth limit
-   */
-  async getUploadLimit() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Set the upload bandwidth limit.
-   * 
-   * @param limit - upload limit to set (-1 to reset to default)
-   * @return {int} new upload limit after setting
-   */
-  async setUploadLimit(limit) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Reset the upload bandwidth limit.
-   * 
-   * @return {int} upload bandwidth limit after resetting
-   */
-  async resetUploadLimit() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get known peers including their last known online status.
-   * 
-   * @return {MoneroDaemonPeer[]} known peers
-   */
-  async getKnownPeers() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get incoming and outgoing connections to the node.
-   * 
-   * @return {MoneroDaemonConnection[]} daemon's peer connections
-   */
-  async getConnections() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Limit number of outgoing peers.
-   * 
-   * @param {int} limit - maximum number of outgoing peers
-   */
-  async setOutgoingPeerLimit(limit) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Limit number of incoming peers.
-   * 
-   * @param {int} limit - maximum number of incoming peers
-   */
-  async setIncomingPeerLimit(limit) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get peer bans.
-   * 
-   * @return {MoneroBan[]} entries about banned peers
-   */
-  async getPeerBans() {
-    throw new MoneroError("Subclass must implement");
-  }
-
-  /**
-   * Ban a peer node.
-   * 
-   * @param {MoneroBan} ban - contains information about a node to ban
-   */
-  async setPeerBan(ban) {
-    return await this.setPeerBans([ban]);
-  }
-  
-  /**
-   * Ban peers nodes.
-   * 
-   * @param {MoneroBan[]} bans - specify which peers to ban
-   */
-  async setPeerBans(bans) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Start mining.
-   * 
-   * @param {string} address - address given miner rewards if the daemon mines a block
-   * @param {integer} numThreads - number of mining threads to run
-   * @param {boolean} isBackground - specifies if the miner should run in the background or not
-   * @param {boolean} ignoreBattery - specifies if the battery state (e.g. on laptop) should be ignored or not
-   */
-  async startMining(address, numThreads, isBackground, ignoreBattery) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Stop mining.
-   */
-  async stopMining() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get the daemon's mining status.
-   * 
-   * @return {MoneroMiningStatus} daemon's mining status
-   */
-  async getMiningStatus() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Submit a mined block to the network.
-   * 
-   * @param {string} blockBlob - mined block to submit
-   */
-  async submitBlock(blockBlob) {
-    await this.submitBlocks([blockBlob]);
-  }
-  
-  /**
-   * Submit mined blocks to the network.
-   * 
-   * @param {string[]} blockBlobs - mined blocks to submit
-   */
-  async submitBlocks(blockBlobs) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Check for update.
-   * 
-   * @return {MoneroDaemonUpdateCheckResult} the result
-   */
-  async checkForUpdate() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Download an update.
-   * 
-   * @param {string} path - path to download the update (optional)
-   * @return {MoneroDaemonUpdateDownloadResult} the result
-   */
-  async downloadUpdate(path) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Safely disconnect and shut down the daemon.
-   */
-  async stop() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Get the header of the next block added to the chain.
-   * 
-   * @return {MoneroBlockHeader} header of the next block added to the chain
-   */
-  async getNextBlockHeader() {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Register a listener to be notified when blocks are added to the chain.
-   * 
-   * @param {function} listener - invoked with MoneroBlockHeaders as blocks are added to the chain
-   */
-  async addBlockListener(listener) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  /**
-   * Unregister a listener to be notified when blocks are added to the chain.
-   * 
-   * @param {function} listener - previously registered listener to be unregistered
-   */
-  async removeBlockListener(listener) {
-    throw new MoneroError("Subclass must implement");
-  }
-  
-  // ----------------------------- STATIC UTILITIES ---------------------------
-  
-  /**
-   * Parses a network string to an enumerated type.
-   * 
-   * @param {string} network - network string to parse
-   * @return {MoneroNetworkType} enumerated network type
-   */
-  static parseNetworkType(network) {
-    const MoneroNetworkType = require("./model/MoneroNetworkType");
-    if (network === "mainnet") return MoneroNetworkType.MAINNET;
-    if (network === "testnet") return MoneroNetworkType.TESTNET;
-    if (network === "stagenet") return MoneroNetworkType.STAGENET;
-    throw new MoneroError("Invalid network type to parse: " + network);
-  }
-}
-
-module.exports = MoneroDaemon;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_MoneroDaemonRpc.js.html b/docs/src_main_js_daemon_MoneroDaemonRpc.js.html deleted file mode 100644 index 7933f8151..000000000 --- a/docs/src_main_js_daemon_MoneroDaemonRpc.js.html +++ /dev/null @@ -1,1839 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/MoneroDaemonRpc.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/MoneroDaemonRpc.js

- - - - - - -
-
-
const assert = require("assert");
-const BigInteger = require("../common/biginteger").BigInteger;
-const GenUtils = require("../common/GenUtils");
-const LibraryUtils = require("../common/LibraryUtils");
-const MoneroAltChain = require("./model/MoneroAltChain");
-const MoneroBan = require("./model/MoneroBan");
-const MoneroBlock = require("./model/MoneroBlock");
-const MoneroBlockHeader = require("./model/MoneroBlockHeader");
-const MoneroBlockTemplate = require("./model/MoneroBlockTemplate");
-const MoneroDaemon = require("./MoneroDaemon");
-const MoneroDaemonConnection = require("./model/MoneroDaemonConnection");
-const MoneroDaemonInfo = require("./model/MoneroDaemonInfo");
-const MoneroDaemonPeer = require("./model/MoneroDaemonPeer");
-const MoneroDaemonSyncInfo = require("./model/MoneroDaemonSyncInfo");
-const MoneroError = require("../common/MoneroError");
-const MoneroHardForkInfo = require("./model/MoneroHardForkInfo");
-const MoneroKeyImage = require("./model/MoneroKeyImage");
-const MoneroMinerTxSum = require("./model/MoneroMinerTxSum");
-const MoneroMiningStatus = require("./model/MoneroMiningStatus");
-const MoneroNetworkType = require("./model/MoneroNetworkType");
-const MoneroOutput = require("./model/MoneroOutput");
-const MoneroOutputHistogramEntry = require("./model/MoneroOutputHistogramEntry");
-const MoneroRpcConnection = require("../common/MoneroRpcConnection");
-const MoneroSubmitTxResult = require("./model/MoneroSubmitTxResult");
-const MoneroTx = require("./model/MoneroTx");
-const MoneroUtils = require("../common/MoneroUtils");
-const MoneroVersion = require("./model/MoneroVersion");
-
-/**
- * Copyright (c) woodser
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/**
- * Implements a MoneroDaemon as a client of monero-daemon-rpc.
- * 
- * @implements {MoneroDaemon}
- */
-class MoneroDaemonRpc extends MoneroDaemon {
-  
-  /**
-   * <p>Construct a daemon RPC client.<p>
-   * 
-   * <p>Examples:<p>
-   * 
-   * <code>
-   * let daemon = new MoneroDaemonRpc("http://localhost:38081", "superuser", "abctesting123");<br><br>
-   * 
-   * let daemon = new MoneroDaemonRpc({<br>
-   * &nbsp;&nbsp; uri: "http://localhost:38081",<br>
-   * &nbsp;&nbsp; username: "superuser",<br>
-   * &nbsp;&nbsp; password: "abctesting123"<br>
-   * });
-   * </code>
-   * 
-   * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - uri of monero-daemon-rpc or JS config object or MoneroRpcConnection
-   * @param {string} uriOrConfigOrConnection.uri - uri of monero-daemon-rpc
-   * @param {string} uriOrConfigOrConnection.username - username to authenticate with monero-daemon-rpc (optional)
-   * @param {string} uriOrConfigOrConnection.password - password to authenticate with monero-daemon-rpc (optional)
-   * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true)
-   * @param {number} uriOrConfigOrConnection.pollInterval - poll interval to query for updates in ms (default 5000)
-   * @param {boolean} uriOrConfigOrConnection.proxyToWorker - run the daemon client in a web worker if true (default true if browser, false otherwise)
-   * @param {string} username - username to authenticate with monero-daemon-rpc (optional)
-   * @param {string} password - password to authenticate with monero-daemon-rpc (optional)
-   * @param {boolean} rejectUnauthorized - rejects self-signed certificates if true (default true)
-   * @param {number} pollInterval - poll interval to query for updates in ms (default 5000)
-   * @param {boolean} proxyToWorker - runs the daemon client in a web worker if true (default true if browser, false otherwise)
-   */
-  constructor(uriOrConfigOrConnection, username, password, rejectUnauthorized, pollInterval, proxyToWorker) {
-    super();
-    
-    // normalize configuration
-    this.config = MoneroDaemonRpc._normalizeConfig(uriOrConfigOrConnection, username, password, rejectUnauthorized, pollInterval, proxyToWorker);
-    
-    // initialize proxy if proxying to worker
-    if (this.config.proxyToWorker) this._proxyPromise = MoneroDaemonRpcProxy.connect(this.config);
-    else {
-      this.rpc = new MoneroRpcConnection(this.config);
-      this.listeners = [];      // block listeners
-      this.cachedHeaders = {};  // cached headers for fetching blocks in bound chunks
-    }
-  }
-  
-  /**
-   * Get the daemon's RPC connection.
-   * 
-   * @return {MoneroRpcConnection} the daemon's rpc connection
-   */
-  async getRpcConnection() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getRpcConnection();
-    return this.rpc;
-  }
-  
-  async isConnected() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).isConnected();
-    try {
-      await this.getHeight();
-      return true;
-    } catch (e) {
-      return false;
-    }
-  }
-  
-  async getVersion() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getVersion();
-    let resp = await this.rpc.sendJsonRequest("get_version");
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    return new MoneroVersion(resp.result.version, resp.result.release);
-  }
-  
-  async isTrusted() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).isTrusted();
-    let resp = await this.rpc.sendPathRequest("get_height");
-    MoneroDaemonRpc._checkResponseStatus(resp);
-    return !resp.untrusted;
-  }
-  
-  async getHeight() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getHeight();
-    let resp = await this.rpc.sendJsonRequest("get_block_count");
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    return resp.result.count;
-  }
-  
-  async getBlockHash(height) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockHash(height);
-    return (await this.rpc.sendJsonRequest("on_get_block_hash", [height])).result;  // TODO monero-wallet-rpc: no status returned
-  }
-  
-  async getBlockTemplate(walletAddress, reserveSize) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockTemplate(walletAddress, reserveSize);
-    assert(walletAddress && typeof walletAddress === "string", "Must specify wallet address to be mined to");
-    let resp = await this.rpc.sendJsonRequest("get_block_template", {wallet_address: walletAddress, reserve_size: reserveSize});
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    return MoneroDaemonRpc._convertRpcBlockTemplate(resp.result);
-  }
-  
-  async getLastBlockHeader() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getLastBlockHeader();
-    let resp = await this.rpc.sendJsonRequest("get_last_block_header");
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    return MoneroDaemonRpc._convertRpcBlockHeader(resp.result.block_header);
-  }
-  
-  async getBlockHeaderByHash(blockHash) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockHeaderByHash(blockHash);
-    let resp = await this.rpc.sendJsonRequest("get_block_header_by_hash", {hash: blockHash});
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    return MoneroDaemonRpc._convertRpcBlockHeader(resp.result.block_header);
-  }
-  
-  async getBlockHeaderByHeight(height) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockHeaderByHeight(height);
-    let resp = await this.rpc.sendJsonRequest("get_block_header_by_height", {height: height});
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    return MoneroDaemonRpc._convertRpcBlockHeader(resp.result.block_header);
-  }
-  
-  async getBlockHeadersByRange(startHeight, endHeight) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockHeadersByRange(startHeight, endHeight);
-    
-    // fetch block headers
-    let resp = await this.rpc.sendJsonRequest("get_block_headers_range", {
-      start_height: startHeight,
-      end_height: endHeight
-    });
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    
-    // build headers
-    let headers = [];
-    for (let rpcHeader of resp.result.headers) {
-      headers.push(MoneroDaemonRpc._convertRpcBlockHeader(rpcHeader));
-    }
-    return headers;
-  }
-  
-  async getBlockByHash(blockHash) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockByHash(blockHash);
-    let resp = await this.rpc.sendJsonRequest("get_block", {hash: blockHash});
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    return MoneroDaemonRpc._convertRpcBlock(resp.result);
-  }
-  
-  async getBlockByHeight(height) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockByHeight(height);
-    let resp = await this.rpc.sendJsonRequest("get_block", {height: height});
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    return MoneroDaemonRpc._convertRpcBlock(resp.result);
-  }
-  
-  async getBlocksByHeight(heights) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlocksByHeight(heights);
-    
-    // fetch blocks in binary
-    let respBin = await this.rpc.sendBinaryRequest("get_blocks_by_height.bin", {heights: heights});
-    
-    // load wasm module
-    await LibraryUtils.loadKeysModule();
-    
-    // convert binary blocks to json
-    let rpcBlocks = MoneroUtils.binaryBlocksToJson(respBin);
-    MoneroDaemonRpc._checkResponseStatus(rpcBlocks);
-    //console.log(JSON.stringify(rpcBlocks));
-    
-    // build blocks with transactions
-    assert.equal(rpcBlocks.txs.length, rpcBlocks.blocks.length);    
-    let blocks = [];
-    for (let blockIdx = 0; blockIdx < rpcBlocks.blocks.length; blockIdx++) {
-      
-      // build block
-      let block = MoneroDaemonRpc._convertRpcBlock(rpcBlocks.blocks[blockIdx]);
-      block.setHeight(heights[blockIdx]);
-      blocks.push(block);
-      
-      // build transactions
-      let txs = [];
-      for (let txIdx = 0; txIdx < rpcBlocks.txs[blockIdx].length; txIdx++) {
-        let tx = new MoneroTx();
-        txs.push(tx);
-        tx.setHash(rpcBlocks.blocks[blockIdx].tx_hashes[txIdx]);
-        tx.setIsConfirmed(true);
-        tx.setInTxPool(false);
-        tx.setIsMinerTx(false);
-        tx.setRelay(true);
-        tx.setIsRelayed(true);
-        tx.setIsFailed(false);
-        tx.setIsDoubleSpend(false);
-        MoneroDaemonRpc._convertRpcTx(rpcBlocks.txs[blockIdx][txIdx], tx);
-      }
-      
-      // merge into one block
-      block.setTxs([]);
-      for (let tx of txs) {
-        if (tx.getBlock()) block.merge(tx.getBlock());
-        else block.getTxs().push(tx.setBlock(block));
-      }
-    }
-    
-    return blocks;
-  }
-  
-  async getBlocksByRange(startHeight, endHeight) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlocksByRange(startHeight, endHeight);
-    if (startHeight === undefined) startHeight = 0;
-    if (endHeight === undefined) endHeight = await this.getHeight() - 1;
-    let heights = [];
-    for (let height = startHeight; height <= endHeight; height++) heights.push(height);
-    return await this.getBlocksByHeight(heights);
-  }
-  
-  async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize);
-    if (startHeight === undefined) startHeight = 0;
-    if (endHeight === undefined) endHeight = await this.getHeight() - 1;
-    let lastHeight = startHeight - 1;
-    let blocks = [];
-    while (lastHeight < endHeight) {
-      for (let block of await this._getMaxBlocks(lastHeight + 1, endHeight, maxChunkSize)) {
-        blocks.push(block);
-      }
-      lastHeight = blocks[blocks.length - 1].getHeight();
-    }
-    return blocks;
-  }
-  
-  async getTxs(txHashes, prune) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getTxs(txHashes, prune);
-        
-    // validate input
-    assert(Array.isArray(txHashes) && txHashes.length > 0, "Must provide an array of transaction hashes");
-    assert(prune === undefined || typeof prune === "boolean", "Prune must be a boolean or undefined");
-        
-    // fetch transactions
-    let resp = await this.rpc.sendPathRequest("get_transactions", {
-      txs_hashes: txHashes,
-      decode_as_json: true,
-      prune: prune
-    });
-    try {
-      MoneroDaemonRpc._checkResponseStatus(resp);
-    } catch (e) {
-      if (e.message.indexOf("Failed to parse hex representation of transaction hash") >= 0) throw new MoneroError("Invalid transaction hash");
-      throw e;
-    }
-        
-    // build transaction models
-    let txs = [];
-    if (resp.txs) {
-      for (let txIdx = 0; txIdx < resp.txs.length; txIdx++) {
-        let tx = new MoneroTx();
-        tx.setIsMinerTx(false);
-        txs.push(MoneroDaemonRpc._convertRpcTx(resp.txs[txIdx], tx));
-      }
-    }
-    
-    // fetch unconfirmed txs from pool and merge additional fields  // TODO monero-daemon-rpc: merge rpc calls so this isn't necessary?
-    let poolTxs = await this.getTxPool();
-    for (let tx of txs) {
-      for (let poolTx of poolTxs) {
-        if (tx.getHash() === poolTx.getHash()) tx.merge(poolTx);
-      }
-    }
-    
-    return txs;
-  }
-  
-  async getTxHexes(txHashes, prune) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getTxHexes(txHashes, prune);
-    let hexes = [];
-    for (let tx of await this.getTxs(txHashes, prune)) hexes.push(prune ? tx.getPrunedHex() : tx.getFullHex());
-    return hexes;
-  }
-  
-  async getMinerTxSum(height, numBlocks) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getMinerTxSum(height, numBlocks);
-    if (height === undefined) height = 0;
-    else assert(height >= 0, "Height must be an integer >= 0");
-    if (numBlocks === undefined) numBlocks = await this.getHeight();
-    else assert(numBlocks >= 0, "Count must be an integer >= 0");
-    let resp = await this.rpc.sendJsonRequest("get_coinbase_tx_sum", {height: height, count: numBlocks});
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    let txSum = new MoneroMinerTxSum();
-    txSum.setEmissionSum(new BigInteger(resp.result.emission_amount));
-    txSum.setFeeSum(new BigInteger(resp.result.fee_amount));
-    return txSum;
-  }
-  
-  async getFeeEstimate(graceBlocks) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getFeeEstimate(graceBlocks);
-    let resp = await this.rpc.sendJsonRequest("get_fee_estimate", {grace_blocks: graceBlocks});
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    return new BigInteger(resp.result.fee);
-  }
-  
-  async submitTxHex(txHex, doNotRelay) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).submitTxHex(txHex, doNotRelay);
-    let resp = await this.rpc.sendPathRequest("send_raw_transaction", {tx_as_hex: txHex, do_not_relay: doNotRelay});
-    let result = MoneroDaemonRpc._convertRpcSubmitTxResult(resp);
-    
-    // set isGood based on status
-    try {
-      MoneroDaemonRpc._checkResponseStatus(resp); 
-      result.setIsGood(true);
-    } catch(e) {
-      result.setIsGood(false);
-    }
-    return result;
-  }
-  
-  async relayTxsByHash(txHashes) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).relayTxsByHash(txHashes);
-    let resp = await this.rpc.sendJsonRequest("relay_tx", {txids: txHashes});
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-  }
-  
-  async getTxPool() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getTxPool();
-    
-    // send rpc request
-    let resp = await this.rpc.sendPathRequest("get_transaction_pool");
-    MoneroDaemonRpc._checkResponseStatus(resp);
-    
-    // build txs
-    let txs = [];
-    if (resp.transactions) {
-      for (let rpcTx of resp.transactions) {
-        let tx = new MoneroTx();
-        txs.push(tx);
-        tx.setIsConfirmed(false);
-        tx.setIsMinerTx(false);
-        tx.setInTxPool(true);
-        tx.setNumConfirmations(0);
-        MoneroDaemonRpc._convertRpcTx(rpcTx, tx);
-      }
-    }
-    
-    return txs;
-  }
-  
-  async getTxPoolHashes() {
-    throw new MoneroError("Not implemented");
-  }
-  
-  async getTxPoolBacklog() {
-    throw new MoneroError("Not implemented");
-  }
-
-  async getTxPoolStats() {
-    throw new MoneroError("Response contains field 'histo' which is binary'");
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getTxPoolStats();
-    let resp = await this.rpc.sendPathRequest("get_transaction_pool_stats");
-    MoneroDaemonRpc._checkResponseStatus(resp);
-    let stats = MoneroDaemonRpc._convertRpcTxPoolStats(resp.pool_stats);
-    
-    // uninitialize some stats if not applicable
-    if (stats.getHisto98pc() === 0) stats.setHisto98pc(undefined);
-    if (stats.getNumTxs() === 0) {
-      stats.setBytesMin(undefined);
-      stats.setBytesMed(undefined);
-      stats.setBytesMax(undefined);
-      stats.setHisto98pc(undefined);
-      stats.setOldestTimestamp(undefined);
-    }
-    
-    return stats;
-  }
-  
-  async flushTxPool(hashes) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).flushTxPool(hashes);
-    if (hashes) hashes = GenUtils.listify(hashes);
-    let resp = await this.rpc.sendJsonRequest("flush_txpool", {txids: hashes});
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-  }
-  
-  async getKeyImageSpentStatuses(keyImages) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getKeyImageSpentStatuses(keyImages);
-    if (keyImages === undefined || keyImages.length === 0) throw new MoneroError("Must provide key images to check the status of");
-    let resp = await this.rpc.sendPathRequest("is_key_image_spent", {key_images: keyImages});
-    MoneroDaemonRpc._checkResponseStatus(resp);
-    return resp.spent_status;
-  }
-  
-  async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff);
-    
-    // send rpc request
-    let resp = await this.rpc.sendJsonRequest("get_output_histogram", {
-      amounts: amounts,
-      min_count: minCount,
-      max_count: maxCount,
-      unlocked: isUnlocked,
-      recent_cutoff: recentCutoff
-    });
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    
-    // build histogram entries from response
-    let entries = [];
-    if (!resp.result.histogram) return entries;
-    for (let rpcEntry of resp.result.histogram) {
-      entries.push(MoneroDaemonRpc._convertRpcOutputHistogramEntry(rpcEntry));
-    }
-    return entries;
-  }
-  
-  async getOutputDistribution(amounts, cumulative, startHeight, endHeight) {
-    throw new MoneroError("Not implemented (response 'distribution' field is binary)");
-    
-//    let amountStrs = [];
-//    for (let amount of amounts) amountStrs.push(amount.toJSValue());
-//    console.log(amountStrs);
-//    console.log(cumulative);
-//    console.log(startHeight);
-//    console.log(endHeight);
-//    
-//    // send rpc request
-//    console.log("*********** SENDING REQUEST *************");
-//    if (startHeight === undefined) startHeight = 0;
-//    let resp = await this.rpc.sendJsonRequest("get_output_distribution", {
-//      amounts: amountStrs,
-//      cumulative: cumulative,
-//      from_height: startHeight,
-//      to_height: endHeight
-//    });
-//    
-//    console.log("RESPONSE");
-//    console.log(resp);
-//    
-//    // build distribution entries from response
-//    let entries = [];
-//    if (!resp.result.distributions) return entries; 
-//    for (let rpcEntry of resp.result.distributions) {
-//      let entry = MoneroDaemonRpc._convertRpcOutputDistributionEntry(rpcEntry);
-//      entries.push(entry);
-//    }
-//    return entries;
-  }
-  
-  async getInfo() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getInfo();
-    let resp = await this.rpc.sendJsonRequest("get_info");
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    return MoneroDaemonRpc._convertRpcInfo(resp.result);
-  }
-  
-  async getSyncInfo() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getSyncInfo();
-    let resp = await this.rpc.sendJsonRequest("sync_info");
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    return MoneroDaemonRpc._convertRpcSyncInfo(resp.result);
-  }
-  
-  async getHardForkInfo() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getHardForkInfo();
-    let resp = await this.rpc.sendJsonRequest("hard_fork_info");
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    return MoneroDaemonRpc._convertRpcHardForkInfo(resp.result);
-  }
-  
-  async getAltChains() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getAltChains();
-    
-//    // mocked response for test
-//    let resp = {
-//        status: "OK",
-//        chains: [
-//          {
-//            block_hash: "697cf03c89a9b118f7bdf11b1b3a6a028d7b3617d2d0ed91322c5709acf75625",
-//            difficulty: 14114729638300280,
-//            height: 1562062,
-//            length: 2
-//          }
-//        ]
-//    }
-    
-    let resp = await this.rpc.sendJsonRequest("get_alternate_chains");
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    let chains = [];
-    if (!resp.result.chains) return chains;
-    for (let rpcChain of resp.result.chains) chains.push(MoneroDaemonRpc._convertRpcAltChain(rpcChain));
-    return chains;
-  }
-  
-  async getAltBlockHashes() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getAltBlockHashes();
-    
-//    // mocked response for test
-//    let resp = {
-//        status: "OK",
-//        untrusted: false,
-//        blks_hashes: ["9c2277c5470234be8b32382cdf8094a103aba4fcd5e875a6fc159dc2ec00e011","637c0e0f0558e284493f38a5fcca3615db59458d90d3a5eff0a18ff59b83f46f","6f3adc174a2e8082819ebb965c96a095e3e8b63929ad9be2d705ad9c086a6b1c","697cf03c89a9b118f7bdf11b1b3a6a028d7b3617d2d0ed91322c5709acf75625"]
-//    }
-    
-    let resp = await this.rpc.sendPathRequest("get_alt_blocks_hashes");
-    MoneroDaemonRpc._checkResponseStatus(resp);
-    if (!resp.blks_hashes) return [];
-    return resp.blks_hashes;
-  }
-  
-  async getDownloadLimit() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getDownloadLimit();
-    return (await this._getBandwidthLimits())[0];
-  }
-  
-  async setDownloadLimit(limit) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setDownloadLimit(limit);
-    if (limit == -1) return await this.resetDownloadLimit();
-    if (!(GenUtils.isInt(limit) && limit > 0)) throw new MoneroError("Download limit must be an integer greater than 0");
-    return (await this._setBandwidthLimits(limit, 0))[0];
-  }
-  
-  async resetDownloadLimit() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).resetDownloadLimit();
-    return (await this._setBandwidthLimits(-1, 0))[0];
-  }
-
-  async getUploadLimit() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getUploadLimit();
-    return (await this._getBandwidthLimits())[1];
-  }
-  
-  async setUploadLimit(limit) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setUploadLimit(limit);
-    if (limit == -1) return await this.resetUploadLimit();
-    if (!(GenUtils.isInt(limit) && limit > 0)) throw new MoneroError("Upload limit must be an integer greater than 0");
-    return (await this._setBandwidthLimits(0, limit))[1];
-  }
-  
-  async resetUploadLimit() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).resetUploadLimit();
-    return (await this._setBandwidthLimits(0, -1))[1];
-  }
-  
-  async getConnections() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getConnections();
-    let resp = await this.rpc.sendJsonRequest("get_connections");
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    let connections = [];
-    if (!resp.result.connections) return connections;
-    for (let rpcConnection of resp.result.connections) {
-      connections.push(MoneroDaemonRpc._convertRpcConnection(rpcConnection));
-    }
-    return connections;
-  }
-  
-  async getKnownPeers() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getKnownPeers();
-    
-    // tx config
-    let resp = await this.rpc.sendPathRequest("get_peer_list");
-    MoneroDaemonRpc._checkResponseStatus(resp);
-    
-    // build peers
-    let peers = [];
-    if (resp.gray_list) {
-      for (let rpcPeer of resp.gray_list) {
-        let peer = MoneroDaemonRpc._convertRpcPeer(rpcPeer);
-        peer.setIsOnline(false); // gray list means offline last checked
-        peers.push(peer);
-      }
-    }
-    if (resp.white_list) {
-      for (let rpcPeer of resp.white_list) {
-        let peer = MoneroDaemonRpc._convertRpcPeer(rpcPeer);
-        peer.setIsOnline(true); // white list means online last checked
-        peers.push(peer);
-      }
-    }
-    return peers;
-  }
-  
-  async setOutgoingPeerLimit(limit) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setOutgoingPeerLimit(limit);
-    if (!(GenUtils.isInt(limit) && limit >= 0)) throw new MoneroError("Outgoing peer limit must be >= 0");
-    let resp = await this.rpc.sendPathRequest("out_peers", {out_peers: limit});
-    MoneroDaemonRpc._checkResponseStatus(resp);
-  }
-  
-  async setIncomingPeerLimit(limit) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setIncomingPeerLimit(limit);
-    if (!(GenUtils.isInt(limit) && limit >= 0)) throw new MoneroError("Incoming peer limit must be >= 0");
-    let resp = await this.rpc.sendPathRequest("in_peers", {in_peers: limit});
-    MoneroDaemonRpc._checkResponseStatus(resp);
-  }
-  
-  async getPeerBans() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getPeerBans();
-    let resp = await this.rpc.sendJsonRequest("get_bans");
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-    let bans = [];
-    for (let rpcBan of resp.result.bans) {
-      let ban = new MoneroBan();
-      ban.setHost(rpcBan.host);
-      ban.setIp(rpcBan.ip);
-      ban.setSeconds(rpcBan.seconds);
-      bans.push(ban);
-    }
-    return bans;
-  }
-  
-  async setPeerBans(bans) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setPeerBans(bans);
-    let rpcBans = [];
-    for (let ban of bans) rpcBans.push(MoneroDaemonRpc._convertToRpcBan(ban));
-    let resp = await this.rpc.sendJsonRequest("set_bans", {bans: rpcBans});
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-  }
-  
-  async startMining(address, numThreads, isBackground, ignoreBattery) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).startMining(address, numThreads, isBackground, ignoreBattery);
-    assert(address, "Must provide address to mine to");
-    assert(GenUtils.isInt(numThreads) && numThreads > 0, "Number of threads must be an integer greater than 0");
-    assert(isBackground === undefined || typeof isBackground === "boolean");
-    assert(ignoreBattery === undefined || typeof ignoreBattery === "boolean");
-    let resp = await this.rpc.sendPathRequest("start_mining", {
-      miner_address: address,
-      threads_count: numThreads,
-      do_background_mining: isBackground,
-      ignore_battery: ignoreBattery,
-    });
-    MoneroDaemonRpc._checkResponseStatus(resp);
-  }
-  
-  async stopMining() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).stopMining();
-    let resp = await this.rpc.sendPathRequest("stop_mining");
-    MoneroDaemonRpc._checkResponseStatus(resp);
-  }
-  
-  async getMiningStatus() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getMiningStatus();
-    let resp = await this.rpc.sendPathRequest("mining_status");
-    MoneroDaemonRpc._checkResponseStatus(resp);
-    return MoneroDaemonRpc._convertRpcMiningStatus(resp);
-  }
-  
-  async submitBlocks(blockBlobs) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).submitBlocks(blockBlobs);
-    assert(Array.isArray(blockBlobs) && blockBlobs.length > 0, "Must provide an array of mined block blobs to submit");
-    let resp = await this.rpc.sendJsonRequest("submit_block", blockBlobs);
-    MoneroDaemonRpc._checkResponseStatus(resp.result);
-  }
-  
-  async checkForUpdate() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).checkForUpdate();
-    let resp = await this.rpc.sendPathRequest("update", {command: "check"});
-    MoneroDaemonRpc._checkResponseStatus(resp);
-    return MoneroDaemonRpc._convertRpcUpdateCheckResult(resp);
-  }
-  
-  async downloadUpdate(path) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).downloadUpdate();
-    let resp = await this.rpc.sendPathRequest("update", {command: "download", path: path});
-    MoneroDaemonRpc._checkResponseStatus(resp);
-    return MoneroDaemonRpc._convertRpcUpdateDownloadResult(resp);
-  }
-  
-  async stop() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).stop();
-    let resp = await this.rpc.sendPathRequest("stop_daemon");
-    MoneroDaemonRpc._checkResponseStatus(resp);
-  }
-  
-  async getNextBlockHeader() {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getNextBlockHeader();
-    let that = this;
-    return new Promise(async function(resolve, reject) {
-      let listener = async function(header) {
-        resolve(header);
-        await that.removeBlockListener(listener);
-      }
-      await that.addBlockListener(listener);
-    });
-  }
-  
-  async addBlockListener(listener) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).addBlockListener(listener);
-
-    // register listener
-    this.listeners.push(listener);
-    
-    // start polling for new blocks
-    if (!this.isPollingHeaders) this._startPollingHeaders(this.config.pollInterval);
-  }
-  
-  async removeBlockListener(listener) {
-    if (this.config.proxyToWorker) return (await this._getDaemonProxy()).removeBlockListener(listener);
-    let found = GenUtils.remove(this.listeners, listener);
-    assert(found, "Listener is not registered");
-    if (this.listeners.length === 0) this._stopPollingHeaders();
-  }
-  
-  // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS --------------
-  
-  async getTx() { return super.getTx(...arguments); }
-  async getTxHex() { return super.getTxHex(...arguments); }
-  async getKeyImageSpentStatus() { return super.getKeyImageSpentStatus(...arguments); }
-  async setPeerBan() { return super.setPeerBan(...arguments); }
-  async submitBlock() { return super.submitBlock(...arguments); }
-  
-  // ------------------------------- PRIVATE ----------------------------------
-  
-  async _getDaemonProxy() {
-    return await this._proxyPromise;
-  }
-  
-  async _startPollingHeaders(interval) {
-    assert(!this.isPollingHeaders, "Daemon is already polling block headers");
-    
-    // get header to detect changes while polling
-    let lastHeader = await this.getLastBlockHeader(); // TODO: this should be passed in
-    
-    // poll until stopped
-    let that = this;
-    this.isPollingHeaders = true;
-    while (this.isPollingHeaders) {
-      await new Promise(function(resolve) { setTimeout(resolve, interval); });
-      let header;
-      try {
-        header = await this.getLastBlockHeader();
-      } catch (e) {
-        console.error("Failed to poll last block header, retrying...");
-        continue;
-      }
-      if (header.getHash() !== lastHeader.getHash()) {
-        lastHeader = header;
-        for (let listener of this.listeners) {
-          listener(header); // notify listener
-        }
-      }
-    }
-  }
-  
-  _stopPollingHeaders() {
-    this.isPollingHeaders = false; // causes polling loop to exit
-  }
-  
-  async _getBandwidthLimits() {
-    let resp = await this.rpc.sendPathRequest("get_limit");
-    MoneroDaemonRpc._checkResponseStatus(resp);
-    return [resp.limit_down, resp.limit_up];
-  }
-  
-  async _setBandwidthLimits(downLimit, upLimit) {
-    if (downLimit === undefined) downLimit = 0;
-    if (upLimit === undefined) upLimit = 0;
-    let resp = await this.rpc.sendPathRequest("set_limit", {limit_down: downLimit, limit_up: upLimit});
-    MoneroDaemonRpc._checkResponseStatus(resp);
-    return [resp.limit_down, resp.limit_up];
-  }
-  
-  /**
-   * Get a contiguous chunk of blocks starting from a given height up to a maximum
-   * height or amount of block data fetched from the blockchain, whichever comes first.
-   * 
-   * @param {number} startHeight - start height to retrieve blocks (default 0)
-   * @param {number} maxHeight - maximum end height to retrieve blocks (default blockchain height)
-   * @param {number} maxReqSize - maximum amount of block data to fetch from the blockchain in bytes (default 3,000,000 bytes)
-   * @return {MoneroBlock[]} are the resulting chunk of blocks
-   */
-  async _getMaxBlocks(startHeight, maxHeight, maxReqSize) {
-    if (startHeight === undefined) startHeight = 0;
-    if (maxHeight === undefined) maxHeight = await this.getHeight() - 1;
-    if (maxReqSize === undefined) maxReqSize = MoneroDaemonRpc.MAX_REQ_SIZE;
-    
-    // determine end height to fetch
-    let reqSize = 0;
-    let endHeight = startHeight - 1;
-    while (reqSize < maxReqSize && endHeight < maxHeight) {
-      
-      // get header of next block
-      let header = await this._getBlockHeaderByHeightCached(endHeight + 1, maxHeight);
-      
-      // block cannot be bigger than max request size
-      assert(header.getSize() <= maxReqSize, "Block exceeds maximum request size: " + header.getSize());
-      
-      // done iterating if fetching block would exceed max request size
-      if (reqSize + header.getSize() > maxReqSize) break;
-      
-      // otherwise block is included
-      reqSize += header.getSize();
-      endHeight++;
-    }
-    return endHeight >= startHeight ? await this.getBlocksByRange(startHeight, endHeight) : [];
-  }
-  
-  /**
-   * Retrieves a header by height from the cache or fetches and caches a header
-   * range if not already in the cache.
-   * 
-   * @param {number} height - height of the header to retrieve from the cache
-   * @param {number} maxHeight - maximum height of headers to cache
-   */
-  async _getBlockHeaderByHeightCached(height, maxHeight) {
-    
-    // get header from cache
-    let cachedHeader = this.cachedHeaders[height];
-    if (cachedHeader) return cachedHeader;
-    
-    // fetch and cache headers if not in cache
-    let endHeight = Math.min(maxHeight, height + MoneroDaemonRpc.NUM_HEADERS_PER_REQ - 1);  // TODO: could specify end height to cache to optimize small requests (would like to have time profiling in place though)
-    let headers = await this.getBlockHeadersByRange(height, endHeight);
-    for (let header of headers) {
-      this.cachedHeaders[header.getHeight()] = header;
-    }
-    
-    // return the cached header
-    return this.cachedHeaders[height];
-  }
-  
-  // --------------------------------- STATIC ---------------------------------
-  
-  static _normalizeConfig(uriOrConfigOrConnection, username, password, rejectUnauthorized, pollInterval, proxyToWorker) {
-    let config;
-    if (typeof uriOrConfigOrConnection === "string") config = {uri: uriOrConfigOrConnection, username: username, password: password, proxyToWorker: proxyToWorker, rejectUnauthorized: rejectUnauthorized, pollInterval: pollInterval};
-    else {
-      if (typeof uriOrConfigOrConnection !== "object") throw new MoneroError("Invalid configuration to create daemon rpc client; must be string, object, or MoneroRpcConnection");
-      if (username || password || rejectUnauthorized || pollInterval || proxyToWorker) throw new MoneroError("Can provide config object or params or new MoneroDaemonRpc(...) but not both");
-      if (uriOrConfigOrConnection instanceof MoneroRpcConnection) config = Object.assign({}, uriOrConfigOrConnection.getConfig());
-      else config = Object.assign({}, uriOrConfigOrConnection);
-    }
-    if (config.pollInterval === undefined) config.pollInterval = 5000; // TODO: move to config
-    if (config.server) {
-      config = Object.assign(config, new MoneroRpcConnection(config.server).getConfig());
-      delete config.server;
-    }
-    if (config.proxyToWorker === undefined) config.proxyToWorker = GenUtils.isBrowser();
-    return config;
-  }
-  
-  static _checkResponseStatus(resp) {
-    if (resp.status !== "OK") throw new MoneroError(resp.status);
-  }
-  
-  static _convertRpcBlockHeader(rpcHeader) {
-    if (!rpcHeader) return undefined;
-    let header = new MoneroBlockHeader();
-    for (let key of Object.keys(rpcHeader)) {
-      let val = rpcHeader[key];
-      if (key === "block_size") GenUtils.safeSet(header, header.getSize, header.setSize, val);
-      else if (key === "depth") GenUtils.safeSet(header, header.getDepth, header.setDepth, val);
-      else if (key === "difficulty") { }  // handled by wide_difficulty
-      else if (key === "cumulative_difficulty") { } // handled by wide_cumulative_difficulty
-      else if (key === "difficulty_top64") { }  // handled by wide_difficulty
-      else if (key === "cumulative_difficulty_top64") { } // handled by wide_cumulative_difficulty
-      else if (key === "wide_difficulty") header.setDifficulty(GenUtils.reconcile(header.getDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val)));
-      else if (key === "wide_cumulative_difficulty") header.setCumulativeDifficulty(GenUtils.reconcile(header.getCumulativeDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val)));
-      else if (key === "hash") GenUtils.safeSet(header, header.getHash, header.setHash, val);
-      else if (key === "height") GenUtils.safeSet(header, header.getHeight, header.setHeight, val);
-      else if (key === "major_version") GenUtils.safeSet(header, header.getMajorVersion, header.setMajorVersion, val);
-      else if (key === "minor_version") GenUtils.safeSet(header, header.getMinorVersion, header.setMinorVersion, val);
-      else if (key === "nonce") GenUtils.safeSet(header, header.getNonce, header.setNonce, val);
-      else if (key === "num_txes") GenUtils.safeSet(header, header.getNumTxs, header.setNumTxs, val);
-      else if (key === "orphan_status") GenUtils.safeSet(header, header.getOrphanStatus, header.setOrphanStatus, val);
-      else if (key === "prev_hash" || key === "prev_id") GenUtils.safeSet(header, header.getPrevHash, header.setPrevHash, val);
-      else if (key === "reward") GenUtils.safeSet(header, header.getReward, header.setReward, BigInteger.parse(val));
-      else if (key === "timestamp") GenUtils.safeSet(header, header.getTimestamp, header.setTimestamp, val);
-      else if (key === "block_weight") GenUtils.safeSet(header, header.getWeight, header.setWeight, val);
-      else if (key === "long_term_weight") GenUtils.safeSet(header, header.getLongTermWeight, header.setLongTermWeight, val);
-      else if (key === "pow_hash") GenUtils.safeSet(header, header.getPowHash, header.setPowHash, val === "" ? undefined : val);
-      else if (key === "tx_hashes") {}  // used in block model, not header model
-      else if (key === "miner_tx") {}   // used in block model, not header model
-      else if (key === "miner_tx_hash") header.setMinerTxHash(val);
-      else console.log("WARNING: ignoring unexpected block header field: '" + key + "': " + val);
-    }
-    return header;
-  }
-  
-  static _convertRpcBlock(rpcBlock) {
-    
-    // build block
-    let block = new MoneroBlock(MoneroDaemonRpc._convertRpcBlockHeader(rpcBlock.block_header ? rpcBlock.block_header : rpcBlock));
-    block.setHex(rpcBlock.blob);
-    block.setTxHashes(rpcBlock.tx_hashes === undefined ? [] : rpcBlock.tx_hashes);
-    
-    // build miner tx
-    let rpcMinerTx = rpcBlock.json ? JSON.parse(rpcBlock.json).miner_tx : rpcBlock.miner_tx;  // may need to be parsed from json
-    let minerTx = new MoneroTx();
-    block.setMinerTx(minerTx);
-    minerTx.setIsConfirmed(true);
-    minerTx.setIsMinerTx(true);
-    MoneroDaemonRpc._convertRpcTx(rpcMinerTx, minerTx);
-    
-    return block;
-  }
-  
-  /**
-   * Transfers RPC tx fields to a given MoneroTx without overwriting previous values.
-   * 
-   * TODO: switch from safe set
-   * 
-   * @param rpcTx - RPC map containing transaction fields
-   * @param tx  - MoneroTx to populate with values (optional)
-   * @returns tx - same tx that was passed in or a new one if none given
-   */
-  static _convertRpcTx(rpcTx, tx) {
-    if (rpcTx === undefined) return undefined;
-    if (tx === undefined) tx = new MoneroTx();
-    
-//    console.log("******** BUILDING TX ***********");
-//    console.log(rpcTx);
-//    console.log(tx.toString());
-    
-    // initialize from rpc map
-    let header;
-    for (let key of Object.keys(rpcTx)) {
-      let val = rpcTx[key];
-      if (key === "tx_hash" || key === "id_hash") GenUtils.safeSet(tx, tx.getHash, tx.setHash, val);
-      else if (key === "block_timestamp") {
-        if (!header) header = new MoneroBlockHeader();
-        GenUtils.safeSet(header, header.getTimestamp, header.setTimestamp, val);
-      }
-      else if (key === "block_height") {
-        if (!header) header = new MoneroBlockHeader();
-        GenUtils.safeSet(header, header.getHeight, header.setHeight, val);
-      }
-      else if (key === "last_relayed_time") GenUtils.safeSet(tx, tx.getLastRelayedTimestamp, tx.setLastRelayedTimestamp, val);
-      else if (key === "receive_time" || key === "received_timestamp") GenUtils.safeSet(tx, tx.getReceivedTimestamp, tx.setReceivedTimestamp, val);
-      else if (key === "in_pool") {
-        GenUtils.safeSet(tx, tx.isConfirmed, tx.setIsConfirmed, !val);
-        GenUtils.safeSet(tx, tx.inTxPool, tx.setInTxPool, val);
-      }
-      else if (key === "double_spend_seen") GenUtils.safeSet(tx, tx.isDoubleSpendSeen, tx.setIsDoubleSpend, val);
-      else if (key === "version") GenUtils.safeSet(tx, tx.getVersion, tx.setVersion, val);
-      else if (key === "extra") GenUtils.safeSet(tx, tx.getExtra, tx.setExtra, val);
-      else if (key === "vin") {
-        if (val.length !== 1 || !val[0].gen) {  // ignore miner input TODO: why?
-          tx.setInputs(val.map(rpcVin => MoneroDaemonRpc._convertRpcOutput(rpcVin, tx)));
-        }
-      }
-      else if (key === "vout") tx.setOutputs(val.map(rpcOutput => MoneroDaemonRpc._convertRpcOutput(rpcOutput, tx)));
-      else if (key === "rct_signatures") GenUtils.safeSet(tx, tx.getRctSignatures, tx.setRctSignatures, val);
-      else if (key === "rctsig_prunable") GenUtils.safeSet(tx, tx.getRctSigPrunable, tx.setRctSigPrunable, val);
-      else if (key === "unlock_time") GenUtils.safeSet(tx, tx.getUnlockHeight, tx.setUnlockHeight, val);
-      else if (key === "as_json" || key === "tx_json") { }  // handled last so tx is as initialized as possible
-      else if (key === "as_hex" || key === "tx_blob") GenUtils.safeSet(tx, tx.getFullHex, tx.setFullHex, val ? val : undefined);
-      else if (key === "blob_size") GenUtils.safeSet(tx, tx.getSize, tx.setSize, val);
-      else if (key === "weight") GenUtils.safeSet(tx, tx.getWeight, tx.setWeight, val);
-      else if (key === "fee") GenUtils.safeSet(tx, tx.getFee, tx.setFee, BigInteger.parse(val));
-      else if (key === "relayed") GenUtils.safeSet(tx, tx.isRelayed, tx.setIsRelayed, val);
-      else if (key === "output_indices") GenUtils.safeSet(tx, tx.getOutputIndices, tx.setOutputIndices, val);
-      else if (key === "do_not_relay") GenUtils.safeSet(tx, tx.getRelay, tx.setRelay, !val);
-      else if (key === "kept_by_block") GenUtils.safeSet(tx, tx.isKeptByBlock, tx.setIsKeptByBlock, val);
-      else if (key === "signatures") GenUtils.safeSet(tx, tx.getSignatures, tx.setSignatures, val);
-      else if (key === "last_failed_height") {
-        if (val === 0) GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, false);
-        else {
-          GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, true);
-          GenUtils.safeSet(tx, tx.getLastFailedHeight, tx.setLastFailedHeight, val);
-        }
-      }
-      else if (key === "last_failed_id_hash") {
-        if (val === MoneroDaemonRpc.DEFAULT_ID) GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, false);
-        else {
-          GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, true);
-          GenUtils.safeSet(tx, tx.getLastFailedHash, tx.setLastFailedHash, val);
-        }
-      }
-      else if (key === "max_used_block_height") GenUtils.safeSet(tx, tx.getMaxUsedBlockHeight, tx.setMaxUsedBlockHeight, val);
-      else if (key === "max_used_block_id_hash") GenUtils.safeSet(tx, tx.getMaxUsedBlockHash, tx.setMaxUsedBlockHash, val);
-      else if (key === "prunable_hash") GenUtils.safeSet(tx, tx.getPrunableHash, tx.setPrunableHash, val ? val : undefined);
-      else if (key === "prunable_as_hex") GenUtils.safeSet(tx, tx.getPrunableHex, tx.setPrunableHex, val ? val : undefined);
-      else if (key === "pruned_as_hex") GenUtils.safeSet(tx, tx.getPrunedHex, tx.setPrunedHex, val ? val : undefined);
-      else console.log("WARNING: ignoring unexpected field in rpc tx: " + key + ": " + val);
-    }
-    
-    // link block and tx
-    if (header) tx.setBlock(new MoneroBlock(header).setTxs([tx]));
-    
-    // TODO monero-daemon-rpc: unconfirmed txs misreport block height and timestamp
-    if (tx.getBlock() && tx.getBlock().getHeight() !== undefined && tx.getBlock().getHeight() === tx.getBlock().getTimestamp()) {
-      tx.setBlock(undefined);
-      tx.setIsConfirmed(false);
-    }
-    
-    // initialize remaining known fields
-    if (tx.isConfirmed()) {
-      GenUtils.safeSet(tx, tx.isRelayed, tx.setIsRelayed, true);
-      GenUtils.safeSet(tx, tx.getRelay, tx.setRelay, true);
-      GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, false);
-    } else {
-      tx.setNumConfirmations(0);
-    }
-    if (tx.isFailed() === undefined) tx.setIsFailed(false);
-    if (tx.getOutputIndices() && tx.getOutputs())  {
-      assert.equal(tx.getOutputs().length, tx.getOutputIndices().length);
-      for (let i = 0; i < tx.getOutputs().length; i++) {
-        tx.getOutputs()[i].setIndex(tx.getOutputIndices()[i]);  // transfer output indices to outputs
-      }
-    }
-    if (rpcTx.as_json) MoneroDaemonRpc._convertRpcTx(JSON.parse(rpcTx.as_json), tx);
-    if (rpcTx.tx_json) MoneroDaemonRpc._convertRpcTx(JSON.parse(rpcTx.tx_json), tx);
-    if (!tx.isRelayed()) tx.setLastRelayedTimestamp(undefined);  // TODO monero-daemon-rpc: returns last_relayed_timestamp despite relayed: false, self inconsistent
-    
-    // return built transaction
-    return tx;
-  }
-  
-  static _convertRpcOutput(rpcOutput, tx) {
-    let output = new MoneroOutput();
-    output.setTx(tx);
-    for (let key of Object.keys(rpcOutput)) {
-      let val = rpcOutput[key];
-      if (key === "gen") throw new MoneroError("Output with 'gen' from daemon rpc is miner tx which we ignore (i.e. each miner input is undefined)");
-      else if (key === "key") {
-        GenUtils.safeSet(output, output.getAmount, output.setAmount, new BigInteger(val.amount));
-        GenUtils.safeSet(output, output.getKeyImage, output.setKeyImage, new MoneroKeyImage(val.k_image));
-        GenUtils.safeSet(output, output.getRingOutputIndices, output.setRingOutputIndices, val.key_offsets);
-      }
-      else if (key === "amount") GenUtils.safeSet(output, output.getAmount, output.setAmount, BigInteger.parse(val));
-      else if (key === "target") GenUtils.safeSet(output, output.getStealthPublicKey, output.setStealthPublicKey, val.key);
-      else console.log("WARNING: ignoring unexpected field output: " + key + ": " + val);
-    }
-    return output;
-  }
-  
-  static _convertRpcBlockTemplate(rpcTemplate) {
-    let template = new MoneroBlockTemplate();
-    for (let key of Object.keys(rpcTemplate)) {
-      let val = rpcTemplate[key];
-      if (key === "blockhashing_blob") template.setBlockTemplateBlob(val);
-      else if (key === "blocktemplate_blob") template.setBlockHashingBlob(val);
-      else if (key === "difficulty") template.setDifficulty(BigInteger.parse(val));
-      else if (key === "expected_reward") template.setExpectedReward(val);
-      else if (key === "difficulty") { }  // handled by wide_difficulty
-      else if (key === "difficulty_top64") { }  // handled by wide_difficulty
-      else if (key === "wide_difficulty") template.setDifficulty(GenUtils.reconcile(template.getDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val)));
-      else if (key === "height") template.setHeight(val);
-      else if (key === "prev_hash") template.setPrevHash(val);
-      else if (key === "reserved_offset") template.setReservedOffset(val);
-      else if (key === "status") {}  // handled elsewhere
-      else if (key === "untrusted") {}  // handled elsewhere
-      else if (key === "seed_height") template.setSeedHeight(val);
-      else if (key === "seed_hash") template.setSeedHash(val);
-      else if (key === "next_seed_hash") template.setNextSeedHash(val);
-      else console.log("WARNING: ignoring unexpected field in block template: " + key + ": " + val);
-    }
-    if ("" === template.getNextSeedHash()) template.setNextSeedHash(undefined);
-    return template;
-  }
-  
-  static _convertRpcInfo(rpcInfo) {
-    if (!rpcInfo) return undefined;
-    let info = new MoneroDaemonInfo();
-    for (let key of Object.keys(rpcInfo)) {
-      let val = rpcInfo[key];
-      if (key === "version") info.setVersion(val);
-      else if (key === "alt_blocks_count") info.setNumAltBlocks(val);
-      else if (key === "block_size_limit") info.setBlockSizeLimit(val);
-      else if (key === "block_size_median") info.setBlockSizeMedian(val);
-      else if (key === "block_weight_limit") info.setBlockWeightLimit(val);
-      else if (key === "block_weight_median") info.setBlockWeightMedian(val);
-      else if (key === "bootstrap_daemon_address") { if (val) info.setBootstrapDaemonAddress(val); }
-      else if (key === "difficulty") { }  // handled by wide_difficulty
-      else if (key === "cumulative_difficulty") { } // handled by wide_cumulative_difficulty
-      else if (key === "difficulty_top64") { }  // handled by wide_difficulty
-      else if (key === "cumulative_difficulty_top64") { } // handled by wide_cumulative_difficulty
-      else if (key === "wide_difficulty") info.setDifficulty(GenUtils.reconcile(info.getDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val)));
-      else if (key === "wide_cumulative_difficulty") info.setCumulativeDifficulty(GenUtils.reconcile(info.getCumulativeDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val)));
-      else if (key === "free_space") info.setFreeSpace(BigInteger.parse(val));
-      else if (key === "database_size") info.setDatabaseSize(val);
-      else if (key === "grey_peerlist_size") info.setNumOfflinePeers(val);
-      else if (key === "height") info.setHeight(val);
-      else if (key === "height_without_bootstrap") info.setHeightWithoutBootstrap(val);
-      else if (key === "incoming_connections_count") info.setNumIncomingConnections(val);
-      else if (key === "offline") info.setIsOffline(val);
-      else if (key === "outgoing_connections_count") info.setNumOutgoingConnections(val);
-      else if (key === "rpc_connections_count") info.setNumRpcConnections(val);
-      else if (key === "start_time") info.setStartTimestamp(val);
-      else if (key === "status") {}  // handled elsewhere
-      else if (key === "target") info.setTarget(val);
-      else if (key === "target_height") info.setTargetHeight(val);
-      else if (key === "top_block_hash") info.setTopBlockHash(val);
-      else if (key === "tx_count") info.setNumTxs(val);
-      else if (key === "tx_pool_size") info.setNumTxsPool(val);
-      else if (key === "untrusted") {} // handled elsewhere
-      else if (key === "was_bootstrap_ever_used") info.setWasBootstrapEverUsed(val);
-      else if (key === "white_peerlist_size") info.setNumOnlinePeers(val);
-      else if (key === "update_available") info.setUpdateAvailable(val);
-      else if (key === "nettype") GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroDaemon.parseNetworkType(val));
-      else if (key === "mainnet") { if (val) GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.MAINNET); }
-      else if (key === "testnet") { if (val) GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.TESTNET); }
-      else if (key === "stagenet") { if (val) GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.STAGENET); }
-      else if (key === "credits") info.setCredits(BigInteger.parse(val));
-      else if (key === "top_block_hash" || key === "top_hash") info.setTopBlockHash(GenUtils.reconcile(info.getTopBlockHash(), "" === val ? undefined : val))
-      else console.log("WARNING: Ignoring unexpected info field: " + key + ": " + val);
-    }
-    return info;
-  }
-  
-  /**
-   * Initializes sync info from RPC sync info.
-   * 
-   * @param rpcSyncInfo - rpc map to initialize the sync info from
-   * @return {MoneroDaemonSyncInfo} is sync info initialized from the map
-   */
-  static _convertRpcSyncInfo(rpcSyncInfo) {
-    let syncInfo = new MoneroDaemonSyncInfo();
-    for (let key of Object.keys(rpcSyncInfo)) {
-      let val = rpcSyncInfo[key];
-      if (key === "height") syncInfo.setHeight(val);
-      else if (key === "peers") {
-        syncInfo.setConnections([]);
-        let rpcConnections = val;
-        for (let rpcConnection of rpcConnections) {
-          syncInfo.getConnections().push(MoneroDaemonRpc._convertRpcConnection(rpcConnection.info));
-        }
-      }
-      else if (key === "spans") {
-        syncInfo.setSpans([]);
-        let rpcSpans = val;
-        for (let rpcSpan of rpcSpans) {
-          syncInfo.getSpans().push(MoneroDaemonRpc._convertRpcConnectionSpan(rpcSpan));
-        }
-      } else if (key === "status") {}   // handled elsewhere
-      else if (key === "target_height") syncInfo.setTargetHeight(BigInteger.parse(val));
-      else if (key === "next_needed_pruning_seed") syncInfo.setNextNeededPruningSeed(val);
-      else if (key === "overview") {  // this returns [] without pruning
-        let overview;
-        try {
-          overview = JSON.parse(val);
-          if (overview !== undefined && overview.length > 0) console.error("Ignoring non-empty 'overview' field (not implemented): " + overview); // TODO
-        } catch (e) {
-          console.error("Failed to parse 'overview' field: " + overview + ": " + e.message);
-        }
-      }
-      else if (key === "credits") syncInfo.setCredits(BigInteger.parse(val));
-      else if (key === "top_hash") syncInfo.setTopBlockHash("" === val ? undefined : val);
-      else if (key === "untrusted") {}  // handled elsewhere
-      else console.log("WARNING: ignoring unexpected field in sync info: " + key + ": " + val);
-    }
-    return syncInfo;
-  }
-  
-  static _convertRpcHardForkInfo(rpcHardForkInfo) {
-    let info = new MoneroHardForkInfo();
-    for (let key of Object.keys(rpcHardForkInfo)) {
-      let val = rpcHardForkInfo[key];
-      if (key === "earliest_height") info.setEarliestHeight(val);
-      else if (key === "enabled") info.setIsEnabled(val);
-      else if (key === "state") info.setState(val);
-      else if (key === "status") {}     // handled elsewhere
-      else if (key === "untrusted") {}  // handled elsewhere
-      else if (key === "threshold") info.setThreshold(val);
-      else if (key === "version") info.setVersion(val);
-      else if (key === "votes") info.setNumVotes(val);
-      else if (key === "voting") info.setVoting(val);
-      else if (key === "window") info.setWindow(val);
-      else if (key === "credits") info.setCredits(BigInteger.parse(val));
-      else if (key === "top_hash") info.setTopBlockHash("" === val ? undefined : val);
-      else console.log("WARNING: ignoring unexpected field in hard fork info: " + key + ": " + val);
-    }
-    return info;
-  }
-  
-  static _convertRpcConnectionSpan(rpcConnectionSpan) {
-    let span = new MoneroDaemonConnectionSpan();
-    for (let key of Object.keys(rpcConnectionSpan)) {
-      let val = rpcConnectionSpan[key];
-      if (key === "connection_id") span.setConnectionId(val);
-      else if (key === "nblocks") span.setNumBlocks(val);
-      else if (key === "rate") span.setRate(val);
-      else if (key === "remote_address") { if (val !== "") span.setRemoteAddress(val); }
-      else if (key === "size") span.setSize(val);
-      else if (key === "speed") span.setSpeed(val);
-      else if (key === "start_block_height") span.setStartHeight(val);
-      else console.log("WARNING: ignoring unexpected field in daemon connection span: " + key + ": " + val);
-    }
-    return span;
-  }
-  
-  static _convertRpcOutputHistogramEntry(rpcEntry) {
-    let entry = new MoneroOutputHistogramEntry();
-    for (let key of Object.keys(rpcEntry)) {
-      let val = rpcEntry[key];
-      if (key === "amount") entry.setAmount(BigInteger.parse(val));
-      else if (key === "total_instances") entry.setNumInstances(val);
-      else if (key === "unlocked_instances") entry.setNumUnlockedInstances(val);
-      else if (key === "recent_instances") entry.setNumRecentInstances(val);
-      else console.log("WARNING: ignoring unexpected field in output histogram: " + key + ": " + val);
-    }
-    return entry;
-  }
-  
-  static _convertRpcSubmitTxResult(rpcResult) {
-    assert(rpcResult);
-    let result = new MoneroSubmitTxResult();
-    for (let key of Object.keys(rpcResult)) {
-      let val = rpcResult[key];
-      if (key === "double_spend") result.setIsDoubleSpend(val);
-      else if (key === "fee_too_low") result.setIsFeeTooLow(val);
-      else if (key === "invalid_input") result.setHasInvalidInput(val);
-      else if (key === "invalid_output") result.setHasInvalidOutput(val);
-      else if (key === "too_few_outputs") result.setHasTooFewOutputs(val);
-      else if (key === "low_mixin") result.setIsMixinTooLow(val);
-      else if (key === "not_relayed") result.setIsRelayed(!val);
-      else if (key === "overspend") result.setIsOverspend(val);
-      else if (key === "reason") result.setReason(val === "" ? undefined : val);
-      else if (key === "too_big") result.setIsTooBig(val);
-      else if (key === "sanity_check_failed") result.setSanityCheckFailed(val);
-      else if (key === "credits") result.setCredits(BigInteger.parse(val))
-      else if (key === "status" || key === "untrusted") {}  // handled elsewhere
-      else if (key === "top_hash") result.setTopBlockHash("" === val ? undefined : val);
-      else console.log("WARNING: ignoring unexpected field in submit tx hex result: " + key + ": " + val);
-    }
-    return result;
-  }
-  
-  static _convertRpcTxPoolStats(rpcStats) {
-    assert(rpcStats);
-    let stats = new MoneroTxPoolStats();
-    for (let key of Object.keys(rpcStats)) {
-      let val = rpcStats[key];
-      if (key === "bytes_max") stats.setBytesMax(val);
-      else if (key === "bytes_med") stats.setBytesMed(val);
-      else if (key === "bytes_min") stats.setBytesMin(val);
-      else if (key === "bytes_total") stats.setBytesTotal(val);
-      else if (key === "histo_98pc") stats.setHisto98pc(val);
-      else if (key === "num_10m") stats.setNum10m(val);
-      else if (key === "num_double_spends") stats.setNumDoubleSpends(val);
-      else if (key === "num_failing") stats.setNumFailing(val);
-      else if (key === "num_not_relayed") stats.setNumNotRelayed(val);
-      else if (key === "oldest") stats.setOldestTimestamp(val);
-      else if (key === "txs_total") stats.setNumTxs(val);
-      else if (key === "fee_total") stats.setFeeTotal(BigInteger.parse(val));
-      else if (key === "histo") throw new MoneroError("Not implemented");
-      else console.log("WARNING: ignoring unexpected field in tx pool stats: " + key + ": " + val);
-    }
-    return stats;
-  }
-  
-  static _convertRpcAltChain(rpcChain) {
-    assert(rpcChain);
-    let chain = new MoneroAltChain();
-    for (let key of Object.keys(rpcChain)) {
-      let val = rpcChain[key];
-      if (key === "block_hash") {}  // using block_hashes instead
-      else if (key === "difficulty") { } // handled by wide_difficulty
-      else if (key === "difficulty_top64") { }  // handled by wide_difficulty
-      else if (key === "wide_difficulty") chain.setDifficulty(GenUtils.reconcile(chain.getDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val)));
-      else if (key === "height") chain.setHeight(val);
-      else if (key === "length") chain.setLength(val);
-      else if (key === "block_hashes") chain.setBlockHashes(val);
-      else if (key === "main_chain_parent_block") chain.setMainChainParentBlockHash(val);
-      else console.log("WARNING: ignoring unexpected field in alternative chain: " + key + ": " + val);
-    }
-    return chain;
-  }
-  
-  static _convertRpcPeer(rpcPeer) {
-    assert(rpcPeer);
-    let peer = new MoneroDaemonPeer();
-    for (let key of Object.keys(rpcPeer)) {
-      let val = rpcPeer[key];
-      if (key === "host") peer.setHost(val);
-      else if (key === "id") peer.setId("" + val);  // TODO monero-wallet-rpc: peer id is BigInteger but string in `get_connections`
-      else if (key === "ip") {} // host used instead which is consistently a string
-      else if (key === "last_seen") peer.setLastSeenTimestamp(val);
-      else if (key === "port") peer.setPort(val);
-      else if (key === "rpc_port") peer.setRpcPort(val);
-      else if (key === "pruning_seed") peer.setPruningSeed(val);
-      else if (key === "rpc_credits_per_hash") peer.setRpcCreditsPerHash(BigInteger.parse(val));
-      else console.log("WARNING: ignoring unexpected field in rpc peer: " + key + ": " + val);
-    }
-    return peer;
-  }
-  
-  static _convertRpcConnection(rpcConnection) {
-    let connection = new MoneroDaemonConnection();
-    let peer = new MoneroDaemonPeer();
-    connection.setPeer(peer);
-    peer.setIsOnline(true);
-    for (let key of Object.keys(rpcConnection)) {
-      let val = rpcConnection[key];
-      if (key === "address") peer.setAddress(val);
-      else if (key === "avg_download") connection.setAvgDownload(val);
-      else if (key === "avg_upload") connection.setAvgUpload(val);
-      else if (key === "connection_id") connection.setId(val);
-      else if (key === "current_download") connection.setCurrentDownload(val);
-      else if (key === "current_upload") connection.setCurrentUpload(val);
-      else if (key === "height") connection.setHeight(val);
-      else if (key === "host") peer.setHost(val);
-      else if (key === "ip") {} // host used instead which is consistently a string
-      else if (key === "incoming") connection.setIsIncoming(val);
-      else if (key === "live_time") connection.setLiveTime(val);
-      else if (key === "local_ip") connection.setIsLocalIp(val);
-      else if (key === "localhost") connection.setIsLocalHost(val);
-      else if (key === "peer_id") peer.setId(val);
-      else if (key === "port") peer.setPort(parseInt(val));
-      else if (key === "rpc_port") peer.setRpcPort(val);
-      else if (key === "recv_count") connection.setNumReceives(val);
-      else if (key === "recv_idle_time") connection.setReceiveIdleTime(val);
-      else if (key === "send_count") connection.setNumSends(val);
-      else if (key === "send_idle_time") connection.setSendIdleTime(val);
-      else if (key === "state") connection.setState(val);
-      else if (key === "support_flags") connection.setNumSupportFlags(val);
-      else if (key === "pruning_seed") peer.setPruningSeed(val);
-      else if (key === "rpc_credits_per_hash") peer.setRpcCreditsPerHash(BigInteger.parse(val));
-      else if (key === "address_type") connection.setType(val);
-      else console.log("WARNING: ignoring unexpected field in connection: " + key + ": " + val);
-    }
-    return connection;
-  }
-  
-  static _convertToRpcBan(ban) {
-    let rpcBan = {};
-    rpcBan.host = ban.getHost();
-    rpcBan.ip = ban.getIp();
-    rpcBan.ban = ban.isBanned();
-    rpcBan.seconds = ban.getSeconds();
-    return rpcBan;
-  }
-  
-  static _convertRpcMiningStatus(rpcStatus) {
-    let status = new MoneroMiningStatus();
-    status.setIsActive(rpcStatus.active);
-    status.setSpeed(rpcStatus.speed);
-    status.setNumThreads(rpcStatus.threads_count);
-    if (rpcStatus.active) {
-      status.setAddress(rpcStatus.address);
-      status.setIsBackground(rpcStatus.is_background_mining_enabled);
-    }
-    return status;
-  }
-  
-  static _convertRpcUpdateCheckResult(rpcResult) {
-    assert(rpcResult);
-    let result = new MoneroDaemonUpdateCheckResult();
-    for (let key of Object.keys(rpcResult)) {
-      let val = rpcResult[key];
-      if (key === "auto_uri") result.setAutoUri(val);
-      else if (key === "hash") result.setHash(val);
-      else if (key === "path") {} // handled elsewhere
-      else if (key === "status") {} // handled elsewhere
-      else if (key === "update") result.setIsUpdateAvailable(val);
-      else if (key === "user_uri") result.setUserUri(val);
-      else if (key === "version") result.setVersion(val);
-      else if (key === "untrusted") {} // handled elsewhere
-      else console.log("WARNING: ignoring unexpected field in rpc check update result: " + key + ": " + val);
-    }
-    if (result.getAutoUri() === "") result.setAutoUri(undefined);
-    if (result.getUserUri() === "") result.setUserUri(undefined);
-    if (result.getVersion() === "") result.setVersion(undefined);
-    if (result.getHash() === "") result.setHash(undefined);
-    return result;
-  }
-  
-  static _convertRpcUpdateDownloadResult(rpcResult) {
-    let result = new MoneroDaemonUpdateDownloadResult(MoneroDaemonRpc._convertRpcUpdateCheckResult(rpcResult));
-    result.setDownloadPath(rpcResult["path"]);
-    if (result.getDownloadPath() === "") result.setDownloadPath(undefined);
-    return result;
-  }
-
-  /**
-   * Converts a '0x' prefixed hexidecimal string to a BigInteger.
-   * 
-   * @param hex is the '0x' prefixed hexidecimal string to convert
-   * @return BigInteger is the hexicedimal converted to decimal
-   */
-  static _prefixedHexToBI(hex) {
-    assert(hex.substring(0, 2) === "0x");
-    return BigInteger.parse(hex, 16);
-  }
-}
-
-// static variables
-MoneroDaemonRpc.DEFAULT_ID = "0000000000000000000000000000000000000000000000000000000000000000";  // uninitialized tx or block hash from daemon rpc
-MoneroDaemonRpc.MAX_REQ_SIZE = "3000000";  // max request size when fetching blocks from daemon
-MoneroDaemonRpc.NUM_HEADERS_PER_REQ = "750";  // number of headers to fetch and cache per request
-
-/**
- * Implements a MoneroDaemon by proxying requests to a web worker.
- * 
- * @private
- */
-class MoneroDaemonRpcProxy extends MoneroDaemon {
-  
-  // --------------------------- STATIC UTILITIES -----------------------------
-  
-  static async connect(config) {
-    let daemonId = GenUtils.getUUID();
-    config = Object.assign({}, config, {proxyToWorker: false});
-    await LibraryUtils.invokeWorker(daemonId, "connectDaemonRpc", [config]);
-    return new MoneroDaemonRpcProxy(daemonId, LibraryUtils.getWorker());
-  }
-  
-  // ---------------------------- INSTANCE METHODS ----------------------------
-  
-  constructor(daemonId, worker) {
-    super();
-    this.daemonId = daemonId;
-    this.worker = worker;
-    this.wrappedListeners = [];
-  }
-  
-  async getRpcConnection() {
-    let config = await this._invokeWorker("daemonGetRpcConnection");
-    return new MoneroRpcConnection(config);
-  }
-  
-  async isConnected() {
-    return this._invokeWorker("daemonIsConnected");
-  }
-  
-  async getVersion() {
-    let versionJson = await this._invokeWorker("daemonGetVersion");
-    return new MoneroVersion(versionJson.number, versionJson.isRelease);
-  }
-  
-  async isTrusted() {
-    return this._invokeWorker("daemonIsTrusted");
-  }
-  
-  async getHeight() {
-    return this._invokeWorker("daemonGetHeight");
-  }
-  
-  async getBlockHash(height) {
-    return this._invokeWorker("daemonGetBlockHash", Array.from(arguments));
-  }
-  
-  async getBlockTemplate(walletAddress, reserveSize) {
-    return new MoneroBlockTemplate(await this._invokeWorker("daemonGetBlockTemplate", Array.from(arguments)));
-  }
-  
-  async getLastBlockHeader() {
-    return new MoneroBlockHeader(await this._invokeWorker("daemonGetLastBlockHeader"));
-  }
-  
-  async getBlockHeaderByHash(blockHash) {
-    return new MoneroBlockHeader(await this._invokeWorker("daemonGetBlockHeaderByHash", Array.from(arguments)));
-  }
-  
-  async getBlockHeaderByHeight(height) {
-    return new MoneroBlockHeader(await this._invokeWorker("daemonGetBlockHeaderByHeight", Array.from(arguments)));
-  }
-  
-  async getBlockHeadersByRange(startHeight, endHeight) {
-    let blockHeadersJson = await this._invokeWorker("daemonGetBlockHeadersByRange", Array.from(arguments));
-    let headers = [];
-    for (let blockHeaderJson of blockHeadersJson) headers.push(new MoneroBlockHeader(blockHeaderJson));
-    return headers;
-  }
-  
-  async getBlockByHash(blockHash) {
-    return new MoneroBlock(await this._invokeWorker("daemonGetBlockByHash", Array.from(arguments)));
-  }
-  
-  async getBlocksByHash(blockHashes, startHeight, prune) {
-    let blocksJson = await this._invokeWorker("daemonGetBlocksByHash", Array.from(arguments));
-    let blocks = [];
-    for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson));
-    return blocks;
-  }
-  
-  async getBlockByHeight(height) {
-    return new MoneroBlock(await this._invokeWorker("daemonGetBlockByHeight", Array.from(arguments)));
-  }
-  
-  async getBlocksByHeight(heights) {
-    let blocksJson = await this._invokeWorker("daemonGetBlocksByHeight", Array.from(arguments));
-    let blocks = [];
-    for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson));
-    return blocks;
-  }
-  
-  async getBlocksByRange(startHeight, endHeight) {
-    let blocksJson = await this._invokeWorker("daemonGetBlocksByRange", Array.from(arguments));
-    let blocks = [];
-    for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson));
-    return blocks;
-  }
-  
-  async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) {
-    let blocksJson = await this._invokeWorker("daemonGetBlocksByRangeChunked", Array.from(arguments));
-    let blocks = [];
-    for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson));
-    return blocks;
-  }
-  
-  async getBlockHashes(blockHashes, startHeight) {
-    return this._invokeWorker("daemonGetBlockHashes", Array.from(arguments));
-  }
-  
-  async getTxs(txHashes, prune = false) {
-    
-    // deserialize txs from blocks
-    let blocks = [];
-    for (let blockJson of await this._invokeWorker("daemonGetTxs", Array.from(arguments))) {
-      blocks.push(new MoneroBlock(blockJson));
-    }
-    
-    // collect txs
-    let txs = [];
-    for (let block of blocks) {
-      for (let tx of block.getTxs()) {
-        if (!tx.isConfirmed()) tx.setBlock(undefined);
-        txs.push(tx);
-      }
-    }
-    return txs;
-  }
-  
-  async getTxHexes(txHashes, prune = false) {
-    return this._invokeWorker("daemonGetTxHexes", Array.from(arguments));
-  }
-  
-  async getMinerTxSum(height, numBlocks) {
-    return new MoneroMinerTxSum(await this._invokeWorker("daemonGetMinerTxSum", Array.from(arguments)));
-  }
-  
-  async getFeeEstimate(graceBlocks) {
-    return BigInteger.parse(await this._invokeWorker("daemonGetFeeEstimate", Array.from(arguments)));
-  }
-  
-  async submitTxHex(txHex, doNotRelay) {
-    return new MoneroSubmitTxResult(await this._invokeWorker("daemonSubmitTxHex", Array.from(arguments)));
-  }
-  
-  async relayTxsByHash(txHashes) {
-    return this._invokeWorker("daemonRelayTxsByHash", Array.from(arguments));
-  }
-  
-  async getTxPool() {
-    let blockJson = await this._invokeWorker("daemonGetTxPool");
-    let txs = new MoneroBlock(blockJson).getTxs();
-    for (let tx of txs) tx.setBlock(undefined);
-    return txs ? txs : [];
-  }
-  
-  async getTxPoolHashes() {
-    return this._invokeWorker("daemonGetTxPoolHashes", Array.from(arguments));
-  }
-  
-  async getTxPoolBacklog() {
-    throw new MoneroError("Not implemented");
-  }
-  
-  async getTxPoolStats() {
-    return new MoneroTxPoolStats(await this._invokeWorker("daemonGetTxPoolStats"));
-  }
-  
-  async flushTxPool(hashes) {
-    return this._invokeWorker("daemonFlushTxPool", Array.from(arguments));
-  }
-  
-  async getKeyImageSpentStatuses(keyImages) {
-    return this._invokeWorker("daemonGetKeyImageSpentStatuses", Array.from(arguments));
-  }
-  
-  async getOutputs(outputs) {
-    throw new MoneroError("Not implemented");
-  }
-  
-  async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) {
-    let entries = [];
-    for (let entryJson of await this._invokeWorker("daemonGetOutputHistogram", [amounts, minCount, maxCount, isUnlocked, recentCutoff])) {
-      entries.push(new MoneroOutputHistogramEntry(entryJson));
-    }
-    return entries;
-  }
-  
-  async getOutputDistribution(amounts, cumulative, startHeight, endHeight) {
-    throw new MoneroError("Not implemented");
-  }
-  
-  async getInfo() {
-    return new MoneroDaemonInfo(await this._invokeWorker("daemonGetInfo"));
-  }
-  
-  async getSyncInfo() {
-    return new MoneroDaemonSyncInfo(await this._invokeWorker("daemonGetSyncInfo"));
-  }
-  
-  async getHardForkInfo() {
-    return new MoneroHardForkInfo(await this._invokeWorker("daemonGetHardForkInfo"));
-  }
-  
-  async getAltChains() {
-    let altChains = [];
-    for (let altChainJson of await this._invokeWorker("daemonGetAltChains")) altChains.push(new MoneroAltChain(altChainJson));
-    return altChains;
-  }
-  
-  async getAltBlockHashes() {
-    return this._invokeWorker("daemonGetAltBlockHashes");
-  }
-  
-  async getDownloadLimit() {
-    return this._invokeWorker("daemonGetDownloadLimit");
-  }
-  
-  async setDownloadLimit(limit) {
-    return this._invokeWorker("daemonSetDownloadLimit", Array.from(arguments));
-  }
-  
-  async resetDownloadLimit() {
-    return this._invokeWorker("daemonResetDownloadLimit");
-  }
-  
-  async getUploadLimit() {
-    return this._invokeWorker("daemonGetUploadLimit");
-  }
-  
-  async setUploadLimit(limit) {
-    return this._invokeWorker("daemonSetUploadLimit", Array.from(arguments));
-  }
-  
-  async resetUploadLimit() {
-    return this._invokeWorker("daemonResetUploadLimit");
-  }
-  
-  async getKnownPeers() {
-    let peers = [];
-    for (let peerJson of await this._invokeWorker("daemonGetKnownPeers")) peers.push(new MoneroDaemonPeer(peerJson));
-    return peers;
-  }
-  
-  async getConnections() {
-    let connections = [];
-    for (let connectionJson of await this._invokeWorker("daemonGetConnections")) connections.push(new MoneroDaemonConnection(connectionJson));
-    return connections;
-  }
-  
-  async setOutgoingPeerLimit(limit) {
-    return this._invokeWorker("daemonSetIncomingPeerLimit", Array.from(arguments));
-  }
-  
-  async setIncomingPeerLimit(limit) {
-    return this._invokeWorker("daemonSetIncomingPeerLimit", Array.from(arguments));
-  }
-  
-  async getPeerBans() {
-    let bans = [];
-    for (let banJson of await this._invokeWorker("daemonGetPeerBans")) bans.push(new MoneroBan(banJson));
-    return bans;
-  }
-
-  async setPeerBans(bans) {
-    let bansJson = [];
-    for (let ban of bans) bansJson.push(ban.toJson());
-    return this._invokeWorker("daemonSetPeerBans", [bansJson]);
-  }
-  
-  async startMining(address, numThreads, isBackground, ignoreBattery) {
-    return this._invokeWorker("daemonStartMining", Array.from(arguments));
-  }
-  
-  async stopMining() {
-    return this._invokeWorker("daemonStopMining")
-  }
-  
-  async getMiningStatus() {
-    return new MoneroMiningStatus(await this._invokeWorker("daemonGetMiningStatus"));
-  }
-  
-  async submitBlocks(blockBlobs) {
-    throw new MoneroError("Not implemented");
-  }
-  
-  async checkForUpdate() {
-    throw new MoneroError("Not implemented");
-  }
-  
-  async downloadUpdate(path) {
-    throw new MoneroError("Not implemented");
-  }
-  
-  async stop() {
-    while (this.wrappedListeners.length) await this.removeBlockListener(this.wrappedListeners[0].getListener());
-    return this._invokeWorker("daemonStop");
-  }
-  
-  async getNextBlockHeader() {
-    return new MoneroBlockHeader(await this._invokeWorker("daemonGetNextBlockHeader"));
-  }
-  
-  async addBlockListener(listener) {
-    let wrappedListener = new DaemonWorkerListener(listener);
-    let listenerId = wrappedListener.getId();
-    LibraryUtils.WORKER_OBJECTS[this.daemonId].callbacks["onNewBlockHeader_" + listenerId] = [wrappedListener.onNewBlockHeader, wrappedListener];
-    this.wrappedListeners.push(wrappedListener);
-    return this._invokeWorker("daemonAddBlockListener", [listenerId]);
-  }
-  
-  async removeBlockListener(listener) {
-    for (let i = 0; i < this.wrappedListeners.length; i++) {
-      if (this.wrappedListeners[i].getListener() === listener) {
-        let listenerId = this.wrappedListeners[i].getId();
-        await this._invokeWorker("daemonRemoveBlockListener", [listenerId]);
-        delete LibraryUtils.WORKER_OBJECTS[this.daemonId].callbacks["onNewBlockHeader_" + listenerId];
-        this.wrappedListeners.splice(i, 1);
-        return;
-      }
-    }
-    throw new MoneroError("Listener is not registered with wallet");
-  }
-  
-  // --------------------------- PRIVATE HELPERS ------------------------------
-  
-  // TODO: duplicated with MoneroWalletWasmProxy
-  async _invokeWorker(fnName, args) {
-    return LibraryUtils.invokeWorker(this.daemonId, fnName, args);
-  }
-}
-
-/**
- * Internal listener to bridge notifications to external listeners.
- * 
- * @private
- */
-class DaemonWorkerListener {
-  
-  constructor(listener) {
-    this._id = GenUtils.getUUID();
-    this._listener = listener;
-  }
-  
-  getId() {
-    return this._id;
-  }
-  
-  getListener() {
-    return this._listener;
-  }
-  
-  onNewBlockHeader(headerJson) {
-    this._listener(new MoneroBlockHeader(headerJson));
-  }
-}
-
-module.exports = MoneroDaemonRpc;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_ConnectionType.js.html b/docs/src_main_js_daemon_model_ConnectionType.js.html deleted file mode 100644 index 5b09aaddd..000000000 --- a/docs/src_main_js_daemon_model_ConnectionType.js.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/ConnectionType.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/ConnectionType.js

- - - - - - -
-
-
const assert = require("assert");
-
-/**
- * Enumerates connection types.
- * 
- * Based on enums.h in monero-project.
- * 
- * @hideconstructor
- */
-class ConnectionType {
-    
-  /**
-   * Asserts that the given connection type is valid.
-   */
-  static validate(type) {
-    assert(type === 0 || type === 1 || type === 2 || type === 3, "Connection type is invalid: " + type);
-  }
-  
-  /**
-   * Indicates if the given connection type is valid or not.
-   */
-  static isValid(type) {
-    return type === 0 || type === 1 || type === 2 || 3;
-  }
-}
-
-/**
- * Invalid connection type (value=0).
- */
-ConnectionType.INVALID = 0;
-
-/**
- * IPV4 connection type (value=1).
- */
-ConnectionType.IPV4 = 1;
-
-/**
- * IPV6 connection type (value=2).
- */
-ConnectionType.IPV6 = 2;
-
-/**
- * TOR connection type (value=3).
- */
-ConnectionType.TOR = 3;
-
-/**
- * I2P connection type (value=4).
- */
-ConnectionType.I2P = 4;
-
-module.exports = ConnectionType;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroAltChain.js.html b/docs/src_main_js_daemon_model_MoneroAltChain.js.html deleted file mode 100644 index 0d3c10fa9..000000000 --- a/docs/src_main_js_daemon_model_MoneroAltChain.js.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroAltChain.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroAltChain.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-
-/**
- * Models an alternative chain seen by the node.
- */
-class MoneroAltChain {
-  
-  constructor(state) {
-    state = Object.assign({}, state);
-    if (state.difficulty !== undefined && !(state.difficulty instanceof BigInteger)) state.difficulty = BigInteger.parse(state.difficulty);
-    this.state = state;
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (this.getDifficulty()) json.difficulty = this.getDifficulty().toString();
-    return json;
-  }
-  
-  getBlockHashes(blockHashes) {
-    return this.state.blockHashes;
-  }
-  
-  setBlockHashes(blockHashes) {
-    this.state.blockHashes = blockHashes;
-    return this;
-  }
-  
-  getDifficulty() {
-    return this.state.difficulty;
-  }
-  
-  setDifficulty(difficulty) {
-    this.state.difficulty = difficulty;
-    return this;
-  }
-  
-  getHeight() {
-    return this.state.height;
-  }
-  
-  setHeight(height) {
-    this.state.height = height;
-    return this;
-  }
-  
-  getLength() {
-    return this.state.length;
-  }
-  
-  setLength(length) {
-    this.state.length = length;
-    return this;
-  }
-  
-  getMainChainParentBlockHash() {
-    return this.state.mainChainParentBlockHash;
-  }
-  
-  setMainChainParentBlockHash(mainChainParentBlockHash) {
-    this.state.mainChainParentBlockHash = mainChainParentBlockHash;
-    return this;
-  }
-}
-
-module.exports = MoneroAltChain;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroBan.js.html b/docs/src_main_js_daemon_model_MoneroBan.js.html deleted file mode 100644 index f1e74cbda..000000000 --- a/docs/src_main_js_daemon_model_MoneroBan.js.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroBan.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroBan.js

- - - - - - -
-
-
/**
- * Monero banhammer.
- */
-class MoneroBan {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-  }
-  
-  toJson() {
-    return Object.assign({}, this.state);
-  }
-  
-  getHost() {
-    return this.state.host;
-  }
-  
-  setHost(host) {
-    this.state.host = host;
-    return this;
-  }
-  
-  getIp() {
-    return this.state.ip;
-  }
-  
-  setIp(ip) {
-    this.state.ip = ip;
-    return this;
-  }
-  
-  isBanned() {
-    return this.state.isBanned;
-  }
-  
-  setIsBanned(isBanned) {
-    this.state.isBanned = isBanned;
-    return this;
-  }
-  
-  getSeconds() {
-    return this.state.seconds;
-  }
-  
-  setSeconds(seconds) {
-    this.state.seconds = seconds;
-    return this;
-  }
-}
-
-module.exports = MoneroBan;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroBlock.js.html b/docs/src_main_js_daemon_model_MoneroBlock.js.html deleted file mode 100644 index 0335734de..000000000 --- a/docs/src_main_js_daemon_model_MoneroBlock.js.html +++ /dev/null @@ -1,208 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroBlock.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroBlock.js

- - - - - - -
-
-
const assert = require("assert");
-const GenUtils = require("../../common/GenUtils");
-const MoneroBlockHeader = require("./MoneroBlockHeader");
-const MoneroTx = require("./MoneroTx");
-const MoneroTxQuery = require("../../wallet/model/MoneroTxQuery");
-const MoneroTxWallet = require("../../wallet/model/MoneroTxWallet");
-
-/**
- * Models a Monero block in the blockchain.
- * 
- * @extends {MoneroBlockHeader}
- */
-class MoneroBlock extends MoneroBlockHeader {
-  
-  /**
-   * Construct the model.
-   * 
-   * @param {MoneroBlock|MoneroBlockHeader|object} state is existing state to initialize from (optional)
-   * @param {MoneroBlock.DeserializationType} txType informs the tx deserialization type (MoneroTx, MoneroTxWallet, MoneroTxQuery)
-   */
-  constructor(state, txType) {
-    super(state);
-    state = this.state;
-    
-    // deserialize miner tx
-    if (state.minerTx && !(state.minerTx instanceof MoneroTx)) state.minerTx = new MoneroTx(state.minerTx).setBlock(this);
-    
-    // deserialize non-miner txs
-    if (state.txs) {
-      for (let i = 0; i < state.txs.length; i++) {
-        if (txType === MoneroBlock.DeserializationType.TX || txType === undefined) {
-          if (!(state.txs[i] instanceof MoneroTx)) state.txs[i] = new MoneroTx(state.txs[i]).setBlock(this);
-        } else if (txType === MoneroBlock.DeserializationType.TX_WALLET) {
-          if (!(state.txs[i] instanceof MoneroTxWallet)) state.txs[i] = new MoneroTxWallet(state.txs[i]).setBlock(this);
-        } else if (txType === MoneroBlock.DeserializationType.TX_QUERY) {
-          if (!(state.txs[i] instanceof MoneroTxQuery)) state.txs[i] = new MoneroTxQuery(state.txs[i]).setBlock(this);
-        } else {
-          throw new Error("Unrecognized tx deserialization type: " + txType);
-        }
-      }
-    }
-  }
-  
-  getHex() {
-    return this.state.hex;
-  }
-  
-  setHex(hex) {
-    this.state.hex = hex;
-    return this;
-  }
-  
-  getMinerTx() {
-    return this.state.minerTx;
-  }
-  
-  setMinerTx(minerTx) {
-    this.state.minerTx = minerTx;
-    return this;
-  }
-  
-  getTxs() {
-    return this.state.txs;
-  }
-  
-  setTxs(txs) {
-    this.state.txs = txs;
-    return this;
-  }
-  
-  getTxHashes() {
-    return this.state.txHashes;
-  }
-  
-  setTxHashes(txHashes) {
-    this.state.txHashes = txHashes;
-    return this;
-  }
-  
-  copy() {
-    return new MoneroBlock(this);
-  }
-  
-  toJson() {
-    let json = super.toJson();
-    if (this.getMinerTx()) json.minerTx = this.getMinerTx().toJson();
-    if (this.getTxs()) {
-      json.txs = [];
-      for (let tx of this.getTxs()) json.txs.push(tx.toJson());
-    }
-    return json;
-  }
-  
-  merge(block) {
-    assert(block instanceof MoneroBlock);
-    if (this === block) return this;
-    
-    // merge header fields
-    super.merge(block);
-    
-    // merge reconcilable block extensions
-    this.setHex(GenUtils.reconcile(this.getHex(), block.getHex()));
-    this.setTxHashes(GenUtils.reconcile(this.getTxHashes(), block.getTxHashes()));
-    
-    // merge miner tx
-    if (this.getMinerTx() === undefined) this.setMinerTx(block.getMinerTx());
-    if (block.getMinerTx() !== undefined) {
-      block.getMinerTx().setBlock(this);
-      minerTx.merge(block.getMinerTx());
-    }
-    
-    // merge non-miner txs
-    if (block.getTxs() !== undefined) {
-      for (let tx of block.getTxs()) {
-        tx.setBlock(this);
-        MoneroBlock._mergeTx(this.getTxs(), tx);
-      }
-    }
-
-    return this;
-  }
-  
-  toString(indent = 0) {
-    let str = super.toString(indent) + "\n";
-    str += GenUtils.kvLine("Hex", this.getHex(), indent);
-    if (this.getTxs()) {
-      str += GenUtils.kvLine("Txs", "", indent);
-      for (let tx of this.getTxs()) {
-        str += tx.toString(indent + 1) + "\n";
-      }
-    }
-    if (this.getMinerTx()) {
-      str += GenUtils.kvLine("Miner tx", "", indent);
-      str += this.getMinerTx().toString(indent + 1) + "\n";
-    }
-    str += GenUtils.kvLine("Txs hashes", this.getTxHashes(), indent);
-    return str[str.length - 1] === "\n" ? str.slice(0, str.length - 1) : str  // strip last newline
-  }
-  
-  // private helper to merge txs
-  static _mergeTx(txs, tx) {
-    for (let aTx of txs) {
-      if (aTx.getHash() === tx.getHash()) {
-        aTx.merge(tx);
-        return;
-      }
-    }
-    txs.push(tx);
-  }
-}
-
-MoneroBlock.DeserializationType = {
-    TX: 0,
-    TX_WALLET: 1,
-    TX_QUERY: 2
-}
-
-module.exports = MoneroBlock;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroBlockHeader.js.html b/docs/src_main_js_daemon_model_MoneroBlockHeader.js.html deleted file mode 100644 index 95ef2f40d..000000000 --- a/docs/src_main_js_daemon_model_MoneroBlockHeader.js.html +++ /dev/null @@ -1,313 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroBlockHeader.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroBlockHeader.js

- - - - - - -
-
-
const assert = require("assert");
-const BigInteger = require("../../common/biginteger").BigInteger;
-const GenUtils = require("../../common/GenUtils");
-
-/**
- * Models a Monero block header which contains information about the block.
- * 
- * @class
- */
-class MoneroBlockHeader {
-  
-  /**
-   * Construct the model.
-   * 
-   * @param {MoneroBlockHeader|object} state is existing state to initialize from (optional)
-   */
-  constructor(state) {
-    
-    // initialize internal state
-    if (!state) state = {};
-    else if (state instanceof MoneroBlockHeader) state = state.toJson();
-    else if (typeof state === "object") state = Object.assign({}, state);
-    else throw new MoneroError("state must be a MoneroBlockHeader or JavaScript object");
-    this.state = state;
-    
-    // deserialize BigIntegers
-    if (state.difficulty !== undefined && !(state.difficulty instanceof BigInteger)) state.difficulty = BigInteger.parse(state.difficulty);
-    if (state.cumulativeDifficulty !== undefined && !(state.cumulativeDifficulty instanceof BigInteger)) state.cumulativeDifficulty = BigInteger.parse(state.cumulativeDifficulty);
-    if (state.reward !== undefined && !(state.reward instanceof BigInteger)) state.reward = BigInteger.parse(state.reward);
-  }
-  
-  copy() {
-    return new MoneroBlockHeader(this);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (this.getDifficulty()) json.difficulty = this.getDifficulty().toString();
-    if (this.getCumulativeDifficulty()) json.cumulativeDifficulty = this.getCumulativeDifficulty().toString();
-    if (this.getReward()) json.reward = this.getReward().toString();
-    return json;
-  }
-  
-  getHash() {
-    return this.state.hash;
-  }
-  
-  setHash(hash) {
-    this.state.hash = hash;
-    return this;
-  }
-  
-  /**
-   * Return the block's height which is the total number of blocks that have occurred before.
-   * 
-   * @return {number} the block's height
-   */
-  getHeight() {
-    return this.state.height;
-  }
-  
-  /**
-   * Set the block's height which is the total number of blocks that have occurred before.
-   * 
-   * @param {number} height is the block's height to set
-   * @return {MoneroBlockHeader} a reference to this header for chaining
-   */
-  setHeight(height) {
-    this.state.height = height;
-    return this;
-  }
-  
-  getTimestamp() {
-    return this.state.timestamp;
-  }
-  
-  setTimestamp(timestamp) {
-    this.state.timestamp = timestamp;
-    return this;
-  }
-  
-  getSize() {
-    return this.state.size;
-  }
-  
-  setSize(size) {
-    this.state.size = size;
-    return this;
-  }
-  
-  getWeight() {
-    return this.state.weight;
-  }
-  
-  setWeight(weight) {
-    this.state.weight = weight;
-    return this;
-  }
-  
-  getLongTermWeight() {
-    return this.state.longTermWeight;
-  }
-  
-  setLongTermWeight(longTermWeight) {
-    this.state.longTermWeight = longTermWeight;
-    return this;
-  }
-  
-  getDepth() {
-    return this.state.depth;
-  }
-  
-  setDepth(depth) {
-    this.state.depth = depth;
-    return this;
-  }
-  
-  getDifficulty() {
-    return this.state.difficulty;
-  }
-  
-  setDifficulty(difficulty) {
-    this.state.difficulty = difficulty;
-    return this;
-  }
-  
-  getCumulativeDifficulty() {
-    return this.state.cumulativeDifficulty;
-  }
-  
-  setCumulativeDifficulty(cumulativeDifficulty) {
-    this.state.cumulativeDifficulty = cumulativeDifficulty;
-    return this;
-  }
-  
-  getMajorVersion() {
-    return this.state.majorVersion;
-  }
-  
-  setMajorVersion(majorVersion) {
-    this.state.majorVersion = majorVersion;
-    return this;
-  }
-  
-  getMinorVersion() {
-    return this.state.minorVersion;
-  }
-  
-  setMinorVersion(minorVersion) {
-    this.state.minorVersion = minorVersion;
-    return this;
-  }
-  
-  getNonce() {
-    return this.state.nonce;
-  }
-  
-  setNonce(nonce) {
-    this.state.nonce = nonce;
-    return this;
-  }
-  
-  getMinerTxHash() {
-    return this.state.minerTxHash;
-  }
-  
-  setMinerTxHash(minerTxHash) {
-    this.state.minerTxHash = minerTxHash;
-    return this;
-  }
-  
-  getNumTxs() {
-    return this.state.numTxs;
-  }
-  
-  setNumTxs(numTxs) {
-    this.state.numTxs = numTxs;
-    return this;
-  }
-  
-  getOrphanStatus() {
-    return this.state.orphanStatus;
-  }
-  
-  setOrphanStatus(orphanStatus) {
-    this.state.orphanStatus = orphanStatus;
-    return this;
-  }
-  
-  getPrevHash() {
-    return this.state.prevHash;
-  }
-  
-  setPrevHash(prevHash) {
-    this.state.prevHash = prevHash;
-    return this;
-  }
-  
-  getReward() {
-    return this.state.reward;
-  }
-  
-  setReward(reward) {
-    this.state.reward = reward;
-    return this;
-  }
-  
-  getPowHash() {
-    return this.state.powHash;
-  }
-  
-  setPowHash(powHash) {
-    this.state.powHash = powHash;
-    return this;
-  }
-  
-  merge(header) {
-    assert(header instanceof MoneroBlockHeader);
-    if (this === header) return this;
-    this.setHash(GenUtils.reconcile(this.getHash(), header.getHash()));
-    this.setHeight(GenUtils.reconcile(this.getHeight(), header.getHeight(), {resolveMax: true}));  // height can increase
-    this.setTimestamp(GenUtils.reconcile(this.getTimestamp(), header.getTimestamp(), {resolveMax: true}));  // block timestamp can increase
-    this.setSize(GenUtils.reconcile(this.getSize(), header.getSize()));
-    this.setWeight(GenUtils.reconcile(this.getWeight(), header.getWeight()));
-    this.setDepth(GenUtils.reconcile(this.getDepth(), header.getDepth()));
-    this.setDifficulty(GenUtils.reconcile(this.getDifficulty(), header.getDifficulty()));
-    this.setCumulativeDifficulty(GenUtils.reconcile(this.getCumulativeDifficulty(), header.getCumulativeDifficulty()));
-    this.setMajorVersion(GenUtils.reconcile(this.getMajorVersion(), header.getMajorVersion()));
-    this.setMinorVersion(GenUtils.reconcile(this.getMinorVersion(), header.getMinorVersion()));
-    this.setNonce(GenUtils.reconcile(this.getNonce(), header.getNonce()));
-    this.setMinerTxHash(GenUtils.reconcile(this.getMinerTxHash(), header.getMinerTxHash()));
-    this.setNumTxs(GenUtils.reconcile(this.getNumTxs(), header.getNumTxs()));
-    this.setOrphanStatus(GenUtils.reconcile(this.getOrphanStatus(), header.getOrphanStatus()));
-    this.setPrevHash(GenUtils.reconcile(this.getPrevHash(), header.getPrevHash()));
-    this.setReward(GenUtils.reconcile(this.getReward(), header.getReward()));
-    this.setPowHash(GenUtils.reconcile(this.getPowHash(), header.getPowHash()));
-    return this;
-  }
-  
-  toString(indent = 0) {
-    let str = "";
-    str += GenUtils.kvLine("Hash", this.getHash(), indent);
-    str += GenUtils.kvLine("Height", this.getHeight(), indent);
-    str += GenUtils.kvLine("Timestamp", this.getTimestamp(), indent);
-    str += GenUtils.kvLine("Size", this.getSize(), indent);
-    str += GenUtils.kvLine("Weight", this.getWeight(), indent);
-    str += GenUtils.kvLine("Depth", this.getDepth(), indent);
-    str += GenUtils.kvLine("Difficulty", this.getDifficulty(), indent);
-    str += GenUtils.kvLine("Cumulative difficulty", this.getCumulativeDifficulty(), indent);
-    str += GenUtils.kvLine("Major version", this.getMajorVersion(), indent);
-    str += GenUtils.kvLine("Minor version", this.getMinorVersion(), indent);
-    str += GenUtils.kvLine("Nonce", this.getNonce(), indent);
-    str += GenUtils.kvLine("Miner tx hash", this.getMinerTxHash(), indent);
-    str += GenUtils.kvLine("Num txs", this.getNumTxs(), indent);
-    str += GenUtils.kvLine("Orphan status", this.getOrphanStatus(), indent);
-    str += GenUtils.kvLine("Prev hash", this.getPrevHash(), indent);
-    str += GenUtils.kvLine("Reward", this.getReward(), indent);
-    str += GenUtils.kvLine("Pow hash", this.getPowHash(), indent);
-    return str[str.length - 1] === "\n" ? str.slice(0, str.length - 1) : str  // strip last newline
-  }
-}
-
-module.exports = MoneroBlockHeader;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroBlockTemplate.js.html b/docs/src_main_js_daemon_model_MoneroBlockTemplate.js.html deleted file mode 100644 index 38e00643d..000000000 --- a/docs/src_main_js_daemon_model_MoneroBlockTemplate.js.html +++ /dev/null @@ -1,172 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroBlockTemplate.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroBlockTemplate.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-
-/**
- * Monero block template to mine.
- */
-class MoneroBlockTemplate {
-  
-  constructor(state) {
-    state = Object.assign({}, state);
-    this.state = state;
-    
-    // deserialize BigIntegers
-    if (state.expectedReward !== undefined && !(state.expectedReward instanceof BigInteger)) state.expectedReward = BigInteger.parse(state.expectedReward);
-    if (state.difficulty !== undefined && !(state.difficulty instanceof BigInteger)) state.difficulty = BigInteger.parse(state.difficulty);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (this.getExpectedReward()) json.expectedReward = this.getExpectedReward().toString();
-    if (this.getDifficulty()) json.difficulty = this.getDifficulty().toString();
-    return json;
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (json.expectedReward) json.expectedReward = json.expectedReward.toString();
-    if (json.difficulty) json.difficulty = json.difficulty.toString();
-    return json;
-  }
-  
-  getBlockTemplateBlob() {
-    return this.state.blockTemplateBlob;
-  }
-  
-  setBlockTemplateBlob(blockTemplateBlob) {
-    this.state.blockTemplateBlob = blockTemplateBlob;
-    return this;
-  }
-  
-  getBlockHashingBlob() {
-    return this.state.blockHashingBlob;
-  }
-  
-  setBlockHashingBlob(blockHashingBlob) {
-    this.state.blockHashingBlob = blockHashingBlob;
-    return this;
-  }
-  
-  getDifficulty() {
-    return this.state.difficulty;
-  }
-  
-  setDifficulty(difficulty) {
-    this.state.difficulty = difficulty;
-    return this;
-  }
-  
-  getExpectedReward() {
-    return this.state.expectedReward;
-  }
-  
-  setExpectedReward(expectedReward) {
-    this.state.expectedReward = expectedReward;
-    return this;
-  }
-  
-  getHeight() {
-    return this.state.height;
-  }
-  
-  setHeight(height) {
-    this.state.height = height;
-    return this;
-  }
-  
-  getPrevHash() {
-    return this.state.prevId;
-  }
-  
-  setPrevHash(prevId) {
-    this.state.prevId = prevId;
-    return this;
-  }
-  
-  getReservedOffset() {
-    return this.state.reservedOffset;
-  }
-  
-  setReservedOffset(reservedOffset) {
-    this.state.reservedOffset = reservedOffset;
-    return this;
-  }
-  
-  getSeedHeight() {
-    return this.state.height;
-  }
-  
-  setSeedHeight(seedHeight) {
-    this.state.seedHeight = seedHeight;
-    return this;
-  }
-  
-  getSeedHash() {
-    return this.state.seedHash;
-  }
-  
-  setSeedHash(seedHash) {
-    this.state.seedHash = seedHash;
-    return this;
-  }
-  
-  getNextSeedHash() {
-    return this.state.nextSeedHash
-  }
-  
-  setNextSeedHash(nextSeedHash) {
-    this.state.nextSeedHash = nextSeedHash;
-    return this;
-  }
-}
-
-module.exports = MoneroBlockTemplate;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroDaemonConnection.js.html b/docs/src_main_js_daemon_model_MoneroDaemonConnection.js.html deleted file mode 100644 index 3d3b35064..000000000 --- a/docs/src_main_js_daemon_model_MoneroDaemonConnection.js.html +++ /dev/null @@ -1,232 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroDaemonConnection.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroDaemonConnection.js

- - - - - - -
-
-
const MoneroDaemonPeer = require("./MoneroDaemonPeer");
-
-/**
- * Monero daemon connection.
- */
-class MoneroDaemonConnection {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-    if (this.state.peer !== undefined && !(this.state.peer instanceof MoneroDaemonPeer)) this.state.peer = new MoneroDaemonPeer(this.state.peer);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (json.peer) json.peer = json.peer.toJson();
-    return json;
-  }
-  
-  getPeer() {
-    return this.state.peer;
-  }
-
-  setPeer(peer) {
-    this.state.peer = peer;
-    return this;
-  }
-  
-  getId() {
-    return this.state.id;
-  }
-
-  setId(id) {
-    this.state.id = id;
-    return this;
-  }
-
-  getAvgDownload() {
-    return this.state.avgDownload;
-  }
-
-  setAvgDownload(avgDownload) {
-    this.state.avgDownload = avgDownload;
-    return this;
-  }
-
-  getAvgUpload() {
-    return this.state.avgUpload;
-  }
-
-  setAvgUpload(avgUpload) {
-    this.state.avgUpload = avgUpload;
-    return this;
-  }
-
-  getCurrentDownload() {
-    return this.state.currentDownload;
-  }
-
-  setCurrentDownload(currentDownload) {
-    this.state.currentDownload = currentDownload;
-    return this;
-  }
-
-  getCurrentUpload() {
-    return this.state.currentUpload;
-  }
-
-  setCurrentUpload(currentUpload) {
-    this.state.currentUpload = currentUpload;
-    return this;
-  }
-
-  getHeight() {
-    return this.state.height;
-  }
-
-  setHeight(height) {
-    this.state.height = height;
-    return this;
-  }
-
-  isIncoming() {
-    return this.state.isIncoming;
-  }
-
-  setIsIncoming(isIncoming) {
-    this.state.isIncoming = isIncoming;
-    return this;
-  }
-
-  getLiveTime() {
-    return this.state.liveTime;
-  }
-
-  setLiveTime(liveTime) {
-    this.state.liveTime = liveTime;
-    return this;
-  }
-
-  isLocalIp() {
-    return this.state.isLocalIp;
-  }
-
-  setIsLocalIp(isLocalIp) {
-    this.state.isLocalIp = isLocalIp;
-    return this;
-  }
-
-  isLocalHost() {
-    return this.state.isLocalHost;
-  }
-
-  setIsLocalHost(isLocalHost) {
-    this.state.isLocalHost = isLocalHost;
-    return this;
-  }
-
-  getNumReceives() {
-    return this.state.numReceives;
-  }
-
-  setNumReceives(numReceives) {
-    this.state.numReceives = numReceives;
-    return this;
-  }
-
-  getNumSends() {
-    return this.state.numSends;
-  }
-
-  setNumSends(numSends) {
-    this.state.numSends = numSends;
-    return this;
-  }
-
-  getReceiveIdleTime() {
-    return this.state.receiveIdleTime;
-  }
-
-  setReceiveIdleTime(receiveIdleTime) {
-    this.state.receiveIdleTime = receiveIdleTime;
-    return this;
-  }
-
-  getSendIdleTime() {
-    return this.state.sendIdleTime;
-  }
-
-  setSendIdleTime(sendIdleTime) {
-    this.state.sendIdleTime = sendIdleTime;
-    return this;
-  }
-
-  getState() {
-    return this.state.state;
-  }
-
-  setState(state) {
-    this.state.state = state;
-    return this;
-  }
-
-  getNumSupportFlags() {
-    return this.state.numSupportFlags;
-  }
-
-  setNumSupportFlags(numSupportFlags) {
-    this.state.numSupportFlags = numSupportFlags;
-    return this;
-  }
-  
-  getType() {
-    return this.state.type;
-  }
-  
-  setType(type) {
-    this.state.type = type;
-    return this;
-  }
-}
-
-module.exports = MoneroDaemonConnection;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroDaemonConnectionSpan.js.html b/docs/src_main_js_daemon_model_MoneroDaemonConnectionSpan.js.html deleted file mode 100644 index 26d6c1dca..000000000 --- a/docs/src_main_js_daemon_model_MoneroDaemonConnectionSpan.js.html +++ /dev/null @@ -1,128 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroDaemonConnectionSpan.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroDaemonConnectionSpan.js

- - - - - - -
-
-
/**
- * Monero daemon connection span.
- */
-class MoneroDaemonConnectionSpan {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-  }
-  
-  toJson() {
-    return Object.assign({}, this.state);
-  }
-  
-  getConnectionId() {
-    return this.state.connectionId;
-  }
-
-  setConnectionId(connectionId) {
-    this.state.connectionId = connectionId;
-    return this;
-  }
-  
-  getNumBlocks() {
-    return this.state.numBlocks;
-  }
-
-  setNumBlocks(numBlocks) {
-    this.state.numBlocks = numBlocks;
-    return this;
-  }
-  
-  getRemoteAddress() {
-    return this.state.remoteAddress;
-  }
-
-  setRemoteAddress(remoteAddress) {
-    this.state.remoteAddress = remoteAddress;
-    return this;
-  }
-  
-  getRate() {
-    return this.state.rate;
-  }
-
-  setRate(rate) {
-    this.state.rate = rate;
-    return this;
-  }
-  
-  getSpeed() {
-    return this.state.speed;
-  }
-
-  setSpeed(speed) {
-    this.state.speed = speed;
-    return this;
-  }
-  
-  getSize() {
-    return this.state.size;
-  }
-  
-  setSize(size) {
-    this.state.size = size;
-    return this;
-  }
-  
-  getStartHeight() {
-    return this.state.startHeight;
-  }
-  
-  setStartHeight(startHeight) {
-    this.state.startHeight = startHeight;
-    return this;
-  }
-}
-
-module.exports = MoneroDaemonConnectionSpan;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroDaemonInfo.js.html b/docs/src_main_js_daemon_model_MoneroDaemonInfo.js.html deleted file mode 100644 index 14a97f4a9..000000000 --- a/docs/src_main_js_daemon_model_MoneroDaemonInfo.js.html +++ /dev/null @@ -1,338 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroDaemonInfo.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroDaemonInfo.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-
-/**
- * Monero daemon info.
- */
-class MoneroDaemonInfo {
-  
-  constructor(state) {
-    state = Object.assign({}, state);
-    this.state = state;
-    
-    // deserialize BigIntegers
-    if (state.difficulty !== undefined && !(state.difficulty instanceof BigInteger)) state.difficulty = BigInteger.parse(state.difficulty);
-    if (state.cumulativeDifficulty !== undefined && !(state.cumulativeDifficulty instanceof BigInteger)) state.cumulativeDifficulty = BigInteger.parse(state.cumulativeDifficulty);
-    if (state.credits !== undefined && !(state.credits instanceof BigInteger)) state.credits = BigInteger.parse(state.credits);
-  }
-  
-  toJson() {
-    let json = Object.assign([], this.state);
-    if (json.difficulty) json.difficulty = json.difficulty.toString();
-    if (json.cumulativeDifficulty) json.cumulativeDifficulty = json.cumulativeDifficulty.toString();
-    if (json.credits) json.credits = json.credits.toString();
-    return json;
-  }
-  
-  getVersion() {
-    return this.state.version;
-  }
-  
-  setVersion(version) {
-    this.state.version = version;
-    return this;
-  }
-  
-  getNumAltBlocks() {
-    return this.state.numAltBlocks;
-  }
-  
-  setNumAltBlocks(numAltBlocks) {
-    this.state.numAltBlocks = numAltBlocks;
-    return this;
-  }
-  
-  getBlockSizeLimit() {
-    return this.state.blockSizeLimit;
-  }
-  
-  setBlockSizeLimit(blockSizeLimit) {
-    this.state.blockSizeLimit = blockSizeLimit;
-    return this;
-  }
-  
-  getBlockSizeMedian() {
-    return this.state.blockSizeMedian;
-  }
-  
-  setBlockSizeMedian(blockSizeMedian) {
-    this.state.blockSizeMedian = blockSizeMedian;
-    return this;
-  }
-  
-  getBlockWeightLimit() {
-    return this.state.blockWeightLimit;
-  }
-  
-  setBlockWeightLimit(blockWeightLimit) {
-    this.state.blockWeightLimit = blockWeightLimit;
-    return this;
-  }
-  
-  getBlockWeightMedian() {
-    return this.state.blockWeightMedian;
-  }
-  
-  setBlockWeightMedian(blockWeightMedian) {
-    this.state.blockWeightMedian = blockWeightMedian;
-    return this;
-  }
-  
-  getBootstrapDaemonAddress() {
-    return this.state.bootstrapDaemonAddress;
-  }
-  
-  setBootstrapDaemonAddress(bootstrapDaemonAddress) {
-    this.state.bootstrapDaemonAddress = bootstrapDaemonAddress;
-    return this;
-  }
-  
-  getDifficulty() {
-    return this.state.difficulty;
-  }
-  
-  setDifficulty(difficulty) {
-    this.state.difficulty = difficulty;
-    return this;
-  }
-  
-  getCumulativeDifficulty() {
-    return this.state.cumulativeDifficulty;
-  }
-  
-  setCumulativeDifficulty(cumulativeDifficulty) {
-    this.state.cumulativeDifficulty = cumulativeDifficulty;
-    return this;
-  }
-  
-  getFreeSpace() {
-    return this.state.freeSpace;
-  }
-  
-  setFreeSpace(freeSpace) {
-    this.state.freeSpace = freeSpace;
-    return this;
-  }
-  
-  getNumOfflinePeers() {
-    return this.state.numOfflinePeers;
-  }
-  
-  setNumOfflinePeers(numOfflinePeers) {
-    this.state.numOfflinePeers = numOfflinePeers;
-    return this;
-  }
-  
-  getNumOnlinePeers() {
-    return this.state.numOnlinePeers;
-  }
-  
-  setNumOnlinePeers(numOnlinePeers) {
-    this.state.numOnlinePeers = numOnlinePeers;
-    return this;
-  }
-  
-  getHeight() {
-    return this.state.height;
-  }
-  
-  setHeight(height) {
-    this.state.height = height;
-    return this;
-  }
-  
-  getHeightWithoutBootstrap() {
-    return this.state.heightWithoutBootstrap;
-  }
-  
-  setHeightWithoutBootstrap(heightWithoutBootstrap) {
-    this.state.heightWithoutBootstrap = heightWithoutBootstrap;
-    return this;
-  }
-  
-  getNetworkType() {
-    return this.state.networkType;
-  }
-
-  setNetworkType(networkType) {
-    this.state.networkType = networkType;
-    return this;
-  }
-
-  isOffline() {
-    return this.state.isOffline;
-  }
-  
-  setIsOffline(isOffline) {
-    this.state.isOffline = isOffline;
-    return this;
-  }
-  
-  getNumIncomingConnections() {
-    return this.state.numIncomingConnections;
-  }
-  
-  setNumIncomingConnections(numIncomingConnections) {
-    this.state.numIncomingConnections = numIncomingConnections;
-    return this;
-  }
-  
-  getNumOutgoingConnections() {
-    return this.state.numOutgoingConnections;
-  }
-  
-  setNumOutgoingConnections(numOutgoingConnections) {
-    this.state.numOutgoingConnections = numOutgoingConnections;
-    return this;
-  }
-  
-  getNumRpcConnections() {
-    return this.state.numRpcConnections;
-  }
-  
-  setNumRpcConnections(numRpcConnections) {
-    this.state.numRpcConnections = numRpcConnections;
-    return this;
-  }
-  
-  getStartTimestamp() {
-    return this.state.startTimestamp;
-  }
-  
-  setStartTimestamp(startTimestamp) {
-    this.state.startTimestamp = startTimestamp;
-    return this;
-  }
-  
-  getTarget() {
-    return this.state.target;
-  }
-  
-  setTarget(target) {
-    this.state.target = target;
-    return this;
-  }
-  
-  getTargetHeight() {
-    return this.state.targetHeight;
-  }
-  
-  setTargetHeight(targetHeight) {
-    this.state.targetHeight = targetHeight;
-    return this;
-  }
-  
-  getTopBlockHash() {
-    return this.state.topBlockHash;
-  }
-  
-  setTopBlockHash(topBlockHash) {
-    this.state.topBlockHash = topBlockHash;
-    return this;
-  }
-  
-  getNumTxs() {
-    return this.state.numTxs;
-  }
-  
-  setNumTxs(numTxs) {
-    this.state.numTxs = numTxs;
-    return this;
-  }
-  
-  getNumTxsPool() {
-    return this.state.numTxsPool;
-  }
-  
-  setNumTxsPool(numTxsPool) {
-    this.state.numTxsPool = numTxsPool;
-    return this;
-  }
-  
-  getWasBootstrapEverUsed() {
-    return this.state.wasBootstrapEverUsed;
-  }
-  
-  setWasBootstrapEverUsed(wasBootstrapEverUsed) {
-    this.state.wasBootstrapEverUsed = wasBootstrapEverUsed;
-    return this;
-  }
-  
-  getDatabaseSize() {
-    return this.state.databaseSize;
-  }
-  
-  setDatabaseSize(databaseSize) {
-    this.state.databaseSize = databaseSize;
-    return this;
-  }
-  
-  getUpdateAvailable() {
-    return this.state.updateAvailable;
-  }
-  
-  setUpdateAvailable(updateAvailable) {
-    this.state.updateAvailable = updateAvailable;
-    return this;
-  }
-  
-  getCredits() {
-    return this.state.credits;
-  }
-  
-  setCredits(credits) {
-    this.state.credits = credits;
-    return this;
-  }
-}
-
-module.exports = MoneroDaemonInfo;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroDaemonPeer.js.html b/docs/src_main_js_daemon_model_MoneroDaemonPeer.js.html deleted file mode 100644 index b11981163..000000000 --- a/docs/src_main_js_daemon_model_MoneroDaemonPeer.js.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroDaemonPeer.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroDaemonPeer.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-
-/**
- * Models a peer to the daemon.
- */
-class MoneroDaemonPeer {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-    if (this.state.rpcCreditsPerHash !== undefined && !(this.state.rpcCreditsPerHash instanceof BigInteger)) this.state.rpcCreditsPerHash = BigInteger.parse(this.state.rpcCreditsPerHash);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (json.rpcCreditsPerHash) json.rpcCreditsPerHash = json.rpcCreditsPerHash.toString();
-    return json;
-  }
-  
-  getId() {
-    return this.state.id;
-  }
-
-  setId(id) {
-    this.state.id = id;
-    return this;
-  }
-
-  getAddress() {
-    return this.state.address;
-  }
-
-  setAddress(address) {
-    this.state.address = address;
-    return this;
-  }
-
-  getHost() {
-    return this.state.host;
-  }
-
-  setHost(host) {
-    this.state.host = host;
-    return this;
-  }
-
-  getPort() {
-    return this.state.port;
-  }
-
-  setPort(port) {
-    this.state.port = port;
-    return this;
-  }
-  
-  /**
-   * Indicates if the peer was online when last checked (aka "white listed" as
-   * opposed to "gray listed").
-   * 
-   * @return {boolean} true if peer was online when last checked, false otherwise
-   */
-  isOnline() {
-    return this.state.isOnline;
-  }
-  
-  setIsOnline(isOnline) {
-    this.state.isOnline = isOnline;
-    return this;
-  }
-  
-  getLastSeenTimestamp() {
-    return this.state.lastSeenTimestamp;
-  }
-  
-  setLastSeenTimestamp(lastSeenTimestamp) {
-    this.state.lastSeenTimestamp = lastSeenTimestamp;
-    return this;
-  }
-  
-  getPruningSeed() {
-    return this.state.pruningSeed;
-  }
-  
-  setPruningSeed(pruningSeed) {
-    this.state.pruningSeed = pruningSeed;
-    return this;
-  }
-  
-  getRpcPort() {
-    return this.state.rpcPort;
-  }
-
-  setRpcPort(rpcPort) {
-    this.state.rpcPort = rpcPort;
-    return this;
-  }
-  
-  getRpcCreditsPerHash() {
-    return this.state.rpcCreditsPerHash;
-  }
-  
-  setRpcCreditsPerHash(rpcCreditsPerHash) {
-    this.state.rpcCreditsPerHash = rpcCreditsPerHash;
-    return this;
-  }
-}
-
-module.exports = MoneroDaemonPeer;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroDaemonSyncInfo.js.html b/docs/src_main_js_daemon_model_MoneroDaemonSyncInfo.js.html deleted file mode 100644 index 1b0a162a5..000000000 --- a/docs/src_main_js_daemon_model_MoneroDaemonSyncInfo.js.html +++ /dev/null @@ -1,175 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroDaemonSyncInfo.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroDaemonSyncInfo.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-const MoneroDaemonConnection = require("./MoneroDaemonConnection");
-const MoneroDaemonConnectionSpan = require("./MoneroDaemonConnectionSpan");
-
-/**
- * Models daemon synchronization information.
- */
-class MoneroDaemonSyncInfo {
-  
-  constructor(state) {
-    
-    // copy state
-    state = Object.assign({}, state);
-    
-    // deserialize if necessary
-    if (state.connections) {
-      for (let i = 0; i < state.connections.length; i++) {
-        if (!(state.connections[i] instanceof MoneroDaemonConnection)) {
-          state.connections[i] = new MoneroDaemonConnection(state.connections[i]);
-        }
-      }
-    }
-    if (state.spans) {
-      for (let i = 0; i < state.spans.length; i++) {
-        if (!(state.spans[i] instanceof MoneroDaemonConnectionSpan)) {
-          state.spans[i] = new MoneroDaemonConnectionSpan(state.spans[i]);
-        }
-      }
-    }
-    if (state.credits !== undefined && !(state.credits instanceof BigInteger)) state.credits = BigInteger.parse(state.credits);
-    
-    // assign internal state
-    this.state = state;
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (json.connections) {
-      for (let i = 0; i < json.connections.length; i++) {
-        json.connections[i] = json.connections[i].toJson();
-      }
-    }
-    if (json.spans) {
-      for (let i = 0; i < json.spans.length; i++) {
-        json.spans[i] = json.spans[i].toJson();
-      }
-    }
-    if (json.credits) json.credits = json.credits.toString();
-    return json;
-  }
-  
-  getHeight() {
-    return this.state.height;
-  }
-  
-  setHeight(height) {
-    this.state.height = height;
-    return this;
-  }
-  
-  getConnections() {
-    return this.state.connections;
-  }
-  
-  setConnections(connections) {
-    this.state.connections = connections;
-    return this;
-  }
-  
-  getSpans() {
-    return this.state.spans;
-  }
-  
-  setSpans(spans) {
-    this.state.spans = spans;
-    return this;
-  }
-  
-  getTargetHeight() {
-    return this.state.targetHeight;
-  }
-  
-  setTargetHeight(targetHeight) {
-    this.state.targetHeight = targetHeight;
-    return this;
-  }
-  
-  getNextNeededPruningSeed() {
-    return this.state.nextNeededPruningSeed;
-  }
-  
-  setNextNeededPruningSeed(nextNeededPruningSeed) {
-    this.state.nextNeededPruningSeed = nextNeededPruningSeed;
-    return this;
-  }
-  
-  getOverview() {
-    return this.state.overview;
-  }
-  
-  setOverview(overview) {
-    this.state.overview = overview;
-    return this;
-  }
-  
-  getCredits() {
-    return this.state.credits;
-  }
-  
-  setCredits(credits) {
-    this.state.credits = credits;
-    return this;
-  }
-  
-  getTopBlockHash() {
-    return this.state.topBlockHash;
-  }
-  
-  setTopBlockHash(topBlockHash) {
-    this.state.topBlockHash = topBlockHash;
-    return this;
-  }
-}
-
-module.exports = MoneroDaemonSyncInfo;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroDaemonUpdateCheckResult.js.html b/docs/src_main_js_daemon_model_MoneroDaemonUpdateCheckResult.js.html deleted file mode 100644 index e23c828f0..000000000 --- a/docs/src_main_js_daemon_model_MoneroDaemonUpdateCheckResult.js.html +++ /dev/null @@ -1,144 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroDaemonUpdateCheckResult.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroDaemonUpdateCheckResult.js

- - - - - - -
-
-
/**
- * Models the result of checking for a daemon update.
- */
-class MoneroDaemonUpdateCheckResult {
-  
-  /**
-   * Deep copy constructor.
-   * 
-   * @param {MoneroDaemonUpdateCheckResult} is an existing result to deep copy from
-   */
-  constructor(result) {
-    this.state = {};
-    if (result !== undefined) {
-      assert(result instanceof MoneroDaemonUpdateCheckResult);
-      this.setIsUpdateAvailable(result.isUpdateAvailable());
-      this.setVersion(result.getVersion());
-      this.setHash(result.getHash());
-      this.setAutoUri(result.getAutoUri());
-      this.setUserUri(result.getUserUri());
-    }
-  }
-  
-  /**
-   * Indicates if an update is available.
-   * 
-   * @return {boolean} true if an update is available, false otherwise
-   */
-  isUpdateAvailable() {
-    return this.state.isUpdateAvailable;
-  }
-  
-  setIsUpdateAvailable(isUpdateAvailable) {
-    this.state.isUpdateAvailable = isUpdateAvailable;
-    return this;
-  }
-  
-  /**
-   * Get the update's version.
-   * 
-   * @return {string} is the update's version
-   */
-  getVersion() {
-    return this.state.version;
-  }
-  
-  setVersion(version) {
-    this.state.version = version;
-    return this;
-  }
-  
-  /**
-   * Get the update's hash.
-   * 
-   * @return {string} is the update's hash
-   */
-  getHash() {
-    return this.state.hash;
-  }
-  
-  setHash(hash) {
-    this.state.hash = hash;
-    return this;
-  }
-  
-  /**
-   * Get the uri to automatically download the update.
-   * 
-   * @return {string} is the uri to automatically download the update
-   */
-  getAutoUri() {
-    return this.state.autoUri;
-  }
-  
-  setAutoUri(autoUri) {
-    this.state.autoUri = autoUri;
-    return this;
-  }
-  
-  /**
-   * Get the uri to manually download the update.
-   * 
-   * @return {string} is the uri to manually download the update
-   */
-  getUserUri() {
-    return this.state.userUri;
-  }
-  
-  setUserUri(userUri) {
-    this.state.userUri = userUri;
-    return this;
-  }
-}
-
-module.exports = MoneroDaemonUpdateCheckResult;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroDaemonUpdateDownloadResult.js.html b/docs/src_main_js_daemon_model_MoneroDaemonUpdateDownloadResult.js.html deleted file mode 100644 index c7893433e..000000000 --- a/docs/src_main_js_daemon_model_MoneroDaemonUpdateDownloadResult.js.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroDaemonUpdateDownloadResult.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroDaemonUpdateDownloadResult.js

- - - - - - -
-
-
const MoneroDaemonUpdateCheckResult = require("./MoneroDaemonUpdateCheckResult");
-
-/**
- * Models the result of downloading an update.
- */
-class MoneroDaemonUpdateDownloadResult extends MoneroDaemonUpdateCheckResult {
-  
-  /**
-   * Construct a download result.
-   * 
-   * @param {MoneroDaemonUpdateCheckResult} is an existing result to copy from
-   */
-  constructor(result) {
-    super(result);
-  }
-  
-  /**
-   * Get the path the update was downloaded to.
-   * 
-   * @return {string} is the path the update was downloaded to
-   */
-  getDownloadPath() {
-    return this.state.downloadPath;
-  }
-  
-  setDownloadPath(downloadPath) {
-    this.state.downloadPath = downloadPath;
-    return this;
-  }
-}
-
-module.exports = MoneroDaemonUpdateDownloadResult;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroHardForkInfo.js.html b/docs/src_main_js_daemon_model_MoneroHardForkInfo.js.html deleted file mode 100644 index 9adb0a193..000000000 --- a/docs/src_main_js_daemon_model_MoneroHardForkInfo.js.html +++ /dev/null @@ -1,160 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroHardForkInfo.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroHardForkInfo.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-
-/**
- * Monero hard fork info.
- */
-class MoneroHardForkInfo {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-    if (this.state.credits !== undefined && !(this.state.credits instanceof BigInteger)) this.state.credits = BigInteger.parse(this.state.credits);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (json.credits) json.credits = json.credits.toString();
-    return json;
-  }
-  
-  getEarliestHeight() {
-    return this.state.earliestHeight;
-  }
-
-  setEarliestHeight(earliestHeight) {
-    this.state.earliestHeight = earliestHeight;
-    return this;
-  }
-
-  isEnabled() {
-    return this.state.isEnabled;
-  }
-
-  setIsEnabled(isEnabled) {
-    this.state.isEnabled = isEnabled;
-    return this;
-  }
-
-  getState() {
-    return this.state.state;
-  }
-
-  setState(state) {
-    this.state.state = state;
-    return this;
-  }
-
-  getThreshold() {
-    return this.state.threshold;
-  }
-
-  setThreshold(threshold) {
-    this.state.threshold = threshold;
-    return this;
-  }
-
-  getVersion() {
-    return this.state.version;
-  }
-
-  setVersion(version) {
-    this.state.version = version;
-    return this;
-  }
-
-  getNumVotes() {
-    return this.state.numVotes;
-  }
-
-  setNumVotes(numVotes) {
-    this.state.numVotes = numVotes;
-    return this;
-  }
-
-  getWindow() {
-    return this.state.window;
-  }
-
-  setWindow(window) {
-    this.state.window = window;
-    return this;
-  }
-
-  getVoting() {
-    return this.state.voting;
-  }
-
-  setVoting(voting) {
-    this.state.voting = voting;
-    return this;
-  }
-  
-  getCredits() {
-    return this.state.credits;
-  }
-  
-  setCredits(credits) {
-    this.state.credits = credits;
-    return this;
-  }
-  
-  getTopBlockHash() {
-    return this.state.topBlockHash;
-  }
-  
-  setTopBlockHash(topBlockHash) {
-    this.state.topBlockHash = topBlockHash;
-    return this;
-  }
-}
-
-module.exports = MoneroHardForkInfo;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroKeyImage.js.html b/docs/src_main_js_daemon_model_MoneroKeyImage.js.html deleted file mode 100644 index 53907f7d4..000000000 --- a/docs/src_main_js_daemon_model_MoneroKeyImage.js.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroKeyImage.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroKeyImage.js

- - - - - - -
-
-
const assert = require("assert");
-const GenUtils = require("../../common/GenUtils");
-
-/**
- * Models a Monero key image.
- */
-class MoneroKeyImage {
-  
-  /**
-   * Construct the model.
-   * 
-   * @param {MoneroKeyImage|object|string} stateOrHex is a MoneroKeyImage, JS object, or hex string to initialize from (optional)
-   * @param {string} signature is the key image's signature
-   */
-  constructor(stateOrHex, signature) {
-    if (!stateOrHex) this.state = {};
-    else if (stateOrHex instanceof MoneroKeyImage) this.state = stateOrHex.toJson();
-    else if (typeof stateOrHex === "object") this.state = Object.assign({}, stateOrHex);
-    else if (typeof stateOrHex === "string") {
-      this.state = {};
-      this.setHex(stateOrHex);
-      this.setSignature(signature);
-    } else {
-      throw new MoneroError("stateOrHex must be a MoneroKeyImage, JavaScript object, or string");
-    }
-  }
-
-  getHex() {
-    return this.state.hex;
-  }
-
-  setHex(hex) {
-    this.state.hex = hex;
-    return this;
-  }
-
-  getSignature() {
-    return this.state.signature;
-  }
-
-  setSignature(signature) {
-    this.state.signature = signature;
-    return this;
-  }
-  
-  copy() {
-    return new MoneroKeyImage(this);
-  }
-  
-  toJson() {
-    return Object.assign({}, this.state);
-  }
-  
-  merge(keyImage) {
-    assert(keyImage instanceof MoneroKeyImage);
-    if (keyImage === this) return this;
-    this.setHex(GenUtils.reconcile(this.getHex(), keyImage.getHex()));
-    this.setSignature(GenUtils.reconcile(this.getSignature(), keyImage.getSignature()));
-    return this;
-  }
-  
-  toString(indent = 0) {
-    let str = "";
-    str += GenUtils.kvLine("Hex", this.getHex(), indent);
-    str += GenUtils.kvLine("Signature", this.getSignature(), indent);
-    return str.slice(0, str.length - 1);  // strip last newline
-  }
-}
-
-module.exports = MoneroKeyImage;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroKeyImageSpentStatus.js.html b/docs/src_main_js_daemon_model_MoneroKeyImageSpentStatus.js.html deleted file mode 100644 index 93c2d63d7..000000000 --- a/docs/src_main_js_daemon_model_MoneroKeyImageSpentStatus.js.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroKeyImageSpentStatus.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroKeyImageSpentStatus.js

- - - - - - -
-
-
/**
- * Enumerate key image spent statuses.
- * 
- * @hideconstructor
- */
-class MoneroKeyImageSpentStatus {}
-
-/**
- * Key image is not spent (value=0).
- */
-MoneroKeyImageSpentStatus.NOT_SPENT = 0;
-
-/**
- * Key image is confirmed (value=1).
- */
-MoneroKeyImageSpentStatus.CONFIRMED = 1;
-
-/**
- * Key image is in the pool (value=2).
- */
-MoneroKeyImageSpentStatus.TX_POOL = 2;
-
-module.exports = MoneroKeyImageSpentStatus;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroMinerTxSum.js.html b/docs/src_main_js_daemon_model_MoneroMinerTxSum.js.html deleted file mode 100644 index a7fbba634..000000000 --- a/docs/src_main_js_daemon_model_MoneroMinerTxSum.js.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroMinerTxSum.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroMinerTxSum.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-
-/**
- * Model for the summation of miner emissions and fees.
- */
-class MoneroMinerTxSum {
-  
-  constructor(state) {
-    state = Object.assign({}, state);
-    this.state = state;
-    
-    // deserialize BigIntegers
-    if (state.emissionSum !== undefined && !(state.emissionSum instanceof BigInteger)) state.emissionSum = BigInteger.parse(state.emissionSum);
-    if (state.feeSum !== undefined && !(state.feeSum instanceof BigInteger)) state.feeSum = BigInteger.parse(state.feeSum);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (this.getEmissionSum()) json.emissionSum = this.getEmissionSum().toString();
-    if (this.getFeeSum()) json.feeSum = this.getFeeSum().toString();
-    return json;
-  }
-  
-  getEmissionSum() {
-    return this.state.emissionSum;
-  }
-  
-  setEmissionSum(emissionSum) {
-    this.state.emissionSum = emissionSum;
-    return this;
-  }
-  
-  getFeeSum() {
-    return this.state.feeSum;
-  }
-  
-  setFeeSum(feeSum) {
-    this.state.feeSum = feeSum;
-    return this;
-  }
-}
-
-module.exports = MoneroMinerTxSum;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroMiningStatus.js.html b/docs/src_main_js_daemon_model_MoneroMiningStatus.js.html deleted file mode 100644 index 7032b2fdb..000000000 --- a/docs/src_main_js_daemon_model_MoneroMiningStatus.js.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroMiningStatus.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroMiningStatus.js

- - - - - - -
-
-
/**
- * Models daemon mining status.
- */
-class MoneroMiningStatus {
-  
-  constructor(state) {
-    if (!state) state = {};
-    else if (state instanceof MoneroMiningStatus) state = state.toJson();
-    else if (typeof state === "object") state = Object.assign({}, state);
-    else throw new MoneroError("state must be a MoneroMiningStatus or JavaScript object");
-    this.state = state;
-  }
-  
-  toJson() {
-    return Object.assign({}, this.state);
-  }
-  
-  isActive() {
-    return this.state.isActive;
-  }
-  
-  setIsActive(isActive) {
-    this.state.isActive = isActive;
-    return this;
-  }
-  
-  getAddress() {
-    return this.state.address;
-  }
-  
-  setAddress(address) {
-    this.state.address = address;
-    return this;
-  }
-  
-  getSpeed() {
-    return this.state.speed;
-  }
-  
-  setSpeed(speed) {
-    this.state.speed = speed;
-    return this;
-  }
-  
-  getNumThreads() {
-    return this.state.numThreads;
-  }
-  
-  setNumThreads(numThreads) {
-    this.state.numThreads = numThreads;
-    return this;
-  }
-  
-  isBackground() {
-    return this.state.isBackground;
-  }
-  
-  setIsBackground(isBackground) {
-    this.state.isBackground = isBackground;
-    return this;
-  }
-}
-
-module.exports = MoneroMiningStatus;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroNetworkType.js.html b/docs/src_main_js_daemon_model_MoneroNetworkType.js.html deleted file mode 100644 index c9883498f..000000000 --- a/docs/src_main_js_daemon_model_MoneroNetworkType.js.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroNetworkType.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroNetworkType.js

- - - - - - -
-
-
const assert = require("assert");
-
-/**
- * Defines the Monero network types (mainnet, testnet, and stagenet).
- * 
- * @hideconstructor
- */
-class MoneroNetworkType {
-  
-  /**
-   * Asserts that the given network type is valid.
-   * 
-   * @param {int} networkType - the network type to validate as a numeric
-   */
-  static validate(networkType) {
-    assert(networkType === 0 || networkType === 1 || networkType === 2, "Network type is invalid: " + networkType);
-  }
-  
-  /**
-   * Indicates if the given network type is valid or not.
-   * 
-   * @param {int} networkType - the network type to validate as a numeric
-   * @return {boolean} true if the network type is valid, false otherwise
-   */
-  static isValid(networkType) {
-    return networkType === 0 || networkType === 1 || networkType === 2;
-  }
-  
-  /**
-   * Parse the given string as a network type.
-   * 
-   * @param {string} networkTypeStr - "mainnet", "testnet", or "stagenet" (case insensitive)
-   * @return {int} the network type as a numeric
-   */
-  static parse(networkTypeStr) {
-    let str = ("" + networkTypeStr).toLowerCase();
-    switch (str) {
-      case "mainnet": return MoneroNetworkType.MAINNET;
-      case "testnet": return MoneroNetworkType.TESTNET;
-      case "stagenet": return MoneroNetworkType.STAGENET;
-      default: throw new MoneroError("Invalid network type to parse: '" + networkTypeStr + "'");
-    }
-  }
-}
-
-/**
- * Mainnet (value=0).
- */
-MoneroNetworkType.MAINNET = 0;
-
-/**
- * Testnet (value=1).
- */
-MoneroNetworkType.TESTNET = 1;
-
-/**
- * Stagnet (value=2).
- */
-MoneroNetworkType.STAGENET = 2;
-
-module.exports = MoneroNetworkType;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroOutput.js.html b/docs/src_main_js_daemon_model_MoneroOutput.js.html deleted file mode 100644 index 36b855212..000000000 --- a/docs/src_main_js_daemon_model_MoneroOutput.js.html +++ /dev/null @@ -1,181 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroOutput.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroOutput.js

- - - - - - -
-
-
const assert = require("assert");
-const BigInteger = require("../../common/biginteger").BigInteger;
-const GenUtils = require("../../common/GenUtils");
-const MoneroKeyImage = require("./MoneroKeyImage");
-
-/**
- * Models a Monero transaction output.
- * 
- * @class
- */
-class MoneroOutput {
-  
-  /**
-   * Construct the model.
-   * 
-   * @param {MoneroOutput|object} state is existing state to initialize from (optional)
-   */
-  constructor(state) {
-    
-    // initialize internal state
-    if (!state) state = {};
-    else if (state instanceof MoneroOutput) state = state.toJson();
-    else if (typeof state === "object") state = Object.assign({}, state);
-    else throw new MoneroError("state must be a MoneroOutput or JavaScript object");
-    this.state = state;
-    
-    // deserialize fields if necessary
-    if (state.amount !== undefined && !(state.amount instanceof BigInteger)) state.amount = BigInteger.parse(state.amount);
-    if (state.keyImage && !(state.keyImage instanceof MoneroKeyImage)) state.keyImage = new MoneroKeyImage(state.keyImage);
-  }
-  
-  getTx() {
-    return this.state.tx;
-  }
-  
-  setTx(tx) {
-    this.state.tx = tx;
-    return this;
-  }
-  
-  getKeyImage() {
-    return this.state.keyImage;
-  }
-
-  setKeyImage(keyImage) {
-    assert(keyImage === undefined || keyImage instanceof MoneroKeyImage);
-    this.state.keyImage = keyImage;
-    return this;
-  }
-  
-  getAmount() {
-    return this.state.amount;
-  }
-
-  setAmount(amount) {
-    this.state.amount = amount;
-    return this;
-  }
-  
-  getIndex() {
-    return this.state.index;
-  }
-  
-  setIndex(index) {
-    this.state.index = index;
-    return this;
-  }
-  
-  getRingOutputIndices() {
-    return this.state.ringOutputIndices;
-  }
-  
-  setRingOutputIndices(ringOutputIndices) {
-    this.state.ringOutputIndices = ringOutputIndices;
-    return this;
-  }
-  
-  getStealthPublicKey() {
-    return this.state.stealthPublicKey;
-  }
-  
-  setStealthPublicKey(stealthPublicKey) {
-    this.state.stealthPublicKey = stealthPublicKey;
-    return this;
-  }
-  
-  copy() {
-    return new MoneroOutput(this);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (this.getAmount()) json.amount = this.getAmount() ? this.getAmount().toString() : undefined;
-    if (this.getKeyImage()) json.keyImage = this.getKeyImage() ? this.getKeyImage().toJson() : undefined;
-    delete json.tx;
-    return json;
-  }
-  
-  merge(output) {
-    assert(output instanceof MoneroOutput);
-    if (this === output) return this;
-    
-    // merge txs if they're different which comes back to merging outputs
-    if (this.getTx() !== output.getTx()) this.getTx().merge(output.getTx());
-    
-    // otherwise merge output fields
-    else {
-      if (this.getKeyImage() === undefined) this.setKeyImage(output.getKeyImage());
-      else if (output.getKeyImage() !== undefined) this.getKeyImage().merge(output.getKeyImage());
-      this.setAmount(GenUtils.reconcile(this.getAmount(), output.getAmount()));
-      this.setIndex(GenUtils.reconcile(this.getIndex(), output.getIndex()));
-    }
-
-    return this;
-  }
-  
-  toString(indent = 0) {
-    let str = "";
-    if (this.getKeyImage()) {
-      str += GenUtils.kvLine("Key image", "", indent);
-      str += this.getKeyImage().toString(indent + 1) + "\n";
-    }
-    str += GenUtils.kvLine("Amount", this.getAmount(), indent);
-    str += GenUtils.kvLine("Index", this.getIndex(), indent);
-    str += GenUtils.kvLine("Ring output indices", this.getRingOutputIndices(), indent);
-    str += GenUtils.kvLine("Stealth public key", this.getStealthPublicKey(), indent);
-    return str === "" ? str : str.slice(0, str.length - 1);  // strip last newline
-  }
-}
-
-module.exports = MoneroOutput;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroOutputHistogramEntry.js.html b/docs/src_main_js_daemon_model_MoneroOutputHistogramEntry.js.html deleted file mode 100644 index 877c5726f..000000000 --- a/docs/src_main_js_daemon_model_MoneroOutputHistogramEntry.js.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroOutputHistogramEntry.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroOutputHistogramEntry.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-
-/**
- * Entry in a Monero output histogram (see get_output_histogram of Daemon RPC documentation).
- */
-class MoneroOutputHistogramEntry {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-    if (this.state.amount !== undefined && !(this.state.amount instanceof BigInteger)) this.state.amount = BigInteger.parse(this.state.amount);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (json.amount) json.amount = json.amount.toString();
-    return json;
-  }
-  
-  getAmount() {
-    return this.state.amount;
-  }
-  
-  setAmount(amount) {
-    this.state.amount = amount;
-    return this;
-  }
-
-  getNumInstances() {
-    return this.state.numInstances;
-  }
-
-  setNumInstances(numInstances) {
-    this.state.numInstances = numInstances;
-    return this;
-  }
-
-  getNumUnlockedInstances() {
-    return this.state.numUnlockedInstances;
-  }
-
-  setNumUnlockedInstances(numUnlockedInstances) {
-    this.state.numUnlockedInstances = numUnlockedInstances;
-    return this;
-  }
-
-  getNumRecentInstances() {
-    return this.state.numRecentInstances;
-  }
-
-  setNumRecentInstances(numRecentInstances) {
-    this.state.numRecentInstances = numRecentInstances;
-    return this;
-  }
-}
-
-module.exports = MoneroOutputHistogramEntry;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroSubmitTxResult.js.html b/docs/src_main_js_daemon_model_MoneroSubmitTxResult.js.html deleted file mode 100644 index 2b59ce1d1..000000000 --- a/docs/src_main_js_daemon_model_MoneroSubmitTxResult.js.html +++ /dev/null @@ -1,199 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroSubmitTxResult.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroSubmitTxResult.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-
-/**
- * Models the result from submitting a tx to a daemon.
- */
-class MoneroSubmitTxResult {
-  
-  constructor(state) {
-    state = Object.assign({}, state);
-    this.state = state;
-    
-    // deserialize BigIntegers
-    if (state.credits !== undefined && !(state.credits instanceof BigInteger)) state.credits = BigInteger.parse(state.credits);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (json.credits) json.credits = json.credits.toString();
-    return json;
-  }
-  
-  isGood() {
-    return this.state.isGood;
-  }
-  
-  setIsGood(isGood) {
-    this.state.isGood = isGood;
-    return this;
-  }
-  
-  isRelayed() {
-    return this.state.isRelayed;
-  }
-  
-  setIsRelayed(isRelayed) {
-    this.state.isRelayed = isRelayed;
-    return this;
-  }
-  
-  isDoubleSpendSeen() {
-    return this.state.isDoubleSpendSeen;
-  }
-  
-  setIsDoubleSpend(isDoubleSpendSeen) {
-    this.state.isDoubleSpendSeen = isDoubleSpendSeen
-    return this;
-  }
-  
-  isFeeTooLow() {
-    return this.state.isFeeTooLow;
-  }
-  
-  setIsFeeTooLow(isFeeTooLow) {
-    this.state.isFeeTooLow = isFeeTooLow;
-    return this;
-  }
-  
-  isMixinTooLow() {
-    return this.state.isMixinTooLow;
-  }
-  
-  setIsMixinTooLow(isMixinTooLow) {
-    this.state.isMixinTooLow = isMixinTooLow;
-    return this;
-  }
-  
-  hasInvalidInput() {
-    return this.state.hasInvalidInput;
-  }
-  
-  setHasInvalidInput(hasInvalidInput) {
-    this.state.hasInvalidInput = hasInvalidInput;
-    return this;
-  }
-  
-  hasInvalidOutput() {
-    return this.state.hasInvalidOutput;
-  }
-  
-  setHasInvalidOutput(hasInvalidOutput) {
-    this.state.hasInvalidOutput = hasInvalidOutput;
-    return this;
-  }
-  
-  hasTooFewOutputs() {
-    return this.state.hasTooFewOutputs;
-  }
-  
-  setHasTooFewOutputs(hasTooFewOutputs) {
-    this.state.hasTooFewOutputs = hasTooFewOutputs;
-    return this;
-  }
-  
-  isOverspend() {
-    return this.state.isOverspend;
-  }
-  
-  setIsOverspend(isOverspend) {
-    this.state.isOverspend = isOverspend;
-    return this;
-  }
-  
-  getReason() {
-    return this.state.reason;
-  }
-  
-  setReason(reason) {
-    this.state.reason = reason;
-    return this;
-  }
-  
-  isTooBig() {
-    return this.state.isTooBig;
-  }
-  
-  setIsTooBig(isTooBig) {
-    this.state.isTooBig = isTooBig;
-    return this;
-  }
-  
-  getSanityCheckFailed() {
-    return this.state.sanityCheckFailed;
-  }
-  
-  setSanityCheckFailed(sanityCheckFailed) {
-    this.state.sanityCheckFailed = sanityCheckFailed;
-    return this;
-  }
-  
-  getCredits() {
-    return this.state.credits;
-  }
-  
-  setCredits(credits) {
-    this.state.credits = credits;
-    return this;
-  }
-  
-  getTopBlockHash() {
-    return this.state.topBlockHash;
-  }
-  
-  setTopBlockHash(topBlockHash) {
-    this.state.topBlockHash = topBlockHash;
-    return this;
-  }
-}
-
-module.exports = MoneroSubmitTxResult;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroTx.js.html b/docs/src_main_js_daemon_model_MoneroTx.js.html deleted file mode 100644 index c6a03ac6f..000000000 --- a/docs/src_main_js_daemon_model_MoneroTx.js.html +++ /dev/null @@ -1,648 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroTx.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroTx.js

- - - - - - -
-
-
const assert = require("assert");
-const BigInteger = require("../../common/biginteger").BigInteger;
-const GenUtils = require("../../common/GenUtils");
-const MoneroOutput = require("./MoneroOutput");
-
-/**
- * Represents a transaction on the Monero network.
- * 
- * @class
- */
-class MoneroTx {
-  
-  /**
-   * Construct the model.
-   * 
-   * @param {MoneroTx|object} state is existing state to initialize from (optional)
-   */
-  constructor(state) {
-    
-    // initialize internal state
-    if (!state) state = {};
-    else if (state instanceof MoneroTx) state = state.toJson();
-    else if (typeof state === "object") state = Object.assign({}, state);
-    else throw new MoneroError("state must be a MoneroTx or JavaScript object");
-    this.state = state;
-    
-    // deserialize fee
-    if (state.fee !== undefined && !(state.fee instanceof BigInteger)) state.fee = BigInteger.parse(state.fee);
-    
-    // deserialize inputs
-    if (state.inputs) {
-      for (let i = 0; i < state.inputs.length; i++) {
-        if (!(state.inputs[i] instanceof MoneroOutput)) {
-          state.inputs[i] = new MoneroOutput(Object.assign(state.inputs[i], {tx: this}));
-        }
-      }
-    }
-    
-    // deserialize outputs
-    if (state.outputs) {
-      for (let i = 0; i < state.outputs.length; i++) {
-        if (!(state.outputs[i] instanceof MoneroOutput)) {
-          state.outputs[i] = new MoneroOutput(Object.assign(state.outputs[i], {tx: this}));
-        }
-      }
-    }
-  }
-  
-  getBlock() {
-    return this.state.block;
-  }
-  
-  setBlock(block) {
-    this.state.block = block;
-    return this;
-  }
-  
-  getHeight() {
-    return this.getBlock() === undefined ? undefined : this.getBlock().getHeight();
-  }
-  
-  getHash() {
-    return this.state.hash;
-  }
-  
-  setHash(hash) {
-    this.state.hash = hash;
-    return this;
-  }
-  
-  getVersion() {
-    return this.state.version;
-  }
-  
-  setVersion(version) {
-    this.state.version = version;
-    return this;
-  }
-  
-  isMinerTx() {
-    return this.state.isMinerTx;
-  }
-  
-  setIsMinerTx(miner) {
-    this.state.isMinerTx = miner;
-    return this;
-  }
-  
-  getPaymentId() {
-    return this.state.paymentId;
-  }
-  
-  setPaymentId(paymentId) {
-    this.state.paymentId = paymentId;
-    return this;
-  }
-  
-  getFee() {
-    return this.state.fee;
-  }
-  
-  setFee(fee) {
-    this.state.fee = fee;
-    return this;
-  }
-  
-  getRingSize() {
-    return this.state.ringSize;
-  }
-  
-  setRingSize(ringSize) {
-    this.state.ringSize = ringSize;
-    return this;
-  }
-  
-  getRelay() {
-    return this.state.relay;
-  }
-  
-  setRelay(relay) {
-    this.state.relay = relay;
-    return this;
-  }
-  
-  isRelayed() {
-    return this.state.isRelayed;
-  }
-  
-  setIsRelayed(isRelayed) {
-    this.state.isRelayed = isRelayed;
-    return this;
-  }
-  
-  isConfirmed() {
-    return this.state.isConfirmed;
-  }
-  
-  setIsConfirmed(isConfirmed) {
-    this.state.isConfirmed = isConfirmed;
-    return this;
-  }
-  
-  inTxPool() {
-    return this.state.inTxPool;
-  }
-  
-  setInTxPool(inTxPool) {
-    this.state.inTxPool = inTxPool;
-    return this;
-  }
-  
-  getNumConfirmations() {
-    return this.state.numConfirmations;
-  }
-  
-  setNumConfirmations(numConfirmations) {
-    this.state.numConfirmations = numConfirmations;
-    return this;
-  }
-  
-  getUnlockHeight() {
-    return this.state.unlockHeight;
-  }
-  
-  setUnlockHeight(unlockHeight) {
-    this.state.unlockHeight = unlockHeight;
-    return this;
-  }
-  
-  getLastRelayedTimestamp() {
-    return this.state.lastRelayedTimestamp;
-  }
-  
-  setLastRelayedTimestamp(lastRelayedTimestamp) {
-    this.state.lastRelayedTimestamp = lastRelayedTimestamp;
-    return this;
-  }
-  
-  getReceivedTimestamp() {
-    return this.state.receivedTimestamp;
-  }
-  
-  setReceivedTimestamp(receivedTimestamp) {
-    this.state.receivedTimestamp = receivedTimestamp;
-    return this;
-  }
-  
-  isDoubleSpendSeen() {
-    return this.state.isDoubleSpendSeen;
-  }
-  
-  setIsDoubleSpend(isDoubleSpendSeen) {
-    this.state.isDoubleSpendSeen = isDoubleSpendSeen;
-    return this;
-  }
-  
-  getKey() {
-    return this.state.key;
-  }
-  
-  setKey(key) {
-    this.state.key = key;
-    return this;
-  }
-  
-  /**
-   * Get full transaction hex.  Full hex = pruned hex + prunable hex.
-   * 
-   * @return {string} is full transaction hex
-   */
-  getFullHex() {
-    return this.state.fullHex;
-  }
-  
-  setFullHex(fullHex) {
-    this.state.fullHex = fullHex;
-    return this;
-  }
-  
-  /**
-   * Get pruned transaction hex.  Full hex = pruned hex + prunable hex.
-   * 
-   * @return {string} is pruned transaction hex
-   */
-  getPrunedHex() {
-    return this.state.prunedHex;
-  }
-  
-  setPrunedHex(prunedHex) {
-    this.state.prunedHex = prunedHex;
-    return this;
-  }
-  
-  /**
-   * Get prunable transaction hex which is hex that is removed from a pruned
-   * transaction. Full hex = pruned hex + prunable hex.
-   * 
-   * @return {string} is the prunable transaction hex
-   */
-  getPrunableHex() {
-    return this.state.prunableHex;
-  }
-  
-  setPrunableHex(prunableHex) {
-    this.state.prunableHex = prunableHex;
-    return this;
-  }
-  
-  getPrunableHash() {
-    return this.state.prunableHash;
-  }
-  
-  setPrunableHash(prunableHash) {
-    this.state.prunableHash = prunableHash;
-    return this;
-  }
-  
-  getSize() {
-    return this.state.size;
-  }
-  
-  setSize(size) {
-    this.state.size = size;
-    return this;
-  }
-  
-  getWeight() {
-    return this.state.weight;
-  }
-  
-  setWeight(weight) {
-    this.state.weight = weight;
-    return this;
-  }
-  
-  getInputs() {
-    return this.state.inputs;
-  }
-  
-  setInputs(inputs) {
-    this.state.inputs = inputs;
-    return this;
-  }
-  
-  getOutputs() {
-    return this.state.outputs;
-  }
-  
-  setOutputs(outputs) {
-    this.state.outputs = outputs;
-    return this;
-  }
-  
-  getOutputIndices() {
-    return this.state.outputIndices;
-  }
-  
-  setOutputIndices(outputIndices) {
-    this.state.outputIndices = outputIndices;
-    return this;
-  }
-  
-  getMetadata() {
-    return this.state.metadata;
-  }
-  
-  setMetadata(metadata) {
-    this.state.metadata = metadata;
-    return this;
-  }
-  
-  getExtra() {
-    return this.state.extra;
-  }
-  
-  setExtra(extra) {
-    this.state.extra = extra;
-    return this;
-  }
-
-  getRctSignatures() {
-    return this.state.rctSignatures;
-  }
-  
-  setRctSignatures(rctSignatures) {
-    this.state.rctSignatures = rctSignatures;
-    return this;
-  }
-  
-  getRctSigPrunable() {
-    return this.state.rctSigPrunable;
-  }
-  
-  setRctSigPrunable(rctSigPrunable) {
-    this.state.rctSigPrunable = rctSigPrunable;
-    return this;
-  }
-  
-  isKeptByBlock() {
-    return  this.state.isKeptByBlock;
-  }
-  
-  setIsKeptByBlock(isKeptByBlock) {
-    this.state.isKeptByBlock = isKeptByBlock;
-    return this;
-  }
-  
-  isFailed() {
-    return this.state.isFailed;
-  }
-  
-  setIsFailed(isFailed) {
-    this.state.isFailed = isFailed;
-    return this;
-  }
-  
-  getLastFailedHeight() {
-    return this.state.lastFailedHeight;
-  }
-  
-  setLastFailedHeight(lastFailedHeight) {
-    this.state.lastFailedHeight = lastFailedHeight;
-    return this;
-  }
-  
-  getLastFailedHash() {
-    return this.state.lastFailedHash;
-  }
-  
-  setLastFailedHash(lastFailedHash) {
-    this.state.lastFailedHash = lastFailedHash;
-    return this;
-  }
-  
-  getMaxUsedBlockHeight() {
-    return this.state.maxUsedBlockHeight;
-  }
-  
-  setMaxUsedBlockHeight(maxUsedBlockHeight) {
-    this.state.maxUsedBlockHeight = maxUsedBlockHeight;
-    return this;
-  }
-  
-  getMaxUsedBlockHash() {
-    return this.state.maxUsedBlockHash;
-  }
-  
-  setMaxUsedBlockHash(maxUsedBlockHash) {
-    this.state.maxUsedBlockHash = maxUsedBlockHash;
-    return this;
-  }
-  
-  getSignatures() {
-    return this.state.signatures;
-  }
-  
-  setSignatures(signatures) {
-    this.state.signatures = signatures;
-    return this;
-  }
-  
-  copy() {
-    return new MoneroTx(this);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (this.getFee()) json.fee = this.getFee().toString();
-    if (this.getInputs()) {
-      json.inputs = [];
-      for (let input of this.getInputs()) json.inputs.push(input.toJson());
-    }
-    if (this.getOutputs()) {
-      json.outputs = [];
-      for (let output of this.getOutputs()) json.outputs.push(output.toJson());
-    }
-    if (this.getExtra()) json.extra = this.getExtra().slice();
-    delete json.block;  // do not serialize parent block
-    return json;
-  }
-  
-  /**
-   * Updates this transaction by merging the latest information from the given
-   * transaction.
-   * 
-   * @param tx is the transaction to update this transaction with
-   * @return {MoneroTx} this for method chaining
-   */
-  merge(tx) {
-    assert(tx instanceof MoneroTx);
-    if (this === tx) return this;
-    
-    // merge blocks if they're different which comes back to merging txs
-    const MoneroBlock = require("./MoneroBlock");
-    if (this.getBlock() !== tx.getBlock()) {
-      if (this.getBlock() === undefined) {
-        this.setBlock(new MoneroBlock());
-        this.getBlock().setTxs([this]);
-        this.getBlock().setHeight(tx.getHeight());
-      }
-      if (tx.getBlock() === undefined) {
-        tx.setBlock(new MoneroBlock());
-        tx.getBlock().setTxs([tx]);
-        tx.getBlock().setHeight(this.getHeight());
-      }
-      this.getBlock().merge(tx.getBlock());
-      return this;
-    }
-    
-    // otherwise merge tx fields
-    this.setHash(GenUtils.reconcile(this.getHash(), tx.getHash()));
-    this.setVersion(GenUtils.reconcile(this.getVersion(), tx.getVersion()));
-    this.setPaymentId(GenUtils.reconcile(this.getPaymentId(), tx.getPaymentId()));
-    this.setFee(GenUtils.reconcile(this.getFee(), tx.getFee()));
-    this.setRingSize(GenUtils.reconcile(this.getRingSize(), tx.getRingSize()));
-    this.setIsConfirmed(GenUtils.reconcile(this.isConfirmed(), tx.isConfirmed(), {resolveTrue: true}));
-    this.setIsMinerTx(GenUtils.reconcile(this.isMinerTx(), tx.isMinerTx(), null, null, null));
-    this.setRelay(GenUtils.reconcile(this.getRelay(), tx.getRelay(), {resolveTrue: true}));       // tx can become relayed
-    this.setIsRelayed(GenUtils.reconcile(this.isRelayed(), tx.isRelayed(), {resolveTrue: true})); // tx can become relayed
-    this.setIsDoubleSpend(GenUtils.reconcile(this.isDoubleSpendSeen(), tx.isDoubleSpendSeen()));
-    this.setKey(GenUtils.reconcile(this.getKey(), tx.getKey()));
-    this.setFullHex(GenUtils.reconcile(this.getFullHex(), tx.getFullHex()));
-    this.setPrunedHex(GenUtils.reconcile(this.getPrunedHex(), tx.getPrunedHex()));
-    this.setPrunableHex(GenUtils.reconcile(this.getPrunableHex(), tx.getPrunableHex()));
-    this.setPrunableHash(GenUtils.reconcile(this.getPrunableHash(), tx.getPrunableHash()));
-    this.setSize(GenUtils.reconcile(this.getSize(), tx.getSize()));
-    this.setWeight(GenUtils.reconcile(this.getWeight(), tx.getWeight()));
-    this.setOutputIndices(GenUtils.reconcile(this.getOutputIndices(), tx.getOutputIndices()));
-    this.setMetadata(GenUtils.reconcile(this.getMetadata(), tx.getMetadata()));
-    this.setExtra(GenUtils.reconcile(this.getExtra(), tx.getExtra()));
-    this.setRctSignatures(GenUtils.reconcile(this.getRctSignatures(), tx.getRctSignatures()));
-    this.setRctSigPrunable(GenUtils.reconcile(this.getRctSigPrunable(), tx.getRctSigPrunable()));
-    this.setIsKeptByBlock(GenUtils.reconcile(this.isKeptByBlock(), tx.isKeptByBlock()));
-    this.setIsFailed(GenUtils.reconcile(this.isFailed(), tx.isFailed()));
-    this.setLastFailedHeight(GenUtils.reconcile(this.getLastFailedHeight(), tx.getLastFailedHeight()));
-    this.setLastFailedHash(GenUtils.reconcile(this.getLastFailedHash(), tx.getLastFailedHash()));
-    this.setMaxUsedBlockHeight(GenUtils.reconcile(this.getMaxUsedBlockHeight(), tx.getMaxUsedBlockHeight()));
-    this.setMaxUsedBlockHash(GenUtils.reconcile(this.getMaxUsedBlockHash(), tx.getMaxUsedBlockHash()));
-    this.setSignatures(GenUtils.reconcile(this.getSignatures(), tx.getSignatures()));
-    this.setUnlockHeight(GenUtils.reconcile(this.getUnlockHeight(), tx.getUnlockHeight()));
-    this.setNumConfirmations(GenUtils.reconcile(this.getNumConfirmations(), tx.getNumConfirmations(), {resolveMax: true})); // num confirmations can increase
-    
-    // merge inputs
-    if (tx.getInputs()) {
-      for (let merger of tx.getInputs()) {
-        let merged = false;
-        merger.setTx(this);
-        if (!this.getInputs()) this.setInputs([]);
-        for (let mergee of this.getInputs()) {
-          if (mergee.getKeyImage().getHex() === merger.getKeyImage().getHex()) {
-            mergee.merge(merger);
-            merged = true;
-            break;
-          }
-        }
-        if (!merged) this.getInputs().push(merger);
-      }
-    }
-    
-    // merge outputs
-    if (tx.getOutputs()) {
-      for (let output of tx.getOutputs()) output.setTx(this);
-      if (!this.getOutputs()) this.setOutputs(tx.getOutputs());
-      else {
-        
-        // merge outputs if key image or stealth public key present, otherwise append
-        for (let merger of tx.getOutputs()) {
-          let merged = false;
-          merger.setTx(this);
-          for (let mergee of this.getOutputs()) {
-            if ((merger.getKeyImage() && mergee.getKeyImage().getHex() === merger.getKeyImage().getHex()) ||
-                (merger.getStealthPublicKey() && mergee.getStealthPublicKey() === merger.getStealthPublicKey())) {
-             mergee.merge(merger);
-             merged = true;
-             break;
-            }
-          }
-          if (!merged) this.getOutputs().push(merger); // append output
-        }
-      }
-    }
-    
-    // handle unrelayed -> relayed -> confirmed
-    if (this.isConfirmed()) {
-      this.setInTxPool(false);
-      this.setReceivedTimestamp(undefined);
-      this.setLastRelayedTimestamp(undefined);
-    } else {
-      this.setInTxPool(GenUtils.reconcile(this.inTxPool(), tx.inTxPool(), {resolveTrue: true})); // unrelayed -> tx pool
-      this.setReceivedTimestamp(GenUtils.reconcile(this.getReceivedTimestamp(), tx.getReceivedTimestamp(), {resolveMax: false})); // take earliest receive time
-      this.setLastRelayedTimestamp(GenUtils.reconcile(this.getLastRelayedTimestamp(), tx.getLastRelayedTimestamp(), {resolveMax: true}));  // take latest relay time
-    }
-    
-    return this;  // for chaining
-  }
-  
-  toString(indent = 0) {
-    let str = "";
-    str += GenUtils.getIndent(indent) + "=== TX ===\n";
-    str += GenUtils.kvLine("Tx hash", this.getHash(), indent);
-    str += GenUtils.kvLine("Height", this.getHeight(), indent);
-    str += GenUtils.kvLine("Version", this.getVersion(), indent);
-    str += GenUtils.kvLine("Is miner tx", this.isMinerTx(), indent);
-    str += GenUtils.kvLine("Payment ID", this.getPaymentId(), indent);
-    str += GenUtils.kvLine("Fee", this.getFee(), indent);
-    str += GenUtils.kvLine("Ring size", this.getRingSize(), indent);
-    str += GenUtils.kvLine("Relay", this.getRelay(), indent);
-    str += GenUtils.kvLine("Is relayed", this.isRelayed(), indent);
-    str += GenUtils.kvLine("Is confirmed", this.isConfirmed(), indent);
-    str += GenUtils.kvLine("In tx pool", this.inTxPool(), indent);
-    str += GenUtils.kvLine("Num confirmations", this.getNumConfirmations(), indent);
-    str += GenUtils.kvLine("Unlock height", this.getUnlockHeight(), indent);
-    str += GenUtils.kvLine("Last relayed time", this.getLastRelayedTimestamp(), indent);
-    str += GenUtils.kvLine("Received time", this.getReceivedTimestamp(), indent);
-    str += GenUtils.kvLine("Is double spend", this.isDoubleSpendSeen(), indent);
-    str += GenUtils.kvLine("Key", this.getKey(), indent);
-    str += GenUtils.kvLine("Full hex", this.getFullHex(), indent);
-    str += GenUtils.kvLine("Pruned hex", this.getPrunedHex(), indent);
-    str += GenUtils.kvLine("Prunable hex", this.getPrunableHex(), indent);
-    str += GenUtils.kvLine("Prunable hash", this.getPrunableHash(), indent);
-    str += GenUtils.kvLine("Size", this.getSize(), indent);
-    str += GenUtils.kvLine("Weight", this.getWeight(), indent);
-    str += GenUtils.kvLine("Output indices", this.getOutputIndices(), indent);
-    str += GenUtils.kvLine("Metadata", this.getMetadata(), indent);
-    str += GenUtils.kvLine("Extra", this.getExtra(), indent);
-    str += GenUtils.kvLine("RCT signatures", this.getRctSignatures(), indent);
-    str += GenUtils.kvLine("RCT sig prunable", this.getRctSigPrunable(), indent);
-    str += GenUtils.kvLine("Kept by block", this.isKeptByBlock(), indent);
-    str += GenUtils.kvLine("Is failed", this.isFailed(), indent);
-    str += GenUtils.kvLine("Last failed height", this.getLastFailedHeight(), indent);
-    str += GenUtils.kvLine("Last failed hash", this.getLastFailedHash(), indent);
-    str += GenUtils.kvLine("Max used block height", this.getMaxUsedBlockHeight(), indent);
-    str += GenUtils.kvLine("Max used block hash", this.getMaxUsedBlockHash(), indent);
-    str += GenUtils.kvLine("Signatures", this.getSignatures(), indent);
-    if (this.getInputs()) {
-      str += GenUtils.kvLine("Inputs", "", indent);
-      for (let i = 0; i < this.getInputs().length; i++) {
-        str += GenUtils.kvLine(i + 1, "", indent + 1);
-        str += this.getInputs()[i].toString(indent + 2);
-        str += '\n'
-      }
-    }
-    if (this.getOutputs()) {
-      str += GenUtils.kvLine("Outputs", "", indent);
-      for (let i = 0; i < this.getOutputs().length; i++) {
-        str += GenUtils.kvLine(i + 1, "", indent + 1);
-        str += this.getOutputs()[i].toString(indent + 2);
-        str += '\n'
-      }
-    }
-    return str.slice(0, str.length - 1);  // strip last newline
-  }
-}
-
-// default payment id
-MoneroTx.DEFAULT_PAYMENT_ID = "0000000000000000";
-
-module.exports = MoneroTx;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroTxPoolStats.js.html b/docs/src_main_js_daemon_model_MoneroTxPoolStats.js.html deleted file mode 100644 index 822599297..000000000 --- a/docs/src_main_js_daemon_model_MoneroTxPoolStats.js.html +++ /dev/null @@ -1,188 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroTxPoolStats.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroTxPoolStats.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-
-/**
- * Models transaction pool statistics.
- */
-class MoneroTxPoolStats {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-    if (this.state.feeTotal !== undefined && !(this.state.feeTotal instanceof BigInteger)) this.state.feeTotal = BigInteger.parse(this.state.feeTotal);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (json.feeTotal) json.feeTotal = json.feeTotal.toString();
-    return json;
-  }
-  
-  getNumTxs() {
-    return this.state.numTxs;
-  }
-  
-  setNumTxs(numTxs) {
-    this.state.numTxs = numTxs;
-    return this;
-  }
-  
-  getNumNotRelayed() {
-    return this.state.numNotRelayed;
-  }
-  
-  setNumNotRelayed(numNotRelayed) {
-    this.state.numNotRelayed = numNotRelayed;
-    return this;
-  }
-  
-  getNumFailing() {
-    return this.state.numFailing;
-  }
-  
-  setNumFailing(numFailing) {
-    this.state.numFailing = numFailing;
-    return this;
-  }
-  
-  getNumDoubleSpends() {
-    return this.state.numDoubleSpends;
-  }
-  
-  setNumDoubleSpends(numDoubleSpends) {
-    this.state.numDoubleSpends = numDoubleSpends;
-    return this;
-  }
-  
-  getNum10m() {
-    return this.state.num10m;
-  }
-  
-  setNum10m(num10m) {
-    this.state.num10m = num10m;
-    return this;
-  }
-  
-  getFeeTotal() {
-    return this.state.feeTotal;
-  }
-  
-  setFeeTotal(feeTotal) {
-    this.state.feeTotal = feeTotal;
-    return this;
-  }
-  
-  getBytesMax() {
-    return this.state.bytesMax;
-  }
-  
-  setBytesMax(bytesMax) {
-    this.state.bytesMax = bytesMax;
-    return this;
-  }
-  
-  getBytesMed() {
-    return this.state.bytesMed;
-  }
-  
-  setBytesMed(bytesMed) {
-    this.state.bytesMed = bytesMed;
-    return this;
-  }
-  
-  getBytesMin() {
-    return this.state.bytesMin;
-  }
-  
-  setBytesMin(bytesMin) {
-    this.state.bytesMin = bytesMin;
-    return this;
-  }
-  
-  getBytesTotal() {
-    return this.state.bytesTotal;
-  }
-  
-  setBytesTotal(bytesTotal) {
-    this.state.bytesTotal = bytesTotal;
-    return this;
-  }
-  
-  // TODO: histo... what?
-  getHisto() {
-    return this.state.histo;
-  }
-  
-  setHisto(histo) {
-    this.state.histo = histo;
-    return this;
-  }
-  
-  getHisto98pc() {
-    return this.state.histo98pc;
-  }
-  
-  setHisto98pc(histo98pc) {
-    this.state.histo98pc = histo98pc;
-    return this;
-  }
-  
-  getOldestTimestamp() {
-    return this.state.oldestTimestamp;
-  }
-  
-  setOldestTimestamp(oldestTimestamp) {
-    this.state.oldestTimestamp = oldestTimestamp;
-    return this;
-  }
-}
-
-module.exports = MoneroTxPoolStats;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_daemon_model_MoneroVersion.js.html b/docs/src_main_js_daemon_model_MoneroVersion.js.html deleted file mode 100644 index c5f4f5bcf..000000000 --- a/docs/src_main_js_daemon_model_MoneroVersion.js.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - JSDoc: Source: src/main/js/daemon/model/MoneroVersion.js - - - - - - - - - - -
- -

Source: src/main/js/daemon/model/MoneroVersion.js

- - - - - - -
-
-
/**
- * Models a Monero version.
- */
-class MoneroVersion {
-  
-  /**
-   * Construct the model.
-   * 
-   * @param number is the version number
-   * @param isRelease indicates if this version is a release
-   */
-  constructor(number, isRelease) {
-    this.state = {};
-    this.state.number = number;
-    this.state.isRelease = isRelease;
-  }
-
-  getNumber() {
-    return this.state.number;
-  }
-
-  setNumber(number) {
-    this.state.number = number;
-    return this;
-  }
-
-  isRelease() {
-    return this.state.isRelease;
-  }
-
-  setIsRelease(isRelease) {
-    this.state.isRelease = isRelease;
-    return this;
-  }
-  
-  copy() {
-    return new MoneroKeyImage(this);
-  }
-  
-  toJson() {
-    return Object.assign({}, this.state);
-  }
-}
-
-module.exports = MoneroVersion;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_MoneroWallet.js.html b/docs/src_main_js_wallet_MoneroWallet.js.html deleted file mode 100644 index bff3b10ec..000000000 --- a/docs/src_main_js_wallet_MoneroWallet.js.html +++ /dev/null @@ -1,1272 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/MoneroWallet.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/MoneroWallet.js

- - - - - - -
-
-
const assert = require("assert");
-const MoneroBlock = require("../daemon/model/MoneroBlock");
-const MoneroError = require("../common/MoneroError");
-const MoneroOutputQuery = require("./model/MoneroOutputQuery");
-const MoneroTransferQuery = require("./model/MoneroTransferQuery");
-const MoneroTxConfig = require("./model/MoneroTxConfig");
-const MoneroTxQuery = require("./model/MoneroTxQuery");
-
-/**
- * Copyright (c) woodser
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/**
- * Monero wallet interface and default implementations.
- * 
- * @interface
- */
-class MoneroWallet {
-  
-  /**
-   * Indicates if the wallet is view-only, meaning it does have the private
-   * spend key and can therefore only observe incoming outputs.
-   * 
-   * @return {bool} true if the wallet is view-only, false otherwise
-   */
-  async isViewOnly() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Set the wallet's daemon connection.
-   * 
-   * @param {string|MoneroRpcConnection} uriOrConnection - daemon's URI or connection (defaults to offline)
-   * @param {string} username - username to authenticate with the daemon (optional)
-   * @param {string} password - password to authenticate with the daemon (optional)
-   */
-  async setDaemonConnection(uriOrConnection, username, password) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the wallet's daemon connection.
-   * 
-   * @return {MoneroRpcConnection} the wallet's daemon connection
-   */
-  async getDaemonConnection() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Indicates if the wallet is connected to daemon.
-   * 
-   * @return {boolean} true if the wallet is connected to a daemon, false otherwise
-   */
-  async isConnected() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Gets the version of the wallet.
-   * 
-   * @return {MoneroVersion} the version of the wallet
-   */
-  async getVersion() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the wallet's path.
-   * 
-   * @return {string} the path the wallet can be opened with
-   */
-  async getPath() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the wallet's mnemonic phrase derived from the seed.
-   * 
-   * @return {string} the wallet's mnemonic phrase
-   */
-  async getMnemonic() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the language of the wallet's mnemonic phrase.
-   * 
-   * @return {string} the language of the wallet's mnemonic phrase
-   */
-  async getMnemonicLanguage() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the wallet's private view key.
-   * 
-   * @return {string} the wallet's private view key
-   */
-  async getPrivateViewKey() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the wallet's private spend key.
-   * 
-   * @return {string} the wallet's private spend key
-   */
-  async getPrivateSpendKey() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the wallet's public view key.
-   * 
-   * @return {string} the wallet's public view key
-   */
-  async getPublicViewKey() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the wallet's public spend key.
-   * 
-   * @return {string} the wallet's public spend key
-   */
-  async getPublicSpendKey() {
-    throw new MoneroError("Not supported");
-  }
-    
-  /**
-   * Get the wallet's primary address.
-   * 
-   * @return {string} the wallet's primary address
-   */
-  async getPrimaryAddress() {
-    return await this.getAddress(0, 0);
-  }
-  
-  /**
-   * Get the address of a specific subaddress.
-   * 
-   * @param {int} accountIdx - the account index of the address's subaddress
-   * @param {int} subaddressIdx - the subaddress index within the account
-   * @return {string} the receive address of the specified subaddress
-   */
-  async getAddress(accountIdx, subaddressIdx) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the account and subaddress index of the given address.
-   * 
-   * @param {string} address - address to get the account and subaddress index from
-   * @return {MoneroSubaddress} the account and subaddress indices
-   */
-  async getAddressIndex(address) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get an integrated address based on this wallet's primary address and the
-   * given payment ID.  Generates a random payment ID if none is given.
-   * 
-   * @param {string} paymentId - payment ID to generate an integrated address from (randomly generated if undefined)
-   * @return {MoneroIntegratedAddress} the integrated address
-   */
-  async getIntegratedAddress(paymentId) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Decode an integrated address to get its standard address and payment id.
-   * 
-   * @param {string} integratedAddress - integrated address to decode
-   * @return {MoneroIntegratedAddress} the decoded integrated address including standard address and payment id
-   */
-  async decodeIntegratedAddress(integratedAddress) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the height of the last block processed by the wallet (its index + 1).
-   * 
-   * @return {int} the height of the last block processed by the wallet
-   */
-  async getHeight() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the blockchain's height.
-   * 
-   * @return {int} the blockchain's height
-   */
-  async getDaemonHeight() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the blockchain's height by date as a conservative estimate for scanning.
-   * 
-   * @param {int} year - year of the height to get
-   * @param {int} month - month of the height to get as a number between 1 and 12
-   * @param {int} day - day of the height to get as a number between 1 and 31
-   * @return the blockchain's approximate height at the given date
-   */
-  async getHeightByDate(year, month, day) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Synchronize the wallet with the daemon as a one-time synchronous process.
-   * 
-   * @param {MoneroWalletListener|number} listenerOrStartHeight - listener xor start height (defaults to no sync listener, the last synced block)
-   * @param {number} startHeight - startHeight if not given in first arg (defaults to last synced block)
-   */
-  async sync(listenerOrStartHeight, startHeight) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Start an asynchronous thread to continuously synchronize the wallet with the daemon.
-   */
-  async startSyncing() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Stop synchronizing the wallet with the daemon.
-   */
-  async stopSyncing() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * <p>Rescan the blockchain for spent outputs.</p>
-   * 
-   * <p>Note: this can only be called with a trusted daemon.</p>
-   * 
-   * <p>Example use case: peer multisig hex is import when connected to an untrusted daemon,
-   * so the wallet will not rescan spent outputs.  Then the wallet connects to a trusted
-   * daemon.  This method should be manually invoked to rescan outputs.</p>
-   */
-  async rescanSpent() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * <p>Rescan the blockchain from scratch, losing any information which cannot be recovered from
-   * the blockchain itself.</p>
-   * 
-   * <p>WARNING: This method discards local wallet data like destination addresses, tx secret keys,
-   * tx notes, etc.</p>
-   */
-  async rescanBlockchain() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the balance of the wallet, account, or subaddress.
-   * 
-   * @param {int} accountIdx - index of the account to get the balance of (optional)
-   * @param {int} subaddressIdx - index of the subaddress to get the balance of (optional)
-   * @return {BigInteger} the balance of the wallet, account, or subaddress
-   */
-  async getBalance(accountIdx, subaddressIdx) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get the unlocked balance of the wallet, account, or subaddress.
-   * 
-   * @param {int} accountIdx - index of the account to get the unlocked balance of (optional)
-   * @param {int} subaddressIdx - index of the subaddress to get the unlocked balance of (optional)
-   * @return {BigInteger} the unlocked balance of the wallet, account, or subaddress
-   */
-  async getUnlockedBalance(accountIdx, subaddressIdx) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get accounts with a given tag.
-   * 
-   * @param {boolean} includeSubaddresses - include subaddresses if true
-   * @param {string} tag - tag for filtering accounts, all accounts if undefined
-   * @return {MoneroAccount[]} all accounts with the given tag
-   */
-  async getAccounts(includeSubaddresses, tag) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get an account.
-   * 
-   * @param {int} accountIdx - index of the account to get
-   * @param {boolean} includeSubaddresses - include subaddresses if true
-   * @return {MoneroAccount} the retrieved account
-   */
-  async getAccount(accountIdx, includeSubaddresses) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Create a new account with a label for the first subaddress.
-   * 
-   * @param {string} label - label for account's first subaddress (optional)
-   * @return {MoneroAccount} the created account
-   */
-  async createAccount(label) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get subaddresses in an account.
-   * 
-   * @param {int} accountIdx - account to get subaddresses within
-   * @param {int[]} subaddressIndices - indices of subaddresses to get (optional)
-   * @return {MoneroSubaddress[]} the retrieved subaddresses
-   */
-  async getSubaddresses(accountIdx, subaddressIndices) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get a subaddress.
-   * 
-   * @param {int} accountIdx - index of the subaddress's account
-   * @param {int} subaddressIdx - index of the subaddress within the account
-   * @return {MoneroSubaddress} the retrieved subaddress
-   */
-  async getSubaddress(accountIdx, subaddressIdx) {
-    assert(accountIdx >= 0);
-    assert(subaddressIdx >= 0);
-    return (await this.getSubaddresses(accountIdx, subaddressIdx))[0];
-  }
-  
-  /**
-   * Create a subaddress within an account.
-   * 
-   * @param {int} accountIdx - index of the account to create the subaddress within
-   * @param {string} label - the label for the subaddress (optional)
-   * @return {MoneroSubaddress} the created subaddress
-   */
-  async createSubaddress(accountIdx, label) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get a wallet transaction by hash.
-   * 
-   * @param {string} txHash - hash of a transaction to get
-   * @return {MoneroTxWallet} the identified transactions
-   */
-  async getTx(txHash) {
-    return (await this.getTxs([txHash]))[0];
-  }
-  
-  /**
-   * <p>Get wallet transactions.  Wallet transactions contain one or more
-   * transfers that are either incoming or outgoing to the wallet.<p>
-   * 
-   * <p>Results can be filtered by passing a query object.  Transactions must
-   * meet every criteria defined in the query in order to be returned.  All
-   * criteria are optional and no filtering is applied when not defined.</p>
-   * 
-   * @param {(MoneroTxQuery|string[]|object)} query - configures the query (optional)
-   * @param {boolean} query.isConfirmed - get txs that are confirmed or not (optional)
-   * @param {boolean} query.inTxPool - get txs that are in the tx pool or not (optional)
-   * @param {boolean} query.isRelayed - get txs that are relayed or not (optional)
-   * @param {boolean} query.isFailed - get txs that are failed or not (optional)
-   * @param {boolean} query.isMinerTx - get miner txs or not (optional)
-   * @param {string} query.hash - get a tx with the hash (optional)
-   * @param {string[]} query.hashes - get txs with the hashes (optional)
-   * @param {string} query.paymentId - get transactions with the payment id (optional)
-   * @param {string[]} query.paymentIds - get transactions with the payment ids (optional)
-   * @param {boolean} query.hasPaymentId - get transactions with a payment id or not (optional)
-   * @param {int} query.minHeight - get txs with height >= the given height (optional)
-   * @param {int} query.maxHeight - get txs with height <= the given height (optional)
-   * @param {boolean} query.isOutgoing - get txs with an outgoing transfer or not (optional)
-   * @param {boolean} query.isIncoming - get txs with an incoming transfer or not (optional)
-   * @param {MoneroTransferQuery} query.transferQuery - get txs that have a transfer that meets this query (optional)
-   * @param {boolean} query.includeOutputs - specifies that tx outputs should be returned with tx results (optional)
-   * @param {string[]} missingTxHashes - populated with hashes of unfound or unmet transactions that were queried by hash (throws error if undefined and queried transaction hashes are unfound or unmet) 
-   * @return {MoneroTxWallet[]} wallet transactions per the configuration
-   */
-  async getTxs(query, missingTxHashes) {
-    throw new MoneroError("Not supported");
-  }
-
-  /**
-   * <p>Get incoming and outgoing transfers to and from this wallet.  An outgoing
-   * transfer represents a total amount sent from one or more subaddresses
-   * within an account to individual destination addresses, each with their
-   * own amount.  An incoming transfer represents a total amount received into
-   * a subaddress within an account.  Transfers belong to transactions which
-   * are stored on the blockchain.</p>
-   * 
-   * <p>Results can be filtered by passing a query object.  Transfers must
-   * meet every criteria defined in the query in order to be returned.  All
-   * criteria are optional and no filtering is applied when not defined.</p>
-   * 
-   * @param {(MoneroTransferQuery|object)} query - configures the query (optional)
-   * @param {boolean} query.isOutgoing - get transfers that are outgoing or not (optional)
-   * @param {boolean} query.isIncoming - get transfers that are incoming or not (optional)
-   * @param {string} query.address - wallet's address that a transfer either originated from (if outgoing) or is destined for (if incoming) (optional)
-   * @param {int} query.accountIndex - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific account index (optional)
-   * @param {int} query.subaddressIndex - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific subaddress index (optional)
-   * @param {int[]} query.subaddressIndices - get transfers that either originated from (if outgoing) or are destined for (if incoming) specific subaddress indices (optional)
-   * @param {BigInteger} query.amount - amount being transferred (optional)
-   * @param {MoneroDestination[]} query.destinations - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional)
-   * @param {boolean} query.hasDestinations - get transfers that have destinations or not (optional)
-   * @param {MoneroTxQuery} query.txQuery - get transfers whose transaction meets this query (optional)
-   * @return {MoneroTransfer[]} are wallet transfers per the configuration
-   */
-  async getTransfers(query) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get all of the wallet's incoming transfers.
-   * 
-   * @param query - passed to getTransfers() with isIncoming=true
-   * @return {MoneroIncomingTransfer[]} the wallet's incoming transfers
-   */
-  async getIncomingTransfers(query) {
-    
-    // copy query and set direction
-    let _query;
-    if (query === undefined) _query = new MoneroTransferQuery();
-    else {
-      if (query.isIncoming() === false) throw new MoneroError("Transfer query contradicts getting incoming transfers");
-      _query = query.copy();
-    }
-    _query.setIsIncoming(true);
-    
-    // fetch and cast transfers
-    let inTransfers = [];
-    for (let transfer of await this.getTransfers(_query)) {
-      inTransfers.push(transfer);
-    }
-    return inTransfers;
-  }
-  
-  /**
-   * Get all of the wallet's outgoing transfers.
-   * 
-   * @param query - passed to getTransfers() with isOutgoing=true
-   * @return {MoneroOutgoingTransfer[]} the wallet's outgoing transfers
-   */
-  async getOutgoingTransfers(query) {
-    
-    // copy query and set direction
-    let _query;
-    if (query === undefined) _query = new MoneroTransferQuery();
-    else {
-      if (query.isOutgoing() === false) throw new MoneroError("Transfer query contradicts getting outgoing transfers");
-      _query = query.copy();
-    }
-    _query.setIsOutgoing(true);
-    
-    // fetch and cast transfers
-    let outTransfers = [];
-    for (let transfer of await this.getTransfers(_query)) {
-      outTransfers.push(transfer);
-    }
-    return outTransfers;
-  }
-  
-  /**
-   * <p>Get outputs created from previous transactions that belong to the wallet
-   * (i.e. that the wallet can spend one time).  Outputs are part of
-   * transactions which are stored in blocks on the blockchain.</p>
-   * 
-   * <p>Results can be filtered by passing a query object.  Outputs must
-   * meet every criteria defined in the query in order to be returned.  All
-   * filtering is optional and no filtering is applied when not defined.</p>
-   * 
-   * @param {(MoneroOutputQuery|object)} query - configures the query (optional)
-   * @param {int} query.accountIndex - get outputs associated with a specific account index (optional)
-   * @param {int} query.subaddressIndex - get outputs associated with a specific subaddress index (optional)
-   * @param {int[]} query.subaddressIndices - get outputs associated with specific subaddress indices (optional)
-   * @param {BigInteger} query.amount - get outputs with a specific amount (optional)
-   * @param {BigInteger} query.minAmount - get outputs greater than or equal to a minimum amount (optional)
-   * @param {BigInteger} query.maxAmount - get outputs less than or equal to a maximum amount (optional)
-   * @param {boolean} query.isSpent - get outputs that are spent or not (optional)
-   * @param {string|MoneroKeyImage} query.keyImage - get output with a key image or which matches fields defined in a MoneroKeyImage (optional)
-   * @param {MoneroTxQuery} query.txQuery - get outputs whose transaction meets this filter (optional)
-   * @return {MoneroOutputWallet[]} are queried outputs
-   */
-  async getOutputs(query) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Export all outputs in hex format.
-   * 
-   * @return {string} all outputs in hex format, undefined if no outputs
-   */
-  async getOutputsHex() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Import outputs in hex format.
-   * 
-   * @param {string} outputsHex - outputs in hex format
-   * @return {int} the number of outputs imported
-   */
-  async importOutputsHex(outputsHex) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get all signed key images.
-   * 
-   * @return {MoneroKeyImage[]} the wallet's signed key images
-   */
-  async getKeyImages() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Import signed key images and verify their spent status.
-   * 
-   * @param {MoneroKeyImage[]} keyImages -  images to import and verify (requires hex and signature)
-   * @return {MoneroKeyImageImportResult} results of the import
-   */
-  async importKeyImages(keyImages) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get new key images from the last imported outputs.
-   * 
-   * @return {MoneroKeyImage[]} the key images from the last imported outputs
-   */
-  async getNewKeyImagesFromLastImport() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Create a transaction to transfer funds from this wallet.
-   * 
-   * @param {MoneroTxConfig|object} config - configures the transaction to create (required)
-   * @param {string} config.address - single destination address (required unless `destinations` provided)
-   * @param {BigInteger|string} config.amount - single destination amount (required unless `destinations` provided)
-   * @param {int} config.accountIndex - source account index to transfer funds from (required)
-   * @param {int} config.subaddressIndex - source subaddress index to transfer funds from (optional)
-   * @param {int[]} config.subaddressIndices - source subaddress indices to transfer funds from (optional)
-   * @param {boolean} config.relay - relay the transaction to peers to commit to the blockchain (default false)
-   * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL)
-   * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided)
-   * @param {string} config.paymentId - transaction payment ID (optional)
-   * @param {int} config.unlockHeight - minimum height for the transaction to unlock (default 0)
-   * @return {MoneroTxWallet} the created transaction
-   */
-  async createTx(config) {
-    config = MoneroWallet._normalizeCreateTxsConfig(config);
-    if (config.getCanSplit() !== undefined) assert.equal(config.getCanSplit(), false, "Cannot split transactions using createTx(); use createTxs()");
-    config.setCanSplit(false);
-    return (await this.createTxs(config))[0];
-  }
-  
-  /**
-   * Create one or more transactions to transfer funds from this wallet.
-   * 
-   * @param {MoneroTxConfig|object} config - configures the transactions to create (required)
-   * @param {string} config.address - single destination address (required unless `destinations` provided)
-   * @param {BigInteger|string} config.amount - single destination amount (required unless `destinations` provided)
-   * @param {int} config.accountIndex - source account index to transfer funds from (required)
-   * @param {int} config.subaddressIndex - source subaddress index to transfer funds from (optional)
-   * @param {int[]} config.subaddressIndices - source subaddress indices to transfer funds from (optional)
-   * @param {boolean} config.relay - relay the transactions to peers to commit to the blockchain (default false)
-   * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL)
-   * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided)
-   * @param {string} config.paymentId - transaction payment ID (optional)
-   * @param {int} config.unlockHeight - minimum height for the transactions to unlock (default 0)
-   * @param {boolean} config.canSplit - allow funds to be transferred using multiple transactions (default true)
-   * @return {MoneroTxWallet[]} the created transactions
-   */
-  async createTxs(config) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Sweep an output by key image.
-   * 
-   * @param {MoneroTxConfig} config - configures the transaction to create (required)
-   * @param {string} config.address - single destination address (required)
-   * @param {string} config.keyImage - key image to sweep (required)
-   * @param {boolean} config.relay - relay the transaction to peers to commit to the blockchain (default false)
-   * @param {int} config.unlockHeight - minimum height for the transaction to unlock (default 0)
-   * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL)
-   * @return {MoneroTxWallet} the created transaction
-   */
-  async sweepOutput(config) {
-    throw new MoneroError("Not supported");
-  }
-
-  /**
-   * Sweep all unlocked funds according to the given configuration.
-   * 
-   * @param {MoneroTxConfig|object} config - configures the transactions to create (required)
-   * @param {string} config.address - single destination address (required)
-   * @param {int} config.accountIndex - source account index to sweep from from (required)
-   * @param {int} config.subaddressIndex - source subaddress index to sweep from (optional)
-   * @param {int[]} config.subaddressIndices - source subaddress indices to sweep from (optional)
-   * @param {boolean} config.relay - relay the transactions to peers to commit to the blockchain (default false)
-   * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL)
-   * @param {int} config.unlockHeight - minimum height for the transactions to unlock (default 0)
-   * @return {MoneroTxWallet[]} the created transactions
-   */
-  async sweepUnlocked(config) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * <p>Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.</p>
-   * 
-   * <p>NOTE: Dust only exists pre RCT, so this method will throw "no dust to sweep" on new wallets.</p>
-   * 
-   * @param {boolean} relay - specifies if the resulting transaction should be relayed (default false)
-   * @return {MoneroTxWallet[]} the created transactions
-   */
-  async sweepDust(relay) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Relay a previously created transaction.
-   * 
-   * @param {(MoneroTxWallet|string)} txOrMetadata - transaction or its metadata to relay
-   * @return {string} the hash of the relayed tx
-   */
-  async relayTx(txOrMetadata) {
-    return (await this.relayTxs([txOrMetadata]))[0];
-  }
-  
-  /**
-   * Relay previously created transactions.
-   * 
-   * @param {(MoneroTxWallet[]|string[])} txsOrMetadatas - transactions or their metadata to relay
-   * @return {string[]} the hashes of the relayed txs
-   */
-  async relayTxs(txsOrMetadatas) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Parse a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions.
-   * 
-   * @param {MoneroTxSet} txSet - a tx set containing unsigned or multisig tx hex
-   * @return {MoneroTxSet} the parsed tx set containing structured transactions
-   */
-  async parseTxSet(txSet) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Sign unsigned transactions from a view-only wallet.
-   * 
-   * @param {string} unsignedTxHex - unsigned transaction hex from when the transactions were created
-   * @return {string} the signed transaction hex
-   */
-  async signTxs(unsignedTxHex) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Submit signed transactions from a view-only wallet.
-   * 
-   * @param {string} signedTxHex - signed transaction hex from signTxs()
-   * @return {string[]} the resulting transaction hashes
-   */
-  async submitTxs(signedTxHex) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Sign a message.
-   * 
-   * @param {string} msg - message to sign
-   * @return {string} the signature
-   */
-  async signMessage(message) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Verify a signature on a message.
-   * 
-   * @param {string} msg - signed message
-   * @param {string} address - signing address
-   * @param {string} signature - signature
-   * @return {boolean} true if the signature is good, false otherwise
-   */
-  async verifyMessage(message, address, signature) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get a transaction's secret key from its hash.
-   * 
-   * @param {string} txHash - transaction's hash
-   * @return {string} - transaction's secret key
-   */
-  async getTxKey(txHash) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Check a transaction in the blockchain with its secret key.
-   * 
-   * @param {string} txHash - transaction to check
-   * @param {string} txKey - transaction's secret key
-   * @param {string} address - destination public address of the transaction
-   * @return {MoneroCheckTx} the result of the check
-   */
-  async checkTxKey(txHash, txKey, address) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get a transaction signature to prove it.
-   * 
-   * @param {string} txHash - transaction to prove
-   * @param {string} address - destination public address of the transaction
-   * @param {string} message - message to include with the signature to further authenticate the proof (optional)
-   * @return {string} the transaction signature
-   */
-  async getTxProof(txHash, address, message) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Prove a transaction by checking its signature.
-   * 
-   * @param {string} txHash - transaction to prove
-   * @param {string} address - destination public address of the transaction
-   * @param {string} message - message included with the signature to further authenticate the proof (optional)
-   * @param {string} signature - transaction signature to confirm
-   * @return {MoneroCheckTx} the result of the check
-   */
-  async checkTxProof(txHash, address, message, signature) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address.
-   * 
-   * @param {string} txHash - transaction to prove
-   * @param {string} message - message to include with the signature to further authenticate the proof (optional)
-   * @return {string} the transaction signature
-   */
-  async getSpendProof(txHash, message) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address.
-   * 
-   * @param {string} txHash - transaction to prove
-   * @param {string} message - message included with the signature to further authenticate the proof (optional)
-   * @param {string} signature - transaction signature to confirm
-   * @return {boolean} true if the signature is good, false otherwise
-   */
-  async checkSpendProof(txHash, message, signature) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Generate a signature to prove the entire balance of the wallet.
-   * 
-   * @param message - message included with the signature to further authenticate the proof (optional)
-   * @return the reserve proof signature
-   */
-  async getReserveProofWallet(message) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Generate a signature to prove an available amount in an account.
-   * 
-   * @param {int} accountIdx - account to prove ownership of the amount
-   * @param {BigInteger} amount - minimum amount to prove as available in the account
-   * @param {string} message - message to include with the signature to further authenticate the proof (optional)
-   * @return {string} the reserve proof signature
-   */
-  async getReserveProofAccount(accountIdx, amount, message) {
-    throw new MoneroError("Not supported");
-  }
-
-  /**
-   * Proves a wallet has a disposable reserve using a signature.
-   * 
-   * @param {string} address - public wallet address
-   * @param {string} message - message included with the signature to further authenticate the proof (optional)
-   * @param {string} signature - reserve proof signature to check
-   * @return {MoneroCheckReserve} the result of checking the signature proof
-   */
-  async checkReserveProof(address, message, signature) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get a transaction note.
-   * 
-   * @param {string} txHash - transaction to get the note of
-   * @return {string} the tx note
-   */
-  async getTxNote(txHash) {
-    return (await this.getTxNotes([txHash]))[0];
-  }
-  
-  /**
-   * Get notes for multiple transactions.
-   * 
-   * @param {string[]} txHashes - hashes of the transactions to get notes for
-   * @return {string[]} notes for the transactions
-   */
-  async getTxNotes(txHashes) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Set a note for a specific transaction.
-   * 
-   * @param {string} txHash - hash of the transaction to set a note for
-   * @param {string} note - the transaction note
-   */
-  async setTxNote(txHash, note) {
-    await this.setTxNotes([txHash], [note]);
-  }
-  
-  /**
-   * Set notes for multiple transactions.
-   * 
-   * @param {string[]} txHashes - transactions to set notes for
-   * @param {string[]} notes - notes to set for the transactions
-   */
-  async setTxNotes(txHashes, notes) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get address book entries.
-   * 
-   * @param {int[]} entryIndices - indices of the entries to get
-   * @return {MoneroAddressBookEntry[]} the address book entries
-   */
-  async getAddressBookEntries(entryIndices) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Add an address book entry.
-   * 
-   * @param {string} address - entry address
-   * @param {string} description - entry description (optional)
-   * @return {int} the index of the added entry
-   */
-  async addAddressBookEntry(address, description) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Edit an address book entry.
-   * 
-   * @param {number} index - index of the address book entry to edit
-   * @param {boolean} setAddress - specifies if the address should be updated
-   * @param {string} address - updated address
-   * @param {boolean} setDescription - specifies if the description should be updated
-   * @param {string} description - updated description
-   */
-  async editAddressBookEntry(index, setAddress, address, setDescription, description) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Delete an address book entry.
-   * 
-   * @param {int} entryIdx - index of the entry to delete
-   */
-  async deleteAddressBookEntry(entryIdx) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Tag accounts.
-   * 
-   * @param {string} tag - tag to apply to the specified accounts
-   * @param {int[]} accountIndices - indices of the accounts to tag
-   */
-  async tagAccounts(tag, accountIndices) {
-    throw new MoneroError("Not supported");
-  }
-
-  /**
-   * Untag accounts.
-   * 
-   * @param {int[]} accountIndices - indices of the accounts to untag
-   */
-  async untagAccounts(accountIndices) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Return all account tags.
-   * 
-   * @return {MoneroAccountTag[]} the wallet's account tags
-   */
-  async getAccountTags() {
-    throw new MoneroError("Not supported");
-  }
-
-  /**
-   * Sets a human-readable description for a tag.
-   * 
-   * @param {string} tag - tag to set a description for
-   * @param {string} label - label to set for the tag
-   */
-  async setAccountTagLabel(tag, label) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Creates a payment URI from a send configuration.
-   * 
-   * @param {MoneroTxConfig} config - specifies configuration for a potential tx
-   * @return {string} the payment uri
-   */
-  async createPaymentUri(config) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Parses a payment URI to a tx config.
-   * 
-   * @param {string} uri - payment uri to parse
-   * @return {MoneroTxConfig} the send configuration parsed from the uri
-   */
-  async parsePaymentUri(uri) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get an attribute.
-   * 
-   * @param {string} key - attribute to get the value of
-   * @return {string} the attribute's value
-   */
-  async getAttribute(key) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Set an arbitrary attribute.
-   * 
-   * @param {string} key - attribute key
-   * @param {string} val - attribute value
-   */
-  async setAttribute(key, val) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Start mining.
-   * 
-   * @param {int} numThreads - number of threads created for mining (optional)
-   * @param {boolean} backgroundMining - specifies if mining should occur in the background (optional)
-   * @param {boolean} ignoreBattery - specifies if the battery should be ignored for mining (optional)
-   */
-  async startMining(numThreads, backgroundMining, ignoreBattery) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Stop mining.
-   */
-  async stopMining() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Indicates if importing multisig data is needed for returning a correct balance.
-   * 
-   * @return {boolean} true if importing multisig data is needed for returning a correct balance, false otherwise
-   */
-  async isMultisigImportNeeded() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Indicates if this wallet is a multisig wallet.
-   * 
-   * @return {boolean} true if this is a multisig wallet, false otherwise
-   */
-  async isMultisig() {
-    return (await this.getMultisigInfo()).isMultisig();
-  }
-  
-  /**
-   * Get multisig info about this wallet.
-   * 
-   * @return {MoneroMultisigInfo} multisig info about this wallet
-   */
-  async getMultisigInfo() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Get multisig info as hex to share with participants to begin creating a
-   * multisig wallet.
-   * 
-   * @return {string} this wallet's multisig hex to share with participants
-   */
-  async prepareMultisig() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Make this wallet multisig by importing multisig hex from participants.
-   * 
-   * @param {String[]} multisigHexes - multisig hex from each participant
-   * @param {int} threshold - number of signatures needed to sign transfers
-   * @param {string} password - wallet password
-   * @return {MoneroMultisigInitResult} the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not N/N
-   */
-  async makeMultisig(multisigHexes, threshold, password) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Exchange multisig hex with participants in a M/N multisig wallet.
-   * 
-   * This process must be repeated with participants exactly N-M times.
-   * 
-   * @param {string[]} multisigHexes are multisig hex from each participant
-   * @param {string} password - wallet's password // TODO monero core: redundant? wallet is created with password
-   * @return {MoneroMultisigInitResult} the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done
-   */
-  async exchangeMultisigKeys(multisigHexes, password) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Export this wallet's multisig info as hex for other participants.
-   * 
-   * @return {string} this wallet's multisig info as hex for other participants
-   */
-  async getMultisigHex() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Import multisig info as hex from other participants.
-   * 
-   * @param {string[]} multisigHexes - multisig hex from each participant
-   * @return {int} the number of outputs signed with the given multisig hex
-   */
-  async importMultisigHex(multisigHexes) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Sign multisig transactions from a multisig wallet.
-   * 
-   * @param {string} multisigTxHex - unsigned multisig transactions as hex
-   * @return {MoneroMultisigSignResult} the result of signing the multisig transactions
-   */
-  async signMultisigTxHex(multisigTxHex) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Submit signed multisig transactions from a multisig wallet.
-   * 
-   * @param {string} signedMultisigTxHex - signed multisig hex returned from signMultisigTxHex()
-   * @return {string[]} the resulting transaction hashes
-   */
-  async submitMultisigTxHex(signedMultisigTxHex) {
-    throw new MoneroError("Not supported");
-  }
-
-  /**
-   * Save the wallet at its current path.
-   */
-  save() {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Optionally save then close the wallet.
-   *
-   * @param {boolean} save - specifies if the wallet should be saved before being closed (default false)
-   */
-  async close(save) {
-    throw new MoneroError("Not supported");
-  }
-  
-  /**
-   * Indicates if this wallet is closed or not.
-   * 
-   * @return {boolean} true if the wallet is closed, false otherwise
-   */
-  async isClosed() {
-    throw new MoneroError("Not supported");
-  }
-  
-  // -------------------------------- PRIVATE ---------------------------------
-  
-  static _normalizeTxQuery(query) {
-    if (query instanceof MoneroTxQuery) query = query.copy();
-    else if (Array.isArray(query)) query = new MoneroTxQuery().setHashes(query);
-    else {
-      query = Object.assign({}, query);
-      query = new MoneroTxQuery(query);
-    }
-    if (query.getBlock() === undefined) query.setBlock(new MoneroBlock().setTxs([query]));
-    return query;
-  }
-  
-  static _normalizeTransferQuery(query) {
-    if (query === undefined) query = new MoneroTransferQuery();
-    else if (query instanceof MoneroTransferQuery) {
-      if (query.getTxQuery() === undefined) query = query.copy();
-      else {
-        let txQuery = query.getTxQuery().copy();
-        if (query.getTxQuery().getTransferQuery() === query) query = txQuery.getTransferQuery();
-        else {
-          assert.equal(query.getTxQuery().getTransferQuery(), undefined, "Transfer query's tx query must be circular reference or null");
-          query = query.copy();
-          query.setTxQuery(txQuery);
-        }
-      }
-    } else {
-      query = Object.assign({}, query);
-      query = new MoneroTransferQuery(query);
-    }
-    if (query.getTxQuery() === undefined) query.setTxQuery(new MoneroTxQuery());
-    query.getTxQuery().setTransferQuery(query);
-    if (query.getTxQuery().getBlock() === undefined) query.getTxQuery().setBlock(new MoneroBlock().setTxs([query.getTxQuery()]));
-    return query;
-  }
-  
-  static _normalizeOutputQuery(query) {
-    if (query === undefined) query = new MoneroOutputQuery();
-    else if (query instanceof MoneroOutputQuery) {
-      if (query.getTxQuery() === undefined) query = query.copy();
-      else {
-        let txQuery = query.getTxQuery().copy();
-        if (query.getTxQuery().getOutputQuery() === query) query = txQuery.getOutputQuery();
-        else {
-          assert.equal(query.getTxQuery().getOutputQuery(), undefined, "Output query's tx query must be circular reference or null");
-          query = query.copy();
-          query.setTxQuery(txQuery);
-        }
-      }
-    } else {
-      query = Object.assign({}, query);
-      query = new MoneroOutputQuery(query);
-    }
-    if (query.getTxQuery() === undefined) query.setTxQuery(new MoneroTxQuery());
-    query.getTxQuery().setOutputQuery(query);
-    if (query.getTxQuery().getBlock() === undefined) query.getTxQuery().setBlock(new MoneroBlock().setTxs([query.getTxQuery()]));
-    return query;
-  }
-  
-  static _normalizeCreateTxsConfig(config) {
-    if (config === undefined || !(config instanceof Object)) throw new MoneroError("Must provide MoneroTxConfig or equivalent JS object");
-    config = new MoneroTxConfig(config);
-    assert(config.getDestinations() && config.getDestinations().length > 0, "Must provide destinations");
-    assert.equal(config.getSweepEachSubaddress(), undefined);
-    assert.equal(config.getBelowAmount(), undefined);
-    return config;
-  }
-  
-  static _normalizeSweepOutputConfig(config) {
-    if (config === undefined || !(config instanceof Object)) throw new MoneroError("Must provide MoneroTxConfig or equivalent JS object");
-    config = new MoneroTxConfig(config);
-    assert.equal(config.getSweepEachSubaddress(), undefined);
-    assert.equal(config.getBelowAmount(), undefined);
-    assert.equal(config.getCanSplit(), undefined, "Cannot split transactions when sweeping an output");
-    if (!config.getDestinations() || config.getDestinations().length !== 1 || !config.getDestinations()[0].getAddress()) throw new MoneroError("Must provide exactly one destination address to sweep output to");
-    return config;
-  }
-  
-  static _normalizeSweepUnlockedConfig(config) {
-    if (config === undefined || !(config instanceof Object)) throw new MoneroError("Must provide MoneroTxConfig or equivalent JS object");
-    config = new MoneroTxConfig(config);
-    if (config.getDestinations() === undefined || config.getDestinations().length != 1) throw new MoneroError("Must provide exactly one destination to sweep to");
-    if (config.getDestinations()[0].getAddress() === undefined) throw new MoneroError("Must provide destination address to sweep to");
-    if (config.getDestinations()[0].getAmount() !== undefined) throw new MoneroError("Cannot provide amount in sweep config");
-    if (config.getKeyImage() !== undefined) throw new MoneroError("Key image defined; use sweepOutput() to sweep an output by its key image");
-    if (config.getSubaddressIndices() !== undefined && config.getSubaddressIndices().length === 0) config.setSubaddressIndices(undefined);
-    if (config.getAccountIndex() === undefined && config.getSubaddressIndices() !== undefined) throw new MoneroError("Must provide account index if subaddress indices are provided");
-    return config;
-  }
-}
-
-MoneroWallet.DEFAULT_LANGUAGE = "English";
-
-module.exports = MoneroWallet;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_MoneroWalletKeys.js.html b/docs/src_main_js_wallet_MoneroWalletKeys.js.html deleted file mode 100644 index 4f20e7479..000000000 --- a/docs/src_main_js_wallet_MoneroWalletKeys.js.html +++ /dev/null @@ -1,381 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/MoneroWalletKeys.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/MoneroWalletKeys.js

- - - - - - -
-
-
const assert = require("assert");
-const LibraryUtils = require("../common/LibraryUtils");
-const MoneroError = require("../common/MoneroError");
-const MoneroNetworkType = require("../daemon/model/MoneroNetworkType");
-const MoneroSubaddress = require("./model/MoneroSubaddress");
-const MoneroUtils = require("../common/MoneroUtils");
-const MoneroVersion = require("../daemon/model/MoneroVersion");
-const MoneroWallet = require("./MoneroWallet");
-const MoneroWalletConfig = require("./model/MoneroWalletConfig");
-
-/**
- * Implements a MoneroWallet which only manages keys using WebAssembly.
- * 
- * @implements {MoneroWallet}
- * @hideconstructor
- */
-class MoneroWalletKeys extends MoneroWallet {
-  
-  // --------------------------- STATIC UTILITIES -----------------------------
-  
-  /**
-   * <p>Create a wallet using WebAssembly bindings to monero-core.</p>
-   * 
-   * <p>Example:</p>
-   * 
-   * <code>
-   * let wallet = await MoneroWalletKeys.createWallet({<br>
-   * &nbsp;&nbsp; password: "abc123",<br>
-   * &nbsp;&nbsp; networkType: MoneroNetworkType.STAGENET,<br>
-   * &nbsp;&nbsp; mnemonic: "coexist igloo pamphlet lagoon..."<br>
-   * });
-   * </code>
-   * 
-   * @param {MoneroWalletConfig|object} config - MoneroWalletConfig or equivalent config object
-   * @param {string|number} config.networkType - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
-   * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)
-   * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase
-   * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys)
-   * @param {string} config.privateViewKey - private view key of the wallet to create (optional)
-   * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional)
-   * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected)
-   * @return {MoneroWalletKeys} the created wallet
-   */
-  static async createWallet(config) {
-    
-    // normalize and validate config
-    if (config === undefined) throw new MoneroError("Must provide config to create wallet");
-    config = config instanceof MoneroWalletConfig ? config : new MoneroWalletConfig(config);
-    if (config.getMnemonic() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) {
-      throw new MoneroError("Wallet may be initialized with a mnemonic or keys but not both");
-    }
-    if (config.getNetworkType() === undefined) throw new MoneroError("Must provide a networkType: 'mainnet', 'testnet' or 'stagenet'");
-    if (config.getSaveCurrent() === true) throw new MoneroError("Cannot save current wallet when creating keys-only wallet");
-    
-    // create wallet
-    if (config.getMnemonic() !== undefined) {
-      if (config.getLanguage() !== undefined) throw new MoneroError("Cannot provide language when creating wallet from mnemonic");
-      return MoneroWalletKeys._createWalletFromMnemonic(config.getNetworkType(), config.getMnemonic(), config.getSeedOffset());
-    } else if (config.getPrimaryAddress() !== undefined) {
-      if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating wallet from keys");
-      return MoneroWalletKeys._createWalletFromKeys(config.getNetworkType(), config.getPrimaryAddress(), config.getPrivateViewKey(), config.getPrivateSpendKey(), config.getLanguage());
-    } else {
-      if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating random wallet");
-      if (config.getRestoreHeight() !== undefined) throw new MoneroError("Cannot provide restoreHeight when creating random wallet");
-      return MoneroWalletKeys._createWalletRandom(config.getNetworkType(), config.getLanguage());
-    }
-  }
-  
-  static async _createWalletRandom(networkType, language) {
-
-    // validate and sanitize params
-    MoneroNetworkType.validate(networkType);
-    if (language === undefined) language = "English";
-    
-    // load wasm module
-    let module = await LibraryUtils.loadKeysModule();
-    
-    // queue call to wasm module
-    return module.queueTask(async function() {
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = async function(cppAddress) {
-          if (typeof cppAddress === "string") reject(new MoneroError(cppAddress));
-          else resolve(new MoneroWalletKeys(cppAddress));
-        };
-        
-        // create wallet in wasm and invoke callback when done
-        module.create_keys_wallet_random(networkType, language, callbackFn);
-      });
-    });
-  }
-  
-  static async _createWalletFromMnemonic(networkType, mnemonic, seedOffset) {
-    
-    // validate and sanitize params
-    MoneroNetworkType.validate(networkType);
-    if (mnemonic === undefined) throw Error("Must define mnemonic phrase to create wallet from");
-    if (seedOffset === undefined) seedOffset = "";
-    
-    // load wasm module
-    let module = await LibraryUtils.loadKeysModule();
-    
-    // queue call to wasm module
-    return module.queueTask(async function() {
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = async function(cppAddress) {
-          if (typeof cppAddress === "string") reject(new MoneroError(cppAddress));
-          else resolve(new MoneroWalletKeys(cppAddress));
-        };
-        
-        // create wallet in wasm and invoke callback when done
-        module.create_keys_wallet_from_mnemonic(networkType, mnemonic, seedOffset, callbackFn);
-      });
-    });
-  }
-  
-  static async _createWalletFromKeys(networkType, address, privateViewKey, privateSpendKey, language) {
-    
-    // validate and sanitize params
-    MoneroNetworkType.validate(networkType);
-    if (address === undefined) address = "";
-    if (privateViewKey === undefined) privateViewKey = "";
-    if (privateSpendKey === undefined) privateSpendKey = "";
-    if (language === undefined) language = "English";
-    
-    // load wasm module
-    let module = await LibraryUtils.loadKeysModule();
-    
-    // queue call to wasm module
-    return module.queueTask(async function() {
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = async function(cppAddress) {
-          if (typeof cppAddress === "string") reject(new MoneroError(cppAddress));
-          else resolve(new MoneroWalletKeys(cppAddress));
-        };
-        
-        // create wallet in wasm and invoke callback when done
-        module.create_keys_wallet_from_keys(networkType, address, privateViewKey, privateSpendKey, language, callbackFn);
-      });
-    });
-  }
-  
-  static async getMnemonicLanguages() {
-    let module = await LibraryUtils.loadKeysModule();
-    return module.queueTask(async function() {
-      return JSON.parse(module.get_keys_wallet_mnemonic_languages()).languages;
-    });
-  }
-  
-  // --------------------------- INSTANCE METHODS -----------------------------
-  
-  /**
-   * Internal constructor which is given the memory address of a C++ wallet
-   * instance.
-   * 
-   * This method should not be called externally but should be called through
-   * static wallet creation utilities in this class.
-   * 
-   * @param {int} cppAddress - address of the wallet instance in C++
-   */
-  constructor(cppAddress) {
-    super();
-    this._cppAddress = cppAddress;
-    this._module = LibraryUtils.getWasmModule();
-    if (!this._module.create_core_wallet_from_mnemonic) throw new Error("WASM module not loaded - create wallet instance using static utilities");  // static utilites pre-load wasm module
-  }
-  
-  async isViewOnly() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.is_view_only(that._cppAddress);
-    });
-  }
-  
-  async isConnected() {
-    return false;
-  }
-  
-  async getVersion() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      let versionStr = that._module.get_version(that._cppAddress);
-      let versionJson = JSON.parse(versionStr);
-      return new MoneroVersion(versionJson.number, versionJson.isRelease);
-    });
-  }
-  
-  /**
-   * @ignore
-   */
-  getPath() {
-    this._assertNotClosed();
-    throw new Error("MoneroWalletKeys does not support a persisted path");
-  }
-  
-  async getMnemonic() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      let mnemonic = that._module.get_mnemonic(that._cppAddress);
-      return mnemonic ? mnemonic : undefined;
-    });
-  }
-  
-  async getMnemonicLanguage() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      let mnemonicLanguage = that._module.get_mnemonic_language(that._cppAddress);
-      return mnemonicLanguage ? mnemonicLanguage : undefined;
-    });
-  }
-  
-  async getPrivateSpendKey() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      let privateSpendKey = that._module.get_private_spend_key(that._cppAddress);
-      return privateSpendKey ? privateSpendKey : undefined;
-    });
-  }
-  
-  async getPrivateViewKey() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.get_private_view_key(that._cppAddress);
-    });
-  }
-  
-  async getPublicViewKey() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.get_public_view_key(that._cppAddress);
-    });
-  }
-  
-  async getPublicSpendKey() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.get_public_spend_key(that._cppAddress);
-    });
-  }
-  
-  async getAddress(accountIdx, subaddressIdx) {
-    this._assertNotClosed();
-    assert(typeof accountIdx === "number");
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.get_address(that._cppAddress, accountIdx, subaddressIdx);
-    });
-  }
-  
-  async getAddressIndex(address) {
-    this._assertNotClosed();
-    if (!MoneroUtils.isValidAddress(address)) throw new MoneroError("Invalid address");
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      try {
-        let subaddressJson = JSON.parse(that._module.get_address_index(that._cppAddress, address));
-        return new MoneroSubaddress(subaddressJson);
-      } catch (e) {
-        throw new Error("Address doesn't belong to the wallet");
-      }
-    });
-  }
-  
-  getAccounts() {
-    this._assertNotClosed();
-    throw new Error("MoneroWalletKeys does not support getting an enumerable set of accounts; query specific accounts");
-  }
-  
-  // getIntegratedAddress(paymentId)  // TODO
-  // decodeIntegratedAddress
-  
-  async close(save) {
-    if (this._isClosed) return; // closing a closed wallet has no effect
-    
-    // save wallet if requested
-    if (save) await this.save();
-    
-    // queue task to use wasm module
-    let that = this;
-    return that._module.queueTask(async function() {
-      return new Promise(function(resolve, reject) {
-        if (that._isClosed) {
-          resolve();
-          return;
-        }
-        
-        // define callback for wasm
-        let callbackFn = async function() {
-          delete that._cppAddress;
-          that._isClosed = true;
-          resolve();
-        };
-        
-        // close wallet in wasm and invoke callback when done
-        that._module.close(that._cppAddress, false, callbackFn);  // saving handled external to webassembly
-      });
-    });
-  }
-  
-  async isClosed() {
-    return this._isClosed;
-  }
-  
-  // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS --------------
-  
-  async getPrimaryAddress() { return super.getPrimaryAddress(...arguments); }
-  async getSubaddress() { return super.getSubaddress(...arguments); }
-  
-  // ----------------------------- PRIVATE HELPERS ----------------------------
-  
-  _assertNotClosed() {
-    if (this._isClosed) throw new MoneroError("Wallet is closed");
-  }
-}
-
-module.exports = MoneroWalletKeys;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_MoneroWalletRpc.js.html b/docs/src_main_js_wallet_MoneroWalletRpc.js.html deleted file mode 100644 index 8b6eaa786..000000000 --- a/docs/src_main_js_wallet_MoneroWalletRpc.js.html +++ /dev/null @@ -1,2187 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/MoneroWalletRpc.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/MoneroWalletRpc.js

- - - - - - -
-
-
const assert = require("assert");
-const BigInteger = require("../common/biginteger").BigInteger;
-const GenUtils = require("../common/GenUtils");
-const MoneroAccount = require("./model/MoneroAccount");
-const MoneroAccountTag = require("./model/MoneroAccountTag");
-const MoneroAddressBookEntry = require("./model/MoneroAddressBookEntry");
-const MoneroBlock = require("../daemon/model/MoneroBlock");
-const MoneroBlockHeader = require("../daemon/model/MoneroBlockHeader");
-const MoneroCheckReserve = require("./model/MoneroCheckReserve");
-const MoneroCheckTx = require("./model/MoneroCheckTx");
-const MoneroDaemonRpc = require("../daemon/MoneroDaemonRpc");
-const MoneroDestination = require("./model/MoneroDestination");
-const MoneroError = require("../common/MoneroError");
-const MoneroIncomingTransfer = require("./model/MoneroIncomingTransfer");
-const MoneroIntegratedAddress = require("./model/MoneroIntegratedAddress");
-const MoneroKeyImage = require("../daemon/model/MoneroKeyImage");
-const MoneroKeyImageImportResult = require("./model/MoneroKeyImageImportResult");
-const MoneroMultisigInfo = require("./model/MoneroMultisigInfo");
-const MoneroMultisigInitResult = require("./model/MoneroMultisigInitResult");
-const MoneroMultisigSignResult = require("./model/MoneroMultisigSignResult");
-const MoneroOutgoingTransfer = require("./model/MoneroOutgoingTransfer");
-const MoneroOutputQuery = require("./model/MoneroOutputQuery");
-const MoneroOutputWallet = require("./model/MoneroOutputWallet");
-const MoneroRpcConnection = require("../common/MoneroRpcConnection");
-const MoneroRpcError = require("../common/MoneroRpcError");
-const MoneroSubaddress = require("./model/MoneroSubaddress");
-const MoneroSyncResult = require("./model/MoneroSyncResult");
-const MoneroTransferQuery = require("./model/MoneroTransferQuery");
-const MoneroTxConfig = require("./model/MoneroTxConfig");
-const MoneroTxQuery = require("./model/MoneroTxQuery");
-const MoneroTxSet = require("./model/MoneroTxSet");
-const MoneroTxWallet = require("./model/MoneroTxWallet");
-const MoneroUtils = require("../common/MoneroUtils");
-const MoneroVersion = require("../daemon/model/MoneroVersion");
-const MoneroWallet = require("./MoneroWallet");
-const MoneroWalletConfig = require("./model/MoneroWalletConfig");
-const SslOptions = require("../common/SslOptions");
-
-/**
- * Copyright (c) woodser
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/**
- * Implements a MoneroWallet as a client of monero-wallet-rpc.
- * 
- * @implements {MoneroWallet}
- */
-class MoneroWalletRpc extends MoneroWallet {
-  
-  /**
-   * <p>Construct a wallet RPC client.</p>
-   * 
-   * <p>Examples:</p>
-   * 
-   * <code>
-   * let walletRpc = new MoneroWalletRpc("http://localhost:38081", "superuser", "abctesting123");<br><br>
-   * 
-   * let walletRpc = new MoneroWalletRpc({<br>
-   * &nbsp;&nbsp; uri: "http://localhost:38081",<br>
-   * &nbsp;&nbsp; username: "superuser",<br>
-   * &nbsp;&nbsp; password: "abctesting123",<br>
-   * &nbsp;&nbsp; rejectUnauthorized: false // e.g. local development<br>
-   * });
-   * </code>
-   * 
-   * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - uri of monero-wallet-rpc or JS config object or MoneroRpcConnection
-   * @param {string} uriOrConfigOrConnection.uri - uri of monero-wallet-rpc
-   * @param {string} uriOrConfigOrConnection.username - username to authenticate with monero-wallet-rpc (optional)
-   * @param {string} uriOrConfigOrConnection.password - password to authenticate with monero-wallet-rpc (optional)
-   * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true)
-   * @param {string} username - username to authenticate with monero-wallet-rpc (optional)
-   * @param {string} password - password to authenticate with monero-wallet-rpc (optional)
-   * @param {boolean} rejectUnauthorized - rejects self-signed certificates if true (default true)
-   */
-  constructor(uriOrConfigOrConnection, username, password, rejectUnauthorized) {
-    super();
-    this.config = MoneroDaemonRpc._normalizeConfig(uriOrConfigOrConnection, username, password, rejectUnauthorized);
-    this.rpc = new MoneroRpcConnection(this.config);
-    this.addressCache = {}; // avoid unecessary requests for addresses
-  }
-  
-  /**
-   * Get the wallet's RPC connection.
-   * 
-   * @return {MoneroWalletRpc} the wallet's rpc connection
-   */
-  async getRpcConnection() {
-    return this.rpc;
-  }
-  
-  /**
-   * <p>Open an existing wallet on the monero-wallet-rpc server.</p>
-   * 
-   * <p>Example:<p>
-   * 
-   * <code>
-   * let wallet = new MoneroWalletRpc("http://localhost:38083", "rpc_user", "abc123");<br>
-   * await wallet.openWallet("mywallet1", "supersecretpassword");<br>
-   * await wallet.openWallet({<br>
-   * &nbsp;&nbsp; path: "mywallet2",<br>
-   * &nbsp;&nbsp; password: "supersecretpassword",<br>
-   * &nbsp;&nbsp; serverUri: "http://locahost:38081",<br>
-   * &nbsp;&nbsp; rejectUnauthorized: false<br>
-   * });<br>
-   * </code>
-   * 
-   * @param {string|object|MoneroWalletConfig} pathOrConfig  - the wallet's name or configuration to open
-   * @param {string} pathOrConfig.path - path of the wallet to create (optional, in-memory wallet if not given)
-   * @param {string} pathOrConfig.password - password of the wallet to create
-   * @param {string} pathOrConfig.serverUri - uri of a daemon to use (optional, monero-wallet-rpc usually started with daemon config)
-   * @param {string} pathOrConfig.serverUsername - username to authenticate with the daemon (optional)
-   * @param {string} pathOrConfig.serverPassword - password to authenticate with the daemon (optional)
-   * @param {boolean} pathOrConfig.rejectUnauthorized - reject self-signed server certificates if true (defaults to true)
-   * @param {MoneroRpcConnection|object} pathOrConfig.server - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional)
-   * @param {string} password is the wallet's password
-   */
-  async openWallet(pathOrConfig, password) {
-    
-    // normalize and validate config
-    let config = new MoneroWalletConfig(typeof pathOrConfig === "string" ? {path: pathOrConfig, password: password} : pathOrConfig);
-    // TODO: ensure other fields are uninitialized?
-    
-    // open wallet on rpc server
-    if (!config.getPath()) throw new MoneroError("Must provide name of wallet to open");
-    if (!config.getPassword()) throw new MoneroError("Must provide password of wallet to open");
-    await this.rpc.sendJsonRequest("open_wallet", {filename: config.getPath(), password: config.getPassword()});
-    this._clear();
-    this.path = config.getPath();
-    
-    // set daemon if provided
-    if (config.getServer()) return this.setDaemonConnection(config.getServer());
-  }
-  
-  /**
-   * <p>Create and open a wallet on the monero-wallet-rpc server.<p>
-   * 
-   * <p>Example:<p>
-   * 
-   * <code>
-   * &sol;&sol; construct client to monero-wallet-rpc<br>
-   * let walletRpc = new MoneroWalletRpc("http://localhost:38083", "rpc_user", "abc123");<br><br>
-   * 
-   * &sol;&sol; create and open wallet on monero-wallet-rpc<br>
-   * await walletRpc.createWallet({<br>
-   * &nbsp;&nbsp; path: "mywallet",<br>
-   * &nbsp;&nbsp; password: "abc123",<br>
-   * &nbsp;&nbsp; mnemonic: "coexist igloo pamphlet lagoon...",<br>
-   * &nbsp;&nbsp; restoreHeight: 1543218l<br>
-   * });
-   *  </code>
-   * 
-   * @param {object|MoneroWalletConfig} config - MoneroWalletConfig or equivalent JS object
-   * @param {string} config.path - path of the wallet to create (optional, in-memory wallet if not given)
-   * @param {string} config.password - password of the wallet to create
-   * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)
-   * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase
-   * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys)
-   * @param {string} config.privateViewKey - private view key of the wallet to create (optional)
-   * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional)
-   * @param {number} config.restoreHeight - block height to start scanning from (defaults to 0 unless generating random wallet)
-   * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected)
-   * @param {string} config.serverUri - uri of a daemon to use (optional, monero-wallet-rpc usually started with daemon config)
-   * @param {string} config.serverUsername - username to authenticate with the daemon (optional)
-   * @param {string} config.serverPassword - password to authenticate with the daemon (optional)
-   * @param {boolean} config.rejectUnauthorized - reject self-signed server certificates if true (defaults to true)
-   * @param {MoneroRpcConnection|object} config.server - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional)
-   * @param {boolean} config.saveCurrent - specifies if the current RPC wallet should be saved before being closed (default true)
-   */
-  async createWallet(config) {
-    
-    // normalize and validate config
-    if (config === undefined) throw new MoneroError("Must provide config to create wallet");
-    config = config instanceof MoneroWalletConfig ? config : new MoneroWalletConfig(config);
-    if (config.getMnemonic() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) {
-      throw new MoneroError("Wallet may be initialized with a mnemonic or keys but not both");
-    }
-    if (config.getNetworkType() !== undefined) throw new MoneroError("Cannot provide networkType when creating RPC wallet because server's network type is already set");
-    
-    // create wallet
-    if (config.getMnemonic() !== undefined) {
-      await this._createWalletFromMnemonic(config.getPath(), config.getPassword(), config.getMnemonic(), config.getRestoreHeight(), config.getLanguage(), config.getSeedOffset(), config.getSaveCurrent());
-    } else if (config.getPrimaryAddress() !== undefined) {
-      if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating wallet from keys");
-      await this._createWalletFromKeys(config.getPath(), config.getPassword(), config.getPrimaryAddress(), config.getPrivateViewKey(), config.getPrivateSpendKey(), config.getRestoreHeight(), config.getLanguage(), config.getSaveCurrent());
-    } else {
-      if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating random wallet");
-      if (config.getRestoreHeight() !== undefined) throw new MoneroError("Cannot provide restoreHeight when creating random wallet");
-      if (config.getSaveCurrent() === false) throw new MoneroError("Current wallet is saved automatically when creating random wallet");
-      await this._createWalletRandom(config.getPath(), config.getPassword(), config.getLanguage());
-    }
-    
-    // set daemon if provided
-    if (config.getServer()) return this.setDaemonConnection(config.getServer());
-  }
-  
-  /**
-   * Create and open a new wallet with a randomly generated seed on the RPC server.
-   * 
-   * @param {string} name - name of the wallet file to create
-   * @param {string} password - wallet's password
-   * @param {string} language - language for the wallet's mnemonic phrase
-   */
-  async _createWalletRandom(name, password, language) {
-    if (!name) throw new MoneroError("Name is not initialized");
-    if (!password) throw new MoneroError("Password is not initialized");
-    if (!language) language = MoneroWallet.DEFAULT_LANGUAGE;
-    let params = { filename: name, password: password, language: language };
-    try {
-      await this.rpc.sendJsonRequest("create_wallet", params);
-    } catch (e) {
-      if (e.message === "Cannot create wallet. Already exists.") throw new MoneroError("Wallet already exists: " + name);
-      throw e;
-    }
-    this._clear();
-    this.path = name;
-  }
-  
-  /**
-   * Create and open a wallet from an existing mnemonic phrase on the RPC server,
-   * closing the currently open wallet if applicable.
-   * 
-   * @param {string} name - name of the wallet to create on the RPC server
-   * @param {string} password - wallet's password
-   * @param {string} mnemonic - mnemonic of the wallet to construct
-   * @param {int} restoreHeight - block height to restore from (default = 0)
-   * @param {string} language - language of the mnemonic in case the old language is invalid
-   * @param {string} seedOffset - offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase
-   * @param {boolean} saveCurrent - specifies if the current RPC wallet should be saved before being closed
-   */
-  async _createWalletFromMnemonic(name, password, mnemonic, restoreHeight, language, seedOffset, saveCurrent) {
-    try {
-      await this.rpc.sendJsonRequest("restore_deterministic_wallet", {
-        filename: name,
-        password: password,
-        seed: mnemonic,
-        seed_offset: seedOffset,
-        restore_height: restoreHeight,
-        language: language,
-        autosave_current: saveCurrent
-      });
-    } catch (e) {
-      if (e.message === "Cannot create wallet. Already exists.") throw new MoneroError("Wallet already exists: " + name);
-      throw e;
-    }
-    this._clear();
-    this.path = name;
-  }
-  
-  /**
-   * Create a wallet on the RPC server from an address, view key, and (optionally) spend key.
-   * 
-   * @param name - name of the wallet to create on the RPC server
-   * @param password - password encrypt the wallet
-   * @param networkType - wallet's network type
-   * @param address - address of the wallet to construct
-   * @param viewKey - view key of the wallet to construct
-   * @param spendKey - spend key of the wallet to construct or null to create a view-only wallet
-   * @param restoreHeight - block height to restore (i.e. scan the chain) from (default = 0)
-   * @param language - wallet and mnemonic's language (default = "English")
-   */
-  async _createWalletFromKeys(name, password, address, viewKey, spendKey, restoreHeight, language, saveCurrent) {
-    if (restoreHeight === undefined) restoreHeight = 0;
-    if (language === undefined) language = MoneroWallet.DEFAULT_LANGUAGE;
-    try {
-      await this.rpc.sendJsonRequest("generate_from_keys", {
-        filename: name,
-        password: password,
-        address: address,
-        viewkey: viewKey,
-        spendkey: spendKey,
-        restore_height: restoreHeight,
-        autosave_current: saveCurrent
-      });
-    } catch (e) {
-      if (e.message === "Cannot create wallet. Already exists.") throw new MoneroError("Wallet already exists: " + name);
-      throw e;
-    }
-    this._clear();
-    this.path = name;
-  }
-  
-  async isViewOnly() {
-    try {
-      await this.rpc.sendJsonRequest("query_key", {key_type: "mnemonic"});
-      return false; // key retrieval succeeds if not view only
-    } catch (e) {
-      if (e.getCode() === -29) return true;  // wallet is view only
-      if (e.getCode() === -1) return false;  // wallet is offline but not view only
-      throw e;
-    }
-  }
-  
-  /**
-   * Set the wallet's daemon connection.
-   * 
-   * @param {string|MoneroRpcConnection} uriOrConnection - the daemon's URI or connection (defaults to offline)
-   * @param {boolean} isTrusted - indicates if the daemon in trusted
-   * @param {SslOptions} sslOptions - custom SSL configuration
-   */
-  async setDaemonConnection(daemonUriOrConnection, isTrusted, sslOptions) {
-    let daemonConnection = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection : new MoneroRpcConnection(daemonUriOrConnection);
-    if (daemonConnection.getUsername()) throw new MoneroError("monero-wallet-rpc does not support setting daemon connection with authentication");
-    if (!sslOptions) sslOptions = new SslOptions();
-    let params = {};
-    params.address = !daemonConnection ? "bad_uri" : daemonConnection.getUri(); // TODO monero-wallet-rpc: bad daemon uri necessary for offline?
-    params.trusted = isTrusted;
-    params.ssl_support = "autodetect";
-    params.ssl_private_key_path = sslOptions.getPrivateKeyPath();
-    params.ssl_certificate_path  = sslOptions.getCertificatePath();
-    params.ssl_ca_file = sslOptions.getCertificateAuthorityFile();
-    params.ssl_allowed_fingerprints = sslOptions.getAllowedFingerprints();
-    params.ssl_allow_any_cert = sslOptions.getAllowAnyCert();
-    await this.rpc.sendJsonRequest("set_daemon", params);
-  }
-  
-  async getDaemonConnection() {
-    throw new MoneroError("Not implemented");
-  }
-  
-  async isConnected() {
-    try {
-      await this.sync(); // wallet rpc auto syncs so worst case this call blocks and blocks upfront  TODO: better way to determine if wallet rpc is connected to daemon?
-      return true;
-    } catch (e) {
-      return false;
-    }
-  }
-  
-  async getVersion() {
-    let resp = await this.rpc.sendJsonRequest("get_version");
-    return new MoneroVersion(resp.result.version, resp.result.release);
-  }
-  
-  async getPath() {
-    return this.path;
-  }
-  
-  async getMnemonic() {
-    try {
-      let resp = await this.rpc.sendJsonRequest("query_key", { key_type: "mnemonic" });
-      return resp.result.key;
-    } catch (e) {
-      if (e.getCode() === -29) return undefined;  // wallet is view-only
-      throw e;
-    }
-  }
-  
-  async getMnemonicLanguage() {
-    if (await this.getMnemonic() === undefined) return undefined;
-    throw new MoneroError("MoneroWalletRpc.getMnemonicLanguage() not supported");
-  }
-
-  /**
-   * Get a list of available languages for the wallet's mnemonic phrase.
-   * 
-   * @return {string[]} the available languages for the wallet's mnemonic phrase
-   */
-  async getMnemonicLanguages() {
-    return (await this.rpc.sendJsonRequest("get_languages")).result.languages;
-  }
-  
-  async getPrivateViewKey() {
-    let resp = await this.rpc.sendJsonRequest("query_key", { key_type: "view_key" });
-    return resp.result.key;
-  }
-  
-  async getPrivateSpendKey() {
-    
-    // get private spend key which will throw error if wallet is view-only
-    try {
-      let resp = await this.rpc.sendJsonRequest("query_key", { key_type: "spend_key" });
-      return resp.result.key;
-    } catch (e) {
-      if (e.getCode() === -29 && e.message.indexOf("watch-only") !== -1) return undefined; // return undefined if wallet is view-only
-      throw e;
-    }
-  }
-  
-  async getAddress(accountIdx, subaddressIdx) {
-    let subaddressMap = this.addressCache[accountIdx];
-    if (!subaddressMap) {
-      await this.getSubaddresses(accountIdx, undefined, true);  // cache's all addresses at this account
-      return this.getAddress(accountIdx, subaddressIdx);        // recursive call uses cache
-    }
-    let address = subaddressMap[subaddressIdx];
-    if (!address) {
-      await this.getSubaddresses(accountIdx, undefined, true);  // cache's all addresses at this account
-      return this.addressCache[accountIdx][subaddressIdx];
-    }
-    return address;
-  }
-  
-  // TODO: use cache
-  async getAddressIndex(address) {
-    
-    // fetch result and normalize error if address does not belong to the wallet
-    let resp;
-    try {
-      resp = await this.rpc.sendJsonRequest("get_address_index", {address: address});
-    } catch (e) {
-      if (e.getCode() === -2) throw new MoneroError(e.message);
-      throw e;
-    }
-    
-    // convert rpc response
-    let subaddress = new MoneroSubaddress(address);
-    subaddress.setAccountIndex(resp.result.index.major);
-    subaddress.setIndex(resp.result.index.minor);
-    return subaddress;
-  }
-  
-  async getIntegratedAddress(paymentId) {
-    try {
-      let integratedAddressStr = (await this.rpc.sendJsonRequest("make_integrated_address", {payment_id: paymentId})).result.integrated_address;
-      return await this.decodeIntegratedAddress(integratedAddressStr);
-    } catch (e) {
-      if (e.message.includes("Invalid payment ID")) throw new MoneroError("Invalid payment ID: " + paymentId);
-      throw e;
-    }
-  }
-  
-  async decodeIntegratedAddress(integratedAddress) {
-    let resp = await this.rpc.sendJsonRequest("split_integrated_address", {integrated_address: integratedAddress});
-    return new MoneroIntegratedAddress().setStandardAddress(resp.result.standard_address).setPaymentId(resp.result.payment_id).setIntegratedAddress(integratedAddress);
-  }
-  
-  async getHeight() {
-    return (await this.rpc.sendJsonRequest("get_height")).result.height;
-  }
-  
-  async getDaemonHeight() {
-    throw new MoneroError("monero-wallet-rpc does not support getting the chain height");
-  }
-  
-  async getHeightByDate(year, month, day) {
-    throw new MoneroError("monero-wallet-rpc does not support getting a height by date");
-  }
-  
-  async sync(startHeight, onProgress) {
-    assert(onProgress === undefined, "Monero Wallet RPC does not support reporting sync progress");
-    let resp = await this.rpc.sendJsonRequest("refresh", {start_height: startHeight});
-    return new MoneroSyncResult(resp.result.blocks_fetched, resp.result.received_money);
-  }
-  
-  async startSyncing() {
-    // nothing to do because wallet rpc syncs automatically
-  }
-  
-  async rescanSpent() {
-    await this.rpc.sendJsonRequest("rescan_spent");
-  }
-  
-  async rescanBlockchain() {
-    await this.rpc.sendJsonRequest("rescan_blockchain");
-  }
-  
-  async getBalance(accountIdx, subaddressIdx) {
-    return (await this._getBalances(accountIdx, subaddressIdx))[0];
-  }
-  
-  async getUnlockedBalance(accountIdx, subaddressIdx) {
-    return (await this._getBalances(accountIdx, subaddressIdx))[1];
-  }
-  
-  async getAccounts(includeSubaddresses, tag, skipBalances) {
-    
-    // fetch accounts from rpc
-    let resp = await this.rpc.sendJsonRequest("get_accounts", {tag: tag});
-    
-    // build account objects and fetch subaddresses per account using get_address
-    // TODO monero-wallet-rpc: get_address should support all_accounts so not called once per account
-    let accounts = [];
-    for (let rpcAccount of resp.result.subaddress_accounts) {
-      let account = MoneroWalletRpc._convertRpcAccount(rpcAccount);
-      if (includeSubaddresses) account.setSubaddresses(await this.getSubaddresses(account.getIndex(), undefined, true));
-      accounts.push(account);
-    }
-    
-    // fetch and merge fields from get_balance across all accounts
-    if (includeSubaddresses && !skipBalances) {
-      
-      // these fields are not initialized if subaddress is unused and therefore not returned from `get_balance`
-      for (let account of accounts) {
-        for (let subaddress of account.getSubaddresses()) {
-          subaddress.setBalance(new BigInteger(0));
-          subaddress.setUnlockedBalance(new BigInteger(0));
-          subaddress.setNumUnspentOutputs(0);
-          subaddress.setNumBlocksToUnlock(0);
-        }
-      }
-      
-      // fetch and merge info from get_balance
-      resp = await this.rpc.sendJsonRequest("get_balance", {all_accounts: true});
-      if (resp.result.per_subaddress) {
-        for (let rpcSubaddress of resp.result.per_subaddress) {
-          let subaddress = MoneroWalletRpc._convertRpcSubaddress(rpcSubaddress);
-          
-          // merge info
-          let account = accounts[subaddress.getAccountIndex()];
-          assert.equal(subaddress.getAccountIndex(), account.getIndex(), "RPC accounts are out of order");  // would need to switch lookup to loop
-          let tgtSubaddress = account.getSubaddresses()[subaddress.getIndex()];
-          assert.equal(subaddress.getIndex(), tgtSubaddress.getIndex(), "RPC subaddresses are out of order");
-          if (subaddress.getBalance() !== undefined) tgtSubaddress.setBalance(subaddress.getBalance());
-          if (subaddress.getUnlockedBalance() !== undefined) tgtSubaddress.setUnlockedBalance(subaddress.getUnlockedBalance());
-          if (subaddress.getNumUnspentOutputs() !== undefined) tgtSubaddress.setNumUnspentOutputs(subaddress.getNumUnspentOutputs());
-        }
-      }
-    }
-    
-    // return accounts
-    return accounts;
-  }
-  
-  // TODO: getAccountByIndex(), getAccountByTag()
-  async getAccount(accountIdx, includeSubaddresses, skipBalances) {
-    assert(accountIdx >= 0);
-    for (let account of await this.getAccounts()) {
-      if (account.getIndex() === accountIdx) {
-        if (includeSubaddresses) account.setSubaddresses(await this.getSubaddresses(accountIdx, undefined, skipBalances));
-        return account;
-      }
-    }
-    throw new Exception("Account with index " + accountIdx + " does not exist");
-  }
-
-  async createAccount(label) {
-    label = label ? label : undefined;
-    let resp = await this.rpc.sendJsonRequest("create_account", {label: label});
-    return new MoneroAccount(resp.result.account_index, resp.result.address, new BigInteger(0), new BigInteger(0));
-  }
-
-  async getSubaddresses(accountIdx, subaddressIndices, skipBalances) {
-    
-    // fetch subaddresses
-    let params = {};
-    params.account_index = accountIdx;
-    if (subaddressIndices) params.address_index = GenUtils.listify(subaddressIndices);
-    let resp = await this.rpc.sendJsonRequest("get_address", params);
-    
-    // initialize subaddresses
-    let subaddresses = [];
-    for (let rpcSubaddress of resp.result.addresses) {
-      let subaddress = MoneroWalletRpc._convertRpcSubaddress(rpcSubaddress);
-      subaddress.setAccountIndex(accountIdx);
-      subaddresses.push(subaddress);
-    }
-    
-    // fetch and initialize subaddress balances
-    if (!skipBalances) {
-      
-      // these fields are not initialized if subaddress is unused and therefore not returned from `get_balance`
-      for (let subaddress of subaddresses) {
-        subaddress.setBalance(new BigInteger(0));
-        subaddress.setUnlockedBalance(new BigInteger(0));
-        subaddress.setNumUnspentOutputs(0);
-        subaddress.setNumBlocksToUnlock(0);
-      }
-
-      // fetch and initialize balances
-      resp = await this.rpc.sendJsonRequest("get_balance", params);
-      if (resp.result.per_subaddress) {
-        for (let rpcSubaddress of resp.result.per_subaddress) {
-          let subaddress = MoneroWalletRpc._convertRpcSubaddress(rpcSubaddress);
-          
-          // transfer info to existing subaddress object
-          for (let tgtSubaddress of subaddresses) {
-            if (tgtSubaddress.getIndex() !== subaddress.getIndex()) continue; // skip to subaddress with same index
-            if (subaddress.getBalance() !== undefined) tgtSubaddress.setBalance(subaddress.getBalance());
-            if (subaddress.getUnlockedBalance() !== undefined) tgtSubaddress.setUnlockedBalance(subaddress.getUnlockedBalance());
-            if (subaddress.getNumUnspentOutputs() !== undefined) tgtSubaddress.setNumUnspentOutputs(subaddress.getNumUnspentOutputs());
-            if (subaddress.getNumBlocksToUnlock() !== undefined) tgtSubaddress.setNumBlocksToUnlock(subaddress.getNumBlocksToUnlock());
-          }
-        }
-      }
-    }
-    
-    // cache addresses
-    let subaddressMap = this.addressCache[accountIdx];
-    if (!subaddressMap) {
-      subaddressMap = {};
-      this.addressCache[accountIdx] = subaddressMap;
-    }
-    for (let subaddress of subaddresses) {
-      subaddressMap[subaddress.getIndex()] = subaddress.getAddress();
-    }
-    
-    // return results
-    return subaddresses;
-  }
-
-  async getSubaddress(accountIdx, subaddressIdx, skipBalances) {
-    assert(accountIdx >= 0);
-    assert(subaddressIdx >= 0);
-    return (await this.getSubaddresses(accountIdx, subaddressIdx, skipBalances))[0];
-  }
-
-  async createSubaddress(accountIdx, label) {
-    
-    // send request
-    let resp = await this.rpc.sendJsonRequest("create_address", {account_index: accountIdx, label: label});
-    
-    // build subaddress object
-    let subaddress = new MoneroSubaddress();
-    subaddress.setAccountIndex(accountIdx);
-    subaddress.setIndex(resp.result.address_index);
-    subaddress.setAddress(resp.result.address);
-    subaddress.setLabel(label ? label : undefined);
-    subaddress.setBalance(new BigInteger(0));
-    subaddress.setUnlockedBalance(new BigInteger(0));
-    subaddress.setNumUnspentOutputs(0);
-    subaddress.setIsUsed(false);
-    subaddress.setNumBlocksToUnlock(0);
-    return subaddress;
-  }
-  
-  async getTxs(query, missingTxHashes) {
-    
-    // copy query
-    query = MoneroWallet._normalizeTxQuery(query);
-    
-    // temporarily disable transfer and output queries in order to collect all tx information
-    let transferQuery = query.getTransferQuery();
-    let outputQuery = query.getOutputQuery();
-    query.setTransferQuery(undefined);
-    query.setOutputQuery(undefined);
-    
-    // fetch all transfers that meet tx query
-    let transfers = await this._getTransfersAux(new MoneroTransferQuery().setTxQuery(MoneroWalletRpc._decontextualize(query.copy())));
-    
-    // collect unique txs from transfers while retaining order
-    let txs = [];
-    let txsSet = new Set();
-    for (let transfer of transfers) {
-      if (!txsSet.has(transfer.getTx())) {
-        txs.push(transfer.getTx());
-        txsSet.add(transfer.getTx());
-      }
-    }
-    
-    // cache types into maps for merging and lookup
-    let txMap = new Map();
-    let blockMap = new Map();
-    for (let tx of txs) {
-      MoneroWalletRpc._mergeTx(tx, txMap, blockMap, false);
-    }
-    
-    // fetch and merge outputs if requested
-    if (query.getIncludeOutputs() || outputQuery) {
-      let outputs = await this._getOutputsAux(new MoneroOutputQuery().setTxQuery(MoneroWalletRpc._decontextualize(query.copy())));
-      
-      // merge output txs one time while retaining order
-      let outputTxs = [];
-      for (let output of outputs) {
-        if (!outputTxs.includes(output.getTx())) {
-          MoneroWalletRpc._mergeTx(output.getTx(), txMap, blockMap, true);
-          outputTxs.push(output.getTx());
-        }
-      }
-    }
-    
-    // restore transfer and output queries
-    query.setTransferQuery(transferQuery);
-    query.setOutputQuery(outputQuery);
-    
-    // filter txs that don't meet transfer query
-    let txsQueried = [];
-    for (let tx of txs) {
-      if (query.meetsCriteria(tx)) txsQueried.push(tx);
-      else if (tx.getBlock() !== undefined) tx.getBlock().getTxs().splice(tx.getBlock().getTxs().indexOf(tx), 1);
-    }
-    txs = txsQueried;
-    
-    // collect unfound tx hashes
-    if (query.getHashes()) {
-      let unfoundTxHashes = [];
-      for (let txHash of query.getHashes()) {
-        let found = false;
-        for (let tx of txs) {
-          if (txHash === tx.getHash()) {
-            found = true;
-            break;
-          }
-        }
-        if (!found) unfoundTxHashes.push(txHash);
-      }
-     
-      // if txs not found, collect missing hashes or throw error if no collection given
-      if (missingTxHashes) for (let unfoundTxHash of unfoundTxHashes) missingTxHashes.push(unfoundTxHash);
-      else if (unfoundTxHashes.length > 0) throw new MoneroError("Wallet missing requested tx hashes: " + unfoundTxHashes);
-    }
-    
-    // special case: re-fetch txs if inconsistency caused by needing to make multiple rpc calls
-    for (let tx of txs) {
-      if (tx.isConfirmed() && tx.getBlock() === undefined) return this.getTxs(query);
-    }
-    
-    // order txs if tx hashes given then return
-    if (query.getHashes() && query.getHashes().length > 0) {
-      let txsById = new Map()  // store txs in temporary map for sorting
-      for (let tx of txs) txsById.set(tx.getHash(), tx);
-      let orderedTxs = [];
-      for (let hash of query.getHashes()) if (txsById.get(hash)) orderedTxs.push(txsById.get(hash));
-      txs = orderedTxs;
-    }
-    return txs;
-  }
-  
-  async getTransfers(query) {
-    
-    // copy and normalize query up to block
-    query = MoneroWallet._normalizeTransferQuery(query);
-    
-    // get transfers directly if query does not require tx context (other transfers, outputs)
-    if (!MoneroWalletRpc._isContextual(query)) return this._getTransfersAux(query);
-    
-    // otherwise get txs with full models to fulfill query
-    let transfers = [];
-    for (let tx of await this.getTxs(query.getTxQuery())) {
-      for (let transfer of tx.filterTransfers(query)) {
-        transfers.push(transfer);
-      }
-    }
-    
-    return transfers;
-  }
-  
-  async getOutputs(query) {
-    
-    // copy and normalize query up to block
-    query = MoneroWallet._normalizeOutputQuery(query);
-    
-    // get outputs directly if query does not require tx context (other outputs, transfers)
-    if (!MoneroWalletRpc._isContextual(query)) return this._getOutputsAux(query);
-    
-    // otherwise get txs with full models to fulfill query
-    let outputs = [];
-    for (let tx of await this.getTxs(query.getTxQuery())) {
-      for (let output of tx.filterOutputs(query)) {
-        outputs.push(output);
-      }
-    }
-    
-    return outputs;
-  }
-  
-  async getOutputsHex() {
-    return (await this.rpc.sendJsonRequest("export_outputs")).result.outputs_data_hex;
-  }
-  
-  async importOutputsHex(outputsHex) {
-    let resp = await this.rpc.sendJsonRequest("import_outputs", {outputs_data_hex: outputsHex});
-    return resp.result.num_imported;
-  }
-  
-  async getKeyImages() {
-    return await this._rpcExportKeyImages(true);
-  }
-  
-  async importKeyImages(keyImages) {
-    
-    // convert key images to rpc parameter
-    let rpcKeyImages = keyImages.map(keyImage => ({key_image: keyImage.getHex(), signature: keyImage.getSignature()}));
-    
-    // send request
-    let resp = await this.rpc.sendJsonRequest("import_key_images", {signed_key_images: rpcKeyImages});
-    
-    // build and return result
-    let importResult = new MoneroKeyImageImportResult();
-    importResult.setHeight(resp.result.height);
-    importResult.setSpentAmount(new BigInteger(resp.result.spent));
-    importResult.setUnspentAmount(new BigInteger(resp.result.unspent));
-    return importResult;
-  }
-  
-  async getNewKeyImagesFromLastImport() {
-    return await this._rpcExportKeyImages(false);
-  }
-  
-  async relayTxs(txsOrMetadatas) {
-    assert(Array.isArray(txsOrMetadatas), "Must provide an array of txs or their metadata to relay");
-    let txHashes = [];
-    for (let txOrMetadata of txsOrMetadatas) {
-      let metadata = txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata;
-      let resp = await this.rpc.sendJsonRequest("relay_tx", { hex: metadata });
-      txHashes.push(resp.result.tx_hash);
-    }
-    return txHashes;
-  }
-
-  async createTxs(config) {
-    
-    // validate, copy, and normalize config
-    config = MoneroWallet._normalizeCreateTxsConfig(config);
-    if (config.getCanSplit() === undefined) config.setCanSplit(true);
-    if (config.getRelay() === true && await this.isMultisig()) throw new MoneroError("Cannot relay multisig transaction until co-signed");
-
-    // determine account and subaddresses to send from
-    let accountIdx = config.getAccountIndex();
-    if (accountIdx === undefined) throw new MoneroError("Must provide the account index to send from");
-    let subaddressIndices = config.getSubaddressIndices() === undefined ? undefined : config.getSubaddressIndices().slice(0); // fetch all or copy given indices
-    
-    // build config parameters
-    let params = {};
-    params.destinations = [];
-    for (let destination of config.getDestinations()) {
-      assert(destination.getAddress(), "Destination address is not defined");
-      assert(destination.getAmount(), "Destination amount is not defined");
-      params.destinations.push({ address: destination.getAddress(), amount: destination.getAmount().toString() });
-    }
-    params.account_index = accountIdx;
-    params.subaddr_indices = subaddressIndices;
-    params.payment_id = config.getPaymentId();
-    params.unlock_time = config.getUnlockHeight();
-    params.do_not_relay = config.getRelay() !== true;
-    assert(config.getPriority() === undefined || config.getPriority() >= 0 && config.getPriority() <= 3);
-    params.priority = config.getPriority();
-    params.get_tx_hex = true;
-    params.get_tx_metadata = true;
-    if (config.getCanSplit()) params.get_tx_keys = true; // param to get tx key(s) depends if split
-    else params.get_tx_key = true;
-    
-    // send request
-    let resp = await this.rpc.sendJsonRequest(config.getCanSplit() ? "transfer_split" : "transfer", params);
-    let result = resp.result;
-    
-    // pre-initialize txs iff present.  multisig and view-only wallets will have tx set without transactions
-    let txs;
-    let numTxs = config.getCanSplit() ? (result.fee_list !== undefined ? result.fee_list.length : 0) : (result.fee !== undefined ? 1 : 0);
-    if (numTxs > 0) txs = [];
-    for (let i = 0; i < numTxs; i++) {
-      let tx = new MoneroTxWallet();
-      MoneroWalletRpc._initSentTxWallet(config, tx);
-      tx.getOutgoingTransfer().setAccountIndex(accountIdx);
-      if (subaddressIndices !== undefined && subaddressIndices.length === 1) tx.getOutgoingTransfer().setSubaddressIndices(subaddressIndices);
-      txs.push(tx);
-    }
-    
-    // initialize tx set from rpc response with pre-initialized txs
-    if (config.getCanSplit()) return MoneroWalletRpc._convertRpcSentTxsToTxSet(result, txs).getTxs();
-    else return MoneroWalletRpc._convertRpcTxToTxSet(result, txs === undefined ? undefined : txs[0], true).getTxs();
-  }
-  
-  async sweepOutput(config) {
-    
-    // normalize and validate config
-    config = MoneroWallet._normalizeSweepOutputConfig(config);
-    
-    // build config parameters
-    let params = {};
-    params.address = config.getDestinations()[0].getAddress();
-    params.account_index = config.getAccountIndex();
-    params.subaddr_indices = config.getSubaddressIndices();
-    params.key_image = config.getKeyImage();
-    params.unlock_time = config.getUnlockHeight();
-    params.do_not_relay = config.getRelay() !== true;
-    assert(config.getPriority() === undefined || config.getPriority() >= 0 && config.getPriority() <= 3);
-    params.priority = config.getPriority();
-    params.payment_id = config.getPaymentId();
-    params.get_tx_key = true;
-    params.get_tx_hex = true;
-    params.get_tx_metadata = true;
-    
-    // send request
-    let resp = await this.rpc.sendJsonRequest("sweep_single", params);
-    let result = resp.result;
-    
-    // build and return tx response
-    let tx = MoneroWalletRpc._initSentTxWallet(config, null);
-    let txSet = MoneroWalletRpc._convertRpcTxToTxSet(result, tx, true);
-    tx.getOutgoingTransfer().getDestinations()[0].setAmount(tx.getOutgoingTransfer().getAmount());  // initialize destination amount
-    return tx;
-  }
-  
-  async sweepUnlocked(config) {
-    
-    // validate and normalize config
-    config = MoneroWallet._normalizeSweepUnlockedConfig(config);
-    
-    // determine account and subaddress indices to sweep; default to all with unlocked balance if not specified
-    let indices = new Map();  // maps each account index to subaddress indices to sweep
-    if (config.getAccountIndex() !== undefined) {
-      if (config.getSubaddressIndices() !== undefined) {
-        indices.set(config.getAccountIndex(), config.getSubaddressIndices());
-      } else {
-        let subaddressIndices = [];
-        indices.set(config.getAccountIndex(), subaddressIndices);
-        for (let subaddress of await this.getSubaddresses(config.getAccountIndex())) {
-          if (subaddress.getUnlockedBalance().compare(new BigInteger(0)) > 0) subaddressIndices.push(subaddress.getIndex());
-        }
-      }
-    } else {
-      let accounts = await this.getAccounts(true);
-      for (let account of accounts) {
-        if (account.getUnlockedBalance().compare(new BigInteger(0)) > 0) {
-          let subaddressIndices = [];
-          indices.set(account.getIndex(), subaddressIndices);
-          for (let subaddress of account.getSubaddresses()) {
-            if (subaddress.getUnlockedBalance().compare(new BigInteger(0)) > 0) subaddressIndices.push(subaddress.getIndex());
-          }
-        }
-      }
-    }
-    
-    // sweep from each account and collect resulting tx sets
-    let txs = [];
-    for (let accountIdx of indices.keys()) {
-      
-      // copy and modify the original config
-      let copy = config.copy();
-      copy.setAccountIndex(accountIdx);
-      copy.setSweepEachSubaddress(false);
-      
-      // sweep all subaddresses together  // TODO monero core: can this reveal outputs belong to the same wallet?
-      if (copy.getSweepEachSubaddress() !== true) {
-        copy.setSubaddressIndices(indices.get(accountIdx));
-        for (let tx of await this._rpcSweepAccount(copy)) txs.push(tx);
-      }
-      
-      // otherwise sweep each subaddress individually
-      else {
-        for (let subaddressIdx of indices.get(accountIdx)) {
-          copy.setSubaddressIndices([subaddressIdx]);
-          for (let tx of await this._rpcSweepAccount(copy)) txs.push(tx);
-        }
-      }
-    }
-    
-    return txs;
-  }
-  
-  async sweepDust(relay) {
-    if (relay === undefined) relay = false;
-    let resp = await this.rpc.sendJsonRequest("sweep_dust", {do_not_relay: !relay});
-    let result = resp.result;
-    let txSet = MoneroWalletRpc._convertRpcSentTxsToTxSet(result);
-    if (txSet.getTxs() !== undefined) {
-      for (let tx of txSet.getTxs()) {
-        tx.setIsRelayed(!relay);
-        tx.setInTxPool(tx.isRelayed());
-      }
-    } else if (txSet.getMultisigTxHex() === undefined && txSet.getSignedTxHex() === undefined && txSet.getUnsignedTxHex() === undefined) {
-      throw new MoneroError("No dust to sweep");
-    }
-    return txSet.getTxs();
-  }
-  
-  async parseTxSet(txSet) {
-    let resp = await this.rpc.sendJsonRequest("describe_transfer", {
-      unsigned_txset: txSet.getUnsignedTxHex(),
-      multisig_txset: txSet.getMultisigTxHex()
-    });
-    return MoneroWalletRpc._convertRpcDescribeTransfer(resp.result);
-  }
-  
-  async signTxs(unsignedTxHex) {
-    let resp = await this.rpc.sendJsonRequest("sign_transfer", {
-      unsigned_txset: unsignedTxHex,
-      export_raw: false
-    });
-    return resp.result.signed_txset
-  }
-  
-  async submitTxs(signedTxHex) {
-    let resp = await this.rpc.sendJsonRequest("submit_transfer", {
-      tx_data_hex: signedTxHex
-    });
-    return resp.result.tx_hash_list;
-  }
-  
-  async signMessage(message) {
-    let resp = await this.rpc.sendJsonRequest("sign", {data: message});
-    return resp.result.signature;
-  }
-  
-  async verifyMessage(message, address, signature) {
-    let resp = await this.rpc.sendJsonRequest("verify", {data: message, address: address, signature: signature});
-    return resp.result.good;
-  }
-  
-  async getTxKey(txHash) {
-    try {
-      return (await this.rpc.sendJsonRequest("get_tx_key", {txid: txHash})).result.tx_key;
-    } catch (e) {
-      if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams());  // normalize error message
-      throw e;
-    }
-  }
-  
-  async checkTxKey(txHash, txKey, address) {
-    try {
-      
-      // send request
-      let resp = await this.rpc.sendJsonRequest("check_tx_key", {txid: txHash, tx_key: txKey, address: address});
-      
-      // interpret result
-      let check = new MoneroCheckTx();
-      check.setIsGood(true);
-      check.setNumConfirmations(resp.result.confirmations);
-      check.setInTxPool(resp.result.in_pool);
-      check.setReceivedAmount(new BigInteger(resp.result.received));
-      return check;
-    } catch (e) {
-      if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams());  // normalize error message
-      throw e;
-    }
-  }
-  
-  async getTxProof(txHash, address, message) {
-    try {
-      let resp = await this.rpc.sendJsonRequest("get_tx_proof", {txid: txHash, address: address, message: message});
-      return resp.result.signature;
-    } catch (e) {
-      if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams());  // normalize error message
-      throw e;
-    }
-  }
-  
-  async checkTxProof(txHash, address, message, signature) {
-    try {
-      
-      // send request
-      let resp = await this.rpc.sendJsonRequest("check_tx_proof", {
-        txid: txHash,
-        address: address,
-        message: message,
-        signature: signature
-      });
-      
-      // interpret response
-      let isGood = resp.result.good;
-      let check = new MoneroCheckTx();
-      check.setIsGood(isGood);
-      if (isGood) {
-        check.setNumConfirmations(resp.result.confirmations);
-        check.setInTxPool(resp.result.in_pool);
-        check.setReceivedAmount(new BigInteger(resp.result.received));
-      }
-      return check;
-    } catch (e) {
-      if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams());  // normalize error message
-      throw e;
-    }
-  }
-  
-  async getSpendProof(txHash, message) {
-    try {
-      let resp = await this.rpc.sendJsonRequest("get_spend_proof", {txid: txHash, message: message});
-      return resp.result.signature;
-    } catch (e) {
-      if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams());  // normalize error message
-      throw e;
-    }
-  }
-  
-  async checkSpendProof(txHash, message, signature) {
-    try {
-      let resp = await this.rpc.sendJsonRequest("check_spend_proof", {
-        txid: txHash,
-        message: message,
-        signature: signature
-      });
-      return resp.result.good;
-    } catch (e) {
-      if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams());  // normalize error message
-      throw e;
-    }
-  }
-  
-  async getReserveProofWallet(message) {
-    let resp = await this.rpc.sendJsonRequest("get_reserve_proof", {
-      all: true,
-      message: message
-    });
-    return resp.result.signature;
-  }
-  
-  async getReserveProofAccount(accountIdx, amount, message) {
-    let resp = await this.rpc.sendJsonRequest("get_reserve_proof", {
-      account_index: accountIdx,
-      amount: amount.toString(),
-      message: message
-    });
-    return resp.result.signature;
-  }
-
-  async checkReserveProof(address, message, signature) {
-    
-    // send request
-    let resp = await this.rpc.sendJsonRequest("check_reserve_proof", {
-      address: address,
-      message: message,
-      signature: signature
-    });
-    
-    // interpret results
-    let isGood = resp.result.good;
-    let check = new MoneroCheckReserve();
-    check.setIsGood(isGood);
-    if (isGood) {
-      check.setUnconfirmedSpentAmount(new BigInteger(resp.result.spent));
-      check.setTotalAmount(new BigInteger(resp.result.total));
-    }
-    return check;
-  }
-  
-  async getTxNotes(txHashes) {
-    return (await this.rpc.sendJsonRequest("get_tx_notes", {txids: txHashes})).result.notes;
-  }
-  
-  async setTxNotes(txHashes, notes) {
-    await this.rpc.sendJsonRequest("set_tx_notes", {txids: txHashes, notes: notes});
-  }
-  
-  async getAddressBookEntries(entryIndices) {
-    let resp = await this.rpc.sendJsonRequest("get_address_book", {entries: entryIndices});
-    if (!resp.result.entries) return [];
-    let entries = [];
-    for (let rpcEntry of resp.result.entries) {
-      entries.push(new MoneroAddressBookEntry().setIndex(rpcEntry.index).setAddress(rpcEntry.address).setDescription(rpcEntry.description).setPaymentId(rpcEntry.payment_id));
-    }
-    return entries;
-  }
-  
-  async addAddressBookEntry(address, description) {
-    let resp = await this.rpc.sendJsonRequest("add_address_book", {address: address, description: description});
-    return resp.result.index;
-  }
-  
-  async editAddressBookEntry(index, setAddress, address, setDescription, description) {
-    let resp = await this.rpc.sendJsonRequest("edit_address_book", {
-      index: index,
-      set_address: setAddress,
-      address: address,
-      set_description: setDescription,
-      description: description
-    });
-  }
-  
-  async deleteAddressBookEntry(entryIdx) {
-    await this.rpc.sendJsonRequest("delete_address_book", {index: entryIdx});
-  }
-  
-  async tagAccounts(tag, accountIndices) {
-    await this.rpc.sendJsonRequest("tag_accounts", {tag: tag, accounts: accountIndices});
-  }
-
-  async untagAccounts(accountIndices) {
-    await this.rpc.sendJsonRequest("untag_accounts", {accounts: accountIndices});
-  }
-
-  async getAccountTags() {
-    let tags = [];
-    let resp = await this.rpc.sendJsonRequest("get_account_tags");
-    if (resp.result.account_tags) {
-      for (let rpcAccountTag of resp.result.account_tags) {
-        tags.push(new MoneroAccountTag(rpcAccountTag.tag ? rpcAccountTag.tag : undefined, rpcAccountTag.label ? rpcAccountTag.label : undefined, rpcAccountTag.accounts));
-      }
-    }
-    return tags;
-  }
-
-  async setAccountTagLabel(tag, label) {
-    await this.rpc.sendJsonRequest("set_account_tag_description", {tag: tag, description: label});
-  }
-  
-  async createPaymentUri(config) {
-    config = MoneroWallet._normalizeCreateTxsConfig(config);
-    let resp = await this.rpc.sendJsonRequest("make_uri", {
-      address: config.getDestinations()[0].getAddress(),
-      amount: config.getDestinations()[0].getAmount() ? config.getDestinations()[0].getAmount().toString() : undefined,
-      payment_id: config.getPaymentId(),
-      recipient_name: config.getRecipientName(),
-      tx_description: config.getNote()
-    });
-    return resp.result.uri;
-  }
-  
-  async parsePaymentUri(uri) {
-    assert(uri, "Must provide URI to parse");
-    let resp = await this.rpc.sendJsonRequest("parse_uri", {uri: uri});
-    let config = new MoneroTxConfig({address: resp.result.uri.address, amount: new BigInteger(resp.result.uri.amount)});
-    config.setPaymentId(resp.result.uri.payment_id);
-    config.setRecipientName(resp.result.uri.recipient_name);
-    config.setNote(resp.result.uri.tx_description);
-    if ("" === config.getDestinations()[0].getAddress()) config.getDestinations()[0].setAddress(undefined);
-    if ("" === config.getPaymentId()) config.setPaymentId(undefined);
-    if ("" === config.getRecipientName()) config.setRecipientName(undefined);
-    if ("" === config.getNote()) config.setNote(undefined);
-    return config;
-  }
-  
-  async getAttribute(key) {
-    try {
-      let resp = await this.rpc.sendJsonRequest("get_attribute", {key: key});
-      return resp.result.value === "" ? undefined : resp.result.value;
-    } catch (e) {
-      if (e instanceof MoneroRpcError && e.getCode() === -45) return undefined;
-      throw e;
-    }
-  }
-  
-  async setAttribute(key, val) {
-    await this.rpc.sendJsonRequest("set_attribute", {key: key, value: val});
-  }
-  
-  async startMining(numThreads, backgroundMining, ignoreBattery) {
-    await this.rpc.sendJsonRequest("start_mining", {
-      threads_count: numThreads,
-      do_background_mining: backgroundMining,
-      ignore_battery: ignoreBattery
-    });
-  }
-  
-  async stopMining() {
-    await this.rpc.sendJsonRequest("stop_mining");
-  }
-  
-  async isMultisigImportNeeded() {
-    let resp = await this.rpc.sendJsonRequest("get_balance");
-    return resp.result.multisig_import_needed === true;
-  }
-  
-  async getMultisigInfo() {
-    let resp = await this.rpc.sendJsonRequest("is_multisig");
-    let result = resp.result;
-    let info = new MoneroMultisigInfo();
-    info.setIsMultisig(result.multisig);
-    info.setIsReady(result.ready);
-    info.setThreshold(result.threshold);
-    info.setNumParticipants(result.total);
-    return info;
-  }
-  
-  async prepareMultisig() {
-    let resp = await this.rpc.sendJsonRequest("prepare_multisig");
-    let result = resp.result;
-    return result.multisig_info;
-  }
-  
-  async makeMultisig(multisigHexes, threshold, password) {
-    let resp = await this.rpc.sendJsonRequest("make_multisig", {
-      multisig_info: multisigHexes,
-      threshold: threshold,
-      password: password
-    });
-    let result = resp.result;
-    let msResult = new MoneroMultisigInitResult();
-    msResult.setAddress(result.address);
-    msResult.setMultisigHex(result.multisig_info);
-    if (msResult.getAddress().length === 0) msResult.setAddress(undefined);
-    if (msResult.getMultisigHex().length === 0) msResult.setMultisigHex(undefined);
-    return msResult;
-  }
-  
-  async exchangeMultisigKeys(multisigHexes, password) {
-    let resp = await this.rpc.sendJsonRequest("exchange_multisig_keys", {multisig_info: multisigHexes, password: password});
-    let msResult = new MoneroMultisigInitResult();
-    msResult.setAddress(resp.result.address);
-    msResult.setMultisigHex(resp.result.multisig_info);
-    if (msResult.getAddress().length === 0) msResult.setAddress(undefined);
-    if (msResult.getMultisigHex().length === 0) msResult.setMultisigHex(undefined);
-    return msResult;
-  }
-  
-  async getMultisigHex() {
-    let resp = await this.rpc.sendJsonRequest("export_multisig_info");
-    return resp.result.info;
-  }
-
-  async importMultisigHex(multisigHexes) {
-    let resp = await this.rpc.sendJsonRequest("import_multisig_info", {info: multisigHexes});
-    return resp.result.n_outputs;
-  }
-
-  async signMultisigTxHex(multisigTxHex) {
-    let resp = await this.rpc.sendJsonRequest("sign_multisig", {tx_data_hex: multisigTxHex});
-    let result = resp.result;
-    let signResult = new MoneroMultisigSignResult();
-    signResult.setSignedMultisigTxHex(result.tx_data_hex);
-    signResult.setTxHashes(result.tx_hash_list);
-    return signResult;
-  }
-
-  async submitMultisigTxHex(signedMultisigTxHex) {
-    let resp = await this.rpc.sendJsonRequest("submit_multisig", {tx_data_hex: signedMultisigTxHex});
-    return resp.result.tx_hash_list;
-  }
-  
-  async save() {
-    await this.rpc.sendJsonRequest("store");
-  }
-  
-  async close(save) {
-    if (save === undefined) save = false;
-    this._clear();
-    await this.rpc.sendJsonRequest("close_wallet", {autosave_current: save});
-  }
-  
-  async isClosed() {
-    try {
-      await this.getPrimaryAddress();
-    } catch (e) {
-      return e instanceof MoneroRpcError && e.getCode() === -13 && e.message.indexOf("No wallet file") > -1;
-    }
-    return false;
-  }
-  
-  /**
-   * Save and close the current wallet and stop the RPC server.
-   */
-  async stop() {
-    this._clear();
-    await this.rpc.sendJsonRequest("stop_wallet");
-  }
-  
-  // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS --------------
-  
-  async getTx() { return super.getTx(...arguments); }
-  async getIncomingTransfers() { return super.getIncomingTransfers(...arguments); }
-  async getOutgoingTransfers() { return super.getOutgoingTransfers(...arguments); }
-  async createTx() { return super.createTx(...arguments); }
-  async relayTx() { return super.relayTx(...arguments); }
-  async getTxNote() { return super.getTxNote(...arguments); }
-  async setTxNote() { return super.setTxNote(...arguments); }
-  
-  // -------------------------------- PRIVATE ---------------------------------
-  
-  async _clear() {
-    delete this.addressCache;
-    this.addressCache = {};
-    this.path = undefined;
-  }
-  
-  async _getBalances(accountIdx, subaddressIdx) {
-    if (accountIdx === undefined) {
-      assert.equal(subaddressIdx, undefined, "Must provide account index with subaddress index");
-      let balance = new BigInteger(0);
-      let unlockedBalance = new BigInteger(0);
-      for (let account of await this.getAccounts()) {
-        balance = balance.add(account.getBalance());
-        unlockedBalance = unlockedBalance.add(account.getUnlockedBalance());
-      }
-      return [balance, unlockedBalance];
-    } else {
-      let params = {account_index: accountIdx, address_indices: subaddressIdx === undefined ? undefined : [subaddressIdx]};
-      let resp = await this.rpc.sendJsonRequest("get_balance", params);
-      if (subaddressIdx === undefined) return [new BigInteger(resp.result.balance), new BigInteger(resp.result.unlocked_balance)];
-      else return [new BigInteger(resp.result.per_subaddress[0].balance), new BigInteger(resp.result.per_subaddress[0].unlocked_balance)];
-    }
-  }
-  
-  async _getAccountIndices(getSubaddressIndices) {
-    let indices = new Map();
-    for (let account of await this.getAccounts()) {
-      indices.set(account.getIndex(), getSubaddressIndices ? await this._getSubaddressIndices(account.getIndex()) : undefined);
-    }
-    return indices;
-  }
-  
-  async _getSubaddressIndices(accountIdx) {
-    let subaddressIndices = [];
-    let resp = await this.rpc.sendJsonRequest("get_address", {account_index: accountIdx});
-    for (let address of resp.result.addresses) subaddressIndices.push(address.address_index);
-    return subaddressIndices;
-  }
-  
-  async _getTransfersAux(query) {
-    
-    // check if pool txs explicitly requested without daemon connection
-    let txQuery = query.getTxQuery();
-    if (txQuery.inTxPool() !== undefined && txQuery.inTxPool() && !await this.isConnected()) {
-      throw new MoneroError("Cannot fetch pool transactions because wallet has no daemon connection");
-    }
-    
-    // build params for get_transfers rpc call
-    let params = {};
-    let canBeConfirmed = txQuery.isConfirmed() !== false && txQuery.inTxPool() !== true && txQuery.isFailed() !== true && txQuery.isRelayed() !== false;
-    let canBeInTxPool = await this.isConnected() && txQuery.isConfirmed() !== true && txQuery.inTxPool() !== false && txQuery.isFailed() !== true && txQuery.isRelayed() !== false && txQuery.getHeight() === undefined && txQuery.getMinHeight() === undefined && txQuery.getMaxHeight() === undefined;
-    let canBeIncoming = query.isIncoming() !== false && query.isOutgoing() !== true && query.hasDestinations() !== true;
-    let canBeOutgoing = query.isOutgoing() !== false && query.isIncoming() !== true;
-    params.in = canBeIncoming && canBeConfirmed;
-    params.out = canBeOutgoing && canBeConfirmed;
-    params.pool = canBeIncoming && canBeInTxPool;
-    params.pending = canBeOutgoing && canBeInTxPool;
-    params.failed = txQuery.isFailed() !== false && txQuery.isConfirmed() !== true && txQuery.inTxPool() != true;
-    if (txQuery.getMinHeight() !== undefined) {
-      if (txQuery.getMinHeight() > 0) params.min_height = txQuery.getMinHeight() - 1; // TODO monero core: wallet2::get_payments() min_height is exclusive, so manually offset to match intended range (issues #5751, #5598)
-      else params.min_height = txQuery.getMinHeight();
-    }
-    if (txQuery.getMaxHeight() !== undefined) params.max_height = txQuery.getMaxHeight();
-    params.filter_by_height = txQuery.getMinHeight() !== undefined || txQuery.getMaxHeight() !== undefined;
-    if (query.getAccountIndex() === undefined) {
-      assert(query.getSubaddressIndex() === undefined && query.getSubaddressIndices() === undefined, "Query specifies a subaddress index but not an account index");
-      params.all_accounts = true;
-    } else {
-      params.account_index = query.getAccountIndex();
-      
-      // set subaddress indices param
-      let subaddressIndices = new Set();
-      if (query.getSubaddressIndex() !== undefined) subaddressIndices.add(query.getSubaddressIndex());
-      if (query.getSubaddressIndices() !== undefined) query.getSubaddressIndices().map(subaddressIdx => subaddressIndices.add(subaddressIdx));
-      if (subaddressIndices.size) params.subaddr_indices = Array.from(subaddressIndices);
-    }
-    
-    // cache unique txs and blocks
-    let txMap = {};
-    let blockMap = {};
-    
-    // build txs using `get_transfers`
-    let resp = await this.rpc.sendJsonRequest("get_transfers", params);
-    for (let key of Object.keys(resp.result)) {
-      for (let rpcTx of resp.result[key]) {
-        //if (rpcTx.txid === query.debugTxId) console.log(rpcTx);
-        let tx = MoneroWalletRpc._convertRpcTxWithTransfer(rpcTx);
-        if (tx.isConfirmed()) assert(tx.getBlock().getTxs().indexOf(tx) > -1);
-        
-        // replace transfer amount with destination sum
-        // TODO monero-wallet-rpc: confirmed tx from/to same account has amount 0 but cached transfers
-        if (tx.getOutgoingTransfer() !== undefined && tx.isRelayed() && !tx.isFailed() &&
-            tx.getOutgoingTransfer().getDestinations() && tx.getOutgoingAmount().compare(new BigInteger(0)) === 0) {
-          let outgoingTransfer = tx.getOutgoingTransfer();
-          let transferTotal = new BigInteger(0);
-          for (let destination of outgoingTransfer.getDestinations()) transferTotal = transferTotal.add(destination.getAmount());
-          tx.getOutgoingTransfer().setAmount(transferTotal);
-        }
-        
-        // merge tx
-        MoneroWalletRpc._mergeTx(tx, txMap, blockMap, false);
-      }
-    }
-    
-    // sort txs by block height
-    let txs = Object.values(txMap);
-    txs.sort(MoneroWalletRpc._compareTxsByHeight);
-    
-    // filter and return transfers
-    let transfers = [];
-    for (let tx of txs) {
-      
-      // tx is not incoming/outgoing unless already set
-      if (tx.isIncoming() === undefined) tx.setIsIncoming(false);
-      if (tx.isOutgoing() === undefined) tx.setIsOutgoing(false);
-      
-      // sort incoming transfers
-      if (tx.getIncomingTransfers() !== undefined) tx.getIncomingTransfers().sort(MoneroWalletRpc._compareIncomingTransfers);
-      
-      // collect queried transfers, erase if excluded
-      for (let transfer of tx.filterTransfers(query)) {
-        transfers.push(transfer);
-      }
-      
-      // remove txs without requested transfer
-      if (tx.getBlock() !== undefined && tx.getOutgoingTransfer() === undefined && tx.getIncomingTransfers() === undefined) {
-        tx.getBlock().getTxs().splice(tx.getBlock().getTxs().indexOf(tx), 1);
-      }
-    }
-    
-    return transfers;
-  }
-  
-  async _getOutputsAux(query) {
-    
-    // determine account and subaddress indices to be queried
-    let indices = new Map();
-    if (query.getAccountIndex() !== undefined) {
-      let subaddressIndices = new Set();
-      if (query.getSubaddressIndex() !== undefined) subaddressIndices.add(query.getSubaddressIndex());
-      if (query.getSubaddressIndices() !== undefined) query.getSubaddressIndices().map(subaddressIdx => subaddressIndices.add(subaddressIdx));
-      indices.set(query.getAccountIndex(), subaddressIndices.size ? Array.from(subaddressIndices) : undefined);  // undefined will fetch from all subaddresses
-    } else {
-      assert.equal(query.getSubaddressIndex(), undefined, "Query specifies a subaddress index but not an account index")
-      assert(query.getSubaddressIndices() === undefined || query.getSubaddressIndices().length === 0, "Query specifies subaddress indices but not an account index");
-      indices = await this._getAccountIndices();  // fetch all account indices without subaddresses
-    }
-    
-    // cache unique txs and blocks
-    let txMap = {};
-    let blockMap = {};
-    
-    // collect txs with outputs for each indicated account using `incoming_transfers` rpc call
-    let params = {};
-    params.transfer_type = query.isSpent() === true ? "unavailable" : query.isSpent() === false ? "available" : "all";
-    params.verbose = true;
-    for (let accountIdx of indices.keys()) {
-    
-      // send request
-      params.account_index = accountIdx;
-      params.subaddr_indices = indices.get(accountIdx);
-      let resp = await this.rpc.sendJsonRequest("incoming_transfers", params);
-      
-      // convert response to txs with outputs and merge
-      if (resp.result.transfers === undefined) continue;
-      for (let rpcOutput of resp.result.transfers) {
-        let tx = MoneroWalletRpc._convertRpcTxWalletWithOutput(rpcOutput);
-        MoneroWalletRpc._mergeTx(tx, txMap, blockMap, false);
-      }
-    }
-    
-    // sort txs by block height
-    let txs = Object.values(txMap);
-    txs.sort(MoneroWalletRpc._compareTxsByHeight);
-    
-    // collect queried outputs
-    let outputs = [];
-    for (let tx of txs) {
-      
-      // sort outputs
-      if (tx.getOutputs() !== undefined) tx.getOutputs().sort(MoneroWalletRpc._compareOutputs);
-      
-      // collect queried outputs, erase if excluded
-      for (let output of tx.filterOutputs(query)) outputs.push(output);
-      
-      // remove excluded txs from block
-      if (tx.getOutputs() === undefined && tx.getBlock() !== undefined) {
-        tx.getBlock().getTxs().splice(tx.getBlock().getTxs().indexOf(tx), 1);
-      }
-    }
-    return outputs;
-  }
-  
-  /**
-   * Common method to get key images.
-   * 
-   * @param all - pecifies to get all xor only new images from last import
-   * @return {MoneroKeyImage[]} are the key images
-   */
-  async _rpcExportKeyImages(all) {
-    let resp = await this.rpc.sendJsonRequest("export_key_images", {all: all});
-    if (!resp.result.signed_key_images) return [];
-    return resp.result.signed_key_images.map(rpcImage => new MoneroKeyImage(rpcImage.key_image, rpcImage.signature));
-  }
-  
-  async _rpcSweepAccount(config) {
-    
-    // validate config
-    if (config === undefined) throw new MoneroError("Must provide sweep config");
-    if (config.getAccountIndex() === undefined) throw new MoneroError("Must provide an account index to sweep from");
-    if (config.getDestinations() === undefined || config.getDestinations().length != 1) throw new MoneroError("Must provide exactly one destination to sweep to");
-    if (config.getDestinations()[0].getAddress() === undefined) throw new MoneroError("Must provide destination address to sweep to");
-    if (config.getDestinations()[0].getAmount() !== undefined) throw new MoneroError("Cannot specify amount in sweep config");
-    if (config.getKeyImage() !== undefined) throw new MoneroError("Key image defined; use sweepOutput() to sweep an output by its key image");
-    if (config.getSubaddressIndices() !== undefined && config.getSubaddressIndices().length === 0) throw new MoneroError("Empty list given for subaddresses indices to sweep");
-    if (config.getSweepEachSubaddress()) throw new MoneroError("Cannot sweep each subaddress with RPC `sweep_all`");
-    
-    // sweep from all subaddresses if not otherwise defined
-    if (config.getSubaddressIndices() === undefined) {
-      config.setSubaddressIndices([]);
-      for (let subaddress of await this.getSubaddresses(config.getAccountIndex())) {
-        config.getSubaddressIndices().push(subaddress.getIndex());
-      }
-    }
-    if (config.getSubaddressIndices().length === 0) throw new MoneroError("No subaddresses to sweep from");
-    
-    // common config params
-    let params = {};
-    let relay = config.getRelay() === true;
-    params.account_index = config.getAccountIndex();
-    params.subaddr_indices = config.getSubaddressIndices();
-    params.address = config.getDestinations()[0].getAddress();
-    assert(config.getPriority() === undefined || config.getPriority() >= 0 && config.getPriority() <= 3);
-    params.priority = config.getPriority();
-    params.unlock_time = config.getUnlockHeight();
-    params.payment_id = config.getPaymentId();
-    params.do_not_relay = !relay;
-    params.below_amount = config.getBelowAmount();
-    params.get_tx_keys = true;
-    params.get_tx_hex = true;
-    params.get_tx_metadata = true;
-    
-    // invoke wallet rpc `sweep_all`
-    let resp = await this.rpc.sendJsonRequest("sweep_all", params);
-    let result = resp.result;
-    
-    // initialize txs from response
-    let txSet = MoneroWalletRpc._convertRpcSentTxsToTxSet(result);
-    
-    // initialize remaining known fields
-    for (let tx of txSet.getTxs()) {
-      tx.setIsLocked(true);
-      tx.setIsConfirmed(false);
-      tx.setNumConfirmations(0);
-      tx.setRelay(relay);
-      tx.setInTxPool(relay);
-      tx.setIsRelayed(relay);
-      tx.setIsMinerTx(false);
-      tx.setIsFailed(false);
-      tx.setRingSize(MoneroUtils.RING_SIZE);
-      let transfer = tx.getOutgoingTransfer();
-      transfer.setAccountIndex(config.getAccountIndex());
-      if (config.getSubaddressIndices().length === 1) transfer.setSubaddressIndices(config.getSubaddressIndices());
-      let destination = new MoneroDestination(config.getDestinations()[0].getAddress(), new BigInteger(transfer.getAmount()));
-      transfer.setDestinations([destination]);
-      tx.setOutgoingTransfer(transfer);
-      tx.setPaymentId(config.getPaymentId());
-      if (tx.getUnlockHeight() === undefined) tx.setUnlockHeight(config.getUnlockHeight() === undefined ? 0 : config.getUnlockHeight());
-      if (tx.getRelay()) {
-        if (tx.getLastRelayedTimestamp() === undefined) tx.setLastRelayedTimestamp(+new Date().getTime());  // TODO (monero-wallet-rpc): provide timestamp on response; unconfirmed timestamps vary
-        if (tx.isDoubleSpendSeen() === undefined) tx.setIsDoubleSpend(false);
-      }
-    }
-    return txSet.getTxs();
-  }
-  
-  // ---------------------------- PRIVATE STATIC ------------------------------
-  
-  /**
-   * Remove criteria which requires looking up other transfers/outputs to
-   * fulfill query.
-   * 
-   * @param {MoneroTxQuery} query - the query to decontextualize
-   * @return {MoneroTxQuery} a reference to the query for convenience
-   */
-  static _decontextualize(query) {
-    query.setIsIncoming(undefined);
-    query.setIsOutgoing(undefined);
-    query.setTransferQuery(undefined);
-    query.setOutputQuery(undefined);
-    return query;
-  }
-  
-  static _isContextual(query) {
-    if (!query) return false;
-    if (!query.getTxQuery()) return false;
-    if (query.getTxQuery().isIncoming() !== undefined) return true; // requires getting other transfers
-    if (query.getTxQuery().isOutgoing() !== undefined) return true;
-    if (query instanceof MoneroTransferQuery) {
-      if (query.getTxQuery().getOutputQuery() !== undefined) return true; // requires getting other outputs
-    } else if (query instanceof MoneroOutputQuery) {
-      if (query.getTxQuery().getTransferQuery() !== undefined) return true; // requires getting other transfers
-    } else {
-      throw new MoneroError("query must be tx or transfer query");
-    }
-    return false;
-  }
-  
-  static _convertRpcAccount(rpcAccount) {
-    let account = new MoneroAccount();
-    for (let key of Object.keys(rpcAccount)) {
-      let val = rpcAccount[key];
-      if (key === "account_index") account.setIndex(val);
-      else if (key === "balance") account.setBalance(new BigInteger(val));
-      else if (key === "unlocked_balance") account.setUnlockedBalance(new BigInteger(val));
-      else if (key === "base_address") account.setPrimaryAddress(val);
-      else if (key === "tag") account.setTag(val);
-      else if (key === "label") { } // label belongs to first subaddress
-      else console.log("WARNING: ignoring unexpected account field: " + key + ": " + val);
-    }
-    if ("" === account.getTag()) account.setTag(undefined);
-    return account;
-  }
-  
-  static _convertRpcSubaddress(rpcSubaddress) {
-    let subaddress = new MoneroSubaddress();
-    for (let key of Object.keys(rpcSubaddress)) {
-      let val = rpcSubaddress[key];
-      if (key === "account_index") subaddress.setAccountIndex(val);
-      else if (key === "address_index") subaddress.setIndex(val);
-      else if (key === "address") subaddress.setAddress(val);
-      else if (key === "balance") subaddress.setBalance(new BigInteger(val));
-      else if (key === "unlocked_balance") subaddress.setUnlockedBalance(new BigInteger(val));
-      else if (key === "num_unspent_outputs") subaddress.setNumUnspentOutputs(val);
-      else if (key === "label") { if (val) subaddress.setLabel(val); }
-      else if (key === "used") subaddress.setIsUsed(val);
-      else if (key === "blocks_to_unlock") subaddress.setNumBlocksToUnlock(val);
-      else if (key == "time_to_unlock") {}  // ignoring
-      else console.log("WARNING: ignoring unexpected subaddress field: " + key + ": " + val);
-    }
-    return subaddress;
-  }
-  
-  /**
-   * Initializes a sent transaction.
-   * 
-   * @param {MoneroTxConfig} config - send config
-   * @param {MoneroTxWallet} tx - existing transaction to initialize (optional)
-   * @return {MoneroTxWallet} is the initialized send tx
-   */
-  static _initSentTxWallet(config, tx) {
-    if (!tx) tx = new MoneroTxWallet();
-    let relay = config.getRelay() === true;
-    tx.setIsOutgoing(true);
-    tx.setIsConfirmed(false);
-    tx.setNumConfirmations(0);
-    tx.setInTxPool(relay);
-    tx.setRelay(relay);
-    tx.setIsRelayed(relay);
-    tx.setIsMinerTx(false);
-    tx.setIsFailed(false);
-    tx.setIsLocked(true);
-    tx.setRingSize(MoneroUtils.RING_SIZE);
-    let transfer = new MoneroOutgoingTransfer().setTx(tx);
-    if (config.getSubaddressIndices() && config.getSubaddressIndices().length === 1) transfer.setSubaddressIndices(config.getSubaddressIndices().slice(0)); // we know src subaddress indices iff config specifies 1
-    let destCopies = [];
-    for (let dest of config.getDestinations()) destCopies.push(dest.copy());
-    transfer.setDestinations(destCopies);
-    tx.setOutgoingTransfer(transfer);
-    tx.setPaymentId(config.getPaymentId());
-    if (tx.getUnlockHeight() === undefined) tx.setUnlockHeight(config.getUnlockHeight() === undefined ? 0 : config.getUnlockHeight());
-    if (config.getRelay()) {
-      if (tx.getLastRelayedTimestamp() === undefined) tx.setLastRelayedTimestamp(+new Date().getTime());  // TODO (monero-wallet-rpc): provide timestamp on response; unconfirmed timestamps vary
-      if (tx.isDoubleSpendSeen() === undefined) tx.setIsDoubleSpend(false);
-    }
-    return tx;
-  }
-  
-  /**
-   * Initializes a tx set from a RPC map excluding txs.
-   * 
-   * @param rpcMap - map to initialize the tx set from
-   * @return MoneroTxSet - initialized tx set
-   * @return the resulting tx set
-   */
-  static _convertRpcTxSet(rpcMap) {
-    let txSet = new MoneroTxSet();
-    txSet.setMultisigTxHex(rpcMap.multisig_txset);
-    txSet.setUnsignedTxHex(rpcMap.unsigned_txset);
-    txSet.setSignedTxHex(rpcMap.signed_txset);
-    if (txSet.getMultisigTxHex() !== undefined && txSet.getMultisigTxHex().length === 0) txSet.setMultisigTxHex(undefined);
-    if (txSet.getUnsignedTxHex() !== undefined && txSet.getUnsignedTxHex().length === 0) txSet.setUnsignedTxHex(undefined);
-    if (txSet.getSignedTxHex() !== undefined && txSet.getSignedTxHex().length === 0) txSet.setSignedTxHex(undefined);
-    return txSet;
-  }
-  
-  /**
-   * Initializes a MoneroTxSet from from a list of rpc txs.
-   * 
-   * @param rpcTxs - rpc txs to initialize the set from
-   * @param txs - existing txs to further initialize (optional)
-   * @return the converted tx set
-   */
-  static _convertRpcSentTxsToTxSet(rpcTxs, txs) {
-    
-    // build shared tx set
-    let txSet = MoneroWalletRpc._convertRpcTxSet(rpcTxs);
-    
-    // get number of txs
-    let numTxs = rpcTxs.fee_list ? rpcTxs.fee_list.length : 0;
-    
-    // done if rpc response contains no txs
-    if (numTxs === 0) {
-      assert.equal(txs, undefined);
-      return txSet;
-    }
-    
-    // pre-initialize txs if none given
-    if (txs) txSet.setTxs(txs);
-    else {
-      txs = [];
-      for (let i = 0; i < numTxs; i++) txs.push(new MoneroTxWallet());
-    }
-    for (let tx of txs) {
-      tx.setTxSet(txSet);
-      tx.setIsOutgoing(true);
-    }
-    txSet.setTxs(txs);
-    
-    // initialize txs from rpc lists
-    for (let key of Object.keys(rpcTxs)) {
-      let val = rpcTxs[key];
-      if (key === "tx_hash_list") for (let i = 0; i < val.length; i++) txs[i].setHash(val[i]);
-      else if (key === "tx_key_list") for (let i = 0; i < val.length; i++) txs[i].setKey(val[i]);
-      else if (key === "tx_blob_list") for (let i = 0; i < val.length; i++) txs[i].setFullHex(val[i]);
-      else if (key === "tx_metadata_list") for (let i = 0; i < val.length; i++) txs[i].setMetadata(val[i]);
-      else if (key === "fee_list") for (let i = 0; i < val.length; i++) txs[i].setFee(new BigInteger(val[i]));
-      else if (key === "weight_list") for (let i = 0; i < val.length; i++) txs[i].setWeight(val[i]);
-      else if (key === "amount_list") {
-        for (let i = 0; i < val.length; i++) {
-          if (txs[i].getOutgoingTransfer() !== undefined) txs[i].getOutgoingTransfer().setAmount(new BigInteger(val[i]));
-          else txs[i].setOutgoingTransfer(new MoneroOutgoingTransfer().setTx(txs[i]).setAmount(new BigInteger(val[i])));
-        }
-      }
-      else if (key === "multisig_txset" || key === "unsigned_txset" || key === "signed_txset") {} // handled elsewhere
-      else LOGGER.warning("WARNING: ignoring unexpected transaction field: " + key + ": " + val);
-    }
-    
-    return txSet;
-  }
-  
-  /**
-   * Converts a rpc tx with a transfer to a tx set with a tx and transfer.
-   * 
-   * @param rpcTx - rpc tx to build from
-   * @param tx - existing tx to continue initializing (optional)
-   * @param isOutgoing - specifies if the tx is outgoing if true, incoming if false, or decodes from type if undefined
-   * @returns the initialized tx set with a tx
-   */
-  static _convertRpcTxToTxSet(rpcTx, tx, isOutgoing) {
-    let txSet = MoneroWalletRpc._convertRpcTxSet(rpcTx);
-    txSet.setTxs([MoneroWalletRpc._convertRpcTxWithTransfer(rpcTx, tx, isOutgoing).setTxSet(txSet)]);
-    return txSet;
-  }
-  
-  /**
-   * Builds a MoneroTxWallet from a RPC tx.
-   * 
-   * @param rpcTx - rpc tx to build from
-   * @param tx - existing tx to continue initializing (optional)
-   * @param isOutgoing - specifies if the tx is outgoing if true, incoming if false, or decodes from type if undefined
-   * @returns {MoneroTxWallet} is the initialized tx
-   */
-  static _convertRpcTxWithTransfer(rpcTx, tx, isOutgoing) {  // TODO: change everything to safe set
-        
-    // initialize tx to return
-    if (!tx) tx = new MoneroTxWallet();
-    
-    // initialize tx state from rpc type
-    if (rpcTx.type !== undefined) isOutgoing = MoneroWalletRpc._decodeRpcType(rpcTx.type, tx);
-    else assert.equal(typeof isOutgoing, "boolean", "Must indicate if tx is outgoing (true) xor incoming (false) since unknown");
-    
-    // TODO: safe set
-    // initialize remaining fields  TODO: seems this should be part of common function with DaemonRpc._convertRpcTx
-    let header;
-    let transfer;
-    for (let key of Object.keys(rpcTx)) {
-      let val = rpcTx[key];
-      if (key === "txid") tx.setHash(val);
-      else if (key === "tx_hash") tx.setHash(val);
-      else if (key === "fee") tx.setFee(new BigInteger(val));
-      else if (key === "note") { if (val) tx.setNote(val); }
-      else if (key === "tx_key") tx.setKey(val);
-      else if (key === "type") { } // type already handled
-      else if (key === "tx_size") tx.setSize(val);
-      else if (key === "unlock_time") tx.setUnlockHeight(val);
-      else if (key === "weight") tx.setWeight(val);
-      else if (key === "locked") tx.setIsLocked(val);
-      else if (key === "tx_blob") tx.setFullHex(val);
-      else if (key === "tx_metadata") tx.setMetadata(val);
-      else if (key === "double_spend_seen") tx.setIsDoubleSpend(val);
-      else if (key === "block_height" || key === "height") {
-        if (tx.isConfirmed()) {
-          if (!header) header = new MoneroBlockHeader();
-          header.setHeight(val);
-        }
-      }
-      else if (key === "timestamp") {
-        if (tx.isConfirmed()) {
-          if (!header) header = new MoneroBlockHeader();
-          header.setTimestamp(val);
-        } else {
-          // timestamp of unconfirmed tx is current request time
-        }
-      }
-      else if (key === "confirmations") tx.setNumConfirmations(val);
-      else if (key === "suggested_confirmations_threshold") {
-        if (transfer === undefined) transfer = (isOutgoing ? new MoneroOutgoingTransfer() : new MoneroIncomingTransfer()).setTx(tx);
-        if (!isOutgoing) transfer.setNumSuggestedConfirmations(val);
-      }
-      else if (key === "amount") {
-        if (transfer === undefined) transfer = (isOutgoing ? new MoneroOutgoingTransfer() : new MoneroIncomingTransfer()).setTx(tx);
-        transfer.setAmount(new BigInteger(val));
-      }
-      else if (key === "amounts") {}  // ignoring, amounts sum to amount
-      else if (key === "address") {
-        if (!isOutgoing) {
-          if (!transfer) transfer = new MoneroIncomingTransfer().setTx(tx);
-          transfer.setAddress(val);
-        }
-      }
-      else if (key === "payment_id") {
-        if ("" !== val && MoneroTxWallet.DEFAULT_PAYMENT_ID !== val) tx.setPaymentId(val);  // default is undefined
-      }
-      else if (key === "subaddr_index") assert(rpcTx.subaddr_indices);  // handled by subaddr_indices
-      else if (key === "subaddr_indices") {
-        if (!transfer) transfer = (isOutgoing ? new MoneroOutgoingTransfer() : new MoneroIncomingTransfer()).setTx(tx);
-        let rpcIndices = val;
-        transfer.setAccountIndex(rpcIndices[0].major);
-        if (isOutgoing) {
-          let subaddressIndices = [];
-          for (let rpcIndex of rpcIndices) subaddressIndices.push(rpcIndex.minor);
-          transfer.setSubaddressIndices(subaddressIndices);
-        } else {
-          assert.equal(rpcIndices.length, 1);
-          transfer.setSubaddressIndex(rpcIndices[0].minor);
-        }
-      }
-      else if (key === "destinations" || key == "recipients") {
-        assert(isOutgoing);
-        let destinations = [];
-        for (let rpcDestination of val) {
-          let destination = new MoneroDestination();
-          destinations.push(destination);
-          for (let destinationKey of Object.keys(rpcDestination)) {
-            if (destinationKey === "address") destination.setAddress(rpcDestination[destinationKey]);
-            else if (destinationKey === "amount") destination.setAmount(new BigInteger(rpcDestination[destinationKey]));
-            else throw new MoneroError("Unrecognized transaction destination field: " + destinationKey);
-          }
-        }
-        if (transfer === undefined) transfer = new MoneroOutgoingTransfer({tx: tx});
-        transfer.setDestinations(destinations);
-      }
-      else if (key === "multisig_txset" && val !== undefined) {} // handled elsewhere; this method only builds a tx wallet
-      else if (key === "unsigned_txset" && val !== undefined) {} // handled elsewhere; this method only builds a tx wallet
-      else if (key === "amount_in") tx.setInputSum(new BigInteger(val));
-      else if (key === "amount_out") tx.setOutputSum(new BigInteger(val));
-      else if (key === "change_address") tx.setChangeAddress(val === "" ? undefined : val);
-      else if (key === "change_amount") tx.setChangeAmount(new BigInteger(val));
-      else if (key === "dummy_outputs") tx.setNumDummyOutputs(val);
-      else if (key === "extra") tx.setExtraHex(val);
-      else if (key === "ring_size") tx.setRingSize(val);
-      else console.log("WARNING: ignoring unexpected transaction field: " + key + ": " + val);
-    }
-    
-    // link block and tx
-    if (header) tx.setBlock(new MoneroBlock(header).setTxs([tx]));
-    
-    // initialize final fields
-    if (transfer) {
-      if (tx.isConfirmed() === undefined) tx.setIsConfirmed(false);
-      if (!transfer.getTx().isConfirmed()) tx.setNumConfirmations(0);
-      if (isOutgoing) {
-        tx.setIsOutgoing(true);
-        if (tx.getOutgoingTransfer()) tx.getOutgoingTransfer().merge(transfer);
-        else tx.setOutgoingTransfer(transfer);
-      } else {
-        tx.setIsIncoming(true);
-        tx.setIncomingTransfers([transfer]);
-      }
-    }
-    
-    // return initialized transaction
-    return tx;
-  }
-  
-  static _convertRpcTxWalletWithOutput(rpcOutput) {
-    
-    // initialize tx
-    let tx = new MoneroTxWallet();
-    tx.setIsConfirmed(true);
-    tx.setIsRelayed(true);
-    tx.setIsFailed(false);
-    
-    // initialize output
-    let output = new MoneroOutputWallet({tx: tx});
-    for (let key of Object.keys(rpcOutput)) {
-      let val = rpcOutput[key];
-      if (key === "amount") output.setAmount(new BigInteger(val));
-      else if (key === "spent") output.setIsSpent(val);
-      else if (key === "key_image") { if ("" !== val) output.setKeyImage(new MoneroKeyImage(val)); }
-      else if (key === "global_index") output.setIndex(val);
-      else if (key === "tx_hash") tx.setHash(val);
-      else if (key === "unlocked") tx.setIsLocked(!val);
-      else if (key === "frozen") output.setIsFrozen(val);
-      else if (key === "subaddr_index") {
-        output.setAccountIndex(val.major);
-        output.setSubaddressIndex(val.minor);
-      }
-      else if (key === "block_height") tx.setBlock(new MoneroBlock().setHeight(val).setTxs([tx]));
-      else console.log("WARNING: ignoring unexpected transaction field: " + key + ": " + val);
-    }
-    
-    // initialize tx with output
-    tx.setOutputs([output]);
-    return tx;
-  }
-  
-  static _convertRpcDescribeTransfer(rpcDescribeTransferResult) {
-    let txSet = new MoneroTxSet();
-    for (let key of Object.keys(rpcDescribeTransferResult)) {
-      let val = rpcDescribeTransferResult[key];
-      if (key === "desc") {
-        txSet.setTxs([]);
-        for (let txMap of val) {
-          let tx = MoneroWalletRpc._convertRpcTxWithTransfer(txMap, undefined, true);
-          txSet.getTxs().push(tx);
-        }
-      }
-      else console.log("WARNING: ignoring unexpected descdribe transfer field: " + key + ": " + val);
-    }
-    return txSet;
-  }
-  
-  /**
-   * Decodes a "type" from monero-wallet-rpc to initialize type and state
-   * fields in the given transaction.
-   * 
-   * TODO: these should be safe set
-   * 
-   * @param rpcType is the type to decode
-   * @param tx is the transaction to decode known fields to
-   * @return {boolean} true if the rpc type indicates outgoing xor incoming
-   */
-  static _decodeRpcType(rpcType, tx) {
-    let isOutgoing;
-    if (rpcType === "in") {
-      isOutgoing = false;
-      tx.setIsConfirmed(true);
-      tx.setInTxPool(false);
-      tx.setIsRelayed(true);
-      tx.setRelay(true);
-      tx.setIsFailed(false);
-      tx.setIsMinerTx(false);
-    } else if (rpcType === "out") {
-      isOutgoing = true;
-      tx.setIsConfirmed(true);
-      tx.setInTxPool(false);
-      tx.setIsRelayed(true);
-      tx.setRelay(true);
-      tx.setIsFailed(false);
-      tx.setIsMinerTx(false);
-    } else if (rpcType === "pool") {
-      isOutgoing = false;
-      tx.setIsConfirmed(false);
-      tx.setInTxPool(true);
-      tx.setIsRelayed(true);
-      tx.setRelay(true);
-      tx.setIsFailed(false);
-      tx.setIsMinerTx(false);  // TODO: but could it be?
-    } else if (rpcType === "pending") {
-      isOutgoing = true;
-      tx.setIsConfirmed(false);
-      tx.setInTxPool(true);
-      tx.setIsRelayed(true);
-      tx.setRelay(true);
-      tx.setIsFailed(false);
-      tx.setIsMinerTx(false);
-    } else if (rpcType === "block") {
-      isOutgoing = false;
-      tx.setIsConfirmed(true);
-      tx.setInTxPool(false);
-      tx.setIsRelayed(true);
-      tx.setRelay(true);
-      tx.setIsFailed(false);
-      tx.setIsMinerTx(true);
-    } else if (rpcType === "failed") {
-      isOutgoing = true;
-      tx.setIsConfirmed(false);
-      tx.setInTxPool(false);
-      tx.setIsRelayed(true);
-      tx.setRelay(true);
-      tx.setIsFailed(true);
-      tx.setIsMinerTx(false);
-    } else {
-      throw new MoneroError("Unrecognized transfer type: " + rpcType);
-    }
-    return isOutgoing;
-  }
-  
-  /**
-   * Merges a transaction into a unique set of transactions.
-   *
-   * TODO monero core: skipIfAbsent only necessary because incoming payments not returned
-   * when sent from/to same account #4500
-   *
-   * @param tx is the transaction to merge into the existing txs
-   * @param txMap maps tx hashes to txs
-   * @param blockMap maps block heights to blocks
-   * @param skipIfAbsent specifies if the tx should not be added if it doesn't already exist
-   */
-  static _mergeTx(tx, txMap, blockMap, skipIfAbsent) {
-    assert(tx.getHash() !== undefined);
-
-    // if tx doesn't exist, add it (unless skipped)
-    let aTx = txMap[tx.getHash()];
-    if (aTx === undefined) {
-      if (!skipIfAbsent) {
-        txMap[tx.getHash()] = tx;
-      } else {
-        console.log("WARNING: tx does not already exist");
-      }
-    }
-
-    // otherwise merge with existing tx
-    else {
-      aTx.merge(tx);
-    }
-
-    // if confirmed, merge tx's block
-    if (tx.getHeight() !== undefined) {
-      let aBlock = blockMap[tx.getHeight()];
-      if (aBlock === undefined) {
-        blockMap[tx.getHeight()] = tx.getBlock();
-      } else {
-        aBlock.merge(tx.getBlock());
-      }
-    }
-  }
-  
-  /**
-   * Compares two transactions by their height.
-   */
-  static _compareTxsByHeight(tx1, tx2) {
-    if (tx1.getHeight() === undefined && tx2.getHeight() === undefined) return 0; // both unconfirmed
-    else if (tx1.getHeight() === undefined) return 1;   // tx1 is unconfirmed
-    else if (tx2.getHeight() === undefined) return -1;  // tx2 is unconfirmed
-    let diff = tx1.getHeight() - tx2.getHeight();
-    if (diff !== 0) return diff;
-    return tx1.getBlock().getTxs().indexOf(tx1) - tx2.getBlock().getTxs().indexOf(tx2); // txs are in the same block so retain their original order
-  }
-  
-  /**
-   * Compares two transfers by ascending account and subaddress indices.
-   */
-  static _compareIncomingTransfers(t1, t2) {
-    if (t1.getAccountIndex() < t2.getAccountIndex()) return -1;
-    else if (t1.getAccountIndex() === t2.getAccountIndex()) return t1.getSubaddressIndex() - t2.getSubaddressIndex();
-    return 1;
-  }
-  
-  /**
-   * Compares two outputs by ascending account and subaddress indices.
-   */
-  static _compareOutputs(o1, o2) {
-    
-    // compare by height
-    let heightComparison = MoneroWalletRpc._compareTxsByHeight(o1.getTx(), o2.getTx());
-    if (heightComparison !== 0) return heightComparison;
-    
-    // compare by account index, subaddress index, output index, then key image hex
-    let compare = o1.getAccountIndex() - o2.getAccountIndex();
-    if (compare !== 0) return compare;
-    compare = o1.getSubaddressIndex() - o2.getSubaddressIndex();
-    if (compare !== 0) return compare;
-    compare = o1.getIndex() - o2.getIndex();
-    if (compare !== 0) return compare;
-    return o1.getKeyImage().getHex().compare(o2.getKeyImage().getHex());
-  }
-}
-
-module.exports = MoneroWalletRpc;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_MoneroWalletWasm.js.html b/docs/src_main_js_wallet_MoneroWalletWasm.js.html deleted file mode 100644 index 8e82d597b..000000000 --- a/docs/src_main_js_wallet_MoneroWalletWasm.js.html +++ /dev/null @@ -1,2576 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/MoneroWalletWasm.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/MoneroWalletWasm.js

- - - - - - -
-
-
const assert = require("assert");
-const BigInteger = require("../common/biginteger").BigInteger;
-const GenUtils = require("../common/GenUtils");
-const LibraryUtils = require("../common/LibraryUtils");
-const MoneroAccount = require("./model/MoneroAccount");
-const MoneroAddressBookEntry = require("./model/MoneroAddressBookEntry");
-const MoneroBlock = require("../daemon/model/MoneroBlock");
-const MoneroCheckTx = require("./model/MoneroCheckTx");
-const MoneroDaemonRpc = require("../daemon/MoneroDaemonRpc");
-const MoneroError = require("../common/MoneroError");
-const MoneroIntegratedAddress = require("./model/MoneroIntegratedAddress");
-const MoneroKeyImage = require("../daemon/model/MoneroKeyImage");
-const MoneroKeyImageImportResult = require("./model/MoneroKeyImageImportResult");
-const MoneroMultisigInfo = require("./model/MoneroMultisigInfo");
-const MoneroMultisigInitResult = require("./model/MoneroMultisigInitResult");
-const MoneroMultisigSignResult = require("./model/MoneroMultisigSignResult");
-const MoneroNetworkType = require("../daemon/model/MoneroNetworkType");
-const MoneroOutputWallet = require("./model/MoneroOutputWallet");
-const MoneroRpcConnection = require("../common/MoneroRpcConnection");
-const MoneroSubaddress = require("./model/MoneroSubaddress");
-const MoneroSyncResult = require("./model/MoneroSyncResult");
-const MoneroTxConfig = require("./model/MoneroTxConfig");
-const MoneroTxSet = require("./model/MoneroTxSet");
-const MoneroTxWallet = require("./model/MoneroTxWallet");
-const MoneroUtils = require("../common/MoneroUtils");
-const MoneroWallet = require("./MoneroWallet");
-const MoneroWalletConfig = require("./model/MoneroWalletConfig");
-const MoneroWalletKeys = require("./MoneroWalletKeys");
-const MoneroWalletListener = require("./model/MoneroWalletListener");
-
-/**
- * Implements a MoneroWallet using WebAssembly bindings to monero-project's wallet2.
- * 
- * @extends {MoneroWalletKeys}
- * @implements {MoneroWallet}
- * @hideconstructor
- */
-class MoneroWalletWasm extends MoneroWalletKeys {
-  
-  // --------------------------- STATIC UTILITIES -----------------------------
-  
-  /**
-   * Check if a wallet exists at a given path.
-   * 
-   * @param {string} path - path of the wallet on the file system
-   * @param {fs} - Node.js compatible file system to use (optional, defaults to disk if nodejs)
-   * @return {boolean} true if a wallet exists at the given path, false otherwise
-   */
-  static async walletExists(path, fs) {
-    assert(path, "Must provide a path to look for a wallet");
-    if (!fs) fs = MoneroWalletWasm._getFs();
-    if (!fs) throw new MoneroError("Must provide file system to check if wallet exists");
-    let exists = fs.existsSync(path); // TODO: look for keys file
-    console.log("Wallet exists at " + path + ": " + exists);
-    return exists;
-  }
-  
-  /**
-   * <p>Open an existing wallet using WebAssembly bindings to wallet2.h.</p>
-   * 
-   * <p>Examples:<p>
-   * 
-   * <code>
-   * let wallet1 = await MoneroWalletWasm.openWallet(<br>
-   * &nbsp;&nbsp; "./wallets/wallet1",<br>
-   * &nbsp;&nbsp; "supersecretpassword",<br>
-   * &nbsp;&nbsp; MoneroNetworkType.STAGENET,<br>
-   * &nbsp;&nbsp; "http://localhost:38081" // daemon uri<br>
-   * );<br><br>
-   * 
-   * let wallet2 = await MoneroWalletWasm.openWallet({<br>
-   * &nbsp;&nbsp; path: "./wallets/wallet2",<br>
-   * &nbsp;&nbsp; password: "supersecretpassword",<br>
-   * &nbsp;&nbsp; networkType: MoneroNetworkType.STAGENET,<br>
-   * &nbsp;&nbsp; serverUri: "http://localhost:38081", // daemon configuration<br>
-   * &nbsp;&nbsp; serverUsername: "superuser",<br>
-   * &nbsp;&nbsp; serverPassword: "abctesting123"<br>
-   * });
-   * </code>
-   * 
-   * @param {MoneroWalletConfig|object|string} configOrPath - MoneroWalletConfig or equivalent config object or a path to a wallet to open
-   * @param {string} configOrPath.path - path of the wallet to open (optional if 'keysData' provided)
-   * @param {string} configOrPath.password - password of the wallet to open
-   * @param {string|number} configOrPath.networkType - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
-   * @param {Uint8Array} configOrPath.keysData - wallet keys data to open (optional if path provided)
-   * @param {Uint8Array} configOrPath.cacheData - wallet cache data to open (optional)
-   * @param {string} configOrPath.serverUri - uri of the wallet's daemon (optional)
-   * @param {string} configOrPath.serverUsername - username to authenticate with the daemon (optional)
-   * @param {string} configOrPath.serverPassword - password to authenticate with the daemon (optional)
-   * @param {boolean} configOrPath.rejectUnauthorized - reject self-signed server certificates if true (defaults to true)
-   * @param {MoneroRpcConnection|object} configOrPath.server - MoneroRpcConnection or equivalent JS object configuring the daemon connection (optional)
-   * @param {boolean} configOrPath.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)
-   * @param {fs} configOrPath.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
-   * @param {string} password - password of the wallet to open
-   * @param {string|number} networkType - network type of the wallet to open
-   * @param {string|MoneroRpcConnection} daemonUriOrConnection - daemon URI or MoneroRpcConnection
-   * @param {boolean} proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)
-   * @param {fs} fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
-   * @return {MoneroWalletWasm} the opened wallet
-   */
-  static async openWallet(configOrPath, password, networkType, daemonUriOrConnection, proxyToWorker, fs) {
-
-    // normalize and validate config
-    let config;
-    if (typeof configOrPath === "object") {
-      config = configOrPath instanceof MoneroWalletConfig ? configOrPath : new MoneroWalletConfig(configOrPath);
-      if (password !== undefined || networkType !== undefined || daemonUriOrConnection !== undefined || proxyToWorker !== undefined || fs !== undefined) throw new MoneroError("Can specify config object or params but not both when opening WASM wallet")
-    } else {
-      config = new MoneroWalletConfig().setPath(configOrPath).setPassword(password).setNetworkType(networkType).setProxyToWorker(proxyToWorker).setFs(fs);
-      if (typeof daemonUriOrConnection === "object") config.setServer(daemonUriOrConnection);
-      else config.setServerUri(daemonUriOrConnection);
-    }
-    if (config.getProxyToWorker() === undefined) config.setProxyToWorker(GenUtils.isBrowser());
-    if (config.getMnemonic() !== undefined) throw new MoneroError("Cannot specify mnemonic when opening wallet");
-    if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot specify seed offset when opening wallet");
-    if (config.getPrimaryAddress() !== undefined) throw new MoneroError("Cannot specify primary address when opening wallet");
-    if (config.getPrivateViewKey() !== undefined) throw new MoneroError("Cannot specify private view key when opening wallet");
-    if (config.getPrivateSpendKey() !== undefined) throw new MoneroError("Cannot specify private spend key when opening wallet");
-    if (config.getRestoreHeight() !== undefined) throw new MoneroError("Cannot specify restore height when opening wallet");
-    if (config.getLanguage() !== undefined) throw new MoneroError("Cannot specify language when opening wallet");
-    if (config.getSaveCurrent() === true) throw new MoneroError("Cannot save current wallet when opening JNI wallet");
-    
-    // read wallet data from disk if not provided
-    if (!config.getKeysData()) {
-      let fs = config.getFs() ? config.getFs() : MoneroWalletWasm._getFs();
-      if (!fs) throw new MoneroError("Must provide file system to read wallet data from");
-      if (!await this.walletExists(config.getPath(), fs)) throw new MoneroError("Wallet does not exist at path: " + config.getPath());
-      config.setKeysData(fs.readFileSync(config.getPath() + ".keys"));
-      config.setCacheData(fs.readFileSync(config.getPath()));
-    }
-    
-    // open wallet from data
-    return MoneroWalletWasm._openWalletData(config.getPath(), config.getPassword(), config.getNetworkType(), config.getKeysData(), config.getCacheData(), config.getServer(), config.getProxyToWorker(), config.getFs());
-  }
-  
-  /**
-   * <p>Create a wallet using WebAssembly bindings to wallet2.h.<p>
-   * 
-   * <p>Example:</p>
-   * 
-   * <code>
-   * let wallet = await MoneroWalletWasm.createWallet({<br>
-   * &nbsp;&nbsp; path: "./test_wallets/wallet1", // leave blank for in-memory wallet<br>
-   * &nbsp;&nbsp; password: "supersecretpassword",<br>
-   * &nbsp;&nbsp; networkType: MoneroNetworkType.STAGENET,<br>
-   * &nbsp;&nbsp; mnemonic: "coexist igloo pamphlet lagoon...",<br>
-   * &nbsp;&nbsp; restoreHeight: 1543218,<br>
-   * &nbsp;&nbsp; server: new MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123"),<br>
-   * });
-   * </code>
-   * 
-   * @param {object|MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object
-   * @param {string} config.path - path of the wallet to create (optional, in-memory wallet if not given)
-   * @param {string} config.password - password of the wallet to create
-   * @param {string|number} config.networkType - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
-   * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given)
-   * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase
-   * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys)
-   * @param {string} config.privateViewKey - private view key of the wallet to create (optional)
-   * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional)
-   * @param {number} config.restoreHeight - block height to start scanning from (defaults to 0 unless generating random wallet)
-   * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected)
-   * @param {string} config.serverUri - uri of the wallet's daemon (optional)
-   * @param {string} config.serverUsername - username to authenticate with the daemon (optional)
-   * @param {string} config.serverPassword - password to authenticate with the daemon (optional)
-   * @param {boolean} config.rejectUnauthorized - reject self-signed server certificates if true (defaults to true)
-   * @param {MoneroRpcConnection|object} config.server - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional)
-   * @param {boolean} config.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise)
-   * @param {fs} config.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
-   * @return {MoneroWalletWasm} the created wallet
-   */
-  static async createWallet(config) {
-    
-    // normalize and validate config
-    if (config === undefined) throw new MoneroError("Must provide config to create wallet");
-    config = config instanceof MoneroWalletConfig ? config : new MoneroWalletConfig(config);
-    if (config.getMnemonic() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) {
-      throw new MoneroError("Wallet may be initialized with a mnemonic or keys but not both");
-    } // TODO: factor this much out to common
-    if (config.getNetworkType() === undefined) throw new MoneroError("Must provide a networkType: 'mainnet', 'testnet' or 'stagenet'");
-    if (config.getSaveCurrent() === true) throw new MoneroError("Cannot save current wallet when creating WASM wallet");
-    
-    // create wallet
-    if (config.getMnemonic() !== undefined) {
-      if (config.getLanguage() !== undefined) throw new MoneroError("Cannot provide language when creating wallet from mnemonic");
-      return MoneroWalletWasm._createWalletFromMnemonic(config.getPath(), config.getPassword(), config.getNetworkType(), config.getMnemonic(), config.getServer(), config.getRestoreHeight(), config.getSeedOffset(), config.getProxyToWorker(), config.getFs());
-    } else if (config.getPrimaryAddress() !== undefined) {
-      if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating wallet from keys");
-      return MoneroWalletWasm._createWalletFromKeys(config.getPath(), config.getPassword(), config.getNetworkType(), config.getPrimaryAddress(), config.getPrivateViewKey(), config.getPrivateSpendKey(), config.getServer(), config.getRestoreHeight(), config.getLanguage(), config.getProxyToWorker(), config.getFs());
-    } else {
-      if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating random wallet");
-      if (config.getRestoreHeight() !== undefined) throw new MoneroError("Cannot provide restoreHeight when creating random wallet");
-      return MoneroWalletWasm._createWalletRandom(config.getPath(), config.getPassword(), config.getNetworkType(), config.getServer(), config.getLanguage(), config.getProxyToWorker(), config.getFs());
-    }
-  }
-  
-  static async _createWalletRandom(path, password, networkType, daemonUriOrConnection, language, proxyToWorker, fs) {
-    if (proxyToWorker === undefined) proxyToWorker = GenUtils.isBrowser();
-    if (proxyToWorker) return MoneroWalletWasmProxy._createWalletRandom(path, password, networkType, daemonUriOrConnection, language, fs);
-    
-    // validate and normalize params
-    if (path === undefined) path = "";
-    if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error("Wallet already exists: " + path);
-    assert(password, "Must provide a password to create the wallet with");
-    MoneroNetworkType.validate(networkType);
-    if (language === undefined) language = "English";
-    let daemonConnection = typeof daemonUriOrConnection === "string" ? new MoneroRpcConnection(daemonUriOrConnection) : daemonUriOrConnection;
-    let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : "";
-    let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : "";
-    let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : "";
-    let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true;
-    
-    // load wasm module
-    let module = await LibraryUtils.loadCoreModule();
-    
-    // create wallet in queue
-    let wallet = await module.queueTask(async function() {
-      return new Promise(function(resolve, reject) {
-        
-        // register fn informing if unauthorized reqs should be rejected
-        let rejectUnauthorizedFnId = GenUtils.getUUID();
-        LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return rejectUnauthorized });
-      
-        // define callback for wasm
-        let callbackFn = async function(cppAddress) {
-          if (typeof cppAddress === "string") reject(new MoneroError(cppAddress));
-          else resolve(new MoneroWalletWasm(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId));
-        };
-        
-        // create wallet in wasm and invoke callback when done
-        module.create_core_wallet_random(password, networkType, daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, language, callbackFn);
-      });
-    });
-    
-    // save wallet
-    if (path) await wallet.save();
-    return wallet;
-  }
-  
-  static async _createWalletFromMnemonic(path, password, networkType, mnemonic, daemonUriOrConnection, restoreHeight, seedOffset, proxyToWorker, fs) {
-    if (proxyToWorker === undefined) proxyToWorker = GenUtils.isBrowser();
-    if (proxyToWorker) return MoneroWalletWasmProxy._createWalletFromMnemonic(path, password, networkType, mnemonic, daemonUriOrConnection, restoreHeight, seedOffset, fs);
-    
-    // validate and normalize params
-    if (path === undefined) path = "";
-    if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error("Wallet already exists: " + path);
-    assert(password, "Must provide a password to create the wallet with");
-    MoneroNetworkType.validate(networkType);
-    let daemonConnection = typeof daemonUriOrConnection === "string" ? new MoneroRpcConnection(daemonUriOrConnection) : daemonUriOrConnection;
-    let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : "";
-    let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : "";
-    let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : "";
-    let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true;
-    if (restoreHeight === undefined) restoreHeight = 0;
-    if (seedOffset === undefined) seedOffset = "";
-    
-    // load wasm module
-    let module = await LibraryUtils.loadCoreModule();
-    
-    // create wallet in queue
-    let wallet = await module.queueTask(async function() {
-      return new Promise(function(resolve, reject) {
-        
-        // register fn informing if unauthorized reqs should be rejected
-        let rejectUnauthorizedFnId = GenUtils.getUUID();
-        LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return rejectUnauthorized });
-      
-        // define callback for wasm
-        let callbackFn = async function(cppAddress) {
-          if (typeof cppAddress === "string") reject(new MoneroError(cppAddress));
-          else resolve(new MoneroWalletWasm(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId));
-        };
-        
-        // create wallet in wasm and invoke callback when done
-        module.create_core_wallet_from_mnemonic(password, networkType, mnemonic, daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, restoreHeight, seedOffset, callbackFn);
-      });
-    });
-    
-    // save wallet
-    if (path) await wallet.save();
-    return wallet;
-  }
-  
-  static async _createWalletFromKeys(path, password, networkType, address, viewKey, spendKey, daemonUriOrConnection, restoreHeight, language, proxyToWorker, fs) {
-    if (proxyToWorker === undefined) proxyToWorker = GenUtils.isBrowser();
-    if (proxyToWorker) return MoneroWalletWasmProxy._createWalletFromKeys(path, password, networkType, address, viewKey, spendKey, daemonUriOrConnection, restoreHeight, language, fs);
-    
-    // validate and normalize params
-    if (path === undefined) path = "";
-    if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error("Wallet already exists: " + path);
-    assert(password, "Must provide a password to create the wallet with");
-    MoneroNetworkType.validate(networkType);
-    if (address === undefined) address = "";
-    if (viewKey === undefined) viewKey = "";
-    if (spendKey === undefined) spendKey = "";
-    let daemonConnection = typeof daemonUriOrConnection === "string" ? new MoneroRpcConnection(daemonUriOrConnection) : daemonUriOrConnection;
-    let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : "";
-    let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : "";
-    let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : "";
-    let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true;
-    if (restoreHeight === undefined) restoreHeight = 0;
-    if (language === undefined) language = "English";
-    
-    // load wasm module
-    let module = await LibraryUtils.loadCoreModule();
-    
-    // create wallet in queue
-    let wallet = await module.queueTask(async function() {
-      return new Promise(function(resolve, reject) {
-        
-        // register fn informing if unauthorized reqs should be rejected
-        let rejectUnauthorizedFnId = GenUtils.getUUID();
-        LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return rejectUnauthorized });
-      
-        // define callback for wasm
-        let callbackFn = async function(cppAddress) {
-          if (typeof cppAddress === "string") reject(new MoneroError(cppAddress));
-          else resolve(new MoneroWalletWasm(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId));
-        };
-        
-        // create wallet in wasm and invoke callback when done
-        module.create_core_wallet_from_keys(password, networkType, address, viewKey, spendKey, daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, restoreHeight, language, callbackFn);
-      });
-    });
-    
-    // save wallet
-    if (path) await wallet.save();
-    return wallet;
-  }
-  
-  static async getMnemonicLanguages() {
-    let module = await LibraryUtils.loadCoreModule();
-    return module.queueTask(async function() {
-      return JSON.parse(module.get_keys_wallet_mnemonic_languages()).languages;
-    });
-  }
-  
-  // --------------------------- INSTANCE METHODS -----------------------------
-  
-  /**
-   * Internal constructor which is given the memory address of a C++ wallet
-   * instance.
-   * 
-   * This method should not be called externally but should be called through
-   * static wallet creation utilities in this class.
-   * 
-   * @param {int} cppAddress - address of the wallet instance in C++
-   * @param {string} path - path of the wallet instance
-   * @param {string} password - password of the wallet instance
-   * @param {FileSystem} fs - node.js-compatible file system to read/write wallet files
-   * @param {boolean} rejectUnauthorized - specifies if unauthorized requests (e.g. self-signed certificates) should be rejected
-   * @param {string} rejectUnauthorizedFnId - unique identifier for http_client_wasm to query rejectUnauthorized
-   */
-  constructor(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId) {
-    super(cppAddress);
-    this._path = path;
-    this._password = password;
-    this._listeners = [];
-    this._fs = fs ? fs : (path ? MoneroWalletWasm._getFs() : undefined);
-    this._isClosed = false;
-    this._wasmListener = new WalletWasmListener(this); // receives notifications from wasm c++
-    this._wasmListenerHandle = 0;                      // memory address of the wallet listener in c++
-    this._rejectUnauthorized = rejectUnauthorized;
-    this._rejectUnauthorizedConfigId = rejectUnauthorizedFnId;
-    let that = this;
-    LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return that._rejectUnauthorized }); // register fn informing if unauthorized reqs should be rejected
-  }
-  
-  // ------------ WALLET METHODS SPECIFIC TO WASM IMPLEMENTATION --------------
-  
-  /**
-   * Get the maximum height of the peers the wallet's daemon is connected to.
-   *
-   * @return {number} the maximum height of the peers the wallet's daemon is connected to
-   */
-  async getDaemonMaxPeerHeight() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-      
-        // define callback for wasm
-        let callbackFn = function(resp) {
-          resolve(resp);
-        }
-        
-        // sync wallet in wasm and invoke callback when done
-        that._module.get_daemon_max_peer_height(that._cppAddress, callbackFn);
-      });
-    });
-  }
-  
-  /**
-   * Indicates if the wallet's daemon is synced with the network.
-   * 
-   * @return {boolean} true if the daemon is synced with the network, false otherwise
-   */
-  async isDaemonSynced() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-      
-        // define callback for wasm
-        let callbackFn = function(resp) {
-          resolve(resp);
-        }
-        
-        // sync wallet in wasm and invoke callback when done
-        that._module.is_daemon_synced(that._cppAddress, callbackFn);
-      });
-    });
-  }
-  
-  /**
-   * Indicates if the wallet is synced with the daemon.
-   * 
-   * @return {boolean} true if the wallet is synced with the daemon, false otherwise
-   */
-  async isSynced() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-      
-        // define callback for wasm
-        let callbackFn = function(resp) {
-          resolve(resp);
-        }
-        
-        // sync wallet in wasm and invoke callback when done
-        that._module.is_synced(that._cppAddress, callbackFn);
-      });
-    });
-  }
-  
-  /**
-   * Get the wallet's network type (mainnet, testnet, or stagenet).
-   * 
-   * @return {MoneroNetworkType} the wallet's network type
-   */
-  async getNetworkType() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.get_network_type(that._cppAddress);
-    });
-  }
-  
-  /**
-   * Get the height of the first block that the wallet scans.
-   * 
-   * @return {number} the height of the first block that the wallet scans
-   */
-  async getSyncHeight() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.get_sync_height(that._cppAddress);
-    });
-  }
-  
-  /**
-   * Set the height of the first block that the wallet scans.
-   * 
-   * @param {number} syncHeight - height of the first block that the wallet scans
-   */
-  async setSyncHeight(syncHeight) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.set_sync_height(that._cppAddress, syncHeight);
-    });
-  }
-  
-  /**
-   * Register a listener to receive wallet notifications.
-   * 
-   * @param {MoneroWalletListener} listener - listener to receive wallet notifications
-   */
-  async addListener(listener) {
-    this._assertNotClosed();
-    assert(listener instanceof MoneroWalletListener, "Listener must be instance of MoneroWalletListener");
-    this._listeners.push(listener);
-    await this._setIsListening(true);
-  }
-  
-  /**
-   * Unregister a listener to receive wallet notifications.
-   * 
-   * @param {MoneroWalletListener} listener - listener to unregister
-   */
-  async removeListener(listener) {
-    this._assertNotClosed();
-    let idx = this._listeners.indexOf(listener);
-    if (idx > -1) this._listeners.splice(idx, 1);
-    else throw new MoneroError("Listener is not registered with wallet");
-    if (this._listeners.length === 0) await this._setIsListening(false);
-  }
-  
-  /**
-   * Get the listeners registered with the wallet.
-   * 
-   * @return {MoneroWalletListener[]} the registered listeners
-   */
-  getListeners() {
-    this._assertNotClosed();
-    return this._listeners;
-  }
-  
-  /**
-   * Move the wallet from its current path to the given path.
-   * 
-   * @param {string} path is the new wallet's path
-   * @param {string} password is the new wallet's password
-   */
-  async moveTo(path, password) {
-    this._assertNotClosed();
-    throw new Error("Not implemented");
-  }
-  
-  // -------------------------- COMMON WALLET METHODS -------------------------
-  
-  async setDaemonConnection(uriOrRpcConnection, username, password, rejectUnauthorized) {
-    this._assertNotClosed();
-    
-    // normalize connection
-    let connection = new MoneroRpcConnection(uriOrRpcConnection, username, password, rejectUnauthorized);
-    let uri = connection.getUri();
-    username = connection.getUsername();
-    password = connection.getPassword();
-    rejectUnauthorized = connection.getRejectUnauthorized();
-    if (!uri) uri = "";
-    if (!username) username = "";
-    if (!password) password = "";
-    this._rejectUnauthorized = rejectUnauthorized;  // persist locally
-    
-    // set connection in queue
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-      
-        // define callback for wasm
-        let callbackFn = function(resp) { resolve(); }
-        
-        // sync wallet in wasm and invoke callback when done
-        that._module.set_daemon_connection(that._cppAddress, uri, username, password, callbackFn);
-      });
-    });
-  }
-  
-  async getDaemonConnection() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        let connectionContainerStr = that._module.get_daemon_connection(that._cppAddress);
-        if (!connectionContainerStr) resolve();
-        else {
-          let jsonConnection = JSON.parse(connectionContainerStr);
-          resolve(new MoneroRpcConnection(jsonConnection.uri, jsonConnection.username, jsonConnection.password, that._rejectUnauthorized));
-        }
-      });
-    });
-  }
-  
-  async isConnected() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-      
-        // define callback for wasm
-        let callbackFn = function(resp) {
-          resolve(resp);
-        }
-        
-        // sync wallet in wasm and invoke callback when done
-        that._module.is_connected(that._cppAddress, callbackFn);
-      });
-    });
-  }
-  
-  async getVersion() {
-    this._assertNotClosed();
-    throw new Error("Not implemented");
-  }
-  
-  async getPath() {
-    this._assertNotClosed();
-    return this._path;
-  }
-  
-  async getIntegratedAddress(paymentId) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      try {
-        return new MoneroIntegratedAddress(JSON.parse(that._module.get_integrated_address(that._cppAddress, "", paymentId ? paymentId : "")));
-      } catch (e) {
-        throw new MoneroError("Invalid payment ID: " + paymentId);
-      }
-    });
-  }
-  
-  async decodeIntegratedAddress(integratedAddress) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      try {
-        return new MoneroIntegratedAddress(JSON.parse(that._module.decode_integrated_address(that._cppAddress, integratedAddress)));
-      } catch (e) {
-        throw new MoneroError("Invalid integrated address: " + integratedAddress);
-      }
-    });
-  }
-  
-  async getHeight() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = function(resp) {
-          resolve(resp);
-        }
-        
-        // sync wallet in wasm and invoke callback when done
-        that._module.get_height(that._cppAddress, callbackFn);
-      });
-    });
-  }
-  
-  async getDaemonHeight() {
-    this._assertNotClosed();
-    if (!(await this.isConnected())) throw new MoneroError("Wallet is not connected to daemon");
-    
-    // schedule task
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = function(resp) {
-          resolve(resp);
-        }
-        
-        // sync wallet in wasm and invoke callback when done
-        that._module.get_daemon_height(that._cppAddress, callbackFn);
-      });
-    });
-  }
-  
-  async getHeightByDate(year, month, day) {
-    this._assertNotClosed();
-    if (!(await this.isConnected())) throw new MoneroError("Wallet is not connected to daemon");
-    
-    // schedule task
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = function(resp) {
-          if (typeof resp === "string") reject(new MoneroError(resp));
-          else resolve(resp);
-        }
-        
-        // sync wallet in wasm and invoke callback when done
-        that._module.get_height_by_date(that._cppAddress, year, month, day, callbackFn);
-      });
-    });
-  }
-  
-  async sync(listenerOrStartHeight, startHeight) {
-    this._assertNotClosed();
-    if (!(await this.isConnected())) throw new MoneroError("Wallet is not connected to daemon");
-    
-    // normalize params
-    startHeight = listenerOrStartHeight instanceof MoneroWalletListener ? startHeight : listenerOrStartHeight;
-    let listener = listenerOrStartHeight instanceof MoneroWalletListener ? listenerOrStartHeight : undefined;
-    if (startHeight === undefined) startHeight = Math.max(await this.getHeight(), await this.getSyncHeight());
-    
-    // register listener if given
-    if (listener) await this.addListener(listener);
-    
-    // sync wallet
-    let err;
-    let result;
-    try {
-      let that = this;
-      result = await that._module.queueTask(async function() {
-        that._assertNotClosed();
-        return new Promise(function(resolve, reject) {
-        
-          // define callback for wasm
-          let callbackFn = async function(resp) {
-            if (resp.charAt(0) !== "{") reject(new MoneroError(resp));
-            else {
-              let respJson = JSON.parse(resp);
-              resolve(new MoneroSyncResult(respJson.numBlocksFetched, respJson.receivedMoney));
-            }
-          }
-          
-          // sync wallet in wasm and invoke callback when done
-          that._module.sync(that._cppAddress, startHeight, callbackFn);
-        });
-      });
-    } catch (e) {
-      err = e;
-    }
-    
-    // unregister listener
-    if (listener) await this.removeListener(listener);
-    
-    // throw error or return
-    if (err) throw err;
-    return result;
-  }
-  
-  async startSyncing() {
-    this._assertNotClosed();
-    if (!(await this.isConnected())) throw new MoneroError("Wallet is not connected to daemon");
-    if (!this._syncingEnabled) {
-      this._syncingEnabled = true;
-      this._runSyncLoop();  // sync wallet on loop in background
-    }
-  }
-    
-  async stopSyncing() {
-    this._assertNotClosed();
-    this._syncingEnabled = false;
-    this._module.stop_syncing(this._cppAddress); // task is not queued so wallet stops immediately
-  }
-  
-  async rescanSpent() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        let callbackFn = function() { resolve(); }
-        that._module.rescan_spent(that._cppAddress, callbackFn);
-      });
-    });
-  }
-  
-  async rescanBlockchain() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        let callbackFn = function() { resolve(); }
-        that._module.rescan_blockchain(that._cppAddress, callbackFn);
-      });
-    });
-  }
-  
-  async getBalance(accountIdx, subaddressIdx) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      
-      // get balance encoded in json string
-      let balanceStr;
-      if (accountIdx === undefined) {
-        assert(subaddressIdx === undefined, "Subaddress index must be undefined if account index is undefined");
-        balanceStr = that._module.get_balance_wallet(that._cppAddress);
-      } else if (subaddressIdx === undefined) {
-        balanceStr = that._module.get_balance_account(that._cppAddress, accountIdx);
-      } else {
-        balanceStr = that._module.get_balance_subaddress(that._cppAddress, accountIdx, subaddressIdx);
-      }
-      
-      // parse json string to BigInteger
-      return BigInteger.parse(JSON.parse(GenUtils.stringifyBIs(balanceStr)).balance);
-    });
-  }
-  
-  async getUnlockedBalance(accountIdx, subaddressIdx) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      
-      // get balance encoded in json string
-      let unlockedBalanceStr;
-      if (accountIdx === undefined) {
-        assert(subaddressIdx === undefined, "Subaddress index must be undefined if account index is undefined");
-        unlockedBalanceStr = that._module.get_unlocked_balance_wallet(that._cppAddress);
-      } else if (subaddressIdx === undefined) {
-        unlockedBalanceStr = that._module.get_unlocked_balance_account(that._cppAddress, accountIdx);
-      } else {
-        unlockedBalanceStr = that._module.get_unlocked_balance_subaddress(that._cppAddress, accountIdx, subaddressIdx);
-      }
-      
-      // parse json string to BigInteger
-      return BigInteger.parse(JSON.parse(GenUtils.stringifyBIs(unlockedBalanceStr)).unlockedBalance);
-    });
-  }
-  
-  async getAccounts(includeSubaddresses, tag) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      let accountsStr = that._module.get_accounts(that._cppAddress, includeSubaddresses ? true : false, tag ? tag : "");
-      let accounts = [];
-      for (let accountJson of JSON.parse(GenUtils.stringifyBIs(accountsStr)).accounts) {
-        accounts.push(MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson)));
-      }
-      return accounts;
-    });
-  }
-  
-  async getAccount(accountIdx, includeSubaddresses) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      let accountStr = that._module.get_account(that._cppAddress, accountIdx, includeSubaddresses ? true : false);
-      let accountJson = JSON.parse(GenUtils.stringifyBIs(accountStr));
-      return MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson));
-    });
-
-  }
-  
-  async createAccount(label) {
-    if (label === undefined) label = "";
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      let accountStr = that._module.create_account(that._cppAddress, label);
-      let accountJson = JSON.parse(GenUtils.stringifyBIs(accountStr));
-      return MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson));
-    });
-  }
-  
-  async getSubaddresses(accountIdx, subaddressIndices) {
-    let args = {accountIdx: accountIdx, subaddressIndices: subaddressIndices === undefined ? [] : GenUtils.listify(subaddressIndices)};
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      let subaddressesJson = JSON.parse(GenUtils.stringifyBIs(that._module.get_subaddresses(that._cppAddress, JSON.stringify(args)))).subaddresses;
-      let subaddresses = [];
-      for (let subaddressJson of subaddressesJson) subaddresses.push(MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson)));
-      return subaddresses;
-    });
-  }
-  
-  async createSubaddress(accountIdx, label) {
-    if (label === undefined) label = "";
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      let subaddressStr = that._module.create_subaddress(that._cppAddress, accountIdx, label);
-      let subaddressJson = JSON.parse(GenUtils.stringifyBIs(subaddressStr));
-      return MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson));
-    });
-  }
-  
-  async getTxs(query, missingTxHashes) {
-    this._assertNotClosed();
-    
-    // copy and normalize query up to block
-    query = MoneroWallet._normalizeTxQuery(query);
-    
-    // schedule task
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = function(blocksJsonStr) {
-            
-          // check for error
-          if (blocksJsonStr.charAt(0) !== "{") {
-            reject(new MoneroError(blocksJsonStr));
-            return;
-          }
-          
-          // resolve with deserialized txs
-          try {
-            resolve(MoneroWalletWasm._deserializeTxs(query, blocksJsonStr, missingTxHashes));
-          } catch (e) {
-            reject(e);
-          }
-        }
-        
-        // sync wallet in wasm and invoke callback when done
-        that._module.get_txs(that._cppAddress, JSON.stringify(query.getBlock().toJson()), callbackFn);
-      });
-    });
-  }
-  
-  async getTransfers(query) {
-    this._assertNotClosed();
-    
-    // copy and normalize query up to block
-    query = MoneroWallet._normalizeTransferQuery(query);
-    
-    // return promise which resolves on callback
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = function(blocksJsonStr) {
-            
-          // check for error
-          if (blocksJsonStr.charAt(0) !== "{") {
-            reject(new MoneroError(blocksJsonStr));
-            return;
-          }
-           
-          // resolve with deserialized transfers 
-          try {
-            resolve(MoneroWalletWasm._deserializeTransfers(query, blocksJsonStr));
-          } catch (e) {
-            reject(e);
-          }
-        }
-        
-        // sync wallet in wasm and invoke callback when done
-        that._module.get_transfers(that._cppAddress, JSON.stringify(query.getTxQuery().getBlock().toJson()), callbackFn);
-      });
-    });
-  }
-  
-  async getOutputs(query) {
-    this._assertNotClosed();
-    
-    // copy and normalize query up to block
-    query = MoneroWallet._normalizeOutputQuery(query);
-    
-    // return promise which resolves on callback
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = function(blocksJsonStr) {
-          
-          // check for error
-          if (blocksJsonStr.charAt(0) !== "{") {
-            reject(new MoneroError(blocksJsonStr));
-            return;
-          }
-          
-          // resolve with deserialized outputs
-          try {
-            resolve(MoneroWalletWasm._deserializeOutputs(query, blocksJsonStr));
-          } catch (e) {
-            reject(e);
-          }
-        }
-        
-        // sync wallet in wasm and invoke callback when done
-        that._module.get_outputs(that._cppAddress, JSON.stringify(query.getTxQuery().getBlock().toJson()), callbackFn);
-      });
-    });
-  }
-  
-  async getOutputsHex() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        that._module.get_outputs_hex(that._cppAddress, function(outputsHex) { resolve(outputsHex); });
-      });
-    });
-  }
-  
-  async importOutputsHex(outputsHex) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        that._module.import_outputs_hex(that._cppAddress, outputsHex, function(numImported) { resolve(numImported); });
-      });
-    });
-  }
-  
-  async getKeyImages() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        let callback = function(keyImagesStr) {
-          let keyImages = [];
-          for (let keyImageJson of JSON.parse(GenUtils.stringifyBIs(keyImagesStr)).keyImages) keyImages.push(new MoneroKeyImage(keyImageJson));
-          resolve(keyImages);
-        }
-        that._module.get_key_images(that._cppAddress, callback);
-      });
-    });
-  }
-  
-  async importKeyImages(keyImages) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        let callback = function(keyImageImportResultStr) {
-          resolve(new MoneroKeyImageImportResult(JSON.parse(GenUtils.stringifyBIs(keyImageImportResultStr))));
-        }
-        that._module.import_key_images(that._cppAddress, JSON.stringify({keyImages: keyImages.map(keyImage => keyImage.toJson())}), callback);
-      });
-    });
-  }
-  
-  async getNewKeyImagesFromLastImport() {
-    this._assertNotClosed();
-    throw new MoneroError("Not implemented");
-  }
-  
-  async createTxs(config) {
-    this._assertNotClosed();
-    
-    // validate, copy, and normalize config
-    config = MoneroWallet._normalizeCreateTxsConfig(config);
-    if (config.getCanSplit() === undefined) config.setCanSplit(true);
-    
-    // check for payment id to avoid error in wasm 
-    if (config.getPaymentId()) throw new MoneroError("Standalone payment IDs are obsolete. Use subaddresses or integrated addresses instead"); // TODO: this should no longer be necessary, remove and re-test
-    
-    // return promise which resolves on callback
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = function(txSetJsonStr) {
-          if (txSetJsonStr.charAt(0) !== '{') reject(new MoneroError(txSetJsonStr)); // json expected, else error
-          else resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBIs(txSetJsonStr))).getTxs());
-        }
-        
-        // create txs in wasm and invoke callback when done
-        that._module.create_txs(that._cppAddress, JSON.stringify(config.toJson()), callbackFn);
-      });
-    });
-  }
-  
-  async sweepOutput(config) {
-    this._assertNotClosed();
-    
-    // normalize and validate config
-    config = MoneroWallet._normalizeSweepOutputConfig(config);
-    
-    // return promise which resolves on callback
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = function(txSetJsonStr) {
-          if (txSetJsonStr.charAt(0) !== '{') reject(new MoneroError(txSetJsonStr)); // json expected, else error
-          else resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBIs(txSetJsonStr))).getTxs()[0]);
-        }
-        
-        // sweep output in wasm and invoke callback when done
-        that._module.sweep_output(that._cppAddress, JSON.stringify(config.toJson()), callbackFn);
-      });
-    });
-  }
-
-  async sweepUnlocked(config) {
-    this._assertNotClosed();
-    
-    // validate and normalize config
-    config = MoneroWallet._normalizeSweepUnlockedConfig(config);
-    
-    // return promise which resolves on callback
-    let that = this;
-    return that._module.queueTask(async function() { // TODO: could factor this pattern out, invoked with module params and callback handler
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = function(txSetsJson) {
-          if (txSetsJson.charAt(0) !== '{') reject(new MoneroError(txSetsJson)); // json expected, else error
-          else {
-            let txSets = [];
-            for (let txSetJson of JSON.parse(GenUtils.stringifyBIs(txSetsJson)).txSets) txSets.push(new MoneroTxSet(txSetJson));
-            let txs = [];
-            for (let txSet of txSets) for (let tx of txSet.getTxs()) txs.push(tx);
-            resolve(txs);
-          }
-        }
-        
-        // sweep unlocked in wasm and invoke callback when done
-        that._module.sweep_unlocked(that._cppAddress, JSON.stringify(config.toJson()), callbackFn);
-      });
-    });
-  }
-  
-  async sweepDust(relay) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        
-        // define callback for wasm
-        let callbackFn = function(txSetJsonStr) {
-          if (txSetJsonStr.charAt(0) !== '{') reject(new MoneroError(txSetJsonStr)); // json expected, else error
-          else resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBIs(txSetJsonStr))).getTxs());
-        }
-        
-        // sync wallet in wasm and invoke callback when done
-        that._module.sweep_dust(that._cppAddress, relay, callbackFn);
-      });
-    });
-  }
-  
-  async relayTxs(txsOrMetadatas) {
-    this._assertNotClosed();
-    assert(Array.isArray(txsOrMetadatas), "Must provide an array of txs or their metadata to relay");
-    let txMetadatas = [];
-    for (let txOrMetadata of txsOrMetadatas) txMetadatas.push(txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata);
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        let callback = function(txHashesJson) {
-          if (txHashesJson.charAt(0) !== "{") reject(new MoneroError(txHashesJson));
-          else resolve(JSON.parse(txHashesJson).txHashes);
-        }
-        that._module.relay_txs(that._cppAddress, JSON.stringify({txMetadatas: txMetadatas}), callback);
-      });
-    });
-  }
-  
-  async parseTxSet(txSet) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new MoneroTxSet(JSON.parse(GenUtils.stringifyBIs(that._module.parse_tx_set(that._cppAddress, JSON.stringify(txSet.toJson())))));
-    });
-  }
-  
-  async signTxs(unsignedTxHex) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.sign_txs(that._cppAddress, unsignedTxHex);
-    });
-  }
-  
-  async submitTxs(signedTxHex) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        let callbackFn = function(resp) {
-          resolve(JSON.parse(resp).txHashes);
-        }
-        that._module.submit_txs(that._cppAddress, signedTxHex, callbackFn);
-      });
-    });
-  }
-  
-  async signMessage(message) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.sign_message(that._cppAddress, message);
-    });
-  }
-  
-  async verifyMessage(message, address, signature) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.verify_message(that._cppAddress, message, address, signature);
-    });
-  }
-  
-  async getTxKey(txHash) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.get_tx_key(that._cppAddress, txHash);
-    });
-  }
-  
-  async checkTxKey(txHash, txKey, address) {
-    throw new Error("MoneroWalletWasm.checkTxKey() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html")
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new MoneroCheckTx(JSON.parse(GenUtils.stringifyBIs(that._module.check_tx_key(that._cppAddress, txHash, txKey, address))));
-    });
-  }
-  
-  async getTxProof(txHash, address, message) {
-    throw new Error("MoneroWalletWasm.checkTxKey() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html")
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.get_tx_proof(that._cppAddress, txHash, address, message);
-    });
-  }
-  
-  async checkTxProof(txHash, address, message, signature) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new MoneroCheckTx(JSON.parse(GenUtils.stringifyBIs(that._module.check_tx_proof(that._cppAddress, txHash, address, message, signature))));
-    });
-  }
-  
-  async getSpendProof(txHash, message) {
-    throw new Error("MoneroWalletWasm.getSpendProof() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html");  // TODO
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.get_spend_proof(that._cppAddress, txHash, message);
-    });
-  }
-  
-  async checkSpendProof(txHash, message, signature) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.check_spend_proof(that._cppAddress, txHash, message, signature);
-    });
-  }
-  
-  async getReserveProofWallet(message) {
-    throw new Error("MoneroWalletWasm.getReserveProofWallet() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html");  // TODO
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.get_reserve_proof_wallet(that._cppAddress, message);
-    });
-  }
-  
-  async getReserveProofAccount(accountIdx, amount, message) {
-    throw new Error("MoneroWalletWasm.getReserveProofAccount() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html"); // TODO
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.get_reserve_proof_account(that._cppAddress, accountIdx, amount.toString(), message);
-    });
-  }
-
-  async checkReserveProof(address, message, signature) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new MoneroCheckReserve(JSON.parse(GenUtils.stringifyBIs(that._module.check_reserve_proof(that._cppAddress, address, message, signature))));
-    });
-  }
-  
-  async getTxNotes(txHashes) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return JSON.parse(that._module.get_tx_notes(that._cppAddress, JSON.stringify({txHashes: txHashes}))).txNotes;
-    });
-  }
-  
-  async setTxNotes(txHashes, notes) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      that._module.set_tx_notes(that._cppAddress, JSON.stringify({txHashes: txHashes, txNotes: notes}));
-    });
-  }
-  
-  async getAddressBookEntries(entryIndices) {
-    if (!entryIndices) entryIndices = [];
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      let entries = [];
-      for (let entryJson of JSON.parse(that._module.get_address_book_entries(that._cppAddress, JSON.stringify({entryIndices: entryIndices}))).entries) {
-        entries.push(new MoneroAddressBookEntry(entryJson));
-      }
-      return entries;
-    });
-  }
-  
-  async addAddressBookEntry(address, description) {
-    if (!address) address = "";
-    if (!description) description = "";
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.add_address_book_entry(that._cppAddress, address, description);
-    });
-  }
-  
-  async editAddressBookEntry(index, setAddress, address, setDescription, description) {
-    if (!setAddress) setAddress = false;
-    if (!address) address = "";
-    if (!setDescription) setDescription = false;
-    if (!description) description = "";
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      that._module.edit_address_book_entry(that._cppAddress, index, setAddress, address, setDescription, description);
-    });
-  }
-  
-  async deleteAddressBookEntry(entryIdx) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      that._module.delete_address_book_entry(that._cppAddress, entryIdx);
-    });
-  }
-  
-  async tagAccounts(tag, accountIndices) {
-    if (!tag) tag = "";
-    if (!accountIndices) accountIndices = [];
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      that._module.tag_accounts(that._cppAddress, JSON.stringify({tag: tag, accountIndices: accountIndices}));
-    });
-  }
-
-  async untagAccounts(accountIndices) {
-    if (!accountIndices) accountIndices = [];
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      that._module.tag_accounts(that._cppAddress, JSON.stringify({accountIndices: accountIndices}));
-    });
-  }
-  
-  async getAccountTags() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      let accountTags = [];
-      for (let accountTagJson of JSON.parse(that._module.get_account_tags(that._cppAddress)).accountTags) accountTags.push(new MoneroAccountTag(accountTagJson));
-      return accountTags;
-    });
-  }
-
-  async setAccountTagLabel(tag, label) {
-    if (!tag) tag = "";
-    if (!llabel) label = "";
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      that._module.set_account_tag_label(that._cppAddress, tag, label);
-    });
-  }
-  
-  async createPaymentUri(config) {
-    config = MoneroWallet._normalizeCreateTxsConfig(config);
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      try {
-        return that._module.create_payment_uri(that._cppAddress, JSON.stringify(config.toJson()));
-      } catch (e) {
-        throw new MoneroError("Cannot make URI from supplied parameters");
-      }
-    });
-  }
-  
-  async parsePaymentUri(uri) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      try {
-        return new MoneroTxConfig(JSON.parse(GenUtils.stringifyBIs(that._module.parse_payment_uri(that._cppAddress, uri))));
-      } catch (e) {
-        throw new MoneroError(e.message);
-      }
-    });
-  }
-  
-  async getAttribute(key) {
-    this._assertNotClosed();
-    assert(typeof key === "string", "Attribute key must be a string");
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      let value = that._module.get_attribute(that._cppAddress, key);
-      return value === "" ? null : value;
-    });
-  }
-  
-  async setAttribute(key, val) {
-    this._assertNotClosed();
-    assert(typeof key === "string", "Attribute key must be a string");
-    assert(typeof val === "string", "Attribute value must be a string");
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      that._module.set_attribute(that._cppAddress, key, val);
-    });
-  }
-  
-  async startMining(numThreads, backgroundMining, ignoreBattery) {
-    this._assertNotClosed();
-    let daemon = new MoneroDaemonRpc(await this.getDaemonConnection());
-    await daemon.startMining(await this.getPrimaryAddress(), numThreads, backgroundMining, ignoreBattery);
-  }
-  
-  async stopMining() {
-    this._assertNotClosed();
-    let daemon = new MoneroDaemonRpc(await this.getDaemonConnection());
-    await daemon.stopMining();
-  }
-  
-  async isMultisigImportNeeded() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.is_multisig_import_needed(that._cppAddress);
-    });
-  }
-  
-  async isMultisig() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.is_multisig(that._cppAddress);
-    });
-  }
-  
-  async getMultisigInfo() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new MoneroMultisigInfo(JSON.parse(that._module.get_multisig_info(that._cppAddress)));
-    });
-  }
-  
-  async prepareMultisig() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.prepare_multisig(that._cppAddress);
-    });
-  }
-  
-  async makeMultisig(multisigHexes, threshold, password) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new MoneroMultisigInitResult(JSON.parse(that._module.make_multisig(that._cppAddress, JSON.stringify({multisigHexes: multisigHexes, threshold: threshold, password: password}))));
-    });
-  }
-  
-  async exchangeMultisigKeys(multisigHexes, password) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new MoneroMultisigInitResult(JSON.parse(that._module.exchange_multisig_keys(that._cppAddress, JSON.stringify({multisigHexes: multisigHexes, password: password}))));
-    });
-  }
-  
-  async getMultisigHex() {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return that._module.get_multisig_hex(that._cppAddress);
-    });
-  }
-  
-  async importMultisigHex(multisigHexes) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        let callbackFn = function(resp) {
-          if (typeof resp === "string") reject(new MoneroError(resp));
-          else resolve(resp);
-        }
-        that._module.import_multisig_hex(that._cppAddress, JSON.stringify({multisigHexes: multisigHexes}), callbackFn);
-      });
-    });
-  }
-  
-  async signMultisigTxHex(multisigTxHex) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new MoneroMultisigSignResult(JSON.parse(that._module.sign_multisig_tx_hex(that._cppAddress, multisigTxHex)));
-    });
-  }
-  
-  async submitMultisigTxHex(signedMultisigTxHex) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-      return new Promise(function(resolve, reject) {
-        let callbackFn = function(resp) { resolve(JSON.parse(resp).txHashes); }
-        that._module.submit_multisig_tx_hex(that._cppAddress, signedMultisigTxHex, callbackFn);
-      });
-    });
-  }
-  
-  /**
-   * Get the wallet's keys and cache data.
-   * 
-   * @return {DataView[]} is the keys and cache data respectively
-   */
-  async getData() {
-    this._assertNotClosed();
-    
-    // queue call to wasm module
-    let viewOnly = await this.isViewOnly();
-    let that = this;
-    return that._module.queueTask(async function() {
-      that._assertNotClosed();
-
-      // store views in array
-      let views = [];
-      
-      // malloc cache buffer and get buffer location in c++ heap
-      let cacheBufferLoc = JSON.parse(that._module.get_cache_file_buffer(that._cppAddress, that._password));
-      
-      // read binary data from heap to DataView
-      let view = new DataView(new ArrayBuffer(cacheBufferLoc.length));
-      for (let i = 0; i < cacheBufferLoc.length; i++) {
-        view.setInt8(i, that._module.HEAPU8[cacheBufferLoc.pointer / Uint8Array.BYTES_PER_ELEMENT + i]);
-      }
-      
-      // free binary on heap
-      that._module._free(cacheBufferLoc.pointer);
-      
-      // write cache file
-      views.push(Buffer.from(view.buffer));
-      
-      // malloc keys buffer and get buffer location in c++ heap
-      let keysBufferLoc = JSON.parse(that._module.get_keys_file_buffer(that._cppAddress, that._password, viewOnly));
-      
-      // read binary data from heap to DataView
-      view = new DataView(new ArrayBuffer(keysBufferLoc.length));
-      for (let i = 0; i < keysBufferLoc.length; i++) {
-        view.setInt8(i, that._module.HEAPU8[keysBufferLoc.pointer / Uint8Array.BYTES_PER_ELEMENT + i]);
-      }
-      
-      // free binary on heap
-      that._module._free(keysBufferLoc.pointer);
-      
-      // prepend keys file
-      views.unshift(Buffer.from(view.buffer));
-      return views;
-    });
-  }
-
-  async save() {
-    this._assertNotClosed();
-        
-    // path must be set
-    let path = await this.getPath();
-    if (!path) throw new MoneroError("Cannot save wallet because path is not set");
-    
-    // write address file
-    this._fs.writeFileSync(path + ".address.txt", await this.getPrimaryAddress());
-    
-    // write keys and cache data
-    let data = await this.getData();
-    this._fs.writeFileSync(path + ".keys", data[0], "binary");
-    this._fs.writeFileSync(path, data[1], "binary");
-  }
-  
-  async close(save) {
-    if (this._isClosed) return; // no effect if closed
-    this._syncingEnabled = false;
-    await this._setIsListening(false);
-    await this.stopSyncing();
-    await super.close(save);
-    delete this._path;
-    delete this._password;
-    delete this._listeners;
-    delete this._wasmListener;
-    LibraryUtils.setRejectUnauthorizedFn(this._rejectUnauthorizedConfigId, undefined); // unregister fn informing if unauthorized reqs should be rejected
-  }
-  
-  // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS --------------
-  
-  async getTx() { return super.getTx(...arguments); }
-  async getIncomingTransfers() { return super.getIncomingTransfers(...arguments); }
-  async getOutgoingTransfers() { return super.getOutgoingTransfers(...arguments); }
-  async createTx() { return super.createTx(...arguments); }
-  async relayTx() { return super.relayTx(...arguments); }
-  async getTxNote() { return super.getTxNote(...arguments); }
-  async setTxNote() { return super.setTxNote(...arguments); }
-  
-  // ---------------------------- PRIVATE HELPERS ----------------------------
-  
-  static _getFs() {
-    if (!MoneroWalletWasm.FS) MoneroWalletWasm.FS = GenUtils.isBrowser() ? undefined : require('fs');
-    return MoneroWalletWasm.FS;
-  }
-  
-  static async _openWalletData(path, password, networkType, keysData, cacheData, daemonUriOrConnection, proxyToWorker, fs) {
-    if (proxyToWorker) return MoneroWalletWasmProxy.openWalletData(path, password, networkType, keysData, cacheData, daemonUriOrConnection, fs);
-    
-    // validate and normalize parameters
-    assert(password, "Must provide a password to open the wallet");
-    if (networkType === undefined) throw new MoneroError("Must provide the wallet's network type");
-    MoneroNetworkType.validate(networkType);
-    let daemonConnection = typeof daemonUriOrConnection === "string" ? new MoneroRpcConnection(daemonUriOrConnection) : daemonUriOrConnection;
-    let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : "";
-    let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : "";
-    let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : "";
-    let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true;
-    
-    // load wasm module
-    let module = await LibraryUtils.loadCoreModule();
-    
-    // open wallet in queue
-    return module.queueTask(async function() {
-      return new Promise(function(resolve, reject) {
-        
-        // register fn informing if unauthorized reqs should be rejected
-        let rejectUnauthorizedFnId = GenUtils.getUUID();
-        LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return rejectUnauthorized });
-      
-        // define callback for wasm
-        let callbackFn = async function(cppAddress) {
-          if (typeof cppAddress === "string") reject(new MoneroError(cppAddress));
-          else resolve(new MoneroWalletWasm(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId));
-        };
-        
-        // create wallet in wasm and invoke callback when done
-        module.open_core_wallet(password, networkType, keysData, cacheData, daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, callbackFn);
-      });
-    });
-  }
-  
-  /**
-   * Loop while syncing enabled.
-   */
-  async _runSyncLoop() {
-    if (this._syncLoopRunning) return;  // only run one loop at a time
-    this._syncLoopRunning = true;
-    
-    // sync while enabled
-    let label = this._path ? this._path : (this._browserMainPath ? this._browserMainPath : "in-memory wallet"); // label for log
-    while (this._syncingEnabled) {
-      try {
-        console.log("Background synchronizing " + label);
-        await this.sync();
-      } catch (e) {
-        if (!this._isClosed) console.log("Failed to background synchronize " + label + ": " + e.message);
-      }
-      
-      // only wait if syncing still enabled
-      if (this._syncingEnabled) await new Promise(function(resolve) { setTimeout(resolve, MoneroUtils.WALLET_REFRESH_RATE); });
-    }
-    
-    this._syncLoopRunning = false;
-  }
-  
-  /**
-   * Enables or disables listening in the c++ wallet.
-   */
-  async _setIsListening(isEnabled) {
-    let that = this;
-    return that._module.queueTask(async function() {
-      if (isEnabled) {
-        that._wasmListenerHandle = that._module.set_listener(
-            that._cppAddress,
-            that._wasmListenerHandle,
-            function(height, startHeight, endHeight, percentDone, message) { that._wasmListener.onSyncProgress(height, startHeight, endHeight, percentDone, message); },
-            function(height) { that._wasmListener.onNewBlock(height); },
-            function(newBalanceStr, newUnlockedBalanceStr) { that._wasmListener.onBalancesChanged(newBalanceStr, newUnlockedBalanceStr); },
-            function(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockHeight, isLocked) { that._wasmListener.onOutputReceived(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockHeight, isLocked); },
-            function(height, txHash, amountStr, accountIdx, subaddressIdx, version) { that._wasmListener.onOutputSpent(height, txHash, amountStr, accountIdx, subaddressIdx, version); });
-      } else {
-        that._wasmListenerHandle = that._module.set_listener(that._cppAddress, that._wasmListenerHandle, undefined, undefined, undefined, undefined, undefined);
-      }
-    });
-  }
-  
-  static _sanitizeBlock(block) {
-    for (let tx of block.getTxs()) MoneroWalletWasm._sanitizeTxWallet(tx);
-    return block;
-  }
-  
-  static _sanitizeTxWallet(tx) {
-    assert(tx instanceof MoneroTxWallet);
-    return tx;
-  }
-  
-  static _sanitizeAccount(account) {
-    if (account.getSubaddresses()) {
-      for (let subaddress of account.getSubaddresses()) MoneroWalletWasm._sanitizeSubaddress(subaddress);
-    }
-    return account;
-  }
-  
-  static _sanitizeSubaddress(subaddress) {
-    if (subaddress.getLabel() === "") subaddress.setLabel(undefined);
-    return subaddress
-  }
-  
-  static _deserializeBlocks(blocksJsonStr) {
-    let blocksJson = JSON.parse(GenUtils.stringifyBIs(blocksJsonStr));
-    let deserializedBlocks = {};
-    deserializedBlocks.blocks = [];
-    deserializedBlocks.missingTxHashes = [];
-    if (blocksJson.blocks) for (let blockJson of blocksJson.blocks) deserializedBlocks.blocks.push(MoneroWalletWasm._sanitizeBlock(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET)));
-    if (blocksJson.missingTxHashes) for (let missingTxHash of blocksJson.missingTxHashes) deserializedBlocks.missingTxHashes.push(missingTxHash);
-    return deserializedBlocks;
-  }
-  
-  static _deserializeTxs(query, blocksJsonStr, missingTxHashes) {
-    
-    // deserialize blocks
-    let deserializedBlocks = MoneroWalletWasm._deserializeBlocks(blocksJsonStr);
-    if (missingTxHashes === undefined && deserializedBlocks.missingTxHashes.length > 0) throw new MoneroError("Wallet missing requested tx hashes: " + deserializedBlocks.missingTxHashes);
-    for (let missingTxHash of deserializedBlocks.missingTxHashes) missingTxHashes.push(missingTxHash);
-    let blocks = deserializedBlocks.blocks;
-    
-    // collect txs
-    let txs = [];
-    for (let block of blocks) {
-      MoneroWalletWasm._sanitizeBlock(block);
-      for (let tx of block.getTxs()) {
-        if (block.getHeight() === undefined) tx.setBlock(undefined); // dereference placeholder block for unconfirmed txs
-        txs.push(tx);
-      }
-    }
-    
-    // re-sort txs which is lost over wasm serialization  // TODO: confirm that order is lost
-    if (query.getHashes() !== undefined) {
-      let txMap = new Map();
-      for (let tx of txs) txMap[tx.getHash()] = tx;
-      let txsSorted = [];
-      for (let txHash of query.getHashes()) if (txMap[txHash] !== undefined) txsSorted.push(txMap[txHash]);
-      txs = txsSorted;
-    }
-    
-    return txs;
-  }
-  
-  static _deserializeTransfers(query, blocksJsonStr) {
-    
-    // deserialize blocks
-    let deserializedBlocks = MoneroWalletWasm._deserializeBlocks(blocksJsonStr);
-    if (deserializedBlocks.missingTxHashes.length > 0) throw new MoneroError("Wallet missing requested tx hashes: " + deserializedBlocks.missingTxHashes);
-    let blocks = deserializedBlocks.blocks;
-    
-    // collect transfers
-    let transfers = [];
-    for (let block of blocks) {
-      for (let tx of block.getTxs()) {
-        if (block.getHeight() === undefined) tx.setBlock(undefined); // dereference placeholder block for unconfirmed txs
-        if (tx.getOutgoingTransfer() !== undefined) transfers.push(tx.getOutgoingTransfer());
-        if (tx.getIncomingTransfers() !== undefined) {
-          for (let transfer of tx.getIncomingTransfers()) transfers.push(transfer);
-        }
-      }
-    }
-    
-    return transfers;
-  }
-  
-  static _deserializeOutputs(query, blocksJsonStr) {
-    
-    // deserialize blocks
-    let deserializedBlocks = MoneroWalletWasm._deserializeBlocks(blocksJsonStr);
-    if (deserializedBlocks.missingTxHashes.length > 0) throw new MoneroError("Wallet missing requested tx hashes: " + deserializedBlocks.missingTxHashes);
-    let blocks = deserializedBlocks.blocks;
-    
-    // collect outputs
-    let outputs = [];
-    for (let block of blocks) {
-      for (let tx of block.getTxs()) {
-        for (let output of tx.getOutputs()) outputs.push(output);
-      }
-    }
-    
-    return outputs;
-  }
-  
-  /**
-   * Set the path of the wallet on the browser main thread if run as a web worker.
-   * 
-   * @param {string} browserMainPath - path of the wallet on the browser main thread
-   */
-  _setBrowserMainPath(browserMainPath) {
-    this._browserMainPath = browserMainPath;
-  }
-}
-
-// ------------------------------- LISTENERS --------------------------------
-
-/**
- * Receives notifications directly from wasm c++.
- * 
- * @private
- */
-class WalletWasmListener {
-  
-  constructor(wallet) {
-    this._wallet = wallet;
-  }
-  
-  onSyncProgress(height, startHeight, endHeight, percentDone, message) {
-    for (let listener of this._wallet.getListeners()) {
-      listener.onSyncProgress(height, startHeight, endHeight, percentDone, message);
-    }
-  }
-  
-  onNewBlock(height) {
-    for (let listener of this._wallet.getListeners()) listener.onNewBlock(height);
-  }
-  
-  onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) {
-    for (let listener of this._wallet.getListeners()) listener.onBalancesChanged(BigInteger.parse(newBalanceStr), BigInteger.parse(newUnlockedBalanceStr));
-  }
-  
-  onOutputReceived(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockHeight, isLocked) {
-    
-    // build received output
-    let output = new MoneroOutputWallet();
-    output.setAmount(BigInteger.parse(amountStr));
-    output.setAccountIndex(accountIdx);
-    output.setSubaddressIndex(subaddressIdx);
-    let tx = new MoneroTxWallet();
-    tx.setHash(txHash);
-    tx.setVersion(version);
-    tx.setUnlockHeight(unlockHeight);
-    output.setTx(tx);
-    tx.setOutputs([output]);
-    tx.setIsIncoming(true);
-    tx.setIsLocked(isLocked);
-    if (height > 0) {
-      let block = new MoneroBlock().setHeight(height);
-      block.setTxs([tx]);
-      tx.setBlock(block);
-      tx.setIsConfirmed(true);
-      tx.setInTxPool(false);
-      tx.setIsFailed(false);
-    } else {
-      tx.setIsConfirmed(false);
-      tx.setInTxPool(true);
-    }
-    
-    // announce output
-    for (let listener of this._wallet.getListeners()) listener.onOutputReceived(tx.getOutputs()[0]);
-  }
-  
-  onOutputSpent(height, txHash, amountStr, accountIdx, subaddressIdx, version) {
-    
-    // build spent output
-    let output = new MoneroOutputWallet();
-    output.setAmount(BigInteger.parse(amountStr));
-    output.setAccountIndex(accountIdx);
-    output.setSubaddressIndex(subaddressIdx);
-    let tx = new MoneroTxWallet();
-    tx.setHash(txHash);
-    tx.setVersion(version);
-    output.setTx(tx);
-    tx.setInputs([output]);
-    if (height > 0) {
-      let block = new MoneroBlock().setHeight(height);
-      block.setTxs([tx]);
-      tx.setBlock(block);
-      tx.setIsConfirmed(true);
-      tx.setInTxPool(false);
-      tx.setIsFailed(false);
-    } else {
-      tx.setIsConfirmed(false);
-      tx.setInTxPool(true);
-    }
-    
-    // notify wallet listeners
-    for (let listener of this._wallet.getListeners()) listener.onOutputSpent(tx.getInputs()[0]);
-  }
-}
-
-/**
- * Wraps a sync listener as a general wallet listener.
- * 
- * @private
- */
-class SyncListenerWrapper extends MoneroWalletListener {
-  
-  constructor(listener) {
-    super();
-    this._listener = listener;
-  }
-  
-  onSyncProgress(height, startHeight, endHeight, percentDone, message) {
-    this._listener.onSyncProgress(height, startHeight, endHeight, percentDone, message);
-  }
-}
-
-/**
- * Implements a MoneroWallet by proxying requests to a web worker which runs a core wallet.
- * 
- * TODO: sort these methods according to master sort in MoneroWallet.js
- * TODO: probably only allow one listener to web worker then propogate to registered listeners for performance
- * TODO: ability to recycle worker for use in another wallet
- * TODO: using LibraryUtils.WORKER_OBJECTS directly breaks encapsulation
- * 
- * @private
- */
-class MoneroWalletWasmProxy extends MoneroWallet {
-  
-  // -------------------------- WALLET STATIC UTILS ---------------------------
-  
-  static async openWalletData(path, password, networkType, keysData, cacheData, daemonUriOrConnection, fs) {
-    let walletId = GenUtils.getUUID();
-    let daemonUriOrConfig = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection.getConfig() : daemonUriOrConnection;
-    await LibraryUtils.invokeWorker(walletId, "openWalletData", [path, password, networkType, keysData, cacheData, daemonUriOrConfig]);
-    let wallet = new MoneroWalletWasmProxy(walletId, LibraryUtils.getWorker(), path, fs);
-    if (path) await wallet.save();
-    return wallet;
-  }
-  
-  static async _createWalletRandom(path, password, networkType, daemonUriOrConnection, language, fs) {
-    if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error("Wallet already exists: " + path);
-    let walletId = GenUtils.getUUID();
-    let daemonUriOrConfig = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection.getConfig() : daemonUriOrConnection;
-    await LibraryUtils.invokeWorker(walletId, "_createWalletRandom", [path, password, networkType, daemonUriOrConfig, language]);
-    let wallet = new MoneroWalletWasmProxy(walletId, LibraryUtils.getWorker(), path, fs);
-    if (path) await wallet.save();
-    return wallet;
-  }
-  
-  static async _createWalletFromMnemonic(path, password, networkType, mnemonic, daemonUriOrConnection, restoreHeight, seedOffset, fs) {
-    if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error("Wallet already exists: " + path);
-    let walletId = GenUtils.getUUID();
-    let daemonUriOrConfig = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection.getConfig() : daemonUriOrConnection;
-    await LibraryUtils.invokeWorker(walletId, "_createWalletFromMnemonic", [path, password, networkType, mnemonic, daemonUriOrConfig, restoreHeight, seedOffset]);
-    let wallet = new MoneroWalletWasmProxy(walletId, LibraryUtils.getWorker(), path, fs);
-    if (path) await wallet.save();
-    return wallet;
-  }
-  
-  static async _createWalletFromKeys(path, password, networkType, address, viewKey, spendKey, daemonUriOrConnection, restoreHeight, language, fs) {
-    if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error("Wallet already exists: " + path);
-    let walletId = GenUtils.getUUID();
-    let daemonUriOrConfig = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection.getConfig() : daemonUriOrConnection;
-    await LibraryUtils.invokeWorker(walletId, "_createWalletFromKeys", [path, password, networkType, address, viewKey, spendKey, daemonUriOrConfig, restoreHeight, language]);
-    let wallet = new MoneroWalletWasmProxy(walletId, LibraryUtils.getWorker(), path, fs);
-    if (path) await wallet.save();
-    return wallet;
-  }
-  
-  // --------------------------- INSTANCE METHODS ----------------------------
-  
-  /**
-   * Internal constructor which is given a worker to communicate with via messages.
-   * 
-   * This method should not be called externally but should be called through
-   * static wallet creation utilities in this class.
-   * 
-   * @param {string} walletId - identifies the wallet with the worker
-   * @param {Worker} worker - web worker to communicate with via messages
-   */
-  constructor(walletId, worker, path, fs) {
-    super();
-    this._walletId = walletId;
-    this._worker = worker;
-    this._path = path;
-    this._fs = fs ? fs : (path ? MoneroWalletWasm._getFs() : undefined);
-    this._wrappedListeners = [];
-  }
-  
-  async isViewOnly() {
-    return this._invokeWorker("isViewOnly");
-  }
-  
-  async getNetworkType() {
-    return this._invokeWorker("getNetworkType");
-  }
-  
-  async getVersion() {
-    throw new Error("Not implemented");
-  }
-  
-  getPath() {
-    return this._path;
-  }
-  
-  async getMnemonic() {
-    return this._invokeWorker("getMnemonic");
-  }
-  
-  async getMnemonicLanguage() {
-    return this._invokeWorker("getMnemonicLanguage");
-  }
-  
-  async getMnemonicLanguages() {
-    return this._invokeWorker("getMnemonicLanguages");
-  }
-  
-  async getPrivateSpendKey() {
-    return this._invokeWorker("getPrivateSpendKey");
-  }
-  
-  async getPrivateViewKey() {
-    return this._invokeWorker("getPrivateViewKey");
-  }
-  
-  async getPublicViewKey() {
-    return this._invokeWorker("getPublicViewKey");
-  }
-  
-  async getPublicSpendKey() {
-    return this._invokeWorker("getPublicSpendKey");
-  }
-  
-  async getAddress(accountIdx, subaddressIdx) {
-    return this._invokeWorker("getAddress", Array.from(arguments));
-  }
-  
-  async getAddressIndex(address) {
-    let subaddressJson = await this._invokeWorker("getAddressIndex", Array.from(arguments));
-    return MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson));
-  }
-  
-  async getIntegratedAddress(paymentId) {
-    return new MoneroIntegratedAddress(await this._invokeWorker("getIntegratedAddress", Array.from(arguments)));
-  }
-  
-  async decodeIntegratedAddress(integratedAddress) {
-    return new MoneroIntegratedAddress(await this._invokeWorker("decodeIntegratedAddress", Array.from(arguments)));
-  }
-  
-  async setDaemonConnection(uriOrRpcConnection, username, password) {
-    if (!uriOrRpcConnection) await this._invokeWorker("setDaemonConnection");
-    else {
-      let connection = uriOrRpcConnection instanceof MoneroRpcConnection? uriOrRpcConnection : new MoneroRpcConnection({uri: uriOrRpcConnection, username: username, password: password});
-      await this._invokeWorker("setDaemonConnection", connection.getConfig());
-    }
-  }
-  
-  async getDaemonConnection() {
-    let rpcConfig = await this._invokeWorker("getDaemonConnection");
-    return rpcConfig ? new MoneroRpcConnection(rpcConfig) : undefined;
-  }
-  
-  async isConnected() {
-    return this._invokeWorker("isConnected");
-  }
-  
-  async getSyncHeight() {
-    return this._invokeWorker("getSyncHeight");
-  }
-  
-  async setSyncHeight(syncHeight) {
-    return this._invokeWorker("setSyncHeight", [syncHeight]);
-  }
-  
-  async getDaemonHeight() {
-    return this._invokeWorker("getDaemonHeight");
-  }
-  
-  async getDaemonMaxPeerHeight() {
-    return this._invokeWorker("getDaemonMaxPeerHeight");
-  }
-  
-  async getHeightByDate(year, month, day) {
-    return this._invokeWorker("getHeightByDate", [year, month, day]);
-  }
-  
-  async isDaemonSynced() {
-    return this._invokeWorker("isDaemonSynced");
-  }
-  
-  async getHeight() {
-    return this._invokeWorker("getHeight");
-  }
-  
-  async addListener(listener) {
-    let wrappedListener = new WalletWorkerListener(listener);
-    let listenerId = wrappedListener.getId();
-    LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onSyncProgress_" + listenerId] = [wrappedListener.onSyncProgress, wrappedListener];
-    LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onNewBlock_" + listenerId] = [wrappedListener.onNewBlock, wrappedListener];
-    LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onBalancesChanged_" + listenerId] = [wrappedListener.onBalancesChanged, wrappedListener];
-    LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onOutputReceived_" + listenerId] = [wrappedListener.onOutputReceived, wrappedListener];
-    LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onOutputSpent_" + listenerId] = [wrappedListener.onOutputSpent, wrappedListener];
-    this._wrappedListeners.push(wrappedListener);
-    return this._invokeWorker("addListener", [listenerId]);
-  }
-  
-  async removeListener(listener) {
-    for (let i = 0; i < this._wrappedListeners.length; i++) {
-      if (this._wrappedListeners[i].getListener() === listener) {
-        let listenerId = this._wrappedListeners[i].getId();
-        await this._invokeWorker("removeListener", [listenerId]);
-        delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onSyncProgress_" + listenerId];
-        delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onNewBlock_" + listenerId];
-        delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onBalancesChanged_" + listenerId];
-        delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onOutputReceived_" + listenerId];
-        delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onOutputSpent_" + listenerId];
-        this._wrappedListeners.splice(i, 1);
-        return;
-      }
-    }
-    throw new MoneroError("Listener is not registered with wallet");
-  }
-  
-  getListeners() {
-    let listeners = [];
-    for (let wrappedListener of this._wrappedListeners) listeners.push(wrappedListener.getListener());
-    return listeners;
-  }
-  
-  async isSynced() {
-    return this._invokeWorker("isSynced");
-  }
-  
-  async sync(listenerOrStartHeight, startHeight) {
-    
-    // normalize params
-    startHeight = listenerOrStartHeight instanceof MoneroWalletListener ? startHeight : listenerOrStartHeight;
-    let listener = listenerOrStartHeight instanceof MoneroWalletListener ? listenerOrStartHeight : undefined;
-    if (startHeight === undefined) startHeight = Math.max(await this.getHeight(), await this.getSyncHeight());
-    
-    // register listener if given
-    if (listener) await this.addListener(listener);
-    
-    // sync wallet in worker 
-    let err;
-    let result;
-    try {
-      let resultJson = await this._invokeWorker("sync", [startHeight]);
-      result = new MoneroSyncResult(resultJson.numBlocksFetched, resultJson.receivedMoney);
-    } catch (e) {
-      err = e;
-    }
-    
-    // unregister listener
-    if (listener) await this.removeListener(listener);
-    
-    // throw error or return
-    if (err) throw err;
-    return result;
-  }
-  
-  async startSyncing() {
-    return this._invokeWorker("startSyncing");
-  }
-    
-  async stopSyncing() {
-    return this._invokeWorker("stopSyncing");
-  }
-  
-  async rescanSpent() {
-    return this._invokeWorker("rescanSpent");
-  }
-    
-  async rescanBlockchain() {
-    return this._invokeWorker("rescanBlockchain");
-  }
-  
-  async getBalance(accountIdx, subaddressIdx) {
-    return BigInteger.parse(await this._invokeWorker("getBalance", Array.from(arguments)));
-  }
-  
-  async getUnlockedBalance(accountIdx, subaddressIdx) {
-    let unlockedBalanceStr = await this._invokeWorker("getUnlockedBalance", Array.from(arguments));
-    return BigInteger.parse(unlockedBalanceStr);
-  }
-  
-  async getAccounts(includeSubaddresses, tag) {
-    let accounts = [];
-    for (let accountJson of (await this._invokeWorker("getAccounts", Array.from(arguments)))) {
-      accounts.push(MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson)));
-    }
-    return accounts;
-  }
-  
-  async getAccount(accountIdx, includeSubaddresses) {
-    let accountJson = await this._invokeWorker("getAccount", Array.from(arguments));
-    return MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson));
-  }
-  
-  async createAccount(label) {
-    let accountJson = await this._invokeWorker("createAccount", Array.from(arguments));
-    return MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson));
-  }
-  
-  async getSubaddresses(accountIdx, subaddressIndices) {
-    let subaddresses = [];
-    for (let subaddressJson of (await this._invokeWorker("getSubaddresses", Array.from(arguments)))) {
-      subaddresses.push(MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson)));
-    }
-    return subaddresses;
-  }
-  
-  async createSubaddress(accountIdx, label) {
-    let subaddressJson = await this._invokeWorker("createSubaddress", Array.from(arguments));
-    return MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson));
-  }
-  
-  async getTxs(query, missingTxHashes) {
-    query = MoneroWallet._normalizeTxQuery(query);
-    let blockJsons = await this._invokeWorker("getTxs", [query.getBlock().toJson()]);
-    return MoneroWalletWasm._deserializeTxs(query, JSON.stringify({blocks: blockJsons}), missingTxHashes); // initialize txs from blocks json string TODO: this stringifies then utility parses, avoid
-  }
-  
-  async getTransfers(query) {
-    query = MoneroWallet._normalizeTransferQuery(query);
-    let blockJsons = await this._invokeWorker("getTransfers", [query.getTxQuery().getBlock().toJson()]);
-    return MoneroWalletWasm._deserializeTransfers(query, JSON.stringify({blocks: blockJsons})); // initialize transfers from blocks json string TODO: this stringifies then utility parses, avoid
-  }
-  
-  async getOutputs(query) {
-    query = MoneroWallet._normalizeOutputQuery(query);
-    let blockJsons = await this._invokeWorker("getOutputs", [query.getTxQuery().getBlock().toJson()]);
-    return MoneroWalletWasm._deserializeOutputs(query, JSON.stringify({blocks: blockJsons})); // initialize transfers from blocks json string TODO: this stringifies then utility parses, avoid
-  }
-  
-  async getOutputsHex() {
-    return this._invokeWorker("getOutputsHex");
-  }
-  
-  async importOutputsHex(outputsHex) {
-    return this._invokeWorker("importOutputsHex", [outputsHex]);
-  }
-  
-  async getKeyImages() {
-    let keyImages = [];
-    for (let keyImageJson of await this._invokeWorker("getKeyImages")) keyImages.push(new MoneroKeyImage(keyImageJson));
-    return keyImages;
-  }
-  
-  async importKeyImages(keyImages) {
-    let keyImagesJson = [];
-    for (let keyImage of keyImages) keyImagesJson.push(keyImage.toJson());
-    return new MoneroKeyImageImportResult(await this._invokeWorker("importKeyImages", [keyImagesJson]));
-  }
-  
-  async getNewKeyImagesFromLastImport() {
-    throw new MoneroError("MoneroWalletWasm.getNewKeyImagesFromLastImport() not implemented");
-  }
-  
-  async createTxs(config) {
-    config = MoneroWallet._normalizeCreateTxsConfig(config);
-    let txSetJson = await this._invokeWorker("createTxs", [config.toJson()]);
-    return new MoneroTxSet(txSetJson).getTxs();
-  }
-  
-  async sweepOutput(config) {
-    config = MoneroWallet._normalizeSweepOutputConfig(config);
-    let txSetJson = await this._invokeWorker("sweepOutput", [config.toJson()]);
-    return new MoneroTxSet(txSetJson).getTxs()[0];
-  }
-
-  async sweepUnlocked(config) {
-    config = MoneroWallet._normalizeSweepUnlockedConfig(config);
-    let txSetsJson = await this._invokeWorker("sweepUnlocked", [config.toJson()]);
-    let txs = [];
-    for (let txSetJson of txSetsJson) for (let tx of new MoneroTxSet(txSetJson).getTxs()) txs.push(tx);
-    return txs;
-  }
-  
-  async sweepDust(relay) {
-    return new MoneroTxSet(await this._invokeWorker("sweepDust", [relay])).getTxs();
-  }
-  
-  async relayTxs(txsOrMetadatas) {
-    assert(Array.isArray(txsOrMetadatas), "Must provide an array of txs or their metadata to relay");
-    let txMetadatas = [];
-    for (let txOrMetadata of txsOrMetadatas) txMetadatas.push(txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata);
-    return this._invokeWorker("relayTxs", [txMetadatas]);
-  }
-  
-  async parseTxSet(txSet) {
-    return new MoneroTxSet(await this._invokeWorker("parseTxSet", [txSet.toJson()]));
-  }
-  
-  async signTxs(unsignedTxHex) {
-    return this._invokeWorker("signTxs", Array.from(arguments));
-  }
-  
-  async submitTxs(signedTxHex) {
-    return this._invokeWorker("submitTxs", Array.from(arguments));
-  }
-  
-  async signMessage(message) {
-    return this._invokeWorker("signMessage", Array.from(arguments));
-  }
-  
-  async verifyMessage(message, address, signature) {
-    return this._invokeWorker("verifyMessage", Array.from(arguments));
-  }
-  
-  async getTxKey(txHash) {
-    return this._invokeWorker("getTxKey", Array.from(arguments));
-  }
-  
-  async checkTxKey(txHash, txKey, address) {
-    return new MoneroCheckTx(await this._invokeWorker("checkTxKey", Array.from(arguments)));
-  }
-  
-  async getTxProof(txHash, address, message) {
-    return this._invokeWorker("getTxProof", Array.from(arguments));
-  }
-  
-  async checkTxProof(txHash, address, message, signature) {
-    return new MoneroCheckTx(await this._invokeWorker("checkTxProof", Array.from(arguments)));
-  }
-  
-  async getSpendProof(txHash, message) {
-    return this._invokeWorker("getSpendProof", Array.from(arguments));
-  }
-  
-  async checkSpendProof(txHash, message, signature) {
-    return this._invokeWorker("checkSpendProof", Array.from(arguments));
-  }
-  
-  async getReserveProofWallet(message) {
-    return this._invokeWorker("getReserveProofWallet", Array.from(arguments));
-  }
-  
-  async getReserveProofAccount(accountIdx, amount, message) {
-    return this._invokeWorker("getReserveProofAccount", Array.from(arguments));
-  }
-
-  async checkReserveProof(address, message, signature) {
-    return new MoneroCheckReserve(await this._invokeWorker("checkReserveProof", Array.from(arguments)));
-  }
-  
-  async getTxNotes(txHashes) {
-    return this._invokeWorker("getTxNotes", Array.from(arguments));
-  }
-  
-  async setTxNotes(txHashes, notes) {
-    return this._invokeWorker("setTxNotes", Array.from(arguments));
-  }
-  
-  async getAddressBookEntries(entryIndices) {
-    if (!entryIndices) entryIndices = [];
-    let entries = [];
-    for (let entryJson of await this._invokeWorker("getAddressBookEntries", Array.from(arguments))) {
-      entries.push(new MoneroAddressBookEntry(entryJson));
-    }
-    return entries;
-  }
-  
-  async addAddressBookEntry(address, description) {
-    return this._invokeWorker("addAddressBookEntry", Array.from(arguments));
-  }
-  
-  async editAddressBookEntry(index, setAddress, address, setDescription, description) {
-    return this._invokeWorker("editAddressBookEntry", Array.from(arguments));
-  }
-  
-  async deleteAddressBookEntry(entryIdx) {
-    return this._invokeWorker("deleteAddressBookEntry", Array.from(arguments));
-  }
-  
-  async tagAccounts(tag, accountIndices) {
-    return this._invokeWorker("tagAccounts", Array.from(arguments));
-  }
-
-  async untagAccounts(accountIndices) {
-    return this._invokeWorker("untagAccounts", Array.from(arguments));
-  }
-  
-  async getAccountTags() {
-    return this._invokeWorker("getAccountTags", Array.from(arguments));
-  }
-
-  async setAccountTagLabel(tag, label) {
-    return this._invokeWorker("setAccountTagLabel", Array.from(arguments));
-  }
-  
-  async createPaymentUri(config) {
-    config = MoneroWallet._normalizeCreateTxsConfig(config);
-    return this._invokeWorker("createPaymentUri", [config.toJson()]);
-  }
-  
-  async parsePaymentUri(uri) {
-    return new MoneroTxConfig(await this._invokeWorker("parsePaymentUri", Array.from(arguments)));
-  }
-  
-  async getAttribute(key) {
-    return this._invokeWorker("getAttribute", Array.from(arguments));
-  }
-  
-  async setAttribute(key, val) {
-    return this._invokeWorker("setAttribute", Array.from(arguments));
-  }
-  
-  async startMining(numThreads, backgroundMining, ignoreBattery) {
-    return this._invokeWorker("startMining", Array.from(arguments));
-  }
-  
-  async stopMining() {
-    return this._invokeWorker("stopMining", Array.from(arguments));
-  }
-  
-  async isMultisigImportNeeded() {
-    return this._invokeWorker("isMultisigImportNeeded");
-  }
-  
-  async isMultisig() {
-    return this._invokeWorker("isMultisig");
-  }
-  
-  async getMultisigInfo() {
-    return new MoneroMultisigInfo(await this._invokeWorker("getMultisigInfo"));
-  }
-  
-  async prepareMultisig() {
-    return this._invokeWorker("prepareMultisig");
-  }
-  
-  async makeMultisig(multisigHexes, threshold, password) {
-    return new MoneroMultisigInitResult(await this._invokeWorker("makeMultisig", Array.from(arguments)));
-  }
-  
-  async exchangeMultisigKeys(multisigHexes, password) {
-    return new MoneroMultisigInitResult(await this._invokeWorker("exchangeMultisigKeys", Array.from(arguments)));
-  }
-  
-  async getMultisigHex() {
-    return this._invokeWorker("getMultisigHex");
-  }
-  
-  async importMultisigHex(multisigHexes) {
-    return this._invokeWorker("importMultisigHex", Array.from(arguments));
-  }
-  
-  async signMultisigTxHex(multisigTxHex) {
-    return new MoneroMultisigSignResult(await this._invokeWorker("signMultisigTxHex", Array.from(arguments)));
-  }
-  
-  async submitMultisigTxHex(signedMultisigTxHex) {
-    return this._invokeWorker("submitMultisigTxHex", Array.from(arguments));
-  }
-  
-  async getData() {
-    return this._invokeWorker("getData");
-  }
-  
-  async moveTo(path, password) {
-    throw new Error("MoneroWalletWasmProxy.moveTo() not implemented");
-  }
-  
-  // TODO: factor this duplicate code with MoneroWalletWasm save(), common util
-  async save() {
-    assert(!await this.isClosed(), "Wallet is closed");
-    
-    // path must be set
-    let path = await this.getPath();
-    if (!path) throw new MoneroError("Cannot save wallet because path is not set");
-    
-    // write address file
-    this._fs.writeFileSync(path + ".address.txt", await this.getPrimaryAddress());
-    
-    // write keys and cache data
-    let data = await this.getData();
-    this._fs.writeFileSync(path + ".keys", data[0], "binary");
-    this._fs.writeFileSync(path, data[1], "binary");
-  }
-  
-  async close(save) {
-    if (save) await this.save();
-    while (this._wrappedListeners.length) await this.removeListener(this._wrappedListeners[0].getListener());
-    await this._invokeWorker("close");
-    delete LibraryUtils.WORKER_OBJECTS[this._walletId];
-  }
-  
-  async isClosed() {
-    return this._invokeWorker("isClosed");
-  }
-  
-  // --------------------------- PRIVATE HELPERS ------------------------------
-  
-  async _invokeWorker(fnName, args) {
-    return LibraryUtils.invokeWorker(this._walletId, fnName, args);
-  }
-}
-
-/**
- * Internal listener to bridge notifications to external listeners.
- * 
- * @private
- */
-class WalletWorkerListener {
-  
-  constructor(listener) {
-    this._id = GenUtils.getUUID();
-    this._listener = listener;
-  }
-  
-  getId() {
-    return this._id;
-  }
-  
-  getListener() {
-    return this._listener;
-  }
-  
-  onSyncProgress(height, startHeight, endHeight, percentDone, message) {
-    this._listener.onSyncProgress(height, startHeight, endHeight, percentDone, message);
-  }
-
-  onNewBlock(height) {
-    this._listener.onNewBlock(height);
-  }
-  
-  onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) {
-    this._listener.onBalancesChanged(BigInteger.parse(newBalanceStr), BigInteger.parse(newUnlockedBalanceStr));
-  }
-
-  onOutputReceived(blockJson) {
-    let block = new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET);
-    this._listener.onOutputReceived(block.getTxs()[0].getOutputs()[0]);
-  }
-  
-  onOutputSpent(blockJson) {
-    let block = new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET);
-    this._listener.onOutputSpent(block.getTxs()[0].getInputs()[0]);
-  }
-}
-
-module.exports = MoneroWalletWasm;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroAccount.js.html b/docs/src_main_js_wallet_model_MoneroAccount.js.html deleted file mode 100644 index cf8efec09..000000000 --- a/docs/src_main_js_wallet_model_MoneroAccount.js.html +++ /dev/null @@ -1,181 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroAccount.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroAccount.js

- - - - - - -
-
-
const assert = require("assert");
-const BigInteger = require("../../common/biginteger").BigInteger;
-const MoneroSubaddress = require("./MoneroSubaddress");
-
-/**
- * Monero account model.
- */
-class MoneroAccount {
-  
-  constructor(stateOrIndex, primaryAddress, balance, unlockedBalance, subaddresses) {
-    
-    // construct from json
-    if (typeof stateOrIndex === "object") {
-      this.state = stateOrIndex;
-      
-      // deserialize balances
-      if (this.state.balance !== undefined && !(this.state.balance instanceof BigInteger)) this.state.balance = BigInteger.parse(this.state.balance);
-      if (this.state.unlockedBalance !== undefined && !(this.state.unlockedBalance instanceof BigInteger)) this.state.unlockedBalance = BigInteger.parse(this.state.unlockedBalance);
-      
-      // deserialize subaddresses
-      if (this.state.subaddresses) {
-        for (let i = 0; i < this.state.subaddresses.length; i++) {
-          if (!(this.state.subaddresses[i] instanceof MoneroSubaddress)) {
-            this.state.subaddresses[i] = new MoneroSubaddress(this.state.subaddresses[i]);
-          }
-        }
-      }
-    }
-    
-    // construct from individual params
-    else {
-      this.state = {};
-      this.setIndex(stateOrIndex);
-      this.setPrimaryAddress(primaryAddress);
-      this.setBalance(balance);
-      this.setUnlockedBalance(unlockedBalance);
-      this.setSubaddresses(subaddresses);
-    }
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (json.balance) json.balance = json.balance.toString();
-    if (json.unlockedBalance) json.unlockedBalance = json.unlockedBalance.toString();
-    if (json.subaddresses) {
-      for (let i = 0; i < json.subaddresses.length; i++) {
-        json.subaddresses[i] = json.subaddresses[i].toJson();
-      }
-    }
-    return json;
-  }
-  
-  getIndex() {
-    return this.state.index;
-  }
-  
-  setIndex(index) {
-    this.state.index = index;
-    return this;
-  }
-  
-  getPrimaryAddress() {
-    return this.state.primaryAddress;
-  }
-
-  setPrimaryAddress(primaryAddress) {
-    this.state.primaryAddress = primaryAddress;
-    return this;
-  }
-  
-  getBalance() {
-    return this.state.balance;
-  }
-  
-  setBalance(balance) {
-    this.state.balance = balance;
-    return this;
-  }
-  
-  getUnlockedBalance() {
-    return this.state.unlockedBalance;
-  }
-  
-  setUnlockedBalance(unlockedBalance) {
-    this.state.unlockedBalance = unlockedBalance;
-    return this;
-  }
-  
-  getTag() {
-    return this.state.tag;
-  }
-  
-  setTag(tag) {
-    this.state.tag = tag;
-    return this;
-  }
-  
-  getSubaddresses() {
-    return this.state.subaddresses;
-  }
-  
-  setSubaddresses(subaddresses) {
-    assert(subaddresses === undefined || Array.isArray(subaddresses), "Given subaddresses must be undefined or an array of subaddresses");
-    this.state.subaddresses = subaddresses;
-    if (subaddresses) {
-      for (let subaddress of subaddresses) {
-        subaddress.setAccountIndex(this.state.index);
-      }
-    }
-    return this;
-  }
-  
-  toString(indent = 0) {
-    let str = "";
-    str += GenUtils.kvLine("Index", this.getIndex(), indent);
-    str += GenUtils.kvLine("Primary address", this.getPrimaryAddress(), indent);
-    str += GenUtils.kvLine("Balance", this.getBalance(), indent);
-    str += GenUtils.kvLine("Unlocked balance", this.getUnlockedBalance(), indent);
-    str += GenUtils.kvLine("Tag", this.getTag(), indent);
-    if (this.getSubaddresses() != null) {
-      sb += GenUtils.kvLine("Subaddresses", "", indent)
-      for (let i = 0; i < this.getSubaddresses().size(); i++) {
-        str += GenUtils.kvLine(i + 1, "", indent + 1);
-        str += this.getSubaddresses()[i].toString(indent + 2) + "\n";
-      }
-    }
-    return str.slice(0, str.length - 1);  // strip last newline
-  }
-}
-
-module.exports = MoneroAccount;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroAccountTag.js.html b/docs/src_main_js_wallet_model_MoneroAccountTag.js.html deleted file mode 100644 index 696c32a4f..000000000 --- a/docs/src_main_js_wallet_model_MoneroAccountTag.js.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroAccountTag.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroAccountTag.js

- - - - - - -
-
-
/**
- * Represents an account tag.
- */
-class MoneroAccountTag {
-  
-  constructor(tag, label, accountIndices) {
-    this.tag = tag;
-    this.label = label;
-    this.accountIndices = accountIndices;
-  }
-  
-  getTag() {
-    return this.tag;
-  }
-  
-  setTag(tag) {
-    this.tag = tag;
-    return this;
-  }
-  
-  getLabel() {
-    return this.label;
-  }
-  
-  setLabel(label) {
-    this.label = label;
-    return this;
-  }
-  
-  getAccountIndices() {
-    return this.accountIndices;
-  }
-  
-  setAccountIndices(accountIndices) {
-    this.accoutIndices = accountIndices;
-    return this;
-  }
-}
-
-module.exports = MoneroAccountTag;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroAddressBookEntry.js.html b/docs/src_main_js_wallet_model_MoneroAddressBookEntry.js.html deleted file mode 100644 index cc892c4c8..000000000 --- a/docs/src_main_js_wallet_model_MoneroAddressBookEntry.js.html +++ /dev/null @@ -1,101 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroAddressBookEntry.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroAddressBookEntry.js

- - - - - - -
-
-
/**
- * Monero address book entry model
- */
-class MoneroAddressBookEntry {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-  }
-  
-  toJson() {
-    return Object.assign({}, this.state);
-  }
-  
-  getIndex() {
-    return this.state.index;
-  }
-  
-  setIndex(index) {
-    this.state.index = index;
-    return this;
-  }
-  
-  getAddress() {
-    return this.state.address;
-  }
-  
-  setAddress(address) {
-    this.state.address = address;
-    return this;
-  }
-  
-  getDescription() {
-    return this.state.description;
-  }
-  
-  setDescription(description) {
-    this.state.description = description;
-    return this;
-  }
-  
-  getPaymentId() {
-    return this.state.paymentId;
-  }
-  
-  setPaymentId(paymentId) {
-    this.state.paymentId = paymentId;
-    return this;
-  }
-}
-
-module.exports = MoneroAddressBookEntry;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroCheck.js.html b/docs/src_main_js_wallet_model_MoneroCheck.js.html deleted file mode 100644 index bfac51194..000000000 --- a/docs/src_main_js_wallet_model_MoneroCheck.js.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroCheck.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroCheck.js

- - - - - - -
-
-
/**
- * Base class for results from checking a transaction or reserve proof.
- * 
- * @class
- */
-class MoneroCheck {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-  }
-
-  isGood() {
-    return this.state.isGood;
-  }
-
-  setIsGood(isGood) {
-    this.state.isGood = isGood;
-    return this;
-  }
-}
-
-module.exports = MoneroCheck;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroCheckReserve.js.html b/docs/src_main_js_wallet_model_MoneroCheckReserve.js.html deleted file mode 100644 index ea2064ef1..000000000 --- a/docs/src_main_js_wallet_model_MoneroCheckReserve.js.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroCheckReserve.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroCheckReserve.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-const MoneroCheck = require("./MoneroCheck");
-
-/**
- * Results from checking a reserve proof.
- * 
- * @extends {MoneroCheck}
- */
-class MoneroCheckReserve extends MoneroCheck {
-  
-  constructor(state) {
-    super(state);
-    if (this.state.totalAmount !== undefined && !(this.state.totalAmount instanceof BigInteger)) this.state.totalAmount = BigInteger.parse(this.state.totalAmount);
-    if (this.state.unconfirmedSpentAmount !== undefined && !(this.state.unconfirmedSpentAmount instanceof BigInteger)) this.state.unconfirmedSpentAmount = BigInteger.parse(this.state.unconfirmedSpentAmount);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (this.getTotalAmount()) json.totalAmount = this.getTotalAmount().toString();
-    if (this.getUnconfirmedSpentAmount()) json.unconfirmedSpentAmount = this.getUnconfirmedSpentAmount().toString();
-    return json;
-  }
-  
-  getTotalAmount() {
-    return this.state.totalAmount;
-  }
-
-  setTotalAmount(totalAmount) {
-    this.state.totalAmount = totalAmount;
-    return this;
-  }
-  
-  getUnconfirmedSpentAmount() {
-    return this.state.unconfirmedSpentAmount;
-  }
-
-  setUnconfirmedSpentAmount(unconfirmedSpentAmount) {
-    this.state.unconfirmedSpentAmount = unconfirmedSpentAmount;
-    return this;
-  }
-}
-
-module.exports = MoneroCheckReserve;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroCheckTx.js.html b/docs/src_main_js_wallet_model_MoneroCheckTx.js.html deleted file mode 100644 index cd175de94..000000000 --- a/docs/src_main_js_wallet_model_MoneroCheckTx.js.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroCheckTx.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroCheckTx.js

- - - - - - -
-
-
const MoneroCheck = require("./MoneroCheck");
-const BigInteger = require("../../common/biginteger").BigInteger;
-
-/**
- * Results from checking a transaction key.
- * 
- * @extends {MoneroCheck}
- */
-class MoneroCheckTx extends MoneroCheck {
-  
-  constructor(state) {
-    super(state);
-    if (this.state.receivedAmount !== undefined && !(this.state.receivedAmount instanceof BigInteger)) this.state.receivedAmount = BigInteger.parse(this.state.receivedAmount);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, state);
-    if (this.getReceivedAmount()) json.receivedAmount = this.getReceivedAmount().toString();
-    return json;
-  }
-
-  inTxPool() {
-    return this.state.inTxPool;
-  }
-  
-  setInTxPool(inTxPool) {
-    this.state.inTxPool = inTxPool;
-    return this;
-  }
-  
-  getNumConfirmations() {
-    return this.state.numConfirmations;
-  }
-  
-  setNumConfirmations(numConfirmations) {
-    this.state.numConfirmations = numConfirmations;
-    return this;
-  }
-  
-  getReceivedAmount() {
-    return this.state.receivedAmount;
-  }
-  
-  setReceivedAmount(receivedAmount) {
-    this.state.receivedAmount = receivedAmount;
-    return this;
-  }
-}
-
-module.exports = MoneroCheckTx;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroDestination.js.html b/docs/src_main_js_wallet_model_MoneroDestination.js.html deleted file mode 100644 index 34848ed08..000000000 --- a/docs/src_main_js_wallet_model_MoneroDestination.js.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroDestination.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroDestination.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-const GenUtils = require("../../common/GenUtils");
-
-/**
- * Models an outgoing transfer destination.
- */
-class MoneroDestination {
-  
-  /**
-   * Construct the model.
-   * 
-   * @param {MoneroDestination|object|string} stateOrAddress is a MoneroDestination, JS object, or hex string to initialize from (optional)
-   * @param {BigInteger|string} amount - the destination amount
-   */
-  constructor(stateOrAddress, amount) {
-    
-    // initialize internal state
-    if (!stateOrAddress) this.state = {};
-    else if (stateOrAddress instanceof MoneroDestination) this.state = stateOrAddress.toJson();
-    else if (typeof stateOrAddress === "object") this.state = Object.assign({}, stateOrAddress);
-    else if (typeof stateOrAddress === "string")  {
-      this.state = {};
-      this.setAddress(stateOrAddress);
-      this.setAmount(amount);
-    } else {
-      throw new MoneroError("stateOrAddress must be a MoneroDestination, JavaScript object, or hex string");
-    }
-      
-    // deserialize amount  
-    if (amount) this.state.amount = amount;
-    if (this.state.amount !== undefined && !(this.state.amount instanceof BigInteger)) this.state.amount = BigInteger.parse(this.state.amount);
-  }
-  
-  getAddress() {
-    return this.state.address;
-  }
-
-  setAddress(address) {
-    this.state.address = address;
-    return this;
-  }
-  
-  getAmount() {
-    return this.state.amount;
-  }
-
-  setAmount(amount) {
-    this.state.amount = amount;
-    return this;
-  }
-
-  copy() {
-    return new MoneroDestination(this);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (this.getAmount()) json.amount = this.getAmount().toString();
-    return json;
-  }
-  
-  toString(indent = 0) {
-    let str = GenUtils.kvLine("Address", this.getAddress(), indent);
-    str += GenUtils.kvLine("Amount", this.getAmount() ? this.getAmount().toString() : undefined, indent);
-    return str.slice(0, str.length - 1);  // strip last newline
-  }
-}
-
-module.exports = MoneroDestination;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroIncomingTransfer.js.html b/docs/src_main_js_wallet_model_MoneroIncomingTransfer.js.html deleted file mode 100644 index 3c2e813ec..000000000 --- a/docs/src_main_js_wallet_model_MoneroIncomingTransfer.js.html +++ /dev/null @@ -1,146 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroIncomingTransfer.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroIncomingTransfer.js

- - - - - - -
-
-
const assert = require("assert");
-const GenUtils = require("../../common/GenUtils");
-const MoneroTransfer = require("./MoneroTransfer");
-
-/**
- * Models an incoming transfer of funds to the wallet.
- * 
- * @extends {MoneroTransfer}
- */
-class MoneroIncomingTransfer extends MoneroTransfer {
-  
-  /**
-   * Construct the model.
-   * 
-   * @param {MoneroTransfer|object} state is existing state to initialize from (optional)
-   */
-  constructor(state) {
-    super(state);
-  }
-  
-  isIncoming() {
-    return true;
-  }
-  
-  getSubaddressIndex() {
-    return this.state.subaddressIndex;
-  }
-  
-  setSubaddressIndex(subaddressIndex) {
-    this.state.subaddressIndex = subaddressIndex;
-    return this;
-  }
-  
-  getAddress() {
-    return this.state.address;
-  }
-
-  setAddress(address) {
-    this.state.address = address;
-    return this;
-  }
-  
-  /**
-   * Return how many confirmations till it's not economically worth re-writing the chain.
-   * That is, the number of confirmations before the transaction is highly unlikely to be
-   * double spent or overwritten and may be considered settled, e.g. for a merchant to trust
-   * as finalized.
-   * 
-   * @return {number} is the number of confirmations before it's not worth rewriting the chain
-   */
-  getNumSuggestedConfirmations() {
-    return this.state.numSuggestedConfirmations;
-  }
-  
-  setNumSuggestedConfirmations(numSuggestedConfirmations) {
-    this.state.numSuggestedConfirmations = numSuggestedConfirmations;
-    return this;
-  }
-
-  copy() {
-    return new MoneroIncomingTransfer(this.toJson());
-  }
-  
-  /**
-   * Updates this transaction by merging the latest information from the given
-   * transaction.
-   * 
-   * Merging can modify or build references to the transfer given so it
-   * should not be re-used or it should be copied before calling this method.
-   * 
-   * @param {MoneroIncomingTransfer} transfer is the transfer to merge into this one
-   */
-  merge(transfer) {
-    super.merge(transfer);
-    assert(transfer instanceof MoneroIncomingTransfer);
-    if (this === transfer) return this;
-    this.setSubaddressIndex(GenUtils.reconcile(this.getSubaddressIndex(), transfer.getSubaddressIndex()));
-    this.setAddress(GenUtils.reconcile(this.getAddress(), transfer.getAddress()));
-    this.setNumSuggestedConfirmations(GenUtils.reconcile(this.getNumSuggestedConfirmations(), transfer.getNumSuggestedConfirmations(), {resolveMax: false}));
-    return this;
-  }
-  
-  toString() {
-    return this.toString(0);
-  }
-  
-  toString(indent) {
-    let str = super.toString(indent) + "\n";
-    str += GenUtils.kvLine("Subaddress index", this.getSubaddressIndex(), indent);
-    str += GenUtils.kvLine("Address", this.getAddress(), indent);
-    str += GenUtils.kvLine("Num suggested confirmations", this.getNumSuggestedConfirmations(), indent);
-    return str.slice(0, str.length - 1);  // strip last newline
-  }
-}
-
-module.exports = MoneroIncomingTransfer;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroIntegratedAddress.js.html b/docs/src_main_js_wallet_model_MoneroIntegratedAddress.js.html deleted file mode 100644 index a88645c99..000000000 --- a/docs/src_main_js_wallet_model_MoneroIntegratedAddress.js.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroIntegratedAddress.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroIntegratedAddress.js

- - - - - - -
-
-
/**
- * Monero integrated address model.
- */
-class MoneroIntegratedAddress {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-  }
-  
-  toJson() {
-    return Object.assign({}, this.state);
-  }
-
-  getStandardAddress() {
-    return this.state.standardAddress;
-  }
-  
-  setStandardAddress(standardAddress) {
-    this.state.standardAddress = standardAddress;
-    return this;
-  }
-  
-  getPaymentId() {
-    return this.state.paymentId;
-  }
-  
-  setPaymentId(paymentId) {
-    this.state.paymentId = paymentId;
-    return this;
-  }
-  
-  getIntegratedAddress() {
-    return this.state.integratedAddress;
-  }
-  
-  setIntegratedAddress(integratedAddress) {
-    this.state.integratedAddress = integratedAddress;
-    return this;
-  }
-  
-  toString() {
-    return this.state.integratedAddress;
-  }
-}
-
-module.exports = MoneroIntegratedAddress;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroKeyImageImportResult.js.html b/docs/src_main_js_wallet_model_MoneroKeyImageImportResult.js.html deleted file mode 100644 index a6a572b62..000000000 --- a/docs/src_main_js_wallet_model_MoneroKeyImageImportResult.js.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroKeyImageImportResult.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroKeyImageImportResult.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-
-/**
- * Models results from importing key images.
- */
-class MoneroKeyImageImportResult {
-  
-  constructor(state) {
-    state = Object.assign({}, state);
-    if (state.spentAmount !== undefined && !(state.spentAmount instanceof BigInteger)) state.spentAmount = BigInteger.parse(state.spentAmount);
-    if (state.unspentAmount !== undefined && !(state.unspentAmount instanceof BigInteger)) state.unspentAmount = BigInteger.parse(state.unspentAmount);
-    this.state = state;
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (this.getSpentAmount()) json.spentAmount = this.getSpentAmount().toString();
-    if (this.getUnspentAmount()) json.unspentAmount = this.getUnspentAmount().toString();
-    return json;
-  }
-  
-  getHeight() {
-    return this.state.height;
-  }
-  
-  setHeight(height) {
-    this.state.height = height;
-    return this;
-  }
-  
-  getSpentAmount() {
-    return this.state.spentAmount;
-  }
-  
-  setSpentAmount(spentAmount) {
-    this.state.spentAmount = spentAmount;
-    return this;
-  }
-  
-  getUnspentAmount() {
-    return this.state.unspentAmount;
-  }
-  
-  setUnspentAmount(unspentAmount) {
-    this.state.unspentAmount = unspentAmount;
-    return this;
-  }
-}
-
-module.exports = MoneroKeyImageImportResult;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroMultisigInfo.js.html b/docs/src_main_js_wallet_model_MoneroMultisigInfo.js.html deleted file mode 100644 index 585c2f479..000000000 --- a/docs/src_main_js_wallet_model_MoneroMultisigInfo.js.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroMultisigInfo.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroMultisigInfo.js

- - - - - - -
-
-
/**
- * Models information about a multisig wallet.
- */
-class MoneroMultisigInfo {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-  }
-  
-  toJson() {
-    return Object.assign({}, this.state);
-  }
-  
-  isMultisig() {
-    return this.state.isMultisig;
-  }
-  
-  setIsMultisig(isMultisig) {
-    this.state.isMultisig = isMultisig;
-    return this;
-  }
-  
-  isReady() {
-    return this.state.isReady;
-  }
-  
-  setIsReady(isReady) {
-    this.state.isReady = isReady;
-  }
-  
-  getThreshold() {
-    return this.state.threshold;
-  }
-  
-  setThreshold(threshold) {
-    this.state.threshold = threshold;
-  }
-  
-  getNumParticipants() {
-    return this.state.numParticipants;
-  }
-  
-  setNumParticipants(numParticipants) {
-    this.state.numParticipants = numParticipants;
-  }
-}
-
-module.exports = MoneroMultisigInfo;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroMultisigInitResult.js.html b/docs/src_main_js_wallet_model_MoneroMultisigInitResult.js.html deleted file mode 100644 index c6fccef25..000000000 --- a/docs/src_main_js_wallet_model_MoneroMultisigInitResult.js.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroMultisigInitResult.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroMultisigInitResult.js

- - - - - - -
-
-
/**
- * Models the result of initializing a multisig wallet which results in the
- * multisig wallet's address xor another multisig hex to share with
- * participants to create the wallet.
- */
-class MoneroMultisigInitResult {
-
-  constructor(state) {
-    this.state = Object.assign({}, state);
-  }
-  
-  toJson() {
-    return Object.assign({}, this.state);
-  }
-  
-  getAddress() {
-    return this.state.address;
-  }
-  
-  setAddress(address) {
-    this.state.address = address;
-    return this;
-  }
-  
-  getMultisigHex() {
-    return this.state.multisigHex;
-  }
-  
-  setMultisigHex(multisigHex) {
-    this.state.multisigHex = multisigHex;
-    return this;
-  }
-}
-
-module.exports = MoneroMultisigInitResult;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroMultisigSignResult.js.html b/docs/src_main_js_wallet_model_MoneroMultisigSignResult.js.html deleted file mode 100644 index 91d3e17d4..000000000 --- a/docs/src_main_js_wallet_model_MoneroMultisigSignResult.js.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroMultisigSignResult.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroMultisigSignResult.js

- - - - - - -
-
-
/**
- * Models the result of signing multisig tx hex.
- */
-class MoneroMultisigSignResult {
-  
-  constructor(state) {
-    this.state = Object.assign({}, state);
-  }
-  
-  toJson() {
-    return Object.assign({}, this.state);
-  }
-  
-  getSignedMultisigTxHex() {
-    return this.state.signedMultisigTxHex;
-  }
-
-  setSignedMultisigTxHex(signedTxMultisigHex) {
-    this.state.signedMultisigTxHex = signedTxMultisigHex;
-  }
-
-  getTxHashes() {
-    return this.state.txHashes;
-  }
-
-  setTxHashes(txHashes) {
-    this.state.txHashes = txHashes;
-  }
-}
-
-module.exports = MoneroMultisigSignResult;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroOutgoingTransfer.js.html b/docs/src_main_js_wallet_model_MoneroOutgoingTransfer.js.html deleted file mode 100644 index a600d3b59..000000000 --- a/docs/src_main_js_wallet_model_MoneroOutgoingTransfer.js.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroOutgoingTransfer.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroOutgoingTransfer.js

- - - - - - -
-
-
const assert = require("assert");
-const GenUtils = require("../../common/GenUtils");
-const MoneroDestination = require("./MoneroDestination");
-const MoneroTransfer = require("./MoneroTransfer");
-
-/**
- * Models an outgoing transfer of funds from the wallet.
- * 
- * @extends {MoneroTransfer}
- */
-class MoneroOutgoingTransfer extends MoneroTransfer {
-
-  /**
-   * Construct the model.
-   * 
-   * @param {MoneroOutgoingTranser|object} state is existing state to initialize from (optional)
-   */
-  constructor(state) {
-    super(state);
-    state = this.state;
-    
-    // deserialize destinations
-    if (state.destinations) {
-      for (let i = 0; i < state.destinations.length; i++) {
-        if (!(state.destinations[i] instanceof MoneroDestination)) state.destinations[i] = new MoneroDestination(state.destinations[i]);
-      }
-    }
-  }
-  
-  isIncoming() {
-    return false;
-  }
-  
-  getSubaddressIndices() {
-    return this.state.subaddressIndices;
-  }
-
-  setSubaddressIndices(subaddressIndices) {
-    this.state.subaddressIndices = subaddressIndices;
-    return this;
-  }
-  
-  getAddresses() {
-    return this.state.addresses;
-  }
-
-  setAddresses(addresses) {
-    this.state.addresses = addresses;
-    return this;
-  }
-
-  getDestinations() {
-    return this.state.destinations;
-  }
-  
-  setDestinations(destinations) {
-    this.state.destinations = destinations;
-    return this;
-  }
-  
-  copy() {
-    return new MoneroOutgoingTransfer(this);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state, super.toJson()); // merge json onto inherited state
-    if (this.getDestinations()) {
-      json.destinations = [];
-      for (let destination of this.getDestinations()) json.destinations.push(destination.toJson());
-    }
-    delete json.tx; // parent tx is not serialized
-    return json;
-  }
-  
-  /**
-   * Updates this transaction by merging the latest information from the given
-   * transaction.
-   * 
-   * Merging can modify or build references to the transfer given so it
-   * should not be re-used or it should be copied before calling this method.
-   * 
-   * @param transfer is the transfer to merge into this one
-   */
-  merge(transfer) {
-    super.merge(transfer);
-    assert(transfer instanceof MoneroOutgoingTransfer);
-    if (this === transfer) return this;
-    this.setSubaddressIndices(GenUtils.reconcile(this.getSubaddressIndices(), transfer.getSubaddressIndices()));
-    this.setAddresses(GenUtils.reconcile(this.getAddresses(), transfer.getAddresses()));
-    this.setDestinations(GenUtils.reconcile(this.getDestinations(), transfer.getDestinations()));
-    return this;
-  }
-
-  toString(indent = 0) {
-    let str = super.toString(indent) + "\n";
-    str += GenUtils.kvLine("Subaddress indices", this.getSubaddressIndices(), indent);
-    str += GenUtils.kvLine("Addresses", this.getAddresses(), indent);
-    if (this.getDestinations()) {
-      str += GenUtils.kvLine("Destinations", "", indent);
-      for (let i = 0; i < this.getDestinations().length; i++) {
-        str += GenUtils.kvLine(i + 1, "", indent + 1);
-        str += this.getDestinations()[i].toString(indent + 2) + "\n";
-      }
-    }
-    return str.slice(0, str.length - 1);  // strip last newline
-  }
-}
-
-module.exports = MoneroOutgoingTransfer;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroOutputQuery.js.html b/docs/src_main_js_wallet_model_MoneroOutputQuery.js.html deleted file mode 100644 index c62aa228b..000000000 --- a/docs/src_main_js_wallet_model_MoneroOutputQuery.js.html +++ /dev/null @@ -1,209 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroOutputQuery.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroOutputQuery.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-const MoneroOutputWallet = require("./MoneroOutputWallet");
-
-/**
- * Configuration to query wallet outputs.
- * 
- * @extends {MoneroOutputWallet}
- */
-class MoneroOutputQuery extends MoneroOutputWallet {
-  
-  /**
-   * <p>Construct the output query.</p>
-   * 
-   * <p>Example:</p>
-   * 
-   * <code>
-   * &sol;&sol; get available outputs in account 0 with a minimum amount<br>
-   * let outputs = await wallet.getOutputs({<br>
-   * &nbsp;&nbsp; isSpent: false,<br>
-   * &nbsp;&nbsp; isLocked: false,<br>
-   * &nbsp;&nbsp; accountIndex: 0,<br>
-   * &nbsp;&nbsp; minAmount: new BigInteger("750000")<br>
-   * });
-   * </code>
-   * 
-   * <p>All configuration is optional.  All outputs are returned except those that don't meet criteria defined in this query.</p>
-   * 
-   * @param {object} config - output query configuration (optional)
-   * @param {int} config.accountIndex - get outputs in this account index
-   * @param {int} config.subaddressIndex - get outputs in this subaddress index
-   * @param {int[]} config.subaddressIndices - get outputs in these subaddress indices
-   * @param {BigInteger} config.amount - get outputs with this amount
-   * @param {BigInteger} config.minAmount - get outputs with amount greater than or equal to this amount
-   * @param {BigInteger} config.maxAmount - get outputs with amount less than or equal to this amount
-   * @param {boolean} config.isLocked - get locked xor unlocked outputs
-   * @param {boolean} config.isSpent - get spent xor unspent outputs
-   * @param {object|MoneroKeyImage} config.keyImage - get outputs with a key image matching fields defined in this key image
-   * @param {string} config.keyImage.hex - get outputs with this key image hex
-   * @param {string} config.keyImage.signature - get outputs with this key image signature
-   * @param {object|MoneroTxQuery} config.txQuery - get outputs whose tx match this tx query
-   */
-  constructor(config) {
-    super(config);
-    
-    // deserialize if necessary
-    const MoneroTxQuery = require("./MoneroTxQuery");
-    if (this.state.minAmount !== undefined && !(this.state.minAmount instanceof BigInteger)) this.state.minAmount = BigInteger.parse(this.state.minAmount);
-    if (this.state.maxAmount !== undefined && !(this.state.maxAmount instanceof BigInteger)) this.state.maxAmount = BigInteger.parse(this.state.maxAmount);
-    if (this.state.txQuery && !(this.state.txQuery instanceof MoneroTxQuery)) this.state.txQuery = new MoneroTxQuery(this.state.txQuery);
-    if (this.state.txQuery) this.state.txQuery.setOutputQuery(this);
-  }
-  
-  copy() {
-    return new MoneroOutputQuery(this);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state, super.toJson());
-    if (this.getMinAmount()) json.minAmount = this.getMinAmount().toString();
-    if (this.getMaxAmount()) json.maxAmount = this.getMaxAmount().toString();
-    delete json.txQuery;
-    return json;
-  }
-  
-  getMinAmount() {
-    return this.state.minAmount;
-  }
-
-  setMinAmount(minAmount) {
-    this.state.minAmount = minAmount;
-    return this;
-  }
-
-  getMaxAmount() {
-    return this.state.maxAmount;
-  }
-
-  setMaxAmount(maxAmount) {
-    this.state.maxAmount = maxAmount;
-    return this;
-  }
-  
-  getTxQuery() {
-    return this.state.txQuery;
-  }
-  
-  setTxQuery(txQuery) {
-    this.state.txQuery = txQuery;
-    if (txQuery) txQuery.state.outputQuery = this;
-    return this;
-  }
-  
-  getSubaddressIndices() {
-    return this.state.subaddressIndices;
-  }
-  
-  setSubaddressIndices(subaddressIndices) {
-    this.state.subaddressIndices = subaddressIndices;
-    return this;
-  }
-  
-  /**
-   * Indicates if the this query will fetch locked outputs, unlocked outputs, or both (null).
-   * 
-   * @return true if locked outputs queried, false of unlocked outputs queried, undefined if both
-   */
-  isLocked() {
-    if (this.state.txQuery === undefined) return undefined;
-    return txQuery.isLocked();
-  }
-  
-  /**
-   * Convenience method to query outputs by the locked state of their tx.
-   * 
-   * @param isLocked specifies if the output's tx must be locked or unlocked (optional)
-   * @return {MoneroOutputQuery} this query for chaining
-   */
-  setIsLocked(isLocked) {
-    const MoneroTxQuery = require("./MoneroTxQuery");
-    if (this.state.txQuery === undefined) this.state.txQuery = new MoneroTxQuery();
-    this.state.txQuery.setIsLocked(isLocked);
-    return this;
-  }
-  
-  meetsCriteria(output, queryParent) {
-    if (!(output instanceof MoneroOutputWallet)) throw new Error("Output not given to MoneroOutputQuery.meetsCriteria(output)");
-    if (queryParent === undefined) queryParent = true;
-    
-    // filter on output
-    if (this.getAccountIndex() !== undefined && this.getAccountIndex() !== output.getAccountIndex()) return false;
-    if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() !== output.getSubaddressIndex()) return false;
-    if (this.getAmount() !== undefined && this.getAmount().compare(output.getAmount()) !== 0) return false;
-    if (this.isSpent() !== undefined && this.isSpent() !== output.isSpent()) return false;
-    
-    // filter on output's key image
-    if (this.getKeyImage() !== undefined) {
-      if (output.getKeyImage() === undefined) return false;
-      if (this.getKeyImage().getHex() !== undefined && this.getKeyImage().getHex() !== output.getKeyImage().getHex()) return false;
-      if (this.getKeyImage().getSignature() !== undefined && this.getKeyImage().getSignature() !== output.getKeyImage().getSignature()) return false;
-    }
-    
-    // filter on extensions
-    if (this.getSubaddressIndices() !== undefined && !this.getSubaddressIndices().includes(output.getSubaddressIndex())) return false;
-    
-    // filter with tx query
-    if (this.getTxQuery() && !this.getTxQuery().meetsCriteria(output.getTx(), false)) return false;
-    
-    // filter on remaining fields
-    if (this.getMinAmount() !== undefined && (output.getAmount() === undefined || output.getAmount().compare(this.getMinAmount()) < 0)) return false;
-    if (this.getMaxAmount() !== undefined && (output.getAmount() === undefined || output.getAmount().compare(this.getMaxAmount()) > 0)) return false;
-    
-    // output meets query
-    return true;
-  }
-}
-
-MoneroOutputQuery._EMPTY_OUTPUT = new MoneroOutputWallet();
-
-module.exports = MoneroOutputQuery;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroOutputWallet.js.html b/docs/src_main_js_wallet_model_MoneroOutputWallet.js.html deleted file mode 100644 index fc8c66911..000000000 --- a/docs/src_main_js_wallet_model_MoneroOutputWallet.js.html +++ /dev/null @@ -1,159 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroOutputWallet.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroOutputWallet.js

- - - - - - -
-
-
const assert = require("assert");
-const GenUtils = require("../../common/GenUtils");
-const MoneroOutput = require("../../daemon/model/MoneroOutput");
-
-/**
- * Models a Monero output with wallet extensions.
- * 
- * @class
- * @extends {MoneroOutput}
- */
-class MoneroOutputWallet extends MoneroOutput {
-  
-  /**
-   * Construct the model.
-   * 
-   * @param {MoneroOutputWallet|object} state is existing state to initialize from (optional)
-   */
-  constructor(state) {
-    super(state);
-  }
-  
-  getAccountIndex() {
-    return this.state.accountIndex;
-  }
-
-  setAccountIndex(accountIndex) {
-    this.state.accountIndex = accountIndex;
-    return this;
-  }
-
-  getSubaddressIndex() {
-    return this.state.subaddressIndex;
-  }
-
-  setSubaddressIndex(subaddressIndex) {
-    this.state.subaddressIndex = subaddressIndex;
-    return this;
-  }
-  
-  isSpent() {
-    return this.state.isSpent;
-  }
-
-  setIsSpent(isSpent) {
-    this.state.isSpent = isSpent;
-    return this;
-  }
-  
-  /**
-   * Indicates if this output has been deemed 'malicious' and will therefore
-   * not be spent by the wallet.
-   * 
-   * @return Boolean is whether or not this output is frozen
-   */
-  isFrozen() {
-    return this.state.isFrozen;
-  }
-
-  setIsFrozen(isFrozen) {
-    this.state.isFrozen = isFrozen;
-    return this;
-  }
-  
-  isLocked() {
-    if (this.getTx() === undefined) return undefined;
-    return this.getTx().isLocked();
-  }
-  
-  copy() {
-    return new MoneroOutputWallet(this.toJson());
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state, super.toJson());
-    delete json.tx;
-    return json;
-  }
-  
-  /**
-   * Updates this output by merging the latest information from the given
-   * output.
-   * 
-   * Merging can modify or build references to the output given so it
-   * should not be re-used or it should be copied before calling this method.
-   * 
-   * @param output is the output to merge into this one
-   */
-  merge(output) {
-    assert(output instanceof MoneroOutputWallet);
-    if (this === output) return;
-    super.merge(output);
-    this.setAccountIndex(GenUtils.reconcile(this.getAccountIndex(), output.getAccountIndex()));
-    this.setSubaddressIndex(GenUtils.reconcile(this.getSubaddressIndex(), output.getSubaddressIndex()));
-    this.setIsSpent(GenUtils.reconcile(this.isSpent(), output.isSpent(), {resolveTrue: true})); // output can become spent
-    this.setIsFrozen(GenUtils.reconcile(this.isFrozen(), output.isFrozen()));
-    return this;
-  }
-  
-  toString(indent) {
-    let str = super.toString(indent) + "\n"
-    str += GenUtils.kvLine("Account index", this.getAccountIndex(), indent);
-    str += GenUtils.kvLine("Subaddress index", this.getSubaddressIndex(), indent);
-    str += GenUtils.kvLine("Is spent", this.isSpent(), indent);
-    str += GenUtils.kvLine("Is frozen", this.isFrozen(), indent);
-    return str.slice(0, str.length - 1);  // strip last newline
-  }
-}
-
-module.exports = MoneroOutputWallet;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroSubaddress.js.html b/docs/src_main_js_wallet_model_MoneroSubaddress.js.html deleted file mode 100644 index f25e19f09..000000000 --- a/docs/src_main_js_wallet_model_MoneroSubaddress.js.html +++ /dev/null @@ -1,173 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroSubaddress.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroSubaddress.js

- - - - - - -
-
-
const BigInteger = require("../../common/biginteger").BigInteger;
-const GenUtils = require("../../common/GenUtils");
-
-/**
- * Monero subaddress model.
- */
-class MoneroSubaddress {
-  
-  constructor(stateOrAddress) {
-    if (stateOrAddress === undefined || typeof stateOrAddress === "string") {
-      this.state = {};
-      this.setAddress(stateOrAddress);
-    } else {
-      this.state = stateOrAddress;
-      if (this.state.balance !== undefined && !(this.state.balance instanceof BigInteger)) this.state.balance = BigInteger.parse(this.state.balance);
-      if (this.state.unlockedBalance !== undefined && !(this.state.unlockedBalance instanceof BigInteger)) this.state.unlockedBalance = BigInteger.parse(this.state.unlockedBalance);
-    }
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (json.balance) json.balance = json.balance.toString();
-    if (json.unlockedBalance) json.unlockedBalance = json.unlockedBalance.toString();
-    return json;
-  }
-  
-  getAccountIndex() {
-    return this.state.accountIndex;
-  }
-
-  setAccountIndex(accountIndex) {
-    this.state.accountIndex = accountIndex;
-    return this;
-  }
-
-  getIndex() {
-    return this.state.index;
-  }
-
-  setIndex(index) {
-    this.state.index = index;
-    return this;
-  }
-  
-  getAddress() {
-    return this.state.address;
-  }
-
-  setAddress(address) {
-    this.state.address = address;
-    return this;
-  }
-
-  getLabel() {
-    return this.state.label;
-  }
-
-  setLabel(label) {
-    this.state.label = label;
-    return this;
-  }
-
-  getBalance() {
-    return this.state.balance;
-  }
-
-  setBalance(balance) {
-    this.state.balance = balance;
-    return this;
-  }
-
-  getUnlockedBalance() {
-    return this.state.unlockedBalance;
-  }
-
-  setUnlockedBalance(unlockedBalance) {
-    this.state.unlockedBalance = unlockedBalance;
-    return this;
-  }
-
-  getNumUnspentOutputs() {
-    return this.state.numUnspentOutputs;
-  }
-
-  setNumUnspentOutputs(numUnspentOutputs) {
-    this.state.numUnspentOutputs = numUnspentOutputs;
-    return this;
-  }
-
-  isUsed() {
-    return this.state.isUsed;
-  }
-
-  setIsUsed(isUsed) {
-    this.state.isUsed = isUsed;
-    return this;
-  }
-
-  getNumBlocksToUnlock() {
-    return this.state.numBlocksToUnlock;
-  }
-
-  setNumBlocksToUnlock(numBlocksToUnlock) {
-    this.state.numBlocksToUnlock = numBlocksToUnlock;
-    return this;
-  }
-  
-  toString(indent) {
-    let str = "";
-    str += GenUtils.kvLine("Account index", this.getAccountIndex(), indent);
-    str += GenUtils.kvLine("Subaddress index", this.getIndex(), indent);
-    str += GenUtils.kvLine("Address", this.getAddress(), indent);
-    str += GenUtils.kvLine("Label", this.getLabel(), indent);
-    str += GenUtils.kvLine("Balance", this.getBalance(), indent);
-    str += GenUtils.kvLine("Unlocked balance", this.getUnlockedBalance(), indent);
-    str += GenUtils.kvLine("Num unspent outputs", this.getNumUnspentOutputs(), indent);
-    str += GenUtils.kvLine("Is used", this.isUsed(), indent);
-    str += GenUtils.kvLine("Num blocks to unlock", this.isUsed(), indent);
-    return str.slice(0, str.length - 1);  // strip last newline
-  }
-}
-
-module.exports = MoneroSubaddress;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroSyncResult.js.html b/docs/src_main_js_wallet_model_MoneroSyncResult.js.html deleted file mode 100644 index 3dcb60a13..000000000 --- a/docs/src_main_js_wallet_model_MoneroSyncResult.js.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroSyncResult.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroSyncResult.js

- - - - - - -
-
-
/**
- * Result from syncing a Monero wallet.
- */
-class MoneroSyncResult {
-  
-  constructor(numBlocksFetched, receivedMoney) {
-    this.setNumBlocksFetched(numBlocksFetched);
-    this.setReceivedMoney(receivedMoney);
-  }
-  
-  getNumBlocksFetched() {
-    return this.numBlocksFetched;
-  }
-  
-  setNumBlocksFetched(numBlocksFetched) {
-    this.numBlocksFetched = numBlocksFetched;
-    return this;
-  }
-  
-  getReceivedMoney() {
-    return this.receivedMoney;
-  }
-  
-  setReceivedMoney(receivedMoney) {
-    this.receivedMoney = receivedMoney;
-    return this;
-  }
-}
-
-module.exports = MoneroSyncResult;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroTransfer.js.html b/docs/src_main_js_wallet_model_MoneroTransfer.js.html deleted file mode 100644 index a5c3a7a75..000000000 --- a/docs/src_main_js_wallet_model_MoneroTransfer.js.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroTransfer.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroTransfer.js

- - - - - - -
-
-
const assert = require("assert");
-const BigInteger = require("../../common/biginteger").BigInteger;
-const GenUtils = require("../../common/GenUtils");
-
-/**
- * Models a base transfer of funds to or from the wallet.
- * 
- * @class
- */
-class MoneroTransfer {
-  
-  /**
-   * Construct the model.
-   * 
-   * @param {MoneroTransfer|object} state is existing state to initialize from (optional)
-   */
-  constructor(state) {
-    
-    // initialize internal state
-    if (!state) state = {};
-    else if (state instanceof MoneroTransfer) state = state.toJson();
-    else if (typeof state === "object") state = Object.assign({}, state);
-    else throw new MoneroError("state must be a MoneroTransfer or JavaScript object");
-    this.state = state;
-    
-    // deserialize fields if necessary
-    if (state.amount !== undefined && !(state.amount instanceof BigInteger)) state.amount = BigInteger.parse(state.amount);
-    
-    // validate state
-    this._validate();
-  }
-  
-  copy() {
-    return new MoneroTransfer(this);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state);
-    if (this.getAmount()) json.amount = this.getAmount().toString()
-    delete json.tx; // parent tx is not serialized
-    return json;
-  }
-  
-  getTx() {
-    return this.state.tx;
-  }
-  
-  setTx(tx) {
-    this.state.tx = tx;
-    return this;
-  }
-  
-  isOutgoing() {
-    let isIncoming = this.isIncoming();
-    assert(typeof isIncoming === "boolean");
-    return !isIncoming;
-  }
-  
-  isIncoming() {
-    throw new Error("Subclass must implement");
-  }
-
-  getAccountIndex() {
-    return this.state.accountIndex;
-  }
-
-  setAccountIndex(accountIndex) {
-    this.state.accountIndex = accountIndex;
-    this._validate();
-    return this;
-  }
-
-  getAmount() {
-    return this.state.amount;
-  }
-
-  setAmount(amount) {
-    this.state.amount = amount;
-    return this;
-  }
-  
-  /**
-   * Updates this transaction by merging the latest information from the given
-   * transaction.
-   * 
-   * Merging can modify or build references to the transfer given so it
-   * should not be re-used or it should be copied before calling this method.
-   * 
-   * @param transfer is the transfer to merge into this one
-   * @return {MoneroTransfer} the merged transfer
-   */
-  merge(transfer) {
-    assert(transfer instanceof MoneroTransfer);
-    if (this === transfer) return this;
-    
-    // merge transactions if they're different which comes back to merging transfers
-    if (this.getTx() !== transfer.getTx()) {
-      this.getTx().merge(transfer.getTx());
-      return this;
-    }
-    
-    // otherwise merge transfer fields
-    this.setAccountIndex(GenUtils.reconcile(this.getAccountIndex(), transfer.getAccountIndex()));
-    
-    // TODO monero core: failed tx in pool (after testUpdateLockedDifferentAccounts()) causes non-originating saved wallets to return duplicate incoming transfers but one has amount of 0
-    if (this.getAmount() !== undefined && transfer.getAmount() !== undefined && this.getAmount().compare(transfer.getAmount()) !== 0 && (this.getAmount().compare(BigInteger.parse("0")) === 0 || transfer.getAmount().compare(BigInteger.parse("0")) === 0)) {
-      //throw new Error("WARNING: monero core returning transfers with 0 amount/numSuggestedConfirmations");
-    } else {
-      this.setAmount(GenUtils.reconcile(this.getAmount(), transfer.getAmount()));
-    }
-    
-    return this;
-  }
-  
-  toString(indent = 0) {
-    let str = "";
-    str += GenUtils.kvLine("Is incoming", this.isIncoming(), indent);
-    str += GenUtils.kvLine("Account index", this.getAccountIndex(), indent);
-    str += GenUtils.kvLine("Amount", this.getAmount() ? this.getAmount().toString() : undefined, indent);
-    return str === "" ? str :  str.slice(0, str.length - 1);  // strip last newline
-  }
-  
-  _validate() {
-    if (this.getAccountIndex() !== undefined && this.getAccountIndex() < 0) throw new MoneroError("Account index must be >= 0");
-  }
-}
-
-module.exports = MoneroTransfer;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroTransferQuery.js.html b/docs/src_main_js_wallet_model_MoneroTransferQuery.js.html deleted file mode 100644 index ef6418ae8..000000000 --- a/docs/src_main_js_wallet_model_MoneroTransferQuery.js.html +++ /dev/null @@ -1,271 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroTransferQuery.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroTransferQuery.js

- - - - - - -
-
-
const MoneroIncomingTransfer = require("./MoneroIncomingTransfer");
-const MoneroOutgoingTransfer = require("./MoneroOutgoingTransfer");
-const MoneroTransfer = require("./MoneroTransfer");
-const MoneroError = require("../../common/MoneroError")
-
-/**
- * Configuration to query wallet transfers.
- * 
- * @extends {MoneroTransfer}
- */
-class MoneroTransferQuery extends MoneroTransfer {
-  
-  /**
-   * <p>Construct the transfer query.</p>
-   * 
-   * <p>Example:</p>
-   * 
-   * <code>
-   * &sol;&sol; get incoming transfers to account 0, subaddress 1<br>
-   * let transfers = await wallet.getTransfers({<br>
-   * &nbsp;&nbsp; accountIndex: 0,<br>
-   * &nbsp;&nbsp; subaddressIndex: 0<br>
-   * });
-   * </code>
-   * 
-   * <p>All configuration is optional.  All transfers are returned except those that don't meet criteria defined in this query.</p>
-   * 
-   * @param {object} config - transfer query configuration (optional)
-   * @param {BigInteger} config.amount - get transfers with this amount
-   * @param {int} config.accountIndex - get transfers to/from this account index
-   * @param {int} config.subaddressIndex - get transfers to/from this subaddress index
-   * @param {int[]} config.subaddressIndices - get transfers to/from these subaddress indices
-   * @param {string} config.address - get transfers to/from this wallet address
-   * @param {string[]} config.addresses - get transfers to/from these wallet addresses
-   * @param {boolean} config.isIncoming - get transfers which are incoming if true
-   * @param {boolean} config.isOutgoing - get transfers which are outgoing if true
-   * @param {boolean} config.hasDestinations - get transfers with known destinations if true (destinations are only stored locally with the wallet)
-   * @param {object|MoneroTxQuery} config.txQuery - get transfers whose tx match this tx query
-   */
-  constructor(config) {
-    super(config);
-    
-    // deserialize if necessary
-    const MoneroTxQuery = require("./MoneroTxQuery");
-    if (this.state.txQuery && !(this.state.txQuery instanceof MoneroTxQuery)) this.state.txQuery = new MoneroTxQuery(this.state.txQuery);
-    if (this.state.txQuery) this.state.txQuery.setTransferQuery(this);
-    
-    // alias isOutgoing to isIncoming
-    if (this.state.isOutgoing !== undefined) this.state.isIncoming = !this.state.isOutgoing;
-    
-    // validate state
-    this._validate();
-  }
-  
-  copy() {
-    return new MoneroTransferQuery(this);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state, super.toJson());
-    delete json.txQuery;
-    return json;
-  }
-  
-  getTxQuery() {
-    return this.state.txQuery;
-  }
-  
-  setTxQuery(txQuery) {
-    this.state.txQuery = txQuery;
-    if (txQuery) txQuery.state.transferQuery = this;
-    return this;
-  }
-  
-  isIncoming() {
-    return this.state.isIncoming;
-  }
-
-  setIsIncoming(isIncoming) {
-    this.state.isIncoming = isIncoming;
-    return this;
-  }
-  
-  isOutgoing() {
-    return this.state.isIncoming === undefined ? undefined : !this.state.isIncoming;
-  }
-  
-  setIsOutgoing(isOutgoing) {
-    this.state.isIncoming = isOutgoing === undefined ? undefined : !isOutgoing;
-    return this;
-  }
-  
-  getAddress() {
-    return this.state.address;
-  }
-
-  setAddress(address) {
-    this.state.address = address;
-    return this;
-  }
-  
-  getAddresses() {
-    return this.state.addresses;
-  }
-
-  setAddresses(addresses) {
-    this.state.addresses = addresses;
-    return this;
-  }
-  
-  getSubaddressIndex() {
-    return this.state.subaddressIndex;
-  }
-  
-  setSubaddressIndex(subaddressIndex) {
-    this.state.subaddressIndex = subaddressIndex;
-    this._validate();
-    return this;
-  }
-  
-  getSubaddressIndices() {
-    return this.state.subaddressIndices;
-  }
-  
-  setSubaddressIndices(subaddressIndices) {
-    this.state.subaddressIndices = subaddressIndices;
-    this._validate();
-    return this;
-  }
-  
-  getDestinations() {
-    return this.state.destinations;
-  }
-  
-  setDestinations(destinations) {
-    this.state.destinations = destinations;
-    return this;
-  }
-  
-  hasDestinations() {
-    return this.state.hasDestinations;
-  }
-  
-  setHasDestinations(hasDestinations) {
-    this.state.hasDestinations = hasDestinations;
-    return this;
-  }
-  
-  /**
-   * Convenience method to query outputs by the locked state of their tx.
-   * 
-   * @param isLocked specifies if the output's tx must be locked or unlocked (optional)
-   * @return {MoneroOutputQuery} this query for chaining
-   */
-  setIsLocked(isLocked) {
-    if (this.state.txQuery === undefined) this.state.txQuery = new MoneroTxQuery();
-    this.state.txQuery.setIsLocked(isLocked);
-    return this;
-  }
-  
-  meetsCriteria(transfer, queryParent) {
-    if (!(transfer instanceof MoneroTransfer)) throw new Error("Transfer not given to MoneroTransferQuery.meetsCriteria(transfer)");
-    if (queryParent === undefined) queryParent = true;
-    
-    // filter on common fields
-    if (this.isIncoming() !== undefined && this.isIncoming() !== transfer.isIncoming()) return false;
-    if (this.isOutgoing() !== undefined && this.isOutgoing() !== transfer.isOutgoing()) return false;
-    if (this.getAmount() !== undefined && this.getAmount().compare(transfer.getAmount()) !== 0) return false;
-    if (this.getAccountIndex() !== undefined && this.getAccountIndex() !== transfer.getAccountIndex()) return false;
-    
-    // filter on incoming fields
-    if (transfer instanceof MoneroIncomingTransfer) {
-      if (this.hasDestinations()) return false;
-      if (this.getAddress() !== undefined && this.getAddress() !== transfer.getAddress()) return false;
-      if (this.getAddresses() !== undefined && !this.getAddresses().includes(transfer.getAddress())) return false;
-      if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() !== transfer.getSubaddressIndex()) return false;
-      if (this.getSubaddressIndices() !== undefined && !this.getSubaddressIndices().includes(transfer.getSubaddressIndex())) return false;
-    }
-
-    // filter on outgoing fields
-    else if (transfer instanceof MoneroOutgoingTransfer) {
-      
-      // filter on addresses which must have overlap
-      if (this.getAddress() !== undefined && (transfer.getAddresses() === undefined || !transfer.getAddresses().includes(this.getAddress()))) return false;   // TODO: will filter all transfers that don't contain addresses (outgoing txs might not have this field initialized)
-      if (this.getAddresses() !== undefined) {
-        if (!transfer.getAddresses()) return false;
-        if (!this.getAddresses().some(address => transfer.getAddresses().includes(address))) return false;
-      }
-      
-      // filter on subaddress indices
-      if (this.getSubaddressIndex() !== undefined && (transfer.getSubaddressIndices() === undefined || !transfer.getSubaddressIndices().includes(this.getSubaddressIndex()))) return false;
-      if (this.getSubaddressIndices() !== undefined) {
-        if (!transfer.getSubaddressIndices()) return false;
-        if (!this.getSubaddressIndices().some(subaddressIdx => transfer.getSubaddressIndices().includes(subaddressIdx))) return false;
-      }
-      
-      // filter on having destinations
-      if (this.hasDestinations() !== undefined) {
-        if (this.hasDestinations() && transfer.getDestinations() === undefined) return false;
-        if (!this.hasDestinations() && transfer.getDestinations() !== undefined) return false;
-      }
-      
-      // filter on destinations TODO: start with test for this
-//    if (this.getDestionations() !== undefined && this.getDestionations() !== transfer.getDestionations()) return false;
-    }
-    
-    // otherwise invalid type
-    else throw new Error("Transfer must be MoneroIncomingTransfer or MoneroOutgoingTransfer");
-    
-    // filter with tx filter
-    if (queryParent && this.getTxQuery() !== undefined && !this.getTxQuery().meetsCriteria(transfer.getTx())) return false;    
-    return true;
-  }
-  
-  _validate() {
-    if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() < 0) throw new MoneroError("Subaddress index must be >= 0");
-    if (this.getSubaddressIndices() !== undefined) for (let subaddressIdx of this.getSubaddressIndices()) if (subaddressIdx < 0) throw new MoneroError("Subaddress indices must be >= 0");
-  }
-}
-
-module.exports = MoneroTransferQuery;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroTxConfig.js.html b/docs/src_main_js_wallet_model_MoneroTxConfig.js.html deleted file mode 100644 index 6210514ca..000000000 --- a/docs/src_main_js_wallet_model_MoneroTxConfig.js.html +++ /dev/null @@ -1,341 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroTxConfig.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroTxConfig.js

- - - - - - -
-
-
const assert = require("assert");
-const MoneroDestination = require("./MoneroDestination");
-const MoneroError = require("../../common/MoneroError");
-
-/**
- * Configures a transaction to send, sweep, or create a payment URI.
- */
-class MoneroTxConfig {
-  
-  /**
-   * <p>Generic request to transfer funds from a wallet.</p>
-   * 
-   * <p>Examples:</p>
-   * 
-   * <code>
-   * let config1 = new MoneroTxConfig({<br>
-   * &nbsp;&nbsp; accountIndex: 0,<br>
-   * &nbsp;&nbsp; address: "59aZULsUF3YN...",<br>
-   * &nbsp;&nbsp; amount: new BigInteger("500000"),<br>
-   * &nbsp;&nbsp; priority: MoneroTxPriority.NORMAL,<br>
-   * &nbsp;&nbsp; relay: true<br>
-   * });<br><br>
-   * </code>
-   * 
-   * @param {MoneroTxConfig|object} config - configures the transaction to create (optional)
-   * @param {string} config.address - single destination address
-   * @param {BigInteger} config.amount - single destination amount
-   * @param {int} config.accountIndex - source account index to transfer funds from
-   * @param {int} config.subaddressIndex - source subaddress index to transfer funds from
-   * @param {int[]} config.subaddressIndices - source subaddress indices to transfer funds from
-   * @param {boolean} config.relay - relay the transaction to peers to commit to the blockchain
-   * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL)
-   * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx
-   * @param {string} config.paymentId - transaction payment ID
-   * @param {int} config.unlockHeight - minimum height for the transaction to unlock (default 0)
-   * @param {string} config.note - transaction note saved locally with the wallet
-   * @param {string} config.recipientName - recipient name saved locally with the wallet
-   * @param {boolean} config.canSplit - allow funds to be transferred using multiple transactions
-   * @param {BigInteger} config.belowAmount - for sweep requests, include outputs below this amount when sweeping wallet, account, subaddress, or all unlocked funds 
-   * @param {boolean} config.sweepEachSubaddress - for sweep requests, sweep each subaddress individually instead of together if true
-   * @param {string} config.keyImage - key image to sweep (ignored except in sweepOutput() requests)
-   */
-  constructor(config) {
-    if (arguments.length > 1) throw new MoneroError("MoneroTxConfig can be constructed with only one parameter but was given " + arguments.length)
-    
-    // initialize internal state
-    if (!config) this.state = {};
-    else if (config instanceof MoneroTxConfig) this.state = config.toJson();
-    else if (typeof config === "object") this.state = Object.assign({}, config);
-    else throw new MoneroError("Invalid argument given to MoneroTxConfig: " + typeof config);
-    
-    // deserialize if necessary
-    if (this.state.destinations) {
-      assert(this.state.address === undefined && this.state.amount === undefined, "Tx configuration may specify destinations or an address/amount but not both");
-      this.setDestinations(this.state.destinations.map(destination => destination instanceof MoneroDestination ? destination : new MoneroDestination(destination)));
-    }
-    
-    // alias 'address' and 'amount' to single destination to support e.g. createTx({address: "..."})
-    if (this.state.address || this.state.amount) {
-      assert(!this.state.destinations, "Tx configuration may specify destinations or an address/amount but not both");
-      this.setDestinations([new MoneroDestination(this.state.address, this.state.amount)]);
-      delete this.state.address;
-      delete this.state.amount;
-    }
-    
-    // alias 'subaddressIndex' to subaddress indices
-    if (this.state.subaddressIndex !== undefined) {
-      this.setSubaddressIndices([this.state.subaddressIndex]);
-      delete this.state.subaddressIndex;
-    }
-  }
-  
-  copy() {
-    return new MoneroTxConfig(this);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state); // copy state
-    if (this.getDestinations()) {
-      json.destinations = [];
-      for (let destination of this.getDestinations()) json.destinations.push(destination.toJson());
-    }
-    if (this.getFee()) json.fee = this.getFee().toString();
-    if (this.getBelowAmount()) json.belowAmount = this.getBelowAmount().toString();
-    return json;
-  }
-  
-  /**
-   * Set the address of a single-destination configuration.
-   * 
-   * @param {string} address - the address to set for the single destination
-   * @return {MoneroTxConfig} this configuration for chaining
-   */
-  setAddress(address) {
-    if (this.state.destinations !== undefined && this.state.destinations.length > 1) throw new MoneroError("Cannot set address because MoneroTxConfig already has multiple destinations");
-    if (this.state.destinations === undefined || this.state.destinations.length === 0) this.addDestination(new MoneroDestination(address));
-    else this.state.destinations[0].setAddress(address);
-    return this;
-  }
-  
-  /**
-   * Get the address of a single-destination configuration.
-   * 
-   * @return {string} the address of the single destination
-   */
-  getAddress() {
-    if (this.state.destinations === undefined || this.state.destinations.length !== 1) throw new MoneroError("Cannot get address because MoneroTxConfig does not have exactly one destination");
-    return this.state.destinations[0].getAddress();
-  }
-  
-  /**
-   * Set the amount of a single-destination configuration.
-   * 
-   * @param {BigInteger} amount - the amount to set for the single destination
-   * @return {MoneroTxConfig} this configuration for chaining
-   */
-  setAmount(amount) {
-    if (this.state.destinations !== undefined && this.state.destinations.length > 1) throw new MoneroError("Cannot set amount because MoneroTxConfig already has multiple destinations");
-    if (this.state.destinations === undefined || this.state.destinations.length === 0) this.addDestination(new MoneroDestination(undefined, amount));
-    else this.state.destinations[0].setAmount(amount);
-    return this;
-  }
-  
-  /**
-   * Get the amount of a single-destination configuration.
-   * 
-   * @return {BigInteger} the amount of the single destination
-   */
-  getAmount() {
-    if (this.state.destinations === undefined || this.state.destinations.length !== 1) throw new MoneroError("Cannot get amount because MoneroTxConfig does not have exactly one destination");
-    return this.state.destinations[0].getAmount();
-  }
-  
-  addDestination(destination) {
-    assert(destination instanceof MoneroDestination);
-    if (this.state.destinations === undefined) this.state.destinations = [];
-    this.state.destinations.push(destination);
-    return this;
-  }
-  
-  getDestinations() {
-    return this.state.destinations;
-  }
-  
-  setDestinations(destinations) {
-    if (arguments.length > 1) destinations = Array.from(arguments);
-    this.state.destinations = destinations;
-    return this;
-  }
-  
-  setDestination(destination) {
-    return this.setDestinations(destination ? [destination] : destination);
-  }
-  
-  getPaymentId() {
-    return this.state.paymentId;
-  }
-  
-  setPaymentId(paymentId) {
-    this.state.paymentId = paymentId;
-    return this;
-  }
-  
-  getPriority() {
-    return this.state.priority;
-  }
-  
-  setPriority(priority) {
-    this.state.priority = priority;
-    return this;
-  }
-  
-  getFee() {
-    return this.state.fee;
-  }
-  
-  setFee(fee) {
-    this.state.fee = fee;
-    return this;
-  }
-  
-  getAccountIndex() {
-    return this.state.accountIndex;
-  }
-  
-  setAccountIndex(accountIndex) {
-    this.state.accountIndex = accountIndex;
-    return this;
-  }
-  
-  setSubaddressIndex(subaddressIndex) {
-    this.setSubaddressIndices([subaddressIndex]);
-    return this;
-  }
-  
-  getSubaddressIndices() {
-    return this.state.subaddressIndices;
-  }
-  
-  setSubaddressIndices(subaddressIndices) {
-    if (arguments.length > 1) subaddressIndices = Array.from(arguments);
-    this.state.subaddressIndices = subaddressIndices;
-    return this;
-  }
-  
-  getUnlockHeight() {
-    return this.state.unlockHeight;
-  }
-  
-  setUnlockHeight(unlockHeight) {
-    this.state.unlockHeight = unlockHeight;
-    return this;
-  }
-  
-  getRelay() {
-    return this.state.relay;
-  }
-  
-  setRelay(relay) {
-    this.state.relay = relay;
-    return this;
-  }
-  
-  getCanSplit() {
-    return this.state.canSplit;
-  }
-  
-  setCanSplit(canSplit) {
-    this.state.canSplit = canSplit;
-    return this;
-  }
-  
-  getNote() {
-    return this.state.note;
-  }
-  
-  setNote(note) {
-    this.state.note = note;
-    return this;
-  }
-  
-  getRecipientName() {
-    return this.state.recipientName;
-  }
-  
-  setRecipientName(recipientName) {
-    this.state.recipientName = recipientName;
-    return this;
-  }
-  
-  // --------------------------- SPECIFIC TO SWEEP ----------------------------
-  
-  getBelowAmount() {
-    return this.state.belowAmount;
-  }
-  
-  setBelowAmount(belowAmount) {
-    this.state.belowAmount = belowAmount;
-    return this;
-  }
-  
-  getSweepEachSubaddress() {
-    return this.state.sweepEachSubaddress;
-  }
-  
-  setSweepEachSubaddress(sweepEachSubaddress) {
-    this.state.sweepEachSubaddress = sweepEachSubaddress;
-    return this;
-  }
-  
-  /**
-   * Get the key image hex of the output to sweep.
-   * 
-   * return {string} is the key image hex of the output to sweep
-   */
-  getKeyImage() {
-    return this.state.keyImage;
-  }
-  
-  /**
-   * Set the key image hex of the output to sweep.
-   * 
-   * @param {string} keyImage is the key image hex of the output to sweep
-   */
-  setKeyImage(keyImage) {
-    this.state.keyImage = keyImage;
-    return this;
-  }
-}
-
-module.exports = MoneroTxConfig
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroTxPriority.js.html b/docs/src_main_js_wallet_model_MoneroTxPriority.js.html deleted file mode 100644 index b6b44eead..000000000 --- a/docs/src_main_js_wallet_model_MoneroTxPriority.js.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroTxPriority.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroTxPriority.js

- - - - - - -
-
-
/**
- * Enumerates send priorities.
- * 
- * @hideconstructor
- */
-class MoneroTxPriority {}
-
-/**
- * Default priority (i.e. normal) (value=0).
- */
-MoneroTxPriority.DEFAULT = 0;
-
-/**
- * Unimportant priority (value=1).
- */
-MoneroTxPriority.UNIMPORTANT = 1;
-
-/**
- * Normal priority (value=2).
- */
-MoneroTxPriority.NORMAL = 2;
-
-/**
- * Elevated priority (value=3).
- */
-MoneroTxPriority.ELEVATED = 3;
-
-module.exports = MoneroTxPriority;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroTxQuery.js.html b/docs/src_main_js_wallet_model_MoneroTxQuery.js.html deleted file mode 100644 index b639987b2..000000000 --- a/docs/src_main_js_wallet_model_MoneroTxQuery.js.html +++ /dev/null @@ -1,323 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroTxQuery.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroTxQuery.js

- - - - - - -
-
-
const assert = require("assert");
-const MoneroOutputQuery = require("./MoneroOutputQuery");
-const MoneroTransferQuery = require("./MoneroTransferQuery");
-const MoneroTxWallet = require("./MoneroTxWallet");
-
-/**
- * <p>Configuration to query transactions.</p>
- * 
- * @class
- * @extends {MoneroTxWallet}
- */
-class MoneroTxQuery extends MoneroTxWallet {
-  
-  /**
-   * <p>Construct the transaction query.</p>
-   * 
-   * <p>Example:</p>
-   * 
-   * <code>
-   * &sol;&sol; get transactions with unlocked incoming transfers to account 0<br>
-   * let txs = await wallet.getTxs({<br>
-   * &nbsp;&nbsp; isLocked: false,<br>
-   * &nbsp;&nbsp; transferQuery: {<br>
-   * &nbsp;&nbsp;&nbsp;&nbsp; isIncoming: true,<br>
-   * &nbsp;&nbsp;&nbsp;&nbsp; accountIndex: 0<br>
-   * &nbsp;&nbsp; }<br>
-   * });
-   * </code>
-   * 
-   * <p>All configuration is optional.  All transactions are returned except those that don't meet criteria defined in this query.</p>
-   * 
-   * @param {object} config - tx query configuration
-   * @param {string} config.hash - get a tx with this hash
-   * @param {string[]} config.txHashes - get txs with these hashes
-   * @param {int} config.height - get txs with this height
-   * @param {int} config.minHeight - get txs with height greater than or equal to this height
-   * @param {int} config.maxHeight - get txs with height less than or equal to this height
-   * @param {boolean} config.isConfirmed - get confirmed or unconfirmed txs
-   * @param {boolean} config.inTxPool - get txs in or out of the tx pool
-   * @param {boolean} config.relay - get txs with the same relay status
-   * @param {boolean} config.isRelayed - get relayed or non-relayed txs
-   * @param {boolean} config.isFailed - get failed or non-failed txs
-   * @param {boolean} config.isMinerTx - get miner or non-miner txs
-   * @param {boolean} config.isLocked - get locked or unlocked txs
-   * @param {boolean} config.isIncoming - get txs with or without incoming transfers
-   * @param {boolean} config.isOutgoing - get txs with or without outgoing transfers
-   * @param {string} config.paymentId - get txs with this payment ID
-   * @param {string} config.paymentIds - get txs with a payment ID among these payment IDs
-   * @param {boolean} config.hasPaymentId - get txs with or without payment IDs
-   * @param {object|MoneroTransferQuery} config.transferQuery - get txs with transfers matching this transfer query
-   * @param {object|MoneroOutputQuery} config.outputQuery - get txs with outputs matching this output query
-   */
-  constructor(config) {
-    super(config);
-    
-    // deserialize if necessary
-    if (this.state.transferQuery && !(this.state.transferQuery instanceof MoneroTransferQuery)) this.state.transferQuery = new MoneroTransferQuery(this.state.transferQuery);
-    if (this.state.outputQuery && !(this.state.outputQuery instanceof MoneroOutputQuery)) this.state.outputQuery = new MoneroOutputQuery(this.state.outputQuery);
-    
-    // link cycles
-    if (this.state.transferQuery) this.state.transferQuery.setTxQuery(this);
-    if (this.state.outputQuery) this.state.outputQuery.setTxQuery(this);
-    
-    // alias 'hash' to hashes
-    if (this.state.hash) {
-      this.setHashes([this.state.hash]);
-      delete this.state.hash;
-    }
-  }
-  
-  copy() {
-    return new MoneroTxQuery(this);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state, super.toJson()); // merge json onto inherited state
-    if (this.getTransferQuery()) json.transferQuery = this.getTransferQuery().toJson();
-    if (this.getOutputQuery()) json.outputQuery = this.getOutputQuery().toJson();
-    delete json.block;  // do not serialize parent block
-    return json;
-  }
-  
-  isIncoming() {
-    return this.state.isIncoming;
-  }
-  
-  setIsIncoming(isIncoming) {
-    this.state.isIncoming = isIncoming;
-    return this;
-  }
-  
-  isOutgoing() {
-    return this.state.isOutgoing;
-  }
-  
-  setIsOutgoing(isOutgoing) {
-    this.state.isOutgoing = isOutgoing;
-    return this;
-  }
-
-  getHashes() {
-    return this.state.hashes;
-  }
-
-  setHashes(hashes) {
-    this.state.hashes = hashes;
-    return this;
-  }
-  
-  setHash(hash) {
-    if (hash === undefined) return this.setHashes(undefined);
-    assert(typeof hash === "string");
-    return this.setHashes([hash]);
-  }
-  
-  hasPaymentId() {
-    return this.state.hasPaymentId;
-  }
-  
-  setHasPaymentId() {
-    this.state.hasPaymentId = hasPaymentId;
-    return this;
-  }
-  
-  getPaymentIds() {
-    return this.state.paymentIds;
-  }
-
-  setPaymentIds(paymentIds) {
-    this.state.paymentIds = paymentIds;
-    return this;
-  }
-  
-  setPaymentId(paymentId) {
-    if (paymentId === undefined) return this.setPaymentIds(undefined);
-    assert(typeof paymentId === "string");
-    return this.setPaymentIds([paymentId]);
-  }
-  
-  getHeight() {
-    return this.state.height;
-  }
-  
-  setHeight(height) {
-    this.state.height = height;
-    return this;
-  }
-  
-  getMinHeight() {
-    return this.state.minHeight;
-  }
-
-  setMinHeight(minHeight) {
-    this.state.minHeight = minHeight;
-    return this;
-  }
-
-  getMaxHeight() {
-    return this.state.maxHeight;
-  }
-
-  setMaxHeight(maxHeight) {
-    this.state.maxHeight = maxHeight;
-    return this;
-  }
-  
-  getIncludeOutputs() {
-    return this.state.includeOutputs;
-  }
-
-  setIncludeOutputs(includeOutputs) {
-    this.state.includeOutputs = includeOutputs;
-    return this;
-  }
-  
-  getTransferQuery() {
-    return this.state.transferQuery;
-  }
-  
-  setTransferQuery(transferQuery) {
-    this.state.transferQuery = transferQuery;
-    if (transferQuery) transferQuery.state.txQuery = this;
-    return this;
-  }
-  
-  getOutputQuery() {
-    return this.state.outputQuery;
-  }
-  
-  setOutputQuery(outputQuery) {
-    this.state.outputQuery = outputQuery;
-    if (outputQuery) outputQuery.state.txQuery = this;
-    return this;
-  }
-  
-  meetsCriteria(tx, queryChildren) {
-    if (!(tx instanceof MoneroTxWallet)) throw new Error("Tx not given to MoneroTxQuery.meetsCriteria(tx)");
-    if (queryChildren === undefined) queryChildren = true;
-    
-    // filter on tx
-    if (this.getHash() !== undefined && this.getHash() !== tx.getHash()) return false;
-    if (this.getPaymentId() !== undefined && this.getPaymentId() !== tx.getPaymentId()) return false;
-    if (this.isConfirmed() !== undefined && this.isConfirmed() !== tx.isConfirmed()) return false;
-    if (this.inTxPool() !== undefined && this.inTxPool() !== tx.inTxPool()) return false;
-    if (this.getRelay() !== undefined && this.getRelay() !== tx.getRelay()) return false;
-    if (this.isRelayed() !== undefined && this.isRelayed() !== tx.isRelayed()) return false;
-    if (this.isFailed() !== undefined && this.isFailed() !== tx.isFailed()) return false;
-    if (this.isMinerTx() !== undefined && this.isMinerTx() !== tx.isMinerTx()) return false;
-    if (this.isLocked() !== undefined && this.isLocked() !== tx.isLocked()) return false;
-    
-    // filter on having a payment id
-    if (this.hasPaymentId() !== undefined) {
-      if (this.hasPaymentId() && tx.getPaymentId() === undefined) return false;
-      if (!this.hasPaymentId() && tx.getPaymentId() !== undefined) return false;
-    }
-    
-    // filter on incoming
-    if (this.isIncoming() !== undefined) {
-      if (this.isIncoming() && !tx.isIncoming()) return false;
-      if (!this.isIncoming() && tx.isIncoming()) return false;
-    }
-    
-    // filter on outgoing
-    if (this.isOutgoing() !== undefined) {
-      if (this.isOutgoing() && !tx.isOutgoing()) return false;
-      if (!this.isOutgoing() && tx.isOutgoing()) return false;
-    }
-    
-    // filter on remaining fields
-    let txHeight = tx.getBlock() === undefined ? undefined : tx.getBlock().getHeight();
-    if (this.getHashes() !== undefined && !this.getHashes().includes(tx.getHash())) return false;
-    if (this.getPaymentIds() !== undefined && !this.getPaymentIds().includes(tx.getPaymentId())) return false;
-    if (this.getHeight() !== undefined && (txHeight === undefined || txHeight !== this.getHeight())) return false;
-    if (this.getMinHeight() !== undefined && (txHeight === undefined || txHeight < this.getMinHeight())) return false;
-    if (this.getMaxHeight() !== undefined && (txHeight === undefined || txHeight > this.getMaxHeight())) return false;
-    // TODO: filtering not complete
-    
-    // done if not querying transfers or outputs
-    if (!queryChildren) return true;
-    
-    // at least one transfer must meet transfer filter if defined
-    if (this.getTransferQuery()) {
-      let matchFound = false;
-      if (tx.getOutgoingTransfer() && this.getTransferQuery().meetsCriteria(tx.getOutgoingTransfer(), false)) matchFound = true;
-      else if (tx.getIncomingTransfers()) {
-        for (let incomingTransfer of tx.getIncomingTransfers()) {
-          if (this.getTransferQuery().meetsCriteria(incomingTransfer, false)) {
-            matchFound = true;
-            break;
-          }
-        }
-      }
-      if (!matchFound) return false;
-    }
-    
-    // at least one output must meet output query if defined
-    if (this.getOutputQuery() !== undefined) {
-      if (tx.getOutputs() === undefined || tx.getOutputs().length === 0) return false;
-      let matchFound = false;
-      for (let output of tx.getOutputs()) {
-        if (this.getOutputQuery().meetsCriteria(output, false)) {
-          matchFound = true;
-          break;
-        }
-      }
-      if (!matchFound) return false;
-    }
-    
-    return true;  // transaction meets filter criteria
-  }
-}
-
-module.exports = MoneroTxQuery;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroTxSet.js.html b/docs/src_main_js_wallet_model_MoneroTxSet.js.html deleted file mode 100644 index 730e9be80..000000000 --- a/docs/src_main_js_wallet_model_MoneroTxSet.js.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroTxSet.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroTxSet.js

- - - - - - -
-
-
const assert = require("assert");
-const GenUtils = require("../../common/GenUtils");
-const MoneroTxWallet = require("./MoneroTxWallet");
-const MoneroUtils = require("../../common/MoneroUtils");
-
-/**
- * Groups transactions who share common hex data which is needed in order to
- * sign and submit the transactions.
- * 
- * For example, multisig transactions created from createTxs() share a common
- * hex string which is needed in order to sign and submit the multisig
- * transactions.
- */
-class MoneroTxSet {
-  
-  constructor(state) {
-    
-    // initialize internal state
-    if (!state) state = {};
-    else if (typeof state === "object") state = Object.assign({}, state);
-    else throw new MoneroError("state must be JavaScript object");
-    this.state = state;
-    
-    // deserialize txs
-    if (state.txs) {
-      for (let i = 0; i < state.txs.length; i++) {
-        if (!(state.txs[i] instanceof MoneroTxWallet)) state.txs[i] = new MoneroTxWallet(state.txs[i]);
-        state.txs[i].setTxSet(this);
-      }
-    }
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state); // copy state
-    if (this.getTxs()) {
-      json.txs = [];
-      for (let tx of this.getTxs()) json.txs.push(tx.toJson());
-    }
-    return json;
-  }
-
-  getTxs() {
-    return this.state.txs;
-  }
-
-  setTxs(txs) {
-    this.state.txs = txs;
-    return this;
-  }
-  
-  getMultisigTxHex() {
-    return this.state.multisigTxHex;
-  }
-  
-  setMultisigTxHex(multisigTxHex) {
-    this.state.multisigTxHex = multisigTxHex;
-    return this;
-  }
-  
-  getUnsignedTxHex() {
-    return this.state.unsignedTxHex;
-  }
-  
-  setUnsignedTxHex(unsignedTxHex) {
-    this.state.unsignedTxHex = unsignedTxHex;
-    return this;
-  }
-  
-  getSignedTxHex() {
-    return this.state.signedTxHex;
-  }
-  
-  setSignedTxHex(signedTxHex) {
-    this.state.signedTxHex = signedTxHex;
-    return this;
-  }
-  
-  merge(txSet) {
-    assert(txSet instanceof MoneroTxSet);
-    if (this === txSet) return this;
-    
-    // merge sets
-    this.setMultisigTxHex(GenUtils.reconcile(this.getMultisigTxHex(), txSet.getMultisigTxHex()));
-    this.setUnsignedTxHex(GenUtils.reconcile(this.getUnsignedTxHex(), txSet.getUnsignedTxHex()));
-    this.setSignedTxHex(GenUtils.reconcile(this.getSignedTxHex(), txSet.getSignedTxHex()));
-    
-    // merge txs
-    if (txSet.getTxs() !== undefined) {
-      for (let tx of txSet.getTxs()) {
-        tx.setTxSet(this);
-        MoneroUtils.mergeTx(this.getTxs(), tx);
-      }
-    }
-
-    return this;
-  }
-  
-  toString(indent = 0) {
-    let str = "";
-    str += GenUtils.kvLine("Multisig tx hex: ", getMultisigTxHex(), indent);
-    str += GenUtils.kvLine("Unsigned tx hex: ", getUnsignedTxHex(), indent);
-    str += GenUtils.kvLine("Signed tx hex: ", getSignedTxHex(), indent);
-    if (getTxs() !== undefined) {
-      str += GenUtils.kvLine("Txs", "", indent);
-      for (let tx of getTxs()) {
-        str += tx.toString(indent + 1) + "\n";
-      }
-    }
-    return str;
-  }
-}
-
-module.exports = MoneroTxSet;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroTxWallet.js.html b/docs/src_main_js_wallet_model_MoneroTxWallet.js.html deleted file mode 100644 index c07a89123..000000000 --- a/docs/src_main_js_wallet_model_MoneroTxWallet.js.html +++ /dev/null @@ -1,445 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroTxWallet.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroTxWallet.js

- - - - - - -
-
-
const assert = require("assert");
-const BigInteger = require("../../common/biginteger").BigInteger;
-const GenUtils = require("../../common/GenUtils");
-const MoneroIncomingTransfer = require("./MoneroIncomingTransfer");
-const MoneroOutgoingTransfer = require("./MoneroOutgoingTransfer");
-const MoneroOutputWallet = require("./MoneroOutputWallet");
-const MoneroTx = require("../../daemon/model/MoneroTx");
-
-/**
- * Models a Monero transaction with wallet extensions.
- * 
- * @class
- * @extends {MoneroTx}
- */
-class MoneroTxWallet extends MoneroTx {
-  
-  /**
-   * Construct the model.
-   * 
-   * @param {MoneroTxWallet|object} state is existing state to initialize from (optional)
-   */
-  constructor(state) {
-    super(state);
-    if (state instanceof MoneroTxWallet && state.getTxSet()) this.setTxSet(state.getTxSet()); // preserve reference to tx set
-    state = this.state;
-    
-    // deserialize incoming transfers
-    if (state.incomingTransfers) {
-      for (let i = 0; i < state.incomingTransfers.length; i++) {
-        if (!(state.incomingTransfers[i] instanceof MoneroIncomingTransfer)) {
-          state.incomingTransfers[i] = new MoneroIncomingTransfer(Object.assign(state.incomingTransfers[i], {tx: this}));
-        }
-      }
-    }
-    
-    // deserialize outgoing transfer
-    if (state.outgoingTransfer && !(state.outgoingTransfer instanceof MoneroOutgoingTransfer)) {
-      this.setOutgoingTransfer(new MoneroOutgoingTransfer(Object.assign(state.outgoingTransfer, {tx: this})));
-    }
-    
-    // deserialize inputs
-    if (state.inputs) {
-      for (let i = 0; i < state.inputs.length; i++) {
-        if (!(state.inputs[i] instanceof MoneroOutputWallet)) {
-          state.inputs[i] = new MoneroOutputWallet(Object.assign(state.inputs[i].toJson(), {tx: this}));
-        }
-      }
-    }
-    
-    // deserialize outputs
-    if (state.outputs) {
-      for (let i = 0; i < state.outputs.length; i++) {
-        if (!(state.outputs[i] instanceof MoneroOutputWallet)) {
-          state.outputs[i] = new MoneroOutputWallet(Object.assign(state.outputs[i].toJson(), {tx: this}));
-        }
-      }
-    }
-    
-    // deserialize BigIntegers
-    if (state.inputSum !== undefined && !(state.inputSum instanceof BigInteger)) state.inputSum = BigInteger.parse(state.inputSum);
-    if (state.outputSum !== undefined && !(state.outputSum instanceof BigInteger)) state.outputSum = BigInteger.parse(state.outputSum);
-    if (state.changeAmount !== undefined && !(state.changeAmount instanceof BigInteger)) state.changeAmount = BigInteger.parse(state.changeAmount);
-  }
-  
-  toJson() {
-    let json = Object.assign({}, this.state, super.toJson()); // merge json onto inherited state
-    if (this.getIncomingTransfers()) {
-      json.incomingTransfers = [];
-      for (let incomingTransfer of this.getIncomingTransfers()) json.incomingTransfers.push(incomingTransfer.toJson());
-    }
-    if (this.getOutgoingTransfer()) json.outgoingTransfer = this.getOutgoingTransfer().toJson();
-    if (this.getInputSum()) json.inputSum = this.getInputSum().toString();
-    if (this.getOutputSum()) json.outputSum = this.getOutputSum().toString();
-    if (this.getChangeAmount()) json.changeAmount = this.getChangeAmount().toString();
-    delete json.block;  // do not serialize parent block
-    delete json.txSet;  // do not serialize parent tx set
-    return json;
-  }
-  
-  getTxSet() {
-    return this.state.txSet;
-  }
-  
-  setTxSet(txSet) {
-    this.state.txSet = txSet;
-    return this;
-  }
-  
-  isIncoming() {
-    return this.state.isIncoming;
-  }
-  
-  setIsIncoming(isIncoming) {
-    this.state.isIncoming = isIncoming;
-    return this;
-  }
-  
-  isOutgoing() {
-    return this.state.isOutgoing;
-  }
-  
-  setIsOutgoing(isOutgoing) {
-    this.state.isOutgoing = isOutgoing;
-    return this;
-  }
-  
-  getIncomingAmount() {
-    if (this.getIncomingTransfers() === undefined) return undefined;
-    let incomingAmt = BigInteger.parse("0");
-    for (let transfer of this.getIncomingTransfers()) incomingAmt = incomingAmt.add(transfer.getAmount());
-    return incomingAmt;
-  }
-  
-  getOutgoingAmount() {
-    return this.getOutgoingTransfer() ? this.getOutgoingTransfer().getAmount() : undefined;
-  }
-  
-  getTransfers(transferQuery) {
-    let transfers = [];
-    if (this.getOutgoingTransfer() && (!transferQuery || transferQuery.meetsCriteria(this.getOutgoingTransfer()))) transfers.push(this.getOutgoingTransfer());
-    if (this.getIncomingTransfers()) {
-      for (let transfer of this.getIncomingTransfers()) {
-        if (!transferQuery || transferQuery.meetsCriteria(transfer)) transfers.push(transfer);
-      }
-    }
-    return transfers;
-  }
-  
-  filterTransfers(transferQuery) {
-    let transfers = [];
-    
-    // collect outgoing transfer or erase if filtered
-    if (this.getOutgoingTransfer() && (!transferQuery || transferQuery.meetsCriteria(this.getOutgoingTransfer()))) transfers.push(this.getOutgoingTransfer());
-    else this.setOutgoingTransfer(undefined);
-    
-    // collect incoming transfers or erase if filtered
-    if (this.getIncomingTransfers()) {
-      let toRemoves = [];
-      for (let transfer of this.getIncomingTransfers()) {
-        if (transferQuery.meetsCriteria(transfer)) transfers.push(transfer);
-        else toRemoves.push(transfer);
-      }
-      this.setIncomingTransfers(this.getIncomingTransfers().filter(function(transfer) {
-        return !toRemoves.includes(transfer);
-      }));
-      if (this.getIncomingTransfers().length === 0) this.setIncomingTransfers(undefined);
-    }
-    
-    return transfers;
-  }
-  
-  getIncomingTransfers() {
-    return this.state.incomingTransfers;
-  }
-  
-  setIncomingTransfers(incomingTransfers) {
-    this.state.incomingTransfers = incomingTransfers;
-    return this;
-  }
-  
-  getOutgoingTransfer() {
-    return this.state.outgoingTransfer;
-  }
-  
-  setOutgoingTransfer(outgoingTransfer) {
-    this.state.outgoingTransfer = outgoingTransfer;
-    return this;
-  }
-  
-  getOutputs(outputQuery) {
-    if (!outputQuery || !super.getOutputs()) return super.getOutputs();
-    let outputs = [];
-    for (let output of super.getOutputs()) if (!outputQuery || outputQuery.meetsCriteria(output)) outputs.push(output);
-    return outputs;
-  }
-  
-  setOutputs(outputs) {
-    
-    // validate that all outputs are wallet outputs
-    if (outputs) {
-      for (let output of outputs) {
-        if (!(output instanceof MoneroOutputWallet)) throw new MoneroError("Wallet transaction outputs must be of type MoneroOutputWallet");
-      }
-    }
-    super.setOutputs(outputs);
-    return this;
-  }
-  
-  filterOutputs(outputQuery) {
-    let outputs = [];
-    if (super.getOutputs()) {
-      let toRemoves = [];
-      for (let output of super.getOutputs()) {
-        if (!outputQuery || outputQuery.meetsCriteria(output)) outputs.push(output);
-        else toRemoves.push(output);
-      }
-      this.setOutputs(super.getOutputs().filter(function(output) {
-        return !toRemoves.includes(output);
-      }));
-      if (this.getOutputs().length === 0) this.setOutputs(undefined);
-    }
-    return outputs;
-  }
-  
-  getNote() {
-    return this.state.note;
-  }
-  
-  setNote(note) {
-    this.state.note = note;
-    return this;
-  }
-  
-  isLocked() {
-    return this.state.isLocked;
-  }
-  
-  setIsLocked(isLocked) {
-    this.state.isLocked = isLocked;
-    return this;
-  }
-  
-  getInputSum() {
-    return this.state.inputSum;
-  }
-  
-  setInputSum(inputSum) {
-    this.state.inputSum = inputSum;
-    return this;
-  }
-  
-  getOutputSum() {
-    return this.state.outputSum;
-  }
-  
-  setOutputSum(outputSum) {
-    this.state.outputSum = outputSum;
-    return this;
-  }
-  
-  getChangeAddress() {
-    return this.state.changeAddress;
-  }
-  
-  setChangeAddress(changeAddress) {
-    this.state.changeAddress = changeAddress;
-    return this;
-  }
-  
-  getChangeAmount() {
-    return this.state.changeAmount;
-  }
-  
-  setChangeAmount(changeAmount) {
-    this.state.changeAmount = changeAmount;
-    return this;
-  }
-  
-  getNumDummyOutputs() {
-    return this.state.numDummyOutputs;
-  }
-  
-  setNumDummyOutputs(numDummyOutputs) {
-    this.state.numDummyOutputs = numDummyOutputs;
-    return this;
-  }
-  
-  getExtraHex() {
-    return this.state.extraHex;
-  }
-  
-  setExtraHex(extraHex) {
-    this.state.extraHex = extraHex;
-    return this;
-  }
-  
-  copy() {
-    return new MoneroTxWallet(this);
-  }
-  
-  /**
-   * Updates this transaction by merging the latest information from the given
-   * transaction.
-   * 
-   * Merging can modify or build references to the transaction given so it
-   * should not be re-used or it should be copied before calling this method.
-   * 
-   * @param tx is the transaction to merge into this transaction
-   */
-  merge(tx) {
-    assert(tx instanceof MoneroTxWallet);
-    if (this === tx) return this;
-    
-    // merge base classes
-    super.merge(tx);
-    
-    // merge tx set if they're different which comes back to merging txs
-    const MoneroTxSet = require("./MoneroTxSet");
-    if (this.getTxSet() !== tx.getTxSet()) {
-      if (this.getTxSet() == undefined) {
-        this.setTxSet(new MoneroTxSet().setTxs([this]));
-      }
-      if (tx.getTxSet() === undefined) {
-        tx.setTxSet(new MoneroTxSet().setTxs([tx]));
-      }
-      this.getTxSet().merge(tx.getTxSet());
-      return this;
-    }
-    
-    // merge incoming transfers
-    if (tx.getIncomingTransfers()) {
-      if (this.getIncomingTransfers() === undefined) this.setIncomingTransfers([]);
-      for (let transfer of tx.getIncomingTransfers()) {
-        transfer.setTx(this);
-        MoneroTxWallet._mergeIncomingTransfer(this.getIncomingTransfers(), transfer);
-      }
-    }
-    
-    // merge outgoing transfer
-    if (tx.getOutgoingTransfer()) {
-      tx.getOutgoingTransfer().setTx(this);
-      if (this.getOutgoingTransfer() === undefined) this.setOutgoingTransfer(tx.getOutgoingTransfer());
-      else this.getOutgoingTransfer().merge(tx.getOutgoingTransfer());
-    }
-    
-    // merge simple extensions
-    this.setIsIncoming(GenUtils.reconcile(this.isIncoming(), tx.isIncoming()));
-    this.setIsOutgoing(GenUtils.reconcile(this.isOutgoing(), tx.isOutgoing()));
-    this.setNote(GenUtils.reconcile(this.getNote(), tx.getNote()));
-    this.setIsLocked(GenUtils.reconcile(this.isLocked(), tx.isLocked()));
-    this.setInputSum(GenUtils.reconcile(this.getInputSum(), tx.getInputSum()));
-    this.setOutputSum(GenUtils.reconcile(this.getOutputSum(), tx.getOutputSum()));
-    this.setChangeAddress(GenUtils.reconcile(this.getChangeAddress(), tx.getChangeAddress()));
-    this.setChangeAmount(GenUtils.reconcile(this.getChangeAmount(), tx.getChangeAmount()));
-    this.setNumDummyOutputs(GenUtils.reconcile(this.getNumDummyOutputs(), tx.getNumDummyOutputs()));
-    this.setExtraHex(GenUtils.reconcile(this.getExtraHex(), tx.getExtraHex()));
-    
-    return this;  // for chaining
-  }
-  
-  toString(indent = 0, oneLine) {
-    let str = "";
-    
-    // represent tx with one line string
-    // TODO: proper csv export
-    if (oneLine) {
-      str += this.getHash() + ", ";
-      str += (this.isConfirmed() ? this.getBlock().getTimestamp() : this.getReceivedTimestamp()) + ", ";
-      str += this.isConfirmed() + ", ";
-      str += (this.getOutgoingAmount() ? this.getOutgoingAmount().toString() : "") + ", ";
-      str += this.getIncomingAmount() ? this.getIncomingAmount().toString() : "";
-      return str;
-    }
-    
-    // otherwise stringify all fields
-    str += super.toString(indent) + "\n";
-    str += GenUtils.kvLine("Is incoming", this.isIncoming(), indent);
-    str += GenUtils.kvLine("Incoming amount", this.getIncomingAmount(), indent);
-    if (this.getIncomingTransfers()) {
-      str += GenUtils.kvLine("Incoming transfers", "", indent);
-      for (let i = 0; i < this.getIncomingTransfers().length; i++) {
-        str += GenUtils.kvLine(i + 1, "", indent + 1);
-        str += this.getIncomingTransfers()[i].toString(indent + 2) + "\n";
-      }
-    }
-    str += GenUtils.kvLine("Is outgoing", this.isOutgoing(), indent);
-    str += GenUtils.kvLine("Outgoing amount", this.getOutgoingAmount(), indent);
-    if (this.getOutgoingTransfer()) {
-      str += GenUtils.kvLine("Outgoing transfer", "", indent);
-      str += this.getOutgoingTransfer().toString(indent + 1) + "\n";
-    }
-    str += GenUtils.kvLine("Note", this.getNote(), indent);
-    str += GenUtils.kvLine("Is locked", this.isLocked(), indent);
-    str += GenUtils.kvLine("Input sum", this.getInputSum(), indent);
-    str += GenUtils.kvLine("Output sum", this.getOutputSum(), indent);
-    str += GenUtils.kvLine("Change address", this.getChangeAddress(), indent);
-    str += GenUtils.kvLine("Change amount", this.getChangeAmount(), indent);
-    str += GenUtils.kvLine("Num dummy outputs", this.getNumDummyOutputs(), indent);
-    str += GenUtils.kvLine("Extra hex", this.getExtraHex(), indent);
-    return str.slice(0, str.length - 1);  // strip last newline
-  }
-  
-  // private helper to merge transfers
-  static _mergeIncomingTransfer(transfers, transfer) {
-    for (let aTransfer of transfers) {
-      if (aTransfer.getAccountIndex() === transfer.getAccountIndex() && aTransfer.getSubaddressIndex() === transfer.getSubaddressIndex()) {
-        aTransfer.merge(transfer);
-        return;
-      }
-    }
-    transfers.push(transfer);
-  }
-}
-
-module.exports = MoneroTxWallet;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroWalletConfig.js.html b/docs/src_main_js_wallet_model_MoneroWalletConfig.js.html deleted file mode 100644 index 30a2e7351..000000000 --- a/docs/src_main_js_wallet_model_MoneroWalletConfig.js.html +++ /dev/null @@ -1,291 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroWalletConfig.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroWalletConfig.js

- - - - - - -
-
-
const GenUtils = require("../../common/GenUtils");
-const MoneroNetworkType = require("../../daemon/model/MoneroNetworkType");
-const MoneroRpcConnection = require("../../common/MoneroRpcConnection");
-
-/**
- * Configuration to create a Monero wallet.
- */
-class MoneroWalletConfig {
-  
-  /**
-   * Construct a configuration to open or create a wallet.
-   * 
-   * @param {object|MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object
-   * @param {string} config.path - path of the wallet to open or create
-   * @param {string} config.password - password of the wallet to open
-   * @param {string|number} config.networkType - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET)
-   * @param {string} config.serverUri - uri of the wallet's server (optional)
-   * @param {string} config.serverUsername - username of the wallet's server (optional)
-   * @param {string} config.serverPassword - password of the wallet's server (optional)
-   * @param {boolean} config.rejectUnauthorized - reject self-signed server certificates if true (defaults to true)
-   * @param {MoneroRpcConnection|object} config.server - MoneroRpcConnection or equivalent JS object configuring the server connection (optional)
-   * @param {Uint8Array} config.keysData - wallet keys data to open (optional)
-   * @param {Uint8Array} config.cacheData - wallet cache data to open (optional)
-   * @param {boolean} config.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default: false)
-   * @param {fs} config.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser)
-   * @param {boolean} config.saveCurrent - specifies if the current RPC wallet should be saved before being closed
-   */
-  constructor(config) {
-    
-    // initialize internal config
-    if (!config) config = {};
-    else if (config instanceof MoneroWalletConfig) config = config.toJson();
-    else if (typeof config === "object") config = Object.assign({}, config);
-    else throw new MoneroError("config must be a MoneroWalletConfig or JavaScript object");
-    this.config = config;
-    
-    // normalize config
-    this.setNetworkType(config.networkType);
-    if (config.server) this.setServer(config.server);
-    delete this.config.server;
-    
-    // check for unsupported fields
-    for (let key of Object.keys(this.config)) {
-      if (!GenUtils.arrayContains(MoneroWalletConfig.SUPPORTED_FIELDS, key)) {
-        throw new MoneroError("Wallet config includes unsupported field: '" + key + "'");
-      }
-    }
-  }
-  
-  toJson() {
-    return Object.assign({}, this.config);
-  }
-  
-  getPath() {
-    return this.config.path;
-  }
-  
-  setPath(path) {
-    this.config.path = path;
-    return this;
-  }
-  
-  getPassword() {
-    return this.config.password;
-  }
-  
-  setPassword(password) {
-    this.config.password = password;
-    return this;
-  }
-  
-  getNetworkType() {
-    return this.config.networkType;
-  }
-  
-  setNetworkType(networkTypeOrStr) {
-    this.config.networkType = typeof networkTypeOrStr === "string" ? MoneroNetworkType.parse(networkTypeOrStr) : networkTypeOrStr;
-    return this;
-  }
-  
-  getServer() {
-    return !this.config.serverUri ? undefined : new MoneroRpcConnection({uri: this.config.serverUri, username: this.config.serverUsername, password: this.config.serverPassword, rejectUnauthorized: this.config.rejectUnauthorized})
-  }
-  
-  setServer(server) {
-    if (server && !(server instanceof MoneroRpcConnection)) server = new MoneroRpcConnection(server);
-    this.config.serverUri = server === undefined ? undefined : server.getUri();
-    this.config.serverUsername = server === undefined ? undefined : server.getUsername();
-    this.config.serverPassword = server === undefined ? undefined : server.getPassword();
-    this.config.rejectUnauthorized = server === undefined ? undefined : server.getRejectUnauthorized();
-    return this;
-  }
-  
-  getServerUri() {
-    return this.config.serverUri;
-  }
-  
-  setServerUri(serverUri) {
-    this.config.serverUri = serverUri;
-    return this;
-  }
-  
-  getServerUsername() {
-    return this.config.serverUsername;
-  }
-  
-  setServerUsername(serverUsername) {
-    this.config.serverUsername = serverUsername;
-    return this;
-  }
-  
-  getServerPassword() {
-    return this.config.serverPassword;
-  }
-  
-  setServerPassword(serverPassword) {
-    this.config.serverPassword = serverPassword;
-    return this;
-  }
-  
-  getRejectUnauthorized() {
-    return this.config.rejectUnauthorized;
-  }
-  
-  setRejectUnauthorized(rejectUnauthorized) {
-    this.config.rejectUnauthorized = rejectUnauthorized;
-    return this;
-  }
-  
-  getMnemonic() {
-    return this.config.mnemonic;
-  }
-  
-  setMnemonic(mnemonic) {
-    this.config.mnemonic = mnemonic;
-    return this;
-  }
-  
-  getSeedOffset() {
-    return this.config.seedOffset;
-  }
-  
-  setSeedOffset(seedOffset) {
-    this.config.seedOffset = seedOffset;
-    return this;
-  }
-  
-  getPrimaryAddress() {
-    return this.config.primaryAddress;
-  }
-  
-  setPrimaryAddress(primaryAddress) {
-    this.config.primaryAddress = primaryAddress;
-    return this;
-  }
-  
-  getPrivateViewKey() {
-    return this.config.privateViewKey;
-  }
-  
-  setPrivateViewKey(privateViewKey) {
-    this.config.privateViewKey = privateViewKey;
-    return this;
-  }
-  
-  getPrivateSpendKey() {
-    return this.config.privateSpendKey;
-  }
-  
-  setPrivateSpendKey(privateSpendKey) {
-    this.config.privateSpendKey = privateSpendKey;
-    return this;
-  }
-  
-  getRestoreHeight() {
-    return this.config.restoreHeight;
-  }
-  
-  setRestoreHeight(restoreHeight) {
-    this.config.restoreHeight = restoreHeight;
-    return this;
-  }
-  
-  getLanguage() {
-    return this.config.language;
-  }
-  
-  setLanguage(language) {
-    this.config.language = language;
-    return this;
-  }
-  
-  getSaveCurrent() {
-    return this.config.saveCurrent;
-  }
-  
-  setSaveCurrent(saveCurrent) {
-    this.config.saveCurrent = saveCurrent;
-    return this;
-  }
-  
-  getProxyToWorker() {
-    return this.config.proxyToWorker;
-  }
-  
-  setProxyToWorker(proxyToWorker) {
-    this.config.proxyToWorker = proxyToWorker;
-    return this;
-  }
-  
-  getFs() {
-    return this.config.fs;
-  }
-  
-  setFs(fs) {
-    this.config.fs = fs;
-    return this;
-  }
-  
-  getKeysData() {
-    return this.config.keysData;
-  }
-  
-  setKeysData(keysData) {
-    this.config.keysData = keysData;
-    return this;
-  }
-  
-  getCacheData() {
-    return this.config.cacheData;
-  }
-  
-  setCacheData(cacheData) {
-    this.config.cacheData = cacheData;
-    return this;
-  }
-}
-
-MoneroWalletConfig.SUPPORTED_FIELDS = ["path", "password", "networkType", "serverUri", "serverUsername", "serverPassword", "rejectUnauthorized", "mnemonic", "seedOffset", "primaryAddress", "privateViewKey", "privateSpendKey", "restoreHeight", "language", "saveCurrent", "proxyToWorker", "fs", "keysData", "cacheData"];
-
-module.exports = MoneroWalletConfig;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/src_main_js_wallet_model_MoneroWalletListener.js.html b/docs/src_main_js_wallet_model_MoneroWalletListener.js.html deleted file mode 100644 index f3d5f42e7..000000000 --- a/docs/src_main_js_wallet_model_MoneroWalletListener.js.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - JSDoc: Source: src/main/js/wallet/model/MoneroWalletListener.js - - - - - - - - - - -
- -

Source: src/main/js/wallet/model/MoneroWalletListener.js

- - - - - - -
-
-
/**
- * Default wallet listener which takes no action on notifications.
- */
-class MoneroWalletListener {
-  
-  /**
-   * Invoked as the wallet is synchronized.
-   * 
-   * @param {number} height - height of the synced block 
-   * @param {number} startHeight - starting height of the sync request
-   * @param {number} endHeight - ending height of the sync request
-   * @param {number} percentDone - sync progress as a percentage
-   * @param {string} message - human-readable description of the current progress
-   */
-  onSyncProgress(height, startHeight, endHeight, percentDone, message) { }
-
-  /**
-   * Invoked when a new block is added to the chain.
-   * 
-   * @param {int} height - the height of the block added to the chain
-   */
-  onNewBlock(height) { }
-  
-  /**
-   * Invoked when the wallet's balances change.
-   * 
-   * @param {BigInteger} newBalance - new wallet balance
-   * @param {BigInteger} newUnlockedBalance - new unlocked wallet balance
-   */
-  onBalancesChanged(newBalance, newUnlockedBalance) { }
-
-  /**
-   * Invoked when the wallet receives an unconfirmed output, when the output is confirmed,
-   * and when the output is unlocked.
-   * 
-   * @param {MoneroOutputWallet} output - the received output
-   */
-  onOutputReceived(output) { }
-  
-  /**
-   * Invoked when the wallet spends an output.
-   * 
-   * @param {MoneroOutputWallet} output - the spent output
-   */
-  onOutputSpent(output) { }
-}
-
-module.exports = MoneroWalletListener;
-
-
- - - - -
- - - -
- -
- Documentation generated by JSDoc 3.6.4 on Sat Sep 05 2020 14:21:46 GMT-0400 (Eastern Daylight Time) -
- - - - - diff --git a/docs/styles/jsdoc-default.css b/docs/styles/jsdoc-default.css deleted file mode 100644 index 7d1729dc9..000000000 --- a/docs/styles/jsdoc-default.css +++ /dev/null @@ -1,358 +0,0 @@ -@font-face { - font-family: 'Open Sans'; - font-weight: normal; - font-style: normal; - src: url('../fonts/OpenSans-Regular-webfont.eot'); - src: - local('Open Sans'), - local('OpenSans'), - url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), - url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), - url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg'); -} - -@font-face { - font-family: 'Open Sans Light'; - font-weight: normal; - font-style: normal; - src: url('../fonts/OpenSans-Light-webfont.eot'); - src: - local('Open Sans Light'), - local('OpenSans Light'), - url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), - url('../fonts/OpenSans-Light-webfont.woff') format('woff'), - url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg'); -} - -html -{ - overflow: auto; - background-color: #fff; - font-size: 14px; -} - -body -{ - font-family: 'Open Sans', sans-serif; - line-height: 1.5; - color: #4d4e53; - background-color: white; -} - -a, a:visited, a:active { - color: #0095dd; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -header -{ - display: block; - padding: 0px 4px; -} - -tt, code, kbd, samp { - font-family: Consolas, Monaco, 'Andale Mono', monospace; -} - -.class-description { - font-size: 130%; - line-height: 140%; - margin-bottom: 1em; - margin-top: 1em; -} - -.class-description:empty { - margin: 0; -} - -#main { - float: left; - width: 70%; -} - -article dl { - margin-bottom: 40px; -} - -article img { - max-width: 100%; -} - -section -{ - display: block; - background-color: #fff; - padding: 12px 24px; - border-bottom: 1px solid #ccc; - margin-right: 30px; -} - -.variation { - display: none; -} - -.signature-attributes { - font-size: 60%; - color: #aaa; - font-style: italic; - font-weight: lighter; -} - -nav -{ - display: block; - float: right; - margin-top: 28px; - width: 30%; - box-sizing: border-box; - border-left: 1px solid #ccc; - padding-left: 16px; -} - -nav ul { - font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; - font-size: 100%; - line-height: 17px; - padding: 0; - margin: 0; - list-style-type: none; -} - -nav ul a, nav ul a:visited, nav ul a:active { - font-family: Consolas, Monaco, 'Andale Mono', monospace; - line-height: 18px; - color: #4D4E53; -} - -nav h3 { - margin-top: 12px; -} - -nav li { - margin-top: 6px; -} - -footer { - display: block; - padding: 6px; - margin-top: 12px; - font-style: italic; - font-size: 90%; -} - -h1, h2, h3, h4 { - font-weight: 200; - margin: 0; -} - -h1 -{ - font-family: 'Open Sans Light', sans-serif; - font-size: 48px; - letter-spacing: -2px; - margin: 12px 24px 20px; -} - -h2, h3.subsection-title -{ - font-size: 30px; - font-weight: 700; - letter-spacing: -1px; - margin-bottom: 12px; -} - -h3 -{ - font-size: 24px; - letter-spacing: -0.5px; - margin-bottom: 12px; -} - -h4 -{ - font-size: 18px; - letter-spacing: -0.33px; - margin-bottom: 12px; - color: #4d4e53; -} - -h5, .container-overview .subsection-title -{ - font-size: 120%; - font-weight: bold; - letter-spacing: -0.01em; - margin: 8px 0 3px 0; -} - -h6 -{ - font-size: 100%; - letter-spacing: -0.01em; - margin: 6px 0 3px 0; - font-style: italic; -} - -table -{ - border-spacing: 0; - border: 0; - border-collapse: collapse; -} - -td, th -{ - border: 1px solid #ddd; - margin: 0px; - text-align: left; - vertical-align: top; - padding: 4px 6px; - display: table-cell; -} - -thead tr -{ - background-color: #ddd; - font-weight: bold; -} - -th { border-right: 1px solid #aaa; } -tr > th:last-child { border-right: 1px solid #ddd; } - -.ancestors, .attribs { color: #999; } -.ancestors a, .attribs a -{ - color: #999 !important; - text-decoration: none; -} - -.clear -{ - clear: both; -} - -.important -{ - font-weight: bold; - color: #950B02; -} - -.yes-def { - text-indent: -1000px; -} - -.type-signature { - color: #aaa; -} - -.name, .signature { - font-family: Consolas, Monaco, 'Andale Mono', monospace; -} - -.details { margin-top: 14px; border-left: 2px solid #DDD; } -.details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } -.details dd { margin-left: 70px; } -.details ul { margin: 0; } -.details ul { list-style-type: none; } -.details li { margin-left: 30px; padding-top: 6px; } -.details pre.prettyprint { margin: 0 } -.details .object-value { padding-top: 0; } - -.description { - margin-bottom: 1em; - margin-top: 1em; -} - -.code-caption -{ - font-style: italic; - font-size: 107%; - margin: 0; -} - -.source -{ - border: 1px solid #ddd; - width: 80%; - overflow: auto; -} - -.prettyprint.source { - width: inherit; -} - -.source code -{ - font-size: 100%; - line-height: 18px; - display: block; - padding: 4px 12px; - margin: 0; - background-color: #fff; - color: #4D4E53; -} - -.prettyprint code span.line -{ - display: inline-block; -} - -.prettyprint.linenums -{ - padding-left: 70px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.prettyprint.linenums ol -{ - padding-left: 0; -} - -.prettyprint.linenums li -{ - border-left: 3px #ddd solid; -} - -.prettyprint.linenums li.selected, -.prettyprint.linenums li.selected * -{ - background-color: lightyellow; -} - -.prettyprint.linenums li * -{ - -webkit-user-select: text; - -moz-user-select: text; - -ms-user-select: text; - user-select: text; -} - -.params .name, .props .name, .name code { - color: #4D4E53; - font-family: Consolas, Monaco, 'Andale Mono', monospace; - font-size: 100%; -} - -.params td.description > p:first-child, -.props td.description > p:first-child -{ - margin-top: 0; - padding-top: 0; -} - -.params td.description > p:last-child, -.props td.description > p:last-child -{ - margin-bottom: 0; - padding-bottom: 0; -} - -.disabled { - color: #454545; -} diff --git a/docs/styles/prettify-jsdoc.css b/docs/styles/prettify-jsdoc.css deleted file mode 100644 index 5a2526e37..000000000 --- a/docs/styles/prettify-jsdoc.css +++ /dev/null @@ -1,111 +0,0 @@ -/* JSDoc prettify.js theme */ - -/* plain text */ -.pln { - color: #000000; - font-weight: normal; - font-style: normal; -} - -/* string content */ -.str { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* a keyword */ -.kwd { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* a comment */ -.com { - font-weight: normal; - font-style: italic; -} - -/* a type name */ -.typ { - color: #000000; - font-weight: normal; - font-style: normal; -} - -/* a literal value */ -.lit { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* punctuation */ -.pun { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* lisp open bracket */ -.opn { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* lisp close bracket */ -.clo { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* a markup tag name */ -.tag { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* a markup attribute name */ -.atn { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* a markup attribute value */ -.atv { - color: #006400; - font-weight: normal; - font-style: normal; -} - -/* a declaration */ -.dec { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* a variable name */ -.var { - color: #000000; - font-weight: normal; - font-style: normal; -} - -/* a function name */ -.fun { - color: #000000; - font-weight: bold; - font-style: normal; -} - -/* Specify class=linenums on a pre to get line numbering */ -ol.linenums { - margin-top: 0; - margin-bottom: 0; -} diff --git a/docs/styles/prettify-tomorrow.css b/docs/styles/prettify-tomorrow.css deleted file mode 100644 index b6f92a78d..000000000 --- a/docs/styles/prettify-tomorrow.css +++ /dev/null @@ -1,132 +0,0 @@ -/* Tomorrow Theme */ -/* Original theme - https://github.com/chriskempson/tomorrow-theme */ -/* Pretty printing styles. Used with prettify.js. */ -/* SPAN elements with the classes below are added by prettyprint. */ -/* plain text */ -.pln { - color: #4d4d4c; } - -@media screen { - /* string content */ - .str { - color: #718c00; } - - /* a keyword */ - .kwd { - color: #8959a8; } - - /* a comment */ - .com { - color: #8e908c; } - - /* a type name */ - .typ { - color: #4271ae; } - - /* a literal value */ - .lit { - color: #f5871f; } - - /* punctuation */ - .pun { - color: #4d4d4c; } - - /* lisp open bracket */ - .opn { - color: #4d4d4c; } - - /* lisp close bracket */ - .clo { - color: #4d4d4c; } - - /* a markup tag name */ - .tag { - color: #c82829; } - - /* a markup attribute name */ - .atn { - color: #f5871f; } - - /* a markup attribute value */ - .atv { - color: #3e999f; } - - /* a declaration */ - .dec { - color: #f5871f; } - - /* a variable name */ - .var { - color: #c82829; } - - /* a function name */ - .fun { - color: #4271ae; } } -/* Use higher contrast and text-weight for printable form. */ -@media print, projection { - .str { - color: #060; } - - .kwd { - color: #006; - font-weight: bold; } - - .com { - color: #600; - font-style: italic; } - - .typ { - color: #404; - font-weight: bold; } - - .lit { - color: #044; } - - .pun, .opn, .clo { - color: #440; } - - .tag { - color: #006; - font-weight: bold; } - - .atn { - color: #404; } - - .atv { - color: #060; } } -/* Style */ -/* -pre.prettyprint { - background: white; - font-family: Consolas, Monaco, 'Andale Mono', monospace; - font-size: 12px; - line-height: 1.5; - border: 1px solid #ccc; - padding: 10px; } -*/ - -/* Specify class=linenums on a pre to get line numbering */ -ol.linenums { - margin-top: 0; - margin-bottom: 0; } - -/* IE indents via margin-left */ -li.L0, -li.L1, -li.L2, -li.L3, -li.L4, -li.L5, -li.L6, -li.L7, -li.L8, -li.L9 { - /* */ } - -/* Alternate shading for lines */ -li.L1, -li.L3, -li.L5, -li.L7, -li.L9 { - /* */ } diff --git a/docs/typedocs/.nojekyll b/docs/typedocs/.nojekyll new file mode 100644 index 000000000..e2ac6616a --- /dev/null +++ b/docs/typedocs/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/typedocs/assets/highlight.css b/docs/typedocs/assets/highlight.css new file mode 100644 index 000000000..3f89ee86d --- /dev/null +++ b/docs/typedocs/assets/highlight.css @@ -0,0 +1,92 @@ +:root { + --light-hl-0: #008000; + --dark-hl-0: #6A9955; + --light-hl-1: #AF00DB; + --dark-hl-1: #C586C0; + --light-hl-2: #000000; + --dark-hl-2: #D4D4D4; + --light-hl-3: #001080; + --dark-hl-3: #9CDCFE; + --light-hl-4: #A31515; + --dark-hl-4: #CE9178; + --light-hl-5: #0000FF; + --dark-hl-5: #569CD6; + --light-hl-6: #795E26; + --dark-hl-6: #DCDCAA; + --light-hl-7: #0070C1; + --dark-hl-7: #4FC1FF; + --light-hl-8: #098658; + --dark-hl-8: #B5CEA8; + --light-hl-9: #267F99; + --dark-hl-9: #4EC9B0; + --light-code-background: #FFFFFF; + --dark-code-background: #1E1E1E; +} + +@media (prefers-color-scheme: light) { :root { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --hl-2: var(--light-hl-2); + --hl-3: var(--light-hl-3); + --hl-4: var(--light-hl-4); + --hl-5: var(--light-hl-5); + --hl-6: var(--light-hl-6); + --hl-7: var(--light-hl-7); + --hl-8: var(--light-hl-8); + --hl-9: var(--light-hl-9); + --code-background: var(--light-code-background); +} } + +@media (prefers-color-scheme: dark) { :root { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --hl-2: var(--dark-hl-2); + --hl-3: var(--dark-hl-3); + --hl-4: var(--dark-hl-4); + --hl-5: var(--dark-hl-5); + --hl-6: var(--dark-hl-6); + --hl-7: var(--dark-hl-7); + --hl-8: var(--dark-hl-8); + --hl-9: var(--dark-hl-9); + --code-background: var(--dark-code-background); +} } + +:root[data-theme='light'] { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --hl-2: var(--light-hl-2); + --hl-3: var(--light-hl-3); + --hl-4: var(--light-hl-4); + --hl-5: var(--light-hl-5); + --hl-6: var(--light-hl-6); + --hl-7: var(--light-hl-7); + --hl-8: var(--light-hl-8); + --hl-9: var(--light-hl-9); + --code-background: var(--light-code-background); +} + +:root[data-theme='dark'] { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --hl-2: var(--dark-hl-2); + --hl-3: var(--dark-hl-3); + --hl-4: var(--dark-hl-4); + --hl-5: var(--dark-hl-5); + --hl-6: var(--dark-hl-6); + --hl-7: var(--dark-hl-7); + --hl-8: var(--dark-hl-8); + --hl-9: var(--dark-hl-9); + --code-background: var(--dark-code-background); +} + +.hl-0 { color: var(--hl-0); } +.hl-1 { color: var(--hl-1); } +.hl-2 { color: var(--hl-2); } +.hl-3 { color: var(--hl-3); } +.hl-4 { color: var(--hl-4); } +.hl-5 { color: var(--hl-5); } +.hl-6 { color: var(--hl-6); } +.hl-7 { color: var(--hl-7); } +.hl-8 { color: var(--hl-8); } +.hl-9 { color: var(--hl-9); } +pre, code { background: var(--code-background); } diff --git a/docs/typedocs/assets/main.js b/docs/typedocs/assets/main.js new file mode 100644 index 000000000..01bcad55f --- /dev/null +++ b/docs/typedocs/assets/main.js @@ -0,0 +1,59 @@ +"use strict"; +"use strict";(()=>{var Pe=Object.create;var ne=Object.defineProperty;var Ie=Object.getOwnPropertyDescriptor;var Oe=Object.getOwnPropertyNames;var _e=Object.getPrototypeOf,Re=Object.prototype.hasOwnProperty;var Me=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Fe=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Oe(e))!Re.call(t,i)&&i!==n&&ne(t,i,{get:()=>e[i],enumerable:!(r=Ie(e,i))||r.enumerable});return t};var De=(t,e,n)=>(n=t!=null?Pe(_e(t)):{},Fe(e||!t||!t.__esModule?ne(n,"default",{value:t,enumerable:!0}):n,t));var ae=Me((se,oe)=>{(function(){var t=function(e){var n=new t.Builder;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),n.searchPipeline.add(t.stemmer),e.call(n,n),n.build()};t.version="2.3.9";t.utils={},t.utils.warn=function(e){return function(n){e.console&&console.warn&&console.warn(n)}}(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var n=Object.create(null),r=Object.keys(e),i=0;i0){var d=t.utils.clone(n)||{};d.position=[a,u],d.index=s.length,s.push(new t.Token(r.slice(a,o),d))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. +`,e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(r){var i=t.Pipeline.registeredFunctions[r];if(i)n.add(i);else throw new Error("Cannot load unregistered function: "+r)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(n){t.Pipeline.warnIfFunctionNotRegistered(n),this._stack.push(n)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");r=r+1,this._stack.splice(r,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");this._stack.splice(r,0,n)},t.Pipeline.prototype.remove=function(e){var n=this._stack.indexOf(e);n!=-1&&this._stack.splice(n,1)},t.Pipeline.prototype.run=function(e){for(var n=this._stack.length,r=0;r1&&(oe&&(r=s),o!=e);)i=r-n,s=n+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(ol?d+=2:a==l&&(n+=r[u+1]*i[d+1],u+=2,d+=2);return n},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),n=1,r=0;n0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new t.TokenSet;s.node.edges["*"]=l}if(s.str.length==0&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new t.TokenSet;s.node.edges["*"]=u}s.str.length==1&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var d=s.str.charAt(0),v=s.str.charAt(1),f;v in s.node.edges?f=s.node.edges[v]:(f=new t.TokenSet,s.node.edges[v]=f),s.str.length==1&&(f.final=!0),i.push({node:f,editsRemaining:s.editsRemaining-1,str:d+s.str.slice(2)})}}}return r},t.TokenSet.fromString=function(e){for(var n=new t.TokenSet,r=n,i=0,s=e.length;i=e;n--){var r=this.uncheckedNodes[n],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r.char]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}};t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(n){var r=new t.QueryParser(e,n);r.parse()})},t.Index.prototype.query=function(e){for(var n=new t.Query(this.fields),r=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),l=0;l1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,n){var r=e[this._ref],i=Object.keys(this._fields);this._documents[r]=n||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,n;do e=this.next(),n=e.charCodeAt(0);while(n>47&&n<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var n=e.next();if(n==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(n.charCodeAt(0)==92){e.escapeCharacter();continue}if(n==":")return t.QueryLexer.lexField;if(n=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(n=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(n=="+"&&e.width()===1||n=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(n.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,n){this.lexer=new t.QueryLexer(e),this.query=n,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var n=e.peekLexeme();if(n!=null)switch(n.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expected either a field or a term, found "+n.type;throw n.str.length>=1&&(r+=" with value '"+n.str+"'"),new t.QueryParseError(r,n.start,n.end)}},t.QueryParser.parsePresence=function(e){var n=e.consumeLexeme();if(n!=null){switch(n.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var r="unrecognised presence operator'"+n.str+"'";throw new t.QueryParseError(r,n.start,n.end)}var i=e.peekLexeme();if(i==null){var r="expecting term or field, found nothing";throw new t.QueryParseError(r,n.start,n.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(r,i.start,i.end)}}},t.QueryParser.parseField=function(e){var n=e.consumeLexeme();if(n!=null){if(e.query.allFields.indexOf(n.str)==-1){var r=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+n.str+"', possible fields: "+r;throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.fields=[n.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,n.start,n.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var n=e.consumeLexeme();if(n!=null){e.currentClause.term=n.str.toLowerCase(),n.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var r=e.peekLexeme();if(r==null){e.nextClause();return}switch(r.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+r.type+"'";throw new t.QueryParseError(i,r.start,r.end)}}},t.QueryParser.parseEditDistance=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="edit distance must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.editDistance=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="boost must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.boost=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,n){typeof define=="function"&&define.amd?define(n):typeof se=="object"?oe.exports=n():e.lunr=n()}(this,function(){return t})})()});var re=[];function G(t,e){re.push({selector:e,constructor:t})}var U=class{constructor(){this.alwaysVisibleMember=null;this.createComponents(document.body),this.ensureActivePageVisible(),this.ensureFocusedElementVisible(),this.listenForCodeCopies(),window.addEventListener("hashchange",()=>this.ensureFocusedElementVisible())}createComponents(e){re.forEach(n=>{e.querySelectorAll(n.selector).forEach(r=>{r.dataset.hasInstance||(new n.constructor({el:r,app:this}),r.dataset.hasInstance=String(!0))})})}filterChanged(){this.ensureFocusedElementVisible()}ensureActivePageVisible(){let e=document.querySelector(".tsd-navigation .current"),n=e?.parentElement;for(;n&&!n.classList.contains(".tsd-navigation");)n instanceof HTMLDetailsElement&&(n.open=!0),n=n.parentElement;if(e){let r=e.getBoundingClientRect().top-document.documentElement.clientHeight/4;document.querySelector(".site-menu").scrollTop=r}}ensureFocusedElementVisible(){if(this.alwaysVisibleMember&&(this.alwaysVisibleMember.classList.remove("always-visible"),this.alwaysVisibleMember.firstElementChild.remove(),this.alwaysVisibleMember=null),!location.hash)return;let e=document.getElementById(location.hash.substring(1));if(!e)return;let n=e.parentElement;for(;n&&n.tagName!=="SECTION";)n=n.parentElement;if(n&&n.offsetParent==null){this.alwaysVisibleMember=n,n.classList.add("always-visible");let r=document.createElement("p");r.classList.add("warning"),r.textContent="This member is normally hidden due to your filter settings.",n.prepend(r)}}listenForCodeCopies(){document.querySelectorAll("pre > button").forEach(e=>{let n;e.addEventListener("click",()=>{e.previousElementSibling instanceof HTMLElement&&navigator.clipboard.writeText(e.previousElementSibling.innerText.trim()),e.textContent="Copied!",e.classList.add("visible"),clearTimeout(n),n=setTimeout(()=>{e.classList.remove("visible"),n=setTimeout(()=>{e.textContent="Copy"},100)},1e3)})})}};var ie=(t,e=100)=>{let n;return()=>{clearTimeout(n),n=setTimeout(()=>t(),e)}};var de=De(ae());async function le(t,e){if(!window.searchData)return;let n=await fetch(window.searchData),r=new Blob([await n.arrayBuffer()]).stream().pipeThrough(new DecompressionStream("gzip")),i=await new Response(r).json();t.data=i,t.index=de.Index.load(i.index),e.classList.remove("loading"),e.classList.add("ready")}function he(){let t=document.getElementById("tsd-search");if(!t)return;let e={base:t.dataset.base+"/"},n=document.getElementById("tsd-search-script");t.classList.add("loading"),n&&(n.addEventListener("error",()=>{t.classList.remove("loading"),t.classList.add("failure")}),n.addEventListener("load",()=>{le(e,t)}),le(e,t));let r=document.querySelector("#tsd-search input"),i=document.querySelector("#tsd-search .results");if(!r||!i)throw new Error("The input field or the result list wrapper was not found");let s=!1;i.addEventListener("mousedown",()=>s=!0),i.addEventListener("mouseup",()=>{s=!1,t.classList.remove("has-focus")}),r.addEventListener("focus",()=>t.classList.add("has-focus")),r.addEventListener("blur",()=>{s||(s=!1,t.classList.remove("has-focus"))}),Ae(t,i,r,e)}function Ae(t,e,n,r){n.addEventListener("input",ie(()=>{Ne(t,e,n,r)},200));let i=!1;n.addEventListener("keydown",s=>{i=!0,s.key=="Enter"?Ve(e,n):s.key=="Escape"?n.blur():s.key=="ArrowUp"?ue(e,-1):s.key==="ArrowDown"?ue(e,1):i=!1}),n.addEventListener("keypress",s=>{i&&s.preventDefault()}),document.body.addEventListener("keydown",s=>{s.altKey||s.ctrlKey||s.metaKey||!n.matches(":focus")&&s.key==="/"&&(n.focus(),s.preventDefault())})}function Ne(t,e,n,r){if(!r.index||!r.data)return;e.textContent="";let i=n.value.trim(),s=i?r.index.search(`*${i}*`):[];for(let o=0;oa.score-o.score);for(let o=0,a=Math.min(10,s.length);o`,d=ce(l.name,i);globalThis.DEBUG_SEARCH_WEIGHTS&&(d+=` (score: ${s[o].score.toFixed(2)})`),l.parent&&(d=` + ${ce(l.parent,i)}.${d}`);let v=document.createElement("li");v.classList.value=l.classes??"";let f=document.createElement("a");f.href=r.base+l.url,f.innerHTML=u+d,v.append(f),e.appendChild(v)}}function ue(t,e){let n=t.querySelector(".current");if(!n)n=t.querySelector(e==1?"li:first-child":"li:last-child"),n&&n.classList.add("current");else{let r=n;if(e===1)do r=r.nextElementSibling??void 0;while(r instanceof HTMLElement&&r.offsetParent==null);else do r=r.previousElementSibling??void 0;while(r instanceof HTMLElement&&r.offsetParent==null);r&&(n.classList.remove("current"),r.classList.add("current"))}}function Ve(t,e){let n=t.querySelector(".current");if(n||(n=t.querySelector("li:first-child")),n){let r=n.querySelector("a");r&&(window.location.href=r.href),e.blur()}}function ce(t,e){if(e==="")return t;let n=t.toLocaleLowerCase(),r=e.toLocaleLowerCase(),i=[],s=0,o=n.indexOf(r);for(;o!=-1;)i.push(K(t.substring(s,o)),`${K(t.substring(o,o+r.length))}`),s=o+r.length,o=n.indexOf(r,s);return i.push(K(t.substring(s))),i.join("")}var Be={"&":"&","<":"<",">":">","'":"'",'"':"""};function K(t){return t.replace(/[&<>"'"]/g,e=>Be[e])}var C=class{constructor(e){this.el=e.el,this.app=e.app}};var F="mousedown",pe="mousemove",B="mouseup",J={x:0,y:0},fe=!1,ee=!1,He=!1,D=!1,me=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);document.documentElement.classList.add(me?"is-mobile":"not-mobile");me&&"ontouchstart"in document.documentElement&&(He=!0,F="touchstart",pe="touchmove",B="touchend");document.addEventListener(F,t=>{ee=!0,D=!1;let e=F=="touchstart"?t.targetTouches[0]:t;J.y=e.pageY||0,J.x=e.pageX||0});document.addEventListener(pe,t=>{if(ee&&!D){let e=F=="touchstart"?t.targetTouches[0]:t,n=J.x-(e.pageX||0),r=J.y-(e.pageY||0);D=Math.sqrt(n*n+r*r)>10}});document.addEventListener(B,()=>{ee=!1});document.addEventListener("click",t=>{fe&&(t.preventDefault(),t.stopImmediatePropagation(),fe=!1)});var X=class extends C{constructor(n){super(n);this.className=this.el.dataset.toggle||"",this.el.addEventListener(B,r=>this.onPointerUp(r)),this.el.addEventListener("click",r=>r.preventDefault()),document.addEventListener(F,r=>this.onDocumentPointerDown(r)),document.addEventListener(B,r=>this.onDocumentPointerUp(r))}setActive(n){if(this.active==n)return;this.active=n,document.documentElement.classList.toggle("has-"+this.className,n),this.el.classList.toggle("active",n);let r=(this.active?"to-has-":"from-has-")+this.className;document.documentElement.classList.add(r),setTimeout(()=>document.documentElement.classList.remove(r),500)}onPointerUp(n){D||(this.setActive(!0),n.preventDefault())}onDocumentPointerDown(n){if(this.active){if(n.target.closest(".col-sidebar, .tsd-filter-group"))return;this.setActive(!1)}}onDocumentPointerUp(n){if(!D&&this.active&&n.target.closest(".col-sidebar")){let r=n.target.closest("a");if(r){let i=window.location.href;i.indexOf("#")!=-1&&(i=i.substring(0,i.indexOf("#"))),r.href.substring(0,i.length)==i&&setTimeout(()=>this.setActive(!1),250)}}}};var te;try{te=localStorage}catch{te={getItem(){return null},setItem(){}}}var Q=te;var ve=document.head.appendChild(document.createElement("style"));ve.dataset.for="filters";var Y=class extends C{constructor(n){super(n);this.key=`filter-${this.el.name}`,this.value=this.el.checked,this.el.addEventListener("change",()=>{this.setLocalStorage(this.el.checked)}),this.setLocalStorage(this.fromLocalStorage()),ve.innerHTML+=`html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; } +`}fromLocalStorage(){let n=Q.getItem(this.key);return n?n==="true":this.el.checked}setLocalStorage(n){Q.setItem(this.key,n.toString()),this.value=n,this.handleValueChange()}handleValueChange(){this.el.checked=this.value,document.documentElement.classList.toggle(this.key,this.value),this.app.filterChanged(),document.querySelectorAll(".tsd-index-section").forEach(n=>{n.style.display="block";let r=Array.from(n.querySelectorAll(".tsd-index-link")).every(i=>i.offsetParent==null);n.style.display=r?"none":"block"})}};var Z=class extends C{constructor(n){super(n);this.summary=this.el.querySelector(".tsd-accordion-summary"),this.icon=this.summary.querySelector("svg"),this.key=`tsd-accordion-${this.summary.dataset.key??this.summary.textContent.trim().replace(/\s+/g,"-").toLowerCase()}`;let r=Q.getItem(this.key);this.el.open=r?r==="true":this.el.open,this.el.addEventListener("toggle",()=>this.update());let i=this.summary.querySelector("a");i&&i.addEventListener("click",()=>{location.assign(i.href)}),this.update()}update(){this.icon.style.transform=`rotate(${this.el.open?0:-90}deg)`,Q.setItem(this.key,this.el.open.toString())}};function ge(t){let e=Q.getItem("tsd-theme")||"os";t.value=e,ye(e),t.addEventListener("change",()=>{Q.setItem("tsd-theme",t.value),ye(t.value)})}function ye(t){document.documentElement.dataset.theme=t}var Le;function be(){let t=document.getElementById("tsd-nav-script");t&&(t.addEventListener("load",xe),xe())}async function xe(){let t=document.getElementById("tsd-nav-container");if(!t||!window.navigationData)return;let n=await(await fetch(window.navigationData)).arrayBuffer(),r=new Blob([n]).stream().pipeThrough(new DecompressionStream("gzip")),i=await new Response(r).json();Le=t.dataset.base+"/",t.innerHTML="";for(let s of i)we(s,t,[]);window.app.createComponents(t),window.app.ensureActivePageVisible()}function we(t,e,n){let r=e.appendChild(document.createElement("li"));if(t.children){let i=[...n,t.text],s=r.appendChild(document.createElement("details"));s.className=t.class?`${t.class} tsd-index-accordion`:"tsd-index-accordion",s.dataset.key=i.join("$");let o=s.appendChild(document.createElement("summary"));o.className="tsd-accordion-summary",o.innerHTML='',Ee(t,o);let a=s.appendChild(document.createElement("div"));a.className="tsd-accordion-details";let l=a.appendChild(document.createElement("ul"));l.className="tsd-nested-navigation";for(let u of t.children)we(u,l,i)}else Ee(t,r,t.class)}function Ee(t,e,n){if(t.path){let r=e.appendChild(document.createElement("a"));r.href=Le+t.path,n&&(r.className=n),location.href===r.href&&r.classList.add("current"),t.kind&&(r.innerHTML=``),r.appendChild(document.createElement("span")).textContent=t.text}else e.appendChild(document.createElement("span")).textContent=t.text}G(X,"a[data-toggle]");G(Z,".tsd-index-accordion");G(Y,".tsd-filter-item input[type=checkbox]");var Se=document.getElementById("tsd-theme");Se&&ge(Se);var je=new U;Object.defineProperty(window,"app",{value:je});he();be();})(); +/*! Bundled license information: + +lunr/lunr.js: + (** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + *) + (*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Set + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.tokenizer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Vector + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.stemmer + * Copyright (C) 2020 Oliver Nightingale + * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt + *) + (*! + * lunr.stopWordFilter + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.trimmer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.TokenSet + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Builder + * Copyright (C) 2020 Oliver Nightingale + *) +*/ diff --git a/docs/typedocs/assets/navigation.js b/docs/typedocs/assets/navigation.js new file mode 100644 index 000000000..31a87c774 --- /dev/null +++ b/docs/typedocs/assets/navigation.js @@ -0,0 +1 @@ +window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE52YT2/TMBiHv0vPExMDIbQb6zZasbGxBDggDl7yNrWa2JHtbKkQ3x2nbZo4iV+/5bLDfo8fx//t/vozM1Cb2eVsLoWAxHAp4m0Js7NZycza/h9EVehzN32zNkVukQ0X6ezy49+zo+VeClDyC2yXBcsgKkGYyDBT6aHQC4bc96B1U4JnwuIKpr7WT4bscf2ouFTcbKedXe43fQbx3fC81+QkZ1qDPm8Tt+zbi37phTHlPOe2P8bluwwz3PFnxdTW8w39FLPs2/spSWQ19SlOTPbELAuoLEGwpamyg3sl5eZGGLX1OgccwZyb+Zpx4TUe8rDpinklNiKUz2Wy8RqakOhYAEtBoaY9QvTFUJQ5M4AaWyjsnK/B385dSHQ8gQb14v2sPkM0xjUqi2uC57hv3jNhNyPvOIzA/3DfcW1AnFBHW+CUuqLSP7FdKmy9ZlBIr22fUi227hX37i59hmpcipXEfQ1BtYUGx6Wo1qcywYUWoLqirUjCbW4pqvV7mdp9oF19Ve49Szz4afVcy1eRS5bSq3JLEGoDbbi9UHBk4nZI2HejlPROil0YdtwC3NgqC2RX7iFh34Kp9FaqDTYb+kzYuBSJLLjIYsWEXvlXwZCjmA1kyjYrPZz2fvUADLvb66lP2eZ007IopTL47JxiwzUMb7t4HdM0oRZu/8Z1VBVe85Eg2exYDx8II9+RIRhtK7jmGTZz+8wpRh4YtzFJtzcDQbN3ZNj+FcyrXaLuE8nV9pCw76EymSSs4iFHMpeVt+37lGpZ2DNU2pVeoG+DKZZaw7cKQuIdQvX9ZHkOgdbvmbDxEfzj0mQEg6pEYPvoIWGfvYJ0F0Of0YFITvTgbPOwKaqeGX5wdATJVnAT13j3uRTBau9cAeORCNtCq5e+alsSXQ8ORHB6H12U91Zc4++ANqeYHqXMm3PHOzF6CMWH91JN7p/Iv1XsQooD33HaPGzy/MjUC8OOH6A0sjMc4rAHbxO1RXsOn0V9hmq8rfIc9zUE1WbviN5u7wiqLfQ2dSmqFXmbHgHMFen8oWyOg4mWdhlmiJne3ElZTrWsy1DDWgFLm2U+YThmmCGFFXM27hemOHvOreAQuaXfXfQKJ/sjMZ567a8qsTss9fmYcpUf3k8pJwZpQukZKVdp+8HA1DTvCQcMUefO82ndeKY7ugzMaIfpRF2KKOwsEXjzXAJR6XVlUvk6+S1tNir++x936q+cpxkAAA==" \ No newline at end of file diff --git a/docs/typedocs/assets/search.js b/docs/typedocs/assets/search.js new file mode 100644 index 000000000..d93c83fab --- /dev/null +++ b/docs/typedocs/assets/search.js @@ -0,0 +1 @@ +window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file diff --git a/docs/typedocs/assets/style.css b/docs/typedocs/assets/style.css new file mode 100644 index 000000000..108428c3f --- /dev/null +++ b/docs/typedocs/assets/style.css @@ -0,0 +1,1383 @@ +:root { + /* Light */ + --light-color-background: #f2f4f8; + --light-color-background-secondary: #eff0f1; + --light-color-warning-text: #222; + --light-color-background-warning: #e6e600; + --light-color-icon-background: var(--light-color-background); + --light-color-accent: #c5c7c9; + --light-color-active-menu-item: var(--light-color-accent); + --light-color-text: #222; + --light-color-text-aside: #6e6e6e; + --light-color-link: #1f70c2; + + --light-color-ts-project: #b111c9; + --light-color-ts-module: var(--light-color-ts-project); + --light-color-ts-namespace: var(--light-color-ts-project); + --light-color-ts-enum: #7e6f15; + --light-color-ts-enum-member: var(--light-color-ts-enum); + --light-color-ts-variable: #4760ec; + --light-color-ts-function: #572be7; + --light-color-ts-class: #1f70c2; + --light-color-ts-interface: #108024; + --light-color-ts-constructor: var(--light-color-ts-class); + --light-color-ts-property: var(--light-color-ts-variable); + --light-color-ts-method: var(--light-color-ts-function); + --light-color-ts-call-signature: var(--light-color-ts-method); + --light-color-ts-index-signature: var(--light-color-ts-property); + --light-color-ts-constructor-signature: var(--light-color-ts-constructor); + --light-color-ts-parameter: var(--light-color-ts-variable); + /* type literal not included as links will never be generated to it */ + --light-color-ts-type-parameter: var(--light-color-ts-type-alias); + --light-color-ts-accessor: var(--light-color-ts-property); + --light-color-ts-get-signature: var(--light-color-ts-accessor); + --light-color-ts-set-signature: var(--light-color-ts-accessor); + --light-color-ts-type-alias: #d51270; + /* reference not included as links will be colored with the kind that it points to */ + + --light-external-icon: url("data:image/svg+xml;utf8,"); + --light-color-scheme: light; + + /* Dark */ + --dark-color-background: #2b2e33; + --dark-color-background-secondary: #1e2024; + --dark-color-background-warning: #bebe00; + --dark-color-warning-text: #222; + --dark-color-icon-background: var(--dark-color-background-secondary); + --dark-color-accent: #9096a2; + --dark-color-active-menu-item: #5d5d6a; + --dark-color-text: #f5f5f5; + --dark-color-text-aside: #dddddd; + --dark-color-link: #00aff4; + + --dark-color-ts-project: #e358ff; + --dark-color-ts-module: var(--dark-color-ts-project); + --dark-color-ts-namespace: var(--dark-color-ts-project); + --dark-color-ts-enum: #f4d93e; + --dark-color-ts-enum-member: var(--dark-color-ts-enum); + --dark-color-ts-variable: #798dff; + --dark-color-ts-function: #a280ff; + --dark-color-ts-class: #8ac4ff; + --dark-color-ts-interface: #6cff87; + --dark-color-ts-constructor: var(--dark-color-ts-class); + --dark-color-ts-property: var(--dark-color-ts-variable); + --dark-color-ts-method: var(--dark-color-ts-function); + --dark-color-ts-call-signature: var(--dark-color-ts-method); + --dark-color-ts-index-signature: var(--dark-color-ts-property); + --dark-color-ts-constructor-signature: var(--dark-color-ts-constructor); + --dark-color-ts-parameter: var(--dark-color-ts-variable); + /* type literal not included as links will never be generated to it */ + --dark-color-ts-type-parameter: var(--dark-color-ts-type-alias); + --dark-color-ts-accessor: var(--dark-color-ts-property); + --dark-color-ts-get-signature: var(--dark-color-ts-accessor); + --dark-color-ts-set-signature: var(--dark-color-ts-accessor); + --dark-color-ts-type-alias: #ff6492; + /* reference not included as links will be colored with the kind that it points to */ + + --dark-external-icon: url("data:image/svg+xml;utf8,"); + --dark-color-scheme: dark; +} + +@media (prefers-color-scheme: light) { + :root { + --color-background: var(--light-color-background); + --color-background-secondary: var(--light-color-background-secondary); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); + --color-icon-background: var(--light-color-icon-background); + --color-accent: var(--light-color-accent); + --color-active-menu-item: var(--light-color-active-menu-item); + --color-text: var(--light-color-text); + --color-text-aside: var(--light-color-text-aside); + --color-link: var(--light-color-link); + + --color-ts-module: var(--light-color-ts-module); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-enum-member: var(--light-color-ts-enum-member); + --color-ts-variable: var(--light-color-ts-variable); + --color-ts-function: var(--light-color-ts-function); + --color-ts-class: var(--light-color-ts-class); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-constructor: var(--light-color-ts-constructor); + --color-ts-property: var(--light-color-ts-property); + --color-ts-method: var(--light-color-ts-method); + --color-ts-call-signature: var(--light-color-ts-call-signature); + --color-ts-index-signature: var(--light-color-ts-index-signature); + --color-ts-constructor-signature: var( + --light-color-ts-constructor-signature + ); + --color-ts-parameter: var(--light-color-ts-parameter); + --color-ts-type-parameter: var(--light-color-ts-type-parameter); + --color-ts-accessor: var(--light-color-ts-accessor); + --color-ts-get-signature: var(--light-color-ts-get-signature); + --color-ts-set-signature: var(--light-color-ts-set-signature); + --color-ts-type-alias: var(--light-color-ts-type-alias); + + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); + } +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--dark-color-background); + --color-background-secondary: var(--dark-color-background-secondary); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); + --color-icon-background: var(--dark-color-icon-background); + --color-accent: var(--dark-color-accent); + --color-active-menu-item: var(--dark-color-active-menu-item); + --color-text: var(--dark-color-text); + --color-text-aside: var(--dark-color-text-aside); + --color-link: var(--dark-color-link); + + --color-ts-module: var(--dark-color-ts-module); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-enum-member: var(--dark-color-ts-enum-member); + --color-ts-variable: var(--dark-color-ts-variable); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-constructor: var(--dark-color-ts-constructor); + --color-ts-property: var(--dark-color-ts-property); + --color-ts-method: var(--dark-color-ts-method); + --color-ts-call-signature: var(--dark-color-ts-call-signature); + --color-ts-index-signature: var(--dark-color-ts-index-signature); + --color-ts-constructor-signature: var( + --dark-color-ts-constructor-signature + ); + --color-ts-parameter: var(--dark-color-ts-parameter); + --color-ts-type-parameter: var(--dark-color-ts-type-parameter); + --color-ts-accessor: var(--dark-color-ts-accessor); + --color-ts-get-signature: var(--dark-color-ts-get-signature); + --color-ts-set-signature: var(--dark-color-ts-set-signature); + --color-ts-type-alias: var(--dark-color-ts-type-alias); + + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); + } +} + +html { + color-scheme: var(--color-scheme); +} + +body { + margin: 0; +} + +:root[data-theme="light"] { + --color-background: var(--light-color-background); + --color-background-secondary: var(--light-color-background-secondary); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); + --color-icon-background: var(--light-color-icon-background); + --color-accent: var(--light-color-accent); + --color-active-menu-item: var(--light-color-active-menu-item); + --color-text: var(--light-color-text); + --color-text-aside: var(--light-color-text-aside); + --color-link: var(--light-color-link); + + --color-ts-module: var(--light-color-ts-module); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-enum-member: var(--light-color-ts-enum-member); + --color-ts-variable: var(--light-color-ts-variable); + --color-ts-function: var(--light-color-ts-function); + --color-ts-class: var(--light-color-ts-class); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-constructor: var(--light-color-ts-constructor); + --color-ts-property: var(--light-color-ts-property); + --color-ts-method: var(--light-color-ts-method); + --color-ts-call-signature: var(--light-color-ts-call-signature); + --color-ts-index-signature: var(--light-color-ts-index-signature); + --color-ts-constructor-signature: var( + --light-color-ts-constructor-signature + ); + --color-ts-parameter: var(--light-color-ts-parameter); + --color-ts-type-parameter: var(--light-color-ts-type-parameter); + --color-ts-accessor: var(--light-color-ts-accessor); + --color-ts-get-signature: var(--light-color-ts-get-signature); + --color-ts-set-signature: var(--light-color-ts-set-signature); + --color-ts-type-alias: var(--light-color-ts-type-alias); + + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); +} + +:root[data-theme="dark"] { + --color-background: var(--dark-color-background); + --color-background-secondary: var(--dark-color-background-secondary); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); + --color-icon-background: var(--dark-color-icon-background); + --color-accent: var(--dark-color-accent); + --color-active-menu-item: var(--dark-color-active-menu-item); + --color-text: var(--dark-color-text); + --color-text-aside: var(--dark-color-text-aside); + --color-link: var(--dark-color-link); + + --color-ts-module: var(--dark-color-ts-module); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-enum-member: var(--dark-color-ts-enum-member); + --color-ts-variable: var(--dark-color-ts-variable); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-constructor: var(--dark-color-ts-constructor); + --color-ts-property: var(--dark-color-ts-property); + --color-ts-method: var(--dark-color-ts-method); + --color-ts-call-signature: var(--dark-color-ts-call-signature); + --color-ts-index-signature: var(--dark-color-ts-index-signature); + --color-ts-constructor-signature: var( + --dark-color-ts-constructor-signature + ); + --color-ts-parameter: var(--dark-color-ts-parameter); + --color-ts-type-parameter: var(--dark-color-ts-type-parameter); + --color-ts-accessor: var(--dark-color-ts-accessor); + --color-ts-get-signature: var(--dark-color-ts-get-signature); + --color-ts-set-signature: var(--dark-color-ts-set-signature); + --color-ts-type-alias: var(--dark-color-ts-type-alias); + + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); +} + +.always-visible, +.always-visible .tsd-signatures { + display: inherit !important; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + line-height: 1.2; +} + +h1 > a, +h2 > a, +h3 > a, +h4 > a, +h5 > a, +h6 > a { + text-decoration: none; + color: var(--color-text); +} + +h1 { + font-size: 1.875rem; + margin: 0.67rem 0; +} + +h2 { + font-size: 1.5rem; + margin: 0.83rem 0; +} + +h3 { + font-size: 1.25rem; + margin: 1rem 0; +} + +h4 { + font-size: 1.05rem; + margin: 1.33rem 0; +} + +h5 { + font-size: 1rem; + margin: 1.5rem 0; +} + +h6 { + font-size: 0.875rem; + margin: 2.33rem 0; +} + +.uppercase { + text-transform: uppercase; +} + +dl, +menu, +ol, +ul { + margin: 1em 0; +} + +dd { + margin: 0 0 0 40px; +} + +.container { + max-width: 1700px; + padding: 0 2rem; +} + +/* Footer */ +.tsd-generator { + border-top: 1px solid var(--color-accent); + padding-top: 1rem; + padding-bottom: 1rem; + max-height: 3.5rem; +} + +.tsd-generator > p { + margin-top: 0; + margin-bottom: 0; + padding: 0 1rem; +} + +.container-main { + margin: 0 auto; + /* toolbar, footer, margin */ + min-height: calc(100vh - 41px - 56px - 4rem); +} + +@keyframes fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } +} +@keyframes fade-out { + from { + opacity: 1; + visibility: visible; + } + to { + opacity: 0; + } +} +@keyframes fade-in-delayed { + 0% { + opacity: 0; + } + 33% { + opacity: 0; + } + 100% { + opacity: 1; + } +} +@keyframes fade-out-delayed { + 0% { + opacity: 1; + visibility: visible; + } + 66% { + opacity: 0; + } + 100% { + opacity: 0; + } +} +@keyframes pop-in-from-right { + from { + transform: translate(100%, 0); + } + to { + transform: translate(0, 0); + } +} +@keyframes pop-out-to-right { + from { + transform: translate(0, 0); + visibility: visible; + } + to { + transform: translate(100%, 0); + } +} +body { + background: var(--color-background); + font-family: "Segoe UI", sans-serif; + font-size: 16px; + color: var(--color-text); +} + +a { + color: var(--color-link); + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +a.external[target="_blank"] { + background-image: var(--external-icon); + background-position: top 3px right; + background-repeat: no-repeat; + padding-right: 13px; +} + +code, +pre { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + padding: 0.2em; + margin: 0; + font-size: 0.875rem; + border-radius: 0.8em; +} + +pre { + position: relative; + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; + padding: 10px; + border: 1px solid var(--color-accent); +} +pre code { + padding: 0; + font-size: 100%; +} +pre > button { + position: absolute; + top: 10px; + right: 10px; + opacity: 0; + transition: opacity 0.1s; + box-sizing: border-box; +} +pre:hover > button, +pre > button.visible { + opacity: 1; +} + +blockquote { + margin: 1em 0; + padding-left: 1em; + border-left: 4px solid gray; +} + +.tsd-typography { + line-height: 1.333em; +} +.tsd-typography ul { + list-style: square; + padding: 0 0 0 20px; + margin: 0; +} +.tsd-typography .tsd-index-panel h3, +.tsd-index-panel .tsd-typography h3, +.tsd-typography h4, +.tsd-typography h5, +.tsd-typography h6 { + font-size: 1em; +} +.tsd-typography h5, +.tsd-typography h6 { + font-weight: normal; +} +.tsd-typography p, +.tsd-typography ul, +.tsd-typography ol { + margin: 1em 0; +} +.tsd-typography table { + border-collapse: collapse; + border: none; +} +.tsd-typography td, +.tsd-typography th { + padding: 6px 13px; + border: 1px solid var(--color-accent); +} +.tsd-typography thead, +.tsd-typography tr:nth-child(even) { + background-color: var(--color-background-secondary); +} + +.tsd-breadcrumb { + margin: 0; + padding: 0; + color: var(--color-text-aside); +} +.tsd-breadcrumb a { + color: var(--color-text-aside); + text-decoration: none; +} +.tsd-breadcrumb a:hover { + text-decoration: underline; +} +.tsd-breadcrumb li { + display: inline; +} +.tsd-breadcrumb li:after { + content: " / "; +} + +.tsd-comment-tags { + display: flex; + flex-direction: column; +} +dl.tsd-comment-tag-group { + display: flex; + align-items: center; + overflow: hidden; + margin: 0.5em 0; +} +dl.tsd-comment-tag-group dt { + display: flex; + margin-right: 0.5em; + font-size: 0.875em; + font-weight: normal; +} +dl.tsd-comment-tag-group dd { + margin: 0; +} +code.tsd-tag { + padding: 0.25em 0.4em; + border: 0.1em solid var(--color-accent); + margin-right: 0.25em; + font-size: 70%; +} +h1 code.tsd-tag:first-of-type { + margin-left: 0.25em; +} + +dl.tsd-comment-tag-group dd:before, +dl.tsd-comment-tag-group dd:after { + content: " "; +} +dl.tsd-comment-tag-group dd pre, +dl.tsd-comment-tag-group dd:after { + clear: both; +} +dl.tsd-comment-tag-group p { + margin: 0; +} + +.tsd-panel.tsd-comment .lead { + font-size: 1.1em; + line-height: 1.333em; + margin-bottom: 2em; +} +.tsd-panel.tsd-comment .lead:last-child { + margin-bottom: 0; +} + +.tsd-filter-visibility h4 { + font-size: 1rem; + padding-top: 0.75rem; + padding-bottom: 0.5rem; + margin: 0; +} +.tsd-filter-item:not(:last-child) { + margin-bottom: 0.5rem; +} +.tsd-filter-input { + display: flex; + width: fit-content; + width: -moz-fit-content; + align-items: center; + user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + cursor: pointer; +} +.tsd-filter-input input[type="checkbox"] { + cursor: pointer; + position: absolute; + width: 1.5em; + height: 1.5em; + opacity: 0; +} +.tsd-filter-input input[type="checkbox"]:disabled { + pointer-events: none; +} +.tsd-filter-input svg { + cursor: pointer; + width: 1.5em; + height: 1.5em; + margin-right: 0.5em; + border-radius: 0.33em; + /* Leaving this at full opacity breaks event listeners on Firefox. + Don't remove unless you know what you're doing. */ + opacity: 0.99; +} +.tsd-filter-input input[type="checkbox"]:focus + svg { + transform: scale(0.95); +} +.tsd-filter-input input[type="checkbox"]:focus:not(:focus-visible) + svg { + transform: scale(1); +} +.tsd-checkbox-background { + fill: var(--color-accent); +} +input[type="checkbox"]:checked ~ svg .tsd-checkbox-checkmark { + stroke: var(--color-text); +} +.tsd-filter-input input:disabled ~ svg > .tsd-checkbox-background { + fill: var(--color-background); + stroke: var(--color-accent); + stroke-width: 0.25rem; +} +.tsd-filter-input input:disabled ~ svg > .tsd-checkbox-checkmark { + stroke: var(--color-accent); +} + +.tsd-theme-toggle { + padding-top: 0.75rem; +} +.tsd-theme-toggle > h4 { + display: inline; + vertical-align: middle; + margin-right: 0.75rem; +} + +.tsd-hierarchy { + list-style: square; + margin: 0; +} +.tsd-hierarchy .target { + font-weight: bold; +} + +.tsd-panel-group.tsd-index-group { + margin-bottom: 0; +} +.tsd-index-panel .tsd-index-list { + list-style: none; + line-height: 1.333em; + margin: 0; + padding: 0.25rem 0 0 0; + overflow: hidden; + display: grid; + grid-template-columns: repeat(3, 1fr); + column-gap: 1rem; + grid-template-rows: auto; +} +@media (max-width: 1024px) { + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(2, 1fr); + } +} +@media (max-width: 768px) { + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(1, 1fr); + } +} +.tsd-index-panel .tsd-index-list li { + -webkit-page-break-inside: avoid; + -moz-page-break-inside: avoid; + -ms-page-break-inside: avoid; + -o-page-break-inside: avoid; + page-break-inside: avoid; +} + +.tsd-flag { + display: inline-block; + padding: 0.25em 0.4em; + border-radius: 4px; + color: var(--color-comment-tag-text); + background-color: var(--color-comment-tag); + text-indent: 0; + font-size: 75%; + line-height: 1; + font-weight: normal; +} + +.tsd-anchor { + position: relative; + top: -100px; +} + +.tsd-member { + position: relative; +} +.tsd-member .tsd-anchor + h3 { + display: flex; + align-items: center; + margin-top: 0; + margin-bottom: 0; + border-bottom: none; +} + +.tsd-navigation.settings { + margin: 1rem 0; +} +.tsd-navigation > a, +.tsd-navigation .tsd-accordion-summary { + width: calc(100% - 0.5rem); +} +.tsd-navigation a, +.tsd-navigation summary > span, +.tsd-page-navigation a { + display: inline-flex; + align-items: center; + padding: 0.25rem; + color: var(--color-text); + text-decoration: none; + box-sizing: border-box; +} +.tsd-navigation a.current, +.tsd-page-navigation a.current { + background: var(--color-active-menu-item); +} +.tsd-navigation a:hover, +.tsd-page-navigation a:hover { + text-decoration: underline; +} +.tsd-navigation ul, +.tsd-page-navigation ul { + margin-top: 0; + margin-bottom: 0; + padding: 0; + list-style: none; +} +.tsd-navigation li, +.tsd-page-navigation li { + padding: 0; + max-width: 100%; +} +.tsd-nested-navigation { + margin-left: 3rem; +} +.tsd-nested-navigation > li > details { + margin-left: -1.5rem; +} +.tsd-small-nested-navigation { + margin-left: 1.5rem; +} +.tsd-small-nested-navigation > li > details { + margin-left: -1.5rem; +} + +.tsd-nested-navigation > li > a, +.tsd-nested-navigation > li > span { + width: calc(100% - 1.75rem - 0.5rem); +} + +.tsd-page-navigation ul { + padding-left: 1.75rem; +} + +#tsd-sidebar-links a { + margin-top: 0; + margin-bottom: 0.5rem; + line-height: 1.25rem; +} +#tsd-sidebar-links a:last-of-type { + margin-bottom: 0; +} + +a.tsd-index-link { + padding: 0.25rem 0 !important; + font-size: 1rem; + line-height: 1.25rem; + display: inline-flex; + align-items: center; + color: var(--color-text); +} +.tsd-accordion-summary { + list-style-type: none; /* hide marker on non-safari */ + outline: none; /* broken on safari, so just hide it */ +} +.tsd-accordion-summary::-webkit-details-marker { + display: none; /* hide marker on safari */ +} +.tsd-accordion-summary, +.tsd-accordion-summary a { + user-select: none; + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + + cursor: pointer; +} +.tsd-accordion-summary a { + width: calc(100% - 1.5rem); +} +.tsd-accordion-summary > * { + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; +} +.tsd-index-accordion .tsd-accordion-summary > svg { + margin-left: 0.25rem; +} +.tsd-index-content > :not(:first-child) { + margin-top: 0.75rem; +} +.tsd-index-heading { + margin-top: 1.5rem; + margin-bottom: 0.75rem; +} + +.tsd-kind-icon { + margin-right: 0.5rem; + width: 1.25rem; + height: 1.25rem; + min-width: 1.25rem; + min-height: 1.25rem; +} +.tsd-kind-icon path { + transform-origin: center; + transform: scale(1.1); +} +.tsd-signature > .tsd-kind-icon { + margin-right: 0.8rem; +} + +.tsd-panel { + margin-bottom: 2.5rem; +} +.tsd-panel.tsd-member { + margin-bottom: 4rem; +} +.tsd-panel:empty { + display: none; +} +.tsd-panel > h1, +.tsd-panel > h2, +.tsd-panel > h3 { + margin: 1.5rem -1.5rem 0.75rem -1.5rem; + padding: 0 1.5rem 0.75rem 1.5rem; +} +.tsd-panel > h1.tsd-before-signature, +.tsd-panel > h2.tsd-before-signature, +.tsd-panel > h3.tsd-before-signature { + margin-bottom: 0; + border-bottom: none; +} + +.tsd-panel-group { + margin: 4rem 0; +} +.tsd-panel-group.tsd-index-group { + margin: 2rem 0; +} +.tsd-panel-group.tsd-index-group details { + margin: 2rem 0; +} + +#tsd-search { + transition: background-color 0.2s; +} +#tsd-search .title { + position: relative; + z-index: 2; +} +#tsd-search .field { + position: absolute; + left: 0; + top: 0; + right: 2.5rem; + height: 100%; +} +#tsd-search .field input { + box-sizing: border-box; + position: relative; + top: -50px; + z-index: 1; + width: 100%; + padding: 0 10px; + opacity: 0; + outline: 0; + border: 0; + background: transparent; + color: var(--color-text); +} +#tsd-search .field label { + position: absolute; + overflow: hidden; + right: -40px; +} +#tsd-search .field input, +#tsd-search .title, +#tsd-toolbar-links a { + transition: opacity 0.2s; +} +#tsd-search .results { + position: absolute; + visibility: hidden; + top: 40px; + width: 100%; + margin: 0; + padding: 0; + list-style: none; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.25); +} +#tsd-search .results li { + background-color: var(--color-background); + line-height: initial; + padding: 4px; +} +#tsd-search .results li:nth-child(even) { + background-color: var(--color-background-secondary); +} +#tsd-search .results li.state { + display: none; +} +#tsd-search .results li.current:not(.no-results), +#tsd-search .results li:hover:not(.no-results) { + background-color: var(--color-accent); +} +#tsd-search .results a { + display: flex; + align-items: center; + padding: 0.25rem; + box-sizing: border-box; +} +#tsd-search .results a:before { + top: 10px; +} +#tsd-search .results span.parent { + color: var(--color-text-aside); + font-weight: normal; +} +#tsd-search.has-focus { + background-color: var(--color-accent); +} +#tsd-search.has-focus .field input { + top: 0; + opacity: 1; +} +#tsd-search.has-focus .title, +#tsd-search.has-focus #tsd-toolbar-links a { + z-index: 0; + opacity: 0; +} +#tsd-search.has-focus .results { + visibility: visible; +} +#tsd-search.loading .results li.state.loading { + display: block; +} +#tsd-search.failure .results li.state.failure { + display: block; +} + +#tsd-toolbar-links { + position: absolute; + top: 0; + right: 2rem; + height: 100%; + display: flex; + align-items: center; + justify-content: flex-end; +} +#tsd-toolbar-links a { + margin-left: 1.5rem; +} +#tsd-toolbar-links a:hover { + text-decoration: underline; +} + +.tsd-signature { + margin: 0 0 1rem 0; + padding: 1rem 0.5rem; + border: 1px solid var(--color-accent); + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + font-size: 14px; + overflow-x: auto; +} + +.tsd-signature-symbol { + color: var(--color-text-aside); + font-weight: normal; +} + +.tsd-signature-type { + font-style: italic; + font-weight: normal; +} + +.tsd-signatures { + padding: 0; + margin: 0 0 1em 0; + list-style-type: none; +} +.tsd-signatures .tsd-signature { + margin: 0; + border-color: var(--color-accent); + border-width: 1px 0; + transition: background-color 0.1s; +} +.tsd-description .tsd-signatures .tsd-signature { + border-width: 1px; +} + +ul.tsd-parameter-list, +ul.tsd-type-parameter-list { + list-style: square; + margin: 0; + padding-left: 20px; +} +ul.tsd-parameter-list > li.tsd-parameter-signature, +ul.tsd-type-parameter-list > li.tsd-parameter-signature { + list-style: none; + margin-left: -20px; +} +ul.tsd-parameter-list h5, +ul.tsd-type-parameter-list h5 { + font-size: 16px; + margin: 1em 0 0.5em 0; +} +.tsd-sources { + margin-top: 1rem; + font-size: 0.875em; +} +.tsd-sources a { + color: var(--color-text-aside); + text-decoration: underline; +} +.tsd-sources ul { + list-style: none; + padding: 0; +} + +.tsd-page-toolbar { + position: sticky; + z-index: 1; + top: 0; + left: 0; + width: 100%; + color: var(--color-text); + background: var(--color-background-secondary); + border-bottom: 1px var(--color-accent) solid; + transition: transform 0.3s ease-in-out; +} +.tsd-page-toolbar a { + color: var(--color-text); + text-decoration: none; +} +.tsd-page-toolbar a.title { + font-weight: bold; +} +.tsd-page-toolbar a.title:hover { + text-decoration: underline; +} +.tsd-page-toolbar .tsd-toolbar-contents { + display: flex; + justify-content: space-between; + height: 2.5rem; + margin: 0 auto; +} +.tsd-page-toolbar .table-cell { + position: relative; + white-space: nowrap; + line-height: 40px; +} +.tsd-page-toolbar .table-cell:first-child { + width: 100%; +} +.tsd-page-toolbar .tsd-toolbar-icon { + box-sizing: border-box; + line-height: 0; + padding: 12px 0; +} + +.tsd-widget { + display: inline-block; + overflow: hidden; + opacity: 0.8; + height: 40px; + transition: + opacity 0.1s, + background-color 0.2s; + vertical-align: bottom; + cursor: pointer; +} +.tsd-widget:hover { + opacity: 0.9; +} +.tsd-widget.active { + opacity: 1; + background-color: var(--color-accent); +} +.tsd-widget.no-caption { + width: 40px; +} +.tsd-widget.no-caption:before { + margin: 0; +} + +.tsd-widget.options, +.tsd-widget.menu { + display: none; +} +input[type="checkbox"] + .tsd-widget:before { + background-position: -120px 0; +} +input[type="checkbox"]:checked + .tsd-widget:before { + background-position: -160px 0; +} + +img { + max-width: 100%; +} + +.tsd-anchor-icon { + display: inline-flex; + align-items: center; + margin-left: 0.5rem; + vertical-align: middle; + color: var(--color-text); +} + +.tsd-anchor-icon svg { + width: 1em; + height: 1em; + visibility: hidden; +} + +.tsd-anchor-link:hover > .tsd-anchor-icon svg { + visibility: visible; +} + +.deprecated { + text-decoration: line-through !important; +} + +.warning { + padding: 1rem; + color: var(--color-warning-text); + background: var(--color-background-warning); +} + +.tsd-kind-project { + color: var(--color-ts-project); +} +.tsd-kind-module { + color: var(--color-ts-module); +} +.tsd-kind-namespace { + color: var(--color-ts-namespace); +} +.tsd-kind-enum { + color: var(--color-ts-enum); +} +.tsd-kind-enum-member { + color: var(--color-ts-enum-member); +} +.tsd-kind-variable { + color: var(--color-ts-variable); +} +.tsd-kind-function { + color: var(--color-ts-function); +} +.tsd-kind-class { + color: var(--color-ts-class); +} +.tsd-kind-interface { + color: var(--color-ts-interface); +} +.tsd-kind-constructor { + color: var(--color-ts-constructor); +} +.tsd-kind-property { + color: var(--color-ts-property); +} +.tsd-kind-method { + color: var(--color-ts-method); +} +.tsd-kind-call-signature { + color: var(--color-ts-call-signature); +} +.tsd-kind-index-signature { + color: var(--color-ts-index-signature); +} +.tsd-kind-constructor-signature { + color: var(--color-ts-constructor-signature); +} +.tsd-kind-parameter { + color: var(--color-ts-parameter); +} +.tsd-kind-type-literal { + color: var(--color-ts-type-literal); +} +.tsd-kind-type-parameter { + color: var(--color-ts-type-parameter); +} +.tsd-kind-accessor { + color: var(--color-ts-accessor); +} +.tsd-kind-get-signature { + color: var(--color-ts-get-signature); +} +.tsd-kind-set-signature { + color: var(--color-ts-set-signature); +} +.tsd-kind-type-alias { + color: var(--color-ts-type-alias); +} + +/* if we have a kind icon, don't color the text by kind */ +.tsd-kind-icon ~ span { + color: var(--color-text); +} + +* { + scrollbar-width: thin; + scrollbar-color: var(--color-accent) var(--color-icon-background); +} + +*::-webkit-scrollbar { + width: 0.75rem; +} + +*::-webkit-scrollbar-track { + background: var(--color-icon-background); +} + +*::-webkit-scrollbar-thumb { + background-color: var(--color-accent); + border-radius: 999rem; + border: 0.25rem solid var(--color-icon-background); +} + +/* mobile */ +@media (max-width: 769px) { + .tsd-widget.options, + .tsd-widget.menu { + display: inline-block; + } + + .container-main { + display: flex; + } + html .col-content { + float: none; + max-width: 100%; + width: 100%; + } + html .col-sidebar { + position: fixed !important; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + z-index: 1024; + top: 0 !important; + bottom: 0 !important; + left: auto !important; + right: 0 !important; + padding: 1.5rem 1.5rem 0 0; + width: 75vw; + visibility: hidden; + background-color: var(--color-background); + transform: translate(100%, 0); + } + html .col-sidebar > *:last-child { + padding-bottom: 20px; + } + html .overlay { + content: ""; + display: block; + position: fixed; + z-index: 1023; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.75); + visibility: hidden; + } + + .to-has-menu .overlay { + animation: fade-in 0.4s; + } + + .to-has-menu .col-sidebar { + animation: pop-in-from-right 0.4s; + } + + .from-has-menu .overlay { + animation: fade-out 0.4s; + } + + .from-has-menu .col-sidebar { + animation: pop-out-to-right 0.4s; + } + + .has-menu body { + overflow: hidden; + } + .has-menu .overlay { + visibility: visible; + } + .has-menu .col-sidebar { + visibility: visible; + transform: translate(0, 0); + display: flex; + flex-direction: column; + gap: 1.5rem; + max-height: 100vh; + padding: 1rem 2rem; + } + .has-menu .tsd-navigation { + max-height: 100%; + } +} + +/* one sidebar */ +@media (min-width: 770px) { + .container-main { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); + grid-template-areas: "sidebar content"; + margin: 2rem auto; + } + + .col-sidebar { + grid-area: sidebar; + } + .col-content { + grid-area: content; + padding: 0 1rem; + } +} +@media (min-width: 770px) and (max-width: 1399px) { + .col-sidebar { + max-height: calc(100vh - 2rem - 42px); + overflow: auto; + position: sticky; + top: 42px; + padding-top: 1rem; + } + .site-menu { + margin-top: 1rem; + } +} + +/* two sidebars */ +@media (min-width: 1200px) { + .container-main { + grid-template-columns: minmax(0, 1fr) minmax(0, 2.5fr) minmax(0, 20rem); + grid-template-areas: "sidebar content toc"; + } + + .col-sidebar { + display: contents; + } + + .page-menu { + grid-area: toc; + padding-left: 1rem; + } + .site-menu { + grid-area: sidebar; + } + + .site-menu { + margin-top: 1rem 0; + } + + .page-menu, + .site-menu { + max-height: calc(100vh - 2rem - 42px); + overflow: auto; + position: sticky; + top: 42px; + } +} diff --git a/docs/typedocs/classes/GenUtils.html b/docs/typedocs/classes/GenUtils.html new file mode 100644 index 000000000..35b4a9bbe --- /dev/null +++ b/docs/typedocs/classes/GenUtils.html @@ -0,0 +1,2232 @@ +GenUtils | monero-ts
+
+ +
+
+
+
+ +

Class GenUtils

+
+

Collection of general purpose utilities.

+
+
+
+

Hierarchy

+
    +
  • GenUtils
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Methods

+
+ +
    + +
  • +

    Get the absolute value of the given bigint or number.

    +
    +
    +

    Parameters

    +
      +
    • +
      bi: number | bigint
      +

      the bigint or number to get the absolute value of

      +
      +
    +

    Returns number | bigint

    the absolute value of the given bigint or number

    + +
+
+ +
    + +
  • +

    Indicates if the given array contains the given object.

    +
    +
    +

    Parameters

    +
      +
    • +
      arr: any
      +

      array that may or may not contain the object

      +
      +
    • +
    • +
      obj: any
      +

      object to check for inclusion in the array

      +
      +
    • +
    • +
      Optional compareByReference: boolean = false
      +

      compare strictly by reference, forgoing deep equality check (default false)

      +
      +
    +

    Returns boolean

    true if the array contains the object, false otherwise

    + +
+
+ +
    + +
  • +

    Determines if two arrays are equal.

    +
    +
    +

    Parameters

    +
      +
    • +
      arr1: any
      +

      is an array to compare

      +
      +
    • +
    • +
      arr2: any
      +

      is an array to compare

      +
      +
    +

    Returns boolean

    true if the arrays are equal, false otherwise

    + +
+
+ +
    + +
  • +

    Asserts that the given argument is an array.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to assert as an array

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if the argument is not an array

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is base58.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
    • +
    • +
      msg: any
      +

      is the message to throw if the argument is not base58

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is base64.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
    • +
    • +
      msg: any
      +

      is the message to throw if the argument is not base64

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is a boolean.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to assert as a boolean

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if the argument is not a boolean

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is defined. Throws an exception if undefined.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to assert defined

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if arg is undefined (optional)

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given arguments are equal. Throws an exception if not equal.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg1: any
      +

      is an argument to assert as equal

      +
      +
    • +
    • +
      arg2: any
      +

      is an argument to assert as equal

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if the arguments are not equal

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given boolean is false. Throws an exception if not a boolean or true.

    +
    +
    +

    Parameters

    +
      +
    • +
      bool: any
      +

      is the boolean to assert false

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if bool is true (optional)

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is a static.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to assert as a static

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if the argument is not a static

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is hex.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
    • +
    • +
      msg: any
      +

      is the message to throw if the argument is not hex

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is initialized. Throws an exception if not initialized.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to assert as initialized

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if arg is not initialized (optional)

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is an integer.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to assert as an integer

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if the argument is not an integer

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given arguments are not equal. Throws an exception if equal.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg1: any
      +

      is an argument to assert as not equal

      +
      +
    • +
    • +
      arg2: any
      +

      is an argument to assert as not equal

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if the arguments are equal

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is not null. Throws an exception if null.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to assert not null

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if arg is null (optional)

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is null. Throws an exception if not null.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to assert null

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if arg is not null (optional)

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is a number.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to assert as a number

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if the argument is not a number

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is an object with the given name.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to test

      +
      +
    • +
    • +
      obj: any
      +

      is an object to assert arg instanceof obj (optional)

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if the argument is not the specified object

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is a string.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to assert as a string

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if the argument is not a string

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given condition is true. Throws an exception if not a boolean or false.

    +
    +
    +

    Parameters

    +
      +
    • +
      condition: any
      +

      is the boolean to assert true

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if condition is false (optional)

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is undefined. Throws an exception if defined.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to assert undefined

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if arg is defined (optional)

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Asserts that the given argument is uninitialized. Throws an exception if initialized.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to assert as uninitialized

      +
      +
    • +
    • +
      Optional msg: any
      +

      is the message to throw if arg is initialized (optional)

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Manually builds an HTML document string.

    +
    +
    +

    Parameters

    +
      +
    • +
      content: any
      +

      specifies optional document content + content.div is a pre-existing div to stringify and add to the body + content.title is the title of the new tab + content.dependencyPaths specifies paths to js, css, or img paths + content.internalCss is css to embed in the html document + content.metas are meta elements with keys/values to include

      +
      +
    +

    Returns string

    str is the document string

    + +
+
+ +
    + +
  • +

    Copies the given array.

    +
    +
    +

    Parameters

    +
      +
    • +
      arr: any
      +

      is the array to copy

      +
      +
    +

    Returns any[]

    a copy of the given array

    + +
+
+ +
    + +
  • +

    Copies properties in the given object to a new object.

    +
    +
    +

    Parameters

    +
      +
    • +
      obj: any
      +

      is object to copy properties for

      +
      +
    +

    Returns any

    a new object with properties copied from the given object

    + +
+
+ +
    + +
  • +

    Counts the number of non-whitespace characters in the given string.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
      +

      is the string to count the number of non-whitespace characters in

      +
      +
    +

    Returns number

    int is the number of non-whitespace characters in the given string

    + +
+
+ +
    + +
  • +

    Deletes all properties in the given object.

    +
    +
    +

    Parameters

    +
      +
    • +
      obj: any
      +

      is the object to delete properties from

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Deletes properties from the object that are undefined.

    +
    +
    +

    Parameters

    +
      +
    • +
      obj: any
      +

      is the object to delete undefined keys from

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Determines if two arguments are deep equal.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg1: any
      +

      is an argument to compare

      +
      +
    • +
    • +
      arg2: any
      +

      is an argument to compare

      +
      +
    +

    Returns boolean

    true if the arguments are deep equals, false otherwise

    + +
+
+ +
    + +
  • +

    Resolve the given promise with a timeout.

    +
    +
    +

    Parameters

    +
      +
    • +
      promise: any
      +

      the promise to resolve within the timeout

      +
      +
    • +
    • +
      timeoutMs: any
      +

      the timeout in milliseconds to resolve the promise

      +
      +
    +

    Returns Promise<any>

    the result of the promise unless error thrown

    + +
+
+ +
    + +
  • +

    Throws an exception with the given message.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional msg: any
      +

      defines the message to throw the exception with (optional)

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Returns combinations of the given array of the given size.

    +
    +
    +

    Parameters

    +
      +
    • +
      arr: any
      +

      is the array to get combinations from

      +
      +
    • +
    • +
      combinationSize: any
      +

      specifies the size of each combination

      +
      +
    +

    Returns any[]

    +
+
+ +
    + +
  • +

    Gets an 'a' element that is downloadable when clicked.

    +
    +
    +

    Parameters

    +
      +
    • +
      name: any
      +

      is the name of the file to download

      +
      +
    • +
    • +
      contents: any
      +

      are the string contents of the file to download

      +
      +
    +

    Returns HTMLAnchorElement

    'a' dom element with downloadable file

    + +
+
+ +
    + +
  • +

    Get an enum key name by value.

    +
    +
    +

    Parameters

    +
      +
    • +
      enumType: any
      +

      is the enum type to get the key from

      +
      +
    • +
    • +
      enumValue: any
      +

      is the enum value to get the key for

      +
      +
    +

    Returns string

    the enum key name

    + +
+
+ +
+
+ +
    + +
  • +

    Fetches the given list of images.

    +

    Prerequisite: async.js.

    +
    +
    +

    Parameters

    +
      +
    • +
      paths: any
      +

      are the paths to the images to fetch

      +
      +
    • +
    • +
      onDone: any
    +

    Returns void

    +
+
+ +
    + +
  • +

    Returns a string indentation of the given length;

    +
    +
    +

    Parameters

    +
      +
    • +
      length: any
      +

      is the length of the indentation

      +
      +
    +

    Returns string

    is an indentation string of the given length

    + +
+
+ +
    + +
  • +

    Returns an array of indices of the given size.

    +
    +
    +

    Parameters

    +
      +
    • +
      size: any
      +

      specifies the size to get indices for

      +
      +
    +

    Returns any[]

    array of the given size with indices starting at 0

    + +
+
+ +
    + +
  • +

    Returns the document's first stylesheet which has no href.

    +
    +

    Returns CSSStyleSheet

    StyleSheet is the internal stylesheet

    + +
+
+ +
    + +
  • +

    Returns the document's internal stylesheet as text.

    +
    +

    Returns string

    str is the document's internal stylesheet

    + +
+
+ +
    + +
  • +

    Returns lines separated by newlines from the given string.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
      +

      is the string to get lines from

      +
      +
    +

    Returns any

    +
+
+ +
+
+ +
    + +
  • +

    Returns the power set of the given array.

    +
    +
    +

    Parameters

    +
      +
    • +
      arr: any
      +

      is the array to get the power set of

      +
      +
    +

    Returns any[]

    [][] is the power set of the given array

    + +
+
+ +
    + +
  • +

    Returns the power set of the given array whose elements are the given size.

    +
    +
    +

    Parameters

    +
      +
    • +
      arr: any
      +

      is the array to get the power set of

      +
      +
    • +
    • +
      size: any
      +

      is the required size of the elements within the power set +returns [][] is the power set of the given array whose elements are the given size

      +
      +
    +

    Returns any[]

    +
+
+ +
+
+ +
    + +
  • +

    Gets random ints.

    +
    +
    +

    Parameters

    +
      +
    • +
      min: any
      +

      is the minimum range of the ints to generate, inclusive

      +
      +
    • +
    • +
      max: any
      +

      is the maximum range of the ints to generate, inclusive

      +
      +
    • +
    • +
      count: any
      +

      is the number of random ints to get

      +
      +
    +

    Returns any[]

    +
+
+ +
+
+ +
    + +
  • +

    Gets a given number of unique random ints within a range.

    +
    +
    +

    Parameters

    +
      +
    • +
      min: any
      +

      is the minimum range of the ints to generate, inclusive

      +
      +
    • +
    • +
      max: any
      +

      is the maximum range of the ints to generate, inclusive

      +
      +
    • +
    • +
      count: any
      +

      is the number of unique random ints to get

      +
      +
    +

    Returns any[]

    +
+
+ +
    + +
  • +

    Returns tokens separated by whitespace from the given string.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
      +

      is the string to get tokens from

      +
      +
    +

    Returns any

    string[] are the tokens separated by whitespace within the string

    + +
+
+ +
    + +
  • +

    Indicates if the given string contains whitespace.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
      +

      is the string to test

      +
      +
    +

    Returns boolean

    true if the string contains whitespace, false otherwise

    + +
+
+ +
    + +
  • +

    Converts the given image to a base64 encoded data url.

    +
    +
    +

    Parameters

    +
      +
    • +
      img: any
      +

      is the image to convert

      +
      +
    • +
    • +
      quality: any
      +

      is a number between 0 and 1 specifying the image quality

      +
      +
    +

    Returns string

    +
+
+ +
    + +
  • +

    Sets the child's prototype to the parent's prototype.

    +
    +
    +

    Parameters

    +
      +
    • +
      child: any
      +

      is the child class

      +
      +
    • +
    • +
      parent: any
      +

      is the parent class

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Returns void

+
+ +
    + +
  • +

    Invokes functions with arguments.

    +

    arguments[0] is assumed to be an array of functions to invoke +arguments[1...n] are args to invoke the functions with

    +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Indicates if the given argument is an array.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to test as being an array

      +
      +
    +

    Returns boolean

    true if the argument is an array, false otherwise

    + +
+
+ +
    + +
  • +

    Determines if the given string is base32.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
    +

    Returns boolean

    +
+
+ +
    + +
  • +

    Determines if the given string is base58.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
    +

    Returns boolean

    +
+
+ +
    + +
  • +

    Determines if the given string is base64.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
    +

    Returns boolean

    +
+
+ +
    + +
  • +

    Determines if the given argument is a boolean.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to test as being a boolean

      +
      +
    +

    Returns boolean

    true if the argument is a boolean, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the current environment is a browser.

    +
    +

    Returns boolean

    true if the environment is a browser, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the given argument is defined.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the arg to test

      +
      +
    +

    Returns boolean

    true if the given arg is defined, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the current environment is Deno

    +
    +

    Returns boolean

    true if the environment is Deno, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the current environment is a firefox-based browser.

    +
    +

    Returns boolean

    true if the environment is a firefox-based browser, false otherwise

    + +
+
+ +
    + +
  • +

    Determines if the given argument is a static.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to test as being a static

      +
      +
    +

    Returns boolean

    true if the argument is a static, false otherwise

    + +
+
+ +
+
+ +
    + +
  • +

    Determines if the image at the given URL is accessible.

    +
    +
    +

    Parameters

    +
      +
    • +
      url: any
      +

      is the url to an image

      +
      +
    • +
    • +
      timeout: any
      +

      is the maximum time to wait

      +
      +
    • +
    • +
      onDone: any
    +

    Returns void

    +
+
+ +
    + +
  • +

    Indicates if the given arg is initialized.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the arg to test

      +
      +
    +

    Returns boolean

    true if the given arg is initialized, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the given argument is an integer.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to test

      +
      +
    +

    Returns boolean

    true if the given argument is an integer, false otherwise

    + +
+
+ +
    + +
  • +

    Determines if the given file is a json file.

    +
    +
    +

    Parameters

    +
      +
    • +
      file: any
      +

      is a file

      +
      +
    +

    Returns any

    true if the given file is a json file, false otherwise

    + +
+
+ +
    + +
  • +

    Determines if all alphabet characters in the given string are lower case.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
      +

      is the string to test

      +
      +
    +

    Returns boolean

    +
+
+ +
    + +
  • +

    Indicates if the given character is a newline.

    +
    +
    +

    Parameters

    +
      +
    • +
      char: any
      +

      is the character to test

      +
      +
    +

    Returns boolean

    true if the given character is a newline, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the given argument is a number.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to test

      +
      +
    +

    Returns boolean

    true if the argument is a number, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the given argument is an object and optionally if it has the given constructor name.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to test

      +
      +
    • +
    • +
      Optional obj: any
      +

      is an object to test arg instanceof obj (optional)

      +
      +
    +

    Returns boolean

    true if the given argument is an object and optionally has the given constructor name

    + +
+
+ +
    + +
  • +

    Indicates if the given argument is a string.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the argument to test as being a string

      +
      +
    +

    Returns boolean

    true if the argument is a string, false otherwise

    + +
+
+ +
    + +
  • +

    Determines if the given file is a txt file.

    +
    +
    +

    Parameters

    +
      +
    • +
      file: any
      +

      is a file

      +
      +
    +

    Returns any

    true if the given file is a txt file, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the given argument is undefined.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the arg to test

      +
      +
    +

    Returns boolean

    true if the given arg is undefined, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the given arg is uninitialized.

    +
    +
    +

    Parameters

    +
      +
    • +
      arg: any
      +

      is the arg to test

      +
      +
    +

    Returns boolean

    true if the given arg is uninitialized, false otherwise

    + +
+
+ +
    + +
  • +

    Determines if all alphabet characters in the given string are upper case.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: string
      +

      is the string to test

      +
      +
    +

    Returns boolean

    true if the string is upper case, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the given character is whitespace.

    +
    +
    +

    Parameters

    +
      +
    • +
      char: any
      +

      is the character to test

      +
      +
    +

    Returns boolean

    true if the given character is whitespace, false otherwise

    + +
+
+ +
    + +
  • +

    Determines if the given file is a zip file.

    +
    +
    +

    Parameters

    +
      +
    • +
      file: any
      +

      is a file

      +
      +
    +

    Returns any

    true if the given file is a zip file, false otherwise

    + +
+
+ +
    + +
  • +

    Kill the given nodejs child process.

    +
    +
    +

    Parameters

    +
      +
    • +
      process: ChildProcess
      +

      the nodejs child process to kill

      +
      +
    • +
    • +
      Optional signal: number | Signals
      +

      the kill signal, e.g. SIGTERM, SIGKILL, SIGINT (default)

      +
      +
    +

    Returns Promise<number>

    the exit code from killing the process

    + +
+
+ +
    + +
  • +

    Returns a human-friendly key value line.

    +
    +
    +

    Parameters

    +
      +
    • +
      key: any
      +

      is the key

      +
      +
    • +
    • +
      value: any
      +

      is the value

      +
      +
    • +
    • +
      indent: number = 0
      +

      indents the line

      +
      +
    • +
    • +
      newline: boolean = true
      +

      specifies if the string should be terminated with a newline or not

      +
      +
    • +
    • +
      ignoreUndefined: boolean = true
      +

      specifies if undefined values should return an empty string

      +
      +
    +

    Returns string

    is the human-friendly key value line

    + +
+
+ +
    + +
  • +

    Listifies the given argument.

    +
    +
    +

    Parameters

    +
      +
    • +
      arrOrElem: any
      +

      is an array or an element in the array

      +
      +
    +

    Returns any

    an array which is the given arg if it's an array or an array with the given arg as an element

    + +
+
+ +
    + +
  • +

    Opens the given div in a new window.

    +
    +
    +

    Parameters

    +
      +
    • +
      content: any
      +

      specifies optional window content + content.div is a pre-existing div to stringify and add to the body + content.title is the title of the new tab + content.dependencyPaths specifies paths to js, css, or img paths + content.internalCss is css to embed in the html document + content.metas are meta elements with keys/values to include

      +
      +
    • +
    • +
      onLoad: any
    +

    Returns void

    +
+
+ +
    + +
  • +

    Normalize a URI.

    +
    +
    +

    Parameters

    +
      +
    • +
      uri: any
      +

      the URI to normalize

      +
      +
    +

    Returns any

    the normalized URI

    + +
+
+ +
    + +
  • +

    Determines if two objects are deep equal.

    +

    Undefined values are considered equal to non-existent keys.

    +
    +
    +

    Parameters

    +
      +
    • +
      map1: any
      +

      is a map to compare

      +
      +
    • +
    • +
      map2: any
      +

      is a map to compare

      +
      +
    +

    Returns boolean

    true if the maps have identical keys and values, false otherwise

    + +
+
+ +
    + +
  • +

    Print the current stack trace.

    +
    +
    +

    Parameters

    +
      +
    • +
      msg: any
      +

      optional message to print with the trace

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Reconciles two values.

    +

    TODO: remove custom error message

    +
    +
    +

    Parameters

    +
      +
    • +
      val1: any
      +

      is a value to reconcile

      +
      +
    • +
    • +
      val2: any
      +

      is a value to reconcile

      +
      +
    • +
    • +
      Optional config: any
      +

      specifies reconciliation configuration + config.resolveDefined uses defined value if true or undefined, undefined if false + config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined + config.resolveMax uses max over min if true, min over max if false, must be equal if undefined

      +
      +
    • +
    • +
      Optional errMsg: any
      +

      is the error message to throw if the values cannot be reconciled (optional)

      +
      +
    +

    Returns any

    the reconciled value if reconcilable, throws error otherwise

    + +
+
+ +
    + +
  • +

    Removes every instance of the given value from the given array.

    +
    +
    +

    Parameters

    +
      +
    • +
      arr: any
      +

      is the array to remove the value from

      +
      +
    • +
    • +
      val: any
      +

      is the value to remove from the array

      +
      +
    +

    Returns boolean

    true if the value is found and removed, false otherwise

    + +
+
+ +
    + +
  • +

    Sets the given value ensuring a previous value is not overwritten.

    +

    TODO: remove for portability because function passing not supported in other languages, use reconcile only

    +
    +
    +

    Parameters

    +
      +
    • +
      obj: any
      +

      is the object to invoke the getter and setter on

      +
      +
    • +
    • +
      getFn: any
      +

      gets the current value

      +
      +
    • +
    • +
      setFn: any
      +

      sets the current value

      +
      +
    • +
    • +
      val: any
      +

      is the value to set iff it does not overwrite a previous value

      +
      +
    • +
    • +
      Optional config: any
      +

      specifies reconciliation configuration + config.resolveDefined uses defined value if true or undefined, undefined if false + config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined + config.resolveMax uses max over min if true, min over max if false, must be equal if undefined

      +
      +
    • +
    • +
      Optional errMsg: any
      +

      is the error message to throw if the values cannot be reconciled (optional)

      +
      +
    +

    Returns void

    +
+
+ +
+
+ +
    + +
  • +

    Sorts an array by natural ordering.

    +
    +
    +

    Parameters

    +
      +
    • +
      array: any
    +

    Returns void

    +
+
+ +
    + +
  • +

    Indicates if the given string contains the given substring.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
      +

      is the string to search for a substring

      +
      +
    • +
    • +
      substring: any
      +

      is the substring to searchin within the string

      +
      +
    +

    Returns boolean

    true if the substring is within the string, false otherwise

    + +
+
+ +
    + +
  • +

    Replace big integers (16 or more consecutive digits) with strings in order +to preserve numeric precision.

    +
    +
    +

    Parameters

    +
      +
    • +
      str: any
      +

      is the string to be modified

      +
      +
    +

    Returns any

    the modified string with big numbers converted to strings

    + +
+
+ +
    + +
  • +

    Returns a copy of the given array where each element is lowercase.

    +
    +
    +

    Parameters

    +
      +
    • +
      arr: any
      +

      is the array to convert to lowercase

      +
      +
    +

    Returns any[]

    a copy of the given array where each element is lowercase

    + +
+
+ +
    + +
  • +

    Returns a new array containing unique elements of the given array.

    +
    +
    +

    Parameters

    +
      +
    • +
      arr: any
      +

      is the array to return unique elements from

      +
      +
    +

    Returns any

    a new array with the given array's unique elements

    + +
+
+ +
    + +
  • +

    Wait for the duration.

    +
    +
    +

    Parameters

    +
      +
    • +
      durationMs: any
      +

      the duration to wait for in milliseconds

      +
      +
    +

    Returns Promise<unknown>

    +
+
+ +
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/HttpClient.html b/docs/typedocs/classes/HttpClient.html new file mode 100644 index 000000000..cd08c0ddb --- /dev/null +++ b/docs/typedocs/classes/HttpClient.html @@ -0,0 +1,230 @@ +HttpClient | monero-ts
+
+ +
+
+
+
+ +

Class HttpClient

+
+

Handle HTTP requests with a uniform interface.

+
+
+
+

Hierarchy

+
    +
  • HttpClient
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
DEFAULT_REQUEST: {
    method: string;
    rejectUnauthorized: boolean;
    resolveWithFullResponse: boolean;
} = ...
+
+

Type declaration

+
    +
  • +
    method: string
  • +
  • +
    rejectUnauthorized: boolean
  • +
  • +
    resolveWithFullResponse: boolean
+
+ +
DEFAULT_TIMEOUT: number = 60000
+
+ +
HTTPS_AGENT: any
+
+ +
HTTP_AGENT: any
+
+ +
MAX_REQUESTS_PER_SECOND: number = 50
+
+ +
MAX_TIMEOUT: number = 2147483647
+
+ +
PROMISE_THROTTLES: any[] = []
+
+ +
TASK_QUEUES: any[] = []
+
+ +
axiosDigestAuthRequest: ((method, url, username, password, body) => Promise<AxiosResponse<any, any>>) = ...
+
+

Type declaration

+
    +
  • +
      +
    • (method, url, username, password, body): Promise<AxiosResponse<any, any>>
    • +
    • +
      +

      Parameters

      +
        +
      • +
        method: any
      • +
      • +
        url: any
      • +
      • +
        username: any
      • +
      • +
        password: any
      • +
      • +
        body: any
      +

      Returns Promise<AxiosResponse<any, any>>

+
+

Methods

+
+ +
    + +
  • +

    Get a singleton instance of an HTTP client to share.

    +
    +

    Returns any

    a shared agent for network requests among library instances

    + +
+
+ +
    + +
  • +

    Get a singleton instance of an HTTPS client to share.

    +
    +

    Returns any

    a shared agent for network requests among library instances

    + +
+
+ +
    + +
  • +

    Make a HTTP request.

    +
    +

    Parameters

    +
      +
    • +
      request: any
      +

      configures the request to make

      +
      +
    +

    Returns Promise<any>

    response - the response object

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      req: any
    +

    Returns Promise<any>

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/LibraryUtils.html b/docs/typedocs/classes/LibraryUtils.html new file mode 100644 index 000000000..95a7434ce --- /dev/null +++ b/docs/typedocs/classes/LibraryUtils.html @@ -0,0 +1,527 @@ +LibraryUtils | monero-ts
+
+ +
+
+
+
+ +

Class LibraryUtils

+
+

Collection of helper utilities for the library.

+
+
+
+

Hierarchy

+
    +
  • LibraryUtils
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
FULL_LOADED: any
+
+ +
LOG_LEVEL: number = 0
+
+ +
MUTEX: ThreadPool = ...
+
+ +
REJECT_UNAUTHORIZED_FNS: any
+
+ +
WASM_MODULE: any
+
+ +
WORKER: any
+
+ +
WORKER_DIST_PATH: string = LibraryUtils.WORKER_DIST_PATH_DEFAULT
+
+ +
WORKER_DIST_PATH_DEFAULT: string = ...
+
+ +
WORKER_LOADER?: (() => Worker) = undefined
+
+

Type declaration

+
    +
  • +
      +
    • (): Worker
    • +
    • +

      Returns Worker

+
+ +
WORKER_OBJECTS: any
+
+

Methods

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      objectId: any
    • +
    • +
      callbackId: any
    • +
    • +
      callbackArgs: any
    +

    Returns void

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      serializedErr: any
    +

    Returns Error

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      fs: any
    • +
    • +
      path: string
    +

    Returns Promise<boolean>

+
+ +
    + +
  • +

    Get the library's log level.

    +
    +

    Returns number

    the library's log level

    + +
+
+ +
    + +
  • +

    Get the total memory used by WebAssembly.

    +
    +

    Returns Promise<number>

    the total memory used by WebAssembly

    + +
+
+ +
    + +
  • +

    Get the WebAssembly module in the current context (nodejs, browser main thread or worker).

    +
    +

    Returns any

    +
+
+ +
    + +
  • +

    Get a singleton instance of a worker to share.

    +
    +

    Returns Promise<any>

    a worker to share among wallet instances

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      wasmModule: any
    +

    Returns void

+
+ +
    + +
  • +

    Invoke a worker function and get the result with error handling.

    +
    +
    +

    Parameters

    +
      +
    • +
      objectId: any
      +

      identifies the worker object to invoke (default random id)

      +
      +
    • +
    • +
      fnName: any
      +

      is the name of the function to invoke

      +
      +
    • +
    • +
      Optional args: any
      +

      are function arguments to invoke with

      +
      +
    +

    Returns Promise<unknown>

    resolves with response payload from the worker or an error

    + +
+
+ +
    + +
  • +

    Indicate if unauthorized requests should be rejected.

    +
    +
    +

    Parameters

    +
      +
    • +
      fnId: any
      +

      uniquely identifies the function

      +
      +
    +

    Returns any

    +
+
+ +
    + +
  • +

    Load the WebAssembly full module with caching.

    +

    The full module is a superset of the keys module and overrides it.

    +
    +

    Returns Promise<any>

    +
+
+ +
    + +
  • +

    Log a message.

    +
    +
    +

    Parameters

    +
      +
    • +
      level: any
      +

      log level of the message

      +
      +
    • +
    • +
      msg: any
      +

      message to log

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      path: any
    +

    Returns any

+
+ +
    + +
  • +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Parameters

    +
      +
    • +
      asyncFn: (() => Promise<T>)
      +
        +
      • +
          +
        • (): Promise<T>
        • +
        • +

          Returns Promise<T>

    +

    Returns Promise<T>

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      objectId: any
    • +
    • +
      callbackId: any
    +

    Returns void

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      objectId: any
    +

    Returns void

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      err: any
    +

    Returns any

+
+ +
    + +
  • +

    Set the library's log level with 0 being least verbose.

    +
    +
    +

    Parameters

    +
      +
    • +
      level: any
      +

      the library's log level

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Register a function by id which informs if unauthorized requests (e.g. +self-signed certificates) should be rejected.

    +
    +
    +

    Parameters

    +
      +
    • +
      fnId: any
      +

      unique identifier for the function

      +
      +
    • +
    • +
      fn: any
      +

      function to inform if unauthorized requests should be rejected

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Set the path to load the worker. Defaults to "/monero.worker.js" in the browser +and "./MoneroWebWorker.js" in node.

    +
    +
    +

    Parameters

    +
      +
    • +
      workerDistPath: any
      +

      path to load the worker

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Set the worker loader closure to customize worker loading. +Takes precedence over default loading mechanisms.

    +

    Could be as simple as () => new Worker(new URL("monero-ts/dist/monero.worker.js", import.meta.url)); for browsers.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional loader: (() => Worker)
      +

      loader function which instantiates a worker

      +
      +
      +
        +
      • +
          +
        • (): Worker
        • +
        • +

          Returns Worker

    +

    Returns void

    +
+
+ +
    + +
  • +

    Terminate monero-ts's singleton worker.

    +
    +

    Returns Promise<void>

    +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroAccount.html b/docs/typedocs/classes/MoneroAccount.html new file mode 100644 index 000000000..e2efc928b --- /dev/null +++ b/docs/typedocs/classes/MoneroAccount.html @@ -0,0 +1,307 @@ +MoneroAccount | monero-ts
+
+ +
+
+
+
+ +

Class MoneroAccount

+
+

Monero account model.

+
+
+
+

Hierarchy

+
    +
  • MoneroAccount
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
balance: bigint
+
+ +
index: number
+
+ +
label: string
+
+ +
primaryAddress: string
+
+ +
subaddresses: MoneroSubaddress[]
+
+ +
tag: string
+
+ +
unlockedBalance: bigint
+
+

Methods

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns bigint

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroAccountTag.html b/docs/typedocs/classes/MoneroAccountTag.html new file mode 100644 index 000000000..1d65d24c2 --- /dev/null +++ b/docs/typedocs/classes/MoneroAccountTag.html @@ -0,0 +1,182 @@ +MoneroAccountTag | monero-ts
+
+ +
+
+
+
+ +

Class MoneroAccountTag

+
+

Represents an account tag.

+
+
+
+

Hierarchy

+
    +
  • MoneroAccountTag
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
accountIndices: number[]
+
+ +
label: string
+
+ +
tag: string
+
+

Methods

+
+ +
    + +
  • +

    Returns number[]

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroAddressBookEntry.html b/docs/typedocs/classes/MoneroAddressBookEntry.html new file mode 100644 index 000000000..86f395c90 --- /dev/null +++ b/docs/typedocs/classes/MoneroAddressBookEntry.html @@ -0,0 +1,216 @@ +MoneroAddressBookEntry | monero-ts
+
+ +
+
+
+
+ +

Class MoneroAddressBookEntry

+
+

Monero address book entry model

+
+
+
+

Hierarchy

+
    +
  • MoneroAddressBookEntry
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
address: string
+
+ +
description: string
+
+ +
index: number
+
+ +
paymentId: string
+
+

Methods

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroAltChain.html b/docs/typedocs/classes/MoneroAltChain.html new file mode 100644 index 000000000..fe745700d --- /dev/null +++ b/docs/typedocs/classes/MoneroAltChain.html @@ -0,0 +1,242 @@ +MoneroAltChain | monero-ts
+
+ +
+
+
+
+ +

Class MoneroAltChain

+
+

Models an alternative chain seen by the node.

+
+
+
+

Hierarchy

+
    +
  • MoneroAltChain
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
blockHashes: string[]
+
+ +
difficulty: bigint
+
+ +
height: number
+
+ +
length: number
+
+ +
mainChainParentBlockHash: string
+
+

Methods

+
+ +
    + +
  • +

    Returns string[]

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      mainChainParentBlockHash: string
    +

    Returns MoneroAltChain

+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroBan.html b/docs/typedocs/classes/MoneroBan.html new file mode 100644 index 000000000..e6c799c70 --- /dev/null +++ b/docs/typedocs/classes/MoneroBan.html @@ -0,0 +1,216 @@ +MoneroBan | monero-ts
+
+ +
+
+
+
+ +

Class MoneroBan

+
+

Monero banhammer.

+
+
+
+

Hierarchy

+
    +
  • MoneroBan
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
host: string
+
+ +
ip: string
+
+ +
isBanned: boolean
+
+ +
seconds: number
+
+

Methods

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      isBanned: boolean
    +

    Returns MoneroBan

+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroBlock.html b/docs/typedocs/classes/MoneroBlock.html new file mode 100644 index 000000000..cf0ee761d --- /dev/null +++ b/docs/typedocs/classes/MoneroBlock.html @@ -0,0 +1,827 @@ +MoneroBlock | monero-ts
+
+ +
+
+
+
+ +

Class MoneroBlock

+
+

Models a Monero block in the blockchain.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
cumulativeDifficulty: bigint
+
+ +
depth: number
+
+ +
difficulty: bigint
+
+ +
hash: string
+
+ +
height: number
+
+ +
hex: string
+
+ +
longTermWeight: number
+
+ +
majorVersion: number
+
+ +
minerTx: MoneroTx
+
+ +
minerTxHash: string
+
+ +
minorVersion: number
+
+ +
nonce: number
+
+ +
numTxs: number
+
+ +
orphanStatus: boolean
+
+ +
powHash: string
+
+ +
prevHash: string
+
+ +
reward: bigint
+
+ +
size: number
+
+ +
timestamp: number
+
+ +
txHashes: string[]
+
+ +
txs: MoneroTx[]
+
+ +
weight: number
+
+ +
DeserializationType: typeof DeserializationType = DeserializationType
+
+

Methods

+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      tx: any
    • +
    • +
      Optional txType: DeserializationType
    +

    Returns MoneroTx

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Return the block's height which is the total number of blocks that have occurred before.

    +
    +

    Returns number

    the block's height

    + +
+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns string[]

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Set the block's height which is the total number of blocks that have occurred before.

    +
    +
    +

    Parameters

    +
      +
    • +
      height: number
      +

      is the block's height to set

      +
      +
    +

    Returns MoneroBlock

    a reference to this header for chaining

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      txs: any
    • +
    • +
      tx: any
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroBlockHeader.html b/docs/typedocs/classes/MoneroBlockHeader.html new file mode 100644 index 000000000..be4aacf1e --- /dev/null +++ b/docs/typedocs/classes/MoneroBlockHeader.html @@ -0,0 +1,627 @@ +MoneroBlockHeader | monero-ts
+
+ +
+
+
+
+ +

Class MoneroBlockHeader

+
+

Models a Monero block header which contains information about the block.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
cumulativeDifficulty: bigint
+
+ +
depth: number
+
+ +
difficulty: bigint
+
+ +
hash: string
+
+ +
height: number
+
+ +
longTermWeight: number
+
+ +
majorVersion: number
+
+ +
minerTxHash: string
+
+ +
minorVersion: number
+
+ +
nonce: number
+
+ +
numTxs: number
+
+ +
orphanStatus: boolean
+
+ +
powHash: string
+
+ +
prevHash: string
+
+ +
reward: bigint
+
+ +
size: number
+
+ +
timestamp: number
+
+ +
weight: number
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Return the block's height which is the total number of blocks that have occurred before.

    +
    +

    Returns number

    the block's height

    + +
+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Set the block's height which is the total number of blocks that have occurred before.

    +
    +
    +

    Parameters

    +
      +
    • +
      height: number
      +

      is the block's height to set

      +
      +
    +

    Returns MoneroBlockHeader

    a reference to this header for chaining

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroBlockTemplate.html b/docs/typedocs/classes/MoneroBlockTemplate.html new file mode 100644 index 000000000..959d9e963 --- /dev/null +++ b/docs/typedocs/classes/MoneroBlockTemplate.html @@ -0,0 +1,372 @@ +MoneroBlockTemplate | monero-ts
+
+ +
+
+
+
+ +

Class MoneroBlockTemplate

+
+

Monero block template to mine.

+
+
+
+

Hierarchy

+
    +
  • MoneroBlockTemplate
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
blockHashingBlob: string
+
+ +
blockTemplateBlob: string
+
+ +
difficulty: bigint
+
+ +
expectedReward: bigint
+
+ +
height: number
+
+ +
nextSeedHash: string
+
+ +
prevId: string
+
+ +
reservedOffset: number
+
+ +
seedHash: string
+
+ +
seedHeight: number
+
+

Methods

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroCheck.html b/docs/typedocs/classes/MoneroCheck.html new file mode 100644 index 000000000..dc93b29f5 --- /dev/null +++ b/docs/typedocs/classes/MoneroCheck.html @@ -0,0 +1,133 @@ +MoneroCheck | monero-ts
+
+ +
+
+
+
+ +

Class MoneroCheck

+
+

Base class for results from checking a transaction or reserve proof.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
isGood?: boolean
+
+

Methods

+
+ +
    + +
  • +

    Returns boolean

+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroCheckReserve.html b/docs/typedocs/classes/MoneroCheckReserve.html new file mode 100644 index 000000000..740c42bf3 --- /dev/null +++ b/docs/typedocs/classes/MoneroCheckReserve.html @@ -0,0 +1,196 @@ +MoneroCheckReserve | monero-ts
+
+ +
+
+
+
+ +

Class MoneroCheckReserve

+
+

Results from checking a reserve proof.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
isGood?: boolean
+
+ +
totalAmount: bigint
+
+ +
unconfirmedSpentAmount: bigint
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns bigint

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroCheckTx.html b/docs/typedocs/classes/MoneroCheckTx.html new file mode 100644 index 000000000..a21a10f00 --- /dev/null +++ b/docs/typedocs/classes/MoneroCheckTx.html @@ -0,0 +1,222 @@ +MoneroCheckTx | monero-ts
+
+ +
+
+
+
+ +

Class MoneroCheckTx

+
+

Results from checking a transaction key.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
inTxPool: boolean
+
+ +
isGood?: boolean
+
+ +
numConfirmations: number
+
+ +
receivedAmount: bigint
+
+

Methods

+
+ +
    + +
  • +

    Returns boolean

+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns bigint

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroConnectionManager.html b/docs/typedocs/classes/MoneroConnectionManager.html new file mode 100644 index 000000000..d040ce4e2 --- /dev/null +++ b/docs/typedocs/classes/MoneroConnectionManager.html @@ -0,0 +1,821 @@ +MoneroConnectionManager | monero-ts
+
+ +
+
+
+
+ +

Class MoneroConnectionManager

+
+

Manages a collection of prioritized connections to daemon or wallet RPC endpoints.

+ +

Example usage:

+ + +// imports
+import { MoneroRpcConnection, MoneroConnectionManager, MoneroConnectionManagerListener } from "monero-ts";
+
+// create connection manager
+let connectionManager = new MoneroConnectionManager();
+
+// add managed connections with priorities
+await connectionManager.addConnection({uri: "http://localhost:38081", priority: 1}); // use localhost as first priority
+await connectionManager.addConnection({uri: "http://example.com"}); // default priority is prioritized last
+
+// set current connection
+await connectionManager.setConnection({uri: "http://foo.bar", username: "admin", password: "password"}); // connection is added if new
+
+// check connection status
+await connectionManager.checkConnection();
+console.log("Connection manager is connected: " + connectionManager.isConnected());
+console.log("Connection is online: " + connectionManager.getConnection().getIsOnline());
+console.log("Connection is authenticated: " + connectionManager.getConnection().getIsAuthenticated());
+
+// receive notifications of any changes to current connection
+connectionManager.addListener(new class extends MoneroConnectionManagerListener {
+   async onConnectionChanged(connection) {
+     console.log("Connection changed to: " + connection);
+   }
+});
+
+// start polling for best connection every 10 seconds and automatically switch
+connectionManager.startPolling(10000);
+
+// automatically switch to best available connection if disconnected
+connectionManager.setAutoSwitch(true);
+
+// get best available connection in order of priority then response time
+let bestConnection = await connectionManager.getBestAvailableConnection();
+
+// check status of all connections
+await connectionManager.checkConnections();
+
+// get connections in order of current connection, online status from last check, priority, and name
+let connections = connectionManager.getConnections();
+
+// clear connection manager
+connectionManager.clear(); +
+
+
+

Hierarchy

+
    +
  • MoneroConnectionManager
+
+
+
+ +
+
+

Constructors

+
+ +
    + +
  • +

    Construct a connection manager.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional proxyToWorker: boolean = true
      +

      configure all connections to proxy to worker (default true)

      +
      +
    +

    Returns MoneroConnectionManager

    +
+
+

Properties

+
+ +
autoSwitch: any
+
+ +
connections: any
+
+ +
currentConnection: any
+
+ +
listeners: any
+
+ +
poller: any
+
+ +
proxyToWorker: any
+
+ +
responseTimes: any
+
+ +
timeoutMs: any
+
+ +
DEFAULT_AUTO_SWITCH: boolean = true
+
+ +
DEFAULT_POLL_PERIOD: number = 20000
+
+ +
DEFAULT_TIMEOUT: number = 5000
+
+ +
MIN_BETTER_RESPONSES: number = 3
+
+ +
PollType: {
    ALL: number;
    CURRENT: number;
    PRIORITIZED: number;
} = ...
+

Specify behavior when polling.

+

One of PRIORITIZED (poll connections in order of priority until connected; default), CURRENT (poll current connection), or ALL (poll all connections).

+
+
+

Type declaration

+
    +
  • +
    ALL: number
  • +
  • +
    CURRENT: number
  • +
  • +
    PRIORITIZED: number
+
+
+

Methods

+
+ +
    + +
  • +

    Add a connection. The connection may have an elevated priority for this manager to use.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<MoneroConnectionManager>

    this connection manager for chaining

    + +
+
+ +
+
+ +
    + +
  • +

    Check the current connection. If disconnected and auto switch enabled, switches to best available connection.

    +
    +

    Returns Promise<MoneroConnectionManager>

    this connection manager for chaining

    + +
+
+ +
    + +
  • +

    Check all managed connections, returning a promise for each connection check. +Does not auto switch if disconnected.

    +
    +

    Returns Promise<void>[]

    a promise for each connection in the order of getConnections().

    + +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      connections: any
    • +
    • +
      Optional excludedConnections: any
    +

    Returns Promise<boolean>

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      excludedConnections: any
    +

    Returns Promise<void>

+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      c1: any
    • +
    • +
      c2: any
    +

    Returns any

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      p1: any
    • +
    • +
      p2: any
    +

    Returns number

+
+ +
+
+ +
    + +
  • +

    Get if auto switch is enabled or disabled.

    +
    +

    Returns boolean

    true if auto switch enabled, false otherwise

    + +
+
+ +
    + +
  • +

    Get the best available connection in order of priority then response time.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional excludedConnections: MoneroRpcConnection[]
      +

      connections to be excluded from consideration (optional)

      +
      +
    +

    Returns Promise<MoneroRpcConnection>

    the best available connection in order of priority then response time, undefined if no connections available

    + +
+
+ +
    + +
  • +

    Get the best connection from the given responses.

    +
    +
    +

    Parameters

    +
      +
    • +
      responses: any
      +

      connection responses to update from

      +
      +
    +

    Returns Promise<MoneroRpcConnection>

    the best response among the given responses or undefined if none are best

    + +
+
+ +
+
+ +
    + +
  • +

    Get a connection by URI.

    +
    +
    +

    Parameters

    +
      +
    • +
      uri: string
      +

      is the URI of the connection to get

      +
      +
    +

    Returns MoneroRpcConnection

    the connection with the URI or undefined if no connection with the URI exists

    + +
+
+ +
    + +
  • +

    Get all connections in order of current connection (if applicable), online status, priority, and name.

    +
    +

    Returns MoneroRpcConnection[]

    the list of sorted connections

    + +
+
+ +
    + +
  • +

    Returns any[]

+
+ +
+
+ +
+
+ +
    + +
  • +

    Get the request timeout.

    +
    +

    Returns number

    the request timeout before a connection is considered offline

    + +
+
+ +
    + +
  • +

    Indicates if this manager has a connection with the given URI.

    +
    +
    +

    Parameters

    +
      +
    • +
      uri: string
      +

      URI of the connection to check

      +
      +
    +

    Returns boolean

    true if this manager has a connection with the given URI, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the connection manager is connected to a node.

    +
    +

    Returns boolean

    true if the current connection is set, online, and not unauthenticated, undefined if unknown, false otherwise

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      connection: any
    +

    Returns Promise<any[]>

+
+ +
+
+ +
    + +
  • +

    Remove a connection.

    +
    +
    +

    Parameters

    +
      +
    • +
      uri: string
      +

      of the the connection to remove

      +
      +
    +

    Returns Promise<MoneroConnectionManager>

    this connection manager for chaining

    + +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Automatically switch to the best available connection as connections are polled, based on priority, response time, and consistency.

    +
    +
    +

    Parameters

    +
      +
    • +
      autoSwitch: boolean
      +

      specifies if the connection should auto switch to a better connection

      +
      +
    +

    Returns MoneroConnectionManager

    this connection manager for chaining

    + +
+
+ +
    + +
  • +

    Set the current connection. +Provide a URI to select an existing connection without updating its credentials. +Provide a MoneroRpcConnection to add new connection or replace existing connection with the same URI. +Notify if current connection changes. +Does not check the connection.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional uriOrConnection: string | Partial<MoneroRpcConnection>
      +

      is the uri of the connection or the connection to make current (default undefined for no current connection)

      +
      +
    +

    Returns Promise<MoneroConnectionManager>

    this connection manager for chaining

    + +
+
+ +
    + +
  • +

    Set the maximum request time before its connection is considered offline.

    +
    +
    +

    Parameters

    +
      +
    • +
      timeoutMs: number
      +

      the timeout before the connection is considered offline

      +
      +
    +

    Returns MoneroConnectionManager

    this connection manager for chaining

    + +
+
+ +
    + +
  • +

    Start polling connections.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional periodMs: number
      +

      poll period in milliseconds (default 20s)

      +
      +
    • +
    • +
      Optional autoSwitch: boolean
      +

      specifies to automatically switch to the best connection (default true unless changed)

      +
      +
    • +
    • +
      Optional timeoutMs: number
      +

      specifies the timeout to poll a single connection (default 5s unless changed)

      +
      +
    • +
    • +
      Optional pollType: number
      +

      one of PRIORITIZED (poll connections in order of priority until connected; default), CURRENT (poll current connection), or ALL (poll all connections)

      +
      +
    • +
    • +
      Optional excludedConnections: MoneroRpcConnection[]
      +

      connections excluded from being polled

      +
      +
    +

    Returns MoneroConnectionManager

    this connection manager for chaining

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroConnectionManagerListener.html b/docs/typedocs/classes/MoneroConnectionManagerListener.html new file mode 100644 index 000000000..d0c76d447 --- /dev/null +++ b/docs/typedocs/classes/MoneroConnectionManagerListener.html @@ -0,0 +1,113 @@ +MoneroConnectionManagerListener | monero-ts
+
+ +
+
+
+
+ +

Class MoneroConnectionManagerListener

+
+

Default connection manager listener which takes no action on notifications.

+
+
+
+

Hierarchy

+
    +
  • MoneroConnectionManagerListener
+
+
+
+ +
+
+

Constructors

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Methods

+
+ +
    + +
  • +

    Notified on connection change events.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroConnectionSpan.html b/docs/typedocs/classes/MoneroConnectionSpan.html new file mode 100644 index 000000000..ff0e4b41a --- /dev/null +++ b/docs/typedocs/classes/MoneroConnectionSpan.html @@ -0,0 +1,294 @@ +MoneroConnectionSpan | monero-ts
+
+ +
+
+
+
+ +

Class MoneroConnectionSpan

+
+

Monero daemon connection span.

+
+
+
+

Hierarchy

+
    +
  • MoneroConnectionSpan
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
connectionId: string
+
+ +
numBlocks: number
+
+ +
rate: number
+
+ +
remoteAddress: string
+
+ +
size: number
+
+ +
speed: number
+
+ +
startHeight: number
+
+

Methods

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroDaemon.html b/docs/typedocs/classes/MoneroDaemon.html new file mode 100644 index 000000000..4a1e23e81 --- /dev/null +++ b/docs/typedocs/classes/MoneroDaemon.html @@ -0,0 +1,1288 @@ +MoneroDaemon | monero-ts
+
+ +
+
+
+
+ +

Class MoneroDaemon

+
+

Monero daemon interface and default implementations.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Methods

+
+ +
    + +
  • +

    Register a listener to receive daemon notifications.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Flush transactions from the tx pool.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional hashes: string | string[]
      +

      specific transactions to flush (defaults to all)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Get known block hashes which are not on the main chain.

    +
    +

    Returns Promise<string[]>

    known block hashes which are not on the main chain

    + +
+
+ +
    + +
  • +

    Get alternative chains seen by the node.

    +
    +

    Returns Promise<MoneroAltChain[]>

    alternative chains

    + +
+
+ +
    + +
  • +

    Get a block by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      blockHash: string
      +

      hash of the block to get

      +
      +
    +

    Returns Promise<MoneroBlock>

    with the given hash

    + +
+
+ +
    + +
  • +

    Get a block by height.

    +
    +
    +

    Parameters

    +
      +
    • +
      height: number
      +

      height of the block to get

      +
      +
    +

    Returns Promise<MoneroBlock>

    with the given height

    + +
+
+ +
    + +
  • +

    Get a block's hash by its height.

    +
    +
    +

    Parameters

    +
      +
    • +
      height: number
      +

      height of the block hash to get

      +
      +
    +

    Returns Promise<string>

    the block's hash at the given height

    + +
+
+ +
    + +
  • +

    Get block hashes as a binary request to the daemon.

    +
    +
    +

    Parameters

    +
      +
    • +
      blockHashes: string[]
      +

      specify block hashes to fetch; first 10 blocks hash goes + sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 + and so on, and the last one is always genesis block

      +
      +
    • +
    • +
      startHeight: number
      +

      starting height of block hashes to return

      +
      +
    +

    Returns Promise<string[]>

    requested block hashes

    + +
+
+ +
    + +
  • +

    Get a block header by its hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      blockHash: string
      +

      hash of the block to get the header of

      +
      +
    +

    Returns Promise<MoneroBlockHeader>

    block's header

    + +
+
+ +
    + +
  • +

    Get a block header by its height.

    +
    +
    +

    Parameters

    +
      +
    • +
      height: number
      +

      height of the block to get the header of

      +
      +
    +

    Returns Promise<MoneroBlockHeader>

    block's header

    + +
+
+ +
    + +
  • +

    Get block headers for the given range.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional startHeight: number
      +

      start height lower bound inclusive (optional)

      +
      +
    • +
    • +
      Optional endHeight: number
      +

      end height upper bound inclusive (optional)

      +
      +
    +

    Returns Promise<MoneroBlockHeader[]>

    for the given range

    + +
+
+ +
    + +
  • +

    Get a block template for mining a new block.

    +
    +
    +

    Parameters

    +
      +
    • +
      walletAddress: string
      +

      address of the wallet to receive miner transactions if block is successfully mined

      +
      +
    • +
    • +
      Optional reserveSize: number
      +

      reserve size (optional)

      +
      +
    +

    Returns Promise<MoneroBlockTemplate>

    is a block template for mining a new block

    + +
+
+ +
    + +
  • +

    Get blocks by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      blockHashes: string[]
      +

      array of hashes; first 10 blocks hashes goes sequential, + next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, + and the last one is always genesis block

      +
      +
    • +
    • +
      startHeight: number
      +

      start height to get blocks by hash

      +
      +
    • +
    • +
      Optional prune: boolean = false
      +

      specifies if returned blocks should be pruned (defaults to false) // TODO: test default

      +
      +
    +

    Returns Promise<MoneroBlock[]>

    retrieved blocks

    + +
+
+ +
    + +
  • +

    Get blocks at the given heights.

    +
    +
    +

    Parameters

    +
      +
    • +
      heights: number[]
      +

      heights of the blocks to get

      +
      +
    +

    Returns Promise<MoneroBlock[]>

    are blocks at the given heights

    + +
+
+ +
    + +
  • +

    Get blocks in the given height range.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional startHeight: number
      +

      start height lower bound inclusive (optional)

      +
      +
    • +
    • +
      Optional endHeight: number
      +

      end height upper bound inclusive (optional)

      +
      +
    +

    Returns Promise<MoneroBlock[]>

    are blocks in the given height range

    + +
+
+ +
    + +
  • +

    Get blocks in the given height range as chunked requests so that each request is +not too big.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional startHeight: number
      +

      start height lower bound inclusive (optional)

      +
      +
    • +
    • +
      Optional endHeight: number
      +

      end height upper bound inclusive (optional)

      +
      +
    • +
    • +
      Optional maxChunkSize: number
      +

      maximum chunk size in any one request (default 3,000,000 bytes)

      +
      +
    +

    Returns Promise<MoneroBlock[]>

    blocks in the given height range

    + +
+
+ +
    + +
  • +

    Get the download bandwidth limit.

    +
    +

    Returns Promise<number>

    download bandwidth limit

    + +
+
+ +
    + +
  • +

    Get mining fee estimates per kB.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional graceBlocks: number
      +

      TODO

      +
      +
    +

    Returns Promise<MoneroFeeEstimate>

    mining fee estimates per kB

    + +
+
+ +
    + +
  • +

    Look up information regarding hard fork voting and readiness.

    +
    +

    Returns Promise<MoneroHardForkInfo>

    contains hard fork information

    + +
+
+ +
    + +
  • +

    Get the number of blocks in the longest chain known to the node.

    +
    +

    Returns Promise<number>

    the number of blocks!

    + +
+
+ +
    + +
  • +

    Get general information about the state of the node and the network.

    +
    +

    Returns Promise<MoneroDaemonInfo>

    is general information about the node and network

    + +
+
+ +
    + +
  • +

    Get the spent status of the given key image.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image hex to get the status of

      +
      +
    +

    Returns Promise<MoneroKeyImageSpentStatus>

    status of the key image

    + +
+
+ +
    + +
  • +

    Get the spent status of each given key image.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImages: string[]
      +

      are hex key images to get the statuses of

      +
      +
    +

    Returns Promise<MoneroKeyImageSpentStatus[]>

    status for each key image

    + +
+
+ +
    + +
  • +

    Get known peers including their last known online status.

    +
    +

    Returns Promise<MoneroPeer[]>

    the daemon's known peers

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Gets the total emissions and fees from the genesis block to the current height.

    +
    +
    +

    Parameters

    +
      +
    • +
      height: number
      +

      height to start computing the miner sum

      +
      +
    • +
    • +
      numBlocks: number
      +

      number of blocks to include in the sum

      +
      +
    +

    Returns Promise<MoneroMinerTxSum>

    encapsulates the total emissions and fees since the genesis block

    + +
+
+ +
+
+ +
    + +
  • +

    Get a histogram of output amounts. For all amounts (possibly filtered by +parameters), gives the number of outputs on the chain for that amount. +RingCT outputs counts as 0 amount.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional amounts: bigint[]
      +

      amounts of outputs to make the histogram with

      +
      +
    • +
    • +
      Optional minCount: number
      +

      TODO

      +
      +
    • +
    • +
      Optional maxCount: number
      +

      TODO

      +
      +
    • +
    • +
      Optional isUnlocked: boolean
      +

      makes a histogram with outputs with the specified lock state

      +
      +
    • +
    • +
      Optional recentCutoff: number
      +

      TODO

      +
      +
    +

    Returns Promise<MoneroOutputHistogramEntry[]>

    are entries meeting the parameters

    + +
+
+ +
    + +
  • +

    Get outputs identified by a list of output amounts and indices as a binary +request.

    +
    +
    +

    Parameters

    +
      +
    • +
      outputs: MoneroOutput[]
      +

      identify each output by amount and index

      +
      +
    +

    Returns Promise<MoneroOutput[]>

    identified outputs

    + +
+
+ +
    + +
  • +

    Get peer bans.

    +
    +

    Returns Promise<MoneroBan[]>

    entries about banned peers

    + +
+
+ +
    + +
  • +

    Get peers with active incoming or outgoing connections to the node.

    +
    +

    Returns Promise<MoneroPeer[]>

    the daemon's peers

    + +
+
+ +
+
+ +
    + +
  • +

    Get a transaction by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional txHash: string
      +

      hash of the transaction to get

      +
      +
    • +
    • +
      Optional prune: boolean = false
      +

      specifies if the returned tx should be pruned (defaults to false)

      +
      +
    +

    Returns Promise<MoneroTx>

    transaction with the given hash or undefined if not found

    + +
+
+ +
    + +
  • +

    Get a transaction hex by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      hash of the transaction to get hex from

      +
      +
    • +
    • +
      Optional prune: boolean = false
      +

      specifies if the returned tx hex should be pruned (defaults to false)

      +
      +
    +

    Returns Promise<string>

    tx hex with the given hash

    + +
+
+ +
    + +
  • +

    Get transaction hexes by hashes.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      hashes of transactions to get hexes from

      +
      +
    • +
    • +
      Optional prune: boolean = false
      +

      specifies if the returned tx hexes should be pruned (defaults to false)

      +
      +
    +

    Returns Promise<string[]>

    tx hexes

    + +
+
+ +
    + +
  • +

    Get valid transactions seen by the node but not yet mined into a block, as well +as spent key image information for the tx pool.

    +
    +

    Returns Promise<MoneroTx[]>

    are transactions in the transaction pool!

    + +
+
+ +
    + +
  • +

    Get hashes of transactions in the transaction pool.

    +
    +

    Returns Promise<string[]>

    are hashes of transactions in the transaction pool

    + +
+
+ +
    + +
  • +

    Get transaction pool statistics.

    +
    +

    Returns Promise<MoneroTxPoolStats>

    contains statistics about the transaction pool

    + +
+
+ +
    + +
  • +

    Get transactions by hashes.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      hashes of transactions to get

      +
      +
    • +
    • +
      Optional prune: boolean = false
      +

      specifies if the returned txs should be pruned (defaults to false)

      +
      +
    +

    Returns Promise<MoneroTx[]>

    found transactions with the given hashes

    + +
+
+ +
    + +
  • +

    Get the upload bandwidth limit.

    +
    +

    Returns Promise<number>

    upload bandwidth limit

    + +
+
+ +
    + +
  • +

    Gets the version of the daemon.

    +
    +

    Returns Promise<MoneroVersion>

    the version of the daemon

    + +
+
+ +
    + +
  • +

    Indicates if the client is connected to the daemon via RPC.

    +
    +

    Returns Promise<boolean>

    true if the client is connected to the daemon, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the daemon is trusted xor untrusted.

    +
    +

    Returns Promise<boolean>

    true if the daemon is trusted, false otherwise

    + +
+
+ +
    + +
  • +

    Prune the blockchain.

    +
    +
    +

    Parameters

    +
      +
    • +
      check: boolean
      +

      specifies to check the pruning (default false)

      +
      +
    +

    Returns Promise<MoneroPruneResult>

    the prune result

    + +
+
+ +
    + +
  • +

    Relays a transaction by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      hash of the transaction to relay

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Relays transactions by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      hashes of the transactinos to relay

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Unregister a listener to receive daemon notifications.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Reset the download bandwidth limit.

    +
    +

    Returns Promise<number>

    download bandwidth limit after resetting

    + +
+
+ +
    + +
  • +

    Reset the upload bandwidth limit.

    +
    +

    Returns Promise<number>

    upload bandwidth limit after resetting

    + +
+
+ +
    + +
  • +

    Set the download bandwidth limit.

    +
    +
    +

    Parameters

    +
      +
    • +
      limit: number
      +

      download limit to set (-1 to reset to default)

      +
      +
    +

    Returns Promise<number>

    new download limit after setting

    + +
+
+ +
    + +
  • +

    Limit number of incoming peers.

    +
    +
    +

    Parameters

    +
      +
    • +
      limit: number
      +

      maximum number of incoming peers

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Limit number of outgoing peers.

    +
    +
    +

    Parameters

    +
      +
    • +
      limit: number
      +

      maximum number of outgoing peers

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Ban a peer node.

    +
    +
    +

    Parameters

    +
      +
    • +
      ban: MoneroBan
      +

      contains information about a node to ban

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Ban peers nodes.

    +
    +
    +

    Parameters

    +
      +
    • +
      bans: MoneroBan[]
      +

      specify which peers to ban

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set the upload bandwidth limit.

    +
    +
    +

    Parameters

    +
      +
    • +
      limit: number
      +

      upload limit to set (-1 to reset to default)

      +
      +
    +

    Returns Promise<number>

    new upload limit after setting

    + +
+
+ +
    + +
  • +

    Start mining.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      address given miner rewards if the daemon mines a block

      +
      +
    • +
    • +
      Optional numThreads: number
      +

      number of mining threads to run (default 1)

      +
      +
    • +
    • +
      Optional isBackground: boolean
      +

      specifies if the miner should run in the background or not (default false)

      +
      +
    • +
    • +
      Optional ignoreBattery: boolean
      +

      specifies if the battery state (e.g. on laptop) should be ignored or not (default false)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Safely disconnect and shut down the daemon.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Stop mining.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Submit a mined block to the network.

    +
    +
    +

    Parameters

    +
      +
    • +
      blockBlob: string
      +

      mined block to submit

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Submit mined blocks to the network.

    +
    +
    +

    Parameters

    +
      +
    • +
      blockBlobs: string[]
      +

      mined blocks to submit

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Submits a transaction to the daemon's pool.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHex: string
      +

      raw transaction hex to submit

      +
      +
    • +
    • +
      doNotRelay: boolean = false
      +

      specifies if the tx should be relayed (default false, i.e. relay)

      +
      +
    +

    Returns Promise<MoneroSubmitTxResult>

    contains submission results

    + +
+
+ +
    + +
  • +

    Get the header of the next block added to the chain.

    +
    +

    Returns Promise<MoneroBlockHeader>

    header of the next block added to the chain

    + +
+
+ +
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroDaemonConfig.html b/docs/typedocs/classes/MoneroDaemonConfig.html new file mode 100644 index 000000000..03d4a9cfe --- /dev/null +++ b/docs/typedocs/classes/MoneroDaemonConfig.html @@ -0,0 +1,242 @@ +MoneroDaemonConfig | monero-ts
+
+ +
+
+
+
+ +

Class MoneroDaemonConfig

+
+

Configuration to connect to monerod.

+
+
+
+

Hierarchy

+
    +
  • MoneroDaemonConfig
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
cmd: string[]
+

Command to start monerod as a child process.

+
+
+
+ +
pollInterval: number
+

Interval in milliseconds to poll the daemon for updates (default 20000).

+
+
+
+ +
proxyToWorker: boolean
+

Proxy requests to monerod to a worker (default true).

+
+
+
+ +
server: string | Partial<MoneroRpcConnection>
+

Server config to monerod.

+
+
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Returns string[]

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns boolean

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroDaemonInfo.html b/docs/typedocs/classes/MoneroDaemonInfo.html new file mode 100644 index 000000000..63a51b666 --- /dev/null +++ b/docs/typedocs/classes/MoneroDaemonInfo.html @@ -0,0 +1,970 @@ +MoneroDaemonInfo | monero-ts
+
+ +
+
+
+
+ +

Class MoneroDaemonInfo

+
+

Monero daemon info.

+
+
+
+

Hierarchy

+
    +
  • MoneroDaemonInfo
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
adjustedTimestamp: number
+
+ +
blockSizeLimit: number
+
+ +
blockSizeMedian: number
+
+ +
blockWeightLimit: number
+
+ +
blockWeightMedian: number
+
+ +
bootstrapDaemonAddress: string
+
+ +
credits: bigint
+
+ +
cumulativeDifficulty: bigint
+
+ +
databaseSize: number
+
+ +
difficulty: bigint
+
+ +
freeSpace: bigint
+
+ +
height: number
+
+ +
heightWithoutBootstrap: number
+
+ +
isBusySyncing: boolean
+
+ +
isOffline: boolean
+
+ +
isRestricted: boolean
+
+ +
isSynchronized: boolean
+
+ +
networkType: string
+
+ +
numAltBlocks: number
+
+ +
numIncomingConnections: number
+
+ +
numOfflinePeers: number
+
+ +
numOnlinePeers: number
+
+ +
numOutgoingConnections: number
+
+ +
numRpcConnections: number
+
+ +
numTxs: number
+
+ +
numTxsPool: number
+
+ +
startTimestamp: number
+
+ +
target: number
+
+ +
targetHeight: number
+
+ +
topBlockHash: string
+
+ +
updateAvailable: boolean
+
+ +
version: string
+
+ +
wasBootstrapEverUsed: boolean
+
+

Methods

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns boolean

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+ +
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroDaemonListener.html b/docs/typedocs/classes/MoneroDaemonListener.html new file mode 100644 index 000000000..aa94591c0 --- /dev/null +++ b/docs/typedocs/classes/MoneroDaemonListener.html @@ -0,0 +1,135 @@ +MoneroDaemonListener | monero-ts
+
+ +
+
+
+
+ +

Class MoneroDaemonListener

+
+

Receives notifications as a daemon is updated.

+
+
+
+

Hierarchy

+
    +
  • MoneroDaemonListener
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
lastHeader: MoneroBlockHeader
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Called when a new block is added to the chain.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroDaemonRpc.html b/docs/typedocs/classes/MoneroDaemonRpc.html new file mode 100644 index 000000000..485c85c61 --- /dev/null +++ b/docs/typedocs/classes/MoneroDaemonRpc.html @@ -0,0 +1,1902 @@ +MoneroDaemonRpc | monero-ts
+
+ +
+
+
+
+ +

Class MoneroDaemonRpc

+
+

Implements a MoneroDaemon as a client of monerod.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Methods

+
addListener +checkForUpdate +downloadUpdate +flushTxPool +getAltBlockHashes +getAltChains +getBandwidthLimits +getBlockByHash +getBlockByHeight +getBlockHash +getBlockHashes +getBlockHeaderByHash +getBlockHeaderByHeight +getBlockHeaderByHeightCached +getBlockHeadersByRange +getBlockTemplate +getBlocksByHash +getBlocksByHeight +getBlocksByRange +getBlocksByRangeChunked +getDownloadLimit +getFeeEstimate +getHardForkInfo +getHeight +getInfo +getKeyImageSpentStatus +getKeyImageSpentStatuses +getKnownPeers +getLastBlockHeader +getListeners +getMaxBlocks +getMinerTxSum +getMiningStatus +getOutputDistribution +getOutputHistogram +getOutputs +getPeerBans +getPeers +getPollInterval +getProcess +getRpcConnection +getSyncInfo +getTx +getTxHex +getTxHexes +getTxPool +getTxPoolHashes +getTxPoolStats +getTxs +getUploadLimit +getVersion +isConnected +isTrusted +pruneBlockchain +refreshListening +relayTxByHash +relayTxsByHash +removeListener +resetDownloadLimit +resetUploadLimit +setBandwidthLimits +setDownloadLimit +setIncomingPeerLimit +setOutgoingPeerLimit +setPeerBan +setPeerBans +setUploadLimit +startMining +stop +stopMining +stopProcess +submitBlock +submitBlocks +submitTxHex +waitForNextBlockHeader +checkResponseStatus +connectToDaemonRpc +convertRpcAltChain +convertRpcBlock +convertRpcBlockHeader +convertRpcBlockTemplate +convertRpcConnection +convertRpcConnectionSpan +convertRpcHardForkInfo +convertRpcInfo +convertRpcMiningStatus +convertRpcOutput +convertRpcOutputHistogramEntry +convertRpcPeer +convertRpcSubmitTxResult +convertRpcSyncInfo +convertRpcTx +convertRpcTxPoolStats +convertRpcUpdateCheckResult +convertRpcUpdateDownloadResult +convertToRpcBan +normalizeConfig +prefixedHexToBI +startMonerodProcess +
+
+

Properties

+
+ +
cachedHeaders: any
+
+ +
config: Partial<MoneroDaemonConfig>
+
+ +
+
+ +
pollListener: any
+
+ +
process: any
+
+ +
proxyDaemon: any
+
+ +
DEFAULT_ID: "0000000000000000000000000000000000000000000000000000000000000000" = "0000000000000000000000000000000000000000000000000000000000000000"
+
+ +
DEFAULT_POLL_PERIOD: 20000 = 20000
+
+ +
MAX_REQ_SIZE: "3000000" = "3000000"
+
+ +
NUM_HEADERS_PER_REQ: 750 = 750
+
+

Methods

+
+ +
    + +
  • +

    Register a listener to receive daemon notifications.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Flush transactions from the tx pool.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional hashes: string | string[]
      +

      specific transactions to flush (defaults to all)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Get known block hashes which are not on the main chain.

    +
    +

    Returns Promise<string[]>

    known block hashes which are not on the main chain

    + +
+
+ +
+
+ +
    + +
  • +

    Returns Promise<any[]>

+
+ +
+
+ +
+
+ +
    + +
  • +

    Get a block's hash by its height.

    +
    +
    +

    Parameters

    +
      +
    • +
      height: number
      +

      height of the block hash to get

      +
      +
    +

    Returns Promise<string>

    the block's hash at the given height

    + +
+
+ +
    + +
  • +

    Get block hashes as a binary request to the daemon.

    +
    +
    +

    Parameters

    +
      +
    • +
      blockHashes: string[]
      +

      specify block hashes to fetch; first 10 blocks hash goes + sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 + and so on, and the last one is always genesis block

      +
      +
    • +
    • +
      startHeight: number
      +

      starting height of block hashes to return

      +
      +
    +

    Returns Promise<string[]>

    requested block hashes

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Retrieves a header by height from the cache or fetches and caches a header +range if not already in the cache.

    +
    +
    +

    Parameters

    +
      +
    • +
      height: any
      +

      height of the header to retrieve from the cache

      +
      +
    • +
    • +
      maxHeight: any
      +

      maximum height of headers to cache

      +
      +
    +

    Returns Promise<any>

    +
+
+ +
    + +
  • +

    Get block headers for the given range.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional startHeight: number
      +

      start height lower bound inclusive (optional)

      +
      +
    • +
    • +
      Optional endHeight: number
      +

      end height upper bound inclusive (optional)

      +
      +
    +

    Returns Promise<MoneroBlockHeader[]>

    for the given range

    + +
+
+ +
    + +
  • +

    Get a block template for mining a new block.

    +
    +
    +

    Parameters

    +
      +
    • +
      walletAddress: string
      +

      address of the wallet to receive miner transactions if block is successfully mined

      +
      +
    • +
    • +
      Optional reserveSize: number
      +

      reserve size (optional)

      +
      +
    +

    Returns Promise<MoneroBlockTemplate>

    is a block template for mining a new block

    + +
+
+ +
    + +
  • +

    Get blocks by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      blockHashes: string[]
      +

      array of hashes; first 10 blocks hashes goes sequential, + next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, + and the last one is always genesis block

      +
      +
    • +
    • +
      startHeight: number
      +

      start height to get blocks by hash

      +
      +
    • +
    • +
      Optional prune: boolean = false
      +

      specifies if returned blocks should be pruned (defaults to false) // TODO: test default

      +
      +
    +

    Returns Promise<MoneroBlock[]>

    retrieved blocks

    + +
+
+ +
    + +
  • +

    Get blocks at the given heights.

    +
    +
    +

    Parameters

    +
      +
    • +
      heights: number[]
      +

      heights of the blocks to get

      +
      +
    +

    Returns Promise<MoneroBlock[]>

    are blocks at the given heights

    + +
+
+ +
    + +
  • +

    Get blocks in the given height range.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional startHeight: number
      +

      start height lower bound inclusive (optional)

      +
      +
    • +
    • +
      Optional endHeight: number
      +

      end height upper bound inclusive (optional)

      +
      +
    +

    Returns Promise<MoneroBlock[]>

    are blocks in the given height range

    + +
+
+ +
    + +
  • +

    Get blocks in the given height range as chunked requests so that each request is +not too big.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional startHeight: number
      +

      start height lower bound inclusive (optional)

      +
      +
    • +
    • +
      Optional endHeight: number
      +

      end height upper bound inclusive (optional)

      +
      +
    • +
    • +
      Optional maxChunkSize: number
      +

      maximum chunk size in any one request (default 3,000,000 bytes)

      +
      +
    +

    Returns Promise<MoneroBlock[]>

    blocks in the given height range

    + +
+
+ +
    + +
  • +

    Get the download bandwidth limit.

    +
    +

    Returns Promise<number>

    download bandwidth limit

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get the number of blocks in the longest chain known to the node.

    +
    +

    Returns Promise<number>

    the number of blocks!

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get a contiguous chunk of blocks starting from a given height up to a maximum +height or amount of block data fetched from the blockchain, whichever comes first.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional startHeight: any
      +

      start height to retrieve blocks (default 0)

      +
      +
    • +
    • +
      Optional maxHeight: any
      +

      maximum end height to retrieve blocks (default blockchain height)

      +
      +
    • +
    • +
      Optional maxReqSize: any
      +

      maximum amount of block data to fetch from the blockchain in bytes (default 3,000,000 bytes)

      +
      +
    +

    Returns Promise<MoneroBlock[]>

    are the resulting chunk of blocks

    + +
+
+ +
    + +
  • +

    Gets the total emissions and fees from the genesis block to the current height.

    +
    +
    +

    Parameters

    +
      +
    • +
      height: number
      +

      height to start computing the miner sum

      +
      +
    • +
    • +
      numBlocks: number
      +

      number of blocks to include in the sum

      +
      +
    +

    Returns Promise<MoneroMinerTxSum>

    encapsulates the total emissions and fees since the genesis block

    + +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      amounts: any
    • +
    • +
      cumulative: any
    • +
    • +
      startHeight: any
    • +
    • +
      endHeight: any
    +

    Returns Promise<any>

+
+ +
    + +
  • +

    Get a histogram of output amounts. For all amounts (possibly filtered by +parameters), gives the number of outputs on the chain for that amount. +RingCT outputs counts as 0 amount.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional amounts: bigint[]
      +

      amounts of outputs to make the histogram with

      +
      +
    • +
    • +
      Optional minCount: number
      +

      TODO

      +
      +
    • +
    • +
      Optional maxCount: number
      +

      TODO

      +
      +
    • +
    • +
      Optional isUnlocked: boolean
      +

      makes a histogram with outputs with the specified lock state

      +
      +
    • +
    • +
      Optional recentCutoff: number
      +

      TODO

      +
      +
    +

    Returns Promise<MoneroOutputHistogramEntry[]>

    are entries meeting the parameters

    + +
+
+ +
    + +
  • +

    Get outputs identified by a list of output amounts and indices as a binary +request.

    +
    +
    +

    Parameters

    +
      +
    • +
      outputs: MoneroOutput[]
      +

      identify each output by amount and index

      +
      +
    +

    Returns Promise<MoneroOutput[]>

    identified outputs

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Get the internal process running monerod.

    +
    +

    Returns ChildProcess

    the node process running monerod, undefined if not created from new process

    + +
+
+ +
    + +
  • +

    Get the daemon's RPC connection.

    +
    +

    Returns Promise<any>

    the daemon's rpc connection

    + +
+
+ +
+
+ +
    + +
  • +

    Get a transaction by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional txHash: string
      +

      hash of the transaction to get

      +
      +
    • +
    • +
      prune: boolean = false
      +

      specifies if the returned tx should be pruned (defaults to false)

      +
      +
    +

    Returns Promise<MoneroTx>

    transaction with the given hash or undefined if not found

    + +
+
+ +
    + +
  • +

    Get a transaction hex by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      hash of the transaction to get hex from

      +
      +
    • +
    • +
      prune: boolean = false
      +

      specifies if the returned tx hex should be pruned (defaults to false)

      +
      +
    +

    Returns Promise<string>

    tx hex with the given hash

    + +
+
+ +
    + +
  • +

    Get transaction hexes by hashes.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      hashes of transactions to get hexes from

      +
      +
    • +
    • +
      prune: boolean = false
      +

      specifies if the returned tx hexes should be pruned (defaults to false)

      +
      +
    +

    Returns Promise<string[]>

    tx hexes

    + +
+
+ +
    + +
  • +

    Get valid transactions seen by the node but not yet mined into a block, as well +as spent key image information for the tx pool.

    +
    +

    Returns Promise<MoneroTx[]>

    are transactions in the transaction pool!

    + +
+
+ +
    + +
  • +

    Get hashes of transactions in the transaction pool.

    +
    +

    Returns Promise<string[]>

    are hashes of transactions in the transaction pool

    + +
+
+ +
+
+ +
    + +
  • +

    Get transactions by hashes.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      hashes of transactions to get

      +
      +
    • +
    • +
      prune: boolean = false
      +

      specifies if the returned txs should be pruned (defaults to false)

      +
      +
    +

    Returns Promise<MoneroTx[]>

    found transactions with the given hashes

    + +
+
+ +
    + +
  • +

    Get the upload bandwidth limit.

    +
    +

    Returns Promise<number>

    upload bandwidth limit

    + +
+
+ +
+
+ +
    + +
  • +

    Indicates if the client is connected to the daemon via RPC.

    +
    +

    Returns Promise<boolean>

    true if the client is connected to the daemon, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the daemon is trusted xor untrusted.

    +
    +

    Returns Promise<boolean>

    true if the daemon is trusted, false otherwise

    + +
+
+ +
+
+ +
    + +
  • +

    Returns void

+
+ +
    + +
  • +

    Relays a transaction by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      hash of the transaction to relay

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Relays transactions by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      hashes of the transactinos to relay

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Unregister a listener to receive daemon notifications.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Reset the download bandwidth limit.

    +
    +

    Returns Promise<number>

    download bandwidth limit after resetting

    + +
+
+ +
    + +
  • +

    Reset the upload bandwidth limit.

    +
    +

    Returns Promise<number>

    upload bandwidth limit after resetting

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      downLimit: any
    • +
    • +
      upLimit: any
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +

    Set the download bandwidth limit.

    +
    +
    +

    Parameters

    +
      +
    • +
      limit: number
      +

      download limit to set (-1 to reset to default)

      +
      +
    +

    Returns Promise<number>

    new download limit after setting

    + +
+
+ +
    + +
  • +

    Limit number of incoming peers.

    +
    +
    +

    Parameters

    +
      +
    • +
      limit: number
      +

      maximum number of incoming peers

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Limit number of outgoing peers.

    +
    +
    +

    Parameters

    +
      +
    • +
      limit: number
      +

      maximum number of outgoing peers

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Ban a peer node.

    +
    +
    +

    Parameters

    +
      +
    • +
      ban: MoneroBan
      +

      contains information about a node to ban

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Ban peers nodes.

    +
    +
    +

    Parameters

    +
      +
    • +
      bans: MoneroBan[]
      +

      specify which peers to ban

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set the upload bandwidth limit.

    +
    +
    +

    Parameters

    +
      +
    • +
      limit: number
      +

      upload limit to set (-1 to reset to default)

      +
      +
    +

    Returns Promise<number>

    new upload limit after setting

    + +
+
+ +
    + +
  • +

    Start mining.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      address given miner rewards if the daemon mines a block

      +
      +
    • +
    • +
      Optional numThreads: number
      +

      number of mining threads to run (default 1)

      +
      +
    • +
    • +
      Optional isBackground: boolean
      +

      specifies if the miner should run in the background or not (default false)

      +
      +
    • +
    • +
      Optional ignoreBattery: boolean
      +

      specifies if the battery state (e.g. on laptop) should be ignored or not (default false)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Safely disconnect and shut down the daemon.

    +
    +

    Returns Promise<void>

    +
+
+ +
+
+ +
    + +
  • +

    Stop the internal process running monerod, if applicable.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional force: boolean = false
      +

      specifies if the process should be destroyed forcibly (default false)

      +
      +
    +

    Returns Promise<number>

    the exit code from stopping the process

    + +
+
+ +
    + +
  • +

    Submit a mined block to the network.

    +
    +
    +

    Parameters

    +
      +
    • +
      blockBlob: string
      +

      mined block to submit

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Submit mined blocks to the network.

    +
    +
    +

    Parameters

    +
      +
    • +
      blockBlobs: string[]
      +

      mined blocks to submit

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Submits a transaction to the daemon's pool.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHex: string
      +

      raw transaction hex to submit

      +
      +
    • +
    • +
      doNotRelay: boolean
      +

      specifies if the tx should be relayed (default false, i.e. relay)

      +
      +
    +

    Returns Promise<MoneroSubmitTxResult>

    contains submission results

    + +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      resp: any
    +

    Returns void

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      rpcConnection: any
    +

    Returns MoneroPeer

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Initializes sync info from RPC sync info.

    +
    +
    +

    Parameters

    +
      +
    • +
      rpcSyncInfo: any
      +

      rpc map to initialize the sync info from

      +
      +
    +

    Returns MoneroDaemonSyncInfo

    is sync info initialized from the map

    + +
+
+ +
    + +
  • +

    Transfers RPC tx fields to a given MoneroTx without overwriting previous values.

    +

    TODO: switch from safe set

    +
    +
    +

    Parameters

    +
      +
    • +
      rpcTx: any
      +

      RPC map containing transaction fields

      +
      +
    • +
    • +
      tx: any
      +

      MoneroTx to populate with values (optional)

      +
      +
    +

    Returns any

    tx - same tx that was passed in or a new one if none given

    + +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
    +

    Returns any

+
+ +
+
+ +
    + +
  • +

    Converts a '0x' prefixed hexidecimal string to a bigint.

    +
    +
    +

    Parameters

    +
      +
    • +
      hex: any
      +

      is the '0x' prefixed hexidecimal string to convert

      +
      +
    +

    Returns bigint

    the hexicedimal converted to decimal

    + +
+
+ +
+
+ +
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroDaemonSyncInfo.html b/docs/typedocs/classes/MoneroDaemonSyncInfo.html new file mode 100644 index 000000000..86ba4757a --- /dev/null +++ b/docs/typedocs/classes/MoneroDaemonSyncInfo.html @@ -0,0 +1,320 @@ +MoneroDaemonSyncInfo | monero-ts
+
+ +
+
+
+
+ +

Class MoneroDaemonSyncInfo

+
+

Models daemon synchronization information.

+
+
+
+

Hierarchy

+
    +
  • MoneroDaemonSyncInfo
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
credits: bigint
+
+ +
height: number
+
+ +
nextNeededPruningSeed: number
+
+ +
overview: string
+
+ +
peers: MoneroPeer[]
+
+ +
+
+ +
targetHeight: number
+
+ +
topBlockHash: string
+
+

Methods

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroDaemonUpdateCheckResult.html b/docs/typedocs/classes/MoneroDaemonUpdateCheckResult.html new file mode 100644 index 000000000..bf848796a --- /dev/null +++ b/docs/typedocs/classes/MoneroDaemonUpdateCheckResult.html @@ -0,0 +1,256 @@ +MoneroDaemonUpdateCheckResult | monero-ts
+
+ +
+
+
+
+ +

Class MoneroDaemonUpdateCheckResult

+
+

Models the result of checking for a daemon update.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
autoUri: string
+
+ +
hash: string
+
+ +
isUpdateAvailable: boolean
+
+ +
userUri: string
+
+ +
version: string
+
+

Methods

+
+ +
    + +
  • +

    Get the uri to automatically download the update.

    +
    +

    Returns string

    is the uri to automatically download the update

    + +
+
+ +
    + +
  • +

    Get the update's hash.

    +
    +

    Returns string

    is the update's hash

    + +
+
+ +
    + +
  • +

    Indicates if an update is available.

    +
    +

    Returns boolean

    true if an update is available, false otherwise

    + +
+
+ +
    + +
  • +

    Get the uri to manually download the update.

    +
    +

    Returns string

    is the uri to manually download the update

    + +
+
+ +
    + +
  • +

    Get the update's version.

    +
    +

    Returns string

    is the update's version

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroDaemonUpdateDownloadResult.html b/docs/typedocs/classes/MoneroDaemonUpdateDownloadResult.html new file mode 100644 index 000000000..f71fd0a9f --- /dev/null +++ b/docs/typedocs/classes/MoneroDaemonUpdateDownloadResult.html @@ -0,0 +1,302 @@ +MoneroDaemonUpdateDownloadResult | monero-ts
+
+ +
+
+
+
+ +

Class MoneroDaemonUpdateDownloadResult

+
+

Models the result of downloading an update.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
autoUri: string
+
+ +
downloadPath: string
+
+ +
hash: string
+
+ +
isUpdateAvailable: boolean
+
+ +
userUri: string
+
+ +
version: string
+
+

Methods

+
+ +
    + +
  • +

    Get the uri to automatically download the update.

    +
    +

    Returns string

    is the uri to automatically download the update

    + +
+
+ +
    + +
  • +

    Get the path the update was downloaded to.

    +
    +

    Returns string

    is the path the update was downloaded to

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroDestination.html b/docs/typedocs/classes/MoneroDestination.html new file mode 100644 index 000000000..abdf571a8 --- /dev/null +++ b/docs/typedocs/classes/MoneroDestination.html @@ -0,0 +1,202 @@ +MoneroDestination | monero-ts
+
+ +
+
+
+
+ +

Class MoneroDestination

+
+

Models an outgoing transfer destination.

+
+
+
+

Hierarchy

+
    +
  • MoneroDestination
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
    + +
  • +

    Construct a destination to send funds to.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional destinationOrAddress: string | Partial<MoneroDestination>
      +

      is a MoneroDestination or hex string to initialize from (optional)

      +
      +
    • +
    • +
      Optional amount: bigint
      +

      the destination amount

      +
      +
    +

    Returns MoneroDestination

    +
+
+

Properties

+
+ +
address: string
+

Destination address to send funds to.

+
+
+
+ +
amount: bigint
+

Amount to send to destination address.

+
+
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns bigint

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroError.html b/docs/typedocs/classes/MoneroError.html new file mode 100644 index 000000000..26e2a5880 --- /dev/null +++ b/docs/typedocs/classes/MoneroError.html @@ -0,0 +1,210 @@ +MoneroError | monero-ts
+
+ +
+
+
+
+ +

Class MoneroError

+
+

Exception when interacting with a Monero wallet or daemon.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
    + +
  • +

    Constructs the error.

    +
    +
    +

    Parameters

    +
      +
    • +
      message: any
      +

      is a human-readable message of the error

      +
      +
    • +
    • +
      Optional code: any
      +

      is the error code (optional)

      +
      +
    +

    Returns MoneroError

    +
+
+

Properties

+
+ +
code: number
+
+ +
message: string
+
+ +
name: string
+
+ +
stack?: string
+
+ +
prepareStackTrace?: ((err, stackTraces) => any)
+
+

Type declaration

+
+
+ +
stackTraceLimit: number
+
+

Methods

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Create .stack property on a target object

    +
    +
    +

    Parameters

    +
      +
    • +
      targetObject: object
    • +
    • +
      Optional constructorOpt: Function
    +

    Returns void

    +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroFeeEstimate.html b/docs/typedocs/classes/MoneroFeeEstimate.html new file mode 100644 index 000000000..3e9b3e3c5 --- /dev/null +++ b/docs/typedocs/classes/MoneroFeeEstimate.html @@ -0,0 +1,211 @@ +MoneroFeeEstimate | monero-ts
+
+ +
+
+
+
+ +

Class MoneroFeeEstimate

+
+

Models a Monero fee estimate.

+
+
+
+

Hierarchy

+
    +
  • MoneroFeeEstimate
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
fee: bigint
+
+ +
fees: bigint[]
+
+ +
quantizationMask: bigint
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns bigint[]

+
+ +
    + +
  • +

    Returns bigint

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroHardForkInfo.html b/docs/typedocs/classes/MoneroHardForkInfo.html new file mode 100644 index 000000000..e303f9c52 --- /dev/null +++ b/docs/typedocs/classes/MoneroHardForkInfo.html @@ -0,0 +1,372 @@ +MoneroHardForkInfo | monero-ts
+
+ +
+
+
+
+ +

Class MoneroHardForkInfo

+
+

Monero hard fork info.

+
+
+
+

Hierarchy

+
    +
  • MoneroHardForkInfo
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
credits: bigint
+
+ +
earliestHeight: number
+
+ +
isEnabled: boolean
+
+ +
numVotes: number
+
+ +
state: string
+
+ +
threshold: number
+
+ +
topBlockHash: string
+
+ +
version: number
+
+ +
voting: number
+
+ +
window: number
+
+

Methods

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroIncomingTransfer.html b/docs/typedocs/classes/MoneroIncomingTransfer.html new file mode 100644 index 000000000..70bd4fdef --- /dev/null +++ b/docs/typedocs/classes/MoneroIncomingTransfer.html @@ -0,0 +1,367 @@ +MoneroIncomingTransfer | monero-ts
+
+ +
+
+
+
+ +

Class MoneroIncomingTransfer

+
+

Models an incoming transfer of funds to the wallet.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
accountIndex: number
+
+ +
address: string
+
+ +
amount: bigint
+
+ +
numSuggestedConfirmations: number
+
+ +
subaddressIndex: number
+
+ +
+
+

Methods

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Return how many confirmations till it's not economically worth re-writing the chain. +That is, the number of confirmations before the transaction is highly unlikely to be +double spent or overwritten and may be considered settled, e.g. for a merchant to trust +as finalized.

    +
    +

    Returns number

    is the number of confirmations before it's not worth rewriting the chain

    + +
+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
    + +
  • +

    Updates this transaction by merging the latest information from the given +transaction.

    +

    Merging can modify or build references to the transfer given so it +should not be re-used or it should be copied before calling this method.

    +
    +
    +

    Parameters

    +
    +

    Returns MoneroIncomingTransfer

    +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroIntegratedAddress.html b/docs/typedocs/classes/MoneroIntegratedAddress.html new file mode 100644 index 000000000..1b1edb7d6 --- /dev/null +++ b/docs/typedocs/classes/MoneroIntegratedAddress.html @@ -0,0 +1,198 @@ +MoneroIntegratedAddress | monero-ts
+
+ +
+
+
+
+ +

Class MoneroIntegratedAddress

+
+

Monero integrated address model.

+
+
+
+

Hierarchy

+
    +
  • MoneroIntegratedAddress
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
integratedAddress: string
+
+ +
paymentId: string
+
+ +
standardAddress: string
+
+

Methods

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+ +
    + +
  • +

    Returns string

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroKeyImage.html b/docs/typedocs/classes/MoneroKeyImage.html new file mode 100644 index 000000000..8f1c72b25 --- /dev/null +++ b/docs/typedocs/classes/MoneroKeyImage.html @@ -0,0 +1,206 @@ +MoneroKeyImage | monero-ts
+
+ +
+
+
+
+ +

Class MoneroKeyImage

+
+

Models a Monero key image.

+
+
+
+

Hierarchy

+
    +
  • MoneroKeyImage
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
    + +
  • +

    Construct the model.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional hexOrKeyImage: string | Partial<MoneroKeyImage>
    • +
    • +
      Optional signature: string
      +

      is the key image's signature

      +
      +
    +

    Returns MoneroKeyImage

    +
+
+

Properties

+
+ +
hex: string
+
+ +
signature: string
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroKeyImageImportResult.html b/docs/typedocs/classes/MoneroKeyImageImportResult.html new file mode 100644 index 000000000..06abb62d0 --- /dev/null +++ b/docs/typedocs/classes/MoneroKeyImageImportResult.html @@ -0,0 +1,190 @@ +MoneroKeyImageImportResult | monero-ts
+
+ +
+
+
+
+ +

Class MoneroKeyImageImportResult

+
+

Models results from importing key images.

+
+
+
+

Hierarchy

+
    +
  • MoneroKeyImageImportResult
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
height: number
+
+ +
spentAmount: bigint
+
+ +
unspentAmount: bigint
+
+

Methods

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns bigint

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroMessageSignatureResult.html b/docs/typedocs/classes/MoneroMessageSignatureResult.html new file mode 100644 index 000000000..9090cf76e --- /dev/null +++ b/docs/typedocs/classes/MoneroMessageSignatureResult.html @@ -0,0 +1,216 @@ +MoneroMessageSignatureResult | monero-ts
+
+ +
+
+
+
+ +

Class MoneroMessageSignatureResult

+
+

Message signature verification result.

+
+
+
+

Hierarchy

+
    +
  • MoneroMessageSignatureResult
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
isGood: boolean
+
+ +
isOld: boolean
+
+ +
+
+ +
version: number
+
+

Methods

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroMinerTxSum.html b/docs/typedocs/classes/MoneroMinerTxSum.html new file mode 100644 index 000000000..a1637d5ce --- /dev/null +++ b/docs/typedocs/classes/MoneroMinerTxSum.html @@ -0,0 +1,164 @@ +MoneroMinerTxSum | monero-ts
+
+ +
+
+
+
+ +

Class MoneroMinerTxSum

+
+

Model for the summation of miner emissions and fees.

+
+
+
+

Hierarchy

+
    +
  • MoneroMinerTxSum
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
emissionSum: bigint
+
+ +
feeSum: bigint
+
+

Methods

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns bigint

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroMiningStatus.html b/docs/typedocs/classes/MoneroMiningStatus.html new file mode 100644 index 000000000..7b536da5c --- /dev/null +++ b/docs/typedocs/classes/MoneroMiningStatus.html @@ -0,0 +1,242 @@ +MoneroMiningStatus | monero-ts
+
+ +
+
+
+
+ +

Class MoneroMiningStatus

+
+

Models daemon mining status.

+
+
+
+

Hierarchy

+
    +
  • MoneroMiningStatus
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
address: string
+
+ +
isActive: boolean
+
+ +
isBackground: boolean
+
+ +
numThreads: number
+
+ +
speed: number
+
+

Methods

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroMultisigInfo.html b/docs/typedocs/classes/MoneroMultisigInfo.html new file mode 100644 index 000000000..54eff0a8c --- /dev/null +++ b/docs/typedocs/classes/MoneroMultisigInfo.html @@ -0,0 +1,216 @@ +MoneroMultisigInfo | monero-ts
+
+ +
+
+
+
+ +

Class MoneroMultisigInfo

+
+

Models information about a multisig wallet.

+
+
+
+

Hierarchy

+
    +
  • MoneroMultisigInfo
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
isMultisig: boolean
+
+ +
isReady: boolean
+
+ +
numParticipants: number
+
+ +
threshold: number
+
+

Methods

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroMultisigInitResult.html b/docs/typedocs/classes/MoneroMultisigInitResult.html new file mode 100644 index 000000000..4ad343852 --- /dev/null +++ b/docs/typedocs/classes/MoneroMultisigInitResult.html @@ -0,0 +1,166 @@ +MoneroMultisigInitResult | monero-ts
+
+ +
+
+
+
+ +

Class MoneroMultisigInitResult

+
+

Models the result of initializing a multisig wallet which results in the +multisig wallet's address xor another multisig hex to share with +participants to create the wallet.

+
+
+
+

Hierarchy

+
    +
  • MoneroMultisigInitResult
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
address: string
+
+ +
multisigHex: string
+
+

Methods

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroMultisigSignResult.html b/docs/typedocs/classes/MoneroMultisigSignResult.html new file mode 100644 index 000000000..a844e3df8 --- /dev/null +++ b/docs/typedocs/classes/MoneroMultisigSignResult.html @@ -0,0 +1,164 @@ +MoneroMultisigSignResult | monero-ts
+
+ +
+
+
+
+ +

Class MoneroMultisigSignResult

+
+

Models the result of signing multisig tx hex.

+
+
+
+

Hierarchy

+
    +
  • MoneroMultisigSignResult
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
signedMultisigTxHex: string
+
+ +
txHashes: string[]
+
+

Methods

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string[]

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroNetworkType.html b/docs/typedocs/classes/MoneroNetworkType.html new file mode 100644 index 000000000..a325a99aa --- /dev/null +++ b/docs/typedocs/classes/MoneroNetworkType.html @@ -0,0 +1,219 @@ +MoneroNetworkType | monero-ts
+
+ +
+
+
+
+ +

Class MoneroNetworkType

+
+

Defines the Monero network types (mainnet, testnet, and stagenet).

+
+
+
+

Hierarchy

+
    +
  • MoneroNetworkType
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
MAINNET: 0 = 0
+

Mainnet (value=0).

+
+
+
+ +
STAGENET: 2 = 2
+

Stagnet (value=2).

+
+
+
+ +
TESTNET: 1 = 1
+

Testnet (value=1).

+
+
+
+

Methods

+
+ +
    + +
  • +

    Validate and normalize the given network type.

    +
    +
    +

    Parameters

    +
      +
    • +
      networkType: string | number | MoneroNetworkType
      +

      the network type to validate and normalize

      +
      +
    +

    Returns MoneroNetworkType

    the given network type

    + +
+
+ +
    + +
  • +

    Indicates if the given network type is valid or not.

    +
    +
    +

    Parameters

    +
      +
    • +
      networkType: string | number | MoneroNetworkType
      +

      the network type to validate as a numeric

      +
      +
    +

    Returns boolean

    true if the network type is valid, false otherwise

    + +
+
+ +
    + +
  • +

    Parse the given string as a network type.

    +
    +
    +

    Parameters

    +
      +
    • +
      networkTypeStr: string
      +

      "mainnet", "testnet", or "stagenet" (case insensitive)

      +
      +
    +

    Returns MoneroNetworkType

    the network type as a numeric

    + +
+
+ +
    + +
  • +

    Get the network type in human-readable form.

    +
    +
    +

    Parameters

    +
    +

    Returns string

    the network type in human-readable form

    + +
+
+ +
    + +
  • +

    Validate the given network type.

    +
    +
    +

    Parameters

    +
      +
    • +
      networkType: string | number | MoneroNetworkType
      +

      the network type to validate as a numeric

      +
      +
    +

    Returns void

    +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroOutgoingTransfer.html b/docs/typedocs/classes/MoneroOutgoingTransfer.html new file mode 100644 index 000000000..10da5ffd9 --- /dev/null +++ b/docs/typedocs/classes/MoneroOutgoingTransfer.html @@ -0,0 +1,357 @@ +MoneroOutgoingTransfer | monero-ts
+
+ +
+
+
+
+ +

Class MoneroOutgoingTransfer

+
+

Models an outgoing transfer of funds from the wallet.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
accountIndex: number
+
+ +
addresses: string[]
+
+ +
amount: bigint
+
+ +
destinations: MoneroDestination[]
+
+ +
subaddressIndices: number[]
+
+ +
+
+

Methods

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns string[]

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns number[]

+
+ +
+
+ +
    + +
  • +

    Updates this transaction by merging the latest information from the given +transaction.

    +

    Merging can modify or build references to the transfer given so it +should not be re-used or it should be copied before calling this method.

    +
    +
    +

    Parameters

    +
    +

    Returns MoneroOutgoingTransfer

    +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroOutput.html b/docs/typedocs/classes/MoneroOutput.html new file mode 100644 index 000000000..829926dc7 --- /dev/null +++ b/docs/typedocs/classes/MoneroOutput.html @@ -0,0 +1,310 @@ +MoneroOutput | monero-ts
+
+ +
+
+
+
+ +

Class MoneroOutput

+
+

Models a Monero transaction output.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
    + +
  • +

    Construct the model.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional output: Partial<MoneroOutput>
      +

      is existing state to initialize from (optional)

      +
      +
    +

    Returns MoneroOutput

    +
+
+

Properties

+
+ +
amount: bigint
+
+ +
index: number
+
+ +
keyImage: Partial<MoneroKeyImage>
+
+ +
ringOutputIndices: number[]
+
+ +
stealthPublicKey: string
+
+ +
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
    + +
  • +

    Returns number[]

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      ringOutputIndices: number[]
    +

    Returns MoneroOutput

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      stealthPublicKey: string
    +

    Returns MoneroOutput

+
+ +
+
+ +
    + +
  • +

    Returns any

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroOutputHistogramEntry.html b/docs/typedocs/classes/MoneroOutputHistogramEntry.html new file mode 100644 index 000000000..5001ae8ff --- /dev/null +++ b/docs/typedocs/classes/MoneroOutputHistogramEntry.html @@ -0,0 +1,216 @@ +MoneroOutputHistogramEntry | monero-ts
+
+ +
+
+
+
+ +

Class MoneroOutputHistogramEntry

+
+

Entry in a Monero output histogram (see get_output_histogram of Daemon RPC documentation).

+
+
+
+

Hierarchy

+
    +
  • MoneroOutputHistogramEntry
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
amount: bigint
+
+ +
numInstances: number
+
+ +
numRecentInstances: number
+
+ +
numUnlockedInstances: number
+
+

Methods

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroOutputQuery.html b/docs/typedocs/classes/MoneroOutputQuery.html new file mode 100644 index 000000000..595f61b55 --- /dev/null +++ b/docs/typedocs/classes/MoneroOutputQuery.html @@ -0,0 +1,607 @@ +MoneroOutputQuery | monero-ts
+
+ +
+
+
+
+ +

Class MoneroOutputQuery

+
+

Configuration to query wallet outputs.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
    + +
  • +

    Construct the output query.

    + +

    Example:

    + + +// get available outputs in account 0 with a minimum amount
    +let outputs = await wallet.getOutputs({
    +   isSpent: false,
    +   isLocked: false,
    +   accountIndex: 0,
    +   minAmount: 750000n
    +}); +
    + +

    All configuration is optional. All outputs are returned except those that don't meet criteria defined in this query.

    +
    +

    Parameters

    +
    +

    Returns MoneroOutputQuery

    +
+
+

Properties

+
+ +
accountIndex: number
+
+ +
amount: bigint
+
+ +
index: number
+
+ +
isFrozen: boolean
+
+ +
isLocked: boolean
+
+ +
isSpent: boolean
+
+ +
keyImage: Partial<MoneroKeyImage>
+
+ +
maxAmount: bigint
+
+ +
minAmount: bigint
+
+ +
ringOutputIndices: number[]
+
+ +
stealthPublicKey: string
+
+ +
subaddressIndex: number
+
+ +
subaddressIndices: number[]
+
+ +
+
+ +
txQuery: Partial<MoneroTxQuery>
+
+

Methods

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Indicates if this output has been deemed 'malicious' and will therefore +not be spent by the wallet.

    +
    +

    Returns boolean

    Boolean is whether or not this output is frozen

    + +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns bigint

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns number[]

+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
    +

    Returns boolean

+
+ +
    + +
  • +

    Updates this output by merging the latest information from the given +output.

    +

    Merging can modify or build references to the output given so it +should not be re-used or it should be copied before calling this method.

    +
    +
    +

    Parameters

    +
    +

    Returns MoneroOutputWallet

    +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroOutputWallet.html b/docs/typedocs/classes/MoneroOutputWallet.html new file mode 100644 index 000000000..d355b9350 --- /dev/null +++ b/docs/typedocs/classes/MoneroOutputWallet.html @@ -0,0 +1,466 @@ +MoneroOutputWallet | monero-ts
+
+ +
+
+
+
+ +

Class MoneroOutputWallet

+
+

Models a Monero output with wallet extensions.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
accountIndex: number
+
+ +
amount: bigint
+
+ +
index: number
+
+ +
isFrozen: boolean
+
+ +
isLocked: boolean
+
+ +
isSpent: boolean
+
+ +
keyImage: Partial<MoneroKeyImage>
+
+ +
ringOutputIndices: number[]
+
+ +
stealthPublicKey: string
+
+ +
subaddressIndex: number
+
+ +
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
    + +
  • +

    Indicates if this output has been deemed 'malicious' and will therefore +not be spent by the wallet.

    +
    +

    Returns boolean

    Boolean is whether or not this output is frozen

    + +
+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
    + +
  • +

    Updates this output by merging the latest information from the given +output.

    +

    Merging can modify or build references to the output given so it +should not be re-used or it should be copied before calling this method.

    +
    +
    +

    Parameters

    +
    +

    Returns MoneroOutputWallet

    +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroPeer.html b/docs/typedocs/classes/MoneroPeer.html new file mode 100644 index 000000000..abd415b48 --- /dev/null +++ b/docs/typedocs/classes/MoneroPeer.html @@ -0,0 +1,767 @@ +MoneroPeer | monero-ts
+
+ +
+
+
+
+ +

Class MoneroPeer

+
+

Models a peer to the daemon.

+
+
+
+

Hierarchy

+
    +
  • MoneroPeer
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
address: string
+
+ +
avgDownload: number
+
+ +
avgUpload: number
+
+ +
currentDownload: number
+
+ +
currentUpload: number
+
+ +
height: number
+
+ +
host: string
+
+ +
id: string
+
+ +
isIncoming: boolean
+
+ +
isLocalHost: boolean
+
+ +
isLocalIp: boolean
+
+ +
isOnline: boolean
+
+ +
lastSeenTimestamp: number
+
+ +
liveTime: number
+
+ +
numReceives: number
+
+ +
numSends: number
+
+ +
numSupportFlags: number
+
+ +
port: number
+
+ +
pruningSeed: number
+
+ +
receiveIdleTime: number
+
+ +
rpcCreditsPerHash: bigint
+
+ +
rpcPort: number
+
+ +
sendIdleTime: number
+
+ +
state: string
+
+ +
+
+

Methods

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Indicates if the peer was online when last checked (aka "white listed" as +opposed to "gray listed").

    +
    +

    Returns boolean

    true if peer was online when last checked, false otherwise

    + +
+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      avgDownload: number
    +

    Returns MoneroPeer

+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      currentDownload: number
    +

    Returns MoneroPeer

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      currentUpload: number
    +

    Returns MoneroPeer

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      isIncoming: boolean
    +

    Returns MoneroPeer

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      isLocalHost: boolean
    +

    Returns MoneroPeer

+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      lastSeenTimestamp: number
    +

    Returns MoneroPeer

+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      numReceives: number
    +

    Returns MoneroPeer

+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      numSupportFlags: number
    +

    Returns MoneroPeer

+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      pruningSeed: number
    +

    Returns MoneroPeer

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      receiveIdleTime: number
    +

    Returns MoneroPeer

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      rpcCreditsPerHash: bigint
    +

    Returns MoneroPeer

+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      sendIdleTime: number
    +

    Returns MoneroPeer

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+ +
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroPruneResult.html b/docs/typedocs/classes/MoneroPruneResult.html new file mode 100644 index 000000000..a56c05a96 --- /dev/null +++ b/docs/typedocs/classes/MoneroPruneResult.html @@ -0,0 +1,164 @@ +MoneroPruneResult | monero-ts
+
+ +
+
+
+
+ +

Class MoneroPruneResult

+
+

Result of pruning the blockchain.

+
+
+
+

Hierarchy

+
    +
  • MoneroPruneResult
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
isPruned: boolean
+
+ +
pruningSeed: number
+
+

Methods

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroRpcConnection.html b/docs/typedocs/classes/MoneroRpcConnection.html new file mode 100644 index 000000000..a93beaec9 --- /dev/null +++ b/docs/typedocs/classes/MoneroRpcConnection.html @@ -0,0 +1,701 @@ +MoneroRpcConnection | monero-ts
+
+ +
+
+
+
+ +

Class MoneroRpcConnection

+
+

Maintains a connection and sends requests to a Monero RPC API.

+
+
+
+

Hierarchy

+
    +
  • MoneroRpcConnection
+
+
+
+ +
+
+

Constructors

+
+ +
    + +
  • +

    Construct a RPC connection.

    + +

    Examples:

    + + +let connection1 = new MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123")

    + +

    let connection2 = new MoneroRpcConnection({
    +   uri: http://localhost:38081,
    +   username: "daemon_user",
    +   password: "daemon_password_123",
    +   rejectUnauthorized: false, // accept self-signed certificates e.g. for local development
    +   proxyToWorker: true // proxy request to worker (default false)
    +}); +

    +
    +
    +

    Parameters

    +
      +
    • +
      uriOrConnection: string | Partial<MoneroRpcConnection>
      +

      MoneroRpcConnection or URI of the RPC endpoint

      +
      +
    • +
    • +
      Optional username: string
      +

      username to authenticate with the RPC endpoint (optional)

      +
      +
    • +
    • +
      Optional password: string
      +

      password to authenticate with the RPC endpoint (optional)

      +
      +
    +

    Returns MoneroRpcConnection

    +
+
+

Properties

+
+ +
attributes: any
+
+ +
checkConnectionMutex: ThreadPool
+
+ +
fakeDisconnected: boolean
+
+ +
isAuthenticated: boolean
+
+ +
isOnline: boolean
+
+ +
password: string
+
+ +
priority: number
+
+ +
proxyToWorker: boolean
+
+ +
proxyUri: string
+
+ +
rejectUnauthorized: boolean
+
+ +
responseTime: number
+
+ +
sendRequestMutex: ThreadPool
+
+ +
timeoutMs: number
+
+ +
uri: string
+
+ +
username: string
+
+ +
zmqUri: string
+
+

Methods

+
+ +
    + +
  • +

    Check the connection status to update isOnline, isAuthenticated, and response time.

    +
    +
    +

    Parameters

    +
      +
    • +
      timeoutMs: any
      +

      maximum response time before considered offline

      +
      +
    +

    Returns Promise<boolean>

    true if there is a change in status, false otherwise

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      key: any
    +

    Returns any

+
+ +
    + +
  • +

    Returns {
        password: string;
        priority: number;
        proxyToWorker: boolean;
        proxyUri: string;
        rejectUnauthorized: boolean;
        timeoutMs: number;
        uri: string;
        username: string;
        zmqUri: string;
    }

    +
      +
    • +
      password: string
    • +
    • +
      priority: number
    • +
    • +
      proxyToWorker: boolean
    • +
    • +
      proxyUri: string
    • +
    • +
      rejectUnauthorized: boolean
    • +
    • +
      timeoutMs: number
    • +
    • +
      uri: string
    • +
    • +
      username: string
    • +
    • +
      zmqUri: string
+
+ +
    + +
  • +

    Indicates if the connection is authenticated according to the last call to checkConnection().

    +

    Note: must call checkConnection() manually unless using MoneroConnectionManager.

    +
    +

    Returns boolean

    true if authenticated or no authentication, false if not authenticated, or undefined if checkConnection() has not been called

    + +
+
+ +
    + +
  • +

    Indicates if the connection is online according to the last call to checkConnection().

    +

    Note: must call checkConnection() manually unless using MoneroConnectionManager.

    +
    +

    Returns boolean

    true or false to indicate if online, or undefined if checkConnection() has not been called

    + +
+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Indicates if the connection is connected according to the last call to checkConnection().

    +

    Note: must call checkConnection() manually unless using MoneroConnectionManager.

    +
    +

    Returns boolean

    true or false to indicate if connected, or undefined if checkConnection() has not been called

    + +
+
+ +
    + +
  • +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Parameters

    +
      +
    • +
      asyncFn: (() => Promise<T>)
      +
        +
      • +
          +
        • (): Promise<T>
        • +
        • +

          Returns Promise<T>

    +

    Returns Promise<T>

+
+ +
    + +
  • +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Parameters

    +
      +
    • +
      asyncFn: (() => Promise<T>)
      +
        +
      • +
          +
        • (): Promise<T>
        • +
        • +

          Returns Promise<T>

    +

    Returns Promise<T>

+
+ +
    + +
  • +

    Send a binary RPC request.

    +
    +
    +

    Parameters

    +
      +
    • +
      path: any
      +

      path of the binary RPC method to invoke

      +
      +
    • +
    • +
      Optional params: any
      +

      request parameters

      +
      +
    • +
    • +
      Optional timeoutMs: any
      +

      request timeout in milliseconds

      +
      +
    +

    Returns Promise<any>

    the binary response

    + +
+
+ +
    + +
  • +

    Send a JSON RPC request.

    +
    +
    +

    Parameters

    +
      +
    • +
      method: any
      +

      JSON RPC method to invoke

      +
      +
    • +
    • +
      Optional params: any
      +

      request parameters

      +
      +
    • +
    • +
      Optional timeoutMs: any
      +

      overrides the request timeout in milliseconds

      +
      +
    +

    Returns Promise<any>

    is the response map

    + +
+
+ +
    + +
  • +

    Send a RPC request to the given path and with the given paramters.

    +

    E.g. "/get_transactions" with params

    +
    +
    +

    Parameters

    +
      +
    • +
      path: any
      +

      JSON RPC path to invoke

      +
      +
    • +
    • +
      Optional params: any
      +

      request parameters

      +
      +
    • +
    • +
      Optional timeoutMs: any
      +

      overrides the request timeout in milliseconds

      +
      +
    +

    Returns Promise<any>

    is the response map

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      fakeDisconnected: any
    +

    Returns void

+
+ +
    + +
  • +

    Set the connection's priority relative to other connections. Priority 1 is highest, +then priority 2, etc. The default priority of 0 is lowest priority.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional priority: any
      +

      the connection priority (default 0)

      +
      +
    +

    Returns MoneroRpcConnection

    this connection

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Set the RPC request timeout in milliseconds.

    +
    +
    +

    Parameters

    +
      +
    • +
      timeoutMs: number
      +

      is the timeout in milliseconds, 0 to disable timeout, or undefined to use default

      +
      +
    +

    Returns MoneroRpcConnection

    this connection

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      resp: any
    • +
    • +
      method: any
    • +
    • +
      params: any
    +

    Returns void

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      resp: any
    +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroRpcError.html b/docs/typedocs/classes/MoneroRpcError.html new file mode 100644 index 000000000..118530306 --- /dev/null +++ b/docs/typedocs/classes/MoneroRpcError.html @@ -0,0 +1,247 @@ +MoneroRpcError | monero-ts
+
+ +
+
+
+
+ +

Class MoneroRpcError

+
+

Error when interacting with Monero RPC.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
    + +
  • +

    Constructs the error.

    +
    +
    +

    Parameters

    +
      +
    • +
      rpcDescription: any
      +

      is a description of the error from rpc

      +
      +
    • +
    • +
      rpcCode: any
      +

      is the error code from rpc

      +
      +
    • +
    • +
      Optional rpcMethod: any
      +

      is the rpc method invoked

      +
      +
    • +
    • +
      Optional rpcParams: any
      +

      are parameters sent with the rpc request

      +
      +
    +

    Returns MoneroRpcError

    +
+
+

Properties

+
+ +
code: number
+
+ +
message: string
+
+ +
name: string
+
+ +
rpcMethod: any
+
+ +
rpcParams: any
+
+ +
stack?: string
+
+ +
prepareStackTrace?: ((err, stackTraces) => any)
+
+

Type declaration

+
+
+ +
stackTraceLimit: number
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Returns any

+
+ +
    + +
  • +

    Returns any

+
+ +
+
+ +
    + +
  • +

    Create .stack property on a target object

    +
    +
    +

    Parameters

    +
      +
    • +
      targetObject: object
    • +
    • +
      Optional constructorOpt: Function
    +

    Returns void

    +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroSubaddress.html b/docs/typedocs/classes/MoneroSubaddress.html new file mode 100644 index 000000000..cd8306734 --- /dev/null +++ b/docs/typedocs/classes/MoneroSubaddress.html @@ -0,0 +1,359 @@ +MoneroSubaddress | monero-ts
+
+ +
+
+
+
+ +

Class MoneroSubaddress

+
+

Monero subaddress model.

+
+
+
+

Hierarchy

+
    +
  • MoneroSubaddress
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
accountIndex: number
+
+ +
address: string
+
+ +
balance: bigint
+
+ +
index: number
+
+ +
isUsed: boolean
+
+ +
label: string
+
+ +
numBlocksToUnlock: number
+
+ +
numUnspentOutputs: number
+
+ +
unlockedBalance: bigint
+
+

Methods

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns bigint

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroSubmitTxResult.html b/docs/typedocs/classes/MoneroSubmitTxResult.html new file mode 100644 index 000000000..d13230463 --- /dev/null +++ b/docs/typedocs/classes/MoneroSubmitTxResult.html @@ -0,0 +1,528 @@ +MoneroSubmitTxResult | monero-ts
+
+ +
+
+
+
+ +

Class MoneroSubmitTxResult

+
+

Models the result from submitting a tx to a daemon.

+
+
+
+

Hierarchy

+
    +
  • MoneroSubmitTxResult
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
credits: bigint
+
+ +
hasInvalidInput: boolean
+
+ +
hasInvalidOutput: boolean
+
+ +
hasTooFewOutputs: boolean
+
+ +
isDoubleSpendSeen: boolean
+
+ +
isFeeTooLow: boolean
+
+ +
isGood: boolean
+
+ +
isMixinTooLow: boolean
+
+ +
isNonzeroUnlockTime: boolean
+
+ +
isOverspend: boolean
+
+ +
isRelayed: boolean
+
+ +
isTooBig: boolean
+
+ +
isTxExtraTooBig: boolean
+
+ +
reason: string
+
+ +
sanityCheckFailed: boolean
+
+ +
topBlockHash: string
+
+

Methods

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroSyncResult.html b/docs/typedocs/classes/MoneroSyncResult.html new file mode 100644 index 000000000..4eb8057f0 --- /dev/null +++ b/docs/typedocs/classes/MoneroSyncResult.html @@ -0,0 +1,158 @@ +MoneroSyncResult | monero-ts
+
+ +
+
+
+
+ +

Class MoneroSyncResult

+
+

Result from syncing a Monero wallet.

+
+
+
+

Hierarchy

+
    +
  • MoneroSyncResult
+
+
+
+ +
+
+

Constructors

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      numBlocksFetched: number
    • +
    • +
      receivedMoney: bigint
    +

    Returns MoneroSyncResult

+
+

Properties

+
+ +
numBlocksFetched: number
+
+ +
receivedMoney: bigint
+
+

Methods

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns bigint

+
+ +
+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroTransfer.html b/docs/typedocs/classes/MoneroTransfer.html new file mode 100644 index 000000000..6def282f2 --- /dev/null +++ b/docs/typedocs/classes/MoneroTransfer.html @@ -0,0 +1,268 @@ +MoneroTransfer | monero-ts
+
+ +
+
+
+
+ +

Class MoneroTransfer

+
+

Models a base transfer of funds to or from the wallet.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
accountIndex: number
+
+ +
amount: bigint
+
+ +
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns boolean

+
+ +
+
+ +
    + +
  • +

    Updates this transaction by merging the latest information from the given +transaction.

    +

    Merging can modify or build references to the transfer given so it +should not be re-used or it should be copied before calling this method.

    +
    +
    +

    Parameters

    +
      +
    • +
      transfer: MoneroTransfer
      +

      is the transfer to merge into this one

      +
      +
    +

    Returns MoneroTransfer

    the merged transfer

    + +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+ +
    + +
  • +

    Returns void

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroTransferQuery.html b/docs/typedocs/classes/MoneroTransferQuery.html new file mode 100644 index 000000000..4d3d7487e --- /dev/null +++ b/docs/typedocs/classes/MoneroTransferQuery.html @@ -0,0 +1,542 @@ +MoneroTransferQuery | monero-ts
+
+ +
+
+
+
+ +

Class MoneroTransferQuery

+
+

Configuration to query wallet transfers.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+ +
    + +
  • +

    Construct the transfer query.

    + +

    Example:

    + + +// get incoming transfers to account 0, subaddress 1
    +let transfers = await wallet.getTransfers({
    +   accountIndex: 0,
    +   subaddressIndex: 0
    +}); +
    + +

    All configuration is optional. All transfers are returned except those that don't meet criteria defined in this query.

    +
    +

    Parameters

    +
    +

    Returns MoneroTransferQuery

    +
+
+

Properties

+
+ +
accountIndex: number
+
+ +
address: string
+
+ +
addresses: string[]
+
+ +
amount: bigint
+
+ +
destinations: MoneroDestination[]
+
+ +
hasDestinations: boolean
+
+ +
isIncoming: boolean
+
+ +
subaddressIndex: number
+
+ +
subaddressIndices: number[]
+
+ +
+
+ +
txQuery: Partial<MoneroTxQuery>
+
+

Methods

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string[]

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns boolean

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number[]

+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
    +

    Returns boolean

+
+ +
    + +
  • +

    Updates this transaction by merging the latest information from the given +transaction.

    +

    Merging can modify or build references to the transfer given so it +should not be re-used or it should be copied before calling this method.

    +
    +
    +

    Parameters

    +
      +
    • +
      transfer: MoneroTransfer
      +

      is the transfer to merge into this one

      +
      +
    +

    Returns MoneroTransfer

    the merged transfer

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Convenience method to query outputs by the locked state of their tx.

    +
    +
    +

    Parameters

    +
      +
    • +
      isLocked: boolean
      +

      specifies if the output's tx must be locked or unlocked (optional)

      +
      +
    +

    Returns MoneroTransferQuery

    this query for chaining

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+ +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroTx.html b/docs/typedocs/classes/MoneroTx.html new file mode 100644 index 000000000..abf6c03db --- /dev/null +++ b/docs/typedocs/classes/MoneroTx.html @@ -0,0 +1,1402 @@ +MoneroTx | monero-ts
+
+ +
+
+
+
+ +

Class MoneroTx

+
+

Represents a transaction on the Monero network.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
+
+ +
extra: Uint8Array
+
+ +
fee: bigint
+
+ +
fullHex: string
+
+ +
hash: string
+
+ +
inTxPool: boolean
+
+ +
inputs: MoneroOutput[]
+
+ +
isConfirmed: boolean
+
+ +
isDoubleSpendSeen: boolean
+
+ +
isFailed: boolean
+
+ +
isKeptByBlock: boolean
+
+ +
isMinerTx: boolean
+
+ +
isRelayed: boolean
+
+ +
key: string
+
+ +
lastFailedHash: string
+
+ +
lastFailedHeight: number
+
+ +
lastRelayedTimestamp: number
+
+ +
maxUsedBlockHash: string
+
+ +
maxUsedBlockHeight: number
+
+ +
metadata: string
+
+ +
numConfirmations: number
+
+ +
outputIndices: number[]
+
+ +
outputs: MoneroOutput[]
+
+ +
paymentId: string
+
+ +
prunableHash: string
+
+ +
prunableHex: string
+
+ +
prunedHex: string
+
+ +
rctSigPrunable: any
+
+ +
rctSignatures: any
+
+ +
receivedTimestamp: number
+
+ +
relay: boolean
+
+ +
ringSize: number
+
+ +
signatures: string[]
+
+ +
size: number
+
+ +
unlockTime: bigint
+
+ +
version: number
+
+ +
weight: number
+
+ +
DEFAULT_PAYMENT_ID: "0000000000000000" = "0000000000000000"
+
+

Methods

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns Uint8Array

    tx extra

    + +
+
+ +
    + +
  • +

    Returns bigint

    tx fee

    + +
+
+ +
    + +
  • +

    Get full transaction hex. Full hex = pruned hex + prunable hex.

    +
    +

    Returns string

    full tx hex

    + +
+
+ +
    + +
  • +

    Returns string

    tx hash

    + +
+
+ +
    + +
  • +

    Returns number

    tx height

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is in the memory pool, false otherwise

    + +
+
+ +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is confirmed, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if a double spend has been seen, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx failed, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if kept by a block, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is a miner tx, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is relayed, false otherwise

    + +
+
+ +
    + +
  • +

    Returns string

    tx key

    + +
+
+ +
    + +
  • +

    Returns string

    block hash of the last tx failure

    + +
+
+ +
    + +
  • +

    Returns number

    block height of the last tx failure

    + +
+
+ +
    + +
  • +

    Returns number

    timestamp the tx was last relayed from the node

    + +
+
+ +
    + +
  • +

    Returns string

    max used block hash

    + +
+
+ +
    + +
  • +

    Returns number

    max used block height

    + +
+
+ +
    + +
  • +

    Returns string

    tx metadata

    + +
+
+ +
    + +
  • +

    Returns number

    number of block confirmations

    + +
+
+ +
    + +
  • +

    Returns number[]

    tx output indices

    + +
+
+ +
+
+ +
    + +
  • +

    Returns string

    tx payment id

    + +
+
+ +
    + +
  • +

    Returns string

    prunable tx hash

    + +
+
+ +
    + +
  • +

    Get prunable transaction hex which is hex that is removed from a pruned +transaction. Full hex = pruned hex + prunable hex.

    +
    +

    Returns string

    prunable tx hex

    + +
+
+ +
    + +
  • +

    Get pruned transaction hex. Full hex = pruned hex + prunable hex.

    +
    +

    Returns string

    pruned tx hex

    + +
+
+ +
    + +
  • +

    Returns object

    prunable RCT signature data

    + +
+
+ +
    + +
  • +

    Returns any

    RCT signatures

    + +
+
+ +
    + +
  • +

    Returns number

    timestamp the tx was received at the node

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is set to be relayed, false otherwise

    + +
+
+ +
    + +
  • +

    Returns number

    tx ring size

    + +
+
+ +
    + +
  • +

    Returns string[]

    tx signatures

    + +
+
+ +
    + +
  • +

    Returns number

    tx size

    + +
+
+ +
    + +
  • +

    Get the minimum height or timestamp for the transactions to unlock.

    +
    +

    Returns bigint

    the minimum height or timestamp for the transaction to unlock

    + +
+
+ +
    + +
  • +

    Returns number

    tx version

    + +
+
+ +
    + +
  • +

    Returns number

    tx weight

    + +
+
+ +
    + +
  • +

    Updates this transaction by merging the latest information from the given +transaction.

    +
    +
    +

    Parameters

    +
      +
    • +
      tx: MoneroTx
      +

      the transaction to update this transaction with

      +
      +
    +

    Returns MoneroTx

    this for method chaining

    + +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      extra: Uint8Array
      +

      tx extra

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      fee: bigint
      +

      tx fee

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      fullHex: string
      +

      full tx hex

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      hash: string
      +

      tx hash

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      inTxPool: boolean
      +

      true if the tx is in the memory pool, false otherwise

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      isConfirmed: boolean
      +

      true if the tx is confirmed, false otherwise

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      isDoubleSpendSeen: boolean
      +

      true if a double spend has been seen, false otherwise

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      isFailed: boolean
      +

      true if the tx failed, false otherwise

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      isKeptByBlock: boolean
      +

      true if kept by a block, false otherwise

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      miner: boolean
      +

      true if the tx is a miner tx, false otherwise

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      isRelayed: boolean
      +

      true if the tx is relayed, false otherwise

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      key: string
      +

      tx key

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      lastFailedHash: string
      +

      block hash of the last tx failure

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      lastFailedHeight: number
      +

      block height of the last tx failure

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      lastRelayedTimestamp: number
      +

      timestamp the tx was last relayed from the node

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      maxUsedBlockHash: string
      +

      max used block hash

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      maxUsedBlockHeight: number
      +

      max used block height

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      metadata: string
      +

      tx metadata

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      numConfirmations: number
      +

      number of block confirmations

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      outputIndices: number[]
      +

      tx output indices

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      paymentId: string
      +

      tx payment id

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      prunableHash: string
      +

      prunable tx hash

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      prunableHex: string
      +

      prunable tx hex

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      prunedHex: string
      +

      pruned tx hex

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      rctSigPrunable: any
      +

      prunable RCT signature data

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      rctSignatures: any
      +

      RCT signatures

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      receivedTimestamp: number
      +

      timestamp the tx was received at the node

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      relay: boolean
      +

      true if the tx is set to be relayed, false otherwise

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      ringSize: number
      +

      tx ring size

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      signatures: string[]
      +

      tx signatures

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      size: number
      +

      tx size

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      unlockTime: string | number | bigint
    +

    Returns MoneroTx

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      version: number
      +

      tx version

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      weight: number
      +

      tx weight

      +
      +
    +

    Returns MoneroTx

    this tx for chaining

    + +
+
+ +
    + +
  • +

    Returns any

    json representation of this tx

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      Optional indent: number = 0
      +

      starting indentation

      +
      +
    +

    Returns string

    string representation of this tx

    + +
+
+ +
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroTxConfig.html b/docs/typedocs/classes/MoneroTxConfig.html new file mode 100644 index 000000000..2e6c76925 --- /dev/null +++ b/docs/typedocs/classes/MoneroTxConfig.html @@ -0,0 +1,682 @@ +MoneroTxConfig | monero-ts
+
+ +
+
+
+
+ +

Class MoneroTxConfig

+
+

Configures a transaction to send, sweep, or create a payment URI.

+
+
+
+

Hierarchy

+
    +
  • MoneroTxConfig
+
+
+
+ +
+
+

Constructors

+
+ +
    + +
  • +

    Generic request to transfer funds from a wallet.

    + +

    Example:

    + + +let config1 = new MoneroTxConfig({
    +   accountIndex: 0,
    +   address: "59aZULsUF3YN...",
    +   amount: 500000n,
    +   priority: MoneroTxPriority.NORMAL,
    +   relay: true
    +}); +
    +
    +

    Parameters

    +
      +
    • +
      Optional config: Partial<MoneroTxConfig>
      +

      configures the transaction to create (optional)

      +
      +
    +

    Returns MoneroTxConfig

    +
+
+

Properties

+
+ +
accountIndex: number
+

Source account index to transfer funds from (required unless sweeping key image).

+
+
+
+ +
address: string
+

Single destination address (required unless destinations provided).

+
+
+
+ +
amount: bigint
+

Single destination amount (required unless `destinations provided).

+
+
+
+ +
belowAmount: bigint
+

For sweep requests, include outputs below this amount when sweeping wallet, account, subaddress, or all unlocked funds.

+
+
+
+ +
canSplit: boolean
+

Allow funds to be transferred using multiple transactions if necessary (default false).

+
+
+
+ +
destinations: Partial<MoneroDestination>[]
+

Multiple destinations to send funds to, if applicable.

+
+
+
+ +
fee: bigint
+

Miner fee (calculated automatically).

+
+
+
+ +
keyImage: string
+

For sweep requests, key image of the output to sweep.

+
+
+
+ +
note: string
+

Transaction note saved locally with the wallet (optional).

+
+
+
+ +
paymentId: string
+

Payment ID for the transaction.

+
+
+
+ + +

Transaction priority to adjust the miner fee (default MoneroTxPriority.NORMAL).

+
+
+
+ +
recipientName: string
+

Recipient name saved locally with the wallet (optional).

+
+
+
+ +
relay: boolean
+

Relay the transaction to peers to commit to the blockchain if true (default false).

+
+
+
+ +
subaddressIndex: number
+

Source subaddress index to send funds from (default all).

+
+
+
+ +
subaddressIndices: number[]
+

Source subaddresses to send funds from (default all).

+
+
+
+ +
subtractFeeFrom: number[]
+

List of destination indices to split the miner fee (optional).

+
+
+
+ +
sweepEachSubaddress: boolean
+

For sweep requests, sweep each subaddress individually instead of together if true.

+
+
+
+

Methods

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Get the address of a single-destination configuration.

    +
    +

    Returns string

    the address of the single destination

    + +
+
+ +
    + +
  • +

    Get the amount of a single-destination configuration.

    +
    +

    Returns bigint

    the amount of the single destination

    + +
+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns boolean

+
+ +
+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Get the key image hex of the output to sweep.

    +

    return {string} is the key image hex of the output to sweep

    +
    +

    Returns string

    +
+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns number[]

+
+ +
    + +
  • +

    Returns number[]

+
+ +
    + +
  • +

    Returns boolean

+
+ +
+
+ +
    + +
  • +

    Set the address of a single-destination configuration.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      the address to set for the single destination

      +
      +
    +

    Returns MoneroTxConfig

    this configuration for chaining

    + +
+
+ +
    + +
  • +

    Set the amount of a single-destination configuration.

    +
    +
    +

    Parameters

    +
      +
    • +
      amount: bigint
      +

      the amount to set for the single destination

      +
      +
    +

    Returns MoneroTxConfig

    this configuration for chaining

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Set the key image hex of the output to sweep.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: any
      +

      is the key image hex of the output to sweep

      +
      +
    +

    Returns MoneroTxConfig

    +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroTxPoolStats.html b/docs/typedocs/classes/MoneroTxPoolStats.html new file mode 100644 index 000000000..8c19d9de8 --- /dev/null +++ b/docs/typedocs/classes/MoneroTxPoolStats.html @@ -0,0 +1,450 @@ +MoneroTxPoolStats | monero-ts
+
+ +
+
+
+
+ +

Class MoneroTxPoolStats

+
+

Models transaction pool statistics.

+
+
+
+

Hierarchy

+
    +
  • MoneroTxPoolStats
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
bytesMax: number
+
+ +
bytesMed: number
+
+ +
bytesMin: number
+
+ +
bytesTotal: number
+
+ +
feeTotal: bigint
+
+ +
histo: Map<number, number>
+
+ +
histo98pc: number
+
+ +
num10m: number
+
+ +
numDoubleSpends: number
+
+ +
numFailing: number
+
+ +
numNotRelayed: number
+
+ +
numTxs: number
+
+ +
oldestTimestamp: number
+
+

Methods

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns bigint

+
+ +
    + +
  • +

    Returns Map<number, number>

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroTxQuery.html b/docs/typedocs/classes/MoneroTxQuery.html new file mode 100644 index 000000000..674675f16 --- /dev/null +++ b/docs/typedocs/classes/MoneroTxQuery.html @@ -0,0 +1,2451 @@ +MoneroTxQuery | monero-ts
+
+ +
+
+
+
+ +

Class MoneroTxQuery

+
+

Configuration to query transactions.

+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
copy +filterOutputs +filterTransfers +getBlock +getChangeAddress +getChangeAmount +getExtra +getExtraHex +getFee +getFullHex +getHasPaymentId +getHash +getHashes +getHeight +getInTxPool +getIncludeOutputs +getIncomingAmount +getIncomingTransfers +getInputQuery +getInputSum +getInputs +getInputsWallet +getIsConfirmed +getIsDoubleSpendSeen +getIsFailed +getIsIncoming +getIsKeptByBlock +getIsLocked +getIsMinerTx +getIsOutgoing +getIsRelayed +getKey +getLastFailedHash +getLastFailedHeight +getLastRelayedTimestamp +getMaxHeight +getMaxUsedBlockHash +getMaxUsedBlockHeight +getMetadata +getMinHeight +getNote +getNumConfirmations +getNumDummyOutputs +getOutgoingAmount +getOutgoingTransfer +getOutputIndices +getOutputQuery +getOutputSum +getOutputs +getOutputsWallet +getPaymentId +getPaymentIds +getPrunableHash +getPrunableHex +getPrunedHex +getRctSigPrunable +getRctSignatures +getReceivedTimestamp +getRelay +getRingSize +getSignatures +getSize +getTransferQuery +getTransfers +getTxSet +getUnlockTime +getVersion +getWeight +meetsCriteria +merge +setBlock +setChangeAddress +setChangeAmount +setExtra +setExtraHex +setFee +setFullHex +setHasPaymentId +setHash +setHashes +setHeight +setInTxPool +setIncludeOutputs +setIncomingTransfers +setInputQuery +setInputSum +setInputs +setInputsWallet +setIsConfirmed +setIsDoubleSpendSeen +setIsFailed +setIsIncoming +setIsKeptByBlock +setIsLocked +setIsMinerTx +setIsOutgoing +setIsRelayed +setKey +setLastFailedHash +setLastFailedHeight +setLastRelayedTimestamp +setMaxHeight +setMaxUsedBlockHash +setMaxUsedBlockHeight +setMetadata +setMinHeight +setNote +setNumConfirmations +setNumDummyOutputs +setOutgoingTransfer +setOutputIndices +setOutputQuery +setOutputSum +setOutputs +setOutputsWallet +setPaymentId +setPaymentIds +setPrunableHash +setPrunableHex +setPrunedHex +setRctSigPrunable +setRctSignatures +setReceivedTimestamp +setRelay +setRingSize +setSignatures +setSize +setTransferQuery +setTxSet +setUnlockTime +setVersion +setWeight +toJson +toString +mergeIncomingTransfer +
+
+

Constructors

+
+ +
    + +
  • +

    Construct the transaction query.

    + +

    Example:

    + + +// get transactions with unlocked incoming transfers to account 0
    +let txs = await wallet.getTxs({
    +   isLocked: false,
    +   transferQuery: {
    +     isIncoming: true,
    +     accountIndex: 0
    +   }
    +}); +
    + +

    All configuration is optional. All transactions are returned except those that don't meet criteria defined in this query.

    +
    +

    Parameters

    +
      +
    • +
      Optional query: Partial<MoneroTxQuery>
      +

      tx query configuration

      +
      +
    +

    Returns MoneroTxQuery

    +
+
+

Properties

+
+ +
+
+ +
changeAddress: string
+
+ +
changeAmount: bigint
+
+ +
extra: Uint8Array
+
+ +
extraHex: string
+
+ +
fee: bigint
+
+ +
fullHex: string
+
+ +
hasPaymentId: boolean
+
+ +
hash: string
+
+ +
hashes: string[]
+
+ +
height: number
+
+ +
inTxPool: boolean
+
+ +
includeOutputs: boolean
+
+ +
incomingTransfers: MoneroIncomingTransfer[]
+
+ +
inputQuery: Partial<MoneroOutputQuery>
+
+ +
inputSum: bigint
+
+ +
inputs: MoneroOutput[]
+
+ +
isConfirmed: boolean
+
+ +
isDoubleSpendSeen: boolean
+
+ +
isFailed: boolean
+
+ +
isIncoming: boolean
+
+ +
isKeptByBlock: boolean
+
+ +
isLocked: boolean
+
+ +
isMinerTx: boolean
+
+ +
isOutgoing: boolean
+
+ +
isRelayed: boolean
+
+ +
key: string
+
+ +
lastFailedHash: string
+
+ +
lastFailedHeight: number
+
+ +
lastRelayedTimestamp: number
+
+ +
maxHeight: number
+
+ +
maxUsedBlockHash: string
+
+ +
maxUsedBlockHeight: number
+
+ +
metadata: string
+
+ +
minHeight: number
+
+ +
note: string
+
+ +
numConfirmations: number
+
+ +
numDummyOutputs: number
+
+ +
outgoingTransfer: MoneroOutgoingTransfer
+
+ +
outputIndices: number[]
+
+ +
outputQuery: Partial<MoneroOutputQuery>
+
+ +
outputSum: bigint
+
+ +
outputs: MoneroOutput[]
+
+ +
paymentId: string
+
+ +
paymentIds: string[]
+
+ +
prunableHash: string
+
+ +
prunableHex: string
+
+ +
prunedHex: string
+
+ +
rctSigPrunable: any
+
+ +
rctSignatures: any
+
+ +
receivedTimestamp: number
+
+ +
relay: boolean
+
+ +
ringSize: number
+
+ +
signatures: string[]
+
+ +
size: number
+
+ +
transferQuery: Partial<MoneroTransferQuery>
+
+ +
+
+ +
unlockTime: bigint
+
+ +
version: number
+
+ +
weight: number
+
+ +
DEFAULT_PAYMENT_ID: "0000000000000000" = "0000000000000000"
+
+

Methods

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get full transaction hex. Full hex = pruned hex + prunable hex.

    +
    +

    Returns string

    full tx hex

    + +
+
+ +
    + +
  • +

    Returns boolean

+
+ +
+
+ +
    + +
  • +

    Returns string[]

+
+ +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is in the memory pool, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is confirmed, false otherwise

    + +
+
+ +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx failed, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx has incoming funds, false otherwise

    + +
+
+ +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is locked, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is a miner tx, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx has outgoing funds, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is relayed, false otherwise

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns string[]

+
+ +
+
+ +
    + +
  • +

    Get prunable transaction hex which is hex that is removed from a pruned +transaction. Full hex = pruned hex + prunable hex.

    +
    +

    Returns string

    prunable tx hex

    + +
+
+ +
    + +
  • +

    Get pruned transaction hex. Full hex = pruned hex + prunable hex.

    +
    +

    Returns string

    pruned tx hex

    + +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is set to be relayed, false otherwise

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get the minimum height or timestamp for the transactions to unlock.

    +
    +

    Returns bigint

    the minimum height or timestamp for the transaction to unlock

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
    +

    Returns boolean

+
+ +
    + +
  • +

    Updates this transaction by merging the latest information from the given +transaction.

    +

    Merging can modify or build references to the transaction given so it +should not be re-used or it should be copied before calling this method.

    +
    +
    +

    Parameters

    +
      +
    • +
      tx: MoneroTxWallet
      +

      the transaction to merge into this transaction

      +
      +
    +

    Returns MoneroTxWallet

    +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      Optional indent: number = 0
      +

      starting indentation

      +
      +
    • +
    • +
      Optional oneLine: boolean = false
      +

      string is one line if true, multiple lines if false

      +
      +
    +

    Returns string

    string representation of this tx

    + +
+
+ +
+
+ +
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroTxSet.html b/docs/typedocs/classes/MoneroTxSet.html new file mode 100644 index 000000000..e86df81c0 --- /dev/null +++ b/docs/typedocs/classes/MoneroTxSet.html @@ -0,0 +1,246 @@ +MoneroTxSet | monero-ts
+
+ +
+
+
+
+ +

Class MoneroTxSet

+
+

Groups transactions who share common hex data which is needed in order to +sign and submit the transactions.

+

For example, multisig transactions created from createTxs() share a common +hex string which is needed in order to sign and submit the multisig +transactions.

+
+
+
+

Hierarchy

+
    +
  • MoneroTxSet
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
multisigTxHex: string
+
+ +
signedTxHex: string
+
+ +
+
+ +
unsignedTxHex: string
+
+

Methods

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      indent: number = 0
    +

    Returns string

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroTxWallet.html b/docs/typedocs/classes/MoneroTxWallet.html new file mode 100644 index 000000000..f8f2ec634 --- /dev/null +++ b/docs/typedocs/classes/MoneroTxWallet.html @@ -0,0 +1,2124 @@ +MoneroTxWallet | monero-ts
+
+ +
+
+
+
+ +

Class MoneroTxWallet

+
+

Models a Monero transaction with wallet extensions.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
copy +filterOutputs +filterTransfers +getBlock +getChangeAddress +getChangeAmount +getExtra +getExtraHex +getFee +getFullHex +getHash +getHeight +getInTxPool +getIncomingAmount +getIncomingTransfers +getInputSum +getInputs +getInputsWallet +getIsConfirmed +getIsDoubleSpendSeen +getIsFailed +getIsIncoming +getIsKeptByBlock +getIsLocked +getIsMinerTx +getIsOutgoing +getIsRelayed +getKey +getLastFailedHash +getLastFailedHeight +getLastRelayedTimestamp +getMaxUsedBlockHash +getMaxUsedBlockHeight +getMetadata +getNote +getNumConfirmations +getNumDummyOutputs +getOutgoingAmount +getOutgoingTransfer +getOutputIndices +getOutputSum +getOutputs +getOutputsWallet +getPaymentId +getPrunableHash +getPrunableHex +getPrunedHex +getRctSigPrunable +getRctSignatures +getReceivedTimestamp +getRelay +getRingSize +getSignatures +getSize +getTransfers +getTxSet +getUnlockTime +getVersion +getWeight +merge +setBlock +setChangeAddress +setChangeAmount +setExtra +setExtraHex +setFee +setFullHex +setHash +setInTxPool +setIncomingTransfers +setInputSum +setInputs +setInputsWallet +setIsConfirmed +setIsDoubleSpendSeen +setIsFailed +setIsIncoming +setIsKeptByBlock +setIsLocked +setIsMinerTx +setIsOutgoing +setIsRelayed +setKey +setLastFailedHash +setLastFailedHeight +setLastRelayedTimestamp +setMaxUsedBlockHash +setMaxUsedBlockHeight +setMetadata +setNote +setNumConfirmations +setNumDummyOutputs +setOutgoingTransfer +setOutputIndices +setOutputSum +setOutputs +setOutputsWallet +setPaymentId +setPrunableHash +setPrunableHex +setPrunedHex +setRctSigPrunable +setRctSignatures +setReceivedTimestamp +setRelay +setRingSize +setSignatures +setSize +setTxSet +setUnlockTime +setVersion +setWeight +toJson +toString +mergeIncomingTransfer +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
+
+ +
changeAddress: string
+
+ +
changeAmount: bigint
+
+ +
extra: Uint8Array
+
+ +
extraHex: string
+
+ +
fee: bigint
+
+ +
fullHex: string
+
+ +
hash: string
+
+ +
inTxPool: boolean
+
+ +
incomingTransfers: MoneroIncomingTransfer[]
+
+ +
inputSum: bigint
+
+ +
inputs: MoneroOutput[]
+
+ +
isConfirmed: boolean
+
+ +
isDoubleSpendSeen: boolean
+
+ +
isFailed: boolean
+
+ +
isIncoming: boolean
+
+ +
isKeptByBlock: boolean
+
+ +
isLocked: boolean
+
+ +
isMinerTx: boolean
+
+ +
isOutgoing: boolean
+
+ +
isRelayed: boolean
+
+ +
key: string
+
+ +
lastFailedHash: string
+
+ +
lastFailedHeight: number
+
+ +
lastRelayedTimestamp: number
+
+ +
maxUsedBlockHash: string
+
+ +
maxUsedBlockHeight: number
+
+ +
metadata: string
+
+ +
note: string
+
+ +
numConfirmations: number
+
+ +
numDummyOutputs: number
+
+ +
outgoingTransfer: MoneroOutgoingTransfer
+
+ +
outputIndices: number[]
+
+ +
outputSum: bigint
+
+ +
outputs: MoneroOutput[]
+
+ +
paymentId: string
+
+ +
prunableHash: string
+
+ +
prunableHex: string
+
+ +
prunedHex: string
+
+ +
rctSigPrunable: any
+
+ +
rctSignatures: any
+
+ +
receivedTimestamp: number
+
+ +
relay: boolean
+
+ +
ringSize: number
+
+ +
signatures: string[]
+
+ +
size: number
+
+ +
+
+ +
unlockTime: bigint
+
+ +
version: number
+
+ +
weight: number
+
+ +
DEFAULT_PAYMENT_ID: "0000000000000000" = "0000000000000000"
+
+

Methods

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns string

    change address

    + +
+
+ +
    + +
  • +

    Returns bigint

    change amount

    + +
+
+ +
    + +
  • +

    Returns Uint8Array

    tx extra

    + +
+
+ +
    + +
  • +

    Returns string

    tx extra as hex

    + +
+
+ +
    + +
  • +

    Returns bigint

    tx fee

    + +
+
+ +
    + +
  • +

    Get full transaction hex. Full hex = pruned hex + prunable hex.

    +
    +

    Returns string

    full tx hex

    + +
+
+ +
    + +
  • +

    Returns string

    tx hash

    + +
+
+ +
    + +
  • +

    Returns number

    tx height

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is in the memory pool, false otherwise

    + +
+
+ +
    + +
  • +

    Returns bigint

    amount received in the tx

    + +
+
+ +
+
+ +
    + +
  • +

    Returns bigint

    sum of tx inputs

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is confirmed, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if a double spend has been seen, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx failed, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx has incoming funds, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if kept by a block, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is locked, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is a miner tx, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx has outgoing funds, false otherwise

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is relayed, false otherwise

    + +
+
+ +
    + +
  • +

    Returns string

    tx key

    + +
+
+ +
    + +
  • +

    Returns string

    block hash of the last tx failure

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns string

    tx note

    + +
+
+ +
+
+ +
    + +
  • +

    Returns number

    number of dummy outputs

    + +
+
+ +
    + +
  • +

    Returns bigint

    amount spent in the tx

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns bigint

    sum of tx outputs

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get prunable transaction hex which is hex that is removed from a pruned +transaction. Full hex = pruned hex + prunable hex.

    +
    +

    Returns string

    prunable tx hex

    + +
+
+ +
    + +
  • +

    Get pruned transaction hex. Full hex = pruned hex + prunable hex.

    +
    +

    Returns string

    pruned tx hex

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns number

    timestamp the tx was received at the node

    + +
+
+ +
    + +
  • +

    Returns boolean

    true if the tx is set to be relayed, false otherwise

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns number

    tx size

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get the minimum height or timestamp for the transactions to unlock.

    +
    +

    Returns bigint

    the minimum height or timestamp for the transaction to unlock

    + +
+
+ +
    + +
  • +

    Returns number

    tx version

    + +
+
+ +
    + +
  • +

    Returns number

    tx weight

    + +
+
+ +
    + +
  • +

    Updates this transaction by merging the latest information from the given +transaction.

    +

    Merging can modify or build references to the transaction given so it +should not be re-used or it should be copied before calling this method.

    +
    +
    +

    Parameters

    +
      +
    • +
      tx: MoneroTxWallet
      +

      the transaction to merge into this transaction

      +
      +
    +

    Returns MoneroTxWallet

    +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      changeAddress: string
      +

      change address

      +
      +
    +

    Returns MoneroTxWallet

    this tx for chaining

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      changeAmount: bigint
      +

      change amount

      +
      +
    +

    Returns MoneroTxWallet

    this tx for chaining

    + +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      extraHex: string
      +

      tx extra as hex

      +
      +
    +

    Returns MoneroTxWallet

    this tx for chaining

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      inputSum: bigint
      +

      sum of tx inputs

      +
      +
    +

    Returns MoneroTxWallet

    this tx for chaining

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      isIncoming: boolean
      +

      true if the tx has incoming funds, false otherwise

      +
      +
    +

    Returns MoneroTxWallet

    this tx for chaining

    + +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      isLocked: boolean
      +

      true if the tx is locked, false otherwise

      +
      +
    +

    Returns MoneroTxWallet

    this tx for chaining

    + +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      isOutgoing: boolean
      +

      true if the tx has outgoing funds, false otherwise

      +
      +
    +

    Returns MoneroTxWallet

    this tx for chaining

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      numDummyOutputs: number
      +

      number of dummy outputs

      +
      +
    +

    Returns MoneroTxWallet

    this tx for chaining

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      outputSum: bigint
      +

      sum of tx outputs

      +
      +
    +

    Returns MoneroTxWallet

    this tx for chaining

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

    json representation of this tx

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      Optional indent: number = 0
      +

      starting indentation

      +
      +
    • +
    • +
      Optional oneLine: boolean = false
      +

      string is one line if true, multiple lines if false

      +
      +
    +

    Returns string

    string representation of this tx

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      transfers: any
    • +
    • +
      transfer: any
    +

    Returns void

+
+ +
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroUtils.html b/docs/typedocs/classes/MoneroUtils.html new file mode 100644 index 000000000..f57b88ba8 --- /dev/null +++ b/docs/typedocs/classes/MoneroUtils.html @@ -0,0 +1,696 @@ +MoneroUtils | monero-ts
+
+ +
+
+
+
+ +

Class MoneroUtils

+
+

Collection of Monero utilities. Runs in a worker thread by default.

+
+
+
+

Hierarchy

+
    +
  • MoneroUtils
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
AU_PER_XMR: bigint = ...
+
+ +
NUM_MNEMONIC_WORDS: number = 25
+
+ +
PROXY_TO_WORKER: boolean = false
+
+ +
RING_SIZE: number = 12
+
+

Methods

+
+ +
    + +
  • +

    Convert atomic units to XMR.

    +
    +
    +

    Parameters

    +
      +
    • +
      amountAtomicUnits: string | bigint
      +

      amount in atomic units to convert to XMR

      +
      +
    +

    Returns number

    amount in XMR

    + +
+
+ +
    + +
  • +

    Convert the binary response from daemon RPC block retrieval to JSON.

    +
    +
    +

    Parameters

    +
      +
    • +
      uint8arr: any
      +

      binary response from daemon RPC when getting blocks

      +
      +
    +

    Returns Promise<any>

    JSON object with the blocks data

    + +
+
+ +
    + +
  • +

    Convert the given portable storage binary to JSON.

    +
    +
    +

    Parameters

    +
      +
    • +
      uint8arr: any
      +

      binary data in Monero's portable storage format

      +
      +
    +

    Returns Promise<any>

    JSON object converted from the binary data

    + +
+
+ +
    + +
  • +

    Divide one atomic units by another.

    +
    +
    +

    Parameters

    +
      +
    • +
      au1: bigint
      +

      dividend

      +
      +
    • +
    • +
      au2: bigint
      +

      divisor

      +
      +
    +

    Returns number

    the result

    + +
+
+ +
    + +
  • +

    Get an integrated address.

    +
    +
    +

    Parameters

    +
      +
    • +
      networkType: MoneroNetworkType
      +

      network type of the integrated address

      +
      +
    • +
    • +
      standardAddress: string
      +

      address to derive the integrated address from

      +
      +
    • +
    • +
      Optional paymentId: string
      +

      optionally specifies the integrated address's payment id (defaults to random payment id)

      +
      +
    +

    Returns Promise<any>

    the integrated address

    + +
+
+ +
    + +
  • +

    Decode tx extra according to https://cryptonote.org/cns/cns005.txt and +returns the last tx pub key.

    +

    TODO: use c++ bridge for this

    +
    +
    +

    Parameters

    +
      +
    • +
      txExtra: any
    +

    Returns Promise<string>

    the last pub key as a hexidecimal string

    + +
+
+ +
    + +
  • +

    Get the version of the monero-ts library.

    +

    Returns string

    the version of this monero-ts library

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      str: any
    +

    Returns boolean

+
+ +
    + +
  • +

    Determine if the given unlock time is a timestamp or block height.

    +
    +
    +

    Parameters

    +
      +
    • +
      unlockTime: bigint
      +

      is the unlock time to check

      +
      +
    +

    Returns boolean

    true if the unlock time is a timestamp, false if a block height

    + +
+
+ +
    + +
  • +

    Determine if the given address is valid.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: any
      +

      address

      +
      +
    • +
    • +
      networkType: any
      +

      network type of the address to validate

      +
      +
    +

    Returns Promise<boolean>

    true if the address is valid, false otherwise

    + +
+
+ +
    + +
  • +

    Determine if the given payment id is valid.

    +
    +
    +

    Parameters

    +
      +
    • +
      paymentId: any
      +

      payment id to determine if valid

      +
      +
    +

    Returns Promise<boolean>

    true if the payment id is valid, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if a private spend key is valid.

    +
    +
    +

    Parameters

    +
      +
    • +
      privateSpendKey: any
      +

      is the private spend key to validate

      +
      +
    +

    Returns Promise<boolean>

    true if the private spend key is valid, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if a private view key is valid.

    +
    +
    +

    Parameters

    +
      +
    • +
      privateViewKey: any
      +

      is the private view key to validate

      +
      +
    +

    Returns Promise<boolean>

    true if the private view key is valid, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if a public spend key is valid.

    +
    +
    +

    Parameters

    +
      +
    • +
      publicSpendKey: any
      +

      is the public spend key to validate

      +
      +
    +

    Returns Promise<boolean>

    true if the public spend key is valid, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if a public view key is valid.

    +
    +
    +

    Parameters

    +
      +
    • +
      publicViewKey: any
      +

      is the public view key to validate

      +
      +
    +

    Returns Promise<boolean>

    true if the public view key is valid, false otherwise

    + +
+
+ +
    + +
  • +

    Convert the given JSON to a binary Uint8Array using Monero's portable storage format.

    +
    +
    +

    Parameters

    +
      +
    • +
      json: any
      +

      json to convert to binary

      +
      +
    +

    Returns Promise<any>

    the json converted to portable storage binary

    + +
+
+ +
    + +
  • +

    Merges a transaction into a list of existing transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txs: any
      +

      existing transactions to merge into

      +
      +
    • +
    • +
      tx: any
      +

      transaction to merge into the list

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Multiply a bigint by a number or bigint.

    +
    +
    +

    Parameters

    +
      +
    • +
      a: bigint
      +

      bigint to multiply

      +
      +
    • +
    • +
      b: number | bigint
      +

      bigint or number to multiply by

      +
      +
    +

    Returns bigint

    the product as a bigint

    + +
+
+ +
    + +
  • +

    Determines if two payment ids are functionally equal.

    +

    For example, 03284e41c342f032 and 03284e41c342f032000000000000000000000000000000000000000000000000 are considered equal.

    +
    +
    +

    Parameters

    +
      +
    • +
      paymentId1: any
      +

      is a payment id to compare

      +
      +
    • +
    • +
      paymentId2: any
      +

      is a payment id to compare

      +
      +
    +

    Returns boolean

    true if the payment ids are equal, false otherwise

    + +
+
+ +
    + +
  • +

    Enable or disable proxying these utilities to a worker thread.

    +
    +
    +

    Parameters

    +
      +
    • +
      proxyToWorker: any
      +

      specifies if utilities should be proxied to a worker

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Validate the given address, throw an error if invalid.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: any
      +

      address to validate

      +
      +
    • +
    • +
      networkType: any
      +

      network type of the address to validate

      +
      +
    +

    Returns Promise<any>

    +
+
+ +
    + +
  • +

    Validate the given mnemonic, throw an error if invalid.

    +

    TODO: improve validation, use network type

    +
    +
    +

    Parameters

    +
      +
    • +
      mnemonic: any
      +

      mnemonic to validate

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Validate the given payment id, throw an error if invalid.

    +

    TODO: improve validation

    +
    +
    +

    Parameters

    +
      +
    • +
      paymentId: any
      +

      payment id to validate

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Validate the given private spend key, throw an error if invalid.

    +
    +
    +

    Parameters

    +
      +
    • +
      privateSpendKey: any
      +

      private spend key to validate

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Validate the given private view key, throw an error if invalid.

    +
    +
    +

    Parameters

    +
      +
    • +
      privateViewKey: any
      +

      private view key to validate

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Validate the given public spend key, throw an error if invalid.

    +
    +
    +

    Parameters

    +
      +
    • +
      publicSpendKey: any
      +

      public spend key to validate

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Validate the given public view key, throw an error if invalid.

    +
    +
    +

    Parameters

    +
      +
    • +
      publicViewKey: any
      +

      public view key to validate

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Convert XMR to atomic units.

    +
    +
    +

    Parameters

    +
      +
    • +
      amountXmr: string | number
      +

      amount in XMR to convert to atomic units

      +
      +
    +

    Returns bigint

    amount in atomic units

    + +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroVersion.html b/docs/typedocs/classes/MoneroVersion.html new file mode 100644 index 000000000..b8ad8af45 --- /dev/null +++ b/docs/typedocs/classes/MoneroVersion.html @@ -0,0 +1,174 @@ +MoneroVersion | monero-ts
+
+ +
+
+
+
+ +

Class MoneroVersion

+
+

Models a Monero version.

+
+
+
+

Hierarchy

+
    +
  • MoneroVersion
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      number: number
    • +
    • +
      isRelease: boolean
    +

    Returns MoneroVersion

+
+

Properties

+
+ +
isRelease: boolean
+
+ +
number: number
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroWallet.html b/docs/typedocs/classes/MoneroWallet.html new file mode 100644 index 000000000..a0eba4614 --- /dev/null +++ b/docs/typedocs/classes/MoneroWallet.html @@ -0,0 +1,2440 @@ +MoneroWallet | monero-ts
+
+ +
+
+
+
+ +

Class MoneroWalletInterface

+
+

Monero wallet interface and default implementations.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Methods

+
addAddressBookEntry +addListener +changePassword +checkReserveProof +checkSpendProof +checkTxKey +checkTxProof +close +createAccount +createSubaddress +createTx +createTxs +decodeIntegratedAddress +deleteAddressBookEntry +describeMultisigTxSet +describeTxSet +describeUnsignedTxSet +editAddressBookEntry +exchangeMultisigKeys +exportKeyImages +exportMultisigHex +exportOutputs +freezeOutput +getAccount +getAccountTags +getAccounts +getAddress +getAddressBookEntries +getAddressIndex +getAttribute +getBalance +getConnectionManager +getDaemonConnection +getDaemonHeight +getDefaultFeePriority +getHeight +getHeightByDate +getIncomingTransfers +getIntegratedAddress +getListeners +getMultisigInfo +getNewKeyImagesFromLastImport +getNumBlocksToUnlock +getOutgoingTransfers +getOutputs +getPath +getPaymentUri +getPrimaryAddress +getPrivateSpendKey +getPrivateViewKey +getPublicSpendKey +getPublicViewKey +getReserveProofAccount +getReserveProofWallet +getSeed +getSeedLanguage +getSpendProof +getSubaddress +getSubaddresses +getTransfers +getTx +getTxKey +getTxNote +getTxNotes +getTxProof +getTxs +getUnlockedBalance +getVersion +importKeyImages +importMultisigHex +importOutputs +isClosed +isConnectedToDaemon +isMultisig +isMultisigImportNeeded +isOutputFrozen +isViewOnly +makeMultisig +parsePaymentUri +prepareMultisig +relayTx +relayTxs +removeListener +rescanBlockchain +rescanSpent +save +scanTxs +setAccountLabel +setAccountTagLabel +setAttribute +setConnectionManager +setDaemonConnection +setSubaddressLabel +setTxNote +setTxNotes +signMessage +signMultisigTxHex +signTxs +startMining +startSyncing +stopMining +stopSyncing +submitMultisigTxHex +submitTxs +sweepDust +sweepOutput +sweepUnlocked +sync +tagAccounts +thawOutput +untagAccounts +verifyMessage +normalizeCreateTxsConfig +normalizeOutputQuery +normalizeSweepOutputConfig +normalizeSweepUnlockedConfig +normalizeTransferQuery +normalizeTxQuery +
+
+

Properties

+
+ +
_isClosed: boolean = false
+
+ +
connectionManager: MoneroConnectionManager
+
+ +
connectionManagerListener: MoneroConnectionManagerListener
+
+ +
listeners: MoneroWalletListener[] = []
+
+ +
DEFAULT_LANGUAGE: "English" = "English"
+
+

Methods

+
+ +
    + +
  • +

    Add an address book entry.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      entry address

      +
      +
    • +
    • +
      Optional description: string
      +

      entry description (optional)

      +
      +
    +

    Returns Promise<number>

    the index of the added entry

    + +
+
+ +
    + +
  • +

    Register a listener to receive wallet notifications.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Change the wallet password.

    +
    +
    +

    Parameters

    +
      +
    • +
      oldPassword: string
      +

      the wallet's old password

      +
      +
    • +
    • +
      newPassword: string
      +

      the wallet's new password

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Proves a wallet has a disposable reserve using a signature.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      public wallet address

      +
      +
    • +
    • +
      message: string
      +

      message included with the signature to further authenticate the proof (optional)

      +
      +
    • +
    • +
      signature: string
      +

      reserve proof signature to check

      +
      +
    +

    Returns Promise<MoneroCheckReserve>

    the result of checking the signature proof

    + +
+
+ +
    + +
  • +

    Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      message: string
      +

      message included with the signature to further authenticate the proof (optional)

      +
      +
    • +
    • +
      signature: string
      +

      transaction signature to confirm

      +
      +
    +

    Returns Promise<boolean>

    true if the signature is good, false otherwise

    + +
+
+ +
    + +
  • +

    Check a transaction in the blockchain with its secret key.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to check

      +
      +
    • +
    • +
      txKey: string
      +

      transaction's secret key

      +
      +
    • +
    • +
      address: string
      +

      destination public address of the transaction

      +
      +
    +

    Returns Promise<MoneroCheckTx>

    the result of the check

    + +
+
+ +
    + +
  • +

    Prove a transaction by checking its signature.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      address: string
      +

      destination public address of the transaction

      +
      +
    • +
    • +
      message: string
      +

      message included with the signature to further authenticate the proof

      +
      +
    • +
    • +
      signature: string
      +

      transaction signature to confirm

      +
      +
    +

    Returns Promise<MoneroCheckTx>

    the result of the check

    + +
+
+ +
    + +
  • +

    Optionally save then close the wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional save: boolean = false
      +

      specifies if the wallet should be saved before being closed (default false)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Create a new account with a label for the first subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional label: string
      +

      label for account's first subaddress (optional)

      +
      +
    +

    Returns Promise<MoneroAccount>

    the created account

    + +
+
+ +
    + +
  • +

    Create a subaddress within an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to create the subaddress within

      +
      +
    • +
    • +
      Optional label: string
      +

      the label for the subaddress (optional)

      +
      +
    +

    Returns Promise<MoneroSubaddress>

    the created subaddress

    + +
+
+ +
    + +
  • +

    Create a transaction to transfer funds from this wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      config: Partial<MoneroTxConfig>
      +

      configures the transaction to create (required)

      +
      +
    +

    Returns Promise<MoneroTxWallet>

    the created transaction

    + +
+
+ +
    + +
  • +

    Create one or more transactions to transfer funds from this wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      config: Partial<MoneroTxConfig>
      +

      configures the transactions to create (required)

      +
      +
    +

    Returns Promise<MoneroTxWallet[]>

    the created transactions

    + +
+
+ +
    + +
  • +

    Decode an integrated address to get its standard address and payment id.

    +
    +
    +

    Parameters

    +
      +
    • +
      integratedAddress: string
      +

      integrated address to decode

      +
      +
    +

    Returns Promise<MoneroIntegratedAddress>

    the decoded integrated address including standard address and payment id

    + +
+
+ +
    + +
  • +

    Delete an address book entry.

    +
    +
    +

    Parameters

    +
      +
    • +
      entryIdx: number
      +

      index of the entry to delete

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Describe a tx set from multisig tx hex.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigTxHex: string
      +

      multisig tx hex

      +
      +
    +

    Returns Promise<MoneroTxSet>

    the tx set containing structured transactions

    + +
+
+ +
    + +
  • +

    Describe a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txSet: MoneroTxSet
      +

      a tx set containing unsigned or multisig tx hex

      +
      +
    +

    Returns Promise<MoneroTxSet>

    txSet - the tx set containing structured transactions

    + +
+
+ +
    + +
  • +

    Describe a tx set from unsigned tx hex.

    +
    +
    +

    Parameters

    +
      +
    • +
      unsignedTxHex: string
      +

      unsigned tx hex

      +
      +
    +

    Returns Promise<MoneroTxSet>

    the tx set containing structured transactions

    + +
+
+ +
    + +
  • +

    Edit an address book entry.

    +
    +
    +

    Parameters

    +
      +
    • +
      index: number
      +

      index of the address book entry to edit

      +
      +
    • +
    • +
      setAddress: boolean
      +

      specifies if the address should be updated

      +
      +
    • +
    • +
      address: string
      +

      updated address

      +
      +
    • +
    • +
      setDescription: boolean
      +

      specifies if the description should be updated

      +
      +
    • +
    • +
      description: string
      +

      updated description

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Exchange multisig hex with participants in a M/N multisig wallet.

    +

    This process must be repeated with participants exactly N-M times.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigHexes: string[]
      +

      are multisig hex from each participant

      +
      +
    • +
    • +
      password: string
      +

      wallet's password // TODO monero-project: redundant? wallet is created with password

      +
      +
    +

    Returns Promise<MoneroMultisigInitResult>

    the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done

    + +
+
+ +
    + +
  • +

    Export signed key images.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional all: boolean = false
      +

      export all key images if true, else export the key images since the last export (default false)

      +
      +
    +

    Returns Promise<MoneroKeyImage[]>

    the wallet's signed key images

    + +
+
+ +
    + +
  • +

    Export this wallet's multisig info as hex for other participants.

    +
    +

    Returns Promise<string>

    this wallet's multisig info as hex for other participants

    + +
+
+ +
    + +
  • +

    Export outputs in hex format.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional all: boolean = false
      +

      export all outputs if true, else export the outputs since the last export (default false)

      +
      +
    +

    Returns Promise<string>

    outputs in hex format

    + +
+
+ +
    + +
  • +

    Freeze an output.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image of the output to freeze

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Get an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to get

      +
      +
    • +
    • +
      Optional includeSubaddresses: boolean
      +

      include subaddresses if true

      +
      +
    +

    Returns Promise<MoneroAccount>

    the retrieved account

    + +
+
+ +
+
+ +
    + +
  • +

    Get accounts with a given tag.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional includeSubaddresses: boolean
      +

      include subaddresses if true

      +
      +
    • +
    • +
      Optional tag: string
      +

      tag for filtering accounts, all accounts if undefined

      +
      +
    +

    Returns Promise<MoneroAccount[]>

    all accounts with the given tag

    + +
+
+ +
    + +
  • +

    Get the address of a specific subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      the account index of the address's subaddress

      +
      +
    • +
    • +
      subaddressIdx: number
      +

      the subaddress index within the account

      +
      +
    +

    Returns Promise<string>

    the receive address of the specified subaddress

    + +
+
+ +
    + +
  • +

    Get address book entries.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional entryIndices: number[]
      +

      indices of the entries to get

      +
      +
    +

    Returns Promise<MoneroAddressBookEntry[]>

    the address book entries

    + +
+
+ +
    + +
  • +

    Get the account and subaddress index of the given address.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      address to get the account and subaddress index from

      +
      +
    +

    Returns Promise<MoneroSubaddress>

    the account and subaddress indices

    + +
+
+ +
    + +
  • +

    Get an attribute.

    +
    +
    +

    Parameters

    +
      +
    • +
      key: string
      +

      attribute to get the value of

      +
      +
    +

    Returns Promise<string>

    the attribute's value

    + +
+
+ +
    + +
  • +

    Get the balance of the wallet, account, or subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional accountIdx: number
      +

      index of the account to get the balance of (default all accounts)

      +
      +
    • +
    • +
      Optional subaddressIdx: number
      +

      index of the subaddress to get the balance of (default all subaddresses)

      +
      +
    +

    Returns Promise<bigint>

    the balance of the wallet, account, or subaddress

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get the blockchain's height.

    +
    +

    Returns Promise<number>

    the blockchain's height

    + +
+
+ +
    + +
  • +

    Get the current default fee priority (unimportant, normal, elevated, etc).

    +
    +

    Returns Promise<MoneroTxPriority>

    the current fee priority

    + +
+
+ +
    + +
  • +

    Get the block height that the wallet is synced to.

    +
    +

    Returns Promise<number>

    the block height that the wallet is synced to

    + +
+
+ +
    + +
  • +

    Get the blockchain's height by date as a conservative estimate for scanning.

    +
    +
    +

    Parameters

    +
      +
    • +
      year: number
      +

      year of the height to get

      +
      +
    • +
    • +
      month: number
      +

      month of the height to get as a number between 1 and 12

      +
      +
    • +
    • +
      day: number
      +

      day of the height to get as a number between 1 and 31

      +
      +
    +

    Returns Promise<number>

    the blockchain's approximate height at the given date

    + +
+
+ +
+
+ +
    + +
  • +

    Get an integrated address based on the given standard address and payment +ID. Uses the wallet's primary address if an address is not given. +Generates a random payment ID if a payment ID is not given.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional standardAddress: string
      +

      is the standard address to generate the integrated address from (wallet's primary address if undefined)

      +
      +
    • +
    • +
      Optional paymentId: string
      +

      is the payment ID to generate an integrated address from (randomly generated if undefined)

      +
      +
    +

    Returns Promise<MoneroIntegratedAddress>

    the integrated address

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get new key images from the last imported outputs.

    +
    +

    Returns Promise<MoneroKeyImage[]>

    the key images from the last imported outputs

    + +
+
+ +
    + +
  • +

    Get the number of blocks until the next and last funds unlock. Ignores txs with unlock time as timestamp.

    +
    +

    Returns Promise<number[]>

    the number of blocks until the next and last funds unlock in elements 0 and 1, respectively, or undefined if no balance

    + +
+
+ +
+
+ +
    + +
  • +

    Get outputs created from previous transactions that belong to the wallet +(i.e. that the wallet can spend one time). Outputs are part of +transactions which are stored in blocks on the blockchain.

    + +

    Results can be filtered by passing a query object. Outputs must +meet every criteria defined in the query in order to be returned. All +filtering is optional and no filtering is applied when not defined.

    +
    +

    Parameters

    +
    +

    Returns Promise<MoneroOutputWallet[]>

    the queried outputs

    + +
+
+ +
    + +
  • +

    Get the wallet's path.

    +
    +

    Returns Promise<string>

    the path the wallet can be opened with

    + +
+
+ +
    + +
  • +

    Creates a payment URI from a send configuration.

    +
    +
    +

    Parameters

    +
      +
    • +
      config: MoneroTxConfig
      +

      specifies configuration for a potential tx

      +
      +
    +

    Returns Promise<string>

    the payment uri

    + +
+
+ +
    + +
  • +

    Get the wallet's primary address.

    +
    +

    Returns Promise<string>

    the wallet's primary address

    + +
+
+ +
    + +
  • +

    Get the wallet's private spend key.

    +
    +

    Returns Promise<string>

    the wallet's private spend key

    + +
+
+ +
    + +
  • +

    Get the wallet's private view key.

    +
    +

    Returns Promise<string>

    the wallet's private view key

    + +
+
+ +
    + +
  • +

    Get the wallet's public spend key.

    +
    +

    Returns Promise<string>

    the wallet's public spend key

    + +
+
+ +
    + +
  • +

    Get the wallet's public view key.

    +
    +

    Returns Promise<string>

    the wallet's public view key

    + +
+
+ +
    + +
  • +

    Generate a signature to prove an available amount in an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      account to prove ownership of the amount

      +
      +
    • +
    • +
      amount: bigint
      +

      minimum amount to prove as available in the account

      +
      +
    • +
    • +
      Optional message: string
      +

      message to include with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the reserve proof signature

    + +
+
+ +
    + +
  • +

    Generate a signature to prove the entire balance of the wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional message: string
      +

      message included with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the reserve proof signature

    + +
+
+ +
    + +
  • +

    Get the wallet's mnemonic phrase or seed.

    +
    +

    Returns Promise<string>

    the wallet's mnemonic phrase or seed.

    + +
+
+ +
    + +
  • +

    Get the language of the wallet's mnemonic phrase or seed.

    +
    +

    Returns Promise<string>

    the language of the wallet's mnemonic phrase or seed.

    + +
+
+ +
    + +
  • +

    Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      Optional message: string
      +

      message to include with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the transaction signature

    + +
+
+ +
    + +
  • +

    Get a subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the subaddress's account

      +
      +
    • +
    • +
      subaddressIdx: number
      +

      index of the subaddress within the account

      +
      +
    +

    Returns Promise<MoneroSubaddress>

    the retrieved subaddress

    + +
+
+ +
    + +
  • +

    Get subaddresses in an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      account to get subaddresses within

      +
      +
    • +
    • +
      Optional subaddressIndices: number[]
      +

      indices of subaddresses to get (optional)

      +
      +
    +

    Returns Promise<MoneroSubaddress[]>

    the retrieved subaddresses

    + +
+
+ +
    + +
  • +

    Get incoming and outgoing transfers to and from this wallet. An outgoing +transfer represents a total amount sent from one or more subaddresses +within an account to individual destination addresses, each with their +own amount. An incoming transfer represents a total amount received into +a subaddress within an account. Transfers belong to transactions which +are stored on the blockchain.

    + +

    Results can be filtered by passing a query object. Transfers must +meet every criteria defined in the query in order to be returned. All +criteria are optional and no filtering is applied when not defined.

    +
    +

    Parameters

    +
    +

    Returns Promise<MoneroTransfer[]>

    wallet transfers that meet the query

    + +
+
+ +
    + +
  • +

    Get a wallet transaction by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      hash of a transaction to get

      +
      +
    +

    Returns Promise<MoneroTxWallet>

    the identified transaction or undefined if not found

    + +
+
+ +
    + +
  • +

    Get a transaction's secret key from its hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction's hash

      +
      +
    +

    Returns Promise<string>

      +
    • transaction's secret key
    • +
    + +
+
+ +
    + +
  • +

    Get a transaction note.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to get the note of

      +
      +
    +

    Returns Promise<string>

    the tx note

    + +
+
+ +
    + +
  • +

    Get notes for multiple transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      hashes of the transactions to get notes for

      +
      +
    +

    Returns Promise<string[]>

    notes for the transactions

    + +
+
+ +
    + +
  • +

    Get a transaction signature to prove it.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      address: string
      +

      destination public address of the transaction

      +
      +
    • +
    • +
      Optional message: string
      +

      message to include with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the transaction signature

    + +
+
+ +
    + +
  • +

    Get wallet transactions. Wallet transactions contain one or more +transfers that are either incoming or outgoing to the wallet.

    + +

    Results can be filtered by passing a query object. Transactions must +meet every criteria defined in the query in order to be returned. All +criteria are optional and no filtering is applied when not defined.

    +
    +

    Parameters

    +
      +
    • +
      Optional query: string[] | Partial<MoneroTxQuery>
      +

      configures the query (optional)

      +
      +
    +

    Returns Promise<MoneroTxWallet[]>

    wallet transactions per the configuration

    + +
+
+ +
    + +
  • +

    Get the unlocked balance of the wallet, account, or subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional accountIdx: number
      +

      index of the account to get the unlocked balance of (optional)

      +
      +
    • +
    • +
      Optional subaddressIdx: number
      +

      index of the subaddress to get the unlocked balance of (optional)

      +
      +
    +

    Returns Promise<bigint>

    the unlocked balance of the wallet, account, or subaddress

    + +
+
+ +
    + +
  • +

    Gets the version of the wallet.

    +
    +

    Returns Promise<MoneroVersion>

    the version of the wallet

    + +
+
+ +
+
+ +
    + +
  • +

    Import multisig info as hex from other participants.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigHexes: string[]
      +

      multisig hex from each participant

      +
      +
    +

    Returns Promise<number>

    the number of outputs signed with the given multisig hex

    + +
+
+ +
    + +
  • +

    Import outputs in hex format.

    +
    +
    +

    Parameters

    +
      +
    • +
      outputsHex: string
      +

      outputs in hex format

      +
      +
    +

    Returns Promise<number>

    the number of outputs imported

    + +
+
+ +
    + +
  • +

    Indicates if this wallet is closed or not.

    +
    +

    Returns Promise<boolean>

    true if the wallet is closed, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the wallet is connected to daemon.

    +
    +

    Returns Promise<boolean>

    true if the wallet is connected to a daemon, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if this wallet is a multisig wallet.

    +
    +

    Returns Promise<boolean>

    true if this is a multisig wallet, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if importing multisig data is needed for returning a correct balance.

    +
    +

    Returns Promise<boolean>

    true if importing multisig data is needed for returning a correct balance, false otherwise

    + +
+
+ +
    + +
  • +

    Check if an output is frozen.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image of the output to check if frozen

      +
      +
    +

    Returns Promise<boolean>

    true if the output is frozen, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the wallet is view-only, meaning it does not have the private +spend key and can therefore only observe incoming outputs.

    +
    +

    Returns Promise<boolean>

    true if the wallet is view-only, false otherwise

    + +
+
+ +
    + +
  • +

    Make this wallet multisig by importing multisig hex from participants.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigHexes: string[]
      +

      multisig hex from each participant

      +
      +
    • +
    • +
      threshold: number
      +

      number of signatures needed to sign transfers

      +
      +
    • +
    • +
      password: string
      +

      wallet password

      +
      +
    +

    Returns Promise<string>

    this wallet's multisig hex to share with participants

    + +
+
+ +
    + +
  • +

    Parses a payment URI to a tx config.

    +
    +
    +

    Parameters

    +
      +
    • +
      uri: string
      +

      payment uri to parse

      +
      +
    +

    Returns Promise<MoneroTxConfig>

    the send configuration parsed from the uri

    + +
+
+ +
    + +
  • +

    Get multisig info as hex to share with participants to begin creating a +multisig wallet.

    +
    +

    Returns Promise<string>

    this wallet's multisig hex to share with participants

    + +
+
+ +
    + +
  • +

    Relay a previously created transaction.

    +
    +
    +

    Parameters

    +
      +
    • +
      txOrMetadata: string | MoneroTxWallet
      +

      transaction or its metadata to relay

      +
      +
    +

    Returns Promise<string>

    the hash of the relayed tx

    + +
+
+ +
    + +
  • +

    Relay previously created transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txsOrMetadatas: (string | MoneroTxWallet)[]
      +

      transactions or their metadata to relay

      +
      +
    +

    Returns Promise<string[]>

    the hashes of the relayed txs

    + +
+
+ +
    + +
  • +

    Unregister a listener to receive wallet notifications.

    +
    +
    +

    Parameters

    +
      +
    • +
      listener: any
      +

      listener to unregister

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Rescan the blockchain from scratch, losing any information which cannot be recovered from +the blockchain itself.

    + +

    WARNING: This method discards local wallet data like destination addresses, tx secret keys, +tx notes, etc.

    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Rescan the blockchain for spent outputs.

    + +

    Note: this can only be called with a trusted daemon.

    + +

    Example use case: peer multisig hex is import when connected to an untrusted daemon, +so the wallet will not rescan spent outputs. Then the wallet connects to a trusted +daemon. This method should be manually invoked to rescan outputs.

    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Save the wallet at its current path.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Scan transactions by their hash/id.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      tx hashes to scan

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set an account label.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to set the label for

      +
      +
    • +
    • +
      label: string
      +

      the label to set

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Sets a human-readable description for a tag.

    +
    +
    +

    Parameters

    +
      +
    • +
      tag: string
      +

      tag to set a description for

      +
      +
    • +
    • +
      label: string
      +

      label to set for the tag

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set an arbitrary attribute.

    +
    +
    +

    Parameters

    +
      +
    • +
      key: string
      +

      attribute key

      +
      +
    • +
    • +
      val: string
      +

      attribute value

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set the wallet's daemon connection manager.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set the wallet's daemon connection.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional uriOrConnection: string | MoneroRpcConnection
      +

      daemon's URI or connection (defaults to offline)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set a subaddress label.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to set the label for

      +
      +
    • +
    • +
      subaddressIdx: number
      +

      index of the subaddress to set the label for

      +
      +
    • +
    • +
      label: string
      +

      the label to set

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set a note for a specific transaction.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      hash of the transaction to set a note for

      +
      +
    • +
    • +
      note: string
      +

      the transaction note

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set notes for multiple transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      transactions to set notes for

      +
      +
    • +
    • +
      notes: string[]
      +

      notes to set for the transactions

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Sign a message.

    +
    +
    +

    Parameters

    +
      +
    • +
      message: string
      +

      the message to sign

      +
      +
    • +
    • +
      Optional signatureType: MoneroMessageSignatureType = MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY
      +

      sign with spend key or view key (default spend key)

      +
      +
    • +
    • +
      Optional accountIdx: number = 0
      +

      the account index of the message signature (default 0)

      +
      +
    • +
    • +
      Optional subaddressIdx: number = 0
      +

      the subaddress index of the message signature (default 0)

      +
      +
    +

    Returns Promise<string>

    the signature

    + +
+
+ +
    + +
  • +

    Sign multisig transactions from a multisig wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigTxHex: string
      +

      unsigned multisig transactions as hex

      +
      +
    +

    Returns Promise<MoneroMultisigSignResult>

    the result of signing the multisig transactions

    + +
+
+ +
    + +
  • +

    Sign unsigned transactions from a view-only wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      unsignedTxHex: string
      +

      unsigned transaction hex from when the transactions were created

      +
      +
    +

    Returns Promise<MoneroTxSet>

    the signed transaction set

    + +
+
+ +
    + +
  • +

    Start mining.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional numThreads: number
      +

      number of threads created for mining (optional)

      +
      +
    • +
    • +
      Optional backgroundMining: boolean
      +

      specifies if mining should occur in the background (optional)

      +
      +
    • +
    • +
      Optional ignoreBattery: boolean
      +

      specifies if the battery should be ignored for mining (optional)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Start background synchronizing with a maximum period between syncs.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional syncPeriodInMs: number
      +

      maximum period between syncs in milliseconds (default is wallet-specific)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Stop mining.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Stop synchronizing the wallet with the daemon.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Submit signed multisig transactions from a multisig wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      signedMultisigTxHex: string
      +

      signed multisig hex returned from signMultisigTxHex()

      +
      +
    +

    Returns Promise<string[]>

    the resulting transaction hashes

    + +
+
+ +
    + +
  • +

    Submit signed transactions from a view-only wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      signedTxHex: string
      +

      signed transaction hex from signTxs()

      +
      +
    +

    Returns Promise<string[]>

    the resulting transaction hashes

    + +
+
+ +
    + +
  • +

    Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

    + +

    NOTE: Dust only exists pre RCT, so this method will throw "no dust to sweep" on new wallets.

    +
    +

    Parameters

    +
      +
    • +
      Optional relay: boolean
      +

      specifies if the resulting transaction should be relayed (default false)

      +
      +
    +

    Returns Promise<MoneroTxWallet[]>

    the created transactions

    + +
+
+ +
    + +
  • +

    Sweep an output by key image.

    +
    +
    +

    Parameters

    +
      +
    • +
      config: Partial<MoneroTxConfig>
      +

      configures the transaction to create (required)

      +
      +
    +

    Returns Promise<MoneroTxWallet>

    the created transaction

    + +
+
+ +
    + +
  • +

    Sweep all unlocked funds according to the given configuration.

    +
    +
    +

    Parameters

    +
      +
    • +
      config: Partial<MoneroTxConfig>
      +

      configures the transactions to create (required)

      +
      +
    +

    Returns Promise<MoneroTxWallet[]>

    the created transactions

    + +
+
+ +
    + +
  • +

    Synchronize the wallet with the daemon as a one-time synchronous process.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional listenerOrStartHeight: number | MoneroWalletListener
      +

      listener xor start height (defaults to no sync listener, the last synced block)

      +
      +
    • +
    • +
      Optional startHeight: number
      +

      startHeight if not given in first arg (defaults to last synced block)

      +
      +
    +

    Returns Promise<MoneroSyncResult>

    +
+
+ +
    + +
  • +

    Tag accounts.

    +
    +
    +

    Parameters

    +
      +
    • +
      tag: string
      +

      tag to apply to the specified accounts

      +
      +
    • +
    • +
      accountIndices: number[]
      +

      indices of the accounts to tag

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Thaw a frozen output.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image of the output to thaw

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Untag accounts.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIndices: number[]
      +

      indices of the accounts to untag

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Verify a signature on a message.

    +
    +
    +

    Parameters

    +
      +
    • +
      message: string
      +

      signed message

      +
      +
    • +
    • +
      address: string
      +

      signing address

      +
      +
    • +
    • +
      signature: string
      +

      signature

      +
      +
    +

    Returns Promise<MoneroMessageSignatureResult>

    true if the signature is good, false otherwise

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroWalletConfig.html b/docs/typedocs/classes/MoneroWalletConfig.html new file mode 100644 index 000000000..93dbad130 --- /dev/null +++ b/docs/typedocs/classes/MoneroWalletConfig.html @@ -0,0 +1,714 @@ +MoneroWalletConfig | monero-ts
+
+ +
+
+
+
+ +

Class MoneroWalletConfig

+
+

Configuration to create a Monero wallet.

+
+
+
+

Hierarchy

+
    +
  • MoneroWalletConfig
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
accountLookahead: number
+

Number of accounts to scan (optional).

+
+
+
+ +
cacheData: Uint8Array
+

Wallet cache data to open.

+
+
+
+ +
cmd: string[]
+

Command to start monero-wallet-rpc as a child process.

+
+
+
+ +
connectionManager: MoneroConnectionManager
+

Govern the wallet's server connection.

+
+
+
+ +
fs: any
+

File system compatible with Node.js fs.promises API (defaults to disk or in-memory FS if browser).

+
+
+
+ +
isMultisig: boolean
+

Indicates if the wallet seed is multisig.

+
+
+
+ +
keysData: Uint8Array
+

Wallet keys data to open.

+
+
+
+ +
language: string
+

Language of the wallet's seed phrase (defaults to "English" or auto-detected).

+
+
+
+ +
networkType: MoneroNetworkType
+

Network type of the wallet to open or create.

+
+
+
+ +
password: string
+

Password of the wallet to open or create.

+
+
+
+ +
path: string
+

Path to the wallet to open or create.

+
+
+
+ +
primaryAddress: string
+

Primary address of the wallet to create (only provide if restoring from keys).

+
+
+
+ +
privateSpendKey: string
+

Private spend key of the wallet to create.

+
+
+
+ +
privateViewKey: string
+

Private view key of the wallet to create.

+
+
+
+ +
proxyToWorker: boolean
+

Proxies wallet operations to a worker in order to not block the main thread (default true).

+
+
+
+ +
restoreHeight: number
+

Block height to start scanning from (defaults to 0 unless generating random wallet).

+
+
+
+ +
saveCurrent: boolean
+

Specifies if the currently open RPC wallet should be saved before being closed.

+
+
+
+ +
seed: string
+

Seed of the wallet to ceate (random wallet created if neither seed nor keys given).

+
+
+
+ +
seedOffset: string
+

Offset to derive a new seed from the given seed to recover a secret wallet.

+
+
+
+ +
server: string | Partial<MoneroRpcConnection>
+

Server config to monerod or monero-wallet-rpc.

+
+
+
+ +
subaddressLookahead: number
+

Number of subaddresses to scan per account (optional).

+
+
+
+

Methods

+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns Uint8Array

+
+ +
+
+ +
    + +
  • +

    Returns any

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns Uint8Array

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
+
+ +
    + +
  • +

    Returns number

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Returns any

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroWalletFull.html b/docs/typedocs/classes/MoneroWalletFull.html new file mode 100644 index 000000000..39223d87c --- /dev/null +++ b/docs/typedocs/classes/MoneroWalletFull.html @@ -0,0 +1,3083 @@ +MoneroWalletFull | monero-ts
+
+ +
+
+
+
+ +

Class MoneroWalletFull

+
+

Implements a Monero wallet using client-side WebAssembly bindings to monero-project's wallet2 in C++.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Methods

+
addAddressBookEntry +addListener +assertNotClosed +backgroundSync +changePassword +checkReserveProof +checkSpendProof +checkTxKey +checkTxProof +close +createAccount +createSubaddress +createTx +createTxs +decodeIntegratedAddress +deleteAddressBookEntry +describeMultisigTxSet +describeTxSet +describeUnsignedTxSet +editAddressBookEntry +exchangeMultisigKeys +exportKeyImages +exportMultisigHex +exportOutputs +freezeOutput +getAccount +getAccountTags +getAccounts +getAddress +getAddressBookEntries +getAddressIndex +getAttribute +getBalance +getConnectionManager +getDaemonConnection +getDaemonHeight +getDaemonMaxPeerHeight +getData +getDefaultFeePriority +getHeight +getHeightByDate +getIncomingTransfers +getIntegratedAddress +getListeners +getMultisigInfo +getNetworkType +getNewKeyImagesFromLastImport +getNumBlocksToUnlock +getOutgoingTransfers +getOutputs +getPath +getPaymentUri +getPrimaryAddress +getPrivateSpendKey +getPrivateViewKey +getPublicSpendKey +getPublicViewKey +getReserveProofAccount +getReserveProofWallet +getRestoreHeight +getSeed +getSeedLanguage +getSpendProof +getSubaddress +getSubaddresses +getTransfers +getTx +getTxKey +getTxNote +getTxNotes +getTxProof +getTxs +getUnlockedBalance +getVersion +getWalletProxy +importKeyImages +importMultisigHex +importOutputs +isClosed +isConnectedToDaemon +isDaemonSynced +isMultisig +isMultisigImportNeeded +isOutputFrozen +isSynced +isViewOnly +makeMultisig +moveTo +parsePaymentUri +prepareMultisig +refreshListening +relayTx +relayTxs +removeListener +rescanBlockchain +rescanSpent +save +scanTxs +setAccountLabel +setAccountTagLabel +setAttribute +setBrowserMainPath +setConnectionManager +setDaemonConnection +setRestoreHeight +setSubaddressLabel +setTxNote +setTxNotes +signMessage +signMultisigTxHex +signTxs +startMining +startSyncing +stopMining +stopSyncing +submitMultisigTxHex +submitTxs +sweepDust +sweepOutput +sweepUnlocked +sync +tagAccounts +thawOutput +untagAccounts +verifyMessage +createWallet +createWalletFromKeys +createWalletFromSeed +createWalletRandom +deserializeBlocks +deserializeOutputs +deserializeTransfers +deserializeTxs +getFs +getSeedLanguages +moveTo +normalizeCreateTxsConfig +normalizeOutputQuery +normalizeSweepOutputConfig +normalizeSweepUnlockedConfig +normalizeTransferQuery +normalizeTxQuery +openWallet +openWalletData +sanitizeAccount +sanitizeBlock +sanitizeSubaddress +sanitizeTxWallet +save +walletExists +
+
+

Properties

+
+ +
_isClosed: boolean = false
+
+ +
browserMainPath: string
+
+ +
connectionManager: MoneroConnectionManager
+
+ +
connectionManagerListener: MoneroConnectionManagerListener
+
+ +
cppAddress: string
+
+ +
fs: any
+
+ +
+
+ +
module: any
+
+ +
password: string
+
+ +
path: string
+
+ +
rejectUnauthorized: boolean
+
+ +
rejectUnauthorizedConfigId: string
+
+ +
syncLooper: TaskLooper
+
+ +
syncPeriodInMs: number
+
+ +
walletProxy: MoneroWalletKeysProxy
+
+ +
wasmListener: WalletWasmListener
+
+ +
wasmListenerHandle: number
+
+ +
DEFAULT_LANGUAGE: "English" = "English"
+
+ +
DEFAULT_SYNC_PERIOD_IN_MS: 20000 = 20000
+
+ +
FS: any
+
+

Methods

+
+ +
    + +
  • +

    Add an address book entry.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      entry address

      +
      +
    • +
    • +
      Optional description: string
      +

      entry description (optional)

      +
      +
    +

    Returns Promise<number>

    the index of the added entry

    + +
+
+ +
    + +
  • +

    Register a listener to receive wallet notifications.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+ +
+
+ +
    + +
  • +

    Returns Promise<void>

+
+ +
    + +
  • +

    Change the wallet password.

    +
    +
    +

    Parameters

    +
      +
    • +
      oldPassword: string
      +

      the wallet's old password

      +
      +
    • +
    • +
      newPassword: string
      +

      the wallet's new password

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Proves a wallet has a disposable reserve using a signature.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      public wallet address

      +
      +
    • +
    • +
      message: string
      +

      message included with the signature to further authenticate the proof (optional)

      +
      +
    • +
    • +
      signature: string
      +

      reserve proof signature to check

      +
      +
    +

    Returns Promise<MoneroCheckReserve>

    the result of checking the signature proof

    + +
+
+ +
    + +
  • +

    Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      message: string
      +

      message included with the signature to further authenticate the proof (optional)

      +
      +
    • +
    • +
      signature: string
      +

      transaction signature to confirm

      +
      +
    +

    Returns Promise<boolean>

    true if the signature is good, false otherwise

    + +
+
+ +
    + +
  • +

    Check a transaction in the blockchain with its secret key.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to check

      +
      +
    • +
    • +
      txKey: string
      +

      transaction's secret key

      +
      +
    • +
    • +
      address: string
      +

      destination public address of the transaction

      +
      +
    +

    Returns Promise<MoneroCheckTx>

    the result of the check

    + +
+
+ +
    + +
  • +

    Prove a transaction by checking its signature.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      address: string
      +

      destination public address of the transaction

      +
      +
    • +
    • +
      message: string
      +

      message included with the signature to further authenticate the proof

      +
      +
    • +
    • +
      signature: string
      +

      transaction signature to confirm

      +
      +
    +

    Returns Promise<MoneroCheckTx>

    the result of the check

    + +
+
+ +
    + +
  • +

    Optionally save then close the wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      save: boolean = false
      +

      specifies if the wallet should be saved before being closed (default false)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Create a new account with a label for the first subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional label: string
      +

      label for account's first subaddress (optional)

      +
      +
    +

    Returns Promise<MoneroAccount>

    the created account

    + +
+
+ +
    + +
  • +

    Create a subaddress within an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to create the subaddress within

      +
      +
    • +
    • +
      Optional label: string
      +

      the label for the subaddress (optional)

      +
      +
    +

    Returns Promise<MoneroSubaddress>

    the created subaddress

    + +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Delete an address book entry.

    +
    +
    +

    Parameters

    +
      +
    • +
      entryIdx: number
      +

      index of the entry to delete

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Describe a tx set from multisig tx hex.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigTxHex: string
      +

      multisig tx hex

      +
      +
    +

    Returns Promise<MoneroTxSet>

    the tx set containing structured transactions

    + +
+
+ +
    + +
  • +

    Describe a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txSet: MoneroTxSet
      +

      a tx set containing unsigned or multisig tx hex

      +
      +
    +

    Returns Promise<MoneroTxSet>

    txSet - the tx set containing structured transactions

    + +
+
+ +
    + +
  • +

    Describe a tx set from unsigned tx hex.

    +
    +
    +

    Parameters

    +
      +
    • +
      unsignedTxHex: string
      +

      unsigned tx hex

      +
      +
    +

    Returns Promise<MoneroTxSet>

    the tx set containing structured transactions

    + +
+
+ +
    + +
  • +

    Edit an address book entry.

    +
    +
    +

    Parameters

    +
      +
    • +
      index: number
      +

      index of the address book entry to edit

      +
      +
    • +
    • +
      setAddress: boolean
      +

      specifies if the address should be updated

      +
      +
    • +
    • +
      address: string
      +

      updated address

      +
      +
    • +
    • +
      setDescription: boolean
      +

      specifies if the description should be updated

      +
      +
    • +
    • +
      description: string
      +

      updated description

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Exchange multisig hex with participants in a M/N multisig wallet.

    +

    This process must be repeated with participants exactly N-M times.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigHexes: string[]
      +

      are multisig hex from each participant

      +
      +
    • +
    • +
      password: string
      +

      wallet's password // TODO monero-project: redundant? wallet is created with password

      +
      +
    +

    Returns Promise<MoneroMultisigInitResult>

    the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done

    + +
+
+ +
    + +
  • +

    Export signed key images.

    +
    +
    +

    Parameters

    +
      +
    • +
      all: boolean = false
      +

      export all key images if true, else export the key images since the last export (default false)

      +
      +
    +

    Returns Promise<MoneroKeyImage[]>

    the wallet's signed key images

    + +
+
+ +
    + +
  • +

    Export this wallet's multisig info as hex for other participants.

    +
    +

    Returns Promise<string>

    this wallet's multisig info as hex for other participants

    + +
+
+ +
    + +
  • +

    Export outputs in hex format.

    +
    +
    +

    Parameters

    +
      +
    • +
      all: boolean = false
      +

      export all outputs if true, else export the outputs since the last export (default false)

      +
      +
    +

    Returns Promise<string>

    outputs in hex format

    + +
+
+ +
    + +
  • +

    Freeze an output.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image of the output to freeze

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Get an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to get

      +
      +
    • +
    • +
      Optional includeSubaddresses: boolean
      +

      include subaddresses if true

      +
      +
    +

    Returns Promise<MoneroAccount>

    the retrieved account

    + +
+
+ +
+
+ +
    + +
  • +

    Get accounts with a given tag.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional includeSubaddresses: boolean
      +

      include subaddresses if true

      +
      +
    • +
    • +
      Optional tag: string
      +

      tag for filtering accounts, all accounts if undefined

      +
      +
    +

    Returns Promise<MoneroAccount[]>

    all accounts with the given tag

    + +
+
+ +
    + +
  • +

    Get the address of a specific subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      the account index of the address's subaddress

      +
      +
    • +
    • +
      subaddressIdx: number
      +

      the subaddress index within the account

      +
      +
    +

    Returns Promise<string>

    the receive address of the specified subaddress

    + +
+
+ +
+
+ +
    + +
  • +

    Get the account and subaddress index of the given address.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      address to get the account and subaddress index from

      +
      +
    +

    Returns Promise<MoneroSubaddress>

    the account and subaddress indices

    + +
+
+ +
    + +
  • +

    Get an attribute.

    +
    +
    +

    Parameters

    +
      +
    • +
      key: string
      +

      attribute to get the value of

      +
      +
    +

    Returns Promise<string>

    the attribute's value

    + +
+
+ +
    + +
  • +

    Get the balance of the wallet, account, or subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional accountIdx: number
      +

      index of the account to get the balance of (default all accounts)

      +
      +
    • +
    • +
      Optional subaddressIdx: number
      +

      index of the subaddress to get the balance of (default all subaddresses)

      +
      +
    +

    Returns Promise<bigint>

    the balance of the wallet, account, or subaddress

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get the blockchain's height.

    +
    +

    Returns Promise<number>

    the blockchain's height

    + +
+
+ +
    + +
  • +

    Get the maximum height of the peers the wallet's daemon is connected to.

    +
    +

    Returns Promise<number>

    the maximum height of the peers the wallet's daemon is connected to

    + +
+
+ +
    + +
  • +

    Get the wallet's keys and cache data.

    +
    +

    Returns Promise<DataView[]>

    is the keys and cache data, respectively

    + +
+
+ +
+
+ +
    + +
  • +

    Get the block height that the wallet is synced to.

    +
    +

    Returns Promise<number>

    the block height that the wallet is synced to

    + +
+
+ +
    + +
  • +

    Get the blockchain's height by date as a conservative estimate for scanning.

    +
    +
    +

    Parameters

    +
      +
    • +
      year: number
      +

      year of the height to get

      +
      +
    • +
    • +
      month: number
      +

      month of the height to get as a number between 1 and 12

      +
      +
    • +
    • +
      day: number
      +

      day of the height to get as a number between 1 and 31

      +
      +
    +

    Returns Promise<number>

    the blockchain's approximate height at the given date

    + +
+
+ +
+
+ +
    + +
  • +

    Get an integrated address based on the given standard address and payment +ID. Uses the wallet's primary address if an address is not given. +Generates a random payment ID if a payment ID is not given.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional standardAddress: string
      +

      is the standard address to generate the integrated address from (wallet's primary address if undefined)

      +
      +
    • +
    • +
      Optional paymentId: string
      +

      is the payment ID to generate an integrated address from (randomly generated if undefined)

      +
      +
    +

    Returns Promise<MoneroIntegratedAddress>

    the integrated address

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get the wallet's network type (mainnet, testnet, or stagenet).

    +
    +

    Returns Promise<MoneroNetworkType>

    the wallet's network type

    + +
+
+ +
+
+ +
    + +
  • +

    Get the number of blocks until the next and last funds unlock. Ignores txs with unlock time as timestamp.

    +
    +

    Returns Promise<number[]>

    the number of blocks until the next and last funds unlock in elements 0 and 1, respectively, or undefined if no balance

    + +
+
+ +
+
+ +
    + +
  • +

    Get outputs created from previous transactions that belong to the wallet +(i.e. that the wallet can spend one time). Outputs are part of +transactions which are stored in blocks on the blockchain.

    + +

    Results can be filtered by passing a query object. Outputs must +meet every criteria defined in the query in order to be returned. All +filtering is optional and no filtering is applied when not defined.

    +
    +

    Parameters

    +
    +

    Returns Promise<MoneroOutputWallet[]>

    the queried outputs

    + +
+
+ +
    + +
  • +

    Returns Promise<string>

+
+ +
    + +
  • +

    Creates a payment URI from a send configuration.

    +
    +
    +

    Parameters

    +
      +
    • +
      config: MoneroTxConfig
      +

      specifies configuration for a potential tx

      +
      +
    +

    Returns Promise<string>

    the payment uri

    + +
+
+ +
    + +
  • +

    Get the wallet's primary address.

    +
    +

    Returns Promise<string>

    the wallet's primary address

    + +
+
+ +
    + +
  • +

    Get the wallet's private spend key.

    +
    +

    Returns Promise<string>

    the wallet's private spend key

    + +
+
+ +
    + +
  • +

    Get the wallet's private view key.

    +
    +

    Returns Promise<string>

    the wallet's private view key

    + +
+
+ +
    + +
  • +

    Get the wallet's public spend key.

    +
    +

    Returns Promise<string>

    the wallet's public spend key

    + +
+
+ +
    + +
  • +

    Get the wallet's public view key.

    +
    +

    Returns Promise<string>

    the wallet's public view key

    + +
+
+ +
    + +
  • +

    Generate a signature to prove an available amount in an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      account to prove ownership of the amount

      +
      +
    • +
    • +
      amount: bigint
      +

      minimum amount to prove as available in the account

      +
      +
    • +
    • +
      Optional message: string
      +

      message to include with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the reserve proof signature

    + +
+
+ +
    + +
  • +

    Generate a signature to prove the entire balance of the wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional message: string
      +

      message included with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the reserve proof signature

    + +
+
+ +
    + +
  • +

    Get the height of the first block that the wallet scans.

    +
    +

    Returns Promise<number>

    the height of the first block that the wallet scans

    + +
+
+ +
    + +
  • +

    Get the wallet's mnemonic phrase or seed.

    +
    +

    Returns Promise<string>

    the wallet's mnemonic phrase or seed.

    + +
+
+ +
    + +
  • +

    Get the language of the wallet's mnemonic phrase or seed.

    +
    +

    Returns Promise<string>

    the language of the wallet's mnemonic phrase or seed.

    + +
+
+ +
    + +
  • +

    Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      Optional message: string
      +

      message to include with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the transaction signature

    + +
+
+ +
    + +
  • +

    Get a subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the subaddress's account

      +
      +
    • +
    • +
      subaddressIdx: number
      +

      index of the subaddress within the account

      +
      +
    +

    Returns Promise<MoneroSubaddress>

    the retrieved subaddress

    + +
+
+ +
    + +
  • +

    Get subaddresses in an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      account to get subaddresses within

      +
      +
    • +
    • +
      Optional subaddressIndices: number[]
      +

      indices of subaddresses to get (optional)

      +
      +
    +

    Returns Promise<MoneroSubaddress[]>

    the retrieved subaddresses

    + +
+
+ +
    + +
  • +

    Get incoming and outgoing transfers to and from this wallet. An outgoing +transfer represents a total amount sent from one or more subaddresses +within an account to individual destination addresses, each with their +own amount. An incoming transfer represents a total amount received into +a subaddress within an account. Transfers belong to transactions which +are stored on the blockchain.

    + +

    Results can be filtered by passing a query object. Transfers must +meet every criteria defined in the query in order to be returned. All +criteria are optional and no filtering is applied when not defined.

    +
    +

    Parameters

    +
    +

    Returns Promise<MoneroTransfer[]>

    wallet transfers that meet the query

    + +
+
+ +
    + +
  • +

    Get a wallet transaction by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      hash of a transaction to get

      +
      +
    +

    Returns Promise<MoneroTxWallet>

    the identified transaction or undefined if not found

    + +
+
+ +
    + +
  • +

    Get a transaction's secret key from its hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction's hash

      +
      +
    +

    Returns Promise<string>

      +
    • transaction's secret key
    • +
    + +
+
+ +
    + +
  • +

    Get a transaction note.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to get the note of

      +
      +
    +

    Returns Promise<string>

    the tx note

    + +
+
+ +
    + +
  • +

    Get notes for multiple transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      hashes of the transactions to get notes for

      +
      +
    +

    Returns Promise<string[]>

    notes for the transactions

    + +
+
+ +
    + +
  • +

    Get a transaction signature to prove it.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      address: string
      +

      destination public address of the transaction

      +
      +
    • +
    • +
      Optional message: string
      +

      message to include with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the transaction signature

    + +
+
+ +
    + +
  • +

    Get wallet transactions. Wallet transactions contain one or more +transfers that are either incoming or outgoing to the wallet.

    + +

    Results can be filtered by passing a query object. Transactions must +meet every criteria defined in the query in order to be returned. All +criteria are optional and no filtering is applied when not defined.

    +
    +

    Parameters

    +
      +
    • +
      Optional query: string[] | Partial<MoneroTxQuery>
      +

      configures the query (optional)

      +
      +
    +

    Returns Promise<MoneroTxWallet[]>

    wallet transactions per the configuration

    + +
+
+ +
    + +
  • +

    Get the unlocked balance of the wallet, account, or subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional accountIdx: number
      +

      index of the account to get the unlocked balance of (optional)

      +
      +
    • +
    • +
      Optional subaddressIdx: number
      +

      index of the subaddress to get the unlocked balance of (optional)

      +
      +
    +

    Returns Promise<bigint>

    the unlocked balance of the wallet, account, or subaddress

    + +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Import multisig info as hex from other participants.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigHexes: string[]
      +

      multisig hex from each participant

      +
      +
    +

    Returns Promise<number>

    the number of outputs signed with the given multisig hex

    + +
+
+ +
    + +
  • +

    Import outputs in hex format.

    +
    +
    +

    Parameters

    +
      +
    • +
      outputsHex: string
      +

      outputs in hex format

      +
      +
    +

    Returns Promise<number>

    the number of outputs imported

    + +
+
+ +
    + +
  • +

    Indicates if this wallet is closed or not.

    +
    +

    Returns Promise<boolean>

    true if the wallet is closed, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the wallet is connected to daemon.

    +
    +

    Returns Promise<boolean>

    true if the wallet is connected to a daemon, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the wallet's daemon is synced with the network.

    +
    +

    Returns Promise<boolean>

    true if the daemon is synced with the network, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if this wallet is a multisig wallet.

    +
    +

    Returns Promise<boolean>

    true if this is a multisig wallet, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if importing multisig data is needed for returning a correct balance.

    +
    +

    Returns Promise<boolean>

    true if importing multisig data is needed for returning a correct balance, false otherwise

    + +
+
+ +
    + +
  • +

    Check if an output is frozen.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image of the output to check if frozen

      +
      +
    +

    Returns Promise<boolean>

    true if the output is frozen, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the wallet is synced with the daemon.

    +
    +

    Returns Promise<boolean>

    true if the wallet is synced with the daemon, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the wallet is view-only, meaning it does not have the private +spend key and can therefore only observe incoming outputs.

    +
    +

    Returns Promise<boolean>

    true if the wallet is view-only, false otherwise

    + +
+
+ +
    + +
  • +

    Make this wallet multisig by importing multisig hex from participants.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigHexes: string[]
      +

      multisig hex from each participant

      +
      +
    • +
    • +
      threshold: number
      +

      number of signatures needed to sign transfers

      +
      +
    • +
    • +
      password: string
      +

      wallet password

      +
      +
    +

    Returns Promise<string>

    this wallet's multisig hex to share with participants

    + +
+
+ +
    + +
  • +

    Move the wallet from its current path to the given path.

    +
    +
    +

    Parameters

    +
      +
    • +
      path: string
      +

      the wallet's destination path

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
+
+ +
    + +
  • +

    Get multisig info as hex to share with participants to begin creating a +multisig wallet.

    +
    +

    Returns Promise<string>

    this wallet's multisig hex to share with participants

    + +
+
+ +
    + +
  • +

    Returns Promise<any>

+
+ +
    + +
  • +

    Relay a previously created transaction.

    +
    +
    +

    Parameters

    +
      +
    • +
      txOrMetadata: string | MoneroTxWallet
      +

      transaction or its metadata to relay

      +
      +
    +

    Returns Promise<string>

    the hash of the relayed tx

    + +
+
+ +
    + +
  • +

    Relay previously created transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txsOrMetadatas: (string | MoneroTxWallet)[]
      +

      transactions or their metadata to relay

      +
      +
    +

    Returns Promise<string[]>

    the hashes of the relayed txs

    + +
+
+ +
    + +
  • +

    Unregister a listener to receive wallet notifications.

    +
    +
    +

    Parameters

    +
      +
    • +
      listener: any
      +

      listener to unregister

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Rescan the blockchain from scratch, losing any information which cannot be recovered from +the blockchain itself.

    + +

    WARNING: This method discards local wallet data like destination addresses, tx secret keys, +tx notes, etc.

    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Rescan the blockchain for spent outputs.

    + +

    Note: this can only be called with a trusted daemon.

    + +

    Example use case: peer multisig hex is import when connected to an untrusted daemon, +so the wallet will not rescan spent outputs. Then the wallet connects to a trusted +daemon. This method should be manually invoked to rescan outputs.

    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Save the wallet at its current path.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Scan transactions by their hash/id.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      tx hashes to scan

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set an account label.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to set the label for

      +
      +
    • +
    • +
      label: string
      +

      the label to set

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Sets a human-readable description for a tag.

    +
    +
    +

    Parameters

    +
      +
    • +
      tag: string
      +

      tag to set a description for

      +
      +
    • +
    • +
      label: string
      +

      label to set for the tag

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set an arbitrary attribute.

    +
    +
    +

    Parameters

    +
      +
    • +
      key: string
      +

      attribute key

      +
      +
    • +
    • +
      val: string
      +

      attribute value

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set the path of the wallet on the browser main thread if run as a worker.

    +
    +
    +

    Parameters

    +
      +
    • +
      browserMainPath: any
      +

      path of the wallet on the browser main thread

      +
      +
    +

    Returns void

    +
+
+ +
+
+ +
    + +
  • +

    Set the wallet's daemon connection.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional uriOrConnection: string | MoneroRpcConnection
      +

      daemon's URI or connection (defaults to offline)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set the height of the first block that the wallet scans.

    +
    +
    +

    Parameters

    +
      +
    • +
      restoreHeight: number
      +

      height of the first block that the wallet scans

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set a subaddress label.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to set the label for

      +
      +
    • +
    • +
      subaddressIdx: number
      +

      index of the subaddress to set the label for

      +
      +
    • +
    • +
      label: string
      +

      the label to set

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set a note for a specific transaction.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      hash of the transaction to set a note for

      +
      +
    • +
    • +
      note: string
      +

      the transaction note

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set notes for multiple transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      transactions to set notes for

      +
      +
    • +
    • +
      notes: string[]
      +

      notes to set for the transactions

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Sign a message.

    +
    +
    +

    Parameters

    +
      +
    • +
      message: string
      +

      the message to sign

      +
      +
    • +
    • +
      signatureType: MoneroMessageSignatureType = MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY
      +

      sign with spend key or view key (default spend key)

      +
      +
    • +
    • +
      accountIdx: number = 0
      +

      the account index of the message signature (default 0)

      +
      +
    • +
    • +
      subaddressIdx: number = 0
      +

      the subaddress index of the message signature (default 0)

      +
      +
    +

    Returns Promise<string>

    the signature

    + +
+
+ +
+
+ +
    + +
  • +

    Sign unsigned transactions from a view-only wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      unsignedTxHex: string
      +

      unsigned transaction hex from when the transactions were created

      +
      +
    +

    Returns Promise<MoneroTxSet>

    the signed transaction set

    + +
+
+ +
    + +
  • +

    Start mining.

    +
    +
    +

    Parameters

    +
      +
    • +
      numThreads: number
      +

      number of threads created for mining (optional)

      +
      +
    • +
    • +
      Optional backgroundMining: boolean
      +

      specifies if mining should occur in the background (optional)

      +
      +
    • +
    • +
      Optional ignoreBattery: boolean
      +

      specifies if the battery should be ignored for mining (optional)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Start background synchronizing with a maximum period between syncs.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional syncPeriodInMs: number
      +

      maximum period between syncs in milliseconds (default is wallet-specific)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
+
+ +
    + +
  • +

    Stop synchronizing the wallet with the daemon.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Submit signed multisig transactions from a multisig wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      signedMultisigTxHex: string
      +

      signed multisig hex returned from signMultisigTxHex()

      +
      +
    +

    Returns Promise<string[]>

    the resulting transaction hashes

    + +
+
+ +
    + +
  • +

    Submit signed transactions from a view-only wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      signedTxHex: string
      +

      signed transaction hex from signTxs()

      +
      +
    +

    Returns Promise<string[]>

    the resulting transaction hashes

    + +
+
+ +
    + +
  • +

    Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

    + +

    NOTE: Dust only exists pre RCT, so this method will throw "no dust to sweep" on new wallets.

    +
    +

    Parameters

    +
      +
    • +
      Optional relay: boolean
      +

      specifies if the resulting transaction should be relayed (default false)

      +
      +
    +

    Returns Promise<MoneroTxWallet[]>

    the created transactions

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Synchronize the wallet with the daemon as a one-time synchronous process.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional listenerOrStartHeight: number | MoneroWalletListener
      +

      listener xor start height (defaults to no sync listener, the last synced block)

      +
      +
    • +
    • +
      Optional startHeight: number
      +

      startHeight if not given in first arg (defaults to last synced block)

      +
      +
    • +
    • +
      Optional allowConcurrentCalls: boolean = false
      +

      allow other wallet methods to be processed simultaneously during sync (default false)

      WARNING: enabling this option will crash wallet execution if another call makes a simultaneous network request. TODO: possible to sync wasm network requests in http_client_wasm.cpp?

      +
      +
    +

    Returns Promise<MoneroSyncResult>

    +
+
+ +
    + +
  • +

    Tag accounts.

    +
    +
    +

    Parameters

    +
      +
    • +
      tag: string
      +

      tag to apply to the specified accounts

      +
      +
    • +
    • +
      accountIndices: number[]
      +

      indices of the accounts to tag

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Thaw a frozen output.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image of the output to thaw

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Untag accounts.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIndices: number[]
      +

      indices of the accounts to untag

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
+
+ +
    + +
  • +

    Create a wallet using WebAssembly bindings to monero-project.

    + +

    Example:

    + + +let wallet = await MoneroWalletKeys.createWallet({
    +   password: "abc123",
    +   networkType: MoneroNetworkType.STAGENET,
    +   seed: "coexist igloo pamphlet lagoon..."
    +}); +
    +
    +

    Parameters

    +
    +

    Returns Promise<MoneroWalletFull>

    the created wallet

    + +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      blocksJsonStr: any
    +

    Returns any

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      query: any
    • +
    • +
      blocksJsonStr: any
    +

    Returns any[]

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      query: any
    • +
    • +
      blocksJsonStr: any
    +

    Returns any[]

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      query: any
    • +
    • +
      blocksJsonStr: any
    +

    Returns any[]

+
+ +
    + +
  • +

    Returns any

+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      path: any
    • +
    • +
      wallet: any
    +

    Returns Promise<any>

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
    +

    Returns Promise<any>

+
+ +
    + +
  • +
    +

    Parameters

    +
    +

    Returns Promise<any>

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      account: any
    +

    Returns any

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      block: any
    +

    Returns any

+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      wallet: any
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Check if a wallet exists at a given path.

    +
    +
    +

    Parameters

    +
      +
    • +
      path: any
      +

      path of the wallet on the file system

      +
      +
    • +
    • +
      fs: any
      +

      file system compatible with Node.js fs.promises API (defaults to disk or in-memory FS if browser)

      +
      +
    +

    Returns Promise<boolean>

    true if a wallet exists at the given path, false otherwise

    + +
+
+ +
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroWalletKeys.html b/docs/typedocs/classes/MoneroWalletKeys.html new file mode 100644 index 000000000..c96ef88d1 --- /dev/null +++ b/docs/typedocs/classes/MoneroWalletKeys.html @@ -0,0 +1,2671 @@ +MoneroWalletKeys | monero-ts
+
+ +
+
+
+
+ +

Class MoneroWalletKeys

+
+

Implements a MoneroWallet which only manages keys using WebAssembly.

+
+
+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Methods

+
addAddressBookEntry +addListener +assertNotClosed +changePassword +checkReserveProof +checkSpendProof +checkTxKey +checkTxProof +close +createAccount +createSubaddress +createTx +createTxs +decodeIntegratedAddress +deleteAddressBookEntry +describeMultisigTxSet +describeTxSet +describeUnsignedTxSet +editAddressBookEntry +exchangeMultisigKeys +exportKeyImages +exportMultisigHex +exportOutputs +freezeOutput +getAccount +getAccountTags +getAccounts +getAddress +getAddressBookEntries +getAddressIndex +getAttribute +getBalance +getConnectionManager +getDaemonConnection +getDaemonHeight +getDefaultFeePriority +getHeight +getHeightByDate +getIncomingTransfers +getIntegratedAddress +getListeners +getMultisigInfo +getNewKeyImagesFromLastImport +getNumBlocksToUnlock +getOutgoingTransfers +getOutputs +getPaymentUri +getPrimaryAddress +getPrivateSpendKey +getPrivateViewKey +getPublicSpendKey +getPublicViewKey +getReserveProofAccount +getReserveProofWallet +getSeed +getSeedLanguage +getSpendProof +getSubaddress +getSubaddresses +getTransfers +getTx +getTxKey +getTxNote +getTxNotes +getTxProof +getTxs +getUnlockedBalance +getVersion +getWalletProxy +importKeyImages +importMultisigHex +importOutputs +isClosed +isConnectedToDaemon +isMultisig +isMultisigImportNeeded +isOutputFrozen +isViewOnly +makeMultisig +parsePaymentUri +prepareMultisig +relayTx +relayTxs +removeListener +rescanBlockchain +rescanSpent +save +scanTxs +setAccountLabel +setAccountTagLabel +setAttribute +setConnectionManager +setDaemonConnection +setSubaddressLabel +setTxNote +setTxNotes +signMessage +signMultisigTxHex +signTxs +startMining +startSyncing +stopMining +stopSyncing +submitMultisigTxHex +submitTxs +sweepDust +sweepOutput +sweepUnlocked +sync +tagAccounts +thawOutput +untagAccounts +verifyMessage +createWallet +createWalletFromKeys +createWalletFromSeed +createWalletRandom +getSeedLanguages +normalizeCreateTxsConfig +normalizeOutputQuery +normalizeSweepOutputConfig +normalizeSweepUnlockedConfig +normalizeTransferQuery +normalizeTxQuery +sanitizeSubaddress +
+
+

Properties

+
+ +
_isClosed: boolean = false
+
+ +
connectionManager: MoneroConnectionManager
+
+ +
connectionManagerListener: MoneroConnectionManagerListener
+
+ +
cppAddress: string
+
+ +
listeners: MoneroWalletListener[] = []
+
+ +
module: any
+
+ +
walletProxy: MoneroWalletKeysProxy
+
+ +
DEFAULT_LANGUAGE: "English" = "English"
+
+

Methods

+
+ +
    + +
  • +

    Add an address book entry.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      entry address

      +
      +
    • +
    • +
      Optional description: string
      +

      entry description (optional)

      +
      +
    +

    Returns Promise<number>

    the index of the added entry

    + +
+
+ +
    + +
  • +

    Register a listener to receive wallet notifications.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Returns void

+
+ +
    + +
  • +

    Change the wallet password.

    +
    +
    +

    Parameters

    +
      +
    • +
      oldPassword: string
      +

      the wallet's old password

      +
      +
    • +
    • +
      newPassword: string
      +

      the wallet's new password

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Proves a wallet has a disposable reserve using a signature.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      public wallet address

      +
      +
    • +
    • +
      message: string
      +

      message included with the signature to further authenticate the proof (optional)

      +
      +
    • +
    • +
      signature: string
      +

      reserve proof signature to check

      +
      +
    +

    Returns Promise<MoneroCheckReserve>

    the result of checking the signature proof

    + +
+
+ +
    + +
  • +

    Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      message: string
      +

      message included with the signature to further authenticate the proof (optional)

      +
      +
    • +
    • +
      signature: string
      +

      transaction signature to confirm

      +
      +
    +

    Returns Promise<boolean>

    true if the signature is good, false otherwise

    + +
+
+ +
    + +
  • +

    Check a transaction in the blockchain with its secret key.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to check

      +
      +
    • +
    • +
      txKey: string
      +

      transaction's secret key

      +
      +
    • +
    • +
      address: string
      +

      destination public address of the transaction

      +
      +
    +

    Returns Promise<MoneroCheckTx>

    the result of the check

    + +
+
+ +
    + +
  • +

    Prove a transaction by checking its signature.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      address: string
      +

      destination public address of the transaction

      +
      +
    • +
    • +
      message: string
      +

      message included with the signature to further authenticate the proof

      +
      +
    • +
    • +
      signature: string
      +

      transaction signature to confirm

      +
      +
    +

    Returns Promise<MoneroCheckTx>

    the result of the check

    + +
+
+ +
    + +
  • +

    Optionally save then close the wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      save: boolean = false
      +

      specifies if the wallet should be saved before being closed (default false)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Create a new account with a label for the first subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional label: string
      +

      label for account's first subaddress (optional)

      +
      +
    +

    Returns Promise<MoneroAccount>

    the created account

    + +
+
+ +
    + +
  • +

    Create a subaddress within an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to create the subaddress within

      +
      +
    • +
    • +
      Optional label: string
      +

      the label for the subaddress (optional)

      +
      +
    +

    Returns Promise<MoneroSubaddress>

    the created subaddress

    + +
+
+ +
+
+ +
    + +
  • +

    Create one or more transactions to transfer funds from this wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      config: Partial<MoneroTxConfig>
      +

      configures the transactions to create (required)

      +
      +
    +

    Returns Promise<MoneroTxWallet[]>

    the created transactions

    + +
+
+ +
    + +
  • +

    Decode an integrated address to get its standard address and payment id.

    +
    +
    +

    Parameters

    +
      +
    • +
      integratedAddress: string
      +

      integrated address to decode

      +
      +
    +

    Returns Promise<MoneroIntegratedAddress>

    the decoded integrated address including standard address and payment id

    + +
+
+ +
    + +
  • +

    Delete an address book entry.

    +
    +
    +

    Parameters

    +
      +
    • +
      entryIdx: number
      +

      index of the entry to delete

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Describe a tx set from multisig tx hex.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigTxHex: string
      +

      multisig tx hex

      +
      +
    +

    Returns Promise<MoneroTxSet>

    the tx set containing structured transactions

    + +
+
+ +
    + +
  • +

    Describe a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txSet: MoneroTxSet
      +

      a tx set containing unsigned or multisig tx hex

      +
      +
    +

    Returns Promise<MoneroTxSet>

    txSet - the tx set containing structured transactions

    + +
+
+ +
    + +
  • +

    Describe a tx set from unsigned tx hex.

    +
    +
    +

    Parameters

    +
      +
    • +
      unsignedTxHex: string
      +

      unsigned tx hex

      +
      +
    +

    Returns Promise<MoneroTxSet>

    the tx set containing structured transactions

    + +
+
+ +
    + +
  • +

    Edit an address book entry.

    +
    +
    +

    Parameters

    +
      +
    • +
      index: number
      +

      index of the address book entry to edit

      +
      +
    • +
    • +
      setAddress: boolean
      +

      specifies if the address should be updated

      +
      +
    • +
    • +
      address: string
      +

      updated address

      +
      +
    • +
    • +
      setDescription: boolean
      +

      specifies if the description should be updated

      +
      +
    • +
    • +
      description: string
      +

      updated description

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Exchange multisig hex with participants in a M/N multisig wallet.

    +

    This process must be repeated with participants exactly N-M times.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigHexes: string[]
      +

      are multisig hex from each participant

      +
      +
    • +
    • +
      password: string
      +

      wallet's password // TODO monero-project: redundant? wallet is created with password

      +
      +
    +

    Returns Promise<MoneroMultisigInitResult>

    the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done

    + +
+
+ +
    + +
  • +

    Export signed key images.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional all: boolean = false
      +

      export all key images if true, else export the key images since the last export (default false)

      +
      +
    +

    Returns Promise<MoneroKeyImage[]>

    the wallet's signed key images

    + +
+
+ +
    + +
  • +

    Export this wallet's multisig info as hex for other participants.

    +
    +

    Returns Promise<string>

    this wallet's multisig info as hex for other participants

    + +
+
+ +
    + +
  • +

    Export outputs in hex format.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional all: boolean = false
      +

      export all outputs if true, else export the outputs since the last export (default false)

      +
      +
    +

    Returns Promise<string>

    outputs in hex format

    + +
+
+ +
    + +
  • +

    Freeze an output.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image of the output to freeze

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Get an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to get

      +
      +
    • +
    • +
      Optional includeSubaddresses: boolean
      +

      include subaddresses if true

      +
      +
    +

    Returns Promise<MoneroAccount>

    the retrieved account

    + +
+
+ +
+
+ +
    + +
  • +

    Get accounts with a given tag.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional includeSubaddresses: boolean
      +

      include subaddresses if true

      +
      +
    • +
    • +
      Optional tag: string
      +

      tag for filtering accounts, all accounts if undefined

      +
      +
    +

    Returns Promise<MoneroAccount[]>

    all accounts with the given tag

    + +
+
+ +
    + +
  • +

    Get the address of a specific subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      the account index of the address's subaddress

      +
      +
    • +
    • +
      subaddressIdx: number
      +

      the subaddress index within the account

      +
      +
    +

    Returns Promise<string>

    the receive address of the specified subaddress

    + +
+
+ +
+
+ +
    + +
  • +

    Get the account and subaddress index of the given address.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      address to get the account and subaddress index from

      +
      +
    +

    Returns Promise<MoneroSubaddress>

    the account and subaddress indices

    + +
+
+ +
    + +
  • +

    Get an attribute.

    +
    +
    +

    Parameters

    +
      +
    • +
      key: string
      +

      attribute to get the value of

      +
      +
    +

    Returns Promise<string>

    the attribute's value

    + +
+
+ +
    + +
  • +

    Get the balance of the wallet, account, or subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional accountIdx: number
      +

      index of the account to get the balance of (default all accounts)

      +
      +
    • +
    • +
      Optional subaddressIdx: number
      +

      index of the subaddress to get the balance of (default all subaddresses)

      +
      +
    +

    Returns Promise<bigint>

    the balance of the wallet, account, or subaddress

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get the blockchain's height.

    +
    +

    Returns Promise<number>

    the blockchain's height

    + +
+
+ +
+
+ +
    + +
  • +

    Get the block height that the wallet is synced to.

    +
    +

    Returns Promise<number>

    the block height that the wallet is synced to

    + +
+
+ +
    + +
  • +

    Get the blockchain's height by date as a conservative estimate for scanning.

    +
    +
    +

    Parameters

    +
      +
    • +
      year: number
      +

      year of the height to get

      +
      +
    • +
    • +
      month: number
      +

      month of the height to get as a number between 1 and 12

      +
      +
    • +
    • +
      day: number
      +

      day of the height to get as a number between 1 and 31

      +
      +
    +

    Returns Promise<number>

    the blockchain's approximate height at the given date

    + +
+
+ +
+
+ +
    + +
  • +

    Get an integrated address based on the given standard address and payment +ID. Uses the wallet's primary address if an address is not given. +Generates a random payment ID if a payment ID is not given.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional standardAddress: string
      +

      is the standard address to generate the integrated address from (wallet's primary address if undefined)

      +
      +
    • +
    • +
      Optional paymentId: string
      +

      is the payment ID to generate an integrated address from (randomly generated if undefined)

      +
      +
    +

    Returns Promise<MoneroIntegratedAddress>

    the integrated address

    + +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get the number of blocks until the next and last funds unlock. Ignores txs with unlock time as timestamp.

    +
    +

    Returns Promise<number[]>

    the number of blocks until the next and last funds unlock in elements 0 and 1, respectively, or undefined if no balance

    + +
+
+ +
+
+ +
    + +
  • +

    Get outputs created from previous transactions that belong to the wallet +(i.e. that the wallet can spend one time). Outputs are part of +transactions which are stored in blocks on the blockchain.

    + +

    Results can be filtered by passing a query object. Outputs must +meet every criteria defined in the query in order to be returned. All +filtering is optional and no filtering is applied when not defined.

    +
    +

    Parameters

    +
    +

    Returns Promise<MoneroOutputWallet[]>

    the queried outputs

    + +
+
+ +
    + +
  • +

    Creates a payment URI from a send configuration.

    +
    +
    +

    Parameters

    +
      +
    • +
      config: MoneroTxConfig
      +

      specifies configuration for a potential tx

      +
      +
    +

    Returns Promise<string>

    the payment uri

    + +
+
+ +
    + +
  • +

    Get the wallet's primary address.

    +
    +

    Returns Promise<string>

    the wallet's primary address

    + +
+
+ +
    + +
  • +

    Get the wallet's private spend key.

    +
    +

    Returns Promise<string>

    the wallet's private spend key

    + +
+
+ +
    + +
  • +

    Get the wallet's private view key.

    +
    +

    Returns Promise<string>

    the wallet's private view key

    + +
+
+ +
    + +
  • +

    Get the wallet's public spend key.

    +
    +

    Returns Promise<string>

    the wallet's public spend key

    + +
+
+ +
    + +
  • +

    Get the wallet's public view key.

    +
    +

    Returns Promise<string>

    the wallet's public view key

    + +
+
+ +
    + +
  • +

    Generate a signature to prove an available amount in an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      account to prove ownership of the amount

      +
      +
    • +
    • +
      amount: bigint
      +

      minimum amount to prove as available in the account

      +
      +
    • +
    • +
      Optional message: string
      +

      message to include with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the reserve proof signature

    + +
+
+ +
    + +
  • +

    Generate a signature to prove the entire balance of the wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional message: string
      +

      message included with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the reserve proof signature

    + +
+
+ +
    + +
  • +

    Get the wallet's mnemonic phrase or seed.

    +
    +

    Returns Promise<string>

    the wallet's mnemonic phrase or seed.

    + +
+
+ +
    + +
  • +

    Get the language of the wallet's mnemonic phrase or seed.

    +
    +

    Returns Promise<string>

    the language of the wallet's mnemonic phrase or seed.

    + +
+
+ +
    + +
  • +

    Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      Optional message: string
      +

      message to include with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the transaction signature

    + +
+
+ +
    + +
  • +

    Get a subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the subaddress's account

      +
      +
    • +
    • +
      subaddressIdx: number
      +

      index of the subaddress within the account

      +
      +
    +

    Returns Promise<MoneroSubaddress>

    the retrieved subaddress

    + +
+
+ +
    + +
  • +

    Get subaddresses in an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      account to get subaddresses within

      +
      +
    • +
    • +
      Optional subaddressIndices: number[]
      +

      indices of subaddresses to get (optional)

      +
      +
    +

    Returns Promise<MoneroSubaddress[]>

    the retrieved subaddresses

    + +
+
+ +
    + +
  • +

    Get incoming and outgoing transfers to and from this wallet. An outgoing +transfer represents a total amount sent from one or more subaddresses +within an account to individual destination addresses, each with their +own amount. An incoming transfer represents a total amount received into +a subaddress within an account. Transfers belong to transactions which +are stored on the blockchain.

    + +

    Results can be filtered by passing a query object. Transfers must +meet every criteria defined in the query in order to be returned. All +criteria are optional and no filtering is applied when not defined.

    +
    +

    Parameters

    +
    +

    Returns Promise<MoneroTransfer[]>

    wallet transfers that meet the query

    + +
+
+ +
    + +
  • +

    Get a wallet transaction by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      hash of a transaction to get

      +
      +
    +

    Returns Promise<MoneroTxWallet>

    the identified transaction or undefined if not found

    + +
+
+ +
    + +
  • +

    Get a transaction's secret key from its hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction's hash

      +
      +
    +

    Returns Promise<string>

      +
    • transaction's secret key
    • +
    + +
+
+ +
    + +
  • +

    Get a transaction note.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to get the note of

      +
      +
    +

    Returns Promise<string>

    the tx note

    + +
+
+ +
    + +
  • +

    Get notes for multiple transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      hashes of the transactions to get notes for

      +
      +
    +

    Returns Promise<string[]>

    notes for the transactions

    + +
+
+ +
    + +
  • +

    Get a transaction signature to prove it.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      address: string
      +

      destination public address of the transaction

      +
      +
    • +
    • +
      Optional message: string
      +

      message to include with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the transaction signature

    + +
+
+ +
    + +
  • +

    Get wallet transactions. Wallet transactions contain one or more +transfers that are either incoming or outgoing to the wallet.

    + +

    Results can be filtered by passing a query object. Transactions must +meet every criteria defined in the query in order to be returned. All +criteria are optional and no filtering is applied when not defined.

    +
    +

    Parameters

    +
      +
    • +
      Optional query: string[] | Partial<MoneroTxQuery>
      +

      configures the query (optional)

      +
      +
    +

    Returns Promise<MoneroTxWallet[]>

    wallet transactions per the configuration

    + +
+
+ +
    + +
  • +

    Get the unlocked balance of the wallet, account, or subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional accountIdx: number
      +

      index of the account to get the unlocked balance of (optional)

      +
      +
    • +
    • +
      Optional subaddressIdx: number
      +

      index of the subaddress to get the unlocked balance of (optional)

      +
      +
    +

    Returns Promise<bigint>

    the unlocked balance of the wallet, account, or subaddress

    + +
+
+ +
+
+ +
    + +
  • +

    Returns MoneroWalletKeysProxy

+
+ +
+
+ +
    + +
  • +

    Import multisig info as hex from other participants.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigHexes: string[]
      +

      multisig hex from each participant

      +
      +
    +

    Returns Promise<number>

    the number of outputs signed with the given multisig hex

    + +
+
+ +
    + +
  • +

    Import outputs in hex format.

    +
    +
    +

    Parameters

    +
      +
    • +
      outputsHex: string
      +

      outputs in hex format

      +
      +
    +

    Returns Promise<number>

    the number of outputs imported

    + +
+
+ +
    + +
  • +

    Indicates if this wallet is closed or not.

    +
    +

    Returns Promise<boolean>

    true if the wallet is closed, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the wallet is connected to daemon.

    +
    +

    Returns Promise<boolean>

    true if the wallet is connected to a daemon, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if this wallet is a multisig wallet.

    +
    +

    Returns Promise<boolean>

    true if this is a multisig wallet, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if importing multisig data is needed for returning a correct balance.

    +
    +

    Returns Promise<boolean>

    true if importing multisig data is needed for returning a correct balance, false otherwise

    + +
+
+ +
    + +
  • +

    Check if an output is frozen.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image of the output to check if frozen

      +
      +
    +

    Returns Promise<boolean>

    true if the output is frozen, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the wallet is view-only, meaning it does not have the private +spend key and can therefore only observe incoming outputs.

    +
    +

    Returns Promise<boolean>

    true if the wallet is view-only, false otherwise

    + +
+
+ +
    + +
  • +

    Make this wallet multisig by importing multisig hex from participants.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigHexes: string[]
      +

      multisig hex from each participant

      +
      +
    • +
    • +
      threshold: number
      +

      number of signatures needed to sign transfers

      +
      +
    • +
    • +
      password: string
      +

      wallet password

      +
      +
    +

    Returns Promise<string>

    this wallet's multisig hex to share with participants

    + +
+
+ +
+
+ +
    + +
  • +

    Get multisig info as hex to share with participants to begin creating a +multisig wallet.

    +
    +

    Returns Promise<string>

    this wallet's multisig hex to share with participants

    + +
+
+ +
    + +
  • +

    Relay a previously created transaction.

    +
    +
    +

    Parameters

    +
      +
    • +
      txOrMetadata: string | MoneroTxWallet
      +

      transaction or its metadata to relay

      +
      +
    +

    Returns Promise<string>

    the hash of the relayed tx

    + +
+
+ +
    + +
  • +

    Relay previously created transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txsOrMetadatas: (string | MoneroTxWallet)[]
      +

      transactions or their metadata to relay

      +
      +
    +

    Returns Promise<string[]>

    the hashes of the relayed txs

    + +
+
+ +
    + +
  • +

    Unregister a listener to receive wallet notifications.

    +
    +
    +

    Parameters

    +
      +
    • +
      listener: any
      +

      listener to unregister

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Rescan the blockchain from scratch, losing any information which cannot be recovered from +the blockchain itself.

    + +

    WARNING: This method discards local wallet data like destination addresses, tx secret keys, +tx notes, etc.

    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Rescan the blockchain for spent outputs.

    + +

    Note: this can only be called with a trusted daemon.

    + +

    Example use case: peer multisig hex is import when connected to an untrusted daemon, +so the wallet will not rescan spent outputs. Then the wallet connects to a trusted +daemon. This method should be manually invoked to rescan outputs.

    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Save the wallet at its current path.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Scan transactions by their hash/id.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      tx hashes to scan

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set an account label.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to set the label for

      +
      +
    • +
    • +
      label: string
      +

      the label to set

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Sets a human-readable description for a tag.

    +
    +
    +

    Parameters

    +
      +
    • +
      tag: string
      +

      tag to set a description for

      +
      +
    • +
    • +
      label: string
      +

      label to set for the tag

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set an arbitrary attribute.

    +
    +
    +

    Parameters

    +
      +
    • +
      key: string
      +

      attribute key

      +
      +
    • +
    • +
      val: string
      +

      attribute value

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set the wallet's daemon connection manager.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set the wallet's daemon connection.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional uriOrConnection: string | MoneroRpcConnection
      +

      daemon's URI or connection (defaults to offline)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set a subaddress label.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to set the label for

      +
      +
    • +
    • +
      subaddressIdx: number
      +

      index of the subaddress to set the label for

      +
      +
    • +
    • +
      label: string
      +

      the label to set

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set a note for a specific transaction.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      hash of the transaction to set a note for

      +
      +
    • +
    • +
      note: string
      +

      the transaction note

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set notes for multiple transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      transactions to set notes for

      +
      +
    • +
    • +
      notes: string[]
      +

      notes to set for the transactions

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Sign a message.

    +
    +
    +

    Parameters

    +
      +
    • +
      message: string
      +

      the message to sign

      +
      +
    • +
    • +
      Optional signatureType: MoneroMessageSignatureType = MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY
      +

      sign with spend key or view key (default spend key)

      +
      +
    • +
    • +
      Optional accountIdx: number = 0
      +

      the account index of the message signature (default 0)

      +
      +
    • +
    • +
      Optional subaddressIdx: number = 0
      +

      the subaddress index of the message signature (default 0)

      +
      +
    +

    Returns Promise<string>

    the signature

    + +
+
+ +
+
+ +
    + +
  • +

    Sign unsigned transactions from a view-only wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      unsignedTxHex: string
      +

      unsigned transaction hex from when the transactions were created

      +
      +
    +

    Returns Promise<MoneroTxSet>

    the signed transaction set

    + +
+
+ +
    + +
  • +

    Start mining.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional numThreads: number
      +

      number of threads created for mining (optional)

      +
      +
    • +
    • +
      Optional backgroundMining: boolean
      +

      specifies if mining should occur in the background (optional)

      +
      +
    • +
    • +
      Optional ignoreBattery: boolean
      +

      specifies if the battery should be ignored for mining (optional)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Start background synchronizing with a maximum period between syncs.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional syncPeriodInMs: number
      +

      maximum period between syncs in milliseconds (default is wallet-specific)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Stop mining.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Stop synchronizing the wallet with the daemon.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Submit signed multisig transactions from a multisig wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      signedMultisigTxHex: string
      +

      signed multisig hex returned from signMultisigTxHex()

      +
      +
    +

    Returns Promise<string[]>

    the resulting transaction hashes

    + +
+
+ +
    + +
  • +

    Submit signed transactions from a view-only wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      signedTxHex: string
      +

      signed transaction hex from signTxs()

      +
      +
    +

    Returns Promise<string[]>

    the resulting transaction hashes

    + +
+
+ +
    + +
  • +

    Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

    + +

    NOTE: Dust only exists pre RCT, so this method will throw "no dust to sweep" on new wallets.

    +
    +

    Parameters

    +
      +
    • +
      Optional relay: boolean
      +

      specifies if the resulting transaction should be relayed (default false)

      +
      +
    +

    Returns Promise<MoneroTxWallet[]>

    the created transactions

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Synchronize the wallet with the daemon as a one-time synchronous process.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional listenerOrStartHeight: number | MoneroWalletListener
      +

      listener xor start height (defaults to no sync listener, the last synced block)

      +
      +
    • +
    • +
      Optional startHeight: number
      +

      startHeight if not given in first arg (defaults to last synced block)

      +
      +
    +

    Returns Promise<MoneroSyncResult>

    +
+
+ +
    + +
  • +

    Tag accounts.

    +
    +
    +

    Parameters

    +
      +
    • +
      tag: string
      +

      tag to apply to the specified accounts

      +
      +
    • +
    • +
      accountIndices: number[]
      +

      indices of the accounts to tag

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Thaw a frozen output.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image of the output to thaw

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Untag accounts.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIndices: number[]
      +

      indices of the accounts to untag

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
+
+ +
    + +
  • +

    Create a wallet using WebAssembly bindings to monero-project.

    + +

    Example:

    + + +let wallet = await MoneroWalletKeys.createWallet({
    +   password: "abc123",
    +   networkType: MoneroNetworkType.STAGENET,
    +   seed: "coexist igloo pamphlet lagoon..."
    +}); +
    +
    +

    Parameters

    +
      +
    • +
      config: Partial<MoneroWalletConfig>
      +

      MoneroWalletConfig or equivalent config object

      +
      +
    +

    Returns Promise<any>

    the created wallet

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
    +

    Returns Promise<any>

+
+ +
    + +
  • +
    +

    Parameters

    +
    +

    Returns Promise<any>

+
+ +
    + +
  • +
    +

    Parameters

    +
    +

    Returns Promise<any>

+
+ +
    + +
  • +

    Returns Promise<string[]>

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      subaddress: any
    +

    Returns any

+
+ +
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroWalletListener.html b/docs/typedocs/classes/MoneroWalletListener.html new file mode 100644 index 000000000..62658dfaa --- /dev/null +++ b/docs/typedocs/classes/MoneroWalletListener.html @@ -0,0 +1,217 @@ +MoneroWalletListener | monero-ts
+
+ +
+
+
+
+ +

Class MoneroWalletListener

+
+

Default wallet listener which takes no action on notifications.

+
+
+
+

Hierarchy

+
    +
  • MoneroWalletListener
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Methods

+
+ +
    + +
  • +

    Invoked when the wallet's balances change.

    +
    +
    +

    Parameters

    +
      +
    • +
      newBalance: bigint
      +

      new wallet balance

      +
      +
    • +
    • +
      newUnlockedBalance: bigint
      +

      new unlocked wallet balance

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Invoked when a new block is added to the chain.

    +
    +
    +

    Parameters

    +
      +
    • +
      height: number
      +

      the height of the new block (i.e. the number of blocks before it).

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Invoked 3 times per received output: once when unconfirmed, once when confirmed, and +once when unlocked.

    +

    The notified output includes basic fields only, so the output or its transaction should be fetched to get all available fields.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Invoked twice per spent output: once when confirmed and once when unlocked.

    +

    The notified output includes basic fields only, so the output or its transaction should be fetched to get all available fields.

    +
    +
    +

    Parameters

    +
      +
    • +
      output: any
      +

      the spent output

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Invoked as the wallet is synchronized.

    +
    +
    +

    Parameters

    +
      +
    • +
      height: number
      +

      height of the synced block

      +
      +
    • +
    • +
      startHeight: number
      +

      starting height of the sync request

      +
      +
    • +
    • +
      endHeight: number
      +

      ending height of the sync request

      +
      +
    • +
    • +
      percentDone: number
      +

      sync progress as a percentage

      +
      +
    • +
    • +
      message: string
      +

      human-readable description of the current progress

      +
      +
    +

    Returns Promise<void>

    +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/MoneroWalletRpc.html b/docs/typedocs/classes/MoneroWalletRpc.html new file mode 100644 index 000000000..44a7d0787 --- /dev/null +++ b/docs/typedocs/classes/MoneroWalletRpc.html @@ -0,0 +1,3354 @@ +MoneroWalletRpc | monero-ts
+
+ +
+
+
+
+ +

Class MoneroWalletRpc

+
+

Implements a MoneroWallet as a client of monero-wallet-rpc.

+
+
+

Implements

+
+

Hierarchy

+
+
+
+
+ +
+
+

Properties

+
+
+

Methods

+
addAddressBookEntry +addListener +changePassword +checkReserveProof +checkSpendProof +checkTxKey +checkTxProof +clear +close +createAccount +createSubaddress +createTx +createTxs +createWallet +createWalletFromKeys +createWalletFromSeed +createWalletRandom +decodeIntegratedAddress +deleteAddressBookEntry +describeMultisigTxSet +describeTxSet +describeUnsignedTxSet +editAddressBookEntry +exchangeMultisigKeys +exportKeyImages +exportMultisigHex +exportOutputs +freezeOutput +getAccount +getAccountIndices +getAccountTags +getAccounts +getAddress +getAddressBookEntries +getAddressIndex +getAttribute +getBalance +getBalances +getConnectionManager +getDaemonConnection +getDaemonHeight +getDefaultFeePriority +getHeight +getHeightByDate +getIncomingTransfers +getIntegratedAddress +getListeners +getMultisigInfo +getNewKeyImagesFromLastImport +getNumBlocksToUnlock +getOutgoingTransfers +getOutputs +getOutputsAux +getPath +getPaymentUri +getPrimaryAddress +getPrivateSpendKey +getPrivateViewKey +getProcess +getPublicSpendKey +getPublicViewKey +getReserveProofAccount +getReserveProofWallet +getRpcConnection +getSeed +getSeedLanguage +getSeedLanguages +getSpendProof +getSubaddress +getSubaddressIndices +getSubaddresses +getSyncPeriodInMs +getTransfers +getTransfersAux +getTx +getTxKey +getTxNote +getTxNotes +getTxProof +getTxs +getUnlockedBalance +getVersion +handleCreateWalletError +importKeyImages +importMultisigHex +importOutputs +isClosed +isConnectedToDaemon +isMultisig +isMultisigImportNeeded +isOutputFrozen +isViewOnly +makeMultisig +openWallet +parsePaymentUri +poll +prepareMultisig +refreshListening +relayTx +relayTxs +removeListener +rescanBlockchain +rescanSpent +rpcExportKeyImages +rpcSweepAccount +save +scanTxs +setAccountLabel +setAccountTagLabel +setAttribute +setConnectionManager +setDaemonConnection +setSubaddressLabel +setTxNote +setTxNotes +signMessage +signMultisigTxHex +signTxs +startMining +startSyncing +stop +stopMining +stopProcess +stopSyncing +submitMultisigTxHex +submitTxs +sweepDust +sweepOutput +sweepUnlocked +sync +tagAccounts +thawOutput +untagAccounts +verifyMessage +compareIncomingTransfers +compareOutputs +compareTxsByHeight +connectToWalletRpc +convertRpcAccount +convertRpcDescribeTransfer +convertRpcSentTxsToTxSet +convertRpcSubaddress +convertRpcTxSet +convertRpcTxToTxSet +convertRpcTxWalletWithOutput +convertRpcTxWithTransfer +decodeRpcType +decontextualize +initSentTxWallet +isContextual +mergeTx +normalizeConfig +normalizeCreateTxsConfig +normalizeOutputQuery +normalizeSweepOutputConfig +normalizeSweepUnlockedConfig +normalizeTransferQuery +normalizeTxQuery +startWalletRpcProcess +
+
+

Properties

+
+ +
_isClosed: boolean = false
+
+ +
addressCache: any
+
+ +
config: Partial<MoneroWalletConfig>
+
+ +
connectionManager: MoneroConnectionManager
+
+ +
connectionManagerListener: MoneroConnectionManagerListener
+
+ +
daemonConnection: MoneroRpcConnection
+
+ +
+
+ +
path: string
+
+ +
process: any
+
+ +
syncPeriodInMs: number
+
+ +
walletPoller: WalletPoller
+
+ +
DEFAULT_LANGUAGE: "English" = "English"
+
+ +
DEFAULT_SYNC_PERIOD_IN_MS: 20000 = 20000
+
+

Methods

+
+ +
    + +
  • +

    Add an address book entry.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      entry address

      +
      +
    • +
    • +
      Optional description: string
      +

      entry description (optional)

      +
      +
    +

    Returns Promise<number>

    the index of the added entry

    + +
+
+ +
    + +
  • +

    Register a listener to receive wallet notifications.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Change the wallet password.

    +
    +
    +

    Parameters

    +
      +
    • +
      oldPassword: string
      +

      the wallet's old password

      +
      +
    • +
    • +
      newPassword: string
      +

      the wallet's new password

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Proves a wallet has a disposable reserve using a signature.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      public wallet address

      +
      +
    • +
    • +
      message: string
      +

      message included with the signature to further authenticate the proof (optional)

      +
      +
    • +
    • +
      signature: string
      +

      reserve proof signature to check

      +
      +
    +

    Returns Promise<MoneroCheckReserve>

    the result of checking the signature proof

    + +
+
+ +
    + +
  • +

    Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      message: string
      +

      message included with the signature to further authenticate the proof (optional)

      +
      +
    • +
    • +
      signature: string
      +

      transaction signature to confirm

      +
      +
    +

    Returns Promise<boolean>

    true if the signature is good, false otherwise

    + +
+
+ +
    + +
  • +

    Check a transaction in the blockchain with its secret key.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to check

      +
      +
    • +
    • +
      txKey: string
      +

      transaction's secret key

      +
      +
    • +
    • +
      address: string
      +

      destination public address of the transaction

      +
      +
    +

    Returns Promise<MoneroCheckTx>

    the result of the check

    + +
+
+ +
    + +
  • +

    Prove a transaction by checking its signature.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      address: string
      +

      destination public address of the transaction

      +
      +
    • +
    • +
      message: string
      +

      message included with the signature to further authenticate the proof

      +
      +
    • +
    • +
      signature: string
      +

      transaction signature to confirm

      +
      +
    +

    Returns Promise<MoneroCheckTx>

    the result of the check

    + +
+
+ +
    + +
  • +

    Returns Promise<void>

+
+ +
    + +
  • +

    Optionally save then close the wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      save: boolean = false
      +

      specifies if the wallet should be saved before being closed (default false)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Create a new account with a label for the first subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional label: string
      +

      label for account's first subaddress (optional)

      +
      +
    +

    Returns Promise<MoneroAccount>

    the created account

    + +
+
+ +
    + +
  • +

    Create a subaddress within an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to create the subaddress within

      +
      +
    • +
    • +
      Optional label: string
      +

      the label for the subaddress (optional)

      +
      +
    +

    Returns Promise<MoneroSubaddress>

    the created subaddress

    + +
+
+ +
+
+ +
    + +
  • +

    Create one or more transactions to transfer funds from this wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      config: Partial<MoneroTxConfig>
      +

      configures the transactions to create (required)

      +
      +
    +

    Returns Promise<MoneroTxWallet[]>

    the created transactions

    + +
+
+ +
    + +
  • +

    Create and open a wallet on the monero-wallet-rpc server.

    + +

    Example:

    + + +// construct client to monero-wallet-rpc
    +let walletRpc = new MoneroWalletRpc("http://localhost:38084", "rpc_user", "abc123");

    + +

    // create and open wallet on monero-wallet-rpc
    +await walletRpc.createWallet({
    +   path: "mywallet",
    +   password: "abc123",
    +   seed: "coexist igloo pamphlet lagoon...",
    +   restoreHeight: 1543218l
    +}); +

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<MoneroWalletRpc>

    this wallet client

    + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Delete an address book entry.

    +
    +
    +

    Parameters

    +
      +
    • +
      entryIdx: number
      +

      index of the entry to delete

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Describe a tx set from multisig tx hex.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigTxHex: string
      +

      multisig tx hex

      +
      +
    +

    Returns Promise<MoneroTxSet>

    the tx set containing structured transactions

    + +
+
+ +
    + +
  • +

    Describe a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txSet: MoneroTxSet
      +

      a tx set containing unsigned or multisig tx hex

      +
      +
    +

    Returns Promise<MoneroTxSet>

    txSet - the tx set containing structured transactions

    + +
+
+ +
    + +
  • +

    Describe a tx set from unsigned tx hex.

    +
    +
    +

    Parameters

    +
      +
    • +
      unsignedTxHex: string
      +

      unsigned tx hex

      +
      +
    +

    Returns Promise<MoneroTxSet>

    the tx set containing structured transactions

    + +
+
+ +
    + +
  • +

    Edit an address book entry.

    +
    +
    +

    Parameters

    +
      +
    • +
      index: number
      +

      index of the address book entry to edit

      +
      +
    • +
    • +
      setAddress: boolean
      +

      specifies if the address should be updated

      +
      +
    • +
    • +
      address: string
      +

      updated address

      +
      +
    • +
    • +
      setDescription: boolean
      +

      specifies if the description should be updated

      +
      +
    • +
    • +
      description: string
      +

      updated description

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Exchange multisig hex with participants in a M/N multisig wallet.

    +

    This process must be repeated with participants exactly N-M times.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigHexes: string[]
      +

      are multisig hex from each participant

      +
      +
    • +
    • +
      password: string
      +

      wallet's password // TODO monero-project: redundant? wallet is created with password

      +
      +
    +

    Returns Promise<MoneroMultisigInitResult>

    the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done

    + +
+
+ +
    + +
  • +

    Export signed key images.

    +
    +
    +

    Parameters

    +
      +
    • +
      all: boolean = false
      +

      export all key images if true, else export the key images since the last export (default false)

      +
      +
    +

    Returns Promise<MoneroKeyImage[]>

    the wallet's signed key images

    + +
+
+ +
    + +
  • +

    Export this wallet's multisig info as hex for other participants.

    +
    +

    Returns Promise<string>

    this wallet's multisig info as hex for other participants

    + +
+
+ +
    + +
  • +

    Export outputs in hex format.

    +
    +
    +

    Parameters

    +
      +
    • +
      all: boolean = false
      +

      export all outputs if true, else export the outputs since the last export (default false)

      +
      +
    +

    Returns Promise<string>

    outputs in hex format

    + +
+
+ +
    + +
  • +

    Freeze an output.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image of the output to freeze

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Get an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to get

      +
      +
    • +
    • +
      Optional includeSubaddresses: boolean
      +

      include subaddresses if true

      +
      +
    • +
    • +
      Optional skipBalances: boolean
    +

    Returns Promise<MoneroAccount>

    the retrieved account

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      Optional getSubaddressIndices: any
    +

    Returns Promise<Map<any, any>>

+
+ +
+
+ +
    + +
  • +

    Get accounts with a given tag.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional includeSubaddresses: boolean
      +

      include subaddresses if true

      +
      +
    • +
    • +
      Optional tag: string
      +

      tag for filtering accounts, all accounts if undefined

      +
      +
    • +
    • +
      Optional skipBalances: boolean
    +

    Returns Promise<MoneroAccount[]>

    all accounts with the given tag

    + +
+
+ +
    + +
  • +

    Get the address of a specific subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      the account index of the address's subaddress

      +
      +
    • +
    • +
      subaddressIdx: number
      +

      the subaddress index within the account

      +
      +
    +

    Returns Promise<string>

    the receive address of the specified subaddress

    + +
+
+ +
+
+ +
    + +
  • +

    Get the account and subaddress index of the given address.

    +
    +
    +

    Parameters

    +
      +
    • +
      address: string
      +

      address to get the account and subaddress index from

      +
      +
    +

    Returns Promise<MoneroSubaddress>

    the account and subaddress indices

    + +
+
+ +
    + +
  • +

    Get an attribute.

    +
    +
    +

    Parameters

    +
      +
    • +
      key: string
      +

      attribute to get the value of

      +
      +
    +

    Returns Promise<string>

    the attribute's value

    + +
+
+ +
    + +
  • +

    Get the balance of the wallet, account, or subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional accountIdx: number
      +

      index of the account to get the balance of (default all accounts)

      +
      +
    • +
    • +
      Optional subaddressIdx: number
      +

      index of the subaddress to get the balance of (default all subaddresses)

      +
      +
    +

    Returns Promise<bigint>

    the balance of the wallet, account, or subaddress

    + +
+
+ +
    + +
  • +

    Get the total and unlocked balances in a single request.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional accountIdx: number
      +

      account index

      +
      +
    • +
    • +
      Optional subaddressIdx: number
      +

      subaddress index

      +
      +
    +

    Returns Promise<bigint[]>

    is the total and unlocked balances in an array, respectively

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get the blockchain's height.

    +
    +

    Returns Promise<number>

    the blockchain's height

    + +
+
+ +
+
+ +
    + +
  • +

    Get the block height that the wallet is synced to.

    +
    +

    Returns Promise<number>

    the block height that the wallet is synced to

    + +
+
+ +
    + +
  • +

    Get the blockchain's height by date as a conservative estimate for scanning.

    +
    +
    +

    Parameters

    +
      +
    • +
      year: number
      +

      year of the height to get

      +
      +
    • +
    • +
      month: number
      +

      month of the height to get as a number between 1 and 12

      +
      +
    • +
    • +
      day: number
      +

      day of the height to get as a number between 1 and 31

      +
      +
    +

    Returns Promise<number>

    the blockchain's approximate height at the given date

    + +
+
+ +
+
+ +
    + +
  • +

    Get an integrated address based on the given standard address and payment +ID. Uses the wallet's primary address if an address is not given. +Generates a random payment ID if a payment ID is not given.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional standardAddress: string
      +

      is the standard address to generate the integrated address from (wallet's primary address if undefined)

      +
      +
    • +
    • +
      Optional paymentId: string
      +

      is the payment ID to generate an integrated address from (randomly generated if undefined)

      +
      +
    +

    Returns Promise<MoneroIntegratedAddress>

    the integrated address

    + +
+
+ +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Get the number of blocks until the next and last funds unlock. Ignores txs with unlock time as timestamp.

    +
    +

    Returns Promise<number[]>

    the number of blocks until the next and last funds unlock in elements 0 and 1, respectively, or undefined if no balance

    + +
+
+ +
+
+ +
    + +
  • +

    Get outputs created from previous transactions that belong to the wallet +(i.e. that the wallet can spend one time). Outputs are part of +transactions which are stored in blocks on the blockchain.

    + +

    Results can be filtered by passing a query object. Outputs must +meet every criteria defined in the query in order to be returned. All +filtering is optional and no filtering is applied when not defined.

    +
    +

    Parameters

    +
    +

    Returns Promise<MoneroOutputWallet[]>

    the queried outputs

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      query: any
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +

    Get the wallet's path.

    +
    +

    Returns Promise<string>

    the path the wallet can be opened with

    + +
+
+ +
    + +
  • +

    Creates a payment URI from a send configuration.

    +
    +
    +

    Parameters

    +
      +
    • +
      config: MoneroTxConfig
      +

      specifies configuration for a potential tx

      +
      +
    +

    Returns Promise<string>

    the payment uri

    + +
+
+ +
    + +
  • +

    Get the wallet's primary address.

    +
    +

    Returns Promise<string>

    the wallet's primary address

    + +
+
+ +
    + +
  • +

    Get the wallet's private spend key.

    +
    +

    Returns Promise<string>

    the wallet's private spend key

    + +
+
+ +
    + +
  • +

    Get the wallet's private view key.

    +
    +

    Returns Promise<string>

    the wallet's private view key

    + +
+
+ +
    + +
  • +

    Get the internal process running monero-wallet-rpc.

    +
    +

    Returns ChildProcess

    the process running monero-wallet-rpc, undefined if not created from new process

    + +
+
+ +
    + +
  • +

    Get the wallet's public spend key.

    +
    +

    Returns Promise<string>

    the wallet's public spend key

    + +
+
+ +
    + +
  • +

    Get the wallet's public view key.

    +
    +

    Returns Promise<string>

    the wallet's public view key

    + +
+
+ +
    + +
  • +

    Generate a signature to prove an available amount in an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      account to prove ownership of the amount

      +
      +
    • +
    • +
      amount: bigint
      +

      minimum amount to prove as available in the account

      +
      +
    • +
    • +
      Optional message: string
      +

      message to include with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the reserve proof signature

    + +
+
+ +
    + +
  • +

    Generate a signature to prove the entire balance of the wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional message: string
      +

      message included with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the reserve proof signature

    + +
+
+ +
+
+ +
    + +
  • +

    Get the wallet's mnemonic phrase or seed.

    +
    +

    Returns Promise<string>

    the wallet's mnemonic phrase or seed.

    + +
+
+ +
    + +
  • +

    Get the language of the wallet's mnemonic phrase or seed.

    +
    +

    Returns Promise<string>

    the language of the wallet's mnemonic phrase or seed.

    + +
+
+ +
    + +
  • +

    Get a list of available languages for the wallet's seed.

    +
    +

    Returns Promise<any>

    the available languages for the wallet's seed.

    + +
+
+ +
    + +
  • +

    Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      Optional message: string
      +

      message to include with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the transaction signature

    + +
+
+ +
    + +
  • +

    Get a subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the subaddress's account

      +
      +
    • +
    • +
      subaddressIdx: number
      +

      index of the subaddress within the account

      +
      +
    • +
    • +
      Optional skipBalances: boolean
    +

    Returns Promise<MoneroSubaddress>

    the retrieved subaddress

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      accountIdx: any
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +

    Get subaddresses in an account.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      account to get subaddresses within

      +
      +
    • +
    • +
      Optional subaddressIndices: number[]
      +

      indices of subaddresses to get (optional)

      +
      +
    • +
    • +
      Optional skipBalances: boolean
    +

    Returns Promise<MoneroSubaddress[]>

    the retrieved subaddresses

    + +
+
+ +
    + +
  • +

    Returns number

+
+ +
    + +
  • +

    Get incoming and outgoing transfers to and from this wallet. An outgoing +transfer represents a total amount sent from one or more subaddresses +within an account to individual destination addresses, each with their +own amount. An incoming transfer represents a total amount received into +a subaddress within an account. Transfers belong to transactions which +are stored on the blockchain.

    + +

    Results can be filtered by passing a query object. Transfers must +meet every criteria defined in the query in order to be returned. All +criteria are optional and no filtering is applied when not defined.

    +
    +

    Parameters

    +
    +

    Returns Promise<MoneroTransfer[]>

    wallet transfers that meet the query

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
    +

    Returns Promise<any[]>

+
+ +
    + +
  • +

    Get a wallet transaction by hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      hash of a transaction to get

      +
      +
    +

    Returns Promise<MoneroTxWallet>

    the identified transaction or undefined if not found

    + +
+
+ +
    + +
  • +

    Get a transaction's secret key from its hash.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction's hash

      +
      +
    +

    Returns Promise<string>

      +
    • transaction's secret key
    • +
    + +
+
+ +
    + +
  • +

    Get a transaction note.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to get the note of

      +
      +
    +

    Returns Promise<string>

    the tx note

    + +
+
+ +
    + +
  • +

    Get notes for multiple transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      hashes of the transactions to get notes for

      +
      +
    +

    Returns Promise<string[]>

    notes for the transactions

    + +
+
+ +
    + +
  • +

    Get a transaction signature to prove it.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      transaction to prove

      +
      +
    • +
    • +
      address: string
      +

      destination public address of the transaction

      +
      +
    • +
    • +
      Optional message: string
      +

      message to include with the signature to further authenticate the proof (optional)

      +
      +
    +

    Returns Promise<string>

    the transaction signature

    + +
+
+ +
    + +
  • +

    Get wallet transactions. Wallet transactions contain one or more +transfers that are either incoming or outgoing to the wallet.

    + +

    Results can be filtered by passing a query object. Transactions must +meet every criteria defined in the query in order to be returned. All +criteria are optional and no filtering is applied when not defined.

    +
    +

    Parameters

    +
      +
    • +
      Optional query: string[] | Partial<MoneroTxQuery>
      +

      configures the query (optional)

      +
      +
    +

    Returns Promise<MoneroTxWallet[]>

    wallet transactions per the configuration

    + +
+
+ +
    + +
  • +

    Get the unlocked balance of the wallet, account, or subaddress.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional accountIdx: number
      +

      index of the account to get the unlocked balance of (optional)

      +
      +
    • +
    • +
      Optional subaddressIdx: number
      +

      index of the subaddress to get the unlocked balance of (optional)

      +
      +
    +

    Returns Promise<bigint>

    the unlocked balance of the wallet, account, or subaddress

    + +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      name: any
    • +
    • +
      err: any
    +

    Returns void

+
+ +
+
+ +
    + +
  • +

    Import multisig info as hex from other participants.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigHexes: string[]
      +

      multisig hex from each participant

      +
      +
    +

    Returns Promise<number>

    the number of outputs signed with the given multisig hex

    + +
+
+ +
    + +
  • +

    Import outputs in hex format.

    +
    +
    +

    Parameters

    +
      +
    • +
      outputsHex: string
      +

      outputs in hex format

      +
      +
    +

    Returns Promise<number>

    the number of outputs imported

    + +
+
+ +
    + +
  • +

    Indicates if this wallet is closed or not.

    +
    +

    Returns Promise<boolean>

    true if the wallet is closed, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the wallet is connected to daemon.

    +
    +

    Returns Promise<boolean>

    true if the wallet is connected to a daemon, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if this wallet is a multisig wallet.

    +
    +

    Returns Promise<boolean>

    true if this is a multisig wallet, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if importing multisig data is needed for returning a correct balance.

    +
    +

    Returns Promise<boolean>

    true if importing multisig data is needed for returning a correct balance, false otherwise

    + +
+
+ +
    + +
  • +

    Check if an output is frozen.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image of the output to check if frozen

      +
      +
    +

    Returns Promise<boolean>

    true if the output is frozen, false otherwise

    + +
+
+ +
    + +
  • +

    Indicates if the wallet is view-only, meaning it does not have the private +spend key and can therefore only observe incoming outputs.

    +
    +

    Returns Promise<boolean>

    true if the wallet is view-only, false otherwise

    + +
+
+ +
    + +
  • +

    Make this wallet multisig by importing multisig hex from participants.

    +
    +
    +

    Parameters

    +
      +
    • +
      multisigHexes: string[]
      +

      multisig hex from each participant

      +
      +
    • +
    • +
      threshold: number
      +

      number of signatures needed to sign transfers

      +
      +
    • +
    • +
      password: string
      +

      wallet password

      +
      +
    +

    Returns Promise<string>

    this wallet's multisig hex to share with participants

    + +
+
+ +
    + +
  • +

    Open an existing wallet on the monero-wallet-rpc server.

    + +

    Example:

    + + +let wallet = new MoneroWalletRpc("http://localhost:38084", "rpc_user", "abc123");
    +await wallet.openWallet("mywallet1", "supersecretpassword");
    +
    +await wallet.openWallet({
    +   path: "mywallet2",
    +   password: "supersecretpassword",
    +   server: "http://locahost:38081", // or object with uri, username, password, etc
    +   rejectUnauthorized: false
    +});
    +

    +
    +

    Parameters

    +
      +
    • +
      pathOrConfig: string | Partial<MoneroWalletConfig>
      +

      the wallet's name or configuration to open

      +
      +
    • +
    • +
      Optional password: string
      +

      the wallet's password

      +
      +
    +

    Returns Promise<MoneroWalletRpc>

    this wallet client

    + +
+
+ +
+
+ +
    + +
  • +

    Poll if listening.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Get multisig info as hex to share with participants to begin creating a +multisig wallet.

    +
    +

    Returns Promise<string>

    this wallet's multisig hex to share with participants

    + +
+
+ +
    + +
  • +

    Returns void

+
+ +
    + +
  • +

    Relay a previously created transaction.

    +
    +
    +

    Parameters

    +
      +
    • +
      txOrMetadata: string | MoneroTxWallet
      +

      transaction or its metadata to relay

      +
      +
    +

    Returns Promise<string>

    the hash of the relayed tx

    + +
+
+ +
    + +
  • +

    Relay previously created transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txsOrMetadatas: (string | MoneroTxWallet)[]
      +

      transactions or their metadata to relay

      +
      +
    +

    Returns Promise<string[]>

    the hashes of the relayed txs

    + +
+
+ +
    + +
  • +

    Unregister a listener to receive wallet notifications.

    +
    +
    +

    Parameters

    +
      +
    • +
      listener: any
      +

      listener to unregister

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Rescan the blockchain from scratch, losing any information which cannot be recovered from +the blockchain itself.

    + +

    WARNING: This method discards local wallet data like destination addresses, tx secret keys, +tx notes, etc.

    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Rescan the blockchain for spent outputs.

    + +

    Note: this can only be called with a trusted daemon.

    + +

    Example use case: peer multisig hex is import when connected to an untrusted daemon, +so the wallet will not rescan spent outputs. Then the wallet connects to a trusted +daemon. This method should be manually invoked to rescan outputs.

    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Common method to get key images.

    +
    +
    +

    Parameters

    +
      +
    • +
      all: any
      +

      pecifies to get all xor only new images from last import

      +
      +
    +

    Returns Promise<any>

    are the key images

    + +
+
+ +
+
+ +
    + +
  • +

    Save the wallet at its current path.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Scan transactions by their hash/id.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      tx hashes to scan

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set an account label.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to set the label for

      +
      +
    • +
    • +
      label: string
      +

      the label to set

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Sets a human-readable description for a tag.

    +
    +
    +

    Parameters

    +
      +
    • +
      tag: string
      +

      tag to set a description for

      +
      +
    • +
    • +
      label: string
      +

      label to set for the tag

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set an arbitrary attribute.

    +
    +
    +

    Parameters

    +
      +
    • +
      key: string
      +

      attribute key

      +
      +
    • +
    • +
      val: string
      +

      attribute value

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set the wallet's daemon connection manager.

    +
    +
    +

    Parameters

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set the wallet's daemon connection.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional uriOrConnection: string | MoneroRpcConnection
      +

      the daemon's URI or connection (defaults to offline)

      +
      +
    • +
    • +
      Optional isTrusted: boolean
      +

      indicates if the daemon in trusted

      +
      +
    • +
    • +
      Optional sslOptions: SslOptions
      +

      custom SSL configuration

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set a subaddress label.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIdx: number
      +

      index of the account to set the label for

      +
      +
    • +
    • +
      subaddressIdx: number
      +

      index of the subaddress to set the label for

      +
      +
    • +
    • +
      label: string
      +

      the label to set

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set a note for a specific transaction.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHash: string
      +

      hash of the transaction to set a note for

      +
      +
    • +
    • +
      note: string
      +

      the transaction note

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Set notes for multiple transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      txHashes: string[]
      +

      transactions to set notes for

      +
      +
    • +
    • +
      notes: string[]
      +

      notes to set for the transactions

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Sign a message.

    +
    +
    +

    Parameters

    +
      +
    • +
      message: string
      +

      the message to sign

      +
      +
    • +
    • +
      signatureType: MoneroMessageSignatureType = MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY
      +

      sign with spend key or view key (default spend key)

      +
      +
    • +
    • +
      accountIdx: number = 0
      +

      the account index of the message signature (default 0)

      +
      +
    • +
    • +
      subaddressIdx: number = 0
      +

      the subaddress index of the message signature (default 0)

      +
      +
    +

    Returns Promise<string>

    the signature

    + +
+
+ +
+
+ +
    + +
  • +

    Sign unsigned transactions from a view-only wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      unsignedTxHex: string
      +

      unsigned transaction hex from when the transactions were created

      +
      +
    +

    Returns Promise<MoneroTxSet>

    the signed transaction set

    + +
+
+ +
    + +
  • +

    Start mining.

    +
    +
    +

    Parameters

    +
      +
    • +
      numThreads: number
      +

      number of threads created for mining (optional)

      +
      +
    • +
    • +
      Optional backgroundMining: boolean
      +

      specifies if mining should occur in the background (optional)

      +
      +
    • +
    • +
      Optional ignoreBattery: boolean
      +

      specifies if the battery should be ignored for mining (optional)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Start background synchronizing with a maximum period between syncs.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional syncPeriodInMs: number
      +

      maximum period between syncs in milliseconds (default is wallet-specific)

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Save and close the current wallet and stop the RPC server.

    +
    +

    Returns Promise<void>

    +
+
+ +
+
+ +
    + +
  • +

    Stop the internal process running monero-wallet-rpc, if applicable.

    +
    +
    +

    Parameters

    +
      +
    • +
      force: boolean = false
      +

      specifies if the process should be destroyed forcibly (default false)

      +
      +
    +

    Returns Promise<number>

    the exit code from stopping the process

    + +
+
+ +
    + +
  • +

    Stop synchronizing the wallet with the daemon.

    +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Submit signed multisig transactions from a multisig wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      signedMultisigTxHex: string
      +

      signed multisig hex returned from signMultisigTxHex()

      +
      +
    +

    Returns Promise<string[]>

    the resulting transaction hashes

    + +
+
+ +
    + +
  • +

    Submit signed transactions from a view-only wallet.

    +
    +
    +

    Parameters

    +
      +
    • +
      signedTxHex: string
      +

      signed transaction hex from signTxs()

      +
      +
    +

    Returns Promise<string[]>

    the resulting transaction hashes

    + +
+
+ +
    + +
  • +

    Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

    + +

    NOTE: Dust only exists pre RCT, so this method will throw "no dust to sweep" on new wallets.

    +
    +

    Parameters

    +
      +
    • +
      Optional relay: boolean
      +

      specifies if the resulting transaction should be relayed (default false)

      +
      +
    +

    Returns Promise<MoneroTxWallet[]>

    the created transactions

    + +
+
+ +
+
+ +
+
+ +
    + +
  • +

    Synchronize the wallet with the daemon as a one-time synchronous process.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional listenerOrStartHeight: number | MoneroWalletListener
      +

      listener xor start height (defaults to no sync listener, the last synced block)

      +
      +
    • +
    • +
      Optional startHeight: number
      +

      startHeight if not given in first arg (defaults to last synced block)

      +
      +
    +

    Returns Promise<MoneroSyncResult>

    +
+
+ +
    + +
  • +

    Tag accounts.

    +
    +
    +

    Parameters

    +
      +
    • +
      tag: any
      +

      tag to apply to the specified accounts

      +
      +
    • +
    • +
      accountIndices: any
      +

      indices of the accounts to tag

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Thaw a frozen output.

    +
    +
    +

    Parameters

    +
      +
    • +
      keyImage: string
      +

      key image of the output to thaw

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
    + +
  • +

    Untag accounts.

    +
    +
    +

    Parameters

    +
      +
    • +
      accountIndices: number[]
      +

      indices of the accounts to untag

      +
      +
    +

    Returns Promise<void>

    +
+
+ +
+
+ +
    + +
  • +

    Compares two transfers by ascending account and subaddress indices.

    +
    +
    +

    Parameters

    +
      +
    • +
      t1: any
    • +
    • +
      t2: any
    +

    Returns number

    +
+
+ +
    + +
  • +

    Compares two outputs by ascending account and subaddress indices.

    +
    +
    +

    Parameters

    +
      +
    • +
      o1: any
    • +
    • +
      o2: any
    +

    Returns any

    +
+
+ +
    + +
  • +

    Compares two transactions by their height.

    +
    +
    +

    Parameters

    +
      +
    • +
      tx1: any
    • +
    • +
      tx2: any
    +

    Returns number

    +
+
+ +
+
+ +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      rpcDescribeTransferResult: any
    +

    Returns MoneroTxSet

+
+ +
    + +
  • +

    Initializes a MoneroTxSet from a list of rpc txs.

    +
    +
    +

    Parameters

    +
      +
    • +
      rpcTxs: any
      +

      rpc txs to initialize the set from

      +
      +
    • +
    • +
      Optional txs: any
      +

      existing txs to further initialize (optional)

      +
      +
    • +
    • +
      Optional config: any
      +

      tx config

      +
      +
    +

    Returns MoneroTxSet

    the converted tx set

    + +
+
+ +
+
+ +
    + +
  • +

    Initializes a tx set from a RPC map excluding txs.

    +
    +
    +

    Parameters

    +
      +
    • +
      rpcMap: any
      +

      map to initialize the tx set from

      +
      +
    +

    Returns MoneroTxSet

    MoneroTxSet - initialized tx set

    + +
+
+ +
    + +
  • +

    Converts a rpc tx with a transfer to a tx set with a tx and transfer.

    +
    +
    +

    Parameters

    +
      +
    • +
      rpcTx: any
      +

      rpc tx to build from

      +
      +
    • +
    • +
      tx: any
      +

      existing tx to continue initializing (optional)

      +
      +
    • +
    • +
      isOutgoing: any
      +

      specifies if the tx is outgoing if true, incoming if false, or decodes from type if undefined

      +
      +
    • +
    • +
      config: any
      +

      tx config

      +
      +
    +

    Returns MoneroTxSet

    the initialized tx set with a tx

    + +
+
+ +
+
+ +
    + +
  • +

    Builds a MoneroTxWallet from a RPC tx.

    +
    +
    +

    Parameters

    +
      +
    • +
      rpcTx: any
      +

      rpc tx to build from

      +
      +
    • +
    • +
      Optional tx: any
      +

      existing tx to continue initializing (optional)

      +
      +
    • +
    • +
      Optional isOutgoing: any
      +

      specifies if the tx is outgoing if true, incoming if false, or decodes from type if undefined

      +
      +
    • +
    • +
      Optional config: any
      +

      tx config

      +
      +
    +

    Returns any

    is the initialized tx

    + +
+
+ +
    + +
  • +

    Decodes a "type" from monero-wallet-rpc to initialize type and state +fields in the given transaction.

    +

    TODO: these should be safe set

    +
    +
    +

    Parameters

    +
      +
    • +
      rpcType: any
      +

      is the type to decode

      +
      +
    • +
    • +
      tx: any
      +

      is the transaction to decode known fields to

      +
      +
    +

    Returns any

    true if the rpc type indicates outgoing xor incoming

    + +
+
+ +
    + +
  • +

    Remove criteria which requires looking up other transfers/outputs to +fulfill query.

    +
    +
    +

    Parameters

    +
      +
    • +
      query: any
      +

      the query to decontextualize

      +
      +
    +

    Returns any

    a reference to the query for convenience

    + +
+
+ +
    + +
  • +

    Initializes a sent transaction.

    +

    TODO: remove copyDestinations after >18.3.1 when subtractFeeFrom fully supported

    +
    +
    +

    Parameters

    +
      +
    • +
      config: Partial<MoneroTxConfig>
      +

      send config

      +
      +
    • +
    • +
      Optional tx: any
      +

      existing transaction to initialize (optional)

      +
      +
    • +
    • +
      copyDestinations: any
      +

      copies config destinations if true

      +
      +
    +

    Returns any

    is the initialized send tx

    + +
+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      query: any
    +

    Returns boolean

+
+ +
    + +
  • +

    Merges a transaction into a unique set of transactions.

    +
    +
    +

    Parameters

    +
      +
    • +
      tx: any
      +

      the transaction to merge into the existing txs

      +
      +
    • +
    • +
      txMap: any
      +

      maps tx hashes to txs

      +
      +
    • +
    • +
      blockMap: any
      +

      maps block heights to blocks

      +
      +
    +

    Returns void

    +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/SslOptions.html b/docs/typedocs/classes/SslOptions.html new file mode 100644 index 000000000..84f934e53 --- /dev/null +++ b/docs/typedocs/classes/SslOptions.html @@ -0,0 +1,234 @@ +SslOptions | monero-ts
+
+ +
+
+
+
+ +

Class SslOptions

+
+

SSL options for remote endpoints.

+
+
+
+

Hierarchy

+
    +
  • SslOptions
+
+
+
+ +
+
+

Constructors

+
+ +
+
+

Properties

+
+ +
allowAnyCert: boolean
+
+ +
allowedFingerprints: string[]
+
+ +
certificateAuthorityFile: string
+
+ +
certificatePath: string
+
+ +
privateKeyPath: string
+
+

Methods

+
+ +
    + +
  • +

    Returns boolean

+
+ +
    + +
  • +

    Returns string[]

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +

    Returns string

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      allowAnyCert: any
    +

    Returns SslOptions

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      allowedFingerprints: any
    +

    Returns SslOptions

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      certificateAuthorityFile: any
    +

    Returns SslOptions

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      certificatePath: any
    +

    Returns SslOptions

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      privateKeyPath: any
    +

    Returns SslOptions

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/TaskLooper.html b/docs/typedocs/classes/TaskLooper.html new file mode 100644 index 000000000..737910e1f --- /dev/null +++ b/docs/typedocs/classes/TaskLooper.html @@ -0,0 +1,247 @@ +TaskLooper | monero-ts
+
+ +
+
+
+
+ +

Class TaskLooper

+
+

Run a task in a fixed period loop.

+
+
+
+

Hierarchy

+
    +
  • TaskLooper
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
    + +
  • +

    Build the looper with a function to invoke on a fixed period loop.

    +
    +
    +

    Parameters

    +
      +
    • +
      fn: (() => Promise<void>)
      +

      the async function to invoke

      +
      +
      +
        +
      • +
          +
        • (): Promise<void>
        • +
        • +

          Returns Promise<void>

    +

    Returns TaskLooper

    +
+
+

Properties

+
+ +
_fn: (() => Promise<void>)
+
+

Type declaration

+
    +
  • +
      +
    • (): Promise<void>
    • +
    • +

      Returns Promise<void>

+
+ +
_isLooping: boolean
+
+ +
_isStarted: boolean
+
+ +
_periodInMs: number
+
+ +
_timeout: Timeout
+
+

Methods

+
+ +
    + +
  • +
    +

    Parameters

    +
      +
    • +
      targetFixedPeriod: boolean
    +

    Returns Promise<void>

+
+ +
    + +
  • +

    Get the task function to invoke on a fixed period loop.

    +
    +

    Returns (() => Promise<void>)

    the task function

    + +
      +
    • +
        +
      • (): Promise<void>
      • +
      • +

        Returns Promise<void>

    +
+
+ +
    + +
  • +

    Indicates if looping.

    +
    +

    Returns boolean

    true if looping, false otherwise

    + +
+
+ +
    + +
  • +

    Set the loop period in milliseconds.

    +
    +
    +

    Parameters

    +
      +
    • +
      periodInMs: any
      +

      the loop period in milliseconds

      +
      +
    +

    Returns void

    +
+
+ +
    + +
  • +

    Start the task loop.

    +
    +
    +

    Parameters

    +
      +
    • +
      periodInMs: number
      +

      the loop period in milliseconds

      +
      +
    • +
    • +
      Optional targetFixedPeriod: boolean
      +

      specifies if the task should target a fixed period by accounting for run time (default false)

      +
      +
    +

    Returns void

    this instance for chaining

    + +
+
+ +
    + +
  • +

    Stop the task loop.

    +
    +

    Returns void

    +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/classes/ThreadPool.html b/docs/typedocs/classes/ThreadPool.html new file mode 100644 index 000000000..9d6149848 --- /dev/null +++ b/docs/typedocs/classes/ThreadPool.html @@ -0,0 +1,157 @@ +ThreadPool | monero-ts
+
+ +
+
+
+
+ +

Class ThreadPool

+
+

Simple thread pool using the async library.

+
+
+
+

Hierarchy

+
    +
  • ThreadPool
+
+
+
+ +
+
+

Constructors

+
+
+

Properties

+
+
+

Methods

+
+
+

Constructors

+
+ +
    + +
  • +

    Construct the thread pool.

    +
    +
    +

    Parameters

    +
      +
    • +
      Optional maxConcurrency: any
      +

      maximum number of threads in the pool (default 1)

      +
      +
    +

    Returns ThreadPool

    +
+
+

Properties

+
+ +
drainListeners: any
+
+ +
taskQueue: any
+
+

Methods

+
+ +
    + +
  • +

    Await all functions to complete.

    +
    +

    Returns Promise<void>

    resolves when all functions complete

    + +
+
+ +
    + +
  • +

    Submit an asynchronous function to run using the thread pool.

    +
    +
    +

    Type Parameters

    +
      +
    • +

      T

    +
    +

    Parameters

    +
      +
    • +
      asyncFn: any
      +

      asynchronous function to run with the thread pool

      +
      +
    +

    Returns Promise<T>

    resolves when the function completes execution

    + +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/enums/ConnectionType.html b/docs/typedocs/enums/ConnectionType.html new file mode 100644 index 000000000..371f332bf --- /dev/null +++ b/docs/typedocs/enums/ConnectionType.html @@ -0,0 +1,118 @@ +ConnectionType | monero-ts
+
+ +
+
+
+
+ +

Enumeration ConnectionType

+
+

Enumerates connection types.

+

Based on enums.h in monero-project.

+
+
+
+
+
+ +
+
+

Enumeration Members

+
+
+

Enumeration Members

+
+ +
I2P: 4
+

I2P connection type (value=4).

+
+
+
+ +
INVALID: 0
+

Invalid connection type (value=0).

+
+
+
+ +
IPV4: 1
+

IPV4 connection type (value=1).

+
+
+
+ +
IPV6: 2
+

IPV6 connection type (value=2).

+
+
+
+ +
TOR: 3
+

TOR connection type (value=3).

+
+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/enums/MoneroKeyImageSpentStatus.html b/docs/typedocs/enums/MoneroKeyImageSpentStatus.html new file mode 100644 index 000000000..d282c7bc7 --- /dev/null +++ b/docs/typedocs/enums/MoneroKeyImageSpentStatus.html @@ -0,0 +1,102 @@ +MoneroKeyImageSpentStatus | monero-ts
+
+ +
+
+
+
+ +

Enumeration MoneroKeyImageSpentStatus

+
+

Enumerates connection types.

+

Based on enums.h in monero-project.

+
+
+
+
+
+ +
+
+

Enumeration Members

+
+
+

Enumeration Members

+
+ +
CONFIRMED: 1
+

Key image is confirmed (value=1).

+
+
+
+ +
NOT_SPENT: 0
+

Key image is not spent (value=0).

+
+
+
+ +
TX_POOL: 2
+

Key image is in the pool (value=2).

+
+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/enums/MoneroMessageSignatureType.html b/docs/typedocs/enums/MoneroMessageSignatureType.html new file mode 100644 index 000000000..68fa24783 --- /dev/null +++ b/docs/typedocs/enums/MoneroMessageSignatureType.html @@ -0,0 +1,93 @@ +MoneroMessageSignatureType | monero-ts
+
+ +
+
+
+
+ +

Enumeration MoneroMessageSignatureType

+
+

Enumerate message signature types.

+
+
+
+
+
+ +
+
+

Enumeration Members

+
+
+

Enumeration Members

+
+ +
SIGN_WITH_SPEND_KEY: 0
+

Sign with spend key (value=0).

+
+
+
+ +
SIGN_WITH_VIEW_KEY: 1
+

Sign with the view key (value=1).

+
+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/enums/MoneroTxPriority.html b/docs/typedocs/enums/MoneroTxPriority.html new file mode 100644 index 000000000..3255bc58f --- /dev/null +++ b/docs/typedocs/enums/MoneroTxPriority.html @@ -0,0 +1,109 @@ +MoneroTxPriority | monero-ts
+
+ +
+
+
+
+ +

Enumeration MoneroTxPriority

+
+

Enumerates send priorities.

+
+
+
+
+
+ +
+
+

Enumeration Members

+
+
+

Enumeration Members

+
+ +
DEFAULT: 0
+

Default priority (i.e. normal) (value=0).

+
+
+
+ +
ELEVATED: 3
+

Elevated priority (value=3).

+
+
+
+ +
NORMAL: 2
+

Normal priority (value=2).

+
+
+
+ +
UNIMPORTANT: 1
+

Unimportant priority (value=1).

+
+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/functions/connectToDaemonRpc.html b/docs/typedocs/functions/connectToDaemonRpc.html new file mode 100644 index 000000000..cd4cc61d3 --- /dev/null +++ b/docs/typedocs/functions/connectToDaemonRpc.html @@ -0,0 +1,106 @@ +connectToDaemonRpc | monero-ts
+
+ +
+
+
+
+ +

Function connectToDaemonRpc

+
+
    + +
  • +

    Create a client connected to monerod.

    + +

    Examples:

    + + +let daemon = await moneroTs.connectToDaemonRpc("http://localhost:38081");
    +

    +
    + +let daemon = await moneroTs.connectToDaemonRpc({
    +   uri: "http://localhost:38081",
    +   username: "superuser",
    +   password: "abctesting123"
    +}); +

    +
    + +// start monerod as an internal process
    +let daemon = await moneroTs.connectToDaemonRpc({
    +   cmd: ["path/to/monerod", ...params...],
    +}); +

    +
    +

    Parameters

    +
      +
    • +
      uriOrConfig: string | string[] | Partial<MoneroRpcConnection> | Partial<MoneroDaemonConfig>
      +

      uri or rpc connection or config or terminal parameters to connect to monerod

      +
      +
    • +
    • +
      Optional username: string
      +

      username to authenticate with monerod

      +
      +
    • +
    • +
      Optional password: string
      +

      password to authenticate with monerod

      +
      +
    +

    Returns Promise<MoneroDaemonRpc>

    the daemon RPC client

    + +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/functions/connectToWalletRpc.html b/docs/typedocs/functions/connectToWalletRpc.html new file mode 100644 index 000000000..1822029c2 --- /dev/null +++ b/docs/typedocs/functions/connectToWalletRpc.html @@ -0,0 +1,110 @@ +connectToWalletRpc | monero-ts
+
+ +
+
+
+
+ +

Function connectToWalletRpc

+
+
    + +
  • +

    Create a client connected to monero-wallet-rpc.

    + +

    Examples:

    + + +let walletRpc = await moneroTs.connectToWalletRpc({
    +   uri: "http://localhost:38081",
    +   username: "superuser",
    +   password: "abctesting123",
    +   rejectUnauthorized: false // e.g. local development
    +});
    +

    +
    + +// connect to monero-wallet-rpc running as internal process
    +let walletRpc = await moneroTs.connectToWalletRpc({cmd: [
    +   "/path/to/monero-wallet-rpc",
    +   "--stagenet",
    +   "--daemon-address", "http://localhost:38081",
    +   "--daemon-login", "superuser:abctesting123",
    +   "--rpc-bind-port", "38085",
    +   "--rpc-login", "rpc_user:abc123",
    +   "--wallet-dir", "/path/to/wallets", // defaults to monero-wallet-rpc directory
    +   "--rpc-access-control-origins", "http://localhost:8080"
    + ]}); +
    +
    +

    Parameters

    +
      +
    • +
      uriOrConfig: string | string[] | Partial<MoneroRpcConnection> | Partial<MoneroWalletConfig>
      +

      uri or rpc connection or config or terminal parameters to connect to monero-wallet-rpc

      +
      +
    • +
    • +
      Optional username: string
      +

      username to authenticate with monero-wallet-rpc

      +
      +
    • +
    • +
      Optional password: string
      +

      password to authenticate with monero-wallet-rpc

      +
      +
    +

    Returns Promise<MoneroWalletRpc>

    the wallet RPC client

    + +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/functions/createWalletFull.html b/docs/typedocs/functions/createWalletFull.html new file mode 100644 index 000000000..963a1f0e7 --- /dev/null +++ b/docs/typedocs/functions/createWalletFull.html @@ -0,0 +1,104 @@ +createWalletFull | monero-ts
+
+ +
+
+
+
+ +

Function createWalletFull

+
+
    + +
  • +

    Create a Monero wallet using client-side WebAssembly bindings to monero-project's wallet2 in C++.

    + +

    Example:

    + + +const wallet = await moneroTs.createWalletFull({
    +   path: "./test_wallets/wallet1", // leave blank for in-memory wallet
    +   password: "supersecretpassword",
    +   networkType: moneroTs.MoneroNetworkType.STAGENET,
    +   seed: "coexist igloo pamphlet lagoon...",
    +   restoreHeight: 1543218,
    +   server: "http://localhost:38081"
    +}); +

    +
    + +const wallet = await moneroTs.createWalletFull({
    +   path: "./test_wallets/wallet1", // leave blank for in-memory wallet
    +   password: "supersecretpassword",
    +   networkType: moneroTs.MoneroNetworkType.STAGENET,
    +   seed: "coexist igloo pamphlet lagoon...",
    +   restoreHeight: 1543218,
    +   proxyToWorker: false, // override default
    +   server: {
    +     uri: "http://localhost:38081",
    +     username: "daemon_user",
    +     password: "daemon_password_123"
    +   }
    +}); +
    +
    +

    Parameters

    +
      +
    • +
      config: Partial<MoneroWalletConfig>
      +

      MoneroWalletConfig or equivalent config object

      +
      +
    +

    Returns Promise<MoneroWalletFull>

    the created wallet

    + +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/functions/createWalletKeys.html b/docs/typedocs/functions/createWalletKeys.html new file mode 100644 index 000000000..338435805 --- /dev/null +++ b/docs/typedocs/functions/createWalletKeys.html @@ -0,0 +1,85 @@ +createWalletKeys | monero-ts
+
+ +
+
+
+
+ +

Function createWalletKeys

+
+
    + +
  • +

    Create a wallet using WebAssembly bindings to monero-project.

    + +

    Example:

    + + +const wallet = await moneroTs.createWalletKeys({
    +   password: "abc123",
    +   networkType: moneroTs.MoneroNetworkType.STAGENET,
    +   seed: "coexist igloo pamphlet lagoon..."
    +}); +
    +
    +

    Parameters

    +
      +
    • +
      config: Partial<MoneroWalletConfig>
      +

      MoneroWalletConfig or equivalent config object

      +
      +
    +

    Returns Promise<MoneroWalletKeys>

    the created wallet

    + +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/functions/getVersion.html b/docs/typedocs/functions/getVersion.html new file mode 100644 index 000000000..56f788015 --- /dev/null +++ b/docs/typedocs/functions/getVersion.html @@ -0,0 +1,67 @@ +getVersion | monero-ts
+
+ +
+
+
+
+ +

Function getVersion

+
+
    + +
  • +

    Get the version of the monero-ts library.

    +

    Returns string

    the version of this monero-ts library

    + +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/functions/openWalletFull.html b/docs/typedocs/functions/openWalletFull.html new file mode 100644 index 000000000..b575287f8 --- /dev/null +++ b/docs/typedocs/functions/openWalletFull.html @@ -0,0 +1,90 @@ +openWalletFull | monero-ts
+
+ +
+
+
+
+ +

Function openWalletFull

+
+
    + +
  • +

    Open an existing Monero wallet using client-side WebAssembly bindings to monero-project's wallet2 in C++.

    + +

    Example:

    + + +const wallet = await moneroTs.openWalletFull({
    +   path: "./wallets/wallet1",
    +   password: "supersecretpassword",
    +   networkType: moneroTs.MoneroNetworkType.STAGENET,
    +   server: { // daemon configuration
    +     uri: "http://localhost:38081",
    +     username: "superuser",
    +     password: "abctesting123"
    +   }
    +}); +

    +
    +

    Parameters

    +
    +

    Returns Promise<MoneroWalletFull>

    the opened wallet

    + +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/functions/shutdown.html b/docs/typedocs/functions/shutdown.html new file mode 100644 index 000000000..dfc72b0aa --- /dev/null +++ b/docs/typedocs/functions/shutdown.html @@ -0,0 +1,67 @@ +shutdown | monero-ts
+
+ +
+
+
+
+ +

Function shutdown

+
+
    + +
  • +

    Shut down the monero-ts library, terminating any running workers.

    +

    Returns Promise<void>

    promise that resolves when the library has shut down

    + +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/index.html b/docs/typedocs/index.html new file mode 100644 index 000000000..17bc16f63 --- /dev/null +++ b/docs/typedocs/index.html @@ -0,0 +1,194 @@ +monero-ts
+
+ +
+
+
+
+

monero-ts

+

Monero TypeScript Library

A TypeScript library for creating Monero applications using RPC and WebAssembly bindings to monero v0.18.4.3 'Fluorine Fermi'.

+
    +
  • Supports client-side wallets in Node.js and the browser using WebAssembly.
  • +
  • Supports wallet and daemon RPC clients.
  • +
  • Supports multisig, view-only, and offline wallets.
  • +
  • Wallet types are interchangeable by conforming to a common interface.
  • +
  • Uses a clearly defined data model and API specification intended to be intuitive and robust.
  • +
  • Query wallet transactions, transfers, and outputs by their properties.
  • +
  • Fetch and process binary data from the daemon (e.g. raw blocks).
  • +
  • Receive notifications when blocks are added to the chain or when wallets sync, send, or receive.
  • +
  • Over 300 passing Mocha tests.
  • +
+

Architecture

+
+ Build browser or Node.js applications using RPC or WebAssembly bindings to monero-project/monero. Wallet implementations are interchangeable by conforming to a common interface, MoneroWallet.ts. +

+ +

Sample code

// import monero-ts (or import types individually)
import moneroTs from "monero-ts";

// connect to daemon
let daemon = await moneroTs.connectToDaemonRpc("http://localhost:28081");
let height = await daemon.getHeight(); // 1523651
let txsInPool = await daemon.getTxPool(); // get transactions in the pool

// create wallet from mnemonic phrase using WebAssembly bindings to monero-project
let walletFull = await moneroTs.createWalletFull({
path: "sample_wallet_full",
password: "supersecretpassword123",
networkType: moneroTs.MoneroNetworkType.TESTNET,
seed: "hefty value scenic...",
restoreHeight: 573936,
server: { // provide url or MoneroRpcConnection
uri: "http://localhost:28081",
username: "superuser",
password: "abctesting123"
}
});

// synchronize with progress notifications
await walletFull.sync(new class extends moneroTs.MoneroWalletListener {
async onSyncProgress(height: number, startHeight: number, endHeight: number, percentDone: number, message: string) {
// feed a progress bar?
}
});

// synchronize in the background every 5 seconds
await walletFull.startSyncing(5000);

// receive notifications when funds are received, confirmed, and unlocked
let fundsReceived = false;
await walletFull.addListener(new class extends moneroTs.MoneroWalletListener {
async onOutputReceived(output: moneroTs.MoneroOutputWallet) {
let amount = output.getAmount();
let txHash = output.getTx().getHash();
let isConfirmed = output.getTx().getIsConfirmed();
let isLocked = output.getTx().getIsLocked();
fundsReceived = true;
}
});

// connect to wallet RPC and open wallet
let walletRpc = await moneroTs.connectToWalletRpc("http://localhost:28084", "rpc_user", "abc123");
await walletRpc.openWallet("sample_wallet_rpc", "supersecretpassword123");
let primaryAddress = await walletRpc.getPrimaryAddress(); // 555zgduFhmKd2o8rPUz...
let balance = await walletRpc.getBalance(); // 533648366742
let txs = await walletRpc.getTxs(); // get transactions containing transfers to/from the wallet

// send funds from RPC wallet to WebAssembly wallet
let createdTx = await walletRpc.createTx({
accountIndex: 0,
address: await walletFull.getAddress(1, 0),
amount: 250000000000n, // send 0.25 XMR (denominated in atomic units)
relay: false // create transaction and relay to the network if true
});
let fee = createdTx.getFee(); // "Are you sure you want to send... ?"
await walletRpc.relayTx(createdTx); // relay the transaction

// recipient receives unconfirmed funds within 5 seconds
await new Promise(function(resolve) { setTimeout(resolve, 5000); });
assert(fundsReceived);

// save and close WebAssembly wallet
await walletFull.close(true);

// terminate any running resources (e.g. workers)
await moneroTs.shutdown(); +
+

Documentation

+

Sample projects

+

Related projects

+

Using monero-ts in your project

    +
  1. cd your_project or mkdir your_project && cd your_project && npm init
  2. +
  3. npm install monero-ts
  4. +
  5. Add import moneroTs from "monero-ts" in your application code (or import types individually).
  6. +
+

Running in Node.js

Node 20 LTS is recommended. Alternatively, Node 16 and 18 LTS work using the --experimental-wasm-threads flag.

+

Building a browser application

    +
  1. Bundle your application code for a browser. See xmr-sample-webpack for an example project using Webpack.
  2. +
  3. Copy assets from ./dist to your web app's build directory.
  4. +
+

Using RPC servers:

    +
  1. Download and install Monero CLI.
  2. +
  3. Start monerod, e.g.: ./monerod --stagenet (or use a remote daemon).
  4. +
  5. Start monero-wallet-rpc, e.g.: ./monero-wallet-rpc --daemon-address http://localhost:38081 --stagenet --rpc-bind-port 38084 --rpc-login rpc_user:abc123 --wallet-dir ./
  6. +
+

Building WebAssembly binaries from source

This project uses WebAssembly to package and execute Monero's source code for a browser or other WebAssembly-supported environment.

+

Compiled WebAssembly binaries are committed to ./dist for convenience, but these files can be built independently from source code:

+
    +
  1. Install and activate emscripten.
      +
    1. Clone emscripten repository: git clone https://github.com/emscripten-core/emsdk.git
    2. +
    3. cd emsdk
    4. +
    5. git pull && ./emsdk install 3.1.66 && ./emsdk activate 3.1.66 && source ./emsdk_env.sh
    6. +
    7. export EMSCRIPTEN=path/to/emsdk/upstream/emscripten (change for your system)
    8. +
    +
  2. +
  3. Clone monero-ts repository: git clone --recursive https://github.com/woodser/monero-ts.git
  4. +
  5. cd monero-ts
  6. +
  7. ./bin/update_submodules.sh
  8. +
  9. Modify ./external/monero-cpp/external/monero-project/src/crypto/wallet/CMakeLists.txt from set(MONERO_WALLET_CRYPTO_LIBRARY "auto" ... to set(MONERO_WALLET_CRYPTO_LIBRARY "cn" ....
  10. +
  11. Build the monero-cpp submodule (located at ./external/monero-cpp) by following instructions for your system. This will ensure all dependencies are installed. Be sure to install unbound 1.19.0 to your home directory (~/unbound-1.19.0).
  12. +
  13. ./bin/build_all.sh (install monero-project dependencies as needed for your system)
  14. +
+

Running tests

    +
  1. Clone the project repository: git clone https://github.com/woodser/monero-ts.git
  2. +
  3. cd monero-ts
  4. +
  5. Start RPC servers:
      +
    1. Download and install Monero CLI.
    2. +
    3. Start monerod, e.g.: ./monerod --testnet (or use a remote daemon).
    4. +
    5. Start monero-wallet-rpc, e.g.: ./monero-wallet-rpc --daemon-address http://localhost:38081 --testnet --rpc-bind-port 28084 --rpc-login rpc_user:abc123 --wallet-dir ./
    6. +
    +
  6. +
  7. Configure the appropriate RPC endpoints, authentication, and other settings in TestUtils.ts (e.g. WALLET_RPC_CONFIG and DAEMON_RPC_CONFIG).
  8. +
+

Running tests in Node.js

    +
  • Run all tests: npm test
  • +
  • Run tests by their description, e.g.: npm run test -- --grep "Can get transactions"
  • +
+

Running tests in a browser

    +
  1. Start monero-wallet-rpc servers used by tests: ./bin/start_wallet_rpc_test_servers.sh
  2. +
  3. In another terminal, build browser tests: ./bin/build_browser_tests.sh
  4. +
  5. Access http://localhost:8080/tests.html in a browser to run all tests
  6. +
+

License

This project is licensed under MIT.

+

Donations

Please consider donating to support the development of this project. 🙏

+

+
+ 46FR1GKVqFNQnDiFkH7AuzbUBrGQwz2VdaXTDD4jcjRE8YkkoTYTmZ2Vohsz9gLSqkj5EM6ai9Q7sBoX4FPPYJdGKQQXPVz +

+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/modules.html b/docs/typedocs/modules.html new file mode 100644 index 000000000..4dc14758e --- /dev/null +++ b/docs/typedocs/modules.html @@ -0,0 +1,154 @@ +monero-ts
+
+ +
+
+
+
+

monero-ts

+
+
+

Index

+
+

Enumerations

+
+
+

Classes

+
+
+

Variables

+
+
+

Functions

+
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/docs/typedocs/variables/default.html b/docs/typedocs/variables/default.html new file mode 100644 index 000000000..834da944d --- /dev/null +++ b/docs/typedocs/variables/default.html @@ -0,0 +1,452 @@ +default | monero-ts
+
+ +
+
+
+
+ +

Variable defaultConst

+
default: {
    ConnectionType: typeof ConnectionType;
    Filter: typeof default;
    GenUtils: typeof GenUtils;
    HttpClient: typeof HttpClient;
    LibraryUtils: typeof LibraryUtils;
    MoneroAccount: typeof MoneroAccount;
    MoneroAccountTag: typeof MoneroAccountTag;
    MoneroAddressBookEntry: typeof MoneroAddressBookEntry;
    MoneroAltChain: typeof MoneroAltChain;
    MoneroBan: typeof MoneroBan;
    MoneroBlock: typeof MoneroBlock;
    MoneroBlockHeader: typeof MoneroBlockHeader;
    MoneroBlockTemplate: typeof MoneroBlockTemplate;
    MoneroCheck: typeof MoneroCheck;
    MoneroCheckReserve: typeof MoneroCheckReserve;
    MoneroCheckTx: typeof MoneroCheckTx;
    MoneroConnectionManager: typeof MoneroConnectionManager;
    MoneroConnectionManagerListener: typeof MoneroConnectionManagerListener;
    MoneroConnectionSpan: typeof MoneroConnectionSpan;
    MoneroDaemon: typeof MoneroDaemon;
    MoneroDaemonConfig: typeof MoneroDaemonConfig;
    MoneroDaemonInfo: typeof MoneroDaemonInfo;
    MoneroDaemonListener: typeof MoneroDaemonListener;
    MoneroDaemonRpc: typeof MoneroDaemonRpc;
    MoneroDaemonSyncInfo: typeof MoneroDaemonSyncInfo;
    MoneroDaemonUpdateCheckResult: typeof MoneroDaemonUpdateCheckResult;
    MoneroDaemonUpdateDownloadResult: typeof MoneroDaemonUpdateDownloadResult;
    MoneroDestination: typeof MoneroDestination;
    MoneroError: typeof MoneroError;
    MoneroFeeEstimate: typeof MoneroFeeEstimate;
    MoneroHardForkInfo: typeof MoneroHardForkInfo;
    MoneroIncomingTransfer: typeof MoneroIncomingTransfer;
    MoneroIntegratedAddress: typeof MoneroIntegratedAddress;
    MoneroKeyImage: typeof MoneroKeyImage;
    MoneroKeyImageImportResult: typeof MoneroKeyImageImportResult;
    MoneroKeyImageSpentStatus: typeof MoneroKeyImageSpentStatus;
    MoneroMessageSignatureResult: typeof MoneroMessageSignatureResult;
    MoneroMessageSignatureType: typeof MoneroMessageSignatureType;
    MoneroMinerTxSum: typeof MoneroMinerTxSum;
    MoneroMiningStatus: typeof MoneroMiningStatus;
    MoneroMultisigInfo: typeof MoneroMultisigInfo;
    MoneroMultisigInitResult: typeof MoneroMultisigInitResult;
    MoneroMultisigSignResult: typeof MoneroMultisigSignResult;
    MoneroNetworkType: typeof MoneroNetworkType;
    MoneroOutgoingTransfer: typeof MoneroOutgoingTransfer;
    MoneroOutput: typeof MoneroOutput;
    MoneroOutputHistogramEntry: typeof MoneroOutputHistogramEntry;
    MoneroOutputQuery: typeof MoneroOutputQuery;
    MoneroOutputWallet: typeof MoneroOutputWallet;
    MoneroPeer: typeof MoneroPeer;
    MoneroPruneResult: typeof MoneroPruneResult;
    MoneroRpcConnection: typeof MoneroRpcConnection;
    MoneroRpcError: typeof MoneroRpcError;
    MoneroSubaddress: typeof MoneroSubaddress;
    MoneroSubmitTxResult: typeof MoneroSubmitTxResult;
    MoneroSyncResult: typeof MoneroSyncResult;
    MoneroTransfer: typeof MoneroTransfer;
    MoneroTransferQuery: typeof MoneroTransferQuery;
    MoneroTx: typeof MoneroTx;
    MoneroTxConfig: typeof MoneroTxConfig;
    MoneroTxPoolStats: typeof MoneroTxPoolStats;
    MoneroTxPriority: typeof MoneroTxPriority;
    MoneroTxQuery: typeof MoneroTxQuery;
    MoneroTxSet: typeof MoneroTxSet;
    MoneroTxWallet: typeof MoneroTxWallet;
    MoneroUtils: typeof MoneroUtils;
    MoneroVersion: typeof MoneroVersion;
    MoneroWallet: typeof MoneroWallet;
    MoneroWalletConfig: typeof MoneroWalletConfig;
    MoneroWalletFull: typeof MoneroWalletFull;
    MoneroWalletKeys: typeof MoneroWalletKeys;
    MoneroWalletListener: typeof MoneroWalletListener;
    MoneroWalletRpc: typeof MoneroWalletRpc;
    SslOptions: typeof SslOptions;
    TaskLooper: typeof TaskLooper;
    ThreadPool: typeof ThreadPool;
    connectToDaemonRpc: ((uriOrConfig, username?, password?) => Promise<MoneroDaemonRpc>);
    connectToWalletRpc: ((uriOrConfig, username?, password?) => Promise<MoneroWalletRpc>);
    createWalletFull: ((config) => Promise<MoneroWalletFull>);
    createWalletKeys: ((config) => Promise<MoneroWalletKeys>);
    getVersion: (() => string);
    openWalletFull: ((config) => Promise<MoneroWalletFull>);
    shutdown: (() => Promise<void>);
} = ...
+
+

Type declaration

+
    +
  • +
    ConnectionType: typeof ConnectionType
  • +
  • +
    Filter: typeof default
  • +
  • +
    GenUtils: typeof GenUtils
  • +
  • +
    HttpClient: typeof HttpClient
  • +
  • +
    LibraryUtils: typeof LibraryUtils
  • +
  • +
    MoneroAccount: typeof MoneroAccount
  • +
  • +
    MoneroAccountTag: typeof MoneroAccountTag
  • +
  • +
    MoneroAddressBookEntry: typeof MoneroAddressBookEntry
  • +
  • +
    MoneroAltChain: typeof MoneroAltChain
  • +
  • +
    MoneroBan: typeof MoneroBan
  • +
  • +
    MoneroBlock: typeof MoneroBlock
  • +
  • +
    MoneroBlockHeader: typeof MoneroBlockHeader
  • +
  • +
    MoneroBlockTemplate: typeof MoneroBlockTemplate
  • +
  • +
    MoneroCheck: typeof MoneroCheck
  • +
  • +
    MoneroCheckReserve: typeof MoneroCheckReserve
  • +
  • +
    MoneroCheckTx: typeof MoneroCheckTx
  • +
  • +
    MoneroConnectionManager: typeof MoneroConnectionManager
  • +
  • +
    MoneroConnectionManagerListener: typeof MoneroConnectionManagerListener
  • +
  • +
    MoneroConnectionSpan: typeof MoneroConnectionSpan
  • +
  • +
    MoneroDaemon: typeof MoneroDaemon
  • +
  • +
    MoneroDaemonConfig: typeof MoneroDaemonConfig
  • +
  • +
    MoneroDaemonInfo: typeof MoneroDaemonInfo
  • +
  • +
    MoneroDaemonListener: typeof MoneroDaemonListener
  • +
  • +
    MoneroDaemonRpc: typeof MoneroDaemonRpc
  • +
  • +
    MoneroDaemonSyncInfo: typeof MoneroDaemonSyncInfo
  • +
  • +
    MoneroDaemonUpdateCheckResult: typeof MoneroDaemonUpdateCheckResult
  • +
  • +
    MoneroDaemonUpdateDownloadResult: typeof MoneroDaemonUpdateDownloadResult
  • +
  • +
    MoneroDestination: typeof MoneroDestination
  • +
  • +
    MoneroError: typeof MoneroError
  • +
  • +
    MoneroFeeEstimate: typeof MoneroFeeEstimate
  • +
  • +
    MoneroHardForkInfo: typeof MoneroHardForkInfo
  • +
  • +
    MoneroIncomingTransfer: typeof MoneroIncomingTransfer
  • +
  • +
    MoneroIntegratedAddress: typeof MoneroIntegratedAddress
  • +
  • +
    MoneroKeyImage: typeof MoneroKeyImage
  • +
  • +
    MoneroKeyImageImportResult: typeof MoneroKeyImageImportResult
  • +
  • +
    MoneroKeyImageSpentStatus: typeof MoneroKeyImageSpentStatus
  • +
  • +
    MoneroMessageSignatureResult: typeof MoneroMessageSignatureResult
  • +
  • +
    MoneroMessageSignatureType: typeof MoneroMessageSignatureType
  • +
  • +
    MoneroMinerTxSum: typeof MoneroMinerTxSum
  • +
  • +
    MoneroMiningStatus: typeof MoneroMiningStatus
  • +
  • +
    MoneroMultisigInfo: typeof MoneroMultisigInfo
  • +
  • +
    MoneroMultisigInitResult: typeof MoneroMultisigInitResult
  • +
  • +
    MoneroMultisigSignResult: typeof MoneroMultisigSignResult
  • +
  • +
    MoneroNetworkType: typeof MoneroNetworkType
  • +
  • +
    MoneroOutgoingTransfer: typeof MoneroOutgoingTransfer
  • +
  • +
    MoneroOutput: typeof MoneroOutput
  • +
  • +
    MoneroOutputHistogramEntry: typeof MoneroOutputHistogramEntry
  • +
  • +
    MoneroOutputQuery: typeof MoneroOutputQuery
  • +
  • +
    MoneroOutputWallet: typeof MoneroOutputWallet
  • +
  • +
    MoneroPeer: typeof MoneroPeer
  • +
  • +
    MoneroPruneResult: typeof MoneroPruneResult
  • +
  • +
    MoneroRpcConnection: typeof MoneroRpcConnection
  • +
  • +
    MoneroRpcError: typeof MoneroRpcError
  • +
  • +
    MoneroSubaddress: typeof MoneroSubaddress
  • +
  • +
    MoneroSubmitTxResult: typeof MoneroSubmitTxResult
  • +
  • +
    MoneroSyncResult: typeof MoneroSyncResult
  • +
  • +
    MoneroTransfer: typeof MoneroTransfer
  • +
  • +
    MoneroTransferQuery: typeof MoneroTransferQuery
  • +
  • +
    MoneroTx: typeof MoneroTx
  • +
  • +
    MoneroTxConfig: typeof MoneroTxConfig
  • +
  • +
    MoneroTxPoolStats: typeof MoneroTxPoolStats
  • +
  • +
    MoneroTxPriority: typeof MoneroTxPriority
  • +
  • +
    MoneroTxQuery: typeof MoneroTxQuery
  • +
  • +
    MoneroTxSet: typeof MoneroTxSet
  • +
  • +
    MoneroTxWallet: typeof MoneroTxWallet
  • +
  • +
    MoneroUtils: typeof MoneroUtils
  • +
  • +
    MoneroVersion: typeof MoneroVersion
  • +
  • +
    MoneroWallet: typeof MoneroWallet
  • +
  • +
    MoneroWalletConfig: typeof MoneroWalletConfig
  • +
  • +
    MoneroWalletFull: typeof MoneroWalletFull
  • +
  • +
    MoneroWalletKeys: typeof MoneroWalletKeys
  • +
  • +
    MoneroWalletListener: typeof MoneroWalletListener
  • +
  • +
    MoneroWalletRpc: typeof MoneroWalletRpc
  • +
  • +
    SslOptions: typeof SslOptions
  • +
  • +
    TaskLooper: typeof TaskLooper
  • +
  • +
    ThreadPool: typeof ThreadPool
  • +
  • +
    connectToDaemonRpc: ((uriOrConfig, username?, password?) => Promise<MoneroDaemonRpc>)
    +
      +
    • +
        +
      • (uriOrConfig, username?, password?): Promise<MoneroDaemonRpc>
      • +
      • +

        Create a client connected to monerod.

        + +

        Examples:

        + + +let daemon = await moneroTs.connectToDaemonRpc("http://localhost:38081");
        +

        +
        + +let daemon = await moneroTs.connectToDaemonRpc({
        +   uri: "http://localhost:38081",
        +   username: "superuser",
        +   password: "abctesting123"
        +}); +

        +
        + +// start monerod as an internal process
        +let daemon = await moneroTs.connectToDaemonRpc({
        +   cmd: ["path/to/monerod", ...params...],
        +}); +

        +
        +

        Parameters

        +
          +
        • +
          uriOrConfig: string | string[] | Partial<MoneroRpcConnection> | Partial<MoneroDaemonConfig>
          +

          uri or rpc connection or config or terminal parameters to connect to monerod

          +
          +
        • +
        • +
          Optional username: string
          +

          username to authenticate with monerod

          +
          +
        • +
        • +
          Optional password: string
          +

          password to authenticate with monerod

          +
          +
        +

        Returns Promise<MoneroDaemonRpc>

        the daemon RPC client

        + +
  • +
  • +
    connectToWalletRpc: ((uriOrConfig, username?, password?) => Promise<MoneroWalletRpc>)
    +
      +
    • +
        +
      • (uriOrConfig, username?, password?): Promise<MoneroWalletRpc>
      • +
      • +

        Create a client connected to monero-wallet-rpc.

        + +

        Examples:

        + + +let walletRpc = await moneroTs.connectToWalletRpc({
        +   uri: "http://localhost:38081",
        +   username: "superuser",
        +   password: "abctesting123",
        +   rejectUnauthorized: false // e.g. local development
        +});
        +

        +
        + +// connect to monero-wallet-rpc running as internal process
        +let walletRpc = await moneroTs.connectToWalletRpc({cmd: [
        +   "/path/to/monero-wallet-rpc",
        +   "--stagenet",
        +   "--daemon-address", "http://localhost:38081",
        +   "--daemon-login", "superuser:abctesting123",
        +   "--rpc-bind-port", "38085",
        +   "--rpc-login", "rpc_user:abc123",
        +   "--wallet-dir", "/path/to/wallets", // defaults to monero-wallet-rpc directory
        +   "--rpc-access-control-origins", "http://localhost:8080"
        + ]}); +
        +
        +

        Parameters

        +
          +
        • +
          uriOrConfig: string | string[] | Partial<MoneroRpcConnection> | Partial<MoneroWalletConfig>
          +

          uri or rpc connection or config or terminal parameters to connect to monero-wallet-rpc

          +
          +
        • +
        • +
          Optional username: string
          +

          username to authenticate with monero-wallet-rpc

          +
          +
        • +
        • +
          Optional password: string
          +

          password to authenticate with monero-wallet-rpc

          +
          +
        +

        Returns Promise<MoneroWalletRpc>

        the wallet RPC client

        + +
  • +
  • +
    createWalletFull: ((config) => Promise<MoneroWalletFull>)
    +
      +
    • +
        +
      • (config): Promise<MoneroWalletFull>
      • +
      • +

        Create a Monero wallet using client-side WebAssembly bindings to monero-project's wallet2 in C++.

        + +

        Example:

        + + +const wallet = await moneroTs.createWalletFull({
        +   path: "./test_wallets/wallet1", // leave blank for in-memory wallet
        +   password: "supersecretpassword",
        +   networkType: moneroTs.MoneroNetworkType.STAGENET,
        +   seed: "coexist igloo pamphlet lagoon...",
        +   restoreHeight: 1543218,
        +   server: "http://localhost:38081"
        +}); +

        +
        + +const wallet = await moneroTs.createWalletFull({
        +   path: "./test_wallets/wallet1", // leave blank for in-memory wallet
        +   password: "supersecretpassword",
        +   networkType: moneroTs.MoneroNetworkType.STAGENET,
        +   seed: "coexist igloo pamphlet lagoon...",
        +   restoreHeight: 1543218,
        +   proxyToWorker: false, // override default
        +   server: {
        +     uri: "http://localhost:38081",
        +     username: "daemon_user",
        +     password: "daemon_password_123"
        +   }
        +}); +
        +
        +

        Parameters

        +
          +
        • +
          config: Partial<MoneroWalletConfig>
          +

          MoneroWalletConfig or equivalent config object

          +
          +
        +

        Returns Promise<MoneroWalletFull>

        the created wallet

        + +
  • +
  • +
    createWalletKeys: ((config) => Promise<MoneroWalletKeys>)
    +
      +
    • +
        +
      • (config): Promise<MoneroWalletKeys>
      • +
      • +

        Create a wallet using WebAssembly bindings to monero-project.

        + +

        Example:

        + + +const wallet = await moneroTs.createWalletKeys({
        +   password: "abc123",
        +   networkType: moneroTs.MoneroNetworkType.STAGENET,
        +   seed: "coexist igloo pamphlet lagoon..."
        +}); +
        +
        +

        Parameters

        +
          +
        • +
          config: Partial<MoneroWalletConfig>
          +

          MoneroWalletConfig or equivalent config object

          +
          +
        +

        Returns Promise<MoneroWalletKeys>

        the created wallet

        + +
  • +
  • +
    getVersion: (() => string)
    +
      +
    • +
        +
      • (): string
      • +
      • +

        Get the version of the monero-ts library.

        +

        Returns string

        the version of this monero-ts library

        + +
  • +
  • +
    openWalletFull: ((config) => Promise<MoneroWalletFull>)
    +
      +
    • +
        +
      • (config): Promise<MoneroWalletFull>
      • +
      • +

        Open an existing Monero wallet using client-side WebAssembly bindings to monero-project's wallet2 in C++.

        + +

        Example:

        + + +const wallet = await moneroTs.openWalletFull({
        +   path: "./wallets/wallet1",
        +   password: "supersecretpassword",
        +   networkType: moneroTs.MoneroNetworkType.STAGENET,
        +   server: { // daemon configuration
        +     uri: "http://localhost:38081",
        +     username: "superuser",
        +     password: "abctesting123"
        +   }
        +}); +

        +
        +

        Parameters

        +
        +

        Returns Promise<MoneroWalletFull>

        the opened wallet

        + +
  • +
  • +
    shutdown: (() => Promise<void>)
    +
      +
    • +
        +
      • (): Promise<void>
      • +
      • +

        Shut down the monero-ts library, terminating any running workers.

        +

        Returns Promise<void>

        promise that resolves when the library has shut down

        + +
+
+
+

Generated using TypeDoc

+
\ No newline at end of file diff --git a/external/monero-cpp b/external/monero-cpp index c5ef7959e..4e22908e5 160000 --- a/external/monero-cpp +++ b/external/monero-cpp @@ -1 +1 @@ -Subproject commit c5ef7959e85e43cb89cad65daf3d40d960f65452 +Subproject commit 4e22908e511a531ec58bc04dc9b262187b7f8051 diff --git a/index.js b/index.js deleted file mode 100644 index c23111bc2..000000000 --- a/index.js +++ /dev/null @@ -1,262 +0,0 @@ -'use strict' - -/** - * Export all library models. - * - * See the full model specification: http://moneroecosystem.org/monero-java/monero-spec.pdf - */ -module.exports = {}; - -// export common models -module.exports.GenUtils = require("./src/main/js/common/GenUtils"); -module.exports.BigInteger = require("./src/main/js/common/biginteger").BigInteger; -module.exports.Filter = require("./src/main/js/common/Filter"); -module.exports.MoneroError = require("./src/main/js/common/MoneroError"); -module.exports.HttpClient = require("./src/main/js/common/HttpClient"); -module.exports.LibraryUtils = require("./src/main/js/common/LibraryUtils"); -module.exports.MoneroRpcConnection = require("./src/main/js/common/MoneroRpcConnection"); -module.exports.MoneroRpcError = require("./src/main/js/common/MoneroRpcError"); -module.exports.SslOptions = require("./src/main/js/common/SslOptions"); - -// export daemon models -module.exports.ConnectionType = require("./src/main/js/daemon/model/ConnectionType"); -module.exports.MoneroAltChain = require("./src/main/js/daemon/model/MoneroAltChain"); -module.exports.MoneroBan = require("./src/main/js/daemon/model/MoneroBan"); -module.exports.MoneroBlockHeader = require("./src/main/js/daemon/model/MoneroBlockHeader"); -module.exports.MoneroBlock = require("./src/main/js/daemon/model/MoneroBlock"); -module.exports.MoneroBlockTemplate = require("./src/main/js/daemon/model/MoneroBlockTemplate"); -module.exports.MoneroDaemonConnection = require("./src/main/js/daemon/model/MoneroDaemonConnection"); -module.exports.MoneroDaemonConnectionSpan = require("./src/main/js/daemon/model/MoneroDaemonConnectionSpan"); -module.exports.MoneroDaemonInfo = require("./src/main/js/daemon/model/MoneroDaemonInfo"); -module.exports.MoneroDaemonPeer = require("./src/main/js/daemon/model/MoneroDaemonPeer"); -module.exports.MoneroDaemonSyncInfo = require("./src/main/js/daemon/model/MoneroDaemonSyncInfo"); -module.exports.MoneroDaemonUpdateCheckResult = require("./src/main/js/daemon/model/MoneroDaemonUpdateCheckResult"); -module.exports.MoneroDaemonUpdateDownloadResult = require("./src/main/js/daemon/model/MoneroDaemonUpdateDownloadResult"); -module.exports.MoneroHardForkInfo = require("./src/main/js/daemon/model/MoneroHardForkInfo"); -module.exports.MoneroKeyImage = require("./src/main/js/daemon/model/MoneroKeyImage"); -module.exports.MoneroKeyImageSpentStatus = require("./src/main/js/daemon/model/MoneroKeyImageSpentStatus"); -module.exports.MoneroMinerTxSum = require("./src/main/js/daemon/model/MoneroMinerTxSum"); -module.exports.MoneroMiningStatus = require("./src/main/js/daemon/model/MoneroMiningStatus"); -module.exports.MoneroNetworkType = require("./src/main/js/daemon/model/MoneroNetworkType"); -module.exports.MoneroOutput = require("./src/main/js/daemon/model/MoneroOutput"); -module.exports.MoneroOutputHistogramEntry = require("./src/main/js/daemon/model/MoneroOutputHistogramEntry"); -module.exports.MoneroSubmitTxResult = require("./src/main/js/daemon/model/MoneroSubmitTxResult"); -module.exports.MoneroTx = require("./src/main/js/daemon/model/MoneroTx"); -module.exports.MoneroTxPoolStats = require("./src/main/js/daemon/model/MoneroTxPoolStats"); -module.exports.MoneroVersion = require("./src/main/js/daemon/model/MoneroVersion"); - -// export wallet models -module.exports.MoneroAccount = require("./src/main/js/wallet/model/MoneroAccount"); -module.exports.MoneroAccountTag = require("./src/main/js/wallet/model/MoneroAccountTag"); -module.exports.MoneroAddressBookEntry = require("./src/main/js/wallet/model/MoneroAddressBookEntry"); -module.exports.MoneroCheck = require("./src/main/js/wallet/model/MoneroCheck"); -module.exports.MoneroCheckReserve = require("./src/main/js/wallet/model/MoneroCheckReserve"); -module.exports.MoneroCheckTx = require("./src/main/js/wallet/model/MoneroCheckTx"); -module.exports.MoneroDestination = require("./src/main/js/wallet/model/MoneroDestination"); -module.exports.MoneroIntegratedAddress = require("./src/main/js/wallet/model/MoneroIntegratedAddress"); -module.exports.MoneroKeyImageImportResult = require("./src/main/js/wallet/model/MoneroKeyImageImportResult"); -module.exports.MoneroMultisigInfo = require("./src/main/js/wallet/model/MoneroMultisigInfo"); -module.exports.MoneroMultisigInitResult = require("./src/main/js/wallet/model/MoneroMultisigInitResult"); -module.exports.MoneroMultisigSignResult = require("./src/main/js/wallet/model/MoneroMultisigSignResult"); -module.exports.MoneroOutputWallet = require("./src/main/js/wallet/model/MoneroOutputWallet"); -module.exports.MoneroOutputQuery = require("./src/main/js/wallet/model/MoneroOutputQuery"); -module.exports.MoneroTxPriority = require("./src/main/js/wallet/model/MoneroTxPriority"); -module.exports.MoneroTxConfig = require("./src/main/js/wallet/model/MoneroTxConfig"); -module.exports.MoneroSubaddress = require("./src/main/js/wallet/model/MoneroSubaddress"); -module.exports.MoneroSyncResult = require("./src/main/js/wallet/model/MoneroSyncResult"); -module.exports.MoneroTransfer = require("./src/main/js/wallet/model/MoneroTransfer"); -module.exports.MoneroIncomingTransfer = require("./src/main/js/wallet/model/MoneroIncomingTransfer"); -module.exports.MoneroOutgoingTransfer = require("./src/main/js/wallet/model/MoneroOutgoingTransfer"); -module.exports.MoneroTransferQuery = require("./src/main/js/wallet/model/MoneroTransferQuery"); -module.exports.MoneroTxSet = require("./src/main/js/wallet/model/MoneroTxSet"); -module.exports.MoneroTxWallet = require("./src/main/js/wallet/model/MoneroTxWallet"); -module.exports.MoneroTxQuery = require("./src/main/js/wallet/model/MoneroTxQuery"); -module.exports.MoneroWalletListener = require("./src/main/js/wallet/model/MoneroWalletListener"); -module.exports.MoneroWalletConfig = require("./src/main/js/wallet/model/MoneroWalletConfig"); - -// export daemon, wallet, and utils classes -module.exports.MoneroUtils = require("./src/main/js/common/MoneroUtils"); -module.exports.MoneroDaemon = require("./src/main/js/daemon/MoneroDaemon"); -module.exports.MoneroWallet = require("./src/main/js/wallet/MoneroWallet"); -module.exports.MoneroDaemonRpc = require("./src/main/js/daemon/MoneroDaemonRpc"); -module.exports.MoneroWalletRpc = require("./src/main/js/wallet/MoneroWalletRpc"); -module.exports.MoneroWalletKeys = require("./src/main/js/wallet/MoneroWalletKeys"); -module.exports.MoneroWalletWasm = require("./src/main/js/wallet/MoneroWalletWasm"); - -// ---------------------------- GLOBAL FUNCTIONS ------------------------------ - -/** - *

Get the version of the monero-javascript library.

- * - * @return {string} the version of this monero-javascript library - */ -module.exports.getVersion = function() { - return module.exports.MoneroUtils.getVersion(); -} - -/** - *

Create a client connected to monero-daemon-rpc.

- * - *

Examples:

- * - * - * let daemon = monerojs.connectToDaemonRpc("http://localhost:38081", "superuser", "abctesting123");

- * - * let daemon = monerojs.connectToDaemonRpc({
- *    uri: "http://localhost:38081",
- *    username: "superuser",
- *    password: "abctesting123"
- * }); - *
- * - * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - uri of monero-daemon-rpc or JS config object or MoneroRpcConnection - * @param {string} uriOrConfigOrConnection.uri - uri of monero-daemon-rpc - * @param {string} uriOrConfigOrConnection.username - username to authenticate with monero-daemon-rpc (optional) - * @param {string} uriOrConfigOrConnection.password - password to authenticate with monero-daemon-rpc (optional) - * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true) - * @param {number} uriOrConfigOrConnection.pollInterval - poll interval to query for updates in ms (default 5000) - * @param {boolean} uriOrConfigOrConnection.proxyToWorker - run the daemon client in a web worker if true (default true if browser, false otherwise) - * @param {string} username - username to authenticate with monero-daemon-rpc (optional) - * @param {string} password - password to authenticate with monero-daemon-rpc (optional) - * @param {boolean} rejectUnauthorized - rejects self-signed certificates if true (default true) - * @param {number} pollInterval - poll interval to query for updates in ms (default 5000) - * @param {boolean} proxyToWorker - runs the daemon client in a web worker if true (default true if browser, false otherwise) - * @return {MoneroDaemonRpc} the daemon RPC client - */ -module.exports.connectToDaemonRpc = function() { return new module.exports.MoneroDaemonRpc(...arguments); } - -/** - *

Create a client connected to monero-wallet-rpc.

- * - *

Examples:

- * - * - * let walletRpc = monerojs.connectToWalletRpc("http://localhost:38081", "superuser", "abctesting123");

- * - * let walletRpc = monerojs.connectToWalletRpc({
- *    uri: "http://localhost:38081",
- *    username: "superuser",
- *    password: "abctesting123",
- *    rejectUnauthorized: false // e.g. local development
- * }); - *
- * - * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - uri of monero-wallet-rpc or JS config object or MoneroRpcConnection - * @param {string} uriOrConfigOrConnection.uri - uri of monero-wallet-rpc - * @param {string} uriOrConfigOrConnection.username - username to authenticate with monero-wallet-rpc (optional) - * @param {string} uriOrConfigOrConnection.password - password to authenticate with monero-wallet-rpc (optional) - * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true) - * @param {string} username - username to authenticate with monero-wallet-rpc (optional) - * @param {string} password - password to authenticate with monero-wallet-rpc (optional) - * @param {boolean} rejectUnauthorized - rejects self-signed certificates if true (default true) - * @return {MoneroWalletRpc} the wallet RPC client - */ -module.exports.connectToWalletRpc = function() { return new module.exports.MoneroWalletRpc(...arguments); } - -/** - *

Create a wallet using WebAssembly bindings to monero-core.

- * - *

Example:

- * - * - * let wallet = await monerojs.createWalletWasm({
- *    path: "./test_wallets/wallet1", // leave blank for in-memory wallet
- *    password: "supersecretpassword",
- *    networkType: MoneroNetworkType.STAGENET,
- *    mnemonic: "coexist igloo pamphlet lagoon...",
- *    restoreHeight: 1543218,
- *    server: new monerojs.MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123"),
- * }); - *
- * - * @param {object|MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object - * @param {string} config.path - path of the wallet to create (optional, in-memory wallet if not given) - * @param {string} config.password - password of the wallet to create - * @param {string|number} config.networkType - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) - * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given) - * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase - * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys) - * @param {string} config.privateViewKey - private view key of the wallet to create (optional) - * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional) - * @param {number} config.restoreHeight - block height to start scanning frsom (defaults to 0 unless generating random wallet) - * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected) - * @param {string} config.serverUri - uri of the wallet's daemon (optional) - * @param {string} config.serverUsername - username to authenticate with the daemon (optional) - * @param {string} config.serverPassword - password to authenticate with the daemon (optional) - * @param {boolean} config.rejectUnauthorized - reject self-signed server certificates if true (defaults to true) - * @param {MoneroRpcConnection|object} config.server - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional) - * @param {boolean} config.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise) - * @param {fs} config.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser) - * @return {MoneroWalletWasm} the created wallet - */ -module.exports.createWalletWasm = function() { return module.exports.MoneroWalletWasm.createWallet(...arguments); } - -/** - *

Open an existing wallet using WebAssembly bindings to monero-core.

- * - *

Examples:

- * - * - * let wallet1 = await monerojs.openWalletWasm(
- *    "./wallets/wallet1",
- *    "supersecretpassword",
- *    MoneroNetworkType.STAGENET,
- *    "http://localhost:38081" // daemon uri
- * );

- * - * let wallet2 = await monerojs.openWalletWasm({
- *    path: "./wallets/wallet2",
- *    password: "supersecretpassword",
- *    networkType: MoneroNetworkType.STAGENET,
- *    serverUri: "http://localhost:38081", // daemon configuration
- *    serverUsername: "superuser",
- *    serverPassword: "abctesting123"
- * }); - *
- * - * @param {MoneroWalletConfig|object|string} configOrPath - MoneroWalletConfig or equivalent config object or a path to a wallet to open - * @param {string} configOrPath.path - path of the wallet to open (optional if 'keysData' provided) - * @param {string} configOrPath.password - password of the wallet to open - * @param {string|number} configOrPath.networkType - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) - * @param {Uint8Array} configOrPath.keysData - wallet keys data to open (optional if path provided) - * @param {Uint8Array} configOrPath.cacheData - wallet cache data to open (optional) - * @param {string} configOrPath.serverUri - uri of the wallet's daemon (optional) - * @param {string} configOrPath.serverUsername - username to authenticate with the daemon (optional) - * @param {string} configOrPath.serverPassword - password to authenticate with the daemon (optional) - * @param {boolean} configOrPath.rejectUnauthorized - reject self-signed server certificates if true (defaults to true) - * @param {MoneroRpcConnection|object} configOrPath.server - MoneroRpcConnection or equivalent JS object configuring the daemon connection (optional) - * @param {boolean} configOrPath.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise) - * @param {fs} configOrPath.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser) - * @param {string} password - password of the wallet to open - * @param {string|number} networkType - network type of the wallet to open - * @param {string|MoneroRpcConnection} daemonUriOrConnection - daemon URI or MoneroRpcConnection - * @param {boolean} proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise) - * @param {fs} fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser) - * @return {MoneroWalletWasm} the opened wallet - */ -module.exports.openWalletWasm = function() { return module.exports.MoneroWalletWasm.openWallet(...arguments); } - -/** - *

Create a wallet using WebAssembly bindings to monero-core.

- * - *

Example:

- * - * - * let wallet = await monerojs.createWalletKeys({
- *    password: "abc123",
- *    networkType: MoneroNetworkType.STAGENET,
- *    mnemonic: "coexist igloo pamphlet lagoon..."
- * }); - *
- * - * @param {MoneroWalletConfig|object} config - MoneroWalletConfig or equivalent config object - * @param {string|number} config.networkType - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) - * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given) - * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase - * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys) - * @param {string} config.privateViewKey - private view key of the wallet to create (optional) - * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional) - * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected) - * @return {MoneroWalletKeys} the created wallet - */ -module.exports.createWalletKeys = function() { return module.exports.MoneroWalletKeys.createWallet(...arguments); } diff --git a/index.ts b/index.ts new file mode 100644 index 000000000..3bf3466d8 --- /dev/null +++ b/index.ts @@ -0,0 +1,562 @@ +'use strict' + +// --------------------------------- IMPORTS ---------------------------------- + +// See the full model specification: https://woodser.github.io/monero-java/monero-spec.pdf + +// import common models +import GenUtils from "./src/main/ts/common/GenUtils"; +import Filter from "./src/main/ts/common/Filter"; +import MoneroError from "./src/main/ts/common/MoneroError"; +import HttpClient from "./src/main/ts/common/HttpClient"; +import LibraryUtils from "./src/main/ts/common/LibraryUtils"; +import MoneroRpcConnection from "./src/main/ts/common/MoneroRpcConnection"; +import MoneroRpcError from "./src/main/ts/common/MoneroRpcError"; +import SslOptions from "./src/main/ts/common/SslOptions"; +import TaskLooper from "./src/main/ts/common/TaskLooper"; + +// import daemon models +import ConnectionType from "./src/main/ts/daemon/model/ConnectionType"; +import MoneroAltChain from "./src/main/ts/daemon/model/MoneroAltChain"; +import MoneroBan from "./src/main/ts/daemon/model/MoneroBan"; +import MoneroBlockHeader from "./src/main/ts/daemon/model/MoneroBlockHeader"; +import MoneroBlock from "./src/main/ts/daemon/model/MoneroBlock"; +import MoneroBlockTemplate from "./src/main/ts/daemon/model/MoneroBlockTemplate"; +import MoneroConnectionSpan from "./src/main/ts/daemon/model/MoneroConnectionSpan"; +import MoneroDaemonConfig from "./src/main/ts/daemon/model/MoneroDaemonConfig"; +import MoneroDaemonInfo from "./src/main/ts/daemon/model/MoneroDaemonInfo"; +import MoneroDaemonListener from "./src/main/ts/daemon/model/MoneroDaemonListener"; +import MoneroDaemonSyncInfo from "./src/main/ts/daemon/model/MoneroDaemonSyncInfo"; +import MoneroDaemonUpdateCheckResult from "./src/main/ts/daemon/model/MoneroDaemonUpdateCheckResult"; +import MoneroDaemonUpdateDownloadResult from "./src/main/ts/daemon/model/MoneroDaemonUpdateDownloadResult"; +import MoneroFeeEstimate from "./src/main/ts/daemon/model/MoneroFeeEstimate"; +import MoneroHardForkInfo from "./src/main/ts/daemon/model/MoneroHardForkInfo"; +import MoneroKeyImage from "./src/main/ts/daemon/model/MoneroKeyImage"; +import MoneroKeyImageSpentStatus from "./src/main/ts/daemon/model/MoneroKeyImageSpentStatus"; +import MoneroMinerTxSum from "./src/main/ts/daemon/model/MoneroMinerTxSum"; +import MoneroMiningStatus from "./src/main/ts/daemon/model/MoneroMiningStatus"; +import MoneroNetworkType from "./src/main/ts/daemon/model/MoneroNetworkType"; +import MoneroOutput from "./src/main/ts/daemon/model/MoneroOutput"; +import MoneroOutputHistogramEntry from "./src/main/ts/daemon/model/MoneroOutputHistogramEntry"; +import MoneroSubmitTxResult from "./src/main/ts/daemon/model/MoneroSubmitTxResult"; +import MoneroTx from "./src/main/ts/daemon/model/MoneroTx"; +import MoneroTxPoolStats from "./src/main/ts/daemon/model/MoneroTxPoolStats"; +import MoneroVersion from "./src/main/ts/daemon/model/MoneroVersion"; +import MoneroPeer from "./src/main/ts/daemon/model/MoneroPeer"; +import MoneroPruneResult from "./src/main/ts/daemon/model/MoneroPruneResult"; + +// import wallet models +import MoneroAccount from "./src/main/ts/wallet/model/MoneroAccount"; +import MoneroAccountTag from "./src/main/ts/wallet/model/MoneroAccountTag"; +import MoneroAddressBookEntry from "./src/main/ts/wallet/model/MoneroAddressBookEntry"; +import MoneroCheck from "./src/main/ts/wallet/model/MoneroCheck"; +import MoneroCheckReserve from "./src/main/ts/wallet/model/MoneroCheckReserve"; +import MoneroCheckTx from "./src/main/ts/wallet/model/MoneroCheckTx"; +import MoneroDestination from "./src/main/ts/wallet/model/MoneroDestination"; +import MoneroIntegratedAddress from "./src/main/ts/wallet/model/MoneroIntegratedAddress"; +import MoneroKeyImageImportResult from "./src/main/ts/wallet/model/MoneroKeyImageImportResult"; +import MoneroMultisigInfo from "./src/main/ts/wallet/model/MoneroMultisigInfo"; +import MoneroMultisigInitResult from "./src/main/ts/wallet/model/MoneroMultisigInitResult"; +import MoneroMultisigSignResult from "./src/main/ts/wallet/model/MoneroMultisigSignResult"; +import MoneroOutputWallet from "./src/main/ts/wallet/model/MoneroOutputWallet"; +import MoneroOutputQuery from "./src/main/ts/wallet/model/MoneroOutputQuery"; +import MoneroTxPriority from "./src/main/ts/wallet/model/MoneroTxPriority"; +import MoneroTxConfig from "./src/main/ts/wallet/model/MoneroTxConfig"; +import MoneroSubaddress from "./src/main/ts/wallet/model/MoneroSubaddress"; +import MoneroSyncResult from "./src/main/ts/wallet/model/MoneroSyncResult"; +import MoneroTransfer from "./src/main/ts/wallet/model/MoneroTransfer"; +import MoneroIncomingTransfer from "./src/main/ts/wallet/model/MoneroIncomingTransfer"; +import MoneroOutgoingTransfer from "./src/main/ts/wallet/model/MoneroOutgoingTransfer"; +import MoneroTransferQuery from "./src/main/ts/wallet/model/MoneroTransferQuery"; +import MoneroTxSet from "./src/main/ts/wallet/model/MoneroTxSet"; +import MoneroTxWallet from "./src/main/ts/wallet/model/MoneroTxWallet"; +import MoneroTxQuery from "./src/main/ts/wallet/model/MoneroTxQuery"; +import MoneroWalletListener from "./src/main/ts/wallet/model/MoneroWalletListener"; +import MoneroWalletConfig from "./src/main/ts/wallet/model/MoneroWalletConfig"; +import MoneroMessageSignatureType from "./src/main/ts/wallet/model/MoneroMessageSignatureType"; +import MoneroMessageSignatureResult from "./src/main/ts/wallet/model/MoneroMessageSignatureResult"; + +// import connection manager +import MoneroConnectionManager from "./src/main/ts/common/MoneroConnectionManager"; +import MoneroConnectionManagerListener from "./src/main/ts/common/MoneroConnectionManagerListener"; + +// import daemon, wallet, and util classes +import MoneroDaemon from "./src/main/ts/daemon/MoneroDaemon"; +import MoneroWallet from "./src/main/ts/wallet/MoneroWallet"; +import MoneroDaemonRpc from "./src/main/ts/daemon/MoneroDaemonRpc"; +import MoneroWalletRpc from "./src/main/ts/wallet/MoneroWalletRpc"; +import { MoneroWalletKeys } from "./src/main/ts/wallet/MoneroWalletKeys"; +import MoneroWalletFull from "./src/main/ts/wallet/MoneroWalletFull"; +import MoneroUtils from "./src/main/ts/common/MoneroUtils"; +import ThreadPool from "./src/main/ts/common/ThreadPool"; + +// ---------------------------- GLOBAL FUNCTIONS ------------------------------ + +/** + *

Get the version of the monero-ts library.

+ * + * @return {string} the version of this monero-ts library + */ +function getVersion() { + return MoneroUtils.getVersion(); +} + +/** + *

Create a client connected to monerod.

+ * + *

Examples:

+ * + * + * let daemon = await moneroTs.connectToDaemonRpc("http://localhost:38081");
+ *

+ *
+ * + * let daemon = await moneroTs.connectToDaemonRpc({
+ *    uri: "http://localhost:38081",
+ *    username: "superuser",
+ *    password: "abctesting123"
+ * }); + *

+ *
+ * + * // start monerod as an internal process
+ * let daemon = await moneroTs.connectToDaemonRpc({
+ *    cmd: ["path/to/monerod", ...params...],
+ * }); + *
+ * + * @param {string|Partial|Partial|string[]} uriOrConfig - uri or rpc connection or config or terminal parameters to connect to monerod + * @param {string} [username] - username to authenticate with monerod + * @param {string} [password] - password to authenticate with monerod + * @return {Promise} the daemon RPC client + */ +function connectToDaemonRpc(uriOrConfig: string | Partial | Partial | string[], username?: string, password?: string): Promise { + return MoneroDaemonRpc.connectToDaemonRpc(uriOrConfig, username, password); +} + +/** + *

Create a client connected to monero-wallet-rpc.

+ * + *

Examples:

+ * + * + * let walletRpc = await moneroTs.connectToWalletRpc({
+ *    uri: "http://localhost:38081",
+ *    username: "superuser",
+ *    password: "abctesting123",
+ *    rejectUnauthorized: false // e.g. local development
+ * });
+ *

+ *
+ * + * // connect to monero-wallet-rpc running as internal process
+ * let walletRpc = await moneroTs.connectToWalletRpc({cmd: [
+ *    "/path/to/monero-wallet-rpc",
+ *    "--stagenet",
+ *    "--daemon-address", "http://localhost:38081",
+ *    "--daemon-login", "superuser:abctesting123",
+ *    "--rpc-bind-port", "38085",
+ *    "--rpc-login", "rpc_user:abc123",
+ *    "--wallet-dir", "/path/to/wallets", // defaults to monero-wallet-rpc directory
+ *    "--rpc-access-control-origins", "http://localhost:8080"
+ *  ]}); + *
+ * + * @param {string|Partial|Partial|string[]} uriOrConfig - uri or rpc connection or config or terminal parameters to connect to monero-wallet-rpc + * @param {string} [username] - username to authenticate with monero-wallet-rpc + * @param {string} [password] - password to authenticate with monero-wallet-rpc + * @return {Promise} the wallet RPC client + */ +function connectToWalletRpc(uriOrConfig: string | Partial | Partial | string[], username?: string, password?: string): Promise { + return MoneroWalletRpc.connectToWalletRpc(uriOrConfig, username, password); +} + +/** + *

Create a Monero wallet using client-side WebAssembly bindings to monero-project's wallet2 in C++.

+ * + *

Example:

+ * + * + * const wallet = await moneroTs.createWalletFull({
+ *    path: "./test_wallets/wallet1", // leave blank for in-memory wallet
+ *    password: "supersecretpassword",
+ *    networkType: moneroTs.MoneroNetworkType.STAGENET,
+ *    seed: "coexist igloo pamphlet lagoon...",
+ *    restoreHeight: 1543218,
+ *    server: "http://localhost:38081"
+ * }); + *

+ *
+ * + * const wallet = await moneroTs.createWalletFull({
+ *    path: "./test_wallets/wallet1", // leave blank for in-memory wallet
+ *    password: "supersecretpassword",
+ *    networkType: moneroTs.MoneroNetworkType.STAGENET,
+ *    seed: "coexist igloo pamphlet lagoon...",
+ *    restoreHeight: 1543218,
+ *    proxyToWorker: false, // override default
+ *    server: {
+ *      uri: "http://localhost:38081",
+ *      username: "daemon_user",
+ *      password: "daemon_password_123"
+ *    }
+ * }); + *
+ * + * @param {Partial} config - MoneroWalletConfig or equivalent config object + * @param {string} [config.path] - path of the wallet to create (optional, in-memory wallet if not given) + * @param {string} [config.password] - password of the wallet to create + * @param {MoneroNetworkType|string} [config.networkType] - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) + * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given) + * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed phrase + * @param {boolean} [config.isMultisig] - restore multisig wallet from seed + * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys) + * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional) + * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional) + * @param {number} [config.restoreHeight] - block height to start scanning from (defaults to 0 unless generating random wallet) + * @param {string} [config.language] - language of the wallet's seed phrase (defaults to "English" or auto-detected) + * @param {number} [config.accountLookahead] - number of accounts to scan (optional) + * @param {number} [config.subaddressLookahead] - number of subaddresses to scan per account (optional) + * @param {string|Partial} [config.server] - connection to monero daemon (optional) + * @param {MoneroConnectionManager} [config.connectionManager] - manage connections to monerod (optional) + * @param {boolean} [config.rejectUnauthorized] - reject self-signed server certificates if true (defaults to true) + * @param {boolean} [config.proxyToWorker] - proxies wallet operations to a worker in order to not block the main thread (default true) + * @param {any} [config.fs] - file system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser) + * @return {Promise} the created wallet + */ +function createWalletFull(config: Partial): Promise { + return MoneroWalletFull.createWallet(new MoneroWalletConfig(config)); +} + +/** + *

Open an existing Monero wallet using client-side WebAssembly bindings to monero-project's wallet2 in C++.

+ * + *

Example:

+ * + * + * const wallet = await moneroTs.openWalletFull({
+ *    path: "./wallets/wallet1",
+ *    password: "supersecretpassword",
+ *    networkType: moneroTs.MoneroNetworkType.STAGENET,
+ *    server: { // daemon configuration
+ *      uri: "http://localhost:38081",
+ *      username: "superuser",
+ *      password: "abctesting123"
+ *    }
+ * }); + *
+ * + * @param {Partial} config - config to open a full wallet + * @param {string} [config.path] - path of the wallet to open (optional if 'keysData' provided) + * @param {string} [config.password] - password of the wallet to open + * @param {string|number} [config.networkType] - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) + * @param {string|MoneroRpcConnection} [config.server] - uri or connection to monero daemon (optional) + * @param {Uint8Array} [config.keysData] - wallet keys data to open (optional if path provided) + * @param {Uint8Array} [config.cacheData] - wallet cache data to open (optional) + * @param {boolean} [config.proxyToWorker] - proxies wallet operations to a worker in order to not block the main thread (default true) + * @param {any} [config.fs] - file system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser) + * @return {Promise} the opened wallet + */ +function openWalletFull(config: Partial): Promise { + return MoneroWalletFull.openWallet(new MoneroWalletConfig(config)); +} + +/** + *

Create a wallet using WebAssembly bindings to monero-project.

+ * + *

Example:

+ * + * + * const wallet = await moneroTs.createWalletKeys({
+ *    password: "abc123",
+ *    networkType: moneroTs.MoneroNetworkType.STAGENET,
+ *    seed: "coexist igloo pamphlet lagoon..."
+ * }); + *
+ * + * @param {Partial} config - MoneroWalletConfig or equivalent config object + * @param {string|number} config.networkType - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) + * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given) + * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed phrase + * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys) + * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional) + * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional) + * @param {string} [config.language] - language of the wallet's seed (defaults to "English" or auto-detected) + * @return {Promise} the created wallet + */ +function createWalletKeys(config: Partial): Promise { + return MoneroWalletKeys.createWallet(new MoneroWalletConfig(config)); +} + +/** + *

Shut down the monero-ts library, terminating any running workers.

+ * + * @return {Promise} promise that resolves when the library has shut down + */ +function shutdown(): Promise { + return LibraryUtils.terminateWorker(); +} + +// --------------------------------- EXPORTS ---------------------------------- + +export { + + // types + GenUtils, + Filter, + MoneroError, + HttpClient, + LibraryUtils, + MoneroRpcConnection, + MoneroRpcError, + SslOptions, + TaskLooper, + ConnectionType, + MoneroAltChain, + MoneroBan, + MoneroBlockHeader, + MoneroBlock, + MoneroBlockTemplate, + MoneroConnectionSpan, + MoneroDaemonConfig, + MoneroDaemonInfo, + MoneroDaemonListener, + MoneroDaemonSyncInfo, + MoneroDaemonUpdateCheckResult, + MoneroDaemonUpdateDownloadResult, + MoneroFeeEstimate, + MoneroHardForkInfo, + MoneroKeyImage, + MoneroKeyImageSpentStatus, + MoneroMinerTxSum, + MoneroMiningStatus, + MoneroNetworkType, + MoneroOutput, + MoneroOutputHistogramEntry, + MoneroSubmitTxResult, + MoneroTx, + MoneroTxPoolStats, + MoneroVersion, + MoneroPeer, + MoneroPruneResult, + MoneroAccount, + MoneroAccountTag, + MoneroAddressBookEntry, + MoneroCheck, + MoneroCheckReserve, + MoneroCheckTx, + MoneroDestination, + MoneroIntegratedAddress, + MoneroKeyImageImportResult, + MoneroMultisigInfo, + MoneroMultisigInitResult, + MoneroMultisigSignResult, + MoneroOutputWallet, + MoneroOutputQuery, + MoneroTxPriority, + MoneroTxConfig, + MoneroSubaddress, + MoneroSyncResult, + MoneroTransfer, + MoneroIncomingTransfer, + MoneroOutgoingTransfer, + MoneroTransferQuery, + MoneroTxSet, + MoneroTxWallet, + MoneroTxQuery, + MoneroWalletListener, + MoneroWalletConfig, + MoneroMessageSignatureType, + MoneroMessageSignatureResult, + MoneroConnectionManagerListener, + MoneroConnectionManager, + MoneroDaemon, + MoneroWallet, + MoneroDaemonRpc, + MoneroWalletRpc, + MoneroWalletKeys, + MoneroWalletFull, + MoneroUtils, + ThreadPool, + + // global functions + getVersion, + connectToDaemonRpc, + connectToWalletRpc, + createWalletFull, + openWalletFull, + createWalletKeys, + shutdown +}; + +// export default object with aggregate of all exports +const moneroTs = { + GenUtils, + Filter, + MoneroError, + HttpClient, + LibraryUtils, + MoneroRpcConnection, + MoneroRpcError, + SslOptions, + TaskLooper, + ConnectionType, + MoneroAltChain, + MoneroBan, + MoneroBlockHeader, + MoneroBlock, + MoneroBlockTemplate, + MoneroConnectionSpan, + MoneroDaemonConfig, + MoneroDaemonInfo, + MoneroDaemonListener, + MoneroDaemonSyncInfo, + MoneroDaemonUpdateCheckResult, + MoneroDaemonUpdateDownloadResult, + MoneroFeeEstimate, + MoneroHardForkInfo, + MoneroKeyImage, + MoneroKeyImageSpentStatus, + MoneroMinerTxSum, + MoneroMiningStatus, + MoneroNetworkType, + MoneroOutput, + MoneroOutputHistogramEntry, + MoneroSubmitTxResult, + MoneroTx, + MoneroTxPoolStats, + MoneroVersion, + MoneroPeer, + MoneroPruneResult, + MoneroAccount, + MoneroAccountTag, + MoneroAddressBookEntry, + MoneroCheck, + MoneroCheckReserve, + MoneroCheckTx, + MoneroDestination, + MoneroIntegratedAddress, + MoneroKeyImageImportResult, + MoneroMultisigInfo, + MoneroMultisigInitResult, + MoneroMultisigSignResult, + MoneroOutputWallet, + MoneroOutputQuery, + MoneroTxPriority, + MoneroTxConfig, + MoneroSubaddress, + MoneroSyncResult, + MoneroTransfer, + MoneroIncomingTransfer, + MoneroOutgoingTransfer, + MoneroTransferQuery, + MoneroTxSet, + MoneroTxWallet, + MoneroTxQuery, + MoneroWalletListener, + MoneroWalletConfig, + MoneroMessageSignatureType, + MoneroMessageSignatureResult, + MoneroConnectionManagerListener, + MoneroConnectionManager, + MoneroDaemon, + MoneroWallet, + MoneroDaemonRpc, + MoneroWalletRpc, + MoneroWalletKeys, + MoneroWalletFull, + MoneroUtils, + ThreadPool, + + // global functions + getVersion, + connectToDaemonRpc, + connectToWalletRpc, + createWalletFull, + openWalletFull, + createWalletKeys, + shutdown +} +export default moneroTs; + +// augment global scope with same namespace as default export +declare global { + namespace moneroTs { + type GenUtils = InstanceType; + type Filter = InstanceType; + type MoneroError = InstanceType; + type HttpClient = InstanceType; + type LibraryUtils = InstanceType; + type MoneroRpcConnection = InstanceType; + type MoneroRpcError = InstanceType; + type SslOptions = InstanceType; + type TaskLooper = InstanceType; + type ConnectionType = import("./index").ConnectionType; // type alias for enum + type MoneroAltChain = InstanceType; + type MoneroBan = InstanceType; + type MoneroBlockHeader = InstanceType; + type MoneroBlock = InstanceType; + type MoneroBlockTemplate = InstanceType; + type MoneroConnectionSpan = InstanceType; + type MoneroDaemonConfig = InstanceType; + type MoneroDaemonInfo = InstanceType; + type MoneroDaemonListener = InstanceType; + type MoneroDaemonSyncInfo = InstanceType; + type MoneroDaemonUpdateCheckResult = InstanceType; + type MoneroDaemonUpdateDownloadResult = InstanceType; + type MoneroFeeEstimate = InstanceType; + type MoneroHardForkInfo = InstanceType; + type MoneroKeyImage = InstanceType; + type MoneroKeyImageSpentStatus = import("./index").MoneroKeyImageSpentStatus; + type MoneroMinerTxSum = InstanceType; + type MoneroMiningStatus = InstanceType; + type MoneroNetworkType = InstanceType; + type MoneroOutput = InstanceType; + type MoneroOutputHistogramEntry = InstanceType; + type MoneroSubmitTxResult = InstanceType; + type MoneroTx = InstanceType; + type MoneroTxPoolStats = InstanceType; + type MoneroVersion = InstanceType; + type MoneroPeer = InstanceType; + type MoneroPruneResult = InstanceType; + type MoneroAccount = InstanceType; + type MoneroAccountTag = InstanceType; + type MoneroAddressBookEntry = InstanceType; + type MoneroCheck = InstanceType; + type MoneroCheckReserve = InstanceType; + type MoneroCheckTx = InstanceType; + type MoneroDestination = InstanceType; + type MoneroIntegratedAddress = InstanceType; + type MoneroKeyImageImportResult = InstanceType; + type MoneroMultisigInfo = InstanceType; + type MoneroMultisigInitResult = InstanceType; + type MoneroMultisigSignResult = InstanceType; + type MoneroOutputWallet = InstanceType; + type MoneroOutputQuery = InstanceType; + type MoneroTxPriority = import("./index").MoneroTxPriority; + type MoneroTxConfig = InstanceType; + type MoneroSubaddress = InstanceType; + type MoneroSyncResult = InstanceType; + type MoneroTransfer = InstanceType; + type MoneroIncomingTransfer = InstanceType; + type MoneroOutgoingTransfer = InstanceType; + type MoneroTransferQuery = InstanceType; + type MoneroTxSet = InstanceType; + type MoneroTxWallet = InstanceType; + type MoneroTxQuery = InstanceType; + type MoneroWalletListener = InstanceType; + type MoneroWalletConfig = InstanceType; + type MoneroMessageSignatureType = import("./index").MoneroMessageSignatureType; + type MoneroMessageSignatureResult = InstanceType; + type MoneroConnectionManagerListener = InstanceType; + type MoneroConnectionManager = InstanceType; + type MoneroDaemon = InstanceType; + type MoneroWallet = InstanceType; + type MoneroDaemonRpc = InstanceType; + type MoneroWalletRpc = InstanceType; + type MoneroWalletKeys = InstanceType; + type MoneroWalletFull = InstanceType; + type MoneroUtils = InstanceType; + type ThreadPool = InstanceType; + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9d4f141b9..81748fcb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,2266 +1,3713 @@ { - "name": "monero-javascript", - "version": "0.4.3", - "lockfileVersion": 1, + "name": "monero-ts", + "version": "0.11.6", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", - "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/core": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.6.tgz", - "integrity": "sha512-nD3deLvbsApbHAHttzIssYqgb883yU/d9roe4RZymBCDaZryMJDbptVpEpeQuRh4BJ+SYI8le9YGxKvFEvl1Wg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.6", - "@babel/helper-module-transforms": "^7.9.0", - "@babel/helpers": "^7.9.6", - "@babel/parser": "^7.9.6", - "@babel/template": "^7.8.6", - "@babel/traverse": "^7.9.6", - "@babel/types": "^7.9.6", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", - "json5": "^2.1.2", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "packages": { + "": { + "name": "monero-ts", + "version": "0.11.6", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2", + "@types/node": "^20.6.0", + "ajv": "^6.12.6", + "async": "2.6.4", + "axios": "^1.7.4", + "crypto-js": "^4.0.0", + "decimal.js": "^10.4.3", + "net": "^1.0.2", + "promise-throttle": "^1.1.2", + "serialize-javascript": "^3.1.0", + "text-encoding": "^0.7.0", + "tls": "0.0.1", + "uuid": "3.3.2", + "web-worker": "1.3.0" + }, + "devDependencies": { + "@babel/cli": "^7.18.10", + "@babel/core": "^7.22.17", + "@babel/node": "^7.18.10", + "@babel/plugin-transform-runtime": "^7.18.10", + "@babel/preset-env": "^7.22.15", + "@babel/preset-typescript": "^7.22.15", + "@babel/register": "^7.22.15", + "@types/jquery": "^3.5.19", + "@types/mocha": "^9.1.1", + "@typescript-eslint/eslint-plugin": "5.53.0", + "@typescript-eslint/parser": "^5.53.0", + "assert": "^2.1.0", + "babel-loader": "^9.1.3", + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.3", + "crypto-browserify": "^3.12.0", + "eslint": "^8.35.0", + "eslint-config-prettier": "^8.6.0", + "eslint-import-resolver-typescript": "^3.5.3", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-jsx-a11y": "^6.7.1", + "https-browserify": "^1.0.0", + "memfs": "^4.11.1", + "mocha": "^9.1.3", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "querystring-es3": "^0.2.1", + "shx": "^0.3.4", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "ts-loader": "^9.4.4", + "ts-node": "^10.9.1", + "typedoc": "^0.25.1", + "typescript": "^5.2.2", + "url": "^0.11.3", + "util": "^0.12.5", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4", + "webpack-merge": "^5.9.0" + }, + "engines": { + "node": ">=10.0.0" } }, - "@babel/generator": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.6.tgz", - "integrity": "sha512-+htwWKJbH2bL72HRluF8zumBxzuX0ZZUFl3JLNyoUjM/Ho8wnVpPXM6aUz8cfKDqQ/h7zHqKt4xzJteUosckqQ==", + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", "dev": true, - "requires": { - "@babel/types": "^7.9.6", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - } + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "@babel/helper-function-name": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz", - "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==", + "node_modules/@ampproject/remapping": { + "version": "2.2.1", "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.8.3", - "@babel/template": "^7.8.3", - "@babel/types": "^7.9.5" + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" } }, - "@babel/helper-get-function-arity": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", - "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", + "node_modules/@babel/cli": { + "version": "7.23.0", "dev": true, - "requires": { - "@babel/types": "^7.8.3" + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "commander": "^4.0.1", + "convert-source-map": "^2.0.0", + "fs-readdir-recursive": "^1.1.0", + "glob": "^7.2.0", + "make-dir": "^2.1.0", + "slash": "^2.0.0" + }, + "bin": { + "babel": "bin/babel.js", + "babel-external-helpers": "bin/babel-external-helpers.js" + }, + "engines": { + "node": ">=6.9.0" + }, + "optionalDependencies": { + "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", + "chokidar": "^3.4.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "@babel/helper-member-expression-to-functions": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", - "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", + "node_modules/@babel/code-frame": { + "version": "7.22.13", "dev": true, - "requires": { - "@babel/types": "^7.8.3" + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-module-imports": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", - "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", + "node_modules/@babel/compat-data": { + "version": "7.22.20", "dev": true, - "requires": { - "@babel/types": "^7.8.3" + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-module-transforms": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz", - "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==", + "node_modules/@babel/core": { + "version": "7.23.0", "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.8.3", - "@babel/helper-replace-supers": "^7.8.6", - "@babel/helper-simple-access": "^7.8.3", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/template": "^7.8.6", - "@babel/types": "^7.9.0", - "lodash": "^4.17.13" + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helpers": "^7.23.0", + "@babel/parser": "^7.23.0", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.0", + "@babel/types": "^7.23.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "@babel/helper-optimise-call-expression": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", - "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", + "node_modules/@babel/generator": { + "version": "7.23.0", "dev": true, - "requires": { - "@babel/types": "^7.8.3" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.23.0", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-replace-supers": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.9.6.tgz", - "integrity": "sha512-qX+chbxkbArLyCImk3bWV+jB5gTNU/rsze+JlcF6Nf8tVTigPJSI1o1oBow/9Resa1yehUO9lIipsmu9oG4RzA==", + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.8.3", - "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/traverse": "^7.9.6", - "@babel/types": "^7.9.6" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-simple-access": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", - "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", "dev": true, - "requires": { - "@babel/template": "^7.8.3", - "@babel/types": "^7.8.3" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-split-export-declaration": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", - "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", "dev": true, - "requires": { - "@babel/types": "^7.8.3" + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "@babel/helper-validator-identifier": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", - "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", - "dev": true - }, - "@babel/helpers": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.6.tgz", - "integrity": "sha512-tI4bUbldloLcHWoRUMAj4g1bF313M/o6fBKhIsb3QnGVPwRm9JsNf/gqMkQ7zjqReABiffPV6RWj7hEglID5Iw==", + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.22.15", "dev": true, - "requires": { - "@babel/template": "^7.8.3", - "@babel/traverse": "^7.9.6", - "@babel/types": "^7.9.6" + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "@babel/highlight": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", - "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - }, + "license": "MIT", "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "@babel/parser": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", - "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", - "dev": true - }, - "@babel/template": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz", - "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/parser": "^7.8.6", - "@babel/types": "^7.8.6" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "@babel/traverse": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.6.tgz", - "integrity": "sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg==", + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", "dev": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.6", - "@babel/helper-function-name": "^7.9.5", - "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.9.6", - "@babel/types": "^7.9.6", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "@babel/types": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.6.tgz", - "integrity": "sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA==", + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.5", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - }, + "license": "MIT", "dependencies": { - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - } + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "@electron/get": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.12.2.tgz", - "integrity": "sha512-vAuHUbfvBQpYTJ5wB7uVIDq5c/Ry0fiTBMs7lnEYAo/qXXppIVcWdfBr57u6eRnKdVso7KSiH6p/LbQAG6Izrg==", + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", "dev": true, - "requires": { - "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "global-agent": "^2.0.2", - "global-tunnel-ng": "^2.7.1", - "got": "^9.6.0", - "progress": "^2.0.3", - "sanitize-filename": "^1.6.2", - "sumchecker": "^3.0.1" - }, + "license": "MIT", "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - } + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", "dev": true, - "requires": { - "defer-to-connect": "^1.0.1" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "@types/node": { - "version": "12.12.48", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.48.tgz", - "integrity": "sha512-m3Nmo/YaDUfYzdCQlxjF5pIy7TNyDTAJhIa//xtHcF0dlgYIBKULKnmloCPtByDxtZXrWV8Pge1AKT6/lRvVWg==", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", - "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", "dev": true, - "requires": { - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" } }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", - "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", - "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", - "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", - "dev": true - }, - "@webassemblyjs/helper-code-frame": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", - "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.0", "dev": true, - "requires": { - "@webassemblyjs/wast-printer": "1.9.0" + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "@webassemblyjs/helper-fsm": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", - "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", - "dev": true - }, - "@webassemblyjs/helper-module-context": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", - "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", - "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", - "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0" + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "@webassemblyjs/ieee754": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", - "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "@webassemblyjs/leb128": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", - "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", "dev": true, - "requires": { - "@xtuc/long": "4.2.2" + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "@webassemblyjs/utf8": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", - "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", - "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/helper-wasm-section": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-opt": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "@webassemblyjs/wast-printer": "1.9.0" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "@webassemblyjs/wasm-gen": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", - "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "@webassemblyjs/wasm-opt": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", - "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-buffer": "1.9.0", - "@webassemblyjs/wasm-gen": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "@webassemblyjs/wasm-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", - "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-wasm-bytecode": "1.9.0", - "@webassemblyjs/ieee754": "1.9.0", - "@webassemblyjs/leb128": "1.9.0", - "@webassemblyjs/utf8": "1.9.0" + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "@webassemblyjs/wast-parser": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", - "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/floating-point-hex-parser": "1.9.0", - "@webassemblyjs/helper-api-error": "1.9.0", - "@webassemblyjs/helper-code-frame": "1.9.0", - "@webassemblyjs/helper-fsm": "1.9.0", - "@xtuc/long": "4.2.2" + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "@webassemblyjs/wast-printer": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", - "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "node_modules/@babel/helper-validator-option": { + "version": "7.22.15", "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/wast-parser": "1.9.0", - "@xtuc/long": "4.2.2" + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "acorn": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", - "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", - "dev": true - }, - "acorn-jsx": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.0.tgz", - "integrity": "sha512-XkB50fn0MURDyww9+UYL3c1yLbOBz0ZFvrdYlGB8l+Ije1oSC75qAqrzSPjYQbdnQUzhlUGNKuesryAv0gxZOg==", - "dev": true - }, - "ajv": { - "version": "6.12.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", - "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" } }, - "ajv-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", - "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", - "dev": true - }, - "ajv-keywords": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", - "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", - "dev": true - }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==" - }, - "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } + "node_modules/@babel/helpers": { + "version": "7.23.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.0", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" + "node_modules/@babel/highlight": { + "version": "7.22.20", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "node_modules/@babel/node": { + "version": "7.22.19", "dev": true, - "requires": { - "array-uniq": "^1.0.1" + "license": "MIT", + "dependencies": { + "@babel/register": "^7.22.15", + "commander": "^4.0.1", + "core-js": "^3.30.2", + "node-environment-flags": "^1.0.5", + "regenerator-runtime": "^0.14.0", + "v8flags": "^3.1.1" + }, + "bin": { + "babel-node": "bin/babel-node.js" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" + "node_modules/@babel/parser": { + "version": "7.23.0", + "dev": true, + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" } }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.22.15", "dev": true, - "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.22.15", + "dev": true, + "license": "MIT", "dependencies": { - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" } }, - "assert": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", - "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", "dev": true, - "requires": { - "object-assign": "^4.1.1", - "util": "0.10.3" + "license": "MIT", + "engines": { + "node": ">=6.9.0" }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "dev": true, + "license": "MIT", "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "dev": true, - "requires": { - "inherits": "2.0.1" - } - } + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", - "requires": { - "lodash": "^4.17.10" + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } - }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - }, + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", "dev": true, - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - }, + "license": "MIT", "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-helper-evaluate-path": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.4.3.tgz", - "integrity": "sha1-ComvcCwGshcCf6NxkI3UmJ0+Yz8=", - "dev": true - }, - "babel-helper-flip-expressions": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz", - "integrity": "sha1-NpZzahKKwYvCUlS19AoizrPB0/0=", - "dev": true - }, - "babel-helper-is-nodes-equiv": { - "version": "0.0.1", - "resolved": "http://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", - "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", - "dev": true - }, - "babel-helper-is-void-0": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz", - "integrity": "sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=", - "dev": true - }, - "babel-helper-mark-eval-scopes": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz", - "integrity": "sha1-0kSjvvmESHJgP/tG4izorN9VFWI=", - "dev": true - }, - "babel-helper-remove-or-void": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz", - "integrity": "sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=", - "dev": true - }, - "babel-helper-to-multiple-sequence-expressions": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.4.3.tgz", - "integrity": "sha1-W1GLESf0ezA4dzOGoVYaK0jmMrY=", - "dev": true - }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-loader": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.2.tgz", - "integrity": "sha512-Law0PGtRV1JL8Y9Wpzc0d6EE0GD7LzXWCfaeWwboUMcBWNG6gvaWTK1/+BK7a4X5EmeJiGEuDDFxUsOa8RSWCw==", + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.22.5", "dev": true, - "requires": { - "find-cache-dir": "^1.0.0", - "loader-utils": "^1.0.2", - "mkdirp": "^0.5.1", - "util.promisify": "^1.0.0" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.22.5", "dev": true, - "requires": { - "babel-runtime": "^6.22.0" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-minify": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-minify/-/babel-minify-0.4.3.tgz", - "integrity": "sha1-2Ufk7WtibcjCVofyQsJcvPbygaY=", + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", "dev": true, - "requires": { - "@babel/core": "^7.0.0-beta.46", - "babel-preset-minify": "^0.4.3", - "fs-readdir-recursive": "^1.1.0", - "mkdirp": "^0.5.1", - "util.promisify": "^1.0.0", - "yargs-parser": "^10.0.0" - }, - "dependencies": { - "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - } + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-plugin-minify-builtins": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.4.3.tgz", - "integrity": "sha1-nqPVn0rEp7uVjXEtKVVqH4b3+B4=", + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.4.3" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-plugin-minify-constant-folding": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.4.3.tgz", - "integrity": "sha1-MA+d6N2ghEoXaxk2U5YOJK0z4ZE=", + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.22.5", "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.4.3" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-plugin-minify-dead-code-elimination": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.4.3.tgz", - "integrity": "sha1-c2KCZYZPkAjQAnUG9Yq+s8HQLZg=", + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.4.3", - "babel-helper-mark-eval-scopes": "^0.4.3", - "babel-helper-remove-or-void": "^0.4.3", - "lodash.some": "^4.6.0" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-plugin-minify-flip-comparisons": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz", - "integrity": "sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=", + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", "dev": true, - "requires": { - "babel-helper-is-void-0": "^0.4.3" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-plugin-minify-guarded-expressions": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz", - "integrity": "sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==", + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.5.0", - "babel-helper-flip-expressions": "^0.4.3" - }, + "license": "MIT", "dependencies": { - "babel-helper-evaluate-path": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz", - "integrity": "sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-plugin-minify-infinity": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz", - "integrity": "sha1-37h2obCKBldjhO8/kuZTumB7Oco=", - "dev": true - }, - "babel-plugin-minify-mangle-names": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.4.3.tgz", - "integrity": "sha1-FvG/90t6fJPfwkHngx3V+0sCPvc=", + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", "dev": true, - "requires": { - "babel-helper-mark-eval-scopes": "^0.4.3" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-plugin-minify-numeric-literals": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz", - "integrity": "sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=", - "dev": true - }, - "babel-plugin-minify-replace": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.4.3.tgz", - "integrity": "sha1-nSifS6FdTmAR6HmfpfG6d+yBIZ0=", - "dev": true - }, - "babel-plugin-minify-simplify": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.4.3.tgz", - "integrity": "sha1-N3VthcYURktLCSfytOQXGR1Vc4o=", + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", "dev": true, - "requires": { - "babel-helper-flip-expressions": "^0.4.3", - "babel-helper-is-nodes-equiv": "^0.0.1", - "babel-helper-to-multiple-sequence-expressions": "^0.4.3" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-plugin-minify-type-constructors": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz", - "integrity": "sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=", + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", "dev": true, - "requires": { - "babel-helper-is-void-0": "^0.4.3" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-plugin-transform-inline-consecutive-adds": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz", - "integrity": "sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=", - "dev": true - }, - "babel-plugin-transform-member-expression-literals": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz", - "integrity": "sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=", - "dev": true - }, - "babel-plugin-transform-merge-sibling-variables": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz", - "integrity": "sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=", - "dev": true - }, - "babel-plugin-transform-minify-booleans": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz", - "integrity": "sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=", - "dev": true - }, - "babel-plugin-transform-property-literals": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz", - "integrity": "sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=", + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", "dev": true, - "requires": { - "esutils": "^2.0.2" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-plugin-transform-regexp-constructors": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz", - "integrity": "sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=", - "dev": true - }, - "babel-plugin-transform-remove-console": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz", - "integrity": "sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=", - "dev": true - }, - "babel-plugin-transform-remove-debugger": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz", - "integrity": "sha1-QrcnYxyXl44estGZp67IShgznvI=", - "dev": true - }, - "babel-plugin-transform-remove-undefined": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.4.3.tgz", - "integrity": "sha1-1AsNp/kcCMBsxyt2dHTAHEiU3gI=", + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", "dev": true, - "requires": { - "babel-helper-evaluate-path": "^0.4.3" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-plugin-transform-simplify-comparison-operators": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz", - "integrity": "sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=", - "dev": true - }, - "babel-plugin-transform-undefined-to-void": { - "version": "6.9.4", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz", - "integrity": "sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=", - "dev": true - }, - "babel-preset-minify": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.4.3.tgz", - "integrity": "sha1-spw91pGJBThFmPCSuVUVLiah/g8=", - "dev": true, - "requires": { - "babel-plugin-minify-builtins": "^0.4.3", - "babel-plugin-minify-constant-folding": "^0.4.3", - "babel-plugin-minify-dead-code-elimination": "^0.4.3", - "babel-plugin-minify-flip-comparisons": "^0.4.3", - "babel-plugin-minify-guarded-expressions": "^0.4.3", - "babel-plugin-minify-infinity": "^0.4.3", - "babel-plugin-minify-mangle-names": "^0.4.3", - "babel-plugin-minify-numeric-literals": "^0.4.3", - "babel-plugin-minify-replace": "^0.4.3", - "babel-plugin-minify-simplify": "^0.4.3", - "babel-plugin-minify-type-constructors": "^0.4.3", - "babel-plugin-transform-inline-consecutive-adds": "^0.4.3", - "babel-plugin-transform-member-expression-literals": "^6.9.4", - "babel-plugin-transform-merge-sibling-variables": "^6.9.4", - "babel-plugin-transform-minify-booleans": "^6.9.4", - "babel-plugin-transform-property-literals": "^6.9.4", - "babel-plugin-transform-regexp-constructors": "^0.4.3", - "babel-plugin-transform-remove-console": "^6.9.4", - "babel-plugin-transform-remove-debugger": "^6.9.4", - "babel-plugin-transform-remove-undefined": "^0.4.3", - "babel-plugin-transform-simplify-comparison-operators": "^6.9.4", - "babel-plugin-transform-undefined-to-void": "^6.9.4", - "lodash.isplainobject": "^4.0.6" - } - }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", - "dev": true, - "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "^0.5.6" - } - } + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.22.5", "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.22.15", "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - }, + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.22.5", "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", - "dev": true - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.22.5", "dev": true, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "bluebird": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz", - "integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg==" - }, - "bn.js": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.1.tgz", - "integrity": "sha512-IUTD/REb78Z2eodka1QZyyEk66pciRcP6Sroka0aI3tG/iwIdYLrBD62RsubR7vqdt3WyX8p4jxeatzmRSphtA==", - "dev": true - }, - "boolean": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.1.tgz", - "integrity": "sha512-HRZPIjPcbwAVQvOTxR4YE3o8Xs98NqbbL1iEZDCz7CL8ql0Lt5iOyJFxfnAB0oFs8Oh02F/lLlg30Mexv46LjA==", + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.22.11", "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.11", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" } }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "node_modules/@babel/plugin-transform-classes": { + "version": "7.22.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.9", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" - }, - "browserify-aes": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.22.5", "dev": true, - "requires": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "browserify-cipher": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.0", "dev": true, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "browserify-des": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", - "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.22.5", "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.22.5", "dev": true, - "requires": { - "bn.js": "^4.1.0", - "randombytes": "^2.0.1" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.22.11", + "dev": true, + "license": "MIT", "dependencies": { - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - } + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "browserify-sign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.1.0.tgz", - "integrity": "sha512-VYxo7cDCeYUoBZ0ZCy4UyEUCP3smyBd4DRQM5nrFS1jJjPJjX7rP3oLRpPoWfkhQfyJ0I9ZbHbKafrFD/SGlrg==", + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.22.5", "dev": true, - "requires": { - "bn.js": "^5.1.1", - "browserify-rsa": "^4.0.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "elliptic": "^6.5.2", - "inherits": "^2.0.4", - "parse-asn1": "^5.1.5", - "readable-stream": "^3.6.0" + "license": "MIT", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.22.11", + "dev": true, + "license": "MIT", "dependencies": { - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", - "dev": true - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - } + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.22.15", "dev": true, - "requires": { - "pako": "~1.0.5" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "buffer": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", - "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.22.5", "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.22.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true + "node_modules/@babel/plugin-transform-literals": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.22.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.22.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.22.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.22.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.22.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.22.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.22.11", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.11", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.22.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.22.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "babel-plugin-polyfill-corejs2": "^0.4.5", + "babel-plugin-polyfill-corejs3": "^0.8.3", + "babel-plugin-polyfill-regenerator": "^0.5.2", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.22.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.22.10", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.22.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.22.20", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.20", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.15", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.15", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.22.5", + "@babel/plugin-syntax-import-attributes": "^7.22.5", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.22.5", + "@babel/plugin-transform-async-generator-functions": "^7.22.15", + "@babel/plugin-transform-async-to-generator": "^7.22.5", + "@babel/plugin-transform-block-scoped-functions": "^7.22.5", + "@babel/plugin-transform-block-scoping": "^7.22.15", + "@babel/plugin-transform-class-properties": "^7.22.5", + "@babel/plugin-transform-class-static-block": "^7.22.11", + "@babel/plugin-transform-classes": "^7.22.15", + "@babel/plugin-transform-computed-properties": "^7.22.5", + "@babel/plugin-transform-destructuring": "^7.22.15", + "@babel/plugin-transform-dotall-regex": "^7.22.5", + "@babel/plugin-transform-duplicate-keys": "^7.22.5", + "@babel/plugin-transform-dynamic-import": "^7.22.11", + "@babel/plugin-transform-exponentiation-operator": "^7.22.5", + "@babel/plugin-transform-export-namespace-from": "^7.22.11", + "@babel/plugin-transform-for-of": "^7.22.15", + "@babel/plugin-transform-function-name": "^7.22.5", + "@babel/plugin-transform-json-strings": "^7.22.11", + "@babel/plugin-transform-literals": "^7.22.5", + "@babel/plugin-transform-logical-assignment-operators": "^7.22.11", + "@babel/plugin-transform-member-expression-literals": "^7.22.5", + "@babel/plugin-transform-modules-amd": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.22.15", + "@babel/plugin-transform-modules-systemjs": "^7.22.11", + "@babel/plugin-transform-modules-umd": "^7.22.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.22.5", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11", + "@babel/plugin-transform-numeric-separator": "^7.22.11", + "@babel/plugin-transform-object-rest-spread": "^7.22.15", + "@babel/plugin-transform-object-super": "^7.22.5", + "@babel/plugin-transform-optional-catch-binding": "^7.22.11", + "@babel/plugin-transform-optional-chaining": "^7.22.15", + "@babel/plugin-transform-parameters": "^7.22.15", + "@babel/plugin-transform-private-methods": "^7.22.5", + "@babel/plugin-transform-private-property-in-object": "^7.22.11", + "@babel/plugin-transform-property-literals": "^7.22.5", + "@babel/plugin-transform-regenerator": "^7.22.10", + "@babel/plugin-transform-reserved-words": "^7.22.5", + "@babel/plugin-transform-shorthand-properties": "^7.22.5", + "@babel/plugin-transform-spread": "^7.22.5", + "@babel/plugin-transform-sticky-regex": "^7.22.5", + "@babel/plugin-transform-template-literals": "^7.22.5", + "@babel/plugin-transform-typeof-symbol": "^7.22.5", + "@babel/plugin-transform-unicode-escapes": "^7.22.10", + "@babel/plugin-transform-unicode-property-regex": "^7.22.5", + "@babel/plugin-transform-unicode-regex": "^7.22.5", + "@babel/plugin-transform-unicode-sets-regex": "^7.22.5", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "@babel/types": "^7.22.19", + "babel-plugin-polyfill-corejs2": "^0.4.5", + "babel-plugin-polyfill-corejs3": "^0.8.3", + "babel-plugin-polyfill-regenerator": "^0.5.2", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-syntax-jsx": "^7.22.5", + "@babel/plugin-transform-modules-commonjs": "^7.23.0", + "@babel/plugin-transform-typescript": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register": { + "version": "7.22.15", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.5", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/runtime": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.9.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.22.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.50.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.11", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.19", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", + "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", + "dev": true, + "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", + "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@nicolo-ribaudo/chokidar-2": { + "version": "2.1.8-no-fsevents.3", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/eslint": { + "version": "8.44.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jquery": { + "version": "3.5.20", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sizzle": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.13", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mocha": { + "version": "9.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.8.0", + "license": "MIT" + }, + "node_modules/@types/semver": { + "version": "7.5.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sizzle": { + "version": "2.3.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.53.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "5.53.0", + "@typescript-eslint/type-utils": "5.53.0", + "@typescript-eslint/utils": "5.53.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.5.4", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.53.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/visitor-keys": "5.53.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/scope-manager/node_modules/@typescript-eslint/types": { + "version": "5.53.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.53.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.53.0", + "@typescript-eslint/utils": "5.53.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "5.53.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.53.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/visitor-keys": "5.53.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/semver": { + "version": "7.5.4", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.4", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.53.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.53.0", + "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/typescript-estree": "5.53.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "5.53.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.53.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.53.0", + "@typescript-eslint/visitor-keys": "5.53.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.5.4", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.53.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.53.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/@typescript-eslint/types": { + "version": "5.53.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "dev": true, + "license": "ISC" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/acorn": { + "version": "8.10.0", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", - "dev": true + "node_modules/ajv": { + "version": "6.12.6", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", - "dev": true + "node_modules/ajv-formats": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } }, - "cacache": { - "version": "12.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", - "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", - "dev": true, - "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - }, - "dependencies": { - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.reduce": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/assert": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "dev": true, + "license": "ISC" + }, + "node_modules/async": { + "version": "2.6.4", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.8.2", + "dev": true, + "license": "MPL-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/axios": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axobject-query": { + "version": "3.2.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/babel-loader": { + "version": "9.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-loader/node_modules/find-cache-dir": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/find-up": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/locate-path": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/p-limit": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/p-locate": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/path-exists": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/babel-loader/node_modules/pkg-dir": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-loader/node_modules/yocto-queue": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.2", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.2", + "core-js-compat": "^3.32.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } + { + "type": "consulting", + "url": "https://feross.org/support" } + ], + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/bn.js": { + "version": "5.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "dev": true, + "license": "ISC" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "cache-base": { + "node_modules/browserify-cipher": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - } + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" } }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "node_modules/browserify-des": { + "version": "1.0.2", "dev": true, - "requires": { - "callsites": "^0.2.0" + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true - }, - "camelcase": { + "node_modules/browserify-rsa": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } }, - "catharsis": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz", - "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==", + "node_modules/browserify-sign": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", + "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", "dev": true, - "requires": { - "lodash": "^4.17.14" + "dependencies": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.4", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.6", + "readable-stream": "^3.6.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 4" } }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "node_modules/browserify-zlib": { + "version": "0.2.0", "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "license": "MIT", + "dependencies": { + "pako": "~1.0.5" } }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true + "node_modules/browserslist": { + "version": "4.22.1", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "node_modules/buffer": { + "version": "6.0.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true + "node_modules/buffer-from": { + "version": "1.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "dev": true, + "license": "MIT" }, - "chrome-trace-event": { + "node_modules/call-bind": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", - "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", "dev": true, - "requires": { - "tslib": "^1.9.0" + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "node_modules/callsites": { + "version": "3.1.0", "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true + "node_modules/camelcase": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } + "node_modules/caniuse-lite": { + "version": "1.0.30001541", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } - } + ], + "license": "CC-BY-4.0" }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "node_modules/chalk": { + "version": "2.4.2", "dev": true, - "requires": { - "restore-cursor": "^2.0.0" + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } + "node_modules/chokidar": { + "version": "3.5.3", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", "dev": true, - "requires": { - "mimic-response": "^1.0.0" + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + "node_modules/cliui": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "node_modules/clone-deep": { + "version": "4.0.1", "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "color-convert": { + "node_modules/color-convert": { "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { + "dev": true, + "license": "MIT", + "dependencies": { "color-name": "1.1.3" } }, - "color-name": { + "node_modules/color-name": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "dev": true, + "license": "MIT" }, - "combined-stream": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", - "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", - "requires": { + "node_modules/colorette": { + "version": "2.0.20", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "node_modules/commander": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true + "node_modules/common-path-prefix": { + "version": "3.0.0", + "dev": true, + "license": "ISC" }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true + "node_modules/commondir": { + "version": "1.0.1", + "dev": true, + "license": "MIT" }, - "concat-map": { + "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "dev": true, + "license": "MIT" }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "node_modules/convert-source-map": { + "version": "2.0.0", "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } + "license": "MIT" }, - "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "node_modules/core-js": { + "version": "3.32.2", "dev": true, - "optional": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "console-browserify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", - "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", - "dev": true - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", - "dev": true - }, - "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "node_modules/core-js-compat": { + "version": "3.32.2", "dev": true, - "requires": { - "safe-buffer": "~5.1.1" + "license": "MIT", + "dependencies": { + "browserslist": "^4.21.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "dev": true, - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "create-ecdh": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "node_modules/create-ecdh": { + "version": "4.0.4", "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - }, + "license": "MIT", "dependencies": { - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - } + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" } }, - "create-hash": { + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/create-hash": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", "md5.js": "^1.3.4", @@ -2268,12 +3715,11 @@ "sha.js": "^2.4.0" } }, - "create-hmac": { + "node_modules/create-hmac": { "version": "1.1.7", - "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", "inherits": "^2.0.1", @@ -2282,25 +3728,29 @@ "sha.js": "^2.4.8" } }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "node_modules/create-require": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" } }, - "crypto-browserify": { + "node_modules/crypto-browserify": { "version": "3.12.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "browserify-cipher": "^1.0.0", "browserify-sign": "^4.0.0", "create-ecdh": "^4.0.0", @@ -2312,5676 +3762,4585 @@ "public-encrypt": "^4.0.0", "randombytes": "^2.0.0", "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/debug": { + "version": "4.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "crypto-js": { + "node_modules/decamelize": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.0.0.tgz", - "integrity": "sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==" + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "cyclist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", - "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", - "dev": true + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" + "node_modules/define-properties": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true + "node_modules/electron-to-chromium": { + "version": "1.4.537", + "dev": true, + "license": "ISC" }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "node_modules/elliptic": { + "version": "6.5.7", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz", + "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==", "dev": true, - "requires": { - "mimic-response": "^1.0.0" + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" } }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true + "node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "license": "MIT" }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/envinfo": { + "version": "7.10.0", "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } + "engines": { + "node": ">=4" } }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "node_modules/es-abstract": { + "version": "1.22.2", "dev": true, - "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.1", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "delayed-stream": { + "node_modules/es-array-method-boxes-properly": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "dev": true, + "license": "MIT" }, - "des.js": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", - "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "node_modules/es-module-lexer": { + "version": "1.3.1", "dev": true, - "requires": { - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "license": "MIT" + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "detect-file": { + "node_modules/es-shim-unscopables": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true + "dev": true, + "license": "MIT", + "dependencies": { + "has": "^1.0.3" + } }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "node_modules/es-to-primitive": { + "version": "1.2.1", "dev": true, - "requires": { - "repeating": "^2.0.0" + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "detect-node": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", - "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "node_modules/escalade": { + "version": "3.1.1", "dev": true, - "optional": true + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, - "diffie-hellman": { - "version": "5.0.3", - "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "node_modules/eslint": { + "version": "8.50.0", "dev": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - }, + "license": "MIT", "dependencies": { - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - } + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.50.0", + "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/eslint-config-prettier": { + "version": "8.10.0", "dev": true, - "requires": { - "esutils": "^2.0.2" + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "domain-browser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", - "dev": true - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", - "dev": true - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" } }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" } }, - "electron": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/electron/-/electron-7.2.4.tgz", - "integrity": "sha512-Z+R692uTzXgP8AHrabE+kkrMlQJ6pnAYoINenwj9QSqaD2YbO8IuXU9DMCcUY0+VpA91ee09wFZJNUKYPMnCKg==", + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", "dev": true, - "requires": { - "@electron/get": "^1.0.1", - "@types/node": "^12.0.12", - "extract-zip": "^1.0.3" + "license": "ISC", + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" } }, - "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "node_modules/eslint-module-utils": { + "version": "2.8.0", "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - }, + "license": "MIT", "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true } } }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "node_modules/eslint-plugin-import": { + "version": "2.28.1", "dev": true, - "optional": true + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.findlastindex": "^1.2.2", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.8.0", + "has": "^1.0.3", + "is-core-module": "^2.13.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.6", + "object.groupby": "^1.0.0", + "object.values": "^1.1.6", + "semver": "^6.3.1", + "tsconfig-paths": "^3.14.2" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", "dev": true, - "requires": { - "once": "^1.4.0" + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" } }, - "enhanced-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", - "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "tapable": "^1.0.0" + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", - "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", - "dev": true + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.7.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.7", + "aria-query": "^5.1.3", + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.6.2", + "axobject-query": "^3.1.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.3", + "language-tags": "=1.0.5", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } }, - "env-paths": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", - "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==", - "dev": true + "node_modules/eslint-scope": { + "version": "5.1.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "node_modules/eslint-utils": { + "version": "3.0.0", "dev": true, - "requires": { - "prr": "~1.0.1" + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" } }, - "es-abstract": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", - "requires": { - "es-to-primitive": "^1.1.1", - "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" } }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", "dev": true, - "optional": true + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "eslint": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.6.0.tgz", - "integrity": "sha512-/eVYs9VVVboX286mBK7bbKnO1yamUy2UCRjiY6MryhQL2PaaXCExsCQ2aO83OeYRhU2eCU/FMFP+tVMoOrzNrA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.5.3", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^3.1.0", - "doctrine": "^2.1.0", - "eslint-scope": "^4.0.0", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^4.0.0", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^2.0.0", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "imurmurhash": "^0.1.4", - "inquirer": "^6.1.0", - "is-resolvable": "^1.1.0", - "js-yaml": "^3.12.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.5", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "pluralize": "^7.0.0", - "progress": "^2.0.0", - "regexpp": "^2.0.0", - "require-uncached": "^1.0.3", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^4.0.3", - "text-table": "^0.2.0" + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", "dependencies": { - "ajv": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz", - "integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globals": { - "version": "11.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz", - "integrity": "sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "eslint-scope": { + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "eslint-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", - "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", "dev": true, - "requires": { - "eslint-visitor-keys": "^1.0.0" + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", - "dev": true - }, - "espree": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz", - "integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==", + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", "dev": true, - "requires": { - "acorn": "^6.0.2", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "node_modules/eslint/node_modules/globals": { + "version": "13.22.0", "dev": true, - "requires": { - "estraverse": "^4.0.0" + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", "dev": true, - "requires": { - "estraverse": "^4.1.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", - "dev": true + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true + "node_modules/espree": { + "version": "9.6.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, - "events": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", - "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==", - "dev": true + "node_modules/esquery": { + "version": "1.5.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } }, - "evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", "dev": true, - "requires": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" } }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" } }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "node_modules/estraverse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" } }, - "external-editor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", - "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "dependencies": { - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - } + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" } }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } + "node_modules/events": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" } }, - "extract-zip": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", - "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "node_modules/evp_bytestokey": { + "version": "1.0.3", "dev": true, - "requires": { - "concat-stream": "^1.6.2", - "debug": "^2.6.9", - "mkdirp": "^0.5.4", - "yauzl": "^2.10.0" - }, + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "license": "MIT" }, - "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + "node_modules/fast-glob": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "license": "MIT" }, - "fast-levenshtein": { + "node_modules/fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true + "dev": true, + "license": "MIT" }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "node_modules/fastest-levenshtein": { + "version": "1.0.16", "dev": true, - "requires": { - "pend": "~1.2.0" + "license": "MIT", + "engines": { + "node": ">= 4.9.1" } }, - "figgy-pudding": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", - "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", - "dev": true - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "node_modules/fastq": { + "version": "1.15.0", "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" } }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "node_modules/file-entry-cache": { + "version": "6.0.1", "dev": true, - "requires": { - "flat-cache": "^1.2.1", - "object-assign": "^4.0.1" + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" } }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, - "optional": true - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "node_modules/find-cache-dir": { + "version": "2.1.0", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "node_modules/find-up": { + "version": "5.0.0", "dev": true, - "requires": { - "locate-path": "^2.0.0" + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "node_modules/flat": { + "version": "5.0.2", "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" } }, - "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "requires": { - "is-buffer": "~2.0.3" - }, + "node_modules/flat-cache": { + "version": "3.1.0", + "dev": true, + "license": "MIT", "dependencies": { - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==" - } + "flatted": "^3.2.7", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" } }, - "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "node_modules/flatted": { + "version": "3.2.9", "dev": true, - "requires": { - "circular-json": "^0.3.1", - "del": "^2.0.2", - "graceful-fs": "^4.1.2", - "write": "^0.2.1" + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "node_modules/for-each": { + "version": "0.3.3", "dev": true, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" } }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" } }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", "dev": true, - "requires": { - "map-cache": "^0.2.2" - } + "license": "MIT" }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "node_modules/fs.realpath": { + "version": "1.0.0", "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } + "license": "ISC" }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "node_modules/fsevents": { + "version": "2.3.3", "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", - "dev": true - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "fs-monkey": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.0.tgz", - "integrity": "sha512-nxkkzQ5Ga+ETriXxIof4TncyMSzrV9jFIF+kGN16nw5CiAdWAnG/2FgM7CHhRenW1EBiDx+r1tf/P78HGKCgnA==", - "dev": true - }, - "fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true + "node_modules/function-bind": { + "version": "1.1.1", + "dev": true, + "license": "MIT" }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "node_modules/function.prototype.name": { + "version": "1.1.6", "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "node_modules/functions-have-names": { + "version": "1.2.3", "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.1", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", - "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", - "dev": true + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } }, - "get-caller-file": { + "node_modules/get-caller-file": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "node_modules/get-intrinsic": { + "version": "1.2.1", "dev": true, - "requires": { - "pump": "^3.0.0" + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true + "node_modules/get-symbol-description": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" + "node_modules/get-tsconfig": { + "version": "4.7.2", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "requires": { + "node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } + "node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "global-agent": { - "version": "2.1.12", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.12.tgz", - "integrity": "sha512-caAljRMS/qcDo69X9BfkgrihGUgGx44Fb4QQToNQjsiWh+YlQ66uqYVAdA8Olqit+5Ng0nkz09je3ZzANMZcjg==", + "node_modules/glob-to-regexp": { + "version": "0.4.1", "dev": true, - "optional": true, - "requires": { - "boolean": "^3.0.1", - "core-js": "^3.6.5", - "es6-error": "^4.1.1", - "matcher": "^3.0.0", - "roarr": "^2.15.3", - "semver": "^7.3.2", - "serialize-error": "^7.0.1" - }, - "dependencies": { - "core-js": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", - "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", - "dev": true, - "optional": true - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true, - "optional": true - } - } + "license": "BSD-2-Clause" }, - "global-modules": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", - "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", - "dev": true, - "requires": { - "global-prefix": "^3.0.0" - }, - "dependencies": { - "global-prefix": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", - "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", - "dev": true, - "requires": { - "ini": "^1.3.5", - "kind-of": "^6.0.2", - "which": "^1.3.1" - } - } + "node_modules/globals": { + "version": "11.12.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" } }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "node_modules/globalthis": { + "version": "1.0.3", "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "global-tunnel-ng": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz", - "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==", + "node_modules/globby": { + "version": "11.1.0", "dev": true, - "optional": true, - "requires": { - "encodeurl": "^1.0.2", - "lodash": "^4.17.10", - "npm-conf": "^1.1.3", - "tunnel": "^0.0.6" + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - }, - "globalthis": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.1.tgz", - "integrity": "sha512-mJPRTc/P39NH/iNG4mXa9aIhNymaQikTrnspeCa2ZuJ+mH2QN/rXwtX3XwKrHqWgUQFbNZKtHM105aHzJalElw==", + "node_modules/globby/node_modules/slash": { + "version": "3.0.0", "dev": true, - "optional": true, - "requires": { - "define-properties": "^1.1.3" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "node_modules/gopd": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true + "node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==" + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "dev": true, + "license": "MIT" }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" }, - "har-validator": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", - "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", - "requires": { - "ajv": "^5.3.0", - "har-schema": "^2.0.0" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" - } + "node_modules/growl": { + "version": "1.10.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.x" } }, - "has": { + "node_modules/has": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { + "dev": true, + "license": "MIT", + "dependencies": { "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "node_modules/has-bigints": { + "version": "1.0.2", "dev": true, - "requires": { - "ansi-regex": "^2.0.0" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "has-flag": { + "node_modules/has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "has-symbols": { + "node_modules/has-property-descriptors": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "node_modules/has-proto": { + "version": "1.0.1", "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "has-values": { + "node_modules/has-tostringtag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "hash-base": { + "node_modules/hash-base": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "inherits": "^2.0.4", "readable-stream": "^3.6.0", "safe-buffer": "^5.2.0" }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "dev": true, + "license": "MIT", "dependencies": { - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "engines": { + "node": ">=10.18" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", - "dev": true + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } + { + "type": "consulting", + "url": "https://feross.org/support" } - } + ], + "license": "BSD-3-Clause" }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "node_modules/ignore": { + "version": "5.2.4", "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" + "license": "MIT", + "engines": { + "node": ">= 4" } }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "node_modules/import-fresh": { + "version": "3.3.0", "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "node_modules/import-local": { + "version": "3.1.0", "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "node_modules/import-local/node_modules/find-up": { + "version": "4.1.0", "dev": true, - "requires": { - "parse-passwd": "^1.0.0" + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "html5-fs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/html5-fs/-/html5-fs-0.1.1.tgz", - "integrity": "sha1-jxRcucLoOLt9D6kx4wraBUtHzX0=" - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "node_modules/import-local/node_modules/locate-path": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" } }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/import-local/node_modules/p-limit": { + "version": "2.3.0", "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", - "dev": true - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true + "node_modules/import-local/node_modules/p-locate": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dev": true, - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - } + "node_modules/import-local/node_modules/pkg-dir": { + "version": "4.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "imurmurhash": { + "node_modules/imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } }, - "inflight": { + "node_modules/inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { + "dev": true, + "license": "ISC", + "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" }, - "inquirer": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz", - "integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==", - "dev": true, - "requires": { - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.0", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.0", - "figures": "^2.0.0", - "lodash": "^4.17.10", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.1.0", - "string-width": "^2.1.0", - "strip-ansi": "^4.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } + "node_modules/internal-slot": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" } }, - "interpret": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", - "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", - "dev": true - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "node_modules/interpret": { + "version": "3.1.1", "dev": true, - "requires": { - "loose-envify": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=10.13.0" } }, - "invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "node_modules/is-arguments": { + "version": "1.1.1", "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, + "license": "MIT", "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "node_modules/is-array-buffer": { + "version": "3.0.2", "dev": true, - "requires": { - "binary-extensions": "^1.0.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "node_modules/is-bigint": { + "version": "1.0.4", "dev": true, - "requires": { - "kind-of": "^3.0.2" + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" } }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + "node_modules/is-boolean-object": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "node_modules/is-callable": { + "version": "1.2.7", "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "dev": true, + "license": "MIT", "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true + "node_modules/is-date-object": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "is-extglob": { + "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", "dev": true, - "requires": { - "number-is-nan": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "requires": { - "is-extglob": "^2.1.1" + "node_modules/is-generator-function": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "node_modules/is-glob": { + "version": "4.0.3", "dev": true, - "requires": { - "kind-of": "^3.0.2" + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "dev": true, + "license": "MIT", "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", - "dev": true + "node_modules/is-negative-zero": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "requires": { - "is-path-inside": "^1.0.0" + "engines": { + "node": ">=0.12.0" } }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "node_modules/is-number-object": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", "dev": true, - "requires": { - "path-is-inside": "^1.0.1" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "is-plain-object": { + "node_modules/is-plain-object": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "requires": { - "has": "^1.0.1" + "node_modules/is-regex": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", - "dev": true + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true + "node_modules/is-string": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "requires": { - "has-symbols": "^1.0.0" + "node_modules/is-symbol": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "node_modules/is-typed-array": { + "version": "1.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true + "node_modules/is-weakref": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "node_modules/isarray": { + "version": "2.0.5", + "dev": true, + "license": "MIT" }, - "isexe": { + "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "dev": true, + "license": "ISC" }, - "isobject": { + "node_modules/isobject": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "js2xmlparser": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.1.tgz", - "integrity": "sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw==", - "dev": true, - "requires": { - "xmlcreate": "^2.0.3" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "jsdoc": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.4.tgz", - "integrity": "sha512-3G9d37VHv7MFdheviDCjUfQoIjdv4TC5zTTf5G9VODLtOnVS6La1eoYBDlbWfsRT3/Xo+j2MIqki2EV12BZfwA==", - "dev": true, - "requires": { - "@babel/parser": "^7.9.4", - "bluebird": "^3.7.2", - "catharsis": "^0.8.11", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.1", - "klaw": "^3.0.0", - "markdown-it": "^10.0.0", - "markdown-it-anchor": "^5.2.7", - "marked": "^0.8.2", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "taffydb": "2.6.2", - "underscore": "~1.10.2" - }, - "dependencies": { - "@babel/parser": { - "version": "7.9.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", - "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", - "dev": true - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz", - "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==", - "dev": true - } + "node_modules/jsesc": { + "version": "2.5.2", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" } }, - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", - "dev": true - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT" }, - "json-schema-traverse": { + "node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "license": "MIT" }, - "json-stable-stringify-without-jsonify": { + "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true + "dev": true, + "license": "MIT" }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "node_modules/json5": { + "version": "2.2.3", "dev": true, - "requires": { - "graceful-fs": "^4.1.6" + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" + "node_modules/jsonc-parser": { + "version": "3.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" } }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "node_modules/keyv": { + "version": "4.5.3", "dev": true, - "requires": { - "json-buffer": "3.0.0" + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" } }, - "kind-of": { + "node_modules/kind-of": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", "dev": true, - "requires": { - "graceful-fs": "^4.1.9" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "node_modules/language-subtag-registry": { + "version": "0.3.22", "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } + "license": "CC0-1.0" }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "node_modules/language-tags": { + "version": "1.0.5", "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "license": "MIT", + "dependencies": { + "language-subtag-registry": "~0.3.2" } }, - "linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "node_modules/levn": { + "version": "0.4.1", "dev": true, - "requires": { - "uc.micro": "^1.0.1" + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "loader-runner": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", - "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", - "dev": true - }, - "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "node_modules/loader-runner": { + "version": "4.3.0", "dev": true, - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0" + "license": "MIT", + "engines": { + "node": ">=6.11.5" } }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "node_modules/locate-path": { + "version": "6.0.0", "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + "node_modules/lodash": { + "version": "4.17.21", + "license": "MIT" }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", - "dev": true + "node_modules/lodash.debounce": { + "version": "4.0.8", + "dev": true, + "license": "MIT" }, - "lodash.some": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", - "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", - "dev": true + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" }, - "log-symbols": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", - "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", - "requires": { - "chalk": "^2.4.2" + "node_modules/log-symbols": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", "dev": true, - "requires": { - "yallist": "^3.0.2" + "license": "MIT" + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", "dev": true, - "requires": { - "pify": "^3.0.0" - }, + "license": "MIT", "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "node_modules/lru-cache": { + "version": "5.1.1", "dev": true, - "requires": { - "p-defer": "^1.0.0" + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true + "node_modules/lunr": { + "version": "2.3.9", + "dev": true, + "license": "MIT" }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "node_modules/make-dir": { + "version": "2.1.0", "dev": true, - "requires": { - "object-visit": "^1.0.0" + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" } }, - "markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", "dev": true, - "requires": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "license": "ISC", + "bin": { + "semver": "bin/semver" } }, - "markdown-it-anchor": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.2.7.tgz", - "integrity": "sha512-REFmIaSS6szaD1bye80DMbp7ePwsPNvLTR5HunsUcZ0SG0rWJQ+Pz24R4UlTKtjKBPhxo0v0tOBDYjZQQknW8Q==", - "dev": true - }, - "marked": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz", - "integrity": "sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw==", - "dev": true + "node_modules/make-error": { + "version": "1.3.6", + "dev": true, + "license": "ISC" }, - "matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "node_modules/marked": { + "version": "4.3.0", "dev": true, - "optional": true, - "requires": { - "escape-string-regexp": "^4.0.0" + "license": "MIT", + "bin": { + "marked": "bin/marked.js" }, - "dependencies": { - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "optional": true - } + "engines": { + "node": ">= 12" } }, - "md5.js": { + "node_modules/md5.js": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" } }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "node_modules/memfs": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.11.1.tgz", + "integrity": "sha512-LZcMTBAgqUUKNXZagcZxvXXfgF1bHX7Y7nQ0QyEiNbRJgE29GhgPd8Yna1VQcLlPiHt/5RFJMWYN9Uv/VPNvjQ==", "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - }, "dependencies": { - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - } + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" } }, - "memfs": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.1.2.tgz", - "integrity": "sha512-YubKuE+RGSdpZcRq2Nih8HcHj3LrqndsDFNB9IFjrgwzdM4eq+fImlDMfNm/HdRhYRkLdUecHGIpdz+wyrqlDg==", + "node_modules/merge-stream": { + "version": "2.0.0", "dev": true, - "requires": { - "fs-monkey": "1.0.0" - } + "license": "MIT" }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "node_modules/merge2": { + "version": "1.4.1", "dev": true, - "requires": { - "errno": "^0.1.3", - "readable-stream": "^2.0.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "license": "MIT", + "engines": { + "node": ">= 8" } }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "node_modules/micromatch": { + "version": "4.0.5", "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" } }, - "miller-rabin": { + "node_modules/miller-rabin": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "bn.js": "^4.0.0", "brorand": "^1.0.1" }, - "dependencies": { - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - } + "bin": { + "miller-rabin": "bin/miller-rabin" } }, - "mime-db": { - "version": "1.37.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", - "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" }, - "mime-types": { - "version": "2.1.21", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", - "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", - "requires": { - "mime-db": "~1.37.0" + "node_modules/mime-db": { + "version": "1.52.0", + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true + "node_modules/mime-types": { + "version": "2.1.35", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } }, - "minimalistic-assert": { + "node_modules/minimalistic-assert": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "dev": true, + "license": "ISC" }, - "minimalistic-crypto-utils": { + "node_modules/minimalistic-crypto-utils": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true + "dev": true, + "license": "MIT" }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "mississippi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", - "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", - "dev": true, - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" + "node_modules/minimist": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "mocha": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", - "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", - "requires": { - "ansi-colors": "3.2.3", + "node_modules/mocha": { + "version": "9.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", - "chokidar": "3.3.0", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", "growl": "1.10.5", "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "3.0.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.5", - "ms": "2.1.1", - "node-environment-flags": "1.0.6", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "binary-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==" - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "chokidar": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", - "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", - "requires": { - "anymatch": "~3.1.1", - "braces": "~3.0.2", - "fsevents": "~2.1.1", - "glob-parent": "~5.1.0", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.2.0" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "optional": true - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "readdirp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", - "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", - "requires": { - "picomatch": "^2.0.4" - } - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - }, + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "requires": { - "has-flag": "^3.0.0" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "optional": true } } }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "4.2.1", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha/node_modules/serialize-javascript": { + "version": "6.0.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", "dev": true, - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "nan": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", + "node_modules/ms": { + "version": "2.1.2", "dev": true, - "optional": true + "license": "MIT" }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "node_modules/nanoid": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "natural-compare": { + "node_modules/natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true + "dev": true, + "license": "MIT" }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", - "dev": true + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "dev": true, + "license": "MIT" }, - "net": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/net/-/net-1.0.2.tgz", - "integrity": "sha1-0XV+yaf7I3HYPPR1XOPifhCCk4g=" + "node_modules/neo-async": { + "version": "2.6.2", + "dev": true, + "license": "MIT" }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true + "node_modules/net": { + "version": "1.0.2", + "license": "MIT" }, - "node-environment-flags": { + "node_modules/node-environment-flags": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", - "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", - "requires": { + "dev": true, + "license": "Apache-2.0", + "dependencies": { "object.getownpropertydescriptors": "^2.0.3", "semver": "^5.7.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } } }, - "node-libs-browser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", - "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "node_modules/node-environment-flags/node_modules/semver": { + "version": "5.7.2", "dev": true, - "requires": { - "assert": "^1.1.1", - "browserify-zlib": "^0.2.0", - "buffer": "^4.3.0", - "console-browserify": "^1.1.0", - "constants-browserify": "^1.0.0", - "crypto-browserify": "^3.11.0", - "domain-browser": "^1.1.1", - "events": "^3.0.0", - "https-browserify": "^1.0.0", - "os-browserify": "^0.3.0", - "path-browserify": "0.0.1", - "process": "^0.11.10", - "punycode": "^1.2.4", - "querystring-es3": "^0.2.0", - "readable-stream": "^2.3.3", - "stream-browserify": "^2.0.1", - "stream-http": "^2.7.2", - "string_decoder": "^1.0.0", - "timers-browserify": "^2.0.4", - "tty-browserify": "0.0.0", - "url": "^0.11.0", - "util": "^0.11.0", - "vm-browserify": "^1.0.1" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", - "dev": true - } - } - } + "license": "ISC", + "bin": { + "semver": "bin/semver" } }, - "normalize-path": { + "node_modules/node-releases": { + "version": "2.0.13", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "normalize-url": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", - "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", - "dev": true + "node_modules/object-inspect": { + "version": "1.12.3", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "npm-conf": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", - "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "node_modules/object-is": { + "version": "1.1.5", "dev": true, - "optional": true, - "requires": { - "config-chain": "^1.1.11", - "pify": "^3.0.0" - }, + "license": "MIT", "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true, - "optional": true - } + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "node_modules/object-keys": { + "version": "1.1.1", "dev": true, - "requires": { - "path-key": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + "node_modules/object.assign": { + "version": "4.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "node_modules/object.entries": { + "version": "1.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + } }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "node_modules/object.fromentries": { + "version": "2.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "object-keys": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.reduce": "^1.0.6", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "safe-array-concat": "^1.0.0" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "object-visit": { + "node_modules/object.groupby": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", "dev": true, - "requires": { - "isobject": "^3.0.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1" } }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" + "node_modules/object.values": { + "version": "1.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" } }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "node_modules/optionator": { + "version": "0.9.3", "dev": true, - "requires": { - "isobject": "^3.0.1" + "license": "MIT", + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" + "node_modules/os-browserify": { + "version": "0.3.0", + "dev": true, + "license": "MIT" + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "node_modules/p-locate": { + "version": "5.0.0", "dev": true, - "requires": { - "mimic-fn": "^1.0.0" + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "node_modules/p-try": { + "version": "2.2.0", "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", - "dev": true + "node_modules/pako": { + "version": "1.0.11", + "dev": true, + "license": "(MIT AND Zlib)" }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "node_modules/parse-asn1": { + "version": "5.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true + "node_modules/path-browserify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", - "dev": true + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "node_modules/path-type": { + "version": "4.0.0", "dev": true, - "requires": { - "p-try": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "node_modules/pbkdf2": { + "version": "3.1.2", "dev": true, - "requires": { - "p-limit": "^1.1.0" + "license": "MIT", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" } }, - "p-try": { + "node_modules/picocolors": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true + "dev": true, + "license": "ISC" }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "parallel-transform": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", - "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "node_modules/pify": { + "version": "4.0.1", "dev": true, - "requires": { - "cyclist": "^1.0.1", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "parse-asn1": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", - "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "node_modules/pirates": { + "version": "4.0.6", "dev": true, - "requires": { - "asn1.js": "^4.0.0", - "browserify-aes": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3", - "safe-buffer": "^5.1.1" + "license": "MIT", + "engines": { + "node": ">= 6" } }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true + "node_modules/pkg-dir": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true + "node_modules/pkg-dir/node_modules/find-up": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } }, - "path-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", - "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", - "dev": true + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "path-exists": { + "node_modules/pkg-dir/node_modules/p-locate": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true + "node_modules/process": { + "version": "0.11.10", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true + "node_modules/promise-throttle": { + "version": "1.1.2", + "license": "MIT" }, - "pbkdf2": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", - "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/public-encrypt": { + "version": "4.0.3", "dev": true, - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" } }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "node_modules/punycode": { + "version": "2.3.0", + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" + "node_modules/querystring-es3": { + "version": "0.2.1", + "dev": true, + "engines": { + "node": ">=0.4.x" + } }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true + "node_modules/randombytes": { + "version": "2.1.0", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "node_modules/randomfill": { + "version": "1.0.4", "dev": true, - "requires": { - "pinkie": "^2.0.0" + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" } }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "node_modules/readable-stream": { + "version": "3.6.2", "dev": true, - "requires": { - "find-up": "^2.1.0" + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", - "dev": true + "node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true + "node_modules/rechoir": { + "version": "0.8.0", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true + "node_modules/regenerate": { + "version": "1.4.2", + "dev": true, + "license": "MIT" }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } }, - "private": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", - "dev": true + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "license": "MIT" }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true + "node_modules/regenerator-transform": { + "version": "0.15.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.4" + } }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", - "dev": true + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "progress": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", - "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==", - "dev": true + "node_modules/regexpp": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", - "dev": true + "node_modules/regexpu-core": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } }, - "promise-throttle": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-throttle/-/promise-throttle-1.0.1.tgz", - "integrity": "sha512-pdiK8b2RU2e93U0rBK7YyO18x74OQPsg3sFmyCGGNYNbfnyUwWiU5g6mFgWtOW8KsPnCYVHIOzm1iRwv0YWXrw==" + "node_modules/regjsparser": { + "version": "0.9.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", "dev": true, - "optional": true + "bin": { + "jsesc": "bin/jsesc" + } }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", - "dev": true + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "psl": { - "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", - "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" + "node_modules/require-from-string": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "public-encrypt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", - "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "node_modules/resolve": { + "version": "1.22.6", "dev": true, - "requires": { - "bn.js": "^4.1.0", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1", - "safe-buffer": "^5.1.2" - }, + "license": "MIT", "dependencies": { - "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", - "dev": true - } + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "pump": { + "node_modules/resolve-cwd": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" } }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", "dev": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } + "license": "MIT", + "engines": { + "node": ">=8" } }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "dev": true + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", - "dev": true + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "requires": { - "safe-buffer": "^5.1.0" + "node_modules/ripemd160": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, - "randomfill": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "node_modules/run-parallel": { + "version": "1.2.0", "dev": true, - "requires": { - "randombytes": "^2.0.5", - "safe-buffer": "^5.1.0" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" } }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "node_modules/safe-array-concat": { + "version": "1.0.1", "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } + ], + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true + "node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "license": "MIT" }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "node_modules/schema-utils": { + "version": "4.2.0", "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.12.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "dev": true, + "license": "MIT" }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true + "node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "3.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } }, - "repeating": { + "node_modules/set-function-name": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "dev": true, - "requires": { - "is-finite": "^1.0.0" - } - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "request-promise": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.5.tgz", - "integrity": "sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==", - "requires": { - "bluebird": "^3.5.0", - "request-promise-core": "1.1.3", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, - "request-promise-core": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", - "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", - "requires": { - "lodash": "^4.17.15" + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + "node_modules/sha.js": { + "version": "2.4.11", + "dev": true, + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } }, - "require-main-filename": { + "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "node_modules/shebang-regex": { + "version": "3.0.0", "dev": true, - "requires": { - "caller-path": "^0.1.0", - "resolve-from": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "requizzle": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.3.tgz", - "integrity": "sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ==", + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", "dev": true, - "requires": { - "lodash": "^4.17.14" + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" } }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "node_modules/shelljs/node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true, - "requires": { - "path-parse": "^1.0.6" + "engines": { + "node": ">= 0.10" } }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "node_modules/shelljs/node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dev": true, - "requires": { - "resolve-from": "^3.0.0" - }, "dependencies": { - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - } + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" } }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - }, - "dependencies": { - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - } + "node_modules/shiki": { + "version": "0.14.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" } }, - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true + "node_modules/shx": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", + "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", + "dev": true, + "dependencies": { + "minimist": "^1.2.3", + "shelljs": "^0.8.5" + }, + "bin": { + "shx": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "node_modules/side-channel": { + "version": "1.0.4", "dev": true, - "requires": { - "lowercase-keys": "^1.0.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "restore-cursor": { + "node_modules/slash": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, - "requires": { - "glob": "^7.0.5" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "node_modules/source-map-support": { + "version": "0.5.21", "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "roarr": { - "version": "2.15.3", - "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.3.tgz", - "integrity": "sha512-AEjYvmAhlyxOeB9OqPUzQCo3kuAkNfuDk/HqWbZdFsqDFpapkTjiw+p4svNEoRLvuqNTxqfL+s+gtD4eDgZ+CA==", + "node_modules/stream-browserify": { + "version": "3.0.0", "dev": true, - "optional": true, - "requires": { - "boolean": "^3.0.0", - "detect-node": "^2.0.4", - "globalthis": "^1.0.1", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" - }, - "dependencies": { - "sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", - "dev": true, - "optional": true - } + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" } }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "node_modules/stream-http": { + "version": "3.2.0", "dev": true, - "requires": { - "is-promise": "^2.1.0" - }, + "license": "MIT", "dependencies": { - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", - "dev": true - } + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" } }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "node_modules/string_decoder": { + "version": "1.3.0", "dev": true, - "requires": { - "aproba": "^1.1.1" + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" } }, - "rxjs": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", - "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==", + "node_modules/string-width": { + "version": "4.2.3", "dev": true, - "requires": { - "tslib": "^1.9.0" + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "node_modules/string.prototype.trim": { + "version": "1.2.8", "dev": true, - "requires": { - "ret": "~0.1.10" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sanitize-filename": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", - "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "node_modules/string.prototype.trimend": { + "version": "1.0.7", "dev": true, - "requires": { - "truncate-utf8-bytes": "^1.0.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "schema-utils": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", - "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" - }, + "license": "MIT", "dependencies": { - "ajv": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz", - "integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - } + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", - "dev": true - }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "node_modules/strip-ansi": { + "version": "6.0.1", "dev": true, - "optional": true + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } }, - "serialize-error": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", - "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "node_modules/strip-bom": { + "version": "3.0.0", "dev": true, - "optional": true, - "requires": { - "type-fest": "^0.13.1" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "serialize-javascript": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz", - "integrity": "sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==", - "requires": { - "randombytes": "^2.1.0" + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "sha.js": { - "version": "2.4.11", - "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "node_modules/tapable": { + "version": "2.2.1", "dev": true, - "requires": { - "shebang-regex": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "node_modules/terser": { + "version": "5.20.0", "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0" - }, + "license": "BSD-2-Clause", "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" } }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } + "esbuild": { + "optional": true }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "uglify-js": { + "optional": true } } }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "node_modules/terser-webpack-plugin/node_modules/serialize-javascript": { + "version": "6.0.1", "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, + "license": "BSD-3-Clause", "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "randombytes": "^2.1.0" } }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "dev": true, + "license": "MIT" }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "node_modules/text-encoding": { + "version": "0.7.0", + "license": "(Unlicense OR Apache-2.0)" }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "node_modules/text-table": { + "version": "0.2.0", "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } + "license": "MIT" }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "engines": { + "node": ">=10.18" }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } + "peerDependencies": { + "tslib": "^2" } }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true + "node_modules/tls": { + "version": "0.0.1" }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "node_modules/to-fast-properties": { + "version": "2.0.0", "dev": true, - "requires": { - "extend-shallow": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "sshpk": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz", - "integrity": "sha512-mSdgNUaidk+dRU5MhYtN9zebdzF2iG0cNPWy8HG+W8y+fT1JnSkh0fzzpjOa0L7P8i1Rscz38t0h4gPcKz43xA==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "ssri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "requires": { - "figgy-pudding": "^3.5.1" + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "node_modules/tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "engines": { + "node": ">=10.0" }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" - }, - "stream-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", - "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "node_modules/ts-loader": { + "version": "9.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" } }, - "stream-each": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "4.3.0", "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "stream-http": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", - "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "node_modules/ts-loader/node_modules/chalk": { + "version": "4.1.2", "dev": true, - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.6", - "to-arraybuffer": "^1.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, + "node_modules/ts-loader/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "^3.0.0" - } - } + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.4", "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } + "license": "MIT" }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "node_modules/ts-loader/node_modules/has-flag": { + "version": "4.0.0", "dev": true, - "requires": { - "ansi-regex": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + "node_modules/ts-loader/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } }, - "sumchecker": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", - "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "node_modules/ts-loader/node_modules/semver": { + "version": "7.5.4", "dev": true, - "requires": { - "debug": "^4.1.0" + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true + "node_modules/ts-loader/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" }, - "table": { - "version": "4.0.3", - "resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz", - "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", + "node_modules/ts-node": { + "version": "10.9.1", "dev": true, - "requires": { - "ajv": "^6.0.1", - "ajv-keywords": "^3.0.0", - "chalk": "^2.1.0", - "lodash": "^4.17.4", - "slice-ansi": "1.0.0", - "string-width": "^2.1.1" - }, + "license": "MIT", "dependencies": { - "ajv": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.4.tgz", - "integrity": "sha512-4Wyjt8+t6YszqaXnLDfMmG/8AlO5Zbcsy3ATHncCzjW/NoPzAId8AK6749Ybjmdt+kUY1gP60fCu46oDxPv/mg==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } + "@swc/wasm": { + "optional": true } } }, - "taffydb": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz", - "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=", - "dev": true + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "dev": true, + "license": "MIT" }, - "tapable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.0.tgz", - "integrity": "sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA==", - "dev": true + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } }, - "terser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", - "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "node_modules/tsconfig-paths": { + "version": "3.14.2", "dev": true, - "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - }, + "license": "MIT", "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" } }, - "terser-webpack-plugin": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", - "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", - "dev": true, - "requires": { - "cacache": "^12.0.2", - "find-cache-dir": "^2.1.0", - "is-wsl": "^1.1.0", - "schema-utils": "^1.0.0", - "serialize-javascript": "^4.0.0", - "source-map": "^0.6.1", - "terser": "^4.1.2", - "webpack-sources": "^1.4.0", - "worker-farm": "^1.7.0" - }, - "dependencies": { - "find-cache-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", - "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^2.0.0", - "pkg-dir": "^3.0.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" } }, - "text-encoding": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz", - "integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==" - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "node_modules/tsutils": { + "version": "3.21.0", "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "license": "MIT", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "timers-browserify": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", - "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", "dev": true, - "requires": { - "setimmediate": "^1.0.4" - } + "license": "0BSD" }, - "tls": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/tls/-/tls-0.0.1.tgz", - "integrity": "sha1-CrK/WWjXHfL4wOFRXSSiJAuYqsg=" - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true + "node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "node_modules/typed-array-buffer": { + "version": "1.0.0", "dev": true, - "requires": { - "kind-of": "^3.0.2" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "to-readable-stream": { + "node_modules/typed-array-byte-offset": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "node_modules/typed-array-length": { + "version": "1.0.4", "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "node_modules/typedoc": { + "version": "0.25.1", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.3.0", + "minimatch": "^9.0.3", + "shiki": "^0.14.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x" } }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", - "dev": true - }, - "truncate-utf8-bytes": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", - "integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=", + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", "dev": true, - "requires": { - "utf8-byte-length": "^1.0.1" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" } }, - "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", - "dev": true - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", - "dev": true - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "node_modules/typedoc/node_modules/minimatch": { + "version": "9.0.3", "dev": true, - "optional": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "node_modules/typescript": { + "version": "5.2.2", "dev": true, - "requires": { - "prelude-ls": "~1.1.2" + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" } }, - "type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "node_modules/unbox-primitive": { + "version": "1.0.2", "dev": true, - "optional": true - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "underscore": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz", - "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==", - "dev": true + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", "dev": true, - "requires": { - "unique-slug": "^2.0.0" + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" } }, - "unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", "dev": true, - "requires": { - "imurmurhash": "^0.1.4" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { + "node_modules/uri-js": { + "version": "4.4.1", + "license": "BSD-2-Clause", + "dependencies": { "punycode": "^2.1.0" - }, + } + }, + "node_modules/url": { + "version": "0.11.3", + "dev": true, + "license": "MIT", "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - } + "punycode": "^1.4.1", + "qs": "^6.11.2" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "dev": true, + "license": "MIT" }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "node_modules/url/node_modules/qs": { + "version": "6.11.2", "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, + "license": "BSD-3-Clause", "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", - "dev": true - } + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "node_modules/util": { + "version": "0.12.5", "dev": true, - "requires": { - "prepend-http": "^2.0.0" + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" } }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "utf8-byte-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", - "integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=", - "dev": true - }, - "util": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", - "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "node_modules/util-deprecate": { + "version": "1.0.2", "dev": true, - "requires": { - "inherits": "2.0.3" + "license": "MIT" + }, + "node_modules/uuid": { + "version": "3.3.2", + "license": "MIT", + "bin": { + "uuid": "bin/uuid" } }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "dev": true, + "license": "MIT" }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "node_modules/v8flags": { + "version": "3.2.0", "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" } }, - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "dev": true, + "license": "MIT" }, - "v8-compile-cache": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", - "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==", - "dev": true + "node_modules/vscode-textmate": { + "version": "8.0.0", + "dev": true, + "license": "MIT" }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "node_modules/watchpack": { + "version": "2.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" } }, - "vm-browserify": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", - "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", - "dev": true + "node_modules/web-worker": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.3.0.tgz", + "integrity": "sha512-BSR9wyRsy/KOValMgd5kMyr3JzpdeoR9KVId8u5GVlTTAtNChlsE4yTxeY7zMdNSyOmoKBv8NH2qeRY9Tg+IaA==", + "license": "Apache-2.0" }, - "watchpack": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.1.tgz", - "integrity": "sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA==", - "dev": true, - "requires": { - "chokidar": "^2.1.8", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" - } - }, - "webpack": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.43.0.tgz", - "integrity": "sha512-GW1LjnPipFW2Y78OOab8NJlCflB7EFskMih2AHdvjbpKMeDJqEgSx24cXXXiPS65+WSwVyxtDsJH6jGX2czy+g==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.9.0", - "@webassemblyjs/helper-module-context": "1.9.0", - "@webassemblyjs/wasm-edit": "1.9.0", - "@webassemblyjs/wasm-parser": "1.9.0", - "acorn": "^6.4.1", - "ajv": "^6.10.2", - "ajv-keywords": "^3.4.1", + "node_modules/webpack": { + "version": "5.88.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^4.1.0", - "eslint-scope": "^4.0.3", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^2.4.0", - "loader-utils": "^1.2.3", - "memory-fs": "^0.4.1", - "micromatch": "^3.1.10", - "mkdirp": "^0.5.3", - "neo-async": "^2.6.1", - "node-libs-browser": "^2.2.1", - "schema-utils": "^1.0.0", - "tapable": "^1.1.3", - "terser-webpack-plugin": "^1.4.3", - "watchpack": "^1.6.1", - "webpack-sources": "^1.4.1" - }, - "dependencies": { - "ajv-keywords": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", - "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", - "dev": true - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - } - }, - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - }, - "tapable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", - "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", - "dev": true + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true } } }, - "webpack-cli": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.11.tgz", - "integrity": "sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g==", - "dev": true, - "requires": { - "chalk": "2.4.2", - "cross-spawn": "6.0.5", - "enhanced-resolve": "4.1.0", - "findup-sync": "3.0.0", - "global-modules": "2.0.0", - "import-local": "2.0.0", - "interpret": "1.2.0", - "loader-utils": "1.2.3", - "supports-color": "6.1.0", - "v8-compile-cache": "2.0.3", - "yargs": "13.2.4" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } + "node_modules/webpack-cli": { + "version": "5.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true }, - "loader-utils": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", - "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^2.0.0", - "json5": "^1.0.1" - } + "webpack-bundle-analyzer": { + "optional": true }, - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } + "webpack-dev-server": { + "optional": true } } }, - "webpack-merge": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.1.4.tgz", - "integrity": "sha512-TmSe1HZKeOPey3oy1Ov2iS3guIZjWvMT2BBJDzzT5jScHTjVC3mpjJofgueEzaEd6ibhxRDD6MIblDr8tzh8iQ==", + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", "dev": true, - "requires": { - "lodash": "^4.17.5" + "license": "MIT", + "engines": { + "node": ">=14" } }, - "webpack-sources": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", - "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "node_modules/webpack-merge": { + "version": "5.9.0", "dev": true, - "requires": { - "source-list-map": "^2.0.0", - "source-map": "~0.6.1" + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "dev": true, + "license": "MIT", "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "requires": { - "string-width": "^1.0.2 || 2" + "node_modules/which-typed-array": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true + "node_modules/wildcard": { + "version": "2.0.1", + "dev": true, + "license": "MIT" }, - "worker-farm": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", - "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "node_modules/workerpool": { + "version": "6.2.0", "dev": true, - "requires": { - "errno": "~0.1.7" - } + "license": "Apache-2.0" }, - "worker-loader": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-2.0.0.tgz", - "integrity": "sha512-tnvNp4K3KQOpfRnD20m8xltE3eWh89Ye+5oj7wXEEHKac1P4oZ6p9oTj8/8ExqoSBnk9nu5Pr4nKfQ1hn2APJw==", + "node_modules/wrap-ansi": { + "version": "7.0.0", "dev": true, - "requires": { - "loader-utils": "^1.0.0", - "schema-utils": "^0.4.0" + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - } + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", "dev": true, - "requires": { - "mkdirp": "^0.5.1" + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "xmlcreate": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz", - "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==", - "dev": true + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" }, - "xtend": { + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/xtend": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + "node_modules/y18n": { + "version": "5.0.8", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } }, - "yallist": { + "node_modules/yallist": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "dev": true, + "license": "ISC" }, - "yargs": { - "version": "13.2.4", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", - "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "node_modules/yargs": { + "version": "16.2.0", "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "os-locale": "^3.1.0", + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" } }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "node_modules/yargs-parser": { + "version": "20.2.4", "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - } + "license": "ISC", + "engines": { + "node": ">=10" } }, - "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" - }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "requires": { - "locate-path": "^3.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - } + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" } }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "node_modules/yocto-queue": { + "version": "0.1.0", "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } } } diff --git a/package.json b/package.json index 56bda24b1..6072a0c3f 100644 --- a/package.json +++ b/package.json @@ -1,58 +1,102 @@ { - "name": "monero-javascript", - "description": "A JavaScript library for using Monero", - "version": "0.4.3", + "name": "monero-ts", + "description": "A TypeScript library for using Monero", + "version": "0.11.6", "license": "MIT", - "repository": "https://github.com/monero-ecosystem/monero-javascript", + "repository": "https://github.com/woodser/monero-ts", "private": false, - "main": "index.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist/", + "!dist/src/test/**", + "README.md", + "package.json", + "tsconfig.json", + ".babelrc", + "CMakeListst.txt", + "LICENSE.txt" + ], + "imports": { + "#monero-ts/monero.js": "./dist/monero.js" + }, "scripts": { "start": "todo", "build_web_worker": "webpack --config ./webpack.worker.js", "build_web_tests": "webpack --config ./webpack.tests.js", - "test": "node --experimental-wasm-threads --experimental-wasm-bulk-memory node_modules/mocha/bin/_mocha 'src/test/TestAll' --timeout 900000000 --exit", - "jsdoc": "jsdoc -r -c ./configs/jsdoc_config.js -d ./docs" + "test": "npm run build_commonjs && node --enable-source-maps node_modules/mocha/bin/_mocha --require @babel/register \"dist/src/test/TestAll\" --timeout 900000000 --exit", + "typedoc": "typedoc ./index.ts --out ./docs/typedocs --excludePrivate --disableSources", + "build_commonjs": "babel ./src --extensions \".js,.ts\" --out-dir ./dist/src && babel ./index.ts --extensions \".ts\" --out-dir ./dist", + "check_babel_version": "babel -V" }, "build": { "publish": [ { "provider": "github", "owner": "woodser", - "repo": "monero-javascript" + "repo": "monero-ts" } ] }, "engines": { - "node": "7.4.0" + "node": ">=10.0.0" }, "dependencies": { - "ajv": "^6.12.2", - "async": "2.6.1", + "@babel/runtime": "^7.23.2", + "@types/node": "^20.6.0", + "ajv": "^6.12.6", + "async": "2.6.4", + "axios": "^1.7.4", "crypto-js": "^4.0.0", - "html5-fs": "0.1.1", - "mocha": "^7.1.2", + "decimal.js": "^10.4.3", "net": "^1.0.2", - "promise-throttle": "^1.0.1", - "request": "2.88.0", - "request-promise": "^4.2.5", + "promise-throttle": "^1.1.2", "serialize-javascript": "^3.1.0", "text-encoding": "^0.7.0", "tls": "0.0.1", - "uuid": "3.3.2" + "uuid": "3.3.2", + "web-worker": "1.3.0" }, "devDependencies": { - "babel-core": "6.26.3", - "babel-loader": "8.0.2", - "babel-minify": "^0.4.3", - "electron": "7.2.4", - "eslint": "5.6.0", - "jsdoc": "^3.6.4", - "memfs": "^3.1.2", - "minimist": "^1.2.5", - "webpack": "^4.43.0", - "webpack-cli": "^3.3.11", - "webpack-merge": "4.1.4", - "worker-loader": "2.0.0", - "yargs-parser": "^18.1.3" + "@babel/cli": "^7.18.10", + "@babel/core": "^7.22.17", + "@babel/node": "^7.18.10", + "@babel/plugin-transform-runtime": "^7.18.10", + "@babel/preset-env": "^7.22.15", + "@babel/preset-typescript": "^7.22.15", + "@babel/register": "^7.22.15", + "@types/jquery": "^3.5.19", + "@types/mocha": "^9.1.1", + "@typescript-eslint/eslint-plugin": "5.53.0", + "@typescript-eslint/parser": "^5.53.0", + "assert": "^2.1.0", + "babel-loader": "^9.1.3", + "browserify-zlib": "^0.2.0", + "buffer": "^6.0.3", + "crypto-browserify": "^3.12.0", + "eslint": "^8.35.0", + "eslint-config-prettier": "^8.6.0", + "eslint-import-resolver-typescript": "^3.5.3", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-jsx-a11y": "^6.7.1", + "https-browserify": "^1.0.0", + "memfs": "^4.11.1", + "mocha": "^9.1.3", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "querystring-es3": "^0.2.1", + "shx": "^0.3.4", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "ts-loader": "^9.4.4", + "ts-node": "^10.9.1", + "typedoc": "^0.25.1", + "typescript": "^5.2.2", + "url": "^0.11.3", + "util": "^0.12.5", + "webpack": "^5.88.2", + "webpack-cli": "^5.1.4", + "webpack-merge": "^5.9.0" } } diff --git a/src/main/cpp/http_client_wasm.cpp b/src/main/cpp/http_client_wasm.cpp index a254ef710..4ba60d794 100644 --- a/src/main/cpp/http_client_wasm.cpp +++ b/src/main/cpp/http_client_wasm.cpp @@ -4,16 +4,17 @@ #include "http_client_wasm.h" #include #include +#include "string_tools.h" +#include "misc_log_ex.h" using namespace std; EM_JS(const char*, js_send_json_request, (const char* uri, const char* username, const char* password, const char* reject_unauthorized_fn_id, const char* method, const char* body, std::chrono::milliseconds timeout), { //console.log("EM_JS js_send_json_request(" + UTF8ToString(uri) + ", " + UTF8ToString(username) + ", " + UTF8ToString(password) + ", " + UTF8ToString(method) + ")"); - const monerojs = require("../index"); - const HttpClient = monerojs.HttpClient; - const LibraryUtils = monerojs.LibraryUtils; - const GenUtils = monerojs.GenUtils; + const HttpClient = this.HttpClient; + const LibraryUtils = this.LibraryUtils; + const GenUtils = this.GenUtils; // use asyncify to synchronously return to C++ return Asyncify.handleSleep(function(wakeUp) { @@ -28,7 +29,6 @@ EM_JS(const char*, js_send_json_request, (const char* uri, const char* username, body: UTF8ToString(body), resolveWithFullResponse: true, rejectUnauthorized: LibraryUtils.isRejectUnauthorized(UTF8ToString(reject_unauthorized_fn_id)), - requestApi: GenUtils.isFirefox() ? "xhr" : "fetch" // firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1491010 }).then(resp => { // build response container @@ -65,16 +65,15 @@ EM_JS(const char*, js_send_json_request, (const char* uri, const char* username, EM_JS(const char*, js_send_binary_request, (const char* uri, const char* username, const char* password, const char* reject_unauthorized_fn_id, const char* method, const char* body, int body_length, std::chrono::milliseconds timeout), { //console.log("EM_JS js_send_binary_request(" + UTF8ToString(uri) + ", " + UTF8ToString(username) + ", " + UTF8ToString(password) + ", " + UTF8ToString(method) + ")"); - const monerojs = require("../index"); - const HttpClient = monerojs.HttpClient; - const LibraryUtils = monerojs.LibraryUtils; - const GenUtils = monerojs.GenUtils; + const HttpClient = this.HttpClient; + const LibraryUtils = this.LibraryUtils; + const GenUtils = this.GenUtils; // use asyncify to synchronously return to C++ return Asyncify.handleSleep(function(wakeUp) { - // load wasm module then convert from json to binary - LibraryUtils.loadCoreModule().then(module => { + // load full wasm module then convert from json to binary + LibraryUtils.loadWasmModule().then(module => { // read binary data from heap to Uint8Array let ptr = body; @@ -94,7 +93,6 @@ EM_JS(const char*, js_send_binary_request, (const char* uri, const char* usernam body: view, resolveWithFullResponse: true, rejectUnauthorized: LibraryUtils.isRejectUnauthorized(UTF8ToString(reject_unauthorized_fn_id)), - requestApi: GenUtils.isFirefox() ? "xhr" : "fetch" // firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1491010 }).then(resp => { // write binary body to heap to pass back pointer @@ -138,11 +136,19 @@ EM_JS(const char*, js_send_binary_request, (const char* uri, const char* usernam wakeUp(ptr); }); }).catch(err => { - throw new Error("Could not load core wasm module"); + throw new Error("Could not load full wasm module"); }); }); }); +bool http_client_wasm::set_proxy(const std::string& address) { + if (!address.empty()) { + std::cout << "WARNING: http_client_wasm::set_proxy() not supported, returning false" << std::endl; + return false; + } + return true; +} + void http_client_wasm::set_server(std::string host, std::string port, boost::optional user, ssl_options_t ssl_options) { disconnect(); m_host = host; @@ -198,7 +204,7 @@ void build_http_header_info(const boost::property_tree::ptree& headers_node, htt } } -bool http_client_wasm::invoke_json(const boost::string_ref path, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info, const fields_list& additional_params) { +bool http_client_wasm::invoke_json(const boost::string_ref path, const boost::string_ref method, const boost::string_ref body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info, const fields_list& additional_params) { // make json request through javascript string uri = string(m_ssl_enabled ? "https" : "http") + "://" + m_host + ":" + m_port + string(path); @@ -240,7 +246,7 @@ bool http_client_wasm::invoke_json(const boost::string_ref path, const boost::st return m_response_info.m_response_code == 200; } -bool http_client_wasm::invoke_binary(const boost::string_ref path, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info, const fields_list& additional_params) { +bool http_client_wasm::invoke_binary(const boost::string_ref path, const boost::string_ref method, const boost::string_ref body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info, const fields_list& additional_params) { // make binary request through javascript string uri = string(m_ssl_enabled ? "https" : "http") + "://" + m_host + ":" + m_port + string(path); @@ -287,7 +293,7 @@ bool http_client_wasm::invoke_binary(const boost::string_ref path, const boost:: return m_response_info.m_response_code == 200; } -bool http_client_wasm::invoke(const boost::string_ref path, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info, const fields_list& additional_params) { +bool http_client_wasm::invoke(const boost::string_ref path, const boost::string_ref method, const boost::string_ref body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info, const fields_list& additional_params) { //cout << "invoke(" << path << ", " << method << ", ...)" << endl; if(!is_connected()) diff --git a/src/main/cpp/http_client_wasm.h b/src/main/cpp/http_client_wasm.h index a6d9f60d8..2026b8a6e 100644 --- a/src/main/cpp/http_client_wasm.h +++ b/src/main/cpp/http_client_wasm.h @@ -26,20 +26,21 @@ namespace epee disconnect(); } + bool set_proxy(const std::string& address) override; void set_server(std::string host, std::string port, boost::optional user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect) override; void set_auto_connect(bool auto_connect) override; bool connect(std::chrono::milliseconds timeout) override; bool disconnect() override; bool is_connected(bool *ssl = NULL) override; - bool invoke(const boost::string_ref uri, const boost::string_ref method, const string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override; + bool invoke(const boost::string_ref uri, const boost::string_ref method, const boost::string_ref body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override; bool invoke_get(const boost::string_ref uri, std::chrono::milliseconds timeout, const string& body = string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override; bool invoke_post(const boost::string_ref uri, const string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override; uint64_t get_bytes_sent() const override; uint64_t get_bytes_received() const override; private: - string m_host; - string m_port; + std::string m_host; + std::string m_port; boost::optional m_user; string m_reject_unauthorized_fn_id; bool m_ssl_enabled; @@ -47,8 +48,8 @@ namespace epee http_response_info m_response_info; bool m_auto_connect; - bool invoke_json(const boost::string_ref uri, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info, const fields_list& additional_params); - bool invoke_binary(const boost::string_ref uri, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info, const fields_list& additional_params); + bool invoke_json(const boost::string_ref uri, const boost::string_ref method, const boost::string_ref body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info, const fields_list& additional_params); + bool invoke_binary(const boost::string_ref uri, const boost::string_ref method, const boost::string_ref body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info, const fields_list& additional_params); }; /** diff --git a/src/main/cpp/index.cpp b/src/main/cpp/index.cpp index a7d9ea109..1b1467c21 100644 --- a/src/main/cpp/index.cpp +++ b/src/main/cpp/index.cpp @@ -9,33 +9,35 @@ EMSCRIPTEN_BINDINGS(module) { // ------------------------------ UTILITIES --------------------------------- + emscripten::function("set_log_level", &monero_wasm_bridge::set_log_level); + emscripten::function("get_integrated_address_util", &monero_wasm_bridge::get_integrated_address_util); + emscripten::function("validate_address", &monero_wasm_bridge::validate_address); + emscripten::function("get_exception_message", &monero_wasm_bridge::get_exception_message); emscripten::function("malloc_binary_from_json", &monero_wasm_bridge::malloc_binary_from_json); emscripten::function("binary_to_json", &monero_wasm_bridge::binary_to_json); emscripten::function("binary_blocks_to_json", &monero_wasm_bridge::binary_blocks_to_json); // --------------------------- WALLET CREATION ------------------------------ - emscripten::function("open_core_wallet", &monero_wasm_bridge::open_core_wallet); - emscripten::function("create_core_wallet_random", &monero_wasm_bridge::create_core_wallet_random); - emscripten::function("create_core_wallet_from_mnemonic", &monero_wasm_bridge::create_core_wallet_from_mnemonic); - emscripten::function("create_core_wallet_from_keys", &monero_wasm_bridge::create_core_wallet_from_keys); - emscripten::function("get_core_wallet_mnemonic_languages", &monero_wasm_bridge::get_core_wallet_mnemonic_languages); + emscripten::function("open_wallet_full", &monero_wasm_bridge::open_wallet_full); + emscripten::function("create_full_wallet", &monero_wasm_bridge::create_full_wallet); + emscripten::function("get_full_wallet_seed_languages", &monero_wasm_bridge::get_full_wallet_seed_languages); emscripten::function("create_keys_wallet_random", &monero_wasm_bridge::create_keys_wallet_random); - emscripten::function("create_keys_wallet_from_mnemonic", &monero_wasm_bridge::create_keys_wallet_from_mnemonic); + emscripten::function("create_keys_wallet_from_seed", &monero_wasm_bridge::create_keys_wallet_from_seed); emscripten::function("create_keys_wallet_from_keys", &monero_wasm_bridge::create_keys_wallet_from_keys); - emscripten::function("get_keys_wallet_mnemonic_languages", &monero_wasm_bridge::get_keys_wallet_mnemonic_languages); + emscripten::function("get_keys_wallet_seed_languages", &monero_wasm_bridge::get_keys_wallet_seed_languages); // ----------------------- WALLET INSTANCE METHODS -------------------------- emscripten::function("is_view_only", &monero_wasm_bridge::is_view_only); emscripten::function("set_daemon_connection", &monero_wasm_bridge::set_daemon_connection); emscripten::function("get_daemon_connection", &monero_wasm_bridge::get_daemon_connection); - emscripten::function("is_connected", &monero_wasm_bridge::is_connected); + emscripten::function("is_connected_to_daemon", &monero_wasm_bridge::is_connected_to_daemon); emscripten::function("get_daemon_max_peer_height", &monero_wasm_bridge::get_daemon_max_peer_height); emscripten::function("get_version", &monero_wasm_bridge::get_version); - emscripten::function("get_mnemonic", &monero_wasm_bridge::get_mnemonic); - emscripten::function("get_mnemonic_language", &monero_wasm_bridge::get_mnemonic_language); + emscripten::function("get_seed", &monero_wasm_bridge::get_seed); + emscripten::function("get_seed_language", &monero_wasm_bridge::get_seed_language); emscripten::function("get_private_spend_key", &monero_wasm_bridge::get_private_spend_key); emscripten::function("get_private_view_key", &monero_wasm_bridge::get_private_view_key); emscripten::function("get_public_view_key", &monero_wasm_bridge::get_public_view_key); @@ -50,11 +52,12 @@ EMSCRIPTEN_BINDINGS(module) emscripten::function("is_daemon_synced", &monero_wasm_bridge::is_daemon_synced); emscripten::function("is_synced", &monero_wasm_bridge::is_synced); emscripten::function("get_network_type", &monero_wasm_bridge::get_network_type); - emscripten::function("get_sync_height", &monero_wasm_bridge::get_sync_height); - emscripten::function("set_sync_height", &monero_wasm_bridge::set_sync_height); + emscripten::function("get_restore_height", &monero_wasm_bridge::get_restore_height); + emscripten::function("set_restore_height", &monero_wasm_bridge::set_restore_height); emscripten::function("set_listener", &monero_wasm_bridge::set_listener); emscripten::function("sync", &monero_wasm_bridge::sync); emscripten::function("stop_syncing", &monero_wasm_bridge::stop_syncing); + emscripten::function("scan_txs", &monero_wasm_bridge::scan_txs); emscripten::function("rescan_spent", &monero_wasm_bridge::rescan_spent); emscripten::function("rescan_blockchain", &monero_wasm_bridge::rescan_blockchain); emscripten::function("get_balance_wallet", &monero_wasm_bridge::get_balance_wallet); @@ -68,20 +71,25 @@ EMSCRIPTEN_BINDINGS(module) emscripten::function("create_account", &monero_wasm_bridge::create_account); emscripten::function("get_subaddresses", &monero_wasm_bridge::get_subaddresses); emscripten::function("create_subaddress", &monero_wasm_bridge::create_subaddress); + emscripten::function("set_subaddress_label", &monero_wasm_bridge::set_subaddress_label); emscripten::function("get_txs", &monero_wasm_bridge::get_txs); emscripten::function("get_transfers", &monero_wasm_bridge::get_transfers); emscripten::function("get_outputs", &monero_wasm_bridge::get_outputs); - emscripten::function("get_outputs_hex", &monero_wasm_bridge::get_outputs_hex); - emscripten::function("import_outputs_hex", &monero_wasm_bridge::import_outputs_hex); - emscripten::function("get_key_images", &monero_wasm_bridge::get_key_images); + emscripten::function("export_outputs", &monero_wasm_bridge::export_outputs); + emscripten::function("import_outputs", &monero_wasm_bridge::import_outputs); + emscripten::function("export_key_images", &monero_wasm_bridge::export_key_images); emscripten::function("import_key_images", &monero_wasm_bridge::import_key_images); // emscripten::function("get_new_key_images_from_last_import", &monero_wasm_bridge::get_new_key_images_from_last_import); + emscripten::function("freeze_output", &monero_wasm_bridge::freeze_output); + emscripten::function("thaw_output", &monero_wasm_bridge::thaw_output); + emscripten::function("is_output_frozen", &monero_wasm_bridge::is_output_frozen); + emscripten::function("get_default_fee_priority", &monero_wasm_bridge::get_default_fee_priority); emscripten::function("create_txs", &monero_wasm_bridge::create_txs); emscripten::function("sweep_output", &monero_wasm_bridge::sweep_output); emscripten::function("sweep_unlocked", &monero_wasm_bridge::sweep_unlocked); emscripten::function("sweep_dust", &monero_wasm_bridge::sweep_dust); emscripten::function("relay_txs", &monero_wasm_bridge::relay_txs); - emscripten::function("parse_tx_set", &monero_wasm_bridge::parse_tx_set); + emscripten::function("describe_tx_set", &monero_wasm_bridge::describe_tx_set); emscripten::function("sign_txs", &monero_wasm_bridge::sign_txs); emscripten::function("submit_txs", &monero_wasm_bridge::submit_txs); emscripten::function("sign_message", &monero_wasm_bridge::sign_message); @@ -105,7 +113,7 @@ EMSCRIPTEN_BINDINGS(module) emscripten::function("untag_accounts", &monero_wasm_bridge::untag_accounts); emscripten::function("get_account_tags", &monero_wasm_bridge::get_account_tags); emscripten::function("set_account_tag_label", &monero_wasm_bridge::set_account_tag_label); - emscripten::function("create_payment_uri", &monero_wasm_bridge::create_payment_uri); + emscripten::function("get_payment_uri", &monero_wasm_bridge::get_payment_uri); emscripten::function("parse_payment_uri", &monero_wasm_bridge::parse_payment_uri); emscripten::function("get_attribute", &monero_wasm_bridge::get_attribute); emscripten::function("set_attribute", &monero_wasm_bridge::set_attribute); @@ -114,12 +122,13 @@ EMSCRIPTEN_BINDINGS(module) emscripten::function("prepare_multisig", &monero_wasm_bridge::prepare_multisig); emscripten::function("make_multisig", &monero_wasm_bridge::make_multisig); emscripten::function("exchange_multisig_keys", &monero_wasm_bridge::exchange_multisig_keys); - emscripten::function("get_multisig_hex", &monero_wasm_bridge::get_multisig_hex); + emscripten::function("export_multisig_hex", &monero_wasm_bridge::export_multisig_hex); emscripten::function("import_multisig_hex", &monero_wasm_bridge::import_multisig_hex); emscripten::function("sign_multisig_tx_hex", &monero_wasm_bridge::sign_multisig_tx_hex); emscripten::function("submit_multisig_tx_hex", &monero_wasm_bridge::submit_multisig_tx_hex); emscripten::function("get_keys_file_buffer", &monero_wasm_bridge::get_keys_file_buffer); emscripten::function("get_cache_file_buffer", &monero_wasm_bridge::get_cache_file_buffer); + emscripten::function("change_wallet_password", &monero_wasm_bridge::change_wallet_password); emscripten::function("close", &monero_wasm_bridge::close); } extern "C" diff --git a/src/main/cpp/monero_wasm_bridge.cpp b/src/main/cpp/monero_wasm_bridge.cpp index e72fba0fd..a2df62928 100644 --- a/src/main/cpp/monero_wasm_bridge.cpp +++ b/src/main/cpp/monero_wasm_bridge.cpp @@ -2,7 +2,7 @@ #include "monero_wasm_bridge.h" #include "wallet/monero_wallet_keys.h" #include "utils/monero_utils.h" -#include "wallet/monero_wallet_core.h" +#include "wallet/monero_wallet_full.h" #include "http_client_wasm.h" using namespace std; @@ -17,6 +17,10 @@ string strip_last_char(const string& str) { return str.substr(0, str.size() - 1); } +std::string tools::dns_utils::get_account_address_as_str_from_url(const std::string& url, bool& dnssec_valid, std::function&, bool)> dns_confirm) { + throw std::runtime_error("Invalid destination address"); +} + /** * Listens for wallet notifications and notifies the listener in JavaScript. */ @@ -52,19 +56,52 @@ struct wallet_wasm_listener : public monero_wallet_listener { void on_output_received(const monero_output_wallet& output) override { boost::optional height = output.m_tx->get_height(); - int version = output.m_tx->m_version == boost::none ? 1 : *output.m_tx->m_version; // TODO: version not present in unlocked output notification, defaulting to 1 + int version = output.m_tx->m_version == boost::none ? 2 : *output.m_tx->m_version; // TODO: version not present in unlocked output notification, defaulting to 2 bool is_locked = std::static_pointer_cast(output.m_tx)->m_is_locked.get(); - m_on_output_received(height == boost::none ? (long) 0 : (long) *height, output.m_tx->m_hash.get(), to_string(*output.m_amount), (int) *output.m_account_index, (int) *output.m_subaddress_index, version, (int) *output.m_tx->m_unlock_height, is_locked); + m_on_output_received(height == boost::none ? (long) 0 : (long) *height, output.m_tx->m_hash.get(), to_string(*output.m_amount), (int) *output.m_account_index, (int) *output.m_subaddress_index, version, to_string(*output.m_tx->m_unlock_time), is_locked); } void on_output_spent(const monero_output_wallet& output) override { boost::optional height = output.m_tx->get_height(); - m_on_output_spent(height == boost::none ? (long) 0 : (long) *height, output.m_tx->m_hash.get(), to_string(*output.m_amount), (int) *output.m_account_index, (int) *output.m_subaddress_index, (int) *output.m_tx->m_version); + string account_idx_str = output.m_account_index == boost::none ? "" : to_string(*output.m_account_index).c_str(); + string subaddress_idx_str = output.m_subaddress_index == boost::none ? "" : to_string(*output.m_subaddress_index).c_str(); + int version = output.m_tx->m_version == boost::none ? 2 : *output.m_tx->m_version; // TODO: version not present in unlocked output notification, defaulting to 2 + bool is_locked = std::static_pointer_cast(output.m_tx)->m_is_locked.get(); + m_on_output_spent(height == boost::none ? (long) 0 : (long) *height, output.m_tx->m_hash.get(), to_string(*output.m_amount), account_idx_str, subaddress_idx_str, version, to_string(*output.m_tx->m_unlock_time), is_locked); } }; // ------------------------------- UTILITIES ---------------------------------- +void monero_wasm_bridge::set_log_level(int level) +{ + monero_utils::set_log_level(level); +} + +string monero_wasm_bridge::get_integrated_address_util(int network_type, const string& standard_address, const string& payment_id) +{ + try { + return monero_utils::get_integrated_address(static_cast(network_type), standard_address, payment_id).serialize(); + } catch (exception& e) { + return string(e.what()); + } +} + +string monero_wasm_bridge::validate_address(const string& address, int network_type) +{ + try { + monero_utils::validate_address(address, static_cast(network_type)); + return string(""); + } catch (exception& e) { + return string(e.what()); + } +} + +string monero_wasm_bridge::get_exception_message(int exception_ptr) +{ + return std::string(reinterpret_cast(exception_ptr)->what()); +} + string monero_wasm_bridge::malloc_binary_from_json(const std::string &buff_json) { // convert json to binary string @@ -124,102 +161,83 @@ string monero_wasm_bridge::binary_blocks_to_json(const std::string &bin_mem_info // -------------------------- STATIC WALLET UTILS ----------------------------- -void monero_wasm_bridge::open_core_wallet(const string& password, int network_type, const string& keys_data, const string& cache_data, const string& daemon_uri, const string& daemon_username, const string& daemon_password, const string& reject_unauthorized_fn_id, emscripten::val callback) { -#if defined BUILD_CORE_WALLET +void monero_wasm_bridge::open_wallet_full(const string& password, int network_type, const string& keys_data, const string& cache_data, const string& daemon_uri, const string& daemon_username, const string& daemon_password, const string& reject_unauthorized_fn_id, emscripten::val callback) { +#if defined BUILD_WALLET_FULL try { monero_rpc_connection daemon_connection = monero_rpc_connection(daemon_uri, daemon_username, daemon_password); - monero_wallet* wallet = monero_wallet_core::open_wallet_data(password, static_cast(network_type), keys_data, cache_data, daemon_connection, std::unique_ptr(new http_client_wasm_factory(reject_unauthorized_fn_id))); + monero_wallet* wallet = monero_wallet_full::open_wallet_data(password, static_cast(network_type), keys_data, cache_data, daemon_connection, std::unique_ptr(new http_client_wasm_factory(reject_unauthorized_fn_id))); callback((int) wallet); // callback with wallet memory address } catch (exception& e) { callback(string(e.what())); } #else - throw runtime_error("monero_wallet_core not built"); -#endif -} - -void monero_wasm_bridge::create_core_wallet_random(const string& password, int network_type, const string& daemon_uri, const string& daemon_username, const string& daemon_password, const string& reject_unauthorized_fn_id, const string& language, emscripten::val callback) { -#if defined BUILD_CORE_WALLET - try { - monero_rpc_connection daemon_connection = monero_rpc_connection(daemon_uri, daemon_username, daemon_password); - monero_wallet* wallet = monero_wallet_core::create_wallet_random("", password, static_cast(network_type), daemon_connection, language, std::unique_ptr(new http_client_wasm_factory(reject_unauthorized_fn_id))); - callback((int) wallet); // callback with wallet memory address - } catch (exception& e) { - callback(string(e.what())); - } -#else - throw runtime_error("monero_wallet_core not built"); -#endif -} - -void monero_wasm_bridge::create_core_wallet_from_mnemonic(const string& password, int network_type, const string& mnemonic, const string& daemon_uri, const string& daemon_username, const string& daemon_password, const string& reject_unauthorized_fn_id, long restore_height, const string& seed_offset, emscripten::val callback) { -#if defined BUILD_CORE_WALLET - try { - monero_rpc_connection daemon_connection = monero_rpc_connection(daemon_uri, daemon_username, daemon_password); - monero_wallet* wallet = monero_wallet_core::create_wallet_from_mnemonic("", password, static_cast(network_type), mnemonic, daemon_connection, restore_height, seed_offset, std::unique_ptr(new http_client_wasm_factory(reject_unauthorized_fn_id))); - callback((int) wallet); // callback with wallet memory address - } catch (exception& e) { - callback(string(e.what())); - } + throw runtime_error("monero_wallet_full not built"); #endif } -void monero_wasm_bridge::create_core_wallet_from_keys(const string& password, int network_type, const string& address, const string& view_key, const string& spend_key, const string& daemon_uri, const string& daemon_username, const string& daemon_password, const string& reject_unauthorized_fn_id, long restore_height, const string& language, emscripten::val callback) { -#if defined BUILD_CORE_WALLET +void monero_wasm_bridge::create_full_wallet(const string& config_json, const string& reject_unauthorized_fn_id, emscripten::val callback) { +#if defined BUILD_WALLET_FULL try { - monero_rpc_connection daemon_connection = monero_rpc_connection(daemon_uri, daemon_username, daemon_password); - monero_wallet* wallet = monero_wallet_core::create_wallet_from_keys("", password, static_cast(network_type), address, view_key, spend_key, daemon_connection, restore_height, language, std::unique_ptr(new http_client_wasm_factory(reject_unauthorized_fn_id))); + shared_ptr config = monero_wallet_config::deserialize(config_json); + config->m_path = std::string(""); + monero_wallet* wallet = monero_wallet_full::create_wallet(*config, std::unique_ptr(new http_client_wasm_factory(reject_unauthorized_fn_id))); callback((int) wallet); // callback with wallet memory address } catch (exception& e) { callback(string(e.what())); } #else - throw runtime_error("monero_wallet_core not built"); + throw runtime_error("monero_wallet_full not built"); #endif } -string monero_wasm_bridge::get_core_wallet_mnemonic_languages() { -#if defined BUILD_CORE_WALLET +string monero_wasm_bridge::get_full_wallet_seed_languages() { +#if defined BUILD_WALLET_FULL rapidjson::Document doc; doc.SetObject(); - doc.AddMember("languages", monero_utils::to_rapidjson_val(doc.GetAllocator(), monero_wallet_core::get_mnemonic_languages()), doc.GetAllocator()); + doc.AddMember("languages", monero_utils::to_rapidjson_val(doc.GetAllocator(), monero_wallet_full::get_seed_languages()), doc.GetAllocator()); return monero_utils::serialize(doc); #else - throw runtime_error("monero_wallet_core not built"); + throw runtime_error("monero_wallet_full not built"); #endif } -void monero_wasm_bridge::create_keys_wallet_random(int network_type, const string& language, emscripten::val callback) { +void monero_wasm_bridge::create_keys_wallet_random(const string& config_json, emscripten::val callback) { try { - monero_wallet* wallet = monero_wallet_keys::create_wallet_random(static_cast(network_type), language); + shared_ptr config = monero_wallet_config::deserialize(config_json); + config->m_path = std::string(""); + monero_wallet* wallet = monero_wallet_keys::create_wallet_random(*config); callback((int) wallet); // callback with wallet memory address } catch (exception& e) { callback(string(e.what())); } } -void monero_wasm_bridge::create_keys_wallet_from_mnemonic(int network_type, const string& mnemonic, const string& seed_offset, emscripten::val callback) { +void monero_wasm_bridge::create_keys_wallet_from_seed(const string& config_json, emscripten::val callback) { try { - monero_wallet* wallet = monero_wallet_keys::create_wallet_from_mnemonic(static_cast(network_type), mnemonic, seed_offset); + shared_ptr config = monero_wallet_config::deserialize(config_json); + config->m_path = std::string(""); + monero_wallet* wallet = monero_wallet_keys::create_wallet_from_seed(*config); callback((int) wallet); // callback with wallet memory address } catch (exception& e) { callback(string(e.what())); } } -void monero_wasm_bridge::create_keys_wallet_from_keys(int network_type, const string& address, const string& view_key, const string& spend_key, const string& language, emscripten::val callback) { +void monero_wasm_bridge::create_keys_wallet_from_keys(const string& config_json, emscripten::val callback) { try { - monero_wallet* wallet = monero_wallet_keys::create_wallet_from_keys(static_cast(network_type), address, view_key, spend_key); + shared_ptr config = monero_wallet_config::deserialize(config_json); + config->m_path = std::string(""); + monero_wallet* wallet = monero_wallet_keys::create_wallet_from_keys(*config); callback((int) wallet); // callback with wallet memory address } catch (exception& e) { callback(string(e.what())); } } -string monero_wasm_bridge::get_keys_wallet_mnemonic_languages() { +string monero_wasm_bridge::get_keys_wallet_seed_languages() { rapidjson::Document doc; doc.SetObject(); - doc.AddMember("languages", monero_utils::to_rapidjson_val(doc.GetAllocator(), monero_wallet_keys::get_mnemonic_languages()), doc.GetAllocator()); + doc.AddMember("languages", monero_utils::to_rapidjson_val(doc.GetAllocator(), monero_wallet_keys::get_seed_languages()), doc.GetAllocator()); return monero_utils::serialize(doc); } @@ -230,9 +248,9 @@ bool monero_wasm_bridge::is_view_only(int handle) { return wallet->is_view_only(); } -void monero_wasm_bridge::set_daemon_connection(int handle, const string& uri, const string& username, const string& password, emscripten::val callback) { +void monero_wasm_bridge::set_daemon_connection(int handle, const string& uri, const string& username, const string& password, const string& proxy_uri, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - wallet->set_daemon_connection(uri, username, password); + wallet->set_daemon_connection(uri, username, password, proxy_uri); callback(); } @@ -242,9 +260,9 @@ string monero_wasm_bridge::get_daemon_connection(int handle) { return daemon_connection == boost::none ? "" : daemon_connection.get().serialize(); } -void monero_wasm_bridge::is_connected(int handle, emscripten::val callback) { +void monero_wasm_bridge::is_connected_to_daemon(int handle, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - callback((bool) wallet->is_connected()); + callback((bool) wallet->is_connected_to_daemon()); } void monero_wasm_bridge::get_daemon_max_peer_height(int handle, emscripten::val callback) { @@ -262,34 +280,58 @@ string monero_wasm_bridge::get_version(int handle) { return wallet->get_version().serialize(); } -string monero_wasm_bridge::get_mnemonic(int handle) { +string monero_wasm_bridge::get_seed(int handle) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->get_mnemonic(); + try { + return wallet->get_seed(); + } catch (exception& e) { + return string("error: ") + string(e.what()); + } } -string monero_wasm_bridge::get_mnemonic_language(int handle) { +string monero_wasm_bridge::get_seed_language(int handle) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->get_mnemonic_language(); + try { + return wallet->get_seed_language(); + } catch (exception& e) { + return string("error: ") + string(e.what()); + } } string monero_wasm_bridge::get_public_view_key(int handle) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->get_public_view_key(); + try { + return wallet->get_public_view_key(); + } catch (exception& e) { + return string("error: ") + string(e.what()); + } } string monero_wasm_bridge::get_private_view_key(int handle) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->get_private_view_key(); + try { + return wallet->get_private_view_key(); + } catch (exception& e) { + return string("error: ") + string(e.what()); + } } string monero_wasm_bridge::get_public_spend_key(int handle) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->get_public_spend_key(); + try { + return wallet->get_public_spend_key(); + } catch (exception& e) { + return string("error: ") + string(e.what()); + } } string monero_wasm_bridge::get_private_spend_key(int handle) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->get_private_spend_key(); + try { + return wallet->get_private_spend_key(); + } catch (exception& e) { + return string("error: ") + string(e.what()); + } } string monero_wasm_bridge::get_address(int handle, const uint32_t account_idx, const uint32_t subaddress_idx) { @@ -299,20 +341,32 @@ string monero_wasm_bridge::get_address(int handle, const uint32_t account_idx, c string monero_wasm_bridge::get_address_index(int handle, const string& address) { monero_wallet* wallet = (monero_wallet*) handle; - monero_subaddress subaddress = wallet->get_address_index(address); - return subaddress.serialize(); + try { + monero_subaddress subaddress = wallet->get_address_index(address); + return subaddress.serialize(); + } catch (exception& e) { + return e.what(); + } } -string monero_wasm_bridge::get_integrated_address(int handle, const string& standardAddress, const string& payment_id) { +string monero_wasm_bridge::get_integrated_address(int handle, const string& standard_address, const string& payment_id) { monero_wallet* wallet = (monero_wallet*) handle; - monero_integrated_address integrated_address = wallet->get_integrated_address(standardAddress, payment_id); - return integrated_address.serialize(); + try { + monero_integrated_address integrated_address = wallet->get_integrated_address(standard_address, payment_id); + return integrated_address.serialize(); + } catch (exception& e) { + return string(e.what()); + } } string monero_wasm_bridge::decode_integrated_address(int handle, const string& integrated_address_str) { monero_wallet* wallet = (monero_wallet*) handle; - monero_integrated_address integrated_address = wallet->decode_integrated_address(integrated_address_str); - return integrated_address.serialize(); + try { + monero_integrated_address integrated_address = wallet->decode_integrated_address(integrated_address_str); + return integrated_address.serialize(); + } catch (exception& e) { + return string(e.what()); + } } void monero_wasm_bridge::get_height(int handle, emscripten::val callback) { @@ -349,31 +403,40 @@ int monero_wasm_bridge::get_network_type(int handle) { return (int) wallet->get_network_type(); } -long monero_wasm_bridge::get_sync_height(int handle) { +long monero_wasm_bridge::get_restore_height(int handle) { monero_wallet* wallet = (monero_wallet*) handle; - return (long) wallet->get_sync_height(); + return (long) wallet->get_restore_height(); } -void monero_wasm_bridge::set_sync_height(int handle, long sync_height) { +void monero_wasm_bridge::set_restore_height(int handle, long restore_height) { monero_wallet* wallet = (monero_wallet*) handle; - wallet->set_sync_height(sync_height); + wallet->set_restore_height(restore_height); } -int monero_wasm_bridge::set_listener(int wallet_handle, int old_listener_handle, emscripten::val on_sync_progress, emscripten::val on_new_block, emscripten::val on_balances_changed, emscripten::val on_output_received, emscripten::val on_output_spent) { +void monero_wasm_bridge::set_listener(int wallet_handle, int old_listener_handle, emscripten::val callback, emscripten::val on_sync_progress, emscripten::val on_new_block, emscripten::val on_balances_changed, emscripten::val on_output_received, emscripten::val on_output_spent) { monero_wallet* wallet = (monero_wallet*) wallet_handle; + try { - // remove old listener - wallet_wasm_listener* old_listener = (wallet_wasm_listener*) old_listener_handle; - if (old_listener != nullptr) { - wallet->remove_listener(*old_listener); - delete old_listener; - } + // remove old listener + wallet_wasm_listener* old_listener = (wallet_wasm_listener*) old_listener_handle; + if (old_listener != nullptr) { + wallet->remove_listener(*old_listener); + delete old_listener; + } - // add new listener - if (on_sync_progress == emscripten::val::undefined()) return 0; - wallet_wasm_listener* listener = new wallet_wasm_listener(on_sync_progress, on_new_block, on_balances_changed, on_output_received, on_output_spent); - wallet->add_listener(*listener); - return (int) listener; + // done if listeners not given + if (on_sync_progress == emscripten::val::undefined()) { + callback(0); + return; + } + + // add new listener + wallet_wasm_listener* listener = new wallet_wasm_listener(on_sync_progress, on_new_block, on_balances_changed, on_output_received, on_output_spent); + wallet->add_listener(*listener); + callback((int) listener); + } catch (exception& e) { + callback(string(e.what())); + } } void monero_wasm_bridge::sync(int handle, long start_height, emscripten::val callback) { @@ -397,6 +460,28 @@ void monero_wasm_bridge::rescan_spent(int handle, emscripten::val callback) { callback(); } +void monero_wasm_bridge::scan_txs(int handle, const string& args, emscripten::val callback) { + monero_wallet* wallet = (monero_wallet*) handle; + try { + + // deserialize args to property tree + std::istringstream iss = std::istringstream(args); + boost::property_tree::ptree node; + boost::property_tree::read_json(iss, node); + + // get tx hashes from args + vector tx_hashes; + boost::property_tree::ptree tx_hashes_node = node.get_child("txHashes"); + for (const auto& child : tx_hashes_node) tx_hashes.push_back(child.second.get_value()); + + // scan txs + wallet->scan_txs(tx_hashes); + callback(); + } catch (exception& e) { + callback(string(e.what())); + } +} + void monero_wasm_bridge::rescan_blockchain(int handle, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; wallet->rescan_blockchain(); @@ -527,85 +612,65 @@ string monero_wasm_bridge::create_subaddress(int handle, const uint32_t account_ return subaddress.serialize(); } +void monero_wasm_bridge::set_subaddress_label(int handle, const uint32_t account_idx, const uint32_t subaddress_idx, const string& label) { + monero_wallet* wallet = (monero_wallet*) handle; + wallet->set_subaddress_label(account_idx, subaddress_idx, label); +} + void monero_wasm_bridge::get_txs(int handle, const string& tx_query_json, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; + try { - // deserialize tx query string - shared_ptr tx_query = monero_tx_query::deserialize_from_block(tx_query_json); + // deserialize tx query string + shared_ptr tx_query = monero_tx_query::deserialize_from_block(tx_query_json); - // get txs - vector missing_tx_hashes; - vector> txs = wallet->get_txs(*tx_query, missing_tx_hashes); + // get txs + vector> txs = wallet->get_txs(*tx_query); - // collect unique blocks to preserve model relationships as trees - shared_ptr unconfirmed_block = nullptr; // placeholder to store unconfirmed txs in return json - vector> blocks; - unordered_set> seen_block_ptrs; - for (const shared_ptr& tx : txs) { - if (tx->m_block == boost::none) { - if (unconfirmed_block == nullptr) unconfirmed_block = make_shared(); - tx->m_block = unconfirmed_block; - unconfirmed_block->m_txs.push_back(tx); - } - unordered_set>::const_iterator got = seen_block_ptrs.find(tx->m_block.get()); - if (got == seen_block_ptrs.end()) { - seen_block_ptrs.insert(tx->m_block.get()); - blocks.push_back(tx->m_block.get()); - } - } - - // wrap and serialize blocks - rapidjson::Document doc; - doc.SetObject(); - doc.AddMember("blocks", monero_utils::to_rapidjson_val(doc.GetAllocator(), blocks), doc.GetAllocator()); - if (!missing_tx_hashes.empty()) doc.AddMember("missingTxHashes", monero_utils::to_rapidjson_val(doc.GetAllocator(), missing_tx_hashes), doc.GetAllocator()); - callback(monero_utils::serialize(doc)); + // wrap and serialize blocks + vector> blocks = monero_utils::get_blocks_from_txs(txs); + rapidjson::Document doc; + doc.SetObject(); + doc.AddMember("blocks", monero_utils::to_rapidjson_val(doc.GetAllocator(), blocks), doc.GetAllocator()); + callback(monero_utils::serialize(doc)); - // free memory - monero_utils::free(blocks); + // free memory + monero_utils::free(blocks); + monero_utils::free(tx_query); + } catch (exception& e) { + callback(string(e.what())); + } } void monero_wasm_bridge::get_transfers(int handle, const string& transfer_query_json, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; + try { - // deserialize transfer query - shared_ptr transfer_query = monero_transfer_query::deserialize_from_block(transfer_query_json); - -// // log query -// if (transfer_query->m_tx_query != boost::none) { -// if ((*transfer_query->m_tx_query)->m_block == boost::none) cout << "Transfer query's tx query rooted at [tx]:" << (*transfer_query->m_tx_query)->serialize() << endl; -// else cout << "Transfer query's tx query rooted at [block]: " << (*(*transfer_query->m_tx_query)->m_block)->serialize() << endl; -// } else cout << "Transfer query: " << transfer_query->serialize() << endl; - - // get transfers - vector> transfers = wallet->get_transfers(*transfer_query); - - // collect unique blocks to preserve model relationships as tree - shared_ptr unconfirmed_block = nullptr; // placeholder to store unconfirmed txs in return json - vector> blocks; - unordered_set> seen_block_ptrs; - for (auto const& transfer : transfers) { - shared_ptr tx = transfer->m_tx; - if (tx->m_block == boost::none) { - if (unconfirmed_block == nullptr) unconfirmed_block = make_shared(); - tx->m_block = unconfirmed_block; - unconfirmed_block->m_txs.push_back(tx); - } - unordered_set>::const_iterator got = seen_block_ptrs.find(tx->m_block.get()); - if (got == seen_block_ptrs.end()) { - seen_block_ptrs.insert(tx->m_block.get()); - blocks.push_back(tx->m_block.get()); - } - } + // deserialize transfer query + shared_ptr transfer_query = monero_transfer_query::deserialize_from_block(transfer_query_json); - // wrap and serialize blocks - rapidjson::Document doc; - doc.SetObject(); - doc.AddMember("blocks", monero_utils::to_rapidjson_val(doc.GetAllocator(), blocks), doc.GetAllocator()); - callback(monero_utils::serialize(doc)); + // // log query + // if (transfer_query->m_tx_query != boost::none) { + // if ((*transfer_query->m_tx_query)->m_block == boost::none) cout << "Transfer query's tx query rooted at [tx]:" << (*transfer_query->m_tx_query)->serialize() << endl; + // else cout << "Transfer query's tx query rooted at [block]: " << (*(*transfer_query->m_tx_query)->m_block)->serialize() << endl; + // } else cout << "Transfer query: " << transfer_query->serialize() << endl; + + // get transfers + vector> transfers = wallet->get_transfers(*transfer_query); - // free memory - monero_utils::free(blocks); + // wrap and serialize blocks + vector> blocks = monero_utils::get_blocks_from_transfers(transfers); + rapidjson::Document doc; + doc.SetObject(); + doc.AddMember("blocks", monero_utils::to_rapidjson_val(doc.GetAllocator(), blocks), doc.GetAllocator()); + callback(monero_utils::serialize(doc)); + + // free memory + monero_utils::free(blocks); + monero_utils::free(transfer_query->m_tx_query.get()); + } catch (exception& e) { + callback(string(e.what())); + } } // emscripten::function("get_incoming_transfers", &monero_wasm_bridge::TODO); @@ -613,65 +678,112 @@ void monero_wasm_bridge::get_transfers(int handle, const string& transfer_query_ void monero_wasm_bridge::get_outputs(int handle, const string& output_query_json, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; + try { - // deserialize output query - shared_ptr output_query = monero_output_query::deserialize_from_block(output_query_json); + // deserialize output query + shared_ptr output_query = monero_output_query::deserialize_from_block(output_query_json); - // get outputs - vector> outputs = wallet->get_outputs(*output_query); + // get outputs + vector> outputs = wallet->get_outputs(*output_query); - // collect unique blocks to preserve model relationships as tree - vector> blocks; - unordered_set> seen_block_ptrs; - for (auto const& output : outputs) { - shared_ptr tx = static_pointer_cast(output->m_tx); - if (tx->m_block == boost::none) throw runtime_error("Need to handle unconfirmed output"); - unordered_set>::const_iterator got = seen_block_ptrs.find(*tx->m_block); - if (got == seen_block_ptrs.end()) { - seen_block_ptrs.insert(tx->m_block.get()); - blocks.push_back(tx->m_block.get()); - } - } - - // wrap and serialize blocks - rapidjson::Document doc; - doc.SetObject(); - doc.AddMember("blocks", monero_utils::to_rapidjson_val(doc.GetAllocator(), blocks), doc.GetAllocator()); - callback(monero_utils::serialize(doc)); + // wrap and serialize blocks + vector> blocks = monero_utils::get_blocks_from_outputs(outputs); + rapidjson::Document doc; + doc.SetObject(); + doc.AddMember("blocks", monero_utils::to_rapidjson_val(doc.GetAllocator(), blocks), doc.GetAllocator()); + callback(monero_utils::serialize(doc)); - // free memory - monero_utils::free(blocks); + // free memory + monero_utils::free(blocks); + monero_utils::free(output_query->m_tx_query.get()); + } catch (exception& e) { + callback(string(e.what())); + } } -void monero_wasm_bridge::get_outputs_hex(int handle, emscripten::val callback) { +void monero_wasm_bridge::export_outputs(int handle, bool all, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - callback(wallet->get_outputs_hex()); + try { + callback(wallet->export_outputs(all)); + } catch (exception& e) { + callback(string(e.what())); + } } -void monero_wasm_bridge::import_outputs_hex(int handle, const string& outputs_hex, emscripten::val callback) { +void monero_wasm_bridge::import_outputs(int handle, const string& outputs_hex, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - callback(wallet->import_outputs_hex(outputs_hex)); + try { + callback(wallet->import_outputs(outputs_hex)); + } catch (exception& e) { + callback(string(e.what())); + } } -void monero_wasm_bridge::get_key_images(int handle, emscripten::val callback) { +void monero_wasm_bridge::export_key_images(int handle, bool all, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - vector> key_images = wallet->get_key_images(); + try { + vector> key_images = wallet->export_key_images(all); - // wrap and serialize key images - rapidjson::Document doc; - doc.SetObject(); - doc.AddMember("keyImages", monero_utils::to_rapidjson_val(doc.GetAllocator(), key_images), doc.GetAllocator()); - callback(monero_utils::serialize(doc)); + // wrap and serialize key images + rapidjson::Document doc; + doc.SetObject(); + doc.AddMember("keyImages", monero_utils::to_rapidjson_val(doc.GetAllocator(), key_images), doc.GetAllocator()); + callback(monero_utils::serialize(doc)); + } catch (exception& e) { + callback(string(e.what())); + } } void monero_wasm_bridge::import_key_images(int handle, const string& key_images_str, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - vector> key_images = monero_key_image::deserialize_key_images(key_images_str); - callback(wallet->import_key_images(key_images)->serialize()); + try { + vector> key_images = monero_key_image::deserialize_key_images(key_images_str); + callback(wallet->import_key_images(key_images)->serialize()); + } catch (exception& e) { + callback(string(e.what())); + } } // emscripten::function("get_new_key_images_from_last_import", &monero_wasm_bridge::get_new_key_images_from_last_import); +void monero_wasm_bridge::freeze_output(int handle, const string& key_image, emscripten::val callback) { + monero_wallet* wallet = (monero_wallet*) handle; + try { + wallet->freeze_output(key_image); + callback(); + } catch (exception& e) { + callback(string(e.what())); + } +} + +void monero_wasm_bridge::thaw_output(int handle, const string& key_image, emscripten::val callback) { + monero_wallet* wallet = (monero_wallet*) handle; + try { + wallet->thaw_output(key_image); + callback(); + } catch (exception& e) { + callback(string(e.what())); + } +} + +void monero_wasm_bridge::is_output_frozen(int handle, const string& key_image, emscripten::val callback) { + monero_wallet* wallet = (monero_wallet*) handle; + try { + callback(wallet->is_output_frozen(key_image)); + } catch (exception& e) { + callback(string(e.what())); + } +} + +void monero_wasm_bridge::get_default_fee_priority(int handle, emscripten::val callback) { + monero_wallet* wallet = (monero_wallet*) handle; + try { + callback(static_cast(wallet->get_default_fee_priority())); + } catch (exception& e) { + callback(string(e.what())); + } +} + void monero_wasm_bridge::create_txs(int handle, const string& config_json, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; try { @@ -683,7 +795,9 @@ void monero_wasm_bridge::create_txs(int handle, const string& config_json, emscr vector> txs = wallet->create_txs(*config); // serialize and return tx set - callback(txs[0]->m_tx_set.get()->serialize()); + string tx_set_json = txs[0]->m_tx_set.get()->serialize(); + monero_utils::free(txs); + callback(tx_set_json); } catch (exception& e) { callback(string(e.what())); } @@ -700,7 +814,9 @@ void monero_wasm_bridge::sweep_output(int handle, const string& config_json, ems shared_ptr tx = wallet->sweep_output(*config); // serialize and return tx set - callback(tx->m_tx_set.get()->serialize()); + string tx_set_json = tx->m_tx_set.get()->serialize(); + monero_utils::free(tx); + callback(tx_set_json); } catch (exception& e) { callback(string(e.what())); } @@ -728,7 +844,11 @@ void monero_wasm_bridge::sweep_unlocked(int handle, const string& config_json, e rapidjson::Document doc; doc.SetObject(); doc.AddMember("txSets", monero_utils::to_rapidjson_val(doc.GetAllocator(), tx_sets), doc.GetAllocator()); - callback(monero_utils::serialize(doc)); + string tx_sets_json = monero_utils::serialize(doc); + + // free and return + monero_utils::free(txs); + callback(tx_sets_json); } catch (exception& e) { callback(string(e.what())); } @@ -738,9 +858,9 @@ void monero_wasm_bridge::sweep_dust(int handle, bool relay, emscripten::val call monero_wallet* wallet = (monero_wallet*) handle; try { vector> txs = wallet->sweep_dust(relay); - - // serialize and return tx set - callback(txs[0]->m_tx_set.get()->serialize()); + string tx_set_json = txs.empty() ? string("{}") : txs[0]->m_tx_set.get()->serialize(); + monero_utils::free(txs); + callback(tx_set_json); } catch (exception& e) { callback(string(e.what())); } @@ -773,37 +893,47 @@ void monero_wasm_bridge::relay_txs(int handle, const string& args, emscripten::v } } -string monero_wasm_bridge::parse_tx_set(int handle, const string& tx_set_str) { +string monero_wasm_bridge::describe_tx_set(int handle, const string& tx_set_str) { monero_wallet* wallet = (monero_wallet*) handle; monero_tx_set tx_set = monero_tx_set::deserialize(tx_set_str); - monero_tx_set parsed_tx_set = wallet->parse_tx_set(tx_set); - return parsed_tx_set.serialize(); + monero_tx_set described_tx_set = wallet->describe_tx_set(tx_set); + std::string monero_tx_set_json = described_tx_set.serialize(); + monero_utils::free(described_tx_set.m_txs); + return monero_tx_set_json; } string monero_wasm_bridge::sign_txs(int handle, const string& unsigned_tx_hex) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->sign_txs(unsigned_tx_hex); + monero_tx_set signed_tx_set = wallet->sign_txs(unsigned_tx_hex); + std::string monero_tx_set_json = signed_tx_set.serialize(); + monero_utils::free(signed_tx_set.m_txs); + return monero_tx_set_json; } void monero_wasm_bridge::submit_txs(int handle, const string& signed_tx_hex, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - vector tx_hashes = wallet->submit_txs(signed_tx_hex); + try { + vector tx_hashes = wallet->submit_txs(signed_tx_hex); - // wrap and serialize tx hashes - rapidjson::Document doc; - doc.SetObject(); - doc.AddMember("txHashes", monero_utils::to_rapidjson_val(doc.GetAllocator(), tx_hashes), doc.GetAllocator()); - callback(monero_utils::serialize(doc)); + // wrap and serialize tx hashes + rapidjson::Document doc; + doc.SetObject(); + doc.AddMember("txHashes", monero_utils::to_rapidjson_val(doc.GetAllocator(), tx_hashes), doc.GetAllocator()); + callback(monero_utils::serialize(doc)); + } catch (exception& e) { + callback(string(e.what())); + } } -string monero_wasm_bridge::sign_message(int handle, const string& msg) { +string monero_wasm_bridge::sign_message(int handle, const string& msg, uint32_t signature_type_num, uint32_t account_idx, uint32_t subaddress_idx) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->sign_message(msg); + monero_message_signature_type signature_type = signature_type_num == 0 ? monero_message_signature_type::SIGN_WITH_SPEND_KEY : monero_message_signature_type::SIGN_WITH_VIEW_KEY; + return wallet->sign_message(msg, signature_type, account_idx, subaddress_idx); } -bool monero_wasm_bridge::verify_message(int handle, const string& msg, const string& address, const string& signature) { +string monero_wasm_bridge::verify_message(int handle, const string& msg, const string& address, const string& signature) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->verify_message(msg, address, signature); + return wallet->verify_message(msg, address, signature).serialize(); } string monero_wasm_bridge::get_tx_key(int handle, const string& tx_hash) { @@ -811,47 +941,79 @@ string monero_wasm_bridge::get_tx_key(int handle, const string& tx_hash) { return wallet->get_tx_key(tx_hash); } -string monero_wasm_bridge::check_tx_key(int handle, const string& tx_hash, const string& tx_key, const string& address) { +void monero_wasm_bridge::check_tx_key(int handle, const string& tx_hash, const string& tx_key, const string& address, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->check_tx_key(tx_hash, tx_key, address)->serialize(); + try { + callback(wallet->check_tx_key(tx_hash, tx_key, address)->serialize()); + } catch (exception& e) { + callback(string(e.what())); + } } -string monero_wasm_bridge::get_tx_proof(int handle, const string& tx_hash, const string& address, const string& message) { +void monero_wasm_bridge::get_tx_proof(int handle, const string& tx_hash, const string& address, const string& message, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->get_tx_proof(tx_hash, address, message); + try { + callback(wallet->get_tx_proof(tx_hash, address, message)); + } catch (exception& e) { + callback(string("error: ") + string(e.what())); // indicate error with prefix + } } -string monero_wasm_bridge::check_tx_proof(int handle, const string& tx_hash, const string& address, const string& message, const string& signature) { +void monero_wasm_bridge::check_tx_proof(int handle, const string& tx_hash, const string& address, const string& message, const string& signature, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->check_tx_proof(tx_hash, address, message, signature)->serialize(); + try { + callback(wallet->check_tx_proof(tx_hash, address, message, signature)->serialize()); + } catch (exception& e) { + callback(string(e.what())); + } } -string monero_wasm_bridge::get_spend_proof(int handle, const string& tx_hash, const string& message) { +void monero_wasm_bridge::get_spend_proof(int handle, const string& tx_hash, const string& message, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->get_spend_proof(tx_hash, message); + try { + callback(wallet->get_spend_proof(tx_hash, message)); + } catch (exception& e) { + callback(string("error: ") + string(e.what())); + } } -bool monero_wasm_bridge::check_spend_proof(int handle, const string& tx_hash, const string& message, const string& signature) { +void monero_wasm_bridge::check_spend_proof(int handle, const string& tx_hash, const string& message, const string& signature, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->check_spend_proof(tx_hash, message, signature); + try { + callback(wallet->check_spend_proof(tx_hash, message, signature)); + } catch (exception& e) { + callback(string(e.what())); + } } -string monero_wasm_bridge::get_reserve_proof_wallet(int handle, const string& message) { +void monero_wasm_bridge::get_reserve_proof_wallet(int handle, const string& message, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->get_reserve_proof_wallet(message); + try { + callback(wallet->get_reserve_proof_wallet(message)); + } catch (exception& e) { + callback(string("error: ") + string(e.what())); + } } -string monero_wasm_bridge::get_reserve_proof_account(int handle, uint32_t account_idx, const string& amount_str, const string& message) { +void monero_wasm_bridge::get_reserve_proof_account(int handle, uint32_t account_idx, const string& amount_str, const string& message, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - std::stringstream sstr(amount_str); - uint64_t amount; - sstr >> amount; - return wallet->get_reserve_proof_account(account_idx, amount, message); + try { + std::stringstream sstr(amount_str); + uint64_t amount; + sstr >> amount; + callback(wallet->get_reserve_proof_account(account_idx, amount, message)); + } catch (exception& e) { + callback(string("error: ") + string(e.what())); + } } -string monero_wasm_bridge::check_reserve_proof(int handle, const string& address, const string& message, const string& signature) { +void monero_wasm_bridge::check_reserve_proof(int handle, const string& address, const string& message, const string& signature, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->check_reserve_proof(address, message, signature)->serialize(); + try { + callback(wallet->check_reserve_proof(address, message, signature)->serialize()); + } catch (exception& e) { + callback(string(e.what())); + } } string monero_wasm_bridge::get_tx_notes(int handle, const string& args) { @@ -957,10 +1119,10 @@ void monero_wasm_bridge::set_account_tag_label(int handle, const string& tag, co throw runtime_error("Not implemented"); } -string monero_wasm_bridge::create_payment_uri(int handle, const string& config_json) { +string monero_wasm_bridge::get_payment_uri(int handle, const string& config_json) { monero_wallet* wallet = (monero_wallet*) handle; shared_ptr config = monero_tx_config::deserialize(config_json); - return wallet->create_payment_uri(*config); + return wallet->get_payment_uri(*config); } string monero_wasm_bridge::parse_payment_uri(int handle, const string& uri) { @@ -995,51 +1157,58 @@ string monero_wasm_bridge::prepare_multisig(int handle) { return wallet->prepare_multisig(); } -string monero_wasm_bridge::make_multisig(int handle, const string& args) { +void monero_wasm_bridge::make_multisig(int handle, const string& args, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; + try { - // deserialize args to property tree - std::istringstream iss = std::istringstream(args); - boost::property_tree::ptree node; - boost::property_tree::read_json(iss, node); + // deserialize args to property tree + std::istringstream iss = std::istringstream(args); + boost::property_tree::ptree node; + boost::property_tree::read_json(iss, node); - // get multisig hexes from args - vector multisig_hexes; - boost::property_tree::ptree multisig_hexes_node = node.get_child("multisigHexes"); - for (const auto& child : multisig_hexes_node) multisig_hexes.push_back(child.second.get_value()); + // get multisig hexes from args + vector multisig_hexes; + boost::property_tree::ptree multisig_hexes_node = node.get_child("multisigHexes"); + for (const auto& child : multisig_hexes_node) multisig_hexes.push_back(child.second.get_value()); - // get threshold and password from args - int threshold = node.get_child("threshold").get_value(); - string password = node.get_child("password").get_value(); + // get threshold and password from args + int threshold = node.get_child("threshold").get_value(); + string password = node.get_child("password").get_value(); - // make multisig - return wallet->make_multisig(multisig_hexes, threshold, password).serialize(); + // make multisig + callback(wallet->make_multisig(multisig_hexes, threshold, password)); + } catch (exception& e) { + callback(string("error: ") + string(e.what())); // indicate error with prefix + } } -string monero_wasm_bridge::exchange_multisig_keys(int handle, const string& args) { - +void monero_wasm_bridge::exchange_multisig_keys(int handle, const string& args, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; + try { - // deserialize args to property tree - std::istringstream iss = std::istringstream(args); - boost::property_tree::ptree node; - boost::property_tree::read_json(iss, node); + // deserialize args to property tree + std::istringstream iss = std::istringstream(args); + boost::property_tree::ptree node; + boost::property_tree::read_json(iss, node); - // get multisig hexes from args - vector multisig_hexes; - boost::property_tree::ptree multisig_hexes_node = node.get_child("multisigHexes"); - for (const auto& child : multisig_hexes_node) multisig_hexes.push_back(child.second.get_value()); + // get multisig hexes from args + vector multisig_hexes; + boost::property_tree::ptree multisig_hexes_node = node.get_child("multisigHexes"); + for (const auto& child : multisig_hexes_node) multisig_hexes.push_back(child.second.get_value()); - // get password from args - string password = node.get_child("password").get_value(); + // get password from args + string password = node.get_child("password").get_value(); - // exchange multisig keys - return wallet->exchange_multisig_keys(multisig_hexes, password).serialize(); + // exchange multisig keys + callback(wallet->exchange_multisig_keys(multisig_hexes, password).serialize()); + } catch (exception& e) { + callback(string("error: ") + string(e.what())); // indicate error with prefix + } } -string monero_wasm_bridge::get_multisig_hex(int handle) { +string monero_wasm_bridge::export_multisig_hex(int handle) { monero_wallet* wallet = (monero_wallet*) handle; - return wallet->get_multisig_hex(); + return wallet->export_multisig_hex(); } void monero_wasm_bridge::import_multisig_hex(int handle, const string& args, emscripten::val callback) { @@ -1063,30 +1232,48 @@ void monero_wasm_bridge::import_multisig_hex(int handle, const string& args, ems } } -string monero_wasm_bridge::sign_multisig_tx_hex(int handle, const string& multisig_tx_hex) { - monero_wallet* wallet = (monero_wallet*) handle; - monero_multisig_sign_result result = wallet->sign_multisig_tx_hex(multisig_tx_hex); - return result.serialize(); +void monero_wasm_bridge::sign_multisig_tx_hex(int handle, const string& multisig_tx_hex, emscripten::val callback) { + try { + monero_wallet* wallet = (monero_wallet*) handle; + monero_multisig_sign_result result = wallet->sign_multisig_tx_hex(multisig_tx_hex); + callback(result.serialize()); + } catch (exception& e) { + callback(string(e.what())); + } } void monero_wasm_bridge::submit_multisig_tx_hex(int handle, const string& signed_multisig_tx_hex, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; - vector tx_hashes = wallet->submit_multisig_tx_hex(signed_multisig_tx_hex); + try { + vector tx_hashes = wallet->submit_multisig_tx_hex(signed_multisig_tx_hex); - // wrap and serialize tx hashes - rapidjson::Document doc; - doc.SetObject(); - doc.AddMember("txHashes", monero_utils::to_rapidjson_val(doc.GetAllocator(), tx_hashes), doc.GetAllocator()); - callback(monero_utils::serialize(doc)); + // wrap and serialize tx hashes + rapidjson::Document doc; + doc.SetObject(); + doc.AddMember("txHashes", monero_utils::to_rapidjson_val(doc.GetAllocator(), tx_hashes), doc.GetAllocator()); + callback(monero_utils::serialize(doc)); + } catch (exception& e) { + callback(string(e.what())); + } +} + +void monero_wasm_bridge::change_wallet_password(int handle, const string& old_password, const string& new_password, emscripten::val callback) { + monero_wallet* wallet = (monero_wallet*) handle; + try { + wallet->change_password(old_password, new_password); + callback(); + } catch (exception& e) { + callback(string(e.what())); + } } void monero_wasm_bridge::close(int handle, bool save, emscripten::val callback) { monero_wallet* wallet = (monero_wallet*) handle; // TODO: ensure http clients are being deleted -// // if core wallet, disconnect and delete http client -// monero_wallet_core* wallet_core = dynamic_cast(wallet); -// if (core_wallet != nullptr) delete wallet_core->m_http_client; +// // if full wallet, disconnect and delete http client +// monero_wallet_full* wallet_full = dynamic_cast(wallet); +// if (full_wallet != nullptr) delete wallet_full->m_http_client; if (save) wallet->save(); delete wallet; @@ -1095,9 +1282,9 @@ void monero_wasm_bridge::close(int handle, bool save, emscripten::val callback) } string monero_wasm_bridge::get_keys_file_buffer(int handle, string password, bool view_only) { -#if defined BUILD_CORE_WALLET +#if defined BUILD_WALLET_FULL // get wallet - monero_wallet_core* wallet = (monero_wallet_core*) handle; + monero_wallet_full* wallet = (monero_wallet_full*) handle; // get keys buffer string keys_buf = wallet->get_keys_file_buffer(password, view_only); @@ -1113,17 +1300,17 @@ string monero_wasm_bridge::get_keys_file_buffer(int handle, string password, boo doc.AddMember("length", rapidjson::Value().SetUint64(keys_buf_ptr->length()), doc.GetAllocator()); return monero_utils::serialize(doc); #else - throw runtime_error("monero_wallet_core not built"); + throw runtime_error("monero_wallet_full not built"); #endif } -string monero_wasm_bridge::get_cache_file_buffer(int handle, string password) { -#if defined BUILD_CORE_WALLET +string monero_wasm_bridge::get_cache_file_buffer(int handle) { +#if defined BUILD_WALLET_FULL // get wallet - monero_wallet_core* wallet = (monero_wallet_core*) handle; + monero_wallet_full* wallet = (monero_wallet_full*) handle; // get cache buffer - string cache_buf = wallet->get_cache_file_buffer(password); + string cache_buf = wallet->get_cache_file_buffer(); // copy cache buffer to heap and keep pointer std::string* cache_buf_ptr = new std::string(cache_buf.c_str(), cache_buf.length()); @@ -1136,6 +1323,6 @@ string monero_wasm_bridge::get_cache_file_buffer(int handle, string password) { doc.AddMember("length", rapidjson::Value().SetUint64(cache_buf_ptr->length()), doc.GetAllocator()); return monero_utils::serialize(doc); #else - throw runtime_error("monero_wallet_core not built"); + throw runtime_error("monero_wallet_full not built"); #endif } diff --git a/src/main/cpp/monero_wasm_bridge.h b/src/main/cpp/monero_wasm_bridge.h index 82ac64853..a5333d99b 100644 --- a/src/main/cpp/monero_wasm_bridge.h +++ b/src/main/cpp/monero_wasm_bridge.h @@ -10,38 +10,47 @@ using namespace std; using namespace emscripten; +// override tools::dns_utils::get_account_address_as_str_from_url() so error caught when sending to invalid address +namespace tools { + namespace dns_utils { + std::string get_account_address_as_str_from_url(const std::string& url, bool& dnssec_valid, std::function&, bool)> dns_confirm); + } +} + namespace monero_wasm_bridge { // ------------------------------ UTILITIES --------------------------------- - string malloc_binary_from_json(const string &args_string); - string binary_to_json(const string &args_string); - string binary_blocks_to_json(const string &args_string); + void set_log_level(int level); + string get_integrated_address_util(int network_type, const string& standard_address, const string& payment_id); + string validate_address(const string& address, int network_type); + string get_exception_message(int exception_ptr); + string malloc_binary_from_json(const string& args_string); + string binary_to_json(const string& args_string); + string binary_blocks_to_json(const string& args_string); // ------------------------- STATIC WALLET UTILS ---------------------------- - void open_core_wallet(const string& password, int network_type, const string& keys_data, const string& cache_data, const string& daemon_uri, const string& daemon_username, const string& daemon_password, const string& reject_unauthorized_fn_id, emscripten::val callback); - void create_core_wallet_random(const string& password, int network_type, const string& daemon_uri, const string& daemon_username, const string& daemon_password, const string& reject_unauthorized_fn_id, const string& language, emscripten::val callback); - void create_core_wallet_from_mnemonic(const string& password, int network_type, const string& mnemonic, const string& daemon_uri, const string& daemon_username, const string& daemon_password, const string& reject_unauthorized_fn_id, long restore_height, const string& seed_offset, emscripten::val callback); - void create_core_wallet_from_keys(const string& password, int network_type, const string& address, const string& view_key, const string& spend_key, const string& daemon_uri, const string& daemon_username, const string& daemon_password, const string& reject_unauthorized_fn_id, long restore_height, const string& language, emscripten::val callback); - string get_core_wallet_mnemonic_languages(); + void open_wallet_full(const string& password, int network_type, const string& keys_data, const string& cache_data, const string& daemon_uri, const string& daemon_username, const string& daemon_password, const string& reject_unauthorized_fn_id, emscripten::val callback); + void create_full_wallet(const string& config_json, const string& reject_unauthorized_fn_id, emscripten::val callback); + string get_full_wallet_seed_languages(); - void create_keys_wallet_random(int network_type, const string& language, emscripten::val callback); - void create_keys_wallet_from_mnemonic(int network_type, const string& mnemonic, const string& seed_offset, emscripten::val callback); - void create_keys_wallet_from_keys(int network_type, const string& address, const string& view_key, const string& spend_key, const string& language, emscripten::val callback); - string get_keys_wallet_mnemonic_languages(); + void create_keys_wallet_random(const string& config_json, emscripten::val callback); + void create_keys_wallet_from_seed(const string& config_json, emscripten::val callback); + void create_keys_wallet_from_keys(const string& config_json, emscripten::val callback); + string get_keys_wallet_seed_languages(); // ----------------------- WALLET INSTANCE METHODS -------------------------- bool is_view_only(int handle); - void set_daemon_connection(int handle, const string& uri, const string& username, const string& password, emscripten::val callback); + void set_daemon_connection(int handle, const string& uri, const string& username, const string& password, const string& proxy_uri, emscripten::val callback); string get_daemon_connection(int handle); - void is_connected(int handle, emscripten::val callback); + void is_connected_to_daemon(int handle, emscripten::val callback); void get_daemon_max_peer_height(int handle, emscripten::val callback); string get_version(int handle); - string get_mnemonic(int handle); - string get_mnemonic_language(int handle); + string get_seed(int handle); + string get_seed_language(int handle); string get_public_view_key(int handle); string get_private_view_key(int handle); string get_public_spend_key(int handle); @@ -56,16 +65,17 @@ namespace monero_wasm_bridge void is_daemon_synced(int handle, emscripten::val callback); void is_synced(int handle, emscripten::val callback); int get_network_type(int handle); - long get_sync_height(int handle); - void set_sync_height(int handle, long sync_height); + long get_restore_height(int handle); + void set_restore_height(int handle, long restore_height); // long get_daemon_height(int handle); // long get_daemon_max_peer_height(int handle); //void add_listener(int handle, monero_wallet_listener& listener); //void remove_listener(int handle, monero_wallet_listener& listener); //set get_listeners(int handle); - int set_listener(int wallet_handle, int old_listener_handle, emscripten::val on_sync_progress = emscripten::val::undefined(), emscripten::val on_new_block = emscripten::val::undefined(), emscripten::val on_balances_changed = emscripten::val::undefined(), emscripten::val on_output_received = emscripten::val::undefined(), emscripten::val on_output_spent = emscripten::val::undefined()); + void set_listener(int wallet_handle, int old_listener_handle, emscripten::val callback, emscripten::val on_sync_progress = emscripten::val::undefined(), emscripten::val on_new_block = emscripten::val::undefined(), emscripten::val on_balances_changed = emscripten::val::undefined(), emscripten::val on_output_received = emscripten::val::undefined(), emscripten::val on_output_spent = emscripten::val::undefined()); void sync(int handle, long start_height, emscripten::val callback); void stop_syncing(int handle); + void scan_txs(int handle, const string& args, emscripten::val callback); void rescan_spent(int handle, emscripten::val callback); void rescan_blockchain(int handle, emscripten::val callback); string get_balance_wallet(int handle); @@ -79,33 +89,38 @@ namespace monero_wasm_bridge string create_account(int handle, const string& label); string get_subaddresses(int handle, const string& args); string create_subaddress(int handle, const uint32_t account_idx, const string& label); + void set_subaddress_label(int handle, const uint32_t account_idx, const uint32_t subaddress_idx, const string& label); void get_txs(int handle, const string& tx_query_json, emscripten::val callback); void get_transfers(int handle, const string& transfer_query_json, emscripten::val callback); void get_outputs(int handle, const string& output_query_json, emscripten::val callback); - void get_outputs_hex(int handle, emscripten::val callback); - void import_outputs_hex(int handle, const string& outputs_hex, emscripten::val callback); - void get_key_images(int handle, emscripten::val callback); + void export_outputs(int handle, bool all, emscripten::val callback); + void import_outputs(int handle, const string& outputs_hex, emscripten::val callback); + void export_key_images(int handle, bool all, emscripten::val callback); void import_key_images(int handle, const string& key_images_str, emscripten::val callback); // emscripten::function("get_new_key_images_from_last_import", &monero_wasm_bridge::get_new_key_images_from_last_import); + void freeze_output(int handle, const string& key_image, emscripten::val callback); + void thaw_output(int handle, const string& key_image, emscripten::val callback); + void is_output_frozen(int handle, const string& key_image, emscripten::val callback); + void get_default_fee_priority(int handle, emscripten::val callback); void create_txs(int handle, const string& config_json, emscripten::val callback); void sweep_output(int handle, const string& config_json, emscripten::val callback); void sweep_unlocked(int handle, const string& config_json, emscripten::val callback); void sweep_dust(int handle, bool relay, emscripten::val callback); void relay_txs(int handle, const string& args, emscripten::val callback); - string parse_tx_set(int handle, const string& tx_set_str); + string describe_tx_set(int handle, const string& tx_set_str); string sign_txs(int handle, const string& unsigned_tx_hex); void submit_txs(int handle, const string& signed_tx_hex, emscripten::val callback); - string sign_message(int handle, const string& msg); - bool verify_message(int handle, const string& msg, const string& address, const string& signature); + string sign_message(int handle, const string& msg, uint32_t signature_type_num, uint32_t account_idx, uint32_t subaddress_idx); + string verify_message(int handle, const string& msg, const string& address, const string& signature); string get_tx_key(int handle, const string& tx_hash); - string check_tx_key(int handle, const string& tx_hash, const string& tx_key, const string& address); - string get_tx_proof(int handle, const string& tx_hash, const string& address, const string& message); - string check_tx_proof(int handle, const string& tx_hash, const string& address, const string& message, const string& signature); - string get_spend_proof(int handle, const string& tx_hash, const string& message); - bool check_spend_proof(int handle, const string& tx_hash, const string& message, const string& signature); - string get_reserve_proof_wallet(int handle, const string& message); - string get_reserve_proof_account(int handle, uint32_t account_idx, const string& amount_str, const string& message); - string check_reserve_proof(int handle, const string& address, const string& message, const string& signature); + void check_tx_key(int handle, const string& tx_hash, const string& tx_key, const string& address, emscripten::val callback); + void get_tx_proof(int handle, const string& tx_hash, const string& address, const string& message, emscripten::val callback); + void check_tx_proof(int handle, const string& tx_hash, const string& address, const string& message, const string& signature, emscripten::val callback); + void get_spend_proof(int handle, const string& tx_hash, const string& message, emscripten::val callback); + void check_spend_proof(int handle, const string& tx_hash, const string& message, const string& signature, emscripten::val callback); + void get_reserve_proof_wallet(int handle, const string& message, emscripten::val callback); + void get_reserve_proof_account(int handle, uint32_t account_idx, const string& amount_str, const string& message, emscripten::val callback); + void check_reserve_proof(int handle, const string& address, const string& message, const string& signature, emscripten::val callback); string get_tx_notes(int handle, const string& args); void set_tx_notes(int handle, const string& args); string get_address_book_entries(int handle, const string& args); @@ -116,22 +131,23 @@ namespace monero_wasm_bridge void untag_accounts(int handle, const string& args); string get_account_tags(int handle); void set_account_tag_label(int handle, const string& tag, const string& label); - string create_payment_uri(int handle, const string& config_json); + string get_payment_uri(int handle, const string& config_json); string parse_payment_uri(int handle, const string& uri); string get_attribute(int handle, const string& key); void set_attribute(int handle, const string& key, const string& val); bool is_multisig_import_needed(int handle); string get_multisig_info(int handle); string prepare_multisig(int handle); - string make_multisig(int handle, const string& args); - string exchange_multisig_keys(int handle, const string& args); - string get_multisig_hex(int handle); + void make_multisig(int handle, const string& args, emscripten::val callback); + void exchange_multisig_keys(int handle, const string& args, emscripten::val callback); + string export_multisig_hex(int handle); void import_multisig_hex(int handle, const string& args, emscripten::val callback); - string sign_multisig_tx_hex(int handle, const string& multisig_tx_hex); + void sign_multisig_tx_hex(int handle, const string& multisig_tx_hex, emscripten::val callback); void submit_multisig_tx_hex(int handle, const string& signed_multisig_tx_hex, emscripten::val callback); + void change_wallet_password(int handle, const string& old_password, const string& new_password, emscripten::val callback); void close(int handle, bool save, emscripten::val callback); string get_keys_file_buffer(int handle, string password, bool view_only); - string get_cache_file_buffer(int handle, string password); + string get_cache_file_buffer(int handle); } #endif /* monero_wasm_bridge_h */ diff --git a/src/main/js/common/HttpClient.js b/src/main/js/common/HttpClient.js deleted file mode 100644 index acd953a47..000000000 --- a/src/main/js/common/HttpClient.js +++ /dev/null @@ -1,483 +0,0 @@ -const MoneroUtils = require("./MoneroUtils"); -const PromiseThrottle = require("promise-throttle"); -const Request = require("request-promise"); - -/** - * Handle HTTP requests with a uniform interface. - * - * @hideconstructor - */ -class HttpClient { - - /** - *

Make a HTTP request.

- * - * @param {object} request - configures the request to make - * @param {string} request.method - HTTP method ("GET", "PUT", "POST", "DELETE", etc) - * @param {string} request.uri - uri to request - * @param {string|object|Uint8Array} request.body - request body - * @param {string} request.username - username to authenticate the request (optional) - * @param {string} request.password - password to authenticate the request (optional) - * @param {object} request.headers - headers to add to the request (optional) - * @param {string} request.requestApi - one of "fetch" or "xhr" (default "fetch") - * @param {boolean} request.resolveWithFullResponse - return full response if true, else body only (default false) - * @param {boolean} request.rejectUnauthorized - whether or not to reject self-signed certificates (default true) - * @returns {object} response - the response object - * @returns {string|object|Uint8Array} response.body - the response body - * @returns {number} response.statusCode - the response code - * @returns {number} response.statusText - the response message - * @returns {object} response.headers - the response headers - */ - static async request(request) { - - // assign defaults - request = Object.assign(HttpClient.DEFAULT_REQUEST, request); - - // validate request - try { new URL(request.uri); } catch (e) { throw new Error("Invalid request URL: " + request.uri); } - if (request.body && !(typeof request.body === "string" || typeof request.body === "object")) { - throw new Error("Request body type is not string or object"); - } - - // initialize promise throttle one time - if (!HttpClient.PROMISE_THROTTLE) { - HttpClient.PROMISE_THROTTLE = new PromiseThrottle({ - requestsPerSecond: MoneroUtils.MAX_REQUESTS_PER_SECOND, - promiseImplementation: Promise - }); - } - - // request using fetch or xhr - return request.requestApi === "fetch" ? HttpClient._requestFetch(request) : HttpClient._requestXhr(request); - } - - // ----------------------------- PRIVATE HELPERS ---------------------------- - - static async _requestFetch(req) { - - // build request options - let opts = { - method: req.method, - uri: req.uri, - body: req.body, - agent: req.uri.startsWith("https") ? HttpClient._getHttpsAgent() : HttpClient._getHttpAgent(), - rejectUnauthorized: req.rejectUnauthorized, - resolveWithFullResponse: req.resolveWithFullResponse, - requestCert: true // TODO: part of config? - }; - if (req.username) { - opts.forever = true; - opts.auth = { - user: req.username, - pass: req.password, - sendImmediately: false - } - } - if (req.body instanceof Uint8Array) opts.encoding = null; - - // queue and throttle request to execute in serial and rate limited - let resp = await HttpClient._queueTask(async function() { - return HttpClient.PROMISE_THROTTLE.add(function(opts) { return Request(opts); }.bind(this, opts)); - }); - - // normalize response - let normalizedResponse = {}; - if (req.resolveWithFullResponse) { - normalizedResponse.statusCode = resp.statusCode; - normalizedResponse.statusText = resp.statusMessage; - normalizedResponse.headers = resp.headers; - normalizedResponse.body = resp.body; - } else { - normalizedResponse.body = resp; - } - return normalizedResponse; - } - - static async _requestXhr(req) { - if (req.headers) throw new Error("Custom headers not implemented in XHR request"); // TODO - - // collect params from request which change on await - let method = req.method; - let uri = req.uri; - let username = req.username; - let password = req.password; - let body = req.body; - let isBinary = body instanceof Uint8Array; - - // queue and throttle request to execute in serial and rate limited - let resp = await HttpClient._queueTask(async function() { - return HttpClient.PROMISE_THROTTLE.add(function() { - return new Promise(function(resolve, reject) { - let digestAuthRequest = new HttpClient.digestAuthRequest(method, uri, username, password); - digestAuthRequest.request(function(resp) { - resolve(resp); - }, function(resp) { - if (resp.status) resolve(resp); - else reject(new Error("Request failed without response: " + method + " " + uri)); - }, body); - }); - }.bind(this)); - }); - - // normalize response - let normalizedResponse = {}; - normalizedResponse.statusCode = resp.status; - normalizedResponse.statusText = resp.statusText; - normalizedResponse.headers = HttpClient._parseXhrResponseHeaders(resp.getAllResponseHeaders()); - normalizedResponse.body = isBinary ? new Uint8Array(resp.response) : resp.response; - if (normalizedResponse.body instanceof ArrayBuffer) normalizedResponse.body = new Uint8Array(normalizedResponse.body); // handle empty binary request - return normalizedResponse; - } - - /** - * Executes given tasks serially (first in, first out). - * - * @param {function} asyncFn is an asynchronous function to execute after previously given tasks - */ - static async _queueTask(asyncFn) { - - // initialize task queue one time - if (!HttpClient.TASK_QUEUE) { - const async = require("async"); - HttpClient.TASK_QUEUE = async.queue(function(asyncFn, callback) { - if (asyncFn.then) asyncFn.then(resp => { callback(resp); }).catch(err => { callback(undefined, err); }); - else asyncFn().then(resp => { callback(resp); }).catch(err => { callback(undefined, err); }); - }, 1); - } - - // return promise which resolves when task is executed - return new Promise(function(resolve, reject) { - HttpClient.TASK_QUEUE.push(asyncFn, function(resp, err) { - if (err !== undefined) reject(err); - else resolve(resp); - }); - }); - } - - /** - * Get a singleton instance of an HTTP client to share. - * - * @return {http.Agent} a shared agent for network requests among library instances - */ - static _getHttpAgent() { - if (!HttpClient.HTTP_AGENT) { - let http = require('http'); - HttpClient.HTTP_AGENT = new http.Agent({keepAlive: true}); - } - return HttpClient.HTTP_AGENT; - } - - /** - * Get a singleton instance of an HTTPS client to share. - * - * @return {https.Agent} a shared agent for network requests among library instances - */ - static _getHttpsAgent() { - if (!HttpClient.HTTPS_AGENT) { - let https = require('https'); - HttpClient.HTTPS_AGENT = new https.Agent({keepAlive: true}); - } - return HttpClient.HTTPS_AGENT; - } - - - static _parseXhrResponseHeaders(headersStr) { - let headerMap = {}; - let headers = headersStr.trim().split(/[\r\n]+/); - for (let header of headers) { - let headerVals = header.split(": "); - headerMap[headerVals[0]] = headerVals[1]; - } - return headerMap; - } -} - -// default request config -HttpClient.DEFAULT_REQUEST = { - method: "GET", - requestApi: "fetch", - resolveWithFullResponse: false, - rejectUnauthorized: true -} - -/** - * Modification of digest auth request by @inorganik. - * - * Dependent on CryptoJS MD5 hashing: http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5.js - * - * MIT licensed. - */ -HttpClient.digestAuthRequest = function(method, url, username, password) { - var self = this; - - if (typeof CryptoJS === 'undefined' && typeof require === 'function') { - var CryptoJS = require('crypto-js'); - } - - this.scheme = null; // we just echo the scheme, to allow for 'Digest', 'X-Digest', 'JDigest' etc - this.nonce = null; // server issued nonce - this.realm = null; // server issued realm - this.qop = null; // "quality of protection" - '' or 'auth' or 'auth-int' - this.response = null; // hashed response to server challenge - this.opaque = null; // hashed response to server challenge - this.nc = 1; // nonce count - increments with each request used with the same nonce - this.cnonce = null; // client nonce - - // settings - this.timeout = 60000; // timeout - this.loggingOn = false; // toggle console logging - - // determine if a post, so that request will send data - this.post = false; - if (method.toLowerCase() === 'post' || method.toLowerCase() === 'put') { - this.post = true; - } - - // start here - // successFn - will be passed JSON data - // errorFn - will be passed the failed authenticatedRequest - // data - optional, for POSTS - this.request = function(successFn, errorFn, data) { - - // stringify json - if (data) { - try { - self.data = data instanceof Uint8Array || typeof data === "string" ? data : JSON.stringify(data); - } catch (e) { - console.error(e); - throw e; - } - } - self.successFn = successFn; - self.errorFn = errorFn; - - if (!self.nonce) { - self.makeUnauthenticatedRequest(self.data); - } else { - self.makeAuthenticatedRequest(); - } - } - this.makeUnauthenticatedRequest = function(data) { - self.firstRequest = new XMLHttpRequest(); - self.firstRequest.open(method, url, true); - self.firstRequest.timeout = self.timeout; - // if we are posting, add appropriate headers - if (self.post && data) { - if (typeof data === "string") { - self.firstRequest.setRequestHeader('Content-type', 'text/plain'); - } else { - self.firstRequest.responseType = "arraybuffer"; - } - } - - self.firstRequest.onreadystatechange = function() { - - // 2: received headers, 3: loading, 4: done - if (self.firstRequest.readyState === 2) { - - var responseHeaders = self.firstRequest.getAllResponseHeaders(); - responseHeaders = responseHeaders.split('\n'); - // get authenticate header - var digestHeaders; - for(var i = 0; i < responseHeaders.length; i++) { - if (responseHeaders[i].match(/www-authenticate/i) != null) { - digestHeaders = responseHeaders[i]; - } - } - - if (digestHeaders != null) { - // parse auth header and get digest auth keys - digestHeaders = digestHeaders.slice(digestHeaders.indexOf(':') + 1, -1); - digestHeaders = digestHeaders.split(','); - self.scheme = digestHeaders[0].split(/\s/)[1]; - for (var i = 0; i < digestHeaders.length; i++) { - var equalIndex = digestHeaders[i].indexOf('='), - key = digestHeaders[i].substring(0, equalIndex), - val = digestHeaders[i].substring(equalIndex + 1); - val = val.replace(/['"]+/g, ''); - // find realm - if (key.match(/realm/i) != null) { - self.realm = val; - } - // find nonce - if (key.match(/nonce/i) != null) { - self.nonce = val; - } - // find opaque - if (key.match(/opaque/i) != null) { - self.opaque = val; - } - // find QOP - if (key.match(/qop/i) != null) { - self.qop = val; - } - } - // client generated keys - self.cnonce = self.generateCnonce(); - self.nc++; - // if logging, show headers received: - self.log('received headers:'); - self.log(' realm: '+self.realm); - self.log(' nonce: '+self.nonce); - self.log(' opaque: '+self.opaque); - self.log(' qop: '+self.qop); - // now we can make an authenticated request - self.makeAuthenticatedRequest(); - } - } - if (self.firstRequest.readyState === 4) { - if (self.firstRequest.status === 200) { - self.log('Authentication not required for '+url); - if (data instanceof Uint8Array) { - console.log("BINARY RESPONSE 1"); - self.successFn(self.firstRequest); - } else { - if (self.firstRequest.responseText !== 'undefined') { - if (self.firstRequest.responseText.length > 0) { - // If JSON, parse and return object - if (self.isJson(self.firstRequest.responseText)) { // TODO: redundant - self.successFn(self.firstRequest); - } else { - self.successFn(self.firstRequest); - } - } - } else { - self.successFn(); - } - } - } - } - } - // send - if (self.post) { - // in case digest auth not required - self.firstRequest.send(self.data); - } else { - self.firstRequest.send(); - } - self.log('Unauthenticated request to '+url); - - // handle error - self.firstRequest.onerror = function() { - if (self.firstRequest.status !== 401) { - self.log('Error ('+self.firstRequest.status+') on unauthenticated request to '+url); - self.errorFn(self.firstRequest); - } - } - } - this.makeAuthenticatedRequest= function() { - - self.response = self.formulateResponse(); - self.authenticatedRequest = new XMLHttpRequest(); - self.authenticatedRequest.open(method, url, true); - self.authenticatedRequest.timeout = self.timeout; - var digestAuthHeader = self.scheme+' '+ - 'username="'+username+'", '+ - 'realm="'+self.realm+'", '+ - 'nonce="'+self.nonce+'", '+ - 'uri="'+url+'", '+ - 'response="'+self.response+'", '+ - 'opaque="'+self.opaque+'", '+ - 'qop='+self.qop+', '+ - 'nc='+('00000000' + self.nc).slice(-8)+', '+ - 'cnonce="'+self.cnonce+'"'; - self.authenticatedRequest.setRequestHeader('Authorization', digestAuthHeader); - self.log('digest auth header response to be sent:'); - self.log(digestAuthHeader); - // if we are posting, add appropriate headers - if (self.post && self.data) { - if (typeof self.data === "string") { - self.authenticatedRequest.setRequestHeader('Content-type', 'text/plain'); - } else { - self.authenticatedRequest.responseType = "arraybuffer"; - } - } - self.authenticatedRequest.onload = function() { - // success - if (self.authenticatedRequest.status >= 200 && self.authenticatedRequest.status < 400) { - // increment nonce count - self.nc++; - // return data - if (self.data instanceof Uint8Array) { - self.successFn(self.authenticatedRequest); - } else { - if (self.authenticatedRequest.responseText !== 'undefined' && self.authenticatedRequest.responseText.length > 0 ) { - // If JSON, parse and return object - if (self.isJson(self.authenticatedRequest.responseText)) { // TODO: redundant from not parsing - self.successFn(self.authenticatedRequest); - } else { - self.successFn(self.authenticatedRequest); - } - } else { - self.successFn(); - } - } - } - // failure - else { - self.nonce = null; - self.errorFn(self.authenticatedRequest); - } - } - // handle errors - self.authenticatedRequest.onerror = function() { - self.log('Error ('+self.authenticatedRequest.status+') on authenticated request to '+url); - self.nonce = null; - self.errorFn(self.authenticatedRequest); - }; - // send - if (self.post) { - self.authenticatedRequest.send(self.data); - } else { - self.authenticatedRequest.send(); - } - self.log('Authenticated request to '+url); - } - // hash response based on server challenge - this.formulateResponse = function() { - var HA1 = CryptoJS.MD5(username+':'+self.realm+':'+password).toString(); - var HA2 = CryptoJS.MD5(method+':'+url).toString(); - var response = CryptoJS.MD5(HA1+':'+ - self.nonce+':'+ - ('00000000' + self.nc).slice(-8)+':'+ - self.cnonce+':'+ - self.qop+':'+ - HA2).toString(); - return response; - } - // generate 16 char client nonce - this.generateCnonce = function() { - var characters = 'abcdef0123456789'; - var token = ''; - for (var i = 0; i < 16; i++) { - var randNum = Math.round(Math.random() * characters.length); - token += characters.substr(randNum, 1); - } - return token; - } - this.abort = function() { - self.log('[digestAuthRequest] Aborted request to '+url); - if (self.firstRequest != null) { - if (self.firstRequest.readyState != 4) self.firstRequest.abort(); - } - if (self.authenticatedRequest != null) { - if (self.authenticatedRequest.readyState != 4) self.authenticatedRequest.abort(); - } - } - this.isJson = function(str) { - try { - JSON.parse(str); - } catch (e) { - return false; - } - return true; - } - this.log = function(str) { - if (self.loggingOn) { - console.log('[digestAuthRequest] '+str); - } - } - this.version = function() { return '0.8.0' } -} - -module.exports = HttpClient; \ No newline at end of file diff --git a/src/main/js/common/LibraryUtils.js b/src/main/js/common/LibraryUtils.js deleted file mode 100644 index 1a552cdf5..000000000 --- a/src/main/js/common/LibraryUtils.js +++ /dev/null @@ -1,191 +0,0 @@ -const assert = require("assert"); -const GenUtils = require("./GenUtils"); -const MoneroError = require("./MoneroError"); - -/** - * Collection of helper utilities for the library. - * - * @hideconstructor - */ -class LibraryUtils { - - /** - * Get the total memory used by WebAssembly. - * - * @return {int} the total memory used by WebAssembly - */ - static async getWasmMemoryUsed() { - let total = 0; - if (LibraryUtils.WORKER) total += await LibraryUtils.invokeWorker(GenUtils.getUUID(), "getWasmMemoryUsed", []); - if (LibraryUtils.getWasmModule() && LibraryUtils.getWasmModule().HEAP8) total += LibraryUtils.getWasmModule().HEAP8.length; - return total; - } - - /** - * Get the WebAssembly module in the current context (nodejs, browser main thread or worker). - */ - static getWasmModule() { - return LibraryUtils.WASM_MODULE; - } - - /** - * Load the WebAssembly keys module with caching. - */ - static async loadKeysModule() { - - // use cache if suitable, core module supersedes keys module because it is superset - if (LibraryUtils.WASM_MODULE) return LibraryUtils.WASM_MODULE; - - // load module - delete LibraryUtils.WASM_MODULE; - LibraryUtils.WASM_MODULE = require("../../../../dist/monero_core_keys")(); - return new Promise(function(resolve, reject) { - LibraryUtils.WASM_MODULE.then(module => { - LibraryUtils.WASM_MODULE = module - delete LibraryUtils.WASM_MODULE.then; - LibraryUtils._initWasmModule(LibraryUtils.WASM_MODULE); - resolve(LibraryUtils.WASM_MODULE); - }); - }); - } - - /** - * Load the WebAssembly core module with caching. - * - * The core module is a superset of the keys module and overrides it. - * - * TODO: this is separate static function from loadKeysModule() because webpack cannot bundle WebWorker using runtime param for conditional import - */ - static async loadCoreModule() { - - // use cache if suitable, core module supersedes keys module because it is superset - if (LibraryUtils.WASM_MODULE && LibraryUtils.CORE_LOADED) return LibraryUtils.WASM_MODULE; - - // load module - delete LibraryUtils.WASM_MODULE; - LibraryUtils.WASM_MODULE = require("../../../../dist/monero_core")(); - return new Promise(function(resolve, reject) { - LibraryUtils.WASM_MODULE.then(module => { - LibraryUtils.WASM_MODULE = module - delete LibraryUtils.WASM_MODULE.then; - LibraryUtils.CORE_LOADED = true; - LibraryUtils._initWasmModule(LibraryUtils.WASM_MODULE); - resolve(LibraryUtils.WASM_MODULE); - }); - }); - } - - /** - * Private helper to initialize the wasm module with data structures to synchronize access. - */ - static _initWasmModule(wasmModule) { - - // initialize data structure to synchronize access to wasm module - const async = require("async"); - wasmModule.taskQueue = async.queue(function(asyncFn, callback) { - if (asyncFn.then) asyncFn.then(resp => { callback(resp); }).catch(err => { callback(undefined, err); }); - else asyncFn().then(resp => { callback(resp); }).catch(err => { callback(undefined, err); }); - }, 1); - - // initialize method to synchronize access to wasm module - wasmModule.queueTask = async function(asyncFn) { - return new Promise(function(resolve, reject) { - wasmModule.taskQueue.push(asyncFn, function(resp, err) { - if (err !== undefined) reject(err); - else resolve(resp); - }); - }); - } - } - - /** - * Register a function by id which informs if unauthorized requests (e.g. - * self-signed certificates) should be rejected. - * - * @param {string} fnId - unique identifier for the function - * @param {function} fn - function to inform if unauthorized requests should be rejected - */ - static setRejectUnauthorizedFn(fnId, fn) { - if (!LibraryUtils.REJECT_UNAUTHORIZED_FNS) LibraryUtils.REJECT_UNAUTHORIZED_FNS = []; - if (fn === undefined) delete LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId]; - else LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId] = fn; - } - - /** - * Indicate if unauthorized requests should be rejected. - * - * @param {string} fnId - uniquely identifies the function - */ - static isRejectUnauthorized(fnId) { - if (!LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId]) throw new Error("No function registered with id " + fnId + " to inform if unauthorized reqs should be rejected"); - return LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId](); - } - - /** - * Set the path to load MoneroWebWorker.dist.js when running this library in - * a web worker (defaults to "/MoneroWebWorker.dist.js"). - * - * @param {string} workerDistPath - path to load MoneroWebWorker.dist.js - */ - static setWorkerDistPath(workerDistPath) { - let path = workerDistPath ? workerDistPath : LibraryUtils.WORKER_DIST_PATH_DEFAULT; - if (path !== LibraryUtils.WORKER_DIST_PATH) delete LibraryUtils.WORKER; - LibraryUtils.WORKER_DIST_PATH = path; - } - - /** - * Get a singleton instance of a web worker to share. - * - * @return {Worker} a worker to share among wallet instances - */ - static getWorker() { - - // one time initialization - if (!LibraryUtils.WORKER) { - LibraryUtils.WORKER = new Worker(LibraryUtils.WORKER_DIST_PATH); - LibraryUtils.WORKER_OBJECTS = {}; // store per object running in the worker - - // catch worker messages - LibraryUtils.WORKER.onmessage = function(e) { - - // lookup object id, callback function, and this arg - let thisArg = null; - let callbackFn = LibraryUtils.WORKER_OBJECTS[e.data[0]].callbacks[e.data[1]]; // look up by object id then by function name - if (callbackFn === undefined) throw new Error("No worker callback function defined for key '" + e.data[1] + "'"); - if (callbackFn instanceof Array) { // this arg may be stored with callback function - thisArg = callbackFn[1]; - callbackFn = callbackFn[0]; - } - - // invoke callback function with this arg and arguments - callbackFn.apply(thisArg, e.data.slice(2)); - } - } - return LibraryUtils.WORKER; - } - - /** - * Invoke a web worker function and get the result with error handling. - * - * @param {objectId} identifies the worker object to invoke - * @param {string} fnName is the name of the function to invoke - * @param {Object[]} args are function arguments to invoke with - * @return {Promise} resolves with response payload from the worker or an error - */ - static async invokeWorker(objectId, fnName, args) { - assert(fnName.length >= 2); - let worker = LibraryUtils.getWorker(); - if (!LibraryUtils.WORKER_OBJECTS[objectId]) LibraryUtils.WORKER_OBJECTS[objectId] = {callbacks: {}}; - return new Promise(function(resolve, reject) { - LibraryUtils.WORKER_OBJECTS[objectId].callbacks["on" + fnName.charAt(0).toUpperCase() + fnName.substring(1)] = function(resp) { // TODO: this defines function once per callback - resp ? (resp.error ? reject(new MoneroError(resp.error)) : resolve(resp.result)) : resolve(); - }; - worker.postMessage([objectId, fnName].concat(args === undefined ? [] : GenUtils.listify(args))); - }); - } -} - -LibraryUtils.WORKER_DIST_PATH_DEFAULT = "/MoneroWebWorker.dist.js"; -LibraryUtils.WORKER_DIST_PATH = LibraryUtils.WORKER_DIST_PATH_DEFAULT; - -module.exports = LibraryUtils; \ No newline at end of file diff --git a/src/main/js/common/MoneroRpcConnection.js b/src/main/js/common/MoneroRpcConnection.js deleted file mode 100644 index a14d03b22..000000000 --- a/src/main/js/common/MoneroRpcConnection.js +++ /dev/null @@ -1,208 +0,0 @@ -const GenUtils = require("./GenUtils"); -const HttpClient = require("./HttpClient"); -const LibraryUtils = require("./LibraryUtils"); -const MoneroError = require("../common/MoneroError"); -const MoneroRpcError = require("../common/MoneroRpcError"); -const MoneroUtils = require("./MoneroUtils"); - -/** - * Maintains a connection and sends requests to a Monero RPC API. - */ -class MoneroRpcConnection { - - /** - *

Construct a RPC connection.

- * - *

Examples:

- * - * - * let connection1 = new MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123")

- * - * let connection2 = new MoneroRpcConnection({
- *    uri: http://localhost:38081,
- *    username: "daemon_user",
- *    password: "daemon_password_123",
- *    rejectUnauthorized: false // accept self-signed certificates e.g. for local development
- * }); - *
- * - * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - RPC endpoint URI, MoneroRpcConnection, or equivalent JS object - * @param {string} uriOrConfigOrConnection.uri - URI of the RPC endpoint - * @param {string} uriOrConfigOrConnection.username - username to authenticate with the RPC endpoint (optional) - * @param {string} uriOrConfigOrConnection.password - password to authenticate with the RPC endpoint (optional) - * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true) - * @param {string} username - username to authenticate with the RPC endpoint (optional) - * @param {string} password - password to authenticate with the RPC endpoint (optional) - * @param {boolean} rejectUnauthorized - reject self-signed certificates if true (default true) - */ - constructor(uriOrConfigOrConnection, username, password, rejectUnauthorized) { - - // validate and normalize config - if (typeof uriOrConfigOrConnection === "string") { - this.config = {uri: uriOrConfigOrConnection}; - if (username !== undefined) this.config.username = username; - if (password !== undefined) this.config.password = password; - if (rejectUnauthorized !== undefined) this.config.rejectUnauthorized = rejectUnauthorized; - } else if (typeof uriOrConfigOrConnection === "object") { - if (username !== undefined || password !== undefined || rejectUnauthorized !== undefined) throw new MoneroError("Can provide config object or params but not both"); - if (uriOrConfigOrConnection instanceof MoneroRpcConnection) this.config = Object.assign({}, uriOrConfigOrConnection.getConfig()); - else this.config = Object.assign({}, uriOrConfigOrConnection); - } else if (uriOrConfigOrConnection !== undefined) { - throw new MoneroError("Invalid configuration to MoneroRpcConnection; must be string or MoneroRpcConnection or equivalent JS object"); - } - - // merge default config - this.config = Object.assign({}, MoneroRpcConnection.DEFAULT_CONFIG, this.config); - - // standardize uri - if (this.config.uri) this.config.uri = this.config.uri.replace(/\/$/, ""); // strip trailing slash - - // fail with friendly message if using old api - if (this.config.user || this.config.pass) throw new MoneroError("Authentication fields 'user' and 'pass' have been renamed to 'username' and 'password'. Please update to the new api"); - } - - getUri() { - return this.config.uri; - } - - getUsername() { - return this.config.username; - } - - getPassword() { - return this.config.password; - } - - getRejectUnauthorized() { - return this.config.rejectUnauthorized; - } - - getConfig() { - return this.config; - } - - /** - * Sends a JSON RPC request. - * - * @param method is the JSON RPC method to invoke - * @param params are request parameters - * @return {object} is the response map - */ - async sendJsonRequest(method, params) { - //console.log("sendJsonRequest(" + method + ", " + JSON.stringify(params) + ")"); - - try { - // tx config - let resp = await HttpClient.request({ - method: "POST", - uri: this.getUri() + '/json_rpc', - username: this.getUsername(), - password: this.getPassword(), - body: JSON.stringify({ // body is stringified so text/plain is returned so BigIntegers are preserved - id: "0", - jsonrpc: "2.0", - method: method, - params: params - }), - rejectUnauthorized: this.config.rejectUnauthorized, - requestApi: GenUtils.isFirefox() ? "xhr" : "fetch" // firefox issue: https://bugzilla.mozilla.org/show_bug.cgi?id=1491010 - }); - - // process response - resp = JSON.parse(resp.body.replace(/("[^"]*"\s*:\s*)(\d{16,})/g, '$1"$2"')); // replace 16 or more digits with strings and parse - if (resp.error) throw new MoneroRpcError(resp.error.message, resp.error.code, method, params); - return resp; - } catch (e) { - if (e instanceof MoneroRpcError) throw e; - else throw new MoneroRpcError(e, undefined, method, params); - } - } - - /** - * Sends a RPC request to the given path and with the given paramters. - * - * E.g. "/get_transactions" with params - */ - async sendPathRequest(path, params) { - //console.log("sendPathRequest(" + path + ", " + JSON.stringify(params) + ")"); - - try { - // tx config - let resp = await HttpClient.request({ - method: "POST", - uri: this.getUri() + '/' + path, - username: this.getUsername(), - password: this.getPassword(), - body: JSON.stringify(params), // body is stringified so text/plain is returned so BigIntegers are preserved - rejectUnauthorized: this.config.rejectUnauthorized, - requestApi: GenUtils.isFirefox() ? "xhr" : "fetch" - }); - - // process response - resp = JSON.parse(resp.body.replace(/("[^"]*"\s*:\s*)(\d{16,})/g, '$1"$2"')); // replace 16 or more digits with strings and parse - if (typeof resp === "string") resp = JSON.parse(resp); // TODO: some responses returned as strings? - if (resp.error) throw new MoneroRpcError(resp.error.message, resp.error.code, path, params); - return resp; - } catch (e) { - if (e instanceof MoneroRpcError) throw e; - else throw new MoneroRpcError(e, undefined, path, params); - } - } - - /** - * Sends a binary RPC request. - * - * @param path is the path of the binary RPC method to invoke - * @paramm params are the request parameters - * @return a Uint8Array with the binary response - */ - async sendBinaryRequest(path, params) { - //console.log("sendBinaryRequest(" + path + ", " + JSON.stringify(params) + ")"); - - // load wasm module - await LibraryUtils.loadKeysModule(); - - // serialize params - let paramsBin = MoneroUtils.jsonToBinary(params); - - try { - // tx config - let resp = await HttpClient.request({ - method: "POST", - uri: this.getUri() + '/' + path, - username: this.getUsername(), - password: this.getPassword(), - body: paramsBin, - rejectUnauthorized: this.config.rejectUnauthorized, - requestApi: GenUtils.isFirefox() ? "xhr" : "fetch" - }); - - // process response - resp = resp.body; - if (!(resp instanceof Uint8Array)) { - console.error("resp is not uint8array"); - console.error(resp); - } - if (resp.error) throw new MoneroRpcError(resp.error.message, resp.error.code, path, params); - return resp; - } catch (e) { - if (e instanceof MoneroRpcError) throw e; - else throw new MoneroRpcError(e, undefined, path, params); - } - } -} - - -/** - * Default RPC configuration. - */ -MoneroRpcConnection.DEFAULT_CONFIG = { - uri: undefined, - username: undefined, - password: undefined, - rejectUnauthorized: true // reject self-signed certificates if true -} - -MoneroRpcConnection.SUPPORTED_FIELDS = ["uri", "username", "password", "rejectUnauthorized"]; - -module.exports = MoneroRpcConnection; \ No newline at end of file diff --git a/src/main/js/common/MoneroRpcError.js b/src/main/js/common/MoneroRpcError.js deleted file mode 100644 index df022dca8..000000000 --- a/src/main/js/common/MoneroRpcError.js +++ /dev/null @@ -1,37 +0,0 @@ -const MoneroError = require("./MoneroError"); - -/** - * Error when interacting with Monero RPC. - */ -class MoneroRpcError extends MoneroError { - - /** - * Constructs the error. - * - * @param {string} rpcDescription is a description of the error from rpc - * @param {int} rpcCode is the error code from rpc - * @param {string} rpcMethod is the rpc method invoked - * @param {object} rpcParams are parameters sent with the rpc request - */ - constructor(rpcDescription, rpcCode, rpcMethod, rpcParams) { - super(rpcDescription, rpcCode); - this.rpcMethod = rpcMethod; - this.rpcParams = rpcParams; - } - - getRpcMethod() { - return this.rpcMethod; - } - - getRpcParams() { - return this.rpcParams; - } - - toString() { - let str = super.toString(); - if (this.rpcMethod || this.rpcParams) str += "\nRequest: '" + this.rpcMethod + "' with params: " + (typeof this.rpcParams === "object" ? JSON.stringify(this.rpcParams) : this.rpcParams); - return str; - } -} - -module.exports = MoneroRpcError; \ No newline at end of file diff --git a/src/main/js/common/MoneroUtils.js b/src/main/js/common/MoneroUtils.js deleted file mode 100644 index db2e119ad..000000000 --- a/src/main/js/common/MoneroUtils.js +++ /dev/null @@ -1,248 +0,0 @@ -const assert = require("assert"); -const GenUtils = require("./GenUtils"); -const LibraryUtils = require("./LibraryUtils"); -const MoneroError = require("./MoneroError"); - -/** - * Collection of Monero utilities. - * - * @hideconstructor - */ -class MoneroUtils { - - - /** - *

Get the version of the monero-javascript library.

- * - * @return {string} the version of this monero-javascript library - */ - static getVersion() { - return "0.4.3"; - } - - // TODO: improve validation - static validateMnemonic(mnemonic) { - assert(mnemonic, "Mnemonic phrase is not initialized"); - let words = mnemonic.split(" "); - if (words.length !== MoneroUtils.NUM_MNEMONIC_WORDS) throw new Error("Mnemonic phrase is " + words.length + " words but must be " + MoneroUtils.NUM_MNEMONIC_WORDS); - } - - // TODO: improve validation - static validatePrivateViewKey(privateViewKey) { - assert(typeof privateViewKey === "string"); - assert(privateViewKey.length === 64); - } - - // TODO: improve validation - static validatePrivateSpendKey(privateSpendKey) { - assert(typeof privateSpendKey === "string"); - assert(privateSpendKey.length === 64); - } - - // TODO: improve validation - static validatePublicViewKey(publicViewKey) { - assert(typeof publicViewKey === "string"); - assert(publicViewKey.length === 64); - } - - // TODO: improve validation - static validatePublicSpendKey(publicSpendKey) { - assert(typeof publicSpendKey === "string"); - assert(publicSpendKey.length === 64); - } - - // TODO: improve validation, will require knowing network type - static isValidAddress(address) { - try { - MoneroUtils.validateAddress(address); - return true; - } catch (e) { - return false; - } - } - - static validateAddress(address) { - assert(typeof address === "string", "Address is not string"); - assert(address.length > 0, "Address is empty"); - assert(GenUtils.isBase58(address), "Address is not base 58"); - } - - static isValidPaymentId(paymentId) { - try { - MoneroUtils.validatePaymentId(paymentId); - return true; - } catch (e) { - return false; - } - } - - // TODO: beef this up - static validatePaymentId(paymentId) { - assert.equal(typeof paymentId, "string"); - assert(paymentId.length === 16 || paymentId.length === 64); - } - - /** - * Decodes tx extra according to https://cryptonote.org/cns/cns005.txt and - * returns the last tx pub key. - * - * TODO: use c++ bridge for this - * - * @param txExtra is an array of tx extra bytes - * @return the last pub key as a hexidecimal string - */ - static getLastTxPubKey(txExtra) { - let lastPubKeyIdx; - for (let i = 0; i < txExtra.length; i++) { - let tag = txExtra[i]; - if (tag === 0 || tag === 2) { - i += 1 + txExtra[i + 1]; // advance to next tag - } else if (tag === 1) { - lastPubKeyIdx = i + 1; - i += 1 + 32; // advance to next tag - } else throw new Error("Invalid sub-field tag: " + tag); - } - return Buffer.from(new Uint8Array(txExtra.slice(lastPubKeyIdx, lastPubKeyIdx + 32))).toString("hex"); - } - - /** - * Determines if two payment ids are functionally equal. - * - * For example, 03284e41c342f032 and 03284e41c342f032000000000000000000000000000000000000000000000000 are considered equal. - * - * @param paymentId1 is a payment id to compare - * @param paymentId2 is a payment id to compare - * @return true if the payment ids are equal, false otherwise - */ - static paymentIdsEqual(paymentId1, paymentId2) { - let maxLength = Math.max(paymentId1.length, paymentId2.length); - for (let i = 0; i < maxLength; i++) { - if (i < paymentId1.length && i < paymentId2.length && paymentId1[i] !== paymentId2[i]) return false; - if (i >= paymentId1.length && paymentId2[i] !== '0') return false; - if (i >= paymentId2.length && paymentId1[i] !== '0') return false; - } - return true; - } - - /** - * Merges a transaction into a list of existing transactions. - * - * @param txs are existing transactions to merge into - * @param tx is the transaction to merge into the list - */ - static mergeTx(txs, tx) { - for (let aTx of txs) { - if (aTx.getHash() === tx.getHash()) { - aTx.merge(tx); - return; - } - } - txs.push(tx); - } - - /** - * Converts the given JSON to a binary Uint8Array using Monero's portable storage format. - * - * @param json is the json to convert to binary - * @returns Uint8Array is the json converted to portable storage binary - */ - static jsonToBinary(json) { - - // wasm module must be pre-loaded - if (LibraryUtils.getWasmModule() === undefined) throw MoneroError("WASM module is not loaded; call 'await LibraryUtils.loadKeysModule()' to load"); - - // serialize json to binary which is stored in c++ heap - let binMemInfoStr = LibraryUtils.getWasmModule().malloc_binary_from_json(JSON.stringify(json)); - - // sanitize binary memory address info - let binMemInfo = JSON.parse(binMemInfoStr); - binMemInfo.ptr = parseInt(binMemInfo.ptr); - binMemInfo.length = parseInt(binMemInfo.length); - - // read binary data from heap to Uint8Array - let view = new Uint8Array(binMemInfo.length); - for (let i = 0; i < binMemInfo.length; i++) { - view[i] = LibraryUtils.getWasmModule().HEAPU8[binMemInfo.ptr / Uint8Array.BYTES_PER_ELEMENT + i]; - } - - // free binary on heap - LibraryUtils.getWasmModule()._free(binMemInfo.ptr); - - // return json from binary data - return view; - } - - /** - * Converts the given portable storage binary to JSON. - * - * @param uint8arr is a Uint8Array with binary data in Monero's portable storage format - * @returns a JSON object converted from the binary data - */ - static binaryToJson(uint8arr) { - - // wasm module must be pre-loaded - if (LibraryUtils.getWasmModule() === undefined) throw MoneroError("WASM module is not loaded; call 'await LibraryUtils.loadKeysModule()' to load"); - - // allocate space in c++ heap for binary - let ptr = LibraryUtils.getWasmModule()._malloc(uint8arr.length * uint8arr.BYTES_PER_ELEMENT); - let heap = new Uint8Array(LibraryUtils.getWasmModule().HEAPU8.buffer, ptr, uint8arr.length * uint8arr.BYTES_PER_ELEMENT); - if (ptr !== heap.byteOffset) throw new Error("Memory ptr !== heap.byteOffset"); // should be equal - - // write binary to heap - heap.set(new Uint8Array(uint8arr.buffer)); - - // create object with binary memory address info - let binMemInfo = { ptr: ptr, length: uint8arr.length } - - // convert binary to json str - const ret_string = LibraryUtils.getWasmModule().binary_to_json(JSON.stringify(binMemInfo)); - - // free binary on heap - LibraryUtils.getWasmModule()._free(ptr); - - // parse and return json - return JSON.parse(ret_string); - } - - /** - * Converts the binary response from daemon RPC block retrieval to JSON. - * - * @param uint8arr is the binary response from daemon RPC when getting blocks - * @returns a JSON object with the blocks data - */ - static binaryBlocksToJson(uint8arr) { - - // wasm module must be pre-loaded - if (LibraryUtils.getWasmModule() === undefined) throw MoneroError("WASM module is not loaded; call 'await LibraryUtils.loadKeysModule()' to load"); - - // allocate space in c++ heap for binary - let ptr = LibraryUtils.getWasmModule()._malloc(uint8arr.length * uint8arr.BYTES_PER_ELEMENT); - let heap = new Uint8Array(LibraryUtils.getWasmModule().HEAPU8.buffer, ptr, uint8arr.length * uint8arr.BYTES_PER_ELEMENT); - if (ptr !== heap.byteOffset) throw new Error("Memory ptr !== heap.byteOffset"); // should be equal - - // write binary to heap - heap.set(new Uint8Array(uint8arr.buffer)); - - // create object with binary memory address info - let binMemInfo = { ptr: ptr, length: uint8arr.length } - - // convert binary to json str - const json_str = LibraryUtils.getWasmModule().binary_blocks_to_json(JSON.stringify(binMemInfo)); - - // free memory - LibraryUtils.getWasmModule()._free(ptr); - - // parse result to json - let json = JSON.parse(json_str); // parsing json gives arrays of block and tx strings - json.blocks = json.blocks.map(blockStr => JSON.parse(blockStr)); // replace block strings with parsed blocks - json.txs = json.txs.map(txs => txs ? txs.map(tx => JSON.parse(tx.replace(",", "{") + "}")) : []); // modify tx string to proper json and parse // TODO: more efficient way than this json manipulation? - return json; - } -} - -MoneroUtils.NUM_MNEMONIC_WORDS = 25; -MoneroUtils.WALLET_REFRESH_RATE = 10000; // 10 seconds -MoneroUtils.RING_SIZE = 12; -MoneroUtils.MAX_REQUESTS_PER_SECOND = 50; - -module.exports = MoneroUtils; \ No newline at end of file diff --git a/src/main/js/common/SslOptions.js b/src/main/js/common/SslOptions.js deleted file mode 100644 index 5c82b0505..000000000 --- a/src/main/js/common/SslOptions.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * SSL options for remote endpoints. - */ -class SslOptions { - - constructor(state) { - this.state = Object.assign({}, state); - } - - getPrivateKeyPath() { - return this.state.privateKeyPath; - } - - setPrivateKeyPath(privateKeyPath) { - this.state.privateKeyPath = privateKeyPath; - return this; - } - - getCertificatePath() { - return this.state.certificatePath; - } - - setCertificatePath(certificatePath) { - this.state.certificatePath = certificatePath; - return this; - } - - getCertificateAuthorityFile() { - return this.state.certificateAuthorityFile; - } - - setCertificateAuthorityFile(certificateAuthorityFile) { - this.state.certificateAuthorityFile = certificateAuthorityFile; - return this; - } - - getAllowedFingerprints() { - return this.state.allowedFingerprints; - } - - setAllowedFingerprints(allowedFingerprints) { - this.state.allowedFingerprints = allowedFingerprints; - return this; - } - - getAllowAnyCert() { - return this.state.allowAnyCert; - } - - setAllowAnyCert(allowAnyCert) { - this.state.allowAnyCert = allowAnyCert; - return this; - } -} - -module.exports = SslOptions; \ No newline at end of file diff --git a/src/main/js/common/biginteger.js b/src/main/js/common/biginteger.js deleted file mode 100644 index 5082ef0a6..000000000 --- a/src/main/js/common/biginteger.js +++ /dev/null @@ -1,1636 +0,0 @@ -/* - JavaScript BigInteger library version 0.9.1 - http://silentmatt.com/biginteger/ - - Copyright (c) 2009 Matthew Crumley - Copyright (c) 2010,2011 by John Tobey - Licensed under the MIT license. - - Support for arbitrary internal representation base was added by - Vitaly Magerya. -*/ -/* - -This file has been modified by Paul Shapiro: - -1. to bring in the function lowVal which was written by Lucas Jones -2. to expose CONSTRUCT - -*/ -/* - File: biginteger.js - - Exports: - - -*/ -(function(exports) { -"use strict"; -/* - Class: BigInteger - An arbitrarily-large integer. - - objects should be considered immutable. None of the "built-in" - methods modify *this* or their arguments. All properties should be - considered private. - - All the methods of instances can be called "statically". The - static versions are convenient if you don't already have a - object. - - As an example, these calls are equivalent. - - > BigInteger(4).multiply(5); // returns BigInteger(20); - > BigInteger.multiply(4, 5); // returns BigInteger(20); - - > var a = 42; - > var a = BigInteger.toJSValue("0b101010"); // Not completely useless... -*/ - -var CONSTRUCT = {}; // Unique token to call "private" version of constructor - -/* - Constructor: BigInteger() - Convert a value to a . - - Although is the constructor for objects, it is - best not to call it as a constructor. If *n* is a object, it is - simply returned as-is. Otherwise, is equivalent to - without a radix argument. - - > var n0 = BigInteger(); // Same as - > var n1 = BigInteger("123"); // Create a new with value 123 - > var n2 = BigInteger(123); // Create a new with value 123 - > var n3 = BigInteger(n2); // Return n2, unchanged - - The constructor form only takes an array and a sign. *n* must be an - array of numbers in little-endian order, where each digit is between 0 - and BigInteger.base. The second parameter sets the sign: -1 for - negative, +1 for positive, or 0 for zero. The array is *not copied and - may be modified*. If the array contains only zeros, the sign parameter - is ignored and is forced to zero. - - > new BigInteger([5], -1): create a new BigInteger with value -5 - - Parameters: - - n - Value to convert to a . - - Returns: - - A value. - - See Also: - - , -*/ -function BigInteger(n, s, token) { - if (token !== CONSTRUCT) { - if (n instanceof BigInteger) { - return n; - } - else if (typeof n === "undefined") { - return ZERO; - } - return BigInteger.parse(n); - } - - n = n || []; // Provide the nullary constructor for subclasses. - while (n.length && !n[n.length - 1]) { - --n.length; - } - this._d = n; - this._s = n.length ? (s || 1) : 0; -} -BigInteger.CONSTRUCT = CONSTRUCT; // added by PS to actually use the constructor - -BigInteger._construct = function(n, s) { - return new BigInteger(n, s, CONSTRUCT); -}; - -// Base-10 speedup hacks in parse, toString, exp10 and log functions -// require base to be a power of 10. 10^7 is the largest such power -// that won't cause a precision loss when digits are multiplied. -var BigInteger_base = 10000000; -var BigInteger_base_log10 = 7; - -BigInteger.base = BigInteger_base; -BigInteger.base_log10 = BigInteger_base_log10; - -var ZERO = new BigInteger([], 0, CONSTRUCT); -// Constant: ZERO -// 0. -BigInteger.ZERO = ZERO; - -var ONE = new BigInteger([1], 1, CONSTRUCT); -// Constant: ONE -// 1. -BigInteger.ONE = ONE; - -var M_ONE = new BigInteger(ONE._d, -1, CONSTRUCT); -// Constant: M_ONE -// -1. -BigInteger.M_ONE = M_ONE; - -// Constant: _0 -// Shortcut for . -BigInteger._0 = ZERO; - -// Constant: _1 -// Shortcut for . -BigInteger._1 = ONE; - -/* - Constant: small - Array of from 0 to 36. - - These are used internally for parsing, but useful when you need a "small" - . - - See Also: - - , , <_0>, <_1> -*/ -BigInteger.small = [ - ZERO, - ONE, - /* Assuming BigInteger_base > 36 */ - new BigInteger( [2], 1, CONSTRUCT), - new BigInteger( [3], 1, CONSTRUCT), - new BigInteger( [4], 1, CONSTRUCT), - new BigInteger( [5], 1, CONSTRUCT), - new BigInteger( [6], 1, CONSTRUCT), - new BigInteger( [7], 1, CONSTRUCT), - new BigInteger( [8], 1, CONSTRUCT), - new BigInteger( [9], 1, CONSTRUCT), - new BigInteger([10], 1, CONSTRUCT), - new BigInteger([11], 1, CONSTRUCT), - new BigInteger([12], 1, CONSTRUCT), - new BigInteger([13], 1, CONSTRUCT), - new BigInteger([14], 1, CONSTRUCT), - new BigInteger([15], 1, CONSTRUCT), - new BigInteger([16], 1, CONSTRUCT), - new BigInteger([17], 1, CONSTRUCT), - new BigInteger([18], 1, CONSTRUCT), - new BigInteger([19], 1, CONSTRUCT), - new BigInteger([20], 1, CONSTRUCT), - new BigInteger([21], 1, CONSTRUCT), - new BigInteger([22], 1, CONSTRUCT), - new BigInteger([23], 1, CONSTRUCT), - new BigInteger([24], 1, CONSTRUCT), - new BigInteger([25], 1, CONSTRUCT), - new BigInteger([26], 1, CONSTRUCT), - new BigInteger([27], 1, CONSTRUCT), - new BigInteger([28], 1, CONSTRUCT), - new BigInteger([29], 1, CONSTRUCT), - new BigInteger([30], 1, CONSTRUCT), - new BigInteger([31], 1, CONSTRUCT), - new BigInteger([32], 1, CONSTRUCT), - new BigInteger([33], 1, CONSTRUCT), - new BigInteger([34], 1, CONSTRUCT), - new BigInteger([35], 1, CONSTRUCT), - new BigInteger([36], 1, CONSTRUCT) -]; - -// Used for parsing/radix conversion -BigInteger.digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""); - -/* - Method: toString - Convert a to a string. - - When *base* is greater than 10, letters are upper case. - - Parameters: - - base - Optional base to represent the number in (default is base 10). - Must be between 2 and 36 inclusive, or an Error will be thrown. - - Returns: - - The string representation of the . -*/ -BigInteger.prototype.toString = function(base) { - base = +base || 10; - if (base < 2 || base > 36) { - throw new Error("illegal radix " + base + "."); - } - if (this._s === 0) { - return "0"; - } - if (base === 10) { - var str = this._s < 0 ? "-" : ""; - str += this._d[this._d.length - 1].toString(); - for (var i = this._d.length - 2; i >= 0; i--) { - var group = this._d[i].toString(); - while (group.length < BigInteger_base_log10) group = '0' + group; - str += group; - } - return str; - } - else { - var numerals = BigInteger.digits; - base = BigInteger.small[base]; - var sign = this._s; - - var n = this.abs(); - var digits = []; - var digit; - - while (n._s !== 0) { - var divmod = n.divRem(base); - n = divmod[0]; - digit = divmod[1]; - // TODO: This could be changed to unshift instead of reversing at the end. - // Benchmark both to compare speeds. - digits.push(numerals[digit.valueOf()]); - } - return (sign < 0 ? "-" : "") + digits.reverse().join(""); - } -}; - -// Verify strings for parsing -BigInteger.radixRegex = [ - /^$/, - /^$/, - /^[01]*$/, - /^[012]*$/, - /^[0-3]*$/, - /^[0-4]*$/, - /^[0-5]*$/, - /^[0-6]*$/, - /^[0-7]*$/, - /^[0-8]*$/, - /^[0-9]*$/, - /^[0-9aA]*$/, - /^[0-9abAB]*$/, - /^[0-9abcABC]*$/, - /^[0-9a-dA-D]*$/, - /^[0-9a-eA-E]*$/, - /^[0-9a-fA-F]*$/, - /^[0-9a-gA-G]*$/, - /^[0-9a-hA-H]*$/, - /^[0-9a-iA-I]*$/, - /^[0-9a-jA-J]*$/, - /^[0-9a-kA-K]*$/, - /^[0-9a-lA-L]*$/, - /^[0-9a-mA-M]*$/, - /^[0-9a-nA-N]*$/, - /^[0-9a-oA-O]*$/, - /^[0-9a-pA-P]*$/, - /^[0-9a-qA-Q]*$/, - /^[0-9a-rA-R]*$/, - /^[0-9a-sA-S]*$/, - /^[0-9a-tA-T]*$/, - /^[0-9a-uA-U]*$/, - /^[0-9a-vA-V]*$/, - /^[0-9a-wA-W]*$/, - /^[0-9a-xA-X]*$/, - /^[0-9a-yA-Y]*$/, - /^[0-9a-zA-Z]*$/ -]; - -/* - Function: parse - Parse a string into a . - - *base* is optional but, if provided, must be from 2 to 36 inclusive. If - *base* is not provided, it will be guessed based on the leading characters - of *s* as follows: - - - "0x" or "0X": *base* = 16 - - "0c" or "0C": *base* = 8 - - "0b" or "0B": *base* = 2 - - else: *base* = 10 - - If no base is provided, or *base* is 10, the number can be in exponential - form. For example, these are all valid: - - > BigInteger.parse("1e9"); // Same as "1000000000" - > BigInteger.parse("1.234*10^3"); // Same as 1234 - > BigInteger.parse("56789 * 10 ** -2"); // Same as 567 - - If any characters fall outside the range defined by the radix, an exception - will be thrown. - - Parameters: - - s - The string to parse. - base - Optional radix (default is to guess based on *s*). - - Returns: - - a instance. -*/ -BigInteger.parse = function(s, base) { - // Expands a number in exponential form to decimal form. - // expandExponential("-13.441*10^5") === "1344100"; - // expandExponential("1.12300e-1") === "0.112300"; - // expandExponential(1000000000000000000000000000000) === "1000000000000000000000000000000"; - function expandExponential(str) { - str = str.replace(/\s*[*xX]\s*10\s*(\^|\*\*)\s*/, "e"); - - return str.replace(/^([+\-])?(\d+)\.?(\d*)[eE]([+\-]?\d+)$/, function(x, s, n, f, c) { - c = +c; - var l = c < 0; - var i = n.length + c; - x = (l ? n : f).length; - c = ((c = Math.abs(c)) >= x ? c - x + l : 0); - var z = (new Array(c + 1)).join("0"); - var r = n + f; - return (s || "") + (l ? r = z + r : r += z).substr(0, i += l ? z.length : 0) + (i < r.length ? "." + r.substr(i) : ""); - }); - } - - s = s.toString(); - if (typeof base === "undefined" || +base === 10) { - s = expandExponential(s); - } - - var prefixRE; - if (typeof base === "undefined") { - prefixRE = '0[xcb]'; - } - else if (base == 16) { - prefixRE = '0x'; - } - else if (base == 8) { - prefixRE = '0c'; - } - else if (base == 2) { - prefixRE = '0b'; - } - else { - prefixRE = ''; - } - var parts = new RegExp('^([+\\-]?)(' + prefixRE + ')?([0-9a-z]*)(?:\\.\\d*)?$', 'i').exec(s); - if (parts) { - var sign = parts[1] || "+"; - var baseSection = parts[2] || ""; - var digits = parts[3] || ""; - - if (typeof base === "undefined") { - // Guess base - if (baseSection === "0x" || baseSection === "0X") { // Hex - base = 16; - } - else if (baseSection === "0c" || baseSection === "0C") { // Octal - base = 8; - } - else if (baseSection === "0b" || baseSection === "0B") { // Binary - base = 2; - } - else { - base = 10; - } - } - else if (base < 2 || base > 36) { - throw new Error("Illegal radix " + base + "."); - } - - base = +base; - - // Check for digits outside the range - if (!(BigInteger.radixRegex[base].test(digits))) { - throw new Error("Bad digit for radix " + base); - } - - // Strip leading zeros, and convert to array - digits = digits.replace(/^0+/, "").split(""); - if (digits.length === 0) { - return ZERO; - } - - // Get the sign (we know it's not zero) - sign = (sign === "-") ? -1 : 1; - - // Optimize 10 - if (base == 10) { - var d = []; - while (digits.length >= BigInteger_base_log10) { - d.push(parseInt(digits.splice(digits.length-BigInteger.base_log10, BigInteger.base_log10).join(''), 10)); - } - d.push(parseInt(digits.join(''), 10)); - return new BigInteger(d, sign, CONSTRUCT); - } - - // Do the conversion - var d = ZERO; - base = BigInteger.small[base]; - var small = BigInteger.small; - for (var i = 0; i < digits.length; i++) { - d = d.multiply(base).add(small[parseInt(digits[i], 36)]); - } - return new BigInteger(d._d, sign, CONSTRUCT); - } - else { - throw new Error("Invalid BigInteger format: " + s); - } -}; - -/* - Function: add - Add two . - - Parameters: - - n - The number to add to *this*. Will be converted to a . - - Returns: - - The numbers added together. - - See Also: - - , , , -*/ -BigInteger.prototype.add = function(n) { - if (this._s === 0) { - return BigInteger(n); - } - - n = BigInteger(n); - if (n._s === 0) { - return this; - } - if (this._s !== n._s) { - n = n.negate(); - return this.subtract(n); - } - - var a = this._d; - var b = n._d; - var al = a.length; - var bl = b.length; - var sum = new Array(Math.max(al, bl) + 1); - var size = Math.min(al, bl); - var carry = 0; - var digit; - - for (var i = 0; i < size; i++) { - digit = a[i] + b[i] + carry; - sum[i] = digit % BigInteger_base; - carry = (digit / BigInteger_base) | 0; - } - if (bl > al) { - a = b; - al = bl; - } - for (i = size; carry && i < al; i++) { - digit = a[i] + carry; - sum[i] = digit % BigInteger_base; - carry = (digit / BigInteger_base) | 0; - } - if (carry) { - sum[i] = carry; - } - - for ( ; i < al; i++) { - sum[i] = a[i]; - } - - return new BigInteger(sum, this._s, CONSTRUCT); -}; - -/* - Function: negate - Get the additive inverse of a . - - Returns: - - A with the same magnatude, but with the opposite sign. - - See Also: - - -*/ -BigInteger.prototype.negate = function() { - return new BigInteger(this._d, (-this._s) | 0, CONSTRUCT); -}; - -/* - Function: abs - Get the absolute value of a . - - Returns: - - A with the same magnatude, but always positive (or zero). - - See Also: - - -*/ -BigInteger.prototype.abs = function() { - return (this._s < 0) ? this.negate() : this; -}; - -/* - Function: subtract - Subtract two . - - Parameters: - - n - The number to subtract from *this*. Will be converted to a . - - Returns: - - The *n* subtracted from *this*. - - See Also: - - , , , -*/ -BigInteger.prototype.subtract = function(n) { - if (this._s === 0) { - return BigInteger(n).negate(); - } - - n = BigInteger(n); - if (n._s === 0) { - return this; - } - if (this._s !== n._s) { - n = n.negate(); - return this.add(n); - } - - var m = this; - // negative - negative => -|a| - -|b| => -|a| + |b| => |b| - |a| - if (this._s < 0) { - m = new BigInteger(n._d, 1, CONSTRUCT); - n = new BigInteger(this._d, 1, CONSTRUCT); - } - - // Both are positive => a - b - var sign = m.compareAbs(n); - if (sign === 0) { - return ZERO; - } - else if (sign < 0) { - // swap m and n - var t = n; - n = m; - m = t; - } - - // a > b - var a = m._d; - var b = n._d; - var al = a.length; - var bl = b.length; - var diff = new Array(al); // al >= bl since a > b - var borrow = 0; - var i; - var digit; - - for (i = 0; i < bl; i++) { - digit = a[i] - borrow - b[i]; - if (digit < 0) { - digit += BigInteger_base; - borrow = 1; - } - else { - borrow = 0; - } - diff[i] = digit; - } - for (i = bl; i < al; i++) { - digit = a[i] - borrow; - if (digit < 0) { - digit += BigInteger_base; - } - else { - diff[i++] = digit; - break; - } - diff[i] = digit; - } - for ( ; i < al; i++) { - diff[i] = a[i]; - } - - return new BigInteger(diff, sign, CONSTRUCT); -}; - -(function() { - function addOne(n, sign) { - var a = n._d; - var sum = a.slice(); - var carry = true; - var i = 0; - - while (true) { - var digit = (a[i] || 0) + 1; - sum[i] = digit % BigInteger_base; - if (digit <= BigInteger_base - 1) { - break; - } - ++i; - } - - return new BigInteger(sum, sign, CONSTRUCT); - } - - function subtractOne(n, sign) { - var a = n._d; - var sum = a.slice(); - var borrow = true; - var i = 0; - - while (true) { - var digit = (a[i] || 0) - 1; - if (digit < 0) { - sum[i] = digit + BigInteger_base; - } - else { - sum[i] = digit; - break; - } - ++i; - } - - return new BigInteger(sum, sign, CONSTRUCT); - } - - /* - Function: next - Get the next (add one). - - Returns: - - *this* + 1. - - See Also: - - , - */ - BigInteger.prototype.next = function() { - switch (this._s) { - case 0: - return ONE; - case -1: - return subtractOne(this, -1); - // case 1: - default: - return addOne(this, 1); - } - }; - - /* - Function: prev - Get the previous (subtract one). - - Returns: - - *this* - 1. - - See Also: - - , - */ - BigInteger.prototype.prev = function() { - switch (this._s) { - case 0: - return M_ONE; - case -1: - return addOne(this, -1); - // case 1: - default: - return subtractOne(this, 1); - } - }; -})(); - -/* - Function: compareAbs - Compare the absolute value of two . - - Calling is faster than calling twice, then . - - Parameters: - - n - The number to compare to *this*. Will be converted to a . - - Returns: - - -1, 0, or +1 if *|this|* is less than, equal to, or greater than *|n|*. - - See Also: - - , -*/ -BigInteger.prototype.compareAbs = function(n) { - if (this === n) { - return 0; - } - - if (!(n instanceof BigInteger)) { - if (!isFinite(n)) { - return(isNaN(n) ? n : -1); - } - n = BigInteger(n); - } - - if (this._s === 0) { - return (n._s !== 0) ? -1 : 0; - } - if (n._s === 0) { - return 1; - } - - var l = this._d.length; - var nl = n._d.length; - if (l < nl) { - return -1; - } - else if (l > nl) { - return 1; - } - - var a = this._d; - var b = n._d; - for (var i = l-1; i >= 0; i--) { - if (a[i] !== b[i]) { - return a[i] < b[i] ? -1 : 1; - } - } - - return 0; -}; - -/* - Function: compare - Compare two . - - Parameters: - - n - The number to compare to *this*. Will be converted to a . - - Returns: - - -1, 0, or +1 if *this* is less than, equal to, or greater than *n*. - - See Also: - - , , , -*/ -BigInteger.prototype.compare = function(n) { - if (this === n) { - return 0; - } - - n = BigInteger(n); - - if (this._s === 0) { - return -n._s; - } - - if (this._s === n._s) { // both positive or both negative - var cmp = this.compareAbs(n); - return cmp * this._s; - } - else { - return this._s; - } -}; - -/* - Function: isUnit - Return true iff *this* is either 1 or -1. - - Returns: - - true if *this* compares equal to or . - - See Also: - - , , , , , - , -*/ -BigInteger.prototype.isUnit = function() { - return this === ONE || - this === M_ONE || - (this._d.length === 1 && this._d[0] === 1); -}; - -/* - Function: multiply - Multiply two . - - Parameters: - - n - The number to multiply *this* by. Will be converted to a - . - - Returns: - - The numbers multiplied together. - - See Also: - - , , , -*/ -BigInteger.prototype.multiply = function(n) { - // TODO: Consider adding Karatsuba multiplication for large numbers - if (this._s === 0) { - return ZERO; - } - - n = BigInteger(n); - if (n._s === 0) { - return ZERO; - } - if (this.isUnit()) { - if (this._s < 0) { - return n.negate(); - } - return n; - } - if (n.isUnit()) { - if (n._s < 0) { - return this.negate(); - } - return this; - } - if (this === n) { - return this.square(); - } - - var r = (this._d.length >= n._d.length); - var a = (r ? this : n)._d; // a will be longer than b - var b = (r ? n : this)._d; - var al = a.length; - var bl = b.length; - - var pl = al + bl; - var partial = new Array(pl); - var i; - for (i = 0; i < pl; i++) { - partial[i] = 0; - } - - for (i = 0; i < bl; i++) { - var carry = 0; - var bi = b[i]; - var jlimit = al + i; - var digit; - for (var j = i; j < jlimit; j++) { - digit = partial[j] + bi * a[j - i] + carry; - carry = (digit / BigInteger_base) | 0; - partial[j] = (digit % BigInteger_base) | 0; - } - if (carry) { - digit = partial[j] + carry; - carry = (digit / BigInteger_base) | 0; - partial[j] = digit % BigInteger_base; - } - } - return new BigInteger(partial, this._s * n._s, CONSTRUCT); -}; - -// Multiply a BigInteger by a single-digit native number -// Assumes that this and n are >= 0 -// This is not really intended to be used outside the library itself -BigInteger.prototype.multiplySingleDigit = function(n) { - if (n === 0 || this._s === 0) { - return ZERO; - } - if (n === 1) { - return this; - } - - var digit; - if (this._d.length === 1) { - digit = this._d[0] * n; - if (digit >= BigInteger_base) { - return new BigInteger([(digit % BigInteger_base)|0, - (digit / BigInteger_base)|0], 1, CONSTRUCT); - } - return new BigInteger([digit], 1, CONSTRUCT); - } - - if (n === 2) { - return this.add(this); - } - if (this.isUnit()) { - return new BigInteger([n], 1, CONSTRUCT); - } - - var a = this._d; - var al = a.length; - - var pl = al + 1; - var partial = new Array(pl); - for (var i = 0; i < pl; i++) { - partial[i] = 0; - } - - var carry = 0; - for (var j = 0; j < al; j++) { - digit = n * a[j] + carry; - carry = (digit / BigInteger_base) | 0; - partial[j] = (digit % BigInteger_base) | 0; - } - if (carry) { - partial[j] = carry; - } - - return new BigInteger(partial, 1, CONSTRUCT); -}; - -/* - Function: square - Multiply a by itself. - - This is slightly faster than regular multiplication, since it removes the - duplicated multiplcations. - - Returns: - - > this.multiply(this) - - See Also: - -*/ -BigInteger.prototype.square = function() { - // Normally, squaring a 10-digit number would take 100 multiplications. - // Of these 10 are unique diagonals, of the remaining 90 (100-10), 45 are repeated. - // This procedure saves (N*(N-1))/2 multiplications, (e.g., 45 of 100 multiplies). - // Based on code by Gary Darby, Intellitech Systems Inc., www.DelphiForFun.org - - if (this._s === 0) { - return ZERO; - } - if (this.isUnit()) { - return ONE; - } - - var digits = this._d; - var length = digits.length; - var imult1 = new Array(length + length + 1); - var product, carry, k; - var i; - - // Calculate diagonal - for (i = 0; i < length; i++) { - k = i * 2; - product = digits[i] * digits[i]; - carry = (product / BigInteger_base) | 0; - imult1[k] = product % BigInteger_base; - imult1[k + 1] = carry; - } - - // Calculate repeating part - for (i = 0; i < length; i++) { - carry = 0; - k = i * 2 + 1; - for (var j = i + 1; j < length; j++, k++) { - product = digits[j] * digits[i] * 2 + imult1[k] + carry; - carry = (product / BigInteger_base) | 0; - imult1[k] = product % BigInteger_base; - } - k = length + i; - var digit = carry + imult1[k]; - carry = (digit / BigInteger_base) | 0; - imult1[k] = digit % BigInteger_base; - imult1[k + 1] += carry; - } - - return new BigInteger(imult1, 1, CONSTRUCT); -}; - -/* - Function: quotient - Divide two and truncate towards zero. - - throws an exception if *n* is zero. - - Parameters: - - n - The number to divide *this* by. Will be converted to a . - - Returns: - - The *this* / *n*, truncated to an integer. - - See Also: - - , , , , -*/ -BigInteger.prototype.quotient = function(n) { - return this.divRem(n)[0]; -}; - -/* - Function: divide - Deprecated synonym for . -*/ -BigInteger.prototype.divide = BigInteger.prototype.quotient; - -/* - Function: remainder - Calculate the remainder of two . - - throws an exception if *n* is zero. - - Parameters: - - n - The remainder after *this* is divided *this* by *n*. Will be - converted to a . - - Returns: - - *this* % *n*. - - See Also: - - , -*/ -BigInteger.prototype.remainder = function(n) { - return this.divRem(n)[1]; -}; - -/* - Function: divRem - Calculate the integer quotient and remainder of two . - - throws an exception if *n* is zero. - - Parameters: - - n - The number to divide *this* by. Will be converted to a . - - Returns: - - A two-element array containing the quotient and the remainder. - - > a.divRem(b) - - is exactly equivalent to - - > [a.quotient(b), a.remainder(b)] - - except it is faster, because they are calculated at the same time. - - See Also: - - , -*/ -BigInteger.prototype.divRem = function(n) { - n = BigInteger(n); - if (n._s === 0) { - throw new Error("Divide by zero"); - } - if (this._s === 0) { - return [ZERO, ZERO]; - } - if (n._d.length === 1) { - return this.divRemSmall(n._s * n._d[0]); - } - - // Test for easy cases -- |n1| <= |n2| - switch (this.compareAbs(n)) { - case 0: // n1 == n2 - return [this._s === n._s ? ONE : M_ONE, ZERO]; - case -1: // |n1| < |n2| - return [ZERO, this]; - } - - var sign = this._s * n._s; - var a = n.abs(); - var b_digits = this._d; - var b_index = b_digits.length; - var digits = n._d.length; - var quot = []; - var guess; - - var part = new BigInteger([], 0, CONSTRUCT); - - while (b_index) { - part._d.unshift(b_digits[--b_index]); - part = new BigInteger(part._d, 1, CONSTRUCT); - - if (part.compareAbs(n) < 0) { - quot.push(0); - continue; - } - if (part._s === 0) { - guess = 0; - } - else { - var xlen = part._d.length, ylen = a._d.length; - var highx = part._d[xlen-1]*BigInteger_base + part._d[xlen-2]; - var highy = a._d[ylen-1]*BigInteger_base + a._d[ylen-2]; - if (part._d.length > a._d.length) { - // The length of part._d can either match a._d length, - // or exceed it by one. - highx = (highx+1)*BigInteger_base; - } - guess = Math.ceil(highx/highy); - } - do { - var check = a.multiplySingleDigit(guess); - if (check.compareAbs(part) <= 0) { - break; - } - guess--; - } while (guess); - - quot.push(guess); - if (!guess) { - continue; - } - var diff = part.subtract(check); - part._d = diff._d.slice(); - } - - return [new BigInteger(quot.reverse(), sign, CONSTRUCT), - new BigInteger(part._d, this._s, CONSTRUCT)]; -}; - -// Throws an exception if n is outside of (-BigInteger.base, -1] or -// [1, BigInteger.base). It's not necessary to call this, since the -// other division functions will call it if they are able to. -BigInteger.prototype.divRemSmall = function(n) { - var r; - n = +n; - if (n === 0) { - throw new Error("Divide by zero"); - } - - var n_s = n < 0 ? -1 : 1; - var sign = this._s * n_s; - n = Math.abs(n); - - if (n < 1 || n >= BigInteger_base) { - throw new Error("Argument out of range"); - } - - if (this._s === 0) { - return [ZERO, ZERO]; - } - - if (n === 1 || n === -1) { - return [(sign === 1) ? this.abs() : new BigInteger(this._d, sign, CONSTRUCT), ZERO]; - } - - // 2 <= n < BigInteger_base - - // divide a single digit by a single digit - if (this._d.length === 1) { - var q = new BigInteger([(this._d[0] / n) | 0], 1, CONSTRUCT); - r = new BigInteger([(this._d[0] % n) | 0], 1, CONSTRUCT); - if (sign < 0) { - q = q.negate(); - } - if (this._s < 0) { - r = r.negate(); - } - return [q, r]; - } - - var digits = this._d.slice(); - var quot = new Array(digits.length); - var part = 0; - var diff = 0; - var i = 0; - var guess; - - while (digits.length) { - part = part * BigInteger_base + digits[digits.length - 1]; - if (part < n) { - quot[i++] = 0; - digits.pop(); - diff = BigInteger_base * diff + part; - continue; - } - if (part === 0) { - guess = 0; - } - else { - guess = (part / n) | 0; - } - - var check = n * guess; - diff = part - check; - quot[i++] = guess; - if (!guess) { - digits.pop(); - continue; - } - - digits.pop(); - part = diff; - } - - r = new BigInteger([diff], 1, CONSTRUCT); - if (this._s < 0) { - r = r.negate(); - } - return [new BigInteger(quot.reverse(), sign, CONSTRUCT), r]; -}; - -/* - Function: isEven - Return true iff *this* is divisible by two. - - Note that is even. - - Returns: - - true if *this* is even, false otherwise. - - See Also: - - -*/ -BigInteger.prototype.isEven = function() { - var digits = this._d; - return this._s === 0 || digits.length === 0 || (digits[0] % 2) === 0; -}; - -/* - Function: isOdd - Return true iff *this* is not divisible by two. - - Returns: - - true if *this* is odd, false otherwise. - - See Also: - - -*/ -BigInteger.prototype.isOdd = function() { - return !this.isEven(); -}; - -/* - Function: sign - Get the sign of a . - - Returns: - - * -1 if *this* < 0 - * 0 if *this* == 0 - * +1 if *this* > 0 - - See Also: - - , , , , -*/ -BigInteger.prototype.sign = function() { - return this._s; -}; - -/* - Function: isPositive - Return true iff *this* > 0. - - Returns: - - true if *this*.compare() == 1. - - See Also: - - , , , , , -*/ -BigInteger.prototype.isPositive = function() { - return this._s > 0; -}; - -/* - Function: isNegative - Return true iff *this* < 0. - - Returns: - - true if *this*.compare() == -1. - - See Also: - - , , , , , -*/ -BigInteger.prototype.isNegative = function() { - return this._s < 0; -}; - -/* - Function: isZero - Return true iff *this* == 0. - - Returns: - - true if *this*.compare() == 0. - - See Also: - - , , , , -*/ -BigInteger.prototype.isZero = function() { - return this._s === 0; -}; - -/* - Function: exp10 - Multiply a by a power of 10. - - This is equivalent to, but faster than - - > if (n >= 0) { - > return this.multiply(BigInteger("1e" + n)); - > } - > else { // n <= 0 - > return this.quotient(BigInteger("1e" + -n)); - > } - - Parameters: - - n - The power of 10 to multiply *this* by. *n* is converted to a - javascipt number and must be no greater than - (0x7FFFFFFF), or an exception will be thrown. - - Returns: - - *this* * (10 ** *n*), truncated to an integer if necessary. - - See Also: - - , -*/ -BigInteger.prototype.exp10 = function(n) { - n = +n; - if (n === 0) { - return this; - } - if (Math.abs(n) > Number(MAX_EXP)) { - throw new Error("exponent too large in BigInteger.exp10"); - } - // Optimization for this == 0. This also keeps us from having to trim zeros in the positive n case - if (this._s === 0) { - return ZERO; - } - if (n > 0) { - var k = new BigInteger(this._d.slice(), this._s, CONSTRUCT); - - for (; n >= BigInteger_base_log10; n -= BigInteger_base_log10) { - k._d.unshift(0); - } - if (n == 0) - return k; - k._s = 1; - k = k.multiplySingleDigit(Math.pow(10, n)); - return (this._s < 0 ? k.negate() : k); - } else if (-n >= this._d.length*BigInteger_base_log10) { - return ZERO; - } else { - var k = new BigInteger(this._d.slice(), this._s, CONSTRUCT); - - for (n = -n; n >= BigInteger_base_log10; n -= BigInteger_base_log10) { - k._d.shift(); - } - return (n == 0) ? k : k.divRemSmall(Math.pow(10, n))[0]; - } -}; - -/* - Function: pow - Raise a to a power. - - In this implementation, 0**0 is 1. - - Parameters: - - n - The exponent to raise *this* by. *n* must be no greater than - (0x7FFFFFFF), or an exception will be thrown. - - Returns: - - *this* raised to the *nth* power. - - See Also: - - -*/ -BigInteger.prototype.pow = function(n) { - if (this.isUnit()) { - if (this._s > 0) { - return this; - } - else { - return BigInteger(n).isOdd() ? this : this.negate(); - } - } - - n = BigInteger(n); - if (n._s === 0) { - return ONE; - } - else if (n._s < 0) { - if (this._s === 0) { - throw new Error("Divide by zero"); - } - else { - return ZERO; - } - } - if (this._s === 0) { - return ZERO; - } - if (n.isUnit()) { - return this; - } - - if (n.compareAbs(MAX_EXP) > 0) { - throw new Error("exponent too large in BigInteger.pow"); - } - var x = this; - var aux = ONE; - var two = BigInteger.small[2]; - - while (n.isPositive()) { - if (n.isOdd()) { - aux = aux.multiply(x); - if (n.isUnit()) { - return aux; - } - } - x = x.square(); - n = n.quotient(two); - } - - return aux; -}; - -/* - Function: modPow - Raise a to a power (mod m). - - Because it is reduced by a modulus, is not limited by - like . - - Parameters: - - exponent - The exponent to raise *this* by. Must be positive. - modulus - The modulus. - - Returns: - - *this* ^ *exponent* (mod *modulus*). - - See Also: - - , -*/ -BigInteger.prototype.modPow = function(exponent, modulus) { - var result = ONE; - var base = this; - - while (exponent.isPositive()) { - if (exponent.isOdd()) { - result = result.multiply(base).remainder(modulus); - } - - exponent = exponent.quotient(BigInteger.small[2]); - if (exponent.isPositive()) { - base = base.square().remainder(modulus); - } - } - - return result; -}; - -/* - Function: log - Get the natural logarithm of a as a native JavaScript number. - - This is equivalent to - - > Math.log(this.toJSValue()) - - but handles values outside of the native number range. - - Returns: - - log( *this* ) - - See Also: - - -*/ -BigInteger.prototype.log = function() { - switch (this._s) { - case 0: return -Infinity; - case -1: return NaN; - default: // Fall through. - } - - var l = this._d.length; - - if (l*BigInteger_base_log10 < 30) { - return Math.log(this.valueOf()); - } - - var N = Math.ceil(30/BigInteger_base_log10); - var firstNdigits = this._d.slice(l - N); - return Math.log((new BigInteger(firstNdigits, 1, CONSTRUCT)).valueOf()) + (l - N) * Math.log(BigInteger_base); -}; - -/* - Function: valueOf - Convert a to a native JavaScript integer. - - This is called automatically by JavaScipt to convert a to a - native value. - - Returns: - - > parseInt(this.toString(), 10) - - See Also: - - , -*/ -BigInteger.prototype.valueOf = function() { - return parseInt(this.toString(), 10); -}; - -/* - Function: toJSValue - Convert a to a native JavaScript integer. - - This is the same as valueOf, but more explicitly named. - - Returns: - - > parseInt(this.toString(), 10) - - See Also: - - , -*/ -BigInteger.prototype.toJSValue = function() { - return parseInt(this.toString(), 10); -}; - -/* - Function: lowVal - Author: Lucas Jones -*/ -BigInteger.prototype.lowVal = function () { - return this._d[0] || 0; -}; - -var MAX_EXP = BigInteger(0x7FFFFFFF); -// Constant: MAX_EXP -// The largest exponent allowed in and (0x7FFFFFFF or 2147483647). -BigInteger.MAX_EXP = MAX_EXP; - -(function() { - function makeUnary(fn) { - return function(a) { - return fn.call(BigInteger(a)); - }; - } - - function makeBinary(fn) { - return function(a, b) { - return fn.call(BigInteger(a), BigInteger(b)); - }; - } - - function makeTrinary(fn) { - return function(a, b, c) { - return fn.call(BigInteger(a), BigInteger(b), BigInteger(c)); - }; - } - - (function() { - var i, fn; - var unary = "toJSValue,isEven,isOdd,sign,isZero,isNegative,abs,isUnit,square,negate,isPositive,toString,next,prev,log".split(","); - var binary = "compare,remainder,divRem,subtract,add,quotient,divide,multiply,pow,compareAbs".split(","); - var trinary = ["modPow"]; - - for (i = 0; i < unary.length; i++) { - fn = unary[i]; - BigInteger[fn] = makeUnary(BigInteger.prototype[fn]); - } - - for (i = 0; i < binary.length; i++) { - fn = binary[i]; - BigInteger[fn] = makeBinary(BigInteger.prototype[fn]); - } - - for (i = 0; i < trinary.length; i++) { - fn = trinary[i]; - BigInteger[fn] = makeTrinary(BigInteger.prototype[fn]); - } - - BigInteger.exp10 = function(x, n) { - return BigInteger(x).exp10(n); - }; - })(); -})(); - -exports.BigInteger = BigInteger; -})(typeof exports !== 'undefined' ? exports : this); \ No newline at end of file diff --git a/src/main/js/daemon/MoneroDaemon.js b/src/main/js/daemon/MoneroDaemon.js deleted file mode 100644 index 5c9de4a7f..000000000 --- a/src/main/js/daemon/MoneroDaemon.js +++ /dev/null @@ -1,690 +0,0 @@ -/** - * Copyright (c) woodser - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Monero daemon interface and default implementations. - * - * @interface - */ -class MoneroDaemon { - - /** - * Indicates if the client is connected to the daemon via RPC. - * - * @return {boolean} true if the client is connected to the daemon, false otherwise - */ - async isConnected() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Gets the version of the daemon. - * - * @return {MoneroVersion} the version of the daemon - */ - async getVersion() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Indicates if the daemon is trusted xor untrusted. - * - * @return {boolean} true if the daemon is trusted, false otherwise - */ - async isTrusted() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get the number of blocks in the longest chain known to the node. - * - * @return {int} the number of blocks - */ - async getHeight() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get a block's hash by its height. - * - * @param {int} height - height of the block hash to get - * @return {string} the block's hash at the given height - */ - async getBlockHash(height) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get a block template for mining a new block. - * - * @param {string} walletAddress - address of the wallet to receive miner transactions if block is successfully mined - * @param {int} reserveSize - reserve size (optional) - * @return {MoneroBlockTemplate} is a block template for mining a new block - */ - async getBlockTemplate(walletAddress, reserveSize) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get the last block's header. - * - * @return {MoneroBlockHeader} last block's header - */ - async getLastBlockHeader() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get a block header by its hash. - * - * @param {string} blockHash - hash of the block to get the header of - * @return {MoneroBlockHeader} block's header - */ - async getBlockHeaderByHash(blockHash) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get a block header by its height. - * - * @param {int} height - height of the block to get the header of - * @return {MoneroBlockHeader} block's header - */ - async getBlockHeaderByHeight(height) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get block headers for the given range. - * - * @param {int} startHeight - start height lower bound inclusive (optional) - * @param {int} endHeight - end height upper bound inclusive (optional) - * @return {MoneroBlockHeader[]} for the given range - */ - async getBlockHeadersByRange(startHeight, endHeight) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get a block by hash. - * - * @param {string} blockHash - hash of the block to get - * @return {MoneroBlock} with the given hash - */ - async getBlockByHash(blockHash) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get blocks by hash. - * - * @param {string[]} blockHashes - array of hashes; first 10 blocks hashes goes sequential, - * next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, - * and the last one is always genesis block - * @param {int} startHeight - start height to get blocks by hash - * @param {boolean} prune - specifies if returned blocks should be pruned (defaults to false) // TODO: test default - * @return {MoneroBlock[]} retrieved blocks - */ - async getBlocksByHash(blockHashes, startHeight, prune) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get a block by height. - * - * @param {int} height - height of the block to get - * @return {MoneroBlock} with the given height - */ - async getBlockByHeight(height) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get blocks at the given heights. - * - * @param {int[]} heights - heights of the blocks to get - * @return {MoneroBlock[]} are blocks at the given heights - */ - async getBlocksByHeight(heights) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get blocks in the given height range. - * - * @param {int} startHeight - start height lower bound inclusive (optional) - * @param {int} endHeight - end height upper bound inclusive (optional) - * @return {MoneroBlock[]} are blocks in the given height range - */ - async getBlocksByRange(startHeight, endHeight) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get blocks in the given height range as chunked requests so that each request is - * not too big. - * - * @param {int} startHeight - start height lower bound inclusive (optional) - * @param {int} endHeight - end height upper bound inclusive (optional) - * @param {int} maxChunkSize - maximum chunk size in any one request (default 3,000,000 bytes) - * @return {MoneroBlock[]} blocks in the given height range - */ - async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get block hashes as a binary request to the daemon. - * - * @param {string[]} blockHashes - specify block hashes to fetch; first 10 blocks hash goes - * sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 - * and so on, and the last one is always genesis block - * @param {int} startHeight - starting height of block hashes to return - * @return {string[]} requested block hashes - */ - async getBlockHashes(blockHashes, startHeight) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get a transaction by hash. - * - * @param {string} txHash - hash of the transaction to get - * @param {boolean} prune - specifies if the returned tx should be pruned (defaults to false) - * @return {MoneroTx} transaction with the given hash - */ - async getTx(txHash, prune = false) { - return (await this.getTxs([txHash], prune))[0]; - } - - /** - * Get transactions by hashes. - * - * @param {string[]} txHashes - hashes of transactions to get - * @param {boolean} prune - specifies if the returned txs should be pruned (defaults to false) - * @return {MoneroTx[]} transactions with the given hashes - */ - async getTxs(txHashes, prune = false) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get a transaction hex by hash. - * - * @param {string} txHash - hash of the transaction to get hex from - * @param {boolean} prune - specifies if the returned tx hex should be pruned (defaults to false) - * @return {string} tx hex with the given hash - */ - async getTxHex(txHash, prune = false) { - return (await this.getTxHexes([txHash], prune))[0]; - } - - /** - * Get transaction hexes by hashes. - * - * @param {string[]} txHashes - hashes of transactions to get hexes from - * @param {boolean} prune - specifies if the returned tx hexes should be pruned (defaults to false) - * @return {string[]} tx hexes - */ - async getTxHexes(txHashes, prune = false) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Gets the total emissions and fees from the genesis block to the current height. - * - * @param {int} height - height to start computing the miner sum - * @param {int} numBlocks - number of blocks to include in the sum - * @return {MoneroMinerTxSum} encapsulates the total emissions and fees since the genesis block - */ - async getMinerTxSum(height, numBlocks) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get the fee estimate per kB. - * - * @param {int} graceBlocks TODO - * @return {BigInteger} fee estimate per kB. - */ - async getFeeEstimate(graceBlocks) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Submits a transaction to the daemon's pool. - * - * @param {string} txHex - raw transaction hex to submit - * @param {boolean} doNotRelay specifies if the tx should be relayed (optional) - * @return {MoneroSubmitTxResult} contains submission results - */ - async submitTxHex(txHex, doNotRelay) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Relays a transaction by hash. - * - * @param {string} txHash - hash of the transaction to relay - */ - async relayTxByHash(txHash) { - const assert = require("assert"); - assert.equal(typeof txHash, "string", "Must provide a transaction hash"); - await this.relayTxsByHash([txHash]); - } - - /** - * Relays transactions by hash. - * - * @param {string[]} txHashes - hashes of the transactinos to relay - */ - async relayTxsByHash(txHashes) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get valid transactions seen by the node but not yet mined into a block, as well - * as spent key image information for the tx pool. - * - * @return {MoneroTx[]} are transactions in the transaction pool - */ - async getTxPool() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get hashes of transactions in the transaction pool. - * - * @return {string[]} are hashes of transactions in the transaction pool - */ - async getTxPoolHashes() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get all transaction pool backlog. - * - * @return {MoneroTxBacklogEntry[]} backlog entries - */ - async getTxPoolBacklog() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get transaction pool statistics. - * - * @return {MoneroTxPoolStats} contains statistics about the transaction pool - */ - async getTxPoolStats() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Flush transactions from the tx pool. - * - * @param {(string|string[])} hashes - specific transactions to flush (defaults to all) - */ - async flushTxPool(hashes) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get the spent status of the given key image. - * - * @param {string} keyImage - key image hex to get the status of - * @return {MoneroKeyImageSpentStatus} status of the key image - */ - async getKeyImageSpentStatus(keyImage) { - return (await this.getKeyImageSpentStatuses([keyImage]))[0]; - } - - /** - * Get the spent status of each given key image. - * - * @param {string[]} keyImages are hex key images to get the statuses of - * @return {MoneroKeyImageSpentStatus[]} status for each key image - */ - async getKeyImageSpentStatuses(keyImages) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get outputs identified by a list of output amounts and indices as a binary - * request. - * - * @param {MoneroOutput[]} outputs - identify each output by amount and index - * @return {MoneroOutput[]} identified outputs - */ - async getOutputs(outputs) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get a histogram of output amounts. For all amounts (possibly filtered by - * parameters), gives the number of outputs on the chain for that amount. - * RingCT outputs counts as 0 amount. - * - * @param {BigInteger[]} amounts - amounts of outputs to make the histogram with - * @param {int} minCount - TODO - * @param {int} maxCount - TODO - * @param {boolean} isUnlocked - makes a histogram with outputs with the specified lock state - * @param {int} recentCutoff - TODO - * @return {MoneroOutputHistogramEntry[]} are entries meeting the parameters - */ - async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Creates an output distribution. - * - * @param {BigInteger[]} amounts - amounts of outputs to make the distribution with - * @param {boolean} cumulative - specifies if the results should be cumulative (defaults to TODO) - * @param {int} startHeight - start height lower bound inclusive (optional) - * @param {int} endHeight - end height upper bound inclusive (optional) - * @return {MoneroOutputDistributionEntry[]} are entries meeting the parameters - */ - async getOutputDistribution(amounts, cumulative, startHeight, endHeight) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get general information about the state of the node and the network. - * - * @return {MoneroDaemonInfo} is general information about the node and network - */ - async getInfo() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get synchronization information. - * - * @return {MoneroDaemonSyncInfo} contains sync information - */ - async getSyncInfo() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Look up information regarding hard fork voting and readiness. - * - * @return {MoneroHardForkInfo} contains hard fork information - */ - async getHardForkInfo() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get alternative chains seen by the node. - * - * @return {MoneroAltChain[]} alternative chains - */ - async getAltChains() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get known block hashes which are not on the main chain. - * - * @return {string[]} known block hashes which are not on the main chain - */ - async getAltBlockHashes() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get the download bandwidth limit. - * - * @return {int} download bandwidth limit - */ - async getDownloadLimit() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Set the download bandwidth limit. - * - * @param {int} limit - download limit to set (-1 to reset to default) - * @return {int} new download limit after setting - */ - async setDownloadLimit(limit) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Reset the download bandwidth limit. - * - * @return {int} download bandwidth limit after resetting - */ - async resetDownloadLimit() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get the upload bandwidth limit. - * - * @return {int} upload bandwidth limit - */ - async getUploadLimit() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Set the upload bandwidth limit. - * - * @param limit - upload limit to set (-1 to reset to default) - * @return {int} new upload limit after setting - */ - async setUploadLimit(limit) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Reset the upload bandwidth limit. - * - * @return {int} upload bandwidth limit after resetting - */ - async resetUploadLimit() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get known peers including their last known online status. - * - * @return {MoneroDaemonPeer[]} known peers - */ - async getKnownPeers() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get incoming and outgoing connections to the node. - * - * @return {MoneroDaemonConnection[]} daemon's peer connections - */ - async getConnections() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Limit number of outgoing peers. - * - * @param {int} limit - maximum number of outgoing peers - */ - async setOutgoingPeerLimit(limit) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Limit number of incoming peers. - * - * @param {int} limit - maximum number of incoming peers - */ - async setIncomingPeerLimit(limit) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get peer bans. - * - * @return {MoneroBan[]} entries about banned peers - */ - async getPeerBans() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Ban a peer node. - * - * @param {MoneroBan} ban - contains information about a node to ban - */ - async setPeerBan(ban) { - return await this.setPeerBans([ban]); - } - - /** - * Ban peers nodes. - * - * @param {MoneroBan[]} bans - specify which peers to ban - */ - async setPeerBans(bans) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Start mining. - * - * @param {string} address - address given miner rewards if the daemon mines a block - * @param {integer} numThreads - number of mining threads to run - * @param {boolean} isBackground - specifies if the miner should run in the background or not - * @param {boolean} ignoreBattery - specifies if the battery state (e.g. on laptop) should be ignored or not - */ - async startMining(address, numThreads, isBackground, ignoreBattery) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Stop mining. - */ - async stopMining() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get the daemon's mining status. - * - * @return {MoneroMiningStatus} daemon's mining status - */ - async getMiningStatus() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Submit a mined block to the network. - * - * @param {string} blockBlob - mined block to submit - */ - async submitBlock(blockBlob) { - await this.submitBlocks([blockBlob]); - } - - /** - * Submit mined blocks to the network. - * - * @param {string[]} blockBlobs - mined blocks to submit - */ - async submitBlocks(blockBlobs) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Check for update. - * - * @return {MoneroDaemonUpdateCheckResult} the result - */ - async checkForUpdate() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Download an update. - * - * @param {string} path - path to download the update (optional) - * @return {MoneroDaemonUpdateDownloadResult} the result - */ - async downloadUpdate(path) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Safely disconnect and shut down the daemon. - */ - async stop() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Get the header of the next block added to the chain. - * - * @return {MoneroBlockHeader} header of the next block added to the chain - */ - async getNextBlockHeader() { - throw new MoneroError("Subclass must implement"); - } - - /** - * Register a listener to be notified when blocks are added to the chain. - * - * @param {function} listener - invoked with MoneroBlockHeaders as blocks are added to the chain - */ - async addBlockListener(listener) { - throw new MoneroError("Subclass must implement"); - } - - /** - * Unregister a listener to be notified when blocks are added to the chain. - * - * @param {function} listener - previously registered listener to be unregistered - */ - async removeBlockListener(listener) { - throw new MoneroError("Subclass must implement"); - } - - // ----------------------------- STATIC UTILITIES --------------------------- - - /** - * Parses a network string to an enumerated type. - * - * @param {string} network - network string to parse - * @return {MoneroNetworkType} enumerated network type - */ - static parseNetworkType(network) { - const MoneroNetworkType = require("./model/MoneroNetworkType"); - if (network === "mainnet") return MoneroNetworkType.MAINNET; - if (network === "testnet") return MoneroNetworkType.TESTNET; - if (network === "stagenet") return MoneroNetworkType.STAGENET; - throw new MoneroError("Invalid network type to parse: " + network); - } -} - -module.exports = MoneroDaemon; \ No newline at end of file diff --git a/src/main/js/daemon/MoneroDaemonRpc.js b/src/main/js/daemon/MoneroDaemonRpc.js deleted file mode 100644 index 64de24fed..000000000 --- a/src/main/js/daemon/MoneroDaemonRpc.js +++ /dev/null @@ -1,1789 +0,0 @@ -const assert = require("assert"); -const BigInteger = require("../common/biginteger").BigInteger; -const GenUtils = require("../common/GenUtils"); -const LibraryUtils = require("../common/LibraryUtils"); -const MoneroAltChain = require("./model/MoneroAltChain"); -const MoneroBan = require("./model/MoneroBan"); -const MoneroBlock = require("./model/MoneroBlock"); -const MoneroBlockHeader = require("./model/MoneroBlockHeader"); -const MoneroBlockTemplate = require("./model/MoneroBlockTemplate"); -const MoneroDaemon = require("./MoneroDaemon"); -const MoneroDaemonConnection = require("./model/MoneroDaemonConnection"); -const MoneroDaemonInfo = require("./model/MoneroDaemonInfo"); -const MoneroDaemonPeer = require("./model/MoneroDaemonPeer"); -const MoneroDaemonSyncInfo = require("./model/MoneroDaemonSyncInfo"); -const MoneroError = require("../common/MoneroError"); -const MoneroHardForkInfo = require("./model/MoneroHardForkInfo"); -const MoneroKeyImage = require("./model/MoneroKeyImage"); -const MoneroMinerTxSum = require("./model/MoneroMinerTxSum"); -const MoneroMiningStatus = require("./model/MoneroMiningStatus"); -const MoneroNetworkType = require("./model/MoneroNetworkType"); -const MoneroOutput = require("./model/MoneroOutput"); -const MoneroOutputHistogramEntry = require("./model/MoneroOutputHistogramEntry"); -const MoneroRpcConnection = require("../common/MoneroRpcConnection"); -const MoneroSubmitTxResult = require("./model/MoneroSubmitTxResult"); -const MoneroTx = require("./model/MoneroTx"); -const MoneroUtils = require("../common/MoneroUtils"); -const MoneroVersion = require("./model/MoneroVersion"); - -/** - * Copyright (c) woodser - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Implements a MoneroDaemon as a client of monero-daemon-rpc. - * - * @implements {MoneroDaemon} - */ -class MoneroDaemonRpc extends MoneroDaemon { - - /** - *

Construct a daemon RPC client.

- * - *

Examples:

- * - * - * let daemon = new MoneroDaemonRpc("http://localhost:38081", "superuser", "abctesting123");

- * - * let daemon = new MoneroDaemonRpc({
- *    uri: "http://localhost:38081",
- *    username: "superuser",
- *    password: "abctesting123"
- * }); - *
- * - * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - uri of monero-daemon-rpc or JS config object or MoneroRpcConnection - * @param {string} uriOrConfigOrConnection.uri - uri of monero-daemon-rpc - * @param {string} uriOrConfigOrConnection.username - username to authenticate with monero-daemon-rpc (optional) - * @param {string} uriOrConfigOrConnection.password - password to authenticate with monero-daemon-rpc (optional) - * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true) - * @param {number} uriOrConfigOrConnection.pollInterval - poll interval to query for updates in ms (default 5000) - * @param {boolean} uriOrConfigOrConnection.proxyToWorker - run the daemon client in a web worker if true (default true if browser, false otherwise) - * @param {string} username - username to authenticate with monero-daemon-rpc (optional) - * @param {string} password - password to authenticate with monero-daemon-rpc (optional) - * @param {boolean} rejectUnauthorized - rejects self-signed certificates if true (default true) - * @param {number} pollInterval - poll interval to query for updates in ms (default 5000) - * @param {boolean} proxyToWorker - runs the daemon client in a web worker if true (default true if browser, false otherwise) - */ - constructor(uriOrConfigOrConnection, username, password, rejectUnauthorized, pollInterval, proxyToWorker) { - super(); - - // normalize configuration - this.config = MoneroDaemonRpc._normalizeConfig(uriOrConfigOrConnection, username, password, rejectUnauthorized, pollInterval, proxyToWorker); - - // initialize proxy if proxying to worker - if (this.config.proxyToWorker) this._proxyPromise = MoneroDaemonRpcProxy.connect(this.config); - else { - this.rpc = new MoneroRpcConnection(this.config); - this.listeners = []; // block listeners - this.cachedHeaders = {}; // cached headers for fetching blocks in bound chunks - } - } - - /** - * Get the daemon's RPC connection. - * - * @return {MoneroRpcConnection} the daemon's rpc connection - */ - async getRpcConnection() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getRpcConnection(); - return this.rpc; - } - - async isConnected() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).isConnected(); - try { - await this.getHeight(); - return true; - } catch (e) { - return false; - } - } - - async getVersion() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getVersion(); - let resp = await this.rpc.sendJsonRequest("get_version"); - MoneroDaemonRpc._checkResponseStatus(resp.result); - return new MoneroVersion(resp.result.version, resp.result.release); - } - - async isTrusted() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).isTrusted(); - let resp = await this.rpc.sendPathRequest("get_height"); - MoneroDaemonRpc._checkResponseStatus(resp); - return !resp.untrusted; - } - - async getHeight() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getHeight(); - let resp = await this.rpc.sendJsonRequest("get_block_count"); - MoneroDaemonRpc._checkResponseStatus(resp.result); - return resp.result.count; - } - - async getBlockHash(height) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockHash(height); - return (await this.rpc.sendJsonRequest("on_get_block_hash", [height])).result; // TODO monero-wallet-rpc: no status returned - } - - async getBlockTemplate(walletAddress, reserveSize) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockTemplate(walletAddress, reserveSize); - assert(walletAddress && typeof walletAddress === "string", "Must specify wallet address to be mined to"); - let resp = await this.rpc.sendJsonRequest("get_block_template", {wallet_address: walletAddress, reserve_size: reserveSize}); - MoneroDaemonRpc._checkResponseStatus(resp.result); - return MoneroDaemonRpc._convertRpcBlockTemplate(resp.result); - } - - async getLastBlockHeader() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getLastBlockHeader(); - let resp = await this.rpc.sendJsonRequest("get_last_block_header"); - MoneroDaemonRpc._checkResponseStatus(resp.result); - return MoneroDaemonRpc._convertRpcBlockHeader(resp.result.block_header); - } - - async getBlockHeaderByHash(blockHash) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockHeaderByHash(blockHash); - let resp = await this.rpc.sendJsonRequest("get_block_header_by_hash", {hash: blockHash}); - MoneroDaemonRpc._checkResponseStatus(resp.result); - return MoneroDaemonRpc._convertRpcBlockHeader(resp.result.block_header); - } - - async getBlockHeaderByHeight(height) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockHeaderByHeight(height); - let resp = await this.rpc.sendJsonRequest("get_block_header_by_height", {height: height}); - MoneroDaemonRpc._checkResponseStatus(resp.result); - return MoneroDaemonRpc._convertRpcBlockHeader(resp.result.block_header); - } - - async getBlockHeadersByRange(startHeight, endHeight) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockHeadersByRange(startHeight, endHeight); - - // fetch block headers - let resp = await this.rpc.sendJsonRequest("get_block_headers_range", { - start_height: startHeight, - end_height: endHeight - }); - MoneroDaemonRpc._checkResponseStatus(resp.result); - - // build headers - let headers = []; - for (let rpcHeader of resp.result.headers) { - headers.push(MoneroDaemonRpc._convertRpcBlockHeader(rpcHeader)); - } - return headers; - } - - async getBlockByHash(blockHash) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockByHash(blockHash); - let resp = await this.rpc.sendJsonRequest("get_block", {hash: blockHash}); - MoneroDaemonRpc._checkResponseStatus(resp.result); - return MoneroDaemonRpc._convertRpcBlock(resp.result); - } - - async getBlockByHeight(height) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlockByHeight(height); - let resp = await this.rpc.sendJsonRequest("get_block", {height: height}); - MoneroDaemonRpc._checkResponseStatus(resp.result); - return MoneroDaemonRpc._convertRpcBlock(resp.result); - } - - async getBlocksByHeight(heights) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlocksByHeight(heights); - - // fetch blocks in binary - let respBin = await this.rpc.sendBinaryRequest("get_blocks_by_height.bin", {heights: heights}); - - // load wasm module - await LibraryUtils.loadKeysModule(); - - // convert binary blocks to json - let rpcBlocks = MoneroUtils.binaryBlocksToJson(respBin); - MoneroDaemonRpc._checkResponseStatus(rpcBlocks); - //console.log(JSON.stringify(rpcBlocks)); - - // build blocks with transactions - assert.equal(rpcBlocks.txs.length, rpcBlocks.blocks.length); - let blocks = []; - for (let blockIdx = 0; blockIdx < rpcBlocks.blocks.length; blockIdx++) { - - // build block - let block = MoneroDaemonRpc._convertRpcBlock(rpcBlocks.blocks[blockIdx]); - block.setHeight(heights[blockIdx]); - blocks.push(block); - - // build transactions - let txs = []; - for (let txIdx = 0; txIdx < rpcBlocks.txs[blockIdx].length; txIdx++) { - let tx = new MoneroTx(); - txs.push(tx); - tx.setHash(rpcBlocks.blocks[blockIdx].tx_hashes[txIdx]); - tx.setIsConfirmed(true); - tx.setInTxPool(false); - tx.setIsMinerTx(false); - tx.setRelay(true); - tx.setIsRelayed(true); - tx.setIsFailed(false); - tx.setIsDoubleSpend(false); - MoneroDaemonRpc._convertRpcTx(rpcBlocks.txs[blockIdx][txIdx], tx); - } - - // merge into one block - block.setTxs([]); - for (let tx of txs) { - if (tx.getBlock()) block.merge(tx.getBlock()); - else block.getTxs().push(tx.setBlock(block)); - } - } - - return blocks; - } - - async getBlocksByRange(startHeight, endHeight) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlocksByRange(startHeight, endHeight); - if (startHeight === undefined) startHeight = 0; - if (endHeight === undefined) endHeight = await this.getHeight() - 1; - let heights = []; - for (let height = startHeight; height <= endHeight; height++) heights.push(height); - return await this.getBlocksByHeight(heights); - } - - async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize); - if (startHeight === undefined) startHeight = 0; - if (endHeight === undefined) endHeight = await this.getHeight() - 1; - let lastHeight = startHeight - 1; - let blocks = []; - while (lastHeight < endHeight) { - for (let block of await this._getMaxBlocks(lastHeight + 1, endHeight, maxChunkSize)) { - blocks.push(block); - } - lastHeight = blocks[blocks.length - 1].getHeight(); - } - return blocks; - } - - async getTxs(txHashes, prune) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getTxs(txHashes, prune); - - // validate input - assert(Array.isArray(txHashes) && txHashes.length > 0, "Must provide an array of transaction hashes"); - assert(prune === undefined || typeof prune === "boolean", "Prune must be a boolean or undefined"); - - // fetch transactions - let resp = await this.rpc.sendPathRequest("get_transactions", { - txs_hashes: txHashes, - decode_as_json: true, - prune: prune - }); - try { - MoneroDaemonRpc._checkResponseStatus(resp); - } catch (e) { - if (e.message.indexOf("Failed to parse hex representation of transaction hash") >= 0) throw new MoneroError("Invalid transaction hash"); - throw e; - } - - // build transaction models - let txs = []; - if (resp.txs) { - for (let txIdx = 0; txIdx < resp.txs.length; txIdx++) { - let tx = new MoneroTx(); - tx.setIsMinerTx(false); - txs.push(MoneroDaemonRpc._convertRpcTx(resp.txs[txIdx], tx)); - } - } - - // fetch unconfirmed txs from pool and merge additional fields // TODO monero-daemon-rpc: merge rpc calls so this isn't necessary? - let poolTxs = await this.getTxPool(); - for (let tx of txs) { - for (let poolTx of poolTxs) { - if (tx.getHash() === poolTx.getHash()) tx.merge(poolTx); - } - } - - return txs; - } - - async getTxHexes(txHashes, prune) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getTxHexes(txHashes, prune); - let hexes = []; - for (let tx of await this.getTxs(txHashes, prune)) hexes.push(prune ? tx.getPrunedHex() : tx.getFullHex()); - return hexes; - } - - async getMinerTxSum(height, numBlocks) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getMinerTxSum(height, numBlocks); - if (height === undefined) height = 0; - else assert(height >= 0, "Height must be an integer >= 0"); - if (numBlocks === undefined) numBlocks = await this.getHeight(); - else assert(numBlocks >= 0, "Count must be an integer >= 0"); - let resp = await this.rpc.sendJsonRequest("get_coinbase_tx_sum", {height: height, count: numBlocks}); - MoneroDaemonRpc._checkResponseStatus(resp.result); - let txSum = new MoneroMinerTxSum(); - txSum.setEmissionSum(new BigInteger(resp.result.emission_amount)); - txSum.setFeeSum(new BigInteger(resp.result.fee_amount)); - return txSum; - } - - async getFeeEstimate(graceBlocks) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getFeeEstimate(graceBlocks); - let resp = await this.rpc.sendJsonRequest("get_fee_estimate", {grace_blocks: graceBlocks}); - MoneroDaemonRpc._checkResponseStatus(resp.result); - return new BigInteger(resp.result.fee); - } - - async submitTxHex(txHex, doNotRelay) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).submitTxHex(txHex, doNotRelay); - let resp = await this.rpc.sendPathRequest("send_raw_transaction", {tx_as_hex: txHex, do_not_relay: doNotRelay}); - let result = MoneroDaemonRpc._convertRpcSubmitTxResult(resp); - - // set isGood based on status - try { - MoneroDaemonRpc._checkResponseStatus(resp); - result.setIsGood(true); - } catch(e) { - result.setIsGood(false); - } - return result; - } - - async relayTxsByHash(txHashes) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).relayTxsByHash(txHashes); - let resp = await this.rpc.sendJsonRequest("relay_tx", {txids: txHashes}); - MoneroDaemonRpc._checkResponseStatus(resp.result); - } - - async getTxPool() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getTxPool(); - - // send rpc request - let resp = await this.rpc.sendPathRequest("get_transaction_pool"); - MoneroDaemonRpc._checkResponseStatus(resp); - - // build txs - let txs = []; - if (resp.transactions) { - for (let rpcTx of resp.transactions) { - let tx = new MoneroTx(); - txs.push(tx); - tx.setIsConfirmed(false); - tx.setIsMinerTx(false); - tx.setInTxPool(true); - tx.setNumConfirmations(0); - MoneroDaemonRpc._convertRpcTx(rpcTx, tx); - } - } - - return txs; - } - - async getTxPoolHashes() { - throw new MoneroError("Not implemented"); - } - - async getTxPoolBacklog() { - throw new MoneroError("Not implemented"); - } - - async getTxPoolStats() { - throw new MoneroError("Response contains field 'histo' which is binary'"); - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getTxPoolStats(); - let resp = await this.rpc.sendPathRequest("get_transaction_pool_stats"); - MoneroDaemonRpc._checkResponseStatus(resp); - let stats = MoneroDaemonRpc._convertRpcTxPoolStats(resp.pool_stats); - - // uninitialize some stats if not applicable - if (stats.getHisto98pc() === 0) stats.setHisto98pc(undefined); - if (stats.getNumTxs() === 0) { - stats.setBytesMin(undefined); - stats.setBytesMed(undefined); - stats.setBytesMax(undefined); - stats.setHisto98pc(undefined); - stats.setOldestTimestamp(undefined); - } - - return stats; - } - - async flushTxPool(hashes) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).flushTxPool(hashes); - if (hashes) hashes = GenUtils.listify(hashes); - let resp = await this.rpc.sendJsonRequest("flush_txpool", {txids: hashes}); - MoneroDaemonRpc._checkResponseStatus(resp.result); - } - - async getKeyImageSpentStatuses(keyImages) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getKeyImageSpentStatuses(keyImages); - if (keyImages === undefined || keyImages.length === 0) throw new MoneroError("Must provide key images to check the status of"); - let resp = await this.rpc.sendPathRequest("is_key_image_spent", {key_images: keyImages}); - MoneroDaemonRpc._checkResponseStatus(resp); - return resp.spent_status; - } - - async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff); - - // send rpc request - let resp = await this.rpc.sendJsonRequest("get_output_histogram", { - amounts: amounts, - min_count: minCount, - max_count: maxCount, - unlocked: isUnlocked, - recent_cutoff: recentCutoff - }); - MoneroDaemonRpc._checkResponseStatus(resp.result); - - // build histogram entries from response - let entries = []; - if (!resp.result.histogram) return entries; - for (let rpcEntry of resp.result.histogram) { - entries.push(MoneroDaemonRpc._convertRpcOutputHistogramEntry(rpcEntry)); - } - return entries; - } - - async getOutputDistribution(amounts, cumulative, startHeight, endHeight) { - throw new MoneroError("Not implemented (response 'distribution' field is binary)"); - -// let amountStrs = []; -// for (let amount of amounts) amountStrs.push(amount.toJSValue()); -// console.log(amountStrs); -// console.log(cumulative); -// console.log(startHeight); -// console.log(endHeight); -// -// // send rpc request -// console.log("*********** SENDING REQUEST *************"); -// if (startHeight === undefined) startHeight = 0; -// let resp = await this.rpc.sendJsonRequest("get_output_distribution", { -// amounts: amountStrs, -// cumulative: cumulative, -// from_height: startHeight, -// to_height: endHeight -// }); -// -// console.log("RESPONSE"); -// console.log(resp); -// -// // build distribution entries from response -// let entries = []; -// if (!resp.result.distributions) return entries; -// for (let rpcEntry of resp.result.distributions) { -// let entry = MoneroDaemonRpc._convertRpcOutputDistributionEntry(rpcEntry); -// entries.push(entry); -// } -// return entries; - } - - async getInfo() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getInfo(); - let resp = await this.rpc.sendJsonRequest("get_info"); - MoneroDaemonRpc._checkResponseStatus(resp.result); - return MoneroDaemonRpc._convertRpcInfo(resp.result); - } - - async getSyncInfo() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getSyncInfo(); - let resp = await this.rpc.sendJsonRequest("sync_info"); - MoneroDaemonRpc._checkResponseStatus(resp.result); - return MoneroDaemonRpc._convertRpcSyncInfo(resp.result); - } - - async getHardForkInfo() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getHardForkInfo(); - let resp = await this.rpc.sendJsonRequest("hard_fork_info"); - MoneroDaemonRpc._checkResponseStatus(resp.result); - return MoneroDaemonRpc._convertRpcHardForkInfo(resp.result); - } - - async getAltChains() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getAltChains(); - -// // mocked response for test -// let resp = { -// status: "OK", -// chains: [ -// { -// block_hash: "697cf03c89a9b118f7bdf11b1b3a6a028d7b3617d2d0ed91322c5709acf75625", -// difficulty: 14114729638300280, -// height: 1562062, -// length: 2 -// } -// ] -// } - - let resp = await this.rpc.sendJsonRequest("get_alternate_chains"); - MoneroDaemonRpc._checkResponseStatus(resp.result); - let chains = []; - if (!resp.result.chains) return chains; - for (let rpcChain of resp.result.chains) chains.push(MoneroDaemonRpc._convertRpcAltChain(rpcChain)); - return chains; - } - - async getAltBlockHashes() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getAltBlockHashes(); - -// // mocked response for test -// let resp = { -// status: "OK", -// untrusted: false, -// blks_hashes: ["9c2277c5470234be8b32382cdf8094a103aba4fcd5e875a6fc159dc2ec00e011","637c0e0f0558e284493f38a5fcca3615db59458d90d3a5eff0a18ff59b83f46f","6f3adc174a2e8082819ebb965c96a095e3e8b63929ad9be2d705ad9c086a6b1c","697cf03c89a9b118f7bdf11b1b3a6a028d7b3617d2d0ed91322c5709acf75625"] -// } - - let resp = await this.rpc.sendPathRequest("get_alt_blocks_hashes"); - MoneroDaemonRpc._checkResponseStatus(resp); - if (!resp.blks_hashes) return []; - return resp.blks_hashes; - } - - async getDownloadLimit() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getDownloadLimit(); - return (await this._getBandwidthLimits())[0]; - } - - async setDownloadLimit(limit) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setDownloadLimit(limit); - if (limit == -1) return await this.resetDownloadLimit(); - if (!(GenUtils.isInt(limit) && limit > 0)) throw new MoneroError("Download limit must be an integer greater than 0"); - return (await this._setBandwidthLimits(limit, 0))[0]; - } - - async resetDownloadLimit() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).resetDownloadLimit(); - return (await this._setBandwidthLimits(-1, 0))[0]; - } - - async getUploadLimit() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getUploadLimit(); - return (await this._getBandwidthLimits())[1]; - } - - async setUploadLimit(limit) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setUploadLimit(limit); - if (limit == -1) return await this.resetUploadLimit(); - if (!(GenUtils.isInt(limit) && limit > 0)) throw new MoneroError("Upload limit must be an integer greater than 0"); - return (await this._setBandwidthLimits(0, limit))[1]; - } - - async resetUploadLimit() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).resetUploadLimit(); - return (await this._setBandwidthLimits(0, -1))[1]; - } - - async getConnections() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getConnections(); - let resp = await this.rpc.sendJsonRequest("get_connections"); - MoneroDaemonRpc._checkResponseStatus(resp.result); - let connections = []; - if (!resp.result.connections) return connections; - for (let rpcConnection of resp.result.connections) { - connections.push(MoneroDaemonRpc._convertRpcConnection(rpcConnection)); - } - return connections; - } - - async getKnownPeers() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getKnownPeers(); - - // tx config - let resp = await this.rpc.sendPathRequest("get_peer_list"); - MoneroDaemonRpc._checkResponseStatus(resp); - - // build peers - let peers = []; - if (resp.gray_list) { - for (let rpcPeer of resp.gray_list) { - let peer = MoneroDaemonRpc._convertRpcPeer(rpcPeer); - peer.setIsOnline(false); // gray list means offline last checked - peers.push(peer); - } - } - if (resp.white_list) { - for (let rpcPeer of resp.white_list) { - let peer = MoneroDaemonRpc._convertRpcPeer(rpcPeer); - peer.setIsOnline(true); // white list means online last checked - peers.push(peer); - } - } - return peers; - } - - async setOutgoingPeerLimit(limit) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setOutgoingPeerLimit(limit); - if (!(GenUtils.isInt(limit) && limit >= 0)) throw new MoneroError("Outgoing peer limit must be >= 0"); - let resp = await this.rpc.sendPathRequest("out_peers", {out_peers: limit}); - MoneroDaemonRpc._checkResponseStatus(resp); - } - - async setIncomingPeerLimit(limit) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setIncomingPeerLimit(limit); - if (!(GenUtils.isInt(limit) && limit >= 0)) throw new MoneroError("Incoming peer limit must be >= 0"); - let resp = await this.rpc.sendPathRequest("in_peers", {in_peers: limit}); - MoneroDaemonRpc._checkResponseStatus(resp); - } - - async getPeerBans() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getPeerBans(); - let resp = await this.rpc.sendJsonRequest("get_bans"); - MoneroDaemonRpc._checkResponseStatus(resp.result); - let bans = []; - for (let rpcBan of resp.result.bans) { - let ban = new MoneroBan(); - ban.setHost(rpcBan.host); - ban.setIp(rpcBan.ip); - ban.setSeconds(rpcBan.seconds); - bans.push(ban); - } - return bans; - } - - async setPeerBans(bans) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).setPeerBans(bans); - let rpcBans = []; - for (let ban of bans) rpcBans.push(MoneroDaemonRpc._convertToRpcBan(ban)); - let resp = await this.rpc.sendJsonRequest("set_bans", {bans: rpcBans}); - MoneroDaemonRpc._checkResponseStatus(resp.result); - } - - async startMining(address, numThreads, isBackground, ignoreBattery) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).startMining(address, numThreads, isBackground, ignoreBattery); - assert(address, "Must provide address to mine to"); - assert(GenUtils.isInt(numThreads) && numThreads > 0, "Number of threads must be an integer greater than 0"); - assert(isBackground === undefined || typeof isBackground === "boolean"); - assert(ignoreBattery === undefined || typeof ignoreBattery === "boolean"); - let resp = await this.rpc.sendPathRequest("start_mining", { - miner_address: address, - threads_count: numThreads, - do_background_mining: isBackground, - ignore_battery: ignoreBattery, - }); - MoneroDaemonRpc._checkResponseStatus(resp); - } - - async stopMining() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).stopMining(); - let resp = await this.rpc.sendPathRequest("stop_mining"); - MoneroDaemonRpc._checkResponseStatus(resp); - } - - async getMiningStatus() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getMiningStatus(); - let resp = await this.rpc.sendPathRequest("mining_status"); - MoneroDaemonRpc._checkResponseStatus(resp); - return MoneroDaemonRpc._convertRpcMiningStatus(resp); - } - - async submitBlocks(blockBlobs) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).submitBlocks(blockBlobs); - assert(Array.isArray(blockBlobs) && blockBlobs.length > 0, "Must provide an array of mined block blobs to submit"); - let resp = await this.rpc.sendJsonRequest("submit_block", blockBlobs); - MoneroDaemonRpc._checkResponseStatus(resp.result); - } - - async checkForUpdate() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).checkForUpdate(); - let resp = await this.rpc.sendPathRequest("update", {command: "check"}); - MoneroDaemonRpc._checkResponseStatus(resp); - return MoneroDaemonRpc._convertRpcUpdateCheckResult(resp); - } - - async downloadUpdate(path) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).downloadUpdate(); - let resp = await this.rpc.sendPathRequest("update", {command: "download", path: path}); - MoneroDaemonRpc._checkResponseStatus(resp); - return MoneroDaemonRpc._convertRpcUpdateDownloadResult(resp); - } - - async stop() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).stop(); - let resp = await this.rpc.sendPathRequest("stop_daemon"); - MoneroDaemonRpc._checkResponseStatus(resp); - } - - async getNextBlockHeader() { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).getNextBlockHeader(); - let that = this; - return new Promise(async function(resolve, reject) { - let listener = async function(header) { - resolve(header); - await that.removeBlockListener(listener); - } - await that.addBlockListener(listener); - }); - } - - async addBlockListener(listener) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).addBlockListener(listener); - - // register listener - this.listeners.push(listener); - - // start polling for new blocks - if (!this.isPollingHeaders) this._startPollingHeaders(this.config.pollInterval); - } - - async removeBlockListener(listener) { - if (this.config.proxyToWorker) return (await this._getDaemonProxy()).removeBlockListener(listener); - let found = GenUtils.remove(this.listeners, listener); - assert(found, "Listener is not registered"); - if (this.listeners.length === 0) this._stopPollingHeaders(); - } - - // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS -------------- - - async getTx() { return super.getTx(...arguments); } - async getTxHex() { return super.getTxHex(...arguments); } - async getKeyImageSpentStatus() { return super.getKeyImageSpentStatus(...arguments); } - async setPeerBan() { return super.setPeerBan(...arguments); } - async submitBlock() { return super.submitBlock(...arguments); } - - // ------------------------------- PRIVATE ---------------------------------- - - async _getDaemonProxy() { - return await this._proxyPromise; - } - - async _startPollingHeaders(interval) { - assert(!this.isPollingHeaders, "Daemon is already polling block headers"); - - // get header to detect changes while polling - let lastHeader = await this.getLastBlockHeader(); // TODO: this should be passed in - - // poll until stopped - let that = this; - this.isPollingHeaders = true; - while (this.isPollingHeaders) { - await new Promise(function(resolve) { setTimeout(resolve, interval); }); - let header; - try { - header = await this.getLastBlockHeader(); - } catch (e) { - console.error("Failed to poll last block header, retrying..."); - continue; - } - if (header.getHash() !== lastHeader.getHash()) { - lastHeader = header; - for (let listener of this.listeners) { - listener(header); // notify listener - } - } - } - } - - _stopPollingHeaders() { - this.isPollingHeaders = false; // causes polling loop to exit - } - - async _getBandwidthLimits() { - let resp = await this.rpc.sendPathRequest("get_limit"); - MoneroDaemonRpc._checkResponseStatus(resp); - return [resp.limit_down, resp.limit_up]; - } - - async _setBandwidthLimits(downLimit, upLimit) { - if (downLimit === undefined) downLimit = 0; - if (upLimit === undefined) upLimit = 0; - let resp = await this.rpc.sendPathRequest("set_limit", {limit_down: downLimit, limit_up: upLimit}); - MoneroDaemonRpc._checkResponseStatus(resp); - return [resp.limit_down, resp.limit_up]; - } - - /** - * Get a contiguous chunk of blocks starting from a given height up to a maximum - * height or amount of block data fetched from the blockchain, whichever comes first. - * - * @param {number} startHeight - start height to retrieve blocks (default 0) - * @param {number} maxHeight - maximum end height to retrieve blocks (default blockchain height) - * @param {number} maxReqSize - maximum amount of block data to fetch from the blockchain in bytes (default 3,000,000 bytes) - * @return {MoneroBlock[]} are the resulting chunk of blocks - */ - async _getMaxBlocks(startHeight, maxHeight, maxReqSize) { - if (startHeight === undefined) startHeight = 0; - if (maxHeight === undefined) maxHeight = await this.getHeight() - 1; - if (maxReqSize === undefined) maxReqSize = MoneroDaemonRpc.MAX_REQ_SIZE; - - // determine end height to fetch - let reqSize = 0; - let endHeight = startHeight - 1; - while (reqSize < maxReqSize && endHeight < maxHeight) { - - // get header of next block - let header = await this._getBlockHeaderByHeightCached(endHeight + 1, maxHeight); - - // block cannot be bigger than max request size - assert(header.getSize() <= maxReqSize, "Block exceeds maximum request size: " + header.getSize()); - - // done iterating if fetching block would exceed max request size - if (reqSize + header.getSize() > maxReqSize) break; - - // otherwise block is included - reqSize += header.getSize(); - endHeight++; - } - return endHeight >= startHeight ? await this.getBlocksByRange(startHeight, endHeight) : []; - } - - /** - * Retrieves a header by height from the cache or fetches and caches a header - * range if not already in the cache. - * - * @param {number} height - height of the header to retrieve from the cache - * @param {number} maxHeight - maximum height of headers to cache - */ - async _getBlockHeaderByHeightCached(height, maxHeight) { - - // get header from cache - let cachedHeader = this.cachedHeaders[height]; - if (cachedHeader) return cachedHeader; - - // fetch and cache headers if not in cache - let endHeight = Math.min(maxHeight, height + MoneroDaemonRpc.NUM_HEADERS_PER_REQ - 1); // TODO: could specify end height to cache to optimize small requests (would like to have time profiling in place though) - let headers = await this.getBlockHeadersByRange(height, endHeight); - for (let header of headers) { - this.cachedHeaders[header.getHeight()] = header; - } - - // return the cached header - return this.cachedHeaders[height]; - } - - // --------------------------------- STATIC --------------------------------- - - static _normalizeConfig(uriOrConfigOrConnection, username, password, rejectUnauthorized, pollInterval, proxyToWorker) { - let config; - if (typeof uriOrConfigOrConnection === "string") config = {uri: uriOrConfigOrConnection, username: username, password: password, proxyToWorker: proxyToWorker, rejectUnauthorized: rejectUnauthorized, pollInterval: pollInterval}; - else { - if (typeof uriOrConfigOrConnection !== "object") throw new MoneroError("Invalid configuration to create daemon rpc client; must be string, object, or MoneroRpcConnection"); - if (username || password || rejectUnauthorized || pollInterval || proxyToWorker) throw new MoneroError("Can provide config object or params or new MoneroDaemonRpc(...) but not both"); - if (uriOrConfigOrConnection instanceof MoneroRpcConnection) config = Object.assign({}, uriOrConfigOrConnection.getConfig()); - else config = Object.assign({}, uriOrConfigOrConnection); - } - if (config.pollInterval === undefined) config.pollInterval = 5000; // TODO: move to config - if (config.server) { - config = Object.assign(config, new MoneroRpcConnection(config.server).getConfig()); - delete config.server; - } - if (config.proxyToWorker === undefined) config.proxyToWorker = GenUtils.isBrowser(); - return config; - } - - static _checkResponseStatus(resp) { - if (resp.status !== "OK") throw new MoneroError(resp.status); - } - - static _convertRpcBlockHeader(rpcHeader) { - if (!rpcHeader) return undefined; - let header = new MoneroBlockHeader(); - for (let key of Object.keys(rpcHeader)) { - let val = rpcHeader[key]; - if (key === "block_size") GenUtils.safeSet(header, header.getSize, header.setSize, val); - else if (key === "depth") GenUtils.safeSet(header, header.getDepth, header.setDepth, val); - else if (key === "difficulty") { } // handled by wide_difficulty - else if (key === "cumulative_difficulty") { } // handled by wide_cumulative_difficulty - else if (key === "difficulty_top64") { } // handled by wide_difficulty - else if (key === "cumulative_difficulty_top64") { } // handled by wide_cumulative_difficulty - else if (key === "wide_difficulty") header.setDifficulty(GenUtils.reconcile(header.getDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val))); - else if (key === "wide_cumulative_difficulty") header.setCumulativeDifficulty(GenUtils.reconcile(header.getCumulativeDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val))); - else if (key === "hash") GenUtils.safeSet(header, header.getHash, header.setHash, val); - else if (key === "height") GenUtils.safeSet(header, header.getHeight, header.setHeight, val); - else if (key === "major_version") GenUtils.safeSet(header, header.getMajorVersion, header.setMajorVersion, val); - else if (key === "minor_version") GenUtils.safeSet(header, header.getMinorVersion, header.setMinorVersion, val); - else if (key === "nonce") GenUtils.safeSet(header, header.getNonce, header.setNonce, val); - else if (key === "num_txes") GenUtils.safeSet(header, header.getNumTxs, header.setNumTxs, val); - else if (key === "orphan_status") GenUtils.safeSet(header, header.getOrphanStatus, header.setOrphanStatus, val); - else if (key === "prev_hash" || key === "prev_id") GenUtils.safeSet(header, header.getPrevHash, header.setPrevHash, val); - else if (key === "reward") GenUtils.safeSet(header, header.getReward, header.setReward, BigInteger.parse(val)); - else if (key === "timestamp") GenUtils.safeSet(header, header.getTimestamp, header.setTimestamp, val); - else if (key === "block_weight") GenUtils.safeSet(header, header.getWeight, header.setWeight, val); - else if (key === "long_term_weight") GenUtils.safeSet(header, header.getLongTermWeight, header.setLongTermWeight, val); - else if (key === "pow_hash") GenUtils.safeSet(header, header.getPowHash, header.setPowHash, val === "" ? undefined : val); - else if (key === "tx_hashes") {} // used in block model, not header model - else if (key === "miner_tx") {} // used in block model, not header model - else if (key === "miner_tx_hash") header.setMinerTxHash(val); - else console.log("WARNING: ignoring unexpected block header field: '" + key + "': " + val); - } - return header; - } - - static _convertRpcBlock(rpcBlock) { - - // build block - let block = new MoneroBlock(MoneroDaemonRpc._convertRpcBlockHeader(rpcBlock.block_header ? rpcBlock.block_header : rpcBlock)); - block.setHex(rpcBlock.blob); - block.setTxHashes(rpcBlock.tx_hashes === undefined ? [] : rpcBlock.tx_hashes); - - // build miner tx - let rpcMinerTx = rpcBlock.json ? JSON.parse(rpcBlock.json).miner_tx : rpcBlock.miner_tx; // may need to be parsed from json - let minerTx = new MoneroTx(); - block.setMinerTx(minerTx); - minerTx.setIsConfirmed(true); - minerTx.setIsMinerTx(true); - MoneroDaemonRpc._convertRpcTx(rpcMinerTx, minerTx); - - return block; - } - - /** - * Transfers RPC tx fields to a given MoneroTx without overwriting previous values. - * - * TODO: switch from safe set - * - * @param rpcTx - RPC map containing transaction fields - * @param tx - MoneroTx to populate with values (optional) - * @returns tx - same tx that was passed in or a new one if none given - */ - static _convertRpcTx(rpcTx, tx) { - if (rpcTx === undefined) return undefined; - if (tx === undefined) tx = new MoneroTx(); - -// console.log("******** BUILDING TX ***********"); -// console.log(rpcTx); -// console.log(tx.toString()); - - // initialize from rpc map - let header; - for (let key of Object.keys(rpcTx)) { - let val = rpcTx[key]; - if (key === "tx_hash" || key === "id_hash") GenUtils.safeSet(tx, tx.getHash, tx.setHash, val); - else if (key === "block_timestamp") { - if (!header) header = new MoneroBlockHeader(); - GenUtils.safeSet(header, header.getTimestamp, header.setTimestamp, val); - } - else if (key === "block_height") { - if (!header) header = new MoneroBlockHeader(); - GenUtils.safeSet(header, header.getHeight, header.setHeight, val); - } - else if (key === "last_relayed_time") GenUtils.safeSet(tx, tx.getLastRelayedTimestamp, tx.setLastRelayedTimestamp, val); - else if (key === "receive_time" || key === "received_timestamp") GenUtils.safeSet(tx, tx.getReceivedTimestamp, tx.setReceivedTimestamp, val); - else if (key === "in_pool") { - GenUtils.safeSet(tx, tx.isConfirmed, tx.setIsConfirmed, !val); - GenUtils.safeSet(tx, tx.inTxPool, tx.setInTxPool, val); - } - else if (key === "double_spend_seen") GenUtils.safeSet(tx, tx.isDoubleSpendSeen, tx.setIsDoubleSpend, val); - else if (key === "version") GenUtils.safeSet(tx, tx.getVersion, tx.setVersion, val); - else if (key === "extra") GenUtils.safeSet(tx, tx.getExtra, tx.setExtra, val); - else if (key === "vin") { - if (val.length !== 1 || !val[0].gen) { // ignore miner input TODO: why? - tx.setInputs(val.map(rpcVin => MoneroDaemonRpc._convertRpcOutput(rpcVin, tx))); - } - } - else if (key === "vout") tx.setOutputs(val.map(rpcOutput => MoneroDaemonRpc._convertRpcOutput(rpcOutput, tx))); - else if (key === "rct_signatures") GenUtils.safeSet(tx, tx.getRctSignatures, tx.setRctSignatures, val); - else if (key === "rctsig_prunable") GenUtils.safeSet(tx, tx.getRctSigPrunable, tx.setRctSigPrunable, val); - else if (key === "unlock_time") GenUtils.safeSet(tx, tx.getUnlockHeight, tx.setUnlockHeight, val); - else if (key === "as_json" || key === "tx_json") { } // handled last so tx is as initialized as possible - else if (key === "as_hex" || key === "tx_blob") GenUtils.safeSet(tx, tx.getFullHex, tx.setFullHex, val ? val : undefined); - else if (key === "blob_size") GenUtils.safeSet(tx, tx.getSize, tx.setSize, val); - else if (key === "weight") GenUtils.safeSet(tx, tx.getWeight, tx.setWeight, val); - else if (key === "fee") GenUtils.safeSet(tx, tx.getFee, tx.setFee, BigInteger.parse(val)); - else if (key === "relayed") GenUtils.safeSet(tx, tx.isRelayed, tx.setIsRelayed, val); - else if (key === "output_indices") GenUtils.safeSet(tx, tx.getOutputIndices, tx.setOutputIndices, val); - else if (key === "do_not_relay") GenUtils.safeSet(tx, tx.getRelay, tx.setRelay, !val); - else if (key === "kept_by_block") GenUtils.safeSet(tx, tx.isKeptByBlock, tx.setIsKeptByBlock, val); - else if (key === "signatures") GenUtils.safeSet(tx, tx.getSignatures, tx.setSignatures, val); - else if (key === "last_failed_height") { - if (val === 0) GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, false); - else { - GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, true); - GenUtils.safeSet(tx, tx.getLastFailedHeight, tx.setLastFailedHeight, val); - } - } - else if (key === "last_failed_id_hash") { - if (val === MoneroDaemonRpc.DEFAULT_ID) GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, false); - else { - GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, true); - GenUtils.safeSet(tx, tx.getLastFailedHash, tx.setLastFailedHash, val); - } - } - else if (key === "max_used_block_height") GenUtils.safeSet(tx, tx.getMaxUsedBlockHeight, tx.setMaxUsedBlockHeight, val); - else if (key === "max_used_block_id_hash") GenUtils.safeSet(tx, tx.getMaxUsedBlockHash, tx.setMaxUsedBlockHash, val); - else if (key === "prunable_hash") GenUtils.safeSet(tx, tx.getPrunableHash, tx.setPrunableHash, val ? val : undefined); - else if (key === "prunable_as_hex") GenUtils.safeSet(tx, tx.getPrunableHex, tx.setPrunableHex, val ? val : undefined); - else if (key === "pruned_as_hex") GenUtils.safeSet(tx, tx.getPrunedHex, tx.setPrunedHex, val ? val : undefined); - else console.log("WARNING: ignoring unexpected field in rpc tx: " + key + ": " + val); - } - - // link block and tx - if (header) tx.setBlock(new MoneroBlock(header).setTxs([tx])); - - // TODO monero-daemon-rpc: unconfirmed txs misreport block height and timestamp - if (tx.getBlock() && tx.getBlock().getHeight() !== undefined && tx.getBlock().getHeight() === tx.getBlock().getTimestamp()) { - tx.setBlock(undefined); - tx.setIsConfirmed(false); - } - - // initialize remaining known fields - if (tx.isConfirmed()) { - GenUtils.safeSet(tx, tx.isRelayed, tx.setIsRelayed, true); - GenUtils.safeSet(tx, tx.getRelay, tx.setRelay, true); - GenUtils.safeSet(tx, tx.isFailed, tx.setIsFailed, false); - } else { - tx.setNumConfirmations(0); - } - if (tx.isFailed() === undefined) tx.setIsFailed(false); - if (tx.getOutputIndices() && tx.getOutputs()) { - assert.equal(tx.getOutputs().length, tx.getOutputIndices().length); - for (let i = 0; i < tx.getOutputs().length; i++) { - tx.getOutputs()[i].setIndex(tx.getOutputIndices()[i]); // transfer output indices to outputs - } - } - if (rpcTx.as_json) MoneroDaemonRpc._convertRpcTx(JSON.parse(rpcTx.as_json), tx); - if (rpcTx.tx_json) MoneroDaemonRpc._convertRpcTx(JSON.parse(rpcTx.tx_json), tx); - if (!tx.isRelayed()) tx.setLastRelayedTimestamp(undefined); // TODO monero-daemon-rpc: returns last_relayed_timestamp despite relayed: false, self inconsistent - - // return built transaction - return tx; - } - - static _convertRpcOutput(rpcOutput, tx) { - let output = new MoneroOutput(); - output.setTx(tx); - for (let key of Object.keys(rpcOutput)) { - let val = rpcOutput[key]; - if (key === "gen") throw new MoneroError("Output with 'gen' from daemon rpc is miner tx which we ignore (i.e. each miner input is undefined)"); - else if (key === "key") { - GenUtils.safeSet(output, output.getAmount, output.setAmount, new BigInteger(val.amount)); - GenUtils.safeSet(output, output.getKeyImage, output.setKeyImage, new MoneroKeyImage(val.k_image)); - GenUtils.safeSet(output, output.getRingOutputIndices, output.setRingOutputIndices, val.key_offsets); - } - else if (key === "amount") GenUtils.safeSet(output, output.getAmount, output.setAmount, BigInteger.parse(val)); - else if (key === "target") GenUtils.safeSet(output, output.getStealthPublicKey, output.setStealthPublicKey, val.key); - else console.log("WARNING: ignoring unexpected field output: " + key + ": " + val); - } - return output; - } - - static _convertRpcBlockTemplate(rpcTemplate) { - let template = new MoneroBlockTemplate(); - for (let key of Object.keys(rpcTemplate)) { - let val = rpcTemplate[key]; - if (key === "blockhashing_blob") template.setBlockTemplateBlob(val); - else if (key === "blocktemplate_blob") template.setBlockHashingBlob(val); - else if (key === "difficulty") template.setDifficulty(BigInteger.parse(val)); - else if (key === "expected_reward") template.setExpectedReward(val); - else if (key === "difficulty") { } // handled by wide_difficulty - else if (key === "difficulty_top64") { } // handled by wide_difficulty - else if (key === "wide_difficulty") template.setDifficulty(GenUtils.reconcile(template.getDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val))); - else if (key === "height") template.setHeight(val); - else if (key === "prev_hash") template.setPrevHash(val); - else if (key === "reserved_offset") template.setReservedOffset(val); - else if (key === "status") {} // handled elsewhere - else if (key === "untrusted") {} // handled elsewhere - else if (key === "seed_height") template.setSeedHeight(val); - else if (key === "seed_hash") template.setSeedHash(val); - else if (key === "next_seed_hash") template.setNextSeedHash(val); - else console.log("WARNING: ignoring unexpected field in block template: " + key + ": " + val); - } - if ("" === template.getNextSeedHash()) template.setNextSeedHash(undefined); - return template; - } - - static _convertRpcInfo(rpcInfo) { - if (!rpcInfo) return undefined; - let info = new MoneroDaemonInfo(); - for (let key of Object.keys(rpcInfo)) { - let val = rpcInfo[key]; - if (key === "version") info.setVersion(val); - else if (key === "alt_blocks_count") info.setNumAltBlocks(val); - else if (key === "block_size_limit") info.setBlockSizeLimit(val); - else if (key === "block_size_median") info.setBlockSizeMedian(val); - else if (key === "block_weight_limit") info.setBlockWeightLimit(val); - else if (key === "block_weight_median") info.setBlockWeightMedian(val); - else if (key === "bootstrap_daemon_address") { if (val) info.setBootstrapDaemonAddress(val); } - else if (key === "difficulty") { } // handled by wide_difficulty - else if (key === "cumulative_difficulty") { } // handled by wide_cumulative_difficulty - else if (key === "difficulty_top64") { } // handled by wide_difficulty - else if (key === "cumulative_difficulty_top64") { } // handled by wide_cumulative_difficulty - else if (key === "wide_difficulty") info.setDifficulty(GenUtils.reconcile(info.getDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val))); - else if (key === "wide_cumulative_difficulty") info.setCumulativeDifficulty(GenUtils.reconcile(info.getCumulativeDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val))); - else if (key === "free_space") info.setFreeSpace(BigInteger.parse(val)); - else if (key === "database_size") info.setDatabaseSize(val); - else if (key === "grey_peerlist_size") info.setNumOfflinePeers(val); - else if (key === "height") info.setHeight(val); - else if (key === "height_without_bootstrap") info.setHeightWithoutBootstrap(val); - else if (key === "incoming_connections_count") info.setNumIncomingConnections(val); - else if (key === "offline") info.setIsOffline(val); - else if (key === "outgoing_connections_count") info.setNumOutgoingConnections(val); - else if (key === "rpc_connections_count") info.setNumRpcConnections(val); - else if (key === "start_time") info.setStartTimestamp(val); - else if (key === "status") {} // handled elsewhere - else if (key === "target") info.setTarget(val); - else if (key === "target_height") info.setTargetHeight(val); - else if (key === "top_block_hash") info.setTopBlockHash(val); - else if (key === "tx_count") info.setNumTxs(val); - else if (key === "tx_pool_size") info.setNumTxsPool(val); - else if (key === "untrusted") {} // handled elsewhere - else if (key === "was_bootstrap_ever_used") info.setWasBootstrapEverUsed(val); - else if (key === "white_peerlist_size") info.setNumOnlinePeers(val); - else if (key === "update_available") info.setUpdateAvailable(val); - else if (key === "nettype") GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroDaemon.parseNetworkType(val)); - else if (key === "mainnet") { if (val) GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.MAINNET); } - else if (key === "testnet") { if (val) GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.TESTNET); } - else if (key === "stagenet") { if (val) GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.STAGENET); } - else if (key === "credits") info.setCredits(BigInteger.parse(val)); - else if (key === "top_block_hash" || key === "top_hash") info.setTopBlockHash(GenUtils.reconcile(info.getTopBlockHash(), "" === val ? undefined : val)) - else console.log("WARNING: Ignoring unexpected info field: " + key + ": " + val); - } - return info; - } - - /** - * Initializes sync info from RPC sync info. - * - * @param rpcSyncInfo - rpc map to initialize the sync info from - * @return {MoneroDaemonSyncInfo} is sync info initialized from the map - */ - static _convertRpcSyncInfo(rpcSyncInfo) { - let syncInfo = new MoneroDaemonSyncInfo(); - for (let key of Object.keys(rpcSyncInfo)) { - let val = rpcSyncInfo[key]; - if (key === "height") syncInfo.setHeight(val); - else if (key === "peers") { - syncInfo.setConnections([]); - let rpcConnections = val; - for (let rpcConnection of rpcConnections) { - syncInfo.getConnections().push(MoneroDaemonRpc._convertRpcConnection(rpcConnection.info)); - } - } - else if (key === "spans") { - syncInfo.setSpans([]); - let rpcSpans = val; - for (let rpcSpan of rpcSpans) { - syncInfo.getSpans().push(MoneroDaemonRpc._convertRpcConnectionSpan(rpcSpan)); - } - } else if (key === "status") {} // handled elsewhere - else if (key === "target_height") syncInfo.setTargetHeight(BigInteger.parse(val)); - else if (key === "next_needed_pruning_seed") syncInfo.setNextNeededPruningSeed(val); - else if (key === "overview") { // this returns [] without pruning - let overview; - try { - overview = JSON.parse(val); - if (overview !== undefined && overview.length > 0) console.error("Ignoring non-empty 'overview' field (not implemented): " + overview); // TODO - } catch (e) { - console.error("Failed to parse 'overview' field: " + overview + ": " + e.message); - } - } - else if (key === "credits") syncInfo.setCredits(BigInteger.parse(val)); - else if (key === "top_hash") syncInfo.setTopBlockHash("" === val ? undefined : val); - else if (key === "untrusted") {} // handled elsewhere - else console.log("WARNING: ignoring unexpected field in sync info: " + key + ": " + val); - } - return syncInfo; - } - - static _convertRpcHardForkInfo(rpcHardForkInfo) { - let info = new MoneroHardForkInfo(); - for (let key of Object.keys(rpcHardForkInfo)) { - let val = rpcHardForkInfo[key]; - if (key === "earliest_height") info.setEarliestHeight(val); - else if (key === "enabled") info.setIsEnabled(val); - else if (key === "state") info.setState(val); - else if (key === "status") {} // handled elsewhere - else if (key === "untrusted") {} // handled elsewhere - else if (key === "threshold") info.setThreshold(val); - else if (key === "version") info.setVersion(val); - else if (key === "votes") info.setNumVotes(val); - else if (key === "voting") info.setVoting(val); - else if (key === "window") info.setWindow(val); - else if (key === "credits") info.setCredits(BigInteger.parse(val)); - else if (key === "top_hash") info.setTopBlockHash("" === val ? undefined : val); - else console.log("WARNING: ignoring unexpected field in hard fork info: " + key + ": " + val); - } - return info; - } - - static _convertRpcConnectionSpan(rpcConnectionSpan) { - let span = new MoneroDaemonConnectionSpan(); - for (let key of Object.keys(rpcConnectionSpan)) { - let val = rpcConnectionSpan[key]; - if (key === "connection_id") span.setConnectionId(val); - else if (key === "nblocks") span.setNumBlocks(val); - else if (key === "rate") span.setRate(val); - else if (key === "remote_address") { if (val !== "") span.setRemoteAddress(val); } - else if (key === "size") span.setSize(val); - else if (key === "speed") span.setSpeed(val); - else if (key === "start_block_height") span.setStartHeight(val); - else console.log("WARNING: ignoring unexpected field in daemon connection span: " + key + ": " + val); - } - return span; - } - - static _convertRpcOutputHistogramEntry(rpcEntry) { - let entry = new MoneroOutputHistogramEntry(); - for (let key of Object.keys(rpcEntry)) { - let val = rpcEntry[key]; - if (key === "amount") entry.setAmount(BigInteger.parse(val)); - else if (key === "total_instances") entry.setNumInstances(val); - else if (key === "unlocked_instances") entry.setNumUnlockedInstances(val); - else if (key === "recent_instances") entry.setNumRecentInstances(val); - else console.log("WARNING: ignoring unexpected field in output histogram: " + key + ": " + val); - } - return entry; - } - - static _convertRpcSubmitTxResult(rpcResult) { - assert(rpcResult); - let result = new MoneroSubmitTxResult(); - for (let key of Object.keys(rpcResult)) { - let val = rpcResult[key]; - if (key === "double_spend") result.setIsDoubleSpend(val); - else if (key === "fee_too_low") result.setIsFeeTooLow(val); - else if (key === "invalid_input") result.setHasInvalidInput(val); - else if (key === "invalid_output") result.setHasInvalidOutput(val); - else if (key === "too_few_outputs") result.setHasTooFewOutputs(val); - else if (key === "low_mixin") result.setIsMixinTooLow(val); - else if (key === "not_relayed") result.setIsRelayed(!val); - else if (key === "overspend") result.setIsOverspend(val); - else if (key === "reason") result.setReason(val === "" ? undefined : val); - else if (key === "too_big") result.setIsTooBig(val); - else if (key === "sanity_check_failed") result.setSanityCheckFailed(val); - else if (key === "credits") result.setCredits(BigInteger.parse(val)) - else if (key === "status" || key === "untrusted") {} // handled elsewhere - else if (key === "top_hash") result.setTopBlockHash("" === val ? undefined : val); - else console.log("WARNING: ignoring unexpected field in submit tx hex result: " + key + ": " + val); - } - return result; - } - - static _convertRpcTxPoolStats(rpcStats) { - assert(rpcStats); - let stats = new MoneroTxPoolStats(); - for (let key of Object.keys(rpcStats)) { - let val = rpcStats[key]; - if (key === "bytes_max") stats.setBytesMax(val); - else if (key === "bytes_med") stats.setBytesMed(val); - else if (key === "bytes_min") stats.setBytesMin(val); - else if (key === "bytes_total") stats.setBytesTotal(val); - else if (key === "histo_98pc") stats.setHisto98pc(val); - else if (key === "num_10m") stats.setNum10m(val); - else if (key === "num_double_spends") stats.setNumDoubleSpends(val); - else if (key === "num_failing") stats.setNumFailing(val); - else if (key === "num_not_relayed") stats.setNumNotRelayed(val); - else if (key === "oldest") stats.setOldestTimestamp(val); - else if (key === "txs_total") stats.setNumTxs(val); - else if (key === "fee_total") stats.setFeeTotal(BigInteger.parse(val)); - else if (key === "histo") throw new MoneroError("Not implemented"); - else console.log("WARNING: ignoring unexpected field in tx pool stats: " + key + ": " + val); - } - return stats; - } - - static _convertRpcAltChain(rpcChain) { - assert(rpcChain); - let chain = new MoneroAltChain(); - for (let key of Object.keys(rpcChain)) { - let val = rpcChain[key]; - if (key === "block_hash") {} // using block_hashes instead - else if (key === "difficulty") { } // handled by wide_difficulty - else if (key === "difficulty_top64") { } // handled by wide_difficulty - else if (key === "wide_difficulty") chain.setDifficulty(GenUtils.reconcile(chain.getDifficulty(), MoneroDaemonRpc._prefixedHexToBI(val))); - else if (key === "height") chain.setHeight(val); - else if (key === "length") chain.setLength(val); - else if (key === "block_hashes") chain.setBlockHashes(val); - else if (key === "main_chain_parent_block") chain.setMainChainParentBlockHash(val); - else console.log("WARNING: ignoring unexpected field in alternative chain: " + key + ": " + val); - } - return chain; - } - - static _convertRpcPeer(rpcPeer) { - assert(rpcPeer); - let peer = new MoneroDaemonPeer(); - for (let key of Object.keys(rpcPeer)) { - let val = rpcPeer[key]; - if (key === "host") peer.setHost(val); - else if (key === "id") peer.setId("" + val); // TODO monero-wallet-rpc: peer id is BigInteger but string in `get_connections` - else if (key === "ip") {} // host used instead which is consistently a string - else if (key === "last_seen") peer.setLastSeenTimestamp(val); - else if (key === "port") peer.setPort(val); - else if (key === "rpc_port") peer.setRpcPort(val); - else if (key === "pruning_seed") peer.setPruningSeed(val); - else if (key === "rpc_credits_per_hash") peer.setRpcCreditsPerHash(BigInteger.parse(val)); - else console.log("WARNING: ignoring unexpected field in rpc peer: " + key + ": " + val); - } - return peer; - } - - static _convertRpcConnection(rpcConnection) { - let connection = new MoneroDaemonConnection(); - let peer = new MoneroDaemonPeer(); - connection.setPeer(peer); - peer.setIsOnline(true); - for (let key of Object.keys(rpcConnection)) { - let val = rpcConnection[key]; - if (key === "address") peer.setAddress(val); - else if (key === "avg_download") connection.setAvgDownload(val); - else if (key === "avg_upload") connection.setAvgUpload(val); - else if (key === "connection_id") connection.setId(val); - else if (key === "current_download") connection.setCurrentDownload(val); - else if (key === "current_upload") connection.setCurrentUpload(val); - else if (key === "height") connection.setHeight(val); - else if (key === "host") peer.setHost(val); - else if (key === "ip") {} // host used instead which is consistently a string - else if (key === "incoming") connection.setIsIncoming(val); - else if (key === "live_time") connection.setLiveTime(val); - else if (key === "local_ip") connection.setIsLocalIp(val); - else if (key === "localhost") connection.setIsLocalHost(val); - else if (key === "peer_id") peer.setId(val); - else if (key === "port") peer.setPort(parseInt(val)); - else if (key === "rpc_port") peer.setRpcPort(val); - else if (key === "recv_count") connection.setNumReceives(val); - else if (key === "recv_idle_time") connection.setReceiveIdleTime(val); - else if (key === "send_count") connection.setNumSends(val); - else if (key === "send_idle_time") connection.setSendIdleTime(val); - else if (key === "state") connection.setState(val); - else if (key === "support_flags") connection.setNumSupportFlags(val); - else if (key === "pruning_seed") peer.setPruningSeed(val); - else if (key === "rpc_credits_per_hash") peer.setRpcCreditsPerHash(BigInteger.parse(val)); - else if (key === "address_type") connection.setType(val); - else console.log("WARNING: ignoring unexpected field in connection: " + key + ": " + val); - } - return connection; - } - - static _convertToRpcBan(ban) { - let rpcBan = {}; - rpcBan.host = ban.getHost(); - rpcBan.ip = ban.getIp(); - rpcBan.ban = ban.isBanned(); - rpcBan.seconds = ban.getSeconds(); - return rpcBan; - } - - static _convertRpcMiningStatus(rpcStatus) { - let status = new MoneroMiningStatus(); - status.setIsActive(rpcStatus.active); - status.setSpeed(rpcStatus.speed); - status.setNumThreads(rpcStatus.threads_count); - if (rpcStatus.active) { - status.setAddress(rpcStatus.address); - status.setIsBackground(rpcStatus.is_background_mining_enabled); - } - return status; - } - - static _convertRpcUpdateCheckResult(rpcResult) { - assert(rpcResult); - let result = new MoneroDaemonUpdateCheckResult(); - for (let key of Object.keys(rpcResult)) { - let val = rpcResult[key]; - if (key === "auto_uri") result.setAutoUri(val); - else if (key === "hash") result.setHash(val); - else if (key === "path") {} // handled elsewhere - else if (key === "status") {} // handled elsewhere - else if (key === "update") result.setIsUpdateAvailable(val); - else if (key === "user_uri") result.setUserUri(val); - else if (key === "version") result.setVersion(val); - else if (key === "untrusted") {} // handled elsewhere - else console.log("WARNING: ignoring unexpected field in rpc check update result: " + key + ": " + val); - } - if (result.getAutoUri() === "") result.setAutoUri(undefined); - if (result.getUserUri() === "") result.setUserUri(undefined); - if (result.getVersion() === "") result.setVersion(undefined); - if (result.getHash() === "") result.setHash(undefined); - return result; - } - - static _convertRpcUpdateDownloadResult(rpcResult) { - let result = new MoneroDaemonUpdateDownloadResult(MoneroDaemonRpc._convertRpcUpdateCheckResult(rpcResult)); - result.setDownloadPath(rpcResult["path"]); - if (result.getDownloadPath() === "") result.setDownloadPath(undefined); - return result; - } - - /** - * Converts a '0x' prefixed hexidecimal string to a BigInteger. - * - * @param hex is the '0x' prefixed hexidecimal string to convert - * @return BigInteger is the hexicedimal converted to decimal - */ - static _prefixedHexToBI(hex) { - assert(hex.substring(0, 2) === "0x"); - return BigInteger.parse(hex, 16); - } -} - -// static variables -MoneroDaemonRpc.DEFAULT_ID = "0000000000000000000000000000000000000000000000000000000000000000"; // uninitialized tx or block hash from daemon rpc -MoneroDaemonRpc.MAX_REQ_SIZE = "3000000"; // max request size when fetching blocks from daemon -MoneroDaemonRpc.NUM_HEADERS_PER_REQ = "750"; // number of headers to fetch and cache per request - -/** - * Implements a MoneroDaemon by proxying requests to a web worker. - * - * @private - */ -class MoneroDaemonRpcProxy extends MoneroDaemon { - - // --------------------------- STATIC UTILITIES ----------------------------- - - static async connect(config) { - let daemonId = GenUtils.getUUID(); - config = Object.assign({}, config, {proxyToWorker: false}); - await LibraryUtils.invokeWorker(daemonId, "connectDaemonRpc", [config]); - return new MoneroDaemonRpcProxy(daemonId, LibraryUtils.getWorker()); - } - - // ---------------------------- INSTANCE METHODS ---------------------------- - - constructor(daemonId, worker) { - super(); - this.daemonId = daemonId; - this.worker = worker; - this.wrappedListeners = []; - } - - async getRpcConnection() { - let config = await this._invokeWorker("daemonGetRpcConnection"); - return new MoneroRpcConnection(config); - } - - async isConnected() { - return this._invokeWorker("daemonIsConnected"); - } - - async getVersion() { - let versionJson = await this._invokeWorker("daemonGetVersion"); - return new MoneroVersion(versionJson.number, versionJson.isRelease); - } - - async isTrusted() { - return this._invokeWorker("daemonIsTrusted"); - } - - async getHeight() { - return this._invokeWorker("daemonGetHeight"); - } - - async getBlockHash(height) { - return this._invokeWorker("daemonGetBlockHash", Array.from(arguments)); - } - - async getBlockTemplate(walletAddress, reserveSize) { - return new MoneroBlockTemplate(await this._invokeWorker("daemonGetBlockTemplate", Array.from(arguments))); - } - - async getLastBlockHeader() { - return new MoneroBlockHeader(await this._invokeWorker("daemonGetLastBlockHeader")); - } - - async getBlockHeaderByHash(blockHash) { - return new MoneroBlockHeader(await this._invokeWorker("daemonGetBlockHeaderByHash", Array.from(arguments))); - } - - async getBlockHeaderByHeight(height) { - return new MoneroBlockHeader(await this._invokeWorker("daemonGetBlockHeaderByHeight", Array.from(arguments))); - } - - async getBlockHeadersByRange(startHeight, endHeight) { - let blockHeadersJson = await this._invokeWorker("daemonGetBlockHeadersByRange", Array.from(arguments)); - let headers = []; - for (let blockHeaderJson of blockHeadersJson) headers.push(new MoneroBlockHeader(blockHeaderJson)); - return headers; - } - - async getBlockByHash(blockHash) { - return new MoneroBlock(await this._invokeWorker("daemonGetBlockByHash", Array.from(arguments))); - } - - async getBlocksByHash(blockHashes, startHeight, prune) { - let blocksJson = await this._invokeWorker("daemonGetBlocksByHash", Array.from(arguments)); - let blocks = []; - for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson)); - return blocks; - } - - async getBlockByHeight(height) { - return new MoneroBlock(await this._invokeWorker("daemonGetBlockByHeight", Array.from(arguments))); - } - - async getBlocksByHeight(heights) { - let blocksJson = await this._invokeWorker("daemonGetBlocksByHeight", Array.from(arguments)); - let blocks = []; - for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson)); - return blocks; - } - - async getBlocksByRange(startHeight, endHeight) { - let blocksJson = await this._invokeWorker("daemonGetBlocksByRange", Array.from(arguments)); - let blocks = []; - for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson)); - return blocks; - } - - async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) { - let blocksJson = await this._invokeWorker("daemonGetBlocksByRangeChunked", Array.from(arguments)); - let blocks = []; - for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson)); - return blocks; - } - - async getBlockHashes(blockHashes, startHeight) { - return this._invokeWorker("daemonGetBlockHashes", Array.from(arguments)); - } - - async getTxs(txHashes, prune = false) { - - // deserialize txs from blocks - let blocks = []; - for (let blockJson of await this._invokeWorker("daemonGetTxs", Array.from(arguments))) { - blocks.push(new MoneroBlock(blockJson)); - } - - // collect txs - let txs = []; - for (let block of blocks) { - for (let tx of block.getTxs()) { - if (!tx.isConfirmed()) tx.setBlock(undefined); - txs.push(tx); - } - } - return txs; - } - - async getTxHexes(txHashes, prune = false) { - return this._invokeWorker("daemonGetTxHexes", Array.from(arguments)); - } - - async getMinerTxSum(height, numBlocks) { - return new MoneroMinerTxSum(await this._invokeWorker("daemonGetMinerTxSum", Array.from(arguments))); - } - - async getFeeEstimate(graceBlocks) { - return BigInteger.parse(await this._invokeWorker("daemonGetFeeEstimate", Array.from(arguments))); - } - - async submitTxHex(txHex, doNotRelay) { - return new MoneroSubmitTxResult(await this._invokeWorker("daemonSubmitTxHex", Array.from(arguments))); - } - - async relayTxsByHash(txHashes) { - return this._invokeWorker("daemonRelayTxsByHash", Array.from(arguments)); - } - - async getTxPool() { - let blockJson = await this._invokeWorker("daemonGetTxPool"); - let txs = new MoneroBlock(blockJson).getTxs(); - for (let tx of txs) tx.setBlock(undefined); - return txs ? txs : []; - } - - async getTxPoolHashes() { - return this._invokeWorker("daemonGetTxPoolHashes", Array.from(arguments)); - } - - async getTxPoolBacklog() { - throw new MoneroError("Not implemented"); - } - - async getTxPoolStats() { - return new MoneroTxPoolStats(await this._invokeWorker("daemonGetTxPoolStats")); - } - - async flushTxPool(hashes) { - return this._invokeWorker("daemonFlushTxPool", Array.from(arguments)); - } - - async getKeyImageSpentStatuses(keyImages) { - return this._invokeWorker("daemonGetKeyImageSpentStatuses", Array.from(arguments)); - } - - async getOutputs(outputs) { - throw new MoneroError("Not implemented"); - } - - async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) { - let entries = []; - for (let entryJson of await this._invokeWorker("daemonGetOutputHistogram", [amounts, minCount, maxCount, isUnlocked, recentCutoff])) { - entries.push(new MoneroOutputHistogramEntry(entryJson)); - } - return entries; - } - - async getOutputDistribution(amounts, cumulative, startHeight, endHeight) { - throw new MoneroError("Not implemented"); - } - - async getInfo() { - return new MoneroDaemonInfo(await this._invokeWorker("daemonGetInfo")); - } - - async getSyncInfo() { - return new MoneroDaemonSyncInfo(await this._invokeWorker("daemonGetSyncInfo")); - } - - async getHardForkInfo() { - return new MoneroHardForkInfo(await this._invokeWorker("daemonGetHardForkInfo")); - } - - async getAltChains() { - let altChains = []; - for (let altChainJson of await this._invokeWorker("daemonGetAltChains")) altChains.push(new MoneroAltChain(altChainJson)); - return altChains; - } - - async getAltBlockHashes() { - return this._invokeWorker("daemonGetAltBlockHashes"); - } - - async getDownloadLimit() { - return this._invokeWorker("daemonGetDownloadLimit"); - } - - async setDownloadLimit(limit) { - return this._invokeWorker("daemonSetDownloadLimit", Array.from(arguments)); - } - - async resetDownloadLimit() { - return this._invokeWorker("daemonResetDownloadLimit"); - } - - async getUploadLimit() { - return this._invokeWorker("daemonGetUploadLimit"); - } - - async setUploadLimit(limit) { - return this._invokeWorker("daemonSetUploadLimit", Array.from(arguments)); - } - - async resetUploadLimit() { - return this._invokeWorker("daemonResetUploadLimit"); - } - - async getKnownPeers() { - let peers = []; - for (let peerJson of await this._invokeWorker("daemonGetKnownPeers")) peers.push(new MoneroDaemonPeer(peerJson)); - return peers; - } - - async getConnections() { - let connections = []; - for (let connectionJson of await this._invokeWorker("daemonGetConnections")) connections.push(new MoneroDaemonConnection(connectionJson)); - return connections; - } - - async setOutgoingPeerLimit(limit) { - return this._invokeWorker("daemonSetIncomingPeerLimit", Array.from(arguments)); - } - - async setIncomingPeerLimit(limit) { - return this._invokeWorker("daemonSetIncomingPeerLimit", Array.from(arguments)); - } - - async getPeerBans() { - let bans = []; - for (let banJson of await this._invokeWorker("daemonGetPeerBans")) bans.push(new MoneroBan(banJson)); - return bans; - } - - async setPeerBans(bans) { - let bansJson = []; - for (let ban of bans) bansJson.push(ban.toJson()); - return this._invokeWorker("daemonSetPeerBans", [bansJson]); - } - - async startMining(address, numThreads, isBackground, ignoreBattery) { - return this._invokeWorker("daemonStartMining", Array.from(arguments)); - } - - async stopMining() { - return this._invokeWorker("daemonStopMining") - } - - async getMiningStatus() { - return new MoneroMiningStatus(await this._invokeWorker("daemonGetMiningStatus")); - } - - async submitBlocks(blockBlobs) { - throw new MoneroError("Not implemented"); - } - - async checkForUpdate() { - throw new MoneroError("Not implemented"); - } - - async downloadUpdate(path) { - throw new MoneroError("Not implemented"); - } - - async stop() { - while (this.wrappedListeners.length) await this.removeBlockListener(this.wrappedListeners[0].getListener()); - return this._invokeWorker("daemonStop"); - } - - async getNextBlockHeader() { - return new MoneroBlockHeader(await this._invokeWorker("daemonGetNextBlockHeader")); - } - - async addBlockListener(listener) { - let wrappedListener = new DaemonWorkerListener(listener); - let listenerId = wrappedListener.getId(); - LibraryUtils.WORKER_OBJECTS[this.daemonId].callbacks["onNewBlockHeader_" + listenerId] = [wrappedListener.onNewBlockHeader, wrappedListener]; - this.wrappedListeners.push(wrappedListener); - return this._invokeWorker("daemonAddBlockListener", [listenerId]); - } - - async removeBlockListener(listener) { - for (let i = 0; i < this.wrappedListeners.length; i++) { - if (this.wrappedListeners[i].getListener() === listener) { - let listenerId = this.wrappedListeners[i].getId(); - await this._invokeWorker("daemonRemoveBlockListener", [listenerId]); - delete LibraryUtils.WORKER_OBJECTS[this.daemonId].callbacks["onNewBlockHeader_" + listenerId]; - this.wrappedListeners.splice(i, 1); - return; - } - } - throw new MoneroError("Listener is not registered with wallet"); - } - - // --------------------------- PRIVATE HELPERS ------------------------------ - - // TODO: duplicated with MoneroWalletWasmProxy - async _invokeWorker(fnName, args) { - return LibraryUtils.invokeWorker(this.daemonId, fnName, args); - } -} - -/** - * Internal listener to bridge notifications to external listeners. - * - * @private - */ -class DaemonWorkerListener { - - constructor(listener) { - this._id = GenUtils.getUUID(); - this._listener = listener; - } - - getId() { - return this._id; - } - - getListener() { - return this._listener; - } - - onNewBlockHeader(headerJson) { - this._listener(new MoneroBlockHeader(headerJson)); - } -} - -module.exports = MoneroDaemonRpc; \ No newline at end of file diff --git a/src/main/js/daemon/model/ConnectionType.js b/src/main/js/daemon/model/ConnectionType.js deleted file mode 100644 index 9d0d83689..000000000 --- a/src/main/js/daemon/model/ConnectionType.js +++ /dev/null @@ -1,52 +0,0 @@ -const assert = require("assert"); - -/** - * Enumerates connection types. - * - * Based on enums.h in monero-project. - * - * @hideconstructor - */ -class ConnectionType { - - /** - * Asserts that the given connection type is valid. - */ - static validate(type) { - assert(type === 0 || type === 1 || type === 2 || type === 3, "Connection type is invalid: " + type); - } - - /** - * Indicates if the given connection type is valid or not. - */ - static isValid(type) { - return type === 0 || type === 1 || type === 2 || 3; - } -} - -/** - * Invalid connection type (value=0). - */ -ConnectionType.INVALID = 0; - -/** - * IPV4 connection type (value=1). - */ -ConnectionType.IPV4 = 1; - -/** - * IPV6 connection type (value=2). - */ -ConnectionType.IPV6 = 2; - -/** - * TOR connection type (value=3). - */ -ConnectionType.TOR = 3; - -/** - * I2P connection type (value=4). - */ -ConnectionType.I2P = 4; - -module.exports = ConnectionType; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroAltChain.js b/src/main/js/daemon/model/MoneroAltChain.js deleted file mode 100644 index 5ca7b6058..000000000 --- a/src/main/js/daemon/model/MoneroAltChain.js +++ /dev/null @@ -1,66 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; - -/** - * Models an alternative chain seen by the node. - */ -class MoneroAltChain { - - constructor(state) { - state = Object.assign({}, state); - if (state.difficulty !== undefined && !(state.difficulty instanceof BigInteger)) state.difficulty = BigInteger.parse(state.difficulty); - this.state = state; - } - - toJson() { - let json = Object.assign({}, this.state); - if (this.getDifficulty()) json.difficulty = this.getDifficulty().toString(); - return json; - } - - getBlockHashes(blockHashes) { - return this.state.blockHashes; - } - - setBlockHashes(blockHashes) { - this.state.blockHashes = blockHashes; - return this; - } - - getDifficulty() { - return this.state.difficulty; - } - - setDifficulty(difficulty) { - this.state.difficulty = difficulty; - return this; - } - - getHeight() { - return this.state.height; - } - - setHeight(height) { - this.state.height = height; - return this; - } - - getLength() { - return this.state.length; - } - - setLength(length) { - this.state.length = length; - return this; - } - - getMainChainParentBlockHash() { - return this.state.mainChainParentBlockHash; - } - - setMainChainParentBlockHash(mainChainParentBlockHash) { - this.state.mainChainParentBlockHash = mainChainParentBlockHash; - return this; - } -} - -module.exports = MoneroAltChain; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroBan.js b/src/main/js/daemon/model/MoneroBan.js deleted file mode 100644 index b71152bf7..000000000 --- a/src/main/js/daemon/model/MoneroBan.js +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Monero banhammer. - */ -class MoneroBan { - - constructor(state) { - this.state = Object.assign({}, state); - } - - toJson() { - return Object.assign({}, this.state); - } - - getHost() { - return this.state.host; - } - - setHost(host) { - this.state.host = host; - return this; - } - - getIp() { - return this.state.ip; - } - - setIp(ip) { - this.state.ip = ip; - return this; - } - - isBanned() { - return this.state.isBanned; - } - - setIsBanned(isBanned) { - this.state.isBanned = isBanned; - return this; - } - - getSeconds() { - return this.state.seconds; - } - - setSeconds(seconds) { - this.state.seconds = seconds; - return this; - } -} - -module.exports = MoneroBan; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroBlock.js b/src/main/js/daemon/model/MoneroBlock.js deleted file mode 100644 index 39bbb4774..000000000 --- a/src/main/js/daemon/model/MoneroBlock.js +++ /dev/null @@ -1,158 +0,0 @@ -const assert = require("assert"); -const GenUtils = require("../../common/GenUtils"); -const MoneroBlockHeader = require("./MoneroBlockHeader"); -const MoneroTx = require("./MoneroTx"); -const MoneroTxQuery = require("../../wallet/model/MoneroTxQuery"); -const MoneroTxWallet = require("../../wallet/model/MoneroTxWallet"); - -/** - * Models a Monero block in the blockchain. - * - * @extends {MoneroBlockHeader} - */ -class MoneroBlock extends MoneroBlockHeader { - - /** - * Construct the model. - * - * @param {MoneroBlock|MoneroBlockHeader|object} state is existing state to initialize from (optional) - * @param {MoneroBlock.DeserializationType} txType informs the tx deserialization type (MoneroTx, MoneroTxWallet, MoneroTxQuery) - */ - constructor(state, txType) { - super(state); - state = this.state; - - // deserialize miner tx - if (state.minerTx && !(state.minerTx instanceof MoneroTx)) state.minerTx = new MoneroTx(state.minerTx).setBlock(this); - - // deserialize non-miner txs - if (state.txs) { - for (let i = 0; i < state.txs.length; i++) { - if (txType === MoneroBlock.DeserializationType.TX || txType === undefined) { - if (!(state.txs[i] instanceof MoneroTx)) state.txs[i] = new MoneroTx(state.txs[i]).setBlock(this); - } else if (txType === MoneroBlock.DeserializationType.TX_WALLET) { - if (!(state.txs[i] instanceof MoneroTxWallet)) state.txs[i] = new MoneroTxWallet(state.txs[i]).setBlock(this); - } else if (txType === MoneroBlock.DeserializationType.TX_QUERY) { - if (!(state.txs[i] instanceof MoneroTxQuery)) state.txs[i] = new MoneroTxQuery(state.txs[i]).setBlock(this); - } else { - throw new Error("Unrecognized tx deserialization type: " + txType); - } - } - } - } - - getHex() { - return this.state.hex; - } - - setHex(hex) { - this.state.hex = hex; - return this; - } - - getMinerTx() { - return this.state.minerTx; - } - - setMinerTx(minerTx) { - this.state.minerTx = minerTx; - return this; - } - - getTxs() { - return this.state.txs; - } - - setTxs(txs) { - this.state.txs = txs; - return this; - } - - getTxHashes() { - return this.state.txHashes; - } - - setTxHashes(txHashes) { - this.state.txHashes = txHashes; - return this; - } - - copy() { - return new MoneroBlock(this); - } - - toJson() { - let json = super.toJson(); - if (this.getMinerTx()) json.minerTx = this.getMinerTx().toJson(); - if (this.getTxs()) { - json.txs = []; - for (let tx of this.getTxs()) json.txs.push(tx.toJson()); - } - return json; - } - - merge(block) { - assert(block instanceof MoneroBlock); - if (this === block) return this; - - // merge header fields - super.merge(block); - - // merge reconcilable block extensions - this.setHex(GenUtils.reconcile(this.getHex(), block.getHex())); - this.setTxHashes(GenUtils.reconcile(this.getTxHashes(), block.getTxHashes())); - - // merge miner tx - if (this.getMinerTx() === undefined) this.setMinerTx(block.getMinerTx()); - if (block.getMinerTx() !== undefined) { - block.getMinerTx().setBlock(this); - minerTx.merge(block.getMinerTx()); - } - - // merge non-miner txs - if (block.getTxs() !== undefined) { - for (let tx of block.getTxs()) { - tx.setBlock(this); - MoneroBlock._mergeTx(this.getTxs(), tx); - } - } - - return this; - } - - toString(indent = 0) { - let str = super.toString(indent) + "\n"; - str += GenUtils.kvLine("Hex", this.getHex(), indent); - if (this.getTxs()) { - str += GenUtils.kvLine("Txs", "", indent); - for (let tx of this.getTxs()) { - str += tx.toString(indent + 1) + "\n"; - } - } - if (this.getMinerTx()) { - str += GenUtils.kvLine("Miner tx", "", indent); - str += this.getMinerTx().toString(indent + 1) + "\n"; - } - str += GenUtils.kvLine("Txs hashes", this.getTxHashes(), indent); - return str[str.length - 1] === "\n" ? str.slice(0, str.length - 1) : str // strip last newline - } - - // private helper to merge txs - static _mergeTx(txs, tx) { - for (let aTx of txs) { - if (aTx.getHash() === tx.getHash()) { - aTx.merge(tx); - return; - } - } - txs.push(tx); - } -} - -MoneroBlock.DeserializationType = { - TX: 0, - TX_WALLET: 1, - TX_QUERY: 2 -} - -module.exports = MoneroBlock; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroBlockTemplate.js b/src/main/js/daemon/model/MoneroBlockTemplate.js deleted file mode 100644 index 0c89d83cf..000000000 --- a/src/main/js/daemon/model/MoneroBlockTemplate.js +++ /dev/null @@ -1,122 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; - -/** - * Monero block template to mine. - */ -class MoneroBlockTemplate { - - constructor(state) { - state = Object.assign({}, state); - this.state = state; - - // deserialize BigIntegers - if (state.expectedReward !== undefined && !(state.expectedReward instanceof BigInteger)) state.expectedReward = BigInteger.parse(state.expectedReward); - if (state.difficulty !== undefined && !(state.difficulty instanceof BigInteger)) state.difficulty = BigInteger.parse(state.difficulty); - } - - toJson() { - let json = Object.assign({}, this.state); - if (this.getExpectedReward()) json.expectedReward = this.getExpectedReward().toString(); - if (this.getDifficulty()) json.difficulty = this.getDifficulty().toString(); - return json; - } - - toJson() { - let json = Object.assign({}, this.state); - if (json.expectedReward) json.expectedReward = json.expectedReward.toString(); - if (json.difficulty) json.difficulty = json.difficulty.toString(); - return json; - } - - getBlockTemplateBlob() { - return this.state.blockTemplateBlob; - } - - setBlockTemplateBlob(blockTemplateBlob) { - this.state.blockTemplateBlob = blockTemplateBlob; - return this; - } - - getBlockHashingBlob() { - return this.state.blockHashingBlob; - } - - setBlockHashingBlob(blockHashingBlob) { - this.state.blockHashingBlob = blockHashingBlob; - return this; - } - - getDifficulty() { - return this.state.difficulty; - } - - setDifficulty(difficulty) { - this.state.difficulty = difficulty; - return this; - } - - getExpectedReward() { - return this.state.expectedReward; - } - - setExpectedReward(expectedReward) { - this.state.expectedReward = expectedReward; - return this; - } - - getHeight() { - return this.state.height; - } - - setHeight(height) { - this.state.height = height; - return this; - } - - getPrevHash() { - return this.state.prevId; - } - - setPrevHash(prevId) { - this.state.prevId = prevId; - return this; - } - - getReservedOffset() { - return this.state.reservedOffset; - } - - setReservedOffset(reservedOffset) { - this.state.reservedOffset = reservedOffset; - return this; - } - - getSeedHeight() { - return this.state.height; - } - - setSeedHeight(seedHeight) { - this.state.seedHeight = seedHeight; - return this; - } - - getSeedHash() { - return this.state.seedHash; - } - - setSeedHash(seedHash) { - this.state.seedHash = seedHash; - return this; - } - - getNextSeedHash() { - return this.state.nextSeedHash - } - - setNextSeedHash(nextSeedHash) { - this.state.nextSeedHash = nextSeedHash; - return this; - } -} - -module.exports = MoneroBlockTemplate; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroDaemonConnection.js b/src/main/js/daemon/model/MoneroDaemonConnection.js deleted file mode 100644 index 56b25d5d5..000000000 --- a/src/main/js/daemon/model/MoneroDaemonConnection.js +++ /dev/null @@ -1,182 +0,0 @@ -const MoneroDaemonPeer = require("./MoneroDaemonPeer"); - -/** - * Monero daemon connection. - */ -class MoneroDaemonConnection { - - constructor(state) { - this.state = Object.assign({}, state); - if (this.state.peer !== undefined && !(this.state.peer instanceof MoneroDaemonPeer)) this.state.peer = new MoneroDaemonPeer(this.state.peer); - } - - toJson() { - let json = Object.assign({}, this.state); - if (json.peer) json.peer = json.peer.toJson(); - return json; - } - - getPeer() { - return this.state.peer; - } - - setPeer(peer) { - this.state.peer = peer; - return this; - } - - getId() { - return this.state.id; - } - - setId(id) { - this.state.id = id; - return this; - } - - getAvgDownload() { - return this.state.avgDownload; - } - - setAvgDownload(avgDownload) { - this.state.avgDownload = avgDownload; - return this; - } - - getAvgUpload() { - return this.state.avgUpload; - } - - setAvgUpload(avgUpload) { - this.state.avgUpload = avgUpload; - return this; - } - - getCurrentDownload() { - return this.state.currentDownload; - } - - setCurrentDownload(currentDownload) { - this.state.currentDownload = currentDownload; - return this; - } - - getCurrentUpload() { - return this.state.currentUpload; - } - - setCurrentUpload(currentUpload) { - this.state.currentUpload = currentUpload; - return this; - } - - getHeight() { - return this.state.height; - } - - setHeight(height) { - this.state.height = height; - return this; - } - - isIncoming() { - return this.state.isIncoming; - } - - setIsIncoming(isIncoming) { - this.state.isIncoming = isIncoming; - return this; - } - - getLiveTime() { - return this.state.liveTime; - } - - setLiveTime(liveTime) { - this.state.liveTime = liveTime; - return this; - } - - isLocalIp() { - return this.state.isLocalIp; - } - - setIsLocalIp(isLocalIp) { - this.state.isLocalIp = isLocalIp; - return this; - } - - isLocalHost() { - return this.state.isLocalHost; - } - - setIsLocalHost(isLocalHost) { - this.state.isLocalHost = isLocalHost; - return this; - } - - getNumReceives() { - return this.state.numReceives; - } - - setNumReceives(numReceives) { - this.state.numReceives = numReceives; - return this; - } - - getNumSends() { - return this.state.numSends; - } - - setNumSends(numSends) { - this.state.numSends = numSends; - return this; - } - - getReceiveIdleTime() { - return this.state.receiveIdleTime; - } - - setReceiveIdleTime(receiveIdleTime) { - this.state.receiveIdleTime = receiveIdleTime; - return this; - } - - getSendIdleTime() { - return this.state.sendIdleTime; - } - - setSendIdleTime(sendIdleTime) { - this.state.sendIdleTime = sendIdleTime; - return this; - } - - getState() { - return this.state.state; - } - - setState(state) { - this.state.state = state; - return this; - } - - getNumSupportFlags() { - return this.state.numSupportFlags; - } - - setNumSupportFlags(numSupportFlags) { - this.state.numSupportFlags = numSupportFlags; - return this; - } - - getType() { - return this.state.type; - } - - setType(type) { - this.state.type = type; - return this; - } -} - -module.exports = MoneroDaemonConnection; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroDaemonConnectionSpan.js b/src/main/js/daemon/model/MoneroDaemonConnectionSpan.js deleted file mode 100644 index 42f50d3be..000000000 --- a/src/main/js/daemon/model/MoneroDaemonConnectionSpan.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Monero daemon connection span. - */ -class MoneroDaemonConnectionSpan { - - constructor(state) { - this.state = Object.assign({}, state); - } - - toJson() { - return Object.assign({}, this.state); - } - - getConnectionId() { - return this.state.connectionId; - } - - setConnectionId(connectionId) { - this.state.connectionId = connectionId; - return this; - } - - getNumBlocks() { - return this.state.numBlocks; - } - - setNumBlocks(numBlocks) { - this.state.numBlocks = numBlocks; - return this; - } - - getRemoteAddress() { - return this.state.remoteAddress; - } - - setRemoteAddress(remoteAddress) { - this.state.remoteAddress = remoteAddress; - return this; - } - - getRate() { - return this.state.rate; - } - - setRate(rate) { - this.state.rate = rate; - return this; - } - - getSpeed() { - return this.state.speed; - } - - setSpeed(speed) { - this.state.speed = speed; - return this; - } - - getSize() { - return this.state.size; - } - - setSize(size) { - this.state.size = size; - return this; - } - - getStartHeight() { - return this.state.startHeight; - } - - setStartHeight(startHeight) { - this.state.startHeight = startHeight; - return this; - } -} - -module.exports = MoneroDaemonConnectionSpan; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroDaemonInfo.js b/src/main/js/daemon/model/MoneroDaemonInfo.js deleted file mode 100644 index b80dd9e35..000000000 --- a/src/main/js/daemon/model/MoneroDaemonInfo.js +++ /dev/null @@ -1,288 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; - -/** - * Monero daemon info. - */ -class MoneroDaemonInfo { - - constructor(state) { - state = Object.assign({}, state); - this.state = state; - - // deserialize BigIntegers - if (state.difficulty !== undefined && !(state.difficulty instanceof BigInteger)) state.difficulty = BigInteger.parse(state.difficulty); - if (state.cumulativeDifficulty !== undefined && !(state.cumulativeDifficulty instanceof BigInteger)) state.cumulativeDifficulty = BigInteger.parse(state.cumulativeDifficulty); - if (state.credits !== undefined && !(state.credits instanceof BigInteger)) state.credits = BigInteger.parse(state.credits); - } - - toJson() { - let json = Object.assign([], this.state); - if (json.difficulty) json.difficulty = json.difficulty.toString(); - if (json.cumulativeDifficulty) json.cumulativeDifficulty = json.cumulativeDifficulty.toString(); - if (json.credits) json.credits = json.credits.toString(); - return json; - } - - getVersion() { - return this.state.version; - } - - setVersion(version) { - this.state.version = version; - return this; - } - - getNumAltBlocks() { - return this.state.numAltBlocks; - } - - setNumAltBlocks(numAltBlocks) { - this.state.numAltBlocks = numAltBlocks; - return this; - } - - getBlockSizeLimit() { - return this.state.blockSizeLimit; - } - - setBlockSizeLimit(blockSizeLimit) { - this.state.blockSizeLimit = blockSizeLimit; - return this; - } - - getBlockSizeMedian() { - return this.state.blockSizeMedian; - } - - setBlockSizeMedian(blockSizeMedian) { - this.state.blockSizeMedian = blockSizeMedian; - return this; - } - - getBlockWeightLimit() { - return this.state.blockWeightLimit; - } - - setBlockWeightLimit(blockWeightLimit) { - this.state.blockWeightLimit = blockWeightLimit; - return this; - } - - getBlockWeightMedian() { - return this.state.blockWeightMedian; - } - - setBlockWeightMedian(blockWeightMedian) { - this.state.blockWeightMedian = blockWeightMedian; - return this; - } - - getBootstrapDaemonAddress() { - return this.state.bootstrapDaemonAddress; - } - - setBootstrapDaemonAddress(bootstrapDaemonAddress) { - this.state.bootstrapDaemonAddress = bootstrapDaemonAddress; - return this; - } - - getDifficulty() { - return this.state.difficulty; - } - - setDifficulty(difficulty) { - this.state.difficulty = difficulty; - return this; - } - - getCumulativeDifficulty() { - return this.state.cumulativeDifficulty; - } - - setCumulativeDifficulty(cumulativeDifficulty) { - this.state.cumulativeDifficulty = cumulativeDifficulty; - return this; - } - - getFreeSpace() { - return this.state.freeSpace; - } - - setFreeSpace(freeSpace) { - this.state.freeSpace = freeSpace; - return this; - } - - getNumOfflinePeers() { - return this.state.numOfflinePeers; - } - - setNumOfflinePeers(numOfflinePeers) { - this.state.numOfflinePeers = numOfflinePeers; - return this; - } - - getNumOnlinePeers() { - return this.state.numOnlinePeers; - } - - setNumOnlinePeers(numOnlinePeers) { - this.state.numOnlinePeers = numOnlinePeers; - return this; - } - - getHeight() { - return this.state.height; - } - - setHeight(height) { - this.state.height = height; - return this; - } - - getHeightWithoutBootstrap() { - return this.state.heightWithoutBootstrap; - } - - setHeightWithoutBootstrap(heightWithoutBootstrap) { - this.state.heightWithoutBootstrap = heightWithoutBootstrap; - return this; - } - - getNetworkType() { - return this.state.networkType; - } - - setNetworkType(networkType) { - this.state.networkType = networkType; - return this; - } - - isOffline() { - return this.state.isOffline; - } - - setIsOffline(isOffline) { - this.state.isOffline = isOffline; - return this; - } - - getNumIncomingConnections() { - return this.state.numIncomingConnections; - } - - setNumIncomingConnections(numIncomingConnections) { - this.state.numIncomingConnections = numIncomingConnections; - return this; - } - - getNumOutgoingConnections() { - return this.state.numOutgoingConnections; - } - - setNumOutgoingConnections(numOutgoingConnections) { - this.state.numOutgoingConnections = numOutgoingConnections; - return this; - } - - getNumRpcConnections() { - return this.state.numRpcConnections; - } - - setNumRpcConnections(numRpcConnections) { - this.state.numRpcConnections = numRpcConnections; - return this; - } - - getStartTimestamp() { - return this.state.startTimestamp; - } - - setStartTimestamp(startTimestamp) { - this.state.startTimestamp = startTimestamp; - return this; - } - - getTarget() { - return this.state.target; - } - - setTarget(target) { - this.state.target = target; - return this; - } - - getTargetHeight() { - return this.state.targetHeight; - } - - setTargetHeight(targetHeight) { - this.state.targetHeight = targetHeight; - return this; - } - - getTopBlockHash() { - return this.state.topBlockHash; - } - - setTopBlockHash(topBlockHash) { - this.state.topBlockHash = topBlockHash; - return this; - } - - getNumTxs() { - return this.state.numTxs; - } - - setNumTxs(numTxs) { - this.state.numTxs = numTxs; - return this; - } - - getNumTxsPool() { - return this.state.numTxsPool; - } - - setNumTxsPool(numTxsPool) { - this.state.numTxsPool = numTxsPool; - return this; - } - - getWasBootstrapEverUsed() { - return this.state.wasBootstrapEverUsed; - } - - setWasBootstrapEverUsed(wasBootstrapEverUsed) { - this.state.wasBootstrapEverUsed = wasBootstrapEverUsed; - return this; - } - - getDatabaseSize() { - return this.state.databaseSize; - } - - setDatabaseSize(databaseSize) { - this.state.databaseSize = databaseSize; - return this; - } - - getUpdateAvailable() { - return this.state.updateAvailable; - } - - setUpdateAvailable(updateAvailable) { - this.state.updateAvailable = updateAvailable; - return this; - } - - getCredits() { - return this.state.credits; - } - - setCredits(credits) { - this.state.credits = credits; - return this; - } -} - -module.exports = MoneroDaemonInfo; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroDaemonPeer.js b/src/main/js/daemon/model/MoneroDaemonPeer.js deleted file mode 100644 index 6ce9f6d5d..000000000 --- a/src/main/js/daemon/model/MoneroDaemonPeer.js +++ /dev/null @@ -1,107 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; - -/** - * Models a peer to the daemon. - */ -class MoneroDaemonPeer { - - constructor(state) { - this.state = Object.assign({}, state); - if (this.state.rpcCreditsPerHash !== undefined && !(this.state.rpcCreditsPerHash instanceof BigInteger)) this.state.rpcCreditsPerHash = BigInteger.parse(this.state.rpcCreditsPerHash); - } - - toJson() { - let json = Object.assign({}, this.state); - if (json.rpcCreditsPerHash) json.rpcCreditsPerHash = json.rpcCreditsPerHash.toString(); - return json; - } - - getId() { - return this.state.id; - } - - setId(id) { - this.state.id = id; - return this; - } - - getAddress() { - return this.state.address; - } - - setAddress(address) { - this.state.address = address; - return this; - } - - getHost() { - return this.state.host; - } - - setHost(host) { - this.state.host = host; - return this; - } - - getPort() { - return this.state.port; - } - - setPort(port) { - this.state.port = port; - return this; - } - - /** - * Indicates if the peer was online when last checked (aka "white listed" as - * opposed to "gray listed"). - * - * @return {boolean} true if peer was online when last checked, false otherwise - */ - isOnline() { - return this.state.isOnline; - } - - setIsOnline(isOnline) { - this.state.isOnline = isOnline; - return this; - } - - getLastSeenTimestamp() { - return this.state.lastSeenTimestamp; - } - - setLastSeenTimestamp(lastSeenTimestamp) { - this.state.lastSeenTimestamp = lastSeenTimestamp; - return this; - } - - getPruningSeed() { - return this.state.pruningSeed; - } - - setPruningSeed(pruningSeed) { - this.state.pruningSeed = pruningSeed; - return this; - } - - getRpcPort() { - return this.state.rpcPort; - } - - setRpcPort(rpcPort) { - this.state.rpcPort = rpcPort; - return this; - } - - getRpcCreditsPerHash() { - return this.state.rpcCreditsPerHash; - } - - setRpcCreditsPerHash(rpcCreditsPerHash) { - this.state.rpcCreditsPerHash = rpcCreditsPerHash; - return this; - } -} - -module.exports = MoneroDaemonPeer; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroDaemonSyncInfo.js b/src/main/js/daemon/model/MoneroDaemonSyncInfo.js deleted file mode 100644 index 7354fbc80..000000000 --- a/src/main/js/daemon/model/MoneroDaemonSyncInfo.js +++ /dev/null @@ -1,125 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; -const MoneroDaemonConnection = require("./MoneroDaemonConnection"); -const MoneroDaemonConnectionSpan = require("./MoneroDaemonConnectionSpan"); - -/** - * Models daemon synchronization information. - */ -class MoneroDaemonSyncInfo { - - constructor(state) { - - // copy state - state = Object.assign({}, state); - - // deserialize if necessary - if (state.connections) { - for (let i = 0; i < state.connections.length; i++) { - if (!(state.connections[i] instanceof MoneroDaemonConnection)) { - state.connections[i] = new MoneroDaemonConnection(state.connections[i]); - } - } - } - if (state.spans) { - for (let i = 0; i < state.spans.length; i++) { - if (!(state.spans[i] instanceof MoneroDaemonConnectionSpan)) { - state.spans[i] = new MoneroDaemonConnectionSpan(state.spans[i]); - } - } - } - if (state.credits !== undefined && !(state.credits instanceof BigInteger)) state.credits = BigInteger.parse(state.credits); - - // assign internal state - this.state = state; - } - - toJson() { - let json = Object.assign({}, this.state); - if (json.connections) { - for (let i = 0; i < json.connections.length; i++) { - json.connections[i] = json.connections[i].toJson(); - } - } - if (json.spans) { - for (let i = 0; i < json.spans.length; i++) { - json.spans[i] = json.spans[i].toJson(); - } - } - if (json.credits) json.credits = json.credits.toString(); - return json; - } - - getHeight() { - return this.state.height; - } - - setHeight(height) { - this.state.height = height; - return this; - } - - getConnections() { - return this.state.connections; - } - - setConnections(connections) { - this.state.connections = connections; - return this; - } - - getSpans() { - return this.state.spans; - } - - setSpans(spans) { - this.state.spans = spans; - return this; - } - - getTargetHeight() { - return this.state.targetHeight; - } - - setTargetHeight(targetHeight) { - this.state.targetHeight = targetHeight; - return this; - } - - getNextNeededPruningSeed() { - return this.state.nextNeededPruningSeed; - } - - setNextNeededPruningSeed(nextNeededPruningSeed) { - this.state.nextNeededPruningSeed = nextNeededPruningSeed; - return this; - } - - getOverview() { - return this.state.overview; - } - - setOverview(overview) { - this.state.overview = overview; - return this; - } - - getCredits() { - return this.state.credits; - } - - setCredits(credits) { - this.state.credits = credits; - return this; - } - - getTopBlockHash() { - return this.state.topBlockHash; - } - - setTopBlockHash(topBlockHash) { - this.state.topBlockHash = topBlockHash; - return this; - } -} - -module.exports = MoneroDaemonSyncInfo; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroDaemonUpdateCheckResult.js b/src/main/js/daemon/model/MoneroDaemonUpdateCheckResult.js deleted file mode 100644 index 62cb767c6..000000000 --- a/src/main/js/daemon/model/MoneroDaemonUpdateCheckResult.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Models the result of checking for a daemon update. - */ -class MoneroDaemonUpdateCheckResult { - - /** - * Deep copy constructor. - * - * @param {MoneroDaemonUpdateCheckResult} is an existing result to deep copy from - */ - constructor(result) { - this.state = {}; - if (result !== undefined) { - assert(result instanceof MoneroDaemonUpdateCheckResult); - this.setIsUpdateAvailable(result.isUpdateAvailable()); - this.setVersion(result.getVersion()); - this.setHash(result.getHash()); - this.setAutoUri(result.getAutoUri()); - this.setUserUri(result.getUserUri()); - } - } - - /** - * Indicates if an update is available. - * - * @return {boolean} true if an update is available, false otherwise - */ - isUpdateAvailable() { - return this.state.isUpdateAvailable; - } - - setIsUpdateAvailable(isUpdateAvailable) { - this.state.isUpdateAvailable = isUpdateAvailable; - return this; - } - - /** - * Get the update's version. - * - * @return {string} is the update's version - */ - getVersion() { - return this.state.version; - } - - setVersion(version) { - this.state.version = version; - return this; - } - - /** - * Get the update's hash. - * - * @return {string} is the update's hash - */ - getHash() { - return this.state.hash; - } - - setHash(hash) { - this.state.hash = hash; - return this; - } - - /** - * Get the uri to automatically download the update. - * - * @return {string} is the uri to automatically download the update - */ - getAutoUri() { - return this.state.autoUri; - } - - setAutoUri(autoUri) { - this.state.autoUri = autoUri; - return this; - } - - /** - * Get the uri to manually download the update. - * - * @return {string} is the uri to manually download the update - */ - getUserUri() { - return this.state.userUri; - } - - setUserUri(userUri) { - this.state.userUri = userUri; - return this; - } -} - -module.exports = MoneroDaemonUpdateCheckResult; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroDaemonUpdateDownloadResult.js b/src/main/js/daemon/model/MoneroDaemonUpdateDownloadResult.js deleted file mode 100644 index e77cef0f9..000000000 --- a/src/main/js/daemon/model/MoneroDaemonUpdateDownloadResult.js +++ /dev/null @@ -1,32 +0,0 @@ -const MoneroDaemonUpdateCheckResult = require("./MoneroDaemonUpdateCheckResult"); - -/** - * Models the result of downloading an update. - */ -class MoneroDaemonUpdateDownloadResult extends MoneroDaemonUpdateCheckResult { - - /** - * Construct a download result. - * - * @param {MoneroDaemonUpdateCheckResult} is an existing result to copy from - */ - constructor(result) { - super(result); - } - - /** - * Get the path the update was downloaded to. - * - * @return {string} is the path the update was downloaded to - */ - getDownloadPath() { - return this.state.downloadPath; - } - - setDownloadPath(downloadPath) { - this.state.downloadPath = downloadPath; - return this; - } -} - -module.exports = MoneroDaemonUpdateDownloadResult; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroHardForkInfo.js b/src/main/js/daemon/model/MoneroHardForkInfo.js deleted file mode 100644 index b0f58ce26..000000000 --- a/src/main/js/daemon/model/MoneroHardForkInfo.js +++ /dev/null @@ -1,110 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; - -/** - * Monero hard fork info. - */ -class MoneroHardForkInfo { - - constructor(state) { - this.state = Object.assign({}, state); - if (this.state.credits !== undefined && !(this.state.credits instanceof BigInteger)) this.state.credits = BigInteger.parse(this.state.credits); - } - - toJson() { - let json = Object.assign({}, this.state); - if (json.credits) json.credits = json.credits.toString(); - return json; - } - - getEarliestHeight() { - return this.state.earliestHeight; - } - - setEarliestHeight(earliestHeight) { - this.state.earliestHeight = earliestHeight; - return this; - } - - isEnabled() { - return this.state.isEnabled; - } - - setIsEnabled(isEnabled) { - this.state.isEnabled = isEnabled; - return this; - } - - getState() { - return this.state.state; - } - - setState(state) { - this.state.state = state; - return this; - } - - getThreshold() { - return this.state.threshold; - } - - setThreshold(threshold) { - this.state.threshold = threshold; - return this; - } - - getVersion() { - return this.state.version; - } - - setVersion(version) { - this.state.version = version; - return this; - } - - getNumVotes() { - return this.state.numVotes; - } - - setNumVotes(numVotes) { - this.state.numVotes = numVotes; - return this; - } - - getWindow() { - return this.state.window; - } - - setWindow(window) { - this.state.window = window; - return this; - } - - getVoting() { - return this.state.voting; - } - - setVoting(voting) { - this.state.voting = voting; - return this; - } - - getCredits() { - return this.state.credits; - } - - setCredits(credits) { - this.state.credits = credits; - return this; - } - - getTopBlockHash() { - return this.state.topBlockHash; - } - - setTopBlockHash(topBlockHash) { - this.state.topBlockHash = topBlockHash; - return this; - } -} - -module.exports = MoneroHardForkInfo; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroKeyImage.js b/src/main/js/daemon/model/MoneroKeyImage.js deleted file mode 100644 index 466126ad4..000000000 --- a/src/main/js/daemon/model/MoneroKeyImage.js +++ /dev/null @@ -1,70 +0,0 @@ -const assert = require("assert"); -const GenUtils = require("../../common/GenUtils"); - -/** - * Models a Monero key image. - */ -class MoneroKeyImage { - - /** - * Construct the model. - * - * @param {MoneroKeyImage|object|string} stateOrHex is a MoneroKeyImage, JS object, or hex string to initialize from (optional) - * @param {string} signature is the key image's signature - */ - constructor(stateOrHex, signature) { - if (!stateOrHex) this.state = {}; - else if (stateOrHex instanceof MoneroKeyImage) this.state = stateOrHex.toJson(); - else if (typeof stateOrHex === "object") this.state = Object.assign({}, stateOrHex); - else if (typeof stateOrHex === "string") { - this.state = {}; - this.setHex(stateOrHex); - this.setSignature(signature); - } else { - throw new MoneroError("stateOrHex must be a MoneroKeyImage, JavaScript object, or string"); - } - } - - getHex() { - return this.state.hex; - } - - setHex(hex) { - this.state.hex = hex; - return this; - } - - getSignature() { - return this.state.signature; - } - - setSignature(signature) { - this.state.signature = signature; - return this; - } - - copy() { - return new MoneroKeyImage(this); - } - - toJson() { - return Object.assign({}, this.state); - } - - merge(keyImage) { - assert(keyImage instanceof MoneroKeyImage); - if (keyImage === this) return this; - this.setHex(GenUtils.reconcile(this.getHex(), keyImage.getHex())); - this.setSignature(GenUtils.reconcile(this.getSignature(), keyImage.getSignature())); - return this; - } - - toString(indent = 0) { - let str = ""; - str += GenUtils.kvLine("Hex", this.getHex(), indent); - str += GenUtils.kvLine("Signature", this.getSignature(), indent); - return str.slice(0, str.length - 1); // strip last newline - } -} - -module.exports = MoneroKeyImage; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroKeyImageSpentStatus.js b/src/main/js/daemon/model/MoneroKeyImageSpentStatus.js deleted file mode 100644 index 894377d4b..000000000 --- a/src/main/js/daemon/model/MoneroKeyImageSpentStatus.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Enumerate key image spent statuses. - * - * @hideconstructor - */ -class MoneroKeyImageSpentStatus {} - -/** - * Key image is not spent (value=0). - */ -MoneroKeyImageSpentStatus.NOT_SPENT = 0; - -/** - * Key image is confirmed (value=1). - */ -MoneroKeyImageSpentStatus.CONFIRMED = 1; - -/** - * Key image is in the pool (value=2). - */ -MoneroKeyImageSpentStatus.TX_POOL = 2; - -module.exports = MoneroKeyImageSpentStatus; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroMinerTxSum.js b/src/main/js/daemon/model/MoneroMinerTxSum.js deleted file mode 100644 index e04ef2c0b..000000000 --- a/src/main/js/daemon/model/MoneroMinerTxSum.js +++ /dev/null @@ -1,43 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; - -/** - * Model for the summation of miner emissions and fees. - */ -class MoneroMinerTxSum { - - constructor(state) { - state = Object.assign({}, state); - this.state = state; - - // deserialize BigIntegers - if (state.emissionSum !== undefined && !(state.emissionSum instanceof BigInteger)) state.emissionSum = BigInteger.parse(state.emissionSum); - if (state.feeSum !== undefined && !(state.feeSum instanceof BigInteger)) state.feeSum = BigInteger.parse(state.feeSum); - } - - toJson() { - let json = Object.assign({}, this.state); - if (this.getEmissionSum()) json.emissionSum = this.getEmissionSum().toString(); - if (this.getFeeSum()) json.feeSum = this.getFeeSum().toString(); - return json; - } - - getEmissionSum() { - return this.state.emissionSum; - } - - setEmissionSum(emissionSum) { - this.state.emissionSum = emissionSum; - return this; - } - - getFeeSum() { - return this.state.feeSum; - } - - setFeeSum(feeSum) { - this.state.feeSum = feeSum; - return this; - } -} - -module.exports = MoneroMinerTxSum; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroMiningStatus.js b/src/main/js/daemon/model/MoneroMiningStatus.js deleted file mode 100644 index c7c99fdd7..000000000 --- a/src/main/js/daemon/model/MoneroMiningStatus.js +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Models daemon mining status. - */ -class MoneroMiningStatus { - - constructor(state) { - if (!state) state = {}; - else if (state instanceof MoneroMiningStatus) state = state.toJson(); - else if (typeof state === "object") state = Object.assign({}, state); - else throw new MoneroError("state must be a MoneroMiningStatus or JavaScript object"); - this.state = state; - } - - toJson() { - return Object.assign({}, this.state); - } - - isActive() { - return this.state.isActive; - } - - setIsActive(isActive) { - this.state.isActive = isActive; - return this; - } - - getAddress() { - return this.state.address; - } - - setAddress(address) { - this.state.address = address; - return this; - } - - getSpeed() { - return this.state.speed; - } - - setSpeed(speed) { - this.state.speed = speed; - return this; - } - - getNumThreads() { - return this.state.numThreads; - } - - setNumThreads(numThreads) { - this.state.numThreads = numThreads; - return this; - } - - isBackground() { - return this.state.isBackground; - } - - setIsBackground(isBackground) { - this.state.isBackground = isBackground; - return this; - } -} - -module.exports = MoneroMiningStatus; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroNetworkType.js b/src/main/js/daemon/model/MoneroNetworkType.js deleted file mode 100644 index f25853e03..000000000 --- a/src/main/js/daemon/model/MoneroNetworkType.js +++ /dev/null @@ -1,61 +0,0 @@ -const assert = require("assert"); - -/** - * Defines the Monero network types (mainnet, testnet, and stagenet). - * - * @hideconstructor - */ -class MoneroNetworkType { - - /** - * Asserts that the given network type is valid. - * - * @param {int} networkType - the network type to validate as a numeric - */ - static validate(networkType) { - assert(networkType === 0 || networkType === 1 || networkType === 2, "Network type is invalid: " + networkType); - } - - /** - * Indicates if the given network type is valid or not. - * - * @param {int} networkType - the network type to validate as a numeric - * @return {boolean} true if the network type is valid, false otherwise - */ - static isValid(networkType) { - return networkType === 0 || networkType === 1 || networkType === 2; - } - - /** - * Parse the given string as a network type. - * - * @param {string} networkTypeStr - "mainnet", "testnet", or "stagenet" (case insensitive) - * @return {int} the network type as a numeric - */ - static parse(networkTypeStr) { - let str = ("" + networkTypeStr).toLowerCase(); - switch (str) { - case "mainnet": return MoneroNetworkType.MAINNET; - case "testnet": return MoneroNetworkType.TESTNET; - case "stagenet": return MoneroNetworkType.STAGENET; - default: throw new MoneroError("Invalid network type to parse: '" + networkTypeStr + "'"); - } - } -} - -/** - * Mainnet (value=0). - */ -MoneroNetworkType.MAINNET = 0; - -/** - * Testnet (value=1). - */ -MoneroNetworkType.TESTNET = 1; - -/** - * Stagnet (value=2). - */ -MoneroNetworkType.STAGENET = 2; - -module.exports = MoneroNetworkType; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroOutput.js b/src/main/js/daemon/model/MoneroOutput.js deleted file mode 100644 index 2b5dccd1b..000000000 --- a/src/main/js/daemon/model/MoneroOutput.js +++ /dev/null @@ -1,131 +0,0 @@ -const assert = require("assert"); -const BigInteger = require("../../common/biginteger").BigInteger; -const GenUtils = require("../../common/GenUtils"); -const MoneroKeyImage = require("./MoneroKeyImage"); - -/** - * Models a Monero transaction output. - * - * @class - */ -class MoneroOutput { - - /** - * Construct the model. - * - * @param {MoneroOutput|object} state is existing state to initialize from (optional) - */ - constructor(state) { - - // initialize internal state - if (!state) state = {}; - else if (state instanceof MoneroOutput) state = state.toJson(); - else if (typeof state === "object") state = Object.assign({}, state); - else throw new MoneroError("state must be a MoneroOutput or JavaScript object"); - this.state = state; - - // deserialize fields if necessary - if (state.amount !== undefined && !(state.amount instanceof BigInteger)) state.amount = BigInteger.parse(state.amount); - if (state.keyImage && !(state.keyImage instanceof MoneroKeyImage)) state.keyImage = new MoneroKeyImage(state.keyImage); - } - - getTx() { - return this.state.tx; - } - - setTx(tx) { - this.state.tx = tx; - return this; - } - - getKeyImage() { - return this.state.keyImage; - } - - setKeyImage(keyImage) { - assert(keyImage === undefined || keyImage instanceof MoneroKeyImage); - this.state.keyImage = keyImage; - return this; - } - - getAmount() { - return this.state.amount; - } - - setAmount(amount) { - this.state.amount = amount; - return this; - } - - getIndex() { - return this.state.index; - } - - setIndex(index) { - this.state.index = index; - return this; - } - - getRingOutputIndices() { - return this.state.ringOutputIndices; - } - - setRingOutputIndices(ringOutputIndices) { - this.state.ringOutputIndices = ringOutputIndices; - return this; - } - - getStealthPublicKey() { - return this.state.stealthPublicKey; - } - - setStealthPublicKey(stealthPublicKey) { - this.state.stealthPublicKey = stealthPublicKey; - return this; - } - - copy() { - return new MoneroOutput(this); - } - - toJson() { - let json = Object.assign({}, this.state); - if (this.getAmount()) json.amount = this.getAmount() ? this.getAmount().toString() : undefined; - if (this.getKeyImage()) json.keyImage = this.getKeyImage() ? this.getKeyImage().toJson() : undefined; - delete json.tx; - return json; - } - - merge(output) { - assert(output instanceof MoneroOutput); - if (this === output) return this; - - // merge txs if they're different which comes back to merging outputs - if (this.getTx() !== output.getTx()) this.getTx().merge(output.getTx()); - - // otherwise merge output fields - else { - if (this.getKeyImage() === undefined) this.setKeyImage(output.getKeyImage()); - else if (output.getKeyImage() !== undefined) this.getKeyImage().merge(output.getKeyImage()); - this.setAmount(GenUtils.reconcile(this.getAmount(), output.getAmount())); - this.setIndex(GenUtils.reconcile(this.getIndex(), output.getIndex())); - } - - return this; - } - - toString(indent = 0) { - let str = ""; - if (this.getKeyImage()) { - str += GenUtils.kvLine("Key image", "", indent); - str += this.getKeyImage().toString(indent + 1) + "\n"; - } - str += GenUtils.kvLine("Amount", this.getAmount(), indent); - str += GenUtils.kvLine("Index", this.getIndex(), indent); - str += GenUtils.kvLine("Ring output indices", this.getRingOutputIndices(), indent); - str += GenUtils.kvLine("Stealth public key", this.getStealthPublicKey(), indent); - return str === "" ? str : str.slice(0, str.length - 1); // strip last newline - } -} - -module.exports = MoneroOutput; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroOutputHistogramEntry.js b/src/main/js/daemon/model/MoneroOutputHistogramEntry.js deleted file mode 100644 index 300133385..000000000 --- a/src/main/js/daemon/model/MoneroOutputHistogramEntry.js +++ /dev/null @@ -1,56 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; - -/** - * Entry in a Monero output histogram (see get_output_histogram of Daemon RPC documentation). - */ -class MoneroOutputHistogramEntry { - - constructor(state) { - this.state = Object.assign({}, state); - if (this.state.amount !== undefined && !(this.state.amount instanceof BigInteger)) this.state.amount = BigInteger.parse(this.state.amount); - } - - toJson() { - let json = Object.assign({}, this.state); - if (json.amount) json.amount = json.amount.toString(); - return json; - } - - getAmount() { - return this.state.amount; - } - - setAmount(amount) { - this.state.amount = amount; - return this; - } - - getNumInstances() { - return this.state.numInstances; - } - - setNumInstances(numInstances) { - this.state.numInstances = numInstances; - return this; - } - - getNumUnlockedInstances() { - return this.state.numUnlockedInstances; - } - - setNumUnlockedInstances(numUnlockedInstances) { - this.state.numUnlockedInstances = numUnlockedInstances; - return this; - } - - getNumRecentInstances() { - return this.state.numRecentInstances; - } - - setNumRecentInstances(numRecentInstances) { - this.state.numRecentInstances = numRecentInstances; - return this; - } -} - -module.exports = MoneroOutputHistogramEntry; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroSubmitTxResult.js b/src/main/js/daemon/model/MoneroSubmitTxResult.js deleted file mode 100644 index a6d73286e..000000000 --- a/src/main/js/daemon/model/MoneroSubmitTxResult.js +++ /dev/null @@ -1,149 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; - -/** - * Models the result from submitting a tx to a daemon. - */ -class MoneroSubmitTxResult { - - constructor(state) { - state = Object.assign({}, state); - this.state = state; - - // deserialize BigIntegers - if (state.credits !== undefined && !(state.credits instanceof BigInteger)) state.credits = BigInteger.parse(state.credits); - } - - toJson() { - let json = Object.assign({}, this.state); - if (json.credits) json.credits = json.credits.toString(); - return json; - } - - isGood() { - return this.state.isGood; - } - - setIsGood(isGood) { - this.state.isGood = isGood; - return this; - } - - isRelayed() { - return this.state.isRelayed; - } - - setIsRelayed(isRelayed) { - this.state.isRelayed = isRelayed; - return this; - } - - isDoubleSpendSeen() { - return this.state.isDoubleSpendSeen; - } - - setIsDoubleSpend(isDoubleSpendSeen) { - this.state.isDoubleSpendSeen = isDoubleSpendSeen - return this; - } - - isFeeTooLow() { - return this.state.isFeeTooLow; - } - - setIsFeeTooLow(isFeeTooLow) { - this.state.isFeeTooLow = isFeeTooLow; - return this; - } - - isMixinTooLow() { - return this.state.isMixinTooLow; - } - - setIsMixinTooLow(isMixinTooLow) { - this.state.isMixinTooLow = isMixinTooLow; - return this; - } - - hasInvalidInput() { - return this.state.hasInvalidInput; - } - - setHasInvalidInput(hasInvalidInput) { - this.state.hasInvalidInput = hasInvalidInput; - return this; - } - - hasInvalidOutput() { - return this.state.hasInvalidOutput; - } - - setHasInvalidOutput(hasInvalidOutput) { - this.state.hasInvalidOutput = hasInvalidOutput; - return this; - } - - hasTooFewOutputs() { - return this.state.hasTooFewOutputs; - } - - setHasTooFewOutputs(hasTooFewOutputs) { - this.state.hasTooFewOutputs = hasTooFewOutputs; - return this; - } - - isOverspend() { - return this.state.isOverspend; - } - - setIsOverspend(isOverspend) { - this.state.isOverspend = isOverspend; - return this; - } - - getReason() { - return this.state.reason; - } - - setReason(reason) { - this.state.reason = reason; - return this; - } - - isTooBig() { - return this.state.isTooBig; - } - - setIsTooBig(isTooBig) { - this.state.isTooBig = isTooBig; - return this; - } - - getSanityCheckFailed() { - return this.state.sanityCheckFailed; - } - - setSanityCheckFailed(sanityCheckFailed) { - this.state.sanityCheckFailed = sanityCheckFailed; - return this; - } - - getCredits() { - return this.state.credits; - } - - setCredits(credits) { - this.state.credits = credits; - return this; - } - - getTopBlockHash() { - return this.state.topBlockHash; - } - - setTopBlockHash(topBlockHash) { - this.state.topBlockHash = topBlockHash; - return this; - } -} - -module.exports = MoneroSubmitTxResult; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroTx.js b/src/main/js/daemon/model/MoneroTx.js deleted file mode 100644 index 27ddd1cb8..000000000 --- a/src/main/js/daemon/model/MoneroTx.js +++ /dev/null @@ -1,598 +0,0 @@ -const assert = require("assert"); -const BigInteger = require("../../common/biginteger").BigInteger; -const GenUtils = require("../../common/GenUtils"); -const MoneroOutput = require("./MoneroOutput"); - -/** - * Represents a transaction on the Monero network. - * - * @class - */ -class MoneroTx { - - /** - * Construct the model. - * - * @param {MoneroTx|object} state is existing state to initialize from (optional) - */ - constructor(state) { - - // initialize internal state - if (!state) state = {}; - else if (state instanceof MoneroTx) state = state.toJson(); - else if (typeof state === "object") state = Object.assign({}, state); - else throw new MoneroError("state must be a MoneroTx or JavaScript object"); - this.state = state; - - // deserialize fee - if (state.fee !== undefined && !(state.fee instanceof BigInteger)) state.fee = BigInteger.parse(state.fee); - - // deserialize inputs - if (state.inputs) { - for (let i = 0; i < state.inputs.length; i++) { - if (!(state.inputs[i] instanceof MoneroOutput)) { - state.inputs[i] = new MoneroOutput(Object.assign(state.inputs[i], {tx: this})); - } - } - } - - // deserialize outputs - if (state.outputs) { - for (let i = 0; i < state.outputs.length; i++) { - if (!(state.outputs[i] instanceof MoneroOutput)) { - state.outputs[i] = new MoneroOutput(Object.assign(state.outputs[i], {tx: this})); - } - } - } - } - - getBlock() { - return this.state.block; - } - - setBlock(block) { - this.state.block = block; - return this; - } - - getHeight() { - return this.getBlock() === undefined ? undefined : this.getBlock().getHeight(); - } - - getHash() { - return this.state.hash; - } - - setHash(hash) { - this.state.hash = hash; - return this; - } - - getVersion() { - return this.state.version; - } - - setVersion(version) { - this.state.version = version; - return this; - } - - isMinerTx() { - return this.state.isMinerTx; - } - - setIsMinerTx(miner) { - this.state.isMinerTx = miner; - return this; - } - - getPaymentId() { - return this.state.paymentId; - } - - setPaymentId(paymentId) { - this.state.paymentId = paymentId; - return this; - } - - getFee() { - return this.state.fee; - } - - setFee(fee) { - this.state.fee = fee; - return this; - } - - getRingSize() { - return this.state.ringSize; - } - - setRingSize(ringSize) { - this.state.ringSize = ringSize; - return this; - } - - getRelay() { - return this.state.relay; - } - - setRelay(relay) { - this.state.relay = relay; - return this; - } - - isRelayed() { - return this.state.isRelayed; - } - - setIsRelayed(isRelayed) { - this.state.isRelayed = isRelayed; - return this; - } - - isConfirmed() { - return this.state.isConfirmed; - } - - setIsConfirmed(isConfirmed) { - this.state.isConfirmed = isConfirmed; - return this; - } - - inTxPool() { - return this.state.inTxPool; - } - - setInTxPool(inTxPool) { - this.state.inTxPool = inTxPool; - return this; - } - - getNumConfirmations() { - return this.state.numConfirmations; - } - - setNumConfirmations(numConfirmations) { - this.state.numConfirmations = numConfirmations; - return this; - } - - getUnlockHeight() { - return this.state.unlockHeight; - } - - setUnlockHeight(unlockHeight) { - this.state.unlockHeight = unlockHeight; - return this; - } - - getLastRelayedTimestamp() { - return this.state.lastRelayedTimestamp; - } - - setLastRelayedTimestamp(lastRelayedTimestamp) { - this.state.lastRelayedTimestamp = lastRelayedTimestamp; - return this; - } - - getReceivedTimestamp() { - return this.state.receivedTimestamp; - } - - setReceivedTimestamp(receivedTimestamp) { - this.state.receivedTimestamp = receivedTimestamp; - return this; - } - - isDoubleSpendSeen() { - return this.state.isDoubleSpendSeen; - } - - setIsDoubleSpend(isDoubleSpendSeen) { - this.state.isDoubleSpendSeen = isDoubleSpendSeen; - return this; - } - - getKey() { - return this.state.key; - } - - setKey(key) { - this.state.key = key; - return this; - } - - /** - * Get full transaction hex. Full hex = pruned hex + prunable hex. - * - * @return {string} is full transaction hex - */ - getFullHex() { - return this.state.fullHex; - } - - setFullHex(fullHex) { - this.state.fullHex = fullHex; - return this; - } - - /** - * Get pruned transaction hex. Full hex = pruned hex + prunable hex. - * - * @return {string} is pruned transaction hex - */ - getPrunedHex() { - return this.state.prunedHex; - } - - setPrunedHex(prunedHex) { - this.state.prunedHex = prunedHex; - return this; - } - - /** - * Get prunable transaction hex which is hex that is removed from a pruned - * transaction. Full hex = pruned hex + prunable hex. - * - * @return {string} is the prunable transaction hex - */ - getPrunableHex() { - return this.state.prunableHex; - } - - setPrunableHex(prunableHex) { - this.state.prunableHex = prunableHex; - return this; - } - - getPrunableHash() { - return this.state.prunableHash; - } - - setPrunableHash(prunableHash) { - this.state.prunableHash = prunableHash; - return this; - } - - getSize() { - return this.state.size; - } - - setSize(size) { - this.state.size = size; - return this; - } - - getWeight() { - return this.state.weight; - } - - setWeight(weight) { - this.state.weight = weight; - return this; - } - - getInputs() { - return this.state.inputs; - } - - setInputs(inputs) { - this.state.inputs = inputs; - return this; - } - - getOutputs() { - return this.state.outputs; - } - - setOutputs(outputs) { - this.state.outputs = outputs; - return this; - } - - getOutputIndices() { - return this.state.outputIndices; - } - - setOutputIndices(outputIndices) { - this.state.outputIndices = outputIndices; - return this; - } - - getMetadata() { - return this.state.metadata; - } - - setMetadata(metadata) { - this.state.metadata = metadata; - return this; - } - - getExtra() { - return this.state.extra; - } - - setExtra(extra) { - this.state.extra = extra; - return this; - } - - getRctSignatures() { - return this.state.rctSignatures; - } - - setRctSignatures(rctSignatures) { - this.state.rctSignatures = rctSignatures; - return this; - } - - getRctSigPrunable() { - return this.state.rctSigPrunable; - } - - setRctSigPrunable(rctSigPrunable) { - this.state.rctSigPrunable = rctSigPrunable; - return this; - } - - isKeptByBlock() { - return this.state.isKeptByBlock; - } - - setIsKeptByBlock(isKeptByBlock) { - this.state.isKeptByBlock = isKeptByBlock; - return this; - } - - isFailed() { - return this.state.isFailed; - } - - setIsFailed(isFailed) { - this.state.isFailed = isFailed; - return this; - } - - getLastFailedHeight() { - return this.state.lastFailedHeight; - } - - setLastFailedHeight(lastFailedHeight) { - this.state.lastFailedHeight = lastFailedHeight; - return this; - } - - getLastFailedHash() { - return this.state.lastFailedHash; - } - - setLastFailedHash(lastFailedHash) { - this.state.lastFailedHash = lastFailedHash; - return this; - } - - getMaxUsedBlockHeight() { - return this.state.maxUsedBlockHeight; - } - - setMaxUsedBlockHeight(maxUsedBlockHeight) { - this.state.maxUsedBlockHeight = maxUsedBlockHeight; - return this; - } - - getMaxUsedBlockHash() { - return this.state.maxUsedBlockHash; - } - - setMaxUsedBlockHash(maxUsedBlockHash) { - this.state.maxUsedBlockHash = maxUsedBlockHash; - return this; - } - - getSignatures() { - return this.state.signatures; - } - - setSignatures(signatures) { - this.state.signatures = signatures; - return this; - } - - copy() { - return new MoneroTx(this); - } - - toJson() { - let json = Object.assign({}, this.state); - if (this.getFee()) json.fee = this.getFee().toString(); - if (this.getInputs()) { - json.inputs = []; - for (let input of this.getInputs()) json.inputs.push(input.toJson()); - } - if (this.getOutputs()) { - json.outputs = []; - for (let output of this.getOutputs()) json.outputs.push(output.toJson()); - } - if (this.getExtra()) json.extra = this.getExtra().slice(); - delete json.block; // do not serialize parent block - return json; - } - - /** - * Updates this transaction by merging the latest information from the given - * transaction. - * - * @param tx is the transaction to update this transaction with - * @return {MoneroTx} this for method chaining - */ - merge(tx) { - assert(tx instanceof MoneroTx); - if (this === tx) return this; - - // merge blocks if they're different which comes back to merging txs - const MoneroBlock = require("./MoneroBlock"); - if (this.getBlock() !== tx.getBlock()) { - if (this.getBlock() === undefined) { - this.setBlock(new MoneroBlock()); - this.getBlock().setTxs([this]); - this.getBlock().setHeight(tx.getHeight()); - } - if (tx.getBlock() === undefined) { - tx.setBlock(new MoneroBlock()); - tx.getBlock().setTxs([tx]); - tx.getBlock().setHeight(this.getHeight()); - } - this.getBlock().merge(tx.getBlock()); - return this; - } - - // otherwise merge tx fields - this.setHash(GenUtils.reconcile(this.getHash(), tx.getHash())); - this.setVersion(GenUtils.reconcile(this.getVersion(), tx.getVersion())); - this.setPaymentId(GenUtils.reconcile(this.getPaymentId(), tx.getPaymentId())); - this.setFee(GenUtils.reconcile(this.getFee(), tx.getFee())); - this.setRingSize(GenUtils.reconcile(this.getRingSize(), tx.getRingSize())); - this.setIsConfirmed(GenUtils.reconcile(this.isConfirmed(), tx.isConfirmed(), {resolveTrue: true})); - this.setIsMinerTx(GenUtils.reconcile(this.isMinerTx(), tx.isMinerTx(), null, null, null)); - this.setRelay(GenUtils.reconcile(this.getRelay(), tx.getRelay(), {resolveTrue: true})); // tx can become relayed - this.setIsRelayed(GenUtils.reconcile(this.isRelayed(), tx.isRelayed(), {resolveTrue: true})); // tx can become relayed - this.setIsDoubleSpend(GenUtils.reconcile(this.isDoubleSpendSeen(), tx.isDoubleSpendSeen())); - this.setKey(GenUtils.reconcile(this.getKey(), tx.getKey())); - this.setFullHex(GenUtils.reconcile(this.getFullHex(), tx.getFullHex())); - this.setPrunedHex(GenUtils.reconcile(this.getPrunedHex(), tx.getPrunedHex())); - this.setPrunableHex(GenUtils.reconcile(this.getPrunableHex(), tx.getPrunableHex())); - this.setPrunableHash(GenUtils.reconcile(this.getPrunableHash(), tx.getPrunableHash())); - this.setSize(GenUtils.reconcile(this.getSize(), tx.getSize())); - this.setWeight(GenUtils.reconcile(this.getWeight(), tx.getWeight())); - this.setOutputIndices(GenUtils.reconcile(this.getOutputIndices(), tx.getOutputIndices())); - this.setMetadata(GenUtils.reconcile(this.getMetadata(), tx.getMetadata())); - this.setExtra(GenUtils.reconcile(this.getExtra(), tx.getExtra())); - this.setRctSignatures(GenUtils.reconcile(this.getRctSignatures(), tx.getRctSignatures())); - this.setRctSigPrunable(GenUtils.reconcile(this.getRctSigPrunable(), tx.getRctSigPrunable())); - this.setIsKeptByBlock(GenUtils.reconcile(this.isKeptByBlock(), tx.isKeptByBlock())); - this.setIsFailed(GenUtils.reconcile(this.isFailed(), tx.isFailed())); - this.setLastFailedHeight(GenUtils.reconcile(this.getLastFailedHeight(), tx.getLastFailedHeight())); - this.setLastFailedHash(GenUtils.reconcile(this.getLastFailedHash(), tx.getLastFailedHash())); - this.setMaxUsedBlockHeight(GenUtils.reconcile(this.getMaxUsedBlockHeight(), tx.getMaxUsedBlockHeight())); - this.setMaxUsedBlockHash(GenUtils.reconcile(this.getMaxUsedBlockHash(), tx.getMaxUsedBlockHash())); - this.setSignatures(GenUtils.reconcile(this.getSignatures(), tx.getSignatures())); - this.setUnlockHeight(GenUtils.reconcile(this.getUnlockHeight(), tx.getUnlockHeight())); - this.setNumConfirmations(GenUtils.reconcile(this.getNumConfirmations(), tx.getNumConfirmations(), {resolveMax: true})); // num confirmations can increase - - // merge inputs - if (tx.getInputs()) { - for (let merger of tx.getInputs()) { - let merged = false; - merger.setTx(this); - if (!this.getInputs()) this.setInputs([]); - for (let mergee of this.getInputs()) { - if (mergee.getKeyImage().getHex() === merger.getKeyImage().getHex()) { - mergee.merge(merger); - merged = true; - break; - } - } - if (!merged) this.getInputs().push(merger); - } - } - - // merge outputs - if (tx.getOutputs()) { - for (let output of tx.getOutputs()) output.setTx(this); - if (!this.getOutputs()) this.setOutputs(tx.getOutputs()); - else { - - // merge outputs if key image or stealth public key present, otherwise append - for (let merger of tx.getOutputs()) { - let merged = false; - merger.setTx(this); - for (let mergee of this.getOutputs()) { - if ((merger.getKeyImage() && mergee.getKeyImage().getHex() === merger.getKeyImage().getHex()) || - (merger.getStealthPublicKey() && mergee.getStealthPublicKey() === merger.getStealthPublicKey())) { - mergee.merge(merger); - merged = true; - break; - } - } - if (!merged) this.getOutputs().push(merger); // append output - } - } - } - - // handle unrelayed -> relayed -> confirmed - if (this.isConfirmed()) { - this.setInTxPool(false); - this.setReceivedTimestamp(undefined); - this.setLastRelayedTimestamp(undefined); - } else { - this.setInTxPool(GenUtils.reconcile(this.inTxPool(), tx.inTxPool(), {resolveTrue: true})); // unrelayed -> tx pool - this.setReceivedTimestamp(GenUtils.reconcile(this.getReceivedTimestamp(), tx.getReceivedTimestamp(), {resolveMax: false})); // take earliest receive time - this.setLastRelayedTimestamp(GenUtils.reconcile(this.getLastRelayedTimestamp(), tx.getLastRelayedTimestamp(), {resolveMax: true})); // take latest relay time - } - - return this; // for chaining - } - - toString(indent = 0) { - let str = ""; - str += GenUtils.getIndent(indent) + "=== TX ===\n"; - str += GenUtils.kvLine("Tx hash", this.getHash(), indent); - str += GenUtils.kvLine("Height", this.getHeight(), indent); - str += GenUtils.kvLine("Version", this.getVersion(), indent); - str += GenUtils.kvLine("Is miner tx", this.isMinerTx(), indent); - str += GenUtils.kvLine("Payment ID", this.getPaymentId(), indent); - str += GenUtils.kvLine("Fee", this.getFee(), indent); - str += GenUtils.kvLine("Ring size", this.getRingSize(), indent); - str += GenUtils.kvLine("Relay", this.getRelay(), indent); - str += GenUtils.kvLine("Is relayed", this.isRelayed(), indent); - str += GenUtils.kvLine("Is confirmed", this.isConfirmed(), indent); - str += GenUtils.kvLine("In tx pool", this.inTxPool(), indent); - str += GenUtils.kvLine("Num confirmations", this.getNumConfirmations(), indent); - str += GenUtils.kvLine("Unlock height", this.getUnlockHeight(), indent); - str += GenUtils.kvLine("Last relayed time", this.getLastRelayedTimestamp(), indent); - str += GenUtils.kvLine("Received time", this.getReceivedTimestamp(), indent); - str += GenUtils.kvLine("Is double spend", this.isDoubleSpendSeen(), indent); - str += GenUtils.kvLine("Key", this.getKey(), indent); - str += GenUtils.kvLine("Full hex", this.getFullHex(), indent); - str += GenUtils.kvLine("Pruned hex", this.getPrunedHex(), indent); - str += GenUtils.kvLine("Prunable hex", this.getPrunableHex(), indent); - str += GenUtils.kvLine("Prunable hash", this.getPrunableHash(), indent); - str += GenUtils.kvLine("Size", this.getSize(), indent); - str += GenUtils.kvLine("Weight", this.getWeight(), indent); - str += GenUtils.kvLine("Output indices", this.getOutputIndices(), indent); - str += GenUtils.kvLine("Metadata", this.getMetadata(), indent); - str += GenUtils.kvLine("Extra", this.getExtra(), indent); - str += GenUtils.kvLine("RCT signatures", this.getRctSignatures(), indent); - str += GenUtils.kvLine("RCT sig prunable", this.getRctSigPrunable(), indent); - str += GenUtils.kvLine("Kept by block", this.isKeptByBlock(), indent); - str += GenUtils.kvLine("Is failed", this.isFailed(), indent); - str += GenUtils.kvLine("Last failed height", this.getLastFailedHeight(), indent); - str += GenUtils.kvLine("Last failed hash", this.getLastFailedHash(), indent); - str += GenUtils.kvLine("Max used block height", this.getMaxUsedBlockHeight(), indent); - str += GenUtils.kvLine("Max used block hash", this.getMaxUsedBlockHash(), indent); - str += GenUtils.kvLine("Signatures", this.getSignatures(), indent); - if (this.getInputs()) { - str += GenUtils.kvLine("Inputs", "", indent); - for (let i = 0; i < this.getInputs().length; i++) { - str += GenUtils.kvLine(i + 1, "", indent + 1); - str += this.getInputs()[i].toString(indent + 2); - str += '\n' - } - } - if (this.getOutputs()) { - str += GenUtils.kvLine("Outputs", "", indent); - for (let i = 0; i < this.getOutputs().length; i++) { - str += GenUtils.kvLine(i + 1, "", indent + 1); - str += this.getOutputs()[i].toString(indent + 2); - str += '\n' - } - } - return str.slice(0, str.length - 1); // strip last newline - } -} - -// default payment id -MoneroTx.DEFAULT_PAYMENT_ID = "0000000000000000"; - -module.exports = MoneroTx; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroTxPoolStats.js b/src/main/js/daemon/model/MoneroTxPoolStats.js deleted file mode 100644 index dcc9a5484..000000000 --- a/src/main/js/daemon/model/MoneroTxPoolStats.js +++ /dev/null @@ -1,138 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; - -/** - * Models transaction pool statistics. - */ -class MoneroTxPoolStats { - - constructor(state) { - this.state = Object.assign({}, state); - if (this.state.feeTotal !== undefined && !(this.state.feeTotal instanceof BigInteger)) this.state.feeTotal = BigInteger.parse(this.state.feeTotal); - } - - toJson() { - let json = Object.assign({}, this.state); - if (json.feeTotal) json.feeTotal = json.feeTotal.toString(); - return json; - } - - getNumTxs() { - return this.state.numTxs; - } - - setNumTxs(numTxs) { - this.state.numTxs = numTxs; - return this; - } - - getNumNotRelayed() { - return this.state.numNotRelayed; - } - - setNumNotRelayed(numNotRelayed) { - this.state.numNotRelayed = numNotRelayed; - return this; - } - - getNumFailing() { - return this.state.numFailing; - } - - setNumFailing(numFailing) { - this.state.numFailing = numFailing; - return this; - } - - getNumDoubleSpends() { - return this.state.numDoubleSpends; - } - - setNumDoubleSpends(numDoubleSpends) { - this.state.numDoubleSpends = numDoubleSpends; - return this; - } - - getNum10m() { - return this.state.num10m; - } - - setNum10m(num10m) { - this.state.num10m = num10m; - return this; - } - - getFeeTotal() { - return this.state.feeTotal; - } - - setFeeTotal(feeTotal) { - this.state.feeTotal = feeTotal; - return this; - } - - getBytesMax() { - return this.state.bytesMax; - } - - setBytesMax(bytesMax) { - this.state.bytesMax = bytesMax; - return this; - } - - getBytesMed() { - return this.state.bytesMed; - } - - setBytesMed(bytesMed) { - this.state.bytesMed = bytesMed; - return this; - } - - getBytesMin() { - return this.state.bytesMin; - } - - setBytesMin(bytesMin) { - this.state.bytesMin = bytesMin; - return this; - } - - getBytesTotal() { - return this.state.bytesTotal; - } - - setBytesTotal(bytesTotal) { - this.state.bytesTotal = bytesTotal; - return this; - } - - // TODO: histo... what? - getHisto() { - return this.state.histo; - } - - setHisto(histo) { - this.state.histo = histo; - return this; - } - - getHisto98pc() { - return this.state.histo98pc; - } - - setHisto98pc(histo98pc) { - this.state.histo98pc = histo98pc; - return this; - } - - getOldestTimestamp() { - return this.state.oldestTimestamp; - } - - setOldestTimestamp(oldestTimestamp) { - this.state.oldestTimestamp = oldestTimestamp; - return this; - } -} - -module.exports = MoneroTxPoolStats; \ No newline at end of file diff --git a/src/main/js/daemon/model/MoneroVersion.js b/src/main/js/daemon/model/MoneroVersion.js deleted file mode 100644 index 83bf52b44..000000000 --- a/src/main/js/daemon/model/MoneroVersion.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Models a Monero version. - */ -class MoneroVersion { - - /** - * Construct the model. - * - * @param number is the version number - * @param isRelease indicates if this version is a release - */ - constructor(number, isRelease) { - this.state = {}; - this.state.number = number; - this.state.isRelease = isRelease; - } - - getNumber() { - return this.state.number; - } - - setNumber(number) { - this.state.number = number; - return this; - } - - isRelease() { - return this.state.isRelease; - } - - setIsRelease(isRelease) { - this.state.isRelease = isRelease; - return this; - } - - copy() { - return new MoneroKeyImage(this); - } - - toJson() { - return Object.assign({}, this.state); - } -} - -module.exports = MoneroVersion; \ No newline at end of file diff --git a/src/main/js/wallet/MoneroWallet.js b/src/main/js/wallet/MoneroWallet.js deleted file mode 100644 index dcc0b1a2d..000000000 --- a/src/main/js/wallet/MoneroWallet.js +++ /dev/null @@ -1,1222 +0,0 @@ -const assert = require("assert"); -const MoneroBlock = require("../daemon/model/MoneroBlock"); -const MoneroError = require("../common/MoneroError"); -const MoneroOutputQuery = require("./model/MoneroOutputQuery"); -const MoneroTransferQuery = require("./model/MoneroTransferQuery"); -const MoneroTxConfig = require("./model/MoneroTxConfig"); -const MoneroTxQuery = require("./model/MoneroTxQuery"); - -/** - * Copyright (c) woodser - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Monero wallet interface and default implementations. - * - * @interface - */ -class MoneroWallet { - - /** - * Indicates if the wallet is view-only, meaning it does have the private - * spend key and can therefore only observe incoming outputs. - * - * @return {bool} true if the wallet is view-only, false otherwise - */ - async isViewOnly() { - throw new MoneroError("Not supported"); - } - - /** - * Set the wallet's daemon connection. - * - * @param {string|MoneroRpcConnection} uriOrConnection - daemon's URI or connection (defaults to offline) - * @param {string} username - username to authenticate with the daemon (optional) - * @param {string} password - password to authenticate with the daemon (optional) - */ - async setDaemonConnection(uriOrConnection, username, password) { - throw new MoneroError("Not supported"); - } - - /** - * Get the wallet's daemon connection. - * - * @return {MoneroRpcConnection} the wallet's daemon connection - */ - async getDaemonConnection() { - throw new MoneroError("Not supported"); - } - - /** - * Indicates if the wallet is connected to daemon. - * - * @return {boolean} true if the wallet is connected to a daemon, false otherwise - */ - async isConnected() { - throw new MoneroError("Not supported"); - } - - /** - * Gets the version of the wallet. - * - * @return {MoneroVersion} the version of the wallet - */ - async getVersion() { - throw new MoneroError("Not supported"); - } - - /** - * Get the wallet's path. - * - * @return {string} the path the wallet can be opened with - */ - async getPath() { - throw new MoneroError("Not supported"); - } - - /** - * Get the wallet's mnemonic phrase derived from the seed. - * - * @return {string} the wallet's mnemonic phrase - */ - async getMnemonic() { - throw new MoneroError("Not supported"); - } - - /** - * Get the language of the wallet's mnemonic phrase. - * - * @return {string} the language of the wallet's mnemonic phrase - */ - async getMnemonicLanguage() { - throw new MoneroError("Not supported"); - } - - /** - * Get the wallet's private view key. - * - * @return {string} the wallet's private view key - */ - async getPrivateViewKey() { - throw new MoneroError("Not supported"); - } - - /** - * Get the wallet's private spend key. - * - * @return {string} the wallet's private spend key - */ - async getPrivateSpendKey() { - throw new MoneroError("Not supported"); - } - - /** - * Get the wallet's public view key. - * - * @return {string} the wallet's public view key - */ - async getPublicViewKey() { - throw new MoneroError("Not supported"); - } - - /** - * Get the wallet's public spend key. - * - * @return {string} the wallet's public spend key - */ - async getPublicSpendKey() { - throw new MoneroError("Not supported"); - } - - /** - * Get the wallet's primary address. - * - * @return {string} the wallet's primary address - */ - async getPrimaryAddress() { - return await this.getAddress(0, 0); - } - - /** - * Get the address of a specific subaddress. - * - * @param {int} accountIdx - the account index of the address's subaddress - * @param {int} subaddressIdx - the subaddress index within the account - * @return {string} the receive address of the specified subaddress - */ - async getAddress(accountIdx, subaddressIdx) { - throw new MoneroError("Not supported"); - } - - /** - * Get the account and subaddress index of the given address. - * - * @param {string} address - address to get the account and subaddress index from - * @return {MoneroSubaddress} the account and subaddress indices - */ - async getAddressIndex(address) { - throw new MoneroError("Not supported"); - } - - /** - * Get an integrated address based on this wallet's primary address and the - * given payment ID. Generates a random payment ID if none is given. - * - * @param {string} paymentId - payment ID to generate an integrated address from (randomly generated if undefined) - * @return {MoneroIntegratedAddress} the integrated address - */ - async getIntegratedAddress(paymentId) { - throw new MoneroError("Not supported"); - } - - /** - * Decode an integrated address to get its standard address and payment id. - * - * @param {string} integratedAddress - integrated address to decode - * @return {MoneroIntegratedAddress} the decoded integrated address including standard address and payment id - */ - async decodeIntegratedAddress(integratedAddress) { - throw new MoneroError("Not supported"); - } - - /** - * Get the height of the last block processed by the wallet (its index + 1). - * - * @return {int} the height of the last block processed by the wallet - */ - async getHeight() { - throw new MoneroError("Not supported"); - } - - /** - * Get the blockchain's height. - * - * @return {int} the blockchain's height - */ - async getDaemonHeight() { - throw new MoneroError("Not supported"); - } - - /** - * Get the blockchain's height by date as a conservative estimate for scanning. - * - * @param {int} year - year of the height to get - * @param {int} month - month of the height to get as a number between 1 and 12 - * @param {int} day - day of the height to get as a number between 1 and 31 - * @return the blockchain's approximate height at the given date - */ - async getHeightByDate(year, month, day) { - throw new MoneroError("Not supported"); - } - - /** - * Synchronize the wallet with the daemon as a one-time synchronous process. - * - * @param {MoneroWalletListener|number} listenerOrStartHeight - listener xor start height (defaults to no sync listener, the last synced block) - * @param {number} startHeight - startHeight if not given in first arg (defaults to last synced block) - */ - async sync(listenerOrStartHeight, startHeight) { - throw new MoneroError("Not supported"); - } - - /** - * Start an asynchronous thread to continuously synchronize the wallet with the daemon. - */ - async startSyncing() { - throw new MoneroError("Not supported"); - } - - /** - * Stop synchronizing the wallet with the daemon. - */ - async stopSyncing() { - throw new MoneroError("Not supported"); - } - - /** - *

Rescan the blockchain for spent outputs.

- * - *

Note: this can only be called with a trusted daemon.

- * - *

Example use case: peer multisig hex is import when connected to an untrusted daemon, - * so the wallet will not rescan spent outputs. Then the wallet connects to a trusted - * daemon. This method should be manually invoked to rescan outputs.

- */ - async rescanSpent() { - throw new MoneroError("Not supported"); - } - - /** - *

Rescan the blockchain from scratch, losing any information which cannot be recovered from - * the blockchain itself.

- * - *

WARNING: This method discards local wallet data like destination addresses, tx secret keys, - * tx notes, etc.

- */ - async rescanBlockchain() { - throw new MoneroError("Not supported"); - } - - /** - * Get the balance of the wallet, account, or subaddress. - * - * @param {int} accountIdx - index of the account to get the balance of (optional) - * @param {int} subaddressIdx - index of the subaddress to get the balance of (optional) - * @return {BigInteger} the balance of the wallet, account, or subaddress - */ - async getBalance(accountIdx, subaddressIdx) { - throw new MoneroError("Not supported"); - } - - /** - * Get the unlocked balance of the wallet, account, or subaddress. - * - * @param {int} accountIdx - index of the account to get the unlocked balance of (optional) - * @param {int} subaddressIdx - index of the subaddress to get the unlocked balance of (optional) - * @return {BigInteger} the unlocked balance of the wallet, account, or subaddress - */ - async getUnlockedBalance(accountIdx, subaddressIdx) { - throw new MoneroError("Not supported"); - } - - /** - * Get accounts with a given tag. - * - * @param {boolean} includeSubaddresses - include subaddresses if true - * @param {string} tag - tag for filtering accounts, all accounts if undefined - * @return {MoneroAccount[]} all accounts with the given tag - */ - async getAccounts(includeSubaddresses, tag) { - throw new MoneroError("Not supported"); - } - - /** - * Get an account. - * - * @param {int} accountIdx - index of the account to get - * @param {boolean} includeSubaddresses - include subaddresses if true - * @return {MoneroAccount} the retrieved account - */ - async getAccount(accountIdx, includeSubaddresses) { - throw new MoneroError("Not supported"); - } - - /** - * Create a new account with a label for the first subaddress. - * - * @param {string} label - label for account's first subaddress (optional) - * @return {MoneroAccount} the created account - */ - async createAccount(label) { - throw new MoneroError("Not supported"); - } - - /** - * Get subaddresses in an account. - * - * @param {int} accountIdx - account to get subaddresses within - * @param {int[]} subaddressIndices - indices of subaddresses to get (optional) - * @return {MoneroSubaddress[]} the retrieved subaddresses - */ - async getSubaddresses(accountIdx, subaddressIndices) { - throw new MoneroError("Not supported"); - } - - /** - * Get a subaddress. - * - * @param {int} accountIdx - index of the subaddress's account - * @param {int} subaddressIdx - index of the subaddress within the account - * @return {MoneroSubaddress} the retrieved subaddress - */ - async getSubaddress(accountIdx, subaddressIdx) { - assert(accountIdx >= 0); - assert(subaddressIdx >= 0); - return (await this.getSubaddresses(accountIdx, subaddressIdx))[0]; - } - - /** - * Create a subaddress within an account. - * - * @param {int} accountIdx - index of the account to create the subaddress within - * @param {string} label - the label for the subaddress (optional) - * @return {MoneroSubaddress} the created subaddress - */ - async createSubaddress(accountIdx, label) { - throw new MoneroError("Not supported"); - } - - /** - * Get a wallet transaction by hash. - * - * @param {string} txHash - hash of a transaction to get - * @return {MoneroTxWallet} the identified transactions - */ - async getTx(txHash) { - return (await this.getTxs([txHash]))[0]; - } - - /** - *

Get wallet transactions. Wallet transactions contain one or more - * transfers that are either incoming or outgoing to the wallet.

- * - *

Results can be filtered by passing a query object. Transactions must - * meet every criteria defined in the query in order to be returned. All - * criteria are optional and no filtering is applied when not defined.

- * - * @param {(MoneroTxQuery|string[]|object)} query - configures the query (optional) - * @param {boolean} query.isConfirmed - get txs that are confirmed or not (optional) - * @param {boolean} query.inTxPool - get txs that are in the tx pool or not (optional) - * @param {boolean} query.isRelayed - get txs that are relayed or not (optional) - * @param {boolean} query.isFailed - get txs that are failed or not (optional) - * @param {boolean} query.isMinerTx - get miner txs or not (optional) - * @param {string} query.hash - get a tx with the hash (optional) - * @param {string[]} query.hashes - get txs with the hashes (optional) - * @param {string} query.paymentId - get transactions with the payment id (optional) - * @param {string[]} query.paymentIds - get transactions with the payment ids (optional) - * @param {boolean} query.hasPaymentId - get transactions with a payment id or not (optional) - * @param {int} query.minHeight - get txs with height >= the given height (optional) - * @param {int} query.maxHeight - get txs with height <= the given height (optional) - * @param {boolean} query.isOutgoing - get txs with an outgoing transfer or not (optional) - * @param {boolean} query.isIncoming - get txs with an incoming transfer or not (optional) - * @param {MoneroTransferQuery} query.transferQuery - get txs that have a transfer that meets this query (optional) - * @param {boolean} query.includeOutputs - specifies that tx outputs should be returned with tx results (optional) - * @param {string[]} missingTxHashes - populated with hashes of unfound or unmet transactions that were queried by hash (throws error if undefined and queried transaction hashes are unfound or unmet) - * @return {MoneroTxWallet[]} wallet transactions per the configuration - */ - async getTxs(query, missingTxHashes) { - throw new MoneroError("Not supported"); - } - - /** - *

Get incoming and outgoing transfers to and from this wallet. An outgoing - * transfer represents a total amount sent from one or more subaddresses - * within an account to individual destination addresses, each with their - * own amount. An incoming transfer represents a total amount received into - * a subaddress within an account. Transfers belong to transactions which - * are stored on the blockchain.

- * - *

Results can be filtered by passing a query object. Transfers must - * meet every criteria defined in the query in order to be returned. All - * criteria are optional and no filtering is applied when not defined.

- * - * @param {(MoneroTransferQuery|object)} query - configures the query (optional) - * @param {boolean} query.isOutgoing - get transfers that are outgoing or not (optional) - * @param {boolean} query.isIncoming - get transfers that are incoming or not (optional) - * @param {string} query.address - wallet's address that a transfer either originated from (if outgoing) or is destined for (if incoming) (optional) - * @param {int} query.accountIndex - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific account index (optional) - * @param {int} query.subaddressIndex - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific subaddress index (optional) - * @param {int[]} query.subaddressIndices - get transfers that either originated from (if outgoing) or are destined for (if incoming) specific subaddress indices (optional) - * @param {BigInteger} query.amount - amount being transferred (optional) - * @param {MoneroDestination[]} query.destinations - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional) - * @param {boolean} query.hasDestinations - get transfers that have destinations or not (optional) - * @param {MoneroTxQuery} query.txQuery - get transfers whose transaction meets this query (optional) - * @return {MoneroTransfer[]} are wallet transfers per the configuration - */ - async getTransfers(query) { - throw new MoneroError("Not supported"); - } - - /** - * Get all of the wallet's incoming transfers. - * - * @param query - passed to getTransfers() with isIncoming=true - * @return {MoneroIncomingTransfer[]} the wallet's incoming transfers - */ - async getIncomingTransfers(query) { - - // copy query and set direction - let _query; - if (query === undefined) _query = new MoneroTransferQuery(); - else { - if (query.isIncoming() === false) throw new MoneroError("Transfer query contradicts getting incoming transfers"); - _query = query.copy(); - } - _query.setIsIncoming(true); - - // fetch and cast transfers - let inTransfers = []; - for (let transfer of await this.getTransfers(_query)) { - inTransfers.push(transfer); - } - return inTransfers; - } - - /** - * Get all of the wallet's outgoing transfers. - * - * @param query - passed to getTransfers() with isOutgoing=true - * @return {MoneroOutgoingTransfer[]} the wallet's outgoing transfers - */ - async getOutgoingTransfers(query) { - - // copy query and set direction - let _query; - if (query === undefined) _query = new MoneroTransferQuery(); - else { - if (query.isOutgoing() === false) throw new MoneroError("Transfer query contradicts getting outgoing transfers"); - _query = query.copy(); - } - _query.setIsOutgoing(true); - - // fetch and cast transfers - let outTransfers = []; - for (let transfer of await this.getTransfers(_query)) { - outTransfers.push(transfer); - } - return outTransfers; - } - - /** - *

Get outputs created from previous transactions that belong to the wallet - * (i.e. that the wallet can spend one time). Outputs are part of - * transactions which are stored in blocks on the blockchain.

- * - *

Results can be filtered by passing a query object. Outputs must - * meet every criteria defined in the query in order to be returned. All - * filtering is optional and no filtering is applied when not defined.

- * - * @param {(MoneroOutputQuery|object)} query - configures the query (optional) - * @param {int} query.accountIndex - get outputs associated with a specific account index (optional) - * @param {int} query.subaddressIndex - get outputs associated with a specific subaddress index (optional) - * @param {int[]} query.subaddressIndices - get outputs associated with specific subaddress indices (optional) - * @param {BigInteger} query.amount - get outputs with a specific amount (optional) - * @param {BigInteger} query.minAmount - get outputs greater than or equal to a minimum amount (optional) - * @param {BigInteger} query.maxAmount - get outputs less than or equal to a maximum amount (optional) - * @param {boolean} query.isSpent - get outputs that are spent or not (optional) - * @param {string|MoneroKeyImage} query.keyImage - get output with a key image or which matches fields defined in a MoneroKeyImage (optional) - * @param {MoneroTxQuery} query.txQuery - get outputs whose transaction meets this filter (optional) - * @return {MoneroOutputWallet[]} are queried outputs - */ - async getOutputs(query) { - throw new MoneroError("Not supported"); - } - - /** - * Export all outputs in hex format. - * - * @return {string} all outputs in hex format, undefined if no outputs - */ - async getOutputsHex() { - throw new MoneroError("Not supported"); - } - - /** - * Import outputs in hex format. - * - * @param {string} outputsHex - outputs in hex format - * @return {int} the number of outputs imported - */ - async importOutputsHex(outputsHex) { - throw new MoneroError("Not supported"); - } - - /** - * Get all signed key images. - * - * @return {MoneroKeyImage[]} the wallet's signed key images - */ - async getKeyImages() { - throw new MoneroError("Not supported"); - } - - /** - * Import signed key images and verify their spent status. - * - * @param {MoneroKeyImage[]} keyImages - images to import and verify (requires hex and signature) - * @return {MoneroKeyImageImportResult} results of the import - */ - async importKeyImages(keyImages) { - throw new MoneroError("Not supported"); - } - - /** - * Get new key images from the last imported outputs. - * - * @return {MoneroKeyImage[]} the key images from the last imported outputs - */ - async getNewKeyImagesFromLastImport() { - throw new MoneroError("Not supported"); - } - - /** - * Create a transaction to transfer funds from this wallet. - * - * @param {MoneroTxConfig|object} config - configures the transaction to create (required) - * @param {string} config.address - single destination address (required unless `destinations` provided) - * @param {BigInteger|string} config.amount - single destination amount (required unless `destinations` provided) - * @param {int} config.accountIndex - source account index to transfer funds from (required) - * @param {int} config.subaddressIndex - source subaddress index to transfer funds from (optional) - * @param {int[]} config.subaddressIndices - source subaddress indices to transfer funds from (optional) - * @param {boolean} config.relay - relay the transaction to peers to commit to the blockchain (default false) - * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL) - * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided) - * @param {string} config.paymentId - transaction payment ID (optional) - * @param {int} config.unlockHeight - minimum height for the transaction to unlock (default 0) - * @return {MoneroTxWallet} the created transaction - */ - async createTx(config) { - config = MoneroWallet._normalizeCreateTxsConfig(config); - if (config.getCanSplit() !== undefined) assert.equal(config.getCanSplit(), false, "Cannot split transactions using createTx(); use createTxs()"); - config.setCanSplit(false); - return (await this.createTxs(config))[0]; - } - - /** - * Create one or more transactions to transfer funds from this wallet. - * - * @param {MoneroTxConfig|object} config - configures the transactions to create (required) - * @param {string} config.address - single destination address (required unless `destinations` provided) - * @param {BigInteger|string} config.amount - single destination amount (required unless `destinations` provided) - * @param {int} config.accountIndex - source account index to transfer funds from (required) - * @param {int} config.subaddressIndex - source subaddress index to transfer funds from (optional) - * @param {int[]} config.subaddressIndices - source subaddress indices to transfer funds from (optional) - * @param {boolean} config.relay - relay the transactions to peers to commit to the blockchain (default false) - * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL) - * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided) - * @param {string} config.paymentId - transaction payment ID (optional) - * @param {int} config.unlockHeight - minimum height for the transactions to unlock (default 0) - * @param {boolean} config.canSplit - allow funds to be transferred using multiple transactions (default true) - * @return {MoneroTxWallet[]} the created transactions - */ - async createTxs(config) { - throw new MoneroError("Not supported"); - } - - /** - * Sweep an output by key image. - * - * @param {MoneroTxConfig} config - configures the transaction to create (required) - * @param {string} config.address - single destination address (required) - * @param {string} config.keyImage - key image to sweep (required) - * @param {boolean} config.relay - relay the transaction to peers to commit to the blockchain (default false) - * @param {int} config.unlockHeight - minimum height for the transaction to unlock (default 0) - * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL) - * @return {MoneroTxWallet} the created transaction - */ - async sweepOutput(config) { - throw new MoneroError("Not supported"); - } - - /** - * Sweep all unlocked funds according to the given configuration. - * - * @param {MoneroTxConfig|object} config - configures the transactions to create (required) - * @param {string} config.address - single destination address (required) - * @param {int} config.accountIndex - source account index to sweep from from (required) - * @param {int} config.subaddressIndex - source subaddress index to sweep from (optional) - * @param {int[]} config.subaddressIndices - source subaddress indices to sweep from (optional) - * @param {boolean} config.relay - relay the transactions to peers to commit to the blockchain (default false) - * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL) - * @param {int} config.unlockHeight - minimum height for the transactions to unlock (default 0) - * @return {MoneroTxWallet[]} the created transactions - */ - async sweepUnlocked(config) { - throw new MoneroError("Not supported"); - } - - /** - *

Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

- * - *

NOTE: Dust only exists pre RCT, so this method will throw "no dust to sweep" on new wallets.

- * - * @param {boolean} relay - specifies if the resulting transaction should be relayed (default false) - * @return {MoneroTxWallet[]} the created transactions - */ - async sweepDust(relay) { - throw new MoneroError("Not supported"); - } - - /** - * Relay a previously created transaction. - * - * @param {(MoneroTxWallet|string)} txOrMetadata - transaction or its metadata to relay - * @return {string} the hash of the relayed tx - */ - async relayTx(txOrMetadata) { - return (await this.relayTxs([txOrMetadata]))[0]; - } - - /** - * Relay previously created transactions. - * - * @param {(MoneroTxWallet[]|string[])} txsOrMetadatas - transactions or their metadata to relay - * @return {string[]} the hashes of the relayed txs - */ - async relayTxs(txsOrMetadatas) { - throw new MoneroError("Not supported"); - } - - /** - * Parse a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions. - * - * @param {MoneroTxSet} txSet - a tx set containing unsigned or multisig tx hex - * @return {MoneroTxSet} the parsed tx set containing structured transactions - */ - async parseTxSet(txSet) { - throw new MoneroError("Not supported"); - } - - /** - * Sign unsigned transactions from a view-only wallet. - * - * @param {string} unsignedTxHex - unsigned transaction hex from when the transactions were created - * @return {string} the signed transaction hex - */ - async signTxs(unsignedTxHex) { - throw new MoneroError("Not supported"); - } - - /** - * Submit signed transactions from a view-only wallet. - * - * @param {string} signedTxHex - signed transaction hex from signTxs() - * @return {string[]} the resulting transaction hashes - */ - async submitTxs(signedTxHex) { - throw new MoneroError("Not supported"); - } - - /** - * Sign a message. - * - * @param {string} msg - message to sign - * @return {string} the signature - */ - async signMessage(message) { - throw new MoneroError("Not supported"); - } - - /** - * Verify a signature on a message. - * - * @param {string} msg - signed message - * @param {string} address - signing address - * @param {string} signature - signature - * @return {boolean} true if the signature is good, false otherwise - */ - async verifyMessage(message, address, signature) { - throw new MoneroError("Not supported"); - } - - /** - * Get a transaction's secret key from its hash. - * - * @param {string} txHash - transaction's hash - * @return {string} - transaction's secret key - */ - async getTxKey(txHash) { - throw new MoneroError("Not supported"); - } - - /** - * Check a transaction in the blockchain with its secret key. - * - * @param {string} txHash - transaction to check - * @param {string} txKey - transaction's secret key - * @param {string} address - destination public address of the transaction - * @return {MoneroCheckTx} the result of the check - */ - async checkTxKey(txHash, txKey, address) { - throw new MoneroError("Not supported"); - } - - /** - * Get a transaction signature to prove it. - * - * @param {string} txHash - transaction to prove - * @param {string} address - destination public address of the transaction - * @param {string} message - message to include with the signature to further authenticate the proof (optional) - * @return {string} the transaction signature - */ - async getTxProof(txHash, address, message) { - throw new MoneroError("Not supported"); - } - - /** - * Prove a transaction by checking its signature. - * - * @param {string} txHash - transaction to prove - * @param {string} address - destination public address of the transaction - * @param {string} message - message included with the signature to further authenticate the proof (optional) - * @param {string} signature - transaction signature to confirm - * @return {MoneroCheckTx} the result of the check - */ - async checkTxProof(txHash, address, message, signature) { - throw new MoneroError("Not supported"); - } - - /** - * Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address. - * - * @param {string} txHash - transaction to prove - * @param {string} message - message to include with the signature to further authenticate the proof (optional) - * @return {string} the transaction signature - */ - async getSpendProof(txHash, message) { - throw new MoneroError("Not supported"); - } - - /** - * Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address. - * - * @param {string} txHash - transaction to prove - * @param {string} message - message included with the signature to further authenticate the proof (optional) - * @param {string} signature - transaction signature to confirm - * @return {boolean} true if the signature is good, false otherwise - */ - async checkSpendProof(txHash, message, signature) { - throw new MoneroError("Not supported"); - } - - /** - * Generate a signature to prove the entire balance of the wallet. - * - * @param message - message included with the signature to further authenticate the proof (optional) - * @return the reserve proof signature - */ - async getReserveProofWallet(message) { - throw new MoneroError("Not supported"); - } - - /** - * Generate a signature to prove an available amount in an account. - * - * @param {int} accountIdx - account to prove ownership of the amount - * @param {BigInteger} amount - minimum amount to prove as available in the account - * @param {string} message - message to include with the signature to further authenticate the proof (optional) - * @return {string} the reserve proof signature - */ - async getReserveProofAccount(accountIdx, amount, message) { - throw new MoneroError("Not supported"); - } - - /** - * Proves a wallet has a disposable reserve using a signature. - * - * @param {string} address - public wallet address - * @param {string} message - message included with the signature to further authenticate the proof (optional) - * @param {string} signature - reserve proof signature to check - * @return {MoneroCheckReserve} the result of checking the signature proof - */ - async checkReserveProof(address, message, signature) { - throw new MoneroError("Not supported"); - } - - /** - * Get a transaction note. - * - * @param {string} txHash - transaction to get the note of - * @return {string} the tx note - */ - async getTxNote(txHash) { - return (await this.getTxNotes([txHash]))[0]; - } - - /** - * Get notes for multiple transactions. - * - * @param {string[]} txHashes - hashes of the transactions to get notes for - * @return {string[]} notes for the transactions - */ - async getTxNotes(txHashes) { - throw new MoneroError("Not supported"); - } - - /** - * Set a note for a specific transaction. - * - * @param {string} txHash - hash of the transaction to set a note for - * @param {string} note - the transaction note - */ - async setTxNote(txHash, note) { - await this.setTxNotes([txHash], [note]); - } - - /** - * Set notes for multiple transactions. - * - * @param {string[]} txHashes - transactions to set notes for - * @param {string[]} notes - notes to set for the transactions - */ - async setTxNotes(txHashes, notes) { - throw new MoneroError("Not supported"); - } - - /** - * Get address book entries. - * - * @param {int[]} entryIndices - indices of the entries to get - * @return {MoneroAddressBookEntry[]} the address book entries - */ - async getAddressBookEntries(entryIndices) { - throw new MoneroError("Not supported"); - } - - /** - * Add an address book entry. - * - * @param {string} address - entry address - * @param {string} description - entry description (optional) - * @return {int} the index of the added entry - */ - async addAddressBookEntry(address, description) { - throw new MoneroError("Not supported"); - } - - /** - * Edit an address book entry. - * - * @param {number} index - index of the address book entry to edit - * @param {boolean} setAddress - specifies if the address should be updated - * @param {string} address - updated address - * @param {boolean} setDescription - specifies if the description should be updated - * @param {string} description - updated description - */ - async editAddressBookEntry(index, setAddress, address, setDescription, description) { - throw new MoneroError("Not supported"); - } - - /** - * Delete an address book entry. - * - * @param {int} entryIdx - index of the entry to delete - */ - async deleteAddressBookEntry(entryIdx) { - throw new MoneroError("Not supported"); - } - - /** - * Tag accounts. - * - * @param {string} tag - tag to apply to the specified accounts - * @param {int[]} accountIndices - indices of the accounts to tag - */ - async tagAccounts(tag, accountIndices) { - throw new MoneroError("Not supported"); - } - - /** - * Untag accounts. - * - * @param {int[]} accountIndices - indices of the accounts to untag - */ - async untagAccounts(accountIndices) { - throw new MoneroError("Not supported"); - } - - /** - * Return all account tags. - * - * @return {MoneroAccountTag[]} the wallet's account tags - */ - async getAccountTags() { - throw new MoneroError("Not supported"); - } - - /** - * Sets a human-readable description for a tag. - * - * @param {string} tag - tag to set a description for - * @param {string} label - label to set for the tag - */ - async setAccountTagLabel(tag, label) { - throw new MoneroError("Not supported"); - } - - /** - * Creates a payment URI from a send configuration. - * - * @param {MoneroTxConfig} config - specifies configuration for a potential tx - * @return {string} the payment uri - */ - async createPaymentUri(config) { - throw new MoneroError("Not supported"); - } - - /** - * Parses a payment URI to a tx config. - * - * @param {string} uri - payment uri to parse - * @return {MoneroTxConfig} the send configuration parsed from the uri - */ - async parsePaymentUri(uri) { - throw new MoneroError("Not supported"); - } - - /** - * Get an attribute. - * - * @param {string} key - attribute to get the value of - * @return {string} the attribute's value - */ - async getAttribute(key) { - throw new MoneroError("Not supported"); - } - - /** - * Set an arbitrary attribute. - * - * @param {string} key - attribute key - * @param {string} val - attribute value - */ - async setAttribute(key, val) { - throw new MoneroError("Not supported"); - } - - /** - * Start mining. - * - * @param {int} numThreads - number of threads created for mining (optional) - * @param {boolean} backgroundMining - specifies if mining should occur in the background (optional) - * @param {boolean} ignoreBattery - specifies if the battery should be ignored for mining (optional) - */ - async startMining(numThreads, backgroundMining, ignoreBattery) { - throw new MoneroError("Not supported"); - } - - /** - * Stop mining. - */ - async stopMining() { - throw new MoneroError("Not supported"); - } - - /** - * Indicates if importing multisig data is needed for returning a correct balance. - * - * @return {boolean} true if importing multisig data is needed for returning a correct balance, false otherwise - */ - async isMultisigImportNeeded() { - throw new MoneroError("Not supported"); - } - - /** - * Indicates if this wallet is a multisig wallet. - * - * @return {boolean} true if this is a multisig wallet, false otherwise - */ - async isMultisig() { - return (await this.getMultisigInfo()).isMultisig(); - } - - /** - * Get multisig info about this wallet. - * - * @return {MoneroMultisigInfo} multisig info about this wallet - */ - async getMultisigInfo() { - throw new MoneroError("Not supported"); - } - - /** - * Get multisig info as hex to share with participants to begin creating a - * multisig wallet. - * - * @return {string} this wallet's multisig hex to share with participants - */ - async prepareMultisig() { - throw new MoneroError("Not supported"); - } - - /** - * Make this wallet multisig by importing multisig hex from participants. - * - * @param {String[]} multisigHexes - multisig hex from each participant - * @param {int} threshold - number of signatures needed to sign transfers - * @param {string} password - wallet password - * @return {MoneroMultisigInitResult} the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not N/N - */ - async makeMultisig(multisigHexes, threshold, password) { - throw new MoneroError("Not supported"); - } - - /** - * Exchange multisig hex with participants in a M/N multisig wallet. - * - * This process must be repeated with participants exactly N-M times. - * - * @param {string[]} multisigHexes are multisig hex from each participant - * @param {string} password - wallet's password // TODO monero core: redundant? wallet is created with password - * @return {MoneroMultisigInitResult} the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done - */ - async exchangeMultisigKeys(multisigHexes, password) { - throw new MoneroError("Not supported"); - } - - /** - * Export this wallet's multisig info as hex for other participants. - * - * @return {string} this wallet's multisig info as hex for other participants - */ - async getMultisigHex() { - throw new MoneroError("Not supported"); - } - - /** - * Import multisig info as hex from other participants. - * - * @param {string[]} multisigHexes - multisig hex from each participant - * @return {int} the number of outputs signed with the given multisig hex - */ - async importMultisigHex(multisigHexes) { - throw new MoneroError("Not supported"); - } - - /** - * Sign multisig transactions from a multisig wallet. - * - * @param {string} multisigTxHex - unsigned multisig transactions as hex - * @return {MoneroMultisigSignResult} the result of signing the multisig transactions - */ - async signMultisigTxHex(multisigTxHex) { - throw new MoneroError("Not supported"); - } - - /** - * Submit signed multisig transactions from a multisig wallet. - * - * @param {string} signedMultisigTxHex - signed multisig hex returned from signMultisigTxHex() - * @return {string[]} the resulting transaction hashes - */ - async submitMultisigTxHex(signedMultisigTxHex) { - throw new MoneroError("Not supported"); - } - - /** - * Save the wallet at its current path. - */ - save() { - throw new MoneroError("Not supported"); - } - - /** - * Optionally save then close the wallet. - * - * @param {boolean} save - specifies if the wallet should be saved before being closed (default false) - */ - async close(save) { - throw new MoneroError("Not supported"); - } - - /** - * Indicates if this wallet is closed or not. - * - * @return {boolean} true if the wallet is closed, false otherwise - */ - async isClosed() { - throw new MoneroError("Not supported"); - } - - // -------------------------------- PRIVATE --------------------------------- - - static _normalizeTxQuery(query) { - if (query instanceof MoneroTxQuery) query = query.copy(); - else if (Array.isArray(query)) query = new MoneroTxQuery().setHashes(query); - else { - query = Object.assign({}, query); - query = new MoneroTxQuery(query); - } - if (query.getBlock() === undefined) query.setBlock(new MoneroBlock().setTxs([query])); - return query; - } - - static _normalizeTransferQuery(query) { - if (query === undefined) query = new MoneroTransferQuery(); - else if (query instanceof MoneroTransferQuery) { - if (query.getTxQuery() === undefined) query = query.copy(); - else { - let txQuery = query.getTxQuery().copy(); - if (query.getTxQuery().getTransferQuery() === query) query = txQuery.getTransferQuery(); - else { - assert.equal(query.getTxQuery().getTransferQuery(), undefined, "Transfer query's tx query must be circular reference or null"); - query = query.copy(); - query.setTxQuery(txQuery); - } - } - } else { - query = Object.assign({}, query); - query = new MoneroTransferQuery(query); - } - if (query.getTxQuery() === undefined) query.setTxQuery(new MoneroTxQuery()); - query.getTxQuery().setTransferQuery(query); - if (query.getTxQuery().getBlock() === undefined) query.getTxQuery().setBlock(new MoneroBlock().setTxs([query.getTxQuery()])); - return query; - } - - static _normalizeOutputQuery(query) { - if (query === undefined) query = new MoneroOutputQuery(); - else if (query instanceof MoneroOutputQuery) { - if (query.getTxQuery() === undefined) query = query.copy(); - else { - let txQuery = query.getTxQuery().copy(); - if (query.getTxQuery().getOutputQuery() === query) query = txQuery.getOutputQuery(); - else { - assert.equal(query.getTxQuery().getOutputQuery(), undefined, "Output query's tx query must be circular reference or null"); - query = query.copy(); - query.setTxQuery(txQuery); - } - } - } else { - query = Object.assign({}, query); - query = new MoneroOutputQuery(query); - } - if (query.getTxQuery() === undefined) query.setTxQuery(new MoneroTxQuery()); - query.getTxQuery().setOutputQuery(query); - if (query.getTxQuery().getBlock() === undefined) query.getTxQuery().setBlock(new MoneroBlock().setTxs([query.getTxQuery()])); - return query; - } - - static _normalizeCreateTxsConfig(config) { - if (config === undefined || !(config instanceof Object)) throw new MoneroError("Must provide MoneroTxConfig or equivalent JS object"); - config = new MoneroTxConfig(config); - assert(config.getDestinations() && config.getDestinations().length > 0, "Must provide destinations"); - assert.equal(config.getSweepEachSubaddress(), undefined); - assert.equal(config.getBelowAmount(), undefined); - return config; - } - - static _normalizeSweepOutputConfig(config) { - if (config === undefined || !(config instanceof Object)) throw new MoneroError("Must provide MoneroTxConfig or equivalent JS object"); - config = new MoneroTxConfig(config); - assert.equal(config.getSweepEachSubaddress(), undefined); - assert.equal(config.getBelowAmount(), undefined); - assert.equal(config.getCanSplit(), undefined, "Cannot split transactions when sweeping an output"); - if (!config.getDestinations() || config.getDestinations().length !== 1 || !config.getDestinations()[0].getAddress()) throw new MoneroError("Must provide exactly one destination address to sweep output to"); - return config; - } - - static _normalizeSweepUnlockedConfig(config) { - if (config === undefined || !(config instanceof Object)) throw new MoneroError("Must provide MoneroTxConfig or equivalent JS object"); - config = new MoneroTxConfig(config); - if (config.getDestinations() === undefined || config.getDestinations().length != 1) throw new MoneroError("Must provide exactly one destination to sweep to"); - if (config.getDestinations()[0].getAddress() === undefined) throw new MoneroError("Must provide destination address to sweep to"); - if (config.getDestinations()[0].getAmount() !== undefined) throw new MoneroError("Cannot provide amount in sweep config"); - if (config.getKeyImage() !== undefined) throw new MoneroError("Key image defined; use sweepOutput() to sweep an output by its key image"); - if (config.getSubaddressIndices() !== undefined && config.getSubaddressIndices().length === 0) config.setSubaddressIndices(undefined); - if (config.getAccountIndex() === undefined && config.getSubaddressIndices() !== undefined) throw new MoneroError("Must provide account index if subaddress indices are provided"); - return config; - } -} - -MoneroWallet.DEFAULT_LANGUAGE = "English"; - -module.exports = MoneroWallet; \ No newline at end of file diff --git a/src/main/js/wallet/MoneroWalletKeys.js b/src/main/js/wallet/MoneroWalletKeys.js deleted file mode 100644 index 480cc60b4..000000000 --- a/src/main/js/wallet/MoneroWalletKeys.js +++ /dev/null @@ -1,331 +0,0 @@ -const assert = require("assert"); -const LibraryUtils = require("../common/LibraryUtils"); -const MoneroError = require("../common/MoneroError"); -const MoneroNetworkType = require("../daemon/model/MoneroNetworkType"); -const MoneroSubaddress = require("./model/MoneroSubaddress"); -const MoneroUtils = require("../common/MoneroUtils"); -const MoneroVersion = require("../daemon/model/MoneroVersion"); -const MoneroWallet = require("./MoneroWallet"); -const MoneroWalletConfig = require("./model/MoneroWalletConfig"); - -/** - * Implements a MoneroWallet which only manages keys using WebAssembly. - * - * @implements {MoneroWallet} - * @hideconstructor - */ -class MoneroWalletKeys extends MoneroWallet { - - // --------------------------- STATIC UTILITIES ----------------------------- - - /** - *

Create a wallet using WebAssembly bindings to monero-core.

- * - *

Example:

- * - * - * let wallet = await MoneroWalletKeys.createWallet({
- *    password: "abc123",
- *    networkType: MoneroNetworkType.STAGENET,
- *    mnemonic: "coexist igloo pamphlet lagoon..."
- * }); - *
- * - * @param {MoneroWalletConfig|object} config - MoneroWalletConfig or equivalent config object - * @param {string|number} config.networkType - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) - * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given) - * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase - * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys) - * @param {string} config.privateViewKey - private view key of the wallet to create (optional) - * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional) - * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected) - * @return {MoneroWalletKeys} the created wallet - */ - static async createWallet(config) { - - // normalize and validate config - if (config === undefined) throw new MoneroError("Must provide config to create wallet"); - config = config instanceof MoneroWalletConfig ? config : new MoneroWalletConfig(config); - if (config.getMnemonic() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) { - throw new MoneroError("Wallet may be initialized with a mnemonic or keys but not both"); - } - if (config.getNetworkType() === undefined) throw new MoneroError("Must provide a networkType: 'mainnet', 'testnet' or 'stagenet'"); - if (config.getSaveCurrent() === true) throw new MoneroError("Cannot save current wallet when creating keys-only wallet"); - - // create wallet - if (config.getMnemonic() !== undefined) { - if (config.getLanguage() !== undefined) throw new MoneroError("Cannot provide language when creating wallet from mnemonic"); - return MoneroWalletKeys._createWalletFromMnemonic(config.getNetworkType(), config.getMnemonic(), config.getSeedOffset()); - } else if (config.getPrimaryAddress() !== undefined) { - if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating wallet from keys"); - return MoneroWalletKeys._createWalletFromKeys(config.getNetworkType(), config.getPrimaryAddress(), config.getPrivateViewKey(), config.getPrivateSpendKey(), config.getLanguage()); - } else { - if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating random wallet"); - if (config.getRestoreHeight() !== undefined) throw new MoneroError("Cannot provide restoreHeight when creating random wallet"); - return MoneroWalletKeys._createWalletRandom(config.getNetworkType(), config.getLanguage()); - } - } - - static async _createWalletRandom(networkType, language) { - - // validate and sanitize params - MoneroNetworkType.validate(networkType); - if (language === undefined) language = "English"; - - // load wasm module - let module = await LibraryUtils.loadKeysModule(); - - // queue call to wasm module - return module.queueTask(async function() { - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = async function(cppAddress) { - if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); - else resolve(new MoneroWalletKeys(cppAddress)); - }; - - // create wallet in wasm and invoke callback when done - module.create_keys_wallet_random(networkType, language, callbackFn); - }); - }); - } - - static async _createWalletFromMnemonic(networkType, mnemonic, seedOffset) { - - // validate and sanitize params - MoneroNetworkType.validate(networkType); - if (mnemonic === undefined) throw Error("Must define mnemonic phrase to create wallet from"); - if (seedOffset === undefined) seedOffset = ""; - - // load wasm module - let module = await LibraryUtils.loadKeysModule(); - - // queue call to wasm module - return module.queueTask(async function() { - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = async function(cppAddress) { - if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); - else resolve(new MoneroWalletKeys(cppAddress)); - }; - - // create wallet in wasm and invoke callback when done - module.create_keys_wallet_from_mnemonic(networkType, mnemonic, seedOffset, callbackFn); - }); - }); - } - - static async _createWalletFromKeys(networkType, address, privateViewKey, privateSpendKey, language) { - - // validate and sanitize params - MoneroNetworkType.validate(networkType); - if (address === undefined) address = ""; - if (privateViewKey === undefined) privateViewKey = ""; - if (privateSpendKey === undefined) privateSpendKey = ""; - if (language === undefined) language = "English"; - - // load wasm module - let module = await LibraryUtils.loadKeysModule(); - - // queue call to wasm module - return module.queueTask(async function() { - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = async function(cppAddress) { - if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); - else resolve(new MoneroWalletKeys(cppAddress)); - }; - - // create wallet in wasm and invoke callback when done - module.create_keys_wallet_from_keys(networkType, address, privateViewKey, privateSpendKey, language, callbackFn); - }); - }); - } - - static async getMnemonicLanguages() { - let module = await LibraryUtils.loadKeysModule(); - return module.queueTask(async function() { - return JSON.parse(module.get_keys_wallet_mnemonic_languages()).languages; - }); - } - - // --------------------------- INSTANCE METHODS ----------------------------- - - /** - * Internal constructor which is given the memory address of a C++ wallet - * instance. - * - * This method should not be called externally but should be called through - * static wallet creation utilities in this class. - * - * @param {int} cppAddress - address of the wallet instance in C++ - */ - constructor(cppAddress) { - super(); - this._cppAddress = cppAddress; - this._module = LibraryUtils.getWasmModule(); - if (!this._module.create_core_wallet_from_mnemonic) throw new Error("WASM module not loaded - create wallet instance using static utilities"); // static utilites pre-load wasm module - } - - async isViewOnly() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.is_view_only(that._cppAddress); - }); - } - - async isConnected() { - return false; - } - - async getVersion() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - let versionStr = that._module.get_version(that._cppAddress); - let versionJson = JSON.parse(versionStr); - return new MoneroVersion(versionJson.number, versionJson.isRelease); - }); - } - - /** - * @ignore - */ - getPath() { - this._assertNotClosed(); - throw new Error("MoneroWalletKeys does not support a persisted path"); - } - - async getMnemonic() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - let mnemonic = that._module.get_mnemonic(that._cppAddress); - return mnemonic ? mnemonic : undefined; - }); - } - - async getMnemonicLanguage() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - let mnemonicLanguage = that._module.get_mnemonic_language(that._cppAddress); - return mnemonicLanguage ? mnemonicLanguage : undefined; - }); - } - - async getPrivateSpendKey() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - let privateSpendKey = that._module.get_private_spend_key(that._cppAddress); - return privateSpendKey ? privateSpendKey : undefined; - }); - } - - async getPrivateViewKey() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.get_private_view_key(that._cppAddress); - }); - } - - async getPublicViewKey() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.get_public_view_key(that._cppAddress); - }); - } - - async getPublicSpendKey() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.get_public_spend_key(that._cppAddress); - }); - } - - async getAddress(accountIdx, subaddressIdx) { - this._assertNotClosed(); - assert(typeof accountIdx === "number"); - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.get_address(that._cppAddress, accountIdx, subaddressIdx); - }); - } - - async getAddressIndex(address) { - this._assertNotClosed(); - if (!MoneroUtils.isValidAddress(address)) throw new MoneroError("Invalid address"); - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - try { - let subaddressJson = JSON.parse(that._module.get_address_index(that._cppAddress, address)); - return new MoneroSubaddress(subaddressJson); - } catch (e) { - throw new Error("Address doesn't belong to the wallet"); - } - }); - } - - getAccounts() { - this._assertNotClosed(); - throw new Error("MoneroWalletKeys does not support getting an enumerable set of accounts; query specific accounts"); - } - - // getIntegratedAddress(paymentId) // TODO - // decodeIntegratedAddress - - async close(save) { - if (this._isClosed) return; // closing a closed wallet has no effect - - // save wallet if requested - if (save) await this.save(); - - // queue task to use wasm module - let that = this; - return that._module.queueTask(async function() { - return new Promise(function(resolve, reject) { - if (that._isClosed) { - resolve(); - return; - } - - // define callback for wasm - let callbackFn = async function() { - delete that._cppAddress; - that._isClosed = true; - resolve(); - }; - - // close wallet in wasm and invoke callback when done - that._module.close(that._cppAddress, false, callbackFn); // saving handled external to webassembly - }); - }); - } - - async isClosed() { - return this._isClosed; - } - - // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS -------------- - - async getPrimaryAddress() { return super.getPrimaryAddress(...arguments); } - async getSubaddress() { return super.getSubaddress(...arguments); } - - // ----------------------------- PRIVATE HELPERS ---------------------------- - - _assertNotClosed() { - if (this._isClosed) throw new MoneroError("Wallet is closed"); - } -} - -module.exports = MoneroWalletKeys; \ No newline at end of file diff --git a/src/main/js/wallet/MoneroWalletRpc.js b/src/main/js/wallet/MoneroWalletRpc.js deleted file mode 100644 index 63a98c2b1..000000000 --- a/src/main/js/wallet/MoneroWalletRpc.js +++ /dev/null @@ -1,2137 +0,0 @@ -const assert = require("assert"); -const BigInteger = require("../common/biginteger").BigInteger; -const GenUtils = require("../common/GenUtils"); -const MoneroAccount = require("./model/MoneroAccount"); -const MoneroAccountTag = require("./model/MoneroAccountTag"); -const MoneroAddressBookEntry = require("./model/MoneroAddressBookEntry"); -const MoneroBlock = require("../daemon/model/MoneroBlock"); -const MoneroBlockHeader = require("../daemon/model/MoneroBlockHeader"); -const MoneroCheckReserve = require("./model/MoneroCheckReserve"); -const MoneroCheckTx = require("./model/MoneroCheckTx"); -const MoneroDaemonRpc = require("../daemon/MoneroDaemonRpc"); -const MoneroDestination = require("./model/MoneroDestination"); -const MoneroError = require("../common/MoneroError"); -const MoneroIncomingTransfer = require("./model/MoneroIncomingTransfer"); -const MoneroIntegratedAddress = require("./model/MoneroIntegratedAddress"); -const MoneroKeyImage = require("../daemon/model/MoneroKeyImage"); -const MoneroKeyImageImportResult = require("./model/MoneroKeyImageImportResult"); -const MoneroMultisigInfo = require("./model/MoneroMultisigInfo"); -const MoneroMultisigInitResult = require("./model/MoneroMultisigInitResult"); -const MoneroMultisigSignResult = require("./model/MoneroMultisigSignResult"); -const MoneroOutgoingTransfer = require("./model/MoneroOutgoingTransfer"); -const MoneroOutputQuery = require("./model/MoneroOutputQuery"); -const MoneroOutputWallet = require("./model/MoneroOutputWallet"); -const MoneroRpcConnection = require("../common/MoneroRpcConnection"); -const MoneroRpcError = require("../common/MoneroRpcError"); -const MoneroSubaddress = require("./model/MoneroSubaddress"); -const MoneroSyncResult = require("./model/MoneroSyncResult"); -const MoneroTransferQuery = require("./model/MoneroTransferQuery"); -const MoneroTxConfig = require("./model/MoneroTxConfig"); -const MoneroTxQuery = require("./model/MoneroTxQuery"); -const MoneroTxSet = require("./model/MoneroTxSet"); -const MoneroTxWallet = require("./model/MoneroTxWallet"); -const MoneroUtils = require("../common/MoneroUtils"); -const MoneroVersion = require("../daemon/model/MoneroVersion"); -const MoneroWallet = require("./MoneroWallet"); -const MoneroWalletConfig = require("./model/MoneroWalletConfig"); -const SslOptions = require("../common/SslOptions"); - -/** - * Copyright (c) woodser - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * Implements a MoneroWallet as a client of monero-wallet-rpc. - * - * @implements {MoneroWallet} - */ -class MoneroWalletRpc extends MoneroWallet { - - /** - *

Construct a wallet RPC client.

- * - *

Examples:

- * - * - * let walletRpc = new MoneroWalletRpc("http://localhost:38081", "superuser", "abctesting123");

- * - * let walletRpc = new MoneroWalletRpc({
- *    uri: "http://localhost:38081",
- *    username: "superuser",
- *    password: "abctesting123",
- *    rejectUnauthorized: false // e.g. local development
- * }); - *
- * - * @param {string|object|MoneroRpcConnection} uriOrConfigOrConnection - uri of monero-wallet-rpc or JS config object or MoneroRpcConnection - * @param {string} uriOrConfigOrConnection.uri - uri of monero-wallet-rpc - * @param {string} uriOrConfigOrConnection.username - username to authenticate with monero-wallet-rpc (optional) - * @param {string} uriOrConfigOrConnection.password - password to authenticate with monero-wallet-rpc (optional) - * @param {boolean} uriOrConfigOrConnection.rejectUnauthorized - rejects self-signed certificates if true (default true) - * @param {string} username - username to authenticate with monero-wallet-rpc (optional) - * @param {string} password - password to authenticate with monero-wallet-rpc (optional) - * @param {boolean} rejectUnauthorized - rejects self-signed certificates if true (default true) - */ - constructor(uriOrConfigOrConnection, username, password, rejectUnauthorized) { - super(); - this.config = MoneroDaemonRpc._normalizeConfig(uriOrConfigOrConnection, username, password, rejectUnauthorized); - this.rpc = new MoneroRpcConnection(this.config); - this.addressCache = {}; // avoid unecessary requests for addresses - } - - /** - * Get the wallet's RPC connection. - * - * @return {MoneroWalletRpc} the wallet's rpc connection - */ - async getRpcConnection() { - return this.rpc; - } - - /** - *

Open an existing wallet on the monero-wallet-rpc server.

- * - *

Example:

- * - * - * let wallet = new MoneroWalletRpc("http://localhost:38083", "rpc_user", "abc123");
- * await wallet.openWallet("mywallet1", "supersecretpassword");
- * await wallet.openWallet({
- *    path: "mywallet2",
- *    password: "supersecretpassword",
- *    serverUri: "http://locahost:38081",
- *    rejectUnauthorized: false
- * });
- *
- * - * @param {string|object|MoneroWalletConfig} pathOrConfig - the wallet's name or configuration to open - * @param {string} pathOrConfig.path - path of the wallet to create (optional, in-memory wallet if not given) - * @param {string} pathOrConfig.password - password of the wallet to create - * @param {string} pathOrConfig.serverUri - uri of a daemon to use (optional, monero-wallet-rpc usually started with daemon config) - * @param {string} pathOrConfig.serverUsername - username to authenticate with the daemon (optional) - * @param {string} pathOrConfig.serverPassword - password to authenticate with the daemon (optional) - * @param {boolean} pathOrConfig.rejectUnauthorized - reject self-signed server certificates if true (defaults to true) - * @param {MoneroRpcConnection|object} pathOrConfig.server - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional) - * @param {string} password is the wallet's password - */ - async openWallet(pathOrConfig, password) { - - // normalize and validate config - let config = new MoneroWalletConfig(typeof pathOrConfig === "string" ? {path: pathOrConfig, password: password} : pathOrConfig); - // TODO: ensure other fields are uninitialized? - - // open wallet on rpc server - if (!config.getPath()) throw new MoneroError("Must provide name of wallet to open"); - if (!config.getPassword()) throw new MoneroError("Must provide password of wallet to open"); - await this.rpc.sendJsonRequest("open_wallet", {filename: config.getPath(), password: config.getPassword()}); - this._clear(); - this.path = config.getPath(); - - // set daemon if provided - if (config.getServer()) return this.setDaemonConnection(config.getServer()); - } - - /** - *

Create and open a wallet on the monero-wallet-rpc server.

- * - *

Example:

- * - * - * // construct client to monero-wallet-rpc
- * let walletRpc = new MoneroWalletRpc("http://localhost:38083", "rpc_user", "abc123");

- * - * // create and open wallet on monero-wallet-rpc
- * await walletRpc.createWallet({
- *    path: "mywallet",
- *    password: "abc123",
- *    mnemonic: "coexist igloo pamphlet lagoon...",
- *    restoreHeight: 1543218l
- * }); - *
- * - * @param {object|MoneroWalletConfig} config - MoneroWalletConfig or equivalent JS object - * @param {string} config.path - path of the wallet to create (optional, in-memory wallet if not given) - * @param {string} config.password - password of the wallet to create - * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given) - * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase - * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys) - * @param {string} config.privateViewKey - private view key of the wallet to create (optional) - * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional) - * @param {number} config.restoreHeight - block height to start scanning from (defaults to 0 unless generating random wallet) - * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected) - * @param {string} config.serverUri - uri of a daemon to use (optional, monero-wallet-rpc usually started with daemon config) - * @param {string} config.serverUsername - username to authenticate with the daemon (optional) - * @param {string} config.serverPassword - password to authenticate with the daemon (optional) - * @param {boolean} config.rejectUnauthorized - reject self-signed server certificates if true (defaults to true) - * @param {MoneroRpcConnection|object} config.server - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional) - * @param {boolean} config.saveCurrent - specifies if the current RPC wallet should be saved before being closed (default true) - */ - async createWallet(config) { - - // normalize and validate config - if (config === undefined) throw new MoneroError("Must provide config to create wallet"); - config = config instanceof MoneroWalletConfig ? config : new MoneroWalletConfig(config); - if (config.getMnemonic() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) { - throw new MoneroError("Wallet may be initialized with a mnemonic or keys but not both"); - } - if (config.getNetworkType() !== undefined) throw new MoneroError("Cannot provide networkType when creating RPC wallet because server's network type is already set"); - - // create wallet - if (config.getMnemonic() !== undefined) { - await this._createWalletFromMnemonic(config.getPath(), config.getPassword(), config.getMnemonic(), config.getRestoreHeight(), config.getLanguage(), config.getSeedOffset(), config.getSaveCurrent()); - } else if (config.getPrimaryAddress() !== undefined) { - if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating wallet from keys"); - await this._createWalletFromKeys(config.getPath(), config.getPassword(), config.getPrimaryAddress(), config.getPrivateViewKey(), config.getPrivateSpendKey(), config.getRestoreHeight(), config.getLanguage(), config.getSaveCurrent()); - } else { - if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating random wallet"); - if (config.getRestoreHeight() !== undefined) throw new MoneroError("Cannot provide restoreHeight when creating random wallet"); - if (config.getSaveCurrent() === false) throw new MoneroError("Current wallet is saved automatically when creating random wallet"); - await this._createWalletRandom(config.getPath(), config.getPassword(), config.getLanguage()); - } - - // set daemon if provided - if (config.getServer()) return this.setDaemonConnection(config.getServer()); - } - - /** - * Create and open a new wallet with a randomly generated seed on the RPC server. - * - * @param {string} name - name of the wallet file to create - * @param {string} password - wallet's password - * @param {string} language - language for the wallet's mnemonic phrase - */ - async _createWalletRandom(name, password, language) { - if (!name) throw new MoneroError("Name is not initialized"); - if (!password) throw new MoneroError("Password is not initialized"); - if (!language) language = MoneroWallet.DEFAULT_LANGUAGE; - let params = { filename: name, password: password, language: language }; - try { - await this.rpc.sendJsonRequest("create_wallet", params); - } catch (e) { - if (e.message === "Cannot create wallet. Already exists.") throw new MoneroError("Wallet already exists: " + name); - throw e; - } - this._clear(); - this.path = name; - } - - /** - * Create and open a wallet from an existing mnemonic phrase on the RPC server, - * closing the currently open wallet if applicable. - * - * @param {string} name - name of the wallet to create on the RPC server - * @param {string} password - wallet's password - * @param {string} mnemonic - mnemonic of the wallet to construct - * @param {int} restoreHeight - block height to restore from (default = 0) - * @param {string} language - language of the mnemonic in case the old language is invalid - * @param {string} seedOffset - offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase - * @param {boolean} saveCurrent - specifies if the current RPC wallet should be saved before being closed - */ - async _createWalletFromMnemonic(name, password, mnemonic, restoreHeight, language, seedOffset, saveCurrent) { - try { - await this.rpc.sendJsonRequest("restore_deterministic_wallet", { - filename: name, - password: password, - seed: mnemonic, - seed_offset: seedOffset, - restore_height: restoreHeight, - language: language, - autosave_current: saveCurrent - }); - } catch (e) { - if (e.message === "Cannot create wallet. Already exists.") throw new MoneroError("Wallet already exists: " + name); - throw e; - } - this._clear(); - this.path = name; - } - - /** - * Create a wallet on the RPC server from an address, view key, and (optionally) spend key. - * - * @param name - name of the wallet to create on the RPC server - * @param password - password encrypt the wallet - * @param networkType - wallet's network type - * @param address - address of the wallet to construct - * @param viewKey - view key of the wallet to construct - * @param spendKey - spend key of the wallet to construct or null to create a view-only wallet - * @param restoreHeight - block height to restore (i.e. scan the chain) from (default = 0) - * @param language - wallet and mnemonic's language (default = "English") - */ - async _createWalletFromKeys(name, password, address, viewKey, spendKey, restoreHeight, language, saveCurrent) { - if (restoreHeight === undefined) restoreHeight = 0; - if (language === undefined) language = MoneroWallet.DEFAULT_LANGUAGE; - try { - await this.rpc.sendJsonRequest("generate_from_keys", { - filename: name, - password: password, - address: address, - viewkey: viewKey, - spendkey: spendKey, - restore_height: restoreHeight, - autosave_current: saveCurrent - }); - } catch (e) { - if (e.message === "Cannot create wallet. Already exists.") throw new MoneroError("Wallet already exists: " + name); - throw e; - } - this._clear(); - this.path = name; - } - - async isViewOnly() { - try { - await this.rpc.sendJsonRequest("query_key", {key_type: "mnemonic"}); - return false; // key retrieval succeeds if not view only - } catch (e) { - if (e.getCode() === -29) return true; // wallet is view only - if (e.getCode() === -1) return false; // wallet is offline but not view only - throw e; - } - } - - /** - * Set the wallet's daemon connection. - * - * @param {string|MoneroRpcConnection} uriOrConnection - the daemon's URI or connection (defaults to offline) - * @param {boolean} isTrusted - indicates if the daemon in trusted - * @param {SslOptions} sslOptions - custom SSL configuration - */ - async setDaemonConnection(daemonUriOrConnection, isTrusted, sslOptions) { - let daemonConnection = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection : new MoneroRpcConnection(daemonUriOrConnection); - if (daemonConnection.getUsername()) throw new MoneroError("monero-wallet-rpc does not support setting daemon connection with authentication"); - if (!sslOptions) sslOptions = new SslOptions(); - let params = {}; - params.address = !daemonConnection ? "bad_uri" : daemonConnection.getUri(); // TODO monero-wallet-rpc: bad daemon uri necessary for offline? - params.trusted = isTrusted; - params.ssl_support = "autodetect"; - params.ssl_private_key_path = sslOptions.getPrivateKeyPath(); - params.ssl_certificate_path = sslOptions.getCertificatePath(); - params.ssl_ca_file = sslOptions.getCertificateAuthorityFile(); - params.ssl_allowed_fingerprints = sslOptions.getAllowedFingerprints(); - params.ssl_allow_any_cert = sslOptions.getAllowAnyCert(); - await this.rpc.sendJsonRequest("set_daemon", params); - } - - async getDaemonConnection() { - throw new MoneroError("Not implemented"); - } - - async isConnected() { - try { - await this.sync(); // wallet rpc auto syncs so worst case this call blocks and blocks upfront TODO: better way to determine if wallet rpc is connected to daemon? - return true; - } catch (e) { - return false; - } - } - - async getVersion() { - let resp = await this.rpc.sendJsonRequest("get_version"); - return new MoneroVersion(resp.result.version, resp.result.release); - } - - async getPath() { - return this.path; - } - - async getMnemonic() { - try { - let resp = await this.rpc.sendJsonRequest("query_key", { key_type: "mnemonic" }); - return resp.result.key; - } catch (e) { - if (e.getCode() === -29) return undefined; // wallet is view-only - throw e; - } - } - - async getMnemonicLanguage() { - if (await this.getMnemonic() === undefined) return undefined; - throw new MoneroError("MoneroWalletRpc.getMnemonicLanguage() not supported"); - } - - /** - * Get a list of available languages for the wallet's mnemonic phrase. - * - * @return {string[]} the available languages for the wallet's mnemonic phrase - */ - async getMnemonicLanguages() { - return (await this.rpc.sendJsonRequest("get_languages")).result.languages; - } - - async getPrivateViewKey() { - let resp = await this.rpc.sendJsonRequest("query_key", { key_type: "view_key" }); - return resp.result.key; - } - - async getPrivateSpendKey() { - - // get private spend key which will throw error if wallet is view-only - try { - let resp = await this.rpc.sendJsonRequest("query_key", { key_type: "spend_key" }); - return resp.result.key; - } catch (e) { - if (e.getCode() === -29 && e.message.indexOf("watch-only") !== -1) return undefined; // return undefined if wallet is view-only - throw e; - } - } - - async getAddress(accountIdx, subaddressIdx) { - let subaddressMap = this.addressCache[accountIdx]; - if (!subaddressMap) { - await this.getSubaddresses(accountIdx, undefined, true); // cache's all addresses at this account - return this.getAddress(accountIdx, subaddressIdx); // recursive call uses cache - } - let address = subaddressMap[subaddressIdx]; - if (!address) { - await this.getSubaddresses(accountIdx, undefined, true); // cache's all addresses at this account - return this.addressCache[accountIdx][subaddressIdx]; - } - return address; - } - - // TODO: use cache - async getAddressIndex(address) { - - // fetch result and normalize error if address does not belong to the wallet - let resp; - try { - resp = await this.rpc.sendJsonRequest("get_address_index", {address: address}); - } catch (e) { - if (e.getCode() === -2) throw new MoneroError(e.message); - throw e; - } - - // convert rpc response - let subaddress = new MoneroSubaddress(address); - subaddress.setAccountIndex(resp.result.index.major); - subaddress.setIndex(resp.result.index.minor); - return subaddress; - } - - async getIntegratedAddress(paymentId) { - try { - let integratedAddressStr = (await this.rpc.sendJsonRequest("make_integrated_address", {payment_id: paymentId})).result.integrated_address; - return await this.decodeIntegratedAddress(integratedAddressStr); - } catch (e) { - if (e.message.includes("Invalid payment ID")) throw new MoneroError("Invalid payment ID: " + paymentId); - throw e; - } - } - - async decodeIntegratedAddress(integratedAddress) { - let resp = await this.rpc.sendJsonRequest("split_integrated_address", {integrated_address: integratedAddress}); - return new MoneroIntegratedAddress().setStandardAddress(resp.result.standard_address).setPaymentId(resp.result.payment_id).setIntegratedAddress(integratedAddress); - } - - async getHeight() { - return (await this.rpc.sendJsonRequest("get_height")).result.height; - } - - async getDaemonHeight() { - throw new MoneroError("monero-wallet-rpc does not support getting the chain height"); - } - - async getHeightByDate(year, month, day) { - throw new MoneroError("monero-wallet-rpc does not support getting a height by date"); - } - - async sync(startHeight, onProgress) { - assert(onProgress === undefined, "Monero Wallet RPC does not support reporting sync progress"); - let resp = await this.rpc.sendJsonRequest("refresh", {start_height: startHeight}); - return new MoneroSyncResult(resp.result.blocks_fetched, resp.result.received_money); - } - - async startSyncing() { - // nothing to do because wallet rpc syncs automatically - } - - async rescanSpent() { - await this.rpc.sendJsonRequest("rescan_spent"); - } - - async rescanBlockchain() { - await this.rpc.sendJsonRequest("rescan_blockchain"); - } - - async getBalance(accountIdx, subaddressIdx) { - return (await this._getBalances(accountIdx, subaddressIdx))[0]; - } - - async getUnlockedBalance(accountIdx, subaddressIdx) { - return (await this._getBalances(accountIdx, subaddressIdx))[1]; - } - - async getAccounts(includeSubaddresses, tag, skipBalances) { - - // fetch accounts from rpc - let resp = await this.rpc.sendJsonRequest("get_accounts", {tag: tag}); - - // build account objects and fetch subaddresses per account using get_address - // TODO monero-wallet-rpc: get_address should support all_accounts so not called once per account - let accounts = []; - for (let rpcAccount of resp.result.subaddress_accounts) { - let account = MoneroWalletRpc._convertRpcAccount(rpcAccount); - if (includeSubaddresses) account.setSubaddresses(await this.getSubaddresses(account.getIndex(), undefined, true)); - accounts.push(account); - } - - // fetch and merge fields from get_balance across all accounts - if (includeSubaddresses && !skipBalances) { - - // these fields are not initialized if subaddress is unused and therefore not returned from `get_balance` - for (let account of accounts) { - for (let subaddress of account.getSubaddresses()) { - subaddress.setBalance(new BigInteger(0)); - subaddress.setUnlockedBalance(new BigInteger(0)); - subaddress.setNumUnspentOutputs(0); - subaddress.setNumBlocksToUnlock(0); - } - } - - // fetch and merge info from get_balance - resp = await this.rpc.sendJsonRequest("get_balance", {all_accounts: true}); - if (resp.result.per_subaddress) { - for (let rpcSubaddress of resp.result.per_subaddress) { - let subaddress = MoneroWalletRpc._convertRpcSubaddress(rpcSubaddress); - - // merge info - let account = accounts[subaddress.getAccountIndex()]; - assert.equal(subaddress.getAccountIndex(), account.getIndex(), "RPC accounts are out of order"); // would need to switch lookup to loop - let tgtSubaddress = account.getSubaddresses()[subaddress.getIndex()]; - assert.equal(subaddress.getIndex(), tgtSubaddress.getIndex(), "RPC subaddresses are out of order"); - if (subaddress.getBalance() !== undefined) tgtSubaddress.setBalance(subaddress.getBalance()); - if (subaddress.getUnlockedBalance() !== undefined) tgtSubaddress.setUnlockedBalance(subaddress.getUnlockedBalance()); - if (subaddress.getNumUnspentOutputs() !== undefined) tgtSubaddress.setNumUnspentOutputs(subaddress.getNumUnspentOutputs()); - } - } - } - - // return accounts - return accounts; - } - - // TODO: getAccountByIndex(), getAccountByTag() - async getAccount(accountIdx, includeSubaddresses, skipBalances) { - assert(accountIdx >= 0); - for (let account of await this.getAccounts()) { - if (account.getIndex() === accountIdx) { - if (includeSubaddresses) account.setSubaddresses(await this.getSubaddresses(accountIdx, undefined, skipBalances)); - return account; - } - } - throw new Exception("Account with index " + accountIdx + " does not exist"); - } - - async createAccount(label) { - label = label ? label : undefined; - let resp = await this.rpc.sendJsonRequest("create_account", {label: label}); - return new MoneroAccount(resp.result.account_index, resp.result.address, new BigInteger(0), new BigInteger(0)); - } - - async getSubaddresses(accountIdx, subaddressIndices, skipBalances) { - - // fetch subaddresses - let params = {}; - params.account_index = accountIdx; - if (subaddressIndices) params.address_index = GenUtils.listify(subaddressIndices); - let resp = await this.rpc.sendJsonRequest("get_address", params); - - // initialize subaddresses - let subaddresses = []; - for (let rpcSubaddress of resp.result.addresses) { - let subaddress = MoneroWalletRpc._convertRpcSubaddress(rpcSubaddress); - subaddress.setAccountIndex(accountIdx); - subaddresses.push(subaddress); - } - - // fetch and initialize subaddress balances - if (!skipBalances) { - - // these fields are not initialized if subaddress is unused and therefore not returned from `get_balance` - for (let subaddress of subaddresses) { - subaddress.setBalance(new BigInteger(0)); - subaddress.setUnlockedBalance(new BigInteger(0)); - subaddress.setNumUnspentOutputs(0); - subaddress.setNumBlocksToUnlock(0); - } - - // fetch and initialize balances - resp = await this.rpc.sendJsonRequest("get_balance", params); - if (resp.result.per_subaddress) { - for (let rpcSubaddress of resp.result.per_subaddress) { - let subaddress = MoneroWalletRpc._convertRpcSubaddress(rpcSubaddress); - - // transfer info to existing subaddress object - for (let tgtSubaddress of subaddresses) { - if (tgtSubaddress.getIndex() !== subaddress.getIndex()) continue; // skip to subaddress with same index - if (subaddress.getBalance() !== undefined) tgtSubaddress.setBalance(subaddress.getBalance()); - if (subaddress.getUnlockedBalance() !== undefined) tgtSubaddress.setUnlockedBalance(subaddress.getUnlockedBalance()); - if (subaddress.getNumUnspentOutputs() !== undefined) tgtSubaddress.setNumUnspentOutputs(subaddress.getNumUnspentOutputs()); - if (subaddress.getNumBlocksToUnlock() !== undefined) tgtSubaddress.setNumBlocksToUnlock(subaddress.getNumBlocksToUnlock()); - } - } - } - } - - // cache addresses - let subaddressMap = this.addressCache[accountIdx]; - if (!subaddressMap) { - subaddressMap = {}; - this.addressCache[accountIdx] = subaddressMap; - } - for (let subaddress of subaddresses) { - subaddressMap[subaddress.getIndex()] = subaddress.getAddress(); - } - - // return results - return subaddresses; - } - - async getSubaddress(accountIdx, subaddressIdx, skipBalances) { - assert(accountIdx >= 0); - assert(subaddressIdx >= 0); - return (await this.getSubaddresses(accountIdx, subaddressIdx, skipBalances))[0]; - } - - async createSubaddress(accountIdx, label) { - - // send request - let resp = await this.rpc.sendJsonRequest("create_address", {account_index: accountIdx, label: label}); - - // build subaddress object - let subaddress = new MoneroSubaddress(); - subaddress.setAccountIndex(accountIdx); - subaddress.setIndex(resp.result.address_index); - subaddress.setAddress(resp.result.address); - subaddress.setLabel(label ? label : undefined); - subaddress.setBalance(new BigInteger(0)); - subaddress.setUnlockedBalance(new BigInteger(0)); - subaddress.setNumUnspentOutputs(0); - subaddress.setIsUsed(false); - subaddress.setNumBlocksToUnlock(0); - return subaddress; - } - - async getTxs(query, missingTxHashes) { - - // copy query - query = MoneroWallet._normalizeTxQuery(query); - - // temporarily disable transfer and output queries in order to collect all tx information - let transferQuery = query.getTransferQuery(); - let outputQuery = query.getOutputQuery(); - query.setTransferQuery(undefined); - query.setOutputQuery(undefined); - - // fetch all transfers that meet tx query - let transfers = await this._getTransfersAux(new MoneroTransferQuery().setTxQuery(MoneroWalletRpc._decontextualize(query.copy()))); - - // collect unique txs from transfers while retaining order - let txs = []; - let txsSet = new Set(); - for (let transfer of transfers) { - if (!txsSet.has(transfer.getTx())) { - txs.push(transfer.getTx()); - txsSet.add(transfer.getTx()); - } - } - - // cache types into maps for merging and lookup - let txMap = new Map(); - let blockMap = new Map(); - for (let tx of txs) { - MoneroWalletRpc._mergeTx(tx, txMap, blockMap, false); - } - - // fetch and merge outputs if requested - if (query.getIncludeOutputs() || outputQuery) { - let outputs = await this._getOutputsAux(new MoneroOutputQuery().setTxQuery(MoneroWalletRpc._decontextualize(query.copy()))); - - // merge output txs one time while retaining order - let outputTxs = []; - for (let output of outputs) { - if (!outputTxs.includes(output.getTx())) { - MoneroWalletRpc._mergeTx(output.getTx(), txMap, blockMap, true); - outputTxs.push(output.getTx()); - } - } - } - - // restore transfer and output queries - query.setTransferQuery(transferQuery); - query.setOutputQuery(outputQuery); - - // filter txs that don't meet transfer query - let txsQueried = []; - for (let tx of txs) { - if (query.meetsCriteria(tx)) txsQueried.push(tx); - else if (tx.getBlock() !== undefined) tx.getBlock().getTxs().splice(tx.getBlock().getTxs().indexOf(tx), 1); - } - txs = txsQueried; - - // collect unfound tx hashes - if (query.getHashes()) { - let unfoundTxHashes = []; - for (let txHash of query.getHashes()) { - let found = false; - for (let tx of txs) { - if (txHash === tx.getHash()) { - found = true; - break; - } - } - if (!found) unfoundTxHashes.push(txHash); - } - - // if txs not found, collect missing hashes or throw error if no collection given - if (missingTxHashes) for (let unfoundTxHash of unfoundTxHashes) missingTxHashes.push(unfoundTxHash); - else if (unfoundTxHashes.length > 0) throw new MoneroError("Wallet missing requested tx hashes: " + unfoundTxHashes); - } - - // special case: re-fetch txs if inconsistency caused by needing to make multiple rpc calls - for (let tx of txs) { - if (tx.isConfirmed() && tx.getBlock() === undefined) return this.getTxs(query); - } - - // order txs if tx hashes given then return - if (query.getHashes() && query.getHashes().length > 0) { - let txsById = new Map() // store txs in temporary map for sorting - for (let tx of txs) txsById.set(tx.getHash(), tx); - let orderedTxs = []; - for (let hash of query.getHashes()) if (txsById.get(hash)) orderedTxs.push(txsById.get(hash)); - txs = orderedTxs; - } - return txs; - } - - async getTransfers(query) { - - // copy and normalize query up to block - query = MoneroWallet._normalizeTransferQuery(query); - - // get transfers directly if query does not require tx context (other transfers, outputs) - if (!MoneroWalletRpc._isContextual(query)) return this._getTransfersAux(query); - - // otherwise get txs with full models to fulfill query - let transfers = []; - for (let tx of await this.getTxs(query.getTxQuery())) { - for (let transfer of tx.filterTransfers(query)) { - transfers.push(transfer); - } - } - - return transfers; - } - - async getOutputs(query) { - - // copy and normalize query up to block - query = MoneroWallet._normalizeOutputQuery(query); - - // get outputs directly if query does not require tx context (other outputs, transfers) - if (!MoneroWalletRpc._isContextual(query)) return this._getOutputsAux(query); - - // otherwise get txs with full models to fulfill query - let outputs = []; - for (let tx of await this.getTxs(query.getTxQuery())) { - for (let output of tx.filterOutputs(query)) { - outputs.push(output); - } - } - - return outputs; - } - - async getOutputsHex() { - return (await this.rpc.sendJsonRequest("export_outputs")).result.outputs_data_hex; - } - - async importOutputsHex(outputsHex) { - let resp = await this.rpc.sendJsonRequest("import_outputs", {outputs_data_hex: outputsHex}); - return resp.result.num_imported; - } - - async getKeyImages() { - return await this._rpcExportKeyImages(true); - } - - async importKeyImages(keyImages) { - - // convert key images to rpc parameter - let rpcKeyImages = keyImages.map(keyImage => ({key_image: keyImage.getHex(), signature: keyImage.getSignature()})); - - // send request - let resp = await this.rpc.sendJsonRequest("import_key_images", {signed_key_images: rpcKeyImages}); - - // build and return result - let importResult = new MoneroKeyImageImportResult(); - importResult.setHeight(resp.result.height); - importResult.setSpentAmount(new BigInteger(resp.result.spent)); - importResult.setUnspentAmount(new BigInteger(resp.result.unspent)); - return importResult; - } - - async getNewKeyImagesFromLastImport() { - return await this._rpcExportKeyImages(false); - } - - async relayTxs(txsOrMetadatas) { - assert(Array.isArray(txsOrMetadatas), "Must provide an array of txs or their metadata to relay"); - let txHashes = []; - for (let txOrMetadata of txsOrMetadatas) { - let metadata = txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata; - let resp = await this.rpc.sendJsonRequest("relay_tx", { hex: metadata }); - txHashes.push(resp.result.tx_hash); - } - return txHashes; - } - - async createTxs(config) { - - // validate, copy, and normalize config - config = MoneroWallet._normalizeCreateTxsConfig(config); - if (config.getCanSplit() === undefined) config.setCanSplit(true); - if (config.getRelay() === true && await this.isMultisig()) throw new MoneroError("Cannot relay multisig transaction until co-signed"); - - // determine account and subaddresses to send from - let accountIdx = config.getAccountIndex(); - if (accountIdx === undefined) throw new MoneroError("Must provide the account index to send from"); - let subaddressIndices = config.getSubaddressIndices() === undefined ? undefined : config.getSubaddressIndices().slice(0); // fetch all or copy given indices - - // build config parameters - let params = {}; - params.destinations = []; - for (let destination of config.getDestinations()) { - assert(destination.getAddress(), "Destination address is not defined"); - assert(destination.getAmount(), "Destination amount is not defined"); - params.destinations.push({ address: destination.getAddress(), amount: destination.getAmount().toString() }); - } - params.account_index = accountIdx; - params.subaddr_indices = subaddressIndices; - params.payment_id = config.getPaymentId(); - params.unlock_time = config.getUnlockHeight(); - params.do_not_relay = config.getRelay() !== true; - assert(config.getPriority() === undefined || config.getPriority() >= 0 && config.getPriority() <= 3); - params.priority = config.getPriority(); - params.get_tx_hex = true; - params.get_tx_metadata = true; - if (config.getCanSplit()) params.get_tx_keys = true; // param to get tx key(s) depends if split - else params.get_tx_key = true; - - // send request - let resp = await this.rpc.sendJsonRequest(config.getCanSplit() ? "transfer_split" : "transfer", params); - let result = resp.result; - - // pre-initialize txs iff present. multisig and view-only wallets will have tx set without transactions - let txs; - let numTxs = config.getCanSplit() ? (result.fee_list !== undefined ? result.fee_list.length : 0) : (result.fee !== undefined ? 1 : 0); - if (numTxs > 0) txs = []; - for (let i = 0; i < numTxs; i++) { - let tx = new MoneroTxWallet(); - MoneroWalletRpc._initSentTxWallet(config, tx); - tx.getOutgoingTransfer().setAccountIndex(accountIdx); - if (subaddressIndices !== undefined && subaddressIndices.length === 1) tx.getOutgoingTransfer().setSubaddressIndices(subaddressIndices); - txs.push(tx); - } - - // initialize tx set from rpc response with pre-initialized txs - if (config.getCanSplit()) return MoneroWalletRpc._convertRpcSentTxsToTxSet(result, txs).getTxs(); - else return MoneroWalletRpc._convertRpcTxToTxSet(result, txs === undefined ? undefined : txs[0], true).getTxs(); - } - - async sweepOutput(config) { - - // normalize and validate config - config = MoneroWallet._normalizeSweepOutputConfig(config); - - // build config parameters - let params = {}; - params.address = config.getDestinations()[0].getAddress(); - params.account_index = config.getAccountIndex(); - params.subaddr_indices = config.getSubaddressIndices(); - params.key_image = config.getKeyImage(); - params.unlock_time = config.getUnlockHeight(); - params.do_not_relay = config.getRelay() !== true; - assert(config.getPriority() === undefined || config.getPriority() >= 0 && config.getPriority() <= 3); - params.priority = config.getPriority(); - params.payment_id = config.getPaymentId(); - params.get_tx_key = true; - params.get_tx_hex = true; - params.get_tx_metadata = true; - - // send request - let resp = await this.rpc.sendJsonRequest("sweep_single", params); - let result = resp.result; - - // build and return tx response - let tx = MoneroWalletRpc._initSentTxWallet(config, null); - let txSet = MoneroWalletRpc._convertRpcTxToTxSet(result, tx, true); - tx.getOutgoingTransfer().getDestinations()[0].setAmount(tx.getOutgoingTransfer().getAmount()); // initialize destination amount - return tx; - } - - async sweepUnlocked(config) { - - // validate and normalize config - config = MoneroWallet._normalizeSweepUnlockedConfig(config); - - // determine account and subaddress indices to sweep; default to all with unlocked balance if not specified - let indices = new Map(); // maps each account index to subaddress indices to sweep - if (config.getAccountIndex() !== undefined) { - if (config.getSubaddressIndices() !== undefined) { - indices.set(config.getAccountIndex(), config.getSubaddressIndices()); - } else { - let subaddressIndices = []; - indices.set(config.getAccountIndex(), subaddressIndices); - for (let subaddress of await this.getSubaddresses(config.getAccountIndex())) { - if (subaddress.getUnlockedBalance().compare(new BigInteger(0)) > 0) subaddressIndices.push(subaddress.getIndex()); - } - } - } else { - let accounts = await this.getAccounts(true); - for (let account of accounts) { - if (account.getUnlockedBalance().compare(new BigInteger(0)) > 0) { - let subaddressIndices = []; - indices.set(account.getIndex(), subaddressIndices); - for (let subaddress of account.getSubaddresses()) { - if (subaddress.getUnlockedBalance().compare(new BigInteger(0)) > 0) subaddressIndices.push(subaddress.getIndex()); - } - } - } - } - - // sweep from each account and collect resulting tx sets - let txs = []; - for (let accountIdx of indices.keys()) { - - // copy and modify the original config - let copy = config.copy(); - copy.setAccountIndex(accountIdx); - copy.setSweepEachSubaddress(false); - - // sweep all subaddresses together // TODO monero core: can this reveal outputs belong to the same wallet? - if (copy.getSweepEachSubaddress() !== true) { - copy.setSubaddressIndices(indices.get(accountIdx)); - for (let tx of await this._rpcSweepAccount(copy)) txs.push(tx); - } - - // otherwise sweep each subaddress individually - else { - for (let subaddressIdx of indices.get(accountIdx)) { - copy.setSubaddressIndices([subaddressIdx]); - for (let tx of await this._rpcSweepAccount(copy)) txs.push(tx); - } - } - } - - return txs; - } - - async sweepDust(relay) { - if (relay === undefined) relay = false; - let resp = await this.rpc.sendJsonRequest("sweep_dust", {do_not_relay: !relay}); - let result = resp.result; - let txSet = MoneroWalletRpc._convertRpcSentTxsToTxSet(result); - if (txSet.getTxs() !== undefined) { - for (let tx of txSet.getTxs()) { - tx.setIsRelayed(!relay); - tx.setInTxPool(tx.isRelayed()); - } - } else if (txSet.getMultisigTxHex() === undefined && txSet.getSignedTxHex() === undefined && txSet.getUnsignedTxHex() === undefined) { - throw new MoneroError("No dust to sweep"); - } - return txSet.getTxs(); - } - - async parseTxSet(txSet) { - let resp = await this.rpc.sendJsonRequest("describe_transfer", { - unsigned_txset: txSet.getUnsignedTxHex(), - multisig_txset: txSet.getMultisigTxHex() - }); - return MoneroWalletRpc._convertRpcDescribeTransfer(resp.result); - } - - async signTxs(unsignedTxHex) { - let resp = await this.rpc.sendJsonRequest("sign_transfer", { - unsigned_txset: unsignedTxHex, - export_raw: false - }); - return resp.result.signed_txset - } - - async submitTxs(signedTxHex) { - let resp = await this.rpc.sendJsonRequest("submit_transfer", { - tx_data_hex: signedTxHex - }); - return resp.result.tx_hash_list; - } - - async signMessage(message) { - let resp = await this.rpc.sendJsonRequest("sign", {data: message}); - return resp.result.signature; - } - - async verifyMessage(message, address, signature) { - let resp = await this.rpc.sendJsonRequest("verify", {data: message, address: address, signature: signature}); - return resp.result.good; - } - - async getTxKey(txHash) { - try { - return (await this.rpc.sendJsonRequest("get_tx_key", {txid: txHash})).result.tx_key; - } catch (e) { - if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message - throw e; - } - } - - async checkTxKey(txHash, txKey, address) { - try { - - // send request - let resp = await this.rpc.sendJsonRequest("check_tx_key", {txid: txHash, tx_key: txKey, address: address}); - - // interpret result - let check = new MoneroCheckTx(); - check.setIsGood(true); - check.setNumConfirmations(resp.result.confirmations); - check.setInTxPool(resp.result.in_pool); - check.setReceivedAmount(new BigInteger(resp.result.received)); - return check; - } catch (e) { - if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message - throw e; - } - } - - async getTxProof(txHash, address, message) { - try { - let resp = await this.rpc.sendJsonRequest("get_tx_proof", {txid: txHash, address: address, message: message}); - return resp.result.signature; - } catch (e) { - if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message - throw e; - } - } - - async checkTxProof(txHash, address, message, signature) { - try { - - // send request - let resp = await this.rpc.sendJsonRequest("check_tx_proof", { - txid: txHash, - address: address, - message: message, - signature: signature - }); - - // interpret response - let isGood = resp.result.good; - let check = new MoneroCheckTx(); - check.setIsGood(isGood); - if (isGood) { - check.setNumConfirmations(resp.result.confirmations); - check.setInTxPool(resp.result.in_pool); - check.setReceivedAmount(new BigInteger(resp.result.received)); - } - return check; - } catch (e) { - if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message - throw e; - } - } - - async getSpendProof(txHash, message) { - try { - let resp = await this.rpc.sendJsonRequest("get_spend_proof", {txid: txHash, message: message}); - return resp.result.signature; - } catch (e) { - if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message - throw e; - } - } - - async checkSpendProof(txHash, message, signature) { - try { - let resp = await this.rpc.sendJsonRequest("check_spend_proof", { - txid: txHash, - message: message, - signature: signature - }); - return resp.result.good; - } catch (e) { - if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message - throw e; - } - } - - async getReserveProofWallet(message) { - let resp = await this.rpc.sendJsonRequest("get_reserve_proof", { - all: true, - message: message - }); - return resp.result.signature; - } - - async getReserveProofAccount(accountIdx, amount, message) { - let resp = await this.rpc.sendJsonRequest("get_reserve_proof", { - account_index: accountIdx, - amount: amount.toString(), - message: message - }); - return resp.result.signature; - } - - async checkReserveProof(address, message, signature) { - - // send request - let resp = await this.rpc.sendJsonRequest("check_reserve_proof", { - address: address, - message: message, - signature: signature - }); - - // interpret results - let isGood = resp.result.good; - let check = new MoneroCheckReserve(); - check.setIsGood(isGood); - if (isGood) { - check.setUnconfirmedSpentAmount(new BigInteger(resp.result.spent)); - check.setTotalAmount(new BigInteger(resp.result.total)); - } - return check; - } - - async getTxNotes(txHashes) { - return (await this.rpc.sendJsonRequest("get_tx_notes", {txids: txHashes})).result.notes; - } - - async setTxNotes(txHashes, notes) { - await this.rpc.sendJsonRequest("set_tx_notes", {txids: txHashes, notes: notes}); - } - - async getAddressBookEntries(entryIndices) { - let resp = await this.rpc.sendJsonRequest("get_address_book", {entries: entryIndices}); - if (!resp.result.entries) return []; - let entries = []; - for (let rpcEntry of resp.result.entries) { - entries.push(new MoneroAddressBookEntry().setIndex(rpcEntry.index).setAddress(rpcEntry.address).setDescription(rpcEntry.description).setPaymentId(rpcEntry.payment_id)); - } - return entries; - } - - async addAddressBookEntry(address, description) { - let resp = await this.rpc.sendJsonRequest("add_address_book", {address: address, description: description}); - return resp.result.index; - } - - async editAddressBookEntry(index, setAddress, address, setDescription, description) { - let resp = await this.rpc.sendJsonRequest("edit_address_book", { - index: index, - set_address: setAddress, - address: address, - set_description: setDescription, - description: description - }); - } - - async deleteAddressBookEntry(entryIdx) { - await this.rpc.sendJsonRequest("delete_address_book", {index: entryIdx}); - } - - async tagAccounts(tag, accountIndices) { - await this.rpc.sendJsonRequest("tag_accounts", {tag: tag, accounts: accountIndices}); - } - - async untagAccounts(accountIndices) { - await this.rpc.sendJsonRequest("untag_accounts", {accounts: accountIndices}); - } - - async getAccountTags() { - let tags = []; - let resp = await this.rpc.sendJsonRequest("get_account_tags"); - if (resp.result.account_tags) { - for (let rpcAccountTag of resp.result.account_tags) { - tags.push(new MoneroAccountTag(rpcAccountTag.tag ? rpcAccountTag.tag : undefined, rpcAccountTag.label ? rpcAccountTag.label : undefined, rpcAccountTag.accounts)); - } - } - return tags; - } - - async setAccountTagLabel(tag, label) { - await this.rpc.sendJsonRequest("set_account_tag_description", {tag: tag, description: label}); - } - - async createPaymentUri(config) { - config = MoneroWallet._normalizeCreateTxsConfig(config); - let resp = await this.rpc.sendJsonRequest("make_uri", { - address: config.getDestinations()[0].getAddress(), - amount: config.getDestinations()[0].getAmount() ? config.getDestinations()[0].getAmount().toString() : undefined, - payment_id: config.getPaymentId(), - recipient_name: config.getRecipientName(), - tx_description: config.getNote() - }); - return resp.result.uri; - } - - async parsePaymentUri(uri) { - assert(uri, "Must provide URI to parse"); - let resp = await this.rpc.sendJsonRequest("parse_uri", {uri: uri}); - let config = new MoneroTxConfig({address: resp.result.uri.address, amount: new BigInteger(resp.result.uri.amount)}); - config.setPaymentId(resp.result.uri.payment_id); - config.setRecipientName(resp.result.uri.recipient_name); - config.setNote(resp.result.uri.tx_description); - if ("" === config.getDestinations()[0].getAddress()) config.getDestinations()[0].setAddress(undefined); - if ("" === config.getPaymentId()) config.setPaymentId(undefined); - if ("" === config.getRecipientName()) config.setRecipientName(undefined); - if ("" === config.getNote()) config.setNote(undefined); - return config; - } - - async getAttribute(key) { - try { - let resp = await this.rpc.sendJsonRequest("get_attribute", {key: key}); - return resp.result.value === "" ? undefined : resp.result.value; - } catch (e) { - if (e instanceof MoneroRpcError && e.getCode() === -45) return undefined; - throw e; - } - } - - async setAttribute(key, val) { - await this.rpc.sendJsonRequest("set_attribute", {key: key, value: val}); - } - - async startMining(numThreads, backgroundMining, ignoreBattery) { - await this.rpc.sendJsonRequest("start_mining", { - threads_count: numThreads, - do_background_mining: backgroundMining, - ignore_battery: ignoreBattery - }); - } - - async stopMining() { - await this.rpc.sendJsonRequest("stop_mining"); - } - - async isMultisigImportNeeded() { - let resp = await this.rpc.sendJsonRequest("get_balance"); - return resp.result.multisig_import_needed === true; - } - - async getMultisigInfo() { - let resp = await this.rpc.sendJsonRequest("is_multisig"); - let result = resp.result; - let info = new MoneroMultisigInfo(); - info.setIsMultisig(result.multisig); - info.setIsReady(result.ready); - info.setThreshold(result.threshold); - info.setNumParticipants(result.total); - return info; - } - - async prepareMultisig() { - let resp = await this.rpc.sendJsonRequest("prepare_multisig"); - let result = resp.result; - return result.multisig_info; - } - - async makeMultisig(multisigHexes, threshold, password) { - let resp = await this.rpc.sendJsonRequest("make_multisig", { - multisig_info: multisigHexes, - threshold: threshold, - password: password - }); - let result = resp.result; - let msResult = new MoneroMultisigInitResult(); - msResult.setAddress(result.address); - msResult.setMultisigHex(result.multisig_info); - if (msResult.getAddress().length === 0) msResult.setAddress(undefined); - if (msResult.getMultisigHex().length === 0) msResult.setMultisigHex(undefined); - return msResult; - } - - async exchangeMultisigKeys(multisigHexes, password) { - let resp = await this.rpc.sendJsonRequest("exchange_multisig_keys", {multisig_info: multisigHexes, password: password}); - let msResult = new MoneroMultisigInitResult(); - msResult.setAddress(resp.result.address); - msResult.setMultisigHex(resp.result.multisig_info); - if (msResult.getAddress().length === 0) msResult.setAddress(undefined); - if (msResult.getMultisigHex().length === 0) msResult.setMultisigHex(undefined); - return msResult; - } - - async getMultisigHex() { - let resp = await this.rpc.sendJsonRequest("export_multisig_info"); - return resp.result.info; - } - - async importMultisigHex(multisigHexes) { - let resp = await this.rpc.sendJsonRequest("import_multisig_info", {info: multisigHexes}); - return resp.result.n_outputs; - } - - async signMultisigTxHex(multisigTxHex) { - let resp = await this.rpc.sendJsonRequest("sign_multisig", {tx_data_hex: multisigTxHex}); - let result = resp.result; - let signResult = new MoneroMultisigSignResult(); - signResult.setSignedMultisigTxHex(result.tx_data_hex); - signResult.setTxHashes(result.tx_hash_list); - return signResult; - } - - async submitMultisigTxHex(signedMultisigTxHex) { - let resp = await this.rpc.sendJsonRequest("submit_multisig", {tx_data_hex: signedMultisigTxHex}); - return resp.result.tx_hash_list; - } - - async save() { - await this.rpc.sendJsonRequest("store"); - } - - async close(save) { - if (save === undefined) save = false; - this._clear(); - await this.rpc.sendJsonRequest("close_wallet", {autosave_current: save}); - } - - async isClosed() { - try { - await this.getPrimaryAddress(); - } catch (e) { - return e instanceof MoneroRpcError && e.getCode() === -13 && e.message.indexOf("No wallet file") > -1; - } - return false; - } - - /** - * Save and close the current wallet and stop the RPC server. - */ - async stop() { - this._clear(); - await this.rpc.sendJsonRequest("stop_wallet"); - } - - // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS -------------- - - async getTx() { return super.getTx(...arguments); } - async getIncomingTransfers() { return super.getIncomingTransfers(...arguments); } - async getOutgoingTransfers() { return super.getOutgoingTransfers(...arguments); } - async createTx() { return super.createTx(...arguments); } - async relayTx() { return super.relayTx(...arguments); } - async getTxNote() { return super.getTxNote(...arguments); } - async setTxNote() { return super.setTxNote(...arguments); } - - // -------------------------------- PRIVATE --------------------------------- - - async _clear() { - delete this.addressCache; - this.addressCache = {}; - this.path = undefined; - } - - async _getBalances(accountIdx, subaddressIdx) { - if (accountIdx === undefined) { - assert.equal(subaddressIdx, undefined, "Must provide account index with subaddress index"); - let balance = new BigInteger(0); - let unlockedBalance = new BigInteger(0); - for (let account of await this.getAccounts()) { - balance = balance.add(account.getBalance()); - unlockedBalance = unlockedBalance.add(account.getUnlockedBalance()); - } - return [balance, unlockedBalance]; - } else { - let params = {account_index: accountIdx, address_indices: subaddressIdx === undefined ? undefined : [subaddressIdx]}; - let resp = await this.rpc.sendJsonRequest("get_balance", params); - if (subaddressIdx === undefined) return [new BigInteger(resp.result.balance), new BigInteger(resp.result.unlocked_balance)]; - else return [new BigInteger(resp.result.per_subaddress[0].balance), new BigInteger(resp.result.per_subaddress[0].unlocked_balance)]; - } - } - - async _getAccountIndices(getSubaddressIndices) { - let indices = new Map(); - for (let account of await this.getAccounts()) { - indices.set(account.getIndex(), getSubaddressIndices ? await this._getSubaddressIndices(account.getIndex()) : undefined); - } - return indices; - } - - async _getSubaddressIndices(accountIdx) { - let subaddressIndices = []; - let resp = await this.rpc.sendJsonRequest("get_address", {account_index: accountIdx}); - for (let address of resp.result.addresses) subaddressIndices.push(address.address_index); - return subaddressIndices; - } - - async _getTransfersAux(query) { - - // check if pool txs explicitly requested without daemon connection - let txQuery = query.getTxQuery(); - if (txQuery.inTxPool() !== undefined && txQuery.inTxPool() && !await this.isConnected()) { - throw new MoneroError("Cannot fetch pool transactions because wallet has no daemon connection"); - } - - // build params for get_transfers rpc call - let params = {}; - let canBeConfirmed = txQuery.isConfirmed() !== false && txQuery.inTxPool() !== true && txQuery.isFailed() !== true && txQuery.isRelayed() !== false; - let canBeInTxPool = await this.isConnected() && txQuery.isConfirmed() !== true && txQuery.inTxPool() !== false && txQuery.isFailed() !== true && txQuery.isRelayed() !== false && txQuery.getHeight() === undefined && txQuery.getMinHeight() === undefined && txQuery.getMaxHeight() === undefined; - let canBeIncoming = query.isIncoming() !== false && query.isOutgoing() !== true && query.hasDestinations() !== true; - let canBeOutgoing = query.isOutgoing() !== false && query.isIncoming() !== true; - params.in = canBeIncoming && canBeConfirmed; - params.out = canBeOutgoing && canBeConfirmed; - params.pool = canBeIncoming && canBeInTxPool; - params.pending = canBeOutgoing && canBeInTxPool; - params.failed = txQuery.isFailed() !== false && txQuery.isConfirmed() !== true && txQuery.inTxPool() != true; - if (txQuery.getMinHeight() !== undefined) { - if (txQuery.getMinHeight() > 0) params.min_height = txQuery.getMinHeight() - 1; // TODO monero core: wallet2::get_payments() min_height is exclusive, so manually offset to match intended range (issues #5751, #5598) - else params.min_height = txQuery.getMinHeight(); - } - if (txQuery.getMaxHeight() !== undefined) params.max_height = txQuery.getMaxHeight(); - params.filter_by_height = txQuery.getMinHeight() !== undefined || txQuery.getMaxHeight() !== undefined; - if (query.getAccountIndex() === undefined) { - assert(query.getSubaddressIndex() === undefined && query.getSubaddressIndices() === undefined, "Query specifies a subaddress index but not an account index"); - params.all_accounts = true; - } else { - params.account_index = query.getAccountIndex(); - - // set subaddress indices param - let subaddressIndices = new Set(); - if (query.getSubaddressIndex() !== undefined) subaddressIndices.add(query.getSubaddressIndex()); - if (query.getSubaddressIndices() !== undefined) query.getSubaddressIndices().map(subaddressIdx => subaddressIndices.add(subaddressIdx)); - if (subaddressIndices.size) params.subaddr_indices = Array.from(subaddressIndices); - } - - // cache unique txs and blocks - let txMap = {}; - let blockMap = {}; - - // build txs using `get_transfers` - let resp = await this.rpc.sendJsonRequest("get_transfers", params); - for (let key of Object.keys(resp.result)) { - for (let rpcTx of resp.result[key]) { - //if (rpcTx.txid === query.debugTxId) console.log(rpcTx); - let tx = MoneroWalletRpc._convertRpcTxWithTransfer(rpcTx); - if (tx.isConfirmed()) assert(tx.getBlock().getTxs().indexOf(tx) > -1); - - // replace transfer amount with destination sum - // TODO monero-wallet-rpc: confirmed tx from/to same account has amount 0 but cached transfers - if (tx.getOutgoingTransfer() !== undefined && tx.isRelayed() && !tx.isFailed() && - tx.getOutgoingTransfer().getDestinations() && tx.getOutgoingAmount().compare(new BigInteger(0)) === 0) { - let outgoingTransfer = tx.getOutgoingTransfer(); - let transferTotal = new BigInteger(0); - for (let destination of outgoingTransfer.getDestinations()) transferTotal = transferTotal.add(destination.getAmount()); - tx.getOutgoingTransfer().setAmount(transferTotal); - } - - // merge tx - MoneroWalletRpc._mergeTx(tx, txMap, blockMap, false); - } - } - - // sort txs by block height - let txs = Object.values(txMap); - txs.sort(MoneroWalletRpc._compareTxsByHeight); - - // filter and return transfers - let transfers = []; - for (let tx of txs) { - - // tx is not incoming/outgoing unless already set - if (tx.isIncoming() === undefined) tx.setIsIncoming(false); - if (tx.isOutgoing() === undefined) tx.setIsOutgoing(false); - - // sort incoming transfers - if (tx.getIncomingTransfers() !== undefined) tx.getIncomingTransfers().sort(MoneroWalletRpc._compareIncomingTransfers); - - // collect queried transfers, erase if excluded - for (let transfer of tx.filterTransfers(query)) { - transfers.push(transfer); - } - - // remove txs without requested transfer - if (tx.getBlock() !== undefined && tx.getOutgoingTransfer() === undefined && tx.getIncomingTransfers() === undefined) { - tx.getBlock().getTxs().splice(tx.getBlock().getTxs().indexOf(tx), 1); - } - } - - return transfers; - } - - async _getOutputsAux(query) { - - // determine account and subaddress indices to be queried - let indices = new Map(); - if (query.getAccountIndex() !== undefined) { - let subaddressIndices = new Set(); - if (query.getSubaddressIndex() !== undefined) subaddressIndices.add(query.getSubaddressIndex()); - if (query.getSubaddressIndices() !== undefined) query.getSubaddressIndices().map(subaddressIdx => subaddressIndices.add(subaddressIdx)); - indices.set(query.getAccountIndex(), subaddressIndices.size ? Array.from(subaddressIndices) : undefined); // undefined will fetch from all subaddresses - } else { - assert.equal(query.getSubaddressIndex(), undefined, "Query specifies a subaddress index but not an account index") - assert(query.getSubaddressIndices() === undefined || query.getSubaddressIndices().length === 0, "Query specifies subaddress indices but not an account index"); - indices = await this._getAccountIndices(); // fetch all account indices without subaddresses - } - - // cache unique txs and blocks - let txMap = {}; - let blockMap = {}; - - // collect txs with outputs for each indicated account using `incoming_transfers` rpc call - let params = {}; - params.transfer_type = query.isSpent() === true ? "unavailable" : query.isSpent() === false ? "available" : "all"; - params.verbose = true; - for (let accountIdx of indices.keys()) { - - // send request - params.account_index = accountIdx; - params.subaddr_indices = indices.get(accountIdx); - let resp = await this.rpc.sendJsonRequest("incoming_transfers", params); - - // convert response to txs with outputs and merge - if (resp.result.transfers === undefined) continue; - for (let rpcOutput of resp.result.transfers) { - let tx = MoneroWalletRpc._convertRpcTxWalletWithOutput(rpcOutput); - MoneroWalletRpc._mergeTx(tx, txMap, blockMap, false); - } - } - - // sort txs by block height - let txs = Object.values(txMap); - txs.sort(MoneroWalletRpc._compareTxsByHeight); - - // collect queried outputs - let outputs = []; - for (let tx of txs) { - - // sort outputs - if (tx.getOutputs() !== undefined) tx.getOutputs().sort(MoneroWalletRpc._compareOutputs); - - // collect queried outputs, erase if excluded - for (let output of tx.filterOutputs(query)) outputs.push(output); - - // remove excluded txs from block - if (tx.getOutputs() === undefined && tx.getBlock() !== undefined) { - tx.getBlock().getTxs().splice(tx.getBlock().getTxs().indexOf(tx), 1); - } - } - return outputs; - } - - /** - * Common method to get key images. - * - * @param all - pecifies to get all xor only new images from last import - * @return {MoneroKeyImage[]} are the key images - */ - async _rpcExportKeyImages(all) { - let resp = await this.rpc.sendJsonRequest("export_key_images", {all: all}); - if (!resp.result.signed_key_images) return []; - return resp.result.signed_key_images.map(rpcImage => new MoneroKeyImage(rpcImage.key_image, rpcImage.signature)); - } - - async _rpcSweepAccount(config) { - - // validate config - if (config === undefined) throw new MoneroError("Must provide sweep config"); - if (config.getAccountIndex() === undefined) throw new MoneroError("Must provide an account index to sweep from"); - if (config.getDestinations() === undefined || config.getDestinations().length != 1) throw new MoneroError("Must provide exactly one destination to sweep to"); - if (config.getDestinations()[0].getAddress() === undefined) throw new MoneroError("Must provide destination address to sweep to"); - if (config.getDestinations()[0].getAmount() !== undefined) throw new MoneroError("Cannot specify amount in sweep config"); - if (config.getKeyImage() !== undefined) throw new MoneroError("Key image defined; use sweepOutput() to sweep an output by its key image"); - if (config.getSubaddressIndices() !== undefined && config.getSubaddressIndices().length === 0) throw new MoneroError("Empty list given for subaddresses indices to sweep"); - if (config.getSweepEachSubaddress()) throw new MoneroError("Cannot sweep each subaddress with RPC `sweep_all`"); - - // sweep from all subaddresses if not otherwise defined - if (config.getSubaddressIndices() === undefined) { - config.setSubaddressIndices([]); - for (let subaddress of await this.getSubaddresses(config.getAccountIndex())) { - config.getSubaddressIndices().push(subaddress.getIndex()); - } - } - if (config.getSubaddressIndices().length === 0) throw new MoneroError("No subaddresses to sweep from"); - - // common config params - let params = {}; - let relay = config.getRelay() === true; - params.account_index = config.getAccountIndex(); - params.subaddr_indices = config.getSubaddressIndices(); - params.address = config.getDestinations()[0].getAddress(); - assert(config.getPriority() === undefined || config.getPriority() >= 0 && config.getPriority() <= 3); - params.priority = config.getPriority(); - params.unlock_time = config.getUnlockHeight(); - params.payment_id = config.getPaymentId(); - params.do_not_relay = !relay; - params.below_amount = config.getBelowAmount(); - params.get_tx_keys = true; - params.get_tx_hex = true; - params.get_tx_metadata = true; - - // invoke wallet rpc `sweep_all` - let resp = await this.rpc.sendJsonRequest("sweep_all", params); - let result = resp.result; - - // initialize txs from response - let txSet = MoneroWalletRpc._convertRpcSentTxsToTxSet(result); - - // initialize remaining known fields - for (let tx of txSet.getTxs()) { - tx.setIsLocked(true); - tx.setIsConfirmed(false); - tx.setNumConfirmations(0); - tx.setRelay(relay); - tx.setInTxPool(relay); - tx.setIsRelayed(relay); - tx.setIsMinerTx(false); - tx.setIsFailed(false); - tx.setRingSize(MoneroUtils.RING_SIZE); - let transfer = tx.getOutgoingTransfer(); - transfer.setAccountIndex(config.getAccountIndex()); - if (config.getSubaddressIndices().length === 1) transfer.setSubaddressIndices(config.getSubaddressIndices()); - let destination = new MoneroDestination(config.getDestinations()[0].getAddress(), new BigInteger(transfer.getAmount())); - transfer.setDestinations([destination]); - tx.setOutgoingTransfer(transfer); - tx.setPaymentId(config.getPaymentId()); - if (tx.getUnlockHeight() === undefined) tx.setUnlockHeight(config.getUnlockHeight() === undefined ? 0 : config.getUnlockHeight()); - if (tx.getRelay()) { - if (tx.getLastRelayedTimestamp() === undefined) tx.setLastRelayedTimestamp(+new Date().getTime()); // TODO (monero-wallet-rpc): provide timestamp on response; unconfirmed timestamps vary - if (tx.isDoubleSpendSeen() === undefined) tx.setIsDoubleSpend(false); - } - } - return txSet.getTxs(); - } - - // ---------------------------- PRIVATE STATIC ------------------------------ - - /** - * Remove criteria which requires looking up other transfers/outputs to - * fulfill query. - * - * @param {MoneroTxQuery} query - the query to decontextualize - * @return {MoneroTxQuery} a reference to the query for convenience - */ - static _decontextualize(query) { - query.setIsIncoming(undefined); - query.setIsOutgoing(undefined); - query.setTransferQuery(undefined); - query.setOutputQuery(undefined); - return query; - } - - static _isContextual(query) { - if (!query) return false; - if (!query.getTxQuery()) return false; - if (query.getTxQuery().isIncoming() !== undefined) return true; // requires getting other transfers - if (query.getTxQuery().isOutgoing() !== undefined) return true; - if (query instanceof MoneroTransferQuery) { - if (query.getTxQuery().getOutputQuery() !== undefined) return true; // requires getting other outputs - } else if (query instanceof MoneroOutputQuery) { - if (query.getTxQuery().getTransferQuery() !== undefined) return true; // requires getting other transfers - } else { - throw new MoneroError("query must be tx or transfer query"); - } - return false; - } - - static _convertRpcAccount(rpcAccount) { - let account = new MoneroAccount(); - for (let key of Object.keys(rpcAccount)) { - let val = rpcAccount[key]; - if (key === "account_index") account.setIndex(val); - else if (key === "balance") account.setBalance(new BigInteger(val)); - else if (key === "unlocked_balance") account.setUnlockedBalance(new BigInteger(val)); - else if (key === "base_address") account.setPrimaryAddress(val); - else if (key === "tag") account.setTag(val); - else if (key === "label") { } // label belongs to first subaddress - else console.log("WARNING: ignoring unexpected account field: " + key + ": " + val); - } - if ("" === account.getTag()) account.setTag(undefined); - return account; - } - - static _convertRpcSubaddress(rpcSubaddress) { - let subaddress = new MoneroSubaddress(); - for (let key of Object.keys(rpcSubaddress)) { - let val = rpcSubaddress[key]; - if (key === "account_index") subaddress.setAccountIndex(val); - else if (key === "address_index") subaddress.setIndex(val); - else if (key === "address") subaddress.setAddress(val); - else if (key === "balance") subaddress.setBalance(new BigInteger(val)); - else if (key === "unlocked_balance") subaddress.setUnlockedBalance(new BigInteger(val)); - else if (key === "num_unspent_outputs") subaddress.setNumUnspentOutputs(val); - else if (key === "label") { if (val) subaddress.setLabel(val); } - else if (key === "used") subaddress.setIsUsed(val); - else if (key === "blocks_to_unlock") subaddress.setNumBlocksToUnlock(val); - else if (key == "time_to_unlock") {} // ignoring - else console.log("WARNING: ignoring unexpected subaddress field: " + key + ": " + val); - } - return subaddress; - } - - /** - * Initializes a sent transaction. - * - * @param {MoneroTxConfig} config - send config - * @param {MoneroTxWallet} tx - existing transaction to initialize (optional) - * @return {MoneroTxWallet} is the initialized send tx - */ - static _initSentTxWallet(config, tx) { - if (!tx) tx = new MoneroTxWallet(); - let relay = config.getRelay() === true; - tx.setIsOutgoing(true); - tx.setIsConfirmed(false); - tx.setNumConfirmations(0); - tx.setInTxPool(relay); - tx.setRelay(relay); - tx.setIsRelayed(relay); - tx.setIsMinerTx(false); - tx.setIsFailed(false); - tx.setIsLocked(true); - tx.setRingSize(MoneroUtils.RING_SIZE); - let transfer = new MoneroOutgoingTransfer().setTx(tx); - if (config.getSubaddressIndices() && config.getSubaddressIndices().length === 1) transfer.setSubaddressIndices(config.getSubaddressIndices().slice(0)); // we know src subaddress indices iff config specifies 1 - let destCopies = []; - for (let dest of config.getDestinations()) destCopies.push(dest.copy()); - transfer.setDestinations(destCopies); - tx.setOutgoingTransfer(transfer); - tx.setPaymentId(config.getPaymentId()); - if (tx.getUnlockHeight() === undefined) tx.setUnlockHeight(config.getUnlockHeight() === undefined ? 0 : config.getUnlockHeight()); - if (config.getRelay()) { - if (tx.getLastRelayedTimestamp() === undefined) tx.setLastRelayedTimestamp(+new Date().getTime()); // TODO (monero-wallet-rpc): provide timestamp on response; unconfirmed timestamps vary - if (tx.isDoubleSpendSeen() === undefined) tx.setIsDoubleSpend(false); - } - return tx; - } - - /** - * Initializes a tx set from a RPC map excluding txs. - * - * @param rpcMap - map to initialize the tx set from - * @return MoneroTxSet - initialized tx set - * @return the resulting tx set - */ - static _convertRpcTxSet(rpcMap) { - let txSet = new MoneroTxSet(); - txSet.setMultisigTxHex(rpcMap.multisig_txset); - txSet.setUnsignedTxHex(rpcMap.unsigned_txset); - txSet.setSignedTxHex(rpcMap.signed_txset); - if (txSet.getMultisigTxHex() !== undefined && txSet.getMultisigTxHex().length === 0) txSet.setMultisigTxHex(undefined); - if (txSet.getUnsignedTxHex() !== undefined && txSet.getUnsignedTxHex().length === 0) txSet.setUnsignedTxHex(undefined); - if (txSet.getSignedTxHex() !== undefined && txSet.getSignedTxHex().length === 0) txSet.setSignedTxHex(undefined); - return txSet; - } - - /** - * Initializes a MoneroTxSet from from a list of rpc txs. - * - * @param rpcTxs - rpc txs to initialize the set from - * @param txs - existing txs to further initialize (optional) - * @return the converted tx set - */ - static _convertRpcSentTxsToTxSet(rpcTxs, txs) { - - // build shared tx set - let txSet = MoneroWalletRpc._convertRpcTxSet(rpcTxs); - - // get number of txs - let numTxs = rpcTxs.fee_list ? rpcTxs.fee_list.length : 0; - - // done if rpc response contains no txs - if (numTxs === 0) { - assert.equal(txs, undefined); - return txSet; - } - - // pre-initialize txs if none given - if (txs) txSet.setTxs(txs); - else { - txs = []; - for (let i = 0; i < numTxs; i++) txs.push(new MoneroTxWallet()); - } - for (let tx of txs) { - tx.setTxSet(txSet); - tx.setIsOutgoing(true); - } - txSet.setTxs(txs); - - // initialize txs from rpc lists - for (let key of Object.keys(rpcTxs)) { - let val = rpcTxs[key]; - if (key === "tx_hash_list") for (let i = 0; i < val.length; i++) txs[i].setHash(val[i]); - else if (key === "tx_key_list") for (let i = 0; i < val.length; i++) txs[i].setKey(val[i]); - else if (key === "tx_blob_list") for (let i = 0; i < val.length; i++) txs[i].setFullHex(val[i]); - else if (key === "tx_metadata_list") for (let i = 0; i < val.length; i++) txs[i].setMetadata(val[i]); - else if (key === "fee_list") for (let i = 0; i < val.length; i++) txs[i].setFee(new BigInteger(val[i])); - else if (key === "weight_list") for (let i = 0; i < val.length; i++) txs[i].setWeight(val[i]); - else if (key === "amount_list") { - for (let i = 0; i < val.length; i++) { - if (txs[i].getOutgoingTransfer() !== undefined) txs[i].getOutgoingTransfer().setAmount(new BigInteger(val[i])); - else txs[i].setOutgoingTransfer(new MoneroOutgoingTransfer().setTx(txs[i]).setAmount(new BigInteger(val[i]))); - } - } - else if (key === "multisig_txset" || key === "unsigned_txset" || key === "signed_txset") {} // handled elsewhere - else LOGGER.warning("WARNING: ignoring unexpected transaction field: " + key + ": " + val); - } - - return txSet; - } - - /** - * Converts a rpc tx with a transfer to a tx set with a tx and transfer. - * - * @param rpcTx - rpc tx to build from - * @param tx - existing tx to continue initializing (optional) - * @param isOutgoing - specifies if the tx is outgoing if true, incoming if false, or decodes from type if undefined - * @returns the initialized tx set with a tx - */ - static _convertRpcTxToTxSet(rpcTx, tx, isOutgoing) { - let txSet = MoneroWalletRpc._convertRpcTxSet(rpcTx); - txSet.setTxs([MoneroWalletRpc._convertRpcTxWithTransfer(rpcTx, tx, isOutgoing).setTxSet(txSet)]); - return txSet; - } - - /** - * Builds a MoneroTxWallet from a RPC tx. - * - * @param rpcTx - rpc tx to build from - * @param tx - existing tx to continue initializing (optional) - * @param isOutgoing - specifies if the tx is outgoing if true, incoming if false, or decodes from type if undefined - * @returns {MoneroTxWallet} is the initialized tx - */ - static _convertRpcTxWithTransfer(rpcTx, tx, isOutgoing) { // TODO: change everything to safe set - - // initialize tx to return - if (!tx) tx = new MoneroTxWallet(); - - // initialize tx state from rpc type - if (rpcTx.type !== undefined) isOutgoing = MoneroWalletRpc._decodeRpcType(rpcTx.type, tx); - else assert.equal(typeof isOutgoing, "boolean", "Must indicate if tx is outgoing (true) xor incoming (false) since unknown"); - - // TODO: safe set - // initialize remaining fields TODO: seems this should be part of common function with DaemonRpc._convertRpcTx - let header; - let transfer; - for (let key of Object.keys(rpcTx)) { - let val = rpcTx[key]; - if (key === "txid") tx.setHash(val); - else if (key === "tx_hash") tx.setHash(val); - else if (key === "fee") tx.setFee(new BigInteger(val)); - else if (key === "note") { if (val) tx.setNote(val); } - else if (key === "tx_key") tx.setKey(val); - else if (key === "type") { } // type already handled - else if (key === "tx_size") tx.setSize(val); - else if (key === "unlock_time") tx.setUnlockHeight(val); - else if (key === "weight") tx.setWeight(val); - else if (key === "locked") tx.setIsLocked(val); - else if (key === "tx_blob") tx.setFullHex(val); - else if (key === "tx_metadata") tx.setMetadata(val); - else if (key === "double_spend_seen") tx.setIsDoubleSpend(val); - else if (key === "block_height" || key === "height") { - if (tx.isConfirmed()) { - if (!header) header = new MoneroBlockHeader(); - header.setHeight(val); - } - } - else if (key === "timestamp") { - if (tx.isConfirmed()) { - if (!header) header = new MoneroBlockHeader(); - header.setTimestamp(val); - } else { - // timestamp of unconfirmed tx is current request time - } - } - else if (key === "confirmations") tx.setNumConfirmations(val); - else if (key === "suggested_confirmations_threshold") { - if (transfer === undefined) transfer = (isOutgoing ? new MoneroOutgoingTransfer() : new MoneroIncomingTransfer()).setTx(tx); - if (!isOutgoing) transfer.setNumSuggestedConfirmations(val); - } - else if (key === "amount") { - if (transfer === undefined) transfer = (isOutgoing ? new MoneroOutgoingTransfer() : new MoneroIncomingTransfer()).setTx(tx); - transfer.setAmount(new BigInteger(val)); - } - else if (key === "amounts") {} // ignoring, amounts sum to amount - else if (key === "address") { - if (!isOutgoing) { - if (!transfer) transfer = new MoneroIncomingTransfer().setTx(tx); - transfer.setAddress(val); - } - } - else if (key === "payment_id") { - if ("" !== val && MoneroTxWallet.DEFAULT_PAYMENT_ID !== val) tx.setPaymentId(val); // default is undefined - } - else if (key === "subaddr_index") assert(rpcTx.subaddr_indices); // handled by subaddr_indices - else if (key === "subaddr_indices") { - if (!transfer) transfer = (isOutgoing ? new MoneroOutgoingTransfer() : new MoneroIncomingTransfer()).setTx(tx); - let rpcIndices = val; - transfer.setAccountIndex(rpcIndices[0].major); - if (isOutgoing) { - let subaddressIndices = []; - for (let rpcIndex of rpcIndices) subaddressIndices.push(rpcIndex.minor); - transfer.setSubaddressIndices(subaddressIndices); - } else { - assert.equal(rpcIndices.length, 1); - transfer.setSubaddressIndex(rpcIndices[0].minor); - } - } - else if (key === "destinations" || key == "recipients") { - assert(isOutgoing); - let destinations = []; - for (let rpcDestination of val) { - let destination = new MoneroDestination(); - destinations.push(destination); - for (let destinationKey of Object.keys(rpcDestination)) { - if (destinationKey === "address") destination.setAddress(rpcDestination[destinationKey]); - else if (destinationKey === "amount") destination.setAmount(new BigInteger(rpcDestination[destinationKey])); - else throw new MoneroError("Unrecognized transaction destination field: " + destinationKey); - } - } - if (transfer === undefined) transfer = new MoneroOutgoingTransfer({tx: tx}); - transfer.setDestinations(destinations); - } - else if (key === "multisig_txset" && val !== undefined) {} // handled elsewhere; this method only builds a tx wallet - else if (key === "unsigned_txset" && val !== undefined) {} // handled elsewhere; this method only builds a tx wallet - else if (key === "amount_in") tx.setInputSum(new BigInteger(val)); - else if (key === "amount_out") tx.setOutputSum(new BigInteger(val)); - else if (key === "change_address") tx.setChangeAddress(val === "" ? undefined : val); - else if (key === "change_amount") tx.setChangeAmount(new BigInteger(val)); - else if (key === "dummy_outputs") tx.setNumDummyOutputs(val); - else if (key === "extra") tx.setExtraHex(val); - else if (key === "ring_size") tx.setRingSize(val); - else console.log("WARNING: ignoring unexpected transaction field: " + key + ": " + val); - } - - // link block and tx - if (header) tx.setBlock(new MoneroBlock(header).setTxs([tx])); - - // initialize final fields - if (transfer) { - if (tx.isConfirmed() === undefined) tx.setIsConfirmed(false); - if (!transfer.getTx().isConfirmed()) tx.setNumConfirmations(0); - if (isOutgoing) { - tx.setIsOutgoing(true); - if (tx.getOutgoingTransfer()) tx.getOutgoingTransfer().merge(transfer); - else tx.setOutgoingTransfer(transfer); - } else { - tx.setIsIncoming(true); - tx.setIncomingTransfers([transfer]); - } - } - - // return initialized transaction - return tx; - } - - static _convertRpcTxWalletWithOutput(rpcOutput) { - - // initialize tx - let tx = new MoneroTxWallet(); - tx.setIsConfirmed(true); - tx.setIsRelayed(true); - tx.setIsFailed(false); - - // initialize output - let output = new MoneroOutputWallet({tx: tx}); - for (let key of Object.keys(rpcOutput)) { - let val = rpcOutput[key]; - if (key === "amount") output.setAmount(new BigInteger(val)); - else if (key === "spent") output.setIsSpent(val); - else if (key === "key_image") { if ("" !== val) output.setKeyImage(new MoneroKeyImage(val)); } - else if (key === "global_index") output.setIndex(val); - else if (key === "tx_hash") tx.setHash(val); - else if (key === "unlocked") tx.setIsLocked(!val); - else if (key === "frozen") output.setIsFrozen(val); - else if (key === "subaddr_index") { - output.setAccountIndex(val.major); - output.setSubaddressIndex(val.minor); - } - else if (key === "block_height") tx.setBlock(new MoneroBlock().setHeight(val).setTxs([tx])); - else console.log("WARNING: ignoring unexpected transaction field: " + key + ": " + val); - } - - // initialize tx with output - tx.setOutputs([output]); - return tx; - } - - static _convertRpcDescribeTransfer(rpcDescribeTransferResult) { - let txSet = new MoneroTxSet(); - for (let key of Object.keys(rpcDescribeTransferResult)) { - let val = rpcDescribeTransferResult[key]; - if (key === "desc") { - txSet.setTxs([]); - for (let txMap of val) { - let tx = MoneroWalletRpc._convertRpcTxWithTransfer(txMap, undefined, true); - txSet.getTxs().push(tx); - } - } - else console.log("WARNING: ignoring unexpected descdribe transfer field: " + key + ": " + val); - } - return txSet; - } - - /** - * Decodes a "type" from monero-wallet-rpc to initialize type and state - * fields in the given transaction. - * - * TODO: these should be safe set - * - * @param rpcType is the type to decode - * @param tx is the transaction to decode known fields to - * @return {boolean} true if the rpc type indicates outgoing xor incoming - */ - static _decodeRpcType(rpcType, tx) { - let isOutgoing; - if (rpcType === "in") { - isOutgoing = false; - tx.setIsConfirmed(true); - tx.setInTxPool(false); - tx.setIsRelayed(true); - tx.setRelay(true); - tx.setIsFailed(false); - tx.setIsMinerTx(false); - } else if (rpcType === "out") { - isOutgoing = true; - tx.setIsConfirmed(true); - tx.setInTxPool(false); - tx.setIsRelayed(true); - tx.setRelay(true); - tx.setIsFailed(false); - tx.setIsMinerTx(false); - } else if (rpcType === "pool") { - isOutgoing = false; - tx.setIsConfirmed(false); - tx.setInTxPool(true); - tx.setIsRelayed(true); - tx.setRelay(true); - tx.setIsFailed(false); - tx.setIsMinerTx(false); // TODO: but could it be? - } else if (rpcType === "pending") { - isOutgoing = true; - tx.setIsConfirmed(false); - tx.setInTxPool(true); - tx.setIsRelayed(true); - tx.setRelay(true); - tx.setIsFailed(false); - tx.setIsMinerTx(false); - } else if (rpcType === "block") { - isOutgoing = false; - tx.setIsConfirmed(true); - tx.setInTxPool(false); - tx.setIsRelayed(true); - tx.setRelay(true); - tx.setIsFailed(false); - tx.setIsMinerTx(true); - } else if (rpcType === "failed") { - isOutgoing = true; - tx.setIsConfirmed(false); - tx.setInTxPool(false); - tx.setIsRelayed(true); - tx.setRelay(true); - tx.setIsFailed(true); - tx.setIsMinerTx(false); - } else { - throw new MoneroError("Unrecognized transfer type: " + rpcType); - } - return isOutgoing; - } - - /** - * Merges a transaction into a unique set of transactions. - * - * TODO monero core: skipIfAbsent only necessary because incoming payments not returned - * when sent from/to same account #4500 - * - * @param tx is the transaction to merge into the existing txs - * @param txMap maps tx hashes to txs - * @param blockMap maps block heights to blocks - * @param skipIfAbsent specifies if the tx should not be added if it doesn't already exist - */ - static _mergeTx(tx, txMap, blockMap, skipIfAbsent) { - assert(tx.getHash() !== undefined); - - // if tx doesn't exist, add it (unless skipped) - let aTx = txMap[tx.getHash()]; - if (aTx === undefined) { - if (!skipIfAbsent) { - txMap[tx.getHash()] = tx; - } else { - console.log("WARNING: tx does not already exist"); - } - } - - // otherwise merge with existing tx - else { - aTx.merge(tx); - } - - // if confirmed, merge tx's block - if (tx.getHeight() !== undefined) { - let aBlock = blockMap[tx.getHeight()]; - if (aBlock === undefined) { - blockMap[tx.getHeight()] = tx.getBlock(); - } else { - aBlock.merge(tx.getBlock()); - } - } - } - - /** - * Compares two transactions by their height. - */ - static _compareTxsByHeight(tx1, tx2) { - if (tx1.getHeight() === undefined && tx2.getHeight() === undefined) return 0; // both unconfirmed - else if (tx1.getHeight() === undefined) return 1; // tx1 is unconfirmed - else if (tx2.getHeight() === undefined) return -1; // tx2 is unconfirmed - let diff = tx1.getHeight() - tx2.getHeight(); - if (diff !== 0) return diff; - return tx1.getBlock().getTxs().indexOf(tx1) - tx2.getBlock().getTxs().indexOf(tx2); // txs are in the same block so retain their original order - } - - /** - * Compares two transfers by ascending account and subaddress indices. - */ - static _compareIncomingTransfers(t1, t2) { - if (t1.getAccountIndex() < t2.getAccountIndex()) return -1; - else if (t1.getAccountIndex() === t2.getAccountIndex()) return t1.getSubaddressIndex() - t2.getSubaddressIndex(); - return 1; - } - - /** - * Compares two outputs by ascending account and subaddress indices. - */ - static _compareOutputs(o1, o2) { - - // compare by height - let heightComparison = MoneroWalletRpc._compareTxsByHeight(o1.getTx(), o2.getTx()); - if (heightComparison !== 0) return heightComparison; - - // compare by account index, subaddress index, output index, then key image hex - let compare = o1.getAccountIndex() - o2.getAccountIndex(); - if (compare !== 0) return compare; - compare = o1.getSubaddressIndex() - o2.getSubaddressIndex(); - if (compare !== 0) return compare; - compare = o1.getIndex() - o2.getIndex(); - if (compare !== 0) return compare; - return o1.getKeyImage().getHex().compare(o2.getKeyImage().getHex()); - } -} - -module.exports = MoneroWalletRpc; \ No newline at end of file diff --git a/src/main/js/wallet/MoneroWalletWasm.js b/src/main/js/wallet/MoneroWalletWasm.js deleted file mode 100644 index 080852de9..000000000 --- a/src/main/js/wallet/MoneroWalletWasm.js +++ /dev/null @@ -1,2526 +0,0 @@ -const assert = require("assert"); -const BigInteger = require("../common/biginteger").BigInteger; -const GenUtils = require("../common/GenUtils"); -const LibraryUtils = require("../common/LibraryUtils"); -const MoneroAccount = require("./model/MoneroAccount"); -const MoneroAddressBookEntry = require("./model/MoneroAddressBookEntry"); -const MoneroBlock = require("../daemon/model/MoneroBlock"); -const MoneroCheckTx = require("./model/MoneroCheckTx"); -const MoneroDaemonRpc = require("../daemon/MoneroDaemonRpc"); -const MoneroError = require("../common/MoneroError"); -const MoneroIntegratedAddress = require("./model/MoneroIntegratedAddress"); -const MoneroKeyImage = require("../daemon/model/MoneroKeyImage"); -const MoneroKeyImageImportResult = require("./model/MoneroKeyImageImportResult"); -const MoneroMultisigInfo = require("./model/MoneroMultisigInfo"); -const MoneroMultisigInitResult = require("./model/MoneroMultisigInitResult"); -const MoneroMultisigSignResult = require("./model/MoneroMultisigSignResult"); -const MoneroNetworkType = require("../daemon/model/MoneroNetworkType"); -const MoneroOutputWallet = require("./model/MoneroOutputWallet"); -const MoneroRpcConnection = require("../common/MoneroRpcConnection"); -const MoneroSubaddress = require("./model/MoneroSubaddress"); -const MoneroSyncResult = require("./model/MoneroSyncResult"); -const MoneroTxConfig = require("./model/MoneroTxConfig"); -const MoneroTxSet = require("./model/MoneroTxSet"); -const MoneroTxWallet = require("./model/MoneroTxWallet"); -const MoneroUtils = require("../common/MoneroUtils"); -const MoneroWallet = require("./MoneroWallet"); -const MoneroWalletConfig = require("./model/MoneroWalletConfig"); -const MoneroWalletKeys = require("./MoneroWalletKeys"); -const MoneroWalletListener = require("./model/MoneroWalletListener"); - -/** - * Implements a MoneroWallet using WebAssembly bindings to monero-project's wallet2. - * - * @extends {MoneroWalletKeys} - * @implements {MoneroWallet} - * @hideconstructor - */ -class MoneroWalletWasm extends MoneroWalletKeys { - - // --------------------------- STATIC UTILITIES ----------------------------- - - /** - * Check if a wallet exists at a given path. - * - * @param {string} path - path of the wallet on the file system - * @param {fs} - Node.js compatible file system to use (optional, defaults to disk if nodejs) - * @return {boolean} true if a wallet exists at the given path, false otherwise - */ - static async walletExists(path, fs) { - assert(path, "Must provide a path to look for a wallet"); - if (!fs) fs = MoneroWalletWasm._getFs(); - if (!fs) throw new MoneroError("Must provide file system to check if wallet exists"); - let exists = fs.existsSync(path); // TODO: look for keys file - console.log("Wallet exists at " + path + ": " + exists); - return exists; - } - - /** - *

Open an existing wallet using WebAssembly bindings to wallet2.h.

- * - *

Examples:

- * - * - * let wallet1 = await MoneroWalletWasm.openWallet(
- *    "./wallets/wallet1",
- *    "supersecretpassword",
- *    MoneroNetworkType.STAGENET,
- *    "http://localhost:38081" // daemon uri
- * );

- * - * let wallet2 = await MoneroWalletWasm.openWallet({
- *    path: "./wallets/wallet2",
- *    password: "supersecretpassword",
- *    networkType: MoneroNetworkType.STAGENET,
- *    serverUri: "http://localhost:38081", // daemon configuration
- *    serverUsername: "superuser",
- *    serverPassword: "abctesting123"
- * }); - *
- * - * @param {MoneroWalletConfig|object|string} configOrPath - MoneroWalletConfig or equivalent config object or a path to a wallet to open - * @param {string} configOrPath.path - path of the wallet to open (optional if 'keysData' provided) - * @param {string} configOrPath.password - password of the wallet to open - * @param {string|number} configOrPath.networkType - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) - * @param {Uint8Array} configOrPath.keysData - wallet keys data to open (optional if path provided) - * @param {Uint8Array} configOrPath.cacheData - wallet cache data to open (optional) - * @param {string} configOrPath.serverUri - uri of the wallet's daemon (optional) - * @param {string} configOrPath.serverUsername - username to authenticate with the daemon (optional) - * @param {string} configOrPath.serverPassword - password to authenticate with the daemon (optional) - * @param {boolean} configOrPath.rejectUnauthorized - reject self-signed server certificates if true (defaults to true) - * @param {MoneroRpcConnection|object} configOrPath.server - MoneroRpcConnection or equivalent JS object configuring the daemon connection (optional) - * @param {boolean} configOrPath.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise) - * @param {fs} configOrPath.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser) - * @param {string} password - password of the wallet to open - * @param {string|number} networkType - network type of the wallet to open - * @param {string|MoneroRpcConnection} daemonUriOrConnection - daemon URI or MoneroRpcConnection - * @param {boolean} proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise) - * @param {fs} fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser) - * @return {MoneroWalletWasm} the opened wallet - */ - static async openWallet(configOrPath, password, networkType, daemonUriOrConnection, proxyToWorker, fs) { - - // normalize and validate config - let config; - if (typeof configOrPath === "object") { - config = configOrPath instanceof MoneroWalletConfig ? configOrPath : new MoneroWalletConfig(configOrPath); - if (password !== undefined || networkType !== undefined || daemonUriOrConnection !== undefined || proxyToWorker !== undefined || fs !== undefined) throw new MoneroError("Can specify config object or params but not both when opening WASM wallet") - } else { - config = new MoneroWalletConfig().setPath(configOrPath).setPassword(password).setNetworkType(networkType).setProxyToWorker(proxyToWorker).setFs(fs); - if (typeof daemonUriOrConnection === "object") config.setServer(daemonUriOrConnection); - else config.setServerUri(daemonUriOrConnection); - } - if (config.getProxyToWorker() === undefined) config.setProxyToWorker(GenUtils.isBrowser()); - if (config.getMnemonic() !== undefined) throw new MoneroError("Cannot specify mnemonic when opening wallet"); - if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot specify seed offset when opening wallet"); - if (config.getPrimaryAddress() !== undefined) throw new MoneroError("Cannot specify primary address when opening wallet"); - if (config.getPrivateViewKey() !== undefined) throw new MoneroError("Cannot specify private view key when opening wallet"); - if (config.getPrivateSpendKey() !== undefined) throw new MoneroError("Cannot specify private spend key when opening wallet"); - if (config.getRestoreHeight() !== undefined) throw new MoneroError("Cannot specify restore height when opening wallet"); - if (config.getLanguage() !== undefined) throw new MoneroError("Cannot specify language when opening wallet"); - if (config.getSaveCurrent() === true) throw new MoneroError("Cannot save current wallet when opening JNI wallet"); - - // read wallet data from disk if not provided - if (!config.getKeysData()) { - let fs = config.getFs() ? config.getFs() : MoneroWalletWasm._getFs(); - if (!fs) throw new MoneroError("Must provide file system to read wallet data from"); - if (!await this.walletExists(config.getPath(), fs)) throw new MoneroError("Wallet does not exist at path: " + config.getPath()); - config.setKeysData(fs.readFileSync(config.getPath() + ".keys")); - config.setCacheData(fs.readFileSync(config.getPath())); - } - - // open wallet from data - return MoneroWalletWasm._openWalletData(config.getPath(), config.getPassword(), config.getNetworkType(), config.getKeysData(), config.getCacheData(), config.getServer(), config.getProxyToWorker(), config.getFs()); - } - - /** - *

Create a wallet using WebAssembly bindings to wallet2.h.

- * - *

Example:

- * - * - * let wallet = await MoneroWalletWasm.createWallet({
- *    path: "./test_wallets/wallet1", // leave blank for in-memory wallet
- *    password: "supersecretpassword",
- *    networkType: MoneroNetworkType.STAGENET,
- *    mnemonic: "coexist igloo pamphlet lagoon...",
- *    restoreHeight: 1543218,
- *    server: new MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123"),
- * }); - *
- * - * @param {object|MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object - * @param {string} config.path - path of the wallet to create (optional, in-memory wallet if not given) - * @param {string} config.password - password of the wallet to create - * @param {string|number} config.networkType - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) - * @param {string} config.mnemonic - mnemonic of the wallet to create (optional, random wallet created if neither mnemonic nor keys given) - * @param {string} config.seedOffset - the offset used to derive a new seed from the given mnemonic to recover a secret wallet from the mnemonic phrase - * @param {string} config.primaryAddress - primary address of the wallet to create (only provide if restoring from keys) - * @param {string} config.privateViewKey - private view key of the wallet to create (optional) - * @param {string} config.privateSpendKey - private spend key of the wallet to create (optional) - * @param {number} config.restoreHeight - block height to start scanning from (defaults to 0 unless generating random wallet) - * @param {string} config.language - language of the wallet's mnemonic phrase (defaults to "English" or auto-detected) - * @param {string} config.serverUri - uri of the wallet's daemon (optional) - * @param {string} config.serverUsername - username to authenticate with the daemon (optional) - * @param {string} config.serverPassword - password to authenticate with the daemon (optional) - * @param {boolean} config.rejectUnauthorized - reject self-signed server certificates if true (defaults to true) - * @param {MoneroRpcConnection|object} config.server - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional) - * @param {boolean} config.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default true if browser, false otherwise) - * @param {fs} config.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser) - * @return {MoneroWalletWasm} the created wallet - */ - static async createWallet(config) { - - // normalize and validate config - if (config === undefined) throw new MoneroError("Must provide config to create wallet"); - config = config instanceof MoneroWalletConfig ? config : new MoneroWalletConfig(config); - if (config.getMnemonic() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) { - throw new MoneroError("Wallet may be initialized with a mnemonic or keys but not both"); - } // TODO: factor this much out to common - if (config.getNetworkType() === undefined) throw new MoneroError("Must provide a networkType: 'mainnet', 'testnet' or 'stagenet'"); - if (config.getSaveCurrent() === true) throw new MoneroError("Cannot save current wallet when creating WASM wallet"); - - // create wallet - if (config.getMnemonic() !== undefined) { - if (config.getLanguage() !== undefined) throw new MoneroError("Cannot provide language when creating wallet from mnemonic"); - return MoneroWalletWasm._createWalletFromMnemonic(config.getPath(), config.getPassword(), config.getNetworkType(), config.getMnemonic(), config.getServer(), config.getRestoreHeight(), config.getSeedOffset(), config.getProxyToWorker(), config.getFs()); - } else if (config.getPrimaryAddress() !== undefined) { - if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating wallet from keys"); - return MoneroWalletWasm._createWalletFromKeys(config.getPath(), config.getPassword(), config.getNetworkType(), config.getPrimaryAddress(), config.getPrivateViewKey(), config.getPrivateSpendKey(), config.getServer(), config.getRestoreHeight(), config.getLanguage(), config.getProxyToWorker(), config.getFs()); - } else { - if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating random wallet"); - if (config.getRestoreHeight() !== undefined) throw new MoneroError("Cannot provide restoreHeight when creating random wallet"); - return MoneroWalletWasm._createWalletRandom(config.getPath(), config.getPassword(), config.getNetworkType(), config.getServer(), config.getLanguage(), config.getProxyToWorker(), config.getFs()); - } - } - - static async _createWalletRandom(path, password, networkType, daemonUriOrConnection, language, proxyToWorker, fs) { - if (proxyToWorker === undefined) proxyToWorker = GenUtils.isBrowser(); - if (proxyToWorker) return MoneroWalletWasmProxy._createWalletRandom(path, password, networkType, daemonUriOrConnection, language, fs); - - // validate and normalize params - if (path === undefined) path = ""; - if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error("Wallet already exists: " + path); - assert(password, "Must provide a password to create the wallet with"); - MoneroNetworkType.validate(networkType); - if (language === undefined) language = "English"; - let daemonConnection = typeof daemonUriOrConnection === "string" ? new MoneroRpcConnection(daemonUriOrConnection) : daemonUriOrConnection; - let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : ""; - let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : ""; - let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : ""; - let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true; - - // load wasm module - let module = await LibraryUtils.loadCoreModule(); - - // create wallet in queue - let wallet = await module.queueTask(async function() { - return new Promise(function(resolve, reject) { - - // register fn informing if unauthorized reqs should be rejected - let rejectUnauthorizedFnId = GenUtils.getUUID(); - LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return rejectUnauthorized }); - - // define callback for wasm - let callbackFn = async function(cppAddress) { - if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); - else resolve(new MoneroWalletWasm(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId)); - }; - - // create wallet in wasm and invoke callback when done - module.create_core_wallet_random(password, networkType, daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, language, callbackFn); - }); - }); - - // save wallet - if (path) await wallet.save(); - return wallet; - } - - static async _createWalletFromMnemonic(path, password, networkType, mnemonic, daemonUriOrConnection, restoreHeight, seedOffset, proxyToWorker, fs) { - if (proxyToWorker === undefined) proxyToWorker = GenUtils.isBrowser(); - if (proxyToWorker) return MoneroWalletWasmProxy._createWalletFromMnemonic(path, password, networkType, mnemonic, daemonUriOrConnection, restoreHeight, seedOffset, fs); - - // validate and normalize params - if (path === undefined) path = ""; - if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error("Wallet already exists: " + path); - assert(password, "Must provide a password to create the wallet with"); - MoneroNetworkType.validate(networkType); - let daemonConnection = typeof daemonUriOrConnection === "string" ? new MoneroRpcConnection(daemonUriOrConnection) : daemonUriOrConnection; - let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : ""; - let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : ""; - let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : ""; - let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true; - if (restoreHeight === undefined) restoreHeight = 0; - if (seedOffset === undefined) seedOffset = ""; - - // load wasm module - let module = await LibraryUtils.loadCoreModule(); - - // create wallet in queue - let wallet = await module.queueTask(async function() { - return new Promise(function(resolve, reject) { - - // register fn informing if unauthorized reqs should be rejected - let rejectUnauthorizedFnId = GenUtils.getUUID(); - LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return rejectUnauthorized }); - - // define callback for wasm - let callbackFn = async function(cppAddress) { - if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); - else resolve(new MoneroWalletWasm(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId)); - }; - - // create wallet in wasm and invoke callback when done - module.create_core_wallet_from_mnemonic(password, networkType, mnemonic, daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, restoreHeight, seedOffset, callbackFn); - }); - }); - - // save wallet - if (path) await wallet.save(); - return wallet; - } - - static async _createWalletFromKeys(path, password, networkType, address, viewKey, spendKey, daemonUriOrConnection, restoreHeight, language, proxyToWorker, fs) { - if (proxyToWorker === undefined) proxyToWorker = GenUtils.isBrowser(); - if (proxyToWorker) return MoneroWalletWasmProxy._createWalletFromKeys(path, password, networkType, address, viewKey, spendKey, daemonUriOrConnection, restoreHeight, language, fs); - - // validate and normalize params - if (path === undefined) path = ""; - if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error("Wallet already exists: " + path); - assert(password, "Must provide a password to create the wallet with"); - MoneroNetworkType.validate(networkType); - if (address === undefined) address = ""; - if (viewKey === undefined) viewKey = ""; - if (spendKey === undefined) spendKey = ""; - let daemonConnection = typeof daemonUriOrConnection === "string" ? new MoneroRpcConnection(daemonUriOrConnection) : daemonUriOrConnection; - let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : ""; - let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : ""; - let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : ""; - let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true; - if (restoreHeight === undefined) restoreHeight = 0; - if (language === undefined) language = "English"; - - // load wasm module - let module = await LibraryUtils.loadCoreModule(); - - // create wallet in queue - let wallet = await module.queueTask(async function() { - return new Promise(function(resolve, reject) { - - // register fn informing if unauthorized reqs should be rejected - let rejectUnauthorizedFnId = GenUtils.getUUID(); - LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return rejectUnauthorized }); - - // define callback for wasm - let callbackFn = async function(cppAddress) { - if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); - else resolve(new MoneroWalletWasm(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId)); - }; - - // create wallet in wasm and invoke callback when done - module.create_core_wallet_from_keys(password, networkType, address, viewKey, spendKey, daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, restoreHeight, language, callbackFn); - }); - }); - - // save wallet - if (path) await wallet.save(); - return wallet; - } - - static async getMnemonicLanguages() { - let module = await LibraryUtils.loadCoreModule(); - return module.queueTask(async function() { - return JSON.parse(module.get_keys_wallet_mnemonic_languages()).languages; - }); - } - - // --------------------------- INSTANCE METHODS ----------------------------- - - /** - * Internal constructor which is given the memory address of a C++ wallet - * instance. - * - * This method should not be called externally but should be called through - * static wallet creation utilities in this class. - * - * @param {int} cppAddress - address of the wallet instance in C++ - * @param {string} path - path of the wallet instance - * @param {string} password - password of the wallet instance - * @param {FileSystem} fs - node.js-compatible file system to read/write wallet files - * @param {boolean} rejectUnauthorized - specifies if unauthorized requests (e.g. self-signed certificates) should be rejected - * @param {string} rejectUnauthorizedFnId - unique identifier for http_client_wasm to query rejectUnauthorized - */ - constructor(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId) { - super(cppAddress); - this._path = path; - this._password = password; - this._listeners = []; - this._fs = fs ? fs : (path ? MoneroWalletWasm._getFs() : undefined); - this._isClosed = false; - this._wasmListener = new WalletWasmListener(this); // receives notifications from wasm c++ - this._wasmListenerHandle = 0; // memory address of the wallet listener in c++ - this._rejectUnauthorized = rejectUnauthorized; - this._rejectUnauthorizedConfigId = rejectUnauthorizedFnId; - let that = this; - LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return that._rejectUnauthorized }); // register fn informing if unauthorized reqs should be rejected - } - - // ------------ WALLET METHODS SPECIFIC TO WASM IMPLEMENTATION -------------- - - /** - * Get the maximum height of the peers the wallet's daemon is connected to. - * - * @return {number} the maximum height of the peers the wallet's daemon is connected to - */ - async getDaemonMaxPeerHeight() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(resp) { - resolve(resp); - } - - // sync wallet in wasm and invoke callback when done - that._module.get_daemon_max_peer_height(that._cppAddress, callbackFn); - }); - }); - } - - /** - * Indicates if the wallet's daemon is synced with the network. - * - * @return {boolean} true if the daemon is synced with the network, false otherwise - */ - async isDaemonSynced() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(resp) { - resolve(resp); - } - - // sync wallet in wasm and invoke callback when done - that._module.is_daemon_synced(that._cppAddress, callbackFn); - }); - }); - } - - /** - * Indicates if the wallet is synced with the daemon. - * - * @return {boolean} true if the wallet is synced with the daemon, false otherwise - */ - async isSynced() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(resp) { - resolve(resp); - } - - // sync wallet in wasm and invoke callback when done - that._module.is_synced(that._cppAddress, callbackFn); - }); - }); - } - - /** - * Get the wallet's network type (mainnet, testnet, or stagenet). - * - * @return {MoneroNetworkType} the wallet's network type - */ - async getNetworkType() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.get_network_type(that._cppAddress); - }); - } - - /** - * Get the height of the first block that the wallet scans. - * - * @return {number} the height of the first block that the wallet scans - */ - async getSyncHeight() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.get_sync_height(that._cppAddress); - }); - } - - /** - * Set the height of the first block that the wallet scans. - * - * @param {number} syncHeight - height of the first block that the wallet scans - */ - async setSyncHeight(syncHeight) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.set_sync_height(that._cppAddress, syncHeight); - }); - } - - /** - * Register a listener to receive wallet notifications. - * - * @param {MoneroWalletListener} listener - listener to receive wallet notifications - */ - async addListener(listener) { - this._assertNotClosed(); - assert(listener instanceof MoneroWalletListener, "Listener must be instance of MoneroWalletListener"); - this._listeners.push(listener); - await this._setIsListening(true); - } - - /** - * Unregister a listener to receive wallet notifications. - * - * @param {MoneroWalletListener} listener - listener to unregister - */ - async removeListener(listener) { - this._assertNotClosed(); - let idx = this._listeners.indexOf(listener); - if (idx > -1) this._listeners.splice(idx, 1); - else throw new MoneroError("Listener is not registered with wallet"); - if (this._listeners.length === 0) await this._setIsListening(false); - } - - /** - * Get the listeners registered with the wallet. - * - * @return {MoneroWalletListener[]} the registered listeners - */ - getListeners() { - this._assertNotClosed(); - return this._listeners; - } - - /** - * Move the wallet from its current path to the given path. - * - * @param {string} path is the new wallet's path - * @param {string} password is the new wallet's password - */ - async moveTo(path, password) { - this._assertNotClosed(); - throw new Error("Not implemented"); - } - - // -------------------------- COMMON WALLET METHODS ------------------------- - - async setDaemonConnection(uriOrRpcConnection, username, password, rejectUnauthorized) { - this._assertNotClosed(); - - // normalize connection - let connection = new MoneroRpcConnection(uriOrRpcConnection, username, password, rejectUnauthorized); - let uri = connection.getUri(); - username = connection.getUsername(); - password = connection.getPassword(); - rejectUnauthorized = connection.getRejectUnauthorized(); - if (!uri) uri = ""; - if (!username) username = ""; - if (!password) password = ""; - this._rejectUnauthorized = rejectUnauthorized; // persist locally - - // set connection in queue - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(resp) { resolve(); } - - // sync wallet in wasm and invoke callback when done - that._module.set_daemon_connection(that._cppAddress, uri, username, password, callbackFn); - }); - }); - } - - async getDaemonConnection() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - let connectionContainerStr = that._module.get_daemon_connection(that._cppAddress); - if (!connectionContainerStr) resolve(); - else { - let jsonConnection = JSON.parse(connectionContainerStr); - resolve(new MoneroRpcConnection(jsonConnection.uri, jsonConnection.username, jsonConnection.password, that._rejectUnauthorized)); - } - }); - }); - } - - async isConnected() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(resp) { - resolve(resp); - } - - // sync wallet in wasm and invoke callback when done - that._module.is_connected(that._cppAddress, callbackFn); - }); - }); - } - - async getVersion() { - this._assertNotClosed(); - throw new Error("Not implemented"); - } - - async getPath() { - this._assertNotClosed(); - return this._path; - } - - async getIntegratedAddress(paymentId) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - try { - return new MoneroIntegratedAddress(JSON.parse(that._module.get_integrated_address(that._cppAddress, "", paymentId ? paymentId : ""))); - } catch (e) { - throw new MoneroError("Invalid payment ID: " + paymentId); - } - }); - } - - async decodeIntegratedAddress(integratedAddress) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - try { - return new MoneroIntegratedAddress(JSON.parse(that._module.decode_integrated_address(that._cppAddress, integratedAddress))); - } catch (e) { - throw new MoneroError("Invalid integrated address: " + integratedAddress); - } - }); - } - - async getHeight() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(resp) { - resolve(resp); - } - - // sync wallet in wasm and invoke callback when done - that._module.get_height(that._cppAddress, callbackFn); - }); - }); - } - - async getDaemonHeight() { - this._assertNotClosed(); - if (!(await this.isConnected())) throw new MoneroError("Wallet is not connected to daemon"); - - // schedule task - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(resp) { - resolve(resp); - } - - // sync wallet in wasm and invoke callback when done - that._module.get_daemon_height(that._cppAddress, callbackFn); - }); - }); - } - - async getHeightByDate(year, month, day) { - this._assertNotClosed(); - if (!(await this.isConnected())) throw new MoneroError("Wallet is not connected to daemon"); - - // schedule task - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(resp) { - if (typeof resp === "string") reject(new MoneroError(resp)); - else resolve(resp); - } - - // sync wallet in wasm and invoke callback when done - that._module.get_height_by_date(that._cppAddress, year, month, day, callbackFn); - }); - }); - } - - async sync(listenerOrStartHeight, startHeight) { - this._assertNotClosed(); - if (!(await this.isConnected())) throw new MoneroError("Wallet is not connected to daemon"); - - // normalize params - startHeight = listenerOrStartHeight instanceof MoneroWalletListener ? startHeight : listenerOrStartHeight; - let listener = listenerOrStartHeight instanceof MoneroWalletListener ? listenerOrStartHeight : undefined; - if (startHeight === undefined) startHeight = Math.max(await this.getHeight(), await this.getSyncHeight()); - - // register listener if given - if (listener) await this.addListener(listener); - - // sync wallet - let err; - let result; - try { - let that = this; - result = await that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = async function(resp) { - if (resp.charAt(0) !== "{") reject(new MoneroError(resp)); - else { - let respJson = JSON.parse(resp); - resolve(new MoneroSyncResult(respJson.numBlocksFetched, respJson.receivedMoney)); - } - } - - // sync wallet in wasm and invoke callback when done - that._module.sync(that._cppAddress, startHeight, callbackFn); - }); - }); - } catch (e) { - err = e; - } - - // unregister listener - if (listener) await this.removeListener(listener); - - // throw error or return - if (err) throw err; - return result; - } - - async startSyncing() { - this._assertNotClosed(); - if (!(await this.isConnected())) throw new MoneroError("Wallet is not connected to daemon"); - if (!this._syncingEnabled) { - this._syncingEnabled = true; - this._runSyncLoop(); // sync wallet on loop in background - } - } - - async stopSyncing() { - this._assertNotClosed(); - this._syncingEnabled = false; - this._module.stop_syncing(this._cppAddress); // task is not queued so wallet stops immediately - } - - async rescanSpent() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - let callbackFn = function() { resolve(); } - that._module.rescan_spent(that._cppAddress, callbackFn); - }); - }); - } - - async rescanBlockchain() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - let callbackFn = function() { resolve(); } - that._module.rescan_blockchain(that._cppAddress, callbackFn); - }); - }); - } - - async getBalance(accountIdx, subaddressIdx) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - - // get balance encoded in json string - let balanceStr; - if (accountIdx === undefined) { - assert(subaddressIdx === undefined, "Subaddress index must be undefined if account index is undefined"); - balanceStr = that._module.get_balance_wallet(that._cppAddress); - } else if (subaddressIdx === undefined) { - balanceStr = that._module.get_balance_account(that._cppAddress, accountIdx); - } else { - balanceStr = that._module.get_balance_subaddress(that._cppAddress, accountIdx, subaddressIdx); - } - - // parse json string to BigInteger - return BigInteger.parse(JSON.parse(GenUtils.stringifyBIs(balanceStr)).balance); - }); - } - - async getUnlockedBalance(accountIdx, subaddressIdx) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - - // get balance encoded in json string - let unlockedBalanceStr; - if (accountIdx === undefined) { - assert(subaddressIdx === undefined, "Subaddress index must be undefined if account index is undefined"); - unlockedBalanceStr = that._module.get_unlocked_balance_wallet(that._cppAddress); - } else if (subaddressIdx === undefined) { - unlockedBalanceStr = that._module.get_unlocked_balance_account(that._cppAddress, accountIdx); - } else { - unlockedBalanceStr = that._module.get_unlocked_balance_subaddress(that._cppAddress, accountIdx, subaddressIdx); - } - - // parse json string to BigInteger - return BigInteger.parse(JSON.parse(GenUtils.stringifyBIs(unlockedBalanceStr)).unlockedBalance); - }); - } - - async getAccounts(includeSubaddresses, tag) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - let accountsStr = that._module.get_accounts(that._cppAddress, includeSubaddresses ? true : false, tag ? tag : ""); - let accounts = []; - for (let accountJson of JSON.parse(GenUtils.stringifyBIs(accountsStr)).accounts) { - accounts.push(MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson))); - } - return accounts; - }); - } - - async getAccount(accountIdx, includeSubaddresses) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - let accountStr = that._module.get_account(that._cppAddress, accountIdx, includeSubaddresses ? true : false); - let accountJson = JSON.parse(GenUtils.stringifyBIs(accountStr)); - return MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson)); - }); - - } - - async createAccount(label) { - if (label === undefined) label = ""; - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - let accountStr = that._module.create_account(that._cppAddress, label); - let accountJson = JSON.parse(GenUtils.stringifyBIs(accountStr)); - return MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson)); - }); - } - - async getSubaddresses(accountIdx, subaddressIndices) { - let args = {accountIdx: accountIdx, subaddressIndices: subaddressIndices === undefined ? [] : GenUtils.listify(subaddressIndices)}; - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - let subaddressesJson = JSON.parse(GenUtils.stringifyBIs(that._module.get_subaddresses(that._cppAddress, JSON.stringify(args)))).subaddresses; - let subaddresses = []; - for (let subaddressJson of subaddressesJson) subaddresses.push(MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson))); - return subaddresses; - }); - } - - async createSubaddress(accountIdx, label) { - if (label === undefined) label = ""; - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - let subaddressStr = that._module.create_subaddress(that._cppAddress, accountIdx, label); - let subaddressJson = JSON.parse(GenUtils.stringifyBIs(subaddressStr)); - return MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson)); - }); - } - - async getTxs(query, missingTxHashes) { - this._assertNotClosed(); - - // copy and normalize query up to block - query = MoneroWallet._normalizeTxQuery(query); - - // schedule task - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(blocksJsonStr) { - - // check for error - if (blocksJsonStr.charAt(0) !== "{") { - reject(new MoneroError(blocksJsonStr)); - return; - } - - // resolve with deserialized txs - try { - resolve(MoneroWalletWasm._deserializeTxs(query, blocksJsonStr, missingTxHashes)); - } catch (e) { - reject(e); - } - } - - // sync wallet in wasm and invoke callback when done - that._module.get_txs(that._cppAddress, JSON.stringify(query.getBlock().toJson()), callbackFn); - }); - }); - } - - async getTransfers(query) { - this._assertNotClosed(); - - // copy and normalize query up to block - query = MoneroWallet._normalizeTransferQuery(query); - - // return promise which resolves on callback - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(blocksJsonStr) { - - // check for error - if (blocksJsonStr.charAt(0) !== "{") { - reject(new MoneroError(blocksJsonStr)); - return; - } - - // resolve with deserialized transfers - try { - resolve(MoneroWalletWasm._deserializeTransfers(query, blocksJsonStr)); - } catch (e) { - reject(e); - } - } - - // sync wallet in wasm and invoke callback when done - that._module.get_transfers(that._cppAddress, JSON.stringify(query.getTxQuery().getBlock().toJson()), callbackFn); - }); - }); - } - - async getOutputs(query) { - this._assertNotClosed(); - - // copy and normalize query up to block - query = MoneroWallet._normalizeOutputQuery(query); - - // return promise which resolves on callback - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(blocksJsonStr) { - - // check for error - if (blocksJsonStr.charAt(0) !== "{") { - reject(new MoneroError(blocksJsonStr)); - return; - } - - // resolve with deserialized outputs - try { - resolve(MoneroWalletWasm._deserializeOutputs(query, blocksJsonStr)); - } catch (e) { - reject(e); - } - } - - // sync wallet in wasm and invoke callback when done - that._module.get_outputs(that._cppAddress, JSON.stringify(query.getTxQuery().getBlock().toJson()), callbackFn); - }); - }); - } - - async getOutputsHex() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - that._module.get_outputs_hex(that._cppAddress, function(outputsHex) { resolve(outputsHex); }); - }); - }); - } - - async importOutputsHex(outputsHex) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - that._module.import_outputs_hex(that._cppAddress, outputsHex, function(numImported) { resolve(numImported); }); - }); - }); - } - - async getKeyImages() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - let callback = function(keyImagesStr) { - let keyImages = []; - for (let keyImageJson of JSON.parse(GenUtils.stringifyBIs(keyImagesStr)).keyImages) keyImages.push(new MoneroKeyImage(keyImageJson)); - resolve(keyImages); - } - that._module.get_key_images(that._cppAddress, callback); - }); - }); - } - - async importKeyImages(keyImages) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - let callback = function(keyImageImportResultStr) { - resolve(new MoneroKeyImageImportResult(JSON.parse(GenUtils.stringifyBIs(keyImageImportResultStr)))); - } - that._module.import_key_images(that._cppAddress, JSON.stringify({keyImages: keyImages.map(keyImage => keyImage.toJson())}), callback); - }); - }); - } - - async getNewKeyImagesFromLastImport() { - this._assertNotClosed(); - throw new MoneroError("Not implemented"); - } - - async createTxs(config) { - this._assertNotClosed(); - - // validate, copy, and normalize config - config = MoneroWallet._normalizeCreateTxsConfig(config); - if (config.getCanSplit() === undefined) config.setCanSplit(true); - - // check for payment id to avoid error in wasm - if (config.getPaymentId()) throw new MoneroError("Standalone payment IDs are obsolete. Use subaddresses or integrated addresses instead"); // TODO: this should no longer be necessary, remove and re-test - - // return promise which resolves on callback - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(txSetJsonStr) { - if (txSetJsonStr.charAt(0) !== '{') reject(new MoneroError(txSetJsonStr)); // json expected, else error - else resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBIs(txSetJsonStr))).getTxs()); - } - - // create txs in wasm and invoke callback when done - that._module.create_txs(that._cppAddress, JSON.stringify(config.toJson()), callbackFn); - }); - }); - } - - async sweepOutput(config) { - this._assertNotClosed(); - - // normalize and validate config - config = MoneroWallet._normalizeSweepOutputConfig(config); - - // return promise which resolves on callback - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(txSetJsonStr) { - if (txSetJsonStr.charAt(0) !== '{') reject(new MoneroError(txSetJsonStr)); // json expected, else error - else resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBIs(txSetJsonStr))).getTxs()[0]); - } - - // sweep output in wasm and invoke callback when done - that._module.sweep_output(that._cppAddress, JSON.stringify(config.toJson()), callbackFn); - }); - }); - } - - async sweepUnlocked(config) { - this._assertNotClosed(); - - // validate and normalize config - config = MoneroWallet._normalizeSweepUnlockedConfig(config); - - // return promise which resolves on callback - let that = this; - return that._module.queueTask(async function() { // TODO: could factor this pattern out, invoked with module params and callback handler - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(txSetsJson) { - if (txSetsJson.charAt(0) !== '{') reject(new MoneroError(txSetsJson)); // json expected, else error - else { - let txSets = []; - for (let txSetJson of JSON.parse(GenUtils.stringifyBIs(txSetsJson)).txSets) txSets.push(new MoneroTxSet(txSetJson)); - let txs = []; - for (let txSet of txSets) for (let tx of txSet.getTxs()) txs.push(tx); - resolve(txs); - } - } - - // sweep unlocked in wasm and invoke callback when done - that._module.sweep_unlocked(that._cppAddress, JSON.stringify(config.toJson()), callbackFn); - }); - }); - } - - async sweepDust(relay) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - - // define callback for wasm - let callbackFn = function(txSetJsonStr) { - if (txSetJsonStr.charAt(0) !== '{') reject(new MoneroError(txSetJsonStr)); // json expected, else error - else resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBIs(txSetJsonStr))).getTxs()); - } - - // sync wallet in wasm and invoke callback when done - that._module.sweep_dust(that._cppAddress, relay, callbackFn); - }); - }); - } - - async relayTxs(txsOrMetadatas) { - this._assertNotClosed(); - assert(Array.isArray(txsOrMetadatas), "Must provide an array of txs or their metadata to relay"); - let txMetadatas = []; - for (let txOrMetadata of txsOrMetadatas) txMetadatas.push(txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata); - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - let callback = function(txHashesJson) { - if (txHashesJson.charAt(0) !== "{") reject(new MoneroError(txHashesJson)); - else resolve(JSON.parse(txHashesJson).txHashes); - } - that._module.relay_txs(that._cppAddress, JSON.stringify({txMetadatas: txMetadatas}), callback); - }); - }); - } - - async parseTxSet(txSet) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new MoneroTxSet(JSON.parse(GenUtils.stringifyBIs(that._module.parse_tx_set(that._cppAddress, JSON.stringify(txSet.toJson()))))); - }); - } - - async signTxs(unsignedTxHex) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.sign_txs(that._cppAddress, unsignedTxHex); - }); - } - - async submitTxs(signedTxHex) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - let callbackFn = function(resp) { - resolve(JSON.parse(resp).txHashes); - } - that._module.submit_txs(that._cppAddress, signedTxHex, callbackFn); - }); - }); - } - - async signMessage(message) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.sign_message(that._cppAddress, message); - }); - } - - async verifyMessage(message, address, signature) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.verify_message(that._cppAddress, message, address, signature); - }); - } - - async getTxKey(txHash) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.get_tx_key(that._cppAddress, txHash); - }); - } - - async checkTxKey(txHash, txKey, address) { - throw new Error("MoneroWalletWasm.checkTxKey() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html") - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new MoneroCheckTx(JSON.parse(GenUtils.stringifyBIs(that._module.check_tx_key(that._cppAddress, txHash, txKey, address)))); - }); - } - - async getTxProof(txHash, address, message) { - throw new Error("MoneroWalletWasm.checkTxKey() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html") - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.get_tx_proof(that._cppAddress, txHash, address, message); - }); - } - - async checkTxProof(txHash, address, message, signature) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new MoneroCheckTx(JSON.parse(GenUtils.stringifyBIs(that._module.check_tx_proof(that._cppAddress, txHash, address, message, signature)))); - }); - } - - async getSpendProof(txHash, message) { - throw new Error("MoneroWalletWasm.getSpendProof() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html"); // TODO - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.get_spend_proof(that._cppAddress, txHash, message); - }); - } - - async checkSpendProof(txHash, message, signature) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.check_spend_proof(that._cppAddress, txHash, message, signature); - }); - } - - async getReserveProofWallet(message) { - throw new Error("MoneroWalletWasm.getReserveProofWallet() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html"); // TODO - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.get_reserve_proof_wallet(that._cppAddress, message); - }); - } - - async getReserveProofAccount(accountIdx, amount, message) { - throw new Error("MoneroWalletWasm.getReserveProofAccount() not supported because of possible bug in emscripten: https://www.mail-archive.com/emscripten-discuss@googlegroups.com/msg08964.html"); // TODO - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.get_reserve_proof_account(that._cppAddress, accountIdx, amount.toString(), message); - }); - } - - async checkReserveProof(address, message, signature) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new MoneroCheckReserve(JSON.parse(GenUtils.stringifyBIs(that._module.check_reserve_proof(that._cppAddress, address, message, signature)))); - }); - } - - async getTxNotes(txHashes) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return JSON.parse(that._module.get_tx_notes(that._cppAddress, JSON.stringify({txHashes: txHashes}))).txNotes; - }); - } - - async setTxNotes(txHashes, notes) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - that._module.set_tx_notes(that._cppAddress, JSON.stringify({txHashes: txHashes, txNotes: notes})); - }); - } - - async getAddressBookEntries(entryIndices) { - if (!entryIndices) entryIndices = []; - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - let entries = []; - for (let entryJson of JSON.parse(that._module.get_address_book_entries(that._cppAddress, JSON.stringify({entryIndices: entryIndices}))).entries) { - entries.push(new MoneroAddressBookEntry(entryJson)); - } - return entries; - }); - } - - async addAddressBookEntry(address, description) { - if (!address) address = ""; - if (!description) description = ""; - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.add_address_book_entry(that._cppAddress, address, description); - }); - } - - async editAddressBookEntry(index, setAddress, address, setDescription, description) { - if (!setAddress) setAddress = false; - if (!address) address = ""; - if (!setDescription) setDescription = false; - if (!description) description = ""; - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - that._module.edit_address_book_entry(that._cppAddress, index, setAddress, address, setDescription, description); - }); - } - - async deleteAddressBookEntry(entryIdx) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - that._module.delete_address_book_entry(that._cppAddress, entryIdx); - }); - } - - async tagAccounts(tag, accountIndices) { - if (!tag) tag = ""; - if (!accountIndices) accountIndices = []; - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - that._module.tag_accounts(that._cppAddress, JSON.stringify({tag: tag, accountIndices: accountIndices})); - }); - } - - async untagAccounts(accountIndices) { - if (!accountIndices) accountIndices = []; - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - that._module.tag_accounts(that._cppAddress, JSON.stringify({accountIndices: accountIndices})); - }); - } - - async getAccountTags() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - let accountTags = []; - for (let accountTagJson of JSON.parse(that._module.get_account_tags(that._cppAddress)).accountTags) accountTags.push(new MoneroAccountTag(accountTagJson)); - return accountTags; - }); - } - - async setAccountTagLabel(tag, label) { - if (!tag) tag = ""; - if (!llabel) label = ""; - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - that._module.set_account_tag_label(that._cppAddress, tag, label); - }); - } - - async createPaymentUri(config) { - config = MoneroWallet._normalizeCreateTxsConfig(config); - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - try { - return that._module.create_payment_uri(that._cppAddress, JSON.stringify(config.toJson())); - } catch (e) { - throw new MoneroError("Cannot make URI from supplied parameters"); - } - }); - } - - async parsePaymentUri(uri) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - try { - return new MoneroTxConfig(JSON.parse(GenUtils.stringifyBIs(that._module.parse_payment_uri(that._cppAddress, uri)))); - } catch (e) { - throw new MoneroError(e.message); - } - }); - } - - async getAttribute(key) { - this._assertNotClosed(); - assert(typeof key === "string", "Attribute key must be a string"); - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - let value = that._module.get_attribute(that._cppAddress, key); - return value === "" ? null : value; - }); - } - - async setAttribute(key, val) { - this._assertNotClosed(); - assert(typeof key === "string", "Attribute key must be a string"); - assert(typeof val === "string", "Attribute value must be a string"); - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - that._module.set_attribute(that._cppAddress, key, val); - }); - } - - async startMining(numThreads, backgroundMining, ignoreBattery) { - this._assertNotClosed(); - let daemon = new MoneroDaemonRpc(await this.getDaemonConnection()); - await daemon.startMining(await this.getPrimaryAddress(), numThreads, backgroundMining, ignoreBattery); - } - - async stopMining() { - this._assertNotClosed(); - let daemon = new MoneroDaemonRpc(await this.getDaemonConnection()); - await daemon.stopMining(); - } - - async isMultisigImportNeeded() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.is_multisig_import_needed(that._cppAddress); - }); - } - - async isMultisig() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.is_multisig(that._cppAddress); - }); - } - - async getMultisigInfo() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new MoneroMultisigInfo(JSON.parse(that._module.get_multisig_info(that._cppAddress))); - }); - } - - async prepareMultisig() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.prepare_multisig(that._cppAddress); - }); - } - - async makeMultisig(multisigHexes, threshold, password) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new MoneroMultisigInitResult(JSON.parse(that._module.make_multisig(that._cppAddress, JSON.stringify({multisigHexes: multisigHexes, threshold: threshold, password: password})))); - }); - } - - async exchangeMultisigKeys(multisigHexes, password) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new MoneroMultisigInitResult(JSON.parse(that._module.exchange_multisig_keys(that._cppAddress, JSON.stringify({multisigHexes: multisigHexes, password: password})))); - }); - } - - async getMultisigHex() { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return that._module.get_multisig_hex(that._cppAddress); - }); - } - - async importMultisigHex(multisigHexes) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - let callbackFn = function(resp) { - if (typeof resp === "string") reject(new MoneroError(resp)); - else resolve(resp); - } - that._module.import_multisig_hex(that._cppAddress, JSON.stringify({multisigHexes: multisigHexes}), callbackFn); - }); - }); - } - - async signMultisigTxHex(multisigTxHex) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new MoneroMultisigSignResult(JSON.parse(that._module.sign_multisig_tx_hex(that._cppAddress, multisigTxHex))); - }); - } - - async submitMultisigTxHex(signedMultisigTxHex) { - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - return new Promise(function(resolve, reject) { - let callbackFn = function(resp) { resolve(JSON.parse(resp).txHashes); } - that._module.submit_multisig_tx_hex(that._cppAddress, signedMultisigTxHex, callbackFn); - }); - }); - } - - /** - * Get the wallet's keys and cache data. - * - * @return {DataView[]} is the keys and cache data respectively - */ - async getData() { - this._assertNotClosed(); - - // queue call to wasm module - let viewOnly = await this.isViewOnly(); - let that = this; - return that._module.queueTask(async function() { - that._assertNotClosed(); - - // store views in array - let views = []; - - // malloc cache buffer and get buffer location in c++ heap - let cacheBufferLoc = JSON.parse(that._module.get_cache_file_buffer(that._cppAddress, that._password)); - - // read binary data from heap to DataView - let view = new DataView(new ArrayBuffer(cacheBufferLoc.length)); - for (let i = 0; i < cacheBufferLoc.length; i++) { - view.setInt8(i, that._module.HEAPU8[cacheBufferLoc.pointer / Uint8Array.BYTES_PER_ELEMENT + i]); - } - - // free binary on heap - that._module._free(cacheBufferLoc.pointer); - - // write cache file - views.push(Buffer.from(view.buffer)); - - // malloc keys buffer and get buffer location in c++ heap - let keysBufferLoc = JSON.parse(that._module.get_keys_file_buffer(that._cppAddress, that._password, viewOnly)); - - // read binary data from heap to DataView - view = new DataView(new ArrayBuffer(keysBufferLoc.length)); - for (let i = 0; i < keysBufferLoc.length; i++) { - view.setInt8(i, that._module.HEAPU8[keysBufferLoc.pointer / Uint8Array.BYTES_PER_ELEMENT + i]); - } - - // free binary on heap - that._module._free(keysBufferLoc.pointer); - - // prepend keys file - views.unshift(Buffer.from(view.buffer)); - return views; - }); - } - - async save() { - this._assertNotClosed(); - - // path must be set - let path = await this.getPath(); - if (!path) throw new MoneroError("Cannot save wallet because path is not set"); - - // write address file - this._fs.writeFileSync(path + ".address.txt", await this.getPrimaryAddress()); - - // write keys and cache data - let data = await this.getData(); - this._fs.writeFileSync(path + ".keys", data[0], "binary"); - this._fs.writeFileSync(path, data[1], "binary"); - } - - async close(save) { - if (this._isClosed) return; // no effect if closed - this._syncingEnabled = false; - await this._setIsListening(false); - await this.stopSyncing(); - await super.close(save); - delete this._path; - delete this._password; - delete this._listeners; - delete this._wasmListener; - LibraryUtils.setRejectUnauthorizedFn(this._rejectUnauthorizedConfigId, undefined); // unregister fn informing if unauthorized reqs should be rejected - } - - // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS -------------- - - async getTx() { return super.getTx(...arguments); } - async getIncomingTransfers() { return super.getIncomingTransfers(...arguments); } - async getOutgoingTransfers() { return super.getOutgoingTransfers(...arguments); } - async createTx() { return super.createTx(...arguments); } - async relayTx() { return super.relayTx(...arguments); } - async getTxNote() { return super.getTxNote(...arguments); } - async setTxNote() { return super.setTxNote(...arguments); } - - // ---------------------------- PRIVATE HELPERS ---------------------------- - - static _getFs() { - if (!MoneroWalletWasm.FS) MoneroWalletWasm.FS = GenUtils.isBrowser() ? undefined : require('fs'); - return MoneroWalletWasm.FS; - } - - static async _openWalletData(path, password, networkType, keysData, cacheData, daemonUriOrConnection, proxyToWorker, fs) { - if (proxyToWorker) return MoneroWalletWasmProxy.openWalletData(path, password, networkType, keysData, cacheData, daemonUriOrConnection, fs); - - // validate and normalize parameters - assert(password, "Must provide a password to open the wallet"); - if (networkType === undefined) throw new MoneroError("Must provide the wallet's network type"); - MoneroNetworkType.validate(networkType); - let daemonConnection = typeof daemonUriOrConnection === "string" ? new MoneroRpcConnection(daemonUriOrConnection) : daemonUriOrConnection; - let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : ""; - let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : ""; - let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : ""; - let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true; - - // load wasm module - let module = await LibraryUtils.loadCoreModule(); - - // open wallet in queue - return module.queueTask(async function() { - return new Promise(function(resolve, reject) { - - // register fn informing if unauthorized reqs should be rejected - let rejectUnauthorizedFnId = GenUtils.getUUID(); - LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, function() { return rejectUnauthorized }); - - // define callback for wasm - let callbackFn = async function(cppAddress) { - if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); - else resolve(new MoneroWalletWasm(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId)); - }; - - // create wallet in wasm and invoke callback when done - module.open_core_wallet(password, networkType, keysData, cacheData, daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, callbackFn); - }); - }); - } - - /** - * Loop while syncing enabled. - */ - async _runSyncLoop() { - if (this._syncLoopRunning) return; // only run one loop at a time - this._syncLoopRunning = true; - - // sync while enabled - let label = this._path ? this._path : (this._browserMainPath ? this._browserMainPath : "in-memory wallet"); // label for log - while (this._syncingEnabled) { - try { - console.log("Background synchronizing " + label); - await this.sync(); - } catch (e) { - if (!this._isClosed) console.log("Failed to background synchronize " + label + ": " + e.message); - } - - // only wait if syncing still enabled - if (this._syncingEnabled) await new Promise(function(resolve) { setTimeout(resolve, MoneroUtils.WALLET_REFRESH_RATE); }); - } - - this._syncLoopRunning = false; - } - - /** - * Enables or disables listening in the c++ wallet. - */ - async _setIsListening(isEnabled) { - let that = this; - return that._module.queueTask(async function() { - if (isEnabled) { - that._wasmListenerHandle = that._module.set_listener( - that._cppAddress, - that._wasmListenerHandle, - function(height, startHeight, endHeight, percentDone, message) { that._wasmListener.onSyncProgress(height, startHeight, endHeight, percentDone, message); }, - function(height) { that._wasmListener.onNewBlock(height); }, - function(newBalanceStr, newUnlockedBalanceStr) { that._wasmListener.onBalancesChanged(newBalanceStr, newUnlockedBalanceStr); }, - function(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockHeight, isLocked) { that._wasmListener.onOutputReceived(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockHeight, isLocked); }, - function(height, txHash, amountStr, accountIdx, subaddressIdx, version) { that._wasmListener.onOutputSpent(height, txHash, amountStr, accountIdx, subaddressIdx, version); }); - } else { - that._wasmListenerHandle = that._module.set_listener(that._cppAddress, that._wasmListenerHandle, undefined, undefined, undefined, undefined, undefined); - } - }); - } - - static _sanitizeBlock(block) { - for (let tx of block.getTxs()) MoneroWalletWasm._sanitizeTxWallet(tx); - return block; - } - - static _sanitizeTxWallet(tx) { - assert(tx instanceof MoneroTxWallet); - return tx; - } - - static _sanitizeAccount(account) { - if (account.getSubaddresses()) { - for (let subaddress of account.getSubaddresses()) MoneroWalletWasm._sanitizeSubaddress(subaddress); - } - return account; - } - - static _sanitizeSubaddress(subaddress) { - if (subaddress.getLabel() === "") subaddress.setLabel(undefined); - return subaddress - } - - static _deserializeBlocks(blocksJsonStr) { - let blocksJson = JSON.parse(GenUtils.stringifyBIs(blocksJsonStr)); - let deserializedBlocks = {}; - deserializedBlocks.blocks = []; - deserializedBlocks.missingTxHashes = []; - if (blocksJson.blocks) for (let blockJson of blocksJson.blocks) deserializedBlocks.blocks.push(MoneroWalletWasm._sanitizeBlock(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET))); - if (blocksJson.missingTxHashes) for (let missingTxHash of blocksJson.missingTxHashes) deserializedBlocks.missingTxHashes.push(missingTxHash); - return deserializedBlocks; - } - - static _deserializeTxs(query, blocksJsonStr, missingTxHashes) { - - // deserialize blocks - let deserializedBlocks = MoneroWalletWasm._deserializeBlocks(blocksJsonStr); - if (missingTxHashes === undefined && deserializedBlocks.missingTxHashes.length > 0) throw new MoneroError("Wallet missing requested tx hashes: " + deserializedBlocks.missingTxHashes); - for (let missingTxHash of deserializedBlocks.missingTxHashes) missingTxHashes.push(missingTxHash); - let blocks = deserializedBlocks.blocks; - - // collect txs - let txs = []; - for (let block of blocks) { - MoneroWalletWasm._sanitizeBlock(block); - for (let tx of block.getTxs()) { - if (block.getHeight() === undefined) tx.setBlock(undefined); // dereference placeholder block for unconfirmed txs - txs.push(tx); - } - } - - // re-sort txs which is lost over wasm serialization // TODO: confirm that order is lost - if (query.getHashes() !== undefined) { - let txMap = new Map(); - for (let tx of txs) txMap[tx.getHash()] = tx; - let txsSorted = []; - for (let txHash of query.getHashes()) if (txMap[txHash] !== undefined) txsSorted.push(txMap[txHash]); - txs = txsSorted; - } - - return txs; - } - - static _deserializeTransfers(query, blocksJsonStr) { - - // deserialize blocks - let deserializedBlocks = MoneroWalletWasm._deserializeBlocks(blocksJsonStr); - if (deserializedBlocks.missingTxHashes.length > 0) throw new MoneroError("Wallet missing requested tx hashes: " + deserializedBlocks.missingTxHashes); - let blocks = deserializedBlocks.blocks; - - // collect transfers - let transfers = []; - for (let block of blocks) { - for (let tx of block.getTxs()) { - if (block.getHeight() === undefined) tx.setBlock(undefined); // dereference placeholder block for unconfirmed txs - if (tx.getOutgoingTransfer() !== undefined) transfers.push(tx.getOutgoingTransfer()); - if (tx.getIncomingTransfers() !== undefined) { - for (let transfer of tx.getIncomingTransfers()) transfers.push(transfer); - } - } - } - - return transfers; - } - - static _deserializeOutputs(query, blocksJsonStr) { - - // deserialize blocks - let deserializedBlocks = MoneroWalletWasm._deserializeBlocks(blocksJsonStr); - if (deserializedBlocks.missingTxHashes.length > 0) throw new MoneroError("Wallet missing requested tx hashes: " + deserializedBlocks.missingTxHashes); - let blocks = deserializedBlocks.blocks; - - // collect outputs - let outputs = []; - for (let block of blocks) { - for (let tx of block.getTxs()) { - for (let output of tx.getOutputs()) outputs.push(output); - } - } - - return outputs; - } - - /** - * Set the path of the wallet on the browser main thread if run as a web worker. - * - * @param {string} browserMainPath - path of the wallet on the browser main thread - */ - _setBrowserMainPath(browserMainPath) { - this._browserMainPath = browserMainPath; - } -} - -// ------------------------------- LISTENERS -------------------------------- - -/** - * Receives notifications directly from wasm c++. - * - * @private - */ -class WalletWasmListener { - - constructor(wallet) { - this._wallet = wallet; - } - - onSyncProgress(height, startHeight, endHeight, percentDone, message) { - for (let listener of this._wallet.getListeners()) { - listener.onSyncProgress(height, startHeight, endHeight, percentDone, message); - } - } - - onNewBlock(height) { - for (let listener of this._wallet.getListeners()) listener.onNewBlock(height); - } - - onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) { - for (let listener of this._wallet.getListeners()) listener.onBalancesChanged(BigInteger.parse(newBalanceStr), BigInteger.parse(newUnlockedBalanceStr)); - } - - onOutputReceived(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockHeight, isLocked) { - - // build received output - let output = new MoneroOutputWallet(); - output.setAmount(BigInteger.parse(amountStr)); - output.setAccountIndex(accountIdx); - output.setSubaddressIndex(subaddressIdx); - let tx = new MoneroTxWallet(); - tx.setHash(txHash); - tx.setVersion(version); - tx.setUnlockHeight(unlockHeight); - output.setTx(tx); - tx.setOutputs([output]); - tx.setIsIncoming(true); - tx.setIsLocked(isLocked); - if (height > 0) { - let block = new MoneroBlock().setHeight(height); - block.setTxs([tx]); - tx.setBlock(block); - tx.setIsConfirmed(true); - tx.setInTxPool(false); - tx.setIsFailed(false); - } else { - tx.setIsConfirmed(false); - tx.setInTxPool(true); - } - - // announce output - for (let listener of this._wallet.getListeners()) listener.onOutputReceived(tx.getOutputs()[0]); - } - - onOutputSpent(height, txHash, amountStr, accountIdx, subaddressIdx, version) { - - // build spent output - let output = new MoneroOutputWallet(); - output.setAmount(BigInteger.parse(amountStr)); - output.setAccountIndex(accountIdx); - output.setSubaddressIndex(subaddressIdx); - let tx = new MoneroTxWallet(); - tx.setHash(txHash); - tx.setVersion(version); - output.setTx(tx); - tx.setInputs([output]); - if (height > 0) { - let block = new MoneroBlock().setHeight(height); - block.setTxs([tx]); - tx.setBlock(block); - tx.setIsConfirmed(true); - tx.setInTxPool(false); - tx.setIsFailed(false); - } else { - tx.setIsConfirmed(false); - tx.setInTxPool(true); - } - - // notify wallet listeners - for (let listener of this._wallet.getListeners()) listener.onOutputSpent(tx.getInputs()[0]); - } -} - -/** - * Wraps a sync listener as a general wallet listener. - * - * @private - */ -class SyncListenerWrapper extends MoneroWalletListener { - - constructor(listener) { - super(); - this._listener = listener; - } - - onSyncProgress(height, startHeight, endHeight, percentDone, message) { - this._listener.onSyncProgress(height, startHeight, endHeight, percentDone, message); - } -} - -/** - * Implements a MoneroWallet by proxying requests to a web worker which runs a core wallet. - * - * TODO: sort these methods according to master sort in MoneroWallet.js - * TODO: probably only allow one listener to web worker then propogate to registered listeners for performance - * TODO: ability to recycle worker for use in another wallet - * TODO: using LibraryUtils.WORKER_OBJECTS directly breaks encapsulation - * - * @private - */ -class MoneroWalletWasmProxy extends MoneroWallet { - - // -------------------------- WALLET STATIC UTILS --------------------------- - - static async openWalletData(path, password, networkType, keysData, cacheData, daemonUriOrConnection, fs) { - let walletId = GenUtils.getUUID(); - let daemonUriOrConfig = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection.getConfig() : daemonUriOrConnection; - await LibraryUtils.invokeWorker(walletId, "openWalletData", [path, password, networkType, keysData, cacheData, daemonUriOrConfig]); - let wallet = new MoneroWalletWasmProxy(walletId, LibraryUtils.getWorker(), path, fs); - if (path) await wallet.save(); - return wallet; - } - - static async _createWalletRandom(path, password, networkType, daemonUriOrConnection, language, fs) { - if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error("Wallet already exists: " + path); - let walletId = GenUtils.getUUID(); - let daemonUriOrConfig = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection.getConfig() : daemonUriOrConnection; - await LibraryUtils.invokeWorker(walletId, "_createWalletRandom", [path, password, networkType, daemonUriOrConfig, language]); - let wallet = new MoneroWalletWasmProxy(walletId, LibraryUtils.getWorker(), path, fs); - if (path) await wallet.save(); - return wallet; - } - - static async _createWalletFromMnemonic(path, password, networkType, mnemonic, daemonUriOrConnection, restoreHeight, seedOffset, fs) { - if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error("Wallet already exists: " + path); - let walletId = GenUtils.getUUID(); - let daemonUriOrConfig = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection.getConfig() : daemonUriOrConnection; - await LibraryUtils.invokeWorker(walletId, "_createWalletFromMnemonic", [path, password, networkType, mnemonic, daemonUriOrConfig, restoreHeight, seedOffset]); - let wallet = new MoneroWalletWasmProxy(walletId, LibraryUtils.getWorker(), path, fs); - if (path) await wallet.save(); - return wallet; - } - - static async _createWalletFromKeys(path, password, networkType, address, viewKey, spendKey, daemonUriOrConnection, restoreHeight, language, fs) { - if (path && await MoneroWalletWasm.walletExists(path, fs)) throw new Error("Wallet already exists: " + path); - let walletId = GenUtils.getUUID(); - let daemonUriOrConfig = daemonUriOrConnection instanceof MoneroRpcConnection ? daemonUriOrConnection.getConfig() : daemonUriOrConnection; - await LibraryUtils.invokeWorker(walletId, "_createWalletFromKeys", [path, password, networkType, address, viewKey, spendKey, daemonUriOrConfig, restoreHeight, language]); - let wallet = new MoneroWalletWasmProxy(walletId, LibraryUtils.getWorker(), path, fs); - if (path) await wallet.save(); - return wallet; - } - - // --------------------------- INSTANCE METHODS ---------------------------- - - /** - * Internal constructor which is given a worker to communicate with via messages. - * - * This method should not be called externally but should be called through - * static wallet creation utilities in this class. - * - * @param {string} walletId - identifies the wallet with the worker - * @param {Worker} worker - web worker to communicate with via messages - */ - constructor(walletId, worker, path, fs) { - super(); - this._walletId = walletId; - this._worker = worker; - this._path = path; - this._fs = fs ? fs : (path ? MoneroWalletWasm._getFs() : undefined); - this._wrappedListeners = []; - } - - async isViewOnly() { - return this._invokeWorker("isViewOnly"); - } - - async getNetworkType() { - return this._invokeWorker("getNetworkType"); - } - - async getVersion() { - throw new Error("Not implemented"); - } - - getPath() { - return this._path; - } - - async getMnemonic() { - return this._invokeWorker("getMnemonic"); - } - - async getMnemonicLanguage() { - return this._invokeWorker("getMnemonicLanguage"); - } - - async getMnemonicLanguages() { - return this._invokeWorker("getMnemonicLanguages"); - } - - async getPrivateSpendKey() { - return this._invokeWorker("getPrivateSpendKey"); - } - - async getPrivateViewKey() { - return this._invokeWorker("getPrivateViewKey"); - } - - async getPublicViewKey() { - return this._invokeWorker("getPublicViewKey"); - } - - async getPublicSpendKey() { - return this._invokeWorker("getPublicSpendKey"); - } - - async getAddress(accountIdx, subaddressIdx) { - return this._invokeWorker("getAddress", Array.from(arguments)); - } - - async getAddressIndex(address) { - let subaddressJson = await this._invokeWorker("getAddressIndex", Array.from(arguments)); - return MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson)); - } - - async getIntegratedAddress(paymentId) { - return new MoneroIntegratedAddress(await this._invokeWorker("getIntegratedAddress", Array.from(arguments))); - } - - async decodeIntegratedAddress(integratedAddress) { - return new MoneroIntegratedAddress(await this._invokeWorker("decodeIntegratedAddress", Array.from(arguments))); - } - - async setDaemonConnection(uriOrRpcConnection, username, password) { - if (!uriOrRpcConnection) await this._invokeWorker("setDaemonConnection"); - else { - let connection = uriOrRpcConnection instanceof MoneroRpcConnection? uriOrRpcConnection : new MoneroRpcConnection({uri: uriOrRpcConnection, username: username, password: password}); - await this._invokeWorker("setDaemonConnection", connection.getConfig()); - } - } - - async getDaemonConnection() { - let rpcConfig = await this._invokeWorker("getDaemonConnection"); - return rpcConfig ? new MoneroRpcConnection(rpcConfig) : undefined; - } - - async isConnected() { - return this._invokeWorker("isConnected"); - } - - async getSyncHeight() { - return this._invokeWorker("getSyncHeight"); - } - - async setSyncHeight(syncHeight) { - return this._invokeWorker("setSyncHeight", [syncHeight]); - } - - async getDaemonHeight() { - return this._invokeWorker("getDaemonHeight"); - } - - async getDaemonMaxPeerHeight() { - return this._invokeWorker("getDaemonMaxPeerHeight"); - } - - async getHeightByDate(year, month, day) { - return this._invokeWorker("getHeightByDate", [year, month, day]); - } - - async isDaemonSynced() { - return this._invokeWorker("isDaemonSynced"); - } - - async getHeight() { - return this._invokeWorker("getHeight"); - } - - async addListener(listener) { - let wrappedListener = new WalletWorkerListener(listener); - let listenerId = wrappedListener.getId(); - LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onSyncProgress_" + listenerId] = [wrappedListener.onSyncProgress, wrappedListener]; - LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onNewBlock_" + listenerId] = [wrappedListener.onNewBlock, wrappedListener]; - LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onBalancesChanged_" + listenerId] = [wrappedListener.onBalancesChanged, wrappedListener]; - LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onOutputReceived_" + listenerId] = [wrappedListener.onOutputReceived, wrappedListener]; - LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onOutputSpent_" + listenerId] = [wrappedListener.onOutputSpent, wrappedListener]; - this._wrappedListeners.push(wrappedListener); - return this._invokeWorker("addListener", [listenerId]); - } - - async removeListener(listener) { - for (let i = 0; i < this._wrappedListeners.length; i++) { - if (this._wrappedListeners[i].getListener() === listener) { - let listenerId = this._wrappedListeners[i].getId(); - await this._invokeWorker("removeListener", [listenerId]); - delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onSyncProgress_" + listenerId]; - delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onNewBlock_" + listenerId]; - delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onBalancesChanged_" + listenerId]; - delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onOutputReceived_" + listenerId]; - delete LibraryUtils.WORKER_OBJECTS[this._walletId].callbacks["onOutputSpent_" + listenerId]; - this._wrappedListeners.splice(i, 1); - return; - } - } - throw new MoneroError("Listener is not registered with wallet"); - } - - getListeners() { - let listeners = []; - for (let wrappedListener of this._wrappedListeners) listeners.push(wrappedListener.getListener()); - return listeners; - } - - async isSynced() { - return this._invokeWorker("isSynced"); - } - - async sync(listenerOrStartHeight, startHeight) { - - // normalize params - startHeight = listenerOrStartHeight instanceof MoneroWalletListener ? startHeight : listenerOrStartHeight; - let listener = listenerOrStartHeight instanceof MoneroWalletListener ? listenerOrStartHeight : undefined; - if (startHeight === undefined) startHeight = Math.max(await this.getHeight(), await this.getSyncHeight()); - - // register listener if given - if (listener) await this.addListener(listener); - - // sync wallet in worker - let err; - let result; - try { - let resultJson = await this._invokeWorker("sync", [startHeight]); - result = new MoneroSyncResult(resultJson.numBlocksFetched, resultJson.receivedMoney); - } catch (e) { - err = e; - } - - // unregister listener - if (listener) await this.removeListener(listener); - - // throw error or return - if (err) throw err; - return result; - } - - async startSyncing() { - return this._invokeWorker("startSyncing"); - } - - async stopSyncing() { - return this._invokeWorker("stopSyncing"); - } - - async rescanSpent() { - return this._invokeWorker("rescanSpent"); - } - - async rescanBlockchain() { - return this._invokeWorker("rescanBlockchain"); - } - - async getBalance(accountIdx, subaddressIdx) { - return BigInteger.parse(await this._invokeWorker("getBalance", Array.from(arguments))); - } - - async getUnlockedBalance(accountIdx, subaddressIdx) { - let unlockedBalanceStr = await this._invokeWorker("getUnlockedBalance", Array.from(arguments)); - return BigInteger.parse(unlockedBalanceStr); - } - - async getAccounts(includeSubaddresses, tag) { - let accounts = []; - for (let accountJson of (await this._invokeWorker("getAccounts", Array.from(arguments)))) { - accounts.push(MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson))); - } - return accounts; - } - - async getAccount(accountIdx, includeSubaddresses) { - let accountJson = await this._invokeWorker("getAccount", Array.from(arguments)); - return MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson)); - } - - async createAccount(label) { - let accountJson = await this._invokeWorker("createAccount", Array.from(arguments)); - return MoneroWalletWasm._sanitizeAccount(new MoneroAccount(accountJson)); - } - - async getSubaddresses(accountIdx, subaddressIndices) { - let subaddresses = []; - for (let subaddressJson of (await this._invokeWorker("getSubaddresses", Array.from(arguments)))) { - subaddresses.push(MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson))); - } - return subaddresses; - } - - async createSubaddress(accountIdx, label) { - let subaddressJson = await this._invokeWorker("createSubaddress", Array.from(arguments)); - return MoneroWalletWasm._sanitizeSubaddress(new MoneroSubaddress(subaddressJson)); - } - - async getTxs(query, missingTxHashes) { - query = MoneroWallet._normalizeTxQuery(query); - let blockJsons = await this._invokeWorker("getTxs", [query.getBlock().toJson()]); - return MoneroWalletWasm._deserializeTxs(query, JSON.stringify({blocks: blockJsons}), missingTxHashes); // initialize txs from blocks json string TODO: this stringifies then utility parses, avoid - } - - async getTransfers(query) { - query = MoneroWallet._normalizeTransferQuery(query); - let blockJsons = await this._invokeWorker("getTransfers", [query.getTxQuery().getBlock().toJson()]); - return MoneroWalletWasm._deserializeTransfers(query, JSON.stringify({blocks: blockJsons})); // initialize transfers from blocks json string TODO: this stringifies then utility parses, avoid - } - - async getOutputs(query) { - query = MoneroWallet._normalizeOutputQuery(query); - let blockJsons = await this._invokeWorker("getOutputs", [query.getTxQuery().getBlock().toJson()]); - return MoneroWalletWasm._deserializeOutputs(query, JSON.stringify({blocks: blockJsons})); // initialize transfers from blocks json string TODO: this stringifies then utility parses, avoid - } - - async getOutputsHex() { - return this._invokeWorker("getOutputsHex"); - } - - async importOutputsHex(outputsHex) { - return this._invokeWorker("importOutputsHex", [outputsHex]); - } - - async getKeyImages() { - let keyImages = []; - for (let keyImageJson of await this._invokeWorker("getKeyImages")) keyImages.push(new MoneroKeyImage(keyImageJson)); - return keyImages; - } - - async importKeyImages(keyImages) { - let keyImagesJson = []; - for (let keyImage of keyImages) keyImagesJson.push(keyImage.toJson()); - return new MoneroKeyImageImportResult(await this._invokeWorker("importKeyImages", [keyImagesJson])); - } - - async getNewKeyImagesFromLastImport() { - throw new MoneroError("MoneroWalletWasm.getNewKeyImagesFromLastImport() not implemented"); - } - - async createTxs(config) { - config = MoneroWallet._normalizeCreateTxsConfig(config); - let txSetJson = await this._invokeWorker("createTxs", [config.toJson()]); - return new MoneroTxSet(txSetJson).getTxs(); - } - - async sweepOutput(config) { - config = MoneroWallet._normalizeSweepOutputConfig(config); - let txSetJson = await this._invokeWorker("sweepOutput", [config.toJson()]); - return new MoneroTxSet(txSetJson).getTxs()[0]; - } - - async sweepUnlocked(config) { - config = MoneroWallet._normalizeSweepUnlockedConfig(config); - let txSetsJson = await this._invokeWorker("sweepUnlocked", [config.toJson()]); - let txs = []; - for (let txSetJson of txSetsJson) for (let tx of new MoneroTxSet(txSetJson).getTxs()) txs.push(tx); - return txs; - } - - async sweepDust(relay) { - return new MoneroTxSet(await this._invokeWorker("sweepDust", [relay])).getTxs(); - } - - async relayTxs(txsOrMetadatas) { - assert(Array.isArray(txsOrMetadatas), "Must provide an array of txs or their metadata to relay"); - let txMetadatas = []; - for (let txOrMetadata of txsOrMetadatas) txMetadatas.push(txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata); - return this._invokeWorker("relayTxs", [txMetadatas]); - } - - async parseTxSet(txSet) { - return new MoneroTxSet(await this._invokeWorker("parseTxSet", [txSet.toJson()])); - } - - async signTxs(unsignedTxHex) { - return this._invokeWorker("signTxs", Array.from(arguments)); - } - - async submitTxs(signedTxHex) { - return this._invokeWorker("submitTxs", Array.from(arguments)); - } - - async signMessage(message) { - return this._invokeWorker("signMessage", Array.from(arguments)); - } - - async verifyMessage(message, address, signature) { - return this._invokeWorker("verifyMessage", Array.from(arguments)); - } - - async getTxKey(txHash) { - return this._invokeWorker("getTxKey", Array.from(arguments)); - } - - async checkTxKey(txHash, txKey, address) { - return new MoneroCheckTx(await this._invokeWorker("checkTxKey", Array.from(arguments))); - } - - async getTxProof(txHash, address, message) { - return this._invokeWorker("getTxProof", Array.from(arguments)); - } - - async checkTxProof(txHash, address, message, signature) { - return new MoneroCheckTx(await this._invokeWorker("checkTxProof", Array.from(arguments))); - } - - async getSpendProof(txHash, message) { - return this._invokeWorker("getSpendProof", Array.from(arguments)); - } - - async checkSpendProof(txHash, message, signature) { - return this._invokeWorker("checkSpendProof", Array.from(arguments)); - } - - async getReserveProofWallet(message) { - return this._invokeWorker("getReserveProofWallet", Array.from(arguments)); - } - - async getReserveProofAccount(accountIdx, amount, message) { - return this._invokeWorker("getReserveProofAccount", Array.from(arguments)); - } - - async checkReserveProof(address, message, signature) { - return new MoneroCheckReserve(await this._invokeWorker("checkReserveProof", Array.from(arguments))); - } - - async getTxNotes(txHashes) { - return this._invokeWorker("getTxNotes", Array.from(arguments)); - } - - async setTxNotes(txHashes, notes) { - return this._invokeWorker("setTxNotes", Array.from(arguments)); - } - - async getAddressBookEntries(entryIndices) { - if (!entryIndices) entryIndices = []; - let entries = []; - for (let entryJson of await this._invokeWorker("getAddressBookEntries", Array.from(arguments))) { - entries.push(new MoneroAddressBookEntry(entryJson)); - } - return entries; - } - - async addAddressBookEntry(address, description) { - return this._invokeWorker("addAddressBookEntry", Array.from(arguments)); - } - - async editAddressBookEntry(index, setAddress, address, setDescription, description) { - return this._invokeWorker("editAddressBookEntry", Array.from(arguments)); - } - - async deleteAddressBookEntry(entryIdx) { - return this._invokeWorker("deleteAddressBookEntry", Array.from(arguments)); - } - - async tagAccounts(tag, accountIndices) { - return this._invokeWorker("tagAccounts", Array.from(arguments)); - } - - async untagAccounts(accountIndices) { - return this._invokeWorker("untagAccounts", Array.from(arguments)); - } - - async getAccountTags() { - return this._invokeWorker("getAccountTags", Array.from(arguments)); - } - - async setAccountTagLabel(tag, label) { - return this._invokeWorker("setAccountTagLabel", Array.from(arguments)); - } - - async createPaymentUri(config) { - config = MoneroWallet._normalizeCreateTxsConfig(config); - return this._invokeWorker("createPaymentUri", [config.toJson()]); - } - - async parsePaymentUri(uri) { - return new MoneroTxConfig(await this._invokeWorker("parsePaymentUri", Array.from(arguments))); - } - - async getAttribute(key) { - return this._invokeWorker("getAttribute", Array.from(arguments)); - } - - async setAttribute(key, val) { - return this._invokeWorker("setAttribute", Array.from(arguments)); - } - - async startMining(numThreads, backgroundMining, ignoreBattery) { - return this._invokeWorker("startMining", Array.from(arguments)); - } - - async stopMining() { - return this._invokeWorker("stopMining", Array.from(arguments)); - } - - async isMultisigImportNeeded() { - return this._invokeWorker("isMultisigImportNeeded"); - } - - async isMultisig() { - return this._invokeWorker("isMultisig"); - } - - async getMultisigInfo() { - return new MoneroMultisigInfo(await this._invokeWorker("getMultisigInfo")); - } - - async prepareMultisig() { - return this._invokeWorker("prepareMultisig"); - } - - async makeMultisig(multisigHexes, threshold, password) { - return new MoneroMultisigInitResult(await this._invokeWorker("makeMultisig", Array.from(arguments))); - } - - async exchangeMultisigKeys(multisigHexes, password) { - return new MoneroMultisigInitResult(await this._invokeWorker("exchangeMultisigKeys", Array.from(arguments))); - } - - async getMultisigHex() { - return this._invokeWorker("getMultisigHex"); - } - - async importMultisigHex(multisigHexes) { - return this._invokeWorker("importMultisigHex", Array.from(arguments)); - } - - async signMultisigTxHex(multisigTxHex) { - return new MoneroMultisigSignResult(await this._invokeWorker("signMultisigTxHex", Array.from(arguments))); - } - - async submitMultisigTxHex(signedMultisigTxHex) { - return this._invokeWorker("submitMultisigTxHex", Array.from(arguments)); - } - - async getData() { - return this._invokeWorker("getData"); - } - - async moveTo(path, password) { - throw new Error("MoneroWalletWasmProxy.moveTo() not implemented"); - } - - // TODO: factor this duplicate code with MoneroWalletWasm save(), common util - async save() { - assert(!await this.isClosed(), "Wallet is closed"); - - // path must be set - let path = await this.getPath(); - if (!path) throw new MoneroError("Cannot save wallet because path is not set"); - - // write address file - this._fs.writeFileSync(path + ".address.txt", await this.getPrimaryAddress()); - - // write keys and cache data - let data = await this.getData(); - this._fs.writeFileSync(path + ".keys", data[0], "binary"); - this._fs.writeFileSync(path, data[1], "binary"); - } - - async close(save) { - if (save) await this.save(); - while (this._wrappedListeners.length) await this.removeListener(this._wrappedListeners[0].getListener()); - await this._invokeWorker("close"); - delete LibraryUtils.WORKER_OBJECTS[this._walletId]; - } - - async isClosed() { - return this._invokeWorker("isClosed"); - } - - // --------------------------- PRIVATE HELPERS ------------------------------ - - async _invokeWorker(fnName, args) { - return LibraryUtils.invokeWorker(this._walletId, fnName, args); - } -} - -/** - * Internal listener to bridge notifications to external listeners. - * - * @private - */ -class WalletWorkerListener { - - constructor(listener) { - this._id = GenUtils.getUUID(); - this._listener = listener; - } - - getId() { - return this._id; - } - - getListener() { - return this._listener; - } - - onSyncProgress(height, startHeight, endHeight, percentDone, message) { - this._listener.onSyncProgress(height, startHeight, endHeight, percentDone, message); - } - - onNewBlock(height) { - this._listener.onNewBlock(height); - } - - onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) { - this._listener.onBalancesChanged(BigInteger.parse(newBalanceStr), BigInteger.parse(newUnlockedBalanceStr)); - } - - onOutputReceived(blockJson) { - let block = new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET); - this._listener.onOutputReceived(block.getTxs()[0].getOutputs()[0]); - } - - onOutputSpent(blockJson) { - let block = new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET); - this._listener.onOutputSpent(block.getTxs()[0].getInputs()[0]); - } -} - -module.exports = MoneroWalletWasm; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroAccount.js b/src/main/js/wallet/model/MoneroAccount.js deleted file mode 100644 index 253d704cd..000000000 --- a/src/main/js/wallet/model/MoneroAccount.js +++ /dev/null @@ -1,131 +0,0 @@ -const assert = require("assert"); -const BigInteger = require("../../common/biginteger").BigInteger; -const MoneroSubaddress = require("./MoneroSubaddress"); - -/** - * Monero account model. - */ -class MoneroAccount { - - constructor(stateOrIndex, primaryAddress, balance, unlockedBalance, subaddresses) { - - // construct from json - if (typeof stateOrIndex === "object") { - this.state = stateOrIndex; - - // deserialize balances - if (this.state.balance !== undefined && !(this.state.balance instanceof BigInteger)) this.state.balance = BigInteger.parse(this.state.balance); - if (this.state.unlockedBalance !== undefined && !(this.state.unlockedBalance instanceof BigInteger)) this.state.unlockedBalance = BigInteger.parse(this.state.unlockedBalance); - - // deserialize subaddresses - if (this.state.subaddresses) { - for (let i = 0; i < this.state.subaddresses.length; i++) { - if (!(this.state.subaddresses[i] instanceof MoneroSubaddress)) { - this.state.subaddresses[i] = new MoneroSubaddress(this.state.subaddresses[i]); - } - } - } - } - - // construct from individual params - else { - this.state = {}; - this.setIndex(stateOrIndex); - this.setPrimaryAddress(primaryAddress); - this.setBalance(balance); - this.setUnlockedBalance(unlockedBalance); - this.setSubaddresses(subaddresses); - } - } - - toJson() { - let json = Object.assign({}, this.state); - if (json.balance) json.balance = json.balance.toString(); - if (json.unlockedBalance) json.unlockedBalance = json.unlockedBalance.toString(); - if (json.subaddresses) { - for (let i = 0; i < json.subaddresses.length; i++) { - json.subaddresses[i] = json.subaddresses[i].toJson(); - } - } - return json; - } - - getIndex() { - return this.state.index; - } - - setIndex(index) { - this.state.index = index; - return this; - } - - getPrimaryAddress() { - return this.state.primaryAddress; - } - - setPrimaryAddress(primaryAddress) { - this.state.primaryAddress = primaryAddress; - return this; - } - - getBalance() { - return this.state.balance; - } - - setBalance(balance) { - this.state.balance = balance; - return this; - } - - getUnlockedBalance() { - return this.state.unlockedBalance; - } - - setUnlockedBalance(unlockedBalance) { - this.state.unlockedBalance = unlockedBalance; - return this; - } - - getTag() { - return this.state.tag; - } - - setTag(tag) { - this.state.tag = tag; - return this; - } - - getSubaddresses() { - return this.state.subaddresses; - } - - setSubaddresses(subaddresses) { - assert(subaddresses === undefined || Array.isArray(subaddresses), "Given subaddresses must be undefined or an array of subaddresses"); - this.state.subaddresses = subaddresses; - if (subaddresses) { - for (let subaddress of subaddresses) { - subaddress.setAccountIndex(this.state.index); - } - } - return this; - } - - toString(indent = 0) { - let str = ""; - str += GenUtils.kvLine("Index", this.getIndex(), indent); - str += GenUtils.kvLine("Primary address", this.getPrimaryAddress(), indent); - str += GenUtils.kvLine("Balance", this.getBalance(), indent); - str += GenUtils.kvLine("Unlocked balance", this.getUnlockedBalance(), indent); - str += GenUtils.kvLine("Tag", this.getTag(), indent); - if (this.getSubaddresses() != null) { - sb += GenUtils.kvLine("Subaddresses", "", indent) - for (let i = 0; i < this.getSubaddresses().size(); i++) { - str += GenUtils.kvLine(i + 1, "", indent + 1); - str += this.getSubaddresses()[i].toString(indent + 2) + "\n"; - } - } - return str.slice(0, str.length - 1); // strip last newline - } -} - -module.exports = MoneroAccount; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroAccountTag.js b/src/main/js/wallet/model/MoneroAccountTag.js deleted file mode 100644 index ca50ae452..000000000 --- a/src/main/js/wallet/model/MoneroAccountTag.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Represents an account tag. - */ -class MoneroAccountTag { - - constructor(tag, label, accountIndices) { - this.tag = tag; - this.label = label; - this.accountIndices = accountIndices; - } - - getTag() { - return this.tag; - } - - setTag(tag) { - this.tag = tag; - return this; - } - - getLabel() { - return this.label; - } - - setLabel(label) { - this.label = label; - return this; - } - - getAccountIndices() { - return this.accountIndices; - } - - setAccountIndices(accountIndices) { - this.accoutIndices = accountIndices; - return this; - } -} - -module.exports = MoneroAccountTag; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroAddressBookEntry.js b/src/main/js/wallet/model/MoneroAddressBookEntry.js deleted file mode 100644 index a3d943c96..000000000 --- a/src/main/js/wallet/model/MoneroAddressBookEntry.js +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Monero address book entry model - */ -class MoneroAddressBookEntry { - - constructor(state) { - this.state = Object.assign({}, state); - } - - toJson() { - return Object.assign({}, this.state); - } - - getIndex() { - return this.state.index; - } - - setIndex(index) { - this.state.index = index; - return this; - } - - getAddress() { - return this.state.address; - } - - setAddress(address) { - this.state.address = address; - return this; - } - - getDescription() { - return this.state.description; - } - - setDescription(description) { - this.state.description = description; - return this; - } - - getPaymentId() { - return this.state.paymentId; - } - - setPaymentId(paymentId) { - this.state.paymentId = paymentId; - return this; - } -} - -module.exports = MoneroAddressBookEntry; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroCheck.js b/src/main/js/wallet/model/MoneroCheck.js deleted file mode 100644 index 50a1139c1..000000000 --- a/src/main/js/wallet/model/MoneroCheck.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Base class for results from checking a transaction or reserve proof. - * - * @class - */ -class MoneroCheck { - - constructor(state) { - this.state = Object.assign({}, state); - } - - isGood() { - return this.state.isGood; - } - - setIsGood(isGood) { - this.state.isGood = isGood; - return this; - } -} - -module.exports = MoneroCheck; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroCheckReserve.js b/src/main/js/wallet/model/MoneroCheckReserve.js deleted file mode 100644 index 84465b1b9..000000000 --- a/src/main/js/wallet/model/MoneroCheckReserve.js +++ /dev/null @@ -1,43 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; -const MoneroCheck = require("./MoneroCheck"); - -/** - * Results from checking a reserve proof. - * - * @extends {MoneroCheck} - */ -class MoneroCheckReserve extends MoneroCheck { - - constructor(state) { - super(state); - if (this.state.totalAmount !== undefined && !(this.state.totalAmount instanceof BigInteger)) this.state.totalAmount = BigInteger.parse(this.state.totalAmount); - if (this.state.unconfirmedSpentAmount !== undefined && !(this.state.unconfirmedSpentAmount instanceof BigInteger)) this.state.unconfirmedSpentAmount = BigInteger.parse(this.state.unconfirmedSpentAmount); - } - - toJson() { - let json = Object.assign({}, this.state); - if (this.getTotalAmount()) json.totalAmount = this.getTotalAmount().toString(); - if (this.getUnconfirmedSpentAmount()) json.unconfirmedSpentAmount = this.getUnconfirmedSpentAmount().toString(); - return json; - } - - getTotalAmount() { - return this.state.totalAmount; - } - - setTotalAmount(totalAmount) { - this.state.totalAmount = totalAmount; - return this; - } - - getUnconfirmedSpentAmount() { - return this.state.unconfirmedSpentAmount; - } - - setUnconfirmedSpentAmount(unconfirmedSpentAmount) { - this.state.unconfirmedSpentAmount = unconfirmedSpentAmount; - return this; - } -} - -module.exports = MoneroCheckReserve; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroCheckTx.js b/src/main/js/wallet/model/MoneroCheckTx.js deleted file mode 100644 index 643dc0568..000000000 --- a/src/main/js/wallet/model/MoneroCheckTx.js +++ /dev/null @@ -1,50 +0,0 @@ -const MoneroCheck = require("./MoneroCheck"); -const BigInteger = require("../../common/biginteger").BigInteger; - -/** - * Results from checking a transaction key. - * - * @extends {MoneroCheck} - */ -class MoneroCheckTx extends MoneroCheck { - - constructor(state) { - super(state); - if (this.state.receivedAmount !== undefined && !(this.state.receivedAmount instanceof BigInteger)) this.state.receivedAmount = BigInteger.parse(this.state.receivedAmount); - } - - toJson() { - let json = Object.assign({}, state); - if (this.getReceivedAmount()) json.receivedAmount = this.getReceivedAmount().toString(); - return json; - } - - inTxPool() { - return this.state.inTxPool; - } - - setInTxPool(inTxPool) { - this.state.inTxPool = inTxPool; - return this; - } - - getNumConfirmations() { - return this.state.numConfirmations; - } - - setNumConfirmations(numConfirmations) { - this.state.numConfirmations = numConfirmations; - return this; - } - - getReceivedAmount() { - return this.state.receivedAmount; - } - - setReceivedAmount(receivedAmount) { - this.state.receivedAmount = receivedAmount; - return this; - } -} - -module.exports = MoneroCheckTx; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroDestination.js b/src/main/js/wallet/model/MoneroDestination.js deleted file mode 100644 index bdf17bbe8..000000000 --- a/src/main/js/wallet/model/MoneroDestination.js +++ /dev/null @@ -1,69 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; -const GenUtils = require("../../common/GenUtils"); - -/** - * Models an outgoing transfer destination. - */ -class MoneroDestination { - - /** - * Construct the model. - * - * @param {MoneroDestination|object|string} stateOrAddress is a MoneroDestination, JS object, or hex string to initialize from (optional) - * @param {BigInteger|string} amount - the destination amount - */ - constructor(stateOrAddress, amount) { - - // initialize internal state - if (!stateOrAddress) this.state = {}; - else if (stateOrAddress instanceof MoneroDestination) this.state = stateOrAddress.toJson(); - else if (typeof stateOrAddress === "object") this.state = Object.assign({}, stateOrAddress); - else if (typeof stateOrAddress === "string") { - this.state = {}; - this.setAddress(stateOrAddress); - this.setAmount(amount); - } else { - throw new MoneroError("stateOrAddress must be a MoneroDestination, JavaScript object, or hex string"); - } - - // deserialize amount - if (amount) this.state.amount = amount; - if (this.state.amount !== undefined && !(this.state.amount instanceof BigInteger)) this.state.amount = BigInteger.parse(this.state.amount); - } - - getAddress() { - return this.state.address; - } - - setAddress(address) { - this.state.address = address; - return this; - } - - getAmount() { - return this.state.amount; - } - - setAmount(amount) { - this.state.amount = amount; - return this; - } - - copy() { - return new MoneroDestination(this); - } - - toJson() { - let json = Object.assign({}, this.state); - if (this.getAmount()) json.amount = this.getAmount().toString(); - return json; - } - - toString(indent = 0) { - let str = GenUtils.kvLine("Address", this.getAddress(), indent); - str += GenUtils.kvLine("Amount", this.getAmount() ? this.getAmount().toString() : undefined, indent); - return str.slice(0, str.length - 1); // strip last newline - } -} - -module.exports = MoneroDestination; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroIntegratedAddress.js b/src/main/js/wallet/model/MoneroIntegratedAddress.js deleted file mode 100644 index 57fff0cce..000000000 --- a/src/main/js/wallet/model/MoneroIntegratedAddress.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Monero integrated address model. - */ -class MoneroIntegratedAddress { - - constructor(state) { - this.state = Object.assign({}, state); - } - - toJson() { - return Object.assign({}, this.state); - } - - getStandardAddress() { - return this.state.standardAddress; - } - - setStandardAddress(standardAddress) { - this.state.standardAddress = standardAddress; - return this; - } - - getPaymentId() { - return this.state.paymentId; - } - - setPaymentId(paymentId) { - this.state.paymentId = paymentId; - return this; - } - - getIntegratedAddress() { - return this.state.integratedAddress; - } - - setIntegratedAddress(integratedAddress) { - this.state.integratedAddress = integratedAddress; - return this; - } - - toString() { - return this.state.integratedAddress; - } -} - -module.exports = MoneroIntegratedAddress; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroKeyImageImportResult.js b/src/main/js/wallet/model/MoneroKeyImageImportResult.js deleted file mode 100644 index 64f8ad60b..000000000 --- a/src/main/js/wallet/model/MoneroKeyImageImportResult.js +++ /dev/null @@ -1,50 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; - -/** - * Models results from importing key images. - */ -class MoneroKeyImageImportResult { - - constructor(state) { - state = Object.assign({}, state); - if (state.spentAmount !== undefined && !(state.spentAmount instanceof BigInteger)) state.spentAmount = BigInteger.parse(state.spentAmount); - if (state.unspentAmount !== undefined && !(state.unspentAmount instanceof BigInteger)) state.unspentAmount = BigInteger.parse(state.unspentAmount); - this.state = state; - } - - toJson() { - let json = Object.assign({}, this.state); - if (this.getSpentAmount()) json.spentAmount = this.getSpentAmount().toString(); - if (this.getUnspentAmount()) json.unspentAmount = this.getUnspentAmount().toString(); - return json; - } - - getHeight() { - return this.state.height; - } - - setHeight(height) { - this.state.height = height; - return this; - } - - getSpentAmount() { - return this.state.spentAmount; - } - - setSpentAmount(spentAmount) { - this.state.spentAmount = spentAmount; - return this; - } - - getUnspentAmount() { - return this.state.unspentAmount; - } - - setUnspentAmount(unspentAmount) { - this.state.unspentAmount = unspentAmount; - return this; - } -} - -module.exports = MoneroKeyImageImportResult; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroMultisigInfo.js b/src/main/js/wallet/model/MoneroMultisigInfo.js deleted file mode 100644 index 89f401599..000000000 --- a/src/main/js/wallet/model/MoneroMultisigInfo.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Models information about a multisig wallet. - */ -class MoneroMultisigInfo { - - constructor(state) { - this.state = Object.assign({}, state); - } - - toJson() { - return Object.assign({}, this.state); - } - - isMultisig() { - return this.state.isMultisig; - } - - setIsMultisig(isMultisig) { - this.state.isMultisig = isMultisig; - return this; - } - - isReady() { - return this.state.isReady; - } - - setIsReady(isReady) { - this.state.isReady = isReady; - } - - getThreshold() { - return this.state.threshold; - } - - setThreshold(threshold) { - this.state.threshold = threshold; - } - - getNumParticipants() { - return this.state.numParticipants; - } - - setNumParticipants(numParticipants) { - this.state.numParticipants = numParticipants; - } -} - -module.exports = MoneroMultisigInfo; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroMultisigInitResult.js b/src/main/js/wallet/model/MoneroMultisigInitResult.js deleted file mode 100644 index c49c80aac..000000000 --- a/src/main/js/wallet/model/MoneroMultisigInitResult.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Models the result of initializing a multisig wallet which results in the - * multisig wallet's address xor another multisig hex to share with - * participants to create the wallet. - */ -class MoneroMultisigInitResult { - - constructor(state) { - this.state = Object.assign({}, state); - } - - toJson() { - return Object.assign({}, this.state); - } - - getAddress() { - return this.state.address; - } - - setAddress(address) { - this.state.address = address; - return this; - } - - getMultisigHex() { - return this.state.multisigHex; - } - - setMultisigHex(multisigHex) { - this.state.multisigHex = multisigHex; - return this; - } -} - -module.exports = MoneroMultisigInitResult; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroMultisigSignResult.js b/src/main/js/wallet/model/MoneroMultisigSignResult.js deleted file mode 100644 index 1abdecd61..000000000 --- a/src/main/js/wallet/model/MoneroMultisigSignResult.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Models the result of signing multisig tx hex. - */ -class MoneroMultisigSignResult { - - constructor(state) { - this.state = Object.assign({}, state); - } - - toJson() { - return Object.assign({}, this.state); - } - - getSignedMultisigTxHex() { - return this.state.signedMultisigTxHex; - } - - setSignedMultisigTxHex(signedTxMultisigHex) { - this.state.signedMultisigTxHex = signedTxMultisigHex; - } - - getTxHashes() { - return this.state.txHashes; - } - - setTxHashes(txHashes) { - this.state.txHashes = txHashes; - } -} - -module.exports = MoneroMultisigSignResult; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroOutgoingTransfer.js b/src/main/js/wallet/model/MoneroOutgoingTransfer.js deleted file mode 100644 index f747ac49e..000000000 --- a/src/main/js/wallet/model/MoneroOutgoingTransfer.js +++ /dev/null @@ -1,109 +0,0 @@ -const assert = require("assert"); -const GenUtils = require("../../common/GenUtils"); -const MoneroDestination = require("./MoneroDestination"); -const MoneroTransfer = require("./MoneroTransfer"); - -/** - * Models an outgoing transfer of funds from the wallet. - * - * @extends {MoneroTransfer} - */ -class MoneroOutgoingTransfer extends MoneroTransfer { - - /** - * Construct the model. - * - * @param {MoneroOutgoingTranser|object} state is existing state to initialize from (optional) - */ - constructor(state) { - super(state); - state = this.state; - - // deserialize destinations - if (state.destinations) { - for (let i = 0; i < state.destinations.length; i++) { - if (!(state.destinations[i] instanceof MoneroDestination)) state.destinations[i] = new MoneroDestination(state.destinations[i]); - } - } - } - - isIncoming() { - return false; - } - - getSubaddressIndices() { - return this.state.subaddressIndices; - } - - setSubaddressIndices(subaddressIndices) { - this.state.subaddressIndices = subaddressIndices; - return this; - } - - getAddresses() { - return this.state.addresses; - } - - setAddresses(addresses) { - this.state.addresses = addresses; - return this; - } - - getDestinations() { - return this.state.destinations; - } - - setDestinations(destinations) { - this.state.destinations = destinations; - return this; - } - - copy() { - return new MoneroOutgoingTransfer(this); - } - - toJson() { - let json = Object.assign({}, this.state, super.toJson()); // merge json onto inherited state - if (this.getDestinations()) { - json.destinations = []; - for (let destination of this.getDestinations()) json.destinations.push(destination.toJson()); - } - delete json.tx; // parent tx is not serialized - return json; - } - - /** - * Updates this transaction by merging the latest information from the given - * transaction. - * - * Merging can modify or build references to the transfer given so it - * should not be re-used or it should be copied before calling this method. - * - * @param transfer is the transfer to merge into this one - */ - merge(transfer) { - super.merge(transfer); - assert(transfer instanceof MoneroOutgoingTransfer); - if (this === transfer) return this; - this.setSubaddressIndices(GenUtils.reconcile(this.getSubaddressIndices(), transfer.getSubaddressIndices())); - this.setAddresses(GenUtils.reconcile(this.getAddresses(), transfer.getAddresses())); - this.setDestinations(GenUtils.reconcile(this.getDestinations(), transfer.getDestinations())); - return this; - } - - toString(indent = 0) { - let str = super.toString(indent) + "\n"; - str += GenUtils.kvLine("Subaddress indices", this.getSubaddressIndices(), indent); - str += GenUtils.kvLine("Addresses", this.getAddresses(), indent); - if (this.getDestinations()) { - str += GenUtils.kvLine("Destinations", "", indent); - for (let i = 0; i < this.getDestinations().length; i++) { - str += GenUtils.kvLine(i + 1, "", indent + 1); - str += this.getDestinations()[i].toString(indent + 2) + "\n"; - } - } - return str.slice(0, str.length - 1); // strip last newline - } -} - -module.exports = MoneroOutgoingTransfer; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroOutputQuery.js b/src/main/js/wallet/model/MoneroOutputQuery.js deleted file mode 100644 index 99a89a5f3..000000000 --- a/src/main/js/wallet/model/MoneroOutputQuery.js +++ /dev/null @@ -1,159 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; -const MoneroOutputWallet = require("./MoneroOutputWallet"); - -/** - * Configuration to query wallet outputs. - * - * @extends {MoneroOutputWallet} - */ -class MoneroOutputQuery extends MoneroOutputWallet { - - /** - *

Construct the output query.

- * - *

Example:

- * - * - * // get available outputs in account 0 with a minimum amount
- * let outputs = await wallet.getOutputs({
- *    isSpent: false,
- *    isLocked: false,
- *    accountIndex: 0,
- *    minAmount: new BigInteger("750000")
- * }); - *
- * - *

All configuration is optional. All outputs are returned except those that don't meet criteria defined in this query.

- * - * @param {object} config - output query configuration (optional) - * @param {int} config.accountIndex - get outputs in this account index - * @param {int} config.subaddressIndex - get outputs in this subaddress index - * @param {int[]} config.subaddressIndices - get outputs in these subaddress indices - * @param {BigInteger} config.amount - get outputs with this amount - * @param {BigInteger} config.minAmount - get outputs with amount greater than or equal to this amount - * @param {BigInteger} config.maxAmount - get outputs with amount less than or equal to this amount - * @param {boolean} config.isLocked - get locked xor unlocked outputs - * @param {boolean} config.isSpent - get spent xor unspent outputs - * @param {object|MoneroKeyImage} config.keyImage - get outputs with a key image matching fields defined in this key image - * @param {string} config.keyImage.hex - get outputs with this key image hex - * @param {string} config.keyImage.signature - get outputs with this key image signature - * @param {object|MoneroTxQuery} config.txQuery - get outputs whose tx match this tx query - */ - constructor(config) { - super(config); - - // deserialize if necessary - const MoneroTxQuery = require("./MoneroTxQuery"); - if (this.state.minAmount !== undefined && !(this.state.minAmount instanceof BigInteger)) this.state.minAmount = BigInteger.parse(this.state.minAmount); - if (this.state.maxAmount !== undefined && !(this.state.maxAmount instanceof BigInteger)) this.state.maxAmount = BigInteger.parse(this.state.maxAmount); - if (this.state.txQuery && !(this.state.txQuery instanceof MoneroTxQuery)) this.state.txQuery = new MoneroTxQuery(this.state.txQuery); - if (this.state.txQuery) this.state.txQuery.setOutputQuery(this); - } - - copy() { - return new MoneroOutputQuery(this); - } - - toJson() { - let json = Object.assign({}, this.state, super.toJson()); - if (this.getMinAmount()) json.minAmount = this.getMinAmount().toString(); - if (this.getMaxAmount()) json.maxAmount = this.getMaxAmount().toString(); - delete json.txQuery; - return json; - } - - getMinAmount() { - return this.state.minAmount; - } - - setMinAmount(minAmount) { - this.state.minAmount = minAmount; - return this; - } - - getMaxAmount() { - return this.state.maxAmount; - } - - setMaxAmount(maxAmount) { - this.state.maxAmount = maxAmount; - return this; - } - - getTxQuery() { - return this.state.txQuery; - } - - setTxQuery(txQuery) { - this.state.txQuery = txQuery; - if (txQuery) txQuery.state.outputQuery = this; - return this; - } - - getSubaddressIndices() { - return this.state.subaddressIndices; - } - - setSubaddressIndices(subaddressIndices) { - this.state.subaddressIndices = subaddressIndices; - return this; - } - - /** - * Indicates if the this query will fetch locked outputs, unlocked outputs, or both (null). - * - * @return true if locked outputs queried, false of unlocked outputs queried, undefined if both - */ - isLocked() { - if (this.state.txQuery === undefined) return undefined; - return txQuery.isLocked(); - } - - /** - * Convenience method to query outputs by the locked state of their tx. - * - * @param isLocked specifies if the output's tx must be locked or unlocked (optional) - * @return {MoneroOutputQuery} this query for chaining - */ - setIsLocked(isLocked) { - const MoneroTxQuery = require("./MoneroTxQuery"); - if (this.state.txQuery === undefined) this.state.txQuery = new MoneroTxQuery(); - this.state.txQuery.setIsLocked(isLocked); - return this; - } - - meetsCriteria(output, queryParent) { - if (!(output instanceof MoneroOutputWallet)) throw new Error("Output not given to MoneroOutputQuery.meetsCriteria(output)"); - if (queryParent === undefined) queryParent = true; - - // filter on output - if (this.getAccountIndex() !== undefined && this.getAccountIndex() !== output.getAccountIndex()) return false; - if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() !== output.getSubaddressIndex()) return false; - if (this.getAmount() !== undefined && this.getAmount().compare(output.getAmount()) !== 0) return false; - if (this.isSpent() !== undefined && this.isSpent() !== output.isSpent()) return false; - - // filter on output's key image - if (this.getKeyImage() !== undefined) { - if (output.getKeyImage() === undefined) return false; - if (this.getKeyImage().getHex() !== undefined && this.getKeyImage().getHex() !== output.getKeyImage().getHex()) return false; - if (this.getKeyImage().getSignature() !== undefined && this.getKeyImage().getSignature() !== output.getKeyImage().getSignature()) return false; - } - - // filter on extensions - if (this.getSubaddressIndices() !== undefined && !this.getSubaddressIndices().includes(output.getSubaddressIndex())) return false; - - // filter with tx query - if (this.getTxQuery() && !this.getTxQuery().meetsCriteria(output.getTx(), false)) return false; - - // filter on remaining fields - if (this.getMinAmount() !== undefined && (output.getAmount() === undefined || output.getAmount().compare(this.getMinAmount()) < 0)) return false; - if (this.getMaxAmount() !== undefined && (output.getAmount() === undefined || output.getAmount().compare(this.getMaxAmount()) > 0)) return false; - - // output meets query - return true; - } -} - -MoneroOutputQuery._EMPTY_OUTPUT = new MoneroOutputWallet(); - -module.exports = MoneroOutputQuery; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroOutputWallet.js b/src/main/js/wallet/model/MoneroOutputWallet.js deleted file mode 100644 index 54c883328..000000000 --- a/src/main/js/wallet/model/MoneroOutputWallet.js +++ /dev/null @@ -1,109 +0,0 @@ -const assert = require("assert"); -const GenUtils = require("../../common/GenUtils"); -const MoneroOutput = require("../../daemon/model/MoneroOutput"); - -/** - * Models a Monero output with wallet extensions. - * - * @class - * @extends {MoneroOutput} - */ -class MoneroOutputWallet extends MoneroOutput { - - /** - * Construct the model. - * - * @param {MoneroOutputWallet|object} state is existing state to initialize from (optional) - */ - constructor(state) { - super(state); - } - - getAccountIndex() { - return this.state.accountIndex; - } - - setAccountIndex(accountIndex) { - this.state.accountIndex = accountIndex; - return this; - } - - getSubaddressIndex() { - return this.state.subaddressIndex; - } - - setSubaddressIndex(subaddressIndex) { - this.state.subaddressIndex = subaddressIndex; - return this; - } - - isSpent() { - return this.state.isSpent; - } - - setIsSpent(isSpent) { - this.state.isSpent = isSpent; - return this; - } - - /** - * Indicates if this output has been deemed 'malicious' and will therefore - * not be spent by the wallet. - * - * @return Boolean is whether or not this output is frozen - */ - isFrozen() { - return this.state.isFrozen; - } - - setIsFrozen(isFrozen) { - this.state.isFrozen = isFrozen; - return this; - } - - isLocked() { - if (this.getTx() === undefined) return undefined; - return this.getTx().isLocked(); - } - - copy() { - return new MoneroOutputWallet(this.toJson()); - } - - toJson() { - let json = Object.assign({}, this.state, super.toJson()); - delete json.tx; - return json; - } - - /** - * Updates this output by merging the latest information from the given - * output. - * - * Merging can modify or build references to the output given so it - * should not be re-used or it should be copied before calling this method. - * - * @param output is the output to merge into this one - */ - merge(output) { - assert(output instanceof MoneroOutputWallet); - if (this === output) return; - super.merge(output); - this.setAccountIndex(GenUtils.reconcile(this.getAccountIndex(), output.getAccountIndex())); - this.setSubaddressIndex(GenUtils.reconcile(this.getSubaddressIndex(), output.getSubaddressIndex())); - this.setIsSpent(GenUtils.reconcile(this.isSpent(), output.isSpent(), {resolveTrue: true})); // output can become spent - this.setIsFrozen(GenUtils.reconcile(this.isFrozen(), output.isFrozen())); - return this; - } - - toString(indent) { - let str = super.toString(indent) + "\n" - str += GenUtils.kvLine("Account index", this.getAccountIndex(), indent); - str += GenUtils.kvLine("Subaddress index", this.getSubaddressIndex(), indent); - str += GenUtils.kvLine("Is spent", this.isSpent(), indent); - str += GenUtils.kvLine("Is frozen", this.isFrozen(), indent); - return str.slice(0, str.length - 1); // strip last newline - } -} - -module.exports = MoneroOutputWallet; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroSubaddress.js b/src/main/js/wallet/model/MoneroSubaddress.js deleted file mode 100644 index 3473d8c4f..000000000 --- a/src/main/js/wallet/model/MoneroSubaddress.js +++ /dev/null @@ -1,123 +0,0 @@ -const BigInteger = require("../../common/biginteger").BigInteger; -const GenUtils = require("../../common/GenUtils"); - -/** - * Monero subaddress model. - */ -class MoneroSubaddress { - - constructor(stateOrAddress) { - if (stateOrAddress === undefined || typeof stateOrAddress === "string") { - this.state = {}; - this.setAddress(stateOrAddress); - } else { - this.state = stateOrAddress; - if (this.state.balance !== undefined && !(this.state.balance instanceof BigInteger)) this.state.balance = BigInteger.parse(this.state.balance); - if (this.state.unlockedBalance !== undefined && !(this.state.unlockedBalance instanceof BigInteger)) this.state.unlockedBalance = BigInteger.parse(this.state.unlockedBalance); - } - } - - toJson() { - let json = Object.assign({}, this.state); - if (json.balance) json.balance = json.balance.toString(); - if (json.unlockedBalance) json.unlockedBalance = json.unlockedBalance.toString(); - return json; - } - - getAccountIndex() { - return this.state.accountIndex; - } - - setAccountIndex(accountIndex) { - this.state.accountIndex = accountIndex; - return this; - } - - getIndex() { - return this.state.index; - } - - setIndex(index) { - this.state.index = index; - return this; - } - - getAddress() { - return this.state.address; - } - - setAddress(address) { - this.state.address = address; - return this; - } - - getLabel() { - return this.state.label; - } - - setLabel(label) { - this.state.label = label; - return this; - } - - getBalance() { - return this.state.balance; - } - - setBalance(balance) { - this.state.balance = balance; - return this; - } - - getUnlockedBalance() { - return this.state.unlockedBalance; - } - - setUnlockedBalance(unlockedBalance) { - this.state.unlockedBalance = unlockedBalance; - return this; - } - - getNumUnspentOutputs() { - return this.state.numUnspentOutputs; - } - - setNumUnspentOutputs(numUnspentOutputs) { - this.state.numUnspentOutputs = numUnspentOutputs; - return this; - } - - isUsed() { - return this.state.isUsed; - } - - setIsUsed(isUsed) { - this.state.isUsed = isUsed; - return this; - } - - getNumBlocksToUnlock() { - return this.state.numBlocksToUnlock; - } - - setNumBlocksToUnlock(numBlocksToUnlock) { - this.state.numBlocksToUnlock = numBlocksToUnlock; - return this; - } - - toString(indent) { - let str = ""; - str += GenUtils.kvLine("Account index", this.getAccountIndex(), indent); - str += GenUtils.kvLine("Subaddress index", this.getIndex(), indent); - str += GenUtils.kvLine("Address", this.getAddress(), indent); - str += GenUtils.kvLine("Label", this.getLabel(), indent); - str += GenUtils.kvLine("Balance", this.getBalance(), indent); - str += GenUtils.kvLine("Unlocked balance", this.getUnlockedBalance(), indent); - str += GenUtils.kvLine("Num unspent outputs", this.getNumUnspentOutputs(), indent); - str += GenUtils.kvLine("Is used", this.isUsed(), indent); - str += GenUtils.kvLine("Num blocks to unlock", this.isUsed(), indent); - return str.slice(0, str.length - 1); // strip last newline - } -} - -module.exports = MoneroSubaddress; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroTransfer.js b/src/main/js/wallet/model/MoneroTransfer.js deleted file mode 100644 index 787e3e05d..000000000 --- a/src/main/js/wallet/model/MoneroTransfer.js +++ /dev/null @@ -1,128 +0,0 @@ -const assert = require("assert"); -const BigInteger = require("../../common/biginteger").BigInteger; -const GenUtils = require("../../common/GenUtils"); - -/** - * Models a base transfer of funds to or from the wallet. - * - * @class - */ -class MoneroTransfer { - - /** - * Construct the model. - * - * @param {MoneroTransfer|object} state is existing state to initialize from (optional) - */ - constructor(state) { - - // initialize internal state - if (!state) state = {}; - else if (state instanceof MoneroTransfer) state = state.toJson(); - else if (typeof state === "object") state = Object.assign({}, state); - else throw new MoneroError("state must be a MoneroTransfer or JavaScript object"); - this.state = state; - - // deserialize fields if necessary - if (state.amount !== undefined && !(state.amount instanceof BigInteger)) state.amount = BigInteger.parse(state.amount); - - // validate state - this._validate(); - } - - copy() { - return new MoneroTransfer(this); - } - - toJson() { - let json = Object.assign({}, this.state); - if (this.getAmount()) json.amount = this.getAmount().toString() - delete json.tx; // parent tx is not serialized - return json; - } - - getTx() { - return this.state.tx; - } - - setTx(tx) { - this.state.tx = tx; - return this; - } - - isOutgoing() { - let isIncoming = this.isIncoming(); - assert(typeof isIncoming === "boolean"); - return !isIncoming; - } - - isIncoming() { - throw new Error("Subclass must implement"); - } - - getAccountIndex() { - return this.state.accountIndex; - } - - setAccountIndex(accountIndex) { - this.state.accountIndex = accountIndex; - this._validate(); - return this; - } - - getAmount() { - return this.state.amount; - } - - setAmount(amount) { - this.state.amount = amount; - return this; - } - - /** - * Updates this transaction by merging the latest information from the given - * transaction. - * - * Merging can modify or build references to the transfer given so it - * should not be re-used or it should be copied before calling this method. - * - * @param transfer is the transfer to merge into this one - * @return {MoneroTransfer} the merged transfer - */ - merge(transfer) { - assert(transfer instanceof MoneroTransfer); - if (this === transfer) return this; - - // merge transactions if they're different which comes back to merging transfers - if (this.getTx() !== transfer.getTx()) { - this.getTx().merge(transfer.getTx()); - return this; - } - - // otherwise merge transfer fields - this.setAccountIndex(GenUtils.reconcile(this.getAccountIndex(), transfer.getAccountIndex())); - - // TODO monero core: failed tx in pool (after testUpdateLockedDifferentAccounts()) causes non-originating saved wallets to return duplicate incoming transfers but one has amount of 0 - if (this.getAmount() !== undefined && transfer.getAmount() !== undefined && this.getAmount().compare(transfer.getAmount()) !== 0 && (this.getAmount().compare(BigInteger.parse("0")) === 0 || transfer.getAmount().compare(BigInteger.parse("0")) === 0)) { - //throw new Error("WARNING: monero core returning transfers with 0 amount/numSuggestedConfirmations"); - } else { - this.setAmount(GenUtils.reconcile(this.getAmount(), transfer.getAmount())); - } - - return this; - } - - toString(indent = 0) { - let str = ""; - str += GenUtils.kvLine("Is incoming", this.isIncoming(), indent); - str += GenUtils.kvLine("Account index", this.getAccountIndex(), indent); - str += GenUtils.kvLine("Amount", this.getAmount() ? this.getAmount().toString() : undefined, indent); - return str === "" ? str : str.slice(0, str.length - 1); // strip last newline - } - - _validate() { - if (this.getAccountIndex() !== undefined && this.getAccountIndex() < 0) throw new MoneroError("Account index must be >= 0"); - } -} - -module.exports = MoneroTransfer; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroTransferQuery.js b/src/main/js/wallet/model/MoneroTransferQuery.js deleted file mode 100644 index 899d7d1d8..000000000 --- a/src/main/js/wallet/model/MoneroTransferQuery.js +++ /dev/null @@ -1,221 +0,0 @@ -const MoneroIncomingTransfer = require("./MoneroIncomingTransfer"); -const MoneroOutgoingTransfer = require("./MoneroOutgoingTransfer"); -const MoneroTransfer = require("./MoneroTransfer"); -const MoneroError = require("../../common/MoneroError") - -/** - * Configuration to query wallet transfers. - * - * @extends {MoneroTransfer} - */ -class MoneroTransferQuery extends MoneroTransfer { - - /** - *

Construct the transfer query.

- * - *

Example:

- * - * - * // get incoming transfers to account 0, subaddress 1
- * let transfers = await wallet.getTransfers({
- *    accountIndex: 0,
- *    subaddressIndex: 0
- * }); - *
- * - *

All configuration is optional. All transfers are returned except those that don't meet criteria defined in this query.

- * - * @param {object} config - transfer query configuration (optional) - * @param {BigInteger} config.amount - get transfers with this amount - * @param {int} config.accountIndex - get transfers to/from this account index - * @param {int} config.subaddressIndex - get transfers to/from this subaddress index - * @param {int[]} config.subaddressIndices - get transfers to/from these subaddress indices - * @param {string} config.address - get transfers to/from this wallet address - * @param {string[]} config.addresses - get transfers to/from these wallet addresses - * @param {boolean} config.isIncoming - get transfers which are incoming if true - * @param {boolean} config.isOutgoing - get transfers which are outgoing if true - * @param {boolean} config.hasDestinations - get transfers with known destinations if true (destinations are only stored locally with the wallet) - * @param {object|MoneroTxQuery} config.txQuery - get transfers whose tx match this tx query - */ - constructor(config) { - super(config); - - // deserialize if necessary - const MoneroTxQuery = require("./MoneroTxQuery"); - if (this.state.txQuery && !(this.state.txQuery instanceof MoneroTxQuery)) this.state.txQuery = new MoneroTxQuery(this.state.txQuery); - if (this.state.txQuery) this.state.txQuery.setTransferQuery(this); - - // alias isOutgoing to isIncoming - if (this.state.isOutgoing !== undefined) this.state.isIncoming = !this.state.isOutgoing; - - // validate state - this._validate(); - } - - copy() { - return new MoneroTransferQuery(this); - } - - toJson() { - let json = Object.assign({}, this.state, super.toJson()); - delete json.txQuery; - return json; - } - - getTxQuery() { - return this.state.txQuery; - } - - setTxQuery(txQuery) { - this.state.txQuery = txQuery; - if (txQuery) txQuery.state.transferQuery = this; - return this; - } - - isIncoming() { - return this.state.isIncoming; - } - - setIsIncoming(isIncoming) { - this.state.isIncoming = isIncoming; - return this; - } - - isOutgoing() { - return this.state.isIncoming === undefined ? undefined : !this.state.isIncoming; - } - - setIsOutgoing(isOutgoing) { - this.state.isIncoming = isOutgoing === undefined ? undefined : !isOutgoing; - return this; - } - - getAddress() { - return this.state.address; - } - - setAddress(address) { - this.state.address = address; - return this; - } - - getAddresses() { - return this.state.addresses; - } - - setAddresses(addresses) { - this.state.addresses = addresses; - return this; - } - - getSubaddressIndex() { - return this.state.subaddressIndex; - } - - setSubaddressIndex(subaddressIndex) { - this.state.subaddressIndex = subaddressIndex; - this._validate(); - return this; - } - - getSubaddressIndices() { - return this.state.subaddressIndices; - } - - setSubaddressIndices(subaddressIndices) { - this.state.subaddressIndices = subaddressIndices; - this._validate(); - return this; - } - - getDestinations() { - return this.state.destinations; - } - - setDestinations(destinations) { - this.state.destinations = destinations; - return this; - } - - hasDestinations() { - return this.state.hasDestinations; - } - - setHasDestinations(hasDestinations) { - this.state.hasDestinations = hasDestinations; - return this; - } - - /** - * Convenience method to query outputs by the locked state of their tx. - * - * @param isLocked specifies if the output's tx must be locked or unlocked (optional) - * @return {MoneroOutputQuery} this query for chaining - */ - setIsLocked(isLocked) { - if (this.state.txQuery === undefined) this.state.txQuery = new MoneroTxQuery(); - this.state.txQuery.setIsLocked(isLocked); - return this; - } - - meetsCriteria(transfer, queryParent) { - if (!(transfer instanceof MoneroTransfer)) throw new Error("Transfer not given to MoneroTransferQuery.meetsCriteria(transfer)"); - if (queryParent === undefined) queryParent = true; - - // filter on common fields - if (this.isIncoming() !== undefined && this.isIncoming() !== transfer.isIncoming()) return false; - if (this.isOutgoing() !== undefined && this.isOutgoing() !== transfer.isOutgoing()) return false; - if (this.getAmount() !== undefined && this.getAmount().compare(transfer.getAmount()) !== 0) return false; - if (this.getAccountIndex() !== undefined && this.getAccountIndex() !== transfer.getAccountIndex()) return false; - - // filter on incoming fields - if (transfer instanceof MoneroIncomingTransfer) { - if (this.hasDestinations()) return false; - if (this.getAddress() !== undefined && this.getAddress() !== transfer.getAddress()) return false; - if (this.getAddresses() !== undefined && !this.getAddresses().includes(transfer.getAddress())) return false; - if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() !== transfer.getSubaddressIndex()) return false; - if (this.getSubaddressIndices() !== undefined && !this.getSubaddressIndices().includes(transfer.getSubaddressIndex())) return false; - } - - // filter on outgoing fields - else if (transfer instanceof MoneroOutgoingTransfer) { - - // filter on addresses which must have overlap - if (this.getAddress() !== undefined && (transfer.getAddresses() === undefined || !transfer.getAddresses().includes(this.getAddress()))) return false; // TODO: will filter all transfers that don't contain addresses (outgoing txs might not have this field initialized) - if (this.getAddresses() !== undefined) { - if (!transfer.getAddresses()) return false; - if (!this.getAddresses().some(address => transfer.getAddresses().includes(address))) return false; - } - - // filter on subaddress indices - if (this.getSubaddressIndex() !== undefined && (transfer.getSubaddressIndices() === undefined || !transfer.getSubaddressIndices().includes(this.getSubaddressIndex()))) return false; - if (this.getSubaddressIndices() !== undefined) { - if (!transfer.getSubaddressIndices()) return false; - if (!this.getSubaddressIndices().some(subaddressIdx => transfer.getSubaddressIndices().includes(subaddressIdx))) return false; - } - - // filter on having destinations - if (this.hasDestinations() !== undefined) { - if (this.hasDestinations() && transfer.getDestinations() === undefined) return false; - if (!this.hasDestinations() && transfer.getDestinations() !== undefined) return false; - } - - // filter on destinations TODO: start with test for this -// if (this.getDestionations() !== undefined && this.getDestionations() !== transfer.getDestionations()) return false; - } - - // otherwise invalid type - else throw new Error("Transfer must be MoneroIncomingTransfer or MoneroOutgoingTransfer"); - - // filter with tx filter - if (queryParent && this.getTxQuery() !== undefined && !this.getTxQuery().meetsCriteria(transfer.getTx())) return false; - return true; - } - - _validate() { - if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() < 0) throw new MoneroError("Subaddress index must be >= 0"); - if (this.getSubaddressIndices() !== undefined) for (let subaddressIdx of this.getSubaddressIndices()) if (subaddressIdx < 0) throw new MoneroError("Subaddress indices must be >= 0"); - } -} - -module.exports = MoneroTransferQuery; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroTxConfig.js b/src/main/js/wallet/model/MoneroTxConfig.js deleted file mode 100644 index 40da6a76c..000000000 --- a/src/main/js/wallet/model/MoneroTxConfig.js +++ /dev/null @@ -1,291 +0,0 @@ -const assert = require("assert"); -const MoneroDestination = require("./MoneroDestination"); -const MoneroError = require("../../common/MoneroError"); - -/** - * Configures a transaction to send, sweep, or create a payment URI. - */ -class MoneroTxConfig { - - /** - *

Generic request to transfer funds from a wallet.

- * - *

Examples:

- * - * - * let config1 = new MoneroTxConfig({
- *    accountIndex: 0,
- *    address: "59aZULsUF3YN...",
- *    amount: new BigInteger("500000"),
- *    priority: MoneroTxPriority.NORMAL,
- *    relay: true
- * });

- *
- * - * @param {MoneroTxConfig|object} config - configures the transaction to create (optional) - * @param {string} config.address - single destination address - * @param {BigInteger} config.amount - single destination amount - * @param {int} config.accountIndex - source account index to transfer funds from - * @param {int} config.subaddressIndex - source subaddress index to transfer funds from - * @param {int[]} config.subaddressIndices - source subaddress indices to transfer funds from - * @param {boolean} config.relay - relay the transaction to peers to commit to the blockchain - * @param {MoneroTxPriority} config.priority - transaction priority (default MoneroTxPriority.NORMAL) - * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx - * @param {string} config.paymentId - transaction payment ID - * @param {int} config.unlockHeight - minimum height for the transaction to unlock (default 0) - * @param {string} config.note - transaction note saved locally with the wallet - * @param {string} config.recipientName - recipient name saved locally with the wallet - * @param {boolean} config.canSplit - allow funds to be transferred using multiple transactions - * @param {BigInteger} config.belowAmount - for sweep requests, include outputs below this amount when sweeping wallet, account, subaddress, or all unlocked funds - * @param {boolean} config.sweepEachSubaddress - for sweep requests, sweep each subaddress individually instead of together if true - * @param {string} config.keyImage - key image to sweep (ignored except in sweepOutput() requests) - */ - constructor(config) { - if (arguments.length > 1) throw new MoneroError("MoneroTxConfig can be constructed with only one parameter but was given " + arguments.length) - - // initialize internal state - if (!config) this.state = {}; - else if (config instanceof MoneroTxConfig) this.state = config.toJson(); - else if (typeof config === "object") this.state = Object.assign({}, config); - else throw new MoneroError("Invalid argument given to MoneroTxConfig: " + typeof config); - - // deserialize if necessary - if (this.state.destinations) { - assert(this.state.address === undefined && this.state.amount === undefined, "Tx configuration may specify destinations or an address/amount but not both"); - this.setDestinations(this.state.destinations.map(destination => destination instanceof MoneroDestination ? destination : new MoneroDestination(destination))); - } - - // alias 'address' and 'amount' to single destination to support e.g. createTx({address: "..."}) - if (this.state.address || this.state.amount) { - assert(!this.state.destinations, "Tx configuration may specify destinations or an address/amount but not both"); - this.setDestinations([new MoneroDestination(this.state.address, this.state.amount)]); - delete this.state.address; - delete this.state.amount; - } - - // alias 'subaddressIndex' to subaddress indices - if (this.state.subaddressIndex !== undefined) { - this.setSubaddressIndices([this.state.subaddressIndex]); - delete this.state.subaddressIndex; - } - } - - copy() { - return new MoneroTxConfig(this); - } - - toJson() { - let json = Object.assign({}, this.state); // copy state - if (this.getDestinations()) { - json.destinations = []; - for (let destination of this.getDestinations()) json.destinations.push(destination.toJson()); - } - if (this.getFee()) json.fee = this.getFee().toString(); - if (this.getBelowAmount()) json.belowAmount = this.getBelowAmount().toString(); - return json; - } - - /** - * Set the address of a single-destination configuration. - * - * @param {string} address - the address to set for the single destination - * @return {MoneroTxConfig} this configuration for chaining - */ - setAddress(address) { - if (this.state.destinations !== undefined && this.state.destinations.length > 1) throw new MoneroError("Cannot set address because MoneroTxConfig already has multiple destinations"); - if (this.state.destinations === undefined || this.state.destinations.length === 0) this.addDestination(new MoneroDestination(address)); - else this.state.destinations[0].setAddress(address); - return this; - } - - /** - * Get the address of a single-destination configuration. - * - * @return {string} the address of the single destination - */ - getAddress() { - if (this.state.destinations === undefined || this.state.destinations.length !== 1) throw new MoneroError("Cannot get address because MoneroTxConfig does not have exactly one destination"); - return this.state.destinations[0].getAddress(); - } - - /** - * Set the amount of a single-destination configuration. - * - * @param {BigInteger} amount - the amount to set for the single destination - * @return {MoneroTxConfig} this configuration for chaining - */ - setAmount(amount) { - if (this.state.destinations !== undefined && this.state.destinations.length > 1) throw new MoneroError("Cannot set amount because MoneroTxConfig already has multiple destinations"); - if (this.state.destinations === undefined || this.state.destinations.length === 0) this.addDestination(new MoneroDestination(undefined, amount)); - else this.state.destinations[0].setAmount(amount); - return this; - } - - /** - * Get the amount of a single-destination configuration. - * - * @return {BigInteger} the amount of the single destination - */ - getAmount() { - if (this.state.destinations === undefined || this.state.destinations.length !== 1) throw new MoneroError("Cannot get amount because MoneroTxConfig does not have exactly one destination"); - return this.state.destinations[0].getAmount(); - } - - addDestination(destination) { - assert(destination instanceof MoneroDestination); - if (this.state.destinations === undefined) this.state.destinations = []; - this.state.destinations.push(destination); - return this; - } - - getDestinations() { - return this.state.destinations; - } - - setDestinations(destinations) { - if (arguments.length > 1) destinations = Array.from(arguments); - this.state.destinations = destinations; - return this; - } - - setDestination(destination) { - return this.setDestinations(destination ? [destination] : destination); - } - - getPaymentId() { - return this.state.paymentId; - } - - setPaymentId(paymentId) { - this.state.paymentId = paymentId; - return this; - } - - getPriority() { - return this.state.priority; - } - - setPriority(priority) { - this.state.priority = priority; - return this; - } - - getFee() { - return this.state.fee; - } - - setFee(fee) { - this.state.fee = fee; - return this; - } - - getAccountIndex() { - return this.state.accountIndex; - } - - setAccountIndex(accountIndex) { - this.state.accountIndex = accountIndex; - return this; - } - - setSubaddressIndex(subaddressIndex) { - this.setSubaddressIndices([subaddressIndex]); - return this; - } - - getSubaddressIndices() { - return this.state.subaddressIndices; - } - - setSubaddressIndices(subaddressIndices) { - if (arguments.length > 1) subaddressIndices = Array.from(arguments); - this.state.subaddressIndices = subaddressIndices; - return this; - } - - getUnlockHeight() { - return this.state.unlockHeight; - } - - setUnlockHeight(unlockHeight) { - this.state.unlockHeight = unlockHeight; - return this; - } - - getRelay() { - return this.state.relay; - } - - setRelay(relay) { - this.state.relay = relay; - return this; - } - - getCanSplit() { - return this.state.canSplit; - } - - setCanSplit(canSplit) { - this.state.canSplit = canSplit; - return this; - } - - getNote() { - return this.state.note; - } - - setNote(note) { - this.state.note = note; - return this; - } - - getRecipientName() { - return this.state.recipientName; - } - - setRecipientName(recipientName) { - this.state.recipientName = recipientName; - return this; - } - - // --------------------------- SPECIFIC TO SWEEP ---------------------------- - - getBelowAmount() { - return this.state.belowAmount; - } - - setBelowAmount(belowAmount) { - this.state.belowAmount = belowAmount; - return this; - } - - getSweepEachSubaddress() { - return this.state.sweepEachSubaddress; - } - - setSweepEachSubaddress(sweepEachSubaddress) { - this.state.sweepEachSubaddress = sweepEachSubaddress; - return this; - } - - /** - * Get the key image hex of the output to sweep. - * - * return {string} is the key image hex of the output to sweep - */ - getKeyImage() { - return this.state.keyImage; - } - - /** - * Set the key image hex of the output to sweep. - * - * @param {string} keyImage is the key image hex of the output to sweep - */ - setKeyImage(keyImage) { - this.state.keyImage = keyImage; - return this; - } -} - -module.exports = MoneroTxConfig \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroTxPriority.js b/src/main/js/wallet/model/MoneroTxPriority.js deleted file mode 100644 index 48869b365..000000000 --- a/src/main/js/wallet/model/MoneroTxPriority.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Enumerates send priorities. - * - * @hideconstructor - */ -class MoneroTxPriority {} - -/** - * Default priority (i.e. normal) (value=0). - */ -MoneroTxPriority.DEFAULT = 0; - -/** - * Unimportant priority (value=1). - */ -MoneroTxPriority.UNIMPORTANT = 1; - -/** - * Normal priority (value=2). - */ -MoneroTxPriority.NORMAL = 2; - -/** - * Elevated priority (value=3). - */ -MoneroTxPriority.ELEVATED = 3; - -module.exports = MoneroTxPriority; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroTxQuery.js b/src/main/js/wallet/model/MoneroTxQuery.js deleted file mode 100644 index b7479208d..000000000 --- a/src/main/js/wallet/model/MoneroTxQuery.js +++ /dev/null @@ -1,273 +0,0 @@ -const assert = require("assert"); -const MoneroOutputQuery = require("./MoneroOutputQuery"); -const MoneroTransferQuery = require("./MoneroTransferQuery"); -const MoneroTxWallet = require("./MoneroTxWallet"); - -/** - *

Configuration to query transactions.

- * - * @class - * @extends {MoneroTxWallet} - */ -class MoneroTxQuery extends MoneroTxWallet { - - /** - *

Construct the transaction query.

- * - *

Example:

- * - * - * // get transactions with unlocked incoming transfers to account 0
- * let txs = await wallet.getTxs({
- *    isLocked: false,
- *    transferQuery: {
- *      isIncoming: true,
- *      accountIndex: 0
- *    }
- * }); - *
- * - *

All configuration is optional. All transactions are returned except those that don't meet criteria defined in this query.

- * - * @param {object} config - tx query configuration - * @param {string} config.hash - get a tx with this hash - * @param {string[]} config.txHashes - get txs with these hashes - * @param {int} config.height - get txs with this height - * @param {int} config.minHeight - get txs with height greater than or equal to this height - * @param {int} config.maxHeight - get txs with height less than or equal to this height - * @param {boolean} config.isConfirmed - get confirmed or unconfirmed txs - * @param {boolean} config.inTxPool - get txs in or out of the tx pool - * @param {boolean} config.relay - get txs with the same relay status - * @param {boolean} config.isRelayed - get relayed or non-relayed txs - * @param {boolean} config.isFailed - get failed or non-failed txs - * @param {boolean} config.isMinerTx - get miner or non-miner txs - * @param {boolean} config.isLocked - get locked or unlocked txs - * @param {boolean} config.isIncoming - get txs with or without incoming transfers - * @param {boolean} config.isOutgoing - get txs with or without outgoing transfers - * @param {string} config.paymentId - get txs with this payment ID - * @param {string} config.paymentIds - get txs with a payment ID among these payment IDs - * @param {boolean} config.hasPaymentId - get txs with or without payment IDs - * @param {object|MoneroTransferQuery} config.transferQuery - get txs with transfers matching this transfer query - * @param {object|MoneroOutputQuery} config.outputQuery - get txs with outputs matching this output query - */ - constructor(config) { - super(config); - - // deserialize if necessary - if (this.state.transferQuery && !(this.state.transferQuery instanceof MoneroTransferQuery)) this.state.transferQuery = new MoneroTransferQuery(this.state.transferQuery); - if (this.state.outputQuery && !(this.state.outputQuery instanceof MoneroOutputQuery)) this.state.outputQuery = new MoneroOutputQuery(this.state.outputQuery); - - // link cycles - if (this.state.transferQuery) this.state.transferQuery.setTxQuery(this); - if (this.state.outputQuery) this.state.outputQuery.setTxQuery(this); - - // alias 'hash' to hashes - if (this.state.hash) { - this.setHashes([this.state.hash]); - delete this.state.hash; - } - } - - copy() { - return new MoneroTxQuery(this); - } - - toJson() { - let json = Object.assign({}, this.state, super.toJson()); // merge json onto inherited state - if (this.getTransferQuery()) json.transferQuery = this.getTransferQuery().toJson(); - if (this.getOutputQuery()) json.outputQuery = this.getOutputQuery().toJson(); - delete json.block; // do not serialize parent block - return json; - } - - isIncoming() { - return this.state.isIncoming; - } - - setIsIncoming(isIncoming) { - this.state.isIncoming = isIncoming; - return this; - } - - isOutgoing() { - return this.state.isOutgoing; - } - - setIsOutgoing(isOutgoing) { - this.state.isOutgoing = isOutgoing; - return this; - } - - getHashes() { - return this.state.hashes; - } - - setHashes(hashes) { - this.state.hashes = hashes; - return this; - } - - setHash(hash) { - if (hash === undefined) return this.setHashes(undefined); - assert(typeof hash === "string"); - return this.setHashes([hash]); - } - - hasPaymentId() { - return this.state.hasPaymentId; - } - - setHasPaymentId() { - this.state.hasPaymentId = hasPaymentId; - return this; - } - - getPaymentIds() { - return this.state.paymentIds; - } - - setPaymentIds(paymentIds) { - this.state.paymentIds = paymentIds; - return this; - } - - setPaymentId(paymentId) { - if (paymentId === undefined) return this.setPaymentIds(undefined); - assert(typeof paymentId === "string"); - return this.setPaymentIds([paymentId]); - } - - getHeight() { - return this.state.height; - } - - setHeight(height) { - this.state.height = height; - return this; - } - - getMinHeight() { - return this.state.minHeight; - } - - setMinHeight(minHeight) { - this.state.minHeight = minHeight; - return this; - } - - getMaxHeight() { - return this.state.maxHeight; - } - - setMaxHeight(maxHeight) { - this.state.maxHeight = maxHeight; - return this; - } - - getIncludeOutputs() { - return this.state.includeOutputs; - } - - setIncludeOutputs(includeOutputs) { - this.state.includeOutputs = includeOutputs; - return this; - } - - getTransferQuery() { - return this.state.transferQuery; - } - - setTransferQuery(transferQuery) { - this.state.transferQuery = transferQuery; - if (transferQuery) transferQuery.state.txQuery = this; - return this; - } - - getOutputQuery() { - return this.state.outputQuery; - } - - setOutputQuery(outputQuery) { - this.state.outputQuery = outputQuery; - if (outputQuery) outputQuery.state.txQuery = this; - return this; - } - - meetsCriteria(tx, queryChildren) { - if (!(tx instanceof MoneroTxWallet)) throw new Error("Tx not given to MoneroTxQuery.meetsCriteria(tx)"); - if (queryChildren === undefined) queryChildren = true; - - // filter on tx - if (this.getHash() !== undefined && this.getHash() !== tx.getHash()) return false; - if (this.getPaymentId() !== undefined && this.getPaymentId() !== tx.getPaymentId()) return false; - if (this.isConfirmed() !== undefined && this.isConfirmed() !== tx.isConfirmed()) return false; - if (this.inTxPool() !== undefined && this.inTxPool() !== tx.inTxPool()) return false; - if (this.getRelay() !== undefined && this.getRelay() !== tx.getRelay()) return false; - if (this.isRelayed() !== undefined && this.isRelayed() !== tx.isRelayed()) return false; - if (this.isFailed() !== undefined && this.isFailed() !== tx.isFailed()) return false; - if (this.isMinerTx() !== undefined && this.isMinerTx() !== tx.isMinerTx()) return false; - if (this.isLocked() !== undefined && this.isLocked() !== tx.isLocked()) return false; - - // filter on having a payment id - if (this.hasPaymentId() !== undefined) { - if (this.hasPaymentId() && tx.getPaymentId() === undefined) return false; - if (!this.hasPaymentId() && tx.getPaymentId() !== undefined) return false; - } - - // filter on incoming - if (this.isIncoming() !== undefined) { - if (this.isIncoming() && !tx.isIncoming()) return false; - if (!this.isIncoming() && tx.isIncoming()) return false; - } - - // filter on outgoing - if (this.isOutgoing() !== undefined) { - if (this.isOutgoing() && !tx.isOutgoing()) return false; - if (!this.isOutgoing() && tx.isOutgoing()) return false; - } - - // filter on remaining fields - let txHeight = tx.getBlock() === undefined ? undefined : tx.getBlock().getHeight(); - if (this.getHashes() !== undefined && !this.getHashes().includes(tx.getHash())) return false; - if (this.getPaymentIds() !== undefined && !this.getPaymentIds().includes(tx.getPaymentId())) return false; - if (this.getHeight() !== undefined && (txHeight === undefined || txHeight !== this.getHeight())) return false; - if (this.getMinHeight() !== undefined && (txHeight === undefined || txHeight < this.getMinHeight())) return false; - if (this.getMaxHeight() !== undefined && (txHeight === undefined || txHeight > this.getMaxHeight())) return false; - // TODO: filtering not complete - - // done if not querying transfers or outputs - if (!queryChildren) return true; - - // at least one transfer must meet transfer filter if defined - if (this.getTransferQuery()) { - let matchFound = false; - if (tx.getOutgoingTransfer() && this.getTransferQuery().meetsCriteria(tx.getOutgoingTransfer(), false)) matchFound = true; - else if (tx.getIncomingTransfers()) { - for (let incomingTransfer of tx.getIncomingTransfers()) { - if (this.getTransferQuery().meetsCriteria(incomingTransfer, false)) { - matchFound = true; - break; - } - } - } - if (!matchFound) return false; - } - - // at least one output must meet output query if defined - if (this.getOutputQuery() !== undefined) { - if (tx.getOutputs() === undefined || tx.getOutputs().length === 0) return false; - let matchFound = false; - for (let output of tx.getOutputs()) { - if (this.getOutputQuery().meetsCriteria(output, false)) { - matchFound = true; - break; - } - } - if (!matchFound) return false; - } - - return true; // transaction meets filter criteria - } -} - -module.exports = MoneroTxQuery; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroTxWallet.js b/src/main/js/wallet/model/MoneroTxWallet.js deleted file mode 100644 index b4769c2eb..000000000 --- a/src/main/js/wallet/model/MoneroTxWallet.js +++ /dev/null @@ -1,395 +0,0 @@ -const assert = require("assert"); -const BigInteger = require("../../common/biginteger").BigInteger; -const GenUtils = require("../../common/GenUtils"); -const MoneroIncomingTransfer = require("./MoneroIncomingTransfer"); -const MoneroOutgoingTransfer = require("./MoneroOutgoingTransfer"); -const MoneroOutputWallet = require("./MoneroOutputWallet"); -const MoneroTx = require("../../daemon/model/MoneroTx"); - -/** - * Models a Monero transaction with wallet extensions. - * - * @class - * @extends {MoneroTx} - */ -class MoneroTxWallet extends MoneroTx { - - /** - * Construct the model. - * - * @param {MoneroTxWallet|object} state is existing state to initialize from (optional) - */ - constructor(state) { - super(state); - if (state instanceof MoneroTxWallet && state.getTxSet()) this.setTxSet(state.getTxSet()); // preserve reference to tx set - state = this.state; - - // deserialize incoming transfers - if (state.incomingTransfers) { - for (let i = 0; i < state.incomingTransfers.length; i++) { - if (!(state.incomingTransfers[i] instanceof MoneroIncomingTransfer)) { - state.incomingTransfers[i] = new MoneroIncomingTransfer(Object.assign(state.incomingTransfers[i], {tx: this})); - } - } - } - - // deserialize outgoing transfer - if (state.outgoingTransfer && !(state.outgoingTransfer instanceof MoneroOutgoingTransfer)) { - this.setOutgoingTransfer(new MoneroOutgoingTransfer(Object.assign(state.outgoingTransfer, {tx: this}))); - } - - // deserialize inputs - if (state.inputs) { - for (let i = 0; i < state.inputs.length; i++) { - if (!(state.inputs[i] instanceof MoneroOutputWallet)) { - state.inputs[i] = new MoneroOutputWallet(Object.assign(state.inputs[i].toJson(), {tx: this})); - } - } - } - - // deserialize outputs - if (state.outputs) { - for (let i = 0; i < state.outputs.length; i++) { - if (!(state.outputs[i] instanceof MoneroOutputWallet)) { - state.outputs[i] = new MoneroOutputWallet(Object.assign(state.outputs[i].toJson(), {tx: this})); - } - } - } - - // deserialize BigIntegers - if (state.inputSum !== undefined && !(state.inputSum instanceof BigInteger)) state.inputSum = BigInteger.parse(state.inputSum); - if (state.outputSum !== undefined && !(state.outputSum instanceof BigInteger)) state.outputSum = BigInteger.parse(state.outputSum); - if (state.changeAmount !== undefined && !(state.changeAmount instanceof BigInteger)) state.changeAmount = BigInteger.parse(state.changeAmount); - } - - toJson() { - let json = Object.assign({}, this.state, super.toJson()); // merge json onto inherited state - if (this.getIncomingTransfers()) { - json.incomingTransfers = []; - for (let incomingTransfer of this.getIncomingTransfers()) json.incomingTransfers.push(incomingTransfer.toJson()); - } - if (this.getOutgoingTransfer()) json.outgoingTransfer = this.getOutgoingTransfer().toJson(); - if (this.getInputSum()) json.inputSum = this.getInputSum().toString(); - if (this.getOutputSum()) json.outputSum = this.getOutputSum().toString(); - if (this.getChangeAmount()) json.changeAmount = this.getChangeAmount().toString(); - delete json.block; // do not serialize parent block - delete json.txSet; // do not serialize parent tx set - return json; - } - - getTxSet() { - return this.state.txSet; - } - - setTxSet(txSet) { - this.state.txSet = txSet; - return this; - } - - isIncoming() { - return this.state.isIncoming; - } - - setIsIncoming(isIncoming) { - this.state.isIncoming = isIncoming; - return this; - } - - isOutgoing() { - return this.state.isOutgoing; - } - - setIsOutgoing(isOutgoing) { - this.state.isOutgoing = isOutgoing; - return this; - } - - getIncomingAmount() { - if (this.getIncomingTransfers() === undefined) return undefined; - let incomingAmt = BigInteger.parse("0"); - for (let transfer of this.getIncomingTransfers()) incomingAmt = incomingAmt.add(transfer.getAmount()); - return incomingAmt; - } - - getOutgoingAmount() { - return this.getOutgoingTransfer() ? this.getOutgoingTransfer().getAmount() : undefined; - } - - getTransfers(transferQuery) { - let transfers = []; - if (this.getOutgoingTransfer() && (!transferQuery || transferQuery.meetsCriteria(this.getOutgoingTransfer()))) transfers.push(this.getOutgoingTransfer()); - if (this.getIncomingTransfers()) { - for (let transfer of this.getIncomingTransfers()) { - if (!transferQuery || transferQuery.meetsCriteria(transfer)) transfers.push(transfer); - } - } - return transfers; - } - - filterTransfers(transferQuery) { - let transfers = []; - - // collect outgoing transfer or erase if filtered - if (this.getOutgoingTransfer() && (!transferQuery || transferQuery.meetsCriteria(this.getOutgoingTransfer()))) transfers.push(this.getOutgoingTransfer()); - else this.setOutgoingTransfer(undefined); - - // collect incoming transfers or erase if filtered - if (this.getIncomingTransfers()) { - let toRemoves = []; - for (let transfer of this.getIncomingTransfers()) { - if (transferQuery.meetsCriteria(transfer)) transfers.push(transfer); - else toRemoves.push(transfer); - } - this.setIncomingTransfers(this.getIncomingTransfers().filter(function(transfer) { - return !toRemoves.includes(transfer); - })); - if (this.getIncomingTransfers().length === 0) this.setIncomingTransfers(undefined); - } - - return transfers; - } - - getIncomingTransfers() { - return this.state.incomingTransfers; - } - - setIncomingTransfers(incomingTransfers) { - this.state.incomingTransfers = incomingTransfers; - return this; - } - - getOutgoingTransfer() { - return this.state.outgoingTransfer; - } - - setOutgoingTransfer(outgoingTransfer) { - this.state.outgoingTransfer = outgoingTransfer; - return this; - } - - getOutputs(outputQuery) { - if (!outputQuery || !super.getOutputs()) return super.getOutputs(); - let outputs = []; - for (let output of super.getOutputs()) if (!outputQuery || outputQuery.meetsCriteria(output)) outputs.push(output); - return outputs; - } - - setOutputs(outputs) { - - // validate that all outputs are wallet outputs - if (outputs) { - for (let output of outputs) { - if (!(output instanceof MoneroOutputWallet)) throw new MoneroError("Wallet transaction outputs must be of type MoneroOutputWallet"); - } - } - super.setOutputs(outputs); - return this; - } - - filterOutputs(outputQuery) { - let outputs = []; - if (super.getOutputs()) { - let toRemoves = []; - for (let output of super.getOutputs()) { - if (!outputQuery || outputQuery.meetsCriteria(output)) outputs.push(output); - else toRemoves.push(output); - } - this.setOutputs(super.getOutputs().filter(function(output) { - return !toRemoves.includes(output); - })); - if (this.getOutputs().length === 0) this.setOutputs(undefined); - } - return outputs; - } - - getNote() { - return this.state.note; - } - - setNote(note) { - this.state.note = note; - return this; - } - - isLocked() { - return this.state.isLocked; - } - - setIsLocked(isLocked) { - this.state.isLocked = isLocked; - return this; - } - - getInputSum() { - return this.state.inputSum; - } - - setInputSum(inputSum) { - this.state.inputSum = inputSum; - return this; - } - - getOutputSum() { - return this.state.outputSum; - } - - setOutputSum(outputSum) { - this.state.outputSum = outputSum; - return this; - } - - getChangeAddress() { - return this.state.changeAddress; - } - - setChangeAddress(changeAddress) { - this.state.changeAddress = changeAddress; - return this; - } - - getChangeAmount() { - return this.state.changeAmount; - } - - setChangeAmount(changeAmount) { - this.state.changeAmount = changeAmount; - return this; - } - - getNumDummyOutputs() { - return this.state.numDummyOutputs; - } - - setNumDummyOutputs(numDummyOutputs) { - this.state.numDummyOutputs = numDummyOutputs; - return this; - } - - getExtraHex() { - return this.state.extraHex; - } - - setExtraHex(extraHex) { - this.state.extraHex = extraHex; - return this; - } - - copy() { - return new MoneroTxWallet(this); - } - - /** - * Updates this transaction by merging the latest information from the given - * transaction. - * - * Merging can modify or build references to the transaction given so it - * should not be re-used or it should be copied before calling this method. - * - * @param tx is the transaction to merge into this transaction - */ - merge(tx) { - assert(tx instanceof MoneroTxWallet); - if (this === tx) return this; - - // merge base classes - super.merge(tx); - - // merge tx set if they're different which comes back to merging txs - const MoneroTxSet = require("./MoneroTxSet"); - if (this.getTxSet() !== tx.getTxSet()) { - if (this.getTxSet() == undefined) { - this.setTxSet(new MoneroTxSet().setTxs([this])); - } - if (tx.getTxSet() === undefined) { - tx.setTxSet(new MoneroTxSet().setTxs([tx])); - } - this.getTxSet().merge(tx.getTxSet()); - return this; - } - - // merge incoming transfers - if (tx.getIncomingTransfers()) { - if (this.getIncomingTransfers() === undefined) this.setIncomingTransfers([]); - for (let transfer of tx.getIncomingTransfers()) { - transfer.setTx(this); - MoneroTxWallet._mergeIncomingTransfer(this.getIncomingTransfers(), transfer); - } - } - - // merge outgoing transfer - if (tx.getOutgoingTransfer()) { - tx.getOutgoingTransfer().setTx(this); - if (this.getOutgoingTransfer() === undefined) this.setOutgoingTransfer(tx.getOutgoingTransfer()); - else this.getOutgoingTransfer().merge(tx.getOutgoingTransfer()); - } - - // merge simple extensions - this.setIsIncoming(GenUtils.reconcile(this.isIncoming(), tx.isIncoming())); - this.setIsOutgoing(GenUtils.reconcile(this.isOutgoing(), tx.isOutgoing())); - this.setNote(GenUtils.reconcile(this.getNote(), tx.getNote())); - this.setIsLocked(GenUtils.reconcile(this.isLocked(), tx.isLocked())); - this.setInputSum(GenUtils.reconcile(this.getInputSum(), tx.getInputSum())); - this.setOutputSum(GenUtils.reconcile(this.getOutputSum(), tx.getOutputSum())); - this.setChangeAddress(GenUtils.reconcile(this.getChangeAddress(), tx.getChangeAddress())); - this.setChangeAmount(GenUtils.reconcile(this.getChangeAmount(), tx.getChangeAmount())); - this.setNumDummyOutputs(GenUtils.reconcile(this.getNumDummyOutputs(), tx.getNumDummyOutputs())); - this.setExtraHex(GenUtils.reconcile(this.getExtraHex(), tx.getExtraHex())); - - return this; // for chaining - } - - toString(indent = 0, oneLine) { - let str = ""; - - // represent tx with one line string - // TODO: proper csv export - if (oneLine) { - str += this.getHash() + ", "; - str += (this.isConfirmed() ? this.getBlock().getTimestamp() : this.getReceivedTimestamp()) + ", "; - str += this.isConfirmed() + ", "; - str += (this.getOutgoingAmount() ? this.getOutgoingAmount().toString() : "") + ", "; - str += this.getIncomingAmount() ? this.getIncomingAmount().toString() : ""; - return str; - } - - // otherwise stringify all fields - str += super.toString(indent) + "\n"; - str += GenUtils.kvLine("Is incoming", this.isIncoming(), indent); - str += GenUtils.kvLine("Incoming amount", this.getIncomingAmount(), indent); - if (this.getIncomingTransfers()) { - str += GenUtils.kvLine("Incoming transfers", "", indent); - for (let i = 0; i < this.getIncomingTransfers().length; i++) { - str += GenUtils.kvLine(i + 1, "", indent + 1); - str += this.getIncomingTransfers()[i].toString(indent + 2) + "\n"; - } - } - str += GenUtils.kvLine("Is outgoing", this.isOutgoing(), indent); - str += GenUtils.kvLine("Outgoing amount", this.getOutgoingAmount(), indent); - if (this.getOutgoingTransfer()) { - str += GenUtils.kvLine("Outgoing transfer", "", indent); - str += this.getOutgoingTransfer().toString(indent + 1) + "\n"; - } - str += GenUtils.kvLine("Note", this.getNote(), indent); - str += GenUtils.kvLine("Is locked", this.isLocked(), indent); - str += GenUtils.kvLine("Input sum", this.getInputSum(), indent); - str += GenUtils.kvLine("Output sum", this.getOutputSum(), indent); - str += GenUtils.kvLine("Change address", this.getChangeAddress(), indent); - str += GenUtils.kvLine("Change amount", this.getChangeAmount(), indent); - str += GenUtils.kvLine("Num dummy outputs", this.getNumDummyOutputs(), indent); - str += GenUtils.kvLine("Extra hex", this.getExtraHex(), indent); - return str.slice(0, str.length - 1); // strip last newline - } - - // private helper to merge transfers - static _mergeIncomingTransfer(transfers, transfer) { - for (let aTransfer of transfers) { - if (aTransfer.getAccountIndex() === transfer.getAccountIndex() && aTransfer.getSubaddressIndex() === transfer.getSubaddressIndex()) { - aTransfer.merge(transfer); - return; - } - } - transfers.push(transfer); - } -} - -module.exports = MoneroTxWallet; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroWalletConfig.js b/src/main/js/wallet/model/MoneroWalletConfig.js deleted file mode 100644 index 7eba0003d..000000000 --- a/src/main/js/wallet/model/MoneroWalletConfig.js +++ /dev/null @@ -1,242 +0,0 @@ -const GenUtils = require("../../common/GenUtils"); -const MoneroNetworkType = require("../../daemon/model/MoneroNetworkType"); -const MoneroRpcConnection = require("../../common/MoneroRpcConnection"); -const MoneroError = require("../../common/MoneroError"); - -/** - * Configuration to create a Monero wallet. - */ -class MoneroWalletConfig { - - /** - * Construct a configuration to open or create a wallet. - * - * @param {object|MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object - * @param {string} config.path - path of the wallet to open or create - * @param {string} config.password - password of the wallet to open - * @param {string|number} config.networkType - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) - * @param {string} config.serverUri - uri of the wallet's server (optional) - * @param {string} config.serverUsername - username of the wallet's server (optional) - * @param {string} config.serverPassword - password of the wallet's server (optional) - * @param {boolean} config.rejectUnauthorized - reject self-signed server certificates if true (defaults to true) - * @param {MoneroRpcConnection|object} config.server - MoneroRpcConnection or equivalent JS object configuring the server connection (optional) - * @param {Uint8Array} config.keysData - wallet keys data to open (optional) - * @param {Uint8Array} config.cacheData - wallet cache data to open (optional) - * @param {boolean} config.proxyToWorker - proxies wallet operations to a web worker in order to not block the browser's main thread (default: false) - * @param {fs} config.fs - Node.js compatible file system to use (defaults to disk or in-memory FS if browser) - * @param {boolean} config.saveCurrent - specifies if the current RPC wallet should be saved before being closed - */ - constructor(config) { - - // initialize internal config - if (!config) config = {}; - else if (config instanceof MoneroWalletConfig) config = config.toJson(); - else if (typeof config === "object") config = Object.assign({}, config); - else throw new MoneroError("config must be a MoneroWalletConfig or JavaScript object"); - this.config = config; - - // normalize config - this.setNetworkType(config.networkType); - if (config.server) this.setServer(config.server); - delete this.config.server; - - // check for unsupported fields - for (let key of Object.keys(this.config)) { - if (!GenUtils.arrayContains(MoneroWalletConfig.SUPPORTED_FIELDS, key)) { - throw new MoneroError("Wallet config includes unsupported field: '" + key + "'"); - } - } - } - - toJson() { - return Object.assign({}, this.config); - } - - getPath() { - return this.config.path; - } - - setPath(path) { - this.config.path = path; - return this; - } - - getPassword() { - return this.config.password; - } - - setPassword(password) { - this.config.password = password; - return this; - } - - getNetworkType() { - return this.config.networkType; - } - - setNetworkType(networkTypeOrStr) { - this.config.networkType = typeof networkTypeOrStr === "string" ? MoneroNetworkType.parse(networkTypeOrStr) : networkTypeOrStr; - return this; - } - - getServer() { - return !this.config.serverUri ? undefined : new MoneroRpcConnection({uri: this.config.serverUri, username: this.config.serverUsername, password: this.config.serverPassword, rejectUnauthorized: this.config.rejectUnauthorized}) - } - - setServer(server) { - if (server && !(server instanceof MoneroRpcConnection)) server = new MoneroRpcConnection(server); - this.config.serverUri = server === undefined ? undefined : server.getUri(); - this.config.serverUsername = server === undefined ? undefined : server.getUsername(); - this.config.serverPassword = server === undefined ? undefined : server.getPassword(); - this.config.rejectUnauthorized = server === undefined ? undefined : server.getRejectUnauthorized(); - return this; - } - - getServerUri() { - return this.config.serverUri; - } - - setServerUri(serverUri) { - this.config.serverUri = serverUri; - return this; - } - - getServerUsername() { - return this.config.serverUsername; - } - - setServerUsername(serverUsername) { - this.config.serverUsername = serverUsername; - return this; - } - - getServerPassword() { - return this.config.serverPassword; - } - - setServerPassword(serverPassword) { - this.config.serverPassword = serverPassword; - return this; - } - - getRejectUnauthorized() { - return this.config.rejectUnauthorized; - } - - setRejectUnauthorized(rejectUnauthorized) { - this.config.rejectUnauthorized = rejectUnauthorized; - return this; - } - - getMnemonic() { - return this.config.mnemonic; - } - - setMnemonic(mnemonic) { - this.config.mnemonic = mnemonic; - return this; - } - - getSeedOffset() { - return this.config.seedOffset; - } - - setSeedOffset(seedOffset) { - this.config.seedOffset = seedOffset; - return this; - } - - getPrimaryAddress() { - return this.config.primaryAddress; - } - - setPrimaryAddress(primaryAddress) { - this.config.primaryAddress = primaryAddress; - return this; - } - - getPrivateViewKey() { - return this.config.privateViewKey; - } - - setPrivateViewKey(privateViewKey) { - this.config.privateViewKey = privateViewKey; - return this; - } - - getPrivateSpendKey() { - return this.config.privateSpendKey; - } - - setPrivateSpendKey(privateSpendKey) { - this.config.privateSpendKey = privateSpendKey; - return this; - } - - getRestoreHeight() { - return this.config.restoreHeight; - } - - setRestoreHeight(restoreHeight) { - this.config.restoreHeight = restoreHeight; - return this; - } - - getLanguage() { - return this.config.language; - } - - setLanguage(language) { - this.config.language = language; - return this; - } - - getSaveCurrent() { - return this.config.saveCurrent; - } - - setSaveCurrent(saveCurrent) { - this.config.saveCurrent = saveCurrent; - return this; - } - - getProxyToWorker() { - return this.config.proxyToWorker; - } - - setProxyToWorker(proxyToWorker) { - this.config.proxyToWorker = proxyToWorker; - return this; - } - - getFs() { - return this.config.fs; - } - - setFs(fs) { - this.config.fs = fs; - return this; - } - - getKeysData() { - return this.config.keysData; - } - - setKeysData(keysData) { - this.config.keysData = keysData; - return this; - } - - getCacheData() { - return this.config.cacheData; - } - - setCacheData(cacheData) { - this.config.cacheData = cacheData; - return this; - } -} - -MoneroWalletConfig.SUPPORTED_FIELDS = ["path", "password", "networkType", "serverUri", "serverUsername", "serverPassword", "rejectUnauthorized", "mnemonic", "seedOffset", "primaryAddress", "privateViewKey", "privateSpendKey", "restoreHeight", "language", "saveCurrent", "proxyToWorker", "fs", "keysData", "cacheData"]; - -module.exports = MoneroWalletConfig; \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroWalletListener.js b/src/main/js/wallet/model/MoneroWalletListener.js deleted file mode 100644 index a65c8700a..000000000 --- a/src/main/js/wallet/model/MoneroWalletListener.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Default wallet listener which takes no action on notifications. - */ -class MoneroWalletListener { - - /** - * Invoked as the wallet is synchronized. - * - * @param {number} height - height of the synced block - * @param {number} startHeight - starting height of the sync request - * @param {number} endHeight - ending height of the sync request - * @param {number} percentDone - sync progress as a percentage - * @param {string} message - human-readable description of the current progress - */ - onSyncProgress(height, startHeight, endHeight, percentDone, message) { } - - /** - * Invoked when a new block is added to the chain. - * - * @param {int} height - the height of the block added to the chain - */ - onNewBlock(height) { } - - /** - * Invoked when the wallet's balances change. - * - * @param {BigInteger} newBalance - new wallet balance - * @param {BigInteger} newUnlockedBalance - new unlocked wallet balance - */ - onBalancesChanged(newBalance, newUnlockedBalance) { } - - /** - * Invoked when the wallet receives an unconfirmed output, when the output is confirmed, - * and when the output is unlocked. - * - * @param {MoneroOutputWallet} output - the received output - */ - onOutputReceived(output) { } - - /** - * Invoked when the wallet spends an output. - * - * @param {MoneroOutputWallet} output - the spent output - */ - onOutputSpent(output) { } -} - -module.exports = MoneroWalletListener; \ No newline at end of file diff --git a/src/main/js/common/Filter.js b/src/main/ts/common/Filter.ts similarity index 76% rename from src/main/js/common/Filter.js rename to src/main/ts/common/Filter.ts index eee991fda..d9e3ef85d 100644 --- a/src/main/js/common/Filter.js +++ b/src/main/ts/common/Filter.ts @@ -3,7 +3,7 @@ * * @private */ -class Filter { +export default class Filter { /** * Indicates if the given value meets the criteria of this filter. @@ -11,7 +11,7 @@ class Filter { * @param val is the value to test * @return true if the value meets the criteria of this filter, false otherwise */ - meetsCriteria(val) { + meetsCriteria(val: any): boolean { throw new Error("Subclass must implement"); } @@ -23,9 +23,7 @@ class Filter { * @param array is the array to apply the filter to * @return the new array of filtered elements */ - static apply(filter, array) { - return array.filter(elem => filter.meetsCriteria(elem)); + static apply(filter: Filter, array: any[]): any[] { + return array.filter(elem => !filter || filter.meetsCriteria(elem)); } } - -module.exports = Filter; \ No newline at end of file diff --git a/src/main/js/common/GenUtils.js b/src/main/ts/common/GenUtils.ts similarity index 76% rename from src/main/js/common/GenUtils.js rename to src/main/ts/common/GenUtils.ts index 8367c1ca5..343a5f6d7 100644 --- a/src/main/js/common/GenUtils.js +++ b/src/main/ts/common/GenUtils.ts @@ -1,5 +1,8 @@ -const assert = require("assert"); -const BigInteger = require("./biginteger").BigInteger; +import assert from "assert"; +import async from "async"; +import { ChildProcess } from "child_process"; + +declare var Deno: any; /** * MIT License @@ -25,19 +28,16 @@ const BigInteger = require("./biginteger").BigInteger; /** * Collection of general purpose utilities. - * - * TODO: could pull in assert and remove these asserts - * TODO: needs cleanup as ES6+ utility class */ -class GenUtils { +export default class GenUtils { /** * Indicates if the given argument is defined. * - * @param arg is the arg to test - * @returns true if the given arg is defined, false otherwise + * @param {any} arg is the arg to test + * @return {boolean} true if the given arg is defined, false otherwise */ - static isDefined(arg) { + static isDefined(arg: any): boolean { return typeof arg !== 'undefined'; } @@ -45,19 +45,19 @@ class GenUtils { * Indicates if the given argument is undefined. * * @param arg is the arg to test - * @returns true if the given arg is undefined, false otherwise + * @return {boolean} true if the given arg is undefined, false otherwise */ - static isUndefined(arg) { + static isUndefined(arg): boolean { return typeof arg === 'undefined'; } /** * Indicates if the given arg is initialized. * - * @param arg is the arg to test - * @returns true if the given arg is initialized, false otherwise + * @param {any} arg is the arg to test + * @return {boolean} true if the given arg is initialized, false otherwise */ - static isInitialized(arg) { + static isInitialized(arg: any): boolean { return arg !== undefined && arg !== null; } @@ -65,9 +65,9 @@ class GenUtils { * Indicates if the given arg is uninitialized. * * @param arg is the arg to test - * @returns true if the given arg is uninitialized, false otherwise + * @return true if the given arg is uninitialized, false otherwise */ - static isUninitialized(arg) { + static isUninitialized(arg: any): boolean { if (!arg) return true; return false; } @@ -75,74 +75,71 @@ class GenUtils { /** * Indicates if the given argument is a number. * - * @param arg is the argument to test - * @returns true if the argument is a number, false otherwise + * @param {any} arg is the argument to test + * @return {boolean} true if the argument is a number, false otherwise */ - static isNumber(arg) { + static isNumber(arg: any): boolean { return !isNaN(parseFloat(arg)) && isFinite(arg); } /** * Indicates if the given argument is an integer. * - * @param arg is the argument to test - * @returns true if the given argument is an integer, false otherwise + * @param {any} arg is the argument to test + * @return {boolean} true if the given argument is an integer, false otherwise */ - static isInt(arg) { - return arg === parseInt(Number(arg)) && !isNaN(arg) && !isNaN(parseInt(arg, 10)); + static isInt(arg: any): boolean { + return arg === parseInt("" + Number(arg)) && !isNaN(arg) && !isNaN(parseInt(arg, 10)); } /** * Indicates if the given argument is an array. * - * TODO: remove this entirely since just a direct wrapper? - * TODO: this method returns true for object - * - * @param arg is the argument to test as being an array - * @returns true if the argument is an array, false otherwise + * @param {any} arg is the argument to test as being an array + * @return {booolean} true if the argument is an array, false otherwise */ - static isArray(arg) { - return Array.isArray(arg); + static isArray(arg: any): boolean { + return arg instanceof Array && Array.isArray(arg); } /** * Indicates if the given argument is a string. * - * @param arg is the argument to test as being a string - * @returns true if the argument is a string, false otherwise + * @param {any} arg is the argument to test as being a string + * @return {boolean} true if the argument is a string, false otherwise */ - static isString(arg) { + static isString(arg: any): boolean { return typeof arg === 'string'; } /** * Determines if the given argument is a boolean. * - * @param arg is the argument to test as being a boolean - * @returns true if the argument is a boolean, false otherwise + * @param {any} arg is the argument to test as being a boolean + * @return {boolean} true if the argument is a boolean, false otherwise */ - static isBoolean(arg) { + static isBoolean(arg: any): boolean { return typeof(arg) == typeof(true); } /** * Determines if the given argument is a static. * - * @param arg is the argument to test as being a static - * @returns true if the argument is a static, false otherwise + * @param {any} arg is the argument to test as being a static + * @return {boolean} true if the argument is a static, false otherwise */ - static isFunction(arg) { - return typeof arg === "static"; + static isFunction(arg: any): boolean { + return typeof arg === "function"; } /** * Indicates if the given argument is an object and optionally if it has the given constructor name. * - * @param arg is the argument to test - * @param obj is an object to test arg instanceof obj (optional) - * @returns true if the given argument is an object and optionally has the given constructor name + * @param {any} arg is the argument to test + * @param {any} obj is an object to test arg instanceof obj (optional) + * @return {boolean} true if the given argument is an object and optionally has the given constructor name */ - static isObject(arg, obj) { + static isObject(arg: any, obj?: any): boolean { if (!arg) return false; if (typeof arg !== 'object') return false; if (obj && !(arg instanceof obj)) return false; @@ -152,10 +149,10 @@ class GenUtils { /** * Determines if all alphabet characters in the given string are upper case. * - * @param str is the string to test - * @returns true if the string is upper case, false otherwise + * @param {string} str is the string to test + * @return {boolean} true if the string is upper case, false otherwise */ - static isUpperCase(str) { + static isUpperCase(str: string): boolean { return str.toUpperCase() === str; } @@ -176,7 +173,7 @@ class GenUtils { * @param msg is the message to throw if the argument is not hex */ static assertHex(str, msg) { - GenUtils.assertTrue(isHex(str), msg ? msg : "Argument asserted as hex but is not hex"); + GenUtils.assertTrue(GenUtils.isHex(str), msg ? msg : "Argument asserted as hex but is not hex"); } /** @@ -185,7 +182,7 @@ class GenUtils { * Credit: https://github.com/roryrjb/is-hex/blob/master/is-hex.js. * * @param str is the string to test - * @returns true if the given string is hexidecimal, false otherwise + * @return true if the given string is hexidecimal, false otherwise */ static isHex(arg) { if (typeof arg !== 'string') return false; @@ -209,7 +206,7 @@ class GenUtils { * @param msg is the message to throw if the argument is not base58 */ static assertBase58(str, msg) { - GenUtils.assertTrue(isBase58(str), msg ? msg : "Argument asserted as base58 but is not base58"); + GenUtils.assertTrue(GenUtils.isBase58(str), msg ? msg : "Argument asserted as base58 but is not base58"); } /** @@ -228,7 +225,7 @@ class GenUtils { * @param msg is the message to throw if the argument is not base64 */ static assertBase64(str, msg) { - GenUtils.assertTrue(isBase64(str), msg ? msg : "Argument asserted as base64 but is not base64"); + GenUtils.assertTrue(GenUtils.isBase64(str), msg ? msg : "Argument asserted as base64 but is not base64"); } /** @@ -249,19 +246,19 @@ class GenUtils { * * @param msg defines the message to throw the exception with (optional) */ - static fail(msg) { + static fail(msg?) { throw new Error(msg ? msg : "Failure (no message)"); } /** - * Asserts that the given boolean is true. Throws an exception if not a boolean or false. + * Asserts that the given condition is true. Throws an exception if not a boolean or false. * - * @param bool is the boolean to assert true - * @param msg is the message to throw if bool is false (optional) + * @param {boolean} condition is the boolean to assert true + * @param {string} [msg] is the message to throw if condition is false (optional) */ - static assertTrue(bool, msg) { - if (typeof bool !== 'boolean') throw new Error("Argument is not a boolean"); - if (!bool) throw new Error(msg ? msg : "Boolean asserted as true but was false"); + static assertTrue(condition, msg?) { + if (typeof condition !== 'boolean') throw new Error("Argument is not a boolean"); + if (!condition) throw new Error(msg ? msg : "Boolean asserted as true but was false"); } /** @@ -270,7 +267,7 @@ class GenUtils { * @param bool is the boolean to assert false * @param msg is the message to throw if bool is true (optional) */ - static assertFalse(bool, msg) { + static assertFalse(bool, msg?) { if (typeof bool !== 'boolean') throw new Error("Argument is not a boolean"); if (bool) throw new Error(msg ? msg : "Boolean asserted as false but was true"); } @@ -281,7 +278,7 @@ class GenUtils { * @param arg is the argument to assert null * @param msg is the message to throw if arg is not null (optional) */ - static assertNull(arg, msg) { + static assertNull(arg, msg?) { if (arg !== null) throw new Error(msg ? msg : "Argument asserted as null but was not null: " + arg); } @@ -291,7 +288,7 @@ class GenUtils { * @param arg is the argument to assert not null * @param msg is the message to throw if arg is null (optional) */ - static assertNotNull(arg, msg) { + static assertNotNull(arg, msg?) { if (arg === null) throw new Error(msg ? msg : "Argument asserted as not null but was null"); } @@ -301,7 +298,7 @@ class GenUtils { * @param arg is the argument to assert defined * @param msg is the message to throw if arg is undefined (optional) */ - static assertDefined(arg, msg) { + static assertDefined(arg, msg?) { if (GenUtils.isUndefined(arg)) throw new Error(msg ? msg : "Argument asserted as defined but was undefined"); } @@ -311,7 +308,7 @@ class GenUtils { * @param arg is the argument to assert undefined * @param msg is the message to throw if arg is defined (optional) */ - static assertUndefined(arg, msg) { + static assertUndefined(arg, msg?) { if (GenUtils.isDefined(arg)) throw new Error(msg ? msg : "Argument asserted as undefined but was defined: " + arg); } @@ -321,7 +318,7 @@ class GenUtils { * @param arg is the argument to assert as initialized * @param msg is the message to throw if arg is not initialized (optional) */ - static assertInitialized(arg, msg) { + static assertInitialized(arg, msg?) { if (GenUtils.isUninitialized(arg)) { throw new Error(msg ? msg : "Argument asserted as initialized but was " + arg); } @@ -333,7 +330,7 @@ class GenUtils { * @param arg is the argument to assert as uninitialized * @param msg is the message to throw if arg is initialized (optional) */ - static assertUninitialized(arg, msg) { + static assertUninitialized(arg, msg?) { if (GenUtils.isInitialized(arg)) throw new Error(msg ? msg : "Argument asserted as uninitialized but was initialized"); } @@ -344,8 +341,8 @@ class GenUtils { * @param arg2 is an argument to assert as equal * @param msg is the message to throw if the arguments are not equal */ - static assertEquals(arg1, arg2, msg) { - GenUtils.assertTrue(equals(arg1, arg2), msg ? msg : "Arguments asserted as equal but are not equal: " + arg1 + " vs " + arg2); + static assertEquals(arg1, arg2, msg?) { + GenUtils.assertTrue(GenUtils.equals(arg1, arg2), msg ? msg : "Arguments asserted as equal but are not equal: " + arg1 + " vs " + arg2); } /** @@ -355,7 +352,7 @@ class GenUtils { * @param arg2 is an argument to assert as not equal * @param msg is the message to throw if the arguments are equal */ - static assertNotEquals(arg1, arg2, msg) { + static assertNotEquals(arg1, arg2, msg?) { if (arg1 === arg2) throw new Error(msg ? msg : "Arguments asserted as not equal but are equal: " + arg1 + " vs " + arg2); } @@ -365,7 +362,7 @@ class GenUtils { * @param arg is the argument to assert as an integer * @param msg is the message to throw if the argument is not an integer */ - static assertInt(arg, msg) { + static assertInt(arg, msg?) { if (!GenUtils.isInt(arg)) throw new Error(msg ? msg : "Argument asserted as an integer but is not an integer"); } @@ -375,7 +372,7 @@ class GenUtils { * @param arg is the argument to assert as a number * @param msg is the message to throw if the argument is not a number */ - static assertNumber(arg, msg) { + static assertNumber(arg, msg?) { if (!GenUtils.isNumber(arg)) throw new Error(msg ? msg : "Argument asserted as a number but is not a number"); } @@ -385,7 +382,7 @@ class GenUtils { * @param arg is the argument to assert as a boolean * @param msg is the message to throw if the argument is not a boolean */ - static assertBoolean(arg, msg) { + static assertBoolean(arg, msg?) { if (!GenUtils.isBoolean(arg)) throw new Error(msg ? msg : "Argument asserted as a boolean but is not a boolean"); } @@ -395,7 +392,7 @@ class GenUtils { * @param arg is the argument to assert as a string * @param msg is the message to throw if the argument is not a string */ - static assertString(arg, msg) { + static assertString(arg, msg?) { if (!GenUtils.isString(arg)) throw new Error(msg ? msg : "Argument asserted as a string but is not a string: " + arg); } @@ -405,7 +402,7 @@ class GenUtils { * @param arg is the argument to assert as an array * @param msg is the message to throw if the argument is not an array */ - static assertArray(arg, msg) { + static assertArray(arg, msg?) { if (!GenUtils.isArray(arg)) throw new Error(msg ? msg : "Argument asserted as an array but is not an array"); } @@ -415,7 +412,7 @@ class GenUtils { * @param arg is the argument to assert as a static * @param msg is the message to throw if the argument is not a static */ - static assertFunction(arg, msg) { + static assertFunction(arg, msg?) { if (!GenUtils.isFunction(arg)) throw new Error(msg ? msg : "Argument asserted as a static but is not a static"); } @@ -426,12 +423,12 @@ class GenUtils { * @param obj is an object to assert arg instanceof obj (optional) * @param msg is the message to throw if the argument is not the specified object */ - static assertObject(arg, obj, msg) { + static assertObject(arg, obj, msg?) { GenUtils.assertInitialized(arg, msg); if (obj) { - if (!isObject(arg, obj)) throw new Error(msg ? msg : "Argument asserted as object '" + obj.name + "' but was not"); + if (!GenUtils.isObject(arg, obj)) throw new Error(msg ? msg : "Argument asserted as object '" + obj.name + "' but was not"); } else { - if (!isObject(arg)) throw new Error(msg ? msg : "Argument asserted as object but was not"); + if (!GenUtils.isObject(arg)) throw new Error(msg ? msg : "Argument asserted as object but was not"); } } @@ -457,7 +454,7 @@ class GenUtils { let args = []; for (let i = 1; i < arguments.length; i++) args.push(arguments[i]); for (let i = 0; i < fns.length; i++) { - assertFunction(fns[i], "Functions[" + i + "] is not a static"); + GenUtils.assertFunction(fns[i], "Functions[" + i + "] is not a static"); fns[i].apply(null, args); } } @@ -466,7 +463,7 @@ class GenUtils { * Returns the power set of the given array. * * @param arr is the array to get the power set of - * @returns [][] is the power set of the given array + * @return [][] is the power set of the given array */ static getPowerSet(arr) { let fn = function(n, src, got, all) { @@ -498,10 +495,10 @@ class GenUtils { * returns [][] is the power set of the given array whose elements are the given size */ static getPowerSetOfLength(arr, size) { - assertInitialized(arr); - assertInitialized(size); + GenUtils.assertInitialized(arr); + GenUtils.assertInitialized(size); GenUtils.assertTrue(size >= 1); - let powerSet = getPowerSet(arr); + let powerSet = GenUtils.getPowerSet(arr); let powerSetOfLength = []; for (let i = 0; i < powerSet.length; i++) { if (powerSet[i].length === size) { @@ -515,7 +512,7 @@ class GenUtils { * Returns an array of indices of the given size. * * @param size specifies the size to get indices for - * @returns array of the given size with indices starting at 0 + * @return array of the given size with indices starting at 0 */ static getIndices(size) { let indices = []; @@ -529,7 +526,7 @@ class GenUtils { * Returns a new array containing unique elements of the given array. * * @param arr is the array to return unique elements from - * @returns a new array with the given array's unique elements + * @return a new array with the given array's unique elements */ static toUniqueArray(arr) { return arr.filter(function(value, index, self) { @@ -541,7 +538,7 @@ class GenUtils { * Copies the given array. * * @param arr is the array to copy - * @returns a copy of the given array + * @return a copy of the given array */ static copyArray(arr) { GenUtils.assertArray(arr); @@ -555,7 +552,7 @@ class GenUtils { * * @param arr is the array to remove the value from * @param val is the value to remove from the array - * @returns true if the value is found and removed, false otherwise + * @return true if the value is found and removed, false otherwise */ static remove(arr, val) { let found = false; @@ -573,7 +570,7 @@ class GenUtils { * Returns a copy of the given array where each element is lowercase. * * @param arr is the array to convert to lowercase - * @returns a copy of the given array where each element is lowercase + * @return a copy of the given array where each element is lowercase */ static toLowerCaseArray(arr) { let arr2 = []; @@ -587,7 +584,7 @@ class GenUtils { * Listifies the given argument. * * @param arrOrElem is an array or an element in the array - * @returns an array which is the given arg if it's an array or an array with the given arg as an element + * @return an array which is the given arg if it's an array or an array with the given arg as an element */ static listify(arrOrElem) { return GenUtils.isArray(arrOrElem) ? arrOrElem : [arrOrElem]; @@ -596,12 +593,12 @@ class GenUtils { /** * Indicates if the given array contains the given object. * - * @param {object[]} arr - array that may or may not contain the object - * @param {object} obj - object to check for inclusion in the array - * @param {boolean} compareByReference - compare strictly by reference, forgoing deep equality check - * @returns true if the array contains the object, false otherwise + * @param {any} arr - array that may or may not contain the object + * @param {any} obj - object to check for inclusion in the array + * @param {boolean} [compareByReference] - compare strictly by reference, forgoing deep equality check (default false) + * @return true if the array contains the object, false otherwise */ - static arrayContains(arr, obj, compareByReference) { + static arrayContains(arr, obj, compareByReference = false) { GenUtils.assertTrue(GenUtils.isArray(arr)); for (let i = 0; i < arr.length; i++) { if (arr[i] === obj) return true; @@ -615,7 +612,7 @@ class GenUtils { * * @param str is the string to search for a substring * @param substring is the substring to searchin within the string - * @returns true if the substring is within the string, false otherwise + * @return true if the substring is within the string, false otherwise */ static strContains(str, substring) { return str.indexOf(substring) > -1; @@ -626,7 +623,7 @@ class GenUtils { * * @param arr1 is an array to compare * @param arr2 is an array to compare - * @returns true if the arrays are equal, false otherwise + * @return true if the arrays are equal, false otherwise */ static arraysEqual(arr1, arr2) { if (arr1 === arr2) return true; @@ -648,7 +645,7 @@ class GenUtils { * * @param arg1 is an argument to compare * @param arg2 is an argument to compare - * @returns true if the arguments are deep equals, false otherwise + * @return true if the arguments are deep equals, false otherwise */ static equals(arg1, arg2) { if (GenUtils.isArray(arg1) && GenUtils.isArray(arg2)) return GenUtils.arraysEqual(arg1, arg2); @@ -663,7 +660,7 @@ class GenUtils { * * @param map1 is a map to compare * @param map2 is a map to compare - * @returns true if the maps have identical keys and values, false otherwise + * @return true if the maps have identical keys and values, false otherwise */ static objectsEqual(map1, map2) { let keys1 = Object.keys(map1); @@ -726,12 +723,12 @@ class GenUtils { static getCombinations(arr, combinationSize) { // validate input - assertInitialized(arr); - assertInitialized(combinationSize); + GenUtils.assertInitialized(arr); + GenUtils.assertInitialized(combinationSize); GenUtils.assertTrue(combinationSize >= 1); // get combinations of array indices of the given size - let indexCombinations = getPowerSetOfLength(getIndices(arr.length), combinationSize); + let indexCombinations = GenUtils.getPowerSetOfLength(GenUtils.getIndices(arr.length), combinationSize); // collect combinations from each combination of array indices let combinations = []; @@ -758,7 +755,7 @@ class GenUtils { * * @param name is the name of the file to download * @param contents are the string contents of the file to download - * @returns 'a' dom element with downloadable file + * @return 'a' dom element with downloadable file */ static getDownloadableA(name, contents) { let a = window.document.createElement('a'); @@ -769,21 +766,11 @@ class GenUtils { return a; } - /** - * Returns the given node's outer HTML. - * - * @param node is the node to get outer HTML for - * @returns the outer HTML of the given node - */ - static getOuterHtml(node) { - return $('
').append($(node).clone()).html(); - } - /** * Copies properties in the given object to a new object. * * @param obj is object to copy properties for - * @returns a new object with properties copied from the given object + * @return a new object with properties copied from the given object */ static copyProperties(obj) { return JSON.parse(JSON.stringify(obj)) @@ -797,34 +784,14 @@ class GenUtils { static deleteProperties(obj) { let props = []; for (let prop in obj) props.push(prop); // TODO: if (obj.hasOwnProperty(prop)) { ... - for (i = 0; i < props.length; i++) delete obj[props[i].toString()]; - } - - /** - * Converts a CSV string to a 2-dimensional array of strings. - * - * @param csv is the CSV string to convert - * @returns a 2-dimensional array of strings - */ - static csvToArr(csv) { - return $.csv.toArrays(csv); - } - - /** - * Converts the given array to a CSV string. - * - * @param arr is a 2-dimensional array of strings - * @returns the CSV string - */ - static arrToCsv(arr) { - return $.csv.fromObjects(arr, {headers: false}); + for (let i = 0; i < props.length; i++) delete obj[props[i].toString()]; } /** * Indicates if the given string contains whitespace. * * @param str is the string to test - * @returns true if the string contains whitespace, false otherwise + * @return true if the string contains whitespace, false otherwise */ static hasWhitespace(str) { return /\s/g.test(str); @@ -834,7 +801,7 @@ class GenUtils { * Indicates if the given character is whitespace. * * @param char is the character to test - * @returns true if the given character is whitespace, false otherwise + * @return true if the given character is whitespace, false otherwise */ static isWhitespace(char) { return /\s/.test(char); @@ -844,7 +811,7 @@ class GenUtils { * Indicates if the given character is a newline. * * @param char is the character to test - * @returns true if the given character is a newline, false otherwise + * @return true if the given character is a newline, false otherwise */ static isNewline(char) { return char === '\n' || char === '\r'; @@ -854,12 +821,12 @@ class GenUtils { * Counts the number of non-whitespace characters in the given string. * * @param str is the string to count the number of non-whitespace characters in - * @returns int is the number of non-whitespace characters in the given string + * @return int is the number of non-whitespace characters in the given string */ static countNonWhitespaceCharacters(str) { let count = 0; for (let i = 0; i < str.length; i++) { - if (!isWhitespace(str.charAt(i))) count++; + if (!GenUtils.isWhitespace(str.charAt(i))) count++; } return count; } @@ -868,7 +835,7 @@ class GenUtils { * Returns tokens separated by whitespace from the given string. * * @param str is the string to get tokens from - * @returns string[] are the tokens separated by whitespace within the string + * @return string[] are the tokens separated by whitespace within the string */ static getWhitespaceTokens(str) { return str.match(/\S+/g); @@ -887,7 +854,7 @@ class GenUtils { /** * Returns the document's first stylesheet which has no href. * - * @returns StyleSheet is the internal stylesheet + * @return StyleSheet is the internal stylesheet */ static getInternalStyleSheet() { for (let i = 0; i < document.styleSheets.length; i++) { @@ -900,11 +867,11 @@ class GenUtils { /** * Returns the document's internal stylesheet as text. * - * @returns str is the document's internal stylesheet + * @return str is the document's internal stylesheet */ static getInternalStyleSheetText() { let internalCss = ""; - let internalStyleSheet = getInternalStyleSheet(); + let internalStyleSheet = GenUtils.getInternalStyleSheet(); if (!internalStyleSheet) return null; for (let i = 0; i < internalStyleSheet.cssRules.length; i++) { internalCss += internalStyleSheet.cssRules[i].cssText + "\n"; @@ -921,7 +888,7 @@ class GenUtils { * content.dependencyPaths specifies paths to js, css, or img paths * content.internalCss is css to embed in the html document * content.metas are meta elements with keys/values to include - * @returns str is the document string + * @return str is the document string */ static buildHtmlDocument(content) { let str = ""; @@ -929,7 +896,7 @@ class GenUtils { // add metas if (content.metas) { - let metas = listify(content.metas); + let metas = GenUtils.listify(content.metas); for (let i = 0; i < metas.length; i++) { let meta = metas[i]; let elem = document.createElement("meta"); @@ -948,7 +915,7 @@ class GenUtils { // add dependency paths if (content.dependencyPaths) { - let dependencyPaths = listify(content.dependencyPaths); + let dependencyPaths = GenUtils.listify(content.dependencyPaths); for (let i = 0; i < dependencyPaths.length; i++) { let dependencyPath = dependencyPaths[i]; if (dependencyPath.endsWith(".js")) str += ""; @@ -977,19 +944,19 @@ class GenUtils { static newWindow(content, onLoad) { let onLoadCalled = false; let w = window.open(); - if (!isInitialized(w) || !isInitialized(w.document)) { + if (!GenUtils.isInitialized(w) || !GenUtils.isInitialized(w.document)) { onLoadOnce(new Error("Could not get window reference")); return; } w.opener = null; - w.document.write(buildHtmlDocument(content)); + w.document.write(GenUtils.buildHtmlDocument(content)); w.addEventListener('load', function() { onLoadOnce(null, w); }); w.document.close(); // prevents onLoad() from being called multiple times - function onLoadOnce(err, window) { + function onLoadOnce(err, window?) { if (onLoadCalled) return; onLoadCalled = true; if (onLoad) onLoad(err, window); @@ -1055,7 +1022,7 @@ class GenUtils { * Determines if the given file is a zip file. * * @param file is a file - * @returns true if the given file is a zip file, false otherwise + * @return true if the given file is a zip file, false otherwise */ static isZipFile(file) { return file.name.endsWith(".zip") || file.type === 'application/zip'; @@ -1065,27 +1032,17 @@ class GenUtils { * Determines if the given file is a json file. * * @param file is a file - * @returns true if the given file is a json file, false otherwise + * @return true if the given file is a json file, false otherwise */ static isJsonFile(file) { return file.name.endsWith(".json") || file.type === 'application/json'; } - /** - * Determines if the given file is a csv file. - * - * @param file is a file - * @returns true if the given file is a csv file, false otherwise - */ - static isCsvFile(file) { - return file.name.endsWith(".csv") || file.type === 'text/csv'; - } - /** * Determines if the given file is a txt file. * * @param file is a file - * @returns true if the given file is a txt file, false otherwise + * @return true if the given file is a txt file, false otherwise */ static isTxtFile(file) { return file.name.endsWith(".txt") || file.type === 'text/plain'; @@ -1103,7 +1060,7 @@ class GenUtils { // listify paths if (!GenUtils.isArray(paths)) { - GenUtils.assertTrue(isString(paths)); + GenUtils.assertTrue(GenUtils.isString(paths)); paths = [paths]; } @@ -1131,7 +1088,7 @@ class GenUtils { * Returns a string indentation of the given length; * * @param length is the length of the indentation - * @returns {string} is an indentation string of the given length + * @return {string} is an indentation string of the given length */ static getIndent(length) { let str = ""; @@ -1143,7 +1100,7 @@ class GenUtils { // Polyfill Object.assign() // Credit: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign - if (typeof Object.assign != 'static') { + if (typeof Object.assign != 'function') { // Must be writable: true, enumerable: false, configurable: true Object.defineProperty(Object, "assign", { value: function assign(target, varArgs) { // .length of static is 2 @@ -1173,13 +1130,6 @@ class GenUtils { }); } - /** - * Polyfill str.replaceAt(idx, replacement). - */ - String.prototype.replaceAt=function(idx, replacement) { - return this.substr(0, idx) + replacement + this.substr(idx + replacement.length); - } - /** * Polyfill str.startsWith(searchString, position). * @@ -1199,23 +1149,6 @@ class GenUtils { else position |= 0; // round position return this.substr(position - searchString.length, searchString.length) === searchString; } - - /** - * Removes the given value from the array. - * - * @returns true if the value was found and removed, false otherwise - */ - Array.prototype.removeVal = function(val) { - var found = false; - for (var i = 0; i < this.length; i++) { - if (this[i] == val) { - found = true; - this.splice(i, 1); - i--; - } - } - return found;; - }; } /** @@ -1238,7 +1171,17 @@ class GenUtils { static isBrowser() { let isWorker = typeof importScripts === 'function'; let isBrowserMain = new Function("try {return this===window;}catch(e){return false;}")(); - return isWorker || isBrowserMain; + let isJsDom = isBrowserMain ? new Function("try {return window.navigator.userAgent.includes('jsdom');}catch(e){return false;}")() : false; + return isWorker || (isBrowserMain && !isJsDom); + } + + /** + * Indicates if the current environment is Deno + * + * @return {boolean} true if the environment is Deno, false otherwise + */ + static isDeno() { + return typeof Deno === "object" && Deno.hasOwnProperty("version") && typeof Deno.version === "object" && Deno.version.hasOwnProperty("deno") && typeof Deno.version.deno === "string"; } /** @@ -1255,7 +1198,7 @@ class GenUtils { * * Credit: https://stackoverflow.com/questions/19999388/check-if-user-is-using-ie-with-jquery/21712356#21712356 * - * @returns the IE version number of null if not IE + * @return the IE version number or null if not IE */ static getIEVersion() { let ua = window.navigator.userAgent; @@ -1290,7 +1233,7 @@ class GenUtils { * * @param name is the name of the parameter to get the value of * @param url is a URL to get the parameter from, uses the window's current href if not given - * @returns the parameter's value + * @return the parameter's value */ static getParameterByName(name, url) { if (!url) url = window.location.href; @@ -1379,13 +1322,13 @@ class GenUtils { * @param getFn gets the current value * @param setFn sets the current value * @param val is the value to set iff it does not overwrite a previous value - * @param config specifies reconciliation configuration + * @param [config] specifies reconciliation configuration * config.resolveDefined uses defined value if true or undefined, undefined if false * config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined * config.resolveMax uses max over min if true, min over max if false, must be equal if undefined - * @param errMsg is the error message to throw if the values cannot be reconciled (optional) + * @param [errMsg] is the error message to throw if the values cannot be reconciled (optional) */ - static safeSet(obj, getFn, setFn, val, config, errMsg) { + static safeSet(obj, getFn, setFn, val, config?, errMsg?) { let curVal = getFn.call(obj); let reconciledVal = GenUtils.reconcile(curVal, val, config, errMsg); if (curVal !== reconciledVal) setFn.call(obj, reconciledVal); @@ -1398,23 +1341,22 @@ class GenUtils { * * @param val1 is a value to reconcile * @param val2 is a value to reconcile - * @param config specifies reconciliation configuration + * @param [config] specifies reconciliation configuration * config.resolveDefined uses defined value if true or undefined, undefined if false * config.resolveTrue uses true over false if true, false over true if false, must be equal if undefined * config.resolveMax uses max over min if true, min over max if false, must be equal if undefined - * @param errMsg is the error message to throw if the values cannot be reconciled (optional) - * @returns the reconciled value if reconcilable, throws error otherwise + * @param [errMsg] is the error message to throw if the values cannot be reconciled (optional) + * @return the reconciled value if reconcilable, throws error otherwise */ - static reconcile(val1, val2, config, errMsg) { + static reconcile(val1, val2, config?, errMsg?) { // check for equality if (val1 === val2) return val1; - // check for BigInteger equality + // check for bigint equality let comparison; // save comparison for later if applicable - if (val1 instanceof BigInteger && val2 instanceof BigInteger) { - comparison = val1.compare(val2); - if (comparison === 0) return val1; + if (typeof val1 === "bigint" && typeof val2 === "bigint") { + if (val1 === val2) return val1; } // resolve one value defined @@ -1438,8 +1380,8 @@ class GenUtils { return config.resolveMax ? Math.max(val1, val2) : Math.min(val1, val2); } - // resolve BigIntegers - if (val1 instanceof BigInteger && val2 instanceof BigInteger) { + // resolve bigints + if (typeof val1 === "bigint" && typeof val2 === "bigint") { return config.resolveMax ? (comparison < 0 ? val2 : val1) : (comparison < 0 ? val1 : val2); } } @@ -1457,7 +1399,7 @@ class GenUtils { * @param indent indents the line * @param newline specifies if the string should be terminated with a newline or not * @param ignoreUndefined specifies if undefined values should return an empty string - * @returns {string} is the human-friendly key value line + * @return {string} is the human-friendly key value line */ static kvLine(key, value, indent = 0, newline = true, ignoreUndefined = true) { if (value === undefined && ignoreUndefined) return ""; @@ -1471,9 +1413,108 @@ class GenUtils { * @param {string} str is the string to be modified * @return {string} the modified string with big numbers converted to strings */ - static stringifyBIs(str) { + static stringifyBigInts(str) { return str.replace(/("[^"]*"\s*:\s*)(\d{16,})/g, '$1"$2"'); } + + /** + * Print the current stack trace. + * + * @param {string} msg - optional message to print with the trace + */ + static printStackTrace(msg) { + try { throw new Error(msg); } + catch (err: any) { console.error(err.stack); } + } + + /** + * Wait for the duration. + * + * @param {number} durationMs - the duration to wait for in milliseconds + */ + static async waitFor(durationMs) { + return new Promise(function(resolve) { setTimeout(resolve, durationMs); }); + } + + /** + * Kill the given nodejs child process. + * + * @param {ChildProcess} process - the nodejs child process to kill + * @param {number | NodeJS.Signals} [signal] - the kill signal, e.g. SIGTERM, SIGKILL, SIGINT (default) + * @return {Promise} the exit code from killing the process + */ + static async killProcess(process: ChildProcess, signal?: number | NodeJS.Signals): Promise { + return new Promise((resolve, reject) => { + process.on("exit", function(code, signal) { resolve(code); }); + process.on("error", function(err) { reject(err); }); + try { + if (!process.kill(signal === undefined ? "SIGINT" : signal)) resolve(undefined); // resolve immediately if not running + } catch (err) { + reject(err); + } + }); + } + + /** + * Normalize a URI. + * + * @param {string} uri - the URI to normalize + * @return {string} the normalized URI + */ + static normalizeUri(uri) { + if (!uri) throw Error("Must provide URI to normalize"); + uri = uri.replace(/\/$/, ""); // strip trailing slash + if (!new RegExp("^\\w+://.+").test(uri)) uri= "http://" + uri; // assume http if protocol not given + return uri; + } + + /** + * Get the absolute value of the given bigint or number. + * + * @param {bigint | number} bi - the bigint or number to get the absolute value of + * @return {bigint | number} the absolute value of the given bigint or number + */ + static abs(bi: bigint | number): bigint | number { + return bi < 0 ? -bi : bi; + } + + /** + * Get an enum key name by value. + * + * @param {any} enumType is the enum type to get the key from + * @param {any} enumValue is the enum value to get the key for + * @return {string | undefined} the enum key name + */ + static getEnumKeyByValue(enumType: any, enumValue: any): string | undefined { + for (let key in enumType) { + if (enumType[key] === enumValue) return key; + } + return undefined; + } + + /** + * Resolve the given promise with a timeout. + * + * @param promise the promise to resolve within the timeout + * @param timeoutMs the timeout in milliseconds to resolve the promise + * @return the result of the promise unless error thrown + */ + static async executeWithTimeout(promise, timeoutMs): Promise { + return new Promise((resolve, reject) => { + const timeoutId = setTimeout(() => { + reject('Execution timed out in ' + timeoutMs + ' milliseconds') + }, timeoutMs); + promise.then( + (result) => { + clearTimeout(timeoutId); + resolve(result); + }, + (error) => { + clearTimeout(timeoutId); + reject(error); + } + ); + }); + } } -module.exports = GenUtils; \ No newline at end of file diff --git a/src/main/ts/common/HttpClient.ts b/src/main/ts/common/HttpClient.ts new file mode 100644 index 000000000..44c6779d6 --- /dev/null +++ b/src/main/ts/common/HttpClient.ts @@ -0,0 +1,245 @@ +import GenUtils from "./GenUtils"; +import LibraryUtils from "./LibraryUtils"; +import ThreadPool from "./ThreadPool"; +import PromiseThrottle from "promise-throttle"; +import http from "http"; +import https from "https"; +import axios, { AxiosError } from "axios"; + +/** + * Handle HTTP requests with a uniform interface. + */ +export default class HttpClient { + + static MAX_REQUESTS_PER_SECOND = 50; + + // default request config + protected static DEFAULT_REQUEST = { + method: "GET", + resolveWithFullResponse: false, + rejectUnauthorized: true + } + + // rate limit requests per host + protected static PROMISE_THROTTLES = []; + protected static TASK_QUEUES = []; + protected static DEFAULT_TIMEOUT = 60000; + static MAX_TIMEOUT = 2147483647; // max 32-bit signed number + + protected static HTTP_AGENT: any; + protected static HTTPS_AGENT: any; + + /** + *

Make a HTTP request.

+ * + * @param {object} request - configures the request to make + * @param {string} request.method - HTTP method ("GET", "PUT", "POST", "DELETE", etc) + * @param {string} request.uri - uri to request + * @param {string|Uint8Array|object} request.body - request body + * @param {string} [request.username] - username to authenticate the request (optional) + * @param {string} [request.password] - password to authenticate the request (optional) + * @param {object} [request.headers] - headers to add to the request (optional) + * @param {boolean} [request.resolveWithFullResponse] - return full response if true, else body only (default false) + * @param {boolean} [request.rejectUnauthorized] - whether or not to reject self-signed certificates (default true) + * @param {number} request.timeout - maximum time allowed in milliseconds + * @param {number} request.proxyToWorker - proxy request to worker thread + * @return {object} response - the response object + * @return {string|Uint8Array|object} response.body - the response body + * @return {number} response.statusCode - the response code + * @return {String} response.statusText - the response message + * @return {object} response.headers - the response headers + */ + static async request(request) { + // proxy to worker if configured + if (request.proxyToWorker) { + try { + return await LibraryUtils.invokeWorker(undefined, "httpRequest", request); + } catch (err: any) { + if (err.message.length > 0 && err.message.charAt(0) === "{") { + let parsed = JSON.parse(err.message); + err.message = parsed.statusMessage; + err.statusCode = parsed.statusCode; + } + throw err; + } + } + + // assign defaults + request = Object.assign({}, HttpClient.DEFAULT_REQUEST, request); + + // validate request + try { request.host = new URL(request.uri).host; } // hostname:port + catch (err) { throw new Error("Invalid request URL: " + request.uri); } + if (request.body && !(typeof request.body === "string" || typeof request.body === "object")) { + throw new Error("Request body type is not string or object"); + } + + // initialize one task queue per host + if (!HttpClient.TASK_QUEUES[request.host]) HttpClient.TASK_QUEUES[request.host] = new ThreadPool(1); + + // initialize one promise throttle per host + if (!HttpClient.PROMISE_THROTTLES[request.host]) { + HttpClient.PROMISE_THROTTLES[request.host] = new PromiseThrottle({ + requestsPerSecond: HttpClient.MAX_REQUESTS_PER_SECOND, // TODO: HttpClient should not depend on MoneroUtils for configuration + promiseImplementation: Promise + }); + } + + // request using fetch or xhr with timeout + let timeout = request.timeout === undefined ? HttpClient.DEFAULT_TIMEOUT : request.timeout === 0 ? HttpClient.MAX_TIMEOUT : request.timeout; + let requestPromise = HttpClient.requestAxios(request); + return GenUtils.executeWithTimeout(requestPromise, timeout); + } + + // ----------------------------- PRIVATE HELPERS ---------------------------- + + + /** + * Get a singleton instance of an HTTP client to share. + * + * @return {http.Agent} a shared agent for network requests among library instances + */ + protected static getHttpAgent() { + if (!HttpClient.HTTP_AGENT) HttpClient.HTTP_AGENT = new http.Agent({ + keepAlive: true, + family: 4 // use IPv4 + }); + return HttpClient.HTTP_AGENT; + } + + /** + * Get a singleton instance of an HTTPS client to share. + * + * @return {https.Agent} a shared agent for network requests among library instances + */ + protected static getHttpsAgent() { + if (!HttpClient.HTTPS_AGENT) HttpClient.HTTPS_AGENT = new https.Agent({ + keepAlive: true, + family: 4 // use IPv4 + }); + return HttpClient.HTTPS_AGENT; + } + + protected static async requestAxios(req) { + if (req.headers) throw new Error("Custom headers not implemented in XHR request"); // TODO + + // collect params from request which change on await + const method = req.method; + const uri = req.uri; + const host = req.host; + const username = req.username; + const password = req.password; + const body = req.body; + const isBinary = body instanceof Uint8Array; + + // queue and throttle requests to execute in serial and rate limited per host + const resp = await HttpClient.TASK_QUEUES[host].submit(async function() { + return HttpClient.PROMISE_THROTTLES[host].add(function() { + return new Promise(function(resolve, reject) { + HttpClient.axiosDigestAuthRequest(method, uri, username, password, body).then(function(resp) { + resolve(resp); + }).catch(function(error: AxiosError) { + if (error.response?.status) resolve(error.response); + reject(new Error("Request failed without response: " + method + " " + uri + " due to underlying error:\n" + error.message + "\n" + error.stack)); + }); + }); + + }.bind(this)); + }); + + // normalize response + let normalizedResponse: any = {}; + normalizedResponse.statusCode = resp.status; + normalizedResponse.statusText = resp.statusText; + normalizedResponse.headers = {...resp.headers}; + normalizedResponse.body = isBinary ? new Uint8Array(resp.data) : resp.data; + if (normalizedResponse.body instanceof ArrayBuffer) normalizedResponse.body = new Uint8Array(normalizedResponse.body); // handle empty binary request + return normalizedResponse; + } + + protected static axiosDigestAuthRequest = async function(method, url, username, password, body) { + if (typeof CryptoJS === 'undefined' && typeof require === 'function') { + var CryptoJS = require('crypto-js'); + } + + const generateCnonce = function(): string { + const characters = 'abcdef0123456789'; + let token = ''; + for (let i = 0; i < 16; i++) { + const randNum = Math.round(Math.random() * characters.length); + token += characters.slice(randNum, randNum+1); + } + return token; + } + + let count = 0; + return axios.request({ + url: url, + method: method, + timeout: this.timeout, + headers: { + 'Content-Type': 'application/json' + }, + responseType: body instanceof Uint8Array ? 'arraybuffer' : undefined, + httpAgent: url.startsWith("https") ? undefined : HttpClient.getHttpAgent(), + httpsAgent: url.startsWith("https") ? HttpClient.getHttpsAgent() : undefined, + data: body, + transformResponse: res => res, + adapter: GenUtils.isDeno() ? ['fetch'] : ['http', 'xhr', 'fetch'] + }).catch(async (err) => { + if (err.response?.status === 401) { + let authHeader = err.response.headers['www-authenticate'].replace(/,\sDigest.*/, ""); + if (!authHeader) { + throw err; + } + + // Digest qop="auth",algorithm=MD5,realm="monero-rpc",nonce="hBZ2rZIxElv4lqCRrUylXA==",stale=false + const authHeaderMap = authHeader.replace("Digest ", "").replaceAll('"', "").split(",").reduce((prev, curr) => ({...prev, [curr.split("=")[0]]: curr.split("=").slice(1).join('=')}), {}) + + ++count; + + const cnonce = generateCnonce(); + const HA1 = CryptoJS.MD5(username+':'+authHeaderMap.realm+':'+password).toString(); + const HA2 = CryptoJS.MD5(method+':'+url).toString(); + + const response = CryptoJS.MD5(HA1+':'+ + authHeaderMap.nonce+':'+ + ('00000000' + count).slice(-8)+':'+ + cnonce+':'+ + authHeaderMap.qop+':'+ + HA2).toString(); + const digestAuthHeader = 'Digest'+' '+ + 'username="'+username+'", '+ + 'realm="'+authHeaderMap.realm+'", '+ + 'nonce="'+authHeaderMap.nonce+'", '+ + 'uri="'+url+'", '+ + 'response="'+response+'", '+ + 'opaque="'+(authHeaderMap.opaque ?? null)+'", '+ + 'qop='+authHeaderMap.qop+', '+ + 'nc='+('00000000' + count).slice(-8)+', '+ + 'cnonce="'+cnonce+'"'; + + const finalResponse = await axios.request({ + url: url, + method: method, + timeout: this.timeout, + headers: { + 'Authorization': digestAuthHeader, + 'Content-Type': 'application/json' + }, + responseType: body instanceof Uint8Array ? 'arraybuffer' : undefined, + httpAgent: url.startsWith("https") ? undefined : HttpClient.getHttpAgent(), + httpsAgent: url.startsWith("https") ? HttpClient.getHttpsAgent() : undefined, + data: body, + transformResponse: res => res, + adapter: GenUtils.isDeno() ? ['fetch'] : ['http', 'xhr', 'fetch'] + }); + + return finalResponse; + } + throw err; + }).catch(err => { + throw err; + }); + } +} diff --git a/src/main/ts/common/LibraryUtils.ts b/src/main/ts/common/LibraryUtils.ts new file mode 100644 index 000000000..f6b36f01a --- /dev/null +++ b/src/main/ts/common/LibraryUtils.ts @@ -0,0 +1,291 @@ +import assert from "assert"; +import GenUtils from "./GenUtils"; +import MoneroError from "./MoneroError"; +import ThreadPool from "./ThreadPool"; +import path from "path"; + +/** + * Collection of helper utilities for the library. + */ +export default class LibraryUtils { + + // static variables + static LOG_LEVEL = 0; + static WASM_MODULE: any; + static WORKER: any; + static WORKER_OBJECTS: any; + static FULL_LOADED: any; + static REJECT_UNAUTHORIZED_FNS: any; + static readonly MUTEX = new ThreadPool(1); + static WORKER_DIST_PATH_DEFAULT = GenUtils.isBrowser() ? "/monero.worker.js" : function() { + + // get worker path in dist (assumes library is running from src or dist) + let curPath = path.normalize(__dirname); + const targetPath = path.join('monero-ts', 'dist'); + if (!curPath.includes(targetPath)) curPath = path.join(curPath, "../../../../dist/src/main/js/common"); + curPath = LibraryUtils.prefixWindowsPath(path.join(curPath, "./MoneroWebWorker.js")); + if (GenUtils.isDeno()) curPath = path.join("file://", curPath); + return curPath; + }(); + static WORKER_DIST_PATH = LibraryUtils.WORKER_DIST_PATH_DEFAULT; + static WORKER_LOADER?: () => Worker = undefined; + + /** + * Log a message. + * + * @param {number} level - log level of the message + * @param {string} msg - message to log + */ + static log(level, msg) { + assert(level === parseInt(level, 10) && level >= 0, "Log level must be an integer >= 0"); + if (LibraryUtils.LOG_LEVEL >= level) console.log(msg); + } + + /** + * Set the library's log level with 0 being least verbose. + * + * @param {number} level - the library's log level + */ + static async setLogLevel(level) { + assert(level === parseInt(level, 10) && level >= 0, "Log level must be an integer >= 0"); + LibraryUtils.LOG_LEVEL = level; + if (LibraryUtils.WASM_MODULE) LibraryUtils.WASM_MODULE.set_log_level(level); + if (LibraryUtils.WORKER) await LibraryUtils.invokeWorker(undefined, "setLogLevel", [level]); + } + + /** + * Get the library's log level. + * + * @return {number} the library's log level + */ + static getLogLevel(): number { + return LibraryUtils.LOG_LEVEL; + } + + /** + * Get the total memory used by WebAssembly. + * + * @return {Promise} the total memory used by WebAssembly + */ + static async getWasmMemoryUsed(): Promise { + let total = 0; + if (LibraryUtils.WORKER) total += await LibraryUtils.invokeWorker(undefined, "getWasmMemoryUsed", []) as number; + if (LibraryUtils.getWasmModule() && LibraryUtils.getWasmModule().HEAP8) total += LibraryUtils.getWasmModule().HEAP8.length; + return total; + } + + /** + * Get the WebAssembly module in the current context (nodejs, browser main thread or worker). + */ + static getWasmModule() { + return LibraryUtils.WASM_MODULE; + } + + /** + * Load the WebAssembly full module with caching. + * + * The full module is a superset of the keys module and overrides it. + */ + static async loadWasmModule() { + + // use cache if suitable, full module supersedes keys module because it is superset + if (LibraryUtils.WASM_MODULE && LibraryUtils.FULL_LOADED) return LibraryUtils.WASM_MODULE; + + // load module + const module = await require("#monero-ts/monero.js")(); + LibraryUtils.WASM_MODULE = module; + delete LibraryUtils.WASM_MODULE.then; + LibraryUtils.FULL_LOADED = true; + LibraryUtils.initWasmModule(LibraryUtils.WASM_MODULE); + return module; + } + + /** + * Register a function by id which informs if unauthorized requests (e.g. + * self-signed certificates) should be rejected. + * + * @param {string} fnId - unique identifier for the function + * @param {function} fn - function to inform if unauthorized requests should be rejected + */ + static setRejectUnauthorizedFn(fnId, fn) { + if (!LibraryUtils.REJECT_UNAUTHORIZED_FNS) LibraryUtils.REJECT_UNAUTHORIZED_FNS = []; + if (fn === undefined) delete LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId]; + else LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId] = fn; + } + + /** + * Indicate if unauthorized requests should be rejected. + * + * @param {string} fnId - uniquely identifies the function + */ + static isRejectUnauthorized(fnId) { + if (!LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId]) throw new Error("No function registered with id " + fnId + " to inform if unauthorized reqs should be rejected"); + return LibraryUtils.REJECT_UNAUTHORIZED_FNS[fnId](); + } + + /** + * Set the path to load the worker. Defaults to "/monero.worker.js" in the browser + * and "./MoneroWebWorker.js" in node. + * + * @param {string} workerDistPath - path to load the worker + */ + static setWorkerDistPath(workerDistPath) { + let path = LibraryUtils.prefixWindowsPath(workerDistPath ? workerDistPath : LibraryUtils.WORKER_DIST_PATH_DEFAULT); + if (path !== LibraryUtils.WORKER_DIST_PATH) delete LibraryUtils.WORKER; + LibraryUtils.WORKER_DIST_PATH = path; + } + + /** + * Set the worker loader closure to customize worker loading. + * Takes precedence over default loading mechanisms. + * + * Could be as simple as `() => new Worker(new URL("monero-ts/dist/monero.worker.js", import.meta.url));` for browsers. + * + * @param {function} loader - loader function which instantiates a worker + */ + static setWorkerLoader(loader?: () => Worker): void { + LibraryUtils.WORKER_LOADER = loader; + } + + /** + * Get a singleton instance of a worker to share. + * + * @return {Worker} a worker to share among wallet instances + */ + static async getWorker() { + + // one time initialization + if (!LibraryUtils.WORKER) { + + // try to load worker with user provided closure + if (LibraryUtils.WORKER_LOADER) { + LibraryUtils.WORKER = LibraryUtils.WORKER_LOADER(); + } else { + + // otherwise use standard loading mechanisms for browser and node + if (GenUtils.isBrowser()) { + LibraryUtils.WORKER = new Worker(LibraryUtils.WORKER_DIST_PATH); + } else if (GenUtils.isDeno()) { + LibraryUtils.WORKER = new Worker(LibraryUtils.WORKER_DIST_PATH, { type: "module" }); + } else { + const Worker = require("web-worker"); // import web worker if nodejs + LibraryUtils.WORKER = new Worker(LibraryUtils.WORKER_DIST_PATH); + } + } + LibraryUtils.WORKER_OBJECTS = {}; // store per object running in the worker + + // receive worker errors + LibraryUtils.WORKER.onerror = function(err) { + console.error("Error posting message to monero.worker.js; is it built and copied to the app's public or build directory?"); + console.log(err); + }; + + // receive worker messages + LibraryUtils.WORKER.onmessage = function(e) { + + // lookup object id, callback function, and this arg + let thisArg = undefined; + let callbackFn = LibraryUtils.WORKER_OBJECTS[e.data[0]].callbacks[e.data[1]]; // look up by object id then by function name + if (callbackFn === undefined) throw new Error("No worker callback function defined for key '" + e.data[1] + "'"); + if (callbackFn instanceof Array) { // this arg may be stored with callback function + thisArg = callbackFn[1]; + callbackFn = callbackFn[0]; + } + + // invoke callback function with this arg and arguments + callbackFn.apply(thisArg, e.data.slice(2)); + } + } + return LibraryUtils.WORKER; + } + + static addWorkerCallback(objectId, callbackId, callbackArgs) { + LibraryUtils.WORKER_OBJECTS[objectId].callbacks[callbackId] = callbackArgs; + } + + static removeWorkerCallback(objectId, callbackId) { + delete LibraryUtils.WORKER_OBJECTS[objectId].callbacks[callbackId]; + } + + static removeWorkerObject(objectId) { + delete LibraryUtils.WORKER_OBJECTS[objectId]; + } + + /** + * Terminate monero-ts's singleton worker. + */ + static async terminateWorker() { + if (LibraryUtils.WORKER) { + LibraryUtils.WORKER.terminate(); + delete LibraryUtils.WORKER; + LibraryUtils.WORKER = undefined; + } + } + + /** + * Invoke a worker function and get the result with error handling. + * + * @param {string} objectId identifies the worker object to invoke (default random id) + * @param {string} fnName is the name of the function to invoke + * @param {any[]} [args] are function arguments to invoke with + * @return {any} resolves with response payload from the worker or an error + */ + static async invokeWorker(objectId, fnName, args) { + assert(fnName.length >= 2); + let worker = await LibraryUtils.getWorker(); + let randomObject = objectId === undefined; + if (randomObject) objectId = GenUtils.getUUID(); + if (!LibraryUtils.WORKER_OBJECTS[objectId]) LibraryUtils.WORKER_OBJECTS[objectId] = {callbacks: {}}; + let callbackId = GenUtils.getUUID(); + try { + return await new Promise((resolve, reject) => { + LibraryUtils.WORKER_OBJECTS[objectId].callbacks[callbackId] = (resp) => { // TODO: this defines function once per callback + delete LibraryUtils.WORKER_OBJECTS[objectId].callbacks[callbackId]; + if (randomObject) delete LibraryUtils.WORKER_OBJECTS[objectId]; + resp ? (resp.error ? reject(new Error(JSON.stringify(resp.error))) : resolve(resp.result)) : resolve(undefined); + }; + worker.postMessage([objectId, fnName, callbackId].concat(args === undefined ? [] : GenUtils.listify(args))); + }); + } catch (e: any) { + throw LibraryUtils.deserializeError(JSON.parse(e.message)); + } + } + + static serializeError(err) { + const serializedErr: any = { name: err.name, message: err.message, code: err.code, stack: err.stack }; + if (err instanceof MoneroError) serializedErr.type = "MoneroError"; + return serializedErr; + } + + protected static deserializeError(serializedErr) { + const err = serializedErr.type === "MoneroError" ? new MoneroError(serializedErr.message, serializedErr.code) : new Error(serializedErr.message); + err.name = serializedErr.name; + err.stack = err.stack + "\nWorker error: " + serializedErr.stack; + return err; + } + + static async queueTask(asyncFn: () => Promise): Promise { + return LibraryUtils.MUTEX.submit(asyncFn); + } + + static async exists(fs: any, path: string): Promise { + try { + await fs.access(path); + return true; + } catch (err) { + return false; + } + } + + // ------------------------------ PRIVATE HELPERS --------------------------- + + protected static initWasmModule(wasmModule) { + wasmModule.taskQueue = new ThreadPool(1); + wasmModule.queueTask = async function(asyncFn) { return wasmModule.taskQueue.submit(asyncFn); } + } + + protected static prefixWindowsPath(path) { + if (/^[A-Z]:/.test(path) && path.indexOf("file://") == -1) path = "file://" + path; // prepend e.g. C: paths with file:// + return path; + } +} diff --git a/src/main/ts/common/MoneroConnectionManager.ts b/src/main/ts/common/MoneroConnectionManager.ts new file mode 100644 index 000000000..7fe14e5b7 --- /dev/null +++ b/src/main/ts/common/MoneroConnectionManager.ts @@ -0,0 +1,680 @@ +import GenUtils from "./GenUtils"; +import TaskLooper from "./TaskLooper"; +import ThreadPool from "./ThreadPool"; +import MoneroConnectionManagerListener from "./MoneroConnectionManagerListener"; +import MoneroError from "./MoneroError"; +import MoneroRpcConnection from "./MoneroRpcConnection"; + +/** + *

Manages a collection of prioritized connections to daemon or wallet RPC endpoints.

+ * + *

Example usage:

+ * + * + * // imports
+ * import { MoneroRpcConnection, MoneroConnectionManager, MoneroConnectionManagerListener } from "monero-ts";
+ *
+ * // create connection manager
+ * let connectionManager = new MoneroConnectionManager();
+ *
+ * // add managed connections with priorities
+ * await connectionManager.addConnection({uri: "http://localhost:38081", priority: 1}); // use localhost as first priority
+ * await connectionManager.addConnection({uri: "http://example.com"}); // default priority is prioritized last
+ *
+ * // set current connection
+ * await connectionManager.setConnection({uri: "http://foo.bar", username: "admin", password: "password"}); // connection is added if new
+ *
+ * // check connection status
+ * await connectionManager.checkConnection();
+ * console.log("Connection manager is connected: " + connectionManager.isConnected());
+ * console.log("Connection is online: " + connectionManager.getConnection().getIsOnline());
+ * console.log("Connection is authenticated: " + connectionManager.getConnection().getIsAuthenticated());
+ *
+ * // receive notifications of any changes to current connection
+ * connectionManager.addListener(new class extends MoneroConnectionManagerListener {
+ *    async onConnectionChanged(connection) {
+ *      console.log("Connection changed to: " + connection);
+ *    }
+ * });
+ *
+ * // start polling for best connection every 10 seconds and automatically switch
+ * connectionManager.startPolling(10000);
+ *
+ * // automatically switch to best available connection if disconnected
+ * connectionManager.setAutoSwitch(true);
+ *
+ * // get best available connection in order of priority then response time
+ * let bestConnection = await connectionManager.getBestAvailableConnection();
+ *
+ * // check status of all connections
+ * await connectionManager.checkConnections();
+ *
+ * // get connections in order of current connection, online status from last check, priority, and name
+ * let connections = connectionManager.getConnections();
+ *
+ * // clear connection manager
+ * connectionManager.clear(); + *
+ */ +export default class MoneroConnectionManager { + + // static variables + static DEFAULT_TIMEOUT = 5000; + static DEFAULT_POLL_PERIOD = 20000; + static DEFAULT_AUTO_SWITCH = true; + static MIN_BETTER_RESPONSES = 3; + + // instance variables + protected proxyToWorker: any; + protected timeoutMs: any; + protected autoSwitch: any; + protected connections: any; + protected responseTimes: any; + protected listeners: any; + protected currentConnection: any; + protected poller: any; + + /** + * Specify behavior when polling. + * + * One of PRIORITIZED (poll connections in order of priority until connected; default), CURRENT (poll current connection), or ALL (poll all connections). + */ + static PollType = { + PRIORITIZED: 0, + CURRENT: 1, + ALL: 2 + } + + /** + * Construct a connection manager. + * + * @param {boolean} [proxyToWorker] - configure all connections to proxy to worker (default true) + */ + constructor(proxyToWorker = true) { + this.proxyToWorker = proxyToWorker !== false; + this.timeoutMs = MoneroConnectionManager.DEFAULT_TIMEOUT; + this.autoSwitch = MoneroConnectionManager.DEFAULT_AUTO_SWITCH; + this.connections = []; + this.responseTimes = new Map(); + this.listeners = []; + } + + /** + * Add a listener to receive notifications when the connection changes. + * + * @param {MoneroConnectionManagerListener} listener - the listener to add + * @return {MoneroConnectionManager} this connection manager for chaining + */ + addListener(listener: MoneroConnectionManagerListener): MoneroConnectionManager { + this.listeners.push(listener); + return this; + } + + /** + * Remove a listener. + * + * @param {MoneroConnectionManagerListener} listener - the listener to remove + * @return {MoneroConnectionManager} this connection manager for chaining + */ + removeListener(listener: MoneroConnectionManagerListener): MoneroConnectionManager { + if (!GenUtils.remove(this.listeners, listener)) throw new MoneroError("Monero connection manager does not contain listener to remove"); + return this; + } + + /** + * Remove all listeners. + * + * @return {MoneroConnectionManager} this connection manager for chaining + */ + removeListeners(): MoneroConnectionManager { + this.listeners.splice(0, this.listeners.length); + return this; + } + + /** + * Get all listeners. + * + * @return {MoneroConnectionManagerListener[]} all listeners + */ + getListeners(): MoneroConnectionManagerListener[] { + return this.listeners + } + + /** + * Add a connection. The connection may have an elevated priority for this manager to use. + * + * @param {string|Partial} uriOrConnection - uri or connection to add + * @return {Promise} this connection manager for chaining + */ + async addConnection(uriOrConnection: string | Partial): Promise { + let connection = uriOrConnection instanceof MoneroRpcConnection ? uriOrConnection : new MoneroRpcConnection(uriOrConnection); + for (let aConnection of this.connections) { + if (aConnection.getUri() === connection.getUri()) throw new MoneroError("Connection URI already exists"); + } + if (this.proxyToWorker !== undefined) connection.setProxyToWorker(this.proxyToWorker); + this.connections.push(connection); + return this; + } + + /** + * Remove a connection. + * + * @param {string} uri - of the the connection to remove + * @return {Promise} this connection manager for chaining + */ + async removeConnection(uri: string): Promise { + let connection = this.getConnectionByUri(uri); + if (!connection) throw new MoneroError("No connection exists with URI: " + uri); + GenUtils.remove(this.connections, connection); + this.responseTimes.delete(connection.getUri()); + if (connection === this.currentConnection) { + this.currentConnection = undefined; + await this.onConnectionChanged(this.currentConnection); + } + return this; + } + + /** + * Set the current connection. + * Provide a URI to select an existing connection without updating its credentials. + * Provide a MoneroRpcConnection to add new connection or replace existing connection with the same URI. + * Notify if current connection changes. + * Does not check the connection. + * + * @param {string|Partial} [uriOrConnection] - is the uri of the connection or the connection to make current (default undefined for no current connection) + * @return {Promise} this connection manager for chaining + */ + async setConnection(uriOrConnection?: string | Partial): Promise { + + // handle uri + if (uriOrConnection && typeof uriOrConnection === "string") { + let connection = this.getConnectionByUri(uriOrConnection); + return this.setConnection(connection === undefined ? new MoneroRpcConnection(uriOrConnection) : connection); + } + + // handle connection + let connection = uriOrConnection; + if (this.currentConnection === connection) return this; + + // check if setting undefined connection + if (!connection) { + this.currentConnection = undefined; + await this.onConnectionChanged(undefined); + return this; + } + + // validate connection + if (!(connection instanceof MoneroRpcConnection)) connection = new MoneroRpcConnection(connection); + if (!connection.getUri()) throw new MoneroError("Connection is missing URI"); + + // add or replace connection + let prevConnection = this.getConnectionByUri(connection.getUri()); + if (prevConnection) GenUtils.remove(this.connections, prevConnection); + await this.addConnection(connection); + this.currentConnection = connection; + await this.onConnectionChanged(this.currentConnection); + + return this; + } + + /** + * Get the current connection. + * + * @return {MoneroRpcConnection} the current connection or undefined if no connection set + */ + getConnection(): MoneroRpcConnection { + return this.currentConnection; + } + + /** + * Indicates if this manager has a connection with the given URI. + * + * @param {string} uri URI of the connection to check + * @return {boolean} true if this manager has a connection with the given URI, false otherwise + */ + hasConnection(uri: string): boolean { + return this.getConnectionByUri(uri) !== undefined; + } + + /** + * Get a connection by URI. + * + * @param {string} uri is the URI of the connection to get + * @return {MoneroRpcConnection} the connection with the URI or undefined if no connection with the URI exists + */ + getConnectionByUri(uri: string): MoneroRpcConnection { + for (let connection of this.connections) if (connection.getUri() === uri) return connection; + return undefined; + } + + /** + * Get all connections in order of current connection (if applicable), online status, priority, and name. + * + * @return {MoneroRpcConnection[]} the list of sorted connections + */ + getConnections(): MoneroRpcConnection[] { + let sortedConnections = GenUtils.copyArray(this.connections); + sortedConnections.sort(this.compareConnections.bind(this)); + return sortedConnections; + } + + /** + * Indicates if the connection manager is connected to a node. + * + * @return {boolean|undefined} true if the current connection is set, online, and not unauthenticated, undefined if unknown, false otherwise + */ + isConnected(): boolean | undefined { + if (!this.currentConnection) return false; + return this.currentConnection.isConnected(); + } + + /** + * Start polling connections. + * + * @param {number} [periodMs] poll period in milliseconds (default 20s) + * @param {boolean} [autoSwitch] specifies to automatically switch to the best connection (default true unless changed) + * @param {number} [timeoutMs] specifies the timeout to poll a single connection (default 5s unless changed) + * @param {number} [pollType] one of PRIORITIZED (poll connections in order of priority until connected; default), CURRENT (poll current connection), or ALL (poll all connections) + * @param {MoneroRpcConnection[]} [excludedConnections] connections excluded from being polled + * @return {MoneroConnectionManager} this connection manager for chaining + */ + startPolling(periodMs?: number, autoSwitch?: boolean, timeoutMs?: number, pollType?: number, excludedConnections?: MoneroRpcConnection[]): MoneroConnectionManager { + + // apply defaults + if (periodMs == undefined) periodMs = MoneroConnectionManager.DEFAULT_POLL_PERIOD; + if (autoSwitch !== undefined) this.setAutoSwitch(autoSwitch); + if (timeoutMs !== undefined) this.setTimeout(timeoutMs); + if (pollType === undefined) pollType = MoneroConnectionManager.PollType.PRIORITIZED; + + // stop polling + this.stopPolling(); + + // start polling + switch (pollType) { + case MoneroConnectionManager.PollType.CURRENT: + this.startPollingConnection(periodMs); + break; + case MoneroConnectionManager.PollType.ALL: + this.startPollingConnections(periodMs); + break; + case MoneroConnectionManager.PollType.PRIORITIZED: + default: + this.startPollingPrioritizedConnections(periodMs, excludedConnections); + } + return this; + } + + /** + * Stop polling connections. + * + * @return {MoneroConnectionManager} this connection manager for chaining + */ + stopPolling(): MoneroConnectionManager { + if (this.poller) this.poller.stop(); + this.poller = undefined; + return this; + } + + /** + * Check the current connection. If disconnected and auto switch enabled, switches to best available connection. + * + * @return {Promise} this connection manager for chaining + */ + async checkConnection(): Promise { + let connectionChanged = false; + let connection = this.getConnection(); + if (connection) { + if (await connection.checkConnection(this.timeoutMs)) connectionChanged = true; + await this.processResponses([connection]); + } + if (this.autoSwitch && !this.isConnected()) { + let bestConnection = await this.getBestAvailableConnection([connection]); + if (bestConnection) { + await this.setConnection(bestConnection); + return this; + } + } + if (connectionChanged) await this.onConnectionChanged(connection); + return this; + } + + /** + * Check all managed connections. + * + * @return {Promise} this connection manager for chaining + */ + async checkConnections(): Promise { + await this.checkConnectionsAux(this.getConnections()); + return this; + } + + /** + * Check all managed connections, returning a promise for each connection check. + * Does not auto switch if disconnected. + * + * @return {Promise[]} a promise for each connection in the order of getConnections(). + */ + checkConnectionPromises(): Promise[] { + let checkPromises = []; + let pool = new ThreadPool(this.connections.length); + for (let connection of this.getConnections()) { + checkPromises.push(pool.submit(async () => { + try { + if (await connection.checkConnection(this.timeoutMs) && connection === this.currentConnection) await this.onConnectionChanged(connection); + } catch (err) { + // ignore error + } + })); + } + Promise.all(checkPromises); + return checkPromises; + } + + /** + * Get the best available connection in order of priority then response time. + * + * @param {MoneroRpcConnection[]} [excludedConnections] - connections to be excluded from consideration (optional) + * @return {Promise} the best available connection in order of priority then response time, undefined if no connections available + */ + async getBestAvailableConnection(excludedConnections?: MoneroRpcConnection[]): Promise { + + // try connections within each ascending priority + for (let prioritizedConnections of this.getConnectionsInAscendingPriority()) { + try { + + // create promises to check connections + let that = this; + let checkPromises = []; + for (let connection of prioritizedConnections) { + if (excludedConnections && GenUtils.arrayContains(excludedConnections, connection)) continue; + checkPromises.push(new Promise(async function(resolve, reject) { + await connection.checkConnection(that.timeoutMs); + if (connection.isConnected()) resolve(connection); + else reject(); + })); + } + + // use first available connection + let firstAvailable = await Promise.any(checkPromises); + if (firstAvailable) return firstAvailable; + } catch (err) { + if (!(err instanceof AggregateError)) throw new MoneroError(err); + } + } + return undefined; + } + + /** + * Automatically switch to the best available connection as connections are polled, based on priority, response time, and consistency. + * + * @param {boolean} autoSwitch specifies if the connection should auto switch to a better connection + * @return {MoneroConnectionManager} this connection manager for chaining + */ + setAutoSwitch(autoSwitch: boolean): MoneroConnectionManager { + this.autoSwitch = autoSwitch; + return this; + } + + /** + * Get if auto switch is enabled or disabled. + * + * @return {boolean} true if auto switch enabled, false otherwise + */ + getAutoSwitch(): boolean { + return this.autoSwitch; + } + + /** + * Set the maximum request time before its connection is considered offline. + * + * @param {number} timeoutMs - the timeout before the connection is considered offline + * @return {MoneroConnectionManager} this connection manager for chaining + */ + setTimeout(timeoutMs: number): MoneroConnectionManager { + this.timeoutMs = timeoutMs; + return this; + } + + /** + * Get the request timeout. + * + * @return {number} the request timeout before a connection is considered offline + */ + getTimeout(): number { + return this.timeoutMs; + } + + /** + * Collect connectable peers of the managed connections. + * + * @return {Promise} connectable peers + */ + async getPeerConnections(): Promise { + throw new MoneroError("Not implemented"); + } + + /** + * Disconnect from the current connection. + * + * @return {Promise} this connection manager for chaining + */ + async disconnect(): Promise { + await this.setConnection(undefined); + return this; + } + + /** + * Remove all connections. + * + * @return {Promise} this connection manager for chaining + */ + async clear(): Promise { + this.connections.splice(0, this.connections.length); + if (this.currentConnection) { + this.currentConnection = undefined; + await this.onConnectionChanged(undefined); + } + return this; + } + + /** + * Reset to default state. + * + * @return {MoneroConnectionManager} this connection manager for chaining + */ + reset(): MoneroConnectionManager { + this.removeListeners(); + this.stopPolling(); + this.clear(); + this.timeoutMs = MoneroConnectionManager.DEFAULT_TIMEOUT; + this.autoSwitch = MoneroConnectionManager.DEFAULT_AUTO_SWITCH; + return this; + } + + // ------------------------------ PRIVATE HELPERS --------------------------- + + protected async onConnectionChanged(connection) { + let promises = []; + for (let listener of this.listeners) promises.push(listener.onConnectionChanged(connection)); + return Promise.all(promises); + } + + protected getConnectionsInAscendingPriority() { + let connectionPriorities = new Map(); + for (let connection of this.connections) { + if (!connectionPriorities.has(connection.getPriority())) connectionPriorities.set(connection.getPriority(), []); + connectionPriorities.get(connection.getPriority()).push(connection); + } + let ascendingPriorities = new Map([...connectionPriorities].sort((a, b) => parseInt(a[0]) - parseInt(b[0]))); // create map in ascending order + let ascendingPrioritiesList = []; + for (let priorityConnections of ascendingPriorities.values()) ascendingPrioritiesList.push(priorityConnections); + if (connectionPriorities.has(0)) ascendingPrioritiesList.push(ascendingPrioritiesList.splice(0, 1)[0]); // move priority 0 to end + return ascendingPrioritiesList; + } + + protected compareConnections(c1, c2) { + + // current connection is first + if (c1 === this.currentConnection) return -1; + if (c2 === this.currentConnection) return 1; + + // order by availability then priority then by name + if (c1.getIsOnline() === c2.getIsOnline()) { + if (c1.getPriority() === c2.getPriority()) return c1.getUri().localeCompare(c2.getUri()); + return this.comparePriorities(c1.getPriority(), c2.getPriority()) * -1 // order by priority in descending order + } else { + if (c1.getIsOnline()) return -1; + else if (c2.getIsOnline()) return 1; + else if (c1.getIsOnline() === undefined) return -1; + else return 1; // c1 is offline + } + } + + protected comparePriorities(p1, p2) { + if (p1 == p2) return 0; + if (p1 == 0) return -1; + if (p2 == 0) return 1; + return p2 - p1; + } + + protected startPollingConnection(periodMs) { + this.poller = new TaskLooper(async () => { + try { await this.checkConnection(); } + catch (err) { console.log(err); } + }); + this.poller.start(periodMs); + return this; + } + + protected startPollingConnections(periodMs) { + this.poller = new TaskLooper(async () => { + try { await this.checkConnections(); } + catch (err) { console.log(err); } + }); + this.poller.start(periodMs); + return this; + } + + protected startPollingPrioritizedConnections(periodMs, excludedConnections) { + this.poller = new TaskLooper(async () => { + try { await this.checkPrioritizedConnections(excludedConnections); } + catch (err) { console.log(err); } + }); + this.poller.start(periodMs); + return this; + } + + async checkPrioritizedConnections(excludedConnections) { + for (let prioritizedConnections of this.getConnectionsInAscendingPriority()) { + let hasConnection = await this.checkConnectionsAux(prioritizedConnections, excludedConnections); + if (hasConnection) return; + } + } + + protected async checkConnectionsAux(connections, excludedConnections?) { + try { + + // check connections in parallel + let that = this; + let checkPromises = []; + let hasConnection = false; + for (let connection of connections) { + if (excludedConnections && GenUtils.arrayContains(excludedConnections, connection)) continue; + checkPromises.push(new Promise(async function(resolve, reject) { + try { + let change = await connection.checkConnection(that.timeoutMs); + if (change && connection === that.getConnection()) await that.onConnectionChanged(connection); + if (connection.isConnected() && !hasConnection) { + hasConnection = true; + if (!that.isConnected() && that.autoSwitch) await that.setConnection(connection); // set first available connection if disconnected + } + resolve(undefined); + } catch (err) { + reject(err); + } + })); + } + await Promise.all(checkPromises); + + // process responses + await this.processResponses(connections); + return hasConnection; + } catch (err) { + throw new MoneroError(err); + } + } + + protected async processResponses(responses): Promise { + + // add new connections + for (let connection of responses) { + if (!this.responseTimes.has(connection.getUri())) this.responseTimes.set(connection.getUri(), []); + } + + // insert response times or undefined + this.responseTimes.forEach((times, connection) => { + times.unshift(GenUtils.arrayContains(responses, connection) ? connection.getResponseTime() : undefined); + + // remove old response times + if (times.length > MoneroConnectionManager.MIN_BETTER_RESPONSES) times.pop(); + }); + + // update best connection based on responses and priority + return await this.updateBestConnectionInPriority(); + } + + protected async updateBestConnectionInPriority(): Promise { + if (!this.autoSwitch) return undefined; + for (let prioritizedConnections of this.getConnectionsInAscendingPriority()) { + let bestConnectionFromResponses = await this.getBestConnectionFromPrioritizedResponses(prioritizedConnections); + if (bestConnectionFromResponses) { + await this.setConnection(bestConnectionFromResponses); + return bestConnectionFromResponses; + } + } + return undefined; + } + + /** + * Get the best connection from the given responses. + * + * @param {MoneroRpcConnection[]} responses connection responses to update from + * @return {MoneroRpcConnection} the best response among the given responses or undefined if none are best + */ + protected async getBestConnectionFromPrioritizedResponses(responses): Promise { + + // get best response + let bestResponse = undefined; + for (let connection of responses) { + if (connection.isConnected() === true && (!bestResponse || connection.getResponseTime() < bestResponse.getResponseTime())) bestResponse = connection; + } + + // no update if no responses + if (!bestResponse) return undefined; + + // use best response if disconnected + let bestConnection = await this.getConnection(); + if (!bestConnection || bestConnection.isConnected() !== true) return bestResponse; + + // use best response if different priority (assumes being called in descending priority) + if (this.comparePriorities(bestResponse.getPriority(), bestConnection.getPriority()) !== 0) return bestResponse; + + // keep best connection if not enough data + if (!this.responseTimes.has(bestConnection.getUri())) return bestConnection; + + // check if connection is consistently better + for (let connection of responses) { + if (connection === bestConnection) continue; + if (!this.responseTimes.has(connection.getUri()) || this.responseTimes.get(connection.getUri()).length < MoneroConnectionManager.MIN_BETTER_RESPONSES) continue; + let better = true; + for (let i = 0; i < MoneroConnectionManager.MIN_BETTER_RESPONSES; i++) { + if (this.responseTimes.get(connection.getUri())[i] === undefined || this.responseTimes.get(bestConnection.getUri())[i] || this.responseTimes.get(connection.getUri())[i] > this.responseTimes.get(bestConnection.getUri())[i]) { + better = false; + break; + } + } + if (better) bestConnection = connection; + } + return bestConnection; + } +} diff --git a/src/main/ts/common/MoneroConnectionManagerListener.ts b/src/main/ts/common/MoneroConnectionManagerListener.ts new file mode 100644 index 000000000..11075d170 --- /dev/null +++ b/src/main/ts/common/MoneroConnectionManagerListener.ts @@ -0,0 +1,15 @@ +import MoneroRpcConnection from "./MoneroRpcConnection"; + +/** + * Default connection manager listener which takes no action on notifications. + */ +export default class MoneroConnectionManagerListener { + + /** + * Notified on connection change events. + * + * @param {MoneroRpcConnection | undefined} connection - the connection manager's current connection + * @return {Promise} + */ + async onConnectionChanged(connection: MoneroRpcConnection | undefined): Promise { } +} diff --git a/src/main/js/common/MoneroError.js b/src/main/ts/common/MoneroError.ts similarity index 77% rename from src/main/js/common/MoneroError.js rename to src/main/ts/common/MoneroError.ts index 4e5d5a0d7..445f5a7ee 100644 --- a/src/main/js/common/MoneroError.js +++ b/src/main/ts/common/MoneroError.ts @@ -1,15 +1,17 @@ /** * Exception when interacting with a Monero wallet or daemon. */ -class MoneroError extends Error { +export default class MoneroError extends Error { + + code: number; /** * Constructs the error. * * @param {string} message is a human-readable message of the error - * @param {int} code is the error code (optional) + * @param {number} [code] is the error code (optional) */ - constructor(message, code) { + constructor(message, code?) { super(message); this.code = code; } @@ -26,5 +28,3 @@ class MoneroError extends Error { return str; } } - -module.exports = MoneroError; \ No newline at end of file diff --git a/src/main/ts/common/MoneroRpcConnection.ts b/src/main/ts/common/MoneroRpcConnection.ts new file mode 100644 index 000000000..528597391 --- /dev/null +++ b/src/main/ts/common/MoneroRpcConnection.ts @@ -0,0 +1,497 @@ +import GenUtils from "./GenUtils"; +import HttpClient from "./HttpClient"; +import LibraryUtils from "./LibraryUtils"; +import MoneroError from "./MoneroError"; +import MoneroRpcError from "./MoneroRpcError"; +import MoneroUtils from "./MoneroUtils"; +import ThreadPool from "./ThreadPool"; + +/** + * Maintains a connection and sends requests to a Monero RPC API. + */ +export default class MoneroRpcConnection { + + // public instance variables + uri: string; + username: string; + password: string; + zmqUri: string; + proxyUri: string; + rejectUnauthorized: boolean; + proxyToWorker: boolean; + priority: number; + timeoutMs: number; + + // private instance variables + protected isOnline: boolean; + protected isAuthenticated: boolean; + protected attributes: any; + protected fakeDisconnected: boolean; + protected responseTime: number; + protected checkConnectionMutex: ThreadPool; + protected sendRequestMutex: ThreadPool; + + // default config + /** @private */ + static DEFAULT_CONFIG: Partial = { + uri: undefined, + username: undefined, + password: undefined, + zmqUri: undefined, + proxyUri: undefined, + rejectUnauthorized: true, // reject self-signed certificates if true + proxyToWorker: false, + priority: 0, + timeoutMs: undefined + } + + /** + *

Construct a RPC connection.

+ * + *

Examples:

+ * + * + * let connection1 = new MoneroRpcConnection("http://localhost:38081", "daemon_user", "daemon_password_123")

+ * + * let connection2 = new MoneroRpcConnection({
+ *    uri: http://localhost:38081,
+ *    username: "daemon_user",
+ *    password: "daemon_password_123",
+ *    rejectUnauthorized: false, // accept self-signed certificates e.g. for local development
+ *    proxyToWorker: true // proxy request to worker (default false)
+ * }); + *
+ * + * @param {string|Partial} uriOrConnection - MoneroRpcConnection or URI of the RPC endpoint + * @param {string} uriOrConnection.uri - URI of the RPC endpoint + * @param {string} [uriOrConnection.username] - username to authenticate with the RPC endpoint (optional) + * @param {string} [uriOrConnection.password] - password to authenticate with the RPC endpoint (optional) + * @param {string} [uriOrConnection.zmqUri] - URI of the ZMQ endpoint (optional) + * @param {string} [uriOrConnection.proxyUri] - URI of a proxy server to route requests through (optional) + * @param {boolean} [uriOrConnection.rejectUnauthorized] - rejects self-signed certificates if true (default true) + * @param {boolean} uriOrConnection.proxyToWorker - proxy requests to worker (default true) + * @param {string} username - username to authenticate with the RPC endpoint (optional) + * @param {string} password - password to authenticate with the RPC endpoint (optional) + */ + constructor(uriOrConnection: string | Partial, username?: string, password?: string) { + + // validate and normalize config + if (typeof uriOrConnection === "string") { + Object.assign(this, MoneroRpcConnection.DEFAULT_CONFIG); + this.uri = uriOrConnection; + this.setCredentials(username, password); + } else { + if (username !== undefined || password !== undefined) throw new MoneroError("Can provide config object or params but not both"); + Object.assign(this, MoneroRpcConnection.DEFAULT_CONFIG, uriOrConnection); + this.setCredentials(this.username, this.password); + } + + // normalize uris + if (this.uri) this.uri = GenUtils.normalizeUri(this.uri); + if (this.zmqUri) this.zmqUri = GenUtils.normalizeUri(this.zmqUri); + if (this.proxyUri) this.proxyUri = GenUtils.normalizeUri(this.proxyUri); + + // initialize mutexes + this.checkConnectionMutex = new ThreadPool(1); + this.sendRequestMutex = new ThreadPool(1); + } + + setCredentials(username, password) { + if (username === "") username = undefined; + if (password === "") password = undefined; + if (username || password) { + if (!username) throw new MoneroError("username must be defined because password is defined"); + if (!password) throw new MoneroError("password must be defined because username is defined"); + } + if (this.username === "") this.username = undefined; + if (this.password === "") this.password = undefined; + if (this.username !== username || this.password !== password) { + this.isOnline = undefined; + this.isAuthenticated = undefined; + } + this.username = username; + this.password = password; + return this; + } + + getUri() { + return this.uri; + } + + getUsername() { + return this.username ? this.username : ""; + } + + getPassword() { + return this.password ? this.password : ""; + } + + getZmqUri() { + return this.zmqUri; + } + + setZmqUri(zmqUri) { + this.zmqUri = zmqUri; + return this; + } + + getProxyUri() { + return this.proxyUri; + } + + setProxyUri(proxyUri) { + this.proxyUri = proxyUri; + return this; + } + + getRejectUnauthorized() { + return this.rejectUnauthorized; + } + + setProxyToWorker(proxyToWorker) { + this.proxyToWorker = proxyToWorker; + return this; + } + + getProxyToWorker() { + return this.proxyToWorker; + } + + /** + * Set the connection's priority relative to other connections. Priority 1 is highest, + * then priority 2, etc. The default priority of 0 is lowest priority. + * + * @param {number} [priority] - the connection priority (default 0) + * @return {MoneroRpcConnection} this connection + */ + setPriority(priority) { + if (!(priority >= 0)) throw new MoneroError("Priority must be >= 0"); + this.priority = priority; + return this; + } + + getPriority() { + return this.priority; + } + + /** + * Set the RPC request timeout in milliseconds. + * + * @param {number} timeoutMs is the timeout in milliseconds, 0 to disable timeout, or undefined to use default + * @return {MoneroRpcConnection} this connection + */ + setTimeout(timeoutMs: number) { + this.timeoutMs = timeoutMs; + return this; + } + + getTimeout() { + return this.timeoutMs; + } + + setAttribute(key, value) { + if (!this.attributes) this.attributes = new Map(); + this.attributes.put(key, value); + return this; + } + + getAttribute(key) { + return this.attributes.get(key); + } + + /** + * Check the connection status to update isOnline, isAuthenticated, and response time. + * + * @param {number} timeoutMs - maximum response time before considered offline + * @return {Promise} true if there is a change in status, false otherwise + */ + async checkConnection(timeoutMs): Promise { + return this.queueCheckConnection(async () => { + await LibraryUtils.loadWasmModule(); // cache wasm for binary request + let isOnlineBefore = this.isOnline; + let isAuthenticatedBefore = this.isAuthenticated; + let startTime = Date.now(); + try { + if (this.fakeDisconnected) throw new Error("Connection is fake disconnected"); + let heights = []; + for (let i = 0; i < 100; i++) heights.push(i); + await this.sendBinaryRequest("get_blocks_by_height.bin", {heights: heights}, timeoutMs); // assume daemon connection + this.isOnline = true; + this.isAuthenticated = true; + } catch (err) { + this.isOnline = false; + this.isAuthenticated = undefined; + this.responseTime = undefined; + if (err instanceof MoneroRpcError) { + if (err.getCode() === 401) { + this.isOnline = true; + this.isAuthenticated = false; + } else if (err.getCode() === 404) { // fallback to latency check + this.isOnline = true; + this.isAuthenticated = true; + } + } + } + if (this.isOnline) this.responseTime = Date.now() - startTime; + return isOnlineBefore !== this.isOnline || isAuthenticatedBefore !== this.isAuthenticated; + }); + } + + /** + * Indicates if the connection is connected according to the last call to checkConnection().

+ * + * Note: must call checkConnection() manually unless using MoneroConnectionManager. + * + * @return {boolean} true or false to indicate if connected, or undefined if checkConnection() has not been called + */ + isConnected() { + return this.isOnline === undefined ? undefined : this.isOnline && this.isAuthenticated !== false; + } + + /** + * Indicates if the connection is online according to the last call to checkConnection().

+ * + * Note: must call checkConnection() manually unless using MoneroConnectionManager. + * + * @return {boolean} true or false to indicate if online, or undefined if checkConnection() has not been called + */ + getIsOnline() { + return this.isOnline; + } + + /** + * Indicates if the connection is authenticated according to the last call to checkConnection().

+ * + * Note: must call checkConnection() manually unless using MoneroConnectionManager. + * + * @return {boolean} true if authenticated or no authentication, false if not authenticated, or undefined if checkConnection() has not been called + */ + getIsAuthenticated() { + return this.isAuthenticated; + } + + getResponseTime() { + return this.responseTime; + } + + /** + * Send a JSON RPC request. + * + * @param {string} method - JSON RPC method to invoke + * @param {object} params - request parameters + * @param {number} [timeoutMs] - overrides the request timeout in milliseconds + * @return {object} is the response map + */ + async sendJsonRequest(method, params?, timeoutMs?): Promise { + return this.queueSendRequest(async () => { + try { + + // build request body + let body = JSON.stringify({ // body is stringified so text/plain is returned so bigints are preserved + id: "0", + jsonrpc: "2.0", + method: method, + params: params + }); + + // logging + if (LibraryUtils.getLogLevel() >= 2) LibraryUtils.log(2, "Sending json request with method '" + method + "' and body: " + body); + + // proxy uri is not supported + if (this.getProxyUri()) throw new MoneroError("Proxy URI not supported for JSON requests"); + + // send http request + let startTime = new Date().getTime(); + let resp = await HttpClient.request({ + method: "POST", + uri: this.getUri() + '/json_rpc', + username: this.getUsername(), + password: this.getPassword(), + body: body, + timeout: timeoutMs === undefined ? this.timeoutMs : timeoutMs, + rejectUnauthorized: this.rejectUnauthorized, + proxyToWorker: this.proxyToWorker + }); + + // validate response + MoneroRpcConnection.validateHttpResponse(resp); + + // deserialize response + if (resp.body[0] != '{') throw resp.body; + resp = JSON.parse(resp.body.replace(/("[^"]*"\s*:\s*)(\d{16,})/g, '$1"$2"')); // replace 16 or more digits with strings and parse + if (LibraryUtils.getLogLevel() >= 3) { + let respStr = JSON.stringify(resp); + LibraryUtils.log(3, "Received response from method='" + method + "', response=" + respStr.substring(0, Math.min(1000, respStr.length)) + "(" + (new Date().getTime() - startTime) + " ms)"); + } + + // check rpc response for errors + this.validateRpcResponse(resp, method, params); + return resp; + } catch (err: any) { + if (err instanceof MoneroRpcError) throw err; + else throw new MoneroRpcError(err, err.statusCode, method, params); + } + }); + } + + /** + * Send a RPC request to the given path and with the given paramters. + * + * E.g. "/get_transactions" with params + * + * @param {string} path - JSON RPC path to invoke + * @param {object} params - request parameters + * @param {number} [timeoutMs] - overrides the request timeout in milliseconds + * @return {object} is the response map + */ + async sendPathRequest(path, params?, timeoutMs?): Promise { + return this.queueSendRequest(async () => { + try { + + // logging + if (LibraryUtils.getLogLevel() >= 2) LibraryUtils.log(2, "Sending path request with path '" + path + "' and params: " + JSON.stringify(params)); + + // proxy uri is not supported + if (this.getProxyUri()) throw new MoneroError("Proxy URI not supported for path requests"); + + // send http request + let startTime = new Date().getTime(); + let resp = await HttpClient.request({ + method: "POST", + uri: this.getUri() + '/' + path, + username: this.getUsername(), + password: this.getPassword(), + body: JSON.stringify(params), // body is stringified so text/plain is returned so bigints are preserved + timeout: timeoutMs === undefined ? this.timeoutMs : timeoutMs, + rejectUnauthorized: this.rejectUnauthorized, + proxyToWorker: this.proxyToWorker + }); + + // validate response + MoneroRpcConnection.validateHttpResponse(resp); + + // deserialize response + if (resp.body[0] != '{') throw resp.body; + resp = JSON.parse(resp.body.replace(/("[^"]*"\s*:\s*)(\d{16,})/g, '$1"$2"')); // replace 16 or more digits with strings and parse + if (typeof resp === "string") resp = JSON.parse(resp); // TODO: some responses returned as strings? + if (LibraryUtils.getLogLevel() >= 3) { + let respStr = JSON.stringify(resp); + LibraryUtils.log(3, "Received response from path='" + path + "', response=" + respStr.substring(0, Math.min(1000, respStr.length)) + "(" + (new Date().getTime() - startTime) + " ms)"); + } + + // check rpc response for errors + this.validateRpcResponse(resp, path, params); + return resp; + } catch (err: any) { + if (err instanceof MoneroRpcError) throw err; + else throw new MoneroRpcError(err, err.statusCode, path, params); + } + }); + } + + /** + * Send a binary RPC request. + * + * @param {string} path - path of the binary RPC method to invoke + * @param {object} [params] - request parameters + * @param {number} [timeoutMs] - request timeout in milliseconds + * @return {Uint8Array} the binary response + */ + async sendBinaryRequest(path, params?, timeoutMs?): Promise { + return this.queueSendRequest(async () => { + + // serialize params + let paramsBin = await MoneroUtils.jsonToBinary(params); + + try { + + // logging + if (LibraryUtils.getLogLevel() >= 2) LibraryUtils.log(2, "Sending binary request with path '" + path + "' and params: " + JSON.stringify(params)); + + // proxy uri is not supported + if (this.getProxyUri()) throw new MoneroError("Proxy URI not supported for binary requests"); + + // send http request + let resp = await HttpClient.request({ + method: "POST", + uri: this.getUri() + '/' + path, + username: this.getUsername(), + password: this.getPassword(), + body: paramsBin, + timeout: timeoutMs === undefined ? this.timeoutMs : timeoutMs, + rejectUnauthorized: this.rejectUnauthorized, + proxyToWorker: this.proxyToWorker + }); + + // validate response + MoneroRpcConnection.validateHttpResponse(resp); + + // process response + resp = resp.body; + if (!(resp instanceof Uint8Array)) { + console.error("resp is not uint8array"); + console.error(resp); + } + if (resp.error) throw new MoneroRpcError(resp.error.message, resp.error.code, path, params); + return resp; + } catch (err: any) { + if (err instanceof MoneroRpcError) throw err; + else throw new MoneroRpcError(err, err.statusCode, path, params); + } + }); + } + + getConfig() { + return { + uri: this.uri, + username: this.username, + password: this.password, + zmqUri: this.zmqUri, + proxyUri: this.proxyUri, + rejectUnauthorized: this.rejectUnauthorized, + proxyToWorker: this.proxyToWorker, + priority: this.priority, + timeoutMs: this.timeoutMs + }; + } + + toJson() { + let json = Object.assign({}, this) + json.checkConnectionMutex = undefined; + json.sendRequestMutex = undefined; + return json; + } + + toString() { + return this.getUri() + " (username=" + this.getUsername() + ", password=" + (this.getPassword() ? "***" : this.getPassword()) + ", zmqUri=" + this.getZmqUri() + ", proxyUri=" + this.getProxyUri() + ", priority=" + this.getPriority() + ", timeoutMs=" + this.getTimeout() + ", isOnline=" + this.getIsOnline() + ", isAuthenticated=" + this.getIsAuthenticated() + ")"; + } + + setFakeDisconnected(fakeDisconnected) { // used to test connection manager + this.fakeDisconnected = fakeDisconnected; + } + + // ------------------------------ PRIVATE HELPERS -------------------------- + + protected async queueCheckConnection(asyncFn: () => Promise): Promise { + return this.checkConnectionMutex.submit(asyncFn); + } + + protected async queueSendRequest(asyncFn: () => Promise): Promise { + return this.sendRequestMutex.submit(asyncFn); + } + + protected static validateHttpResponse(resp) { + let code = resp.statusCode; + if (code < 200 || code > 299) { + let content = resp.body; + throw new MoneroRpcError(code + " " + resp.statusText + (!content ? "" : (": " + content)), code, undefined, undefined); + } + } + + protected validateRpcResponse(resp, method, params) { + if (resp.error === undefined) return; + let errorMsg = resp.error.message; + if (errorMsg === "") errorMsg = "Received error response from RPC request with method '" + method + "' to " + this.getUri(); // TODO (monero-project): response sometimes has empty error message + throw new MoneroRpcError(resp.error.message, resp.error.code, method, params); + } +} diff --git a/src/main/ts/common/MoneroRpcError.ts b/src/main/ts/common/MoneroRpcError.ts new file mode 100644 index 000000000..7b116d761 --- /dev/null +++ b/src/main/ts/common/MoneroRpcError.ts @@ -0,0 +1,39 @@ +import MoneroError from "./MoneroError"; + +/** + * Error when interacting with Monero RPC. + */ +export default class MoneroRpcError extends MoneroError { + + // instance variables + protected rpcMethod: any; + protected rpcParams: any; + + /** + * Constructs the error. + * + * @param {string} rpcDescription is a description of the error from rpc + * @param {number} rpcCode is the error code from rpc + * @param {string} [rpcMethod] is the rpc method invoked + * @param {object} [rpcParams] are parameters sent with the rpc request + */ + constructor(rpcDescription, rpcCode, rpcMethod?, rpcParams?) { + super(rpcDescription, rpcCode); + this.rpcMethod = rpcMethod; + this.rpcParams = rpcParams; + } + + getRpcMethod() { + return this.rpcMethod; + } + + getRpcParams() { + return this.rpcParams; + } + + toString() { + let str = super.toString(); + if (this.rpcMethod) str += "\nRPC request: '" + this.rpcMethod + "'"; + return str; + } +} diff --git a/src/main/ts/common/MoneroUtils.ts b/src/main/ts/common/MoneroUtils.ts new file mode 100644 index 000000000..022e84b08 --- /dev/null +++ b/src/main/ts/common/MoneroUtils.ts @@ -0,0 +1,477 @@ +import assert from "assert"; +import Decimal from 'decimal.js'; +import GenUtils from "./GenUtils"; +import LibraryUtils from "./LibraryUtils"; +import MoneroError from "./MoneroError"; +import MoneroIntegratedAddress from "../wallet/model/MoneroIntegratedAddress"; +import MoneroNetworkType from "../daemon/model/MoneroNetworkType"; +import ConnectionType from "../daemon/model/ConnectionType"; + +/** + * Collection of Monero utilities. Runs in a worker thread by default. + */ +export default class MoneroUtils { + + // static variables + static PROXY_TO_WORKER = false; + static NUM_MNEMONIC_WORDS = 25; + static AU_PER_XMR = 1000000000000n; + static RING_SIZE = 12; + + /** + *

Get the version of the monero-ts library.

+ * + * @return {string} the version of this monero-ts library + */ + static getVersion() { + return "0.11.6"; + } + + /** + * Enable or disable proxying these utilities to a worker thread. + * + * @param {boolean} proxyToWorker - specifies if utilities should be proxied to a worker + */ + static setProxyToWorker(proxyToWorker) { + MoneroUtils.PROXY_TO_WORKER = proxyToWorker || false; + } + + /** + * Validate the given mnemonic, throw an error if invalid. + * + * TODO: improve validation, use network type + * + * @param {string} mnemonic - mnemonic to validate + */ + static async validateMnemonic(mnemonic) { + assert(mnemonic, "Mnemonic phrase is not initialized"); + let words = mnemonic.split(" "); + if (words.length !== MoneroUtils.NUM_MNEMONIC_WORDS) throw new MoneroError("Mnemonic phrase is " + words.length + " words but must be " + MoneroUtils.NUM_MNEMONIC_WORDS); + } + + /** + * Indicates if a private view key is valid. + * + * @param {string} privateViewKey is the private view key to validate + * @return {Promise} true if the private view key is valid, false otherwise + */ + static async isValidPrivateViewKey(privateViewKey) { + try { + await MoneroUtils.validatePrivateViewKey(privateViewKey); + return true; + } catch (e) { + return false; + } + } + + /** + * Indicates if a public view key is valid. + * + * @param {string} publicViewKey is the public view key to validate + * @return {Promise} true if the public view key is valid, false otherwise + */ + static async isValidPublicViewKey(publicViewKey) { + try { + await MoneroUtils.validatePublicViewKey(publicViewKey); + return true; + } catch (e) { + return false; + } + } + + /** + * Indicates if a private spend key is valid. + * + * @param {string} privateSpendKey is the private spend key to validate + * @return {Promise} true if the private spend key is valid, false otherwise + */ + static async isValidPrivateSpendKey(privateSpendKey) { + try { + await MoneroUtils.validatePrivateSpendKey(privateSpendKey); + return true; + } catch (e) { + return false; + } + } + + /** + * Indicates if a public spend key is valid. + * + * @param {string} publicSpendKey is the public spend key to validate + * @return {Promise} true if the public spend key is valid, false otherwise + */ + static async isValidPublicSpendKey(publicSpendKey) { + try { + await MoneroUtils.validatePublicSpendKey(publicSpendKey); + return true; + } catch (e) { + return false; + } + } + + /** + * Validate the given private view key, throw an error if invalid. + * + * @param {string} privateViewKey - private view key to validate + */ + static async validatePrivateViewKey(privateViewKey) { + if (!MoneroUtils.isHex64(privateViewKey)) throw new MoneroError("private view key expected to be 64 hex characters"); + } + + /** + * Validate the given public view key, throw an error if invalid. + * + * @param {string} publicViewKey - public view key to validate + */ + static async validatePublicViewKey(publicViewKey) { + if (!MoneroUtils.isHex64(publicViewKey)) throw new MoneroError("public view key expected to be 64 hex characters"); + } + + /** + * Validate the given private spend key, throw an error if invalid. + * + * @param {string} privateSpendKey - private spend key to validate + */ + static async validatePrivateSpendKey(privateSpendKey) { + if (!MoneroUtils.isHex64(privateSpendKey)) throw new MoneroError("private spend key expected to be 64 hex characters"); + } + + /** + * Validate the given public spend key, throw an error if invalid. + * + * @param {string} publicSpendKey - public spend key to validate + */ + static async validatePublicSpendKey(publicSpendKey) { + if (!MoneroUtils.isHex64(publicSpendKey)) throw new MoneroError("public spend key expected to be 64 hex characters"); + } + + /** + * Get an integrated address. + * + * @param {MoneroNetworkType} networkType - network type of the integrated address + * @param {string} standardAddress - address to derive the integrated address from + * @param {string} [paymentId] - optionally specifies the integrated address's payment id (defaults to random payment id) + * @return {Promise} the integrated address + */ + static async getIntegratedAddress(networkType: MoneroNetworkType, standardAddress: string, paymentId?: string) { + if (MoneroUtils.PROXY_TO_WORKER) return new MoneroIntegratedAddress(await LibraryUtils.invokeWorker(undefined, "moneroUtilsGetIntegratedAddress", Array.from(arguments))); + + // validate inputs + MoneroNetworkType.validate(networkType); + assert(typeof standardAddress === "string", "Address is not string"); + assert(standardAddress.length > 0, "Address is empty"); + assert(GenUtils.isBase58(standardAddress), "Address is not base 58"); + + // load keys module by default + if (LibraryUtils.getWasmModule() === undefined) await LibraryUtils.loadWasmModule(); + + // get integrated address in queue + return LibraryUtils.getWasmModule().queueTask(async () => { + let integratedAddressJson = LibraryUtils.getWasmModule().get_integrated_address_util(networkType, standardAddress, paymentId ? paymentId : ""); + if (integratedAddressJson.charAt(0) !== '{') throw new MoneroError(integratedAddressJson); + return new MoneroIntegratedAddress(JSON.parse(integratedAddressJson)); + }); + } + + /** + * Determine if the given address is valid. + * + * @param {string} address - address + * @param {MoneroNetworkType} networkType - network type of the address to validate + * @return {Promise} true if the address is valid, false otherwise + */ + static async isValidAddress(address, networkType) { + try { + await MoneroUtils.validateAddress(address, networkType); + return true; + } catch (err) { + return false; + } + } + + /** + * Validate the given address, throw an error if invalid. + * + * @param {string} address - address to validate + * @param {MoneroNetworkType} networkType - network type of the address to validate + */ + static async validateAddress(address, networkType) { + if (MoneroUtils.PROXY_TO_WORKER) return LibraryUtils.invokeWorker(undefined, "moneroUtilsValidateAddress", Array.from(arguments)); + + // validate inputs + assert(typeof address === "string", "Address is not string"); + assert(address.length > 0, "Address is empty"); + assert(GenUtils.isBase58(address), "Address is not base 58"); + networkType = MoneroNetworkType.from(networkType); + + // load keys module by default + if (LibraryUtils.getWasmModule() === undefined) await LibraryUtils.loadWasmModule(); + + // validate address in queue + return LibraryUtils.getWasmModule().queueTask(async function() { + let errMsg = LibraryUtils.getWasmModule().validate_address(address, networkType); + if (errMsg) throw new MoneroError(errMsg); + }); + } + + /** + * Determine if the given payment id is valid. + * + * @param {string} paymentId - payment id to determine if valid + * @return {Promise} true if the payment id is valid, false otherwise + */ + static async isValidPaymentId(paymentId) { + try { + await MoneroUtils.validatePaymentId(paymentId); + return true; + } catch (e) { + return false; + } + } + + /** + * Validate the given payment id, throw an error if invalid. + * + * TODO: improve validation + * + * @param {string} paymentId - payment id to validate + */ + static async validatePaymentId(paymentId) { + assert.equal(typeof paymentId, "string"); + assert(paymentId.length === 16 || paymentId.length === 64); + } + + /** + * Decode tx extra according to https://cryptonote.org/cns/cns005.txt and + * returns the last tx pub key. + * + * TODO: use c++ bridge for this + * + * @param [byte[]] txExtra - array of tx extra bytes + * @return {string} the last pub key as a hexidecimal string + */ + static async getLastTxPubKey(txExtra) { + let lastPubKeyIdx; + for (let i = 0; i < txExtra.length; i++) { + let tag = txExtra[i]; + if (tag === 0 || tag === 2) { + i += 1 + txExtra[i + 1]; // advance to next tag + } else if (tag === 1) { + lastPubKeyIdx = i + 1; + i += 1 + 32; // advance to next tag + } else throw new MoneroError("Invalid sub-field tag: " + tag); + } + return Buffer.from(new Uint8Array(txExtra.slice(lastPubKeyIdx, lastPubKeyIdx + 32))).toString("hex"); + } + + /** + * Determines if two payment ids are functionally equal. + * + * For example, 03284e41c342f032 and 03284e41c342f032000000000000000000000000000000000000000000000000 are considered equal. + * + * @param {string} paymentId1 is a payment id to compare + * @param {string} paymentId2 is a payment id to compare + * @return {bool} true if the payment ids are equal, false otherwise + */ + static paymentIdsEqual(paymentId1, paymentId2) { + let maxLength = Math.max(paymentId1.length, paymentId2.length); + for (let i = 0; i < maxLength; i++) { + if (i < paymentId1.length && i < paymentId2.length && paymentId1[i] !== paymentId2[i]) return false; + if (i >= paymentId1.length && paymentId2[i] !== '0') return false; + if (i >= paymentId2.length && paymentId1[i] !== '0') return false; + } + return true; + } + + /** + * Merges a transaction into a list of existing transactions. + * + * @param {MoneroTx[]} txs - existing transactions to merge into + * @param {MoneroTx} tx - transaction to merge into the list + */ + static mergeTx(txs, tx) { + for (let aTx of txs) { + if (aTx.getHash() === tx.getHash()) { + aTx.merge(tx); + return; + } + } + txs.push(tx); + } + + /** + * Convert the given JSON to a binary Uint8Array using Monero's portable storage format. + * + * @param {object} json - json to convert to binary + * @return {Promise} the json converted to portable storage binary + */ + static async jsonToBinary(json) { + if (MoneroUtils.PROXY_TO_WORKER) return LibraryUtils.invokeWorker(undefined, "moneroUtilsJsonToBinary", Array.from(arguments)); + + // load keys module by default + if (LibraryUtils.getWasmModule() === undefined) await LibraryUtils.loadWasmModule(); + + // use wasm in queue + return LibraryUtils.getWasmModule().queueTask(async function() { + + // serialize json to binary which is stored in c++ heap + let binMemInfoStr = LibraryUtils.getWasmModule().malloc_binary_from_json(JSON.stringify(json)); + + // sanitize binary memory address info + let binMemInfo = JSON.parse(binMemInfoStr); + binMemInfo.ptr = parseInt(binMemInfo.ptr); + binMemInfo.length = parseInt(binMemInfo.length); + + // read binary data from heap to Uint8Array + let view = new Uint8Array(binMemInfo.length); + for (let i = 0; i < binMemInfo.length; i++) { + view[i] = LibraryUtils.getWasmModule().HEAPU8[binMemInfo.ptr / Uint8Array.BYTES_PER_ELEMENT + i]; + } + + // free binary on heap + LibraryUtils.getWasmModule()._free(binMemInfo.ptr); + + // return json from binary data + return view; + }); + } + + /** + * Convert the given portable storage binary to JSON. + * + * @param {Uint8Array} uint8arr - binary data in Monero's portable storage format + * @return {Promise} JSON object converted from the binary data + */ + static async binaryToJson(uint8arr) { + if (MoneroUtils.PROXY_TO_WORKER) return LibraryUtils.invokeWorker(undefined, "moneroUtilsBinaryToJson", Array.from(arguments)); + + // load keys module by default + if (LibraryUtils.getWasmModule() === undefined) await LibraryUtils.loadWasmModule(); + + // use wasm in queue + return LibraryUtils.getWasmModule().queueTask(async function() { + + // allocate space in c++ heap for binary + let ptr = LibraryUtils.getWasmModule()._malloc(uint8arr.length * uint8arr.BYTES_PER_ELEMENT); + let heap = new Uint8Array(LibraryUtils.getWasmModule().HEAPU8.buffer, ptr, uint8arr.length * uint8arr.BYTES_PER_ELEMENT); + if (ptr !== heap.byteOffset) throw new MoneroError("Memory ptr !== heap.byteOffset"); // should be equal + + // write binary to heap + heap.set(new Uint8Array(uint8arr.buffer)); + + // create object with binary memory address info + let binMemInfo = { ptr: ptr, length: uint8arr.length }; + + // convert binary to json str + const ret_string = LibraryUtils.getWasmModule().binary_to_json(JSON.stringify(binMemInfo)); + + // free binary on heap + LibraryUtils.getWasmModule()._free(ptr); + + // parse and return json + return JSON.parse(ret_string); + }); + } + + /** + * Convert the binary response from daemon RPC block retrieval to JSON. + * + * @param {Uint8Array} uint8arr - binary response from daemon RPC when getting blocks + * @return {Promise} JSON object with the blocks data + */ + static async binaryBlocksToJson(uint8arr) { + if (MoneroUtils.PROXY_TO_WORKER) return LibraryUtils.invokeWorker(undefined, "moneroUtilsBinaryBlocksToJson", Array.from(arguments)); + + // load keys module by default + if (LibraryUtils.getWasmModule() === undefined) await LibraryUtils.loadWasmModule(); + + // use wasm in queue + return LibraryUtils.getWasmModule().queueTask(async function() { + + // allocate space in c++ heap for binary + let ptr = LibraryUtils.getWasmModule()._malloc(uint8arr.length * uint8arr.BYTES_PER_ELEMENT); + let heap = new Uint8Array(LibraryUtils.getWasmModule().HEAPU8.buffer, ptr, uint8arr.length * uint8arr.BYTES_PER_ELEMENT); + if (ptr !== heap.byteOffset) throw new MoneroError("Memory ptr !== heap.byteOffset"); // should be equal + + // write binary to heap + heap.set(new Uint8Array(uint8arr.buffer)); + + // create object with binary memory address info + let binMemInfo = { ptr: ptr, length: uint8arr.length } + + // convert binary to json str + const json_str = LibraryUtils.getWasmModule().binary_blocks_to_json(JSON.stringify(binMemInfo)); + + // free memory + LibraryUtils.getWasmModule()._free(ptr); + + // parse result to json + let json = JSON.parse(json_str); // parsing json gives arrays of block and tx strings + json.blocks = json.blocks.map(blockStr => JSON.parse(blockStr)); // replace block strings with parsed blocks + json.txs = json.txs.map(txs => txs ? txs.map(tx => JSON.parse(tx.replace(",", "{") + "}")) : []); // modify tx string to proper json and parse // TODO: more efficient way than this json manipulation? + return json; + }); + } + + /** + * Convert XMR to atomic units. + * + * @param {number | string} amountXmr - amount in XMR to convert to atomic units + * @return {bigint} amount in atomic units + */ + static xmrToAtomicUnits(amountXmr: number | string): bigint { + return BigInt(new Decimal(amountXmr).mul(MoneroUtils.AU_PER_XMR.toString()).toDecimalPlaces(0, Decimal.ROUND_HALF_UP).toFixed(0)); + } + + /** + * Convert atomic units to XMR. + * + * @param {bigint | string} amountAtomicUnits - amount in atomic units to convert to XMR + * @return {number} amount in XMR + */ + static atomicUnitsToXmr(amountAtomicUnits: bigint | string): number { + return new Decimal(amountAtomicUnits.toString()).div(MoneroUtils.AU_PER_XMR.toString()).toDecimalPlaces(12, Decimal.ROUND_HALF_UP).toNumber(); + } + + /** + * Divide one atomic units by another. + * + * @param {bigint} au1 dividend + * @param {bigint} au2 divisor + * @returns {number} the result + */ + static divide(au1: bigint, au2: bigint): number { + return new Decimal(au1.toString()).div(new Decimal(au2.toString())).toDecimalPlaces(12, Decimal.ROUND_HALF_UP).toNumber(); + } + + /** + * Multiply a bigint by a number or bigint. + * + * @param a bigint to multiply + * @param b bigint or number to multiply by + * @returns the product as a bigint + */ + static multiply(a: bigint, b: number | bigint): bigint { + return BigInt(new Decimal(a.toString()).mul(new Decimal(b.toString())).toDecimalPlaces(0, Decimal.ROUND_HALF_UP).toString()); + } + + protected static isHex64(str) { + return typeof str === "string" && str.length === 64 && GenUtils.isHex(str); + } + + /** + * Determine if the given unlock time is a timestamp or block height. + * + * @param unlockTime is the unlock time to check + * @return {boolean} true if the unlock time is a timestamp, false if a block height + */ + static isTimestamp(unlockTime: bigint) { + + // threshold for distinguishing between timestamp and block height + // current block height is around 3 million, current unix timestamp is around 1.7 billion + const threshold = 500000000n; + + return unlockTime >= threshold; + } +} + diff --git a/src/main/js/common/MoneroWebWorker.js b/src/main/ts/common/MoneroWebWorker.ts similarity index 72% rename from src/main/js/common/MoneroWebWorker.js rename to src/main/ts/common/MoneroWebWorker.ts index d45d8a23d..47af22c15 100644 --- a/src/main/js/common/MoneroWebWorker.js +++ b/src/main/ts/common/MoneroWebWorker.ts @@ -1,28 +1,48 @@ -const assert = require("assert"); -const GenUtils = require("./GenUtils"); -const LibraryUtils = require("./LibraryUtils"); -const MoneroBan = require("../daemon/model/MoneroBan"); -const MoneroBlock = require("../daemon/model/MoneroBlock"); -const MoneroDaemonRpc = require("../daemon/MoneroDaemonRpc"); -const MoneroError = require("./MoneroError"); -const MoneroKeyImage = require("../daemon/model/MoneroKeyImage"); -const MoneroRpcConnection = require("./MoneroRpcConnection"); -const MoneroTxConfig = require("../wallet/model/MoneroTxConfig"); -const MoneroTxSet = require("../wallet/model/MoneroTxSet"); -const MoneroUtils = require("./MoneroUtils"); -const MoneroWalletListener = require("../wallet/model/MoneroWalletListener"); -const MoneroWalletWasm = require("../wallet/MoneroWalletWasm"); +import assert from "assert"; +import GenUtils from "./GenUtils"; +import HttpClient from "./HttpClient"; +import LibraryUtils from "./LibraryUtils"; +import MoneroBan from "../daemon/model/MoneroBan"; +import MoneroBlock from "../daemon/model/MoneroBlock"; +import MoneroDaemonConfig from "../daemon/model/MoneroDaemonConfig"; +import MoneroDaemonListener from "../daemon/model/MoneroDaemonListener"; +import MoneroDaemonRpc from "../daemon/MoneroDaemonRpc"; +import MoneroError from "./MoneroError"; +import MoneroKeyImage from "../daemon/model/MoneroKeyImage"; +import MoneroRpcConnection from "./MoneroRpcConnection"; +import MoneroTxConfig from "../wallet/model/MoneroTxConfig"; +import MoneroTxQuery from "../wallet/model/MoneroTxQuery"; +import MoneroTxSet from "../wallet/model/MoneroTxSet"; +import MoneroUtils from "./MoneroUtils"; +import MoneroWalletConfig from "../wallet/model/MoneroWalletConfig" +import MoneroWalletListener from "../wallet/model/MoneroWalletListener" +import {MoneroWalletKeys} from "../wallet/MoneroWalletKeys"; +import MoneroWalletFull from "../wallet/MoneroWalletFull"; + +declare var self: any; + +// deno configuration +declare var DedicatedWorkerGlobalScope: any; +if (GenUtils.isDeno() && typeof self === "undefined" && typeof globalThis === "object" && typeof DedicatedWorkerGlobalScope === "function" && DedicatedWorkerGlobalScope.prototype.isPrototypeOf(globalThis)) { + self = globalThis; + (globalThis as any).self = globalThis; +} + +// expose some modules to the worker +self.HttpClient = HttpClient; +self.LibraryUtils = LibraryUtils; +self.GenUtils = GenUtils; /** - * Web worker to manage a daemon and wasm wallet off the main thread with messages. + * Worker to manage a daemon and wasm wallet off the main thread using messages. * * Required message format: e.data[0] = object id, e.data[1] = function name, e.data[2+] = function args * - * This file must be browserified and placed in the web app root. + * For browser applications, this file must be browserified and placed in the web app root. * * @private */ -onmessage = async function(e) { +self.onmessage = async function(e) { // initialize one time await self.initOneTime(); @@ -30,17 +50,18 @@ onmessage = async function(e) { // validate params let objectId = e.data[0]; let fnName = e.data[1]; - assert(objectId, "Must provide object id to apply function to"); - assert(fnName.length >= 2, "Must provide a function name with length >= 2"); + let callbackId = e.data[2]; + assert(fnName, "Must provide function name to worker"); + assert(callbackId, "Must provide callback id to worker"); if (!self[fnName]) throw new Error("Method '" + fnName + "' is not registered with worker"); - e.data.splice(1, 1); // remove function name + e.data.splice(1, 2); // remove function name and callback id to apply function with arguments // execute worker function and post result to callback - let callbackFn = "on" + fnName.charAt(0).toUpperCase() + fnName.substring(1); try { - postMessage([objectId, callbackFn, {result: await self[fnName].apply(null, e.data)}]); - } catch (e) { - postMessage([objectId, callbackFn, {error: e.message}]); + postMessage([objectId, callbackId, {result: await self[fnName].apply(null, e.data)}]); + } catch (e: any) { + if (!(e instanceof Error)) e = new Error(e); + postMessage([objectId, callbackId, {error: LibraryUtils.serializeError(e)}]); } } @@ -48,19 +69,71 @@ self.initOneTime = async function() { if (!self.isInitialized) { self.WORKER_OBJECTS = {}; self.isInitialized = true; + MoneroUtils.PROXY_TO_WORKER = false; } } // --------------------------- STATIC UTILITIES ------------------------------- -self.getWasmMemoryUsed = async function(objectId) { // TODO: object id not needed for static utilites, using throwaway uuid +self.httpRequest = async function(objectId, opts) { + try { + return await HttpClient.request(Object.assign(opts, {proxyToWorker: false})); + } catch (err: any) { + throw err.statusCode ? new Error(JSON.stringify({statusCode: err.statusCode, statusMessage: err.message})) : err; + } +} + +self.setLogLevel = async function(objectId, level) { + return LibraryUtils.setLogLevel(level); +} + +self.getWasmMemoryUsed = async function(objectId) { return LibraryUtils.getWasmModule() && LibraryUtils.getWasmModule().HEAP8 ? LibraryUtils.getWasmModule().HEAP8.length : undefined; } +// ----------------------------- MONERO UTILS --------------------------------- + +self.moneroUtilsGetIntegratedAddress = async function(objectId, networkType, standardAddress, paymentId) { + return (await MoneroUtils.getIntegratedAddress(networkType, standardAddress, paymentId)).toJson(); +} + +self.moneroUtilsValidateAddress = async function(objectId, address, networkType) { + return MoneroUtils.validateAddress(address, networkType); +} + +self.moneroUtilsJsonToBinary = async function(objectId, json) { + return MoneroUtils.jsonToBinary(json); +} + +self.moneroUtilsBinaryToJson = async function(objectId, uint8arr) { + return MoneroUtils.binaryToJson(uint8arr); +} + +self.moneroUtilsBinaryBlocksToJson = async function(objectId, uint8arr) { + return MoneroUtils.binaryBlocksToJson(uint8arr); +} + // ---------------------------- DAEMON METHODS -------------------------------- +self.daemonAddListener = async function(daemonId, listenerId) { + let listener = new class extends MoneroDaemonListener { + async onBlockHeader(blockHeader) { + self.postMessage([daemonId, "onBlockHeader_" + listenerId, blockHeader.toJson()]); + } + } + if (!self.daemonListeners) self.daemonListeners = {}; + self.daemonListeners[listenerId] = listener; + await self.WORKER_OBJECTS[daemonId].addListener(listener); +} + +self.daemonRemoveListener = async function(daemonId, listenerId) { + if (!self.daemonListeners[listenerId]) throw new MoneroError("No daemon worker listener registered with id: " + listenerId); + await self.WORKER_OBJECTS[daemonId].removeListener(self.daemonListeners[listenerId]); + delete self.daemonListeners[listenerId]; +} + self.connectDaemonRpc = async function(daemonId, config) { - self.WORKER_OBJECTS[daemonId] = new MoneroDaemonRpc(config); + self.WORKER_OBJECTS[daemonId] = await MoneroDaemonRpc.connectToDaemonRpc(new MoneroDaemonConfig(config)); } self.daemonGetRpcConnection = async function(daemonId) { @@ -182,7 +255,7 @@ self.daemonGetMinerTxSum = async function(daemonId, height, numBlocks) { } self.daemonGetFeeEstimate = async function(daemonId, graceBlocks) { - return (await self.WORKER_OBJECTS[daemonId].getFeeEstimate(graceBlocks)).toString(); + return (await self.WORKER_OBJECTS[daemonId].getFeeEstimate(graceBlocks)).toJson(); } self.daemonSubmitTxHex = async function(daemonId, txHex, doNotRelay) { @@ -284,16 +357,16 @@ self.daemonResetUploadLimit = async function(daemonId) { return self.WORKER_OBJECTS[daemonId].resetUploadLimit(); } -self.daemonGetKnownPeers = async function(daemonId) { +self.daemonGetPeers = async function(daemonId) { let peersJson = []; - for (let peer of await self.WORKER_OBJECTS[daemonId].getKnownPeers()) peersJson.push(peer.toJson()); + for (let peer of await self.WORKER_OBJECTS[daemonId].getPeers()) peersJson.push(peer.toJson()); return peersJson; } -self.daemonGetConnections = async function(daemonId) { - let connectionsJson = []; - for (let connection of await self.WORKER_OBJECTS[daemonId].getConnections()) connectionsJson.push(connection.toJson()); - return connectionsJson; +self.daemonGetKnownPeers = async function(daemonId) { + let peersJson = []; + for (let peer of await self.WORKER_OBJECTS[daemonId].getKnownPeers()) peersJson.push(peer.toJson()); + return peersJson; } self.daemonSetOutgoingPeerLimit = async function(daemonId, limit) { @@ -328,11 +401,14 @@ self.daemonGetMiningStatus = async function(daemonId) { return (await self.WORKER_OBJECTS[daemonId].getMiningStatus()).toJson(); } -// -//async submitBlocks(blockBlobs) { -// throw new MoneroError("Not implemented"); -//} -// +self.daemonSubmitBlocks = async function(daemonId, blockBlobs) { + return self.WORKER_OBJECTS[daemonId].submitBlocks(blockBlobs); +} + +self.daemonPruneBlockchain = async function(daemonId, check) { + return (await self.WORKER_OBJECTS[daemonId].pruneBlockchain(check)).toJson(); +} + //async checkForUpdate() { // throw new MoneroError("Not implemented"); //} @@ -345,49 +421,31 @@ self.daemonStop = async function(daemonId) { return self.WORKER_OBJECTS[daemonId].stop(); } -self.daemonGetNextBlockHeader = async function(daemonId) { - return (await self.WORKER_OBJECTS[daemonId].getNextBlockHeader()).toJson(); -} - -self.daemonAddBlockListener = async function(daemonId, listenerId) { - let listener = function(blockHeader) { - self.postMessage([daemonId, "onNewBlockHeader_" + listenerId, blockHeader.toJson()]); - } - if (!self.daemonListeners) self.daemonListeners = {}; - self.daemonListeners[listenerId] = listener; - await self.WORKER_OBJECTS[daemonId].addBlockListener(listener); -} - -self.daemonRemoveBlockListener = async function(daemonId, listenerId) { - if (!self.daemonListeners[listenerId]) throw new MoneroError("No daemon worker listener registered with id: " + listenerId); - await self.WORKER_OBJECTS[daemonId].removeBlockListener(self.daemonListeners[listenerId]); - delete self.daemonListeners[listenerId]; +self.daemonWaitForNextBlockHeader = async function(daemonId) { + return (await self.WORKER_OBJECTS[daemonId].waitForNextBlockHeader()).toJson(); } //------------------------------ WALLET METHODS ------------------------------- self.openWalletData = async function(walletId, path, password, networkType, keysData, cacheData, daemonUriOrConfig) { let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined; - self.WORKER_OBJECTS[walletId] = await MoneroWalletWasm.openWallet({path: "", password: password, networkType: networkType, keysData: keysData, cacheData: cacheData, server: daemonConnection, proxyToWorker: false}); - self.WORKER_OBJECTS[walletId]._setBrowserMainPath(path); + self.WORKER_OBJECTS[walletId] = await MoneroWalletFull.openWallet({path: "", password: password, networkType: networkType, keysData: keysData, cacheData: cacheData, server: daemonConnection, proxyToWorker: false}); + self.WORKER_OBJECTS[walletId].setBrowserMainPath(path); } -self._createWalletRandom = async function(walletId, path, password, networkType, daemonUriOrConfig, language) { - let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined; - self.WORKER_OBJECTS[walletId] = await MoneroWalletWasm._createWalletRandom("", password, networkType, daemonConnection, language, false); - self.WORKER_OBJECTS[walletId]._setBrowserMainPath(path); -} - -self._createWalletFromMnemonic = async function(walletId, path, password, networkType, mnemonic, daemonUriOrConfig, restoreHeight, seedOffset) { - let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined; - self.WORKER_OBJECTS[walletId] = await MoneroWalletWasm._createWalletFromMnemonic("", password, networkType, mnemonic, daemonConnection, restoreHeight, seedOffset, false); - self.WORKER_OBJECTS[walletId]._setBrowserMainPath(path); +self.createWalletKeys = async function(walletId, configJson) { + let config = new MoneroWalletConfig(configJson); + config.setProxyToWorker(false); + self.WORKER_OBJECTS[walletId] = await MoneroWalletKeys.createWallet(config); } -self._createWalletFromKeys = async function(walletId, path, password, networkType, address, viewKey, spendKey, daemonUriOrConfig, restoreHeight, language) { - let daemonConnection = daemonUriOrConfig ? new MoneroRpcConnection(daemonUriOrConfig) : undefined; - self.WORKER_OBJECTS[walletId] = await MoneroWalletWasm._createWalletFromKeys("", password, networkType, address, viewKey, spendKey, daemonConnection, restoreHeight, language, false); - self.WORKER_OBJECTS[walletId]._setBrowserMainPath(path); +self.createWalletFull = async function(walletId, configJson) { + let config = new MoneroWalletConfig(configJson); + let path = config.getPath(); + config.setPath(""); + config.setProxyToWorker(false); + self.WORKER_OBJECTS[walletId] = await MoneroWalletFull.createWallet(config); + self.WORKER_OBJECTS[walletId].setBrowserMainPath(path); } self.isViewOnly = async function(walletId) { @@ -403,16 +461,16 @@ self.getNetworkType = async function(walletId) { // throw new Error("Not implemented"); //} -self.getMnemonic = async function(walletId) { - return self.WORKER_OBJECTS[walletId].getMnemonic(); +self.getSeed = async function(walletId) { + return self.WORKER_OBJECTS[walletId].getSeed(); } -self.getMnemonicLanguage = async function(walletId) { - return self.WORKER_OBJECTS[walletId].getMnemonicLanguage(); +self.getSeedLanguage = async function(walletId) { + return self.WORKER_OBJECTS[walletId].getSeedLanguage(); } -self.getMnemonicLanguages = async function(walletId) { - return self.WORKER_OBJECTS[walletId].getMnemonicLanguages(); +self.getSeedLanguages = async function(walletId) { + return self.WORKER_OBJECTS[walletId].getSeedLanguages(); } self.getPrivateSpendKey = async function(walletId) { @@ -439,8 +497,12 @@ self.getAddressIndex = async function(walletId, address) { return (await self.WORKER_OBJECTS[walletId].getAddressIndex(address)).toJson(); } -self.getIntegratedAddress = async function(walletId, paymentId) { - return (await self.WORKER_OBJECTS[walletId].getIntegratedAddress(paymentId)).toJson(); +self.setSubaddressLabel = async function(walletId, accountIdx, subaddressIdx, label) { + await self.WORKER_OBJECTS[walletId].setSubaddressLabel(accountIdx, subaddressIdx, label); +} + +self.getIntegratedAddress = async function(walletId, standardAddress, paymentId) { + return (await self.WORKER_OBJECTS[walletId].getIntegratedAddress(standardAddress, paymentId)).toJson(); } self.decodeIntegratedAddress = async function(walletId, integratedAddress) { @@ -448,7 +510,7 @@ self.decodeIntegratedAddress = async function(walletId, integratedAddress) { } self.setDaemonConnection = async function(walletId, config) { - return self.WORKER_OBJECTS[walletId].setDaemonConnection(config ? new MoneroRpcConnection(config) : undefined); + return self.WORKER_OBJECTS[walletId].setDaemonConnection(config ? new MoneroRpcConnection(Object.assign(config, {proxyToWorker: false})) : undefined); } self.getDaemonConnection = async function(walletId) { @@ -456,16 +518,16 @@ self.getDaemonConnection = async function(walletId) { return connection ? connection.getConfig() : undefined; } -self.isConnected = async function(walletId) { - return self.WORKER_OBJECTS[walletId].isConnected(); +self.isConnectedToDaemon = async function(walletId) { + return self.WORKER_OBJECTS[walletId].isConnectedToDaemon(); } -self.getSyncHeight = async function(walletId) { - return self.WORKER_OBJECTS[walletId].getSyncHeight(); +self.getRestoreHeight = async function(walletId) { + return self.WORKER_OBJECTS[walletId].getRestoreHeight(); } -self.setSyncHeight = async function(walletId, syncHeight) { - return self.WORKER_OBJECTS[walletId].setSyncHeight(syncHeight); +self.setRestoreHeight = async function(walletId, restoreHeight) { + return self.WORKER_OBJECTS[walletId].setRestoreHeight(restoreHeight); } self.getDaemonHeight = async function(walletId) { @@ -498,6 +560,10 @@ self.addListener = async function(walletId, listenerId) { * @private */ class WalletWorkerHelperListener extends MoneroWalletListener { + + protected walletId: string; + protected id: string; + protected worker: Worker; constructor(walletId, id, worker) { super(); @@ -510,25 +576,25 @@ self.addListener = async function(walletId, listenerId) { return this.id; } - onSyncProgress(height, startHeight, endHeight, percentDone, message) { + async onSyncProgress(height, startHeight, endHeight, percentDone, message) { this.worker.postMessage([this.walletId, "onSyncProgress_" + this.getId(), height, startHeight, endHeight, percentDone, message]); } - onNewBlock(height) { + async onNewBlock(height) { this.worker.postMessage([this.walletId, "onNewBlock_" + this.getId(), height]); } - onBalancesChanged(newBalance, newUnlockedBalance) { + async onBalancesChanged(newBalance, newUnlockedBalance) { this.worker.postMessage([this.walletId, "onBalancesChanged_" + this.getId(), newBalance.toString(), newUnlockedBalance.toString()]); } - onOutputReceived(output) { + async onOutputReceived(output) { let block = output.getTx().getBlock(); if (block === undefined) block = new MoneroBlock().setTxs([output.getTx()]); this.worker.postMessage([this.walletId, "onOutputReceived_" + this.getId(), block.toJson()]); // serialize from root block } - onOutputSpent(output) { + async onOutputSpent(output) { let block = output.getTx().getBlock(); if (block === undefined) block = new MoneroBlock().setTxs([output.getTx()]); this.worker.postMessage([this.walletId, "onOutputSpent_" + this.getId(), block.toJson()]); // serialize from root block @@ -555,18 +621,22 @@ self.isSynced = async function(walletId) { return self.WORKER_OBJECTS[walletId].isSynced(); } -self.sync = async function(walletId, startHeight) { - return await self.WORKER_OBJECTS[walletId].sync(startHeight); +self.sync = async function(walletId, startHeight, allowConcurrentCalls) { + return (await self.WORKER_OBJECTS[walletId].sync(undefined, startHeight, allowConcurrentCalls)); } -self.startSyncing = async function(walletId) { - return self.WORKER_OBJECTS[walletId].startSyncing(); +self.startSyncing = async function(walletId, syncPeriodInMs) { + return self.WORKER_OBJECTS[walletId].startSyncing(syncPeriodInMs); } self.stopSyncing = async function(walletId) { return self.WORKER_OBJECTS[walletId].stopSyncing(); } +self.scanTxs = async function(walletId, txHashes) { + return self.WORKER_OBJECTS[walletId].scanTxs(txHashes); +} + self.rescanSpent = async function(walletId) { return self.WORKER_OBJECTS[walletId].rescanSpent(); } @@ -634,13 +704,13 @@ self.getTxs = async function(walletId, blockJsonQuery) { // serialize blocks to json for (let i = 0; i < blocks.length; i++) blocks[i] = blocks[i].toJson(); - return blocks; + return {blocks: blocks}; } self.getTransfers = async function(walletId, blockJsonQuery) { // deserialize query which is json string rooted at block - let query = new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0].getTransferQuery(); + let query = (new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0] as MoneroTxQuery).getTransferQuery(); // get transfers let transfers = await self.WORKER_OBJECTS[walletId].getTransfers(query); @@ -670,7 +740,7 @@ self.getTransfers = async function(walletId, blockJsonQuery) { self.getOutputs = async function(walletId, blockJsonQuery) { // deserialize query which is json string rooted at block - let query = new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0].getOutputQuery(); + let query = (new MoneroBlock(blockJsonQuery, MoneroBlock.DeserializationType.TX_QUERY).getTxs()[0] as MoneroTxQuery).getOutputQuery(); // get outputs let outputs = await self.WORKER_OBJECTS[walletId].getOutputs(query); @@ -697,17 +767,17 @@ self.getOutputs = async function(walletId, blockJsonQuery) { return blocks; } -self.getOutputsHex = async function(walletId) { - return self.WORKER_OBJECTS[walletId].getOutputsHex(); +self.exportOutputs = async function(walletId, all) { + return self.WORKER_OBJECTS[walletId].exportOutputs(all); } -self.importOutputsHex = async function(walletId, outputsHex) { - return self.WORKER_OBJECTS[walletId].importOutputsHex(outputsHex); +self.importOutputs = async function(walletId, outputsHex) { + return self.WORKER_OBJECTS[walletId].importOutputs(outputsHex); } -self.getKeyImages = async function(walletId) { +self.getKeyImages = async function(walletId, all) { let keyImagesJson = []; - for (let keyImage of await self.WORKER_OBJECTS[walletId].getKeyImages()) keyImagesJson.push(keyImage.toJson()); + for (let keyImage of await self.WORKER_OBJECTS[walletId].exportKeyImages(all)) keyImagesJson.push(keyImage.toJson()); return keyImagesJson; } @@ -721,6 +791,22 @@ self.importKeyImages = async function(walletId, keyImagesJson) { // throw new MoneroError("Not implemented"); //} +self.freezeOutput = async function(walletId, keyImage) { + return self.WORKER_OBJECTS[walletId].freezeOutput(keyImage); +} + +self.thawOutput = async function(walletId, keyImage) { + return self.WORKER_OBJECTS[walletId].thawOutput(keyImage); +} + +self.isOutputFrozen = async function(walletId, keyImage) { + return self.WORKER_OBJECTS[walletId].isOutputFrozen(keyImage); +} + +self.getDefaultFeePriority = async function(walletId) { + return self.WORKER_OBJECTS[walletId].getDefaultFeePriority(); +} + self.createTxs = async function(walletId, config) { if (typeof config === "object") config = new MoneroTxConfig(config); let txs = await self.WORKER_OBJECTS[walletId].createTxs(config); @@ -745,15 +831,15 @@ self.sweepUnlocked = async function(walletId, config) { self.sweepDust = async function(walletId, relay) { let txs = await self.WORKER_OBJECTS[walletId].sweepDust(relay); - return txs[0].getTxSet().toJson(); + return txs.length === 0 ? {} : txs[0].getTxSet().toJson(); } self.relayTxs = async function(walletId, txMetadatas) { return self.WORKER_OBJECTS[walletId].relayTxs(txMetadatas); } -self.parseTxSet = async function(walletId, txSetJson) { - return (await self.WORKER_OBJECTS[walletId].parseTxSet(new MoneroTxSet(txSetJson))).toJson(); +self.describeTxSet = async function(walletId, txSetJson) { + return (await self.WORKER_OBJECTS[walletId].describeTxSet(new MoneroTxSet(txSetJson))).toJson(); } self.signTxs = async function(walletId, unsignedTxHex) { @@ -764,12 +850,12 @@ self.submitTxs = async function(walletId, signedTxHex) { return self.WORKER_OBJECTS[walletId].submitTxs(signedTxHex); } -self.signMessage = async function(walletId, message) { - return self.WORKER_OBJECTS[walletId].signMessage(message); +self.signMessage = async function(walletId, message, signatureType, accountIdx, subaddressIdx) { + return self.WORKER_OBJECTS[walletId].signMessage(message, signatureType, accountIdx, subaddressIdx); } self.verifyMessage = async function(walletId, message, address, signature) { - return self.WORKER_OBJECTS[walletId].verifyMessage(message, address, signature); + return (await self.WORKER_OBJECTS[walletId].verifyMessage(message, address, signature)).toJson(); } self.getTxKey = async function(walletId, txHash) { @@ -785,7 +871,7 @@ self.getTxProof = async function(walletId, txHash, address, message) { } self.checkTxProof = async function(walletId, txHash, address, message, signature) { - return (self.WORKER_OBJECTS[walletId].checkTxProof(txHash, address, message, signature)).toJson(); + return (await self.WORKER_OBJECTS[walletId].checkTxProof(txHash, address, message, signature)).toJson(); } self.getSpendProof = async function(walletId, txHash, message) { @@ -800,8 +886,8 @@ self.getReserveProofWallet = async function(walletId, message) { return self.WORKER_OBJECTS[walletId].getReserveProofWallet(message); } -self.getReserveProofAccount = async function(walletId, accountIdx, amount, message) { - return self.WORKER_OBJECTS[walletId].getReserveProofAccount(accountIdx, amount, message); +self.getReserveProofAccount = async function(walletId, accountIdx, amountStr, message) { + return self.WORKER_OBJECTS[walletId].getReserveProofAccount(accountIdx, amountStr, message); } self.checkReserveProof = async function(walletId, address, message, signature) { @@ -850,8 +936,8 @@ self.setAccountTagLabel = async function(walletId, tag, label) { throw new Error("Not implemented"); } -self.createPaymentUri = async function(walletId, configJson) { - return self.WORKER_OBJECTS[walletId].createPaymentUri(new MoneroTxConfig(configJson)); +self.getPaymentUri = async function(walletId, configJson) { + return self.WORKER_OBJECTS[walletId].getPaymentUri(new MoneroTxConfig(configJson)); } self.parsePaymentUri = async function(walletId, uri) { @@ -891,15 +977,15 @@ self.prepareMultisig = async function(walletId) { } self.makeMultisig = async function(walletId, multisigHexes, threshold, password) { - return (await self.WORKER_OBJECTS[walletId].makeMultisig(multisigHexes, threshold, password)).toJson(); + return await self.WORKER_OBJECTS[walletId].makeMultisig(multisigHexes, threshold, password); } self.exchangeMultisigKeys = async function(walletId, multisigHexes, password) { return (await self.WORKER_OBJECTS[walletId].exchangeMultisigKeys(multisigHexes, password)).toJson(); } -self.getMultisigHex = async function(walletId) { - return self.WORKER_OBJECTS[walletId].getMultisigHex(); +self.exportMultisigHex = async function(walletId) { + return self.WORKER_OBJECTS[walletId].exportMultisigHex(); } self.importMultisigHex = async function(walletId, multisigHexes) { @@ -918,10 +1004,15 @@ self.getData = async function(walletId) { return self.WORKER_OBJECTS[walletId].getData(); } +self.changePassword = async function(walletId, oldPassword, newPassword) { + return self.WORKER_OBJECTS[walletId].changePassword(oldPassword, newPassword); +} + self.isClosed = async function(walletId) { - return self.WORKER_OBJECTS[walletId].isClosed(); + return !self.WORKER_OBJECTS[walletId] || self.WORKER_OBJECTS[walletId].isClosed(); } self.close = async function(walletId, save) { - return self.WORKER_OBJECTS[walletId].close(save); // TODO: remove listeners and delete wallet from WORKER_OBJECTS + return self.WORKER_OBJECTS[walletId].close(save); + delete self.WORKER_OBJECTS[walletId]; } \ No newline at end of file diff --git a/src/main/ts/common/SslOptions.ts b/src/main/ts/common/SslOptions.ts new file mode 100644 index 000000000..cb2b2e4bc --- /dev/null +++ b/src/main/ts/common/SslOptions.ts @@ -0,0 +1,60 @@ +/** + * SSL options for remote endpoints. + */ +export default class SslOptions { + + privateKeyPath: string; + certificatePath: string; + certificateAuthorityFile: string; + allowedFingerprints: string[]; + allowAnyCert: boolean; + + constructor(options?: Partial) { + Object.assign(this, options); + } + + getPrivateKeyPath() { + return this.privateKeyPath; + } + + setPrivateKeyPath(privateKeyPath) { + this.privateKeyPath = privateKeyPath; + return this; + } + + getCertificatePath() { + return this.certificatePath; + } + + setCertificatePath(certificatePath) { + this.certificatePath = certificatePath; + return this; + } + + getCertificateAuthorityFile() { + return this.certificateAuthorityFile; + } + + setCertificateAuthorityFile(certificateAuthorityFile) { + this.certificateAuthorityFile = certificateAuthorityFile; + return this; + } + + getAllowedFingerprints() { + return this.allowedFingerprints; + } + + setAllowedFingerprints(allowedFingerprints) { + this.allowedFingerprints = allowedFingerprints; + return this; + } + + getAllowAnyCert() { + return this.allowAnyCert; + } + + setAllowAnyCert(allowAnyCert) { + this.allowAnyCert = allowAnyCert; + return this; + } +} diff --git a/src/main/ts/common/TaskLooper.ts b/src/main/ts/common/TaskLooper.ts new file mode 100644 index 000000000..64e00d304 --- /dev/null +++ b/src/main/ts/common/TaskLooper.ts @@ -0,0 +1,85 @@ +/** + * Run a task in a fixed period loop. + */ +export default class TaskLooper { + + _fn: () => Promise; + _isStarted: boolean; + _isLooping: boolean; + _periodInMs: number; + _timeout: NodeJS.Timeout | undefined; + + /** + * Build the looper with a function to invoke on a fixed period loop. + * + * @param {function} fn - the async function to invoke + */ + constructor(fn: () => Promise) { + this._fn = fn; + this._isStarted = false; + this._isLooping = false; + } + + /** + * Get the task function to invoke on a fixed period loop. + * + * @return {function} the task function + */ + getTask() { + return this._fn; + } + + /** + * Start the task loop. + * + * @param {number} periodInMs the loop period in milliseconds + * @param {boolean} targetFixedPeriod specifies if the task should target a fixed period by accounting for run time (default false) + * @return {TaskLooper} this instance for chaining + */ + start(periodInMs: number, targetFixedPeriod?: boolean) { + if (periodInMs <= 0) throw new Error("Looper period must be greater than 0 ms"); + this.setPeriodInMs(periodInMs); + if (this._isStarted) return; + this._isStarted = true; + this._runLoop(targetFixedPeriod); + } + + /** + * Indicates if looping. + * + * @return {boolean} true if looping, false otherwise + */ + isStarted() { + return this._isStarted; + } + + /** + * Stop the task loop. + */ + stop() { + this._isStarted = false; + clearTimeout(this._timeout!); + this._timeout = undefined; + } + + /** + * Set the loop period in milliseconds. + * + * @param {number} periodInMs the loop period in milliseconds + */ + setPeriodInMs(periodInMs) { + if (periodInMs <= 0) throw new Error("Looper period must be greater than 0 ms"); + this._periodInMs = periodInMs; + } + + async _runLoop(targetFixedPeriod: boolean) { + this._isLooping = true; + while (this._isStarted) { + const startTime = Date.now(); + await this._fn(); + let that = this; + if (this._isStarted) await new Promise((resolve) => { this._timeout = setTimeout(resolve, that._periodInMs - (targetFixedPeriod ? (Date.now() - startTime) : 0)); }); + } + this._isLooping = false; + } +} diff --git a/src/main/ts/common/ThreadPool.ts b/src/main/ts/common/ThreadPool.ts new file mode 100644 index 000000000..5ddaa81f1 --- /dev/null +++ b/src/main/ts/common/ThreadPool.ts @@ -0,0 +1,65 @@ +import GenUtils from "./GenUtils"; +import async from "async"; + +/** + * Simple thread pool using the async library. + */ +export default class ThreadPool { + + protected taskQueue: any; + protected drainListeners: any; + + /** + * Construct the thread pool. + * + * @param {number} [maxConcurrency] - maximum number of threads in the pool (default 1) + */ + constructor(maxConcurrency) { + if (maxConcurrency === undefined) maxConcurrency = 1; + if (maxConcurrency < 1) throw new Error("Max concurrency must be greater than or equal to 1"); + + // manager concurrency with async queue + //import async from "async"; + this.taskQueue = async.queue((asyncFn, callback) => { + if (asyncFn.then) asyncFn.then(resp => { callback(resp); }).catch(err => { callback(undefined, err); }); + else asyncFn().then(resp => { callback(resp); }).catch(err => { callback(undefined, err); }); + }, maxConcurrency); + + // use drain listeners to support await all + this.drainListeners = []; + this.taskQueue.drain = () => { + for (let listener of this.drainListeners) listener(); + } + } + + /** + * Submit an asynchronous function to run using the thread pool. + * + * @param {function} asyncFn - asynchronous function to run with the thread pool + * @return {Promise} resolves when the function completes execution + */ + async submit(asyncFn): Promise { + return new Promise((resolve, reject) => { + this.taskQueue.push(asyncFn, (resp, err) => { + if (err !== undefined) reject(err); + else resolve(resp); + }); + }); + } + + /** + * Await all functions to complete. + * + * @return {Promise} resolves when all functions complete + */ + async awaitAll(): Promise { + if (this.taskQueue.length === 0) return; + return new Promise((resolve) => { + this.drainListeners.push(() => { + GenUtils.remove(this.drainListeners, this); + resolve(); + }) + }); + } +} + diff --git a/src/main/ts/daemon/MoneroDaemon.ts b/src/main/ts/daemon/MoneroDaemon.ts new file mode 100644 index 000000000..15c8b4b20 --- /dev/null +++ b/src/main/ts/daemon/MoneroDaemon.ts @@ -0,0 +1,732 @@ +import assert from "assert"; +import MoneroAltChain from "./model/MoneroAltChain"; +import MoneroBan from "./model/MoneroBan"; +import MoneroBlock from "./model/MoneroBlock"; +import MoneroBlockHeader from "./model/MoneroBlockHeader"; +import MoneroBlockTemplate from "./model/MoneroBlockTemplate"; +import MoneroDaemonInfo from "./model/MoneroDaemonInfo"; +import MoneroDaemonListener from "./model/MoneroDaemonListener"; +import MoneroDaemonSyncInfo from "./model/MoneroDaemonSyncInfo"; +import MoneroDaemonUpdateCheckResult from "./model/MoneroDaemonUpdateCheckResult"; +import MoneroDaemonUpdateDownloadResult from "./model/MoneroDaemonUpdateDownloadResult"; +import MoneroError from "../common/MoneroError"; +import MoneroFeeEstimate from "./model/MoneroFeeEstimate"; +import MoneroHardForkInfo from "./model/MoneroHardForkInfo"; +import MoneroKeyImageSpentStatus from "./model/MoneroKeyImageSpentStatus"; +import MoneroMinerTxSum from "./model/MoneroMinerTxSum"; +import MoneroMiningStatus from "./model/MoneroMiningStatus"; +import MoneroOutput from "./model/MoneroOutput"; +//import MoneroOutputDistributionEntry from "./model/MoneroOutputDistributionEntry"; +import MoneroOutputHistogramEntry from "./model/MoneroOutputHistogramEntry"; +import MoneroNetworkType from "./model/MoneroNetworkType"; +import MoneroPeer from "./model/MoneroPeer"; +import MoneroPruneResult from "./model/MoneroPruneResult"; +import MoneroSubmitTxResult from "./model/MoneroSubmitTxResult"; +import MoneroTx from "./model/MoneroTx"; +import MoneroTxPoolStats from "./model/MoneroTxPoolStats"; +import MoneroVersion from "./model/MoneroVersion"; + +/** + * Copyright (c) woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Monero daemon interface and default implementations. + */ +export default class MoneroDaemon { + + /** + * Register a listener to receive daemon notifications. + * + * @param {MoneroDaemonListener} listener - listener to receive daemon notifications + * @return {Promise} + */ + async addListener(listener: MoneroDaemonListener): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Unregister a listener to receive daemon notifications. + * + * @param {MoneroDaemonListener} listener - listener to unregister + * @return {Promise} + */ + async removeListener(listener: MoneroDaemonListener): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get the listeners registered with the daemon. + * + * @return {MoneroDaemonListener[]} the registered listeners + */ + getListeners(): MoneroDaemonListener[] { + throw new MoneroError("Subclass must implement"); + } + + /** + * Indicates if the client is connected to the daemon via RPC. + * + * @return {Promise} true if the client is connected to the daemon, false otherwise + */ + async isConnected(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Gets the version of the daemon. + * + * @return {Promise} the version of the daemon + */ + async getVersion(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Indicates if the daemon is trusted xor untrusted. + * + * @return {Promise} true if the daemon is trusted, false otherwise + */ + async isTrusted(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get the number of blocks in the longest chain known to the node. + * + * @return {Promise} the number of blocks! + */ + async getHeight(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get a block's hash by its height. + * + * @param {number} height - height of the block hash to get + * @return {Promise} the block's hash at the given height + */ + async getBlockHash(height: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get a block template for mining a new block. + * + * @param {string} walletAddress - address of the wallet to receive miner transactions if block is successfully mined + * @param {number} [reserveSize] - reserve size (optional) + * @return {Promise} is a block template for mining a new block + */ + async getBlockTemplate(walletAddress: string, reserveSize?: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get the last block's header. + * + * @return {Promise} last block's header + */ + async getLastBlockHeader(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get a block header by its hash. + * + * @param {string} blockHash - hash of the block to get the header of + * @return {Promise} block's header + */ + async getBlockHeaderByHash(blockHash: string): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get a block header by its height. + * + * @param {number} height - height of the block to get the header of + * @return {Promise} block's header + */ + async getBlockHeaderByHeight(height: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get block headers for the given range. + * + * @param {number} [startHeight] - start height lower bound inclusive (optional) + * @param {number} [endHeight] - end height upper bound inclusive (optional) + * @return {Promise} for the given range + */ + async getBlockHeadersByRange(startHeight?: number, endHeight?: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get a block by hash. + * + * @param {string} blockHash - hash of the block to get + * @return {Promise} with the given hash + */ + async getBlockByHash(blockHash: string): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get blocks by hash. + * + * @param {string[]} blockHashes - array of hashes; first 10 blocks hashes goes sequential, + * next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, + * and the last one is always genesis block + * @param {number} startHeight - start height to get blocks by hash + * @param {boolean} [prune] - specifies if returned blocks should be pruned (defaults to false) // TODO: test default + * @return {Promise} retrieved blocks + */ + async getBlocksByHash(blockHashes: string[], startHeight: number, prune = false): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get a block by height. + * + * @param {number} height - height of the block to get + * @return {Promise} with the given height + */ + async getBlockByHeight(height: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get blocks at the given heights. + * + * @param {number[]} heights - heights of the blocks to get + * @return {Promise} are blocks at the given heights + */ + async getBlocksByHeight(heights: number[]): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get blocks in the given height range. + * + * @param {number} [startHeight] - start height lower bound inclusive (optional) + * @param {number} [endHeight] - end height upper bound inclusive (optional) + * @return {Promise} are blocks in the given height range + */ + async getBlocksByRange(startHeight?: number, endHeight?: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get blocks in the given height range as chunked requests so that each request is + * not too big. + * + * @param {number} [startHeight] - start height lower bound inclusive (optional) + * @param {number} [endHeight] - end height upper bound inclusive (optional) + * @param {number} [maxChunkSize] - maximum chunk size in any one request (default 3,000,000 bytes) + * @return {Promise} blocks in the given height range + */ + async getBlocksByRangeChunked(startHeight?: number, endHeight?: number, maxChunkSize?: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get block hashes as a binary request to the daemon. + * + * @param {string[]} blockHashes - specify block hashes to fetch; first 10 blocks hash goes + * sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 + * and so on, and the last one is always genesis block + * @param {number} startHeight - starting height of block hashes to return + * @return {Promise} requested block hashes + */ + async getBlockHashes(blockHashes: string[], startHeight: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get a transaction by hash. + * + * @param {string} txHash - hash of the transaction to get + * @param {boolean} [prune] - specifies if the returned tx should be pruned (defaults to false) + * @return {Promise} transaction with the given hash or undefined if not found + */ + async getTx(txHash?: string, prune = false): Promise { + return (await this.getTxs([txHash], prune))[0]; + } + + /** + * Get transactions by hashes. + * + * @param {string[]} txHashes - hashes of transactions to get + * @param {boolean} [prune] - specifies if the returned txs should be pruned (defaults to false) + * @return {Promise} found transactions with the given hashes + */ + async getTxs(txHashes: string[], prune = false): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get a transaction hex by hash. + * + * @param {string} txHash - hash of the transaction to get hex from + * @param {boolean} [prune] - specifies if the returned tx hex should be pruned (defaults to false) + * @return {Promise} tx hex with the given hash + */ + async getTxHex(txHash: string, prune = false): Promise { + return (await this.getTxHexes([txHash], prune))[0]; + } + + /** + * Get transaction hexes by hashes. + * + * @param {string[]} txHashes - hashes of transactions to get hexes from + * @param {boolean} [prune] - specifies if the returned tx hexes should be pruned (defaults to false) + * @return {Promise} tx hexes + */ + async getTxHexes(txHashes: string[], prune = false): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Gets the total emissions and fees from the genesis block to the current height. + * + * @param {number} height - height to start computing the miner sum + * @param {number} numBlocks - number of blocks to include in the sum + * @return {Promise} encapsulates the total emissions and fees since the genesis block + */ + async getMinerTxSum(height: number, numBlocks: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get mining fee estimates per kB. + * + * @param {number} graceBlocks TODO + * @return {Promise} mining fee estimates per kB + */ + async getFeeEstimate(graceBlocks?: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Submits a transaction to the daemon's pool. + * + * @param {string} txHex - raw transaction hex to submit + * @param {boolean} doNotRelay specifies if the tx should be relayed (default false, i.e. relay) + * @return {Promise} contains submission results + */ + async submitTxHex(txHex: string, doNotRelay = false): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Relays a transaction by hash. + * + * @param {string} txHash - hash of the transaction to relay + * @return {Promise} + */ + async relayTxByHash(txHash: string): Promise { + assert.equal(typeof txHash, "string", "Must provide a transaction hash"); + await this.relayTxsByHash([txHash]); + } + + /** + * Relays transactions by hash. + * + * @param {string[]} txHashes - hashes of the transactinos to relay + * @return {Promise} + */ + async relayTxsByHash(txHashes: string[]): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get valid transactions seen by the node but not yet mined into a block, as well + * as spent key image information for the tx pool. + * + * @return {Promise} are transactions in the transaction pool! + */ + async getTxPool(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get hashes of transactions in the transaction pool. + * + * @return {string[]} are hashes of transactions in the transaction pool + */ + async getTxPoolHashes(): Promise { + throw new MoneroError("Subclass must implement"); + } + + // /** + // * Get all transaction pool backlog. + // * + // * @return {Promise} backlog entries + // */ + // async getTxPoolBacklog(): Promise { + // throw new MoneroError("Subclass must implement"); + // } + + /** + * Get transaction pool statistics. + * + * @return {Promise} contains statistics about the transaction pool + */ + async getTxPoolStats(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Flush transactions from the tx pool. + * + * @param {(string | string[])} [hashes] - specific transactions to flush (defaults to all) + * @return {Promise} + */ + async flushTxPool(hashes?: string | string[]): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get the spent status of the given key image. + * + * @param {string} keyImage - key image hex to get the status of + * @return {Promise} status of the key image + */ + async getKeyImageSpentStatus(keyImage: string): Promise { + return (await this.getKeyImageSpentStatuses([keyImage]))[0]; + } + + /** + * Get the spent status of each given key image. + * + * @param {string[]} keyImages are hex key images to get the statuses of + * @return {Promise} status for each key image + */ + async getKeyImageSpentStatuses(keyImages: string[]): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get outputs identified by a list of output amounts and indices as a binary + * request. + * + * @param {MoneroOutput[]} outputs - identify each output by amount and index + * @return {Promise} identified outputs + */ + async getOutputs(outputs: MoneroOutput[]): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get a histogram of output amounts. For all amounts (possibly filtered by + * parameters), gives the number of outputs on the chain for that amount. + * RingCT outputs counts as 0 amount. + * + * @param {bigint[]} [amounts] - amounts of outputs to make the histogram with + * @param {number} [minCount] - TODO + * @param {number} [maxCount] - TODO + * @param {boolean} [isUnlocked] - makes a histogram with outputs with the specified lock state + * @param {number} [recentCutoff] - TODO + * @return {Promise} are entries meeting the parameters + */ + async getOutputHistogram(amounts?: bigint[], minCount?: number, maxCount?: number, isUnlocked?: boolean, recentCutoff?: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + // /** + // * Creates an output distribution. + // * + // * @param {bigint[]} amounts - amounts of outputs to make the distribution with + // * @param {boolean} [cumulative] - specifies if the results should be cumulative (defaults to TODO) + // * @param {number} [startHeight] - start height lower bound inclusive (optional) + // * @param {number} [endHeight] - end height upper bound inclusive (optional) + // * @return {Promise} are entries meeting the parameters + // */ + // async getOutputDistribution(amounts: bigint[], cumulative?: boolean, startHeight?: number, endHeight?: number): Promise { + // throw new MoneroError("Subclass must implement"); + // } + + /** + * Get general information about the state of the node and the network. + * + * @return {Promise} is general information about the node and network + */ + async getInfo(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get synchronization information. + * + * @return {Promise} contains sync information + */ + async getSyncInfo(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Look up information regarding hard fork voting and readiness. + * + * @return {Promise } contains hard fork information + */ + async getHardForkInfo(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get alternative chains seen by the node. + * + * @return {Promise} alternative chains + */ + async getAltChains(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get known block hashes which are not on the main chain. + * + * @return {Promise} known block hashes which are not on the main chain + */ + async getAltBlockHashes(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get the download bandwidth limit. + * + * @return {Promise} download bandwidth limit + */ + async getDownloadLimit(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Set the download bandwidth limit. + * + * @param {number} limit - download limit to set (-1 to reset to default) + * @return {number} new download limit after setting + */ + async setDownloadLimit(limit: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Reset the download bandwidth limit. + * + * @return {Promise} download bandwidth limit after resetting + */ + async resetDownloadLimit(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get the upload bandwidth limit. + * + * @return {Promise} upload bandwidth limit + */ + async getUploadLimit(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Set the upload bandwidth limit. + * + * @param limit - upload limit to set (-1 to reset to default) + * @return {Promise} new upload limit after setting + */ + async setUploadLimit(limit: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Reset the upload bandwidth limit. + * + * @return {Promise} upload bandwidth limit after resetting + */ + async resetUploadLimit(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get peers with active incoming or outgoing connections to the node. + * + * @return {Promise} the daemon's peers + */ + async getPeers(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get known peers including their last known online status. + * + * @return {MoneroPeer[]} the daemon's known peers + */ + async getKnownPeers(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Limit number of outgoing peers. + * + * @param {number} limit - maximum number of outgoing peers + * @return {Promise} + */ + async setOutgoingPeerLimit(limit: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Limit number of incoming peers. + * + * @param {number} limit - maximum number of incoming peers + * @return {Promise} + */ + async setIncomingPeerLimit(limit: number): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get peer bans. + * + * @return {Promise} entries about banned peers + */ + async getPeerBans(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Ban a peer node. + * + * @param {MoneroBan} ban - contains information about a node to ban + * @return {Promise} + */ + async setPeerBan(ban: MoneroBan): Promise { + return await this.setPeerBans([ban]); + } + + /** + * Ban peers nodes. + * + * @param {MoneroBan[]} bans - specify which peers to ban + * @return {Promise} + */ + async setPeerBans(bans: MoneroBan[]): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Start mining. + * + * @param {string} address - address given miner rewards if the daemon mines a block + * @param {integer} [numThreads] - number of mining threads to run (default 1) + * @param {boolean} [isBackground] - specifies if the miner should run in the background or not (default false) + * @param {boolean} [ignoreBattery] - specifies if the battery state (e.g. on laptop) should be ignored or not (default false) + * @return {Promise} + */ + async startMining(address: string, numThreads?: number, isBackground?: boolean, ignoreBattery?: boolean): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Stop mining. + * + * @return {Promise} + */ + async stopMining(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get the daemon's mining status. + * + * @return {Promise} daemon's mining status + */ + async getMiningStatus(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Submit a mined block to the network. + * + * @param {string} blockBlob - mined block to submit + * @return {Promise} + */ + async submitBlock(blockBlob: string): Promise { + await this.submitBlocks([blockBlob]); + } + + /** + * Prune the blockchain. + * + * @param {boolean} check specifies to check the pruning (default false) + * @return {Promise} the prune result + */ + async pruneBlockchain(check: boolean): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Submit mined blocks to the network. + * + * @param {string[]} blockBlobs - mined blocks to submit + * @return {Promise} + */ + async submitBlocks(blockBlobs: string[]): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Check for update. + * + * @return {Promise} the result + */ + async checkForUpdate(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Download an update. + * + * @param {string} [path] - path to download the update (optional) + * @return {Promise} the result + */ + async downloadUpdate(path?: string): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Safely disconnect and shut down the daemon. + * + * @return {Promise} + */ + async stop(): Promise { + throw new MoneroError("Subclass must implement"); + } + + /** + * Get the header of the next block added to the chain. + * + * @return {Promise} header of the next block added to the chain + */ + async waitForNextBlockHeader(): Promise { + throw new MoneroError("Subclass must implement"); + } +} \ No newline at end of file diff --git a/src/main/ts/daemon/MoneroDaemonRpc.ts b/src/main/ts/daemon/MoneroDaemonRpc.ts new file mode 100644 index 000000000..5b309c24c --- /dev/null +++ b/src/main/ts/daemon/MoneroDaemonRpc.ts @@ -0,0 +1,1958 @@ +import assert from "assert"; +import GenUtils from "../common/GenUtils"; +import LibraryUtils from "../common/LibraryUtils"; +import TaskLooper from "../common/TaskLooper"; +import MoneroAltChain from "./model/MoneroAltChain"; +import MoneroBan from "./model/MoneroBan"; +import MoneroBlock from "./model/MoneroBlock"; +import MoneroBlockHeader from "./model/MoneroBlockHeader"; +import MoneroBlockTemplate from "./model/MoneroBlockTemplate"; +import MoneroConnectionSpan from "./model/MoneroConnectionSpan"; +import MoneroDaemon from "./MoneroDaemon"; +import MoneroDaemonConfig from "./model/MoneroDaemonConfig"; +import MoneroDaemonInfo from "./model/MoneroDaemonInfo"; +import MoneroDaemonListener from "./model/MoneroDaemonListener"; +import MoneroDaemonSyncInfo from "./model/MoneroDaemonSyncInfo"; +import MoneroDaemonUpdateCheckResult from "./model/MoneroDaemonUpdateCheckResult"; +import MoneroDaemonUpdateDownloadResult from "./model/MoneroDaemonUpdateDownloadResult"; +import MoneroFeeEstimate from "./model/MoneroFeeEstimate"; +import MoneroError from "../common/MoneroError"; +import MoneroHardForkInfo from "./model/MoneroHardForkInfo"; +import MoneroKeyImage from "./model/MoneroKeyImage"; +import MoneroKeyImageSpentStatus from "./model/MoneroKeyImageSpentStatus"; +import MoneroMinerTxSum from "./model/MoneroMinerTxSum"; +import MoneroMiningStatus from "./model/MoneroMiningStatus"; +import MoneroNetworkType from "./model/MoneroNetworkType"; +import MoneroOutput from "./model/MoneroOutput"; +import MoneroOutputHistogramEntry from "./model/MoneroOutputHistogramEntry"; +import MoneroPeer from "./model/MoneroPeer"; +import MoneroPruneResult from "./model/MoneroPruneResult"; +import MoneroRpcConnection from "../common/MoneroRpcConnection"; +import MoneroSubmitTxResult from "./model/MoneroSubmitTxResult"; +import MoneroTx from "./model/MoneroTx"; +import MoneroTxPoolStats from "./model/MoneroTxPoolStats"; +import MoneroUtils from "../common/MoneroUtils"; +import MoneroVersion from "./model/MoneroVersion"; +import { ChildProcess } from "child_process"; + +/** + * Copyright (c) woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Implements a MoneroDaemon as a client of monerod. + */ +class MoneroDaemonRpc extends MoneroDaemon { + + // static variables + protected static readonly MAX_REQ_SIZE = "3000000"; + protected static readonly DEFAULT_ID = "0000000000000000000000000000000000000000000000000000000000000000"; // uninitialized tx or block hash from daemon rpc + protected static readonly NUM_HEADERS_PER_REQ = 750; // number of headers to fetch and cache per request + protected static readonly DEFAULT_POLL_PERIOD = 20000; // default interval between polling the daemon in ms + + // instance variables + protected config: Partial; + protected listeners: MoneroDaemonListener[]; + protected cachedHeaders: any; + protected process: any; + protected pollListener: any; + protected proxyDaemon: any; + + /** @private */ + constructor(config: MoneroDaemonConfig, proxyDaemon: MoneroDaemonRpcProxy) { + super(); + this.config = config; + this.proxyDaemon = proxyDaemon; + if (config.proxyToWorker) return; + this.listeners = []; // block listeners + this.cachedHeaders = {}; // cached headers for fetching blocks in bound chunks + } + + /** + * Get the internal process running monerod. + * + * @return {ChildProcess} the node process running monerod, undefined if not created from new process + */ + getProcess(): ChildProcess { + return this.process; + } + + /** + * Stop the internal process running monerod, if applicable. + * + * @param {boolean} [force] specifies if the process should be destroyed forcibly (default false) + * @return {Promise} the exit code from stopping the process + */ + async stopProcess(force = false): Promise { + if (this.process === undefined) throw new MoneroError("MoneroDaemonRpc instance not created from new process"); + let listenersCopy = GenUtils.copyArray(await this.getListeners()); + for (let listener of listenersCopy) await this.removeListener(listener); + return GenUtils.killProcess(this.process, force ? "SIGKILL" : undefined); + } + + async addListener(listener: MoneroDaemonListener): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.addListener(listener); + assert(listener instanceof MoneroDaemonListener, "Listener must be instance of MoneroDaemonListener"); + this.listeners.push(listener); + this.refreshListening(); + } + + async removeListener(listener: MoneroDaemonListener): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.removeListener(listener); + assert(listener instanceof MoneroDaemonListener, "Listener must be instance of MoneroDaemonListener"); + let idx = this.listeners.indexOf(listener); + if (idx > -1) this.listeners.splice(idx, 1); + else throw new MoneroError("Listener is not registered with daemon"); + this.refreshListening(); + } + + getListeners(): MoneroDaemonListener[] { + if (this.config.proxyToWorker) return this.proxyDaemon.getListeners(); + return this.listeners; + } + + /** + * Get the daemon's RPC connection. + * + * @return {MoneroRpcConnection} the daemon's rpc connection + */ + async getRpcConnection() { + if (this.config.proxyToWorker) return this.proxyDaemon.getRpcConnection(); + return this.config.getServer(); + } + + async isConnected(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.isConnected(); + try { + await this.getVersion(); + return true; + } catch (e: any) { + return false; + } + } + + async getVersion(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getVersion(); + let resp = await this.config.getServer().sendJsonRequest("get_version"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return new MoneroVersion(resp.result.version, resp.result.release); + } + + async isTrusted(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.isTrusted(); + let resp = await this.config.getServer().sendPathRequest("get_height"); + MoneroDaemonRpc.checkResponseStatus(resp); + return !resp.untrusted; + } + + async getHeight(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getHeight(); + let resp = await this.config.getServer().sendJsonRequest("get_block_count"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return resp.result.count; + } + + async getBlockHash(height: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockHash(height); + return (await this.config.getServer().sendJsonRequest("on_get_block_hash", [height])).result; // TODO monero-wallet-rpc: no status returned + } + + async getBlockTemplate(walletAddress: string, reserveSize?: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockTemplate(walletAddress, reserveSize); + assert(walletAddress && typeof walletAddress === "string", "Must specify wallet address to be mined to"); + let resp = await this.config.getServer().sendJsonRequest("get_block_template", {wallet_address: walletAddress, reserve_size: reserveSize}); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcBlockTemplate(resp.result); + } + + async getLastBlockHeader(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getLastBlockHeader(); + let resp = await this.config.getServer().sendJsonRequest("get_last_block_header"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcBlockHeader(resp.result.block_header); + } + + async getBlockHeaderByHash(blockHash: string): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockHeaderByHash(blockHash); + let resp = await this.config.getServer().sendJsonRequest("get_block_header_by_hash", {hash: blockHash}); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcBlockHeader(resp.result.block_header); + } + + async getBlockHeaderByHeight(height: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockHeaderByHeight(height); + let resp = await this.config.getServer().sendJsonRequest("get_block_header_by_height", {height: height}); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcBlockHeader(resp.result.block_header); + } + + async getBlockHeadersByRange(startHeight?: number, endHeight?: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockHeadersByRange(startHeight, endHeight); + + // fetch block headers + let resp = await this.config.getServer().sendJsonRequest("get_block_headers_range", { + start_height: startHeight, + end_height: endHeight + }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + + // build headers + let headers = []; + for (let rpcHeader of resp.result.headers) { + headers.push(MoneroDaemonRpc.convertRpcBlockHeader(rpcHeader)); + } + return headers; + } + + async getBlockByHash(blockHash: string): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockByHash(blockHash); + let resp = await this.config.getServer().sendJsonRequest("get_block", {hash: blockHash}); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcBlock(resp.result); + } + + async getBlockByHeight(height: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlockByHeight(height); + let resp = await this.config.getServer().sendJsonRequest("get_block", {height: height}); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcBlock(resp.result); + } + + async getBlocksByHeight(heights: number[]): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlocksByHeight(heights); + + // fetch blocks in binary + let respBin = await this.config.getServer().sendBinaryRequest("get_blocks_by_height.bin", {heights: heights}); + + // convert binary blocks to json + let rpcBlocks = await MoneroUtils.binaryBlocksToJson(respBin); + MoneroDaemonRpc.checkResponseStatus(rpcBlocks); + + // build blocks with transactions + assert.equal(rpcBlocks.txs.length, rpcBlocks.blocks.length); + let blocks = []; + for (let blockIdx = 0; blockIdx < rpcBlocks.blocks.length; blockIdx++) { + + // build block + let block = MoneroDaemonRpc.convertRpcBlock(rpcBlocks.blocks[blockIdx]); + block.setHeight(heights[blockIdx]); + blocks.push(block); + + // build transactions + let txs = []; + for (let txIdx = 0; txIdx < rpcBlocks.txs[blockIdx].length; txIdx++) { + let tx = new MoneroTx(); + txs.push(tx); + tx.setHash(rpcBlocks.blocks[blockIdx].tx_hashes[txIdx]); + tx.setIsConfirmed(true); + tx.setInTxPool(false); + tx.setIsMinerTx(false); + tx.setRelay(true); + tx.setIsRelayed(true); + tx.setIsFailed(false); + tx.setIsDoubleSpendSeen(false); + MoneroDaemonRpc.convertRpcTx(rpcBlocks.txs[blockIdx][txIdx], tx); + } + + // merge into one block + block.setTxs([]); + for (let tx of txs) { + if (tx.getBlock()) block.merge(tx.getBlock()); + else block.getTxs().push(tx.setBlock(block)); + } + } + + return blocks; + } + + async getBlocksByRange(startHeight?: number, endHeight?: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlocksByRange(startHeight, endHeight); + if (startHeight === undefined) startHeight = 0; + if (endHeight === undefined) endHeight = await this.getHeight() - 1; + let heights = []; + for (let height = startHeight; height <= endHeight; height++) heights.push(height); + return await this.getBlocksByHeight(heights); + } + + async getBlocksByRangeChunked(startHeight?: number, endHeight?: number, maxChunkSize?: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize); + if (startHeight === undefined) startHeight = 0; + if (endHeight === undefined) endHeight = await this.getHeight() - 1; + let lastHeight = startHeight - 1; + let blocks = []; + while (lastHeight < endHeight) { + for (let block of await this.getMaxBlocks(lastHeight + 1, endHeight, maxChunkSize)) { + blocks.push(block); + } + lastHeight = blocks[blocks.length - 1].getHeight(); + } + return blocks; + } + + async getTxs(txHashes: string[], prune = false): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getTxs(txHashes, prune); + + // validate input + assert(Array.isArray(txHashes) && txHashes.length > 0, "Must provide an array of transaction hashes"); + assert(prune === undefined || typeof prune === "boolean", "Prune must be a boolean or undefined"); + + // fetch transactions + let resp = await this.config.getServer().sendPathRequest("get_transactions", { + txs_hashes: txHashes, + decode_as_json: true, + prune: prune + }); + try { + MoneroDaemonRpc.checkResponseStatus(resp); + } catch (e: any) { + if (e.message.indexOf("Failed to parse hex representation of transaction hash") >= 0) throw new MoneroError("Invalid transaction hash"); + throw e; + } + + // build transaction models + let txs = []; + if (resp.txs) { + for (let txIdx = 0; txIdx < resp.txs.length; txIdx++) { + let tx = new MoneroTx(); + tx.setIsMinerTx(false); + txs.push(MoneroDaemonRpc.convertRpcTx(resp.txs[txIdx], tx)); + } + } + + return txs; + } + + async getTxHexes(txHashes: string[], prune = false): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getTxHexes(txHashes, prune); + let hexes = []; + for (let tx of await this.getTxs(txHashes, prune)) hexes.push(prune ? tx.getPrunedHex() : tx.getFullHex()); + return hexes; + } + + async getMinerTxSum(height: number, numBlocks: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getMinerTxSum(height, numBlocks); + if (height === undefined) height = 0; + else assert(height >= 0, "Height must be an integer >= 0"); + if (numBlocks === undefined) numBlocks = await this.getHeight(); + else assert(numBlocks >= 0, "Count must be an integer >= 0"); + let resp = await this.config.getServer().sendJsonRequest("get_coinbase_tx_sum", {height: height, count: numBlocks}); + MoneroDaemonRpc.checkResponseStatus(resp.result); + let txSum = new MoneroMinerTxSum(); + txSum.setEmissionSum(BigInt(resp.result.emission_amount)); + txSum.setFeeSum(BigInt(resp.result.fee_amount)); + return txSum; + } + + async getFeeEstimate(graceBlocks?: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getFeeEstimate(graceBlocks); + let resp = await this.config.getServer().sendJsonRequest("get_fee_estimate", {grace_blocks: graceBlocks}); + MoneroDaemonRpc.checkResponseStatus(resp.result); + let feeEstimate = new MoneroFeeEstimate(); + feeEstimate.setFee(BigInt(resp.result.fee)); + feeEstimate.setQuantizationMask(BigInt(resp.result.quantization_mask)); + if (resp.result.fees !== undefined) { + let fees = []; + for (let i = 0; i < resp.result.fees.length; i++) fees.push(BigInt(resp.result.fees[i])); + feeEstimate.setFees(fees); + } + return feeEstimate; + } + + async submitTxHex(txHex: string, doNotRelay: boolean): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.submitTxHex(txHex, doNotRelay); + let resp = await this.config.getServer().sendPathRequest("send_raw_transaction", {tx_as_hex: txHex, do_not_relay: doNotRelay}); + let result = MoneroDaemonRpc.convertRpcSubmitTxResult(resp); + + // set isGood based on status + try { + MoneroDaemonRpc.checkResponseStatus(resp); + result.setIsGood(true); + } catch (e: any) { + result.setIsGood(false); + } + return result; + } + + async relayTxsByHash(txHashes: string[]): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.relayTxsByHash(txHashes); + let resp = await this.config.getServer().sendJsonRequest("relay_tx", {txids: txHashes}); + MoneroDaemonRpc.checkResponseStatus(resp.result); + } + + async getTxPool(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getTxPool(); + + // send rpc request + let resp = await this.config.getServer().sendPathRequest("get_transaction_pool"); + MoneroDaemonRpc.checkResponseStatus(resp); + + // build txs + let txs = []; + if (resp.transactions) { + for (let rpcTx of resp.transactions) { + let tx = new MoneroTx(); + txs.push(tx); + tx.setIsConfirmed(false); + tx.setIsMinerTx(false); + tx.setInTxPool(true); + tx.setNumConfirmations(0); + MoneroDaemonRpc.convertRpcTx(rpcTx, tx); + } + } + + return txs; + } + + async getTxPoolHashes(): Promise { + throw new MoneroError("Not implemented"); + } + + // async getTxPoolBacklog(): Promise { + // throw new MoneroError("Not implemented"); + // } + + async getTxPoolStats(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getTxPoolStats(); + let resp = await this.config.getServer().sendPathRequest("get_transaction_pool_stats"); + MoneroDaemonRpc.checkResponseStatus(resp); + return MoneroDaemonRpc.convertRpcTxPoolStats(resp.pool_stats); + } + + async flushTxPool(hashes?: string | string[]): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.flushTxPool(hashes); + if (hashes) hashes = GenUtils.listify(hashes); + let resp = await this.config.getServer().sendJsonRequest("flush_txpool", {txids: hashes}); + MoneroDaemonRpc.checkResponseStatus(resp.result); + } + + async getKeyImageSpentStatuses(keyImages: string[]): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getKeyImageSpentStatuses(keyImages); + if (keyImages === undefined || keyImages.length === 0) throw new MoneroError("Must provide key images to check the status of"); + let resp = await this.config.getServer().sendPathRequest("is_key_image_spent", {key_images: keyImages}); + MoneroDaemonRpc.checkResponseStatus(resp); + return resp.spent_status; + } + + async getOutputHistogram(amounts?: bigint[], minCount?: number, maxCount?: number, isUnlocked?: boolean, recentCutoff?: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff); + + // send rpc request + let resp = await this.config.getServer().sendJsonRequest("get_output_histogram", { + amounts: amounts, + min_count: minCount, + max_count: maxCount, + unlocked: isUnlocked, + recent_cutoff: recentCutoff + }); + MoneroDaemonRpc.checkResponseStatus(resp.result); + + // build histogram entries from response + let entries = []; + if (!resp.result.histogram) return entries; + for (let rpcEntry of resp.result.histogram) { + entries.push(MoneroDaemonRpc.convertRpcOutputHistogramEntry(rpcEntry)); + } + return entries; + } + + async getOutputDistribution(amounts, cumulative, startHeight, endHeight) { + if (this.config.proxyToWorker) return this.proxyDaemon.getOutputDistribution(amounts, cumulative, startHeight, endHeight); + throw new MoneroError("Not implemented (response 'distribution' field is binary)"); + +// let amountStrs = []; +// for (let amount of amounts) amountStrs.push(amount.toJSValue()); +// console.log(amountStrs); +// console.log(cumulative); +// console.log(startHeight); +// console.log(endHeight); +// +// // send rpc request +// console.log("*********** SENDING REQUEST *************"); +// if (startHeight === undefined) startHeight = 0; +// let resp = await this.config.getServer().sendJsonRequest("get_output_distribution", { +// amounts: amountStrs, +// cumulative: cumulative, +// from_height: startHeight, +// to_height: endHeight +// }); +// +// console.log("RESPONSE"); +// console.log(resp); +// +// // build distribution entries from response +// let entries = []; +// if (!resp.result.distributions) return entries; +// for (let rpcEntry of resp.result.distributions) { +// let entry = MoneroDaemonRpc.convertRpcOutputDistributionEntry(rpcEntry); +// entries.push(entry); +// } +// return entries; + } + + async getInfo(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getInfo(); + let resp = await this.config.getServer().sendJsonRequest("get_info"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcInfo(resp.result); + } + + async getSyncInfo(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getSyncInfo(); + let resp = await this.config.getServer().sendJsonRequest("sync_info"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcSyncInfo(resp.result); + } + + async getHardForkInfo(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getHardForkInfo(); + let resp = await this.config.getServer().sendJsonRequest("hard_fork_info"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + return MoneroDaemonRpc.convertRpcHardForkInfo(resp.result); + } + + async getAltChains(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getAltChains(); + +// // mocked response for test +// let resp = { +// status: "OK", +// chains: [ +// { +// block_hash: "697cf03c89a9b118f7bdf11b1b3a6a028d7b3617d2d0ed91322c5709acf75625", +// difficulty: 14114729638300280, +// height: 1562062, +// length: 2 +// } +// ] +// } + + let resp = await this.config.getServer().sendJsonRequest("get_alternate_chains"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + let chains = []; + if (!resp.result.chains) return chains; + for (let rpcChain of resp.result.chains) chains.push(MoneroDaemonRpc.convertRpcAltChain(rpcChain)); + return chains; + } + + async getAltBlockHashes(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getAltBlockHashes(); + +// // mocked response for test +// let resp = { +// status: "OK", +// untrusted: false, +// blks_hashes: ["9c2277c5470234be8b32382cdf8094a103aba4fcd5e875a6fc159dc2ec00e011","637c0e0f0558e284493f38a5fcca3615db59458d90d3a5eff0a18ff59b83f46f","6f3adc174a2e8082819ebb965c96a095e3e8b63929ad9be2d705ad9c086a6b1c","697cf03c89a9b118f7bdf11b1b3a6a028d7b3617d2d0ed91322c5709acf75625"] +// } + + let resp = await this.config.getServer().sendPathRequest("get_alt_blocks_hashes"); + MoneroDaemonRpc.checkResponseStatus(resp); + if (!resp.blks_hashes) return []; + return resp.blks_hashes; + } + + async getDownloadLimit(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getDownloadLimit(); + return (await this.getBandwidthLimits())[0]; + } + + async setDownloadLimit(limit: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.setDownloadLimit(limit); + if (limit == -1) return await this.resetDownloadLimit(); + if (!(GenUtils.isInt(limit) && limit > 0)) throw new MoneroError("Download limit must be an integer greater than 0"); + return (await this.setBandwidthLimits(limit, 0))[0]; + } + + async resetDownloadLimit(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.resetDownloadLimit(); + return (await this.setBandwidthLimits(-1, 0))[0]; + } + + async getUploadLimit(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getUploadLimit(); + return (await this.getBandwidthLimits())[1]; + } + + async setUploadLimit(limit: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.setUploadLimit(limit); + if (limit == -1) return await this.resetUploadLimit(); + if (!(GenUtils.isInt(limit) && limit > 0)) throw new MoneroError("Upload limit must be an integer greater than 0"); + return (await this.setBandwidthLimits(0, limit))[1]; + } + + async resetUploadLimit(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.resetUploadLimit(); + return (await this.setBandwidthLimits(0, -1))[1]; + } + + async getPeers(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getPeers(); + let resp = await this.config.getServer().sendJsonRequest("get_connections"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + let peers = []; + if (!resp.result.connections) return peers; + for (let rpcConnection of resp.result.connections) { + peers.push(MoneroDaemonRpc.convertRpcConnection(rpcConnection)); + } + return peers; + } + + async getKnownPeers(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getKnownPeers(); + + // tx config + let resp = await this.config.getServer().sendPathRequest("get_peer_list"); + MoneroDaemonRpc.checkResponseStatus(resp); + + // build peers + let peers = []; + if (resp.gray_list) { + for (let rpcPeer of resp.gray_list) { + let peer = MoneroDaemonRpc.convertRpcPeer(rpcPeer); + peer.setIsOnline(false); // gray list means offline last checked + peers.push(peer); + } + } + if (resp.white_list) { + for (let rpcPeer of resp.white_list) { + let peer = MoneroDaemonRpc.convertRpcPeer(rpcPeer); + peer.setIsOnline(true); // white list means online last checked + peers.push(peer); + } + } + return peers; + } + + async setOutgoingPeerLimit(limit: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.setOutgoingPeerLimit(limit); + if (!(GenUtils.isInt(limit) && limit >= 0)) throw new MoneroError("Outgoing peer limit must be >= 0"); + let resp = await this.config.getServer().sendPathRequest("out_peers", {out_peers: limit}); + MoneroDaemonRpc.checkResponseStatus(resp); + } + + async setIncomingPeerLimit(limit: number): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.setIncomingPeerLimit(limit); + if (!(GenUtils.isInt(limit) && limit >= 0)) throw new MoneroError("Incoming peer limit must be >= 0"); + let resp = await this.config.getServer().sendPathRequest("in_peers", {in_peers: limit}); + MoneroDaemonRpc.checkResponseStatus(resp); + } + + async getPeerBans(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getPeerBans(); + let resp = await this.config.getServer().sendJsonRequest("get_bans"); + MoneroDaemonRpc.checkResponseStatus(resp.result); + let bans = []; + for (let rpcBan of resp.result.bans) { + let ban = new MoneroBan(); + ban.setHost(rpcBan.host); + ban.setIp(rpcBan.ip); + ban.setSeconds(rpcBan.seconds); + bans.push(ban); + } + return bans; + } + + async setPeerBans(bans: MoneroBan[]): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.setPeerBans(bans); + let rpcBans = []; + for (let ban of bans) rpcBans.push(MoneroDaemonRpc.convertToRpcBan(ban)); + let resp = await this.config.getServer().sendJsonRequest("set_bans", {bans: rpcBans}); + MoneroDaemonRpc.checkResponseStatus(resp.result); + } + + async startMining(address: string, numThreads?: number, isBackground?: boolean, ignoreBattery?: boolean): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.startMining(address, numThreads, isBackground, ignoreBattery); + assert(address, "Must provide address to mine to"); + assert(GenUtils.isInt(numThreads) && numThreads > 0, "Number of threads must be an integer greater than 0"); + assert(isBackground === undefined || typeof isBackground === "boolean"); + assert(ignoreBattery === undefined || typeof ignoreBattery === "boolean"); + let resp = await this.config.getServer().sendPathRequest("start_mining", { + miner_address: address, + threads_count: numThreads, + do_background_mining: isBackground, + ignore_battery: ignoreBattery, + }); + MoneroDaemonRpc.checkResponseStatus(resp); + } + + async stopMining(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.stopMining(); + let resp = await this.config.getServer().sendPathRequest("stop_mining"); + MoneroDaemonRpc.checkResponseStatus(resp); + } + + async getMiningStatus(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.getMiningStatus(); + let resp = await this.config.getServer().sendPathRequest("mining_status"); + MoneroDaemonRpc.checkResponseStatus(resp); + return MoneroDaemonRpc.convertRpcMiningStatus(resp); + } + + async submitBlocks(blockBlobs: string[]): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.submitBlocks(blockBlobs); + assert(Array.isArray(blockBlobs) && blockBlobs.length > 0, "Must provide an array of mined block blobs to submit"); + let resp = await this.config.getServer().sendJsonRequest("submit_block", blockBlobs); + MoneroDaemonRpc.checkResponseStatus(resp.result); + } + + async pruneBlockchain(check: boolean): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.pruneBlockchain(); + let resp = await this.config.getServer().sendJsonRequest("prune_blockchain", {check: check}, 0); + MoneroDaemonRpc.checkResponseStatus(resp.result); + let result = new MoneroPruneResult(); + result.setIsPruned(resp.result.pruned); + result.setPruningSeed(resp.result.pruning_seed); + return result; + } + + async checkForUpdate(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.checkForUpdate(); + let resp = await this.config.getServer().sendPathRequest("update", {command: "check"}); + MoneroDaemonRpc.checkResponseStatus(resp); + return MoneroDaemonRpc.convertRpcUpdateCheckResult(resp); + } + + async downloadUpdate(path?: string): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.downloadUpdate(path); + let resp = await this.config.getServer().sendPathRequest("update", {command: "download", path: path}); + MoneroDaemonRpc.checkResponseStatus(resp); + return MoneroDaemonRpc.convertRpcUpdateDownloadResult(resp); + } + + async stop(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.stop(); + let resp = await this.config.getServer().sendPathRequest("stop_daemon"); + MoneroDaemonRpc.checkResponseStatus(resp); + } + + async waitForNextBlockHeader(): Promise { + if (this.config.proxyToWorker) return this.proxyDaemon.waitForNextBlockHeader(); + let that = this; + return new Promise(async function(resolve) { + await that.addListener(new class extends MoneroDaemonListener { + async onBlockHeader(header) { + await that.removeListener(this); + resolve(header); + } + }); + }); + } + + getPollInterval(): number { + return this.config.pollInterval; + } + + // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS -------------- + async getTx(txHash?: string, prune = false): Promise { return super.getTx(txHash, prune); }; + async getTxHex(txHash: string, prune = false): Promise { return super.getTxHex(txHash, prune); }; + async getKeyImageSpentStatus(keyImage: string): Promise { return super.getKeyImageSpentStatus(keyImage); } + async setPeerBan(ban: MoneroBan): Promise { return super.setPeerBan(ban); } + async submitBlock(blockBlob: string): Promise { return super.submitBlock(blockBlob); } + + // ------------------------------- PRIVATE ---------------------------------- + + protected refreshListening() { + if (this.pollListener == undefined && this.listeners.length) this.pollListener = new DaemonPoller(this); + if (this.pollListener !== undefined) this.pollListener.setIsPolling(this.listeners.length > 0); + } + + protected async getBandwidthLimits() { + let resp = await this.config.getServer().sendPathRequest("get_limit"); + MoneroDaemonRpc.checkResponseStatus(resp); + return [resp.limit_down, resp.limit_up]; + } + + protected async setBandwidthLimits(downLimit, upLimit) { + if (downLimit === undefined) downLimit = 0; + if (upLimit === undefined) upLimit = 0; + let resp = await this.config.getServer().sendPathRequest("set_limit", {limit_down: downLimit, limit_up: upLimit}); + MoneroDaemonRpc.checkResponseStatus(resp); + return [resp.limit_down, resp.limit_up]; + } + + /** + * Get a contiguous chunk of blocks starting from a given height up to a maximum + * height or amount of block data fetched from the blockchain, whichever comes first. + * + * @param {number} [startHeight] - start height to retrieve blocks (default 0) + * @param {number} [maxHeight] - maximum end height to retrieve blocks (default blockchain height) + * @param {number} [maxReqSize] - maximum amount of block data to fetch from the blockchain in bytes (default 3,000,000 bytes) + * @return {MoneroBlock[]} are the resulting chunk of blocks + */ + protected async getMaxBlocks(startHeight, maxHeight, maxReqSize) { + if (startHeight === undefined) startHeight = 0; + if (maxHeight === undefined) maxHeight = await this.getHeight() - 1; + if (maxReqSize === undefined) maxReqSize = MoneroDaemonRpc.MAX_REQ_SIZE; + + // determine end height to fetch + let reqSize = 0; + let endHeight = startHeight - 1; + while (reqSize < maxReqSize && endHeight < maxHeight) { + + // get header of next block + let header = await this.getBlockHeaderByHeightCached(endHeight + 1, maxHeight); + + // block cannot be bigger than max request size + assert(header.getSize() <= maxReqSize, "Block exceeds maximum request size: " + header.getSize()); + + // done iterating if fetching block would exceed max request size + if (reqSize + header.getSize() > maxReqSize) break; + + // otherwise block is included + reqSize += header.getSize(); + endHeight++; + } + return endHeight >= startHeight ? await this.getBlocksByRange(startHeight, endHeight) : []; + } + + /** + * Retrieves a header by height from the cache or fetches and caches a header + * range if not already in the cache. + * + * @param {number} height - height of the header to retrieve from the cache + * @param {number} maxHeight - maximum height of headers to cache + */ + protected async getBlockHeaderByHeightCached(height, maxHeight) { + + // get header from cache + let cachedHeader = this.cachedHeaders[height]; + if (cachedHeader) return cachedHeader; + + // fetch and cache headers if not in cache + let endHeight = Math.min(maxHeight, height + MoneroDaemonRpc.NUM_HEADERS_PER_REQ - 1); // TODO: could specify end height to cache to optimize small requests (would like to have time profiling in place though) + let headers = await this.getBlockHeadersByRange(height, endHeight); + for (let header of headers) { + this.cachedHeaders[header.getHeight()] = header; + } + + // return the cached header + return this.cachedHeaders[height]; + } + + // --------------------------------- STATIC --------------------------------- + + static async connectToDaemonRpc(uriOrConfig: string | Partial | Partial | string[], username?: string, password?: string): Promise { + let config = MoneroDaemonRpc.normalizeConfig(uriOrConfig, username, password); + if (config.cmd) return MoneroDaemonRpc.startMonerodProcess(config); + return new MoneroDaemonRpc(config, config.proxyToWorker ? await MoneroDaemonRpcProxy.connect(config) : undefined); + } + + protected static async startMonerodProcess(config: MoneroDaemonConfig): Promise { + assert(GenUtils.isArray(config.cmd), "Must provide string array with command line parameters"); + + // start process + let childProcess = require('child_process').spawn(config.cmd[0], config.cmd.slice(1), { + env: { ...process.env, LANG: 'en_US.UTF-8' } // scrape output in english + }); + childProcess.stdout.setEncoding('utf8'); + childProcess.stderr.setEncoding('utf8'); + + // return promise which resolves after starting monerod + let uri; + let output = ""; + try { + return await new Promise(function(resolve, reject) { + + // handle stdout + childProcess.stdout.on('data', async function(data) { + let line = data.toString(); + LibraryUtils.log(2, line); + output += line + '\n'; // capture output in case of error + + // extract uri from e.g. "I Binding on 127.0.0.1 (IPv4):38085" + let uriLineContains = "Binding on "; + let uriLineContainsIdx = line.indexOf(uriLineContains); + if (uriLineContainsIdx >= 0) { + let host = line.substring(uriLineContainsIdx + uriLineContains.length, line.lastIndexOf(' ')); + let unformattedLine = line.replace(/\u001b\[.*?m/g, '').trim(); // remove color formatting + let port = unformattedLine.substring(unformattedLine.lastIndexOf(':') + 1); + let sslIdx = config.cmd.indexOf("--rpc-ssl"); + let sslEnabled = sslIdx >= 0 ? "enabled" == config.cmd[sslIdx + 1].toLowerCase() : false; + uri = (sslEnabled ? "https" : "http") + "://" + host + ":" + port; + } + + // read success message + if (line.indexOf("core RPC server started ok") >= 0) { + + // get username and password from params + let userPassIdx = config.cmd.indexOf("--rpc-login"); + let userPass = userPassIdx >= 0 ? config.cmd[userPassIdx + 1] : undefined; + let username = userPass === undefined ? undefined : userPass.substring(0, userPass.indexOf(':')); + let password = userPass === undefined ? undefined : userPass.substring(userPass.indexOf(':') + 1); + + // create client connected to internal process + config = config.copy().setServer({uri: uri, username: username, password: password, rejectUnauthorized: config.getServer() ? config.getServer().getRejectUnauthorized() : undefined}); + config.setProxyToWorker(config.proxyToWorker); + config.cmd = undefined + let daemon = await MoneroDaemonRpc.connectToDaemonRpc(config); + daemon.process = childProcess; + + // resolve promise with client connected to internal process + this.isResolved = true; + resolve(daemon); + } + }); + + // handle stderr + childProcess.stderr.on('data', function(data) { + if (LibraryUtils.getLogLevel() >= 2) console.error(data); + }); + + // handle exit + childProcess.on("exit", function(code) { + if (!this.isResolved) reject(new Error("monerod process terminated with exit code " + code + (output ? ":\n\n" + output : ""))); + }); + + // handle error + childProcess.on("error", function(err) { + if (err.message.indexOf("ENOENT") >= 0) reject(new Error("monerod does not exist at path '" + config.cmd[0] + "'")); + if (!this.isResolved) reject(err); + }); + + // handle uncaught exception + childProcess.on("uncaughtException", function(err, origin) { + console.error("Uncaught exception in monerod process: " + err.message); + console.error(origin); + if (!this.isResolved) reject(err); + }); + }); + } catch (err: any) { + throw new MoneroError(err.message); + } + } + + protected static normalizeConfig(uriOrConfig: string | Partial | Partial | string[], username?: string, password?: string): MoneroDaemonConfig { + let config: undefined | Partial = undefined; + if (typeof uriOrConfig === "string") { + config = new MoneroDaemonConfig({server: new MoneroRpcConnection(uriOrConfig as string, username, password)}); + } else if ((uriOrConfig as Partial).uri !== undefined) { + config = new MoneroDaemonConfig({server: new MoneroRpcConnection(uriOrConfig as Partial)}); + + // transfer worker proxy setting from rpc connection to daemon config + config.setProxyToWorker((uriOrConfig as Partial).proxyToWorker); + config.getServer().setProxyToWorker(MoneroRpcConnection.DEFAULT_CONFIG.proxyToWorker); + } else if (GenUtils.isArray(uriOrConfig)) { + config = new MoneroDaemonConfig({cmd: uriOrConfig as string[]}); + } else { + config = new MoneroDaemonConfig(uriOrConfig as Partial); + } + if (config.proxyToWorker === undefined) config.proxyToWorker = true; + if (config.pollInterval === undefined) config.pollInterval = MoneroDaemonRpc.DEFAULT_POLL_PERIOD; + return config as MoneroDaemonConfig; + } + + protected static checkResponseStatus(resp) { + if (resp.status !== "OK") throw new MoneroError(resp.status); + } + + protected static convertRpcBlockHeader(rpcHeader) { + if (!rpcHeader) return undefined; + let header = new MoneroBlockHeader(); + for (let key of Object.keys(rpcHeader)) { + let val = rpcHeader[key]; + if (key === "block_size") GenUtils.safeSet(header, header.getSize, header.setSize, val); + else if (key === "depth") GenUtils.safeSet(header, header.getDepth, header.setDepth, val); + else if (key === "difficulty") { } // handled by wide_difficulty + else if (key === "cumulative_difficulty") { } // handled by wide_cumulative_difficulty + else if (key === "difficulty_top64") { } // handled by wide_difficulty + else if (key === "cumulative_difficulty_top64") { } // handled by wide_cumulative_difficulty + else if (key === "wide_difficulty") header.setDifficulty(GenUtils.reconcile(header.getDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val))); + else if (key === "wide_cumulative_difficulty") header.setCumulativeDifficulty(GenUtils.reconcile(header.getCumulativeDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val))); + else if (key === "hash") GenUtils.safeSet(header, header.getHash, header.setHash, val); + else if (key === "height") GenUtils.safeSet(header, header.getHeight, header.setHeight, val); + else if (key === "major_version") GenUtils.safeSet(header, header.getMajorVersion, header.setMajorVersion, val); + else if (key === "minor_version") GenUtils.safeSet(header, header.getMinorVersion, header.setMinorVersion, val); + else if (key === "nonce") GenUtils.safeSet(header, header.getNonce, header.setNonce, val); + else if (key === "num_txes") GenUtils.safeSet(header, header.getNumTxs, header.setNumTxs, val); + else if (key === "orphan_status") GenUtils.safeSet(header, header.getOrphanStatus, header.setOrphanStatus, val); + else if (key === "prev_hash" || key === "prev_id") GenUtils.safeSet(header, header.getPrevHash, header.setPrevHash, val); + else if (key === "reward") GenUtils.safeSet(header, header.getReward, header.setReward, BigInt(val)); + else if (key === "timestamp") GenUtils.safeSet(header, header.getTimestamp, header.setTimestamp, val); + else if (key === "block_weight") GenUtils.safeSet(header, header.getWeight, header.setWeight, val); + else if (key === "long_term_weight") GenUtils.safeSet(header, header.getLongTermWeight, header.setLongTermWeight, val); + else if (key === "pow_hash") GenUtils.safeSet(header, header.getPowHash, header.setPowHash, val === "" ? undefined : val); + else if (key === "tx_hashes") {} // used in block model, not header model + else if (key === "miner_tx") {} // used in block model, not header model + else if (key === "miner_tx_hash") header.setMinerTxHash(val); + else console.log("WARNING: ignoring unexpected block header field: '" + key + "': " + val); + } + return header; + } + + protected static convertRpcBlock(rpcBlock) { + + // build block + let block = new MoneroBlock(MoneroDaemonRpc.convertRpcBlockHeader(rpcBlock.block_header ? rpcBlock.block_header : rpcBlock) as MoneroBlock); + block.setHex(rpcBlock.blob); + block.setTxHashes(rpcBlock.tx_hashes === undefined ? [] : rpcBlock.tx_hashes); + + // build miner tx + let rpcMinerTx = rpcBlock.json ? JSON.parse(rpcBlock.json).miner_tx : rpcBlock.miner_tx; // may need to be parsed from json + let minerTx = new MoneroTx(); + block.setMinerTx(minerTx); + minerTx.setIsConfirmed(true); + minerTx.setInTxPool(false) + minerTx.setIsMinerTx(true); + MoneroDaemonRpc.convertRpcTx(rpcMinerTx, minerTx); + + return block; + } + + /** + * Transfers RPC tx fields to a given MoneroTx without overwriting previous values. + * + * TODO: switch from safe set + * + * @param rpcTx - RPC map containing transaction fields + * @param tx - MoneroTx to populate with values (optional) + * @return tx - same tx that was passed in or a new one if none given + */ + protected static convertRpcTx(rpcTx, tx) { + if (rpcTx === undefined) return undefined; + if (tx === undefined) tx = new MoneroTx(); + + // initialize from rpc map + let header; + for (let key of Object.keys(rpcTx)) { + let val = rpcTx[key]; + if (key === "tx_hash" || key === "id_hash") GenUtils.safeSet(tx, tx.getHash, tx.setHash, val); + else if (key === "block_timestamp") { + if (!header) header = new MoneroBlockHeader(); + GenUtils.safeSet(header, header.getTimestamp, header.setTimestamp, val); + } + else if (key === "block_height") { + if (!header) header = new MoneroBlockHeader(); + GenUtils.safeSet(header, header.getHeight, header.setHeight, val); + } + else if (key === "last_relayed_time") GenUtils.safeSet(tx, tx.getLastRelayedTimestamp, tx.setLastRelayedTimestamp, val); + else if (key === "receive_time" || key === "received_timestamp") GenUtils.safeSet(tx, tx.getReceivedTimestamp, tx.setReceivedTimestamp, val); + else if (key === "confirmations") GenUtils.safeSet(tx, tx.getNumConfirmations, tx.setNumConfirmations, val); + else if (key === "in_pool") { + GenUtils.safeSet(tx, tx.getIsConfirmed, tx.setIsConfirmed, !val); + GenUtils.safeSet(tx, tx.getInTxPool, tx.setInTxPool, val); + } + else if (key === "double_spend_seen") GenUtils.safeSet(tx, tx.getIsDoubleSpendSeen, tx.setIsDoubleSpendSeen, val); + else if (key === "version") GenUtils.safeSet(tx, tx.getVersion, tx.setVersion, val); + else if (key === "extra") { + if (typeof val === "string") console.log("WARNING: extra field as string not being asigned to int[]: " + key + ": " + val); // TODO: how to set string to int[]? - or, extra is string which can encode int[] + else GenUtils.safeSet(tx, tx.getExtra, tx.setExtra, new Uint8Array(val)); + } + else if (key === "vin") { + if (val.length !== 1 || !val[0].gen) { // ignore miner input TODO: why? + tx.setInputs(val.map(rpcVin => MoneroDaemonRpc.convertRpcOutput(rpcVin, tx))); + } + } + else if (key === "vout") tx.setOutputs(val.map(rpcOutput => MoneroDaemonRpc.convertRpcOutput(rpcOutput, tx))); + else if (key === "rct_signatures") { + GenUtils.safeSet(tx, tx.getRctSignatures, tx.setRctSignatures, val); + if (val.txnFee) GenUtils.safeSet(tx, tx.getFee, tx.setFee, BigInt(val.txnFee)); + } + else if (key === "rctsig_prunable") GenUtils.safeSet(tx, tx.getRctSigPrunable, tx.setRctSigPrunable, val); + else if (key === "unlock_time") GenUtils.safeSet(tx, tx.getUnlockTime, tx.setUnlockTime, val); + else if (key === "as_json" || key === "tx_json") { } // handled last so tx is as initialized as possible + else if (key === "as_hex" || key === "tx_blob") GenUtils.safeSet(tx, tx.getFullHex, tx.setFullHex, val ? val : undefined); + else if (key === "blob_size") GenUtils.safeSet(tx, tx.getSize, tx.setSize, val); + else if (key === "weight") GenUtils.safeSet(tx, tx.getWeight, tx.setWeight, val); + else if (key === "fee") GenUtils.safeSet(tx, tx.getFee, tx.setFee, BigInt(val)); + else if (key === "relayed") GenUtils.safeSet(tx, tx.getIsRelayed, tx.setIsRelayed, val); + else if (key === "output_indices") GenUtils.safeSet(tx, tx.getOutputIndices, tx.setOutputIndices, val); + else if (key === "do_not_relay") GenUtils.safeSet(tx, tx.getRelay, tx.setRelay, !val); + else if (key === "kept_by_block") GenUtils.safeSet(tx, tx.getIsKeptByBlock, tx.setIsKeptByBlock, val); + else if (key === "signatures") GenUtils.safeSet(tx, tx.getSignatures, tx.setSignatures, val); + else if (key === "last_failed_height") { + if (val === 0) GenUtils.safeSet(tx, tx.getIsFailed, tx.setIsFailed, false); + else { + GenUtils.safeSet(tx, tx.getIsFailed, tx.setIsFailed, true); + GenUtils.safeSet(tx, tx.getLastFailedHeight, tx.setLastFailedHeight, val); + } + } + else if (key === "last_failed_id_hash") { + if (val === MoneroDaemonRpc.DEFAULT_ID) GenUtils.safeSet(tx, tx.getIsFailed, tx.setIsFailed, false); + else { + GenUtils.safeSet(tx, tx.getIsFailed, tx.setIsFailed, true); + GenUtils.safeSet(tx, tx.getLastFailedHash, tx.setLastFailedHash, val); + } + } + else if (key === "max_used_block_height") GenUtils.safeSet(tx, tx.getMaxUsedBlockHeight, tx.setMaxUsedBlockHeight, val); + else if (key === "max_used_block_id_hash") GenUtils.safeSet(tx, tx.getMaxUsedBlockHash, tx.setMaxUsedBlockHash, val); + else if (key === "prunable_hash") GenUtils.safeSet(tx, tx.getPrunableHash, tx.setPrunableHash, val ? val : undefined); + else if (key === "prunable_as_hex") GenUtils.safeSet(tx, tx.getPrunableHex, tx.setPrunableHex, val ? val : undefined); + else if (key === "pruned_as_hex") GenUtils.safeSet(tx, tx.getPrunedHex, tx.setPrunedHex, val ? val : undefined); + else console.log("WARNING: ignoring unexpected field in rpc tx: " + key + ": " + val); + } + + // link block and tx + if (header) tx.setBlock(new MoneroBlock(header).setTxs([tx])); + + // TODO monerod: unconfirmed txs misreport block height and timestamp? + if (tx.getBlock() && tx.getBlock().getHeight() !== undefined && tx.getBlock().getHeight() === tx.getBlock().getTimestamp()) { + tx.setBlock(undefined); + tx.setIsConfirmed(false); + } + + // initialize remaining known fields + if (tx.getIsConfirmed()) { + GenUtils.safeSet(tx, tx.getIsRelayed, tx.setIsRelayed, true); + GenUtils.safeSet(tx, tx.getRelay, tx.setRelay, true); + GenUtils.safeSet(tx, tx.getIsFailed, tx.setIsFailed, false); + } else { + tx.setNumConfirmations(0); + } + if (tx.getIsFailed() === undefined) tx.setIsFailed(false); + if (tx.getOutputIndices() && tx.getOutputs()) { + assert.equal(tx.getOutputs().length, tx.getOutputIndices().length); + for (let i = 0; i < tx.getOutputs().length; i++) { + tx.getOutputs()[i].setIndex(tx.getOutputIndices()[i]); // transfer output indices to outputs + } + } + if (rpcTx.as_json) MoneroDaemonRpc.convertRpcTx(JSON.parse(rpcTx.as_json), tx); + if (rpcTx.tx_json) MoneroDaemonRpc.convertRpcTx(JSON.parse(rpcTx.tx_json), tx); + if (!tx.getIsRelayed()) tx.setLastRelayedTimestamp(undefined); // TODO monerod: returns last_relayed_timestamp despite relayed: false, self inconsistent + + // return built transaction + return tx; + } + + protected static convertRpcOutput(rpcOutput, tx) { + let output = new MoneroOutput(); + output.setTx(tx); + for (let key of Object.keys(rpcOutput)) { + let val = rpcOutput[key]; + if (key === "gen") throw new MoneroError("Output with 'gen' from daemon rpc is miner tx which we ignore (i.e. each miner input is undefined)"); + else if (key === "key") { + GenUtils.safeSet(output, output.getAmount, output.setAmount, BigInt(val.amount)); + GenUtils.safeSet(output, output.getKeyImage, output.setKeyImage, new MoneroKeyImage(val.k_image)); + GenUtils.safeSet(output, output.getRingOutputIndices, output.setRingOutputIndices, val.key_offsets); + } + else if (key === "amount") GenUtils.safeSet(output, output.getAmount, output.setAmount, BigInt(val)); + else if (key === "target") { + let pubKey = val.key === undefined ? val.tagged_key.key : val.key; // TODO (monerod): rpc json uses {tagged_key={key=...}}, binary blocks use {key=...} + GenUtils.safeSet(output, output.getStealthPublicKey, output.setStealthPublicKey, pubKey); + } + else console.log("WARNING: ignoring unexpected field output: " + key + ": " + val); + } + return output; + } + + protected static convertRpcBlockTemplate(rpcTemplate) { + let template = new MoneroBlockTemplate(); + for (let key of Object.keys(rpcTemplate)) { + let val = rpcTemplate[key]; + if (key === "blockhashing_blob") template.setBlockHashingBlob(val); + else if (key === "blocktemplate_blob") template.setBlockTemplateBlob(val); + else if (key === "expected_reward") template.setExpectedReward(val); + else if (key === "difficulty") { } // handled by wide_difficulty + else if (key === "difficulty_top64") { } // handled by wide_difficulty + else if (key === "wide_difficulty") template.setDifficulty(GenUtils.reconcile(template.getDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val))); + else if (key === "height") template.setHeight(val); + else if (key === "prev_hash") template.setPrevHash(val); + else if (key === "reserved_offset") template.setReservedOffset(val); + else if (key === "status") {} // handled elsewhere + else if (key === "untrusted") {} // handled elsewhere + else if (key === "seed_height") template.setSeedHeight(val); + else if (key === "seed_hash") template.setSeedHash(val); + else if (key === "next_seed_hash") template.setNextSeedHash(val); + else console.log("WARNING: ignoring unexpected field in block template: " + key + ": " + val); + } + if ("" === template.getNextSeedHash()) template.setNextSeedHash(undefined); + return template; + } + + protected static convertRpcInfo(rpcInfo) { + if (!rpcInfo) return undefined; + let info = new MoneroDaemonInfo(); + for (let key of Object.keys(rpcInfo)) { + let val = rpcInfo[key]; + if (key === "version") info.setVersion(val); + else if (key === "alt_blocks_count") info.setNumAltBlocks(val); + else if (key === "block_size_limit") info.setBlockSizeLimit(val); + else if (key === "block_size_median") info.setBlockSizeMedian(val); + else if (key === "block_weight_limit") info.setBlockWeightLimit(val); + else if (key === "block_weight_median") info.setBlockWeightMedian(val); + else if (key === "bootstrap_daemon_address") { if (val) info.setBootstrapDaemonAddress(val); } + else if (key === "difficulty") { } // handled by wide_difficulty + else if (key === "cumulative_difficulty") { } // handled by wide_cumulative_difficulty + else if (key === "difficulty_top64") { } // handled by wide_difficulty + else if (key === "cumulative_difficulty_top64") { } // handled by wide_cumulative_difficulty + else if (key === "wide_difficulty") info.setDifficulty(GenUtils.reconcile(info.getDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val))); + else if (key === "wide_cumulative_difficulty") info.setCumulativeDifficulty(GenUtils.reconcile(info.getCumulativeDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val))); + else if (key === "free_space") info.setFreeSpace(BigInt(val)); + else if (key === "database_size") info.setDatabaseSize(val); + else if (key === "grey_peerlist_size") info.setNumOfflinePeers(val); + else if (key === "height") info.setHeight(val); + else if (key === "height_without_bootstrap") info.setHeightWithoutBootstrap(val); + else if (key === "incoming_connections_count") info.setNumIncomingConnections(val); + else if (key === "offline") info.setIsOffline(val); + else if (key === "outgoing_connections_count") info.setNumOutgoingConnections(val); + else if (key === "rpc_connections_count") info.setNumRpcConnections(val); + else if (key === "start_time") info.setStartTimestamp(val); + else if (key === "adjusted_time") info.setAdjustedTimestamp(val); + else if (key === "status") {} // handled elsewhere + else if (key === "target") info.setTarget(val); + else if (key === "target_height") info.setTargetHeight(val); + else if (key === "top_block_hash") info.setTopBlockHash(val); + else if (key === "tx_count") info.setNumTxs(val); + else if (key === "tx_pool_size") info.setNumTxsPool(val); + else if (key === "untrusted") {} // handled elsewhere + else if (key === "was_bootstrap_ever_used") info.setWasBootstrapEverUsed(val); + else if (key === "white_peerlist_size") info.setNumOnlinePeers(val); + else if (key === "update_available") info.setUpdateAvailable(val); + else if (key === "nettype") GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.parse(val)); + else if (key === "mainnet") { if (val) GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.MAINNET); } + else if (key === "testnet") { if (val) GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.TESTNET); } + else if (key === "stagenet") { if (val) GenUtils.safeSet(info, info.getNetworkType, info.setNetworkType, MoneroNetworkType.STAGENET); } + else if (key === "credits") info.setCredits(BigInt(val)); + else if (key === "top_block_hash" || key === "top_hash") info.setTopBlockHash(GenUtils.reconcile(info.getTopBlockHash(), "" === val ? undefined : val)) + else if (key === "busy_syncing") info.setIsBusySyncing(val); + else if (key === "synchronized") info.setIsSynchronized(val); + else if (key === "restricted") info.setIsRestricted(val); + else console.log("WARNING: Ignoring unexpected info field: " + key + ": " + val); + } + return info; + } + + /** + * Initializes sync info from RPC sync info. + * + * @param rpcSyncInfo - rpc map to initialize the sync info from + * @return {MoneroDaemonSyncInfo} is sync info initialized from the map + */ + protected static convertRpcSyncInfo(rpcSyncInfo) { + let syncInfo = new MoneroDaemonSyncInfo(); + for (let key of Object.keys(rpcSyncInfo)) { + let val = rpcSyncInfo[key]; + if (key === "height") syncInfo.setHeight(val); + else if (key === "peers") { + syncInfo.setPeers([]); + let rpcConnections = val; + for (let rpcConnection of rpcConnections) { + syncInfo.getPeers().push(MoneroDaemonRpc.convertRpcConnection(rpcConnection.info)); + } + } + else if (key === "spans") { + syncInfo.setSpans([]); + let rpcSpans = val; + for (let rpcSpan of rpcSpans) { + syncInfo.getSpans().push(MoneroDaemonRpc.convertRpcConnectionSpan(rpcSpan)); + } + } else if (key === "status") {} // handled elsewhere + else if (key === "target_height") syncInfo.setTargetHeight(val); + else if (key === "next_needed_pruning_seed") syncInfo.setNextNeededPruningSeed(val); + else if (key === "overview") { // this returns [] without pruning + let overview; + try { + overview = JSON.parse(val); + if (overview !== undefined && overview.length > 0) console.error("Ignoring non-empty 'overview' field (not implemented): " + overview); // TODO + } catch (e: any) { + console.error("Failed to parse 'overview' field: " + overview + ": " + e.message); + } + } + else if (key === "credits") syncInfo.setCredits(BigInt(val)); + else if (key === "top_hash") syncInfo.setTopBlockHash("" === val ? undefined : val); + else if (key === "untrusted") {} // handled elsewhere + else console.log("WARNING: ignoring unexpected field in sync info: " + key + ": " + val); + } + return syncInfo; + } + + protected static convertRpcHardForkInfo(rpcHardForkInfo) { + let info = new MoneroHardForkInfo(); + for (let key of Object.keys(rpcHardForkInfo)) { + let val = rpcHardForkInfo[key]; + if (key === "earliest_height") info.setEarliestHeight(val); + else if (key === "enabled") info.setIsEnabled(val); + else if (key === "state") info.setState(val); + else if (key === "status") {} // handled elsewhere + else if (key === "untrusted") {} // handled elsewhere + else if (key === "threshold") info.setThreshold(val); + else if (key === "version") info.setVersion(val); + else if (key === "votes") info.setNumVotes(val); + else if (key === "voting") info.setVoting(val); + else if (key === "window") info.setWindow(val); + else if (key === "credits") info.setCredits(BigInt(val)); + else if (key === "top_hash") info.setTopBlockHash("" === val ? undefined : val); + else console.log("WARNING: ignoring unexpected field in hard fork info: " + key + ": " + val); + } + return info; + } + + protected static convertRpcConnectionSpan(rpcConnectionSpan) { + let span = new MoneroConnectionSpan(); + for (let key of Object.keys(rpcConnectionSpan)) { + let val = rpcConnectionSpan[key]; + if (key === "connection_id") span.setConnectionId(val); + else if (key === "nblocks") span.setNumBlocks(val); + else if (key === "rate") span.setRate(val); + else if (key === "remote_address") { if (val !== "") span.setRemoteAddress(val); } + else if (key === "size") span.setSize(val); + else if (key === "speed") span.setSpeed(val); + else if (key === "start_block_height") span.setStartHeight(val); + else console.log("WARNING: ignoring unexpected field in daemon connection span: " + key + ": " + val); + } + return span; + } + + protected static convertRpcOutputHistogramEntry(rpcEntry) { + let entry = new MoneroOutputHistogramEntry(); + for (let key of Object.keys(rpcEntry)) { + let val = rpcEntry[key]; + if (key === "amount") entry.setAmount(BigInt(val)); + else if (key === "total_instances") entry.setNumInstances(val); + else if (key === "unlocked_instances") entry.setNumUnlockedInstances(val); + else if (key === "recent_instances") entry.setNumRecentInstances(val); + else console.log("WARNING: ignoring unexpected field in output histogram: " + key + ": " + val); + } + return entry; + } + + protected static convertRpcSubmitTxResult(rpcResult) { + assert(rpcResult); + let result = new MoneroSubmitTxResult(); + for (let key of Object.keys(rpcResult)) { + let val = rpcResult[key]; + if (key === "double_spend") result.setIsDoubleSpendSeen(val); + else if (key === "fee_too_low") result.setIsFeeTooLow(val); + else if (key === "invalid_input") result.setHasInvalidInput(val); + else if (key === "invalid_output") result.setHasInvalidOutput(val); + else if (key === "too_few_outputs") result.setHasTooFewOutputs(val); + else if (key === "low_mixin") result.setIsMixinTooLow(val); + else if (key === "not_relayed") result.setIsRelayed(!val); + else if (key === "overspend") result.setIsOverspend(val); + else if (key === "reason") result.setReason(val === "" ? undefined : val); + else if (key === "too_big") result.setIsTooBig(val); + else if (key === "sanity_check_failed") result.setSanityCheckFailed(val); + else if (key === "credits") result.setCredits(BigInt(val)) + else if (key === "status" || key === "untrusted") {} // handled elsewhere + else if (key === "top_hash") result.setTopBlockHash("" === val ? undefined : val); + else if (key === "tx_extra_too_big") result.setIsTxExtraTooBig(val); + else if (key === "nonzero_unlock_time") result.setIsNonzeroUnlockTime(val); + else console.log("WARNING: ignoring unexpected field in submit tx hex result: " + key + ": " + val); + } + return result; + } + + protected static convertRpcTxPoolStats(rpcStats) { + assert(rpcStats); + let stats = new MoneroTxPoolStats(); + for (let key of Object.keys(rpcStats)) { + let val = rpcStats[key]; + if (key === "bytes_max") stats.setBytesMax(val); + else if (key === "bytes_med") stats.setBytesMed(val); + else if (key === "bytes_min") stats.setBytesMin(val); + else if (key === "bytes_total") stats.setBytesTotal(val); + else if (key === "histo_98pc") stats.setHisto98pc(val); + else if (key === "num_10m") stats.setNum10m(val); + else if (key === "num_double_spends") stats.setNumDoubleSpends(val); + else if (key === "num_failing") stats.setNumFailing(val); + else if (key === "num_not_relayed") stats.setNumNotRelayed(val); + else if (key === "oldest") stats.setOldestTimestamp(val); + else if (key === "txs_total") stats.setNumTxs(val); + else if (key === "fee_total") stats.setFeeTotal(BigInt(val)); + else if (key === "histo") { + stats.setHisto(new Map()); + for (let elem of val) stats.getHisto().set(elem.bytes, elem.txs); + } + else console.log("WARNING: ignoring unexpected field in tx pool stats: " + key + ": " + val); + } + + // uninitialize some stats if not applicable + if (stats.getHisto98pc() === 0) stats.setHisto98pc(undefined); + if (stats.getNumTxs() === 0) { + stats.setBytesMin(undefined); + stats.setBytesMed(undefined); + stats.setBytesMax(undefined); + stats.setHisto98pc(undefined); + stats.setOldestTimestamp(undefined); + } + + return stats; + } + + protected static convertRpcAltChain(rpcChain) { + assert(rpcChain); + let chain = new MoneroAltChain(); + for (let key of Object.keys(rpcChain)) { + let val = rpcChain[key]; + if (key === "block_hash") {} // using block_hashes instead + else if (key === "difficulty") { } // handled by wide_difficulty + else if (key === "difficulty_top64") { } // handled by wide_difficulty + else if (key === "wide_difficulty") chain.setDifficulty(GenUtils.reconcile(chain.getDifficulty(), MoneroDaemonRpc.prefixedHexToBI(val))); + else if (key === "height") chain.setHeight(val); + else if (key === "length") chain.setLength(val); + else if (key === "block_hashes") chain.setBlockHashes(val); + else if (key === "main_chain_parent_block") chain.setMainChainParentBlockHash(val); + else console.log("WARNING: ignoring unexpected field in alternative chain: " + key + ": " + val); + } + return chain; + } + + protected static convertRpcPeer(rpcPeer) { + assert(rpcPeer); + let peer = new MoneroPeer(); + for (let key of Object.keys(rpcPeer)) { + let val = rpcPeer[key]; + if (key === "host") peer.setHost(val); + else if (key === "id") peer.setId("" + val); // TODO monero-wallet-rpc: peer id is BigInt but string in `get_connections` + else if (key === "ip") {} // host used instead which is consistently a string + else if (key === "last_seen") peer.setLastSeenTimestamp(val); + else if (key === "port") peer.setPort(val); + else if (key === "rpc_port") peer.setRpcPort(val); + else if (key === "pruning_seed") peer.setPruningSeed(val); + else if (key === "rpc_credits_per_hash") peer.setRpcCreditsPerHash(BigInt(val)); + else console.log("WARNING: ignoring unexpected field in rpc peer: " + key + ": " + val); + } + return peer; + } + + protected static convertRpcConnection(rpcConnection) { + let peer = new MoneroPeer(); + peer.setIsOnline(true); + for (let key of Object.keys(rpcConnection)) { + let val = rpcConnection[key]; + if (key === "address") peer.setAddress(val); + else if (key === "avg_download") peer.setAvgDownload(val); + else if (key === "avg_upload") peer.setAvgUpload(val); + else if (key === "connection_id") peer.setId(val); + else if (key === "current_download") peer.setCurrentDownload(val); + else if (key === "current_upload") peer.setCurrentUpload(val); + else if (key === "height") peer.setHeight(val); + else if (key === "host") peer.setHost(val); + else if (key === "ip") {} // host used instead which is consistently a string + else if (key === "incoming") peer.setIsIncoming(val); + else if (key === "live_time") peer.setLiveTime(val); + else if (key === "local_ip") peer.setIsLocalIp(val); + else if (key === "localhost") peer.setIsLocalHost(val); + else if (key === "peer_id") peer.setId(val); + else if (key === "port") peer.setPort(parseInt(val)); + else if (key === "rpc_port") peer.setRpcPort(val); + else if (key === "recv_count") peer.setNumReceives(val); + else if (key === "recv_idle_time") peer.setReceiveIdleTime(val); + else if (key === "send_count") peer.setNumSends(val); + else if (key === "send_idle_time") peer.setSendIdleTime(val); + else if (key === "state") peer.setState(val); + else if (key === "support_flags") peer.setNumSupportFlags(val); + else if (key === "pruning_seed") peer.setPruningSeed(val); + else if (key === "rpc_credits_per_hash") peer.setRpcCreditsPerHash(BigInt(val)); + else if (key === "address_type") peer.setType(val); + else console.log("WARNING: ignoring unexpected field in peer: " + key + ": " + val); + } + return peer; + } + + protected static convertToRpcBan(ban: MoneroBan) { + let rpcBan: any = {}; + rpcBan.host = ban.getHost(); + rpcBan.ip = ban.getIp(); + rpcBan.ban = ban.getIsBanned(); + rpcBan.seconds = ban.getSeconds(); + return rpcBan; + } + + protected static convertRpcMiningStatus(rpcStatus) { + let status = new MoneroMiningStatus(); + status.setIsActive(rpcStatus.active); + status.setSpeed(rpcStatus.speed); + status.setNumThreads(rpcStatus.threads_count); + if (rpcStatus.active) { + status.setAddress(rpcStatus.address); + status.setIsBackground(rpcStatus.is_background_mining_enabled); + } + return status; + } + + protected static convertRpcUpdateCheckResult(rpcResult) { + assert(rpcResult); + let result = new MoneroDaemonUpdateCheckResult(); + for (let key of Object.keys(rpcResult)) { + let val = rpcResult[key]; + if (key === "auto_uri") result.setAutoUri(val); + else if (key === "hash") result.setHash(val); + else if (key === "path") {} // handled elsewhere + else if (key === "status") {} // handled elsewhere + else if (key === "update") result.setIsUpdateAvailable(val); + else if (key === "user_uri") result.setUserUri(val); + else if (key === "version") result.setVersion(val); + else if (key === "untrusted") {} // handled elsewhere + else console.log("WARNING: ignoring unexpected field in rpc check update result: " + key + ": " + val); + } + if (result.getAutoUri() === "") result.setAutoUri(undefined); + if (result.getUserUri() === "") result.setUserUri(undefined); + if (result.getVersion() === "") result.setVersion(undefined); + if (result.getHash() === "") result.setHash(undefined); + return result; + } + + protected static convertRpcUpdateDownloadResult(rpcResult) { + let result = new MoneroDaemonUpdateDownloadResult(MoneroDaemonRpc.convertRpcUpdateCheckResult(rpcResult) as MoneroDaemonUpdateDownloadResult); + result.setDownloadPath(rpcResult["path"]); + if (result.getDownloadPath() === "") result.setDownloadPath(undefined); + return result; + } + + /** + * Converts a '0x' prefixed hexidecimal string to a bigint. + * + * @param {string} hex is the '0x' prefixed hexidecimal string to convert + * @return {bigint} the hexicedimal converted to decimal + */ + protected static prefixedHexToBI(hex) { + assert(hex.substring(0, 2) === "0x"); + return BigInt(hex); + } +} + +/** + * Implements a MoneroDaemon by proxying requests to a worker. + * + * @private + */ +class MoneroDaemonRpcProxy { + + // state variables + private daemonId: any; + private worker: any; + private wrappedListeners: any; + private process: any; + + constructor(daemonId, worker) { + this.daemonId = daemonId; + this.worker = worker; + this.wrappedListeners = []; + } + + // --------------------------- STATIC UTILITIES ----------------------------- + + static async connect(config: MoneroDaemonConfig) { + let daemonId = GenUtils.getUUID(); + config = Object.assign({}, config.toJson(), {proxyToWorker: false}); + await LibraryUtils.invokeWorker(daemonId, "connectDaemonRpc", [config]); + return new MoneroDaemonRpcProxy(daemonId, await LibraryUtils.getWorker()); + } + + // ---------------------------- INSTANCE METHODS ---------------------------- + + async addListener(listener) { + let wrappedListener = new DaemonWorkerListener(listener); + let listenerId = wrappedListener.getId(); + LibraryUtils.addWorkerCallback(this.daemonId, "onBlockHeader_" + listenerId, [wrappedListener.onBlockHeader, wrappedListener]); + this.wrappedListeners.push(wrappedListener); + return this.invokeWorker("daemonAddListener", [listenerId]); + } + + async removeListener(listener) { + for (let i = 0; i < this.wrappedListeners.length; i++) { + if (this.wrappedListeners[i].getListener() === listener) { + let listenerId = this.wrappedListeners[i].getId(); + await this.invokeWorker("daemonRemoveListener", [listenerId]); + LibraryUtils.removeWorkerCallback(this.daemonId, "onBlockHeader_" + listenerId); + this.wrappedListeners.splice(i, 1); + return; + } + } + throw new MoneroError("Listener is not registered with daemon"); + } + + async getListeners() { + let listeners = []; + for (let wrappedListener of this.wrappedListeners) listeners.push(wrappedListener.getListener()); + return listeners; + } + + async getRpcConnection() { + let config = await this.invokeWorker("daemonGetRpcConnection"); + return new MoneroRpcConnection(config as Partial); + } + + async isConnected() { + return this.invokeWorker("daemonIsConnected"); + } + + async getVersion() { + let versionJson: any = await this.invokeWorker("daemonGetVersion"); + return new MoneroVersion(versionJson.number, versionJson.isRelease); + } + + async isTrusted() { + return this.invokeWorker("daemonIsTrusted"); + } + + async getHeight() { + return this.invokeWorker("daemonGetHeight"); + } + + async getBlockHash(height) { + return this.invokeWorker("daemonGetBlockHash", Array.from(arguments)); + } + + async getBlockTemplate(walletAddress, reserveSize) { + return new MoneroBlockTemplate(await this.invokeWorker("daemonGetBlockTemplate", Array.from(arguments))); + } + + async getLastBlockHeader() { + return new MoneroBlockHeader(await this.invokeWorker("daemonGetLastBlockHeader")); + } + + async getBlockHeaderByHash(blockHash) { + return new MoneroBlockHeader(await this.invokeWorker("daemonGetBlockHeaderByHash", Array.from(arguments))); + } + + async getBlockHeaderByHeight(height) { + return new MoneroBlockHeader(await this.invokeWorker("daemonGetBlockHeaderByHeight", Array.from(arguments))); + } + + async getBlockHeadersByRange(startHeight, endHeight) { + let blockHeadersJson: any[] = await this.invokeWorker("daemonGetBlockHeadersByRange", Array.from(arguments)) as any[]; + let headers = []; + for (let blockHeaderJson of blockHeadersJson) headers.push(new MoneroBlockHeader(blockHeaderJson)); + return headers; + } + + async getBlockByHash(blockHash) { + return new MoneroBlock(await this.invokeWorker("daemonGetBlockByHash", Array.from(arguments)), MoneroBlock.DeserializationType.TX); + } + + async getBlocksByHash(blockHashes, startHeight, prune) { + let blocksJson: any[] = await this.invokeWorker("daemonGetBlocksByHash", Array.from(arguments)) as any[]; + let blocks = []; + for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson)); + return blocks; + } + + async getBlockByHeight(height) { + return new MoneroBlock(await this.invokeWorker("daemonGetBlockByHeight", Array.from(arguments)), MoneroBlock.DeserializationType.TX); + } + + async getBlocksByHeight(heights) { + let blocksJson: any[]= await this.invokeWorker("daemonGetBlocksByHeight", Array.from(arguments)) as any[]; + let blocks = []; + for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX)); + return blocks; + } + + async getBlocksByRange(startHeight, endHeight) { + let blocksJson: any[] = await this.invokeWorker("daemonGetBlocksByRange", Array.from(arguments)) as any[]; + let blocks = []; + for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX)); + return blocks; + } + + async getBlocksByRangeChunked(startHeight, endHeight, maxChunkSize) { + let blocksJson = await this.invokeWorker("daemonGetBlocksByRangeChunked", Array.from(arguments)) as any[]; + let blocks = []; + for (let blockJson of blocksJson) blocks.push(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX)); + return blocks; + } + + async getBlockHashes(blockHashes, startHeight) { + return this.invokeWorker("daemonGetBlockHashes", Array.from(arguments)); + } + + async getTxs(txHashes, prune = false) { + + // deserialize txs from blocks + let blocks = []; + for (let blockJson of await this.invokeWorker("daemonGetTxs", Array.from(arguments)) as any[]) { + blocks.push(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX)); + } + + // collect txs + let txs = []; + for (let block of blocks) { + for (let tx of block.getTxs()) { + if (!tx.getIsConfirmed()) tx.setBlock(undefined); + txs.push(tx); + } + } + return txs; + } + + async getTxHexes(txHashes, prune = false) { + return this.invokeWorker("daemonGetTxHexes", Array.from(arguments)); + } + + async getMinerTxSum(height, numBlocks) { + return new MoneroMinerTxSum(await this.invokeWorker("daemonGetMinerTxSum", Array.from(arguments))); + } + + async getFeeEstimate(graceBlocks?) { + return new MoneroFeeEstimate(await this.invokeWorker("daemonGetFeeEstimate", Array.from(arguments))); + } + + async submitTxHex(txHex, doNotRelay) { + return new MoneroSubmitTxResult(await this.invokeWorker("daemonSubmitTxHex", Array.from(arguments))); + } + + async relayTxsByHash(txHashes) { + return this.invokeWorker("daemonRelayTxsByHash", Array.from(arguments)); + } + + async getTxPool() { + let blockJson = await this.invokeWorker("daemonGetTxPool"); + let txs = new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX).getTxs(); + for (let tx of txs) tx.setBlock(undefined); + return txs ? txs : []; + } + + async getTxPoolHashes() { + return this.invokeWorker("daemonGetTxPoolHashes", Array.from(arguments)); + } + + async getTxPoolBacklog() { + throw new MoneroError("Not implemented"); + } + + async getTxPoolStats() { + return new MoneroTxPoolStats(await this.invokeWorker("daemonGetTxPoolStats")); + } + + async flushTxPool(hashes) { + return this.invokeWorker("daemonFlushTxPool", Array.from(arguments)); + } + + async getKeyImageSpentStatuses(keyImages) { + return this.invokeWorker("daemonGetKeyImageSpentStatuses", Array.from(arguments)); + } + + async getOutputs(outputs): Promise { + throw new MoneroError("Not implemented"); + } + + async getOutputHistogram(amounts, minCount, maxCount, isUnlocked, recentCutoff) { + let entries = []; + for (let entryJson of await this.invokeWorker("daemonGetOutputHistogram", [amounts, minCount, maxCount, isUnlocked, recentCutoff]) as any[]) { + entries.push(new MoneroOutputHistogramEntry(entryJson)); + } + return entries; + } + + async getOutputDistribution(amounts, cumulative, startHeight, endHeight) { + throw new MoneroError("Not implemented"); + } + + async getInfo() { + return new MoneroDaemonInfo(await this.invokeWorker("daemonGetInfo")); + } + + async getSyncInfo() { + return new MoneroDaemonSyncInfo(await this.invokeWorker("daemonGetSyncInfo")); + } + + async getHardForkInfo() { + return new MoneroHardForkInfo(await this.invokeWorker("daemonGetHardForkInfo")); + } + + async getAltChains() { + let altChains = []; + for (let altChainJson of await this.invokeWorker("daemonGetAltChains") as any) altChains.push(new MoneroAltChain(altChainJson)); + return altChains; + } + + async getAltBlockHashes() { + return this.invokeWorker("daemonGetAltBlockHashes"); + } + + async getDownloadLimit() { + return this.invokeWorker("daemonGetDownloadLimit"); + } + + async setDownloadLimit(limit) { + return this.invokeWorker("daemonSetDownloadLimit", Array.from(arguments)); + } + + async resetDownloadLimit() { + return this.invokeWorker("daemonResetDownloadLimit"); + } + + async getUploadLimit() { + return this.invokeWorker("daemonGetUploadLimit"); + } + + async setUploadLimit(limit) { + return this.invokeWorker("daemonSetUploadLimit", Array.from(arguments)); + } + + async resetUploadLimit() { + return this.invokeWorker("daemonResetUploadLimit"); + } + + async getPeers() { + let peers = []; + for (let peerJson of await this.invokeWorker("daemonGetPeers") as any) peers.push(new MoneroPeer(peerJson)); + return peers; + } + + async getKnownPeers() { + let peers = []; + for (let peerJson of await this.invokeWorker("daemonGetKnownPeers") as any) peers.push(new MoneroPeer(peerJson)); + return peers; + } + + async setOutgoingPeerLimit(limit) { + return this.invokeWorker("daemonSetIncomingPeerLimit", Array.from(arguments)); + } + + async setIncomingPeerLimit(limit) { + return this.invokeWorker("daemonSetIncomingPeerLimit", Array.from(arguments)); + } + + async getPeerBans() { + let bans = []; + for (let banJson of await this.invokeWorker("daemonGetPeerBans") as any) bans.push(new MoneroBan(banJson)); + return bans; + } + + async setPeerBans(bans) { + let bansJson = []; + for (let ban of bans) bansJson.push(ban.toJson()); + return this.invokeWorker("daemonSetPeerBans", [bansJson]); + } + + async startMining(address, numThreads, isBackground, ignoreBattery) { + return this.invokeWorker("daemonStartMining", Array.from(arguments)); + } + + async stopMining() { + await this.invokeWorker("daemonStopMining") + } + + async getMiningStatus() { + return new MoneroMiningStatus(await this.invokeWorker("daemonGetMiningStatus")); + } + + async submitBlocks(blockBlobs) { + return this.invokeWorker("daemonSubmitBlocks", Array.from(arguments)); + } + + async pruneBlockchain(check) { + return new MoneroPruneResult(await this.invokeWorker("daemonPruneBlockchain")); + } + + async checkForUpdate(): Promise { + throw new MoneroError("Not implemented"); + } + + async downloadUpdate(path): Promise { + throw new MoneroError("Not implemented"); + } + + async stop() { + while (this.wrappedListeners.length) await this.removeListener(this.wrappedListeners[0].getListener()); + return this.invokeWorker("daemonStop"); + } + + async waitForNextBlockHeader() { + return new MoneroBlockHeader(await this.invokeWorker("daemonWaitForNextBlockHeader")); + } + + // --------------------------- PRIVATE HELPERS ------------------------------ + + // TODO: duplicated with MoneroWalletFullProxy + protected async invokeWorker(fnName: string, args?: any) { + return LibraryUtils.invokeWorker(this.daemonId, fnName, args); + } +} + +/** + * Polls a Monero daemon for updates and notifies listeners as they occur. + * + * @private + */ +class DaemonPoller { + + protected daemon: MoneroDaemonRpc; + protected looper: TaskLooper; + protected isPolling: boolean; + protected lastHeader: MoneroBlockHeader; + + constructor(daemon) { + let that = this; + this.daemon = daemon; + this.looper = new TaskLooper(async function() { await that.poll(); }); + } + + setIsPolling(isPolling: boolean) { + this.isPolling = isPolling; + if (isPolling) this.looper.start(this.daemon.getPollInterval()); + else this.looper.stop(); + } + + async poll() { + try { + + // get latest block header + let header = await this.daemon.getLastBlockHeader(); + + // save first header for comparison + if (!this.lastHeader) { + this.lastHeader = await this.daemon.getLastBlockHeader(); + return; + } + + // compare header to last + if (header.getHash() !== this.lastHeader.getHash()) { + this.lastHeader = header; + await this.announceBlockHeader(header); + } + } catch (err) { + console.error("Failed to background poll daemon header"); + console.error(err); + } + } + + protected async announceBlockHeader(header: MoneroBlockHeader) { + for (let listener of await this.daemon.getListeners()) { + try { + await listener.onBlockHeader(header); // notify listener + } catch (err) { + console.error("Error calling listener on block header", err); + } + } + } +} + +/** + * Internal listener to bridge notifications to external listeners. + * + * @private + */ +class DaemonWorkerListener { + + protected id: any; + protected listener: any; + + constructor(listener) { + this.id = GenUtils.getUUID(); + this.listener = listener; + } + + getId() { + return this.id; + } + + getListener() { + return this.listener; + } + + async onBlockHeader(headerJson) { + this.listener.onBlockHeader(new MoneroBlockHeader(headerJson)); + } +} + +export default MoneroDaemonRpc; diff --git a/src/main/ts/daemon/model/ConnectionType.ts b/src/main/ts/daemon/model/ConnectionType.ts new file mode 100644 index 000000000..c258ca9f3 --- /dev/null +++ b/src/main/ts/daemon/model/ConnectionType.ts @@ -0,0 +1,36 @@ +import assert from "assert"; + +/** + * Enumerates connection types. + * + * Based on enums.h in monero-project. + */ +enum ConnectionType { + + /** + * Invalid connection type (value=0). + */ + INVALID = 0, + + /** + * IPV4 connection type (value=1). + */ + IPV4 = 1, + + /** + * IPV6 connection type (value=2). + */ + IPV6 = 2, + + /** + * TOR connection type (value=3). + */ + TOR = 3, + + /** + * I2P connection type (value=4). + */ + I2P = 4 +} + +export default ConnectionType; \ No newline at end of file diff --git a/src/main/ts/daemon/model/MoneroAltChain.ts b/src/main/ts/daemon/model/MoneroAltChain.ts new file mode 100644 index 000000000..a1e9be47d --- /dev/null +++ b/src/main/ts/daemon/model/MoneroAltChain.ts @@ -0,0 +1,67 @@ +/** + * Models an alternative chain seen by the node. + */ +export default class MoneroAltChain { + + blockHashes: string[]; + difficulty: bigint; + height: number; + length: number; + mainChainParentBlockHash: string; + + constructor(altChain?: Partial) { + Object.assign(this, altChain); + if (this.difficulty !== undefined && typeof this.difficulty !== "bigint") this.difficulty = BigInt(this.difficulty); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (this.getDifficulty() !== undefined) json.difficulty = this.getDifficulty().toString(); + return json; + } + + getBlockHashes(): string[] { + return this.blockHashes; + } + + setBlockHashes(blockHashes: string[]): MoneroAltChain { + this.blockHashes = blockHashes; + return this; + } + + getDifficulty(): bigint { + return this.difficulty; + } + + setDifficulty(difficulty: bigint): MoneroAltChain { + this.difficulty = difficulty; + return this; + } + + getHeight(): number { + return this.height; + } + + setHeight(height: number): MoneroAltChain { + this.height = height; + return this; + } + + getLength(): number { + return this.length; + } + + setLength(length: number): MoneroAltChain { + this.length = length; + return this; + } + + getMainChainParentBlockHash(): string { + return this.mainChainParentBlockHash; + } + + setMainChainParentBlockHash(mainChainParentBlockHash: string): MoneroAltChain { + this.mainChainParentBlockHash = mainChainParentBlockHash; + return this; + } +} diff --git a/src/main/ts/daemon/model/MoneroBan.ts b/src/main/ts/daemon/model/MoneroBan.ts new file mode 100644 index 000000000..8b333b170 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroBan.ts @@ -0,0 +1,54 @@ +/** + * Monero banhammer. + */ +export default class MoneroBan { + + host: string; + ip: string; + isBanned: boolean; + seconds: number; + + constructor(ban?: Partial) { + Object.assign(this, ban); + } + + toJson(): any { + return Object.assign({}, this); + } + + getHost(): string { + return this.host; + } + + setHost(host: string): MoneroBan { + this.host = host; + return this; + } + + getIp(): string { + return this.ip; + } + + setIp(ip: string): MoneroBan { + this.ip = ip; + return this; + } + + getIsBanned(): boolean { + return this.isBanned; + } + + setIsBanned(isBanned: boolean): MoneroBan { + this.isBanned = isBanned; + return this; + } + + getSeconds(): number { + return this.seconds; + } + + setSeconds(seconds: number): MoneroBan { + this.seconds = seconds; + return this; + } +} diff --git a/src/main/ts/daemon/model/MoneroBlock.ts b/src/main/ts/daemon/model/MoneroBlock.ts new file mode 100644 index 000000000..d07663d14 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroBlock.ts @@ -0,0 +1,254 @@ +import assert from "assert"; +import GenUtils from "../../common/GenUtils"; +import MoneroBlockHeader from "./MoneroBlockHeader"; +import MoneroTx from "./MoneroTx"; +import MoneroTxQuery from "../../wallet/model/MoneroTxQuery"; +import MoneroTxWallet from "../../wallet/model/MoneroTxWallet"; + +/** + * Enumerates types to deserialize to. + */ +enum DeserializationType { + TX = 0, + TX_WALLET = 1, + TX_QUERY = 2 +} + +/** + * Models a Monero block in the blockchain. + */ +export default class MoneroBlock extends MoneroBlockHeader { + + static DeserializationType = DeserializationType; + + hex: string; + minerTx: MoneroTx; + txs: MoneroTx[]; + txHashes: string[]; + + constructor(block?: Partial, txType?: DeserializationType) { + super(block); + + // copy miner tx + if (this.minerTx) { + this.minerTx = this.deserializeTx(this.minerTx, txType).setBlock(this); + } + + // copy non-miner txs + if (this.txs) { + this.txs = this.txs.slice(); + for (let i = 0; i < this.txs.length; i++) { + this.txs[i] = this.deserializeTx(this.txs[i], txType).setBlock(this); + } + } + } + + getHex(): string { + return this.hex; + } + + setHex(hex: string): MoneroBlock { + this.hex = hex; + return this; + } + + getMinerTx(): MoneroTx { + return this.minerTx; + } + + setMinerTx(minerTx: MoneroTx): MoneroBlock { + this.minerTx = minerTx; + return this; + } + + getTxs(): MoneroTx[] { + return this.txs; + } + + setTxs(txs: MoneroTx[]): MoneroBlock { + this.txs = txs; + return this; + } + + getTxHashes(): string[] { + return this.txHashes; + } + + setTxHashes(txHashes: string[]): MoneroBlock { + this.txHashes = txHashes; + return this; + } + + copy(): MoneroBlock { + return new MoneroBlock(this); + } + + toJson(): any { + let json = super.toJson(); + if (this.getMinerTx() !== undefined) json.minerTx = this.getMinerTx().toJson(); + if (this.getTxs() !== undefined) { + json.txs = []; + for (let tx of this.getTxs()) json.txs.push(tx.toJson()); + } + return json; + } + + merge(block: MoneroBlock): MoneroBlock { + assert(block instanceof MoneroBlock); + if (this === block) return this; + + // merge header fields + super.merge(block); + + // merge reconcilable block extensions + this.setHex(GenUtils.reconcile(this.getHex(), block.getHex())); + this.setTxHashes(GenUtils.reconcile(this.getTxHashes(), block.getTxHashes())); + + // merge miner tx + if (this.getMinerTx() === undefined) this.setMinerTx(block.getMinerTx()); + if (block.getMinerTx() !== undefined) { + block.getMinerTx().setBlock(this); + this.getMinerTx().merge(block.getMinerTx()); + } + + // merge non-miner txs + if (block.getTxs() !== undefined) { + for (let tx of block.getTxs()) { + tx.setBlock(this); + MoneroBlock.mergeTx(this.getTxs(), tx); + } + } + + return this; + } + + toString(indent = 0): string { + let str = super.toString(indent) + "\n"; + str += GenUtils.kvLine("Hex", this.getHex(), indent); + if (this.getTxs() !== undefined) { + str += GenUtils.kvLine("Txs", "", indent); + for (let tx of this.getTxs()) { + str += tx.toString(indent + 1) + "\n"; + } + } + if (this.getMinerTx() !== undefined) { + str += GenUtils.kvLine("Miner tx", "", indent); + str += this.getMinerTx().toString(indent + 1) + "\n"; + } + str += GenUtils.kvLine("Txs hashes", this.getTxHashes(), indent); + return str[str.length - 1] === "\n" ? str.slice(0, str.length - 1) : str // strip last newline + } + + // helper to merge txs + protected static mergeTx(txs, tx) { + for (let aTx of txs) { + if (aTx.getHash() === tx.getHash()) { + aTx.merge(tx); + return; + } + } + txs.push(tx); + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setHeight(height: number): MoneroBlock { + super.setHeight(height); + return this; + } + + setTimestamp(timestamp: number): MoneroBlock { + super.setTimestamp(timestamp); + return this; + } + + setSize(size: number): MoneroBlock { + super.setSize(size); + return this; + } + + setWeight(weight: number): MoneroBlock { + super.setWeight(weight); + return this; + } + + setLongTermWeight(longTermWeight: number): MoneroBlock { + super.setLongTermWeight(longTermWeight); + return this; + } + + setDepth(depth: number): MoneroBlock { + super.setDepth(depth); + return this; + } + + setDifficulty(difficulty: bigint): MoneroBlock { + super.setDifficulty(difficulty); + return this; + } + + setCumulativeDifficulty(cumulativeDifficulty: bigint): MoneroBlock { + super.setCumulativeDifficulty(cumulativeDifficulty); + return this; + } + + setMajorVersion(majorVersion: number): MoneroBlock { + super.setMajorVersion(majorVersion); + return this; + } + + setMinorVersion(minorVersion: number): MoneroBlock { + super.setMinorVersion(minorVersion); + return this; + } + + setNonce(nonce: number): MoneroBlock { + super.setNonce(nonce); + return this; + } + + setMinerTxHash(minerTxHash: string): MoneroBlock { + super.setMinerTxHash(minerTxHash); + return this; + } + + setNumTxs(numTxs: number): MoneroBlock { + super.setNumTxs(numTxs); + return this; + } + + setOrphanStatus(orphanStatus: boolean): MoneroBlock { + super.setOrphanStatus(orphanStatus); + return this; + } + + setPrevHash(prevHash: string): MoneroBlock { + super.setPrevHash(prevHash); + return this; + } + + setReward(reward: bigint): MoneroBlock { + super.setReward(reward); + return this; + } + + setPowHash(powHash: string): MoneroBlock { + super.setPowHash(powHash); + return this; + } + + protected deserializeTx(tx: any, txType?: DeserializationType): MoneroTx { + if (txType === undefined) { + if (!(tx instanceof MoneroTx)) throw new Error("Must provide DeserializationType if tx is not instanceof MoneroTx"); + return tx.copy(); + } else if (txType === MoneroBlock.DeserializationType.TX || txType === undefined) { + return new MoneroTx(tx); + } else if (txType === MoneroBlock.DeserializationType.TX_WALLET) { + return new MoneroTxWallet(tx); + } else if (txType === MoneroBlock.DeserializationType.TX_QUERY) { + return new MoneroTxQuery(tx); + } else { + throw new Error("Unrecognized tx deserialization type: " + txType); + } + } +} diff --git a/src/main/js/daemon/model/MoneroBlockHeader.js b/src/main/ts/daemon/model/MoneroBlockHeader.ts similarity index 51% rename from src/main/js/daemon/model/MoneroBlockHeader.js rename to src/main/ts/daemon/model/MoneroBlockHeader.ts index 078c2658b..52d90dcc0 100644 --- a/src/main/js/daemon/model/MoneroBlockHeader.js +++ b/src/main/ts/daemon/model/MoneroBlockHeader.ts @@ -1,52 +1,57 @@ -const assert = require("assert"); -const BigInteger = require("../../common/biginteger").BigInteger; -const GenUtils = require("../../common/GenUtils"); +import assert from "assert"; +import GenUtils from "../../common/GenUtils"; /** * Models a Monero block header which contains information about the block. - * - * @class */ -class MoneroBlockHeader { +export default class MoneroBlockHeader { + + hash: string; + height: number; + timestamp: number; + size: number; + weight: number; + longTermWeight: number; + depth: number; + difficulty: bigint; + cumulativeDifficulty: bigint; + majorVersion: number; + minorVersion: number; + nonce: number; + minerTxHash: string; + numTxs: number; + orphanStatus: boolean; + prevHash: string; + reward: bigint; + powHash: string; + + constructor(header?: Partial) { + Object.assign(this, header); + + // deserialize bigints + if (this.difficulty !== undefined && typeof this.difficulty !== "bigint") this.difficulty = BigInt(this.difficulty); + if (this.cumulativeDifficulty !== undefined && typeof this.cumulativeDifficulty !== "bigint") this.cumulativeDifficulty = BigInt(this.cumulativeDifficulty); + if (this.reward !== undefined && typeof this.reward !== "bigint") this.reward = BigInt(this.reward); + } - /** - * Construct the model. - * - * @param {MoneroBlockHeader|object} state is existing state to initialize from (optional) - */ - constructor(state) { - - // initialize internal state - if (!state) state = {}; - else if (state instanceof MoneroBlockHeader) state = state.toJson(); - else if (typeof state === "object") state = Object.assign({}, state); - else throw new MoneroError("state must be a MoneroBlockHeader or JavaScript object"); - this.state = state; - - // deserialize BigIntegers - if (state.difficulty !== undefined && !(state.difficulty instanceof BigInteger)) state.difficulty = BigInteger.parse(state.difficulty); - if (state.cumulativeDifficulty !== undefined && !(state.cumulativeDifficulty instanceof BigInteger)) state.cumulativeDifficulty = BigInteger.parse(state.cumulativeDifficulty); - if (state.reward !== undefined && !(state.reward instanceof BigInteger)) state.reward = BigInteger.parse(state.reward); - } - - copy() { + copy(): MoneroBlockHeader { return new MoneroBlockHeader(this); } toJson() { - let json = Object.assign({}, this.state); - if (this.getDifficulty()) json.difficulty = this.getDifficulty().toString(); - if (this.getCumulativeDifficulty()) json.cumulativeDifficulty = this.getCumulativeDifficulty().toString(); - if (this.getReward()) json.reward = this.getReward().toString(); + let json: any = Object.assign({}, this); + if (this.getDifficulty() !== undefined) json.difficulty = this.getDifficulty().toString(); + if (this.getCumulativeDifficulty() !== undefined) json.cumulativeDifficulty = this.getCumulativeDifficulty().toString(); + if (this.getReward() !== undefined) json.reward = this.getReward().toString(); return json; } getHash() { - return this.state.hash; + return this.hash; } - setHash(hash) { - this.state.hash = hash; + setHash(hash: string) { + this.hash = hash; return this; } @@ -55,8 +60,8 @@ class MoneroBlockHeader { * * @return {number} the block's height */ - getHeight() { - return this.state.height; + getHeight(): number { + return this.height; } /** @@ -65,156 +70,156 @@ class MoneroBlockHeader { * @param {number} height is the block's height to set * @return {MoneroBlockHeader} a reference to this header for chaining */ - setHeight(height) { - this.state.height = height; + setHeight(height: number): MoneroBlockHeader { + this.height = height; return this; } - getTimestamp() { - return this.state.timestamp; + getTimestamp(): number { + return this.timestamp; } - setTimestamp(timestamp) { - this.state.timestamp = timestamp; + setTimestamp(timestamp): MoneroBlockHeader { + this.timestamp = timestamp; return this; } - getSize() { - return this.state.size; + getSize(): number { + return this.size; } - setSize(size) { - this.state.size = size; + setSize(size: number): MoneroBlockHeader { + this.size = size; return this; } - getWeight() { - return this.state.weight; + getWeight(): number { + return this.weight; } - setWeight(weight) { - this.state.weight = weight; + setWeight(weight: number): MoneroBlockHeader { + this.weight = weight; return this; } - getLongTermWeight() { - return this.state.longTermWeight; + getLongTermWeight(): number { + return this.longTermWeight; } - setLongTermWeight(longTermWeight) { - this.state.longTermWeight = longTermWeight; + setLongTermWeight(longTermWeight: number): MoneroBlockHeader { + this.longTermWeight = longTermWeight; return this; } - getDepth() { - return this.state.depth; + getDepth(): number { + return this.depth; } - setDepth(depth) { - this.state.depth = depth; + setDepth(depth: number): MoneroBlockHeader { + this.depth = depth; return this; } - getDifficulty() { - return this.state.difficulty; + getDifficulty(): bigint { + return this.difficulty; } - setDifficulty(difficulty) { - this.state.difficulty = difficulty; + setDifficulty(difficulty: bigint): MoneroBlockHeader { + this.difficulty = difficulty; return this; } - getCumulativeDifficulty() { - return this.state.cumulativeDifficulty; + getCumulativeDifficulty(): bigint { + return this.cumulativeDifficulty; } - setCumulativeDifficulty(cumulativeDifficulty) { - this.state.cumulativeDifficulty = cumulativeDifficulty; + setCumulativeDifficulty(cumulativeDifficulty: bigint): MoneroBlockHeader { + this.cumulativeDifficulty = cumulativeDifficulty; return this; } - getMajorVersion() { - return this.state.majorVersion; + getMajorVersion(): number { + return this.majorVersion; } - setMajorVersion(majorVersion) { - this.state.majorVersion = majorVersion; + setMajorVersion(majorVersion: number): MoneroBlockHeader { + this.majorVersion = majorVersion; return this; } - getMinorVersion() { - return this.state.minorVersion; + getMinorVersion(): number { + return this.minorVersion; } - setMinorVersion(minorVersion) { - this.state.minorVersion = minorVersion; + setMinorVersion(minorVersion: number): MoneroBlockHeader { + this.minorVersion = minorVersion; return this; } - getNonce() { - return this.state.nonce; + getNonce(): number { + return this.nonce; } - setNonce(nonce) { - this.state.nonce = nonce; + setNonce(nonce: number): MoneroBlockHeader { + this.nonce = nonce; return this; } - getMinerTxHash() { - return this.state.minerTxHash; + getMinerTxHash(): string { + return this.minerTxHash; } - setMinerTxHash(minerTxHash) { - this.state.minerTxHash = minerTxHash; + setMinerTxHash(minerTxHash: string): MoneroBlockHeader { + this.minerTxHash = minerTxHash; return this; } - getNumTxs() { - return this.state.numTxs; + getNumTxs(): number { + return this.numTxs; } - setNumTxs(numTxs) { - this.state.numTxs = numTxs; + setNumTxs(numTxs: number): MoneroBlockHeader { + this.numTxs = numTxs; return this; } - getOrphanStatus() { - return this.state.orphanStatus; + getOrphanStatus(): boolean { + return this.orphanStatus; } - setOrphanStatus(orphanStatus) { - this.state.orphanStatus = orphanStatus; + setOrphanStatus(orphanStatus: boolean): MoneroBlockHeader { + this.orphanStatus = orphanStatus; return this; } - getPrevHash() { - return this.state.prevHash; + getPrevHash(): string { + return this.prevHash; } - setPrevHash(prevHash) { - this.state.prevHash = prevHash; + setPrevHash(prevHash: string): MoneroBlockHeader { + this.prevHash = prevHash; return this; } - getReward() { - return this.state.reward; + getReward(): bigint { + return this.reward; } - setReward(reward) { - this.state.reward = reward; + setReward(reward: bigint): MoneroBlockHeader { + this.reward = reward; return this; } - getPowHash() { - return this.state.powHash; + getPowHash(): string { + return this.powHash; } - setPowHash(powHash) { - this.state.powHash = powHash; + setPowHash(powHash: string): MoneroBlockHeader { + this.powHash = powHash; return this; } - merge(header) { + merge(header: MoneroBlockHeader): MoneroBlockHeader { assert(header instanceof MoneroBlockHeader); if (this === header) return this; this.setHash(GenUtils.reconcile(this.getHash(), header.getHash())); @@ -258,6 +263,4 @@ class MoneroBlockHeader { str += GenUtils.kvLine("Pow hash", this.getPowHash(), indent); return str[str.length - 1] === "\n" ? str.slice(0, str.length - 1) : str // strip last newline } -} - -module.exports = MoneroBlockHeader; \ No newline at end of file +} \ No newline at end of file diff --git a/src/main/ts/daemon/model/MoneroBlockTemplate.ts b/src/main/ts/daemon/model/MoneroBlockTemplate.ts new file mode 100644 index 000000000..7b630c1a3 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroBlockTemplate.ts @@ -0,0 +1,119 @@ +/** + * Monero block template to mine. + */ +export default class MoneroBlockTemplate { + + blockTemplateBlob: string; + blockHashingBlob: string; + difficulty: bigint; + expectedReward: bigint; + height: number; + prevId: string; + reservedOffset: number; + seedHeight: number; + seedHash: string; + nextSeedHash: string; + + constructor(template?: Partial) { + Object.assign(this, template); + if (this.expectedReward !== undefined && typeof this.expectedReward !== "bigint") this.expectedReward = BigInt(this.expectedReward); + if (this.difficulty !== undefined && typeof this.difficulty !== "bigint") this.difficulty = BigInt(this.difficulty); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (this.getExpectedReward() !== undefined) json.expectedReward = this.getExpectedReward().toString(); + if (this.getDifficulty() !== undefined) json.difficulty = this.getDifficulty().toString(); + return json; + } + + getBlockTemplateBlob(): string { + return this.blockTemplateBlob; + } + + setBlockTemplateBlob(blockTemplateBlob: string): MoneroBlockTemplate { + this.blockTemplateBlob = blockTemplateBlob; + return this; + } + + getBlockHashingBlob(): string { + return this.blockHashingBlob; + } + + setBlockHashingBlob(blockHashingBlob: string): MoneroBlockTemplate { + this.blockHashingBlob = blockHashingBlob; + return this; + } + + getDifficulty(): bigint { + return this.difficulty; + } + + setDifficulty(difficulty: bigint): MoneroBlockTemplate { + this.difficulty = difficulty; + return this; + } + + getExpectedReward(): bigint { + return this.expectedReward; + } + + setExpectedReward(expectedReward: bigint): MoneroBlockTemplate { + this.expectedReward = expectedReward; + return this; + } + + getHeight(): number { + return this.height; + } + + setHeight(height: number): MoneroBlockTemplate { + this.height = height; + return this; + } + + getPrevHash(): string { + return this.prevId; + } + + setPrevHash(prevId: string): MoneroBlockTemplate { + this.prevId = prevId; + return this; + } + + getReservedOffset(): number { + return this.reservedOffset; + } + + setReservedOffset(reservedOffset: number): MoneroBlockTemplate { + this.reservedOffset = reservedOffset; + return this; + } + + getSeedHeight(): number { + return this.height; + } + + setSeedHeight(seedHeight: number): MoneroBlockTemplate { + this.seedHeight = seedHeight; + return this; + } + + getSeedHash(): string { + return this.seedHash; + } + + setSeedHash(seedHash: string): MoneroBlockTemplate { + this.seedHash = seedHash; + return this; + } + + getNextSeedHash(): string { + return this.nextSeedHash + } + + setNextSeedHash(nextSeedHash: string): MoneroBlockTemplate { + this.nextSeedHash = nextSeedHash; + return this; + } +} \ No newline at end of file diff --git a/src/main/ts/daemon/model/MoneroConnectionSpan.ts b/src/main/ts/daemon/model/MoneroConnectionSpan.ts new file mode 100644 index 000000000..e523eaa3f --- /dev/null +++ b/src/main/ts/daemon/model/MoneroConnectionSpan.ts @@ -0,0 +1,84 @@ +/** + * Monero daemon connection span. + */ +export default class MoneroConnectionSpan { + + connectionId: string; + numBlocks: number; + remoteAddress: string; + rate: number; + speed: number; + size: number; + startHeight: number; + + constructor(span?: any) { + Object.assign(this, span); + } + + toJson(): any { + return Object.assign({}, this); + } + + getConnectionId(): string { + return this.connectionId; + } + + setConnectionId(connectionId: string): MoneroConnectionSpan { + this.connectionId = connectionId; + return this; + } + + getNumBlocks(): number { + return this.numBlocks; + } + + setNumBlocks(numBlocks: number): MoneroConnectionSpan { + this.numBlocks = numBlocks; + return this; + } + + getRemoteAddress(): string { + return this.remoteAddress; + } + + setRemoteAddress(remoteAddress: string): MoneroConnectionSpan { + this.remoteAddress = remoteAddress; + return this; + } + + getRate(): number { + return this.rate; + } + + setRate(rate: number): MoneroConnectionSpan { + this.rate = rate; + return this; + } + + getSpeed(): number { + return this.speed; + } + + setSpeed(speed: number): MoneroConnectionSpan { + this.speed = speed; + return this; + } + + getSize(): number { + return this.size; + } + + setSize(size: number): MoneroConnectionSpan { + this.size = size; + return this; + } + + getStartHeight(): number { + return this.startHeight; + } + + setStartHeight(startHeight: number): MoneroConnectionSpan { + this.startHeight = startHeight; + return this; + } +} diff --git a/src/main/ts/daemon/model/MoneroDaemonConfig.ts b/src/main/ts/daemon/model/MoneroDaemonConfig.ts new file mode 100644 index 000000000..a5efe711c --- /dev/null +++ b/src/main/ts/daemon/model/MoneroDaemonConfig.ts @@ -0,0 +1,81 @@ +import MoneroRpcConnection from "../../common/MoneroRpcConnection"; + +/** + * Configuration to connect to monerod. + */ +export default class MoneroDaemonConfig { + + /** Server config to monerod. */ + server: string | Partial; + + /** Proxy requests to monerod to a worker (default true). */ + proxyToWorker: boolean; + + /** Command to start monerod as a child process. */ + cmd: string[]; + + /** Interval in milliseconds to poll the daemon for updates (default 20000). */ + pollInterval: number; + + /** + * Construct a configuration to open or create a wallet. + * + * @param {Partial} [config] - MoneroDaemonConfig to construct from (optional) + * @param {string|Partial} [config.server] - uri or MoneroRpcConnection to the daemon (optional) + * @param {boolean} [config.proxyToWorker] - proxy daemon requests to a worker (default true) + * @param {string[]} [config.cmd] - command to start monerod (optional) + * @param {number} [config.pollInterval] - interval in milliseconds to poll the daemon for updates (default 20000) + */ + constructor(config?: Partial) { + Object.assign(this, config); + if (this.server) this.setServer(this.server); + this.setProxyToWorker(this.proxyToWorker); + } + + copy(): MoneroDaemonConfig { + return new MoneroDaemonConfig(this); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (json.server) json.server = json.server.toJson(); + return json; + } + + getServer(): MoneroRpcConnection { + return this.server as MoneroRpcConnection; + } + + setServer(server: Partial | string): MoneroDaemonConfig { + if (server && !(server instanceof MoneroRpcConnection)) server = new MoneroRpcConnection(server); + this.server = server as MoneroRpcConnection; + return this; + } + + getProxyToWorker(): boolean { + return this.proxyToWorker; + } + + setProxyToWorker(proxyToWorker: boolean): MoneroDaemonConfig { + this.proxyToWorker = proxyToWorker; + return this; + } + + getCmd(): string[] { + return this.cmd; + } + + setCmd(cmd: string[]): MoneroDaemonConfig { + this.cmd = cmd; + return this; + } + + getPollInterval(): number { + return this.pollInterval; + } + + setPollInterval(pollInterval: number): MoneroDaemonConfig { + this.pollInterval = pollInterval; + return this; + } +} \ No newline at end of file diff --git a/src/main/ts/daemon/model/MoneroDaemonInfo.ts b/src/main/ts/daemon/model/MoneroDaemonInfo.ts new file mode 100644 index 000000000..512176d72 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroDaemonInfo.ts @@ -0,0 +1,353 @@ +/** + * Monero daemon info. + */ +export default class MoneroDaemonInfo { + + version: string; + numAltBlocks: number; + blockSizeLimit: number; + blockSizeMedian: number; + blockWeightLimit: number; + blockWeightMedian: number; + bootstrapDaemonAddress: string; + difficulty: bigint; + cumulativeDifficulty: bigint; + freeSpace: bigint; + numOfflinePeers: number; + numOnlinePeers: number; + height: number; + heightWithoutBootstrap: number; + networkType: string; + isOffline: boolean; + numIncomingConnections: number; + numOutgoingConnections: number; + numRpcConnections: number; + startTimestamp: number; + adjustedTimestamp: number; + target: number; + targetHeight: number; + topBlockHash: string; + numTxs: number; + numTxsPool: number; + wasBootstrapEverUsed: boolean; + databaseSize: number; + updateAvailable: boolean; + credits: bigint; + isBusySyncing: boolean; + isSynchronized: boolean; + isRestricted: boolean; + + constructor(info?: Partial) { + Object.assign(this, info); + + // deserialize bigints + if (this.difficulty !== undefined && typeof this.difficulty !== "bigint") this.difficulty = BigInt(this.difficulty); + if (this.cumulativeDifficulty !== undefined && typeof this.cumulativeDifficulty !== "bigint") this.cumulativeDifficulty = BigInt(this.cumulativeDifficulty); + if (this.credits !== undefined && typeof this.credits !== "bigint") this.credits = BigInt(this.credits); + } + + toJson(): any { + let json: any = Object.assign([], this); + if (json.difficulty !== undefined) json.difficulty = json.difficulty.toString(); + if (json.cumulativeDifficulty !== undefined) json.cumulativeDifficulty = json.cumulativeDifficulty.toString(); + if (json.credits !== undefined) json.credits = json.credits.toString(); + return json; + } + + getVersion(): string { + return this.version; + } + + setVersion(version: string): MoneroDaemonInfo { + this.version = version; + return this; + } + + getNumAltBlocks(): number { + return this.numAltBlocks; + } + + setNumAltBlocks(numAltBlocks: number): MoneroDaemonInfo { + this.numAltBlocks = numAltBlocks; + return this; + } + + getBlockSizeLimit(): number { + return this.blockSizeLimit; + } + + setBlockSizeLimit(blockSizeLimit: number): MoneroDaemonInfo { + this.blockSizeLimit = blockSizeLimit; + return this; + } + + getBlockSizeMedian(): number { + return this.blockSizeMedian; + } + + setBlockSizeMedian(blockSizeMedian: number): MoneroDaemonInfo { + this.blockSizeMedian = blockSizeMedian; + return this; + } + + getBlockWeightLimit(): number { + return this.blockWeightLimit; + } + + setBlockWeightLimit(blockWeightLimit: number): MoneroDaemonInfo { + this.blockWeightLimit = blockWeightLimit; + return this; + } + + getBlockWeightMedian(): number { + return this.blockWeightMedian; + } + + setBlockWeightMedian(blockWeightMedian: number): MoneroDaemonInfo { + this.blockWeightMedian = blockWeightMedian; + return this; + } + + getBootstrapDaemonAddress(): string { + return this.bootstrapDaemonAddress; + } + + setBootstrapDaemonAddress(bootstrapDaemonAddress): MoneroDaemonInfo { + this.bootstrapDaemonAddress = bootstrapDaemonAddress; + return this; + } + + getDifficulty(): bigint { + return this.difficulty; + } + + setDifficulty(difficulty: bigint): MoneroDaemonInfo { + this.difficulty = difficulty; + return this; + } + + getCumulativeDifficulty(): bigint { + return this.cumulativeDifficulty; + } + + setCumulativeDifficulty(cumulativeDifficulty: bigint): MoneroDaemonInfo { + this.cumulativeDifficulty = cumulativeDifficulty; + return this; + } + + getFreeSpace(): bigint { + return this.freeSpace; + } + + setFreeSpace(freeSpace: bigint): MoneroDaemonInfo { + this.freeSpace = freeSpace; + return this; + } + + getNumOfflinePeers(): number { + return this.numOfflinePeers; + } + + setNumOfflinePeers(numOfflinePeers: number): MoneroDaemonInfo { + this.numOfflinePeers = numOfflinePeers; + return this; + } + + getNumOnlinePeers(): number { + return this.numOnlinePeers; + } + + setNumOnlinePeers(numOnlinePeers: number): MoneroDaemonInfo { + this.numOnlinePeers = numOnlinePeers; + return this; + } + + getHeight(): number { + return this.height; + } + + setHeight(height: number): MoneroDaemonInfo { + this.height = height; + return this; + } + + getHeightWithoutBootstrap(): number { + return this.heightWithoutBootstrap; + } + + setHeightWithoutBootstrap(heightWithoutBootstrap: number): MoneroDaemonInfo { + this.heightWithoutBootstrap = heightWithoutBootstrap; + return this; + } + + getNetworkType(): string { + return this.networkType; + } + + setNetworkType(networkType: string) { + this.networkType = networkType; + return this; + } + + getIsOffline(): boolean { + return this.isOffline; + } + + setIsOffline(isOffline: boolean): MoneroDaemonInfo { + this.isOffline = isOffline; + return this; + } + + getNumIncomingConnections(): number { + return this.numIncomingConnections; + } + + setNumIncomingConnections(numIncomingConnections: number): MoneroDaemonInfo { + this.numIncomingConnections = numIncomingConnections; + return this; + } + + getNumOutgoingConnections(): number { + return this.numOutgoingConnections; + } + + setNumOutgoingConnections(numOutgoingConnections: number): MoneroDaemonInfo { + this.numOutgoingConnections = numOutgoingConnections; + return this; + } + + getNumRpcConnections(): number { + return this.numRpcConnections; + } + + setNumRpcConnections(numRpcConnections: number): MoneroDaemonInfo { + this.numRpcConnections = numRpcConnections; + return this; + } + + getStartTimestamp(): number { + return this.startTimestamp; + } + + setStartTimestamp(startTimestamp: number): MoneroDaemonInfo { + this.startTimestamp = startTimestamp; + return this; + } + + getAdjustedTimestamp(): number { + return this.adjustedTimestamp; + } + + setAdjustedTimestamp(adjustedTimestamp: number): MoneroDaemonInfo { + this.adjustedTimestamp = adjustedTimestamp; + return this; + } + + getTarget(): number { + return this.target; + } + + setTarget(target: number): MoneroDaemonInfo { + this.target = target; + return this; + } + + getTargetHeight(): number { + return this.targetHeight; + } + + setTargetHeight(targetHeight: number): MoneroDaemonInfo { + this.targetHeight = targetHeight; + return this; + } + + getTopBlockHash(): string { + return this.topBlockHash; + } + + setTopBlockHash(topBlockHash): MoneroDaemonInfo { + this.topBlockHash = topBlockHash; + return this; + } + + getNumTxs(): number { + return this.numTxs; + } + + setNumTxs(numTxs: number): MoneroDaemonInfo { + this.numTxs = numTxs; + return this; + } + + getNumTxsPool(): number { + return this.numTxsPool; + } + + setNumTxsPool(numTxsPool): MoneroDaemonInfo { + this.numTxsPool = numTxsPool; + return this; + } + + getWasBootstrapEverUsed(): boolean { + return this.wasBootstrapEverUsed; + } + + setWasBootstrapEverUsed(wasBootstrapEverUsed): MoneroDaemonInfo { + this.wasBootstrapEverUsed = wasBootstrapEverUsed; + return this; + } + + getDatabaseSize(): number { + return this.databaseSize; + } + + setDatabaseSize(databaseSize: number): MoneroDaemonInfo { + this.databaseSize = databaseSize; + return this; + } + + getUpdateAvailable(): boolean { + return this.updateAvailable; + } + + setUpdateAvailable(updateAvailable: boolean): MoneroDaemonInfo { + this.updateAvailable = updateAvailable; + return this; + } + + getCredits(): bigint { + return this.credits; + } + + setCredits(credits: bigint): MoneroDaemonInfo { + this.credits = credits; + return this; + } + + getIsBusySyncing(): boolean { + return this.isBusySyncing; + } + + setIsBusySyncing(isBusySyncing: boolean): MoneroDaemonInfo { + this.isBusySyncing = isBusySyncing; + return this; + } + + getIsSynchronized(): boolean { + return this.isSynchronized; + } + + setIsSynchronized(isSynchronized: boolean): MoneroDaemonInfo { + this.isSynchronized = isSynchronized; + return this; + } + + getIsRestricted(): boolean { + return this.isRestricted; + } + + setIsRestricted(isRestricted: boolean): MoneroDaemonInfo { + this.isRestricted = isRestricted; + return this; + } +} diff --git a/src/main/ts/daemon/model/MoneroDaemonListener.ts b/src/main/ts/daemon/model/MoneroDaemonListener.ts new file mode 100644 index 000000000..2c0f84846 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroDaemonListener.ts @@ -0,0 +1,27 @@ +import MoneroBlockHeader from "./MoneroBlockHeader"; + +/** + * Receives notifications as a daemon is updated. + */ +export default class MoneroDaemonListener { + + protected lastHeader: MoneroBlockHeader; + + /** + * Called when a new block is added to the chain. + * + * @param {MoneroBlockHeader} header - the header of the block added to the chain + */ + async onBlockHeader(header: MoneroBlockHeader) { + this.lastHeader = header; + } + + /** + * Get the last notified block header. + * + * @return {MoneroBlockHeader} the last notified block header + */ + getLastBlockHeader(): MoneroBlockHeader { + return this.lastHeader; + } +} diff --git a/src/main/ts/daemon/model/MoneroDaemonSyncInfo.ts b/src/main/ts/daemon/model/MoneroDaemonSyncInfo.ts new file mode 100644 index 000000000..f3921cc4a --- /dev/null +++ b/src/main/ts/daemon/model/MoneroDaemonSyncInfo.ts @@ -0,0 +1,126 @@ +import MoneroConnectionSpan from "./MoneroConnectionSpan"; +import MoneroPeer from "./MoneroPeer"; + +/** + * Models daemon synchronization information. + */ +export default class MoneroDaemonSyncInfo { + + height: number; + peers: MoneroPeer[]; + spans: MoneroConnectionSpan[]; + targetHeight: number; + nextNeededPruningSeed: number; + overview: string; + credits: bigint; + topBlockHash: string; + + constructor(info?: Partial) { + Object.assign(this, info); + + // deserialize bigints + if (this.credits !== undefined && typeof this.credits !== "bigint") this.credits = BigInt(this.credits); + + // copy peers + if (this.peers) { + for (let i = 0; i < this.peers.length; i++) { + this.peers[i] = new MoneroPeer(this.peers[i]); + } + } + + // copy spans + if (this.spans) { + for (let i = 0; i < this.spans.length; i++) { + this.spans[i] = new MoneroConnectionSpan(this.spans[i]); + } + } + } + + toJson() { + let json: any = Object.assign({}, this); + if (json.peers !== undefined) { + for (let i = 0; i < json.peers.length; i++) { + json.peers[i] = json.peers[i].toJson(); + } + } + if (json.spans !== undefined) { + for (let i = 0; i < json.spans.length; i++) { + json.spans[i] = json.spans[i].toJson(); + } + } + if (json.credits !== undefined) json.credits = json.credits.toString(); + return json; + } + + getHeight(): number { + return this.height; + } + + setHeight(height: number): MoneroDaemonSyncInfo { + this.height = height; + return this; + } + + getPeers(): MoneroPeer[] { + return this.peers; + } + + setPeers(peers: MoneroPeer[]): MoneroDaemonSyncInfo { + this.peers = peers; + return this; + } + + getSpans(): MoneroConnectionSpan[] { + return this.spans; + } + + setSpans(spans: MoneroConnectionSpan[]): MoneroDaemonSyncInfo { + this.spans = spans; + return this; + } + + getTargetHeight(): number { + return this.targetHeight; + } + + setTargetHeight(targetHeight: number): MoneroDaemonSyncInfo { + this.targetHeight = targetHeight; + return this; + } + + getNextNeededPruningSeed(): number { + return this.nextNeededPruningSeed; + } + + setNextNeededPruningSeed(nextNeededPruningSeed: number): MoneroDaemonSyncInfo { + this.nextNeededPruningSeed = nextNeededPruningSeed; + return this; + } + + getOverview(): string { + return this.overview; + } + + setOverview(overview: string): MoneroDaemonSyncInfo { + this.overview = overview; + return this; + } + + getCredits(): bigint { + return this.credits; + } + + setCredits(credits: bigint): MoneroDaemonSyncInfo { + this.credits = credits; + return this; + } + + getTopBlockHash(): string { + return this.topBlockHash; + } + + setTopBlockHash(topBlockHash: string): MoneroDaemonSyncInfo { + this.topBlockHash = topBlockHash; + return this; + } +} diff --git a/src/main/ts/daemon/model/MoneroDaemonUpdateCheckResult.ts b/src/main/ts/daemon/model/MoneroDaemonUpdateCheckResult.ts new file mode 100644 index 000000000..e01e1ad9b --- /dev/null +++ b/src/main/ts/daemon/model/MoneroDaemonUpdateCheckResult.ts @@ -0,0 +1,85 @@ +/** + * Models the result of checking for a daemon update. + */ +export default class MoneroDaemonUpdateCheckResult { + + isUpdateAvailable: boolean; + version: string; + hash: string; + autoUri: string; + userUri: string; + + constructor(result?: MoneroDaemonUpdateCheckResult) { + Object.assign(this, result); + } + + /** + * Indicates if an update is available. + * + * @return {boolean} true if an update is available, false otherwise + */ + getIsUpdateAvailable(): boolean { + return this.isUpdateAvailable; + } + + setIsUpdateAvailable(isUpdateAvailable: boolean): MoneroDaemonUpdateCheckResult { + this.isUpdateAvailable = isUpdateAvailable; + return this; + } + + /** + * Get the update's version. + * + * @return {string} is the update's version + */ + getVersion(): string { + return this.version; + } + + setVersion(version: string): MoneroDaemonUpdateCheckResult { + this.version = version; + return this; + } + + /** + * Get the update's hash. + * + * @return {string} is the update's hash + */ + getHash(): string { + return this.hash; + } + + setHash(hash: string): MoneroDaemonUpdateCheckResult { + this.hash = hash; + return this; + } + + /** + * Get the uri to automatically download the update. + * + * @return {string} is the uri to automatically download the update + */ + getAutoUri(): string { + return this.autoUri; + } + + setAutoUri(autoUri: string): MoneroDaemonUpdateCheckResult { + this.autoUri = autoUri; + return this; + } + + /** + * Get the uri to manually download the update. + * + * @return {string} is the uri to manually download the update + */ + getUserUri(): string { + return this.userUri; + } + + setUserUri(userUri: string): MoneroDaemonUpdateCheckResult { + this.userUri = userUri; + return this; + } +} \ No newline at end of file diff --git a/src/main/ts/daemon/model/MoneroDaemonUpdateDownloadResult.ts b/src/main/ts/daemon/model/MoneroDaemonUpdateDownloadResult.ts new file mode 100644 index 000000000..b7523132c --- /dev/null +++ b/src/main/ts/daemon/model/MoneroDaemonUpdateDownloadResult.ts @@ -0,0 +1,27 @@ +import MoneroDaemonUpdateCheckResult from "./MoneroDaemonUpdateCheckResult"; + +/** + * Models the result of downloading an update. + */ +export default class MoneroDaemonUpdateDownloadResult extends MoneroDaemonUpdateCheckResult { + + downloadPath: string; + + constructor(state: MoneroDaemonUpdateDownloadResult) { + super(state); + } + + /** + * Get the path the update was downloaded to. + * + * @return {string} is the path the update was downloaded to + */ + getDownloadPath(): string { + return this.downloadPath; + } + + setDownloadPath(downloadPath: string): MoneroDaemonUpdateDownloadResult { + this.downloadPath = downloadPath; + return this; + } +} \ No newline at end of file diff --git a/src/main/ts/daemon/model/MoneroFeeEstimate.ts b/src/main/ts/daemon/model/MoneroFeeEstimate.ts new file mode 100644 index 000000000..3cea83323 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroFeeEstimate.ts @@ -0,0 +1,72 @@ +import GenUtils from "../../common/GenUtils"; + +/** + * Models a Monero fee estimate. + */ +export default class MoneroFeeEstimate { + + fee: bigint; + fees: bigint[]; + quantizationMask: bigint; + + constructor(feeEstimate?: Partial) { + Object.assign(this, feeEstimate); + + // deserialize + if (this.fee !== undefined && typeof this.fee !== "bigint") this.fee = BigInt(this.fee); + if (this.fees !== undefined) { + for (let i = 0; i < this.fees.length; i++) { + if (typeof this.fees[i] !== "bigint") this.fees[i] = BigInt(this.fees[i]); + } + } + if (this.quantizationMask !== undefined && typeof this.quantizationMask !== "bigint") this.quantizationMask = BigInt(this.quantizationMask); + } + + getFee(): bigint { + return this.fee; + } + + setFee(fee: bigint): MoneroFeeEstimate { + this.fee = fee; + return this; + } + + getFees(): bigint[] { + return this.fees; + } + + setFees(fees) { + this.fees = fees; + return this; + } + + getQuantizationMask(): bigint { + return this.quantizationMask; + } + + setQuantizationMask(quantizationMask): MoneroFeeEstimate { + this.quantizationMask = quantizationMask; + return this; + } + + copy(): MoneroFeeEstimate { + return new MoneroFeeEstimate(this); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (this.getFee()) json.fee = this.getFee().toString(); + if (this.getFees()) for (let i = 0; i < this.getFees().length; i++) json.fees[i] = this.getFees()[i].toString(); + if (this.getQuantizationMask()) json.quantizationMask = this.getQuantizationMask().toString(); + return json; + } + + toString(indent = 0) { + let str = ""; + let json = this.toJson(); + str += GenUtils.kvLine("Fee", json.fee, indent); + str += GenUtils.kvLine("Fees", json.fees, indent); + str += GenUtils.kvLine("Quantization mask", json.quantizationMask, indent); + return str.slice(0, str.length - 1); // strip last newline + } +} \ No newline at end of file diff --git a/src/main/ts/daemon/model/MoneroHardForkInfo.ts b/src/main/ts/daemon/model/MoneroHardForkInfo.ts new file mode 100644 index 000000000..16ba6ee4c --- /dev/null +++ b/src/main/ts/daemon/model/MoneroHardForkInfo.ts @@ -0,0 +1,117 @@ +/** + * Monero hard fork info. + */ +export default class MoneroHardForkInfo { + + earliestHeight: number; + isEnabled: boolean; + state: string; + threshold: number; + version: number; + numVotes: number; + window: number; + voting: number; + credits: bigint; + topBlockHash: string; + + constructor(info?: Partial) { + Object.assign(this, info); + if (this.credits !== undefined && typeof this.credits !== "bigint") this.credits = BigInt(this.credits); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (json.credits !== undefined) json.credits = json.credits.toString(); + return json; + } + + getEarliestHeight(): number { + return this.earliestHeight; + } + + setEarliestHeight(earliestHeight: number): MoneroHardForkInfo { + this.earliestHeight = earliestHeight; + return this; + } + + getIsEnabled(): boolean { + return this.isEnabled; + } + + setIsEnabled(isEnabled: boolean): MoneroHardForkInfo { + this.isEnabled = isEnabled; + return this; + } + + getState(): string { + return this.state; + } + + setState(state: string): MoneroHardForkInfo { + this.state = state; + return this; + } + + getThreshold(): number { + return this.threshold; + } + + setThreshold(threshold: number): MoneroHardForkInfo { + this.threshold = threshold; + return this; + } + + getVersion(): number { + return this.version; + } + + setVersion(version: number): MoneroHardForkInfo { + this.version = version; + return this; + } + + getNumVotes(): number { + return this.numVotes; + } + + setNumVotes(numVotes: number): MoneroHardForkInfo { + this.numVotes = numVotes; + return this; + } + + getWindow(): number { + return this.window; + } + + setWindow(window: number): MoneroHardForkInfo { + this.window = window; + return this; + } + + getVoting(): number { + return this.voting; + } + + setVoting(voting: number): MoneroHardForkInfo { + this.voting = voting; + return this; + } + + getCredits(): bigint{ + return this.credits; + } + + setCredits(credits: bigint): MoneroHardForkInfo { + this.credits = credits; + return this; + } + + getTopBlockHash(): string { + return this.topBlockHash; + } + + setTopBlockHash(topBlockHash: string): MoneroHardForkInfo { + this.topBlockHash = topBlockHash; + return this; + } +} diff --git a/src/main/ts/daemon/model/MoneroKeyImage.ts b/src/main/ts/daemon/model/MoneroKeyImage.ts new file mode 100644 index 000000000..6ef6e272d --- /dev/null +++ b/src/main/ts/daemon/model/MoneroKeyImage.ts @@ -0,0 +1,68 @@ +import assert from "assert"; +import GenUtils from "../../common/GenUtils"; +import MoneroError from "../../common/MoneroError"; + +/** + * Models a Monero key image. + */ +export default class MoneroKeyImage { + + hex: string; + signature: string; + + /** + * Construct the model. + * + * @param {string|Partial} [keyImageOrHex] is a MoneroKeyImage or hex string to initialize from (optional) + * @param {string} [signature] is the key image's signature + */ + constructor(hexOrKeyImage?: string | Partial, signature?: string) { + if (typeof hexOrKeyImage === "string") { + this.setHex(hexOrKeyImage); + this.setSignature(signature); + } else { + Object.assign(this, hexOrKeyImage); + } + } + + getHex(): string { + return this.hex; + } + + setHex(hex: string): MoneroKeyImage { + this.hex = hex; + return this; + } + + getSignature(): string { + return this.signature; + } + + setSignature(signature: string): MoneroKeyImage { + this.signature = signature; + return this; + } + + copy(): MoneroKeyImage { + return new MoneroKeyImage(this); + } + + toJson() { + return Object.assign({}, this); + } + + merge(keyImage: MoneroKeyImage): MoneroKeyImage { + assert(keyImage instanceof MoneroKeyImage); + if (keyImage === this) return this; + this.setHex(GenUtils.reconcile(this.getHex(), keyImage.getHex())); + this.setSignature(GenUtils.reconcile(this.getSignature(), keyImage.getSignature())); + return this; + } + + toString(indent = 0): string { + let str = ""; + str += GenUtils.kvLine("Hex", this.getHex(), indent); + str += GenUtils.kvLine("Signature", this.getSignature(), indent); + return str.slice(0, str.length - 1); // strip last newline + } +} diff --git a/src/main/ts/daemon/model/MoneroKeyImageSpentStatus.ts b/src/main/ts/daemon/model/MoneroKeyImageSpentStatus.ts new file mode 100644 index 000000000..d6d1eba76 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroKeyImageSpentStatus.ts @@ -0,0 +1,24 @@ +/** + * Enumerates connection types. + * + * Based on enums.h in monero-project. + */ +enum MoneroKeyImageSpentStatus { + + /** + * Key image is not spent (value=0). + */ + NOT_SPENT = 0, + + /** + * Key image is confirmed (value=1). + */ + CONFIRMED = 1, + + /** + * Key image is in the pool (value=2). + */ + TX_POOL = 2 + } + + export default MoneroKeyImageSpentStatus; \ No newline at end of file diff --git a/src/main/ts/daemon/model/MoneroMinerTxSum.ts b/src/main/ts/daemon/model/MoneroMinerTxSum.ts new file mode 100644 index 000000000..fb9f6f078 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroMinerTxSum.ts @@ -0,0 +1,41 @@ +/** + * Model for the summation of miner emissions and fees. + */ +export default class MoneroMinerTxSum { + + emissionSum: bigint; + feeSum: bigint; + + constructor(txSum?: Partial) { + Object.assign(this, txSum); + + // deserialize bigints + if (this.emissionSum !== undefined && typeof this.emissionSum !== "bigint") this.emissionSum = BigInt(this.emissionSum); + if (this.feeSum !== undefined && typeof this.feeSum !== "bigint") this.feeSum = BigInt(this.feeSum); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (this.getEmissionSum() !== undefined) json.emissionSum = this.getEmissionSum().toString(); + if (this.getFeeSum() !== undefined) json.feeSum = this.getFeeSum().toString(); + return json; + } + + getEmissionSum(): bigint { + return this.emissionSum; + } + + setEmissionSum(emissionSum: bigint): MoneroMinerTxSum { + this.emissionSum = emissionSum; + return this; + } + + getFeeSum(): bigint { + return this.feeSum; + } + + setFeeSum(feeSum: bigint): MoneroMinerTxSum { + this.feeSum = feeSum; + return this; + } +} \ No newline at end of file diff --git a/src/main/ts/daemon/model/MoneroMiningStatus.ts b/src/main/ts/daemon/model/MoneroMiningStatus.ts new file mode 100644 index 000000000..59c27afe1 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroMiningStatus.ts @@ -0,0 +1,64 @@ +/** + * Models daemon mining status. + */ +export default class MoneroMiningStatus { + + isActive: boolean; + address: string; + speed: number; + numThreads: number; + isBackground: boolean; + + constructor(status?: Partial) { + Object.assign(this, status); + } + + toJson() { + return Object.assign({}, this); + } + + getIsActive(): boolean { + return this.isActive; + } + + setIsActive(isActive: boolean): MoneroMiningStatus { + this.isActive = isActive; + return this; + } + + getAddress(): string { + return this.address; + } + + setAddress(address: string): MoneroMiningStatus { + this.address = address; + return this; + } + + getSpeed(): number { + return this.speed; + } + + setSpeed(speed: number): MoneroMiningStatus { + this.speed = speed; + return this; + } + + getNumThreads(): number { + return this.numThreads; + } + + setNumThreads(numThreads: number): MoneroMiningStatus { + this.numThreads = numThreads; + return this; + } + + getIsBackground(): boolean { + return this.isBackground; + } + + setIsBackground(isBackground: boolean): MoneroMiningStatus { + this.isBackground = isBackground; + return this; + } +} diff --git a/src/main/ts/daemon/model/MoneroNetworkType.ts b/src/main/ts/daemon/model/MoneroNetworkType.ts new file mode 100644 index 000000000..dfc26bf98 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroNetworkType.ts @@ -0,0 +1,87 @@ +import MoneroError from "../../common/MoneroError"; + +/** + * Defines the Monero network types (mainnet, testnet, and stagenet). + */ +export default class MoneroNetworkType { + + /** + * Mainnet (value=0). + */ + static readonly MAINNET = 0; + + /** + * Testnet (value=1). + */ + static readonly TESTNET = 1; + + /** + * Stagnet (value=2). + */ + static readonly STAGENET = 2; + + /** + * Validate and normalize the given network type. + * + * @param {MoneroNetworkType | number | string} networkType - the network type to validate and normalize + * @return {MoneroNetworkType} the given network type + */ + static from(networkType: MoneroNetworkType | number | string): MoneroNetworkType { + if (typeof networkType === "string") return MoneroNetworkType.parse(networkType); + MoneroNetworkType.validate(networkType); + return networkType; + } + + /** + * Validate the given network type. + * + * @param {MoneroNetworkType} networkType - the network type to validate as a numeric + */ + static validate(networkType: MoneroNetworkType | number | string) { + if (typeof networkType === "string") MoneroNetworkType.parse(networkType); + else if (networkType !== 0 && networkType !== 1 && networkType !== 2) throw new MoneroError("Network type is invalid: " + networkType); + } + + /** + * Indicates if the given network type is valid or not. + * + * @param {MoneroNetworkType | number} networkType - the network type to validate as a numeric + * @return {boolean} true if the network type is valid, false otherwise + */ + static isValid(networkType: MoneroNetworkType | number | string): boolean { + try { + MoneroNetworkType.validate(networkType); + return true; + } catch(err) { + return false; + } + } + + /** + * Parse the given string as a network type. + * + * @param {string} networkTypeStr - "mainnet", "testnet", or "stagenet" (case insensitive) + * @return {MoneroNetworkType} the network type as a numeric + */ + static parse(networkTypeStr: string): MoneroNetworkType { + let str = ("" + networkTypeStr).toLowerCase(); + switch (str) { + case "mainnet": return MoneroNetworkType.MAINNET; + case "testnet": return MoneroNetworkType.TESTNET; + case "stagenet": return MoneroNetworkType.STAGENET; + default: throw new MoneroError("Invalid network type to parse: '" + networkTypeStr + "'"); + } + } + + /** + * Get the network type in human-readable form. + * + * @return {string} the network type in human-readable form + */ + static toString(networkType: MoneroNetworkType | number): string { + if (networkType === 0) return "mainnet"; + if (networkType === 1) return "testnet"; + if (networkType === 2) return "stagenet"; + throw new MoneroError("Invalid network type: " + networkType); + } +} \ No newline at end of file diff --git a/src/main/ts/daemon/model/MoneroOutput.ts b/src/main/ts/daemon/model/MoneroOutput.ts new file mode 100644 index 000000000..94655e19f --- /dev/null +++ b/src/main/ts/daemon/model/MoneroOutput.ts @@ -0,0 +1,128 @@ +import assert from "assert"; +import GenUtils from "../../common/GenUtils"; +import MoneroError from "../../common/MoneroError"; +import MoneroKeyImage from "./MoneroKeyImage"; +import MoneroTx from "./MoneroTx"; + +/** + * Models a Monero transaction output. + */ +export default class MoneroOutput { + + tx: MoneroTx; + keyImage: Partial; + amount: bigint; + index: number; + ringOutputIndices: number[]; + stealthPublicKey: string; + + /** + * Construct the model. + * + * @param {MoneroOutput} [output] is existing state to initialize from (optional) + */ + constructor(output?: Partial) { + Object.assign(this, output); + + // deserialize fields if necessary + if (this.amount !== undefined && typeof this.amount !== "bigint") this.amount = BigInt(this.amount); + if (this.keyImage) this.keyImage = this.keyImage instanceof MoneroKeyImage ? this.keyImage.copy() : new MoneroKeyImage(this.keyImage); + } + + getTx(): MoneroTx { + return this.tx; + } + + setTx(tx: MoneroTx): MoneroOutput { + this.tx = tx; + return this; + } + + getKeyImage(): MoneroKeyImage { + return this.keyImage as MoneroKeyImage; + } + + setKeyImage(keyImage: MoneroKeyImage): MoneroOutput { + this.keyImage = keyImage === undefined ? undefined : keyImage instanceof MoneroKeyImage ? keyImage : new MoneroKeyImage(keyImage); + return this; + } + + getAmount(): bigint { + return this.amount; + } + + setAmount(amount: bigint): MoneroOutput { + this.amount = amount; + return this; + } + + getIndex(): number { + return this.index; + } + + setIndex(index: number): MoneroOutput { + this.index = index; + return this; + } + + getRingOutputIndices(): number[] { + return this.ringOutputIndices; + } + + setRingOutputIndices(ringOutputIndices: number[]): MoneroOutput { + this.ringOutputIndices = ringOutputIndices; + return this; + } + + getStealthPublicKey(): string { + return this.stealthPublicKey; + } + + setStealthPublicKey(stealthPublicKey: string): MoneroOutput { + this.stealthPublicKey = stealthPublicKey; + return this; + } + + copy(): MoneroOutput { + return new MoneroOutput(this); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (this.getAmount() !== undefined) json.amount = this.getAmount().toString(); + if (this.getKeyImage() !== undefined) json.keyImage = this.getKeyImage() ? this.getKeyImage().toJson() : undefined; + delete json.tx; + return json; + } + + merge(output: MoneroOutput): MoneroOutput { + assert(output instanceof MoneroOutput); + if (this === output) return this; + + // merge txs if they're different which comes back to merging outputs + if (this.getTx() !== output.getTx()) this.getTx().merge(output.getTx()); + + // otherwise merge output fields + else { + if (this.getKeyImage() === undefined) this.setKeyImage(output.getKeyImage()); + else if (output.getKeyImage() !== undefined) this.getKeyImage().merge(output.getKeyImage()); + this.setAmount(GenUtils.reconcile(this.getAmount(), output.getAmount())); + this.setIndex(GenUtils.reconcile(this.getIndex(), output.getIndex())); + } + + return this; + } + + toString(indent = 0): string { + let str = ""; + if (this.getKeyImage() !== undefined) { + str += GenUtils.kvLine("Key image", "", indent); + str += this.getKeyImage().toString(indent + 1) + "\n"; + } + str += GenUtils.kvLine("Amount", this.getAmount(), indent); + str += GenUtils.kvLine("Index", this.getIndex(), indent); + str += GenUtils.kvLine("Ring output indices", this.getRingOutputIndices(), indent); + str += GenUtils.kvLine("Stealth public key", this.getStealthPublicKey(), indent); + return str === "" ? str : str.slice(0, str.length - 1); // strip last newline + } +} \ No newline at end of file diff --git a/src/main/ts/daemon/model/MoneroOutputHistogramEntry.ts b/src/main/ts/daemon/model/MoneroOutputHistogramEntry.ts new file mode 100644 index 000000000..a15939b47 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroOutputHistogramEntry.ts @@ -0,0 +1,57 @@ +/** + * Entry in a Monero output histogram (see get_output_histogram of Daemon RPC documentation). + */ +export default class MoneroOutputHistogramEntry { + + amount: bigint; + numInstances: number; + numUnlockedInstances: number; + numRecentInstances: number; + + constructor(entry?: MoneroOutputHistogramEntry) { + Object.assign(this, entry); + if (this.amount !== undefined && typeof this.amount !== "bigint") this.amount = BigInt(this.amount); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (json.amount !== undefined) json.amount = json.amount.toString(); + return json; + } + + getAmount(): bigint { + return this.amount; + } + + setAmount(amount: bigint): MoneroOutputHistogramEntry { + this.amount = amount; + return this; + } + + getNumInstances(): number { + return this.numInstances; + } + + setNumInstances(numInstances: number): MoneroOutputHistogramEntry { + this.numInstances = numInstances; + return this; + } + + getNumUnlockedInstances(): number { + return this.numUnlockedInstances; + } + + setNumUnlockedInstances(numUnlockedInstances: number) { + this.numUnlockedInstances = numUnlockedInstances; + return this; + } + + getNumRecentInstances(): number { + return this.numRecentInstances; + } + + setNumRecentInstances(numRecentInstances: number): MoneroOutputHistogramEntry { + this.numRecentInstances = numRecentInstances; + return this; + } +} diff --git a/src/main/ts/daemon/model/MoneroPeer.ts b/src/main/ts/daemon/model/MoneroPeer.ts new file mode 100644 index 000000000..585818bf4 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroPeer.ts @@ -0,0 +1,275 @@ +import ConnectionType from "./ConnectionType"; + +/** + * Models a peer to the daemon. + */ +export default class MoneroPeer { + + id: string; + address: string; + host: string; + port: number; + isOnline: boolean; + lastSeenTimestamp: number; + pruningSeed: number; + rpcPort: number; + rpcCreditsPerHash: bigint; + avgDownload: number; + avgUpload: number; + currentDownload: number; + currentUpload: number; + height: number; + isIncoming: boolean; + liveTime: number; + isLocalIp: boolean; + isLocalHost: boolean; + numReceives: number; + numSends: number; + receiveIdleTime: number; + sendIdleTime: number; + state: string; + numSupportFlags: number; + type: ConnectionType; + + constructor(peer?: MoneroPeer) { + Object.assign(this, peer); + if (this.rpcCreditsPerHash !== undefined && typeof this.rpcCreditsPerHash !== "bigint") this.rpcCreditsPerHash = BigInt(this.rpcCreditsPerHash); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (json.rpcCreditsPerHash !== undefined) json.rpcCreditsPerHash = json.rpcCreditsPerHash.toString(); + return json; + } + + getId(): string { + return this.id; + } + + setId(id: string): MoneroPeer { + this.id = id; + return this; + } + + getAddress(): string { + return this.address; + } + + setAddress(address: string): MoneroPeer { + this.address = address; + return this; + } + + getHost(): string { + return this.host; + } + + setHost(host: string): MoneroPeer { + this.host = host; + return this; + } + + getPort(): number { + return this.port; + } + + setPort(port: number): MoneroPeer { + this.port = port; + return this; + } + + /** + * Indicates if the peer was online when last checked (aka "white listed" as + * opposed to "gray listed"). + * + * @return {boolean} true if peer was online when last checked, false otherwise + */ + getIsOnline(): boolean { + return this.isOnline; + } + + setIsOnline(isOnline: boolean): MoneroPeer { + this.isOnline = isOnline; + return this; + } + + getLastSeenTimestamp(): number { + return this.lastSeenTimestamp; + } + + setLastSeenTimestamp(lastSeenTimestamp: number): MoneroPeer { + this.lastSeenTimestamp = lastSeenTimestamp; + return this; + } + + getPruningSeed(): number { + return this.pruningSeed; + } + + setPruningSeed(pruningSeed: number): MoneroPeer { + this.pruningSeed = pruningSeed; + return this; + } + + getRpcPort(): number { + return this.rpcPort; + } + + setRpcPort(rpcPort: number): MoneroPeer { + this.rpcPort = rpcPort; + return this; + } + + getRpcCreditsPerHash(): bigint { + return this.rpcCreditsPerHash; + } + + setRpcCreditsPerHash(rpcCreditsPerHash: bigint): MoneroPeer { + this.rpcCreditsPerHash = rpcCreditsPerHash; + return this; + } + + getAvgDownload(): number { + return this.avgDownload; + } + + setAvgDownload(avgDownload: number): MoneroPeer { + this.avgDownload = avgDownload; + return this; + } + + getAvgUpload(): number { + return this.avgUpload; + } + + setAvgUpload(avgUpload: number): MoneroPeer { + this.avgUpload = avgUpload; + return this; + } + + getCurrentDownload(): number { + return this.currentDownload; + } + + setCurrentDownload(currentDownload: number): MoneroPeer { + this.currentDownload = currentDownload; + return this; + } + + getCurrentUpload(): number { + return this.currentUpload; + } + + setCurrentUpload(currentUpload: number): MoneroPeer { + this.currentUpload = currentUpload; + return this; + } + + getHeight(): number { + return this.height; + } + + setHeight(height: number): MoneroPeer { + this.height = height; + return this; + } + + getIsIncoming(): boolean { + return this.isIncoming; + } + + setIsIncoming(isIncoming: boolean): MoneroPeer { + this.isIncoming = isIncoming; + return this; + } + + getLiveTime(): number { + return this.liveTime; + } + + setLiveTime(liveTime: number) { + this.liveTime = liveTime; + return this; + } + + getIsLocalIp(): boolean { + return this.isLocalIp; + } + + setIsLocalIp(isLocalIp: boolean): MoneroPeer { + this.isLocalIp = isLocalIp; + return this; + } + + getIsLocalHost(): boolean { + return this.isLocalHost; + } + + setIsLocalHost(isLocalHost: boolean): MoneroPeer { + this.isLocalHost = isLocalHost; + return this; + } + + getNumReceives(): number { + return this.numReceives; + } + + setNumReceives(numReceives: number): MoneroPeer { + this.numReceives = numReceives; + return this; + } + + getNumSends(): number { + return this.numSends; + } + + setNumSends(numSends: number): MoneroPeer { + this.numSends = numSends; + return this; + } + + getReceiveIdleTime(): number { + return this.receiveIdleTime; + } + + setReceiveIdleTime(receiveIdleTime: number): MoneroPeer { + this.receiveIdleTime = receiveIdleTime; + return this; + } + + getSendIdleTime(): number { + return this.sendIdleTime; + } + + setSendIdleTime(sendIdleTime: number): MoneroPeer { + this.sendIdleTime = sendIdleTime; + return this; + } + + getState(): string { + return this.state; + } + + setState(state: string): MoneroPeer { + this.state = state; + return this; + } + + getNumSupportFlags(): number { + return this.numSupportFlags; + } + + setNumSupportFlags(numSupportFlags: number): MoneroPeer { + this.numSupportFlags = numSupportFlags; + return this; + } + + getType(): ConnectionType { + return this.type; + } + + setType(type: ConnectionType): MoneroPeer { + this.type = type; + return this; + } +} diff --git a/src/main/ts/daemon/model/MoneroPruneResult.ts b/src/main/ts/daemon/model/MoneroPruneResult.ts new file mode 100644 index 000000000..8fc7a56f6 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroPruneResult.ts @@ -0,0 +1,37 @@ +/** + * Result of pruning the blockchain. + */ +export default class MoneroPruneResult { + + isPruned: boolean; + pruningSeed: number; + + constructor(result?: Partial) { + Object.assign(this, result); + } + + toJson(): any { + let json = Object.assign({}, this); + if (this.getIsPruned()) json.isPruned = this.getIsPruned(); + if (this.getPruningSeed()) json.pruningSeed = this.getPruningSeed(); + return json; + } + + getIsPruned(): boolean { + return this.isPruned; + } + + setIsPruned(isPruned: boolean): MoneroPruneResult { + this.isPruned = isPruned; + return this; + } + + getPruningSeed(): number { + return this.pruningSeed; + } + + setPruningSeed(pruningSeed: number): MoneroPruneResult { + this.pruningSeed = pruningSeed; + return this; + } +} diff --git a/src/main/ts/daemon/model/MoneroSubmitTxResult.ts b/src/main/ts/daemon/model/MoneroSubmitTxResult.ts new file mode 100644 index 000000000..8f6a3f34c --- /dev/null +++ b/src/main/ts/daemon/model/MoneroSubmitTxResult.ts @@ -0,0 +1,177 @@ +/** + * Models the result from submitting a tx to a daemon. + */ +export default class MoneroSubmitTxResult { + + isGood: boolean; + isRelayed: boolean; + isDoubleSpendSeen: boolean; + isFeeTooLow: boolean; + isMixinTooLow: boolean; + hasInvalidInput: boolean; + hasInvalidOutput: boolean; + hasTooFewOutputs: boolean; + isOverspend: boolean; + reason: string; + isTooBig: boolean; + sanityCheckFailed: boolean; + credits: bigint; + topBlockHash: string; + isTxExtraTooBig: boolean; + isNonzeroUnlockTime: boolean; + + constructor(result?: Partial) { + Object.assign(this, result); + if (this.credits !== undefined && typeof this.credits !== "bigint") this.credits = BigInt(this.credits); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (json.credits !== undefined) json.credits = json.credits.toString(); + return json; + } + + getIsGood(): boolean { + return this.isGood; + } + + setIsGood(isGood: boolean): MoneroSubmitTxResult { + this.isGood = isGood; + return this; + } + + getIsRelayed(): boolean { + return this.isRelayed; + } + + setIsRelayed(isRelayed: boolean) { + this.isRelayed = isRelayed; + return this; + } + + getIsDoubleSpendSeen(): boolean { + return this.isDoubleSpendSeen; + } + + setIsDoubleSpendSeen(isDoubleSpendSeen: boolean): MoneroSubmitTxResult { + this.isDoubleSpendSeen = isDoubleSpendSeen + return this; + } + + getIsFeeTooLow(): boolean { + return this.isFeeTooLow; + } + + setIsFeeTooLow(isFeeTooLow: boolean): MoneroSubmitTxResult { + this.isFeeTooLow = isFeeTooLow; + return this; + } + + getIsMixinTooLow(): boolean { + return this.isMixinTooLow; + } + + setIsMixinTooLow(isMixinTooLow: boolean): MoneroSubmitTxResult { + this.isMixinTooLow = isMixinTooLow; + return this; + } + + getHasInvalidInput(): boolean { + return this.hasInvalidInput; + } + + setHasInvalidInput(hasInvalidInput: boolean): MoneroSubmitTxResult { + this.hasInvalidInput = hasInvalidInput; + return this; + } + + getHasInvalidOutput(): boolean { + return this.hasInvalidOutput; + } + + setHasInvalidOutput(hasInvalidOutput: boolean): MoneroSubmitTxResult { + this.hasInvalidOutput = hasInvalidOutput; + return this; + } + + getHasTooFewOutputs(): boolean { + return this.hasTooFewOutputs; + } + + setHasTooFewOutputs(hasTooFewOutputs: boolean): MoneroSubmitTxResult { + this.hasTooFewOutputs = hasTooFewOutputs; + return this; + } + + getIsOverspend(): boolean { + return this.isOverspend; + } + + setIsOverspend(isOverspend: boolean): MoneroSubmitTxResult { + this.isOverspend = isOverspend; + return this; + } + + getReason(): string { + return this.reason; + } + + setReason(reason): MoneroSubmitTxResult { + this.reason = reason; + return this; + } + + getIsTooBig(): boolean { + return this.isTooBig; + } + + setIsTooBig(isTooBig: boolean) { + this.isTooBig = isTooBig; + return this; + } + + getSanityCheckFailed(): boolean { + return this.sanityCheckFailed; + } + + setSanityCheckFailed(sanityCheckFailed): MoneroSubmitTxResult { + this.sanityCheckFailed = sanityCheckFailed; + return this; + } + + getCredits(): bigint { + return this.credits; + } + + setCredits(credits): MoneroSubmitTxResult { + this.credits = credits; + return this; + } + + getTopBlockHash(): string { + return this.topBlockHash; + } + + setTopBlockHash(topBlockHash: string): MoneroSubmitTxResult { + this.topBlockHash = topBlockHash; + return this; + } + + getIsTxExtraTooBig(): boolean { + return this.isTxExtraTooBig; + } + + setIsTxExtraTooBig(isTxExtraTooBig: boolean): MoneroSubmitTxResult { + this.isTxExtraTooBig = isTxExtraTooBig; + return this; + } + + getIsNonzeroUnlockTime(): boolean { + return this.isNonzeroUnlockTime; + } + + setIsNonzeroUnlockTime(isNonzeroUnlockTime: boolean): MoneroSubmitTxResult { + this.isNonzeroUnlockTime = isNonzeroUnlockTime; + return this; + } +} diff --git a/src/main/ts/daemon/model/MoneroTx.ts b/src/main/ts/daemon/model/MoneroTx.ts new file mode 100644 index 000000000..7fdc11397 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroTx.ts @@ -0,0 +1,880 @@ +import assert from "assert"; +import GenUtils from "../../common/GenUtils"; +import MoneroBlock from "./MoneroBlock"; +import MoneroOutput from "./MoneroOutput"; + +/** + * Represents a transaction on the Monero network. + */ +export default class MoneroTx { + + static readonly DEFAULT_PAYMENT_ID = "0000000000000000"; + + block: MoneroBlock; + hash: string; + version: number; + isMinerTx: boolean; + paymentId: string; + fee: bigint; + ringSize: number; + relay: boolean; + isRelayed: boolean; + isConfirmed: boolean; + inTxPool: boolean; + numConfirmations: number; + unlockTime: bigint; + lastRelayedTimestamp: number; + receivedTimestamp: number; + isDoubleSpendSeen: boolean; + key: string; + fullHex: string; + prunedHex: string; + prunableHex: string; + prunableHash: string; + size: number; + weight: number; + inputs: MoneroOutput[]; + outputs: MoneroOutput[]; + outputIndices: number[]; + metadata: string; + extra: Uint8Array; + rctSignatures: any; + rctSigPrunable: any; + isKeptByBlock: boolean; + isFailed: boolean; + lastFailedHeight: number; + lastFailedHash: string; + maxUsedBlockHeight: number; + maxUsedBlockHash: string; + signatures: string[]; + + constructor(tx?: Partial) { + Object.assign(this, tx); + this.block = undefined; + + // deserialize extra + if (this.extra !== undefined) this.extra = new Uint8Array(this.extra); + + // deserialize bigints + if (this.fee !== undefined && typeof this.fee !== "bigint") this.fee = BigInt(this.fee); + if (this.unlockTime !== undefined && typeof this.unlockTime !== "bigint") this.unlockTime = BigInt(this.unlockTime); + + // copy inputs + if (this.inputs) { + this.inputs = this.inputs.slice(); + for (let i = 0; i < this.inputs.length; i++) { + this.inputs[i] = new MoneroOutput(this.inputs[i]).setTx(this); + } + } + + // copy outputs + if (this.outputs) { + this.outputs = this.outputs.slice(); + for (let i = 0; i < this.outputs.length; i++) { + this.outputs[i] = new MoneroOutput(this.outputs[i]).setTx(this); + } + } + } + + /** + * @return {MoneroBlock} tx block + */ + getBlock(): MoneroBlock { + return this.block; + } + + /** + * @param {MoneroBlock} block - tx block + * @return {MoneroTx} this tx for chaining + */ + setBlock(block: MoneroBlock): MoneroTx { + this.block = block; + return this; + } + + /** + * @return {number} tx height + */ + getHeight(): number { + return this.getBlock() === undefined ? undefined : this.getBlock().getHeight(); + } + + /** + * @return {string} tx hash + */ + getHash(): string { + return this.hash; + } + + /** + * @param {string} hash - tx hash + * @return {MoneroTx} this tx for chaining + */ + setHash(hash: string): MoneroTx { + this.hash = hash; + return this; + } + + /** + * @return {number} tx version + */ + getVersion(): number { + return this.version; + } + + /** + * @param {number} version - tx version + * @return {MoneroTx} this tx for chaining + */ + setVersion(version: number): MoneroTx { + this.version = version; + return this; + } + + /** + * @return {boolean} true if the tx is a miner tx, false otherwise + */ + getIsMinerTx(): boolean { + return this.isMinerTx; + } + + /** + * @param {boolean} miner - true if the tx is a miner tx, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsMinerTx(miner: boolean): MoneroTx { + this.isMinerTx = miner; + return this; + } + + /** + * @return {string} tx payment id + */ + getPaymentId(): string { + return this.paymentId; + } + + /** + * @param {string} paymentId - tx payment id + * @return {MoneroTx} this tx for chaining + */ + setPaymentId(paymentId: string): MoneroTx { + this.paymentId = paymentId; + return this; + } + + /** + * @return {bigint} tx fee + */ + getFee(): bigint { + return this.fee; + } + + /** + * @param {bigint} fee - tx fee + * @return {MoneroTx} this tx for chaining + */ + setFee(fee: bigint): MoneroTx { + this.fee = fee; + return this; + } + + /** + * @return {number} tx ring size + */ + getRingSize(): number { + return this.ringSize; + } + + /** + * @param {number} ringSize - tx ring size + * @return {MoneroTx} this tx for chaining + */ + setRingSize(ringSize: number): MoneroTx { + this.ringSize = ringSize; + return this; + } + + /** + * @return {boolean} true if the tx is set to be relayed, false otherwise + */ + getRelay(): boolean { + return this.relay; + } + + /** + * @param {boolean} relay - true if the tx is set to be relayed, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setRelay(relay: boolean): MoneroTx { + this.relay = relay; + return this; + } + + /** + * @return {boolean} true if the tx is relayed, false otherwise + */ + getIsRelayed(): boolean { + return this.isRelayed; + } + + /** + * @param {boolean} isRelayed - true if the tx is relayed, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsRelayed(isRelayed: boolean): MoneroTx { + this.isRelayed = isRelayed; + return this; + } + + /** + * @return {boolean} true if the tx is confirmed, false otherwise + */ + getIsConfirmed(): boolean { + return this.isConfirmed; + } + + /** + * @param {boolean} isConfirmed - true if the tx is confirmed, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsConfirmed(isConfirmed: boolean): MoneroTx { + this.isConfirmed = isConfirmed; + return this; + } + + /** + * @return {boolean} true if the tx is in the memory pool, false otherwise + */ + getInTxPool(): boolean { + return this.inTxPool; + } + + /** + * @param {boolean} inTxPool - true if the tx is in the memory pool, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setInTxPool(inTxPool: boolean): MoneroTx { + this.inTxPool = inTxPool; + return this; + } + + /** + * @return {number} number of block confirmations + */ + getNumConfirmations(): number { + return this.numConfirmations; + } + + /** + * @param {number} numConfirmations - number of block confirmations + * @return {MoneroTx} this tx for chaining + */ + setNumConfirmations(numConfirmations: number): MoneroTx { + this.numConfirmations = numConfirmations; + return this; + } + + /** + * Get the minimum height or timestamp for the transactions to unlock. + * + * @return {bigint} the minimum height or timestamp for the transaction to unlock + */ + getUnlockTime(): bigint { + return this.unlockTime; + } + + setUnlockTime(unlockTime: bigint | string | number | undefined): MoneroTx { + if (unlockTime !== undefined && typeof unlockTime !== "bigint") unlockTime = BigInt(unlockTime); + this.unlockTime = unlockTime as bigint | undefined; + return this; + } + + /** + * @return {number} timestamp the tx was last relayed from the node + */ + getLastRelayedTimestamp(): number { + return this.lastRelayedTimestamp; + } + + /** + * @param {number} lastRelayedTimestamp - timestamp the tx was last relayed from the node + * @return {MoneroTx} this tx for chaining + */ + setLastRelayedTimestamp(lastRelayedTimestamp: number): MoneroTx { + this.lastRelayedTimestamp = lastRelayedTimestamp; + return this; + } + + /** + * @return {number} timestamp the tx was received at the node + */ + getReceivedTimestamp(): number { + return this.receivedTimestamp; + } + + /** + * @param {number} receivedTimestamp - timestamp the tx was received at the node + * @return {MoneroTx} this tx for chaining + */ + setReceivedTimestamp(receivedTimestamp: number): MoneroTx { + this.receivedTimestamp = receivedTimestamp; + return this; + } + + /** + * @return {boolean} true if a double spend has been seen, false otherwise + */ + getIsDoubleSpendSeen(): boolean { + return this.isDoubleSpendSeen; + } + + /** + * @param {boolean} isDoubleSpendSeen - true if a double spend has been seen, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsDoubleSpendSeen(isDoubleSpendSeen: boolean ): MoneroTx { + this.isDoubleSpendSeen = isDoubleSpendSeen; + return this; + } + + /** + * @return {string} tx key + */ + getKey(): string { + return this.key; + } + + /** + * @param {string} key - tx key + * @return {MoneroTx} this tx for chaining + */ + setKey(key: string): MoneroTx { + this.key = key; + return this; + } + + /** + * Get full transaction hex. Full hex = pruned hex + prunable hex. + * + * @return {string|undefined} full tx hex + */ + getFullHex(): string|undefined { + return this.fullHex; + } + + /** + * @param {string} fullHex - full tx hex + * @return {MoneroTx} this tx for chaining + */ + setFullHex(fullHex: string): MoneroTx { + this.fullHex = fullHex; + return this; + } + + /** + * Get pruned transaction hex. Full hex = pruned hex + prunable hex. + * + * @return {string} pruned tx hex + */ + getPrunedHex(): string { + return this.prunedHex; + } + + /** + * @param {string} prunedHex - pruned tx hex + * @return {MoneroTx} this tx for chaining + */ + setPrunedHex(prunedHex: string): MoneroTx { + this.prunedHex = prunedHex; + return this; + } + + /** + * Get prunable transaction hex which is hex that is removed from a pruned + * transaction. Full hex = pruned hex + prunable hex. + * + * @return {string} prunable tx hex + */ + getPrunableHex(): string { + return this.prunableHex; + } + + /** + * @param {string} prunableHex - prunable tx hex + * @return {MoneroTx} this tx for chaining + */ + setPrunableHex(prunableHex: string): MoneroTx { + this.prunableHex = prunableHex; + return this; + } + + /** + * @return {string} prunable tx hash + */ + getPrunableHash(): string { + return this.prunableHash; + } + + /** + * @param {string} prunableHash - prunable tx hash + * @return {MoneroTx} this tx for chaining + */ + setPrunableHash(prunableHash: string): MoneroTx { + this.prunableHash = prunableHash; + return this; + } + + /** + * @return {number} tx size + */ + getSize(): number { + return this.size; + } + + /** + * @param {number} size - tx size + * @return {MoneroTx} this tx for chaining + */ + setSize(size: number): MoneroTx { + this.size = size; + return this; + } + + /** + * @return {number} tx weight + */ + getWeight(): number { + return this.weight; + } + + /** + * @param {number} weight - tx weight + * @return {MoneroTx} this tx for chaining + */ + setWeight(weight: number): MoneroTx { + this.weight = weight; + return this; + } + + /** + * @return {MoneroOutput[]} tx inputs + */ + getInputs(): MoneroOutput[] { + return this.inputs; + } + + /** + * @param {MoneroOutput[]} - tx inputs + * @return {MoneroTx} this tx for chaining + */ + setInputs(inputs: MoneroOutput[]): MoneroTx { + this.inputs = inputs; + return this; + } + + /** + * @return {MoneroOutput[]} tx outputs + */ + getOutputs(): MoneroOutput[] { + return this.outputs; + } + + /** + * @param {MoneroOutput[]} outputs - tx outputs + * @return {MoneroTx} this tx for chaining + */ + setOutputs(outputs: MoneroOutput[]): MoneroTx { + this.outputs = outputs; + return this; + } + + /** + * @return {number[]} tx output indices + */ + getOutputIndices(): number[] { + return this.outputIndices; + } + + /** + * @param {number[]} outputIndices - tx output indices + * @return {MoneroTx} this tx for chaining + */ + setOutputIndices(outputIndices: number[]): MoneroTx { + this.outputIndices = outputIndices; + return this; + } + + /** + * @return {string} tx metadata + */ + getMetadata(): string { + return this.metadata; + } + + /** + * @param {string} metadata - tx metadata + * @return {MoneroTx} this tx for chaining + */ + setMetadata(metadata: string): MoneroTx { + this.metadata = metadata; + return this; + } + + /** + * @return {Uint8Array} tx extra + */ + getExtra(): Uint8Array { + return this.extra; + } + + /** + * @param {Uint8Array} extra - tx extra + * @return {MoneroTx} this tx for chaining + */ + setExtra(extra: Uint8Array): MoneroTx { + this.extra = extra; + return this; + } + + /** + * @return {any} RCT signatures + */ + getRctSignatures(): any { + return this.rctSignatures; + } + + /** + * @param {any} rctSignatures - RCT signatures + * @return {MoneroTx} this tx for chaining + */ + setRctSignatures(rctSignatures: any): MoneroTx { + this.rctSignatures = rctSignatures; + return this; + } + + /** + * @return {any} prunable RCT signature data + */ + getRctSigPrunable(): object { + return this.rctSigPrunable; + } + + /** + * @param {any} rctSigPrunable - prunable RCT signature data + * @return {MoneroTx} this tx for chaining + */ + setRctSigPrunable(rctSigPrunable: any): MoneroTx { + this.rctSigPrunable = rctSigPrunable; + return this; + } + + /** + * @return {boolean} true if kept by a block, false otherwise + */ + getIsKeptByBlock(): boolean { + return this.isKeptByBlock; + } + + /** + * @param {boolean} isKeptByBlock - true if kept by a block, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsKeptByBlock(isKeptByBlock: boolean): MoneroTx { + this.isKeptByBlock = isKeptByBlock; + return this; + } + + /** + * @return {boolean} true if the tx failed, false otherwise + */ + getIsFailed(): boolean { + return this.isFailed; + } + + /** + * @param {boolean} isFailed - true if the tx failed, false otherwise + * @return {MoneroTx} this tx for chaining + */ + setIsFailed(isFailed: boolean): MoneroTx { + this.isFailed = isFailed; + return this; + } + + /** + * @return {number} block height of the last tx failure + */ + getLastFailedHeight(): number { + return this.lastFailedHeight; + } + + /** + * @param {number} lastFailedHeight - block height of the last tx failure + * @return {MoneroTx} this tx for chaining + */ + setLastFailedHeight(lastFailedHeight: number): MoneroTx { + this.lastFailedHeight = lastFailedHeight; + return this; + } + + /** + * @return {string} block hash of the last tx failure + */ + getLastFailedHash(): string { + return this.lastFailedHash; + } + + /** + * @param {string} lastFailedHash - block hash of the last tx failure + * @return {MoneroTx} this tx for chaining + */ + setLastFailedHash(lastFailedHash: string): MoneroTx { + this.lastFailedHash = lastFailedHash; + return this; + } + + /** + * @return {number} max used block height + */ + getMaxUsedBlockHeight(): number { + return this.maxUsedBlockHeight; + } + + /** + * @param {number} maxUsedBlockHeight - max used block height + * @return {MoneroTx} this tx for chaining + */ + setMaxUsedBlockHeight(maxUsedBlockHeight: number): MoneroTx { + this.maxUsedBlockHeight = maxUsedBlockHeight; + return this; + } + + /** + * @return {string} max used block hash + */ + getMaxUsedBlockHash(): string { + return this.maxUsedBlockHash; + } + + /** + * @param {string} maxUsedBlockHash - max used block hash + * @return {MoneroTx} this tx for chaining + */ + setMaxUsedBlockHash(maxUsedBlockHash: string): MoneroTx { + this.maxUsedBlockHash = maxUsedBlockHash; + return this; + } + + /** + * @return {string[]} tx signatures + */ + getSignatures(): string[] { + return this.signatures; + } + + /** + * @param {string[]} signatures - tx signatures + * @return {MoneroTx} this tx for chaining + */ + setSignatures(signatures: string[]): MoneroTx { + this.signatures = signatures; + return this; + } + + /** + * @return {MoneroTx} a copy of this tx + */ + copy(): MoneroTx { + return new MoneroTx(this); + } + + /** + * @return {any} json representation of this tx + */ + toJson(): any { + let json: any = Object.assign({}, this); + if (this.getFee() !== undefined) json.fee = this.getFee().toString(); + if (this.getUnlockTime() !== undefined) json.unlockTime = this.getUnlockTime().toString(); + if (this.getInputs()) { + json.inputs = []; + for (let input of this.getInputs()) json.inputs.push(input.toJson()); + } + if (this.getOutputs()) { + json.outputs = []; + for (let output of this.getOutputs()) json.outputs.push(output.toJson()); + } + if (this.getExtra() !== undefined) json.extra = Array.from(this.getExtra(), byte => byte); + delete json.block; // do not serialize parent block + return json; + } + + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * @param {MoneroTx} tx - the transaction to update this transaction with + * @return {MoneroTx} this for method chaining + */ + merge(tx: MoneroTx): MoneroTx { + assert(tx instanceof MoneroTx); + if (this === tx) return this; + + // merge blocks if they're different + if (this.getBlock() !== tx.getBlock()) { + if (this.getBlock() === undefined) { + this.setBlock(tx.getBlock()); + this.getBlock().getTxs[this.getBlock().getTxs().indexOf(tx)] = this; // update block to point to this tx + } else if (tx.getBlock() !== undefined) { + this.getBlock().merge(tx.getBlock()); // comes back to merging txs + return this; + } + } + + // otherwise merge tx fields + this.setHash(GenUtils.reconcile(this.getHash(), tx.getHash())); + this.setVersion(GenUtils.reconcile(this.getVersion(), tx.getVersion())); + this.setPaymentId(GenUtils.reconcile(this.getPaymentId(), tx.getPaymentId())); + this.setFee(GenUtils.reconcile(this.getFee(), tx.getFee())); + this.setRingSize(GenUtils.reconcile(this.getRingSize(), tx.getRingSize())); + this.setIsConfirmed(GenUtils.reconcile(this.getIsConfirmed(), tx.getIsConfirmed(), {resolveTrue: true})); // tx can become confirmed + this.setIsMinerTx(GenUtils.reconcile(this.getIsMinerTx(), tx.getIsMinerTx())); + this.setRelay(GenUtils.reconcile(this.getRelay(), tx.getRelay(), {resolveTrue: true})); // tx can become relayed + this.setIsRelayed(GenUtils.reconcile(this.getIsRelayed(), tx.getIsRelayed(), {resolveTrue: true})); // tx can become relayed + this.setIsDoubleSpendSeen(GenUtils.reconcile(this.getIsDoubleSpendSeen(), tx.getIsDoubleSpendSeen(), {resolveTrue: true})); // double spend can become seen + this.setKey(GenUtils.reconcile(this.getKey(), tx.getKey())); + this.setFullHex(GenUtils.reconcile(this.getFullHex(), tx.getFullHex())); + this.setPrunedHex(GenUtils.reconcile(this.getPrunedHex(), tx.getPrunedHex())); + this.setPrunableHex(GenUtils.reconcile(this.getPrunableHex(), tx.getPrunableHex())); + this.setPrunableHash(GenUtils.reconcile(this.getPrunableHash(), tx.getPrunableHash())); + this.setSize(GenUtils.reconcile(this.getSize(), tx.getSize())); + this.setWeight(GenUtils.reconcile(this.getWeight(), tx.getWeight())); + this.setOutputIndices(GenUtils.reconcile(this.getOutputIndices(), tx.getOutputIndices())); + this.setMetadata(GenUtils.reconcile(this.getMetadata(), tx.getMetadata())); + this.setExtra(GenUtils.reconcile(this.getExtra(), tx.getExtra())); + this.setRctSignatures(GenUtils.reconcile(this.getRctSignatures(), tx.getRctSignatures())); + this.setRctSigPrunable(GenUtils.reconcile(this.getRctSigPrunable(), tx.getRctSigPrunable())); + this.setIsKeptByBlock(GenUtils.reconcile(this.getIsKeptByBlock(), tx.getIsKeptByBlock())); + this.setIsFailed(GenUtils.reconcile(this.getIsFailed(), tx.getIsFailed(), {resolveTrue: true})); + this.setLastFailedHeight(GenUtils.reconcile(this.getLastFailedHeight(), tx.getLastFailedHeight())); + this.setLastFailedHash(GenUtils.reconcile(this.getLastFailedHash(), tx.getLastFailedHash())); + this.setMaxUsedBlockHeight(GenUtils.reconcile(this.getMaxUsedBlockHeight(), tx.getMaxUsedBlockHeight())); + this.setMaxUsedBlockHash(GenUtils.reconcile(this.getMaxUsedBlockHash(), tx.getMaxUsedBlockHash())); + this.setSignatures(GenUtils.reconcile(this.getSignatures(), tx.getSignatures())); + this.setUnlockTime(GenUtils.reconcile(this.getUnlockTime(), tx.getUnlockTime())); + this.setNumConfirmations(GenUtils.reconcile(this.getNumConfirmations(), tx.getNumConfirmations(), {resolveMax: true})); // num confirmations can increase + + // merge inputs + if (tx.getInputs()) { + for (let merger of tx.getInputs()) { + let merged = false; + merger.setTx(this); + if (!this.getInputs()) this.setInputs([]); + for (let mergee of this.getInputs()) { + if (mergee.getKeyImage().getHex() === merger.getKeyImage().getHex()) { + mergee.merge(merger); + merged = true; + break; + } + } + if (!merged) this.getInputs().push(merger); + } + } + + // merge outputs + if (tx.getOutputs()) { + for (let output of tx.getOutputs()) output.setTx(this); + if (!this.getOutputs()) this.setOutputs(tx.getOutputs()); + else { + + // merge outputs if key image or stealth public key present, otherwise append + for (let merger of tx.getOutputs()) { + let merged = false; + merger.setTx(this); + for (let mergee of this.getOutputs()) { + if ((merger.getKeyImage() && mergee.getKeyImage().getHex() === merger.getKeyImage().getHex()) || + (merger.getStealthPublicKey() && mergee.getStealthPublicKey() === merger.getStealthPublicKey())) { + mergee.merge(merger); + merged = true; + break; + } + } + if (!merged) this.getOutputs().push(merger); // append output + } + } + } + + // handle unrelayed -> relayed -> confirmed + if (this.getIsConfirmed()) { + this.setInTxPool(false); + this.setReceivedTimestamp(undefined); + this.setLastRelayedTimestamp(undefined); + } else { + this.setInTxPool(GenUtils.reconcile(this.getInTxPool(), tx.getInTxPool(), {resolveTrue: true})); // unrelayed -> tx pool + this.setReceivedTimestamp(GenUtils.reconcile(this.getReceivedTimestamp(), tx.getReceivedTimestamp(), {resolveMax: false})); // take earliest receive time + this.setLastRelayedTimestamp(GenUtils.reconcile(this.getLastRelayedTimestamp(), tx.getLastRelayedTimestamp(), {resolveMax: true})); // take latest relay time + } + + return this; // for chaining + } + + /** + * @param {number} [indent] - starting indentation + * @return {string} string representation of this tx + */ + toString(indent = 0): string { + let str = ""; + str += GenUtils.getIndent(indent) + "=== TX ===\n"; + str += GenUtils.kvLine("Tx hash", this.getHash(), indent); + str += GenUtils.kvLine("Height", this.getHeight(), indent); + str += GenUtils.kvLine("Version", this.getVersion(), indent); + str += GenUtils.kvLine("Is miner tx", this.getIsMinerTx(), indent); + str += GenUtils.kvLine("Payment ID", this.getPaymentId(), indent); + str += GenUtils.kvLine("Fee", this.getFee(), indent); + str += GenUtils.kvLine("Ring size", this.getRingSize(), indent); + str += GenUtils.kvLine("Relay", this.getRelay(), indent); + str += GenUtils.kvLine("Is relayed", this.getIsRelayed(), indent); + str += GenUtils.kvLine("Is confirmed", this.getIsConfirmed(), indent); + str += GenUtils.kvLine("In tx pool", this.getInTxPool(), indent); + str += GenUtils.kvLine("Num confirmations", this.getNumConfirmations(), indent); + str += GenUtils.kvLine("Unlock time", this.getUnlockTime(), indent); + str += GenUtils.kvLine("Last relayed time", this.getLastRelayedTimestamp(), indent); + str += GenUtils.kvLine("Received time", this.getReceivedTimestamp(), indent); + str += GenUtils.kvLine("Is double spend", this.getIsDoubleSpendSeen(), indent); + str += GenUtils.kvLine("Key", this.getKey(), indent); + str += GenUtils.kvLine("Full hex", this.getFullHex(), indent); + str += GenUtils.kvLine("Pruned hex", this.getPrunedHex(), indent); + str += GenUtils.kvLine("Prunable hex", this.getPrunableHex(), indent); + str += GenUtils.kvLine("Prunable hash", this.getPrunableHash(), indent); + str += GenUtils.kvLine("Size", this.getSize(), indent); + str += GenUtils.kvLine("Weight", this.getWeight(), indent); + str += GenUtils.kvLine("Output indices", this.getOutputIndices(), indent); + str += GenUtils.kvLine("Metadata", this.getMetadata(), indent); + str += GenUtils.kvLine("Extra", this.getExtra(), indent); + str += GenUtils.kvLine("RCT signatures", this.getRctSignatures(), indent); + str += GenUtils.kvLine("RCT sig prunable", this.getRctSigPrunable(), indent); + str += GenUtils.kvLine("Kept by block", this.getIsKeptByBlock(), indent); + str += GenUtils.kvLine("Is failed", this.getIsFailed(), indent); + str += GenUtils.kvLine("Last failed height", this.getLastFailedHeight(), indent); + str += GenUtils.kvLine("Last failed hash", this.getLastFailedHash(), indent); + str += GenUtils.kvLine("Max used block height", this.getMaxUsedBlockHeight(), indent); + str += GenUtils.kvLine("Max used block hash", this.getMaxUsedBlockHash(), indent); + str += GenUtils.kvLine("Signatures", this.getSignatures(), indent); + if (this.getInputs() !== undefined) { + str += GenUtils.kvLine("Inputs", "", indent); + for (let i = 0; i < this.getInputs().length; i++) { + str += GenUtils.kvLine(i + 1, "", indent + 1); + str += this.getInputs()[i].toString(indent + 2); + str += '\n' + } + } + if (this.getOutputs() !== undefined) { + str += GenUtils.kvLine("Outputs", "", indent); + for (let i = 0; i < this.getOutputs().length; i++) { + str += GenUtils.kvLine(i + 1, "", indent + 1); + str += this.getOutputs()[i].toString(indent + 2); + str += '\n' + } + } + return str.slice(0, str.length - 1); // strip last newline + } +} diff --git a/src/main/ts/daemon/model/MoneroTxPoolStats.ts b/src/main/ts/daemon/model/MoneroTxPoolStats.ts new file mode 100644 index 000000000..ffa348684 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroTxPoolStats.ts @@ -0,0 +1,149 @@ +/** + * Models transaction pool statistics. + */ +export default class MoneroTxPoolStats { + + numTxs: number; + numNotRelayed: number; + numFailing: number; + numDoubleSpends: number; + num10m: number; + feeTotal: bigint; + bytesMax: number; + bytesMed: number; + bytesMin: number; + bytesTotal: number; + histo: Map; + histo98pc: number; + oldestTimestamp: number; + + constructor(stats?: Partial) { + Object.assign(this, stats); + if (this.feeTotal !== undefined && typeof this.feeTotal !== "bigint") this.feeTotal = BigInt(this.feeTotal); + if (this.histo !== undefined && !(this.histo instanceof Map)) this.histo = new Map(JSON.parse(this.histo)); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (json.feeTotal) json.feeTotal = json.feeTotal.toString(); + if (json.histo) json.histo = JSON.stringify([...json.histo]); // convert map to array of key-value pairs then stringify + return json; + } + + getNumTxs(): number { + return this.numTxs; + } + + setNumTxs(numTxs: number): MoneroTxPoolStats { + this.numTxs = numTxs; + return this; + } + + getNumNotRelayed(): number { + return this.numNotRelayed; + } + + setNumNotRelayed(numNotRelayed: number): MoneroTxPoolStats { + this.numNotRelayed = numNotRelayed; + return this; + } + + getNumFailing(): number { + return this.numFailing; + } + + setNumFailing(numFailing: number): MoneroTxPoolStats { + this.numFailing = numFailing; + return this; + } + + getNumDoubleSpends(): number { + return this.numDoubleSpends; + } + + setNumDoubleSpends(numDoubleSpends: number): MoneroTxPoolStats { + this.numDoubleSpends = numDoubleSpends; + return this; + } + + getNum10m(): number { + return this.num10m; + } + + setNum10m(num10m): MoneroTxPoolStats { + this.num10m = num10m; + return this; + } + + getFeeTotal(): bigint { + return this.feeTotal; + } + + setFeeTotal(feeTotal: bigint): MoneroTxPoolStats { + this.feeTotal = feeTotal; + return this; + } + + getBytesMax(): number { + return this.bytesMax; + } + + setBytesMax(bytesMax: number): MoneroTxPoolStats { + this.bytesMax = bytesMax; + return this; + } + + getBytesMed(): number { + return this.bytesMed; + } + + setBytesMed(bytesMed: number): MoneroTxPoolStats { + this.bytesMed = bytesMed; + return this; + } + + getBytesMin(): number { + return this.bytesMin; + } + + setBytesMin(bytesMin: number): MoneroTxPoolStats { + this.bytesMin = bytesMin; + return this; + } + + getBytesTotal(): number { + return this.bytesTotal; + } + + setBytesTotal(bytesTotal: number): MoneroTxPoolStats { + this.bytesTotal = bytesTotal; + return this; + } + + getHisto(): Map { + return this.histo; + } + + setHisto(histo: Map): MoneroTxPoolStats { + this.histo = histo; + return this; + } + + getHisto98pc(): number { + return this.histo98pc; + } + + setHisto98pc(histo98pc: number): MoneroTxPoolStats { + this.histo98pc = histo98pc; + return this; + } + + getOldestTimestamp(): number { + return this.oldestTimestamp; + } + + setOldestTimestamp(oldestTimestamp: number): MoneroTxPoolStats { + this.oldestTimestamp = oldestTimestamp; + return this; + } +} diff --git a/src/main/ts/daemon/model/MoneroVersion.ts b/src/main/ts/daemon/model/MoneroVersion.ts new file mode 100644 index 000000000..ce66d6102 --- /dev/null +++ b/src/main/ts/daemon/model/MoneroVersion.ts @@ -0,0 +1,39 @@ +/** + * Models a Monero version. + */ +export default class MoneroVersion { + + number: number; + isRelease: boolean; + + constructor(number: number, isRelease: boolean) { + this.number = number; + this.isRelease = isRelease; + } + + getNumber(): number { + return this.number; + } + + setNumber(number: number): MoneroVersion { + this.number = number; + return this; + } + + getIsRelease(): boolean { + return this.isRelease; + } + + setIsRelease(isRelease: boolean): MoneroVersion { + this.isRelease = isRelease; + return this; + } + + copy(): MoneroVersion { + return new MoneroVersion(this.number, this.isRelease); + } + + toJson(): any { + return Object.assign({}, this); + } +} diff --git a/src/main/ts/wallet/MoneroWallet.ts b/src/main/ts/wallet/MoneroWallet.ts new file mode 100644 index 000000000..3e6fc2ebc --- /dev/null +++ b/src/main/ts/wallet/MoneroWallet.ts @@ -0,0 +1,1547 @@ +import assert from "assert"; +import GenUtils from "../common/GenUtils"; +import MoneroAccount from "./model/MoneroAccount"; +import MoneroAccountTag from "./model/MoneroAccountTag"; +import MoneroAddressBookEntry from "./model/MoneroAddressBookEntry"; +import MoneroBlock from "../daemon/model/MoneroBlock"; +import MoneroCheckReserve from "./model/MoneroCheckReserve"; +import MoneroCheckTx from "./model/MoneroCheckTx"; +import MoneroConnectionManager from "../common/MoneroConnectionManager"; +import MoneroConnectionManagerListener from "../common/MoneroConnectionManagerListener"; +import MoneroError from "../common/MoneroError"; +import MoneroIncomingTransfer from "./model/MoneroIncomingTransfer"; +import MoneroIntegratedAddress from "./model/MoneroIntegratedAddress"; +import MoneroKeyImage from "../daemon/model/MoneroKeyImage"; +import MoneroKeyImageImportResult from "./model/MoneroKeyImageImportResult"; +import MoneroMessageSignatureResult from "./model/MoneroMessageSignatureResult"; +import MoneroMessageSignatureType from "./model/MoneroMessageSignatureType"; +import MoneroMultisigInfo from "./model/MoneroMultisigInfo"; +import MoneroMultisigInitResult from "./model/MoneroMultisigInitResult"; +import MoneroMultisigSignResult from "./model/MoneroMultisigSignResult"; +import MoneroOutputQuery from "./model/MoneroOutputQuery"; +import MoneroOutputWallet from "./model/MoneroOutputWallet"; +import MoneroOutgoingTransfer from "./model/MoneroOutgoingTransfer"; +import MoneroRpcConnection from "../common/MoneroRpcConnection"; +import MoneroSubaddress from "./model/MoneroSubaddress"; +import MoneroSyncResult from "./model/MoneroSyncResult"; +import MoneroTransfer from "./model/MoneroTransfer"; +import MoneroTransferQuery from "./model/MoneroTransferQuery"; +import MoneroTxConfig from "./model/MoneroTxConfig"; +import MoneroTxPriority from "./model/MoneroTxPriority"; +import MoneroTxQuery from "./model/MoneroTxQuery"; +import MoneroTxWallet from "./model/MoneroTxWallet"; +import MoneroTxSet from "./model/MoneroTxSet"; +import MoneroUtils from "../common/MoneroUtils"; +import MoneroVersion from "../daemon/model/MoneroVersion"; +import MoneroWalletListener from "./model/MoneroWalletListener"; + +/** + * Copyright (c) woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Monero wallet interface and default implementations. + * + * @interface + */ +export default class MoneroWallet { + + // static variables + static readonly DEFAULT_LANGUAGE = "English"; + + // state variables + protected connectionManager: MoneroConnectionManager; + protected connectionManagerListener: MoneroConnectionManagerListener; + protected listeners: MoneroWalletListener[] = []; + protected _isClosed = false; + + /** + * Hidden constructor. + * + * @private + */ + constructor() { + // no code needed + } + + /** + * Register a listener to receive wallet notifications. + * + * @param {MoneroWalletListener} listener - listener to receive wallet notifications + * @return {Promise} + */ + async addListener(listener: MoneroWalletListener): Promise { + assert(listener instanceof MoneroWalletListener, "Listener must be instance of MoneroWalletListener"); + this.listeners.push(listener); + } + + /** + * Unregister a listener to receive wallet notifications. + * + * @param {MoneroWalletListener} listener - listener to unregister + * @return {Promise} + */ + async removeListener(listener): Promise { + let idx = this.listeners.indexOf(listener); + if (idx > -1) this.listeners.splice(idx, 1); + else throw new MoneroError("Listener is not registered with wallet"); + } + + /** + * Get the listeners registered with the wallet. + * + * @return {MoneroWalletListener[]} the registered listeners + */ + getListeners(): MoneroWalletListener[] { + return this.listeners; + } + + /** + * Indicates if the wallet is view-only, meaning it does not have the private + * spend key and can therefore only observe incoming outputs. + * + * @return {Promise} true if the wallet is view-only, false otherwise + */ + async isViewOnly(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Set the wallet's daemon connection. + * + * @param {MoneroRpcConnection | string} [uriOrConnection] - daemon's URI or connection (defaults to offline) + * @return {Promise} + */ + async setDaemonConnection(uriOrConnection?: MoneroRpcConnection | string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the wallet's daemon connection. + * + * @return {Promise} the wallet's daemon connection + */ + async getDaemonConnection(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Set the wallet's daemon connection manager. + * + * @param {MoneroConnectionManager} connectionManager manages connections to monerod + * @return {Promise} + */ + async setConnectionManager(connectionManager?: MoneroConnectionManager): Promise { + if (this.connectionManager) this.connectionManager.removeListener(this.connectionManagerListener); + this.connectionManager = connectionManager; + if (!connectionManager) return; + let that = this; + if (!this.connectionManagerListener) this.connectionManagerListener = new class extends MoneroConnectionManagerListener { + async onConnectionChanged(connection: MoneroRpcConnection | undefined) { + await that.setDaemonConnection(connection); + } + }; + connectionManager.addListener(this.connectionManagerListener); + await this.setDaemonConnection(connectionManager.getConnection()); + } + + /** + * Get the wallet's daemon connection manager. + * + * @return {Promise} the wallet's daemon connection manager + */ + async getConnectionManager(): Promise { + return this.connectionManager; + } + + /** + * Indicates if the wallet is connected to daemon. + * + * @return {Promise} true if the wallet is connected to a daemon, false otherwise + */ + async isConnectedToDaemon(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Gets the version of the wallet. + * + * @return {Promise} the version of the wallet + */ + async getVersion(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the wallet's path. + * + * @return {Promise} the path the wallet can be opened with + */ + async getPath(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the wallet's mnemonic phrase or seed. + * + * @return {Promise} the wallet's mnemonic phrase or seed. + */ + async getSeed(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the language of the wallet's mnemonic phrase or seed. + * + * @return {Promise} the language of the wallet's mnemonic phrase or seed. + */ + async getSeedLanguage(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the wallet's private view key. + * + * @return {Promise} the wallet's private view key + */ + async getPrivateViewKey(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the wallet's private spend key. + * + * @return {Promise} the wallet's private spend key + */ + async getPrivateSpendKey(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the wallet's public view key. + * + * @return {Promise} the wallet's public view key + */ + async getPublicViewKey(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the wallet's public spend key. + * + * @return {Promise} the wallet's public spend key + */ + async getPublicSpendKey(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the wallet's primary address. + * + * @return {Promise} the wallet's primary address + */ + async getPrimaryAddress(): Promise { + return await this.getAddress(0, 0); + } + + /** + * Get the address of a specific subaddress. + * + * @param {number} accountIdx - the account index of the address's subaddress + * @param {number} subaddressIdx - the subaddress index within the account + * @return {Promise} the receive address of the specified subaddress + */ + async getAddress(accountIdx: number, subaddressIdx: number): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the account and subaddress index of the given address. + * + * @param {string} address - address to get the account and subaddress index from + * @return {Promise} the account and subaddress indices + */ + async getAddressIndex(address: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get an integrated address based on the given standard address and payment + * ID. Uses the wallet's primary address if an address is not given. + * Generates a random payment ID if a payment ID is not given. + * + * @param {string} standardAddress is the standard address to generate the integrated address from (wallet's primary address if undefined) + * @param {string} paymentId is the payment ID to generate an integrated address from (randomly generated if undefined) + * @return {Promise} the integrated address + */ + async getIntegratedAddress(standardAddress?: string, paymentId?: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Decode an integrated address to get its standard address and payment id. + * + * @param {string} integratedAddress - integrated address to decode + * @return {Promise} the decoded integrated address including standard address and payment id + */ + async decodeIntegratedAddress(integratedAddress: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the block height that the wallet is synced to. + * + * @return {Promise} the block height that the wallet is synced to + */ + async getHeight(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the blockchain's height. + * + * @return {Promise} the blockchain's height + */ + async getDaemonHeight(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the blockchain's height by date as a conservative estimate for scanning. + * + * @param {number} year - year of the height to get + * @param {number} month - month of the height to get as a number between 1 and 12 + * @param {number} day - day of the height to get as a number between 1 and 31 + * @return {Promise} the blockchain's approximate height at the given date + */ + async getHeightByDate(year: number, month: number, day: number): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Synchronize the wallet with the daemon as a one-time synchronous process. + * + * @param {MoneroWalletListener|number} [listenerOrStartHeight] - listener xor start height (defaults to no sync listener, the last synced block) + * @param {number} [startHeight] - startHeight if not given in first arg (defaults to last synced block) + * @return {Promise} + */ + async sync(listenerOrStartHeight?: MoneroWalletListener | number, startHeight?: number): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Start background synchronizing with a maximum period between syncs. + * + * @param {number} [syncPeriodInMs] - maximum period between syncs in milliseconds (default is wallet-specific) + * @return {Promise} + */ + async startSyncing(syncPeriodInMs?: number): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Stop synchronizing the wallet with the daemon. + * + * @return {Promise} + */ + async stopSyncing(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Scan transactions by their hash/id. + * + * @param {string[]} txHashes - tx hashes to scan + * @return {Promise} + */ + async scanTxs(txHashes: string[]): Promise { + throw new MoneroError("Not supported"); + } + + /** + *

Rescan the blockchain for spent outputs.

+ * + *

Note: this can only be called with a trusted daemon.

+ * + *

Example use case: peer multisig hex is import when connected to an untrusted daemon, + * so the wallet will not rescan spent outputs. Then the wallet connects to a trusted + * daemon. This method should be manually invoked to rescan outputs.

+ * + * @return {Promise} + */ + async rescanSpent(): Promise { + throw new MoneroError("Not supported"); + } + + /** + *

Rescan the blockchain from scratch, losing any information which cannot be recovered from + * the blockchain itself.

+ * + *

WARNING: This method discards local wallet data like destination addresses, tx secret keys, + * tx notes, etc.

+ * + * @return {Promise} + */ + async rescanBlockchain(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the balance of the wallet, account, or subaddress. + * + * @param {number} [accountIdx] - index of the account to get the balance of (default all accounts) + * @param {number} [subaddressIdx] - index of the subaddress to get the balance of (default all subaddresses) + * @return {Promise} the balance of the wallet, account, or subaddress + */ + async getBalance(accountIdx?: number, subaddressIdx?: number): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the unlocked balance of the wallet, account, or subaddress. + * + * @param {number} [accountIdx] - index of the account to get the unlocked balance of (optional) + * @param {number} [subaddressIdx] - index of the subaddress to get the unlocked balance of (optional) + * @return {Promise} the unlocked balance of the wallet, account, or subaddress + */ + async getUnlockedBalance(accountIdx?: number, subaddressIdx?: number): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the number of blocks until the next and last funds unlock. Ignores txs with unlock time as timestamp. + * + * @return {Promise} the number of blocks until the next and last funds unlock in elements 0 and 1, respectively, or undefined if no balance + */ + async getNumBlocksToUnlock(): Promise { + + // get balances + let balance = await this.getBalance(); + if (balance === 0n) return [undefined, undefined]; // skip if no balance + let unlockedBalance = await this.getUnlockedBalance(); + + // compute number of blocks until next funds available + let txs: MoneroTxWallet[]; + let height: number; + let numBlocksToNextUnlock = undefined; + if (unlockedBalance > 0n) numBlocksToNextUnlock = 0; + else { + txs = await this.getTxs({isLocked: true}); // get locked txs + height = await this.getHeight(); // get most recent height + for (let tx of txs) { + if (!tx.getIsConfirmed() && MoneroUtils.isTimestamp(tx.getUnlockTime())) continue; + let numBlocksToUnlock = Math.max((tx.getIsConfirmed() ? tx.getHeight() : height) + 10, Number(tx.getUnlockTime())) - height; + numBlocksToNextUnlock = numBlocksToNextUnlock === undefined ? numBlocksToUnlock : Math.min(numBlocksToNextUnlock, numBlocksToUnlock); + } + } + + // compute number of blocks until all funds available + let numBlocksToLastUnlock = undefined; + if (balance === unlockedBalance) { + if (unlockedBalance > 0n) numBlocksToLastUnlock = 0; + } else { + if (!txs) { + txs = await this.getTxs({isLocked: true}); // get locked txs + height = await this.getHeight(); // get most recent height + } + for (let tx of txs) { + if (!tx.getIsConfirmed() && MoneroUtils.isTimestamp(tx.getUnlockTime())) continue; + let numBlocksToUnlock = Math.max((tx.getIsConfirmed() ? tx.getHeight() : height) + 10, Number(tx.getUnlockTime())) - height; + numBlocksToLastUnlock = numBlocksToLastUnlock === undefined ? numBlocksToUnlock : Math.max(numBlocksToLastUnlock, numBlocksToUnlock); + } + } + + return [numBlocksToNextUnlock, numBlocksToLastUnlock]; + } + + /** + * Get accounts with a given tag. + * + * @param {boolean} includeSubaddresses - include subaddresses if true + * @param {string} tag - tag for filtering accounts, all accounts if undefined + * @return {Promise} all accounts with the given tag + */ + async getAccounts(includeSubaddresses?: boolean, tag?: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get an account. + * + * @param {number} accountIdx - index of the account to get + * @param {boolean} includeSubaddresses - include subaddresses if true + * @return {Promise} the retrieved account + */ + async getAccount(accountIdx: number, includeSubaddresses?: boolean): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Create a new account with a label for the first subaddress. + * + * @param {string} [label] - label for account's first subaddress (optional) + * @return {Promise} the created account + */ + async createAccount(label?: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Set an account label. + * + * @param {number} accountIdx - index of the account to set the label for + * @param {string} label - the label to set + * @return {Promise} + */ + async setAccountLabel(accountIdx: number, label: string): Promise { + await this.setSubaddressLabel(accountIdx, 0, label); + } + + /** + * Get subaddresses in an account. + * + * @param {number} accountIdx - account to get subaddresses within + * @param {number[]} [subaddressIndices] - indices of subaddresses to get (optional) + * @return {Promise} the retrieved subaddresses + */ + async getSubaddresses(accountIdx: number, subaddressIndices?: number[]): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get a subaddress. + * + * @param {number} accountIdx - index of the subaddress's account + * @param {number} subaddressIdx - index of the subaddress within the account + * @return {Promise} the retrieved subaddress + */ + async getSubaddress(accountIdx: number, subaddressIdx: number): Promise { + assert(accountIdx >= 0); + assert(subaddressIdx >= 0); + return (await this.getSubaddresses(accountIdx, [subaddressIdx]))[0]; + } + + /** + * Create a subaddress within an account. + * + * @param {number} accountIdx - index of the account to create the subaddress within + * @param {string} [label] - the label for the subaddress (optional) + * @return {Promise} the created subaddress + */ + async createSubaddress(accountIdx: number, label?: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Set a subaddress label. + * + * @param {number} accountIdx - index of the account to set the label for + * @param {number} subaddressIdx - index of the subaddress to set the label for + * @param {Promise} label - the label to set + */ + async setSubaddressLabel(accountIdx: number, subaddressIdx: number, label: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get a wallet transaction by hash. + * + * @param {string} txHash - hash of a transaction to get + * @return {Promise } the identified transaction or undefined if not found + */ + async getTx(txHash: string): Promise { + let txs = await this.getTxs([txHash]); + return txs.length === 0 ? undefined : txs[0]; + } + + /** + *

Get wallet transactions. Wallet transactions contain one or more + * transfers that are either incoming or outgoing to the wallet.

+ * + *

Results can be filtered by passing a query object. Transactions must + * meet every criteria defined in the query in order to be returned. All + * criteria are optional and no filtering is applied when not defined.

+ * + * @param {string[] | MoneroTxQuery} [query] - configures the query (optional) + * @param {boolean} [query.isConfirmed] - get txs that are confirmed or not (optional) + * @param {boolean} [query.inTxPool] - get txs that are in the tx pool or not (optional) + * @param {boolean} [query.isRelayed] - get txs that are relayed or not (optional) + * @param {boolean} [query.isFailed] - get txs that are failed or not (optional) + * @param {boolean} [query.isMinerTx] - get miner txs or not (optional) + * @param {string} [query.hash] - get a tx with the hash (optional) + * @param {string[]} [query.hashes] - get txs with the hashes (optional) + * @param {string} [query.paymentId] - get transactions with the payment id (optional) + * @param {string[]} [query.paymentIds] - get transactions with the payment ids (optional) + * @param {boolean} [query.hasPaymentId] - get transactions with a payment id or not (optional) + * @param {number} [query.minHeight] - get txs with height >= the given height (optional) + * @param {number} [query.maxHeight] - get txs with height <= the given height (optional) + * @param {boolean} [query.isOutgoing] - get txs with an outgoing transfer or not (optional) + * @param {boolean} [query.isIncoming] - get txs with an incoming transfer or not (optional) + * @param {MoneroTransferQuery} [query.transferQuery] - get txs that have a transfer that meets this query (optional) + * @param {boolean} [query.includeOutputs] - specifies that tx outputs should be returned with tx results (optional) + * @return {Promise} wallet transactions per the configuration + */ + async getTxs(query?: string[] | Partial): Promise { + throw new MoneroError("Not supported"); + } + + /** + *

Get incoming and outgoing transfers to and from this wallet. An outgoing + * transfer represents a total amount sent from one or more subaddresses + * within an account to individual destination addresses, each with their + * own amount. An incoming transfer represents a total amount received into + * a subaddress within an account. Transfers belong to transactions which + * are stored on the blockchain.

+ * + *

Results can be filtered by passing a query object. Transfers must + * meet every criteria defined in the query in order to be returned. All + * criteria are optional and no filtering is applied when not defined.

+ * + * @param {MoneroTransferQuery} [query] - configures the query (optional) + * @param {boolean} [query.isOutgoing] - get transfers that are outgoing or not (optional) + * @param {boolean} [query.isIncoming] - get transfers that are incoming or not (optional) + * @param {string} [query.address] - wallet's address that a transfer either originated from (if outgoing) or is destined for (if incoming) (optional) + * @param {number} [query.accountIndex] - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific account index (optional) + * @param {number} [query.subaddressIndex] - get transfers that either originated from (if outgoing) or are destined for (if incoming) a specific subaddress index (optional) + * @param {int[]} [query.subaddressIndices] - get transfers that either originated from (if outgoing) or are destined for (if incoming) specific subaddress indices (optional) + * @param {bigint} [query.amount] - amount being transferred (optional) + * @param {MoneroDestination[] | MoneroDestinationModel[]} [query.destinations] - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional) + * @param {boolean} [query.hasDestinations] - get transfers that have destinations or not (optional) + * @param {MoneroTxQuery} [query.txQuery] - get transfers whose transaction meets this query (optional) + * @return {Promise} wallet transfers that meet the query + */ + async getTransfers(query?: Partial): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get incoming transfers. + * + * @param {Partial} [query] - configures the query (optional) + * @param {string} [query.address] - get incoming transfers to a specific address in the wallet (optional) + * @param {number} [query.accountIndex] - get incoming transfers to a specific account index (optional) + * @param {number} [query.subaddressIndex] - get incoming transfers to a specific subaddress index (optional) + * @param {int[]} [query.subaddressIndices] - get transfers destined for specific subaddress indices (optional) + * @param {bigint} [query.amount] - amount being transferred (optional) + * @param {MoneroTxQuery} [query.txQuery] - get transfers whose transaction meets this query (optional) + * @return {Promise} incoming transfers that meet the query + */ + async getIncomingTransfers(query?: Partial): Promise { + const queryNormalized: MoneroTransferQuery = MoneroWallet.normalizeTransferQuery(query); + if (queryNormalized.getIsIncoming() === false) throw new MoneroError("Transfer query contradicts getting incoming transfers"); + queryNormalized.setIsIncoming(true); + return this.getTransfers(queryNormalized) as unknown as MoneroIncomingTransfer[]; + } + + /** + * Get outgoing transfers. + * + * @param {Partial} [query] - configures the query (optional) + * @param {string} [query.address] - get outgoing transfers from a specific address in the wallet (optional) + * @param {number} [query.accountIndex] - get outgoing transfers from a specific account index (optional) + * @param {number} [query.subaddressIndex] - get outgoing transfers from a specific subaddress index (optional) + * @param {int[]} [query.subaddressIndices] - get outgoing transfers from specific subaddress indices (optional) + * @param {bigint} [query.amount] - amount being transferred (optional) + * @param {MoneroDestination[] | MoneroDestinationModel[]} [query.destinations] - individual destinations of an outgoing transfer, which is local wallet data and NOT recoverable from the blockchain (optional) + * @param {boolean} [query.hasDestinations] - get transfers that have destinations or not (optional) + * @param {MoneroTxQuery} [query.txQuery] - get transfers whose transaction meets this query (optional) + * @return {Promise} outgoing transfers that meet the query + */ + async getOutgoingTransfers(query?: Partial): Promise { + const queryNormalized: MoneroTransferQuery = MoneroWallet.normalizeTransferQuery(query); + if (queryNormalized.getIsOutgoing() === false) throw new MoneroError("Transfer query contradicts getting outgoing transfers"); + queryNormalized.setIsOutgoing(true); + return this.getTransfers(queryNormalized) as unknown as MoneroOutgoingTransfer[]; + } + + /** + *

Get outputs created from previous transactions that belong to the wallet + * (i.e. that the wallet can spend one time). Outputs are part of + * transactions which are stored in blocks on the blockchain.

+ * + *

Results can be filtered by passing a query object. Outputs must + * meet every criteria defined in the query in order to be returned. All + * filtering is optional and no filtering is applied when not defined.

+ * + * @param {Parital} [query] - configures the query (optional) + * @param {number} [query.accountIndex] - get outputs associated with a specific account index (optional) + * @param {number} [query.subaddressIndex] - get outputs associated with a specific subaddress index (optional) + * @param {int[]} [query.subaddressIndices] - get outputs associated with specific subaddress indices (optional) + * @param {bigint} [query.amount] - get outputs with a specific amount (optional) + * @param {bigint} [query.minAmount] - get outputs greater than or equal to a minimum amount (optional) + * @param {bigint} [query.maxAmount] - get outputs less than or equal to a maximum amount (optional) + * @param {boolean} [query.isSpent] - get outputs that are spent or not (optional) + * @param {string|MoneroKeyImage} [query.keyImage] - get output with a key image or which matches fields defined in a MoneroKeyImage (optional) + * @param {MoneroTxQuery} [query.txQuery] - get outputs whose transaction meets this filter (optional) + * @return {Promise} the queried outputs + */ + async getOutputs(query?: Partial): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Export outputs in hex format. + * + * @param {boolean} [all] - export all outputs if true, else export the outputs since the last export (default false) + * @return {Promise} outputs in hex format + */ + async exportOutputs(all = false): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Import outputs in hex format. + * + * @param {string} outputsHex - outputs in hex format + * @return {Promise} the number of outputs imported + */ + async importOutputs(outputsHex: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Export signed key images. + * + * @param {boolean} [all] - export all key images if true, else export the key images since the last export (default false) + * @return {Promise} the wallet's signed key images + */ + async exportKeyImages(all = false): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Import signed key images and verify their spent status. + * + * @param {MoneroKeyImage[]} keyImages - images to import and verify (requires hex and signature) + * @return {Promise} results of the import + */ + async importKeyImages(keyImages: MoneroKeyImage[]): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get new key images from the last imported outputs. + * + * @return {Promise} the key images from the last imported outputs + */ + async getNewKeyImagesFromLastImport(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Freeze an output. + * + * @param {string} keyImage - key image of the output to freeze + * @return {Promise} + */ + async freezeOutput(keyImage: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Thaw a frozen output. + * + * @param {string} keyImage - key image of the output to thaw + * @return {Promise} + */ + async thawOutput(keyImage: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Check if an output is frozen. + * + * @param {string} keyImage - key image of the output to check if frozen + * @return {Promise} true if the output is frozen, false otherwise + */ + async isOutputFrozen(keyImage: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get the current default fee priority (unimportant, normal, elevated, etc). + * + * @return {Promise} the current fee priority + */ + async getDefaultFeePriority(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Create a transaction to transfer funds from this wallet. + * + * @param {MoneroTxConfig} config - configures the transaction to create (required) + * @param {string} config.address - single destination address (required unless `destinations` provided) + * @param {bigint|string} config.amount - single destination amount (required unless `destinations` provided) + * @param {number} config.accountIndex - source account index to transfer funds from (required) + * @param {number} [config.subaddressIndex] - source subaddress index to transfer funds from (optional) + * @param {number[]} [config.subaddressIndices] - source subaddress indices to transfer funds from (optional) + * @param {boolean} [config.relay] - relay the transaction to peers to commit to the blockchain (default false) + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @param {MoneroDestination[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided) + * @param {number[]} [config.subtractFeeFrom] - list of destination indices to split the transaction fee (optional) + * @param {string} [config.paymentId] - transaction payment ID (optional) + * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transaction to unlock (default 0) + * @return {Promise} the created transaction + */ + async createTx(config: Partial): Promise { + const configNormalized: MoneroTxConfig = MoneroWallet.normalizeCreateTxsConfig(config); + if (configNormalized.getCanSplit() !== undefined) assert.equal(configNormalized.getCanSplit(), false, "Cannot split transactions using createTx(); use createTxs()"); + configNormalized.setCanSplit(false); + return (await this.createTxs(configNormalized))[0]; + } + + /** + * Create one or more transactions to transfer funds from this wallet. + * + * @param {Partial} config - configures the transactions to create (required) + * @param {string} config.address - single destination address (required unless `destinations` provided) + * @param {bigint|string} config.amount - single destination amount (required unless `destinations` provided) + * @param {number} config.accountIndex - source account index to transfer funds from (required) + * @param {number} [config.subaddressIndex] - source subaddress index to transfer funds from (optional) + * @param {int[]} [config.subaddressIndices] - source subaddress indices to transfer funds from (optional) + * @param {boolean} [config.relay] - relay the transactions to peers to commit to the blockchain (default false) + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @param {MoneroDestination[] | MoneroDestinationModel[]} config.destinations - addresses and amounts in a multi-destination tx (required unless `address` and `amount` provided) + * @param {string} [config.paymentId] - transaction payment ID (optional) + * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transactions to unlock (default 0) + * @param {boolean} [config.canSplit] - allow funds to be transferred using multiple transactions (default true) + * @return {Promise} the created transactions + */ + async createTxs(config: Partial): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Sweep an output by key image. + * + * @param {Partial} config - configures the transaction to create (required) + * @param {string} config.address - single destination address (required) + * @param {string} config.keyImage - key image to sweep (required) + * @param {boolean} [config.relay] - relay the transaction to peers to commit to the blockchain (default false) + * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transaction to unlock (default 0) + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @return {Promise} the created transaction + */ + async sweepOutput(config: Partial): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Sweep all unlocked funds according to the given configuration. + * + * @param {Partial} config - configures the transactions to create (required) + * @param {string} config.address - single destination address (required) + * @param {number} [config.accountIndex] - source account index to sweep from (optional, defaults to all accounts) + * @param {number} [config.subaddressIndex] - source subaddress index to sweep from (optional, defaults to all subaddresses) + * @param {number[]} [config.subaddressIndices] - source subaddress indices to sweep from (optional) + * @param {boolean} [config.relay] - relay the transactions to peers to commit to the blockchain (default false) + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @param {bigint|string} [config.unlockTime] - minimum height or timestamp for the transactions to unlock (default 0) + * @param {boolean} [config.sweepEachSubaddress] - sweep each subaddress individually if true (default false) + * @return {Promise} the created transactions + */ + async sweepUnlocked(config: Partial): Promise { + throw new MoneroError("Not supported"); + } + + /** + *

Sweep all unmixable dust outputs back to the wallet to make them easier to spend and mix.

+ * + *

NOTE: Dust only exists pre RCT, so this method will throw "no dust to sweep" on new wallets.

+ * + * @param {boolean} [relay] - specifies if the resulting transaction should be relayed (default false) + * @return {Promise} the created transactions + */ + async sweepDust(relay?: boolean): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Relay a previously created transaction. + * + * @param {(MoneroTxWallet | string)} txOrMetadata - transaction or its metadata to relay + * @return {Promise} the hash of the relayed tx + */ + async relayTx(txOrMetadata: MoneroTxWallet | string): Promise { + return (await this.relayTxs([txOrMetadata]))[0]; + } + + /** + * Relay previously created transactions. + * + * @param {(MoneroTxWallet[] | string[])} txsOrMetadatas - transactions or their metadata to relay + * @return {Promise} the hashes of the relayed txs + */ + async relayTxs(txsOrMetadatas: (MoneroTxWallet | string)[]): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Describe a tx set from unsigned tx hex. + * + * @param {string} unsignedTxHex - unsigned tx hex + * @return {Promise} the tx set containing structured transactions + */ + async describeUnsignedTxSet(unsignedTxHex: string): Promise { + return this.describeTxSet(new MoneroTxSet().setUnsignedTxHex(unsignedTxHex)); + } + + /** + * Describe a tx set from multisig tx hex. + * + * @param {string} multisigTxHex - multisig tx hex + * @return {Promise} the tx set containing structured transactions + */ + async describeMultisigTxSet(multisigTxHex: string): Promise { + return this.describeTxSet(new MoneroTxSet().setMultisigTxHex(multisigTxHex)); + } + + /** + * Describe a tx set containing unsigned or multisig tx hex to a new tx set containing structured transactions. + * + * @param {MoneroTxSet} txSet - a tx set containing unsigned or multisig tx hex + * @return {Promise} txSet - the tx set containing structured transactions + */ + async describeTxSet(txSet: MoneroTxSet): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Sign unsigned transactions from a view-only wallet. + * + * @param {string} unsignedTxHex - unsigned transaction hex from when the transactions were created + * @return {Promise} the signed transaction set + */ + async signTxs(unsignedTxHex: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Submit signed transactions from a view-only wallet. + * + * @param {string} signedTxHex - signed transaction hex from signTxs() + * @return {Promise} the resulting transaction hashes + */ + async submitTxs(signedTxHex: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Sign a message. + * + * @param {string} message - the message to sign + * @param {MoneroMessageSignatureType} [signatureType] - sign with spend key or view key (default spend key) + * @param {number} [accountIdx] - the account index of the message signature (default 0) + * @param {number} [subaddressIdx] - the subaddress index of the message signature (default 0) + * @return {Promise} the signature + */ + async signMessage(message: string, signatureType = MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY, accountIdx = 0, subaddressIdx = 0): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Verify a signature on a message. + * + * @param {string} message - signed message + * @param {string} address - signing address + * @param {string} signature - signature + * @return {Promise} true if the signature is good, false otherwise + */ + async verifyMessage(message: string, address: string, signature: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get a transaction's secret key from its hash. + * + * @param {string} txHash - transaction's hash + * @return {Promise} - transaction's secret key + */ + async getTxKey(txHash: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Check a transaction in the blockchain with its secret key. + * + * @param {string} txHash - transaction to check + * @param {string} txKey - transaction's secret key + * @param {string} address - destination public address of the transaction + * @return {romise} the result of the check + */ + async checkTxKey(txHash: string, txKey: string, address: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get a transaction signature to prove it. + * + * @param {string} txHash - transaction to prove + * @param {string} address - destination public address of the transaction + * @param {string} [message] - message to include with the signature to further authenticate the proof (optional) + * @return {Promise} the transaction signature + */ + async getTxProof(txHash: string, address: string, message?: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Prove a transaction by checking its signature. + * + * @param {string} txHash - transaction to prove + * @param {string} address - destination public address of the transaction + * @param {string | undefined} message - message included with the signature to further authenticate the proof + * @param {string} signature - transaction signature to confirm + * @return {Promise} the result of the check + */ + async checkTxProof(txHash: string, address: string, message: string | undefined, signature: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Generate a signature to prove a spend. Unlike proving a transaction, it does not require the destination public address. + * + * @param {string} txHash - transaction to prove + * @param {string} [message] - message to include with the signature to further authenticate the proof (optional) + * @return {Promise} the transaction signature + */ + async getSpendProof(txHash: string, message?: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Prove a spend using a signature. Unlike proving a transaction, it does not require the destination public address. + * + * @param {string} txHash - transaction to prove + * @param {string | undefined} message - message included with the signature to further authenticate the proof (optional) + * @param {string} signature - transaction signature to confirm + * @return {Promise} true if the signature is good, false otherwise + */ + async checkSpendProof(txHash: string, message: string | undefined, signature: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Generate a signature to prove the entire balance of the wallet. + * + * @param {string} [message] - message included with the signature to further authenticate the proof (optional) + * @return {Promise} the reserve proof signature + */ + async getReserveProofWallet(message?: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Generate a signature to prove an available amount in an account. + * + * @param {number} accountIdx - account to prove ownership of the amount + * @param {bigint} amount - minimum amount to prove as available in the account + * @param {string} [message] - message to include with the signature to further authenticate the proof (optional) + * @return {Promise} the reserve proof signature + */ + async getReserveProofAccount(accountIdx: number, amount: bigint, message?: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Proves a wallet has a disposable reserve using a signature. + * + * @param {string} address - public wallet address + * @param {string | undefined} message - message included with the signature to further authenticate the proof (optional) + * @param {string} signature - reserve proof signature to check + * @return {Promise} the result of checking the signature proof + */ + async checkReserveProof(address: string, message: string | undefined, signature: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get a transaction note. + * + * @param {string} txHash - transaction to get the note of + * @return {Promise} the tx note + */ + async getTxNote(txHash: string): Promise { + return (await this.getTxNotes([txHash]))[0]; + } + + /** + * Get notes for multiple transactions. + * + * @param {string[]} txHashes - hashes of the transactions to get notes for + * @return {Promise} notes for the transactions + */ + async getTxNotes(txHashes: string[]): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Set a note for a specific transaction. + * + * @param {string} txHash - hash of the transaction to set a note for + * @param {string} note - the transaction note + * @return {Promise} + */ + async setTxNote(txHash: string, note: string): Promise { + await this.setTxNotes([txHash], [note]); + } + + /** + * Set notes for multiple transactions. + * + * @param {string[]} txHashes - transactions to set notes for + * @param {string[]} notes - notes to set for the transactions + * @return {Promise} + */ + async setTxNotes(txHashes: string[], notes: string[]): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get address book entries. + * + * @param {number[]} [entryIndices] - indices of the entries to get + * @return {Promise} the address book entries + */ + async getAddressBookEntries(entryIndices?: number[]): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Add an address book entry. + * + * @param {string} address - entry address + * @param {string} [description] - entry description (optional) + * @return {Promise} the index of the added entry + */ + async addAddressBookEntry(address: string, description?: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Edit an address book entry. + * + * @param {number} index - index of the address book entry to edit + * @param {boolean} setAddress - specifies if the address should be updated + * @param {string | undefined} address - updated address + * @param {boolean} setDescription - specifies if the description should be updated + * @param {string | undefined} description - updated description + * @return {Promise} + */ + async editAddressBookEntry(index: number, setAddress: boolean, address: string | undefined, setDescription: boolean, description: string | undefined): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Delete an address book entry. + * + * @param {number} entryIdx - index of the entry to delete + * @return {Promise} + */ + async deleteAddressBookEntry(entryIdx: number): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Tag accounts. + * + * @param {string} tag - tag to apply to the specified accounts + * @param {number[]} accountIndices - indices of the accounts to tag + * @return {Promise} + */ + async tagAccounts(tag: string, accountIndices: number[]): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Untag accounts. + * + * @param {number[]} accountIndices - indices of the accounts to untag + * @return {Promise} + */ + async untagAccounts(accountIndices: number[]): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Return all account tags. + * + * @return {Promise} the wallet's account tags + */ + async getAccountTags(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Sets a human-readable description for a tag. + * + * @param {string} tag - tag to set a description for + * @param {string} label - label to set for the tag + * @return {Promise} + */ + async setAccountTagLabel(tag: string, label: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Creates a payment URI from a send configuration. + * + * @param {MoneroTxConfig} config - specifies configuration for a potential tx + * @return {Promise} the payment uri + */ + async getPaymentUri(config: MoneroTxConfig): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Parses a payment URI to a tx config. + * + * @param {string} uri - payment uri to parse + * @return {Promise} the send configuration parsed from the uri + */ + async parsePaymentUri(uri: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get an attribute. + * + * @param {string} key - attribute to get the value of + * @return {Promise} the attribute's value + */ + async getAttribute(key: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Set an arbitrary attribute. + * + * @param {string} key - attribute key + * @param {string} val - attribute value + * @return {Promise} + */ + async setAttribute(key: string, val: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Start mining. + * + * @param {number} [numThreads] - number of threads created for mining (optional) + * @param {boolean} [backgroundMining] - specifies if mining should occur in the background (optional) + * @param {boolean} [ignoreBattery] - specifies if the battery should be ignored for mining (optional) + * @return {Promise} + */ + async startMining(numThreads: number, backgroundMining?: boolean, ignoreBattery?: boolean): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Stop mining. + * + * @return {Promise} + */ + async stopMining(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Indicates if importing multisig data is needed for returning a correct balance. + * + * @return {Promise} true if importing multisig data is needed for returning a correct balance, false otherwise + */ + async isMultisigImportNeeded(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Indicates if this wallet is a multisig wallet. + * + * @return {Promise} true if this is a multisig wallet, false otherwise + */ + async isMultisig(): Promise { + return (await this.getMultisigInfo()).getIsMultisig(); + } + + /** + * Get multisig info about this wallet. + * + * @return {Promise} multisig info about this wallet + */ + async getMultisigInfo(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Get multisig info as hex to share with participants to begin creating a + * multisig wallet. + * + * @return {Promise} this wallet's multisig hex to share with participants + */ + async prepareMultisig(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Make this wallet multisig by importing multisig hex from participants. + * + * @param {string[]} multisigHexes - multisig hex from each participant + * @param {number} threshold - number of signatures needed to sign transfers + * @param {string} password - wallet password + * @return {Promise} this wallet's multisig hex to share with participants + */ + async makeMultisig(multisigHexes: string[], threshold: number, password: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Exchange multisig hex with participants in a M/N multisig wallet. + * + * This process must be repeated with participants exactly N-M times. + * + * @param {string[]} multisigHexes are multisig hex from each participant + * @param {string} password - wallet's password // TODO monero-project: redundant? wallet is created with password + * @return {Promise} the result which has the multisig's address xor this wallet's multisig hex to share with participants iff not done + */ + async exchangeMultisigKeys(multisigHexes: string[], password: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Export this wallet's multisig info as hex for other participants. + * + * @return {Promise} this wallet's multisig info as hex for other participants + */ + async exportMultisigHex(): Promise { + throw new MoneroError("Not supported?"); + } + + /** + * Import multisig info as hex from other participants. + * + * @param {string[]} multisigHexes - multisig hex from each participant + * @return {Promise} the number of outputs signed with the given multisig hex + */ + async importMultisigHex(multisigHexes: string[]): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Sign multisig transactions from a multisig wallet. + * + * @param {string} multisigTxHex - unsigned multisig transactions as hex + * @return {MoneroMultisigSignResult} the result of signing the multisig transactions + */ + async signMultisigTxHex(multisigTxHex: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Submit signed multisig transactions from a multisig wallet. + * + * @param {string} signedMultisigTxHex - signed multisig hex returned from signMultisigTxHex() + * @return {Promise} the resulting transaction hashes + */ + async submitMultisigTxHex(signedMultisigTxHex: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Change the wallet password. + * + * @param {string} oldPassword - the wallet's old password + * @param {string} newPassword - the wallet's new password + * @return {Promise} + */ + async changePassword(oldPassword: string, newPassword: string): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Save the wallet at its current path. + * + * @return {Promise} + */ + async save(): Promise { + throw new MoneroError("Not supported"); + } + + /** + * Optionally save then close the wallet. + * + * @param {boolean} [save] - specifies if the wallet should be saved before being closed (default false) + * @return {Promise} + */ + async close(save = false): Promise { + if (this.connectionManager) this.connectionManager.removeListener(this.connectionManagerListener); + this.connectionManager = undefined; + this.connectionManagerListener = undefined; + this.listeners.splice(0, this.listeners.length); + this._isClosed = true; + } + + /** + * Indicates if this wallet is closed or not. + * + * @return {Promise} true if the wallet is closed, false otherwise + */ + async isClosed(): Promise { + return this._isClosed; + } + + // -------------------------------- PRIVATE --------------------------------- + + /** + * @private + */ + async announceSyncProgress(height: number, startHeight: number, endHeight: number, percentDone: number, message: string): Promise { + for (let listener of this.listeners) { + try { + await listener.onSyncProgress(height, startHeight, endHeight, percentDone, message); + } catch (err) { + console.error("Error calling listener on sync progress", err); + } + } + } + + /** + * @private + */ + async announceNewBlock(height: number): Promise { + for (let listener of this.listeners) { + try { + await listener.onNewBlock(height); + } catch (err) { + console.error("Error calling listener on new block", err); + } + } + } + + /** + * @private + */ + async announceBalancesChanged(newBalance: bigint, newUnlockedBalance: bigint): Promise { + for (let listener of this.listeners) { + try { + await listener.onBalancesChanged(newBalance, newUnlockedBalance); + } catch (err) { + console.error("Error calling listener on balances changed", err); + } + } + } + + /** + * @private + */ + async announceOutputReceived(output: MoneroOutputWallet): Promise { + for (let listener of this.listeners) { + try { + await listener.onOutputReceived(output); + } catch (err) { + console.error("Error calling listener on output received", err); + } + } + } + + /** + * @private + */ + async announceOutputSpent(output: MoneroOutputWallet): Promise { + for (let listener of this.listeners) { + try { + await listener.onOutputSpent(output); + } catch (err) { + console.error("Error calling listener on output spent", err); + } + } + } + + protected static normalizeTxQuery(query): MoneroTxQuery { + if (query instanceof MoneroTxQuery) query = query.copy(); + else if (Array.isArray(query)) query = new MoneroTxQuery().setHashes(query); + else { + query = Object.assign({}, query); + query = new MoneroTxQuery(query); + } + if (query.getBlock() === undefined) query.setBlock(new MoneroBlock().setTxs([query])); + if (query.getInputQuery()) query.getInputQuery().setTxQuery(query); + if (query.getOutputQuery()) query.getOutputQuery().setTxQuery(query); + return query; + } + + protected static normalizeTransferQuery(query): MoneroTransferQuery { + query = new MoneroTransferQuery(query); + if (query.getTxQuery() !== undefined) { + let txQuery = query.getTxQuery().copy(); + query = txQuery.getTransferQuery(); + } + if (query.getTxQuery() === undefined) query.setTxQuery(new MoneroTxQuery()); + query.getTxQuery().setTransferQuery(query); + if (query.getTxQuery().getBlock() === undefined) query.getTxQuery().setBlock(new MoneroBlock().setTxs([query.getTxQuery()])); + return query; + } + + protected static normalizeOutputQuery(query): MoneroOutputQuery { + query = new MoneroOutputQuery(query); + if (query.getTxQuery() !== undefined) { + let txQuery = query.getTxQuery().copy(); + query = txQuery.getOutputQuery(); + } + if (query.getTxQuery() === undefined) query.setTxQuery(new MoneroTxQuery()); + query.getTxQuery().setOutputQuery(query); + if (query.getTxQuery().getBlock() === undefined) query.getTxQuery().setBlock(new MoneroBlock().setTxs([query.getTxQuery()])); + return query; + } + + protected static normalizeCreateTxsConfig(config): MoneroTxConfig { + if (config === undefined || !(config instanceof Object)) throw new MoneroError("Must provide MoneroTxConfig or equivalent JS object"); + config = new MoneroTxConfig(config); + assert(config.getDestinations() && config.getDestinations().length > 0, "Must provide destinations"); + assert.equal(config.getSweepEachSubaddress(), undefined); + assert.equal(config.getBelowAmount(), undefined); + return config; + } + + protected static normalizeSweepOutputConfig(config): MoneroTxConfig { + if (config === undefined || !(config instanceof Object)) throw new MoneroError("Must provide MoneroTxConfig or equivalent JS object"); + config = new MoneroTxConfig(config); + assert.equal(config.getSweepEachSubaddress(), undefined); + assert.equal(config.getBelowAmount(), undefined); + assert.equal(config.getCanSplit(), undefined, "Cannot split transactions when sweeping an output"); + if (!config.getDestinations() || config.getDestinations().length !== 1 || !config.getDestinations()[0].getAddress()) throw new MoneroError("Must provide exactly one destination address to sweep output to"); + if (config.getSubtractFeeFrom() && config.getSubtractFeeFrom().length > 0) throw new MoneroError("Sweep transactions do not support subtracting fees from destinations"); + return config; + } + + protected static normalizeSweepUnlockedConfig(config): MoneroTxConfig { + if (config === undefined || !(config instanceof Object)) throw new MoneroError("Must provide MoneroTxConfig or equivalent JS object"); + config = new MoneroTxConfig(config); + if (config.getDestinations() === undefined || config.getDestinations().length != 1) throw new MoneroError("Must provide exactly one destination to sweep to"); + if (config.getDestinations()[0].getAddress() === undefined) throw new MoneroError("Must provide destination address to sweep to"); + if (config.getDestinations()[0].getAmount() !== undefined) throw new MoneroError("Cannot provide amount in sweep config"); + if (config.getKeyImage() !== undefined) throw new MoneroError("Key image defined; use sweepOutput() to sweep an output by its key image"); + if (config.getSubaddressIndices() !== undefined && config.getSubaddressIndices().length === 0) config.setSubaddressIndices(undefined); + if (config.getAccountIndex() === undefined && config.getSubaddressIndices() !== undefined) throw new MoneroError("Must provide account index if subaddress indices are provided"); + if (config.getSubtractFeeFrom() && config.getSubtractFeeFrom().length > 0) throw new MoneroError("Sweep transactions do not support subtracting fees from destinations"); + return config; + } +} diff --git a/src/main/ts/wallet/MoneroWalletFull.ts b/src/main/ts/wallet/MoneroWalletFull.ts new file mode 100644 index 000000000..7408503e9 --- /dev/null +++ b/src/main/ts/wallet/MoneroWalletFull.ts @@ -0,0 +1,2500 @@ +import assert from "assert"; +import Path from "path"; +import GenUtils from "../common/GenUtils"; +import LibraryUtils from "../common/LibraryUtils"; +import TaskLooper from "../common/TaskLooper"; +import MoneroAccount from "./model/MoneroAccount"; +import MoneroAccountTag from "./model/MoneroAccountTag"; +import MoneroAddressBookEntry from "./model/MoneroAddressBookEntry"; +import MoneroBlock from "../daemon/model/MoneroBlock"; +import MoneroCheckTx from "./model/MoneroCheckTx"; +import MoneroCheckReserve from "./model/MoneroCheckReserve"; +import MoneroDaemonRpc from "../daemon/MoneroDaemonRpc"; +import MoneroError from "../common/MoneroError"; +import MoneroIncomingTransfer from "./model/MoneroIncomingTransfer"; +import MoneroIntegratedAddress from "./model/MoneroIntegratedAddress"; +import MoneroKeyImage from "../daemon/model/MoneroKeyImage"; +import MoneroKeyImageImportResult from "./model/MoneroKeyImageImportResult"; +import MoneroMultisigInfo from "./model/MoneroMultisigInfo"; +import MoneroMultisigInitResult from "./model/MoneroMultisigInitResult"; +import MoneroMultisigSignResult from "./model/MoneroMultisigSignResult"; +import MoneroNetworkType from "../daemon/model/MoneroNetworkType"; +import MoneroOutputQuery from "./model/MoneroOutputQuery"; +import MoneroOutputWallet from "./model/MoneroOutputWallet"; +import MoneroRpcConnection from "../common/MoneroRpcConnection"; +import MoneroSubaddress from "./model/MoneroSubaddress"; +import MoneroSyncResult from "./model/MoneroSyncResult"; +import MoneroTransfer from "./model/MoneroTransfer"; +import MoneroTransferQuery from "./model/MoneroTransferQuery"; +import MoneroTxConfig from "./model/MoneroTxConfig"; +import MoneroTxPriority from "./model/MoneroTxPriority"; +import MoneroTxQuery from "./model/MoneroTxQuery"; +import MoneroTxSet from "./model/MoneroTxSet"; +import MoneroTx from "../daemon/model/MoneroTx"; +import MoneroTxWallet from "./model/MoneroTxWallet"; +import MoneroWallet from "./MoneroWallet"; +import MoneroWalletConfig from "./model/MoneroWalletConfig"; +import { MoneroWalletKeys, MoneroWalletKeysProxy } from "./MoneroWalletKeys"; +import MoneroWalletListener from "./model/MoneroWalletListener"; +import MoneroMessageSignatureType from "./model/MoneroMessageSignatureType"; +import MoneroMessageSignatureResult from "./model/MoneroMessageSignatureResult"; +import MoneroVersion from "../daemon/model/MoneroVersion"; +import fs from "fs"; + +/** + * Implements a Monero wallet using client-side WebAssembly bindings to monero-project's wallet2 in C++. + */ +export default class MoneroWalletFull extends MoneroWalletKeys { + + // static variables + protected static readonly DEFAULT_SYNC_PERIOD_IN_MS = 20000; + protected static FS; + + // instance variables + protected path: string; + protected password: string; + protected listeners: MoneroWalletListener[]; + protected fs: any; + protected wasmListener: WalletWasmListener; + protected wasmListenerHandle: number; + protected rejectUnauthorized: boolean; + protected rejectUnauthorizedConfigId: string; + protected syncPeriodInMs: number; + protected syncLooper: TaskLooper; + protected browserMainPath: string; + + /** + * Internal constructor which is given the memory address of a C++ wallet instance. + * + * This constructor should be called through static wallet creation utilities in this class. + * + * @param {number} cppAddress - address of the wallet instance in C++ + * @param {string} path - path of the wallet instance + * @param {string} password - password of the wallet instance + * @param {FileSystem} fs - node.js-compatible file system to read/write wallet files + * @param {boolean} rejectUnauthorized - specifies if unauthorized requests (e.g. self-signed certificates) should be rejected + * @param {string} rejectUnauthorizedFnId - unique identifier for http_client_wasm to query rejectUnauthorized + * @param {MoneroWalletFullProxy} walletProxy - proxy to invoke wallet operations in a web worker + * + * @private + */ + constructor(cppAddress, path, password, fs, rejectUnauthorized, rejectUnauthorizedFnId, walletProxy?: MoneroWalletFullProxy) { + super(cppAddress, walletProxy); + if (walletProxy) return; + this.path = path; + this.password = password; + this.listeners = []; + this.fs = fs ? fs : (path ? MoneroWalletFull.getFs() : undefined); + this._isClosed = false; + this.wasmListener = new WalletWasmListener(this); // receives notifications from wasm c++ + this.wasmListenerHandle = 0; // memory address of the wallet listener in c++ + this.rejectUnauthorized = rejectUnauthorized; + this.rejectUnauthorizedConfigId = rejectUnauthorizedFnId; + this.syncPeriodInMs = MoneroWalletFull.DEFAULT_SYNC_PERIOD_IN_MS; + LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => this.rejectUnauthorized); // register fn informing if unauthorized reqs should be rejected + } + + // --------------------------- STATIC UTILITIES ----------------------------- + + /** + * Check if a wallet exists at a given path. + * + * @param {string} path - path of the wallet on the file system + * @param {any} fs - file system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser) + * @return {boolean} true if a wallet exists at the given path, false otherwise + */ + static async walletExists(path, fs) { + assert(path, "Must provide a path to look for a wallet"); + if (!fs) fs = MoneroWalletFull.getFs(); + if (!fs) throw new MoneroError("Must provide file system to check if wallet exists"); + let exists = await LibraryUtils.exists(fs, path + ".keys"); + LibraryUtils.log(1, "Wallet exists at " + path + ": " + exists); + return exists; + } + + static async openWallet(config: Partial) { + + // validate config + config = new MoneroWalletConfig(config); + if (config.getProxyToWorker() === undefined) config.setProxyToWorker(true); + if (config.getSeed() !== undefined) throw new MoneroError("Cannot specify seed when opening wallet"); + if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot specify seed offset when opening wallet"); + if (config.getPrimaryAddress() !== undefined) throw new MoneroError("Cannot specify primary address when opening wallet"); + if (config.getPrivateViewKey() !== undefined) throw new MoneroError("Cannot specify private view key when opening wallet"); + if (config.getPrivateSpendKey() !== undefined) throw new MoneroError("Cannot specify private spend key when opening wallet"); + if (config.getRestoreHeight() !== undefined) throw new MoneroError("Cannot specify restore height when opening wallet"); + if (config.getLanguage() !== undefined) throw new MoneroError("Cannot specify language when opening wallet"); + if (config.getSaveCurrent() === true) throw new MoneroError("Cannot save current wallet when opening full wallet"); + if (config.getFs() === undefined) config.setFs(MoneroWalletFull.getFs()); + + // set server from connection manager if provided + if (config.getConnectionManager()) { + if (config.getServer()) throw new MoneroError("Wallet can be opened with a server or connection manager but not both"); + config.setServer(config.getConnectionManager().getConnection()); + } + + // read wallet data from disk unless provided + if (!config.getKeysData()) { + let fs = config.getFs(); + if (!fs) throw new MoneroError("Must provide file system to read wallet data from"); + if (!await this.walletExists(config.getPath(), fs)) throw new MoneroError("Wallet does not exist at path: " + config.getPath()); + config.setKeysData(await fs.readFile(config.getPath() + ".keys")); + config.setCacheData(await LibraryUtils.exists(fs, config.getPath()) ? await fs.readFile(config.getPath()) : ""); + } + + // open wallet from data + const wallet = await MoneroWalletFull.openWalletData(config); + + // set connection manager + await wallet.setConnectionManager(config.getConnectionManager()); + return wallet; + } + + static async createWallet(config: MoneroWalletConfig): Promise { + + // validate config + if (config === undefined) throw new MoneroError("Must provide config to create wallet"); + if (config.getSeed() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) throw new MoneroError("Wallet may be initialized with a seed or keys but not both"); + if (config.getNetworkType() === undefined) throw new MoneroError("Must provide a networkType: 'mainnet', 'testnet' or 'stagenet'"); + MoneroNetworkType.validate(config.getNetworkType()); + if (config.getSaveCurrent() === true) throw new MoneroError("Cannot save current wallet when creating full WASM wallet"); + if (config.getPath() === undefined) config.setPath(""); + if (config.getPath() && await MoneroWalletFull.walletExists(config.getPath(), config.getFs())) throw new MoneroError("Wallet already exists: " + config.getPath()); + if (config.getPassword() === undefined) config.setPassword(""); + + // set server from connection manager if provided + if (config.getConnectionManager()) { + if (config.getServer()) throw new MoneroError("Wallet can be created with a server or connection manager but not both"); + config.setServer(config.getConnectionManager().getConnection()); + } + + // create proxied or local wallet + let wallet; + if (config.getProxyToWorker() === undefined) config.setProxyToWorker(true); + if (config.getProxyToWorker()) { + let walletProxy = await MoneroWalletFullProxy.createWallet(config); + wallet = new MoneroWalletFull(undefined, undefined, undefined, undefined, undefined, undefined, walletProxy); + } else { + if (config.getSeed() !== undefined) { + if (config.getLanguage() !== undefined) throw new MoneroError("Cannot provide language when creating wallet from seed"); + wallet = await MoneroWalletFull.createWalletFromSeed(config); + } else if (config.getPrivateSpendKey() !== undefined || config.getPrimaryAddress() !== undefined) { + if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating wallet from keys"); + wallet = await MoneroWalletFull.createWalletFromKeys(config); + } else { + if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating random wallet"); + if (config.getRestoreHeight() !== undefined) throw new MoneroError("Cannot provide restoreHeight when creating random wallet"); + wallet = await MoneroWalletFull.createWalletRandom(config); + } + } + + // set connection manager + await wallet.setConnectionManager(config.getConnectionManager()); + return wallet; + } + + protected static async createWalletFromSeed(config: MoneroWalletConfig): Promise { + + // validate and normalize params + let daemonConnection = config.getServer(); + let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true; + if (config.getRestoreHeight() === undefined) config.setRestoreHeight(0); + if (config.getSeedOffset() === undefined) config.setSeedOffset(""); + + // load full wasm module + let module = await LibraryUtils.loadWasmModule(); + + // create wallet in queue + let wallet = await module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // register fn informing if unauthorized reqs should be rejected + let rejectUnauthorizedFnId = GenUtils.getUUID(); + LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => rejectUnauthorized); + + // create wallet in wasm which invokes callback when done + module.create_full_wallet(JSON.stringify(config.toJson()), rejectUnauthorizedFnId, async (cppAddress) => { + if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); + else resolve(new MoneroWalletFull(cppAddress, config.getPath(), config.getPassword(), config.getFs(), config.getServer() ? config.getServer().getRejectUnauthorized() : undefined, rejectUnauthorizedFnId)); + }); + }); + }); + + // save wallet + if (config.getPath()) await wallet.save(); + return wallet; + } + + protected static async createWalletFromKeys(config: MoneroWalletConfig): Promise { + + // validate and normalize params + MoneroNetworkType.validate(config.getNetworkType()); + if (config.getPrimaryAddress() === undefined) config.setPrimaryAddress(""); + if (config.getPrivateViewKey() === undefined) config.setPrivateViewKey(""); + if (config.getPrivateSpendKey() === undefined) config.setPrivateSpendKey(""); + let daemonConnection = config.getServer(); + let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true; + if (config.getRestoreHeight() === undefined) config.setRestoreHeight(0); + if (config.getLanguage() === undefined) config.setLanguage("English"); + + // load full wasm module + let module = await LibraryUtils.loadWasmModule(); + + // create wallet in queue + let wallet = await module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // register fn informing if unauthorized reqs should be rejected + let rejectUnauthorizedFnId = GenUtils.getUUID(); + LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => rejectUnauthorized); + + // create wallet in wasm which invokes callback when done + module.create_full_wallet(JSON.stringify(config.toJson()), rejectUnauthorizedFnId, async (cppAddress) => { + if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); + else resolve(new MoneroWalletFull(cppAddress, config.getPath(), config.getPassword(), config.getFs(), config.getServer() ? config.getServer().getRejectUnauthorized() : undefined, rejectUnauthorizedFnId)); + }); + }); + }); + + // save wallet + if (config.getPath()) await wallet.save(); + return wallet; + } + + protected static async createWalletRandom(config: MoneroWalletConfig): Promise { + + // validate and normalize params + if (config.getLanguage() === undefined) config.setLanguage("English"); + let daemonConnection = config.getServer(); + let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true; + + // load wasm module + let module = await LibraryUtils.loadWasmModule(); + + // create wallet in queue + let wallet = await module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // register fn informing if unauthorized reqs should be rejected + let rejectUnauthorizedFnId = GenUtils.getUUID(); + LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => rejectUnauthorized); + + // create wallet in wasm which invokes callback when done + module.create_full_wallet(JSON.stringify(config.toJson()), rejectUnauthorizedFnId, async (cppAddress) => { + if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); + else resolve(new MoneroWalletFull(cppAddress, config.getPath(), config.getPassword(), config.getFs(), config.getServer() ? config.getServer().getRejectUnauthorized() : undefined, rejectUnauthorizedFnId)); + }); + }); + }); + + // save wallet + if (config.getPath()) await wallet.save(); + return wallet; + } + + static async getSeedLanguages() { + let module = await LibraryUtils.loadWasmModule(); + return module.queueTask(async () => { + return JSON.parse(module.get_keys_wallet_seed_languages()).languages; + }); + } + + static getFs() { + if (!MoneroWalletFull.FS) MoneroWalletFull.FS = fs.promises; + return MoneroWalletFull.FS; + } + + // ------------ WALLET METHODS SPECIFIC TO WASM IMPLEMENTATION -------------- + + // TODO: move these to MoneroWallet.ts, others can be unsupported + + /** + * Get the maximum height of the peers the wallet's daemon is connected to. + * + * @return {Promise} the maximum height of the peers the wallet's daemon is connected to + */ + async getDaemonMaxPeerHeight(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getDaemonMaxPeerHeight(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // call wasm which invokes callback when done + this.module.get_daemon_max_peer_height(this.cppAddress, (resp) => { + resolve(resp); + }); + }); + }); + } + + /** + * Indicates if the wallet's daemon is synced with the network. + * + * @return {Promise} true if the daemon is synced with the network, false otherwise + */ + async isDaemonSynced(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().isDaemonSynced(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // call wasm which invokes callback when done + this.module.is_daemon_synced(this.cppAddress, (resp) => { + resolve(resp); + }); + }); + }); + } + + /** + * Indicates if the wallet is synced with the daemon. + * + * @return {Promise} true if the wallet is synced with the daemon, false otherwise + */ + async isSynced(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().isSynced(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.is_synced(this.cppAddress, (resp) => { + resolve(resp); + }); + }); + }); + } + + /** + * Get the wallet's network type (mainnet, testnet, or stagenet). + * + * @return {Promise} the wallet's network type + */ + async getNetworkType(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getNetworkType(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.get_network_type(this.cppAddress); + }); + } + + /** + * Get the height of the first block that the wallet scans. + * + * @return {Promise} the height of the first block that the wallet scans + */ + async getRestoreHeight(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getRestoreHeight(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.get_restore_height(this.cppAddress); + }); + } + + /** + * Set the height of the first block that the wallet scans. + * + * @param {number} restoreHeight - height of the first block that the wallet scans + * @return {Promise} + */ + async setRestoreHeight(restoreHeight: number): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().setRestoreHeight(restoreHeight); + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.set_restore_height(this.cppAddress, restoreHeight); + }); + } + + /** + * Move the wallet from its current path to the given path. + * + * @param {string} path - the wallet's destination path + * @return {Promise} + */ + async moveTo(path: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().moveTo(path); + return MoneroWalletFull.moveTo(path, this); + } + + // -------------------------- COMMON WALLET METHODS ------------------------- + + async addListener(listener: MoneroWalletListener): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().addListener(listener); + await super.addListener(listener); + await this.refreshListening(); + } + + async removeListener(listener): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().removeListener(listener); + await super.removeListener(listener); + await this.refreshListening(); + } + + getListeners(): MoneroWalletListener[] { + if (this.getWalletProxy()) return this.getWalletProxy().getListeners(); + return super.getListeners(); + } + + async setDaemonConnection(uriOrConnection?: MoneroRpcConnection | string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().setDaemonConnection(uriOrConnection); + + // normalize connection + let connection = !uriOrConnection ? undefined : uriOrConnection instanceof MoneroRpcConnection ? uriOrConnection : new MoneroRpcConnection(uriOrConnection); + let uri = connection && connection.getUri() ? connection.getUri() : ""; + let username = connection && connection.getUsername() ? connection.getUsername() : ""; + let password = connection && connection.getPassword() ? connection.getPassword() : ""; + let proxyUri = connection && connection.getProxyUri() ? connection.getProxyUri() : ""; + let rejectUnauthorized = connection ? connection.getRejectUnauthorized() : undefined; + this.rejectUnauthorized = rejectUnauthorized; // persist locally + + // set connection in queue + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.set_daemon_connection(this.cppAddress, uri, username, password, proxyUri, (resp) => { + resolve(); + }); + }); + }); + } + + async getDaemonConnection(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getDaemonConnection(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + let connectionContainerStr = this.module.get_daemon_connection(this.cppAddress); + if (!connectionContainerStr) resolve(undefined); + else { + let jsonConnection = JSON.parse(connectionContainerStr); + resolve(new MoneroRpcConnection({uri: jsonConnection.uri, username: jsonConnection.username, password: jsonConnection.password, proxyUri: jsonConnection.proxyUri, rejectUnauthorized: this.rejectUnauthorized})); + } + }); + }); + } + + async isConnectedToDaemon(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().isConnectedToDaemon(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.is_connected_to_daemon(this.cppAddress, (resp) => { + resolve(resp); + }); + }); + }); + } + + async getVersion(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getVersion(); + throw new MoneroError("Not implemented"); + } + + async getPath(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getPath(); + return this.path; + } + + async getIntegratedAddress(standardAddress?: string, paymentId?: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getIntegratedAddress(standardAddress, paymentId); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { + let result = this.module.get_integrated_address(this.cppAddress, standardAddress ? standardAddress : "", paymentId ? paymentId : ""); + if (result.charAt(0) !== '{') throw new MoneroError(result); + return new MoneroIntegratedAddress(JSON.parse(result)); + } catch (err: any) { + if (err.message.includes("Invalid payment ID")) throw new MoneroError("Invalid payment ID: " + paymentId); + throw new MoneroError(err.message); + } + }); + } + + async decodeIntegratedAddress(integratedAddress: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().decodeIntegratedAddress(integratedAddress); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { + let result = this.module.decode_integrated_address(this.cppAddress, integratedAddress); + if (result.charAt(0) !== '{') throw new MoneroError(result); + return new MoneroIntegratedAddress(JSON.parse(result)); + } catch (err: any) { + throw new MoneroError(err.message); + } + }); + } + + async getHeight(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getHeight(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_height(this.cppAddress, (resp) => { + resolve(resp); + }); + }); + }); + } + + async getDaemonHeight(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getDaemonHeight(); + if (!await this.isConnectedToDaemon()) throw new MoneroError("Wallet is not connected to daemon"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_daemon_height(this.cppAddress, (resp) => { + resolve(resp); + }); + }); + }); + } + + async getHeightByDate(year: number, month: number, day: number): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getHeightByDate(year, month, day); + if (!await this.isConnectedToDaemon()) throw new MoneroError("Wallet is not connected to daemon"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_height_by_date(this.cppAddress, year, month, day, (resp) => { + if (typeof resp === "string") reject(new MoneroError(resp)); + else resolve(resp); + }); + }); + }); + } + + /** + * Synchronize the wallet with the daemon as a one-time synchronous process. + * + * @param {MoneroWalletListener|number} [listenerOrStartHeight] - listener xor start height (defaults to no sync listener, the last synced block) + * @param {number} [startHeight] - startHeight if not given in first arg (defaults to last synced block) + * @param {boolean} [allowConcurrentCalls] - allow other wallet methods to be processed simultaneously during sync (default false)

WARNING: enabling this option will crash wallet execution if another call makes a simultaneous network request. TODO: possible to sync wasm network requests in http_client_wasm.cpp? + */ + async sync(listenerOrStartHeight?: MoneroWalletListener | number, startHeight?: number, allowConcurrentCalls = false): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().sync(listenerOrStartHeight, startHeight, allowConcurrentCalls); + if (!await this.isConnectedToDaemon()) throw new MoneroError("Wallet is not connected to daemon"); + + // normalize params + startHeight = listenerOrStartHeight === undefined || listenerOrStartHeight instanceof MoneroWalletListener ? startHeight : listenerOrStartHeight; + let listener = listenerOrStartHeight instanceof MoneroWalletListener ? listenerOrStartHeight : undefined; + if (startHeight === undefined) startHeight = Math.max(await this.getHeight(), await this.getRestoreHeight()); + + // register listener if given + if (listener) await this.addListener(listener); + + // sync wallet + let err; + let result; + try { + let that = this; + result = await (allowConcurrentCalls ? syncWasm() : this.module.queueTask(async () => syncWasm())); + function syncWasm() { + that.assertNotClosed(); + return new Promise((resolve, reject) => { + + // sync wallet in wasm which invokes callback when done + that.module.sync(that.cppAddress, startHeight, async (resp) => { + if (resp.charAt(0) !== '{') reject(new MoneroError(resp)); + else { + let respJson = JSON.parse(resp); + resolve(new MoneroSyncResult(respJson.numBlocksFetched, respJson.receivedMoney)); + } + }); + }); + } + } catch (e) { + err = e; + } + + // unregister listener + if (listener) await this.removeListener(listener); + + // throw error or return + if (err) throw err; + return result; + } + + async startSyncing(syncPeriodInMs?: number): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().startSyncing(syncPeriodInMs); + if (!await this.isConnectedToDaemon()) throw new MoneroError("Wallet is not connected to daemon"); + this.syncPeriodInMs = syncPeriodInMs === undefined ? MoneroWalletFull.DEFAULT_SYNC_PERIOD_IN_MS : syncPeriodInMs; + if (!this.syncLooper) this.syncLooper = new TaskLooper(async () => await this.backgroundSync()) + this.syncLooper.start(this.syncPeriodInMs); + } + + async stopSyncing(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().stopSyncing(); + this.assertNotClosed(); + if (this.syncLooper) this.syncLooper.stop(); + this.module.stop_syncing(this.cppAddress); // task is not queued so wallet stops immediately + } + + async scanTxs(txHashes: string[]): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().scanTxs(txHashes); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.scan_txs(this.cppAddress, JSON.stringify({txHashes: txHashes}), (err) => { + if (err) reject(new MoneroError(err)); + else resolve(); + }); + }); + }); + } + + async rescanSpent(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().rescanSpent(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.rescan_spent(this.cppAddress, () => resolve()); + }); + }); + } + + async rescanBlockchain(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().rescanBlockchain(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.rescan_blockchain(this.cppAddress, () => resolve()); + }); + }); + } + + async getBalance(accountIdx?: number, subaddressIdx?: number): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getBalance(accountIdx, subaddressIdx); + return this.module.queueTask(async () => { + this.assertNotClosed(); + + // get balance encoded in json string + let balanceStr; + if (accountIdx === undefined) { + assert(subaddressIdx === undefined, "Subaddress index must be undefined if account index is undefined"); + balanceStr = this.module.get_balance_wallet(this.cppAddress); + } else if (subaddressIdx === undefined) { + balanceStr = this.module.get_balance_account(this.cppAddress, accountIdx); + } else { + balanceStr = this.module.get_balance_subaddress(this.cppAddress, accountIdx, subaddressIdx); + } + + // parse json string to bigint + return BigInt(JSON.parse(GenUtils.stringifyBigInts(balanceStr)).balance); + }); + } + + async getUnlockedBalance(accountIdx?: number, subaddressIdx?: number): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getUnlockedBalance(accountIdx, subaddressIdx); + return this.module.queueTask(async () => { + this.assertNotClosed(); + + // get balance encoded in json string + let unlockedBalanceStr; + if (accountIdx === undefined) { + assert(subaddressIdx === undefined, "Subaddress index must be undefined if account index is undefined"); + unlockedBalanceStr = this.module.get_unlocked_balance_wallet(this.cppAddress); + } else if (subaddressIdx === undefined) { + unlockedBalanceStr = this.module.get_unlocked_balance_account(this.cppAddress, accountIdx); + } else { + unlockedBalanceStr = this.module.get_unlocked_balance_subaddress(this.cppAddress, accountIdx, subaddressIdx); + } + + // parse json string to bigint + return BigInt(JSON.parse(GenUtils.stringifyBigInts(unlockedBalanceStr)).unlockedBalance); + }); + } + + async getAccounts(includeSubaddresses?: boolean, tag?: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getAccounts(includeSubaddresses, tag); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let accountsStr = this.module.get_accounts(this.cppAddress, includeSubaddresses ? true : false, tag ? tag : ""); + let accounts = []; + for (let accountJson of JSON.parse(GenUtils.stringifyBigInts(accountsStr)).accounts) { + accounts.push(MoneroWalletFull.sanitizeAccount(new MoneroAccount(accountJson))); + } + return accounts; + }); + } + + async getAccount(accountIdx: number, includeSubaddresses?: boolean): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getAccount(accountIdx, includeSubaddresses); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let accountStr = this.module.get_account(this.cppAddress, accountIdx, includeSubaddresses ? true : false); + let accountJson = JSON.parse(GenUtils.stringifyBigInts(accountStr)); + return MoneroWalletFull.sanitizeAccount(new MoneroAccount(accountJson)); + }); + + } + + async createAccount(label?: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().createAccount(label); + if (label === undefined) label = ""; + return this.module.queueTask(async () => { + this.assertNotClosed(); + let accountStr = this.module.create_account(this.cppAddress, label); + let accountJson = JSON.parse(GenUtils.stringifyBigInts(accountStr)); + return MoneroWalletFull.sanitizeAccount(new MoneroAccount(accountJson)); + }); + } + + async getSubaddresses(accountIdx: number, subaddressIndices?: number[]): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getSubaddresses(accountIdx, subaddressIndices); + let args = {accountIdx: accountIdx, subaddressIndices: subaddressIndices === undefined ? [] : GenUtils.listify(subaddressIndices)}; + return this.module.queueTask(async () => { + this.assertNotClosed(); + let subaddressesJson = JSON.parse(GenUtils.stringifyBigInts(this.module.get_subaddresses(this.cppAddress, JSON.stringify(args)))).subaddresses; + let subaddresses = []; + for (let subaddressJson of subaddressesJson) subaddresses.push(MoneroWalletKeys.sanitizeSubaddress(new MoneroSubaddress(subaddressJson))); + return subaddresses; + }); + } + + async createSubaddress(accountIdx: number, label?: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().createSubaddress(accountIdx, label); + if (label === undefined) label = ""; + return this.module.queueTask(async () => { + this.assertNotClosed(); + let subaddressStr = this.module.create_subaddress(this.cppAddress, accountIdx, label); + let subaddressJson = JSON.parse(GenUtils.stringifyBigInts(subaddressStr)); + return MoneroWalletKeys.sanitizeSubaddress(new MoneroSubaddress(subaddressJson)); + }); + } + + async setSubaddressLabel(accountIdx: number, subaddressIdx: number, label: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().setSubaddressLabel(accountIdx, subaddressIdx, label); + if (label === undefined) label = ""; + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.set_subaddress_label(this.cppAddress, accountIdx, subaddressIdx, label); + }); + } + + async getTxs(query?: string[] | Partial): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getTxs(query); + + // copy and normalize query up to block + const queryNormalized = query = MoneroWallet.normalizeTxQuery(query); + + // schedule task + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // call wasm which invokes callback + this.module.get_txs(this.cppAddress, JSON.stringify(queryNormalized.getBlock().toJson()), (blocksJsonStr) => { + + // check for error + if (blocksJsonStr.charAt(0) !== '{') { + reject(new MoneroError(blocksJsonStr)); + return; + } + + // resolve with deserialized txs + try { + resolve(MoneroWalletFull.deserializeTxs(queryNormalized, blocksJsonStr)); + } catch (err) { + reject(err); + } + }); + }); + }); + } + + async getTransfers(query?: Partial): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getTransfers(query); + + // copy and normalize query up to block + const queryNormalized = MoneroWallet.normalizeTransferQuery(query); + + // return promise which resolves on callback + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // call wasm which invokes callback + this.module.get_transfers(this.cppAddress, JSON.stringify(queryNormalized.getTxQuery().getBlock().toJson()), (blocksJsonStr) => { + + // check for error + if (blocksJsonStr.charAt(0) !== '{') { + reject(new MoneroError(blocksJsonStr)); + return; + } + + // resolve with deserialized transfers + try { + resolve(MoneroWalletFull.deserializeTransfers(queryNormalized, blocksJsonStr)); + } catch (err) { + reject(err); + } + }); + }); + }); + } + + async getOutputs(query?: Partial): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getOutputs(query); + + // copy and normalize query up to block + const queryNormalized = MoneroWallet.normalizeOutputQuery(query); + + // return promise which resolves on callback + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) =>{ + + // call wasm which invokes callback + this.module.get_outputs(this.cppAddress, JSON.stringify(queryNormalized.getTxQuery().getBlock().toJson()), (blocksJsonStr) => { + + // check for error + if (blocksJsonStr.charAt(0) !== '{') { + reject(new MoneroError(blocksJsonStr)); + return; + } + + // resolve with deserialized outputs + try { + resolve(MoneroWalletFull.deserializeOutputs(queryNormalized, blocksJsonStr)); + } catch (err) { + reject(err); + } + }); + }); + }); + } + + async exportOutputs(all = false): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().exportOutputs(all); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.export_outputs(this.cppAddress, all, (outputsHex) => resolve(outputsHex)); + }); + }); + } + + async importOutputs(outputsHex: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().importOutputs(outputsHex); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.import_outputs(this.cppAddress, outputsHex, (numImported) => resolve(numImported)); + }); + }); + } + + async exportKeyImages(all = false): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().exportKeyImages(all); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.export_key_images(this.cppAddress, all, (keyImagesStr) => { + if (keyImagesStr.charAt(0) !== '{')reject(new MoneroError(keyImagesStr)); // json expected, else error + else { + let keyImages = []; + for (let keyImageJson of JSON.parse(GenUtils.stringifyBigInts(keyImagesStr)).keyImages) keyImages.push(new MoneroKeyImage(keyImageJson)); + resolve(keyImages); + } + }); + }); + }); + } + + async importKeyImages(keyImages: MoneroKeyImage[]): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().importKeyImages(keyImages); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.import_key_images(this.cppAddress, JSON.stringify({keyImages: keyImages.map(keyImage => keyImage.toJson())}), (keyImageImportResultStr) => { + if (keyImageImportResultStr.charAt(0) !== '{') reject(new MoneroError(keyImageImportResultStr)); // json expected, else error + else resolve(new MoneroKeyImageImportResult(JSON.parse(GenUtils.stringifyBigInts(keyImageImportResultStr)))); + }); + }); + }); + } + + async getNewKeyImagesFromLastImport(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getNewKeyImagesFromLastImport(); + throw new MoneroError("Not implemented"); + } + + async freezeOutput(keyImage: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().freezeOutput(keyImage); + if (!keyImage) throw new MoneroError("Must specify key image to freeze"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.freeze_output(this.cppAddress, keyImage, () => resolve()); + }); + }); + } + + async thawOutput(keyImage: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().thawOutput(keyImage); + if (!keyImage) throw new MoneroError("Must specify key image to thaw"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.thaw_output(this.cppAddress, keyImage, () => resolve()); + }); + }); + } + + async isOutputFrozen(keyImage: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().isOutputFrozen(keyImage); + if (!keyImage) throw new MoneroError("Must specify key image to check if frozen"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.is_output_frozen(this.cppAddress, keyImage, (result) => resolve(result)); + }); + }); + } + + async getDefaultFeePriority(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getDefaultFeePriority(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_default_fee_priority(this.cppAddress, (result) => resolve(result)); + }); + }); + } + + async createTxs(config: Partial): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().createTxs(config); + + // validate, copy, and normalize config + const configNormalized = MoneroWallet.normalizeCreateTxsConfig(config); + if (configNormalized.getCanSplit() === undefined) configNormalized.setCanSplit(true); + + // create txs in queue + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // create txs in wasm which invokes callback when done + this.module.create_txs(this.cppAddress, JSON.stringify(configNormalized.toJson()), (txSetJsonStr) => { + if (txSetJsonStr.charAt(0) !== '{') reject(new MoneroError(txSetJsonStr)); // json expected, else error + else resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBigInts(txSetJsonStr))).getTxs()); + }); + }); + }); + } + + async sweepOutput(config: Partial): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().sweepOutput(config); + + // normalize and validate config + const configNormalized = MoneroWallet.normalizeSweepOutputConfig(config); + + // sweep output in queue + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // sweep output in wasm which invokes callback when done + this.module.sweep_output(this.cppAddress, JSON.stringify(configNormalized.toJson()), (txSetJsonStr) => { + if (txSetJsonStr.charAt(0) !== '{') reject(new MoneroError(txSetJsonStr)); // json expected, else error + else resolve(new MoneroTxSet(JSON.parse(GenUtils.stringifyBigInts(txSetJsonStr))).getTxs()[0]); + }); + }); + }); + } + + async sweepUnlocked(config: Partial): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().sweepUnlocked(config); + + // validate and normalize config + const configNormalized = MoneroWallet.normalizeSweepUnlockedConfig(config); + + // sweep unlocked in queue + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // sweep unlocked in wasm which invokes callback when done + this.module.sweep_unlocked(this.cppAddress, JSON.stringify(configNormalized.toJson()), (txSetsJson) => { + if (txSetsJson.charAt(0) !== '{') reject(new MoneroError(txSetsJson)); // json expected, else error + else { + let txSets = []; + for (let txSetJson of JSON.parse(GenUtils.stringifyBigInts(txSetsJson)).txSets) txSets.push(new MoneroTxSet(txSetJson)); + let txs = []; + for (let txSet of txSets) for (let tx of txSet.getTxs()) txs.push(tx); + resolve(txs); + } + }); + }); + }); + } + + async sweepDust(relay?: boolean): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().sweepDust(relay); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + + // call wasm which invokes callback when done + this.module.sweep_dust(this.cppAddress, relay, (txSetJsonStr) => { + if (txSetJsonStr.charAt(0) !== '{') reject(new MoneroError(txSetJsonStr)); // json expected, else error + else { + let txSet = new MoneroTxSet(JSON.parse(GenUtils.stringifyBigInts(txSetJsonStr))); + if (txSet.getTxs() === undefined) txSet.setTxs([]); + resolve(txSet.getTxs()); + } + }); + }); + }); + } + + async relayTxs(txsOrMetadatas: (MoneroTxWallet | string)[]): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().relayTxs(txsOrMetadatas); + assert(Array.isArray(txsOrMetadatas), "Must provide an array of txs or their metadata to relay"); + let txMetadatas = []; + for (let txOrMetadata of txsOrMetadatas) txMetadatas.push(txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.relay_txs(this.cppAddress, JSON.stringify({txMetadatas: txMetadatas}), (txHashesJson) => { + if (txHashesJson.charAt(0) !== '{') reject(new MoneroError(txHashesJson)); + else resolve(JSON.parse(txHashesJson).txHashes); + }); + }); + }); + } + + async describeTxSet(txSet: MoneroTxSet): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().describeTxSet(txSet); + return this.module.queueTask(async () => { + this.assertNotClosed(); + txSet = new MoneroTxSet({unsignedTxHex: txSet.getUnsignedTxHex(), signedTxHex: txSet.getSignedTxHex(), multisigTxHex: txSet.getMultisigTxHex()}); + try { return new MoneroTxSet(JSON.parse(GenUtils.stringifyBigInts(this.module.describe_tx_set(this.cppAddress, JSON.stringify(txSet.toJson()))))); } + catch (err) { throw new MoneroError(this.module.get_exception_message(err)); } + }); + } + + async signTxs(unsignedTxHex: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().signTxs(unsignedTxHex); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { return new MoneroTxSet(JSON.parse(GenUtils.stringifyBigInts(this.module.sign_txs(this.cppAddress, unsignedTxHex)))); } + catch (err) { throw new MoneroError(this.module.get_exception_message(err)); } + }); + } + + async submitTxs(signedTxHex: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().submitTxs(signedTxHex); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.submit_txs(this.cppAddress, signedTxHex, (resp) => { + if (resp.charAt(0) !== '{') reject(new MoneroError(resp)); + else resolve(JSON.parse(resp).txHashes); + }); + }); + }); + } + + async signMessage(message: string, signatureType = MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY, accountIdx = 0, subaddressIdx = 0): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().signMessage(message, signatureType, accountIdx, subaddressIdx); + + // assign defaults + signatureType = signatureType || MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY; + accountIdx = accountIdx || 0; + subaddressIdx = subaddressIdx || 0; + + // queue task to sign message + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { return this.module.sign_message(this.cppAddress, message, signatureType === MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY ? 0 : 1, accountIdx, subaddressIdx); } + catch (err) { throw new MoneroError(this.module.get_exception_message(err)); } + }); + } + + async verifyMessage(message: string, address: string, signature: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().verifyMessage(message, address, signature); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let result; + try { + result = JSON.parse(this.module.verify_message(this.cppAddress, message, address, signature)); + } catch (err) { + result = {isGood: false}; + } + return new MoneroMessageSignatureResult(result.isGood ? + {isGood: result.isGood, isOld: result.isOld, signatureType: result.signatureType === "spend" ? MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY : MoneroMessageSignatureType.SIGN_WITH_VIEW_KEY, version: result.version} : + {isGood: false} + ); + }); + } + + async getTxKey(txHash: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getTxKey(txHash); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { return this.module.get_tx_key(this.cppAddress, txHash); } + catch (err) { throw new MoneroError(this.module.get_exception_message(err)); } + }); + } + + async checkTxKey(txHash: string, txKey: string, address: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().checkTxKey(txHash, txKey, address); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.check_tx_key(this.cppAddress, txHash, txKey, address, (respJsonStr) => { + if (respJsonStr.charAt(0) !== '{') reject(new MoneroError(respJsonStr)); + else resolve(new MoneroCheckTx(JSON.parse(GenUtils.stringifyBigInts(respJsonStr)))); + }); + }); + }); + } + + async getTxProof(txHash: string, address: string, message?: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getTxProof(txHash, address, message); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_tx_proof(this.cppAddress, txHash || "", address || "", message || "", (signature) => { + let errorKey = "error: "; + if (signature.indexOf(errorKey) === 0) reject(new MoneroError(signature.substring(errorKey.length))); + else resolve(signature); + }); + }); + }); + } + + async checkTxProof(txHash: string, address: string, message: string | undefined, signature: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().checkTxProof(txHash, address, message, signature); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.check_tx_proof(this.cppAddress, txHash || "", address || "", message || "", signature || "", (respJsonStr) => { + if (respJsonStr.charAt(0) !== '{') reject(new MoneroError(respJsonStr)); + else resolve(new MoneroCheckTx(JSON.parse(GenUtils.stringifyBigInts(respJsonStr)))); + }); + }); + }); + } + + async getSpendProof(txHash: string, message?: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getSpendProof(txHash, message); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_spend_proof(this.cppAddress, txHash || "", message || "", (signature) => { + let errorKey = "error: "; + if (signature.indexOf(errorKey) === 0) reject(new MoneroError(signature.substring(errorKey.length))); + else resolve(signature); + }); + }); + }); + } + + async checkSpendProof(txHash: string, message: string | undefined, signature: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().checkSpendProof(txHash, message, signature); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.check_spend_proof(this.cppAddress, txHash || "", message || "", signature || "", (resp) => { + typeof resp === "string" ? reject(new MoneroError(resp)) : resolve(resp); + }); + }); + }); + } + + async getReserveProofWallet(message?: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getReserveProofWallet(message); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_reserve_proof_wallet(this.cppAddress, message, (signature) => { + let errorKey = "error: "; + if (signature.indexOf(errorKey) === 0) reject(new MoneroError(signature.substring(errorKey.length), -1)); + else resolve(signature); + }); + }); + }); + } + + async getReserveProofAccount(accountIdx: number, amount: bigint, message?: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getReserveProofAccount(accountIdx, amount, message); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.get_reserve_proof_account(this.cppAddress, accountIdx, amount.toString(), message, (signature) => { + let errorKey = "error: "; + if (signature.indexOf(errorKey) === 0) reject(new MoneroError(signature.substring(errorKey.length), -1)); + else resolve(signature); + }); + }); + }); + } + + async checkReserveProof(address: string, message: string | undefined, signature: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().checkReserveProof(address, message, signature); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.check_reserve_proof(this.cppAddress, address, message, signature, (respJsonStr) => { + if (respJsonStr.charAt(0) !== '{') reject(new MoneroError(respJsonStr, -1)); + else resolve(new MoneroCheckReserve(JSON.parse(GenUtils.stringifyBigInts(respJsonStr)))); + }); + }); + }); + } + + async getTxNotes(txHashes: string[]): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getTxNotes(txHashes); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { return JSON.parse(this.module.get_tx_notes(this.cppAddress, JSON.stringify({txHashes: txHashes}))).txNotes; } + catch (err) { throw new MoneroError(this.module.get_exception_message(err)); } + }); + } + + async setTxNotes(txHashes: string[], notes: string[]): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().setTxNotes(txHashes, notes); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { this.module.set_tx_notes(this.cppAddress, JSON.stringify({txHashes: txHashes, txNotes: notes})); } + catch (err) { throw new MoneroError(this.module.get_exception_message(err)); } + }); + } + + async getAddressBookEntries(entryIndices?: number[]): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getAddressBookEntries(entryIndices); + if (!entryIndices) entryIndices = []; + return this.module.queueTask(async () => { + this.assertNotClosed(); + let entries = []; + for (let entryJson of JSON.parse(this.module.get_address_book_entries(this.cppAddress, JSON.stringify({entryIndices: entryIndices}))).entries) { + entries.push(new MoneroAddressBookEntry(entryJson)); + } + return entries; + }); + } + + async addAddressBookEntry(address: string, description?: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().addAddressBookEntry(address, description); + if (!address) address = ""; + if (!description) description = ""; + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.add_address_book_entry(this.cppAddress, address, description); + }); + } + + async editAddressBookEntry(index: number, setAddress: boolean, address: string | undefined, setDescription: boolean, description: string | undefined): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().editAddressBookEntry(index, setAddress, address, setDescription, description); + if (!setAddress) setAddress = false; + if (!address) address = ""; + if (!setDescription) setDescription = false; + if (!description) description = ""; + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.edit_address_book_entry(this.cppAddress, index, setAddress, address, setDescription, description); + }); + } + + async deleteAddressBookEntry(entryIdx: number): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().deleteAddressBookEntry(entryIdx); + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.delete_address_book_entry(this.cppAddress, entryIdx); + }); + } + + async tagAccounts(tag: string, accountIndices: number[]): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().tagAccounts(tag, accountIndices); + if (!tag) tag = ""; + if (!accountIndices) accountIndices = []; + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.tag_accounts(this.cppAddress, JSON.stringify({tag: tag, accountIndices: accountIndices})); + }); + } + + async untagAccounts(accountIndices: number[]): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().untagAccounts(accountIndices); + if (!accountIndices) accountIndices = []; + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.tag_accounts(this.cppAddress, JSON.stringify({accountIndices: accountIndices})); + }); + } + + async getAccountTags(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getAccountTags(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let accountTags = []; + for (let accountTagJson of JSON.parse(this.module.get_account_tags(this.cppAddress)).accountTags) accountTags.push(new MoneroAccountTag(accountTagJson)); + return accountTags; + }); + } + + async setAccountTagLabel(tag: string, label: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().setAccountTagLabel(tag, label); + if (!tag) tag = ""; + if (!label) label = ""; + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.set_account_tag_label(this.cppAddress, tag, label); + }); + } + + async getPaymentUri(config: MoneroTxConfig): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getPaymentUri(config); + config = MoneroWallet.normalizeCreateTxsConfig(config); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { + return this.module.get_payment_uri(this.cppAddress, JSON.stringify(config.toJson())); + } catch (err) { + throw new MoneroError("Cannot make URI from supplied parameters"); + } + }); + } + + async parsePaymentUri(uri: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().parsePaymentUri(uri); + return this.module.queueTask(async () => { + this.assertNotClosed(); + try { + return new MoneroTxConfig(JSON.parse(GenUtils.stringifyBigInts(this.module.parse_payment_uri(this.cppAddress, uri)))); + } catch (err: any) { + throw new MoneroError(err.message); + } + }); + } + + async getAttribute(key: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getAttribute(key); + this.assertNotClosed(); + assert(typeof key === "string", "Attribute key must be a string"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let value = this.module.get_attribute(this.cppAddress, key); + return value === "" ? null : value; + }); + } + + async setAttribute(key: string, val: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().setAttribute(key, val); + this.assertNotClosed(); + assert(typeof key === "string", "Attribute key must be a string"); + assert(typeof val === "string", "Attribute value must be a string"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + this.module.set_attribute(this.cppAddress, key, val); + }); + } + + async startMining(numThreads: number, backgroundMining?: boolean, ignoreBattery?: boolean): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().startMining(numThreads, backgroundMining, ignoreBattery); + this.assertNotClosed(); + let daemon = await MoneroDaemonRpc.connectToDaemonRpc(await this.getDaemonConnection()); + await daemon.startMining(await this.getPrimaryAddress(), numThreads, backgroundMining, ignoreBattery); + } + + async stopMining(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().stopMining(); + this.assertNotClosed(); + let daemon = await MoneroDaemonRpc.connectToDaemonRpc(await this.getDaemonConnection()); + await daemon.stopMining(); + } + + async isMultisigImportNeeded(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().isMultisigImportNeeded(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.is_multisig_import_needed(this.cppAddress); + }); + } + + async isMultisig(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().isMultisig(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.is_multisig(this.cppAddress); + }); + } + + async getMultisigInfo(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getMultisigInfo(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new MoneroMultisigInfo(JSON.parse(this.module.get_multisig_info(this.cppAddress))); + }); + } + + async prepareMultisig(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().prepareMultisig(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.prepare_multisig(this.cppAddress); + }); + } + + async makeMultisig(multisigHexes: string[], threshold: number, password: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().makeMultisig(multisigHexes, threshold, password); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.make_multisig(this.cppAddress, JSON.stringify({multisigHexes: multisigHexes, threshold: threshold, password: password}), (resp) => { + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) reject(new MoneroError(resp.substring(errorKey.length))); + else resolve(resp); + }); + }); + }); + } + + async exchangeMultisigKeys(multisigHexes: string[], password: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().exchangeMultisigKeys(multisigHexes, password); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.exchange_multisig_keys(this.cppAddress, JSON.stringify({multisigHexes: multisigHexes, password: password}), (resp) => { + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) reject(new MoneroError(resp.substring(errorKey.length))); + else resolve(new MoneroMultisigInitResult(JSON.parse(resp))); + }); + }); + }); + } + + async exportMultisigHex(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().exportMultisigHex(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.export_multisig_hex(this.cppAddress); + }); + } + + async importMultisigHex(multisigHexes: string[]): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().importMultisigHex(multisigHexes); + if (!GenUtils.isArray(multisigHexes)) throw new MoneroError("Must provide string[] to importMultisigHex()") + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.import_multisig_hex(this.cppAddress, JSON.stringify({multisigHexes: multisigHexes}), (resp) => { + if (typeof resp === "string") reject(new MoneroError(resp)); + else resolve(resp); + }); + }); + }); + } + + async signMultisigTxHex(multisigTxHex: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().signMultisigTxHex(multisigTxHex); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.sign_multisig_tx_hex(this.cppAddress, multisigTxHex, (resp) => { + if (resp.charAt(0) !== '{') reject(new MoneroError(resp)); + else resolve(new MoneroMultisigSignResult(JSON.parse(resp))); + }); + }); + }); + } + + async submitMultisigTxHex(signedMultisigTxHex: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().submitMultisigTxHex(signedMultisigTxHex); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.submit_multisig_tx_hex(this.cppAddress, signedMultisigTxHex, (resp) => { + if (resp.charAt(0) !== '{') reject(new MoneroError(resp)); + else resolve(JSON.parse(resp).txHashes); + }); + }); + }); + } + + /** + * Get the wallet's keys and cache data. + * + * @return {Promise} is the keys and cache data, respectively + */ + async getData(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getData(); + + // queue call to wasm module + let viewOnly = await this.isViewOnly(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + + // store views in array + let views = []; + + // malloc cache buffer and get buffer location in c++ heap + let cacheBufferLoc = JSON.parse(this.module.get_cache_file_buffer(this.cppAddress)); + + // read binary data from heap to DataView + let view = new DataView(new ArrayBuffer(cacheBufferLoc.length)); + for (let i = 0; i < cacheBufferLoc.length; i++) { + view.setInt8(i, this.module.HEAPU8[cacheBufferLoc.pointer / Uint8Array.BYTES_PER_ELEMENT + i]); + } + + // free binary on heap + this.module._free(cacheBufferLoc.pointer); + + // write cache file + views.push(Buffer.from(view.buffer)); + + // malloc keys buffer and get buffer location in c++ heap + let keysBufferLoc = JSON.parse(this.module.get_keys_file_buffer(this.cppAddress, this.password, viewOnly)); + + // read binary data from heap to DataView + view = new DataView(new ArrayBuffer(keysBufferLoc.length)); + for (let i = 0; i < keysBufferLoc.length; i++) { + view.setInt8(i, this.module.HEAPU8[keysBufferLoc.pointer / Uint8Array.BYTES_PER_ELEMENT + i]); + } + + // free binary on heap + this.module._free(keysBufferLoc.pointer); + + // prepend keys file + views.unshift(Buffer.from(view.buffer)); + return views; + }); + } + + async changePassword(oldPassword: string, newPassword: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().changePassword(oldPassword, newPassword); + if (oldPassword !== this.password) throw new MoneroError("Invalid original password."); // wallet2 verify_password loads from disk so verify password here + if (newPassword === undefined) newPassword = ""; + await this.module.queueTask(async () => { + this.assertNotClosed(); + return new Promise((resolve, reject) => { + this.module.change_wallet_password(this.cppAddress, oldPassword, newPassword, (errMsg) => { + if (errMsg) reject(new MoneroError(errMsg)); + else resolve(); + }); + }); + }); + this.password = newPassword; + if (this.path) await this.save(); // auto save + } + + async save(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().save(); + return MoneroWalletFull.save(this); + } + + async close(save = false): Promise { + if (this._isClosed) return; // no effect if closed + if (save) await this.save(); + if (this.getWalletProxy()) { + await this.getWalletProxy().close(false); + await super.close(); + return; + } + await this.refreshListening(); + await this.stopSyncing(); + await super.close(); + delete this.path; + delete this.password; + delete this.wasmListener; + LibraryUtils.setRejectUnauthorizedFn(this.rejectUnauthorizedConfigId, undefined); // unregister fn informing if unauthorized reqs should be rejected + } + + // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS -------------- + + async getNumBlocksToUnlock(): Promise { return super.getNumBlocksToUnlock(); } + async getTx(txHash: string): Promise { return super.getTx(txHash); } + async getIncomingTransfers(query: Partial): Promise { return super.getIncomingTransfers(query); } + async getOutgoingTransfers(query: Partial) { return super.getOutgoingTransfers(query); } + async createTx(config: Partial): Promise { return super.createTx(config); } + async relayTx(txOrMetadata: MoneroTxWallet | string): Promise { return super.relayTx(txOrMetadata); } + async getTxNote(txHash: string): Promise { return super.getTxNote(txHash); } + async setTxNote(txHash: string, note: string): Promise { return super.setTxNote(txHash, note); } + + // ---------------------------- PRIVATE HELPERS ---------------------------- + + protected static async openWalletData(config: Partial) { + if (config.proxyToWorker) { + let walletProxy = await MoneroWalletFullProxy.openWalletData(config); + return new MoneroWalletFull(undefined, undefined, undefined, undefined, undefined, undefined, walletProxy); + } + + // validate and normalize parameters + if (config.networkType === undefined) throw new MoneroError("Must provide the wallet's network type"); + config.networkType = MoneroNetworkType.from(config.networkType); + let daemonConnection = config.getServer(); + let daemonUri = daemonConnection && daemonConnection.getUri() ? daemonConnection.getUri() : ""; + let daemonUsername = daemonConnection && daemonConnection.getUsername() ? daemonConnection.getUsername() : ""; + let daemonPassword = daemonConnection && daemonConnection.getPassword() ? daemonConnection.getPassword() : ""; + let rejectUnauthorized = daemonConnection ? daemonConnection.getRejectUnauthorized() : true; + + // load wasm module + let module = await LibraryUtils.loadWasmModule(); + + // open wallet in queue + return module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // register fn informing if unauthorized reqs should be rejected + let rejectUnauthorizedFnId = GenUtils.getUUID(); + LibraryUtils.setRejectUnauthorizedFn(rejectUnauthorizedFnId, () => rejectUnauthorized); + + // create wallet in wasm which invokes callback when done + module.open_wallet_full(config.password, config.networkType, config.keysData ?? "", config.cacheData ?? "", daemonUri, daemonUsername, daemonPassword, rejectUnauthorizedFnId, (cppAddress) => { + if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); + else resolve(new MoneroWalletFull(cppAddress, config.path, config.password, config.fs, rejectUnauthorized, rejectUnauthorizedFnId)); + }); + }); + }); + } + + protected getWalletProxy(): MoneroWalletFullProxy { + return super.getWalletProxy() as MoneroWalletFullProxy; + } + + protected async backgroundSync() { + let label = this.path ? this.path : (this.browserMainPath ? this.browserMainPath : "in-memory wallet"); // label for log + LibraryUtils.log(1, "Background synchronizing " + label); + try { await this.sync(); } + catch (err: any) { if (!this._isClosed) console.error("Failed to background synchronize " + label + ": " + err.message); } + } + + protected async refreshListening() { + let isEnabled = this.listeners.length > 0; + if (this.wasmListenerHandle === 0 && !isEnabled || this.wasmListenerHandle > 0 && isEnabled) return; // no difference + return this.module.queueTask(async () => { + return new Promise((resolve, reject) => { + this.module.set_listener( + this.cppAddress, + this.wasmListenerHandle, + newListenerHandle => { + if (typeof newListenerHandle === "string") reject(new MoneroError(newListenerHandle)); + else { + this.wasmListenerHandle = newListenerHandle; + resolve(); + } + }, + isEnabled ? async (height, startHeight, endHeight, percentDone, message) => await this.wasmListener.onSyncProgress(height, startHeight, endHeight, percentDone, message) : undefined, + isEnabled ? async (height) => await this.wasmListener.onNewBlock(height) : undefined, + isEnabled ? async (newBalanceStr, newUnlockedBalanceStr) => await this.wasmListener.onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) : undefined, + isEnabled ? async (height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockTime, isLocked) => await this.wasmListener.onOutputReceived(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockTime, isLocked) : undefined, + isEnabled ? async (height, txHash, amountStr, accountIdxStr, subaddressIdxStr, version, unlockTime, isLocked) => await this.wasmListener.onOutputSpent(height, txHash, amountStr, accountIdxStr, subaddressIdxStr, version, unlockTime, isLocked) : undefined, + ); + }); + }); + } + + static sanitizeBlock(block) { + for (let tx of block.getTxs()) MoneroWalletFull.sanitizeTxWallet(tx); + return block; + } + + static sanitizeTxWallet(tx) { + assert(tx instanceof MoneroTxWallet); + return tx; + } + + static sanitizeAccount(account) { + if (account.getSubaddresses()) { + for (let subaddress of account.getSubaddresses()) MoneroWalletKeys.sanitizeSubaddress(subaddress); + } + return account; + } + + static deserializeBlocks(blocksJsonStr) { + let blocksJson = JSON.parse(GenUtils.stringifyBigInts(blocksJsonStr)); + let deserializedBlocks: any = {}; + deserializedBlocks.blocks = []; + if (blocksJson.blocks) for (let blockJson of blocksJson.blocks) deserializedBlocks.blocks.push(MoneroWalletFull.sanitizeBlock(new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET))); + return deserializedBlocks; + } + + static deserializeTxs(query, blocksJsonStr) { + + // deserialize blocks + let deserializedBlocks = MoneroWalletFull.deserializeBlocks(blocksJsonStr); + let blocks = deserializedBlocks.blocks; + + // collect txs + let txs = []; + for (let block of blocks) { + MoneroWalletFull.sanitizeBlock(block); + for (let tx of block.getTxs()) { + if (block.getHeight() === undefined) tx.setBlock(undefined); // dereference placeholder block for unconfirmed txs + txs.push(tx); + } + } + + // re-sort txs which is lost over wasm serialization // TODO: confirm that order is lost + if (query.getHashes() !== undefined) { + let txMap = new Map(); + for (let tx of txs) txMap[tx.getHash()] = tx; + let txsSorted = []; + for (let txHash of query.getHashes()) if (txMap[txHash] !== undefined) txsSorted.push(txMap[txHash]); + txs = txsSorted; + } + + return txs; + } + + static deserializeTransfers(query, blocksJsonStr) { + + // deserialize blocks + let deserializedBlocks = MoneroWalletFull.deserializeBlocks(blocksJsonStr); + let blocks = deserializedBlocks.blocks; + + // collect transfers + let transfers = []; + for (let block of blocks) { + for (let tx of block.getTxs()) { + if (block.getHeight() === undefined) tx.setBlock(undefined); // dereference placeholder block for unconfirmed txs + if (tx.getOutgoingTransfer() !== undefined) transfers.push(tx.getOutgoingTransfer()); + if (tx.getIncomingTransfers() !== undefined) { + for (let transfer of tx.getIncomingTransfers()) transfers.push(transfer); + } + } + } + + return transfers; + } + + static deserializeOutputs(query, blocksJsonStr) { + + // deserialize blocks + let deserializedBlocks = MoneroWalletFull.deserializeBlocks(blocksJsonStr); + let blocks = deserializedBlocks.blocks; + + // collect outputs + let outputs = []; + for (let block of blocks) { + for (let tx of block.getTxs()) { + for (let output of tx.getOutputs()) outputs.push(output); + } + } + + return outputs; + } + + /** + * Set the path of the wallet on the browser main thread if run as a worker. + * + * @param {string} browserMainPath - path of the wallet on the browser main thread + */ + protected setBrowserMainPath(browserMainPath) { + this.browserMainPath = browserMainPath; + } + + static async moveTo(path, wallet) { + + // save and return if same path + if (Path.normalize(wallet.path) === Path.normalize(path)) { + return wallet.save(); + } + + return LibraryUtils.queueTask(async () => { + if (await wallet.isClosed()) throw new MoneroError("Wallet is closed"); + if (!path) throw new MoneroError("Must provide path of destination wallet"); + + // create destination directory if it doesn't exist + let walletDir = Path.dirname(path); + if (!await LibraryUtils.exists(wallet.fs, walletDir)) { + try { await wallet.fs.mkdir(walletDir); } + catch (err: any) { throw new MoneroError("Destination path " + path + " does not exist and cannot be created: " + err.message); } + } + + // get wallet data + const data = await wallet.getData(); + + // write wallet files + await wallet.fs.writeFile(path + ".keys", data[0], "binary"); + await wallet.fs.writeFile(path, data[1], "binary"); + await wallet.fs.writeFile(path + ".address.txt", await wallet.getPrimaryAddress()); + let oldPath = wallet.path; + wallet.path = path; + + // delete old wallet files + if (oldPath) { + await wallet.fs.unlink(oldPath + ".address.txt"); + await wallet.fs.unlink(oldPath + ".keys"); + await wallet.fs.unlink(oldPath); + } + }); + } + + static async save(wallet: any) { + return LibraryUtils.queueTask(async () => { + if (await wallet.isClosed()) throw new MoneroError("Wallet is closed"); + + // path must be set + let path = await wallet.getPath(); + if (!path) throw new MoneroError("Cannot save wallet because path is not set"); + + // get wallet data + const data = await wallet.getData(); + + // write wallet files to *.new + let pathNew = path + ".new"; + await wallet.fs.writeFile(pathNew + ".keys", data[0], "binary"); + await wallet.fs.writeFile(pathNew, data[1], "binary"); + await wallet.fs.writeFile(pathNew + ".address.txt", await wallet.getPrimaryAddress()); + + // replace old wallet files with new + await wallet.fs.rename(pathNew + ".keys", path + ".keys"); + await wallet.fs.rename(pathNew, path); + await wallet.fs.rename(pathNew + ".address.txt", path + ".address.txt"); + }); + } +} + +/** + * Implements a MoneroWallet by proxying requests to a worker which runs a full wallet. + * + * @private + */ +class MoneroWalletFullProxy extends MoneroWalletKeysProxy { + + // instance variables + protected path: any; + protected fs: any; + protected wrappedListeners: any; + + // -------------------------- WALLET STATIC UTILS --------------------------- + + static async openWalletData(config: Partial) { + let walletId = GenUtils.getUUID(); + if (config.password === undefined) config.password = ""; + let daemonConnection = config.getServer(); + await LibraryUtils.invokeWorker(walletId, "openWalletData", [config.path, config.password, config.networkType, config.keysData, config.cacheData, daemonConnection ? daemonConnection.toJson() : undefined]); + let wallet = new MoneroWalletFullProxy(walletId, await LibraryUtils.getWorker(), config.path, config.getFs()); + if (config.path) await wallet.save(); + return wallet; + } + + static async createWallet(config) { + if (config.getPath() && await MoneroWalletFull.walletExists(config.getPath(), config.getFs())) throw new MoneroError("Wallet already exists: " + config.getPath()); + let walletId = GenUtils.getUUID(); + await LibraryUtils.invokeWorker(walletId, "createWalletFull", [config.toJson()]); + let wallet = new MoneroWalletFullProxy(walletId, await LibraryUtils.getWorker(), config.getPath(), config.getFs()); + if (config.getPath()) await wallet.save(); + return wallet; + } + + // --------------------------- INSTANCE METHODS ---------------------------- + + /** + * Internal constructor which is given a worker to communicate with via messages. + * + * This method should not be called externally but should be called through + * static wallet creation utilities in this class. + * + * @param {string} walletId - identifies the wallet with the worker + * @param {Worker} worker - worker to communicate with via messages + */ + constructor(walletId, worker, path, fs) { + super(walletId, worker); + this.path = path; + this.fs = fs ? fs : (path ? MoneroWalletFull.getFs() : undefined); + this.wrappedListeners = []; + } + + getPath() { + return this.path; + } + + async getNetworkType() { + return this.invokeWorker("getNetworkType"); + } + + async setSubaddressLabel(accountIdx, subaddressIdx, label) { + return this.invokeWorker("setSubaddressLabel", Array.from(arguments)) as Promise; + } + + async setDaemonConnection(uriOrRpcConnection) { + if (!uriOrRpcConnection) await this.invokeWorker("setDaemonConnection"); + else { + let connection = !uriOrRpcConnection ? undefined : uriOrRpcConnection instanceof MoneroRpcConnection ? uriOrRpcConnection : new MoneroRpcConnection(uriOrRpcConnection); + await this.invokeWorker("setDaemonConnection", connection ? connection.getConfig() : undefined); + } + } + + async getDaemonConnection() { + let rpcConfig = await this.invokeWorker("getDaemonConnection"); + return rpcConfig ? new MoneroRpcConnection(rpcConfig) : undefined; + } + + async isConnectedToDaemon() { + return this.invokeWorker("isConnectedToDaemon"); + } + + async getRestoreHeight() { + return this.invokeWorker("getRestoreHeight"); + } + + async setRestoreHeight(restoreHeight) { + return this.invokeWorker("setRestoreHeight", [restoreHeight]); + } + + async getDaemonHeight() { + return this.invokeWorker("getDaemonHeight"); + } + + async getDaemonMaxPeerHeight() { + return this.invokeWorker("getDaemonMaxPeerHeight"); + } + + async getHeightByDate(year, month, day) { + return this.invokeWorker("getHeightByDate", [year, month, day]); + } + + async isDaemonSynced() { + return this.invokeWorker("isDaemonSynced"); + } + + async getHeight() { + return this.invokeWorker("getHeight"); + } + + async addListener(listener) { + let wrappedListener = new WalletWorkerListener(listener); + let listenerId = wrappedListener.getId(); + LibraryUtils.addWorkerCallback(this.walletId, "onSyncProgress_" + listenerId, [wrappedListener.onSyncProgress, wrappedListener]); + LibraryUtils.addWorkerCallback(this.walletId, "onNewBlock_" + listenerId, [wrappedListener.onNewBlock, wrappedListener]); + LibraryUtils.addWorkerCallback(this.walletId, "onBalancesChanged_" + listenerId, [wrappedListener.onBalancesChanged, wrappedListener]); + LibraryUtils.addWorkerCallback(this.walletId, "onOutputReceived_" + listenerId, [wrappedListener.onOutputReceived, wrappedListener]); + LibraryUtils.addWorkerCallback(this.walletId, "onOutputSpent_" + listenerId, [wrappedListener.onOutputSpent, wrappedListener]); + this.wrappedListeners.push(wrappedListener); + return this.invokeWorker("addListener", [listenerId]); + } + + async removeListener(listener) { + for (let i = 0; i < this.wrappedListeners.length; i++) { + if (this.wrappedListeners[i].getListener() === listener) { + let listenerId = this.wrappedListeners[i].getId(); + await this.invokeWorker("removeListener", [listenerId]); + LibraryUtils.removeWorkerCallback(this.walletId, "onSyncProgress_" + listenerId); + LibraryUtils.removeWorkerCallback(this.walletId, "onNewBlock_" + listenerId); + LibraryUtils.removeWorkerCallback(this.walletId, "onBalancesChanged_" + listenerId); + LibraryUtils.removeWorkerCallback(this.walletId, "onOutputReceived_" + listenerId); + LibraryUtils.removeWorkerCallback(this.walletId, "onOutputSpent_" + listenerId); + this.wrappedListeners.splice(i, 1); + return; + } + } + throw new MoneroError("Listener is not registered with wallet"); + } + + getListeners() { + let listeners = []; + for (let wrappedListener of this.wrappedListeners) listeners.push(wrappedListener.getListener()); + return listeners; + } + + async isSynced() { + return this.invokeWorker("isSynced"); + } + + async sync(listenerOrStartHeight?: MoneroWalletListener | number, startHeight?: number, allowConcurrentCalls = false): Promise { + + // normalize params + startHeight = listenerOrStartHeight instanceof MoneroWalletListener ? startHeight : listenerOrStartHeight; + let listener = listenerOrStartHeight instanceof MoneroWalletListener ? listenerOrStartHeight : undefined; + if (startHeight === undefined) startHeight = Math.max(await this.getHeight(), await this.getRestoreHeight()); + + // register listener if given + if (listener) await this.addListener(listener); + + // sync wallet in worker + let err; + let result; + try { + let resultJson = await this.invokeWorker("sync", [startHeight, allowConcurrentCalls]); + result = new MoneroSyncResult(resultJson.numBlocksFetched, resultJson.receivedMoney); + } catch (e) { + err = e; + } + + // unregister listener + if (listener) await this.removeListener(listener); + + // throw error or return + if (err) throw err; + return result; + } + + async startSyncing(syncPeriodInMs) { + return this.invokeWorker("startSyncing", Array.from(arguments)); + } + + async stopSyncing() { + return this.invokeWorker("stopSyncing"); + } + + async scanTxs(txHashes) { + assert(Array.isArray(txHashes), "Must provide an array of txs hashes to scan"); + return this.invokeWorker("scanTxs", [txHashes]); + } + + async rescanSpent() { + return this.invokeWorker("rescanSpent"); + } + + async rescanBlockchain() { + return this.invokeWorker("rescanBlockchain"); + } + + async getBalance(accountIdx, subaddressIdx) { + return BigInt(await this.invokeWorker("getBalance", Array.from(arguments))); + } + + async getUnlockedBalance(accountIdx, subaddressIdx) { + let unlockedBalanceStr = await this.invokeWorker("getUnlockedBalance", Array.from(arguments)); + return BigInt(unlockedBalanceStr); + } + + async getAccounts(includeSubaddresses, tag) { + let accounts = []; + for (let accountJson of (await this.invokeWorker("getAccounts", Array.from(arguments)))) { + accounts.push(MoneroWalletFull.sanitizeAccount(new MoneroAccount(accountJson))); + } + return accounts; + } + + async getAccount(accountIdx, includeSubaddresses) { + let accountJson = await this.invokeWorker("getAccount", Array.from(arguments)); + return MoneroWalletFull.sanitizeAccount(new MoneroAccount(accountJson)); + } + + async createAccount(label) { + let accountJson = await this.invokeWorker("createAccount", Array.from(arguments)); + return MoneroWalletFull.sanitizeAccount(new MoneroAccount(accountJson)); + } + + async getSubaddresses(accountIdx, subaddressIndices) { + let subaddresses = []; + for (let subaddressJson of (await this.invokeWorker("getSubaddresses", Array.from(arguments)))) { + subaddresses.push(MoneroWalletKeys.sanitizeSubaddress(new MoneroSubaddress(subaddressJson))); + } + return subaddresses; + } + + async createSubaddress(accountIdx, label) { + let subaddressJson = await this.invokeWorker("createSubaddress", Array.from(arguments)); + return MoneroWalletKeys.sanitizeSubaddress(new MoneroSubaddress(subaddressJson)); + } + + async getTxs(query) { + query = MoneroWallet.normalizeTxQuery(query); + let respJson = await this.invokeWorker("getTxs", [query.getBlock().toJson()]); + return MoneroWalletFull.deserializeTxs(query, JSON.stringify({blocks: respJson.blocks})); // initialize txs from blocks json string TODO: this stringifies then utility parses, avoid + } + + async getTransfers(query) { + query = MoneroWallet.normalizeTransferQuery(query); + let blockJsons = await this.invokeWorker("getTransfers", [query.getTxQuery().getBlock().toJson()]); + return MoneroWalletFull.deserializeTransfers(query, JSON.stringify({blocks: blockJsons})); // initialize transfers from blocks json string TODO: this stringifies then utility parses, avoid + } + + async getOutputs(query) { + query = MoneroWallet.normalizeOutputQuery(query); + let blockJsons = await this.invokeWorker("getOutputs", [query.getTxQuery().getBlock().toJson()]); + return MoneroWalletFull.deserializeOutputs(query, JSON.stringify({blocks: blockJsons})); // initialize transfers from blocks json string TODO: this stringifies then utility parses, avoid + } + + async exportOutputs(all) { + return this.invokeWorker("exportOutputs", [all]); + } + + async importOutputs(outputsHex) { + return this.invokeWorker("importOutputs", [outputsHex]); + } + + async exportKeyImages(all) { + let keyImages = []; + for (let keyImageJson of await this.invokeWorker("getKeyImages", [all])) keyImages.push(new MoneroKeyImage(keyImageJson)); + return keyImages; + } + + async importKeyImages(keyImages) { + let keyImagesJson = []; + for (let keyImage of keyImages) keyImagesJson.push(keyImage.toJson()); + return new MoneroKeyImageImportResult(await this.invokeWorker("importKeyImages", [keyImagesJson])); + } + + async getNewKeyImagesFromLastImport(): Promise { + throw new MoneroError("MoneroWalletFull.getNewKeyImagesFromLastImport() not implemented"); + } + + async freezeOutput(keyImage) { + return this.invokeWorker("freezeOutput", [keyImage]); + } + + async thawOutput(keyImage) { + return this.invokeWorker("thawOutput", [keyImage]); + } + + async isOutputFrozen(keyImage) { + return this.invokeWorker("isOutputFrozen", [keyImage]); + } + + async getDefaultFeePriority() { + return this.invokeWorker("getDefaultFeePriority"); + } + + async createTxs(config) { + config = MoneroWallet.normalizeCreateTxsConfig(config); + let txSetJson = await this.invokeWorker("createTxs", [config.toJson()]); + return new MoneroTxSet(txSetJson).getTxs(); + } + + async sweepOutput(config) { + config = MoneroWallet.normalizeSweepOutputConfig(config); + let txSetJson = await this.invokeWorker("sweepOutput", [config.toJson()]); + return new MoneroTxSet(txSetJson).getTxs()[0]; + } + + async sweepUnlocked(config) { + config = MoneroWallet.normalizeSweepUnlockedConfig(config); + let txSetsJson = await this.invokeWorker("sweepUnlocked", [config.toJson()]); + let txs = []; + for (let txSetJson of txSetsJson) for (let tx of new MoneroTxSet(txSetJson).getTxs()) txs.push(tx); + return txs; + } + + async sweepDust(relay) { + return new MoneroTxSet(await this.invokeWorker("sweepDust", [relay])).getTxs() || []; + } + + async relayTxs(txsOrMetadatas) { + assert(Array.isArray(txsOrMetadatas), "Must provide an array of txs or their metadata to relay"); + let txMetadatas = []; + for (let txOrMetadata of txsOrMetadatas) txMetadatas.push(txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata); + return this.invokeWorker("relayTxs", [txMetadatas]); + } + + async describeTxSet(txSet) { + return new MoneroTxSet(await this.invokeWorker("describeTxSet", [txSet.toJson()])); + } + + async signTxs(unsignedTxHex) { + return new MoneroTxSet(await this.invokeWorker("signTxs", Array.from(arguments))); + } + + async submitTxs(signedTxHex) { + return this.invokeWorker("submitTxs", Array.from(arguments)); + } + + async signMessage(message, signatureType, accountIdx, subaddressIdx) { + return this.invokeWorker("signMessage", Array.from(arguments)); + } + + async verifyMessage(message, address, signature) { + return new MoneroMessageSignatureResult(await this.invokeWorker("verifyMessage", Array.from(arguments))); + } + + async getTxKey(txHash) { + return this.invokeWorker("getTxKey", Array.from(arguments)); + } + + async checkTxKey(txHash, txKey, address) { + return new MoneroCheckTx(await this.invokeWorker("checkTxKey", Array.from(arguments))); + } + + async getTxProof(txHash, address, message) { + return this.invokeWorker("getTxProof", Array.from(arguments)); + } + + async checkTxProof(txHash, address, message, signature) { + return new MoneroCheckTx(await this.invokeWorker("checkTxProof", Array.from(arguments))); + } + + async getSpendProof(txHash, message) { + return this.invokeWorker("getSpendProof", Array.from(arguments)); + } + + async checkSpendProof(txHash, message, signature) { + return this.invokeWorker("checkSpendProof", Array.from(arguments)); + } + + async getReserveProofWallet(message) { + return this.invokeWorker("getReserveProofWallet", Array.from(arguments)); + } + + async getReserveProofAccount(accountIdx, amount, message) { + try { return await this.invokeWorker("getReserveProofAccount", [accountIdx, amount.toString(), message]); } + catch (e: any) { throw new MoneroError(e.message, -1); } + } + + async checkReserveProof(address, message, signature) { + try { return new MoneroCheckReserve(await this.invokeWorker("checkReserveProof", Array.from(arguments))); } + catch (e: any) { throw new MoneroError(e.message, -1); } + } + + async getTxNotes(txHashes) { + return this.invokeWorker("getTxNotes", Array.from(arguments)); + } + + async setTxNotes(txHashes, notes) { + return this.invokeWorker("setTxNotes", Array.from(arguments)); + } + + async getAddressBookEntries(entryIndices) { + if (!entryIndices) entryIndices = []; + let entries = []; + for (let entryJson of await this.invokeWorker("getAddressBookEntries", Array.from(arguments))) { + entries.push(new MoneroAddressBookEntry(entryJson)); + } + return entries; + } + + async addAddressBookEntry(address, description) { + return this.invokeWorker("addAddressBookEntry", Array.from(arguments)); + } + + async editAddressBookEntry(index, setAddress, address, setDescription, description) { + return this.invokeWorker("editAddressBookEntry", Array.from(arguments)); + } + + async deleteAddressBookEntry(entryIdx) { + return this.invokeWorker("deleteAddressBookEntry", Array.from(arguments)); + } + + async tagAccounts(tag, accountIndices) { + return this.invokeWorker("tagAccounts", Array.from(arguments)); + } + + async untagAccounts(accountIndices) { + return this.invokeWorker("untagAccounts", Array.from(arguments)); + } + + async getAccountTags() { + return this.invokeWorker("getAccountTags", Array.from(arguments)); + } + + async setAccountTagLabel(tag, label) { + return this.invokeWorker("setAccountTagLabel", Array.from(arguments)); + } + + async getPaymentUri(config) { + config = MoneroWallet.normalizeCreateTxsConfig(config); + return this.invokeWorker("getPaymentUri", [config.toJson()]); + } + + async parsePaymentUri(uri) { + return new MoneroTxConfig(await this.invokeWorker("parsePaymentUri", Array.from(arguments))); + } + + async getAttribute(key) { + return this.invokeWorker("getAttribute", Array.from(arguments)); + } + + async setAttribute(key, val) { + return this.invokeWorker("setAttribute", Array.from(arguments)); + } + + async startMining(numThreads, backgroundMining, ignoreBattery) { + return this.invokeWorker("startMining", Array.from(arguments)); + } + + async stopMining() { + return this.invokeWorker("stopMining", Array.from(arguments)); + } + + async isMultisigImportNeeded() { + return this.invokeWorker("isMultisigImportNeeded"); + } + + async isMultisig() { + return this.invokeWorker("isMultisig"); + } + + async getMultisigInfo() { + return new MoneroMultisigInfo(await this.invokeWorker("getMultisigInfo")); + } + + async prepareMultisig() { + return this.invokeWorker("prepareMultisig"); + } + + async makeMultisig(multisigHexes, threshold, password) { + return await this.invokeWorker("makeMultisig", Array.from(arguments)); + } + + async exchangeMultisigKeys(multisigHexes, password) { + return new MoneroMultisigInitResult(await this.invokeWorker("exchangeMultisigKeys", Array.from(arguments))); + } + + async exportMultisigHex() { + return this.invokeWorker("exportMultisigHex"); + } + + async importMultisigHex(multisigHexes) { + return this.invokeWorker("importMultisigHex", Array.from(arguments)); + } + + async signMultisigTxHex(multisigTxHex) { + return new MoneroMultisigSignResult(await this.invokeWorker("signMultisigTxHex", Array.from(arguments))); + } + + async submitMultisigTxHex(signedMultisigTxHex) { + return this.invokeWorker("submitMultisigTxHex", Array.from(arguments)); + } + + async getData() { + return this.invokeWorker("getData"); + } + + async moveTo(path) { + return MoneroWalletFull.moveTo(path, this); + } + + async changePassword(oldPassword, newPassword) { + await this.invokeWorker("changePassword", Array.from(arguments)); + if (this.path) await this.save(); // auto save + } + + async save() { + return MoneroWalletFull.save(this); + } + + async close(save) { + if (await this.isClosed()) return; + if (save) await this.save(); + while (this.wrappedListeners.length) await this.removeListener(this.wrappedListeners[0].getListener()); + await super.close(false); + } +} + +// -------------------------------- LISTENING --------------------------------- + +/** + * Receives notifications directly from wasm c++. + * + * @private + */ +class WalletWasmListener { + + protected wallet: MoneroWallet; + + constructor(wallet) { + this.wallet = wallet; + } + + async onSyncProgress(height, startHeight, endHeight, percentDone, message) { + await this.wallet.announceSyncProgress(height, startHeight, endHeight, percentDone, message); + } + + async onNewBlock(height) { + await this.wallet.announceNewBlock(height); + } + + async onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) { + await this.wallet.announceBalancesChanged(newBalanceStr, newUnlockedBalanceStr); + } + + async onOutputReceived(height, txHash, amountStr, accountIdx, subaddressIdx, version, unlockTime, isLocked) { + + // build received output + let output = new MoneroOutputWallet(); + output.setAmount(BigInt(amountStr)); + output.setAccountIndex(accountIdx); + output.setSubaddressIndex(subaddressIdx); + let tx = new MoneroTxWallet(); + tx.setHash(txHash); + tx.setVersion(version); + tx.setUnlockTime(unlockTime); + output.setTx(tx); + tx.setOutputs([output]); + tx.setIsIncoming(true); + tx.setIsLocked(isLocked); + if (height > 0) { + let block = new MoneroBlock().setHeight(height); + block.setTxs([tx as MoneroTx]); + tx.setBlock(block); + tx.setIsConfirmed(true); + tx.setInTxPool(false); + tx.setIsFailed(false); + } else { + tx.setIsConfirmed(false); + tx.setInTxPool(true); + } + + // announce output + await this.wallet.announceOutputReceived(output); + } + + async onOutputSpent(height, txHash, amountStr, accountIdxStr, subaddressIdxStr, version, unlockTime, isLocked) { + + // build spent output + let output = new MoneroOutputWallet(); + output.setAmount(BigInt(amountStr)); + if (accountIdxStr) output.setAccountIndex(parseInt(accountIdxStr)); + if (subaddressIdxStr) output.setSubaddressIndex(parseInt(subaddressIdxStr)); + let tx = new MoneroTxWallet(); + tx.setHash(txHash); + tx.setVersion(version); + tx.setUnlockTime(unlockTime); + tx.setIsLocked(isLocked); + output.setTx(tx); + tx.setInputs([output]); + if (height > 0) { + let block = new MoneroBlock().setHeight(height); + block.setTxs([tx]); + tx.setBlock(block); + tx.setIsConfirmed(true); + tx.setInTxPool(false); + tx.setIsFailed(false); + } else { + tx.setIsConfirmed(false); + tx.setInTxPool(true); + } + + // announce output + await this.wallet.announceOutputSpent(output); + } +} + +/** + * Internal listener to bridge notifications to external listeners. + * + * @private + */ +class WalletWorkerListener { + + protected id: any; + protected listener: any; + + constructor(listener) { + this.id = GenUtils.getUUID(); + this.listener = listener; + } + + getId() { + return this.id; + } + + getListener() { + return this.listener; + } + + onSyncProgress(height, startHeight, endHeight, percentDone, message) { + this.listener.onSyncProgress(height, startHeight, endHeight, percentDone, message); + } + + async onNewBlock(height) { + await this.listener.onNewBlock(height); + } + + async onBalancesChanged(newBalanceStr, newUnlockedBalanceStr) { + await this.listener.onBalancesChanged(BigInt(newBalanceStr), BigInt(newUnlockedBalanceStr)); + } + + async onOutputReceived(blockJson) { + let block = new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET); + await this.listener.onOutputReceived(block.getTxs()[0].getOutputs()[0]); + } + + async onOutputSpent(blockJson) { + let block = new MoneroBlock(blockJson, MoneroBlock.DeserializationType.TX_WALLET); + await this.listener.onOutputSpent(block.getTxs()[0].getInputs()[0]); + } +} diff --git a/src/main/ts/wallet/MoneroWalletKeys.ts b/src/main/ts/wallet/MoneroWalletKeys.ts new file mode 100644 index 000000000..d3b32f911 --- /dev/null +++ b/src/main/ts/wallet/MoneroWalletKeys.ts @@ -0,0 +1,472 @@ +import assert from "assert"; +import GenUtils from "../common/GenUtils"; +import LibraryUtils from "../common/LibraryUtils"; +import MoneroAccount from "./model/MoneroAccount"; +import MoneroError from "../common/MoneroError"; +import MoneroIntegratedAddress from "./model/MoneroIntegratedAddress"; +import MoneroNetworkType from "../daemon/model/MoneroNetworkType"; +import MoneroSubaddress from "./model/MoneroSubaddress"; +import MoneroVersion from "../daemon/model/MoneroVersion"; +import MoneroWallet from "./MoneroWallet"; +import MoneroWalletConfig from "./model/MoneroWalletConfig"; +import MoneroWalletListener from "./model/MoneroWalletListener"; + +/** + * Implements a MoneroWallet which only manages keys using WebAssembly. + */ +export class MoneroWalletKeys extends MoneroWallet { + + // instance variables + protected cppAddress: string; + protected module: any; + protected walletProxy: MoneroWalletKeysProxy; + + // --------------------------- STATIC UTILITIES ----------------------------- + + /** + *

Create a wallet using WebAssembly bindings to monero-project.

+ * + *

Example:

+ * + * + * let wallet = await MoneroWalletKeys.createWallet({
+ *    password: "abc123",
+ *    networkType: MoneroNetworkType.STAGENET,
+ *    seed: "coexist igloo pamphlet lagoon..."
+ * }); + *
+ * + * @param {MoneroWalletConfig} config - MoneroWalletConfig or equivalent config object + * @param {string|number} config.networkType - network type of the wallet to create (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) + * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given) + * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed phrase + * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys) + * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional) + * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional) + * @param {string} [config.language] - language of the wallet's seed (defaults to "English" or auto-detected) + * @return {MoneroWalletKeys} the created wallet + */ + static async createWallet(config: Partial) { + + // normalize and validate config + if (config === undefined) throw new MoneroError("Must provide config to create wallet"); + config = config instanceof MoneroWalletConfig ? config : new MoneroWalletConfig(config); + if (config.getSeed() !== undefined && (config.getPrimaryAddress() !== undefined || config.getPrivateViewKey() !== undefined || config.getPrivateSpendKey() !== undefined)) { + throw new MoneroError("Wallet may be initialized with a seed or keys but not both"); + } + if (config.getNetworkType() === undefined) throw new MoneroError("Must provide a networkType: 'mainnet', 'testnet' or 'stagenet'"); + if (config.getSaveCurrent() === true) throw new MoneroError("Cannot save current wallet when creating keys-only wallet"); + + // initialize proxied wallet if configured + if (config.getProxyToWorker() === undefined) config.setProxyToWorker(true); + if (config.getProxyToWorker()) { + let walletProxy = await MoneroWalletKeysProxy.createWallet(config);; + return new MoneroWalletKeys(undefined, walletProxy); + } + + // disallow server connection + if (config.getServer() !== undefined) throw new MoneroError("Cannot initialize keys wallet with server connection"); + + // create wallet + if (config.getSeed() !== undefined) return MoneroWalletKeys.createWalletFromSeed(config); + else if (config.getPrivateSpendKey() !== undefined || config.getPrimaryAddress() !== undefined) return MoneroWalletKeys.createWalletFromKeys(config); + else return MoneroWalletKeys.createWalletRandom(config); + } + + protected static async createWalletRandom(config: Partial) { + + // validate and sanitize params + config = config.copy(); + if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating random wallet"); + if (config.getRestoreHeight() !== undefined) throw new MoneroError("Cannot provide restoreHeight when creating random wallet"); + MoneroNetworkType.validate(config.getNetworkType()); + if (config.getLanguage() === undefined) config.setLanguage("English"); + + // load wasm module + let module = await LibraryUtils.loadWasmModule(); + + // queue call to wasm module + return module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // create wallet in wasm which invokes callback when done + module.create_keys_wallet_random(JSON.stringify(config.toJson()), (cppAddress) => { + if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); + else resolve(new MoneroWalletKeys(cppAddress)); + }); + }); + }); + } + + protected static async createWalletFromSeed(config: Partial) { + + // validate and sanitize params + MoneroNetworkType.validate(config.getNetworkType()); + if (config.getSeed() === undefined) throw Error("Must define seed to create wallet from"); + if (config.getSeedOffset() === undefined) config.setSeedOffset(""); + if (config.getLanguage() !== undefined) throw new MoneroError("Cannot provide language when creating wallet from seed"); + + // load wasm module + let module = await LibraryUtils.loadWasmModule(); + + // queue call to wasm module + return module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // create wallet in wasm which invokes callback when done + module.create_keys_wallet_from_seed(JSON.stringify(config.toJson()), (cppAddress) => { + if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); + else resolve(new MoneroWalletKeys(cppAddress)); + }); + }); + }); + } + + protected static async createWalletFromKeys(config: Partial) { + + // validate and sanitize params + if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating wallet from keys"); + MoneroNetworkType.validate(config.getNetworkType()); + if (config.getPrimaryAddress() === undefined) config.setPrimaryAddress(""); + if (config.getPrivateViewKey() === undefined) config.setPrivateViewKey(""); + if (config.getPrivateSpendKey() === undefined) config.setPrivateSpendKey(""); + if (config.getLanguage() === undefined) config.setLanguage("English"); + + // load wasm module + let module = await LibraryUtils.loadWasmModule(); + + // queue call to wasm module + return module.queueTask(async () => { + return new Promise((resolve, reject) => { + + // create wallet in wasm which invokes callback when done + module.create_keys_wallet_from_keys(JSON.stringify(config.toJson()), (cppAddress) => { + if (typeof cppAddress === "string") reject(new MoneroError(cppAddress)); + else resolve(new MoneroWalletKeys(cppAddress)); + }); + }); + }); + } + + static async getSeedLanguages(): Promise { + let module = await LibraryUtils.loadWasmModule(); + return module.queueTask(async () => { + return JSON.parse(module.get_keys_wallet_seed_languages()).languages; + }); + } + + // --------------------------- INSTANCE METHODS ----------------------------- + + /** + * Internal constructor which is given the memory address of a C++ wallet + * instance. + * + * This method should not be called externally but should be called through + * static wallet creation utilities in this class. + * + * @param {number} cppAddress - address of the wallet instance in C++ + * @param {MoneroWalletKeysProxy} walletProxy - proxy + * + * @private + */ + constructor(cppAddress, walletProxy?: MoneroWalletKeysProxy) { + super(); + if (!cppAddress && !walletProxy) throw new MoneroError("Must provide cppAddress or walletProxy"); + if (walletProxy) this.walletProxy = walletProxy; + else { + this.cppAddress = cppAddress; + this.module = LibraryUtils.getWasmModule(); + if (!this.module.create_full_wallet) throw new MoneroError("WASM module not loaded - create wallet instance using static utilities"); // static utilites pre-load wasm module + } + } + + async isViewOnly(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().isViewOnly(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.is_view_only(this.cppAddress); + }); + } + + async isConnectedToDaemon(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().isConnectedToDaemon(); + return false; + } + + async getVersion(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getVersion(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let versionStr = this.module.get_version(this.cppAddress); + let versionJson = JSON.parse(versionStr); + return new MoneroVersion(versionJson.number, versionJson.isRelease); + }); + } + + /** + * @ignore + */ + getPath(): Promise { + throw new MoneroError("MoneroWalletKeys does not support a persisted path"); + } + + async getSeed(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getSeed(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_seed(this.cppAddress); + const errorStr = "error: "; + if (resp.indexOf(errorStr) === 0) throw new MoneroError(resp.substring(errorStr.length)); + return resp ? resp : undefined; + }); + } + + async getSeedLanguage(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getSeedLanguage(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_seed_language(this.cppAddress); + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) throw new MoneroError(resp.substring(errorKey.length)); + return resp ? resp : undefined; + }); + } + + async getPrivateSpendKey(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getPrivateSpendKey(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_private_spend_key(this.cppAddress); + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) throw new MoneroError(resp.substring(errorKey.length)); + return resp ? resp : undefined; + }); + } + + async getPrivateViewKey(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getPrivateViewKey(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_private_view_key(this.cppAddress); + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) throw new MoneroError(resp.substring(errorKey.length)); + return resp ? resp : undefined; + }); + } + + async getPublicViewKey(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getPublicViewKey(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_public_view_key(this.cppAddress); + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) throw new MoneroError(resp.substring(errorKey.length)); + return resp ? resp : undefined; + }); + } + + async getPublicSpendKey(): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getPublicSpendKey(); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_public_spend_key(this.cppAddress); + let errorKey = "error: "; + if (resp.indexOf(errorKey) === 0) throw new MoneroError(resp.substring(errorKey.length)); + return resp ? resp : undefined; + }); + } + + async getAddress(accountIdx: number, subaddressIdx: number): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getAddress(accountIdx, subaddressIdx); + assert(typeof accountIdx === "number"); + return this.module.queueTask(async () => { + this.assertNotClosed(); + return this.module.get_address(this.cppAddress, accountIdx, subaddressIdx); + }); + } + + async getAddressIndex(address: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getAddressIndex(address); + return this.module.queueTask(async () => { + this.assertNotClosed(); + let resp = this.module.get_address_index(this.cppAddress, address); + if (resp.charAt(0) !== '{') throw new MoneroError(resp); + return new MoneroSubaddress(JSON.parse(resp)); + }); + } + + async getAccounts(includeSubaddresses?: boolean, tag?: string): Promise { + if (this.getWalletProxy()) return this.getWalletProxy().getAccounts(); + throw new MoneroError("MoneroWalletKeys does not support getting an enumerable set of accounts; query specific accounts"); + } + + // getIntegratedAddress(paymentId) // TODO + // decodeIntegratedAddress + + async close(save = false): Promise { + if (this._isClosed) return; // no effect if closed + if (this.getWalletProxy()) { + await this.getWalletProxy().close(save); + await super.close(); + this._isClosed = true; + return; + } + + // save wallet if requested + if (save) await this.save(); + + // close super + await super.close(); + this._isClosed = true; + + // queue task to use wasm module + return this.module.queueTask(async () => { + return new Promise((resolve, reject) => { + if (this._isClosed) { + resolve(undefined); + return; + } + + // close wallet in wasm and invoke callback when done + this.module.close(this.cppAddress, false, async () => { // saving handled external to webassembly + delete this.cppAddress; + this._isClosed = true; + resolve(); + }); + }); + }); + } + + async isClosed(): Promise { + return this._isClosed; + } + + // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS -------------- + + async getPrimaryAddress(): Promise { return super.getPrimaryAddress(); } + async getSubaddress(accountIdx: number, subaddressIdx: number): Promise { return super.getSubaddress(accountIdx, subaddressIdx); } + + // ----------------------------- PRIVATE HELPERS ---------------------------- + + static sanitizeSubaddress(subaddress) { + if (subaddress.getLabel() === "") subaddress.setLabel(undefined); + return subaddress + } + + protected assertNotClosed() { + if (this._isClosed) throw new MoneroError("Wallet is closed"); + } + + protected getWalletProxy(): MoneroWalletKeysProxy { + this.assertNotClosed(); + return this.walletProxy; + } +} + +/** + * Implements a MoneroWallet by proxying requests to a worker which runs a keys-only wallet. + * + * TODO: sort these methods according to master sort in MoneroWallet.ts + * TODO: probably only allow one listener to worker then propogate to registered listeners for performance + * + * @private + */ +export class MoneroWalletKeysProxy extends MoneroWallet { + + // state variables + protected walletId: string; + protected worker: Worker; + + // -------------------------- WALLET STATIC UTILS --------------------------- + + static async createWallet(config) { + let walletId = GenUtils.getUUID(); + await LibraryUtils.invokeWorker(walletId, "createWalletKeys", [config.toJson()]); + return new MoneroWalletKeysProxy(walletId, await LibraryUtils.getWorker()); + } + + // --------------------------- INSTANCE METHODS ---------------------------- + + /** + * Internal constructor which is given a worker to communicate with via messages. + * + * This method should not be called externally but should be called through + * static wallet creation utilities in this class. + * + * @param {string} walletId - identifies the wallet with the worker + * @param {Worker} worker - worker to communicate with via messages + * + * @protected + */ + constructor(walletId, worker) { + super(); + this.walletId = walletId; + this.worker = worker; + } + + async isViewOnly(): Promise { + return this.invokeWorker("isViewOnly"); + } + + async getVersion(): Promise { + throw new MoneroError("Not implemented"); + } + + async getSeed() { + return this.invokeWorker("getSeed") as Promise; + } + + async getSeedLanguage() { + return this.invokeWorker("getSeedLanguage") as Promise; + } + + async getSeedLanguages() { + return this.invokeWorker("getSeedLanguages"); + } + + async getPrivateSpendKey() { + return this.invokeWorker("getPrivateSpendKey") as Promise; + } + + async getPrivateViewKey() { + return this.invokeWorker("getPrivateViewKey") as Promise; + } + + async getPublicViewKey() { + return this.invokeWorker("getPublicViewKey") as Promise; + } + + async getPublicSpendKey() { + return this.invokeWorker("getPublicSpendKey") as Promise; + } + + async getAddress(accountIdx, subaddressIdx) { + return this.invokeWorker("getAddress", Array.from(arguments)) as Promise; + } + + async getAddressIndex(address) { + let subaddressJson = await this.invokeWorker("getAddressIndex", Array.from(arguments)); + return MoneroWalletKeys.sanitizeSubaddress(new MoneroSubaddress(subaddressJson)); + } + + async getIntegratedAddress(standardAddress, paymentId) { + return new MoneroIntegratedAddress(await this.invokeWorker("getIntegratedAddress", Array.from(arguments))); + } + + async decodeIntegratedAddress(integratedAddress) { + return new MoneroIntegratedAddress(await this.invokeWorker("decodeIntegratedAddress", Array.from(arguments))); + } + + async close(save) { + await this.invokeWorker("close", Array.from(arguments)); + LibraryUtils.removeWorkerObject(this.walletId); + } + + async isClosed() { + return this.invokeWorker("isClosed"); + } + + protected async invokeWorker(fnName: string, args?: any): Promise { + return await LibraryUtils.invokeWorker(this.walletId, fnName, args); + } +} diff --git a/src/main/ts/wallet/MoneroWalletRpc.ts b/src/main/ts/wallet/MoneroWalletRpc.ts new file mode 100644 index 000000000..59f86f8f6 --- /dev/null +++ b/src/main/ts/wallet/MoneroWalletRpc.ts @@ -0,0 +1,2583 @@ +import assert from "assert"; +import GenUtils from "../common/GenUtils"; +import LibraryUtils from "../common/LibraryUtils"; +import TaskLooper from "../common/TaskLooper"; +import MoneroAccount from "./model/MoneroAccount"; +import MoneroAccountTag from "./model/MoneroAccountTag"; +import MoneroAddressBookEntry from "./model/MoneroAddressBookEntry"; +import MoneroBlock from "../daemon/model/MoneroBlock"; +import MoneroBlockHeader from "../daemon/model/MoneroBlockHeader"; +import MoneroCheckReserve from "./model/MoneroCheckReserve"; +import MoneroCheckTx from "./model/MoneroCheckTx"; +import MoneroDestination from "./model/MoneroDestination"; +import MoneroError from "../common/MoneroError"; +import MoneroIncomingTransfer from "./model/MoneroIncomingTransfer"; +import MoneroIntegratedAddress from "./model/MoneroIntegratedAddress"; +import MoneroKeyImage from "../daemon/model/MoneroKeyImage"; +import MoneroKeyImageImportResult from "./model/MoneroKeyImageImportResult"; +import MoneroMultisigInfo from "./model/MoneroMultisigInfo"; +import MoneroMultisigInitResult from "./model/MoneroMultisigInitResult"; +import MoneroMultisigSignResult from "./model/MoneroMultisigSignResult"; +import MoneroOutgoingTransfer from "./model/MoneroOutgoingTransfer"; +import MoneroOutputQuery from "./model/MoneroOutputQuery"; +import MoneroOutputWallet from "./model/MoneroOutputWallet"; +import MoneroRpcConnection from "../common/MoneroRpcConnection"; +import MoneroRpcError from "../common/MoneroRpcError"; +import MoneroSubaddress from "./model/MoneroSubaddress"; +import MoneroSyncResult from "./model/MoneroSyncResult"; +import MoneroTransfer from "./model/MoneroTransfer"; +import MoneroTransferQuery from "./model/MoneroTransferQuery"; +import MoneroTx from "../daemon/model/MoneroTx"; +import MoneroTxConfig from "./model/MoneroTxConfig"; +import MoneroTxPriority from "./model/MoneroTxPriority"; +import MoneroTxQuery from "./model/MoneroTxQuery"; +import MoneroTxSet from "./model/MoneroTxSet"; +import MoneroTxWallet from "./model/MoneroTxWallet"; +import MoneroUtils from "../common/MoneroUtils"; +import MoneroVersion from "../daemon/model/MoneroVersion"; +import MoneroWallet from "./MoneroWallet"; +import MoneroWalletConfig from "./model/MoneroWalletConfig"; +import MoneroWalletListener from "./model/MoneroWalletListener"; +import MoneroMessageSignatureType from "./model/MoneroMessageSignatureType"; +import MoneroMessageSignatureResult from "./model/MoneroMessageSignatureResult"; +import ThreadPool from "../common/ThreadPool"; +import SslOptions from "../common/SslOptions"; +import { ChildProcess } from "child_process"; + +/** + * Copyright (c) woodser + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * Implements a MoneroWallet as a client of monero-wallet-rpc. + * + * @implements {MoneroWallet} + */ +export default class MoneroWalletRpc extends MoneroWallet { + + // static variables + protected static readonly DEFAULT_SYNC_PERIOD_IN_MS = 20000; // default period between syncs in ms (defined by DEFAULT_AUTO_REFRESH_PERIOD in wallet_rpc_server.cpp) + + // instance variables + protected config: Partial; + protected addressCache: any; + protected syncPeriodInMs: number; + protected listeners: MoneroWalletListener[]; + protected process: any; + protected path: string; + protected daemonConnection: MoneroRpcConnection; + protected walletPoller: WalletPoller; + + /** @private */ + constructor(config: MoneroWalletConfig) { + super(); + this.config = config; + this.addressCache = {}; // avoid unecessary requests for addresses + this.syncPeriodInMs = MoneroWalletRpc.DEFAULT_SYNC_PERIOD_IN_MS; + } + + // --------------------------- RPC WALLET METHODS --------------------------- + + /** + * Get the internal process running monero-wallet-rpc. + * + * @return {ChildProcess} the process running monero-wallet-rpc, undefined if not created from new process + */ + getProcess(): ChildProcess { + return this.process; + } + + /** + * Stop the internal process running monero-wallet-rpc, if applicable. + * + * @param {boolean} force specifies if the process should be destroyed forcibly (default false) + * @return {Promise} the exit code from stopping the process + */ + async stopProcess(force = false): Promise { + if (this.process === undefined) throw new MoneroError("MoneroWalletRpc instance not created from new process"); + let listenersCopy = GenUtils.copyArray(this.getListeners()); + for (let listener of listenersCopy) await this.removeListener(listener); + return GenUtils.killProcess(this.process, force ? "SIGKILL" : undefined); + } + + /** + * Get the wallet's RPC connection. + * + * @return {MoneroRpcConnection | undefined} the wallet's rpc connection + */ + getRpcConnection(): MoneroRpcConnection | undefined { + return this.config.getServer(); + } + + /** + *

Open an existing wallet on the monero-wallet-rpc server.

+ * + *

Example:

+ * + * + * let wallet = new MoneroWalletRpc("http://localhost:38084", "rpc_user", "abc123");
+ * await wallet.openWallet("mywallet1", "supersecretpassword");
+ *
+ * await wallet.openWallet({
+ *    path: "mywallet2",
+ *    password: "supersecretpassword",
+ *    server: "http://locahost:38081", // or object with uri, username, password, etc
+ *    rejectUnauthorized: false
+ * });
+ *
+ * + * @param {string|MoneroWalletConfig} pathOrConfig - the wallet's name or configuration to open + * @param {string} pathOrConfig.path - path of the wallet to create (optional, in-memory wallet if not given) + * @param {string} pathOrConfig.password - password of the wallet to create + * @param {string|Partial} pathOrConfig.server - uri or MoneroRpcConnection of a daemon to use (optional, monero-wallet-rpc usually started with daemon config) + * @param {string} [password] the wallet's password + * @return {Promise} this wallet client + */ + async openWallet(pathOrConfig: string | Partial, password?: string): Promise { + + // normalize and validate config + let config = new MoneroWalletConfig(typeof pathOrConfig === "string" ? {path: pathOrConfig, password: password ? password : ""} : pathOrConfig); + // TODO: ensure other fields uninitialized? + + // open wallet on rpc server + if (!config.getPath()) throw new MoneroError("Must provide name of wallet to open"); + await this.config.getServer().sendJsonRequest("open_wallet", {filename: config.getPath(), password: config.getPassword()}); + await this.clear(); + this.path = config.getPath(); + + // set connection manager or server + if (config.getConnectionManager() != null) { + if (config.getServer()) throw new MoneroError("Wallet can be opened with a server or connection manager but not both"); + await this.setConnectionManager(config.getConnectionManager()); + } else if (config.getServer() != null) { + await this.setDaemonConnection(config.getServer()); + } + + return this; + } + + /** + *

Create and open a wallet on the monero-wallet-rpc server.

+ * + *

Example:

+ * + * + * // construct client to monero-wallet-rpc
+ * let walletRpc = new MoneroWalletRpc("http://localhost:38084", "rpc_user", "abc123");

+ * + * // create and open wallet on monero-wallet-rpc
+ * await walletRpc.createWallet({
+ *    path: "mywallet",
+ *    password: "abc123",
+ *    seed: "coexist igloo pamphlet lagoon...",
+ *    restoreHeight: 1543218l
+ * }); + *
+ * + * @param {Partial} config - MoneroWalletConfig or equivalent JS object + * @param {string} [config.path] - path of the wallet to create (optional, in-memory wallet if not given) + * @param {string} [config.password] - password of the wallet to create + * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given) + * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed + * @param {boolean} [config.isMultisig] - restore multisig wallet from seed + * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys) + * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional) + * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional) + * @param {number} [config.restoreHeight] - block height to start scanning from (defaults to 0 unless generating random wallet) + * @param {string} [config.language] - language of the wallet's mnemonic phrase or seed (defaults to "English" or auto-detected) + * @param {MoneroRpcConnection} [config.server] - MoneroRpcConnection to a monero daemon (optional)
+ * @param {string} [config.serverUri] - uri of a daemon to use (optional, monero-wallet-rpc usually started with daemon config) + * @param {string} [config.serverUsername] - username to authenticate with the daemon (optional) + * @param {string} [config.serverPassword] - password to authenticate with the daemon (optional) + * @param {MoneroConnectionManager} [config.connectionManager] - manage connections to monerod (optional) + * @param {boolean} [config.rejectUnauthorized] - reject self-signed server certificates if true (defaults to true) + * @param {MoneroRpcConnection} [config.server] - MoneroRpcConnection or equivalent JS object providing daemon configuration (optional) + * @param {boolean} [config.saveCurrent] - specifies if the current RPC wallet should be saved before being closed (default true) + * @return {MoneroWalletRpc} this wallet client + */ + async createWallet(config: Partial): Promise { + + // normalize and validate config + if (config === undefined) throw new MoneroError("Must provide config to create wallet"); + const configNormalized = new MoneroWalletConfig(config); + if (configNormalized.getSeed() !== undefined && (configNormalized.getPrimaryAddress() !== undefined || configNormalized.getPrivateViewKey() !== undefined || configNormalized.getPrivateSpendKey() !== undefined)) { + throw new MoneroError("Wallet can be initialized with a seed or keys but not both"); + } + if (configNormalized.getNetworkType() !== undefined) throw new MoneroError("Cannot provide networkType when creating RPC wallet because server's network type is already set"); + if (configNormalized.getAccountLookahead() !== undefined || configNormalized.getSubaddressLookahead() !== undefined) throw new MoneroError("monero-wallet-rpc does not support creating wallets with subaddress lookahead over rpc"); + if (configNormalized.getPassword() === undefined) configNormalized.setPassword(""); + + // set server from connection manager if provided + if (configNormalized.getConnectionManager()) { + if (configNormalized.getServer()) throw new MoneroError("Wallet can be created with a server or connection manager but not both"); + configNormalized.setServer(config.getConnectionManager().getConnection()); + } + + // create wallet + if (configNormalized.getSeed() !== undefined) await this.createWalletFromSeed(configNormalized); + else if (configNormalized.getPrivateSpendKey() !== undefined || configNormalized.getPrimaryAddress() !== undefined) await this.createWalletFromKeys(configNormalized); + else await this.createWalletRandom(configNormalized); + + // set connection manager or server + if (configNormalized.getConnectionManager()) { + await this.setConnectionManager(configNormalized.getConnectionManager()); + } else if (configNormalized.getServer()) { + await this.setDaemonConnection(configNormalized.getServer()); + } + + return this; + } + + protected async createWalletRandom(config: MoneroWalletConfig) { + if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating random wallet"); + if (config.getRestoreHeight() !== undefined) throw new MoneroError("Cannot provide restoreHeight when creating random wallet"); + if (config.getSaveCurrent() === false) throw new MoneroError("Current wallet is saved automatically when creating random wallet"); + if (!config.getPath()) throw new MoneroError("Name is not initialized"); + if (!config.getLanguage()) config.setLanguage(MoneroWallet.DEFAULT_LANGUAGE); + let params = { filename: config.getPath(), password: config.getPassword(), language: config.getLanguage() }; + try { + await this.config.getServer().sendJsonRequest("create_wallet", params); + } catch (err: any) { + this.handleCreateWalletError(config.getPath(), err); + } + await this.clear(); + this.path = config.getPath(); + return this; + } + + protected async createWalletFromSeed(config: MoneroWalletConfig) { + try { + await this.config.getServer().sendJsonRequest("restore_deterministic_wallet", { + filename: config.getPath(), + password: config.getPassword(), + seed: config.getSeed(), + seed_offset: config.getSeedOffset(), + enable_multisig_experimental: config.getIsMultisig(), + restore_height: config.getRestoreHeight(), + language: config.getLanguage(), + autosave_current: config.getSaveCurrent() + }); + } catch (err: any) { + this.handleCreateWalletError(config.getPath(), err); + } + await this.clear(); + this.path = config.getPath(); + return this; + } + + protected async createWalletFromKeys(config: MoneroWalletConfig) { + if (config.getSeedOffset() !== undefined) throw new MoneroError("Cannot provide seedOffset when creating wallet from keys"); + if (config.getRestoreHeight() === undefined) config.setRestoreHeight(0); + if (config.getLanguage() === undefined) config.setLanguage(MoneroWallet.DEFAULT_LANGUAGE); + try { + await this.config.getServer().sendJsonRequest("generate_from_keys", { + filename: config.getPath(), + password: config.getPassword(), + address: config.getPrimaryAddress(), + viewkey: config.getPrivateViewKey(), + spendkey: config.getPrivateSpendKey(), + restore_height: config.getRestoreHeight(), + autosave_current: config.getSaveCurrent() + }); + } catch (err: any) { + this.handleCreateWalletError(config.getPath(), err); + } + await this.clear(); + this.path = config.getPath(); + return this; + } + + protected handleCreateWalletError(name, err) { + if (err.message) { + if (err.message.toLowerCase().includes("already exists")) throw new MoneroRpcError("Wallet already exists: " + name, err.getCode(), err.getRpcMethod(), err.getRpcParams()); + if (err.message.toLowerCase().includes("word list failed verification")) throw new MoneroRpcError("Invalid mnemonic", err.getCode(), err.getRpcMethod(), err.getRpcParams()); + } + throw err; + } + + async isViewOnly(): Promise { + try { + await this.config.getServer().sendJsonRequest("query_key", {key_type: "mnemonic"}); + return false; // key retrieval succeeds if not view only + } catch (e: any) { + if (e.getCode() === -29) return true; // wallet is view only + if (e.getCode() === -1) return false; // wallet is offline but not view only + throw e; + } + } + + /** + * Set the wallet's daemon connection. + * + * @param {string|MoneroRpcConnection} [uriOrConnection] - the daemon's URI or connection (defaults to offline) + * @param {boolean} isTrusted - indicates if the daemon in trusted + * @param {SslOptions} sslOptions - custom SSL configuration + */ + async setDaemonConnection(uriOrConnection?: MoneroRpcConnection | string, isTrusted?: boolean, sslOptions?: SslOptions): Promise { + let connection = !uriOrConnection ? undefined : uriOrConnection instanceof MoneroRpcConnection ? uriOrConnection : new MoneroRpcConnection(uriOrConnection); + if (!sslOptions) sslOptions = new SslOptions(); + let params: any = {}; + params.address = connection ? connection.getUri() : "bad_uri"; // TODO monero-wallet-rpc: bad daemon uri necessary for offline? + params.username = connection ? connection.getUsername() : ""; + params.password = connection ? connection.getPassword() : ""; + params.trusted = isTrusted; + params.ssl_support = "autodetect"; + params.ssl_private_key_path = sslOptions.getPrivateKeyPath(); + params.ssl_certificate_path = sslOptions.getCertificatePath(); + params.ssl_ca_file = sslOptions.getCertificateAuthorityFile(); + params.ssl_allowed_fingerprints = sslOptions.getAllowedFingerprints(); + params.ssl_allow_any_cert = sslOptions.getAllowAnyCert(); + params.proxy = connection ? connection.getProxyUri() : ""; + await this.config.getServer().sendJsonRequest("set_daemon", params); + this.daemonConnection = connection; + } + + async getDaemonConnection(): Promise { + return this.daemonConnection; + } + + /** + * Get the total and unlocked balances in a single request. + * + * @param {number} [accountIdx] account index + * @param {number} [subaddressIdx] subaddress index + * @return {Promise} is the total and unlocked balances in an array, respectively + */ + async getBalances(accountIdx?: number, subaddressIdx?: number): Promise { + if (accountIdx === undefined) { + assert.equal(subaddressIdx, undefined, "Must provide account index with subaddress index"); + let balance = BigInt(0); + let unlockedBalance = BigInt(0); + for (let account of await this.getAccounts()) { + balance = balance + account.getBalance(); + unlockedBalance = unlockedBalance + account.getUnlockedBalance(); + } + return [balance, unlockedBalance]; + } else { + let params = {account_index: accountIdx, address_indices: subaddressIdx === undefined ? undefined : [subaddressIdx]}; + let resp = await this.config.getServer().sendJsonRequest("get_balance", params); + if (subaddressIdx === undefined) return [BigInt(resp.result.balance), BigInt(resp.result.unlocked_balance)]; + else return [BigInt(resp.result.per_subaddress[0].balance), BigInt(resp.result.per_subaddress[0].unlocked_balance)]; + } + } + + // -------------------------- COMMON WALLET METHODS ------------------------- + + async addListener(listener: MoneroWalletListener): Promise { + await super.addListener(listener); + this.refreshListening(); + } + + async removeListener(listener): Promise { + await super.removeListener(listener); + this.refreshListening(); + } + + async isConnectedToDaemon(): Promise { + try { + await this.checkReserveProof(await this.getPrimaryAddress(), "", ""); // TODO (monero-project): provide better way to know if wallet rpc is connected to daemon + throw new MoneroError("check reserve expected to fail"); + } catch (e: any) { + return e.message.indexOf("Failed to connect to daemon") < 0; + } + } + + async getVersion(): Promise { + let resp = await this.config.getServer().sendJsonRequest("get_version"); + return new MoneroVersion(resp.result.version, resp.result.release); + } + + async getPath(): Promise { + return this.path; + } + + async getSeed(): Promise { + let resp = await this.config.getServer().sendJsonRequest("query_key", { key_type: "mnemonic" }); + return resp.result.key; + } + + async getSeedLanguage(): Promise { + if (await this.getSeed() === undefined) return undefined; + throw new MoneroError("MoneroWalletRpc.getSeedLanguage() not supported"); + } + + /** + * Get a list of available languages for the wallet's seed. + * + * @return {string[]} the available languages for the wallet's seed. + */ + async getSeedLanguages() { + return (await this.config.getServer().sendJsonRequest("get_languages")).result.languages; + } + + async getPrivateViewKey(): Promise { + let resp = await this.config.getServer().sendJsonRequest("query_key", { key_type: "view_key" }); + return resp.result.key; + } + + async getPrivateSpendKey(): Promise { + let resp = await this.config.getServer().sendJsonRequest("query_key", { key_type: "spend_key" }); + return resp.result.key; + } + + async getAddress(accountIdx: number, subaddressIdx: number): Promise { + let subaddressMap = this.addressCache[accountIdx]; + if (!subaddressMap) { + await this.getSubaddresses(accountIdx, undefined, true); // cache's all addresses at this account + return this.getAddress(accountIdx, subaddressIdx); // recursive call uses cache + } + let address = subaddressMap[subaddressIdx]; + if (!address) { + await this.getSubaddresses(accountIdx, undefined, true); // cache's all addresses at this account + return this.addressCache[accountIdx][subaddressIdx]; + } + return address; + } + + // TODO: use cache + async getAddressIndex(address: string): Promise { + + // fetch result and normalize error if address does not belong to the wallet + let resp; + try { + resp = await this.config.getServer().sendJsonRequest("get_address_index", {address: address}); + } catch (e: any) { + if (e.getCode() === -2) throw new MoneroError(e.message); + throw e; + } + + // convert rpc response + let subaddress = new MoneroSubaddress({address: address}); + subaddress.setAccountIndex(resp.result.index.major); + subaddress.setIndex(resp.result.index.minor); + return subaddress; + } + + async getIntegratedAddress(standardAddress?: string, paymentId?: string): Promise { + try { + let integratedAddressStr = (await this.config.getServer().sendJsonRequest("make_integrated_address", {standard_address: standardAddress, payment_id: paymentId})).result.integrated_address; + return await this.decodeIntegratedAddress(integratedAddressStr); + } catch (e: any) { + if (e.message.includes("Invalid payment ID")) throw new MoneroError("Invalid payment ID: " + paymentId); + throw e; + } + } + + async decodeIntegratedAddress(integratedAddress: string): Promise { + let resp = await this.config.getServer().sendJsonRequest("split_integrated_address", {integrated_address: integratedAddress}); + return new MoneroIntegratedAddress().setStandardAddress(resp.result.standard_address).setPaymentId(resp.result.payment_id).setIntegratedAddress(integratedAddress); + } + + async getHeight(): Promise { + return (await this.config.getServer().sendJsonRequest("get_height")).result.height; + } + + async getDaemonHeight(): Promise { + throw new MoneroError("monero-wallet-rpc does not support getting the chain height"); + } + + async getHeightByDate(year: number, month: number, day: number): Promise { + throw new MoneroError("monero-wallet-rpc does not support getting a height by date"); + } + + async sync(listenerOrStartHeight?: MoneroWalletListener | number, startHeight?: number): Promise { + assert(!(listenerOrStartHeight instanceof MoneroWalletListener), "Monero Wallet RPC does not support reporting sync progress"); + try { + let resp = await this.config.getServer().sendJsonRequest("refresh", {start_height: startHeight}); + await this.poll(); + return new MoneroSyncResult(resp.result.blocks_fetched, resp.result.received_money); + } catch (err: any) { + if (err.message === "no connection to daemon") throw new MoneroError("Wallet is not connected to daemon"); + throw err; + } + } + + async startSyncing(syncPeriodInMs?: number): Promise { + + // convert ms to seconds for rpc parameter + let syncPeriodInSeconds = Math.round((syncPeriodInMs === undefined ? MoneroWalletRpc.DEFAULT_SYNC_PERIOD_IN_MS : syncPeriodInMs) / 1000); + + // send rpc request + await this.config.getServer().sendJsonRequest("auto_refresh", { + enable: true, + period: syncPeriodInSeconds + }); + + // update sync period for poller + this.syncPeriodInMs = syncPeriodInSeconds * 1000; + if (this.walletPoller !== undefined) this.walletPoller.setPeriodInMs(this.syncPeriodInMs); + + // poll if listening + await this.poll(); + } + + getSyncPeriodInMs(): number { + return this.syncPeriodInMs; + } + + async stopSyncing(): Promise { + return this.config.getServer().sendJsonRequest("auto_refresh", { enable: false }); + } + + async scanTxs(txHashes: string[]): Promise { + if (!txHashes || !txHashes.length) throw new MoneroError("No tx hashes given to scan"); + await this.config.getServer().sendJsonRequest("scan_tx", {txids: txHashes}); + await this.poll(); + } + + async rescanSpent(): Promise { + await this.config.getServer().sendJsonRequest("rescan_spent", undefined); + } + + async rescanBlockchain(): Promise { + await this.config.getServer().sendJsonRequest("rescan_blockchain", undefined); + } + + async getBalance(accountIdx?: number, subaddressIdx?: number): Promise { + return (await this.getBalances(accountIdx, subaddressIdx))[0]; + } + + async getUnlockedBalance(accountIdx?: number, subaddressIdx?: number): Promise { + return (await this.getBalances(accountIdx, subaddressIdx))[1]; + } + + async getAccounts(includeSubaddresses?: boolean, tag?: string, skipBalances?: boolean): Promise { + + // fetch accounts from rpc + let resp = await this.config.getServer().sendJsonRequest("get_accounts", {tag: tag}); + + // build account objects and fetch subaddresses per account using get_address + // TODO monero-wallet-rpc: get_address should support all_accounts so not called once per account + let accounts: MoneroAccount[] = []; + for (let rpcAccount of resp.result.subaddress_accounts) { + let account = MoneroWalletRpc.convertRpcAccount(rpcAccount); + if (includeSubaddresses) account.setSubaddresses(await this.getSubaddresses(account.getIndex(), undefined, true)); + accounts.push(account); + } + + // fetch and merge fields from get_balance across all accounts + if (includeSubaddresses && !skipBalances) { + + // these fields are not initialized if subaddress is unused and therefore not returned from `get_balance` + for (let account of accounts) { + for (let subaddress of account.getSubaddresses()) { + subaddress.setBalance(BigInt(0)); + subaddress.setUnlockedBalance(BigInt(0)); + subaddress.setNumUnspentOutputs(0); + subaddress.setNumBlocksToUnlock(0); + } + } + + // fetch and merge info from get_balance + resp = await this.config.getServer().sendJsonRequest("get_balance", {all_accounts: true}); + if (resp.result.per_subaddress) { + for (let rpcSubaddress of resp.result.per_subaddress) { + let subaddress = MoneroWalletRpc.convertRpcSubaddress(rpcSubaddress); + + // merge info + let account = accounts[subaddress.getAccountIndex()]; + assert.equal(subaddress.getAccountIndex(), account.getIndex(), "RPC accounts are out of order"); // would need to switch lookup to loop + let tgtSubaddress = account.getSubaddresses()[subaddress.getIndex()]; + assert.equal(subaddress.getIndex(), tgtSubaddress.getIndex(), "RPC subaddresses are out of order"); + if (subaddress.getBalance() !== undefined) tgtSubaddress.setBalance(subaddress.getBalance()); + if (subaddress.getUnlockedBalance() !== undefined) tgtSubaddress.setUnlockedBalance(subaddress.getUnlockedBalance()); + if (subaddress.getNumUnspentOutputs() !== undefined) tgtSubaddress.setNumUnspentOutputs(subaddress.getNumUnspentOutputs()); + } + } + } + + return accounts; + } + + // TODO: getAccountByIndex(), getAccountByTag() + async getAccount(accountIdx: number, includeSubaddresses?: boolean, skipBalances?: boolean): Promise { + assert(accountIdx >= 0); + for (let account of await this.getAccounts()) { + if (account.getIndex() === accountIdx) { + if (includeSubaddresses) account.setSubaddresses(await this.getSubaddresses(accountIdx, undefined, skipBalances)); + return account; + } + } + throw new Error("Account with index " + accountIdx + " does not exist"); + } + + async createAccount(label?: string): Promise { + label = label ? label : undefined; + let resp = await this.config.getServer().sendJsonRequest("create_account", {label: label}); + return new MoneroAccount({ + index: resp.result.account_index, + primaryAddress: resp.result.address, + label: label, + balance: BigInt(0), + unlockedBalance: BigInt(0) + }); + } + + async getSubaddresses(accountIdx: number, subaddressIndices?: number[], skipBalances?: boolean): Promise { + + // fetch subaddresses + let params: any = {}; + params.account_index = accountIdx; + if (subaddressIndices) params.address_index = GenUtils.listify(subaddressIndices); + let resp = await this.config.getServer().sendJsonRequest("get_address", params); + + // initialize subaddresses + let subaddresses = []; + for (let rpcSubaddress of resp.result.addresses) { + let subaddress = MoneroWalletRpc.convertRpcSubaddress(rpcSubaddress); + subaddress.setAccountIndex(accountIdx); + subaddresses.push(subaddress); + } + + // fetch and initialize subaddress balances + if (!skipBalances) { + + // these fields are not initialized if subaddress is unused and therefore not returned from `get_balance` + for (let subaddress of subaddresses) { + subaddress.setBalance(BigInt(0)); + subaddress.setUnlockedBalance(BigInt(0)); + subaddress.setNumUnspentOutputs(0); + subaddress.setNumBlocksToUnlock(0); + } + + // fetch and initialize balances + resp = await this.config.getServer().sendJsonRequest("get_balance", params); + if (resp.result.per_subaddress) { + for (let rpcSubaddress of resp.result.per_subaddress) { + let subaddress = MoneroWalletRpc.convertRpcSubaddress(rpcSubaddress); + + // transfer info to existing subaddress object + for (let tgtSubaddress of subaddresses) { + if (tgtSubaddress.getIndex() !== subaddress.getIndex()) continue; // skip to subaddress with same index + if (subaddress.getBalance() !== undefined) tgtSubaddress.setBalance(subaddress.getBalance()); + if (subaddress.getUnlockedBalance() !== undefined) tgtSubaddress.setUnlockedBalance(subaddress.getUnlockedBalance()); + if (subaddress.getNumUnspentOutputs() !== undefined) tgtSubaddress.setNumUnspentOutputs(subaddress.getNumUnspentOutputs()); + if (subaddress.getNumBlocksToUnlock() !== undefined) tgtSubaddress.setNumBlocksToUnlock(subaddress.getNumBlocksToUnlock()); + } + } + } + } + + // cache addresses + let subaddressMap = this.addressCache[accountIdx]; + if (!subaddressMap) { + subaddressMap = {}; + this.addressCache[accountIdx] = subaddressMap; + } + for (let subaddress of subaddresses) { + subaddressMap[subaddress.getIndex()] = subaddress.getAddress(); + } + + // return results + return subaddresses; + } + + async getSubaddress(accountIdx: number, subaddressIdx: number, skipBalances?: boolean): Promise { + assert(accountIdx >= 0); + assert(subaddressIdx >= 0); + return (await this.getSubaddresses(accountIdx, [subaddressIdx], skipBalances))[0]; + } + + async createSubaddress(accountIdx: number, label?: string): Promise { + + // send request + let resp = await this.config.getServer().sendJsonRequest("create_address", {account_index: accountIdx, label: label}); + + // build subaddress object + let subaddress = new MoneroSubaddress(); + subaddress.setAccountIndex(accountIdx); + subaddress.setIndex(resp.result.address_index); + subaddress.setAddress(resp.result.address); + subaddress.setLabel(label ? label : undefined); + subaddress.setBalance(BigInt(0)); + subaddress.setUnlockedBalance(BigInt(0)); + subaddress.setNumUnspentOutputs(0); + subaddress.setIsUsed(false); + subaddress.setNumBlocksToUnlock(0); + return subaddress; + } + + async setSubaddressLabel(accountIdx: number, subaddressIdx: number, label: string): Promise { + await this.config.getServer().sendJsonRequest("label_address", {index: {major: accountIdx, minor: subaddressIdx}, label: label}); + } + + async getTxs(query?: string[] | Partial): Promise { + + // copy query + const queryNormalized = MoneroWallet.normalizeTxQuery(query); + + // temporarily disable transfer and output queries in order to collect all tx information + let transferQuery = queryNormalized.getTransferQuery(); + let inputQuery = queryNormalized.getInputQuery(); + let outputQuery = queryNormalized.getOutputQuery(); + queryNormalized.setTransferQuery(undefined); + queryNormalized.setInputQuery(undefined); + queryNormalized.setOutputQuery(undefined); + + // fetch all transfers that meet tx query + let transfers = await this.getTransfersAux(new MoneroTransferQuery().setTxQuery(MoneroWalletRpc.decontextualize(queryNormalized.copy()))); + + // collect unique txs from transfers while retaining order + let txs = []; + let txsSet = new Set(); + for (let transfer of transfers) { + if (!txsSet.has(transfer.getTx())) { + txs.push(transfer.getTx()); + txsSet.add(transfer.getTx()); + } + } + + // cache types into maps for merging and lookup + let txMap = {}; + let blockMap = {}; + for (let tx of txs) { + MoneroWalletRpc.mergeTx(tx, txMap, blockMap); + } + + // fetch and merge outputs if requested + if (queryNormalized.getIncludeOutputs() || outputQuery) { + + // fetch outputs + let outputQueryAux = (outputQuery ? outputQuery.copy() : new MoneroOutputQuery()).setTxQuery(MoneroWalletRpc.decontextualize(queryNormalized.copy())); + let outputs = await this.getOutputsAux(outputQueryAux); + + // merge output txs one time while retaining order + let outputTxs = []; + for (let output of outputs) { + if (!outputTxs.includes(output.getTx())) { + MoneroWalletRpc.mergeTx(output.getTx(), txMap, blockMap); + outputTxs.push(output.getTx()); + } + } + } + + // restore transfer and output queries + queryNormalized.setTransferQuery(transferQuery); + queryNormalized.setInputQuery(inputQuery); + queryNormalized.setOutputQuery(outputQuery); + + // filter txs that don't meet transfer query + let txsQueried = []; + for (let tx of txs) { + if (queryNormalized.meetsCriteria(tx)) txsQueried.push(tx); + else if (tx.getBlock() !== undefined) tx.getBlock().getTxs().splice(tx.getBlock().getTxs().indexOf(tx), 1); + } + txs = txsQueried; + + // special case: re-fetch txs if inconsistency caused by needing to make multiple rpc calls + for (let tx of txs) { + if (tx.getIsConfirmed() && tx.getBlock() === undefined || !tx.getIsConfirmed() && tx.getBlock() !== undefined) { + console.error("Inconsistency detected building txs from multiple rpc calls, re-fetching txs"); + return this.getTxs(queryNormalized); + } + } + + // order txs if tx hashes given then return + if (queryNormalized.getHashes() && queryNormalized.getHashes().length > 0) { + let txsById = new Map() // store txs in temporary map for sorting + for (let tx of txs) txsById.set(tx.getHash(), tx); + let orderedTxs = []; + for (let hash of queryNormalized.getHashes()) if (txsById.get(hash)) orderedTxs.push(txsById.get(hash)); + txs = orderedTxs; + } + return txs; + } + + async getTransfers(query?: Partial): Promise { + + // copy and normalize query up to block + const queryNormalized = MoneroWallet.normalizeTransferQuery(query); + + // get transfers directly if query does not require tx context (other transfers, outputs) + if (!MoneroWalletRpc.isContextual(queryNormalized)) return this.getTransfersAux(queryNormalized); + + // otherwise get txs with full models to fulfill query + let transfers = []; + for (let tx of await this.getTxs(queryNormalized.getTxQuery())) { + for (let transfer of tx.filterTransfers(queryNormalized)) { + transfers.push(transfer); + } + } + + return transfers; + } + + async getOutputs(query?: Partial): Promise { + + // copy and normalize query up to block + const queryNormalized = MoneroWallet.normalizeOutputQuery(query); + + // get outputs directly if query does not require tx context (other outputs, transfers) + if (!MoneroWalletRpc.isContextual(queryNormalized)) return this.getOutputsAux(queryNormalized); + + // otherwise get txs with full models to fulfill query + let outputs = []; + for (let tx of await this.getTxs(queryNormalized.getTxQuery())) { + for (let output of tx.filterOutputs(queryNormalized)) { + outputs.push(output); + } + } + + return outputs; + } + + async exportOutputs(all = false): Promise { + return (await this.config.getServer().sendJsonRequest("export_outputs", {all: all})).result.outputs_data_hex; + } + + async importOutputs(outputsHex: string): Promise { + let resp = await this.config.getServer().sendJsonRequest("import_outputs", {outputs_data_hex: outputsHex}); + return resp.result.num_imported; + } + + async exportKeyImages(all = false): Promise { + return await this.rpcExportKeyImages(all); + } + + async importKeyImages(keyImages: MoneroKeyImage[]): Promise { + + // convert key images to rpc parameter + let rpcKeyImages = keyImages.map(keyImage => ({key_image: keyImage.getHex(), signature: keyImage.getSignature()})); + + // send request + let resp = await this.config.getServer().sendJsonRequest("import_key_images", {signed_key_images: rpcKeyImages}); + + // build and return result + let importResult = new MoneroKeyImageImportResult(); + importResult.setHeight(resp.result.height); + importResult.setSpentAmount(BigInt(resp.result.spent)); + importResult.setUnspentAmount(BigInt(resp.result.unspent)); + return importResult; + } + + async getNewKeyImagesFromLastImport(): Promise { + return await this.rpcExportKeyImages(false); + } + + async freezeOutput(keyImage: string): Promise { + return this.config.getServer().sendJsonRequest("freeze", {key_image: keyImage}); + } + + async thawOutput(keyImage: string): Promise { + return this.config.getServer().sendJsonRequest("thaw", {key_image: keyImage}); + } + + async isOutputFrozen(keyImage: string): Promise { + let resp = await this.config.getServer().sendJsonRequest("frozen", {key_image: keyImage}); + return resp.result.frozen === true; + } + + async getDefaultFeePriority(): Promise { + let resp = await this.config.getServer().sendJsonRequest("get_default_fee_priority"); + return resp.result.priority; + } + + async createTxs(config: Partial): Promise { + + // validate, copy, and normalize config + const configNormalized = MoneroWallet.normalizeCreateTxsConfig(config); + if (configNormalized.getCanSplit() === undefined) configNormalized.setCanSplit(true); + if (configNormalized.getRelay() === true && await this.isMultisig()) throw new MoneroError("Cannot relay multisig transaction until co-signed"); + + // determine account and subaddresses to send from + let accountIdx = configNormalized.getAccountIndex(); + if (accountIdx === undefined) throw new MoneroError("Must provide the account index to send from"); + let subaddressIndices = configNormalized.getSubaddressIndices() === undefined ? undefined : configNormalized.getSubaddressIndices().slice(0); // fetch all or copy given indices + + // build config parameters + let params: any = {}; + params.destinations = []; + for (let destination of configNormalized.getDestinations()) { + assert(destination.getAddress(), "Destination address is not defined"); + assert(destination.getAmount(), "Destination amount is not defined"); + params.destinations.push({ address: destination.getAddress(), amount: destination.getAmount().toString() }); + } + if (configNormalized.getSubtractFeeFrom()) params.subtract_fee_from_outputs = configNormalized.getSubtractFeeFrom(); + params.account_index = accountIdx; + params.subaddr_indices = subaddressIndices; + params.payment_id = configNormalized.getPaymentId(); + params.do_not_relay = configNormalized.getRelay() !== true; + assert(configNormalized.getPriority() === undefined || configNormalized.getPriority() >= 0 && configNormalized.getPriority() <= 3); + params.priority = configNormalized.getPriority(); + params.get_tx_hex = true; + params.get_tx_metadata = true; + if (configNormalized.getCanSplit()) params.get_tx_keys = true; // param to get tx key(s) depends if split + else params.get_tx_key = true; + + // cannot apply subtractFeeFrom with `transfer_split` call + if (configNormalized.getCanSplit() && configNormalized.getSubtractFeeFrom() && configNormalized.getSubtractFeeFrom().length > 0) { + throw new MoneroError("subtractfeefrom transfers cannot be split over multiple transactions yet"); + } + + // send request + let result; + try { + let resp = await this.config.getServer().sendJsonRequest(configNormalized.getCanSplit() ? "transfer_split" : "transfer", params); + result = resp.result; + } catch (err: any) { + if (err.message.indexOf("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS") > -1) throw new MoneroError("Invalid destination address"); + throw err; + } + + // pre-initialize txs iff present. multisig and view-only wallets will have tx set without transactions + let txs; + let numTxs = configNormalized.getCanSplit() ? (result.fee_list !== undefined ? result.fee_list.length : 0) : (result.fee !== undefined ? 1 : 0); + if (numTxs > 0) txs = []; + let copyDestinations = numTxs === 1; + for (let i = 0; i < numTxs; i++) { + let tx = new MoneroTxWallet(); + MoneroWalletRpc.initSentTxWallet(configNormalized, tx, copyDestinations); + tx.getOutgoingTransfer().setAccountIndex(accountIdx); + if (subaddressIndices !== undefined && subaddressIndices.length === 1) tx.getOutgoingTransfer().setSubaddressIndices(subaddressIndices); + txs.push(tx); + } + + // notify of changes + if (configNormalized.getRelay()) await this.poll(); + + // initialize tx set from rpc response with pre-initialized txs + if (configNormalized.getCanSplit()) return MoneroWalletRpc.convertRpcSentTxsToTxSet(result, txs, configNormalized).getTxs(); + else return MoneroWalletRpc.convertRpcTxToTxSet(result, txs === undefined ? undefined : txs[0], true, configNormalized).getTxs(); + } + + async sweepOutput(config: Partial): Promise { + + // normalize and validate config + config = MoneroWallet.normalizeSweepOutputConfig(config); + + // build request parameters + let params: any = {}; + params.address = config.getDestinations()[0].getAddress(); + params.account_index = config.getAccountIndex(); + params.subaddr_indices = config.getSubaddressIndices(); + params.key_image = config.getKeyImage(); + params.do_not_relay = config.getRelay() !== true; + assert(config.getPriority() === undefined || config.getPriority() >= 0 && config.getPriority() <= 3); + params.priority = config.getPriority(); + params.payment_id = config.getPaymentId(); + params.get_tx_key = true; + params.get_tx_hex = true; + params.get_tx_metadata = true; + + // send request + let resp = await this.config.getServer().sendJsonRequest("sweep_single", params); + let result = resp.result; + + // notify of changes + if (config.getRelay()) await this.poll(); + + // build and return tx + let tx = MoneroWalletRpc.initSentTxWallet(config, undefined, true); + MoneroWalletRpc.convertRpcTxToTxSet(result, tx, true, config); + tx.getOutgoingTransfer().getDestinations()[0].setAmount(tx.getOutgoingTransfer().getAmount()); // initialize destination amount + return tx; + } + + async sweepUnlocked(config: Partial): Promise { + + // validate and normalize config + const configNormalized = MoneroWallet.normalizeSweepUnlockedConfig(config); + + // determine account and subaddress indices to sweep; default to all with unlocked balance if not specified + let indices = new Map(); // maps each account index to subaddress indices to sweep + if (configNormalized.getAccountIndex() !== undefined) { + if (configNormalized.getSubaddressIndices() !== undefined) { + indices.set(configNormalized.getAccountIndex(), configNormalized.getSubaddressIndices()); + } else { + let subaddressIndices = []; + indices.set(configNormalized.getAccountIndex(), subaddressIndices); + for (let subaddress of await this.getSubaddresses(configNormalized.getAccountIndex())) { + if (subaddress.getUnlockedBalance() > 0n) subaddressIndices.push(subaddress.getIndex()); + } + } + } else { + let accounts = await this.getAccounts(true); + for (let account of accounts) { + if (account.getUnlockedBalance() > 0n) { + let subaddressIndices = []; + indices.set(account.getIndex(), subaddressIndices); + for (let subaddress of account.getSubaddresses()) { + if (subaddress.getUnlockedBalance() > 0n) subaddressIndices.push(subaddress.getIndex()); + } + } + } + } + + // sweep from each account and collect resulting tx sets + let txs = []; + for (let accountIdx of indices.keys()) { + + // copy and modify the original config + let copy = configNormalized.copy(); + copy.setAccountIndex(accountIdx); + copy.setSweepEachSubaddress(false); + + // sweep all subaddresses together // TODO monero-project: can this reveal outputs belong to the same wallet? + if (copy.getSweepEachSubaddress() !== true) { + copy.setSubaddressIndices(indices.get(accountIdx)); + for (let tx of await this.rpcSweepAccount(copy)) txs.push(tx); + } + + // otherwise sweep each subaddress individually + else { + for (let subaddressIdx of indices.get(accountIdx)) { + copy.setSubaddressIndices([subaddressIdx]); + for (let tx of await this.rpcSweepAccount(copy)) txs.push(tx); + } + } + } + + // notify of changes + if (configNormalized.getRelay()) await this.poll(); + return txs; + } + + async sweepDust(relay?: boolean): Promise { + if (relay === undefined) relay = false; + let resp = await this.config.getServer().sendJsonRequest("sweep_dust", {do_not_relay: !relay}); + if (relay) await this.poll(); + let result = resp.result; + let txSet = MoneroWalletRpc.convertRpcSentTxsToTxSet(result); + if (txSet.getTxs() === undefined) return []; + for (let tx of txSet.getTxs()) { + tx.setIsRelayed(!relay); + tx.setInTxPool(tx.getIsRelayed()); + } + return txSet.getTxs(); + } + + async relayTxs(txsOrMetadatas: (MoneroTxWallet | string)[]): Promise { + assert(Array.isArray(txsOrMetadatas), "Must provide an array of txs or their metadata to relay"); + let txHashes = []; + for (let txOrMetadata of txsOrMetadatas) { + let metadata = txOrMetadata instanceof MoneroTxWallet ? txOrMetadata.getMetadata() : txOrMetadata; + let resp = await this.config.getServer().sendJsonRequest("relay_tx", { hex: metadata }); + txHashes.push(resp.result.tx_hash); + } + await this.poll(); // notify of changes + return txHashes; + } + + async describeTxSet(txSet: MoneroTxSet): Promise { + let resp = await this.config.getServer().sendJsonRequest("describe_transfer", { + unsigned_txset: txSet.getUnsignedTxHex(), + multisig_txset: txSet.getMultisigTxHex() + }); + return MoneroWalletRpc.convertRpcDescribeTransfer(resp.result); + } + + async signTxs(unsignedTxHex: string): Promise { + let resp = await this.config.getServer().sendJsonRequest("sign_transfer", { + unsigned_txset: unsignedTxHex, + export_raw: false + }); + await this.poll(); + return MoneroWalletRpc.convertRpcSentTxsToTxSet(resp.result); + } + + async submitTxs(signedTxHex: string): Promise { + let resp = await this.config.getServer().sendJsonRequest("submit_transfer", { + tx_data_hex: signedTxHex + }); + await this.poll(); + return resp.result.tx_hash_list; + } + + async signMessage(message: string, signatureType = MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY, accountIdx = 0, subaddressIdx = 0): Promise { + let resp = await this.config.getServer().sendJsonRequest("sign", { + data: message, + signature_type: signatureType === MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY ? "spend" : "view", + account_index: accountIdx, + address_index: subaddressIdx + }); + return resp.result.signature; + } + + async verifyMessage(message: string, address: string, signature: string): Promise { + try { + let resp = await this.config.getServer().sendJsonRequest("verify", {data: message, address: address, signature: signature}); + let result = resp.result; + return new MoneroMessageSignatureResult( + result.good ? {isGood: result.good, isOld: result.old, signatureType: result.signature_type === "view" ? MoneroMessageSignatureType.SIGN_WITH_VIEW_KEY : MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY, version: result.version} : {isGood: false} + ); + } catch (e: any) { + if (e.getCode() === -2) return new MoneroMessageSignatureResult({isGood: false}); + throw e; + } + } + + async getTxKey(txHash: string): Promise { + try { + return (await this.config.getServer().sendJsonRequest("get_tx_key", {txid: txHash})).result.tx_key; + } catch (e: any) { + if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message + throw e; + } + } + + async checkTxKey(txHash: string, txKey: string, address: string): Promise { + try { + + // send request + let resp = await this.config.getServer().sendJsonRequest("check_tx_key", {txid: txHash, tx_key: txKey, address: address}); + + // interpret result + let check = new MoneroCheckTx(); + check.setIsGood(true); + check.setNumConfirmations(resp.result.confirmations); + check.setInTxPool(resp.result.in_pool); + check.setReceivedAmount(BigInt(resp.result.received)); + return check; + } catch (e: any) { + if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message + throw e; + } + } + + async getTxProof(txHash: string, address: string, message?: string): Promise { + try { + let resp = await this.config.getServer().sendJsonRequest("get_tx_proof", {txid: txHash, address: address, message: message}); + return resp.result.signature; + } catch (e: any) { + if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message + throw e; + } + } + + async checkTxProof(txHash: string, address: string, message: string | undefined, signature: string): Promise { + try { + + // send request + let resp = await this.config.getServer().sendJsonRequest("check_tx_proof", { + txid: txHash, + address: address, + message: message, + signature: signature + }); + + // interpret response + let isGood = resp.result.good; + let check = new MoneroCheckTx(); + check.setIsGood(isGood); + if (isGood) { + check.setNumConfirmations(resp.result.confirmations); + check.setInTxPool(resp.result.in_pool); + check.setReceivedAmount(BigInt(resp.result.received)); + } + return check; + } catch (e: any) { + if (e instanceof MoneroRpcError && e.getCode() === -1 && e.message === "basic_string") e = new MoneroRpcError("Must provide signature to check tx proof", -1); + if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); + throw e; + } + } + + async getSpendProof(txHash: string, message?: string): Promise { + try { + let resp = await this.config.getServer().sendJsonRequest("get_spend_proof", {txid: txHash, message: message}); + return resp.result.signature; + } catch (e: any) { + if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message + throw e; + } + } + + async checkSpendProof(txHash: string, message: string | undefined, signature: string): Promise { + try { + let resp = await this.config.getServer().sendJsonRequest("check_spend_proof", { + txid: txHash, + message: message, + signature: signature + }); + return resp.result.good; + } catch (e: any) { + if (e instanceof MoneroRpcError && e.getCode() === -8 && e.message.includes("TX ID has invalid format")) e = new MoneroRpcError("TX hash has invalid format", e.getCode(), e.getRpcMethod(), e.getRpcParams()); // normalize error message + throw e; + } + } + + async getReserveProofWallet(message?: string): Promise { + let resp = await this.config.getServer().sendJsonRequest("get_reserve_proof", { + all: true, + message: message + }); + return resp.result.signature; + } + + async getReserveProofAccount(accountIdx: number, amount: bigint, message?: string): Promise { + let resp = await this.config.getServer().sendJsonRequest("get_reserve_proof", { + account_index: accountIdx, + amount: amount.toString(), + message: message + }); + return resp.result.signature; + } + + async checkReserveProof(address: string, message: string | undefined, signature: string): Promise { + + // send request + let resp = await this.config.getServer().sendJsonRequest("check_reserve_proof", { + address: address, + message: message, + signature: signature + }); + + // interpret results + let isGood = resp.result.good; + let check = new MoneroCheckReserve(); + check.setIsGood(isGood); + if (isGood) { + check.setUnconfirmedSpentAmount(BigInt(resp.result.spent)); + check.setTotalAmount(BigInt(resp.result.total)); + } + return check; + } + + async getTxNotes(txHashes: string[]): Promise { + return (await this.config.getServer().sendJsonRequest("get_tx_notes", {txids: txHashes})).result.notes; + } + + async setTxNotes(txHashes: string[], notes: string[]): Promise { + await this.config.getServer().sendJsonRequest("set_tx_notes", {txids: txHashes, notes: notes}); + } + + async getAddressBookEntries(entryIndices?: number[]): Promise { + let resp = await this.config.getServer().sendJsonRequest("get_address_book", {entries: entryIndices}); + if (!resp.result.entries) return []; + let entries = []; + for (let rpcEntry of resp.result.entries) { + entries.push(new MoneroAddressBookEntry().setIndex(rpcEntry.index).setAddress(rpcEntry.address).setDescription(rpcEntry.description).setPaymentId(rpcEntry.payment_id)); + } + return entries; + } + + async addAddressBookEntry(address: string, description?: string): Promise { + let resp = await this.config.getServer().sendJsonRequest("add_address_book", {address: address, description: description}); + return resp.result.index; + } + + async editAddressBookEntry(index: number, setAddress: boolean, address: string | undefined, setDescription: boolean, description: string | undefined): Promise { + let resp = await this.config.getServer().sendJsonRequest("edit_address_book", { + index: index, + set_address: setAddress, + address: address, + set_description: setDescription, + description: description + }); + } + + async deleteAddressBookEntry(entryIdx: number): Promise { + await this.config.getServer().sendJsonRequest("delete_address_book", {index: entryIdx}); + } + + async tagAccounts(tag, accountIndices) { + await this.config.getServer().sendJsonRequest("tag_accounts", {tag: tag, accounts: accountIndices}); + } + + async untagAccounts(accountIndices: number[]): Promise { + await this.config.getServer().sendJsonRequest("untag_accounts", {accounts: accountIndices}); + } + + async getAccountTags(): Promise { + let tags = []; + let resp = await this.config.getServer().sendJsonRequest("get_account_tags"); + if (resp.result.account_tags) { + for (let rpcAccountTag of resp.result.account_tags) { + tags.push(new MoneroAccountTag({ + tag: rpcAccountTag.tag ? rpcAccountTag.tag : undefined, + label: rpcAccountTag.label ? rpcAccountTag.label : undefined, + accountIndices: rpcAccountTag.accounts + })); + } + } + return tags; + } + + async setAccountTagLabel(tag: string, label: string): Promise { + await this.config.getServer().sendJsonRequest("set_account_tag_description", {tag: tag, description: label}); + } + + async getPaymentUri(config: MoneroTxConfig): Promise { + config = MoneroWallet.normalizeCreateTxsConfig(config); + let resp = await this.config.getServer().sendJsonRequest("make_uri", { + address: config.getDestinations()[0].getAddress(), + amount: config.getDestinations()[0].getAmount() ? config.getDestinations()[0].getAmount().toString() : undefined, + payment_id: config.getPaymentId(), + recipient_name: config.getRecipientName(), + tx_description: config.getNote() + }); + return resp.result.uri; + } + + async parsePaymentUri(uri: string): Promise { + assert(uri, "Must provide URI to parse"); + let resp = await this.config.getServer().sendJsonRequest("parse_uri", {uri: uri}); + let config = new MoneroTxConfig({address: resp.result.uri.address, amount: BigInt(resp.result.uri.amount)}); + config.setPaymentId(resp.result.uri.payment_id); + config.setRecipientName(resp.result.uri.recipient_name); + config.setNote(resp.result.uri.tx_description); + if ("" === config.getDestinations()[0].getAddress()) config.getDestinations()[0].setAddress(undefined); + if ("" === config.getPaymentId()) config.setPaymentId(undefined); + if ("" === config.getRecipientName()) config.setRecipientName(undefined); + if ("" === config.getNote()) config.setNote(undefined); + return config; + } + + async getAttribute(key: string): Promise { + try { + let resp = await this.config.getServer().sendJsonRequest("get_attribute", {key: key}); + return resp.result.value === "" ? undefined : resp.result.value; + } catch (e: any) { + if (e instanceof MoneroRpcError && e.getCode() === -45) return undefined; + throw e; + } + } + + async setAttribute(key: string, val: string): Promise { + await this.config.getServer().sendJsonRequest("set_attribute", {key: key, value: val}); + } + + async startMining(numThreads: number, backgroundMining?: boolean, ignoreBattery?: boolean): Promise { + await this.config.getServer().sendJsonRequest("start_mining", { + threads_count: numThreads, + do_background_mining: backgroundMining, + ignore_battery: ignoreBattery + }); + } + + async stopMining(): Promise { + await this.config.getServer().sendJsonRequest("stop_mining"); + } + + async isMultisigImportNeeded(): Promise { + let resp = await this.config.getServer().sendJsonRequest("get_balance"); + return resp.result.multisig_import_needed === true; + } + + async getMultisigInfo(): Promise { + let resp = await this.config.getServer().sendJsonRequest("is_multisig"); + let result = resp.result; + let info = new MoneroMultisigInfo(); + info.setIsMultisig(result.multisig); + info.setIsReady(result.ready); + info.setThreshold(result.threshold); + info.setNumParticipants(result.total); + return info; + } + + async prepareMultisig(): Promise { + let resp = await this.config.getServer().sendJsonRequest("prepare_multisig", {enable_multisig_experimental: true}); + this.addressCache = {}; + let result = resp.result; + return result.multisig_info; + } + + async makeMultisig(multisigHexes: string[], threshold: number, password: string): Promise { + let resp = await this.config.getServer().sendJsonRequest("make_multisig", { + multisig_info: multisigHexes, + threshold: threshold, + password: password + }); + this.addressCache = {}; + return resp.result.multisig_info; + } + + async exchangeMultisigKeys(multisigHexes: string[], password: string): Promise { + let resp = await this.config.getServer().sendJsonRequest("exchange_multisig_keys", {multisig_info: multisigHexes, password: password}); + this.addressCache = {}; + let msResult = new MoneroMultisigInitResult(); + msResult.setAddress(resp.result.address); + msResult.setMultisigHex(resp.result.multisig_info); + if (msResult.getAddress().length === 0) msResult.setAddress(undefined); + if (msResult.getMultisigHex().length === 0) msResult.setMultisigHex(undefined); + return msResult; + } + + async exportMultisigHex(): Promise { + let resp = await this.config.getServer().sendJsonRequest("export_multisig_info"); + return resp.result.info; + } + + async importMultisigHex(multisigHexes: string[]): Promise { + if (!GenUtils.isArray(multisigHexes)) throw new MoneroError("Must provide string[] to importMultisigHex()") + let resp = await this.config.getServer().sendJsonRequest("import_multisig_info", {info: multisigHexes}); + return resp.result.n_outputs; + } + + async signMultisigTxHex(multisigTxHex: string): Promise { + let resp = await this.config.getServer().sendJsonRequest("sign_multisig", {tx_data_hex: multisigTxHex}); + let result = resp.result; + let signResult = new MoneroMultisigSignResult(); + signResult.setSignedMultisigTxHex(result.tx_data_hex); + signResult.setTxHashes(result.tx_hash_list); + return signResult; + } + + async submitMultisigTxHex(signedMultisigTxHex: string): Promise { + let resp = await this.config.getServer().sendJsonRequest("submit_multisig", {tx_data_hex: signedMultisigTxHex}); + return resp.result.tx_hash_list; + } + + async changePassword(oldPassword: string, newPassword: string): Promise { + return this.config.getServer().sendJsonRequest("change_wallet_password", {old_password: oldPassword || "", new_password: newPassword || ""}); + } + + async save(): Promise { + await this.config.getServer().sendJsonRequest("store"); + } + + async close(save = false): Promise { + await super.close(save); + if (save === undefined) save = false; + await this.clear(); + await this.config.getServer().sendJsonRequest("close_wallet", {autosave_current: save}); + } + + async isClosed(): Promise { + try { + await this.getPrimaryAddress(); + } catch (e: any) { + return e instanceof MoneroRpcError && e.getCode() === -13 && e.message.indexOf("No wallet file") > -1; + } + return false; + } + + /** + * Save and close the current wallet and stop the RPC server. + * + * @return {Promise} + */ + async stop(): Promise { + await this.clear(); + await this.config.getServer().sendJsonRequest("stop_wallet"); + } + + // ----------- ADD JSDOC FOR SUPPORTED DEFAULT IMPLEMENTATIONS -------------- + + async getNumBlocksToUnlock(): Promise { return super.getNumBlocksToUnlock(); } + async getTx(txHash: string): Promise { return super.getTx(txHash); } + async getIncomingTransfers(query: Partial): Promise { return super.getIncomingTransfers(query); } + async getOutgoingTransfers(query: Partial) { return super.getOutgoingTransfers(query); } + async createTx(config: Partial): Promise { return super.createTx(config); } + async relayTx(txOrMetadata: MoneroTxWallet | string): Promise { return super.relayTx(txOrMetadata); } + async getTxNote(txHash: string): Promise { return super.getTxNote(txHash); } + async setTxNote(txHash: string, note: string): Promise { return super.setTxNote(txHash, note); } + + // -------------------------------- PRIVATE --------------------------------- + + static async connectToWalletRpc(uriOrConfig: string | Partial | Partial | string[], username?: string, password?: string): Promise { + let config = MoneroWalletRpc.normalizeConfig(uriOrConfig, username, password); + if (config.cmd) return MoneroWalletRpc.startWalletRpcProcess(config); + else return new MoneroWalletRpc(config); + } + + protected static async startWalletRpcProcess(config: Partial): Promise { + assert(GenUtils.isArray(config.cmd), "Must provide string array with command line parameters"); + + // start process + let child_process = await import("child_process"); + const childProcess = child_process.spawn(config.cmd[0], config.cmd.slice(1), { + env: { ...process.env, LANG: 'en_US.UTF-8' } // scrape output in english + }); + childProcess.stdout.setEncoding('utf8'); + childProcess.stderr.setEncoding('utf8'); + + // return promise which resolves after starting monero-wallet-rpc + let uri; + let that = this; + let output = ""; + try { + return await new Promise(function(resolve, reject) { + + // handle stdout + childProcess.stdout.on('data', async function(data) { + let line = data.toString(); + LibraryUtils.log(2, line); + output += line + '\n'; // capture output in case of error + + // extract uri from e.g. "I Binding on 127.0.0.1 (IPv4):38085" + let uriLineContains = "Binding on "; + let uriLineContainsIdx = line.indexOf(uriLineContains); + if (uriLineContainsIdx >= 0) { + let host = line.substring(uriLineContainsIdx + uriLineContains.length, line.lastIndexOf(' ')); + let unformattedLine = line.replace(/\u001b\[.*?m/g, '').trim(); // remove color formatting + let port = unformattedLine.substring(unformattedLine.lastIndexOf(':') + 1); + let sslIdx = config.cmd.indexOf("--rpc-ssl"); + let sslEnabled = sslIdx >= 0 ? "enabled" == config.cmd[sslIdx + 1].toLowerCase() : false; + uri = (sslEnabled ? "https" : "http") + "://" + host + ":" + port; + } + + // read success message + if (line.indexOf("Starting wallet RPC server") >= 0) { + + // get username and password from params + let userPassIdx = config.cmd.indexOf("--rpc-login"); + let userPass = userPassIdx >= 0 ? config.cmd[userPassIdx + 1] : undefined; + let username = userPass === undefined ? undefined : userPass.substring(0, userPass.indexOf(':')); + let password = userPass === undefined ? undefined : userPass.substring(userPass.indexOf(':') + 1); + + // create client connected to internal process + config = config.copy().setServer({uri: uri, username: username, password: password, rejectUnauthorized: config.getServer() ? config.getServer().getRejectUnauthorized() : undefined}); + config.cmd = undefined; + let wallet = await MoneroWalletRpc.connectToWalletRpc(config); + wallet.process = childProcess; + + // resolve promise with client connected to internal process + this.isResolved = true; + resolve(wallet); + } + }); + + // handle stderr + childProcess.stderr.on('data', function(data) { + if (LibraryUtils.getLogLevel() >= 2) console.error(data); + }); + + // handle exit + childProcess.on("exit", function(code) { + if (!this.isResolved) reject(new MoneroError("monero-wallet-rpc process terminated with exit code " + code + (output ? ":\n\n" + output : ""))); + }); + + // handle error + childProcess.on("error", function(err) { + if (err.message.indexOf("ENOENT") >= 0) reject(new MoneroError("monero-wallet-rpc does not exist at path '" + config.cmd[0] + "'")); + if (!this.isResolved) reject(err); + }); + + // handle uncaught exception + childProcess.on("uncaughtException", function(err, origin) { + console.error("Uncaught exception in monero-wallet-rpc process: " + err.message); + console.error(origin); + if (!this.isResolved) reject(err); + }); + }); + } catch (err: any) { + throw new MoneroError(err.message); + } + } + + protected async clear() { + this.refreshListening(); + delete this.addressCache; + this.addressCache = {}; + this.path = undefined; + } + + protected async getAccountIndices(getSubaddressIndices?: any) { + let indices = new Map(); + for (let account of await this.getAccounts()) { + indices.set(account.getIndex(), getSubaddressIndices ? await this.getSubaddressIndices(account.getIndex()) : undefined); + } + return indices; + } + + protected async getSubaddressIndices(accountIdx) { + let subaddressIndices = []; + let resp = await this.config.getServer().sendJsonRequest("get_address", {account_index: accountIdx}); + for (let address of resp.result.addresses) subaddressIndices.push(address.address_index); + return subaddressIndices; + } + + protected async getTransfersAux(query: MoneroTransferQuery) { + + // build params for get_transfers rpc call + let txQuery = query.getTxQuery(); + let canBeConfirmed = txQuery.getIsConfirmed() !== false && txQuery.getInTxPool() !== true && txQuery.getIsFailed() !== true && txQuery.getIsRelayed() !== false; + let canBeInTxPool = txQuery.getIsConfirmed() !== true && txQuery.getInTxPool() !== false && txQuery.getIsFailed() !== true && txQuery.getHeight() === undefined && txQuery.getMaxHeight() === undefined && txQuery.getIsLocked() !== false; + let canBeIncoming = query.getIsIncoming() !== false && query.getIsOutgoing() !== true && query.getHasDestinations() !== true; + let canBeOutgoing = query.getIsOutgoing() !== false && query.getIsIncoming() !== true; + + // check if fetching pool txs contradicted by configuration + if (txQuery.getInTxPool() === true && !canBeInTxPool) { + throw new MoneroError("Cannot fetch pool transactions because it contradicts configuration"); + } + + let params: any = {}; + params.in = canBeIncoming && canBeConfirmed; + params.out = canBeOutgoing && canBeConfirmed; + params.pool = canBeIncoming && canBeInTxPool; + params.pending = canBeOutgoing && canBeInTxPool; + params.failed = txQuery.getIsFailed() !== false && txQuery.getIsConfirmed() !== true && txQuery.getInTxPool() != true; + if (txQuery.getMinHeight() !== undefined) { + if (txQuery.getMinHeight() > 0) params.min_height = txQuery.getMinHeight() - 1; // TODO monero-project: wallet2::get_payments() min_height is exclusive, so manually offset to match intended range (issues #5751, #5598) + else params.min_height = txQuery.getMinHeight(); + } + if (txQuery.getMaxHeight() !== undefined) params.max_height = txQuery.getMaxHeight(); + params.filter_by_height = txQuery.getMinHeight() !== undefined || txQuery.getMaxHeight() !== undefined; + if (query.getAccountIndex() === undefined) { + assert(query.getSubaddressIndex() === undefined && query.getSubaddressIndices() === undefined, "Query specifies a subaddress index but not an account index"); + params.all_accounts = true; + } else { + params.account_index = query.getAccountIndex(); + + // set subaddress indices param + let subaddressIndices = new Set(); + if (query.getSubaddressIndex() !== undefined) subaddressIndices.add(query.getSubaddressIndex()); + if (query.getSubaddressIndices() !== undefined) query.getSubaddressIndices().map(subaddressIdx => subaddressIndices.add(subaddressIdx)); + if (subaddressIndices.size) params.subaddr_indices = Array.from(subaddressIndices); + } + + // cache unique txs and blocks + let txMap = {}; + let blockMap = {}; + + // build txs using `get_transfers` + let resp = await this.config.getServer().sendJsonRequest("get_transfers", params); + for (let key of Object.keys(resp.result)) { + for (let rpcTx of resp.result[key]) { + //if (rpcTx.txid === query.debugTxId) console.log(rpcTx); + let tx = MoneroWalletRpc.convertRpcTxWithTransfer(rpcTx); + if (tx.getIsConfirmed()) assert(tx.getBlock().getTxs().indexOf(tx) > -1); + + // replace transfer amount with destination sum + // TODO monero-wallet-rpc: confirmed tx from/to same account has amount 0 but cached transfers + if (tx.getOutgoingTransfer() !== undefined && tx.getIsRelayed() && !tx.getIsFailed() && + tx.getOutgoingTransfer().getDestinations() && tx.getOutgoingAmount() === 0n) { + let outgoingTransfer = tx.getOutgoingTransfer(); + let transferTotal = BigInt(0); + for (let destination of outgoingTransfer.getDestinations()) transferTotal = transferTotal + destination.getAmount(); + tx.getOutgoingTransfer().setAmount(transferTotal); + } + + // merge tx + MoneroWalletRpc.mergeTx(tx, txMap, blockMap); + } + } + + // sort txs by block height + let txs: MoneroTxWallet[] = Object.values(txMap); + txs.sort(MoneroWalletRpc.compareTxsByHeight); + + // filter and return transfers + let transfers = []; + for (let tx of txs) { + + // tx is not incoming/outgoing unless already set + if (tx.getIsIncoming() === undefined) tx.setIsIncoming(false); + if (tx.getIsOutgoing() === undefined) tx.setIsOutgoing(false); + + // sort incoming transfers + if (tx.getIncomingTransfers() !== undefined) tx.getIncomingTransfers().sort(MoneroWalletRpc.compareIncomingTransfers); + + // collect queried transfers, erase if excluded + for (let transfer of tx.filterTransfers(query)) { + transfers.push(transfer); + } + + // remove txs without requested transfer + if (tx.getBlock() !== undefined && tx.getOutgoingTransfer() === undefined && tx.getIncomingTransfers() === undefined) { + tx.getBlock().getTxs().splice(tx.getBlock().getTxs().indexOf(tx), 1); + } + } + + return transfers; + } + + protected async getOutputsAux(query) { + + // determine account and subaddress indices to be queried + let indices = new Map(); + if (query.getAccountIndex() !== undefined) { + let subaddressIndices = new Set(); + if (query.getSubaddressIndex() !== undefined) subaddressIndices.add(query.getSubaddressIndex()); + if (query.getSubaddressIndices() !== undefined) query.getSubaddressIndices().map(subaddressIdx => subaddressIndices.add(subaddressIdx)); + indices.set(query.getAccountIndex(), subaddressIndices.size ? Array.from(subaddressIndices) : undefined); // undefined will fetch from all subaddresses + } else { + assert.equal(query.getSubaddressIndex(), undefined, "Query specifies a subaddress index but not an account index") + assert(query.getSubaddressIndices() === undefined || query.getSubaddressIndices().length === 0, "Query specifies subaddress indices but not an account index"); + indices = await this.getAccountIndices(); // fetch all account indices without subaddresses + } + + // cache unique txs and blocks + let txMap = {}; + let blockMap = {}; + + // collect txs with outputs for each indicated account using `incoming_transfers` rpc call + let params: any = {}; + params.transfer_type = query.getIsSpent() === true ? "unavailable" : query.getIsSpent() === false ? "available" : "all"; + params.verbose = true; + for (let accountIdx of indices.keys()) { + + // send request + params.account_index = accountIdx; + params.subaddr_indices = indices.get(accountIdx); + let resp = await this.config.getServer().sendJsonRequest("incoming_transfers", params); + + // convert response to txs with outputs and merge + if (resp.result.transfers === undefined) continue; + for (let rpcOutput of resp.result.transfers) { + let tx = MoneroWalletRpc.convertRpcTxWalletWithOutput(rpcOutput); + MoneroWalletRpc.mergeTx(tx, txMap, blockMap); + } + } + + // sort txs by block height + let txs: MoneroTxWallet[] = Object.values(txMap); + txs.sort(MoneroWalletRpc.compareTxsByHeight); + + // collect queried outputs + let outputs = []; + for (let tx of txs) { + + // sort outputs + if (tx.getOutputs() !== undefined) tx.getOutputs().sort(MoneroWalletRpc.compareOutputs); + + // collect queried outputs, erase if excluded + for (let output of tx.filterOutputs(query)) outputs.push(output); + + // remove excluded txs from block + if (tx.getOutputs() === undefined && tx.getBlock() !== undefined) { + tx.getBlock().getTxs().splice(tx.getBlock().getTxs().indexOf(tx), 1); + } + } + return outputs; + } + + /** + * Common method to get key images. + * + * @param all - pecifies to get all xor only new images from last import + * @return {MoneroKeyImage[]} are the key images + */ + protected async rpcExportKeyImages(all) { + let resp = await this.config.getServer().sendJsonRequest("export_key_images", {all: all}); + if (!resp.result.signed_key_images) return []; + return resp.result.signed_key_images.map(rpcImage => new MoneroKeyImage(rpcImage.key_image, rpcImage.signature)); + } + + protected async rpcSweepAccount(config: MoneroTxConfig) { + + // validate config + if (config === undefined) throw new MoneroError("Must provide sweep config"); + if (config.getAccountIndex() === undefined) throw new MoneroError("Must provide an account index to sweep from"); + if (config.getDestinations() === undefined || config.getDestinations().length != 1) throw new MoneroError("Must provide exactly one destination to sweep to"); + if (config.getDestinations()[0].getAddress() === undefined) throw new MoneroError("Must provide destination address to sweep to"); + if (config.getDestinations()[0].getAmount() !== undefined) throw new MoneroError("Cannot specify amount in sweep config"); + if (config.getKeyImage() !== undefined) throw new MoneroError("Key image defined; use sweepOutput() to sweep an output by its key image"); + if (config.getSubaddressIndices() !== undefined && config.getSubaddressIndices().length === 0) throw new MoneroError("Empty list given for subaddresses indices to sweep"); + if (config.getSweepEachSubaddress()) throw new MoneroError("Cannot sweep each subaddress with RPC `sweep_all`"); + if (config.getSubtractFeeFrom() !== undefined && config.getSubtractFeeFrom().length > 0) throw new MoneroError("Sweeping output does not support subtracting fees from destinations"); + + // sweep from all subaddresses if not otherwise defined + if (config.getSubaddressIndices() === undefined) { + config.setSubaddressIndices([]); + for (let subaddress of await this.getSubaddresses(config.getAccountIndex())) { + config.getSubaddressIndices().push(subaddress.getIndex()); + } + } + if (config.getSubaddressIndices().length === 0) throw new MoneroError("No subaddresses to sweep from"); + + // common config params + let params: any = {}; + let relay = config.getRelay() === true; + params.account_index = config.getAccountIndex(); + params.subaddr_indices = config.getSubaddressIndices(); + params.address = config.getDestinations()[0].getAddress(); + assert(config.getPriority() === undefined || config.getPriority() >= 0 && config.getPriority() <= 3); + params.priority = config.getPriority(); + params.payment_id = config.getPaymentId(); + params.do_not_relay = !relay; + params.below_amount = config.getBelowAmount(); + params.get_tx_keys = true; + params.get_tx_hex = true; + params.get_tx_metadata = true; + + // invoke wallet rpc `sweep_all` + let resp = await this.config.getServer().sendJsonRequest("sweep_all", params); + let result = resp.result; + + // initialize txs from response + let txSet = MoneroWalletRpc.convertRpcSentTxsToTxSet(result, undefined, config); + + // initialize remaining known fields + for (let tx of txSet.getTxs()) { + tx.setIsLocked(true); + tx.setIsConfirmed(false); + tx.setNumConfirmations(0); + tx.setRelay(relay); + tx.setInTxPool(relay); + tx.setIsRelayed(relay); + tx.setIsMinerTx(false); + tx.setIsFailed(false); + let transfer = tx.getOutgoingTransfer(); + transfer.setAccountIndex(config.getAccountIndex()); + if (config.getSubaddressIndices().length === 1) transfer.setSubaddressIndices(config.getSubaddressIndices()); + let destination = new MoneroDestination(config.getDestinations()[0].getAddress(), BigInt(transfer.getAmount())); + transfer.setDestinations([destination]); + tx.setOutgoingTransfer(transfer); + tx.setPaymentId(config.getPaymentId()); + if (tx.getUnlockTime() === undefined) tx.setUnlockTime(0n); + if (tx.getRelay()) { + if (tx.getLastRelayedTimestamp() === undefined) tx.setLastRelayedTimestamp(+new Date().getTime()); // TODO (monero-wallet-rpc): provide timestamp on response; unconfirmed timestamps vary + if (tx.getIsDoubleSpendSeen() === undefined) tx.setIsDoubleSpendSeen(false); + } + } + return txSet.getTxs(); + } + + protected refreshListening() { + if (this.walletPoller == undefined && this.listeners.length) this.walletPoller = new WalletPoller(this); + if (this.walletPoller !== undefined) this.walletPoller.setIsPolling(this.listeners.length > 0); + } + + /** + * Poll if listening. + */ + protected async poll() { + if (this.walletPoller !== undefined && this.walletPoller.isPolling) await this.walletPoller.poll(); + } + + // ---------------------------- PRIVATE STATIC ------------------------------ + + protected static normalizeConfig(uriOrConfig: string | Partial | Partial | string[], username?: string, password?: string): MoneroWalletConfig { + let config: undefined | Partial = undefined; + if (typeof uriOrConfig === "string" || (uriOrConfig as Partial).uri) config = new MoneroWalletConfig({server: new MoneroRpcConnection(uriOrConfig as string | Partial, username, password)}); + else if (GenUtils.isArray(uriOrConfig)) config = new MoneroWalletConfig({cmd: uriOrConfig as string[]}); + else config = new MoneroWalletConfig(uriOrConfig as Partial); + if (config.proxyToWorker === undefined) config.proxyToWorker = true; + return config as MoneroWalletConfig; + } + + /** + * Remove criteria which requires looking up other transfers/outputs to + * fulfill query. + * + * @param {MoneroTxQuery} query - the query to decontextualize + * @return {MoneroTxQuery} a reference to the query for convenience + */ + protected static decontextualize(query) { + query.setIsIncoming(undefined); + query.setIsOutgoing(undefined); + query.setTransferQuery(undefined); + query.setInputQuery(undefined); + query.setOutputQuery(undefined); + return query; + } + + protected static isContextual(query) { + if (!query) return false; + if (!query.getTxQuery()) return false; + if (query.getTxQuery().getIsIncoming() !== undefined) return true; // requires getting other transfers + if (query.getTxQuery().getIsOutgoing() !== undefined) return true; + if (query instanceof MoneroTransferQuery) { + if (query.getTxQuery().getOutputQuery() !== undefined) return true; // requires getting other outputs + } else if (query instanceof MoneroOutputQuery) { + if (query.getTxQuery().getTransferQuery() !== undefined) return true; // requires getting other transfers + } else { + throw new MoneroError("query must be tx or transfer query"); + } + return false; + } + + protected static convertRpcAccount(rpcAccount) { + let account = new MoneroAccount(); + for (let key of Object.keys(rpcAccount)) { + let val = rpcAccount[key]; + if (key === "account_index") account.setIndex(val); + else if (key === "balance") account.setBalance(BigInt(val)); + else if (key === "unlocked_balance") account.setUnlockedBalance(BigInt(val)); + else if (key === "base_address") account.setPrimaryAddress(val); + else if (key === "tag") account.setTag(val); + else if (key === "label") { } // label belongs to first subaddress + else console.log("WARNING: ignoring unexpected account field: " + key + ": " + val); + } + if ("" === account.getTag()) account.setTag(undefined); + return account; + } + + protected static convertRpcSubaddress(rpcSubaddress) { + let subaddress = new MoneroSubaddress(); + for (let key of Object.keys(rpcSubaddress)) { + let val = rpcSubaddress[key]; + if (key === "account_index") subaddress.setAccountIndex(val); + else if (key === "address_index") subaddress.setIndex(val); + else if (key === "address") subaddress.setAddress(val); + else if (key === "balance") subaddress.setBalance(BigInt(val)); + else if (key === "unlocked_balance") subaddress.setUnlockedBalance(BigInt(val)); + else if (key === "num_unspent_outputs") subaddress.setNumUnspentOutputs(val); + else if (key === "label") { if (val) subaddress.setLabel(val); } + else if (key === "used") subaddress.setIsUsed(val); + else if (key === "blocks_to_unlock") subaddress.setNumBlocksToUnlock(val); + else if (key == "time_to_unlock") {} // ignoring + else console.log("WARNING: ignoring unexpected subaddress field: " + key + ": " + val); + } + return subaddress; + } + + /** + * Initializes a sent transaction. + * + * TODO: remove copyDestinations after >18.3.1 when subtractFeeFrom fully supported + * + * @param {MoneroTxConfig} config - send config + * @param {MoneroTxWallet} [tx] - existing transaction to initialize (optional) + * @param {boolean} copyDestinations - copies config destinations if true + * @return {MoneroTxWallet} is the initialized send tx + */ + protected static initSentTxWallet(config: Partial, tx, copyDestinations) { + if (!tx) tx = new MoneroTxWallet(); + let relay = config.getRelay() === true; + tx.setIsOutgoing(true); + tx.setIsConfirmed(false); + tx.setNumConfirmations(0); + tx.setInTxPool(relay); + tx.setRelay(relay); + tx.setIsRelayed(relay); + tx.setIsMinerTx(false); + tx.setIsFailed(false); + tx.setIsLocked(true); + tx.setRingSize(MoneroUtils.RING_SIZE); + let transfer = new MoneroOutgoingTransfer(); + transfer.setTx(tx); + if (config.getSubaddressIndices() && config.getSubaddressIndices().length === 1) transfer.setSubaddressIndices(config.getSubaddressIndices().slice(0)); // we know src subaddress indices iff config specifies 1 + if (copyDestinations) { + let destCopies = []; + for (let dest of config.getDestinations()) destCopies.push(dest.copy()); + transfer.setDestinations(destCopies); + } + tx.setOutgoingTransfer(transfer); + tx.setPaymentId(config.getPaymentId()); + if (tx.getUnlockTime() === undefined) tx.setUnlockTime(0n); + if (config.getRelay()) { + if (tx.getLastRelayedTimestamp() === undefined) tx.setLastRelayedTimestamp(+new Date().getTime()); // TODO (monero-wallet-rpc): provide timestamp on response; unconfirmed timestamps vary + if (tx.getIsDoubleSpendSeen() === undefined) tx.setIsDoubleSpendSeen(false); + } + return tx; + } + + /** + * Initializes a tx set from a RPC map excluding txs. + * + * @param rpcMap - map to initialize the tx set from + * @return MoneroTxSet - initialized tx set + * @return the resulting tx set + */ + protected static convertRpcTxSet(rpcMap) { + let txSet = new MoneroTxSet(); + txSet.setMultisigTxHex(rpcMap.multisig_txset); + txSet.setUnsignedTxHex(rpcMap.unsigned_txset); + txSet.setSignedTxHex(rpcMap.signed_txset); + if (txSet.getMultisigTxHex() !== undefined && txSet.getMultisigTxHex().length === 0) txSet.setMultisigTxHex(undefined); + if (txSet.getUnsignedTxHex() !== undefined && txSet.getUnsignedTxHex().length === 0) txSet.setUnsignedTxHex(undefined); + if (txSet.getSignedTxHex() !== undefined && txSet.getSignedTxHex().length === 0) txSet.setSignedTxHex(undefined); + return txSet; + } + + /** + * Initializes a MoneroTxSet from a list of rpc txs. + * + * @param rpcTxs - rpc txs to initialize the set from + * @param txs - existing txs to further initialize (optional) + * @param config - tx config + * @return the converted tx set + */ + protected static convertRpcSentTxsToTxSet(rpcTxs: any, txs?: any, config?: any) { + + // build shared tx set + let txSet = MoneroWalletRpc.convertRpcTxSet(rpcTxs); + + // get number of txs + let numTxs = rpcTxs.fee_list ? rpcTxs.fee_list.length : rpcTxs.tx_hash_list ? rpcTxs.tx_hash_list.length : 0; + + // done if rpc response contains no txs + if (numTxs === 0) { + assert.equal(txs, undefined); + return txSet; + } + + // initialize txs if none given + if (txs) txSet.setTxs(txs); + else { + txs = []; + for (let i = 0; i < numTxs; i++) txs.push(new MoneroTxWallet()); + } + for (let tx of txs) { + tx.setTxSet(txSet); + tx.setIsOutgoing(true); + } + txSet.setTxs(txs); + + // initialize txs from rpc lists + for (let key of Object.keys(rpcTxs)) { + let val = rpcTxs[key]; + if (key === "tx_hash_list") for (let i = 0; i < val.length; i++) txs[i].setHash(val[i]); + else if (key === "tx_key_list") for (let i = 0; i < val.length; i++) txs[i].setKey(val[i]); + else if (key === "tx_blob_list") for (let i = 0; i < val.length; i++) txs[i].setFullHex(val[i]); + else if (key === "tx_metadata_list") for (let i = 0; i < val.length; i++) txs[i].setMetadata(val[i]); + else if (key === "fee_list") for (let i = 0; i < val.length; i++) txs[i].setFee(BigInt(val[i])); + else if (key === "weight_list") for (let i = 0; i < val.length; i++) txs[i].setWeight(val[i]); + else if (key === "amount_list") { + for (let i = 0; i < val.length; i++) { + if (txs[i].getOutgoingTransfer() == undefined) txs[i].setOutgoingTransfer(new MoneroOutgoingTransfer().setTx(txs[i])); + txs[i].getOutgoingTransfer().setAmount(BigInt(val[i])); + } + } + else if (key === "multisig_txset" || key === "unsigned_txset" || key === "signed_txset") {} // handled elsewhere + else if (key === "spent_key_images_list") { + let inputKeyImagesList = val; + for (let i = 0; i < inputKeyImagesList.length; i++) { + GenUtils.assertTrue(txs[i].getInputs() === undefined); + txs[i].setInputs([]); + for (let inputKeyImage of inputKeyImagesList[i]["key_images"]) { + txs[i].getInputs().push(new MoneroOutputWallet().setKeyImage(new MoneroKeyImage().setHex(inputKeyImage)).setTx(txs[i])); + } + } + } + else if (key === "amounts_by_dest_list") { + let amountsByDestList = val; + let destinationIdx = 0; + for (let txIdx = 0; txIdx < amountsByDestList.length; txIdx++) { + let amountsByDest = amountsByDestList[txIdx]["amounts"]; + if (txs[txIdx].getOutgoingTransfer() === undefined) txs[txIdx].setOutgoingTransfer(new MoneroOutgoingTransfer().setTx(txs[txIdx])); + txs[txIdx].getOutgoingTransfer().setDestinations([]); + for (let amount of amountsByDest) { + if (config.getDestinations().length === 1) txs[txIdx].getOutgoingTransfer().getDestinations().push(new MoneroDestination(config.getDestinations()[0].getAddress(), BigInt(amount))); // sweeping can create multiple txs with one address + else txs[txIdx].getOutgoingTransfer().getDestinations().push(new MoneroDestination(config.getDestinations()[destinationIdx++].getAddress(), BigInt(amount))); + } + } + } + else console.log("WARNING: ignoring unexpected transaction field: " + key + ": " + val); + } + + return txSet; + } + + /** + * Converts a rpc tx with a transfer to a tx set with a tx and transfer. + * + * @param rpcTx - rpc tx to build from + * @param tx - existing tx to continue initializing (optional) + * @param isOutgoing - specifies if the tx is outgoing if true, incoming if false, or decodes from type if undefined + * @param config - tx config + * @return the initialized tx set with a tx + */ + protected static convertRpcTxToTxSet(rpcTx, tx, isOutgoing, config) { + let txSet = MoneroWalletRpc.convertRpcTxSet(rpcTx); + txSet.setTxs([MoneroWalletRpc.convertRpcTxWithTransfer(rpcTx, tx, isOutgoing, config).setTxSet(txSet)]); + return txSet; + } + + /** + * Builds a MoneroTxWallet from a RPC tx. + * + * @param rpcTx - rpc tx to build from + * @param tx - existing tx to continue initializing (optional) + * @param isOutgoing - specifies if the tx is outgoing if true, incoming if false, or decodes from type if undefined + * @param config - tx config + * @return {MoneroTxWallet} is the initialized tx + */ + protected static convertRpcTxWithTransfer(rpcTx: any, tx?: any, isOutgoing?: any, config?: any) { // TODO: change everything to safe set + + // initialize tx to return + if (!tx) tx = new MoneroTxWallet(); + + // initialize tx state from rpc type + if (rpcTx.type !== undefined) isOutgoing = MoneroWalletRpc.decodeRpcType(rpcTx.type, tx); + else assert.equal(typeof isOutgoing, "boolean", "Must indicate if tx is outgoing (true) xor incoming (false) since unknown"); + + // TODO: safe set + // initialize remaining fields TODO: seems this should be part of common function with DaemonRpc.convertRpcTx + let header; + let transfer; + for (let key of Object.keys(rpcTx)) { + let val = rpcTx[key]; + if (key === "txid") tx.setHash(val); + else if (key === "tx_hash") tx.setHash(val); + else if (key === "fee") tx.setFee(BigInt(val)); + else if (key === "note") { if (val) tx.setNote(val); } + else if (key === "tx_key") tx.setKey(val); + else if (key === "type") { } // type already handled + else if (key === "tx_size") tx.setSize(val); + else if (key === "unlock_time") tx.setUnlockTime(val); + else if (key === "weight") tx.setWeight(val); + else if (key === "locked") tx.setIsLocked(val); + else if (key === "tx_blob") tx.setFullHex(val); + else if (key === "tx_metadata") tx.setMetadata(val); + else if (key === "double_spend_seen") tx.setIsDoubleSpendSeen(val); + else if (key === "block_height" || key === "height") { + if (tx.getIsConfirmed()) { + if (!header) header = new MoneroBlockHeader(); + header.setHeight(val); + } + } + else if (key === "timestamp") { + if (tx.getIsConfirmed()) { + if (!header) header = new MoneroBlockHeader(); + header.setTimestamp(val); + } else { + // timestamp of unconfirmed tx is current request time + } + } + else if (key === "confirmations") tx.setNumConfirmations(val); + else if (key === "suggested_confirmations_threshold") { + if (transfer === undefined) transfer = (isOutgoing ? new MoneroOutgoingTransfer() : new MoneroIncomingTransfer()).setTx(tx); + if (!isOutgoing) transfer.setNumSuggestedConfirmations(val); + } + else if (key === "amount") { + if (transfer === undefined) transfer = (isOutgoing ? new MoneroOutgoingTransfer() : new MoneroIncomingTransfer()).setTx(tx); + transfer.setAmount(BigInt(val)); + } + else if (key === "amounts") {} // ignoring, amounts sum to amount + else if (key === "address") { + if (!isOutgoing) { + if (!transfer) transfer = new MoneroIncomingTransfer().setTx(tx); + transfer.setAddress(val); + } + } + else if (key === "payment_id") { + if ("" !== val && MoneroTxWallet.DEFAULT_PAYMENT_ID !== val) tx.setPaymentId(val); // default is undefined + } + else if (key === "subaddr_index") assert(rpcTx.subaddr_indices); // handled by subaddr_indices + else if (key === "subaddr_indices") { + if (!transfer) transfer = (isOutgoing ? new MoneroOutgoingTransfer() : new MoneroIncomingTransfer()).setTx(tx); + let rpcIndices = val; + transfer.setAccountIndex(rpcIndices[0].major); + if (isOutgoing) { + let subaddressIndices = []; + for (let rpcIndex of rpcIndices) subaddressIndices.push(rpcIndex.minor); + transfer.setSubaddressIndices(subaddressIndices); + } else { + assert.equal(rpcIndices.length, 1); + transfer.setSubaddressIndex(rpcIndices[0].minor); + } + } + else if (key === "destinations" || key == "recipients") { + assert(isOutgoing); + let destinations = []; + for (let rpcDestination of val) { + let destination = new MoneroDestination(); + destinations.push(destination); + for (let destinationKey of Object.keys(rpcDestination)) { + if (destinationKey === "address") destination.setAddress(rpcDestination[destinationKey]); + else if (destinationKey === "amount") destination.setAmount(BigInt(rpcDestination[destinationKey])); + else throw new MoneroError("Unrecognized transaction destination field: " + destinationKey); + } + } + if (transfer === undefined) transfer = new MoneroOutgoingTransfer({tx: tx}); + transfer.setDestinations(destinations); + } + else if (key === "multisig_txset" && val !== undefined) {} // handled elsewhere; this method only builds a tx wallet + else if (key === "unsigned_txset" && val !== undefined) {} // handled elsewhere; this method only builds a tx wallet + else if (key === "amount_in") tx.setInputSum(BigInt(val)); + else if (key === "amount_out") tx.setOutputSum(BigInt(val)); + else if (key === "change_address") tx.setChangeAddress(val === "" ? undefined : val); + else if (key === "change_amount") tx.setChangeAmount(BigInt(val)); + else if (key === "dummy_outputs") tx.setNumDummyOutputs(val); + else if (key === "extra") tx.setExtraHex(val); + else if (key === "ring_size") tx.setRingSize(val); + else if (key === "spent_key_images") { + let inputKeyImages = val.key_images; + GenUtils.assertTrue(tx.getInputs() === undefined); + tx.setInputs([]); + for (let inputKeyImage of inputKeyImages) { + tx.getInputs().push(new MoneroOutputWallet().setKeyImage(new MoneroKeyImage().setHex(inputKeyImage)).setTx(tx)); + } + } + else if (key === "amounts_by_dest") { + GenUtils.assertTrue(isOutgoing); + let amountsByDest = val.amounts; + assert.equal(config.getDestinations().length, amountsByDest.length); + if (transfer === undefined) transfer = new MoneroOutgoingTransfer().setTx(tx); + transfer.setDestinations([]); + for (let i = 0; i < config.getDestinations().length; i++) { + transfer.getDestinations().push(new MoneroDestination(config.getDestinations()[i].getAddress(), BigInt(amountsByDest[i]))); + } + } + else console.log("WARNING: ignoring unexpected transaction field with transfer: " + key + ": " + val); + } + + // link block and tx + if (header) tx.setBlock(new MoneroBlock(header).setTxs([tx])); + + // initialize final fields + if (transfer) { + if (tx.getIsConfirmed() === undefined) tx.setIsConfirmed(false); + if (!transfer.getTx().getIsConfirmed()) tx.setNumConfirmations(0); + if (isOutgoing) { + tx.setIsOutgoing(true); + if (tx.getOutgoingTransfer()) { + if (transfer.getDestinations()) tx.getOutgoingTransfer().setDestinations(undefined); // overwrite to avoid reconcile error TODO: remove after >18.3.1 when amounts_by_dest supported + tx.getOutgoingTransfer().merge(transfer); + } + else tx.setOutgoingTransfer(transfer); + } else { + tx.setIsIncoming(true); + tx.setIncomingTransfers([transfer]); + } + } + + // return initialized transaction + return tx; + } + + protected static convertRpcTxWalletWithOutput(rpcOutput) { + + // initialize tx + let tx = new MoneroTxWallet(); + tx.setIsConfirmed(true); + tx.setIsRelayed(true); + tx.setIsFailed(false); + + // initialize output + let output = new MoneroOutputWallet({tx: tx}); + for (let key of Object.keys(rpcOutput)) { + let val = rpcOutput[key]; + if (key === "amount") output.setAmount(BigInt(val)); + else if (key === "spent") output.setIsSpent(val); + else if (key === "key_image") { if ("" !== val) output.setKeyImage(new MoneroKeyImage(val)); } + else if (key === "global_index") output.setIndex(val); + else if (key === "tx_hash") tx.setHash(val); + else if (key === "unlocked") tx.setIsLocked(!val); + else if (key === "frozen") output.setIsFrozen(val); + else if (key === "pubkey") output.setStealthPublicKey(val); + else if (key === "subaddr_index") { + output.setAccountIndex(val.major); + output.setSubaddressIndex(val.minor); + } + else if (key === "block_height") tx.setBlock((new MoneroBlock().setHeight(val) as MoneroBlock).setTxs([tx as MoneroTx])); + else console.log("WARNING: ignoring unexpected transaction field: " + key + ": " + val); + } + + // initialize tx with output + tx.setOutputs([output]); + return tx; + } + + protected static convertRpcDescribeTransfer(rpcDescribeTransferResult) { + let txSet = new MoneroTxSet(); + for (let key of Object.keys(rpcDescribeTransferResult)) { + let val = rpcDescribeTransferResult[key]; + if (key === "desc") { + txSet.setTxs([]); + for (let txMap of val) { + let tx = MoneroWalletRpc.convertRpcTxWithTransfer(txMap, undefined, true); + tx.setTxSet(txSet); + txSet.getTxs().push(tx); + } + } + else if (key === "summary") { } // TODO: support tx set summary fields? + else console.log("WARNING: ignoring unexpected descdribe transfer field: " + key + ": " + val); + } + return txSet; + } + + /** + * Decodes a "type" from monero-wallet-rpc to initialize type and state + * fields in the given transaction. + * + * TODO: these should be safe set + * + * @param rpcType is the type to decode + * @param tx is the transaction to decode known fields to + * @return {boolean} true if the rpc type indicates outgoing xor incoming + */ + protected static decodeRpcType(rpcType, tx) { + let isOutgoing; + if (rpcType === "in") { + isOutgoing = false; + tx.setIsConfirmed(true); + tx.setInTxPool(false); + tx.setIsRelayed(true); + tx.setRelay(true); + tx.setIsFailed(false); + tx.setIsMinerTx(false); + } else if (rpcType === "out") { + isOutgoing = true; + tx.setIsConfirmed(true); + tx.setInTxPool(false); + tx.setIsRelayed(true); + tx.setRelay(true); + tx.setIsFailed(false); + tx.setIsMinerTx(false); + } else if (rpcType === "pool") { + isOutgoing = false; + tx.setIsConfirmed(false); + tx.setInTxPool(true); + tx.setIsRelayed(true); + tx.setRelay(true); + tx.setIsFailed(false); + tx.setIsMinerTx(false); // TODO: but could it be? + } else if (rpcType === "pending") { + isOutgoing = true; + tx.setIsConfirmed(false); + tx.setInTxPool(true); + tx.setIsRelayed(true); + tx.setRelay(true); + tx.setIsFailed(false); + tx.setIsMinerTx(false); + } else if (rpcType === "block") { + isOutgoing = false; + tx.setIsConfirmed(true); + tx.setInTxPool(false); + tx.setIsRelayed(true); + tx.setRelay(true); + tx.setIsFailed(false); + tx.setIsMinerTx(true); + } else if (rpcType === "failed") { + isOutgoing = true; + tx.setIsConfirmed(false); + tx.setInTxPool(false); + tx.setIsRelayed(true); + tx.setRelay(true); + tx.setIsFailed(true); + tx.setIsMinerTx(false); + } else { + throw new MoneroError("Unrecognized transfer type: " + rpcType); + } + return isOutgoing; + } + + /** + * Merges a transaction into a unique set of transactions. + * + * @param {MoneroTxWallet} tx - the transaction to merge into the existing txs + * @param {Object} txMap - maps tx hashes to txs + * @param {Object} blockMap - maps block heights to blocks + */ + protected static mergeTx(tx, txMap, blockMap) { + assert(tx.getHash() !== undefined); + + // merge tx + let aTx = txMap[tx.getHash()]; + if (aTx === undefined) txMap[tx.getHash()] = tx; // cache new tx + else aTx.merge(tx); // merge with existing tx + + // merge tx's block if confirmed + if (tx.getHeight() !== undefined) { + let aBlock = blockMap[tx.getHeight()]; + if (aBlock === undefined) blockMap[tx.getHeight()] = tx.getBlock(); // cache new block + else aBlock.merge(tx.getBlock()); // merge with existing block + } + } + + /** + * Compares two transactions by their height. + */ + protected static compareTxsByHeight(tx1, tx2) { + if (tx1.getHeight() === undefined && tx2.getHeight() === undefined) return 0; // both unconfirmed + else if (tx1.getHeight() === undefined) return 1; // tx1 is unconfirmed + else if (tx2.getHeight() === undefined) return -1; // tx2 is unconfirmed + let diff = tx1.getHeight() - tx2.getHeight(); + if (diff !== 0) return diff; + return tx1.getBlock().getTxs().indexOf(tx1) - tx2.getBlock().getTxs().indexOf(tx2); // txs are in the same block so retain their original order + } + + /** + * Compares two transfers by ascending account and subaddress indices. + */ + static compareIncomingTransfers(t1, t2) { + if (t1.getAccountIndex() < t2.getAccountIndex()) return -1; + else if (t1.getAccountIndex() === t2.getAccountIndex()) return t1.getSubaddressIndex() - t2.getSubaddressIndex(); + return 1; + } + + /** + * Compares two outputs by ascending account and subaddress indices. + */ + protected static compareOutputs(o1, o2) { + + // compare by height + let heightComparison = MoneroWalletRpc.compareTxsByHeight(o1.getTx(), o2.getTx()); + if (heightComparison !== 0) return heightComparison; + + // compare by account index, subaddress index, output index, then key image hex + let compare = o1.getAccountIndex() - o2.getAccountIndex(); + if (compare !== 0) return compare; + compare = o1.getSubaddressIndex() - o2.getSubaddressIndex(); + if (compare !== 0) return compare; + compare = o1.getIndex() - o2.getIndex(); + if (compare !== 0) return compare; + return o1.getKeyImage().getHex().localeCompare(o2.getKeyImage().getHex()); + } +} + +/** + * Polls monero-wallet-rpc to provide listener notifications. + * + * @private + */ +class WalletPoller { + + // instance variables + isPolling: boolean; + protected wallet: MoneroWalletRpc; + protected looper: TaskLooper; + protected prevLockedTxs: any; + protected prevUnconfirmedNotifications: any; + protected prevConfirmedNotifications: any; + protected threadPool: any; + protected numPolling: any; + protected prevHeight: any; + protected prevBalances: any; + + constructor(wallet) { + let that = this; + this.wallet = wallet; + this.looper = new TaskLooper(async function() { await that.poll(); }); + this.prevLockedTxs = []; + this.prevUnconfirmedNotifications = new Set(); // tx hashes of previous notifications + this.prevConfirmedNotifications = new Set(); // tx hashes of previously confirmed but not yet unlocked notifications + this.threadPool = new ThreadPool(1); // synchronize polls + this.numPolling = 0; + } + + setIsPolling(isPolling) { + this.isPolling = isPolling; + if (isPolling) this.looper.start(this.wallet.getSyncPeriodInMs()); + else this.looper.stop(); + } + + setPeriodInMs(periodInMs) { + this.looper.setPeriodInMs(periodInMs); + } + + async poll() { + + // skip if next poll is queued + if (this.numPolling > 1) return; + this.numPolling++; + + // synchronize polls + let that = this; + return this.threadPool.submit(async function() { + try { + + // skip if wallet is closed + if (await that.wallet.isClosed()) { + that.numPolling--; + return; + } + + // take initial snapshot + if (that.prevBalances === undefined) { + that.prevHeight = await that.wallet.getHeight(); + that.prevLockedTxs = await that.wallet.getTxs(new MoneroTxQuery().setIsLocked(true)); + that.prevBalances = await that.wallet.getBalances(); + that.numPolling--; + return; + } + + // announce height changes + let height = await that.wallet.getHeight(); + if (that.prevHeight !== height) { + for (let i = that.prevHeight; i < height; i++) await that.onNewBlock(i); + that.prevHeight = height; + } + + // get locked txs for comparison to previous + let minHeight = Math.max(0, height - 70); // only monitor recent txs + let lockedTxs = await that.wallet.getTxs(new MoneroTxQuery().setIsLocked(true).setMinHeight(minHeight).setIncludeOutputs(true)); + + // collect hashes of txs no longer locked + let noLongerLockedHashes = []; + for (let prevLockedTx of that.prevLockedTxs) { + if (that.getTx(lockedTxs, prevLockedTx.getHash()) === undefined) { + noLongerLockedHashes.push(prevLockedTx.getHash()); + } + } + + // save locked txs for next comparison + that.prevLockedTxs = lockedTxs; + + // fetch txs which are no longer locked + let unlockedTxs = noLongerLockedHashes.length === 0 ? [] : await that.wallet.getTxs(new MoneroTxQuery().setIsLocked(false).setMinHeight(minHeight).setHashes(noLongerLockedHashes).setIncludeOutputs(true)); + + // announce new unconfirmed and confirmed outputs + for (let lockedTx of lockedTxs) { + let searchSet = lockedTx.getIsConfirmed() ? that.prevConfirmedNotifications : that.prevUnconfirmedNotifications; + let unannounced = !searchSet.has(lockedTx.getHash()); + searchSet.add(lockedTx.getHash()); + if (unannounced) await that.notifyOutputs(lockedTx); + } + + // announce new unlocked outputs + for (let unlockedTx of unlockedTxs) { + that.prevUnconfirmedNotifications.delete(unlockedTx.getHash()); + that.prevConfirmedNotifications.delete(unlockedTx.getHash()); + await that.notifyOutputs(unlockedTx); + } + + // announce balance changes + await that.checkForChangedBalances(); + that.numPolling--; + } catch (err: any) { + that.numPolling--; + console.error("Failed to background poll wallet '" + await that.wallet.getPath() + "': " + err.message); + } + }); + } + + protected async onNewBlock(height) { + await this.wallet.announceNewBlock(height); + } + + protected async notifyOutputs(tx) { + + // notify spent outputs // TODO (monero-project): monero-wallet-rpc does not allow scrape of tx inputs so providing one input with outgoing amount + if (tx.getOutgoingTransfer() !== undefined) { + assert(tx.getInputs() === undefined); + let output = new MoneroOutputWallet() + .setAmount(tx.getOutgoingTransfer().getAmount() + tx.getFee()) + .setAccountIndex(tx.getOutgoingTransfer().getAccountIndex()) + .setSubaddressIndex(tx.getOutgoingTransfer().getSubaddressIndices().length === 1 ? tx.getOutgoingTransfer().getSubaddressIndices()[0] : undefined) // initialize if transfer sourced from single subaddress + .setTx(tx); + tx.setInputs([output]); + await this.wallet.announceOutputSpent(output); + } + + // notify received outputs + if (tx.getIncomingTransfers() !== undefined) { + if (tx.getOutputs() !== undefined && tx.getOutputs().length > 0) { // TODO (monero-project): outputs only returned for confirmed txs + for (let output of tx.getOutputs()) { + await this.wallet.announceOutputReceived(output); + } + } else { // TODO (monero-project): monero-wallet-rpc does not allow scrape of unconfirmed received outputs so using incoming transfer values + let outputs = []; + for (let transfer of tx.getIncomingTransfers()) { + outputs.push(new MoneroOutputWallet() + .setAccountIndex(transfer.getAccountIndex()) + .setSubaddressIndex(transfer.getSubaddressIndex()) + .setAmount(transfer.getAmount()) + .setTx(tx)); + } + tx.setOutputs(outputs); + for (let output of tx.getOutputs()) { + await this.wallet.announceOutputReceived(output); + } + } + } + } + + protected getTx(txs, txHash) { + for (let tx of txs) if (txHash === tx.getHash()) return tx; + return undefined; + } + + protected async checkForChangedBalances() { + let balances = await this.wallet.getBalances(); + if (balances[0] !== this.prevBalances[0] || balances[1] !== this.prevBalances[1]) { + this.prevBalances = balances; + await this.wallet.announceBalancesChanged(balances[0], balances[1]); + return true; + } + return false; + } +} diff --git a/src/main/ts/wallet/model/MoneroAccount.ts b/src/main/ts/wallet/model/MoneroAccount.ts new file mode 100644 index 000000000..04ffd886b --- /dev/null +++ b/src/main/ts/wallet/model/MoneroAccount.ts @@ -0,0 +1,131 @@ +import assert from "assert"; +import GenUtils from "../../common/GenUtils"; +import MoneroSubaddress from "./MoneroSubaddress"; + +/** + * Monero account model. + */ +export default class MoneroAccount { + + index: number; + primaryAddress: string; + balance: bigint; + unlockedBalance: bigint; + label: string; + tag: string; + subaddresses: MoneroSubaddress[]; + + constructor(account?: Partial) { + Object.assign(this, account); + + // deserialize balances + if (this.balance !== undefined && typeof this.balance !== "bigint") this.balance = BigInt(this.balance); + if (this.unlockedBalance !== undefined && typeof this.unlockedBalance !== "bigint") this.unlockedBalance = BigInt(this.unlockedBalance); + + // copy subaddresses + if (this.subaddresses) { + for (let i = 0; i < this.subaddresses.length; i++) { + this.subaddresses[i] = new MoneroSubaddress(this.subaddresses[i]); + } + } + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (json.balance !== undefined) json.balance = json.balance.toString(); + if (json.unlockedBalance !== undefined) json.unlockedBalance = json.unlockedBalance.toString(); + if (json.subaddresses !== undefined) { + for (let i = 0; i < json.subaddresses.length; i++) { + json.subaddresses[i] = json.subaddresses[i].toJson(); + } + } + return json; + } + + getIndex(): number { + return this.index; + } + + setIndex(index: number): MoneroAccount { + this.index = index; + return this; + } + + getPrimaryAddress(): string { + return this.primaryAddress; + } + + setPrimaryAddress(primaryAddress: string): MoneroAccount { + this.primaryAddress = primaryAddress; + return this; + } + + getBalance(): bigint { + return this.balance; + } + + setBalance(balance: bigint): MoneroAccount { + this.balance = balance; + return this; + } + + getUnlockedBalance(): bigint { + return this.unlockedBalance; + } + + setUnlockedBalance(unlockedBalance: bigint): MoneroAccount { + this.unlockedBalance = unlockedBalance; + return this; + } + + getLabel(): string { + return this.label; + } + + setLabel(label: string): MoneroAccount { + this.label = label; + return this; + } + + getTag(): string { + return this.tag; + } + + setTag(tag: string): MoneroAccount { + this.tag = tag; + return this; + } + + getSubaddresses(): MoneroSubaddress[] { + return this.subaddresses; + } + + setSubaddresses(subaddresses: MoneroSubaddress[]): MoneroAccount { + assert(subaddresses === undefined || Array.isArray(subaddresses), "Given subaddresses must be undefined or an array of subaddresses"); + this.subaddresses = subaddresses; + if (subaddresses) { + for (let subaddress of subaddresses) { + subaddress.setAccountIndex(this.index); + } + } + return this; + } + + toString(indent = 0): string { + let str = ""; + str += GenUtils.kvLine("Index", this.getIndex(), indent); + str += GenUtils.kvLine("Primary address", this.getPrimaryAddress(), indent); + str += GenUtils.kvLine("Balance", this.getBalance(), indent); + str += GenUtils.kvLine("Unlocked balance", this.getUnlockedBalance(), indent); + str += GenUtils.kvLine("Label", this.getTag(), indent); + str += GenUtils.kvLine("Tag", this.getTag(), indent); + if (this.getSubaddresses() !== undefined) { + str += GenUtils.kvLine("Subaddresses", "", indent) + for (let i = 0; i < this.getSubaddresses().length; i++) { + str += GenUtils.kvLine(i + 1, "", indent + 1); + str += this.getSubaddresses()[i].toString(indent + 2) + "\n"; + } + } + return str.slice(0, str.length - 1); // strip last newline + } +} diff --git a/src/main/ts/wallet/model/MoneroAccountTag.ts b/src/main/ts/wallet/model/MoneroAccountTag.ts new file mode 100644 index 000000000..7b27d65f0 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroAccountTag.ts @@ -0,0 +1,40 @@ +/** + * Represents an account tag. + */ +export default class MoneroAccountTag { + + tag: string; + label: string; + accountIndices: number[]; + + constructor(accountTag?: Partial) { + Object.assign(this, accountTag); + } + + getTag(): string { + return this.tag; + } + + setTag(tag: string): MoneroAccountTag { + this.tag = tag; + return this; + } + + getLabel(): string { + return this.label; + } + + setLabel(label: string): MoneroAccountTag { + this.label = label; + return this; + } + + getAccountIndices(): number[] { + return this.accountIndices; + } + + setAccountIndices(accountIndices: number[]): MoneroAccountTag { + this.accountIndices = accountIndices; + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroAddressBookEntry.ts b/src/main/ts/wallet/model/MoneroAddressBookEntry.ts new file mode 100644 index 000000000..01c29f9dd --- /dev/null +++ b/src/main/ts/wallet/model/MoneroAddressBookEntry.ts @@ -0,0 +1,54 @@ +/** + * Monero address book entry model + */ +export default class MoneroAddressBookEntry { + + index: number; + address: string; + description: string; + paymentId: string; + + constructor(entry?: Partial) { + Object.assign(this, entry); + } + + toJson(): any { + return Object.assign({}, this); + } + + getIndex(): number { + return this.index; + } + + setIndex(index: number): MoneroAddressBookEntry { + this.index = index; + return this; + } + + getAddress(): string { + return this.address; + } + + setAddress(address: string): MoneroAddressBookEntry { + this.address = address; + return this; + } + + getDescription(): string { + return this.description; + } + + setDescription(description: string): MoneroAddressBookEntry { + this.description = description; + return this; + } + + getPaymentId(): string { + return this.paymentId; + } + + setPaymentId(paymentId: string): MoneroAddressBookEntry { + this.paymentId = paymentId; + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroCheck.ts b/src/main/ts/wallet/model/MoneroCheck.ts new file mode 100644 index 000000000..f43418ca5 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroCheck.ts @@ -0,0 +1,20 @@ +/** + * Base class for results from checking a transaction or reserve proof. + */ +export default class MoneroCheck { + + isGood?: boolean; + + constructor(check?: Partial) { + Object.assign(this, check); + } + + getIsGood(): boolean { + return this.isGood; + } + + setIsGood(isGood: boolean): MoneroCheck { + this.isGood = isGood; + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroCheckReserve.ts b/src/main/ts/wallet/model/MoneroCheckReserve.ts new file mode 100644 index 000000000..b8996c23c --- /dev/null +++ b/src/main/ts/wallet/model/MoneroCheckReserve.ts @@ -0,0 +1,41 @@ +import MoneroCheck from "./MoneroCheck"; + +/** + * Results from checking a reserve proof. + */ +export default class MoneroCheckReserve extends MoneroCheck { + + totalAmount: bigint; + unconfirmedSpentAmount: bigint; + + constructor(check?: Partial) { + super(check); + if (this.totalAmount !== undefined && typeof this.totalAmount !== "bigint") this.totalAmount = BigInt(this.totalAmount); + if (this.unconfirmedSpentAmount !== undefined && typeof this.unconfirmedSpentAmount !== "bigint") this.unconfirmedSpentAmount = BigInt(this.unconfirmedSpentAmount); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (this.getTotalAmount() !== undefined) json.totalAmount = this.getTotalAmount().toString(); + if (this.getUnconfirmedSpentAmount() !== undefined) json.unconfirmedSpentAmount = this.getUnconfirmedSpentAmount().toString(); + return json; + } + + getTotalAmount(): bigint { + return this.totalAmount; + } + + setTotalAmount(totalAmount: bigint): MoneroCheckReserve { + this.totalAmount = totalAmount; + return this; + } + + getUnconfirmedSpentAmount(): bigint { + return this.unconfirmedSpentAmount; + } + + setUnconfirmedSpentAmount(unconfirmedSpentAmount: bigint): MoneroCheckReserve { + this.unconfirmedSpentAmount = unconfirmedSpentAmount; + return this; + } +} \ No newline at end of file diff --git a/src/main/ts/wallet/model/MoneroCheckTx.ts b/src/main/ts/wallet/model/MoneroCheckTx.ts new file mode 100644 index 000000000..22b904f2c --- /dev/null +++ b/src/main/ts/wallet/model/MoneroCheckTx.ts @@ -0,0 +1,49 @@ +import MoneroCheck from "./MoneroCheck"; + +/** + * Results from checking a transaction key. + */ +export default class MoneroCheckTx extends MoneroCheck { + + inTxPool: boolean; + numConfirmations: number; + receivedAmount: bigint; + + constructor(check?: Partial) { + super(check); + if (this.receivedAmount !== undefined && typeof this.receivedAmount !== "bigint") this.receivedAmount = BigInt(this.receivedAmount); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (this.getReceivedAmount() !== undefined) json.receivedAmount = this.getReceivedAmount().toString(); + return json; + } + + getInTxPool(): boolean { + return this.inTxPool; + } + + setInTxPool(inTxPool: boolean): MoneroCheckTx { + this.inTxPool = inTxPool; + return this; + } + + getNumConfirmations(): number { + return this.numConfirmations; + } + + setNumConfirmations(numConfirmations: number): MoneroCheckTx { + this.numConfirmations = numConfirmations; + return this; + } + + getReceivedAmount(): bigint { + return this.receivedAmount; + } + + setReceivedAmount(receivedAmount: bigint): MoneroCheckTx { + this.receivedAmount = receivedAmount; + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroDestination.ts b/src/main/ts/wallet/model/MoneroDestination.ts new file mode 100644 index 000000000..e41e3127a --- /dev/null +++ b/src/main/ts/wallet/model/MoneroDestination.ts @@ -0,0 +1,70 @@ +import GenUtils from "../../common/GenUtils"; +import MoneroError from "../../common/MoneroError"; + +/** + * Models an outgoing transfer destination. + */ +export default class MoneroDestination { + + /** Destination address to send funds to. */ + address: string; + + /** Amount to send to destination address. */ + amount: bigint; + + /** + * Construct a destination to send funds to. + * + * @param {Partial|string} destinationOrAddress is a MoneroDestination or hex string to initialize from (optional) + * @param {bigint} [amount] - the destination amount + */ + constructor(destinationOrAddress?: Partial | string, amount?: bigint) { + if (typeof destinationOrAddress === "string") { + this.setAddress(destinationOrAddress); + this.setAmount(amount); + } else { + if (amount !== undefined) throw new Error("Amount parameter must be undefined when initializing a MoneroDestination from a MoneroDestination") + Object.assign(this, destinationOrAddress); + if (this.amount && typeof this.amount !== "bigint") this.amount = BigInt(this.amount); + } + } + + getAddress(): string { + return this.address; + } + + setAddress(address: string | undefined): MoneroDestination { + this.address = address; + return this; + } + + getAmount(): bigint { + return this.amount; + } + + setAmount(amount: bigint): MoneroDestination { + if (amount !== undefined && typeof amount !== "bigint") { + if (typeof amount === "number") throw new MoneroError("Destination amount must be BigInt or string"); + try { amount = BigInt(amount); } + catch (err) { throw new MoneroError("Invalid destination amount: " + amount); } + } + this.amount = amount; + return this; + } + + copy(): MoneroDestination { + return new MoneroDestination(this); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (this.getAmount() !== undefined) json.amount = this.getAmount().toString(); + return json; + } + + toString(indent = 0): string { + let str = GenUtils.kvLine("Address", this.getAddress(), indent); + str += GenUtils.kvLine("Amount", this.getAmount() ? this.getAmount().toString() : undefined, indent); + return str.slice(0, str.length - 1); // strip last newline + } +} \ No newline at end of file diff --git a/src/main/js/wallet/model/MoneroIncomingTransfer.js b/src/main/ts/wallet/model/MoneroIncomingTransfer.ts similarity index 53% rename from src/main/js/wallet/model/MoneroIncomingTransfer.js rename to src/main/ts/wallet/model/MoneroIncomingTransfer.ts index 8516f3131..463be73ba 100644 --- a/src/main/js/wallet/model/MoneroIncomingTransfer.js +++ b/src/main/ts/wallet/model/MoneroIncomingTransfer.ts @@ -1,42 +1,45 @@ -const assert = require("assert"); -const GenUtils = require("../../common/GenUtils"); -const MoneroTransfer = require("./MoneroTransfer"); +import assert from "assert"; +import GenUtils from "../../common/GenUtils"; +import MoneroTransfer from "./MoneroTransfer"; +import MoneroTxWallet from "./MoneroTxWallet"; /** * Models an incoming transfer of funds to the wallet. - * - * @extends {MoneroTransfer} */ -class MoneroIncomingTransfer extends MoneroTransfer { +export default class MoneroIncomingTransfer extends MoneroTransfer { + + subaddressIndex: number; + address: string; + numSuggestedConfirmations: number; /** - * Construct the model. + * Construct the transfer. * - * @param {MoneroTransfer|object} state is existing state to initialize from (optional) + * @param {MoneroTransfer} [transfer] is existing state to initialize from (optional) */ - constructor(state) { - super(state); + constructor(transfer?: Partial) { + super(transfer); } - isIncoming() { + getIsIncoming(): boolean { return true; } - getSubaddressIndex() { - return this.state.subaddressIndex; + getSubaddressIndex(): number { + return this.subaddressIndex; } - setSubaddressIndex(subaddressIndex) { - this.state.subaddressIndex = subaddressIndex; + setSubaddressIndex(subaddressIndex: number): MoneroIncomingTransfer { + this.subaddressIndex = subaddressIndex; return this; } - getAddress() { - return this.state.address; + getAddress(): string { + return this.address; } - setAddress(address) { - this.state.address = address; + setAddress(address: string): MoneroIncomingTransfer { + this.address = address; return this; } @@ -48,16 +51,16 @@ class MoneroIncomingTransfer extends MoneroTransfer { * * @return {number} is the number of confirmations before it's not worth rewriting the chain */ - getNumSuggestedConfirmations() { - return this.state.numSuggestedConfirmations; + getNumSuggestedConfirmations(): number { + return this.numSuggestedConfirmations; } - setNumSuggestedConfirmations(numSuggestedConfirmations) { - this.state.numSuggestedConfirmations = numSuggestedConfirmations; + setNumSuggestedConfirmations(numSuggestedConfirmations: number): MoneroIncomingTransfer { + this.numSuggestedConfirmations = numSuggestedConfirmations; return this; } - copy() { + copy(): MoneroIncomingTransfer { return new MoneroIncomingTransfer(this.toJson()); } @@ -69,8 +72,9 @@ class MoneroIncomingTransfer extends MoneroTransfer { * should not be re-used or it should be copied before calling this method. * * @param {MoneroIncomingTransfer} transfer is the transfer to merge into this one + * @return {MoneroIncomingTransfer} */ - merge(transfer) { + merge(transfer: MoneroIncomingTransfer): MoneroIncomingTransfer { super.merge(transfer); assert(transfer instanceof MoneroIncomingTransfer); if (this === transfer) return this; @@ -80,17 +84,28 @@ class MoneroIncomingTransfer extends MoneroTransfer { return this; } - toString() { - return this.toString(0); - } - - toString(indent) { + toString(indent = 0) { let str = super.toString(indent) + "\n"; str += GenUtils.kvLine("Subaddress index", this.getSubaddressIndex(), indent); str += GenUtils.kvLine("Address", this.getAddress(), indent); str += GenUtils.kvLine("Num suggested confirmations", this.getNumSuggestedConfirmations(), indent); return str.slice(0, str.length - 1); // strip last newline } -} -module.exports = MoneroIncomingTransfer; \ No newline at end of file + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setTx(tx: MoneroTxWallet): MoneroIncomingTransfer { + super.setTx(tx); + return this; + } + + setAmount(amount: bigint): MoneroIncomingTransfer { + super.setAmount(amount); + return this; + } + + setAccountIndex(accountIndex: number): MoneroIncomingTransfer { + super.setAccountIndex(accountIndex); + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroIntegratedAddress.ts b/src/main/ts/wallet/model/MoneroIntegratedAddress.ts new file mode 100644 index 000000000..7481916a0 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroIntegratedAddress.ts @@ -0,0 +1,48 @@ +/** + * Monero integrated address model. + */ +export default class MoneroIntegratedAddress { + + standardAddress: string; + paymentId: string; + integratedAddress: string; + + constructor(integratedAddress?: Partial) { + Object.assign(this, integratedAddress); + } + + toJson(): any { + return Object.assign({}, this); + } + + getStandardAddress(): string { + return this.standardAddress; + } + + setStandardAddress(standardAddress: string): MoneroIntegratedAddress { + this.standardAddress = standardAddress; + return this; + } + + getPaymentId(): string { + return this.paymentId; + } + + setPaymentId(paymentId: string): MoneroIntegratedAddress { + this.paymentId = paymentId; + return this; + } + + getIntegratedAddress(): string { + return this.integratedAddress; + } + + setIntegratedAddress(integratedAddress: string): MoneroIntegratedAddress { + this.integratedAddress = integratedAddress; + return this; + } + + toString(): string { + return this.integratedAddress; + } +} diff --git a/src/main/ts/wallet/model/MoneroKeyImageImportResult.ts b/src/main/ts/wallet/model/MoneroKeyImageImportResult.ts new file mode 100644 index 000000000..5bd07f23c --- /dev/null +++ b/src/main/ts/wallet/model/MoneroKeyImageImportResult.ts @@ -0,0 +1,49 @@ +/** + * Models results from importing key images. + */ +export default class MoneroKeyImageImportResult { + + height: number; + spentAmount: bigint; + unspentAmount: bigint; + + constructor(result?: Partial) { + Object.assign(this, result); + if (this.spentAmount !== undefined && typeof this.spentAmount !== "bigint") this.spentAmount = BigInt(this.spentAmount); + if (this.unspentAmount !== undefined && typeof this.unspentAmount !== "bigint") this.unspentAmount = BigInt(this.unspentAmount); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (this.getSpentAmount() !== undefined) json.spentAmount = this.getSpentAmount().toString(); + if (this.getUnspentAmount() !== undefined) json.unspentAmount = this.getUnspentAmount().toString(); + return json; + } + + getHeight(): number { + return this.height; + } + + setHeight(height: number): MoneroKeyImageImportResult { + this.height = height; + return this; + } + + getSpentAmount(): bigint { + return this.spentAmount; + } + + setSpentAmount(spentAmount: bigint): MoneroKeyImageImportResult { + this.spentAmount = spentAmount; + return this; + } + + getUnspentAmount(): bigint { + return this.unspentAmount; + } + + setUnspentAmount(unspentAmount: bigint): MoneroKeyImageImportResult { + this.unspentAmount = unspentAmount; + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroMessageSignatureResult.ts b/src/main/ts/wallet/model/MoneroMessageSignatureResult.ts new file mode 100644 index 000000000..36b32a755 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroMessageSignatureResult.ts @@ -0,0 +1,57 @@ +import MoneroMessageSignatureType from "./MoneroMessageSignatureType"; + +/** + * Message signature verification result. + */ +export default class MoneroMessageSignatureResult { + + isGood: boolean; + isOld: boolean; + signatureType: MoneroMessageSignatureType; + version: number; + + constructor(result?: Partial) { + Object.assign(this, result); + } + + toJson(): any { + return Object.assign({}, this); + } + + getIsGood(): boolean { + return this.isGood; + } + + setIsGood(isGood: boolean): MoneroMessageSignatureResult { + this.isGood = isGood; + return this; + } + + getIsOld(): boolean { + return this.isOld; + } + + setIsOld(isOld: boolean): MoneroMessageSignatureResult { + this.isOld = isOld; + return this; + } + + getSignatureType(): MoneroMessageSignatureType { + return this.signatureType; + } + + setSignatureType(signatureType: MoneroMessageSignatureType): MoneroMessageSignatureResult { + this.signatureType = signatureType; + return this; + } + + getVersion(): number { + return this.version; + } + + setVersion(version: number): MoneroMessageSignatureResult { + this.version = version; + return this; + } + +} \ No newline at end of file diff --git a/src/main/ts/wallet/model/MoneroMessageSignatureType.ts b/src/main/ts/wallet/model/MoneroMessageSignatureType.ts new file mode 100644 index 000000000..eca670804 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroMessageSignatureType.ts @@ -0,0 +1,17 @@ +/** + * Enumerate message signature types. + */ +enum MoneroMessageSignatureType { + + /** + * Sign with spend key (value=0). + */ + SIGN_WITH_SPEND_KEY = 0, + + /** + * Sign with the view key (value=1). + */ + SIGN_WITH_VIEW_KEY = 1 +} + +export default MoneroMessageSignatureType; \ No newline at end of file diff --git a/src/main/ts/wallet/model/MoneroMultisigInfo.ts b/src/main/ts/wallet/model/MoneroMultisigInfo.ts new file mode 100644 index 000000000..4446e0f00 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroMultisigInfo.ts @@ -0,0 +1,54 @@ +/** + * Models information about a multisig wallet. + */ +export default class MoneroMultisigInfo { + + isMultisig: boolean; + isReady: boolean; + threshold: number; + numParticipants: number; + + constructor(multisigInfo?: Partial) { + Object.assign(this, multisigInfo); + } + + toJson(): any { + return Object.assign({}, this); + } + + getIsMultisig(): boolean { + return this.isMultisig; + } + + setIsMultisig(isMultisig: boolean): MoneroMultisigInfo { + this.isMultisig = isMultisig; + return this; + } + + getIsReady(): boolean { + return this.isReady; + } + + setIsReady(isReady: boolean): MoneroMultisigInfo { + this.isReady = isReady; + return this; + } + + getThreshold(): number { + return this.threshold; + } + + setThreshold(threshold: number): MoneroMultisigInfo { + this.threshold = threshold; + return this; + } + + getNumParticipants(): number { + return this.numParticipants; + } + + setNumParticipants(numParticipants: number): MoneroMultisigInfo { + this.numParticipants = numParticipants; + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroMultisigInitResult.ts b/src/main/ts/wallet/model/MoneroMultisigInitResult.ts new file mode 100644 index 000000000..c7f2b01dd --- /dev/null +++ b/src/main/ts/wallet/model/MoneroMultisigInitResult.ts @@ -0,0 +1,36 @@ +/** + * Models the result of initializing a multisig wallet which results in the + * multisig wallet's address xor another multisig hex to share with + * participants to create the wallet. + */ +export default class MoneroMultisigInitResult { + + address: string; + multisigHex: string; + + constructor(result?: Partial) { + Object.assign(this, result); + } + + toJson(): any { + return Object.assign({}, this); + } + + getAddress(): string { + return this.address; + } + + setAddress(address: string): MoneroMultisigInitResult { + this.address = address; + return this; + } + + getMultisigHex(): string { + return this.multisigHex; + } + + setMultisigHex(multisigHex: string): MoneroMultisigInitResult { + this.multisigHex = multisigHex; + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroMultisigSignResult.ts b/src/main/ts/wallet/model/MoneroMultisigSignResult.ts new file mode 100644 index 000000000..a1c17fc78 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroMultisigSignResult.ts @@ -0,0 +1,34 @@ +/** + * Models the result of signing multisig tx hex. + */ +export default class MoneroMultisigSignResult { + + signedMultisigTxHex: string; + txHashes: string[]; + + constructor(result?: Partial) { + Object.assign(this, result); + } + + toJson(): any { + return Object.assign({}, this); + } + + getSignedMultisigTxHex(): string { + return this.signedMultisigTxHex; + } + + setSignedMultisigTxHex(signedTxMultisigHex: string): MoneroMultisigSignResult { + this.signedMultisigTxHex = signedTxMultisigHex; + return this; + } + + getTxHashes(): string[] { + return this.txHashes; + } + + setTxHashes(txHashes: string[]): MoneroMultisigSignResult { + this.txHashes = txHashes; + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroOutgoingTransfer.ts b/src/main/ts/wallet/model/MoneroOutgoingTransfer.ts new file mode 100644 index 000000000..b111c1fa2 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroOutgoingTransfer.ts @@ -0,0 +1,127 @@ +import assert from "assert"; +import GenUtils from "../../common/GenUtils"; +import MoneroDestination from "./MoneroDestination"; +import MoneroTransfer from "./MoneroTransfer"; +import MoneroTxWallet from "./MoneroTxWallet"; + +/** + * Models an outgoing transfer of funds from the wallet. + */ +export default class MoneroOutgoingTransfer extends MoneroTransfer { + + subaddressIndices: number[]; + addresses: string[]; + destinations: MoneroDestination[]; + + /** + * Construct the model. + * + * @param {MoneroOutgoingTranser [transfer] existing state to initialize from (optional) + */ + constructor(transfer?: Partial) { + super(transfer); + + // copy destinations + if (this.destinations) { + this.destinations = this.destinations.slice(); + for (let i = 0; i < this.destinations.length; i++) { + this.destinations[i] = new MoneroDestination(this.destinations[i]); + } + } + } + + getIsIncoming(): boolean { + return false; + } + + getSubaddressIndices(): number[] { + return this.subaddressIndices; + } + + setSubaddressIndices(subaddressIndices: number[]): MoneroOutgoingTransfer { + this.subaddressIndices = subaddressIndices; + return this; + } + + getAddresses(): string[] { + return this.addresses; + } + + setAddresses(addresses: string[]): MoneroOutgoingTransfer { + this.addresses = addresses; + return this; + } + + getDestinations(): MoneroDestination[] { + return this.destinations; + } + + setDestinations(destinations: MoneroDestination[]): MoneroOutgoingTransfer { + this.destinations = destinations; + return this; + } + + copy(): MoneroOutgoingTransfer { + return new MoneroOutgoingTransfer(this); + } + + toJson(): any { + let json = Object.assign({}, this, super.toJson()); // merge json onto inherited state + if (this.getDestinations() !== undefined) { + json.destinations = []; + for (let destination of this.getDestinations()) json.destinations.push(destination.toJson()); + } + delete json.tx; // parent tx is not serialized + return json; + } + + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * Merging can modify or build references to the transfer given so it + * should not be re-used or it should be copied before calling this method. + * + * @param transfer is the transfer to merge into this one + */ + merge(transfer: MoneroOutgoingTransfer): MoneroOutgoingTransfer { + super.merge(transfer); + assert(transfer instanceof MoneroOutgoingTransfer); + if (this === transfer) return this; + this.setSubaddressIndices(GenUtils.reconcile(this.getSubaddressIndices(), transfer.getSubaddressIndices())); + this.setAddresses(GenUtils.reconcile(this.getAddresses(), transfer.getAddresses())); + this.setDestinations(GenUtils.reconcile(this.getDestinations(), transfer.getDestinations())); + return this; + } + + toString(indent = 0): string { + let str = super.toString(indent) + "\n"; + str += GenUtils.kvLine("Subaddress indices", this.getSubaddressIndices(), indent); + str += GenUtils.kvLine("Addresses", this.getAddresses(), indent); + if (this.getDestinations() !== undefined) { + str += GenUtils.kvLine("Destinations", "", indent); + for (let i = 0; i < this.getDestinations().length; i++) { + str += GenUtils.kvLine(i + 1, "", indent + 1); + str += this.getDestinations()[i].toString(indent + 2) + "\n"; + } + } + return str.slice(0, str.length - 1); // strip last newline + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setTx(tx: MoneroTxWallet): MoneroOutgoingTransfer { + super.setTx(tx); + return this; + } + + setAmount(amount: bigint): MoneroOutgoingTransfer { + super.setAmount(amount); + return this; + } + + setAccountIndex(accountIndex: number): MoneroOutgoingTransfer { + super.setAccountIndex(accountIndex); + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroOutputQuery.ts b/src/main/ts/wallet/model/MoneroOutputQuery.ts new file mode 100644 index 000000000..db526133e --- /dev/null +++ b/src/main/ts/wallet/model/MoneroOutputQuery.ts @@ -0,0 +1,189 @@ +import MoneroError from "../../common/MoneroError"; +import MoneroKeyImage from "../../daemon/model/MoneroKeyImage"; +import MoneroOutputWallet from "./MoneroOutputWallet"; +import MoneroTx from "../../daemon/model/MoneroTx"; +import MoneroTxWallet from "./MoneroTxWallet"; +import MoneroTxQuery from "./MoneroTxQuery"; + +/** + * Configuration to query wallet outputs. + */ +export default class MoneroOutputQuery extends MoneroOutputWallet { + + minAmount: bigint; + maxAmount: bigint; + txQuery: Partial; + subaddressIndices: number[]; + + /** + *

Construct the output query.

+ * + *

Example:

+ * + * + * // get available outputs in account 0 with a minimum amount
+ * let outputs = await wallet.getOutputs({
+ *    isSpent: false,
+ *    isLocked: false,
+ *    accountIndex: 0,
+ *    minAmount: 750000n
+ * }); + *
+ * + *

All configuration is optional. All outputs are returned except those that don't meet criteria defined in this query.

+ * + * @param {MoneroOutputQuery} [config] - output query configuration (optional) + * @param {number} config.accountIndex - get outputs in this account index + * @param {number} config.subaddressIndex - get outputs in this subaddress index + * @param {number[]} config.subaddressIndices - get outputs in these subaddress indices + * @param {bigint} config.amount - get outputs with this amount + * @param {bigint} config.minAmount - get outputs with amount greater than or equal to this amount + * @param {bigint} config.maxAmount - get outputs with amount less than or equal to this amount + * @param {boolean} config.isSpent - get spent xor unspent outputs + * @param {boolean} config.isFrozen - get frozen xor thawed outputs + * @param {MoneroKeyImage} config.keyImage - get outputs with a key image matching fields defined in this key image + * @param {string} config.keyImage.hex - get outputs with this key image hex + * @param {string} config.keyImage.signature - get outputs with this key image signature + * @param {MoneroTxQuery} config.txQuery - get outputs whose tx match this tx query + */ + constructor(query?: Partial) { + super(query); + if (this.minAmount !== undefined && typeof this.minAmount !== "bigint") this.minAmount = BigInt(this.minAmount); + if (this.maxAmount !== undefined && typeof this.maxAmount !== "bigint") this.maxAmount = BigInt(this.maxAmount); + if (this.txQuery && !(this.txQuery instanceof MoneroTxQuery)) this.txQuery = new MoneroTxQuery(this.txQuery); + if (this.txQuery) this.txQuery.setOutputQuery(this); + if (this.isLocked !== undefined) throw new MoneroError("isLocked must be part of tx query, not output query"); + } + + copy(): MoneroOutputQuery { + return new MoneroOutputQuery(this); + } + + toJson(): any { + let json = Object.assign({}, this, super.toJson()); + if (this.getMinAmount() !== undefined) json.minAmount = this.getMinAmount().toString(); + if (this.getMaxAmount() !== undefined) json.maxAmount = this.getMaxAmount().toString(); + delete json.txQuery; + return json; + } + + getMinAmount(): bigint { + return this.minAmount; + } + + setMinAmount(minAmount: bigint): MoneroOutputQuery { + this.minAmount = minAmount; + return this; + } + + getMaxAmount(): bigint { + return this.maxAmount; + } + + setMaxAmount(maxAmount: bigint): MoneroOutputQuery { + this.maxAmount = maxAmount; + return this; + } + + getTxQuery(): MoneroTxQuery { + return this.txQuery as MoneroTxQuery; + } + + setTxQuery(txQuery: MoneroTxQuery): MoneroOutputQuery { + this.txQuery = txQuery === undefined ? undefined : txQuery instanceof MoneroTxQuery ? txQuery : new MoneroTxQuery(txQuery); + if (txQuery) this.txQuery.outputQuery = this; + return this; + } + + getSubaddressIndices(): number[] { + return this.subaddressIndices; + } + + setSubaddressIndices(subaddressIndices: number[]): MoneroOutputQuery { + this.subaddressIndices = subaddressIndices; + return this; + } + + meetsCriteria(output: MoneroOutputWallet, queryParent = true): boolean { + if (!(output instanceof MoneroOutputWallet)) throw new Error("Output not given to MoneroOutputQuery.meetsCriteria(output)"); + + // filter on output + if (this.getAccountIndex() !== undefined && this.getAccountIndex() !== output.getAccountIndex()) return false; + if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() !== output.getSubaddressIndex()) return false; + if (this.getAmount() !== undefined && this.getAmount() !== output.getAmount()) return false; + if (this.getIsSpent() !== undefined && this.getIsSpent() !== output.getIsSpent()) return false; + if (this.getIsFrozen() !== undefined && this.getIsFrozen() !== output.getIsFrozen()) return false; + + // filter on output's key image + if (this.getKeyImage() !== undefined) { + if (output.getKeyImage() === undefined) return false; + if (this.getKeyImage().getHex() !== undefined && this.getKeyImage().getHex() !== output.getKeyImage().getHex()) return false; + if (this.getKeyImage().getSignature() !== undefined && this.getKeyImage().getSignature() !== output.getKeyImage().getSignature()) return false; + } + + // filter on extensions + if (this.getSubaddressIndices() !== undefined && !this.getSubaddressIndices().includes(output.getSubaddressIndex())) return false; + + // filter with tx query + if (this.getTxQuery() && !this.getTxQuery().meetsCriteria(output.getTx() as MoneroTxWallet, false)) return false; + + // filter on remaining fields + if (this.getMinAmount() !== undefined && (output.getAmount() === undefined || output.getAmount() < this.getMinAmount())) return false; + if (this.getMaxAmount() !== undefined && (output.getAmount() === undefined || output.getAmount() > this.getMaxAmount())) return false; + + // output meets query + return true; + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setTx(tx: MoneroTx): MoneroOutputQuery { + super.setTx(tx); + return this; + } + + setAccountIndex(accountIndex: number): MoneroOutputQuery { + super.setAccountIndex(accountIndex); + return this; + } + + setSubaddressIndex(subaddressIndex: number): MoneroOutputQuery { + super.setSubaddressIndex(subaddressIndex); + return this; + } + + setIsSpent(isSpent: boolean): MoneroOutputQuery { + super.setIsSpent(isSpent); + return this; + } + + setIsFrozen(isFrozen: boolean): MoneroOutputQuery { + super.setIsFrozen(isFrozen); + return this; + } + + setKeyImage(keyImage: MoneroKeyImage): MoneroOutputQuery { + super.setKeyImage(keyImage); + return this; + } + + setAmount(amount: bigint): MoneroOutputQuery { + super.setAmount(amount); + return this; + } + + setIndex(index: number): MoneroOutputQuery { + super.setIndex(index); + return this; + } + + setRingOutputIndices(ringOutputIndices: number[]): MoneroOutputQuery { + super.setRingOutputIndices(ringOutputIndices); + return this; + } + + setStealthPublicKey(stealthPublicKey: string): MoneroOutputQuery { + super.setStealthPublicKey(stealthPublicKey); + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroOutputWallet.ts b/src/main/ts/wallet/model/MoneroOutputWallet.ts new file mode 100644 index 000000000..ff8590f46 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroOutputWallet.ts @@ -0,0 +1,151 @@ +import assert from "assert"; +import GenUtils from "../../common/GenUtils"; +import MoneroError from "../../common/MoneroError"; +import MoneroKeyImage from "../../daemon/model/MoneroKeyImage"; +import MoneroOutput from "../../daemon/model/MoneroOutput"; +import MoneroTx from "../../daemon/model/MoneroTx"; +import MoneroTxWallet from "./MoneroTxWallet"; + +/** + * Models a Monero output with wallet extensions. + */ +export default class MoneroOutputWallet extends MoneroOutput { + + accountIndex: number; + subaddressIndex: number; + isSpent: boolean; + isFrozen: boolean; + isLocked: boolean; + + /** + * Construct the model. + * + * @param {MoneroOutputWallet} [output] is existing state to initialize from (optional) + */ + constructor(output?: Partial) { + super(output); + } + + getTx(): MoneroTxWallet { + return super.getTx() as MoneroTxWallet; + } + + setTx(tx: MoneroTx): MoneroOutputWallet { + if (tx !== undefined && !(tx instanceof MoneroTxWallet)) throw new MoneroError("Wallet output's transaction must be of type MoneroTxWallet"); + super.setTx(tx); + return this; + } + + getAccountIndex(): number { + return this.accountIndex; + } + + setAccountIndex(accountIndex: number): MoneroOutputWallet { + this.accountIndex = accountIndex; + return this; + } + + getSubaddressIndex(): number { + return this.subaddressIndex; + } + + setSubaddressIndex(subaddressIndex: number): MoneroOutputWallet { + this.subaddressIndex = subaddressIndex; + return this; + } + + getIsSpent(): boolean { + return this.isSpent; + } + + setIsSpent(isSpent: boolean): MoneroOutputWallet { + this.isSpent = isSpent; + return this; + } + + /** + * Indicates if this output has been deemed 'malicious' and will therefore + * not be spent by the wallet. + * + * @return Boolean is whether or not this output is frozen + */ + getIsFrozen(): boolean { + return this.isFrozen; + } + + setIsFrozen(isFrozen: boolean): MoneroOutputWallet { + this.isFrozen = isFrozen; + return this; + } + + getIsLocked(): boolean { + if (this.getTx() === undefined) return undefined; + return (this.getTx() as MoneroTxWallet).getIsLocked(); + } + + copy(): MoneroOutputWallet { + return new MoneroOutputWallet(this.toJson()); + } + + toJson(): any { + let json: any = Object.assign({}, this, super.toJson()); + delete json.tx; + return json; + } + + /** + * Updates this output by merging the latest information from the given + * output. + * + * Merging can modify or build references to the output given so it + * should not be re-used or it should be copied before calling this method. + * + * @param output is the output to merge into this one + */ + merge(output: MoneroOutputWallet): MoneroOutputWallet { + assert(output instanceof MoneroOutputWallet); + if (this === output) return; + super.merge(output); + this.setAccountIndex(GenUtils.reconcile(this.getAccountIndex(), output.getAccountIndex())); + this.setSubaddressIndex(GenUtils.reconcile(this.getSubaddressIndex(), output.getSubaddressIndex())); + this.setIsSpent(GenUtils.reconcile(this.getIsSpent(), output.getIsSpent(), {resolveTrue: true})); // output can become spent + this.setIsFrozen(GenUtils.reconcile(this.getIsFrozen(), output.getIsFrozen())); + return this; + } + + toString(indent = 0): string { + let str = super.toString(indent) + "\n" + str += GenUtils.kvLine("Account index", this.getAccountIndex(), indent); + str += GenUtils.kvLine("Subaddress index", this.getSubaddressIndex(), indent); + str += GenUtils.kvLine("Is spent", this.getIsSpent(), indent); + str += GenUtils.kvLine("Is frozen", this.getIsFrozen(), indent); + return str.slice(0, str.length - 1); // strip last newline + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setKeyImage(keyImage: MoneroKeyImage): MoneroOutputWallet { + super.setKeyImage(keyImage); + return this; + } + + setAmount(amount: bigint): MoneroOutputWallet { + super.setAmount(amount); + return this; + } + + setIndex(index: number): MoneroOutputWallet { + super.setIndex(index); + return this; + } + + setRingOutputIndices(ringOutputIndices: number[]): MoneroOutputWallet { + super.setRingOutputIndices(ringOutputIndices); + return this; + } + + setStealthPublicKey(stealthPublicKey: string): MoneroOutputWallet { + super.setStealthPublicKey(stealthPublicKey); + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroSubaddress.ts b/src/main/ts/wallet/model/MoneroSubaddress.ts new file mode 100644 index 000000000..883512fb9 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroSubaddress.ts @@ -0,0 +1,125 @@ +import GenUtils from "../../common/GenUtils"; + +/** + * Monero subaddress model. + */ +export default class MoneroSubaddress { + + accountIndex: number; + index: number; + address: string; + label: string; + balance: bigint; + unlockedBalance: bigint; + numUnspentOutputs: number; + isUsed: boolean; + numBlocksToUnlock: number; + + constructor(subaddress?: Partial) { + Object.assign(this, subaddress); + if (this.balance !== undefined && typeof this.balance !== "bigint") this.balance = BigInt(this.balance); + if (this.unlockedBalance !== undefined && typeof this.unlockedBalance !== "bigint") this.unlockedBalance = BigInt(this.unlockedBalance); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (json.balance !== undefined) json.balance = json.balance.toString(); + if (json.unlockedBalance !== undefined) json.unlockedBalance = json.unlockedBalance.toString(); + return json; + } + + getAccountIndex(): number { + return this.accountIndex; + } + + setAccountIndex(accountIndex: number): MoneroSubaddress { + this.accountIndex = accountIndex; + return this; + } + + getIndex(): number { + return this.index; + } + + setIndex(index: number): MoneroSubaddress { + this.index = index; + return this; + } + + getAddress(): string { + return this.address; + } + + setAddress(address: string): MoneroSubaddress { + this.address = address; + return this; + } + + getLabel(): string { + return this.label; + } + + setLabel(label: string): MoneroSubaddress { + this.label = label; + return this; + } + + getBalance(): bigint { + return this.balance; + } + + setBalance(balance: bigint): MoneroSubaddress { + this.balance = balance; + return this; + } + + getUnlockedBalance(): bigint { + return this.unlockedBalance; + } + + setUnlockedBalance(unlockedBalance: bigint): MoneroSubaddress { + this.unlockedBalance = unlockedBalance; + return this; + } + + getNumUnspentOutputs(): number { + return this.numUnspentOutputs; + } + + setNumUnspentOutputs(numUnspentOutputs: number): MoneroSubaddress { + this.numUnspentOutputs = numUnspentOutputs; + return this; + } + + getIsUsed(): boolean { + return this.isUsed; + } + + setIsUsed(isUsed: boolean): MoneroSubaddress { + this.isUsed = isUsed; + return this; + } + + getNumBlocksToUnlock(): number { + return this.numBlocksToUnlock; + } + + setNumBlocksToUnlock(numBlocksToUnlock: number): MoneroSubaddress { + this.numBlocksToUnlock = numBlocksToUnlock; + return this; + } + + toString(indent = 0): string { + let str = ""; + str += GenUtils.kvLine("Account index", this.getAccountIndex(), indent); + str += GenUtils.kvLine("Subaddress index", this.getIndex(), indent); + str += GenUtils.kvLine("Address", this.getAddress(), indent); + str += GenUtils.kvLine("Label", this.getLabel(), indent); + str += GenUtils.kvLine("Balance", this.getBalance(), indent); + str += GenUtils.kvLine("Unlocked balance", this.getUnlockedBalance(), indent); + str += GenUtils.kvLine("Num unspent outputs", this.getNumUnspentOutputs(), indent); + str += GenUtils.kvLine("Is used", this.getIsUsed(), indent); + str += GenUtils.kvLine("Num blocks to unlock", this.getNumBlocksToUnlock(), indent); + return str.slice(0, str.length - 1); // strip last newline + } +} diff --git a/src/main/js/wallet/model/MoneroSyncResult.js b/src/main/ts/wallet/model/MoneroSyncResult.ts similarity index 50% rename from src/main/js/wallet/model/MoneroSyncResult.js rename to src/main/ts/wallet/model/MoneroSyncResult.ts index c9c52edf3..72dfcec33 100644 --- a/src/main/js/wallet/model/MoneroSyncResult.js +++ b/src/main/ts/wallet/model/MoneroSyncResult.ts @@ -1,30 +1,31 @@ /** * Result from syncing a Monero wallet. */ -class MoneroSyncResult { +export default class MoneroSyncResult { + + numBlocksFetched: number; + receivedMoney: bigint; - constructor(numBlocksFetched, receivedMoney) { + constructor(numBlocksFetched: number, receivedMoney: bigint) { this.setNumBlocksFetched(numBlocksFetched); this.setReceivedMoney(receivedMoney); } - getNumBlocksFetched() { + getNumBlocksFetched(): number { return this.numBlocksFetched; } - setNumBlocksFetched(numBlocksFetched) { + setNumBlocksFetched(numBlocksFetched: number): MoneroSyncResult { this.numBlocksFetched = numBlocksFetched; return this; } - getReceivedMoney() { + getReceivedMoney(): bigint { return this.receivedMoney; } - setReceivedMoney(receivedMoney) { + setReceivedMoney(receivedMoney: bigint): MoneroSyncResult { this.receivedMoney = receivedMoney; return this; } } - -module.exports = MoneroSyncResult; \ No newline at end of file diff --git a/src/main/ts/wallet/model/MoneroTransfer.ts b/src/main/ts/wallet/model/MoneroTransfer.ts new file mode 100644 index 000000000..81e18f5ec --- /dev/null +++ b/src/main/ts/wallet/model/MoneroTransfer.ts @@ -0,0 +1,119 @@ +import assert from "assert"; +import GenUtils from "../../common/GenUtils"; +import MoneroError from "../../common/MoneroError"; +import MoneroTxWallet from "./MoneroTxWallet"; + +/** + * Models a base transfer of funds to or from the wallet. + */ +export default class MoneroTransfer { + + tx: MoneroTxWallet; + accountIndex: number; + amount: bigint; + + /** + * Construct the transfer. + * + * @param {Partial} transfer existing state to initialize from (optional) + */ + constructor(transfer: Partial) { + Object.assign(this, transfer); + if (this.amount !== undefined && typeof this.amount !== "bigint") this.amount = BigInt(this.amount); + this.validate(); + } + + copy(): MoneroTransfer { + return new MoneroTransfer(this); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (this.getAmount() !== undefined) json.amount = this.getAmount().toString() + delete json.tx; // parent tx is not serialized + return json; + } + + getTx(): MoneroTxWallet { + return this.tx; + } + + setTx(tx: MoneroTxWallet): MoneroTransfer { + this.tx = tx; + return this; + } + + getIsOutgoing(): boolean { + let isIncoming = this.getIsIncoming(); + assert(typeof isIncoming === "boolean"); + return !isIncoming; + } + + getIsIncoming(): boolean { + throw new Error("Subclass must implement"); + } + + getAccountIndex(): number { + return this.accountIndex; + } + + setAccountIndex(accountIndex: number): MoneroTransfer { + this.accountIndex = accountIndex; + this.validate(); + return this; + } + + getAmount(): bigint { + return this.amount; + } + + setAmount(amount: bigint): MoneroTransfer { + this.amount = amount; + return this; + } + + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * Merging can modify or build references to the transfer given so it + * should not be re-used or it should be copied before calling this method. + * + * @param transfer is the transfer to merge into this one + * @return {MoneroTransfer} the merged transfer + */ + merge(transfer: MoneroTransfer): MoneroTransfer { + assert(transfer instanceof MoneroTransfer); + if (this === transfer) return this; + + // merge transactions if they're different which comes back to merging transfers + if (this.getTx() !== transfer.getTx()) { + this.getTx().merge(transfer.getTx()); + return this; + } + + // otherwise merge transfer fields + this.setAccountIndex(GenUtils.reconcile(this.getAccountIndex(), transfer.getAccountIndex())); + + // TODO monero-project: failed tx in pool (after testUpdateLockedDifferentAccounts()) causes non-originating saved wallets to return duplicate incoming transfers but one has amount of 0 + if (this.getAmount() !== undefined && transfer.getAmount() !== undefined && this.getAmount() !== transfer.getAmount() && (this.getAmount() === 0n || transfer.getAmount() === 0n)) { + console.warn("monero-project returning transfers with 0 amount/numSuggestedConfirmations"); + } else { + this.setAmount(GenUtils.reconcile(this.getAmount(), transfer.getAmount())); + } + + return this; + } + + toString(indent = 0): string { + let str = ""; + str += GenUtils.kvLine("Is incoming", this.getIsIncoming(), indent); + str += GenUtils.kvLine("Account index", this.getAccountIndex(), indent); + str += GenUtils.kvLine("Amount", this.getAmount() ? this.getAmount().toString() : undefined, indent); + return str === "" ? str : str.slice(0, str.length - 1); // strip last newline + } + + protected validate() { + if (this.getAccountIndex() !== undefined && this.getAccountIndex() < 0) throw new MoneroError("Account index must be >= 0"); + } +} diff --git a/src/main/ts/wallet/model/MoneroTransferQuery.ts b/src/main/ts/wallet/model/MoneroTransferQuery.ts new file mode 100644 index 000000000..2b3b7dd29 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroTransferQuery.ts @@ -0,0 +1,241 @@ +import GenUtils from "../../common/GenUtils"; +import MoneroDestination from "./MoneroDestination"; +import MoneroIncomingTransfer from "./MoneroIncomingTransfer"; +import MoneroOutgoingTransfer from "./MoneroOutgoingTransfer"; +import MoneroTransfer from "./MoneroTransfer"; +import MoneroTxWallet from "./MoneroTxWallet"; +import MoneroTxQuery from "./MoneroTxQuery"; +import MoneroError from "../../common/MoneroError"; + +/** + * Configuration to query wallet transfers. + */ +export default class MoneroTransferQuery extends MoneroTransfer { + + txQuery: Partial; + isIncoming: boolean; + address: string; + addresses: string[]; + subaddressIndex: number; + subaddressIndices: number[]; + destinations: MoneroDestination[]; + hasDestinations: boolean; + + /** + *

Construct the transfer query.

+ * + *

Example:

+ * + * + * // get incoming transfers to account 0, subaddress 1
+ * let transfers = await wallet.getTransfers({
+ *    accountIndex: 0,
+ *    subaddressIndex: 0
+ * }); + *
+ * + *

All configuration is optional. All transfers are returned except those that don't meet criteria defined in this query.

+ * + * @param {Partial} [query] - transfer query configuration (optional) + * @param {bigint} query.amount - get transfers with this amount + * @param {number} query.accountIndex - get transfers to/from this account index + * @param {number} query.subaddressIndex - get transfers to/from this subaddress index + * @param {number[]} query.subaddressIndices - get transfers to/from these subaddress indices + * @param {string} query.address - get transfers to/from this wallet address + * @param {string[]} query.addresses - get transfers to/from these wallet addresses + * @param {boolean} query.isIncoming - get transfers which are incoming if true + * @param {boolean} query.isOutgoing - get transfers which are outgoing if true + * @param {boolean} query.hasDestinations - get transfers with known destinations if true (destinations are only stored locally with the wallet) + * @param {MoneroTxQuery} query.txQuery - get transfers whose tx match this tx query + */ + constructor(query?: Partial) { + super(query); + if (this.txQuery && !(this.txQuery instanceof MoneroTxQuery)) this.txQuery = new MoneroTxQuery(this.txQuery); + if (this.txQuery) this.txQuery.setTransferQuery(this); + + // alias isOutgoing to isIncoming + if ((this as any).isOutgoing !== undefined) this.isIncoming = !(this as any).isOutgoing; + this.validate(); + } + + copy(): MoneroTransferQuery { + return new MoneroTransferQuery(this); + } + + toJson(): any { + let json = Object.assign({}, this, super.toJson()); + delete json.txQuery; + return json; + } + + getTxQuery(): MoneroTxQuery { + return this.txQuery as MoneroTxQuery; + } + + setTxQuery(txQuery: MoneroTxQuery): MoneroTransferQuery { + this.txQuery = txQuery; + if (txQuery) txQuery.setTransferQuery(this); + return this; + } + + getIsIncoming(): boolean { + return this.isIncoming; + } + + setIsIncoming(isIncoming: boolean): MoneroTransferQuery { + this.isIncoming = isIncoming; + return this; + } + + getIsOutgoing(): boolean { + return this.isIncoming === undefined ? undefined : !this.isIncoming; + } + + setIsOutgoing(isOutgoing: boolean): MoneroTransferQuery { + this.isIncoming = isOutgoing === undefined ? undefined : !isOutgoing; + return this; + } + + getAddress(): string { + return this.address; + } + + setAddress(address: string): MoneroTransferQuery { + this.address = address; + return this; + } + + getAddresses(): string[] { + return this.addresses; + } + + setAddresses(addresses: string[]): MoneroTransferQuery { + this.addresses = addresses; + return this; + } + + getSubaddressIndex(): number { + return this.subaddressIndex; + } + + setSubaddressIndex(subaddressIndex: number): MoneroTransferQuery { + this.subaddressIndex = subaddressIndex; + this.validate(); + return this; + } + + getSubaddressIndices(): number[] { + return this.subaddressIndices; + } + + setSubaddressIndices(subaddressIndices: number[]): MoneroTransferQuery { + this.subaddressIndices = subaddressIndices; + this.validate(); + return this; + } + + getDestinations(): MoneroDestination[] { + return this.destinations; + } + + setDestinations(destinations: MoneroDestination[]) { + this.destinations = destinations; + return this; + } + + getHasDestinations(): boolean { + return this.hasDestinations; + } + + setHasDestinations(hasDestinations: boolean): MoneroTransferQuery { + this.hasDestinations = hasDestinations; + return this; + } + + /** + * Convenience method to query outputs by the locked state of their tx. + * + * @param isLocked specifies if the output's tx must be locked or unlocked (optional) + * @return {MoneroOutputQuery} this query for chaining + */ + setIsLocked(isLocked: boolean): MoneroTransferQuery { + if (this.txQuery === undefined) this.txQuery = new MoneroTxQuery(); + this.getTxQuery().setIsLocked(isLocked); + return this; + } + + meetsCriteria(transfer: MoneroTransfer, queryParent = true): boolean { + if (!(transfer instanceof MoneroTransfer)) throw new Error("Transfer not given to MoneroTransferQuery.meetsCriteria(transfer)"); + + // filter on common fields + if (this.getIsIncoming() !== undefined && this.getIsIncoming() !== transfer.getIsIncoming()) return false; + if (this.getIsOutgoing() !== undefined && this.getIsOutgoing() !== transfer.getIsOutgoing()) return false; + if (this.getAmount() !== undefined && this.getAmount() !== transfer.getAmount()) return false; + if (this.getAccountIndex() !== undefined && this.getAccountIndex() !== transfer.getAccountIndex()) return false; + + // filter on incoming fields + if (transfer instanceof MoneroIncomingTransfer) { + if (this.getHasDestinations() !== undefined) return false; + if (this.getAddress() !== undefined && this.getAddress() !== transfer.getAddress()) return false; + if (this.getAddresses() !== undefined && !this.getAddresses().includes(transfer.getAddress())) return false; + if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() !== transfer.getSubaddressIndex()) return false; + if (this.getSubaddressIndices() !== undefined && !this.getSubaddressIndices().includes(transfer.getSubaddressIndex())) return false; + } + + // filter on outgoing fields + else if (transfer instanceof MoneroOutgoingTransfer) { + + // filter on addresses which must have overlap + if (this.getAddress() !== undefined && (transfer.getAddresses() === undefined || !transfer.getAddresses().includes(this.getAddress()))) return false; // TODO: will filter all transfers that don't contain addresses (outgoing txs might not have this field initialized) + if (this.getAddresses() !== undefined) { + if (!transfer.getAddresses()) return false; + if (!this.getAddresses().some(address => transfer.getAddresses().includes(address))) return false; + } + + // filter on subaddress indices + if (this.getSubaddressIndex() !== undefined && (transfer.getSubaddressIndices() === undefined || !transfer.getSubaddressIndices().includes(this.getSubaddressIndex()))) return false; + if (this.getSubaddressIndices() !== undefined) { + if (!transfer.getSubaddressIndices()) return false; + if (!this.getSubaddressIndices().some(subaddressIdx => transfer.getSubaddressIndices().includes(subaddressIdx))) return false; + } + + // filter on having destinations + if (this.getHasDestinations() !== undefined) { + if (this.getHasDestinations() && transfer.getDestinations() === undefined) return false; + if (!this.getHasDestinations() && transfer.getDestinations() !== undefined) return false; + } + + // filter on destinations TODO: start with test for this +// if (this.getDestionations() !== undefined && this.getDestionations() !== transfer.getDestionations()) return false; + } + + // otherwise invalid type + else throw new Error("Transfer must be MoneroIncomingTransfer or MoneroOutgoingTransfer"); + + // filter with tx filter + if (queryParent && this.getTxQuery() !== undefined && !this.getTxQuery().meetsCriteria(transfer.getTx())) return false; + return true; + } + + validate() { + if (this.getSubaddressIndex() !== undefined && this.getSubaddressIndex() < 0) throw new MoneroError("Subaddress index must be >= 0"); + if (this.getSubaddressIndices() !== undefined) for (let subaddressIdx of this.getSubaddressIndices()) if (subaddressIdx < 0) throw new MoneroError("Subaddress indices must be >= 0"); + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setTx(tx: MoneroTxWallet): MoneroTransferQuery { + super.setTx(tx); + return this; + } + + setAmount(amount: bigint): MoneroTransferQuery { + super.setAmount(amount); + return this; + } + + setAccountIndex(accountIndex: number): MoneroTransferQuery { + super.setAccountIndex(accountIndex); + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroTxConfig.ts b/src/main/ts/wallet/model/MoneroTxConfig.ts new file mode 100644 index 000000000..4502ba4d9 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroTxConfig.ts @@ -0,0 +1,349 @@ +import assert from "assert"; +import MoneroDestination from "./MoneroDestination"; +import MoneroError from "../../common/MoneroError"; +import MoneroTxPriority from "./MoneroTxPriority"; + +/** + * Configures a transaction to send, sweep, or create a payment URI. + */ +export default class MoneroTxConfig { + + /** Single destination address (required unless `destinations` provided). */ + address: string; + + /** Single destination amount (required unless `destinations provided). */ + amount: bigint; + + /** Source account index to transfer funds from (required unless sweeping key image). */ + accountIndex: number; + + /** Source subaddress index to send funds from (default all). */ + subaddressIndex: number; + + /** Source subaddresses to send funds from (default all). */ + subaddressIndices: number[]; + + /** Relay the transaction to peers to commit to the blockchain if true (default false). */ + relay: boolean; + + /** Transaction priority to adjust the miner fee (default MoneroTxPriority.NORMAL). */ + priority: MoneroTxPriority; + + /** Multiple destinations to send funds to, if applicable. */ + destinations: Partial[]; + + /** List of destination indices to split the miner fee (optional). */ + subtractFeeFrom: number[]; + + /** Payment ID for the transaction. */ + paymentId: string; + + /** Miner fee (calculated automatically). */ + fee: bigint; + + /** Transaction note saved locally with the wallet (optional). */ + note: string; + + /** Recipient name saved locally with the wallet (optional). */ + recipientName: string; + + /** Allow funds to be transferred using multiple transactions if necessary (default false). */ + canSplit: boolean; + + /** For sweep requests, include outputs below this amount when sweeping wallet, account, subaddress, or all unlocked funds. */ + belowAmount: bigint; + + /** For sweep requests, sweep each subaddress individually instead of together if true. */ + sweepEachSubaddress: boolean; + + /** For sweep requests, key image of the output to sweep. */ + keyImage: string; + + /** + *

Generic request to transfer funds from a wallet.

+ * + *

Example:

+ * + * + * let config1 = new MoneroTxConfig({
+ *    accountIndex: 0,
+ *    address: "59aZULsUF3YN...",
+ *    amount: 500000n,
+ *    priority: MoneroTxPriority.NORMAL,
+ *    relay: true
+ * }); + *
+ * + * @param {Partial} [config] - configures the transaction to create (optional) + * @param {string} [config.address] - single destination address + * @param {bigint} [config.amount] - single destination amount + * @param {number} [config.accountIndex] - source account index to transfer funds from + * @param {number} [config.subaddressIndex] - source subaddress index to transfer funds from + * @param {number[]} [config.subaddressIndices] - source subaddress indices to transfer funds from + * @param {boolean} [config.relay] - relay the transaction to peers to commit to the blockchain + * @param {MoneroTxPriority} [config.priority] - transaction priority (default MoneroTxPriority.NORMAL) + * @param {MoneroDestination[]} [config.destinations] - addresses and amounts in a multi-destination tx + * @param {number[]} [config.subtractFeeFrom] - list of destination indices to split the transaction fee + * @param {string} [config.paymentId] - transaction payment ID + * @param {bigint} [config.unlockTime] - minimum height or timestamp for the transaction to unlock (default 0) + * @param {string} [config.note] - transaction note saved locally with the wallet + * @param {string} [config.recipientName] - recipient name saved locally with the wallet + * @param {boolean} [config.canSplit] - allow funds to be transferred using multiple transactions + * @param {bigint} [config.belowAmount] - for sweep requests, include outputs below this amount when sweeping wallet, account, subaddress, or all unlocked funds + * @param {boolean} [config.sweepEachSubaddress] - for sweep requests, sweep each subaddress individually instead of together if true + * @param {string} [config.keyImage] - key image to sweep (ignored except in sweepOutput() requests) + */ + constructor(config?: Partial) { + Object.assign(this, config); + + // deserialize bigints + if (this.amount !== undefined && typeof this.amount !== "bigint") this.amount = BigInt(this.amount); + if (this.fee !== undefined && typeof this.fee !== "bigint") this.fee = BigInt(this.fee); + if (this.belowAmount !== undefined && typeof this.belowAmount !== "bigint") this.belowAmount = BigInt(this.belowAmount); + + // copy destinations + if (this.destinations) { + assert(this.address === undefined && this.amount === undefined, "Tx configuration may specify destinations or an address/amount but not both"); + this.setDestinations(this.destinations.map(destination => new MoneroDestination(destination))); + } + + // alias 'address' and 'amount' to single destination to support e.g. createTx({address: "..."}) + if (this.address || this.amount) { + assert(!this.destinations, "Tx configuration may specify destinations or an address/amount but not both"); + this.setAddress(this.address); + this.setAmount(this.amount); + delete this.address; + delete this.amount; + } + + // alias 'subaddressIndex' to subaddress indices + if (this.subaddressIndex !== undefined) { + this.setSubaddressIndices([this.subaddressIndex]); + delete this.subaddressIndex; + } + } + + copy(): MoneroTxConfig { + return new MoneroTxConfig(this); + } + + toJson(): any { + let json: any = Object.assign({}, this); // copy state + if (this.getDestinations() !== undefined) { + json.destinations = []; + for (let destination of this.getDestinations()) json.destinations.push(destination.toJson()); + } + if (this.getFee()) json.fee = this.getFee().toString(); + if (this.getBelowAmount()) json.belowAmount = this.getBelowAmount().toString(); + return json; + } + + /** + * Set the address of a single-destination configuration. + * + * @param {string} address - the address to set for the single destination + * @return {MoneroTxConfig} this configuration for chaining + */ + setAddress(address: string): MoneroTxConfig { + if (this.destinations !== undefined && this.destinations.length > 1) throw new MoneroError("Cannot set address because MoneroTxConfig already has multiple destinations"); + if (this.destinations === undefined || this.destinations.length === 0) this.addDestination(new MoneroDestination(address)); + else (this.destinations[0] as MoneroDestination).setAddress(address); + return this; + } + + /** + * Get the address of a single-destination configuration. + * + * @return {string} the address of the single destination + */ + getAddress(): string { + if (this.destinations === undefined || this.destinations.length !== 1) throw new MoneroError("Cannot get address because MoneroTxConfig does not have exactly one destination"); + return (this.destinations[0] as MoneroDestination).getAddress(); + } + + /** + * Set the amount of a single-destination configuration. + * + * @param {bigint} amount - the amount to set for the single destination + * @return {MoneroTxConfig} this configuration for chaining + */ + setAmount(amount: bigint): MoneroTxConfig { + if (amount !== undefined && typeof this.amount !== "bigint") { + if (typeof amount === "number") throw new MoneroError("Destination amount must be bigint or string"); + try { amount = BigInt(amount); } + catch (err) { throw new MoneroError("Invalid destination amount: " + amount); } + } + if (this.destinations !== undefined && this.destinations.length > 1) throw new MoneroError("Cannot set amount because MoneroTxConfig already has multiple destinations"); + if (this.destinations === undefined || this.destinations.length === 0) this.addDestination(new MoneroDestination(undefined, amount)); + else (this.destinations[0] as MoneroDestination).setAmount(amount); + return this; + } + + /** + * Get the amount of a single-destination configuration. + * + * @return {bigint} the amount of the single destination + */ + getAmount(): bigint { + if (this.destinations === undefined || this.destinations.length !== 1) throw new MoneroError("Cannot get amount because MoneroTxConfig does not have exactly one destination"); + return (this.destinations[0] as MoneroDestination).getAmount(); + } + + addDestination(destinationOrAddress: MoneroDestination | string, amount?: bigint): MoneroTxConfig { + if (typeof destinationOrAddress === "string") return this.addDestination(new MoneroDestination(destinationOrAddress, amount)); + assert(destinationOrAddress instanceof MoneroDestination); + if (this.destinations === undefined) this.destinations = []; + this.destinations.push(destinationOrAddress); + return this; + } + + getDestinations(): MoneroDestination[] { + return this.destinations as MoneroDestination[]; + } + + setDestinations(destinations: MoneroDestination[]): MoneroTxConfig { + if (arguments.length > 1) destinations = Array.from(arguments); + this.destinations = destinations; + return this; + } + + setDestination(destination: MoneroDestination): MoneroTxConfig { + return this.setDestinations(destination ? [destination] : undefined); + } + + getSubtractFeeFrom(): number[] { + return this.subtractFeeFrom; + } + + setSubtractFeeFrom(destinationIndices: number[]): MoneroTxConfig { + if (arguments.length > 1) destinationIndices = Array.from(arguments); + this.subtractFeeFrom = destinationIndices; + return this; + } + + getPaymentId(): string { + return this.paymentId; + } + + setPaymentId(paymentId: string): MoneroTxConfig { + this.paymentId = paymentId; + return this; + } + + getPriority(): number { + return this.priority; + } + + setPriority(priority: number): MoneroTxConfig { + this.priority = priority; + return this; + } + + getFee(): bigint { + return this.fee; + } + + setFee(fee: bigint): MoneroTxConfig { + this.fee = fee; + return this; + } + + getAccountIndex(): number { + return this.accountIndex; + } + + setAccountIndex(accountIndex: number): MoneroTxConfig { + this.accountIndex = accountIndex; + return this; + } + + setSubaddressIndex(subaddressIndex: number): MoneroTxConfig { + this.setSubaddressIndices([subaddressIndex]); + return this; + } + + getSubaddressIndices(): number[] { + return this.subaddressIndices; + } + + setSubaddressIndices(subaddressIndices: number[]): MoneroTxConfig { + if (arguments.length > 1) subaddressIndices = Array.from(arguments); + this.subaddressIndices = subaddressIndices; + return this; + } + + getRelay(): boolean { + return this.relay; + } + + setRelay(relay: boolean): MoneroTxConfig { + this.relay = relay; + return this; + } + + getCanSplit(): boolean { + return this.canSplit; + } + + setCanSplit(canSplit: boolean): MoneroTxConfig { + this.canSplit = canSplit; + return this; + } + + getNote(): string { + return this.note; + } + + setNote(note: string): MoneroTxConfig { + this.note = note; + return this; + } + + getRecipientName(): string { + return this.recipientName; + } + + setRecipientName(recipientName: string): MoneroTxConfig { + this.recipientName = recipientName; + return this; + } + + // --------------------------- SPECIFIC TO SWEEP ---------------------------- + + getBelowAmount() { + return this.belowAmount; + } + + setBelowAmount(belowAmount) { + this.belowAmount = belowAmount; + return this; + } + + getSweepEachSubaddress() { + return this.sweepEachSubaddress; + } + + setSweepEachSubaddress(sweepEachSubaddress) { + this.sweepEachSubaddress = sweepEachSubaddress; + return this; + } + + /** + * Get the key image hex of the output to sweep. + * + * return {string} is the key image hex of the output to sweep + */ + getKeyImage() { + return this.keyImage; + } + + /** + * Set the key image hex of the output to sweep. + * + * @param {string} keyImage is the key image hex of the output to sweep + */ + setKeyImage(keyImage) { + this.keyImage = keyImage; + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroTxPriority.ts b/src/main/ts/wallet/model/MoneroTxPriority.ts new file mode 100644 index 000000000..d49da09a7 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroTxPriority.ts @@ -0,0 +1,27 @@ +/** + * Enumerates send priorities. + */ +enum MoneroTxPriority { + + /** + * Default priority (i.e. normal) (value=0). + */ + DEFAULT = 0, + + /** + * Unimportant priority (value=1). + */ + UNIMPORTANT = 1, + + /** + * Normal priority (value=2). + */ + NORMAL = 2, + + /** + * Elevated priority (value=3). + */ + ELEVATED = 3 +} + +export default MoneroTxPriority; \ No newline at end of file diff --git a/src/main/ts/wallet/model/MoneroTxQuery.ts b/src/main/ts/wallet/model/MoneroTxQuery.ts new file mode 100644 index 000000000..ac0bea280 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroTxQuery.ts @@ -0,0 +1,524 @@ +import assert from "assert"; +import MoneroBlock from "../../daemon/model/MoneroBlock"; +import MoneroOutput from "../../daemon/model/MoneroOutput"; +import MoneroIncomingTransfer from "./MoneroIncomingTransfer"; +import MoneroOutgoingTransfer from "./MoneroOutgoingTransfer"; +import MoneroOutputQuery from "./MoneroOutputQuery"; +import MoneroTransferQuery from "./MoneroTransferQuery"; +import MoneroTxSet from "./MoneroTxSet"; +import MoneroTxWallet from "./MoneroTxWallet"; + +/** + *

Configuration to query transactions.

+ */ +export default class MoneroTxQuery extends MoneroTxWallet { + + hash: string; + hashes: string[]; + height: number; + minHeight: number; + maxHeight: number; + includeOutputs: boolean; + isConfirmed: boolean; + inTxPool: boolean; + relay: boolean; + isRelayed: boolean; + isFailed: boolean; + isMinerTx: boolean; + isLocked: boolean; + isIncoming: boolean; + isOutgoing: boolean; + paymentId: string; + paymentIds: string[]; + hasPaymentId: boolean; + transferQuery: Partial; + inputQuery: Partial; + outputQuery: Partial; + + /** + *

Construct the transaction query.

+ * + *

Example:

+ * + * + * // get transactions with unlocked incoming transfers to account 0
+ * let txs = await wallet.getTxs({
+ *    isLocked: false,
+ *    transferQuery: {
+ *      isIncoming: true,
+ *      accountIndex: 0
+ *    }
+ * }); + *
+ * + *

All configuration is optional. All transactions are returned except those that don't meet criteria defined in this query.

+ * + * @param {MoneroTxQuery} [query] - tx query configuration + * @param {string} [query.hash] - get a tx with this hash + * @param {string[]} [query.txHashes] - get txs with these hashes + * @param {number} [query.height] - get txs with this height + * @param {number} [query.minHeight] - get txs with height greater than or equal to this height + * @param {number} [query.maxHeight] - get txs with height less than or equal to this height + * @param {boolean} [query.isConfirmed] - get confirmed or unconfirmed txs + * @param {boolean} [query.inTxPool] - get txs in or out of the tx pool + * @param {boolean} [query.relay] - get txs with the same relay status + * @param {boolean} [query.isRelayed] - get relayed or non-relayed txs + * @param {boolean} [query.isFailed] - get failed or non-failed txs + * @param {boolean} [query.isMinerTx] - get miner or non-miner txs + * @param {boolean} [query.isLocked] - get locked or unlocked txs + * @param {boolean} [query.isIncoming] - get txs with or without incoming transfers + * @param {boolean} [query.isOutgoing] - get txs with or without outgoing transfers + * @param {string} [query.paymentId] - get txs with this payment ID + * @param {string} [query.paymentIds] - get txs with a payment ID among these payment IDs + * @param {boolean} [query.hasPaymentId] - get txs with or without payment IDs + * @param {Partial} [query.transferQuery] - get txs with transfers matching this transfer query + * @param {Partial} [query.inputQuery] - get txs with inputs matching this input query + * @param {Partial} [query.outputQuery] - get txs with outputs matching this output query + */ + constructor(query?: Partial) { + super(query); + + // copy queries + if (this.transferQuery) this.transferQuery = new MoneroTransferQuery(this.transferQuery); + if (this.inputQuery) this.inputQuery = new MoneroOutputQuery(this.inputQuery); + if (this.outputQuery) this.outputQuery = new MoneroOutputQuery(this.outputQuery); + + // link cycles + if (this.transferQuery) this.getTransferQuery().setTxQuery(this); + if (this.inputQuery) this.getInputQuery().setTxQuery(this); + if (this.outputQuery) this.getOutputQuery().setTxQuery(this); + + // alias 'hash' to hashes + if (this.hash) { + this.setHashes([this.hash]); + delete this.hash; + } + } + + copy(): MoneroTxQuery { + return new MoneroTxQuery(this); + } + + toJson(): any { + let json = Object.assign({}, this, super.toJson()); // merge json onto inherited state + if (this.getTransferQuery() !== undefined) json.transferQuery = this.getTransferQuery().toJson(); + if (this.getInputQuery() !== undefined) json.inputQuery = this.getInputQuery().toJson(); + if (this.getOutputQuery() !== undefined) json.outputQuery = this.getOutputQuery().toJson(); + delete json.block; // do not serialize parent block + return json; + } + + getIsIncoming(): boolean { + return this.isIncoming; + } + + setIsIncoming(isIncoming: boolean): MoneroTxQuery { + this.isIncoming = isIncoming; + return this; + } + + getIsOutgoing(): boolean { + return this.isOutgoing; + } + + setIsOutgoing(isOutgoing: boolean): MoneroTxQuery { + this.isOutgoing = isOutgoing; + return this; + } + + getHashes(): string[] { + return this.hashes; + } + + setHashes(hashes: string[]): MoneroTxQuery { + this.hashes = hashes; + return this; + } + + setHash(hash: string): MoneroTxQuery { + if (hash === undefined) return this.setHashes(undefined); + assert(typeof hash === "string"); + return this.setHashes([hash]); + } + + getHasPaymentId(): boolean { + return this.hasPaymentId; + } + + setHasPaymentId(hasPaymentId: boolean): MoneroTxQuery { + this.hasPaymentId = hasPaymentId; + return this; + } + + getPaymentIds(): string[] { + return this.paymentIds; + } + + setPaymentIds(paymentIds: string[]): MoneroTxQuery { + this.paymentIds = paymentIds; + return this; + } + + setPaymentId(paymentId: string): MoneroTxQuery { + if (paymentId === undefined) return this.setPaymentIds(undefined); + assert(typeof paymentId === "string"); + return this.setPaymentIds([paymentId]); + } + + getHeight(): number { + return this.height; + } + + setHeight(height: number): MoneroTxQuery { + this.height = height; + return this; + } + + getMinHeight(): number { + return this.minHeight; + } + + setMinHeight(minHeight: number): MoneroTxQuery { + this.minHeight = minHeight; + return this; + } + + getMaxHeight(): number { + return this.maxHeight; + } + + setMaxHeight(maxHeight: number): MoneroTxQuery { + this.maxHeight = maxHeight; + return this; + } + + getIncludeOutputs(): boolean { + return this.includeOutputs; + } + + setIncludeOutputs(includeOutputs: boolean): MoneroTxQuery { + this.includeOutputs = includeOutputs; + return this; + } + + getTransferQuery(): MoneroTransferQuery { + return this.transferQuery as MoneroTransferQuery + } + + setTransferQuery(transferQuery: MoneroTransferQuery): MoneroTxQuery { + this.transferQuery = transferQuery === undefined ? undefined : transferQuery instanceof MoneroTransferQuery ? transferQuery : new MoneroTransferQuery(transferQuery); + if (transferQuery) this.transferQuery.txQuery = this; + return this; + } + + getInputQuery(): MoneroOutputQuery { + return this.inputQuery as MoneroOutputQuery; + } + + setInputQuery(inputQuery: MoneroOutputQuery): MoneroTxQuery { + this.inputQuery = inputQuery; + if (inputQuery) inputQuery.txQuery = this; + return this; + } + + getOutputQuery(): MoneroOutputQuery { + return this.outputQuery as MoneroOutputQuery; + } + + setOutputQuery(outputQuery: MoneroOutputQuery): MoneroTxQuery { + this.outputQuery = outputQuery === undefined ? undefined : outputQuery instanceof MoneroOutputQuery ? outputQuery : new MoneroOutputQuery(outputQuery); + if (outputQuery) this.outputQuery.txQuery = this; + return this; + } + + meetsCriteria(tx: MoneroTxWallet, queryChildren?: boolean): boolean { + if (!(tx instanceof MoneroTxWallet)) throw new Error("Tx not given to MoneroTxQuery.meetsCriteria(tx)"); + if (queryChildren === undefined) queryChildren = true; + + // filter on tx + if (this.getHash() !== undefined && this.getHash() !== tx.getHash()) return false; + if (this.getPaymentId() !== undefined && this.getPaymentId() !== tx.getPaymentId()) return false; + if (this.getIsConfirmed() !== undefined && this.getIsConfirmed() !== tx.getIsConfirmed()) return false; + if (this.getInTxPool() !== undefined && this.getInTxPool() !== tx.getInTxPool()) return false; + if (this.getRelay() !== undefined && this.getRelay() !== tx.getRelay()) return false; + if (this.getIsRelayed() !== undefined && this.getIsRelayed() !== tx.getIsRelayed()) return false; + if (this.getIsFailed() !== undefined && this.getIsFailed() !== tx.getIsFailed()) return false; + if (this.getIsMinerTx() !== undefined && this.getIsMinerTx() !== tx.getIsMinerTx()) return false; + if (this.getIsLocked() !== undefined && this.getIsLocked() !== tx.getIsLocked()) return false; + + // filter on having a payment id + if (this.getHasPaymentId() !== undefined) { + if (this.getHasPaymentId() && tx.getPaymentId() === undefined) return false; + if (!this.getHasPaymentId() && tx.getPaymentId() !== undefined) return false; + } + + // filter on incoming + if (this.getIsIncoming() !== undefined) { + if (this.getIsIncoming() && !tx.getIsIncoming()) return false; + if (!this.getIsIncoming() && tx.getIsIncoming()) return false; + } + + // filter on outgoing + if (this.getIsOutgoing() !== undefined) { + if (this.getIsOutgoing() && !tx.getIsOutgoing()) return false; + if (!this.getIsOutgoing() && tx.getIsOutgoing()) return false; + } + + // filter on remaining fields + let txHeight = tx.getBlock() === undefined ? undefined : tx.getBlock().getHeight(); + if (this.getHashes() !== undefined && !this.getHashes().includes(tx.getHash())) return false; + if (this.getPaymentIds() !== undefined && !this.getPaymentIds().includes(tx.getPaymentId())) return false; + if (this.getHeight() !== undefined && (txHeight === undefined || txHeight !== this.getHeight())) return false; + if (this.getMinHeight() !== undefined && txHeight !== undefined && txHeight < this.getMinHeight()) return false; // do not filter unconfirmed + if (this.getMaxHeight() !== undefined && (txHeight === undefined || txHeight > this.getMaxHeight())) return false; + // TODO: filtering not complete + + // done if not querying transfers or outputs + if (!queryChildren) return true; + + // at least one transfer must meet transfer filter if defined + if (this.getTransferQuery() !== undefined) { + let matchFound = false; + if (tx.getOutgoingTransfer() && this.getTransferQuery().meetsCriteria(tx.getOutgoingTransfer(), false)) matchFound = true; + else if (tx.getIncomingTransfers()) { + for (let incomingTransfer of tx.getIncomingTransfers()) { + if (this.getTransferQuery().meetsCriteria(incomingTransfer, false)) { + matchFound = true; + break; + } + } + } + if (!matchFound) return false; + } + + // at least one input must meet input query if defined + if (this.getInputQuery() !== undefined) { + if (tx.getInputs() === undefined || tx.getInputs().length === 0) return false; + let matchFound = false; + for (let input of tx.getInputsWallet()) { + if (this.getInputQuery().meetsCriteria(input, false)) { + matchFound = true; + break; + } + } + if (!matchFound) return false; + } + + // at least one output must meet output query if defined + if (this.getOutputQuery() !== undefined) { + if (tx.getOutputs() === undefined || tx.getOutputs().length === 0) return false; + let matchFound = false; + for (let output of tx.getOutputsWallet()) { + if (this.getOutputQuery().meetsCriteria(output, false)) { + matchFound = true; + break; + } + } + if (!matchFound) return false; + } + + return true; // transaction meets filter criteria + } + + // ------------------- OVERRIDE CO-VARIANT RETURN TYPES --------------------- + + setIncomingTransfers(incomingTransfers: MoneroIncomingTransfer[]): MoneroTxQuery { + super.setIncomingTransfers(incomingTransfers); + return this; + } + + setOutgoingTransfer(outgoingTransfer: MoneroOutgoingTransfer): MoneroTxQuery { + super.setOutgoingTransfer(outgoingTransfer); + return this; + } + + setOutputs(outputs: MoneroOutput[]): MoneroTxQuery { + super.setOutputs(outputs); + return this; + } + + setNote(note: string): MoneroTxQuery { + super.setNote(note); + return this; + } + + setIsLocked(isLocked: boolean): MoneroTxQuery { + super.setIsLocked(isLocked); + return this; + } + + setBlock(block: MoneroBlock): MoneroTxQuery { + super.setBlock(block); + return this; + } + + setVersion(version: number): MoneroTxQuery { + super.setVersion(version); + return this; + } + + setIsMinerTx(isMinerTx: boolean): MoneroTxQuery { + super.setIsMinerTx(isMinerTx); + return this; + } + + setFee(fee: bigint): MoneroTxQuery { + super.setFee(fee); + return this; + } + + setRingSize(ringSize: number): MoneroTxQuery { + super.setRingSize(ringSize); + return this; + } + + setRelay(relay: boolean): MoneroTxQuery { + super.setRelay(relay); + return this; + } + + setIsRelayed(isRelayed: boolean): MoneroTxQuery { + super.setIsRelayed(isRelayed); + return this; + } + + setIsConfirmed(isConfirmed: boolean): MoneroTxQuery { + super.setIsConfirmed(isConfirmed); + return this; + } + + setInTxPool(inTxPool: boolean): MoneroTxQuery { + super.setInTxPool(inTxPool); + return this; + } + + setNumConfirmations(numConfirmations: number): MoneroTxQuery { + super.setNumConfirmations(numConfirmations); + return this; + } + + setUnlockTime(unlockTime: bigint): MoneroTxQuery { + super.setUnlockTime(unlockTime); + return this; + } + + setLastRelayedTimestamp(lastRelayedTimestamp: number): MoneroTxQuery { + super.setLastRelayedTimestamp(lastRelayedTimestamp); + return this; + } + + setReceivedTimestamp(receivedTimestamp: number): MoneroTxQuery { + super.setReceivedTimestamp(receivedTimestamp); + return this; + } + + setIsDoubleSpendSeen(isDoubleSpendSeen: boolean): MoneroTxQuery { + super.setIsDoubleSpendSeen(isDoubleSpendSeen); + return this; + } + + setKey(key: string): MoneroTxQuery { + super.setKey(key); + return this; + } + + setFullHex(hex: string): MoneroTxQuery { + super.setFullHex(hex); + return this; + } + + setPrunedHex(prunedHex: string): MoneroTxQuery { + super.setPrunedHex(prunedHex); + return this; + } + + setPrunableHex(prunableHex: string): MoneroTxQuery { + super.setPrunableHex(prunableHex); + return this; + } + + setPrunableHash(prunableHash: string): MoneroTxQuery { + super.setPrunableHash(prunableHash); + return this; + } + + setSize(size: number): MoneroTxQuery { + super.setSize(size); + return this; + } + + setWeight(weight: number): MoneroTxQuery { + super.setWeight(weight); + return this; + } + + setInputs(inputs: MoneroOutput[]): MoneroTxQuery { + super.setInputs(inputs); + return this; + } + + setOutputIndices(outputIndices: number[]): MoneroTxQuery { + super.setOutputIndices(outputIndices); + return this; + } + + setMetadata(metadata: string): MoneroTxQuery { + super.setMetadata(metadata); + return this; + } + + setTxSet(txSet: MoneroTxSet): MoneroTxQuery { + super.setTxSet(txSet); + return this; + } + + setExtra(extra: Uint8Array): MoneroTxQuery { + super.setExtra(extra); + return this; + } + + setRctSignatures(rctSignatures: any): MoneroTxQuery { + super.setRctSignatures(rctSignatures) + return this; + } + + setRctSigPrunable(rctSigPrunable: any): MoneroTxQuery { + super.setRctSigPrunable(rctSigPrunable); + return this; + } + + setIsKeptByBlock(isKeptByBlock: boolean): MoneroTxQuery { + super.setIsKeptByBlock(isKeptByBlock) + return this; + } + + setIsFailed(isFailed: boolean): MoneroTxQuery { + super.setIsFailed(isFailed); + return this; + } + + setLastFailedHeight(lastFailedHeight: number): MoneroTxQuery { + super.setLastFailedHeight(lastFailedHeight); + return this; + } + + setLastFailedHash(lastFailedId: string): MoneroTxQuery { + super.setLastFailedHash(lastFailedId); + return this; + } + + setMaxUsedBlockHeight(maxUsedBlockHeight: number): MoneroTxQuery { + super.setMaxUsedBlockHeight(maxUsedBlockHeight); + return this; + } + + setMaxUsedBlockHash(maxUsedBlockId: string): MoneroTxQuery { + super.setMaxUsedBlockHash(maxUsedBlockId); + return this; + } + + setSignatures(signatures: string[]): MoneroTxQuery { + super.setSignatures(signatures); + return this; + } +} diff --git a/src/main/js/wallet/model/MoneroTxSet.js b/src/main/ts/wallet/model/MoneroTxSet.ts similarity index 52% rename from src/main/js/wallet/model/MoneroTxSet.js rename to src/main/ts/wallet/model/MoneroTxSet.ts index 12cfc477f..3c33e4e9d 100644 --- a/src/main/js/wallet/model/MoneroTxSet.js +++ b/src/main/ts/wallet/model/MoneroTxSet.ts @@ -1,7 +1,7 @@ -const assert = require("assert"); -const GenUtils = require("../../common/GenUtils"); -const MoneroTxWallet = require("./MoneroTxWallet"); -const MoneroUtils = require("../../common/MoneroUtils"); +import assert from "assert"; +import GenUtils from "../../common/GenUtils"; +import MoneroTxWallet from "./MoneroTxWallet"; +import MoneroUtils from "../../common/MoneroUtils"; /** * Groups transactions who share common hex data which is needed in order to @@ -11,28 +11,28 @@ const MoneroUtils = require("../../common/MoneroUtils"); * hex string which is needed in order to sign and submit the multisig * transactions. */ -class MoneroTxSet { +export default class MoneroTxSet { + + txs: MoneroTxWallet[]; + multisigTxHex: string; + unsignedTxHex: string; + signedTxHex: string; - constructor(state) { - - // initialize internal state - if (!state) state = {}; - else if (typeof state === "object") state = Object.assign({}, state); - else throw new MoneroError("state must be JavaScript object"); - this.state = state; + constructor(txSet?: Partial) { + Object.assign(this, txSet); - // deserialize txs - if (state.txs) { - for (let i = 0; i < state.txs.length; i++) { - if (!(state.txs[i] instanceof MoneroTxWallet)) state.txs[i] = new MoneroTxWallet(state.txs[i]); - state.txs[i].setTxSet(this); + // copy txs + if (this.txs) { + for (let i = 0; i < this.txs.length; i++) { + this.txs[i] = new MoneroTxWallet(this.txs[i]); + this.txs[i].setTxSet(this); } } } toJson() { - let json = Object.assign({}, this.state); // copy state - if (this.getTxs()) { + let json = Object.assign({}, this); // copy state + if (this.getTxs() !== undefined) { json.txs = []; for (let tx of this.getTxs()) json.txs.push(tx.toJson()); } @@ -40,38 +40,38 @@ class MoneroTxSet { } getTxs() { - return this.state.txs; + return this.txs; } setTxs(txs) { - this.state.txs = txs; + this.txs = txs; return this; } getMultisigTxHex() { - return this.state.multisigTxHex; + return this.multisigTxHex; } setMultisigTxHex(multisigTxHex) { - this.state.multisigTxHex = multisigTxHex; + this.multisigTxHex = multisigTxHex; return this; } getUnsignedTxHex() { - return this.state.unsignedTxHex; + return this.unsignedTxHex; } setUnsignedTxHex(unsignedTxHex) { - this.state.unsignedTxHex = unsignedTxHex; + this.unsignedTxHex = unsignedTxHex; return this; } getSignedTxHex() { - return this.state.signedTxHex; + return this.signedTxHex; } setSignedTxHex(signedTxHex) { - this.state.signedTxHex = signedTxHex; + this.signedTxHex = signedTxHex; return this; } @@ -97,17 +97,15 @@ class MoneroTxSet { toString(indent = 0) { let str = ""; - str += GenUtils.kvLine("Multisig tx hex: ", getMultisigTxHex(), indent); - str += GenUtils.kvLine("Unsigned tx hex: ", getUnsignedTxHex(), indent); - str += GenUtils.kvLine("Signed tx hex: ", getSignedTxHex(), indent); - if (getTxs() !== undefined) { + str += GenUtils.kvLine("Multisig tx hex: ", this.getMultisigTxHex(), indent); + str += GenUtils.kvLine("Unsigned tx hex: ", this.getUnsignedTxHex(), indent); + str += GenUtils.kvLine("Signed tx hex: ", this.getSignedTxHex(), indent); + if (this.getTxs() !== undefined) { str += GenUtils.kvLine("Txs", "", indent); - for (let tx of getTxs()) { + for (let tx of this.getTxs()) { str += tx.toString(indent + 1) + "\n"; } } return str; } -} - -module.exports = MoneroTxSet; \ No newline at end of file +} \ No newline at end of file diff --git a/src/main/ts/wallet/model/MoneroTxWallet.ts b/src/main/ts/wallet/model/MoneroTxWallet.ts new file mode 100644 index 000000000..5571420e5 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroTxWallet.ts @@ -0,0 +1,746 @@ +import assert from "assert"; +import GenUtils from "../../common/GenUtils"; +import MoneroBlock from "../../daemon/model/MoneroBlock"; +import MoneroError from "../../common/MoneroError"; +import MoneroIncomingTransfer from "./MoneroIncomingTransfer"; +import MoneroOutgoingTransfer from "./MoneroOutgoingTransfer"; +import MoneroOutputQuery from "./MoneroOutputQuery"; +import MoneroOutput from "../../daemon/model/MoneroOutput"; +import MoneroOutputWallet from "./MoneroOutputWallet"; +import MoneroTransfer from "./MoneroTransfer"; +import MoneroTransferQuery from "./MoneroTransferQuery"; +import MoneroTx from "../../daemon/model/MoneroTx"; +import MoneroTxSet from "./MoneroTxSet"; + +/** + * Models a Monero transaction with wallet extensions. + */ +export default class MoneroTxWallet extends MoneroTx { + + txSet: MoneroTxSet; + isIncoming: boolean; + isOutgoing: boolean; + incomingTransfers: MoneroIncomingTransfer[]; + outgoingTransfer: MoneroOutgoingTransfer; + note: string; + isLocked: boolean; + inputSum: bigint; + outputSum: bigint; + changeAddress: string; + changeAmount: bigint; + numDummyOutputs: number; + extraHex: string; + + /** + * Construct the model. + * + * @param {Partial} [tx] is existing state to initialize from (optional) + */ + constructor(tx?: Partial) { + super(tx); + this.setTxSet(this.getTxSet()); // preserve reference to tx set + + // copy incoming transfers + if (this.incomingTransfers) { + this.incomingTransfers = this.incomingTransfers.slice(); + for (let i = 0; i < this.incomingTransfers.length; i++) { + this.incomingTransfers[i] = new MoneroIncomingTransfer(this.incomingTransfers[i]).setTx(this); + } + } + + // copy outgoing transfer + if (this.outgoingTransfer) { + this.outgoingTransfer = new MoneroOutgoingTransfer(this.outgoingTransfer).setTx(this); + } + + // copy inputs + if (this.inputs) { + this.inputs = this.inputs.slice(); + for (let i = 0; i < this.inputs.length; i++) { + this.inputs[i] = new MoneroOutputWallet(this.inputs[i] as MoneroOutputWallet).setTx(this); + } + } + + // copy outputs + if (this.outputs) { + this.outputs = this.outputs.slice(); + for (let i = 0; i < this.outputs.length; i++) { + this.outputs[i] = new MoneroOutputWallet(this.outputs[i] as MoneroOutputWallet).setTx(this); + } + } + + // deserialize bigints + if (this.inputSum !== undefined && typeof this.inputSum !== "bigint") this.inputSum = BigInt(this.inputSum); + if (this.outputSum !== undefined && typeof this.outputSum !== "bigint") this.outputSum = BigInt(this.outputSum); + if (this.changeAmount !== undefined && typeof this.changeAmount !== "bigint") this.changeAmount = BigInt(this.changeAmount); + } + + /** + * @return {any} json representation of this tx + */ + toJson(): any { + let json = Object.assign({}, this, super.toJson()); // merge json onto inherited state + if (this.getIncomingTransfers() !== undefined) { + json.incomingTransfers = []; + for (let incomingTransfer of this.getIncomingTransfers()) json.incomingTransfers.push(incomingTransfer.toJson()); + } + if (this.getOutgoingTransfer() !== undefined) json.outgoingTransfer = this.getOutgoingTransfer().toJson(); + if (this.getInputSum() !== undefined) json.inputSum = this.getInputSum().toString(); + if (this.getOutputSum() !== undefined) json.outputSum = this.getOutputSum().toString(); + if (this.getChangeAmount() !== undefined) json.changeAmount = this.getChangeAmount().toString(); + delete json.block; // do not serialize parent block + delete json.txSet; // do not serialize parent tx set + return json; + } + + /** + * @return {MoneroTxSet} tx set containing txs + */ + getTxSet(): MoneroTxSet { + return this.txSet; + } + + /** + * @param {MoneroTxSet} txSet - tx set containing txs + * @return {MoneroTxWallet} this tx for chaining + */ + setTxSet(txSet: MoneroTxSet): MoneroTxWallet { + this.txSet = txSet; + return this; + } + + /** + * @return {boolean} true if the tx has incoming funds, false otherwise + */ + getIsIncoming(): boolean { + return this.isIncoming; + } + + /** + * @param {boolean} isIncoming - true if the tx has incoming funds, false otherwise + * @return {MoneroTxWallet} this tx for chaining + */ + setIsIncoming(isIncoming: boolean): MoneroTxWallet { + this.isIncoming = isIncoming; + return this; + } + + /** + * @return {boolean} true if the tx has outgoing funds, false otherwise + */ + getIsOutgoing(): boolean { + return this.isOutgoing; + } + + /** + * @param {boolean} isOutgoing - true if the tx has outgoing funds, false otherwise + * @return {MoneroTxWallet} this tx for chaining + */ + setIsOutgoing(isOutgoing: boolean): MoneroTxWallet { + this.isOutgoing = isOutgoing; + return this; + } + + /** + * @return {bigint} amount received in the tx + */ + getIncomingAmount(): bigint { + if (this.getIncomingTransfers() === undefined) return undefined; + let incomingAmt = 0n; + for (let transfer of this.getIncomingTransfers()) incomingAmt = incomingAmt + transfer.getAmount(); + return incomingAmt; + } + + /** + * @return {bigint} amount spent in the tx + */ + getOutgoingAmount(): bigint { + return this.getOutgoingTransfer() ? this.getOutgoingTransfer().getAmount() : undefined; + } + + /** + * @param {MoneroTransferQuery} [transferQuery] - query to get specific transfers + * @return {MoneroTransfer[]} transfers matching the query + */ + getTransfers(transferQuery?: MoneroTransferQuery): MoneroTransfer[] { + let transfers = []; + if (this.getOutgoingTransfer() && (!transferQuery || transferQuery.meetsCriteria(this.getOutgoingTransfer()))) transfers.push(this.getOutgoingTransfer()); + if (this.getIncomingTransfers() !== undefined) { + for (let transfer of this.getIncomingTransfers()) { + if (!transferQuery || transferQuery.meetsCriteria(transfer)) transfers.push(transfer); + } + } + return transfers; + } + + /** + * @param {MoneroTransferQuery} transferQuery - query to keep only specific transfers + * @return {MoneroTransfer[]} remaining transfers matching the query + */ + filterTransfers(transferQuery: MoneroTransferQuery): MoneroTransfer[] { + let transfers = []; + + // collect outgoing transfer or erase if filtered + if (this.getOutgoingTransfer() && (!transferQuery || transferQuery.meetsCriteria(this.getOutgoingTransfer()))) transfers.push(this.getOutgoingTransfer()); + else this.setOutgoingTransfer(undefined); + + // collect incoming transfers or erase if filtered + if (this.getIncomingTransfers() !== undefined) { + let toRemoves = []; + for (let transfer of this.getIncomingTransfers()) { + if (transferQuery.meetsCriteria(transfer)) transfers.push(transfer); + else toRemoves.push(transfer); + } + this.setIncomingTransfers(this.getIncomingTransfers().filter(function(transfer) { + return !toRemoves.includes(transfer); + })); + if (this.getIncomingTransfers().length === 0) this.setIncomingTransfers(undefined); + } + + return transfers; + } + + /** + * @return {MoneroIncomingTransfer[]} incoming transfers + */ + getIncomingTransfers(): MoneroIncomingTransfer[] { + return this.incomingTransfers; + } + + /** + * @param {MoneroIncomingTransfer[]} incomingTransfers - incoming transfers + * @return {MoneroTxWallet} this tx for chaining + */ + setIncomingTransfers(incomingTransfers: MoneroIncomingTransfer[]): MoneroTxWallet { + this.incomingTransfers = incomingTransfers; + return this; + } + + /** + * @return {MoneroOutgoingTransfer} outgoing transfers + */ + getOutgoingTransfer(): MoneroOutgoingTransfer { + return this.outgoingTransfer; + } + + /** + * @param {MoneroOutgoingTransfer} outgoingTransfer - outgoing transfer + * @return {MoneroTxWallet} this tx for chaining + */ + setOutgoingTransfer(outgoingTransfer: MoneroOutgoingTransfer): MoneroTxWallet { + this.outgoingTransfer = outgoingTransfer; + return this; + } + + /** + * @param {MoneroOutputWallet[]} outputQuery - query to get specific inputs + * @return {MoneroOutputWallet[]} inputs matching the query + */ + getInputsWallet(outputQuery?: MoneroOutputQuery): MoneroOutputWallet[] { + let inputs: MoneroOutputWallet[] = []; + for (let output of super.getInputs()) if (!outputQuery || outputQuery.meetsCriteria(output as MoneroOutputWallet)) inputs.push(output as MoneroOutputWallet); + return inputs; + } + + /** + * @param {MoneroOutputWallet[]} inputs - tx inputs + * @return {MoneroTxWallet} this tx for chaining + */ + setInputsWallet(inputs: MoneroOutputWallet[]): MoneroTxWallet { + + // validate that all inputs are wallet inputs + if (inputs) { + for (let output of inputs) { + if (!(output instanceof MoneroOutputWallet)) throw new MoneroError("Wallet transaction inputs must be of type MoneroOutputWallet"); + } + } + super.setInputs(inputs); + return this; + } + + /** + * @param {MoneroOutputQuery} [outputQuery] - query to get specific outputs + * @return {MoneroOutputWallet[]} outputs matching the query + */ + getOutputsWallet(outputQuery?: MoneroOutputQuery): MoneroOutputWallet[] { + let outputs = []; + for (let output of super.getOutputs()) if (!outputQuery || outputQuery.meetsCriteria(output as MoneroOutputWallet)) outputs.push(output); + return outputs; + } + + /** + * @param {MoneroOutputWallet[]} outputs - tx outputs + * @return {MoneroTxWallet} this tx for chaining + */ + setOutputsWallet(outputs: MoneroOutputWallet[]): MoneroTxWallet { + + // validate that all outputs are wallet outputs + if (outputs) { + for (let output of outputs) { + if (!(output instanceof MoneroOutputWallet)) throw new MoneroError("Wallet transaction outputs must be of type MoneroOutputWallet"); + } + } + super.setOutputs(outputs); + return this; + } + + /** + * @param {MoneroOutputQuery} outputQuery - query to keep only specific outputs + * @return {MoneroTransfer[]} remaining outputs matching the query + */ + filterOutputs(outputQuery: MoneroOutputQuery): MoneroTransfer[] { + let outputs = []; + if (super.getOutputs()) { + let toRemoves = []; + for (let output of super.getOutputs()) { + if (!outputQuery || outputQuery.meetsCriteria(output as MoneroOutputWallet)) outputs.push(output); + else toRemoves.push(output); + } + this.setOutputs(super.getOutputs().filter(function(output) { + return !toRemoves.includes(output); + })); + if (this.getOutputs().length === 0) this.setOutputs(undefined); + } + return outputs; + } + + /** + * @return {string} tx note + */ + getNote(): string { + return this.note; + } + + /** + * @param {string} note - tx note + * @return {MoneroTxWallet} this tx for chaining + */ + setNote(note: string): MoneroTxWallet { + this.note = note; + return this; + } + + /** + * @return {boolean} true if the tx is locked, false otherwise + */ + getIsLocked(): boolean { + return this.isLocked; + } + + /** + * @param {boolean} isLocked - true if the tx is locked, false otherwise + * @return {MoneroTxWallet} this tx for chaining + */ + setIsLocked(isLocked: boolean): MoneroTxWallet { + this.isLocked = isLocked; + return this; + } + + /** + * @return {bigint} sum of tx inputs + */ + getInputSum(): bigint { + return this.inputSum; + } + + /** + * @param {bigint} inputSum - sum of tx inputs + * @return {MoneroTxWallet} this tx for chaining + */ + setInputSum(inputSum: bigint): MoneroTxWallet { + this.inputSum = inputSum; + return this; + } + + /** + * @return {bigint} sum of tx outputs + */ + getOutputSum(): bigint { + return this.outputSum; + } + + /** + * @param {bigint} outputSum - sum of tx outputs + * @return {MoneroTxWallet} this tx for chaining + */ + setOutputSum(outputSum: bigint): MoneroTxWallet { + this.outputSum = outputSum; + return this; + } + + /** + * @return {string} change address + */ + getChangeAddress(): string { + return this.changeAddress; + } + + /** + * @param {string} changeAddress - change address + * @return {MoneroTxWallet} this tx for chaining + */ + setChangeAddress(changeAddress: string): MoneroTxWallet { + this.changeAddress = changeAddress; + return this; + } + + /** + * @return {bigint} change amount + */ + getChangeAmount(): bigint { + return this.changeAmount; + } + + /** + * @param {bigint} changeAmount - change amount + * @return {MoneroTxWallet} this tx for chaining + */ + setChangeAmount(changeAmount: bigint): MoneroTxWallet { + this.changeAmount = changeAmount; + return this; + } + + /** + * @return {number} number of dummy outputs + */ + getNumDummyOutputs(): number { + return this.numDummyOutputs; + } + + /** + * @param {number} numDummyOutputs - number of dummy outputs + * @return {MoneroTxWallet} this tx for chaining + */ + setNumDummyOutputs(numDummyOutputs: number): MoneroTxWallet { + this.numDummyOutputs = numDummyOutputs; + return this; + } + + /** + * @return {string} tx extra as hex + */ + getExtraHex(): string { + return this.extraHex; + } + + /** + * @param {string} extraHex - tx extra as hex + * @return {MoneroTxWallet} this tx for chaining + */ + setExtraHex(extraHex: string): MoneroTxWallet { + this.extraHex = extraHex; + return this; + } + + /** + * @return {MoneroTxWallet} a copy of this tx + */ + copy(): MoneroTxWallet { + return new MoneroTxWallet(this); + } + + /** + * Updates this transaction by merging the latest information from the given + * transaction. + * + * Merging can modify or build references to the transaction given so it + * should not be re-used or it should be copied before calling this method. + * + * @param {MoneroTxWallet} tx - the transaction to merge into this transaction + */ + merge(tx: MoneroTxWallet): MoneroTxWallet { + assert(tx instanceof MoneroTxWallet); + if (this === tx) return this; + + // merge base classes + super.merge(tx); + + // merge tx set if they're different which comes back to merging txs + //import MoneroTxSet from "./MoneroTxSet"; + if (this.getTxSet() !== tx.getTxSet()) { + if (this.getTxSet() == undefined) { + this.setTxSet(new MoneroTxSet().setTxs([this])); + } + if (tx.getTxSet() === undefined) { + tx.setTxSet(new MoneroTxSet().setTxs([tx])); + } + this.getTxSet().merge(tx.getTxSet()); + return this; + } + + // merge incoming transfers + if (tx.getIncomingTransfers()) { + if (this.getIncomingTransfers() === undefined) this.setIncomingTransfers([]); + for (let transfer of tx.getIncomingTransfers()) { + transfer.setTx(this); + MoneroTxWallet.mergeIncomingTransfer(this.getIncomingTransfers(), transfer); + } + } + + // merge outgoing transfer + if (tx.getOutgoingTransfer()) { + tx.getOutgoingTransfer().setTx(this); + if (this.getOutgoingTransfer() === undefined) this.setOutgoingTransfer(tx.getOutgoingTransfer()); + else this.getOutgoingTransfer().merge(tx.getOutgoingTransfer()); + } + + // merge simple extensions + this.setIsIncoming(GenUtils.reconcile(this.getIsIncoming(), tx.getIsIncoming(), {resolveTrue: true})); // outputs seen on confirmation + this.setIsOutgoing(GenUtils.reconcile(this.getIsOutgoing(), tx.getIsOutgoing())); + this.setNote(GenUtils.reconcile(this.getNote(), tx.getNote())); + this.setIsLocked(GenUtils.reconcile(this.getIsLocked(), tx.getIsLocked(), {resolveTrue: false})); // tx can become unlocked + this.setInputSum(GenUtils.reconcile(this.getInputSum(), tx.getInputSum())); + this.setOutputSum(GenUtils.reconcile(this.getOutputSum(), tx.getOutputSum())); + this.setChangeAddress(GenUtils.reconcile(this.getChangeAddress(), tx.getChangeAddress())); + this.setChangeAmount(GenUtils.reconcile(this.getChangeAmount(), tx.getChangeAmount())); + this.setNumDummyOutputs(GenUtils.reconcile(this.getNumDummyOutputs(), tx.getNumDummyOutputs())); + this.setExtraHex(GenUtils.reconcile(this.getExtraHex(), tx.getExtraHex())); + + return this; // for chaining + } + + /** + * @param {number} [indent] - starting indentation + * @param {boolean} [oneLine] - string is one line if true, multiple lines if false + * @return {string} string representation of this tx + */ + toString(indent = 0, oneLine = false): string { + let str = ""; + + // represent tx with one line string + // TODO: proper csv export + if (oneLine) { + str += this.getHash() + ", "; + str += (this.getIsConfirmed() ? this.getBlock().getTimestamp() : this.getReceivedTimestamp()) + ", "; + str += this.getIsConfirmed() + ", "; + str += (this.getOutgoingAmount() ? this.getOutgoingAmount().toString() : "") + ", "; + str += this.getIncomingAmount() ? this.getIncomingAmount().toString() : ""; + return str; + } + + // otherwise stringify all fields + str += super.toString(indent) + "\n"; + str += GenUtils.kvLine("Is incoming", this.getIsIncoming(), indent); + str += GenUtils.kvLine("Incoming amount", this.getIncomingAmount(), indent); + if (this.getIncomingTransfers() !== undefined) { + str += GenUtils.kvLine("Incoming transfers", "", indent); + for (let i = 0; i < this.getIncomingTransfers().length; i++) { + str += GenUtils.kvLine(i + 1, "", indent + 1); + str += this.getIncomingTransfers()[i].toString(indent + 2) + "\n"; + } + } + str += GenUtils.kvLine("Is outgoing", this.getIsOutgoing(), indent); + str += GenUtils.kvLine("Outgoing amount", this.getOutgoingAmount(), indent); + if (this.getOutgoingTransfer() !== undefined) { + str += GenUtils.kvLine("Outgoing transfer", "", indent); + str += this.getOutgoingTransfer().toString(indent + 1) + "\n"; + } + str += GenUtils.kvLine("Note", this.getNote(), indent); + str += GenUtils.kvLine("Is locked", this.getIsLocked(), indent); + str += GenUtils.kvLine("Input sum", this.getInputSum(), indent); + str += GenUtils.kvLine("Output sum", this.getOutputSum(), indent); + str += GenUtils.kvLine("Change address", this.getChangeAddress(), indent); + str += GenUtils.kvLine("Change amount", this.getChangeAmount(), indent); + str += GenUtils.kvLine("Num dummy outputs", this.getNumDummyOutputs(), indent); + str += GenUtils.kvLine("Extra hex", this.getExtraHex(), indent); + return str.slice(0, str.length - 1); // strip last newline + } + + // private helper to merge transfers + protected static mergeIncomingTransfer(transfers, transfer) { + for (let aTransfer of transfers) { + if (aTransfer.getAccountIndex() === transfer.getAccountIndex() && aTransfer.getSubaddressIndex() === transfer.getSubaddressIndex()) { + aTransfer.merge(transfer); + return; + } + } + transfers.push(transfer); + } + + // -------------------- OVERRIDE COVARIANT RETURN TYPES --------------------- + + setBlock(block: MoneroBlock): MoneroTxWallet { + super.setBlock(block); + return this; + } + + setHash(hash: string): MoneroTxWallet { + super.setHash(hash); + return this; + } + + setVersion(version: number): MoneroTxWallet { + super.setVersion(version); + return this; + } + + setIsMinerTx(isMinerTx: boolean): MoneroTxWallet { + super.setIsMinerTx(isMinerTx); + return this; + } + + setPaymentId(paymentId: string): MoneroTxWallet { + super.setPaymentId(paymentId); + return this; + } + + setFee(fee: bigint): MoneroTxWallet { + super.setFee(fee); + return this; + } + + setRingSize(ringSize: number): MoneroTxWallet { + super.setRingSize(ringSize); + return this; + } + + setRelay(relay: boolean): MoneroTxWallet { + super.setRelay(relay); + return this; + } + + setIsRelayed(isRelayed: boolean): MoneroTxWallet { + super.setIsRelayed(isRelayed); + return this; + } + + setIsConfirmed(isConfirmed: boolean): MoneroTxWallet { + super.setIsConfirmed(isConfirmed); + return this; + } + + setInTxPool(inTxPool: boolean): MoneroTxWallet { + super.setInTxPool(inTxPool); + return this; + } + + setNumConfirmations(numConfirmations: number): MoneroTxWallet { + super.setNumConfirmations(numConfirmations); + return this; + } + + setUnlockTime(unlockTime: bigint): MoneroTxWallet { + super.setUnlockTime(unlockTime); + return this; + } + + setLastRelayedTimestamp(lastRelayedTimestamp: number): MoneroTxWallet { + super.setLastRelayedTimestamp(lastRelayedTimestamp); + return this; + } + + setReceivedTimestamp(receivedTimestamp: number): MoneroTxWallet { + super.setReceivedTimestamp(receivedTimestamp); + return this; + } + + setIsDoubleSpendSeen(isDoubleSpendSeen: boolean): MoneroTxWallet { + super.setIsDoubleSpendSeen(isDoubleSpendSeen); + return this; + } + + setKey(key: string): MoneroTxWallet { + super.setKey(key); + return this; + } + + setFullHex(fullHex: string): MoneroTxWallet { + super.setFullHex(fullHex); + return this; + } + + setPrunedHex(prunedHex: string): MoneroTxWallet { + super.setPrunedHex(prunedHex); + return this; + } + + setPrunableHex(prunableHex: string): MoneroTxWallet { + super.setPrunableHex(prunableHex); + return this; + } + + setPrunableHash(prunableHash: string): MoneroTxWallet { + super.setPrunableHash(prunableHash); + return this; + } + + setSize(size: number): MoneroTxWallet { + super.setSize(size); + return this; + } + + setWeight(weight: number): MoneroTxWallet { + super.setWeight(weight); + return this; + } + + setInputs(inputs: MoneroOutput[]): MoneroTxWallet { + super.setInputs(inputs); + return this; + } + + setOutputs(outputs: MoneroOutput[]): MoneroTxWallet { + super.setOutputs(outputs); + return this; + } + + setOutputIndices(outputIndices: number[]): MoneroTxWallet { + super.setOutputIndices(outputIndices); + return this; + } + + setMetadata(metadata: string): MoneroTxWallet { + super.setMetadata(metadata); + return this; + } + + setExtra(extra: Uint8Array): MoneroTxWallet { + super.setExtra(extra); + return this; + } + + setRctSignatures(rctSignatures: any): MoneroTxWallet { + super.setRctSignatures(rctSignatures); + return this; + } + + setRctSigPrunable(rctSigPrunable: any): MoneroTxWallet { + super.setRctSigPrunable(rctSigPrunable); + return this; + } + + setIsKeptByBlock(isKeptByBlock: boolean): MoneroTxWallet { + super.setIsKeptByBlock(isKeptByBlock); + return this; + } + + setIsFailed(isFailed: boolean): MoneroTxWallet { + super.setIsFailed(isFailed); + return this; + } + + setLastFailedHeight(lastFailedHeight: number): MoneroTxWallet { + super.setLastFailedHeight(lastFailedHeight); + return this; + } + + setLastFailedHash(lastFailedHash: string): MoneroTxWallet { + super.setLastFailedHash(lastFailedHash); + return this; + } + + setMaxUsedBlockHeight(maxUsedBlockHeight: number): MoneroTxWallet { + super.setMaxUsedBlockHeight(maxUsedBlockHeight); + return this; + } + + setMaxUsedBlockHash(maxUsedBlockHash: string): MoneroTxWallet { + super.setMaxUsedBlockHash(maxUsedBlockHash); + return this; + } + + setSignatures(signatures: string[]): MoneroTxWallet { + super.setSignatures(signatures); + return this; + } +} diff --git a/src/main/ts/wallet/model/MoneroWalletConfig.ts b/src/main/ts/wallet/model/MoneroWalletConfig.ts new file mode 100644 index 000000000..2d22a0804 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroWalletConfig.ts @@ -0,0 +1,304 @@ +import MoneroConnectionManager from "../../common/MoneroConnectionManager"; +import MoneroNetworkType from "../../daemon/model/MoneroNetworkType"; +import MoneroRpcConnection from "../../common/MoneroRpcConnection"; +import MoneroUtils from "../../common/MoneroUtils"; + +/** + * Configuration to create a Monero wallet. + */ +export default class MoneroWalletConfig { + + /** Path to the wallet to open or create. */ + path: string; + + /** Password of the wallet to open or create. */ + password: string; + + /** Network type of the wallet to open or create. */ + networkType: MoneroNetworkType; + + /** Server config to monerod or monero-wallet-rpc. */ + server: string | Partial; + + /** Govern the wallet's server connection. */ + connectionManager: MoneroConnectionManager; + + /** Seed of the wallet to ceate (random wallet created if neither seed nor keys given). */ + seed: string; + + /** Offset to derive a new seed from the given seed to recover a secret wallet. */ + seedOffset: string; + + /** Indicates if the wallet seed is multisig. */ + isMultisig: boolean; + + /** Primary address of the wallet to create (only provide if restoring from keys). */ + primaryAddress: string; + + /** Private view key of the wallet to create. */ + privateViewKey: string; + + /** Private spend key of the wallet to create. */ + privateSpendKey: string; + + /** Block height to start scanning from (defaults to 0 unless generating random wallet). */ + restoreHeight: number; + + /** Language of the wallet's seed phrase (defaults to "English" or auto-detected). */ + language: string; + + /** Specifies if the currently open RPC wallet should be saved before being closed. */ + saveCurrent: boolean; + + /** Proxies wallet operations to a worker in order to not block the main thread (default true). */ + proxyToWorker: boolean; + + /** File system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser). */ + fs: any; + + /** Wallet keys data to open. */ + keysData: Uint8Array; + + /** Wallet cache data to open. */ + cacheData: Uint8Array; + + /** Number of accounts to scan (optional). */ + accountLookahead: number; + + /** Number of subaddresses to scan per account (optional). */ + subaddressLookahead: number; + + /** Command to start monero-wallet-rpc as a child process. */ + cmd: string[]; + + /** + * Construct a configuration to open or create a wallet. + * + * @param {Partial} [config] - MoneroWalletConfig or equivalent config object + * @param {string} [config.path] - path of the wallet to open or create + * @param {string} [config.password] - password of the wallet to open + * @param {string|number} [config.networkType] - network type of the wallet to open (one of "mainnet", "testnet", "stagenet" or MoneroNetworkType.MAINNET|TESTNET|STAGENET) + * @param {string} [config.seed] - seed of the wallet to create (optional, random wallet created if neither seed nor keys given) + * @param {string} [config.seedOffset] - the offset used to derive a new seed from the given seed to recover a secret wallet from the seed phrase + * @param {boolean} [config.isMultisig] - restore multisig wallet from seed + * @param {string} [config.primaryAddress] - primary address of the wallet to create (only provide if restoring from keys) + * @param {string} [config.privateViewKey] - private view key of the wallet to create (optional) + * @param {string} [config.privateSpendKey] - private spend key of the wallet to create (optional) + * @param {number} [config.restoreHeight] - block height to start scanning from (defaults to 0 unless generating random wallet) + * @param {string} [config.language] - language of the wallet's seed phrase (defaults to "English" or auto-detected) + * @param {number} [config.accountLookahead] - number of accounts to scan (optional) + * @param {number} [config.subaddressLookahead] - number of subaddresses to scan per account (optional) + * @param {string|Partial} [config.server] - uri or MoneroRpcConnection to the wallet's server (optional) + * @param {MoneroConnectionManager} [config.connectionManager] - manage connections to monerod (optional) + * @param {boolean} [config.rejectUnauthorized] - reject self-signed server certificates if true (default true) + * @param {Uint8Array} [config.keysData] - wallet keys data to open (optional) + * @param {Uint8Array} [config.cacheData] - wallet cache data to open (optional) + * @param {boolean} [config.proxyToWorker] - proxies wallet operations to a worker in order to not block the main thread (default true) + * @param {any} [config.fs] - file system compatible with Node.js `fs.promises` API (defaults to disk or in-memory FS if browser) + * @param {boolean} [config.saveCurrent] - specifies if the current RPC wallet should be saved before being closed + * @param {number} [config.accountLookahead] - number of accounts to scan (optional) + * @param {number} [config.subaddressLookahead] - number of subaddresses to scan per account (optional) + * @param {string[]} [config.cmd] - command to start wallet daemon (optional) + */ + constructor(config?: Partial) { + Object.assign(this, config); + + // normalize config + if (this.server) this.setServer(this.server); + this.setProxyToWorker(this.proxyToWorker); + if (this.networkType !== undefined) this.networkType = MoneroNetworkType.from(this.networkType); + } + + copy(): MoneroWalletConfig { + return new MoneroWalletConfig(this); + } + + toJson(): any { + let json: any = Object.assign({}, this); + if (json.server) json.server = json.server.toJson(); + json.fs = undefined; + json.connectionManager = undefined; + return json; + } + + getPath(): string { + return this.path; + } + + setPath(path: string): MoneroWalletConfig { + this.path = path; + return this; + } + + getPassword(): string { + return this.password; + } + + setPassword(password): MoneroWalletConfig { + this.password = password; + return this; + } + + getNetworkType(): MoneroNetworkType { + return this.networkType; + } + + setNetworkType(networkTypeOrStr: MoneroNetworkType | string): MoneroWalletConfig { + this.networkType = networkTypeOrStr === undefined ? undefined : MoneroNetworkType.from(networkTypeOrStr); + return this; + } + + getServer(): MoneroRpcConnection { + return this.server as MoneroRpcConnection; + } + + setServer(server: Partial | string): MoneroWalletConfig { + if (server && !(server instanceof MoneroRpcConnection)) server = new MoneroRpcConnection(server); + this.server = server as MoneroRpcConnection; + return this; + } + + getConnectionManager(): MoneroConnectionManager { + return this.connectionManager; + } + + setConnectionManager(connectionManager: MoneroConnectionManager): MoneroWalletConfig { + this.connectionManager = connectionManager; + return this; + } + + getSeed(): string { + return this.seed; + } + + setSeed(seed: string): MoneroWalletConfig { + this.seed = seed; + return this; + } + + getSeedOffset(): string { + return this.seedOffset; + } + + setSeedOffset(seedOffset: string): MoneroWalletConfig { + this.seedOffset = seedOffset; + return this; + } + + getIsMultisig(): boolean { + return this.isMultisig; + } + + setIsMultisig(isMultisig: boolean): MoneroWalletConfig { + this.isMultisig = isMultisig; + return this; + } + + getPrimaryAddress(): string { + return this.primaryAddress; + } + + setPrimaryAddress(primaryAddress: string) { + this.primaryAddress = primaryAddress; + return this; + } + + getPrivateViewKey(): string { + return this.privateViewKey; + } + + setPrivateViewKey(privateViewKey): MoneroWalletConfig { + this.privateViewKey = privateViewKey; + return this; + } + + getPrivateSpendKey(): string { + return this.privateSpendKey; + } + + setPrivateSpendKey(privateSpendKey: string): MoneroWalletConfig { + this.privateSpendKey = privateSpendKey; + return this; + } + + getRestoreHeight(): number { + return this.restoreHeight; + } + + setRestoreHeight(restoreHeight: number): MoneroWalletConfig { + this.restoreHeight = restoreHeight; + return this; + } + + getLanguage(): string { + return this.language; + } + + setLanguage(language: string): MoneroWalletConfig { + this.language = language; + return this; + } + + getSaveCurrent(): boolean { + return this.saveCurrent; + } + + setSaveCurrent(saveCurrent: boolean): MoneroWalletConfig { + this.saveCurrent = saveCurrent; + return this; + } + + getProxyToWorker(): boolean { + return this.proxyToWorker; + } + + setProxyToWorker(proxyToWorker: boolean): MoneroWalletConfig { + this.proxyToWorker = proxyToWorker; + return this; + } + + getFs(): any { + return this.fs; + } + + setFs(fs: any) { + this.fs = fs; + return this; + } + + getKeysData(): Uint8Array { + return this.keysData; + } + + setKeysData(keysData: Uint8Array): MoneroWalletConfig { + this.keysData = keysData; + return this; + } + + getCacheData(): Uint8Array { + return this.cacheData; + } + + setCacheData(cacheData: Uint8Array): MoneroWalletConfig { + this.cacheData = cacheData; + return this; + } + + getAccountLookahead(): number { + return this.accountLookahead; + } + + setAccountLookahead(accountLookahead: number): MoneroWalletConfig { + this.accountLookahead = accountLookahead; + return this; + } + + getSubaddressLookahead(): number { + return this.subaddressLookahead; + } + + setSubaddressLookahead(subaddressLookahead: number): MoneroWalletConfig { + this.subaddressLookahead = subaddressLookahead; + return this; + } +} \ No newline at end of file diff --git a/src/main/ts/wallet/model/MoneroWalletListener.ts b/src/main/ts/wallet/model/MoneroWalletListener.ts new file mode 100644 index 000000000..81c8ef209 --- /dev/null +++ b/src/main/ts/wallet/model/MoneroWalletListener.ts @@ -0,0 +1,57 @@ +import MoneroOutputWallet from "./MoneroOutputWallet"; + +/** + * Default wallet listener which takes no action on notifications. + */ +export default class MoneroWalletListener { + + /** + * Invoked as the wallet is synchronized. + * + * @param {number} height - height of the synced block + * @param {number} startHeight - starting height of the sync request + * @param {number} endHeight - ending height of the sync request + * @param {number} percentDone - sync progress as a percentage + * @param {string} message - human-readable description of the current progress + * @return {Promise} + */ + async onSyncProgress(height: number, startHeight: number, endHeight: number, percentDone: number, message: string) { } + + /** + * Invoked when a new block is added to the chain. + * + * @param {number} height - the height of the new block (i.e. the number of blocks before it). + * @return {Promise} + */ + async onNewBlock(height: number): Promise { } + + /** + * Invoked when the wallet's balances change. + * + * @param {bigint} newBalance - new wallet balance + * @param {bigint} newUnlockedBalance - new unlocked wallet balance + * @return {Promise} + */ + async onBalancesChanged(newBalance: bigint, newUnlockedBalance: bigint): Promise { } + + /** + * Invoked 3 times per received output: once when unconfirmed, once when confirmed, and + * once when unlocked. + * + * The notified output includes basic fields only, so the output or its transaction should be fetched to get all available fields. + * + * @param {MoneroOutputWallet} output - the received output + * @return {Promise} + */ + async onOutputReceived(output: MoneroOutputWallet): Promise { } + + /** + * Invoked twice per spent output: once when confirmed and once when unlocked. + * + * The notified output includes basic fields only, so the output or its transaction should be fetched to get all available fields. + * + * @param {MoneroOutputWallet} output - the spent output + * @return {Promise} + */ + async onOutputSpent(output): Promise { } +} diff --git a/src/test/Scratchpad.js b/src/test/Scratchpad.js deleted file mode 100644 index 35f8334a7..000000000 --- a/src/test/Scratchpad.js +++ /dev/null @@ -1,54 +0,0 @@ -const TestUtils = require("./utils/TestUtils"); -const WalletSyncPrinter = require("./utils/WalletSyncPrinter"); -const monerojs = require("../../index"); - -describe("Scratchpad", function() { - - it("Can be scripted easily", async function() { - - // get test wasm wallet -// let daemon = await TestUtils.getDaemonRpc(); -// let walletRpc = await TestUtils.getWalletRpc(); -// let walletWasm = await TestUtils.getWalletWasm(); - - - // initialize daemon rpc client - let daemon = monerojs.connectToDaemonRpc({ - uri: "http://localhost:38081", - username: "superuser", - password: "abctesting123", - proxyToWorker: TestUtils.PROXY_TO_WORKER, - rejectUnauthorized: false - }); - console.log("Daemon height: " + await daemon.getHeight()); - - // initialize wallet rpc client - let walletRpc = monerojs.connectToWalletRpc({ - uri: "http://localhost:38083", - username: "rpc_user", - password: "abc123", - rejectUnauthorized: false - }); - //await walletRpc.openWallet("test_wallet_1", "supersecretpassword123"); - console.log("RPC wallet mnemonic: " + await walletRpc.getMnemonic()); - - // create in-memory wallet with mnemonic - let walletWasm = await monerojs.createWalletWasm({ - //path: "./test_wallets/" + GenUtils.getUUID(), // in-memory wallet if not given - password: "abctesting123", - networkType: "stagenet", - serverUri: "http://localhost:38081", - serverUsername: "superuser", - serverPassword: "abctesting123", - mnemonic: "hijack lucky rally sober hockey robot gumball amaze gave fifteen organs gecko skater wizard demonstrate upright system vegan tobacco tsunami lurk withdrawn tomorrow uphill organs", - restoreHeight: 0, - proxyToWorker: TestUtils.PROXY_TO_WORKER, - rejectUnauthorized: false - }); - await walletWasm.sync(new WalletSyncPrinter()); - console.log("WASM wallet daemon height: " + await walletWasm.getDaemonHeight()); - console.log("WASM wallet mnemonic: " + await walletWasm.getMnemonic()); - - await walletWasm.close(); - }); -}); \ No newline at end of file diff --git a/src/test/Scratchpad.ts b/src/test/Scratchpad.ts new file mode 100644 index 000000000..eb112b552 --- /dev/null +++ b/src/test/Scratchpad.ts @@ -0,0 +1,57 @@ +import TestUtils from "./utils/TestUtils"; +import WalletSyncPrinter from "./utils/WalletSyncPrinter"; +import {connectToDaemonRpc, + connectToWalletRpc, + createWalletFull, + MoneroNetworkType} from "../../index"; + +describe("Scratchpad", function() { + + it("Can be scripted easily", async function() { + +// let daemon = await TestUtils.getDaemonRpc(); +// let walletRpc = await TestUtils.getWalletRpc(); +// let walletFull = await TestUtils.getWalletFull(); + + // initialize daemon rpc client + let daemon = await connectToDaemonRpc({ + uri: "http://localhost:28081", + username: "superuser", + password: "abctesting123", + proxyToWorker: TestUtils.PROXY_TO_WORKER, + rejectUnauthorized: false + }); + console.log("Daemon height: " + await daemon.getHeight()); + + // initialize wallet rpc client + let walletRpc = await connectToWalletRpc({ + uri: "http://localhost:28084", + username: "rpc_user", + password: "abc123", + rejectUnauthorized: false + }); + await walletRpc.openWallet("test_wallet_1", "supersecretpassword123"); + console.log("RPC wallet seed: " + await walletRpc.getSeed()); + + // create in-memory wallet with mnemonic + let walletFull = await createWalletFull({ + //path: "./test_wallets/" + GenUtils.getUUID(), // in-memory wallet if not given + password: "supersecretpassword123", + networkType: MoneroNetworkType.TESTNET, + server: { + uri: "http://localhost:28081", + username: "superuser", + password: "abctesting123", + rejectUnauthorized: false + }, + seed: "silk mocked cucumber lettuce hope adrenalin aching lush roles fuel revamp baptism wrist long tender teardrop midst pastry pigment equip frying inbound pinched ravine frying", + restoreHeight: 0, + proxyToWorker: TestUtils.PROXY_TO_WORKER, + }); + await walletFull.sync(new WalletSyncPrinter()); + console.log("Full wallet daemon height: " + await walletFull.getDaemonHeight()); + console.log("Full wallet seed: " + await walletFull.getSeed()); + console.log("Wallet balance: " + (await walletFull.getUnlockedBalance()).toString()) + await walletFull.close(); + }); +}); diff --git a/src/test/TestAll.js b/src/test/TestAll.ts similarity index 50% rename from src/test/TestAll.js rename to src/test/TestAll.ts index 600a0846d..5ecaa1dd0 100644 --- a/src/test/TestAll.js +++ b/src/test/TestAll.ts @@ -1,11 +1,15 @@ // import test types -const TestSampleCode = require("./TestSampleCode"); -const TestMoneroUtils = require("./TestMoneroUtils"); -const TestMoneroDaemonRpc = require("./TestMoneroDaemonRpc"); -const TestMoneroWalletKeys = require("./TestMoneroWalletKeys"); -const TestMoneroWalletWasm = require("./TestMoneroWalletWasm"); -const TestMoneroWalletRpc = require("./TestMoneroWalletRpc"); -const TestDeveloperGuide = require("./TestDeveloperGuide"); +import {LibraryUtils} from "../../index"; +import TestSampleCode from "./TestSampleCode"; +import TestMoneroUtils from "./TestMoneroUtils"; +import TestMoneroDaemonRpc from "./TestMoneroDaemonRpc"; +import TestMoneroWalletKeys from "./TestMoneroWalletKeys"; +import TestMoneroWalletFull from "./TestMoneroWalletFull"; +import TestMoneroWalletRpc from "./TestMoneroWalletRpc"; +import TestMoneroConnectionManager from "./TestMoneroConnectionManager"; + +// set log level +LibraryUtils.setLogLevel(1); // no need for await before worker used // test sample code for readme new TestSampleCode().runTests(); @@ -26,17 +30,17 @@ new TestMoneroWalletKeys({ liteMode: false, testNonRelays: true, testRelays: false, - testResets: false, - testNotifications: false + testNotifications: false, + testResets: false }).runTests(); -// test wasm wallet -new TestMoneroWalletWasm({ +// test full wallet +new TestMoneroWalletFull({ liteMode: false, testNonRelays: true, testRelays: true, - testResets: false, - testNotifications: true + testNotifications: true, + testResets: false }).runTests(); // test wallet rpc @@ -44,12 +48,12 @@ new TestMoneroWalletRpc({ liteMode: false, testNonRelays: true, testRelays: true, - testNotifications: false, + testNotifications: true, testResets: false }).runTests(); -// test queries for developer guide -new TestDeveloperGuide().runTests(); +// test connection manager +new TestMoneroConnectionManager().runTests(); // test scratchpad -require("./Scratchpad"); \ No newline at end of file +require("./Scratchpad"); diff --git a/src/test/TestDeveloperGuide.js b/src/test/TestDeveloperGuide.js deleted file mode 100644 index 6c801f590..000000000 --- a/src/test/TestDeveloperGuide.js +++ /dev/null @@ -1,282 +0,0 @@ -const assert = require("assert"); -const TestUtils = require("./utils/TestUtils"); -const monerojs = require("../../index"); -const MoneroWalletWasm = monerojs.MoneroWalletWasm; -const MoneroNetworkType = monerojs.MoneroNetworkType; -const MoneroTxPriority = monerojs.MoneroTxPriority; - -/** - * Test the code in the developer guide. - */ -class TestDeveloperGuide { - - runTests() { - describe("Test developer guide", function() { - let that = this; - let wallet; - - // initialize wallet - before(async function() { - try { - wallet = await TestUtils.getWalletWasm(); - } catch (e) { - console.log(e); - } - }); - - // save wallet - after(async function() { - await wallet.close(true); - }); - - it("Test developer guide transaction queries", async function() { - - // get a transaction by hash - let tx = await wallet.getTx("2bcb953fcd29c02474edc495c1ae069d25689039bd605331dcb9bb467615d362"); - - // get unconfirmed transactions - let txs = await wallet.getTxs({ - isConfirmed: false - }); - for (let tx of txs) { - assert(!tx.isConfirmed()); - } - - // get transactions since height 582106 with incoming transfers to - // account 0, subaddress 0 - txs = await wallet.getTxs({ - minHeight: 582106, - transferQuery: { - isIncoming: true, - accountIndex: 0, - subaddressIndex: 1 - } - }); - for (let tx of txs) { - assert(tx.isConfirmed()); - assert(tx.getHeight() >= 582106) - let found = false; - for (let transfer of tx.getTransfers()) { - if (transfer.isIncoming() && transfer.getAccountIndex() === 0 && transfer.getSubaddressIndex() === 1) { - found = true; - break; - } - } - assert(found); - } - - // get transactions with available outputs - txs = await wallet.getTxs({ - isLocked: false, - outputQuery: { - isSpent: false, - } - }); - for (let tx of txs) { - assert(!tx.isLocked()); - assert(tx.getOutputs().length > 0); - let found = false; - for (let output of tx.getOutputs()) { - if (!output.isSpent()) { - found = true; - break; - } - } - if (!found) { - console.log(tx.getOutputs()); - } - assert(found); - } - }); - - it("Test developer guide transfer queries", async function() { - - // get all transfers - let transfers = await wallet.getTransfers(); - - // get incoming transfers to account 0, subaddress 1 - transfers = await wallet.getTransfers({ - isIncoming: true, - accountIndex: 0, - subaddressIndex: 1 - }); - for (let transfer of transfers) { - assert.equal(transfer.isIncoming(), true); - assert.equal(transfer.getAccountIndex(), 0); - assert.equal(transfer.getSubaddressIndex(), 1); - } - - // get transfers in the tx pool - transfers = await wallet.getTransfers({ - txQuery: { - inTxPool: true - } - }); - for (let transfer of transfers) { - assert.equal(transfer.getTx().inTxPool(), true); - } - - // get confirmed outgoing transfers since a block height - transfers = await wallet.getTransfers({ - isOutgoing: true, - txQuery: { - isConfirmed: true, - minHeight: TestUtils.FIRST_RECEIVE_HEIGHT // *** REPLACE WITH NUMBER IN .MD FILE *** - } - }); - assert(transfers.length > 0); - for (let transfer of transfers) { - assert(transfer.isOutgoing()); - assert(transfer.getTx().isConfirmed()); - assert(transfer.getTx().getHeight() >= TestUtils.FIRST_RECEIVE_HEIGHT); - } - }); - - it("Test developer guide output queries", async function() { - - // get all outputs - let outputs = await wallet.getOutputs(); - assert(outputs.length > 0); - - // get outputs available to be spent - outputs = await wallet.getOutputs({ - isSpent: false, - txQuery: { - isLocked: false - } - }); - assert(outputs.length > 0); - for (let output of outputs) { - assert(!output.isSpent()); - assert(!output.getTx().isLocked()); - } - - // get outputs received to a specific subaddress - outputs = await wallet.getOutputs({ - accountIndex: 0, - subaddressIndex: 1 - }); - assert(outputs.length > 0); - for (let output of outputs) { - assert.equal(output.getAccountIndex(), 0); - assert.equal(output.getSubaddressIndex(), 1); - } - - // get output by key image - let keyImage = outputs[0].getKeyImage().getHex(); - outputs = await wallet.getOutputs({ - keyImage: keyImage - }); - assert.equal(outputs.length, 1); - assert.equal(outputs[0].getKeyImage().getHex(), keyImage); - }); - - it("Test developer guide send funds", async function() { - - // create in-memory test wallet with randomly generated mnemonic - let wallet = await monerojs.createWalletWasm({ - password: "abctesting123", - networkType: "stagenet", - serverUri: "http://localhost:38081", - serverUsername: "superuser", - serverPassword: "abctesting123" - }); - - try { - // create a transaction to send funds to an address, but do not relay - let tx = await wallet.createTx({ - accountIndex: 0, // source account to send funds from - address: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", - amount: "1000000000000" // send 1 XMR (denominated in atomic units) - }); - - // can confirm with the user - let fee = tx.getFee(); // "Are you sure you want to send... ?" - - // relay the transaction - let hash = await wallet.relayTx(tx); - } catch (e) { - assert.equal(e.message, "not enough money"); - } - - try { - // send funds to a single destination - let tx = await wallet.createTx({ - accountIndex: 0, // source account to send funds from - address: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", - amount: "1000000000000", // send 1 XMR (denominated in atomic units) - relay: true // relay the transaction to the network - }); - } catch (e) { - assert.equal(e.message, "not enough money"); - } - - try { - // send funds from a specific subaddress to multiple destinations, - // allowing transfers to be split across multiple transactions if needed - let txs = await wallet.createTxs({ - accountIndex: 0, // source account to send funds from - subaddressIndex: 1, // source subaddress to send funds from - destinations: [{ - address: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", - amount: "500000000000", // send 0.5 XMR (denominated in atomic units) - }, { - address: "52f7hei1UMrbvYUNtDMKZJMQjcfVyufYnezER8wVK271VmGbzE2kN7cMMG6qFjrb6Ub6qPkNt815a98kJmo874qG9GYZKD5", - amount: "500000000000", // send 0.5 XMR (denominated in atomic units) - }], - priority: MoneroTxPriority.IMPORTANT, - relay: true // relay the transaction to the network - }); - } catch (e) { - assert.equal(e.message, "not enough money"); - } - - try { - // sweep an output - let tx = await wallet.sweepOutput({ - address: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", - keyImage: "b7afd6afbb1615c98b1c0350b81c98a77d6d4fc0ab92020d25fd76aca0914f1e", - relay: true - }); - } catch (e) { - assert.equal(e.message, "No outputs found"); - } - - try { - // sweep all unlocked funds in a wallet - let txs = await wallet.sweepUnlocked({ - address: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", - relay: true - }); - } catch (e) { - assert.equal(e.message, "No unlocked balance in the entire wallet"); - } - - try { - // sweep unlocked funds in an account - let txs = await wallet.sweepUnlocked({ - accountIndex: 0, - address: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", - relay: true - }); - } catch (e) { - assert.equal(e.message, "No unlocked balance in the entire wallet"); - } - - try { - // sweep unlocked funds in a subaddress - let txs = await wallet.sweepUnlocked({ - accountIndex: 0, - subaddressIndex: 0, - address: "55bcxMRhBWea6xxsot8moF1rdPprjJR2x4mfnNnTGgBJFgXa4gWXmWAYdUBKiRcJxy9AUAGJEg28DejvWdJU2VgUDrUvCHG", - relay: true - }); - } catch (e) { - assert.equal(e.message, "No unlocked balance in the entire wallet"); - } - }); - }); - } -} - -module.exports = TestDeveloperGuide; \ No newline at end of file diff --git a/src/test/TestMoneroConnectionManager.ts b/src/test/TestMoneroConnectionManager.ts new file mode 100644 index 000000000..16e5f7b74 --- /dev/null +++ b/src/test/TestMoneroConnectionManager.ts @@ -0,0 +1,283 @@ +import assert from "assert"; +import TestUtils from "./utils/TestUtils"; +import { + GenUtils, + MoneroWalletRpc, + MoneroConnectionManager, + MoneroConnectionManagerListener, + MoneroRpcConnection +} from "../../index"; + +/** + * Test the Monero RPC connection manager. + */ +class TestMoneroConnectionManager { + + runTests() { + describe("Test connection manager", function() { + it("Can manage connections", async function() { + let err; + let walletRpcs: MoneroWalletRpc[] = []; + let connectionManager: MoneroConnectionManager; + try { + + // start monero-wallet-rpc instances as test server connections (can also use monerod servers) + for (let i = 0; i < 5; i++) walletRpcs.push(await TestUtils.startWalletRpcProcess()); + + // create connection manager + connectionManager = new MoneroConnectionManager(); + + // listen for changes + let listener = new ConnectionChangeCollector(); + connectionManager.addListener(listener); + + // add prioritized connections + await connectionManager.addConnection(walletRpcs[4].getRpcConnection()!.setPriority(1)); + await connectionManager.addConnection(walletRpcs[2].getRpcConnection()!.setPriority(2)); + await connectionManager.addConnection(walletRpcs[3].getRpcConnection()!.setPriority(2)); + await connectionManager.addConnection(walletRpcs[0].getRpcConnection()); // default priority is lowest + await connectionManager.addConnection(new MoneroRpcConnection(walletRpcs[1].getRpcConnection()!.getUri())); // test unauthenticated + + // test connections and order + let orderedConnections = connectionManager.getConnections(); + assert(orderedConnections[0] === walletRpcs[4].getRpcConnection()); + assert(orderedConnections[1] === walletRpcs[2].getRpcConnection()); + assert(orderedConnections[2] === walletRpcs[3].getRpcConnection()); + assert(orderedConnections[3] === walletRpcs[0].getRpcConnection()); + assert.equal(orderedConnections[4].getUri(), (walletRpcs[1].getRpcConnection()!).getUri()); + for (let connection of orderedConnections) assert.equal(undefined, connection.getIsOnline()); + + // test getting connection by uri + assert(connectionManager.hasConnection(walletRpcs[0].getRpcConnection()!.getUri())); + assert(connectionManager.getConnectionByUri(walletRpcs[0].getRpcConnection()!.getUri()) === walletRpcs[0].getRpcConnection()); + + // test unknown connection + let numExpectedChanges = 0; + await connectionManager.setConnection(orderedConnections[0]); + assert.equal(connectionManager.isConnected(), undefined); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + + // auto connect to best available connection + connectionManager.startPolling(TestUtils.SYNC_PERIOD_IN_MS); + await GenUtils.waitFor(TestUtils.AUTO_CONNECT_TIMEOUT_MS); + assert(connectionManager.isConnected()); + let connection = connectionManager.getConnection(); + assert(connection.getIsOnline()); + assert(connection === walletRpcs[4].getRpcConnection()); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + assert(listener.changedConnections[listener.changedConnections.length - 1] === connection); + connectionManager.setAutoSwitch(false); + connectionManager.stopPolling(); + await connectionManager.disconnect(); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + assert(listener.changedConnections[listener.changedConnections.length - 1] === undefined); + + // start periodically checking connection without auto switch + await connectionManager.startPolling(TestUtils.SYNC_PERIOD_IN_MS, false); + + // connect to best available connection in order of priority and response time + connection = await connectionManager.getBestAvailableConnection(); + await connectionManager.setConnection(connection); + assert(connection === walletRpcs[4].getRpcConnection()); + assert(connection.getIsOnline()); + assert(connection.getIsAuthenticated()); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + assert(listener.changedConnections[listener.changedConnections.length - 1] === connection); + + // test connections and order + orderedConnections = connectionManager.getConnections(); + assert(orderedConnections[0] === walletRpcs[4].getRpcConnection()); + assert(orderedConnections[1] === walletRpcs[2].getRpcConnection()); + assert(orderedConnections[2] === walletRpcs[3].getRpcConnection()); + assert(orderedConnections[3] === walletRpcs[0].getRpcConnection()); + assert.equal(orderedConnections[4].getUri(), walletRpcs[1].getRpcConnection()!.getUri()); + for (let i = 1; i < orderedConnections.length; i++) assert.equal(undefined, orderedConnections[i].getIsOnline()); + + // shut down prioritized servers + walletRpcs[2].getRpcConnection()!.setFakeDisconnected(true); // browser does not start or stop instances + walletRpcs[3].getRpcConnection()!.setFakeDisconnected(true); + walletRpcs[4].getRpcConnection()!.setFakeDisconnected(true); + await GenUtils.waitFor(TestUtils.SYNC_PERIOD_IN_MS + 100); + assert.equal(false, connectionManager.isConnected()); + assert.equal(false, connectionManager.getConnection().getIsOnline()); + assert.equal(undefined, connectionManager.getConnection().getIsAuthenticated()); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + assert(listener.changedConnections[listener.changedConnections.length - 1] === connectionManager.getConnection()); + + // test connection order + orderedConnections = connectionManager.getConnections(); + assert(orderedConnections[0] === walletRpcs[4].getRpcConnection()); + assert(orderedConnections[1] === walletRpcs[0].getRpcConnection()); + assert.equal(orderedConnections[2].getUri(), walletRpcs[1].getRpcConnection()!.getUri()); + assert(orderedConnections[3] === walletRpcs[2].getRpcConnection()); + assert(orderedConnections[4] === walletRpcs[3].getRpcConnection()); + + // check all connections + await connectionManager.checkConnections(); + + // test connection order + orderedConnections = connectionManager.getConnections(); + assert(orderedConnections[0] === walletRpcs[4].getRpcConnection()); + assert(orderedConnections[1] === walletRpcs[0].getRpcConnection()); + assert(orderedConnections[2].getUri() === walletRpcs[1].getRpcConnection()!.getUri()); + assert(orderedConnections[3] === walletRpcs[2].getRpcConnection()); + assert(orderedConnections[4] === walletRpcs[3].getRpcConnection()); + + // test online and authentication status + for (let i = 0; i < orderedConnections.length; i++) { + let isOnline = orderedConnections[i].getIsOnline(); + let isAuthenticated = orderedConnections[i].getIsAuthenticated(); + if (i === 1 || i === 2) assert.equal(true, isOnline); + else assert.equal(false, isOnline); + if (i === 1) assert.equal(true, isAuthenticated); + else if (i === 2) assert.equal(false, isAuthenticated); + else assert.equal(undefined, isAuthenticated); + } + + // test auto switch when disconnected + connectionManager.setAutoSwitch(true); + await GenUtils.waitFor(TestUtils.SYNC_PERIOD_IN_MS + 100); // allow time to poll + assert(connectionManager.isConnected()); + connection = connectionManager.getConnection(); + assert(connection.getIsOnline()); + assert(connection === walletRpcs[0].getRpcConnection()); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + assert(listener.changedConnections[listener.changedConnections.length - 1] === connection); + + // test connection order + orderedConnections = connectionManager.getConnections(); + assert(orderedConnections[0] === connection); + assert(orderedConnections[0] === walletRpcs[0].getRpcConnection()); + assert(orderedConnections[1].getUri() === walletRpcs[1].getRpcConnection()!.getUri()); + assert(orderedConnections[2] === walletRpcs[4].getRpcConnection()); + assert(orderedConnections[3] === walletRpcs[2].getRpcConnection()); + assert(orderedConnections[4] === walletRpcs[3].getRpcConnection()); + + // connect to specific endpoint without authentication + connection = orderedConnections[1]; + assert.equal(false, connection.getIsAuthenticated()); + await connectionManager.setConnection(connection); + assert.equal(false, connectionManager.isConnected()); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + + // connect to specific endpoint with authentication + orderedConnections[1].setCredentials("rpc_user", "abc123"); + await connectionManager.checkConnection(); + assert.equal(connectionManager.getConnection().getUri(), walletRpcs[1].getRpcConnection()!.getUri()); + assert.equal(connection.getUri(), walletRpcs[1].getRpcConnection()!.getUri()); + assert(connection.getIsOnline()); + assert(connection.getIsAuthenticated()); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + assert(listener.changedConnections[listener.changedConnections.length - 1] === connection); + + // test connection order + orderedConnections = connectionManager.getConnections(); + assert(orderedConnections[0] === connectionManager.getConnection()); + assert.equal(orderedConnections[0].getUri(), walletRpcs[1].getRpcConnection()!.getUri()); + assert(orderedConnections[1] === walletRpcs[0].getRpcConnection()); + assert(orderedConnections[2] === walletRpcs[4].getRpcConnection()); + assert(orderedConnections[3] === walletRpcs[2].getRpcConnection()); + assert(orderedConnections[4] === walletRpcs[3].getRpcConnection()); + for (let i = 0; i < orderedConnections.length; i++) assert(i <= 1 ? orderedConnections[i].getIsOnline() : !orderedConnections[i].getIsOnline()); + + // set connection to existing uri + await connectionManager.setConnection(walletRpcs[0].getRpcConnection()!.getUri()); + assert(connectionManager.isConnected()); + assert(walletRpcs[0].getRpcConnection() === connectionManager.getConnection()); + assert.equal(TestUtils.WALLET_RPC_CONFIG.username, connectionManager.getConnection().getUsername()); + assert.equal(TestUtils.WALLET_RPC_CONFIG.password, connectionManager.getConnection().getPassword()); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + assert(listener.changedConnections[listener.changedConnections.length - 1] === walletRpcs[0].getRpcConnection()); + + // set connection to new uri + connectionManager.stopPolling(); + let uri = "http://localhost:49999"; + await connectionManager.setConnection(uri); + assert.equal(connectionManager.getConnection().getUri(), uri); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + assert.equal(uri, listener.changedConnections[listener.changedConnections.length - 1].getUri()); + + // set connection to empty string + await connectionManager.setConnection(""); + assert.equal(undefined, connectionManager.getConnection()); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + + // check all connections and test auto switch + await connectionManager.checkConnections(); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + assert(connectionManager.isConnected()); + + // remove current connection and test auto switch + await connectionManager.removeConnection(connectionManager.getConnection().getUri()); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + assert.equal(connectionManager.isConnected(), false); + await connectionManager.checkConnections(); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + assert(connectionManager.isConnected()); + + // check connection promises + await Promise.all(connectionManager.checkConnectionPromises()); + + // test polling current connection + await connectionManager.setConnection(); + assert.equal(connectionManager.isConnected(), false); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + connectionManager.startPolling(TestUtils.SYNC_PERIOD_IN_MS, undefined, undefined, MoneroConnectionManager.PollType.CURRENT, undefined); + await GenUtils.waitFor(TestUtils.AUTO_CONNECT_TIMEOUT_MS); + assert(connectionManager.isConnected()); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + + // test polling all connections + await connectionManager.setConnection(); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + connectionManager.startPolling(TestUtils.SYNC_PERIOD_IN_MS, undefined, undefined, MoneroConnectionManager.PollType.ALL, undefined); + await GenUtils.waitFor(TestUtils.AUTO_CONNECT_TIMEOUT_MS); + assert(connectionManager.isConnected()); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + + // shut down all connections + connection = connectionManager.getConnection(); + for (let connection of orderedConnections) connection.setFakeDisconnected(true); + await GenUtils.waitFor(TestUtils.SYNC_PERIOD_IN_MS + 100); + assert.equal(false, connection.getIsOnline()); + assert.equal(listener.changedConnections.length, ++numExpectedChanges); + assert(listener.changedConnections[listener.changedConnections.length - 1] === connection); + + // reset + connectionManager.reset(); + assert.equal(connectionManager.getConnections().length, 0); + assert.equal(connectionManager.getConnection(), undefined); + } catch(err2) { + err = err2; + } + + // stop connection manager + if (connectionManager) connectionManager.reset(); + + // stop monero-wallet-rpc instances + for (let walletRpc of walletRpcs) { + try { await TestUtils.stopWalletRpcProcess(walletRpc); } + catch (err2) { } + } + + // throw error if applicable + if (err) throw err; + }); + }); + } +} + +class ConnectionChangeCollector extends MoneroConnectionManagerListener { + + changedConnections: MoneroRpcConnection[] = []; + + constructor() { + super(); + this.changedConnections = []; + } + async onConnectionChanged(connection) { + this.changedConnections.push(connection); + } +} + +export default TestMoneroConnectionManager; diff --git a/src/test/TestMoneroDaemonRpc.js b/src/test/TestMoneroDaemonRpc.ts similarity index 74% rename from src/test/TestMoneroDaemonRpc.js rename to src/test/TestMoneroDaemonRpc.ts index 367ebfa84..fef544164 100644 --- a/src/test/TestMoneroDaemonRpc.js +++ b/src/test/TestMoneroDaemonRpc.ts @@ -1,18 +1,25 @@ -const assert = require("assert"); -const TestUtils = require("./utils/TestUtils"); -const monerojs = require("../../index"); -const BigInteger = monerojs.BigInteger; -const ConnectionType = monerojs.ConnectionType; -const MoneroOutput = monerojs.MoneroOutput; -const MoneroTxConfig = monerojs.MoneroTxConfig; -const MoneroBan = monerojs.MoneroBan; -const MoneroKeyImage = monerojs.MoneroKeyImage; -const MoneroTx = monerojs.MoneroTx; -const MoneroAltChain = monerojs.MoneroAltChain; -const MoneroDaemonSyncInfo = monerojs.MoneroDaemonSyncInfo; -const MoneroDaemonConnection = monerojs.MoneroDaemonConnection; -const MoneroDaemonPeer = monerojs.MoneroDaemonPeer; -const MoneroKeyImageSpentStatus = monerojs.MoneroKeyImageSpentStatus; +import assert from "assert"; +import TestUtils from "./utils/TestUtils"; +import {connectToDaemonRpc, + GenUtils, + MoneroDaemonInfo, + MoneroNetworkType, + MoneroTxWallet, + MoneroTx, + MoneroKeyImageSpentStatus, + MoneroWallet, + MoneroDaemon, + MoneroPeer, + MoneroDaemonUpdateCheckResult, + MoneroBan, + MoneroDaemonListener, + MoneroDaemonSyncInfo, + MoneroTxConfig, + MoneroKeyImage, + MoneroOutput, + MoneroAltChain, + MoneroSubmitTxResult, + MoneroTxPoolStats} from "../../index"; // context for testing binary blocks // TODO: binary blocks have inconsistent client-side pruning @@ -22,11 +29,21 @@ const BINARY_BLOCK_CTX = { hasHex: false, headerIsFull: false, hasTxs: true, ctx /** * Tests a Monero daemon. */ -class TestMoneroDaemonRpc { +export default class TestMoneroDaemonRpc { + + // static variables + static readonly MAX_REQ_SIZE = "3000000"; + static readonly DEFAULT_ID = "0000000000000000000000000000000000000000000000000000000000000000"; // uninitialized tx or block hash from daemon rpc + static readonly NUM_HEADERS_PER_REQ = 750; // number of headers to fetch and cache per request + + // state variables + testConfig: any; + wallet: MoneroWallet; + daemon: MoneroDaemon; constructor(testConfig) { this.testConfig = testConfig; - TestUtils.TX_POOL_WALLET_TRACKER.reset(); // all wallets need to wait for txs to confirm to reliably sync + TestUtils.WALLET_TX_TRACKER.reset(); // all wallets need to wait for txs to confirm to reliably sync } /** @@ -42,7 +59,7 @@ class TestMoneroDaemonRpc { try { that.wallet = await TestUtils.getWalletRpc(); that.daemon = await TestUtils.getDaemonRpc(); - TestUtils.TX_POOL_WALLET_TRACKER.reset(); // all wallets need to wait for txs to confirm to reliably sync + TestUtils.WALLET_TX_TRACKER.reset(); // all wallets need to wait for txs to confirm to reliably sync } catch (e) { console.error("Error before tests: "); console.error(e); @@ -52,11 +69,43 @@ class TestMoneroDaemonRpc { // -------------------------- TEST NON RELAYS --------------------------- + if (testConfig.testNonRelays && !GenUtils.isBrowser()) + it("Can start and stop a daemon process", async function() { + + // create command to start monerod process + let cmd = [ + TestUtils.DAEMON_LOCAL_PATH, + "--" + GenUtils.getEnumKeyByValue(MoneroNetworkType, TestUtils.NETWORK_TYPE)!.toLowerCase(), + "--no-igd", + "--hide-my-port", + "--data-dir", TestUtils.MONERO_BINS_DIR + "/node1", + "--p2p-bind-port", "58080", + "--rpc-bind-port", "58081", + "--rpc-login", "superuser:abctesting123", + "--zmq-rpc-bind-port", "58082" + ]; + + // start monerod process from command + let daemon = await connectToDaemonRpc(cmd); + + // query daemon + let connection = await daemon.getRpcConnection(); + assert.equal("http://127.0.0.1:58081", connection.getUri()); + assert.equal("superuser", connection.getUsername()); + assert.equal("abctesting123", connection.getPassword()); + assert(await daemon.getHeight() > 0); + let info = await daemon.getInfo(); + testInfo(info); + + // stop daemon + await daemon.stopProcess(); + }); + if (testConfig.testNonRelays) it("Can get the daemon's version", async function() { let version = await that.daemon.getVersion(); assert(version.getNumber() > 0); - assert.equal(typeof version.isRelease(), "boolean"); + assert.equal(typeof version.getIsRelease(), "boolean"); }); if (testConfig.testNonRelays) @@ -200,12 +249,14 @@ class TestMoneroDaemonRpc { // select random heights // TODO: this is horribly inefficient way of computing last 100 blocks if not shuffling let currentHeight = await that.daemon.getHeight(); - let allHeights = []; + let allHeights: number[] = []; for (let i = 0; i < currentHeight - 1; i++) allHeights.push(i); //GenUtils.shuffle(allHeights); - let heights = []; + let heights: number[] = []; for (let i = allHeights.length - numBlocks; i < allHeights.length; i++) heights.push(allHeights[i]); + //heights.push(allHeights[i]); + // fetch blocks let blocks = await that.daemon.getBlocksByHeight(heights); @@ -249,7 +300,7 @@ class TestMoneroDaemonRpc { it("Can get blocks by range using chunked requests", async function() { // get long height range - let numBlocks = 1000; + let numBlocks = Math.min(await that.daemon.getHeight() - 2, 1440); // test up to ~2 days of blocks assert(numBlocks > 0); let height = await that.daemon.getHeight(); assert(height - numBlocks - 1 < height); @@ -309,7 +360,7 @@ class TestMoneroDaemonRpc { try { await that.daemon.getTx("invalid tx hash"); throw new Error("fail"); - } catch (e) { + } catch (e: any) { assert.equal("Invalid transaction hash", e.message); } }); @@ -319,6 +370,7 @@ class TestMoneroDaemonRpc { // fetch transaction hashes to test let txHashes = await getConfirmedTxHashes(that.daemon); + assert(txHashes.length > 0); // fetch txs by hash without pruning let txs = await that.daemon.getTxs(txHashes); @@ -334,27 +386,35 @@ class TestMoneroDaemonRpc { testTx(tx, {isPruned: true, isConfirmed: true, fromGetTxPool: false}); } + // fetch missing hash + let tx = await that.wallet.createTx({accountIndex: 0, address: await that.wallet.getPrimaryAddress(), amount: TestUtils.MAX_FEE}); + assert.equal(undefined, await that.daemon.getTx(tx.getHash())); + txHashes.push(tx.getHash()); + let numTxs = txs.length; + txs = await that.daemon.getTxs(txHashes); + assert.equal(numTxs, txs.length); + // fetch invalid hash txHashes.push("invalid tx hash"); try { await that.daemon.getTxs(txHashes); throw new Error("fail"); - } catch (e) { + } catch (e: any) { assert.equal("Invalid transaction hash", e.message); } }); if (testConfig.testNonRelays) it("Can get transactions by hashes that are in the transaction pool", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); // wait for wallet's txs in the pool to clear to ensure reliable sync + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); // wait for wallet's txs in the pool to clear to ensure reliable sync // submit txs to the pool but don't relay - let txHashes = []; + let txHashes: string[] = []; for (let i = 1; i < 3; i++) { let tx = await getUnrelayedTx(that.wallet, i); let result = await that.daemon.submitTxHex(tx.getFullHex(), true); testSubmitTxResultGood(result); - assert.equal(result.isRelayed(), false); + assert.equal(result.getIsRelayed(), false); txHashes.push(tx.getHash()); } @@ -379,8 +439,8 @@ class TestMoneroDaemonRpc { let txHashes = await getConfirmedTxHashes(that.daemon); // fetch each tx hex by hash with and without pruning - let hexes = [] - let hexesPruned = []; + let hexes: string[] = [] + let hexesPruned: string[] = []; for (let txHash of txHashes) { hexes.push(await that.daemon.getTxHex(txHash)); hexesPruned.push(await that.daemon.getTxHex(txHash, true)); @@ -400,7 +460,7 @@ class TestMoneroDaemonRpc { try { await that.daemon.getTxHex("invalid tx hash"); throw new Error("fail"); - } catch (e) { + } catch (e: any) { assert.equal("Invalid transaction hash", e.message); } }); @@ -430,7 +490,7 @@ class TestMoneroDaemonRpc { try { await that.daemon.getTxHexes(txHashes); throw new Error("fail"); - } catch (e) { + } catch (e: any) { assert.equal("Invalid transaction hash", e.message); } }); @@ -443,19 +503,22 @@ class TestMoneroDaemonRpc { if (testConfig.testNonRelays) it("Can get a fee estimate", async function() { - let fee = await that.daemon.getFeeEstimate(); - TestUtils.testUnsignedBigInteger(fee, true); + let feeEstimate = await that.daemon.getFeeEstimate(); + TestUtils.testUnsignedBigInt(feeEstimate.getFee(), true); + assert(feeEstimate.getFees().length === 4); // slow, normal, fast, fastest + for (let i = 0; i < 4; i++) TestUtils.testUnsignedBigInt(feeEstimate.getFees()[i], true); + TestUtils.testUnsignedBigInt(feeEstimate.getQuantizationMask(), true); }); if (testConfig.testNonRelays) it("Can get all transactions in the transaction pool", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); // submit tx to pool but don't relay let tx = await getUnrelayedTx(that.wallet, 0); let result = await that.daemon.submitTxHex(tx.getFullHex(), true); testSubmitTxResultGood(result); - assert.equal(result.isRelayed(), false); + assert.equal(result.getIsRelayed(), false); // fetch txs in pool let txs = await that.daemon.getTxPool(); @@ -485,32 +548,37 @@ class TestMoneroDaemonRpc { }); if (testConfig.testNonRelays) - it("Can get transaction pool statistics (binary)", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - - // submit txs to the pool but don't relay (multiple txs result in binary `histo` field) - for (let i = 0; i < 2; i++) { - - // submit tx hex - let tx = await getUnrelayedTx(that.wallet, i); - let result = await that.daemon.submitTxHex(tx.getFullHex(), true); - assert.equal(result.isGood(), true, "Bad tx submit result: " + result.toJson()); - - // test stats - try { - stats = await that.daemon.getTxPoolStats(); - assert(stats.getNumTxs() > i); + it("Can get transaction pool statistics", async function() { + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + let err; + let txIds = []; + try { + + // submit txs to the pool but don't relay + for (let i = 1; i < 3; i++) { + + // submit tx hex + let tx = await getUnrelayedTx(that.wallet, i); + let result = await that.daemon.submitTxHex(tx.getFullHex(), true); + assert.equal(result.getIsGood(), true, "Bad tx submit result: " + result.toJson()); + + // get tx pool stats + let stats = await that.daemon.getTxPoolStats(); + assert(stats.getNumTxs() > i - 1); testTxPoolStats(stats); - } finally { - await that.daemon.flushTxPool(tx.getHash()); - await that.wallet.sync(); } + } catch (e) { + err = e; } + + // flush txs + await that.daemon.flushTxPool(txIds); + if (err) throw err; }); if (testConfig.testNonRelays) it("Can flush all transactions from the pool", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); // preserve original transactions in the pool let txPoolBefore = await that.daemon.getTxPool(); @@ -529,7 +597,7 @@ class TestMoneroDaemonRpc { // re-submit original transactions for (let tx of txPoolBefore) { - let result = await that.daemon.submitTxHex(tx.getFullHex(), tx.isRelayed()); + let result = await that.daemon.submitTxHex(tx.getFullHex(), tx.getIsRelayed()); testSubmitTxResultGood(result); } @@ -542,13 +610,13 @@ class TestMoneroDaemonRpc { if (testConfig.testNonRelays) it("Can flush a transaction from the pool by hash", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); // preserve original transactions in the pool let txPoolBefore = await that.daemon.getTxPool(); // submit txs to the pool but don't relay - let txs = []; + let txs: MoneroTx[] = []; for (let i = 1; i < 3; i++) { let tx = await getUnrelayedTx(that.wallet, i); let result = await that.daemon.submitTxHex(tx.getFullHex(), true); @@ -576,13 +644,13 @@ class TestMoneroDaemonRpc { if (testConfig.testNonRelays) it("Can flush transactions from the pool by hashes", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); // preserve original transactions in the pool let txPoolBefore = await that.daemon.getTxPool(); // submit txs to the pool but don't relay - let txHashes = []; + let txHashes: string[] = []; for (let i = 1; i < 3; i++) { let tx = await getUnrelayedTx(that.wallet, i); let result = await that.daemon.submitTxHex(tx.getFullHex(), true); @@ -601,16 +669,16 @@ class TestMoneroDaemonRpc { if (testConfig.testNonRelays) it("Can get the spent status of key images", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); // submit txs to the pool to collect key images then flush them - let txs = []; + let txs: MoneroTx[] = []; for (let i = 1; i < 3; i++) { let tx = await getUnrelayedTx(that.wallet, i); await that.daemon.submitTxHex(tx.getFullHex(), true); txs.push(tx); } - let keyImages = []; + let keyImages: string[] = []; let txHashes = txs.map(tx => tx.getHash()); for (let tx of await that.daemon.getTxs(txHashes)) { for (let input of tx.getInputs()) keyImages.push(input.getKeyImage().getHex()); @@ -675,22 +743,22 @@ class TestMoneroDaemonRpc { } }); - if (testConfig.testNonRelays) - it("Can get an output distribution (binary)", async function() { - let amounts = []; - amounts.push(new BigInteger(0)); - amounts.push(new BigInteger(1)); - amounts.push(new BigInteger(10)); - amounts.push(new BigInteger(100)); - amounts.push(new BigInteger(1000)); - amounts.push(new BigInteger(10000)); - amounts.push(new BigInteger(100000)); - amounts.push(new BigInteger(1000000)); - let entries = await that.daemon.getOutputDistribution(amounts); - for (let entry of entries) { - testOutputDistributionEntry(entry); - } - }); + // if (testConfig.testNonRelays) + // it("Can get an output distribution (binary)", async function() { + // let amounts: bigint[] = []; + // amounts.push(BigInt(0)); + // amounts.push(BigInt(1)); + // amounts.push(BigInt(10)); + // amounts.push(BigInt(100)); + // amounts.push(BigInt(1000)); + // amounts.push(BigInt(10000)); + // amounts.push(BigInt(100000)); + // amounts.push(BigInt(1000000)); + // let entries = await that.daemon.getOutputDistribution(amounts); + // for (let entry of entries) { + // testOutputDistributionEntry(entry); + // } + // }); if (testConfig.testNonRelays) it("Can get general information", async function() { @@ -740,22 +808,16 @@ class TestMoneroDaemonRpc { assert.equal(resetVal, initVal); // test invalid limits - try { - await that.daemon.setDownloadLimit(); - fail("Should have thrown error on invalid input"); - } catch (e) { - assert.equal("Download limit must be an integer greater than 0", e.message); - } try { await that.daemon.setDownloadLimit(0); - fail("Should have thrown error on invalid input"); - } catch (e) { + throw new Error("Should have thrown error on invalid input"); + } catch (e: any) { assert.equal("Download limit must be an integer greater than 0", e.message); } try { await that.daemon.setDownloadLimit(1.2); - fail("Should have thrown error on invalid input"); - } catch (e) { + throw new Error("Should have thrown error on invalid input"); + } catch (e: any) { assert.equal("Download limit must be an integer greater than 0", e.message); } assert.equal(await that.daemon.getDownloadLimit(), initVal); @@ -772,43 +834,37 @@ class TestMoneroDaemonRpc { assert.equal(resetVal, initVal); // test invalid limits - try { - await that.daemon.setUploadLimit(); - fail("Should have thrown error on invalid input"); - } catch (e) { - assert.equal("Upload limit must be an integer greater than 0", e.message); - } try { await that.daemon.setUploadLimit(0); - fail("Should have thrown error on invalid input"); - } catch (e) { + throw new Error("Should have thrown error on invalid input"); + } catch (e: any) { assert.equal("Upload limit must be an integer greater than 0", e.message); } try { await that.daemon.setUploadLimit(1.2); - fail("Should have thrown error on invalid input"); - } catch (e) { + throw new Error("Should have thrown error on invalid input"); + } catch (e: any) { assert.equal("Upload limit must be an integer greater than 0", e.message); } assert.equal(await that.daemon.getUploadLimit(), initVal); }); if (testConfig.testNonRelays) - it("Can get known peers which may be online or offline", async function() { - let peers = await that.daemon.getKnownPeers(); - assert(peers.length > 0, "Daemon has no known peers to test"); + it("Can get peers with active incoming or outgoing peers", async function() { + let peers = await that.daemon.getPeers(); + assert(Array.isArray(peers)); + assert(peers.length > 0, "Daemon has no incoming or outgoing peers to test"); for (let peer of peers) { - testKnownPeer(peer); + testPeer(peer); } }); if (testConfig.testNonRelays) - it("Can get incoming and outgoing peer connections", async function() { - let connections = await that.daemon.getConnections(); - assert(Array.isArray(connections)); - assert(connections.length > 0, "Daemon has no incoming or outgoing connections to test"); - for (let connection of connections) { - testDaemonConnection(connection); + it("Can get known peers which may be online or offline", async function() { + let peers = await that.daemon.getKnownPeers(); + assert(peers.length > 0, "Daemon has no known peers to test"); + for (let peer of peers) { + testKnownPeer(peer); } }); @@ -817,12 +873,6 @@ class TestMoneroDaemonRpc { await that.daemon.setOutgoingPeerLimit(0); await that.daemon.setOutgoingPeerLimit(8); await that.daemon.setOutgoingPeerLimit(10); - try { - await that.daemon.setOutgoingPeerLimit("a"); - throw new Error("Should have failed on invalid input"); - } catch(e) { - assert.notEqual("Should have failed on invalid input", e.message); - } }); if (testConfig.testNonRelays) @@ -830,22 +880,17 @@ class TestMoneroDaemonRpc { await that.daemon.setIncomingPeerLimit(0); await that.daemon.setIncomingPeerLimit(8); await that.daemon.setIncomingPeerLimit(10); - try { - await that.daemon.setIncomingPeerLimit("a"); - throw new Error("Should have failed on invalid input"); - } catch(e) { - assert.notEqual("Should have failed on invalid input", e.message); - } }); if (testConfig.testNonRelays) it("Can ban a peer", async function() { // set ban - let ban = new MoneroBan(); - ban.setHost("192.168.1.56"); - ban.setIsBanned(true); - ban.setSeconds(60); + let ban = new MoneroBan({ + host: "192.168.1.56", + isBanned: true, + seconds: 60 + }); await that.daemon.setPeerBan(ban); // test ban @@ -870,7 +915,7 @@ class TestMoneroDaemonRpc { ban2.setHost("192.168.1.53"); ban2.setIsBanned(true); ban2.setSeconds(60); - let bans = []; + let bans: MoneroBan[] = []; bans.push(ban1); bans.push(ban2); await that.daemon.setPeerBans(bans); @@ -916,11 +961,11 @@ class TestMoneroDaemonRpc { // test status without mining let status = await that.daemon.getMiningStatus(); - assert.equal(status.isActive(), false); + assert.equal(status.getIsActive(), false); assert.equal(status.getAddress(), undefined); assert.equal(status.getSpeed(), 0); assert.equal(status.getNumThreads(), 0); - assert.equal(status.isBackground(), undefined); + assert.equal(status.getIsBackground(), undefined); // test status with mining let address = await that.wallet.getPrimaryAddress(); @@ -928,11 +973,11 @@ class TestMoneroDaemonRpc { let isBackground = false; await that.daemon.startMining(address, threadCount, isBackground, true); status = await that.daemon.getMiningStatus(); - assert.equal(status.isActive(), true); + assert.equal(status.getIsActive(), true); assert.equal(status.getAddress(), address); assert(status.getSpeed() >= 0); assert.equal(status.getNumThreads(), threadCount); - assert.equal(status.isBackground(), isBackground); + assert.equal(status.getIsBackground(), isBackground); } catch(e) { throw e; } finally { @@ -953,13 +998,23 @@ class TestMoneroDaemonRpc { // try to submit block hashing blob without nonce try { - await that.daemon.submitBlock(template.getBlockHashingBlob()); - fail("Should have thrown error"); - } catch (e) { + await that.daemon.submitBlock(template.getBlockTemplateBlob()); + throw new Error("Should have thrown error"); + } catch (e: any) { assert.equal(e.getCode(), -7); assert.equal(e.message, "Block not accepted"); } }); + + if (testConfig.testNonRelays) + it("Can prune the blockchain", async function() { + let result = await that.daemon.pruneBlockchain(true); + if (result.getIsPruned()) { + assert(result.getPruningSeed() > 0); + } else { + assert.equal(result.getPruningSeed(), 0); + } + }); if (testConfig.testNonRelays) it("Can check for an update", async function() { @@ -980,13 +1035,13 @@ class TestMoneroDaemonRpc { testUpdateDownloadResult(result, path); // test invalid path - if (result.isUpdateAvailable()) { + if (result.getIsUpdateAvailable()) { try { result = await that.daemon.downloadUpdate("./ohhai/there"); throw new Error("Should have thrown error"); - } catch(e) { + } catch (e: any) { assert.notEqual("Should have thrown error", e.message); - assert.equal(e.statusCode, 500); // TODO monero-daemon-rpc: this causes a 500 in that.daemon rpc + assert.equal(e.statusCode, 500); // TODO monerod: this causes a 500 in that.daemon rpc } } }); @@ -995,20 +1050,20 @@ class TestMoneroDaemonRpc { it("Can be stopped", async function() { return; // test is disabled to not interfere with other tests - // give the that.daemon time to shut down - await new Promise(function(resolve) { setTimeout(resolve, MoneroUtils.WALLET_REFRESH_RATE); }); + // give the daemon time to shut down + await new Promise(function(resolve) { setTimeout(resolve, TestUtils.SYNC_PERIOD_IN_MS); }); - // stop the that.daemon + // stop the daemon await that.daemon.stop(); - // give the that.daemon 10 seconds to shut down + // give the daemon 10 seconds to shut down await new Promise(function(resolve) { setTimeout(resolve, 10000); }); // try to interact with the that.daemon try { await that.daemon.getHeight(); throw new Error("Should have thrown error"); - } catch(e) { + } catch (e: any) { console.log(e); assert.notEqual("Should have thrown error", e.message); } @@ -1020,7 +1075,7 @@ class TestMoneroDaemonRpc { it("Can submit a tx in hex format to the pool and relay in one call", async function() { // wait one time for wallet txs in the pool to clear - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); // create 2 txs, the second will double spend outputs of first let tx1 = await getUnrelayedTx(that.wallet, 2); // TODO: this test requires tx to be from/to different accounts else the occlusion issue (#4500) causes the tx to not be recognized by the wallet at all @@ -1028,7 +1083,7 @@ class TestMoneroDaemonRpc { // submit and relay tx1 let result = await that.daemon.submitTxHex(tx1.getFullHex()); - assert.equal(result.isRelayed(), true); + assert.equal(result.getIsRelayed(), true); testSubmitTxResultGood(result); // tx1 is in the pool @@ -1036,7 +1091,7 @@ class TestMoneroDaemonRpc { let found = false; for (let aTx of txs) { if (aTx.getHash() === tx1.getHash()) { - assert.equal(aTx.isRelayed(), true); + assert.equal(aTx.getIsRelayed(), true); found = true; break; } @@ -1049,7 +1104,7 @@ class TestMoneroDaemonRpc { // submit and relay tx2 hex which double spends tx1 result = await that.daemon.submitTxHex(tx2.getFullHex()); - assert.equal(result.isRelayed(), true); + assert.equal(result.getIsRelayed(), true); testSubmitTxResultDoubleSpend(result); // tx2 is in not the pool @@ -1064,41 +1119,41 @@ class TestMoneroDaemonRpc { assert(!found, "Tx2 should not be in the pool because it double spends tx1 which is in the pool"); // all wallets will need to wait for tx to confirm in order to properly sync - TestUtils.TX_POOL_WALLET_TRACKER.reset(); + TestUtils.WALLET_TX_TRACKER.reset(); }); if (testConfig.testRelays && !testConfig.liteMode) it("Can submit a tx in hex format to the pool then relay", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); let tx = await getUnrelayedTx(that.wallet, 1); await testSubmitThenRelay([tx]); }); if (testConfig.testRelays && !testConfig.liteMode) it("Can submit txs in hex format to the pool then relay", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - let txs = []; - txs.push(await getUnrelayedTx(that.wallet, 2)); - txs.push(await getUnrelayedTx(that.wallet, 3)); // TODO: accounts cannot be re-used across send tests else isRelayed is true; wallet needs to update? + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + let txs: MoneroTxWallet[] = []; + txs.push(await getUnrelayedTx(that.wallet, 1)); + txs.push(await getUnrelayedTx(that.wallet, 2)); // TODO: accounts cannot be re-used across send tests else isRelayed is true; wallet needs to update? await testSubmitThenRelay(txs); }); async function testSubmitThenRelay(txs) { // submit txs hex but don't relay - let txHashes = []; + let txHashes: string[] = []; for (let tx of txs) { txHashes.push(tx.getHash()); let result = await that.daemon.submitTxHex(tx.getFullHex(), true); testSubmitTxResultGood(result); - assert.equal(result.isRelayed(), false); + assert.equal(result.getIsRelayed(), false); // ensure tx is in pool let poolTxs = await that.daemon.getTxPool(); let found = false; for (let aTx of poolTxs) { if (aTx.getHash() === tx.getHash()) { - assert.equal(aTx.isRelayed(), false); + assert.equal(aTx.getIsRelayed(), false); found = true; break; } @@ -1107,7 +1162,7 @@ class TestMoneroDaemonRpc { // fetch tx by hash and ensure not relayed let fetchedTx = await that.daemon.getTx(tx.getHash()); - assert.equal(fetchedTx.isRelayed(), false); + assert.equal(fetchedTx.getIsRelayed(), false); } // relay the txs @@ -1118,13 +1173,16 @@ class TestMoneroDaemonRpc { throw e; } + // wait for txs to be relayed // TODO (monero-project): all txs should be relayed: https://github.com/monero-project/monero/issues/8523 + await new Promise(function(resolve) { setTimeout(resolve, 1000); }); + // ensure txs are relayed + let poolTxs = await that.daemon.getTxPool(); for (let tx of txs) { - let poolTxs = await that.daemon.getTxPool(); let found = false; for (let aTx of poolTxs) { if (aTx.getHash() === tx.getHash()) { - assert.equal(aTx.isRelayed(), true); + assert.equal(aTx.getIsRelayed(), true); found = true; break; } @@ -1133,7 +1191,7 @@ class TestMoneroDaemonRpc { } // wallets will need to wait for tx to confirm in order to properly sync - TestUtils.TX_POOL_WALLET_TRACKER.reset(); + TestUtils.WALLET_TX_TRACKER.reset(); } // ------------------------ TEST NOTIFICATIONS -------------------------- @@ -1146,18 +1204,20 @@ class TestMoneroDaemonRpc { // start mining if possible to help push the network along let address = await that.wallet.getPrimaryAddress(); try { await that.daemon.startMining(address, 8, false, true); } - catch (e) { if ("BUSY" === e.message) throw e; } + catch (e: any) { if ("BUSY" === e.message) throw e; } // register a listener let listenerHeader; - let listener = async function(header) { - listenerHeader = header; - await that.daemon.removeBlockListener(listener); // otherwise daemon will keep polling + let listener = new class extends MoneroDaemonListener { + async onBlockHeader(header) { + listenerHeader = header; + } } - await that.daemon.addBlockListener(listener); + await that.daemon.addListener(listener); // wait for next block notification - let header = await that.daemon.getNextBlockHeader(); + let header = await that.daemon.waitForNextBlockHeader(); + await that.daemon.removeListener(listener); // otherwise daemon will keep polling testBlockHeader(header, true); // test that listener was called with equivalent header @@ -1179,17 +1239,20 @@ function testBlockHeader(header, isFull) { assert(typeof isFull === "boolean"); assert(header); assert(header.getHeight() >= 0); - assert(header.getMajorVersion() >= 0); + assert(header.getMajorVersion() > 0); assert(header.getMinorVersion() >= 0); - assert(header.getTimestamp() >= 0); + if (header.getHeight() === 0) assert(header.getTimestamp() === 0); + else assert(header.getTimestamp() > 0); assert(header.getPrevHash()); - assert(header.getNonce()); + assert(header.getNonce() !== undefined); + if (header.getNonce() === 0) console.log("WARNING: header nonce is 0 at height " + header.getHeight()); // TODO (monero-project): why is header nonce 0? + else assert(header.getNonce() > 0); assert.equal(typeof header.getNonce(), "number"); assert(header.getPowHash() === undefined); // never seen defined assert(!isFull ? undefined === header.getSize() : header.getSize()); assert(!isFull ? undefined === header.getDepth() : header.getDepth() >= 0); - assert(!isFull ? undefined === header.getDifficulty() : header.getDifficulty().toJSValue() > 0); - assert(!isFull ? undefined === header.getCumulativeDifficulty() : header.getCumulativeDifficulty().toJSValue() > 0); + assert(!isFull ? undefined === header.getDifficulty() : header.getDifficulty() > 0); + assert(!isFull ? undefined === header.getCumulativeDifficulty() : header.getCumulativeDifficulty() > 0); assert(!isFull ? undefined === header.getHash() : header.getHash().length === 64); assert(!isFull ? undefined === header.getMinerTxHash() : header.getMinerTxHash().length === 64); assert(!isFull ? undefined === header.getNumTxs() : header.getNumTxs() >= 0); @@ -1209,7 +1272,7 @@ function testBlock(block, ctx) { // test required fields assert(block); - assert(Array.isArray(block.getTxHashes())); // TODO: tx hashes probably part of tx + assert(Array.isArray(block.getTxHashes())); assert(block.getTxHashes().length >= 0); testMinerTx(block.getMinerTx()); // TODO: miner tx doesn't have as much stuff, can't call testTx? testBlockHeader(block, ctx.headerIsFull); @@ -1237,13 +1300,13 @@ function testBlock(block, ctx) { function testMinerTx(minerTx) { assert(minerTx); assert(minerTx instanceof MoneroTx); - assert.equal(typeof minerTx.isMinerTx(), "boolean"); - assert(minerTx.isMinerTx()); + assert.equal(typeof minerTx.getIsMinerTx(), "boolean"); + assert(minerTx.getIsMinerTx()); assert(minerTx.getVersion() >= 0); - assert(Array.isArray(minerTx.getExtra())); + assert(minerTx.getExtra() instanceof Uint8Array); assert(minerTx.getExtra().length > 0); - assert(minerTx.getUnlockHeight() >= 0); + assert(minerTx.getUnlockTime() >= BigInt(0)); // TODO: miner tx does not have hashes in binary requests so this will fail, need to derive using prunable data // testTx(minerTx, { @@ -1257,7 +1320,7 @@ function testMinerTx(minerTx) { } // TODO: how to test output indices? comes back with /get_transactions, maybe others -function testTx(tx, ctx) { +function testTx(tx: MoneroTx, ctx) { // check inputs assert(tx); @@ -1268,68 +1331,72 @@ function testTx(tx, ctx) { // standard across all txs assert(tx.getHash().length === 64); - if (tx.isRelayed() === undefined) assert(tx.inTxPool()); // TODO monero-daemon-rpc: add relayed to get_transactions - else assert.equal(typeof tx.isRelayed(), "boolean"); - assert.equal(typeof tx.isConfirmed(), "boolean"); - assert.equal(typeof tx.inTxPool(), "boolean"); - assert.equal(typeof tx.isMinerTx(), "boolean"); - assert.equal(typeof tx.isDoubleSpendSeen(), "boolean"); + if (tx.getIsRelayed() === undefined) assert(tx.getInTxPool()); // TODO monerod: add relayed to get_transactions + else assert.equal(typeof tx.getIsRelayed(), "boolean"); + assert.equal(typeof tx.getIsConfirmed(), "boolean"); + assert.equal(typeof tx.getInTxPool(), "boolean"); + assert.equal(typeof tx.getIsMinerTx(), "boolean"); + assert.equal(typeof tx.getIsDoubleSpendSeen(), "boolean"); assert(tx.getVersion() >= 0); - assert(tx.getUnlockHeight() >= 0); + assert(tx.getUnlockTime() >= BigInt(0)); assert(tx.getInputs()); assert(tx.getOutputs()); + assert(tx.getExtra() instanceof Uint8Array); assert(tx.getExtra().length > 0); + TestUtils.testUnsignedBigInt(tx.getFee(), true); // test presence of output indices // TODO: change this over to outputs only - if (tx.isMinerTx()) assert.equal(tx.getOutputIndices(), undefined); // TODO: how to get output indices for miner transactions? - if (tx.inTxPool() || ctx.fromGetTxPool || ctx.hasOutputIndices === false) assert.equal(tx.getOutputIndices(), undefined); + if (tx.getIsMinerTx()) assert.equal(tx.getOutputIndices(), undefined); // TODO: how to get output indices for miner transactions? + if (tx.getInTxPool() || ctx.fromGetTxPool || ctx.hasOutputIndices === false) assert.equal(tx.getOutputIndices(), undefined); else assert(tx.getOutputIndices()); if (tx.getOutputIndices()) assert(tx.getOutputIndices().length > 0); // test confirmed ctx - if (ctx.isConfirmed === true) assert.equal(tx.isConfirmed(), true); - if (ctx.isConfirmed === false) assert.equal(tx.isConfirmed(), false); + if (ctx.isConfirmed === true) assert.equal(tx.getIsConfirmed(), true); + if (ctx.isConfirmed === false) assert.equal(tx.getIsConfirmed(), false); // test confirmed - if (tx.isConfirmed()) { + if (tx.getIsConfirmed()) { assert(tx.getBlock()); assert(tx.getBlock().getTxs().includes(tx)); assert(tx.getBlock().getHeight() > 0); assert(tx.getBlock().getTimestamp() > 0); - assert.equal(tx.isRelayed(), true); - assert.equal(tx.isFailed(), false); - assert.equal(tx.inTxPool(), false); + assert.equal(tx.getIsRelayed(), true); + assert.equal(tx.getIsFailed(), false); + assert.equal(tx.getInTxPool(), false); assert.equal(tx.getRelay(), true); - assert.equal(tx.isDoubleSpendSeen(), false); - assert.equal(tx.getNumConfirmations(), undefined); // client must compute + assert.equal(tx.getIsDoubleSpendSeen(), false); + if (ctx.fromBinaryBlock) assert.equal(tx.getNumConfirmations(), undefined); + else assert(tx.getNumConfirmations() > 0); } else { assert.equal(tx.getBlock(), undefined); assert.equal(tx.getNumConfirmations(), 0); } // test in tx pool - if (tx.inTxPool()) { - assert.equal(tx.isConfirmed(), false); - assert.equal(tx.isDoubleSpendSeen(), false); + if (tx.getInTxPool()) { + assert.equal(tx.getIsConfirmed(), false); + assert.equal(tx.getIsDoubleSpendSeen(), false); assert.equal(tx.getLastFailedHeight(), undefined); assert.equal(tx.getLastFailedHash(), undefined); assert(tx.getReceivedTimestamp() > 0); - assert(tx.getSize() > 0); - assert(tx.getWeight() > 0); - assert.equal(typeof tx.isKeptByBlock(), "boolean"); + if (ctx.fromGetTxPool) { + assert(tx.getSize() > 0); + assert(tx.getWeight() > 0); + assert.equal(typeof tx.getIsKeptByBlock(), "boolean"); + assert(tx.getMaxUsedBlockHeight() >= 0); + assert(tx.getMaxUsedBlockHash()); + } assert.equal(tx.getLastFailedHeight(), undefined); assert.equal(tx.getLastFailedHash(), undefined); - assert(tx.getMaxUsedBlockHeight() >= 0); - assert(tx.getMaxUsedBlockHash()); } else { assert.equal(tx.getLastRelayedTimestamp(), undefined); } // test miner tx - if (tx.isMinerTx()) { - assert.equal(tx.getFee().compare(new BigInteger(0)), 0); - assert(tx.getIncomingTransfers().length > 0); // TODO: MoneroTx does not have getIncomingTransfers() but this doesn't fail? + if (tx.getIsMinerTx()) { + assert.equal(tx.getFee(), 0n); assert.equal(tx.getInputs(), undefined); assert.equal(tx.getSignatures(), undefined); } else { @@ -1337,16 +1404,17 @@ function testTx(tx, ctx) { } // test failed // TODO: what else to test associated with failed - if (tx.isFailed()) { - assert(tx.getOutgoingTransfer() instanceof MoneroTransfer); // TODO: MoneroTx does not have getOutgoingTransfer() but this doesn't fail? + if (tx.getIsFailed()) { assert(tx.getReceivedTimestamp() > 0) } else { - if (tx.isRelayed() === undefined) assert.equal(tx.getRelay(), undefined); // TODO monero-daemon-rpc: add relayed to get_transactions - else if (tx.isRelayed()) assert.equal(tx.isDoubleSpendSeen(), false); + if (tx.getIsRelayed() === undefined) assert.equal(tx.getRelay(), undefined); // TODO monerod: add relayed to get_transactions + else if (tx.getIsRelayed()) assert.equal(tx.getIsDoubleSpendSeen(), false); else { - assert.equal(tx.isRelayed(), false); - assert.equal(tx.getRelay(), false); - assert.equal(typeof tx.isDoubleSpendSeen(), "boolean"); + assert.equal(tx.getIsRelayed(), false); + if (ctx.fromGetTxPool) { + assert.equal(tx.getRelay(), false); + assert.equal(typeof tx.getIsDoubleSpendSeen(), "boolean"); + } } } assert.equal(tx.getLastFailedHeight(), undefined); @@ -1354,13 +1422,13 @@ function testTx(tx, ctx) { // received time only for tx pool or failed txs if (tx.getReceivedTimestamp() !== undefined) { - assert(tx.inTxPool() || tx.isFailed()); + assert(tx.getInTxPool() || tx.getIsFailed()); } // test inputs and outputs assert(tx.getInputs() && Array.isArray(tx.getInputs()) && tx.getInputs().length >= 0); assert(tx.getOutputs() && Array.isArray(tx.getOutputs()) && tx.getOutputs().length >= 0); - if (!tx.isMinerTx()) assert(tx.getInputs().length > 0); + if (!tx.getIsMinerTx()) assert(tx.getInputs().length > 0); for (let input of tx.getInputs()) { assert(tx === input.getTx()); testVin(input, ctx); @@ -1372,7 +1440,7 @@ function testTx(tx, ctx) { } // test pruned vs not pruned - if (ctx.fromGetTxPool || ctx.fromBinaryBlock) assert.equal(tx.getPrunableHash(), undefined); // TODO monero-daemon-rpc: tx pool txs do not have prunable hash, TODO: getBlocksByHeight() has inconsistent client-side pruning + if (ctx.fromGetTxPool || ctx.fromBinaryBlock) assert.equal(tx.getPrunableHash(), undefined); // TODO monerod: tx pool txs do not have prunable hash, TODO: getBlocksByHeight() has inconsistent client-side pruning else assert(tx.getPrunableHash()); if (ctx.isPruned) { assert.equal(tx.getRctSigPrunable(), undefined); @@ -1384,24 +1452,25 @@ function testTx(tx, ctx) { } else { assert.equal(tx.getPrunedHex(), undefined); assert(tx.getVersion() >= 0); - assert(tx.getUnlockHeight() >= 0); - assert(Array.isArray(tx.getExtra()) && tx.getExtra().length > 0); + assert(tx.getUnlockTime() >= 0n); + assert(tx.getExtra() instanceof Uint8Array); + assert(tx.getExtra().length > 0); if (ctx.fromBinaryBlock) assert.equal(tx.getFullHex(), undefined); // TODO: getBlocksByHeight() has inconsistent client-side pruning else assert(tx.getFullHex().length > 0); if (ctx.fromBinaryBlock) assert.equal(tx.getRctSigPrunable(), undefined); // TODO: getBlocksByHeight() has inconsistent client-side pruning //else assert.equal(typeof tx.getRctSigPrunable().nbp, "number"); - assert.equal(tx.isDoubleSpendSeen(), false); - if (tx.isConfirmed()) { + assert.equal(tx.getIsDoubleSpendSeen(), false); + if (tx.getIsConfirmed()) { assert.equal(tx.getLastRelayedTimestamp(), undefined); assert.equal(tx.getReceivedTimestamp(), undefined); } else { - if (tx.isRelayed()) assert(tx.getLastRelayedTimestamp() > 0); + if (tx.getIsRelayed()) assert(tx.getLastRelayedTimestamp() > 0); else assert.equal(tx.getLastRelayedTimestamp(), undefined); assert(tx.getReceivedTimestamp() > 0); } } - if (tx.isFailed()) { + if (tx.getIsFailed()) { // TODO: implement this } @@ -1414,26 +1483,26 @@ function testBlockTemplate(template) { assert(template.getBlockTemplateBlob()); assert(template.getBlockHashingBlob()); assert(template.getDifficulty()); - assert(template.getDifficulty() instanceof BigInteger); + assert.equal(typeof template.getDifficulty(), "bigint"); assert(template.getExpectedReward()); assert(template.getHeight()); assert(template.getPrevHash()); assert(template.getReservedOffset()); assert.equal(typeof template.getSeedHeight(), "number"); - assert(template.getSeedHeight() > 0); + assert(template.getSeedHeight() >= 0); assert.equal(typeof template.getSeedHash(), "string"); assert(template.getSeedHash()); // next seed hash can be null or initialized // TODO: test circumstances for each } -function testInfo(info) { +function testInfo(info: MoneroDaemonInfo) { assert(info.getVersion()); assert(info.getNumAltBlocks() >= 0); assert(info.getBlockSizeLimit()); assert(info.getBlockSizeMedian()); assert(info.getBootstrapDaemonAddress() === undefined || (typeof info.getBootstrapDaemonAddress() === "string" && info.getBootstrapDaemonAddress().length > 0)); assert(info.getCumulativeDifficulty()); - assert(info.getCumulativeDifficulty() instanceof BigInteger) + assert.equal(typeof info.getCumulativeDifficulty(), "bigint"); assert(info.getFreeSpace()); assert(info.getNumOfflinePeers() >= 0); assert(info.getNumOnlinePeers() >= 0); @@ -1441,46 +1510,49 @@ function testInfo(info) { assert(info.getHeightWithoutBootstrap()); assert(info.getNumIncomingConnections() >= 0); assert(info.getNetworkType()); - assert(typeof info.isOffline() === "boolean"); + assert.equal(typeof info.getIsOffline(), "boolean"); assert(info.getNumOutgoingConnections() >= 0); assert(info.getNumRpcConnections() >= 0); assert(info.getStartTimestamp()); + assert(info.getAdjustedTimestamp()); assert(info.getTarget()); assert(info.getTargetHeight() >= 0); assert(info.getNumTxs() >= 0); assert(info.getNumTxsPool() >= 0); - assert(typeof info.getWasBootstrapEverUsed() === "boolean"); + assert.equal(typeof info.getWasBootstrapEverUsed(), "boolean"); assert(info.getBlockWeightLimit()); assert(info.getBlockWeightMedian()); assert(info.getDatabaseSize() > 0); assert(typeof info.getUpdateAvailable() === "boolean"); - TestUtils.testUnsignedBigInteger(info.getCredits(), false); + TestUtils.testUnsignedBigInt(info.getCredits(), false); assert.equal(typeof info.getTopBlockHash(), "string"); assert(info.getTopBlockHash()); + assert.equal("boolean", typeof info.getIsBusySyncing()); + assert.equal("boolean", typeof info.getIsSynchronized()); } function testSyncInfo(syncInfo) { // TODO: consistent naming, daemon in name? assert(syncInfo instanceof MoneroDaemonSyncInfo); assert(syncInfo.getHeight() >= 0); - if (syncInfo.getConnections() !== undefined) { - assert(syncInfo.getConnections().length > 0); - for (let connection of syncInfo.getConnections()) { - testDaemonConnection(connection); + if (syncInfo.getPeers() !== undefined) { + assert(syncInfo.getPeers().length > 0); + for (let peer of syncInfo.getPeers()) { + testPeer(peer); } } if (syncInfo.getSpans() !== undefined) { // TODO: test that this is being hit, so far not used assert(syncInfo.getSpans().length > 0); for (let span of syncInfo.getSpans()) { - testDaemonConnectionSpan(span); + testConnectionSpan(span); } } assert(syncInfo.getNextNeededPruningSeed() >= 0); assert.equal(syncInfo.getOverview(), undefined); - TestUtils.testUnsignedBigInteger(syncInfo.getCredits(), false); + TestUtils.testUnsignedBigInt(syncInfo.getCredits(), false); assert.equal(syncInfo.getTopBlockHash(), undefined); } -function testDaemonConnectionSpan(span) { +function testConnectionSpan(span) { assert.notEqual(span, undefined); assert.notEqual(span.getConnectionId(), undefined); assert(span.getConnectionId().length > 0); @@ -1494,14 +1566,14 @@ function testDaemonConnectionSpan(span) { function testHardForkInfo(hardForkInfo) { assert.notEqual(hardForkInfo.getEarliestHeight(), undefined); - assert.notEqual(hardForkInfo.isEnabled(), undefined); + assert.notEqual(hardForkInfo.getIsEnabled(), undefined); assert.notEqual(hardForkInfo.getState(), undefined); assert.notEqual(hardForkInfo.getThreshold(), undefined); assert.notEqual(hardForkInfo.getVersion(), undefined); assert.notEqual(hardForkInfo.getNumVotes(), undefined); assert.notEqual(hardForkInfo.getVoting(), undefined); assert.notEqual(hardForkInfo.getWindow(), undefined); - TestUtils.testUnsignedBigInteger(hardForkInfo.getCredits(), false); + TestUtils.testUnsignedBigInt(hardForkInfo.getCredits(), false); assert.equal(hardForkInfo.getTopBlockHash(), undefined); } @@ -1512,80 +1584,84 @@ function testMoneroBan(ban) { } function testMinerTxSum(txSum) { - TestUtils.testUnsignedBigInteger(txSum.getEmissionSum(), true); - TestUtils.testUnsignedBigInteger(txSum.getFeeSum(), true); + TestUtils.testUnsignedBigInt(txSum.getEmissionSum(), true); + TestUtils.testUnsignedBigInt(txSum.getFeeSum(), true); } function testOutputHistogramEntry(entry) { - TestUtils.testUnsignedBigInteger(entry.getAmount()); + TestUtils.testUnsignedBigInt(entry.getAmount()); assert(entry.getNumInstances() >= 0); assert(entry.getNumUnlockedInstances() >= 0); assert(entry.getNumRecentInstances() >= 0); } function testOutputDistributionEntry(entry) { - TestUtils.testUnsignedBigInteger(entry.getAmount()); + TestUtils.testUnsignedBigInt(entry.getAmount()); assert(entry.getBase() >= 0); assert(Array.isArray(entry.getDistribution()) && entry.getDistribution().length > 0); assert(entry.getStartHeight() >= 0); } -function testSubmitTxResultGood(result) { +function testSubmitTxResultGood(result: MoneroSubmitTxResult) { testSubmitTxResultCommon(result); try { - assert.equal(result.isDoubleSpendSeen(), false, "tx submission is double spend."); - assert.equal(result.isFeeTooLow(), false); - assert.equal(result.isMixinTooLow(), false); - assert.equal(result.hasInvalidInput(), false); - assert.equal(result.hasInvalidOutput(), false); - assert.equal(result.hasTooFewOutputs(), false); - assert.equal(result.isOverspend(), false); - assert.equal(result.isTooBig(), false); + assert.equal(result.getIsDoubleSpendSeen(), false, "tx submission is double spend."); + assert.equal(result.getIsFeeTooLow(), false); + assert.equal(result.getIsMixinTooLow(), false); + assert.equal(result.getHasInvalidInput(), false); + assert.equal(result.getHasInvalidOutput(), false); + assert.equal(result.getHasTooFewOutputs(), false); + assert.equal(result.getIsOverspend(), false); + assert.equal(result.getIsTooBig(), false); assert.equal(result.getSanityCheckFailed(), false); - TestUtils.testUnsignedBigInteger(result.getCredits(), false); // 0 credits + TestUtils.testUnsignedBigInt(result.getCredits(), false); // 0 credits assert.equal(result.getTopBlockHash(), undefined); - assert.equal(result.isGood(), true); + assert.equal(result.getIsTxExtraTooBig(), false); + assert.equal(result.getIsGood(), true); + assert.equal(result.getIsNonzeroUnlockTime(), false); } catch (e) { - console.log("Submit result is not good: " + JSON.stringify(result)); + console.log("Submit result is not good: " + JSON.stringify(result.toJson())); throw e; } } -function testSubmitTxResultDoubleSpend(result) { +function testSubmitTxResultDoubleSpend(result: MoneroSubmitTxResult) { testSubmitTxResultCommon(result); - assert.equal(result.isGood(), false); - assert.equal(result.isDoubleSpendSeen(), true); - assert.equal(result.isFeeTooLow(), false); - assert.equal(result.isMixinTooLow(), false); - assert.equal(result.hasInvalidInput(), false); - assert.equal(result.hasInvalidOutput(), false); - assert.equal(result.isOverspend(), false); - assert.equal(result.isTooBig(), false); + assert.equal(result.getIsGood(), false); + assert.equal(result.getIsDoubleSpendSeen(), true); + assert.equal(result.getIsFeeTooLow(), false); + assert.equal(result.getIsMixinTooLow(), false); + assert.equal(result.getHasInvalidInput(), false); + assert.equal(result.getHasInvalidOutput(), false); + assert.equal(result.getIsOverspend(), false); + assert.equal(result.getIsTooBig(), false); } -function testSubmitTxResultCommon(result) { - assert.equal(typeof result.isGood(), "boolean"); - assert.equal(typeof result.isRelayed(), "boolean"); - assert.equal(typeof result.isDoubleSpendSeen(), "boolean"); - assert.equal(typeof result.isFeeTooLow(), "boolean"); - assert.equal(typeof result.isMixinTooLow(), "boolean"); - assert.equal(typeof result.hasInvalidInput(), "boolean"); - assert.equal(typeof result.hasInvalidOutput(), "boolean"); - assert.equal(typeof result.isOverspend(), "boolean"); - assert.equal(typeof result.isTooBig(), "boolean"); +function testSubmitTxResultCommon(result: MoneroSubmitTxResult) { + assert.equal(typeof result.getIsGood(), "boolean"); + assert.equal(typeof result.getIsRelayed(), "boolean"); + assert.equal(typeof result.getIsDoubleSpendSeen(), "boolean"); + assert.equal(typeof result.getIsFeeTooLow(), "boolean"); + assert.equal(typeof result.getIsMixinTooLow(), "boolean"); + assert.equal(typeof result.getHasInvalidInput(), "boolean"); + assert.equal(typeof result.getHasInvalidOutput(), "boolean"); + assert.equal(typeof result.getIsOverspend(), "boolean"); + assert.equal(typeof result.getIsTooBig(), "boolean"); assert.equal(typeof result.getSanityCheckFailed(), "boolean"); assert(result.getReason() === undefined || result.getReason().length > 0); } -function testTxPoolStats(stats) { +function testTxPoolStats(stats: MoneroTxPoolStats) { assert(stats); assert(stats.getNumTxs() >= 0); if (stats.getNumTxs() > 0) { if (stats.getNumTxs() === 1) assert.equal(stats.getHisto(), undefined); else { assert(stats.getHisto()); - console.log(stats.getHisto()); - throw new Error("Ready to test histogram"); + assert(stats.getHisto().size > 0); + for (let key of stats.getHisto().keys()) { + assert(stats.getHisto().get(key) >= 0); + } } assert(stats.getBytesMax() > 0); assert(stats.getBytesMed() > 0); @@ -1639,18 +1715,18 @@ function testKeyImage(image, ctx) { } } -function testOutput(output, ctx) { +function testOutput(output, ctx?) { assert(output instanceof MoneroOutput); - TestUtils.testUnsignedBigInteger(output.getAmount()); + TestUtils.testUnsignedBigInt(output.getAmount()); if (ctx) { - if (output.getTx().inTxPool() || ctx.fromGetTxPool || ctx.hasOutputIndices === false) assert.equal(output.getIndex(), undefined); // TODO: get_blocks_by_height.bin (#5127), get_transaction_pool, and tx pool txs do not return output indices + if (output.getTx().getInTxPool() || ctx.fromGetTxPool || ctx.hasOutputIndices === false) assert.equal(output.getIndex(), undefined); // TODO: get_blocks_by_height.bin (#5127), get_transaction_pool, and tx pool txs do not return output indices else assert(output.getIndex() >= 0); assert(output.getStealthPublicKey() && output.getStealthPublicKey().length === 64); } } async function getConfirmedTxs(daemon, numTxs) { - let txs = []; + let txs: MoneroTx[] = []; let numBlocksPerReq = 50; for (let startIdx = await daemon.getHeight() - numBlocksPerReq - 1; startIdx >= 0; startIdx -= numBlocksPerReq) { let blocks = await daemon.getBlocksByRange(startIdx, startIdx + numBlocksPerReq); @@ -1668,46 +1744,44 @@ async function getConfirmedTxs(daemon, numTxs) { function testAltChain(altChain) { assert(altChain instanceof MoneroAltChain); assert(Array.isArray(altChain.getBlockHashes()) && altChain.getBlockHashes().length > 0); - TestUtils.testUnsignedBigInteger(altChain.getDifficulty(), true); + TestUtils.testUnsignedBigInt(altChain.getDifficulty(), true); assert(altChain.getHeight() > 0); assert(altChain.getLength() > 0); assert(altChain.getMainChainParentBlockHash().length === 64); } -function testDaemonConnection(connection) { - assert(connection instanceof MoneroDaemonConnection); - assert(connection.getPeer()); - testKnownPeer(connection.getPeer(), true); - assert(connection.getId()); - assert(connection.getAvgDownload() >= 0); - assert(connection.getAvgUpload() >= 0); - assert(connection.getCurrentDownload() >= 0); - assert(connection.getCurrentUpload() >= 0); - assert(connection.getHeight() >= 0); - assert(connection.getLiveTime() >= 0); - assert.equal(typeof connection.isLocalIp(), "boolean"); - assert.equal(typeof connection.isLocalHost(), "boolean"); - assert(connection.getNumReceives() >= 0); - assert(connection.getReceiveIdleTime() >= 0); - assert(connection.getNumSends() >= 0); - assert(connection.getSendIdleTime() >= 0); - assert(connection.getState()); - assert(connection.getNumSupportFlags() >= 0); - ConnectionType.validate(connection.getType()); +function testPeer(peer) { + assert(peer instanceof MoneroPeer); + testKnownPeer(peer, true); + assert(peer.getId()); + assert(peer.getAvgDownload() >= 0); + assert(peer.getAvgUpload() >= 0); + assert(peer.getCurrentDownload() >= 0); + assert(peer.getCurrentUpload() >= 0); + assert(peer.getHeight() >= 0); + assert(peer.getLiveTime() >= 0); + assert.equal(typeof peer.getIsLocalIp(), "boolean"); + assert.equal(typeof peer.getIsLocalHost(), "boolean"); + assert(peer.getNumReceives() >= 0); + assert(peer.getReceiveIdleTime() >= 0); + assert(peer.getNumSends() >= 0); + assert(peer.getSendIdleTime() >= 0); + assert(peer.getState()); + assert(peer.getNumSupportFlags() >= 0); } -function testKnownPeer(peer, fromConnection) { - assert(peer instanceof MoneroDaemonPeer); +function testKnownPeer(peer, fromConnection?) { + assert(peer instanceof MoneroPeer); assert.equal(typeof peer.getId(), "string"); assert.equal(typeof peer.getHost(), "string"); assert(typeof peer.getPort() === "number"); assert(peer.getPort() > 0); assert(peer.getRpcPort() === undefined || (typeof peer.getRpcPort() === "number" && peer.getRpcPort() >= 0)); - assert.equal(typeof peer.isOnline(), "boolean"); - if (peer.getRpcCreditsPerHash() !== undefined) TestUtils.testUnsignedBigInteger(peer.getRpcCreditsPerHash()); + assert.equal(typeof peer.getIsOnline(), "boolean"); + if (peer.getRpcCreditsPerHash() !== undefined) TestUtils.testUnsignedBigInt(peer.getRpcCreditsPerHash()); if (fromConnection) assert.equal(undefined, peer.getLastSeenTimestamp()); else { - if (peer.getLastSeenTimestamp() < 0) console("Last seen timestamp is invalid: " + peer.getLastSeenTimestamp()); + if (peer.getLastSeenTimestamp() < 0) console.log("Last seen timestamp is invalid: " + peer.getLastSeenTimestamp()); assert(peer.getLastSeenTimestamp() >= 0); } assert(peer.getPruningSeed() === undefined || peer.getPruningSeed() >= 0); @@ -1715,8 +1789,8 @@ function testKnownPeer(peer, fromConnection) { function testUpdateCheckResult(result) { assert(result instanceof MoneroDaemonUpdateCheckResult); - assert.equal(typeof result.isUpdateAvailable(), "boolean"); - if (result.isUpdateAvailable()) { + assert.equal(typeof result.getIsUpdateAvailable(), "boolean"); + if (result.getIsUpdateAvailable()) { assert(result.getAutoUri(), "No auto uri; is daemon online?"); assert(result.getUserUri()); assert.equal(typeof result.getVersion(), "string"); @@ -1730,7 +1804,7 @@ function testUpdateCheckResult(result) { } } -function testUpdateDownloadResult(result, path) { +function testUpdateDownloadResult(result, path?) { testUpdateCheckResult(result); if (result.isUpdateAvailable()) { if (path) assert.equal(result.getDownloadPath(), path); @@ -1740,18 +1814,18 @@ function testUpdateDownloadResult(result, path) { } } -async function getConfirmedTxHashes(daemon) { +async function getConfirmedTxHashes(daemon): Promise { let numTxs = 5; - let txHashes = []; + let txHashes: string[] = []; let height = await daemon.getHeight(); - while (txHashes.length < numTxs) { + while (txHashes.length < numTxs && height > 0) { let block = await daemon.getBlockByHeight(--height); for (let txHash of block.getTxHashes()) txHashes.push(txHash); } return txHashes; } -function testTxCopy(tx, ctx) { +function testTxCopy(tx: MoneroTx, ctx) { // copy tx and test let copy = tx.copy(); @@ -1765,7 +1839,7 @@ function testTxCopy(tx, ctx) { else { assert(copy.getInputs() !== tx.getInputs()); for (let i = 0; i < copy.getInputs().length; i++) { - assert.equal(0, tx.getInputs()[i].getAmount().compare(copy.getInputs()[i].getAmount())); + assert.equal(tx.getInputs()[i].getAmount(), copy.getInputs()[i].getAmount()); } } @@ -1774,7 +1848,7 @@ function testTxCopy(tx, ctx) { else { assert(copy.getOutputs() !== tx.getOutputs()); for (let i = 0; i < copy.getOutputs().length; i++) { - assert.equal(0, tx.getOutputs()[i].getAmount().compare(copy.getOutputs()[i].getAmount())); + assert.equal(tx.getOutputs()[i].getAmount(), copy.getOutputs()[i].getAmount()); } } @@ -1788,5 +1862,3 @@ function testTxCopy(tx, ctx) { let merged = copy.merge(copy.copy()); assert.equal(merged.toString(), tx.toString()); } - -module.exports = TestMoneroDaemonRpc; \ No newline at end of file diff --git a/src/test/TestMoneroUtils.js b/src/test/TestMoneroUtils.js deleted file mode 100644 index 8bd6f22f9..000000000 --- a/src/test/TestMoneroUtils.js +++ /dev/null @@ -1,70 +0,0 @@ -const assert = require("assert"); -const monerojs = require("../../index"); -const MoneroUtils = monerojs.MoneroUtils; -const LibraryUtils = monerojs.LibraryUtils; - -/** - * Test utilities including those implemented in WebAssembly. - */ -class TestMoneroUtils { - - runTests() { - describe("TEST MONERO UTILITIES", function() { - - // initialize utils to test - before(async function() { - await LibraryUtils.loadKeysModule(); - }); - - describe("Binary Serialization", function() { - - it("Can serialize heights with small numbers", function() { - let json = { heights: [111, 222, 333] }; - let binary = MoneroUtils.jsonToBinary(json); - assert(binary); - let json2 = MoneroUtils.binaryToJson(binary); - assert.deepEqual(json2, json); - }); - - it("Can serialize heights with big numbers", function() { - let json = { heights: [123456, 1234567, 870987] }; - let binary = MoneroUtils.jsonToBinary(json); - assert(binary); - let json2 = MoneroUtils.binaryToJson(binary); - assert.deepEqual(json2, json); - }); - - it("Can serialize json with text", function() { - let json = { msg: 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' }; - let binary = MoneroUtils.jsonToBinary(json); - assert(binary); - let json2 = MoneroUtils.binaryToJson(binary); - assert.deepEqual(json2, json); - }); - - it("Can serialize json with long text", function() { - let json = { msg: 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + - 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n'}; - let binary = MoneroUtils.jsonToBinary(json); - assert(binary); - let json2 = MoneroUtils.binaryToJson(binary); - assert.deepEqual(json2, json); - }); - }); - }); - } -} - -module.exports = TestMoneroUtils; \ No newline at end of file diff --git a/src/test/TestMoneroUtils.ts b/src/test/TestMoneroUtils.ts new file mode 100644 index 000000000..79f7d3193 --- /dev/null +++ b/src/test/TestMoneroUtils.ts @@ -0,0 +1,274 @@ +import assert from "assert"; +import {MoneroError, + MoneroUtils, + MoneroNetworkType, + LibraryUtils} from "../../index"; + +/** + * Test utilities including those implemented in WebAssembly. + */ +export default class TestMoneroUtils { + + runTests() { + describe("TEST MONERO UTILITIES", function() { + + // initialize utils to test + before(async function() { + MoneroUtils.setProxyToWorker(true); + }); + + it("Can get integrated addresses", async function() { + let primaryAddress = "58qRVVjZ4KxMX57TH6yWqGcH5AswvZZS494hWHcHPt6cDkP7V8AqxFhi3RKXZueVRgUnk8niQGHSpY5Bm9DjuWn16GDKXpF"; + let subaddress = "7B9w2xieXjhDumgPX39h1CAYELpsZ7Pe8Wqtr3pVL9jJ5gGDqgxjWt55gTYUCAuhahhM85ajEp6VbQfLDPETt4oT2ZRXa6n"; + let paymentId = "03284e41c342f036"; + let networkType = MoneroNetworkType.STAGENET; + + // get integrated address with randomly generated payment id + let integratedAddress = await MoneroUtils.getIntegratedAddress(networkType, primaryAddress); + assert.equal(primaryAddress, integratedAddress.getStandardAddress()); + assert.equal(16, integratedAddress.getPaymentId().length); + assert.equal(106, integratedAddress.getIntegratedAddress().length); + + // get integrated address with specific payment id + integratedAddress = await MoneroUtils.getIntegratedAddress(networkType, primaryAddress, paymentId); + assert.equal(primaryAddress, integratedAddress.getStandardAddress()); + assert.equal(paymentId, integratedAddress.getPaymentId()); + assert.equal(106, integratedAddress.getIntegratedAddress().length); + + // get integrated address with subaddress + integratedAddress = await MoneroUtils.getIntegratedAddress(networkType, subaddress, paymentId); + assert.equal(subaddress, integratedAddress.getStandardAddress()); + assert.equal(paymentId, integratedAddress.getPaymentId()); + assert.equal(106, integratedAddress.getIntegratedAddress().length); + + // get integrated address with invalid payment id + try { + await MoneroUtils.getIntegratedAddress(networkType, primaryAddress, "123"); + throw new Error("Getting integrated address with invalid payment id should have failed"); + } catch (err) { + assert(err instanceof MoneroError); + assert.equal("Invalid payment id", err.message); + } + }); + + it("Can serialize heights with small numbers", async function() { + let json = { heights: [111, 222, 333] }; + let binary = await MoneroUtils.jsonToBinary(json); + assert(binary); + let json2 = await MoneroUtils.binaryToJson(binary); + assert.deepEqual(json2, json); + }); + + it("Can serialize heights with big numbers", async function() { + let json = { heights: [123456, 1234567, 870987] }; + let binary = await MoneroUtils.jsonToBinary(json); + assert(binary); + let json2 = await MoneroUtils.binaryToJson(binary); + assert.deepEqual(json2, json); + }); + + it("Can serialize json with text", async function() { + let json = { msg: 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' }; + let binary = await MoneroUtils.jsonToBinary(json); + assert(binary); + let json2 = await MoneroUtils.binaryToJson(binary); + assert.deepEqual(json2, json); + }); + + it("Can serialize json with long text", async function() { + let json = { msg: 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n' + + 'Hello there my good man lets make a nice long text to test with lots of exclamation marks!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n'}; + let binary = await MoneroUtils.jsonToBinary(json); + assert(binary); + let json2 = await MoneroUtils.binaryToJson(binary); + assert.deepEqual(json2, json); + }); + + it("Can validate addresses", async function() { + + // test mainnet primary address validation + assert(await MoneroUtils.isValidAddress("42U9v3qs5CjZEePHBZHwuSckQXebuZu299NSmVEmQ41YJZQhKcPyujyMSzpDH4VMMVSBo3U3b54JaNvQLwAjqDhKS3rvM3L", MoneroNetworkType.MAINNET)); + assert(await MoneroUtils.isValidAddress("48ZxX3Y2y5s4nJ8fdz2w65TrTEp9PRsv5J8iHSShkHQcE2V31FhnWptioNst1K9oeDY4KpWZ7v8V2BZNVa4Wdky89iqmPz2", MoneroNetworkType.MAINNET)); + assert(await MoneroUtils.isValidAddress("48W972Fx1SQMCHVKENnPpM7tRcL5oWMgpMCqQDbhH8UrjDFg2H9i5AQWXuU1qacJgUUCVLTsgDmZKXGz1vPLXY8QB5ypYqG", MoneroNetworkType.MAINNET)); + + // test mainnet integrated address validation + await MoneroUtils.validateAddress("4CApvrfMgUFZEePHBZHwuSckQXebuZu299NSmVEmQ41YJZQhKcPyujyMSzpDH4VMMVSBo3U3b54JaNvQLwAjqDhKeGLQ9vfRBRKFKnBtVH", MoneroNetworkType.MAINNET); + await MoneroUtils.validateAddress("4JGdXrMXaMP4nJ8fdz2w65TrTEp9PRsv5J8iHSShkHQcE2V31FhnWptioNst1K9oeDY4KpWZ7v8V2BZNVa4Wdky8DvDyXvDZXvE9jTQwom", MoneroNetworkType.MAINNET); + await MoneroUtils.validateAddress("4JCp7q5SchvMCHVKENnPpM7tRcL5oWMgpMCqQDbhH8UrjDFg2H9i5AQWXuU1qacJgUUCVLTsgDmZKXGz1vPLXY8QFySJXARQWju8AuRN2z", MoneroNetworkType.MAINNET); + + // test mainnet subaddress validation + await MoneroUtils.validateAddress("891TQPrWshJVpnBR4ZMhHiHpLx1PUnMqa3ccV5TJFBbqcJa3DWhjBh2QByCv3Su7WDPTGMHmCKkiVFN2fyGJKwbM1t6G7Ea", MoneroNetworkType.MAINNET); + await MoneroUtils.validateAddress("88fyq3t8Gxn1QWMG189EufHtMHXZXkfJtJKFJXqeA4GpSiuyfjVwVyp47PeQJnD7Tc8iK8TDvvhcmEmfh8nx7Va2ToP8wAo", MoneroNetworkType.MAINNET); + await MoneroUtils.validateAddress("88hnoBiX3TPjbFaQE8RxgyBcf3DtMKZWWQMoArBjQfn37JJwtm568mPX6ipcCuGKDnLCzgjmpLSqce4aBDyapJJAFtNxUMb", MoneroNetworkType.MAINNET); + + // test testnet primary address validation + await MoneroUtils.validateAddress("9tUBnNCkC3UKGygHCwYvAB1FscpjUuq5e9MYJd2rXuiiTjjfVeSVjnbSG5VTnJgBgy9Y7GTLfxpZNMUwNZjGfdFr1z79eV1", MoneroNetworkType.TESTNET); + await MoneroUtils.validateAddress("9xZmQa1kYakGoHcfXeBgcsLf622NCpChcACwXxfdgY9uAa9hXSPCV9cLvUsAShfDcFKDdPzCNJ1n5cFGKw5GVM722pjuGPd", MoneroNetworkType.TESTNET); + await MoneroUtils.validateAddress("A2TXS6QFQ4wEsp8U7C2Y4B7wBtiML8aDG7mdCbRvDQmRaRNj1YSSgJE46fSzUkwgpMUCXFqscvrQuN7oKpP6eDyQ7XuYsuf", MoneroNetworkType.TESTNET); + + // test testnet integrated address validation + await MoneroUtils.validateAddress("A4AroB2EoJzKGygHCwYvAB1FscpjUuq5e9MYJd2rXuiiTjjfVeSVjnbSG5VTnJgBgy9Y7GTLfxpZNMUwNZjGfdFr2QY5Ba2aHhTEdQa2ra", MoneroNetworkType.TESTNET); + await MoneroUtils.validateAddress("A8GSRNqF9rGGoHcfXeBgcsLf622NCpChcACwXxfdgY9uAa9hXSPCV9cLvUsAShfDcFKDdPzCNJ1n5cFGKw5GVM723iPoCEF1Fs9BcPYxTW", MoneroNetworkType.TESTNET); + await MoneroUtils.validateAddress("ACACSuDk1LTEsp8U7C2Y4B7wBtiML8aDG7mdCbRvDQmRaRNj1YSSgJE46fSzUkwgpMUCXFqscvrQuN7oKpP6eDyQAdgDoT3UnMYKQz7SHC", MoneroNetworkType.TESTNET); + + // test testnet subaddress validation + await MoneroUtils.validateAddress("BgnKzHPJQDcg7xiP7bMN9MfPv9Z8ciT71iEMYnCdgBRBFETWgu9nKTr8fnzyGfU9h9gyNA8SFzYYzHfTS9KhqytSU943Nu1", MoneroNetworkType.TESTNET); + await MoneroUtils.validateAddress("BZwiuKkoNP59zgPHTxpNw3PM4DW2xiAVQJWqfFRrGyeZ7afVdQqoiJg3E2dDL3Ja8BV4ov2LEoHx9UjzF3W4ihPBSZvWwTx", MoneroNetworkType.TESTNET); + await MoneroUtils.validateAddress("Bhf1DEYrentcehUvNreLK5gxosnC2VStMXNCCs163RTxQq4jxFYvpw7LrQFmrMwWW2KsXLhMRtyho6Lq11ci3Fb246bxYmi", MoneroNetworkType.TESTNET); + + // test stagenet primary address validation + await MoneroUtils.validateAddress("5B8s3obCY2ETeQB3GNAGPK2zRGen5UeW1WzegSizVsmf6z5NvM2GLoN6zzk1vHyzGAAfA8pGhuYAeCFZjHAp59jRVQkunGS", MoneroNetworkType.STAGENET); + await MoneroUtils.validateAddress("57VfotUbSZLG82UkKhWXDjS5ZEK9ZCDcmjdk4gpVq2fbKdEgwRCFrGTLZ2MMdSHphRWJDWVBi5qS8T7dz13JTCWtC228zyn", MoneroNetworkType.STAGENET); + await MoneroUtils.validateAddress("52FysgWJYmAG73QUQZRULJj2Dv2C2mceUMB5zHqNzMn8WBtfPWQrSUFSQUKTX9r7bUMmVSGbrau976xYLynR8jTWLdA7rfp", MoneroNetworkType.STAGENET); + + // test stagenet integrated address validation + await MoneroUtils.validateAddress("5LqY4cQh9HkTeQB3GNAGPK2zRGen5UeW1WzegSizVsmf6z5NvM2GLoN6zzk1vHyzGAAfA8pGhuYAeCFZjHAp59jRj6LZRFrjuGK8Whthg2", MoneroNetworkType.STAGENET); + await MoneroUtils.validateAddress("5HCLphJ63prG82UkKhWXDjS5ZEK9ZCDcmjdk4gpVq2fbKdEgwRCFrGTLZ2MMdSHphRWJDWVBi5qS8T7dz13JTCWtHETX8zcUhDjVKcynf6", MoneroNetworkType.STAGENET); + await MoneroUtils.validateAddress("5BxetVKoA2gG73QUQZRULJj2Dv2C2mceUMB5zHqNzMn8WBtfPWQrSUFSQUKTX9r7bUMmVSGbrau976xYLynR8jTWVwQwpHNg5fCLgtA2Dv", MoneroNetworkType.STAGENET); + + // test stagenet subaddress validation + await MoneroUtils.validateAddress("778B5D2JmMh5TJVWFbygJR15dvio5Z5B24hfSrWDzeroM8j8Lqc9sMoFE6324xg2ReaAZqHJkgfGFRugRmYHugHZ4f17Gxo", MoneroNetworkType.STAGENET); + await MoneroUtils.validateAddress("73U97wGEH9RCVUf6bopo45jSgoqjMzz4mTUsvWs5EusmYAmFcBYFm7wKMVmgtVKCBhMQqXrcMbHvwck2md63jMZSFJxUhQ2", MoneroNetworkType.STAGENET); + await MoneroUtils.validateAddress("747wPpaPKrjDPZrF48jAfz9pRRUHLMCWfYu2UanP4ZfTG8NrmYrSEWNW8gYoadU8hTiwBjV14e6DLaC5xfhyEpX5154aMm6", MoneroNetworkType.STAGENET); + + // test invalid addresses on mainnet + await testInvalidAddress(null, MoneroNetworkType.MAINNET); + await testInvalidAddress("", MoneroNetworkType.MAINNET); + await testInvalidAddress("42ZxX3Y2y5s4nJ8fdz2w65TrTEp9PRsv5J8iHSShkHQcE2V31FhnWptioNst1K9oeDY4KpWZ7v8V2BZNVa4Wdky89iqmPz2", MoneroNetworkType.MAINNET); + await testInvalidAddress("41ApvrfMgUFZEePHBZHwuSckQXebuZu299NSmVEmQ41YJZQhKcPyujyMSzpDH4VMMVSBo3U3b54JaNvQLwAjqDhKeGLQ9vfRBRKFKnBtVH", MoneroNetworkType.MAINNET); + await testInvalidAddress("81fyq3t8Gxn1QWMG189EufHtMHXZXkfJtJKFJXqeA4GpSiuyfjVwVyp47PeQJnD7Tc8iK8TDvvhcmEmfh8nx7Va2ToP8wAo", MoneroNetworkType.MAINNET); + + // test invalid addresses on testnet + await testInvalidAddress(null, MoneroNetworkType.TESTNET); + await testInvalidAddress("", MoneroNetworkType.TESTNET); + await testInvalidAddress("91UBnNCkC3UKGygHCwYvAB1FscpjUuq5e9MYJd2rXuiiTjjfVeSVjnbSG5VTnJgBgy9Y7GTLfxpZNMUwNZjGfdFr1z79eV1", MoneroNetworkType.TESTNET); + await testInvalidAddress("A1AroB2EoJzKGygHCwYvAB1FscpjUuq5e9MYJd2rXuiiTjjfVeSVjnbSG5VTnJgBgy9Y7GTLfxpZNMUwNZjGfdFr2QY5Ba2aHhTEdQa2ra", MoneroNetworkType.TESTNET); + await testInvalidAddress("B1nKzHPJQDcg7xiP7bMN9MfPv9Z8ciT71iEMYnCdgBRBFETWgu9nKTr8fnzyGfU9h9gyNA8SFzYYzHfTS9KhqytSU943Nu1", MoneroNetworkType.TESTNET); + + // test invalid addresses on stagenet + await testInvalidAddress(null, MoneroNetworkType.STAGENET); + await testInvalidAddress("", MoneroNetworkType.STAGENET); + await testInvalidAddress("518s3obCY2ETeQB3GNAGPK2zRGen5UeW1WzegSizVsmf6z5NvM2GLoN6zzk1vHyzGAAfA8pGhuYAeCFZjHAp59jRVQkunGS", MoneroNetworkType.STAGENET); + await testInvalidAddress("51qY4cQh9HkTeQB3GNAGPK2zRGen5UeW1WzegSizVsmf6z5NvM2GLoN6zzk1vHyzGAAfA8pGhuYAeCFZjHAp59jRj6LZRFrjuGK8Whthg2", MoneroNetworkType.STAGENET); + await testInvalidAddress("718B5D2JmMh5TJVWFbygJR15dvio5Z5B24hfSrWDzeroM8j8Lqc9sMoFE6324xg2ReaAZqHJkgfGFRugRmYHugHZ4f17Gxo", MoneroNetworkType.STAGENET); + }); + + it("Can validate keys", async function() { + + // test private view key validation + assert(await MoneroUtils.isValidPrivateViewKey("86cf351d10894769feba29b9e201e12fb100b85bb52fc5825c864eef55c5840d")); + await testInvalidPrivateViewKey(""); + await testInvalidPrivateViewKey(); + await testInvalidPrivateViewKey("5B8s3obCY2ETeQB3GNAGPK2zRGen5UeW1WzegSizVsmf6z5NvM2GLoN6zzk1vHyzGAAfA8pGhuYAeCFZjHAp59jRVQkunGS"); + + // test public view key validation + assert(await MoneroUtils.isValidPublicViewKey("99873d76ca874ff1aad676b835dd303abcb21c9911ca8a3d9130abc4544d8a0a")); + await testInvalidPublicViewKey(""); + await testInvalidPublicViewKey(); + await testInvalidPublicViewKey("z86cf351d10894769feba29b9e201e12fb100b85bb52fc5825c864eef55c5840d"); + + // test private spend key validation + assert(await MoneroUtils.isValidPrivateSpendKey("e9ba887e93620ef9fafdfe0c6d3022949f1c5713cbd9ef631f18a0fb00421dee")); + await testInvalidPrivateSpendKey(""); + await testInvalidPrivateSpendKey(null); + await testInvalidPrivateSpendKey("z86cf351d10894769feba29b9e201e12fb100b85bb52fc5825c864eef55c5840d"); + + // test public spend key validation + assert(await MoneroUtils.isValidPublicSpendKey("3e48df9e9d8038dbf6f5382fac2becd8686273cda5bd87187e45dca7ec5af37b")); + await testInvalidPublicSpendKey(""); + await testInvalidPublicSpendKey(); + await testInvalidPublicSpendKey("z86cf351d10894769feba29b9e201e12fb100b85bb52fc5825c864eef55c5840d"); + }); + + async function testInvalidAddress(address, networkType) { + assert(!await MoneroUtils.isValidAddress(address, networkType)); + try { + await MoneroUtils.validateAddress(address, networkType); + throw new Error("Should have thrown exception"); + } catch (err: any) { + assert.notEqual("Should have thrown exception", err.message); + assert(err.message); + } + } + + async function testInvalidPrivateViewKey(privateViewKey?) { + assert(!await MoneroUtils.isValidPrivateViewKey(privateViewKey)); + try { + await MoneroUtils.validatePrivateViewKey(privateViewKey); + throw new Error("Should have thrown exception"); + } catch (e: any) { + assert(e.message.length > 0); + } + } + + async function testInvalidPublicViewKey(publicViewKey?) { + assert(!await MoneroUtils.isValidPublicViewKey(publicViewKey)); + try { + await MoneroUtils.validatePublicViewKey(publicViewKey); + throw new Error("Should have thrown exception"); + } catch (e: any) { + assert(e.message.length > 0); + } + } + + async function testInvalidPrivateSpendKey(privateSpendKey) { + assert(!await MoneroUtils.isValidPrivateSpendKey(privateSpendKey)); + try { + await MoneroUtils.validatePrivateSpendKey(privateSpendKey); + throw new Error("Should have thrown exception"); + } catch (e: any) { + assert(e.message.length > 0); + } + } + + async function testInvalidPublicSpendKey(publicSpendKey?) { + assert(!await MoneroUtils.isValidPublicSpendKey(publicSpendKey)); + try { + await MoneroUtils.validatePublicSpendKey(publicSpendKey); + throw new Error("Should have thrown exception"); + } catch (e: any) { + assert(e.message.length > 0); + } + } + + it("Can convert between XMR and atomic units", function() { + assert.equal(MoneroUtils.xmrToAtomicUnits(1).toString(), 1000000000000n.toString()); + assert.equal(MoneroUtils.atomicUnitsToXmr(1000000000000n), 1); + assert.equal(MoneroUtils.xmrToAtomicUnits(0.001).toString(), 1000000000n.toString()); + assert.equal(MoneroUtils.atomicUnitsToXmr(1000000000n), .001); + assert.equal(MoneroUtils.xmrToAtomicUnits(.25).toString(), 250000000000n.toString()); + assert.equal(MoneroUtils.atomicUnitsToXmr(250000000000n), .25); + assert.equal(MoneroUtils.xmrToAtomicUnits(1.25).toString(), 1250000000000n.toString()); + assert.equal(MoneroUtils.atomicUnitsToXmr(1250000000000n), 1.25); + assert.equal(MoneroUtils.xmrToAtomicUnits("1").toString(), 1000000000000n.toString()); + assert.equal(MoneroUtils.atomicUnitsToXmr(1000000000000n), 1); + assert.equal(MoneroUtils.xmrToAtomicUnits("0.001").toString(), 1000000000n.toString()); + assert.equal(MoneroUtils.atomicUnitsToXmr(1000000000n), .001); + assert.equal(MoneroUtils.xmrToAtomicUnits(".25").toString(), 250000000000n.toString()); + assert.equal(MoneroUtils.atomicUnitsToXmr(250000000000n), .25); + assert.equal(MoneroUtils.xmrToAtomicUnits("1.25").toString(), 1250000000000n.toString()); + assert.equal(MoneroUtils.atomicUnitsToXmr(1250000000000n), 1.25); + assert.equal(MoneroUtils.xmrToAtomicUnits("2.79672619").toString(), 2796726190000n.toString()); + assert.equal(MoneroUtils.atomicUnitsToXmr(2796726190000n), 2.79672619); + assert.equal(MoneroUtils.xmrToAtomicUnits("2.796726190001").toString(), 2796726190001n.toString()); + assert.equal(MoneroUtils.atomicUnitsToXmr(2796726190001n), 2.796726190001); + assert.equal(MoneroUtils.xmrToAtomicUnits("2.796726189999").toString(), 2796726189999n.toString()); + assert.equal(MoneroUtils.atomicUnitsToXmr(2796726189999n), 2.796726189999); + assert.equal(MoneroUtils.xmrToAtomicUnits("2.79672618").toString(), 2796726180000n.toString()); + assert.equal(MoneroUtils.atomicUnitsToXmr(2796726180000n), 2.79672618); + }); + }) + } +} diff --git a/src/test/TestMoneroWalletCommon.js b/src/test/TestMoneroWalletCommon.js deleted file mode 100644 index 83967a145..000000000 --- a/src/test/TestMoneroWalletCommon.js +++ /dev/null @@ -1,4382 +0,0 @@ -const assert = require("assert"); -const StartMining = require("./utils/StartMining"); -const TestUtils = require("./utils/TestUtils"); -const monerojs = require("../../index"); -const MoneroTxPriority = monerojs.MoneroTxPriority; -const MoneroWalletRpc = monerojs.MoneroWalletRpc; -const MoneroWalletKeys = monerojs.MoneroWalletKeys; -const MoneroWallet = monerojs.MoneroWallet; -const MoneroUtils = monerojs.MoneroUtils; -const GenUtils = monerojs.GenUtils; -const MoneroSyncResult = monerojs.MoneroSyncResult; -const BigInteger = monerojs.BigInteger; -const MoneroTxQuery = monerojs.MoneroTxQuery; -const MoneroTransfer = monerojs.MoneroTransfer; -const MoneroTransferQuery = monerojs.MoneroTransferQuery; -const MoneroOutputQuery = monerojs.MoneroOutputQuery; -const MoneroOutputWallet = monerojs.MoneroOutputWallet; -const MoneroTxConfig = monerojs.MoneroTxConfig; -const MoneroTxWallet = monerojs.MoneroTxWallet; -const MoneroDestination = monerojs.MoneroDestination; -const MoneroAddressBookEntry = monerojs.MoneroAddressBookEntry; -const MoneroKeyImage = monerojs.MoneroKeyImage; -const Filter = monerojs.Filter; // TODO: don't export filter -const MoneroTx = monerojs.MoneroTx; - -// test constants -const MIXIN = 11; -const SEND_DIVISOR = 2; -const SEND_MAX_DIFF = 60; -const MAX_TX_PROOFS = 25; // maximum number of transactions to check for each proof, undefined to check all - -/** - * Test a wallet for common functionality. - * - * TODO: test filtering with not relayed - */ -class TestMoneroWalletCommon { - - /** - * Constructs the tester. - * - * @param testConfig is test configuration - */ - constructor(testConfig) { - this.testConfig = testConfig; - TestUtils.TX_POOL_WALLET_TRACKER.reset(); // all wallets need to wait for txs to confirm to reliably sync - } - - /** - * Get the daemon to test. - * - * @return the daemon to test - */ - async getTestDaemon() { - return TestUtils.getDaemonRpc(); - } - - /** - * Get the main wallet to test. - * - * @return the wallet to test - */ - async getTestWallet() { - throw new Error("Subclass must implement"); - } - - /** - * Open a test wallet with default configuration for each wallet type. - * - * @param config configures the wallet to open - * @return MoneroWallet is the opened wallet - */ - async openWallet(config) { - throw new Error("Subclass must implement"); - } - - /** - * Create a test wallet with default configuration for each wallet type. - * - * @param config configures the wallet to create - * @return MoneroWallet is the created wallet - */ - async createWallet(config) { - throw new Error("Subclass must implement"); - } - - /** - * Get the wallet's supported languages for the mnemonic phrase. This is an - * instance method for wallet rpc and a static utility for other wallets. - * - * @return {string[]} the wallet's supported languages - */ - async getMnemonicLanguages() { - throw new Error("Subclass must implement"); - } - - // ------------------------------ BEGIN TESTS ------------------------------- - - runCommonTests() { - let that = this; - let testConfig = this.testConfig; - describe("Common Wallet Tests" + (testConfig.liteMode ? " (lite mode)" : ""), function() { - - // TODO: before and after? -// before(async function() { -// }); -// -// after(async function() { -// }); - - // --------------------------- TEST NON RELAYS ------------------------- - - // local tx cache for tests - let txCache; - async function getCachedTxs() { - if (txCache !== undefined) return txCache; - txCache = await that.wallet.getTxs(); - testGetTxsStructure(txCache); - return txCache; - } - - if (testConfig.testNonRelays) - it("Can create a random wallet", async function() { - let e1 = undefined; - try { - that.wallet = await that.createWallet(); - let path; try { path = await that.wallet.getPath(); } catch(e) { } // TODO: factor out keys-only tests? - let e2 = undefined; - try { - MoneroUtils.validateAddress(await that.wallet.getPrimaryAddress()); - MoneroUtils.validatePrivateViewKey(await that.wallet.getPrivateViewKey()); - MoneroUtils.validatePrivateSpendKey(await that.wallet.getPrivateSpendKey()); - MoneroUtils.validateMnemonic(await that.wallet.getMnemonic()); - if (!(that.wallet instanceof MoneroWalletRpc)) assert.equal(await that.wallet.getMnemonicLanguage(), MoneroWallet.DEFAULT_LANGUAGE); // TODO monero-wallet-rpc: get mnemonic language - } catch (e) { - e2 = e; - } - await that.wallet.close(); - if (e2 !== undefined) throw e2; - - // attempt to create wallet at same path - if (path) { - try { - await that.createWallet({path: path}); - throw new Error("Should have thrown error"); - } catch(e) { - assert.equal(e.message, "Wallet already exists: " + path); - } - } - - // attempt to create wallet with unknown language - try { - await that.createWallet({language: "english"}); // TODO: support lowercase? - throw new Error("Should have thrown error"); - } catch (e) { - assert.equal(e.message, "Unknown language: english"); - } - } catch (e) { - e1 = e; - } - - // open main test wallet for other tests - that.wallet = await that.getTestWallet(); - if (e1 !== undefined) throw e1; - }); - - if (testConfig.testNonRelays) - it("Can create a wallet from a mnemonic phrase", async function() { - let e1 = undefined; - try { - - // save for comparison - let primaryAddress = await that.wallet.getPrimaryAddress(); - let privateViewKey = await that.wallet.getPrivateViewKey(); - let privateSpendKey = await that.wallet.getPrivateSpendKey(); - - // recreate test wallet from mnemonic - that.wallet = await that.createWallet({mnemonic: TestUtils.MNEMONIC, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}); - let path; try { path = await that.wallet.getPath(); } catch(e) { } // TODO: factor out keys-only tests? - let e2 = undefined; - try { - assert.equal(await that.wallet.getPrimaryAddress(), primaryAddress); - assert.equal(await that.wallet.getPrivateViewKey(), privateViewKey); - assert.equal(await that.wallet.getPrivateSpendKey(), privateSpendKey); - if (!(that.wallet instanceof MoneroWalletRpc)) assert.equal(await that.wallet.getMnemonicLanguage(), MoneroWallet.DEFAULT_LANGUAGE); - } catch (e) { - e2 = e; - } - await that.wallet.close(); - if (e2 !== undefined) throw e2; - - // attempt to create wallet at same path - if (path) { - try { - await that.createWallet({path: path}); - throw new Error("Should have thrown error"); - } catch (e) { - assert.equal(e.message, "Wallet already exists: " + path); - } - } - } catch (e) { - e1 = e; - } - - // open main test wallet for other tests - that.wallet = await that.getTestWallet(); - if (e1 !== undefined) throw e1; - }); - - if (testConfig.testNonRelays) - it("Can create a wallet from a mnemonic phrase with a seed offset", async function() { - let e1 = undefined; - try { - - // create test wallet with offset - that.wallet = await that.createWallet({mnemonic: TestUtils.MNEMONIC, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, seedOffset: "my secret offset!"}); - let e2 = undefined; - try { - MoneroUtils.validateMnemonic(await that.wallet.getMnemonic()); - assert.notEqual(await that.wallet.getMnemonic(), TestUtils.MNEMONIC); - MoneroUtils.validateAddress(await that.wallet.getPrimaryAddress(), TestUtils.NETWORK_TYPE); - assert.notEqual(await that.wallet.getPrimaryAddress(), TestUtils.ADDRESS); - if (!(that.wallet instanceof MoneroWalletRpc)) assert.equal(await that.wallet.getMnemonicLanguage(), MoneroWallet.DEFAULT_LANGUAGE); // TODO monero-wallet-rpc: support - } catch (e) { - e2 = e; - } - await that.wallet.close(); - if (e2 !== undefined) throw e2; - } catch (e) { - e1 = e; - } - - // open main test wallet for other tests - that.wallet = await that.getTestWallet(); - if (e1 !== undefined) throw e1; - }); - - if (testConfig.testNonRelays) - it("Can create a wallet from keys", async function() { - let e1 = undefined; - try { - - // save for comparison - let primaryAddress = await that.wallet.getPrimaryAddress(); - let privateViewKey = await that.wallet.getPrivateViewKey(); - let privateSpendKey = await that.wallet.getPrivateSpendKey(); - - // recreate test wallet from keys - that.wallet = await that.createWallet({primaryAddress: primaryAddress, privateViewKey: privateViewKey, privateSpendKey: privateSpendKey, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}); - let path; try { path = await that.wallet.getPath(); } catch(e) { } // TODO: factor out keys-only tests? - let e2 = undefined; - try { - assert.equal(await that.wallet.getPrimaryAddress(), primaryAddress); - assert.equal(await that.wallet.getPrivateViewKey(), privateViewKey); - assert.equal(await that.wallet.getPrivateSpendKey(), privateSpendKey); - if (!(that.wallet instanceof MoneroWalletKeys) && !await that.wallet.isConnected()) console.log("WARNING: wallet created from keys is not connected to authenticated daemon"); // TODO monero-core: keys wallets not connected - if (!(that.wallet instanceof MoneroWalletRpc)) { - assert.equal(await that.wallet.getMnemonic(), TestUtils.MNEMONIC); // TODO monero-wallet-rpc: cannot get mnemonic from wallet created from keys? - assert.equal(await that.wallet.getMnemonicLanguage(), MoneroWallet.DEFAULT_LANGUAGE); - } - } catch (e) { - e2 = e; - } - await that.wallet.close(); - if (e2 !== undefined) throw e2; - - // attempt to create wallet at same path - if (path) { - try { - await that.createWallet({path: path}); - throw new Error("Should have thrown error"); - } catch(e) { - assert.equal(e.message, "Wallet already exists: " + path); - } - } - } catch (e) { - e1 = e; - } - - // open main test wallet for other tests - that.wallet = await that.getTestWallet(); - if (e1 !== undefined) throw e1; - }); - - if (testConfig.testNonRelays) - it("Can get the wallet's version", async function() { - let version = await that.wallet.getVersion(); - assert.equal(typeof version.getNumber(), "number"); - assert(version.getNumber() > 0); - assert.equal(typeof version.isRelease(), "boolean"); - }); - - if (testConfig.testNonRelays) - it("Can get the wallet's path", async function() { - - // create a random wallet - let wallet = await that.createWallet(); - - // set a random attribute - let uuid = GenUtils.getUUID(); - await wallet.setAttribute("uuid", uuid); - - // record the wallet's path then save and close - let path = await wallet.getPath(); - await wallet.close(true); - - // re-open the wallet using its path - wallet = await that.openWallet({path: path}); - - // test the attribute - assert.equal(await wallet.getAttribute("uuid"), uuid); - - // re-open main test wallet - await wallet.close(); - that.wallet = await that.getTestWallet(); - }); - - if (testConfig.testNonRelays) - it("Can get the mnemonic phrase", async function() { - let mnemonic = await that.wallet.getMnemonic(); - MoneroUtils.validateMnemonic(mnemonic); - assert.equal(mnemonic, TestUtils.MNEMONIC); - }); - - if (testConfig.testNonRelays) - it("Can get the language of the mnemonic phrase", async function() { - let language = await that.wallet.getMnemonicLanguage(); - assert.equal(language, "English"); - }); - - if (testConfig.testNonRelays) - it("Can get a list of supported languages for the mnemonic phrase", async function() { - let languages = await that.getMnemonicLanguages(); - assert(Array.isArray(languages)); - assert(languages.length); - for (let language of languages) assert(language); - }); - - if (testConfig.testNonRelays) - it("Can get the private view key", async function() { - let privateViewKey = await that.wallet.getPrivateViewKey() - MoneroUtils.validatePrivateViewKey(privateViewKey); - }); - - if (testConfig.testNonRelays) - it("Can get the private spend key", async function() { - let privateSpendKey = await that.wallet.getPrivateSpendKey() - MoneroUtils.validatePrivateSpendKey(privateSpendKey); - }); - - if (testConfig.testNonRelays) - it("Can get the public view key", async function() { - let publicViewKey = await that.wallet.getPublicViewKey() - MoneroUtils.validatePublicViewKey(publicViewKey); - }); - - if (testConfig.testNonRelays) - it("Can get the public spend key", async function() { - let publicSpendKey = await that.wallet.getPublicSpendKey() - MoneroUtils.validatePublicSpendKey(publicSpendKey); - }); - - if (testConfig.testNonRelays) - it("Can get the primary address", async function() { - let primaryAddress = await that.wallet.getPrimaryAddress(); - MoneroUtils.validateAddress(primaryAddress); - let subaddress = (await that.wallet.getSubaddress(0, 0)); - assert.equal(primaryAddress, (await that.wallet.getSubaddress(0, 0)).getAddress()); - }); - - if (testConfig.testNonRelays) - it("Can get the address of a subaddress at a specified account and subaddress index", async function() { - assert.equal((await that.wallet.getSubaddress(0, 0)).getAddress(), await that.wallet.getPrimaryAddress()); - for (let account of await that.wallet.getAccounts(true)) { - for (let subaddress of account.getSubaddresses()) { - assert.equal(await that.wallet.getAddress(account.getIndex(), subaddress.getIndex()), subaddress.getAddress()); - } - } - }); - - if (testConfig.testNonRelays) - it("Can get addresses out of range of used accounts and subaddresses", async function() { - await that._testGetSubaddressAddressOutOfRange(); - }); - - if (testConfig.testNonRelays) - it("Can get the account and subaddress indices of an address", async function() { - - // get last subaddress to test - let accounts = await that.wallet.getAccounts(true); - let accountIdx = accounts.length - 1; - let subaddressIdx = accounts[accountIdx].getSubaddresses().length - 1; - let address = await that.wallet.getAddress(accountIdx, subaddressIdx); - assert(address); - assert.equal(typeof address, "string"); - - // get address index - let subaddress = await that.wallet.getAddressIndex(address); - assert.equal(subaddress.getAccountIndex(), accountIdx); - assert.equal(subaddress.getIndex(), subaddressIdx); - - // test valid but unfound address - let nonWalletAddress = await TestUtils.getExternalWalletAddress(); - try { - subaddress = await that.wallet.getAddressIndex(nonWalletAddress); - throw new Error("fail"); - } catch (e) { - assert.equal(e.message, "Address doesn't belong to the wallet"); - } - - // test invalid address - try { - subaddress = await that.wallet.getAddressIndex("this is definitely not an address"); - throw new Error("fail"); - } catch (e) { - assert.equal(e.message, "Invalid address"); - } - }); - - if (testConfig.testNonRelays) - it("Can get an integrated address given a payment id", async function() { - - // save address for later comparison - let address = (await that.wallet.getSubaddress(0, 0)).getAddress(); - - // test valid payment id - let paymentId = "03284e41c342f036"; - let integratedAddress = await that.wallet.getIntegratedAddress(paymentId); - assert.equal(integratedAddress.getStandardAddress(), address); - assert.equal(integratedAddress.getPaymentId(), paymentId); - - // test invalid payment id - let invalidPaymentId = "invalid_payment_id_123456"; - try { - integratedAddress = await that.wallet.getIntegratedAddress(invalidPaymentId); - throw new Error("Getting integrated address with invalid payment id " + invalidPaymentId + " should have thrown a RPC exception"); - } catch (e) { - //assert.equal(e.getCode(), -5); // TODO: error codes part of rpc only? - assert.equal(e.message, "Invalid payment ID: " + invalidPaymentId); - } - - // test undefined payment id which generates a new one - integratedAddress = await that.wallet.getIntegratedAddress(undefined); - assert.equal(integratedAddress.getStandardAddress(), address); - assert(integratedAddress.getPaymentId().length); - }); - - if (testConfig.testNonRelays) - it("Can decode an integrated address", async function() { - let integratedAddress = await that.wallet.getIntegratedAddress("03284e41c342f036"); - let decodedAddress = await that.wallet.decodeIntegratedAddress(integratedAddress.toString()); - assert.deepEqual(decodedAddress, integratedAddress); - }); - - // TODO: test syncing from start height - if (testConfig.testNonRelays) - it("Can sync (without progress)", async function() { - let numBlocks = 100; - let chainHeight = await that.daemon.getHeight(); - assert(chainHeight >= numBlocks); - let result = await that.wallet.sync(chainHeight - numBlocks); // sync to end of chain - assert(result instanceof MoneroSyncResult); - assert(result.getNumBlocksFetched() >= 0); - assert.equal(typeof result.getReceivedMoney(), "boolean"); - }); - - if (testConfig.testNonRelays) - it("Can get the current height that the wallet is synchronized to", async function() { - let height = await that.wallet.getHeight(); - assert(height >= 0); - }); - - if (testConfig.testNonRelays) - it("Can get a blockchain height by date", async function() { - - // collect dates to test starting 100 days ago - const DAY_MS = 24 * 60 * 60 * 1000; - let yesterday = new Date(new Date().getTime() - DAY_MS); // TODO monero-core: today's date can throw exception as "in future" so we test up to yesterday - let dates = []; - for (let i = 99; i >= 0; i--) { - dates.push(new Date(yesterday.getTime() - DAY_MS * i)); // subtract i days - } - - // test heights by date - let lastHeight = undefined; - for (let date of dates) { - let height = await that.wallet.getHeightByDate(date.getYear() + 1900, date.getMonth() + 1, date.getDate()); - assert(height >= 0); - if (lastHeight != undefined) assert(height >= lastHeight); - lastHeight = height; - } - assert(lastHeight > 0); - let height = await that.wallet.getHeight(); - assert(height >= 0); - - // test future date - try { - let tomorrow = new Date(yesterday.getTime() + DAY_MS * 2); - await that.wallet.getHeightByDate(tomorrow.getYear() + 1900, tomorrow.getMonth() + 1, tomorrow.getDate()); - throw new Error("Expected exception on future date"); - } catch (err) { - assert.equal(err.message, "specified date is in the future"); - } - }); - - if (testConfig.testNonRelays) - it("Can get the locked and unlocked balances of the wallet, accounts, and subaddresses", async function() { - - // fetch accounts with all info as reference - let accounts = await that.wallet.getAccounts(true); - - // test that balances add up between accounts and wallet - let accountsBalance = new BigInteger(0); - let accountsUnlockedBalance = new BigInteger(0); - for (let account of accounts) { - accountsBalance = accountsBalance.add(account.getBalance()); - accountsUnlockedBalance = accountsUnlockedBalance.add(account.getUnlockedBalance()); - - // test that balances add up between subaddresses and accounts - let subaddressesBalance = new BigInteger(0); - let subaddressesUnlockedBalance = new BigInteger(0); - for (let subaddress of account.getSubaddresses()) { - subaddressesBalance = subaddressesBalance.add(subaddress.getBalance()); - subaddressesUnlockedBalance = subaddressesUnlockedBalance.add(subaddress.getUnlockedBalance()); - - // test that balances are consistent with getAccounts() call - assert.equal((await that.wallet.getBalance(subaddress.getAccountIndex(), subaddress.getIndex())).toString(), subaddress.getBalance().toString()); - assert.equal((await that.wallet.getUnlockedBalance(subaddress.getAccountIndex(), subaddress.getIndex())).toString(), subaddress.getUnlockedBalance().toString()); - } - assert.equal((await that.wallet.getBalance(account.getIndex())).toString(), subaddressesBalance.toString()); - assert.equal((await that.wallet.getUnlockedBalance(account.getIndex())).toString(), subaddressesUnlockedBalance.toString()); - } - TestUtils.testUnsignedBigInteger(accountsBalance); - TestUtils.testUnsignedBigInteger(accountsUnlockedBalance); - assert.equal((await that.wallet.getBalance()).toString(), accountsBalance.toString()); - assert.equal((await that.wallet.getUnlockedBalance()).toString(), accountsUnlockedBalance.toString()); - - // test invalid input - try { - await that.wallet.getBalance(undefined, 0); - throw new Error("Should have failed"); - } catch(e) { - assert.notEqual(e.message, "Should have failed"); - } - }); - - if (testConfig.testNonRelays) - it("Can get accounts without subaddresses", async function() { - let accounts = await that.wallet.getAccounts(); - assert(accounts.length > 0); - accounts.map(account => { - testAccount(account) - assert(account.getSubaddresses() === undefined); - }); - }); - - if (testConfig.testNonRelays) - it("Can get accounts with subaddresses", async function() { - let accounts = await that.wallet.getAccounts(true); - assert(accounts.length > 0); - accounts.map(account => { - testAccount(account); - assert(account.getSubaddresses().length > 0); - }); - }); - - if (testConfig.testNonRelays) - it("Can get an account at a specified index", async function() { - let accounts = await that.wallet.getAccounts(); - assert(accounts.length > 0); - for (let account of accounts) { - testAccount(account); - - // test without subaddresses - let retrieved = await that.wallet.getAccount(account.getIndex()); - assert(retrieved.getSubaddresses() === undefined); - - // test with subaddresses - retrieved = await that.wallet.getAccount(account.getIndex(), true); - assert(retrieved.getSubaddresses().length > 0); - } - }); - - if (testConfig.testNonRelays) - it("Can create a new account without a label", async function() { - let accountsBefore = await that.wallet.getAccounts(); - let createdAccount = await that.wallet.createAccount(); - testAccount(createdAccount); - assert.equal((await that.wallet.getAccounts()).length - 1, accountsBefore.length); - }); - - if (testConfig.testNonRelays) - it("Can create a new account with a label", async function() { - - // create account with label - let accountsBefore = await that.wallet.getAccounts(); - let label = GenUtils.getUUID(); - let createdAccount = await that.wallet.createAccount(label); - testAccount(createdAccount); - assert.equal((await that.wallet.getAccounts()).length - 1, accountsBefore.length); - assert.equal((await that.wallet.getSubaddress(createdAccount.getIndex(), 0)).getLabel(), label); - - // fetch and test account - createdAccount = await that.wallet.getAccount(createdAccount.getIndex()); - testAccount(createdAccount); - - // create account with same label - createdAccount = await that.wallet.createAccount(label); - testAccount(createdAccount); - assert.equal((await that.wallet.getAccounts()).length - 2, accountsBefore.length); - assert.equal((await that.wallet.getSubaddress(createdAccount.getIndex(), 0)).getLabel(), label); - - // fetch and test account - createdAccount = await that.wallet.getAccount(createdAccount.getIndex()); - testAccount(createdAccount); - }); - - if (testConfig.testNonRelays) - it("Can get subaddresses at a specified account index", async function() { - let accounts = await that.wallet.getAccounts(); - assert(accounts.length > 0); - for (let account of accounts) { - let subaddresses = await that.wallet.getSubaddresses(account.getIndex()); - assert(subaddresses.length > 0); - subaddresses.map(subaddress => { - testSubaddress(subaddress); - assert(account.getIndex() === subaddress.getAccountIndex()); - }); - } - }); - - if (testConfig.testNonRelays) - it("Can get subaddresses at specified account and subaddress indices", async function() { - let accounts = await that.wallet.getAccounts(); - assert(accounts.length > 0); - for (let account of accounts) { - - // get subaddresses - let subaddresses = await that.wallet.getSubaddresses(account.getIndex()); - assert(subaddresses.length > 0); - - // remove a subaddress for query if possible - if (subaddresses.length > 1) subaddresses.splice(0, 1); - - // get subaddress indices - let subaddressIndices = subaddresses.map(subaddress => subaddress.getIndex()); - assert(subaddressIndices.length > 0); - - // fetch subaddresses by indices - let fetchedSubaddresses = await that.wallet.getSubaddresses(account.getIndex(), subaddressIndices); - - // original subaddresses (minus one removed if applicable) is equal to fetched subaddresses - assert.deepEqual(fetchedSubaddresses, subaddresses); - } - }); - - if (testConfig.testNonRelays) - it("Can get a subaddress at a specified account and subaddress index", async function() { - let accounts = await that.wallet.getAccounts(); - assert(accounts.length > 0); - for (let account of accounts) { - let subaddresses = await that.wallet.getSubaddresses(account.getIndex()); - assert(subaddresses.length > 0); - for (let subaddress of subaddresses) { - testSubaddress(subaddress); - assert.deepEqual(await that.wallet.getSubaddress(account.getIndex(), subaddress.getIndex()), subaddress); - assert.deepEqual((await that.wallet.getSubaddresses(account.getIndex(), subaddress.getIndex()))[0], subaddress); // test plural call with single subaddr number - } - } - }); - - if (testConfig.testNonRelays) - it("Can create a subaddress with and without a label", async function() { - - // create subaddresses across accounts - let accounts = await that.wallet.getAccounts(); - if (accounts.length < 2) await that.wallet.createAccount(); - accounts = await that.wallet.getAccounts(); - assert(accounts.length > 1); - for (let accountIdx = 0; accountIdx < 2; accountIdx++) { - - // create subaddress with no label - let subaddresses = await that.wallet.getSubaddresses(accountIdx); - let subaddress = await that.wallet.createSubaddress(accountIdx); - assert.equal(subaddress.getLabel(), undefined); - testSubaddress(subaddress); - let subaddressesNew = await that.wallet.getSubaddresses(accountIdx); - assert.equal(subaddressesNew.length - 1, subaddresses.length); - assert.deepEqual(subaddressesNew[subaddressesNew.length - 1].toString(), subaddress.toString()); - - // create subaddress with label - subaddresses = await that.wallet.getSubaddresses(accountIdx); - let uuid = GenUtils.getUUID(); - subaddress = await that.wallet.createSubaddress(accountIdx, uuid); - assert.equal(uuid, subaddress.getLabel()); - testSubaddress(subaddress); - subaddressesNew = await that.wallet.getSubaddresses(accountIdx); - assert.equal(subaddressesNew.length - 1, subaddresses.length); - assert.deepEqual(subaddressesNew[subaddressesNew.length - 1].toString(), subaddress.toString()); - } - }); - - if (testConfig.testNonRelays) - it("Can get transactions in the wallet", async function() { - let nonDefaultIncoming = false; - let txs1 = await getCachedTxs(); - let txs2 = await that._getAndTestTxs(that.wallet, undefined, true); - assert.equal(txs2.length, txs1.length); - assert(txs1.length > 0, "Wallet has no txs to test"); - assert.equal(txs1[0].getHeight(), TestUtils.FIRST_RECEIVE_HEIGHT, "First tx's restore height must match the restore height in TestUtils"); - - // test each tranasction - let blocksPerHeight = {}; - for (let i = 0; i < txs1.length; i++) { - await that._testTxWallet(txs1[i], {wallet: that.wallet}); - await that._testTxWallet(txs2[i], {wallet: that.wallet}); - assert.equal(txs1[i].toString(), txs2[i].toString()); - - // test merging equivalent txs - let copy1 = txs1[i].copy(); - let copy2 = txs2[i].copy(); - if (copy1.isConfirmed()) copy1.setBlock(txs1[i].getBlock().copy().setTxs([copy1])); - if (copy2.isConfirmed()) copy2.setBlock(txs2[i].getBlock().copy().setTxs([copy2])); - let merged = copy1.merge(copy2); - await that._testTxWallet(merged, {wallet: that.wallet}); - - // find non-default incoming - if (txs1[i].getIncomingTransfers()) { - for (let transfer of txs1[i].getIncomingTransfers()) { - if (transfer.getAccountIndex() !== 0 && transfer.getSubaddressIndex() !== 0) nonDefaultIncoming = true; - } - } - - // ensure unique block reference per height - if (txs2[i].isConfirmed()) { - let block = blocksPerHeight[txs2[i].getHeight()]; - if (block === undefined) blocksPerHeight[txs2[i].getHeight()] = txs2[i].getBlock(); - else assert(block === txs2[i].getBlock(), "Block references for same height must be same"); - } - } - - // ensure non-default account and subaddress tested - assert(nonDefaultIncoming, "No incoming transfers found to non-default account and subaddress; run send-to-multiple tests first"); - }); - - if (testConfig.testNonRelays) - it("Can get transactions by hash", async function() { - - let maxNumTxs = 10; // max number of txs to test - - // fetch all txs for testing - let txs = await that.wallet.getTxs(); - assert(txs.length > 1, "Test requires at least 2 txs to fetch by hash"); - - // randomly pick a few for fetching by hash - GenUtils.shuffle(txs); - txs = txs.slice(0, Math.min(txs.length, maxNumTxs)); - - // test fetching by hash - let fetchedTx = await that.wallet.getTx(txs[0].getHash()); - assert.equal(fetchedTx.getHash(), txs[0].getHash()); - await that._testTxWallet(fetchedTx); - - // test fetching by hashes - let txId1 = txs[0].getHash(); - let txId2 = txs[1].getHash(); - let fetchedTxs = await that.wallet.getTxs(txId1, txId2); - - // test fetching by hashes as collection - let txHashes = []; - for (let tx of txs) txHashes.push(tx.getHash()); - fetchedTxs = await that.wallet.getTxs(txHashes); - assert.equal(fetchedTxs.length, txs.length); - for (let i = 0; i < txs.length; i++) { - assert.equal(fetchedTxs[i].getHash(), txs[i].getHash()); - await that._testTxWallet(fetchedTxs[i]); - } - }); - - if (testConfig.testNonRelays && !testConfig.liteMode) - it("Can get transactions with additional configuration", async function() { - - // get random transactions for testing - let randomTxs = await getRandomTransactions(that.wallet, undefined, 3, 5); - for (let randomTx of randomTxs) await that._testTxWallet(randomTx); - - // get transactions by hash - let txHashes = []; - for (let randomTx of randomTxs) { - txHashes.push(randomTx.getHash()); - let txs = await that._getAndTestTxs(that.wallet, {hash: randomTx.getHash()}, true); - assert.equal(txs.length, 1); - let merged = txs[0].merge(randomTx.copy()); // txs change with chain so check mergeability - await that._testTxWallet(merged); - } - - // get transactions by hashes - let txs = await that._getAndTestTxs(that.wallet, {hashes: txHashes}); - assert.equal(txs.length, randomTxs.length); - for (let tx of txs) assert(txHashes.includes(tx.getHash())); - - // get transactions with an outgoing transfer - txs = await that._getAndTestTxs(that.wallet, {isOutgoing: true}, true); - for (let tx of txs) { - assert(tx.isOutgoing()); - assert(tx.getOutgoingTransfer() instanceof MoneroTransfer); - testTransfer(tx.getOutgoingTransfer()); - } - - // get transactions without an outgoing transfer - txs = await that._getAndTestTxs(that.wallet, {isOutgoing: false}, true); - for (let tx of txs) assert.equal(tx.getOutgoingTransfer(), undefined); - - // get transactions with incoming transfers - txs = await that._getAndTestTxs(that.wallet, {isIncoming: true}, true); - for (let tx of txs) { - assert(tx.getIncomingTransfers().length > 0); - for (let transfer of tx.getIncomingTransfers()) assert(transfer instanceof MoneroTransfer); - } - - // get transactions without incoming transfers - txs = await that._getAndTestTxs(that.wallet, {isIncoming: false}, true); - for (let tx of txs) assert.equal(tx.getIncomingTransfers(), undefined); - - // get transactions associated with an account - let accountIdx = 1; - txs = await that.wallet.getTxs({transferQuery: {accountIndex: accountIdx}}); - for (let tx of txs) { - let found = false; - if (tx.getOutgoingTransfer() && tx.getOutgoingTransfer().getAccountIndex() === accountIdx) found = true; - else if (tx.getIncomingTransfers()) { - for (let transfer of tx.getIncomingTransfers()) { - if (transfer.getAccountIndex() === accountIdx) { - found = true; - break; - } - } - } - assert(found, ("Transaction is not associated with account " + accountIdx + ":\n" + tx.toString())); - } - - // get transactions with incoming transfers to an account - txs = await that.wallet.getTxs({transferQuery: {isIncoming: true, accountIndex: accountIdx}}); - for (let tx of txs) { - assert(tx.getIncomingTransfers().length > 0); - let found = false; - for (let transfer of tx.getIncomingTransfers()) { - if (transfer.getAccountIndex() === accountIdx) { - found = true; - break; - } - } - assert(found, "No incoming transfers to account " + accountIdx + " found:\n" + tx.toString()); - } - - // get txs with manually built query that are confirmed and have an outgoing transfer from account 0 - let txQuery = new MoneroTxQuery(); - txQuery.setIsConfirmed(true); - txQuery.setTransferQuery(new MoneroTransferQuery().setAccountIndex(0).setIsOutgoing(true)); - txs = await that._getAndTestTxs(that.wallet, txQuery, true); - for (let tx of txs) { - if (!tx.isConfirmed()) console.log(tx.toString()); - assert.equal(tx.isConfirmed(), true); - assert(tx.getOutgoingTransfer()); - assert.equal(tx.getOutgoingTransfer().getAccountIndex(), 0); - } - - // get txs with outgoing transfers that have destinations to account 1 - txs = await that._getAndTestTxs(that.wallet, {transferQuery: {hasDestinations: true, accountIndex: 0}}); - for (let tx of txs) { - assert(tx.getOutgoingTransfer()); - assert(tx.getOutgoingTransfer().getDestinations().length > 0); - } - - // include outputs with transactions - txs = await that._getAndTestTxs(that.wallet, {includeOutputs: true}, true); - let found = false; - for (let tx of txs) { - if (tx.getOutputs()) { - assert(tx.getOutputs().length > 0); - found = true; - } else { - assert(tx.isOutgoing() || (tx.isIncoming() && !tx.isConfirmed())); // TODO: monero-wallet-rpc: return outputs for unconfirmed txs - } - } - assert(found, "No outputs found in txs"); - - // get txs with output query - let outputQuery = new MoneroOutputQuery().setIsSpent(false).setAccountIndex(1).setSubaddressIndex(2); - txs = await that.wallet.getTxs(new MoneroTxQuery().setOutputQuery(outputQuery)); - assert(txs.length > 0); - for (let tx of txs) { - assert(tx.getOutputs().length > 0); - found = false; - for (let output of tx.getOutputs()) { - if (output.isSpent() === false && output.getAccountIndex() === 1 && output.getSubaddressIndex() === 2) { - found = true; - break; - } - } - if (!found) throw new Error("Tx does not contain specified output"); - } - - // get unlocked txs - txs = await that.wallet.getTxs(new MoneroTxQuery().setIsLocked(false)); - assert(txs.length > 0); - for (let tx of txs) { - assert.equal(tx.isLocked(), false); - } - - // get confirmed transactions sent from/to same wallet with a transfer with destinations - txs = await that.wallet.getTxs({isIncoming: true, isOutgoing: true, isConfirmed: true, includeOutputs: true, transferQuery: { hasDestinations: true }}); - for (let tx of txs) { - assert(tx.isIncoming()); - assert(tx.isOutgoing()); - assert(tx.isConfirmed()); - assert(tx.getOutputs().length > 0); - assert.notEqual(tx.getOutgoingTransfer(), undefined); - assert.notEqual(tx.getOutgoingTransfer().getDestinations(), undefined); - assert(tx.getOutgoingTransfer().getDestinations().length > 0); - } - }); - - if (testConfig.testNonRelays) - it("Can get transactions by height", async function() { - - // get all confirmed txs for testing - let txs = await that._getAndTestTxs(that.wallet, new MoneroTxQuery().setIsConfirmed(true)); - assert(txs.length > 0, "Wallet has no confirmed txs; run send tests"); - - // collect all tx heights - let txHeights = []; - for (let tx of txs) txHeights.push(tx.getHeight()); - - // get height that most txs occur at - let heightCounts = countNumInstances(txHeights); - let heightModes = getModes(heightCounts); - let modeHeight = heightModes.values().next().value; - - // fetch txs at mode height - let modeTxs = await that._getAndTestTxs(that.wallet, new MoneroTxQuery().setHeight(modeHeight)); - assert.equal(modeTxs.length, heightCounts.get(modeHeight)); - - // fetch txs at mode height by range - let modeTxsByRange = await that._getAndTestTxs(that.wallet, new MoneroTxQuery().setMinHeight(modeHeight).setMaxHeight(modeHeight)); - assert.equal(modeTxsByRange.length, modeTxs.length); - assert.deepEqual(modeTxsByRange, modeTxs); - - // fetch all txs by range - let fetched = await that._getAndTestTxs(that.wallet, new MoneroTxQuery().setMinHeight(txs[0].getHeight()).setMaxHeight(txs[txs.length - 1].getHeight())); - assert.deepEqual(txs, fetched); - - // test some filtered by range // TODO: these are separated in Java? - { - txs = await that.wallet.getTxs({isConfirmed: true}); - assert(txs.length > 0, "No transactions; run send to multiple test"); - - // get and sort block heights in ascending order - let heights = []; - for (let tx of txs) { - heights.push(tx.getBlock().getHeight()); - } - GenUtils.sort(heights); - - // pick minimum and maximum heights for filtering - let minHeight = -1; - let maxHeight = -1; - if (heights.length == 1) { - minHeight = 0; - maxHeight = heights[0] - 1; - } else { - minHeight = heights[0] + 1; - maxHeight = heights[heights.length - 1] - 1; - } - - // assert some transactions filtered - let unfilteredCount = txs.length; - txs = await that._getAndTestTxs(that.wallet, {minHeight: minHeight, maxHeight: maxHeight}, true); - assert(txs.length < unfilteredCount); - for (let tx of txs) { - let height = tx.getBlock().getHeight(); - assert(height >= minHeight && height <= maxHeight); - } - } - }); - - // NOTE: payment hashes are deprecated so this test will require an old wallet to pass - if (testConfig.testNonRelays) - it("Can get transactions by payment ids", async function() { - - // get random transactions with payment hashes for testing - let randomTxs = await getRandomTransactions(that.wallet, {hasPaymentId: true}, 3, 5); - for (let randomTx of randomTxs) { - assert(randomTx.getPaymentId()); - } - - // get transactions by payment id - let paymentIds = randomTxs.map(tx => tx.getPaymentId()); - assert(paymentIds.length > 1); - for (let paymentId of paymentIds) { - let txs = await that._getAndTestTxs(that.wallet, {paymentId: paymentId}); - assert.equal(txs.length, 1); - assert(txs[0].getPaymentId()); - MoneroUtils.validatePaymentId(txs[0].getPaymentId()); - } - - // get transactions by payment hashes - let txs = await that._getAndTestTxs(that.wallet, {paymentIds: paymentIds}); - for (let tx of txs) { - assert(paymentIds.includes(tx.getPaymentId())); - } - }); - - if (testConfig.testNonRelays) - it("Returns all known fields of txs regardless of filtering", async function() { - - // fetch wallet txs - let txs = await that.wallet.getTxs({isConfirmed: true}); - for (let tx of txs) { - - // find tx sent to same wallet with incoming transfer in different account than src account - if (!tx.getOutgoingTransfer() || !tx.getIncomingTransfers()) continue; - for (let transfer of tx.getIncomingTransfers()) { - if (transfer.getAccountIndex() === tx.getOutgoingTransfer().getAccountIndex()) continue; - - // fetch tx with filtering - let filteredTxs = await that.wallet.getTxs({transferQuery: {isIncoming: true, accountIndex: transfer.getAccountIndex()}}); - let filteredTx = Filter.apply(new MoneroTxQuery().setHashes([tx.getHash()]), filteredTxs)[0]; - - // txs should be the same (mergeable) - assert.equal(filteredTx.getHash(), tx.getHash()); - tx.merge(filteredTx); - - // test is done - return; - } - } - - // test did not fully execute - throw new Error("Test requires tx sent from/to different accounts of same wallet but none found; run send tests"); - }); - - if (testConfig.testNonRelays && !testConfig.liteMode) - it("Validates inputs when getting transactions", async function() { - - // fetch random txs for testing - let randomTxs = await getRandomTransactions(that.wallet, undefined, 3, 5); - - // valid, invalid, and unknown tx hashes for tests - let txHash = randomTxs[0].getHash(); - let invalidHash = "invalid_id"; - let unknownHash1 = "6c4982f2499ece80e10b627083c4f9b992a00155e98bcba72a9588ccb91d0a61"; - let unknownHash2 = "ff397104dd875882f5e7c66e4f852ee134f8cf45e21f0c40777c9188bc92e943"; - - // fetch unknown tx hash - try { - await that.wallet.getTx(unknownHash1); - throw new Error("Should have thrown error getting tx hash unknown to wallet"); - } catch (e) { - assert.equal(e.message, "Wallet missing requested tx hashes: " + [unknownHash1]); - } - - // fetch unknown tx hash using query - try { - await that.wallet.getTxs(new MoneroTxQuery().setHash(unknownHash1)); - throw new Error("Should have thrown error getting tx hash unknown to wallet"); - } catch (e) { - assert.equal(e.message, "Wallet missing requested tx hashes: " + [unknownHash1]); - } - - // fetch unknown tx hash in collection - try { - await that.wallet.getTxs([txHash, unknownHash1]); - throw new Error("Should have thrown error getting tx hash unknown to wallet"); - } catch (e) { - assert.equal(e.message, "Wallet missing requested tx hashes: " + [unknownHash1]); - } - - // fetch unknown tx hashes in collection - try { - await that.wallet.getTxs([txHash, unknownHash1, unknownHash2]); - throw new Error("Should have thrown error getting tx hash unknown to wallet"); - } catch (e) { - assert.equal(e.message, "Wallet missing requested tx hashes: " + [unknownHash1, unknownHash2]); - } - - // fetch invalid hash - try { - await that.wallet.getTx(invalidHash); - throw new Error("Should have thrown error getting tx hash unknown to wallet"); - } catch (e) { - assert.equal(e.message, "Wallet missing requested tx hashes: " + [invalidHash]); - } - - // fetch invalid hash collection - try { - await that.wallet.getTxs([txHash, invalidHash]); - throw new Error("Should have thrown error getting tx hash unknown to wallet"); - } catch (e) { - assert.equal(e.message, "Wallet missing requested tx hashes: " + [invalidHash]); - } - - // fetch invalid hashes in collection - try { - await that.wallet.getTxs([txHash, invalidHash, "invalid_hash_2"]); - throw new Error("Should have thrown error getting tx hash unknown to wallet"); - } catch (e) { - assert.equal(e.message, "Wallet missing requested tx hashes: " + [invalidHash, "invalid_hash_2"]); - } - }); - - if (testConfig.testNonRelays) - it("Can get transfers in the wallet, accounts, and subaddresses", async function() { - - // get all transfers - await that._getAndTestTransfers(that.wallet, undefined, true); - - // get transfers by account index - let nonDefaultIncoming = false; - for (let account of await that.wallet.getAccounts(true)) { - let accountTransfers = await that._getAndTestTransfers(that.wallet, {accountIndex: account.getIndex()}); - for (let transfer of accountTransfers) assert.equal(transfer.getAccountIndex(), account.getIndex()); - - // get transfers by subaddress index - let subaddressTransfers = []; - for (let subaddress of account.getSubaddresses()) { - let transfers = await that._getAndTestTransfers(that.wallet, {accountIndex: subaddress.getAccountIndex(), subaddressIndex: subaddress.getIndex()}); - for (let transfer of transfers) { - - // test account and subaddress indices - assert.equal(transfer.getAccountIndex(), subaddress.getAccountIndex()); - if (transfer.isIncoming()) { - assert.equal(transfer.getSubaddressIndex(), subaddress.getIndex()); - if (transfer.getAccountIndex() !== 0 && transfer.getSubaddressIndex() !== 0) nonDefaultIncoming = true; - } else { - assert(transfer.getSubaddressIndices().includes(subaddress.getIndex())); - if (transfer.getAccountIndex() !== 0) { - for (let subaddrIdx of transfer.getSubaddressIndices()) { - if (subaddrIdx > 0) { - nonDefaultIncoming = true; - break; - } - } - } - } - - // don't add duplicates TODO monero-wallet-rpc: duplicate outgoing transfers returned for different subaddress indices, way to return outgoing subaddress indices? - let found = false; - for (let subaddressTransfer of subaddressTransfers) { - if (transfer.toString() === subaddressTransfer.toString() && transfer.getTx().getHash() === subaddressTransfer.getTx().getHash()) { - found = true; - break; - } - } - if (!found) subaddressTransfers.push(transfer); - } - } - assert.equal(subaddressTransfers.length, accountTransfers.length); - - // collect unique subaddress indices - let subaddressIndices = new Set(); - for (let transfer of subaddressTransfers) { - if (transfer.isIncoming()) subaddressIndices.add(transfer.getSubaddressIndex()); - else for (let subaddressIdx of transfer.getSubaddressIndices()) subaddressIndices.add(subaddressIdx); - } - - // get and test transfers by subaddress indices - let transfers = await that._getAndTestTransfers(that.wallet, new MoneroTransferQuery().setAccountIndex(account.getIndex()).setSubaddressIndices(Array.from(subaddressIndices)), undefined, undefined); - //if (transfers.length !== subaddressTransfers.length) console.log("WARNING: outgoing transfers always from subaddress 0 (monero-wallet-rpc #5171)"); - assert.equal(transfers.length, subaddressTransfers.length); // TODO monero-wallet-rpc: these may not be equal because outgoing transfers are always from subaddress 0 (#5171) and/or incoming transfers from/to same account are occluded (#4500) - for (let transfer of transfers) { - assert.equal(account.getIndex(), transfer.getAccountIndex()); - if (transfer.isIncoming()) assert(subaddressIndices.has(transfer.getSubaddressIndex())); - else { - let overlaps = false; - for (let subaddressIdx of subaddressIndices) { - for (let outSubaddressIdx of transfer.getSubaddressIndices()) { - if (subaddressIdx === outSubaddressIdx) { - overlaps = true; - break; - } - } - } - assert(overlaps, "Subaddresses must overlap"); - } - } - } - - // ensure transfer found with non-zero account and subaddress indices - assert(nonDefaultIncoming, "No transfers found in non-default account and subaddress; run send-to-multiple tests"); - }); - - if (testConfig.testNonRelays && !testConfig.liteMode) - it("Can get transfers with additional configuration", async function() { - - // get incoming transfers - let transfers = await that._getAndTestTransfers(that.wallet, {isIncoming: true}, true); - for (let transfer of transfers) assert(transfer.isIncoming()); - - // get outgoing transfers - transfers = await that._getAndTestTransfers(that.wallet, {isOutgoing: true}, true); - for (let transfer of transfers) assert(transfer.isOutgoing()); - - // get confirmed transfers to account 0 - transfers = await that._getAndTestTransfers(that.wallet, {accountIndex: 0, txQuery: {isConfirmed: true}}, true); - for (let transfer of transfers) { - assert.equal(transfer.getAccountIndex(), 0); - assert(transfer.getTx().isConfirmed()); - } - - // get confirmed transfers to [1, 2] - transfers = await that._getAndTestTransfers(that.wallet, {accountIndex: 1, subaddressIndex: 2, txQuery: {isConfirmed: true}}, true); - for (let transfer of transfers) { - assert.equal(transfer.getAccountIndex(), 1); - if (transfer.isIncoming()) assert.equal(transfer.getSubaddressIndex(), 2); - else assert(transfer.getSubaddressIndices().includes(2)); - assert(transfer.getTx().isConfirmed()); - } - - // get transfers in the tx pool - transfers = await that._getAndTestTransfers(that.wallet, {txQuery: {inTxPool: true}}); - for (let transfer of transfers) { - assert.equal(transfer.getTx().inTxPool(), true); - } - - // get random transactions - let txs = await getRandomTransactions(that.wallet, undefined, 3, 5); - - // get transfers with a tx hash - let txHashes = []; - for (let tx of txs) { - txHashes.push(tx.getHash()); - transfers = await that._getAndTestTransfers(that.wallet, {txQuery: {hash: tx.getHash()}}, true); - for (let transfer of transfers) assert.equal(transfer.getTx().getHash(), tx.getHash()); - } - - // get transfers with tx hashes - transfers = await that._getAndTestTransfers(that.wallet, {txQuery: {hashes: txHashes}}, true); - for (let transfer of transfers) assert(txHashes.includes(transfer.getTx().getHash())); - - // TODO: test that transfers with the same tx hash have the same tx reference - - // TODO: test transfers destinations - - // get transfers with pre-built query that are confirmed and have outgoing destinations - let transferQuery = new MoneroTransferQuery(); - transferQuery.setIsOutgoing(true); - transferQuery.setHasDestinations(true); - transferQuery.setTxQuery(new MoneroTxQuery().setIsConfirmed(true)); - transfers = await that._getAndTestTransfers(that.wallet, transferQuery); - for (let transfer of transfers) { - assert.equal(transfer.isOutgoing(), true); - assert(transfer.getDestinations().length > 0); - assert.equal(transfer.getTx().isConfirmed(), true); - } - - // get incoming transfers to account 0 which has outgoing transfers (i.e. originated from the same wallet) - transfers = await that.wallet.getTransfers({accountIndex: 1, isIncoming: true, txQuery: {isOutgoing: true}}) - assert(transfers.length > 0); - for (let transfer of transfers) { - assert(transfer.isIncoming()); - assert.equal(transfer.getAccountIndex(), 1); - assert(transfer.getTx().isOutgoing()); - assert.equal(transfer.getTx().getOutgoingTransfer(), undefined); - } - }); - - if (testConfig.testNonRelays && !testConfig.liteMode) - it("Validates inputs when getting transfers", async function() { - - // test with invalid hash - let transfers = await that.wallet.getTransfers({txQuery: {hash: "invalid_id"}}); - assert.equal(transfers.length, 0); - - // test invalid hash in collection - let randomTxs = await getRandomTransactions(that.wallet, undefined, 3, 5); - transfers = await that.wallet.getTransfers({txQuery: {hashes: [randomTxs[0].getHash(), "invalid_id"]}}); - assert(transfers.length > 0); - let tx = transfers[0].getTx(); - for (let transfer of transfers) assert(tx === transfer.getTx()); - - // test unused subaddress indices - transfers = await that.wallet.getTransfers({accountIndex: 0, subaddressIndices: [1234907]}); - assert(transfers.length === 0); - - // test invalid subaddress index - try { - let transfers = await that.wallet.getTransfers({accountIndex: 0, subaddressIndex: -1}); - throw new Error("Should have failed"); - } catch (e) { - assert.notEqual(e.message, "Should have failed"); - } - }); - - if (testConfig.testNonRelays) - it("Can get incoming and outgoing transfers using convenience methods", async function() { - let accountIdx = 1; - let subaddressIdx = 1; - - // get incoming transfers - let inTransfers = await that.wallet.getIncomingTransfers(); - assert(inTransfers.length > 0); - for (let transfer of inTransfers) { - assert(transfer.isIncoming()); - testTransfer(transfer, undefined); - } - - // get incoming transfers with query - inTransfers = await that.wallet.getIncomingTransfers(new MoneroTransferQuery().setAccountIndex(accountIdx).setSubaddressIndex(subaddressIdx)); - assert(inTransfers.length > 0); - for (let transfer of inTransfers) { - assert(transfer.isIncoming()); - assert.equal(transfer.getAccountIndex(), accountIdx); - assert.equal(transfer.getSubaddressIndex(), subaddressIdx); - testTransfer(transfer, undefined); - } - - // get incoming transfers with contradictory query - try { - inTransfers = await that.wallet.getIncomingTransfers(new MoneroTransferQuery().setIsIncoming(false)); - } catch (e) { - assert.equal(e.message, "Transfer query contradicts getting incoming transfers"); - } - - // get outgoing transfers - let outTransfers = await that.wallet.getOutgoingTransfers(); - assert(outTransfers.length > 0); - for (let transfer of outTransfers) { - assert(transfer.isOutgoing()); - testTransfer(transfer, undefined); - } - - // get outgoing transfers with query - outTransfers = await that.wallet.getOutgoingTransfers(new MoneroTransferQuery().setAccountIndex(accountIdx).setSubaddressIndex(subaddressIdx)); - assert(outTransfers.length > 0); - for (let transfer of outTransfers) { - assert(transfer.isOutgoing()); - assert.equal(transfer.getAccountIndex(), accountIdx); - assert(transfer.getSubaddressIndices().includes(subaddressIdx)); - testTransfer(transfer, undefined); - } - - // get outgoing transfers with contradictory query - try { - outTransfers = await that.wallet.getOutgoingTransfers(new MoneroTransferQuery().setIsOutgoing(false)); - } catch (e) { - assert.equal(e.message, "Transfer query contradicts getting outgoing transfers"); - } - }); - - if (testConfig.testNonRelays) - it("Can get outputs in the wallet, accounts, and subaddresses", async function() { - - // get all outputs - await that._getAndTestOutputs(that.wallet, undefined, true); - - // get outputs for each account - let nonDefaultIncoming = false; - let accounts = await that.wallet.getAccounts(true); - for (let account of accounts) { - - // determine if account is used - let isUsed = false; - for (let subaddress of account.getSubaddresses()) if (subaddress.isUsed()) isUsed = true; - - // get outputs by account index - let accountOutputs = await that._getAndTestOutputs(that.wallet, {accountIndex: account.getIndex()}, isUsed); - for (let output of accountOutputs) assert.equal(output.getAccountIndex(), account.getIndex()); - - // get outputs by subaddress index - let subaddressOutputs = []; - for (let subaddress of account.getSubaddresses()) { - let outputs = await that._getAndTestOutputs(that.wallet, {accountIndex: account.getIndex(), subaddressIndex: subaddress.getIndex()}, subaddress.isUsed()); - for (let output of outputs) { - assert.equal(output.getAccountIndex(), subaddress.getAccountIndex()); - assert.equal(output.getSubaddressIndex(), subaddress.getIndex()); - if (output.getAccountIndex() !== 0 && output.getSubaddressIndex() !== 0) nonDefaultIncoming = true; - subaddressOutputs.push(output); - } - } - assert.equal(subaddressOutputs.length, accountOutputs.length); - - // get outputs by subaddress indices - let subaddressIndices = Array.from(new Set(subaddressOutputs.map(output => output.getSubaddressIndex()))); - let outputs = await that._getAndTestOutputs(that.wallet, {accountIndex: account.getIndex(), subaddressIndices: subaddressIndices}, isUsed); - assert.equal(outputs.length, subaddressOutputs.length); - for (let output of outputs) { - assert.equal(output.getAccountIndex(), account.getIndex()); - assert(subaddressIndices.includes(output.getSubaddressIndex())); - } - } - - // ensure output found with non-zero account and subaddress indices - assert(nonDefaultIncoming, "No outputs found in non-default account and subaddress; run send-to-multiple tests"); - }); - - if (testConfig.testNonRelays && !testConfig.liteMode) - it("Can get outputs with additional configuration", async function() { - - // get unspent outputs to account 0 - let outputs = await that._getAndTestOutputs(that.wallet, {accountIndex: 0, isSpent: false}); - for (let output of outputs) { - assert.equal(output.getAccountIndex(), 0); - assert.equal(output.isSpent(), false); - } - - // get spent outputs to account 1 - outputs = await that._getAndTestOutputs(that.wallet, {accountIndex: 1, isSpent: true}, true); - for (let output of outputs) { - assert.equal(output.getAccountIndex(), 1); - assert.equal(output.isSpent(), true); - } - - // get random transactions - let txs = await getRandomTransactions(that.wallet, {isConfirmed: true}, 3, 5); - - // get outputs with a tx hash - let txHashes = []; - for (let tx of txs) { - txHashes.push(tx.getHash()); - outputs = await that._getAndTestOutputs(that.wallet, {txQuery: {hash: tx.getHash()}}, true); - for (let output of outputs) assert.equal(output.getTx().getHash(), tx.getHash()); - } - - // get outputs with tx hashes - outputs = await that._getAndTestOutputs(that.wallet, {txQuery: {hashes: txHashes}}, true); - for (let output of outputs) assert(txHashes.includes(output.getTx().getHash())); - - // get confirmed outputs to specific subaddress with pre-built query - let accountIdx = 0; - let subaddressIdx = 1; - let query = new MoneroOutputQuery(); - query.setAccountIndex(accountIdx).setSubaddressIndex(subaddressIdx); - query.setTxQuery(new MoneroTxQuery().setIsConfirmed(true)); - query.setMinAmount(TestUtils.MAX_FEE); - outputs = await that._getAndTestOutputs(that.wallet, query, true); - for (let output of outputs) { - assert.equal(output.getAccountIndex(), accountIdx); - assert.equal(output.getSubaddressIndex(), subaddressIdx); - assert.equal(output.getTx().isConfirmed(), true); - assert(output.getAmount().compare(TestUtils.MAX_FEE) >= 0); - } - - // get output by key image - let keyImage = outputs[0].getKeyImage().getHex(); - outputs = await that.wallet.getOutputs(new MoneroOutputQuery().setKeyImage(new MoneroKeyImage(keyImage))); - assert.equal(outputs.length, 1); - assert.equal(outputs[0].getKeyImage().getHex(), keyImage); - - // get outputs whose transaction is confirmed and has incoming and outgoing transfers - outputs = await that.wallet.getOutputs({txQuery: {isConfirmed: true, isIncoming: true, isOutgoing: true, includeOutputs: true}}); - assert(outputs.length > 0); - for (let output of outputs) { - assert(output.getTx().isIncoming()); - assert(output.getTx().isOutgoing()); - assert(output.getTx().isConfirmed()); - assert(output.getTx().getOutputs().length > 0); - assert(GenUtils.arrayContains(output.getTx().getOutputs(), output, true)); - } - }); - - if (testConfig.testNonRelays && !testConfig.liteMode) - it("Validates inputs when getting outputs", async function() { - - // test with invalid hash - let outputs = await that.wallet.getOutputs({txQuery: {hash: "invalid_id"}}); - assert.equal(outputs.length, 0); - - // test invalid hash in collection - let randomTxs = await getRandomTransactions(that.wallet, {isConfirmed: true, includeOutputs: true}, 3, 5); - outputs = await that.wallet.getOutputs({txQuery: {hashes: [randomTxs[0].getHash(), "invalid_id"]}}); - assert(outputs.length > 0); - assert.equal(randomTxs[0].getOutputs().length, outputs.length); - let tx = outputs[0].getTx(); - for (let output of outputs) assert(tx === output.getTx()); - }); - - if (testConfig.testNonRelays) - it("Can get outputs in hex format", async function() { - let outputsHex = await that.wallet.getOutputsHex(); - assert.equal(typeof outputsHex, "string"); // TODO: this will fail if wallet has no outputs; run these tests on new wallet - assert(outputsHex.length > 0); - }); - - if (testConfig.testNonRelays) - it("Can import outputs in hex format", async function() { - - // get outputs hex - let outputsHex = await that.wallet.getOutputsHex(); - - // import outputs hex - if (outputsHex !== undefined) { - let numImported = await that.wallet.importOutputsHex(outputsHex); - assert(numImported > 0); - } - }); - - if (testConfig.testNonRelays) - it("Has correct accounting across accounts, subaddresses, txs, transfers, and outputs", async function() { - - // pre-fetch wallet balances, accounts, subaddresses, and txs - let walletBalance = await that.wallet.getBalance(); - let walletUnlockedBalance = await that.wallet.getUnlockedBalance(); - let accounts = await that.wallet.getAccounts(true); // includes subaddresses - let txs = await that.wallet.getTxs(); - - // test wallet balance - TestUtils.testUnsignedBigInteger(walletBalance); - TestUtils.testUnsignedBigInteger(walletUnlockedBalance); - assert(walletBalance.compare(walletUnlockedBalance) >= 0); - - // test that wallet balance equals sum of account balances - let accountsBalance = new BigInteger(0); - let accountsUnlockedBalance = new BigInteger(0); - for (let account of accounts) { - testAccount(account); // test that account balance equals sum of subaddress balances - accountsBalance = accountsBalance.add(account.getBalance()); - accountsUnlockedBalance = accountsUnlockedBalance.add(account.getUnlockedBalance()); - } - assert.equal(walletBalance.compare(accountsBalance), 0); - assert.equal(walletUnlockedBalance.compare(accountsUnlockedBalance), 0); - -// // test that wallet balance equals net of wallet's incoming and outgoing tx amounts -// // TODO monero-wallet-rpc: these tests are disabled because incoming transfers are not returned when sent from the same account, so doesn't balance #4500 -// // TODO: test unlocked balance based on txs, requires e.g. tx.isLocked() -// let outgoingSum = new BigInteger(0); -// let incomingSum = new BigInteger(0); -// for (let tx of txs) { -// if (tx.getOutgoingAmount()) outgoingSum = outgoingSum.add(tx.getOutgoingAmount()); -// if (tx.getIncomingAmount()) incomingSum = incomingSum.add(tx.getIncomingAmount()); -// } -// assert.equal(incomingSum.subtract(outgoingSum).toString(), walletBalance.toString()); -// -// // test that each account's balance equals net of account's incoming and outgoing tx amounts -// for (let account of accounts) { -// if (account.getIndex() !== 1) continue; // find 1 -// outgoingSum = new BigInteger(0); -// incomingSum = new BigInteger(0); -// let filter = new MoneroTxQuery(); -// filter.setAccountIndex(account.getIndex()); -// for (let tx of txs.filter(tx => filter.meetsCriteria(tx))) { // normally we'd call wallet.getTxs(filter) but we're using pre-fetched txs -// if (tx.getHash() === "8d3919d98dd5a734da8c52eddc558db3fbf059ad55d432f0052ecd59ef122ecb") console.log(tx.toString(0)); -// -// //console.log((tx.getOutgoingAmount() ? tx.getOutgoingAmount().toString() : "") + ", " + (tx.getIncomingAmount() ? tx.getIncomingAmount().toString() : "")); -// if (tx.getOutgoingAmount()) outgoingSum = outgoingSum.add(tx.getOutgoingAmount()); -// if (tx.getIncomingAmount()) incomingSum = incomingSum.add(tx.getIncomingAmount()); -// } -// assert.equal(incomingSum.subtract(outgoingSum).toString(), account.getBalance().toString()); -// } - - // balance may not equal sum of unspent outputs if unconfirmed txs - // TODO monero-wallet-rpc: reason not to return unspent outputs on unconfirmed txs? then this isn't necessary - let hasUnconfirmedTx = false; - for (let tx of txs) if (tx.inTxPool()) hasUnconfirmedTx = true; - - // wallet balance is sum of all unspent outputs - let walletSum = new BigInteger(0); - for (let output of await that.wallet.getOutputs({isSpent: false})) walletSum = walletSum.add(output.getAmount()); - if (walletBalance.toString() !== walletSum.toString()) assert(hasUnconfirmedTx, "Wallet balance must equal sum of unspent outputs if no unconfirmed txs"); - - // account balances are sum of their unspent outputs - for (let account of accounts) { - let accountSum = new BigInteger(0); - let accountOutputs = await that.wallet.getOutputs({accountIndex: account.getIndex(), isSpent: false}); - for (let output of accountOutputs) accountSum = accountSum.add(output.getAmount()); - if (account.getBalance().toString() !== accountSum.toString()) assert(hasUnconfirmedTx, "Account balance must equal sum of its unspent outputs if no unconfirmed txs"); - - // subaddress balances are sum of their unspent outputs - for (let subaddress of account.getSubaddresses()) { - let subaddressSum = new BigInteger(0); - let subaddressOutputs = await that.wallet.getOutputs({accountIndex: account.getIndex(), subaddressIndex: subaddress.getIndex(), isSpent: false}); - for (let output of subaddressOutputs) subaddressSum = subaddressSum.add(output.getAmount()); - if (subaddress.getBalance().toString() !== subaddressSum.toString()) assert(hasUnconfirmedTx, "Subaddress balance must equal sum of its unspent outputs if no unconfirmed txs"); - } - } - }); - - if (testConfig.testNonRelays) - it("Can get and set a transaction note", async function() { - let txs = await getRandomTransactions(that.wallet, undefined, 1, 5); - - // set notes - let uuid = GenUtils.getUUID(); - for (let i = 0; i < txs.length; i++) { - await that.wallet.setTxNote(txs[i].getHash(), uuid + i); - } - - // get notes - for (let i = 0; i < txs.length; i++) { - assert.equal(await that.wallet.getTxNote(txs[i].getHash()), uuid + i); - } - }); - - // TODO: why does getting cached txs take 2 seconds when should already be cached? - if (testConfig.testNonRelays) - it("Can get and set multiple transaction notes", async function() { - - // set tx notes - let uuid = GenUtils.getUUID(); - let txs = await getCachedTxs(); - assert(txs.length >= 3, "Test requires 3 or more wallet transactions; run send tests"); - let txHashes = []; - let txNotes = []; - for (let i = 0; i < txHashes.length; i++) { - txHashes.push(txs[i].getHash()); - txNotes.push(uuid + i); - } - await that.wallet.setTxNotes(txHashes, txNotes); - - // get tx notes - txNotes = await that.wallet.getTxNotes(txHashes); - for (let i = 0; i < txHashes.length; i++) { - assert.equal(uuid + i, txNotes[i]); - } - - // TODO: test that get transaction has note - }); - - if (testConfig.testNonRelays) - it("Can check a transfer using the transaction's secret key and the destination", async function() { - - // get random txs that are confirmed and have outgoing destinations - let txs; - try { - txs = await getRandomTransactions(that.wallet, {isConfirmed: true, isOutgoing: true, transferQuery: {hasDestinations: true}}, 1, MAX_TX_PROOFS); - } catch (e) { - if (e.message.indexOf("found with")) throw new Error("No txs with outgoing destinations found; run send tests") - throw e; - } - - // test good checks - assert(txs.length > 0, "No transactions found with outgoing destinations"); - for (let tx of txs) { - let key = await that.wallet.getTxKey(tx.getHash()); - for (let destination of tx.getOutgoingTransfer().getDestinations()) { - let check = await that.wallet.checkTxKey(tx.getHash(), key, destination.getAddress()); - if (destination.getAmount().compare(new BigInteger()) > 0) { - // TODO monero-wallet-rpc: indicates amount received amount is 0 despite transaction with transfer to this address - // TODO monero-wallet-rpc: returns 0-4 errors, not consistent -// assert(check.getReceivedAmount().compare(new BigInteger(0)) > 0); - if (check.getReceivedAmount().compare(new BigInteger(0)) === 0) { - console.log("WARNING: key proof indicates no funds received despite transfer (txid=" + tx.getHash() + ", key=" + key + ", address=" + destination.getAddress() + ", amount=" + destination.getAmount() + ")"); - } - } - else assert(check.getReceivedAmount().compare(new BigInteger(0)) === 0); - testCheckTx(tx, check); - } - } - - // test get tx key with invalid hash - try { - await that.wallet.getTxKey("invalid_tx_id"); - throw new Error("Should throw exception for invalid key"); - } catch (e) { - assert.equal(e.getCode(), -8); - } - - // test check with invalid tx hash - let tx = txs[0]; - let key = await that.wallet.getTxKey(tx.getHash()); - let destination = tx.getOutgoingTransfer().getDestinations()[0]; - try { - await that.wallet.checkTxKey("invalid_tx_id", key, destination.getAddress()); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -8); - } - - // test check with invalid key - try { - await that.wallet.checkTxKey(tx.getHash(), "invalid_tx_key", destination.getAddress()); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -25); - } - - // test check with invalid address - try { - await that.wallet.checkTxKey(tx.getHash(), key, "invalid_tx_address"); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -2); - } - - // test check with different address - let differentAddress; - for (let aTx of await getCachedTxs()) { - if (!aTx.getOutgoingTransfer() || !aTx.getOutgoingTransfer().getDestinations()) continue; - for (let aDestination of aTx.getOutgoingTransfer().getDestinations()) { - if (aDestination.getAddress() !== destination.getAddress()) { - differentAddress = aDestination.getAddress(); - break; - } - } - } - assert(differentAddress, "Could not get a different outgoing address to test; run send tests"); - let check = await that.wallet.checkTxKey(tx.getHash(), key, differentAddress); - assert(check.isGood()); - assert(check.getReceivedAmount().compare(new BigInteger(0)) >= 0); - testCheckTx(tx, check); - }); - - if (testConfig.testNonRelays) - it("Can prove a transaction by getting its signature", async function() { - - // get random txs that are confirmed and have outgoing destinations - let txs; - try { - txs = await getRandomTransactions(that.wallet, {isConfirmed: true, isOutgoing: true, transferQuery: {hasDestinations: true}}, 2, MAX_TX_PROOFS); - } catch (e) { - if (e.message.indexOf("found with")) throw new Error("No txs with outgoing destinations found; run send tests") - throw e; - } - - // test good checks with messages - for (let tx of txs) { - for (let destination of tx.getOutgoingTransfer().getDestinations()) { - let signature = await that.wallet.getTxProof(tx.getHash(), destination.getAddress(), "This transaction definitely happened."); - let check = await that.wallet.checkTxProof(tx.getHash(), destination.getAddress(), "This transaction definitely happened.", signature); - testCheckTx(tx, check); - } - } - - // test good check without message - let tx = txs[0]; - let destination = tx.getOutgoingTransfer().getDestinations()[0]; - let signature = await that.wallet.getTxProof(tx.getHash(), destination.getAddress()); - let check = await that.wallet.checkTxProof(tx.getHash(), destination.getAddress(), undefined, signature); - testCheckTx(tx, check); - - // test get proof with invalid hash - try { - await that.wallet.getTxProof("invalid_tx_id", destination.getAddress()); - throw new Error("Should throw exception for invalid key"); - } catch (e) { - assert.equal(e.getCode(), -8); - } - - // test check with invalid tx hash - try { - await that.wallet.checkTxProof("invalid_tx_id", destination.getAddress(), undefined, signature); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -8); - } - - // test check with invalid address - try { - await that.wallet.checkTxProof(tx.getHash(), "invalid_tx_address", undefined, signature); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -2); - } - - // test check with wrong message - signature = await that.wallet.getTxProof(tx.getHash(), destination.getAddress(), "This is the right message"); - check = await that.wallet.checkTxProof(tx.getHash(), destination.getAddress(), "This is the wrong message", signature); - assert.equal(check.isGood(), false); - testCheckTx(tx, check); - - // test check with wrong signature - let wrongSignature = await that.wallet.getTxProof(txs[1].getHash(), txs[1].getOutgoingTransfer().getDestinations()[0].getAddress(), "This is the right message"); - try { - check = await that.wallet.checkTxProof(tx.getHash(), destination.getAddress(), "This is the right message", wrongSignature); - assert.equal(check.isGood(), false); - } catch (e) { - assert.equal(e.getCode(), -1); // TODO: sometimes comes back bad, sometimes throws exception. ensure txs come from different addresses? - } - }); - - if (testConfig.testNonRelays) - it("Can prove a spend using a generated signature and no destination public address", async function() { - - // get random confirmed outgoing txs - let txs = await getRandomTransactions(that.wallet, {isIncoming: false, inTxPool: false, isFailed: false}, 2, MAX_TX_PROOFS); - for (let tx of txs) { - assert.equal(tx.isConfirmed(), true); - assert.equal(tx.getIncomingTransfers(), undefined); - assert(tx.getOutgoingTransfer()); - } - - // test good checks with messages - for (let tx of txs) { - let signature = await that.wallet.getSpendProof(tx.getHash(), "I am a message."); - assert(await that.wallet.checkSpendProof(tx.getHash(), "I am a message.", signature)); - } - - // test good check without message - let tx = txs[0]; - let signature = await that.wallet.getSpendProof(tx.getHash()); - assert(await that.wallet.checkSpendProof(tx.getHash(), undefined, signature)); - - // test get proof with invalid hash - try { - await that.wallet.getSpendProof("invalid_tx_id"); - throw new Error("Should throw exception for invalid key"); - } catch (e) { - assert.equal(e.getCode(), -8); - } - - // test check with invalid tx hash - try { - await that.wallet.checkSpendProof("invalid_tx_id", undefined, signature); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -8); - } - - // test check with invalid message - signature = await that.wallet.getSpendProof(tx.getHash(), "This is the right message"); - assert.equal(await that.wallet.checkSpendProof(tx.getHash(), "This is the wrong message", signature), false); - - // test check with wrong signature - signature = await that.wallet.getSpendProof(txs[1].getHash(), "This is the right message"); - assert.equal(await that.wallet.checkSpendProof(tx.getHash(), "This is the right message", signature), false); - }); - - if (testConfig.testNonRelays) - it("Can prove reserves in the wallet", async function() { - - // get proof of entire wallet - let signature = await that.wallet.getReserveProofWallet("Test message"); - - // check proof of entire wallet - let check = await that.wallet.checkReserveProof(await that.wallet.getPrimaryAddress(), "Test message", signature); - assert(check.isGood()); - testCheckReserve(check); - let balance = await that.wallet.getBalance(); - if (balance.compare(check.getTotalAmount()) !== 0) { // TODO monero-wallet-rpc: this check fails with unconfirmed txs - let unconfirmedTxs = await that.wallet.getTxs({inTxPool: true}); - assert(unconfirmedTxs.length > 0, "Reserve amount must equal balance unless wallet has unconfirmed txs"); - } - - // test different wallet address - let differentAddress = await TestUtils.getExternalWalletAddress(); - try { - await that.wallet.checkReserveProof(differentAddress, "Test message", signature); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -1); - } - - // test subaddress - try { - await that.wallet.checkReserveProof((await that.wallet.getSubaddress(0, 1)).getAddress(), "Test message", signature); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -1); - } - - // test wrong message - check = await that.wallet.checkReserveProof(await that.wallet.getPrimaryAddress(), "Wrong message", signature); - assert.equal(check.isGood(), false); // TODO: specifically test reserve checks, probably separate objects - testCheckReserve(check); - - // test wrong signature - try { - await that.wallet.checkReserveProof(await that.wallet.getPrimaryAddress(), "Test message", "wrong signature"); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -1); - } - }); - - if (testConfig.testNonRelays) - it("Can prove reserves in an account", async function() { - - // test proofs of accounts - let numNonZeroTests = 0; - let msg = "Test message"; - let accounts = await that.wallet.getAccounts(); - let signature; - for (let account of accounts) { - if (account.getBalance().compare(new BigInteger(0)) > 0) { - let checkAmount = (await account.getBalance()).divide(new BigInteger(2)); - signature = await that.wallet.getReserveProofAccount(account.getIndex(), checkAmount, msg); - let check = await that.wallet.checkReserveProof(await that.wallet.getPrimaryAddress(), msg, signature); - assert(check.isGood()); - testCheckReserve(check); - assert(check.getTotalAmount().compare(checkAmount) >= 0); - numNonZeroTests++; - } else { - try { - await that.wallet.getReserveProofAccount(account.getIndex(), account.getBalance(), msg); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -1); - try { - await that.wallet.getReserveProofAccount(account.getIndex(), TestUtils.MAX_FEE, msg); - throw new Error("Should have thrown exception"); - } catch (e2) { - assert.equal(e2.getCode(), -1); - } - } - } - } - assert(numNonZeroTests > 1, "Must have more than one account with non-zero balance; run send-to-multiple tests"); - - // test error when not enough balance for requested minimum reserve amount - try { - let reserveProof = await that.wallet.getReserveProofAccount(0, accounts[0].getBalance().add(TestUtils.MAX_FEE), "Test message"); - throw new Error("should have thrown error"); - } catch (e) { - if (e.message === "should have thrown error") throw new Error("Should have thrown exception but got reserve proof: https://github.com/monero-project/monero/issues/6595"); - assert.equal(e.getCode(), -1); - } - - // test different wallet address - let differentAddress = await TestUtils.getExternalWalletAddress(); - try { - await that.wallet.checkReserveProof(differentAddress, "Test message", signature); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -1); - } - - // test subaddress - try { - await that.wallet.checkReserveProof((await that.wallet.getSubaddress(0, 1)).getAddress(), "Test message", signature); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -1); - } - - // test wrong message - let check = await that.wallet.checkReserveProof(await that.wallet.getPrimaryAddress(), "Wrong message", signature); - assert.equal(check.isGood(), false); // TODO: specifically test reserve checks, probably separate objects - testCheckReserve(check); - - // test wrong signature - try { - await that.wallet.checkReserveProof(await that.wallet.getPrimaryAddress(), "Test message", "wrong signature"); - throw new Error("Should have thrown exception"); - } catch (e) { - assert.equal(e.getCode(), -1); - } - }); - - if (testConfig.testNonRelays) - it("Can get signed key images", async function() { - let images = await that.wallet.getKeyImages(); - assert(Array.isArray(images)); - assert(images.length > 0, "No signed key images in wallet"); - for (let image of images) { - assert(image instanceof MoneroKeyImage); - assert(image.getHex()); - assert(image.getSignature()); - } - }); - - if (testConfig.testNonRelays) - it("Can get new key images from the last import", async function() { - - // get outputs hex - let outputsHex = await that.wallet.getOutputsHex(); - - // import outputs hex - if (outputsHex !== undefined) { - let numImported = await that.wallet.importOutputsHex(outputsHex); - assert(numImported > 0); - } - - // get and test new key images from last import - let images = await that.wallet.getNewKeyImagesFromLastImport(); - assert(Array.isArray(images)); - assert(images.length > 0, "No new key images in last import"); // TODO: these are already known to the wallet, so no new key images will be imported - for (let image of images) { - assert(image.getHex()); - assert(image.getSignature()); - } - }); - - if (testConfig.testNonRelays && false) // TODO monero core: importing key images can cause erasure of incoming transfers per wallet2.cpp:11957 - it("Can import key images", async function() { - let images = await that.wallet.getKeyImages(); - assert(Array.isArray(images)); - assert(images.length > 0, "Wallet does not have any key images; run send tests"); - let result = await that.wallet.importKeyImages(images); - assert(result.getHeight() > 0); - - // determine if non-zero spent and unspent amounts are expected - let txs = await that.wallet.getTxs({isConfirmed: true, transferQuery: {isOutgoing: true}}); - let balance = await that.wallet.getBalance(); - let hasSpent = txs.length > 0; - let hasUnspent = balance.toJSValue() > 0; - - // test amounts - TestUtils.testUnsignedBigInteger(result.getSpentAmount(), hasSpent); - TestUtils.testUnsignedBigInteger(result.getUnspentAmount(), hasUnspent); - }); - - if (testConfig.testNonRelays) - it("Can sign and verify messages", async function() { - let msg = "This is a super important message which needs to be signed and verified."; - let signature = await that.wallet.signMessage(msg); - let verified = await that.wallet.verifyMessage(msg, await that.wallet.getAddress(0, 0), signature); - assert.equal(verified, true); - verified = await that.wallet.verifyMessage(msg, await TestUtils.getExternalWalletAddress(), signature); - assert.equal(verified, false); - }); - - if (testConfig.testNonRelays) - it("Has an address book", async function() { - - // initial state - let entries = await that.wallet.getAddressBookEntries(); - let numEntriesStart = entries.length - for (let entry of entries) testAddressBookEntry(entry); - - // test adding standard addresses - const NUM_ENTRIES = 5; - let address = (await that.wallet.getSubaddress(0, 0)).getAddress(); - let indices = []; - for (let i = 0; i < NUM_ENTRIES; i++) { - indices.push(await that.wallet.addAddressBookEntry(address, "hi there!")); - } - entries = await that.wallet.getAddressBookEntries(); - assert.equal(entries.length, numEntriesStart + NUM_ENTRIES); - for (let idx of indices) { - let found = false; - for (let entry of entries) { - if (idx === entry.getIndex()) { - testAddressBookEntry(entry); - assert.equal(entry.getAddress(), address); - assert.equal(entry.getDescription(), "hi there!"); - found = true; - break; - } - } - assert(found, "Index " + idx + " not found in address book indices"); - } - - // edit each address book entry - for (let idx of indices) { - await that.wallet.editAddressBookEntry(idx, false, undefined, true, "hello there!!"); - } - entries = await that.wallet.getAddressBookEntries(indices); - for (let entry of entries) { - assert.equal(entry.getDescription(), "hello there!!"); - } - - // delete entries at starting index - let deleteIdx = indices[0]; - for (let i = 0; i < indices.length; i++) { - await that.wallet.deleteAddressBookEntry(deleteIdx); - } - entries = await that.wallet.getAddressBookEntries(); - assert.equal(entries.length, numEntriesStart); - - // test adding integrated addresses - indices = []; - let paymentId = "03284e41c342f03"; // payment id less one character - let integratedAddresses = {}; - let integratedDescriptions = {}; - for (let i = 0; i < NUM_ENTRIES; i++) { - let integratedAddress = await that.wallet.getIntegratedAddress(paymentId + i); // create unique integrated address - let uuid = GenUtils.getUUID(); - let idx = await that.wallet.addAddressBookEntry(integratedAddress.toString(), uuid); - indices.push(idx); - integratedAddresses[idx] = integratedAddress; - integratedDescriptions[idx] = uuid; - } - entries = await that.wallet.getAddressBookEntries(); - assert.equal(entries.length, numEntriesStart + NUM_ENTRIES); - for (let idx of indices) { - let found = false; - for (let entry of entries) { - if (idx === entry.getIndex()) { - testAddressBookEntry(entry); - assert.equal(entry.getDescription(), integratedDescriptions[idx]); - assert.equal(entry.getAddress(), integratedAddresses[idx].toString()); - assert.equal(entry.getPaymentId(), undefined); - found = true; - break; - } - } - assert(found, "Index " + idx + " not found in address book indices"); - } - - // delete entries at starting index - deleteIdx = indices[0]; - for (let i = 0; i < indices.length; i++) { - await that.wallet.deleteAddressBookEntry(deleteIdx); - } - entries = await that.wallet.getAddressBookEntries(); - assert.equal(entries.length, numEntriesStart); - }); - - if (testConfig.testNonRelays) - it("Can get and set arbitrary key/value attributes", async function() { - - // set attributes - let attrs = {}; - for (let i = 0; i < 5; i++) { - let key = "attr" + i; - let val = GenUtils.getUUID(); - attrs[key] = val; - await that.wallet.setAttribute(key, val); - } - - // test attributes - for (let key of Object.keys(attrs)) { - assert.equal(attrs[key], await that.wallet.getAttribute(key)); - } - - // get an undefined attribute - assert.equal(await that.wallet.getAttribute("unset_key"), undefined); - }); - - if (testConfig.testNonRelays) - it("Can convert between a tx config and payment URI", async function() { - - // test with address and amount - let config1 = new MoneroTxConfig({address: await that.wallet.getAddress(0, 0), amount: new BigInteger(0)}); - let uri = await that.wallet.createPaymentUri(config1); - let config2 = await that.wallet.parsePaymentUri(uri); - GenUtils.deleteUndefinedKeys(config1); - GenUtils.deleteUndefinedKeys(config2); - assert.deepEqual(JSON.parse(JSON.stringify(config2)), JSON.parse(JSON.stringify(config1))); - - // test with all fields3 - config1.getDestinations()[0].setAmount(BigInteger.parse("425000000000")); - config1.setPaymentId("03284e41c342f03603284e41c342f03603284e41c342f03603284e41c342f036"); - config1.setRecipientName("John Doe"); - config1.setNote("OMZG XMR FTW"); - uri = await that.wallet.createPaymentUri(config1.toJson()); - config2 = await that.wallet.parsePaymentUri(uri); - GenUtils.deleteUndefinedKeys(config1); - GenUtils.deleteUndefinedKeys(config2); - assert.deepEqual(JSON.parse(JSON.stringify(config2)), JSON.parse(JSON.stringify(config1))); - - // test with undefined address - let address = config1.getDestinations()[0].getAddress(); - config1.getDestinations()[0].setAddress(undefined); - try { - await that.wallet.createPaymentUri(config1); - fail("Should have thrown exception with invalid parameters"); - } catch (e) { - assert(e.message.indexOf("Cannot make URI from supplied parameters") >= 0); - } - config1.getDestinations()[0].setAddress(address); - - // test with invalid payment id - config1.setPaymentId("bizzup"); - try { - await that.wallet.createPaymentUri(config1); - fail("Should have thrown exception with invalid parameters"); - } catch (e) { - assert(e.message.indexOf("Cannot make URI from supplied parameters") >= 0); - } - }); - - if (testConfig.testNonRelays) - it("Can start and stop mining", async function() { - let status = await that.daemon.getMiningStatus(); - if (status.isActive()) await that.wallet.stopMining(); - await that.wallet.startMining(2, false, true); - await that.wallet.stopMining(); - }); - - if (testConfig.testNonRelays) - it("Can save and close the wallet in a single call", async function() { - - // create a random wallet - let wallet = await that.createWallet(); - let path = await wallet.getPath(); - - // set an attribute - let uuid = GenUtils.getUUID(); - await wallet.setAttribute("id", uuid); - - // close the wallet without saving - await wallet.close(); - - // re-open the wallet and ensure attribute was not saved - wallet = await that.openWallet({path: path}); - assert.equal(await wallet.getAttribute("id"), undefined); - - // set the attribute and close with saving - await wallet.setAttribute("id", uuid); - await wallet.save(); - await wallet.close(); - - // re-open the wallet and ensure attribute was saved - wallet = await that.openWallet({path: path}); - assert.equal(await wallet.getAttribute("id"), uuid); - - // re-open main test wallet - await wallet.close(); // defaults to not saving - that.wallet = await that.getTestWallet(); - }); - - // ------------------------ TEST NOTIFICATIONS -------------------------- - - // TODO: test sending to multiple accounts - - if (testConfig.testRelays && testConfig.testNotifications) - it("Can update a locked tx sent from/to the same account as blocks are added to the chain", async function() { - let config = new MoneroTxConfig({accountIndex: 0, address: await that.wallet.getPrimaryAddress(), amount: TestUtils.MAX_FEE, unlockHeight: await that.daemon.getHeight() + 3, canSplit: false, relay: true}); - await testSendAndUpdateTxs(config); - }); - - if (testConfig.testRelays && testConfig.testNotifications && !testConfig.liteMode) - it("Can update split locked txs sent from/to the same account as blocks are added to the chain", async function() { - let config = new MoneroTxConfig({accountIndex: 0, address: await that.wallet.getPrimaryAddress(), amount: TestUtils.MAX_FEE, unlockHeight: await that.daemon.getHeight() + 3, canSplit: true, relay: true}); - await testSendAndUpdateTxs(config); - }); - - if (testConfig.testRelays && testConfig.testNotifications && !testConfig.liteMode) - it("Can update a locked tx sent from/to different accounts as blocks are added to the chain", async function() { - let config = new MoneroTxConfig({accountIndex: 0, address: (await that.wallet.getSubaddress(1, 0)).getAddress(), amount: TestUtils.MAX_FEE, unlockHeight: await that.daemon.getHeight() + 3, canSplit: false, relay: true}); - await testSendAndUpdateTxs(config); - }); - - if (testConfig.testRelays && testConfig.testNotifications && !testConfig.liteMode) - it("Can update locked, split txs sent from/to different accounts as blocks are added to the chain", async function() { - let config = new MoneroTxConfig({accountIndex: 0, address: (await that.wallet.getSubaddress(1, 0)).getAddress(), amount: TestUtils.MAX_FEE, unlockHeight: await that.daemon.getHeight() + 3, relay: true}); - await testSendAndUpdateTxs(config); - }); - - /** - * Tests sending a tx with an unlock height then tracking and updating it as - * blocks are added to the chain. - * - * TODO: test wallet accounting throughout this; dedicated method? probably. - * - * Allows sending to and from the same account which is an edge case where - * incoming txs are occluded by their outgoing counterpart (issue #4500) - * and also where it is impossible to discern which incoming output is - * the tx amount and which is the change amount without wallet metadata. - * - * @param config - tx configuration to send and test - */ - async function testSendAndUpdateTxs(config) { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - if (!config) config = new MoneroTxConfig(); - - // this test starts and stops mining, so it's wrapped in order to stop mining if anything fails - let err; - try { - - // send transactions - let sentTxs = config.getCanSplit() !== false ? await that.wallet.createTxs(config) : [await that.wallet.createTx(config)]; - - // test sent transactions - for (let tx of sentTxs) { - await that._testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true}); - assert.equal(tx.isConfirmed(), false); - assert.equal(tx.inTxPool(), true); - } - - // track resulting outgoing and incoming txs as blocks are added to the chain - let updatedTxs; - - // start mining - try { await StartMining.startMining(); } - catch (e) { console.log("WARNING: could not start mining: " + e.message); } // not fatal - - // loop to update txs through confirmations - let numConfirmations = 0; - const numConfirmationsTotal = 2; // number of confirmations to test - while (numConfirmations < numConfirmationsTotal) { - - // wait for a block - let header = await that.daemon.getNextBlockHeader(); - console.log("*** Block " + header.getHeight() + " added to chain ***"); - - // give wallet time to catch up, otherwise incoming tx may not appear - await new Promise(function(resolve) { setTimeout(resolve, MoneroUtils.WALLET_REFRESH_RATE); }); // TODO: this lets block slip, okay? - - // get incoming/outgoing txs with sent hashes - let txQuery = new MoneroTxQuery(); - txQuery.setHashes(sentTxs.map(sentTx => sentTx.getHash())); // TODO: convenience methods wallet.getTxById(), getTxsById()? - let fetchedTxs = await that._getAndTestTxs(that.wallet, txQuery, true); - assert(fetchedTxs.length > 0); - - // test fetched txs - await testOutInPairs(that.wallet, fetchedTxs, config, false); - - // merge fetched txs into updated txs and original sent txs - for (let fetchedTx of fetchedTxs) { - - // merge with updated txs - if (updatedTxs === undefined) updatedTxs = fetchedTxs; - else { - for (let updatedTx of updatedTxs) { - if (fetchedTx.getHash() !== updatedTx.getHash()) continue; - if (!!fetchedTx.getOutgoingTransfer() !== !!updatedTx.getOutgoingTransfer()) continue; // skip if directions are different - updatedTx.merge(fetchedTx.copy()); - if (!updatedTx.getBlock() && fetchedTx.getBlock()) updatedTx.setBlock(fetchedTx.getBlock().copy().setTxs([updatedTx])); // copy block for testing - } - } - - // merge with original sent txs - for (let sentTx of sentTxs) { - if (fetchedTx.getHash() !== sentTx.getHash()) continue; - if (!!fetchedTx.getOutgoingTransfer() !== !!sentTx.getOutgoingTransfer()) continue; // skip if directions are different - sentTx.merge(fetchedTx.copy()); // TODO: it's mergeable but tests don't account for extra info from send (e.g. hex) so not tested; could specify in test context - } - } - - // test updated txs - testGetTxsStructure(updatedTxs, config); - await testOutInPairs(that.wallet, updatedTxs, config, false); - - // update confirmations in order to exit loop - numConfirmations = fetchedTxs[0].getNumConfirmations(); - } - } catch (e) { - err = e; - } - - // stop mining - try { await that.wallet.stopMining(); } - catch (e) { } - - // throw error if there was one - if (err) throw err; - } - - async function testOutInPairs(wallet, txs, config, isSendResponse) { - - // for each out tx - let txOut; - for (let tx of txs) { - await testUnlockTx(that.wallet, tx, config, isSendResponse); - if (!tx.getOutgoingTransfer()) continue; - let txOut = tx; - - // find incoming counterpart - let txIn; - for (let tx2 of txs) { - if (tx2.getIncomingTransfers() && tx.getHash() === tx2.getHash()) { - txIn = tx2; - break; - } - } - - // test out / in pair - // TODO monero-wallet-rpc: incoming txs occluded by their outgoing counterpart #4500 - if (!txIn) { - console.log("WARNING: outgoing tx " + txOut.getHash() + " missing incoming counterpart (issue #4500)"); - } else { - await testOutInPair(txOut, txIn); - } - } - } - - async function testOutInPair(txOut, txIn) { - assert.equal(txIn.isConfirmed(), txOut.isConfirmed()); - assert.equal(txOut.getOutgoingAmount().compare(txIn.getIncomingAmount()), 0); - } - - async function testUnlockTx(wallet, tx, config, isSendResponse) { - try { - await that._testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: isSendResponse}); - } catch (e) { - console.log(tx.toString()); - throw e; - } - } - - // ----------------------------- TEST RELAYS --------------------------- - - if (testConfig.testRelays) - it("Can send to an external address", async function() { - - // collect balances before - let balance1 = await that.wallet.getBalance(); - let unlockedBalance1 = await that.wallet.getUnlockedBalance(); - - // send funds to external address - let tx = await that.wallet.createTx({accountIndex: 0, address: await TestUtils.getExternalWalletAddress(), amount: TestUtils.MAX_FEE.multiply(new BigInteger(3)), relay: true}); - - // collect balances after - let balance2 = await that.wallet.getBalance(); - let unlockedBalance2 = await that.wallet.getUnlockedBalance(); - - // test balances - assert(unlockedBalance2.compare(unlockedBalance1) < 0); // unlocked balance should decrease - let expectedBalance = balance1.subtract(tx.getOutgoingAmount().subtract(tx.getFee())); - assert.equal(balance2, expectedBalance, "Balance after send was not balance before - net tx amount - fee (5 - 1 != 4 test)"); // TODO: incorrect BigInteger comparison? - }); - - if (testConfig.testRelays) - it("Can send from multiple subaddresses in a single transaction", async function() { - await testSendFromMultiple(); - }); - - if (testConfig.testRelays) - it("Can send from multiple subaddresses in split transactions", async function() { - await testSendFromMultiple(new MoneroTxConfig().setCanSplit(true)); - }); - - async function testSendFromMultiple(config) { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - if (!config) config = new MoneroTxConfig(); - - let NUM_SUBADDRESSES = 2; // number of subaddresses to send from - - // get first account with (NUM_SUBADDRESSES + 1) subaddresses with unlocked balances - let accounts = await that.wallet.getAccounts(true); - assert(accounts.length >= 2, "This test requires at least 2 accounts; run send-to-multiple tests"); - let srcAccount; - let unlockedSubaddresses = []; - let hasBalance = false; - for (let account of accounts) { - unlockedSubaddresses = []; - let numSubaddressBalances = 0; - for (let subaddress of account.getSubaddresses()) { - if (subaddress.getBalance().compare(TestUtils.MAX_FEE) > 0) numSubaddressBalances++; - if (subaddress.getUnlockedBalance().compare(TestUtils.MAX_FEE) > 0) unlockedSubaddresses.push(subaddress); - } - if (numSubaddressBalances >= NUM_SUBADDRESSES + 1) hasBalance = true; - if (unlockedSubaddresses.length >= NUM_SUBADDRESSES + 1) { - srcAccount = account; - break; - } - } - assert(hasBalance, "Wallet does not have account with " + (NUM_SUBADDRESSES + 1) + " subaddresses with balances; run send-to-multiple tests"); - assert(unlockedSubaddresses.length >= NUM_SUBADDRESSES + 1, "Wallet is waiting on unlocked funds"); - - // determine the indices of the first two subaddresses with unlocked balances - let fromSubaddressIndices = []; - for (let i = 0; i < NUM_SUBADDRESSES; i++) { - fromSubaddressIndices.push(unlockedSubaddresses[i].getIndex()); - } - - // determine the amount to send (slightly less than the sum to send from) - let sendAmount = new BigInteger(0); - for (let fromSubaddressIdx of fromSubaddressIndices) { - sendAmount = sendAmount.add(srcAccount.getSubaddresses()[fromSubaddressIdx].getUnlockedBalance()).subtract(TestUtils.MAX_FEE); - } - - // send from the first subaddresses with unlocked balances - let address = await that.wallet.getPrimaryAddress(); - config.setDestinations([new MoneroDestination(address, sendAmount)]); - config.setAccountIndex(srcAccount.getIndex()); - config.setSubaddressIndices(fromSubaddressIndices); - config.setRelay(true); - let configCopy = config.copy(); - let txs = []; - if (config.getCanSplit() !== false) { - for (let tx of await that.wallet.createTxs(config)) txs.push(tx); - } else { - txs.push(await that.wallet.createTx(config)); - } - if (config.getCanSplit() === false) assert.equal(txs.length, 1); // must have exactly one tx if no split - - // test that config is unchanged - assert(configCopy !== config); - assert.deepEqual(config, configCopy); - - // test that balances of intended subaddresses decreased - let accountsAfter = await that.wallet.getAccounts(true); - assert.equal(accountsAfter.length, accounts.length); - for (let i = 0; i < accounts.length; i++) { - assert.equal(accountsAfter[i].getSubaddresses().length, accounts[i].getSubaddresses().length); - for (let j = 0; j < accounts[i].getSubaddresses().length; j++) { - let subaddressBefore = accounts[i].getSubaddresses()[j]; - let subaddressAfter = accountsAfter[i].getSubaddresses()[j]; - if (i === srcAccount.getIndex() && fromSubaddressIndices.includes(j)) { - assert(subaddressAfter.getUnlockedBalance().compare(subaddressBefore.getUnlockedBalance()) < 0, "Subaddress [" + i + "," + j + "] unlocked balance should have decreased but started at " + subaddressBefore.getUnlockedBalance().toString() + " and ended at " + subaddressAfter.getUnlockedBalance().toString()); // TODO: Subaddress [0,1] unlocked balance should have decreased - } else { - assert(subaddressAfter.getUnlockedBalance().compare(subaddressBefore.getUnlockedBalance()) === 0, "Subaddress [" + i + "," + j + "] unlocked balance should not have changed"); - } - } - } - - // test each transaction - assert(txs.length > 0); - let outgoingSum = new BigInteger(0); - for (let tx of txs) { - await that._testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true}); - outgoingSum = outgoingSum.add(tx.getOutgoingAmount()); - if (tx.getOutgoingTransfer() !== undefined && tx.getOutgoingTransfer().getDestinations()) { - let destinationSum = new BigInteger(0); - for (let destination of tx.getOutgoingTransfer().getDestinations()) { - testDestination(destination); - assert.equal(destination.getAddress(), address); - destinationSum = destinationSum.add(destination.getAmount()); - } - assert(tx.getOutgoingAmount().compare(destinationSum) === 0); // assert that transfers sum up to tx amount - } - } - - // assert that tx amounts sum up the amount sent within a small margin - if (Math.abs(sendAmount.subtract(outgoingSum).toJSValue()) > SEND_MAX_DIFF) { // send amounts may be slightly different - throw new Error("Tx amounts are too different: " + sendAmount + " - " + outgoingSum + " = " + sendAmount.subtract(outgoingSum)); - } - } - - if (testConfig.testRelays) - it("Can send to an address in a single transaction.", async function() { - await testSendToSingle(new MoneroTxConfig().setCanSplit(false)); - }); - - // NOTE: this test will be invalid when payment ids are fully removed - if (testConfig.testRelays) - it("Can send to an address in a single transaction with a payment id.", async function() { - let integratedAddress = await that.wallet.getIntegratedAddress(); - let paymentId = integratedAddress.getPaymentId(); - try { - await testSendToSingle(new MoneroTxConfig().setCanSplit(false).setPaymentId(paymentId + paymentId + paymentId + paymentId)); // 64 character payment id - } catch (e) { - assert.equal(e.message, "Standalone payment IDs are obsolete. Use subaddresses or integrated addresses instead"); - } - }); - - if (testConfig.testRelays) - it("Can send to an address with split transactions", async function() { - await testSendToSingle(new MoneroTxConfig().setCanSplit(true)); - }); - - if (testConfig.testRelays) - it("Can create then relay a transaction to send to a single address", async function() { - await testSendToSingle(new MoneroTxConfig().setCanSplit(false)); - }); - - if (testConfig.testRelays) - it("Can create then relay split transactions to send to a single address", async function() { - await testSendToSingle(new MoneroTxConfig().setCanSplit(true)); - }); - - async function testSendToSingle(config) { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - if (!config) config = new MoneroTxConfig(); - - // find a non-primary subaddress to send from - let sufficientBalance = false; - let fromAccount = undefined; - let fromSubaddress = undefined; - let accounts = await that.wallet.getAccounts(true); - for (let account of accounts) { - let subaddresses = account.getSubaddresses(); - for (let i = 1; i < subaddresses.length; i++) { - if (subaddresses[i].getBalance().compare(TestUtils.MAX_FEE) > 0) sufficientBalance = true; - if (subaddresses[i].getUnlockedBalance().compare(TestUtils.MAX_FEE) > 0) { - fromAccount = account; - fromSubaddress = subaddresses[i]; - break; - } - } - if (fromAccount != undefined) break; - } - assert(sufficientBalance, "No non-primary subaddress found with sufficient balance"); - assert(fromSubaddress !== undefined, "Wallet is waiting on unlocked funds"); - - // get balance before send - let balanceBefore = fromSubaddress.getBalance(); - let unlockedBalanceBefore = fromSubaddress.getUnlockedBalance(); - - // init tx config - let sendAmount = unlockedBalanceBefore.subtract(TestUtils.MAX_FEE).divide(new BigInteger(SEND_DIVISOR)); - let address = await that.wallet.getPrimaryAddress(); - let txs = [] - config.setDestinations([new MoneroDestination(address, sendAmount)]); - config.setAccountIndex(fromAccount.getIndex()); - config.setSubaddressIndices([fromSubaddress.getIndex()]); - config.setRelay(true); - let reqCopy = config.copy(); - - // send to self - if (config.getCanSplit() !== false) { - for (let tx of await that.wallet.createTxs(config)) txs.push(tx); - } else { - txs.push(await that.wallet.createTx(config)); - } - if (config.getCanSplit() === false) assert.equal(txs.length, 1); // must have exactly one tx if no split - - // test that config is unchanged - assert(reqCopy !== config); - assert.deepEqual(config, reqCopy); - - // test common tx set among txs - testCommonTxSets(txs, false, false, false); - - // handle non-relayed transaction - if (config.getRelay() !== true) { - - // test transactions - for (let tx of txs) { - await that._testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true}); - } - - // txs are not in the pool - for (let txCreated of txs) { - for (let txPool of await that.daemon.getTxPool()) { - assert(txPool.getHash() !== txCreated.getHash(), "Created tx should not be in the pool"); - } - } - - // relay txs - let txHashes; - if (config.getCanSplit() !== true) txHashes = [await that.wallet.relayTx(txs[0])]; // test relayTx() with single transaction - else { - let txMetadatas = []; - for (let tx of txs) txMetadatas.push(tx.getMetadata()); - txHashes = await that.wallet.relayTxs(txMetadatas); // test relayTxs() with potentially multiple transactions - } - for (let txHash of txHashes) assert(typeof txHash === "string" && txHash.length === 64); - - // fetch txs for testing - txs = await that.wallet.getTxs({hashes: txHashes}); - } - - // test that balance and unlocked balance decreased - // TODO: test that other balances did not decrease - let subaddress = await that.wallet.getSubaddress(fromAccount.getIndex(), fromSubaddress.getIndex()); - assert(subaddress.getBalance().compare(balanceBefore) < 0); - assert(subaddress.getUnlockedBalance().compare(unlockedBalanceBefore) < 0); - - // query locked txs - let lockedTxs = await that._getAndTestTxs(that.wallet, new MoneroTxQuery().setIsLocked(true), undefined, true); - for (let lockedTx of lockedTxs) assert.equal(lockedTx.isLocked(), true); - - // test transactions - assert(txs.length > 0); - for (let tx of txs) { - await that._testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: config.getRelay()}); - assert.equal(tx.getOutgoingTransfer().getAccountIndex(), fromAccount.getIndex()); - assert.equal(tx.getOutgoingTransfer().getSubaddressIndices().length, 1); - assert.equal(tx.getOutgoingTransfer().getSubaddressIndices()[0], fromSubaddress.getIndex()); - assert(sendAmount.compare(tx.getOutgoingAmount()) === 0); - if (config.getPaymentId()) assert.equal(config.getPaymentId(), tx.getPaymentId()); - - // test outgoing destinations - if (tx.getOutgoingTransfer() && tx.getOutgoingTransfer().getDestinations()) { - assert.equal(tx.getOutgoingTransfer().getDestinations().length, 1); - for (let destination of tx.getOutgoingTransfer().getDestinations()) { - testDestination(destination); - assert.equal(destination.getAddress(), address); - assert(sendAmount.compare(destination.getAmount()) === 0); - } - } - - // tx is among locked txs - let found = false; - for (let lockedTx of lockedTxs) { - if (lockedTx.getHash() === tx.getHash()) { - found = true; - break; - } - } - assert(found, "Created txs should be among locked txs"); - } - - // if tx was relayed, all wallets will need to wait for tx to confirm in order to reliably sync - if (config.getRelay()) { - await TestUtils.TX_POOL_WALLET_TRACKER.reset(); // TODO: resetExcept(that.wallet), or does this test wallet also need to be waited on? - } - } - - if (testConfig.testRelays) - it("Can send to multiple addresses in a single transaction", async function() { - await testSendToMultiple(5, 3, false); - }); - - if (testConfig.testRelays) - it("Can send to multiple addresses in split transactions.", async function() { - await testSendToMultiple(3, 5, true); - }); - - if (testConfig.testRelays) - it("Can send to multiple addresses in split transactions using a JavaScript object for configuration", async function() { - await testSendToMultiple(1, 15, true, undefined, true); - }); - - if (testConfig.testRelays) - it("Can send dust to multiple addresses in split transactions", async function() { - let dustAmt = (await that.daemon.getFeeEstimate()).divide(new BigInteger(2)); - await testSendToMultiple(5, 3, true, dustAmt); - }); - - /** - * Sends funds from the first unlocked account to multiple accounts and subaddresses. - * - * @param numAccounts is the number of accounts to receive funds - * @param numSubaddressesPerAccount is the number of subaddresses per account to receive funds - * @param canSplit specifies if the operation can be split into multiple transactions - * @param sendAmountPerSubaddress is the amount to send to each subaddress (optional, computed if not given) - * @param useJsConfig specifies if the api should be invoked with a JS object instead of a MoneroTxConfig - */ - async function testSendToMultiple(numAccounts, numSubaddressesPerAccount, canSplit, sendAmountPerSubaddress, useJsConfig) { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - - // compute the minimum account unlocked balance needed in order to fulfill the request - let minAccountAmount; - let totalSubaddresses = numAccounts * numSubaddressesPerAccount; - if (sendAmountPerSubaddress !== undefined) minAccountAmount = new BigInteger(totalSubaddresses).multiply(sendAmountPerSubaddress.add(TestUtils.MAX_FEE)); // min account amount must cover the total amount being sent plus the tx fee = numAddresses * (amtPerSubaddress + fee) - else minAccountAmount = TestUtils.MAX_FEE.multiply(new BigInteger(totalSubaddresses)).multiply(new BigInteger(SEND_DIVISOR)).add(TestUtils.MAX_FEE); // account balance must be more than fee * numAddresses * divisor + fee so each destination amount is at least a fee's worth (so dust is not sent) - - // send funds from first account with sufficient unlocked funds - let srcAccount; - let hasBalance = false; - for (let account of await that.wallet.getAccounts()) { - if (account.getBalance().compare(minAccountAmount) > 0) hasBalance = true; - if (account.getUnlockedBalance().compare(minAccountAmount) > 0) { - srcAccount = account; - break; - } - } - assert(hasBalance, "Wallet does not have enough balance; load '" + TestUtils.WALLET_NAME + "' with XMR in order to test sending"); - assert(srcAccount, "Wallet is waiting on unlocked funds"); - let balance = srcAccount.getBalance(); - let unlockedBalance = srcAccount.getUnlockedBalance(); - - // get amount to send total and per subaddress - let sendAmount; - if (sendAmountPerSubaddress === undefined) { - sendAmount = unlockedBalance.subtract(TestUtils.MAX_FEE).divide(new BigInteger(SEND_DIVISOR)); - sendAmountPerSubaddress = sendAmount.divide(new BigInteger(totalSubaddresses)); - } else { - sendAmount = sendAmountPerSubaddress.multiply(new BigInteger(totalSubaddresses)); - } - - // create minimum number of accounts - let accounts = await that.wallet.getAccounts(); - for (let i = 0; i < numAccounts - accounts.length; i++) { - await that.wallet.createAccount(); - } - - // create minimum number of subaddresses per account and collect destination addresses - let destinationAddresses = []; - for (let i = 0; i < numAccounts; i++) { - let subaddresses = await that.wallet.getSubaddresses(i); - for (let j = 0; j < numSubaddressesPerAccount - subaddresses.length; j++) await that.wallet.createSubaddress(i); - subaddresses = await that.wallet.getSubaddresses(i); - assert(subaddresses.length >= numSubaddressesPerAccount); - for (let j = 0; j < numSubaddressesPerAccount; j++) destinationAddresses.push(subaddresses[j].getAddress()); - } - - // build tx config using MoneroTxConfig - let config = new MoneroTxConfig(); - config.setAccountIndex(srcAccount.getIndex()); - config.setDestinations([]); - config.setCanSplit(canSplit); - config.setPriority(MoneroTxPriority.NORMAL); - config.setRelay(true); - for (let i = 0; i < destinationAddresses.length; i++) { - config.getDestinations().push(new MoneroDestination(destinationAddresses[i], sendAmountPerSubaddress)); - } - let configCopy = config.copy(); - - // build tx config with JS object - let jsConfig; - if (useJsConfig) { - jsConfig = {}; - jsConfig.ringSize = MoneroUtils.RING_SIZE; - jsConfig.accountIndex = srcAccount.getIndex(); - jsConfig.relay = true; - jsConfig.destinations = []; - for (let i = 0; i < destinationAddresses.length; i++) { - jsConfig.destinations.push({address: destinationAddresses[i], amount: sendAmountPerSubaddress}); - } - } - - // send tx(s) with config xor js object - let txs = []; - if (canSplit) { - for (let tx of await that.wallet.createTxs(useJsConfig ? jsConfig : config)) txs.push(tx); - } else { - txs.push(await that.wallet.createTx(useJsConfig ? jsConfig : config)); - } - - // test that config is unchanged - assert(configCopy !== config); - assert.deepEqual(config, configCopy); - - // test that wallet balance decreased - let account = await that.wallet.getAccount(srcAccount.getIndex()); - assert(account.getBalance().compare(balance) < 0); - assert(account.getUnlockedBalance().compare(unlockedBalance) < 0); - - // test each transaction - assert(txs.length > 0); - let outgoingSum = new BigInteger(0); - for (let tx of txs) { - await that._testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true}); - outgoingSum = outgoingSum.add(tx.getOutgoingAmount()); - if (tx.getOutgoingTransfer() !== undefined && tx.getOutgoingTransfer().getDestinations()) { - let destinationSum = new BigInteger(0); - for (let destination of tx.getOutgoingTransfer().getDestinations()) { - testDestination(destination); - assert(destinationAddresses.includes(destination.getAddress())); - destinationSum = destinationSum.add(destination.getAmount()); - } - assert(tx.getOutgoingAmount().compare(destinationSum) === 0); // assert that transfers sum up to tx amount - } - } - - // assert that outgoing amounts sum up to the amount sent within a small margin - if (Math.abs(sendAmount.subtract(outgoingSum).toJSValue()) > SEND_MAX_DIFF) { // send amounts may be slightly different - throw new Error("Actual send amount is too different from requested send amount: " + sendAmount + " - " + outgoingSum + " = " + sendAmount.subtract(outgoingSum)); - } - } - - it("Supports view-only and offline wallets to create, sign, and submit transactions", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - - // collect info from main test wallet - let primaryAddress = await that.wallet.getPrimaryAddress(); - let privateViewKey = await that.wallet.getPrivateViewKey(); - let privateSpendKey = await that.wallet.getPrivateSpendKey(); - await that.wallet.close(); - - // create, sign, and submit transactions using view-only and offline wallets - let viewOnlyWallet; - let offlineWallet; - let err; - try { - - // create and sync view-only wallet - viewOnlyWallet = await that.createWallet({primaryAddress: primaryAddress, privateViewKey: privateViewKey, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}); - assert.equal(await viewOnlyWallet.getPrimaryAddress(), primaryAddress); - assert.equal(await viewOnlyWallet.getPrivateViewKey(), privateViewKey); - assert.equal(await viewOnlyWallet.getPrivateSpendKey(), undefined); - assert.equal(await viewOnlyWallet.getMnemonic(), undefined); - assert.equal(await viewOnlyWallet.getMnemonicLanguage(), undefined); - assert(await viewOnlyWallet.isViewOnly()); - assert(await viewOnlyWallet.isConnected(), "Wallet created from keys is not connected to authenticated daemon"); // TODO - assert.equal(await viewOnlyWallet.getMnemonic(), undefined); - let viewOnlyPath = await viewOnlyWallet.getPath(); - await viewOnlyWallet.sync(); - assert((await viewOnlyWallet.getTxs()).length > 0); - - // export outputs from view-only wallet - let outputsHex = await viewOnlyWallet.getOutputsHex(); - - // create offline wallet - await viewOnlyWallet.close(true); // only one wallet open at a time to accommodate testing wallet rpc - offlineWallet = await that.createWallet({primaryAddress: primaryAddress, privateViewKey: privateViewKey, privateSpendKey: privateSpendKey, serverUri: "", restoreHeight: 0}); - assert(!await offlineWallet.isConnected()); - assert(!await offlineWallet.isViewOnly()); - if (!(offlineWallet instanceof MoneroWalletRpc)) assert.equal(await offlineWallet.getMnemonic(), TestUtils.MNEMONIC); // TODO monero-core: cannot get mnemonic from offline wallet rpc - let offlineWalletPath = await offlineWallet.getPath(); - assert.equal((await offlineWallet.getTxs()).length, 0); - - // import outputs to offline wallet - await offlineWallet.importOutputsHex(outputsHex); - - // export key images from offline wallet - let keyImages = await offlineWallet.getKeyImages(); - - // import key images to view-only wallet - await offlineWallet.close(true); - viewOnlyWallet = await that.openWallet({path: viewOnlyPath}); - await viewOnlyWallet.importKeyImages(keyImages); - - // create unsigned tx using view-only wallet - let unsignedTx = await viewOnlyWallet.createTx({accountIndex: 0, address: primaryAddress, amount: TestUtils.MAX_FEE.multiply(BigInteger.parse("3"))}); - assert.equal(typeof unsignedTx.getTxSet().getUnsignedTxHex(), "string"); - assert(unsignedTx.getTxSet().getUnsignedTxHex()); - - // sign tx using offline wallet - await viewOnlyWallet.close(true); - offlineWallet = await that.openWallet({path: offlineWalletPath, serverUri: ""}); - let signedTxHex = await offlineWallet.signTxs(unsignedTx.getTxSet().getUnsignedTxHex()); - assert(signedTxHex.length > 0); - - // parse or "describe" unsigned tx set - let parsedTxSet = await offlineWallet.parseTxSet(unsignedTx.getTxSet()); - testParsedTxSet(parsedTxSet); - - // submit signed tx using view-only wallet - if (testConfig.testRelays) { - await offlineWallet.close(); - viewOnlyWallet = await that.openWallet({path: viewOnlyPath}); - let txHashes = await viewOnlyWallet.submitTxs(signedTxHex); - assert.equal(txHashes.length, 1); - assert.equal(txHashes[0].length, 64); - } - } catch (e) { - err = e; - } - - // finally - try { await viewOnlyWallet.close(); } catch (e) { } - try { await offlineWallet.close(); } catch (e) { } - that.wallet = await that.getTestWallet(); // open main test wallet for other tests - if (err) throw err; - }); - - if (testConfig.testRelays) - it("Can sweep individual outputs identified by their key images", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - - // test config - let numOutputs = 3; - - // get outputs to sweep (not spent, unlocked, and amount >= fee) - let spendableUnlockedOutputs = await that.wallet.getOutputs(new MoneroOutputQuery().setIsSpent(false).setIsLocked(false)); - let outputsToSweep = []; - for (let i = 0; i < spendableUnlockedOutputs.length && outputsToSweep.length < numOutputs; i++) { - if (spendableUnlockedOutputs[i].getAmount().compare(TestUtils.MAX_FEE) > 0) outputsToSweep.push(spendableUnlockedOutputs[i]); // output cannot be swept if amount does not cover fee - } - assert(outputsToSweep.length >= numOutputs, "Wallet does not have enough sweepable outputs; run send tests"); - - // sweep each output by key image - for (let output of outputsToSweep) { - testOutputWallet(output); - assert.equal(output.isSpent(), false); - assert.equal(output.isLocked(), false); - if (output.getAmount().compare(TestUtils.MAX_FEE) <= 0) continue; - - // sweep output to address - let address = await that.wallet.getAddress(output.getAccountIndex(), output.getSubaddressIndex()); - let config = new MoneroTxConfig({address: address, keyImage: output.getKeyImage().getHex(), relay: true}); - let tx = await that.wallet.sweepOutput(config); - - // test resulting tx - config.setCanSplit(false); - await that._testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true, isSweepResponse: true, isSweepOutputResponse: true}); - } - - // get outputs after sweeping - let afterOutputs = await that.wallet.getOutputs(); - - // swept output are now spent - for (let afterOutput of afterOutputs) { - for (let output of outputsToSweep) { - if (output.getKeyImage().getHex() === afterOutput.getKeyImage().getHex()) { - assert(afterOutput.isSpent(), "Output should be spent"); - } - } - } - }); - - if (testConfig.testRelays) - it("Can sweep dust without relaying", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - - // generate non-relayed transactions to sweep dust - let txs; - try { - txs = await that.wallet.sweepDust(true); - } catch (e) { - assert.equal(e.message, "No dust to sweep"); - return; - } - - // test txs - let ctx = {config: new MoneroTxConfig(), isSendResponse: true, isSweepResponse: true}; - for (let tx of txs) { - await that._testTxWallet(tx, ctx); - } - - // relay txs - let metadatas = []; - for (let tx of txs) metadatas.push(tx.getMetadata()); - let txHashes = await that.wallet.relayTxs(metadatas); - assert.equal(txs.length, txHashes.length); - for (let txHash of txHashes) assert.equal(txHash.length, 64); - - // fetch and test txs - txs = wallet.getTxs(new MoneroTxQuery().setHashes(txHashes)); - ctx.config.setRelay(true); - for (let tx of txs) { - await that._testTxWallet(tx, ctx); - } - }); - - if (testConfig.testRelays) - it("Can sweep dust", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - - // sweep dust which will throw exception if no dust to sweep (dust does not exist after rct) - let txs; - try { - txs = (await that.wallet.sweepDust()).getTxs(); - } catch (e) { - assert.equal(e.message, "No dust to sweep"); - return; - } - - // if dust swept, test txs - let ctx = {wallet: that.wallet, isSendResponse: true, isSweepResponse: true}; - assert(txs.length > 0); - for (let tx of txs) { - await that._testTxWallet(tx, ctx); - } - }); - - it("Supports multisig wallets", async function() { - let err; - try { - - // test n/n - await that._testMultisig(2, 2, false); - //_testMultisig(3, 3, false); - //_testMultisig(4, 4, false); - - // test (n-1)/n - await that._testMultisig(2, 3, false); - //_testMultisig(3, 4, false); - //_testMultisig(5, 6, false); - - // test m/n - await that._testMultisig(2, 4, testConfig.testRelays && !testConfig.liteMode); - //_testMultisig(3, 5, false); - //_testMultisig(3, 7, false); - } catch (e) { - err = e; - } - - // stop mining at end of test - try { await that.daemon.stopMining(); } - catch (e) { } - - // throw error if there was one - if (err) throw err; - }); - - // ---------------------------- TEST RESETS ----------------------------- - - if (testConfig.testResets) - it("Can sweep subaddresses", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - - const NUM_SUBADDRESSES_TO_SWEEP = 2; - - // collect subaddresses with balance and unlocked balance - let subaddresses = []; - let subaddressesBalance = []; - let subaddressesUnlocked = []; - for (let account of await that.wallet.getAccounts(true)) { - if (account.getIndex() === 0) continue; // skip default account - for (let subaddress of account.getSubaddresses()) { - subaddresses.push(subaddress); - if (subaddress.getBalance().compare(TestUtils.MAX_FEE) > 0) subaddressesBalance.push(subaddress); - if (subaddress.getUnlockedBalance().compare(TestUtils.MAX_FEE) > 0) subaddressesUnlocked.push(subaddress); - } - } - - // test requires at least one more subaddresses than the number being swept to verify it does not change - assert(subaddressesBalance.length >= NUM_SUBADDRESSES_TO_SWEEP + 1, "Test requires balance in at least " + (NUM_SUBADDRESSES_TO_SWEEP + 1) + " subaddresses from non-default acccount; run send-to-multiple tests"); - assert(subaddressesUnlocked.length >= NUM_SUBADDRESSES_TO_SWEEP + 1, "Wallet is waiting on unlocked funds"); - - // sweep from first unlocked subaddresses - for (let i = 0; i < NUM_SUBADDRESSES_TO_SWEEP; i++) { - - // sweep unlocked account - let unlockedSubaddress = subaddressesUnlocked[i]; - let config = new MoneroTxConfig({ - address: await that.wallet.getPrimaryAddress(), - accountIndex: unlockedSubaddress.getAccountIndex(), - subaddressIndex: unlockedSubaddress.getIndex(), - relay: true - }); - let txs = await that.wallet.sweepUnlocked(config); - - // test transactions - assert(txs.length > 0); - for (let tx of txs) { - assert(GenUtils.arrayContains(tx.getTxSet().getTxs(), tx)); - await that._testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true, isSweepResponse: true}); - } - - // assert unlocked balance is less than max fee - let subaddress = await that.wallet.getSubaddress(unlockedSubaddress.getAccountIndex(), unlockedSubaddress.getIndex()); - assert(subaddress.getUnlockedBalance().compare(TestUtils.MAX_FEE) < 0); - } - - // test subaddresses after sweeping - let subaddressesAfter = []; - for (let account of await that.wallet.getAccounts(true)) { - if (account.getIndex() === 0) continue; // skip default account - for (let subaddress of account.getSubaddresses()) { - subaddressesAfter.push(subaddress); - } - } - assert.equal(subaddressesAfter.length, subaddresses.length); - for (let i = 0; i < subaddresses.length; i++) { - let subaddressBefore = subaddresses[i]; - let subaddressAfter = subaddressesAfter[i]; - - // determine if subaddress was swept - let swept = false; - for (let j = 0; j < NUM_SUBADDRESSES_TO_SWEEP; j++) { - if (subaddressesUnlocked[j].getAccountIndex() === subaddressBefore.getAccountIndex() && subaddressesUnlocked[j].getIndex() === subaddressBefore.getIndex()) { - swept = true; - break; - } - } - - // assert unlocked balance is less than max fee if swept, unchanged otherwise - if (swept) { - assert(subaddressAfter.getUnlockedBalance().compare(TestUtils.MAX_FEE) < 0); - } else { - assert(subaddressBefore.getUnlockedBalance().compare(subaddressAfter.getUnlockedBalance()) === 0); - } - } - }); - - if (testConfig.testResets) - it("Can sweep accounts", async function() { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - const NUM_ACCOUNTS_TO_SWEEP = 1; - - // collect accounts with sufficient balance and unlocked balance to cover the fee - let accounts = await that.wallet.getAccounts(true); - let accountsBalance = []; - let accountsUnlocked = []; - for (let account of accounts) { - if (account.getIndex() === 0) continue; // skip default account - if (account.getBalance().compare(TestUtils.MAX_FEE) > 0) accountsBalance.push(account); - if (account.getUnlockedBalance().compare(TestUtils.MAX_FEE) > 0) accountsUnlocked.push(account); - } - - // test requires at least one more accounts than the number being swept to verify it does not change - assert(accountsBalance.length >= NUM_ACCOUNTS_TO_SWEEP + 1, "Test requires balance greater than the fee in at least " + (NUM_ACCOUNTS_TO_SWEEP + 1) + " non-default accounts; run send-to-multiple tests"); - assert(accountsUnlocked.length >= NUM_ACCOUNTS_TO_SWEEP + 1, "Wallet is waiting on unlocked funds"); - - // sweep from first unlocked accounts - for (let i = 0; i < NUM_ACCOUNTS_TO_SWEEP; i++) { - - // sweep unlocked account - let unlockedAccount = accountsUnlocked[i]; - let config = new MoneroTxConfig().setAddress(await that.wallet.getPrimaryAddress()).setAccountIndex(unlockedAccount.getIndex()).setRelay(true); - let txs = await that.wallet.sweepUnlocked(config); - - // test transactions - assert(txs.length > 0); - for (let tx of txs) { - await that._testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true, isSweepResponse: true}); - } - - // assert unlocked account balance less than max fee - let account = await that.wallet.getAccount(unlockedAccount.getIndex()); - assert(account.getUnlockedBalance().compare(TestUtils.MAX_FEE) < 0); - } - - // test accounts after sweeping - let accountsAfter = await that.wallet.getAccounts(true); - assert.equal(accountsAfter.length, accounts.length); - for (let i = 0; i < accounts.length; i++) { - let accountBefore = accounts[i]; - let accountAfter = accountsAfter[i]; - - // determine if account was swept - let swept = false; - for (let j = 0; j < NUM_ACCOUNTS_TO_SWEEP; j++) { - if (accountsUnlocked[j].getIndex() === accountBefore.getIndex()) { - swept = true; - break; - } - } - - // assert unlocked balance is less than max fee if swept, unchanged otherwise - if (swept) { - assert(accountAfter.getUnlockedBalance().compare(TestUtils.MAX_FEE) < 0); - } else { - assert.equal(accountBefore.getUnlockedBalance().compare(accountAfter.getUnlockedBalance()), 0); - } - } - }); - - if (testConfig.testResets) - it("Can sweep the whole wallet by accounts", async function() { - assert(false, "Are you sure you want to sweep the whole wallet?"); - await _testSweepWallet(); - }); - - if (testConfig.testResets) - it("Can sweep the whole wallet by subaddresses", async function() { - assert(false, "Are you sure you want to sweep the whole wallet?"); - await _testSweepWallet(true); - }); - - async function _testSweepWallet(sweepEachSubaddress) { - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - - // verify 2 subaddresses with enough unlocked balance to cover the fee - let subaddressesBalance = []; - let subaddressesUnlocked = []; - for (let account of await that.wallet.getAccounts(true)) { - for (let subaddress of account.getSubaddresses()) { - if (subaddress.getBalance().compare(TestUtils.MAX_FEE) > 0) subaddressesBalance.push(subaddress); - if (subaddress.getUnlockedBalance().compare(TestUtils.MAX_FEE) > 0) subaddressesUnlocked.push(subaddress); - } - } - assert(subaddressesBalance.length >= 2, "Test requires multiple accounts with a balance greater than the fee; run send to multiple first"); - assert(subaddressesUnlocked.length >= 2, "Wallet is waiting on unlocked funds"); - - // sweep - let destination = await that.wallet.getPrimaryAddress(); - let config = new MoneroTxConfig().setAddress(destination).setSweepEachSubaddress(sweepEachSubaddress).setRelay(true); - let copy = config.copy(); - let txs = await that.wallet.sweepUnlocked(config); - assert.deepEqual(config, copy); // config is unchanged - for (let tx of txs) { - assert(GenUtils.arrayContains(tx.getTxSet().getTxs(), tx)); - assert.equal(tx.getTxSet().getMultisigTxHex(), undefined); - assert.equal(tx.getTxSet().getSignedTxHex(), undefined); - assert.equal(tx.getTxSet().getUnsignedTxHex(), undefined); - } - assert(txs.length > 0); - for (let tx of txs) { - config = new MoneroTxConfig({ - address: destination, - accountIndex: tx.getOutgoingTransfer().getAccountIndex(), - sweepEachSubaddress: sweepEachSubaddress, - relay: true - }); - await that._testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true, isSweepResponse: true}); - } - - // all unspent, unlocked outputs must be less than fee - let spendableOutputs = await that.wallet.getOutputs(new MoneroOutputQuery().setIsSpent(false).setIsLocked(false)); - for (let spendableOutput of spendableOutputs) { - assert(spendableOutput.getAmount().compare(TestUtils.MAX_FEE) < 0, "Unspent output should have been swept\n" + spendableOutput.toString()); - } - - // all subaddress unlocked balances must be less than fee - subaddressesBalance = []; - subaddressesUnlocked = []; - for (let account of await that.wallet.getAccounts(true)) { - for (let subaddress of account.getSubaddresses()) { - assert(subaddress.getUnlockedBalance().compare(TestUtils.MAX_FEE) < 0, "No subaddress should have more unlocked than the fee"); - } - } - } - - // disabled so tests don't delete local cache - if (testConfig.testResets) - it("Can rescan the blockchain", async function() { - assert(false, "Are you sure you want to discard local wallet data and rescan the blockchain?"); - await that.wallet.rescanBlockchain(); - for (let tx of await that.wallet.getTxs()) { - await that._testTxWallet(tx); - } - }); - }); - } - - // -------------------------------- PRIVATE --------------------------------- - - async getSubaddressesWithBalance() { - let subaddresses = []; - for (let account of await this.wallet.getAccounts(true)) { - for (let subaddress of account.getSubaddresses()) { - if (subaddress.getBalance().toJSValue() > 0) subaddresses.push(subaddress); - } - } - return subaddresses; - } - - async getSubaddressesWithUnlockedBalance() { - let subaddresses = []; - for (let account of await this.wallet.getAccounts(true)) { - for (let subaddress of account.getSubaddresses()) { - if (subaddress.getUnlockedBalance().toJSValue() > 0) subaddresses.push(subaddress); - } - } - return subaddresses; - } - - async _testGetSubaddressAddressOutOfRange() { - let accounts = await this.wallet.getAccounts(true); - let accountIdx = accounts.length - 1; - let subaddressIdx = accounts[accountIdx].getSubaddresses().length; - let address = await this.wallet.getAddress(accountIdx, subaddressIdx); - assert.notEqual(address, undefined); // subclass my override with custom behavior (e.g. jni returns subaddress but wallet rpc does not) - assert(address.length > 0); - } - - /** - * Fetches and tests transactions according to the given query. - * - * TODO: convert query to query object and ensure each tx passes filter, same with getAndTestTransfer, getAndTestOutputs - */ - async _getAndTestTxs(wallet, query, isExpected) { - let copy; - if (query !== undefined) { - if (query instanceof MoneroTxQuery) copy = query.copy(); - else copy = Object.assign({}, query); - } - let txs = await wallet.getTxs(query); - assert(Array.isArray(txs)); - if (isExpected === false) assert.equal(txs.length, 0); - if (isExpected === true) assert(txs.length > 0, "Transactions were expected but not found; run send tests?"); - for (let tx of txs) await this._testTxWallet(tx, Object.assign({wallet: wallet}, query)); - testGetTxsStructure(txs, query); - if (query !== undefined) { - if (query instanceof MoneroTxQuery) assert.deepEqual(query.toJson(), copy.toJson()); - else assert.deepEqual(query, copy); - } - return txs; - } - - /** - * Fetches and tests transfers according to the given query. - */ - async _getAndTestTransfers(wallet, query, isExpected) { - let copy; - if (query !== undefined) { - if (query instanceof MoneroTransferQuery) copy = query.copy(); - else copy = Object.assign({}, query); - } - let transfers = await wallet.getTransfers(query); - assert(Array.isArray(transfers)); - if (isExpected === false) assert.equal(transfers.length, 0); - if (isExpected === true) assert(transfers.length > 0, "Transfers were expected but not found; run send tests?"); - for (let transfer of transfers) await this._testTxWallet(transfer.getTx(), Object.assign({wallet: wallet}, query)); - if (query !== undefined) { - if (query instanceof MoneroTransferQuery) assert.deepEqual(query.toJson(), copy.toJson()); - else assert.deepEqual(query, copy); - } - return transfers; - } - - /** - * Fetches and tests outputs according to the given query. - */ - async _getAndTestOutputs(wallet, query, isExpected) { - let copy; - if (query !== undefined) { - if (query instanceof MoneroOutputQuery) copy = query.copy(); - else copy = Object.assign({}, query); - } - let outputs = await wallet.getOutputs(query); - assert(Array.isArray(outputs)); - if (isExpected === false) assert.equal(outputs.length, 0); - if (isExpected === true) assert(outputs.length > 0, "Outputs were expected but not found; run send tests?"); - for (let output of outputs) testOutputWallet(output); - if (query !== undefined) { - if (query instanceof MoneroOutputQuery) assert.deepEqual(query.toJson(), copy.toJson()); - else assert.deepEqual(query, copy); - } - return outputs; - } - - /** - * Tests a wallet transaction with a test configuration. - * - * @param tx is the wallet transaction to test - * @param ctx specifies test configuration - * ctx.wallet is used to cross reference tx info if available - * ctx.config specifies the tx's originating send configuration - * ctx.isSendResponse indicates if the tx is built from a send response, which contains additional fields (e.g. key) - * ctx.hasDestinations specifies if the tx has an outgoing transfer with destinations, undefined if doesn't matter - * ctx.includeOutputs specifies if outputs were fetched and should therefore be expected with incoming transfers - */ - async _testTxWallet(tx, ctx) { - - // validate / sanitize inputs - ctx = Object.assign({}, ctx); - delete ctx.wallet; // TODO: re-enable - if (!(tx instanceof MoneroTxWallet)) { - console.log("Tx is not a MoneroTxWallet!"); - console.log(tx); - } - assert(tx instanceof MoneroTxWallet); - if (ctx.wallet) assert(ctx.wallet instanceof MoneroWallet); - assert(ctx.hasDestinations == undefined || typeof ctx.hasDestinations === "boolean"); - if (ctx.isSendResponse === undefined || ctx.config === undefined) { - assert.equal(ctx.isSendResponse, undefined, "if either config or isSendResponse is defined, they must both be defined"); - assert.equal(ctx.config, undefined, "if either config or isSendResponse is defined, they must both be defined"); - } - - // test common field types - testTxWalletTypes(tx, ctx); - - // test confirmed - if (tx.isConfirmed()) { - assert(tx.getBlock()); - assert(tx.getBlock().getTxs().includes(tx)); - assert(tx.getBlock().getHeight() > 0); - assert(tx.getBlock().getTimestamp() > 0); - assert.equal(tx.isRelayed(), true); - assert.equal(tx.isFailed(), false); - assert.equal(tx.inTxPool(), false); - assert.equal(tx.getRelay(), true); - assert.equal(tx.isDoubleSpendSeen(), false); - assert(tx.getNumConfirmations() > 0); - } else { - assert.equal(tx.getBlock(), undefined); - assert.equal(tx.getNumConfirmations(), 0); - } - - // test in tx pool - if (tx.inTxPool()) { - assert.equal(tx.isConfirmed(), false); - assert.equal(tx.getRelay(), true); - assert.equal(tx.isRelayed(), true); - assert.equal(tx.isDoubleSpendSeen(), false); // TODO: test double spend attempt - assert.equal(tx.isLocked(), true); - - // these should be initialized unless a response from sending - if (!ctx.isSendResponse) { - //assert(tx.getReceivedTimestamp() > 0); // TODO: re-enable when received timestamp returned in wallet rpc - } - } else { - assert.equal(tx.getLastRelayedTimestamp(), undefined); - } - - // test miner tx - if (tx.isMinerTx()) { - assert.equal(tx.getFee().compare(new BigInteger(0)), 0); - assert(tx.getIncomingTransfers().length > 0); - } - - // test failed // TODO: what else to test associated with failed - if (tx.isFailed()) { - assert(tx.getOutgoingTransfer() instanceof MoneroTransfer); - //assert(tx.getReceivedTimestamp() > 0); // TODO: re-enable when received timestamp returned in wallet rpc - } else { - if (tx.isRelayed()) assert.equal(tx.isDoubleSpendSeen(), false); - else { - assert.equal(tx.isRelayed(), false); - assert.notEqual(tx.getRelay(), true); - assert.equal(tx.isDoubleSpendSeen(), undefined); - } - } - assert.equal(tx.getLastFailedHeight(), undefined); - assert.equal(tx.getLastFailedHash(), undefined); - - // received time only for tx pool or failed txs - if (tx.getReceivedTimestamp() !== undefined) { - assert(tx.inTxPool() || tx.isFailed()); - } - - // test relayed tx - if (tx.isRelayed()) assert.equal(tx.getRelay(), true); - if (tx.getRelay() !== true) assert.equal(tx.isRelayed(), false); - - // test outgoing transfer per configuration - if (ctx.isOutgoing === false) assert(tx.getOutgoingTransfer() === undefined); - if (ctx.hasDestinations) assert(tx.getOutgoingTransfer() && tx.getOutgoingTransfer().getDestinations().length > 0); // TODO: this was typo with getDestionations so is this actually being tested? - - // test outgoing transfer - if (tx.getOutgoingTransfer()) { - assert(tx.isOutgoing()); - testTransfer(tx.getOutgoingTransfer(), ctx); - if (ctx.isSweepResponse) assert.equal(tx.getOutgoingTransfer().getDestinations().length, 1); - - // TODO: handle special cases - } else { - assert(tx.getIncomingTransfers().length > 0); - assert.equal(tx.getOutgoingAmount(), undefined); - assert.equal(tx.getOutgoingTransfer(), undefined); - assert.equal(tx.getRingSize(), undefined); - assert.equal(tx.getFullHex(), undefined); - assert.equal(tx.getMetadata(), undefined); - assert.equal(tx.getKey(), undefined); - } - - // test incoming transfers - if (tx.getIncomingTransfers()) { - assert(tx.isIncoming()); - assert(tx.getIncomingTransfers().length > 0); - TestUtils.testUnsignedBigInteger(tx.getIncomingAmount()); - assert.equal(tx.isFailed(), false); - - // test each transfer and collect transfer sum - let transferSum = new BigInteger(0); - for (let transfer of tx.getIncomingTransfers()) { - testTransfer(transfer, ctx); - transferSum = transferSum.add(transfer.getAmount()); - if (ctx.wallet) assert.equal(transfer.getAddress(), await ctx.wallet.getAddress(transfer.getAccountIndex(), transfer.getSubaddressIndex())); - - // TODO special case: transfer amount of 0 - } - - // incoming transfers add up to incoming tx amount - assert.equal(transferSum.compare(tx.getIncomingAmount()), 0); - } else { - assert(tx.getOutgoingTransfer()); - assert.equal(tx.getIncomingAmount(), undefined); - assert.equal(tx.getIncomingTransfers(), undefined); - } - - // test tx results from send or relay - if (ctx.isSendResponse) { - - // test tx set - assert.notEqual(tx.getTxSet(), undefined); - let found = false; - for (let aTx of tx.getTxSet().getTxs()) { - if (aTx === tx) { - found = true; - break; - } - } - if (ctx.isCopy) assert(!found); // copy will not have back reference from tx set - else assert(found); - - // test common attributes - let config = ctx.config; - assert.equal(tx.isConfirmed(), false); - testTransfer(tx.getOutgoingTransfer(), ctx); - assert.equal(tx.getRingSize(), MoneroUtils.RING_SIZE); - assert.equal(tx.getUnlockHeight(), config.getUnlockHeight() ? config.getUnlockHeight() : 0); - assert.equal(tx.getBlock(), undefined); - assert(tx.getKey().length > 0); - assert.equal(typeof tx.getFullHex(), "string"); - assert(tx.getFullHex().length > 0); - assert(tx.getMetadata()); - assert.equal(tx.getReceivedTimestamp(), undefined); - assert.equal(tx.isLocked(), true); - - // test locked state - if (tx.getUnlockHeight() === 0) assert.equal(!tx.isLocked(), tx.isConfirmed()); - else assert.equal(tx.isLocked(), true); - if (tx.getOutputs() !== undefined) { - for (let output of tx.getOutputs()) { - assert.equal(output.isLocked(), tx.isLocked()); - } - } - - // test destinations of sent tx - assert.equal(tx.getOutgoingTransfer().getDestinations().length, config.getDestinations().length); - for (let i = 0; i < config.getDestinations().length; i++) { - assert.equal(tx.getOutgoingTransfer().getDestinations()[i].getAddress(), config.getDestinations()[i].getAddress()); - if (ctx.isSweepResponse) { - assert.equal(config.getDestinations().length, 1); - assert.equal(config.getDestinations()[i].getAmount(), undefined); - assert.equal(tx.getOutgoingTransfer().getDestinations()[i].getAmount().toString(), tx.getOutgoingTransfer().getAmount().toString()); - } else { - assert.equal(tx.getOutgoingTransfer().getDestinations()[i].getAmount().toString(), config.getDestinations()[i].getAmount().toString()); - } - } - - // test relayed txs - if (config.getRelay()) { - assert.equal(tx.inTxPool(), true); - assert.equal(tx.getRelay(), true); - assert.equal(tx.isRelayed(), true); - assert(tx.getLastRelayedTimestamp() > 0); - assert.equal(tx.isDoubleSpendSeen(), false); - } - - // test non-relayed txs - else { - assert.equal(tx.inTxPool(), false); - assert.notEqual(tx.getRelay(), true); - assert.equal(tx.isRelayed(), false); - assert.equal(tx.getLastRelayedTimestamp(), undefined); - assert.equal(tx.isDoubleSpendSeen(), undefined); - } - } - - // test tx result query - else { - assert.equal(tx.getTxSet(), undefined); // tx set only initialized on send responses - assert.equal(tx.getRingSize(), undefined); - assert.equal(tx.getKey(), undefined); - assert.equal(tx.getFullHex(), undefined); - assert.equal(tx.getMetadata(), undefined); - assert.equal(tx.getLastRelayedTimestamp(), undefined); - } - - // test outputs - if (tx.isIncoming() && ctx.includeOutputs) { - if (tx.isConfirmed()) { - assert(tx.getOutputs() !== undefined); - assert(tx.getOutputs().length > 0); - } else { - assert(tx.getOutputs() === undefined); - } - - } - if (tx.getOutputs()) for (let output of tx.getOutputs()) testOutputWallet(output); - - // test deep copy - if (!ctx.isCopy) await this._testTxWalletCopy(tx, ctx); - } - - // TODO: move below _testTxWalletCopy - async _testTxWalletCopy(tx, ctx) { - - // copy tx and assert deep equality - let copy = tx.copy(); - assert(copy instanceof MoneroTxWallet); - assert.deepEqual(copy.toJson(), tx.toJson()); - - // test different references - if (tx.getOutgoingTransfer()) { - assert(tx.getOutgoingTransfer() !== copy.getOutgoingTransfer()); - assert(tx.getOutgoingTransfer().getTx() !== copy.getOutgoingTransfer().getTx()); - //assert(tx.getOutgoingTransfer().getAmount() !== copy.getOutgoingTransfer().getAmount()); // TODO: BI 0 === BI 0?, testing this instead: - if (tx.getOutgoingTransfer().getAmount() === copy.getOutgoingTransfer().getAmount()) assert(tx.getOutgoingTransfer().getAmount().compare(new BigInteger(0)) === 0); - if (tx.getOutgoingTransfer().getDestinations()) { - assert(tx.getOutgoingTransfer().getDestinations() !== copy.getOutgoingTransfer().getDestinations()); - for (let i = 0; i < tx.getOutgoingTransfer().getDestinations().length; i++) { - assert.deepEqual(copy.getOutgoingTransfer().getDestinations()[i], tx.getOutgoingTransfer().getDestinations()[i]); - assert(tx.getOutgoingTransfer().getDestinations()[i] !== copy.getOutgoingTransfer().getDestinations()[i]); - if (tx.getOutgoingTransfer().getDestinations()[i].getAmount() === copy.getOutgoingTransfer().getDestinations()[i].getAmount()) assert(tx.getOutgoingTransfer().getDestinations()[i].getAmount().toJSValue() === 0); - } - } - } - if (tx.getIncomingTransfers()) { - for (let i = 0; i < tx.getIncomingTransfers().length; i++) { - assert.deepEqual(copy.getIncomingTransfers()[i].toJson(), tx.getIncomingTransfers()[i].toJson()); - assert(tx.getIncomingTransfers()[i] !== copy.getIncomingTransfers()[i]); - if (tx.getIncomingTransfers()[i].getAmount() == copy.getIncomingTransfers()[i].getAmount()) assert(tx.getIncomingTransfers()[i].getAmount().toJSValue() === 0); - } - } - if (tx.getOutputs()) { - for (let i = 0; i < tx.getOutputs().length; i++) { - assert.deepEqual(copy.getOutputs()[i].toJson(), tx.getOutputs()[i].toJson()); - assert(tx.getOutputs()[i] !== copy.getOutputs()[i]); - if (tx.getOutputs()[i].getAmount() == copy.getOutputs()[i].getAmount()) assert(tx.getOutputs()[i].getAmount().toJSValue() === 0); - } - } - - // test copied tx - ctx = Object.assign({}, ctx); - ctx.isCopy = true; - if (tx.getBlock()) copy.setBlock(tx.getBlock().copy().setTxs([copy])); // copy block for testing - await this._testTxWallet(copy, ctx); - - // test merging with copy - let merged = copy.merge(copy.copy()); - assert.equal(merged.toString(), tx.toString()); - } - - async _testMultisig(m, n, testTx) { - console.log("_testMultisig(" + m + ", " + n + ")"); - let BEGIN_MULTISIG_NAME = "begin_multisig_wallet"; - let err; // try...finally - let curWallet; - try { - - // wait for txs to clear pool - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(this.wallet); - - // set name attribute of test wallet at beginning of test - await this.wallet.setAttribute("name", BEGIN_MULTISIG_NAME); - await this.wallet.save(); - await this.wallet.close(); - - // create n wallets and prepare multisig hexes - let preparedMultisigHexes = []; - let walletIds = []; - for (let i = 0; i < n; i++) { - let wallet = await this.createWallet(); - walletIds.push(await wallet.getPath()); - await wallet.setAttribute("name", await wallet.getPath()); // set the name of each wallet as an attribute - preparedMultisigHexes.push(await wallet.prepareMultisig()); - //console.log("PREPARED HEX: " + preparedMultisigHexes[preparedMultisigHexes.length - 1]); - await wallet.close(true); - } - - // make wallets multisig - let address = undefined; - let madeMultisigHexes = []; - for (let i = 0; i < walletIds.length; i++) { - - // open the wallet - let wallet = await this.openWallet({path: walletIds[i]}); - assert.equal(await wallet.getAttribute("name"), walletIds[i]); - - // collect prepared multisig hexes from wallet's peers - let peerMultisigHexes = []; - for (let j = 0; j < walletIds.length; j++) if (j !== i) peerMultisigHexes.push(preparedMultisigHexes[j]); - - // make the wallet multisig - let result = await wallet.makeMultisig(peerMultisigHexes, m, TestUtils.WALLET_PASSWORD); - //console.log("MADE RESULT: " + JsonUtils.serialize(result)); - if (address === undefined) address = result.getAddress(); - else assert.equal(result.getAddress(), address); - madeMultisigHexes.push(result.getMultisigHex()); - await wallet.close(true); - } - - // handle m/n which exchanges keys n - m times - if (m !== n) { - address = undefined; - - // exchange keys n - m times - assert.equal(madeMultisigHexes.length, n); - let prevMultisigHexes = madeMultisigHexes; - for (let i = 0; i < n - m; i++) { - //console.log("Exchanging multisig keys round " + (i + 1) + " / " + (n - m)); - - // exchange multisig keys with each wallet and collect results - let exchangeMultisigHexes = []; - for (let j = 0; j < walletIds.length; j++) { - let walletId = walletIds[j]; - - // open the wallet - let wallet = await this.openWallet({path: walletId}); - assert.equal(await wallet.getAttribute("name"), walletIds[j]); - - // collect the multisig hexes of the wallet's peers from last round - let peerMultisigHexes = []; - for (let k = 0; k < walletIds.length; k++) if (k !== j) peerMultisigHexes.push(prevMultisigHexes[k]); - - // import the multisig hexes of the wallet's peers - let result = await wallet.exchangeMultisigKeys(peerMultisigHexes, TestUtils.WALLET_PASSWORD); - //console.log("EXCHANGED MULTISIG KEYS RESULT: " + JsonUtils.serialize(result)); - - // test result - if (i === n - m - 1) { // result on last round has address and not multisig hex to share - assert.notEqual(result.getAddress(), undefined); - assert(result.getAddress().length > 0); - if (address === undefined) address = result.getAddress(); - else assert.equal(result.getAddress(), address); - assert.equal(result.getMultisigHex(), undefined); - } else { - assert.notEqual(result.getMultisigHex(), undefined); - assert(result.getMultisigHex().length > 0); - assert.equal(result.getAddress(), undefined); - exchangeMultisigHexes.push(result.getMultisigHex()); - } - - //await wallet.save(); - await wallet.close(true); - } - - // use results for next round of exchange - prevMultisigHexes = exchangeMultisigHexes; - } - } - - // print final multisig address - curWallet = await this.openWallet({path: walletIds[0]}); - assert.equal(await curWallet.getAttribute("name"), walletIds[0]); - //console.log("FINAL MULTISIG ADDRESS: " + await curWallet.getPrimaryAddress()); - await curWallet.close(); - - // test sending a multisig transaction if configured - if (testTx) { - - console.log("Creating account"); - - // create an account in the first multisig wallet to receive funds to - curWallet = await this.openWallet({path: walletIds[0]}); - assert.equal(await curWallet.getAttribute("name"), walletIds[0]); - await curWallet.createAccount(); - - // get destinations to subaddresses within the account of the multisig wallet - let accountIdx = 1; - let destinations = []; - for (let i = 0; i < 3; i++) { - await curWallet.createSubaddress(accountIdx); - destinations.push(new MoneroDestination(await curWallet.getAddress(accountIdx, i), TestUtils.MAX_FEE.multiply(new BigInteger(2)))); - } - await curWallet.close(true); - - // send funds from the main test wallet to destinations in the first multisig wallet - curWallet = await this.getTestWallet(); // get / open the main test wallet - assert.equal(await curWallet.getAttribute("name"), BEGIN_MULTISIG_NAME); - assert((await curWallet.getBalance()).compare(new BigInteger(0)) > 0); - console.log("Sending funds from main wallet"); - await curWallet.createTx({accountIndex: 0, destinations: destinations, relay: true}); - let returnAddress = await curWallet.getPrimaryAddress(); // funds will be returned to this address from the multisig wallet - - // open the first multisig participant - curWallet = await this.openWallet({path: walletIds[0]}); - assert.equal(await curWallet.getAttribute("name"), walletIds[0]); - this._testMultisigInfo(await curWallet.getMultisigInfo(), m, n); - await curWallet.startSyncing(); - - console.log("Starting mining"); - - // start mining to push the network along - await StartMining.startMining(); - - // wait for the multisig wallet's funds to unlock // TODO: replace with MoneroWalletListener.onOutputReceived() which is called when output unlocked - let lastNumConfirmations = undefined; - while (true) { - - // wait for a moment - await new Promise(function(resolve) { setTimeout(resolve, MoneroUtils.WALLET_REFRESH_RATE); }); - - // fetch and test outputs - let outputs = await curWallet.getOutputs(); - if (outputs.length === 0) console.log("No outputs reported yet"); - else { - - // print num confirmations - let height = await this.daemon.getHeight(); - let numConfirmations = height - outputs[0].getTx().getHeight(); - if (lastNumConfirmations === undefined || lastNumConfirmations !== numConfirmations) console.log("Output has " + (height - outputs[0].getTx().getHeight()) + " confirmations"); - lastNumConfirmations = numConfirmations; - - // outputs are not spent - for (let output of outputs) assert(output.isSpent() === false); - - // break if output is unlocked - if (!outputs[0].isLocked()) break; - } - } - - // stop mining - await this.daemon.stopMining(); - - // multisig wallet should have unlocked balance in account 1 subaddresses 0-3 - assert.equal(await curWallet.getAttribute("name"), walletIds[0]); - for (let i = 0; i < 3; i++) { - assert((await curWallet.getUnlockedBalance(1, i)).compare(BigInteger.parse("0")) > 0); - } - let outputs = await curWallet.getOutputs(new MoneroOutputQuery().setAccountIndex(1)); - assert(outputs.length > 0); - if (outputs.length < 3) console.log("WARNING: not one output per subaddress?"); - //assert(outputs.length >= 3); // TODO - for (let output of outputs) assert.equal(output.isLocked(), false); - - // wallet requires importing multisig to be reliable - assert(await curWallet.isMultisigImportNeeded()); - - // attempt creating and relaying transaction without synchronizing with participants - try { - await curWallet.createTxs({accountIndex: 1, address: returnAddress, amount: TestUtils.MAX_FEE.multiply(new BigInteger(3))}); - throw new Error("Should have failed sending funds without synchronizing with peers"); - } catch (e) { - assert.equal(e.message, "No transaction created"); - } - - // synchronize the multisig participants since receiving outputs - console.log("Synchronizing participants"); - curWallet = await this._synchronizeMultisigParticipants(curWallet, walletIds); - assert.equal(await curWallet.getAttribute("name"), walletIds[0]); - - // attempt relaying created transactions without co-signing - try { - await curWallet.createTxs({address: returnAddress, amount: TestUtils.MAX_FEE, accountIndex: 1, subaddressIndex: 0, relay: true}); - throw new RuntimeException("Should have failed"); - } catch (e) { - assert.equal(e.message, "Cannot relay multisig transaction until co-signed"); - } - - // send funds from a subaddress in the multisig wallet - console.log("Sending"); - let txs = await curWallet.createTxs({address: returnAddress, amount: TestUtils.MAX_FEE, accountIndex: 1, subaddressIndex: 0}); - assert(txs.length > 0); - let txSet = txs[0].getTxSet(); - assert.notEqual(txSet.getMultisigTxHex(), undefined); - assert.equal(txSet.getSignedTxHex(), undefined); - assert.equal(txSet.getUnsignedTxHex(), undefined); - - // parse multisig tx hex and test - testParsedTxSet(await curWallet.parseTxSet(txSet)); - await curWallet.close(true); - - // sign the tx with participants 1 through m - 1 to meet threshold - let multisigTxHex = txSet.getMultisigTxHex(); - console.log("Signing"); - for (let i = 1; i < m; i++) { - curWallet = await this.openWallet({path: walletIds[i]}); - let result = await curWallet.signMultisigTxHex(multisigTxHex); - multisigTxHex = result.getSignedMultisigTxHex(); - await curWallet.close(true); - } - - //console.log("Submitting signed multisig tx hex: " + multisigTxHex); - - // submit the signed multisig tx hex to the network - console.log("Submitting"); - curWallet = await this.openWallet({path: walletIds[0]}); - let txHashes = await curWallet.submitMultisigTxHex(multisigTxHex); - await curWallet.save(); - - // synchronize the multisig participants since spending outputs - console.log("Synchronizing participants"); - curWallet = await this._synchronizeMultisigParticipants(curWallet, walletIds); - - // fetch the wallet's multisig txs - let multisigTxs = await curWallet.getTxs(new MoneroTxQuery().setHashes(txHashes)); - assert.equal(txHashes.length, multisigTxs.length); - - // sweep an output from subaddress [1,1] - outputs = await curWallet.getOutputs(new MoneroOutputQuery().setAccountIndex(1).setSubaddressIndex(1)); - assert(outputs.length > 0); - assert(outputs[0].isSpent() === false); - txSet = (await curWallet.sweepOutput({address: returnAddress, keyImage: outputs[0].getKeyImage().getHex(), relay: true})).getTxSet(); - assert.notEqual(txSet.getMultisigTxHex(), undefined); - assert.equal(txSet.getSignedTxHex(), undefined); - assert.equal(txSet.getUnsignedTxHex(), undefined); - assert(txSet.getTxs().length > 0); - await curWallet.close(true); - - // sign the tx with participants 1 through m - 1 to meet threshold - multisigTxHex = txSet.getMultisigTxHex(); - console.log("Signing sweep output"); - for (let i = 1; i < m; i++) { - curWallet = await this.openWallet({path: walletIds[i]}); - let result = await curWallet.signMultisigTxHex(multisigTxHex); - multisigTxHex = result.getSignedMultisigTxHex(); - await curWallet.close(true); - } - - // submit the signed multisig tx hex to the network - console.log("Submitting sweep output"); - curWallet = await this.openWallet({path: walletIds[0]}); - txHashes = await curWallet.submitMultisigTxHex(multisigTxHex); - await curWallet.save(); - - // synchronize the multisig participants since spending outputs - console.log("Synchronizing participants"); - curWallet = await this._synchronizeMultisigParticipants(curWallet, walletIds); - - // fetch the wallet's multisig txs - multisigTxs = await curWallet.getTxs(new MoneroTxQuery().setHashes(txHashes)); - assert.equal(txHashes.length, multisigTxs.length); - - // sweep remaining balance - console.log("Sweeping"); - txs = await curWallet.sweepUnlocked({address: returnAddress, accountIndex: 1, relay: true}); // TODO: test multisig with sweepEachSubaddress which will generate multiple tx sets without synchronizing participants - assert(txs.length > 0, "No txs created on sweepUnlocked"); - txSet = txs[0].getTxSet(); - for (let tx of txs) { - assert(tx.getTxSet() === txSet); // only one tx set created per account - let found = false; - for (let aTx of tx.getTxSet().getTxs()) { - if (aTx === tx) { - found = true; - break; - } - } - assert(found); // tx is contained in tx set - } - assert.notEqual(txSet.getMultisigTxHex(), undefined); - assert.equal(txSet.getSignedTxHex(), undefined); - assert.equal(txSet.getUnsignedTxHex(), undefined); - - // parse multisig tx hex and test - testParsedTxSet(await curWallet.parseTxSet(txSet)); - await curWallet.close(true); - - // sign the tx with participants 1 through m - 1 to meet threshold - multisigTxHex = txSet.getMultisigTxHex(); - console.log("Signing sweep"); - for (let i = 1; i < m; i++) { - curWallet = await this.openWallet({path: walletIds[i]}); - let result = await curWallet.signMultisigTxHex(multisigTxHex); - multisigTxHex = result.getSignedMultisigTxHex(); - await curWallet.close(true); - } - - // submit the signed multisig tx hex to the network - console.log("Submitting sweep"); - curWallet = await this.openWallet({path: walletIds[0]}); - txHashes = await curWallet.submitMultisigTxHex(multisigTxHex); - await curWallet.save(); - - // synchronize the multisig participants since spending outputs - console.log("Synchronizing participants"); - curWallet = await this._synchronizeMultisigParticipants(curWallet, walletIds); - - // fetch the wallet's multisig txs - multisigTxs = await curWallet.getTxs(new MoneroTxQuery().setHashes(txHashes)); - assert.equal(txHashes.length, multisigTxs.length); - - await curWallet.close(true); - } - } catch (e) { - err = e; - } - - // re-open main test wallet - if (curWallet && !await curWallet.isClosed()) await curWallet.close(); - this.wallet = await this.getTestWallet(); - assert.equal(await this.wallet.getAttribute("name"), BEGIN_MULTISIG_NAME); - if (err) throw err; - } - - async _synchronizeMultisigParticipants(currentWallet, walletIds) { - - // close the current wallet - let path = await currentWallet.getPath(); - await currentWallet.close(true); - - // collect multisig hex of all participants to synchronize - let multisigHexes = []; - for (let walletId of walletIds) { - let wallet = await this.openWallet({path: walletId}); - await wallet.sync(); - let hex = await wallet.getMultisigHex(); - multisigHexes.push(hex); - await wallet.close(true); - } - - // import each wallet's peer multisig hex - for (let i = 0; i < walletIds.length; i++) { - let peerMultisigHexes = []; - for (let j = 0; j < walletIds.length; j++) if (j !== i) peerMultisigHexes.push(multisigHexes[j]); - let wallet = await this.openWallet({path: walletIds[i]}); - await wallet.sync(); - await wallet.importMultisigHex(peerMultisigHexes); - await wallet.close(true); - } - - // re-open current wallet and return - let endWallet = await this.openWallet({path: path}); - await endWallet.sync(); - return endWallet; - } - - async _testMultisigInfo(info, m, n) { - assert(info.isMultisig()); - assert(info.isReady()); - assert.equal(info.getThreshold(), m); - assert.equal(info.getNumParticipants(), n); - } -} - -// ------------------------------ PRIVATE STATIC ------------------------------ - -function testAccount(account) { - - // test account - assert(account); - assert(account.getIndex() >= 0); - MoneroUtils.validateAddress(account.getPrimaryAddress()); - TestUtils.testUnsignedBigInteger(account.getBalance()); - TestUtils.testUnsignedBigInteger(account.getUnlockedBalance()); - - // if given, test subaddresses and that their balances add up to account balances - if (account.getSubaddresses()) { - let balance = new BigInteger(0); - let unlockedBalance = new BigInteger(0); - for (let i = 0; i < account.getSubaddresses().length; i++) { - testSubaddress(account.getSubaddresses()[i]); - assert.equal(account.getSubaddresses()[i].getAccountIndex(), account.getIndex()); - assert.equal(account.getSubaddresses()[i].getIndex(), i); - balance = balance.add(account.getSubaddresses()[i].getBalance()); - unlockedBalance = unlockedBalance.add(account.getSubaddresses()[i].getUnlockedBalance()); - } - assert(account.getBalance().compare(balance) === 0, "Subaddress balances " + balance.toString() + " does not equal account " + account.getIndex() + " balance " + account.getBalance().toString()); - assert(account.getUnlockedBalance().compare(unlockedBalance) === 0, "Subaddress unlocked balances " + unlockedBalance.toString() + " does not equal account " + account.getIndex() + " unlocked balance " + account.getUnlockedBalance().toString()); - } - - // tag must be undefined or non-empty - let tag = account.getTag(); - assert(tag === undefined || tag.length > 0); -} - -function testSubaddress(subaddress) { - assert(subaddress.getAccountIndex() >= 0); - assert(subaddress.getIndex() >= 0); - assert(subaddress.getAddress()); - assert(subaddress.getLabel() === undefined || typeof subaddress.getLabel() === "string"); - if (typeof subaddress.getLabel() === "string") assert(subaddress.getLabel().length > 0); - TestUtils.testUnsignedBigInteger(subaddress.getBalance()); - TestUtils.testUnsignedBigInteger(subaddress.getUnlockedBalance()); - assert(subaddress.getNumUnspentOutputs() >= 0); - assert(typeof subaddress.isUsed() === "boolean"); - if (subaddress.getBalance().compare(new BigInteger(0)) > 0) assert(subaddress.isUsed()); - assert(subaddress.getNumBlocksToUnlock() >= 0); -} - -/** - * Gets random transactions. - * - * @param wallet is the wallet to query for transactions - * @param query configures the transactions to retrieve - * @param minTxs specifies the minimum number of transactions (undefined for no minimum) - * @param maxTxs specifies the maximum number of transactions (undefined for all filtered transactions) - * @return {MoneroTxWallet[]} are the random transactions - */ -async function getRandomTransactions(wallet, query, minTxs, maxTxs) { - let txs = await wallet.getTxs(query); - if (minTxs !== undefined) assert(txs.length >= minTxs, txs.length + "/" + minTxs + " transactions found with query: " + JSON.stringify(query)); - GenUtils.shuffle(txs); - if (maxTxs === undefined) return txs; - else return txs.slice(0, Math.min(maxTxs, txs.length)); -} - -/** - * Tests that common tx field types are valid regardless of tx state. - * - * @param tx is the tx to test - */ -function testTxWalletTypes(tx, ctx) { - assert.equal(typeof tx.getHash(), "string"); - assert.equal(typeof tx.isConfirmed(), "boolean"); - assert.equal(typeof tx.isMinerTx(), "boolean"); - assert.equal(typeof tx.isFailed(), "boolean"); - assert.equal(typeof tx.isRelayed(), "boolean"); - assert.equal(typeof tx.inTxPool(), "boolean"); - assert.equal(typeof tx.isLocked(), "boolean"); - TestUtils.testUnsignedBigInteger(tx.getFee()); - assert.equal(tx.getInputs(), undefined); // TODO no way to expose inputs? - if (tx.getPaymentId()) assert.notEqual(tx.getPaymentId(), MoneroTx.DEFAULT_PAYMENT_ID); // default payment id converted to undefined - if (tx.getNote()) assert(tx.getNote().length > 0); // empty notes converted to undefined - assert(tx.getUnlockHeight() >= 0); - assert.equal(tx.getSize(), undefined); // TODO monero-wallet-rpc: add tx_size to get_transfers and get_transfer_by_txid - if (ctx.isSendResponse) assert(tx.getWeight() > 0); - else assert.equal(tx.getWeight(), undefined); - assert.equal(tx.getReceivedTimestamp(), undefined); // TODO monero-wallet-rpc: return received timestamp (asked to file issue if wanted) -} - -function testTransfer(transfer, ctx) { - if (ctx === undefined) ctx = {}; - assert(transfer instanceof MoneroTransfer); - TestUtils.testUnsignedBigInteger(transfer.getAmount()); - if (!ctx.isSweepOutputResponse) assert(transfer.getAccountIndex() >= 0); - if (transfer.isIncoming()) testIncomingTransfer(transfer); - else testOutgoingTransfer(transfer, ctx); - - // transfer and tx reference each other - assert(transfer.getTx()); - if (transfer !== transfer.getTx().getOutgoingTransfer()) { - assert(transfer.getTx().getIncomingTransfers()); - assert(transfer.getTx().getIncomingTransfers().includes(transfer), "Transaction does not reference given transfer"); - } -} - -function testIncomingTransfer(transfer) { - assert(transfer.isIncoming()); - assert(!transfer.isOutgoing()); - assert(transfer.getAddress()); - assert(transfer.getSubaddressIndex() >= 0); - assert(transfer.getNumSuggestedConfirmations() > 0); -} - -function testOutgoingTransfer(transfer, ctx) { - assert(!transfer.isIncoming()); - assert(transfer.isOutgoing()); - if (!ctx.isSendResponse) assert(transfer.getSubaddressIndices()); - if (transfer.getSubaddressIndices()) { - assert(transfer.getSubaddressIndices().length >= 1); - for (let subaddressIdx of transfer.getSubaddressIndices()) assert(subaddressIdx >= 0); - } - if (transfer.getAddresses()) { - assert.equal(transfer.getAddresses().length, transfer.getSubaddressIndices().length); - for (let address of transfer.getAddresses()) assert(address); - } - - // test destinations sum to outgoing amount - if (transfer.getDestinations()) { - assert(transfer.getDestinations().length > 0); - let sum = new BigInteger(0); - for (let destination of transfer.getDestinations()) { - testDestination(destination); - TestUtils.testUnsignedBigInteger(destination.getAmount(), true); - sum = sum.add(destination.getAmount()); - } - if (transfer.getAmount().compare(sum) !== 0) console.log(transfer.getTx().getTxSet() === undefined ? transfer.getTx().toString() : transfer.getTx().getTxSet().toString()); - assert.equal(sum.toString(), transfer.getAmount().toString()); // TODO: sum of destinations != outgoing amount in split txs - } -} - -function testDestination(destination) { - MoneroUtils.validateAddress(destination.getAddress(), TestUtils.NETWORK_TYPE); - TestUtils.testUnsignedBigInteger(destination.getAmount(), true); -} - -function testOutputWallet(output) { - assert(output); - assert(output instanceof MoneroOutputWallet); - assert(output.getAccountIndex() >= 0); - assert(output.getSubaddressIndex() >= 0); - assert(output.getIndex() >= 0); - assert.equal(typeof output.isSpent(), "boolean"); - assert.equal(typeof output.isLocked(), "boolean"); - assert.equal(typeof output.isFrozen(), "boolean"); - assert(output.getKeyImage()); - assert(output.getKeyImage() instanceof MoneroKeyImage); - assert(output.getKeyImage().getHex()); - TestUtils.testUnsignedBigInteger(output.getAmount(), true); - - // output has circular reference to its transaction which has some initialized fields - let tx = output.getTx(); - assert(tx); - assert(tx instanceof MoneroTxWallet); - assert(tx.getOutputs().includes(output)); - assert(tx.getHash()); - assert.equal(typeof tx.isLocked(), "boolean"); - assert.equal(tx.isConfirmed(), true); // TODO monero-wallet-rpc: possible to get unconfirmed outputs? - assert.equal(tx.isRelayed(), true); - assert.equal(tx.isFailed(), false); - assert(tx.getHeight() > 0); - - // test copying - let copy = output.copy(); - assert(copy !== output); - assert.equal(copy.toString(), output.toString()); - assert.equal(copy.getTx(), undefined); // TODO: should output copy do deep copy of tx so models are graph instead of tree? Would need to work out circular references -} - -function testCommonTxSets(txs, hasSigned, hasUnsigned, hasMultisig) { - assert(txs.length > 0); - - // assert that all sets are same reference - let set; - for (let i = 0; i < txs.length; i++) { - assert(txs[i] instanceof MoneroTx); - if (i === 0) set = txs[i].getTxSet(); - else assert(txs[i].getTxSet() === set); - } - - // test expected set - assert(set); - if (hasSigned) { - assert(set.getSignedTxSet()); - assert(set.getSignedTxSet().length > 0); - } - if (hasUnsigned) { - assert(set.getUnsignedTxSet()); - assert(set.getUnsignedTxSet().length > 0); - } - if (hasMultisig) { - assert(set.getMultisigTxSet()); - assert(set.getMultisigTxSet().length > 0); - } -} - -function testCheckTx(tx, check) { - assert.equal(typeof check.isGood(), "boolean"); - if (check.isGood()) { - assert(check.getNumConfirmations() >= 0); - assert.equal(typeof check.inTxPool(), "boolean"); - TestUtils.testUnsignedBigInteger(check.getReceivedAmount()); - if (check.inTxPool()) assert.equal(0, check.getNumConfirmations()); - else assert(check.getNumConfirmations() > 0); // TODO (monero-wall-rpc) this fails (confirmations is 0) for (at least one) transaction that has 1 confirmation on testCheckTxKey() - } else { - assert.equal(check.getNumConfirmations(), undefined); - assert.equal(check.inTxPool(), undefined); - assert.equal(check.getReceivedAmount(), undefined); - } -} - -function testCheckReserve(check) { - assert.equal(typeof check.isGood(), "boolean"); - if (check.isGood()) { - TestUtils.testUnsignedBigInteger(check.getTotalAmount()); - assert(check.getTotalAmount().compare(new BigInteger(0)) >= 0); - TestUtils.testUnsignedBigInteger(check.getUnconfirmedSpentAmount()); - assert(check.getUnconfirmedSpentAmount().compare(new BigInteger(0)) >= 0); - } else { - assert.equal(check.getTotalAmount(), undefined); - assert.equal(check.getUnconfirmedSpentAmount(), undefined); - } -} - -function testParsedTxSet(parsedTxSet) { - assert.notEqual(parsedTxSet, undefined); - assert(parsedTxSet.getTxs().length > 0); - assert.equal(parsedTxSet.getSignedTxHex(), undefined); - assert.equal(parsedTxSet.getUnsignedTxHex(), undefined); - - // test each transaction - // TODO: use common tx wallet test? - assert.equal(parsedTxSet.getMultisigTxHex(), undefined); - for (let parsedTx of parsedTxSet.getTxs()) { - TestUtils.testUnsignedBigInteger(parsedTx.getInputSum(), true); - TestUtils.testUnsignedBigInteger(parsedTx.getOutputSum(), true); - TestUtils.testUnsignedBigInteger(parsedTx.getFee()); - TestUtils.testUnsignedBigInteger(parsedTx.getChangeAmount()); - if (parsedTx.getChangeAmount().compare(new BigInteger(0)) === 0) assert.equal(parsedTx.getChangeAddress(), undefined); - else MoneroUtils.validateAddress(parsedTx.getChangeAddress(), TestUtils.NETWORK_TYPE); - assert(parsedTx.getRingSize() > 1); - assert(parsedTx.getUnlockHeight() >= 0); - assert(parsedTx.getNumDummyOutputs() >= 0); - assert(parsedTx.getExtraHex()); - assert(parsedTx.getPaymentId() === undefined || parsedTx.getPaymentId().length > 0); - assert(parsedTx.isOutgoing()); - assert.notEqual(parsedTx.getOutgoingTransfer(), undefined); - assert.notEqual(parsedTx.getOutgoingTransfer().getDestinations(), undefined); - assert(parsedTx.getOutgoingTransfer().getDestinations().length > 0); - assert.equal(parsedTx.isIncoming(), undefined); - for (let destination of parsedTx.getOutgoingTransfer().getDestinations()) { - testDestination(destination); - } - } -} - -function testAddressBookEntry(entry) { - assert(entry.getIndex() >= 0); - MoneroUtils.validateAddress(entry.getAddress(), TestUtils.NETWORK_TYPE); - assert.equal(typeof entry.getDescription(), "string"); -} - -/** - * Tests the integrity of the full structure in the given txs from the block down - * to transfers / destinations. - */ -function testGetTxsStructure(txs, query = undefined) { - - // normalize query - if (query === undefined) query = new MoneroTxQuery(); - if (!(query instanceof MoneroTxQuery)) query = new MoneroTxQuery(query); - - // collect unique blocks in order (using set and list instead of TreeSet for direct portability to other languages) - let seenBlocks = new Set(); - let blocks = []; - let unconfirmedTxs = []; - for (let tx of txs) { - if (tx.getBlock() === undefined) unconfirmedTxs.push(tx); - else { - assert(tx.getBlock().getTxs().includes(tx)); - if (!seenBlocks.has(tx.getBlock())) { - seenBlocks.add(tx.getBlock()); - blocks.push(tx.getBlock()); - } - } - } - - // tx hashes must be in order if requested - if (query.getHashes() !== undefined) { - assert.equal(txs.length, query.getHashes().length); - for (let i = 0; i < query.getHashes().length; i++) { - assert.equal(txs[i].getHash(), query.getHashes()[i]); - } - } - - // test that txs and blocks reference each other and blocks are in ascending order unless specific tx hashes requested - let index = 0; - let prevBlockHeight = undefined; - for (let block of blocks) { - if (prevBlockHeight === undefined) prevBlockHeight = block.getHeight(); - else if (query.getHashes() === undefined) assert(block.getHeight() > prevBlockHeight, "Blocks are not in order of heights: " + prevBlockHeight + " vs " + block.getHeight()); - for (let tx of block.getTxs()) { - assert(tx.getBlock() === block); - if (query.getHashes() === undefined) { - assert.equal(tx.getHash(), txs[index].getHash()); // verify tx order is self-consistent with blocks unless txs manually re-ordered by requesting by hash - assert(tx === txs[index]); - } - index++; - } - } - assert.equal(index + unconfirmedTxs.length, txs.length); - - // test that incoming transfers are in order of ascending accounts and subaddresses - for (let tx of txs) { - let prevAccountIdx = undefined; - let prevSubaddressIdx = undefined; - if (tx.getIncomingTransfers() === undefined) continue; - for (let transfer of tx.getIncomingTransfers()) { - if (prevAccountIdx === undefined) prevAccountIdx = transfer.getAccountIndex(); - else { - assert(prevAccountIdx <= transfer.getAccountIndex()); - if (prevAccountIdx < transfer.getAccountIndex()) { - prevSubaddressIdx = undefined; - prevAccountIdx = transfer.getAccountIndex(); - } - if (prevSubaddressIdx === undefined) prevSubaddressIdx = transfer.getSubaddressIndex(); - else assert(prevSubaddressIdx < transfer.getSubaddressIndex()); - } - } - } - - // TODO monero core wallet2 does not provide ordered blocks or txs -// // collect given tx hashes -// List txHashes = new ArrayList(); -// for (MoneroTx tx : txs) txHashes.add(tx.getHash()); -// -// // fetch network blocks at tx heights -// List heights = new ArrayList(); -// for (MoneroBlock block : blocks) heights.add(block.getHeight()); -// List networkBlocks = that.daemon.getBlocksByHeight(heights); -// -// // collect matching tx hashes from network blocks in order -// List expectedTxIds = new ArrayList(); -// for (MoneroBlock networkBlock : networkBlocks) { -// for (String txHash : networkBlock.getTxHashes()) { -// if (!txHashes.contains(txHash)) expectedTxIds.add(txHash); -// } -// } -// -// // order of hashes must match -// assertEquals(expectedTxIds, txHashes); -} - -function countNumInstances(instances) { - let counts = new Map(); - for (let instance of instances) { - let count = counts.get(instance); - counts.set(instance, count === undefined ? 1 : count + 1); - } - return counts; -} - -function getModes(counts) { - let modes = new Set(); - let maxCount; - for (let key of counts.keys()) { - let count = counts.get(key); - if (maxCount === undefined || count > maxCount) maxCount = count; - } - for (let key of counts.keys()) { - let count = counts.get(key); - if (count === maxCount) modes.add(key); - } - return modes; -} - -module.exports = TestMoneroWalletCommon; \ No newline at end of file diff --git a/src/test/TestMoneroWalletCommon.ts b/src/test/TestMoneroWalletCommon.ts new file mode 100644 index 000000000..acb3e1c48 --- /dev/null +++ b/src/test/TestMoneroWalletCommon.ts @@ -0,0 +1,5619 @@ +import assert from "assert"; +import StartMining from "./utils/StartMining"; +import TestUtils from "./utils/TestUtils"; +import {Filter, + GenUtils, + LibraryUtils, + MoneroAccount, + MoneroBlock, + MoneroDaemonRpc, + MoneroError, + MoneroTxPriority, + MoneroWalletRpc, + MoneroWalletKeys, + MoneroWallet, + MoneroWalletListener, + MoneroWalletConfig, + MoneroUtils, + MoneroMultisigInfo, + MoneroSyncResult, + MoneroRpcConnection, + MoneroConnectionManager, + MoneroCheckTx, + MoneroTxQuery, + MoneroTransfer, + MoneroIncomingTransfer, + MoneroOutgoingTransfer, + MoneroTransferQuery, + MoneroOutputQuery, + MoneroOutputWallet, + MoneroTxConfig, + MoneroTxWallet, + MoneroDestination, + MoneroSubaddress, + MoneroKeyImage, + MoneroTx, + MoneroMessageSignatureType, + MoneroMessageSignatureResult, + MoneroCheckReserve} from "../../index"; + +// test constants +const SEND_DIVISOR = BigInt(10); +const SEND_MAX_DIFF = BigInt(60); +const MAX_TX_PROOFS = 25; // maximum number of transactions to check for each proof, undefined to check all +const NUM_BLOCKS_LOCKED = 10; + +/** + * Test a wallet for common functionality. + */ +export default class TestMoneroWalletCommon { + + // instance variables + testConfig: any; + wallet: MoneroWallet; + daemon: MoneroDaemonRpc; + + /** + * Construct the tester. + * + * @param {object} testConfig - test configuration + */ + constructor(testConfig) { + this.testConfig = testConfig; + } + + /** + * Called before all wallet tests. + */ + async beforeAll() { + console.log("Before all"); + this.wallet = await this.getTestWallet(); + this.daemon = await this.getTestDaemon(); + TestUtils.WALLET_TX_TRACKER.reset(); // all wallets need to wait for txs to confirm to reliably sync + await LibraryUtils.loadWasmModule(); // for wasm dependents like address validation + } + + /** + * Called before each wallet test. + * + @param {object} currentTest - invoked with Mocha current test + */ + async beforeEach(currentTest) { + console.log("Before test \"" + currentTest.title + "\""); + } + + /** + * Called after all wallet tests. + */ + async afterAll() { + console.log("After all"); + + // try to stop mining + if (this.daemon) { + try { await this.daemon.stopMining(); } + catch (err: any) { } + } + + // close wallet + if (this.wallet) await this.wallet.close(true); + } + + /** + * Called after each wallet test. + * + @param {object} currentTest - invoked with Mocha current test + */ + async afterEach(currentTest) { + console.log("After test \"" + currentTest.title + "\""); + } + + /** + * Get the daemon to test. + * + * @return the daemon to test + */ + async getTestDaemon() { + return TestUtils.getDaemonRpc(); + } + + /** + * Get the main wallet to test. + * + * @return {Promise} the wallet to test + */ + async getTestWallet(): Promise { + throw new Error("Subclass must implement"); + } + + /** + * Open a test wallet with default configuration for each wallet type. + * + * @param config - configures the wallet to open + * @return MoneroWallet is the opened wallet + */ + async openWallet(config): Promise { + throw new Error("Subclass must implement"); + } + + /** + * Create a test wallet with default configuration for each wallet type. + * + * @param [config] - configures the wallet to create + * @return {Promise} is the created wallet + */ + async createWallet(config?: Partial): Promise { + throw new Error("Subclass must implement"); + } + + /** + * Close a test wallet with customization for each wallet type. + * + * @param {MoneroWallet} wallet - the wallet to close + * @param {boolean} [save] - whether or not to save the wallet + * @return {Promise} + */ + async closeWallet(wallet, save?) { + throw new Error("Subclass must implement"); + } + + /** + * Get the wallet's supported languages for the seed phrase. This is an + * instance method for wallet rpc and a static utility for other wallets. + * + * @return {Promise} the wallet's supported languages + */ + async getSeedLanguages(): Promise { + throw new Error("Subclass must implement"); + } + + // ------------------------------ BEGIN TESTS ------------------------------- + + runCommonTests(testConfig?) { + let that = this; + testConfig = Object.assign({}, this.testConfig, testConfig) + describe("Common Wallet Tests" + (testConfig.liteMode ? " (lite mode)" : ""), function() { + + // start tests by sending to multiple addresses + if (testConfig.testRelays) + it("Can send to multiple addresses in a single transaction", async function() { + await testSendToMultiple(5, 3, false); + }); + + // --------------------------- TEST NON RELAYS ------------------------- + + if (testConfig.testNonRelays) + it("Can create a random wallet", async function() { + let e1 = undefined; + try { + let wallet = await that.createWallet(); + let path; try { path = await wallet.getPath(); } catch (e: any) { } // TODO: factor out keys-only tests? + let e2 = undefined; + try { + await MoneroUtils.validateAddress(await wallet.getPrimaryAddress(), TestUtils.NETWORK_TYPE); + await MoneroUtils.validatePrivateViewKey(await wallet.getPrivateViewKey()); + await MoneroUtils.validatePrivateSpendKey(await wallet.getPrivateSpendKey()); + await MoneroUtils.validateMnemonic(await wallet.getSeed()); + if (!(wallet instanceof MoneroWalletRpc)) assert.equal(await wallet.getSeedLanguage(), MoneroWallet.DEFAULT_LANGUAGE); // TODO monero-wallet-rpc: get mnemonic language + } catch (e: any) { + e2 = e; + } + await that.closeWallet(wallet); + if (e2 !== undefined) throw e2; + + // attempt to create wallet at same path + if (path) { + try { + await that.createWallet({path: path}); + throw new Error("Should have thrown error"); + } catch (e: any) { + assert.equal(e.message, "Wallet already exists: " + path); + } + } + + // attempt to create wallet with unknown language + try { + await that.createWallet({language: "english"}); // TODO: support lowercase? + throw new Error("Should have thrown error"); + } catch (e: any) { + assert.equal(e.message, "Unknown language: english"); + } + } catch (e: any) { + e1 = e; + } + + if (e1 !== undefined) throw e1; + }); + + if (testConfig.testNonRelays) + it("Can create a wallet from a mnemonic phrase.", async function() { + let e1 = undefined; + try { + + // save for comparison + let primaryAddress = await that.wallet.getPrimaryAddress(); + let privateViewKey = await that.wallet.getPrivateViewKey(); + let privateSpendKey = await that.wallet.getPrivateSpendKey(); + + // recreate test wallet from seed + let wallet = await that.createWallet({seed: TestUtils.SEED, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}); + let path; try { path = await wallet.getPath(); } catch (e: any) { } // TODO: factor out keys-only tests? + let e2 = undefined; + try { + assert.equal(await wallet.getPrimaryAddress(), primaryAddress); + assert.equal(await wallet.getPrivateViewKey(), privateViewKey); + assert.equal(await wallet.getPrivateSpendKey(), privateSpendKey); + if (!(wallet instanceof MoneroWalletRpc)) assert.equal(await wallet.getSeedLanguage(), MoneroWallet.DEFAULT_LANGUAGE); + } catch (e: any) { + e2 = e; + } + await that.closeWallet(wallet); + if (e2 !== undefined) throw e2; + + // attempt to create wallet with two missing words + try { + let invalidMnemonic = "memoir desk algebra inbound innocent unplugs fully okay five inflamed giant factual ritual toyed topic snake unhappy guarded tweezers haunted inundate giant"; + await that.createWallet(new MoneroWalletConfig().setSeed(invalidMnemonic).setRestoreHeight(TestUtils.FIRST_RECEIVE_HEIGHT)); + } catch (err: any) { + assert.equal("Invalid mnemonic", err.message); + } + + // attempt to create wallet at same path + if (path) { + try { + await that.createWallet({path: path}); + throw new Error("Should have thrown error"); + } catch (e: any) { + assert.equal(e.message, "Wallet already exists: " + path); + } + } + } catch (e: any) { + e1 = e; + } + + if (e1 !== undefined) throw e1; + }); + + if (testConfig.testNonRelays) + it("Can create a wallet from a mnemonic phrase with a seed offset", async function() { + let e1 = undefined; + try { + + // create test wallet with offset + let wallet = await that.createWallet({seed: TestUtils.SEED, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, seedOffset: "my secret offset!"}); + let e2 = undefined; + try { + await MoneroUtils.validateMnemonic(await wallet.getSeed()); + assert.notEqual(await wallet.getSeed(), TestUtils.SEED); + await MoneroUtils.validateAddress(await wallet.getPrimaryAddress(), TestUtils.NETWORK_TYPE); + assert.notEqual(await wallet.getPrimaryAddress(), TestUtils.ADDRESS); + if (!(wallet instanceof MoneroWalletRpc)) assert.equal(await wallet.getSeedLanguage(), MoneroWallet.DEFAULT_LANGUAGE); // TODO monero-wallet-rpc: support + } catch (e: any) { + e2 = e; + } + await that.closeWallet(wallet); + if (e2 !== undefined) throw e2; + } catch (e: any) { + e1 = e; + } + + if (e1 !== undefined) throw e1; + }); + + if (testConfig.testNonRelays) + it("Can create a wallet from keys", async function() { + let e1 = undefined; + try { + + // save for comparison + let primaryAddress = await that.wallet.getPrimaryAddress(); + let privateViewKey = await that.wallet.getPrivateViewKey(); + let privateSpendKey = await that.wallet.getPrivateSpendKey(); + + // recreate test wallet from keys + let wallet = await that.createWallet({primaryAddress: primaryAddress, privateViewKey: privateViewKey, privateSpendKey: privateSpendKey, restoreHeight: await that.daemon.getHeight()}); + let path; try { path = await wallet.getPath(); } catch (e: any) { } // TODO: factor out keys-only tests? + let e2 = undefined; + try { + assert.equal(await wallet.getPrimaryAddress(), primaryAddress); + assert.equal(await wallet.getPrivateViewKey(), privateViewKey); + assert.equal(await wallet.getPrivateSpendKey(), privateSpendKey); + if (!(wallet instanceof MoneroWalletKeys) && !await wallet.isConnectedToDaemon()) console.log("WARNING: wallet created from keys is not connected to authenticated daemon"); // TODO monero-project: keys wallets not connected + if (!(wallet instanceof MoneroWalletRpc)) { + assert.equal(await wallet.getSeed(), TestUtils.SEED); // TODO monero-wallet-rpc: cannot get mnemonic from wallet created from keys? + assert.equal(await wallet.getSeedLanguage(), MoneroWallet.DEFAULT_LANGUAGE); + } + } catch (e: any) { + e2 = e; + } + await that.closeWallet(wallet); + if (e2 !== undefined) throw e2; + + // recreate test wallet from spend key + if (!(wallet instanceof MoneroWalletRpc)) { // TODO monero-wallet-rpc: cannot create wallet from spend key? + wallet = await that.createWallet({privateSpendKey: privateSpendKey, restoreHeight: await that.daemon.getHeight()}); + try { path = await wallet.getPath(); } catch (e: any) { } // TODO: factor out keys-only tests? + e2 = undefined; + try { + assert.equal(await wallet.getPrimaryAddress(), primaryAddress); + assert.equal(await wallet.getPrivateViewKey(), privateViewKey); + assert.equal(await wallet.getPrivateSpendKey(), privateSpendKey); + if (!(wallet instanceof MoneroWalletKeys) && !await wallet.isConnectedToDaemon()) console.log("WARNING: wallet created from keys is not connected to authenticated daemon"); // TODO monero-project: keys wallets not connected + if (!(wallet instanceof MoneroWalletRpc)) { + assert.equal(await wallet.getSeed(), TestUtils.SEED); // TODO monero-wallet-rpc: cannot get seed from wallet created from keys? + assert.equal(await wallet.getSeedLanguage(), MoneroWallet.DEFAULT_LANGUAGE); + } + } catch (e: any) { + e2 = e; + } + await that.closeWallet(wallet); + if (e2 !== undefined) throw e2; + } + + // attempt to create wallet at same path + if (path) { + try { + await that.createWallet({path: path}); + throw new Error("Should have thrown error"); + } catch (e: any) { + assert.equal(e.message, "Wallet already exists: " + path); + } + } + } catch (e: any) { + e1 = e; + } + + if (e1 !== undefined) throw e1; + }); + + if (testConfig.testRelays) + it("Can create wallets with subaddress lookahead", async function() { + let err; + let receiver: MoneroWallet | undefined = undefined; + try { + + // create wallet with high subaddress lookahead + receiver = await that.createWallet({ + accountLookahead: 1, + subaddressLookahead: 100000 + }); + + // transfer funds to subaddress with high index + await that.wallet.createTx(new MoneroTxConfig() + .setAccountIndex(0) + .addDestination((await receiver.getSubaddress(0, 85000)).getAddress(), TestUtils.MAX_FEE) + .setRelay(true)); + + // observe unconfirmed funds + await GenUtils.waitFor(1000); + await receiver.sync(); + assert(await receiver.getBalance() > 0n); + } catch (e: any) { + err = e; + } + + // close wallet and throw if error occurred + if (receiver) await that.closeWallet(receiver); + if (err) throw err; + }); + + if (testConfig.testNonRelays) + it("Can get the wallet's version", async function() { + let version = await that.wallet.getVersion(); + assert.equal(typeof version.getNumber(), "number"); + assert(version.getNumber() > 0); + assert.equal(typeof version.getIsRelease(), "boolean"); + }); + + if (testConfig.testNonRelays) + it("Can get the wallet's path", async function() { + + // create random wallet + let wallet = await that.createWallet(); + + // set a random attribute + let uuid = GenUtils.getUUID(); + await wallet.setAttribute("uuid", uuid); + + // record the wallet's path then save and close + let path = await wallet.getPath(); + await that.closeWallet(wallet, true); + + // re-open the wallet using its path + wallet = await that.openWallet({path: path}); + + // test the attribute + assert.equal(await wallet.getAttribute("uuid"), uuid); + await that.closeWallet(wallet); + }); + + if (testConfig.testNonRelays) + it("Can set the daemon connection", async function() { + let err; + let wallet; + try { + + // create random wallet with default daemon connection + wallet = await that.createWallet(); + assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection(TestUtils.DAEMON_RPC_CONFIG).getConfig()); + assert.equal(await wallet.isConnectedToDaemon(), true); + + // set empty server uri + await wallet.setDaemonConnection(""); + assert.equal(await wallet.getDaemonConnection(), undefined); + assert.equal(await wallet.isConnectedToDaemon(), false); + + // set offline server uri + await wallet.setDaemonConnection(TestUtils.OFFLINE_SERVER_URI); + assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection(TestUtils.OFFLINE_SERVER_URI).getConfig()); + assert.equal(await wallet.isConnectedToDaemon(), false); + + // set daemon with wrong credentials + await wallet.setDaemonConnection({uri: TestUtils.DAEMON_RPC_CONFIG.uri, username: "wronguser", password: "wrongpass"}); + assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection(TestUtils.DAEMON_RPC_CONFIG.uri, "wronguser", "wrongpass").getConfig()); + if (!TestUtils.DAEMON_RPC_CONFIG.username) assert.equal(await wallet.isConnectedToDaemon(), true); // TODO: monerod without authentication works with bad credentials? + else assert.equal(await wallet.isConnectedToDaemon(), false); + + // set daemon with authentication + await wallet.setDaemonConnection(TestUtils.DAEMON_RPC_CONFIG); + assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection(TestUtils.DAEMON_RPC_CONFIG.uri, TestUtils.DAEMON_RPC_CONFIG.username, TestUtils.DAEMON_RPC_CONFIG.password).getConfig()); + assert(await wallet.isConnectedToDaemon()); + + // nullify daemon connection + await wallet.setDaemonConnection(undefined); + assert.equal(await wallet.getDaemonConnection(), undefined); + await wallet.setDaemonConnection(TestUtils.DAEMON_RPC_CONFIG.uri); + assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection(TestUtils.DAEMON_RPC_CONFIG.uri).getConfig()); + await wallet.setDaemonConnection(undefined); + assert.equal(await wallet.getDaemonConnection(), undefined); + + // set daemon uri to non-daemon + await wallet.setDaemonConnection("www.getmonero.org"); + assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection("www.getmonero.org").getConfig()); + assert(!await wallet.isConnectedToDaemon()); + + // set daemon to invalid uri + await wallet.setDaemonConnection("abc123"); + assert(!await wallet.isConnectedToDaemon()); + + // attempt to sync + try { + await wallet.sync(); + throw new Error("Exception expected"); + } catch (e1: any) { + assert.equal(e1.message, "Wallet is not connected to daemon"); + } + } catch (e: any) { + err = e; + } + + // close wallet and throw if error occurred + if (wallet) await that.closeWallet(wallet); + if (err) throw err; + }); + + if (testConfig.testNonRelays) + it("Can use a connection manager", async function() { + let err; + let wallet: MoneroWallet | undefined = undefined; + try { + + // create connection manager with monerod connections + let connectionManager = new MoneroConnectionManager(); + let connection1 = new MoneroRpcConnection(await that.daemon.getRpcConnection()).setPriority(1); + let connection2 = new MoneroRpcConnection("localhost:48081").setPriority(2); + await connectionManager.setConnection(connection1); + await connectionManager.addConnection(connection2); + + // create wallet with connection manager + wallet = await that.createWallet(new MoneroWalletConfig().setServer("").setConnectionManager(connectionManager)); + assert.equal((await wallet.getDaemonConnection()).getUri(), (await that.daemon.getRpcConnection()).getUri()); + assert(await wallet.isConnectedToDaemon()); + + // set manager's connection + await connectionManager.setConnection(connection2); + await GenUtils.waitFor(TestUtils.AUTO_CONNECT_TIMEOUT_MS); + assert.equal((await wallet.getDaemonConnection()).getUri(), connection2.getUri()); + + // reopen wallet with connection manager + let path = await wallet.getPath(); + await that.closeWallet(wallet); + wallet = undefined; + wallet = await that.openWallet(new MoneroWalletConfig().setServer("").setConnectionManager(connectionManager).setPath(path)); + assert.equal((await wallet.getDaemonConnection()).getUri(), connection2.getUri()); + + // disconnect + await connectionManager.setConnection(undefined); + assert.equal(await wallet.getDaemonConnection(), undefined); + assert(!await wallet.isConnectedToDaemon()); + + // start polling connections + connectionManager.startPolling(TestUtils.SYNC_PERIOD_IN_MS); + + // test that wallet auto connects + await GenUtils.waitFor(TestUtils.AUTO_CONNECT_TIMEOUT_MS); + assert.equal((await wallet.getDaemonConnection()).getUri(), connection1.getUri()); + assert(await wallet.isConnectedToDaemon()); + + // test override with bad connection + wallet.addListener(new MoneroWalletListener()); + connectionManager.setAutoSwitch(false); + await connectionManager.setConnection("http://foo.bar.xyz"); + assert.equal((await wallet.getDaemonConnection()).getUri(), "http://foo.bar.xyz"); + assert.equal(false, await wallet.isConnectedToDaemon()); + await GenUtils.waitFor(5000); + assert.equal(false, await wallet.isConnectedToDaemon()); + + // set to another connection manager + let connectionManager2 = new MoneroConnectionManager(); + await connectionManager2.setConnection(connection2); + await wallet.setConnectionManager(connectionManager2); + assert.equal((await wallet.getDaemonConnection()).getUri(), connection2.getUri()); + + // unset connection manager + await wallet.setConnectionManager(); + assert.equal(await wallet.getConnectionManager(), undefined); + assert.equal((await wallet.getDaemonConnection()).getUri(), connection2.getUri()); + + // stop polling and close + connectionManager.stopPolling(); + } catch (e: any) { + err = e; + } + + // close wallet and throw if error occurred + if (wallet) await that.closeWallet(wallet); + if (err) throw err; + }); + + if (testConfig.testNonRelays) + it("Can get the seed as a mnemonic phrase", async function() { + let mnemonic = await that.wallet.getSeed(); + await MoneroUtils.validateMnemonic(mnemonic); + assert.equal(mnemonic, TestUtils.SEED); + }); + + if (testConfig.testNonRelays) + it("Can get the language of the seed", async function() { + let language = await that.wallet.getSeedLanguage(); + assert.equal(language, "English"); + }); + + if (testConfig.testNonRelays) + it("Can get a list of supported languages for the seed", async function() { + let languages = await that.getSeedLanguages(); + assert(Array.isArray(languages)); + assert(languages.length); + for (let language of languages) assert(language); + }); + + if (testConfig.testNonRelays) + it("Can get the private view key", async function() { + let privateViewKey = await that.wallet.getPrivateViewKey() + await MoneroUtils.validatePrivateViewKey(privateViewKey); + }); + + if (testConfig.testNonRelays) + it("Can get the private spend key", async function() { + let privateSpendKey = await that.wallet.getPrivateSpendKey() + await MoneroUtils.validatePrivateSpendKey(privateSpendKey); + }); + + if (testConfig.testNonRelays) + it("Can get the public view key", async function() { + let publicViewKey = await that.wallet.getPublicViewKey() + await MoneroUtils.validatePublicViewKey(publicViewKey); + }); + + if (testConfig.testNonRelays) + it("Can get the public spend key", async function() { + let publicSpendKey = await that.wallet.getPublicSpendKey() + await MoneroUtils.validatePublicSpendKey(publicSpendKey); + }); + + if (testConfig.testNonRelays) + it("Can get the primary address", async function() { + let primaryAddress = await that.wallet.getPrimaryAddress(); + await MoneroUtils.validateAddress(primaryAddress, TestUtils.NETWORK_TYPE); + assert.equal(primaryAddress, await that.wallet.getAddress(0, 0)); + }); + + if (testConfig.testNonRelays) + it("Can get the address of a subaddress at a specified account and subaddress index", async function() { + assert.equal((await that.wallet.getSubaddress(0, 0)).getAddress(), await that.wallet.getPrimaryAddress()); + for (let account of await that.wallet.getAccounts(true)) { + for (let subaddress of account.getSubaddresses()) { + assert.equal(await that.wallet.getAddress(account.getIndex(), subaddress.getIndex()), subaddress.getAddress()); + } + } + }); + + if (testConfig.testNonRelays) + it("Can get addresses out of range of used accounts and subaddresses", async function() { + await that.testGetSubaddressAddressOutOfRange(); + }); + + if (testConfig.testNonRelays) + it("Can get the account and subaddress indices of an address", async function() { + + // get last subaddress to test + let accounts = await that.wallet.getAccounts(true); + let accountIdx = accounts.length - 1; + let subaddressIdx = accounts[accountIdx].getSubaddresses().length - 1; + let address = await that.wallet.getAddress(accountIdx, subaddressIdx); + assert(address); + assert.equal(typeof address, "string"); + + // get address index + let subaddress = await that.wallet.getAddressIndex(address); + assert.equal(subaddress.getAccountIndex(), accountIdx); + assert.equal(subaddress.getIndex(), subaddressIdx); + + // test valid but unfound address + let nonWalletAddress = await TestUtils.getExternalWalletAddress(); + try { + subaddress = await that.wallet.getAddressIndex(nonWalletAddress); + throw new Error("fail"); + } catch (e: any) { + assert.equal(e.message, "Address doesn't belong to the wallet"); + } + + // test invalid address + try { + subaddress = await that.wallet.getAddressIndex("this is definitely not an address"); + throw new Error("fail"); + } catch (e: any) { + assert.equal(e.message, "Invalid address"); + } + }); + + if (testConfig.testNonRelays) + it("Can get an integrated address given a payment id", async function() { + + // save address for later comparison + let address = await that.wallet.getPrimaryAddress(); + + // test valid payment id + let paymentId = "03284e41c342f036"; + let integratedAddress = await that.wallet.getIntegratedAddress(undefined, paymentId); + assert.equal(integratedAddress.getStandardAddress(), address); + assert.equal(integratedAddress.getPaymentId(), paymentId); + + // test undefined payment id which generates a new one + integratedAddress = await that.wallet.getIntegratedAddress(); + assert.equal(integratedAddress.getStandardAddress(), address); + assert(integratedAddress.getPaymentId().length); + + // test with primary address + let primaryAddress = await that.wallet.getPrimaryAddress(); + integratedAddress = await that.wallet.getIntegratedAddress(primaryAddress, paymentId); + assert.equal(integratedAddress.getStandardAddress(), primaryAddress); + assert.equal(integratedAddress.getPaymentId(), paymentId); + + // test with subaddress + if ((await that.wallet.getSubaddresses(0)).length < 2) await that.wallet.createSubaddress(0); + let subaddress = (await that.wallet.getSubaddress(0, 1)).getAddress(); + try { + integratedAddress = await that.wallet.getIntegratedAddress(subaddress); + throw new Error("Getting integrated address from subaddress should have failed"); + } catch (e: any) { + assert.equal(e.message, "Subaddress shouldn't be used"); + } + + // test invalid payment id + let invalidPaymentId = "invalid_payment_id_123456"; + try { + integratedAddress = await that.wallet.getIntegratedAddress(undefined, invalidPaymentId); + throw new Error("Getting integrated address with invalid payment id " + invalidPaymentId + " should have thrown a RPC exception"); + } catch (e: any) { + //assert.equal(e.getCode(), -5); // TODO: error codes part of rpc only? + assert.equal(e.message, "Invalid payment ID: " + invalidPaymentId); + } + }); + + if (testConfig.testNonRelays) + it("Can decode an integrated address", async function() { + let integratedAddress = await that.wallet.getIntegratedAddress(undefined, "03284e41c342f036"); + let decodedAddress = await that.wallet.decodeIntegratedAddress(integratedAddress.toString()); + assert.deepEqual(decodedAddress, integratedAddress); + + // decode invalid address + try { + console.log(await that.wallet.decodeIntegratedAddress("bad address")); + throw new Error("Should have failed decoding bad address"); + } catch (err: any) { + assert.equal(err.message, "Invalid address"); + } + }); + + // TODO: test syncing from start height + if (testConfig.testNonRelays) + it("Can sync (without progress)", async function() { + let numBlocks = 100; + let chainHeight = await that.daemon.getHeight(); + assert(chainHeight >= numBlocks); + let result = await that.wallet.sync(chainHeight - numBlocks); // sync to end of chain + assert(result instanceof MoneroSyncResult); + assert(result.getNumBlocksFetched() >= 0); + assert.equal(typeof result.getReceivedMoney(), "boolean"); + }); + + if (testConfig.testNonRelays) + it("Can get the current height that the wallet is synchronized to", async function() { + let height = await that.wallet.getHeight(); + assert(height >= 0); + }); + + if (testConfig.testNonRelays) + it("Can get a blockchain height by date", async function() { + + // collect dates to test starting 100 days ago + const DAY_MS = 24 * 60 * 60 * 1000; + let yesterday = new Date(new Date().getTime() - DAY_MS); // TODO monero-project: today's date can throw exception as "in future" so we test up to yesterday + let dates: any = []; + for (let i = 99; i >= 0; i--) { + dates.push(new Date(yesterday.getTime() - DAY_MS * i)); // subtract i days + } + + // test heights by date + let lastHeight: number | undefined = undefined; + for (let date of dates) { + let height = await that.wallet.getHeightByDate(date.getYear() + 1900, date.getMonth() + 1, date.getDate()); + assert(height >= 0); + if (lastHeight != undefined) assert(height >= lastHeight); + lastHeight = height; + } + assert(lastHeight! >= 0); + let height = await that.wallet.getHeight(); + assert(height >= 0); + + // test future date + try { + let tomorrow = new Date(yesterday.getTime() + DAY_MS * 2); + await that.wallet.getHeightByDate(tomorrow.getFullYear(), tomorrow.getMonth() + 1, tomorrow.getDate()); + throw new Error("Expected exception on future date"); + } catch (err: any) { + assert.equal(err.message, "specified date is in the future"); + } + }); + + if (testConfig.testNonRelays) + it("Can get the locked and unlocked balances of the wallet, accounts, and subaddresses", async function() { + + // fetch accounts with all info as reference + let accounts = await that.wallet.getAccounts(true); + + // test that balances add up between accounts and wallet + let accountsBalance = BigInt(0); + let accountsUnlockedBalance = BigInt(0); + for (let account of accounts) { + accountsBalance = accountsBalance + (account.getBalance()); + accountsUnlockedBalance = accountsUnlockedBalance + (account.getUnlockedBalance()); + + // test that balances add up between subaddresses and accounts + let subaddressesBalance = BigInt(0); + let subaddressesUnlockedBalance = BigInt(0); + for (let subaddress of account.getSubaddresses()) { + subaddressesBalance = subaddressesBalance + (subaddress.getBalance()); + subaddressesUnlockedBalance = subaddressesUnlockedBalance + (subaddress.getUnlockedBalance()); + + // test that balances are consistent with getAccounts() call + assert.equal((await that.wallet.getBalance(subaddress.getAccountIndex(), subaddress.getIndex())).toString(), subaddress.getBalance().toString()); + assert.equal((await that.wallet.getUnlockedBalance(subaddress.getAccountIndex(), subaddress.getIndex())).toString(), subaddress.getUnlockedBalance().toString()); + } + assert.equal((await that.wallet.getBalance(account.getIndex())).toString(), subaddressesBalance.toString()); + assert.equal((await that.wallet.getUnlockedBalance(account.getIndex())).toString(), subaddressesUnlockedBalance.toString()); + } + TestUtils.testUnsignedBigInt(accountsBalance); + TestUtils.testUnsignedBigInt(accountsUnlockedBalance); + assert.equal((await that.wallet.getBalance()).toString(), accountsBalance.toString()); + assert.equal((await that.wallet.getUnlockedBalance()).toString(), accountsUnlockedBalance.toString()); + + // test invalid input + try { + await that.wallet.getBalance(undefined, 0); + throw new Error("Should have failed"); + } catch (e: any) { + assert.notEqual(e.message, "Should have failed"); + } + }); + + if (testConfig.testNonRelays) + it("Can get accounts without subaddresses", async function() { + let accounts = await that.wallet.getAccounts(); + assert(accounts.length > 0); + accounts.map(async (account) => { + await testAccount(account) + assert(account.getSubaddresses() === undefined); + }); + }); + + if (testConfig.testNonRelays) + it("Can get accounts with subaddresses", async function() { + let accounts = await that.wallet.getAccounts(true); + assert(accounts.length > 0); + accounts.map(async (account) => { + await testAccount(account); + assert(account.getSubaddresses().length > 0); + }); + }); + + if (testConfig.testNonRelays) + it("Can get an account at a specified index", async function() { + let accounts = await that.wallet.getAccounts(); + assert(accounts.length > 0); + for (let account of accounts) { + await testAccount(account); + + // test without subaddresses + let retrieved = await that.wallet.getAccount(account.getIndex()); + assert(retrieved.getSubaddresses() === undefined); + + // test with subaddresses + retrieved = await that.wallet.getAccount(account.getIndex(), true); + assert(retrieved.getSubaddresses().length > 0); + } + }); + + if (testConfig.testNonRelays) + it("Can create a new account without a label", async function() { + let accountsBefore = await that.wallet.getAccounts(); + let createdAccount = await that.wallet.createAccount(); + await testAccount(createdAccount); + assert.equal((await that.wallet.getAccounts()).length - 1, accountsBefore.length); + }); + + if (testConfig.testNonRelays) + it("Can create a new account with a label", async function() { + + // create account with label + let accountsBefore = await that.wallet.getAccounts(); + let label = GenUtils.getUUID(); + let createdAccount = await that.wallet.createAccount(label); + await testAccount(createdAccount); + assert.equal((await that.wallet.getAccounts()).length - 1, accountsBefore.length); + assert.equal((await that.wallet.getSubaddress(createdAccount.getIndex(), 0)).getLabel(), label); + + // fetch and test account + createdAccount = await that.wallet.getAccount(createdAccount.getIndex()); + await testAccount(createdAccount); + + // create account with same label + createdAccount = await that.wallet.createAccount(label); + await testAccount(createdAccount); + assert.equal((await that.wallet.getAccounts()).length - 2, accountsBefore.length); + assert.equal((await that.wallet.getSubaddress(createdAccount.getIndex(), 0)).getLabel(), label); + + // fetch and test account + createdAccount = await that.wallet.getAccount(createdAccount.getIndex()); + await testAccount(createdAccount); + }); + + if (testConfig.testNonRelays) + it("Can set account labels", async function() { + + // create account + if ((await that.wallet.getAccounts()).length < 2) await that.wallet.createAccount(); + + // set account label + const label = GenUtils.getUUID(); + await that.wallet.setAccountLabel(1, label); + assert.equal((await that.wallet.getSubaddress(1, 0)).getLabel(), label); + }); + + if (testConfig.testNonRelays) + it("Can get subaddresses at a specified account index", async function() { + let accounts = await that.wallet.getAccounts(); + assert(accounts.length > 0); + for (let account of accounts) { + let subaddresses = await that.wallet.getSubaddresses(account.getIndex()); + assert(subaddresses.length > 0); + subaddresses.map(subaddress => { + testSubaddress(subaddress); + assert(account.getIndex() === subaddress.getAccountIndex()); + }); + } + }); + + if (testConfig.testNonRelays) + it("Can get subaddresses at specified account and subaddress indices", async function() { + let accounts = await that.wallet.getAccounts(); + assert(accounts.length > 0); + for (let account of accounts) { + + // get subaddresses + let subaddresses = await that.wallet.getSubaddresses(account.getIndex()); + assert(subaddresses.length > 0); + + // remove a subaddress for query if possible + if (subaddresses.length > 1) subaddresses.splice(0, 1); + + // get subaddress indices + let subaddressIndices = subaddresses.map(subaddress => subaddress.getIndex()); + assert(subaddressIndices.length > 0); + + // fetch subaddresses by indices + let fetchedSubaddresses = await that.wallet.getSubaddresses(account.getIndex(), subaddressIndices); + + // original subaddresses (minus one removed if applicable) is equal to fetched subaddresses + assert.deepEqual(fetchedSubaddresses, subaddresses); + } + }); + + if (testConfig.testNonRelays) + it("Can get a subaddress at a specified account and subaddress index", async function() { + let accounts = await that.wallet.getAccounts(); + assert(accounts.length > 0); + for (let account of accounts) { + let subaddresses = await that.wallet.getSubaddresses(account.getIndex()); + assert(subaddresses.length > 0); + for (let subaddress of subaddresses) { + testSubaddress(subaddress); + assert.deepEqual(await that.wallet.getSubaddress(account.getIndex(), subaddress.getIndex()), subaddress); + assert.deepEqual((await that.wallet.getSubaddresses(account.getIndex(), [subaddress.getIndex()]))[0], subaddress); // test plural call with single subaddr number + } + } + }); + + if (testConfig.testNonRelays) + it("Can create a subaddress with and without a label", async function() { + + // create subaddresses across accounts + let accounts = await that.wallet.getAccounts(); + if (accounts.length < 2) await that.wallet.createAccount(); + accounts = await that.wallet.getAccounts(); + assert(accounts.length > 1); + for (let accountIdx = 0; accountIdx < 2; accountIdx++) { + + // create subaddress with no label + let subaddresses = await that.wallet.getSubaddresses(accountIdx); + let subaddress = await that.wallet.createSubaddress(accountIdx); + assert.equal(subaddress.getLabel(), undefined); + testSubaddress(subaddress); + let subaddressesNew = await that.wallet.getSubaddresses(accountIdx); + assert.equal(subaddressesNew.length - 1, subaddresses.length); + assert.deepEqual(subaddressesNew[subaddressesNew.length - 1].toString(), subaddress.toString()); + + // create subaddress with label + subaddresses = await that.wallet.getSubaddresses(accountIdx); + let uuid = GenUtils.getUUID(); + subaddress = await that.wallet.createSubaddress(accountIdx, uuid); + assert.equal(uuid, subaddress.getLabel()); + testSubaddress(subaddress); + subaddressesNew = await that.wallet.getSubaddresses(accountIdx); + assert.equal(subaddressesNew.length - 1, subaddresses.length); + assert.deepEqual(subaddressesNew[subaddressesNew.length - 1].toString(), subaddress.toString()); + } + }); + + if (testConfig.testNonRelays) + it("Can set subaddress labels", async function() { + + // create subaddresses + while ((await that.wallet.getSubaddresses(0)).length < 3) await that.wallet.createSubaddress(0); + + // set subaddress labels + for (let subaddressIdx = 0; subaddressIdx < (await that.wallet.getSubaddresses(0)).length; subaddressIdx++) { + const label = GenUtils.getUUID(); + await that.wallet.setSubaddressLabel(0, subaddressIdx, label); + assert.equal((await that.wallet.getSubaddress(0, subaddressIdx)).getLabel(), label); + } + }); + + if (testConfig.testNonRelays) + it("Can get transactions in the wallet", async function() { + let nonDefaultIncoming = false; + let txs = await that.getAndTestTxs(that.wallet, undefined, true); + assert(txs.length > 0, "Wallet has no txs to test"); + assert.equal(txs[0].getHeight(), TestUtils.FIRST_RECEIVE_HEIGHT, "First tx's restore height must match the restore height in TestUtils"); + + // test each tranasction + let blocksPerHeight = {}; + for (let i = 0; i < txs.length; i++) { + await that.testTxWallet(txs[i], {wallet: that.wallet}); + await that.testTxWallet(txs[i], {wallet: that.wallet}); + assert.equal(txs[i].toString(), txs[i].toString()); + + // test merging equivalent txs + let copy1 = txs[i].copy(); + let copy2 = txs[i].copy(); + if (copy1.getIsConfirmed()) copy1.setBlock(txs[i].getBlock().copy().setTxs([copy1])); + if (copy2.getIsConfirmed()) copy2.setBlock(txs[i].getBlock().copy().setTxs([copy2])); + let merged = copy1.merge(copy2); + await that.testTxWallet(merged, {wallet: that.wallet}); + + // find non-default incoming + if (txs[i].getIncomingTransfers()) { + for (let transfer of txs[i].getIncomingTransfers()) { + if (transfer.getAccountIndex() !== 0 && transfer.getSubaddressIndex() !== 0) nonDefaultIncoming = true; + } + } + + // ensure unique block reference per height + if (txs[i].getIsConfirmed()) { + let block = blocksPerHeight[txs[i].getHeight()]; + if (block === undefined) blocksPerHeight[txs[i].getHeight()] = txs[i].getBlock(); + else assert(block === txs[i].getBlock(), "Block references for same height must be same"); + } + } + + // ensure non-default account and subaddress tested + assert(nonDefaultIncoming, "No incoming transfers found to non-default account and subaddress; run send-to-multiple tests first"); + }); + + if (testConfig.testNonRelays) + it("Can get transactions by hash", async function() { + + let maxNumTxs = 10; // max number of txs to test + + // fetch all txs for testing + let txs = await that.wallet.getTxs(); + assert(txs.length > 1, "Test requires at least 2 txs to fetch by hash"); + + // randomly pick a few for fetching by hash + GenUtils.shuffle(txs); + txs = txs.slice(0, Math.min(txs.length, maxNumTxs)); + + // test fetching by hash + let fetchedTx = await that.wallet.getTx(txs[0].getHash()); + assert.equal(fetchedTx.getHash(), txs[0].getHash()); + await that.testTxWallet(fetchedTx); + + // test fetching by hashes + let txId1 = txs[0].getHash(); + let txId2 = txs[1].getHash(); + let fetchedTxs = await that.wallet.getTxs([txId1, txId2]); + assert.equal(2, fetchedTxs.length); + + // test fetching by hashes as collection + let txHashes: any = []; + for (let tx of txs) txHashes.push(tx.getHash()); + fetchedTxs = await that.wallet.getTxs(txHashes); + assert.equal(fetchedTxs.length, txs.length); + for (let i = 0; i < txs.length; i++) { + assert.equal(fetchedTxs[i].getHash(), txs[i].getHash()); + await that.testTxWallet(fetchedTxs[i]); + } + + // test fetching with missing tx hashes + let missingTxHash = "d01ede9cde813b2a693069b640c4b99c5adbdb49fbbd8da2c16c8087d0c3e320"; + txHashes.push(missingTxHash); + fetchedTxs = await that.wallet.getTxs(txHashes); + assert.equal(txs.length, fetchedTxs.length); + for (let i = 0; i < txs.length; i++) { + assert.equal(txs[i].getHash(), fetchedTxs[i].getHash()); + await that.testTxWallet(fetchedTxs[i]); + } + }); + + if (testConfig.testNonRelays && !testConfig.liteMode) + it("Can get transactions with additional configuration", async function() { + + // get random transactions for testing + let randomTxs = await getRandomTransactions(that.wallet, undefined, 3, 5); + for (let randomTx of randomTxs) await that.testTxWallet(randomTx); + + // get transactions by hash + let txHashes: any = []; + for (let randomTx of randomTxs) { + txHashes.push(randomTx.getHash()); + let txs = await that.getAndTestTxs(that.wallet, {hash: randomTx.getHash()}, true); + assert.equal(txs.length, 1); + let merged = txs[0].merge(randomTx.copy()); // txs change with chain so check mergeability + await that.testTxWallet(merged); + } + + // get transactions by hashes + let txs = await that.getAndTestTxs(that.wallet, {hashes: txHashes}); + assert.equal(txs.length, randomTxs.length); + for (let tx of txs) assert(txHashes.includes(tx.getHash())); + + // get transactions with an outgoing transfer + txs = await that.getAndTestTxs(that.wallet, {isOutgoing: true}, true); + for (let tx of txs) { + assert(tx.getIsOutgoing()); + assert(tx.getOutgoingTransfer() instanceof MoneroTransfer); + await testTransfer(tx.getOutgoingTransfer()); + } + + // get transactions without an outgoing transfer + txs = await that.getAndTestTxs(that.wallet, {isOutgoing: false}, true); + for (let tx of txs) assert.equal(tx.getOutgoingTransfer(), undefined); + + // get transactions with incoming transfers + txs = await that.getAndTestTxs(that.wallet, {isIncoming: true}, true); + for (let tx of txs) { + assert(tx.getIncomingTransfers().length > 0); + for (let transfer of tx.getIncomingTransfers()) assert(transfer instanceof MoneroTransfer); + } + + // get transactions without incoming transfers + txs = await that.getAndTestTxs(that.wallet, {isIncoming: false}, true); + for (let tx of txs) assert.equal(tx.getIncomingTransfers(), undefined); + + // get transactions associated with an account + let accountIdx = 1; + txs = await that.wallet.getTxs({transferQuery: {accountIndex: accountIdx}}); + for (let tx of txs) { + let found = false; + if (tx.getOutgoingTransfer() && tx.getOutgoingTransfer().getAccountIndex() === accountIdx) found = true; + else if (tx.getIncomingTransfers()) { + for (let transfer of tx.getIncomingTransfers()) { + if (transfer.getAccountIndex() === accountIdx) { + found = true; + break; + } + } + } + assert(found, ("Transaction is not associated with account " + accountIdx + ":\n" + tx.toString())); + } + + // get transactions with incoming transfers to an account + txs = await that.wallet.getTxs({transferQuery: {isIncoming: true, accountIndex: accountIdx}}); + for (let tx of txs) { + assert(tx.getIncomingTransfers().length > 0); + let found = false; + for (let transfer of tx.getIncomingTransfers()) { + if (transfer.getAccountIndex() === accountIdx) { + found = true; + break; + } + } + assert(found, "No incoming transfers to account " + accountIdx + " found:\n" + tx.toString()); + } + + // get txs with manually built query that are confirmed and have an outgoing transfer from account 0 + let txQuery = new MoneroTxQuery(); + txQuery.setIsConfirmed(true); + txQuery.setTransferQuery(new MoneroTransferQuery().setAccountIndex(0).setIsOutgoing(true)); + txs = await that.getAndTestTxs(that.wallet, txQuery, true); + for (let tx of txs) { + if (!tx.getIsConfirmed()) console.log(tx.toString()); + assert.equal(tx.getIsConfirmed(), true); + assert(tx.getOutgoingTransfer()); + assert.equal(tx.getOutgoingTransfer().getAccountIndex(), 0); + } + + // get txs with outgoing transfers that have destinations to account 1 + txs = await that.getAndTestTxs(that.wallet, {transferQuery: {hasDestinations: true, accountIndex: 0}}); + for (let tx of txs) { + assert(tx.getOutgoingTransfer()); + assert(tx.getOutgoingTransfer().getDestinations().length > 0); + } + + // include outputs with transactions + txs = await that.getAndTestTxs(that.wallet, {includeOutputs: true}, true); + let found = false; + for (let tx of txs) { + if (tx.getOutputs()) { + assert(tx.getOutputs().length > 0); + found = true; + } else { + assert(tx.getIsOutgoing() || (tx.getIsIncoming() && !tx.getIsConfirmed())); // TODO: monero-wallet-rpc: return outputs for unconfirmed txs + } + } + assert(found, "No outputs found in txs"); + + // get txs with input query // TODO: no inputs returned to filter + + // get txs with output query + let outputQuery = new MoneroOutputQuery().setIsSpent(false).setAccountIndex(1).setSubaddressIndex(2); + txs = await that.wallet.getTxs(new MoneroTxQuery().setOutputQuery(outputQuery)); + assert(txs.length > 0); + for (let tx of txs) { + assert(tx.getOutputs().length > 0); + found = false; + for (let output of tx.getOutputsWallet()) { + if (output.getIsSpent() === false && output.getAccountIndex() === 1 && output.getSubaddressIndex() === 2) { + found = true; + break; + } + } + if (!found) throw new Error("Tx does not contain specified output"); + } + + // get unlocked txs + txs = await that.wallet.getTxs(new MoneroTxQuery().setIsLocked(false)); + assert(txs.length > 0); + for (let tx of txs) { + assert.equal(tx.getIsLocked(), false); + } + + // get confirmed transactions sent from/to same wallet with a transfer with destinations + txs = await that.wallet.getTxs({isIncoming: true, isOutgoing: true, isConfirmed: true, includeOutputs: true, transferQuery: { hasDestinations: true }}); + for (let tx of txs) { + assert(tx.getIsIncoming()); + assert(tx.getIsOutgoing()); + assert(tx.getIsConfirmed()); + assert(tx.getOutputs().length > 0); + assert.notEqual(tx.getOutgoingTransfer(), undefined); + assert.notEqual(tx.getOutgoingTransfer().getDestinations(), undefined); + assert(tx.getOutgoingTransfer().getDestinations().length > 0); + } + }); + + if (testConfig.testNonRelays) + it("Can get transactions by height", async function() { + + // get all confirmed txs for testing + let txs = await that.getAndTestTxs(that.wallet, new MoneroTxQuery().setIsConfirmed(true)); + assert(txs.length > 0, "Wallet has no confirmed txs; run send tests"); + + // collect all tx heights + let txHeights: any = []; + for (let tx of txs) txHeights.push(tx.getHeight()); + + // get height that most txs occur at + let heightCounts = countNumInstances(txHeights); + let heightModes = getModes(heightCounts); + let modeHeight = heightModes.values().next().value as number; + + // fetch txs at mode height + let modeTxs = await that.getAndTestTxs(that.wallet, new MoneroTxQuery().setHeight(modeHeight)); + assert.equal(modeTxs.length, heightCounts.get(modeHeight)); + + // fetch txs at mode height by range + let modeTxsByRange = await that.getAndTestTxs(that.wallet, new MoneroTxQuery().setMinHeight(modeHeight).setMaxHeight(modeHeight)); + assert.equal(modeTxsByRange.length, modeTxs.length); + assert.deepEqual(modeTxsByRange, modeTxs); + + // fetch all txs by range + let fetched = await that.getAndTestTxs(that.wallet, new MoneroTxQuery().setMinHeight(txs[0].getHeight()).setMaxHeight(txs[txs.length - 1].getHeight())); + assert.deepEqual(txs, fetched); + + // test some filtered by range // TODO: these are separated in Java? + { + txs = await that.wallet.getTxs({isConfirmed: true}); + assert(txs.length > 0, "No transactions; run send to multiple test"); + + // get and sort block heights in ascending order + let heights: any = []; + for (let tx of txs) { + heights.push(tx.getBlock().getHeight()); + } + GenUtils.sort(heights); + + // pick minimum and maximum heights for filtering + let minHeight = -1; + let maxHeight = -1; + if (heights.length == 1) { + minHeight = 0; + maxHeight = heights[0] - 1; + } else { + minHeight = heights[0] + 1; + maxHeight = heights[heights.length - 1] - 1; + } + + // assert some transactions filtered + let unfilteredCount = txs.length; + txs = await that.getAndTestTxs(that.wallet, {minHeight: minHeight, maxHeight: maxHeight}, true); + assert(txs.length < unfilteredCount); + for (let tx of txs) { + let height = tx.getBlock().getHeight(); + assert(height >= minHeight && height <= maxHeight); + } + } + }); + + if (testConfig.testNonRelays) + it("Can get transactions by payment ids", async function() { + + // get random transactions with payment hashes for testing + let randomTxs = await getRandomTransactions(that.wallet, {hasPaymentId: true}, 2, 5); + for (let randomTx of randomTxs) { + assert(randomTx.getPaymentId()); + } + + // get transactions by payment id + let paymentIds = randomTxs.map(tx => tx.getPaymentId()); + assert(paymentIds.length > 1); + for (let paymentId of paymentIds) { + let txs = await that.getAndTestTxs(that.wallet, {paymentId: paymentId}); + assert(txs.length > 0); + assert(txs[0].getPaymentId()); + await MoneroUtils.validatePaymentId(txs[0].getPaymentId()); + } + + // get transactions by payment hashes + let txs = await that.getAndTestTxs(that.wallet, {paymentIds: paymentIds}); + for (let tx of txs) { + assert(paymentIds.includes(tx.getPaymentId())); + } + }); + + if (testConfig.testNonRelays) + it("Returns all known fields of txs regardless of filtering", async function() { + + // fetch wallet txs + let txs = await that.wallet.getTxs({isConfirmed: true}); + for (let tx of txs) { + + // find tx sent to same wallet with incoming transfer in different account than src account + if (!tx.getOutgoingTransfer() || !tx.getIncomingTransfers()) continue; + for (let transfer of tx.getIncomingTransfers()) { + if (transfer.getAccountIndex() === tx.getOutgoingTransfer().getAccountIndex()) continue; + + // fetch tx with filtering + let filteredTxs = await that.wallet.getTxs({transferQuery: {isIncoming: true, accountIndex: transfer.getAccountIndex()}}); + let filteredTx = Filter.apply(new MoneroTxQuery().setHashes([tx.getHash()]), filteredTxs)[0]; + + // txs should be the same (mergeable) + assert.equal(filteredTx.getHash(), tx.getHash()); + tx.merge(filteredTx); + + // test is done + return; + } + } + + // test did not fully execute + throw new Error("Test requires tx sent from/to different accounts of same wallet but none found; run send tests"); + }); + + if (testConfig.testNonRelays && !testConfig.liteMode) + it("Validates inputs when getting transactions", async function() { + + // fetch random txs for testing + let randomTxs = await getRandomTransactions(that.wallet, undefined, 3, 5); + + // valid, invalid, and unknown tx hashes for tests + let txHash = randomTxs[0].getHash(); + let invalidHash = "invalid_id"; + let unknownHash1 = "6c4982f2499ece80e10b627083c4f9b992a00155e98bcba72a9588ccb91d0a61"; + let unknownHash2 = "ff397104dd875882f5e7c66e4f852ee134f8cf45e21f0c40777c9188bc92e943"; + + // fetch unknown tx hash + assert.equal(await that.wallet.getTx(unknownHash1), undefined); + + // fetch unknown tx hash using query + let txs = await that.wallet.getTxs(new MoneroTxQuery().setHash(unknownHash1)); + assert.equal(txs.length, 0); + + // fetch unknown tx hash in collection + txs = await that.wallet.getTxs([txHash, unknownHash1]); + assert.equal(txs.length, 1); + assert.equal(txs[0].getHash(), txHash); + + // fetch unknown tx hashes in collection + txs = await that.wallet.getTxs([txHash, unknownHash1, unknownHash2]); + assert.equal(txs.length, 1); + assert.equal(txs[0].getHash(), txHash); + + // fetch invalid hash + assert.equal(await that.wallet.getTx(invalidHash), undefined); + + // fetch invalid hash collection + txs = await that.wallet.getTxs([txHash, invalidHash]); + assert.equal(txs.length, 1); + assert.equal(txs[0].getHash(), txHash); + + // fetch invalid hashes in collection + txs = await that.wallet.getTxs([txHash, invalidHash, "invalid_hash_2"]); + assert.equal(txs.length, 1); + assert.equal(txs[0].getHash(), txHash); + + // test collection of invalid hashes + txs = await that.wallet.getTxs(new MoneroTxQuery().setHashes([txHash, invalidHash, "invalid_hash_2"])); + assert.equal(1, txs.length); + for (let tx of txs) await that.testTxWallet(tx); + }); + + if (testConfig.testNonRelays) + it("Can get transfers in the wallet, accounts, and subaddresses", async function() { + + // get all transfers + await that.getAndTestTransfers(that.wallet, undefined, true); + + // get transfers by account index + let nonDefaultIncoming = false; + for (let account of await that.wallet.getAccounts(true)) { + let accountTransfers = await that.getAndTestTransfers(that.wallet, {accountIndex: account.getIndex()}); + for (let transfer of accountTransfers) assert.equal(transfer.getAccountIndex(), account.getIndex()); + + // get transfers by subaddress index + let subaddressTransfers: MoneroTransfer[] = []; + for (let subaddress of account.getSubaddresses()) { + let transfers = await that.getAndTestTransfers(that.wallet, {accountIndex: subaddress.getAccountIndex(), subaddressIndex: subaddress.getIndex()}); + for (let transfer of transfers) { + + // test account and subaddress indices + assert.equal(transfer.getAccountIndex(), subaddress.getAccountIndex()); + if (transfer.getIsIncoming()) { + const inTransfer = transfer as MoneroIncomingTransfer; + assert.equal(inTransfer.getSubaddressIndex(), subaddress.getIndex()); + if (transfer.getAccountIndex() !== 0 && inTransfer.getSubaddressIndex() !== 0) nonDefaultIncoming = true; + } else { + const outTransfer = transfer as MoneroOutgoingTransfer; + assert(outTransfer.getSubaddressIndices().includes(subaddress.getIndex())); + if (outTransfer.getAccountIndex() !== 0) { + for (let subaddrIdx of outTransfer.getSubaddressIndices()) { + if (subaddrIdx > 0) { + nonDefaultIncoming = true; + break; + } + } + } + } + + // don't add duplicates TODO monero-wallet-rpc: duplicate outgoing transfers returned for different subaddress indices, way to return outgoing subaddress indices? + let found = false; + for (let subaddressTransfer of subaddressTransfers) { + if (transfer.toString() === subaddressTransfer.toString() && transfer.getTx().getHash() === subaddressTransfer.getTx().getHash()) { + found = true; + break; + } + } + if (!found) subaddressTransfers.push(transfer); + } + } + assert.equal(subaddressTransfers.length, accountTransfers.length); + + // collect unique subaddress indices + let subaddressIndices = new Set(); + for (let transfer of subaddressTransfers) { + if (transfer.getIsIncoming()) subaddressIndices.add((transfer as MoneroIncomingTransfer).getSubaddressIndex()); + else for (let subaddressIdx of (transfer as MoneroOutgoingTransfer).getSubaddressIndices()) subaddressIndices.add(subaddressIdx); + } + + // get and test transfers by subaddress indices + let transfers = await that.getAndTestTransfers(that.wallet, new MoneroTransferQuery().setAccountIndex(account.getIndex()).setSubaddressIndices(Array.from(subaddressIndices) as number[])); + //if (transfers.length !== subaddressTransfers.length) console.log("WARNING: outgoing transfers always from subaddress 0 (monero-wallet-rpc #5171)"); + assert.equal(transfers.length, subaddressTransfers.length); // TODO monero-wallet-rpc: these may not be equal because outgoing transfers are always from subaddress 0 (#5171) and/or incoming transfers from/to same account are occluded (#4500) + for (let transfer of transfers) { + assert.equal(account.getIndex(), transfer.getAccountIndex()); + if (transfer.getIsIncoming()) assert(subaddressIndices.has((transfer as MoneroIncomingTransfer).getSubaddressIndex())); + else { + let overlaps = false; + for (let subaddressIdx of subaddressIndices) { + for (let outSubaddressIdx of (transfer as MoneroOutgoingTransfer).getSubaddressIndices()) { + if (subaddressIdx === outSubaddressIdx) { + overlaps = true; + break; + } + } + } + assert(overlaps, "Subaddresses must overlap"); + } + } + } + + // ensure transfer found with non-zero account and subaddress indices + assert(nonDefaultIncoming, "No transfers found in non-default account and subaddress; run send-to-multiple tests"); + }); + + if (testConfig.testNonRelays && !testConfig.liteMode) + it("Can get transfers with additional configuration", async function() { + + // get incoming transfers + let transfers = await that.getAndTestTransfers(that.wallet, {isIncoming: true}, true); + for (let transfer of transfers) assert(transfer.getIsIncoming()); + + // get outgoing transfers + transfers = await that.getAndTestTransfers(that.wallet, {isIncoming: false}, true); + for (let transfer of transfers) assert(transfer.getIsOutgoing()); + + // get confirmed transfers to account 0 + transfers = await that.getAndTestTransfers(that.wallet, {accountIndex: 0, txQuery: {isConfirmed: true}}, true); + for (let transfer of transfers) { + assert.equal(transfer.getAccountIndex(), 0); + assert(transfer.getTx().getIsConfirmed()); + } + + // get confirmed transfers to [1, 2] + transfers = await that.getAndTestTransfers(that.wallet, {accountIndex: 1, subaddressIndex: 2, txQuery: {isConfirmed: true}}, true); + for (let transfer of transfers) { + assert.equal(transfer.getAccountIndex(), 1); + if (transfer.getIsIncoming()) assert.equal((transfer as MoneroIncomingTransfer).getSubaddressIndex(), 2); + else assert((transfer as MoneroOutgoingTransfer).getSubaddressIndices().includes(2)); + assert(transfer.getTx().getIsConfirmed()); + } + + // get transfers in the tx pool + transfers = await that.getAndTestTransfers(that.wallet, {txQuery: {inTxPool: true}}); + for (let transfer of transfers) { + assert.equal(transfer.getTx().getInTxPool(), true); + } + + // get random transactions + let txs = await getRandomTransactions(that.wallet, undefined, 3, 5); + + // get transfers with a tx hash + let txHashes: any = []; + for (let tx of txs) { + txHashes.push(tx.getHash()); + transfers = await that.getAndTestTransfers(that.wallet, {txQuery: {hash: tx.getHash()}}, true); + for (let transfer of transfers) assert.equal(transfer.getTx().getHash(), tx.getHash()); + } + + // get transfers with tx hashes + transfers = await that.getAndTestTransfers(that.wallet, {txQuery: {hashes: txHashes}}, true); + for (let transfer of transfers) assert(txHashes.includes(transfer.getTx().getHash())); + + // TODO: test that transfers with the same tx hash have the same tx reference + + // TODO: test transfers destinations + + // get transfers with pre-built query that are confirmed and have outgoing destinations + let transferQuery = new MoneroTransferQuery(); + transferQuery.setIsOutgoing(true); + transferQuery.setHasDestinations(true); + transferQuery.setTxQuery(new MoneroTxQuery().setIsConfirmed(true)); + transfers = await that.getAndTestTransfers(that.wallet, transferQuery); + for (let transfer of transfers) { + assert.equal(transfer.getIsOutgoing(), true); + assert((transfer as MoneroOutgoingTransfer).getDestinations().length > 0); + assert.equal(transfer.getTx().getIsConfirmed(), true); + } + + // get incoming transfers to account 0 which has outgoing transfers (i.e. originated from the same wallet) + transfers = await that.wallet.getTransfers({accountIndex: 1, isIncoming: true, txQuery: {isOutgoing: true}}) + assert(transfers.length > 0); + for (let transfer of transfers) { + assert(transfer.getIsIncoming()); + assert.equal(transfer.getAccountIndex(), 1); + assert(transfer.getTx().getIsOutgoing()); + assert.equal(transfer.getTx().getOutgoingTransfer(), undefined); + } + + // get incoming transfers to a specific address + let subaddress = await that.wallet.getAddress(1, 0); + transfers = await that.wallet.getTransfers({isIncoming: true, address: subaddress}); + assert(transfers.length > 0); + for (let transfer of transfers) { + assert(transfer instanceof MoneroIncomingTransfer); + assert.equal(1, transfer.getAccountIndex()); + assert.equal(0, transfer.getSubaddressIndex()); + assert.equal(subaddress, transfer.getAddress()); + } + }); + + if (testConfig.testNonRelays && !testConfig.liteMode) + it("Validates inputs when getting transfers", async function() { + + // test with invalid hash + let transfers = await that.wallet.getTransfers({txQuery: {hash: "invalid_id"}}); + assert.equal(transfers.length, 0); + + // test invalid hash in collection + let randomTxs = await getRandomTransactions(that.wallet, undefined, 3, 5); + transfers = await that.wallet.getTransfers({txQuery: {hashes: [randomTxs[0].getHash(), "invalid_id"]}}); + assert(transfers.length > 0); + let tx = transfers[0].getTx(); + for (let transfer of transfers) assert(tx === transfer.getTx()); + + // test unused subaddress indices + transfers = await that.wallet.getTransfers({accountIndex: 0, subaddressIndices: [1234907]}); + assert(transfers.length === 0); + + // test invalid subaddress index + try { + let transfers = await that.wallet.getTransfers({accountIndex: 0, subaddressIndex: -1}); + throw new Error("Should have failed"); + } catch (e: any) { + assert.notEqual(e.message, "Should have failed"); + } + }); + + if (testConfig.testNonRelays) + it("Can get incoming and outgoing transfers using convenience methods", async function() { + + // get incoming transfers + let inTransfers = await that.wallet.getIncomingTransfers(); + assert(inTransfers.length > 0); + for (let transfer of inTransfers) { + assert(transfer.getIsIncoming()); + await testTransfer(transfer, undefined); + } + + // get incoming transfers with query + let amount = inTransfers[0].getAmount(); + let accountIdx = inTransfers[0].getAccountIndex(); + let subaddressIdx = inTransfers[0].getSubaddressIndex(); + inTransfers = await that.wallet.getIncomingTransfers({amount: amount, accountIndex: accountIdx, subaddressIndex: subaddressIdx}); + assert(inTransfers.length > 0); + for (let transfer of inTransfers) { + assert(transfer.getIsIncoming()); + assert.equal(transfer.getAmount().toString(), amount.toString()); + assert.equal(transfer.getAccountIndex(), accountIdx); + assert.equal(transfer.getSubaddressIndex(), subaddressIdx); + await testTransfer(transfer, undefined); + } + + // get incoming transfers with contradictory query + try { + inTransfers = await that.wallet.getIncomingTransfers(new MoneroTransferQuery().setIsIncoming(false)); + } catch (e: any) { + assert.equal(e.message, "Transfer query contradicts getting incoming transfers"); + } + + // get outgoing transfers + let outTransfers = await that.wallet.getOutgoingTransfers(); + assert(outTransfers.length > 0); + for (let transfer of outTransfers) { + assert(transfer.getIsOutgoing()); + await testTransfer(transfer, undefined); + } + + // get outgoing transfers with query + outTransfers = await that.wallet.getOutgoingTransfers({accountIndex: accountIdx, subaddressIndex: subaddressIdx}); + assert(outTransfers.length > 0); + for (let transfer of outTransfers) { + assert(transfer.getIsOutgoing()); + assert.equal(transfer.getAccountIndex(), accountIdx); + assert(transfer.getSubaddressIndices().includes(subaddressIdx)); + await testTransfer(transfer, undefined); + } + + // get outgoing transfers with contradictory query + try { + outTransfers = await that.wallet.getOutgoingTransfers(new MoneroTransferQuery().setIsOutgoing(false)); + } catch (e: any) { + assert.equal(e.message, "Transfer query contradicts getting outgoing transfers"); + } + }); + + if (testConfig.testNonRelays) + it("Can get outputs in the wallet, accounts, and subaddresses", async function() { + + // get all outputs + await that.getAndTestOutputs(that.wallet, undefined, true); + + // get outputs for each account + let nonDefaultIncoming = false; + let accounts = await that.wallet.getAccounts(true); + for (let account of accounts) { + + // determine if account is used + let isUsed = false; + for (let subaddress of account.getSubaddresses()) if (subaddress.getIsUsed()) isUsed = true; + + // get outputs by account index + let accountOutputs = await that.getAndTestOutputs(that.wallet, {accountIndex: account.getIndex()}, isUsed); + for (let output of accountOutputs) assert.equal(output.getAccountIndex(), account.getIndex()); + + // get outputs by subaddress index + let subaddressOutputs: any[] = []; + for (let subaddress of account.getSubaddresses()) { + let outputs = await that.getAndTestOutputs(that.wallet, {accountIndex: account.getIndex(), subaddressIndex: subaddress.getIndex()}, subaddress.getIsUsed()); + for (let output of outputs) { + assert.equal(output.getAccountIndex(), subaddress.getAccountIndex()); + assert.equal(output.getSubaddressIndex(), subaddress.getIndex()); + if (output.getAccountIndex() !== 0 && output.getSubaddressIndex() !== 0) nonDefaultIncoming = true; + subaddressOutputs.push(output); + } + } + assert.equal(subaddressOutputs.length, accountOutputs.length); + + // get outputs by subaddress indices + let subaddressIndices = Array.from(new Set(subaddressOutputs.map(output => output.getSubaddressIndex()))); + let outputs = await that.getAndTestOutputs(that.wallet, {accountIndex: account.getIndex(), subaddressIndices: subaddressIndices}, isUsed); + assert.equal(outputs.length, subaddressOutputs.length); + for (let output of outputs) { + assert.equal(output.getAccountIndex(), account.getIndex()); + assert(subaddressIndices.includes(output.getSubaddressIndex())); + } + } + + // ensure output found with non-zero account and subaddress indices + assert(nonDefaultIncoming, "No outputs found in non-default account and subaddress; run send-to-multiple tests"); + }); + + if (testConfig.testNonRelays && !testConfig.liteMode) + it("Can get outputs with additional configuration", async function() { + + // get unspent outputs to account 0 + let outputs = await that.getAndTestOutputs(that.wallet, {accountIndex: 0, isSpent: false}); + for (let output of outputs) { + assert.equal(output.getAccountIndex(), 0); + assert.equal(output.getIsSpent(), false); + } + + // get spent outputs to account 1 + outputs = await that.getAndTestOutputs(that.wallet, {accountIndex: 1, isSpent: true}, true); + for (let output of outputs) { + assert.equal(output.getAccountIndex(), 1); + assert.equal(output.getIsSpent(), true); + } + + // get random transactions + let txs = await getRandomTransactions(that.wallet, {isConfirmed: true}, 3, 5); + + // get outputs with a tx hash + let txHashes: any = []; + for (let tx of txs) { + txHashes.push(tx.getHash()); + outputs = await that.getAndTestOutputs(that.wallet, {txQuery: {hash: tx.getHash()}}, true); + for (let output of outputs) assert.equal(output.getTx().getHash(), tx.getHash()); + } + + // get outputs with tx hashes + outputs = await that.getAndTestOutputs(that.wallet, {txQuery: {hashes: txHashes}}, true); + for (let output of outputs) assert(txHashes.includes(output.getTx().getHash())); + + // get confirmed outputs to specific subaddress with pre-built query + let accountIdx = 0; + let subaddressIdx = 1; + let query = new MoneroOutputQuery(); + query.setAccountIndex(accountIdx).setSubaddressIndex(subaddressIdx); + query.setTxQuery(new MoneroTxQuery().setIsConfirmed(true)); + query.setMinAmount(TestUtils.MAX_FEE); + outputs = await that.getAndTestOutputs(that.wallet, query, true); + for (let output of outputs) { + assert.equal(output.getAccountIndex(), accountIdx); + assert.equal(output.getSubaddressIndex(), subaddressIdx); + assert.equal(output.getTx().getIsConfirmed(), true); + assert(output.getAmount() >= TestUtils.MAX_FEE); + } + + // get output by key image + let keyImage = outputs[0].getKeyImage().getHex(); + outputs = await that.wallet.getOutputs(new MoneroOutputQuery().setKeyImage(new MoneroKeyImage(keyImage))); + assert.equal(outputs.length, 1); + assert.equal(outputs[0].getKeyImage().getHex(), keyImage); + + // get outputs whose transaction is confirmed and has incoming and outgoing transfers + outputs = await that.wallet.getOutputs({txQuery: {isConfirmed: true, isIncoming: true, isOutgoing: true, includeOutputs: true}}); + assert(outputs.length > 0); + for (let output of outputs) { + assert(output.getTx().getIsIncoming()); + assert(output.getTx().getIsOutgoing()); + assert(output.getTx().getIsConfirmed()); + assert(output.getTx().getOutputs().length > 0); + assert(GenUtils.arrayContains(output.getTx().getOutputs(), output, true)); + } + }); + + if (testConfig.testNonRelays && !testConfig.liteMode) + it("Validates inputs when getting outputs", async function() { + + // test with invalid hash + let outputs = await that.wallet.getOutputs({txQuery: {hash: "invalid_id"}}); + assert.equal(outputs.length, 0); + + // test invalid hash in collection + let randomTxs = await getRandomTransactions(that.wallet, {isConfirmed: true, includeOutputs: true}, 3, 5); + outputs = await that.wallet.getOutputs({txQuery: {hashes: [randomTxs[0].getHash(), "invalid_id"]}}); + assert(outputs.length > 0); + assert.equal(randomTxs[0].getOutputs().length, outputs.length); + let tx = outputs[0].getTx(); + for (let output of outputs) assert(tx === output.getTx()); + }); + + if (testConfig.testNonRelays) + it("Can export outputs in hex format", async function() { + let outputsHex = await that.wallet.exportOutputs(); + assert.equal(typeof outputsHex, "string"); // TODO: this will fail if wallet has no outputs; run these tests on new wallet + assert(outputsHex.length > 0); + + // wallet exports outputs since last export by default + outputsHex = await that.wallet.exportOutputs(); + let outputsHexAll = await that.wallet.exportOutputs(true); + assert(outputsHexAll.length > outputsHex.length); + }); + + if (testConfig.testNonRelays) + it("Can import outputs in hex format", async function() { + + // export outputs hex + let outputsHex = await that.wallet.exportOutputs(); + + // import outputs hex + if (outputsHex !== undefined) { + let numImported = await that.wallet.importOutputs(outputsHex); + assert(numImported >= 0); + } + }); + + if (testConfig.testNonRelays) + it("Has correct accounting across accounts, subaddresses, txs, transfers, and outputs", async function() { + + // pre-fetch wallet balances, accounts, subaddresses, and txs + let walletBalance = await that.wallet.getBalance(); + let walletUnlockedBalance = await that.wallet.getUnlockedBalance(); + let accounts = await that.wallet.getAccounts(true); // includes subaddresses + + // test wallet balance + TestUtils.testUnsignedBigInt(walletBalance); + TestUtils.testUnsignedBigInt(walletUnlockedBalance); + assert(walletBalance >= walletUnlockedBalance); + + // test that wallet balance equals sum of account balances + let accountsBalance = BigInt(0); + let accountsUnlockedBalance = BigInt(0); + for (let account of accounts) { + await testAccount(account); // test that account balance equals sum of subaddress balances + accountsBalance += account.getBalance(); + accountsUnlockedBalance += account.getUnlockedBalance(); + } + assert.equal(accountsBalance, walletBalance); + assert.equal(accountsUnlockedBalance, walletUnlockedBalance); + +// // test that wallet balance equals net of wallet's incoming and outgoing tx amounts +// // TODO monero-wallet-rpc: these tests are disabled because incoming transfers are not returned when sent from the same account, so doesn't balance #4500 +// // TODO: test unlocked balance based on txs, requires e.g. tx.getIsLocked() +// let outgoingSum = BigInt(0); +// let incomingSum = BigInt(0); +// for (let tx of txs) { +// if (tx.getOutgoingAmount()) outgoingSum = outgoingSum + (tx.getOutgoingAmount()); +// if (tx.getIncomingAmount()) incomingSum = incomingSum + (tx.getIncomingAmount()); +// } +// assert.equal(incomingSum - (outgoingSum).toString(), walletBalance.toString()); +// +// // test that each account's balance equals net of account's incoming and outgoing tx amounts +// for (let account of accounts) { +// if (account.getIndex() !== 1) continue; // find 1 +// outgoingSum = BigInt(0); +// incomingSum = BigInt(0); +// let filter = new MoneroTxQuery(); +// filter.setAccountIndex(account.getIndex()); +// for (let tx of txs.filter(tx => filter.meetsCriteria(tx))) { // normally we'd call wallet.getTxs(filter) but we're using pre-fetched txs +// if (tx.getHash() === "8d3919d98dd5a734da8c52eddc558db3fbf059ad55d432f0052ecd59ef122ecb") console.log(tx.toString(0)); +// +// //console.log((tx.getOutgoingAmount() ? tx.getOutgoingAmount().toString() : "") + ", " + (tx.getIncomingAmount() ? tx.getIncomingAmount().toString() : "")); +// if (tx.getOutgoingAmount()) outgoingSum = outgoingSum + (tx.getOutgoingAmount()); +// if (tx.getIncomingAmount()) incomingSum = incomingSum + (tx.getIncomingAmount()); +// } +// assert.equal(incomingSum - (outgoingSum).toString(), account.getBalance().toString()); +// } + + // balance may not equal sum of unspent outputs if unconfirmed txs + // TODO monero-wallet-rpc: reason not to return unspent outputs on unconfirmed txs? then this isn't necessary + let txs = await that.wallet.getTxs(); + let hasUnconfirmedTx = false; + for (let tx of txs) if (tx.getInTxPool()) hasUnconfirmedTx = true; + + // wallet balance is sum of all unspent outputs + let walletSum = BigInt(0); + for (let output of await that.wallet.getOutputs({isSpent: false})) walletSum = walletSum + (output.getAmount()); + if (walletBalance !== walletSum) { + + // txs may have changed in between calls so retry test + walletSum = BigInt(0); + for (let output of await that.wallet.getOutputs({isSpent: false})) walletSum = walletSum + (output.getAmount()); + if (walletBalance !== walletSum) assert(hasUnconfirmedTx, "Wallet balance must equal sum of unspent outputs if no unconfirmed txs"); + } + + // account balances are sum of their unspent outputs + for (let account of accounts) { + let accountSum = BigInt(0); + let accountOutputs = await that.wallet.getOutputs({accountIndex: account.getIndex(), isSpent: false}); + for (let output of accountOutputs) accountSum = accountSum + (output.getAmount()); + if (account.getBalance().toString() !== accountSum.toString()) assert(hasUnconfirmedTx, "Account balance must equal sum of its unspent outputs if no unconfirmed txs"); + + // subaddress balances are sum of their unspent outputs + for (let subaddress of account.getSubaddresses()) { + let subaddressSum = BigInt(0); + let subaddressOutputs = await that.wallet.getOutputs({accountIndex: account.getIndex(), subaddressIndex: subaddress.getIndex(), isSpent: false}); + for (let output of subaddressOutputs) subaddressSum = subaddressSum + (output.getAmount()); + if (subaddress.getBalance().toString() !== subaddressSum.toString()) assert(hasUnconfirmedTx, "Subaddress balance must equal sum of its unspent outputs if no unconfirmed txs"); + } + } + }); + + if (testConfig.testNonRelays) + it("Can get and set a transaction note", async function() { + let txs = await getRandomTransactions(that.wallet, undefined, 1, 5); + + // set notes + let uuid = GenUtils.getUUID(); + for (let i = 0; i < txs.length; i++) { + await that.wallet.setTxNote(txs[i].getHash(), uuid + i); + } + + // get notes + for (let i = 0; i < txs.length; i++) { + assert.equal(await that.wallet.getTxNote(txs[i].getHash()), uuid + i); + } + }); + + // TODO: why does getting cached txs take 2 seconds when should already be cached? + if (testConfig.testNonRelays) + it("Can get and set multiple transaction notes", async function() { + + // set tx notes + let uuid = GenUtils.getUUID(); + let txs = await that.wallet.getTxs(); + assert(txs.length >= 3, "Test requires 3 or more wallet transactions; run send tests"); + let txHashes: any = []; + let txNotes: any = []; + for (let i = 0; i < txHashes.length; i++) { + txHashes.push(txs[i].getHash()); + txNotes.push(uuid + i); + } + await that.wallet.setTxNotes(txHashes, txNotes); + + // get tx notes + txNotes = await that.wallet.getTxNotes(txHashes); + for (let i = 0; i < txHashes.length; i++) { + assert.equal(uuid + i, txNotes[i]); + } + + // TODO: test that get transaction has note + }); + + if (testConfig.testNonRelays) + it("Can check a transfer using the transaction's secret key and the destination", async function() { + + // wait for pool txs to confirm if no confirmed txs with destinations + if ((await that.wallet.getTxs({isConfirmed: true, isOutgoing: true, transferQuery: {hasDestinations: true}})).length === 0) { + TestUtils.WALLET_TX_TRACKER.reset(); + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + } + + // get random txs that are confirmed and have outgoing destinations + let txs; + try { + txs = await getRandomTransactions(that.wallet, {isConfirmed: true, isOutgoing: true, transferQuery: {hasDestinations: true}}, 1, MAX_TX_PROOFS); + } catch (e: any) { + if (e.message.indexOf("found with") >= 0) throw new Error("No txs with outgoing destinations found; run send tests") + throw e; + } + + // test good checks + assert(txs.length > 0, "No transactions found with outgoing destinations"); + for (let tx of txs) { + let key = await that.wallet.getTxKey(tx.getHash()); + assert(key, "No tx key returned for tx hash"); + assert(tx.getOutgoingTransfer().getDestinations().length > 0); + for (let destination of tx.getOutgoingTransfer().getDestinations()) { + let check = await that.wallet.checkTxKey(tx.getHash(), key, destination.getAddress()); + if (destination.getAmount() > 0n) { + // TODO monero-wallet-rpc: indicates amount received amount is 0 despite transaction with transfer to this address + // TODO monero-wallet-rpc: returns 0-4 errors, not consistent + //assert(check.getReceivedAmount() > 0n); + if (check.getReceivedAmount() === 0n) { + console.log("WARNING: key proof indicates no funds received despite transfer (txid=" + tx.getHash() + ", key=" + key + ", address=" + destination.getAddress() + ", amount=" + destination.getAmount() + ")"); + } + } + else assert(check.getReceivedAmount() === 0n); + testCheckTx(tx, check); + } + } + + // test get tx key with invalid hash + try { + await that.wallet.getTxKey("invalid_tx_id"); + throw new Error("Should throw exception for invalid key"); + } catch (e: any) { + that.testInvalidTxHashError(e); + } + + // test check with invalid tx hash + let tx = txs[0]; + let key = await that.wallet.getTxKey(tx.getHash()); + let destination = tx.getOutgoingTransfer().getDestinations()[0]; + try { + await that.wallet.checkTxKey("invalid_tx_id", key, destination.getAddress()); + throw new Error("Should have thrown exception"); + } catch (e: any) { + that.testInvalidTxHashError(e); + } + + // test check with invalid key + try { + await that.wallet.checkTxKey(tx.getHash(), "invalid_tx_key", destination.getAddress()); + throw new Error("Should have thrown exception"); + } catch (e: any) { + that.testInvalidTxKeyError(e); + } + + // test check with invalid address + try { + await that.wallet.checkTxKey(tx.getHash(), key, "invalid_tx_address"); + throw new Error("Should have thrown exception"); + } catch (e: any) { + that.testInvalidAddressError(e); + } + + // test check with different address + let differentAddress; + for (let aTx of await that.wallet.getTxs()) { + if (!aTx.getOutgoingTransfer() || !aTx.getOutgoingTransfer().getDestinations()) continue; + for (let aDestination of aTx.getOutgoingTransfer().getDestinations()) { + if (aDestination.getAddress() !== destination.getAddress()) { + differentAddress = aDestination.getAddress(); + break; + } + } + } + assert(differentAddress, "Could not get a different outgoing address to test; run send tests"); + let check = await that.wallet.checkTxKey(tx.getHash(), key, differentAddress); + assert(check.getIsGood()); + assert(check.getReceivedAmount() >= 0n); + testCheckTx(tx, check); + }); + + if (testConfig.testNonRelays) + it("Can prove a transaction by getting its signature", async function() { + + // get random txs with outgoing destinations + let txs; + try { + txs = await getRandomTransactions(that.wallet, {transferQuery: {hasDestinations: true}}, 2, MAX_TX_PROOFS); + } catch (e: any) { + if (e.message.indexOf("found with") >= 0) throw new Error("No txs with outgoing destinations found; run send tests") + throw e; + } + + // test good checks with messages + for (let tx of txs) { + for (let destination of tx.getOutgoingTransfer().getDestinations()) { + let signature = await that.wallet.getTxProof(tx.getHash(), destination.getAddress(), "This transaction definitely happened."); + assert(signature, "No signature returned from getTxProof()"); + let check = await that.wallet.checkTxProof(tx.getHash(), destination.getAddress(), "This transaction definitely happened.", signature); + testCheckTx(tx, check); + } + } + + // test good check without message + let tx = txs[0]; + let destination = tx.getOutgoingTransfer().getDestinations()[0]; + let signature = await that.wallet.getTxProof(tx.getHash(), destination.getAddress()); + let check = await that.wallet.checkTxProof(tx.getHash(), destination.getAddress(), undefined, signature); + testCheckTx(tx, check); + + // test get proof with invalid hash + try { + await that.wallet.getTxProof("invalid_tx_id", destination.getAddress()); + throw new Error("Should throw exception for invalid key"); + } catch (e: any) { + that.testInvalidTxHashError(e); + } + + // test check with invalid tx hash + try { + await that.wallet.checkTxProof("invalid_tx_id", destination.getAddress(), undefined, signature); + throw new Error("Should have thrown exception"); + } catch (e: any) { + that.testInvalidTxHashError(e); + } + + // test check with invalid address + try { + await that.wallet.checkTxProof(tx.getHash(), "invalid_tx_address", undefined, signature); + throw new Error("Should have thrown exception"); + } catch (e: any) { + that.testInvalidAddressError(e); + } + + // test check with wrong message + signature = await that.wallet.getTxProof(tx.getHash(), destination.getAddress(), "This is the right message"); + check = await that.wallet.checkTxProof(tx.getHash(), destination.getAddress(), "This is the wrong message", signature); + assert.equal(check.getIsGood(), false); + testCheckTx(tx, check); + + // test check with wrong signature + let wrongSignature = await that.wallet.getTxProof(txs[1].getHash(), txs[1].getOutgoingTransfer().getDestinations()[0].getAddress(), "This is the right message"); + try { + check = await that.wallet.checkTxProof(tx.getHash(), destination.getAddress(), "This is the right message", wrongSignature); + assert.equal(check.getIsGood(), false); + } catch (e: any) { + that.testInvalidSignatureError(e); + } + + // test check with empty signature + try { + check = await that.wallet.checkTxProof(tx.getHash(), destination.getAddress(), "This is the right message", ""); + assert.equal(check.getIsGood(), false); + } catch (e: any) { + assert.equal("Must provide signature to check tx proof", e.message); + } + }); + + if (testConfig.testNonRelays) + it("Can prove a spend using a generated signature and no destination public address", async function() { + + // get random confirmed outgoing txs + let txs = await getRandomTransactions(that.wallet, {isIncoming: false, inTxPool: false, isFailed: false}, 2, MAX_TX_PROOFS); + for (let tx of txs) { + assert.equal(tx.getIsConfirmed(), true); + assert.equal(tx.getIncomingTransfers(), undefined); + assert(tx.getOutgoingTransfer()); + } + + // test good checks with messages + for (let tx of txs) { + let signature = await that.wallet.getSpendProof(tx.getHash(), "I am a message."); + assert(signature, "No signature returned for spend proof"); + assert(await that.wallet.checkSpendProof(tx.getHash(), "I am a message.", signature)); + } + + // test good check without message + let tx = txs[0]; + let signature = await that.wallet.getSpendProof(tx.getHash()); + assert(await that.wallet.checkSpendProof(tx.getHash(), undefined, signature)); + + // test get proof with invalid hash + try { + await that.wallet.getSpendProof("invalid_tx_id"); + throw new Error("Should throw exception for invalid key"); + } catch (e: any) { + that.testInvalidTxHashError(e); + } + + // test check with invalid tx hash + try { + await that.wallet.checkSpendProof("invalid_tx_id", undefined, signature); + throw new Error("Should have thrown exception"); + } catch (e: any) { + that.testInvalidTxHashError(e); + } + + // test check with invalid message + signature = await that.wallet.getSpendProof(tx.getHash(), "This is the right message"); + assert.equal(await that.wallet.checkSpendProof(tx.getHash(), "This is the wrong message", signature), false); + + // test check with wrong signature + signature = await that.wallet.getSpendProof(txs[1].getHash(), "This is the right message"); + assert.equal(await that.wallet.checkSpendProof(tx.getHash(), "This is the right message", signature), false); + }); + + if (testConfig.testNonRelays) + it("Can prove reserves in the wallet", async function() { + + // get proof of entire wallet + let signature = await that.wallet.getReserveProofWallet("Test message"); + assert(signature, "No signature returned for wallet reserve proof"); + + // check proof of entire wallet + let check = await that.wallet.checkReserveProof(await that.wallet.getPrimaryAddress(), "Test message", signature); + assert(check.getIsGood()); + testCheckReserve(check); + let balance = await that.wallet.getBalance(); + if (balance !== check.getTotalAmount()) { // TODO monero-wallet-rpc: this check fails with unconfirmed txs + let unconfirmedTxs = await that.wallet.getTxs({inTxPool: true}); + assert(unconfirmedTxs.length > 0, "Reserve amount must equal balance unless wallet has unconfirmed txs"); + } + + // test different wallet address + let differentAddress = await TestUtils.getExternalWalletAddress(); + try { + await that.wallet.checkReserveProof(differentAddress, "Test message", signature); + throw new Error("Should have thrown exception"); + } catch (e: any) { + that.testNoSubaddressError(e); + } + + // test subaddress + try { + await that.wallet.checkReserveProof((await that.wallet.getSubaddress(0, 1)).getAddress(), "Test message", signature); + throw new Error("Should have thrown exception"); + } catch (e: any) { + that.testNoSubaddressError(e); + } + + // test wrong message + check = await that.wallet.checkReserveProof(await that.wallet.getPrimaryAddress(), "Wrong message", signature); + assert.equal(check.getIsGood(), false); // TODO: specifically test reserve checks, probably separate objects + testCheckReserve(check); + + // test wrong signature + try { + await that.wallet.checkReserveProof(await that.wallet.getPrimaryAddress(), "Test message", "wrong signature"); + throw new Error("Should have thrown exception"); + } catch (e: any) { + that.testSignatureHeaderCheckError(e); + } + }); + + if (testConfig.testNonRelays) + it("Can prove reserves in an account", async function() { + + // test proofs of accounts + let numNonZeroTests = 0; + let msg = "Test message"; + let accounts = await that.wallet.getAccounts(); + let signature; + for (let account of accounts) { + if (account.getBalance() > 0n) { + let checkAmount = (await account.getBalance()) / (BigInt(2)); + signature = await that.wallet.getReserveProofAccount(account.getIndex(), checkAmount, msg); + let check = await that.wallet.checkReserveProof(await that.wallet.getPrimaryAddress(), msg, signature); + assert(check.getIsGood()); + testCheckReserve(check); + assert (check.getTotalAmount() >= checkAmount); + numNonZeroTests++; + } else { + try { + await that.wallet.getReserveProofAccount(account.getIndex(), account.getBalance(), msg); + throw new Error("Should have thrown exception"); + } catch (e: any) { + assert.equal(e.getCode(), -1); + try { + await that.wallet.getReserveProofAccount(account.getIndex(), TestUtils.MAX_FEE, msg); + throw new Error("Should have thrown exception"); + } catch (e2: any) { + assert.equal(e2.getCode(), -1); + } + } + } + } + assert(numNonZeroTests > 1, "Must have more than one account with non-zero balance; run send-to-multiple tests"); + + // test error when not enough balance for requested minimum reserve amount + try { + let reserveProof = await that.wallet.getReserveProofAccount(0, accounts[0].getBalance() + (TestUtils.MAX_FEE), "Test message"); + throw new Error("should have thrown error"); + } catch (e: any) { + if (e.message === "should have thrown error") throw new Error("Should have thrown exception but got reserve proof: https://github.com/monero-project/monero/issues/6595"); + assert.equal(e.getCode(), -1); + } + + // test different wallet address + let differentAddress = await TestUtils.getExternalWalletAddress(); + try { + await that.wallet.checkReserveProof(differentAddress, "Test message", signature); + throw new Error("Should have thrown exception"); + } catch (e: any) { + assert.equal(e.getCode(), -1); + } + + // test subaddress + try { + await that.wallet.checkReserveProof((await that.wallet.getSubaddress(0, 1)).getAddress(), "Test message", signature); + throw new Error("Should have thrown exception"); + } catch (e: any) { + assert.equal(e.getCode(), -1); + } + + // test wrong message + let check = await that.wallet.checkReserveProof(await that.wallet.getPrimaryAddress(), "Wrong message", signature); + assert.equal(check.getIsGood(), false); // TODO: specifically test reserve checks, probably separate objects + testCheckReserve(check); + + // test wrong signature + try { + await that.wallet.checkReserveProof(await that.wallet.getPrimaryAddress(), "Test message", "wrong signature"); + throw new Error("Should have thrown exception"); + } catch (e: any) { + assert.equal(e.getCode(), -1); + } + }); + + if (testConfig.testNonRelays) + it("Can export key images", async function() { + let images = await that.wallet.exportKeyImages(true); + assert(Array.isArray(images)); + assert(images.length > 0, "No signed key images in wallet"); + for (let image of images) { + assert(image instanceof MoneroKeyImage); + assert(image.getHex()); + assert(image.getSignature()); + } + + // wallet exports key images since last export by default + images = await that.wallet.exportKeyImages(); + let imagesAll = await that.wallet.exportKeyImages(true); + assert(imagesAll.length > images.length); + }); + + if (testConfig.testNonRelays) + it("Can get new key images from the last import", async function() { + + // get outputs hex + let outputsHex = await that.wallet.exportOutputs(); + + // import outputs hex + if (outputsHex !== undefined) { + let numImported = await that.wallet.importOutputs(outputsHex); + assert(numImported >= 0); + } + + // get and test new key images from last import + let images = await that.wallet.getNewKeyImagesFromLastImport(); + assert(Array.isArray(images)); + assert(images.length > 0, "No new key images in last import"); // TODO: these are already known to the wallet, so no new key images will be imported + for (let image of images) { + assert(image.getHex()); + assert(image.getSignature()); + } + }); + + if (testConfig.testNonRelays && false) // TODO monero-project: importing key images can cause erasure of incoming transfers per wallet2.cpp:11957 + it("Can import key images", async function() { + let images = await that.wallet.exportKeyImages(); + assert(Array.isArray(images)); + assert(images.length > 0, "Wallet does not have any key images; run send tests"); + let result = await that.wallet.importKeyImages(images); + assert(result.getHeight() > 0); + + // determine if non-zero spent and unspent amounts are expected + let txs = await that.wallet.getTxs({isConfirmed: true, transferQuery: {isIncoming: false}}); + let balance = await that.wallet.getBalance(); + let hasSpent = txs.length > 0; + let hasUnspent = balance > 0n; + + // test amounts + TestUtils.testUnsignedBigInt(result.getSpentAmount(), hasSpent); + TestUtils.testUnsignedBigInt(result.getUnspentAmount(), hasUnspent); + }); + + if (testConfig.testNonRelays) + it("Can sign and verify messages", async function() { + + // message to sign and subaddresses to test + let msg = "This is a super important message which needs to be signed and verified."; + let subaddresses = [new MoneroSubaddress({accountIndex: 0, index: 0}), new MoneroSubaddress({accountIndex: 0, index: 1}), new MoneroSubaddress({accountIndex: 1, index: 0})]; + + // test signing message with subaddresses + for (let subaddress of subaddresses) { + + // sign and verify message with spend key + let signature = await that.wallet.signMessage(msg, MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY, subaddress.getAccountIndex(), subaddress.getIndex()); + let result = await that.wallet.verifyMessage(msg, await that.wallet.getAddress(subaddress.getAccountIndex(), subaddress.getIndex()), signature); + assert.deepEqual(result, new MoneroMessageSignatureResult({isGood: true, isOld: false, signatureType: MoneroMessageSignatureType.SIGN_WITH_SPEND_KEY, version: 2})); + + // verify message with incorrect address + result = await that.wallet.verifyMessage(msg, await that.wallet.getAddress(0, 2), signature); + assert.deepEqual(result, new MoneroMessageSignatureResult({isGood: false})); + + // verify message with external address + result = await that.wallet.verifyMessage(msg, await TestUtils.getExternalWalletAddress(), signature); + assert.deepEqual(result, new MoneroMessageSignatureResult({isGood: false})); + + // verify message with invalid address + result = await that.wallet.verifyMessage(msg, "invalid address", signature); + assert.deepEqual(result, new MoneroMessageSignatureResult({isGood: false})); + + // sign and verify message with view key + signature = await that.wallet.signMessage(msg, MoneroMessageSignatureType.SIGN_WITH_VIEW_KEY, subaddress.getAccountIndex(), subaddress.getIndex()); + result = await that.wallet.verifyMessage(msg, await that.wallet.getAddress(subaddress.getAccountIndex(), subaddress.getIndex()), signature); + assert.deepEqual(result, new MoneroMessageSignatureResult({isGood: true, isOld: false, signatureType: MoneroMessageSignatureType.SIGN_WITH_VIEW_KEY, version: 2})); + + // verify message with incorrect address + result = await that.wallet.verifyMessage(msg, await that.wallet.getAddress(0, 2), signature); + assert.deepEqual(result, new MoneroMessageSignatureResult({isGood: false})); + + // verify message with external address + result = await that.wallet.verifyMessage(msg, await TestUtils.getExternalWalletAddress(), signature); + assert.deepEqual(result, new MoneroMessageSignatureResult({isGood: false})); + + // verify message with invalid address + result = await that.wallet.verifyMessage(msg, "invalid address", signature); + assert.deepEqual(result, new MoneroMessageSignatureResult({isGood: false})); + } + }); + + if (testConfig.testNonRelays) + it("Has an address book", async function() { + + // initial state + let entries = await that.wallet.getAddressBookEntries(); + let numEntriesStart = entries.length + for (let entry of entries) await testAddressBookEntry(entry); + + // test adding standard addresses + const NUM_ENTRIES = 5; + let address = (await that.wallet.getSubaddress(0, 0)).getAddress(); + let indices: any = []; + for (let i = 0; i < NUM_ENTRIES; i++) { + indices.push(await that.wallet.addAddressBookEntry(address, "hi there!")); + } + entries = await that.wallet.getAddressBookEntries(); + assert.equal(entries.length, numEntriesStart + NUM_ENTRIES); + for (let idx of indices) { + let found = false; + for (let entry of entries) { + if (idx === entry.getIndex()) { + await testAddressBookEntry(entry); + assert.equal(entry.getAddress(), address); + assert.equal(entry.getDescription(), "hi there!"); + found = true; + break; + } + } + assert(found, "Index " + idx + " not found in address book indices"); + } + + // edit each address book entry + for (let idx of indices) { + await that.wallet.editAddressBookEntry(idx, false, undefined, true, "hello there!!"); + } + entries = await that.wallet.getAddressBookEntries(indices); + for (let entry of entries) { + assert.equal(entry.getDescription(), "hello there!!"); + } + + // delete entries at starting index + let deleteIdx = indices[0]; + for (let i = 0; i < indices.length; i++) { + await that.wallet.deleteAddressBookEntry(deleteIdx); + } + entries = await that.wallet.getAddressBookEntries(); + assert.equal(entries.length, numEntriesStart); + + // test adding integrated addresses + indices = []; + let paymentId = "03284e41c342f03"; // payment id less one character + let integratedAddresses = {}; + let integratedDescriptions = {}; + for (let i = 0; i < NUM_ENTRIES; i++) { + let integratedAddress = await that.wallet.getIntegratedAddress(undefined, paymentId + i); // create unique integrated address + let uuid = GenUtils.getUUID(); + let idx = await that.wallet.addAddressBookEntry(integratedAddress.toString(), uuid); + indices.push(idx); + integratedAddresses[idx] = integratedAddress; + integratedDescriptions[idx] = uuid; + } + entries = await that.wallet.getAddressBookEntries(); + assert.equal(entries.length, numEntriesStart + NUM_ENTRIES); + for (let idx of indices) { + let found = false; + for (let entry of entries) { + if (idx === entry.getIndex()) { + await testAddressBookEntry(entry); + assert.equal(entry.getDescription(), integratedDescriptions[idx]); + assert.equal(entry.getAddress(), integratedAddresses[idx].toString()); + assert.equal(entry.getPaymentId(), undefined); + found = true; + break; + } + } + assert(found, "Index " + idx + " not found in address book indices"); + } + + // delete entries at starting index + deleteIdx = indices[0]; + for (let i = 0; i < indices.length; i++) { + await that.wallet.deleteAddressBookEntry(deleteIdx); + } + entries = await that.wallet.getAddressBookEntries(); + assert.equal(entries.length, numEntriesStart); + }); + + if (testConfig.testNonRelays) + it("Can get and set arbitrary key/value attributes", async function() { + + // set attributes + let attrs = {}; + for (let i = 0; i < 5; i++) { + let key = "attr" + i; + let val = GenUtils.getUUID(); + attrs[key] = val; + await that.wallet.setAttribute(key, val); + } + + // test attributes + for (let key of Object.keys(attrs)) { + assert.equal(attrs[key], await that.wallet.getAttribute(key)); + } + + // get an undefined attribute + assert.equal(await that.wallet.getAttribute("unset_key"), undefined); + }); + + if (testConfig.testNonRelays) + it("Can convert between a tx config and payment URI", async function() { + + // test with address and amount + let config1 = new MoneroTxConfig({address: await that.wallet.getAddress(0, 0), amount: BigInt(0)}); + let uri = await that.wallet.getPaymentUri(config1); + let config2 = await that.wallet.parsePaymentUri(uri); + GenUtils.deleteUndefinedKeys(config1); + GenUtils.deleteUndefinedKeys(config2); + assert.deepEqual(JSON.parse(JSON.stringify(config2.toJson())), JSON.parse(JSON.stringify(config1.toJson()))); + + // test with subaddress and all fields + config1.getDestinations()[0].setAddress((await that.wallet.getSubaddress(0, 1)).getAddress()); + config1.getDestinations()[0].setAmount(425000000000n); + config1.setRecipientName("John Doe"); + config1.setNote("OMZG XMR FTW"); + uri = await that.wallet.getPaymentUri(config1.toJson()); + config2 = await that.wallet.parsePaymentUri(uri); + GenUtils.deleteUndefinedKeys(config1); + GenUtils.deleteUndefinedKeys(config2); + assert.deepEqual(JSON.parse(JSON.stringify(config2.toJson())), JSON.parse(JSON.stringify(config1.toJson()))); + + // test with undefined address + let address = config1.getDestinations()[0].getAddress(); + config1.getDestinations()[0].setAddress(undefined); + try { + await that.wallet.getPaymentUri(config1); + throw new Error("Should have thrown exception with invalid parameters"); + } catch (e: any) { + assert(e.message.indexOf("Cannot make URI from supplied parameters") >= 0); + } + config1.getDestinations()[0].setAddress(address); + + // test with standalone payment id + config1.setPaymentId("03284e41c342f03603284e41c342f03603284e41c342f03603284e41c342f036"); + try { + await that.wallet.getPaymentUri(config1); + throw new Error("Should have thrown exception with invalid parameters"); + } catch (e: any) { + assert(e.message.indexOf("Cannot make URI from supplied parameters") >= 0); + } + }); + + if (testConfig.testNonRelays) + it("Can start and stop mining", async function() { + let status = await that.daemon.getMiningStatus(); + if (status.getIsActive()) await that.wallet.stopMining(); + await that.wallet.startMining(2, false, true); + await that.wallet.stopMining(); + }); + + if (testConfig.testNonRelays) + it("Can change the wallet password", async function() { + + // create random wallet + let wallet = await that.createWallet(new MoneroWalletConfig().setPassword(TestUtils.WALLET_PASSWORD)); + let path = await wallet.getPath(); + + // change password + let newPassword = ""; + await wallet.changePassword(TestUtils.WALLET_PASSWORD, newPassword); + + // close wallet without saving + await that.closeWallet(wallet, true); + + // old password does not work (password change is auto saved) + try { + await that.openWallet(new MoneroWalletConfig().setPath(path).setPassword(TestUtils.WALLET_PASSWORD)); + throw new Error("Should have thrown"); + } catch (err: any) { + assert(err.message.toLowerCase().indexOf("failed to open wallet") >= 0 || err.message.toLowerCase().indexOf("invalid password") >= 0); // TODO: different errors from rpc and wallet2 + } + + // open wallet with new password + wallet = await that.openWallet(new MoneroWalletConfig().setPath(path).setPassword(newPassword)); + + // change password with incorrect password + try { + await wallet.changePassword("badpassword", newPassword); + throw new Error("Should have thrown"); + } catch (err: any) { + assert.equal(err.message, "Invalid original password."); + } + + // save and close + await that.closeWallet(wallet, true); + + // open wallet + wallet = await that.openWallet(new MoneroWalletConfig().setPath(path).setPassword(newPassword)); + + // close wallet + await that.closeWallet(wallet); + }); + + if (testConfig.testNonRelays) + it("Can save and close the wallet in a single call", async function() { + + // create random wallet + let password = ""; // unencrypted + let wallet = await that.createWallet({password: password}); + let path = await wallet.getPath(); + + // set an attribute + let uuid = GenUtils.getUUID(); + await wallet.setAttribute("id", uuid); + + // close the wallet without saving + await that.closeWallet(wallet); + + // re-open the wallet and ensure attribute was not saved + wallet = await that.openWallet({path: path, password: password}); + assert.equal(await wallet.getAttribute("id"), undefined); + + // set the attribute and close with saving + await wallet.setAttribute("id", uuid); + await that.closeWallet(wallet, true); + + // re-open the wallet and ensure attribute was saved + wallet = await that.openWallet({path: path, password: password}); + assert.equal(await wallet.getAttribute("id"), uuid); + await that.closeWallet(wallet); + }); + + // ----------------------------- NOTIFICATION TESTS ------------------------- + + if (testConfig.testNotifications) + it("Can generate notifications sending to different wallet.", async function() { + await testWalletNotifications("testNotificationsDifferentWallet", false, false, false, false, 0); + }); + + if (testConfig.testNotifications) + it("Can generate notifications sending to different wallet when relayed", async function() { + await testWalletNotifications("testNotificationsDifferentWalletWhenRelayed", false, false, false, true, 3); + }); + + if (testConfig.testNotifications) + it("Can generate notifications sending to different account.", async function() { + await testWalletNotifications("testNotificationsDifferentAccounts", true, false, false, false, 0); + }); + + if (testConfig.testNotifications) + it("Can generate notifications sending to same account", async function() { + await testWalletNotifications("testNotificationsSameAccount", true, true, false, false, 0); + }); + + if (testConfig.testNotifications) + it("Can generate notifications sweeping output to different account", async function() { + await testWalletNotifications("testNotificationsDifferentAccountSweepOutput", true, false, true, false, 0); + }); + + if (testConfig.testNotifications) + it("Can generate notifications sweeping output to same account when relayed", async function() { + await testWalletNotifications("testNotificationsSameAccountSweepOutputWhenRelayed", true, true, true, true, 0); + }); + + async function testWalletNotifications(testName, sameWallet, sameAccount, sweepOutput, createThenRelay, unlockDelay) { + let issues = await testWalletNotificationsAux(sameWallet, sameAccount, sweepOutput, createThenRelay, unlockDelay); + if (issues.length === 0) return; + let msg = testName + "(" + sameWallet + ", " + sameAccount + ", " + sweepOutput + ", " + createThenRelay + ") generated " + issues.length + " issues:\n" + issuesToStr(issues); + console.log(msg); + if (msg.includes("ERROR:")) throw new Error(msg); + } + + // TODO: test sweepUnlocked() + async function testWalletNotificationsAux(sameWallet, sameAccount, sweepOutput, createThenRelay, unlockDelay) { + let MAX_POLL_TIME = 5000; // maximum time granted for wallet to poll + + // collect issues as test runs + let issues: any[] = []; + + // set sender and receiver + let sender = that.wallet; + let receiver = sameWallet ? sender : await that.createWallet(new MoneroWalletConfig()); + + // create receiver accounts if necessary + let numAccounts = (await receiver.getAccounts()).length; + for (let i = 0; i < 4 - numAccounts; i++) await receiver.createAccount(); + + // wait for unlocked funds in source account + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(sender); + await TestUtils.WALLET_TX_TRACKER.waitForUnlockedBalance(sender, 0, undefined, TestUtils.MAX_FEE * (10n)); + + // get balances to compare after sending + let senderBalanceBefore = await sender.getBalance(); + let senderUnlockedBalanceBefore = await sender.getUnlockedBalance(); + let receiverBalanceBefore = await receiver.getBalance(); + let receiverUnlockedBalanceBefore = await receiver.getUnlockedBalance(); + let lastHeight = await that.daemon.getHeight(); + + // start collecting notifications from sender and receiver + let senderNotificationCollector = new WalletNotificationCollector(); + let receiverNotificationCollector = new WalletNotificationCollector(); + await sender.addListener(senderNotificationCollector); + await GenUtils.waitFor(TestUtils.SYNC_PERIOD_IN_MS / 2); // TODO: remove this, should be unnecessary + await receiver.addListener(receiverNotificationCollector); + + // send funds + let ctx: any = {wallet: sender, isSendResponse: true}; + let senderTx; + let destinationAccounts = sameAccount ? (sweepOutput ? [0] : [0, 1, 2]) : (sweepOutput ? [1] : [1, 2, 3]); + let expectedOutputs: any = []; + if (sweepOutput) { + ctx.isSweepResponse = true; + ctx.isSweepOutputResponse = true; + let outputs = await sender.getOutputs({isSpent: false, accountIndex: 0, minAmount: TestUtils.MAX_FEE * (5n), txQuery: {isLocked: false}}); + if (outputs.length === 0) { + issues.push("ERROR: No outputs available to sweep from account 0"); + return issues; + } + let config = {address: await receiver.getAddress(destinationAccounts[0], 0), keyImage: outputs[0].getKeyImage().getHex(), relay: !createThenRelay}; + senderTx = await sender.sweepOutput(config); + expectedOutputs.push(new MoneroOutputWallet().setAmount(senderTx.getOutgoingTransfer().getDestinations()[0].getAmount()).setAccountIndex(destinationAccounts[0]).setSubaddressIndex(0)); + ctx.config = new MoneroTxConfig(config); + } else { + let config = new MoneroTxConfig().setAccountIndex(0).setRelay(!createThenRelay); + for (let destinationAccount of destinationAccounts) { + config.addDestination(await receiver.getAddress(destinationAccount, 0), TestUtils.MAX_FEE); // TODO: send and check random amounts? + expectedOutputs.push(new MoneroOutputWallet().setAmount(TestUtils.MAX_FEE).setAccountIndex(destinationAccount).setSubaddressIndex(0)); + } + senderTx = await sender.createTx(config); + ctx.config = config; + } + if (createThenRelay) await sender.relayTx(senderTx); + + // start timer to measure end of sync period + let startTime = Date.now(); // timestamp in ms + + // test send tx + await that.testTxWallet(senderTx, ctx); + + // test sender after sending + let outputQuery = new MoneroOutputQuery().setTxQuery(new MoneroTxQuery().setHash(senderTx.getHash())); // query for outputs from sender tx + if (sameWallet) { + if (senderTx.getIncomingAmount() === undefined) issues.push("WARNING: sender tx incoming amount is null when sent to same wallet"); + else if (senderTx.getIncomingAmount() === 0n) issues.push("WARNING: sender tx incoming amount is 0 when sent to same wallet"); + else if (senderTx.getIncomingAmount() !== senderTx.getOutgoingAmount() - (senderTx.getFee())) issues.push("WARNING: sender tx incoming amount != outgoing amount - fee when sent to same wallet"); + } else { + if (senderTx.getIncomingAmount() !== undefined) issues.push("ERROR: tx incoming amount should be undefined"); // TODO: should be 0? then can remove undefined checks in this method + } + senderTx = (await sender.getTxs(new MoneroTxQuery().setHash(senderTx.getHash()).setIncludeOutputs(true)))[0]; + if (await sender.getBalance() !== senderBalanceBefore - (senderTx.getFee()) - (senderTx.getOutgoingAmount()) + (senderTx.getIncomingAmount() === undefined ? 0n : senderTx.getIncomingAmount())) issues.push("ERROR: sender balance after send != balance before - tx fee - outgoing amount + incoming amount (" + await sender.getBalance() + " != " + senderBalanceBefore + " - " + senderTx.getFee() + " - " + senderTx.getOutgoingAmount() + " + " + senderTx.getIncomingAmount() + ")"); + if (await sender.getUnlockedBalance() >= senderUnlockedBalanceBefore) issues.push("ERROR: sender unlocked balance should have decreased after sending"); + if (senderNotificationCollector.getBalanceNotifications().length === 0) issues.push("ERROR: sender did not notify balance change after sending"); + else { + if (await sender.getBalance() !== senderNotificationCollector.getBalanceNotifications()[senderNotificationCollector.getBalanceNotifications().length - 1].balance) issues.push("ERROR: sender balance != last notified balance after sending (" + await sender.getBalance() + " != " + senderNotificationCollector.getBalanceNotifications()[senderNotificationCollector.getBalanceNotifications().length - 1][0]) + ")"; + if (await sender.getUnlockedBalance() !== senderNotificationCollector.getBalanceNotifications()[senderNotificationCollector.getBalanceNotifications().length - 1].unlockedBalance) issues.push("ERROR: sender unlocked balance != last notified unlocked balance after sending (" + await sender.getUnlockedBalance() + " != " + senderNotificationCollector.getBalanceNotifications()[senderNotificationCollector.getBalanceNotifications().length - 1][1]) + ")"; + } + if (senderNotificationCollector.getOutputsSpent(outputQuery).length === 0) issues.push("ERROR: sender did not announce unconfirmed spent output"); + + // test receiver after 2 sync periods + await GenUtils.waitFor(TestUtils.SYNC_PERIOD_IN_MS * 2 - (Date.now() - startTime)); + startTime = Date.now(); // reset timer + let receiverTx = await receiver.getTx(senderTx.getHash()); + if (senderTx.getOutgoingAmount() !== receiverTx.getIncomingAmount()) { + if (sameAccount) issues.push("WARNING: sender tx outgoing amount != receiver tx incoming amount when sent to same account (" + senderTx.getOutgoingAmount() + " != " + receiverTx.getIncomingAmount() + ")"); + else issues.push("ERROR: sender tx outgoing amount != receiver tx incoming amount (" + senderTx.getOutgoingAmount() + " != " + receiverTx.getIncomingAmount()) + ")"; + } + if (await receiver.getBalance() !== receiverBalanceBefore + (receiverTx.getIncomingAmount() === undefined ? 0n : receiverTx.getIncomingAmount()) - (receiverTx.getOutgoingAmount() === undefined ? 0n : receiverTx.getOutgoingAmount()) - (sameWallet ? receiverTx.getFee() : 0n)) { + if (sameAccount) issues.push("WARNING: after sending, receiver balance != balance before + incoming amount - outgoing amount - tx fee when sent to same account (" + await receiver.getBalance() + " != " + receiverBalanceBefore + " + " + receiverTx.getIncomingAmount() + " - " + receiverTx.getOutgoingAmount() + " - " + (sameWallet ? receiverTx.getFee() : 0n).toString() + ")"); + else issues.push("ERROR: after sending, receiver balance != balance before + incoming amount - outgoing amount - tx fee (" + await receiver.getBalance() + " != " + receiverBalanceBefore + " + " + receiverTx.getIncomingAmount() + " - " + receiverTx.getOutgoingAmount() + " - " + (sameWallet ? receiverTx.getFee() : 0n).toString() + ")"); + } + if (!sameWallet && await receiver.getUnlockedBalance() !== receiverUnlockedBalanceBefore) issues.push("ERROR: receiver unlocked balance should not have changed after sending"); + if (receiverNotificationCollector.getBalanceNotifications().length === 0) issues.push("ERROR: receiver did not notify balance change when funds received"); + else { + if (await receiver.getBalance() !== receiverNotificationCollector.getBalanceNotifications()[receiverNotificationCollector.getBalanceNotifications().length - 1].balance) issues.push("ERROR: receiver balance != last notified balance after funds received"); + if (await receiver.getUnlockedBalance() !== receiverNotificationCollector.getBalanceNotifications()[receiverNotificationCollector.getBalanceNotifications().length - 1].unlockedBalance) issues.push("ERROR: receiver unlocked balance != last notified unlocked balance after funds received"); + } + if (receiverNotificationCollector.getOutputsReceived(outputQuery).length === 0) issues.push("ERROR: receiver did not announce unconfirmed received output"); + else { + for (let output of getMissingOutputs(expectedOutputs, receiverNotificationCollector.getOutputsReceived(outputQuery), true)) { + issues.push("ERROR: receiver did not announce received output for amount " + output.getAmount() + " to subaddress [" + output.getAccountIndex() + ", " + output.getSubaddressIndex() + "]"); + } + } + + // mine until test completes + await StartMining.startMining(); + + // loop every sync period until unlock tested + let threads: any = []; + let expectedUnlockTime = lastHeight + unlockDelay; + let confirmHeight: number | undefined = undefined; + while (true) { + + // test height notifications + let height = await that.daemon.getHeight(); + if (height > lastHeight) { + let testStartHeight = lastHeight; + lastHeight = height; + let threadFn = async function() { + await GenUtils.waitFor(TestUtils.SYNC_PERIOD_IN_MS * 2 + MAX_POLL_TIME); // wait 2 sync periods + poll time for notifications + let senderBlockNotifications = senderNotificationCollector.getBlockNotifications(); + let receiverBlockNotifications = receiverNotificationCollector.getBlockNotifications(); + for (let i = testStartHeight; i < height; i++) { + if (!GenUtils.arrayContains(senderBlockNotifications, i)) issues.push("ERROR: sender did not announce block " + i); + if (!GenUtils.arrayContains(receiverBlockNotifications, i)) issues.push("ERROR: receiver did not announce block " + i); + } + } + threads.push(threadFn()); + } + + // check if tx confirmed + if (confirmHeight === undefined) { + + // get updated tx + let tx = await receiver.getTx(senderTx.getHash()); + + // break if tx fails + if (tx.getIsFailed()) { + issues.push("ERROR: tx failed in tx pool"); + break; + } + + // test confirm notifications + if (tx.getIsConfirmed() && confirmHeight === undefined) { + confirmHeight = tx.getHeight(); + expectedUnlockTime = Math.max(confirmHeight + NUM_BLOCKS_LOCKED, expectedUnlockTime); // exact unlock time known + let threadFn = async function() { + await GenUtils.waitFor(TestUtils.SYNC_PERIOD_IN_MS * 2 + MAX_POLL_TIME); // wait 2 sync periods + poll time for notifications + let confirmedQuery = outputQuery.getTxQuery().copy().setIsConfirmed(true).setIsLocked(true).getOutputQuery(); + if (senderNotificationCollector.getOutputsSpent(confirmedQuery).length === 0) issues.push("ERROR: sender did not announce confirmed spent output"); // TODO: test amount + if (receiverNotificationCollector.getOutputsReceived(confirmedQuery).length === 0) issues.push("ERROR: receiver did not announce confirmed received output"); + else for (let output of getMissingOutputs(expectedOutputs, receiverNotificationCollector.getOutputsReceived(confirmedQuery), true)) issues.push("ERROR: receiver did not announce confirmed received output for amount " + output.getAmount() + " to subaddress [" + output.getAccountIndex() + ", " + output.getSubaddressIndex() + "]"); + + // if same wallet, net amount spent = tx fee = outputs spent - outputs received + if (sameWallet) { + let netAmount = 0n; + for (let outputSpent of senderNotificationCollector.getOutputsSpent(confirmedQuery)) netAmount = netAmount + (outputSpent.getAmount()); + for (let outputReceived of senderNotificationCollector.getOutputsReceived(confirmedQuery)) netAmount = netAmount - (outputReceived.getAmount()); + if (tx.getFee() !== netAmount) { + if (sameAccount) issues.push("WARNING: net output amount != tx fee when funds sent to same account: " + netAmount + " vs " + tx.getFee()); + else if (sender instanceof MoneroWalletRpc) issues.push("WARNING: net output amount != tx fee when funds sent to same wallet because monero-wallet-rpc does not provide tx inputs: " + netAmount + " vs " + tx.getFee()); // TODO (monero-project): open issue to provide tx inputs + else issues.push("ERROR: net output amount must equal tx fee when funds sent to same wallet: " + netAmount + " vs " + tx.getFee()); + } + } + } + threads.push(threadFn()); + } + } + + // otherwise test unlock notifications + else if (height >= expectedUnlockTime) { + let threadFn = async function() { + await GenUtils.waitFor(TestUtils.SYNC_PERIOD_IN_MS * 2 + MAX_POLL_TIME); // wait 2 sync periods + poll time for notifications + let unlockedQuery = outputQuery.getTxQuery().copy().setIsLocked(false).getOutputQuery(); + if (senderNotificationCollector.getOutputsSpent(unlockedQuery).length === 0) issues.push("ERROR: sender did not announce unlocked spent output"); // TODO: test amount? + for (let output of getMissingOutputs(expectedOutputs, receiverNotificationCollector.getOutputsReceived(unlockedQuery), true)) issues.push("ERROR: receiver did not announce unlocked received output for amount " + output.getAmount() + " to subaddress [" + output.getAccountIndex() + ", " + output.getSubaddressIndex() + "]"); + if (!sameWallet && await receiver.getBalance() !== await receiver.getUnlockedBalance()) issues.push("ERROR: receiver balance != unlocked balance after funds unlocked"); + if (senderNotificationCollector.getBalanceNotifications().length === 0) issues.push("ERROR: sender did not announce any balance notifications"); + else { + if (await sender.getBalance() !== senderNotificationCollector.getBalanceNotifications()[senderNotificationCollector.getBalanceNotifications().length - 1].balance) issues.push("ERROR: sender balance != last notified balance after funds unlocked"); + if (await sender.getUnlockedBalance() !== senderNotificationCollector.getBalanceNotifications()[senderNotificationCollector.getBalanceNotifications().length - 1].unlockedBalance) issues.push("ERROR: sender unlocked balance != last notified unlocked balance after funds unlocked"); + } + if (receiverNotificationCollector.getBalanceNotifications().length === 0) issues.push("ERROR: receiver did not announce any balance notifications"); + else { + if (await receiver.getBalance() !== receiverNotificationCollector.getBalanceNotifications()[receiverNotificationCollector.getBalanceNotifications().length - 1].balance) issues.push("ERROR: receiver balance != last notified balance after funds unlocked"); + if (await receiver.getUnlockedBalance() !== receiverNotificationCollector.getBalanceNotifications()[receiverNotificationCollector.getBalanceNotifications().length - 1].unlockedBalance) issues.push("ERROR: receiver unlocked balance != last notified unlocked balance after funds unlocked"); + } + } + threads.push(threadFn()); + break; + } + + // wait for end of sync period + await GenUtils.waitFor(TestUtils.SYNC_PERIOD_IN_MS - (Date.now() - startTime)); + startTime = Date.now(); // reset timer + } + + // wait for test threads + await Promise.all(threads); + + // test notified outputs + for (let output of senderNotificationCollector.getOutputsSpent(outputQuery)) testNotifiedOutput(output, true, issues); + for (let output of senderNotificationCollector.getOutputsReceived(outputQuery)) testNotifiedOutput(output, false, issues); + for (let output of receiverNotificationCollector.getOutputsSpent(outputQuery)) testNotifiedOutput(output, true, issues); + for (let output of receiverNotificationCollector.getOutputsReceived(outputQuery)) testNotifiedOutput(output, false, issues); + + // clean up + if ((await that.daemon.getMiningStatus()).getIsActive()) await that.daemon.stopMining(); + await sender.removeListener(senderNotificationCollector); + senderNotificationCollector.setListening(false); + await receiver.removeListener(receiverNotificationCollector); + receiverNotificationCollector.setListening(false); + if (sender !== receiver) await that.closeWallet(receiver); + return issues; + } + + function getMissingOutputs(expectedOutputs, actualOutputs, matchSubaddress): any[] { + let missing: any[] = []; + let used: any[] = []; + for (let expectedOutput of expectedOutputs) { + let found = false; + for (let actualOutput of actualOutputs) { + if (GenUtils.arrayContains(used, actualOutput, true)) continue; + if (actualOutput.getAmount() === expectedOutput.getAmount() && (!matchSubaddress || (actualOutput.getAccountIndex() === expectedOutput.getAccountIndex() && actualOutput.getSubaddressIndex() === expectedOutput.getSubaddressIndex()))) { + used.push(actualOutput); + found = true; + break; + } + } + if (!found) missing.push(expectedOutput); + } + return missing; + } + + function issuesToStr(issues) { + if (issues.length === 0) return undefined; + let str = ""; + for (let i = 0; i < issues.length; i++) { + str += (i + 1) + ": " + issues[i]; + if (i < issues.length - 1) str += "\n"; + } + return str; + } + + function testNotifiedOutput(output, isTxInput, issues) { + + // test tx link + assert.notEqual(undefined, output.getTx()); + if (isTxInput) assert(output.getTx().getInputs().includes(output)); + else assert(output.getTx().getOutputs().includes(output)); + + // test output values + TestUtils.testUnsignedBigInt(output.getAmount()); + if (output.getAccountIndex() !== undefined) assert(output.getAccountIndex() >= 0); + else { + if (isTxInput) issues.push("WARNING: notification of " + getOutputState(output) + " spent output missing account index"); // TODO (monero-project): account index not provided when output swept by key image. could retrieve it but slows tx creation significantly + else issues.push("ERROR: notification of " + getOutputState(output) + " received output missing account index"); + } + if (output.getSubaddressIndex() !== undefined) assert(output.getSubaddressIndex() >= 0); + else { + if (isTxInput) issues.push("WARNING: notification of " + getOutputState(output) + " spent output missing subaddress index"); // TODO (monero-project): because inputs are not provided, creating fake input from outgoing transfer, which can be sourced from multiple subaddress indices, whereas an output can only come from one subaddress index; need to provide tx inputs to resolve this + else issues.push("ERROR: notification of " + getOutputState(output) + " received output missing subaddress index"); + } + } + + function getOutputState(output) { + if (false === output.getTx().getIsLocked()) return "unlocked"; + if (true === output.getTx().getIsConfirmed()) return "confirmed"; + if (false === output.getTx().getIsConfirmed()) return "unconfirmed"; + throw new Error("Unknown output state: " + output.toString()); + } + + it("Can stop listening", async function() { + + // create offline wallet + let wallet = await that.createWallet(new MoneroWalletConfig().setServer(TestUtils.OFFLINE_SERVER_URI)); + + // add listener + let listener = new WalletNotificationCollector(); + await wallet.addListener(listener); + await wallet.setDaemonConnection(await that.daemon.getRpcConnection()); + await new Promise(function(resolve) { setTimeout(resolve, 1000); }); + + // remove listener and close + await wallet.removeListener(listener); + await that.closeWallet(wallet); + }); + + if (testConfig.testNotifications) + it("Can be created and receive funds", async function() { + + // create a random wallet + let receiver = await that.createWallet({password: "mysupersecretpassword123"}); + let err; + try { + + // listen for received outputs + let myListener = new WalletNotificationCollector(); + await receiver.addListener(myListener); + + // wait for txs to confirm and for sufficient unlocked balance + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + await TestUtils.WALLET_TX_TRACKER.waitForUnlockedBalance(that.wallet, 0, undefined, TestUtils.MAX_FEE); + + // send funds to the created wallet + let sentTx = await that.wallet.createTx({accountIndex: 0, address: await receiver.getPrimaryAddress(), amount: TestUtils.MAX_FEE, relay: true}); + + // wait for funds to confirm + try { await StartMining.startMining(); } catch (e: any) { } + while (!(await that.wallet.getTx(sentTx.getHash())).getIsConfirmed()) { + if ((await that.wallet.getTx(sentTx.getHash())).getIsFailed()) throw new Error("Tx failed in mempool: " + sentTx.getHash()); + await that.daemon.waitForNextBlockHeader(); + } + + // receiver should have notified listeners of received outputs + await new Promise(function(resolve) { setTimeout(resolve, 1000); }); // TODO: this lets block slip, okay? + assert(myListener.getOutputsReceived().length > 0, "Listener did not receive outputs"); + } catch (e: any) { + err = e; + } + + // final cleanup + await that.closeWallet(receiver); + try { await that.daemon.stopMining(); } catch (e: any) { } + if (err) throw err; + }); + + // TODO: test sending to multiple accounts + if (testConfig.testRelays && testConfig.testNotifications) + it("Can update a locked tx sent from/to the same account as blocks are added to the chain", async function() { + let config = new MoneroTxConfig({accountIndex: 0, address: await that.wallet.getPrimaryAddress(), amount: TestUtils.MAX_FEE, canSplit: false, relay: true}); + await testSendAndUpdateTxs(config); + }); + + if (testConfig.testRelays && testConfig.testNotifications && !testConfig.liteMode) + it("Can update split locked txs sent from/to the same account as blocks are added to the chain", async function() { + let config = new MoneroTxConfig({accountIndex: 0, address: await that.wallet.getPrimaryAddress(), amount: TestUtils.MAX_FEE, canSplit: true, relay: true}); + await testSendAndUpdateTxs(config); + }); + + if (testConfig.testRelays && testConfig.testNotifications && !testConfig.liteMode) + it("Can update a locked tx sent from/to different accounts as blocks are added to the chain", async function() { + let config = new MoneroTxConfig({accountIndex: 0, address: (await that.wallet.getSubaddress(1, 0)).getAddress(), amount: TestUtils.MAX_FEE, canSplit: false, relay: true}); + await testSendAndUpdateTxs(config); + }); + + if (testConfig.testRelays && testConfig.testNotifications && !testConfig.liteMode) + it("Can update locked, split txs sent from/to different accounts as blocks are added to the chain", async function() { + let config = new MoneroTxConfig({accountIndex: 0, address: (await that.wallet.getSubaddress(1, 0)).getAddress(), amount: TestUtils.MAX_FEE, relay: true}); + await testSendAndUpdateTxs(config); + }); + + /** + * Tests sending a tx with an unlock time then tracking and updating it as + * blocks are added to the chain. + * + * TODO: test wallet accounting throughout this; dedicated method? probably. + * + * Allows sending to and from the same account which is an edge case where + * incoming txs are occluded by their outgoing counterpart (issue #4500) + * and also where it is impossible to discern which incoming output is + * the tx amount and which is the change amount without wallet metadata. + * + * @param config - tx configuration to send and test + */ + async function testSendAndUpdateTxs(config) { + if (!config) config = new MoneroTxConfig(); + + // wait for txs to confirm and for sufficient unlocked balance + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + assert(!config.getSubaddressIndices()); + await TestUtils.WALLET_TX_TRACKER.waitForUnlockedBalance(that.wallet, config.getAccountIndex(), undefined, TestUtils.MAX_FEE * (2n)); + + // this test starts and stops mining, so it's wrapped in order to stop mining if anything fails + let err; + try { + + // send transactions + let sentTxs = config.getCanSplit() !== false ? await that.wallet.createTxs(config) : [await that.wallet.createTx(config)]; + + // test sent transactions + for (let tx of sentTxs) { + await that.testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true}); + assert.equal(tx.getIsConfirmed(), false); + assert.equal(tx.getInTxPool(), true); + } + + // track resulting outgoing and incoming txs as blocks are added to the chain + let updatedTxs; + + // start mining + try { await StartMining.startMining(); } + catch (e: any) { console.log("WARNING: could not start mining: " + e.message); } // not fatal + + // loop to update txs through confirmations + let numConfirmations = 0; + const numConfirmationsTotal = 2; // number of confirmations to test + while (numConfirmations < numConfirmationsTotal) { + + // wait for a block + let header = await that.daemon.waitForNextBlockHeader(); + console.log("*** Block " + header.getHeight() + " added to chain ***"); + + // give wallet time to catch up, otherwise incoming tx may not appear + await new Promise(function(resolve) { setTimeout(resolve, TestUtils.SYNC_PERIOD_IN_MS); }); // TODO: this lets block slip, okay? + + // get incoming/outgoing txs with sent hashes + let txQuery = new MoneroTxQuery(); + txQuery.setHashes(sentTxs.map(sentTx => sentTx.getHash())); // TODO: convenience methods wallet.getTxById(), getTxsById()? + let fetchedTxs = await that.getAndTestTxs(that.wallet, txQuery, true); + assert(fetchedTxs.length > 0); + + // test fetched txs + await testOutInPairs(that.wallet, fetchedTxs, config, false); + + // merge fetched txs into updated txs and original sent txs + for (let fetchedTx of fetchedTxs) { + + // merge with updated txs + if (updatedTxs === undefined) updatedTxs = fetchedTxs; + else { + for (let updatedTx of updatedTxs) { + if (fetchedTx.getHash() !== updatedTx.getHash()) continue; + if (!!fetchedTx.getOutgoingTransfer() !== !!updatedTx.getOutgoingTransfer()) continue; // skip if directions are different + updatedTx.merge(fetchedTx.copy()); + if (!updatedTx.getBlock() && fetchedTx.getBlock()) updatedTx.setBlock(fetchedTx.getBlock().copy().setTxs([updatedTx])); // copy block for testing + } + } + + // merge with original sent txs + for (let sentTx of sentTxs) { + if (fetchedTx.getHash() !== sentTx.getHash()) continue; + if (!!fetchedTx.getOutgoingTransfer() !== !!sentTx.getOutgoingTransfer()) continue; // skip if directions are different + sentTx.merge(fetchedTx.copy()); // TODO: it's mergeable but tests don't account for extra info from send (e.g. hex) so not tested; could specify in test context + } + } + + // test updated txs + testGetTxsStructure(updatedTxs, config); + await testOutInPairs(that.wallet, updatedTxs, config, false); + + // update confirmations in order to exit loop + numConfirmations = fetchedTxs[0].getNumConfirmations(); + } + } catch (e: any) { + err = e; + } + + // stop mining + try { await that.wallet.stopMining(); } + catch (e: any) { } + + // throw error if there was one + if (err) throw err; + } + + async function testOutInPairs(wallet, txs, config, isSendResponse) { + + // for each out tx + let txOut; + for (let tx of txs) { + await testUnlockTx(that.wallet, tx, config, isSendResponse); + if (!tx.getOutgoingTransfer()) continue; + let txOut = tx; + + // find incoming counterpart + let txIn; + for (let tx2 of txs) { + if (tx2.getIncomingTransfers() && tx.getHash() === tx2.getHash()) { + txIn = tx2; + break; + } + } + + // test out / in pair + // TODO monero-wallet-rpc: incoming txs occluded by their outgoing counterpart #4500 + if (!txIn) { + console.log("WARNING: outgoing tx " + txOut.getHash() + " missing incoming counterpart (issue #4500)"); + } else { + await testOutInPair(txOut, txIn); + } + } + } + + async function testOutInPair(txOut, txIn) { + assert.equal(txIn.getIsConfirmed(), txOut.getIsConfirmed()); + assert.equal(txOut.getOutgoingAmount(), txIn.getIncomingAmount()); + } + + async function testUnlockTx(wallet, tx, config, isSendResponse) { + try { + await that.testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: isSendResponse}); + } catch (e: any) { + console.log(tx.toString()); + throw e; + } + } + + // ----------------------------- TEST RELAYS --------------------------- + + if (testConfig.testNonRelays) + it("Validates inputs when sending funds", async function() { + + // try sending with invalid address + try { + await that.wallet.createTx({address: "my invalid address", accountIndex: 0, amount: TestUtils.MAX_FEE}); + throw new Error("fail"); + } catch (err: any) { + assert.equal(err.message, "Invalid destination address"); + } + }); + + if (testConfig.testRelays) + it("Can send to self", async function() { + let err; + let recipient; + try { + + // wait for txs to confirm and for sufficient unlocked balance + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + let amount = TestUtils.MAX_FEE * (3n); + await TestUtils.WALLET_TX_TRACKER.waitForUnlockedBalance(that.wallet, 0, undefined, amount); + + // collect sender balances before + let balance1 = await that.wallet.getBalance(); + let unlockedBalance1 = await that.wallet.getUnlockedBalance(); + + // send funds to self + let tx = await that.wallet.createTx({ + accountIndex: 0, + address: (await that.wallet.getIntegratedAddress()).getIntegratedAddress(), + amount: amount, + relay: true + }); + + // test balances after + let balance2 = await that.wallet.getBalance(); + let unlockedBalance2 = await that.wallet.getUnlockedBalance(); + assert(unlockedBalance2 < unlockedBalance1); // unlocked balance should decrease + let expectedBalance = balance1 - (tx.getFee()); + assert.equal(expectedBalance.toString(), balance2.toString(), "Balance after send was not balance before - net tx amount - fee (5 - 1 != 4 test)"); + } catch (e: any) { + err = e; + } + + // finally + if (recipient && !await recipient.isClosed()) await that.closeWallet(recipient); + if (err) throw err; + }); + + if (testConfig.testRelays) + it("Can send to an external address", async function() { + let err; + let recipient; + try { + + // wait for txs to confirm and for sufficient unlocked balance + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + let amount = TestUtils.MAX_FEE * (3n); + await TestUtils.WALLET_TX_TRACKER.waitForUnlockedBalance(that.wallet, 0, undefined, amount); + + // create recipient wallet + recipient = await that.createWallet(new MoneroWalletConfig()); + + // collect sender balances before + let balance1 = await that.wallet.getBalance(); + let unlockedBalance1 = await that.wallet.getUnlockedBalance(); + + // send funds to recipient + let tx = await that.wallet.createTx({ + accountIndex: 0, + address: await recipient.getPrimaryAddress(), + amount: amount, + relay: true + }); + + // test sender balances after + let balance2 = await that.wallet.getBalance(); + let unlockedBalance2 = await that.wallet.getUnlockedBalance(); + assert(unlockedBalance2 < unlockedBalance1); // unlocked balance should decrease + let expectedBalance = balance1 - (tx.getOutgoingAmount()) - (tx.getFee()); + assert.equal(expectedBalance.toString(), balance2.toString(), "Balance after send was not balance before - net tx amount - fee (5 - 1 != 4 test)"); + + // test recipient balance after + await recipient.sync(); + assert((await that.wallet.getTxs({isConfirmed: false})).length > 0); + assert.equal(amount.toString(), (await recipient.getBalance()).toString()); + } catch (e: any) { + err = e; + } + + // finally + if (recipient && !await recipient.isClosed()) await that.closeWallet(recipient); + if (err) throw err; + }); + + if (testConfig.testRelays) + it("Can send from multiple subaddresses in a single transaction", async function() { + await testSendFromMultiple(); + }); + + if (testConfig.testRelays) + it("Can send from multiple subaddresses in split transactions", async function() { + await testSendFromMultiple(new MoneroTxConfig().setCanSplit(true)); + }); + + async function testSendFromMultiple(config?) { + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + if (!config) config = new MoneroTxConfig(); + + let NUM_SUBADDRESSES = 2; // number of subaddresses to send from + + // get first account with (NUM_SUBADDRESSES + 1) subaddresses with unlocked balances + let accounts = await that.wallet.getAccounts(true); + assert(accounts.length >= 2, "This test requires at least 2 accounts; run send-to-multiple tests"); + let srcAccount; + let unlockedSubaddresses: any[] = []; + let hasBalance = false; + for (let account of accounts) { + unlockedSubaddresses = []; + let numSubaddressBalances = 0; + for (let subaddress of account.getSubaddresses()) { + if (subaddress.getBalance() > TestUtils.MAX_FEE) numSubaddressBalances++; + if (subaddress.getUnlockedBalance() > TestUtils.MAX_FEE) unlockedSubaddresses.push(subaddress); + } + if (numSubaddressBalances >= NUM_SUBADDRESSES + 1) hasBalance = true; + if (unlockedSubaddresses.length >= NUM_SUBADDRESSES + 1) { + srcAccount = account; + break; + } + } + assert(hasBalance, "Wallet does not have account with " + (NUM_SUBADDRESSES + 1) + " subaddresses with balances; run send-to-multiple tests"); + assert(unlockedSubaddresses.length >= NUM_SUBADDRESSES + 1, "Wallet is waiting on unlocked funds"); + + // determine the indices of the first two subaddresses with unlocked balances + let fromSubaddressIndices: any[] = []; + for (let i = 0; i < NUM_SUBADDRESSES; i++) { + fromSubaddressIndices.push(unlockedSubaddresses[i].getIndex()); + } + + // determine the amount to send + let sendAmount = BigInt(0); + for (let fromSubaddressIdx of fromSubaddressIndices) { + sendAmount = sendAmount + (srcAccount.getSubaddresses()[fromSubaddressIdx].getUnlockedBalance()); + } + sendAmount = sendAmount / SEND_DIVISOR; + + // send from the first subaddresses with unlocked balances + let address = await that.wallet.getPrimaryAddress(); + config.setDestinations([new MoneroDestination(address, sendAmount)]); + config.setAccountIndex(srcAccount.getIndex()); + config.setSubaddressIndices(fromSubaddressIndices); + config.setRelay(true); + let configCopy = config.copy(); + let txs: MoneroTxWallet[] = []; + if (config.getCanSplit() !== false) { + for (let tx of await that.wallet.createTxs(config)) txs.push(tx); + } else { + txs.push(await that.wallet.createTx(config)); + } + if (config.getCanSplit() === false) assert.equal(txs.length, 1); // must have exactly one tx if no split + + // test that config is unchanged + assert(configCopy !== config); + assert.deepEqual(config, configCopy); + + // test that balances of intended subaddresses decreased + let accountsAfter = await that.wallet.getAccounts(true); + assert.equal(accountsAfter.length, accounts.length); + let srcUnlockedBalanceDecreased = false; + for (let i = 0; i < accounts.length; i++) { + assert.equal(accountsAfter[i].getSubaddresses().length, accounts[i].getSubaddresses().length); + for (let j = 0; j < accounts[i].getSubaddresses().length; j++) { + let subaddressBefore = accounts[i].getSubaddresses()[j]; + let subaddressAfter = accountsAfter[i].getSubaddresses()[j]; + if (i === srcAccount.getIndex() && fromSubaddressIndices.includes(j)) { + if (subaddressAfter.getUnlockedBalance() < subaddressBefore.getUnlockedBalance()) srcUnlockedBalanceDecreased = true; + } else { + assert.equal(subaddressAfter.getUnlockedBalance(), subaddressBefore.getUnlockedBalance(), "Subaddress [" + i + "," + j + "] unlocked balance should not have changed"); + } + } + } + assert(srcUnlockedBalanceDecreased, "Subaddress unlocked balances should have decreased"); + + // test each transaction + assert(txs.length > 0); + let outgoingSum = BigInt(0); + for (let tx of txs) { + await that.testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true}); + outgoingSum = outgoingSum + (tx.getOutgoingAmount()); + if (tx.getOutgoingTransfer() !== undefined && tx.getOutgoingTransfer().getDestinations()) { + let destinationSum = BigInt(0); + for (let destination of tx.getOutgoingTransfer().getDestinations()) { + await testDestination(destination); + assert.equal(destination.getAddress(), address); + destinationSum = destinationSum + (destination.getAmount()); + } + assert.equal(tx.getOutgoingAmount(), destinationSum); // assert that transfers sum up to tx amount + } + } + + // assert that tx amounts sum up the amount sent within a small margin + if (GenUtils.abs(sendAmount - outgoingSum) > SEND_MAX_DIFF) { // send amounts may be slightly different + throw new Error("Tx amounts are too different: " + sendAmount + " - " + outgoingSum + " = " + (sendAmount - outgoingSum)); + } + } + + if (testConfig.testRelays) + it("Can send to an address in a single transaction.", async function() { + await testSendToSingle(new MoneroTxConfig().setCanSplit(false)); + }); + + // NOTE: this test will be invalid when payment ids are fully removed + if (testConfig.testRelays) + it("Can send to an address in a single transaction with a payment id", async function() { + let integratedAddress = await that.wallet.getIntegratedAddress(); + let paymentId = integratedAddress.getPaymentId(); + try { + await testSendToSingle(new MoneroTxConfig().setCanSplit(false).setPaymentId(paymentId + paymentId + paymentId + paymentId)); // 64 character payment id + throw new Error("fail"); + } catch (e: any) { + assert.equal(e.message, "Standalone payment IDs are obsolete. Use subaddresses or integrated addresses instead"); + } + }); + + if (testConfig.testRelays) + it("Can send to an address with split transactions", async function() { + await testSendToSingle(new MoneroTxConfig().setCanSplit(true).setRelay(true)); + }); + + if (testConfig.testRelays) + it("Can create then relay a transaction to send to a single address", async function() { + await testSendToSingle(new MoneroTxConfig().setCanSplit(false)); + }); + + if (testConfig.testRelays) + it("Can create then relay split transactions to send to a single address", async function() { + await testSendToSingle(new MoneroTxConfig().setCanSplit(true)); + }); + + async function testSendToSingle(config) { + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + if (!config) config = new MoneroTxConfig(); + + // find a non-primary subaddress to send from + let sufficientBalance = false; + let fromAccount: MoneroAccount | undefined = undefined; + let fromSubaddress: MoneroSubaddress | undefined = undefined; + let accounts = await that.wallet.getAccounts(true); + for (let account of accounts) { + let subaddresses = account.getSubaddresses(); + for (let i = 1; i < subaddresses.length; i++) { + if (subaddresses[i].getBalance() > TestUtils.MAX_FEE) sufficientBalance = true; + if (subaddresses[i].getUnlockedBalance() > TestUtils.MAX_FEE) { + fromAccount = account; + fromSubaddress = subaddresses[i]; + break; + } + } + if (fromAccount != undefined) break; + } + assert(sufficientBalance, "No non-primary subaddress found with sufficient balance"); + assert(fromSubaddress !== undefined, "Wallet is waiting on unlocked funds"); + + // get balance before send + let balanceBefore = fromSubaddress.getBalance(); + let unlockedBalanceBefore = fromSubaddress.getUnlockedBalance(); + + // init tx config + let sendAmount = (unlockedBalanceBefore - TestUtils.MAX_FEE) / SEND_DIVISOR; + let address = await that.wallet.getPrimaryAddress(); + config.setDestinations([new MoneroDestination(address, sendAmount)]); + config.setAccountIndex(fromAccount!.getIndex()); + config.setSubaddressIndices([fromSubaddress.getIndex()]); + let reqCopy = config.copy(); + + // send to self + let txs: any[] = [] + if (config.getCanSplit() !== false) { + for (let tx of await that.wallet.createTxs(config)) txs.push(tx); + } else { + txs.push(await that.wallet.createTx(config)); + } + if (config.getCanSplit() === false) assert.equal(txs.length, 1); // must have exactly one tx if no split + + // test that config is unchanged + assert(reqCopy !== config); + assert.deepEqual(config, reqCopy); + + // test common tx set among txs + testCommonTxSets(txs, false, false, false); + + // handle non-relayed transaction + if (config.getRelay() !== true) { + + // test transactions + for (let tx of txs) { + await that.testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true}); + } + + // txs are not in the pool + for (let txCreated of txs) { + for (let txPool of await that.daemon.getTxPool()) { + assert(txPool.getHash() !== txCreated.getHash(), "Created tx should not be in the pool"); + } + } + + // relay txs + let txHashes; + if (config.getCanSplit() !== true) txHashes = [await that.wallet.relayTx(txs[0])]; // test relayTx() with single transaction + else { + let txMetadatas: any[] = []; + for (let tx of txs) txMetadatas.push(tx.getMetadata()); + txHashes = await that.wallet.relayTxs(txMetadatas); // test relayTxs() with potentially multiple transactions + } + for (let txHash of txHashes) assert(typeof txHash === "string" && txHash.length === 64); + + // fetch txs for testing + txs = await that.wallet.getTxs({hashes: txHashes}); + } + + // test that balance and unlocked balance decreased + // TODO: test that other balances did not decrease + let subaddress = await that.wallet.getSubaddress(fromAccount!.getIndex(), fromSubaddress.getIndex()); + assert(subaddress.getBalance() < balanceBefore); + assert(subaddress.getUnlockedBalance() < unlockedBalanceBefore); + + // query locked txs + let lockedTxs = await that.getAndTestTxs(that.wallet, new MoneroTxQuery().setIsLocked(true), true); + for (let lockedTx of lockedTxs) assert.equal(lockedTx.getIsLocked(), true); + + // test transactions + assert(txs.length > 0); + for (let tx of txs) { + await that.testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: config.getRelay() === true}); + assert.equal(tx.getOutgoingTransfer().getAccountIndex(), fromAccount!.getIndex()); + assert.equal(tx.getOutgoingTransfer().getSubaddressIndices().length, 1); + assert.equal(tx.getOutgoingTransfer().getSubaddressIndices()[0], fromSubaddress.getIndex()); + assert.equal(sendAmount, tx.getOutgoingAmount()); + if (config.getPaymentId()) assert.equal(config.getPaymentId(), tx.getPaymentId()); + + // test outgoing destinations + if (tx.getOutgoingTransfer() && tx.getOutgoingTransfer().getDestinations()) { + assert.equal(tx.getOutgoingTransfer().getDestinations().length, 1); + for (let destination of tx.getOutgoingTransfer().getDestinations()) { + await testDestination(destination); + assert.equal(destination.getAddress(), address); + assert.equal(sendAmount, destination.getAmount()); + } + } + + // tx is among locked txs + let found = false; + for (let lockedTx of lockedTxs) { + if (lockedTx.getHash() === tx.getHash()) { + found = true; + break; + } + } + assert(found, "Created txs should be among locked txs"); + } + + // if tx was relayed in separate step, all wallets will need to wait for tx to confirm in order to reliably sync + if (config.getRelay() != true) { + await TestUtils.WALLET_TX_TRACKER.reset(); // TODO: resetExcept(that.wallet), or does this test wallet also need to be waited on? + } + } + + if (testConfig.testRelays) + it("Can send to multiple addresses in split transactions.", async function() { + await testSendToMultiple(3, 15, true); + }); + + if (testConfig.testRelays) + it("Can send to multiple addresses in split transactions using a JavaScript object for configuration", async function() { + await testSendToMultiple(3, 15, true, undefined, true); + }); + + if (testConfig.testRelays) + it("Can send dust to multiple addresses in split transactions", async function() { + let dustAmt = (await that.daemon.getFeeEstimate()).getFee() / BigInt(2); + await testSendToMultiple(5, 3, true, dustAmt); + }); + + if (testConfig.testRelays) + it("Can subtract fees from destinations", async function() { + await testSendToMultiple(5, 3, false, undefined, false, true); + }); + + if (testConfig.testRelays) + it("Cannot subtract fees from destinations in split transactions", async function() { + await testSendToMultiple(3, 15, true, undefined, true, true); + }); + + /** + * Sends funds from the first unlocked account to multiple accounts and subaddresses. + * + * @param numAccounts is the number of accounts to receive funds + * @param numSubaddressesPerAccount is the number of subaddresses per account to receive funds + * @param canSplit specifies if the operation can be split into multiple transactions + * @param sendAmountPerSubaddress is the amount to send to each subaddress (optional, computed if not given) + * @param useJsConfig specifies if the api should be invoked with a JS object instead of a MoneroTxConfig + * @param subtractFeeFromDestinations specifies to subtract the fee from destination addresses + */ + async function testSendToMultiple(numAccounts, numSubaddressesPerAccount, canSplit, sendAmountPerSubaddress?, useJsConfig?, subtractFeeFromDestinations?) { + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + + // compute the minimum account unlocked balance needed in order to fulfill the request + let minAccountAmount; + let totalSubaddresses = numAccounts * numSubaddressesPerAccount; + if (sendAmountPerSubaddress !== undefined) minAccountAmount = BigInt(totalSubaddresses) * sendAmountPerSubaddress + TestUtils.MAX_FEE; // min account amount must cover the total amount being sent plus the tx fee = numAddresses * (amtPerSubaddress + fee) + else minAccountAmount = TestUtils.MAX_FEE * BigInt(totalSubaddresses) * SEND_DIVISOR + TestUtils.MAX_FEE; // account balance must be more than fee * numAddresses * divisor + fee so each destination amount is at least a fee's worth (so dust is not sent) + + // send funds from first account with sufficient unlocked funds + let srcAccount; + let hasBalance = false; + for (let account of await that.wallet.getAccounts()) { + if (account.getBalance() > minAccountAmount) hasBalance = true; + if (account.getUnlockedBalance() > minAccountAmount) { + srcAccount = account; + break; + } + } + assert(hasBalance, "Wallet does not have enough balance; load '" + TestUtils.WALLET_NAME + "' with XMR in order to test sending"); + assert(srcAccount, "Wallet is waiting on unlocked funds"); + let balance = srcAccount.getBalance(); + let unlockedBalance = srcAccount.getUnlockedBalance(); + + // get amount to send total and per subaddress + let sendAmount; + if (sendAmountPerSubaddress === undefined) { + sendAmount = TestUtils.MAX_FEE * 5n * BigInt(totalSubaddresses); + sendAmountPerSubaddress = sendAmount / BigInt(totalSubaddresses); + } else { + sendAmount = sendAmountPerSubaddress * (BigInt(totalSubaddresses)); + } + + // create minimum number of accounts + let accounts = await that.wallet.getAccounts(); + for (let i = 0; i < numAccounts - accounts.length; i++) { + await that.wallet.createAccount(); + } + + // create minimum number of subaddresses per account and collect destination addresses + let destinationAddresses: any = []; + for (let i = 0; i < numAccounts; i++) { + let subaddresses = await that.wallet.getSubaddresses(i); + for (let j = 0; j < numSubaddressesPerAccount - subaddresses.length; j++) await that.wallet.createSubaddress(i); + subaddresses = await that.wallet.getSubaddresses(i); + assert(subaddresses.length >= numSubaddressesPerAccount); + for (let j = 0; j < numSubaddressesPerAccount; j++) destinationAddresses.push(subaddresses[j].getAddress()); + } + + // build tx config using MoneroTxConfig + let config = new MoneroTxConfig(); + config.setAccountIndex(srcAccount.getIndex()) + config.setSubaddressIndices([]); // test assigning undefined + config.setDestinations([]); + config.setRelay(true); + config.setCanSplit(canSplit); + config.setPriority(MoneroTxPriority.NORMAL); + let subtractFeeFrom: number[] = []; + for (let i = 0; i < destinationAddresses.length; i++) { + config.getDestinations().push(new MoneroDestination(destinationAddresses[i], sendAmountPerSubaddress)); + subtractFeeFrom.push(i); + } + if (subtractFeeFromDestinations) config.setSubtractFeeFrom(subtractFeeFrom); + + // build tx config with JS object + let jsConfig; + if (useJsConfig) { + jsConfig = {}; + jsConfig.accountIndex = srcAccount.getIndex(); + jsConfig.relay = true; + jsConfig.destinations = []; + for (let i = 0; i < destinationAddresses.length; i++) { + jsConfig.destinations.push({address: destinationAddresses[i], amount: sendAmountPerSubaddress}); + } + if (subtractFeeFromDestinations) jsConfig.subtractFeeFrom = subtractFeeFrom; + } + + // send tx(s) with config xor js object + let configCopy = config.copy(); + let txs: MoneroTxWallet[] = undefined; + try { + if (canSplit) { + txs = await that.wallet.createTxs(useJsConfig ? jsConfig : config); + } else { + txs = [await that.wallet.createTx(useJsConfig ? jsConfig : config)]; + } + } catch (err: any) { + + // test error applying subtractFromFee with split txs + if (subtractFeeFromDestinations && !txs) { + if (err.message !== "subtractfeefrom transfers cannot be split over multiple transactions yet") throw err; + return; + } + + throw err; + } + + // test that config is unchanged + assert(configCopy !== config); + assert.deepEqual(config, configCopy); + + // test that wallet balance decreased + let account = await that.wallet.getAccount(srcAccount.getIndex()); + assert(account.getBalance() < balance); + assert(account.getUnlockedBalance() < unlockedBalance); + + // build test context + config.setCanSplit(canSplit); + let ctx: any = {}; + ctx.wallet = that.wallet; + ctx.config = config; + ctx.isSendResponse = true; + + // test each transaction + assert(txs.length > 0); + let feeSum = BigInt(0); + let outgoingSum = BigInt(0); + await that.testTxsWallet(txs, ctx); + for (let tx of txs) { + feeSum = feeSum + tx.getFee(); + outgoingSum = outgoingSum + tx.getOutgoingAmount(); + if (tx.getOutgoingTransfer() !== undefined && tx.getOutgoingTransfer().getDestinations()) { + let destinationSum = BigInt(0); + for (let destination of tx.getOutgoingTransfer().getDestinations()) { + await testDestination(destination); + assert(destinationAddresses.includes(destination.getAddress())); + destinationSum = destinationSum + (destination.getAmount()); + } + assert.equal(tx.getOutgoingAmount(), destinationSum); // assert that transfers sum up to tx amount + } + } + + // assert that outgoing amounts sum up to the amount sent within a small margin + if (GenUtils.abs((sendAmount - (subtractFeeFromDestinations ? feeSum : BigInt(0)) - outgoingSum)) > SEND_MAX_DIFF) { // send amounts may be slightly different + throw new Error("Actual send amount is too different from requested send amount: " + sendAmount + " - " + (subtractFeeFromDestinations ? feeSum : BigInt(0)) + " - " + outgoingSum + " = " + sendAmount.subtract(subtractFeeFromDestinations ? feeSum : BigInt(0)).subtract(outgoingSum)); + } + } + + if (!testConfig.liteMode && (testConfig.testNonRelays || testConfig.testRelays)) + it("Supports view-only and offline wallets to create, sign, and submit transactions", async function() { + + // create view-only and offline wallets + let viewOnlyWallet = await that.createWallet({primaryAddress: await that.wallet.getPrimaryAddress(), privateViewKey: await that.wallet.getPrivateViewKey(), restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}); + let offlineWallet = await that.createWallet({primaryAddress: await that.wallet.getPrimaryAddress(), privateViewKey: await that.wallet.getPrivateViewKey(), privateSpendKey: await that.wallet.getPrivateSpendKey(), server: TestUtils.OFFLINE_SERVER_URI, restoreHeight: 0}); + await viewOnlyWallet.sync(); + + // test tx signing with wallets + let err; + try { + await that.testViewOnlyAndOfflineWallets(viewOnlyWallet, offlineWallet); + } catch (e: any) { + err = e; + } + + // finally + await that.closeWallet(viewOnlyWallet); + await that.closeWallet(offlineWallet); + if (err) throw err; + }); + + if (testConfig.testRelays) + it("Can sweep individual outputs identified by their key images", async function() { + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + + // test config + let numOutputs = 3; + + // get outputs to sweep (not spent, unlocked, and amount >= fee) + let spendableUnlockedOutputs = await that.wallet.getOutputs(new MoneroOutputQuery().setIsSpent(false).setTxQuery(new MoneroTxQuery().setIsLocked(false))); + let outputsToSweep: any[] = []; + for (let i = 0; i < spendableUnlockedOutputs.length && outputsToSweep.length < numOutputs; i++) { + if (spendableUnlockedOutputs[i].getAmount() > TestUtils.MAX_FEE) outputsToSweep.push(spendableUnlockedOutputs[i]); // output cannot be swept if amount does not cover fee + } + assert(outputsToSweep.length >= numOutputs, "Wallet does not have enough sweepable outputs; run send tests"); + + // sweep each output by key image + for (let output of outputsToSweep) { + testOutputWallet(output); + assert.equal(output.getIsSpent(), false); + assert.equal(output.getIsLocked(), false); + if (output.getAmount() <= TestUtils.MAX_FEE) continue; + + // sweep output to address + let address = await that.wallet.getAddress(output.getAccountIndex(), output.getSubaddressIndex()); + let config = new MoneroTxConfig({address: address, keyImage: output.getKeyImage().getHex(), relay: true}); + let tx = await that.wallet.sweepOutput(config); + + // test resulting tx + config.setCanSplit(false); + await that.testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true, isSweepResponse: true, isSweepOutputResponse: true}); + } + + // get outputs after sweeping + let afterOutputs = await that.wallet.getOutputs(); + + // swept output are now spent + for (let afterOutput of afterOutputs) { + for (let output of outputsToSweep) { + if (output.getKeyImage().getHex() === afterOutput.getKeyImage().getHex()) { + assert(afterOutput.getIsSpent(), "Output should be spent"); + } + } + } + }); + + if (testConfig.testRelays) + it("Can sweep dust without relaying", async function() { + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + + // sweep dust which returns empty list if no dust to sweep (dust does not exist after rct) + let txs = await that.wallet.sweepDust(false); + if (txs.length == 0) return; + + // test txs + let ctx = {config: new MoneroTxConfig(), isSendResponse: true, isSweepResponse: true}; + for (let tx of txs) { + await that.testTxWallet(tx, ctx); + } + + // relay txs + let metadatas: any = []; + for (let tx of txs) metadatas.push(tx.getMetadata()); + let txHashes = await that.wallet.relayTxs(metadatas); + assert.equal(txs.length, txHashes.length); + for (let txHash of txHashes) assert.equal(txHash.length, 64); + + // fetch and test txs + txs = await that.wallet.getTxs(new MoneroTxQuery().setHashes(txHashes)); + ctx.config.setRelay(true); + for (let tx of txs) { + await that.testTxWallet(tx, ctx); + } + }); + + if (testConfig.testRelays) + it("Can sweep dust", async function() { + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + + // sweep dust which returns empty list if no dust to sweep (dust does not exist after rct) + let txs = await that.wallet.sweepDust(true); + + // test any txs + let ctx = {wallet: that.wallet, isSendResponse: true, isSweepResponse: true}; + for (let tx of txs) { + await that.testTxWallet(tx, ctx); + } + }); + + it("Supports multisig wallets", async function() { + await that.testMultisig(2, 2, false); // n/n + await that.testMultisig(2, 3, false); // (n-1)/n + await that.testMultisig(2, 4, testConfig.testRelays && !testConfig.liteMode); // m/n + }); + + // ---------------------------- TEST RESETS ----------------------------- + + if (testConfig.testResets) + it("Can sweep subaddresses", async function() { + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + + const NUM_SUBADDRESSES_TO_SWEEP = 2; + + // collect subaddresses with balance and unlocked balance + let subaddresses: any[] = []; + let subaddressesBalance: any[] = []; + let subaddressesUnlocked: any[] = []; + for (let account of await that.wallet.getAccounts(true)) { + if (account.getIndex() === 0) continue; // skip default account + for (let subaddress of account.getSubaddresses()) { + subaddresses.push(subaddress); + if (subaddress.getBalance() > TestUtils.MAX_FEE) subaddressesBalance.push(subaddress); + if (subaddress.getUnlockedBalance() > TestUtils.MAX_FEE) subaddressesUnlocked.push(subaddress); + } + } + + // test requires at least one more subaddresses than the number being swept to verify it does not change + assert(subaddressesBalance.length >= NUM_SUBADDRESSES_TO_SWEEP + 1, "Test requires balance in at least " + (NUM_SUBADDRESSES_TO_SWEEP + 1) + " subaddresses from non-default acccount; run send-to-multiple tests"); + assert(subaddressesUnlocked.length >= NUM_SUBADDRESSES_TO_SWEEP + 1, "Wallet is waiting on unlocked funds"); + + // sweep from first unlocked subaddresses + for (let i = 0; i < NUM_SUBADDRESSES_TO_SWEEP; i++) { + + // sweep unlocked account + let unlockedSubaddress = subaddressesUnlocked[i]; + let config = new MoneroTxConfig({ + address: await that.wallet.getPrimaryAddress(), + accountIndex: unlockedSubaddress.getAccountIndex(), + subaddressIndex: unlockedSubaddress.getIndex(), + relay: true + }); + let txs = await that.wallet.sweepUnlocked(config); + + // test transactions + assert(txs.length > 0); + for (let tx of txs) { + assert(GenUtils.arrayContains(tx.getTxSet().getTxs(), tx)); + await that.testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true, isSweepResponse: true}); + } + + // assert unlocked balance is less than max fee + let subaddress = await that.wallet.getSubaddress(unlockedSubaddress.getAccountIndex(), unlockedSubaddress.getIndex()); + assert(subaddress.getUnlockedBalance() < TestUtils.MAX_FEE); + } + + // test subaddresses after sweeping + let subaddressesAfter: any[] = []; + for (let account of await that.wallet.getAccounts(true)) { + if (account.getIndex() === 0) continue; // skip default account + for (let subaddress of account.getSubaddresses()) { + subaddressesAfter.push(subaddress); + } + } + assert.equal(subaddressesAfter.length, subaddresses.length); + for (let i = 0; i < subaddresses.length; i++) { + let subaddressBefore = subaddresses[i]; + let subaddressAfter = subaddressesAfter[i]; + + // determine if subaddress was swept + let swept = false; + for (let j = 0; j < NUM_SUBADDRESSES_TO_SWEEP; j++) { + if (subaddressesUnlocked[j].getAccountIndex() === subaddressBefore.getAccountIndex() && subaddressesUnlocked[j].getIndex() === subaddressBefore.getIndex()) { + swept = true; + break; + } + } + + // assert unlocked balance is less than max fee if swept, unchanged otherwise + if (swept) { + assert(subaddressAfter.getUnlockedBalance() < TestUtils.MAX_FEE); + } else { + assert.equal(subaddressBefore.getUnlockedBalance(), subaddressAfter.getUnlockedBalance()); + } + } + }); + + if (testConfig.testResets) + it("Can sweep accounts", async function() { + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + const NUM_ACCOUNTS_TO_SWEEP = 1; + + // collect accounts with sufficient balance and unlocked balance to cover the fee + let accounts: any[] = await that.wallet.getAccounts(true); + let accountsBalance: any[] = []; + let accountsUnlocked: any[] = []; + for (let account of accounts) { + if (account.getIndex() === 0) continue; // skip default account + if (account.getBalance() > TestUtils.MAX_FEE) accountsBalance.push(account); + if (account.getUnlockedBalance() > TestUtils.MAX_FEE) accountsUnlocked.push(account); + } + + // test requires at least one more accounts than the number being swept to verify it does not change + assert(accountsBalance.length >= NUM_ACCOUNTS_TO_SWEEP + 1, "Test requires balance greater than the fee in at least " + (NUM_ACCOUNTS_TO_SWEEP + 1) + " non-default accounts; run send-to-multiple tests"); + assert(accountsUnlocked.length >= NUM_ACCOUNTS_TO_SWEEP + 1, "Wallet is waiting on unlocked funds"); + + // sweep from first unlocked accounts + for (let i = 0; i < NUM_ACCOUNTS_TO_SWEEP; i++) { + + // sweep unlocked account + let unlockedAccount = accountsUnlocked[i]; + let config = new MoneroTxConfig().setAddress(await that.wallet.getPrimaryAddress()).setAccountIndex(unlockedAccount.getIndex()).setRelay(true); + let txs = await that.wallet.sweepUnlocked(config); + + // test transactions + assert(txs.length > 0); + for (let tx of txs) { + await that.testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true, isSweepResponse: true}); + } + + // assert unlocked account balance less than max fee + let account = await that.wallet.getAccount(unlockedAccount.getIndex()); + assert(account.getUnlockedBalance() < TestUtils.MAX_FEE); + } + + // test accounts after sweeping + let accountsAfter = await that.wallet.getAccounts(true); + assert.equal(accountsAfter.length, accounts.length); + for (let i = 0; i < accounts.length; i++) { + let accountBefore = accounts[i]; + let accountAfter = accountsAfter[i]; + + // determine if account was swept + let swept = false; + for (let j = 0; j < NUM_ACCOUNTS_TO_SWEEP; j++) { + if (accountsUnlocked[j].getIndex() === accountBefore.getIndex()) { + swept = true; + break; + } + } + + // assert unlocked balance is less than max fee if swept, unchanged otherwise + if (swept) { + assert(accountAfter.getUnlockedBalance() < TestUtils.MAX_FEE); + } else { + assert.equal(accountBefore.getUnlockedBalance(), accountAfter.getUnlockedBalance()); + } + } + }); + + if (testConfig.testResets) + it("Can sweep the whole wallet by accounts", async function() { + assert(false, "Are you sure you want to sweep the whole wallet?"); + await testSweepWallet(); + }); + + if (testConfig.testResets) + it("Can sweep the whole wallet by subaddresses", async function() { + assert(false, "Are you sure you want to sweep the whole wallet?"); + await testSweepWallet(true); + }); + + async function testSweepWallet(sweepEachSubaddress = false) { + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(that.wallet); + + // verify 2 subaddresses with enough unlocked balance to cover the fee + let subaddressesBalance: MoneroSubaddress[] = []; + let subaddressesUnlocked: MoneroSubaddress[] = []; + for (let account of await that.wallet.getAccounts(true)) { + for (let subaddress of account.getSubaddresses()) { + if (subaddress.getBalance() > TestUtils.MAX_FEE) subaddressesBalance.push(subaddress); + if (subaddress.getUnlockedBalance() > TestUtils.MAX_FEE) subaddressesUnlocked.push(subaddress); + } + } + assert(subaddressesBalance.length >= 2, "Test requires multiple accounts with a balance greater than the fee; run send to multiple first"); + assert(subaddressesUnlocked.length >= 2, "Wallet is waiting on unlocked funds"); + + // sweep + let destination = await that.wallet.getPrimaryAddress(); + let config = new MoneroTxConfig().setAddress(destination).setSweepEachSubaddress(sweepEachSubaddress).setRelay(true); + let copy = config.copy(); + let txs = await that.wallet.sweepUnlocked(config); + assert.deepEqual(config, copy); // config is unchanged + for (let tx of txs) { + assert(GenUtils.arrayContains(tx.getTxSet().getTxs(), tx)); + assert.equal(tx.getTxSet().getMultisigTxHex(), undefined); + assert.equal(tx.getTxSet().getSignedTxHex(), undefined); + assert.equal(tx.getTxSet().getUnsignedTxHex(), undefined); + } + assert(txs.length > 0); + for (let tx of txs) { + config = new MoneroTxConfig({ + address: destination, + accountIndex: tx.getOutgoingTransfer().getAccountIndex(), + sweepEachSubaddress: sweepEachSubaddress, + relay: true + }); + await that.testTxWallet(tx, {wallet: that.wallet, config: config, isSendResponse: true, isSweepResponse: true}); + } + + // all unspent, unlocked outputs must be less than fee + let spendableOutputs = await that.wallet.getOutputs(new MoneroOutputQuery().setIsSpent(false).setTxQuery(new MoneroTxQuery().setIsLocked(false))); + for (let spendableOutput of spendableOutputs) { + assert(spendableOutput.getAmount() < TestUtils.MAX_FEE, "Unspent output should have been swept\n" + spendableOutput.toString()); + } + + // all subaddress unlocked balances must be less than fee + subaddressesBalance = []; + subaddressesUnlocked = []; + for (let account of await that.wallet.getAccounts(true)) { + for (let subaddress of account.getSubaddresses()) { + assert(subaddress.getUnlockedBalance() < TestUtils.MAX_FEE, "No subaddress should have more unlocked than the fee"); + } + } + } + + it("Can scan transactions by id", async function() { + + // get a few tx hashes + let txHashes: string[] = []; + let txs = await that.wallet.getTxs(); + if (txs.length < 3) throw new Error("Not enough txs to scan"); + for (let i = 0; i < 3; i++) txHashes.push(txs[i].getHash()); + + // start wallet without scanning + let scanWallet = await that.createWallet(new MoneroWalletConfig().setSeed(await that.wallet.getSeed()).setRestoreHeight(0)); + await scanWallet.stopSyncing(); // TODO: create wallet without daemon connection (offline does not reconnect, default connects to localhost, offline then online causes confirmed txs to disappear) + assert(await scanWallet.isConnectedToDaemon()); + + // scan txs + await scanWallet.scanTxs(txHashes); + + // TODO: scanning txs causes merge problems reconciling 0 fee, isMinerTx with test txs + + // // txs are scanned + // assertEquals(txHashes.size(), scanWallet.getTxs().size()); + // for (int i = 0; i < txHashes.size(); i++) { + // assertEquals(wallet.getTx(txHashes.get(i)), scanWallet.getTx(txHashes.get(i))); + // } + // List scannedTxs = scanWallet.getTxs(txHashes); + // assertEquals(txHashes.size(), scannedTxs.size()); + + // close wallet + await that.closeWallet(scanWallet, false); + }); + + // disabled so tests don't delete local cache + if (testConfig.testResets) + it("Can rescan the blockchain", async function() { + //assert(false, "Are you sure you want to discard local wallet data and rescan the blockchain?"); + await that.wallet.rescanBlockchain(); + for (let tx of await that.wallet.getTxs()) { + await that.testTxWallet(tx); + } + }); + + if (testConfig.testNonRelays) + it("Can freeze and thaw outputs", async function() { + + // get an available output + let outputs = await that.wallet.getOutputs(new MoneroOutputQuery().setIsSpent(false).setIsFrozen(false).setTxQuery(new MoneroTxQuery().setIsLocked(false))); + for (let output of outputs) assert.equal(false, output.getIsFrozen()); + assert(outputs.length > 0); + let output = outputs[0]; + assert.equal(false, output.getTx().getIsLocked()); + assert.equal(false, output.getIsSpent()); + assert.equal(false, output.getIsFrozen()); + assert.equal(false, await that.wallet.isOutputFrozen(output.getKeyImage().getHex())); + + // freeze output by key image + let numFrozenBefore = (await that.wallet.getOutputs(new MoneroOutputQuery().setIsFrozen(true))).length; + await that.wallet.freezeOutput(output.getKeyImage().getHex()); + assert.equal(true, await that.wallet.isOutputFrozen(output.getKeyImage().getHex())); + + // test querying + assert.equal(numFrozenBefore + 1, (await that.wallet.getOutputs(new MoneroOutputQuery().setIsFrozen(true))).length); + outputs = await that.wallet.getOutputs(new MoneroOutputQuery().setKeyImage(new MoneroKeyImage().setHex(output.getKeyImage().getHex())).setIsFrozen(true)); + assert.equal(1, outputs.length); + let outputFrozen = outputs[0]; + assert.equal(true, outputFrozen.getIsFrozen()); + assert.equal(output.getKeyImage().getHex(), outputFrozen.getKeyImage().getHex()); + + // try to sweep frozen output + try { + await that.wallet.sweepOutput(new MoneroTxConfig().setAddress(await that.wallet.getPrimaryAddress()).setKeyImage(output.getKeyImage().getHex())); + throw new Error("Should have thrown error"); + } catch (e: any) { + assert.equal("No outputs found", e.message); + } + + // try to freeze empty key image + try { + await that.wallet.freezeOutput(""); + throw new Error("Should have thrown error"); + } catch (e: any) { + assert.equal("Must specify key image to freeze", e.message); + } + + // try to freeze bad key image + try { + await that.wallet.freezeOutput("123"); + throw new Error("Should have thrown error"); + } catch (e: any) { + //assert.equal("Bad key image", e.message); + } + + // thaw output by key image + await that.wallet.thawOutput(output.getKeyImage().getHex()); + assert.equal(false, await that.wallet.isOutputFrozen(output.getKeyImage().getHex())); + + // test querying + assert.equal(numFrozenBefore, (await that.wallet.getOutputs(new MoneroOutputQuery().setIsFrozen(true))).length); + outputs = await that.wallet.getOutputs(new MoneroOutputQuery().setKeyImage(new MoneroKeyImage().setHex(output.getKeyImage().getHex())).setIsFrozen(true)); + assert.equal(0, outputs.length); + outputs = await that.wallet.getOutputs(new MoneroOutputQuery().setKeyImage(new MoneroKeyImage().setHex(output.getKeyImage().getHex())).setIsFrozen(false)); + assert.equal(1, outputs.length); + let outputThawed = outputs[0]; + assert.equal(false, outputThawed.getIsFrozen()); + assert.equal(output.getKeyImage().getHex(), outputThawed.getKeyImage().getHex()); + }); + + if (testConfig.testNonRelays) + it("Provides key images of spent outputs", async function() { + let accountIndex = 0; + let subaddressIndex = (await that.wallet.getSubaddresses(0)).length > 1 ? 1 : 0; // TODO: avoid subaddress 0 which is more likely to fail transaction sanity check + + // test unrelayed single transaction + testSpendTx(await that.wallet.createTx(new MoneroTxConfig().addDestination(await that.wallet.getPrimaryAddress(), TestUtils.MAX_FEE).setAccountIndex(accountIndex))); + + // test unrelayed split transactions + for (let tx of await that.wallet.createTxs(new MoneroTxConfig().addDestination(await that.wallet.getPrimaryAddress(), TestUtils.MAX_FEE).setAccountIndex(accountIndex))) { + testSpendTx(tx); + } + + // test unrelayed sweep dust + let dustKeyImages: any[] = []; + for (let tx of await that.wallet.sweepDust(false)) { + testSpendTx(tx); + for (let input of tx.getInputs()) dustKeyImages.push(input.getKeyImage().getHex()); + } + + // get available outputs above min amount + let outputs = await that.wallet.getOutputs(new MoneroOutputQuery().setAccountIndex(accountIndex).setSubaddressIndex(subaddressIndex).setIsSpent(false).setIsFrozen(false).setTxQuery(new MoneroTxQuery().setIsLocked(false)).setMinAmount(TestUtils.MAX_FEE)); + + // filter dust outputs + let dustOutputs: any[] = []; + for (let output of outputs) { + if (dustKeyImages.includes(output.getKeyImage().getHex())) dustOutputs.push(output); + } + outputs = outputs.filter(output => !dustOutputs.includes(output)); // remove dust outputs + + // test unrelayed sweep output + testSpendTx(await that.wallet.sweepOutput(new MoneroTxConfig().setAddress(await that.wallet.getPrimaryAddress()).setKeyImage(outputs[0].getKeyImage().getHex()))); + + // test unrelayed sweep wallet ensuring all non-dust outputs are spent + let availableKeyImages = new Set(); + for (let output of outputs) availableKeyImages.add(output.getKeyImage().getHex()); + let sweptKeyImages = new Set(); + let txs = await that.wallet.sweepUnlocked(new MoneroTxConfig().setAccountIndex(accountIndex).setSubaddressIndex(subaddressIndex).setAddress(await that.wallet.getPrimaryAddress())); + for (let tx of txs) { + testSpendTx(tx); + for (let input of tx.getInputs()) sweptKeyImages.add(input.getKeyImage().getHex()); + } + assert(sweptKeyImages.size > 0); + + // max skipped output is less than max fee amount + let maxSkippedOutput: MoneroOutputWallet | undefined = undefined; + for (let output of outputs) { + if (!sweptKeyImages.has(output.getKeyImage().getHex())) { + if (maxSkippedOutput === undefined || maxSkippedOutput.getAmount() < output.getAmount()) { + maxSkippedOutput = output; + } + } + } + assert(maxSkippedOutput === undefined || maxSkippedOutput.getAmount() < TestUtils.MAX_FEE); + }); + + function testSpendTx(spendTx) { + assert.notEqual(undefined, spendTx.getInputs()); + assert(spendTx.getInputs().length > 0); + for (let input of spendTx.getInputs()) assert(input.getKeyImage().getHex()); + } + + if (testConfig.testNonRelays) + it("Can prove unrelayed txs", async function() { + + // create unrelayed tx to verify + let address1 = await TestUtils.getExternalWalletAddress(); + let address2 = await that.wallet.getAddress(0, 0); + let address3 = await that.wallet.getAddress(1, 0); + let tx = await that.wallet.createTx(new MoneroTxConfig() + .setAccountIndex(0) + .addDestination(address1, TestUtils.MAX_FEE) + .addDestination(address2, TestUtils.MAX_FEE * (2n)) + .addDestination(address3, TestUtils.MAX_FEE * (3n))); + + // submit tx to daemon but do not relay + let result = await that.daemon.submitTxHex(tx.getFullHex(), true); + assert.equal(result.getIsGood(), true); + + // create random wallet to verify transfers + let verifyingWallet = await that.createWallet(new MoneroWalletConfig()); + + // verify transfer 1 + let check = await verifyingWallet.checkTxKey(tx.getHash(), tx.getKey(), address1); + assert.equal(check.getIsGood(), true); + assert.equal(check.getInTxPool(), true); + assert.equal(check.getNumConfirmations(), 0); + assert.equal(check.getReceivedAmount().toString(), TestUtils.MAX_FEE.toString()); + + // verify transfer 2 + check = await verifyingWallet.checkTxKey(tx.getHash(), tx.getKey(), address2); + assert.equal(check.getIsGood(), true); + assert.equal(check.getInTxPool(), true); + assert.equal(check.getNumConfirmations(), 0); + assert(check.getReceivedAmount() >= TestUtils.MAX_FEE * 2n); // + change amount + + // verify transfer 3 + check = await verifyingWallet.checkTxKey(tx.getHash(), tx.getKey(), address3); + assert.equal(check.getIsGood(), true); + assert.equal(check.getInTxPool(), true); + assert.equal(check.getNumConfirmations(), 0); + assert.equal(check.getReceivedAmount().toString(), (TestUtils.MAX_FEE * 3n).toString()); + + // cleanup + await that.daemon.flushTxPool(tx.getHash()); + await that.closeWallet(verifyingWallet); + }); + }); + + if (testConfig.testNonRelays) + it("Can get the default fee priority", async function() { + const defaultPriority = await that.wallet.getDefaultFeePriority(); + assert(defaultPriority > 0); + }); + } + + // -------------------------------- PRIVATE --------------------------------- + + async getSubaddressesWithBalance() { + let subaddresses: any[] = []; + for (let account of await this.wallet.getAccounts(true)) { + for (let subaddress of account.getSubaddresses()) { + if (subaddress.getBalance() > 0) subaddresses.push(subaddress); + } + } + return subaddresses; + } + + async getSubaddressesWithUnlockedBalance() { + let subaddresses: any[] = []; + for (let account of await this.wallet.getAccounts(true)) { + for (let subaddress of account.getSubaddresses()) { + if (subaddress.getUnlockedBalance() > 0n) subaddresses.push(subaddress); + } + } + return subaddresses; + } + + protected async testGetSubaddressAddressOutOfRange() { + let accounts = await this.wallet.getAccounts(true); + let accountIdx = accounts.length - 1; + let subaddressIdx = accounts[accountIdx].getSubaddresses().length; + let address = await this.wallet.getAddress(accountIdx, subaddressIdx); + assert.notEqual(address, undefined); // subclass my override with custom behavior (e.g. jni returns subaddress but wallet rpc does not) + assert(address.length > 0); + } + + /** + * Fetches and tests transactions according to the given query. + * + * TODO: convert query to query object and ensure each tx passes filter, same with getAndTestTransfer, getAndTestOutputs + */ + protected async getAndTestTxs(wallet, query: Partial | undefined, isExpected?): Promise { + let copy; + if (query !== undefined) { + if (query instanceof MoneroTxQuery) copy = query.copy(); + else copy = Object.assign({}, query); + } + let txs = await wallet.getTxs(query); + assert(Array.isArray(txs)); + if (isExpected === false) assert.equal(txs.length, 0); + if (isExpected === true) assert(txs.length > 0, "Transactions were expected but not found; run send tests?"); + for (let tx of txs) await this.testTxWallet(tx, Object.assign({wallet: wallet}, query)); + testGetTxsStructure(txs, query); + if (query !== undefined) { + if (query instanceof MoneroTxQuery) assert.deepEqual(query.toJson(), copy.toJson()); + else assert.deepEqual(query, copy); + } + return txs; + } + + /** + * Fetches and tests transfers according to the given query. + */ + protected async getAndTestTransfers(wallet: MoneroWallet, query: Partial, isExpected?): Promise { + let copy; + if (query !== undefined) { + if (query instanceof MoneroTransferQuery) copy = query.copy(); + else copy = Object.assign({}, query); + } + let transfers = await wallet.getTransfers(query); + assert(Array.isArray(transfers)); + if (isExpected === false) assert.equal(transfers.length, 0); + if (isExpected === true) assert(transfers.length > 0, "Transfers were expected but not found; run send tests?"); + for (let transfer of transfers) await this.testTxWallet(transfer.getTx(), Object.assign({wallet: wallet}, query)); + if (query !== undefined) { + if (query instanceof MoneroTransferQuery) assert.deepEqual(query.toJson(), copy.toJson()); + else assert.deepEqual(query, copy); + } + return transfers; + } + + /** + * Fetches and tests outputs according to the given query. + */ + protected async getAndTestOutputs(wallet: MoneroWallet, query: Partial, isExpected?) { + let copy; + if (query !== undefined) { + if (query instanceof MoneroOutputQuery) copy = query.copy(); + else copy = Object.assign({}, query); + } + let outputs = await wallet.getOutputs(query); + assert(Array.isArray(outputs)); + if (isExpected === false) assert.equal(outputs.length, 0); + if (isExpected === true) assert(outputs.length > 0, "Outputs were expected but not found; run send tests?"); + for (let output of outputs) testOutputWallet(output); + if (query !== undefined) { + if (query instanceof MoneroOutputQuery) assert.deepEqual(query.toJson(), copy.toJson()); + else assert.deepEqual(query, copy); + } + return outputs; + } + + protected async testTxsWallet(txs: MoneroTxWallet[], ctx) { + + // test each transaction + assert(txs.length > 0); + for (let tx of txs) await this.testTxWallet(tx, ctx); + + // test destinations across transactions + if (ctx.config && ctx.config.getDestinations()) { + let destinationIdx = 0; + let subtractFeeFromDestinations = ctx.config.getSubtractFeeFrom() && ctx.config.getSubtractFeeFrom().length > 0; + for (let tx of txs) { + + // TODO: remove this after >18.3.1 when amounts_by_dest_list is official + if (tx.getOutgoingTransfer().getDestinations() === undefined) { + console.warn("Tx missing destinations"); + return; + } + + let amountDiff = BigInt(0); + for (let destination of tx.getOutgoingTransfer().getDestinations()) { + let ctxDestination = ctx.config.getDestinations()[destinationIdx]; + assert.equal(destination.getAddress(), ctxDestination.getAddress()); + if (subtractFeeFromDestinations) amountDiff = amountDiff + ctxDestination.getAmount() - destination.getAmount(); + else assert.equal(destination.getAmount().toString(), ctxDestination.getAmount().toString()); + destinationIdx++; + } + if (subtractFeeFromDestinations) assert.equal(tx.getFee().toString(), amountDiff.toString()); + } + assert.equal(ctx.config.getDestinations().length, destinationIdx); + } + } + + /** + * Tests a wallet transaction with a test configuration. + * + * @param tx is the wallet transaction to test + * @param ctx specifies test configuration + * ctx.wallet is used to cross reference tx info if available + * ctx.config specifies the tx's originating send configuration + * ctx.isSendResponse indicates if the tx is built from a send response, which contains additional fields (e.g. key) + * ctx.hasDestinations specifies if the tx has an outgoing transfer with destinations, undefined if doesn't matter + * ctx.includeOutputs specifies if outputs were fetched and should therefore be expected with incoming transfers + */ + protected async testTxWallet(tx: MoneroTxWallet, ctx?: any) { + + // validate / sanitize inputs + ctx = Object.assign({}, ctx); + delete ctx.wallet; // TODO: re-enable + if (!(tx instanceof MoneroTxWallet)) { + console.log("Tx is not a MoneroTxWallet!"); + console.log(tx); + } + assert(tx instanceof MoneroTxWallet); + if (ctx.wallet) assert(ctx.wallet instanceof MoneroWallet); + assert(ctx.hasDestinations == undefined || typeof ctx.hasDestinations === "boolean"); + if (ctx.isSendResponse === undefined || ctx.config === undefined) { + assert.equal(ctx.isSendResponse, undefined, "if either config or isSendResponse is defined, they must both be defined"); + assert.equal(ctx.config, undefined, "if either config or isSendResponse is defined, they must both be defined"); + } + + // test common field types + assert.equal(typeof tx.getHash(), "string"); + assert.equal(typeof tx.getIsConfirmed(), "boolean"); + assert.equal(typeof tx.getIsMinerTx(), "boolean"); + assert.equal(typeof tx.getIsFailed(), "boolean"); + assert.equal(typeof tx.getIsRelayed(), "boolean"); + assert.equal(typeof tx.getInTxPool(), "boolean"); + assert.equal(typeof tx.getIsLocked(), "boolean"); + TestUtils.testUnsignedBigInt(tx.getFee()); + if (tx.getPaymentId()) assert.notEqual(tx.getPaymentId(), MoneroTx.DEFAULT_PAYMENT_ID); // default payment id converted to undefined + if (tx.getNote()) assert(tx.getNote().length > 0); // empty notes converted to undefined + assert(tx.getUnlockTime() >= BigInt(0)); + assert.equal(tx.getSize(), undefined); // TODO monero-wallet-rpc: add tx_size to get_transfers and get_transfer_by_txid + assert.equal(tx.getReceivedTimestamp(), undefined); // TODO monero-wallet-rpc: return received timestamp (asked to file issue if wanted) + + // test send tx + if (ctx.isSendResponse) { + assert(tx.getWeight() > 0); + assert.notEqual(tx.getInputs(), undefined); + assert(tx.getInputs().length > 0); + for (let input of tx.getInputs()) assert(input.getTx() === tx); + } else { + assert.equal(tx.getWeight(), undefined); + assert.equal(tx.getInputs(), undefined); + } + + // test confirmed + if (tx.getIsConfirmed()) { + assert(tx.getBlock()); + assert(tx.getBlock().getTxs().includes(tx)); + assert(tx.getBlock().getHeight() > 0); + assert(tx.getBlock().getTimestamp() > 0); + assert.equal(tx.getIsRelayed(), true); + assert.equal(tx.getIsFailed(), false); + assert.equal(tx.getInTxPool(), false); + assert.equal(tx.getRelay(), true); + assert.equal(tx.getIsDoubleSpendSeen(), false); + assert(tx.getNumConfirmations() > 0); + } else { + assert.equal(undefined, tx.getBlock()); + assert.equal(0, tx.getNumConfirmations()); + } + + // test in tx pool + if (tx.getInTxPool()) { + assert.equal(tx.getIsConfirmed(), false); + assert.equal(tx.getRelay(), true); + assert.equal(tx.getIsRelayed(), true); + assert.equal(tx.getIsDoubleSpendSeen(), false); // TODO: test double spend attempt + assert.equal(tx.getIsLocked(), true); + + // these should be initialized unless a response from sending + if (!ctx.isSendResponse) { + //assert(tx.getReceivedTimestamp() > 0); // TODO: re-enable when received timestamp returned in wallet rpc + } + } else { + assert.equal(tx.getLastRelayedTimestamp(), undefined); + } + + // test miner tx + if (tx.getIsMinerTx()) { + assert.equal(tx.getFee(), 0n); + assert(tx.getIncomingTransfers().length > 0); + } + + // test failed // TODO: what else to test associated with failed + if (tx.getIsFailed()) { + assert(tx.getOutgoingTransfer() instanceof MoneroTransfer); + //assert(tx.getReceivedTimestamp() > 0); // TODO: re-enable when received timestamp returned in wallet rpc + } else { + if (tx.getIsRelayed()) assert.equal(tx.getIsDoubleSpendSeen(), false); + else { + assert.equal(tx.getIsRelayed(), false); + assert.notEqual(tx.getRelay(), true); + assert.equal(tx.getIsDoubleSpendSeen(), undefined); + } + } + assert.equal(tx.getLastFailedHeight(), undefined); + assert.equal(tx.getLastFailedHash(), undefined); + + // received time only for tx pool or failed txs + if (tx.getReceivedTimestamp() !== undefined) { + assert(tx.getInTxPool() || tx.getIsFailed()); + } + + // test relayed tx + if (tx.getIsRelayed()) assert.equal(tx.getRelay(), true); + if (tx.getRelay() !== true) assert.equal(tx.getIsRelayed(), false); + + // test outgoing transfer per configuration + if (ctx.isOutgoing === false) assert(tx.getOutgoingTransfer() === undefined); + if (ctx.hasDestinations) assert(tx.getOutgoingTransfer() && tx.getOutgoingTransfer().getDestinations().length > 0); // TODO: this was typo with getDestionations so is this actually being tested? + + // test outgoing transfer + if (tx.getOutgoingTransfer()) { + assert(tx.getIsOutgoing()); + await testTransfer(tx.getOutgoingTransfer(), ctx); + if (ctx.isSweepResponse) assert.equal(tx.getOutgoingTransfer().getDestinations().length, 1); + + // TODO: handle special cases + } else { + assert(tx.getIncomingTransfers().length > 0); + assert.equal(tx.getOutgoingAmount(), undefined); + assert.equal(tx.getOutgoingTransfer(), undefined); + assert.equal(tx.getRingSize(), undefined); + assert.equal(tx.getFullHex(), undefined); + assert.equal(tx.getMetadata(), undefined); + assert.equal(tx.getKey(), undefined); + } + + // test incoming transfers + if (tx.getIncomingTransfers()) { + assert(tx.getIsIncoming()); + assert(tx.getIncomingTransfers().length > 0); + TestUtils.testUnsignedBigInt(tx.getIncomingAmount()); + assert.equal(tx.getIsFailed(), false); + + // test each transfer and collect transfer sum + let transferSum = BigInt(0); + for (let transfer of tx.getIncomingTransfers()) { + await testTransfer(transfer, ctx); + transferSum += transfer.getAmount(); + if (ctx.wallet) assert.equal(transfer.getAddress(), await ctx.wallet.getAddress(transfer.getAccountIndex(), transfer.getSubaddressIndex())); + + // TODO special case: transfer amount of 0 + } + + // incoming transfers add up to incoming tx amount + assert.equal(transferSum, tx.getIncomingAmount()) + } else { + assert(tx.getOutgoingTransfer()); + assert.equal(tx.getIncomingAmount(), undefined); + assert.equal(tx.getIncomingTransfers(), undefined); + } + + // test tx results from send or relay + if (ctx.isSendResponse) { + + // test tx set + assert.notEqual(tx.getTxSet(), undefined); + let found = false; + for (let aTx of tx.getTxSet().getTxs()) { + if (aTx === tx) { + found = true; + break; + } + } + if (ctx.isCopy) assert(!found); // copy will not have back reference from tx set + else assert(found); + + // test common attributes + let config = ctx.config as MoneroTxConfig; + assert.equal(tx.getIsConfirmed(), false); + await testTransfer(tx.getOutgoingTransfer(), ctx); + assert.equal(tx.getRingSize(), MoneroUtils.RING_SIZE); + assert.equal(tx.getUnlockTime().toString(), BigInt(0).toString()); + assert.equal(tx.getBlock(), undefined); + assert(tx.getKey().length > 0); + assert.equal(typeof tx.getFullHex(), "string"); + assert(tx.getFullHex().length > 0); + assert(tx.getMetadata()); + assert.equal(tx.getReceivedTimestamp(), undefined); + assert.equal(tx.getIsLocked(), true); + + // test locked state + if (BigInt(0) === tx.getUnlockTime()) assert.equal(!tx.getIsLocked(), tx.getIsConfirmed()); + else assert.equal(tx.getIsLocked(), true); + if (tx.getOutputs() !== undefined) { + for (let output of tx.getOutputsWallet()) { + assert.equal(output.getIsLocked(), tx.getIsLocked()); + } + } + + // test destinations of sent tx + if (tx.getOutgoingTransfer().getDestinations() === undefined) { + assert(config.getCanSplit()); + console.warn("Destinations not returned from split transactions"); // TODO: remove this after >18.3.1 when amounts_by_dest_list official + } else { + assert(tx.getOutgoingTransfer().getDestinations()); + assert(tx.getOutgoingTransfer().getDestinations().length > 0); + let subtractFeeFromDestinations = ctx.config.getSubtractFeeFrom() && ctx.config.getSubtractFeeFrom().length > 0; + if (ctx.isSweepResponse) { + assert.equal(config.getDestinations().length, 1); + assert.equal(undefined, config.getDestinations()[0].getAmount()); + if (!subtractFeeFromDestinations) { + assert.equal(tx.getOutgoingTransfer().getDestinations()[0].getAmount().toString(), tx.getOutgoingTransfer().getAmount().toString()); + } + } + } + + // test relayed txs + if (config.getRelay()) { + assert.equal(tx.getInTxPool(), true); + assert.equal(tx.getRelay(), true); + assert.equal(tx.getIsRelayed(), true); + assert(tx.getLastRelayedTimestamp() > 0); + assert.equal(tx.getIsDoubleSpendSeen(), false); + } + + // test non-relayed txs + else { + assert.equal(tx.getInTxPool(), false); + assert.notEqual(tx.getRelay(), true); + assert.equal(tx.getIsRelayed(), false); + assert.equal(tx.getLastRelayedTimestamp(), undefined); + assert.equal(tx.getIsDoubleSpendSeen(), undefined); + } + } + + // test tx result query + else { + assert.equal(tx.getTxSet(), undefined); // tx set only initialized on send responses + assert.equal(tx.getRingSize(), undefined); + assert.equal(tx.getKey(), undefined); + assert.equal(tx.getFullHex(), undefined); + assert.equal(tx.getMetadata(), undefined); + assert.equal(tx.getLastRelayedTimestamp(), undefined); + } + + // test inputs + if (tx.getIsOutgoing() && ctx.isSendResponse) { + assert(tx.getInputs() !== undefined); + assert(tx.getInputs().length > 0); + } else { + if (tx.getInputs()) for (let input of tx.getInputs()) testInputWallet(input); + } + + // test outputs + if (tx.getIsIncoming() && ctx.includeOutputs) { + if (tx.getIsConfirmed()) { + assert(tx.getOutputs() !== undefined); + assert(tx.getOutputs().length > 0); + } else { + assert(tx.getOutputs() === undefined); + } + + } + if (tx.getOutputs()) for (let output of tx.getOutputs()) testOutputWallet(output); + + // test deep copy + if (!ctx.isCopy) await this.testTxWalletCopy(tx, ctx); + } + + // TODO: move below testTxWalletCopy + protected async testTxWalletCopy(tx, ctx) { + + // copy tx and assert deep equality + let copy = tx.copy(); + assert(copy instanceof MoneroTxWallet); + assert.deepEqual(copy.toJson(), tx.toJson()); + + // test different references + if (tx.getOutgoingTransfer()) { + assert(tx.getOutgoingTransfer() !== copy.getOutgoingTransfer()); + assert(tx.getOutgoingTransfer().getTx() !== copy.getOutgoingTransfer().getTx()); + if (tx.getOutgoingTransfer().getDestinations()) { + assert(tx.getOutgoingTransfer().getDestinations() !== copy.getOutgoingTransfer().getDestinations()); + for (let i = 0; i < tx.getOutgoingTransfer().getDestinations().length; i++) { + assert.deepEqual(copy.getOutgoingTransfer().getDestinations()[i], tx.getOutgoingTransfer().getDestinations()[i]); + assert(tx.getOutgoingTransfer().getDestinations()[i] !== copy.getOutgoingTransfer().getDestinations()[i]); + } + } + } + if (tx.getIncomingTransfers()) { + for (let i = 0; i < tx.getIncomingTransfers().length; i++) { + assert.deepEqual(copy.getIncomingTransfers()[i].toJson(), tx.getIncomingTransfers()[i].toJson()); + assert(tx.getIncomingTransfers()[i] !== copy.getIncomingTransfers()[i]); + } + } + if (tx.getInputs()) { + for (let i = 0; i < tx.getInputs().length; i++) { + assert.deepEqual(copy.getInputs()[i].toJson(), tx.getInputs()[i].toJson()); + assert(tx.getInputs()[i] !== copy.getInputs()[i]); + } + } + if (tx.getOutputs()) { + for (let i = 0; i < tx.getOutputs().length; i++) { + assert.deepEqual(copy.getOutputs()[i].toJson(), tx.getOutputs()[i].toJson()); + assert(tx.getOutputs()[i] !== copy.getOutputs()[i]); + } + } + + // test copied tx + ctx = Object.assign({}, ctx); + ctx.isCopy = true; + if (tx.getBlock()) copy.setBlock(tx.getBlock().copy().setTxs([copy])); // copy block for testing + await this.testTxWallet(copy, ctx); + + // test merging with copy + let merged = copy.merge(copy.copy()); + assert.equal(merged.toString(), tx.toString()); + } + + protected async testMultisig(M, N, testTx) { + + // create N participants + let participants: MoneroWallet[] = []; + for (let i = 0; i < N; i++) participants.push(await this.createWallet(new MoneroWalletConfig())); + + // test multisig + let err; + try { + await this.testMultisigParticipants(participants, M, N, testTx); + } catch (e: any) { + err = e; + } + + // stop mining at end of test + try { await this.daemon.stopMining(); } + catch (err2) { } + + // save and close participants + for (let participant of participants) await this.closeWallet(participant, true); + if (err) throw err; + } + + protected async testMultisigParticipants(participants, M, N, testTx) { + console.log("testMultisig(" + M + ", " + N + ")"); + assert.equal(N, participants.length); + + // prepare multisig hexes + let preparedMultisigHexes: string[] = []; + for (let i = 0; i < N; i++) { + let participant = participants[i]; + preparedMultisigHexes.push(await participant.prepareMultisig()); + } + + // make wallets multisig + let madeMultisigHexes: string[] = []; + for (let i = 0; i < participants.length; i++) { + let participant = participants[i]; + + // collect prepared multisig hexes from wallet's peers + let peerMultisigHexes: string[] = []; + for (let j = 0; j < participants.length; j++) if (j !== i) peerMultisigHexes.push(preparedMultisigHexes[j]); + + // test bad input + try { + await participant.makeMultisig(["asd", "dsa"], M, TestUtils.WALLET_PASSWORD); + throw new Error("Should have thrown error making wallet multisig with bad input"); + } catch (err: any) { + if (!(err instanceof MoneroError)) throw err; + if (err.message !== "Kex message unexpectedly small.") console.warn("Unexpected error message: " + err.message); + } + + // make the wallet multisig + let multisigHex = await participant.makeMultisig(peerMultisigHexes, M, TestUtils.WALLET_PASSWORD); + madeMultisigHexes.push(multisigHex); + } + + // try to get seed before wallet initialized + try { + await participants[0].getSeed(); + throw new Error("Should have thrown exception getting multisig seed before initialized"); + } catch (err: any) { + assert.equal("This wallet is multisig, but not yet finalized", err.message); + } + + // exchange keys N - M + 1 times + let address = undefined; + assert.equal(madeMultisigHexes.length, N); + let prevMultisigHexes: string[] = madeMultisigHexes; + for (let i = 0; i < N - M + 1; i++) { + //console.log("Exchanging multisig keys round " + (i + 1) + " / " + (N - M)); + + // exchange multisig keys with each wallet and collect results + let exchangeMultisigHexes: string[] = []; + for (let j = 0; j < participants.length; j++) { + let participant = participants[j]; + + // test bad input + try { + await participant.exchangeMultisigKeys([], TestUtils.WALLET_PASSWORD); + throw new Error("Should have thrown error exchanging multisig keys with bad input"); + } catch (err: any) { + if (!(err instanceof MoneroError)) throw err; + assert(err.message.length > 0); + } + + // collect the multisig hexes of the wallet's peers from last round + let peerMultisigHexes: string[] = []; + for (let k = 0; k < participants.length; k++) if (k !== j) peerMultisigHexes.push(prevMultisigHexes[k]); + + // import the multisig hexes of the wallet's peers + let result = await participant.exchangeMultisigKeys(peerMultisigHexes, TestUtils.WALLET_PASSWORD); + + // test result + assert.notEqual(result.getMultisigHex(), undefined); + assert(result.getMultisigHex().length > 0); + if (i === N - M) { // result on last round has address + assert.notEqual(result.getAddress(), undefined); + assert(result.getAddress().length > 0); + if (address === undefined) address = result.getAddress(); + else assert.equal(result.getAddress(), address); + } else { + assert.equal(result.getAddress(), undefined); + exchangeMultisigHexes.push(result.getMultisigHex()); + } + } + + // use results for next round of exchange + prevMultisigHexes = exchangeMultisigHexes; + } + + // validate final multisig + let participant = participants[0]; + await MoneroUtils.validateAddress(await participant.getPrimaryAddress(), TestUtils.NETWORK_TYPE); + this.testMultisigInfo(await participant.getMultisigInfo(), M, N); + let seed = await participant.getSeed(); + assert(seed.length > 0); + + // restore participant from multisig seed + await this.closeWallet(participant); + participant = await this.createWallet(new MoneroWalletConfig().setRestoreHeight(await this.daemon.getHeight()).setSeed(seed).setIsMultisig(true)); + await MoneroUtils.validateAddress(await participant.getPrimaryAddress(), TestUtils.NETWORK_TYPE); + assert.equal(await participant.getPrimaryAddress(), address); + this.testMultisigInfo(await participant.getMultisigInfo(), M, N); + assert.equal(await participant.getSeed(), seed); + participants[0] = participant; + + // test sending a multisig transaction if configured + if (testTx) { + + // create accounts in the first multisig wallet to receive funds + let accountIdx = 0; + for (let i = 0; i < accountIdx; i++) await participant.createAccount(); + + // get destinations to subaddresses within the account of the multisig wallet + let numSubaddresses = 3; + let destinations: MoneroDestination[] = []; + for (let i = 0; i < numSubaddresses; i++) { + destinations.push(new MoneroDestination(await participant.getAddress(accountIdx, i), TestUtils.MAX_FEE * BigInt(2))); + if (i + 1 < numSubaddresses) participant.createSubaddress(accountIdx); + } + + // wait for txs to confirm and for sufficient unlocked balance + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(this.wallet); + await TestUtils.WALLET_TX_TRACKER.waitForUnlockedBalance(this.wallet, 0, undefined, TestUtils.MAX_FEE * (20n)); + + // send funds from the main test wallet to destinations in the first multisig wallet + assert(await this.wallet.getBalance() > 0n); + console.log("Sending funds from main wallet"); + await this.wallet.createTx({accountIndex: 0, destinations: destinations, relay: true}); + let returnAddress = await this.wallet.getPrimaryAddress(); // funds will be returned to this address from the multisig wallet + + console.log("Starting mining"); + + // start mining to push the network along + await StartMining.startMining(); + + // wait for the multisig wallet's funds to unlock // TODO: replace with MoneroWalletListener.onOutputReceived() which is called when output unlocked + let lastNumConfirmations: number | undefined = undefined; + while (true) { + + // wait for a moment + await new Promise(function(resolve) { setTimeout(resolve, TestUtils.SYNC_PERIOD_IN_MS); }); + + // fetch and test outputs + let outputs = await participant.getOutputs(); + if (outputs.length === 0) console.log("No outputs reported yet"); + else { + + // print num confirmations + let height = await this.daemon.getHeight(); + let numConfirmations = height - outputs[0].getTx().getHeight(); + if (lastNumConfirmations === undefined || lastNumConfirmations !== numConfirmations) console.log("Output has " + (height - outputs[0].getTx().getHeight()) + " confirmations"); + lastNumConfirmations = numConfirmations; + + // outputs are not spent + for (let output of outputs) assert(output.getIsSpent() === false); + + // break if output is unlocked + if (!outputs[0].getIsLocked()) break; + } + } + + // stop mining + await this.daemon.stopMining(); + + // multisig wallet should have unlocked balance in subaddresses 0-3 + for (let i = 0; i < numSubaddresses; i++) { + assert((await participant.getUnlockedBalance(accountIdx, i)) > BigInt(0)); + } + let outputs = await participant.getOutputs({accountIndex: accountIdx}); + assert(outputs.length > 0); + if (outputs.length < 3) console.log("WARNING: not one output per subaddress?"); + //assert(outputs.length >= 3); // TODO + for (let output of outputs) assert.equal(output.getIsLocked(), false); + + // wallet requires importing multisig to be reliable + assert(await participant.isMultisigImportNeeded()); + + // attempt creating and relaying transaction without synchronizing with participants + try { + await participant.createTx({accountIndex: accountIdx, address: returnAddress, amount: TestUtils.MAX_FEE * BigInt(3)}); + throw new Error("Should have failed sending funds without synchronizing with peers"); + } catch (e: any) { + if (e.message !== "No transaction created") throw new Error(e); + } + + // synchronize the multisig participants since receiving outputs + console.log("Synchronizing participants"); + await this.synchronizeMultisigParticipants(participants); + + // expect error exporting key images + try { + await participant.exportKeyImages(true); + } catch (e: any) { + if (e.message.indexOf("key_image generated not matched with cached key image") < 0) throw new Error(e); + } + + // attempt relaying created transactions without co-signing + try { + await participant.createTxs({address: returnAddress, amount: TestUtils.MAX_FEE, accountIndex: accountIdx, subaddressIndex: 0, relay: true}); + throw new Error("Should have failed"); + } catch (e: any) { + if (e.message !== "Cannot relay multisig transaction until co-signed") throw new Error(e); + } + + // create txs to send funds from a subaddress in the multisig wallet + console.log("Sending"); + let txs = await participant.createTxs({address: returnAddress, amount: TestUtils.MAX_FEE, accountIndex: accountIdx, subaddressIndex: 0}); + assert(txs.length > 0); + let txSet = txs[0].getTxSet(); + assert.notEqual(txSet.getMultisigTxHex(), undefined); + assert.equal(txSet.getSignedTxHex(), undefined); + assert.equal(txSet.getUnsignedTxHex(), undefined); + + // parse multisig tx hex and test + await testDescribedTxSet(await participant.describeMultisigTxSet(txSet.getMultisigTxHex())); + + // sign the tx with participants 1 through M - 1 to meet threshold + let multisigTxHex = txSet.getMultisigTxHex(); + console.log("Signing"); + for (let i = 1; i < M; i++) { + let result = await participants[i].signMultisigTxHex(multisigTxHex); + multisigTxHex = result.getSignedMultisigTxHex(); + } + + //console.log("Submitting signed multisig tx hex: " + multisigTxHex); + + // submit the signed multisig tx hex to the network + console.log("Submitting"); + let txHashes = await participant.submitMultisigTxHex(multisigTxHex); + assert(txHashes.length > 0); + + // synchronize the multisig participants since spending outputs + console.log("Synchronizing participants"); + await this.synchronizeMultisigParticipants(participants); + + // fetch the wallet's multisig txs + let multisigTxs = await participant.getTxs({hashes: txHashes}); + assert.equal(txHashes.length, multisigTxs.length); + + // sweep an output from subaddress [accountIdx,1] + outputs = await participant.getOutputs({accountIndex: accountIdx, subaddressIndex: 1}); + assert(outputs.length > 0); + assert(outputs[0].getIsSpent() === false); + txSet = (await participant.sweepOutput({address: returnAddress, keyImage: outputs[0].getKeyImage().getHex(), relay: true})).getTxSet(); + assert.notEqual(txSet.getMultisigTxHex(), undefined); + assert.equal(txSet.getSignedTxHex(), undefined); + assert.equal(txSet.getUnsignedTxHex(), undefined); + assert(txSet.getTxs().length > 0); + + // parse multisig tx hex and test + await testDescribedTxSet(await participant.describeMultisigTxSet(txSet.getMultisigTxHex())); + + // sign the tx with participants 1 through M - 1 to meet threshold + multisigTxHex = txSet.getMultisigTxHex(); + console.log("Signing sweep output"); + for (let i = 1; i < M; i++) { + let result = await participants[i].signMultisigTxHex(multisigTxHex); + multisigTxHex = result.getSignedMultisigTxHex(); + } + + // submit the signed multisig tx hex to the network + console.log("Submitting sweep output"); + txHashes = await participant.submitMultisigTxHex(multisigTxHex); + + // synchronize the multisig participants since spending outputs + console.log("Synchronizing participants"); + await this.synchronizeMultisigParticipants(participants); + + // fetch the wallet's multisig txs + multisigTxs = await participant.getTxs({hashes: txHashes}); + assert.equal(txHashes.length, multisigTxs.length); + + // sweep remaining balance + console.log("Sweeping"); + txs = await participant.sweepUnlocked({address: returnAddress, accountIndex: accountIdx, relay: true}); // TODO: test multisig with sweepEachSubaddress which will generate multiple tx sets without synchronizing participants + assert(txs.length > 0, "No txs created on sweepUnlocked"); + txSet = txs[0].getTxSet(); + for (let tx of txs) { + assert(tx.getTxSet() === txSet); // only one tx set created per account + let found = false; + for (let aTx of tx.getTxSet().getTxs()) { + if (aTx === tx) { + found = true; + break; + } + } + assert(found); // tx is contained in tx set + } + assert.notEqual(txSet.getMultisigTxHex(), undefined); + assert.equal(txSet.getSignedTxHex(), undefined); + assert.equal(txSet.getUnsignedTxHex(), undefined); + + // parse multisig tx hex and test + await testDescribedTxSet(await participant.describeTxSet(txSet)); + + // sign the tx with participants 1 through M - 1 to meet threshold + multisigTxHex = txSet.getMultisigTxHex(); + console.log("Signing sweep"); + for (let i = 1; i < M; i++) { + let result = await participants[i].signMultisigTxHex(multisigTxHex); + multisigTxHex = result.getSignedMultisigTxHex(); + } + + // submit the signed multisig tx hex to the network + console.log("Submitting sweep"); + txHashes = await participant.submitMultisigTxHex(multisigTxHex); + + // synchronize the multisig participants since spending outputs + console.log("Synchronizing participants"); + await this.synchronizeMultisigParticipants(participants); + + // fetch the wallet's multisig txs + multisigTxs = await participant.getTxs({hashes: txHashes}); + assert.equal(txHashes.length, multisigTxs.length); + } + } + + protected async synchronizeMultisigParticipants(wallets) { + + // collect multisig hex of all participants to synchronize + let multisigHexes: string[] = []; + for (let wallet of wallets) { + await wallet.sync(); + multisigHexes.push(await wallet.exportMultisigHex()); + } + + // import each wallet's peer multisig hex + for (let i = 0; i < wallets.length; i++) { + let peerMultisigHexes: string[] = []; + for (let j = 0; j < wallets.length; j++) if (j !== i) peerMultisigHexes.push(multisigHexes[j]); + let wallet = wallets[i]; + await wallet.sync(); + await wallet.importMultisigHex(peerMultisigHexes); + } + } + + protected async testMultisigInfo(info: MoneroMultisigInfo, M, N) { + assert(info.getIsMultisig()); + assert(info.getIsReady()); + assert.equal(info.getThreshold(), M); + assert.equal(info.getNumParticipants(), N); + } + + protected async testViewOnlyAndOfflineWallets(viewOnlyWallet: MoneroWallet, offlineWallet: MoneroWallet) { + + // wait for txs to confirm and for sufficient unlocked balance + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(this.wallet); + await TestUtils.WALLET_TX_TRACKER.waitForUnlockedBalance(this.wallet, 0, undefined, TestUtils.MAX_FEE * (4n)); + + // test getting txs, transfers, and outputs from view-only wallet + assert((await viewOnlyWallet.getTxs()).length, "View-only wallet has no transactions"); + assert((await viewOnlyWallet.getTransfers()).length, "View-only wallet has no transfers"); + assert((await viewOnlyWallet.getOutputs()).length, "View-only wallet has no outputs"); + + // collect info from main test wallet + let primaryAddress = await this.wallet.getPrimaryAddress(); + let privateViewKey = await this.wallet.getPrivateViewKey(); + + // test and sync view-only wallet + assert.equal(await viewOnlyWallet.getPrimaryAddress(), primaryAddress); + assert.equal(await viewOnlyWallet.getPrivateViewKey(), privateViewKey); + assert(await viewOnlyWallet.isViewOnly()); + let errMsg = "Should have failed"; + try { + await await viewOnlyWallet.getSeed(); + throw new Error(errMsg); + } catch (e: any) { + if (e.message === errMsg) throw e; + } + try { + await await viewOnlyWallet.getSeedLanguage(); + throw new Error(errMsg); + } catch (e: any) { + if (e.message === errMsg) throw e; + } + try { + await await viewOnlyWallet.getPrivateSpendKey(); + throw new Error(errMsg); + } catch (e: any) { + if (e.message === errMsg) throw e; + } + assert(await viewOnlyWallet.isConnectedToDaemon(), "Wallet created from keys is not connected to authenticated daemon"); // TODO + await viewOnlyWallet.sync(); + assert((await viewOnlyWallet.getTxs()).length > 0); + + // export outputs from view-only wallet + let outputsHex = await viewOnlyWallet.exportOutputs(); + + // test offline wallet + assert(!await offlineWallet.isConnectedToDaemon()); + assert(!await offlineWallet.isViewOnly()); + if (!(offlineWallet instanceof MoneroWalletRpc)) assert.equal(await offlineWallet.getSeed(), TestUtils.SEED); // TODO monero-project: cannot get seed from offline wallet rpc + assert.equal((await offlineWallet.getTxs(new MoneroTxQuery().setInTxPool(false))).length, 0); + + // import outputs to offline wallet + let numOutputsImported = await offlineWallet.importOutputs(outputsHex); + assert(numOutputsImported > 0, "No outputs imported"); + + // export key images from offline wallet + let keyImages = await offlineWallet.exportKeyImages(); + assert(keyImages.length > 0); + + // import key images to view-only wallet + assert(await viewOnlyWallet.isConnectedToDaemon()); + await viewOnlyWallet.importKeyImages(keyImages); + assert.equal((await viewOnlyWallet.getBalance()).toString(), (await this.wallet.getBalance()).toString()); + + // create unsigned tx using view-only wallet + let unsignedTx = await viewOnlyWallet.createTx({accountIndex: 0, address: primaryAddress, amount: TestUtils.MAX_FEE * (3n)}); + assert.equal(typeof unsignedTx.getTxSet().getUnsignedTxHex(), "string"); + assert(unsignedTx.getTxSet().getUnsignedTxHex()); + + // sign tx using offline wallet + let signedTxSet = await offlineWallet.signTxs(unsignedTx.getTxSet().getUnsignedTxHex()); + assert(signedTxSet.getSignedTxHex().length > 0); + assert.equal(signedTxSet.getTxs().length, 1); + assert(signedTxSet.getTxs()[0].getHash().length > 0); + + // parse or "describe" unsigned tx set + let describedTxSet = await offlineWallet.describeUnsignedTxSet(unsignedTx.getTxSet().getUnsignedTxHex()); + await testDescribedTxSet(describedTxSet); + + // submit signed tx using view-only wallet + if (this.testConfig.testRelays) { + let txHashes = await viewOnlyWallet.submitTxs(signedTxSet.getSignedTxHex()); + assert.equal(txHashes.length, 1); + assert.equal(txHashes[0].length, 64); + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(viewOnlyWallet); // wait for confirmation for other tests + } + } + + protected testInvalidAddressError(err) { + assert.equal("Invalid address", err.message); + } + + protected testInvalidTxHashError(err) { + assert.equal("TX hash has invalid format", err.message); + } + + protected testInvalidTxKeyError(err) { + assert.equal("Tx key has invalid format", err.message); + } + + protected testInvalidSignatureError(err) { + assert.equal("Signature size mismatch with additional tx pubkeys", err.message); + } + + protected testNoSubaddressError(err) { + assert.equal("Address must not be a subaddress", err.message); + } + + protected testSignatureHeaderCheckError(err) { + assert.equal("Signature header check error", err.message); + } +} + +// ------------------------------ PRIVATE STATIC ------------------------------ + +async function testAccount(account) { + + // test account + assert(account); + assert(account.getIndex() >= 0); + await MoneroUtils.validateAddress(account.getPrimaryAddress(), TestUtils.NETWORK_TYPE); + TestUtils.testUnsignedBigInt(account.getBalance()); + TestUtils.testUnsignedBigInt(account.getUnlockedBalance()); + await MoneroUtils.validateAddress(account.getPrimaryAddress(), TestUtils.NETWORK_TYPE); + TestUtils.testUnsignedBigInt(account.getBalance()); + TestUtils.testUnsignedBigInt(account.getUnlockedBalance()); + + // if given, test subaddresses and that their balances add up to account balances + if (account.getSubaddresses()) { + let balance = BigInt(0); + let unlockedBalance = BigInt(0); + for (let i = 0; i < account.getSubaddresses().length; i++) { + testSubaddress(account.getSubaddresses()[i]); + assert.equal(account.getSubaddresses()[i].getAccountIndex(), account.getIndex()); + assert.equal(account.getSubaddresses()[i].getIndex(), i); + balance = balance + (account.getSubaddresses()[i].getBalance()); + unlockedBalance = unlockedBalance + (account.getSubaddresses()[i].getUnlockedBalance()); + } + assert.equal(account.getBalance(), balance, "Subaddress balances " + balance.toString() + " != account " + account.getIndex() + " balance " + account.getBalance().toString()); + assert.equal(account.getUnlockedBalance(), unlockedBalance, "Subaddress unlocked balances " + unlockedBalance.toString() + " != account " + account.getIndex() + " unlocked balance " + account.getUnlockedBalance().toString()); + } + + // tag must be undefined or non-empty + let tag = account.getTag(); + assert(tag === undefined || tag.length > 0); +} + +function testSubaddress(subaddress) { + assert(subaddress.getAccountIndex() >= 0); + assert(subaddress.getIndex() >= 0); + assert(subaddress.getAddress()); + assert(subaddress.getLabel() === undefined || typeof subaddress.getLabel() === "string"); + if (typeof subaddress.getLabel() === "string") assert(subaddress.getLabel().length > 0); + TestUtils.testUnsignedBigInt(subaddress.getBalance()); + TestUtils.testUnsignedBigInt(subaddress.getUnlockedBalance()); + assert(subaddress.getNumUnspentOutputs() >= 0); + assert(typeof subaddress.getIsUsed() === "boolean"); + if (subaddress.getBalance() > 0n) assert(subaddress.getIsUsed()); + assert(subaddress.getNumBlocksToUnlock() >= 0); +} + +/** + * Gets random transactions. + * + * @param wallet is the wallet to query for transactions + * @param query configures the transactions to retrieve + * @param minTxs specifies the minimum number of transactions (undefined for no minimum) + * @param maxTxs specifies the maximum number of transactions (undefined for all filtered transactions) + * @return {MoneroTxWallet[]} are the random transactions + */ +async function getRandomTransactions(wallet, query, minTxs, maxTxs) { + let txs = await wallet.getTxs(query); + if (minTxs !== undefined) assert(txs.length >= minTxs, txs.length + "/" + minTxs + " transactions found with query: " + JSON.stringify(query)); + GenUtils.shuffle(txs); + if (maxTxs === undefined) return txs; + else return txs.slice(0, Math.min(maxTxs, txs.length)); +} + +async function testTransfer(transfer, ctx?) { + if (ctx === undefined) ctx = {}; + assert(transfer instanceof MoneroTransfer); + TestUtils.testUnsignedBigInt(transfer.getAmount()); + if (!ctx.isSweepOutputResponse) assert(transfer.getAccountIndex() >= 0); + if (transfer.getIsIncoming()) testIncomingTransfer(transfer); + else await testOutgoingTransfer(transfer, ctx); + + // transfer and tx reference each other + assert(transfer.getTx()); + if (transfer !== transfer.getTx().getOutgoingTransfer()) { + assert(transfer.getTx().getIncomingTransfers()); + assert(transfer.getTx().getIncomingTransfers().includes(transfer as MoneroIncomingTransfer), "Transaction does not reference given transfer"); + } +} + +function testIncomingTransfer(transfer) { + assert(transfer.getIsIncoming()); + assert(!transfer.getIsOutgoing()); + assert(transfer.getAddress()); + assert(transfer.getSubaddressIndex() >= 0); + assert(transfer.getNumSuggestedConfirmations() > 0); +} + +async function testOutgoingTransfer(transfer, ctx) { + assert(!transfer.getIsIncoming()); + assert(transfer.getIsOutgoing()); + if (!ctx.isSendResponse) assert(transfer.getSubaddressIndices()); + if (transfer.getSubaddressIndices()) { + assert(transfer.getSubaddressIndices().length >= 1); + for (let subaddressIdx of transfer.getSubaddressIndices()) assert(subaddressIdx >= 0); + } + if (transfer.getAddresses()) { + assert.equal(transfer.getAddresses().length, transfer.getSubaddressIndices().length); + for (let address of transfer.getAddresses()) assert(address); + } + + // test destinations sum to outgoing amount + if (transfer.getDestinations()) { + assert(transfer.getDestinations().length > 0); + let sum = BigInt(0); + for (let destination of transfer.getDestinations()) { + await testDestination(destination); + TestUtils.testUnsignedBigInt(destination.getAmount(), true); + sum += destination.getAmount(); + } + if (transfer.getAmount() !== sum) console.log(transfer.getTx().getTxSet() === undefined ? transfer.getTx().toString() : transfer.getTx().getTxSet().toString()); + assert.equal(sum.toString(), transfer.getAmount().toString()); + } +} + +async function testDestination(destination) { + await MoneroUtils.validateAddress(destination.getAddress(), TestUtils.NETWORK_TYPE); + TestUtils.testUnsignedBigInt(destination.getAmount(), true); +} + +function testInputWallet(input) { + assert(input); + assert(input.getKeyImage()); + assert(input.getKeyImage().getHex()); + assert(input.getKeyImage().getHex().length > 0); + assert(input.getAmount() === undefined); // must get info separately +} + +function testOutputWallet(output) { + assert(output); + assert(output instanceof MoneroOutputWallet); + assert(output.getAccountIndex() >= 0); + assert(output.getSubaddressIndex() >= 0); + assert(output.getIndex() >= 0); + assert.equal(typeof output.getIsSpent(), "boolean"); + assert.equal(typeof output.getIsLocked(), "boolean"); + assert.equal(typeof output.getIsFrozen(), "boolean"); + assert(output.getKeyImage()); + assert(output.getKeyImage() instanceof MoneroKeyImage); + assert(output.getKeyImage().getHex()); + TestUtils.testUnsignedBigInt(output.getAmount(), true); + + // output has circular reference to its transaction which has some initialized fields + let tx = output.getTx(); + assert(tx); + assert(tx instanceof MoneroTxWallet); + assert(tx.getOutputs().includes(output)); + assert(tx.getHash()); + assert.equal(typeof tx.getIsLocked(), "boolean"); + assert.equal(tx.getIsConfirmed(), true); // TODO monero-wallet-rpc: possible to get unconfirmed outputs? + assert.equal(tx.getIsRelayed(), true); + assert.equal(tx.getIsFailed(), false); + assert(tx.getHeight() > 0); + + // test copying + let copy = output.copy(); + assert(copy !== output); + assert.equal(copy.toString(), output.toString()); + assert.equal(copy.getTx(), undefined); // TODO: should output copy do deep copy of tx so models are graph instead of tree? Would need to work out circular references +} + +function testCommonTxSets(txs, hasSigned, hasUnsigned, hasMultisig) { + assert(txs.length > 0); + + // assert that all sets are same reference + let set; + for (let i = 0; i < txs.length; i++) { + assert(txs[i] instanceof MoneroTx); + if (i === 0) set = txs[i].getTxSet(); + else assert(txs[i].getTxSet() === set); + } + + // test expected set + assert(set); + if (hasSigned) { + assert(set.getSignedTxSet()); + assert(set.getSignedTxSet().length > 0); + } + if (hasUnsigned) { + assert(set.getUnsignedTxSet()); + assert(set.getUnsignedTxSet().length > 0); + } + if (hasMultisig) { + assert(set.getMultisigTxSet()); + assert(set.getMultisigTxSet().length > 0); + } +} + +function testCheckTx(tx, check: MoneroCheckTx) { + assert.equal(typeof check.getIsGood(), "boolean"); + if (check.getIsGood()) { + assert(check.getNumConfirmations() >= 0); + assert.equal(typeof check.getInTxPool(), "boolean"); + TestUtils.testUnsignedBigInt(check.getReceivedAmount()); + if (check.getInTxPool()) assert.equal(0, check.getNumConfirmations()); + else assert(check.getNumConfirmations() > 0); // TODO (monero-wall-rpc) this fails (confirmations is 0) for (at least one) transaction that has 1 confirmation on testCheckTxKey() + } else { + assert.equal(check.getNumConfirmations(), undefined); + assert.equal(check.getInTxPool(), undefined); + assert.equal(check.getReceivedAmount(), undefined); + } +} + +function testCheckReserve(check: MoneroCheckReserve) { + assert.equal(typeof check.getIsGood(), "boolean"); + if (check.getIsGood()) { + TestUtils.testUnsignedBigInt(check.getTotalAmount()); + assert(check.getTotalAmount() >= 0n); + TestUtils.testUnsignedBigInt(check.getUnconfirmedSpentAmount()); + assert(check.getUnconfirmedSpentAmount() >= 0n); + } else { + assert.equal(check.getTotalAmount(), undefined); + assert.equal(check.getUnconfirmedSpentAmount(), undefined); + } +} + +async function testDescribedTxSet(describedTxSet) { + assert.notEqual(describedTxSet, undefined); + assert(describedTxSet.getTxs().length > 0); + assert.equal(describedTxSet.getSignedTxHex(), undefined); + assert.equal(describedTxSet.getUnsignedTxHex(), undefined); + + // test each transaction + // TODO: use common tx wallet test? + assert.equal(describedTxSet.getMultisigTxHex(), undefined); + for (let describedTx of describedTxSet.getTxs()) { + assert(describedTx.getTxSet() === describedTxSet); + TestUtils.testUnsignedBigInt(describedTx.getInputSum(), true); + TestUtils.testUnsignedBigInt(describedTx.getOutputSum(), true); + TestUtils.testUnsignedBigInt(describedTx.getFee()); + TestUtils.testUnsignedBigInt(describedTx.getChangeAmount()); + if (describedTx.getChangeAmount() === 0n) assert.equal(describedTx.getChangeAddress(), undefined); + else await MoneroUtils.validateAddress(describedTx.getChangeAddress(), TestUtils.NETWORK_TYPE); + assert(describedTx.getRingSize() > 1); + assert (describedTx.getUnlockTime() >= 0n); + assert(describedTx.getNumDummyOutputs() >= 0); + assert(describedTx.getExtraHex()); + assert(describedTx.getPaymentId() === undefined || describedTx.getPaymentId().length > 0); + assert(describedTx.getIsOutgoing()); + assert.notEqual(describedTx.getOutgoingTransfer(), undefined); + assert.notEqual(describedTx.getOutgoingTransfer().getDestinations(), undefined); + assert(describedTx.getOutgoingTransfer().getDestinations().length > 0); + assert.equal(describedTx.getIsIncoming(), undefined); + for (let destination of describedTx.getOutgoingTransfer().getDestinations()) { + await testDestination(destination); + } + } +} + +async function testAddressBookEntry(entry) { + assert(entry.getIndex() >= 0); + await MoneroUtils.validateAddress(entry.getAddress(), TestUtils.NETWORK_TYPE); + assert.equal(typeof entry.getDescription(), "string"); +} + +/** + * Tests the integrity of the full structure in the given txs from the block down + * to transfers / destinations. + */ +function testGetTxsStructure(txs: MoneroTxWallet[], query?) { + + // normalize query + if (query === undefined) query = new MoneroTxQuery(); + if (!(query instanceof MoneroTxQuery)) query = new MoneroTxQuery(query); + + // collect unique blocks in order (using set and list instead of TreeSet for direct portability to other languages) + let seenBlocks = new Set(); + let blocks: MoneroBlock[] = []; + let unconfirmedTxs: MoneroTxWallet[] = []; + for (let tx of txs) { + if (tx.getBlock() === undefined) unconfirmedTxs.push(tx); + else { + assert(tx.getBlock().getTxs().includes(tx)); + if (!seenBlocks.has(tx.getBlock())) { + seenBlocks.add(tx.getBlock()); + blocks.push(tx.getBlock()); + } + } + } + + // tx hashes must be in order if requested + if (query.getHashes() !== undefined) { + assert.equal(txs.length, query.getHashes().length); + for (let i = 0; i < query.getHashes().length; i++) { + assert.equal(txs[i].getHash(), query.getHashes()[i]); + } + } + + // test that txs and blocks reference each other and blocks are in ascending order unless specific tx hashes requested + let index = 0; + let prevBlockHeight: number | undefined = undefined; + for (let block of blocks) { + if (prevBlockHeight === undefined) prevBlockHeight = block.getHeight(); + else if (query.getHashes() === undefined) assert(block.getHeight() > prevBlockHeight, "Blocks are not in order of heights: " + prevBlockHeight + " vs " + block.getHeight()); + for (let tx of block.getTxs()) { + assert(tx.getBlock() === block); + if (query.getHashes() === undefined) { + assert.equal(tx.getHash(), txs[index].getHash()); // verify tx order is self-consistent with blocks unless txs manually re-ordered by requesting by hash + assert(tx === txs[index]); + } + index++; + } + } + assert.equal(index + unconfirmedTxs.length, txs.length); + + // test that incoming transfers are in order of ascending accounts and subaddresses + for (let tx of txs) { + let prevAccountIdx: number | undefined = undefined; + let prevSubaddressIdx: number | undefined = undefined; + if (tx.getIncomingTransfers() === undefined) continue; + for (let transfer of tx.getIncomingTransfers()) { + if (prevAccountIdx === undefined) prevAccountIdx = transfer.getAccountIndex(); + else { + assert(prevAccountIdx <= transfer.getAccountIndex()); + if (prevAccountIdx < transfer.getAccountIndex()) { + prevSubaddressIdx = undefined; + prevAccountIdx = transfer.getAccountIndex(); + } + if (prevSubaddressIdx === undefined) prevSubaddressIdx = transfer.getSubaddressIndex(); + else assert(prevSubaddressIdx < transfer.getSubaddressIndex()); + } + } + } +} + +function countNumInstances(instances) { + let counts = new Map(); + for (let instance of instances) { + let count = counts.get(instance); + counts.set(instance, count === undefined ? 1 : count + 1); + } + return counts; +} + +function getModes(counts) { + let modes = new Set(); + let maxCount; + for (let key of counts.keys()) { + let count = counts.get(key); + if (maxCount === undefined || count > maxCount) maxCount = count; + } + for (let key of counts.keys()) { + let count = counts.get(key); + if (count === maxCount) modes.add(key); + } + return modes; +} + +/** + * Internal tester for output notifications. + */ +class ReceivedOutputNotificationTester extends MoneroWalletListener { + + txHash: string; + testComplete: boolean; + unlockedSeen: boolean; + lastOnNewBlockHeight: number; + lastOnBalancesChangedBalance: BigInt; + lastOnBalancesChangedUnlockedBalance: BigInt; + lastNotifiedOutput: MoneroOutputWallet; + + constructor(txHash) { + super(); + this.txHash = txHash; + this.testComplete = false; + this.unlockedSeen = false; + } + + async onNewBlock(height) { + this.lastOnNewBlockHeight = height; + } + + async onBalancesChanged(newBalance, newUnlockedBalance) { + this.lastOnBalancesChangedBalance = newBalance; + this.lastOnBalancesChangedUnlockedBalance = newUnlockedBalance; + } + + async onOutputReceived(output) { + if (output.getTx().getHash() === this.txHash) this.lastNotifiedOutput = output; + } +} + +/** + * Wallet listener to collect output notifications. + */ +class WalletNotificationCollector extends MoneroWalletListener { + + listening: any; + blockNotifications: any; + balanceNotifications: any; + outputsReceived: any; + outputsSpent: any; + lastNotification: any; + + constructor() { + super(); + this.listening = true; + this.blockNotifications = []; + this.balanceNotifications = []; + this.outputsReceived = []; + this.outputsSpent = []; + } + + async onNewBlock(height) { + assert(this.listening); + if (this.blockNotifications.length > 0) assert(height === this.blockNotifications[this.blockNotifications.length - 1] + 1); + this.blockNotifications.push(height); + } + + async onBalancesChanged(newBalance, newUnlockedBalance) { + assert(this.listening); + if (this.balanceNotifications.length > 0) { + this.lastNotification = this.balanceNotifications[this.balanceNotifications.length - 1]; + assert(newBalance.toString() !== this.lastNotification.balance.toString() || newUnlockedBalance.toString() !== this.lastNotification.unlockedBalance.toString()); + } + this.balanceNotifications.push({balance: newBalance, unlockedBalance: newUnlockedBalance}); + } + + async onOutputReceived(output) { + assert(this.listening); + this.outputsReceived.push(output); + } + + async onOutputSpent(output) { + assert(this.listening); + this.outputsSpent.push(output); + } + + getBlockNotifications() { + return this.blockNotifications; + } + + getBalanceNotifications() { + return this.balanceNotifications; + } + + getOutputsReceived(query?) { + return Filter.apply(query, this.outputsReceived); + } + + getOutputsSpent(query?) { + return Filter.apply(query, this.outputsSpent); + } + + setListening(listening) { + this.listening = listening; + } +} diff --git a/src/test/TestMoneroWalletFull.ts b/src/test/TestMoneroWalletFull.ts new file mode 100644 index 000000000..6747df496 --- /dev/null +++ b/src/test/TestMoneroWalletFull.ts @@ -0,0 +1,1388 @@ +import assert from "assert"; +import TestUtils from "./utils/TestUtils"; +import TestMoneroWalletCommon from "./TestMoneroWalletCommon"; +import StartMining from "./utils/StartMining"; +import WalletSyncPrinter from "./utils/WalletSyncPrinter"; +import WalletEqualityUtils from "./utils/WalletEqualityUtils"; +import {createWalletFull, + openWalletFull, + LibraryUtils, + MoneroWalletConfig, + GenUtils, + MoneroUtils, + MoneroNetworkType, + MoneroTxWallet, + MoneroOutputQuery, + MoneroOutputWallet, + MoneroRpcConnection, + MoneroWallet, + MoneroWalletFull, + MoneroWalletRpc} from "../../index"; + +/** + * Tests a Monero wallet using WebAssembly to bridge to monero-project's wallet2. + */ +export default class TestMoneroWalletFull extends TestMoneroWalletCommon { + + static FULL_TESTS_RUN: boolean; + + constructor(testConfig) { + super(testConfig); + } + + async beforeAll() { + await super.beforeAll(); + } + + async beforeEach(currentTest) { + await super.beforeEach(currentTest); + } + + async afterAll() { + await super.afterAll(); + TestMoneroWalletFull.FULL_TESTS_RUN = true; + } + + async afterEach(currentTest) { + await super.afterEach(currentTest); + + // print memory usage + console.log("WASM memory usage: " + await LibraryUtils.getWasmMemoryUsed()); + //console.log(process.memoryUsage()); + + // remove non-whitelisted wallets + let whitelist = [TestUtils.WALLET_NAME, "ground_truth", "moved"]; + let items = await (await TestUtils.getDefaultFs()).readdir(TestUtils.TEST_WALLETS_DIR, "buffer"); + for (let item of items) { + item = item + ""; // get filename as string + let found = false; + for (let whitelisted of whitelist) { + if (item === whitelisted || item === whitelisted + ".keys" || item === whitelisted + ".address.txt") { + found = true; + break; + } + } + if (!found) await (await TestUtils.getDefaultFs()).unlink(TestUtils.TEST_WALLETS_DIR + "/" + item); + } + } + + async getTestWallet() { + return await TestUtils.getWalletFull(); + } + + async getTestDaemon() { + return await TestUtils.getDaemonRpc(); + } + + async openWallet(config: Partial, startSyncing?: any): Promise { + + // assign defaults + config = new MoneroWalletConfig(config); + if (config.getPassword() === undefined) config.setPassword(TestUtils.WALLET_PASSWORD); + if (config.getNetworkType() === undefined) config.setNetworkType(TestUtils.NETWORK_TYPE); + if (config.getProxyToWorker() === undefined) config.setProxyToWorker(TestUtils.PROXY_TO_WORKER); + if (config.getServer() === undefined && !config.getConnectionManager()) config.setServer(TestUtils.getDaemonRpcConnection()); + if (config.getFs() === undefined) config.setFs(await TestUtils.getDefaultFs()); + + // open wallet + let wallet = await openWalletFull(config); + if (startSyncing !== false && await wallet.isConnectedToDaemon()) await wallet.startSyncing(TestUtils.SYNC_PERIOD_IN_MS); + return wallet; + } + + async createWallet(config?: Partial, startSyncing?): Promise { + + // assign defaults + config = new MoneroWalletConfig(config); + let random = config.getSeed() === undefined && config.getPrimaryAddress() === undefined; + if (config.getPath() === undefined) config.setPath(TestUtils.TEST_WALLETS_DIR + "/" + GenUtils.getUUID()); + if (config.getPassword() === undefined) config.setPassword(TestUtils.WALLET_PASSWORD); + if (config.getNetworkType() === undefined) config.setNetworkType(TestUtils.NETWORK_TYPE); + if (!config.getRestoreHeight() && !random) config.setRestoreHeight(0); + if (!config.getServer() && !config.getConnectionManager()) config.setServer(TestUtils.getDaemonRpcConnection()); + if (config.getProxyToWorker() === undefined) config.setProxyToWorker(TestUtils.PROXY_TO_WORKER); + if (config.getFs() === undefined) config.setFs(await TestUtils.getDefaultFs()); + + // create wallet + let wallet = await createWalletFull(config); + if (!random) assert.equal(await wallet.getRestoreHeight(), config.getRestoreHeight() === undefined ? 0 : config.getRestoreHeight()); + if (startSyncing !== false && await wallet.isConnectedToDaemon()) await wallet.startSyncing(TestUtils.SYNC_PERIOD_IN_MS); + return wallet; + } + + async closeWallet(wallet, save?) { + await wallet.close(save); + } + + async getSeedLanguages(): Promise { + return await MoneroWalletFull.getSeedLanguages(); + } + + // ------------------------------- BEGIN TESTS ------------------------------ + + runTests() { + let that = this; + let testConfig = this.testConfig; + describe("TEST MONERO WALLET FULL", function() { + + // register handlers to run before and after tests + before(async function() { await that.beforeAll(); }); + beforeEach(async function() { await that.beforeEach(this.currentTest); }); + after(async function() { await that.afterAll(); }); + afterEach(async function() { await that.afterEach(this.currentTest); }); + + // run tests specific to full wallet + that.testWalletFull(); + + // run common tests + that.runCommonTests(); + }); + } + + protected testWalletFull() { + let that = this; + let testConfig = this.testConfig; + describe("Tests specific to WebAssembly wallet", function() { + + if (false && testConfig.testNonRelays) + it("Does not leak memory", async function() { + let restoreHeight = TestUtils.FIRST_RECEIVE_HEIGHT; + //let wallet = await that.createWallet({seed: TestUtils.SEED, restoreHeight: restoreHeight}, false); + for (let i = 0; i < 100; i++) { + console.log(process.memoryUsage()); + await testSyncSeed(TestUtils.FIRST_RECEIVE_HEIGHT, undefined, false, true); + } + }); + + if (testConfig.testNonRelays) + it("Can get the daemon's height", async function() { + assert(await that.wallet.isConnectedToDaemon()); + let daemonHeight = await that.wallet.getDaemonHeight(); + assert(daemonHeight > 0); + }); + + if (testConfig.testNonRelays && !testConfig.liteMode) + it("Can open, sync, and close wallets repeatedly", async function() { + let wallets: MoneroWalletFull[] = []; + for (let i = 0; i < 4; i++) { + let wallet = await that.createWallet({seed: TestUtils.SEED, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}); + await wallet.startSyncing(); + wallets.push(wallet); + } + for (let wallet of wallets) await wallet.close(); + }); + + if (testConfig.testNonRelays) + it("Can get the daemon's max peer height", async function() { + let height = await (that.wallet as MoneroWalletFull).getDaemonMaxPeerHeight(); + assert(height > 0); + }); + + if (testConfig.testNonRelays) + it("Can create a random full wallet", async function() { + + // create unconnected random wallet + let wallet = await that.createWallet({networkType: MoneroNetworkType.MAINNET, server: TestUtils.OFFLINE_SERVER_URI}); + await MoneroUtils.validateMnemonic(await wallet.getSeed()); + await MoneroUtils.validateAddress(await wallet.getPrimaryAddress(), MoneroNetworkType.MAINNET); + assert.equal(await wallet.getNetworkType(), MoneroNetworkType.MAINNET); + assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection(TestUtils.OFFLINE_SERVER_URI).getConfig()); + assert(!(await wallet.isConnectedToDaemon())); + assert.equal(await wallet.getSeedLanguage(), "English"); + assert(!(await wallet.isSynced())); + assert.equal(await wallet.getHeight(), 1); // TODO monero-project: why does height of new unsynced wallet start at 1? + assert(await wallet.getRestoreHeight() >= 0); + + // cannot get daemon chain height + try { + await wallet.getDaemonHeight(); + } catch (e: any) { + assert.equal(e.message, "Wallet is not connected to daemon"); + } + + // set daemon connection and check chain height + await wallet.setDaemonConnection(await that.daemon.getRpcConnection()); + assert.equal(await wallet.getDaemonHeight(), await that.daemon.getHeight()); + + // close wallet which releases resources + await wallet.close(); + + // create random wallet with non defaults + wallet = await that.createWallet({networkType: MoneroNetworkType.TESTNET, language: "Spanish"}, false); + await MoneroUtils.validateMnemonic(await wallet.getSeed()); + await MoneroUtils.validateAddress(await wallet.getPrimaryAddress(), MoneroNetworkType.TESTNET); + assert.equal(await wallet.getNetworkType(), await MoneroNetworkType.TESTNET); + assert(await wallet.getDaemonConnection()); + assert((await that.daemon.getRpcConnection()) !== (await wallet.getDaemonConnection())); // not same reference + assert.equal((await wallet.getDaemonConnection()).getUri(), (await that.daemon.getRpcConnection()).getUri()); + assert.equal((await wallet.getDaemonConnection()).getUsername(), (await that.daemon.getRpcConnection()).getUsername()); + assert.equal((await wallet.getDaemonConnection()).getPassword(), (await that.daemon.getRpcConnection()).getPassword()); + assert(await wallet.isConnectedToDaemon()); + assert.equal(await wallet.getSeedLanguage(), "Spanish"); + assert(!(await wallet.isSynced())); + assert.equal(await wallet.getHeight(), 1); // TODO monero-project: why is height of unsynced wallet 1? + if (await that.daemon.isConnected()) assert.equal(await wallet.getRestoreHeight(), await that.daemon.getHeight()); + else assert(await wallet.getRestoreHeight() >= 0); + await wallet.close(); + }); + + if (testConfig.testNonRelays) + it("Can create a full wallet from seed", async function() { + + // create unconnected wallet with mnemonic + let wallet = await that.createWallet({seed: TestUtils.SEED, server: TestUtils.OFFLINE_SERVER_URI}); + assert.equal(await wallet.getSeed(), TestUtils.SEED); + assert.equal(await wallet.getPrimaryAddress(), TestUtils.ADDRESS); + assert.equal(await wallet.getNetworkType(), TestUtils.NETWORK_TYPE); + assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection(TestUtils.OFFLINE_SERVER_URI).getConfig()); + assert(!(await wallet.isConnectedToDaemon())); + assert.equal(await wallet.getSeedLanguage(), "English"); + assert(!(await wallet.isSynced())); + assert.equal(await wallet.getHeight(), 1); + assert.equal(await wallet.getRestoreHeight(), 0); + try { await wallet.startSyncing(); } catch (e: any) { assert.equal(e.message, "Wallet is not connected to daemon"); } + await wallet.close(); + + // create wallet without restore height + wallet = await that.createWallet({seed: TestUtils.SEED}, false); + assert.equal(await wallet.getSeed(), TestUtils.SEED); + assert.equal(await wallet.getPrimaryAddress(), TestUtils.ADDRESS); + assert.equal(TestUtils.NETWORK_TYPE, await wallet.getNetworkType()); + assert(await wallet.getDaemonConnection()); + assert(await that.daemon.getRpcConnection() != await wallet.getDaemonConnection()); + assert.equal((await wallet.getDaemonConnection()).getUri(), (await that.daemon.getRpcConnection()).getUri()); + assert.equal((await wallet.getDaemonConnection()).getUsername(), (await that.daemon.getRpcConnection()).getUsername()); + assert.equal((await wallet.getDaemonConnection()).getPassword(), (await that.daemon.getRpcConnection()).getPassword()); + assert(await wallet.isConnectedToDaemon()); + assert.equal(await wallet.getSeedLanguage(), "English"); + assert(!(await wallet.isSynced())); + assert.equal(await wallet.getHeight(), 1); // TODO monero-project: why does height of new unsynced wallet start at 1? + assert.equal(await wallet.getRestoreHeight(), 0); + await wallet.close(); + + // create wallet with seed, no connection, and restore height + let restoreHeight = 10000; + wallet = await that.createWallet({seed: TestUtils.SEED, restoreHeight: restoreHeight, server: TestUtils.OFFLINE_SERVER_URI}); + assert.equal(await wallet.getSeed(), TestUtils.SEED); + assert.equal(await wallet.getPrimaryAddress(), TestUtils.ADDRESS); + assert.equal(await wallet.getNetworkType(), TestUtils.NETWORK_TYPE); + assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection(TestUtils.OFFLINE_SERVER_URI).getConfig()); + assert(!(await wallet.isConnectedToDaemon())); + assert.equal(await wallet.getSeedLanguage(), "English"); + assert.equal(await wallet.getHeight(), 1); // TODO monero-project: why does height of new unsynced wallet start at 1? + assert.equal(await wallet.getRestoreHeight(), restoreHeight); + let path = await wallet.getPath(); + await wallet.close(true); + wallet = await that.openWallet({path: path, server: TestUtils.OFFLINE_SERVER_URI}); + assert(!(await wallet.isConnectedToDaemon())); + assert(!(await wallet.isSynced())); + assert.equal(await wallet.getHeight(), 1); + assert.equal(await wallet.getRestoreHeight(), restoreHeight); + await wallet.close(); + + // create wallet with seed, connection, and restore height + wallet = await that.createWallet({seed: TestUtils.SEED, restoreHeight: restoreHeight}, false); + assert.equal(await wallet.getSeed(), TestUtils.SEED); + assert(await wallet.getPrimaryAddress(), TestUtils.ADDRESS); + assert.equal(await wallet.getNetworkType(), TestUtils.NETWORK_TYPE); + assert(await wallet.getDaemonConnection()); + assert(await that.daemon.getRpcConnection() != wallet.getDaemonConnection()); + assert.equal((await wallet.getDaemonConnection()).getUri(), (await that.daemon.getRpcConnection()).getUri()); + assert.equal((await wallet.getDaemonConnection()).getUsername(), (await that.daemon.getRpcConnection()).getUsername()); + assert.equal((await wallet.getDaemonConnection()).getPassword(), (await that.daemon.getRpcConnection()).getPassword()); + assert(await wallet.isConnectedToDaemon()); + assert.equal(await wallet.getSeedLanguage(), "English"); + assert(!(await wallet.isSynced())); + assert.equal(await wallet.getHeight(), 1); // TODO monero-project: why does height of new unsynced wallet start at 1? + assert.equal(await wallet.getRestoreHeight(), restoreHeight); + await wallet.close(); + }); + + if (testConfig.testNonRelays) + it("Can create a full wallet from keys", async function() { + + // recreate test wallet from keys + let wallet = that.wallet; + let walletKeys = await that.createWallet({server: TestUtils.OFFLINE_SERVER_URI, networkType: await (wallet as MoneroWalletFull).getNetworkType(), primaryAddress: await wallet.getPrimaryAddress(), privateViewKey: await wallet.getPrivateViewKey(), privateSpendKey: await wallet.getPrivateSpendKey(), restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}); + let err; + try { + assert.equal(await walletKeys.getSeed(), await wallet.getSeed()); + assert.equal(await walletKeys.getPrimaryAddress(), await wallet.getPrimaryAddress()); + assert.equal(await walletKeys.getPrivateViewKey(), await wallet.getPrivateViewKey()); + assert.equal(await walletKeys.getPublicViewKey(), await wallet.getPublicViewKey()); + assert.equal(await walletKeys.getPrivateSpendKey(), await wallet.getPrivateSpendKey()); + assert.equal(await walletKeys.getPublicSpendKey(), await wallet.getPublicSpendKey()); + assert.equal(await walletKeys.getRestoreHeight(), TestUtils.FIRST_RECEIVE_HEIGHT); + assert(!await walletKeys.isConnectedToDaemon()); + assert(!(await walletKeys.isSynced())); + } catch (e) { + err = e; + } + await walletKeys.close(); + if (err) throw err; + }); + + if (testConfig.testNonRelays && !GenUtils.isBrowser()) + it("Is compatible with monero-wallet-rpc wallet files", async function() { + + // create wallet using monero-wallet-rpc + let walletName = GenUtils.getUUID(); + let walletRpc = await TestUtils.getWalletRpc(); + await walletRpc.createWallet(new MoneroWalletConfig().setPath(walletName).setPassword(TestUtils.WALLET_PASSWORD).setSeed(TestUtils.SEED).setRestoreHeight(TestUtils.FIRST_RECEIVE_HEIGHT)); + await walletRpc.sync(); + let balance = await walletRpc.getBalance(); + let outputsHex = await walletRpc.exportOutputs(); + assert(outputsHex.length > 0); + await walletRpc.close(true); + + // open as full wallet + let walletFull = await openWalletFull(new MoneroWalletConfig().setPath(TestUtils.WALLET_RPC_LOCAL_WALLET_DIR + "/" + walletName).setPassword(TestUtils.WALLET_PASSWORD).setNetworkType(TestUtils.NETWORK_TYPE).setServer(TestUtils.DAEMON_RPC_CONFIG)); + await walletFull.sync(); + assert.equal(TestUtils.SEED, await walletFull.getSeed()); + assert.equal(TestUtils.ADDRESS, await walletFull.getPrimaryAddress()); + assert.equal(balance.toString(), (await walletFull.getBalance()).toString()); + assert.equal(outputsHex.length, (await walletFull.exportOutputs()).length); + await walletFull.close(true); + + // create full wallet + walletName = GenUtils.getUUID(); + let path = TestUtils.WALLET_RPC_LOCAL_WALLET_DIR + "/" + walletName; + walletFull = await createWalletFull(new MoneroWalletConfig().setPath(path).setPassword(TestUtils.WALLET_PASSWORD).setNetworkType(TestUtils.NETWORK_TYPE).setSeed(TestUtils.SEED).setRestoreHeight(TestUtils.FIRST_RECEIVE_HEIGHT).setServer(TestUtils.DAEMON_RPC_CONFIG)); + await walletFull.sync(); + balance = await walletFull.getBalance(); + outputsHex = await walletFull.exportOutputs(); + await walletFull.close(true); + + // rebuild wallet cache using full wallet + await (await TestUtils.getDefaultFs()).unlink(path); + walletFull = await openWalletFull(new MoneroWalletConfig().setPath(path).setPassword(TestUtils.WALLET_PASSWORD).setNetworkType(TestUtils.NETWORK_TYPE).setServer(TestUtils.DAEMON_RPC_CONFIG)); + await walletFull.close(true); + + // open wallet using monero-wallet-rpc + await walletRpc.openWallet(new MoneroWalletConfig().setPath(walletName).setPassword(TestUtils.WALLET_PASSWORD)); + await walletRpc.sync(); + assert.equal(TestUtils.SEED, await walletRpc.getSeed()); + assert.equal(TestUtils.ADDRESS, await walletRpc.getPrimaryAddress()); + assert.equal(balance.toString(), (await walletRpc.getBalance()).toString()); + assert.equal(outputsHex.length, (await walletRpc.exportOutputs()).length); + await walletRpc.close(true); + }); + + if (!testConfig.liteMode && (testConfig.testNonRelays || testConfig.testRelays)) + it("Is compatible with monero-wallet-rpc outputs and offline transaction signing", async function() { + + // create view-only wallet in wallet rpc process + let viewOnlyWallet = await TestUtils.startWalletRpcProcess(); + await viewOnlyWallet.createWallet({ + path: GenUtils.getUUID(), + password: TestUtils.WALLET_PASSWORD, + primaryAddress: await that.wallet.getPrimaryAddress(), + privateViewKey: await that.wallet.getPrivateViewKey(), + restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT + }); + await viewOnlyWallet.sync(); + + // create offline full wallet + let offlineWallet = await that.createWallet({primaryAddress: await that.wallet.getPrimaryAddress(), privateViewKey: await that.wallet.getPrivateViewKey(), privateSpendKey: await that.wallet.getPrivateSpendKey(), server: TestUtils.OFFLINE_SERVER_URI, restoreHeight: 0}); + + // test tx signing with wallets + let err; + try { await that.testViewOnlyAndOfflineWallets(viewOnlyWallet, offlineWallet); } + catch (e) { err = e; } + + // finally + TestUtils.stopWalletRpcProcess(viewOnlyWallet); + await that.closeWallet(offlineWallet); + if (err) throw err; + }); + + if (!testConfig.liteMode) + it("Is compatible with monero-wallet-rpc multisig wallets", async function() { + + // create participants with monero-wallet-rpc and full wallet + let participants: MoneroWallet[] = []; + participants.push(await (await TestUtils.startWalletRpcProcess()).createWallet(new MoneroWalletConfig().setPath(GenUtils.getUUID()).setPassword(TestUtils.WALLET_PASSWORD))); + participants.push(await (await TestUtils.startWalletRpcProcess()).createWallet(new MoneroWalletConfig().setPath(GenUtils.getUUID()).setPassword(TestUtils.WALLET_PASSWORD))); + participants.push(await that.createWallet(new MoneroWalletConfig())); + + // test multisig + let err; + try { + await that.testMultisigParticipants(participants, 3, 3, true); + } catch (e) { + err = e; + } + + // stop mining at end of test + try { await that.daemon.stopMining(); } + catch (e) { } + + // save and close participants + if (participants[0] instanceof MoneroWalletRpc) await TestUtils.stopWalletRpcProcess(participants[0]); + else participants[0].close(true); // multisig tests might restore wallet from seed + await TestUtils.stopWalletRpcProcess(participants[1]); + await that.closeWallet(participants[2], true); + if (err) throw err; + }); + + // TODO monero-project: cannot re-sync from lower block height after wallet saved + if (testConfig.testNonRelays && !testConfig.liteMode && false) + it("Can re-sync an existing wallet from scratch", async function() { + let wallet = await that.openWallet({path: TestUtils.WALLET_FULL_PATH, password: TestUtils.WALLET_PASSWORD, networkType: MoneroNetworkType.TESTNET, server: TestUtils.OFFLINE_SERVER_URI}, true); // wallet must already exist + await wallet.setDaemonConnection(TestUtils.getDaemonRpcConnection()); + //long startHeight = TestUtils.TEST_RESTORE_HEIGHT; + let startHeight = 0; + let progressTester = new SyncProgressTester(wallet, startHeight, await wallet.getDaemonHeight()); + await wallet.setRestoreHeight(1); + let result = await wallet.sync(progressTester, 1); + await progressTester.onDone(await wallet.getDaemonHeight()); + + // test result after syncing + assert(await wallet.isConnectedToDaemon()); + assert(await wallet.isSynced()); + assert.equal(result.getNumBlocksFetched(), await wallet.getDaemonHeight() - startHeight); + assert(result.getReceivedMoney()); + assert.equal(await wallet.getHeight(), await that.daemon.getHeight()); + await wallet.close(); + }); + + if (testConfig.testNonRelays) + it("Can sync a wallet with a randomly generated seed", async function() { + assert(await that.daemon.isConnected(), "Not connected to daemon"); + + // create test wallet + let restoreHeight = await that.daemon.getHeight(); + let wallet = await that.createWallet({}, false); + + // test wallet's height before syncing + let walletGt; + let err; + try { + assert.equal((await wallet.getDaemonConnection()).getUri(), (await that.daemon.getRpcConnection()).getUri()); + assert.equal((await wallet.getDaemonConnection()).getUsername(), (await that.daemon.getRpcConnection()).getUsername()); + assert.equal((await wallet.getDaemonConnection()).getPassword(), (await that.daemon.getRpcConnection()).getPassword()); + assert.equal(await wallet.getDaemonHeight(), restoreHeight); + assert(await wallet.isConnectedToDaemon()); + assert(!(await wallet.isSynced())); + assert.equal(await wallet.getHeight(), 1); + assert.equal(await wallet.getRestoreHeight(), restoreHeight); + + // sync the wallet + let progressTester = new SyncProgressTester(wallet, await wallet.getRestoreHeight(), await wallet.getDaemonHeight()); + let result = await wallet.sync(progressTester, undefined); + await progressTester.onDone(await wallet.getDaemonHeight()); + + // test result after syncing + walletGt = await that.createWallet({seed: await wallet.getSeed(), restoreHeight: restoreHeight}); + await walletGt.sync(); + assert(await wallet.isConnectedToDaemon()); + assert(await wallet.isSynced()); + assert.equal(result.getNumBlocksFetched(), 0); + assert(!result.getReceivedMoney()); + if (await wallet.getHeight() !== await that.daemon.getHeight()) console.log("WARNING: wallet height " + await wallet.getHeight() + " is not synced with daemon height " + await that.daemon.getHeight()); // TODO: height may not be same after long sync + + // sync the wallet with default params + await wallet.sync(); + assert(await wallet.isSynced()); + assert.equal(await wallet.getHeight(), await that.daemon.getHeight()); + + // compare wallet to ground truth + await TestMoneroWalletFull.testWalletEqualityOnChain(walletGt, wallet); + } catch (e) { + err = e; + } + + // finally + if (walletGt) await walletGt.close(); + await wallet.close(); + if (err) throw err; + + // attempt to sync unconnected wallet + wallet = await that.createWallet({server: TestUtils.OFFLINE_SERVER_URI}); + err = undefined; + try { + await wallet.sync(); + throw new Error("Should have thrown exception"); + } catch (e1: any) { + try { + assert.equal(e1.message, "Wallet is not connected to daemon"); + } catch (e2) { + err = e2; + } + } + + // finally + await wallet.close(); + if (err) throw err; + }); + + if (false && testConfig.testNonRelays && !testConfig.liteMode) // TODO: re-enable before release + it("Can sync a wallet created from seed from the genesis", async function() { + await testSyncSeed(undefined, undefined, true, false); + }); + + if (testConfig.testNonRelays) + it("Can sync a wallet created from seed from a restore height", async function() { + await testSyncSeed(undefined, TestUtils.FIRST_RECEIVE_HEIGHT); + }); + + if (testConfig.testNonRelays && !testConfig.liteMode) + it("Can sync a wallet created from seed from a start height.", async function() { + await testSyncSeed(TestUtils.FIRST_RECEIVE_HEIGHT, undefined, false, true); + }); + + if (testConfig.testNonRelays && !testConfig.liteMode) + it("Can sync a wallet created from seed from a start height less than the restore height", async function() { + await testSyncSeed(TestUtils.FIRST_RECEIVE_HEIGHT, TestUtils.FIRST_RECEIVE_HEIGHT + 3); + }); + + if (testConfig.testNonRelays && !testConfig.liteMode) + it("Can sync a wallet created from seed from a start height greater than the restore height", async function() { + await testSyncSeed(TestUtils.FIRST_RECEIVE_HEIGHT + 3, TestUtils.FIRST_RECEIVE_HEIGHT); + }); + + async function testSyncSeed(startHeight, restoreHeight?, skipGtComparison?, testPostSyncNotifications?) { + assert(await that.daemon.isConnected(), "Not connected to daemon"); + if (startHeight !== undefined && restoreHeight != undefined) assert(startHeight <= TestUtils.FIRST_RECEIVE_HEIGHT || restoreHeight <= TestUtils.FIRST_RECEIVE_HEIGHT); + + // create wallet from seed + let wallet = await that.createWallet({seed: TestUtils.SEED, restoreHeight: restoreHeight}, false); + + // sanitize expected sync bounds + if (restoreHeight === undefined) restoreHeight = 0; + let startHeightExpected = startHeight === undefined ? restoreHeight : startHeight; + if (startHeightExpected === 0) startHeightExpected = 1; + let endHeightExpected = await wallet.getDaemonMaxPeerHeight(); + + // test wallet and close as final step + let walletGt: MoneroWallet | undefined = undefined; + let err = undefined; // to permit final cleanup like Java's try...catch...finally + try { + + // test wallet's height before syncing + assert(await wallet.isConnectedToDaemon()); + assert(!(await wallet.isSynced())); + assert.equal(await wallet.getHeight(), 1); + assert.equal(await wallet.getRestoreHeight(), restoreHeight); + + // register a wallet listener which tests notifications throughout the sync + let walletSyncTester = new WalletSyncTester(wallet, startHeightExpected, endHeightExpected); + await wallet.addListener(walletSyncTester); + + // sync the wallet with a listener which tests sync notifications + let progressTester = new SyncProgressTester(wallet, startHeightExpected, endHeightExpected); + let result = await wallet.sync(progressTester, startHeight); + + // test completion of the wallet and sync listeners + await progressTester.onDone(await wallet.getDaemonHeight()); + await walletSyncTester.onDone(await wallet.getDaemonHeight()); + + // test result after syncing + assert(await wallet.isSynced()); + assert.equal(result.getNumBlocksFetched(), await wallet.getDaemonHeight() - startHeightExpected); + assert(result.getReceivedMoney()); + if (await wallet.getHeight() !== await that.daemon.getHeight()) console.log("WARNING: wallet height " + await wallet.getHeight() + " is not synced with daemon height " + await that.daemon.getHeight()); // TODO: height may not be same after long sync + assert.equal(await wallet.getDaemonHeight(), await that.daemon.getHeight(), "Daemon heights are not equal: " + await wallet.getDaemonHeight() + " vs " + await that.daemon.getHeight()); + if (startHeightExpected > TestUtils.FIRST_RECEIVE_HEIGHT) assert((await wallet.getTxs())[0].getHeight() > TestUtils.FIRST_RECEIVE_HEIGHT); // wallet is partially synced so first tx happens after true restore height + else assert.equal((await wallet.getTxs())[0].getHeight(), TestUtils.FIRST_RECEIVE_HEIGHT); // wallet should be fully synced so first tx happens on true restore height + + // sync the wallet with default params + result = await wallet.sync(); + assert(await wallet.isSynced()); + if (await wallet.getHeight() !== await that.daemon.getHeight()) console.log("WARNING: wallet height " + await wallet.getHeight() + " is not synced with daemon height " + await that.daemon.getHeight() + " after re-syncing"); + assert.equal(result.getNumBlocksFetched(), 0); + assert(!result.getReceivedMoney()); + + // compare with ground truth + if (!skipGtComparison) { + walletGt = await TestUtils.createWalletGroundTruth(TestUtils.NETWORK_TYPE, await wallet.getSeed(), startHeight, restoreHeight); + await TestMoneroWalletFull.testWalletEqualityOnChain(walletGt, wallet); + } + + // if testing post-sync notifications, wait for a block to be added to the chain + // then test that sync arg listener was not invoked and registered wallet listener was invoked + if (testPostSyncNotifications) { + + // start automatic syncing + await wallet.startSyncing(TestUtils.SYNC_PERIOD_IN_MS); + + // attempt to start mining to push the network along // TODO: TestUtils.tryStartMining() : reqId, TestUtils.tryStopMining(reqId) + let startedMining = false; + let miningStatus = await that.daemon.getMiningStatus(); + if (!miningStatus.getIsActive()) { + try { + await StartMining.startMining(); + startedMining = true; + } catch (e) { + // no problem + } + } + + try { + + // wait for block + console.log("Waiting for next block to test post sync notifications"); + await that.daemon.waitForNextBlockHeader(); + + // ensure wallet has time to detect new block + await new Promise(function(resolve) { setTimeout(resolve, TestUtils.SYNC_PERIOD_IN_MS + 3000); }); // sleep for wallet interval + time to sync + + // test that wallet listener's onSyncProgress() and onNewBlock() were invoked after previous completion + assert(walletSyncTester.getOnSyncProgressAfterDone()); + assert(walletSyncTester.getOnNewBlockAfterDone()); + } catch (e) { + err = e; + } + + // finally + if (startedMining) { + await that.daemon.stopMining(); + //await wallet.stopMining(); // TODO: support client-side mining? + } + if (err) throw err; + } + } catch (e) { + err = e; + } + + // finally + if (walletGt !== undefined) await walletGt.close(true); + await wallet.close(); + if (err) throw err; + } + + if (testConfig.testNonRelays) + it("Can sync a wallet created from keys", async function() { + + // recreate test wallet from keys + let walletKeys = await that.createWallet({primaryAddress: await that.wallet.getPrimaryAddress(), privateViewKey: await that.wallet.getPrivateViewKey(), privateSpendKey: await that.wallet.getPrivateSpendKey(), restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}, false); + + // create ground truth wallet for comparison + let walletGt = await TestUtils.createWalletGroundTruth(TestUtils.NETWORK_TYPE, TestUtils.SEED, undefined, TestUtils.FIRST_RECEIVE_HEIGHT); + + // test wallet and close as final step + let err; + try { + assert.equal(await walletKeys.getSeed(), await walletGt.getSeed()); + assert.equal(await walletKeys.getPrimaryAddress(), await walletGt.getPrimaryAddress()); + assert.equal(await walletKeys.getPrivateViewKey(), await walletGt.getPrivateViewKey()); + assert.equal(await walletKeys.getPublicViewKey(), await walletGt.getPublicViewKey()); + assert.equal(await walletKeys.getPrivateSpendKey(), await walletGt.getPrivateSpendKey()); + assert.equal(await walletKeys.getPublicSpendKey(), await walletGt.getPublicSpendKey()); + assert.equal(await walletKeys.getRestoreHeight(), TestUtils.FIRST_RECEIVE_HEIGHT); + assert(await walletKeys.isConnectedToDaemon()); + assert(!(await walletKeys.isSynced())); + + // sync the wallet + let progressTester = new SyncProgressTester(walletKeys, TestUtils.FIRST_RECEIVE_HEIGHT, await walletKeys.getDaemonMaxPeerHeight()); + let result = await walletKeys.sync(progressTester); + await progressTester.onDone(await walletKeys.getDaemonHeight()); + + // test result after syncing + assert(await walletKeys.isSynced()); + assert.equal(result.getNumBlocksFetched(), await walletKeys.getDaemonHeight() - TestUtils.FIRST_RECEIVE_HEIGHT); + assert(result.getReceivedMoney()); + assert.equal(await walletKeys.getHeight(), await that.daemon.getHeight()); + assert.equal(await walletKeys.getDaemonHeight(), await that.daemon.getHeight()); + assert.equal((await walletKeys.getTxs())[0].getHeight(), TestUtils.FIRST_RECEIVE_HEIGHT); // wallet should be fully synced so first tx happens on true restore height + + // compare with ground truth + await TestMoneroWalletFull.testWalletEqualityOnChain(walletGt, walletKeys); + } catch (e) { + err = e; + } + + // finally + await walletGt.close(true); + await walletKeys.close(); + if (err) throw err; + }); + + // TODO: test start syncing, notification of syncs happening, stop syncing, no notifications, etc + if (testConfig.testNonRelays) + it("Can start and stop syncing", async function() { + + // test unconnected wallet + let err; // used to emulate Java's try...catch...finally + let path = TestMoneroWalletFull.getRandomWalletPath(); + let wallet = await that.createWallet({path: path, password: TestUtils.WALLET_PASSWORD, networkType: TestUtils.NETWORK_TYPE, server: TestUtils.OFFLINE_SERVER_URI}); + try { + assert.notEqual(await wallet.getSeed(), undefined); + assert.equal(await wallet.getHeight(), 1); + assert.equal(await wallet.getBalance(), 0n); + await wallet.startSyncing(); + } catch (e1: any) { // first error is expected + try { + assert.equal(e1.message, "Wallet is not connected to daemon"); + } catch (e2) { + err = e2; + } + } + + // finally + await wallet.close(); + if (err) throw err; + + // test connecting wallet + path = TestMoneroWalletFull.getRandomWalletPath(); + wallet = await that.createWallet({path: path, password: TestUtils.WALLET_PASSWORD, networkType: TestUtils.NETWORK_TYPE, server: TestUtils.OFFLINE_SERVER_URI}); + try { + assert.notEqual(wallet.getSeed(), undefined); + assert(!await wallet.isConnectedToDaemon()); + await wallet.setDaemonConnection(await that.daemon.getRpcConnection()); + assert.equal(await wallet.getHeight(), 1); + assert(!await wallet.isSynced()); + assert.equal(await wallet.getBalance(), 0n); + let chainHeight = await wallet.getDaemonHeight(); + await wallet.setRestoreHeight(chainHeight - 3); + await wallet.startSyncing(); + assert.equal(await wallet.getRestoreHeight(), chainHeight - 3); + assert.equal((await wallet.getDaemonConnection()).getUri(), (await that.daemon.getRpcConnection()).getUri()); // TODO: replace with config comparison + assert.equal((await wallet.getDaemonConnection()).getUsername(), (await that.daemon.getRpcConnection()).getUsername()); + assert.equal((await wallet.getDaemonConnection()).getPassword(), (await that.daemon.getRpcConnection()).getPassword()); + await wallet.stopSyncing(); + await wallet.sync(); + await wallet.stopSyncing(); + await wallet.stopSyncing(); + } catch (e) { + err = e; + } + + // finally + await wallet.close(); + if (err) throw err; + + // test that sync starts automatically + let restoreHeight = await that.daemon.getHeight() - 100; + path = TestMoneroWalletFull.getRandomWalletPath(); + wallet = await that.createWallet({path: path, password: TestUtils.WALLET_PASSWORD, networkType: TestUtils.NETWORK_TYPE, seed: TestUtils.SEED, server: await that.daemon.getRpcConnection(), restoreHeight: restoreHeight}, false); + try { + + // start syncing + assert.equal(await wallet.getHeight(), 1); + assert.equal(await wallet.getRestoreHeight(), restoreHeight); + assert(!(await wallet.isSynced())); + assert.equal(await wallet.getBalance(), BigInt(0)); + await wallet.startSyncing(TestUtils.SYNC_PERIOD_IN_MS); + + // pause for sync to start + await new Promise(function(resolve) { setTimeout(resolve, TestUtils.SYNC_PERIOD_IN_MS + 1000); }); // in ms + + // test that wallet has started syncing + assert(await wallet.getHeight() > 1); + + // stop syncing + await wallet.stopSyncing(); + + // TODO monero-project: wallet.cpp m_synchronized only ever set to true, never false +// // wait for block to be added to chain +// await that.daemon.waitForNextBlockHeader(); +// +// // wallet is no longer synced +// assert(!(await wallet.isSynced())); + } catch (e) { + err = e; + } + + // finally + await wallet.close(); + if (err) throw err; + }); + + if (testConfig.testNonRelays) + it("Does not interfere with other wallet notifications", async function() { + + // create 2 wallets with a recent restore height + let height = await that.daemon.getHeight(); + let restoreHeight = height - 5; + let wallet1 = await that.createWallet({seed: TestUtils.SEED, restoreHeight: restoreHeight}, false); + let wallet2 = await that.createWallet({seed: TestUtils.SEED, restoreHeight: restoreHeight}, false); + + // track notifications of each wallet + let tester1 = new SyncProgressTester(wallet1, restoreHeight, height); + let tester2 = new SyncProgressTester(wallet2, restoreHeight, height); + await wallet1.addListener(tester1); + await wallet2.addListener(tester2); + + // sync first wallet and test that 2nd is not notified + await wallet1.sync(); + assert(tester1.isNotified()); + assert(!tester2.isNotified()); + + // sync 2nd wallet and test that 1st is not notified + let tester3 = new SyncProgressTester(wallet1, restoreHeight, height); + await wallet1.addListener(tester3); + await wallet2.sync(); + assert(tester2.isNotified()); + assert(!(tester3.isNotified())); + + // close wallets + await wallet1.close(); + await wallet2.close(); + }); + + if (testConfig.testNonRelays) + it("Is equal to the RPC wallet.", async function() { + await WalletEqualityUtils.testWalletEqualityOnChain(await TestUtils.getWalletRpc(), that.wallet); + }); + + if (testConfig.testNonRelays) + it("Is equal to the RPC wallet with a seed offset", async function() { + + // use common offset to compare wallet implementations + let seedOffset = "my super secret offset!"; + + // create rpc wallet with offset + let walletRpc = await TestUtils.getWalletRpc(); + await walletRpc.createWallet({path: GenUtils.getUUID(), password: TestUtils.WALLET_PASSWORD, seed: await walletRpc.getSeed(), restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, seedOffset: seedOffset}); + + // create full wallet with offset + let walletFull = await that.createWallet({seed: TestUtils.SEED, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, seedOffset: seedOffset}); + + // deep compare + let err; + try { + await WalletEqualityUtils.testWalletEqualityOnChain(walletRpc, walletFull); + } catch (e) { + err = e; + } + await walletFull.close(); + if (err) throw err; + }); + + if (testConfig.testNonRelays) + it("Supports multisig sample code", async function() { + await testCreateMultisigWallet(2, 2); + await testCreateMultisigWallet(2, 3); + await testCreateMultisigWallet(2, 4); + }); + + async function testCreateMultisigWallet(M, N) { + console.log("Creating " + M + "/" + N + " multisig wallet"); + + // create participating wallets + let wallets: MoneroWallet[] = [] + for (let i = 0; i < N; i++) { + wallets.push(await that.createWallet()); + } + + // prepare and collect multisig hex from each participant + let preparedMultisigHexes: string[] = [] + for (let wallet of wallets) preparedMultisigHexes.push(await wallet.prepareMultisig()); + + // make each wallet multisig and collect results + let madeMultisigHexes: string[] = []; + for (let i = 0; i < wallets.length; i++) { + + // collect prepared multisig hexes from wallet's peers + let peerMultisigHexes: string[] = []; + for (let j = 0; j < wallets.length; j++) if (j !== i) peerMultisigHexes.push(preparedMultisigHexes[j]); + + // make wallet multisig and collect result hex + let multisigHex = await wallets[i].makeMultisig(peerMultisigHexes, M, TestUtils.WALLET_PASSWORD); + madeMultisigHexes.push(multisigHex); + } + + // exchange multisig keys N - M + 1 times + let multisigHexes = madeMultisigHexes; + for (let i = 0; i < N - M + 1; i++) { + + // exchange multisig keys among participants and collect results for next round if applicable + let resultMultisigHexes: string[] = []; + for (let wallet of wallets) { + + // import the multisig hex of other participants and collect results + let result = await wallet.exchangeMultisigKeys(multisigHexes, TestUtils.WALLET_PASSWORD); + resultMultisigHexes.push(result.getMultisigHex()); + } + + // use resulting multisig hex for next round of exchange if applicable + multisigHexes = resultMultisigHexes; + } + + // wallets are now multisig + for (let wallet of wallets) { + let primaryAddress = await wallet.getAddress(0, 0); + await MoneroUtils.validateAddress(primaryAddress, await (wallet as MoneroWalletFull).getNetworkType()); + let info = await wallet.getMultisigInfo(); + assert(info.getIsMultisig()); + assert(info.getIsReady()); + assert.equal(info.getThreshold(), M); + assert.equal(info.getNumParticipants(), N); + await wallet.close(true); + } + } + + if (testConfig.testNonRelays) + it("Can be saved", async function() { + + // create unique path for new test wallet + let path = TestMoneroWalletFull.getRandomWalletPath(); + + // wallet does not exist + assert(!(await MoneroWalletFull.walletExists(path, await TestUtils.getDefaultFs()))); + + // cannot open non-existent wallet + try { + await that.openWallet({path: path, server: ""}); + throw new Error("Cannot open non-existent wallet"); + } catch (e: any) { + assert.equal(e.message, "Wallet does not exist at path: " + path); + } + + // create wallet at the path + let restoreHeight = await that.daemon.getHeight() - 200; + let wallet = await that.createWallet({path: path, password: TestUtils.WALLET_PASSWORD, networkType: TestUtils.NETWORK_TYPE, seed: TestUtils.SEED, restoreHeight: restoreHeight, server: TestUtils.OFFLINE_SERVER_URI}); + + // test wallet at newly created state + let err; + try { + assert(await MoneroWalletFull.walletExists(path, await TestUtils.getDefaultFs())); + assert.equal(await wallet.getSeed(), TestUtils.SEED); + assert.equal(await wallet.getNetworkType(), TestUtils.NETWORK_TYPE); + assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection(TestUtils.OFFLINE_SERVER_URI).getConfig()); + assert.equal(await wallet.getRestoreHeight(), restoreHeight); + assert.equal(await wallet.getSeedLanguage(), "English"); + assert.equal(await wallet.getHeight(), 1); + assert.equal(await wallet.getRestoreHeight(), restoreHeight); + + // set the wallet's connection and sync + await wallet.setDaemonConnection(TestUtils.getDaemonRpcConnection()); + await wallet.sync(); + if (await wallet.getHeight() !== await wallet.getDaemonHeight()) console.log("WARNING: wallet height " + await wallet.getHeight() + " is not synced with daemon height " + await that.daemon.getHeight()); // TODO: height may not be same after long sync + + // close the wallet without saving + await wallet.close(); + + // re-open the wallet + wallet = await that.openWallet({path: path, server: TestUtils.OFFLINE_SERVER_URI}); + + // test wallet is at newly created state + assert(await MoneroWalletFull.walletExists(path, await TestUtils.getDefaultFs())); + assert.equal(await wallet.getSeed(), TestUtils.SEED); + assert.equal(await wallet.getNetworkType(), TestUtils.NETWORK_TYPE); + assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection(TestUtils.OFFLINE_SERVER_URI).getConfig()); + assert(!(await wallet.isConnectedToDaemon())); + assert.equal(await wallet.getSeedLanguage(), "English"); + assert(!(await wallet.isSynced())); + assert.equal(await wallet.getHeight(), 1); + assert(await wallet.getRestoreHeight() > 0); + + // set the wallet's connection and sync + await wallet.setDaemonConnection(TestUtils.getDaemonRpcConnection()); + assert(await wallet.isConnectedToDaemon()); + await wallet.setRestoreHeight(restoreHeight); + await wallet.sync(); + assert(await wallet.isSynced()); + assert.equal(await wallet.getHeight(), await wallet.getDaemonHeight()); + let prevHeight = await wallet.getHeight(); + + // save and close the wallet + await wallet.save(); + await wallet.close(); + + // re-open the wallet + wallet = await that.openWallet({path: path, server: TestUtils.OFFLINE_SERVER_URI}); + + // test wallet state is saved + assert(!(await wallet.isConnectedToDaemon())); + await wallet.setDaemonConnection(TestUtils.getDaemonRpcConnection()); // TODO monero-project: daemon connection not stored in wallet files so must be explicitly set each time + assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), TestUtils.getDaemonRpcConnection().getConfig()); + assert(await wallet.isConnectedToDaemon()); + assert.equal(await wallet.getHeight(), prevHeight); + assert(await wallet.getRestoreHeight() > 0); + assert(await MoneroWalletFull.walletExists(path, await TestUtils.getDefaultFs())); + assert.equal(await wallet.getSeed(), TestUtils.SEED); + assert.equal(await wallet.getNetworkType(), TestUtils.NETWORK_TYPE); + assert.equal(await wallet.getSeedLanguage(), "English"); + + // sync + await wallet.sync(); + } catch (e) { + err = e; + } + + // finally + await wallet.close(); + if (err) throw err; + }); + + if (testConfig.testNonRelays) + it("Can export and import wallet files", async function() { + let err; + let wallet + let wallet2; + try { + + // create random wallet + wallet = await createWalletFull({ + networkType: MoneroNetworkType.MAINNET, + password: "password123" + }); + + // export wallet files + let walletData = await wallet.getData(); + let keysData = walletData[0]; + let cacheData = walletData[1]; + + // import keys file without cache + wallet2 = await openWalletFull({ + networkType: MoneroNetworkType.MAINNET, + password: "password123", + keysData: keysData + }); + + // import wallet files + wallet2 = await openWalletFull({ + networkType: MoneroNetworkType.MAINNET, + password: "password123", + keysData: keysData, + cacheData: cacheData + }); + + // test that wallets are equal + assert.equal(await wallet.getSeed(), await wallet2.getSeed()); + await TestMoneroWalletFull.testWalletEqualityOnChain(wallet, wallet2); + } catch (e) { + err = e; + } + + // finally + if (wallet) await wallet.close(); + if (wallet2) await wallet2.close(); + if (err) throw err; + }); + + if (testConfig.testNonRelays) + it("Can be moved", async function() { + let err; + let wallet; + try { + + // create random in-memory wallet with defaults + wallet = await that.createWallet(new MoneroWalletConfig().setPath("")); + let mnemonic = await wallet.getSeed(); + await wallet.setAttribute("mykey", "myval1"); + + // change password of in-memory wallet + let password2 = "abc123"; + await wallet.changePassword(TestUtils.WALLET_PASSWORD, password2); + + // move wallet from memory to disk + let path1 = TestUtils.TEST_WALLETS_DIR + "/" + GenUtils.getUUID(); + assert(!(await MoneroWalletFull.walletExists(path1, await TestUtils.getDefaultFs()))); + await wallet.moveTo(path1); + assert(await MoneroWalletFull.walletExists(path1, await TestUtils.getDefaultFs())); + assert.equal(await wallet.getSeed(), mnemonic); + assert.equal("myval1", await wallet.getAttribute("mykey")); + + // move to same path which is same as saving + await wallet.setAttribute("mykey", "myval2"); + await wallet.moveTo(path1); + await wallet.close(); + assert(await MoneroWalletFull.walletExists(path1, await TestUtils.getDefaultFs())); + wallet = await that.openWallet(new MoneroWalletConfig().setPath(path1).setPassword(password2)); + assert.equal(await wallet.getSeed(), mnemonic); + assert.equal("myval2", await wallet.getAttribute("mykey")); + + // move wallet to new directory + let path2 = TestUtils.TEST_WALLETS_DIR + "/moved/" + GenUtils.getUUID(); + await wallet.setAttribute("mykey", "myval3"); + await wallet.moveTo(path2); + assert(!await MoneroWalletFull.walletExists(path1, await TestUtils.getDefaultFs())); + assert(await MoneroWalletFull.walletExists(path2, await TestUtils.getDefaultFs())); + assert.equal(await wallet.getSeed(), mnemonic); + + // re-open and test wallet + await wallet.close(); + wallet = await that.openWallet(new MoneroWalletConfig().setPath(path2).setPassword(password2)); + await wallet.sync(); + assert.equal(await wallet.getSeed(), mnemonic); + assert.equal("myval3", await wallet.getAttribute("mykey")); + } catch (e) { + err = e; + } + + // final cleanup + if (wallet) await wallet.close(); + if (err) throw err; + console.log("All done with test"); + }); + + if (testConfig.testNonRelays) + it("Can be closed", async function() { + let err; + let wallet; + try { + + // create a test wallet + wallet = await that.createWallet(); + let path = await wallet.getPath(); + await wallet.sync(); + assert(await wallet.getHeight() > 1); + assert(await wallet.isSynced()); + assert.equal(await wallet.isClosed(), false); + + // close the wallet + await wallet.close(); + assert(await wallet.isClosed()); + + // attempt to interact with the wallet + try { await wallet.getHeight(); } + catch (e: any) { assert.equal(e.message, "Wallet is closed"); } + try { await wallet.getSeed(); } + catch (e: any) { assert.equal(e.message, "Wallet is closed"); } + try { await wallet.sync(); } + catch (e: any) { assert.equal(e.message, "Wallet is closed"); } + try { await wallet.startSyncing(); } + catch (e: any) { assert.equal(e.message, "Wallet is closed"); } + try { await wallet.stopSyncing(); } + catch (e: any) { assert.equal(e.message, "Wallet is closed"); } + + // re-open the wallet + wallet = await that.openWallet({path: path}); + await wallet.sync(); + assert.equal(await wallet.getHeight(), await wallet.getDaemonHeight()); + assert.equal(await wallet.isClosed(), false); + } catch (e) { + console.log(e); + err = e; + } + + // final cleanup + await wallet.close(); + assert(await wallet.isClosed()); + if (err) throw err; + }); + + if (false) + it("Does not leak memory", async function() { + let err; + try { + console.log("Infinite loop starting, monitor memory in OS process manager..."); + let i = 0; + let closeWallet = false; + if (closeWallet) await that.wallet.close(true); + while (true) { + if (closeWallet) that.wallet = await TestUtils.getWalletFull(); + await that.wallet.sync(); + await that.wallet.getTxs(); + await that.wallet.getTransfers(); + await that.wallet.getOutputs(new MoneroOutputQuery().setIsSpent(false)); + if (i % 1000) { + console.log("Iteration: " + i); + } + if (closeWallet) await that.wallet.close(true); + } + } catch (e) { + console.log(e); + err = e; + } + + // final cleanup + if (err) throw err; + }); + }); + } + + //----------------------------- PRIVATE HELPERS ----------------------------- + + protected static getRandomWalletPath() { + return TestUtils.TEST_WALLETS_DIR + "/test_wallet_" + GenUtils.getUUID(); + } + + // possible configuration: on chain xor local wallet data ("strict"), txs ordered same way? TBD + protected static async testWalletEqualityOnChain(wallet1, wallet2) { + await WalletEqualityUtils.testWalletEqualityOnChain(wallet1, wallet2); + assert.equal(await wallet2.getNetworkType(), await wallet1.getNetworkType()); + assert.equal(await wallet2.getRestoreHeight(), await wallet1.getRestoreHeight()); + if (await wallet1.getDaemonConnection() === undefined) assert(await wallet2.getDaemonConnection() === undefined); + else assert.deepEqual((await wallet1.getDaemonConnection()).getConfig(), (await wallet2.getDaemonConnection()).getConfig()); + assert.equal(await wallet2.getSeedLanguage(), await wallet1.getSeedLanguage()); + // TODO: more wasm-specific extensions + } +} + +/** + * Helper class to test progress updates. + */ +class SyncProgressTester extends WalletSyncPrinter { + + wallet: any; + startHeight: number; + prevEndHeight: number; + prevCompleteHeight: number; + prevHeight: number; + isDone: boolean; + onSyncProgressAfterDone: boolean; + + constructor(wallet, startHeight, endHeight) { + super(); + this.wallet = wallet; + assert(startHeight >= 0); + assert(endHeight >= 0); + this.startHeight = startHeight; + this.prevEndHeight = endHeight; + this.isDone = false; + } + + async onSyncProgress(height, startHeight, endHeight, percentDone, message) { + super.onSyncProgress(height, startHeight, endHeight, percentDone, message); + + // registered wallet listeners will continue to get sync notifications after the wallet's initial sync + if (this.isDone) { + assert(this.wallet.getListeners().includes(this), "Listener has completed and is not registered so should not be called again"); + this.onSyncProgressAfterDone = true; + } + + // update tester's start height if new sync session + if (this.prevCompleteHeight !== undefined && startHeight === this.prevCompleteHeight) this.startHeight = startHeight; + + // if sync is complete, record completion height for subsequent start heights + if (percentDone === 1) this.prevCompleteHeight = endHeight; + + // otherwise start height is equal to previous completion height + else if (this.prevCompleteHeight !== undefined) assert.equal(startHeight, this.prevCompleteHeight); + + assert(endHeight > startHeight, "end height > start height"); + assert.equal(startHeight, this.startHeight); + assert(endHeight >= this.prevEndHeight); // chain can grow while syncing + this.prevEndHeight = endHeight; + assert(height >= startHeight); + assert(height < endHeight); + let expectedPercentDone = (height - startHeight + 1) / (endHeight - startHeight); + assert.equal(expectedPercentDone, percentDone); + if (this.prevHeight === undefined) assert.equal(height, startHeight); + else assert.equal(this.prevHeight + 1, height); + this.prevHeight = height; + } + + async onDone(chainHeight) { + assert(!this.isDone); + this.isDone = true; + if (this.prevHeight === undefined) { + assert.equal(this.prevCompleteHeight, undefined); + assert.equal(this.startHeight, chainHeight); + } else { + assert.equal(this.prevHeight, chainHeight - 1); // otherwise last height is chain height - 1 + assert.equal(this.prevCompleteHeight, chainHeight); + } + } + + isNotified() { + return this.prevHeight !== undefined; + } + + getOnSyncProgressAfterDone() { + return this.onSyncProgressAfterDone; + } +} + +/** + * Internal class to test all wallet notifications on sync. + */ +class WalletSyncTester extends SyncProgressTester { + + incomingTotal: bigint; + outgoingTotal: bigint; + prevBalance: bigint; + prevUnlockedBalance: bigint; + prevOutputReceived: MoneroOutputWallet; + prevOutputSpent: MoneroOutputWallet; + walletTesterPrevHeight: number; + onNewBlockAfterDone: boolean; + + constructor(wallet, startHeight, endHeight) { + super(wallet, startHeight, endHeight); + assert(startHeight >= 0); + assert(endHeight >= 0); + this.incomingTotal = 0n; + this.outgoingTotal = 0n; + } + + async onNewBlock(height) { + if (this.isDone) { + assert(this.wallet.getListeners().includes(this), "Listener has completed and is not registered so should not be called again"); + this.onNewBlockAfterDone = true; + } + if (this.walletTesterPrevHeight !== undefined) assert.equal(height, this.walletTesterPrevHeight + 1); + assert(height >= this.startHeight); + this.walletTesterPrevHeight = height; + } + + async onBalancesChanged(newBalance, newUnlockedBalance) { + if (this.prevBalance !== undefined) assert(newBalance.toString() !== this.prevBalance.toString() || newUnlockedBalance.toString() !== this.prevUnlockedBalance.toString()); + this.prevBalance = newBalance; + this.prevUnlockedBalance = newUnlockedBalance; + } + + async onOutputReceived(output) { + assert.notEqual(output, undefined); + this.prevOutputReceived = output; + + // test output + TestUtils.testUnsignedBigInt(output.getAmount()); + assert(output.getAccountIndex() >= 0); + assert(output.getSubaddressIndex() >= 0); + + // test output's tx + assert(output.getTx()); + assert(output.getTx() instanceof MoneroTxWallet); + assert(output.getTx().getHash()); + assert.equal(output.getTx().getHash().length, 64); + assert(output.getTx().getVersion() >= 0); + assert(output.getTx().getUnlockTime() >= 0); + assert.equal(output.getTx().getInputs(), undefined); + assert.equal(output.getTx().getOutputs().length, 1); + assert(output.getTx().getOutputs()[0] === output); + + // extra is not sent over the wasm bridge + assert.equal(output.getTx().getExtra(), undefined); + + // add incoming amount to running total + if (output.getIsLocked()) this.incomingTotal = this.incomingTotal + (output.getAmount()); + } + + async onOutputSpent(output) { + assert.notEqual(output, undefined); + this.prevOutputSpent = output; + + // test output + TestUtils.testUnsignedBigInt(output.getAmount()); + assert(output.getAccountIndex() >= 0); + if (output.getSubaddressIndex() !== undefined) assert(output.getSubaddressIndex() >= 0); // TODO (monero-project): can be undefined because inputs not provided so one created from outgoing transfer + + // test output's tx + assert(output.getTx()); + assert(output.getTx() instanceof MoneroTxWallet); + assert(output.getTx().getHash()); + assert.equal(output.getTx().getHash().length, 64); + assert(output.getTx().getVersion() >= 0); + assert(output.getTx().getUnlockTime() >= 0); + assert.equal(output.getTx().getInputs().length, 1); + assert(output.getTx().getInputs()[0] === output); + assert.equal(output.getTx().getOutputs(), undefined); + + // extra is not sent over the wasm bridge + assert.equal(output.getTx().getExtra(), undefined); + + // add outgoing amount to running total + if (output.getIsLocked()) this.outgoingTotal = this.outgoingTotal + (output.getAmount()); + } + + async onDone(chainHeight) { + await super.onDone(chainHeight); + assert.notEqual(this.walletTesterPrevHeight, undefined); + assert.notEqual(this.prevOutputReceived, undefined); + assert.notEqual(this.prevOutputSpent, undefined); + let balance = this.incomingTotal - (this.outgoingTotal); + assert.equal(balance.toString(), (await this.wallet.getBalance()).toString()); + assert.equal(this.prevBalance.toString(), (await this.wallet.getBalance()).toString()); + assert.equal(this.prevUnlockedBalance.toString(), (await this.wallet.getUnlockedBalance()).toString()); + } + + getOnNewBlockAfterDone() { + return this.onNewBlockAfterDone; + } +} + diff --git a/src/test/TestMoneroWalletKeys.js b/src/test/TestMoneroWalletKeys.ts similarity index 50% rename from src/test/TestMoneroWalletKeys.js rename to src/test/TestMoneroWalletKeys.ts index 17dc4f5a2..9ae03f401 100644 --- a/src/test/TestMoneroWalletKeys.js +++ b/src/test/TestMoneroWalletKeys.ts @@ -1,28 +1,44 @@ -const TestUtils = require("./utils/TestUtils"); -const WalletEqualityUtils = require("./utils/WalletEqualityUtils"); -const TestMoneroWalletCommon = require("./TestMoneroWalletCommon"); -const monerojs = require("../../index"); -const MoneroWalletConfig = monerojs.MoneroWalletConfig; -const GenUtils = monerojs.GenUtils; +import assert from "assert"; +import TestUtils from "./utils/TestUtils"; +import WalletEqualityUtils from "./utils/WalletEqualityUtils"; +import TestMoneroWalletCommon from "./TestMoneroWalletCommon"; +import {createWalletKeys, MoneroWalletConfig, MoneroWalletKeys, GenUtils, MoneroUtils} from "../../index"; /** * Tests the implementation of MoneroWallet which only manages keys using WebAssembly. */ -class TestMoneroWalletKeys extends TestMoneroWalletCommon { +export default class TestMoneroWalletKeys extends TestMoneroWalletCommon { constructor(config) { super(config); } + async beforeAll() { + await super.beforeAll(); + } + + async beforeEach(currentTest) { + await super.beforeEach(currentTest); + } + + async afterAll() { + console.log("After all"); + await this.wallet.close(); + } + + async afterEach(currentTest) { + await super.afterEach(currentTest); + } + async getTestWallet() { return TestUtils.getWalletKeys(); } async getTestDaemon() { - throw new Error("TestMoneroWalletKeys.getTestDaemon() not applicable"); + return await TestUtils.getDaemonRpc(); } - async openWallet(config) { + async openWallet(config?): Promise { throw new Error("TestMoneroWalletKeys.openWallet(config) not applicable, use createWallet()"); } @@ -35,24 +51,29 @@ class TestMoneroWalletKeys extends TestMoneroWalletCommon { if (config.getServer()) throw new Error("Cannot initialize keys wallet with connection"); // create wallet - return await monerojs.createWalletKeys(config); + return await createWalletKeys(config); + } + + async closeWallet(wallet, save) { + await wallet.close(save); } - async getMnemonicLanguages() { - return await monerojs.MoneroWalletKeys.getMnemonicLanguages(); + async getSeedLanguages(): Promise { + return await MoneroWalletKeys.getSeedLanguages(); } runTests() { let that = this; describe("TEST MONERO WALLET KEYS", function() { - // initialize wallet - before(async function() { - that.wallet = await that.getTestWallet(); - }); + // register handlers to run before and after tests + before(async function() { await that.beforeAll(); }); + beforeEach(async function() { await that.beforeEach(this.currentTest); }); + after(async function() { await that.afterAll(); }); + afterEach(async function() { await that.afterEach(this.currentTest); }); // run tests specific to keys wallet - that._testWalletKeys(); + that.testWalletKeys(); // run common tests that.runCommonTests(); @@ -61,9 +82,9 @@ class TestMoneroWalletKeys extends TestMoneroWalletCommon { // ---------------------------------- PRIVATE ------------------------------- - _testWalletKeys() { + protected testWalletKeys() { let that = this; - let config = this.config; + let config = this.testConfig; let daemon = this.daemon; describe("Tests specific to keys wallet", function() { @@ -79,20 +100,27 @@ class TestMoneroWalletKeys extends TestMoneroWalletCommon { // create rpc wallet with offset let walletRpc = await TestUtils.getWalletRpc(); - await walletRpc.createWallet({path: GenUtils.getUUID(), password: TestUtils.WALLET_PASSWORD, mnemonic: await walletRpc.getMnemonic(), restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, seedOffset: seedOffset}); + await walletRpc.createWallet({path: GenUtils.getUUID(), password: TestUtils.WALLET_PASSWORD, seed: await walletRpc.getSeed(), restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, seedOffset: seedOffset}); // create keys-only wallet with offset - let walletKeys = await monerojs.createWalletKeys({ + let walletKeys = await createWalletKeys({ networkType: TestUtils.NETWORK_TYPE, - mnemonic: TestUtils.MNEMONIC, + seed: TestUtils.SEED, seedOffset: seedOffset }); // deep compare await WalletEqualityUtils.testWalletEqualityKeys(walletRpc, walletKeys); }); + + it("Can get the address of a specified account and subaddress index", async function() { + for (let accountIdx= 0; accountIdx < 5; accountIdx++) { + for (let subaddressIdx = 0; subaddressIdx < 5; subaddressIdx++) { + await MoneroUtils.validateAddress(await that.wallet.getAddress(accountIdx, subaddressIdx), TestUtils.NETWORK_TYPE); + } + } + }); }); } } -module.exports = TestMoneroWalletKeys \ No newline at end of file diff --git a/src/test/TestMoneroWalletRpc.js b/src/test/TestMoneroWalletRpc.js deleted file mode 100644 index 068cc91e6..000000000 --- a/src/test/TestMoneroWalletRpc.js +++ /dev/null @@ -1,381 +0,0 @@ -const assert = require("assert"); -const TestUtils = require("./utils/TestUtils"); -const TestMoneroWalletCommon = require("./TestMoneroWalletCommon"); -const monerojs = require("../../index"); -const GenUtils = monerojs.GenUtils; -const MoneroWalletConfig = monerojs.MoneroWalletConfig; -const MoneroUtils = monerojs.MoneroUtils; -const MoneroAccountTag = monerojs.MoneroAccountTag; - -/** - * Tests the Monero Wallet RPC client and server. - */ -class TestMoneroWalletRpc extends TestMoneroWalletCommon { - - constructor(testConfig) { - super(testConfig); - } - - async getTestWallet() { - return TestUtils.getWalletRpc(); - } - - async getTestDaemon() { - return TestUtils.getDaemonRpc(); - } - - async openWallet(config) { - - // assign defaults - config = new MoneroWalletConfig(config); - if (!config) config = new MoneroWalletConfig(); - if (!config.getPassword()) config.setPassword(TestUtils.WALLET_PASSWORD); - - // open wallet - await this.wallet.openWallet(config); - - // serverUri "" denotes offline wallet for tests - if (config.getServerUri() === "") await this.wallet.setDaemonConnection(""); - return this.wallet; - } - - async createWallet(config) { - - // assign defaults - config = new MoneroWalletConfig(config); - let random = !config.getMnemonic() && !config.getPrimaryAddress(); - if (!config.getPath()) config.setPath(GenUtils.getUUID()); - if (!config.getPassword()) config.setPassword(TestUtils.WALLET_PASSWORD); - if (!config.getRestoreHeight() && !random) config.setRestoreHeight(0); - - // create wallet - await this.wallet.createWallet(config); - - // serverUri "" denotes offline wallet for tests - if (config.getServerUri() === "") await this.wallet.setDaemonConnection(""); - return this.wallet; - } - - async getMnemonicLanguages() { - return await this.wallet.getMnemonicLanguages(); - } - - runTests() { - let that = this; - let testConfig = this.testConfig; - describe("TEST MONERO WALLET RPC", function() { - - // initialize wallet - before(async function() { - that.wallet = await that.getTestWallet(); - that.daemon = await that.getTestDaemon(); - TestUtils.TX_POOL_WALLET_TRACKER.reset(); // all wallets need to wait for txs to confirm to reliably sync - }); - - // run tests specific to wallet rpc - that._testWalletRpc(testConfig); - - // run common tests - that.runCommonTests(testConfig); - }); - } - - // ---------------------------------- PRIVATE ------------------------------- - - // rpc-specific tx test - async _testTxWallet(tx, ctx) { - ctx = Object.assign({}, ctx); - - // run common tests - await super._testTxWallet(tx, ctx); - } - - // rpc-specific out-of-range subaddress test - async _testGetSubaddressAddressOutOfRange() { - let accounts = await this.wallet.getAccounts(true); - let accountIdx = accounts.length - 1; - let subaddressIdx = accounts[accountIdx].getSubaddresses().length; - let address = await this.wallet.getAddress(accountIdx, subaddressIdx); - assert.equal(address, undefined); - } - - _testWalletRpc(config) { - let that = this; - describe("Tests specific to RPC wallet", function() { - - // ---------------------------- BEGIN TESTS --------------------------------- - - it("Can create a wallet with a randomly generated mnemonic", async function() { - let err; - try { - - // create random wallet with defaults - let path = GenUtils.getUUID(); - await that.createWallet({path: path}); - let mnemonic = await that.wallet.getMnemonic(); - MoneroUtils.validateMnemonic(mnemonic); - assert.notEqual(mnemonic, TestUtils.MNEMONIC); - MoneroUtils.validateAddress(await that.wallet.getPrimaryAddress()); - await that.wallet.sync(); // very quick because restore height is chain height - await that.wallet.close(); - - // create random wallet with non defaults - path = GenUtils.getUUID(); - await that.createWallet({path: path, language: "Spanish"}); - MoneroUtils.validateMnemonic(await that.wallet.getMnemonic()); - assert.notEqual(await that.wallet.getMnemonic(), mnemonic); - MoneroUtils.validateAddress(await that.wallet.getPrimaryAddress()); - await that.wallet.close(); - - // attempt to create wallet which already exists - try { - await that.createWallet({path: path, language: "Spanish"}); - } catch (e) { - assert.equal(e.message, "Wallet already exists: " + path); - } - } catch (e) { - err = e; - } - - // open main test wallet for other tests - await that.wallet.openWallet(TestUtils.WALLET_NAME, TestUtils.WALLET_PASSWORD); - - // throw error if there was one - if (err) throw err; - }); - - it("Can create a wallet from a mnemonic phrase", async function() { - let err; - try { - - // create wallet with mnemonic and defaults - let path = GenUtils.getUUID(); - await that.createWallet({path: path, password: TestUtils.WALLET_PASSWORD, mnemonic: TestUtils.MNEMONIC, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}); - assert.equal(await that.wallet.getMnemonic(), TestUtils.MNEMONIC); - assert.equal(await that.wallet.getPrimaryAddress(), TestUtils.ADDRESS); - await that.wallet.sync(); - assert.equal(await that.wallet.getHeight(), await that.daemon.getHeight()); - let txs = await that.wallet.getTxs(); - assert(txs.length > 0); // wallet is used - assert.equal(txs[0].getHeight(), TestUtils.FIRST_RECEIVE_HEIGHT); - await that.wallet.close(); - - // create wallet with non-defaults - path = GenUtils.getUUID(); - await that.createWallet({path: path, password: TestUtils.WALLET_PASSWORD, mnemonic: TestUtils.MNEMONIC, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, language: "German", seedOffset: "my offset!", saveCurrent: false}); - MoneroUtils.validateMnemonic(await that.wallet.getMnemonic()); - assert.notEqual(await that.wallet.getMnemonic(), TestUtils.MNEMONIC); // mnemonic is different because of offset - assert.notEqual(await that.wallet.getPrimaryAddress(), TestUtils.ADDRESS); - await that.wallet.close(); - - } catch (e) { - err = e; - } - - // open main test wallet for other tests - await that.wallet.openWallet(TestUtils.WALLET_NAME, TestUtils.WALLET_PASSWORD); - - // throw error if there was one - if (err) throw err; - }); - - it("Can open wallets", async function() { - let err; - try { - - // create names of test wallets - let numTestWallets = 3; - let names = []; - for (let i = 0; i < numTestWallets; i++) names.add(GenUtils.getUUID()); - - // create test wallets - let mnemonics = []; - for (let name of names) { - await that.createWallet({path: name, password: TestUtils.WALLET_PASSWORD}); - mnemonics.add(await that.wallet.getMnemonic()); - await that.wallet.close(); - } - - // open test wallets - for (let i = 0; i < numTestWallets; i++) { - await that.wallet.openWallet(names[i], TestUtils.WALLET_PASSWORD); - assert.equal(await that.wallet.getMnemonic(), mnemonics[i]); - await that.wallet.close(); - } - - // attempt to re-open already opened wallet - try { - await that.wallet.openWallet(names[numTestWallets - 1], TestUtils.WALLET_PASSWORD); - } catch (e) { - assert.equal(e.getCode(), -1); - } - - // attempt to open non-existent - try { - await that.wallet.openWallet("btc_integrity", TestUtils.WALLET_PASSWORD); - } catch (e) { - assert.equal( e.getCode(), -1); // -1 indicates wallet does not exist (or is open by another app) - } - } catch (e) { - let err = e; - } - - // open main test wallet for other tests - try { - await that.wallet.openWallet(TestUtils.WALLET_NAME, TestUtils.WALLET_PASSWORD); - } catch (e) { - assert.equal(e.getCode(), -1); // ok if wallet is already open - } - - // throw error if there was one - if (err) throw err; - }); - - it("Can indicate if multisig import is needed for correct balance information", async function() { - assert.equal(await that.wallet.isMultisigImportNeeded(), false); - }); - - it("Can tag accounts and query accounts by tag", async function() { - - // get accounts - let accounts = await that.wallet.getAccounts(); - assert(accounts.length >= 3, "Not enough accounts to test; run create account test"); - - // tag some of the accounts - let tag = new MoneroAccountTag("my_tag_" + GenUtils.getUUID(), "my tag label", [0, 1]); - await that.wallet.tagAccounts(tag.getTag(), tag.getAccountIndices()); - - // query accounts by tag - let taggedAccounts = await that.wallet.getAccounts(undefined, tag.getTag()); - assert.equal(taggedAccounts.length, 2); - assert.equal(taggedAccounts[0].getIndex(), 0); - assert.equal(taggedAccounts[0].getTag(), tag.getTag()); - assert.equal(taggedAccounts[1].getIndex(), 1); - assert.equal(taggedAccounts[1].getTag(), tag.getTag()); - - // set tag label - await that.wallet.setAccountTagLabel(tag.getTag(), tag.getLabel()); - - // fetch tags and ensure new tag is contained - let tags = await that.wallet.getAccountTags(); - assert(GenUtils.arrayContains(tags, tag)); - - // re-tag an account - let tag2 = new MoneroAccountTag("my_tag_" + GenUtils.getUUID(), "my tag label 2", [1]); - await that.wallet.tagAccounts(tag2.getTag(), tag2.getAccountIndices()); - let taggedAccounts2 = await that.wallet.getAccounts(undefined, tag2.getTag()) - assert.equal(taggedAccounts2.length, 1); - assert.equal(taggedAccounts2[0].getIndex(), 1); - assert.equal(taggedAccounts2[0].getTag(), tag2.getTag()); - - // re-query original tag which only applies to one account now - taggedAccounts = await that.wallet.getAccounts(undefined, tag.getTag()); - assert.equal(taggedAccounts.length, 1); - assert.equal(taggedAccounts[0].getIndex(), 0); - assert.equal(taggedAccounts[0].getTag(), tag.getTag()); - - // untag and query accounts - await that.wallet.untagAccounts([0, 1]); - assert.equal((await that.wallet.getAccountTags()).length, 0); - try { - await that.wallet.getAccounts(undefined, tag.getTag()); - fail("Should have thrown exception with unregistered tag"); - } catch (e) { - assert.equal(e.getCode(), -1); - } - - // test that non-existing tag returns no accounts - try { - await that.wallet.getAccounts(undefined, "non_existing_tag"); - fail("Should have thrown exception with unregistered tag"); - } catch (e) { - assert.equal(e.getCode(), -1); - } - }); - - it("Can fetch accounts and subaddresses without balance info because this is another RPC call", async function() { - let accounts = await that.wallet.getAccounts(true, undefined, true); - assert(accounts.length > 0); - for (let account of accounts) { - assert(account.getSubaddresses().length > 0); - for (let subaddress of account.getSubaddresses()) { - assert.equal(typeof subaddress.getAddress(), "string"); - assert(subaddress.getAddress().length > 0); - assert(subaddress.getAccountIndex() >= 0); - assert(subaddress.getIndex() >= 0); - assert(subaddress.getLabel() === undefined || typeof subaddress.getLabel() === "string"); - if (typeof subaddress.getLabel() === "string") assert(subaddress.getLabel().length > 0); - assert.equal(typeof subaddress.isUsed(), "boolean"); - assert.equal(subaddress.getNumUnspentOutputs(), undefined); - assert.equal(subaddress.getBalance(), undefined); - assert.equal(subaddress.getUnlockedBalance(), undefined); - } - } - }); - - it("Can rescan spent", async function() { - await that.wallet.rescanSpent(); - }); - - it("Can save the wallet file", async function() { - await that.wallet.save(); - }); - - it("Can close a wallet", async function() { - - // create a test wallet - let path = GenUtils.getUUID(); - await that.createWallet({path: path, password: TestUtils.WALLET_PASSWORD}); - await that.wallet.sync(); - assert((await that.wallet.getHeight()) > 1); - - // close the wallet - await that.wallet.close(); - - // attempt to interact with the wallet - try { - await that.wallet.getHeight(); - } catch (e) { - assert.equal(e.getCode(), -13); - assert.equal(e.message, "No wallet file"); - } - try { - await that.wallet.getMnemonic(); - } catch (e) { - assert.equal(e.getCode(), -13); - assert.equal(e.message, "No wallet file"); - } - try { - await that.wallet.sync(); - } catch (e) { - assert.equal(e.getCode(), -13); - assert.equal(e.message, "No wallet file"); - } - - // re-open the wallet - await that.wallet.openWallet(path, TestUtils.WALLET_PASSWORD); - await that.wallet.sync(); - assert.equal(await that.wallet.getHeight(), await that.daemon.getHeight()); - - // close the wallet - await that.wallet.close(); - - // re-open main test wallet for other tests - await that.wallet.openWallet(TestUtils.WALLET_NAME, TestUtils.WALLET_PASSWORD); - }); - - if (false) // disabled so server not actually stopped - it("Can stop the RPC server", async function() { - await that.wallet.stop(); - }); - }); - } -} - -module.exports = TestMoneroWalletRpc; - -function testAddressBookEntry(entry) { - assert(entry.getIndex() >= 0); - assert(entry.getAddress()); - assert(entry.getDescription()); -} \ No newline at end of file diff --git a/src/test/TestMoneroWalletRpc.ts b/src/test/TestMoneroWalletRpc.ts new file mode 100644 index 000000000..dd7290fed --- /dev/null +++ b/src/test/TestMoneroWalletRpc.ts @@ -0,0 +1,436 @@ +import assert from "assert"; +import TestUtils from "./utils/TestUtils"; +import TestMoneroWalletCommon from "./TestMoneroWalletCommon"; +import TestMoneroWalletFull from "./TestMoneroWalletFull"; +import {MoneroError, + GenUtils, + MoneroWalletConfig, + MoneroUtils, + MoneroAccountTag, + MoneroWalletRpc} from "../../index"; + +/** + * Tests the Monero Wallet RPC client and server. + */ +export default class TestMoneroWalletRpc extends TestMoneroWalletCommon { + + constructor(testConfig) { + super(testConfig); + } + + async beforeAll() { + await super.beforeAll(); + + // if full tests ran, wait for full wallet's pool txs to confirm + if (TestMoneroWalletFull.FULL_TESTS_RUN) { + let walletFull = await TestUtils.getWalletFull(); + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(walletFull); + await walletFull.close(true); + } + } + + async beforeEach(currentTest) { + await super.beforeEach(currentTest); + } + + async afterAll() { + await super.afterAll(); + for (let portOffset of Object.keys(TestUtils.WALLET_PORT_OFFSETS)) { // TODO: this breaks encapsulation, use MoneroWalletRpcManager + console.error("WARNING: Wallet RPC process on port " + (TestUtils.WALLET_RPC_PORT_START + Number(portOffset)) + " was not stopped after all tests, stopping"); + await TestUtils.stopWalletRpcProcess(TestUtils.WALLET_PORT_OFFSETS[portOffset]); + } + } + + async afterEach(currentTest) { + await super.afterEach(currentTest); + } + + async getTestWallet() { + return TestUtils.getWalletRpc(); + } + + async getTestDaemon() { + return TestUtils.getDaemonRpc(); + } + + async openWallet(config) { + + // assign defaults + config = new MoneroWalletConfig(config); + if (config.getPassword() === undefined) config.setPassword(TestUtils.WALLET_PASSWORD); + if (!config.getServer() && !config.getConnectionManager()) config.setServer(await this.daemon.getRpcConnection()); + + // create client connected to internal monero-wallet-rpc executable + let offline = config.getServer() && config.getServer().getUri() === TestUtils.OFFLINE_SERVER_URI; + let wallet = await TestUtils.startWalletRpcProcess(offline); + + // open wallet + try { + await wallet.openWallet(config); + await wallet.setDaemonConnection(await wallet.getDaemonConnection(), true, undefined); // set daemon as trusted + if (await wallet.isConnectedToDaemon()) await wallet.startSyncing(TestUtils.SYNC_PERIOD_IN_MS); + return wallet; + } catch (err) { + await TestUtils.stopWalletRpcProcess(wallet); + throw err; + } + } + + async createWallet(config: Partial) { + + // assign defaults + config = new MoneroWalletConfig(config); + let random = !config.getSeed() && !config.getPrimaryAddress(); + if (!config.getPath()) config.setPath(GenUtils.getUUID()); + if (config.getPassword() === undefined) config.setPassword(TestUtils.WALLET_PASSWORD); + if (!config.getRestoreHeight() && !random) config.setRestoreHeight(0); + if (!config.getServer() && !config.getConnectionManager()) config.setServer(await this.daemon.getRpcConnection()); + + // create client connected to internal monero-wallet-rpc executable + let offline = config.getServer() && config.getServer().getUri() === GenUtils.normalizeUri(TestUtils.OFFLINE_SERVER_URI); + let wallet = await TestUtils.startWalletRpcProcess(offline); + + // create wallet + try { + await wallet.createWallet(config); + await wallet.setDaemonConnection(await wallet.getDaemonConnection(), true, undefined); // set daemon as trusted + if (await wallet.isConnectedToDaemon()) await wallet.startSyncing(TestUtils.SYNC_PERIOD_IN_MS); + return wallet; + } catch (err) { + await TestUtils.stopWalletRpcProcess(wallet); + throw err; + } + } + + async closeWallet(wallet, save?) { + await wallet.close(save); + await TestUtils.stopWalletRpcProcess(wallet); + } + + async getSeedLanguages(): Promise { + return await (this.wallet as MoneroWalletRpc).getSeedLanguages(); + } + + runTests() { + let that = this; + let testConfig = this.testConfig; + describe("TEST MONERO WALLET RPC", function() { + + // register handlers to run before and after tests + before(async function() { await that.beforeAll(); }); + beforeEach(async function() { await that.beforeEach(this.currentTest); }); + after(async function() { await that.afterAll(); }); + afterEach(async function() { await that.afterEach(this.currentTest); }); + + // run tests specific to wallet rpc + that.testWalletRpc(testConfig); + + // run common tests + that.runCommonTests(testConfig); + }); + } + + // ---------------------------------- PRIVATE ------------------------------- + + // rpc-specific tx test + async testTxWallet(tx, ctx) { + ctx = Object.assign({}, ctx); + + // run common tests + await super.testTxWallet(tx, ctx); + } + + // rpc-specific out-of-range subaddress test + async testGetSubaddressAddressOutOfRange() { + let accounts = await this.wallet.getAccounts(true); + let accountIdx = accounts.length - 1; + let subaddressIdx = accounts[accountIdx].getSubaddresses().length; + let address = await this.wallet.getAddress(accountIdx, subaddressIdx); + assert.equal(address, undefined); + } + + testInvalidAddressError(err) { + super.testInvalidAddressError(err); + assert.equal(-2, err.getCode()); + } + + testInvalidTxHashError(err) { + super.testInvalidTxHashError(err); + assert.equal(-8, err.getCode()); + } + + testInvalidTxKeyError(err) { + super.testInvalidTxKeyError(err); + assert.equal(-25, err.getCode()); + } + + testInvalidSignatureError(err) { + super.testInvalidSignatureError(err); + assert.equal(-1, err.getCode()); + } + + testNoSubaddressError(err) { + super.testNoSubaddressError(err); + assert.equal(-1, err.getCode()); + } + + testSignatureHeaderCheckError(err) { + super.testSignatureHeaderCheckError(err); + assert.equal(-1, err.getCode()); + } + + protected testWalletRpc(testConfig) { + let that = this; + describe("Tests specific to RPC wallet", function() { + + // ---------------------------- BEGIN TESTS --------------------------------- + + if (testConfig.testNonRelays) + it("Can create a wallet with a randomly generated mnemonic", async function() { + + // create random wallet with defaults + let path = GenUtils.getUUID(); + let wallet = await that.createWallet({ path: path }); + let mnemonic = await wallet.getSeed(); + await MoneroUtils.validateMnemonic(mnemonic); + assert.notEqual(mnemonic, TestUtils.SEED); + await MoneroUtils.validateAddress(await wallet.getPrimaryAddress(), TestUtils.NETWORK_TYPE); + await wallet.sync(); // very quick because restore height is chain height + await that.closeWallet(wallet); + + // create random wallet with non defaults + path = GenUtils.getUUID(); + wallet = await that.createWallet({ path: path, language: "Spanish" }); + await MoneroUtils.validateMnemonic(await wallet.getSeed()); + assert.notEqual(await wallet.getSeed(), mnemonic); + mnemonic = await wallet.getSeed(); + await MoneroUtils.validateAddress(await wallet.getPrimaryAddress(), TestUtils.NETWORK_TYPE); + + // attempt to create wallet which already exists + try { + await that.createWallet({ path: path, language: "Spanish" }); + } catch (e: any) { + assert.equal(e.message, "Wallet already exists: " + path); + assert.equal(-21, e.getCode()) + assert.equal(mnemonic, await wallet.getSeed()); + } + await that.closeWallet(wallet); + }); + + if (testConfig.testNonRelays) + it("Can create a RPC wallet from a mnemonic phrase", async function() { + + // create wallet with mnemonic and defaults + let path = GenUtils.getUUID(); + let wallet = await that.createWallet({ path: path, password: TestUtils.WALLET_PASSWORD, seed: TestUtils.SEED, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT }); + assert.equal(await wallet.getSeed(), TestUtils.SEED); + assert.equal(await wallet.getPrimaryAddress(), TestUtils.ADDRESS); + await wallet.sync(); + assert.equal(await wallet.getHeight(), await that.daemon.getHeight()); + let txs = await wallet.getTxs(); + assert(txs.length > 0); // wallet is used + assert.equal(txs[0].getHeight(), TestUtils.FIRST_RECEIVE_HEIGHT); + await that.closeWallet(wallet); + + // create wallet with non-defaults + path = GenUtils.getUUID(); + wallet = await that.createWallet({ path: path, password: TestUtils.WALLET_PASSWORD, seed: TestUtils.SEED, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, language: "German", seedOffset: "my offset!", saveCurrent: false }); + await MoneroUtils.validateMnemonic(await wallet.getSeed()); + assert.notEqual(await wallet.getSeed(), TestUtils.SEED); // mnemonic is different because of offset + assert.notEqual(await wallet.getPrimaryAddress(), TestUtils.ADDRESS); + await that.closeWallet(wallet); + }); + + if (testConfig.testNonRelays) + it("Can open wallets", async function() { + + // create names of test wallets + let numTestWallets = 3; + let names: string[] = []; + for (let i = 0; i < numTestWallets; i++) names.push(GenUtils.getUUID()); + + // create test wallets + let mnemonics: string[] = []; + for (let name of names) { + let wallet = await that.createWallet({ path: name, password: TestUtils.WALLET_PASSWORD }); + mnemonics.push(await wallet.getSeed()); + await that.closeWallet(wallet, true); + } + + // open test wallets + let wallets: MoneroWalletRpc[] = []; + for (let i = 0; i < numTestWallets; i++) { + let wallet = await that.openWallet({ path: names[i], password: TestUtils.WALLET_PASSWORD }); + assert.equal(await wallet.getSeed(), mnemonics[i]); + wallets.push(wallet); + } + + // attempt to re-open already opened wallet + try { + await that.openWallet({ path: names[numTestWallets - 1], password: TestUtils.WALLET_PASSWORD }); + } catch (e: any) { + assert.equal(e.getCode(), -1); + } + + // attempt to open non-existent + try { + await that.openWallet({ path: "btc_integrity", password: TestUtils.WALLET_PASSWORD }); + throw new Error("Cannot open wallet which is already open"); + } catch (e: any) { + assert(e instanceof MoneroError); + assert.equal(e.getCode(), -1); // -1 indicates wallet does not exist (or is open by another app) + } + + // close wallets + for (let wallet of wallets) await that.closeWallet(wallet); + }); + + if (testConfig.testNonRelays) + it("Can indicate if multisig import is needed for correct balance information", async function() { + assert.equal(await that.wallet.isMultisigImportNeeded(), false); + }); + + if (testConfig.testNonRelays) + it("Can tag accounts and query accounts by tag", async function() { + + // get accounts + let accounts = await that.wallet.getAccounts(); + assert(accounts.length >= 3, "Not enough accounts to test; run create account test"); + + // tag some of the accounts + let tag = new MoneroAccountTag({tag: "my_tag_" + GenUtils.getUUID(), label: "my tag label", accountIndices: [0, 1]}); + await that.wallet.tagAccounts(tag.getTag(), tag.getAccountIndices()); + + // query accounts by tag + let taggedAccounts = await that.wallet.getAccounts(undefined, tag.getTag()); + assert.equal(taggedAccounts.length, 2); + assert.equal(taggedAccounts[0].getIndex(), 0); + assert.equal(taggedAccounts[0].getTag(), tag.getTag()); + assert.equal(taggedAccounts[1].getIndex(), 1); + assert.equal(taggedAccounts[1].getTag(), tag.getTag()); + + // set tag label + await that.wallet.setAccountTagLabel(tag.getTag(), tag.getLabel()); + + // fetch tags and ensure new tag is contained + let tags = await that.wallet.getAccountTags(); + assert(GenUtils.arrayContains(tags, tag)); + + // re-tag an account + let tag2 = new MoneroAccountTag({tag: "my_tag_" + GenUtils.getUUID(), label: "my tag label 2", accountIndices: [1]}); + await that.wallet.tagAccounts(tag2.getTag(), tag2.getAccountIndices()); + let taggedAccounts2 = await that.wallet.getAccounts(undefined, tag2.getTag()) + assert.equal(taggedAccounts2.length, 1); + assert.equal(taggedAccounts2[0].getIndex(), 1); + assert.equal(taggedAccounts2[0].getTag(), tag2.getTag()); + + // re-query original tag which only applies to one account now + taggedAccounts = await that.wallet.getAccounts(undefined, tag.getTag()); + assert.equal(taggedAccounts.length, 1); + assert.equal(taggedAccounts[0].getIndex(), 0); + assert.equal(taggedAccounts[0].getTag(), tag.getTag()); + + // untag and query accounts + await that.wallet.untagAccounts([0, 1]); + assert.equal((await that.wallet.getAccountTags()).length, 0); + try { + await that.wallet.getAccounts(undefined, tag.getTag()); + throw new Error("Should have thrown exception with unregistered tag"); + } catch (e: any) { + assert.equal(e.getCode(), -1); + } + + // test that non-existing tag returns no accounts + try { + await that.wallet.getAccounts(undefined, "non_existing_tag"); + throw new Error("Should have thrown exception with unregistered tag"); + } catch (e: any) { + assert.equal(e.getCode(), -1); + } + }); + + if (testConfig.testNonRelays) + it("Can fetch accounts and subaddresses without balance info because this is another RPC call", async function() { + let accounts = await (that.wallet as MoneroWalletRpc).getAccounts(true, undefined, true); + assert(accounts.length > 0); + for (let account of accounts) { + assert(account.getSubaddresses().length > 0); + for (let subaddress of account.getSubaddresses()) { + assert.equal(typeof subaddress.getAddress(), "string"); + assert(subaddress.getAddress().length > 0); + assert(subaddress.getAccountIndex() >= 0); + assert(subaddress.getIndex() >= 0); + assert(subaddress.getLabel() === undefined || typeof subaddress.getLabel() === "string"); + if (typeof subaddress.getLabel() === "string") assert(subaddress.getLabel().length > 0); + assert.equal(typeof subaddress.getIsUsed(), "boolean"); + assert.equal(subaddress.getNumUnspentOutputs(), undefined); + assert.equal(subaddress.getBalance(), undefined); + assert.equal(subaddress.getUnlockedBalance(), undefined); + } + } + }); + + if (testConfig.testNonRelays) + it("Can rescan spent", async function() { + await that.wallet.rescanSpent(); + }); + + if (testConfig.testNonRelays) + it("Can save the wallet file", async function() { + await that.wallet.save(); + }); + + if (testConfig.testNonRelays) + it("Can close a wallet", async function() { + + // create a test wallet + let path = GenUtils.getUUID(); + let wallet = await that.createWallet({ path: path, password: TestUtils.WALLET_PASSWORD }); + await wallet.sync(); + assert((await wallet.getHeight()) > 1); + + // close the wallet + await wallet.close(); + + // attempt to interact with the wallet + try { + await wallet.getHeight(); + } catch (e: any) { + assert.equal(e.getCode(), -13); + assert.equal(e.message, "No wallet file"); + } + try { + await wallet.getSeed(); + } catch (e: any) { + assert.equal(e.getCode(), -13); + assert.equal(e.message, "No wallet file"); + } + try { + await wallet.sync(); + } catch (e: any) { + assert.equal(e.getCode(), -13); + assert.equal(e.message, "No wallet file"); + } + + // re-open the wallet + await wallet.openWallet(path, TestUtils.WALLET_PASSWORD); + await wallet.sync(); + assert.equal(await wallet.getHeight(), await that.daemon.getHeight()); + + // close the wallet + await that.closeWallet(wallet, true); + }); + + if (false && testConfig.testNonRelays) // disabled so server not actually stopped + it("Can stop the RPC server", async function() { + await (that.wallet as MoneroWalletRpc).stop(); + }); + }); + } +} + +function testAddressBookEntry(entry) { + assert(entry.getIndex() >= 0); + assert(entry.getAddress()); + assert(entry.getDescription()); +} \ No newline at end of file diff --git a/src/test/TestMoneroWalletWasm.js b/src/test/TestMoneroWalletWasm.js deleted file mode 100644 index 2c86ee7b7..000000000 --- a/src/test/TestMoneroWalletWasm.js +++ /dev/null @@ -1,1669 +0,0 @@ -const assert = require("assert"); -const TestUtils = require("./utils/TestUtils"); -const TestMoneroWalletCommon = require("./TestMoneroWalletCommon"); -const StartMining = require("./utils/StartMining"); -const WalletSyncPrinter = require("./utils/WalletSyncPrinter"); -const WalletEqualityUtils = require("./utils/WalletEqualityUtils"); -const monerojs = require("../../index"); -const MoneroWalletListener = monerojs.MoneroWalletListener; -const LibraryUtils = monerojs.LibraryUtils; -const MoneroWalletConfig = monerojs.MoneroWalletConfig; -const GenUtils = monerojs.GenUtils; -const MoneroUtils = monerojs.MoneroUtils; -const BigInteger = monerojs.BigInteger; -const MoneroNetworkType = monerojs.MoneroNetworkType; -const MoneroTxWallet = monerojs.MoneroTxWallet; -const MoneroTxConfig = monerojs.MoneroTxConfig; -const MoneroRpcConnection = monerojs.MoneroRpcConnection; -const MoneroDestination = monerojs.MoneroDestination; -const MoneroOutputQuery = monerojs.MoneroOutputQuery; -const MoneroOutputWallet = monerojs.MoneroOutputWallet; - -/** - * Tests a Monero wallet using WebAssembly to bridge to monero-project's wallet2. - */ -class TestMoneroWalletWasm extends TestMoneroWalletCommon { - - constructor(testConfig) { - super(testConfig); - } - - async getTestWallet() { - return await TestUtils.getWalletWasm(); - } - - async getTestDaemon() { - return await TestUtils.getDaemonRpc(); - } - - async openWallet(config, startSyncing) { - - // assign defaults - config = new MoneroWalletConfig(config); - if (config.getPassword() === undefined) config.setPassword(TestUtils.WALLET_PASSWORD); - if (config.getNetworkType() === undefined) config.setNetworkType(TestUtils.NETWORK_TYPE); - if (config.getProxyToWorker() === undefined) config.setProxyToWorker(TestUtils.PROXY_TO_WORKER); - if (config.getServer() === undefined && config.getServerUri() === undefined) config.setServer(TestUtils.getDaemonRpcConnection()); - if (config.getFs() === undefined) config.setFs(TestUtils.getDefaultFs()); - - // open wallet - let wallet = await monerojs.openWalletWasm(config); - if (startSyncing !== false && await wallet.isConnected()) await wallet.startSyncing(); - return wallet; - } - - async createWallet(config, startSyncing) { - - // assign defaults - config = new MoneroWalletConfig(config); - let random = config.getMnemonic() === undefined && config.getPrimaryAddress() === undefined; - if (config.getPath() === undefined) config.setPath(TestUtils.TEST_WALLETS_DIR + "/" + GenUtils.getUUID()); - if (config.getPassword() === undefined) config.setPassword(TestUtils.WALLET_PASSWORD); - if (config.getNetworkType() === undefined) config.setNetworkType(TestUtils.NETWORK_TYPE); - if (!config.getRestoreHeight() && !random) config.setRestoreHeight(0); - if (!config.getServer() && config.getServerUri() === undefined) config.setServer(TestUtils.getDaemonRpcConnection()); - if (config.getProxyToWorker() === undefined) config.setProxyToWorker(TestUtils.PROXY_TO_WORKER); - if (config.getFs() === undefined) config.setFs(TestUtils.getDefaultFs()); - - // create wallet - let wallet = await monerojs.createWalletWasm(config); - if (!random) assert.equal(await wallet.getSyncHeight(), config.getRestoreHeight() === undefined ? 0 : config.getRestoreHeight()); - if (startSyncing !== false && await wallet.isConnected()) await wallet.startSyncing(); - return wallet; - } - - async getWalletGt() { - let path = TestUtils.TEST_WALLETS_DIR + "/ground_truth"; - let wallet = await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs()) ? await this.openWallet({path: path}) : await this.createWallet({path: path, mnemonic: TestUtils.MNEMONIC, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, proxyToWorker: TestUtils.PROXY_TO_WORKER}); - await wallet.sync(); - return wallet; - } - - async getMnemonicLanguages() { - return await monerojs.MoneroWalletWasm.getMnemonicLanguages(); - } - - // ------------------------------- BEGIN TESTS ------------------------------ - - runTests() { - let that = this; - let testConfig = this.testConfig; - describe("TEST MONERO WALLET WASM", function() { - - // initialize wallet - before(async function() { - try { - that.wallet = await that.getTestWallet(); - that.daemon = await that.getTestDaemon(); - } catch (e) { - console.log("ERROR BEFORE!"); - console.log(e); - throw e; - } - TestUtils.TX_POOL_WALLET_TRACKER.reset(); // all wallets need to wait for txs to confirm to reliably sync - }); - - // delete non-main test wallets after each test - afterEach(async function() { - - // print memory usage - console.log("WASM memory usage: " + await LibraryUtils.getWasmMemoryUsed()); - //console.log(process.memoryUsage()); - - // remove non-whitelisted wallets - let whitelist = [TestUtils.WALLET_NAME, "ground_truth"]; - let items = TestUtils.getDefaultFs().readdirSync(TestUtils.TEST_WALLETS_DIR); - for (let item of items) { - let found = false; - for (let whitelisted of whitelist) { - if (item === whitelisted || item === whitelisted + ".keys" || item === whitelisted + ".address.txt") { - found = true; - break; - } - } - if (!found) TestUtils.getDefaultFs().unlinkSync(TestUtils.TEST_WALLETS_DIR + "/" + item); - } - }); - - // save wallet after tests - after(async function() { - console.log("Saving and closing wallet on shut down"); - try { - await that.wallet.close(true); - } catch (e) { - console.log("ERROR AFTER"); - console.log(e); - throw e; - } - }); - - // run tests specific to wallet wasm - that._testWalletWasm(); - - // run common tests - that.runCommonTests(); - }); - } - - _testWalletWasm() { - let that = this; - let testConfig = this.testConfig; - describe("Tests specific to WebAssembly wallet", function() { - - if (false && testConfig.testNonRelays) - it("Does not leak memory", async function() { - let restoreHeight = TestUtils.FIRST_RECEIVE_HEIGHT; - //let wallet = await that.createWallet({mnemonic: TestUtils.MNEMONIC, restoreHeight: restoreHeight}, false); - for (let i = 0; i < 100; i++) { - console.log(process.memoryUsage()); - await _testSyncMnemonic(TestUtils.FIRST_RECEIVE_HEIGHT, undefined, false, true); - } - }); - - if (testConfig.testNonRelays) - it("Can get the daemon's height", async function() { - assert(await that.wallet.isConnected()); - let daemonHeight = await that.wallet.getDaemonHeight(); - assert(daemonHeight > 0); - }); - - if (testConfig.testNonRelays && !testConfig.liteMode) - it("Can open, sync, and close wallets repeatedly", async function() { - let wallets = []; - for (let i = 0; i < 4; i++) { - let wallet = await that.createWallet({mnemonic: TestUtils.MNEMONIC, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}); - await wallet.startSyncing(); - wallets.push(wallet); - } - for (let wallet of wallets) await wallet.close(); - }); - - if (testConfig.testNonRelays) - it("Can get the daemon's max peer height", async function() { - let height = await that.wallet.getDaemonMaxPeerHeight(); - assert(height > 0); - }); - - if (testConfig.testNonRelays) - it("Can set the daemon connection", async function() { - let err; - let wallet; - try { - - // create unconnected random wallet - wallet = await that.createWallet({serverUri: ""}); - assert.equal(await wallet.getDaemonConnection(), undefined); - - // set daemon uri - await wallet.setDaemonConnection(TestUtils.DAEMON_RPC_CONFIG.uri); - assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection(TestUtils.DAEMON_RPC_CONFIG.uri).getConfig()); - await wallet.setDaemonConnection(TestUtils.DAEMON_RPC_CONFIG.uri, TestUtils.DAEMON_RPC_CONFIG.username, TestUtils.DAEMON_RPC_CONFIG.password, TestUtils.DAEMON_RPC_CONFIG.rejectUnauthorized); - assert(await wallet.isConnected()); - - // nullify daemon connection - await wallet.setDaemonConnection(undefined); - assert.equal(await wallet.getDaemonConnection(), undefined); - await wallet.setDaemonConnection(TestUtils.DAEMON_RPC_CONFIG.uri); - assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection(TestUtils.DAEMON_RPC_CONFIG.uri).getConfig()); - await wallet.setDaemonConnection(undefined); - assert.equal(await wallet.getDaemonConnection(), undefined); - - // set daemon uri to non-daemon - await wallet.setDaemonConnection("www.getmonero.org"); - assert.deepEqual((await wallet.getDaemonConnection()).getConfig(), new MoneroRpcConnection("www.getmonero.org").getConfig()); - assert(!await wallet.isConnected()); - - // set daemon to invalid uri - await wallet.setDaemonConnection("abc123"); - assert(!await wallet.isConnected()); - - // attempt to sync - try { - await wallet.sync(); - throw new Error("Exception expected"); - } catch (e1) { - assert.equal(e1.message, "Wallet is not connected to daemon"); - } - } catch (e) { - err = e; - } - - // close wallet and throw if error occurred - if (err) console.log(err); - await wallet.close(); - if (err) throw err; - }); - - if (testConfig.testNonRelays) - it("Can create a random WASM wallet", async function() { - - // create unconnected random wallet - let wallet = await that.createWallet({networkType: MoneroNetworkType.MAINNET, serverUri: ""}); - MoneroUtils.validateMnemonic(await wallet.getMnemonic()); - MoneroUtils.validateAddress(await wallet.getPrimaryAddress(), MoneroNetworkType.MAINNET); - assert.equal(await wallet.getNetworkType(), MoneroNetworkType.MAINNET); - assert.equal(await wallet.getDaemonConnection(), undefined); - assert(!(await wallet.isConnected())); - assert.equal(await wallet.getMnemonicLanguage(), "English"); - assert(!(await wallet.isSynced())); - assert.equal(await wallet.getHeight(), 1); // TODO monero core: why does height of new unsynced wallet start at 1? - assert(await wallet.getSyncHeight() >= 0); - - // cannot get daemon chain height - try { - await wallet.getDaemonHeight(); - } catch (e) { - assert.equal(e.message, "Wallet is not connected to daemon"); - } - - // set daemon connection and check chain height - await wallet.setDaemonConnection(await that.daemon.getRpcConnection()); - assert.equal(await wallet.getDaemonHeight(), await that.daemon.getHeight()); - - // close wallet which releases resources - await wallet.close(); - - // create random wallet with non defaults - wallet = await that.createWallet({networkType: MoneroNetworkType.TESTNET, language: "Spanish"}); - MoneroUtils.validateMnemonic(await wallet.getMnemonic()); - MoneroUtils.validateAddress(await wallet.getPrimaryAddress(), MoneroNetworkType.TESTNET); - assert.equal(await wallet.getNetworkType(), await MoneroNetworkType.TESTNET); - assert(await wallet.getDaemonConnection()); - assert((await that.daemon.getRpcConnection()).getConfig() !== (await wallet.getDaemonConnection()).getConfig()); // not same reference - assert.equal((await wallet.getDaemonConnection()).getUri(), (await that.daemon.getRpcConnection()).getUri()); - assert.equal((await wallet.getDaemonConnection()).getUsername(), (await that.daemon.getRpcConnection()).getUsername()); - assert.equal((await wallet.getDaemonConnection()).getPassword(), (await that.daemon.getRpcConnection()).getPassword()); - assert(await wallet.isConnected()); - assert.equal(await wallet.getMnemonicLanguage(), "Spanish"); - assert(!(await wallet.isSynced())); - assert.equal(await wallet.getHeight(), 1); // TODO monero core: why is height of unsynced wallet 1? - if (await that.daemon.isConnected()) assert.equal(await wallet.getSyncHeight(), await that.daemon.getHeight()); - else assert(await wallet.getSyncHeight() >= 0); - await wallet.close(); - }); - - if (testConfig.testNonRelays) - it("Can create a WASM wallet from mnemonic", async function() { - - // create unconnected wallet with mnemonic - let wallet = await that.createWallet({mnemonic: TestUtils.MNEMONIC, serverUri: ""}); - assert.equal(await wallet.getMnemonic(), TestUtils.MNEMONIC); - assert.equal(await wallet.getPrimaryAddress(), TestUtils.ADDRESS); - assert.equal(await wallet.getNetworkType(), TestUtils.NETWORK_TYPE); - assert.equal(await wallet.getDaemonConnection(), undefined); - assert(!(await wallet.isConnected())); - assert.equal(await wallet.getMnemonicLanguage(), "English"); - assert(!(await wallet.isSynced())); - assert.equal(await wallet.getHeight(), 1); - assert.equal(await wallet.getSyncHeight(), 0); - try { await wallet.startSyncing(); } catch (e) { assert.equal(e.message, "Wallet is not connected to daemon"); } - await wallet.close(); - - // create wallet without restore height - wallet = await that.createWallet({mnemonic: TestUtils.MNEMONIC}, false); - assert.equal(await wallet.getMnemonic(), TestUtils.MNEMONIC); - assert.equal(await wallet.getPrimaryAddress(), TestUtils.ADDRESS); - assert.equal(TestUtils.NETWORK_TYPE, await wallet.getNetworkType()); - assert(await wallet.getDaemonConnection()); - assert(await that.daemon.getRpcConnection() != await wallet.getDaemonConnection()); - assert.equal((await wallet.getDaemonConnection()).getUri(), (await that.daemon.getRpcConnection()).getUri()); - assert.equal((await wallet.getDaemonConnection()).getUsername(), (await that.daemon.getRpcConnection()).getUsername()); - assert.equal((await wallet.getDaemonConnection()).getPassword(), (await that.daemon.getRpcConnection()).getPassword()); - assert(await wallet.isConnected()); - assert.equal(await wallet.getMnemonicLanguage(), "English"); - assert(!(await wallet.isSynced())); - assert.equal(await wallet.getHeight(), 1); // TODO monero core: why does height of new unsynced wallet start at 1? - assert.equal(await wallet.getSyncHeight(), 0); - await wallet.close(); - - // create wallet with mnemonic, no connection, and restore height - let restoreHeight = 10000; - wallet = await that.createWallet({mnemonic: TestUtils.MNEMONIC, restoreHeight: restoreHeight, serverUri: ""}); - assert.equal(await wallet.getMnemonic(), TestUtils.MNEMONIC); - assert.equal(await wallet.getPrimaryAddress(), TestUtils.ADDRESS); - assert.equal(await wallet.getNetworkType(), TestUtils.NETWORK_TYPE); - assert.equal(await wallet.getDaemonConnection(), undefined); - assert(!(await wallet.isConnected())); - assert.equal(await wallet.getMnemonicLanguage(), "English"); - assert.equal(await wallet.getHeight(), 1); // TODO monero core: why does height of new unsynced wallet start at 1? - assert.equal(await wallet.getSyncHeight(), restoreHeight); - let path = await await wallet.getPath(); - await wallet.close(true); - wallet = await that.openWallet({path: path, serverUri: ""}); - assert(!(await wallet.isConnected())); - assert(!(await wallet.isSynced())); - assert.equal(await wallet.getHeight(), 1); - assert.equal(await wallet.getSyncHeight(), restoreHeight); - await wallet.close(); - - // create wallet with mnemonic, connection, and restore height - wallet = await that.createWallet({mnemonic: TestUtils.MNEMONIC, restoreHeight: restoreHeight}, false); - assert.equal(await wallet.getMnemonic(), TestUtils.MNEMONIC); - assert(await wallet.getPrimaryAddress(), TestUtils.ADDRESS); - assert(await wallet.getNetworkType(), TestUtils.NETWORK_TYPE); - assert(await wallet.getDaemonConnection()); - assert(await that.daemon.getRpcConnection() != wallet.getDaemonConnection()); - assert.equal((await wallet.getDaemonConnection()).getUri(), (await that.daemon.getRpcConnection()).getUri()); - assert.equal((await wallet.getDaemonConnection()).getUsername(), (await that.daemon.getRpcConnection()).getUsername()); - assert.equal((await wallet.getDaemonConnection()).getPassword(), (await that.daemon.getRpcConnection()).getPassword()); - assert(await wallet.isConnected()); - assert.equal(await wallet.getMnemonicLanguage(), "English"); - assert(!(await wallet.isSynced())); - assert.equal(await wallet.getHeight(), 1); // TODO monero core: why does height of new unsynced wallet start at 1? - assert.equal(await wallet.getSyncHeight(), restoreHeight); - await wallet.close(); - }); - - if (testConfig.testNonRelays) - it("Can create a WASM wallet from keys", async function() { - - // recreate test wallet from keys - let wallet = that.wallet; - let walletKeys = await that.createWallet({serverUri: "", networkType: await wallet.getNetworkType(), primaryAddress: await wallet.getPrimaryAddress(), privateViewKey: await wallet.getPrivateViewKey(), privateSpendKey: await wallet.getPrivateSpendKey(), restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}); - let err; - try { - assert.equal(await walletKeys.getMnemonic(), await wallet.getMnemonic()); - assert.equal(await walletKeys.getPrimaryAddress(), await wallet.getPrimaryAddress()); - assert.equal(await walletKeys.getPrivateViewKey(), await wallet.getPrivateViewKey()); - assert.equal(await walletKeys.getPublicViewKey(), await wallet.getPublicViewKey()); - assert.equal(await walletKeys.getPrivateSpendKey(), await wallet.getPrivateSpendKey()); - assert.equal(await walletKeys.getPublicSpendKey(), await wallet.getPublicSpendKey()); - assert.equal(await walletKeys.getSyncHeight(), TestUtils.FIRST_RECEIVE_HEIGHT); - assert(!await walletKeys.isConnected()); - assert(!(await walletKeys.isSynced())); - } catch (e) { - err = e; - } - await walletKeys.close(); - if (err) throw err; - }); - - // TODO monero core: cannot re-sync from lower block height after wallet saved - if (testConfig.testNonRelays && !testConfig.liteMode && false) - it("Can re-sync an existing wallet from scratch", async function() { - let wallet = await that.openWallet({path: TestUtils.WALLET_WASM_PATH, password: TestUtils.WALLET_PASSWORD, networkType: MoneroNetworkType.STAGENET}); // wallet must already exist - await wallet.setDaemonConnection(TestUtils.getDaemonRpcConnection()); - //long startHeight = TestUtils.TEST_RESTORE_HEIGHT; - let startHeight = 0; - let progressTester = new SyncProgressTester(wallet, startHeight, await wallet.getDaemonHeight()); - await wallet.setSyncHeight(1); - let result = await wallet.sync(progressTester, 1); - await progressTester.onDone(await wallet.getDaemonHeight()); - - // test result after syncing - assert(await wallet.isConnected()); - assert(await wallet.isSynced()); - assert.equal(result.getNumBlocksFetched(), await wallet.getDaemonHeight() - startHeight); - assert(result.getReceivedMoney()); - assert.equal(await wallet.getHeight(), await that.daemon.getHeight()); - await wallet.close(); - }); - - if (testConfig.testNonRelays) - it("Can sync a wallet with a randomly generated seed", async function() { - assert(await that.daemon.isConnected(), "Not connected to daemon"); - - // create test wallet - let restoreHeight = await that.daemon.getHeight(); - let wallet = await that.createWallet({}, false); - - // test wallet's height before syncing - let walletGt; - let err; - try { - assert.equal((await wallet.getDaemonConnection()).getUri(), (await that.daemon.getRpcConnection()).getUri()); - assert.equal((await wallet.getDaemonConnection()).getUsername(), (await that.daemon.getRpcConnection()).getUsername()); - assert.equal((await wallet.getDaemonConnection()).getPassword(), (await that.daemon.getRpcConnection()).getPassword()); - assert.equal(await wallet.getDaemonHeight(), restoreHeight); - assert(await wallet.isConnected()); - assert(!(await wallet.isSynced())); - assert.equal(await wallet.getHeight(), 1); - assert.equal(await wallet.getSyncHeight(), restoreHeight); - - // sync the wallet - let progressTester = new SyncProgressTester(wallet, await wallet.getSyncHeight(), await wallet.getDaemonHeight()); - let result = await wallet.sync(progressTester, undefined); - await progressTester.onDone(await wallet.getDaemonHeight()); - - // test result after syncing - walletGt = await that.createWallet({mnemonic: await wallet.getMnemonic(), restoreHeight: restoreHeight}); - await walletGt.sync(); - assert(await wallet.isConnected()); - assert(await wallet.isSynced()); - assert.equal(result.getNumBlocksFetched(), 0); - assert(!result.getReceivedMoney()); - if (await wallet.getHeight() !== await that.daemon.getHeight()) console.log("WARNING: wallet height " + await wallet.getHeight() + " is not synced with daemon height " + await that.daemon.getHeight()); // TODO: height may not be same after long sync - - // sync the wallet with default params - await wallet.sync(); - assert(await wallet.isSynced()); - assert.equal(await wallet.getHeight(), await that.daemon.getHeight()); - - // compare wallet to ground truth - await TestMoneroWalletWasm._testWalletEqualityOnChain(walletGt, wallet); - } catch (e) { - err = e; - } - - // finally - if (walletGt) await walletGt.close(); - await wallet.close(); - if (err) throw err; - - // attempt to sync unconnected wallet - wallet = await that.createWallet({serverUri: ""}); - err = undefined; - try { - await wallet.sync(); - throw new Error("Should have thrown exception"); - } catch (e1) { - try { - assert.equal(e1.message, "Wallet is not connected to daemon"); - } catch (e2) { - err = e2; - } - } - - // finally - await wallet.close(); - if (err) throw err; - }); - - if (false && testConfig.testNonRelays && !testConfig.liteMode) // TODO: re-enable before release - it("Can sync a wallet created from mnemonic from the genesis", async function() { - await _testSyncMnemonic(undefined, undefined, true, false); - }); - - if (testConfig.testNonRelays) - it("Can sync a wallet created from mnemonic from a restore height", async function() { - await _testSyncMnemonic(undefined, TestUtils.FIRST_RECEIVE_HEIGHT); - }); - - if (testConfig.testNonRelays && !testConfig.liteMode) - it("Can sync a wallet created from mnemonic from a start height.", async function() { - await _testSyncMnemonic(TestUtils.FIRST_RECEIVE_HEIGHT, undefined, false, true); - }); - - if (testConfig.testNonRelays && !testConfig.liteMode) - it("Can sync a wallet created from mnemonic from a start height less than the restore height", async function() { - await _testSyncMnemonic(TestUtils.FIRST_RECEIVE_HEIGHT, TestUtils.FIRST_RECEIVE_HEIGHT + 3); - }); - - if (testConfig.testNonRelays && !testConfig.liteMode) - it("Can sync a wallet created from mnemonic from a start height greater than the restore height", async function() { - await _testSyncMnemonic(TestUtils.FIRST_RECEIVE_HEIGHT + 3, TestUtils.FIRST_RECEIVE_HEIGHT); - }); - - async function _testSyncMnemonic(startHeight, restoreHeight, skipGtComparison, testPostSyncNotifications) { - assert(await that.daemon.isConnected(), "Not connected to daemon"); - if (startHeight !== undefined && restoreHeight != undefined) assert(startHeight <= TestUtils.FIRST_RECEIVE_HEIGHT || restoreHeight <= TestUtils.FIRST_RECEIVE_HEIGHT); - - // create wallet from mnemonic - let wallet = await that.createWallet({mnemonic: TestUtils.MNEMONIC, restoreHeight: restoreHeight}, false); - - // sanitize expected sync bounds - if (restoreHeight === undefined) restoreHeight = 0; - let startHeightExpected = startHeight === undefined ? restoreHeight : startHeight; - if (startHeightExpected === 0) startHeightExpected = 1; - let endHeightExpected = await wallet.getDaemonMaxPeerHeight(); - - // test wallet and close as final step - let walletGt = undefined; - let err = undefined; // to permit final cleanup like Java's try...catch...finally - try { - - // test wallet's height before syncing - assert(await wallet.isConnected()); - assert(!(await wallet.isSynced())); - assert.equal(await wallet.getHeight(), 1); - assert.equal(await wallet.getSyncHeight(), restoreHeight); - - // register a wallet listener which tests notifications throughout the sync - let walletSyncTester = new WalletSyncTester(wallet, startHeightExpected, endHeightExpected); - await wallet.addListener(walletSyncTester); - - // sync the wallet with a listener which tests sync notifications - let progressTester = new SyncProgressTester(wallet, startHeightExpected, endHeightExpected); - let result = await wallet.sync(progressTester, startHeight); - - // test completion of the wallet and sync listeners - await progressTester.onDone(await wallet.getDaemonHeight()); - await walletSyncTester.onDone(await wallet.getDaemonHeight()); - - // test result after syncing - assert(await wallet.isSynced()); - assert.equal(result.getNumBlocksFetched(), await wallet.getDaemonHeight() - startHeightExpected); - assert(result.getReceivedMoney()); - if (await wallet.getHeight() !== await that.daemon.getHeight()) console.log("WARNING: wallet height " + await wallet.getHeight() + " is not synced with daemon height " + await that.daemon.getHeight()); // TODO: height may not be same after long sync - assert.equal(await wallet.getDaemonHeight(), await that.daemon.getHeight(), "Daemon heights are not equal: " + await wallet.getDaemonHeight() + " vs " + await that.daemon.getHeight()); - if (startHeightExpected > TestUtils.FIRST_RECEIVE_HEIGHT) assert((await wallet.getTxs())[0].getHeight() > TestUtils.FIRST_RECEIVE_HEIGHT); // wallet is partially synced so first tx happens after true restore height - else assert.equal((await wallet.getTxs())[0].getHeight(), TestUtils.FIRST_RECEIVE_HEIGHT); // wallet should be fully synced so first tx happens on true restore height - - // sync the wallet with default params - result = await wallet.sync(); - assert(await wallet.isSynced()); - if (await wallet.getHeight() !== await that.daemon.getHeight()) console.log("WARNING: wallet height " + await wallet.getHeight() + " is not synced with daemon height " + await that.daemon.getHeight() + " after re-syncing"); - assert.equal(result.getNumBlocksFetched(), 0); - assert(!result.getReceivedMoney()); - - // compare with ground truth - if (!skipGtComparison) { - walletGt = await that.createWallet({mnemonic: TestUtils.MNEMONIC, restoreHeight: startHeightExpected}); - await walletGt.sync(); - await TestMoneroWalletWasm._testWalletEqualityOnChain(walletGt, wallet); - } - - // if testing post-sync notifications, wait for a block to be added to the chain - // then test that sync arg listener was not invoked and registered wallet listener was invoked - if (testPostSyncNotifications) { - - // start automatic syncing - await wallet.startSyncing(); - - // attempt to start mining to push the network along // TODO: TestUtils.tryStartMining() : reqId, TestUtils.tryStopMining(reqId) - let startedMining = false; - let miningStatus = await that.daemon.getMiningStatus(); - if (!miningStatus.isActive()) { - try { - await StartMining.startMining(); - //await wallet.startMining(7, false, true); // TODO: support client-side mining? - startedMining = true; - } catch (e) { - // no problem - } - } - - try { - - // wait for block - console.log("Waiting for next block to test post sync notifications"); - await that.daemon.getNextBlockHeader(); - - // ensure wallet has time to detect new block - await new Promise(function(resolve) { setTimeout(resolve, MoneroUtils.WALLET_REFRESH_RATE); }); // sleep for the wallet interval - - // test that wallet listener's onSyncProgress() and onNewBlock() were invoked after previous completion - assert(walletSyncTester.getOnSyncProgressAfterDone()); - assert(walletSyncTester.getOnNewBlockAfterDone()); - } catch (e) { - err = e; - } - - // finally - if (startedMining) { - await that.daemon.stopMining(); - //await wallet.stopMining(); // TODO: support client-side mining? - } - if (err) throw err; - } - } catch (e) { - err = e; - } - - // finally - if (walletGt !== undefined) await walletGt.close(true); - await wallet.close(); - if (err) throw err; - } - - if (testConfig.testNonRelays) - it("Can sync a wallet created from keys", async function() { - - // recreate test wallet from keys - let walletKeys = await that.createWallet({primaryAddress: await that.wallet.getPrimaryAddress(), privateViewKey: await that.wallet.getPrivateViewKey(), privateSpendKey: await that.wallet.getPrivateSpendKey(), restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}, false); - - // create ground truth wallet for comparison - let walletGt = await that.getWalletGt(); - - // test wallet and close as final step - let err; - try { - assert.equal(await walletKeys.getMnemonic(), await walletGt.getMnemonic()); - assert.equal(await walletKeys.getPrimaryAddress(), await walletGt.getPrimaryAddress()); - assert.equal(await walletKeys.getPrivateViewKey(), await walletGt.getPrivateViewKey()); - assert.equal(await walletKeys.getPublicViewKey(), await walletGt.getPublicViewKey()); - assert.equal(await walletKeys.getPrivateSpendKey(), await walletGt.getPrivateSpendKey()); - assert.equal(await walletKeys.getPublicSpendKey(), await walletGt.getPublicSpendKey()); - assert.equal(await walletKeys.getSyncHeight(), TestUtils.FIRST_RECEIVE_HEIGHT); - assert(await walletKeys.isConnected()); - assert(!(await walletKeys.isSynced())); - - // sync the wallet - let progressTester = new SyncProgressTester(walletKeys, TestUtils.FIRST_RECEIVE_HEIGHT, await walletKeys.getDaemonMaxPeerHeight()); - let result = await walletKeys.sync(progressTester); - await progressTester.onDone(await walletKeys.getDaemonHeight()); - - // test result after syncing - assert(await walletKeys.isSynced()); - assert.equal(result.getNumBlocksFetched(), await walletKeys.getDaemonHeight() - TestUtils.FIRST_RECEIVE_HEIGHT); - assert(result.getReceivedMoney()); - assert.equal(await walletKeys.getHeight(), await that.daemon.getHeight()); - assert.equal(await walletKeys.getDaemonHeight(), await that.daemon.getHeight()); - assert.equal((await walletKeys.getTxs())[0].getHeight(), TestUtils.FIRST_RECEIVE_HEIGHT); // wallet should be fully synced so first tx happens on true restore height - - // compare with ground truth - await TestMoneroWalletWasm._testWalletEqualityOnChain(walletGt, walletKeys); - } catch (e) { - err = e; - } - - // finally - await walletGt.close(true); - await walletKeys.close(); - if (err) throw err; - }); - - // TODO: test start syncing, notification of syncs happening, stop syncing, no notifications, etc - if (testConfig.testNonRelays) - it("Can start and stop syncing", async function() { - - // test unconnected wallet - let err; // used to emulate Java's try...catch...finally - let path = TestMoneroWalletWasm._getRandomWalletPath(); - let wallet = await that.createWallet({path: path, password: TestUtils.WALLET_PASSWORD, networkType: TestUtils.NETWORK_TYPE, serverUri: ""}); - try { - assert.notEqual(await wallet.getMnemonic(), undefined); - assert.equal(await wallet.getHeight(), 1); - assert.equal(await wallet.getBalance(), BigInteger.parse("0")); - await wallet.startSyncing(); - } catch (e1) { // first error is expected - try { - assert.equal(e1.message, "Wallet is not connected to daemon"); - } catch (e2) { - err = e2; - } - } - - // finally - await wallet.close(); - if (err) throw err; - - // test connecting wallet - path = TestMoneroWalletWasm._getRandomWalletPath(); - wallet = await that.createWallet({path: path, password: TestUtils.WALLET_PASSWORD, networkType: TestUtils.NETWORK_TYPE, serverUri: ""}); - try { - assert.notEqual(wallet.getMnemonic(), undefined); - assert(!await wallet.isConnected()); - await wallet.setDaemonConnection(await that.daemon.getRpcConnection()); - assert.equal(await wallet.getHeight(), 1); - assert(!await wallet.isSynced()); - assert.equal((await wallet.getBalance()).compare(new BigInteger(0)), 0); - let chainHeight = await wallet.getDaemonHeight(); - await wallet.setSyncHeight(chainHeight - 3); - await wallet.startSyncing(); - assert.equal(await wallet.getSyncHeight(), chainHeight - 3); - assert.equal((await wallet.getDaemonConnection()).getUri(), (await that.daemon.getRpcConnection()).getUri()); // TODO: replace with config comparison - assert.equal((await wallet.getDaemonConnection()).getUsername(), (await that.daemon.getRpcConnection()).getUsername()); - assert.equal((await wallet.getDaemonConnection()).getPassword(), (await that.daemon.getRpcConnection()).getPassword()); - await wallet.stopSyncing(); - await wallet.sync(); - await wallet.stopSyncing(); - await wallet.stopSyncing(); - } catch (e) { - err = e; - } - - // finally - await wallet.close(); - if (err) throw err; - - // test that sync starts automatically - let restoreHeight = await that.daemon.getHeight() - 100; - path = TestMoneroWalletWasm._getRandomWalletPath(); - wallet = await that.createWallet({path: path, password: TestUtils.WALLET_PASSWORD, networkType: TestUtils.NETWORK_TYPE, mnemonic: TestUtils.MNEMONIC, server: await that.daemon.getRpcConnection(), restoreHeight: restoreHeight}, false); - try { - - // start syncing - assert.equal(await wallet.getHeight(), 1); - assert.equal(await wallet.getSyncHeight(), restoreHeight); - assert(!(await wallet.isSynced())); - assert.equal(await wallet.getBalance(), new BigInteger(0)); - await wallet.startSyncing(); - - // sleep for a moment - await new Promise(function(resolve) { setTimeout(resolve, 15000); }); // in ms - - // test that wallet has started syncing - assert(await wallet.getHeight() > 1); - - // stop syncing - await wallet.stopSyncing(); - - // TODO monero core: wallet.cpp m_synchronized only ever set to true, never false -// // wait for block to be added to chain -// await that.daemon.getNextBlockHeader(); -// -// // wallet is no longer synced -// assert(!(await wallet.isSynced())); - } catch (e) { - err = e; - } - - // finally - await wallet.close(); - if (err) throw err; - }); - - if (testConfig.testNonRelays) - it("Does not interfere with other wallet notifications", async function() { - - // create 2 wallets with a recent restore height - let height = await that.daemon.getHeight(); - let restoreHeight = height - 5; - let wallet1 = await that.createWallet({mnemonic: TestUtils.MNEMONIC, restoreHeight: restoreHeight}, false); - let wallet2 = await that.createWallet({mnemonic: TestUtils.MNEMONIC, restoreHeight: restoreHeight}, false); - - // track notifications of each wallet - let tester1 = new SyncProgressTester(wallet1, restoreHeight, height); - let tester2 = new SyncProgressTester(wallet2, restoreHeight, height); - await wallet1.addListener(tester1); - await wallet2.addListener(tester2); - - // sync first wallet and test that 2nd is not notified - await wallet1.sync(); - assert(tester1.isNotified()); - assert(!tester2.isNotified()); - - // sync 2nd wallet and test that 1st is not notified - let tester3 = new SyncProgressTester(wallet1, restoreHeight, height); - await wallet1.addListener(tester3); - await wallet2.sync(); - assert(tester2.isNotified()); - assert(!(tester3.isNotified())); - - // close wallets - await wallet1.close(); - await wallet2.close(); - }); - - if (testConfig.testNonRelays) - it("Is equal to the RPC wallet.", async function() { - await WalletEqualityUtils.testWalletEqualityOnChain(await TestUtils.getWalletRpc(), that.wallet); - }); - - if (testConfig.testNonRelays) - it("Is equal to the RPC wallet with a seed offset", async function() { - - // use common offset to compare wallet implementations - let seedOffset = "my super secret offset!"; - - // create rpc wallet with offset - let walletRpc = await TestUtils.getWalletRpc(); - await walletRpc.createWallet({path: GenUtils.getUUID(), password: TestUtils.WALLET_PASSWORD, mnemonic: await walletRpc.getMnemonic(), restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, seedOffset: seedOffset}); - - // create wasm wallet with offset - let walletWasm = await that.createWallet({mnemonic: TestUtils.MNEMONIC, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, seedOffset: seedOffset}); - - // deep compare - let err; - try { - await WalletEqualityUtils.testWalletEqualityOnChain(walletRpc, walletWasm); - } catch (e) { - err = e; - } - await walletWasm.close(); - if (err) throw err; - }); - - if (testConfig.testNonRelays) - it("Supports multisig sample code", async function() { - await testCreateMultisigWallet(2, 2); - await testCreateMultisigWallet(2, 3); - await testCreateMultisigWallet(2, 4); - }); - - async function testCreateMultisigWallet(M, N) { - console.log("Creating " + M + "/" + N + " multisig wallet"); - - // create participating wallets - let wallets = [] - for (let i = 0; i < N; i++) { - wallets.push(await that.createWallet()); - } - - // prepare and collect multisig hex from each participant - let preparedMultisigHexes = [] - for (let wallet of wallets) preparedMultisigHexes.push(await wallet.prepareMultisig()); - - // make each wallet multsig and collect results - let madeMultisigHexes = []; - for (let i = 0; i < wallets.length; i++) { - - // collect prepared multisig hexes from wallet's peers - let peerMultisigHexes = []; - for (let j = 0; j < wallets.length; j++) if (j !== i) peerMultisigHexes.push(preparedMultisigHexes[j]); - - // make wallet multisig and collect result hex - let result = await wallets[i].makeMultisig(peerMultisigHexes, M, TestUtils.WALLET_PASSWORD); - madeMultisigHexes.push(result.getMultisigHex()); - } - - // if wallet is not N/N, exchange multisig keys N-M times - if (M !== N) { - let multisigHexes = madeMultisigHexes; - for (let i = 0; i < N - M; i++) { - - // exchange multisig keys among participants and collect results for next round if applicable - let resultMultisigHexes = []; - for (let wallet of wallets) { - - // import the multisig hex of other participants and collect results - let result = await wallet.exchangeMultisigKeys(multisigHexes, TestUtils.WALLET_PASSWORD); - resultMultisigHexes.push(result.getMultisigHex()); - } - - // use resulting multisig hex for next round of exchange if applicable - multisigHexes = resultMultisigHexes; - } - } - - // wallets are now multisig - for (let wallet of wallets) { - let primaryAddress = await wallet.getAddress(0, 0); - MoneroUtils.validateAddress(primaryAddress, await wallet.getNetworkType()); - let info = await wallet.getMultisigInfo(); - assert(info.isMultisig()); - assert(info.isReady()); - assert.equal(info.getThreshold(), M); - assert.equal(info.getNumParticipants(), N); - await wallet.close(true); - } - } - - if (testConfig.testNonRelays) - it("Can be saved", async function() { - - // create unique path for new test wallet - let path = TestMoneroWalletWasm._getRandomWalletPath(); - - // wallet does not exist - assert(!(await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs()))); - - // cannot open non-existant wallet - try { - await that.openWallet({path: path, serverUri: ""}); - throw new Error("Cannot open non-existant wallet"); - } catch (e) { - assert.equal(e.message, "Wallet does not exist at path: " + path); - } - - // create wallet at the path - let restoreHeight = await that.daemon.getHeight() - 200; - let wallet = await that.createWallet({path: path, password: TestUtils.WALLET_PASSWORD, networkType: TestUtils.NETWORK_TYPE, mnemonic: TestUtils.MNEMONIC, restoreHeight: restoreHeight}); - - // test wallet at newly created state - let err; - try { - assert(await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs())); - assert.equal(await wallet.getMnemonic(), TestUtils.MNEMONIC); - assert.equal(await wallet.getNetworkType(), TestUtils.NETWORK_TYPE); - assert.equal(await wallet.getDaemonConnection(), undefined); - assert.equal(await wallet.getSyncHeight(), restoreHeight); - assert.equal(await wallet.getMnemonicLanguage(), "English"); - assert.equal(await wallet.getHeight(), 1); - assert.equal(await wallet.getSyncHeight(), restoreHeight); - - // set the wallet's connection and sync - await wallet.setDaemonConnection(TestUtils.getDaemonRpcConnection()); - await wallet.sync(); - if (await wallet.getHeight() !== await wallet.getDaemonHeight()) console.log("WARNING: wallet height " + await wallet.getHeight() + " is not synced with daemon height " + await that.daemon.getHeight()); // TODO: height may not be same after long sync - - // close the wallet without saving - await wallet.close(); - - // re-open the wallet - wallet = await that.openWallet({path: path}); - - // test wallet is at newly created state - assert(await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs())); - assert.equal(await wallet.getMnemonic(), TestUtils.MNEMONIC); - assert.equal(await wallet.getNetworkType(), TestUtils.NETWORK_TYPE); - assert.equal(await wallet.getDaemonConnection(), undefined); - assert(!(await wallet.isConnected())); - assert.equal(await wallet.getMnemonicLanguage(), "English"); - assert(!(await wallet.isSynced())); - assert.equal(await wallet.getHeight(), 1); - assert.equal(await wallet.getSyncHeight(), 0); // TODO monero-core: restoreHeight is reset to 0 after closing - - // set the wallet's connection and sync - await wallet.setDaemonConnection(TestUtils.getDaemonRpcConnection()); - assert(await wallet.isConnected()); - await wallet.setSyncHeight(restoreHeight); - await wallet.sync(); - assert(await wallet.isSynced()); - assert.equal(await wallet.getHeight(), await wallet.getDaemonHeight()); - let prevHeight = await wallet.getHeight(); - - // save and close the wallet - await wallet.save(); - await wallet.close(); - - // re-open the wallet - wallet = await that.openWallet({path: path, serverUri: ""}); - - // test wallet state is saved - assert(!(await wallet.isConnected())); - await wallet.setDaemonConnection(TestUtils.getDaemonRpcConnection()); // TODO monero core: daemon connection not stored in wallet files so must be explicitly set each time - assert.equal(await wallet.getDaemonConnection(), TestUtils.getDaemonRpcConnection()); - assert(await wallet.isConnected()); - assert.equal(await wallet.getHeight(), prevHeight); - assert.equal(await wallet.getSyncHeight(), 0); // TODO monero core: restoreHeight is reset to 0 after closing - assert(await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs())); - assert.equal(await wallet.getMnemonic(), TestUtils.MNEMONIC); - assert.equal(await wallet.getNetworkType(), TestUtils.NETWORK_TYPE); - assert.equal(await wallet.getMnemonicLanguage(), "English"); - - // sync - await wallet.sync(); - } catch (e) { - let err = e; - } - - // finally - await wallet.close(); - if (err) throw err; - }); - - if (testConfig.testNonRelays) - it("Can be moved", async function() { - let err; - let wallet; - try { - - // create unique name for test wallet - let walletName = "test_wallet_" + GenUtils.getUUID(); - let path = TestUtils.TEST_WALLETS_DIR + "/" + walletName; - - // wallet does not exist - assert(!await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs())); - - // create wallet at the path - let restoreHeight = await that.daemon.getHeight() - 200; - wallet = await that.createWallet({path: path, mnemonic: TestUtils.MNEMONIC, restoreHeight: restoreHeight, serverUri: ""}); - let subaddressLabel = "Move test wallet subaddress!"; - let account = await wallet.createAccount(subaddressLabel); - await wallet.save(); - - // wallet exists - assert(await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs())); - - // move wallet to a subdirectory - let movedPath = TestUtils.TEST_WALLETS_DIR + "/moved/" + walletName; - await wallet.moveTo(movedPath, TestUtils.WALLET_PASSWORD); - assert(!(await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs()))); - assert(!(await MoneroWalletWasm.walletExists(movedPath, TestUtils.getDefaultFs()))); // wallet does not exist until saved - await wallet.save(); - assert(!(await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs()))); - assert(await MoneroWalletWasm.walletExists(movedPath, TestUtils.getDefaultFs())); - await wallet.close(); - assert(!(await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs()))); - assert(await MoneroWalletWasm.walletExists(movedPath, TestUtils.getDefaultFs())); - - // re-open and test wallet - wallet = await that.openWallet({path: movedPath, serverUri: ""}); - assert.equal(await wallet.getSubaddress(account.getIndex(), 0).getLabel(), subaddressLabel); - - // move wallet back - await wallet.moveTo(path, TestUtils.WALLET_PASSWORD); - assert(!(await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs()))); // wallet does not exist until saved - assert(!(await MoneroWalletWasm.walletExists(movedPath, TestUtils.getDefaultFs()))); - await wallet.save(); - assert(await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs())); - assert(!(await MoneroWalletWasm.walletExists(movedPath, TestUtils.getDefaultFs()))); - await wallet.close(); - assert(await monerojs.MoneroWalletWasm.walletExists(path, TestUtils.getDefaultFs())); - assert(!(await MoneroWalletWasm.walletExists(movedPath, TestUtils.getDefaultFs()))); - } catch (e) { - err = e; - } - - // final cleanup - if (wallet) await wallet.close(); - if (err) throw err; - }); - - if (testConfig.testNonRelays) - it("Can be closed", async function() { - let err; - let wallet; - try { - - // create a test wallet - wallet = await that.createWallet(); - let path = await wallet.getPath(); - await wallet.sync(); - assert(await wallet.getHeight() > 1); - assert(await wallet.isSynced()); - assert.equal(await wallet.isClosed(), false); - - // close the wallet - await wallet.close(); - assert(await wallet.isClosed()); - - // attempt to interact with the wallet - try { await wallet.getHeight(); } - catch (e) { assert.equal(e.message, "Wallet is closed"); } - try { await wallet.getMnemonic(); } - catch (e) { assert.equal(e.message, "Wallet is closed"); } - try { await wallet.sync(); } - catch (e) { assert.equal(e.message, "Wallet is closed"); } - try { await wallet.startSyncing(); } - catch (e) { assert.equal(e.message, "Wallet is closed"); } - try { await wallet.stopSyncing(); } - catch (e) { assert.equal(e.message, "Wallet is closed"); } - - // re-open the wallet - wallet = await that.openWallet({path: path}); - await wallet.sync(); - assert.equal(await wallet.getHeight(), await wallet.getDaemonHeight()); - assert.equal(await wallet.isClosed(), false); - } catch (e) { - console.log(e); - err = e; - } - - // final cleanup - await wallet.close(); - assert(await wallet.isClosed()); - if (err) throw err; - }); - - // ----------------------------- NOTIFICATION TESTS ------------------------- - - if (testConfig.testRelays) - it("Receives funds within 10 seconds.", async function() { - await testReceivesFundsWithin10Seconds(false); - }); - - if (testConfig.testRelays && !testConfig.liteMode) - it("Receives funds within 10 seconds to the same account", async function() { - await testReceivesFundsWithin10Seconds(true); - }); - - async function testReceivesFundsWithin10Seconds(sameAccount) { - let sender = that.wallet; - let receiver; - let receiverListener; - let senderListener; - let err; - try { - - // assign wallet to receive funds - receiver = sameAccount ? that.wallet : await that.createWallet(new MoneroWalletConfig()); - - // listen for sent funds - let sender = that.wallet; - senderListener = new OutputNotificationCollector(); - await sender.addListener(senderListener); - - // listen for received funds - receiverListener = new OutputNotificationCollector(); - await receiver.addListener(receiverListener); - - // send funds - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(sender); - let tx = await sender.createTx({accountIndex: 0, address: await receiver.getPrimaryAddress(), amount: TestUtils.MAX_FEE, relay: true}) - await sender.getTx(tx.getHash()); - if (senderListener.getOutputsSpent().length === 0) console.log("WARNING: no notification on send"); - - // unconfirmed funds received within 10 seconds - await new Promise(function(resolve) { setTimeout(resolve, 10000); }); - await receiver.getTx(tx.getHash()); - assert(receiverListener.getOutputsReceived().length !== 0, "No notification of received funds within 10 seconds in " + (sameAccount ? "same account" : "different wallets")); - for (let output of receiverListener.getOutputsReceived()) assert(output.getTx().isConfirmed() !== undefined); - } catch (e) { - err = e; - } - - // finally - await sender.removeListener(senderListener); - await receiver.removeListener(receiverListener); - if (!sameAccount && receiver !== undefined) await receiver.close(); - if (err) throw err; - } - - /** - * 4 output notification tests are considered when transferring within one wallet. // TODO: multi-wallet tests - * - * 1. with local wallet data, transfer from/to same account - * 2. with local wallet data, transfer from/to different accounts - * 3. without local wallet data, transfer from/to same account - * 4. without local wallet data, transfer from/to different accounts - * - * For example, two wallets may be instantiated with the same mnemonic, - * so neither is privy to the local wallet data of the other. - */ - - if (!testConfig.liteMode && testConfig.testNotifications) - it("Notification test #1: notifies listeners of outputs sent from/to the same account using local wallet data", async function() { - let issues = await testOutputNotifications(true); - if (issues === undefined) return; - let msg = "testOutputNotificationsSameAccounts() generated " + issues.length + " issues:\n" + issuesToStr(issues); - console.log(msg); - assert(!msg.includes("ERROR:"), msg); - }); - - if (!testConfig.liteMode && testConfig.testNotifications) - it("Notification test #2: notifies listeners of outputs sent from/to different accounts using local wallet data", async function() { - let issues = await testOutputNotifications(false); - if (issues === undefined) return; - let msg = "testOutputNotificationsDifferentAccounts() generated " + issues.length + " issues:\n" + issuesToStr(issues); - console.log(msg); - assert(!msg.includes("ERROR:"), msg); - }); - - if (!testConfig.liteMode && testConfig.testNotifications) - it("Notification test #3: notifies listeners of swept outputs", async function() { - let issues = await testOutputNotifications(false, true); - if (issues === undefined) return; - let msg = "testOutputNotificationsSweep() generated " + issues.length + " issues:\n" + issuesToStr(issues); - console.log(msg); - assert(!msg.includes("ERROR:"), msg); - }); - - async function testOutputNotifications(sameAccount, sweepOutput) { - - // collect errors and warnings - let errors = []; - let wallet = that.wallet; - - // wait for wallet txs in the pool in case they were sent from another wallet and therefore will not fully sync until confirmed // TODO monero core - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(wallet); - - // get balances before for later comparison - let balanceBefore = await wallet.getBalance(); - let unlockedBalanceBefore = await wallet.getUnlockedBalance(); - - // register a listener to collect notifications - let listener = new OutputNotificationCollector(); - await wallet.addListener(listener); - - // start syncing to test automatic notifications - await wallet.startSyncing(); - - // send tx - let tx; - let destinationAccounts = sameAccount ? (sweepOutput ? [0] : [0, 1, 2]) : (sweepOutput ? [1] : [1, 2, 3]); - if (sweepOutput) { - let outputs = await wallet.getOutputs({isSpent: false, isLocked: false, accountIdx: 0, minAmount: TestUtils.MAX_FEE.multiply(new BigInteger(5))}); - if (outputs.length === 0) { - errors.push("ERROR: No outputs available to sweep"); - return errors; - } - tx = await wallet.sweepOutput({address: await wallet.getAddress(destinationAccounts[0], 0), keyImage: outputs[0].getKeyImage().getHex(), relay: true}); - } else { - let config = new MoneroTxConfig(); - config.setAccountIndex(0); - for (let destinationAccount of destinationAccounts) config.addDestination(new MoneroDestination(await wallet.getAddress(destinationAccount, 0), TestUtils.MAX_FEE)); - config.setRelay(true); - tx = await wallet.createTx(config); - } - - // test wallet's balance - let balanceAfter = await wallet.getBalance(); - let unlockedBalanceAfter = await wallet.getUnlockedBalance(); - let balanceAfterExpected = balanceBefore.subtract(tx.getFee()); // txs sent from/to same wallet so only decrease in balance is tx fee - if (balanceAfterExpected.compare(balanceAfter) !== 0) errors.push("WARNING: wallet balance immediately after send expected to be " + balanceAfterExpected + " but was " + balanceAfter); - if (unlockedBalanceBefore.compare(unlockedBalanceAfter) <= 0 && unlockedBalanceBefore.compare(BigInteger.parse("0")) !== 0) errors.push("WARNING: Wallet unlocked balance immediately after send was expected to decrease but changed from " + unlockedBalanceBefore + " to " + unlockedBalanceAfter); - - // wait for wallet to send notifications - if (listener.getOutputsSpent().length === 0) errors.push("WARNING: wallet does not notify listeners of outputs when tx sent directly through wallet or when refreshed from the pool; must wait for confirmation to receive notifications and have correct balance"); - try { await StartMining.startMining(); } catch (e) { } - while (listener.getOutputsSpent().length === 0) { - if ((await that.wallet.getTx(tx.getHash())).isFailed()) { - try { await that.daemon.stopMining(); } catch (e) { } - errors.push("ERROR: Tx failed in mempool: " + tx.getHash()); - return errors; - } - await that.daemon.getNextBlockHeader(); - } - try { await that.daemon.stopMining(); } catch (e) { } - - // test output notifications - if (listener.getOutputsReceived().length === 0) { - errors.push("ERROR: got " + listener.getOutputsReceived().length + " output received notifications when at least 1 was expected"); - return errors; - } - if (listener.getOutputsSpent().length === 0) { - errors.push("ERROR: got " + listener.getOutputsSpent().length + " output spent notifications when at least 1 was expected"); - return errors; - } - - // must receive outputs with known subaddresses and amounts - for (let destinationAccount of destinationAccounts) { - if (!hasOutput(listener.getOutputsReceived(), destinationAccount, 0, sweepOutput ? undefined : TestUtils.MAX_FEE)) { - errors.push("ERROR: missing expected received output to subaddress [" + destinationAccount + ", 0] of amount " + TestUtils.MAX_FEE); - return errors; - } - } - - // since sending from/to the same wallet, the net amount spent = tx fee = outputs spent - outputs received - let numConfirmedOutputs = 0; - let netAmount = BigInteger.parse("0"); - for (let outputSpent of listener.getOutputsSpent()) netAmount = netAmount.add(outputSpent.getAmount()); - for (let outputReceived of listener.getOutputsReceived()) { - if (outputReceived.getTx().isConfirmed()) { - numConfirmedOutputs++; - netAmount = netAmount.subtract(outputReceived.getAmount()); - } - } - if (tx.getFee().compare(netAmount) !== 0) { - errors.push("WARNING: net output amount must equal tx fee: " + tx.getFee().toString() + " vs " + netAmount.toString() + " (probably received notifications from other tests)"); - return errors; - } - - // receives balance notification per confirmed output - if (listener.getBalanceNotifications().length < numConfirmedOutputs) { - errors.push("ERROR: expected at least one updated balance notification per confirmed output received"); - } - - // test wallet's balance - balanceAfter = await wallet.getBalance(); - unlockedBalanceAfter = await wallet.getUnlockedBalance(); - if (balanceAfterExpected.compare(balanceAfter) !== 0) errors.push("WARNING: Wallet balance after confirmation expected to be " + balanceAfterExpected + " but was " + balanceAfter); - if (unlockedBalanceBefore.compare(unlockedBalanceAfter) <= 0 && unlockedBalanceBefore.compare(BigInteger.parse("0")) !== 0) errors.push("WARNING: Wallet unlocked balance immediately after send was expected to decrease but changed from " + unlockedBalanceBefore + " to " + unlockedBalanceAfter); - - // remove listener - await wallet.removeListener(listener); - - // return all errors and warnings as single string - return errors; - } - - function issuesToStr(issues) { - if (issues.length === 0) return undefined; - let str = ""; - for (let i = 0; i < issues.length; i++) { - str += (i + 1) + ": " + issues[i]; - if (i < issues.length - 1) str += "\n"; - } - return str; - } - - function hasOutput(outputs, accountIdx, subaddressIdx, amount) { // TODO: use common filter? - let query = new MoneroOutputQuery().setAccountIndex(accountIdx).setSubaddressIndex(subaddressIdx).setAmount(amount); - for (let output of outputs) { - if (query.meetsCriteria(output)) return true; - } - return false; - } - - if (!testConfig.liteMode && testConfig.testNotifications) - it("Can receive notifications when outputs are received, confirmed, and unlocked", async function() { - await testReceivedOutputNotificationsWithUnlockHeight(0); - }); - - if (!testConfig.liteMode && testConfig.testNotifications) - it("Can receive notifications when outputs are received, confirmed, and unlocked with an unlock height", async function() { - await testReceivedOutputNotificationsWithUnlockHeight(13); - }); - - async function testReceivedOutputNotificationsWithUnlockHeight(unlockDelay) { - let expectedUnlockHeight = await that.daemon.getHeight() + unlockDelay; - - // create wallet to test received output notifications - let receiver = await that.createWallet(new MoneroWalletConfig()); - - // create tx to transfer funds to receiver - let tx = await that.wallet.createTx(new MoneroTxConfig() - .setAccountIndex(0) - .setAddress(await receiver.getPrimaryAddress()) - .setAmount(TestUtils.MAX_FEE.multiply(BigInteger.parse("10"))) - .setUnlockHeight(expectedUnlockHeight) - .setRelay(false) - ); - - // register listener to test notifications - let listener = new ReceivedOutputNotificationTester(tx.getHash()); - await receiver.addListener(listener); - - // flush tx to prevent double spends from previous tests - await that.daemon.flushTxPool(); - - // relay transaction to pool - let submitHeight = await that.daemon.getHeight(); - //await that.wallet.relayTx(tx); - let result = await that.daemon.submitTxHex(tx.getFullHex()); - assert(result.isGood(), "Bad submit tx result: " + result.toJson()); - - // test notification of tx in pool within 10 seconds - await new Promise(function(resolve) { setTimeout(resolve, 10000); }); - assert(listener.lastNotifiedOutput); - assert(!listener.lastNotifiedOutput.getTx().isConfirmed()); - - // listen for new blocks to test output notifications - receiver.addListener(new class extends MoneroWalletListener { - async onNewBlock(height) { - if (listener.testComplete) return; - try { - - // first confirmation expected within 10 seconds of new block - if (listener.confirmedHeight === undefined) { - await new Promise(function(resolve) { setTimeout(resolve, 10000); }); - if (listener.confirmedHeight === undefined && listener.lastNotifiedOutput.getTx().isConfirmed()) { // only run by first thread after confirmation - listener.confirmedHeight = listener.lastNotifiedOutput.getTx().getHeight(); - if (listener.confirmedHeight !== submitHeight) console.log("WARNING: tx submitted on height " + submitHeight + " but confirmed on height " + listener.confirmedHeight); - } - } - - // output should be locked until max of expected unlock height and 10 blocks after confirmation - if ((listener.confirmedHeight === undefined || height < Math.max(listener.confirmedHeight + 10, expectedUnlockHeight)) && false === listener.lastNotifiedOutput.isLocked()) throw new Error("Last notified output expected to be locked but isLocked=" + listener.lastNotifiedOutput.isLocked() + " at height " + height); - - // test unlock notification - if (listener.confirmedHeight !== undefined && height === Math.max(listener.confirmedHeight + 10, expectedUnlockHeight)) { - - // receives notification of unlocked tx within 1 second of block notification - await new Promise(function(resolve) { setTimeout(resolve, 1000); }); - if (listener.lastNotifiedOutput.isLocked() !== false) throw new Error("Last notified output expected to be unlocked but isLocked=" + listener.lastNotifiedOutput.isLocked()); - listener.unlockedSeen = true; - listener.testComplete = true; - } - } catch (err) { - console.log(err); - listener.testComplete = true; - listener.testError = err.message; - } - } - }); - - // mine until complete - await StartMining.startMining(); - - // run until test completes - while (!listener.testComplete) await new Promise(function(resolve) { setTimeout(resolve, 10000); }); - if ((await that.daemon.getMiningStatus()).isActive()) await that.daemon.stopMining(); - assert.equal(undefined, listener.testError); - assert(listener.confirmedHeight !== undefined, "No notification of output confirmed", ); - assert(listener.unlockedSeen, "No notification of output unlocked"); - } - - if (testConfig.testNotifications) - it("Can be created and receive funds", async function() { - let err; - let myWallet; - try { - - // create a random stagenet wallet - myWallet = await that.createWallet({password: "mysupersecretpassword123"}); - await myWallet.startSyncing(); - - // listen for received outputs - let myListener = new OutputNotificationCollector(); - await myWallet.addListener(myListener); - - // send funds to the created wallet - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(that.wallet); - let sentTx = await that.wallet.createTx({accountIndex: 0, address: await myWallet.getPrimaryAddress(), amount: TestUtils.MAX_FEE, relay: true}); - - // wait for funds to confirm - try { await StartMining.startMining(); } catch (e) { } - while (!(await that.wallet.getTx(sentTx.getHash())).isConfirmed()) { - if ((await that.wallet.getTx(sentTx.getHash())).isFailed()) throw new Error("Tx failed in mempool: " + sentTx.getHash()); - await that.daemon.getNextBlockHeader(); - } - - // created wallet should have notified listeners of received outputs - assert(myListener.getOutputsReceived().length > 0, "Listener did not receive outputs"); - } catch (e) { - err = e; - } - - // final cleanup - try { await that.daemon.stopMining(); } catch (e) { } - await myWallet.close(); - if (err) throw err; - }); - }); - } - - //----------------------------- PRIVATE HELPERS ----------------------------- - - static _getRandomWalletPath() { - return TestUtils.TEST_WALLETS_DIR + "/test_wallet_" + GenUtils.getUUID(); - } - - // possible configuration: on chain xor local wallet data ("strict"), txs ordered same way? TBD - static async _testWalletEqualityOnChain(wallet1, wallet2) { - await WalletEqualityUtils.testWalletEqualityOnChain(wallet1, wallet2); - assert.equal(await wallet2.getNetworkType(), await wallet1.getNetworkType()); - //assert.equal(await wallet2.getSyncHeight(), await wallet1.getSyncHeight()); // TODO monero-core: sync height is lost after close - assert.equal((await wallet2.getDaemonConnection()).getUri(), (await wallet1.getDaemonConnection()).getUri()); - assert.equal((await wallet2.getDaemonConnection()).getUsername(), (await wallet1.getDaemonConnection()).getUsername()); - assert.equal((await wallet2.getDaemonConnection()).getPassword(), (await wallet1.getDaemonConnection()).getPassword()); - assert.equal(await wallet2.getMnemonicLanguage(), await wallet1.getMnemonicLanguage()); - // TODO: more wasm-specific extensions - } -} - -/** - * Wallet listener to collect output notifications. - */ -class OutputNotificationCollector extends MoneroWalletListener { - - constructor() { - super(); - this.balanceNotifications = []; - this.outputsReceived = []; - this.outputsSpent = []; - } - - onBalancesChanged(newBalance, newUnlockedBalance) { - if (this.balanceNotifications.length > 0) { - this.lastNotification = this.balanceNotifications[this.balanceNotifications.length - 1]; - assert(newBalance.toString() !== this.lastNotification.balance.toString() || newUnlockedBalance.toString() !== this.lastNotification.unlockedBalance.toString()); - } - this.balanceNotifications.push({balance: newBalance, unlockedBalance: newUnlockedBalance}); - } - - onOutputReceived(output) { - this.outputsReceived.push(output); - } - - onOutputSpent(output) { - this.outputsSpent.push(output); - } - - getBalanceNotifications() { - return this.balanceNotifications; - } - - getOutputsReceived() { - return this.outputsReceived; - } - - getOutputsSpent() { - return this.outputsSpent; - } -} - -/** - * Helper class to test progress updates. - */ -class SyncProgressTester extends WalletSyncPrinter { - - constructor(wallet, startHeight, endHeight) { - super(); - this.wallet = wallet; - assert(startHeight >= 0); - assert(endHeight >= 0); - this.startHeight = startHeight; - this.prevEndHeight = endHeight; - this.isDone = false; - } - - onSyncProgress(height, startHeight, endHeight, percentDone, message) { - super.onSyncProgress(height, startHeight, endHeight, percentDone, message); - - // registered wallet listeners will continue to get sync notifications after the wallet's initial sync - if (this.isDone) { - assert(this.wallet.getListeners().includes(this), "Listener has completed and is not registered so should not be called again"); - this.onSyncProgressAfterDone = true; - } - - // update tester's start height if new sync session - if (this.prevCompleteHeight !== undefined && startHeight === this.prevCompleteHeight) this.startHeight = startHeight; - - // if sync is complete, record completion height for subsequent start heights - if (percentDone === 1) this.prevCompleteHeight = endHeight; - - // otherwise start height is equal to previous completion height - else if (this.prevCompleteHeight !== undefined) assert.equal(startHeight, this.prevCompleteHeight); - - assert(endHeight > startHeight, "end height > start height"); - assert.equal(startHeight, this.startHeight); - assert(endHeight >= this.prevEndHeight); // chain can grow while syncing - this.prevEndHeight = endHeight; - assert(height >= startHeight); - assert(height < endHeight); - let expectedPercentDone = (height - startHeight + 1) / (endHeight - startHeight); - assert.equal(expectedPercentDone, percentDone); - if (this.prevHeight === undefined) assert.equal(height, startHeight); - else assert.equal(this.prevHeight + 1, height); - this.prevHeight = height; - } - - async onDone(chainHeight) { - assert(!this.isDone); - this.isDone = true; - if (this.prevHeight === undefined) { - assert.equal(this.prevCompleteHeight, undefined); - assert.equal(this.startHeight, chainHeight); - } else { - assert.equal(this.prevHeight, chainHeight - 1); // otherwise last height is chain height - 1 - assert.equal(this.prevCompleteHeight, chainHeight); - } - this.onSyncProgressAfterDone = false; // test subsequent onSyncProgress() calls - } - - isNotified() { - return this.prevHeight !== undefined; - } - - getOnSyncProgressAfterDone() { - return this.onSyncProgressAfterDone; - } -} - -/** - * Internal class to test all wallet notifications on sync. - */ -class WalletSyncTester extends SyncProgressTester { - - constructor(wallet, startHeight, endHeight) { - super(wallet, startHeight, endHeight); - assert(startHeight >= 0); - assert(endHeight >= 0); - this.incomingTotal = BigInteger.parse("0"); - this.outgoingTotal = BigInteger.parse("0"); - } - - onNewBlock(height) { - if (this.isDone) { - assert(this.wallet.getListeners().includes(this), "Listener has completed and is not registered so should not be called again"); - this.onNewBlockAfterDone = true; - } - if (this.walletTesterPrevHeight !== undefined) assert.equal(height, this.walletTesterPrevHeight + 1); - assert(height >= this.startHeight); - this.walletTesterPrevHeight = height; - } - - async onBalancesChanged(newBalance, newUnlockedBalance) { - //assert.equal(newBalance.toString(), (await this.wallet.getBalance()).toString()); // TODO: asynchronous balance queries block until done syncing - //assert.equal(newUnlockedBalance.toString(), (await this.wallet.getUnlockedBalance()).toString()); - if (this.prevBalance !== undefined) assert(newBalance.toString() !== this.prevBalance.toString() || newUnlockedBalance.toString() !== this.prevUnlockedBalance.toString()); - this.prevBalance = newBalance; - this.prevUnlockedBalance = newUnlockedBalance; - } - - onOutputReceived(output) { - assert.notEqual(output, undefined); - this.prevOutputReceived = output; - - // test output - TestUtils.testUnsignedBigInteger(output.getAmount()); - assert(output.getAccountIndex() >= 0); - assert(output.getSubaddressIndex() >= 0); - - // test output's tx - assert(output.getTx()); - assert(output.getTx() instanceof MoneroTxWallet); - assert(output.getTx().getHash()); - assert.equal(output.getTx().getHash().length, 64); - assert(output.getTx().getVersion() >= 0); - assert(output.getTx().getUnlockHeight() >= 0); - assert.equal(output.getTx().getInputs(), undefined); - assert.equal(output.getTx().getOutputs().length, 1); - assert(output.getTx().getOutputs()[0] === output); - - // extra is not sent over the wasm bridge - assert.equal(output.getTx().getExtra(), undefined); - - // add incoming amount to running total if confirmed - if (output.getTx().isConfirmed()) this.incomingTotal = this.incomingTotal.add(output.getAmount()); - } - - onOutputSpent(output) { - assert.notEqual(output, undefined); - this.prevOutputSpent = output; - - // test output - TestUtils.testUnsignedBigInteger(output.getAmount()); - assert(output.getAccountIndex() >= 0); - assert(output.getSubaddressIndex() >= 0); - - // test output's tx - assert(output.getTx()); - assert(output.getTx() instanceof MoneroTxWallet); - assert(output.getTx().getHash()); - assert.equal(output.getTx().getHash().length, 64); - assert(output.getTx().getVersion() >= 0); - assert.equal(output.getTx().getUnlockHeight(), undefined); - assert.equal(output.getTx().getInputs().length, 1); - assert(output.getTx().getInputs()[0] === output); - assert.equal(output.getTx().getOutputs(), undefined); - - // extra is not sent over the wasm bridge - assert.equal(output.getTx().getExtra(), undefined); - - // add outgoing amount to running total - this.outgoingTotal = this.outgoingTotal.add(output.getAmount()); - } - - async onDone(chainHeight) { - await super.onDone(chainHeight); - assert.notEqual(this.walletTesterPrevHeight, undefined); - assert.notEqual(this.prevOutputReceived, undefined); - assert.notEqual(this.prevOutputSpent, undefined); - let balance = this.incomingTotal.subtract(this.outgoingTotal); - assert.equal((await this.wallet.getBalance()).toString(), balance.toString()); - this.onNewBlockAfterDone = false; // test subsequent onNewBlock() calls - assert.equal(this.prevBalance.toString(), (await this.wallet.getBalance()).toString()); - assert.equal(this.prevUnlockedBalance.toString(), (await this.wallet.getUnlockedBalance()).toString()); - } - - getOnNewBlockAfterDone() { - return this.onNewBlockAfterDone; - } -} - -/** - * Internal tester for output notifications. - */ -class ReceivedOutputNotificationTester extends MoneroWalletListener { - - constructor(txHash) { - super(); - this.txHash = txHash; - this.lastNotifiedOutput = undefined; - this.testComplete = false; - this.testError = undefined; - this.unlockedSeen = false; - this.confirmedHeight = undefined; - } - - onOutputReceived(output) { - if (output.getTx().getHash() === this.txHash) this.lastNotifiedOutput = output; - } -} - -module.exports = TestMoneroWalletWasm; diff --git a/src/test/TestSampleCode.js b/src/test/TestSampleCode.js deleted file mode 100644 index b813a1db8..000000000 --- a/src/test/TestSampleCode.js +++ /dev/null @@ -1,258 +0,0 @@ -const assert = require("assert"); -const TestUtils = require("./utils/TestUtils"); - -/** - * Test the sample code in README.md. - */ -class TestSampleCode { - - runTests() { - describe("Test Sample Code", function() { - let that = this; - - // initialize wallet - before(async function() { - try { - // all wallets need to wait for txs to confirm to reliably sync - TestUtils.TX_POOL_WALLET_TRACKER.reset(); - - // pre-create test wallet - let wallet = await TestUtils.getWalletRpc(); - await wallet.close(); - - // create directory for test wallets if it doesn't exist - const monerojs = require("../../index"); - let fs = TestUtils.getDefaultFs(); - if (!fs.existsSync(TestUtils.TEST_WALLETS_DIR)) { - if (!fs.existsSync(process.cwd())) fs.mkdirSync(process.cwd(), { recursive: true }); // create current process directory for relative paths which does not exist in memory fs - fs.mkdirSync(TestUtils.TEST_WALLETS_DIR); - } - } catch (e) { - console.error("Error before tests: "); - console.error(e); - throw e; - } - }); - - // TODO: wrap test in try...catch and close wasm wallet - it("Short sample code demonstration", async function() { - - // import library - const monerojs = require("../../index"); // *** CHANGE README TO "monero-javascript" *** - - // connect to a daemon - let daemon = monerojs.connectToDaemonRpc("http://localhost:38081", "superuser", "abctesting123"); - let height = await daemon.getHeight(); // 1523651 - let feeEstimate = await daemon.getFeeEstimate(); // 1014313512 - let txsInPool = await daemon.getTxPool(); // get transactions in the pool - - // open wallet on monero-wallet-rpc - let walletRpc = monerojs.connectToWalletRpc("http://localhost:38083", "rpc_user", "abc123"); - await walletRpc.openWallet("test_wallet_1", "supersecretpassword123"); // *** CHANGE README TO "sample_wallet_rpc" *** - let primaryAddress = await walletRpc.getPrimaryAddress(); // 555zgduFhmKd2o8rPUz... - let balance = await walletRpc.getBalance(); // 533648366742 - let txs = await walletRpc.getTxs(); // get transactions containing transfers to/from the wallet - - // create wallet from mnemonic phrase using WebAssembly bindings to monero-project - let walletWasm = await monerojs.createWalletWasm({ - path: "./test_wallets/" + monerojs.GenUtils.getUUID(), // *** CHANGE README TO "sample_wallet_wasm" - password: "supersecretpassword123", - networkType: "stagenet", - serverUri: "http://localhost:38081", - serverUsername: "superuser", - serverPassword: "abctesting123", - mnemonic: TestUtils.MNEMONIC, // *** REPLACE README WITH MNEMONIC *** - restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, // *** REPLACE README WITH FIRST RECEIVE HEIGHT *** - fs: TestUtils.getDefaultFs() - }); - - // synchronize with progress notifications - await walletWasm.sync(new class extends monerojs.MoneroWalletListener { - onSyncProgress(height, startHeight, endHeight, percentDone, message) { - // feed a progress bar? - } - }); - - // synchronize in the background - await walletWasm.startSyncing(); - - // listen for incoming transfers - let fundsReceived = false; - await walletWasm.addListener(new class extends monerojs.MoneroWalletListener { - onOutputReceived(output) { - let amount = output.getAmount(); - let txHash = output.getTx().getHash(); - fundsReceived = true; - } - }); - - // send funds from RPC wallet to WebAssembly wallet - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(walletRpc); // *** REMOVE FROM README SAMPLE *** - let createdTx = await walletRpc.createTx({ - accountIndex: 0, - address: await walletWasm.getAddress(1, 0), - amount: "250000000000", // send 0.25 XMR (denominated in atomic units) - relay: false // create transaction and relay to the network if true - }); - let fee = createdTx.getFee(); // "Are you sure you want to send... ?" - await walletRpc.relayTx(createdTx); // relay the transaction - - // recipient receives unconfirmed funds within 10 seconds - await new Promise(function(resolve) { setTimeout(resolve, 10000); }); - assert(fundsReceived); - - // save and close WebAssembly wallet - await walletWasm.close(true); - }); - - // TODO: wrap test in try...catch and close wasm wallet - if (false) - it("Long sample code demonstration", async function() { - - // import library - //require("monero-javascript"); // *** USE IN README.MD *** - - // connect to a daemon - let daemon = new MoneroDaemonRpc({ - uri: "http://localhost:38081", - username: "superuser", - password: "abctesting123", - proxyToWorker: TestUtils.PROXY_TO_WORKER // *** REMOVE FROM README.MD *** - }); - let height = await daemon.getHeight(); // 1523651 - let feeEstimate = await daemon.getFeeEstimate(); // 1014313512 - - // get transactions in the pool - let txsInPool = await daemon.getTxPool(); - for (let tx of txsInPool) { - let hash = tx.getHash(); - let fee = tx.getFee(); - let isDoubleSpendSeen = tx.isDoubleSpendSeen(); - } - - // get last 100 blocks as a binary request - let blocks = await daemon.getBlocksByRange(height - 100, height - 1); - for (let block of blocks) { - let numTxs = block.getTxs().length; - } - - // connect to a monero-wallet-rpc endpoint with authentication - let walletRpc = new MoneroWalletRpc("http://localhost:38083", "rpc_user", "abc123"); - - // open a wallet on the server - await walletRpc.openWallet("test_wallet_1", "supersecretpassword123"); - let primaryAddress = await walletRpc.getPrimaryAddress(); // 59aZULsUF3YNSKGiHz4J... - let balance = await walletRpc.getBalance(); // 533648366742 - let subaddress = await walletRpc.getSubaddress(1, 0); - let subaddressBalance = subaddress.getBalance(); - - // query a transaction by hash - let tx = await walletRpc.getTx((await walletRpc.getTxs(new MoneroTxQuery().setIsOutgoing(true)))[0].getHash()); // *** REMOVE FROM README SAMPLE *** - //let tx = await walletRpc.getTx("32088012e68be1c090dc022f7852ca4d7c23066241649cdfaeb14ec1fd5a10f8"); - let txHeight = tx.getHeight(); - let incomingTransfers = tx.getIncomingTransfers(); - let destinations = tx.getOutgoingTransfer().getDestinations(); - - // query incoming transfers to account 1 - let transferQuery = new MoneroTransferQuery().setIsIncoming(true).setAccountIndex(1); - let transfers = await walletRpc.getTransfers(transferQuery); - - // query unspent outputs - let outputQuery = new MoneroOutputQuery().setIsSpent(false); - let outputs = await walletRpc.getOutputs(outputQuery); - - // create a wallet from a mnemonic phrase using WebAssembly bindings to monero-project - let walletWasm = await MoneroWalletWasm.createWallet({ // *** REPLACE WITH BELOW FOR README.MD *** - path: "./test_wallets/" + GenUtils.getUUID(), - password: "supersecretpassword123", - networkType: TestUtils.NETWORK_TYPE, - mnemonic: TestUtils.MNEMONIC, - server: await daemon.getRpcConnection(), - restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, - proxyToWorker: TestUtils.PROXY_TO_WORKER - }); -// let walletWasm = await MoneroWalletWasm.createWallet({ -// path: "MyWallet", -// password: "supersecretpassword123", -// networkType: MoneroNetworkType.STAGENET, -// mnemonic: "hefty value ...", -// server: await daemon.getRpcConnection(), -// restoreHeight: 501788 -// }); - - // synchronize the wallet and receive progress notifications - await walletWasm.sync(new class extends MoneroWalletListener { - onSyncProgress(height, startHeight, endHeight, percentDone, message) { - // feed a progress bar? - } - }); - - // start syncing the wallet continuously in the background - await walletWasm.startSyncing(); - - // receive notifications when the wasm wallet receives funds - await walletWasm.addListener(new class extends MoneroWalletListener { - onOutputReceived(output) { - console.log("Wallet received funds!"); - let txHash = output.getTx().getHash(); - let accountIdx = output.getAccountIndex(); - let subaddressIdx = output.getSubaddressIndex(); - TestSampleCode.CORE_OUTPUT_RECEIVED = true; - } - }); - - // send funds from the RPC wallet to the wasm wallet - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(walletRpc); // wait for txs to clear pool *** REMOVE FROM README SAMPLE *** - let txSet = await walletRpc.createTx({ - accountIndex: 0, - address: await walletWasm.getPrimaryAddress(), - amount: "50000000", - relay: true - }); - let sentTx = txSet.getTxs()[0]; // send methods return tx set(s) which contain sent txs - assert(sentTx.inTxPool(), "Sent transaction is not in the tx pool"); - - // mine with 7 threads to push the network along - let numThreads = 7; - let isBackground = false; - let ignoreBattery = false; - try { await walletRpc.startMining(numThreads, isBackground, ignoreBattery); } catch(e) { } - - // wait for the next block to be added to the chain - let nextBlockHeader = await daemon.getNextBlockHeader(); - let nextNumTxs = nextBlockHeader.getNumTxs(); - - // stop mining - try { await walletRpc.stopMining(); } catch(e) { } - - // the transaction is (probably) confirmed - await new Promise(function(resolve) { setTimeout(resolve, 10000); }); // wait 10s for auto refresh - let isConfirmed = (await walletRpc.getTx(sentTx.getHash())).isConfirmed(); - - // configure a config to send funds from RPC wallet to multiple destinations in the WASM wallet - let config = new MoneroTxConfig() - .setAccountIndex(1) // send from account 1 - .setSubaddressIndices([0, 1]) // send from subaddresses in account 1 - .setPriority(MoneroTxPriority.UNIMPORTANT) // no rush - .setRelay(true) - .setDestinations([ - new MoneroDestination(await walletWasm.getAddress(1, 0), BigInteger.parse("50000")), - new MoneroDestination(await walletWasm.getAddress(2, 0), BigInteger.parse("50000"))]); - - // create the transaction, confirm with the user, and relay to the network - let createdTx = await walletRpc.createTx(config); - let fee = createdTx.getFee(); // "Are you sure you want to send ...?" - await walletRpc.relayTx(createdTx); // submit the transaction which will notify the JNI wallet - - // wasm wallet will receive notification of incoming output after a moment - await new Promise(function(resolve) { setTimeout(resolve, 10000); }); - assert(TestSampleCode.CORE_OUTPUT_RECEIVED, "Output not received"); - - // save and close the wasm wallet - await walletWasm.close(true); - }); - }); - } -} - -module.exports = TestSampleCode; \ No newline at end of file diff --git a/src/test/TestSampleCode.ts b/src/test/TestSampleCode.ts new file mode 100644 index 000000000..671d3508b --- /dev/null +++ b/src/test/TestSampleCode.ts @@ -0,0 +1,441 @@ +import assert from "assert"; +import TestUtils from "./utils/TestUtils"; +import * as moneroTs from "../../index"; + +/** + * Test the sample code in README.md. + */ +export default class TestSampleCode { + + runTests() { + describe("Test sample code", function() { + let that = this; // Unnecessary? That is never used in the following code + let wallet: moneroTs.MoneroWalletFull; + + // initialize wallet + before(async function() { + try { + + // all wallets need to wait for txs to confirm to reliably sync + TestUtils.WALLET_TX_TRACKER.reset(); + + // create rpc test wallet + let walletRpc = await TestUtils.getWalletRpc(); + await walletRpc.close(); + + // create directory for test wallets if it doesn't exist + let fs = await TestUtils.getDefaultFs(); + if (!await moneroTs.LibraryUtils.exists(fs, TestUtils.TEST_WALLETS_DIR)) { + if (!await moneroTs.LibraryUtils.exists(fs, process.cwd())) await fs.mkdir(process.cwd(), { recursive: true }); // create current process directory for relative paths which does not exist in memory fs + await fs.mkdir(TestUtils.TEST_WALLETS_DIR); + } + + // create full test wallet + wallet = await TestUtils.getWalletFull(); + + } catch (e) { + console.error("Error before tests: "); + console.error(e); + throw e; + } + }); + + after(async function() { + if (wallet) await wallet.close(true); + }); + + it("Sample code demonstration", async function() { + + // import monero-ts (or import as needed) + // import moneroTs from "monero-ts"; // *** UNCOMMENT IN README *** + + // connect to daemon + let daemon = await moneroTs.connectToDaemonRpc("http://localhost:28081"); + let height = await daemon.getHeight(); // 1523651 + let txsInPool = await daemon.getTxPool(); // get transactions in the pool + + // create wallet from mnemonic phrase using WebAssembly bindings to monero-project + let walletFull = await moneroTs.createWalletFull({ + path: "./test_wallets/" + moneroTs.GenUtils.getUUID(), // *** CHANGE README TO "sample_wallet_full" + fs: await TestUtils.getDefaultFs(), // *** REMOVE FROM README SAMPLE *** + password: "supersecretpassword123", + networkType: moneroTs.MoneroNetworkType.TESTNET, + seed: TestUtils.SEED, // *** REPLACE README WITH SEED *** + restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, // *** REPLACE README WITH FIRST RECEIVE HEIGHT *** + server: { // provide url or MoneroRpcConnection + uri: "http://localhost:28081", + username: "superuser", + password: "abctesting123" + } + }); + + // synchronize with progress notifications + await walletFull.sync(new class extends moneroTs.MoneroWalletListener { + async onSyncProgress(height: number, startHeight: number, endHeight: number, percentDone: number, message: string) { + // feed a progress bar? + } + }); + + // synchronize in the background every 5 seconds + await walletFull.startSyncing(5000); + + // receive notifications when funds are received, confirmed, and unlocked + let fundsReceived = false; + await walletFull.addListener(new class extends moneroTs.MoneroWalletListener { + async onOutputReceived(output: moneroTs.MoneroOutputWallet) { + let amount = output.getAmount(); + let txHash = output.getTx().getHash(); + let isConfirmed = output.getTx().getIsConfirmed(); + let isLocked = output.getTx().getIsLocked(); + fundsReceived = true; + } + }); + + // connect to wallet RPC and open wallet + let walletRpc = await moneroTs.connectToWalletRpc("http://localhost:28084", "rpc_user", "abc123"); + await walletRpc.openWallet("test_wallet_1", "supersecretpassword123"); // *** CHANGE README TO "sample_wallet_rpc" *** + let primaryAddress = await walletRpc.getPrimaryAddress(); // 555zgduFhmKd2o8rPUz... + let balance = await walletRpc.getBalance(); // 533648366742 + let txs = await walletRpc.getTxs(); // get transactions containing transfers to/from the wallet + + // send funds from RPC wallet to WebAssembly wallet + await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool(walletRpc); // *** REMOVE FROM README SAMPLE *** + await TestUtils.WALLET_TX_TRACKER.waitForUnlockedBalance(walletRpc, 0, undefined, 250000000000n); // *** REMOVE FROM README SAMPLE *** + let createdTx = await walletRpc.createTx({ + accountIndex: 0, + address: await walletFull.getAddress(1, 0), + amount: 250000000000n, // send 0.25 XMR (denominated in atomic units) + relay: false // create transaction and relay to the network if true + }); + let fee = createdTx.getFee(); // "Are you sure you want to send... ?" + await walletRpc.relayTx(createdTx); // relay the transaction + + // recipient receives unconfirmed funds within 5 seconds + await new Promise(function(resolve) { setTimeout(resolve, 5000); }); + assert(fundsReceived); + + // save and close WebAssembly wallet + await walletFull.close(true); + + // terminate any running resources (e.g. workers) + await moneroTs.shutdown(); + }); + + it("Connection manager demonstration", async function() { + + // import monero-ts (or import types individually) + // import moneroTs from "monero-ts"; // *** UNCOMMENT IN README *** + + // create connection manager + let connectionManager = new moneroTs.MoneroConnectionManager(); + + // add managed connections with priorities + await connectionManager.addConnection({uri: "http://localhost:28081", priority: 1}); // use localhost as first priority + await connectionManager.addConnection("http://example.com"); // default priority is prioritized last + + // set current connection + await connectionManager.setConnection({uri: "http://foo.bar", username: "admin", password: "password"}); // connection is added if new + + // create or open wallet governed by connection manager + let walletFull = await moneroTs.createWalletFull({ + path: "./test_wallets/" + moneroTs.GenUtils.getUUID(), // *** CHANGE README TO "sample_wallet_full" + password: "supersecretpassword123", + networkType: moneroTs.MoneroNetworkType.TESTNET, + connectionManager: connectionManager, + seed: TestUtils.SEED, // *** REPLACE IN README *** + restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, // *** REPLACE IN README *** + fs: await TestUtils.getDefaultFs() // *** REPLACE IN README *** + }); + + // check connection status + await connectionManager.checkConnection(); + + // receive notifications of any changes to current connection + connectionManager.addListener(new class extends moneroTs.MoneroConnectionManagerListener { + async onConnectionChanged(connection: moneroTs.MoneroRpcConnection) { + console.log("Connection changed to: " + connection); + } + }); + + // check connections every 10 seconds (in order of priority) and switch to the best + connectionManager.startPolling(10000); + + // get best available connection in order of priority then response time + let bestConnection = await connectionManager.getBestAvailableConnection(); + + // check status of all connections + await connectionManager.checkConnections(); + + // get connections in order of current connection, online status from last check, priority, and name + let connections = connectionManager.getConnections(); + + // clear connection manager + await connectionManager.clear(); + }); + + it("Test developer guide transaction queries", async function() { + + // get a transaction by hash + let tx = await wallet.getTx((await wallet.getTxs())[0].getHash()); // REPLACE WITH BELOW FOR MD FILE + //let tx = await wallet.getTx("9fb2cb7c73743002f131b72874e77b1152891968dc1f2849d3439ace8bae6d8e"); + + // get unconfirmed transactions + let txs = await wallet.getTxs({ + isConfirmed: false + }); + for (let tx of txs) { + assert(!tx.getIsConfirmed()); + } + + // get transactions since height 582106 with incoming transfers to + // account 0, subaddress 0 + txs = await wallet.getTxs({ + minHeight: 582106, + transferQuery: { + isIncoming: true, + accountIndex: 0, + subaddressIndex: 1 + } + }); + for (let tx of txs) { + assert(tx.getIsConfirmed()); + assert(tx.getHeight() >= 582106) + let found: boolean = false; + for (let transfer of tx.getTransfers()) { + if (transfer.getIsIncoming() && transfer.getAccountIndex() === 0 && (transfer as moneroTs.MoneroIncomingTransfer).getSubaddressIndex() === 1) { + found = true; + break; + } + } + assert(found); + } + + // get transactions with available outputs + txs = await wallet.getTxs({ + isLocked: false, + outputQuery: { + isSpent: false, + } + }); + for (let tx of txs) { + assert(!tx.getIsLocked()); + assert(tx.getOutputs().length > 0); + let found = false; + for (let output of tx.getOutputsWallet()) { + if (!output.getIsSpent()) { + found = true; + break; + } + } + if (!found) { + console.log(tx.getOutputs()); + } + assert(found); + } + }); + + it("Test developer guide transfer queries", async function() { + + // get all transfers + let transfers = await wallet.getTransfers(); + + // get incoming transfers to account 0, subaddress 1 + transfers = await wallet.getTransfers({ + isIncoming: true, + accountIndex: 0, + subaddressIndex: 1 + }); + for (let transfer of transfers) { + assert.equal(transfer.getIsIncoming(), true); + assert.equal(transfer.getAccountIndex(), 0); + assert.equal((transfer as moneroTs.MoneroIncomingTransfer).getSubaddressIndex(), 1); + } + + // get transfers in the tx pool + transfers = await wallet.getTransfers({ + txQuery: { + inTxPool: true + } + }); + for (let transfer of transfers) { + assert.equal(transfer.getTx().getInTxPool(), true); + } + + // get confirmed outgoing transfers since a block height + transfers = await wallet.getTransfers({ + isIncoming: false, + txQuery: { + isConfirmed: true, + minHeight: TestUtils.FIRST_RECEIVE_HEIGHT // *** REPLACE WITH NUMBER IN .MD FILE *** + } + }); + assert(transfers.length > 0); + for (let transfer of transfers) { + assert(transfer.getIsOutgoing()); + assert(transfer.getTx().getIsConfirmed()); + assert(transfer.getTx().getHeight() >= TestUtils.FIRST_RECEIVE_HEIGHT); + } + }); + + it("Test developer guide output queries", async function() { + + // get all outputs + let outputs = await wallet.getOutputs(); + assert(outputs.length > 0); + + // get outputs available to be spent + outputs = await wallet.getOutputs({ + isSpent: false, + txQuery: { + isLocked: false + } + }); + assert(outputs.length > 0); + for (let output of outputs) { + assert(!output.getIsSpent()); + assert(!output.getTx().getIsLocked()); + } + + // get outputs by amount + let amount = outputs[0].getAmount(); + outputs = await wallet.getOutputs({ + amount: amount // *** REPLACE WITH bigint IN .MD FILE *** + }); + assert(outputs.length > 0); + for (let output of outputs) assert.equal(output.getAmount().toString(), amount.toString()); + + // get outputs received to a specific subaddress + outputs = await wallet.getOutputs({ + accountIndex: 0, + subaddressIndex: 1 + }); + assert(outputs.length > 0); + for (let output of outputs) { + assert.equal(output.getAccountIndex(), 0); + assert.equal(output.getSubaddressIndex(), 1); + } + + // get output by key image + let keyImage: string = outputs[0].getKeyImage().getHex(); + outputs = await wallet.getOutputs({ + keyImage: { + hex: keyImage + } + }); + assert.equal(outputs.length, 1); + assert.equal(outputs[0].getKeyImage().getHex(), keyImage); + }); + + it("Test developer guide send funds", async function() { + + // create in-memory test wallet with randomly generated seed + let wallet = await moneroTs.createWalletFull({ + password: "abctesting123", + networkType: moneroTs.MoneroNetworkType.TESTNET, + server: "http://localhost:28081", + proxyToWorker: TestUtils.PROXY_TO_WORKER + }); + + try { + + // create a transaction to send funds to an address, but do not relay + let tx = await wallet.createTx({ + accountIndex: 0, // source account to send funds from + address: "9tsUiG9bwcU7oTbAdBwBk2PzxFtysge5qcEsHEpetmEKgerHQa1fDqH7a4FiquZmms7yM22jdifVAD7jAb2e63GSJMuhY75", + amount: 1000000000000n // send 1 XMR (denominated in atomic units) + }); + + // can confirm with the user + let fee = tx.getFee(); // "Are you sure you want to send... ?" + + // relay the transaction + let hash = await wallet.relayTx(tx); + } catch (err: any) { + if (err.message !== "not enough money") throw err; + } + + try { + + // send funds to a single destination + let tx = await wallet.createTx({ + accountIndex: 0, // source account to send funds from + address: "9tsUiG9bwcU7oTbAdBwBk2PzxFtysge5qcEsHEpetmEKgerHQa1fDqH7a4FiquZmms7yM22jdifVAD7jAb2e63GSJMuhY75", + amount: 1000000000000n, // send 1 XMR (denominated in atomic units) + relay: true // relay the transaction to the network + }); + } catch (err: any) { + if (err.message !== "not enough money") throw err; + } + + try { + + // send funds from a specific subaddress to multiple destinations, + // allowing transfers to be split across multiple transactions if needed + let txs = await wallet.createTxs({ + accountIndex: 0, // source account to send funds from + subaddressIndex: 1, // source subaddress to send funds from + destinations: [{ + address: "9tsUiG9bwcU7oTbAdBwBk2PzxFtysge5qcEsHEpetmEKgerHQa1fDqH7a4FiquZmms7yM22jdifVAD7jAb2e63GSJMuhY75", + amount: 500000000000n, // send 0.5 XMR (denominated in atomic units) + }, { + address: "9tsUiG9bwcU7oTbAdBwBk2PzxFtysge5qcEsHEpetmEKgerHQa1fDqH7a4FiquZmms7yM22jdifVAD7jAb2e63GSJMuhY75", + amount: 500000000000n, // send 0.5 XMR (denominated in atomic units) + }], + priority: moneroTs.MoneroTxPriority.ELEVATED, + relay: true // relay the transaction to the network + }); + } catch (err: any) { + if (err.message !== "not enough money") throw err; + } + + try { + + // sweep an output + let tx = await wallet.sweepOutput({ + address: "9tsUiG9bwcU7oTbAdBwBk2PzxFtysge5qcEsHEpetmEKgerHQa1fDqH7a4FiquZmms7yM22jdifVAD7jAb2e63GSJMuhY75", + keyImage: "b7afd6afbb1615c98b1c0350b81c98a77d6d4fc0ab92020d25fd76aca0914f1e", + relay: true + }); + } catch (err: any) { + if (err.message !== "No outputs found") throw err; + } + + try { + + // sweep all unlocked funds in a wallet + let txs = await wallet.sweepUnlocked({ + address: "9tsUiG9bwcU7oTbAdBwBk2PzxFtysge5qcEsHEpetmEKgerHQa1fDqH7a4FiquZmms7yM22jdifVAD7jAb2e63GSJMuhY75", + relay: true + }); + } catch (err: any) { + if (err.message !== "No unlocked balance in the specified account") throw err; + } + + try { + + // sweep unlocked funds in an account + let txs = await wallet.sweepUnlocked({ + accountIndex: 0, + address: "9tsUiG9bwcU7oTbAdBwBk2PzxFtysge5qcEsHEpetmEKgerHQa1fDqH7a4FiquZmms7yM22jdifVAD7jAb2e63GSJMuhY75", + relay: true + }); + } catch (err: any) { + if (err.message !== "No unlocked balance in the specified account") throw err; + } + + try { + + // sweep unlocked funds in a subaddress + let txs = await wallet.sweepUnlocked({ + accountIndex: 0, + subaddressIndex: 0, + address: "9tsUiG9bwcU7oTbAdBwBk2PzxFtysge5qcEsHEpetmEKgerHQa1fDqH7a4FiquZmms7yM22jdifVAD7jAb2e63GSJMuhY75", + relay: true + }); + } catch (err: any) { + if (err.message !== "No unlocked balance in the specified account") throw err; + } + }); + }); + } +} diff --git a/src/test/browser/favicon.ico b/src/test/browser/favicon.ico index 8cd55fe49..f5ae04c32 100644 Binary files a/src/test/browser/favicon.ico and b/src/test/browser/favicon.ico differ diff --git a/src/test/browser/tests.html b/src/test/browser/tests.html index 9269de9ab..2171362a0 100644 --- a/src/test/browser/tests.html +++ b/src/test/browser/tests.html @@ -7,6 +7,6 @@
- + - \ No newline at end of file + diff --git a/src/test/browser/tests.js b/src/test/browser/tests.js index d78f38a87..719dab6cd 100644 --- a/src/test/browser/tests.js +++ b/src/test/browser/tests.js @@ -23,4 +23,4 @@ function runTests() { // run tests require("../TestAll"); mocha.run(); -} \ No newline at end of file +} diff --git a/src/test/utils/RunWalletRpcTestServers.ts b/src/test/utils/RunWalletRpcTestServers.ts new file mode 100644 index 000000000..0a4ddb5a4 --- /dev/null +++ b/src/test/utils/RunWalletRpcTestServers.ts @@ -0,0 +1,32 @@ +import TestUtils from "./TestUtils"; +import { MoneroWalletRpc } from "../../../index"; + +/** + * Utility class to run monero-wallet-rpc test servers until terminated. + */ +export default class RunWalletRpcTestServers { + + static async run() { + + // start monero-wallet-rpc servers + console.log("Starting monero-wallet-rpc servers..."); + let numProcesses = 10; + let processPromises: Promise[] = []; + for (let i = 0; i < numProcesses; i++) { + processPromises.push(TestUtils.startWalletRpcProcess()); + } + let wallets = await Promise.all(processPromises); + console.log("Done starting monero-wallet-rpc servers"); + + // close wallets and servers on ctrl+c + process.on("SIGINT", async function() { + console.log("Stopping monero-wallet-rpc servers..."); + for (let wallet of wallets) await TestUtils.stopWalletRpcProcess(wallet); + console.log("Stopped monero-wallet-rpc servers"); + process.exit(0); + }); + } +} + +// run until termination +RunWalletRpcTestServers.run(); diff --git a/src/test/utils/StartMining.js b/src/test/utils/StartMining.js deleted file mode 100644 index 04232c86b..000000000 --- a/src/test/utils/StartMining.js +++ /dev/null @@ -1,16 +0,0 @@ -const TestUtils = require("./TestUtils"); - -/** - * Utility class to start mining. - */ -class StartMining { - - static async startMining() { - let numThreads = 1; - //TestUtils.getWalletRpc().startMining(numThreads, false, true); - let daemon = await TestUtils.getDaemonRpc(); - await daemon.startMining("56SWsnhejUTbgNs2EgyXdfNXUawymMMuAC9voZZSQrHzJHNxGsAvMnoUja7JcKVtPwNc1oKAkoAt1cv6EmtKRQ22U37B7cT", numThreads, false, false); // random subaddress - } -} - -module.exports = StartMining; \ No newline at end of file diff --git a/src/test/utils/StartMining.ts b/src/test/utils/StartMining.ts new file mode 100644 index 000000000..1a992c2ca --- /dev/null +++ b/src/test/utils/StartMining.ts @@ -0,0 +1,14 @@ +import TestUtils from "./TestUtils"; + +/** + * Utility class to start mining. + */ +export default class StartMining { + + static async startMining(numThreads?: number) { + if (!numThreads) numThreads = 1; + //TestUtils.getWalletRpc().startMining(numThreads, false, true); + let daemon = await TestUtils.getDaemonRpc(); + await daemon.startMining("9tsUiG9bwcU7oTbAdBwBk2PzxFtysge5qcEsHEpetmEKgerHQa1fDqH7a4FiquZmms7yM22jdifVAD7jAb2e63GSJMuhY75", numThreads, false, false); // random subaddress + } +} diff --git a/src/test/utils/TestUtils.js b/src/test/utils/TestUtils.js deleted file mode 100644 index 7a45d2103..000000000 --- a/src/test/utils/TestUtils.js +++ /dev/null @@ -1,210 +0,0 @@ -const assert = require("assert"); -const WalletSyncPrinter = require("./WalletSyncPrinter"); -const monerojs = require("../../../index"); -const LibraryUtils = monerojs.LibraryUtils; -const GenUtils = monerojs.GenUtils; -const MoneroRpcError = monerojs.MoneroRpcError; -const MoneroRpcConnection = monerojs.MoneroRpcConnection; -const BigInteger = monerojs.BigInteger; -const MoneroNetworkType = monerojs.MoneroNetworkType; - -/** - * Collection of test utilities and configurations. - * - * TODO: move hard coded to config - */ -class TestUtils { - - /** - * Get a default file system. Uses an in-memory file system if running in the browser. - * - * @return nodejs-compatible file system - */ - static getDefaultFs() { - if (!LibraryUtils.FS) LibraryUtils.FS = GenUtils.isBrowser() ? require('memfs') : require('fs'); - return LibraryUtils.FS; - } - - /** - * Get a singleton daemon RPC instance shared among tests. - * - * @return {MoneroDaemonRpc} a daemon RPC instance - */ - static async getDaemonRpc() { - if (TestUtils.daemonRpc === undefined) TestUtils.daemonRpc = monerojs.connectToDaemonRpc(Object.assign({proxyToWorker: TestUtils.PROXY_TO_WORKER}, TestUtils.DAEMON_RPC_CONFIG)); - return TestUtils.daemonRpc; - } - - static getDaemonRpcConnection() { - return new MoneroRpcConnection(TestUtils.DAEMON_RPC_CONFIG); - } - - /** - * Get a singleton wallet RPC instance shared among tests. - * - * @return {MoneroWalletRpc} a wallet RPC instance - */ - static async getWalletRpc() { - if (TestUtils.walletRpc === undefined) { - - // construct wallet rpc instance with daemon connection - TestUtils.walletRpc = monerojs.connectToWalletRpc(TestUtils.WALLET_RPC_CONFIG); - } - - // attempt to open test wallet - try { - await TestUtils.walletRpc.openWallet({path: TestUtils.WALLET_NAME, password: TestUtils.WALLET_PASSWORD}); - } catch (e) { - if (!(e instanceof MoneroRpcError)) throw e; - - // -1 returned when wallet does not exist or fails to open e.g. it's already open by another application - if (e.getCode() === -1) { - - // create wallet - await TestUtils.walletRpc.createWallet({path: TestUtils.WALLET_NAME, password: TestUtils.WALLET_PASSWORD, mnemonic: TestUtils.MNEMONIC, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}); - } else { - throw e; - } - } - - // ensure we're testing the right wallet - assert.equal(await TestUtils.walletRpc.getMnemonic(), TestUtils.MNEMONIC); - assert.equal(await TestUtils.walletRpc.getPrimaryAddress(), TestUtils.ADDRESS); - - // sync and save the wallet - await TestUtils.walletRpc.sync(); - await TestUtils.walletRpc.save(); - - // return cached wallet rpc - return TestUtils.walletRpc; - } - - /** - * Get a singleton wallet WASM instance shared among tests. - * - * @return {MoneroWalletWasm} a wasm wallet instance - */ - static async getWalletWasm() { - if (!TestUtils.walletWasm || await TestUtils.walletWasm.isClosed()) { - - // create wallet from mnemonic phrase if it doesn't exist - let fs = TestUtils.getDefaultFs(); - if (!await monerojs.MoneroWalletWasm.walletExists(TestUtils.WALLET_WASM_PATH, fs)) { - - // create directory for test wallets if it doesn't exist - if (!fs.existsSync(TestUtils.TEST_WALLETS_DIR)) { - if (!fs.existsSync(process.cwd())) fs.mkdirSync(process.cwd(), { recursive: true }); // create current process directory for relative paths which does not exist in memory fs - fs.mkdirSync(TestUtils.TEST_WALLETS_DIR); - } - - // create wallet with connection - TestUtils.walletWasm = await monerojs.createWalletWasm({path: TestUtils.WALLET_WASM_PATH, password: TestUtils.WALLET_PASSWORD, networkType: TestUtils.NETWORK_TYPE, mnemonic: TestUtils.MNEMONIC, server: TestUtils.getDaemonRpcConnection(), restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, proxyToWorker: TestUtils.PROXY_TO_WORKER, fs: fs}); - assert.equal(await TestUtils.walletWasm.getSyncHeight(), TestUtils.FIRST_RECEIVE_HEIGHT); - await TestUtils.walletWasm.sync(new WalletSyncPrinter()); - await TestUtils.walletWasm.save(); - await TestUtils.walletWasm.startSyncing(); - } - - // otherwise open existing wallet - else { - TestUtils.walletWasm = await monerojs.openWalletWasm({path: TestUtils.WALLET_WASM_PATH, password: TestUtils.WALLET_PASSWORD, networkType: TestUtils.NETWORK_TYPE, server: TestUtils.getDaemonRpcConnection(), proxyToWorker: TestUtils.PROXY_TO_WORKER, fs: TestUtils.getDefaultFs()}); - await TestUtils.walletWasm.sync(new WalletSyncPrinter()); - await TestUtils.walletWasm.startSyncing(); - } - } - - // ensure we're testing the right wallet - assert.equal(await TestUtils.walletWasm.getMnemonic(), TestUtils.MNEMONIC); - assert.equal(await TestUtils.walletWasm.getPrimaryAddress(), TestUtils.ADDRESS); - return TestUtils.walletWasm; - } - - /** - * Get a singleton keys-only wallet instance shared among tests. - * - * @return {MoneroWalletKeys} a keys-only wallet instance - */ - static async getWalletKeys() { - if (TestUtils.walletKeys === undefined) { - - // create wallet from mnemonic - TestUtils.walletKeys = await monerojs.createWalletKeys({networkType: TestUtils.NETWORK_TYPE, mnemonic: TestUtils.MNEMONIC}); - } - return TestUtils.walletKeys; - } - - static testUnsignedBigInteger(num, nonZero) { - assert(num); - assert(num instanceof BigInteger); - let comparison = num.compare(new BigInteger(0)); - assert(comparison >= 0); - if (nonZero === true) assert(comparison > 0); - if (nonZero === false) assert(comparison === 0); - } - - static async getExternalWalletAddress() { - let wallet = await monerojs.createWalletKeys({networkType: TestUtils.NETWORK_TYPE}); - return await wallet.getPrimaryAddress(); - } - - static txsMergeable(tx1, tx2) { - try { - let copy1 = tx1.copy(); - let copy2 = tx2.copy(); - if (copy1.isConfirmed()) copy1.setBlock(tx1.getBlock().copy().setTxs([copy1])); - if (copy2.isConfirmed()) copy2.setBlock(tx2.getBlock().copy().setTxs([copy2])); - copy1.merge(copy2); - return true; - } catch (e) { - console.error(e); - return false; - } - } -} - -// ---------------------------- STATIC TEST CONFIG ---------------------------- - -// TODO: export these to key/value properties file for tests - -// test wallet config -TestUtils.WALLET_NAME = "test_wallet_1"; -TestUtils.WALLET_PASSWORD = "supersecretpassword123"; -TestUtils.TEST_WALLETS_DIR = "./test_wallets"; -TestUtils.WALLET_WASM_PATH = TestUtils.TEST_WALLETS_DIR + "/" + TestUtils.WALLET_NAME; - -TestUtils.MAX_FEE = new BigInteger("7500000").multiply(new BigInteger("10000")); -TestUtils.NETWORK_TYPE = MoneroNetworkType.STAGENET; - -// default keypair to test -TestUtils.MNEMONIC = "niece cube almost phase zeal ultimate pyramid tapestry hickory bulb bifocals festival always wayside sphere kept upwards wagtail invoke radar pager flippant sensible stunning kept"; -TestUtils.ADDRESS = "59dF9pSotECe1Fn4dBGZXWHYyNdo53rbZ7YYseu9jBKCf4c2cUzhuFVRH8HuD4wyaKTqtD3VF3F4eQe3Kzq342F5U8R4jeq"; -TestUtils.FIRST_RECEIVE_HEIGHT = 437; // NOTE: this value MUST be the height of the wallet's first tx for tests - -// wallet RPC config -TestUtils.WALLET_RPC_CONFIG = { - uri: "http://localhost:38083", - username: "rpc_user", - password: "abc123", - rejectUnauthorized: true // reject self-signed certificates if true -}; - -// daemon RPC config -TestUtils.DAEMON_RPC_CONFIG = { - uri: "http://localhost:38081", - username: "superuser", - password: "abctesting123", - rejectUnauthorized: true // reject self-signed certificates if true -}; - -//TestUtils.DAEMON_RPC_CONFIG = { -//uri: "http://node.xmrbackb.one:28081", -////username: "superuser", -////password: "abctesting123", -//maxRequestsPerSecond: 1 -//}; - -const TxPoolWalletTracker = require("./TxPoolWalletTracker"); -TestUtils.TX_POOL_WALLET_TRACKER = new TxPoolWalletTracker(); // used to track which wallets are in sync with pool so associated txs in the pool do not need to be waited on -TestUtils.PROXY_TO_WORKER = undefined; // default to true if browser, false otherwise - -module.exports = TestUtils; diff --git a/src/test/utils/TestUtils.ts b/src/test/utils/TestUtils.ts new file mode 100644 index 000000000..1ccaacd79 --- /dev/null +++ b/src/test/utils/TestUtils.ts @@ -0,0 +1,323 @@ +import assert from "assert"; +import WalletSyncPrinter from "./WalletSyncPrinter"; +import WalletTxTracker from "./WalletTxTracker"; +import {LibraryUtils, + GenUtils, + MoneroRpcError, + MoneroRpcConnection, + MoneroNetworkType, + MoneroDaemonRpc, + MoneroWalletRpc, + connectToWalletRpc, + connectToDaemonRpc, + openWalletFull, + createWalletFull, + createWalletKeys, + MoneroWalletFull, + MoneroWalletKeys} from "../../../index"; + +/** + * Collection of test utilities and configurations. + */ +export default class TestUtils { + + // classes to test + static daemonRpc: MoneroDaemonRpc; + static walletRpc: MoneroWalletRpc; + static walletFull: MoneroWalletFull; + static walletKeys: MoneroWalletKeys; + + // common config + static PROXY_TO_WORKER = true; + static MONERO_BINS_DIR = ""; // directory with monero binaries to test (monerod and monero-wallet-rpc) + static SYNC_PERIOD_IN_MS = 5000; // period between wallet syncs in milliseconds + static OFFLINE_SERVER_URI = "offline_server_uri"; // dummy server uri to remain offline because wallet2 connects to default if not given + static AUTO_CONNECT_TIMEOUT_MS = 3000; + + // wallet config + static NETWORK_TYPE = MoneroNetworkType.TESTNET; + static SEED = "silk mocked cucumber lettuce hope adrenalin aching lush roles fuel revamp baptism wrist long tender teardrop midst pastry pigment equip frying inbound pinched ravine frying"; + static ADDRESS = "A1y9sbVt8nqhZAVm3me1U18rUVXcjeNKuBd1oE2cTs8biA9cozPMeyYLhe77nPv12JA3ejJN3qprmREriit2fi6tJDi99RR"; + static FIRST_RECEIVE_HEIGHT = 171; // NOTE: this value must be the height of the wallet's first tx for tests + static WALLET_NAME = "test_wallet_1"; + static WALLET_PASSWORD = "supersecretpassword123"; + static TEST_WALLETS_DIR = "./test_wallets"; + static WALLET_FULL_PATH = TestUtils.TEST_WALLETS_DIR + "/" + TestUtils.WALLET_NAME; + static WALLET_RPC_PORT_START = 28084; + static WALLET_PORT_OFFSETS = {}; + static WALLET_RPC_LOCAL_PATH = TestUtils.MONERO_BINS_DIR + "/monero-wallet-rpc"; + static WALLET_RPC_LOCAL_WALLET_DIR = TestUtils.MONERO_BINS_DIR; + static WALLET_RPC_ACCESS_CONTROL_ORIGINS = "http://localhost:8080"; // cors access from web browser + static MAX_FEE = 7500000n * 10000n; + static WALLET_TX_TRACKER = new WalletTxTracker(); // used to track wallet txs for tests + static WALLET_RPC_CONFIG = { + uri: "localhost:28084", + username: "rpc_user", + password: "abc123", + rejectUnauthorized: true // reject self-signed certificates if true + }; + + // daemon config + static DAEMON_LOCAL_PATH = TestUtils.MONERO_BINS_DIR + "/monerod"; + static DAEMON_RPC_CONFIG = { + uri: "localhost:28081", + username: "", + password: "", + rejectUnauthorized: true // reject self-signed certificates if true + }; + + /** + * Get a default file system. Uses an in-memory file system if running in the browser. + * + * @return {any} nodejs-compatible file system + */ + static async getDefaultFs(): Promise { + return GenUtils.isBrowser() ? (await import('memfs')).fs.promises : (await import('fs')).promises; + } + + /** + * Get a singleton daemon RPC instance shared among tests. + * + * @return {Promise} a daemon RPC instance + */ + static async getDaemonRpc(): Promise { + if (TestUtils.daemonRpc === undefined) TestUtils.daemonRpc = await connectToDaemonRpc(Object.assign({proxyToWorker: TestUtils.PROXY_TO_WORKER}, TestUtils.DAEMON_RPC_CONFIG)); + return TestUtils.daemonRpc; + } + + /** + * Get a singleton instance of a monerod client. + */ + static getDaemonRpcConnection() { + return new MoneroRpcConnection(TestUtils.DAEMON_RPC_CONFIG); + } + + /** + * Get a singleton instance of a monero-wallet-rpc client. + * + * @return {Promise} a wallet RPC instance + */ + static async getWalletRpc(): Promise { + if (TestUtils.walletRpc === undefined) { + + // construct wallet rpc instance with daemon connection + TestUtils.walletRpc = await connectToWalletRpc(TestUtils.WALLET_RPC_CONFIG); + } + + // attempt to open test wallet + try { + await TestUtils.walletRpc.openWallet({path: TestUtils.WALLET_NAME, password: TestUtils.WALLET_PASSWORD}); + } catch (e) { + if (!(e instanceof MoneroRpcError)) throw e; + + console.log(e); + + // -1 returned when wallet does not exist or fails to open e.g. it's already open by another application + if (e.getCode() === -1) { + + // create wallet + console.log("Creating wallet!"); + await TestUtils.walletRpc.createWallet({path: TestUtils.WALLET_NAME, password: TestUtils.WALLET_PASSWORD, seed: TestUtils.SEED, restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT}); + } else { + throw e; + } + } + + // ensure we're testing the right wallet + assert.equal(await TestUtils.walletRpc.getSeed(), TestUtils.SEED); + assert.equal(await TestUtils.walletRpc.getPrimaryAddress(), TestUtils.ADDRESS); + + // sync and save wallet + await TestUtils.walletRpc.sync(); + await TestUtils.walletRpc.save(); + await TestUtils.walletRpc.startSyncing(TestUtils.SYNC_PERIOD_IN_MS); + + // return cached wallet rpc + return TestUtils.walletRpc; + } + + /** + * Create a monero-wallet-rpc process bound to the next available port. + * + * @param {boolean} [offline] - wallet is started in offline mode (default false) + * @return {Promise} - client connected to an internal monero-wallet-rpc instance + */ + static async startWalletRpcProcess(offline = false): Promise { + + // get next available offset of ports to bind to + let portOffset = 1; + while (Object.keys(TestUtils.WALLET_PORT_OFFSETS).includes("" + portOffset)) portOffset++; + TestUtils.WALLET_PORT_OFFSETS[portOffset] = undefined; // reserve port + + // create or connect to monero-wallet-rpc process + let wallet; + if (GenUtils.isBrowser()) { + let uri = TestUtils.WALLET_RPC_CONFIG.uri.substring(0, TestUtils.WALLET_RPC_CONFIG.uri.lastIndexOf(":")) + ":" + (TestUtils.WALLET_RPC_PORT_START + portOffset); + wallet = await connectToWalletRpc(uri, TestUtils.WALLET_RPC_CONFIG.username, TestUtils.WALLET_RPC_CONFIG.password); + } else { + + // create command to start client with internal monero-wallet-rpc process + let cmd = [ + TestUtils.WALLET_RPC_LOCAL_PATH, + "--" + GenUtils.getEnumKeyByValue(MoneroNetworkType, TestUtils.NETWORK_TYPE)!.toLowerCase(), + "--rpc-bind-port", "" + (TestUtils.WALLET_RPC_PORT_START + portOffset), + "--rpc-login", TestUtils.WALLET_RPC_CONFIG.username + ":" + TestUtils.WALLET_RPC_CONFIG.password, + "--wallet-dir", TestUtils.WALLET_RPC_LOCAL_WALLET_DIR, + "--rpc-access-control-origins", TestUtils.WALLET_RPC_ACCESS_CONTROL_ORIGINS + ]; + if (offline) cmd.push("--offline"); + else cmd.push("--daemon-address", TestUtils.DAEMON_RPC_CONFIG.uri); + if (TestUtils.DAEMON_RPC_CONFIG.username) cmd.push("--daemon-login", TestUtils.DAEMON_RPC_CONFIG.username + ":" + TestUtils.DAEMON_RPC_CONFIG.password); + + // TODO: include zmq params when supported and enabled + + // create and connect to monero-wallet-rpc process + wallet = await connectToWalletRpc(cmd); + } + + // register wallet with port offset + TestUtils.WALLET_PORT_OFFSETS[portOffset] = wallet; + return wallet; + } + + /** + * Stop a monero-wallet-rpc process and release its port. + * + * @param {MoneroWalletRpc} walletRpc - wallet created with internal monero-wallet-rpc process + */ + static async stopWalletRpcProcess(walletRpc) { + assert(walletRpc instanceof MoneroWalletRpc, "Must provide instance of MoneroWalletRpc to close"); + + // get corresponding port + let portOffset; + for (const [key, value] of Object.entries(TestUtils.WALLET_PORT_OFFSETS)) { + if (value === walletRpc) { + portOffset = key; + break; + } + } + if (portOffset === undefined) throw new Error("Wallet not registered"); + + // unregister wallet with port offset + delete TestUtils.WALLET_PORT_OFFSETS[portOffset]; + if (!GenUtils.isBrowser()) await walletRpc.stopProcess(); + } + + /** + * Get a singleton instance of a wallet supported by WebAssembly bindings to monero-project's wallet2. + * + * @return {MoneroWalletFull} a full wallet instance + */ + static async getWalletFull() { + if (!TestUtils.walletFull || await TestUtils.walletFull.isClosed()) { + + // create wallet from seed phrase if it doesn't exist + let fs = await TestUtils.getDefaultFs(); + if (!await MoneroWalletFull.walletExists(TestUtils.WALLET_FULL_PATH, fs)) { + // create directory for test wallets if it doesn't exist + await LibraryUtils.exists(fs, TestUtils.TEST_WALLETS_DIR) || await fs.mkdir(TestUtils.TEST_WALLETS_DIR); + if (!await LibraryUtils.exists(fs, TestUtils.TEST_WALLETS_DIR)) { + if (!await LibraryUtils.exists(fs, process.cwd())) await fs.mkdir(process.cwd(), { recursive: true }); // create current process directory for relative paths which does not exist in memory fs + fs.mkdir(TestUtils.TEST_WALLETS_DIR); + } + + // create wallet with connection + TestUtils.walletFull = await createWalletFull({path: TestUtils.WALLET_FULL_PATH, password: TestUtils.WALLET_PASSWORD, networkType: TestUtils.NETWORK_TYPE, seed: TestUtils.SEED, server: TestUtils.getDaemonRpcConnection(), restoreHeight: TestUtils.FIRST_RECEIVE_HEIGHT, proxyToWorker: TestUtils.PROXY_TO_WORKER, fs: fs}); + assert.equal(await TestUtils.walletFull.getRestoreHeight(), TestUtils.FIRST_RECEIVE_HEIGHT); + assert.deepEqual((await TestUtils.walletFull.getDaemonConnection()).getConfig(), TestUtils.getDaemonRpcConnection().getConfig()); + } + + // otherwise open existing wallet + else { + TestUtils.walletFull = await openWalletFull({path: TestUtils.WALLET_FULL_PATH, password: TestUtils.WALLET_PASSWORD, networkType: TestUtils.NETWORK_TYPE, server: TestUtils.getDaemonRpcConnection(), proxyToWorker: TestUtils.PROXY_TO_WORKER, fs: fs}); + await TestUtils.walletFull.setDaemonConnection(TestUtils.getDaemonRpcConnection()); + } + } + + // sync and save wallet + await TestUtils.walletFull.sync(new WalletSyncPrinter()); + await TestUtils.walletFull.save(); + await TestUtils.walletFull.startSyncing(TestUtils.SYNC_PERIOD_IN_MS); + + // ensure we're testing the right wallet + assert.equal(await TestUtils.walletFull.getSeed(), TestUtils.SEED); + assert.equal(await TestUtils.walletFull.getPrimaryAddress(), TestUtils.ADDRESS); + return TestUtils.walletFull; + } + + /** + * Get a singleton keys-only wallet instance shared among tests. + * + * @return {MoneroWalletKeys} a keys-only wallet instance + */ + static async getWalletKeys() { + if (TestUtils.walletKeys === undefined) { + + // create wallet from seed + TestUtils.walletKeys = await createWalletKeys({networkType: TestUtils.NETWORK_TYPE, seed: TestUtils.SEED}); + } + return TestUtils.walletKeys; + } + + /** + * Creates a new wallet considered to be "ground truth". + * + * @param networkType - ground truth wallet's network type + * @param seed - ground truth wallet's seed + * @param startHeight - height to start syncing from + * @param restoreHeight - ground truth wallet's restore height + * @return {MoneroWalletFull} the created wallet + */ + static async createWalletGroundTruth(networkType, seed, startHeight, restoreHeight) { + + // create directory for test wallets if it doesn't exist + let fs = await TestUtils.getDefaultFs(); + if (!await LibraryUtils.exists(fs, TestUtils.TEST_WALLETS_DIR)) { + if (!await LibraryUtils.exists(fs, process.cwd())) await fs.mkdir(process.cwd(), { recursive: true }); // create current process directory for relative paths which does not exist in memory fs + await fs.mkdir(TestUtils.TEST_WALLETS_DIR); + } + + // create ground truth wallet + let daemonConnection = new MoneroRpcConnection(TestUtils.DAEMON_RPC_CONFIG); + let path = TestUtils.TEST_WALLETS_DIR + "/gt_wallet_" + new Date().getTime(); + let gtWallet = await createWalletFull({ + path: path, + password: TestUtils.WALLET_PASSWORD, + networkType: networkType, + seed: seed, + server: daemonConnection, + restoreHeight: restoreHeight, + fs: fs + }); + assert.equal(await gtWallet.getRestoreHeight(), restoreHeight ? restoreHeight : 0); + await gtWallet.sync(new WalletSyncPrinter(), startHeight); + await gtWallet.startSyncing(TestUtils.SYNC_PERIOD_IN_MS); + return gtWallet; + } + + static testUnsignedBigInt(num, nonZero?) { + assert.equal("bigint", typeof num); + assert(num >= 0n); + if (nonZero === true) assert(num > 0n); + else if (nonZero === false) assert(num === 0n); + } + + static async getExternalWalletAddress() { + let wallet = await createWalletKeys({networkType: TestUtils.NETWORK_TYPE}); + return await wallet.getAddress(0, 1); // subaddress + } + + static txsMergeable(tx1, tx2) { + try { + let copy1 = tx1.copy(); + let copy2 = tx2.copy(); + if (copy1.getIsConfirmed()) copy1.setBlock(tx1.getBlock().copy().setTxs([copy1])); + if (copy2.getIsConfirmed()) copy2.setBlock(tx2.getBlock().copy().setTxs([copy2])); + copy1.merge(copy2); + return true; + } catch (e) { + console.error(e); + return false; + } + } +} \ No newline at end of file diff --git a/src/test/utils/WalletEqualityUtils.js b/src/test/utils/WalletEqualityUtils.ts similarity index 76% rename from src/test/utils/WalletEqualityUtils.js rename to src/test/utils/WalletEqualityUtils.ts index ad52caab4..ba2a2a075 100644 --- a/src/test/utils/WalletEqualityUtils.js +++ b/src/test/utils/WalletEqualityUtils.ts @@ -1,24 +1,22 @@ -const assert = require("assert"); -const TestUtils = require("./TestUtils"); -const monerojs = require("../../../index"); -const BigInteger = monerojs.BigInteger; -const GenUtils = monerojs.GenUtils; -const MoneroTxQuery = monerojs.MoneroTxQuery; -const MoneroTransferQuery = monerojs.MoneroTransferQuery; -const MoneroOutputQuery = monerojs.MoneroOutputQuery; -const MoneroOutgoingTransfer = monerojs.MoneroOutgoingTransfer; -const MoneroWalletRpc = monerojs.MoneroWalletRpc; +import assert from "assert"; +import TestUtils from "./TestUtils"; +import {GenUtils, + MoneroTxQuery, + MoneroTransferQuery, + MoneroOutputQuery, + MoneroOutgoingTransfer, + MoneroWalletRpc} from "../../../index"; /** * Utilities to deep compare wallets. */ -class WalletEqualityUtils { +export default class WalletEqualityUtils { /** * Compare the keys of two wallets. */ static async testWalletEqualityKeys(w1, w2) { - assert.equal(await w2.getMnemonic(), await w1.getMnemonic()); + assert.equal(await w2.getSeed(), await w1.getSeed()); assert.equal(await w2.getPrimaryAddress(), await w1.getPrimaryAddress()); assert.equal(await w2.getPrivateViewKey(), await w1.getPrivateViewKey()); } @@ -32,10 +30,11 @@ class WalletEqualityUtils { * @param w2 a wallet to compare */ static async testWalletEqualityOnChain(w1, w2) { - TestUtils.TX_POOL_WALLET_TRACKER.reset(); // all wallets need to wait for txs to confirm to reliably sync + TestUtils.WALLET_TX_TRACKER.reset(); // all wallets need to wait for txs to confirm to reliably sync // wait for relayed txs associated with wallets to clear pool - await TestUtils.TX_POOL_WALLET_TRACKER.waitForWalletTxsToClearPool(w1, w2); + assert.equal(await w1.isConnectedToDaemon(), await w2.isConnectedToDaemon()); + if (await w1.isConnectedToDaemon()) await TestUtils.WALLET_TX_TRACKER.waitForWalletTxsToClearPool([w1, w2]); // sync the wallets until same height while (await w1.getHeight() !== await w2.getHeight()) { @@ -45,46 +44,46 @@ class WalletEqualityUtils { // test that wallets are equal using only on-chain data assert.equal(await w2.getHeight(), await w1.getHeight(), "Wallet heights are not equal after syncing"); - assert.equal(await w2.getMnemonic(), await w1.getMnemonic()); + assert.equal(await w2.getSeed(), await w1.getSeed()); assert.equal(await w2.getPrimaryAddress(), await w1.getPrimaryAddress()); assert.equal(await w2.getPrivateViewKey(), await w1.getPrivateViewKey()); assert.equal(await w2.getPrivateSpendKey(), await w1.getPrivateSpendKey()); let txQuery = new MoneroTxQuery().setIsConfirmed(true); - await WalletEqualityUtils._testTxWalletsEqualOnChain(await w1.getTxs(txQuery), await w2.getTxs(txQuery)); + await WalletEqualityUtils.testTxWalletsEqualOnChain(await w1.getTxs(txQuery), await w2.getTxs(txQuery)); txQuery.setIncludeOutputs(true); - await WalletEqualityUtils._testTxWalletsEqualOnChain(await w1.getTxs(txQuery), await w2.getTxs(txQuery)); // fetch and compare outputs - await WalletEqualityUtils._testAccountsEqualOnChain(await w1.getAccounts(true), await w2.getAccounts(true)); - assert.equal((await w2.getBalance()).toString(), (await await w1.getBalance()).toString()); + await WalletEqualityUtils.testTxWalletsEqualOnChain(await w1.getTxs(txQuery), await w2.getTxs(txQuery)); // fetch and compare outputs + await WalletEqualityUtils.testAccountsEqualOnChain(await w1.getAccounts(true), await w2.getAccounts(true)); + assert.equal((await w2.getBalance()).toString(), (await w1.getBalance()).toString()); assert.equal((await w2.getUnlockedBalance()).toString(), (await w1.getUnlockedBalance()).toString()); let transferQuery = new MoneroTransferQuery().setTxQuery(new MoneroTxQuery().setIsConfirmed(true)); - await WalletEqualityUtils._testTransfersEqualOnChain(await w1.getTransfers(transferQuery), await w2.getTransfers(transferQuery)); + await WalletEqualityUtils.testTransfersEqualOnChain(await w1.getTransfers(transferQuery), await w2.getTransfers(transferQuery)); let outputQuery = new MoneroOutputQuery().setTxQuery(new MoneroTxQuery().setIsConfirmed(true)); - await WalletEqualityUtils._testOutputWalletsEqualOnChain(await w1.getOutputs(outputQuery), await w2.getOutputs(outputQuery)); + await WalletEqualityUtils.testOutputWalletsEqualOnChain(await w1.getOutputs(outputQuery), await w2.getOutputs(outputQuery)); } - static async _testAccountsEqualOnChain(accounts1, accounts2) { + protected static async testAccountsEqualOnChain(accounts1, accounts2) { for (let i = 0; i < Math.max(accounts1.length, accounts2.length); i++) { if (i < accounts1.length && i < accounts2.length) { - await WalletEqualityUtils._testAccountEqualOnChain(accounts1[i], accounts2[i]); + await WalletEqualityUtils.testAccountEqualOnChain(accounts1[i], accounts2[i]); } else if (i >= accounts1.length) { for (let j = i; j < accounts2.length; j++) { - assert.equal(accounts2[j].getBalance().toString(), BigInteger.parse("0").toString()); + assert.equal(accounts2[j].getBalance().toString(), 0n.toString()); assert(accounts2[j].getSubaddresses().length >= 1); - for (let subaddress of accounts2[j].getSubaddresses()) assert(!subaddress.isUsed()); + for (let subaddress of accounts2[j].getSubaddresses()) assert(!subaddress.getIsUsed()); } return; } else { for (let j = i; j < accounts1.length; j++) { - assert.equal(accounts1[j].getBalance().toString(), BigInteger.parse("0")); + assert.equal(accounts1[j].getBalance().toString(), 0n); assert(accounts1[j].getSubaddresses().length >= 1); - for (let subaddress of accounts1[j].getSubaddresses()) assert(!subaddress.isUsed()); + for (let subaddress of accounts1[j].getSubaddresses()) assert(!subaddress.getIsUsed()); } return; } } } - static async _testAccountEqualOnChain(account1, account2) { + protected static async testAccountEqualOnChain(account1, account2) { // nullify off-chain data for comparison let subaddresses1 = account1.getSubaddresses(); @@ -96,23 +95,23 @@ class WalletEqualityUtils { // test account equality assert(GenUtils.equals(account2, account1)); - await WalletEqualityUtils._testSubaddressesEqualOnChain(subaddresses1, subaddresses2); + await WalletEqualityUtils.testSubaddressesEqualOnChainAux(subaddresses1, subaddresses2); } - static async _testSubaddressesEqualOnChain(subaddresses1, subaddresses2) { + protected static async testSubaddressesEqualOnChainAux(subaddresses1, subaddresses2) { for (let i = 0; i < Math.max(subaddresses1.length, subaddresses2.length); i++) { if (i < subaddresses1.length && i < subaddresses2.length) { - await WalletEqualityUtils._testSubaddressesEqualOnChain(subaddresses1[i], subaddresses2[i]); + await WalletEqualityUtils.testSubaddressesEqualOnChainAux(subaddresses1[i], subaddresses2[i]); } else if (i >= subaddresses1.length) { for (let j = i; j < subaddresses2.length; j++) { - assert.equal(BigInteger.parse("0"), subaddresses2[j].getBalance().toString()); - assert(!subaddresses2[j].isUsed()); + assert.equal(0n, subaddresses2[j].getBalance().toString()); + assert(!subaddresses2[j].getIsUsed()); } return; } else { for (let j = i; j < subaddresses1.length; j++) { - assert.equal(BigInteger.parse("0"), subaddresses1[i].getBalance()); - assert(!subaddresses1[j].isUsed()); + assert.equal(0n, subaddresses1[i].getBalance()); + assert(!subaddresses1[j].getIsUsed()); } return; } @@ -125,10 +124,10 @@ class WalletEqualityUtils { assert(GenUtils.equals(subaddress2, subaddress1)); } - static async _testTxWalletsEqualOnChain(txs1, txs2) { + protected static async testTxWalletsEqualOnChain(txs1, txs2) { // nullify off-chain data for comparison - let allTxs = []; + let allTxs: any = []; for (let tx1 of txs1) allTxs.push(tx1); for (let tx2 of txs2) allTxs.push(tx2); for (let tx of allTxs) { @@ -145,11 +144,11 @@ class WalletEqualityUtils { for (let tx2 of txs2) { if (tx1.getHash() === tx2.getHash()) { - // transfer destination info if known for comparison + // transfer cached info if known for comparison if (tx1.getOutgoingTransfer() !== undefined && tx1.getOutgoingTransfer().getDestinations() !== undefined) { - if (tx2.getOutgoingTransfer() === undefined || tx2.getOutgoingTransfer().getDestinations() === undefined) WalletEqualityUtils._transferDestinationInfo(tx1, tx2); + if (tx2.getOutgoingTransfer() === undefined || tx2.getOutgoingTransfer().getDestinations() === undefined) WalletEqualityUtils.transferCachedInfo(tx1, tx2); } else if (tx2.getOutgoingTransfer() !== undefined && tx2.getOutgoingTransfer().getDestinations() !== undefined) { - WalletEqualityUtils._transferDestinationInfo(tx2, tx1); + WalletEqualityUtils.transferCachedInfo(tx2, tx1); } // test tx equality by merging @@ -170,7 +169,7 @@ class WalletEqualityUtils { } } - static async _transferDestinationInfo(src, tgt) { + protected static async transferCachedInfo(src, tgt) { // fill in missing incoming transfers when sending from/to the same account if (src.getIncomingTransfers() !== undefined) { @@ -180,7 +179,7 @@ class WalletEqualityUtils { } } // sort transfers - tgt.getIncomingTransfers().sort(MoneroWalletRpc._compareIncomingTransfers); + tgt.getIncomingTransfers().sort(MoneroWalletRpc.compareIncomingTransfers); } // transfer info to outgoing transfer @@ -189,9 +188,12 @@ class WalletEqualityUtils { tgt.getOutgoingTransfer().setDestinations(src.getOutgoingTransfer().getDestinations()); tgt.getOutgoingTransfer().setAmount(src.getOutgoingTransfer().getAmount()); } + + // transfer payment id if outgoing // TODO: monero-wallet-rpc does not provide payment id for outgoing transfer when cache missing https://github.com/monero-project/monero/issues/8378 + if (tgt.getOutgoingTransfer() !== undefined) tgt.setPaymentId(src.getPaymentId()); } - static async _testTransfersEqualOnChain(transfers1, transfers2) { + protected static async testTransfersEqualOnChain(transfers1, transfers2) { assert.equal(transfers2.length, transfers1.length); // test and collect transfers per transaction @@ -250,15 +252,15 @@ class WalletEqualityUtils { let transfer2 = txTransfers2[i]; // normalize outgoing transfers - if (transfer1 instanceof MoneroOutgoingTransfer) { + if (transfer1 instanceof MoneroOutgoingTransfer && transfer2 instanceof MoneroOutgoingTransfer) { let ot1 = transfer1; let ot2 = transfer2; // transfer destination info if known for comparison if (ot1.getDestinations() !== undefined) { - if (ot2.getDestinations() === undefined) await WalletEqualityUtils._transferDestinationInfo(ot1.getTx(), ot2.getTx()); + if (ot2.getDestinations() === undefined) await WalletEqualityUtils.transferCachedInfo(ot1.getTx(), ot2.getTx()); } else if (ot2.getDestinations() !== undefined) { - await WalletEqualityUtils._transferDestinationInfo(ot2.getTx(), ot1.getTx()); + await WalletEqualityUtils.transferCachedInfo(ot2.getTx(), ot1.getTx()); } // nullify other local wallet data @@ -280,7 +282,7 @@ class WalletEqualityUtils { } } - static async _testOutputWalletsEqualOnChain(outputs1, outputs2) { + protected static async testOutputWalletsEqualOnChain(outputs1, outputs2) { assert.equal(outputs2.length, outputs1.length); // test and collect outputs per transaction @@ -344,4 +346,3 @@ class WalletEqualityUtils { } } -module.exports = WalletEqualityUtils; diff --git a/src/test/utils/WalletSyncPrinter.js b/src/test/utils/WalletSyncPrinter.ts similarity index 58% rename from src/test/utils/WalletSyncPrinter.js rename to src/test/utils/WalletSyncPrinter.ts index 0aa011953..c02b643ca 100644 --- a/src/test/utils/WalletSyncPrinter.js +++ b/src/test/utils/WalletSyncPrinter.ts @@ -1,22 +1,23 @@ -const MoneroWalletListener = require("../../main/js/wallet/model/MoneroWalletListener"); +import { MoneroWalletListener } from "../../../index"; /** * Print sync progress every X blocks. */ -class WalletSyncPrinter extends MoneroWalletListener { +export default class WalletSyncPrinter extends MoneroWalletListener { + + nextIncrement: number; + syncResolution: number; - constructor(syncResolution) { + constructor(syncResolution?: number) { super(); this.nextIncrement = 0; this.syncResolution = syncResolution ? syncResolution : .05; } - onSyncProgress(height, startHeight, endHeight, percentDone, message) { + async onSyncProgress(height, startHeight, endHeight, percentDone, message) { if (percentDone === 1 || percentDone >= this.nextIncrement) { console.log("onSyncProgress(" + height + ", " + startHeight + ", " + endHeight + ", " + percentDone + ", " + message + ")"); this.nextIncrement += this.syncResolution; } } } - -module.exports = WalletSyncPrinter; \ No newline at end of file diff --git a/src/test/utils/TxPoolWalletTracker.js b/src/test/utils/WalletTxTracker.ts similarity index 58% rename from src/test/utils/TxPoolWalletTracker.js rename to src/test/utils/WalletTxTracker.ts index f5eed6246..95e20cec4 100644 --- a/src/test/utils/TxPoolWalletTracker.js +++ b/src/test/utils/WalletTxTracker.ts @@ -1,6 +1,7 @@ -const monerojs = require("../../../index"); -const GenUtils = monerojs.GenUtils; -const MoneroUtils = monerojs.MoneroUtils; +import TestUtils from "./TestUtils"; // to avoid circular reference +import StartMining from "./StartMining"; +import {GenUtils, + MoneroUtils} from "../../../index"; /** * Tracks wallets which are in sync with the tx pool and therefore whose txs in the pool @@ -9,9 +10,11 @@ const MoneroUtils = monerojs.MoneroUtils; * This is only necessary because txs relayed outside wallets are not fully incorporated * into the wallet state until confirmed. * - * TODO monero core: sync txs relayed outside wallet so this class is unecessary + * TODO monero-project: sync txs relayed outside wallet so this class is unecessary */ -class TxPoolWalletTracker { +export default class WalletTxTracker { + + clearedWallets: Set; constructor() { this.clearedWallets = new Set(); @@ -40,7 +43,6 @@ class TxPoolWalletTracker { */ async waitForWalletTxsToClearPool(wallets) { wallets = GenUtils.listify(wallets); - // get wallet tx hashes let txHashesWallet = new Set(); for (let wallet of wallets) { @@ -55,15 +57,15 @@ class TxPoolWalletTracker { // loop until all wallet txs clear from pool let isFirst = true; let miningStarted = false; - const TestUtils = require("./TestUtils"); + //import TestUtils from "./TestUtils"; // to avoid circular reference let daemon = await TestUtils.getDaemonRpc(); while (true) { // get hashes of relayed, non-failed txs in the pool let txHashesPool = new Set(); for (let tx of await daemon.getTxPool()) { - if (!tx.isRelayed()) continue; - else if (tx.isFailed()) await daemon.flushTxPool(tx.getHash()); // flush tx if failed + if (!tx.getIsRelayed()) continue; + else if (tx.getIsFailed()) await daemon.flushTxPool(tx.getHash()); // flush tx if failed else txHashesPool.add(tx.getHash()); } @@ -82,9 +84,9 @@ class TxPoolWalletTracker { isFirst = false; console.log("Waiting for wallet txs to clear from the pool in order to fully sync and avoid double spend attempts (known issue)"); let miningStatus = await daemon.getMiningStatus(); - if (!miningStatus.isActive()) { + if (!miningStatus.getIsActive()) { try { - const StartMining = require("./StartMining"); + //import StartMining from "./StartMining"; await StartMining.startMining(); miningStarted = true; } catch (e) { @@ -95,7 +97,7 @@ class TxPoolWalletTracker { } // sleep for a moment - await new Promise(function(resolve) { setTimeout(resolve, MoneroUtils.WALLET_REFRESH_RATE); }); + await new Promise(function(resolve) { setTimeout(resolve, TestUtils.SYNC_PERIOD_IN_MS); }); } // stop mining if started mining @@ -107,6 +109,42 @@ class TxPoolWalletTracker { this.clearedWallets.add(wallet); } } + + async waitForUnlockedBalance(wallet, accountIndex, subaddressIndex, minAmount) { + if (!minAmount) minAmount = 0n; + + // check if wallet has balance + if (await wallet.getBalance(accountIndex, subaddressIndex) < minAmount) throw new Error("Wallet does not have enough balance to wait for"); + + // check if wallet has unlocked balance + let unlockedBalance = await wallet.getUnlockedBalance(accountIndex, subaddressIndex); + if (unlockedBalance > minAmount) return unlockedBalance; + + // start mining + //import TestUtils from "./TestUtils"; // to avoid circular reference + let daemon = await TestUtils.getDaemonRpc(); + let miningStarted = false; + if (!(await daemon.getMiningStatus()).getIsActive()) { + try { + console.log("Starting mining!"); + //import StartMining from "./StartMining"; // to avoid circular reference + await StartMining.startMining(); + miningStarted = true; + } catch (err) { + console.error("Error starting mining:"); + console.error(err); + } + } + + // wait for unlocked balance // TODO: promote to MoneroWallet interface? + console.log("Waiting for unlocked balance"); + while (unlockedBalance < minAmount) { + unlockedBalance = await wallet.getUnlockedBalance(accountIndex, subaddressIndex); + await new Promise(function(resolve) { setTimeout(resolve, TestUtils.SYNC_PERIOD_IN_MS); }); + } + + // stop mining if started + if (miningStarted) await daemon.stopMining(); + return unlockedBalance; + } } - -module.exports = TxPoolWalletTracker; \ No newline at end of file diff --git a/todo.txt b/todo.txt deleted file mode 100644 index 5205d29a9..000000000 --- a/todo.txt +++ /dev/null @@ -1,154 +0,0 @@ -support listener js object -support strings in queries, etc -wallet.waitForTxsToClearPool()? -http request timeout -run testSendToMultiple() a few times to start wallet or send to random subaddress -monerowalletrpc.js/java can use subaddr_indices_all instead of manually setting all indices (wallet_rpc_server.cpp:1420) -simplify getting available outputs - alias isLocked? isAvailable? -support sign(msg, accountIndex, subaddressIndex) default 0s -support create_subaddress count up to 64 at a time -support on_estimate_tx_size_and_weight -wallet_rpc_server on_create_address "Count must be between 1 and 64." -only get failed synchronize message for one wallet when multiple wallet syncs fail -separate keys tests? -test saving tx note when creating tx -getBlockTemplate() getNextSeedHash sometimes not null -free tx set, tx, transfer, outputs from getTxs(), createTxs(), etc -why not waiting for tx pool? -error when wallet already open? -end-to-end sweep test which fans funds each block for 10 blocks then tests all sweeps, use singleton sweep wallet to re-use on tests for each wallet type -inherit tx config fields in transfer, output configs? -check for unrecognized tx config -wallet2 1128 ::move() causes warning -pre-compress wasm file so server is not compressing when requested: https://emscripten.org/docs/compiling/WebAssembly.html?highlight=wasm, STANDALONE_WASM -optimize asyncify, see https://kripken.github.io/blog/wasm/2019/07/16/asyncify.html -rpc mutisig test failing when run with other tests -startSynchronizing() uses pre-started loop for random start time like core wallet? -real daemon listener instead of registering function to receive block headers -wasm checkTxKey(), getTxProof(), checkTxProof(), getSpendProof(), getReserveProofWallet() -rpc supports view-only request failed: 0, or error after previously called -fix consistent failures in tests (notification failures, Can sync a wallet created from keys numConfirmations increased by two) -getSyncHeight() top level? -wallet2.h updates: wallet_rpc on_sweep_all now sweeps all subaddresses by default, res.signature = m_wallet->sign(req.data, {req.account_index, req.address_index});, on_estimate_tx_size_and_weight -testCheckForUpdate returns confusing error if offline -update MoneroWalletRpc/MoneroWalletJni getTxs() to use missing tx hash logic like monero_wallet_core::get_txs() -sync end height != daemon height for long syncs -implement Can submit a mined block to the network -compare sync performance with multithreading vs singlethreading - build both? -await MoneroWallet.create({type: "wasm", networkType:, 2, connectionUri: connection: {uri: : daemonUri: "...", mnemonic: "}) -MoneroDaemonRpc support 3 string args, just like MoneroWalletRpc or factor method? copy constructor? -support MoneroWalletRpc(string uri, string username, string password) like java -build boost and openssl in ./bin/build_dist.sh only if necessary -emscripten logging -in-memory wallet; wallet2 password is required to create valid cache file on creation (start with tests) -delete old branches -test queuing sync requests in test which opens and closes multiple wallets -low severity vulnerabilities -find boost version in cmake lists -externalize test config -filesystem can be used in emscripten for wasm wallet, possibly supports memfs: https://emscripten.org/docs/api_reference/Filesystem-API.html -open bug on check key no funds received despite transfer - caused by importing key images? -re-test with pthread and compare performance, could load pthreaded library if nodejs or browser supports -namespace exported types to object instead of this.? -"Can update a locked tx sent from/to the same account as blocks are added to the chain" sometimes gets stuck waiting for updates, possibly because tx was rejected with double spend? -daemon rpc getTxs() does not return tx blocks -overload toJson() model protos and use JSON.stringify() instead of class toJsons() -master sort MoneroWallet.js with top level methods -monero_wallet_core get_keys_file_buffer/get_cache_file_buffer use m_password instead of arg -overload create_wallet_* instead of http_client=null? -compare sync speeds with and without notifications -compare performance with dynamic memory growth -update assert.equal(BI, BI) -> assert.equal(BI.toString(), BI.toString()) in tests -port pool relay tests from java TestMoneroWalletCommon.java -port testSyncWithPoolSubmit from java -monero_wallet_core::set_daemon_connection is_local_address() uses common/util which requires libunbound -libsodium dependency in monero-cpp, why doesn't monero-project's work? -test "Can get transactions by id" passes tx query where txs is array of characters -mymonero monero_wallet_utils.cpp 182 mnemonic sanitation -emscripten bind can return native vectors, see https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html -jni compare ground truth test sometimes shows gt output not unlocked but jni is unlocked -support keys-ony wallet integrated address, accounts, subaddresses -pruning -mms -getBlocksByRange() end should be exclusive -model rct_signatures and rct_prunable -what happens if sweep_all is not given account_index. if it sweeps wallet, replace sweepWallet() impl -test filtering on hasDestinations -MoneroTxTestConfig extends MoneroTxFilter -MoneroTxConfig setIncludeVouts(), getIncludeVouts() -MoneroTxConfig isCompatible(MoneroWalletTx) -wallet.getTxById() for convenience? -send priority has no default, must pick one -don't differentiate in spec uint vs long, BigInteger? or specify detailed types (uint64) -class diagram query txs, transfers, vouts -checkTxProof(signature, ...)? -consider how api should generate subaddresses client side -one call per get/set bandwidth limits? -daemon.getBlocksById(), default implementations -daemon test failed txs more -wallet test coinbase txs -sweep subaddresses test -test that note is set if specified in send config -set subaddress getUnspentOutputCount() with outputs assigned -validate all input parameters to api -test every block of the chain -not directly testing sweepUnlocked() -daemon binary tests -daemon notification test needs to test tx merging -merge asserts type -how to handle 'confirmations' block height to add the tx to the chain if unconfirmed? corallary of unlock height? -handle excess undefineds and enable deepEqual() in testWalletTxCopy() -way to throttle rpc requests with agent instead of throttle-request to preserve stacktrace? -send to multiple, suggested_confirmation_threshold outgoing payment 6 but incoming payments 1; large discrepency -remove text-encoding dependency -test notifications hardwired to account 0 which gets emptied by reset tests -test all tx fields in daemon, update tests to be like wallet -test json serialization / deserialization specifically, stringifying in between so cannot be any live objects -support vout filter in tx filter? -undefined amounts instead of 0 for rct amounts -block comments in models -support setting daemon log level -split BooleanSet into new project - -JS now has native BigInt class which could be used instead of current BigInteger -switch to jest? -csv export of types -time profiling -mock response test framework -refactor copying to not be downward of a tree rooted at tx but instead correct per each part of a graph -add typescript? - -BIG PICTURE -support core wallet with webassembly -report rpc issues -fix transfers bug #4500 in wallet rpc -integrate with bisq -port javascript to go & implement binding to integrate with openbazaar -mymonero javascript wallet - -RPC --1: Failed to get the right transaction from daemon --4: failed to get output distribution on send rests (wallet rpc transfer, transfer_split, sweep, sweep_single, etc) --4: Change address is not ours on testSweepUnlocked(); -why is subaddr_indices list of map? -subaddresses occluded by outgoing counterparts when sent from/to same account (#4500) -key proof indicates no funds received despite known incoming transfer from/to same account -not enough money right after opening wallet, pretty much every other run -outgoing transfers always return subaddress index 0 (#5171) -duplicate outgoing transfers returned for different subaddress indices, way to include subaddress indices? - -add relayed to daemon rpc get_transactions, wallet rpc get_transfers, else must use get_transaction_pool (#5137) -add output_indices to get_blocks_by_height.bin (#5127) -wallet rpc sweep_single documentation not correct; contradicts example -daemon rpc supports cors wildcard character (#5172) -unconfirmed tx missing destinations even though known by wallet -send from/to same account, after first confirmation outgoing tx amount is 0 but has payments with amts, so discrepency -show_transfers returns unconfirmed outputs -introduce way to identify change output from blockchain? that solves unknown sent amt issue -identify one call per acount/subaddress and support "all" flag -/get_transactions returns duplicate data per transaction -daemon get_txs prune documentation missing -document alt chain `block_hashes` and `main_chain_parent_block` -each call to `open_wallet` toggles whether or not pending transfers return (#5106) -transfer with do_not_relay then relay_tx issue (#5107) -ability to create new wallet which randomly generates seed? \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..2267fafa6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "declaration": true, + "module": "es2022", + "target": "es2021", + "allowJs": true, + "outDir": "dist", + "skipLibCheck": true, + "types": [ + "mocha", + "node", + "jquery" + ], + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitAny": false, + "noImplicitThis": false, + "strictNullChecks": false, + "moduleResolution": "node", + "resolveJsonModule": true + }, + "include": ["index.ts", "src/**/*"], + "exclude": ["node_modules", "dist/*", "types"] +} \ No newline at end of file diff --git a/wasm_exception_whitelist.txt b/wasm_exception_whitelist.txt index 21e8269cf..5c1a81982 100644 --- a/wasm_exception_whitelist.txt +++ b/wasm_exception_whitelist.txt @@ -1,4 +1,4 @@ -_ZN6monero18monero_wallet_core8sync_auxEN5boost8optionalIyEE +_ZN18monero_wasm_bridge24get_default_fee_priorityEiN10emscripten3valE _ZN18monero_wasm_bridge10create_txsEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge10get_heightEiN10emscripten3valE _ZN18monero_wasm_bridge10get_tx_keyEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE @@ -8,97 +8,118 @@ _ZN18monero_wasm_bridge11get_accountEijb _ZN18monero_wasm_bridge11get_addressEijj _ZN18monero_wasm_bridge11get_outputsEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge11get_versionEi -_ZN18monero_wasm_bridge12check_tx_keyEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_ +_ZN18monero_wasm_bridge12check_tx_keyEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_N10emscripten3valE _ZN18monero_wasm_bridge12get_accountsEibRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE -_ZN18monero_wasm_bridge12get_mnemonicEi +_ZN18monero_wasm_bridge8get_seedEi _ZN18monero_wasm_bridge12get_tx_notesEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE -_ZN18monero_wasm_bridge12get_tx_proofEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_ -_ZN18monero_wasm_bridge12is_connectedEiN10emscripten3valE +_ZN18monero_wasm_bridge12get_tx_proofEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_N10emscripten3valE +_ZN18monero_wasm_bridge12is_connected_to_daemonEiN10emscripten3valE _ZN18monero_wasm_bridge12is_view_onlyEi -_ZN18monero_wasm_bridge12parse_tx_setEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE +_ZN18monero_wasm_bridge15describe_tx_setEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE _ZN18monero_wasm_bridge12rescan_spentEiN10emscripten3valE -_ZN18monero_wasm_bridge12set_listenerEiiN10emscripten3valES1_S1_S1_S1_ +_ZN18monero_wasm_bridge8scan_txsEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE +_ZN18monero_wasm_bridge12set_listenerEiiN10emscripten3valES1_S1_S1_S1_S1_ _ZN18monero_wasm_bridge12set_tx_notesEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE -_ZN18monero_wasm_bridge12sign_messageEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE +_ZN18monero_wasm_bridge12sign_messageEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEjjj _ZN18monero_wasm_bridge12sweep_outputEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge12tag_accountsEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE _ZN18monero_wasm_bridge13get_attributeEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE _ZN18monero_wasm_bridge13get_transfersEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE -_ZN18monero_wasm_bridge13make_multisigEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE +_ZN18monero_wasm_bridge13make_multisigEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge13set_attributeEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_ _ZN18monero_wasm_bridge14binary_to_jsonERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE -_ZN18monero_wasm_bridge14check_tx_proofEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_S8_ +_ZN18monero_wasm_bridge14check_tx_proofEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_S8_N10emscripten3valE _ZN18monero_wasm_bridge14create_accountEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE -_ZN18monero_wasm_bridge14get_key_imagesEiN10emscripten3valE _ZN18monero_wasm_bridge14sweep_unlockedEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge14untag_accountsEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE _ZN18monero_wasm_bridge14verify_messageEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_ _ZN18monero_wasm_bridge15get_outputs_hexEiN10emscripten3valE -_ZN18monero_wasm_bridge15get_spend_proofEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_ -_ZN18monero_wasm_bridge15get_sync_heightEi -_ZN18monero_wasm_bridge15set_sync_heightEil +_ZN18monero_wasm_bridge15get_spend_proofEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_N10emscripten3valE +_ZN18monero_wasm_bridge18get_restore_heightEi +_ZN18monero_wasm_bridge18set_restore_heightEil _ZN18monero_wasm_bridge16get_account_tagsEi -_ZN18monero_wasm_bridge16get_multisig_hexEi +_ZN18monero_wasm_bridge19export_multisig_hexEi _ZN18monero_wasm_bridge16get_network_typeEi _ZN18monero_wasm_bridge16get_subaddressesEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE _ZN18monero_wasm_bridge16is_daemon_syncedEiN10emscripten3valE -_ZN18monero_wasm_bridge16open_core_walletERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEiS8_S8_S8_S8_S8_S8_N10emscripten3valE +_ZN18monero_wasm_bridge16open_wallet_fullERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEiS8_S8_S8_S8_S8_S8_N10emscripten3valE _ZN18monero_wasm_bridge16prepare_multisigEi -_ZN18monero_wasm_bridge17check_spend_proofEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_ +_ZN18monero_wasm_bridge17check_spend_proofEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_N10emscripten3valE _ZN18monero_wasm_bridge17create_subaddressEijRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE +_ZN18monero_wasm_bridge20set_subaddress_labelEijjRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE _ZN18monero_wasm_bridge17get_address_indexEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE _ZN18monero_wasm_bridge17get_daemon_heightEiN10emscripten3valE _ZN18monero_wasm_bridge17get_multisig_infoEi _ZN18monero_wasm_bridge17import_key_imagesEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge17parse_payment_uriEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE _ZN18monero_wasm_bridge17rescan_blockchainEiN10emscripten3valE -_ZN18monero_wasm_bridge18create_payment_uriEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE +_ZN18monero_wasm_bridge15get_payment_uriEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE _ZN18monero_wasm_bridge18get_balance_walletEi _ZN18monero_wasm_bridge18get_height_by_dateEithhN10emscripten3valE _ZN18monero_wasm_bridge18import_outputs_hexEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE -_ZN18monero_wasm_bridge19check_reserve_proofEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_ +_ZN18monero_wasm_bridge17export_key_imagesEibN10emscripten3valE +_ZN18monero_wasm_bridge19check_reserve_proofEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_N10emscripten3valE _ZN18monero_wasm_bridge19get_balance_accountEij _ZN18monero_wasm_bridge19get_public_view_keyEi _ZN18monero_wasm_bridge19import_multisig_hexEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge20get_keys_file_bufferEiNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEb _ZN18monero_wasm_bridge20get_private_view_keyEi _ZN18monero_wasm_bridge20get_public_spend_keyEi -_ZN18monero_wasm_bridge20sign_multisig_tx_hexEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE +_ZN18monero_wasm_bridge20sign_multisig_tx_hexEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge21binary_blocks_to_jsonERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE -_ZN18monero_wasm_bridge21get_cache_file_bufferEiNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE +_ZN18monero_wasm_bridge21get_cache_file_bufferEi _ZN18monero_wasm_bridge21get_daemon_connectionEi -_ZN18monero_wasm_bridge21get_mnemonic_languageEi +_ZN18monero_wasm_bridge17get_seed_languageEi _ZN18monero_wasm_bridge21get_private_spend_keyEi _ZN18monero_wasm_bridge21set_account_tag_labelEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_ _ZN18monero_wasm_bridge21set_daemon_connectionEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_N10emscripten3valE _ZN18monero_wasm_bridge22add_address_book_entryEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_ -_ZN18monero_wasm_bridge22exchange_multisig_keysEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE +_ZN18monero_wasm_bridge22exchange_multisig_keysEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge22get_balance_subaddressEijj _ZN18monero_wasm_bridge22get_integrated_addressEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_ _ZN18monero_wasm_bridge22submit_multisig_tx_hexEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge23edit_address_book_entryEiibRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEbS8_ _ZN18monero_wasm_bridge23malloc_binary_from_jsonERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE _ZN18monero_wasm_bridge24get_address_book_entriesEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE -_ZN18monero_wasm_bridge24get_reserve_proof_walletEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE -_ZN18monero_wasm_bridge25create_core_wallet_randomERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEiS8_S8_S8_S8_S8_N10emscripten3valE -_ZN18monero_wasm_bridge25create_keys_wallet_randomEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE +_ZN18monero_wasm_bridge24get_reserve_proof_walletEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE +_ZN18monero_wasm_bridge25create_keys_wallet_randomERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge25decode_integrated_addressEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE _ZN18monero_wasm_bridge25delete_address_book_entryEii -_ZN18monero_wasm_bridge25get_reserve_proof_accountEijRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_ +_ZN18monero_wasm_bridge25get_reserve_proof_accountEijRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_N10emscripten3valE _ZN18monero_wasm_bridge25is_multisig_import_neededEi _ZN18monero_wasm_bridge26get_daemon_max_peer_heightEiN10emscripten3valE _ZN18monero_wasm_bridge27get_unlocked_balance_walletEi -_ZN18monero_wasm_bridge28create_core_wallet_from_keysERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEiS8_S8_S8_S8_S8_S8_S8_lS8_N10emscripten3valE -_ZN18monero_wasm_bridge28create_keys_wallet_from_keysEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_S8_S8_N10emscripten3valE +_ZN18monero_wasm_bridge28create_keys_wallet_from_keysERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge28get_unlocked_balance_accountEij _ZN18monero_wasm_bridge31get_unlocked_balance_subaddressEijj -_ZN18monero_wasm_bridge32create_core_wallet_from_mnemonicERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEiS8_S8_S8_S8_S8_lS8_N10emscripten3valE -_ZN18monero_wasm_bridge32create_keys_wallet_from_mnemonicEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_N10emscripten3valE -_ZN18monero_wasm_bridge34get_core_wallet_mnemonic_languagesEv -_ZN18monero_wasm_bridge34get_keys_wallet_mnemonic_languagesEv +_ZN18monero_wasm_bridge18create_full_walletERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_N10emscripten3valE +_ZN18monero_wasm_bridge28create_keys_wallet_from_seedERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE +_ZN18monero_wasm_bridge30get_full_wallet_seed_languagesEv +_ZN18monero_wasm_bridge30get_keys_wallet_seed_languagesEv _ZN18monero_wasm_bridge4syncEilN10emscripten3valE +_ZN18monero_wasm_bridge22change_wallet_passwordEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_N10emscripten3valE _ZN18monero_wasm_bridge5closeEibN10emscripten3valE _ZN18monero_wasm_bridge7get_txsEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE _ZN18monero_wasm_bridge8sign_txsEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE _ZN18monero_wasm_bridge9is_syncedEiN10emscripten3valE -_ZN18monero_wasm_bridge9relay_txsEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE \ No newline at end of file +_ZN18monero_wasm_bridge9relay_txsEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE +_ZN18monero_wasm_bridge27get_integrated_address_utilEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEES8_ +_ZN18monero_wasm_bridge16validate_addressERKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEi +_ZN18monero_wasm_bridge11thaw_outputEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE +_ZN18monero_wasm_bridge13freeze_outputEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE +_ZN18monero_wasm_bridge16is_output_frozenEiRKNSt3__212basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEN10emscripten3valE +_ZN6monero18monero_wallet_full10submit_txsERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE +_ZN6monero18monero_wallet_full15describe_tx_setERKNS_13monero_tx_setE +_ZN6monero18monero_wallet_full20sign_multisig_tx_hexERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE +_ZN6monero18monero_wallet_full22submit_multisig_tx_hexERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE +_ZN6monero18monero_wallet_full9relay_txsERKNSt3__26vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEE +_ZN6monero18monero_wallet_full8sign_txsERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE +_ZN6monero18monero_wallet_full8sync_auxEN5boost8optionalIyEE +_ZN6monero18monero_wallet_full13run_sync_loopEv +_ZN5tools10threadpool3runEb +_ZN5tools7wallet24loadERKNSt3__212basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERKN4epee15wipeable_stringES9_S9_ +_ZN5tools7wallet215import_multisigENSt3__26vectorINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS6_IS8_EEEE +_ZN5tools7wallet27refreshEbyRyRbb +_ZN5tools7wallet217import_key_imagesERKNSt3__26vectorINS1_4pairIN6crypto9key_imageENS4_9signatureEEENS1_9allocatorIS7_EEEEmRySD_b +_ZNK5tools7wallet217export_key_imagesEb +_ZNK5tools7wallet212sanity_checkERKNSt3__26vectorINS0_10pending_txENS1_9allocatorIS3_EEEERKNS2_IN10cryptonote20tx_destination_entryENS4_ISA_EEEERKNS1_3setIjNS1_4lessIjEENS4_IjEEEE \ No newline at end of file diff --git a/webpack.base.js b/webpack.base.js index 3722bd015..e5b360302 100644 --- a/webpack.base.js +++ b/webpack.base.js @@ -1,10 +1,17 @@ "use strict" const path = require("path"); +const webpack = require('webpack') let configBase = { + mode: 'production', module: { rules: [ + { + test: /\.ts?$/, + loader: 'ts-loader', + exclude: /node_modules/ + }, { test: /\.js$/, exclude: path.join(__dirname, 'node_modules'), @@ -21,15 +28,47 @@ let configBase = { ] }, devtool: 'source-map', - externals: ['worker_threads','ws','perf_hooks'], // exclude nodejs + externals: ['worker_threads', 'ws', 'perf_hooks', 'child_process', 'web-worker'], // exclude nodejs dependencies + plugins: [ + new webpack.ProvidePlugin({ + process: 'process/browser', + Buffer: ['buffer', 'Buffer'] + }), + ], resolve: { + extensions: ['.js', '.ts'], alias: { - "fs": "html5-fs" + "fs": "memfs", }, - extensions: ['.js', '.jsx', '.css', '.json', 'otf', 'ttf', 'eot', 'svg'], + extensions: ['.js', '.jsx', '.css', '.json', 'otf', 'ttf', 'eot', 'svg', '.ts', '.tsx'], modules: [ - 'node_modules' - ] + 'node_modules', + ], + fallback: { // browser polyfills + assert: require.resolve('assert'), + //buffer: require.resolve('buffer'), + //console: require.resolve('console-browserify'), + //constants: require.resolve('constants-browserify'), + crypto: require.resolve('crypto-browserify'), + //domain: require.resolve('domain-browser'), + //events: require.resolve('events'), + http: require.resolve('stream-http'), + https: require.resolve('https-browserify'), + os: require.resolve('os-browserify/browser'), + path: require.resolve('path-browserify'), + //punycode: require.resolve('punycode'), + 'process/browser': require.resolve('process/browser'), + querystring: require.resolve('querystring-es3'), + stream: require.resolve('stream-browserify'), + //string_decoder: require.resolve('string_decoder'), + //sys: require.resolve('util'), + //timers: require.resolve('timers-browserify'), + //tty: require.resolve('tty-browserify'), + url: require.resolve('url'), + util: require.resolve('util'), + //vm: require.resolve('vm-browserify'), + zlib: require.resolve('browserify-zlib') + } }, cache: true, context: __dirname diff --git a/webpack.tests.js b/webpack.tests.js index f2b20ae48..f1cc897d0 100644 --- a/webpack.tests.js +++ b/webpack.tests.js @@ -4,11 +4,11 @@ const path = require("path"); const configBase = require("./webpack.base.js"); let configBrowserTest = Object.assign({}, configBase, { - name: "Test config", - entry: "./src/test/browser/tests.js", + name: "Browser tests config", + entry: "./dist/src/test/browser/tests.js", output: { path: path.resolve(__dirname, "browser_build"), - filename: "monero-javascript-tests.js" + filename: "monero.tests.js" }, }); diff --git a/webpack.worker.js b/webpack.worker.js index d50fc1d92..f07750e7a 100644 --- a/webpack.worker.js +++ b/webpack.worker.js @@ -5,10 +5,10 @@ const configBase = require("./webpack.base.js"); let configMoneroWebWorker = Object.assign({}, configBase, { name: "Monero web worker config", - entry: "./src/main/js/common/MoneroWebWorker.js", + entry: "./src/main/ts/common/MoneroWebWorker.ts", output: { path: path.resolve(__dirname, "dist"), - filename: "MoneroWebWorker.dist.js" + filename: "monero.worker.js" }, });